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-03-20 18:19:03 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-20 18:19:03 +0300
commit14bd84b61276ef29b97d23642d698de769bacfd2 (patch)
treef9eba90140c1bd874211dea17750a0d422c04080
parent891c388697b2db0d8ee0c8358a9bdbf6dc56d581 (diff)
Add latest changes from gitlab-org/gitlab@15-10-stable-eev15.10.0-rc42
-rw-r--r--.eslintrc.yml7
-rw-r--r--.gitignore1
-rw-r--r--.gitlab-ci.yml49
-rw-r--r--.gitlab/CODEOWNERS167
-rw-r--r--.gitlab/ci/as-if-jh.gitlab-ci.yml16
-rw-r--r--.gitlab/ci/database.gitlab-ci.yml39
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml37
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml27
-rw-r--r--.gitlab/ci/notify.gitlab-ci.yml25
-rw-r--r--.gitlab/ci/package-and-test/main.gitlab-ci.yml179
-rw-r--r--.gitlab/ci/package-and-test/rules.gitlab-ci.yml10
-rw-r--r--.gitlab/ci/package-and-test/variables.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/preflight.gitlab-ci.yml57
-rw-r--r--.gitlab/ci/qa.gitlab-ci.yml19
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml127
-rw-r--r--.gitlab/ci/rails/rspec-foss-impact.gitlab-ci.yml.erb48
-rw-r--r--.gitlab/ci/rails/shared.gitlab-ci.yml18
-rw-r--r--.gitlab/ci/release-environments.gitlab-ci.yml3
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml9
-rw-r--r--.gitlab/ci/review-apps/main.gitlab-ci.yml6
-rw-r--r--.gitlab/ci/review-apps/qa.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml85
-rw-r--r--.gitlab/ci/setup.gitlab-ci.yml16
-rw-r--r--.gitlab/ci/vendored-gems.gitlab-ci.yml8
-rw-r--r--.gitlab/issue_templates/Geo Replicate a new Git repository type.md152
-rw-r--r--.gitlab/issue_templates/Geo Replicate a new blob type.md146
-rw-r--r--.gitlab/issue_templates/UX Theme.md114
-rw-r--r--.gitlab/merge_request_templates/New Static Analysis Check.md2
-rw-r--r--.gitlab/merge_request_templates/Revert To Resolve Incident.md1
-rw-r--r--.gitleaksignore2
-rw-r--r--.rubocop.yml13
-rw-r--r--.rubocop_todo/background_migration/missing_dictionary_file.yml4
-rw-r--r--.rubocop_todo/gitlab/namespaced_class.yml1
-rw-r--r--.rubocop_todo/gitlab/strong_memoize_attr.yml4
-rw-r--r--.rubocop_todo/layout/argument_alignment.yml161
-rw-r--r--.rubocop_todo/layout/empty_line_after_magic_comment.yml2
-rw-r--r--.rubocop_todo/layout/line_length.yml5
-rw-r--r--.rubocop_todo/layout/space_in_lambda_literal.yml1
-rw-r--r--.rubocop_todo/layout/space_inside_parens.yml1
-rw-r--r--.rubocop_todo/lint/unused_block_argument.yml2
-rw-r--r--.rubocop_todo/lint/unused_method_argument.yml1
-rw-r--r--.rubocop_todo/naming/heredoc_delimiter_naming.yml1
-rw-r--r--.rubocop_todo/performance/map_compact.yml13
-rw-r--r--.rubocop_todo/performance/string_include.yml9
-rw-r--r--.rubocop_todo/rails/inverse_of.yml17
-rw-r--r--.rubocop_todo/rake/require.yml14
-rw-r--r--.rubocop_todo/rspec/context_wording.yml5
-rw-r--r--.rubocop_todo/rspec/invalid_feature_category.yml66
-rw-r--r--.rubocop_todo/rspec/missing_feature_category.yml1878
-rw-r--r--.rubocop_todo/style/format_string.yml1
-rw-r--r--.rubocop_todo/style/guard_clause.yml1
-rw-r--r--.rubocop_todo/style/if_unless_modifier.yml2
-rw-r--r--.rubocop_todo/style/mutable_constant.yml1
-rw-r--r--.rubocop_todo/style/percent_literal_delimiters.yml1
-rw-r--r--.rubocop_todo/style/redundant_freeze.yml1
-rw-r--r--.rubocop_todo/style/symbol_proc.yml1
-rw-r--r--CHANGELOG.md34
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_KAS_VERSION2
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile55
-rw-r--r--Gemfile.checksum115
-rw-r--r--Gemfile.lock203
-rw-r--r--README.md2
-rw-r--r--app/assets/images/learn_gitlab/section_code.svg4
-rw-r--r--app/assets/javascripts/access_tokens/components/new_access_token_app.vue2
-rw-r--r--app/assets/javascripts/activities.js2
-rw-r--r--app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue2
-rw-r--r--app/assets/javascripts/add_context_commits_modal/store/actions.js2
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue41
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue109
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/app.vue63
-rw-r--r--app/assets/javascripts/admin/abuse_reports/constants.js81
-rw-r--r--app/assets/javascripts/admin/abuse_reports/index.js31
-rw-r--r--app/assets/javascripts/admin/abuse_reports/utils.js6
-rw-r--r--app/assets/javascripts/admin/application_settings/network_outbound.js28
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/components/base.vue2
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/components/message_form.vue39
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/constants.js1
-rw-r--r--app/assets/javascripts/admin/deploy_keys/components/table.vue2
-rw-r--r--app/assets/javascripts/admin/statistics_panel/store/actions.js2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/activate.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/approve.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/ban.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/block.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/deactivate.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/reject.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/unban.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/unblock.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/unlock.vue2
-rw-r--r--app/assets/javascripts/admin/users/components/users_table.vue2
-rw-r--r--app/assets/javascripts/airflow/dags/components/dags.vue111
-rw-r--r--app/assets/javascripts/alert.js137
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_form.vue35
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue2
-rw-r--r--app/assets/javascripts/alerts_settings/constants.js2
-rw-r--r--app/assets/javascripts/alerts_settings/utils/cache_updates.js2
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/components/base.vue30
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/components/path_navigation.vue17
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue6
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/constants.js8
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/store/actions.js23
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/store/getters.js4
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/store/mutations.js7
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/store/state.js6
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/utils.js26
-rw-r--r--app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue5
-rw-r--r--app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue20
-rw-r--r--app/assets/javascripts/analytics/shared/components/value_streams_dashboard_link.vue30
-rw-r--r--app/assets/javascripts/analytics/shared/utils.js19
-rw-r--r--app/assets/javascripts/analytics/usage_trends/components/usage_counts.vue2
-rw-r--r--app/assets/javascripts/api.js2
-rw-r--r--app/assets/javascripts/api/analytics_api.js58
-rw-r--r--app/assets/javascripts/api/user_api.js2
-rw-r--r--app/assets/javascripts/artifacts/components/artifact_row.vue24
-rw-r--r--app/assets/javascripts/artifacts/components/artifacts_bulk_delete.vue182
-rw-r--r--app/assets/javascripts/artifacts/components/artifacts_table_row_details.vue11
-rw-r--r--app/assets/javascripts/artifacts/components/job_artifacts_table.vue83
-rw-r--r--app/assets/javascripts/artifacts/components/job_checkbox.vue52
-rw-r--r--app/assets/javascripts/artifacts/constants.js39
-rw-r--r--app/assets/javascripts/artifacts/graphql/mutations/bulk_destroy_job_artifacts.mutation.graphql7
-rw-r--r--app/assets/javascripts/artifacts/index.js10
-rw-r--r--app/assets/javascripts/authentication/mount_2fa.js26
-rw-r--r--app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue6
-rw-r--r--app/assets/javascripts/authentication/u2f/authenticate.js106
-rw-r--r--app/assets/javascripts/authentication/u2f/error.js26
-rw-r--r--app/assets/javascripts/authentication/u2f/index.js17
-rw-r--r--app/assets/javascripts/authentication/u2f/register.js102
-rw-r--r--app/assets/javascripts/authentication/u2f/util.js40
-rw-r--r--app/assets/javascripts/authentication/webauthn/authenticate.js3
-rw-r--r--app/assets/javascripts/authentication/webauthn/components/registration.vue226
-rw-r--r--app/assets/javascripts/authentication/webauthn/constants.js46
-rw-r--r--app/assets/javascripts/authentication/webauthn/error.js7
-rw-r--r--app/assets/javascripts/authentication/webauthn/index.js18
-rw-r--r--app/assets/javascripts/authentication/webauthn/register.js3
-rw-r--r--app/assets/javascripts/authentication/webauthn/registration.js22
-rw-r--r--app/assets/javascripts/authentication/webauthn/util.js8
-rw-r--r--app/assets/javascripts/awards_handler.js2
-rw-r--r--app/assets/javascripts/badges/components/badge_form.vue2
-rw-r--r--app/assets/javascripts/badges/components/badge_settings.vue4
-rw-r--r--app/assets/javascripts/batch_comments/components/draft_note.vue13
-rw-r--r--app/assets/javascripts/batch_comments/components/preview_dropdown.vue22
-rw-r--r--app/assets/javascripts/batch_comments/components/submit_dropdown.vue2
-rw-r--r--app/assets/javascripts/batch_comments/index.js8
-rw-r--r--app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js4
-rw-r--r--app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js2
-rw-r--r--app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js3
-rw-r--r--app/assets/javascripts/behaviors/copy_code.js2
-rw-r--r--app/assets/javascripts/behaviors/copy_to_clipboard.js4
-rw-r--r--app/assets/javascripts/behaviors/date_picker.js5
-rw-r--r--app/assets/javascripts/behaviors/markdown/copy_as_gfm.js2
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_json_table.js2
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_observability.js30
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js2
-rw-r--r--app/assets/javascripts/behaviors/markdown/schema.js2
-rw-r--r--app/assets/javascripts/behaviors/preview_markdown.js2
-rw-r--r--app/assets/javascripts/behaviors/shortcuts.js6
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js5
-rw-r--r--app/assets/javascripts/blame/blame_redirect.js2
-rw-r--r--app/assets/javascripts/blame/streaming/index.js56
-rw-r--r--app/assets/javascripts/blob/csv/index.js1
-rw-r--r--app/assets/javascripts/blob/file_template_mediator.js2
-rw-r--r--app/assets/javascripts/blob/notebook/notebook_viewer.vue5
-rw-r--r--app/assets/javascripts/blob/viewer/index.js2
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js2
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js4
-rw-r--r--app/assets/javascripts/boards/components/board_add_new_column.vue116
-rw-r--r--app/assets/javascripts/boards/components/board_add_new_column_form.vue101
-rw-r--r--app/assets/javascripts/boards/components/board_app.vue28
-rw-r--r--app/assets/javascripts/boards/components/board_column.vue15
-rw-r--r--app/assets/javascripts/boards/components/board_content.vue25
-rw-r--r--app/assets/javascripts/boards/components/board_content_sidebar.vue9
-rw-r--r--app/assets/javascripts/boards/components/board_filtered_search.vue24
-rw-r--r--app/assets/javascripts/boards/components/board_form.vue40
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue22
-rw-r--r--app/assets/javascripts/boards/components/board_list_header.vue144
-rw-r--r--app/assets/javascripts/boards/components/board_settings_sidebar.vue4
-rw-r--r--app/assets/javascripts/boards/components/board_top_bar.vue44
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue37
-rw-r--r--app/assets/javascripts/boards/components/config_toggle.vue9
-rw-r--r--app/assets/javascripts/boards/components/issue_board_filtered_search.vue22
-rw-r--r--app/assets/javascripts/boards/constants.js27
-rw-r--r--app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql2
-rw-r--r--app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql2
-rw-r--r--app/assets/javascripts/boards/index.js7
-rw-r--r--app/assets/javascripts/boards/issue_board_filters.js21
-rw-r--r--app/assets/javascripts/boards/stores/actions.js27
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js11
-rw-r--r--app/assets/javascripts/branches/divergence_graph.js2
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue8
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue74
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue43
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/constants.js5
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/graphql/queries/group_variables.query.graphql11
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/graphql/queries/project_variables.query.graphql11
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/graphql/queries/variables.query.graphql10
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/graphql/settings.js49
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/index.js9
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/editor/text_editor.vue11
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/header/validation_segment.vue109
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item.vue39
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item.vue89
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/constants.js36
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer.vue109
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/utils.js22
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/event_hub.js5
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/index.js8
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue21
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/store/index.js12
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/store/mutation_types.js2
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/store/mutations.js10
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/store/state.js4
-rw-r--r--app/assets/javascripts/ci/pipeline_new/components/pipeline_new_form.vue22
-rw-r--r--app/assets/javascripts/ci/pipeline_new/index.js4
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue4
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue3
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue9
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue5
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue10
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue14
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql6
-rw-r--r--app/assets/javascripts/ci/reports/constants.js14
-rw-r--r--app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue37
-rw-r--r--app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue69
-rw-r--r--app/assets/javascripts/ci/runner/admin_register_runner/index.js36
-rw-r--r--app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue2
-rw-r--r--app/assets/javascripts/ci/runner/admin_runners/admin_runners_app.vue6
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/cli_command.vue42
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/platforms_drawer.vue135
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue241
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue6
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/scripts/linux/install.sh12
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/scripts/osx/install.sh11
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/scripts/windows/install.ps113
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/utils.js109
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_create_form.vue71
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_delete_button.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_jobs.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_list_empty_state.vue4
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_pause_button.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_projects.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_update_form.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/search_tokens/tag_token.vue2
-rw-r--r--app/assets/javascripts/ci/runner/constants.js62
-rw-r--r--app/assets/javascripts/ci/runner/graphql/new/runner_create.mutation.graphql9
-rw-r--r--app/assets/javascripts/ci/runner/graphql/register/runner_for_registration.query.graphql8
-rw-r--r--app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue2
-rw-r--r--app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue2
-rw-r--r--app/assets/javascripts/ci/runner/local_storage_alert/show_alert_from_local_storage.js2
-rw-r--r--app/assets/javascripts/ci/runner/runner_edit/runner_edit_app.vue2
-rw-r--r--app/assets/javascripts/clusters/agents/components/revoke_token_button.vue11
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js2
-rw-r--r--app/assets/javascripts/clusters/constants.js16
-rw-r--r--app/assets/javascripts/clusters_list/components/delete_agent_button.vue11
-rw-r--r--app/assets/javascripts/clusters_list/store/actions.js2
-rw-r--r--app/assets/javascripts/commit/components/signature_badge.vue94
-rw-r--r--app/assets/javascripts/commit/components/x509_certificate_details.vue45
-rw-r--r--app/assets/javascripts/commit/constants.js104
-rw-r--r--app/assets/javascripts/commit_merge_requests.js2
-rw-r--r--app/assets/javascripts/confidential_merge_request/components/project_form_group.vue2
-rw-r--r--app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue3
-rw-r--r--app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue35
-rw-r--r--app/assets/javascripts/content_editor/components/content_editor.vue86
-rw-r--r--app/assets/javascripts/content_editor/components/formatting_toolbar.vue168
-rw-r--r--app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue10
-rw-r--r--app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue2
-rw-r--r--app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue2
-rw-r--r--app/assets/javascripts/content_editor/constants/index.js1
-rw-r--r--app/assets/javascripts/content_editor/extensions/attachment.js2
-rw-r--r--app/assets/javascripts/content_editor/extensions/color_chip.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/drawio_diagram.js41
-rw-r--r--app/assets/javascripts/content_editor/extensions/external_keydown_handler.js2
-rw-r--r--app/assets/javascripts/content_editor/extensions/image.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/paste_markdown.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/suggestions.js2
-rw-r--r--app/assets/javascripts/content_editor/extensions/table.js2
-rw-r--r--app/assets/javascripts/content_editor/services/content_editor.js4
-rw-r--r--app/assets/javascripts/content_editor/services/create_content_editor.js8
-rw-r--r--app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js7
-rw-r--r--app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js2
-rw-r--r--app/assets/javascripts/content_editor/services/markdown_serializer.js5
-rw-r--r--app/assets/javascripts/content_editor/services/upload_helpers.js38
-rw-r--r--app/assets/javascripts/contextual_sidebar.js3
-rw-r--r--app/assets/javascripts/contributors/components/contributors.vue42
-rw-r--r--app/assets/javascripts/contributors/stores/actions.js2
-rw-r--r--app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue16
-rw-r--r--app/assets/javascripts/deploy_freeze/store/actions.js2
-rw-r--r--app/assets/javascripts/deploy_keys/components/app.vue2
-rw-r--r--app/assets/javascripts/deploy_keys/components/confirm_modal.vue4
-rw-r--r--app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue9
-rw-r--r--app/assets/javascripts/deploy_tokens/deploy_token_translations.js5
-rw-r--r--app/assets/javascripts/deprecated_notes.js59
-rw-r--r--app/assets/javascripts/design_management/components/design_notes/design_discussion.vue139
-rw-r--r--app/assets/javascripts/design_management/components/design_notes/design_note.vue91
-rw-r--r--app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue112
-rw-r--r--app/assets/javascripts/design_management/components/design_sidebar.vue25
-rw-r--r--app/assets/javascripts/design_management/components/toolbar/index.vue3
-rw-r--r--app/assets/javascripts/design_management/constants.js5
-rw-r--r--app/assets/javascripts/design_management/graphql/mutations/destroy_note.mutation.graphql8
-rw-r--r--app/assets/javascripts/design_management/index.js10
-rw-r--r--app/assets/javascripts/design_management/mixins/all_designs.js2
-rw-r--r--app/assets/javascripts/design_management/pages/design/index.vue81
-rw-r--r--app/assets/javascripts/design_management/utils/cache_update.js2
-rw-r--r--app/assets/javascripts/design_management/utils/error_messages.js8
-rw-r--r--app/assets/javascripts/diff.js2
-rw-r--r--app/assets/javascripts/diffs/components/app.vue36
-rw-r--r--app/assets/javascripts/diffs/components/diff_code_quality.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_expansion_cell.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_row.vue5
-rw-r--r--app/assets/javascripts/diffs/components/file_row_stats.vue2
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue107
-rw-r--r--app/assets/javascripts/diffs/constants.js8
-rw-r--r--app/assets/javascripts/diffs/index.js17
-rw-r--r--app/assets/javascripts/diffs/store/actions.js36
-rw-r--r--app/assets/javascripts/diffs/store/getters.js8
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js1
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js15
-rw-r--r--app/assets/javascripts/diffs/store/utils.js43
-rw-r--r--app/assets/javascripts/diffs/utils/tree_worker_utils.js5
-rw-r--r--app/assets/javascripts/diffs/workers/tree_worker.js19
-rw-r--r--app/assets/javascripts/drawio/constants.js15
-rw-r--r--app/assets/javascripts/drawio/content_editor_facade.js80
-rw-r--r--app/assets/javascripts/drawio/drawio_editor.js277
-rw-r--r--app/assets/javascripts/drawio/markdown_field_editor_facade.js72
-rw-r--r--app/assets/javascripts/editor/components/source_editor_toolbar.vue43
-rw-r--r--app/assets/javascripts/editor/constants.js26
-rw-r--r--app/assets/javascripts/editor/extensions/source_editor_extension_base.js45
-rw-r--r--app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js29
-rw-r--r--app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js6
-rw-r--r--app/assets/javascripts/editor/schema/ci.json14
-rw-r--r--app/assets/javascripts/editor/utils.js9
-rw-r--r--app/assets/javascripts/emoji/components/emoji_group.vue5
-rw-r--r--app/assets/javascripts/entrypoints/super_sidebar.js5
-rw-r--r--app/assets/javascripts/environments/components/canary_update_modal.vue2
-rw-r--r--app/assets/javascripts/environments/components/confirm_rollback_modal.vue2
-rw-r--r--app/assets/javascripts/environments/components/delete_environment_modal.vue4
-rw-r--r--app/assets/javascripts/environments/components/deployment.vue2
-rw-r--r--app/assets/javascripts/environments/components/edit_environment.vue2
-rw-r--r--app/assets/javascripts/environments/components/environment_form.vue2
-rw-r--r--app/assets/javascripts/environments/components/kubernetes_agent_info.vue101
-rw-r--r--app/assets/javascripts/environments/components/kubernetes_overview.vue73
-rw-r--r--app/assets/javascripts/environments/components/new_environment.vue2
-rw-r--r--app/assets/javascripts/environments/components/new_environment_item.vue30
-rw-r--r--app/assets/javascripts/environments/components/stop_environment_modal.vue2
-rw-r--r--app/assets/javascripts/environments/graphql/queries/k8s_cluster_agent.query.graphql19
-rw-r--r--app/assets/javascripts/environments/mixins/environments_mixin.js2
-rw-r--r--app/assets/javascripts/error_tracking/components/error_details.vue2
-rw-r--r--app/assets/javascripts/error_tracking/store/actions.js2
-rw-r--r--app/assets/javascripts/error_tracking/store/details/actions.js2
-rw-r--r--app/assets/javascripts/error_tracking/store/list/actions.js2
-rw-r--r--app/assets/javascripts/error_tracking_settings/store/actions.js2
-rw-r--r--app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue22
-rw-r--r--app/assets/javascripts/feature_flags/components/environments_dropdown.vue2
-rw-r--r--app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue2
-rw-r--r--app/assets/javascripts/feature_flags/constants.js8
-rw-r--r--app/assets/javascripts/feature_flags/store/edit/actions.js2
-rw-r--r--app/assets/javascripts/feature_highlight/feature_highlight_helper.js2
-rw-r--r--app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js36
-rw-r--r--app/assets/javascripts/filtered_search/available_dropdown_mappings.js5
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_ajax_filter.js2
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_emoji.js2
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_non_user.js2
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js5
-rw-r--r--app/assets/javascripts/filtered_search/visual_token_value.js2
-rw-r--r--app/assets/javascripts/flash.js137
-rw-r--r--app/assets/javascripts/gpg_badges.js2
-rw-r--r--app/assets/javascripts/grafana_integration/store/actions.js4
-rw-r--r--app/assets/javascripts/graphql_shared/constants.js1
-rw-r--r--app/assets/javascripts/graphql_shared/possible_types.json3
-rw-r--r--app/assets/javascripts/graphql_shared/queries/get_users_by_usernames.query.graphql9
-rw-r--r--app/assets/javascripts/group.js2
-rw-r--r--app/assets/javascripts/groups/components/app.vue4
-rw-r--r--app/assets/javascripts/groups/components/group_name_and_path.vue2
-rw-r--r--app/assets/javascripts/groups/components/invite_members_banner.vue6
-rw-r--r--app/assets/javascripts/groups/constants.js1
-rw-r--r--app/assets/javascripts/groups/settings/components/access_dropdown.vue2
-rw-r--r--app/assets/javascripts/groups/store/utils.js6
-rw-r--r--app/assets/javascripts/header.js2
-rw-r--r--app/assets/javascripts/header_search/components/app.vue60
-rw-r--r--app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue14
-rw-r--r--app/assets/javascripts/header_search/components/header_search_default_items.vue6
-rw-r--r--app/assets/javascripts/header_search/components/header_search_scoped_items.vue6
-rw-r--r--app/assets/javascripts/header_search/constants.js48
-rw-r--r--app/assets/javascripts/header_search/store/getters.js20
-rw-r--r--app/assets/javascripts/ide/components/ide.vue2
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/modal.vue6
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue26
-rw-r--r--app/assets/javascripts/ide/index.js1
-rw-r--r--app/assets/javascripts/ide/stores/actions.js2
-rw-r--r--app/assets/javascripts/ide/stores/actions/merge_request.js2
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js2
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/actions.js7
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/constants.js6
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/state.js4
-rw-r--r--app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js2
-rw-r--r--app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js2
-rw-r--r--app/assets/javascripts/ide/stores/state.js1
-rw-r--r--app/assets/javascripts/import_entities/components/group_dropdown.vue2
-rw-r--r--app/assets/javascripts/import_entities/components/import_status.vue9
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue25
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_table.vue22
-rw-r--r--app/assets/javascripts/import_entities/import_groups/index.js1
-rw-r--r--app/assets/javascripts/import_entities/import_groups/services/status_poller.js2
-rw-r--r--app/assets/javascripts/import_entities/import_projects/index.js5
-rw-r--r--app/assets/javascripts/import_entities/import_projects/store/actions.js10
-rw-r--r--app/assets/javascripts/incidents/constants.js1
-rw-r--r--app/assets/javascripts/incidents_settings/incidents_settings_service.js2
-rw-r--r--app/assets/javascripts/init_deprecated_notes.js4
-rw-r--r--app/assets/javascripts/integrations/constants.js6
-rw-r--r--app/assets/javascripts/integrations/edit/components/confirmation_modal.vue2
-rw-r--r--app/assets/javascripts/integrations/edit/components/integration_form.vue10
-rw-r--r--app/assets/javascripts/integrations/edit/components/integration_forms/section.vue8
-rw-r--r--app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue2
-rw-r--r--app/assets/javascripts/integrations/edit/components/sections/apple_app_store.vue73
-rw-r--r--app/assets/javascripts/integrations/edit/components/sections/google_play.vue75
-rw-r--r--app/assets/javascripts/integrations/edit/components/upload_dropzone_field.vue143
-rw-r--r--app/assets/javascripts/integrations/index/components/integrations_table.vue14
-rw-r--r--app/assets/javascripts/invite_members/components/group_select.vue1
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue7
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_trigger.vue50
-rw-r--r--app/assets/javascripts/invite_members/components/invite_modal_base.vue41
-rw-r--r--app/assets/javascripts/invite_members/constants.js5
-rw-r--r--app/assets/javascripts/invite_members/utils/trigger_successful_invite_alert.js2
-rw-r--r--app/assets/javascripts/issuable/components/csv_export_modal.vue13
-rw-r--r--app/assets/javascripts/issuable/components/csv_import_export_buttons.vue4
-rw-r--r--app/assets/javascripts/issuable/components/issuable_header_warnings.vue8
-rw-r--r--app/assets/javascripts/issuable/components/related_issuable_item.vue72
-rw-r--r--app/assets/javascripts/issuable/components/status_box.vue11
-rw-r--r--app/assets/javascripts/issuable/constants.js10
-rw-r--r--app/assets/javascripts/issuable/issuable_bulk_update_actions.js2
-rw-r--r--app/assets/javascripts/issuable/issuable_label_selector.js11
-rw-r--r--app/assets/javascripts/issuable/popover/components/mr_popover.vue24
-rw-r--r--app/assets/javascripts/issuable/popover/constants.js13
-rw-r--r--app/assets/javascripts/issues/constants.js29
-rw-r--r--app/assets/javascripts/issues/create_merge_request_dropdown.js123
-rw-r--r--app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue41
-rw-r--r--app/assets/javascripts/issues/index.js8
-rw-r--r--app/assets/javascripts/issues/issue.js2
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue41
-rw-r--r--app/assets/javascripts/issues/list/constants.js1
-rw-r--r--app/assets/javascripts/issues/list/utils.js40
-rw-r--r--app/assets/javascripts/issues/manual_ordering.js2
-rw-r--r--app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue32
-rw-r--r--app/assets/javascripts/issues/related_merge_requests/store/actions.js2
-rw-r--r--app/assets/javascripts/issues/show/components/app.vue40
-rw-r--r--app/assets/javascripts/issues/show/components/delete_issue_modal.vue3
-rw-r--r--app/assets/javascripts/issues/show/components/description.vue162
-rw-r--r--app/assets/javascripts/issues/show/components/edit_actions.vue12
-rw-r--r--app/assets/javascripts/issues/show/components/fields/description.vue1
-rw-r--r--app/assets/javascripts/issues/show/components/fields/type.vue16
-rw-r--r--app/assets/javascripts/issues/show/components/header_actions.vue41
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue4
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue24
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/router.js20
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue6
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue2
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/utils.js2
-rw-r--r--app/assets/javascripts/issues/show/components/locked_warning.vue12
-rw-r--r--app/assets/javascripts/issues/show/components/task_list_item_actions.vue4
-rw-r--r--app/assets/javascripts/issues/show/components/title.vue28
-rw-r--r--app/assets/javascripts/issues/show/constants.js1
-rw-r--r--app/assets/javascripts/issues/show/index.js15
-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/fragments/ci_variable.fragment.graphql6
-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.graphql11
-rw-r--r--app/assets/javascripts/jobs/components/job/job_log_controllers.vue2
-rw-r--r--app/assets/javascripts/jobs/components/job/manual_variables_form.vue148
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue16
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue2
-rw-r--r--app/assets/javascripts/jobs/components/table/constants.js1
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/cache_config.js60
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql1
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql8
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_app.vue46
-rw-r--r--app/assets/javascripts/jobs/constants.js2
-rw-r--r--app/assets/javascripts/jobs/store/actions.js4
-rw-r--r--app/assets/javascripts/labels/components/promote_label_modal.vue4
-rw-r--r--app/assets/javascripts/labels/create_label_dropdown.js22
-rw-r--r--app/assets/javascripts/labels/group_label_subscription.js5
-rw-r--r--app/assets/javascripts/labels/label_manager.js2
-rw-r--r--app/assets/javascripts/labels/labels.js12
-rw-r--r--app/assets/javascripts/labels/labels_select.js2
-rw-r--r--app/assets/javascripts/labels/project_label_subscription.js5
-rw-r--r--app/assets/javascripts/layout_nav.js9
-rw-r--r--app/assets/javascripts/lib/utils/constants.js5
-rw-r--r--app/assets/javascripts/lib/utils/error_message.js20
-rw-r--r--app/assets/javascripts/lib/utils/file_upload.js7
-rw-r--r--app/assets/javascripts/lib/utils/number_utils.js49
-rw-r--r--app/assets/javascripts/lib/utils/ref_validator.js145
-rw-r--r--app/assets/javascripts/lib/utils/resize_observer.js10
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js58
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js43
-rw-r--r--app/assets/javascripts/lib/utils/vue3compat/compat_functional_mixin.js14
-rw-r--r--app/assets/javascripts/lib/utils/vue3compat/mark_raw.js9
-rw-r--r--app/assets/javascripts/locale/sprintf.js4
-rw-r--r--app/assets/javascripts/main.js10
-rw-r--r--app/assets/javascripts/members/constants.js2
-rw-r--r--app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue2
-rw-r--r--app/assets/javascripts/merge_conflicts/store/actions.js2
-rw-r--r--app/assets/javascripts/merge_request.js5
-rw-r--r--app/assets/javascripts/merge_request_tabs.js2
-rw-r--r--app/assets/javascripts/merge_requests/components/compare_dropdown.vue8
-rw-r--r--app/assets/javascripts/milestones/components/delete_milestone_modal.vue4
-rw-r--r--app/assets/javascripts/milestones/components/promote_milestone_modal.vue6
-rw-r--r--app/assets/javascripts/milestones/milestone.js2
-rw-r--r--app/assets/javascripts/mirrors/mirror_repos.js2
-rw-r--r--app/assets/javascripts/mirrors/ssh_mirror.js2
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/components/ml_candidate.vue115
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue200
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/constants.js17
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/index.js3
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/ml_candidates_show.vue125
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/translations.js11
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/constants.js21
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/index.js3
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue221
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js16
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue2
-rw-r--r--app/assets/javascripts/monitoring/constants.js6
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js2
-rw-r--r--app/assets/javascripts/mr_notes/init_notes.js7
-rw-r--r--app/assets/javascripts/namespaces/leave_by_url.js2
-rw-r--r--app/assets/javascripts/nav/components/new_nav_toggle.vue30
-rw-r--r--app/assets/javascripts/nav/components/top_nav_new_dropdown.vue17
-rw-r--r--app/assets/javascripts/notebook/cells/output/error.vue40
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue10
-rw-r--r--app/assets/javascripts/notebook/index.vue4
-rw-r--r--app/assets/javascripts/notes/components/comment_field_layout.vue2
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue127
-rw-r--r--app/assets/javascripts/notes/components/discussion_locked_widget.vue6
-rw-r--r--app/assets/javascripts/notes/components/note_actions.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_body.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_edited_text.vue46
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue15
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue2
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue2
-rw-r--r--app/assets/javascripts/notes/components/toggle_replies_widget.vue6
-rw-r--r--app/assets/javascripts/notes/constants.js23
-rw-r--r--app/assets/javascripts/notes/i18n.js5
-rw-r--r--app/assets/javascripts/notes/index.js6
-rw-r--r--app/assets/javascripts/notes/mixins/diff_line_note_form.js2
-rw-r--r--app/assets/javascripts/notes/mixins/resolvable.js2
-rw-r--r--app/assets/javascripts/notes/stores/actions.js35
-rw-r--r--app/assets/javascripts/notes/stores/mutations.js5
-rw-r--r--app/assets/javascripts/observability/components/observability_app.vue60
-rw-r--r--app/assets/javascripts/observability/components/skeleton/embed.vue15
-rw-r--r--app/assets/javascripts/observability/components/skeleton/index.vue21
-rw-r--r--app/assets/javascripts/observability/constants.js12
-rw-r--r--app/assets/javascripts/observability/index.js32
-rw-r--r--app/assets/javascripts/operation_settings/store/actions.js4
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/delete_modal.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue9
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue9
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue8
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql1
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue5
-rw-r--r--app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/pages/details.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue12
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/details/store/actions.js2
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js1
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js4
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/delete_modal.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/details/maven_installation.vue10
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue45
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue5
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/details/version_row.vue20
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/functional/delete_packages.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue5
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/constants.js19
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql1
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue16
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue9
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/constants.js4
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy_form.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue2
-rw-r--r--app/assets/javascripts/pages/admin/abuse_reports/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue21
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/network/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/payload_downloader.js2
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/payload_previewer.js2
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs_modal.vue4
-rw-r--r--app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue2
-rw-r--r--app/assets/javascripts/pages/admin/runners/register/index.js3
-rw-r--r--app/assets/javascripts/pages/dashboard/todos/index/todos.js2
-rw-r--r--app/assets/javascripts/pages/groups/new/components/app.vue25
-rw-r--r--app/assets/javascripts/pages/groups/new/group_path_validator.js2
-rw-r--r--app/assets/javascripts/pages/groups/new/index.js4
-rw-r--r--app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue9
-rw-r--r--app/assets/javascripts/pages/import/history/components/import_error_details.vue2
-rw-r--r--app/assets/javascripts/pages/import/history/components/import_history_app.vue2
-rw-r--r--app/assets/javascripts/pages/profiles/index.js2
-rw-r--r--app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue2
-rw-r--r--app/assets/javascripts/pages/profiles/two_factor_auths/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/airflow/dags/index/index.js27
-rw-r--r--app/assets/javascripts/pages/projects/blame/show/index.js7
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js30
-rw-r--r--app/assets/javascripts/pages/projects/boards/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/commit/show/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue2
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue2
-rw-r--r--app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue8
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/edit/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/index/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/ml/candidates/show/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/ml/experiments/show/index.js30
-rw-r--r--app/assets/javascripts/pages/projects/project.js2
-rw-r--r--app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/settings/repository/form.js4
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue4
-rw-r--r--app/assets/javascripts/pages/registrations/new/index.js7
-rw-r--r--app/assets/javascripts/pages/sessions/new/index.js2
-rw-r--r--app/assets/javascripts/pages/sessions/new/length_validator.js45
-rw-r--r--app/assets/javascripts/pages/sessions/new/username_validator.js2
-rw-r--r--app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue2
-rw-r--r--app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue1
-rw-r--r--app/assets/javascripts/pages/shared/wikis/wikis.js11
-rw-r--r--app/assets/javascripts/pages/users/activity_calendar.js19
-rw-r--r--app/assets/javascripts/pages/users/show/index.js19
-rw-r--r--app/assets/javascripts/pages/users/user_tabs.js12
-rw-r--r--app/assets/javascripts/persistent_user_callout.js2
-rw-r--r--app/assets/javascripts/persistent_user_callouts.js2
-rw-r--r--app/assets/javascripts/pipeline_wizard/components/editor.vue13
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_item.vue7
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/jobs_app.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_tag_name_token.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue6
-rw-r--r--app/assets/javascripts/pipelines/constants.js3
-rw-r--r--app/assets/javascripts/pipelines/mixins/pipelines_mixin.js2
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_bundle.js2
-rw-r--r--app/assets/javascripts/pipelines/pipeline_tabs.js2
-rw-r--r--app/assets/javascripts/pipelines/stores/test_reports/actions.js2
-rw-r--r--app/assets/javascripts/pipelines/stores/test_reports/mutations.js2
-rw-r--r--app/assets/javascripts/profile/account/components/delete_account_modal.vue11
-rw-r--r--app/assets/javascripts/profile/account/components/update_username.vue9
-rw-r--r--app/assets/javascripts/profile/components/activity_calendar.vue100
-rw-r--r--app/assets/javascripts/profile/components/followers_tab.vue15
-rw-r--r--app/assets/javascripts/profile/components/following_tab.vue15
-rw-r--r--app/assets/javascripts/profile/components/graphql/get_user_achievements.query.graphql21
-rw-r--r--app/assets/javascripts/profile/components/overview_tab.vue5
-rw-r--r--app/assets/javascripts/profile/components/profile_tabs.vue9
-rw-r--r--app/assets/javascripts/profile/components/user_achievements.vue100
-rw-r--r--app/assets/javascripts/profile/constants.js7
-rw-r--r--app/assets/javascripts/profile/index.js36
-rw-r--r--app/assets/javascripts/profile/preferences/components/profile_preferences.vue2
-rw-r--r--app/assets/javascripts/profile/profile.js2
-rw-r--r--app/assets/javascripts/profile/utils.js13
-rw-r--r--app/assets/javascripts/projects/commit/components/branches_dropdown.vue33
-rw-r--r--app/assets/javascripts/projects/commit/components/form_modal.vue24
-rw-r--r--app/assets/javascripts/projects/commit/components/projects_dropdown.vue32
-rw-r--r--app/assets/javascripts/projects/commit/init_revert_commit_modal.js1
-rw-r--r--app/assets/javascripts/projects/commit/store/actions.js2
-rw-r--r--app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue2
-rw-r--r--app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_status.vue2
-rw-r--r--app/assets/javascripts/projects/commits/store/actions.js2
-rw-r--r--app/assets/javascripts/projects/compare/components/revision_dropdown.vue4
-rw-r--r--app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue4
-rw-r--r--app/assets/javascripts/projects/components/shared/delete_button.vue10
-rw-r--r--app/assets/javascripts/projects/new/components/app.vue24
-rw-r--r--app/assets/javascripts/projects/new/index.js6
-rw-r--r--app/assets/javascripts/projects/project_find_file.js2
-rw-r--r--app/assets/javascripts/projects/settings/access_dropdown.js15
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/components/edit/branch_dropdown.vue2
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js24
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue75
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue7
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js7
-rw-r--r--app/assets/javascripts/projects/settings/components/access_dropdown.vue7
-rw-r--r--app/assets/javascripts/projects/settings/constants.js1
-rw-r--r--app/assets/javascripts/projects/settings/mount_ref_switcher_badges.js31
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/app.vue2
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/components/branch_rule.vue11
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/mount_branch_rules.js12
-rw-r--r--app/assets/javascripts/projects/settings/topics/components/topics_token_selector.vue64
-rw-r--r--app/assets/javascripts/projects/settings/utils.js21
-rw-r--r--app/assets/javascripts/projects/star.js2
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue2
-rw-r--r--app/assets/javascripts/protected_branches/constants.js9
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_create.js2
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_edit.js2
-rw-r--r--app/assets/javascripts/protected_tags/constants.js11
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_create.js81
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_edit.js112
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_edit_list.js4
-rw-r--r--app/assets/javascripts/related_issues/components/add_issuable_form.vue2
-rw-r--r--app/assets/javascripts/related_issues/components/related_issuable_input.vue2
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_block.vue117
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_list.vue12
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_root.vue2
-rw-r--r--app/assets/javascripts/related_issues/constants.js31
-rw-r--r--app/assets/javascripts/releases/components/app_index.vue2
-rw-r--r--app/assets/javascripts/releases/components/app_show.vue2
-rw-r--r--app/assets/javascripts/releases/components/tag_field_new.vue9
-rw-r--r--app/assets/javascripts/releases/constants.js5
-rw-r--r--app/assets/javascripts/releases/release_notification_service.js2
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/actions.js2
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/getters.js11
-rw-r--r--app/assets/javascripts/repository/commits_service.js2
-rw-r--r--app/assets/javascripts/repository/components/blob_content_viewer.vue2
-rw-r--r--app/assets/javascripts/repository/components/blob_controls.vue2
-rw-r--r--app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue19
-rw-r--r--app/assets/javascripts/repository/components/delete_blob_modal.vue20
-rw-r--r--app/assets/javascripts/repository/components/fork_info.vue197
-rw-r--r--app/assets/javascripts/repository/components/fork_sync_conflicts_modal.vue137
-rw-r--r--app/assets/javascripts/repository/components/last_commit.vue7
-rw-r--r--app/assets/javascripts/repository/components/new_directory_modal.vue22
-rw-r--r--app/assets/javascripts/repository/components/tree_content.vue15
-rw-r--r--app/assets/javascripts/repository/components/upload_blob_modal.vue22
-rw-r--r--app/assets/javascripts/repository/constants.js8
-rw-r--r--app/assets/javascripts/repository/index.js9
-rw-r--r--app/assets/javascripts/repository/mutations/sync_fork.mutation.graphql11
-rw-r--r--app/assets/javascripts/repository/queries/fork_details.query.graphql2
-rw-r--r--app/assets/javascripts/right_sidebar.js2
-rw-r--r--app/assets/javascripts/saved_replies/components/app.vue2
-rw-r--r--app/assets/javascripts/saved_replies/components/form.vue182
-rw-r--r--app/assets/javascripts/saved_replies/components/list.vue56
-rw-r--r--app/assets/javascripts/saved_replies/components/list_item.vue84
-rw-r--r--app/assets/javascripts/saved_replies/pages/edit.vue68
-rw-r--r--app/assets/javascripts/saved_replies/pages/index.vue54
-rw-r--r--app/assets/javascripts/saved_replies/queries/create_saved_reply.mutation.graphql10
-rw-r--r--app/assets/javascripts/saved_replies/queries/delete_saved_reply.mutation.graphql5
-rw-r--r--app/assets/javascripts/saved_replies/queries/get_saved_reply.query.graphql10
-rw-r--r--app/assets/javascripts/saved_replies/queries/saved_replies.query.graphql4
-rw-r--r--app/assets/javascripts/saved_replies/queries/update_saved_reply.mutation.graphql10
-rw-r--r--app/assets/javascripts/saved_replies/routes.js7
-rw-r--r--app/assets/javascripts/search/sidebar/components/app.vue11
-rw-r--r--app/assets/javascripts/search/sidebar/components/checkbox_filter.vue19
-rw-r--r--app/assets/javascripts/search/sidebar/components/language_filter.vue50
-rw-r--r--app/assets/javascripts/search/sidebar/components/radio_filter.vue8
-rw-r--r--app/assets/javascripts/search/sidebar/components/results_filters.vue7
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_navigation.vue14
-rw-r--r--app/assets/javascripts/search/sidebar/utils.js27
-rw-r--r--app/assets/javascripts/search/store/actions.js31
-rw-r--r--app/assets/javascripts/search/store/getters.js12
-rw-r--r--app/assets/javascripts/search/store/mutations.js2
-rw-r--r--app/assets/javascripts/search/store/utils.js32
-rw-r--r--app/assets/javascripts/search/topbar/components/app.vue79
-rw-r--r--app/assets/javascripts/security_configuration/components/app.vue11
-rw-r--r--app/assets/javascripts/security_configuration/components/constants.js3
-rw-r--r--app/assets/javascripts/self_monitor/components/self_monitor_form.vue34
-rw-r--r--app/assets/javascripts/sentry/constants.js44
-rw-r--r--app/assets/javascripts/sentry/legacy_constants.js46
-rw-r--r--app/assets/javascripts/sentry/legacy_sentry_config.js2
-rw-r--r--app/assets/javascripts/sentry/sentry_config.js4
-rw-r--r--app/assets/javascripts/service_ping_consent.js2
-rw-r--r--app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_invite_members.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue14
-rw-r--r--app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view.vue12
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js2
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/constants.js5
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue17
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue14
-rw-r--r--app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue12
-rw-r--r--app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue11
-rw-r--r--app/assets/javascripts/sidebar/components/move/move_issue_button.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/move/move_issues_button.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/participants/participants.vue10
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/severity/sidebar_severity_widget.vue11
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown.vue16
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue13
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue18
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/report.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue5
-rw-r--r--app/assets/javascripts/sidebar/constants.js54
-rw-r--r--app/assets/javascripts/sidebar/mount_milestone_sidebar.js4
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js31
-rw-r--r--app/assets/javascripts/sidebar/queries/update_epic_due_date.mutation.graphql1
-rw-r--r--app/assets/javascripts/sidebar/queries/update_epic_start_date.mutation.graphql1
-rw-r--r--app/assets/javascripts/sidebar/sidebar_mediator.js2
-rw-r--r--app/assets/javascripts/single_file_diff.js2
-rw-r--r--app/assets/javascripts/snippets/components/edit.vue8
-rw-r--r--app/assets/javascripts/snippets/components/snippet_blob_edit.vue6
-rw-r--r--app/assets/javascripts/snippets/components/snippet_header.vue26
-rw-r--r--app/assets/javascripts/streaming/chunk_writer.js144
-rw-r--r--app/assets/javascripts/streaming/constants.js9
-rw-r--r--app/assets/javascripts/streaming/handle_streamed_anchor_link.js26
-rw-r--r--app/assets/javascripts/streaming/html_stream.js33
-rw-r--r--app/assets/javascripts/streaming/polyfills.js5
-rw-r--r--app/assets/javascripts/streaming/rate_limit_stream_requests.js87
-rw-r--r--app/assets/javascripts/streaming/render_balancer.js36
-rw-r--r--app/assets/javascripts/streaming/render_html_streams.js40
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher.vue158
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue26
-rw-r--r--app/assets/javascripts/super_sidebar/components/counter.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/create_menu.vue1
-rw-r--r--app/assets/javascripts/super_sidebar/components/frequent_items_list.vue77
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue320
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue167
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_items.vue58
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/components/global_search_scoped_items.vue87
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/constants.js33
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/store/actions.js45
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/store/getters.js220
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/store/index.js25
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/store/mutation_types.js6
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/store/mutations.js30
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/store/state.js19
-rw-r--r--app/assets/javascripts/super_sidebar/components/groups_list.vue78
-rw-r--r--app/assets/javascripts/super_sidebar/components/help_center.vue29
-rw-r--r--app/assets/javascripts/super_sidebar/components/items_list.vue40
-rw-r--r--app/assets/javascripts/super_sidebar/components/merge_request_menu.vue16
-rw-r--r--app/assets/javascripts/super_sidebar/components/nav_item.vue122
-rw-r--r--app/assets/javascripts/super_sidebar/components/projects_list.vue79
-rw-r--r--app/assets/javascripts/super_sidebar/components/search_results.vue49
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_menu.vue24
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_portal.vue30
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_portal_target.vue17
-rw-r--r--app/assets/javascripts/super_sidebar/components/super_sidebar.vue85
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_bar.vue73
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_menu.vue291
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_name_group.vue77
-rw-r--r--app/assets/javascripts/super_sidebar/constants.js14
-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/mock_data.js7
-rw-r--r--app/assets/javascripts/super_sidebar/super_sidebar_bundle.js19
-rw-r--r--app/assets/javascripts/super_sidebar/super_sidebar_collapsed_state_manager.js51
-rw-r--r--app/assets/javascripts/super_sidebar/utils.js83
-rw-r--r--app/assets/javascripts/syntax_highlight.js4
-rw-r--r--app/assets/javascripts/task_list.js2
-rw-r--r--app/assets/javascripts/terraform/components/init_command_modal.vue2
-rw-r--r--app/assets/javascripts/terraform/components/states_table_actions.vue4
-rw-r--r--app/assets/javascripts/toggles/index.js16
-rw-r--r--app/assets/javascripts/token_access/components/inbound_token_access.vue2
-rw-r--r--app/assets/javascripts/token_access/components/opt_in_jwt.vue2
-rw-r--r--app/assets/javascripts/token_access/components/outbound_token_access.vue2
-rw-r--r--app/assets/javascripts/token_access/components/token_access_app.vue9
-rw-r--r--app/assets/javascripts/token_access/components/token_projects_table.vue7
-rw-r--r--app/assets/javascripts/usage_quotas/storage/constants.js1
-rw-r--r--app/assets/javascripts/user_lists/components/add_user_modal.vue4
-rw-r--r--app/assets/javascripts/users_select/index.js7
-rw-r--r--app/assets/javascripts/validators/length_validator.js56
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue70
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue72
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approvals.query.graphql18
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql16
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/state_container.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue212
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue20
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/constants.js8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/index.js16
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mixins/approvals.js27
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue77
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/queries/get_state.subscription.graphql1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql9
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js6
-rw-r--r--app/assets/javascripts/vue_shared/alert_details/components/system_notes/system_note.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_badge_link.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_cd_analytics/ci_cd_analytics_area_chart.vue35
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row_header.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/issuable_blocked_icon/constants.js5
-rw-r--r--app/assets/javascripts/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/listbox_input/listbox_input.vue10
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/drawio_toolbar_button.vue48
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/editor_mode_dropdown.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/header.vue35
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue109
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/saved_replies.query.graphql12
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/saved_replies_dropdown.vue120
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestions.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/metric_images/store/actions.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/pagination/constants.js3
-rw-r--r--app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/resizable_chart/resizable_chart_container.vue40
-rw-r--r--app/assets/javascripts/vue_shared/components/source_editor.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/constants.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_select/user_select.vue4
-rw-r--r--app/assets/javascripts/vue_shared/constants.js6
-rw-r--r--app/assets/javascripts/vue_shared/gl_feature_flags_plugin.js16
-rw-r--r--app/assets/javascripts/vue_shared/global_search/constants.js73
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/constants.js13
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_body.vue5
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue4
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue4
-rw-r--r--app/assets/javascripts/vue_shared/new_namespace/new_namespace_page.vue58
-rw-r--r--app/assets/javascripts/vue_shared/plugins/global_toast.js2
-rw-r--r--app/assets/javascripts/vue_shared/security_reports/components/artifact_downloads/merge_request_artifact_download.vue2
-rw-r--r--app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue2
-rw-r--r--app/assets/javascripts/work_items/components/item_state.vue2
-rw-r--r--app/assets/javascripts/work_items/components/item_title.vue1
-rw-r--r--app/assets/javascripts/work_items/components/notes/activity_filter.vue113
-rw-r--r--app/assets/javascripts/work_items/components/notes/system_note.vue2
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_activity_sort_filter.vue116
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_add_note.vue72
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue62
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_comment_locked.vue6
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_discussion.vue164
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_history_only_filter_note.vue61
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note.vue161
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue61
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note_body.vue5
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note_replying.vue20
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note_signed_out.vue2
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_notes_activity_header.vue91
-rw-r--r--app/assets/javascripts/work_items/components/widget_wrapper.vue8
-rw-r--r--app/assets/javascripts/work_items/components/work_item_actions.vue1
-rw-r--r--app/assets/javascripts/work_items/components/work_item_assignees.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_description.vue1
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue455
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail_modal.vue25
-rw-r--r--app/assets/javascripts/work_items/components/work_item_due_date.vue14
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/index.js2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue17
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_link_child_metadata.vue4
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue24
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue4
-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_links/work_item_tree_children.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_milestone.vue1
-rw-r--r--app/assets/javascripts/work_items/components/work_item_notes.vue140
-rw-r--r--app/assets/javascripts/work_items/constants.js31
-rw-r--r--app/assets/javascripts/work_items/graphql/cache_utils.js130
-rw-r--r--app/assets/javascripts/work_items/graphql/get_issue_details.query.graphql11
-rw-r--r--app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql1
-rw-r--r--app/assets/javascripts/work_items/graphql/notes/work_item_note_add_award_emoji.mutation.graphql17
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_links.query.graphql39
-rw-r--r--app/assets/javascripts/work_items/index.js2
-rw-r--r--app/assets/javascripts/work_items/pages/create_work_item.vue2
-rw-r--r--app/assets/javascripts/work_items/router/index.js2
-rw-r--r--app/assets/javascripts/zen_mode.js8
-rw-r--r--app/assets/stylesheets/_page_specific_files.scss1
-rw-r--r--app/assets/stylesheets/components/content_editor.scss1
-rw-r--r--app/assets/stylesheets/components/related_items_list.scss65
-rw-r--r--app/assets/stylesheets/framework/buttons.scss1
-rw-r--r--app/assets/stylesheets/framework/diffs.scss15
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss28
-rw-r--r--app/assets/stylesheets/framework/files.scss28
-rw-r--r--app/assets/stylesheets/framework/filters.scss5
-rw-r--r--app/assets/stylesheets/framework/forms.scss27
-rw-r--r--app/assets/stylesheets/framework/header.scss28
-rw-r--r--app/assets/stylesheets/framework/mixins.scss12
-rw-r--r--app/assets/stylesheets/framework/modal.scss2
-rw-r--r--app/assets/stylesheets/framework/page_title.scss2
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss7
-rw-r--r--app/assets/stylesheets/framework/super_sidebar.scss186
-rw-r--r--app/assets/stylesheets/framework/system_messages.scss3
-rw-r--r--app/assets/stylesheets/framework/tables.scss2
-rw-r--r--app/assets/stylesheets/framework/timeline.scss1
-rw-r--r--app/assets/stylesheets/framework/typography.scss3
-rw-r--r--app/assets/stylesheets/framework/variables.scss11
-rw-r--r--app/assets/stylesheets/framework/wells.scss4
-rw-r--r--app/assets/stylesheets/highlight/diff_custom_colors_addition.scss2
-rw-r--r--app/assets/stylesheets/page_bundles/admin/geo_nodes.scss45
-rw-r--r--app/assets/stylesheets/page_bundles/admin/geo_sites.scss45
-rw-r--r--app/assets/stylesheets/page_bundles/incidents.scss2
-rw-r--r--app/assets/stylesheets/page_bundles/issuable.scss22
-rw-r--r--app/assets/stylesheets/page_bundles/jira_connect.scss2
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss45
-rw-r--r--app/assets/stylesheets/page_bundles/milestone.scss4
-rw-r--r--app/assets/stylesheets/page_bundles/ml_experiment_tracking.scss20
-rw-r--r--app/assets/stylesheets/page_bundles/profile.scss4
-rw-r--r--app/assets/stylesheets/page_bundles/settings.scss22
-rw-r--r--app/assets/stylesheets/page_bundles/tree.scss3
-rw-r--r--app/assets/stylesheets/page_bundles/wiki.scss61
-rw-r--r--app/assets/stylesheets/page_bundles/work_items.scss21
-rw-r--r--app/assets/stylesheets/pages/commits.scss4
-rw-r--r--app/assets/stylesheets/pages/detail_page.scss6
-rw-r--r--app/assets/stylesheets/pages/issues.scss45
-rw-r--r--app/assets/stylesheets/pages/labels.scss49
-rw-r--r--app/assets/stylesheets/pages/ml_experiment_tracking.scss36
-rw-r--r--app/assets/stylesheets/pages/notes.scss34
-rw-r--r--app/assets/stylesheets/pages/profile.scss7
-rw-r--r--app/assets/stylesheets/print.scss1
-rw-r--r--app/assets/stylesheets/startup/startup-dark.scss48
-rw-r--r--app/assets/stylesheets/startup/startup-general.scss48
-rw-r--r--app/assets/stylesheets/startup/startup-signin.scss15
-rw-r--r--app/assets/stylesheets/themes/dark_mode_overrides.scss11
-rw-r--r--app/assets/stylesheets/utilities.scss55
-rw-r--r--app/controllers/admin/abuse_reports_controller.rb8
-rw-r--r--app/controllers/admin/application_settings_controller.rb7
-rw-r--r--app/controllers/admin/applications_controller.rb29
-rw-r--r--app/controllers/admin/broadcast_messages_controller.rb2
-rw-r--r--app/controllers/admin/ci/variables_controller.rb7
-rw-r--r--app/controllers/admin/cohorts_controller.rb2
-rw-r--r--app/controllers/admin/dev_ops_report_controller.rb2
-rw-r--r--app/controllers/admin/groups_controller.rb4
-rw-r--r--app/controllers/admin/identities_controller.rb2
-rw-r--r--app/controllers/admin/impersonation_tokens_controller.rb2
-rw-r--r--app/controllers/admin/impersonations_controller.rb2
-rw-r--r--app/controllers/admin/keys_controller.rb2
-rw-r--r--app/controllers/admin/projects_controller.rb27
-rw-r--r--app/controllers/admin/runners_controller.rb9
-rw-r--r--app/controllers/admin/sessions_controller.rb2
-rw-r--r--app/controllers/admin/spam_logs_controller.rb6
-rw-r--r--app/controllers/admin/topics_controller.rb4
-rw-r--r--app/controllers/admin/usage_trends_controller.rb2
-rw-r--r--app/controllers/application_controller.rb10
-rw-r--r--app/controllers/chaos_controller.rb5
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb33
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb22
-rw-r--r--app/controllers/concerns/confirm_email_warning.rb2
-rw-r--r--app/controllers/concerns/cycle_analytics_params.rb3
-rw-r--r--app/controllers/concerns/enforces_two_factor_authentication.rb3
-rw-r--r--app/controllers/concerns/integrations/params.rb3
-rw-r--r--app/controllers/concerns/invisible_captcha_on_signup.rb14
-rw-r--r--app/controllers/concerns/issuable_actions.rb21
-rw-r--r--app/controllers/concerns/kas_cookie.rb16
-rw-r--r--app/controllers/concerns/known_sign_in.rb9
-rw-r--r--app/controllers/concerns/membership_actions.rb4
-rw-r--r--app/controllers/concerns/notes_actions.rb3
-rw-r--r--app/controllers/concerns/observability/content_security_policy.rb12
-rw-r--r--app/controllers/concerns/product_analytics_tracking.rb83
-rw-r--r--app/controllers/concerns/registrations_tracking.rb2
-rw-r--r--app/controllers/concerns/renders_notes.rb4
-rw-r--r--app/controllers/concerns/renders_projects_list.rb1
-rw-r--r--app/controllers/concerns/sorting_preference.rb4
-rw-r--r--app/controllers/concerns/uploads_actions.rb1
-rw-r--r--app/controllers/concerns/wiki_actions.rb19
-rw-r--r--app/controllers/confirmations_controller.rb12
-rw-r--r--app/controllers/dashboard/projects_controller.rb4
-rw-r--r--app/controllers/dashboard/todos_controller.rb4
-rw-r--r--app/controllers/explore/groups_controller.rb7
-rw-r--r--app/controllers/graphql_controller.rb14
-rw-r--r--app/controllers/groups/children_controller.rb31
-rw-r--r--app/controllers/groups/dependency_proxy_for_containers_controller.rb2
-rw-r--r--app/controllers/groups/group_links_controller.rb2
-rw-r--r--app/controllers/groups/group_members_controller.rb5
-rw-r--r--app/controllers/groups/observability_controller.rb2
-rw-r--r--app/controllers/groups/settings/access_tokens_controller.rb2
-rw-r--r--app/controllers/groups/settings/applications_controller.rb30
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb5
-rw-r--r--app/controllers/groups/variables_controller.rb2
-rw-r--r--app/controllers/groups_controller.rb6
-rw-r--r--app/controllers/ide_controller.rb16
-rw-r--r--app/controllers/import/bulk_imports_controller.rb3
-rw-r--r--app/controllers/import/fogbugz_controller.rb2
-rw-r--r--app/controllers/import/gitea_controller.rb5
-rw-r--r--app/controllers/import/github_controller.rb22
-rw-r--r--app/controllers/invites_controller.rb2
-rw-r--r--app/controllers/jira_connect/public_keys_controller.rb2
-rw-r--r--app/controllers/jwt_controller.rb2
-rw-r--r--app/controllers/metrics_controller.rb7
-rw-r--r--app/controllers/oauth/applications_controller.rb27
-rw-r--r--app/controllers/oauth/authorizations_controller.rb8
-rw-r--r--app/controllers/oauth/authorized_applications_controller.rb4
-rw-r--r--app/controllers/oauth/jira_dvcs/authorizations_controller.rb10
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb7
-rw-r--r--app/controllers/passwords_controller.rb2
-rw-r--r--app/controllers/profiles/accounts_controller.rb2
-rw-r--r--app/controllers/profiles/active_sessions_controller.rb2
-rw-r--r--app/controllers/profiles/emails_controller.rb4
-rw-r--r--app/controllers/profiles/notifications_controller.rb5
-rw-r--r--app/controllers/profiles/passwords_controller.rb2
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb7
-rw-r--r--app/controllers/profiles/two_factor_auths_controller.rb44
-rw-r--r--app/controllers/profiles/u2f_registrations_controller.rb11
-rw-r--r--app/controllers/profiles/webauthn_registrations_controller.rb2
-rw-r--r--app/controllers/profiles_controller.rb2
-rw-r--r--app/controllers/projects/airflow/dags_controller.rb38
-rw-r--r--app/controllers/projects/analytics/cycle_analytics/stages_controller.rb5
-rw-r--r--app/controllers/projects/analytics/cycle_analytics/summary_controller.rb6
-rw-r--r--app/controllers/projects/artifacts_controller.rb4
-rw-r--r--app/controllers/projects/avatars_controller.rb2
-rw-r--r--app/controllers/projects/badges_controller.rb1
-rw-r--r--app/controllers/projects/blame_controller.rb38
-rw-r--r--app/controllers/projects/blob_controller.rb42
-rw-r--r--app/controllers/projects/branches_controller.rb2
-rw-r--r--app/controllers/projects/ci/lints_controller.rb2
-rw-r--r--app/controllers/projects/ci/pipeline_editor_controller.rb2
-rw-r--r--app/controllers/projects/ci/prometheus_metrics/histograms_controller.rb2
-rw-r--r--app/controllers/projects/cluster_agents_controller.rb3
-rw-r--r--app/controllers/projects/commit_controller.rb19
-rw-r--r--app/controllers/projects/commits_controller.rb14
-rw-r--r--app/controllers/projects/cycle_analytics_controller.rb6
-rw-r--r--app/controllers/projects/design_management/designs/raw_images_controller.rb2
-rw-r--r--app/controllers/projects/design_management/designs/resized_image_controller.rb2
-rw-r--r--app/controllers/projects/environments_controller.rb33
-rw-r--r--app/controllers/projects/error_tracking_controller.rb3
-rw-r--r--app/controllers/projects/feature_flags_controller.rb53
-rw-r--r--app/controllers/projects/google_cloud/base_controller.rb4
-rw-r--r--app/controllers/projects/graphs_controller.rb2
-rw-r--r--app/controllers/projects/hooks_controller.rb7
-rw-r--r--app/controllers/projects/issues_controller.rb18
-rw-r--r--app/controllers/projects/jobs_controller.rb17
-rw-r--r--app/controllers/projects/labels_controller.rb24
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb9
-rw-r--r--app/controllers/projects/merge_requests_controller.rb19
-rw-r--r--app/controllers/projects/pages_controller.rb14
-rw-r--r--app/controllers/projects/pages_domains_controller.rb4
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb11
-rw-r--r--app/controllers/projects/pipelines_controller.rb30
-rw-r--r--app/controllers/projects/prometheus/metrics_controller.rb4
-rw-r--r--app/controllers/projects/raw_controller.rb2
-rw-r--r--app/controllers/projects/repositories_controller.rb13
-rw-r--r--app/controllers/projects/security/configuration_controller.rb4
-rw-r--r--app/controllers/projects/settings/access_tokens_controller.rb2
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb2
-rw-r--r--app/controllers/projects/tree_controller.rb9
-rw-r--r--app/controllers/projects/variables_controller.rb2
-rw-r--r--app/controllers/projects/web_ide_terminals_controller.rb5
-rw-r--r--app/controllers/projects/work_items_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb4
-rw-r--r--app/controllers/registrations/welcome_controller.rb4
-rw-r--r--app/controllers/registrations_controller.rb24
-rw-r--r--app/controllers/repositories/git_http_controller.rb6
-rw-r--r--app/controllers/repositories/lfs_api_controller.rb16
-rw-r--r--app/controllers/repositories/lfs_locks_api_controller.rb4
-rw-r--r--app/controllers/search_controller.rb17
-rw-r--r--app/controllers/sessions_controller.rb12
-rw-r--r--app/controllers/snippets_controller.rb10
-rw-r--r--app/controllers/users_controller.rb35
-rw-r--r--app/finders/abuse_reports_finder.rb82
-rw-r--r--app/finders/autocomplete/users_finder.rb2
-rw-r--r--app/finders/ci/pipelines_finder.rb9
-rw-r--r--app/finders/concerns/updated_at_filter.rb10
-rw-r--r--app/finders/deployments_finder.rb9
-rw-r--r--app/finders/group_members_finder.rb7
-rw-r--r--app/finders/groups/accepting_project_shares_finder.rb2
-rw-r--r--app/finders/issuable_finder.rb8
-rw-r--r--app/finders/merge_requests_finder.rb15
-rw-r--r--app/finders/milestones_finder.rb16
-rw-r--r--app/finders/serverless_domain_finder.rb35
-rw-r--r--app/graphql/mutations/achievements/award.rb38
-rw-r--r--app/graphql/mutations/achievements/revoke.rb33
-rw-r--r--app/graphql/mutations/alert_management/base.rb2
-rw-r--r--app/graphql/mutations/ci/job_artifact/bulk_destroy.rb69
-rw-r--r--app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb2
-rw-r--r--app/graphql/mutations/ci/project_ci_cd_settings_update.rb2
-rw-r--r--app/graphql/mutations/ci/runner/common_mutation_arguments.rb50
-rw-r--r--app/graphql/mutations/ci/runner/create.rb44
-rw-r--r--app/graphql/mutations/ci/runner/update.rb39
-rw-r--r--app/graphql/mutations/clusters/agent_tokens/create.rb4
-rw-r--r--app/graphql/mutations/clusters/agent_tokens/revoke.rb3
-rw-r--r--app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb4
-rw-r--r--app/graphql/mutations/design_management/update.rb39
-rw-r--r--app/graphql/mutations/issues/bulk_update.rb23
-rw-r--r--app/graphql/mutations/members/bulk_update_base.rb88
-rw-r--r--app/graphql/mutations/members/groups/bulk_update.rb77
-rw-r--r--app/graphql/mutations/members/projects/bulk_update.rb26
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/create.rb2
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/delete.rb2
-rw-r--r--app/graphql/mutations/projects/sync_fork.rb61
-rw-r--r--app/graphql/mutations/release_asset_links/create.rb14
-rw-r--r--app/graphql/mutations/release_asset_links/delete.rb12
-rw-r--r--app/graphql/mutations/release_asset_links/update.rb12
-rw-r--r--app/graphql/mutations/work_items/export.rb48
-rw-r--r--app/graphql/mutations/work_items/update.rb19
-rw-r--r--app/graphql/queries/repository/path_last_commit.query.graphql25
-rw-r--r--app/graphql/resolvers/achievements/achievements_resolver.rb27
-rw-r--r--app/graphql/resolvers/achievements/user_achievements_resolver.rb33
-rw-r--r--app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb58
-rw-r--r--app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb62
-rw-r--r--app/graphql/resolvers/analytics/cycle_analytics/issue_count_resolver.rb37
-rw-r--r--app/graphql/resolvers/ci/pipeline_job_artifacts_resolver.rb2
-rw-r--r--app/graphql/resolvers/ci/runner_projects_resolver.rb6
-rw-r--r--app/graphql/resolvers/ci/runner_resolver.rb8
-rw-r--r--app/graphql/resolvers/ci/runners_resolver.rb29
-rw-r--r--app/graphql/resolvers/concerns/work_items/shared_filter_arguments.rb28
-rw-r--r--app/graphql/resolvers/project_merge_requests_resolver.rb8
-rw-r--r--app/graphql/resolvers/projects/fork_details_resolver.rb11
-rw-r--r--app/graphql/resolvers/work_items_resolver.rb36
-rw-r--r--app/graphql/types/achievements/achievement_type.rb6
-rw-r--r--app/graphql/types/achievements/user_achievement_type.rb51
-rw-r--r--app/graphql/types/analytics/cycle_analytics/flow_metrics.rb30
-rw-r--r--app/graphql/types/analytics/cycle_analytics/link_type.rb33
-rw-r--r--app/graphql/types/analytics/cycle_analytics/metric_type.rb39
-rw-r--r--app/graphql/types/board_list_type.rb2
-rw-r--r--app/graphql/types/ci/job_type.rb34
-rw-r--r--app/graphql/types/ci/runner_machine_type.rb51
-rw-r--r--app/graphql/types/ci/runner_type.rb28
-rw-r--r--app/graphql/types/commit_signatures/ssh_signature_type.rb17
-rw-r--r--app/graphql/types/design_management/design_type.rb7
-rw-r--r--app/graphql/types/issuable_subscription_event_enum.rb11
-rw-r--r--app/graphql/types/mutation_type.rb10
-rw-r--r--app/graphql/types/namespace_type.rb8
-rw-r--r--app/graphql/types/packages/package_details_type.rb4
-rw-r--r--app/graphql/types/permission_types/ci/pipeline_schedules.rb9
-rw-r--r--app/graphql/types/project_type.rb10
-rw-r--r--app/graphql/types/projects/fork_details_type.rb26
-rw-r--r--app/graphql/types/projects/namespace_project_sort_enum.rb5
-rw-r--r--app/graphql/types/root_storage_statistics_type.rb1
-rw-r--r--app/graphql/types/user_interface.rb9
-rw-r--r--app/graphql/types/work_items/available_export_fields_enum.rb17
-rw-r--r--app/graphql/types/work_items/widget_interface.rb5
-rw-r--r--app/graphql/types/work_items/widgets/notifications_type.rb26
-rw-r--r--app/graphql/types/work_items/widgets/notifications_update_input_type.rb16
-rw-r--r--app/helpers/admin/abuse_reports_helper.rb19
-rw-r--r--app/helpers/analytics/cycle_analytics_helper.rb29
-rw-r--r--app/helpers/application_helper.rb22
-rw-r--r--app/helpers/application_settings_helper.rb17
-rw-r--r--app/helpers/artifacts_helper.rb1
-rw-r--r--app/helpers/blob_helper.rb30
-rw-r--r--app/helpers/ci/catalog/resources_helper.rb15
-rw-r--r--app/helpers/ci/pipeline_editor_helper.rb2
-rw-r--r--app/helpers/ci/status_helper.rb4
-rw-r--r--app/helpers/commits_helper.rb45
-rw-r--r--app/helpers/dashboard_helper.rb13
-rw-r--r--app/helpers/device_registration_helper.rb11
-rw-r--r--app/helpers/diff_helper.rb6
-rw-r--r--app/helpers/dropdowns_helper.rb2
-rw-r--r--app/helpers/events_helper.rb46
-rw-r--r--app/helpers/explore_helper.rb2
-rw-r--r--app/helpers/feature_flags_helper.rb6
-rw-r--r--app/helpers/groups/observability_helper.rb19
-rw-r--r--app/helpers/groups_helper.rb1
-rw-r--r--app/helpers/ide_helper.rb22
-rw-r--r--app/helpers/issuables_helper.rb12
-rw-r--r--app/helpers/jira_connect_helper.rb2
-rw-r--r--app/helpers/markup_helper.rb21
-rw-r--r--app/helpers/merge_requests_helper.rb5
-rw-r--r--app/helpers/mirror_helper.rb2
-rw-r--r--app/helpers/nav/new_dropdown_helper.rb38
-rw-r--r--app/helpers/nav/top_nav_helper.rb72
-rw-r--r--app/helpers/nav_helper.rb35
-rw-r--r--app/helpers/notes_helper.rb7
-rw-r--r--app/helpers/operations_helper.rb2
-rw-r--r--app/helpers/packages_helper.rb11
-rw-r--r--app/helpers/page_layout_helper.rb2
-rw-r--r--app/helpers/plan_limits_helper.rb28
-rw-r--r--app/helpers/projects/error_tracking_helper.rb3
-rw-r--r--app/helpers/projects/settings/branch_rules_helper.rb23
-rw-r--r--app/helpers/projects_helper.rb17
-rw-r--r--app/helpers/registrations_helper.rb4
-rw-r--r--app/helpers/routing/projects_helper.rb7
-rw-r--r--app/helpers/search_helper.rb4
-rw-r--r--app/helpers/sidebars_helper.rb112
-rw-r--r--app/helpers/snippets_helper.rb37
-rw-r--r--app/helpers/sorting_helper.rb6
-rw-r--r--app/helpers/system_note_helper.rb2
-rw-r--r--app/helpers/todos_helper.rb14
-rw-r--r--app/helpers/users/callouts_helper.rb35
-rw-r--r--app/helpers/users/group_callouts_helper.rb8
-rw-r--r--app/helpers/users_helper.rb34
-rw-r--r--app/helpers/visibility_level_helper.rb5
-rw-r--r--app/helpers/web_hooks/web_hooks_helper.rb22
-rw-r--r--app/helpers/work_items_helper.rb3
-rw-r--r--app/mailers/emails/issues.rb13
-rw-r--r--app/mailers/emails/profile.rb2
-rw-r--r--app/mailers/emails/shared.rb20
-rw-r--r--app/mailers/emails/work_items.rb19
-rw-r--r--app/mailers/notify.rb2
-rw-r--r--app/mailers/previews/notify_preview.rb12
-rw-r--r--app/models/ability.rb7
-rw-r--r--app/models/abuse_report.rb9
-rw-r--r--app/models/achievements/user_achievement.rb8
-rw-r--r--app/models/airflow.rb6
-rw-r--r--app/models/airflow/dags.rb14
-rw-r--r--app/models/alert_management/alert.rb7
-rw-r--r--app/models/alert_management/alert_assignee.rb2
-rw-r--r--app/models/alert_management/alert_user_mention.rb5
-rw-r--r--app/models/application_setting.rb101
-rw-r--r--app/models/application_setting_implementation.rb5
-rw-r--r--app/models/audit_event.rb2
-rw-r--r--app/models/badge.rb2
-rw-r--r--app/models/board.rb4
-rw-r--r--app/models/bulk_import.rb13
-rw-r--r--app/models/bulk_imports/batch_tracker.rb46
-rw-r--r--app/models/bulk_imports/entity.rb23
-rw-r--r--app/models/bulk_imports/export.rb1
-rw-r--r--app/models/bulk_imports/export_batch.rb33
-rw-r--r--app/models/bulk_imports/export_upload.rb1
-rw-r--r--app/models/bulk_imports/file_transfer.rb4
-rw-r--r--app/models/bulk_imports/file_transfer/base_config.rb3
-rw-r--r--app/models/bulk_imports/tracker.rb3
-rw-r--r--app/models/chat_name.rb4
-rw-r--r--app/models/ci/build.rb46
-rw-r--r--app/models/ci/build_metadata.rb4
-rw-r--r--app/models/ci/build_pending_state.rb2
-rw-r--r--app/models/ci/build_trace_chunk.rb2
-rw-r--r--app/models/ci/catalog/listing.rb34
-rw-r--r--app/models/ci/catalog/resource.rb16
-rw-r--r--app/models/ci/daily_build_group_report_result.rb5
-rw-r--r--app/models/ci/job_artifact.rb4
-rw-r--r--app/models/ci/job_token/scope.rb3
-rw-r--r--app/models/ci/job_variable.rb2
-rw-r--r--app/models/ci/pipeline.rb53
-rw-r--r--app/models/ci/pipeline_schedule.rb11
-rw-r--r--app/models/ci/resource_group.rb19
-rw-r--r--app/models/ci/runner.rb61
-rw-r--r--app/models/ci/runner_machine.rb51
-rw-r--r--app/models/ci/runner_machine_build.rb26
-rw-r--r--app/models/ci/runner_version.rb3
-rw-r--r--app/models/ci/sources/pipeline.rb1
-rw-r--r--app/models/ci/stage.rb3
-rw-r--r--app/models/clusters/applications/crossplane.rb58
-rw-r--r--app/models/clusters/applications/knative.rb14
-rw-r--r--app/models/clusters/applications/prometheus.rb126
-rw-r--r--app/models/clusters/cluster.rb10
-rw-r--r--app/models/clusters/platforms/kubernetes.rb3
-rw-r--r--app/models/commit.rb3
-rw-r--r--app/models/commit_collection.rb17
-rw-r--r--app/models/commit_range.rb2
-rw-r--r--app/models/commit_status.rb20
-rw-r--r--app/models/concerns/analytics/cycle_analytics/stageable.rb9
-rw-r--r--app/models/concerns/atomic_internal_id.rb12
-rw-r--r--app/models/concerns/cached_commit.rb5
-rw-r--r--app/models/concerns/cascading_namespace_setting_attribute.rb21
-rw-r--r--app/models/concerns/ci/has_status.rb3
-rw-r--r--app/models/concerns/ci/partitionable.rb21
-rw-r--r--app/models/concerns/ci/partitionable/partitioned_filter.rb41
-rw-r--r--app/models/concerns/counter_attribute.rb50
-rw-r--r--app/models/concerns/each_batch.rb76
-rw-r--r--app/models/concerns/enum_with_nil.rb26
-rw-r--r--app/models/concerns/has_unique_internal_users.rb2
-rw-r--r--app/models/concerns/has_user_type.rb14
-rw-r--r--app/models/concerns/issuable.rb8
-rw-r--r--app/models/concerns/noteable.rb1
-rw-r--r--app/models/concerns/packages/debian/component_file.rb4
-rw-r--r--app/models/concerns/partitioned_table.rb3
-rw-r--r--app/models/concerns/redis_cacheable.rb8
-rw-r--r--app/models/concerns/referable.rb6
-rw-r--r--app/models/concerns/routable.rb57
-rw-r--r--app/models/concerns/subscribable.rb13
-rw-r--r--app/models/concerns/token_authenticatable_strategies/base.rb19
-rw-r--r--app/models/concerns/token_authenticatable_strategies/encrypted.rb6
-rw-r--r--app/models/concerns/token_authenticatable_strategies/encryption_helper.rb2
-rw-r--r--app/models/concerns/uniquify.rb40
-rw-r--r--app/models/concerns/web_hooks/auto_disabling.rb101
-rw-r--r--app/models/concerns/web_hooks/has_web_hooks.rb12
-rw-r--r--app/models/concerns/web_hooks/unstoppable.rb29
-rw-r--r--app/models/container_registry/data_repair_detail.rb10
-rw-r--r--app/models/container_registry/event.rb16
-rw-r--r--app/models/container_repository.rb10
-rw-r--r--app/models/dependency_proxy/manifest.rb5
-rw-r--r--app/models/dependency_proxy/registry.rb2
-rw-r--r--app/models/design_management/design.rb12
-rw-r--r--app/models/draft_note.rb2
-rw-r--r--app/models/error_tracking/project_error_tracking_setting.rb2
-rw-r--r--app/models/group.rb35
-rw-r--r--app/models/hooks/project_hook.rb1
-rw-r--r--app/models/hooks/service_hook.rb1
-rw-r--r--app/models/hooks/system_hook.rb1
-rw-r--r--app/models/hooks/web_hook.rb55
-rw-r--r--app/models/import_failure.rb5
-rw-r--r--app/models/integration.rb5
-rw-r--r--app/models/integrations/apple_app_store.rb18
-rw-r--r--app/models/integrations/base_slack_notification.rb2
-rw-r--r--app/models/integrations/base_slash_commands.rb16
-rw-r--r--app/models/integrations/campfire.rb4
-rw-r--r--app/models/integrations/google_play.rb88
-rw-r--r--app/models/integrations/jira.rb2
-rw-r--r--app/models/integrations/mattermost_slash_commands.rb10
-rw-r--r--app/models/integrations/slack_slash_commands.rb10
-rw-r--r--app/models/integrations/squash_tm.rb82
-rw-r--r--app/models/issue.rb41
-rw-r--r--app/models/member.rb6
-rw-r--r--app/models/members/member_role.rb49
-rw-r--r--app/models/members_preloader.rb17
-rw-r--r--app/models/merge_request.rb21
-rw-r--r--app/models/merge_request_diff_commit.rb2
-rw-r--r--app/models/milestone.rb4
-rw-r--r--app/models/namespace.rb98
-rw-r--r--app/models/namespaces/ldap_setting.rb11
-rw-r--r--app/models/namespaces/traversal/linear.rb24
-rw-r--r--app/models/note.rb12
-rw-r--r--app/models/oauth_access_token.rb2
-rw-r--r--app/models/onboarding/completion.rb49
-rw-r--r--app/models/operations/feature_flag.rb2
-rw-r--r--app/models/packages/debian.rb2
-rw-r--r--app/models/packages/debian/file_metadatum.rb6
-rw-r--r--app/models/packages/rpm/repository_file.rb2
-rw-r--r--app/models/pages/lookup_path.rb14
-rw-r--r--app/models/pages_domain.rb19
-rw-r--r--app/models/personal_access_token.rb13
-rw-r--r--app/models/preloaders/commit_status_preloader.rb7
-rw-r--r--app/models/preloaders/labels_preloader.rb17
-rw-r--r--app/models/preloaders/project_policy_preloader.rb5
-rw-r--r--app/models/preloaders/project_root_ancestor_preloader.rb2
-rw-r--r--app/models/preloaders/runner_machine_policy_preloader.rb23
-rw-r--r--app/models/preloaders/user_max_access_level_in_groups_preloader.rb12
-rw-r--r--app/models/project.rb202
-rw-r--r--app/models/project_ci_cd_setting.rb4
-rw-r--r--app/models/project_feature.rb6
-rw-r--r--app/models/project_setting.rb9
-rw-r--r--app/models/projects/data_transfer.rb8
-rw-r--r--app/models/projects/forks/details.rb102
-rw-r--r--app/models/projects/forks/divergence_counts.rb72
-rw-r--r--app/models/projects/import_export/relation_export.rb14
-rw-r--r--app/models/protected_branch.rb35
-rw-r--r--app/models/repository.rb46
-rw-r--r--app/models/resource_label_event.rb5
-rw-r--r--app/models/resource_milestone_event.rb4
-rw-r--r--app/models/serverless/domain.rb44
-rw-r--r--app/models/serverless/domain_cluster.rb39
-rw-r--r--app/models/serverless/function.rb26
-rw-r--r--app/models/serverless/lookup_path.rb30
-rw-r--r--app/models/serverless/virtual_domain.rb22
-rw-r--r--app/models/service_desk.rb7
-rw-r--r--app/models/service_desk/custom_email_verification.rb55
-rw-r--r--app/models/service_desk_setting.rb25
-rw-r--r--app/models/snippet.rb11
-rw-r--r--app/models/system_note_metadata.rb3
-rw-r--r--app/models/user.rb53
-rw-r--r--app/models/user_status.rb2
-rw-r--r--app/models/users/banned_user.rb2
-rw-r--r--app/models/users/callout.rb3
-rw-r--r--app/models/users/group_callout.rb4
-rw-r--r--app/models/wiki.rb5
-rw-r--r--app/models/wiki_directory.rb60
-rw-r--r--app/models/work_item.rb20
-rw-r--r--app/models/work_items/widget_definition.rb3
-rw-r--r--app/models/work_items/widgets/notifications.rb9
-rw-r--r--app/policies/achievements/user_achievement_policy.rb7
-rw-r--r--app/policies/ci/pipeline_schedule_policy.rb4
-rw-r--r--app/policies/ci/runner_machine_policy.rb18
-rw-r--r--app/policies/clusters/instance_policy.rb1
-rw-r--r--app/policies/concerns/archived_abilities.rb1
-rw-r--r--app/policies/global_policy.rb6
-rw-r--r--app/policies/group_policy.rb29
-rw-r--r--app/policies/issue_policy.rb1
-rw-r--r--app/policies/project_hook_policy.rb3
-rw-r--r--app/policies/project_policy.rb26
-rw-r--r--app/presenters/README.md12
-rw-r--r--app/presenters/ci/build_runner_presenter.rb6
-rw-r--r--app/presenters/commit_presenter.rb4
-rw-r--r--app/presenters/event_presenter.rb2
-rw-r--r--app/presenters/label_presenter.rb18
-rw-r--r--app/presenters/merge_request_presenter.rb20
-rw-r--r--app/presenters/project_presenter.rb262
-rw-r--r--app/presenters/snippet_blob_presenter.rb8
-rw-r--r--app/serializers/admin/abuse_report_entity.rb16
-rw-r--r--app/serializers/admin/abuse_report_serializer.rb7
-rw-r--r--app/serializers/cluster_application_entity.rb20
-rw-r--r--app/serializers/cluster_entity.rb1
-rw-r--r--app/serializers/cluster_serializer.rb2
-rw-r--r--app/serializers/pipeline_details_entity.rb10
-rw-r--r--app/serializers/profile/event_entity.rb125
-rw-r--r--app/serializers/profile/event_serializer.rb7
-rw-r--r--app/serializers/project_import_entity.rb7
-rw-r--r--app/services/achievements/award_service.rb48
-rw-r--r--app/services/achievements/revoke_service.rb47
-rw-r--r--app/services/authorized_project_update/project_recalculate_service.rb2
-rw-r--r--app/services/base_container_service.rb22
-rw-r--r--app/services/bulk_imports/archive_extraction_service.rb11
-rw-r--r--app/services/ci/catalog/add_resource_service.rb41
-rw-r--r--app/services/ci/catalog/validate_resource_service.rb46
-rw-r--r--app/services/ci/create_pipeline_service.rb3
-rw-r--r--app/services/ci/job_artifacts/bulk_delete_by_project_service.rb73
-rw-r--r--app/services/ci/job_artifacts/create_service.rb16
-rw-r--r--app/services/ci/job_artifacts/destroy_all_expired_service.rb22
-rw-r--r--app/services/ci/job_artifacts/destroy_batch_service.rb21
-rw-r--r--app/services/ci/job_token_scope/add_project_service.rb2
-rw-r--r--app/services/ci/pipeline_processing/atomic_processing_service.rb24
-rw-r--r--app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb30
-rw-r--r--app/services/ci/pipeline_schedules/take_ownership_service.rb2
-rw-r--r--app/services/ci/process_build_service.rb34
-rw-r--r--app/services/ci/queue/pending_builds_strategy.rb7
-rw-r--r--app/services/ci/register_job_service.rb2
-rw-r--r--app/services/ci/runners/create_runner_service.rb2
-rw-r--r--app/services/ci/runners/process_runner_version_update_service.rb5
-rw-r--r--app/services/ci/update_build_queue_service.rb2
-rw-r--r--app/services/clusters/agent_tokens/create_service.rb20
-rw-r--r--app/services/clusters/agent_tokens/revoke_service.rb46
-rw-r--r--app/services/clusters/agents/authorize_proxy_user_service.rb99
-rw-r--r--app/services/clusters/agents/create_activity_event_service.rb4
-rw-r--r--app/services/commits/change_service.rb20
-rw-r--r--app/services/concerns/incident_management/usage_data.rb2
-rw-r--r--app/services/concerns/update_repository_storage_methods.rb9
-rw-r--r--app/services/container_expiration_policies/cleanup_service.rb1
-rw-r--r--app/services/dependency_proxy/head_manifest_service.rb2
-rw-r--r--app/services/event_create_service.rb47
-rw-r--r--app/services/feature_flags/base_service.rb34
-rw-r--r--app/services/feature_flags/create_service.rb10
-rw-r--r--app/services/feature_flags/destroy_service.rb10
-rw-r--r--app/services/feature_flags/update_service.rb16
-rw-r--r--app/services/files/base_service.rb15
-rw-r--r--app/services/groups/autocomplete_service.rb2
-rw-r--r--app/services/groups/group_links/create_service.rb2
-rw-r--r--app/services/groups/group_links/destroy_service.rb4
-rw-r--r--app/services/groups/group_links/update_service.rb4
-rw-r--r--app/services/import/github/cancel_project_import_service.rb6
-rw-r--r--app/services/import/validate_remote_git_endpoint_service.rb4
-rw-r--r--app/services/import_csv/base_service.rb39
-rw-r--r--app/services/incident_management/timeline_events/base_service.rb2
-rw-r--r--app/services/issuable/clone/base_service.rb5
-rw-r--r--app/services/issuable/destroy_service.rb2
-rw-r--r--app/services/issuable/import_csv/base_service.rb2
-rw-r--r--app/services/issuable_base_service.rb10
-rw-r--r--app/services/issues/after_create_service.rb5
-rw-r--r--app/services/issues/base_service.rb8
-rw-r--r--app/services/issues/build_service.rb5
-rw-r--r--app/services/issues/close_service.rb10
-rw-r--r--app/services/issues/create_service.rb9
-rw-r--r--app/services/issues/duplicate_service.rb5
-rw-r--r--app/services/issues/referenced_merge_requests_service.rb12
-rw-r--r--app/services/issues/related_branches_service.rb5
-rw-r--r--app/services/issues/reopen_service.rb13
-rw-r--r--app/services/issues/reorder_service.rb5
-rw-r--r--app/services/issues/update_service.rb11
-rw-r--r--app/services/issues/zoom_link_service.rb2
-rw-r--r--app/services/jira_connect_installations/proxy_lifecycle_event_service.rb6
-rw-r--r--app/services/keys/revoke_service.rb2
-rw-r--r--app/services/markup/rendering_service.rb2
-rw-r--r--app/services/mattermost/create_team_service.rb2
-rw-r--r--app/services/merge_requests/add_context_service.rb4
-rw-r--r--app/services/merge_requests/base_service.rb10
-rw-r--r--app/services/merge_requests/refresh_service.rb7
-rw-r--r--app/services/metrics/dashboard/annotations/create_service.rb4
-rw-r--r--app/services/metrics/dashboard/annotations/delete_service.rb2
-rw-r--r--app/services/notes/create_service.rb10
-rw-r--r--app/services/notes/quick_actions_service.rb9
-rw-r--r--app/services/packages/debian/extract_metadata_service.rb34
-rw-r--r--app/services/packages/debian/generate_distribution_service.rb34
-rw-r--r--app/services/packages/debian/process_package_file_service.rb4
-rw-r--r--app/services/packages/mark_package_for_destruction_service.rb11
-rw-r--r--app/services/packages/mark_packages_for_destruction_service.rb11
-rw-r--r--app/services/packages/maven/find_or_create_package_service.rb63
-rw-r--r--app/services/personal_access_tokens/create_service.rb8
-rw-r--r--app/services/projects/batch_open_merge_requests_count_service.rb18
-rw-r--r--app/services/projects/blame_service.rb42
-rw-r--r--app/services/projects/container_repository/gitlab/cleanup_tags_service.rb4
-rw-r--r--app/services/projects/forks/sync_service.rb113
-rw-r--r--app/services/projects/import_export/relation_export_service.rb1
-rw-r--r--app/services/projects/lfs_pointers/lfs_link_service.rb12
-rw-r--r--app/services/projects/open_merge_requests_count_service.rb8
-rw-r--r--app/services/projects/protect_default_branch_service.rb6
-rw-r--r--app/services/projects/update_repository_storage_service.rb13
-rw-r--r--app/services/projects/update_service.rb20
-rw-r--r--app/services/protected_branches/base_service.rb2
-rw-r--r--app/services/protected_branches/cache_service.rb3
-rw-r--r--app/services/releases/links/base_service.rb35
-rw-r--r--app/services/releases/links/create_service.rb25
-rw-r--r--app/services/releases/links/destroy_service.rb24
-rw-r--r--app/services/releases/links/update_service.rb24
-rw-r--r--app/services/resource_access_tokens/create_service.rb34
-rw-r--r--app/services/security/ci_configuration/base_create_service.rb16
-rw-r--r--app/services/serverless/associate_domain_service.rb30
-rw-r--r--app/services/system_notes/commit_service.rb56
-rw-r--r--app/services/tasks_to_be_done/base_service.rb2
-rw-r--r--app/services/todo_service.rb2
-rw-r--r--app/services/users/build_service.rb4
-rw-r--r--app/services/users/refresh_authorized_projects_service.rb2
-rw-r--r--app/services/users/validate_manual_otp_service.rb3
-rw-r--r--app/services/work_items/export_csv_service.rb2
-rw-r--r--app/services/work_items/import_csv_service.rb116
-rw-r--r--app/services/work_items/parent_links/create_service.rb2
-rw-r--r--app/services/work_items/widgets/notifications_service/update_service.rb26
-rw-r--r--app/uploaders/ci/pipeline_artifact_uploader.rb2
-rw-r--r--app/uploaders/ci/secure_file_uploader.rb2
-rw-r--r--app/uploaders/deleted_object_uploader.rb2
-rw-r--r--app/uploaders/dependency_proxy/file_uploader.rb2
-rw-r--r--app/uploaders/external_diff_uploader.rb2
-rw-r--r--app/uploaders/gitlab_uploader.rb17
-rw-r--r--app/uploaders/job_artifact_uploader.rb2
-rw-r--r--app/uploaders/lfs_object_uploader.rb2
-rw-r--r--app/uploaders/object_storage.rb3
-rw-r--r--app/uploaders/packages/composer/cache_uploader.rb2
-rw-r--r--app/uploaders/packages/debian/component_file_uploader.rb2
-rw-r--r--app/uploaders/packages/debian/distribution_release_file_uploader.rb2
-rw-r--r--app/uploaders/packages/package_file_uploader.rb2
-rw-r--r--app/uploaders/packages/rpm/repository_file_uploader.rb2
-rw-r--r--app/uploaders/pages/deployment_uploader.rb2
-rw-r--r--app/uploaders/terraform/state_uploader.rb2
-rw-r--r--app/validators/addressable_url_validator.rb3
-rw-r--r--app/validators/json_schema_validator.rb1
-rw-r--r--app/validators/json_schemas/google_service_account_key.json48
-rw-r--r--app/validators/json_schemas/import_failure_external_identifiers.json18
-rw-r--r--app/views/admin/abuse_reports/_abuse_report.html.haml6
-rw-r--r--app/views/admin/abuse_reports/index.html.haml58
-rw-r--r--app/views/admin/application_settings/_ci_cd.html.haml18
-rw-r--r--app/views/admin/application_settings/_outbound.html.haml27
-rw-r--r--app/views/admin/application_settings/_projects_api_limits.html.haml21
-rw-r--r--app/views/admin/application_settings/_realtime.html.haml4
-rw-r--r--app/views/admin/application_settings/_repository_check.html.haml4
-rw-r--r--app/views/admin/application_settings/_runner_registrars_form.html.haml11
-rw-r--r--app/views/admin/application_settings/_visibility_and_access.html.haml2
-rw-r--r--app/views/admin/application_settings/appearances/_form.html.haml12
-rw-r--r--app/views/admin/application_settings/appearances/show.html.haml1
-rw-r--r--app/views/admin/application_settings/ci_cd.html.haml3
-rw-r--r--app/views/admin/application_settings/general.html.haml1
-rw-r--r--app/views/admin/application_settings/integrations.html.haml1
-rw-r--r--app/views/admin/application_settings/metrics_and_profiling.html.haml1
-rw-r--r--app/views/admin/application_settings/network.html.haml6
-rw-r--r--app/views/admin/application_settings/preferences.html.haml1
-rw-r--r--app/views/admin/application_settings/reporting.html.haml1
-rw-r--r--app/views/admin/application_settings/repository.html.haml1
-rw-r--r--app/views/admin/application_settings/service_usage_data.html.haml1
-rw-r--r--app/views/admin/applications/show.html.haml1
-rw-r--r--app/views/admin/background_migrations/index.html.haml2
-rw-r--r--app/views/admin/broadcast_messages/_preview.html.haml3
-rw-r--r--app/views/admin/dev_ops_report/show.html.haml2
-rw-r--r--app/views/admin/groups/_group.html.haml5
-rw-r--r--app/views/admin/groups/show.html.haml3
-rw-r--r--app/views/admin/health_check/show.html.haml5
-rw-r--r--app/views/admin/projects/_form.html.haml23
-rw-r--r--app/views/admin/projects/_projects.html.haml7
-rw-r--r--app/views/admin/projects/edit.html.haml4
-rw-r--r--app/views/admin/projects/show.html.haml4
-rw-r--r--app/views/admin/runners/register.html.haml7
-rw-r--r--app/views/admin/sessions/_two_factor_otp.html.haml8
-rw-r--r--app/views/admin/sessions/new.html.haml1
-rw-r--r--app/views/admin/sessions/two_factor.html.haml3
-rw-r--r--app/views/admin/spam_logs/index.html.haml2
-rw-r--r--app/views/admin/topics/_topic.html.haml5
-rw-r--r--app/views/authentication/_register.html.haml89
-rw-r--r--app/views/clusters/clusters/_integrations.html.haml2
-rw-r--r--app/views/dashboard/_groups_head.html.haml11
-rw-r--r--app/views/dashboard/_projects_head.html.haml5
-rw-r--r--app/views/dashboard/_projects_nav.html.haml3
-rw-r--r--app/views/dashboard/_snippets_head.html.haml15
-rw-r--r--app/views/dashboard/projects/_blank_state_admin_welcome.html.haml8
-rw-r--r--app/views/dashboard/projects/_blank_state_welcome.html.haml8
-rw-r--r--app/views/dashboard/snippets/index.html.haml2
-rw-r--r--app/views/dashboard/todos/index.html.haml14
-rw-r--r--app/views/devise/confirmations/almost_there.haml7
-rw-r--r--app/views/devise/confirmations/new.html.haml5
-rw-r--r--app/views/devise/registrations/new.html.haml2
-rw-r--r--app/views/devise/sessions/two_factor.html.haml12
-rw-r--r--app/views/devise/shared/_error_messages.html.haml9
-rw-r--r--app/views/devise/shared/_sign_in_link.html.haml2
-rw-r--r--app/views/devise/shared/_signup_box.html.haml2
-rw-r--r--app/views/doorkeeper/applications/show.html.haml3
-rw-r--r--app/views/explore/groups/_nav.html.haml4
-rw-r--r--app/views/explore/groups/index.html.haml17
-rw-r--r--app/views/explore/projects/_nav.html.haml6
-rw-r--r--app/views/explore/projects/index.html.haml15
-rw-r--r--app/views/explore/projects/starred.html.haml11
-rw-r--r--app/views/explore/projects/topic.html.haml30
-rw-r--r--app/views/explore/projects/topics.html.haml9
-rw-r--r--app/views/explore/projects/trending.html.haml12
-rw-r--r--app/views/explore/snippets/index.html.haml14
-rw-r--r--app/views/explore/topics/_head.html.haml10
-rw-r--r--app/views/groups/_import_group_from_another_instance_panel.html.haml4
-rw-r--r--app/views/groups/_import_group_from_file_panel.html.haml6
-rw-r--r--app/views/groups/_invite_members_modal.html.haml2
-rw-r--r--app/views/groups/_invite_members_side_nav_link.html.haml8
-rw-r--r--app/views/groups/_invite_members_top_nav_link.html.haml5
-rw-r--r--app/views/groups/_new_group_fields.html.haml3
-rw-r--r--app/views/groups/group_members/index.html.haml4
-rw-r--r--app/views/groups/milestones/_form.html.haml43
-rw-r--r--app/views/groups/milestones/new.html.haml5
-rw-r--r--app/views/groups/new.html.haml4
-rw-r--r--app/views/groups/settings/_export.html.haml5
-rw-r--r--app/views/groups/settings/_general.html.haml3
-rw-r--r--app/views/groups/settings/_transfer.html.haml2
-rw-r--r--app/views/groups/settings/applications/show.html.haml3
-rw-r--r--app/views/groups/settings/ci_cd/_auto_devops_form.html.haml7
-rw-r--r--app/views/groups/show.html.haml1
-rw-r--r--app/views/help/instance_configuration/_ci_cd_limits.html.haml16
-rw-r--r--app/views/ide/_show.html.haml4
-rw-r--r--app/views/layouts/_head.html.haml3
-rw-r--r--app/views/layouts/_loading_hints.html.haml3
-rw-r--r--app/views/layouts/_page.html.haml10
-rw-r--r--app/views/layouts/component_preview.html.haml4
-rw-r--r--app/views/layouts/dashboard.html.haml2
-rw-r--r--app/views/layouts/explore.html.haml11
-rw-r--r--app/views/layouts/group.html.haml4
-rw-r--r--app/views/layouts/header/_new_dropdown.html.haml15
-rw-r--r--app/views/layouts/nav/_breadcrumbs.html.haml45
-rw-r--r--app/views/layouts/nav/sidebar/_explore.html.haml1
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml3
-rw-r--r--app/views/layouts/nav/sidebar/_profile.html.haml170
-rw-r--r--app/views/layouts/nav/sidebar/_user_profile.html.haml1
-rw-r--r--app/views/layouts/nav/sidebar/_your_work.html.haml2
-rw-r--r--app/views/layouts/project.html.haml3
-rw-r--r--app/views/layouts/snippets.html.haml5
-rw-r--r--app/views/notify/_issuable_csv_export.html.haml6
-rw-r--r--app/views/notify/_issuable_csv_export.text.erb7
-rw-r--r--app/views/notify/export_work_items_csv_email.html.haml1
-rw-r--r--app/views/notify/export_work_items_csv_email.text.erb1
-rw-r--r--app/views/notify/import_work_items_csv_email.html.haml49
-rw-r--r--app/views/notify/import_work_items_csv_email.text.erb48
-rw-r--r--app/views/notify/issues_csv_email.text.erb6
-rw-r--r--app/views/notify/merge_request_status_email.text.haml2
-rw-r--r--app/views/notify/merge_requests_csv_email.text.erb6
-rw-r--r--app/views/notify/new_review_email.text.erb1
-rw-r--r--app/views/notify/two_factor_otp_attempt_failed_email.html.haml4
-rw-r--r--app/views/notify/two_factor_otp_attempt_failed_email.text.haml4
-rw-r--r--app/views/notify/unknown_sign_in_email.html.haml5
-rw-r--r--app/views/notify/unknown_sign_in_email.text.haml2
-rw-r--r--app/views/profiles/chat_names/_chat_name.html.haml16
-rw-r--r--app/views/profiles/chat_names/index.html.haml7
-rw-r--r--app/views/profiles/chat_names/new.html.haml40
-rw-r--r--app/views/profiles/gpg_keys/_key.html.haml2
-rw-r--r--app/views/profiles/keys/_key.html.haml2
-rw-r--r--app/views/profiles/preferences/show.html.haml3
-rw-r--r--app/views/profiles/show.html.haml17
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml82
-rw-r--r--app/views/projects/_files.html.haml2
-rw-r--r--app/views/projects/_home_panel.html.haml2
-rw-r--r--app/views/projects/_invite_members_empty_project.html.haml6
-rw-r--r--app/views/projects/_invite_members_modal.html.haml2
-rw-r--r--app/views/projects/_invite_members_side_nav_link.html.haml8
-rw-r--r--app/views/projects/_invite_members_top_nav_link.html.haml5
-rw-r--r--app/views/projects/_new_project_fields.html.haml2
-rw-r--r--app/views/projects/_self_monitoring_deprecation_notice.html.haml13
-rw-r--r--app/views/projects/airflow/dags/index.html.haml11
-rw-r--r--app/views/projects/artifacts/browse.html.haml2
-rw-r--r--app/views/projects/blame/show.html.haml27
-rw-r--r--app/views/projects/blob/_breadcrumb.html.haml2
-rw-r--r--app/views/projects/blob/_editor.html.haml18
-rw-r--r--app/views/projects/blob/viewers/_csv.html.haml2
-rw-r--r--app/views/projects/branch_defaults/_branch_names_fields.html.haml1
-rw-r--r--app/views/projects/branch_rules/_show.html.haml6
-rw-r--r--app/views/projects/branches/_branch_rules_info.haml12
-rw-r--r--app/views/projects/branches/index.html.haml12
-rw-r--r--app/views/projects/buttons/_clone.html.haml8
-rw-r--r--app/views/projects/commit/_signature_badge.html.haml2
-rw-r--r--app/views/projects/commit/diff_files.html.haml6
-rw-r--r--app/views/projects/commits/_commit.html.haml8
-rw-r--r--app/views/projects/compare/index.html.haml4
-rw-r--r--app/views/projects/compare/show.html.haml2
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml1
-rw-r--r--app/views/projects/diffs/_diffs.html.haml4
-rw-r--r--app/views/projects/edit.html.haml8
-rw-r--r--app/views/projects/empty.html.haml1
-rw-r--r--app/views/projects/environments/show.html.haml4
-rw-r--r--app/views/projects/feature_flags/index.html.haml2
-rw-r--r--app/views/projects/graphs/show.html.haml2
-rw-r--r--app/views/projects/issues/_design_management.html.haml3
-rw-r--r--app/views/projects/issues/_discussion.html.haml3
-rw-r--r--app/views/projects/issues/_work_item_links.html.haml2
-rw-r--r--app/views/projects/issues/service_desk/_nav_btns.html.haml2
-rw-r--r--app/views/projects/issues/show.html.haml1
-rw-r--r--app/views/projects/merge_requests/_mr_title.html.haml3
-rw-r--r--app/views/projects/merge_requests/_nav_btns.html.haml2
-rw-r--r--app/views/projects/merge_requests/_page.html.haml8
-rw-r--r--app/views/projects/milestones/_form.html.haml48
-rw-r--r--app/views/projects/mirrors/_mirror_repos_list.html.haml6
-rw-r--r--app/views/projects/ml/candidates/show.html.haml1
-rw-r--r--app/views/projects/ml/experiments/_experiment.html.haml3
-rw-r--r--app/views/projects/ml/experiments/_experiment_list.html.haml7
-rw-r--r--app/views/projects/ml/experiments/_incubation_banner.html.haml8
-rw-r--r--app/views/projects/ml/experiments/show.html.haml2
-rw-r--r--app/views/projects/new.html.haml12
-rw-r--r--app/views/projects/pages/_pages_settings.html.haml11
-rw-r--r--app/views/projects/pages_domains/_certificate.html.haml8
-rw-r--r--app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml2
-rw-r--r--app/views/projects/pipelines/_info.html.haml23
-rw-r--r--app/views/projects/pipelines/_pipeline_stats_text.html.haml1
-rw-r--r--app/views/projects/pipelines/new.html.haml2
-rw-r--r--app/views/projects/pipelines/show.html.haml16
-rw-r--r--app/views/projects/project_members/index.html.haml5
-rw-r--r--app/views/projects/protected_tags/_create_protected_tag.html.haml4
-rw-r--r--app/views/projects/protected_tags/_protected_tag.html.haml4
-rw-r--r--app/views/projects/protected_tags/_protected_tag_create_access_levels.haml8
-rw-r--r--app/views/projects/security/configuration/show.html.haml4
-rw-r--r--app/views/projects/settings/_general.html.haml4
-rw-r--r--app/views/projects/settings/branch_rules/index.html.haml2
-rw-r--r--app/views/projects/settings/ci_cd/_autodevops_form.html.haml6
-rw-r--r--app/views/projects/settings/ci_cd/_badge.html.haml2
-rw-r--r--app/views/projects/settings/ci_cd/_form.html.haml2
-rw-r--r--app/views/projects/settings/integrations/_form.html.haml3
-rw-r--r--app/views/projects/settings/integrations/index.html.haml2
-rw-r--r--app/views/projects/show.html.haml2
-rw-r--r--app/views/projects/starrers/_starrer.html.haml4
-rw-r--r--app/views/projects/work_items/index.html.haml1
-rw-r--r--app/views/registrations/welcome/show.html.haml3
-rw-r--r--app/views/search/_results.html.haml2
-rw-r--r--app/views/search/_results_list.html.haml27
-rw-r--r--app/views/search/_results_status.html.haml49
-rw-r--r--app/views/search/results/_blob.html.haml8
-rw-r--r--app/views/search/show.html.haml5
-rw-r--r--app/views/shared/_label.html.haml9
-rw-r--r--app/views/shared/_mobile_clone_panel.html.haml4
-rw-r--r--app/views/shared/doorkeeper/applications/_show.html.haml17
-rw-r--r--app/views/shared/doorkeeper/applications/_update_form.html.haml3
-rw-r--r--app/views/shared/empty_states/_issues.html.haml3
-rw-r--r--app/views/shared/icons/_mr_widget_empty_state.svg1
-rw-r--r--app/views/shared/integrations/_slack_notifications_deprecation_alert.html.haml20
-rw-r--r--app/views/shared/integrations/prometheus/_custom_metrics.html.haml8
-rw-r--r--app/views/shared/integrations/prometheus/_metrics.html.haml14
-rw-r--r--app/views/shared/issuable/_feed_buttons.html.haml8
-rw-r--r--app/views/shared/issuable/_label_dropdown.html.haml2
-rw-r--r--app/views/shared/issuable/_label_page_create.html.haml6
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml8
-rw-r--r--app/views/shared/issuable/_sidebar_user_dropdown.html.haml4
-rw-r--r--app/views/shared/issuable/form/_type_selector.html.haml2
-rw-r--r--app/views/shared/issue_type/_details_content.html.haml2
-rw-r--r--app/views/shared/labels/_form.html.haml2
-rw-r--r--app/views/shared/milestones/_description.html.haml4
-rw-r--r--app/views/shared/milestones/_form_dates.html.haml21
-rw-r--r--app/views/shared/nav/_explore_scope_header.html.haml6
-rw-r--r--app/views/shared/nav/_user_settings_scope_header.html.haml4
-rw-r--r--app/views/shared/topics/_topic.html.haml5
-rw-r--r--app/views/shared/wikis/_wiki_directory.html.haml7
-rw-r--r--app/views/snippets/show.html.haml5
-rw-r--r--app/views/users/_profile_basic_info.html.haml8
-rw-r--r--app/views/users/show.html.haml253
-rw-r--r--app/workers/all_queues.yml77
-rw-r--r--app/workers/authorized_project_update/project_recalculate_per_user_worker.rb2
-rw-r--r--app/workers/authorized_project_update/project_recalculate_worker.rb2
-rw-r--r--app/workers/authorized_project_update/user_refresh_from_replica_worker.rb2
-rw-r--r--app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb2
-rw-r--r--app/workers/authorized_project_update/user_refresh_with_low_urgency_worker.rb2
-rw-r--r--app/workers/authorized_projects_worker.rb2
-rw-r--r--app/workers/ci/archive_traces_cron_worker.rb10
-rw-r--r--app/workers/concerns/application_worker.rb3
-rw-r--r--app/workers/concerns/gitlab/github_import/object_importer.rb39
-rw-r--r--app/workers/container_expiration_policies/cleanup_container_repository_worker.rb9
-rw-r--r--app/workers/delete_user_worker.rb2
-rw-r--r--app/workers/gitlab/github_import/advance_stage_worker.rb1
-rw-r--r--app/workers/gitlab/github_import/import_collaborator_worker.rb21
-rw-r--r--app/workers/gitlab/github_import/stage/import_collaborators_worker.rb66
-rw-r--r--app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb2
-rw-r--r--app/workers/gitlab/github_import/stage/import_repository_worker.rb2
-rw-r--r--app/workers/gitlab_service_ping_worker.rb2
-rw-r--r--app/workers/group_destroy_worker.rb5
-rw-r--r--app/workers/groups/update_two_factor_requirement_for_members_worker.rb2
-rw-r--r--app/workers/issuable_export_csv_worker.rb18
-rw-r--r--app/workers/issues/placement_worker.rb2
-rw-r--r--app/workers/members_destroyer/unassign_issuables_worker.rb2
-rw-r--r--app/workers/new_merge_request_worker.rb1
-rw-r--r--app/workers/packages/debian/generate_distribution_worker.rb2
-rw-r--r--app/workers/personal_access_tokens/expired_notification_worker.rb2
-rw-r--r--app/workers/personal_access_tokens/expiring_worker.rb2
-rw-r--r--app/workers/post_receive.rb2
-rw-r--r--app/workers/project_destroy_worker.rb5
-rw-r--r--app/workers/projects/forks/sync_worker.rb22
-rw-r--r--app/workers/projects/import_export/create_relation_exports_worker.rb48
-rw-r--r--app/workers/projects/import_export/relation_export_worker.rb23
-rw-r--r--app/workers/projects/import_export/wait_relation_exports_worker.rb82
-rw-r--r--app/workers/prune_old_events_worker.rb10
-rw-r--r--app/workers/remove_expired_group_links_worker.rb2
-rw-r--r--app/workers/remove_expired_members_worker.rb2
-rw-r--r--app/workers/remove_unaccepted_member_invites_worker.rb2
-rw-r--r--app/workers/stage_update_worker.rb1
-rw-r--r--config/application.rb7
-rw-r--r--config/audit_events/types/feature_flag_created.yml9
-rw-r--r--config/audit_events/types/feature_flag_deleted.yml9
-rw-r--r--config/audit_events/types/feature_flag_updated.yml9
-rw-r--r--config/environments/development.rb3
-rw-r--r--config/esbuild.config.js6
-rw-r--r--config/events/1655841083_projects_settings_cicd_show_render.yml2
-rw-r--r--config/events/1655841352_projects_settings_cicd_show_upload.yml2
-rw-r--r--config/events/1655841364_projects_settings_cicd_show_delete.yml2
-rw-r--r--config/events/1666038724_Gitlab__Tracking__Helpers__WeakPasswordErrorEvent_track_weak_password_error.yml2
-rw-r--r--config/events/1674843937_Ci__Build_create_id_tokens.yml2
-rw-r--r--config/events/1676085590_Admin__AuditLogsController_visit_instance_compliance_audit_events.yml26
-rw-r--r--config/events/1676085625_Admin__CredentialsController_visit_compliance_credential_inventory.yml26
-rw-r--r--config/events/1676085737_Groups__AuditEventsController_visit_group_compliance_audit_events.yml26
-rw-r--r--config/events/1676085856_API__AuditEvents_admin_audit_event_request.yml26
-rw-r--r--config/events/1676085891_EE__API__Groups_group_audit_event_request.yml26
-rw-r--r--config/events/1676085919_EE__API__Projects_project_audit_event_request.yml26
-rw-r--r--config/events/202109151015_notes__create_service_execute.yml2
-rw-r--r--config/events/20211215022206_default_review_app_open_review_app.yml2
-rw-r--r--config/events/20230228151130_invite_members_modal_click_cancel.yml26
-rw-r--r--config/events/20230228151130_invite_members_modal_click_x.yml26
-rw-r--r--config/events/20230228151130_invite_members_modal_invite_successful.yml26
-rw-r--r--config/events/20230228151130_invite_members_modal_render.yml26
-rw-r--r--config/feature_categories.yml8
-rw-r--r--config/feature_flags/development/abuse_reports_list.yml8
-rw-r--r--config/feature_flags/development/achievements.yml2
-rw-r--r--config/feature_flags/development/add_refresh_pull_mirror_worker.yml8
-rw-r--r--config/feature_flags/development/airflow_dags.yml8
-rw-r--r--config/feature_flags/development/always_perform_delayed_deletion.yml8
-rw-r--r--config/feature_flags/development/apple_app_store_integration.yml8
-rw-r--r--config/feature_flags/development/artifacts_management_page.yml2
-rw-r--r--config/feature_flags/development/blame_page_streaming.yml8
-rw-r--r--config/feature_flags/development/bulk_import_projects.yml8
-rw-r--r--config/feature_flags/development/ci_batch_project_includes_context.yml8
-rw-r--r--config/feature_flags/development/ci_destroy_unlocked_job_artifacts.yml8
-rw-r--r--config/feature_flags/development/ci_fix_max_includes.yml8
-rw-r--r--config/feature_flags/development/ci_hooks_pre_get_sources_script.yml8
-rw-r--r--config/feature_flags/development/ci_inbound_job_token_scope.yml8
-rw-r--r--config/feature_flags/development/ci_includes_count_duplicates.yml8
-rw-r--r--config/feature_flags/development/ci_job_artifact_bulk_destroy.yml8
-rw-r--r--config/feature_flags/development/ci_private_catalog_beta.yml8
-rw-r--r--config/feature_flags/development/ci_variables_pages.yml8
-rw-r--r--config/feature_flags/development/cloudseed_aws.yml8
-rw-r--r--config/feature_flags/development/code_basic_search_files_by_regexp.yml9
-rw-r--r--config/feature_flags/development/codeowners_default_owners.yml8
-rw-r--r--config/feature_flags/development/counter_attribute_db_lease_for_update.yml2
-rw-r--r--config/feature_flags/development/create_runner_workflow.yml8
-rw-r--r--config/feature_flags/development/create_runner_workflow_for_admin.yml8
-rw-r--r--config/feature_flags/development/create_runner_workflow_for_namespace.yml8
-rw-r--r--config/feature_flags/development/deduplicate_archive_traces_cron_worker.yml8
-rw-r--r--config/feature_flags/development/delayed_repository_update_mirror_worker.yml8
-rw-r--r--config/feature_flags/development/disable_update_max_seats_worker.yml8
-rw-r--r--config/feature_flags/development/disabled_mr_discussions_redis_cache.yml8
-rw-r--r--config/feature_flags/development/do_not_run_safety_net_auth_refresh_jobs.yml2
-rw-r--r--config/feature_flags/development/enable_environments_search_within_folder.yml2
-rw-r--r--config/feature_flags/development/enforce_max_attachment_size_upload_api.yml8
-rw-r--r--config/feature_flags/development/environment_details_vue.yml2
-rw-r--r--config/feature_flags/development/environment_search_api_min_chars.yml2
-rw-r--r--config/feature_flags/development/environments_search_logging.yml8
-rw-r--r--config/feature_flags/development/fe_epic_board_total_weight.yml2
-rw-r--r--config/feature_flags/development/file_line_blame.yml2
-rw-r--r--config/feature_flags/development/full_path_project_search.yml2
-rw-r--r--config/feature_flags/development/github_client_fetch_repos_via_graphql.yml8
-rw-r--r--config/feature_flags/development/github_import_gists.yml2
-rw-r--r--config/feature_flags/development/google_play_integration.yml8
-rw-r--r--config/feature_flags/development/hash_oauth_secrets.yml8
-rw-r--r--config/feature_flags/development/hide_public_email_on_profile.yml2
-rw-r--r--config/feature_flags/development/improved_spread_parallel_import.yml8
-rw-r--r--config/feature_flags/development/incident_event_tags.yml2
-rw-r--r--config/feature_flags/development/include_memberships_from_group_shares_in_preloader.yml8
-rw-r--r--config/feature_flags/development/increase_page_size_exponentially.yml8
-rw-r--r--config/feature_flags/development/integration_slack_app_notifications.yml8
-rw-r--r--config/feature_flags/development/invitation_flow_enforcement_setting.yml2
-rw-r--r--config/feature_flags/development/kas_user_access.yml8
-rw-r--r--config/feature_flags/development/kas_user_access_project.yml8
-rw-r--r--config/feature_flags/development/large_ipynb_diffs.yml8
-rw-r--r--config/feature_flags/development/lazy_load_pipeline_dropdown_actions.yml8
-rw-r--r--config/feature_flags/development/license_from_gitaly.yml8
-rw-r--r--config/feature_flags/development/limited_capacity_seat_refresh_worker_high.yml8
-rw-r--r--config/feature_flags/development/limited_capacity_seat_refresh_worker_low.yml8
-rw-r--r--config/feature_flags/development/limited_capacity_seat_refresh_worker_medium.yml8
-rw-r--r--config/feature_flags/development/linear_group_descendants_finder_upto.yml2
-rw-r--r--config/feature_flags/development/linear_project_ancestors.yml8
-rw-r--r--config/feature_flags/development/linear_user_manageable_groups.yml8
-rw-r--r--config/feature_flags/development/log_response_length.yml2
-rw-r--r--config/feature_flags/development/log_user_git_push_activity.yml8
-rw-r--r--config/feature_flags/development/mr_show_reports_immediately.yml2
-rw-r--r--config/feature_flags/development/multiple_environment_approval_rules_fe.yml2
-rw-r--r--config/feature_flags/development/non_public_artifacts.yml2
-rw-r--r--config/feature_flags/development/notes_create_service_tracking.yml8
-rw-r--r--config/feature_flags/development/npm_allow_packages_in_multiple_projects.yml8
-rw-r--r--config/feature_flags/development/pages_unique_domain.yml8
-rw-r--r--config/feature_flags/development/permit_all_shared_groups_for_approval.yml8
-rw-r--r--config/feature_flags/development/pipeline_trigger_merge_status.yml8
-rw-r--r--config/feature_flags/development/present_groups_select_all.yml2
-rw-r--r--config/feature_flags/development/profile_tabs_vue.yml2
-rw-r--r--config/feature_flags/development/project_members_index_by_project_namespace.yml2
-rw-r--r--config/feature_flags/development/project_statistics_bulk_increment.yml2
-rw-r--r--config/feature_flags/development/rate_limit_for_unauthenticated_projects_api_access.yml8
-rw-r--r--config/feature_flags/development/reduce_sub_batch_size_on_timeouts.yml8
-rw-r--r--config/feature_flags/development/refactor_ci_minutes_consumption.yml8
-rw-r--r--config/feature_flags/development/rely_on_protected_branches_cache.yml8
-rw-r--r--config/feature_flags/development/remove_job_token_on_completion.yml8
-rw-r--r--config/feature_flags/development/repack_after_shard_migration.yml8
-rw-r--r--config/feature_flags/development/restrict_special_characters_in_namespace_path.yml8
-rw-r--r--config/feature_flags/development/revoke_ssh_signatures.yml8
-rw-r--r--config/feature_flags/development/route_hll_to_snowplow_phase2.yml8
-rw-r--r--config/feature_flags/development/runner_machine_heartbeat.yml8
-rw-r--r--config/feature_flags/development/s3_multithreaded_uploads.yml2
-rw-r--r--config/feature_flags/development/search_blobs_language_aggregation.yml8
-rw-r--r--config/feature_flags/development/search_index_integrity.yml8
-rw-r--r--config/feature_flags/development/search_index_partitioning_notes.yml8
-rw-r--r--config/feature_flags/development/sec_mark_dropped_findings_as_resolved_scheduler.yml8
-rw-r--r--config/feature_flags/development/service_desk_new_note_email_native_attachments.yml2
-rw-r--r--config/feature_flags/development/set_traversal_ids_on_save.yml8
-rw-r--r--config/feature_flags/development/show_group_readme.yml2
-rw-r--r--config/feature_flags/development/show_tags_on_commits_view.yml8
-rw-r--r--config/feature_flags/development/skip_group_share_unlink_auth_refresh.yml2
-rw-r--r--config/feature_flags/development/synchronize_fork.yml8
-rw-r--r--config/feature_flags/development/trial_email_validation.yml8
-rw-r--r--config/feature_flags/development/ultimate_feature_removal_banner.yml2
-rw-r--r--config/feature_flags/development/unlink_fork_network_upon_visibility_decrease.yml8
-rw-r--r--config/feature_flags/development/use_iid_in_work_items_path.yml8
-rw-r--r--config/feature_flags/development/use_response_url_for_chat_responder.yml8
-rw-r--r--config/feature_flags/development/use_sub_repositories_api.yml8
-rw-r--r--config/feature_flags/development/use_traversal_ids.yml2
-rw-r--r--config/feature_flags/development/use_traversal_ids_for_ancestor_scopes.yml4
-rw-r--r--config/feature_flags/development/use_traversal_ids_for_ancestors.yml4
-rw-r--r--config/feature_flags/development/use_traversal_ids_for_ancestors_upto.yml4
-rw-r--r--config/feature_flags/development/use_traversal_ids_for_descendants_scopes.yml2
-rw-r--r--config/feature_flags/development/use_traversal_ids_for_root_ancestor.yml2
-rw-r--r--config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy.yml4
-rw-r--r--config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy_scopes.yml2
-rw-r--r--config/feature_flags/development/use_traversal_ids_groups_finder.yml2
-rw-r--r--config/feature_flags/development/use_traversal_ids_roots.yml4
-rw-r--r--config/feature_flags/development/user_time_settings.yml2
-rw-r--r--config/feature_flags/development/validate_environment_tier_presence.yml2
-rw-r--r--config/feature_flags/development/vue_issues_dashboard.yml2
-rw-r--r--config/feature_flags/development/webui_members_inherited_users.yml2
-rw-r--r--config/feature_flags/experiment/generic_explore_groups.yml8
-rw-r--r--config/feature_flags/experiment/invite_members_in_side_nav.yml8
-rw-r--r--config/feature_flags/ops/advanced_user_index.yml8
-rw-r--r--config/feature_flags/ops/advanced_user_search.yml8
-rw-r--r--config/feature_flags/ops/auto_disabling_web_hooks.yml9
-rw-r--r--config/feature_flags/ops/automatic_lock_writes_on_table.yml2
-rw-r--r--config/feature_flags/ops/ci_build_dependencies_artifacts_logger.yml2
-rw-r--r--config/feature_flags/ops/detect_cross_database_modification.yml2
-rw-r--r--config/feature_flags/ops/dynamic_image_resizing.yml2
-rw-r--r--config/feature_flags/ops/dynamic_nonce.yml8
-rw-r--r--config/feature_flags/ops/legacy_open_source_license_available.yml2
-rw-r--r--config/feature_flags/ops/ops_prune_old_events.yml8
-rw-r--r--config/feature_flags/ops/projects_build_artifacts_size_refresh.yml2
-rw-r--r--config/feature_flags/ops/projects_build_artifacts_size_refresh_high.yml2
-rw-r--r--config/feature_flags/ops/projects_build_artifacts_size_refresh_medium.yml2
-rw-r--r--config/feature_flags/ops/query_analyzer_gitlab_schema_metrics.yml2
-rw-r--r--config/feature_flags/ops/split_log_bulk_increment_counter.yml2
-rw-r--r--config/gitlab.yml.example11
-rw-r--r--config/gitlab_loose_foreign_keys.yml8
-rw-r--r--config/initializers/0_1_yaml_safe_load_file_patch.rb15
-rw-r--r--config/initializers/1_settings.rb17
-rw-r--r--config/initializers/7_redis.rb1
-rw-r--r--config/initializers/active_record_preloader.rb11
-rw-r--r--config/initializers/carrierwave_patch.rb6
-rw-r--r--config/initializers/doorkeeper.rb14
-rw-r--r--config/initializers/fog_core_patch.rb3
-rw-r--r--config/initializers/google_cloud_profiler.rb25
-rw-r--r--config/initializers/lograge.rb2
-rw-r--r--config/initializers/postgres_partitioning.rb3
-rw-r--r--config/initializers/safe_session_store_patch.rb80
-rw-r--r--config/initializers_before_autoloader/001_fast_gettext.rb1
-rw-r--r--config/initializers_before_autoloader/004_zeitwerk.rb3
-rw-r--r--config/metrics/counts_28d/20210216175101_merge_requests_users.yml4
-rw-r--r--config/metrics/counts_28d/20210216175132_i_code_review_user_create_mr_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml2
-rw-r--r--config/metrics/counts_28d/20210216180312_snippets.yml2
-rw-r--r--config/metrics/counts_28d/20210216180319_action_monthly_active_users_web_ide_edit.yml4
-rw-r--r--config/metrics/counts_28d/20210216180321_action_monthly_active_users_sfe_edit.yml4
-rw-r--r--config/metrics/counts_28d/20210216180323_action_monthly_active_users_snippet_editor_edit.yml4
-rw-r--r--config/metrics/counts_28d/20210216180334_g_edit_by_sfe_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216183627_omniauth_providers.yml2
-rw-r--r--config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml4
-rw-r--r--config/metrics/counts_28d/20210216184458_p_ci_templates_implicit_auto_devops_monthly.yml2
-rwxr-xr-xconfig/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20210409100451_users_expanding_testing_code_quality_report_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210409100628_users_expanding_testing_accessibility_report_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210413205507_i_testing_summary_widget_total_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml4
-rw-r--r--config/metrics/counts_28d/20210910132229_user_auth_by_provider.yml2
-rw-r--r--config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20221101190915_i_testing_coverage_report_uploaded_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20221213182900_i_code_review_create_mr_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20230112174745_i_testing_active_user_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20230215180530_p_ci_templates_security_api_discovery_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20230217215050_ci_internal_pipelines.yml23
-rw-r--r--config/metrics/counts_28d/20230224095530_bulk_import_entities_group_finished_with_failures.yml27
-rw-r--r--config/metrics/counts_28d/20230224095530_bulk_import_entities_group_finished_without_failures.yml27
-rw-r--r--config/metrics/counts_28d/20230224095530_bulk_import_entities_project_finished_with_failures.yml27
-rw-r--r--config/metrics/counts_28d/20230224095530_bulk_import_entities_project_finished_without_failures.yml27
-rw-r--r--config/metrics/counts_28d/20230306134018_github_import_project_cancelled_monthly.yml26
-rw-r--r--config/metrics/counts_28d/20230306134609_github_import_project_partially_completed_monthly.yml26
-rw-r--r--config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml4
-rwxr-xr-xconfig/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20210409100451_users_expanding_testing_code_quality_report_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210409100628_users_expanding_testing_accessibility_report_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210413205507_i_testing_summary_widget_total_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20221101190913_i_testing_coverage_report_uploaded_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20221213183300_i_code_review_create_mr_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20230112174745_i_testing_active_user_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20230215180530_p_ci_templates_security_api_discovery_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20230306133608_github_import_project_cancelled_weekly.yml26
-rw-r--r--config/metrics/counts_7d/20230306134308_github_import_project_partially_completed_weekly.yml26
-rw-r--r--config/metrics/counts_all/20210216180228_projects_jira_server_active.yml4
-rw-r--r--config/metrics/counts_all/20210216180230_projects_jira_cloud_active.yml4
-rw-r--r--config/metrics/counts_all/20210216180242_web_ide_commits.yml2
-rw-r--r--config/metrics/counts_all/20210216180752_keys.yml2
-rw-r--r--config/metrics/counts_all/20210216183400_omniauth_providers.yml2
-rw-r--r--config/metrics/counts_all/20210910132001_user_auth_by_provider.yml2
-rw-r--r--config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml22
-rw-r--r--config/metrics/counts_all/20230222192643_projects_google_play_active.yml22
-rw-r--r--config/metrics/counts_all/20230222193011_instances_google_play_active.yml22
-rw-r--r--config/metrics/counts_all/20230222193151_groups_inheriting_google_play_active.yml22
-rw-r--r--config/metrics/counts_all/20230222193255_groups_google_play_active.yml22
-rw-r--r--config/metrics/counts_all/20230303131933_groups_inheriting_squash_tm_active.yml22
-rw-r--r--config/metrics/counts_all/20230303131936_groups_squash_tm_active.yml22
-rw-r--r--config/metrics/counts_all/20230303132041_instances_squash_tm_active.yml22
-rw-r--r--config/metrics/counts_all/20230303132048_projects_inheriting_squash_tm_active.yml22
-rw-r--r--config/metrics/counts_all/20230303132352_projects_squash_tm_active.yml22
-rw-r--r--config/metrics/counts_all/20230306191328_i_container_registry_delete_manifest.yml26
-rw-r--r--config/metrics/license/20230228110448_installation_creation_date.yml22
-rw-r--r--config/metrics/license/20230314161014_gitlab_dedicated.yml20
-rw-r--r--config/metrics/objects_schemas/index_inconsistencies_metric.json19
-rw-r--r--config/metrics/settings/20210204124906_ldap_enabled.yml2
-rw-r--r--config/metrics/settings/20210204124910_omniauth_enabled.yml2
-rw-r--r--config/metrics/settings/20210204124918_signup_enabled.yml2
-rw-r--r--config/metrics/settings/20230203164341_index_inconsistencies_metric.yml25
-rw-r--r--config/routes.rb2
-rw-r--r--config/routes/admin.rb9
-rw-r--r--config/routes/group.rb4
-rw-r--r--config/routes/import.rb1
-rw-r--r--config/routes/issues.rb9
-rw-r--r--config/routes/profile.rb3
-rw-r--r--config/routes/project.rb4
-rw-r--r--config/routes/repository.rb1
-rw-r--r--config/settings.rb7
-rw-r--r--config/sidekiq_queues.yml12
-rw-r--r--config/vue3migration/compiler.js50
-rw-r--r--config/webpack.config.js105
-rw-r--r--danger/plugins/sidekiq_args.rb10
-rw-r--r--danger/roulette/Dangerfile2
-rw-r--r--danger/sidekiq_args/Dangerfile5
-rw-r--r--data/deprecations/14-10-old-search-migration-removal.yml2
-rw-r--r--data/deprecations/14-7-deprecate-merged_by-api-field.yml25
-rw-r--r--data/deprecations/14-8-runner-api-active-field-replaced-with-paused-breaking-change.yml30
-rw-r--r--data/deprecations/14-8-runner-api-status-filter-does-accept-active-or-paused.yml19
-rw-r--r--data/deprecations/15-1-deprecate-maintainer_note.yml15
-rw-r--r--data/deprecations/15-10-consul-legacy-metrics-disable.yml15
-rw-r--r--data/deprecations/15-10-gitaly-legacy-config.yml35
-rw-r--r--data/deprecations/15-10-omniauth-dingtalk.yml41
-rw-r--r--data/deprecations/15-6-deprecate-merge_status-api-field.yml12
-rw-r--r--data/deprecations/15-6-deprecate-post-api-v4-runner.yml6
-rw-r--r--data/deprecations/15-6-deprecate-runner-reg-token-helm.yml10
-rw-r--r--data/deprecations/15-6-deprecate-runner-register-command.yml9
-rw-r--r--data/deprecations/15-6-deprecate-runner-register-token-k8s-operator.yml8
-rw-r--r--data/deprecations/15-7-deprecate-api-v4-runner-registration-token-reset-endpoints.yml6
-rw-r--r--data/deprecations/15-7-deprecate-gitlab-runner-exec-cmd.yml10
-rw-r--r--data/deprecations/15-7-deprecate-kas-metrics-port-in-gitlab-chart.yml10
-rw-r--r--data/deprecations/15-7-deprecate-shimo-integration.yml2
-rw-r--r--data/deprecations/15-7-deprecate-single-merge-request-changes-api-endpoint.yml12
-rw-r--r--data/deprecations/15-7-deprecate-zentao-integration.yml2
-rw-r--r--data/deprecations/15-8-deprecate-merge-request-approvals-fields.yml14
-rw-r--r--data/deprecations/15-8-deprecate-slack-notifications-integration.yml2
-rw-r--r--data/deprecations/15-8-deprecate-system-hook-test-endpoint.yml2
-rw-r--r--data/deprecations/15-8-deprecate-updated-at-error.yml2
-rw-r--r--data/deprecations/15-8-jira-connect-app-cookie-auth.yml2
-rw-r--r--data/deprecations/15-8-live-preview.yml2
-rw-r--r--data/deprecations/15-8-projects-api-ops-access-level.yml2
-rw-r--r--data/deprecations/15-8-visual-review-tool.yml2
-rw-r--r--data/deprecations/15-9-accessibility-testing-deprecation.yml2
-rw-r--r--data/deprecations/15-9-ci-builds-column-validations.yml29
-rw-r--r--data/deprecations/15-9-deprecate-ci-pre-clone-script.yml23
-rw-r--r--data/deprecations/15-9-deprecate-option-to-remove-project-immediately.yml6
-rw-r--r--data/deprecations/15-9-env-search-char-limit.yml9
-rw-r--r--data/deprecations/15-9-insecure-ci-job-token.yml20
-rw-r--r--data/deprecations/15-9-legacy-praefect-configuration.yml6
-rw-r--r--data/deprecations/15-9-managed-licenses-api.yml9
-rw-r--r--data/deprecations/15-9-rails-error-tracking.yml4
-rw-r--r--data/deprecations/15-9-remove-offset-pagination-jobs-api.yml2
-rw-r--r--data/deprecations/15-9-secure-analyzers-bump.yml10
-rw-r--r--data/deprecations/15-9-trigger-job-status.yml4
-rw-r--r--data/deprecations/templates/_deprecation_template.md.erb21
-rw-r--r--data/removals/15_10/15_10-non-public-artifacts.yml25
-rw-r--r--data/removals/15_9/15-9-live-preview.yml11
-rw-r--r--data/whats_new/20230222001_15_09.yml75
-rw-r--r--db/docs/airflow_dags.yml10
-rw-r--r--db/docs/application_setting_terms.yml2
-rw-r--r--db/docs/atlassian_identities.yml2
-rw-r--r--db/docs/authentication_events.yml2
-rw-r--r--db/docs/banned_users.yml2
-rw-r--r--db/docs/bulk_import_batch_trackers.yml11
-rw-r--r--db/docs/bulk_import_export_batches.yml11
-rw-r--r--db/docs/catalog_resources.yml8
-rw-r--r--db/docs/ci_build_needs.yml2
-rw-r--r--db/docs/ci_cost_settings.yml10
-rw-r--r--db/docs/ci_group_variables.yml2
-rw-r--r--db/docs/ci_instance_variables.yml2
-rw-r--r--db/docs/ci_job_variables.yml2
-rw-r--r--db/docs/ci_pipeline_variables.yml2
-rw-r--r--db/docs/ci_secure_file_states.yml2
-rw-r--r--db/docs/ci_secure_files.yml2
-rw-r--r--db/docs/ci_sources_pipelines.yml2
-rw-r--r--db/docs/ci_variables.yml2
-rw-r--r--db/docs/clusters_applications_crossplane.yml2
-rw-r--r--db/docs/clusters_applications_prometheus.yml2
-rw-r--r--db/docs/container_registry_data_repair_details.yml10
-rw-r--r--db/docs/container_repository_states.yml11
-rw-r--r--db/docs/deleted_tables/airflow_dags.yml12
-rw-r--r--db/docs/elastic_reindexing_slices.yml2
-rw-r--r--db/docs/elasticsearch_indexed_projects.yml2
-rw-r--r--db/docs/group_group_links.yml2
-rw-r--r--db/docs/identities.yml2
-rw-r--r--db/docs/integrations.yml2
-rw-r--r--db/docs/ip_restrictions.yml2
-rw-r--r--db/docs/keys.yml2
-rw-r--r--db/docs/ldap_group_links.yml2
-rw-r--r--db/docs/namespace_admin_notes.yml2
-rw-r--r--db/docs/namespace_ldap_settings.yml10
-rw-r--r--db/docs/oauth_access_grants.yml2
-rw-r--r--db/docs/oauth_access_tokens.yml2
-rw-r--r--db/docs/oauth_applications.yml2
-rw-r--r--db/docs/oauth_openid_requests.yml2
-rw-r--r--db/docs/p_ci_runner_machine_builds.yml9
-rw-r--r--db/docs/personal_access_tokens.yml2
-rw-r--r--db/docs/postgres_async_foreign_key_validations.yml2
-rw-r--r--db/docs/project_access_tokens.yml2
-rw-r--r--db/docs/project_authorizations.yml2
-rw-r--r--db/docs/project_group_links.yml2
-rw-r--r--db/docs/saml_group_links.yml2
-rw-r--r--db/docs/saml_providers.yml2
-rw-r--r--db/docs/scim_identities.yml2
-rw-r--r--db/docs/scim_oauth_access_tokens.yml2
-rw-r--r--db/docs/serverless_domain_cluster.yml2
-rw-r--r--db/docs/service_desk_custom_email_verifications.yml11
-rw-r--r--db/docs/smartcard_identities.yml2
-rw-r--r--db/docs/term_agreements.yml2
-rw-r--r--db/docs/token_with_ivs.yml2
-rw-r--r--db/docs/u2f_registrations.yml2
-rw-r--r--db/docs/user_canonical_emails.yml2
-rw-r--r--db/docs/user_highest_roles.yml2
-rw-r--r--db/docs/user_permission_export_uploads.yml2
-rw-r--r--db/docs/user_synced_attributes_metadata.yml2
-rw-r--r--db/docs/webauthn_registrations.yml2
-rw-r--r--db/docs/work_item_types.yml1
-rw-r--r--db/docs/work_item_widget_definitions.yml1
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb59
-rw-r--r--db/fixtures/development/36_achievements.rb68
-rw-r--r--db/fixtures/development/heart.pngbin0 -> 22484 bytes
-rw-r--r--db/fixtures/development/rocket.jpgbin0 -> 28042 bytes
-rw-r--r--db/migrate/20230113164245_create_namespace_ldap_settings.rb16
-rw-r--r--db/migrate/20230118135145_add_service_desk_custom_email_verifications.rb24
-rw-r--r--db/migrate/20230127030015_add_deny_all_outgoing_requests_to_application_settings.rb9
-rw-r--r--db/migrate/20230127155217_add_id_column_to_package_metadata_join_table.rb56
-rw-r--r--db/migrate/20230201165656_create_container_repository_states.rb44
-rw-r--r--db/migrate/20230202094723_add_default_syntax_highlighting_theme_to_application_settings.rb7
-rw-r--r--db/migrate/20230210152109_add_bulk_import_export_batches.rb21
-rw-r--r--db/migrate/20230210153420_add_batched_column_to_bulk_import_exports.rb9
-rw-r--r--db/migrate/20230210155715_add_batch_id_to_bulk_import_export_uploads.rb7
-rw-r--r--db/migrate/20230210160037_add_batch_foreign_key_to_bulk_import_export_uploads.rb15
-rw-r--r--db/migrate/20230210160351_add_bulk_import_batch_trackers.rb22
-rw-r--r--db/migrate/20230210161002_add_batched_column_to_bulk_import_trackers.rb7
-rw-r--r--db/migrate/20230210171012_add_batch_id_index_to_bulk_import_export_uploads.rb15
-rw-r--r--db/migrate/20230213213559_add_index_on_project_id_and_scanner_id_and_vulnerability_id_on_vulnerability_reads.rb15
-rw-r--r--db/migrate/20230215074223_add_ci_runner_machine_builds_partitioned_table.rb30
-rw-r--r--db/migrate/20230215124011_add_provisioned_by_group_at_to_user_details.rb9
-rw-r--r--db/migrate/20230215131026_add_has_failures_column_to_bulk_imports.rb7
-rw-r--r--db/migrate/20230215180605_index_sbom_occurrences_on_project_id_and_id.rb15
-rw-r--r--db/migrate/20230216040505_add_status_and_resolved_at_to_abuse_reports.rb8
-rw-r--r--db/migrate/20230216071312_add_status_category_and_id_index_to_abuse_reports.rb15
-rw-r--r--db/migrate/20230216142836_update_vulnerability_reads_trigger_to_set_has_issue.rb185
-rw-r--r--db/migrate/20230216144719_drop_table_airflow_dags.rb22
-rw-r--r--db/migrate/20230216152912_add_has_failures_column_to_bulk_import_entities.rb7
-rw-r--r--db/migrate/20230216171309_create_ci_runner_cost_settings.rb17
-rw-r--r--db/migrate/20230217065736_add_projects_api_rate_limit_unauthenticated_to_application_settings.rb7
-rw-r--r--db/migrate/20230217144421_add_check_type_to_pre_scan_step.rb11
-rw-r--r--db/migrate/20230217232554_add_state_changed_in_to_vulnerability_state_transitions.rb11
-rw-r--r--db/migrate/20230220035034_add_status_and_id_index_to_abuse_reports.rb15
-rw-r--r--db/migrate/20230220163141_create_catalog_resources_table.rb11
-rw-r--r--db/migrate/20230221110256_create_initial_partition_for_ci_runner_machine_builds.rb49
-rw-r--r--db/migrate/20230222153048_add_registry_size_estimated_to_namespace_root_storage_statistics.rb21
-rw-r--r--db/migrate/20230222193845_change_public_projects_minutes_cost_factor_default_to_1.rb17
-rw-r--r--db/migrate/20230224130315_add_constraint_type_to_postgres_async_constraint_validation.rb7
-rw-r--r--db/migrate/20230224161346_add_saml_group_lock_to_application_settings.rb7
-rw-r--r--db/migrate/20230228092612_add_index_next_over_limit_check_at_asc_order_synchronously.rb17
-rw-r--r--db/migrate/20230228133011_add_design_description.rb18
-rw-r--r--db/migrate/20230228135034_add_design_description_limit.rb13
-rw-r--r--db/migrate/20230228142350_add_notifications_work_item_widget.rb57
-rw-r--r--db/migrate/20230228212427_add_index_user_details_on_user_id_for_enterprise_users_without_date.rb19
-rw-r--r--db/migrate/20230228212905_add_index_user_details_on_user_id_for_enterprise_users_with_date.rb19
-rw-r--r--db/migrate/20230303144424_unique_index_on_catalog_resources_project.rb17
-rw-r--r--db/migrate/20230306145230_add_product_analytics_data_collector_host_to_application_settings.rb9
-rw-r--r--db/migrate/20230307091216_add_status_reporter_id_and_id_index_to_abuse_reports.rb15
-rw-r--r--db/migrate/20230307122838_add_text_limit_to_application_settings_product_analytics_data_collector_host.rb13
-rw-r--r--db/migrate/20230307233631_add_public_runner_release_version_fetch_setting.rb14
-rw-r--r--db/migrate/20230308163018_create_container_registry_data_repair_details.rb17
-rw-r--r--db/migrate/20230309000957_add_external_identifiers_to_import_failures.rb9
-rw-r--r--db/migrate/20230313054226_add_status_created_at_and_updated_at_indexes_to_abuse_reports.rb18
-rw-r--r--db/migrate/20230313100920_add_gitlab_dedicated_instance_to_application_settings.rb9
-rw-r--r--db/post_migrate/20230113201308_backfill_namespace_ldap_settings.rb33
-rw-r--r--db/post_migrate/20230118144623_schedule_migration_for_remediation.rb18
-rw-r--r--db/post_migrate/20230125195503_queue_backfill_compliance_violations.rb24
-rw-r--r--db/post_migrate/20230126101907_add_partition_index_to_web_hook_logs.rb21
-rw-r--r--db/post_migrate/20230130182412_schedule_create_vulnerability_links_migration.rb27
-rw-r--r--db/post_migrate/20230131184319_update_billable_users_index_for_service_accounts.rb27
-rw-r--r--db/post_migrate/20230202135758_queue_backfill_prepared_at_data.rb23
-rw-r--r--db/post_migrate/20230202211434_migrate_redis_slot_keys.rb113
-rw-r--r--db/post_migrate/20230208125736_schedule_migration_for_links.rb25
-rw-r--r--db/post_migrate/20230213103019_add_index_for_next_over_limit_check_at.rb17
-rw-r--r--db/post_migrate/20230214181633_finalize_ci_build_needs_big_int_conversion.rb28
-rw-r--r--db/post_migrate/20230215213349_add_sync_index_on_packages_package_file_filename.rb21
-rw-r--r--db/post_migrate/20230216060333_prepare_async_foreign_key_validation_for_ci_build_trace_metadata.rb15
-rw-r--r--db/post_migrate/20230216191507_delete_incorrectly_onboarded_namespaces.rb17
-rw-r--r--db/post_migrate/20230216222956_add_sync_index_on_lfs_objects_file.rb15
-rw-r--r--db/post_migrate/20230216232404_add_sync_index_on_merge_request_diffs_external_diff.rb15
-rw-r--r--db/post_migrate/20230216233937_remove_application_settings_send_user_confirmation_email_column.rb7
-rw-r--r--db/post_migrate/20230218145930_add_index_users_on_updated_at.rb16
-rw-r--r--db/post_migrate/20230218145940_add_index_namespaces_on_updated_at.rb16
-rw-r--r--db/post_migrate/20230218152729_validate_fk_on_ci_job_artifacts_partition_id_and_job_id.rb15
-rw-r--r--db/post_migrate/20230218152730_remove_fk_to_ci_builds_ci_job_artifacts_on_job_id.rb35
-rw-r--r--db/post_migrate/20230219191034_add_pipeline_fk_to_vulnerability_state_transitions.rb15
-rw-r--r--db/post_migrate/20230220102212_swap_columns_ci_build_needs_big_int_conversion.rb57
-rw-r--r--db/post_migrate/20230220112930_replace_uniq_index_on_postgres_async_foreign_key_validations.rb19
-rw-r--r--db/post_migrate/20230220132409_validate_fk_on_ci_build_report_results_partition_id_and_build_id.rb15
-rw-r--r--db/post_migrate/20230220132410_remove_fk_to_ci_builds_ci_build_report_results_on_build_id.rb35
-rw-r--r--db/post_migrate/20230220134145_validate_fk_on_ci_build_needs_partition_id_and_build_id.rb15
-rw-r--r--db/post_migrate/20230220134146_remove_fk_to_ci_builds_ci_build_needs_on_build_id.rb35
-rw-r--r--db/post_migrate/20230220165240_add_index_to_approval_rules_on_scan_result_policy_id.rb19
-rw-r--r--db/post_migrate/20230221010522_prepare_async_foreign_key_validation_for_ci_sources_pipelines.rb15
-rw-r--r--db/post_migrate/20230221011750_prepare_async_foreign_key_validation_for_ci_job_variables.rb15
-rw-r--r--db/post_migrate/20230221093533_add_tmp_partial_index_on_vulnerability_report_types.rb15
-rw-r--r--db/post_migrate/20230221125148_add_fk_to_p_ci_builds_metadata_partitions_on_partition_id_and_build_id.rb41
-rw-r--r--db/post_migrate/20230221162222_raise_ci_variable_limits_on_gitlab_com.rb53
-rw-r--r--db/post_migrate/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress.rb29
-rw-r--r--db/post_migrate/20230222035805_prepare_async_index_removal_of_token_for_ci_builds.rb17
-rw-r--r--db/post_migrate/20230222055510_remove_concurrent_index_on_token_encrypted_for_ci_builds.rb18
-rw-r--r--db/post_migrate/20230222101420_remove_fk_to_ci_build_ci_pending_build_on_build_id.rb35
-rw-r--r--db/post_migrate/20230222102421_remove_fk_to_ci_build_ci_running_build_on_build_id.rb35
-rw-r--r--db/post_migrate/20230223014251_validate_not_null_constraint_on_oauth_access_tokens_expires_in.rb13
-rw-r--r--db/post_migrate/20230223065753_finalize_nullify_creator_id_of_orphaned_projects.rb22
-rw-r--r--db/post_migrate/20230223082752_schedule_fk_validation_for_p_ci_builds_metadata_partitions_and_ci_builds.rb17
-rw-r--r--db/post_migrate/20230223093704_add_foreign_key_on_creator_id_on_projects.rb15
-rw-r--r--db/post_migrate/20230224085743_update_issues_internal_id_scope.rb29
-rw-r--r--db/post_migrate/20230224144233_migrate_evidences_from_raw_metadata.rb25
-rw-r--r--db/post_migrate/20230227123949_validate_fk_on_ci_sources_pipelines_source_partition_id_and_source_job_id.rb15
-rw-r--r--db/post_migrate/20230227123950_remove_fk_to_ci_builds_ci_sources_pipelines_on_source_job_id.rb35
-rw-r--r--db/post_migrate/20230227151608_validate_fk_on_ci_build_trace_metadata_partition_id_and_build_id.rb15
-rw-r--r--db/post_migrate/20230227151609_remove_fk_to_ci_builds_ci_build_trace_metadata_on_build_id.rb35
-rw-r--r--db/post_migrate/20230227153231_validate_fk_on_ci_job_variables_partition_id_and_job_id.rb15
-rw-r--r--db/post_migrate/20230227153232_remove_fk_to_ci_builds_ci_job_variables_on_job_id.rb35
-rw-r--r--db/post_migrate/20230228021910_ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb29
-rw-r--r--db/post_migrate/20230228023014_swap_timelogs_note_id_to_bigint_for_gitlab_dot_com.rb56
-rw-r--r--db/post_migrate/20230301065107_add_index_on_expired_unlocked_non_trace_job_artifacts.rb17
-rw-r--r--db/post_migrate/20230302090155_add_async_index_on_unlocked_non_trace_job_artifacts_expire_at.rb15
-rw-r--r--db/post_migrate/20230302123258_drop_runner_machines_constraint_on_ci_builds_metadata.rb27
-rw-r--r--db/post_migrate/20230302123259_ensure_ci_runner_machines_is_empty.rb17
-rw-r--r--db/post_migrate/20230302123301_add_index_on_runner_machine_id_on_runner_machine_builds.rb17
-rw-r--r--db/post_migrate/20230302163339_add_index_to_oauth_access_grants_application_id.rb15
-rw-r--r--db/post_migrate/20230302185739_queue_fix_vulnerability_reads_has_issues.rb28
-rw-r--r--db/post_migrate/20230303105806_queue_delete_orphaned_packages_dependencies.rb26
-rw-r--r--db/post_migrate/20230303120531_schedule_temporary_partitioning_indexes_removal.rb32
-rw-r--r--db/post_migrate/20230303154314_add_user_type_migration_indexes.rb22
-rw-r--r--db/post_migrate/20230304184416_drop_revokable_from_achievements.rb9
-rw-r--r--db/post_migrate/20230306071456_validate_partitioning_fk_on_p_ci_builds_metadata_partitions.rb20
-rw-r--r--db/post_migrate/20230306072532_add_partitioned_fk_to_p_ci_builds_metadata_on_partition_id_and_build_id.rb36
-rw-r--r--db/post_migrate/20230306082852_remove_fk_to_ci_builds_p_ci_builds_metadata_on_build_id.rb32
-rw-r--r--db/post_migrate/20230306143322_prepare_ci_builds_primary_key_for_partitioning.rb66
-rw-r--r--db/post_migrate/20230306195007_queue_backfill_project_wiki_repositories.rb25
-rw-r--r--db/post_migrate/20230307085644_track_ci_runner_machine_record_changes.rb15
-rw-r--r--db/post_migrate/20230307160251_rename_constraint_fk_rails_f601258b28_on_events_table.rb19
-rw-r--r--db/post_migrate/20230309010000_add_unique_index_mr_user_mentions_note_id_convert_to_bigint.rb31
-rw-r--r--db/post_migrate/20230309010931_add_fk_on_mr_user_mentions_note_id_convert_to_id_bigint.rb43
-rw-r--r--db/post_migrate/20230309020422_validate_fk_on_mr_user_mentions_note_id_convert_to_id_bigint.rb27
-rw-r--r--db/post_migrate/20230309071242_delete_security_policy_bot_users.rb21
-rw-r--r--db/post_migrate/20230309103016_drop_id_partition_id_index_from_p_ci_build_metadata.rb18
-rw-r--r--db/post_migrate/20230310111859_recreate_user_type_migration_indexes.rb24
-rw-r--r--db/post_migrate/20230313133001_ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb30
-rw-r--r--db/post_migrate/20230313143033_swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com.rb64
-rw-r--r--db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb32
-rw-r--r--db/post_migrate/20230313184306_add_temp_index_for_software_license_cleanup.rb15
-rw-r--r--db/post_migrate/20230313185145_cleanup_orphan_software_licenses.rb27
-rw-r--r--db/post_migrate/20230316014650_remove_index_on_events_action_async.rb12
-rw-r--r--db/schema_migrations/202301131642451
-rw-r--r--db/schema_migrations/202301132013081
-rw-r--r--db/schema_migrations/202301181351451
-rw-r--r--db/schema_migrations/202301181446231
-rw-r--r--db/schema_migrations/202301251955031
-rw-r--r--db/schema_migrations/202301261019071
-rw-r--r--db/schema_migrations/202301270300151
-rw-r--r--db/schema_migrations/202301301824121
-rw-r--r--db/schema_migrations/202301311843191
-rw-r--r--db/schema_migrations/202302011656561
-rw-r--r--db/schema_migrations/202302020947231
-rw-r--r--db/schema_migrations/202302021357581
-rw-r--r--db/schema_migrations/202302022114341
-rw-r--r--db/schema_migrations/202302081257361
-rw-r--r--db/schema_migrations/202302101521091
-rw-r--r--db/schema_migrations/202302101534201
-rw-r--r--db/schema_migrations/202302101557151
-rw-r--r--db/schema_migrations/202302101600371
-rw-r--r--db/schema_migrations/202302101603511
-rw-r--r--db/schema_migrations/202302101610021
-rw-r--r--db/schema_migrations/202302101710121
-rw-r--r--db/schema_migrations/202302131030191
-rw-r--r--db/schema_migrations/202302132135591
-rw-r--r--db/schema_migrations/202302141816331
-rw-r--r--db/schema_migrations/202302150742231
-rw-r--r--db/schema_migrations/202302151240111
-rw-r--r--db/schema_migrations/202302151310261
-rw-r--r--db/schema_migrations/202302151806051
-rw-r--r--db/schema_migrations/202302152133491
-rw-r--r--db/schema_migrations/202302160405051
-rw-r--r--db/schema_migrations/202302160603331
-rw-r--r--db/schema_migrations/202302160713121
-rw-r--r--db/schema_migrations/202302161428361
-rw-r--r--db/schema_migrations/202302161447191
-rw-r--r--db/schema_migrations/202302161529121
-rw-r--r--db/schema_migrations/202302161713091
-rw-r--r--db/schema_migrations/202302161915071
-rw-r--r--db/schema_migrations/202302162229561
-rw-r--r--db/schema_migrations/202302162324041
-rw-r--r--db/schema_migrations/202302162339371
-rw-r--r--db/schema_migrations/202302170657361
-rw-r--r--db/schema_migrations/202302171444211
-rw-r--r--db/schema_migrations/202302172325541
-rw-r--r--db/schema_migrations/202302181459301
-rw-r--r--db/schema_migrations/202302181459401
-rw-r--r--db/schema_migrations/202302181527291
-rw-r--r--db/schema_migrations/202302181527301
-rw-r--r--db/schema_migrations/202302191910341
-rw-r--r--db/schema_migrations/202302200350341
-rw-r--r--db/schema_migrations/202302201022121
-rw-r--r--db/schema_migrations/202302201129301
-rw-r--r--db/schema_migrations/202302201324091
-rw-r--r--db/schema_migrations/202302201324101
-rw-r--r--db/schema_migrations/202302201341451
-rw-r--r--db/schema_migrations/202302201341461
-rw-r--r--db/schema_migrations/202302201631411
-rw-r--r--db/schema_migrations/202302201652401
-rw-r--r--db/schema_migrations/202302210105221
-rw-r--r--db/schema_migrations/202302210117501
-rw-r--r--db/schema_migrations/202302210935331
-rw-r--r--db/schema_migrations/202302211102561
-rw-r--r--db/schema_migrations/202302211251481
-rw-r--r--db/schema_migrations/202302211622221
-rw-r--r--db/schema_migrations/202302212145191
-rw-r--r--db/schema_migrations/202302220358051
-rw-r--r--db/schema_migrations/202302220555101
-rw-r--r--db/schema_migrations/202302221014201
-rw-r--r--db/schema_migrations/202302221024211
-rw-r--r--db/schema_migrations/202302221530481
-rw-r--r--db/schema_migrations/202302221938451
-rw-r--r--db/schema_migrations/202302230142511
-rw-r--r--db/schema_migrations/202302230657531
-rw-r--r--db/schema_migrations/202302230827521
-rw-r--r--db/schema_migrations/202302230937041
-rw-r--r--db/schema_migrations/202302240857431
-rw-r--r--db/schema_migrations/202302241303151
-rw-r--r--db/schema_migrations/202302241442331
-rw-r--r--db/schema_migrations/202302241613461
-rw-r--r--db/schema_migrations/202302271239491
-rw-r--r--db/schema_migrations/202302271239501
-rw-r--r--db/schema_migrations/202302271516081
-rw-r--r--db/schema_migrations/202302271516091
-rw-r--r--db/schema_migrations/202302271532311
-rw-r--r--db/schema_migrations/202302271532321
-rw-r--r--db/schema_migrations/202302280219101
-rw-r--r--db/schema_migrations/202302280230141
-rw-r--r--db/schema_migrations/202302280926121
-rw-r--r--db/schema_migrations/202302281330111
-rw-r--r--db/schema_migrations/202302281350341
-rw-r--r--db/schema_migrations/202302281423501
-rw-r--r--db/schema_migrations/202302282124271
-rw-r--r--db/schema_migrations/202302282129051
-rw-r--r--db/schema_migrations/202303010651071
-rw-r--r--db/schema_migrations/202303020901551
-rw-r--r--db/schema_migrations/202303021232581
-rw-r--r--db/schema_migrations/202303021232591
-rw-r--r--db/schema_migrations/202303021233011
-rw-r--r--db/schema_migrations/202303021633391
-rw-r--r--db/schema_migrations/202303021857391
-rw-r--r--db/schema_migrations/202303031058061
-rw-r--r--db/schema_migrations/202303031205311
-rw-r--r--db/schema_migrations/202303031444241
-rw-r--r--db/schema_migrations/202303031543141
-rw-r--r--db/schema_migrations/202303041844161
-rw-r--r--db/schema_migrations/202303060714561
-rw-r--r--db/schema_migrations/202303060725321
-rw-r--r--db/schema_migrations/202303060828521
-rw-r--r--db/schema_migrations/202303061433221
-rw-r--r--db/schema_migrations/202303061452301
-rw-r--r--db/schema_migrations/202303061950071
-rw-r--r--db/schema_migrations/202303070856441
-rw-r--r--db/schema_migrations/202303070912161
-rw-r--r--db/schema_migrations/202303071228381
-rw-r--r--db/schema_migrations/202303071602511
-rw-r--r--db/schema_migrations/202303072336311
-rw-r--r--db/schema_migrations/202303081630181
-rw-r--r--db/schema_migrations/202303090009571
-rw-r--r--db/schema_migrations/202303090100001
-rw-r--r--db/schema_migrations/202303090109311
-rw-r--r--db/schema_migrations/202303090204221
-rw-r--r--db/schema_migrations/202303090712421
-rw-r--r--db/schema_migrations/202303091030161
-rw-r--r--db/schema_migrations/202303101118591
-rw-r--r--db/schema_migrations/202303130542261
-rw-r--r--db/schema_migrations/202303131009201
-rw-r--r--db/schema_migrations/202303131330011
-rw-r--r--db/schema_migrations/202303131430331
-rw-r--r--db/schema_migrations/202303131505311
-rw-r--r--db/schema_migrations/202303131843061
-rw-r--r--db/schema_migrations/202303131851451
-rw-r--r--db/schema_migrations/202303160146501
-rw-r--r--db/structure.sql437
-rw-r--r--doc/.vale/gitlab/CodeblockFences.yml4
-rw-r--r--doc/.vale/gitlab/HeadingDepth.yml2
-rw-r--r--doc/.vale/gitlab/Substitutions.yml1
-rw-r--r--doc/.vale/gitlab/spelling-exceptions.txt10
-rw-r--r--doc/administration/audit_event_streaming.md56
-rw-r--r--doc/administration/audit_events.md13
-rw-r--r--doc/administration/auth/authentiq.md12
-rw-r--r--doc/administration/auth/ldap/index.md2
-rw-r--r--doc/administration/auth/ldap/ldap-troubleshooting.md4
-rw-r--r--doc/administration/auth/ldap/ldap_synchronization.md44
-rw-r--r--doc/administration/auth/oidc.md248
-rw-r--r--doc/administration/clusters/kas.md44
-rw-r--r--doc/administration/dedicated/index.md108
-rw-r--r--doc/administration/docs_self_host.md20
-rw-r--r--doc/administration/environment_variables.md2
-rw-r--r--doc/administration/geo/index.md3
-rw-r--r--doc/administration/geo/replication/configuration.md16
-rw-r--r--doc/administration/geo/replication/container_registry.md16
-rw-r--r--doc/administration/geo/replication/datatypes.md8
-rw-r--r--doc/administration/geo/replication/geo_validation_tests.md3
-rw-r--r--doc/administration/geo/replication/img/adding_a_secondary_v15_8.pngbin0 -> 14698 bytes
-rw-r--r--doc/administration/geo/replication/troubleshooting.md21
-rw-r--r--doc/administration/geo/replication/upgrading_the_geo_sites.md1
-rw-r--r--doc/administration/geo/secondary_proxy/index.md1
-rw-r--r--doc/administration/geo/setup/database.md44
-rw-r--r--doc/administration/geo/setup/external_database.md16
-rw-r--r--doc/administration/geo/setup/index.md23
-rw-r--r--doc/administration/get_started.md7
-rw-r--r--doc/administration/git_protocol.md2
-rw-r--r--doc/administration/gitaly/configure_gitaly.md346
-rw-r--r--doc/administration/gitaly/index.md23
-rw-r--r--doc/administration/gitaly/monitoring.md11
-rw-r--r--doc/administration/gitaly/praefect.md549
-rw-r--r--doc/administration/gitaly/recovery.md70
-rw-r--r--doc/administration/gitaly/reference.md9
-rw-r--r--doc/administration/gitaly/troubleshooting.md27
-rw-r--r--doc/administration/index.md2
-rw-r--r--doc/administration/instance_limits.md33
-rw-r--r--doc/administration/integration/kroki.md15
-rw-r--r--doc/administration/integration/plantuml.md13
-rw-r--r--doc/administration/integration/terminal.md2
-rw-r--r--doc/administration/job_artifacts.md4
-rw-r--r--doc/administration/lfs/index.md14
-rw-r--r--doc/administration/load_balancer.md2
-rw-r--r--doc/administration/logs/index.md22
-rw-r--r--doc/administration/monitoring/gitlab_self_monitoring_project/index.md2
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md110
-rw-r--r--doc/administration/monitoring/prometheus/index.md5
-rw-r--r--doc/administration/object_storage.md426
-rw-r--r--doc/administration/operations/gitlab_sshd.md10
-rw-r--r--doc/administration/operations/index.md1
-rw-r--r--doc/administration/operations/moving_repositories.md16
-rw-r--r--doc/administration/operations/rails_console.md2
-rw-r--r--doc/administration/package_information/supported_os.md9
-rw-r--r--doc/administration/packages/container_registry.md108
-rw-r--r--doc/administration/pages/index.md46
-rw-r--r--doc/administration/postgresql/external.md24
-rw-r--r--doc/administration/postgresql/multiple_databases.md89
-rw-r--r--doc/administration/postgresql/pgbouncer.md21
-rw-r--r--doc/administration/raketasks/github_import.md2
-rw-r--r--doc/administration/raketasks/project_import_export.md144
-rw-r--r--doc/administration/read_only_gitlab.md44
-rw-r--r--doc/administration/redis/replication_and_failover.md43
-rw-r--r--doc/administration/redis/replication_and_failover_external.md14
-rw-r--r--doc/administration/reference_architectures/10k_users.md233
-rw-r--r--doc/administration/reference_architectures/1k_users.md4
-rw-r--r--doc/administration/reference_architectures/25k_users.md235
-rw-r--r--doc/administration/reference_architectures/2k_users.md75
-rw-r--r--doc/administration/reference_architectures/3k_users.md197
-rw-r--r--doc/administration/reference_architectures/50k_users.md235
-rw-r--r--doc/administration/reference_architectures/5k_users.md193
-rw-r--r--doc/administration/reference_architectures/index.md36
-rw-r--r--doc/administration/reply_by_email.md4
-rw-r--r--doc/administration/repository_checks.md35
-rw-r--r--doc/administration/server_hooks.md2
-rw-r--r--doc/administration/sidekiq/extra_sidekiq_routing.md11
-rw-r--r--doc/administration/sidekiq/index.md28
-rw-r--r--doc/administration/sidekiq/processing_specific_job_classes.md25
-rw-r--r--doc/administration/terraform_state.md22
-rw-r--r--doc/administration/uploads.md5
-rw-r--r--doc/api/audit_events.md5
-rw-r--r--doc/api/commits.md8
-rw-r--r--doc/api/deploy_keys.md4
-rw-r--r--doc/api/deploy_tokens.md4
-rw-r--r--doc/api/deployments.md4
-rw-r--r--doc/api/discussions.md21
-rw-r--r--doc/api/dora/metrics.md2
-rw-r--r--doc/api/draft_notes.md40
-rw-r--r--doc/api/environments.md4
-rw-r--r--doc/api/error_tracking.md41
-rw-r--r--doc/api/feature_flag_specs.md14
-rw-r--r--doc/api/feature_flag_user_lists.md4
-rw-r--r--doc/api/feature_flags.md4
-rw-r--r--doc/api/features.md4
-rw-r--r--doc/api/freeze_periods.md4
-rw-r--r--doc/api/geo_nodes.md21
-rw-r--r--doc/api/graphql/getting_started.md7
-rw-r--r--doc/api/graphql/reference/index.md765
-rw-r--r--doc/api/group_badges.md6
-rw-r--r--doc/api/group_clusters.md2
-rw-r--r--doc/api/group_import_export.md24
-rw-r--r--doc/api/group_iterations.md4
-rw-r--r--doc/api/group_level_variables.md2
-rw-r--r--doc/api/group_milestones.md6
-rw-r--r--doc/api/group_protected_branches.md469
-rw-r--r--doc/api/group_protected_environments.md4
-rw-r--r--doc/api/group_releases.md4
-rw-r--r--doc/api/groups.md51
-rw-r--r--doc/api/import.md26
-rw-r--r--doc/api/instance_clusters.md2
-rw-r--r--doc/api/instance_level_ci_variables.md2
-rw-r--r--doc/api/integrations.md115
-rw-r--r--doc/api/iterations.md4
-rw-r--r--doc/api/job_artifacts.md2
-rw-r--r--doc/api/keys.md32
-rw-r--r--doc/api/license.md32
-rw-r--r--doc/api/lint.md208
-rw-r--r--doc/api/managed_licenses.md5
-rw-r--r--doc/api/member_roles.md2
-rw-r--r--doc/api/merge_request_approvals.md2
-rw-r--r--doc/api/merge_requests.md3
-rw-r--r--doc/api/merge_trains.md71
-rw-r--r--doc/api/milestones.md14
-rw-r--r--doc/api/namespaces.md5
-rw-r--r--doc/api/notes.md48
-rw-r--r--doc/api/oauth2.md4
-rw-r--r--doc/api/openapi/openapi.yaml2
-rw-r--r--doc/api/packages.md3
-rw-r--r--doc/api/pages.md8
-rw-r--r--doc/api/pages_domains.md6
-rw-r--r--doc/api/pipeline_triggers.md2
-rw-r--r--doc/api/product_analytics.md3
-rw-r--r--doc/api/project_badges.md2
-rw-r--r--doc/api/project_clusters.md2
-rw-r--r--doc/api/project_import_export.md14
-rw-r--r--doc/api/project_level_variables.md2
-rw-r--r--doc/api/project_vulnerabilities.md4
-rw-r--r--doc/api/projects.md48
-rw-r--r--doc/api/protected_branches.md42
-rw-r--r--doc/api/protected_environments.md4
-rw-r--r--doc/api/protected_tags.md63
-rw-r--r--doc/api/releases/index.md4
-rw-r--r--doc/api/releases/links.md4
-rw-r--r--doc/api/resource_groups.md4
-rw-r--r--doc/api/rest/deprecations.md86
-rw-r--r--doc/api/rest/index.md19
-rw-r--r--doc/api/search.md15
-rw-r--r--doc/api/secure_files.md2
-rw-r--r--doc/api/settings.md16
-rw-r--r--doc/api/suggestions.md16
-rw-r--r--doc/api/topics.md4
-rw-r--r--doc/api/users.md2
-rw-r--r--doc/api/visual_review_discussions.md2
-rw-r--r--doc/architecture/blueprints/_template.md13
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-admin-area.md58
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md29
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-backups.md61
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-ci-runners.md169
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-container-registry.md131
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-contributions-forks.md120
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-dashboard.md29
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-data-migration.md130
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-database-sequences.md94
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-git-access.md163
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md29
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-global-search.md47
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-graphql.md94
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-organizations.md58
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md29
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md46
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-schema-changes.md55
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-secrets.md48
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-snippets.md29
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-template.md29
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-uploads.md29
-rw-r--r--doc/architecture/blueprints/cells/images/iteration0-organizations-introduction.png (renamed from doc/architecture/blueprints/pods/images/iteration0-organizations-introduction.png)bin67160 -> 67160 bytes
-rw-r--r--doc/architecture/blueprints/cells/images/pods-and-fulfillment.png (renamed from doc/architecture/blueprints/pods/images/pods-and-fulfillment.png)bin20899 -> 20899 bytes
-rw-r--r--doc/architecture/blueprints/cells/images/term-cell.pngbin0 -> 88371 bytes
-rw-r--r--doc/architecture/blueprints/cells/images/term-cluster.pngbin0 -> 429127 bytes
-rw-r--r--doc/architecture/blueprints/cells/images/term-organization.pngbin0 -> 156340 bytes
-rw-r--r--doc/architecture/blueprints/cells/images/term-top-level-namespace.png (renamed from doc/architecture/blueprints/pods/images/term-top-level-namespace.png)bin11451 -> 11451 bytes
-rw-r--r--doc/architecture/blueprints/cells/index.md358
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-admin-area.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-agent-for-kubernetes.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-backups.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-ci-runners.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-container-registry.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-contributions-forks.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-dashboard.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-data-migration.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-database-sequences.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-git-access.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-gitlab-pages.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-global-search.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-graphql.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-organizations.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-personal-namespaces.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-router-endpoints-classification.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-schema-changes.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-secrets.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-snippets.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-template.md11
-rw-r--r--doc/architecture/blueprints/cells/pods-feature-uploads.md11
-rw-r--r--doc/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md648
-rw-r--r--doc/architecture/blueprints/cells/proposal-stateless-router-with-routes-learning.md672
-rw-r--r--doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md16
-rw-r--r--doc/architecture/blueprints/ci_pipeline_components/dev_workflow.md155
-rw-r--r--doc/architecture/blueprints/ci_pipeline_components/img/new_release.pngbin0 -> 13622 bytes
-rw-r--r--doc/architecture/blueprints/ci_pipeline_components/img/pipeline_main.pngbin0 -> 6644 bytes
-rw-r--r--doc/architecture/blueprints/ci_pipeline_components/img/pipeline_tag.pngbin0 -> 8697 bytes
-rw-r--r--doc/architecture/blueprints/ci_pipeline_components/index.md185
-rw-r--r--doc/architecture/blueprints/clickhouse_usage/index.md52
-rw-r--r--doc/architecture/blueprints/code_search_with_zoekt/index.md305
-rw-r--r--doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md92
-rw-r--r--doc/architecture/blueprints/consolidating_groups_and_projects/index.md5
-rw-r--r--doc/architecture/blueprints/gitlab_agent_deployments/index.md2
-rw-r--r--doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md4
-rw-r--r--doc/architecture/blueprints/object_storage/index.md2
-rw-r--r--doc/architecture/blueprints/pods/images/term-cluster.pngbin63268 -> 0 bytes
-rw-r--r--doc/architecture/blueprints/pods/images/term-organization.pngbin7150 -> 0 bytes
-rw-r--r--doc/architecture/blueprints/pods/images/term-pod.pngbin16104 -> 0 bytes
-rw-r--r--doc/architecture/blueprints/pods/index.md359
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-admin-area.md61
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-agent-for-kubernetes.md32
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-backups.md64
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-ci-runners.md172
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-container-registry.md134
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-contributions-forks.md123
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-dashboard.md32
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-data-migration.md133
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-database-sequences.md97
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-git-access.md166
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-gitlab-pages.md32
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-global-search.md50
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-graphql.md97
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-organizations.md61
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-personal-namespaces.md32
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md49
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-schema-changes.md58
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-secrets.md51
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-snippets.md32
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-template.md32
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-uploads.md32
-rw-r--r--doc/architecture/blueprints/pods/proposal-stateless-router-with-buffering-requests.md651
-rw-r--r--doc/architecture/blueprints/pods/proposal-stateless-router-with-routes-learning.md675
-rw-r--r--doc/architecture/blueprints/rate_limiting/index.md2
-rw-r--r--doc/architecture/blueprints/runner_tokens/index.md52
-rw-r--r--doc/architecture/blueprints/search/code_search_with_zoekt.md305
-rw-r--r--doc/ci/caching/index.md17
-rw-r--r--doc/ci/chatops/img/gitlab-chatops-icon-small.pngbin2922 -> 0 bytes
-rw-r--r--doc/ci/chatops/index.md125
-rw-r--r--doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md4
-rw-r--r--doc/ci/cloud_deployment/heroku.md4
-rw-r--r--doc/ci/cloud_deployment/index.md4
-rw-r--r--doc/ci/cloud_services/aws/index.md2
-rw-r--r--doc/ci/cloud_services/azure/index.md2
-rw-r--r--doc/ci/cloud_services/google_cloud/index.md2
-rw-r--r--doc/ci/cloud_services/index.md2
-rw-r--r--doc/ci/docker/using_docker_build.md175
-rw-r--r--doc/ci/environments/deployment_approvals.md4
-rw-r--r--doc/ci/environments/deployment_safety.md4
-rw-r--r--doc/ci/environments/environments_dashboard.md4
-rw-r--r--doc/ci/environments/external_deployment_tools.md76
-rw-r--r--doc/ci/environments/img/environments_project_home.pngbin70687 -> 23937 bytes
-rw-r--r--doc/ci/environments/incremental_rollouts.md4
-rw-r--r--doc/ci/environments/index.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/composer-npm-deploy.md4
-rw-r--r--doc/ci/examples/deployment/index.md4
-rw-r--r--doc/ci/examples/end_to_end_testing_webdriverio/index.md2
-rw-r--r--doc/ci/examples/index.md2
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/index.md2
-rw-r--r--doc/ci/examples/semantic-release.md2
-rw-r--r--doc/ci/introduction/index.md2
-rw-r--r--doc/ci/jobs/ci_job_token.md27
-rw-r--r--doc/ci/jobs/index.md6
-rw-r--r--doc/ci/large_repositories/index.md2
-rw-r--r--doc/ci/lint.md4
-rw-r--r--doc/ci/pipeline_editor/index.md2
-rw-r--r--doc/ci/pipelines/cicd_minutes.md13
-rw-r--r--doc/ci/pipelines/downstream_pipelines.md79
-rw-r--r--doc/ci/pipelines/img/multi_project_pipeline_graph_v14_3.pngbin30119 -> 0 bytes
-rw-r--r--doc/ci/pipelines/img/pipeline_mini_graph_v15_0.pngbin6061 -> 0 bytes
-rw-r--r--doc/ci/pipelines/index.md3
-rw-r--r--doc/ci/pipelines/job_artifacts.md4
-rw-r--r--doc/ci/pipelines/merge_request_pipelines.md9
-rw-r--r--doc/ci/pipelines/pipeline_architectures.md2
-rw-r--r--doc/ci/pipelines/pipeline_artifacts.md2
-rw-r--r--doc/ci/pipelines/settings.md2
-rw-r--r--doc/ci/resource_groups/index.md4
-rw-r--r--doc/ci/review_apps/index.md2
-rw-r--r--doc/ci/runners/configure_runners.md7
-rw-r--r--doc/ci/runners/index.md2
-rw-r--r--doc/ci/runners/register_runner.md33
-rw-r--r--doc/ci/runners/saas/linux_saas_runner.md11
-rw-r--r--doc/ci/runners/saas/macos/environment.md4
-rw-r--r--doc/ci/runners/saas/macos_saas_runner.md2
-rw-r--r--doc/ci/secrets/id_token_authentication.md4
-rw-r--r--doc/ci/secrets/index.md2
-rw-r--r--doc/ci/secure_files/index.md2
-rw-r--r--doc/ci/services/index.md2
-rw-r--r--doc/ci/ssh_keys/index.md2
-rw-r--r--doc/ci/test_cases/index.md12
-rw-r--r--doc/ci/testing/accessibility_testing.md2
-rw-r--r--doc/ci/testing/browser_performance_testing.md2
-rw-r--r--doc/ci/testing/code_quality.md7
-rw-r--r--doc/ci/testing/fail_fast_testing.md2
-rw-r--r--doc/ci/testing/img/code_quality_summary_15_9.pngbin0 -> 71968 bytes
-rw-r--r--doc/ci/testing/index.md2
-rw-r--r--doc/ci/testing/load_performance_testing.md2
-rw-r--r--doc/ci/testing/metrics_reports.md2
-rw-r--r--doc/ci/testing/test_coverage_visualization.md4
-rw-r--r--doc/ci/testing/unit_test_report_examples.md23
-rw-r--r--doc/ci/testing/unit_test_reports.md2
-rw-r--r--doc/ci/triggers/index.md12
-rw-r--r--doc/ci/troubleshooting.md4
-rw-r--r--doc/ci/variables/index.md10
-rw-r--r--doc/ci/variables/predefined_variables.md2
-rw-r--r--doc/ci/variables/where_variables_can_be_used.md2
-rw-r--r--doc/ci/yaml/artifacts_reports.md4
-rw-r--r--doc/ci/yaml/includes.md56
-rw-r--r--doc/ci/yaml/index.md88
-rw-r--r--doc/cloud_seed/index.md2
-rw-r--r--doc/development/advanced_search.md336
-rw-r--r--doc/development/api_graphql_styleguide.md2
-rw-r--r--doc/development/api_styleguide.md11
-rw-r--r--doc/development/application_slis/index.md2
-rw-r--r--doc/development/application_slis/rails_request.md282
-rw-r--r--doc/development/application_slis/rails_request_apdex.md253
-rw-r--r--doc/development/architecture.md23
-rw-r--r--doc/development/audit_event_guide/index.md2
-rw-r--r--doc/development/auto_devops.md2
-rw-r--r--doc/development/backend/create_source_code_be/gitaly_touch_points.md2
-rw-r--r--doc/development/backend/create_source_code_be/index.md8
-rw-r--r--doc/development/bulk_import.md9
-rw-r--r--doc/development/caching.md6
-rw-r--r--doc/development/cascading_settings.md36
-rw-r--r--doc/development/changelog.md2
-rw-r--r--doc/development/cicd/cicd_tables.md119
-rw-r--r--doc/development/cicd/index.md3
-rw-r--r--doc/development/cicd/templates.md1
-rw-r--r--doc/development/code_intelligence/index.md2
-rw-r--r--doc/development/code_owners/index.md132
-rw-r--r--doc/development/code_review.md14
-rw-r--r--doc/development/contributing/design.md4
-rw-r--r--doc/development/contributing/index.md28
-rw-r--r--doc/development/contributing/issue_workflow.md322
-rw-r--r--doc/development/contributing/merge_request_workflow.md65
-rw-r--r--doc/development/contributing/style_guides.md24
-rw-r--r--doc/development/dangerbot.md28
-rw-r--r--doc/development/database/add_foreign_key_to_existing_column.md19
-rw-r--r--doc/development/database/batched_background_migrations.md143
-rw-r--r--doc/development/database/clickhouse/merge_request_analytics.md355
-rw-r--r--doc/development/database/clickhouse/tiered_storage.md138
-rw-r--r--doc/development/database/database_dictionary.md1
-rw-r--r--doc/development/database/database_lab.md15
-rw-r--r--doc/development/database/database_migration_pipeline.md2
-rw-r--r--doc/development/database/database_reviewer_guidelines.md5
-rw-r--r--doc/development/database/index.md4
-rw-r--r--doc/development/database/multiple_databases.md2
-rw-r--r--doc/development/database/query_performance.md4
-rw-r--r--doc/development/database/required_stops.md30
-rw-r--r--doc/development/database/understanding_explain_plans.md31
-rw-r--r--doc/development/database_review.md29
-rw-r--r--doc/development/deprecation_guidelines/index.md4
-rw-r--r--doc/development/directory_structure.md11
-rw-r--r--doc/development/distributed_tracing.md2
-rw-r--r--doc/development/distribution/index.md35
-rw-r--r--doc/development/documentation/alpha_beta.md43
-rw-r--r--doc/development/documentation/contribute.md83
-rw-r--r--doc/development/documentation/feature_flags.md74
-rw-r--r--doc/development/documentation/index.md20
-rw-r--r--doc/development/documentation/restful_api_styleguide.md2
-rw-r--r--doc/development/documentation/styleguide/index.md12
-rw-r--r--doc/development/documentation/styleguide/word_list.md76
-rw-r--r--doc/development/documentation/topic_types/task.md16
-rw-r--r--doc/development/documentation/versions.md7
-rw-r--r--doc/development/documentation/workflow.md168
-rw-r--r--doc/development/ee_features.md110
-rw-r--r--doc/development/elasticsearch.md625
-rw-r--r--doc/development/fe_guide/accessibility.md51
-rw-r--r--doc/development/fe_guide/content_editor.md2
-rw-r--r--doc/development/fe_guide/frontend_faq.md4
-rw-r--r--doc/development/fe_guide/graphql.md595
-rw-r--r--doc/development/fe_guide/merge_request_widget_extensions.md1
-rw-r--r--doc/development/fe_guide/performance.md24
-rw-r--r--doc/development/fe_guide/source_editor.md6
-rw-r--r--doc/development/fe_guide/storybook.md28
-rw-r--r--doc/development/fe_guide/style/html.md2
-rw-r--r--doc/development/fe_guide/style/index.md2
-rw-r--r--doc/development/fe_guide/style/javascript.md19
-rw-r--r--doc/development/fe_guide/style/vue.md280
-rw-r--r--doc/development/fe_guide/vue.md31
-rw-r--r--doc/development/fe_guide/vuex.md16
-rw-r--r--doc/development/fe_guide/widgets.md4
-rw-r--r--doc/development/feature_development.md3
-rw-r--r--doc/development/feature_flags/controls.md2
-rw-r--r--doc/development/feature_flags/index.md2
-rw-r--r--doc/development/fips_compliance.md88
-rw-r--r--doc/development/gemfile.md20
-rw-r--r--doc/development/gitaly.md12
-rw-r--r--doc/development/github_importer.md21
-rw-r--r--doc/development/gitlab_flavored_markdown/index.md2
-rw-r--r--doc/development/gitlab_shell/index.md6
-rw-r--r--doc/development/gitpod_internals.md2
-rw-r--r--doc/development/go_guide/go_upgrade.md2
-rw-r--r--doc/development/go_guide/index.md14
-rw-r--r--doc/development/i18n/proofreader.md2
-rw-r--r--doc/development/image_scaling.md4
-rw-r--r--doc/development/img/feature-flag-metrics.pngbin88110 -> 27814 bytes
-rw-r--r--doc/development/import_project.md146
-rw-r--r--doc/development/integrations/codesandbox.md155
-rw-r--r--doc/development/integrations/index.md4
-rw-r--r--doc/development/integrations/jenkins.md4
-rw-r--r--doc/development/integrations/jira_connect.md24
-rw-r--r--doc/development/integrations/secure.md17
-rw-r--r--doc/development/internal_api/index.md34
-rw-r--r--doc/development/issue_types.md2
-rw-r--r--doc/development/json.md2
-rw-r--r--doc/development/kubernetes.md2
-rw-r--r--doc/development/labels/index.md348
-rw-r--r--doc/development/lfs.md4
-rw-r--r--doc/development/logging.md24
-rw-r--r--doc/development/merge_request_concepts/approval_rules.md2
-rw-r--r--doc/development/merge_request_concepts/diffs/index.md2
-rw-r--r--doc/development/merge_request_concepts/index.md2
-rw-r--r--doc/development/merge_request_concepts/performance.md2
-rw-r--r--doc/development/migration_style_guide.md10
-rw-r--r--doc/development/navigation_sidebar.md38
-rw-r--r--doc/development/organization/index.md159
-rw-r--r--doc/development/packages/debian_repository.md4
-rw-r--r--doc/development/packages/index.md2
-rw-r--r--doc/development/permissions.md125
-rw-r--r--doc/development/pipelines/index.md27
-rw-r--r--doc/development/pipelines/internals.md2
-rw-r--r--doc/development/pipelines/performance.md2
-rw-r--r--doc/development/product_qualified_lead_guide/index.md2
-rw-r--r--doc/development/project_templates.md2
-rw-r--r--doc/development/prometheus_metrics.md2
-rw-r--r--doc/development/python_guide/index.md2
-rw-r--r--doc/development/rails_update.md52
-rw-r--r--doc/development/rake_tasks.md2
-rw-r--r--doc/development/real_time.md2
-rw-r--r--doc/development/redis.md22
-rw-r--r--doc/development/redis/new_redis_instance.md64
-rw-r--r--doc/development/repository_mirroring.md2
-rw-r--r--doc/development/rubocop_development_guide.md6
-rw-r--r--doc/development/search/advanced_search_migration_styleguide.md311
-rw-r--r--doc/development/sec/index.md4
-rw-r--r--doc/development/secure_coding_guidelines.md61
-rw-r--r--doc/development/service_ping/implement.md73
-rw-r--r--doc/development/service_ping/index.md40
-rw-r--r--doc/development/service_ping/metrics_dictionary.md4
-rw-r--r--doc/development/service_ping/metrics_instrumentation.md6
-rw-r--r--doc/development/service_ping/metrics_lifecycle.md6
-rw-r--r--doc/development/shell_commands.md2
-rw-r--r--doc/development/sidekiq/compatibility_across_updates.md150
-rw-r--r--doc/development/sidekiq/index.md2
-rw-r--r--doc/development/snowplow/event_dictionary_guide.md7
-rw-r--r--doc/development/snowplow/implementation.md182
-rw-r--r--doc/development/snowplow/index.md2
-rw-r--r--doc/development/snowplow/review_guidelines.md3
-rw-r--r--doc/development/spam_protection_and_captcha/exploratory_testing.md1
-rw-r--r--doc/development/spam_protection_and_captcha/model_and_services.md6
-rw-r--r--doc/development/stage_group_observability/img/error_budgets_kibana_dashboard_v15_10.pngbin0 -> 142096 bytes
-rw-r--r--doc/development/stage_group_observability/index.md42
-rw-r--r--doc/development/testing_guide/best_practices.md2
-rw-r--r--doc/development/testing_guide/contract/index.md4
-rw-r--r--doc/development/testing_guide/end_to_end/beginners_guide.md2
-rw-r--r--doc/development/testing_guide/end_to_end/best_practices.md4
-rw-r--r--doc/development/testing_guide/end_to_end/rspec_metadata_tests.md2
-rw-r--r--doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md20
-rw-r--r--doc/development/testing_guide/flaky_tests.md6
-rw-r--r--doc/development/testing_guide/frontend_testing.md19
-rw-r--r--doc/development/testing_guide/review_apps.md2
-rw-r--r--doc/development/testing_guide/testing_levels.md2
-rw-r--r--doc/development/uploads/index.md2
-rw-r--r--doc/development/uploads/working_with_uploads.md2
-rw-r--r--doc/development/ux/index.md26
-rw-r--r--doc/development/value_stream_analytics.md4
-rw-r--r--doc/development/wikis.md2
-rw-r--r--doc/development/windows.md2
-rw-r--r--doc/development/workspace/index.md162
-rw-r--r--doc/drawers/advanced_search_syntax.md1
-rw-r--r--doc/gitlab-basics/add-file.md178
-rw-r--r--doc/gitlab-basics/command-line-commands.md126
-rw-r--r--doc/gitlab-basics/start-using-git.md2
-rw-r--r--doc/index.md4
-rw-r--r--doc/install/aws/index.md2
-rw-r--r--doc/install/installation.md22
-rw-r--r--doc/install/next_steps.md2
-rw-r--r--doc/integration/advanced_search/elasticsearch.md152
-rw-r--r--doc/integration/advanced_search/elasticsearch_troubleshooting.md16
-rw-r--r--doc/integration/datadog.md2
-rw-r--r--doc/integration/ding_talk.md3
-rw-r--r--doc/integration/external-issue-tracker.md2
-rw-r--r--doc/integration/facebook.md2
-rw-r--r--doc/integration/gitpod.md2
-rw-r--r--doc/integration/glab/index.md33
-rw-r--r--doc/integration/gmail_action_buttons_for_gitlab.md3
-rw-r--r--doc/integration/google.md2
-rw-r--r--doc/integration/index.md2
-rw-r--r--doc/integration/jenkins.md2
-rw-r--r--doc/integration/jira/configure.md6
-rw-r--r--doc/integration/jira/connect-app.md32
-rw-r--r--doc/integration/jira/development_panel.md127
-rw-r--r--doc/integration/jira/img/jira_dev_panel_jira_setup_3.pngbin80136 -> 0 bytes
-rw-r--r--doc/integration/jira/img/jira_dev_panel_jira_setup_4.pngbin21592 -> 0 bytes
-rw-r--r--doc/integration/jira/img/jira_dev_panel_jira_setup_5.pngbin10336 -> 0 bytes
-rw-r--r--doc/integration/jira/index.md8
-rw-r--r--doc/integration/jira/issues.md15
-rw-r--r--doc/integration/jira/jira_server_configuration.md10
-rw-r--r--doc/integration/jira/troubleshooting.md6
-rw-r--r--doc/integration/mattermost/index.md10
-rw-r--r--doc/integration/omniauth.md8
-rw-r--r--doc/integration/partner_marketplace.md114
-rw-r--r--doc/integration/saml.md6
-rw-r--r--doc/integration/trello_power_up.md8
-rw-r--r--doc/operations/error_tracking.md268
-rw-r--r--doc/operations/feature_flags.md13
-rw-r--r--doc/operations/img/copy-group-id.pngbin112686 -> 0 bytes
-rw-r--r--doc/operations/img/create-gitlab-application.pngbin521206 -> 0 bytes
-rw-r--r--doc/operations/img/error_tracking_setting_dsn_v14_4.pngbin39249 -> 0 bytes
-rw-r--r--doc/operations/img/error_tracking_setting_v14_3.pngbin27537 -> 0 bytes
-rw-r--r--doc/operations/img/listing_groups.pngbin40621 -> 0 bytes
-rw-r--r--doc/operations/incident_management/incident_timeline_events.md9
-rw-r--r--doc/operations/incident_management/manage_incidents.md2
-rw-r--r--doc/operations/index.md6
-rw-r--r--doc/operations/metrics/dashboards/default.md2
-rw-r--r--doc/operations/metrics/dashboards/develop.md2
-rw-r--r--doc/operations/metrics/dashboards/index.md8
-rw-r--r--doc/operations/metrics/dashboards/panel_types.md2
-rw-r--r--doc/operations/metrics/dashboards/settings.md2
-rw-r--r--doc/operations/metrics/dashboards/templating_variables.md2
-rw-r--r--doc/operations/metrics/dashboards/variables.md2
-rw-r--r--doc/operations/metrics/dashboards/yaml.md2
-rw-r--r--doc/operations/metrics/embed.md5
-rw-r--r--doc/operations/metrics/index.md4
-rw-r--r--doc/operations/quickstart-guide.md229
-rw-r--r--doc/policy/alpha-beta-support.md2
-rw-r--r--doc/policy/maintenance.md6
-rw-r--r--doc/raketasks/backup_gitlab.md12
-rw-r--r--doc/raketasks/backup_restore.md2
-rw-r--r--doc/raketasks/cleanup.md2
-rw-r--r--doc/raketasks/generate_sample_prometheus_data.md12
-rw-r--r--doc/raketasks/index.md7
-rw-r--r--doc/raketasks/restore_gitlab.md6
-rw-r--r--doc/security/index.md2
-rw-r--r--doc/security/reset_user_password.md16
-rw-r--r--doc/security/token_overview.md2
-rw-r--r--doc/security/user_file_uploads.md24
-rw-r--r--doc/security/webhooks.md111
-rw-r--r--doc/subscriptions/bronze_starter.md4
-rw-r--r--doc/subscriptions/gitlab_com/index.md11
-rw-r--r--doc/subscriptions/gitlab_dedicated/index.md109
-rw-r--r--doc/subscriptions/index.md23
-rw-r--r--doc/subscriptions/self_managed/index.md2
-rw-r--r--doc/topics/authentication/index.md2
-rw-r--r--doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md301
-rw-r--r--doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md2
-rw-r--r--doc/topics/autodevops/index.md1
-rw-r--r--doc/topics/autodevops/upgrading_postgresql.md87
-rw-r--r--doc/topics/awesome_co.md70
-rw-r--r--doc/topics/git/bisect.md79
-rw-r--r--doc/topics/git/feature_branching.md34
-rw-r--r--doc/topics/git/git_log.md63
-rw-r--r--doc/topics/git/index.md8
-rw-r--r--doc/topics/git/merge_conflicts.md11
-rw-r--r--doc/topics/git/partial_clone.md4
-rw-r--r--doc/topics/git/subtree.md53
-rw-r--r--doc/topics/git/tags.md44
-rw-r--r--doc/topics/git/troubleshooting_git.md16
-rw-r--r--doc/topics/git/unstage.md14
-rw-r--r--doc/topics/git/useful_git_commands.md6
-rw-r--r--doc/topics/offline/quick_start_guide.md86
-rw-r--r--doc/topics/set_up_organization.md2
-rw-r--r--doc/topics/your_work.md5
-rw-r--r--doc/tutorials/convert_personal_namespace_into_group.md95
-rw-r--r--doc/tutorials/index.md1
-rw-r--r--doc/update/background_migrations.md6
-rw-r--r--doc/update/deprecations.md328
-rw-r--r--doc/update/index.md460
-rw-r--r--doc/update/mysql_to_postgresql.md11
-rw-r--r--doc/update/package/convert_to_ee.md2
-rw-r--r--doc/update/package/index.md2
-rw-r--r--doc/update/plan_your_upgrade.md2
-rw-r--r--doc/update/removals.md22
-rw-r--r--doc/update/restore_after_failure.md12
-rw-r--r--doc/update/upgrading_from_source.md9
-rw-r--r--doc/update/upgrading_postgresql_using_slony.md12
-rw-r--r--doc/update/zero_downtime.md4
-rw-r--r--doc/user/admin_area/analytics/index.md2
-rw-r--r--doc/user/admin_area/appearance.md21
-rw-r--r--doc/user/admin_area/custom_project_templates.md2
-rw-r--r--doc/user/admin_area/index.md10
-rw-r--r--doc/user/admin_area/license.md2
-rw-r--r--doc/user/admin_area/license_file.md7
-rw-r--r--doc/user/admin_area/monitoring/background_migrations.md11
-rw-r--r--doc/user/admin_area/reporting/git_abuse_rate_limit.md15
-rw-r--r--doc/user/admin_area/reporting/spamcheck.md12
-rw-r--r--doc/user/admin_area/settings/account_and_limit_settings.md10
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md4
-rw-r--r--doc/user/admin_area/settings/deprecated_api_rate_limits.md4
-rw-r--r--doc/user/admin_area/settings/external_authorization.md25
-rw-r--r--doc/user/admin_area/settings/files_api_rate_limits.md2
-rw-r--r--doc/user/admin_area/settings/index.md2
-rw-r--r--doc/user/admin_area/settings/rate_limit_on_projects_api.md33
-rw-r--r--doc/user/admin_area/settings/sign_up_restrictions.md48
-rw-r--r--doc/user/admin_area/settings/third_party_offers.md4
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md3
-rw-r--r--doc/user/analytics/ci_cd_analytics.md4
-rw-r--r--doc/user/analytics/dora_metrics.md125
-rw-r--r--doc/user/analytics/value_stream_analytics.md4
-rw-r--r--doc/user/analytics/value_streams_dashboard.md22
-rw-r--r--doc/user/application_security/api_fuzzing/index.md11
-rw-r--r--doc/user/application_security/api_security/api_discovery/index.md169
-rw-r--r--doc/user/application_security/api_security/index.md21
-rw-r--r--doc/user/application_security/configuration/index.md6
-rw-r--r--doc/user/application_security/container_scanning/index.md29
-rw-r--r--doc/user/application_security/coverage_fuzzing/index.md8
-rw-r--r--doc/user/application_security/dast/authentication.md48
-rw-r--r--doc/user/application_security/dast/browser_based.md32
-rw-r--r--doc/user/application_security/dast/proxy-based.md6
-rw-r--r--doc/user/application_security/dast_api/index.md11
-rw-r--r--doc/user/application_security/dependency_list/index.md2
-rw-r--r--doc/user/application_security/dependency_scanning/index.md51
-rw-r--r--doc/user/application_security/iac_scanning/index.md5
-rw-r--r--doc/user/application_security/policies/img/association_diagram.pngbin6624 -> 19149 bytes
-rw-r--r--doc/user/application_security/policies/img/policy_rule_mode_v14_9.pngbin34025 -> 0 bytes
-rw-r--r--doc/user/application_security/policies/img/policy_rule_mode_v15_9.pngbin0 -> 37866 bytes
-rw-r--r--doc/user/application_security/policies/img/policy_yaml_mode_v14_9.pngbin27424 -> 0 bytes
-rw-r--r--doc/user/application_security/policies/img/policy_yaml_mode_v15_9.pngbin0 -> 29904 bytes
-rw-r--r--doc/user/application_security/policies/img/scan_execution_policy_rule_mode_v15_5.pngbin23688 -> 0 bytes
-rw-r--r--doc/user/application_security/policies/img/scan_execution_policy_rule_mode_v15_9.pngbin0 -> 27667 bytes
-rw-r--r--doc/user/application_security/policies/img/scheduled_scan_execution_policies_diagram.pngbin0 -> 12050 bytes
-rw-r--r--doc/user/application_security/policies/index.md29
-rw-r--r--doc/user/application_security/policies/scan-execution-policies.md22
-rw-r--r--doc/user/application_security/policies/scan-result-policies.md14
-rw-r--r--doc/user/application_security/sast/index.md7
-rw-r--r--doc/user/application_security/secret_detection/index.md47
-rw-r--r--doc/user/application_security/secure_your_application.md2
-rw-r--r--doc/user/application_security/security_dashboard/img/security_center_dashboard_v13_4.pngbin29797 -> 0 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/security_center_dashboard_v15_10.pngbin0 -> 22361 bytes
-rw-r--r--doc/user/application_security/security_dashboard/index.md9
-rw-r--r--doc/user/application_security/vulnerabilities/index.md22
-rw-r--r--doc/user/application_security/vulnerability_report/index.md6
-rw-r--r--doc/user/award_emojis.md2
-rw-r--r--doc/user/clusters/agent/gitops.md4
-rw-r--r--doc/user/clusters/agent/gitops/flux.md36
-rw-r--r--doc/user/clusters/agent/gitops/flux_tutorial.md184
-rw-r--r--doc/user/clusters/agent/gitops/secrets_management.md6
-rw-r--r--doc/user/clusters/agent/index.md16
-rw-r--r--doc/user/clusters/agent/troubleshooting.md111
-rw-r--r--doc/user/clusters/cost_management.md2
-rw-r--r--doc/user/clusters/environments.md2
-rw-r--r--doc/user/clusters/integrations.md2
-rw-r--r--doc/user/clusters/management_project.md2
-rw-r--r--doc/user/clusters/migrating_from_gma_to_project_template.md2
-rw-r--r--doc/user/compliance/compliance_report/index.md193
-rw-r--r--doc/user/compliance/img/license_approval_policy_v15_9.pngbin33240 -> 30952 bytes
-rw-r--r--doc/user/compliance/license_approval_policies.md12
-rw-r--r--doc/user/compliance/license_check_rules.md2
-rw-r--r--doc/user/compliance/license_compliance/index.md2
-rw-r--r--doc/user/compliance/license_scanning_of_cyclonedx_files/index.md28
-rw-r--r--doc/user/crm/index.md4
-rw-r--r--doc/user/discussions/img/index_notes_filters.pngbin21284 -> 0 bytes
-rw-r--r--doc/user/discussions/index.md54
-rw-r--r--doc/user/enterprise_user/index.md39
-rw-r--r--doc/user/gitlab_com/index.md106
-rw-r--r--doc/user/group/access_and_permissions.md40
-rw-r--r--doc/user/group/clusters/index.md2
-rw-r--r--doc/user/group/compliance_frameworks.md48
-rw-r--r--doc/user/group/contribution_analytics/img/group_stats_cal.pngbin2029 -> 0 bytes
-rw-r--r--doc/user/group/contribution_analytics/img/group_stats_table.pngbin22691 -> 0 bytes
-rw-r--r--doc/user/group/custom_project_templates.md2
-rw-r--r--doc/user/group/epics/epic_boards.md20
-rw-r--r--doc/user/group/epics/img/epic_board_epic_create_v14_1.pngbin14584 -> 0 bytes
-rw-r--r--doc/user/group/epics/img/epic_board_epic_create_v15_10.pngbin0 -> 11786 bytes
-rw-r--r--doc/user/group/epics/img/epic_board_v14_1.pngbin28691 -> 0 bytes
-rw-r--r--doc/user/group/epics/img/epic_board_v15_10.pngbin0 -> 78145 bytes
-rw-r--r--doc/user/group/epics/manage_epics.md60
-rw-r--r--doc/user/group/import/index.md287
-rw-r--r--doc/user/group/index.md4
-rw-r--r--doc/user/group/manage.md8
-rw-r--r--doc/user/group/reporting/git_abuse_rate_limit.md15
-rw-r--r--doc/user/group/repositories_analytics/index.md2
-rw-r--r--doc/user/group/saml_sso/group_sync.md31
-rw-r--r--doc/user/group/saml_sso/img/Azure-manage-group-claims.pngbin84609 -> 24492 bytes
-rw-r--r--doc/user/group/saml_sso/index.md368
-rw-r--r--doc/user/group/saml_sso/scim_setup.md8
-rw-r--r--doc/user/group/saml_sso/troubleshooting_scim.md2
-rw-r--r--doc/user/group/settings/group_access_tokens.md16
-rw-r--r--doc/user/group/settings/import_export.md11
-rw-r--r--doc/user/group/subgroups/index.md6
-rw-r--r--doc/user/group/value_stream_analytics/img/object_hierarchy_example_V14_10.pngbin0 -> 20826 bytes
-rw-r--r--doc/user/group/value_stream_analytics/index.md247
-rw-r--r--doc/user/img/observability_copy_shortened_link.pngbin0 -> 15090 bytes
-rw-r--r--doc/user/infrastructure/clusters/connect/index.md2
-rw-r--r--doc/user/infrastructure/clusters/connect/new_civo_cluster.md24
-rw-r--r--doc/user/infrastructure/clusters/connect/new_eks_cluster.md98
-rw-r--r--doc/user/infrastructure/clusters/connect/new_gke_cluster.md26
-rw-r--r--doc/user/infrastructure/clusters/index.md2
-rw-r--r--doc/user/infrastructure/clusters/manage/clusters_health.md2
-rw-r--r--doc/user/infrastructure/iac/terraform_state.md4
-rw-r--r--doc/user/infrastructure/iac/terraform_template_recipes.md4
-rw-r--r--doc/user/instance/clusters/index.md2
-rw-r--r--doc/user/markdown.md86
-rw-r--r--doc/user/namespace/index.md4
-rw-r--r--doc/user/okrs.md50
-rw-r--r--doc/user/operations_dashboard/index.md4
-rw-r--r--doc/user/organization/index.md42
-rw-r--r--doc/user/packages/container_registry/reduce_container_registry_storage.md2
-rw-r--r--doc/user/packages/debian_repository/index.md107
-rw-r--r--doc/user/packages/go_proxy/index.md2
-rw-r--r--doc/user/packages/harbor_container_registry/index.md2
-rw-r--r--doc/user/packages/npm_registry/index.md44
-rw-r--r--doc/user/packages/nuget_repository/index.md2
-rw-r--r--doc/user/packages/package_registry/reduce_package_registry_storage.md3
-rw-r--r--doc/user/packages/package_registry/supported_functionality.md23
-rw-r--r--doc/user/packages/yarn_repository/index.md351
-rw-r--r--doc/user/permissions.md35
-rw-r--r--doc/user/product_analytics/index.md48
-rw-r--r--doc/user/profile/account/create_accounts.md8
-rw-r--r--doc/user/profile/account/delete_account.md1
-rw-r--r--doc/user/profile/account/two_factor_authentication.md178
-rw-r--r--doc/user/profile/active_sessions.md4
-rw-r--r--doc/user/profile/contributions_calendar.md6
-rw-r--r--doc/user/profile/img/saved_replies_dropdown_v15_10.pngbin0 -> 23623 bytes
-rw-r--r--doc/user/profile/index.md86
-rw-r--r--doc/user/profile/notifications.md12
-rw-r--r--doc/user/profile/personal_access_tokens.md5
-rw-r--r--doc/user/profile/preferences.md6
-rw-r--r--doc/user/profile/saved_replies.md61
-rw-r--r--doc/user/project/badges.md8
-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/cluster_access.md2
-rw-r--r--doc/user/project/clusters/deploy_to_cluster.md2
-rw-r--r--doc/user/project/clusters/gitlab_managed_clusters.md2
-rw-r--r--doc/user/project/clusters/index.md2
-rw-r--r--doc/user/project/clusters/multiple_kubernetes_clusters.md2
-rw-r--r--doc/user/project/clusters/runbooks/index.md2
-rw-r--r--doc/user/project/code_owners.md218
-rw-r--r--doc/user/project/deploy_boards.md6
-rw-r--r--doc/user/project/deploy_keys/index.md28
-rw-r--r--doc/user/project/deploy_tokens/index.md4
-rw-r--r--doc/user/project/description_templates.md4
-rw-r--r--doc/user/project/file_lock.md4
-rw-r--r--doc/user/project/img/codeowners_in_UI_v15_10.pngbin0 -> 10529 bytes
-rw-r--r--doc/user/project/img/multi_approvals_code_owners_sections_v15_9.pngbin0 -> 18972 bytes
-rw-r--r--doc/user/project/import/bitbucket.md2
-rw-r--r--doc/user/project/import/bitbucket_server.md10
-rw-r--r--doc/user/project/import/gitea.md7
-rw-r--r--doc/user/project/import/github.md103
-rw-r--r--doc/user/project/import/img/bitbucket_import_select_project_v12_3.pngbin31980 -> 0 bytes
-rw-r--r--doc/user/project/import/img/fogbugz_import_finished.pngbin17744 -> 0 bytes
-rw-r--r--doc/user/project/import/img/manifest_status_v13_3.pngbin31313 -> 0 bytes
-rw-r--r--doc/user/project/import/index.md2
-rw-r--r--doc/user/project/index.md9
-rw-r--r--doc/user/project/integrations/apple_app_store.md8
-rw-r--r--doc/user/project/integrations/asana.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/google_play.md49
-rw-r--r--doc/user/project/integrations/hangouts_chat.md6
-rw-r--r--doc/user/project/integrations/harbor.md6
-rw-r--r--doc/user/project/integrations/index.md5
-rw-r--r--doc/user/project/integrations/irker.md4
-rw-r--r--doc/user/project/integrations/mock_ci.md10
-rw-r--r--doc/user/project/integrations/pivotal_tracker.md2
-rw-r--r--doc/user/project/integrations/prometheus.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/cloudwatch.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/haproxy.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/index.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/kubernetes.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md2
-rw-r--r--doc/user/project/integrations/redmine.md3
-rw-r--r--doc/user/project/integrations/servicenow.md2
-rw-r--r--doc/user/project/integrations/slack_slash_commands.md2
-rw-r--r--doc/user/project/integrations/squash_tm.md37
-rw-r--r--doc/user/project/integrations/unify_circuit.md2
-rw-r--r--doc/user/project/integrations/webhooks.md13
-rw-r--r--doc/user/project/issue_board.md22
-rw-r--r--doc/user/project/issues/create_issues.md7
-rw-r--r--doc/user/project/issues/crosslinking_issues.md4
-rw-r--r--doc/user/project/issues/csv_import.md4
-rw-r--r--doc/user/project/issues/design_management.md13
-rw-r--r--doc/user/project/issues/managing_issues.md2
-rw-r--r--doc/user/project/members/index.md4
-rw-r--r--doc/user/project/members/share_project_with_groups.md14
-rw-r--r--doc/user/project/merge_requests/allow_collaboration.md2
-rw-r--r--doc/user/project/merge_requests/cherry_pick_changes.md10
-rw-r--r--doc/user/project/merge_requests/commits.md11
-rw-r--r--doc/user/project/merge_requests/creating_merge_requests.md6
-rw-r--r--doc/user/project/merge_requests/img/remove_source_branch_status.pngbin32586 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/index.md7
-rw-r--r--doc/user/project/merge_requests/methods/index.md1
-rw-r--r--doc/user/project/merge_requests/reviews/img/apply_suggestion_v13_9.pngbin37127 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/reviews/img/make_suggestion_v13_9.pngbin30463 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/reviews/img/suggestion_button_v13_9.pngbin27319 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/reviews/img/suggestions_custom_commit_messages_v14_7.pngbin14774 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/reviews/index.md6
-rw-r--r--doc/user/project/merge_requests/reviews/suggestions.md138
-rw-r--r--doc/user/project/merge_requests/status_checks.md3
-rw-r--r--doc/user/project/milestones/burndown_and_burnup_charts.md20
-rw-r--r--doc/user/project/milestones/index.md5
-rw-r--r--doc/user/project/organize_work_with_projects.md4
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md7
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/index.md2
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md2
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md5
-rw-r--r--doc/user/project/pages/getting_started/pages_ci_cd_template.md2
-rw-r--r--doc/user/project/pages/getting_started/pages_forked_sample_project.md4
-rw-r--r--doc/user/project/pages/getting_started/pages_new_project_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.md2
-rw-r--r--doc/user/project/pages/introduction.md2
-rw-r--r--doc/user/project/pages/public_folder.md4
-rw-r--r--doc/user/project/pages/redirects.md2
-rw-r--r--doc/user/project/protected_branches.md68
-rw-r--r--doc/user/project/protected_tags.md33
-rw-r--r--doc/user/project/quick_actions.md2
-rw-r--r--doc/user/project/releases/index.md6
-rw-r--r--doc/user/project/releases/release_cicd_examples.md4
-rw-r--r--doc/user/project/releases/release_cli.md4
-rw-r--r--doc/user/project/releases/release_fields.md4
-rw-r--r--doc/user/project/remote_development/index.md2
-rw-r--r--doc/user/project/repository/branches/img/branch_filter_search_box_v13_12.pngbin15803 -> 0 bytes
-rw-r--r--doc/user/project/repository/branches/img/compare_branches_v13_12.pngbin46536 -> 0 bytes
-rw-r--r--doc/user/project/repository/branches/img/repository_filter_search_box_v13_12.pngbin12634 -> 0 bytes
-rw-r--r--doc/user/project/repository/branches/img/swap_revisions_after_v13_12.pngbin8949 -> 0 bytes
-rw-r--r--doc/user/project/repository/branches/img/swap_revisions_before_v13_12.pngbin8935 -> 0 bytes
-rw-r--r--doc/user/project/repository/branches/img/view_branch_protections_v15_10.pngbin0 -> 5103 bytes
-rw-r--r--doc/user/project/repository/branches/index.md210
-rw-r--r--doc/user/project/repository/file_finder.md2
-rw-r--r--doc/user/project/repository/forking_workflow.md10
-rw-r--r--doc/user/project/repository/git_blame.md2
-rw-r--r--doc/user/project/repository/git_history.md2
-rw-r--r--doc/user/project/repository/gpg_signed_commits/index.md2
-rw-r--r--doc/user/project/repository/index.md6
-rw-r--r--doc/user/project/repository/mirror/push.md6
-rw-r--r--doc/user/project/repository/tags/img/tag-display_v15_9.pngbin0 -> 7320 bytes
-rw-r--r--doc/user/project/repository/tags/img/tags_commits_view_v15_10.pngbin0 -> 7054 bytes
-rw-r--r--doc/user/project/repository/tags/index.md108
-rw-r--r--doc/user/project/repository/web_editor.md30
-rw-r--r--doc/user/project/requirements/index.md10
-rw-r--r--doc/user/project/service_desk.md77
-rw-r--r--doc/user/project/settings/import_export.md9
-rw-r--r--doc/user/project/settings/import_export_troubleshooting.md62
-rw-r--r--doc/user/project/settings/index.md6
-rw-r--r--doc/user/project/settings/project_access_tokens.md15
-rw-r--r--doc/user/project/web_ide/index.md4
-rw-r--r--doc/user/project/web_ide_beta/index.md33
-rw-r--r--doc/user/project/wiki/group.md8
-rw-r--r--doc/user/project/working_with_projects.md33
-rw-r--r--doc/user/public_access.md4
-rw-r--r--doc/user/report_abuse.md2
-rw-r--r--doc/user/reserved_names.md4
-rw-r--r--doc/user/search/advanced_search.md64
-rw-r--r--doc/user/search/exact_code_search.md5
-rw-r--r--doc/user/search/global_search/advanced_search_syntax.md11
-rw-r--r--doc/user/search/index.md13
-rw-r--r--doc/user/shortcuts.md2
-rw-r--r--doc/user/snippets.md4
-rw-r--r--doc/user/ssh.md6
-rw-r--r--doc/user/tasks.md20
-rw-r--r--doc/user/todos.md4
-rw-r--r--doc/user/workspace/index.md45
-rw-r--r--glfm_specification/output_example_snapshots/html.yml2
-rw-r--r--jest.config.base.js51
-rw-r--r--lefthook.yml31
-rw-r--r--lib/api/access_requests.rb2
-rw-r--r--lib/api/admin/ci/variables.rb2
-rw-r--r--lib/api/applications.rb2
-rw-r--r--lib/api/ci/helpers/runner.rb8
-rw-r--r--lib/api/ci/pipeline_schedules.rb7
-rw-r--r--lib/api/ci/pipelines.rb4
-rw-r--r--lib/api/ci/runner.rb6
-rw-r--r--lib/api/ci/variables.rb2
-rw-r--r--lib/api/clusters/agent_tokens.rb9
-rw-r--r--lib/api/commits.rb10
-rw-r--r--lib/api/composer_packages.rb2
-rw-r--r--lib/api/concerns/packages/conan_endpoints.rb2
-rw-r--r--lib/api/concerns/packages/debian_package_endpoints.rb42
-rw-r--r--lib/api/concerns/packages/npm_endpoints.rb12
-rw-r--r--lib/api/debian_project_packages.rb4
-rw-r--r--lib/api/draft_notes.rb74
-rw-r--r--lib/api/entities/application_with_secret.rb8
-rw-r--r--lib/api/entities/ci/job_request/response.rb4
-rw-r--r--lib/api/entities/internal/pages/lookup_path.rb8
-rw-r--r--lib/api/entities/note.rb1
-rw-r--r--lib/api/entities/project.rb2
-rw-r--r--lib/api/error_tracking/project_settings.rb40
-rw-r--r--lib/api/files.rb10
-rw-r--r--lib/api/generic_packages.rb4
-rw-r--r--lib/api/group_container_repositories.rb2
-rw-r--r--lib/api/group_variables.rb2
-rw-r--r--lib/api/helpers/integrations_helpers.rb36
-rw-r--r--lib/api/helpers/internal_helpers.rb1
-rw-r--r--lib/api/helpers/packages/conan/api_helpers.rb4
-rw-r--r--lib/api/helpers/packages/dependency_proxy_helpers.rb9
-rw-r--r--lib/api/helpers/packages/npm.rb32
-rw-r--r--lib/api/helpers/packages_helpers.rb1
-rw-r--r--lib/api/internal/base.rb12
-rw-r--r--lib/api/internal/kubernetes.rb45
-rw-r--r--lib/api/internal/pages.rb21
-rw-r--r--lib/api/issues.rb2
-rw-r--r--lib/api/keys.rb2
-rw-r--r--lib/api/lint.rb2
-rw-r--r--lib/api/maven_packages.rb3
-rw-r--r--lib/api/merge_requests.rb4
-rw-r--r--lib/api/metrics/dashboard/annotations.rb2
-rw-r--r--lib/api/milestone_responses.rb45
-rw-r--r--lib/api/npm_project_packages.rb2
-rw-r--r--lib/api/nuget_project_packages.rb2
-rw-r--r--lib/api/personal_access_tokens.rb2
-rw-r--r--lib/api/personal_access_tokens/self_information.rb2
-rw-r--r--lib/api/project_container_repositories.rb10
-rw-r--r--lib/api/projects.rb17
-rw-r--r--lib/api/protected_branches.rb6
-rw-r--r--lib/api/pypi_packages.rb2
-rw-r--r--lib/api/release/links.rb44
-rw-r--r--lib/api/resource_access_tokens.rb2
-rw-r--r--lib/api/rpm_project_packages.rb1
-rw-r--r--lib/api/rubygem_packages.rb2
-rw-r--r--lib/api/search.rb3
-rw-r--r--lib/api/templates.rb2
-rw-r--r--lib/api/terraform/modules/v1/packages.rb4
-rw-r--r--lib/api/terraform/state.rb22
-rw-r--r--lib/api/unleash.rb4
-rw-r--r--lib/api/users.rb68
-rw-r--r--lib/atlassian/jira_connect/serializers/build_entity.rb7
-rw-r--r--lib/backup/gitaly_backup.rb17
-rw-r--r--lib/banzai/filter/inline_observability_filter.rb15
-rw-r--r--lib/banzai/filter/issuable_reference_expansion_filter.rb41
-rw-r--r--lib/banzai/filter/reference_redactor_filter.rb4
-rw-r--r--lib/banzai/filter/references/design_reference_filter.rb2
-rw-r--r--lib/banzai/filter/references/issue_reference_filter.rb2
-rw-r--r--lib/banzai/reference_parser/commit_parser.rb7
-rw-r--r--lib/banzai/reference_parser/commit_range_parser.rb7
-rw-r--r--lib/banzai/reference_parser/issue_parser.rb24
-rw-r--r--lib/banzai/reference_parser/merge_request_parser.rb22
-rw-r--r--lib/banzai/render_context.rb5
-rw-r--r--lib/bulk_imports/clients/http.rb9
-rw-r--r--lib/bulk_imports/error.rb2
-rw-r--r--lib/bulk_imports/features.rb15
-rw-r--r--lib/bulk_imports/groups/stage.rb8
-rw-r--r--lib/bulk_imports/groups/transformers/group_attributes_transformer.rb7
-rw-r--r--lib/bulk_imports/ndjson_pipeline.rb43
-rw-r--r--lib/bulk_imports/projects/pipelines/commit_notes_pipeline.rb15
-rw-r--r--lib/bulk_imports/projects/stage.rb5
-rw-r--r--lib/container_registry/gitlab_api_client.rb48
-rw-r--r--lib/generators/batched_background_migration/USAGE12
-rw-r--r--lib/generators/batched_background_migration/batched_background_migration_generator.rb73
-rw-r--r--lib/generators/batched_background_migration/templates/batched_background_migration_dictionary.template6
-rw-r--r--lib/generators/batched_background_migration/templates/batched_background_migration_job.template22
-rw-r--r--lib/generators/batched_background_migration/templates/batched_background_migration_job_spec.template7
-rw-r--r--lib/generators/batched_background_migration/templates/queue_batched_background_migration.template28
-rw-r--r--lib/generators/batched_background_migration/templates/queue_batched_background_migration_spec.template26
-rw-r--r--lib/generators/gitlab/snowplow_event_definition_generator.rb13
-rw-r--r--lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher.rb8
-rw-r--r--lib/gitlab/analytics/cycle_analytics/records_fetcher.rb8
-rw-r--r--lib/gitlab/analytics/cycle_analytics/request_params.rb100
-rw-r--r--lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb2
-rw-r--r--lib/gitlab/app_logger.rb2
-rw-r--r--lib/gitlab/application_rate_limiter.rb6
-rw-r--r--lib/gitlab/audit/auditor.rb10
-rw-r--r--lib/gitlab/auth/o_auth/user.rb2
-rw-r--r--lib/gitlab/auth/otp/duo_auth.rb13
-rw-r--r--lib/gitlab/auth/otp/strategies/duo_auth/manual_otp.rb46
-rw-r--r--lib/gitlab/auth/user_access_denied_reason.rb3
-rw-r--r--lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens.rb2
-rw-r--r--lib/gitlab/background_migration/backfill_compliance_violations.rb17
-rw-r--r--lib/gitlab/background_migration/backfill_namespace_ldap_settings.rb17
-rw-r--r--lib/gitlab/background_migration/backfill_prepared_at_merge_requests.rb18
-rw-r--r--lib/gitlab/background_migration/backfill_project_wiki_repositories.rb35
-rw-r--r--lib/gitlab/background_migration/batched_migration_job.rb15
-rw-r--r--lib/gitlab/background_migration/create_vulnerability_links.rb14
-rw-r--r--lib/gitlab/background_migration/delete_orphaned_packages_dependencies.rb27
-rw-r--r--lib/gitlab/background_migration/fix_vulnerability_reads_has_issues.rb33
-rw-r--r--lib/gitlab/background_migration/issues_internal_id_scope_updater.rb66
-rw-r--r--lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings.rb81
-rw-r--r--lib/gitlab/background_migration/migrate_links_for_vulnerability_findings.rb79
-rw-r--r--lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings.rb164
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb2
-rw-r--r--lib/gitlab/cache/client.rb68
-rw-r--r--lib/gitlab/cache/metadata.rb11
-rw-r--r--lib/gitlab/changes_list.rb4
-rw-r--r--lib/gitlab/chat/responder.rb18
-rw-r--r--lib/gitlab/checks/base_single_checker.rb2
-rw-r--r--lib/gitlab/checks/changes_access.rb14
-rw-r--r--lib/gitlab/checks/diff_check.rb4
-rw-r--r--lib/gitlab/checks/single_change_access.rb10
-rw-r--r--lib/gitlab/ci/badge/release/latest_release.rb3
-rw-r--r--lib/gitlab/ci/badge/release/template.rb8
-rw-r--r--lib/gitlab/ci/components/header.rb42
-rw-r--r--lib/gitlab/ci/config.rb12
-rw-r--r--lib/gitlab/ci/config/entry/job.rb6
-rw-r--r--lib/gitlab/ci/config/external/context.rb20
-rw-r--r--lib/gitlab/ci/config/external/file/base.rb33
-rw-r--r--lib/gitlab/ci/config/external/file/component.rb2
-rw-r--r--lib/gitlab/ci/config/external/file/project.rb71
-rw-r--r--lib/gitlab/ci/config/external/mapper/verifier.rb63
-rw-r--r--lib/gitlab/ci/config/header/input.rb24
-rw-r--r--lib/gitlab/ci/config/header/root.rb36
-rw-r--r--lib/gitlab/ci/config/header/spec.rb24
-rw-r--r--lib/gitlab/ci/config/yaml.rb44
-rw-r--r--lib/gitlab/ci/config/yaml/result.rb36
-rw-r--r--lib/gitlab/ci/input/arguments/base.rb62
-rw-r--r--lib/gitlab/ci/input/arguments/default.rb44
-rw-r--r--lib/gitlab/ci/input/arguments/options.rb52
-rw-r--r--lib/gitlab/ci/input/arguments/required.rb46
-rw-r--r--lib/gitlab/ci/input/arguments/unknown.rb31
-rw-r--r--lib/gitlab/ci/input/inputs.rb73
-rw-r--r--lib/gitlab/ci/parsers/security/common.rb1
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb3
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/content.rb1
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/process.rb1
-rw-r--r--lib/gitlab/ci/pipeline/duration.rb25
-rw-r--r--lib/gitlab/ci/project_config.rb1
-rw-r--r--lib/gitlab/ci/project_config/auto_devops.rb4
-rw-r--r--lib/gitlab/ci/project_config/external_project.rb4
-rw-r--r--lib/gitlab/ci/project_config/remote.rb4
-rw-r--r--lib/gitlab/ci/project_config/repository.rb4
-rw-r--r--lib/gitlab/ci/project_config/source.rb5
-rw-r--r--lib/gitlab/ci/reports/security/finding.rb4
-rw-r--r--lib/gitlab/ci/reports/security/report.rb5
-rw-r--r--lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb165
-rw-r--r--lib/gitlab/ci/resource_groups/logger.rb13
-rw-r--r--lib/gitlab/ci/runner_releases.rb5
-rw-r--r--lib/gitlab/ci/status/composite.rb28
-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/Dependency-Scanning.gitlab-ci.yml38
-rw-r--r--lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml38
-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/Jobs/SAST-IaC.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml24
-rw-r--r--lib/gitlab/ci/templates/Jobs/Secret-Detection.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Security/API-Discovery.gitlab-ci.yml66
-rw-r--r--lib/gitlab/color_schemes.rb2
-rw-r--r--lib/gitlab/config/entry/validators.rb2
-rw-r--r--lib/gitlab/config/loader/multi_doc_yaml.rb65
-rw-r--r--lib/gitlab/config/loader/yaml.rb4
-rw-r--r--lib/gitlab/content_security_policy/config_loader.rb12
-rw-r--r--lib/gitlab/data_builder/pipeline.rb7
-rw-r--r--lib/gitlab/database/async_constraints.rb15
-rw-r--r--lib/gitlab/database/async_constraints/migration_helpers.rb113
-rw-r--r--lib/gitlab/database/async_constraints/postgres_async_constraint_validation.rb35
-rw-r--r--lib/gitlab/database/async_constraints/validators.rb20
-rw-r--r--lib/gitlab/database/async_constraints/validators/base.rb91
-rw-r--r--lib/gitlab/database/async_constraints/validators/check_constraint.rb19
-rw-r--r--lib/gitlab/database/async_constraints/validators/foreign_key.rb21
-rw-r--r--lib/gitlab/database/async_foreign_keys.rb15
-rw-r--r--lib/gitlab/database/async_foreign_keys/foreign_key_validator.rb94
-rw-r--r--lib/gitlab/database/async_foreign_keys/migration_helpers.rb72
-rw-r--r--lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb21
-rw-r--r--lib/gitlab/database/background_migration/batch_optimizer.rb13
-rw-r--r--lib/gitlab/database/background_migration/batched_job.rb83
-rw-r--r--lib/gitlab/database/background_migration/batched_migration.rb2
-rw-r--r--lib/gitlab/database/background_migration/batched_migration_wrapper.rb13
-rw-r--r--lib/gitlab/database/background_migration/sub_batch_timeout_error.rb17
-rw-r--r--lib/gitlab/database/gitlab_schema.rb15
-rw-r--r--lib/gitlab/database/lock_writes_manager.rb2
-rw-r--r--lib/gitlab/database/migration_helpers.rb89
-rw-r--r--lib/gitlab/database/migration_helpers/convert_to_bigint.rb19
-rw-r--r--lib/gitlab/database/migrations/batched_background_migration_helpers.rb11
-rw-r--r--lib/gitlab/database/migrations/constraints_helpers.rb40
-rw-r--r--lib/gitlab/database/migrations/test_batched_background_runner.rb2
-rw-r--r--lib/gitlab/database/partitioning.rb3
-rw-r--r--lib/gitlab/database/partitioning/ci_sliding_list_strategy.rb40
-rw-r--r--lib/gitlab/database/partitioning/partition_manager.rb2
-rw-r--r--lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers.rb71
-rw-r--r--lib/gitlab/database/postgres_foreign_key.rb8
-rw-r--r--lib/gitlab/database/postgres_partition.rb10
-rw-r--r--lib/gitlab/database/reindexing.rb2
-rw-r--r--lib/gitlab/database/schema_validation/database.rb50
-rw-r--r--lib/gitlab/database/schema_validation/index.rb25
-rw-r--r--lib/gitlab/database/schema_validation/indexes.rb37
-rw-r--r--lib/gitlab/database/schema_validation/runner.rb23
-rw-r--r--lib/gitlab/database/schema_validation/schema_objects/base.rb27
-rw-r--r--lib/gitlab/database/schema_validation/schema_objects/index.rb15
-rw-r--r--lib/gitlab/database/schema_validation/schema_objects/trigger.rb15
-rw-r--r--lib/gitlab/database/schema_validation/structure_sql.rb41
-rw-r--r--lib/gitlab/database/schema_validation/validators/base_validator.rb43
-rw-r--r--lib/gitlab/database/schema_validation/validators/different_definition_indexes.rb22
-rw-r--r--lib/gitlab/database/schema_validation/validators/different_definition_triggers.rb22
-rw-r--r--lib/gitlab/database/schema_validation/validators/extra_indexes.rb19
-rw-r--r--lib/gitlab/database/schema_validation/validators/extra_triggers.rb19
-rw-r--r--lib/gitlab/database/schema_validation/validators/missing_indexes.rb19
-rw-r--r--lib/gitlab/database/schema_validation/validators/missing_triggers.rb19
-rw-r--r--lib/gitlab/database/tables_locker.rb34
-rw-r--r--lib/gitlab/database_importers/work_items/base_type_importer.rb24
-rw-r--r--lib/gitlab/design_management/copy_design_collection_model_attributes.yml3
-rw-r--r--lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512.rb7
-rw-r--r--lib/gitlab/email/html_to_markdown_parser.rb35
-rw-r--r--lib/gitlab/email/receiver.rb2
-rw-r--r--lib/gitlab/etag_caching/router/graphql.rb2
-rw-r--r--lib/gitlab/exception_log_formatter.rb4
-rw-r--r--lib/gitlab/file_finder.rb14
-rw-r--r--lib/gitlab/git.rb2
-rw-r--r--lib/gitlab/git/commit.rb3
-rw-r--r--lib/gitlab/git/diff_collection.rb2
-rw-r--r--lib/gitlab/git/repository.rb22
-rw-r--r--lib/gitlab/git/rugged_impl/tree.rb1
-rw-r--r--lib/gitlab/git/tree.rb4
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb4
-rw-r--r--lib/gitlab/gitaly_client/ref_service.rb2
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb8
-rw-r--r--lib/gitlab/github_import/clients/proxy.rb31
-rw-r--r--lib/gitlab/github_import/clients/search_repos.rb43
-rw-r--r--lib/gitlab/github_import/importer/collaborator_importer.rb66
-rw-r--r--lib/gitlab/github_import/importer/collaborators_importer.rb35
-rw-r--r--lib/gitlab/github_import/importer/events/cross_referenced.rb1
-rw-r--r--lib/gitlab/github_import/importer/label_links_importer.rb2
-rw-r--r--lib/gitlab/github_import/importer/note_attachments_importer.rb24
-rw-r--r--lib/gitlab/github_import/importer/pull_requests/review_request_importer.rb2
-rw-r--r--lib/gitlab/github_import/importer/repository_importer.rb15
-rw-r--r--lib/gitlab/github_import/markdown/attachment.rb16
-rw-r--r--lib/gitlab/github_import/parallel_scheduling.rb35
-rw-r--r--lib/gitlab/github_import/project_relation_type.rb55
-rw-r--r--lib/gitlab/github_import/representation/collaborator.rb42
-rw-r--r--lib/gitlab/github_import/settings.rb4
-rw-r--r--lib/gitlab/gon_helper.rb1
-rw-r--r--lib/gitlab/i18n.rb27
-rw-r--r--lib/gitlab/i18n/pluralization.rb86
-rw-r--r--lib/gitlab/import/errors.rb45
-rw-r--r--lib/gitlab/import/import_failure_service.rb8
-rw-r--r--lib/gitlab/import/metrics.rb27
-rw-r--r--lib/gitlab/import_export/attributes_finder.rb8
-rw-r--r--lib/gitlab/import_export/attributes_permitter.rb2
-rw-r--r--lib/gitlab/import_export/base/relation_object_saver.rb31
-rw-r--r--lib/gitlab/import_export/command_line_util.rb14
-rw-r--r--lib/gitlab/import_export/config.rb1
-rw-r--r--lib/gitlab/import_export/file_importer.rb17
-rw-r--r--lib/gitlab/import_export/group/relation_tree_restorer.rb42
-rw-r--r--lib/gitlab/import_export/project/import_export.yml54
-rw-r--r--lib/gitlab/import_export/project/object_builder.rb1
-rw-r--r--lib/gitlab/import_export/project/relation_factory.rb19
-rw-r--r--lib/gitlab/instrumentation/redis_base.rb17
-rw-r--r--lib/gitlab/instrumentation/redis_interceptor.rb8
-rw-r--r--lib/gitlab/instrumentation/zoekt.rb49
-rw-r--r--lib/gitlab/instrumentation_helper.rb12
-rw-r--r--lib/gitlab/issuable/clone/copy_resource_events_service.rb4
-rw-r--r--lib/gitlab/issues/rebalancing/state.rb4
-rw-r--r--lib/gitlab/jira_import/issues_importer.rb4
-rw-r--r--lib/gitlab/jira_import/metadata_collector.rb2
-rw-r--r--lib/gitlab/json_cache.rb2
-rw-r--r--lib/gitlab/kas/user_access.rb73
-rw-r--r--lib/gitlab/language_detection.rb4
-rw-r--r--lib/gitlab/legacy_github_import/client.rb1
-rw-r--r--lib/gitlab/legacy_github_import/importer.rb47
-rw-r--r--lib/gitlab/loggable.rb11
-rw-r--r--lib/gitlab/metrics/requests_rack_middleware.rb2
-rw-r--r--lib/gitlab/metrics/subscribers/rack_attack.rb5
-rw-r--r--lib/gitlab/metrics/subscribers/rails_cache.rb16
-rw-r--r--lib/gitlab/multi_collection_paginator.rb2
-rw-r--r--lib/gitlab/nav/top_nav_menu_item.rb8
-rw-r--r--lib/gitlab/no_cache_headers.rb1
-rw-r--r--lib/gitlab/observability.rb132
-rw-r--r--lib/gitlab/optimistic_locking.rb5
-rw-r--r--lib/gitlab/pages/random_domain.rb51
-rw-r--r--lib/gitlab/pages/virtual_host_finder.rb72
-rw-r--r--lib/gitlab/patch/node_loader.rb40
-rw-r--r--lib/gitlab/private_commit_email.rb2
-rw-r--r--lib/gitlab/prometheus/queries/knative_invocation_query.rb42
-rw-r--r--lib/gitlab/rack_attack.rb2
-rw-r--r--lib/gitlab/rack_attack/instrumented_cache_store.rb33
-rw-r--r--lib/gitlab/rack_attack/store.rb57
-rw-r--r--lib/gitlab/redis/cache.rb13
-rw-r--r--lib/gitlab/redis/multi_store.rb103
-rw-r--r--lib/gitlab/redis/rate_limiting.rb9
-rw-r--r--lib/gitlab/redis/repository_cache.rb8
-rw-r--r--lib/gitlab/regex.rb13
-rw-r--r--lib/gitlab/search_results.rb8
-rw-r--r--lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb12
-rw-r--r--lib/gitlab/serializer/ci/variables.rb2
-rw-r--r--lib/gitlab/serverless/service.rb102
-rw-r--r--lib/gitlab/slash_commands/incident_management/incident_new.rb4
-rw-r--r--lib/gitlab/task_helpers.rb2
-rw-r--r--lib/gitlab/url_blocker.rb81
-rw-r--r--lib/gitlab/usage/metrics/aggregates/aggregate.rb7
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric.rb5
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric.rb15
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric.rb46
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric.rb15
-rw-r--r--lib/gitlab/usage_data.rb45
-rw-r--r--lib/gitlab/usage_data_counters/container_registry_event_counter.rb10
-rw-r--r--lib/gitlab/usage_data_counters/editor_unique_counter.rb22
-rw-r--r--lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter.rb4
-rw-r--r--lib/gitlab/usage_data_counters/hll_redis_counter.rb73
-rw-r--r--lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb1
-rw-r--r--lib/gitlab/usage_data_counters/known_events/analytics.yml26
-rw-r--r--lib/gitlab/usage_data_counters/known_events/ci_templates.yml302
-rw-r--r--lib/gitlab/usage_data_counters/known_events/ci_users.yml6
-rw-r--r--lib/gitlab/usage_data_counters/known_events/code_review_events.yml224
-rw-r--r--lib/gitlab/usage_data_counters/known_events/common.yml146
-rw-r--r--lib/gitlab/usage_data_counters/known_events/container_registry_events.yml11
-rw-r--r--lib/gitlab/usage_data_counters/known_events/ecosystem.yml22
-rw-r--r--lib/gitlab/usage_data_counters/known_events/error_tracking.yml4
-rw-r--r--lib/gitlab/usage_data_counters/known_events/importer_events.yml10
-rw-r--r--lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml2
-rw-r--r--lib/gitlab/usage_data_counters/known_events/package_events.yml44
-rw-r--r--lib/gitlab/usage_data_counters/known_events/quickactions.yml126
-rw-r--r--lib/gitlab/usage_data_counters/known_events/work_items.yml21
-rw-r--r--lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb4
-rw-r--r--lib/gitlab/usage_data_counters/track_unique_events.rb81
-rw-r--r--lib/gitlab/usage_data_counters/work_item_activity_unique_counter.rb2
-rw-r--r--lib/gitlab/usage_data_non_sql_metrics.rb7
-rw-r--r--lib/gitlab/usage_data_queries.rb7
-rw-r--r--lib/gitlab/utils/error_message.rb13
-rw-r--r--lib/gitlab/utils/override.rb4
-rw-r--r--lib/gitlab/utils/uniquify.rb45
-rw-r--r--lib/gitlab/utils/usage_data.rb27
-rw-r--r--lib/gitlab/utils/username_and_email_generator.rb42
-rw-r--r--lib/gitlab/verify/batch_verifier.rb2
-rw-r--r--lib/object_storage/config.rb24
-rw-r--r--lib/safe_zip/extract.rb21
-rw-r--r--lib/sidebars/concerns/render_if_logged_in.rb11
-rw-r--r--lib/sidebars/concerns/super_sidebar_panel.rb58
-rw-r--r--lib/sidebars/context.rb5
-rw-r--r--lib/sidebars/explore/menus/groups_menu.rb34
-rw-r--r--lib/sidebars/explore/menus/projects_menu.rb34
-rw-r--r--lib/sidebars/explore/menus/snippets_menu.rb34
-rw-r--r--lib/sidebars/explore/menus/topics_menu.rb34
-rw-r--r--lib/sidebars/explore/panel.rb39
-rw-r--r--lib/sidebars/groups/menus/ci_cd_menu.rb5
-rw-r--r--lib/sidebars/groups/menus/group_information_menu.rb10
-rw-r--r--lib/sidebars/groups/menus/invite_team_members_menu.rb46
-rw-r--r--lib/sidebars/groups/menus/issues_menu.rb21
-rw-r--r--lib/sidebars/groups/menus/kubernetes_menu.rb8
-rw-r--r--lib/sidebars/groups/menus/merge_requests_menu.rb11
-rw-r--r--lib/sidebars/groups/menus/observability_menu.rb14
-rw-r--r--lib/sidebars/groups/menus/packages_registries_menu.rb10
-rw-r--r--lib/sidebars/groups/menus/scope_menu.rb12
-rw-r--r--lib/sidebars/groups/menus/settings_menu.rb5
-rw-r--r--lib/sidebars/groups/panel.rb10
-rw-r--r--lib/sidebars/groups/super_sidebar_menus/operations_menu.rb19
-rw-r--r--lib/sidebars/groups/super_sidebar_menus/plan_menu.rb19
-rw-r--r--lib/sidebars/groups/super_sidebar_panel.rb43
-rw-r--r--lib/sidebars/menu.rb45
-rw-r--r--lib/sidebars/menu_item.rb25
-rw-r--r--lib/sidebars/panel.rb11
-rw-r--r--lib/sidebars/projects/menus/analytics_menu.rb5
-rw-r--r--lib/sidebars/projects/menus/ci_cd_menu.rb5
-rw-r--r--lib/sidebars/projects/menus/deployments_menu.rb9
-rw-r--r--lib/sidebars/projects/menus/infrastructure_menu.rb36
-rw-r--r--lib/sidebars/projects/menus/invite_team_members_menu.rb47
-rw-r--r--lib/sidebars/projects/menus/issues_menu.rb16
-rw-r--r--lib/sidebars/projects/menus/merge_requests_menu.rb11
-rw-r--r--lib/sidebars/projects/menus/monitor_menu.rb20
-rw-r--r--lib/sidebars/projects/menus/packages_registries_menu.rb9
-rw-r--r--lib/sidebars/projects/menus/project_information_menu.rb10
-rw-r--r--lib/sidebars/projects/menus/repository_menu.rb9
-rw-r--r--lib/sidebars/projects/menus/scope_menu.rb10
-rw-r--r--lib/sidebars/projects/menus/security_compliance_menu.rb9
-rw-r--r--lib/sidebars/projects/menus/settings_menu.rb5
-rw-r--r--lib/sidebars/projects/menus/snippets_menu.rb9
-rw-r--r--lib/sidebars/projects/menus/wiki_menu.rb8
-rw-r--r--lib/sidebars/projects/panel.rb8
-rw-r--r--lib/sidebars/projects/super_sidebar_menus/operations_menu.rb19
-rw-r--r--lib/sidebars/projects/super_sidebar_menus/plan_menu.rb19
-rw-r--r--lib/sidebars/projects/super_sidebar_panel.rb43
-rw-r--r--lib/sidebars/static_menu.rb13
-rw-r--r--lib/sidebars/uncategorized_menu.rb19
-rw-r--r--lib/sidebars/user_profile/base_menu.rb12
-rw-r--r--lib/sidebars/user_profile/menus/activity_menu.rb24
-rw-r--r--lib/sidebars/user_profile/menus/contributed_projects_menu.rb24
-rw-r--r--lib/sidebars/user_profile/menus/followers_menu.rb38
-rw-r--r--lib/sidebars/user_profile/menus/following_menu.rb38
-rw-r--r--lib/sidebars/user_profile/menus/groups_menu.rb24
-rw-r--r--lib/sidebars/user_profile/menus/overview_menu.rb24
-rw-r--r--lib/sidebars/user_profile/menus/personal_projects_menu.rb24
-rw-r--r--lib/sidebars/user_profile/menus/snippets_menu.rb24
-rw-r--r--lib/sidebars/user_profile/menus/starred_projects_menu.rb24
-rw-r--r--lib/sidebars/user_profile/panel.rb52
-rw-r--r--lib/sidebars/user_settings/menus/access_tokens_menu.rb39
-rw-r--r--lib/sidebars/user_settings/menus/account_menu.rb36
-rw-r--r--lib/sidebars/user_settings/menus/active_sessions_menu.rb31
-rw-r--r--lib/sidebars/user_settings/menus/applications_menu.rb31
-rw-r--r--lib/sidebars/user_settings/menus/authentication_log_menu.rb31
-rw-r--r--lib/sidebars/user_settings/menus/chat_menu.rb31
-rw-r--r--lib/sidebars/user_settings/menus/emails_menu.rb36
-rw-r--r--lib/sidebars/user_settings/menus/gpg_keys_menu.rb31
-rw-r--r--lib/sidebars/user_settings/menus/notifications_menu.rb31
-rw-r--r--lib/sidebars/user_settings/menus/password_menu.rb39
-rw-r--r--lib/sidebars/user_settings/menus/preferences_menu.rb31
-rw-r--r--lib/sidebars/user_settings/menus/profile_menu.rb31
-rw-r--r--lib/sidebars/user_settings/menus/saved_replies_menu.rb42
-rw-r--r--lib/sidebars/user_settings/menus/ssh_keys_menu.rb36
-rw-r--r--lib/sidebars/user_settings/panel.rb51
-rw-r--r--lib/sidebars/your_work/panel.rb9
-rw-r--r--lib/support/nginx/gitlab-pages-ssl11
-rw-r--r--lib/support/nginx/gitlab-ssl11
-rw-r--r--lib/support/nginx/registry-ssl11
-rw-r--r--lib/tasks/contracts/merge_requests.rake2
-rw-r--r--lib/tasks/contracts/pipeline_schedules.rake2
-rw-r--r--lib/tasks/contracts/pipelines.rake2
-rw-r--r--lib/tasks/gitlab/assets.rake4
-rw-r--r--lib/tasks/gitlab/db.rake54
-rw-r--r--lib/tasks/gitlab/db/decomposition/connection_status.rake37
-rw-r--r--lib/tasks/gitlab/docs/redirect.rake7
-rw-r--r--lib/tasks/gitlab/graphql.rake10
-rw-r--r--lib/tasks/gitlab/import_export/import.rake10
-rw-r--r--lib/tasks/gitlab/lfs/migrate.rake4
-rw-r--r--lib/tasks/gitlab/metrics_exporter.rake5
-rw-r--r--lib/tasks/gitlab/openapi.rake4
-rw-r--r--lib/tasks/gitlab/packages/events.rake6
-rw-r--r--lib/tasks/gitlab/packages/migrate.rake4
-rw-r--r--lib/tasks/gitlab/pages.rake4
-rw-r--r--lib/tasks/gitlab/refresh_project_statistics_build_artifacts_size.rake6
-rw-r--r--lib/tasks/gitlab/seed/runner_fleet.rake10
-rw-r--r--lib/tasks/gitlab/terraform/migrate.rake4
-rw-r--r--lib/tasks/gitlab/tw/codeowners.rake46
-rw-r--r--lib/tasks/gitlab/usage_data.rake2
-rw-r--r--lib/tasks/gitlab/x509/update.rake4
-rw-r--r--lib/tasks/import.rake6
-rw-r--r--locale/am_ET/gitlab.po2021
-rw-r--r--locale/ar_SA/gitlab.po2065
-rw-r--r--locale/as_IN/gitlab.po2021
-rw-r--r--locale/az_AZ/gitlab.po2021
-rw-r--r--locale/ba_RU/gitlab.po2010
-rw-r--r--locale/bg/gitlab.po2023
-rw-r--r--locale/bn_BD/gitlab.po2021
-rw-r--r--locale/bn_IN/gitlab.po2021
-rw-r--r--locale/br_FR/gitlab.po2054
-rw-r--r--locale/bs_BA/gitlab.po2032
-rw-r--r--locale/ca_ES/gitlab.po2021
-rw-r--r--locale/cs_CZ/gitlab.po2043
-rw-r--r--locale/cy_GB/gitlab.po2065
-rw-r--r--locale/da_DK/gitlab.po2065
-rw-r--r--locale/de/gitlab.po2039
-rw-r--r--locale/el_GR/gitlab.po2021
-rw-r--r--locale/en_GB/gitlab.po2029
-rw-r--r--locale/eo/gitlab.po2023
-rw-r--r--locale/es/gitlab.po2059
-rw-r--r--locale/et_EE/gitlab.po2021
-rw-r--r--locale/fa_IR/gitlab.po2021
-rw-r--r--locale/fi_FI/gitlab.po2021
-rw-r--r--locale/fil_PH/gitlab.po2021
-rw-r--r--locale/fr/gitlab.po2293
-rw-r--r--locale/gitlab.pot2026
-rw-r--r--locale/gl_ES/gitlab.po2021
-rw-r--r--locale/he_IL/gitlab.po2043
-rw-r--r--locale/hi_IN/gitlab.po2021
-rw-r--r--locale/hr_HR/gitlab.po2032
-rw-r--r--locale/hu_HU/gitlab.po2021
-rw-r--r--locale/hy_AM/gitlab.po2021
-rw-r--r--locale/id_ID/gitlab.po2010
-rw-r--r--locale/ig_NG/gitlab.po2010
-rw-r--r--locale/is_IS/gitlab.po2021
-rw-r--r--locale/it/gitlab.po2023
-rw-r--r--locale/ja/gitlab.po2272
-rw-r--r--locale/ka_GE/gitlab.po2021
-rw-r--r--locale/kab/gitlab.po2021
-rw-r--r--locale/ko/gitlab.po2030
-rw-r--r--locale/ku_TR/gitlab.po2021
-rw-r--r--locale/ky_KG/gitlab.po2021
-rw-r--r--locale/lt_LT/gitlab.po2043
-rw-r--r--locale/mk_MK/gitlab.po2021
-rw-r--r--locale/ml_IN/gitlab.po2021
-rw-r--r--locale/mn_MN/gitlab.po2021
-rw-r--r--locale/ms_MY/gitlab.po2010
-rw-r--r--locale/nb_NO/gitlab.po2047
-rw-r--r--locale/nl_NL/gitlab.po2021
-rw-r--r--locale/or_IN/gitlab.po2021
-rw-r--r--locale/pa_IN/gitlab.po2021
-rw-r--r--locale/pa_PK/gitlab.po2021
-rw-r--r--locale/pl_PL/gitlab.po2043
-rw-r--r--locale/pt_BR/gitlab.po2281
-rw-r--r--locale/pt_PT/gitlab.po2023
-rw-r--r--locale/ro_RO/gitlab.po2134
-rw-r--r--locale/ru/gitlab.po2069
-rw-r--r--locale/si_LK/gitlab.po2035
-rw-r--r--locale/sk_SK/gitlab.po2043
-rw-r--r--locale/sl_SI/gitlab.po2043
-rw-r--r--locale/sq_AL/gitlab.po2021
-rw-r--r--locale/sr_CS/gitlab.po2032
-rw-r--r--locale/sr_SP/gitlab.po2032
-rw-r--r--locale/sv_SE/gitlab.po2021
-rw-r--r--locale/sw_KE/gitlab.po2021
-rw-r--r--locale/ta_IN/gitlab.po2021
-rw-r--r--locale/th_TH/gitlab.po2010
-rw-r--r--locale/tr_TR/gitlab.po2035
-rw-r--r--locale/uk/gitlab.po2133
-rw-r--r--locale/ur_PK/gitlab.po2021
-rw-r--r--locale/uz_UZ/gitlab.po2021
-rw-r--r--locale/vi_VN/gitlab.po2010
-rw-r--r--locale/zh_CN/gitlab.po2414
-rw-r--r--locale/zh_HK/gitlab.po2012
-rw-r--r--locale/zh_TW/gitlab.po2424
-rw-r--r--package.json122
-rw-r--r--patches/@vue+compiler-sfc+3.2.47.patch28
-rw-r--r--patches/@vue+vue3-jest+29.2.3.patch22
-rw-r--r--patches/vue-loader-vue3+17.0.1.patch78
-rw-r--r--public/500.html2
-rw-r--r--public/502.html2
-rw-r--r--public/503.html2
-rw-r--r--qa/Gemfile8
-rw-r--r--qa/Gemfile.lock35
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quotas.rb3
-rw-r--r--qa/qa.rb3
-rw-r--r--qa/qa/fixtures/kubernetes_agent/agentk-manifest.yaml.erb111
-rw-r--r--qa/qa/fixtures/mocks/import/github.yml74
-rw-r--r--qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/gitlab_ci.yaml.erb8
-rw-r--r--qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/settings.xml.erb23
-rw-r--r--qa/qa/flow/login.rb4
-rw-r--r--qa/qa/flow/pipeline.rb8
-rw-r--r--qa/qa/flow/saml.rb2
-rw-r--r--qa/qa/page/component/dropdown.rb18
-rw-r--r--qa/qa/page/component/groups_filter.rb12
-rw-r--r--qa/qa/page/group/sub_menus/common.rb2
-rw-r--r--qa/qa/page/main/login.rb1
-rw-r--r--qa/qa/page/main/menu.rb60
-rw-r--r--qa/qa/page/merge_request/new.rb2
-rw-r--r--qa/qa/page/merge_request/show.rb26
-rw-r--r--qa/qa/page/profile/menu.rb24
-rw-r--r--qa/qa/page/project/job/show.rb8
-rw-r--r--qa/qa/page/project/monitor/alerts/index.rb12
-rw-r--r--qa/qa/page/project/monitor/alerts/show.rb25
-rw-r--r--qa/qa/page/project/monitor/incidents/index.rb12
-rw-r--r--qa/qa/page/project/pipeline/show.rb11
-rw-r--r--qa/qa/page/project/settings/alerts.rb5
-rw-r--r--qa/qa/page/project/show.rb2
-rw-r--r--qa/qa/page/project/sub_menus/common.rb2
-rw-r--r--qa/qa/page/project/sub_menus/monitor.rb16
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb2
-rw-r--r--qa/qa/page/user/show.rb6
-rw-r--r--qa/qa/resource/api_fabricator.rb120
-rw-r--r--qa/qa/resource/base.rb35
-rw-r--r--qa/qa/resource/ci_cd_settings.rb47
-rw-r--r--qa/qa/resource/integrations/web_hook/smockerable.rb41
-rw-r--r--qa/qa/resource/project_web_hook.rb44
-rw-r--r--qa/qa/resource/runner_base.rb4
-rw-r--r--qa/qa/resource/snippet.rb4
-rw-r--r--qa/qa/resource/web_hook_base.rb46
-rw-r--r--qa/qa/runtime/allure_report.rb19
-rw-r--r--qa/qa/runtime/browser.rb1
-rw-r--r--qa/qa/runtime/env.rb18
-rw-r--r--qa/qa/service/cluster_provider/gcloud.rb10
-rw-r--r--qa/qa/service/docker_run/gitlab_runner.rb2
-rw-r--r--qa/qa/service/kubernetes_cluster.rb14
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb7
-rw-r--r--qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb129
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb10
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb4
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb6
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb31
-rw-r--r--qa/qa/specs/features/api/3_create/repository/files_spec.rb1
-rw-r--r--qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb2
-rw-r--r--qa/qa/specs/features/api/4_verify/file_variable_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb13
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb84
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb10
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb448
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb170
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb154
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb105
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb21
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb48
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb49
-rw-r--r--qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb1
-rw-r--r--qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb1
-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.rb73
-rw-r--r--qa/qa/specs/helpers/context_selector.rb6
-rw-r--r--qa/qa/support/json_formatter.rb8
-rw-r--r--qa/qa/support/loglinking.rb22
-rw-r--r--qa/qa/support/matchers/have_matcher.rb3
-rw-r--r--qa/qa/tools/test_resource_data_processor.rb2
-rw-r--r--qa/qa/vendor/smocker/event_payload.rb61
-rw-r--r--qa/qa/vendor/smocker/history_response.rb7
-rw-r--r--qa/qa/vendor/smocker/smocker_api.rb8
-rw-r--r--qa/spec/fixtures/ff/async_commit_diff_files.yml8
-rw-r--r--qa/spec/fixtures/ff/bulk_import_projects.yml8
-rw-r--r--qa/spec/resource/api_fabricator_spec.rb2
-rw-r--r--qa/spec/resource/project_web_hook_spec.rb70
-rw-r--r--qa/spec/runtime/env_spec.rb16
-rw-r--r--qa/spec/specs/helpers/context_selector_spec.rb144
-rw-r--r--qa/spec/specs/helpers/feature_flag_spec.rb64
-rw-r--r--qa/spec/tools/ci/ff_changes_spec.rb8
-rw-r--r--qa/spec/vendor/smocker_api_spec.rb18
-rw-r--r--rubocop/cop/background_migration/missing_dictionary_file.rb59
-rw-r--r--rubocop/cop/gitlab/feature_available_usage.rb2
-rw-r--r--rubocop/cop/gitlab/json.rb6
-rw-r--r--rubocop/cop/gitlab/mark_used_feature_flags.rb24
-rw-r--r--rubocop/cop/graphql/id_type.rb2
-rw-r--r--rubocop/cop/migration/add_reference.rb2
-rw-r--r--rubocop/cop/rspec/factory_bot/inline_association.rb2
-rw-r--r--rubocop/rubocop-ruby30.yml4
-rw-r--r--rubocop/rubocop-ruby31.yml10
-rw-r--r--scripts/api/base.rb28
-rwxr-xr-xscripts/api/cancel_pipeline.rb14
-rw-r--r--scripts/api/commit_merge_requests.rb19
-rw-r--r--scripts/api/create_issue.rb24
-rw-r--r--scripts/api/create_issue_discussion.rb24
-rw-r--r--scripts/api/find_issues.rb24
-rwxr-xr-xscripts/api/get_job_id.rb19
-rw-r--r--scripts/api/pipeline_failed_jobs.rb21
-rw-r--r--scripts/api/update_issue.rb29
-rw-r--r--scripts/database/schema_validator.rb34
-rwxr-xr-xscripts/db_tasks3
-rwxr-xr-xscripts/decomposition/generate-loose-foreign-key11
-rw-r--r--scripts/frontend/startup_css/constants.js3
-rwxr-xr-xscripts/generate-e2e-pipeline3
-rwxr-xr-xscripts/generate-rspec-foss-impact-pipeline66
-rwxr-xr-xscripts/generate_rspec_pipeline.rb176
-rw-r--r--scripts/gitlab_component_helpers.sh31
-rwxr-xr-xscripts/lint-docs-blueprints.rb4
-rwxr-xr-xscripts/pipeline/create_test_failure_issues.rb224
-rwxr-xr-xscripts/pipeline_test_report_builder.rb10
-rw-r--r--scripts/prepare_build.sh6
-rwxr-xr-xscripts/review_apps/automated_cleanup.rb14
-rwxr-xr-xscripts/setup-test-env59
-rwxr-xr-xscripts/trigger-build.rb1
-rw-r--r--scripts/utils.sh14
-rwxr-xr-xscripts/validate_schema_changes7
-rw-r--r--spec/commands/sidekiq_cluster/cli_spec.rb5
-rw-r--r--spec/config/inject_enterprise_edition_module_spec.rb2
-rw-r--r--spec/config/object_store_settings_spec.rb2
-rw-r--r--spec/config/settings_spec.rb16
-rw-r--r--spec/config/smime_signature_settings_spec.rb2
-rw-r--r--spec/contracts/provider/helpers/contract_source_helper.rb5
-rw-r--r--spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb8
-rw-r--r--spec/contracts/publish-contracts.sh3
-rw-r--r--spec/controllers/admin/application_settings_controller_spec.rb2
-rw-r--r--spec/controllers/admin/applications_controller_spec.rb100
-rw-r--r--spec/controllers/admin/cohorts_controller_spec.rb1
-rw-r--r--spec/controllers/admin/dev_ops_report_controller_spec.rb1
-rw-r--r--spec/controllers/admin/integrations_controller_spec.rb6
-rw-r--r--spec/controllers/admin/runners_controller_spec.rb47
-rw-r--r--spec/controllers/admin/sessions_controller_spec.rb25
-rw-r--r--spec/controllers/admin/spam_logs_controller_spec.rb10
-rw-r--r--spec/controllers/admin/usage_trends_controller_spec.rb1
-rw-r--r--spec/controllers/admin/users_controller_spec.rb23
-rw-r--r--spec/controllers/application_controller_spec.rb23
-rw-r--r--spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb3
-rw-r--r--spec/controllers/concerns/confirm_email_warning_spec.rb2
-rw-r--r--spec/controllers/concerns/content_security_policy_patch_spec.rb2
-rw-r--r--spec/controllers/concerns/continue_params_spec.rb5
-rw-r--r--spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb11
-rw-r--r--spec/controllers/concerns/kas_cookie_spec.rb55
-rw-r--r--spec/controllers/concerns/product_analytics_tracking_spec.rb24
-rw-r--r--spec/controllers/concerns/renders_commits_spec.rb2
-rw-r--r--spec/controllers/concerns/send_file_upload_spec.rb2
-rw-r--r--spec/controllers/concerns/sorting_preference_spec.rb41
-rw-r--r--spec/controllers/confirmations_controller_spec.rb74
-rw-r--r--spec/controllers/dashboard/projects_controller_spec.rb46
-rw-r--r--spec/controllers/every_controller_spec.rb3
-rw-r--r--spec/controllers/explore/groups_controller_spec.rb4
-rw-r--r--spec/controllers/graphql_controller_spec.rb66
-rw-r--r--spec/controllers/groups/children_controller_spec.rb12
-rw-r--r--spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb2
-rw-r--r--spec/controllers/groups/group_members_controller_spec.rb41
-rw-r--r--spec/controllers/groups/milestones_controller_spec.rb47
-rw-r--r--spec/controllers/groups/settings/applications_controller_spec.rb135
-rw-r--r--spec/controllers/groups/variables_controller_spec.rb10
-rw-r--r--spec/controllers/help_controller_spec.rb18
-rw-r--r--spec/controllers/import/bitbucket_controller_spec.rb20
-rw-r--r--spec/controllers/import/bulk_imports_controller_spec.rb18
-rw-r--r--spec/controllers/import/fogbugz_controller_spec.rb3
-rw-r--r--spec/controllers/import/github_controller_spec.rb63
-rw-r--r--spec/controllers/oauth/applications_controller_spec.rb54
-rw-r--r--spec/controllers/oauth/authorizations_controller_spec.rb3
-rw-r--r--spec/controllers/omniauth_callbacks_controller_spec.rb75
-rw-r--r--spec/controllers/passwords_controller_spec.rb3
-rw-r--r--spec/controllers/profiles/two_factor_auths_controller_spec.rb2
-rw-r--r--spec/controllers/profiles_controller_spec.rb32
-rw-r--r--spec/controllers/projects/artifacts_controller_spec.rb34
-rw-r--r--spec/controllers/projects/badges_controller_spec.rb12
-rw-r--r--spec/controllers/projects/blame_controller_spec.rb10
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb54
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb294
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb11
-rw-r--r--spec/controllers/projects/commit_controller_spec.rb208
-rw-r--r--spec/controllers/projects/commits_controller_spec.rb78
-rw-r--r--spec/controllers/projects/cycle_analytics_controller_spec.rb7
-rw-r--r--spec/controllers/projects/deploy_keys_controller_spec.rb10
-rw-r--r--spec/controllers/projects/deployments_controller_spec.rb4
-rw-r--r--spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb11
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb131
-rw-r--r--spec/controllers/projects/feature_flags_controller_spec.rb11
-rw-r--r--spec/controllers/projects/find_file_controller_spec.rb15
-rw-r--r--spec/controllers/projects/forks_controller_spec.rb7
-rw-r--r--spec/controllers/projects/grafana_api_controller_spec.rb16
-rw-r--r--spec/controllers/projects/graphs_controller_spec.rb1
-rw-r--r--spec/controllers/projects/group_links_controller_spec.rb2
-rw-r--r--spec/controllers/projects/hooks_controller_spec.rb12
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb53
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb21
-rw-r--r--spec/controllers/projects/mattermosts_controller_spec.rb20
-rw-r--r--spec/controllers/projects/merge_requests/conflicts_controller_spec.rb80
-rw-r--r--spec/controllers/projects/merge_requests/creations_controller_spec.rb43
-rw-r--r--spec/controllers/projects/merge_requests/diffs_controller_spec.rb19
-rw-r--r--spec/controllers/projects/merge_requests/drafts_controller_spec.rb16
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb117
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb57
-rw-r--r--spec/controllers/projects/pages_controller_spec.rb121
-rw-r--r--spec/controllers/projects/pipeline_schedules_controller_spec.rb6
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb103
-rw-r--r--spec/controllers/projects/prometheus/alerts_controller_spec.rb5
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb10
-rw-r--r--spec/controllers/projects/refs_controller_spec.rb11
-rw-r--r--spec/controllers/projects/registry/repositories_controller_spec.rb16
-rw-r--r--spec/controllers/projects/registry/tags_controller_spec.rb29
-rw-r--r--spec/controllers/projects/settings/ci_cd_controller_spec.rb15
-rw-r--r--spec/controllers/projects/settings/merge_requests_controller_spec.rb11
-rw-r--r--spec/controllers/projects/snippets/blobs_controller_spec.rb17
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb11
-rw-r--r--spec/controllers/projects/tree_controller_spec.rb47
-rw-r--r--spec/controllers/projects_controller_spec.rb142
-rw-r--r--spec/controllers/registrations/welcome_controller_spec.rb28
-rw-r--r--spec/controllers/registrations_controller_spec.rb219
-rw-r--r--spec/controllers/repositories/git_http_controller_spec.rb67
-rw-r--r--spec/controllers/search_controller_spec.rb13
-rw-r--r--spec/controllers/sessions_controller_spec.rb48
-rw-r--r--spec/controllers/snippets/blobs_controller_spec.rb8
-rw-r--r--spec/db/schema_spec.rb32
-rw-r--r--spec/deprecation_warnings.rb21
-rw-r--r--spec/experiments/application_experiment_spec.rb8
-rw-r--r--spec/factories/abuse_reports.rb4
-rw-r--r--spec/factories/achievements/user_achievements.rb14
-rw-r--r--spec/factories/airflow/dags.rb8
-rw-r--r--spec/factories/bulk_import/batch_trackers.rb37
-rw-r--r--spec/factories/bulk_import/export_batches.rb23
-rw-r--r--spec/factories/chat_names.rb1
-rw-r--r--spec/factories/ci/builds.rb12
-rw-r--r--spec/factories/ci/catalog/resources.rb7
-rw-r--r--spec/factories/ci/runner_machine_builds.rb8
-rw-r--r--spec/factories/ci/runners.rb6
-rw-r--r--spec/factories/clusters/applications/helm.rb9
-rw-r--r--spec/factories/clusters/clusters.rb3
-rw-r--r--spec/factories/gitlab/database/async_foreign_keys/postgres_async_constraint_validation.rb17
-rw-r--r--spec/factories/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb9
-rw-r--r--spec/factories/integrations.rb21
-rw-r--r--spec/factories/notes.rb5
-rw-r--r--spec/factories/packages/debian/component_file.rb7
-rw-r--r--spec/factories/packages/debian/file_metadatum.rb16
-rw-r--r--spec/factories/packages/package_files.rb29
-rw-r--r--spec/factories/packages/packages.rb1
-rw-r--r--spec/factories/project_error_tracking_settings.rb5
-rw-r--r--spec/factories/project_hooks.rb2
-rw-r--r--spec/factories/projects.rb27
-rw-r--r--spec/factories/serverless/domain.rb11
-rw-r--r--spec/factories/serverless/domain_cluster.rb17
-rw-r--r--spec/factories/service_desk/custom_email_verification.rb8
-rw-r--r--spec/factories/users.rb5
-rw-r--r--spec/factories/users/banned_users.rb7
-rw-r--r--spec/factories/work_items.rb7
-rw-r--r--spec/fast_spec_helper.rb26
-rw-r--r--spec/features/abuse_report_spec.rb19
-rw-r--r--spec/features/action_cable_logging_spec.rb2
-rw-r--r--spec/features/admin/admin_abuse_reports_spec.rb223
-rw-r--r--spec/features/admin/admin_appearance_spec.rb2
-rw-r--r--spec/features/admin/admin_browse_spam_logs_spec.rb2
-rw-r--r--spec/features/admin/admin_deploy_keys_spec.rb2
-rw-r--r--spec/features/admin/admin_health_check_spec.rb6
-rw-r--r--spec/features/admin/admin_mode/login_spec.rb22
-rw-r--r--spec/features/admin/admin_mode/logout_spec.rb2
-rw-r--r--spec/features/admin/admin_mode/workers_spec.rb2
-rw-r--r--spec/features/admin/admin_mode_spec.rb2
-rw-r--r--spec/features/admin/admin_projects_spec.rb25
-rw-r--r--spec/features/admin/admin_runners_spec.rb27
-rw-r--r--spec/features/admin/admin_sees_background_migrations_spec.rb2
-rw-r--r--spec/features/admin/admin_settings_spec.rb18
-rw-r--r--spec/features/admin/admin_system_info_spec.rb2
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb2
-rw-r--r--spec/features/admin_variables_spec.rb16
-rw-r--r--spec/features/boards/boards_spec.rb13
-rw-r--r--spec/features/boards/new_issue_spec.rb50
-rw-r--r--spec/features/breadcrumbs_schema_markup_spec.rb2
-rw-r--r--spec/features/calendar_spec.rb381
-rw-r--r--spec/features/callouts/registration_enabled_spec.rb2
-rw-r--r--spec/features/commit_spec.rb42
-rw-r--r--spec/features/contextual_sidebar_spec.rb69
-rw-r--r--spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb10
-rw-r--r--spec/features/dashboard/groups_list_spec.rb7
-rw-r--r--spec/features/dashboard/projects_spec.rb24
-rw-r--r--spec/features/dashboard/root_explore_spec.rb6
-rw-r--r--spec/features/dashboard/shortcuts_spec.rb2
-rw-r--r--spec/features/dashboard/snippets_spec.rb7
-rw-r--r--spec/features/display_system_header_and_footer_bar_spec.rb2
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb14
-rw-r--r--spec/features/explore/navbar_spec.rb13
-rw-r--r--spec/features/frequently_visited_projects_and_groups_spec.rb2
-rw-r--r--spec/features/group_variables_spec.rb15
-rw-r--r--spec/features/groups/board_spec.rb6
-rw-r--r--spec/features/groups/group_settings_spec.rb11
-rw-r--r--spec/features/groups/import_export/connect_instance_spec.rb2
-rw-r--r--spec/features/groups/members/sort_members_spec.rb2
-rw-r--r--spec/features/groups/new_group_page_spec.rb50
-rw-r--r--spec/features/groups/settings/access_tokens_spec.rb2
-rw-r--r--spec/features/groups/settings/packages_and_registries_spec.rb8
-rw-r--r--spec/features/help_dropdown_spec.rb2
-rw-r--r--spec/features/help_pages_spec.rb2
-rw-r--r--spec/features/incidents/incident_timeline_events_spec.rb3
-rw-r--r--spec/features/incidents/user_views_alert_details_spec.rb34
-rw-r--r--spec/features/invites_spec.rb7
-rw-r--r--spec/features/issuables/issuable_list_spec.rb2
-rw-r--r--spec/features/issues/discussion_lock_spec.rb2
-rw-r--r--spec/features/issues/form_spec.rb66
-rw-r--r--spec/features/issues/issue_detail_spec.rb24
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb2
-rw-r--r--spec/features/issues/move_spec.rb3
-rw-r--r--spec/features/issues/user_comments_on_issue_spec.rb2
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb20
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb22
-rw-r--r--spec/features/markdown/observability_spec.rb124
-rw-r--r--spec/features/merge_request/user_comments_on_diff_spec.rb2
-rw-r--r--spec/features/merge_request/user_comments_on_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_creates_image_diff_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_edits_assignees_sidebar_spec.rb2
-rw-r--r--spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb2
-rw-r--r--spec/features/merge_request/user_reverts_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_discussions_navigation_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_real_time_reviewers_spec.rb24
-rw-r--r--spec/features/merge_request/user_views_open_merge_request_spec.rb12
-rw-r--r--spec/features/merge_requests/user_lists_merge_requests_spec.rb39
-rw-r--r--spec/features/monitor_sidebar_link_spec.rb2
-rw-r--r--spec/features/nav/new_nav_toggle_spec.rb2
-rw-r--r--spec/features/nav/top_nav_responsive_spec.rb22
-rw-r--r--spec/features/nav/top_nav_spec.rb14
-rw-r--r--spec/features/populate_new_pipeline_vars_with_params_spec.rb2
-rw-r--r--spec/features/profiles/chat_names_spec.rb5
-rw-r--r--spec/features/profiles/gpg_keys_spec.rb3
-rw-r--r--spec/features/profiles/user_creates_saved_reply_spec.rb29
-rw-r--r--spec/features/profiles/user_deletes_saved_reply_spec.rb27
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb20
-rw-r--r--spec/features/profiles/user_updates_saved_reply_spec.rb28
-rw-r--r--spec/features/profiles/user_uses_saved_reply_spec.rb29
-rw-r--r--spec/features/profiles/user_visits_profile_authentication_log_spec.rb2
-rw-r--r--spec/features/project_group_variables_spec.rb2
-rw-r--r--spec/features/project_variables_spec.rb15
-rw-r--r--spec/features/projects/badges/list_spec.rb39
-rw-r--r--spec/features/projects/blobs/blame_spec.rb47
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb8
-rw-r--r--spec/features/projects/branches_spec.rb24
-rw-r--r--spec/features/projects/ci/editor_spec.rb2
-rw-r--r--spec/features/projects/ci/lint_spec.rb2
-rw-r--r--spec/features/projects/commit/cherry_pick_spec.rb2
-rw-r--r--spec/features/projects/commit/user_reverts_commit_spec.rb2
-rw-r--r--spec/features/projects/integrations/apple_app_store_spec.rb24
-rw-r--r--spec/features/projects/integrations/google_play_spec.rb25
-rw-r--r--spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb2
-rw-r--r--spec/features/projects/integrations/user_activates_slack_notifications_spec.rb1
-rw-r--r--spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb2
-rw-r--r--spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb2
-rw-r--r--spec/features/projects/jobs_spec.rb13
-rw-r--r--spec/features/projects/members/sorting_spec.rb2
-rw-r--r--spec/features/projects/navbar_spec.rb1
-rw-r--r--spec/features/projects/new_project_spec.rb49
-rw-r--r--spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb12
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb44
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb6
-rw-r--r--spec/features/projects/settings/access_tokens_spec.rb2
-rw-r--r--spec/features/projects/settings/monitor_settings_spec.rb4
-rw-r--r--spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb9
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb9
-rw-r--r--spec/features/projects/user_changes_project_visibility_spec.rb19
-rw-r--r--spec/features/projects/work_items/work_item_children_spec.rb179
-rw-r--r--spec/features/projects/work_items/work_item_spec.rb58
-rw-r--r--spec/features/protected_tags_spec.rb34
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb18
-rw-r--r--spec/features/security/admin_access_spec.rb2
-rw-r--r--spec/features/security/dashboard_access_spec.rb2
-rw-r--r--spec/features/security/group/internal_access_spec.rb2
-rw-r--r--spec/features/security/group/private_access_spec.rb2
-rw-r--r--spec/features/security/group/public_access_spec.rb2
-rw-r--r--spec/features/security/project/internal_access_spec.rb2
-rw-r--r--spec/features/security/project/private_access_spec.rb2
-rw-r--r--spec/features/security/project/public_access_spec.rb2
-rw-r--r--spec/features/security/project/snippet/internal_access_spec.rb2
-rw-r--r--spec/features/security/project/snippet/private_access_spec.rb2
-rw-r--r--spec/features/security/project/snippet/public_access_spec.rb2
-rw-r--r--spec/features/signed_commits_spec.rb2
-rw-r--r--spec/features/snippets/show_spec.rb5
-rw-r--r--spec/features/topic_show_spec.rb2
-rw-r--r--spec/features/u2f_spec.rb216
-rw-r--r--spec/features/unsubscribe_links_spec.rb2
-rw-r--r--spec/features/users/login_spec.rb204
-rw-r--r--spec/features/users/show_spec.rb34
-rw-r--r--spec/features/users/signup_spec.rb9
-rw-r--r--spec/features/webauthn_spec.rb247
-rw-r--r--spec/features/whats_new_spec.rb6
-rw-r--r--spec/features/work_items/work_item_children_spec.rb136
-rw-r--r--spec/features/work_items/work_item_spec.rb37
-rw-r--r--spec/finders/abuse_reports_finder_spec.rb111
-rw-r--r--spec/finders/group_members_finder_spec.rb52
-rw-r--r--spec/finders/merge_requests_finder_spec.rb18
-rw-r--r--spec/finders/milestones_finder_spec.rb92
-rw-r--r--spec/finders/serverless_domain_finder_spec.rb103
-rw-r--r--spec/fixtures/api/schemas/cluster_status.json11
-rw-r--r--spec/fixtures/api/schemas/entities/discussion.json5
-rw-r--r--spec/fixtures/api/schemas/internal/pages/lookup_path.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/notes.json5
-rw-r--r--spec/fixtures/auth_key.p816
-rw-r--r--spec/fixtures/diagram.drawio.svg38
-rw-r--r--spec/fixtures/lib/gitlab/email/basic.html6
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/project.json133
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson8
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/tree/project/commit_notes.ndjson2
-rw-r--r--spec/fixtures/packages/debian/README.md2
-rw-r--r--spec/fixtures/packages/debian/sample-ddeb_1.2.3~alpha2_amd64.ddebbin0 -> 1068 bytes
-rw-r--r--spec/fixtures/packages/debian/sample/debian/.gitignore2
-rw-r--r--spec/fixtures/packages/debian/sample/debian/control4
-rwxr-xr-xspec/fixtures/packages/debian/sample/debian/rules7
-rw-r--r--spec/fixtures/packages/debian/sample_1.2.3~alpha2.dsc9
-rw-r--r--spec/fixtures/packages/debian/sample_1.2.3~alpha2.tar.xzbin864 -> 964 bytes
-rw-r--r--spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.buildinfo306
-rw-r--r--spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.changes21
-rw-r--r--spec/fixtures/service_account.json12
-rw-r--r--spec/fixtures/structure.sql8
-rw-r--r--spec/fixtures/work_items_invalid_types.csv4
-rw-r--r--spec/fixtures/work_items_missing_header.csv3
-rw-r--r--spec/fixtures/work_items_valid.csv3
-rw-r--r--spec/fixtures/work_items_valid_types.csv3
-rw-r--r--spec/frontend/.eslintrc.yml1
-rw-r--r--spec/frontend/__helpers__/create_mock_source_editor_extension.js12
-rw-r--r--spec/frontend/__helpers__/experimentation_helper.js7
-rw-r--r--spec/frontend/__helpers__/gon_helper.js5
-rw-r--r--spec/frontend/__helpers__/keep_alive_component_helper_spec.js4
-rw-r--r--spec/frontend/__helpers__/shared_test_setup.js16
-rw-r--r--spec/frontend/__helpers__/vue_mock_directive.js32
-rw-r--r--spec/frontend/__helpers__/vuex_action_helper.js2
-rw-r--r--spec/frontend/__helpers__/vuex_action_helper_spec.js14
-rw-r--r--spec/frontend/__mocks__/@gitlab/ui.js18
-rw-r--r--spec/frontend/__mocks__/lodash/debounce.js19
-rw-r--r--spec/frontend/__mocks__/lodash/throttle.js2
-rw-r--r--spec/frontend/abuse_reports/components/abuse_category_selector_spec.js4
-rw-r--r--spec/frontend/access_tokens/components/expires_at_field_spec.js4
-rw-r--r--spec/frontend/access_tokens/components/new_access_token_app_spec.js5
-rw-r--r--spec/frontend/access_tokens/components/token_spec.js4
-rw-r--r--spec/frontend/access_tokens/components/tokens_app_spec.js4
-rw-r--r--spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js4
-rw-r--r--spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js4
-rw-r--r--spec/frontend/add_context_commits_modal/store/actions_spec.js2
-rw-r--r--spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js43
-rw-r--r--spec/frontend/admin/abuse_reports/components/abuse_reports_filtered_search_bar_spec.js214
-rw-r--r--spec/frontend/admin/abuse_reports/components/app_spec.js104
-rw-r--r--spec/frontend/admin/abuse_reports/mock_data.js14
-rw-r--r--spec/frontend/admin/abuse_reports/utils_spec.js13
-rw-r--r--spec/frontend/admin/analytics/devops_score/components/devops_score_callout_spec.js4
-rw-r--r--spec/frontend/admin/application_settings/inactive_project_deletion/components/form_spec.js4
-rw-r--r--spec/frontend/admin/application_settings/network_outbound_spec.js70
-rw-r--r--spec/frontend/admin/applications/components/delete_application_spec.js1
-rw-r--r--spec/frontend/admin/background_migrations/components/database_listbox_spec.js4
-rw-r--r--spec/frontend/admin/broadcast_messages/components/base_spec.js5
-rw-r--r--spec/frontend/admin/broadcast_messages/components/message_form_spec.js4
-rw-r--r--spec/frontend/admin/broadcast_messages/components/messages_table_spec.js4
-rw-r--r--spec/frontend/admin/deploy_keys/components/table_spec.js10
-rw-r--r--spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js4
-rw-r--r--spec/frontend/admin/signup_restrictions/components/signup_form_spec.js2
-rw-r--r--spec/frontend/admin/statistics_panel/components/app_spec.js4
-rw-r--r--spec/frontend/admin/topics/components/remove_avatar_spec.js6
-rw-r--r--spec/frontend/admin/topics/components/topic_select_spec.js1
-rw-r--r--spec/frontend/admin/users/components/actions/actions_spec.js5
-rw-r--r--spec/frontend/admin/users/components/app_spec.js5
-rw-r--r--spec/frontend/admin/users/components/modals/delete_user_modal_spec.js5
-rw-r--r--spec/frontend/admin/users/components/user_actions_spec.js7
-rw-r--r--spec/frontend/admin/users/components/user_avatar_spec.js7
-rw-r--r--spec/frontend/admin/users/components/user_date_spec.js5
-rw-r--r--spec/frontend/admin/users/components/users_table_spec.js11
-rw-r--r--spec/frontend/admin/users/index_spec.js4
-rw-r--r--spec/frontend/airflow/dags/components/dags_spec.js115
-rw-r--r--spec/frontend/airflow/dags/components/mock_data.js67
-rw-r--r--spec/frontend/alert_management/components/alert_management_table_spec.js2
-rw-r--r--spec/frontend/alert_spec.js276
-rw-r--r--spec/frontend/alerts_settings/components/__snapshots__/alerts_form_spec.js.snap33
-rw-r--r--spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js12
-rw-r--r--spec/frontend/analytics/components/activity_chart_spec.js5
-rw-r--r--spec/frontend/analytics/cycle_analytics/base_spec.js33
-rw-r--r--spec/frontend/analytics/cycle_analytics/filter_bar_spec.js1
-rw-r--r--spec/frontend/analytics/cycle_analytics/formatted_stage_count_spec.js4
-rw-r--r--spec/frontend/analytics/cycle_analytics/mock_data.js2
-rw-r--r--spec/frontend/analytics/cycle_analytics/path_navigation_spec.js2
-rw-r--r--spec/frontend/analytics/cycle_analytics/stage_table_spec.js6
-rw-r--r--spec/frontend/analytics/cycle_analytics/store/actions_spec.js31
-rw-r--r--spec/frontend/analytics/cycle_analytics/store/mutations_spec.js13
-rw-r--r--spec/frontend/analytics/cycle_analytics/total_time_spec.js4
-rw-r--r--spec/frontend/analytics/cycle_analytics/utils_spec.js23
-rw-r--r--spec/frontend/analytics/cycle_analytics/value_stream_filters_spec.js5
-rw-r--r--spec/frontend/analytics/cycle_analytics/value_stream_metrics_spec.js29
-rw-r--r--spec/frontend/analytics/devops_reports/components/service_ping_disabled_spec.js4
-rw-r--r--spec/frontend/analytics/shared/components/daterange_spec.js15
-rw-r--r--spec/frontend/analytics/shared/components/metric_popover_spec.js4
-rw-r--r--spec/frontend/analytics/shared/components/metric_tile_spec.js4
-rw-r--r--spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js4
-rw-r--r--spec/frontend/analytics/shared/utils_spec.js28
-rw-r--r--spec/frontend/analytics/usage_trends/components/app_spec.js5
-rw-r--r--spec/frontend/analytics/usage_trends/components/usage_counts_spec.js4
-rw-r--r--spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js5
-rw-r--r--spec/frontend/analytics/usage_trends/components/users_chart_spec.js5
-rw-r--r--spec/frontend/api/alert_management_alerts_api_spec.js3
-rw-r--r--spec/frontend/api/groups_api_spec.js13
-rw-r--r--spec/frontend/api/packages_api_spec.js12
-rw-r--r--spec/frontend/api/projects_api_spec.js3
-rw-r--r--spec/frontend/api/tags_api_spec.js3
-rw-r--r--spec/frontend/api/user_api_spec.js3
-rw-r--r--spec/frontend/api_spec.js25
-rw-r--r--spec/frontend/approvals/mock_data.js10
-rw-r--r--spec/frontend/artifacts/components/artifact_row_spec.js39
-rw-r--r--spec/frontend/artifacts/components/artifacts_bulk_delete_spec.js96
-rw-r--r--spec/frontend/artifacts/components/artifacts_table_row_details_spec.js32
-rw-r--r--spec/frontend/artifacts/components/feedback_banner_spec.js4
-rw-r--r--spec/frontend/artifacts/components/job_artifacts_table_spec.js206
-rw-r--r--spec/frontend/artifacts/components/job_checkbox_spec.js71
-rw-r--r--spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js2
-rw-r--r--spec/frontend/authentication/u2f/authenticate_spec.js104
-rw-r--r--spec/frontend/authentication/u2f/mock_u2f_device.js23
-rw-r--r--spec/frontend/authentication/u2f/register_spec.js84
-rw-r--r--spec/frontend/authentication/u2f/util_spec.js61
-rw-r--r--spec/frontend/authentication/webauthn/components/registration_spec.js255
-rw-r--r--spec/frontend/authentication/webauthn/error_spec.js13
-rw-r--r--spec/frontend/authentication/webauthn/util_spec.js31
-rw-r--r--spec/frontend/awards_handler_spec.js5
-rw-r--r--spec/frontend/badges/components/badge_form_spec.js1
-rw-r--r--spec/frontend/badges/components/badge_list_row_spec.js1
-rw-r--r--spec/frontend/badges/components/badge_list_spec.js4
-rw-r--r--spec/frontend/badges/components/badge_settings_spec.js4
-rw-r--r--spec/frontend/badges/components/badge_spec.js4
-rw-r--r--spec/frontend/batch_comments/components/diff_file_drafts_spec.js4
-rw-r--r--spec/frontend/batch_comments/components/draft_note_spec.js4
-rw-r--r--spec/frontend/batch_comments/components/drafts_count_spec.js4
-rw-r--r--spec/frontend/batch_comments/components/preview_dropdown_spec.js19
-rw-r--r--spec/frontend/batch_comments/components/preview_item_spec.js4
-rw-r--r--spec/frontend/batch_comments/components/review_bar_spec.js4
-rw-r--r--spec/frontend/batch_comments/components/submit_dropdown_spec.js1
-rw-r--r--spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js6
-rw-r--r--spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js10
-rw-r--r--spec/frontend/behaviors/components/diagram_performance_warning_spec.js4
-rw-r--r--spec/frontend/behaviors/components/json_table_spec.js4
-rw-r--r--spec/frontend/behaviors/copy_to_clipboard_spec.js2
-rw-r--r--spec/frontend/behaviors/markdown/highlight_current_user_spec.js10
-rw-r--r--spec/frontend/behaviors/markdown/render_observability_spec.js55
-rw-r--r--spec/frontend/blame/blame_redirect_spec.js4
-rw-r--r--spec/frontend/blame/streaming/index_spec.js110
-rw-r--r--spec/frontend/blob/components/blob_content_error_spec.js4
-rw-r--r--spec/frontend/blob/components/blob_content_spec.js4
-rw-r--r--spec/frontend/blob/components/blob_edit_header_spec.js4
-rw-r--r--spec/frontend/blob/components/blob_header_default_actions_spec.js4
-rw-r--r--spec/frontend/blob/components/blob_header_filepath_spec.js4
-rw-r--r--spec/frontend/blob/components/blob_header_spec.js170
-rw-r--r--spec/frontend/blob/components/blob_header_viewer_switcher_spec.js53
-rw-r--r--spec/frontend/blob/components/table_contents_spec.js1
-rw-r--r--spec/frontend/blob/csv/csv_viewer_spec.js4
-rw-r--r--spec/frontend/blob/notebook/notebook_viever_spec.js2
-rw-r--r--spec/frontend/blob/pdf/pdf_viewer_spec.js5
-rw-r--r--spec/frontend/blob/pipeline_tour_success_modal_spec.js1
-rw-r--r--spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js5
-rw-r--r--spec/frontend/blob_edit/blob_bundle_spec.js4
-rw-r--r--spec/frontend/blob_edit/edit_blob_spec.js2
-rw-r--r--spec/frontend/boards/board_card_inner_spec.js8
-rw-r--r--spec/frontend/boards/board_list_helper.js1
-rw-r--r--spec/frontend/boards/board_list_spec.js4
-rw-r--r--spec/frontend/boards/components/board_add_new_column_form_spec.js124
-rw-r--r--spec/frontend/boards/components/board_add_new_column_spec.js61
-rw-r--r--spec/frontend/boards/components/board_add_new_column_trigger_spec.js6
-rw-r--r--spec/frontend/boards/components/board_app_spec.js3
-rw-r--r--spec/frontend/boards/components/board_card_spec.js2
-rw-r--r--spec/frontend/boards/components/board_column_spec.js6
-rw-r--r--spec/frontend/boards/components/board_configuration_options_spec.js4
-rw-r--r--spec/frontend/boards/components/board_content_sidebar_spec.js4
-rw-r--r--spec/frontend/boards/components/board_content_spec.js15
-rw-r--r--spec/frontend/boards/components/board_filtered_search_spec.js28
-rw-r--r--spec/frontend/boards/components/board_form_spec.js77
-rw-r--r--spec/frontend/boards/components/board_list_header_spec.js108
-rw-r--r--spec/frontend/boards/components/board_new_issue_spec.js4
-rw-r--r--spec/frontend/boards/components/board_new_item_spec.js4
-rw-r--r--spec/frontend/boards/components/board_settings_sidebar_spec.js4
-rw-r--r--spec/frontend/boards/components/board_top_bar_spec.js19
-rw-r--r--spec/frontend/boards/components/boards_selector_spec.js11
-rw-r--r--spec/frontend/boards/components/config_toggle_spec.js4
-rw-r--r--spec/frontend/boards/components/issue_board_filtered_search_spec.js16
-rw-r--r--spec/frontend/boards/components/issue_due_date_spec.js4
-rw-r--r--spec/frontend/boards/components/issue_time_estimate_spec.js4
-rw-r--r--spec/frontend/boards/components/item_count_spec.js8
-rw-r--r--spec/frontend/boards/components/sidebar/board_editable_item_spec.js5
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_time_tracker_spec.js5
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js2
-rw-r--r--spec/frontend/boards/components/toggle_focus_spec.js6
-rw-r--r--spec/frontend/boards/mock_data.js4
-rw-r--r--spec/frontend/boards/project_select_spec.js5
-rw-r--r--spec/frontend/boards/stores/actions_spec.js20
-rw-r--r--spec/frontend/boards/stores/getters_spec.js8
-rw-r--r--spec/frontend/branches/components/delete_branch_button_spec.js4
-rw-r--r--spec/frontend/branches/components/delete_branch_modal_spec.js4
-rw-r--r--spec/frontend/branches/components/delete_merged_branches_spec.js6
-rw-r--r--spec/frontend/branches/components/divergence_graph_spec.js4
-rw-r--r--spec/frontend/branches/components/graph_bar_spec.js4
-rw-r--r--spec/frontend/captcha/captcha_modal_spec.js68
-rw-r--r--spec/frontend/ci/ci_lint/components/ci_lint_spec.js1
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_admin_variables_spec.js4
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js4
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js4
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_project_variables_spec.js4
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js4
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js24
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js588
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js189
-rw-r--r--spec/frontend/ci/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/commit/commit_form_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/drawer/cards/getting_started_card_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/editor/ci_config_merged_preview_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/editor/ci_editor_header_spec.js1
-rw-r--r--spec/frontend/ci/pipeline_editor/components/editor/text_editor_spec.js76
-rw-r--r--spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/file-tree/container_spec.js3
-rw-r--r--spec/frontend/ci/pipeline_editor/components/file-tree/file_item_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_header_spec.js5
-rw-r--r--spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js1
-rw-r--r--spec/frontend/ci/pipeline_editor/components/header/validation_segment_spec.js102
-rw-r--r--spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item_spec.js39
-rw-r--r--spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item_spec.js61
-rw-r--r--spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js112
-rw-r--r--spec/frontend/ci/pipeline_editor/components/lint/ci_lint_results_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/lint/ci_lint_warnings_spec.js5
-rw-r--r--spec/frontend/ci/pipeline_editor/components/pipeline_editor_tabs_spec.js1
-rw-r--r--spec/frontend/ci/pipeline_editor/components/popovers/file_tree_popover_spec.js1
-rw-r--r--spec/frontend/ci/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/popovers/walkthrough_popover_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/validate/ci_validate_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/mock_data.js87
-rw-r--r--spec/frontend/ci/pipeline_editor/pipeline_editor_app_spec.js17
-rw-r--r--spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js1
-rw-r--r--spec/frontend/ci/pipeline_new/components/pipeline_new_form_spec.js17
-rw-r--r--spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js6
-rw-r--r--spec/frontend/ci/pipeline_new/mock_data.js2
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js6
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js20
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js7
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js14
-rw-r--r--spec/frontend/ci/pipeline_schedules/mock_data.js2
-rw-r--r--spec/frontend/ci/reports/codequality_report/components/codequality_issue_body_spec.js5
-rw-r--r--spec/frontend/ci/reports/components/grouped_issues_list_spec.js4
-rw-r--r--spec/frontend/ci/reports/components/issue_status_icon_spec.js5
-rw-r--r--spec/frontend/ci/reports/components/report_link_spec.js4
-rw-r--r--spec/frontend/ci/reports/components/report_section_spec.js4
-rw-r--r--spec/frontend/ci/reports/components/summary_row_spec.js5
-rw-r--r--spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js93
-rw-r--r--spec/frontend/ci/runner/admin_register_runner/admin_register_runner_app_spec.js122
-rw-r--r--spec/frontend/ci/runner/admin_runner_show/admin_runner_show_app_spec.js5
-rw-r--r--spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js5
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_actions_cell_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_owner_cell_spec.js6
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_status_cell_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_summary_field_spec.js6
-rw-r--r--spec/frontend/ci/runner/components/registration/__snapshots__/utils_spec.js.snap204
-rw-r--r--spec/frontend/ci/runner/components/registration/cli_command_spec.js39
-rw-r--r--spec/frontend/ci/runner/components/registration/platforms_drawer_spec.js108
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_instructions_spec.js293
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_token_reset_dropdown_item_spec.js10
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_token_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/registration/utils_spec.js118
-rw-r--r--spec/frontend/ci/runner/components/runner_assigned_item_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_bulk_delete_spec.js6
-rw-r--r--spec/frontend/ci/runner/components/runner_create_form_spec.js170
-rw-r--r--spec/frontend/ci/runner/components/runner_delete_button_spec.js12
-rw-r--r--spec/frontend/ci/runner/components/runner_details_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_edit_button_spec.js6
-rw-r--r--spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_groups_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_header_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_jobs_spec.js5
-rw-r--r--spec/frontend/ci/runner/components/runner_jobs_table_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_list_empty_state_spec.js14
-rw-r--r--spec/frontend/ci/runner/components/runner_list_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_membership_toggle_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_pagination_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_pause_button_spec.js10
-rw-r--r--spec/frontend/ci/runner/components/runner_paused_badge_spec.js6
-rw-r--r--spec/frontend/ci/runner/components/runner_projects_spec.js5
-rw-r--r--spec/frontend/ci/runner/components/runner_status_badge_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_tag_spec.js8
-rw-r--r--spec/frontend/ci/runner/components/runner_tags_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_type_badge_spec.js6
-rw-r--r--spec/frontend/ci/runner/components/runner_type_tabs_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_update_form_spec.js8
-rw-r--r--spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js5
-rw-r--r--spec/frontend/ci/runner/components/stat/runner_single_stat_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/stat/runner_stats_spec.js4
-rw-r--r--spec/frontend/ci/runner/group_runner_show/group_runner_show_app_spec.js5
-rw-r--r--spec/frontend/ci/runner/group_runners/group_runners_app_spec.js5
-rw-r--r--spec/frontend/ci/runner/local_storage_alert/show_alert_from_local_storage_spec.js4
-rw-r--r--spec/frontend/ci/runner/mock_data.js8
-rw-r--r--spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js5
-rw-r--r--spec/frontend/ci_secure_files/components/metadata/__snapshots__/modal_spec.js.snap4
-rw-r--r--spec/frontend/ci_secure_files/components/metadata/button_spec.js4
-rw-r--r--spec/frontend/ci_secure_files/components/metadata/modal_spec.js1
-rw-r--r--spec/frontend/ci_secure_files/components/secure_files_list_spec.js13
-rw-r--r--spec/frontend/clusters/agents/components/activity_events_list_spec.js4
-rw-r--r--spec/frontend/clusters/agents/components/activity_history_item_spec.js4
-rw-r--r--spec/frontend/clusters/agents/components/agent_integration_status_row_spec.js4
-rw-r--r--spec/frontend/clusters/agents/components/create_token_button_spec.js6
-rw-r--r--spec/frontend/clusters/agents/components/create_token_modal_spec.js1
-rw-r--r--spec/frontend/clusters/agents/components/integration_status_spec.js4
-rw-r--r--spec/frontend/clusters/agents/components/revoke_token_button_spec.js3
-rw-r--r--spec/frontend/clusters/agents/components/show_spec.js4
-rw-r--r--spec/frontend/clusters/agents/components/token_table_spec.js4
-rw-r--r--spec/frontend/clusters/components/__snapshots__/new_cluster_spec.js.snap2
-rw-r--r--spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap209
-rw-r--r--spec/frontend/clusters/components/new_cluster_spec.js4
-rw-r--r--spec/frontend/clusters/components/remove_cluster_confirmation_spec.js22
-rw-r--r--spec/frontend/clusters/forms/components/integration_form_spec.js31
-rw-r--r--spec/frontend/clusters_list/components/agent_token_spec.js4
-rw-r--r--spec/frontend/clusters_list/components/agents_spec.js2
-rw-r--r--spec/frontend/clusters_list/components/ancestor_notice_spec.js4
-rw-r--r--spec/frontend/clusters_list/components/clusters_actions_spec.js5
-rw-r--r--spec/frontend/clusters_list/components/clusters_empty_state_spec.js4
-rw-r--r--spec/frontend/clusters_list/components/clusters_main_view_spec.js4
-rw-r--r--spec/frontend/clusters_list/components/clusters_spec.js5
-rw-r--r--spec/frontend/clusters_list/components/clusters_view_all_spec.js4
-rw-r--r--spec/frontend/clusters_list/components/delete_agent_button_spec.js5
-rw-r--r--spec/frontend/clusters_list/components/install_agent_modal_spec.js1
-rw-r--r--spec/frontend/clusters_list/components/node_error_help_text_spec.js4
-rw-r--r--spec/frontend/clusters_list/store/actions_spec.js6
-rw-r--r--spec/frontend/code_navigation/components/app_spec.js4
-rw-r--r--spec/frontend/code_navigation/components/popover_spec.js4
-rw-r--r--spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js8
-rw-r--r--spec/frontend/commit/commit_pipeline_status_component_spec.js11
-rw-r--r--spec/frontend/commit/components/commit_box_pipeline_status_spec.js8
-rw-r--r--spec/frontend/commit/components/signature_badge_spec.js134
-rw-r--r--spec/frontend/commit/components/x509_certificate_details_spec.js36
-rw-r--r--spec/frontend/commit/mock_data.js31
-rw-r--r--spec/frontend/commit/pipelines/pipelines_table_spec.js118
-rw-r--r--spec/frontend/confidential_merge_request/components/project_form_group_spec.js1
-rw-r--r--spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap2
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js4
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js4
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js4
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js4
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js97
-rw-r--r--spec/frontend/content_editor/components/content_editor_alert_spec.js4
-rw-r--r--spec/frontend/content_editor/components/content_editor_spec.js68
-rw-r--r--spec/frontend/content_editor/components/editor_state_observer_spec.js4
-rw-r--r--spec/frontend/content_editor/components/formatting_toolbar_spec.js14
-rw-r--r--spec/frontend/content_editor/components/loading_indicator_spec.js4
-rw-r--r--spec/frontend/content_editor/components/toolbar_button_spec.js4
-rw-r--r--spec/frontend/content_editor/components/toolbar_image_button_spec.js1
-rw-r--r--spec/frontend/content_editor/components/toolbar_link_button_spec.js1
-rw-r--r--spec/frontend/content_editor/components/toolbar_more_dropdown_spec.js40
-rw-r--r--spec/frontend/content_editor/components/toolbar_table_button_spec.js1
-rw-r--r--spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js4
-rw-r--r--spec/frontend/content_editor/components/wrappers/code_block_spec.js4
-rw-r--r--spec/frontend/content_editor/components/wrappers/details_spec.js4
-rw-r--r--spec/frontend/content_editor/components/wrappers/footnote_definition_spec.js4
-rw-r--r--spec/frontend/content_editor/components/wrappers/label_spec.js4
-rw-r--r--spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js8
-rw-r--r--spec/frontend/content_editor/components/wrappers/table_cell_body_spec.js4
-rw-r--r--spec/frontend/content_editor/components/wrappers/table_cell_header_spec.js4
-rw-r--r--spec/frontend/content_editor/components/wrappers/table_of_contents_spec.js4
-rw-r--r--spec/frontend/content_editor/extensions/attachment_spec.js21
-rw-r--r--spec/frontend/content_editor/extensions/drawio_diagram_spec.js103
-rw-r--r--spec/frontend/content_editor/extensions/paste_markdown_spec.js2
-rw-r--r--spec/frontend/content_editor/render_html_and_json_for_all_examples.js2
-rw-r--r--spec/frontend/content_editor/services/create_content_editor_spec.js16
-rw-r--r--spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js22
-rw-r--r--spec/frontend/content_editor/services/markdown_serializer_spec.js9
-rw-r--r--spec/frontend/content_editor/test_constants.js6
-rw-r--r--spec/frontend/content_editor/test_utils.js2
-rw-r--r--spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap64
-rw-r--r--spec/frontend/contributors/component/contributors_spec.js6
-rw-r--r--spec/frontend/contributors/store/actions_spec.js6
-rw-r--r--spec/frontend/crm/contact_form_wrapper_spec.js1
-rw-r--r--spec/frontend/crm/contacts_root_spec.js1
-rw-r--r--spec/frontend/crm/crm_form_spec.js4
-rw-r--r--spec/frontend/crm/organization_form_wrapper_spec.js4
-rw-r--r--spec/frontend/crm/organizations_root_spec.js1
-rw-r--r--spec/frontend/custom_metrics/components/custom_metrics_form_fields_spec.js1
-rw-r--r--spec/frontend/custom_metrics/components/custom_metrics_form_spec.js4
-rw-r--r--spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js5
-rw-r--r--spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js5
-rw-r--r--spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js5
-rw-r--r--spec/frontend/deploy_freeze/store/actions_spec.js4
-rw-r--r--spec/frontend/deploy_keys/components/app_spec.js1
-rw-r--r--spec/frontend/deploy_keys/components/key_spec.js5
-rw-r--r--spec/frontend/deploy_keys/components/keys_panel_spec.js5
-rw-r--r--spec/frontend/deploy_tokens/components/new_deploy_token_spec.js51
-rw-r--r--spec/frontend/deploy_tokens/components/revoke_button_spec.js4
-rw-r--r--spec/frontend/design_management/components/delete_button_spec.js4
-rw-r--r--spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap2
-rw-r--r--spec/frontend/design_management/components/design_notes/design_discussion_spec.js170
-rw-r--r--spec/frontend/design_management/components/design_notes/design_note_signed_out_spec.js4
-rw-r--r--spec/frontend/design_management/components/design_notes/design_note_spec.js56
-rw-r--r--spec/frontend/design_management/components/design_notes/design_reply_form_spec.js255
-rw-r--r--spec/frontend/design_management/components/design_notes/toggle_replies_widget_spec.js4
-rw-r--r--spec/frontend/design_management/components/design_presentation_spec.js6
-rw-r--r--spec/frontend/design_management/components/design_scaler_spec.js5
-rw-r--r--spec/frontend/design_management/components/design_sidebar_spec.js10
-rw-r--r--spec/frontend/design_management/components/design_todo_button_spec.js2
-rw-r--r--spec/frontend/design_management/components/image_spec.js4
-rw-r--r--spec/frontend/design_management/components/list/item_spec.js4
-rw-r--r--spec/frontend/design_management/components/toolbar/design_navigation_spec.js4
-rw-r--r--spec/frontend/design_management/components/toolbar/index_spec.js46
-rw-r--r--spec/frontend/design_management/components/upload/button_spec.js4
-rw-r--r--spec/frontend/design_management/components/upload/design_version_dropdown_spec.js4
-rw-r--r--spec/frontend/design_management/mock_data/apollo_mock.js112
-rw-r--r--spec/frontend/design_management/mock_data/project.js17
-rw-r--r--spec/frontend/design_management/pages/design/index_spec.js81
-rw-r--r--spec/frontend/design_management/pages/index_spec.js15
-rw-r--r--spec/frontend/design_management/router_spec.js6
-rw-r--r--spec/frontend/design_management/utils/cache_update_spec.js4
-rw-r--r--spec/frontend/diffs/components/app_spec.js79
-rw-r--r--spec/frontend/diffs/components/collapsed_files_warning_spec.js4
-rw-r--r--spec/frontend/diffs/components/commit_item_spec.js5
-rw-r--r--spec/frontend/diffs/components/compare_dropdown_layout_spec.js5
-rw-r--r--spec/frontend/diffs/components/compare_versions_spec.js5
-rw-r--r--spec/frontend/diffs/components/diff_code_quality_spec.js4
-rw-r--r--spec/frontend/diffs/components/diff_content_spec.js5
-rw-r--r--spec/frontend/diffs/components/diff_discussion_reply_spec.js4
-rw-r--r--spec/frontend/diffs/components/diff_discussions_spec.js4
-rw-r--r--spec/frontend/diffs/components/diff_file_header_spec.js2
-rw-r--r--spec/frontend/diffs/components/diff_file_row_spec.js4
-rw-r--r--spec/frontend/diffs/components/diff_file_spec.js13
-rw-r--r--spec/frontend/diffs/components/diff_gutter_avatars_spec.js4
-rw-r--r--spec/frontend/diffs/components/diff_row_spec.js4
-rw-r--r--spec/frontend/diffs/components/hidden_files_warning_spec.js4
-rw-r--r--spec/frontend/diffs/components/image_diff_overlay_spec.js4
-rw-r--r--spec/frontend/diffs/components/merge_conflict_warning_spec.js4
-rw-r--r--spec/frontend/diffs/components/no_changes_spec.js5
-rw-r--r--spec/frontend/diffs/components/settings_dropdown_spec.js1
-rw-r--r--spec/frontend/diffs/components/tree_list_spec.js83
-rw-r--r--spec/frontend/diffs/store/actions_spec.js49
-rw-r--r--spec/frontend/diffs/store/getters_spec.js25
-rw-r--r--spec/frontend/diffs/store/mutations_spec.js9
-rw-r--r--spec/frontend/diffs/store/utils_spec.js57
-rw-r--r--spec/frontend/diffs/utils/tree_worker_utils_spec.js30
-rw-r--r--spec/frontend/drawio/content_editor_facade_spec.js138
-rw-r--r--spec/frontend/drawio/drawio_editor_spec.js479
-rw-r--r--spec/frontend/drawio/markdown_field_editor_facade_spec.js148
-rw-r--r--spec/frontend/editor/components/helpers.js3
-rw-r--r--spec/frontend/editor/components/source_editor_toolbar_button_spec.js5
-rw-r--r--spec/frontend/editor/components/source_editor_toolbar_spec.js32
-rw-r--r--spec/frontend/editor/schema/ci/ci_schema_spec.js8
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml38
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml31
-rw-r--r--spec/frontend/editor/source_editor_ci_schema_ext_spec.js11
-rw-r--r--spec/frontend/editor/source_editor_extension_base_spec.js112
-rw-r--r--spec/frontend/editor/source_editor_markdown_ext_spec.js25
-rw-r--r--spec/frontend/editor/source_editor_markdown_livepreview_ext_spec.js4
-rw-r--r--spec/frontend/editor/source_editor_webide_ext_spec.js1
-rw-r--r--spec/frontend/editor/utils_spec.js22
-rw-r--r--spec/frontend/emoji/components/category_spec.js21
-rw-r--r--spec/frontend/emoji/components/emoji_group_spec.js4
-rw-r--r--spec/frontend/emoji/components/emoji_list_spec.js33
-rw-r--r--spec/frontend/environment.js8
-rw-r--r--spec/frontend/environments/canary_ingress_spec.js4
-rw-r--r--spec/frontend/environments/canary_update_modal_spec.js4
-rw-r--r--spec/frontend/environments/delete_environment_modal_spec.js6
-rw-r--r--spec/frontend/environments/edit_environment_spec.js5
-rw-r--r--spec/frontend/environments/empty_state_spec.js4
-rw-r--r--spec/frontend/environments/enable_review_app_modal_spec.js4
-rw-r--r--spec/frontend/environments/environment_actions_spec.js3
-rw-r--r--spec/frontend/environments/environment_folder_spec.js2
-rw-r--r--spec/frontend/environments/environment_form_spec.js20
-rw-r--r--spec/frontend/environments/environment_item_spec.js8
-rw-r--r--spec/frontend/environments/environment_pin_spec.js8
-rw-r--r--spec/frontend/environments/environment_table_spec.js4
-rw-r--r--spec/frontend/environments/environments_app_spec.js4
-rw-r--r--spec/frontend/environments/environments_detail_header_spec.js6
-rw-r--r--spec/frontend/environments/environments_folder_view_spec.js1
-rw-r--r--spec/frontend/environments/graphql/mock_data.js6
-rw-r--r--spec/frontend/environments/kubernetes_agent_info_spec.js126
-rw-r--r--spec/frontend/environments/kubernetes_overview_spec.js84
-rw-r--r--spec/frontend/environments/new_environment_item_spec.js83
-rw-r--r--spec/frontend/environments/new_environment_spec.js5
-rw-r--r--spec/frontend/environments/stop_stale_environments_modal_spec.js6
-rw-r--r--spec/frontend/error_tracking/components/error_details_spec.js6
-rw-r--r--spec/frontend/error_tracking/store/actions_spec.js4
-rw-r--r--spec/frontend/error_tracking/store/details/actions_spec.js6
-rw-r--r--spec/frontend/error_tracking/store/list/actions_spec.js6
-rw-r--r--spec/frontend/experimentation/components/gitlab_experiment_spec.js7
-rw-r--r--spec/frontend/experimentation/utils_spec.js3
-rw-r--r--spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js9
-rw-r--r--spec/frontend/feature_flags/components/edit_feature_flag_spec.js1
-rw-r--r--spec/frontend/feature_flags/components/empty_state_spec.js2
-rw-r--r--spec/frontend/feature_flags/components/environments_dropdown_spec.js1
-rw-r--r--spec/frontend/feature_flags/components/feature_flags_spec.js2
-rw-r--r--spec/frontend/feature_flags/components/form_spec.js4
-rw-r--r--spec/frontend/feature_flags/components/new_feature_flag_spec.js4
-rw-r--r--spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js2
-rw-r--r--spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js2
-rw-r--r--spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js2
-rw-r--r--spec/frontend/feature_flags/components/strategies/users_with_id_spec.js2
-rw-r--r--spec/frontend/feature_flags/components/strategy_parameters_spec.js2
-rw-r--r--spec/frontend/feature_highlight/feature_highlight_helper_spec.js6
-rw-r--r--spec/frontend/feature_highlight/feature_highlight_popover_spec.js5
-rw-r--r--spec/frontend/filtered_search/components/recent_searches_dropdown_content_spec.js5
-rw-r--r--spec/frontend/filtered_search/dropdown_user_spec.js4
-rw-r--r--spec/frontend/filtered_search/filtered_search_manager_spec.js4
-rw-r--r--spec/frontend/filtered_search/visual_token_value_spec.js4
-rw-r--r--spec/frontend/fixtures/abuse_reports.rb2
-rw-r--r--spec/frontend/fixtures/api_deploy_keys.rb5
-rw-r--r--spec/frontend/fixtures/jobs.rb22
-rw-r--r--spec/frontend/fixtures/merge_requests.rb6
-rw-r--r--spec/frontend/fixtures/runner.rb34
-rw-r--r--spec/frontend/fixtures/saved_replies.rb28
-rw-r--r--spec/frontend/fixtures/startup_css.rb20
-rw-r--r--spec/frontend/fixtures/u2f.rb48
-rw-r--r--spec/frontend/fixtures/users.rb65
-rw-r--r--spec/frontend/fixtures/webauthn.rb1
-rw-r--r--spec/frontend/flash_spec.js276
-rw-r--r--spec/frontend/frequent_items/components/app_spec.js1
-rw-r--r--spec/frontend/frequent_items/components/frequent_items_list_item_spec.js2
-rw-r--r--spec/frontend/frequent_items/components/frequent_items_list_spec.js4
-rw-r--r--spec/frontend/gitlab_pages/new/pages/pages_pipeline_wizard_spec.js4
-rw-r--r--spec/frontend/gitlab_version_check/components/gitlab_version_check_badge_spec.js1
-rw-r--r--spec/frontend/google_cloud/components/google_cloud_menu_spec.js4
-rw-r--r--spec/frontend/google_cloud/components/incubation_banner_spec.js4
-rw-r--r--spec/frontend/google_cloud/components/revoke_oauth_spec.js4
-rw-r--r--spec/frontend/google_cloud/configuration/panel_spec.js4
-rw-r--r--spec/frontend/google_cloud/databases/cloudsql/create_instance_form_spec.js4
-rw-r--r--spec/frontend/google_cloud/databases/cloudsql/instance_table_spec.js4
-rw-r--r--spec/frontend/google_cloud/databases/panel_spec.js4
-rw-r--r--spec/frontend/google_cloud/databases/service_table_spec.js4
-rw-r--r--spec/frontend/google_cloud/deployments/panel_spec.js4
-rw-r--r--spec/frontend/google_cloud/deployments/service_table_spec.js4
-rw-r--r--spec/frontend/google_cloud/gcp_regions/form_spec.js4
-rw-r--r--spec/frontend/google_cloud/gcp_regions/list_spec.js4
-rw-r--r--spec/frontend/google_cloud/service_accounts/form_spec.js4
-rw-r--r--spec/frontend/google_cloud/service_accounts/list_spec.js4
-rw-r--r--spec/frontend/grafana_integration/components/grafana_integration_spec.js6
-rw-r--r--spec/frontend/group_settings/components/shared_runners_form_spec.js3
-rw-r--r--spec/frontend/groups/components/app_spec.js15
-rw-r--r--spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js4
-rw-r--r--spec/frontend/groups/components/group_folder_spec.js4
-rw-r--r--spec/frontend/groups/components/group_item_spec.js4
-rw-r--r--spec/frontend/groups/components/group_name_and_path_spec.js4
-rw-r--r--spec/frontend/groups/components/groups_spec.js4
-rw-r--r--spec/frontend/groups/components/invite_members_banner_spec.js9
-rw-r--r--spec/frontend/groups/components/item_actions_spec.js5
-rw-r--r--spec/frontend/groups/components/new_top_level_group_alert_spec.js4
-rw-r--r--spec/frontend/groups/components/overview_tabs_spec.js1
-rw-r--r--spec/frontend/groups/components/transfer_group_form_spec.js4
-rw-r--r--spec/frontend/groups_projects/components/transfer_locations_spec.js4
-rw-r--r--spec/frontend/header_search/components/app_spec.js20
-rw-r--r--spec/frontend/header_search/components/header_search_autocomplete_items_spec.js11
-rw-r--r--spec/frontend/header_search/components/header_search_default_items_spec.js4
-rw-r--r--spec/frontend/header_search/components/header_search_scoped_items_spec.js7
-rw-r--r--spec/frontend/header_search/mock_data.js10
-rw-r--r--spec/frontend/header_search/store/actions_spec.js2
-rw-r--r--spec/frontend/header_search/store/getters_spec.js7
-rw-r--r--spec/frontend/helpers/startup_css_helper_spec.js7
-rw-r--r--spec/frontend/ide/components/activity_bar_spec.js4
-rw-r--r--spec/frontend/ide/components/branches/item_spec.js4
-rw-r--r--spec/frontend/ide/components/branches/search_list_spec.js5
-rw-r--r--spec/frontend/ide/components/cannot_push_code_alert_spec.js4
-rw-r--r--spec/frontend/ide/components/commit_sidebar/actions_spec.js4
-rw-r--r--spec/frontend/ide/components/commit_sidebar/editor_header_spec.js39
-rw-r--r--spec/frontend/ide/components/commit_sidebar/empty_state_spec.js4
-rw-r--r--spec/frontend/ide/components/commit_sidebar/form_spec.js6
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_item_spec.js4
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_spec.js4
-rw-r--r--spec/frontend/ide/components/commit_sidebar/message_field_spec.js4
-rw-r--r--spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js6
-rw-r--r--spec/frontend/ide/components/commit_sidebar/radio_group_spec.js6
-rw-r--r--spec/frontend/ide/components/commit_sidebar/success_message_spec.js4
-rw-r--r--spec/frontend/ide/components/error_message_spec.js5
-rw-r--r--spec/frontend/ide/components/file_row_extra_spec.js2
-rw-r--r--spec/frontend/ide/components/file_templates/bar_spec.js4
-rw-r--r--spec/frontend/ide/components/file_templates/dropdown_spec.js5
-rw-r--r--spec/frontend/ide/components/ide_file_row_spec.js5
-rw-r--r--spec/frontend/ide/components/ide_project_header_spec.js4
-rw-r--r--spec/frontend/ide/components/ide_review_spec.js4
-rw-r--r--spec/frontend/ide/components/ide_side_bar_spec.js5
-rw-r--r--spec/frontend/ide/components/ide_sidebar_nav_spec.js11
-rw-r--r--spec/frontend/ide/components/ide_spec.js2
-rw-r--r--spec/frontend/ide/components/ide_status_bar_spec.js4
-rw-r--r--spec/frontend/ide/components/ide_status_list_spec.js3
-rw-r--r--spec/frontend/ide/components/ide_status_mr_spec.js4
-rw-r--r--spec/frontend/ide/components/ide_tree_list_spec.js4
-rw-r--r--spec/frontend/ide/components/ide_tree_spec.js4
-rw-r--r--spec/frontend/ide/components/jobs/detail/description_spec.js4
-rw-r--r--spec/frontend/ide/components/jobs/detail/scroll_button_spec.js4
-rw-r--r--spec/frontend/ide/components/jobs/detail_spec.js4
-rw-r--r--spec/frontend/ide/components/jobs/item_spec.js4
-rw-r--r--spec/frontend/ide/components/jobs/stage_spec.js5
-rw-r--r--spec/frontend/ide/components/merge_requests/item_spec.js5
-rw-r--r--spec/frontend/ide/components/merge_requests/list_spec.js5
-rw-r--r--spec/frontend/ide/components/nav_dropdown_button_spec.js4
-rw-r--r--spec/frontend/ide/components/nav_dropdown_spec.js4
-rw-r--r--spec/frontend/ide/components/new_dropdown/button_spec.js4
-rw-r--r--spec/frontend/ide/components/new_dropdown/index_spec.js4
-rw-r--r--spec/frontend/ide/components/new_dropdown/modal_spec.js21
-rw-r--r--spec/frontend/ide/components/new_dropdown/upload_spec.js4
-rw-r--r--spec/frontend/ide/components/panes/collapsible_sidebar_spec.js5
-rw-r--r--spec/frontend/ide/components/panes/right_spec.js5
-rw-r--r--spec/frontend/ide/components/pipelines/empty_state_spec.js4
-rw-r--r--spec/frontend/ide/components/pipelines/list_spec.js5
-rw-r--r--spec/frontend/ide/components/repo_commit_section_spec.js5
-rw-r--r--spec/frontend/ide/components/repo_editor_spec.js2
-rw-r--r--spec/frontend/ide/components/repo_tab_spec.js5
-rw-r--r--spec/frontend/ide/components/repo_tabs_spec.js4
-rw-r--r--spec/frontend/ide/components/resizable_panel_spec.js5
-rw-r--r--spec/frontend/ide/components/shared/commit_message_field_spec.js4
-rw-r--r--spec/frontend/ide/components/shared/tokened_input_spec.js4
-rw-r--r--spec/frontend/ide/components/terminal/empty_state_spec.js4
-rw-r--r--spec/frontend/ide/components/terminal/terminal_spec.js4
-rw-r--r--spec/frontend/ide/components/terminal/view_spec.js4
-rw-r--r--spec/frontend/ide/components/terminal_sync/terminal_sync_status_safe_spec.js4
-rw-r--r--spec/frontend/ide/components/terminal_sync/terminal_sync_status_spec.js4
-rw-r--r--spec/frontend/ide/services/index_spec.js3
-rw-r--r--spec/frontend/ide/services/terminals_spec.js2
-rw-r--r--spec/frontend/ide/stores/actions/file_spec.js4
-rw-r--r--spec/frontend/ide/stores/actions/merge_request_spec.js8
-rw-r--r--spec/frontend/ide/stores/actions/project_spec.js6
-rw-r--r--spec/frontend/ide/stores/actions_spec.js8
-rw-r--r--spec/frontend/ide/stores/extend_spec.js5
-rw-r--r--spec/frontend/ide/stores/getters_spec.js7
-rw-r--r--spec/frontend/ide/stores/modules/commit/actions_spec.js76
-rw-r--r--spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js8
-rw-r--r--spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js6
-rw-r--r--spec/frontend/import_entities/components/group_dropdown_spec.js4
-rw-r--r--spec/frontend/import_entities/components/import_status_spec.js4
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js43
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_source_cell_spec.js4
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_table_spec.js56
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_target_cell_spec.js5
-rw-r--r--spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js2
-rw-r--r--spec/frontend/import_entities/import_groups/services/status_poller_spec.js6
-rw-r--r--spec/frontend/import_entities/import_projects/components/advanced_settings_spec.js4
-rw-r--r--spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js5
-rw-r--r--spec/frontend/import_entities/import_projects/store/actions_spec.js4
-rw-r--r--spec/frontend/incidents_settings/components/incidents_settings_service_spec.js6
-rw-r--r--spec/frontend/incidents_settings/components/pagerduty_form_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/active_checkbox_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/confirmation_modal_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/dynamic_field_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/integration_form_spec.js51
-rw-r--r--spec/frontend/integrations/edit/components/jira_issues_fields_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/jira_trigger_fields_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/override_dropdown_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/sections/apple_app_store_spec.js57
-rw-r--r--spec/frontend/integrations/edit/components/sections/configuration_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/sections/connection_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/sections/google_play_spec.js54
-rw-r--r--spec/frontend/integrations/edit/components/sections/jira_issues_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/sections/jira_trigger_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/sections/trigger_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/trigger_field_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/trigger_fields_spec.js4
-rw-r--r--spec/frontend/integrations/edit/components/upload_dropzone_field_spec.js88
-rw-r--r--spec/frontend/integrations/index/components/integrations_list_spec.js4
-rw-r--r--spec/frontend/integrations/index/components/integrations_table_spec.js61
-rw-r--r--spec/frontend/integrations/overrides/components/integration_overrides_spec.js1
-rw-r--r--spec/frontend/integrations/overrides/components/integration_tabs_spec.js4
-rw-r--r--spec/frontend/invite_members/components/confetti_spec.js8
-rw-r--r--spec/frontend/invite_members/components/group_select_spec.js8
-rw-r--r--spec/frontend/invite_members/components/import_project_members_modal_spec.js1
-rw-r--r--spec/frontend/invite_members/components/import_project_members_trigger_spec.js4
-rw-r--r--spec/frontend/invite_members/components/invite_group_trigger_spec.js5
-rw-r--r--spec/frontend/invite_members/components/invite_groups_modal_spec.js17
-rw-r--r--spec/frontend/invite_members/components/invite_members_modal_spec.js30
-rw-r--r--spec/frontend/invite_members/components/invite_members_trigger_spec.js49
-rw-r--r--spec/frontend/invite_members/components/invite_modal_base_spec.js31
-rw-r--r--spec/frontend/invite_members/components/members_token_select_spec.js5
-rw-r--r--spec/frontend/invite_members/components/project_select_spec.js4
-rw-r--r--spec/frontend/invite_members/utils/trigger_successful_invite_alert_spec.js4
-rw-r--r--spec/frontend/issuable/components/csv_export_modal_spec.js18
-rw-r--r--spec/frontend/issuable/components/csv_import_export_buttons_spec.js6
-rw-r--r--spec/frontend/issuable/components/csv_import_modal_spec.js4
-rw-r--r--spec/frontend/issuable/components/issuable_by_email_spec.js2
-rw-r--r--spec/frontend/issuable/components/issuable_header_warnings_spec.js7
-rw-r--r--spec/frontend/issuable/components/issue_assignees_spec.js5
-rw-r--r--spec/frontend/issuable/components/issue_milestone_spec.js159
-rw-r--r--spec/frontend/issuable/components/related_issuable_item_spec.js4
-rw-r--r--spec/frontend/issuable/components/status_box_spec.js5
-rw-r--r--spec/frontend/issuable/popover/components/issue_popover_spec.js4
-rw-r--r--spec/frontend/issuable/popover/components/mr_popover_spec.js4
-rw-r--r--spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js243
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_block_spec.js14
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_root_spec.js5
-rw-r--r--spec/frontend/issues/create_merge_request_dropdown_spec.js8
-rw-r--r--spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js20
-rw-r--r--spec/frontend/issues/list/components/issue_card_time_info_spec.js4
-rw-r--r--spec/frontend/issues/list/components/issues_list_app_spec.js80
-rw-r--r--spec/frontend/issues/list/components/jira_issues_import_status_app_spec.js5
-rw-r--r--spec/frontend/issues/list/mock_data.js20
-rw-r--r--spec/frontend/issues/list/utils_spec.js5
-rw-r--r--spec/frontend/issues/new/components/title_suggestions_item_spec.js4
-rw-r--r--spec/frontend/issues/new/components/title_suggestions_spec.js123
-rw-r--r--spec/frontend/issues/new/components/type_popover_spec.js4
-rw-r--r--spec/frontend/issues/new/mock_data.js64
-rw-r--r--spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js1
-rw-r--r--spec/frontend/issues/related_merge_requests/store/actions_spec.js4
-rw-r--r--spec/frontend/issues/show/components/app_spec.js579
-rw-r--r--spec/frontend/issues/show/components/delete_issue_modal_spec.js4
-rw-r--r--spec/frontend/issues/show/components/description_spec.js182
-rw-r--r--spec/frontend/issues/show/components/edit_actions_spec.js4
-rw-r--r--spec/frontend/issues/show/components/edited_spec.js4
-rw-r--r--spec/frontend/issues/show/components/fields/description_spec.js28
-rw-r--r--spec/frontend/issues/show/components/fields/description_template_spec.js4
-rw-r--r--spec/frontend/issues/show/components/fields/title_spec.js5
-rw-r--r--spec/frontend/issues/show/components/fields/type_spec.js8
-rw-r--r--spec/frontend/issues/show/components/form_spec.js4
-rw-r--r--spec/frontend/issues/show/components/header_actions_spec.js47
-rw-r--r--spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js5
-rw-r--r--spec/frontend/issues/show/components/incidents/incident_tabs_spec.js55
-rw-r--r--spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js5
-rw-r--r--spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js8
-rw-r--r--spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js4
-rw-r--r--spec/frontend/issues/show/components/incidents/utils_spec.js4
-rw-r--r--spec/frontend/issues/show/components/locked_warning_spec.js5
-rw-r--r--spec/frontend/issues/show/components/task_list_item_actions_spec.js2
-rw-r--r--spec/frontend/issues/show/components/title_spec.js89
-rw-r--r--spec/frontend/issues/show/mock_data/mock_data.js57
-rw-r--r--spec/frontend/jira_connect/branches/components/new_branch_form_spec.js4
-rw-r--r--spec/frontend/jira_connect/branches/components/project_dropdown_spec.js4
-rw-r--r--spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js4
-rw-r--r--spec/frontend/jira_connect/branches/pages/index_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/api_spec.js3
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/add_namespace_button_spec.js6
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/add_namespace_modal_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/app_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/browser_support_alert_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/group_item_name_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/sign_in_legacy_button_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/user_link_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js4
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js4
-rw-r--r--spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap6
-rw-r--r--spec/frontend/jira_import/components/jira_import_app_spec.js5
-rw-r--r--spec/frontend/jira_import/components/jira_import_form_spec.js1
-rw-r--r--spec/frontend/jira_import/components/jira_import_progress_spec.js5
-rw-r--r--spec/frontend/jira_import/components/jira_import_setup_spec.js5
-rw-r--r--spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js4
-rw-r--r--spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js4
-rw-r--r--spec/frontend/jobs/components/job/artifacts_block_spec.js5
-rw-r--r--spec/frontend/jobs/components/job/commit_block_spec.js4
-rw-r--r--spec/frontend/jobs/components/job/environments_block_spec.js5
-rw-r--r--spec/frontend/jobs/components/job/erased_block_spec.js4
-rw-r--r--spec/frontend/jobs/components/job/job_app_spec.js3
-rw-r--r--spec/frontend/jobs/components/job/job_container_item_spec.js5
-rw-r--r--spec/frontend/jobs/components/job/job_log_controllers_spec.js12
-rw-r--r--spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js12
-rw-r--r--spec/frontend/jobs/components/job/jobs_container_spec.js4
-rw-r--r--spec/frontend/jobs/components/job/manual_variables_form_spec.js106
-rw-r--r--spec/frontend/jobs/components/job/mock_data.js27
-rw-r--r--spec/frontend/jobs/components/job/sidebar_detail_row_spec.js5
-rw-r--r--spec/frontend/jobs/components/job/sidebar_spec.js4
-rw-r--r--spec/frontend/jobs/components/job/stages_dropdown_spec.js4
-rw-r--r--spec/frontend/jobs/components/job/trigger_block_spec.js4
-rw-r--r--spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js4
-rw-r--r--spec/frontend/jobs/components/log/collapsible_section_spec.js4
-rw-r--r--spec/frontend/jobs/components/log/duration_badge_spec.js4
-rw-r--r--spec/frontend/jobs/components/log/line_header_spec.js4
-rw-r--r--spec/frontend/jobs/components/log/line_number_spec.js4
-rw-r--r--spec/frontend/jobs/components/log/log_spec.js15
-rw-r--r--spec/frontend/jobs/components/table/cells/duration_cell_spec.js4
-rw-r--r--spec/frontend/jobs/components/table/cells/job_cell_spec.js4
-rw-r--r--spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js4
-rw-r--r--spec/frontend/jobs/components/table/graphql/cache_config_spec.js19
-rw-r--r--spec/frontend/jobs/components/table/job_table_app_spec.js53
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_spec.js4
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_tabs_spec.js4
-rw-r--r--spec/frontend/jobs/mixins/delayed_job_mixin_spec.js5
-rw-r--r--spec/frontend/jobs/mock_data.js2
-rw-r--r--spec/frontend/labels/components/delete_label_modal_spec.js4
-rw-r--r--spec/frontend/labels/components/promote_label_modal_spec.js1
-rw-r--r--spec/frontend/language_switcher/components/app_spec.js4
-rw-r--r--spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js5
-rw-r--r--spec/frontend/lib/dompurify_spec.js14
-rw-r--r--spec/frontend/lib/utils/axios_startup_calls_spec.js7
-rw-r--r--spec/frontend/lib/utils/common_utils_spec.js8
-rw-r--r--spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js1
-rw-r--r--spec/frontend/lib/utils/confirm_via_gl_modal/confirm_modal_spec.js4
-rw-r--r--spec/frontend/lib/utils/datetime/timeago_utility_spec.js10
-rw-r--r--spec/frontend/lib/utils/error_message_spec.js65
-rw-r--r--spec/frontend/lib/utils/file_upload_spec.js22
-rw-r--r--spec/frontend/lib/utils/number_utility_spec.js29
-rw-r--r--spec/frontend/lib/utils/ref_validator_spec.js79
-rw-r--r--spec/frontend/lib/utils/text_markdown_spec.js62
-rw-r--r--spec/frontend/lib/utils/text_utility_spec.js32
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js8
-rw-r--r--spec/frontend/lib/utils/vuex_module_mappers_spec.js4
-rw-r--r--spec/frontend/locale/sprintf_spec.js11
-rw-r--r--spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js4
-rw-r--r--spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js6
-rw-r--r--spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js4
-rw-r--r--spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js7
-rw-r--r--spec/frontend/members/components/action_buttons/remove_member_button_spec.js6
-rw-r--r--spec/frontend/members/components/action_buttons/resend_invite_button_spec.js6
-rw-r--r--spec/frontend/members/components/action_dropdowns/leave_group_dropdown_item_spec.js6
-rw-r--r--spec/frontend/members/components/action_dropdowns/remove_member_dropdown_item_spec.js4
-rw-r--r--spec/frontend/members/components/action_dropdowns/user_action_dropdown_spec.js6
-rw-r--r--spec/frontend/members/components/app_spec.js1
-rw-r--r--spec/frontend/members/components/avatars/group_avatar_spec.js4
-rw-r--r--spec/frontend/members/components/avatars/invite_avatar_spec.js4
-rw-r--r--spec/frontend/members/components/avatars/user_avatar_spec.js4
-rw-r--r--spec/frontend/members/components/filter_sort/sort_dropdown_spec.js2
-rw-r--r--spec/frontend/members/components/members_tabs_spec.js4
-rw-r--r--spec/frontend/members/components/modals/leave_modal_spec.js4
-rw-r--r--spec/frontend/members/components/modals/remove_group_link_modal_spec.js5
-rw-r--r--spec/frontend/members/components/modals/remove_member_modal_spec.js4
-rw-r--r--spec/frontend/members/components/table/created_at_spec.js4
-rw-r--r--spec/frontend/members/components/table/expiration_datepicker_spec.js4
-rw-r--r--spec/frontend/members/components/table/member_action_buttons_spec.js4
-rw-r--r--spec/frontend/members/components/table/member_avatar_spec.js4
-rw-r--r--spec/frontend/members/components/table/member_source_spec.js6
-rw-r--r--spec/frontend/members/components/table/members_table_cell_spec.js5
-rw-r--r--spec/frontend/members/components/table/members_table_spec.js4
-rw-r--r--spec/frontend/members/components/table/role_dropdown_spec.js10
-rw-r--r--spec/frontend/members/index_spec.js3
-rw-r--r--spec/frontend/merge_conflicts/components/merge_conflict_resolver_app_spec.js4
-rw-r--r--spec/frontend/merge_conflicts/store/actions_spec.js6
-rw-r--r--spec/frontend/merge_request_spec.js4
-rw-r--r--spec/frontend/merge_request_tabs_spec.js2
-rw-r--r--spec/frontend/merge_requests/components/compare_app_spec.js4
-rw-r--r--spec/frontend/merge_requests/components/compare_dropdown_spec.js1
-rw-r--r--spec/frontend/milestones/components/delete_milestone_modal_spec.js8
-rw-r--r--spec/frontend/milestones/components/milestone_combobox_spec.js5
-rw-r--r--spec/frontend/milestones/components/promote_milestone_modal_spec.js8
-rw-r--r--spec/frontend/ml/experiment_tracking/components/__snapshots__/ml_candidate_spec.js.snap268
-rw-r--r--spec/frontend/ml/experiment_tracking/components/ml_candidate_spec.js47
-rw-r--r--spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js316
-rw-r--r--spec/frontend/ml/experiment_tracking/routes/candidates/show/__snapshots__/ml_candidates_show_spec.js.snap285
-rw-r--r--spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js47
-rw-r--r--spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js255
-rw-r--r--spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js52
-rw-r--r--spec/frontend/monitoring/components/charts/column_spec.js4
-rw-r--r--spec/frontend/monitoring/components/charts/gauge_spec.js5
-rw-r--r--spec/frontend/monitoring/components/charts/heatmap_spec.js4
-rw-r--r--spec/frontend/monitoring/components/charts/single_stat_spec.js4
-rw-r--r--spec/frontend/monitoring/components/charts/time_series_spec.js4
-rw-r--r--spec/frontend/monitoring/components/create_dashboard_modal_spec.js4
-rw-r--r--spec/frontend/monitoring/components/dashboard_actions_menu_spec.js5
-rw-r--r--spec/frontend/monitoring/components/dashboard_header_spec.js4
-rw-r--r--spec/frontend/monitoring/components/dashboard_panel_builder_spec.js2
-rw-r--r--spec/frontend/monitoring/components/dashboard_panel_spec.js16
-rw-r--r--spec/frontend/monitoring/components/dashboard_spec.js5
-rw-r--r--spec/frontend/monitoring/components/dashboard_url_time_spec.js4
-rw-r--r--spec/frontend/monitoring/components/graph_group_spec.js4
-rw-r--r--spec/frontend/monitoring/components/group_empty_state_spec.js4
-rw-r--r--spec/frontend/monitoring/components/refresh_button_spec.js1
-rw-r--r--spec/frontend/monitoring/components/variables/dropdown_field_spec.js6
-rw-r--r--spec/frontend/monitoring/components/variables/text_field_spec.js6
-rw-r--r--spec/frontend/monitoring/pages/panel_new_page_spec.js4
-rw-r--r--spec/frontend/monitoring/store/actions_spec.js11
-rw-r--r--spec/frontend/nav/components/new_nav_toggle_spec.js186
-rw-r--r--spec/frontend/nav/components/responsive_app_spec.js4
-rw-r--r--spec/frontend/nav/components/responsive_header_spec.js6
-rw-r--r--spec/frontend/nav/components/responsive_home_spec.js6
-rw-r--r--spec/frontend/nav/components/top_nav_app_spec.js4
-rw-r--r--spec/frontend/nav/components/top_nav_container_view_spec.js4
-rw-r--r--spec/frontend/nav/components/top_nav_dropdown_menu_spec.js4
-rw-r--r--spec/frontend/nav/components/top_nav_menu_sections_spec.js4
-rw-r--r--spec/frontend/nav/components/top_nav_new_dropdown_spec.js29
-rw-r--r--spec/frontend/notebook/cells/code_spec.js4
-rw-r--r--spec/frontend/notebook/cells/markdown_spec.js6
-rw-r--r--spec/frontend/notebook/cells/output/error_spec.js48
-rw-r--r--spec/frontend/notebook/cells/output/index_spec.js4
-rw-r--r--spec/frontend/notebook/cells/prompt_spec.js4
-rw-r--r--spec/frontend/notebook/index_spec.js6
-rw-r--r--spec/frontend/notebook/mock_data.js6
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js120
-rw-r--r--spec/frontend/notes/components/comment_type_dropdown_spec.js4
-rw-r--r--spec/frontend/notes/components/diff_discussion_header_spec.js4
-rw-r--r--spec/frontend/notes/components/discussion_actions_spec.js11
-rw-r--r--spec/frontend/notes/components/discussion_counter_spec.js3
-rw-r--r--spec/frontend/notes/components/discussion_filter_note_spec.js5
-rw-r--r--spec/frontend/notes/components/discussion_navigator_spec.js1
-rw-r--r--spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js4
-rw-r--r--spec/frontend/notes/components/discussion_notes_spec.js5
-rw-r--r--spec/frontend/notes/components/discussion_reply_placeholder_spec.js4
-rw-r--r--spec/frontend/notes/components/discussion_resolve_button_spec.js4
-rw-r--r--spec/frontend/notes/components/discussion_resolve_with_issue_button_spec.js4
-rw-r--r--spec/frontend/notes/components/email_participants_warning_spec.js5
-rw-r--r--spec/frontend/notes/components/note_actions/reply_button_spec.js5
-rw-r--r--spec/frontend/notes/components/note_actions/timeline_event_button_spec.js4
-rw-r--r--spec/frontend/notes/components/note_actions_spec.js7
-rw-r--r--spec/frontend/notes/components/note_attachment_spec.js5
-rw-r--r--spec/frontend/notes/components/note_body_spec.js4
-rw-r--r--spec/frontend/notes/components/note_edited_text_spec.js69
-rw-r--r--spec/frontend/notes/components/note_form_spec.js4
-rw-r--r--spec/frontend/notes/components/note_header_spec.js5
-rw-r--r--spec/frontend/notes/components/note_signed_out_widget_spec.js4
-rw-r--r--spec/frontend/notes/components/noteable_discussion_spec.js15
-rw-r--r--spec/frontend/notes/components/noteable_note_spec.js4
-rw-r--r--spec/frontend/notes/components/notes_activity_header_spec.js4
-rw-r--r--spec/frontend/notes/components/notes_app_spec.js3
-rw-r--r--spec/frontend/notes/components/toggle_replies_widget_spec.js4
-rw-r--r--spec/frontend/notes/deprecated_notes_spec.js1
-rw-r--r--spec/frontend/notes/stores/actions_spec.js26
-rw-r--r--spec/frontend/notifications/components/custom_notifications_modal_spec.js52
-rw-r--r--spec/frontend/notifications/components/notifications_dropdown_spec.js4
-rw-r--r--spec/frontend/observability/index_spec.js64
-rw-r--r--spec/frontend/observability/observability_app_spec.js144
-rw-r--r--spec/frontend/observability/skeleton_spec.js15
-rw-r--r--spec/frontend/operation_settings/components/metrics_settings_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/delete_image_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_alert_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js7
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/partial_cleanup_alert_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/status_alert_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js43
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js26
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/group_empty_state_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js20
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/project_empty_state_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js3
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/dependency_proxy/app_spec.js13
-rw-r--r--spec/frontend/packages_and_registries/dependency_proxy/components/manifest_list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/details/details_header_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_header_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_row_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/pages/details_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/harbor_registry/pages/tags_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/file_sha_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_history_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/terraform_installation_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js10
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap2
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_title_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js10
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js35
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js8
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js7
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js2
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/maven_installation_spec.js.snap3
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/pypi_installation_spec.js.snap10
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/composer_installation_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/conan_installation_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/dependency_row_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/file_sha_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/installation_title_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/installations_commands_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/maven_installation_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/npm_installation_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/nuget_installation_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/package_versions_list_spec.js80
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/pypi_installation_spec.js17
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js34
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/functional/delete_packages_spec.js8
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js9
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/publish_method_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/mock_data.js1
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/details_spec.js8
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/list_spec.js25
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/exceptions_input_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/packages_forwarding_settings_spec.js2
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/cleanup_image_tags_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_form_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js1
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js1
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/shared/components/cli_commands_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/shared/components/delete_package_modal_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/shared/components/package_path_spec.js7
-rw-r--r--spec/frontend/packages_and_registries/shared/components/packages_list_loader_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/shared/components/publish_method_spec.js5
-rw-r--r--spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/shared/components/registry_list_spec.js21
-rw-r--r--spec/frontend/packages_and_registries/shared/components/settings_block_spec.js4
-rw-r--r--spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js4
-rw-r--r--spec/frontend/pages/groups/new/components/app_spec.js25
-rw-r--r--spec/frontend/pages/groups/new/components/create_group_description_details_spec.js4
-rw-r--r--spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js8
-rw-r--r--spec/frontend/pages/import/history/components/import_error_details_spec.js11
-rw-r--r--spec/frontend/pages/import/history/components/import_history_app_spec.js11
-rw-r--r--spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js7
-rw-r--r--spec/frontend/pages/projects/forks/new/components/app_spec.js4
-rw-r--r--spec/frontend/pages/projects/forks/new/components/fork_form_spec.js7
-rw-r--r--spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js17
-rw-r--r--spec/frontend/pages/projects/graphs/code_coverage_spec.js11
-rw-r--r--spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js6
-rw-r--r--spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js8
-rw-r--r--spec/frontend/pages/projects/shared/permissions/components/project_feature_settings_spec.js5
-rw-r--r--spec/frontend/pages/projects/shared/permissions/components/project_setting_row_spec.js4
-rw-r--r--spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js5
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_alert_spec.js5
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_content_spec.js5
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_form_spec.js9
-rw-r--r--spec/frontend/pdf/index_spec.js4
-rw-r--r--spec/frontend/pdf/page_spec.js4
-rw-r--r--spec/frontend/performance_bar/components/add_request_spec.js4
-rw-r--r--spec/frontend/performance_bar/components/detailed_metric_spec.js4
-rw-r--r--spec/frontend/performance_bar/components/request_warning_spec.js4
-rw-r--r--spec/frontend/persistent_user_callout_spec.js4
-rw-r--r--spec/frontend/pipeline_wizard/components/commit_spec.js14
-rw-r--r--spec/frontend/pipeline_wizard/components/editor_spec.js4
-rw-r--r--spec/frontend/pipeline_wizard/components/input_wrapper_spec.js8
-rw-r--r--spec/frontend/pipeline_wizard/components/step_nav_spec.js4
-rw-r--r--spec/frontend/pipeline_wizard/components/widgets/checklist_spec.js4
-rw-r--r--spec/frontend/pipeline_wizard/components/widgets/list_spec.js8
-rw-r--r--spec/frontend/pipeline_wizard/components/wrapper_spec.js21
-rw-r--r--spec/frontend/pipeline_wizard/pipeline_wizard_spec.js4
-rw-r--r--spec/frontend/pipelines/components/dag/dag_annotations_spec.js5
-rw-r--r--spec/frontend/pipelines/components/dag/dag_graph_spec.js5
-rw-r--r--spec/frontend/pipelines/components/dag/dag_spec.js5
-rw-r--r--spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js8
-rw-r--r--spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js8
-rw-r--r--spec/frontend/pipelines/components/jobs/jobs_app_spec.js8
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list_spec.js12
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_mini_graph_spec.js15
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stage_spec.js5
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stages_spec.js5
-rw-r--r--spec/frontend/pipelines/components/pipeline_tabs_spec.js4
-rw-r--r--spec/frontend/pipelines/components/pipelines_filtered_search_spec.js2
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js5
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js5
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js5
-rw-r--r--spec/frontend/pipelines/empty_state_spec.js5
-rw-r--r--spec/frontend/pipelines/graph/action_component_spec.js1
-rw-r--r--spec/frontend/pipelines/graph/graph_component_wrapper_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/graph_view_selector_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/job_group_dropdown_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/job_item_spec.js47
-rw-r--r--spec/frontend/pipelines/graph/linked_pipeline_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/linked_pipelines_column_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/stage_column_component_spec.js4
-rw-r--r--spec/frontend/pipelines/graph_shared/links_inner_spec.js1
-rw-r--r--spec/frontend/pipelines/graph_shared/links_layer_spec.js4
-rw-r--r--spec/frontend/pipelines/header_component_spec.js5
-rw-r--r--spec/frontend/pipelines/nav_controls_spec.js37
-rw-r--r--spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js4
-rw-r--r--spec/frontend/pipelines/pipeline_labels_spec.js4
-rw-r--r--spec/frontend/pipelines/pipeline_multi_actions_spec.js2
-rw-r--r--spec/frontend/pipelines/pipeline_triggerer_spec.js6
-rw-r--r--spec/frontend/pipelines/pipeline_url_spec.js4
-rw-r--r--spec/frontend/pipelines/pipelines_actions_spec.js7
-rw-r--r--spec/frontend/pipelines/pipelines_artifacts_spec.js5
-rw-r--r--spec/frontend/pipelines/pipelines_spec.js5
-rw-r--r--spec/frontend/pipelines/pipelines_table_spec.js6
-rw-r--r--spec/frontend/pipelines/test_reports/stores/actions_spec.js6
-rw-r--r--spec/frontend/pipelines/test_reports/stores/mutations_spec.js6
-rw-r--r--spec/frontend/pipelines/test_reports/test_case_details_spec.js5
-rw-r--r--spec/frontend/pipelines/test_reports/test_reports_spec.js4
-rw-r--r--spec/frontend/pipelines/test_reports/test_suite_table_spec.js4
-rw-r--r--spec/frontend/pipelines/time_ago_spec.js5
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js5
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_status_token_spec.js5
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js5
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js5
-rw-r--r--spec/frontend/popovers/components/popovers_spec.js5
-rw-r--r--spec/frontend/profile/account/components/delete_account_modal_spec.js6
-rw-r--r--spec/frontend/profile/account/components/update_username_spec.js46
-rw-r--r--spec/frontend/profile/components/activity_calendar_spec.js120
-rw-r--r--spec/frontend/profile/components/followers_tab_spec.js21
-rw-r--r--spec/frontend/profile/components/following_tab_spec.js21
-rw-r--r--spec/frontend/profile/components/overview_tab_spec.js7
-rw-r--r--spec/frontend/profile/components/user_achievements_spec.js102
-rw-r--r--spec/frontend/profile/mock_data.js22
-rw-r--r--spec/frontend/profile/preferences/components/diffs_colors_preview_spec.js5
-rw-r--r--spec/frontend/profile/preferences/components/diffs_colors_spec.js5
-rw-r--r--spec/frontend/profile/preferences/components/integration_view_spec.js5
-rw-r--r--spec/frontend/profile/preferences/components/profile_preferences_spec.js9
-rw-r--r--spec/frontend/profile/utils_spec.js15
-rw-r--r--spec/frontend/projects/clusters_deprecation_slert/components/clusters_deprecation_alert_spec.js4
-rw-r--r--spec/frontend/projects/commit/components/branches_dropdown_spec.js4
-rw-r--r--spec/frontend/projects/commit/components/form_modal_spec.js3
-rw-r--r--spec/frontend/projects/commit/components/projects_dropdown_spec.js15
-rw-r--r--spec/frontend/projects/commit/store/actions_spec.js6
-rw-r--r--spec/frontend/projects/commits/components/author_select_spec.js1
-rw-r--r--spec/frontend/projects/commits/store/actions_spec.js8
-rw-r--r--spec/frontend/projects/compare/components/app_spec.js5
-rw-r--r--spec/frontend/projects/compare/components/repo_dropdown_spec.js5
-rw-r--r--spec/frontend/projects/compare/components/revision_card_spec.js5
-rw-r--r--spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js51
-rw-r--r--spec/frontend/projects/compare/components/revision_dropdown_spec.js48
-rw-r--r--spec/frontend/projects/components/project_delete_button_spec.js5
-rw-r--r--spec/frontend/projects/components/shared/delete_button_spec.js5
-rw-r--r--spec/frontend/projects/details/upload_button_spec.js4
-rw-r--r--spec/frontend/projects/new/components/app_spec.js29
-rw-r--r--spec/frontend/projects/new/components/deployment_target_select_spec.js1
-rw-r--r--spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js1
-rw-r--r--spec/frontend/projects/new/components/new_project_url_select_spec.js21
-rw-r--r--spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap29
-rw-r--r--spec/frontend/projects/pipelines/charts/components/app_spec.js4
-rw-r--r--spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_area_chart_spec.js5
-rw-r--r--spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js5
-rw-r--r--spec/frontend/projects/pipelines/charts/components/statistics_list_spec.js4
-rw-r--r--spec/frontend/projects/prune_unreachable_objects_button_spec.js7
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js8
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/index_spec.js4
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/protections/index_spec.js4
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/protections/merge_protections_spec.js4
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/edit/protections/push_protections_spec.js4
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/view/index_spec.js48
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js2
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js2
-rw-r--r--spec/frontend/projects/settings/components/default_branch_selector_spec.js4
-rw-r--r--spec/frontend/projects/settings/components/new_access_dropdown_spec.js20
-rw-r--r--spec/frontend/projects/settings/components/shared_runners_toggle_spec.js4
-rw-r--r--spec/frontend/projects/settings/components/transfer_project_form_spec.js4
-rw-r--r--spec/frontend/projects/settings/repository/branch_rules/app_spec.js6
-rw-r--r--spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js4
-rw-r--r--spec/frontend/projects/settings/repository/branch_rules/mock_data.js2
-rw-r--r--spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js1
-rw-r--r--spec/frontend/projects/settings/utils_spec.js24
-rw-r--r--spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js1
-rw-r--r--spec/frontend/projects/terraform_notification/terraform_notification_spec.js4
-rw-r--r--spec/frontend/protected_branches/protected_branch_edit_spec.js6
-rw-r--r--spec/frontend/ref/components/__snapshots__/ref_selector_spec.js.snap80
-rw-r--r--spec/frontend/ref/components/ref_selector_spec.js53
-rw-r--r--spec/frontend/releases/components/app_edit_new_spec.js7
-rw-r--r--spec/frontend/releases/components/app_index_spec.js12
-rw-r--r--spec/frontend/releases/components/app_show_spec.js15
-rw-r--r--spec/frontend/releases/components/asset_links_form_spec.js5
-rw-r--r--spec/frontend/releases/components/confirm_delete_modal_spec.js4
-rw-r--r--spec/frontend/releases/components/evidence_block_spec.js4
-rw-r--r--spec/frontend/releases/components/issuable_stats_spec.js5
-rw-r--r--spec/frontend/releases/components/release_block_footer_spec.js5
-rw-r--r--spec/frontend/releases/components/release_block_header_spec.js4
-rw-r--r--spec/frontend/releases/components/release_block_milestone_info_spec.js5
-rw-r--r--spec/frontend/releases/components/release_block_spec.js4
-rw-r--r--spec/frontend/releases/components/releases_pagination_spec.js4
-rw-r--r--spec/frontend/releases/components/releases_sort_spec.js4
-rw-r--r--spec/frontend/releases/components/tag_field_exsting_spec.js5
-rw-r--r--spec/frontend/releases/components/tag_field_new_spec.js8
-rw-r--r--spec/frontend/releases/components/tag_field_spec.js5
-rw-r--r--spec/frontend/releases/release_notification_service_spec.js8
-rw-r--r--spec/frontend/releases/stores/modules/detail/actions_spec.js20
-rw-r--r--spec/frontend/releases/stores/modules/detail/getters_spec.js81
-rw-r--r--spec/frontend/repository/commits_service_spec.js4
-rw-r--r--spec/frontend/repository/components/blob_button_group_spec.js4
-rw-r--r--spec/frontend/repository/components/blob_content_viewer_spec.js6
-rw-r--r--spec/frontend/repository/components/blob_controls_spec.js2
-rw-r--r--spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js2
-rw-r--r--spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js22
-rw-r--r--spec/frontend/repository/components/breadcrumbs_spec.js4
-rw-r--r--spec/frontend/repository/components/delete_blob_modal_spec.js8
-rw-r--r--spec/frontend/repository/components/directory_download_links_spec.js4
-rw-r--r--spec/frontend/repository/components/fork_info_spec.js137
-rw-r--r--spec/frontend/repository/components/fork_suggestion_spec.js2
-rw-r--r--spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js42
-rw-r--r--spec/frontend/repository/components/last_commit_spec.js33
-rw-r--r--spec/frontend/repository/components/new_directory_modal_spec.js12
-rw-r--r--spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap42
-rw-r--r--spec/frontend/repository/components/preview/index_spec.js93
-rw-r--r--spec/frontend/repository/components/table/index_spec.js4
-rw-r--r--spec/frontend/repository/components/table/parent_row_spec.js4
-rw-r--r--spec/frontend/repository/components/table/row_spec.js6
-rw-r--r--spec/frontend/repository/components/tree_content_spec.js50
-rw-r--r--spec/frontend/repository/components/upload_blob_modal_spec.js52
-rw-r--r--spec/frontend/repository/mixins/highlight_mixin_spec.js2
-rw-r--r--spec/frontend/repository/mock_data.js6
-rw-r--r--spec/frontend/repository/pages/blob_spec.js4
-rw-r--r--spec/frontend/repository/pages/index_spec.js2
-rw-r--r--spec/frontend/repository/pages/tree_spec.js2
-rw-r--r--spec/frontend/saved_replies/components/__snapshots__/list_item_spec.js.snap48
-rw-r--r--spec/frontend/saved_replies/components/form_spec.js144
-rw-r--r--spec/frontend/saved_replies/components/list_item_spec.js36
-rw-r--r--spec/frontend/saved_replies/components/list_spec.js48
-rw-r--r--spec/frontend/saved_replies/pages/index_spec.js45
-rw-r--r--spec/frontend/search/mock_data.js7
-rw-r--r--spec/frontend/search/sidebar/components/app_spec.js34
-rw-r--r--spec/frontend/search/sidebar/components/checkbox_filter_spec.js9
-rw-r--r--spec/frontend/search/sidebar/components/filters_spec.js21
-rw-r--r--spec/frontend/search/sidebar/components/language_filter_spec.js173
-rw-r--r--spec/frontend/search/sidebar/components/language_filters_spec.js152
-rw-r--r--spec/frontend/search/sidebar/components/radio_filter_spec.js10
-rw-r--r--spec/frontend/search/sidebar/components/scope_navigation_spec.js39
-rw-r--r--spec/frontend/search/sort/components/app_spec.js5
-rw-r--r--spec/frontend/search/store/actions_spec.js48
-rw-r--r--spec/frontend/search/store/getters_spec.js47
-rw-r--r--spec/frontend/search/store/utils_spec.js35
-rw-r--r--spec/frontend/search/topbar/components/app_spec.js4
-rw-r--r--spec/frontend/search/topbar/components/group_filter_spec.js4
-rw-r--r--spec/frontend/search/topbar/components/project_filter_spec.js4
-rw-r--r--spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js4
-rw-r--r--spec/frontend/search/topbar/components/searchable_dropdown_spec.js49
-rw-r--r--spec/frontend/search_autocomplete_spec.js1
-rw-r--r--spec/frontend/search_settings/components/search_settings_spec.js4
-rw-r--r--spec/frontend/security_configuration/components/app_spec.js30
-rw-r--r--spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js4
-rw-r--r--spec/frontend/security_configuration/components/auto_dev_ops_enabled_alert_spec.js4
-rw-r--r--spec/frontend/security_configuration/components/feature_card_spec.js6
-rw-r--r--spec/frontend/security_configuration/components/training_provider_list_spec.js3
-rw-r--r--spec/frontend/security_configuration/components/upgrade_banner_spec.js1
-rw-r--r--spec/frontend/security_configuration/constants.js1
-rw-r--r--spec/frontend/self_monitor/components/__snapshots__/self_monitor_form_spec.js.snap35
-rw-r--r--spec/frontend/sentry/index_spec.js7
-rw-r--r--spec/frontend/sentry/legacy_index_spec.js7
-rw-r--r--spec/frontend/sentry/sentry_config_spec.js7
-rw-r--r--spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js7
-rw-r--r--spec/frontend/set_status_modal/user_profile_set_status_wrapper_spec.js4
-rw-r--r--spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js4
-rw-r--r--spec/frontend/sidebar/components/assignees/assignee_avatar_spec.js7
-rw-r--r--spec/frontend/sidebar/components/assignees/assignee_title_spec.js5
-rw-r--r--spec/frontend/sidebar/components/assignees/assignees_realtime_spec.js1
-rw-r--r--spec/frontend/sidebar/components/assignees/assignees_spec.js4
-rw-r--r--spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js4
-rw-r--r--spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js4
-rw-r--r--spec/frontend/sidebar/components/assignees/issuable_assignees_spec.js5
-rw-r--r--spec/frontend/sidebar/components/assignees/sidebar_assignees_spec.js3
-rw-r--r--spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js11
-rw-r--r--spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js5
-rw-r--r--spec/frontend/sidebar/components/assignees/sidebar_invite_members_spec.js4
-rw-r--r--spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js10
-rw-r--r--spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js4
-rw-r--r--spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js4
-rw-r--r--spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js4
-rw-r--r--spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js12
-rw-r--r--spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js7
-rw-r--r--spec/frontend/sidebar/components/copy/copyable_field_spec.js4
-rw-r--r--spec/frontend/sidebar/components/copy/sidebar_reference_widget_spec.js8
-rw-r--r--spec/frontend/sidebar/components/crm_contacts/crm_contacts_spec.js5
-rw-r--r--spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js15
-rw-r--r--spec/frontend/sidebar/components/date/sidebar_formatted_date_spec.js4
-rw-r--r--spec/frontend/sidebar/components/date/sidebar_inherit_date_spec.js4
-rw-r--r--spec/frontend/sidebar/components/incidents/escalation_status_spec.js4
-rw-r--r--spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js6
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_button_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js16
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_title_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_collapsed_spec.js6
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/label_item_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/labels_select_root_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/store/actions_spec.js8
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js10
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view_spec.js8
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_header_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/embedded_labels_list_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/label_item_spec.js4
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js20
-rw-r--r--spec/frontend/sidebar/components/lock/edit_form_buttons_spec.js13
-rw-r--r--spec/frontend/sidebar/components/lock/edit_form_spec.js5
-rw-r--r--spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js7
-rw-r--r--spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js4
-rw-r--r--spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js1
-rw-r--r--spec/frontend/sidebar/components/move/move_issue_button_spec.js6
-rw-r--r--spec/frontend/sidebar/components/move/move_issues_button_spec.js21
-rw-r--r--spec/frontend/sidebar/components/participants/participants_spec.js197
-rw-r--r--spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js1
-rw-r--r--spec/frontend/sidebar/components/reviewers/reviewer_title_spec.js5
-rw-r--r--spec/frontend/sidebar/components/reviewers/reviewers_spec.js4
-rw-r--r--spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js3
-rw-r--r--spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js4
-rw-r--r--spec/frontend/sidebar/components/severity/sidebar_severity_spec.js13
-rw-r--r--spec/frontend/sidebar/components/sidebar_dropdown_spec.js4
-rw-r--r--spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js11
-rw-r--r--spec/frontend/sidebar/components/status/status_dropdown_spec.js4
-rw-r--r--spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js7
-rw-r--r--spec/frontend/sidebar/components/subscriptions/subscriptions_dropdown_spec.js4
-rw-r--r--spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js5
-rw-r--r--spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js4
-rw-r--r--spec/frontend/sidebar/components/time_tracking/report_spec.js5
-rw-r--r--spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js6
-rw-r--r--spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js7
-rw-r--r--spec/frontend/sidebar/components/todo_toggle/todo_button_spec.js1
-rw-r--r--spec/frontend/sidebar/components/todo_toggle/todo_spec.js4
-rw-r--r--spec/frontend/sidebar/components/toggle/toggle_sidebar_spec.js4
-rw-r--r--spec/frontend/sidebar/mock_data.js1
-rw-r--r--spec/frontend/sidebar/sidebar_mediator_spec.js2
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap3
-rw-r--r--spec/frontend/snippets/components/edit_spec.js21
-rw-r--r--spec/frontend/snippets/components/embed_dropdown_spec.js5
-rw-r--r--spec/frontend/snippets/components/show_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js5
-rw-r--r--spec/frontend/snippets/components/snippet_blob_edit_spec.js8
-rw-r--r--spec/frontend/snippets/components/snippet_blob_view_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_description_edit_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_description_view_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_header_spec.js136
-rw-r--r--spec/frontend/snippets/components/snippet_title_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_visibility_edit_spec.js4
-rw-r--r--spec/frontend/snippets/mock_data.js19
-rw-r--r--spec/frontend/streaming/chunk_writer_spec.js214
-rw-r--r--spec/frontend/streaming/handle_streamed_anchor_link_spec.js132
-rw-r--r--spec/frontend/streaming/html_stream_spec.js46
-rw-r--r--spec/frontend/streaming/rate_limit_stream_requests_spec.js155
-rw-r--r--spec/frontend/streaming/render_balancer_spec.js69
-rw-r--r--spec/frontend/streaming/render_html_streams_spec.js96
-rw-r--r--spec/frontend/super_sidebar/components/context_switcher_spec.js219
-rw-r--r--spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js50
-rw-r--r--spec/frontend/super_sidebar/components/frequent_items_list_spec.js68
-rw-r--r--spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js238
-rw-r--r--spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js102
-rw-r--r--spec/frontend/super_sidebar/components/global_search/components/global_search_scoped_items_spec.js120
-rw-r--r--spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js516
-rw-r--r--spec/frontend/super_sidebar/components/global_search/mock_data.js404
-rw-r--r--spec/frontend/super_sidebar/components/global_search/store/actions_spec.js113
-rw-r--r--spec/frontend/super_sidebar/components/global_search/store/getters_spec.js333
-rw-r--r--spec/frontend/super_sidebar/components/global_search/store/mutations_spec.js63
-rw-r--r--spec/frontend/super_sidebar/components/groups_list_spec.js87
-rw-r--r--spec/frontend/super_sidebar/components/help_center_spec.js11
-rw-r--r--spec/frontend/super_sidebar/components/items_list_spec.js63
-rw-r--r--spec/frontend/super_sidebar/components/nav_item_spec.js49
-rw-r--r--spec/frontend/super_sidebar/components/projects_list_spec.js82
-rw-r--r--spec/frontend/super_sidebar/components/search_results_spec.js57
-rw-r--r--spec/frontend/super_sidebar/components/sidebar_portal_spec.js68
-rw-r--r--spec/frontend/super_sidebar/components/super_sidebar_spec.js27
-rw-r--r--spec/frontend/super_sidebar/components/user_bar_spec.js31
-rw-r--r--spec/frontend/super_sidebar/components/user_menu_spec.js375
-rw-r--r--spec/frontend/super_sidebar/components/user_name_group_spec.js100
-rw-r--r--spec/frontend/super_sidebar/mock_data.js187
-rw-r--r--spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js157
-rw-r--r--spec/frontend/super_sidebar/utils_spec.js160
-rw-r--r--spec/frontend/syntax_highlight_spec.js6
-rw-r--r--spec/frontend/tags/components/delete_tag_modal_spec.js4
-rw-r--r--spec/frontend/terms/components/app_spec.js4
-rw-r--r--spec/frontend/terraform/components/empty_state_spec.js4
-rw-r--r--spec/frontend/terraform/components/init_command_modal_spec.js4
-rw-r--r--spec/frontend/terraform/components/states_table_actions_spec.js8
-rw-r--r--spec/frontend/terraform/components/states_table_spec.js7
-rw-r--r--spec/frontend/terraform/components/terraform_list_spec.js5
-rw-r--r--spec/frontend/toggles/index_spec.js1
-rw-r--r--spec/frontend/token_access/inbound_token_access_spec.js4
-rw-r--r--spec/frontend/token_access/opt_in_jwt_spec.js4
-rw-r--r--spec/frontend/token_access/outbound_token_access_spec.js4
-rw-r--r--spec/frontend/token_access/token_access_app_spec.js14
-rw-r--r--spec/frontend/token_access/token_projects_table_spec.js38
-rw-r--r--spec/frontend/tooltips/components/tooltips_spec.js5
-rw-r--r--spec/frontend/usage_quotas/components/usage_quotas_app_spec.js4
-rw-r--r--spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js4
-rw-r--r--spec/frontend/usage_quotas/storage/components/project_storage_detail_spec.js3
-rw-r--r--spec/frontend/usage_quotas/storage/components/storage_type_icon_spec.js4
-rw-r--r--spec/frontend/usage_quotas/storage/components/usage_graph_spec.js4
-rw-r--r--spec/frontend/user_lists/components/user_lists_spec.js5
-rw-r--r--spec/frontend/user_lists/components/user_lists_table_spec.js4
-rw-r--r--spec/frontend/user_popovers_spec.js11
-rw-r--r--spec/frontend/validators/length_validator_spec.js91
-rw-r--r--spec/frontend/vue_compat_test_setup.js60
-rw-r--r--spec/frontend/vue_merge_request_widget/components/action_buttons.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/added_commit_message_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js221
-rw-r--r--spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js21
-rw-r--r--spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js1
-rw-r--r--spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/extensions/child_content_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/components/extensions/status_icon_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_alert_message_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_author_spec.js1
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_container_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js78
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_related_links_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_status_icon_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/review_app_link_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/commit_edit_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_archived_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_checking_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_commits_header_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_failed_to_merge_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_merging_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_missing_branch_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_not_allowed_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge_spec.js62
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_sha_mismatch_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions_spec.js8
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/new_ready_to_merge_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/action_buttons_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_action_button_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_list_spec.js1
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js1
-rw-r--r--spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js1
-rw-r--r--spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js1
-rw-r--r--spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js1
-rw-r--r--spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js5
-rw-r--r--spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js136
-rw-r--r--spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js2
-rw-r--r--spec/frontend/vue_shared/alert_details/alert_management_sidebar_todo_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap40
-rw-r--r--spec/frontend/vue_shared/components/actions_button_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/alert_details_table_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/awards_list_spec.js10
-rw-r--r--spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/changed_file_icon_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/chronic_duration_input_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/ci_badge_link_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/ci_icon_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/clipboard_button_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/clone_dropdown_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/code_block_highlighted_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/code_block_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/color_picker/color_picker_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js10
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/commit_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/confidentiality_badge_spec.js17
-rw-r--r--spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/confirm_danger/confirm_danger_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/confirm_fork_modal_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/confirm_modal_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/content_transition_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/date_time_picker/date_time_picker_input_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/deployment_instance/deployment_instance_spec.js12
-rw-r--r--spec/frontend/vue_shared/components/design_management/design_note_pin_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/dismissible_alert_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/dismissible_container_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/dismissible_feedback_alert_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/dom_element_listener_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js9
-rw-r--r--spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/ensure_data_spec.js1
-rw-r--r--spec/frontend/vue_shared/components/entity_select/project_select_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/expand_button_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/file_finder/item_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/file_icon_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/file_row_header_spec.js28
-rw-r--r--spec/frontend/vue_shared/components/file_row_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/file_tree_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js22
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js97
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_contact_token_spec.js7
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_organization_token_spec.js7
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js86
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js139
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js108
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js126
-rw-r--r--spec/frontend/vue_shared/components/form/form_footer_actions_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/form/title_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/gl_countdown_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/header_ci_component_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/help_popover_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/integration_help_text_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/keep_alive_slots_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/listbox_input/listbox_input_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/local_storage_sync_spec.js1
-rw-r--r--spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/markdown/drawio_toolbar_button_spec.js66
-rw-r--r--spec/frontend/vue_shared/components/markdown/editor_mode_dropdown_spec.js10
-rw-r--r--spec/frontend/vue_shared/components/markdown/field_view_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/markdown/header_spec.js26
-rw-r--r--spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js193
-rw-r--r--spec/frontend/vue_shared/components/markdown/saved_replies_dropdown_spec.js62
-rw-r--r--spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/markdown/toolbar_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/memory_graph_spec.js20
-rw-r--r--spec/frontend/vue_shared/components/metric_images/store/actions_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/modal_copy_button_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/navigation_tabs_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/new_resource_dropdown/new_resource_dropdown_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/notes/noteable_warning_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/notes/placeholder_note_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/notes/placeholder_system_note_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/notes/system_note_spec.js1
-rw-r--r--spec/frontend/vue_shared/components/notes/timeline_entry_item_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/ordered_layout_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/page_size_selector_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/paginated_list_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js63
-rw-r--r--spec/frontend/vue_shared/components/pagination_bar/pagination_bar_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/pagination_links_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/panel_resizer_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/papa_parse_alert_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/project_avatar_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/project_selector/project_list_item_spec.js136
-rw-r--r--spec/frontend/vue_shared/components/project_selector/project_selector_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/registry/code_instruction_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/registry/details_row_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/registry/history_item_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/registry/list_item_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/registry/metadata_item_spec.js7
-rw-r--r--spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/registry/registry_search_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/registry/title_area_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap23
-rw-r--r--spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js64
-rw-r--r--spec/frontend/vue_shared/components/rich_timestamp_tooltip_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/security_reports/artifact_downloads/merge_request_artifact_download_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/security_reports/help_icon_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/security_reports/security_summary_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/segmented_control_button_group_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/settings/settings_block_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/smart_virtual_list_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/source_editor_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/components/chunk_deprecated_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/components/chunk_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/source_viewer_deprecated_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/stacked_progress_bar_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/table_pagination_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/time_ago_tooltip_spec.js1
-rw-r--r--spec/frontend/vue_shared/components/timezone_dropdown/timezone_dropdown_spec.js36
-rw-r--r--spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js30
-rw-r--r--spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap14
-rw-r--r--spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js7
-rw-r--r--spec/frontend/vue_shared/components/url_sync_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/usage_quotas/usage_banner_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/user_callout_dismisser_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/user_popover/user_popover_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/user_select_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/vuex_module_provider_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/web_ide_link_spec.js4
-rw-r--r--spec/frontend/vue_shared/directives/validation_spec.js5
-rw-r--r--spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js4
-rw-r--r--spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js4
-rw-r--r--spec/frontend/vue_shared/issuable/create/components/issuable_label_selector_spec.js15
-rw-r--r--spec/frontend/vue_shared/issuable/issuable_blocked_icon_spec.js20
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_bulk_edit_sidebar_spec.js1
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js6
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_list_root_spec.js4
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js1
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_body_spec.js6
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_description_spec.js4
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_edit_form_spec.js3
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js1
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_show_root_spec.js4
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_title_spec.js28
-rw-r--r--spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js1
-rw-r--r--spec/frontend/vue_shared/new_namespace/components/legacy_container_spec.js2
-rw-r--r--spec/frontend/vue_shared/new_namespace/components/welcome_spec.js2
-rw-r--r--spec/frontend/vue_shared/new_namespace/new_namespace_page_spec.js9
-rw-r--r--spec/frontend/vue_shared/plugins/global_toast_spec.js22
-rw-r--r--spec/frontend/vue_shared/security_configuration/components/section_layout_spec.js4
-rw-r--r--spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js4
-rw-r--r--spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js5
-rw-r--r--spec/frontend/vue_shared/security_reports/security_reports_app_spec.js8
-rw-r--r--spec/frontend/webhooks/components/form_url_app_spec.js4
-rw-r--r--spec/frontend/whats_new/components/app_spec.js3
-rw-r--r--spec/frontend/whats_new/components/feature_spec.js5
-rw-r--r--spec/frontend/whats_new/utils/get_drawer_body_height_spec.js4
-rw-r--r--spec/frontend/work_items/components/app_spec.js4
-rw-r--r--spec/frontend/work_items/components/item_state_spec.js4
-rw-r--r--spec/frontend/work_items/components/item_title_spec.js4
-rw-r--r--spec/frontend/work_items/components/notes/__snapshots__/work_item_note_replying_spec.js.snap2
-rw-r--r--spec/frontend/work_items/components/notes/activity_filter_spec.js74
-rw-r--r--spec/frontend/work_items/components/notes/work_item_activity_sort_filter_spec.js109
-rw-r--r--spec/frontend/work_items/components/notes/work_item_discussion_spec.js26
-rw-r--r--spec/frontend/work_items/components/notes/work_item_history_only_filter_note_spec.js44
-rw-r--r--spec/frontend/work_items/components/notes/work_item_note_actions_spec.js98
-rw-r--r--spec/frontend/work_items/components/notes/work_item_note_spec.js12
-rw-r--r--spec/frontend/work_items/components/notes/work_item_notes_activity_header_spec.js63
-rw-r--r--spec/frontend/work_items/components/work_item_actions_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_assignees_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_description_rendered_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_description_spec.js9
-rw-r--r--spec/frontend/work_items/components/work_item_detail_modal_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_detail_spec.js49
-rw-r--r--spec/frontend/work_items/components/work_item_due_date_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_labels_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_links/okr_actions_split_button_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js34
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_spec.js13
-rw-r--r--spec/frontend/work_items/components/work_item_notes_spec.js71
-rw-r--r--spec/frontend/work_items/components/work_item_state_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_title_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_type_icon_spec.js6
-rw-r--r--spec/frontend/work_items/mock_data.js236
-rw-r--r--spec/frontend/work_items/pages/create_work_item_spec.js24
-rw-r--r--spec/frontend/work_items/pages/work_item_root_spec.js4
-rw-r--r--spec/frontend/work_items/router_spec.js2
-rw-r--r--spec/frontend/work_items_hierarchy/components/app_spec.js4
-rw-r--r--spec/frontend/work_items_hierarchy/components/hierarchy_spec.js4
-rw-r--r--spec/frontend/zen_mode_spec.js29
-rw-r--r--spec/frontend_integration/content_editor/content_editor_integration_spec.js4
-rw-r--r--spec/frontend_integration/ide/ide_integration_spec.js1
-rw-r--r--spec/frontend_integration/ide/user_opens_file_spec.js1
-rw-r--r--spec/frontend_integration/ide/user_opens_ide_spec.js1
-rw-r--r--spec/frontend_integration/ide/user_opens_mr_spec.js1
-rw-r--r--spec/graphql/mutations/achievements/award_spec.rb53
-rw-r--r--spec/graphql/mutations/achievements/revoke_spec.rb57
-rw-r--r--spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb1
-rw-r--r--spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb1
-rw-r--r--spec/graphql/mutations/alert_management/create_alert_issue_spec.rb2
-rw-r--r--spec/graphql/mutations/alert_management/update_alert_status_spec.rb1
-rw-r--r--spec/graphql/mutations/members/bulk_update_base_spec.rb16
-rw-r--r--spec/graphql/mutations/release_asset_links/create_spec.rb2
-rw-r--r--spec/graphql/mutations/release_asset_links/delete_spec.rb14
-rw-r--r--spec/graphql/mutations/release_asset_links/update_spec.rb2
-rw-r--r--spec/graphql/resolvers/achievements/achievements_resolver_spec.rb34
-rw-r--r--spec/graphql/resolvers/ci/group_runners_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/project_runners_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/runners_resolver_spec.rb10
-rw-r--r--spec/graphql/resolvers/ci/variables_resolver_spec.rb2
-rw-r--r--spec/graphql/types/achievements/achievement_type_spec.rb1
-rw-r--r--spec/graphql/types/achievements/user_achievement_type_spec.rb24
-rw-r--r--spec/graphql/types/ci/job_type_spec.rb6
-rw-r--r--spec/graphql/types/ci/runner_machine_type_spec.rb18
-rw-r--r--spec/graphql/types/ci/runner_type_spec.rb8
-rw-r--r--spec/graphql/types/ci/variable_sort_enum_spec.rb2
-rw-r--r--spec/graphql/types/commit_signature_interface_spec.rb5
-rw-r--r--spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb2
-rw-r--r--spec/graphql/types/design_management/design_at_version_type_spec.rb2
-rw-r--r--spec/graphql/types/design_management/design_type_spec.rb7
-rw-r--r--spec/graphql/types/key_type_spec.rb2
-rw-r--r--spec/graphql/types/project_type_spec.rb2
-rw-r--r--spec/graphql/types/projects/fork_details_type_spec.rb2
-rw-r--r--spec/graphql/types/root_storage_statistics_type_spec.rb2
-rw-r--r--spec/graphql/types/user_type_spec.rb1
-rw-r--r--spec/graphql/types/work_items/available_export_fields_enum_spec.rb26
-rw-r--r--spec/graphql/types/work_items/widget_interface_spec.rb11
-rw-r--r--spec/graphql/types/work_items/widgets/notifications_type_spec.rb12
-rw-r--r--spec/graphql/types/work_items/widgets/notifications_update_input_type_spec.rb9
-rw-r--r--spec/helpers/admin/abuse_reports_helper_spec.rb24
-rw-r--r--spec/helpers/analytics/cycle_analytics_helper_spec.rb61
-rw-r--r--spec/helpers/application_settings_helper_spec.rb6
-rw-r--r--spec/helpers/artifacts_helper_spec.rb1
-rw-r--r--spec/helpers/ci/catalog/resources_helper_spec.rb33
-rw-r--r--spec/helpers/ci/pipeline_editor_helper_spec.rb2
-rw-r--r--spec/helpers/ci/pipelines_helper_spec.rb6
-rw-r--r--spec/helpers/ci/variables_helper_spec.rb2
-rw-r--r--spec/helpers/commits_helper_spec.rb36
-rw-r--r--spec/helpers/device_registration_helper_spec.rb37
-rw-r--r--spec/helpers/diff_helper_spec.rb59
-rw-r--r--spec/helpers/explore_helper_spec.rb2
-rw-r--r--spec/helpers/groups/observability_helper_spec.rb91
-rw-r--r--spec/helpers/groups_helper_spec.rb6
-rw-r--r--spec/helpers/ide_helper_spec.rb190
-rw-r--r--spec/helpers/issuables_helper_spec.rb25
-rw-r--r--spec/helpers/jira_connect_helper_spec.rb19
-rw-r--r--spec/helpers/markup_helper_spec.rb39
-rw-r--r--spec/helpers/nav/new_dropdown_helper_spec.rb71
-rw-r--r--spec/helpers/nav/top_nav_helper_spec.rb52
-rw-r--r--spec/helpers/notes_helper_spec.rb13
-rw-r--r--spec/helpers/packages_helper_spec.rb15
-rw-r--r--spec/helpers/plan_limits_helper_spec.rb29
-rw-r--r--spec/helpers/projects/settings/branch_rules_helper_spec.rb25
-rw-r--r--spec/helpers/projects_helper_spec.rb31
-rw-r--r--spec/helpers/registrations_helper_spec.rb16
-rw-r--r--spec/helpers/search_helper_spec.rb15
-rw-r--r--spec/helpers/sidebars_helper_spec.rb158
-rw-r--r--spec/helpers/sorting_helper_spec.rb54
-rw-r--r--spec/helpers/todos_helper_spec.rb12
-rw-r--r--spec/helpers/users/callouts_helper_spec.rb70
-rw-r--r--spec/helpers/users_helper_spec.rb58
-rw-r--r--spec/initializers/check_forced_decomposition_spec.rb6
-rw-r--r--spec/initializers/direct_upload_support_spec.rb4
-rw-r--r--spec/initializers/google_cloud_profiler_spec.rb87
-rw-r--r--spec/initializers/safe_session_store_patch_spec.rb62
-rw-r--r--spec/lib/api/entities/ssh_key_spec.rb2
-rw-r--r--spec/lib/api/helpers/internal_helpers_spec.rb60
-rw-r--r--spec/lib/api/helpers/packages_helpers_spec.rb3
-rw-r--r--spec/lib/api/helpers_spec.rb2
-rw-r--r--spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb21
-rw-r--r--spec/lib/atlassian/jira_connect_spec.rb2
-rw-r--r--spec/lib/atlassian/jira_issue_key_extractor_spec.rb2
-rw-r--r--spec/lib/backup/gitaly_backup_spec.rb11
-rw-r--r--spec/lib/banzai/filter/inline_observability_filter_spec.rb82
-rw-r--r--spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb123
-rw-r--r--spec/lib/banzai/filter/references/issue_reference_filter_spec.rb9
-rw-r--r--spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb9
-rw-r--r--spec/lib/banzai/filter/references/reference_cache_spec.rb3
-rw-r--r--spec/lib/bulk_imports/clients/http_spec.rb33
-rw-r--r--spec/lib/bulk_imports/features_spec.rb43
-rw-r--r--spec/lib/bulk_imports/groups/stage_spec.rb58
-rw-r--r--spec/lib/bulk_imports/ndjson_pipeline_spec.rb54
-rw-r--r--spec/lib/bulk_imports/projects/pipelines/ci_pipelines_pipeline_spec.rb8
-rw-r--r--spec/lib/bulk_imports/projects/pipelines/commit_notes_pipeline_spec.rb69
-rw-r--r--spec/lib/container_registry/gitlab_api_client_spec.rb202
-rw-r--r--spec/lib/error_tracking/collector/payload_validator_spec.rb2
-rw-r--r--spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb82
-rw-r--r--spec/lib/generators/batched_background_migration/expected_files/my_batched_migration.txt22
-rw-r--r--spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_dictionary_matcher.txt6
-rw-r--r--spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_spec_matcher.txt7
-rw-r--r--spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt28
-rw-r--r--spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration_spec.txt26
-rw-r--r--spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb26
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb4
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb26
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb4
-rw-r--r--spec/lib/gitlab/api_authentication/token_resolver_spec.rb2
-rw-r--r--spec/lib/gitlab/app_logger_spec.rb25
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb2
-rw-r--r--spec/lib/gitlab/audit/auditor_spec.rb33
-rw-r--r--spec/lib/gitlab/auth/auth_finders_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/o_auth/user_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/otp/strategies/duo_auth/manual_otp_spec.rb94
-rw-r--r--spec/lib/gitlab/auth_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_prepared_at_merge_requests_spec.rb57
-rw-r--r--spec/lib/gitlab/background_migration/backfill_project_wiki_repositories_spec.rb65
-rw-r--r--spec/lib/gitlab/background_migration/batched_migration_job_spec.rb22
-rw-r--r--spec/lib/gitlab/background_migration/delete_orphaned_packages_dependencies_spec.rb57
-rw-r--r--spec/lib/gitlab/background_migration/fix_vulnerability_reads_has_issues_spec.rb100
-rw-r--r--spec/lib/gitlab/background_migration/issues_internal_id_scope_updater_spec.rb90
-rw-r--r--spec/lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings_spec.rb136
-rw-r--r--spec/lib/gitlab/background_migration/migrate_links_for_vulnerability_findings_spec.rb141
-rw-r--r--spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb173
-rw-r--r--spec/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects_spec.rb3
-rw-r--r--spec/lib/gitlab/background_task_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/cache/client_spec.rb165
-rw-r--r--spec/lib/gitlab/changes_list_spec.rb2
-rw-r--r--spec/lib/gitlab/chat/responder_spec.rb68
-rw-r--r--spec/lib/gitlab/checks/changes_access_spec.rb12
-rw-r--r--spec/lib/gitlab/checks/diff_check_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/badge/release/template_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/build/auto_retry_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/context/build_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/hook_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/components/header_spec.rb50
-rw-r--r--spec/lib/gitlab/ci/components/instance_path_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/config/entry/policy_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/pull_policy_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/reports_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/trigger_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/context_spec.rb68
-rw-r--r--spec/lib/gitlab/ci/config/external/file/artifact_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/base_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/component_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/local_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/project_spec.rb32
-rw-r--r--spec/lib/gitlab/ci/config/external/file/remote_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/file/template_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper/base_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper/location_expander_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper/matcher_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper/normalizer_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper/variables_expander_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb288
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb13
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/rules_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/header/input_spec.rb70
-rw-r--r--spec/lib/gitlab/ci/config/header/root_spec.rb133
-rw-r--r--spec/lib/gitlab/ci/config/header/spec_spec.rb44
-rw-r--r--spec/lib/gitlab/ci/config/yaml/result_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/config/yaml_spec.rb45
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/input/arguments/base_spec.rb19
-rw-r--r--spec/lib/gitlab/ci/input/arguments/default_spec.rb45
-rw-r--r--spec/lib/gitlab/ci/input/arguments/options_spec.rb52
-rw-r--r--spec/lib/gitlab/ci/input/arguments/required_spec.rb41
-rw-r--r--spec/lib/gitlab/ci/input/arguments/unknown_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/input/inputs_spec.rb126
-rw-r--r--spec/lib/gitlab/ci/interpolation/access_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/interpolation/block_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/interpolation/config_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/interpolation/context_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/interpolation/template_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/lint_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/parsers/security/common_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/pipeline/duration_spec.rb156
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/project_config/repository_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/project_config/source_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb163
-rw-r--r--spec/lib/gitlab/ci/runner_releases_spec.rb32
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/build_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb34
-rw-r--r--spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/variables/builder_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/variables/collection_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/result_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb2
-rw-r--r--spec/lib/gitlab/color_schemes_spec.rb8
-rw-r--r--spec/lib/gitlab/config/entry/validators_spec.rb2
-rw-r--r--spec/lib/gitlab/config/loader/multi_doc_yaml_spec.rb198
-rw-r--r--spec/lib/gitlab/config/loader/yaml_spec.rb28
-rw-r--r--spec/lib/gitlab/console_spec.rb4
-rw-r--r--spec/lib/gitlab/content_security_policy/config_loader_spec.rb53
-rw-r--r--spec/lib/gitlab/database/async_constraints/migration_helpers_spec.rb288
-rw-r--r--spec/lib/gitlab/database/async_constraints/postgres_async_constraint_validation_spec.rb109
-rw-r--r--spec/lib/gitlab/database/async_constraints/validators/check_constraint_spec.rb20
-rw-r--r--spec/lib/gitlab/database/async_constraints/validators/foreign_key_spec.rb35
-rw-r--r--spec/lib/gitlab/database/async_constraints/validators_spec.rb21
-rw-r--r--spec/lib/gitlab/database/async_constraints_spec.rb29
-rw-r--r--spec/lib/gitlab/database/async_foreign_keys/foreign_key_validator_spec.rb152
-rw-r--r--spec/lib/gitlab/database/async_foreign_keys/migration_helpers_spec.rb167
-rw-r--r--spec/lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation_spec.rb52
-rw-r--r--spec/lib/gitlab/database/async_foreign_keys_spec.rb23
-rw-r--r--spec/lib/gitlab/database/background_migration/batch_optimizer_spec.rb9
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_job_spec.rb165
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb15
-rw-r--r--spec/lib/gitlab/database/gitlab_schema_spec.rb20
-rw-r--r--spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb35
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb110
-rw-r--r--spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb44
-rw-r--r--spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb35
-rw-r--r--spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb21
-rw-r--r--spec/lib/gitlab/database/partitioning/ci_sliding_list_strategy_spec.rb178
-rw-r--r--spec/lib/gitlab/database/partitioning/partition_manager_spec.rb27
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers_spec.rb122
-rw-r--r--spec/lib/gitlab/database/partitioning_spec.rb11
-rw-r--r--spec/lib/gitlab/database/postgres_foreign_key_spec.rb24
-rw-r--r--spec/lib/gitlab/database/postgres_partition_spec.rb14
-rw-r--r--spec/lib/gitlab/database/reindexing_spec.rb4
-rw-r--r--spec/lib/gitlab/database/schema_validation/database_spec.rb111
-rw-r--r--spec/lib/gitlab/database/schema_validation/index_spec.rb22
-rw-r--r--spec/lib/gitlab/database/schema_validation/indexes_spec.rb56
-rw-r--r--spec/lib/gitlab/database/schema_validation/runner_spec.rb50
-rw-r--r--spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb10
-rw-r--r--spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb10
-rw-r--r--spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb82
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb31
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/different_definition_indexes_spec.rb8
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/different_definition_triggers_spec.rb8
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb7
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/extra_triggers_spec.rb7
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb14
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/missing_triggers_spec.rb9
-rw-r--r--spec/lib/gitlab/database/tables_locker_spec.rb219
-rw-r--r--spec/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512_spec.rb11
-rw-r--r--spec/lib/gitlab/email/handler/create_issue_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/email/html_to_markdown_parser_spec.rb12
-rw-r--r--spec/lib/gitlab/email/message/build_ios_app_guide_spec.rb6
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/helper_spec.rb6
-rw-r--r--spec/lib/gitlab/endpoint_attributes_spec.rb7
-rw-r--r--spec/lib/gitlab/etag_caching/middleware_spec.rb7
-rw-r--r--spec/lib/gitlab/exception_log_formatter_spec.rb6
-rw-r--r--spec/lib/gitlab/external_authorization/config_spec.rb2
-rw-r--r--spec/lib/gitlab/file_finder_spec.rb126
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb3
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb20
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb54
-rw-r--r--spec/lib/gitlab/git_access_spec.rb2
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_service_spec.rb20
-rw-r--r--spec/lib/gitlab/gitaly_client/repository_service_spec.rb41
-rw-r--r--spec/lib/gitlab/github_import/client_spec.rb57
-rw-r--r--spec/lib/gitlab/github_import/clients/proxy_spec.rb123
-rw-r--r--spec/lib/gitlab/github_import/importer/collaborator_importer_spec.rb86
-rw-r--r--spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb119
-rw-r--r--spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb18
-rw-r--r--spec/lib/gitlab/github_import/importer/note_attachments_importer_spec.rb45
-rw-r--r--spec/lib/gitlab/github_import/markdown/attachment_spec.rb58
-rw-r--r--spec/lib/gitlab/github_import/parallel_scheduling_spec.rb89
-rw-r--r--spec/lib/gitlab/github_import/project_relation_type_spec.rb49
-rw-r--r--spec/lib/gitlab/github_import/representation/collaborator_spec.rb39
-rw-r--r--spec/lib/gitlab/i18n/pluralization_spec.rb53
-rw-r--r--spec/lib/gitlab/i18n_spec.rb17
-rw-r--r--spec/lib/gitlab/import/errors_spec.rb48
-rw-r--r--spec/lib/gitlab/import/metrics_spec.rb130
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml110
-rw-r--r--spec/lib/gitlab/import_export/attribute_configuration_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/attributes_finder_spec.rb15
-rw-r--r--spec/lib/gitlab/import_export/attributes_permitter_spec.rb22
-rw-r--r--spec/lib/gitlab/import_export/base/relation_object_saver_spec.rb30
-rw-r--r--spec/lib/gitlab/import_export/command_line_util_spec.rb61
-rw-r--r--spec/lib/gitlab/import_export/config_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb12
-rw-r--r--spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb79
-rw-r--r--spec/lib/gitlab/import_export/import_failure_service_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/json/legacy_writer_spec.rb3
-rw-r--r--spec/lib/gitlab/import_export/model_configuration_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project/import_task_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project/object_builder_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/project/tree_restorer_spec.rb19
-rw-r--r--spec/lib/gitlab/import_export/project/tree_saver_spec.rb31
-rw-r--r--spec/lib/gitlab/import_export/references_configuration_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml107
-rw-r--r--spec/lib/gitlab/instrumentation/redis_base_spec.rb12
-rw-r--r--spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb34
-rw-r--r--spec/lib/gitlab/internal_post_receive/response_spec.rb2
-rw-r--r--spec/lib/gitlab/issuable_sorter_spec.rb42
-rw-r--r--spec/lib/gitlab/jira_import/issues_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/kas/user_access_spec.rb96
-rw-r--r--spec/lib/gitlab/kroki_spec.rb2
-rw-r--r--spec/lib/gitlab/kubernetes/config_map_spec.rb16
-rw-r--r--spec/lib/gitlab/kubernetes/helm/pod_spec.rb2
-rw-r--r--spec/lib/gitlab/legacy_github_import/importer_spec.rb31
-rw-r--r--spec/lib/gitlab/loggable_spec.rb68
-rw-r--r--spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb3
-rw-r--r--spec/lib/gitlab/metrics/boot_time_tracker_spec.rb4
-rw-r--r--spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb27
-rw-r--r--spec/lib/gitlab/metrics/subscribers/rails_cache_spec.rb31
-rw-r--r--spec/lib/gitlab/monitor/demo_projects_spec.rb6
-rw-r--r--spec/lib/gitlab/multi_collection_paginator_spec.rb7
-rw-r--r--spec/lib/gitlab/nav/top_nav_menu_item_spec.rb3
-rw-r--r--spec/lib/gitlab/net_http_adapter_spec.rb3
-rw-r--r--spec/lib/gitlab/observability_spec.rb186
-rw-r--r--spec/lib/gitlab/optimistic_locking_spec.rb13
-rw-r--r--spec/lib/gitlab/pages/random_domain_spec.rb44
-rw-r--r--spec/lib/gitlab/pages/virtual_host_finder_spec.rb214
-rw-r--r--spec/lib/gitlab/patch/node_loader_spec.rb80
-rw-r--r--spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb31
-rw-r--r--spec/lib/gitlab/rack_attack/instrumented_cache_store_spec.rb89
-rw-r--r--spec/lib/gitlab/rack_attack/store_spec.rb113
-rw-r--r--spec/lib/gitlab/redis/cache_spec.rb17
-rw-r--r--spec/lib/gitlab/redis/multi_store_spec.rb219
-rw-r--r--spec/lib/gitlab/redis/rate_limiting_spec.rb15
-rw-r--r--spec/lib/gitlab/redis/repository_cache_spec.rb15
-rw-r--r--spec/lib/gitlab/regex_spec.rb31
-rw-r--r--spec/lib/gitlab/safe_device_detector_spec.rb2
-rw-r--r--spec/lib/gitlab/sanitizers/exception_message_spec.rb3
-rw-r--r--spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb24
-rw-r--r--spec/lib/gitlab/serverless/service_spec.rb136
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb2
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb8
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb6
-rw-r--r--spec/lib/gitlab/sidekiq_queue_spec.rb10
-rw-r--r--spec/lib/gitlab/slug/path_spec.rb2
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb99
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb22
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb119
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_ci_internal_pipelines_metric_spec.rb26
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric_spec.rb6
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric_spec.rb9
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric_spec.rb30
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric_spec.rb20
-rw-r--r--spec/lib/gitlab/usage_data_counters/code_review_events_spec.rb16
-rw-r--r--spec/lib/gitlab/usage_data_counters/container_registry_event_counter_spec.rb11
-rw-r--r--spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb21
-rw-r--r--spec/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter_spec.rb13
-rw-r--r--spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb142
-rw-r--r--spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb72
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb70
-rw-r--r--spec/lib/gitlab/utils/error_message_spec.rb23
-rw-r--r--spec/lib/gitlab/utils/strong_memoize_spec.rb2
-rw-r--r--spec/lib/gitlab/utils/uniquify_spec.rb44
-rw-r--r--spec/lib/gitlab/utils/usage_data_spec.rb4
-rw-r--r--spec/lib/gitlab/utils/username_and_email_generator_spec.rb24
-rw-r--r--spec/lib/object_storage/config_spec.rb9
-rw-r--r--spec/lib/security/weak_passwords_spec.rb2
-rw-r--r--spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb139
-rw-r--r--spec/lib/sidebars/groups/menus/group_information_menu_spec.rb6
-rw-r--r--spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb55
-rw-r--r--spec/lib/sidebars/groups/menus/issues_menu_spec.rb15
-rw-r--r--spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb11
-rw-r--r--spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb14
-rw-r--r--spec/lib/sidebars/groups/menus/observability_menu_spec.rb60
-rw-r--r--spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb4
-rw-r--r--spec/lib/sidebars/groups/menus/scope_menu_spec.rb16
-rw-r--r--spec/lib/sidebars/groups/super_sidebar_panel_spec.rb44
-rw-r--r--spec/lib/sidebars/menu_spec.rb79
-rw-r--r--spec/lib/sidebars/panel_spec.rb28
-rw-r--r--spec/lib/sidebars/projects/menus/deployments_menu_spec.rb6
-rw-r--r--spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb72
-rw-r--r--spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb52
-rw-r--r--spec/lib/sidebars/projects/menus/issues_menu_spec.rb15
-rw-r--r--spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb15
-rw-r--r--spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb6
-rw-r--r--spec/lib/sidebars/projects/menus/project_information_menu_spec.rb6
-rw-r--r--spec/lib/sidebars/projects/menus/repository_menu_spec.rb2
-rw-r--r--spec/lib/sidebars/projects/menus/scope_menu_spec.rb14
-rw-r--r--spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb4
-rw-r--r--spec/lib/sidebars/projects/menus/snippets_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/projects/menus/wiki_menu_spec.rb12
-rw-r--r--spec/lib/sidebars/projects/panel_spec.rb2
-rw-r--r--spec/lib/sidebars/projects/super_sidebar_menus/operations_menu_spec.rb12
-rw-r--r--spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb12
-rw-r--r--spec/lib/sidebars/projects/super_sidebar_panel_spec.rb45
-rw-r--r--spec/lib/sidebars/static_menu_spec.rb38
-rw-r--r--spec/lib/sidebars/uncategorized_menu_spec.rb12
-rw-r--r--spec/lib/sidebars/user_profile/menus/activity_menu_spec.rb11
-rw-r--r--spec/lib/sidebars/user_profile/menus/contributed_projects_menu_spec.rb11
-rw-r--r--spec/lib/sidebars/user_profile/menus/followers_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_profile/menus/following_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_profile/menus/groups_menu_spec.rb11
-rw-r--r--spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb11
-rw-r--r--spec/lib/sidebars/user_profile/menus/personal_projects_menu_spec.rb11
-rw-r--r--spec/lib/sidebars/user_profile/menus/snippets_menu_spec.rb11
-rw-r--r--spec/lib/sidebars/user_profile/menus/starred_projects_menu_spec.rb11
-rw-r--r--spec/lib/sidebars/user_profile/panel_spec.rb24
-rw-r--r--spec/lib/sidebars/user_settings/menus/access_tokens_menu_spec.rb65
-rw-r--r--spec/lib/sidebars/user_settings/menus/account_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/active_sessions_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/applications_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/authentication_log_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/chat_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/emails_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/gpg_keys_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/notifications_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/password_menu_spec.rb38
-rw-r--r--spec/lib/sidebars/user_settings/menus/preferences_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/profile_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/menus/saved_replies_menu_spec.rb65
-rw-r--r--spec/lib/sidebars/user_settings/menus/ssh_keys_menu_spec.rb13
-rw-r--r--spec/lib/sidebars/user_settings/panel_spec.rb15
-rw-r--r--spec/lib/sidebars/your_work/panel_spec.rb15
-rw-r--r--spec/lib/unnested_in_filters/rewriter_spec.rb26
-rw-r--r--spec/mailers/emails/in_product_marketing_spec.rb6
-rw-r--r--spec/mailers/emails/issues_spec.rb36
-rw-r--r--spec/mailers/emails/profile_spec.rb9
-rw-r--r--spec/mailers/emails/work_items_spec.rb17
-rw-r--r--spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb2
-rw-r--r--spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb2
-rw-r--r--spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb2
-rw-r--r--spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb2
-rw-r--r--spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb2
-rw-r--r--spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb2
-rw-r--r--spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb2
-rw-r--r--spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb25
-rw-r--r--spec/migrations/20230125195503_queue_backfill_compliance_violations_spec.rb32
-rw-r--r--spec/migrations/20230130182412_schedule_create_vulnerability_links_migration_spec.rb30
-rw-r--r--spec/migrations/20230202211434_migrate_redis_slot_keys_spec.rb54
-rw-r--r--spec/migrations/20230208125736_schedule_migration_for_links_spec.rb31
-rw-r--r--spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb43
-rw-r--r--spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb60
-rw-r--r--spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb22
-rw-r--r--spec/migrations/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress_spec.rb59
-rw-r--r--spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb93
-rw-r--r--spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb28
-rw-r--r--spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb31
-rw-r--r--spec/migrations/20230228142350_add_notifications_work_item_widget_spec.rb27
-rw-r--r--spec/migrations/20230302185739_queue_fix_vulnerability_reads_has_issues_spec.rb27
-rw-r--r--spec/migrations/20230303105806_queue_delete_orphaned_packages_dependencies_spec.rb26
-rw-r--r--spec/migrations/20230306195007_queue_backfill_project_wiki_repositories_spec.rb26
-rw-r--r--spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb24
-rw-r--r--spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb31
-rw-r--r--spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb2
-rw-r--r--spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb2
-rw-r--r--spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb37
-rw-r--r--spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb37
-rw-r--r--spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb2
-rw-r--r--spec/migrations/queue_backfill_prepared_at_data_spec.rb24
-rw-r--r--spec/migrations/swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com_spec.rb76
-rw-r--r--spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb66
-rw-r--r--spec/migrations/update_application_settings_protected_paths_spec.rb2
-rw-r--r--spec/models/abuse_report_spec.rb36
-rw-r--r--spec/models/achievements/user_achievement_spec.rb29
-rw-r--r--spec/models/airflow/dags_spec.rb17
-rw-r--r--spec/models/alert_management/alert_assignee_spec.rb6
-rw-r--r--spec/models/alert_management/alert_spec.rb10
-rw-r--r--spec/models/alert_management/alert_user_mention_spec.rb6
-rw-r--r--spec/models/application_setting_spec.rb113
-rw-r--r--spec/models/audit_event_spec.rb4
-rw-r--r--spec/models/board_spec.rb8
-rw-r--r--spec/models/bulk_import_spec.rb29
-rw-r--r--spec/models/bulk_imports/batch_tracker_spec.rb16
-rw-r--r--spec/models/bulk_imports/entity_spec.rb66
-rw-r--r--spec/models/bulk_imports/export_batch_spec.rb17
-rw-r--r--spec/models/bulk_imports/export_spec.rb3
-rw-r--r--spec/models/bulk_imports/file_transfer/project_config_spec.rb12
-rw-r--r--spec/models/bulk_imports/tracker_spec.rb5
-rw-r--r--spec/models/chat_name_spec.rb7
-rw-r--r--spec/models/ci/build_metadata_spec.rb1
-rw-r--r--spec/models/ci/build_pending_state_spec.rb7
-rw-r--r--spec/models/ci/build_spec.rb160
-rw-r--r--spec/models/ci/build_trace_chunk_spec.rb6
-rw-r--r--spec/models/ci/catalog/listing_spec.rb65
-rw-r--r--spec/models/ci/daily_build_group_report_result_spec.rb6
-rw-r--r--spec/models/ci/group_variable_spec.rb2
-rw-r--r--spec/models/ci/job_artifact_spec.rb25
-rw-r--r--spec/models/ci/job_token/scope_spec.rb8
-rw-r--r--spec/models/ci/job_variable_spec.rb2
-rw-r--r--spec/models/ci/pipeline_schedule_spec.rb17
-rw-r--r--spec/models/ci/pipeline_spec.rb217
-rw-r--r--spec/models/ci/processable_spec.rb2
-rw-r--r--spec/models/ci/runner_machine_build_spec.rb100
-rw-r--r--spec/models/ci/runner_machine_spec.rb200
-rw-r--r--spec/models/ci/runner_spec.rb235
-rw-r--r--spec/models/ci/runner_version_spec.rb11
-rw-r--r--spec/models/ci/sources/pipeline_spec.rb5
-rw-r--r--spec/models/ci/variable_spec.rb2
-rw-r--r--spec/models/clusters/applications/crossplane_spec.rb62
-rw-r--r--spec/models/clusters/applications/knative_spec.rb25
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb349
-rw-r--r--spec/models/clusters/cluster_spec.rb20
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb9
-rw-r--r--spec/models/commit_collection_spec.rb15
-rw-r--r--spec/models/commit_status_spec.rb39
-rw-r--r--spec/models/concerns/atomic_internal_id_spec.rb99
-rw-r--r--spec/models/concerns/ci/maskable_spec.rb2
-rw-r--r--spec/models/concerns/ci/partitionable/partitioned_filter_spec.rb80
-rw-r--r--spec/models/concerns/ci/partitionable_spec.rb10
-rw-r--r--spec/models/concerns/each_batch_spec.rb32
-rw-r--r--spec/models/concerns/has_user_type_spec.rb4
-rw-r--r--spec/models/concerns/redis_cacheable_spec.rb52
-rw-r--r--spec/models/concerns/routable_spec.rb11
-rw-r--r--spec/models/concerns/subscribable_spec.rb26
-rw-r--r--spec/models/concerns/token_authenticatable_strategies/base_spec.rb37
-rw-r--r--spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb149
-rw-r--r--spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb92
-rw-r--r--spec/models/concerns/uniquify_spec.rb44
-rw-r--r--spec/models/concerns/web_hooks/has_web_hooks_spec.rb41
-rw-r--r--spec/models/container_registry/data_repair_detail_spec.rb11
-rw-r--r--spec/models/container_registry/event_spec.rb22
-rw-r--r--spec/models/container_repository_spec.rb29
-rw-r--r--spec/models/design_management/design_spec.rb5
-rw-r--r--spec/models/error_tracking/project_error_tracking_setting_spec.rb38
-rw-r--r--spec/models/group_spec.rb14
-rw-r--r--spec/models/hooks/web_hook_spec.rb22
-rw-r--r--spec/models/import_export_upload_spec.rb2
-rw-r--r--spec/models/import_failure_spec.rb16
-rw-r--r--spec/models/integrations/apple_app_store_spec.rb5
-rw-r--r--spec/models/integrations/campfire_spec.rb14
-rw-r--r--spec/models/integrations/google_play_spec.rb81
-rw-r--r--spec/models/integrations/jira_spec.rb6
-rw-r--r--spec/models/integrations/mattermost_slash_commands_spec.rb9
-rw-r--r--spec/models/integrations/slack_slash_commands_spec.rb9
-rw-r--r--spec/models/integrations/squash_tm_spec.rb117
-rw-r--r--spec/models/internal_id_spec.rb12
-rw-r--r--spec/models/issue_spec.rb136
-rw-r--r--spec/models/member_spec.rb109
-rw-r--r--spec/models/members/member_role_spec.rb107
-rw-r--r--spec/models/members/project_member_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb41
-rw-r--r--spec/models/namespace_spec.rb412
-rw-r--r--spec/models/namespaces/randomized_suffix_path_spec.rb2
-rw-r--r--spec/models/note_spec.rb10
-rw-r--r--spec/models/oauth_access_token_spec.rb4
-rw-r--r--spec/models/onboarding/completion_spec.rb73
-rw-r--r--spec/models/packages/debian/file_metadatum_spec.rb1
-rw-r--r--spec/models/packages/package_file_spec.rb1
-rw-r--r--spec/models/pages/lookup_path_spec.rb69
-rw-r--r--spec/models/pages_domain_spec.rb39
-rw-r--r--spec/models/personal_access_token_spec.rb24
-rw-r--r--spec/models/preloaders/runner_machine_policy_preloader_spec.rb38
-rw-r--r--spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb16
-rw-r--r--spec/models/project_ci_cd_setting_spec.rb18
-rw-r--r--spec/models/project_feature_spec.rb34
-rw-r--r--spec/models/project_setting_spec.rb38
-rw-r--r--spec/models/project_spec.rb353
-rw-r--r--spec/models/projects/data_transfer_spec.rb6
-rw-r--r--spec/models/projects/forks/details_spec.rb162
-rw-r--r--spec/models/projects/forks/divergence_counts_spec.rb98
-rw-r--r--spec/models/projects/import_export/relation_export_spec.rb22
-rw-r--r--spec/models/protected_branch_spec.rb85
-rw-r--r--spec/models/repository_spec.rb119
-rw-r--r--spec/models/serverless/domain_cluster_spec.rb75
-rw-r--r--spec/models/serverless/domain_spec.rb97
-rw-r--r--spec/models/serverless/function_spec.rb21
-rw-r--r--spec/models/service_desk/custom_email_verification_spec.rb109
-rw-r--r--spec/models/service_desk_setting_spec.rb57
-rw-r--r--spec/models/user_spec.rb229
-rw-r--r--spec/models/wiki_directory_spec.rb9
-rw-r--r--spec/models/wiki_page_spec.rb14
-rw-r--r--spec/models/work_item_spec.rb24
-rw-r--r--spec/models/work_items/widget_definition_spec.rb3
-rw-r--r--spec/models/work_items/widgets/notifications_spec.rb19
-rw-r--r--spec/policies/ci/pipeline_schedule_policy_spec.rb2
-rw-r--r--spec/policies/ci/runner_machine_policy_spec.rb176
-rw-r--r--spec/policies/design_management/design_policy_spec.rb4
-rw-r--r--spec/policies/global_policy_spec.rb98
-rw-r--r--spec/policies/group_policy_spec.rb37
-rw-r--r--spec/policies/metrics/dashboard/annotation_policy_spec.rb16
-rw-r--r--spec/policies/project_group_link_policy_spec.rb2
-rw-r--r--spec/policies/project_hook_policy_spec.rb6
-rw-r--r--spec/policies/project_policy_spec.rb119
-rw-r--r--spec/presenters/blob_presenter_spec.rb10
-rw-r--r--spec/presenters/ci/build_runner_presenter_spec.rb78
-rw-r--r--spec/presenters/commit_presenter_spec.rb13
-rw-r--r--spec/presenters/issue_presenter_spec.rb20
-rw-r--r--spec/presenters/merge_request_presenter_spec.rb9
-rw-r--r--spec/presenters/packages/detail/package_presenter_spec.rb3
-rw-r--r--spec/rails_autoload.rb56
-rw-r--r--spec/requests/admin/abuse_reports_controller_spec.rb45
-rw-r--r--spec/requests/admin/applications_controller_spec.rb2
-rw-r--r--spec/requests/admin/broadcast_messages_controller_spec.rb5
-rw-r--r--spec/requests/admin/impersonation_tokens_controller_spec.rb2
-rw-r--r--spec/requests/admin/projects_controller_spec.rb58
-rw-r--r--spec/requests/admin/version_check_controller_spec.rb2
-rw-r--r--spec/requests/api/access_requests_spec.rb2
-rw-r--r--spec/requests/api/admin/batched_background_migrations_spec.rb93
-rw-r--r--spec/requests/api/admin/ci/variables_spec.rb121
-rw-r--r--spec/requests/api/admin/instance_clusters_spec.rb137
-rw-r--r--spec/requests/api/admin/plan_limits_spec.rb58
-rw-r--r--spec/requests/api/admin/sidekiq_spec.rb25
-rw-r--r--spec/requests/api/api_guard/admin_mode_middleware_spec.rb2
-rw-r--r--spec/requests/api/api_guard/response_coercer_middleware_spec.rb2
-rw-r--r--spec/requests/api/api_spec.rb2
-rw-r--r--spec/requests/api/appearance_spec.rb4
-rw-r--r--spec/requests/api/applications_spec.rb8
-rw-r--r--spec/requests/api/avatar_spec.rb1
-rw-r--r--spec/requests/api/award_emoji_spec.rb2
-rw-r--r--spec/requests/api/ci/job_artifacts_spec.rb6
-rw-r--r--spec/requests/api/ci/pipeline_schedules_spec.rb4
-rw-r--r--spec/requests/api/ci/pipelines_spec.rb114
-rw-r--r--spec/requests/api/ci/runner/jobs_put_spec.rb11
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb13
-rw-r--r--spec/requests/api/ci/runner/runners_verify_post_spec.rb30
-rw-r--r--spec/requests/api/ci/runners_reset_registration_token_spec.rb15
-rw-r--r--spec/requests/api/ci/runners_spec.rb203
-rw-r--r--spec/requests/api/ci/variables_spec.rb2
-rw-r--r--spec/requests/api/commits_spec.rb62
-rw-r--r--spec/requests/api/composer_packages_spec.rb6
-rw-r--r--spec/requests/api/debian_group_packages_spec.rb40
-rw-r--r--spec/requests/api/debian_project_packages_spec.rb42
-rw-r--r--spec/requests/api/doorkeeper_access_spec.rb2
-rw-r--r--spec/requests/api/draft_notes_spec.rb171
-rw-r--r--spec/requests/api/error_tracking/project_settings_spec.rb244
-rw-r--r--spec/requests/api/files_spec.rb35
-rw-r--r--spec/requests/api/freeze_periods_spec.rb196
-rw-r--r--spec/requests/api/graphql/achievements/user_achievements_query_spec.rb83
-rw-r--r--spec/requests/api/graphql/ci/config_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/group_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/instance_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/jobs_spec.rb62
-rw-r--r--spec/requests/api/graphql/ci/manual_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/project_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb80
-rw-r--r--spec/requests/api/graphql/ci/runners_spec.rb31
-rw-r--r--spec/requests/api/graphql/current_user/todos_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/current_user_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/custom_emoji_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/multiplexed_queries_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/achievements/award_spec.rb106
-rw-r--r--spec/requests/api/graphql/mutations/achievements/revoke_spec.rb91
-rw-r--r--spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/add_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job/cancel_spec.rb45
-rw-r--r--spec/requests/api/graphql/mutations/ci/job/play_spec.rb79
-rw-r--r--spec/requests/api/graphql/mutations/ci/job/retry_spec.rb92
-rw-r--r--spec/requests/api/graphql/mutations/ci/job/unschedule_spec.rb48
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_artifact/bulk_destroy_spec.rb197
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb45
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_play_spec.rb79
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_retry_spec.rb92
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb48
-rw-r--r--spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb15
-rw-r--r--spec/requests/api/graphql/mutations/ci/runner/create_spec.rb121
-rw-r--r--spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/design_management/update_spec.rb77
-rw-r--r--spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb68
-rw-r--r--spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb128
-rw-r--r--spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb18
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/note_spec.rb16
-rw-r--r--spec/requests/api/graphql/mutations/projects/sync_fork_spec.rb131
-rw-r--r--spec/requests/api/graphql/mutations/snippets/update_spec.rb3
-rw-r--r--spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/work_items/create_spec.rb54
-rw-r--r--spec/requests/api/graphql/mutations/work_items/export_spec.rb67
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_spec.rb137
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_task_spec.rb2
-rw-r--r--spec/requests/api/graphql/namespace/projects_spec.rb2
-rw-r--r--spec/requests/api/graphql/packages/package_spec.rb25
-rw-r--r--spec/requests/api/graphql/project/base_service_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/container_repositories_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/flow_metrics_spec.rb23
-rw-r--r--spec/requests/api/graphql/project/fork_details_spec.rb35
-rw-r--r--spec/requests/api/graphql/project/merge_requests_spec.rb3
-rw-r--r--spec/requests/api/graphql/project/work_items_spec.rb28
-rw-r--r--spec/requests/api/graphql/query_spec.rb2
-rw-r--r--spec/requests/api/graphql/user/user_achievements_query_spec.rb91
-rw-r--r--spec/requests/api/graphql/work_item_spec.rb26
-rw-r--r--spec/requests/api/graphql_spec.rb2
-rw-r--r--spec/requests/api/group_milestones_spec.rb78
-rw-r--r--spec/requests/api/group_variables_spec.rb2
-rw-r--r--spec/requests/api/helm_packages_spec.rb15
-rw-r--r--spec/requests/api/helpers_spec.rb2
-rw-r--r--spec/requests/api/internal/base_spec.rb12
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb147
-rw-r--r--spec/requests/api/internal/pages_spec.rb378
-rw-r--r--spec/requests/api/internal/workhorse_spec.rb2
-rw-r--r--spec/requests/api/issues/get_group_issues_spec.rb30
-rw-r--r--spec/requests/api/issues/get_project_issues_spec.rb42
-rw-r--r--spec/requests/api/issues/issues_spec.rb67
-rw-r--r--spec/requests/api/issues/post_projects_issues_spec.rb90
-rw-r--r--spec/requests/api/issues/put_projects_issues_spec.rb62
-rw-r--r--spec/requests/api/keys_spec.rb2
-rw-r--r--spec/requests/api/lint_spec.rb10
-rw-r--r--spec/requests/api/maven_packages_spec.rb37
-rw-r--r--spec/requests/api/merge_requests_spec.rb11
-rw-r--r--spec/requests/api/metadata_spec.rb2
-rw-r--r--spec/requests/api/npm_instance_packages_spec.rb34
-rw-r--r--spec/requests/api/npm_project_packages_spec.rb4
-rw-r--r--spec/requests/api/nuget_group_packages_spec.rb12
-rw-r--r--spec/requests/api/nuget_project_packages_spec.rb11
-rw-r--r--spec/requests/api/oauth_tokens_spec.rb4
-rw-r--r--spec/requests/api/pages/internal_access_spec.rb68
-rw-r--r--spec/requests/api/pages/pages_spec.rb12
-rw-r--r--spec/requests/api/pages/private_access_spec.rb68
-rw-r--r--spec/requests/api/pages/public_access_spec.rb68
-rw-r--r--spec/requests/api/pages_domains_spec.rb40
-rw-r--r--spec/requests/api/personal_access_tokens/self_information_spec.rb2
-rw-r--r--spec/requests/api/personal_access_tokens_spec.rb2
-rw-r--r--spec/requests/api/project_milestones_spec.rb87
-rw-r--r--spec/requests/api/projects_spec.rb105
-rw-r--r--spec/requests/api/protected_branches_spec.rb9
-rw-r--r--spec/requests/api/pypi_packages_spec.rb30
-rw-r--r--spec/requests/api/release/links_spec.rb24
-rw-r--r--spec/requests/api/repositories_spec.rb1
-rw-r--r--spec/requests/api/resource_access_tokens_spec.rb2
-rw-r--r--spec/requests/api/rubygem_packages_spec.rb30
-rw-r--r--spec/requests/api/search_spec.rb17
-rw-r--r--spec/requests/api/settings_spec.rb10
-rw-r--r--spec/requests/api/sidekiq_metrics_spec.rb2
-rw-r--r--spec/requests/api/terraform/modules/v1/packages_spec.rb7
-rw-r--r--spec/requests/api/terraform/state_spec.rb9
-rw-r--r--spec/requests/api/terraform/state_version_spec.rb8
-rw-r--r--spec/requests/api/unleash_spec.rb8
-rw-r--r--spec/requests/api/users_spec.rb12
-rw-r--r--spec/requests/dashboard_controller_spec.rb2
-rw-r--r--spec/requests/git_http_spec.rb24
-rw-r--r--spec/requests/groups/email_campaigns_controller_spec.rb6
-rw-r--r--spec/requests/groups/observability_controller_spec.rb18
-rw-r--r--spec/requests/groups/settings/access_tokens_controller_spec.rb2
-rw-r--r--spec/requests/groups/settings/applications_controller_spec.rb2
-rw-r--r--spec/requests/ide_controller_spec.rb120
-rw-r--r--spec/requests/jira_connect/oauth_application_ids_controller_spec.rb6
-rw-r--r--spec/requests/jira_connect/public_keys_controller_spec.rb21
-rw-r--r--spec/requests/jwks_controller_spec.rb2
-rw-r--r--spec/requests/jwt_controller_spec.rb10
-rw-r--r--spec/requests/oauth/applications_controller_spec.rb2
-rw-r--r--spec/requests/oauth/authorizations_controller_spec.rb2
-rw-r--r--spec/requests/oauth/tokens_controller_spec.rb2
-rw-r--r--spec/requests/oauth_tokens_spec.rb2
-rw-r--r--spec/requests/openid_connect_spec.rb2
-rw-r--r--spec/requests/projects/airflow/dags_controller_spec.rb105
-rw-r--r--spec/requests/projects/ci/promeheus_metrics/histograms_controller_spec.rb2
-rw-r--r--spec/requests/projects/google_cloud/deployments_controller_spec.rb112
-rw-r--r--spec/requests/projects/issue_links_controller_spec.rb16
-rw-r--r--spec/requests/projects/issues_controller_spec.rb29
-rw-r--r--spec/requests/projects/merge_requests_discussions_spec.rb261
-rw-r--r--spec/requests/projects/settings/access_tokens_controller_spec.rb2
-rw-r--r--spec/requests/projects/uploads_spec.rb2
-rw-r--r--spec/requests/projects/wikis_controller_spec.rb73
-rw-r--r--spec/requests/rack_attack_global_spec.rb2
-rw-r--r--spec/requests/sandbox_controller_spec.rb2
-rw-r--r--spec/requests/sessions_spec.rb2
-rw-r--r--spec/requests/users_controller_spec.rb100
-rw-r--r--spec/requests/verifies_with_email_spec.rb2
-rw-r--r--spec/routing/import_routing_spec.rb4
-rw-r--r--spec/routing/user_routing_spec.rb2
-rw-r--r--spec/rubocop/cop/background_migration/missing_dictionary_file_spec.rb137
-rw-r--r--spec/rubocop/cop/gitlab/doc_url_spec.rb2
-rw-r--r--spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb10
-rw-r--r--spec/rubocop/cop/lint/last_keyword_argument_spec.rb2
-rw-r--r--spec/rubocop/cop/rspec/avoid_test_prof_spec.rb2
-rw-r--r--spec/scripts/database/schema_validator_spec.rb67
-rw-r--r--spec/scripts/generate_rspec_pipeline_spec.rb198
-rw-r--r--spec/scripts/lib/glfm/shared_spec.rb3
-rw-r--r--spec/scripts/pipeline/create_test_failure_issues_spec.rb145
-rw-r--r--spec/scripts/pipeline_test_report_builder_spec.rb5
-rw-r--r--spec/scripts/review_apps/automated_cleanup_spec.rb261
-rw-r--r--spec/serializers/admin/abuse_report_entity_spec.rb32
-rw-r--r--spec/serializers/admin/abuse_report_serializer_spec.rb23
-rw-r--r--spec/serializers/build_details_entity_spec.rb2
-rw-r--r--spec/serializers/cluster_application_entity_spec.rb81
-rw-r--r--spec/serializers/cluster_entity_spec.rb14
-rw-r--r--spec/serializers/cluster_serializer_spec.rb4
-rw-r--r--spec/serializers/entity_date_helper_spec.rb10
-rw-r--r--spec/serializers/group_issuable_autocomplete_entity_spec.rb3
-rw-r--r--spec/serializers/issue_board_entity_spec.rb10
-rw-r--r--spec/serializers/issue_entity_spec.rb12
-rw-r--r--spec/serializers/linked_project_issue_entity_spec.rb10
-rw-r--r--spec/serializers/pipeline_details_entity_spec.rb28
-rw-r--r--spec/serializers/profile/event_entity_spec.rb149
-rw-r--r--spec/serializers/project_import_entity_spec.rb30
-rw-r--r--spec/services/access_token_validation_service_spec.rb2
-rw-r--r--spec/services/achievements/award_service_spec.rb73
-rw-r--r--spec/services/achievements/revoke_service_spec.rb66
-rw-r--r--spec/services/admin/set_feature_flag_service_spec.rb2
-rw-r--r--spec/services/alert_management/alerts/todo/create_service_spec.rb2
-rw-r--r--spec/services/alert_management/alerts/update_service_spec.rb2
-rw-r--r--spec/services/alert_management/create_alert_issue_service_spec.rb2
-rw-r--r--spec/services/alert_management/http_integrations/create_service_spec.rb2
-rw-r--r--spec/services/alert_management/http_integrations/destroy_service_spec.rb2
-rw-r--r--spec/services/alert_management/http_integrations/update_service_spec.rb2
-rw-r--r--spec/services/alert_management/metric_images/upload_service_spec.rb2
-rw-r--r--spec/services/alert_management/process_prometheus_alert_service_spec.rb2
-rw-r--r--spec/services/analytics/cycle_analytics/stages/list_service_spec.rb2
-rw-r--r--spec/services/application_settings/update_service_spec.rb6
-rw-r--r--spec/services/audit_event_service_spec.rb2
-rw-r--r--spec/services/audit_events/build_service_spec.rb2
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb2
-rw-r--r--spec/services/auth/dependency_proxy_authentication_service_spec.rb2
-rw-r--r--spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb2
-rw-r--r--spec/services/authorized_project_update/periodic_recalculate_service_spec.rb2
-rw-r--r--spec/services/authorized_project_update/project_access_changed_service_spec.rb2
-rw-r--r--spec/services/authorized_project_update/project_recalculate_per_user_service_spec.rb2
-rw-r--r--spec/services/authorized_project_update/project_recalculate_service_spec.rb2
-rw-r--r--spec/services/auto_merge/base_service_spec.rb2
-rw-r--r--spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb2
-rw-r--r--spec/services/auto_merge_service_spec.rb2
-rw-r--r--spec/services/award_emojis/add_service_spec.rb2
-rw-r--r--spec/services/award_emojis/base_service_spec.rb2
-rw-r--r--spec/services/award_emojis/collect_user_emoji_service_spec.rb2
-rw-r--r--spec/services/award_emojis/copy_service_spec.rb2
-rw-r--r--spec/services/award_emojis/destroy_service_spec.rb2
-rw-r--r--spec/services/award_emojis/toggle_service_spec.rb2
-rw-r--r--spec/services/base_container_service_spec.rb2
-rw-r--r--spec/services/base_count_service_spec.rb2
-rw-r--r--spec/services/boards/create_service_spec.rb2
-rw-r--r--spec/services/boards/destroy_service_spec.rb2
-rw-r--r--spec/services/boards/issues/create_service_spec.rb2
-rw-r--r--spec/services/boards/issues/list_service_spec.rb2
-rw-r--r--spec/services/boards/issues/move_service_spec.rb2
-rw-r--r--spec/services/boards/lists/create_service_spec.rb2
-rw-r--r--spec/services/boards/lists/destroy_service_spec.rb2
-rw-r--r--spec/services/boards/lists/list_service_spec.rb2
-rw-r--r--spec/services/boards/lists/move_service_spec.rb2
-rw-r--r--spec/services/boards/lists/update_service_spec.rb2
-rw-r--r--spec/services/boards/visits/create_service_spec.rb2
-rw-r--r--spec/services/branches/create_service_spec.rb4
-rw-r--r--spec/services/branches/delete_merged_service_spec.rb2
-rw-r--r--spec/services/branches/delete_service_spec.rb2
-rw-r--r--spec/services/branches/diverging_commit_counts_service_spec.rb2
-rw-r--r--spec/services/branches/validate_new_service_spec.rb2
-rw-r--r--spec/services/bulk_create_integration_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/archive_extraction_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/export_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/file_decompression_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/file_download_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/file_export_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/lfs_objects_export_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/relation_export_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/repository_bundle_export_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/tree_export_service_spec.rb2
-rw-r--r--spec/services/bulk_imports/uploads_export_service_spec.rb2
-rw-r--r--spec/services/bulk_push_event_payload_service_spec.rb2
-rw-r--r--spec/services/bulk_update_integration_service_spec.rb2
-rw-r--r--spec/services/captcha/captcha_verification_service_spec.rb2
-rw-r--r--spec/services/chat_names/find_user_service_spec.rb2
-rw-r--r--spec/services/ci/abort_pipelines_service_spec.rb2
-rw-r--r--spec/services/ci/append_build_trace_service_spec.rb2
-rw-r--r--spec/services/ci/build_cancel_service_spec.rb2
-rw-r--r--spec/services/ci/build_erase_service_spec.rb2
-rw-r--r--spec/services/ci/build_report_result_service_spec.rb2
-rw-r--r--spec/services/ci/build_unschedule_service_spec.rb2
-rw-r--r--spec/services/ci/catalog/add_resource_service_spec.rb55
-rw-r--r--spec/services/ci/catalog/validate_resource_service_spec.rb57
-rw-r--r--spec/services/ci/change_variable_service_spec.rb2
-rw-r--r--spec/services/ci/change_variables_service_spec.rb2
-rw-r--r--spec/services/ci/compare_accessibility_reports_service_spec.rb2
-rw-r--r--spec/services/ci/compare_codequality_reports_service_spec.rb2
-rw-r--r--spec/services/ci/compare_reports_base_service_spec.rb2
-rw-r--r--spec/services/ci/compare_test_reports_service_spec.rb2
-rw-r--r--spec/services/ci/components/fetch_service_spec.rb2
-rw-r--r--spec/services/ci/copy_cross_database_associations_service_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/artifacts_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/cache_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/custom_config_content_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/dry_run_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/environment_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/include_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/logger_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/merge_requests_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/needs_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/parallel_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/parameter_content_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/rate_limit_spec.rb3
-rw-r--r--spec/services/ci/create_pipeline_service/rules_spec.rb36
-rw-r--r--spec/services/ci/create_pipeline_service/scripts_spec.rb28
-rw-r--r--spec/services/ci/create_pipeline_service/tags_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/variables_spec.rb3
-rw-r--r--spec/services/ci/create_web_ide_terminal_service_spec.rb2
-rw-r--r--spec/services/ci/daily_build_group_report_result_service_spec.rb2
-rw-r--r--spec/services/ci/delete_objects_service_spec.rb2
-rw-r--r--spec/services/ci/delete_unit_tests_service_spec.rb2
-rw-r--r--spec/services/ci/deployments/destroy_service_spec.rb2
-rw-r--r--spec/services/ci/destroy_pipeline_service_spec.rb2
-rw-r--r--spec/services/ci/destroy_secure_file_service_spec.rb2
-rw-r--r--spec/services/ci/disable_user_pipeline_schedules_service_spec.rb2
-rw-r--r--spec/services/ci/drop_pipeline_service_spec.rb2
-rw-r--r--spec/services/ci/ensure_stage_service_spec.rb2
-rw-r--r--spec/services/ci/expire_pipeline_cache_service_spec.rb2
-rw-r--r--spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb2
-rw-r--r--spec/services/ci/find_exposed_artifacts_service_spec.rb2
-rw-r--r--spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb2
-rw-r--r--spec/services/ci/generate_coverage_reports_service_spec.rb2
-rw-r--r--spec/services/ci/generate_kubeconfig_service_spec.rb2
-rw-r--r--spec/services/ci/generate_terraform_reports_service_spec.rb2
-rw-r--r--spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb121
-rw-r--r--spec/services/ci/job_artifacts/create_service_spec.rb145
-rw-r--r--spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb2
-rw-r--r--spec/services/ci/job_artifacts/delete_service_spec.rb2
-rw-r--r--spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb38
-rw-r--r--spec/services/ci/job_artifacts/destroy_associations_service_spec.rb31
-rw-r--r--spec/services/ci/job_artifacts/destroy_batch_service_spec.rb15
-rw-r--r--spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb2
-rw-r--r--spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb2
-rw-r--r--spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb3
-rw-r--r--spec/services/ci/list_config_variables_service_spec.rb2
-rw-r--r--spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb2
-rw-r--r--spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb2
-rw-r--r--spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb3
-rw-r--r--spec/services/ci/pipeline_bridge_status_service_spec.rb2
-rw-r--r--spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb2
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb25
-rw-r--r--spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb2
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb2
-rw-r--r--spec/services/ci/pipelines/add_job_service_spec.rb2
-rw-r--r--spec/services/ci/pipelines/hook_service_spec.rb2
-rw-r--r--spec/services/ci/play_bridge_service_spec.rb2
-rw-r--r--spec/services/ci/play_build_service_spec.rb2
-rw-r--r--spec/services/ci/play_manual_stage_service_spec.rb2
-rw-r--r--spec/services/ci/prepare_build_service_spec.rb2
-rw-r--r--spec/services/ci/process_build_service_spec.rb2
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb2
-rw-r--r--spec/services/ci/process_sync_events_service_spec.rb2
-rw-r--r--spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb2
-rw-r--r--spec/services/ci/queue/pending_builds_strategy_spec.rb2
-rw-r--r--spec/services/ci/register_job_service_spec.rb1160
-rw-r--r--spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb2
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb2
-rw-r--r--spec/services/ci/run_scheduled_build_service_spec.rb2
-rw-r--r--spec/services/ci/runners/create_runner_service_spec.rb43
-rw-r--r--spec/services/ci/runners/process_runner_version_update_service_spec.rb13
-rw-r--r--spec/services/ci/stuck_builds/drop_pending_service_spec.rb2
-rw-r--r--spec/services/ci/stuck_builds/drop_running_service_spec.rb2
-rw-r--r--spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb2
-rw-r--r--spec/services/ci/test_failure_history_service_spec.rb2
-rw-r--r--spec/services/ci/track_failed_build_service_spec.rb2
-rw-r--r--spec/services/ci/unlock_artifacts_service_spec.rb10
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb2
-rw-r--r--spec/services/ci/update_instance_variables_service_spec.rb2
-rw-r--r--spec/services/ci/update_pending_build_service_spec.rb2
-rw-r--r--spec/services/clusters/agent_tokens/create_service_spec.rb8
-rw-r--r--spec/services/clusters/agent_tokens/revoke_service_spec.rb77
-rw-r--r--spec/services/clusters/agent_tokens/track_usage_service_spec.rb2
-rw-r--r--spec/services/clusters/agents/authorize_proxy_user_service_spec.rb68
-rw-r--r--spec/services/clusters/agents/create_activity_event_service_spec.rb13
-rw-r--r--spec/services/clusters/agents/create_service_spec.rb2
-rw-r--r--spec/services/clusters/agents/delete_expired_events_service_spec.rb2
-rw-r--r--spec/services/clusters/agents/delete_service_spec.rb2
-rw-r--r--spec/services/clusters/build_kubernetes_namespace_service_spec.rb2
-rw-r--r--spec/services/clusters/build_service_spec.rb2
-rw-r--r--spec/services/clusters/cleanup/project_namespace_service_spec.rb2
-rw-r--r--spec/services/clusters/cleanup/service_account_service_spec.rb2
-rw-r--r--spec/services/clusters/create_service_spec.rb2
-rw-r--r--spec/services/clusters/destroy_service_spec.rb2
-rw-r--r--spec/services/clusters/integrations/create_service_spec.rb2
-rw-r--r--spec/services/clusters/integrations/prometheus_health_check_service_spec.rb2
-rw-r--r--spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb2
-rw-r--r--spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb2
-rw-r--r--spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb2
-rw-r--r--spec/services/clusters/kubernetes_spec.rb2
-rw-r--r--spec/services/clusters/management/validate_management_project_permissions_service_spec.rb2
-rw-r--r--spec/services/clusters/update_service_spec.rb2
-rw-r--r--spec/services/cohorts_service_spec.rb2
-rw-r--r--spec/services/commits/cherry_pick_service_spec.rb2
-rw-r--r--spec/services/commits/commit_patch_service_spec.rb2
-rw-r--r--spec/services/commits/tag_service_spec.rb2
-rw-r--r--spec/services/compare_service_spec.rb2
-rw-r--r--spec/services/concerns/audit_event_save_type_spec.rb2
-rw-r--r--spec/services/concerns/exclusive_lease_guard_spec.rb2
-rw-r--r--spec/services/concerns/merge_requests/assigns_merge_params_spec.rb2
-rw-r--r--spec/services/concerns/rate_limited_service_spec.rb2
-rw-r--r--spec/services/container_expiration_policies/cleanup_service_spec.rb3
-rw-r--r--spec/services/container_expiration_policies/update_service_spec.rb2
-rw-r--r--spec/services/customer_relations/contacts/create_service_spec.rb2
-rw-r--r--spec/services/customer_relations/contacts/update_service_spec.rb2
-rw-r--r--spec/services/customer_relations/organizations/create_service_spec.rb2
-rw-r--r--spec/services/customer_relations/organizations/update_service_spec.rb2
-rw-r--r--spec/services/database/consistency_fix_service_spec.rb2
-rw-r--r--spec/services/dependency_proxy/auth_token_service_spec.rb2
-rw-r--r--spec/services/dependency_proxy/find_cached_manifest_service_spec.rb2
-rw-r--r--spec/services/dependency_proxy/group_settings/update_service_spec.rb2
-rw-r--r--spec/services/dependency_proxy/head_manifest_service_spec.rb2
-rw-r--r--spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb2
-rw-r--r--spec/services/dependency_proxy/request_token_service_spec.rb2
-rw-r--r--spec/services/deploy_keys/create_service_spec.rb2
-rw-r--r--spec/services/deployments/archive_in_project_service_spec.rb2
-rw-r--r--spec/services/deployments/create_for_build_service_spec.rb2
-rw-r--r--spec/services/deployments/create_service_spec.rb2
-rw-r--r--spec/services/deployments/link_merge_requests_service_spec.rb2
-rw-r--r--spec/services/deployments/older_deployments_drop_service_spec.rb2
-rw-r--r--spec/services/deployments/update_environment_service_spec.rb2
-rw-r--r--spec/services/deployments/update_service_spec.rb2
-rw-r--r--spec/services/design_management/copy_design_collection/copy_service_spec.rb3
-rw-r--r--spec/services/design_management/copy_design_collection/queue_service_spec.rb3
-rw-r--r--spec/services/design_management/delete_designs_service_spec.rb2
-rw-r--r--spec/services/design_management/design_user_notes_count_service_spec.rb2
-rw-r--r--spec/services/design_management/generate_image_versions_service_spec.rb2
-rw-r--r--spec/services/design_management/move_designs_service_spec.rb2
-rw-r--r--spec/services/discussions/capture_diff_note_position_service_spec.rb2
-rw-r--r--spec/services/discussions/capture_diff_note_positions_service_spec.rb2
-rw-r--r--spec/services/discussions/update_diff_position_service_spec.rb2
-rw-r--r--spec/services/draft_notes/create_service_spec.rb2
-rw-r--r--spec/services/draft_notes/destroy_service_spec.rb2
-rw-r--r--spec/services/draft_notes/publish_service_spec.rb2
-rw-r--r--spec/services/emails/confirm_service_spec.rb2
-rw-r--r--spec/services/emails/create_service_spec.rb2
-rw-r--r--spec/services/emails/destroy_service_spec.rb2
-rw-r--r--spec/services/environments/auto_stop_service_spec.rb3
-rw-r--r--spec/services/environments/canary_ingress/update_service_spec.rb3
-rw-r--r--spec/services/environments/create_for_build_service_spec.rb2
-rw-r--r--spec/services/environments/reset_auto_stop_service_spec.rb2
-rw-r--r--spec/services/environments/schedule_to_delete_review_apps_service_spec.rb2
-rw-r--r--spec/services/environments/stop_service_spec.rb2
-rw-r--r--spec/services/error_tracking/base_service_spec.rb2
-rw-r--r--spec/services/error_tracking/collect_error_service_spec.rb2
-rw-r--r--spec/services/error_tracking/issue_details_service_spec.rb2
-rw-r--r--spec/services/error_tracking/issue_latest_event_service_spec.rb2
-rw-r--r--spec/services/error_tracking/issue_update_service_spec.rb2
-rw-r--r--spec/services/error_tracking/list_issues_service_spec.rb2
-rw-r--r--spec/services/event_create_service_spec.rb59
-rw-r--r--spec/services/events/destroy_service_spec.rb2
-rw-r--r--spec/services/events/render_service_spec.rb2
-rw-r--r--spec/services/feature_flags/create_service_spec.rb10
-rw-r--r--spec/services/feature_flags/destroy_service_spec.rb5
-rw-r--r--spec/services/feature_flags/hook_service_spec.rb2
-rw-r--r--spec/services/feature_flags/update_service_spec.rb7
-rw-r--r--spec/services/files/create_service_spec.rb2
-rw-r--r--spec/services/files/delete_service_spec.rb6
-rw-r--r--spec/services/files/multi_service_spec.rb16
-rw-r--r--spec/services/files/update_service_spec.rb6
-rw-r--r--spec/services/git/base_hooks_service_spec.rb2
-rw-r--r--spec/services/git/branch_hooks_service_spec.rb2
-rw-r--r--spec/services/git/branch_push_service_spec.rb2
-rw-r--r--spec/services/git/process_ref_changes_service_spec.rb2
-rw-r--r--spec/services/git/tag_hooks_service_spec.rb2
-rw-r--r--spec/services/git/tag_push_service_spec.rb2
-rw-r--r--spec/services/git/wiki_push_service/change_spec.rb2
-rw-r--r--spec/services/google_cloud/create_cloudsql_instance_service_spec.rb2
-rw-r--r--spec/services/google_cloud/create_service_accounts_service_spec.rb2
-rw-r--r--spec/services/google_cloud/enable_cloud_run_service_spec.rb2
-rw-r--r--spec/services/google_cloud/enable_cloudsql_service_spec.rb2
-rw-r--r--spec/services/google_cloud/gcp_region_add_or_replace_service_spec.rb2
-rw-r--r--spec/services/google_cloud/generate_pipeline_service_spec.rb2
-rw-r--r--spec/services/google_cloud/get_cloudsql_instances_service_spec.rb2
-rw-r--r--spec/services/google_cloud/service_accounts_service_spec.rb2
-rw-r--r--spec/services/google_cloud/setup_cloudsql_instance_service_spec.rb2
-rw-r--r--spec/services/gpg_keys/create_service_spec.rb2
-rw-r--r--spec/services/grafana/proxy_service_spec.rb2
-rw-r--r--spec/services/gravatar_service_spec.rb2
-rw-r--r--spec/services/groups/auto_devops_service_spec.rb2
-rw-r--r--spec/services/groups/autocomplete_service_spec.rb2
-rw-r--r--spec/services/groups/deploy_tokens/create_service_spec.rb2
-rw-r--r--spec/services/groups/deploy_tokens/destroy_service_spec.rb2
-rw-r--r--spec/services/groups/deploy_tokens/revoke_service_spec.rb2
-rw-r--r--spec/services/groups/group_links/create_service_spec.rb2
-rw-r--r--spec/services/groups/group_links/destroy_service_spec.rb2
-rw-r--r--spec/services/groups/group_links/update_service_spec.rb4
-rw-r--r--spec/services/groups/import_export/export_service_spec.rb2
-rw-r--r--spec/services/groups/import_export/import_service_spec.rb2
-rw-r--r--spec/services/groups/merge_requests_count_service_spec.rb2
-rw-r--r--spec/services/groups/nested_create_service_spec.rb2
-rw-r--r--spec/services/groups/open_issues_count_service_spec.rb2
-rw-r--r--spec/services/groups/participants_service_spec.rb2
-rw-r--r--spec/services/groups/update_service_spec.rb2
-rw-r--r--spec/services/groups/update_shared_runners_service_spec.rb2
-rw-r--r--spec/services/groups/update_statistics_service_spec.rb2
-rw-r--r--spec/services/ide/base_config_service_spec.rb2
-rw-r--r--spec/services/ide/schemas_config_service_spec.rb2
-rw-r--r--spec/services/ide/terminal_config_service_spec.rb2
-rw-r--r--spec/services/import/bitbucket_server_service_spec.rb2
-rw-r--r--spec/services/import/fogbugz_service_spec.rb2
-rw-r--r--spec/services/import/github/cancel_project_import_service_spec.rb14
-rw-r--r--spec/services/import/github/notes/create_service_spec.rb2
-rw-r--r--spec/services/import/github_service_spec.rb2
-rw-r--r--spec/services/import/gitlab_projects/create_project_service_spec.rb11
-rw-r--r--spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb2
-rw-r--r--spec/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3_spec.rb2
-rw-r--r--spec/services/import/prepare_service_spec.rb2
-rw-r--r--spec/services/import/validate_remote_git_endpoint_service_spec.rb24
-rw-r--r--spec/services/import_csv/base_service_spec.rb69
-rw-r--r--spec/services/import_export_clean_up_service_spec.rb2
-rw-r--r--spec/services/incident_management/incidents/create_service_spec.rb2
-rw-r--r--spec/services/incident_management/issuable_escalation_statuses/after_update_service_spec.rb3
-rw-r--r--spec/services/incident_management/issuable_escalation_statuses/build_service_spec.rb2
-rw-r--r--spec/services/incident_management/issuable_escalation_statuses/create_service_spec.rb2
-rw-r--r--spec/services/incident_management/issuable_escalation_statuses/prepare_update_service_spec.rb3
-rw-r--r--spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb2
-rw-r--r--spec/services/incident_management/pager_duty/process_webhook_service_spec.rb2
-rw-r--r--spec/services/incident_management/timeline_event_tags/create_service_spec.rb2
-rw-r--r--spec/services/incident_management/timeline_events/create_service_spec.rb4
-rw-r--r--spec/services/incident_management/timeline_events/destroy_service_spec.rb3
-rw-r--r--spec/services/incident_management/timeline_events/update_service_spec.rb1
-rw-r--r--spec/services/integrations/propagate_service_spec.rb2
-rw-r--r--spec/services/integrations/test/project_service_spec.rb2
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb2
-rw-r--r--spec/services/issuable/common_system_notes_service_spec.rb2
-rw-r--r--spec/services/issuable/destroy_label_links_service_spec.rb2
-rw-r--r--spec/services/issuable/destroy_service_spec.rb2
-rw-r--r--spec/services/issuable/discussions_list_service_spec.rb2
-rw-r--r--spec/services/issuable/process_assignees_spec.rb2
-rw-r--r--spec/services/issue_links/create_service_spec.rb3
-rw-r--r--spec/services/issue_links/destroy_service_spec.rb3
-rw-r--r--spec/services/issue_links/list_service_spec.rb2
-rw-r--r--spec/services/issues/after_create_service_spec.rb2
-rw-r--r--spec/services/issues/base_service_spec.rb9
-rw-r--r--spec/services/issues/build_service_spec.rb2
-rw-r--r--spec/services/issues/clone_service_spec.rb2
-rw-r--r--spec/services/issues/close_service_spec.rb3
-rw-r--r--spec/services/issues/create_service_spec.rb2
-rw-r--r--spec/services/issues/duplicate_service_spec.rb2
-rw-r--r--spec/services/issues/import_csv_service_spec.rb3
-rw-r--r--spec/services/issues/issuable_base_service_spec.rb9
-rw-r--r--spec/services/issues/prepare_import_csv_service_spec.rb2
-rw-r--r--spec/services/issues/referenced_merge_requests_service_spec.rb2
-rw-r--r--spec/services/issues/related_branches_service_spec.rb2
-rw-r--r--spec/services/issues/relative_position_rebalancing_service_spec.rb2
-rw-r--r--spec/services/issues/reopen_service_spec.rb3
-rw-r--r--spec/services/issues/reorder_service_spec.rb2
-rw-r--r--spec/services/issues/resolve_discussions_spec.rb14
-rw-r--r--spec/services/issues/set_crm_contacts_service_spec.rb2
-rw-r--r--spec/services/issues/update_service_spec.rb4
-rw-r--r--spec/services/issues/zoom_link_service_spec.rb3
-rw-r--r--spec/services/jira/requests/projects/list_service_spec.rb2
-rw-r--r--spec/services/jira_connect/sync_service_spec.rb2
-rw-r--r--spec/services/jira_connect_installations/destroy_service_spec.rb2
-rw-r--r--spec/services/jira_connect_installations/proxy_lifecycle_event_service_spec.rb6
-rw-r--r--spec/services/jira_connect_subscriptions/create_service_spec.rb2
-rw-r--r--spec/services/jira_import/cloud_users_mapper_service_spec.rb2
-rw-r--r--spec/services/jira_import/server_users_mapper_service_spec.rb2
-rw-r--r--spec/services/jira_import/start_import_service_spec.rb2
-rw-r--r--spec/services/jira_import/users_importer_spec.rb2
-rw-r--r--spec/services/keys/create_service_spec.rb2
-rw-r--r--spec/services/keys/destroy_service_spec.rb2
-rw-r--r--spec/services/keys/expiry_notification_service_spec.rb2
-rw-r--r--spec/services/keys/last_used_service_spec.rb2
-rw-r--r--spec/services/keys/revoke_service_spec.rb13
-rw-r--r--spec/services/labels/available_labels_service_spec.rb2
-rw-r--r--spec/services/labels/create_service_spec.rb2
-rw-r--r--spec/services/labels/find_or_create_service_spec.rb2
-rw-r--r--spec/services/labels/promote_service_spec.rb2
-rw-r--r--spec/services/labels/transfer_service_spec.rb2
-rw-r--r--spec/services/labels/update_service_spec.rb2
-rw-r--r--spec/services/lfs/lock_file_service_spec.rb2
-rw-r--r--spec/services/lfs/locks_finder_service_spec.rb2
-rw-r--r--spec/services/lfs/push_service_spec.rb2
-rw-r--r--spec/services/lfs/unlock_file_service_spec.rb2
-rw-r--r--spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb2
-rw-r--r--spec/services/loose_foreign_keys/cleaner_service_spec.rb2
-rw-r--r--spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb2
-rw-r--r--spec/services/markdown_content_rewriter_service_spec.rb2
-rw-r--r--spec/services/markup/rendering_service_spec.rb19
-rw-r--r--spec/services/mattermost/create_team_service_spec.rb28
-rw-r--r--spec/services/members/approve_access_request_service_spec.rb2
-rw-r--r--spec/services/members/create_service_spec.rb3
-rw-r--r--spec/services/members/creator_service_spec.rb2
-rw-r--r--spec/services/members/groups/creator_service_spec.rb2
-rw-r--r--spec/services/members/import_project_team_service_spec.rb2
-rw-r--r--spec/services/members/invitation_reminder_email_service_spec.rb2
-rw-r--r--spec/services/members/invite_member_builder_spec.rb2
-rw-r--r--spec/services/members/invite_service_spec.rb3
-rw-r--r--spec/services/members/projects/creator_service_spec.rb2
-rw-r--r--spec/services/members/request_access_service_spec.rb2
-rw-r--r--spec/services/members/standard_member_builder_spec.rb2
-rw-r--r--spec/services/members/unassign_issuables_service_spec.rb2
-rw-r--r--spec/services/members/update_service_spec.rb2
-rw-r--r--spec/services/merge_requests/add_context_service_spec.rb2
-rw-r--r--spec/services/merge_requests/add_spent_time_service_spec.rb2
-rw-r--r--spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb2
-rw-r--r--spec/services/merge_requests/approval_service_spec.rb2
-rw-r--r--spec/services/merge_requests/assign_issues_service_spec.rb2
-rw-r--r--spec/services/merge_requests/base_service_spec.rb4
-rw-r--r--spec/services/merge_requests/cleanup_refs_service_spec.rb2
-rw-r--r--spec/services/merge_requests/close_service_spec.rb6
-rw-r--r--spec/services/merge_requests/conflicts/list_service_spec.rb2
-rw-r--r--spec/services/merge_requests/conflicts/resolve_service_spec.rb2
-rw-r--r--spec/services/merge_requests/create_approval_event_service_spec.rb2
-rw-r--r--spec/services/merge_requests/create_pipeline_service_spec.rb2
-rw-r--r--spec/services/merge_requests/create_service_spec.rb7
-rw-r--r--spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb3
-rw-r--r--spec/services/merge_requests/execute_approval_hooks_service_spec.rb2
-rw-r--r--spec/services/merge_requests/ff_merge_service_spec.rb2
-rw-r--r--spec/services/merge_requests/get_urls_service_spec.rb2
-rw-r--r--spec/services/merge_requests/handle_assignees_change_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mark_reviewer_reviewed_service_spec.rb2
-rw-r--r--spec/services/merge_requests/merge_orchestration_service_spec.rb2
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb2
-rw-r--r--spec/services/merge_requests/merge_to_ref_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/check_base_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/check_broken_status_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/check_ci_status_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/check_discussions_status_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/check_draft_status_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/check_open_status_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/logger_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability/run_checks_service_spec.rb2
-rw-r--r--spec/services/merge_requests/mergeability_check_service_spec.rb2
-rw-r--r--spec/services/merge_requests/migrate_external_diffs_service_spec.rb2
-rw-r--r--spec/services/merge_requests/post_merge_service_spec.rb8
-rw-r--r--spec/services/merge_requests/push_options_handler_service_spec.rb2
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb8
-rw-r--r--spec/services/merge_requests/reload_diffs_service_spec.rb3
-rw-r--r--spec/services/merge_requests/reload_merge_head_diff_service_spec.rb2
-rw-r--r--spec/services/merge_requests/reopen_service_spec.rb8
-rw-r--r--spec/services/merge_requests/request_review_service_spec.rb2
-rw-r--r--spec/services/merge_requests/resolve_todos_service_spec.rb2
-rw-r--r--spec/services/merge_requests/resolved_discussion_notification_service_spec.rb2
-rw-r--r--spec/services/merge_requests/squash_service_spec.rb2
-rw-r--r--spec/services/merge_requests/update_assignees_service_spec.rb2
-rw-r--r--spec/services/merge_requests/update_reviewers_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/annotations/create_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/annotations/delete_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/clone_dashboard_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/custom_dashboard_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/default_embed_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/dynamic_embed_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/panel_preview_service_spec.rb2
-rw-r--r--spec/services/metrics/dashboard/pod_dashboard_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/system_dashboard_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/transient_embed_service_spec.rb3
-rw-r--r--spec/services/metrics/dashboard/update_dashboard_service_spec.rb2
-rw-r--r--spec/services/metrics/sample_metrics_service_spec.rb2
-rw-r--r--spec/services/metrics/users_starred_dashboards/create_service_spec.rb2
-rw-r--r--spec/services/metrics/users_starred_dashboards/delete_service_spec.rb2
-rw-r--r--spec/services/milestones/close_service_spec.rb2
-rw-r--r--spec/services/milestones/closed_issues_count_service_spec.rb3
-rw-r--r--spec/services/milestones/create_service_spec.rb2
-rw-r--r--spec/services/milestones/destroy_service_spec.rb2
-rw-r--r--spec/services/milestones/find_or_create_service_spec.rb2
-rw-r--r--spec/services/milestones/issues_count_service_spec.rb3
-rw-r--r--spec/services/milestones/merge_requests_count_service_spec.rb3
-rw-r--r--spec/services/milestones/promote_service_spec.rb2
-rw-r--r--spec/services/milestones/transfer_service_spec.rb2
-rw-r--r--spec/services/milestones/update_service_spec.rb2
-rw-r--r--spec/services/ml/experiment_tracking/candidate_repository_spec.rb2
-rw-r--r--spec/services/ml/experiment_tracking/experiment_repository_spec.rb2
-rw-r--r--spec/services/namespace_settings/update_service_spec.rb2
-rw-r--r--spec/services/namespaces/in_product_marketing_emails_service_spec.rb2
-rw-r--r--spec/services/namespaces/package_settings/update_service_spec.rb2
-rw-r--r--spec/services/namespaces/statistics_refresher_service_spec.rb2
-rw-r--r--spec/services/note_summary_spec.rb2
-rw-r--r--spec/services/notes/build_service_spec.rb2
-rw-r--r--spec/services/notes/copy_service_spec.rb2
-rw-r--r--spec/services/notes/create_service_spec.rb5
-rw-r--r--spec/services/notes/destroy_service_spec.rb2
-rw-r--r--spec/services/notes/post_process_service_spec.rb2
-rw-r--r--spec/services/notes/quick_actions_service_spec.rb86
-rw-r--r--spec/services/notes/render_service_spec.rb2
-rw-r--r--spec/services/notes/resolve_service_spec.rb2
-rw-r--r--spec/services/notes/update_service_spec.rb2
-rw-r--r--spec/services/notification_recipients/build_service_spec.rb2
-rw-r--r--spec/services/notification_recipients/builder/default_spec.rb2
-rw-r--r--spec/services/notification_recipients/builder/new_note_spec.rb2
-rw-r--r--spec/services/onboarding/progress_service_spec.rb2
-rw-r--r--spec/services/packages/cleanup/execute_policy_service_spec.rb2
-rw-r--r--spec/services/packages/cleanup/update_policy_service_spec.rb2
-rw-r--r--spec/services/packages/composer/composer_json_service_spec.rb2
-rw-r--r--spec/services/packages/composer/create_package_service_spec.rb2
-rw-r--r--spec/services/packages/composer/version_parser_service_spec.rb2
-rw-r--r--spec/services/packages/conan/create_package_file_service_spec.rb2
-rw-r--r--spec/services/packages/conan/create_package_service_spec.rb2
-rw-r--r--spec/services/packages/create_dependency_service_spec.rb2
-rw-r--r--spec/services/packages/create_event_service_spec.rb2
-rw-r--r--spec/services/packages/create_package_file_service_spec.rb2
-rw-r--r--spec/services/packages/create_temporary_package_service_spec.rb2
-rw-r--r--spec/services/packages/debian/create_package_file_service_spec.rb2
-rw-r--r--spec/services/packages/debian/extract_changes_metadata_service_spec.rb2
-rw-r--r--spec/services/packages/debian/extract_metadata_service_spec.rb86
-rw-r--r--spec/services/packages/debian/generate_distribution_service_spec.rb28
-rw-r--r--spec/services/packages/debian/parse_debian822_service_spec.rb20
-rw-r--r--spec/services/packages/debian/process_changes_service_spec.rb2
-rw-r--r--spec/services/packages/debian/process_package_file_service_spec.rb5
-rw-r--r--spec/services/packages/generic/create_package_file_service_spec.rb2
-rw-r--r--spec/services/packages/generic/find_or_create_package_service_spec.rb2
-rw-r--r--spec/services/packages/go/create_package_service_spec.rb2
-rw-r--r--spec/services/packages/go/sync_packages_service_spec.rb2
-rw-r--r--spec/services/packages/helm/extract_file_metadata_service_spec.rb2
-rw-r--r--spec/services/packages/helm/process_file_service_spec.rb2
-rw-r--r--spec/services/packages/mark_package_files_for_destruction_service_spec.rb3
-rw-r--r--spec/services/packages/mark_package_for_destruction_service_spec.rb8
-rw-r--r--spec/services/packages/mark_packages_for_destruction_service_spec.rb7
-rw-r--r--spec/services/packages/maven/create_package_service_spec.rb2
-rw-r--r--spec/services/packages/maven/find_or_create_package_service_spec.rb51
-rw-r--r--spec/services/packages/maven/metadata/append_package_file_service_spec.rb2
-rw-r--r--spec/services/packages/maven/metadata/create_plugins_xml_service_spec.rb2
-rw-r--r--spec/services/packages/maven/metadata/create_versions_xml_service_spec.rb2
-rw-r--r--spec/services/packages/maven/metadata/sync_service_spec.rb2
-rw-r--r--spec/services/packages/npm/create_package_service_spec.rb2
-rw-r--r--spec/services/packages/npm/create_tag_service_spec.rb2
-rw-r--r--spec/services/packages/nuget/create_dependency_service_spec.rb2
-rw-r--r--spec/services/packages/nuget/metadata_extraction_service_spec.rb2
-rw-r--r--spec/services/packages/nuget/search_service_spec.rb2
-rw-r--r--spec/services/packages/nuget/sync_metadatum_service_spec.rb2
-rw-r--r--spec/services/packages/nuget/update_package_from_metadata_service_spec.rb2
-rw-r--r--spec/services/packages/pypi/create_package_service_spec.rb2
-rw-r--r--spec/services/packages/remove_tag_service_spec.rb2
-rw-r--r--spec/services/packages/rpm/parse_package_service_spec.rb2
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb2
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb2
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb2
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb2
-rw-r--r--spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb2
-rw-r--r--spec/services/packages/rubygems/create_dependencies_service_spec.rb2
-rw-r--r--spec/services/packages/rubygems/create_gemspec_service_spec.rb2
-rw-r--r--spec/services/packages/rubygems/dependency_resolver_service_spec.rb2
-rw-r--r--spec/services/packages/rubygems/metadata_extraction_service_spec.rb2
-rw-r--r--spec/services/packages/rubygems/process_gem_service_spec.rb2
-rw-r--r--spec/services/packages/terraform_module/create_package_service_spec.rb2
-rw-r--r--spec/services/packages/update_package_file_service_spec.rb2
-rw-r--r--spec/services/packages/update_tags_service_spec.rb2
-rw-r--r--spec/services/pages/delete_service_spec.rb2
-rw-r--r--spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb2
-rw-r--r--spec/services/pages/zip_directory_service_spec.rb2
-rw-r--r--spec/services/pages_domains/create_acme_order_service_spec.rb2
-rw-r--r--spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb2
-rw-r--r--spec/services/personal_access_tokens/create_service_spec.rb20
-rw-r--r--spec/services/personal_access_tokens/last_used_service_spec.rb2
-rw-r--r--spec/services/personal_access_tokens/revoke_service_spec.rb2
-rw-r--r--spec/services/post_receive_service_spec.rb2
-rw-r--r--spec/services/preview_markdown_service_spec.rb2
-rw-r--r--spec/services/product_analytics/build_activity_graph_service_spec.rb2
-rw-r--r--spec/services/product_analytics/build_graph_service_spec.rb2
-rw-r--r--spec/services/projects/after_rename_service_spec.rb2
-rw-r--r--spec/services/projects/alerting/notify_service_spec.rb2
-rw-r--r--spec/services/projects/all_issues_count_service_spec.rb2
-rw-r--r--spec/services/projects/all_merge_requests_count_service_spec.rb2
-rw-r--r--spec/services/projects/android_target_platform_detector_service_spec.rb2
-rw-r--r--spec/services/projects/apple_target_platform_detector_service_spec.rb2
-rw-r--r--spec/services/projects/auto_devops/disable_service_spec.rb2
-rw-r--r--spec/services/projects/autocomplete_service_spec.rb2
-rw-r--r--spec/services/projects/batch_open_issues_count_service_spec.rb2
-rw-r--r--spec/services/projects/batch_open_merge_requests_count_service_spec.rb32
-rw-r--r--spec/services/projects/blame_service_spec.rb2
-rw-r--r--spec/services/projects/branches_by_mode_service_spec.rb2
-rw-r--r--spec/services/projects/cleanup_service_spec.rb2
-rw-r--r--spec/services/projects/container_repository/cleanup_tags_service_spec.rb7
-rw-r--r--spec/services/projects/container_repository/delete_tags_service_spec.rb2
-rw-r--r--spec/services/projects/container_repository/destroy_service_spec.rb2
-rw-r--r--spec/services/projects/container_repository/gitlab/cleanup_tags_service_spec.rb20
-rw-r--r--spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb2
-rw-r--r--spec/services/projects/container_repository/third_party/cleanup_tags_service_spec.rb2
-rw-r--r--spec/services/projects/container_repository/third_party/delete_tags_service_spec.rb2
-rw-r--r--spec/services/projects/count_service_spec.rb2
-rw-r--r--spec/services/projects/create_from_template_service_spec.rb2
-rw-r--r--spec/services/projects/deploy_tokens/create_service_spec.rb2
-rw-r--r--spec/services/projects/deploy_tokens/destroy_service_spec.rb2
-rw-r--r--spec/services/projects/detect_repository_languages_service_spec.rb2
-rw-r--r--spec/services/projects/download_service_spec.rb2
-rw-r--r--spec/services/projects/enable_deploy_key_service_spec.rb2
-rw-r--r--spec/services/projects/fetch_statistics_increment_service_spec.rb2
-rw-r--r--spec/services/projects/fork_service_spec.rb2
-rw-r--r--spec/services/projects/forks/sync_service_spec.rb185
-rw-r--r--spec/services/projects/forks_count_service_spec.rb2
-rw-r--r--spec/services/projects/git_deduplication_service_spec.rb2
-rw-r--r--spec/services/projects/gitlab_projects_import_service_spec.rb2
-rw-r--r--spec/services/projects/group_links/create_service_spec.rb2
-rw-r--r--spec/services/projects/group_links/destroy_service_spec.rb2
-rw-r--r--spec/services/projects/group_links/update_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/base_attachment_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/migrate_repository_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/migration_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/rollback_repository_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/rollback_service_spec.rb2
-rw-r--r--spec/services/projects/import_error_filter_spec.rb2
-rw-r--r--spec/services/projects/import_export/relation_export_service_spec.rb4
-rw-r--r--spec/services/projects/in_product_marketing_campaign_emails_service_spec.rb2
-rw-r--r--spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb2
-rw-r--r--spec/services/projects/lfs_pointers/lfs_download_service_spec.rb2
-rw-r--r--spec/services/projects/lfs_pointers/lfs_import_service_spec.rb2
-rw-r--r--spec/services/projects/lfs_pointers/lfs_link_service_spec.rb21
-rw-r--r--spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb2
-rw-r--r--spec/services/projects/move_access_service_spec.rb2
-rw-r--r--spec/services/projects/move_deploy_keys_projects_service_spec.rb2
-rw-r--r--spec/services/projects/move_forks_service_spec.rb2
-rw-r--r--spec/services/projects/move_lfs_objects_projects_service_spec.rb2
-rw-r--r--spec/services/projects/move_notification_settings_service_spec.rb2
-rw-r--r--spec/services/projects/move_project_authorizations_service_spec.rb2
-rw-r--r--spec/services/projects/move_project_group_links_service_spec.rb2
-rw-r--r--spec/services/projects/move_project_members_service_spec.rb2
-rw-r--r--spec/services/projects/move_users_star_projects_service_spec.rb2
-rw-r--r--spec/services/projects/open_issues_count_service_spec.rb2
-rw-r--r--spec/services/projects/open_merge_requests_count_service_spec.rb2
-rw-r--r--spec/services/projects/operations/update_service_spec.rb2
-rw-r--r--spec/services/projects/overwrite_project_service_spec.rb2
-rw-r--r--spec/services/projects/participants_service_spec.rb2
-rw-r--r--spec/services/projects/prometheus/alerts/notify_service_spec.rb2
-rw-r--r--spec/services/projects/prometheus/metrics/destroy_service_spec.rb2
-rw-r--r--spec/services/projects/protect_default_branch_service_spec.rb2
-rw-r--r--spec/services/projects/readme_renderer_service_spec.rb2
-rw-r--r--spec/services/projects/record_target_platforms_service_spec.rb2
-rw-r--r--spec/services/projects/refresh_build_artifacts_size_statistics_service_spec.rb2
-rw-r--r--spec/services/projects/repository_languages_service_spec.rb2
-rw-r--r--spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb2
-rw-r--r--spec/services/projects/transfer_service_spec.rb2
-rw-r--r--spec/services/projects/unlink_fork_service_spec.rb2
-rw-r--r--spec/services/projects/update_pages_service_spec.rb2
-rw-r--r--spec/services/projects/update_remote_mirror_service_spec.rb2
-rw-r--r--spec/services/projects/update_repository_storage_service_spec.rb2
-rw-r--r--spec/services/projects/update_service_spec.rb154
-rw-r--r--spec/services/projects/update_statistics_service_spec.rb2
-rw-r--r--spec/services/prometheus/proxy_service_spec.rb2
-rw-r--r--spec/services/prometheus/proxy_variable_substitution_service_spec.rb2
-rw-r--r--spec/services/protected_branches/api_service_spec.rb2
-rw-r--r--spec/services/protected_branches/cache_service_spec.rb2
-rw-r--r--spec/services/protected_branches/destroy_service_spec.rb2
-rw-r--r--spec/services/protected_branches/update_service_spec.rb2
-rw-r--r--spec/services/protected_tags/create_service_spec.rb2
-rw-r--r--spec/services/protected_tags/destroy_service_spec.rb2
-rw-r--r--spec/services/protected_tags/update_service_spec.rb2
-rw-r--r--spec/services/push_event_payload_service_spec.rb2
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb4
-rw-r--r--spec/services/quick_actions/target_service_spec.rb2
-rw-r--r--spec/services/releases/create_evidence_service_spec.rb2
-rw-r--r--spec/services/releases/destroy_service_spec.rb2
-rw-r--r--spec/services/releases/links/create_service_spec.rb84
-rw-r--r--spec/services/releases/links/destroy_service_spec.rb72
-rw-r--r--spec/services/releases/links/update_service_spec.rb89
-rw-r--r--spec/services/repositories/changelog_service_spec.rb2
-rw-r--r--spec/services/repositories/destroy_service_spec.rb2
-rw-r--r--spec/services/repository_archive_clean_up_service_spec.rb2
-rw-r--r--spec/services/reset_project_cache_service_spec.rb2
-rw-r--r--spec/services/resource_access_tokens/create_service_spec.rb56
-rw-r--r--spec/services/resource_access_tokens/revoke_service_spec.rb2
-rw-r--r--spec/services/resource_events/change_labels_service_spec.rb2
-rw-r--r--spec/services/resource_events/change_milestone_service_spec.rb2
-rw-r--r--spec/services/resource_events/change_state_service_spec.rb2
-rw-r--r--spec/services/resource_events/merge_into_notes_service_spec.rb2
-rw-r--r--spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb2
-rw-r--r--spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb2
-rw-r--r--spec/services/resource_events/synthetic_state_notes_builder_service_spec.rb2
-rw-r--r--spec/services/search/global_service_spec.rb2
-rw-r--r--spec/services/search/group_service_spec.rb2
-rw-r--r--spec/services/search/snippet_service_spec.rb2
-rw-r--r--spec/services/security/ci_configuration/container_scanning_create_service_spec.rb2
-rw-r--r--spec/services/security/ci_configuration/sast_iac_create_service_spec.rb2
-rw-r--r--spec/services/security/ci_configuration/sast_parser_service_spec.rb2
-rw-r--r--spec/services/security/ci_configuration/secret_detection_create_service_spec.rb2
-rw-r--r--spec/services/security/merge_reports_service_spec.rb2
-rw-r--r--spec/services/serverless/associate_domain_service_spec.rb91
-rw-r--r--spec/services/service_desk_settings/update_service_spec.rb2
-rw-r--r--spec/services/service_ping/submit_service_ping_service_spec.rb2
-rw-r--r--spec/services/service_response_spec.rb2
-rw-r--r--spec/services/snippets/bulk_destroy_service_spec.rb2
-rw-r--r--spec/services/snippets/count_service_spec.rb2
-rw-r--r--spec/services/snippets/create_service_spec.rb2
-rw-r--r--spec/services/snippets/destroy_service_spec.rb2
-rw-r--r--spec/services/snippets/repository_validation_service_spec.rb2
-rw-r--r--spec/services/snippets/schedule_bulk_repository_shard_moves_service_spec.rb2
-rw-r--r--spec/services/snippets/update_repository_storage_service_spec.rb2
-rw-r--r--spec/services/snippets/update_service_spec.rb2
-rw-r--r--spec/services/snippets/update_statistics_service_spec.rb2
-rw-r--r--spec/services/spam/akismet_mark_as_spam_service_spec.rb2
-rw-r--r--spec/services/spam/akismet_service_spec.rb2
-rw-r--r--spec/services/spam/ham_service_spec.rb2
-rw-r--r--spec/services/spam/spam_action_service_spec.rb2
-rw-r--r--spec/services/spam/spam_params_spec.rb2
-rw-r--r--spec/services/spam/spam_verdict_service_spec.rb2
-rw-r--r--spec/services/submodules/update_service_spec.rb2
-rw-r--r--spec/services/suggestions/apply_service_spec.rb2
-rw-r--r--spec/services/suggestions/create_service_spec.rb2
-rw-r--r--spec/services/suggestions/outdate_service_spec.rb2
-rw-r--r--spec/services/system_hooks_service_spec.rb2
-rw-r--r--spec/services/system_notes/alert_management_service_spec.rb2
-rw-r--r--spec/services/system_notes/base_service_spec.rb2
-rw-r--r--spec/services/system_notes/commit_service_spec.rb82
-rw-r--r--spec/services/system_notes/design_management_service_spec.rb2
-rw-r--r--spec/services/system_notes/incident_service_spec.rb2
-rw-r--r--spec/services/system_notes/incidents_service_spec.rb2
-rw-r--r--spec/services/system_notes/issuables_service_spec.rb2
-rw-r--r--spec/services/system_notes/merge_requests_service_spec.rb2
-rw-r--r--spec/services/system_notes/time_tracking_service_spec.rb2
-rw-r--r--spec/services/system_notes/zoom_service_spec.rb2
-rw-r--r--spec/services/tags/create_service_spec.rb2
-rw-r--r--spec/services/tags/destroy_service_spec.rb2
-rw-r--r--spec/services/task_list_toggle_service_spec.rb2
-rw-r--r--spec/services/tasks_to_be_done/base_service_spec.rb2
-rw-r--r--spec/services/terraform/remote_state_handler_spec.rb2
-rw-r--r--spec/services/terraform/states/destroy_service_spec.rb2
-rw-r--r--spec/services/terraform/states/trigger_destroy_service_spec.rb2
-rw-r--r--spec/services/test_hooks/project_service_spec.rb2
-rw-r--r--spec/services/test_hooks/system_service_spec.rb2
-rw-r--r--spec/services/timelogs/delete_service_spec.rb2
-rw-r--r--spec/services/todo_service_spec.rb3
-rw-r--r--spec/services/todos/allowed_target_filter_service_spec.rb2
-rw-r--r--spec/services/todos/destroy/confidential_issue_service_spec.rb2
-rw-r--r--spec/services/todos/destroy/design_service_spec.rb2
-rw-r--r--spec/services/todos/destroy/destroyed_issuable_service_spec.rb2
-rw-r--r--spec/services/todos/destroy/project_private_service_spec.rb2
-rw-r--r--spec/services/todos/destroy/unauthorized_features_service_spec.rb2
-rw-r--r--spec/services/topics/merge_service_spec.rb2
-rw-r--r--spec/services/two_factor/destroy_service_spec.rb2
-rw-r--r--spec/services/update_container_registry_info_service_spec.rb2
-rw-r--r--spec/services/update_merge_request_metrics_service_spec.rb2
-rw-r--r--spec/services/upload_service_spec.rb2
-rw-r--r--spec/services/uploads/destroy_service_spec.rb2
-rw-r--r--spec/services/user_preferences/update_service_spec.rb2
-rw-r--r--spec/services/user_project_access_changed_service_spec.rb2
-rw-r--r--spec/services/users/activity_service_spec.rb2
-rw-r--r--spec/services/users/approve_service_spec.rb2
-rw-r--r--spec/services/users/authorized_build_service_spec.rb2
-rw-r--r--spec/services/users/ban_service_spec.rb2
-rw-r--r--spec/services/users/banned_user_base_service_spec.rb2
-rw-r--r--spec/services/users/batch_status_cleaner_service_spec.rb2
-rw-r--r--spec/services/users/block_service_spec.rb2
-rw-r--r--spec/services/users/build_service_spec.rb2
-rw-r--r--spec/services/users/create_service_spec.rb2
-rw-r--r--spec/services/users/destroy_service_spec.rb2
-rw-r--r--spec/services/users/dismiss_callout_service_spec.rb2
-rw-r--r--spec/services/users/dismiss_group_callout_service_spec.rb2
-rw-r--r--spec/services/users/dismiss_project_callout_service_spec.rb2
-rw-r--r--spec/services/users/email_verification/generate_token_service_spec.rb2
-rw-r--r--spec/services/users/email_verification/validate_token_service_spec.rb2
-rw-r--r--spec/services/users/in_product_marketing_email_records_spec.rb2
-rw-r--r--spec/services/users/keys_count_service_spec.rb2
-rw-r--r--spec/services/users/last_push_event_service_spec.rb2
-rw-r--r--spec/services/users/migrate_records_to_ghost_user_in_batches_service_spec.rb2
-rw-r--r--spec/services/users/migrate_records_to_ghost_user_service_spec.rb2
-rw-r--r--spec/services/users/refresh_authorized_projects_service_spec.rb2
-rw-r--r--spec/services/users/registrations_build_service_spec.rb2
-rw-r--r--spec/services/users/reject_service_spec.rb2
-rw-r--r--spec/services/users/repair_ldap_blocked_service_spec.rb2
-rw-r--r--spec/services/users/respond_to_terms_service_spec.rb2
-rw-r--r--spec/services/users/saved_replies/create_service_spec.rb2
-rw-r--r--spec/services/users/saved_replies/destroy_service_spec.rb2
-rw-r--r--spec/services/users/saved_replies/update_service_spec.rb2
-rw-r--r--spec/services/users/set_status_service_spec.rb2
-rw-r--r--spec/services/users/signup_service_spec.rb8
-rw-r--r--spec/services/users/unban_service_spec.rb2
-rw-r--r--spec/services/users/unblock_service_spec.rb2
-rw-r--r--spec/services/users/update_canonical_email_service_spec.rb2
-rw-r--r--spec/services/users/update_highest_member_role_service_spec.rb2
-rw-r--r--spec/services/users/update_service_spec.rb2
-rw-r--r--spec/services/users/update_todo_count_cache_service_spec.rb2
-rw-r--r--spec/services/users/upsert_credit_card_validation_service_spec.rb2
-rw-r--r--spec/services/users/validate_manual_otp_service_spec.rb33
-rw-r--r--spec/services/users/validate_push_otp_service_spec.rb2
-rw-r--r--spec/services/verify_pages_domain_service_spec.rb2
-rw-r--r--spec/services/web_hooks/destroy_service_spec.rb2
-rw-r--r--spec/services/web_hooks/log_destroy_service_spec.rb2
-rw-r--r--spec/services/web_hooks/log_execution_service_spec.rb2
-rw-r--r--spec/services/webauthn/authenticate_service_spec.rb2
-rw-r--r--spec/services/webauthn/register_service_spec.rb2
-rw-r--r--spec/services/wiki_pages/base_service_spec.rb2
-rw-r--r--spec/services/wiki_pages/create_service_spec.rb2
-rw-r--r--spec/services/wiki_pages/destroy_service_spec.rb2
-rw-r--r--spec/services/wiki_pages/event_create_service_spec.rb2
-rw-r--r--spec/services/wiki_pages/update_service_spec.rb2
-rw-r--r--spec/services/wikis/create_attachment_service_spec.rb2
-rw-r--r--spec/services/work_items/build_service_spec.rb2
-rw-r--r--spec/services/work_items/create_from_task_service_spec.rb2
-rw-r--r--spec/services/work_items/create_service_spec.rb2
-rw-r--r--spec/services/work_items/delete_service_spec.rb2
-rw-r--r--spec/services/work_items/delete_task_service_spec.rb2
-rw-r--r--spec/services/work_items/export_csv_service_spec.rb5
-rw-r--r--spec/services/work_items/import_csv_service_spec.rb122
-rw-r--r--spec/services/work_items/parent_links/create_service_spec.rb34
-rw-r--r--spec/services/work_items/parent_links/destroy_service_spec.rb2
-rw-r--r--spec/services/work_items/task_list_reference_removal_service_spec.rb2
-rw-r--r--spec/services/work_items/task_list_reference_replacement_service_spec.rb2
-rw-r--r--spec/services/work_items/update_service_spec.rb2
-rw-r--r--spec/services/work_items/widgets/assignees_service/update_service_spec.rb2
-rw-r--r--spec/services/work_items/widgets/description_service/update_service_spec.rb2
-rw-r--r--spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb31
-rw-r--r--spec/services/work_items/widgets/milestone_service/create_service_spec.rb2
-rw-r--r--spec/services/work_items/widgets/milestone_service/update_service_spec.rb2
-rw-r--r--spec/services/work_items/widgets/notifications_service/update_service_spec.rb117
-rw-r--r--spec/services/work_items/widgets/start_and_due_date_service/update_service_spec.rb2
-rw-r--r--spec/services/x509_certificate_revoke_service_spec.rb2
-rw-r--r--spec/simplecov_env.rb1
-rw-r--r--spec/spec_helper.rb40
-rw-r--r--spec/support/ability_check.rb73
-rw-r--r--spec/support/ability_check_todo.yml73
-rw-r--r--spec/support/helpers/ci/template_helpers.rb4
-rw-r--r--spec/support/helpers/content_editor_helpers.rb58
-rw-r--r--spec/support/helpers/fake_u2f_device.rb47
-rw-r--r--spec/support/helpers/features/two_factor_helpers.rb41
-rw-r--r--spec/support/helpers/filtered_search_helpers.rb11
-rw-r--r--spec/support/helpers/fixture_helpers.rb2
-rw-r--r--spec/support/helpers/gitaly_setup.rb17
-rw-r--r--spec/support/helpers/graphql_helpers.rb4
-rw-r--r--spec/support/helpers/login_helpers.rb14
-rw-r--r--spec/support/helpers/navbar_structure_helper.rb8
-rw-r--r--spec/support/helpers/query_recorder.rb4
-rw-r--r--spec/support/helpers/repo_helpers.rb4
-rw-r--r--spec/support/helpers/stub_configuration.rb2
-rw-r--r--spec/support/helpers/stub_object_storage.rb4
-rw-r--r--spec/support/helpers/test_env.rb1
-rw-r--r--spec/support/helpers/usage_data_helpers.rb2
-rw-r--r--spec/support/matchers/background_migrations_matchers.rb14
-rw-r--r--spec/support/matchers/exceed_redis_call_limit.rb57
-rw-r--r--spec/support/matchers/request_urgency_matcher.rb29
-rw-r--r--spec/support/permissions_check.rb18
-rw-r--r--spec/support/protected_tags/access_control_ce_shared_examples.rb27
-rw-r--r--spec/support/rspec.rb7
-rw-r--r--spec/support/rspec_order_todo.yml12
-rw-r--r--spec/support/services/import_csv_service_shared_examples.rb38
-rw-r--r--spec/support/services/issuable_import_csv_service_shared_examples.rb37
-rw-r--r--spec/support/shared_contexts/features/integrations/integrations_shared_context.rb6
-rw-r--r--spec/support/shared_contexts/navbar_structure_context.rb52
-rw-r--r--spec/support/shared_contexts/policies/group_policy_shared_context.rb5
-rw-r--r--spec/support/shared_contexts/policies/project_policy_shared_context.rb15
-rw-r--r--spec/support/shared_contexts/rack_attack_shared_context.rb3
-rw-r--r--spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb3
-rw-r--r--spec/support/shared_contexts/security_and_compliance_permissions_shared_context.rb4
-rw-r--r--spec/support/shared_examples/analytics/cycle_analytics/flow_metrics_examples.rb464
-rw-r--r--spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb127
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/features/2fa_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/abuse_report_shared_examples.rb14
-rw-r--r--spec/support/shared_examples/features/content_editor_shared_examples.rb97
-rw-r--r--spec/support/shared_examples/features/incident_details_routing_shared_examples.rb14
-rw-r--r--spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/manage_applications_shared_examples.rb93
-rw-r--r--spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb61
-rw-r--r--spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/trial_email_validation_shared_example.rb67
-rw-r--r--spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb66
-rw-r--r--spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb24
-rw-r--r--spec/support/shared_examples/features/work_items_shared_examples.rb47
-rw-r--r--spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb123
-rw-r--r--spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb154
-rw-r--r--spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/helpers/callouts_for_web_hooks.rb49
-rw-r--r--spec/support/shared_examples/integrations/integration_settings_form.rb1
-rw-r--r--spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb131
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb38
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb20
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb33
-rw-r--r--spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb104
-rw-r--r--spec/support/shared_examples/lib/menus_shared_examples.rb24
-rw-r--r--spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb89
-rw-r--r--spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb52
-rw-r--r--spec/support/shared_examples/mailers/export_csv_shared_examples.rb37
-rw-r--r--spec/support/shared_examples/models/active_record_enum_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/models/ci/token_format_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/models/concerns/auto_disabling_hooks_shared_examples.rb98
-rw-r--r--spec/support/shared_examples/models/concerns/cascading_namespace_setting_shared_examples.rb56
-rw-r--r--spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb48
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/models/concerns/unstoppable_hooks_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/models/concerns/web_hooks/has_web_hooks_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb16
-rw-r--r--spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/observability/csp_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/observability/embed_observabilities_examples.rb61
-rw-r--r--spec/support/shared_examples/policies/project_policy_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/requests/admin_mode_shared_examples.rb71
-rw-r--r--spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb26
-rw-r--r--spec/support/shared_examples/requests/api/discussions_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/requests/api/hooks_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb455
-rw-r--r--spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb5
-rw-r--r--spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/requests/api/status_shared_examples.rb17
-rw-r--r--spec/support/shared_examples/requests/applications_controller_shared_examples.rb30
-rw-r--r--spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb141
-rw-r--r--spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/services/security/ci_configuration/create_service_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb1
-rw-r--r--spec/support/stub_dot_com_check.rb20
-rw-r--r--spec/support_specs/ability_check_spec.rb148
-rw-r--r--spec/support_specs/helpers/packages/npm_spec.rb133
-rw-r--r--spec/support_specs/matchers/exceed_redis_call_limit_spec.rb59
-rw-r--r--spec/tasks/gitlab/db/decomposition/connection_status_spec.rb61
-rw-r--r--spec/tasks/gitlab/db_rake_spec.rb145
-rw-r--r--spec/tasks/gitlab/feature_categories_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/security/update_banned_ssh_keys_rake_spec.rb2
-rw-r--r--spec/tooling/danger/sidekiq_args_spec.rb125
-rw-r--r--spec/tooling/danger/specs_spec.rb10
-rw-r--r--spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb14
-rw-r--r--spec/uploaders/gitlab_uploader_spec.rb17
-rw-r--r--spec/uploaders/object_storage/cdn_spec.rb88
-rw-r--r--spec/uploaders/object_storage_spec.rb2
-rw-r--r--spec/validators/addressable_url_validator_spec.rb70
-rw-r--r--spec/views/admin/application_settings/ci_cd.html.haml_spec.rb5
-rw-r--r--spec/views/admin/application_settings/network.html.haml_spec.rb33
-rw-r--r--spec/views/admin/sessions/two_factor.html.haml_spec.rb10
-rw-r--r--spec/views/devise/confirmations/almost_there.html.haml_spec.rb17
-rw-r--r--spec/views/devise/sessions/new.html.haml_spec.rb3
-rw-r--r--spec/views/devise/shared/_error_messages.html.haml_spec.rb43
-rw-r--r--spec/views/devise/shared/_signup_box.html.haml_spec.rb1
-rw-r--r--spec/views/events/event/_common.html.haml_spec.rb13
-rw-r--r--spec/views/groups/group_members/index.html.haml_spec.rb1
-rw-r--r--spec/views/layouts/group.html.haml_spec.rb30
-rw-r--r--spec/views/layouts/header/_new_dropdown.haml_spec.rb27
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb14
-rw-r--r--spec/views/layouts/project.html.haml_spec.rb29
-rw-r--r--spec/views/notify/import_issues_csv_email.html.haml_spec.rb4
-rw-r--r--spec/views/notify/import_work_items_csv_email.html.haml_spec.rb133
-rw-r--r--spec/views/profiles/keys/_key.html.haml_spec.rb21
-rw-r--r--spec/views/projects/edit.html.haml_spec.rb24
-rw-r--r--spec/views/projects/empty.html.haml_spec.rb4
-rw-r--r--spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb4
-rw-r--r--spec/views/projects/pipelines/show.html.haml_spec.rb19
-rw-r--r--spec/views/projects/project_members/index.html.haml_spec.rb1
-rw-r--r--spec/workers/admin_email_worker_spec.rb2
-rw-r--r--spec/workers/analytics/usage_trends/count_job_trigger_worker_spec.rb2
-rw-r--r--spec/workers/analytics/usage_trends/counter_job_worker_spec.rb2
-rw-r--r--spec/workers/approve_blocked_pending_approval_users_worker_spec.rb2
-rw-r--r--spec/workers/authorized_keys_worker_spec.rb2
-rw-r--r--spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb2
-rw-r--r--spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb2
-rw-r--r--spec/workers/authorized_project_update/project_recalculate_worker_spec.rb2
-rw-r--r--spec/workers/authorized_project_update/user_refresh_from_replica_worker_spec.rb2
-rw-r--r--spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb2
-rw-r--r--spec/workers/authorized_project_update/user_refresh_with_low_urgency_worker_spec.rb2
-rw-r--r--spec/workers/authorized_projects_worker_spec.rb2
-rw-r--r--spec/workers/auto_devops/disable_worker_spec.rb2
-rw-r--r--spec/workers/auto_merge_process_worker_spec.rb2
-rw-r--r--spec/workers/background_migration/ci_database_worker_spec.rb2
-rw-r--r--spec/workers/background_migration_worker_spec.rb2
-rw-r--r--spec/workers/build_hooks_worker_spec.rb2
-rw-r--r--spec/workers/build_queue_worker_spec.rb2
-rw-r--r--spec/workers/build_success_worker_spec.rb2
-rw-r--r--spec/workers/bulk_imports/entity_worker_spec.rb2
-rw-r--r--spec/workers/bulk_imports/relation_export_worker_spec.rb2
-rw-r--r--spec/workers/bulk_imports/stuck_import_worker_spec.rb2
-rw-r--r--spec/workers/chat_notification_worker_spec.rb2
-rw-r--r--spec/workers/ci/archive_trace_worker_spec.rb2
-rw-r--r--spec/workers/ci/archive_traces_cron_worker_spec.rb14
-rw-r--r--spec/workers/ci/build_finished_worker_spec.rb2
-rw-r--r--spec/workers/ci/build_prepare_worker_spec.rb2
-rw-r--r--spec/workers/ci/build_schedule_worker_spec.rb2
-rw-r--r--spec/workers/ci/build_trace_chunk_flush_worker_spec.rb2
-rw-r--r--spec/workers/ci/cancel_pipeline_worker_spec.rb2
-rw-r--r--spec/workers/ci/create_cross_project_pipeline_worker_spec.rb2
-rw-r--r--spec/workers/ci/create_downstream_pipeline_worker_spec.rb2
-rw-r--r--spec/workers/ci/daily_build_group_report_results_worker_spec.rb2
-rw-r--r--spec/workers/ci/delete_objects_worker_spec.rb2
-rw-r--r--spec/workers/ci/delete_unit_tests_worker_spec.rb2
-rw-r--r--spec/workers/ci/drop_pipeline_worker_spec.rb2
-rw-r--r--spec/workers/ci/job_artifacts/expire_project_build_artifacts_worker_spec.rb2
-rw-r--r--spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb2
-rw-r--r--spec/workers/ci/merge_requests/add_todo_when_build_fails_worker_spec.rb2
-rw-r--r--spec/workers/ci/parse_secure_file_metadata_worker_spec.rb2
-rw-r--r--spec/workers/ci/pending_builds/update_group_worker_spec.rb2
-rw-r--r--spec/workers/ci/pending_builds/update_project_worker_spec.rb2
-rw-r--r--spec/workers/ci/pipeline_artifacts/coverage_report_worker_spec.rb2
-rw-r--r--spec/workers/ci/pipeline_artifacts/create_quality_report_worker_spec.rb2
-rw-r--r--spec/workers/ci/pipeline_artifacts/expire_artifacts_worker_spec.rb2
-rw-r--r--spec/workers/ci/pipeline_bridge_status_worker_spec.rb2
-rw-r--r--spec/workers/ci/pipeline_success_unlock_artifacts_worker_spec.rb2
-rw-r--r--spec/workers/ci/ref_delete_unlock_artifacts_worker_spec.rb2
-rw-r--r--spec/workers/ci/resource_groups/assign_resource_from_resource_group_worker_spec.rb2
-rw-r--r--spec/workers/ci/retry_pipeline_worker_spec.rb2
-rw-r--r--spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb2
-rw-r--r--spec/workers/ci/stuck_builds/drop_running_worker_spec.rb2
-rw-r--r--spec/workers/ci/stuck_builds/drop_scheduled_worker_spec.rb2
-rw-r--r--spec/workers/ci/test_failure_history_worker_spec.rb2
-rw-r--r--spec/workers/ci/track_failed_build_worker_spec.rb2
-rw-r--r--spec/workers/ci/update_locked_unknown_artifacts_worker_spec.rb2
-rw-r--r--spec/workers/ci_platform_metrics_update_cron_worker_spec.rb2
-rw-r--r--spec/workers/cleanup_container_repository_worker_spec.rb2
-rw-r--r--spec/workers/clusters/agents/delete_expired_events_worker_spec.rb2
-rw-r--r--spec/workers/clusters/applications/activate_integration_worker_spec.rb2
-rw-r--r--spec/workers/clusters/applications/deactivate_integration_worker_spec.rb2
-rw-r--r--spec/workers/clusters/cleanup/project_namespace_worker_spec.rb2
-rw-r--r--spec/workers/clusters/cleanup/service_account_worker_spec.rb2
-rw-r--r--spec/workers/clusters/integrations/check_prometheus_health_worker_spec.rb2
-rw-r--r--spec/workers/concerns/application_worker_spec.rb2
-rw-r--r--spec/workers/concerns/cluster_agent_queue_spec.rb3
-rw-r--r--spec/workers/concerns/cluster_queue_spec.rb21
-rw-r--r--spec/workers/concerns/cronjob_queue_spec.rb6
-rw-r--r--spec/workers/concerns/gitlab/github_import/object_importer_spec.rb86
-rw-r--r--spec/workers/concerns/gitlab/github_import/queue_spec.rb18
-rw-r--r--spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/notify_upon_death_spec.rb2
-rw-r--r--spec/workers/concerns/limited_capacity/job_tracker_spec.rb2
-rw-r--r--spec/workers/concerns/limited_capacity/worker_spec.rb2
-rw-r--r--spec/workers/concerns/packages/cleanup_artifact_worker_spec.rb2
-rw-r--r--spec/workers/concerns/pipeline_background_queue_spec.rb21
-rw-r--r--spec/workers/concerns/pipeline_queue_spec.rb21
-rw-r--r--spec/workers/concerns/project_import_options_spec.rb2
-rw-r--r--spec/workers/concerns/reenqueuer_spec.rb2
-rw-r--r--spec/workers/concerns/repository_check_queue_spec.rb6
-rw-r--r--spec/workers/concerns/waitable_worker_spec.rb2
-rw-r--r--spec/workers/concerns/worker_attributes_spec.rb2
-rw-r--r--spec/workers/concerns/worker_context_spec.rb2
-rw-r--r--spec/workers/container_expiration_policies/cleanup_container_repository_worker_spec.rb30
-rw-r--r--spec/workers/container_expiration_policy_worker_spec.rb12
-rw-r--r--spec/workers/container_registry/cleanup_worker_spec.rb2
-rw-r--r--spec/workers/container_registry/delete_container_repository_worker_spec.rb2
-rw-r--r--spec/workers/container_registry/migration/enqueuer_worker_spec.rb3
-rw-r--r--spec/workers/container_registry/migration/guard_worker_spec.rb2
-rw-r--r--spec/workers/container_registry/migration/observer_worker_spec.rb2
-rw-r--r--spec/workers/counters/cleanup_refresh_worker_spec.rb2
-rw-r--r--spec/workers/create_commit_signature_worker_spec.rb2
-rw-r--r--spec/workers/create_note_diff_file_worker_spec.rb2
-rw-r--r--spec/workers/create_pipeline_worker_spec.rb2
-rw-r--r--spec/workers/database/batched_background_migration/ci_database_worker_spec.rb2
-rw-r--r--spec/workers/database/batched_background_migration_worker_spec.rb2
-rw-r--r--spec/workers/database/ci_namespace_mirrors_consistency_check_worker_spec.rb2
-rw-r--r--spec/workers/database/ci_project_mirrors_consistency_check_worker_spec.rb2
-rw-r--r--spec/workers/database/drop_detached_partitions_worker_spec.rb2
-rw-r--r--spec/workers/database/partition_management_worker_spec.rb2
-rw-r--r--spec/workers/delete_container_repository_worker_spec.rb2
-rw-r--r--spec/workers/delete_diff_files_worker_spec.rb2
-rw-r--r--spec/workers/delete_merged_branches_worker_spec.rb2
-rw-r--r--spec/workers/delete_user_worker_spec.rb2
-rw-r--r--spec/workers/dependency_proxy/cleanup_blob_worker_spec.rb2
-rw-r--r--spec/workers/dependency_proxy/cleanup_dependency_proxy_worker_spec.rb2
-rw-r--r--spec/workers/dependency_proxy/cleanup_manifest_worker_spec.rb2
-rw-r--r--spec/workers/dependency_proxy/image_ttl_group_policy_worker_spec.rb2
-rw-r--r--spec/workers/deployments/archive_in_project_worker_spec.rb2
-rw-r--r--spec/workers/deployments/drop_older_deployments_worker_spec.rb2
-rw-r--r--spec/workers/deployments/hooks_worker_spec.rb2
-rw-r--r--spec/workers/deployments/link_merge_request_worker_spec.rb2
-rw-r--r--spec/workers/deployments/update_environment_worker_spec.rb2
-rw-r--r--spec/workers/design_management/copy_design_collection_worker_spec.rb2
-rw-r--r--spec/workers/design_management/new_version_worker_spec.rb2
-rw-r--r--spec/workers/destroy_pages_deployments_worker_spec.rb2
-rw-r--r--spec/workers/detect_repository_languages_worker_spec.rb2
-rw-r--r--spec/workers/disallow_two_factor_for_group_worker_spec.rb2
-rw-r--r--spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb2
-rw-r--r--spec/workers/email_receiver_worker_spec.rb2
-rw-r--r--spec/workers/emails_on_push_worker_spec.rb10
-rw-r--r--spec/workers/environments/auto_delete_cron_worker_spec.rb2
-rw-r--r--spec/workers/environments/auto_stop_cron_worker_spec.rb2
-rw-r--r--spec/workers/environments/auto_stop_worker_spec.rb2
-rw-r--r--spec/workers/environments/canary_ingress/update_worker_spec.rb2
-rw-r--r--spec/workers/error_tracking_issue_link_worker_spec.rb2
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb4
-rw-r--r--spec/workers/expire_build_artifacts_worker_spec.rb2
-rw-r--r--spec/workers/export_csv_worker_spec.rb2
-rw-r--r--spec/workers/external_service_reactive_caching_worker_spec.rb2
-rw-r--r--spec/workers/file_hook_worker_spec.rb2
-rw-r--r--spec/workers/flush_counter_increments_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/advance_stage_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/attachments/import_issue_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/attachments/import_merge_request_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/attachments/import_note_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/attachments/import_release_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_collaborator_worker_spec.rb38
-rw-r--r--spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_issue_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_note_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_protected_branch_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_pull_request_merged_by_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_pull_request_review_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_release_attachments_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_attachments_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_collaborators_worker_spec.rb73
-rw-r--r--spec/workers/gitlab/github_import/stage/import_issue_events_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_protected_branches_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb4
-rw-r--r--spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb10
-rw-r--r--spec/workers/gitlab/import/stuck_import_job_spec.rb2
-rw-r--r--spec/workers/gitlab/import/stuck_project_import_jobs_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/jira_import/import_issue_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/jira_import/stuck_jira_import_jobs_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/phabricator_import/base_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/phabricator_import/import_tasks_worker_spec.rb2
-rw-r--r--spec/workers/gitlab_performance_bar_stats_worker_spec.rb2
-rw-r--r--spec/workers/gitlab_service_ping_worker_spec.rb8
-rw-r--r--spec/workers/gitlab_shell_worker_spec.rb2
-rw-r--r--spec/workers/google_cloud/create_cloudsql_instance_worker_spec.rb2
-rw-r--r--spec/workers/group_destroy_worker_spec.rb23
-rw-r--r--spec/workers/group_export_worker_spec.rb2
-rw-r--r--spec/workers/group_import_worker_spec.rb2
-rw-r--r--spec/workers/groups/update_statistics_worker_spec.rb2
-rw-r--r--spec/workers/groups/update_two_factor_requirement_for_members_worker_spec.rb2
-rw-r--r--spec/workers/hashed_storage/migrator_worker_spec.rb2
-rw-r--r--spec/workers/hashed_storage/project_migrate_worker_spec.rb2
-rw-r--r--spec/workers/hashed_storage/project_rollback_worker_spec.rb2
-rw-r--r--spec/workers/hashed_storage/rollbacker_worker_spec.rb2
-rw-r--r--spec/workers/import_issues_csv_worker_spec.rb2
-rw-r--r--spec/workers/incident_management/add_severity_system_note_worker_spec.rb2
-rw-r--r--spec/workers/incident_management/close_incident_worker_spec.rb2
-rw-r--r--spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb2
-rw-r--r--spec/workers/incident_management/process_alert_worker_v2_spec.rb2
-rw-r--r--spec/workers/integrations/create_external_cross_reference_worker_spec.rb2
-rw-r--r--spec/workers/integrations/execute_worker_spec.rb2
-rw-r--r--spec/workers/integrations/irker_worker_spec.rb2
-rw-r--r--spec/workers/invalid_gpg_signature_update_worker_spec.rb2
-rw-r--r--spec/workers/issuable/label_links_destroy_worker_spec.rb2
-rw-r--r--spec/workers/issuable_export_csv_worker_spec.rb45
-rw-r--r--spec/workers/issuables/clear_groups_issue_counter_worker_spec.rb2
-rw-r--r--spec/workers/issue_due_scheduler_worker_spec.rb2
-rw-r--r--spec/workers/issues/close_worker_spec.rb2
-rw-r--r--spec/workers/issues/placement_worker_spec.rb2
-rw-r--r--spec/workers/issues/rebalancing_worker_spec.rb2
-rw-r--r--spec/workers/issues/reschedule_stuck_issue_rebalances_worker_spec.rb2
-rw-r--r--spec/workers/jira_connect/forward_event_worker_spec.rb2
-rw-r--r--spec/workers/jira_connect/retry_request_worker_spec.rb2
-rw-r--r--spec/workers/jira_connect/sync_branch_worker_spec.rb2
-rw-r--r--spec/workers/jira_connect/sync_builds_worker_spec.rb2
-rw-r--r--spec/workers/jira_connect/sync_deployments_worker_spec.rb2
-rw-r--r--spec/workers/jira_connect/sync_feature_flags_worker_spec.rb2
-rw-r--r--spec/workers/jira_connect/sync_merge_request_worker_spec.rb2
-rw-r--r--spec/workers/jira_connect/sync_project_worker_spec.rb2
-rw-r--r--spec/workers/loose_foreign_keys/cleanup_worker_spec.rb2
-rw-r--r--spec/workers/mail_scheduler/issue_due_worker_spec.rb2
-rw-r--r--spec/workers/mail_scheduler/notification_service_worker_spec.rb2
-rw-r--r--spec/workers/member_invitation_reminder_emails_worker_spec.rb2
-rw-r--r--spec/workers/members_destroyer/unassign_issuables_worker_spec.rb2
-rw-r--r--spec/workers/merge_request_cleanup_refs_worker_spec.rb8
-rw-r--r--spec/workers/merge_request_mergeability_check_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/close_issue_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/create_approval_event_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/create_approval_note_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/delete_source_branch_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/execute_approval_hooks_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/handle_assignees_change_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/resolve_todos_after_approval_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/resolve_todos_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/update_head_pipeline_worker_spec.rb2
-rw-r--r--spec/workers/merge_worker_spec.rb2
-rw-r--r--spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb2
-rw-r--r--spec/workers/metrics/dashboard/schedule_annotations_prune_worker_spec.rb2
-rw-r--r--spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb2
-rw-r--r--spec/workers/migrate_external_diffs_worker_spec.rb2
-rw-r--r--spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb2
-rw-r--r--spec/workers/namespaces/process_sync_events_worker_spec.rb2
-rw-r--r--spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb2
-rw-r--r--spec/workers/namespaces/root_statistics_worker_spec.rb2
-rw-r--r--spec/workers/namespaces/schedule_aggregation_worker_spec.rb2
-rw-r--r--spec/workers/namespaces/update_root_statistics_worker_spec.rb2
-rw-r--r--spec/workers/new_issue_worker_spec.rb2
-rw-r--r--spec/workers/new_merge_request_worker_spec.rb12
-rw-r--r--spec/workers/new_note_worker_spec.rb2
-rw-r--r--spec/workers/object_pool/create_worker_spec.rb2
-rw-r--r--spec/workers/object_pool/destroy_worker_spec.rb2
-rw-r--r--spec/workers/object_pool/join_worker_spec.rb2
-rw-r--r--spec/workers/onboarding/issue_created_worker_spec.rb2
-rw-r--r--spec/workers/onboarding/pipeline_created_worker_spec.rb2
-rw-r--r--spec/workers/onboarding/progress_worker_spec.rb2
-rw-r--r--spec/workers/onboarding/user_added_worker_spec.rb2
-rw-r--r--spec/workers/packages/cleanup/execute_policy_worker_spec.rb2
-rw-r--r--spec/workers/packages/cleanup_package_file_worker_spec.rb2
-rw-r--r--spec/workers/packages/cleanup_package_registry_worker_spec.rb2
-rw-r--r--spec/workers/packages/composer/cache_cleanup_worker_spec.rb2
-rw-r--r--spec/workers/packages/composer/cache_update_worker_spec.rb2
-rw-r--r--spec/workers/packages/debian/generate_distribution_worker_spec.rb10
-rw-r--r--spec/workers/packages/debian/process_changes_worker_spec.rb6
-rw-r--r--spec/workers/packages/debian/process_package_file_worker_spec.rb1
-rw-r--r--spec/workers/packages/go/sync_packages_worker_spec.rb2
-rw-r--r--spec/workers/packages/helm/extraction_worker_spec.rb2
-rw-r--r--spec/workers/packages/mark_package_files_for_destruction_worker_spec.rb2
-rw-r--r--spec/workers/packages/nuget/extraction_worker_spec.rb2
-rw-r--r--spec/workers/packages/rubygems/extraction_worker_spec.rb2
-rw-r--r--spec/workers/pages_domain_removal_cron_worker_spec.rb2
-rw-r--r--spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb2
-rw-r--r--spec/workers/pages_domain_ssl_renewal_worker_spec.rb2
-rw-r--r--spec/workers/pages_domain_verification_cron_worker_spec.rb2
-rw-r--r--spec/workers/pages_domain_verification_worker_spec.rb2
-rw-r--r--spec/workers/pages_worker_spec.rb2
-rw-r--r--spec/workers/partition_creation_worker_spec.rb2
-rw-r--r--spec/workers/personal_access_tokens/expired_notification_worker_spec.rb2
-rw-r--r--spec/workers/personal_access_tokens/expiring_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_hooks_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_metrics_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_notification_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_process_worker_spec.rb2
-rw-r--r--spec/workers/post_receive_spec.rb3
-rw-r--r--spec/workers/process_commit_worker_spec.rb2
-rw-r--r--spec/workers/project_cache_worker_spec.rb2
-rw-r--r--spec/workers/project_destroy_worker_spec.rb25
-rw-r--r--spec/workers/project_export_worker_spec.rb2
-rw-r--r--spec/workers/projects/after_import_worker_spec.rb2
-rw-r--r--spec/workers/projects/finalize_project_statistics_refresh_worker_spec.rb2
-rw-r--r--spec/workers/projects/import_export/create_relation_exports_worker_spec.rb67
-rw-r--r--spec/workers/projects/import_export/relation_export_worker_spec.rb49
-rw-r--r--spec/workers/projects/import_export/wait_relation_exports_worker_spec.rb123
-rw-r--r--spec/workers/projects/inactive_projects_deletion_cron_worker_spec.rb2
-rw-r--r--spec/workers/projects/inactive_projects_deletion_notification_worker_spec.rb2
-rw-r--r--spec/workers/projects/post_creation_worker_spec.rb2
-rw-r--r--spec/workers/projects/process_sync_events_worker_spec.rb2
-rw-r--r--spec/workers/projects/record_target_platforms_worker_spec.rb2
-rw-r--r--spec/workers/projects/refresh_build_artifacts_size_statistics_worker_spec.rb2
-rw-r--r--spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb2
-rw-r--r--spec/workers/projects/schedule_refresh_build_artifacts_size_statistics_worker_spec.rb2
-rw-r--r--spec/workers/projects/update_repository_storage_worker_spec.rb2
-rw-r--r--spec/workers/propagate_integration_group_worker_spec.rb2
-rw-r--r--spec/workers/propagate_integration_inherit_descendant_worker_spec.rb2
-rw-r--r--spec/workers/propagate_integration_inherit_worker_spec.rb2
-rw-r--r--spec/workers/propagate_integration_worker_spec.rb2
-rw-r--r--spec/workers/prune_old_events_worker_spec.rb14
-rw-r--r--spec/workers/purge_dependency_proxy_cache_worker_spec.rb2
-rw-r--r--spec/workers/reactive_caching_worker_spec.rb2
-rw-r--r--spec/workers/rebase_worker_spec.rb2
-rw-r--r--spec/workers/releases/create_evidence_worker_spec.rb2
-rw-r--r--spec/workers/releases/manage_evidence_worker_spec.rb2
-rw-r--r--spec/workers/remote_mirror_notification_worker_spec.rb2
-rw-r--r--spec/workers/remove_expired_group_links_worker_spec.rb2
-rw-r--r--spec/workers/remove_expired_members_worker_spec.rb2
-rw-r--r--spec/workers/remove_unaccepted_member_invites_worker_spec.rb2
-rw-r--r--spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb2
-rw-r--r--spec/workers/repository_check/batch_worker_spec.rb2
-rw-r--r--spec/workers/repository_check/clear_worker_spec.rb2
-rw-r--r--spec/workers/repository_check/dispatch_worker_spec.rb2
-rw-r--r--spec/workers/repository_check/single_repository_worker_spec.rb2
-rw-r--r--spec/workers/repository_cleanup_worker_spec.rb2
-rw-r--r--spec/workers/repository_fork_worker_spec.rb2
-rw-r--r--spec/workers/repository_update_remote_mirror_worker_spec.rb2
-rw-r--r--spec/workers/schedule_merge_request_cleanup_refs_worker_spec.rb2
-rw-r--r--spec/workers/schedule_migrate_external_diffs_worker_spec.rb2
-rw-r--r--spec/workers/self_monitoring_project_create_worker_spec.rb2
-rw-r--r--spec/workers/self_monitoring_project_delete_worker_spec.rb2
-rw-r--r--spec/workers/service_desk_email_receiver_worker_spec.rb2
-rw-r--r--spec/workers/snippets/schedule_bulk_repository_shard_moves_worker_spec.rb2
-rw-r--r--spec/workers/snippets/update_repository_storage_worker_spec.rb2
-rw-r--r--spec/workers/ssh_keys/expired_notification_worker_spec.rb3
-rw-r--r--spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb3
-rw-r--r--spec/workers/stage_update_worker_spec.rb2
-rw-r--r--spec/workers/stuck_ci_jobs_worker_spec.rb2
-rw-r--r--spec/workers/stuck_export_jobs_worker_spec.rb2
-rw-r--r--spec/workers/stuck_merge_jobs_worker_spec.rb2
-rw-r--r--spec/workers/system_hook_push_worker_spec.rb2
-rw-r--r--spec/workers/tasks_to_be_done/create_worker_spec.rb2
-rw-r--r--spec/workers/terraform/states/destroy_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/confidential_issue_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/destroyed_designs_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/destroyed_issuable_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/entity_leave_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/group_private_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/private_features_worker_spec.rb2
-rw-r--r--spec/workers/todos_destroyer/project_private_worker_spec.rb2
-rw-r--r--spec/workers/trending_projects_worker_spec.rb2
-rw-r--r--spec/workers/update_container_registry_info_worker_spec.rb2
-rw-r--r--spec/workers/update_external_pull_requests_worker_spec.rb2
-rw-r--r--spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb2
-rw-r--r--spec/workers/update_highest_role_worker_spec.rb2
-rw-r--r--spec/workers/update_merge_requests_worker_spec.rb2
-rw-r--r--spec/workers/update_project_statistics_worker_spec.rb2
-rw-r--r--spec/workers/upload_checksum_worker_spec.rb2
-rw-r--r--spec/workers/user_status_cleanup/batch_worker_spec.rb2
-rw-r--r--spec/workers/users/create_statistics_worker_spec.rb2
-rw-r--r--spec/workers/users/deactivate_dormant_users_worker_spec.rb5
-rw-r--r--spec/workers/users/migrate_records_to_ghost_user_in_batches_worker_spec.rb2
-rw-r--r--spec/workers/web_hook_worker_spec.rb2
-rw-r--r--spec/workers/web_hooks/log_destroy_worker_spec.rb2
-rw-r--r--spec/workers/x509_certificate_revoke_worker_spec.rb2
-rw-r--r--spec/workers/x509_issuer_crl_check_worker_spec.rb2
-rw-r--r--tooling/danger/sidekiq_args.rb59
-rw-r--r--tooling/danger/sidekiq_queues.rb2
-rw-r--r--tooling/danger/specs.rb14
-rw-r--r--tooling/lib/tooling/find_codeowners.rb6
-rw-r--r--tooling/lib/tooling/kubernetes_client.rb26
-rw-r--r--tooling/lib/tooling/mappings/js_to_system_specs_mappings.rb1
-rw-r--r--tooling/lib/tooling/test_map_generator.rb4
-rw-r--r--vendor/assets/javascripts/u2f.js750
-rw-r--r--vendor/assets/javascripts/vue-virtual-scroller/src/components/RecycleScroller.vue4
-rw-r--r--vendor/gems/cloud_profiler_agent/.gitlab-ci.yml32
-rw-r--r--vendor/gems/cloud_profiler_agent/Gemfile4
-rw-r--r--vendor/gems/cloud_profiler_agent/Gemfile.lock126
-rw-r--r--vendor/gems/cloud_profiler_agent/LICENSE23
-rw-r--r--vendor/gems/cloud_profiler_agent/README.md30
-rw-r--r--vendor/gems/cloud_profiler_agent/cloud_profiler_agent.gemspec29
-rw-r--r--vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent.rb12
-rw-r--r--vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/agent.rb147
-rw-r--r--vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/looper.rb100
-rw-r--r--vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/pprof_builder.rb198
-rw-r--r--vendor/gems/cloud_profiler_agent/lib/profile_pb.rb85
-rwxr-xr-xvendor/gems/cloud_profiler_agent/script/generate_profile.rb17
-rw-r--r--vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/cpu.stackprofbin0 -> 1733 bytes
-rw-r--r--vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/looper_spec.rb157
-rw-r--r--vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/object.stackprofbin0 -> 11714 bytes
-rw-r--r--vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/pprof_builder_spec.rb122
-rw-r--r--vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/wall.stackprofbin0 -> 110819 bytes
-rw-r--r--vendor/gems/cloud_profiler_agent/spec/spec_helper.rb21
-rw-r--r--vendor/gems/kubeclient/.gitignore16
-rw-r--r--vendor/gems/kubeclient/CHANGELOG.md247
-rw-r--r--vendor/gems/kubeclient/Gemfile7
-rw-r--r--vendor/gems/kubeclient/LICENSE.txt22
-rw-r--r--vendor/gems/kubeclient/README.md889
-rw-r--r--vendor/gems/kubeclient/RELEASING.md69
-rw-r--r--vendor/gems/kubeclient/Rakefile9
-rw-r--r--vendor/gems/kubeclient/kubeclient.gemspec39
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient.rb35
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/aws_eks_credentials.rb46
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/common.rb661
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/config.rb202
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/entity_list.rb21
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/exec_credentials.rb89
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/gcp_auth_provider.rb19
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/gcp_command_credentials.rb31
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/google_application_default_credentials.rb31
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/http_error.rb25
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/missing_kind_compatibility.rb68
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/oidc_auth_provider.rb52
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/resource.rb11
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/resource_not_found_error.rb4
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/version.rb4
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/watch_stream.rb97
-rw-r--r--vendor/gems/kubeclient/test/cassettes/kubernetes_guestbook.yml879
-rw-r--r--vendor/gems/kubeclient/test/config/allinone.kubeconfig21
-rw-r--r--vendor/gems/kubeclient/test/config/another-ca1.pem19
-rw-r--r--vendor/gems/kubeclient/test/config/another-ca2.pem19
-rw-r--r--vendor/gems/kubeclient/test/config/concatenated-ca.kubeconfig20
-rw-r--r--vendor/gems/kubeclient/test/config/concatenated-ca.pem57
-rw-r--r--vendor/gems/kubeclient/test/config/execauth.kubeconfig61
-rw-r--r--vendor/gems/kubeclient/test/config/external-ca.pem19
-rw-r--r--vendor/gems/kubeclient/test/config/external-cert.pem20
-rw-r--r--vendor/gems/kubeclient/test/config/external-key.rsa27
-rw-r--r--vendor/gems/kubeclient/test/config/external-without-ca.kubeconfig21
-rw-r--r--vendor/gems/kubeclient/test/config/external.kubeconfig20
-rw-r--r--vendor/gems/kubeclient/test/config/gcpauth.kubeconfig21
-rw-r--r--vendor/gems/kubeclient/test/config/gcpcmdauth.kubeconfig25
-rw-r--r--vendor/gems/kubeclient/test/config/insecure-custom-ca.kubeconfig22
-rw-r--r--vendor/gems/kubeclient/test/config/insecure.kubeconfig25
-rw-r--r--vendor/gems/kubeclient/test/config/nouser.kubeconfig15
-rw-r--r--vendor/gems/kubeclient/test/config/oidcauth.kubeconfig24
-rw-r--r--vendor/gems/kubeclient/test/config/secure-without-ca.kubeconfig22
-rw-r--r--vendor/gems/kubeclient/test/config/secure.kubeconfig21
-rw-r--r--vendor/gems/kubeclient/test/config/timestamps.kubeconfig25
-rwxr-xr-xvendor/gems/kubeclient/test/config/update_certs_k0s.rb53
-rw-r--r--vendor/gems/kubeclient/test/config/userauth.kubeconfig27
-rw-r--r--vendor/gems/kubeclient/test/json/bindings_list.json10
-rw-r--r--vendor/gems/kubeclient/test/json/component_status.json17
-rw-r--r--vendor/gems/kubeclient/test/json/component_status_list.json52
-rw-r--r--vendor/gems/kubeclient/test/json/config.istio.io_api_resource_list.json679
-rw-r--r--vendor/gems/kubeclient/test/json/config_map_list.json9
-rw-r--r--vendor/gems/kubeclient/test/json/core_api_resource_list.json181
-rw-r--r--vendor/gems/kubeclient/test/json/core_api_resource_list_without_kind.json129
-rw-r--r--vendor/gems/kubeclient/test/json/core_oapi_resource_list_without_kind.json197
-rw-r--r--vendor/gems/kubeclient/test/json/created_endpoint.json28
-rw-r--r--vendor/gems/kubeclient/test/json/created_namespace.json20
-rw-r--r--vendor/gems/kubeclient/test/json/created_secret.json16
-rw-r--r--vendor/gems/kubeclient/test/json/created_security_context_constraint.json65
-rw-r--r--vendor/gems/kubeclient/test/json/created_service.json31
-rw-r--r--vendor/gems/kubeclient/test/json/empty_pod_list.json9
-rw-r--r--vendor/gems/kubeclient/test/json/endpoint_list.json48
-rw-r--r--vendor/gems/kubeclient/test/json/entity_list.json56
-rw-r--r--vendor/gems/kubeclient/test/json/event_list.json35
-rw-r--r--vendor/gems/kubeclient/test/json/extensions_v1beta1_api_resource_list.json217
-rw-r--r--vendor/gems/kubeclient/test/json/limit_range.json23
-rw-r--r--vendor/gems/kubeclient/test/json/limit_range_list.json31
-rw-r--r--vendor/gems/kubeclient/test/json/namespace.json13
-rw-r--r--vendor/gems/kubeclient/test/json/namespace_exception.json8
-rw-r--r--vendor/gems/kubeclient/test/json/namespace_list.json32
-rw-r--r--vendor/gems/kubeclient/test/json/node.json29
-rw-r--r--vendor/gems/kubeclient/test/json/node_list.json37
-rw-r--r--vendor/gems/kubeclient/test/json/node_notice.json160
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume.json37
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume_claim.json32
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume_claim_list.json40
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume_claims_nil_items.json8
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume_list.json45
-rw-r--r--vendor/gems/kubeclient/test/json/pod.json92
-rw-r--r--vendor/gems/kubeclient/test/json/pod_list.json79
-rw-r--r--vendor/gems/kubeclient/test/json/pod_template_list.json9
-rw-r--r--vendor/gems/kubeclient/test/json/pods_1.json265
-rw-r--r--vendor/gems/kubeclient/test/json/pods_2.json102
-rw-r--r--vendor/gems/kubeclient/test/json/pods_410.json9
-rw-r--r--vendor/gems/kubeclient/test/json/processed_template.json27
-rw-r--r--vendor/gems/kubeclient/test/json/replication_controller.json57
-rw-r--r--vendor/gems/kubeclient/test/json/replication_controller_list.json66
-rw-r--r--vendor/gems/kubeclient/test/json/resource_quota.json46
-rw-r--r--vendor/gems/kubeclient/test/json/resource_quota_list.json54
-rw-r--r--vendor/gems/kubeclient/test/json/secret_list.json44
-rw-r--r--vendor/gems/kubeclient/test/json/security.openshift.io_api_resource_list.json69
-rw-r--r--vendor/gems/kubeclient/test/json/security_context_constraint_list.json375
-rw-r--r--vendor/gems/kubeclient/test/json/service.json33
-rw-r--r--vendor/gems/kubeclient/test/json/service_account.json25
-rw-r--r--vendor/gems/kubeclient/test/json/service_account_list.json82
-rw-r--r--vendor/gems/kubeclient/test/json/service_illegal_json_404.json1
-rw-r--r--vendor/gems/kubeclient/test/json/service_json_patch.json26
-rw-r--r--vendor/gems/kubeclient/test/json/service_list.json97
-rw-r--r--vendor/gems/kubeclient/test/json/service_merge_patch.json26
-rw-r--r--vendor/gems/kubeclient/test/json/service_patch.json25
-rw-r--r--vendor/gems/kubeclient/test/json/service_update.json22
-rw-r--r--vendor/gems/kubeclient/test/json/template.json27
-rw-r--r--vendor/gems/kubeclient/test/json/template.openshift.io_api_resource_list.json75
-rw-r--r--vendor/gems/kubeclient/test/json/template_list.json35
-rw-r--r--vendor/gems/kubeclient/test/json/versions_list.json6
-rw-r--r--vendor/gems/kubeclient/test/json/watch_stream.json3
-rw-r--r--vendor/gems/kubeclient/test/test_common.rb95
-rw-r--r--vendor/gems/kubeclient/test/test_common_url_handling.rb160
-rw-r--r--vendor/gems/kubeclient/test/test_component_status.rb29
-rw-r--r--vendor/gems/kubeclient/test/test_config.rb271
-rw-r--r--vendor/gems/kubeclient/test/test_endpoint.rb54
-rw-r--r--vendor/gems/kubeclient/test/test_exec_credentials.rb225
-rw-r--r--vendor/gems/kubeclient/test/test_gcp_command_credentials.rb27
-rw-r--r--vendor/gems/kubeclient/test/test_google_application_default_credentials.rb15
-rw-r--r--vendor/gems/kubeclient/test/test_guestbook_go.rb237
-rw-r--r--vendor/gems/kubeclient/test/test_helper.rb28
-rw-r--r--vendor/gems/kubeclient/test/test_kubeclient.rb881
-rw-r--r--vendor/gems/kubeclient/test/test_limit_range.rb25
-rw-r--r--vendor/gems/kubeclient/test/test_missing_methods.rb80
-rw-r--r--vendor/gems/kubeclient/test/test_namespace.rb59
-rw-r--r--vendor/gems/kubeclient/test/test_node.rb70
-rw-r--r--vendor/gems/kubeclient/test/test_oidc_auth_provider.rb103
-rw-r--r--vendor/gems/kubeclient/test/test_persistent_volume.rb29
-rw-r--r--vendor/gems/kubeclient/test/test_persistent_volume_claim.rb28
-rw-r--r--vendor/gems/kubeclient/test/test_pod.rb81
-rw-r--r--vendor/gems/kubeclient/test/test_pod_log.rb157
-rw-r--r--vendor/gems/kubeclient/test/test_process_template.rb80
-rw-r--r--vendor/gems/kubeclient/test/test_real_cluster.rb162
-rw-r--r--vendor/gems/kubeclient/test/test_replication_controller.rb47
-rw-r--r--vendor/gems/kubeclient/test/test_resource_list_without_kind.rb78
-rw-r--r--vendor/gems/kubeclient/test/test_resource_quota.rb23
-rw-r--r--vendor/gems/kubeclient/test/test_secret.rb62
-rw-r--r--vendor/gems/kubeclient/test/test_security_context_constraint.rb62
-rw-r--r--vendor/gems/kubeclient/test/test_service.rb357
-rw-r--r--vendor/gems/kubeclient/test/test_service_account.rb26
-rw-r--r--vendor/gems/kubeclient/test/test_watch.rb195
-rw-r--r--vendor/gems/kubeclient/test/txt/pod_log.txt6
-rw-r--r--vendor/gems/kubeclient/test/valid_token_file1
-rwxr-xr-xvendor/gems/omniauth-salesforce/README.md8
-rw-r--r--vendor/project_templates/learn_gitlab_ultimate.tar.gzbin115431 -> 0 bytes
-rw-r--r--workhorse/go.mod68
-rw-r--r--workhorse/go.sum563
-rw-r--r--yarn.lock1677
8243 files changed, 228356 insertions, 113552 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml
index 4a7197e3bd5..906eeaeeccf 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -117,6 +117,10 @@ rules:
message: 'Migrate to GlSkeletonLoader, or import GlDeprecatedSkeletonLoading.'
- selector: ImportSpecifier[imported.name='GlSafeHtmlDirective']
message: 'Use directive at ~/vue_shared/directives/safe_html.js instead.'
+ # TODO: Remove this rule once GitLab UI no longer exports the deprecated alias.
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/382424.
+ - selector: ImportSpecifier[imported.name='GlListbox']
+ message: 'Import GlCollapsibleListbox instead. The GlListbox name is deprecated.'
# See https://gitlab.com/gitlab-org/gitlab/-/issues/360551
vue/multi-word-component-names: off
unicorn/prefer-dom-node-dataset:
@@ -174,8 +178,7 @@ overrides:
- '@graphql-eslint'
parserOptions:
parser: '@graphql-eslint/eslint-plugin'
- operations:
- - '{,ee/,jh/}app/**/*.graphql'
+ operations: '{,ee/,jh/}app/**/*.graphql'
schema: './tmp/tests/graphql/gitlab_schema_apollo.graphql'
rules:
filenames/match-regex: off
diff --git a/.gitignore b/.gitignore
index 1dd9f4ef8aa..04d5ec06bf6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,6 +70,7 @@ eslint-report.html
/tags
/vendor/bundle/*
/vendor/gitaly-ruby
+/vendor/package_metadata_db/
/builds*
/.gitlab_workhorse_secret
/.gitlab_pages_secret
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 79db6e36288..afb2e2e88c6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -36,11 +36,12 @@ default:
OMNIBUS_GITLAB_RUBY2_BUILD: "true"
OMNIBUS_GITLAB_CACHE_EDITION: "GITLAB_RUBY2"
-.default-branch-incident-variables: &default-branch-incident-variables
+.default-branch-pipeline-failure-variables: &default-branch-pipeline-failure-variables
CREATE_INCIDENT_FOR_PIPELINE_FAILURE: "true"
NOTIFY_PIPELINE_FAILURE_CHANNEL: "master-broken"
BROKEN_BRANCH_INCIDENTS_PROJECT: "gitlab-org/quality/engineering-productivity/master-broken-incidents"
BROKEN_BRANCH_INCIDENTS_PROJECT_TOKEN: "${BROKEN_MASTER_INCIDENTS_PROJECT_TOKEN}"
+ CREATE_ISSUES_FOR_FAILING_TESTS: "true"
workflow:
name: '$PIPELINE_NAME'
@@ -48,8 +49,8 @@ workflow:
# If `$FORCE_GITLAB_CI` is set, create a pipeline.
- if: '$FORCE_GITLAB_CI'
variables:
- <<: *ruby2-variables
- PIPELINE_NAME: 'Ruby 2 forced pipeline'
+ <<: *ruby3-variables
+ PIPELINE_NAME: 'Ruby 3 forced pipeline'
# As part of the process of creating RCs automatically, we update stable
# branches with the changes of the most recent production deployment. The
# merge requests used for this merge a branch release-tools/X into a stable
@@ -62,21 +63,24 @@ workflow:
variables:
<<: *ruby2-variables
PIPELINE_NAME: 'Ruby 2 $CI_MERGE_REQUEST_EVENT_TYPE MR pipeline'
+ NO_SOURCEMAPS: 'true'
- if: '$CI_MERGE_REQUEST_LABELS =~ /Community contribution/'
variables:
- <<: *ruby2-variables
+ <<: *ruby3-variables
GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
- PIPELINE_NAME: 'Ruby 2 $CI_MERGE_REQUEST_EVENT_TYPE MR pipeline (community contribution)'
+ PIPELINE_NAME: 'Ruby 3 $CI_MERGE_REQUEST_EVENT_TYPE MR pipeline (community contribution)'
+ NO_SOURCEMAPS: 'true'
# For (detached) merge request pipelines.
- if: '$CI_MERGE_REQUEST_IID'
variables:
- <<: *ruby2-variables
- PIPELINE_NAME: 'Ruby 2 $CI_MERGE_REQUEST_EVENT_TYPE MR pipeline'
+ <<: *ruby3-variables
+ PIPELINE_NAME: 'Ruby 3 $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:
<<: *ruby3-variables
- <<: *default-branch-incident-variables
+ <<: *default-branch-pipeline-failure-variables
CRYSTALBALL: "true"
PIPELINE_NAME: 'Scheduled Ruby 3 $CI_COMMIT_BRANCH branch pipeline'
# Run pipelines for ruby2 branch
@@ -90,44 +94,44 @@ workflow:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $GITLAB_USER_LOGIN =~ /project_\d+_bot\d*/'
variables:
<<: *ruby3-variables
- <<: *default-branch-incident-variables
+ <<: *default-branch-pipeline-failure-variables
GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
PIPELINE_NAME: 'Ruby 3 $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:
<<: *ruby3-variables
- <<: *default-branch-incident-variables
+ <<: *default-branch-pipeline-failure-variables
PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_BRANCH branch pipeline'
# For tags, create a pipeline.
- if: '$CI_COMMIT_TAG'
variables:
- <<: *ruby2-variables
- PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_TAG tag pipeline'
+ <<: *ruby3-variables
+ PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_TAG tag pipeline'
# If `$GITLAB_INTERNAL` isn't set, don't create a pipeline.
- if: '$GITLAB_INTERNAL == null'
when: never
# For stable, auto-deploy, and security branches, create a pipeline.
- if: '$CI_COMMIT_BRANCH =~ /^[\d-]+-stable(-ee)?$/'
variables:
- <<: *ruby2-variables
+ <<: *ruby3-variables
NOTIFY_PIPELINE_FAILURE_CHANNEL: "releases"
- PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline'
+ PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_BRANCH branch pipeline'
CREATE_INCIDENT_FOR_PIPELINE_FAILURE: "true"
BROKEN_BRANCH_INCIDENTS_PROJECT: "gitlab-org/release/tasks"
BROKEN_BRANCH_INCIDENTS_PROJECT_TOKEN: "${BROKEN_STABLE_INCIDENTS_PROJECT_TOKEN}"
- if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
variables:
- <<: *ruby2-variables
- PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline'
+ <<: *ruby3-variables
+ PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_BRANCH branch pipeline'
- if: '$CI_COMMIT_BRANCH =~ /^security\//'
variables:
- <<: *ruby2-variables
- PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline'
+ <<: *ruby3-variables
+ PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_BRANCH branch pipeline'
variables:
PG_VERSION: "12"
- DEFAULT_CI_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}.patched-golang-${GO_VERSION}-rust-${RUST_VERSION}-node-16.14-postgresql-${PG_VERSION}:rubygems-3.2-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-yarn-1.22-graphicsmagick-1.3.36"
+ DEFAULT_CI_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}.patched-golang-${GO_VERSION}-rust-${RUST_VERSION}-node-16.14-postgresql-${PG_VERSION}:rubygems-${RUBYGEMS_VERSION}-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-yarn-1.22-graphicsmagick-1.3.36"
# We set $GITLAB_DEPENDENCY_PROXY to another variable (since it's set at the group level and has higher precedence than .gitlab-ci.yml)
# so that we can override $GITLAB_DEPENDENCY_PROXY_ADDRESS in workflow rules.
GITLAB_DEPENDENCY_PROXY_ADDRESS: "${GITLAB_DEPENDENCY_PROXY}"
@@ -137,7 +141,7 @@ variables:
BUNDLE_INSTALL_FLAGS: "--jobs=$(nproc) --retry=3"
BUNDLE_FROZEN: "true"
# we override the max_old_space_size to prevent OOM errors
- NODE_OPTIONS: --max_old_space_size=3584
+ NODE_OPTIONS: --max_old_space_size=4096
GIT_DEPTH: "20"
# 'GIT_STRATEGY: clone' optimizes the pack-objects cache hit ratio
GIT_STRATEGY: "clone"
@@ -145,8 +149,9 @@ variables:
GET_SOURCES_ATTEMPTS: "3"
DEBIAN_VERSION: "bullseye"
CHROME_VERSION: "109"
- DOCKER_VERSION: "20.10.14"
+ DOCKER_VERSION: "23.0.1"
RUBY_VERSION: "2.7"
+ RUBYGEMS_VERSION: "3.4"
GO_VERSION: "1.18"
RUST_VERSION: "1.65"
@@ -157,7 +162,7 @@ variables:
JUNIT_RETRY_FILE: rspec/junit_rspec-retry.xml
KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/report-master.json
RSPEC_CHANGED_FILES_PATH: rspec/changed_files.txt
- RSPEC_FOSS_IMPACT_PIPELINE_YML: rspec-foss-impact-pipeline.yml
+ RSPEC_FOSS_IMPACT_PIPELINE_TEMPLATE_YML: .gitlab/ci/rails/rspec-foss-impact.gitlab-ci.yml.erb
RSPEC_LAST_RUN_RESULTS_FILE: rspec/rspec_last_run_results.txt
RSPEC_MATCHING_JS_FILES_PATH: rspec/js_matching_files.txt
RSPEC_MATCHING_TESTS_PATH: rspec/matching_tests.txt
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 02258c366c5..a7ecfebbafb 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -16,6 +16,7 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend
/.gitlab/merge_request_templates/*.md
/doc/*.md
/doc/**/*.md
+/doc/**/*.jpg
/doc/**/*.png
/data/deprecations/*.yml
/data/removals/**/*.yml
@@ -415,6 +416,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/compliance.md @eread
/doc/administration/configure.md @axil
/doc/administration/consul.md @axil
+/doc/administration/dedicated/ @drcatherinepope
/doc/administration/docs_self_host.md @axil
/doc/administration/encrypted_configuration.md @axil
/doc/administration/environment_variables.md @axil
@@ -422,6 +424,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/feature_flags.md @axil
/doc/administration/file_hooks.md @ashrafkhamis
/doc/administration/geo/ @axil
+/doc/administration/get_started.md @kpaizee
/doc/administration/git_protocol.md @aqualls
/doc/administration/gitaly/ @eread
/doc/administration/housekeeping.md @eread
@@ -429,7 +432,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/incoming_email.md @msedlakjakubowski
/doc/administration/index.md @axil
/doc/administration/instance_limits.md @axil
-/doc/administration/instance_review.md @phillipwells
/doc/administration/integration/kroki.md @msedlakjakubowski
/doc/administration/integration/mailgun.md @msedlakjakubowski
/doc/administration/integration/plantuml.md @aqualls
@@ -458,11 +460,11 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/operations/gitlab_sshd.md @aqualls
/doc/administration/operations/moving_repositories.md @eread
/doc/administration/package_information/ @axil
-/doc/administration/packages/ @dianalogan
+/doc/administration/packages/ @marcel.amirault
/doc/administration/pages/ @ashrafkhamis
/doc/administration/polling.md @axil
/doc/administration/postgresql/ @aqualls
-/doc/administration/postgresql/multiple_databases.md @jglassman1
+/doc/administration/postgresql/multiple_databases.md @lciutacu
/doc/administration/raketasks/ @axil
/doc/administration/raketasks/ldap.md @jglassman1
/doc/administration/raketasks/praefect.md @eread
@@ -500,31 +502,29 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/award_emoji.md @msedlakjakubowski
/doc/api/boards.md @msedlakjakubowski
/doc/api/branches.md @aqualls
-/doc/api/broadcast_messages.md @phillipwells
/doc/api/bulk_imports.md @eread
/doc/api/cluster_agents.md @phillipwells
/doc/api/commits.md @aqualls
-/doc/api/container_registry.md @dianalogan
+/doc/api/container_registry.md @marcel.amirault
/doc/api/custom_attributes.md @msedlakjakubowski
/doc/api/dependencies.md @rdickenson
-/doc/api/dependency_proxy.md @dianalogan
-/doc/api/deploy_keys.md @rdickenson
-/doc/api/deploy_tokens.md @rdickenson
-/doc/api/deployments.md @rdickenson
+/doc/api/dependency_proxy.md @marcel.amirault
+/doc/api/deploy_keys.md @phillipwells
+/doc/api/deploy_tokens.md @phillipwells
+/doc/api/deployments.md @phillipwells
/doc/api/discussions.md @aqualls
/doc/api/dora/ @lciutacu
/doc/api/draft_notes.md @aqualls
-/doc/api/environments.md @rdickenson
+/doc/api/environments.md @phillipwells
/doc/api/epic_issues.md @msedlakjakubowski
/doc/api/epic_links.md @msedlakjakubowski
/doc/api/epics.md @msedlakjakubowski
/doc/api/error_tracking.md @drcatherinepope
/doc/api/events.md @eread
-/doc/api/experiments.md @phillipwells
-/doc/api/feature_flag_user_lists.md @rdickenson
-/doc/api/feature_flags.md @rdickenson
-/doc/api/features.md @rdickenson
-/doc/api/freeze_periods.md @rdickenson
+/doc/api/feature_flag_user_lists.md @phillipwells
+/doc/api/feature_flags.md @phillipwells
+/doc/api/features.md @phillipwells
+/doc/api/freeze_periods.md @phillipwells
/doc/api/geo_nodes.md @axil
/doc/api/graphql/audit_report.md @eread
/doc/api/graphql/branch_rules.md @aqualls
@@ -546,9 +546,10 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/group_labels.md @msedlakjakubowski
/doc/api/group_level_variables.md @marcel.amirault
/doc/api/group_milestones.md @msedlakjakubowski
-/doc/api/group_protected_environments.md @rdickenson
+/doc/api/group_protected_branches.md @aqualls
+/doc/api/group_protected_environments.md @phillipwells
/doc/api/group_relations_export.md @eread
-/doc/api/group_releases.md @rdickenson
+/doc/api/group_releases.md @phillipwells
/doc/api/group_repository_storage_moves.md @ashrafkhamis
/doc/api/group_wikis.md @ashrafkhamis
/doc/api/groups.md @lciutacu
@@ -557,7 +558,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/instance_clusters.md @phillipwells
/doc/api/instance_level_ci_variables.md @marcel.amirault
/doc/api/integrations.md @ashrafkhamis
-/doc/api/invitations.md @phillipwells
/doc/api/issue_links.md @msedlakjakubowski
/doc/api/issues.md @msedlakjakubowski
/doc/api/issues_statistics.md @msedlakjakubowski
@@ -586,8 +586,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/notification_settings.md @msedlakjakubowski
/doc/api/oauth2.md @jglassman1
/doc/api/openapi/ @ashrafkhamis
-/doc/api/packages.md @dianalogan
-/doc/api/packages/ @dianalogan
+/doc/api/packages.md @marcel.amirault
+/doc/api/packages/ @marcel.amirault
/doc/api/pages.md @ashrafkhamis
/doc/api/pages_domains.md @ashrafkhamis
/doc/api/personal_access_tokens.md @eread
@@ -607,17 +607,17 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/project_snippets.md @aqualls
/doc/api/project_statistics.md @aqualls
/doc/api/project_templates.md @aqualls
-/doc/api/project_vulnerabilities.md @aqualls
+/doc/api/project_vulnerabilities.md @rdickenson
/doc/api/projects.md @lciutacu
/doc/api/protected_branches.md @aqualls
-/doc/api/protected_environments.md @rdickenson
+/doc/api/protected_environments.md @phillipwells
/doc/api/protected_tags.md @aqualls
-/doc/api/releases/ @rdickenson
+/doc/api/releases/ @phillipwells
/doc/api/remote_mirrors.md @aqualls
/doc/api/repositories.md @aqualls
/doc/api/repository_files.md @aqualls
/doc/api/repository_submodules.md @aqualls
-/doc/api/resource_groups.md @rdickenson
+/doc/api/resource_groups.md @phillipwells
/doc/api/resource_iteration_events.md @msedlakjakubowski
/doc/api/resource_label_events.md @eread
/doc/api/resource_milestone_events.md @msedlakjakubowski
@@ -644,30 +644,30 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/templates/licenses.md @rdickenson
/doc/api/todos.md @msedlakjakubowski
/doc/api/topics.md @lciutacu
-/doc/api/usage_data.md @dianalogan
+/doc/api/usage_data.md @lciutacu
/doc/api/users.md @jglassman1
/doc/api/version.md @phillipwells
-/doc/api/visual_review_discussions.md @marcel.amirault
-/doc/api/vulnerabilities.md @dianalogan
-/doc/api/vulnerability_exports.md @dianalogan
-/doc/api/vulnerability_findings.md @dianalogan
+/doc/api/visual_review_discussions.md @drcatherinepope
+/doc/api/vulnerabilities.md @rdickenson
+/doc/api/vulnerability_exports.md @rdickenson
+/doc/api/vulnerability_findings.md @rdickenson
/doc/api/wikis.md @ashrafkhamis
/doc/architecture/blueprints/database/scalability/patterns/ @aqualls
/doc/architecture/blueprints/database_scaling/ @aqualls
/doc/ci/ @drcatherinepope
/doc/ci/caching/ @marcel.amirault
/doc/ci/chatops/ @phillipwells
-/doc/ci/cloud_deployment/ @rdickenson
+/doc/ci/cloud_deployment/ @phillipwells
/doc/ci/cloud_services/ @marcel.amirault
/doc/ci/directed_acyclic_graph/ @marcel.amirault
/doc/ci/docker/using_docker_images.md @fneill
-/doc/ci/environments/ @rdickenson
+/doc/ci/environments/ @phillipwells
/doc/ci/examples/authenticating-with-hashicorp-vault/ @marcel.amirault
-/doc/ci/examples/deployment/ @rdickenson
-/doc/ci/examples/end_to_end_testing_webdriverio/ @marcel.amirault
-/doc/ci/examples/semantic-release.md @dianalogan
+/doc/ci/examples/deployment/ @phillipwells
+/doc/ci/examples/semantic-release.md @marcel.amirault
/doc/ci/interactive_web_terminal/ @fneill
-/doc/ci/jobs/job_control.md @marcel.amirault
+/doc/ci/introduction/ @marcel.amirault
+/doc/ci/jobs/ @marcel.amirault
/doc/ci/large_repositories/ @fneill
/doc/ci/lint.md @marcel.amirault
/doc/ci/migration/ @marcel.amirault
@@ -675,19 +675,23 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/ci/pipelines/downstream_pipelines.md @marcel.amirault
/doc/ci/pipelines/index.md @marcel.amirault
/doc/ci/pipelines/job_artifacts.md @marcel.amirault
+/doc/ci/pipelines/pipeline_architectures.md @marcel.amirault
/doc/ci/pipelines/pipeline_artifacts.md @marcel.amirault
/doc/ci/quick_start/ @marcel.amirault
-/doc/ci/resource_groups/ @rdickenson
-/doc/ci/review_apps/ @marcel.amirault
+/doc/ci/resource_groups/ @phillipwells
/doc/ci/runners/ @fneill
/doc/ci/secrets/ @marcel.amirault
/doc/ci/secure_files/ @marcel.amirault
/doc/ci/services/ @fneill
+/doc/ci/ssh_keys/ @marcel.amirault
/doc/ci/test_cases/ @msedlakjakubowski
-/doc/ci/testing/ @marcel.amirault
/doc/ci/testing/code_quality.md @rdickenson
+/doc/ci/triggers/ @marcel.amirault
+/doc/ci/troubleshooting.md @marcel.amirault
/doc/ci/variables/ @marcel.amirault
/doc/ci/yaml/ @marcel.amirault
+/doc/ci/yaml/artifacts_reports.md @drcatherinepope
+/doc/development/advanced_search.md @ashrafkhamis
/doc/development/application_limits.md @axil
/doc/development/audit_event_guide/ @eread
/doc/development/auto_devops.md @phillipwells
@@ -699,27 +703,27 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/cascading_settings.md @jglassman1
/doc/development/chatops_on_gitlabcom.md @phillipwells
/doc/development/cicd/ @marcel.amirault
+/doc/development/cicd/cicd_tables.md @drcatherinepope
/doc/development/cicd/index.md @drcatherinepope
/doc/development/code_intelligence/ @aqualls
+/doc/development/code_owners/ @aqualls
/doc/development/contributing/ @sselhorn
/doc/development/database/ @aqualls
/doc/development/database/filtering_by_label.md @msedlakjakubowski
-/doc/development/database/multiple_databases.md @jglassman1
+/doc/development/database/multiple_databases.md @lciutacu
/doc/development/database_review.md @aqualls
/doc/development/developing_with_solargraph.md @aqualls
/doc/development/development_processes.md @sselhorn
/doc/development/distributed_tracing.md @msedlakjakubowski
/doc/development/documentation/ @sselhorn
-/doc/development/elasticsearch.md @ashrafkhamis
-/doc/development/experiment_guide/ @phillipwells
/doc/development/export_csv.md @eread
/doc/development/fe_guide/content_editor.md @ashrafkhamis
/doc/development/fe_guide/customizable_dashboards.md @lciutacu
/doc/development/fe_guide/dark_mode.md @sselhorn
/doc/development/fe_guide/graphql.md @sselhorn
/doc/development/fe_guide/merge_request_widget_extensions.md @aqualls
-/doc/development/fe_guide/source_editor.md @ashrafkhamis
-/doc/development/fe_guide/view_component.md @rdickenson
+/doc/development/fe_guide/source_editor.md @aqualls
+/doc/development/fe_guide/view_component.md @sselhorn
/doc/development/feature_categorization/ @sselhorn
/doc/development/feature_development.md @sselhorn
/doc/development/feature_flags/ @sselhorn
@@ -736,10 +740,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/image_scaling.md @lciutacu
/doc/development/import_export.md @eread
/doc/development/index.md @sselhorn
-/doc/development/integrations/codesandbox.md @sselhorn
-/doc/development/integrations/index.md @ashrafkhamis
-/doc/development/integrations/jenkins.md @ashrafkhamis
-/doc/development/integrations/jira_connect.md @ashrafkhamis
+/doc/development/integrations/ @ashrafkhamis
/doc/development/integrations/secure.md @rdickenson
/doc/development/integrations/secure_partner_integration.md @rdickenson
/doc/development/internal_api/ @aqualls
@@ -747,25 +748,28 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/issuable-like-models.md @msedlakjakubowski
/doc/development/issue_types.md @msedlakjakubowski
/doc/development/kubernetes.md @phillipwells
+/doc/development/labels/ @sselhorn
/doc/development/lfs.md @aqualls
/doc/development/logging.md @msedlakjakubowski
/doc/development/maintenance_mode.md @axil
/doc/development/merge_request_concepts/ @aqualls
+/doc/development/migration_style_guide.md @aqualls
+/doc/development/navigation_sidebar.md @sselhorn
/doc/development/omnibus.md @axil
-/doc/development/packages/ @dianalogan
+/doc/development/organization/ @lciutacu
+/doc/development/packages/ @marcel.amirault
/doc/development/pages/ @ashrafkhamis
/doc/development/permissions.md @jglassman1
/doc/development/policies.md @jglassman1
-/doc/development/product_qualified_lead_guide/ @phillipwells
/doc/development/project_templates.md @aqualls
/doc/development/prometheus_metrics.md @msedlakjakubowski
/doc/development/real_time.md @msedlakjakubowski
/doc/development/rubocop_development_guide.md @sselhorn
+/doc/development/search/ @ashrafkhamis
/doc/development/sec/ @rdickenson
-/doc/development/sec/security_report_ingestion_overview.md @dianalogan
/doc/development/secure_coding_guidelines.md @sselhorn
-/doc/development/service_ping/ @dianalogan
-/doc/development/snowplow/ @dianalogan
+/doc/development/service_ping/ @lciutacu
+/doc/development/snowplow/ @lciutacu
/doc/development/spam_protection_and_captcha/ @phillipwells
/doc/development/sql.md @aqualls
/doc/development/testing_guide/ @sselhorn
@@ -775,7 +779,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/work_items.md @msedlakjakubowski
/doc/development/work_items_widgets.md @msedlakjakubowski
/doc/development/workhorse/ @aqualls
-/doc/development/workspace/ @sselhorn
/doc/downgrade_ee_to_ce/ @axil
/doc/drawers/ @ashrafkhamis
/doc/gitlab-basics/ @aqualls
@@ -794,6 +797,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/integration/jenkins.md @ashrafkhamis
/doc/integration/jira/ @ashrafkhamis
/doc/integration/mattermost/ @axil
+/doc/integration/partner_marketplace.md @fneill
/doc/integration/recaptcha.md @phillipwells
/doc/integration/security_partners/ @rdickenson
/doc/integration/slash_commands.md @ashrafkhamis
@@ -801,7 +805,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/integration/trello_power_up.md @ashrafkhamis
/doc/integration/vault.md @phillipwells
/doc/operations/error_tracking.md @drcatherinepope
-/doc/operations/feature_flags.md @rdickenson
+/doc/operations/feature_flags.md @phillipwells
/doc/operations/incident_management/ @msedlakjakubowski
/doc/operations/index.md @msedlakjakubowski
/doc/operations/metrics/ @msedlakjakubowski
@@ -813,20 +817,19 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/raketasks/x509_signatures.md @aqualls
/doc/security/ @jglassman1
/doc/subscriptions/ @fneill
-/doc/subscriptions/gitlab_dedicated/ @axil
+/doc/subscriptions/gitlab_dedicated/ @drcatherinepope
/doc/topics/authentication/ @jglassman1
/doc/topics/autodevops/ @phillipwells
-/doc/topics/awesome_co.md @rdickenson
+/doc/topics/awesome_co.md @sselhorn
/doc/topics/git/ @aqualls
/doc/topics/gitlab_flow.md @aqualls
/doc/topics/offline/ @axil
/doc/topics/plan_and_track.md @msedlakjakubowski
-/doc/topics/your_work.md @rdickenson
+/doc/topics/your_work.md @sselhorn
/doc/tutorials/ @kpaizee
/doc/update/ @axil
/doc/update/background_migrations.md @aqualls
/doc/user/admin_area/analytics/ @lciutacu
-/doc/user/admin_area/broadcast_messages.md @phillipwells
/doc/user/admin_area/credentials_inventory.md @jglassman1
/doc/user/admin_area/custom_project_templates.md @eread
/doc/user/admin_area/diff_limits.md @aqualls
@@ -853,37 +856,37 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/admin_area/settings/incident_management_rate_limits.md @msedlakjakubowski
/doc/user/admin_area/settings/index.md @aqualls
/doc/user/admin_area/settings/instance_template_repository.md @aqualls
-/doc/user/admin_area/settings/package_registry_rate_limits.md @dianalogan
+/doc/user/admin_area/settings/package_registry_rate_limits.md @marcel.amirault
/doc/user/admin_area/settings/project_integration_management.md @ashrafkhamis
/doc/user/admin_area/settings/push_event_activities_limit.md @aqualls
/doc/user/admin_area/settings/rate_limit_on_issues_creation.md @msedlakjakubowski
/doc/user/admin_area/settings/rate_limit_on_notes_creation.md @msedlakjakubowski
/doc/user/admin_area/settings/rate_limit_on_pipelines_creation.md @drcatherinepope
+/doc/user/admin_area/settings/rate_limit_on_projects_api.md @lciutacu
/doc/user/admin_area/settings/rate_limit_on_users_api.md @jglassman1
/doc/user/admin_area/settings/scim_setup.md @jglassman1
/doc/user/admin_area/settings/terraform_limits.md @phillipwells
/doc/user/admin_area/settings/third_party_offers.md @lciutacu
-/doc/user/admin_area/settings/usage_statistics.md @dianalogan
+/doc/user/admin_area/settings/usage_statistics.md @lciutacu
/doc/user/admin_area/settings/visibility_and_access_controls.md @aqualls
/doc/user/analytics/ @lciutacu
-/doc/user/analytics/ci_cd_analytics.md @rdickenson
+/doc/user/analytics/ci_cd_analytics.md @phillipwells
/doc/user/application_security/ @rdickenson
-/doc/user/application_security/cve_id_request.md @dianalogan
-/doc/user/application_security/generate_test_vulnerabilities/ @dianalogan
/doc/user/application_security/policies/ @dianalogan
-/doc/user/application_security/security_dashboard/ @dianalogan
-/doc/user/application_security/vulnerabilities/ @dianalogan
-/doc/user/application_security/vulnerability_report/ @dianalogan
/doc/user/asciidoc.md @aqualls
/doc/user/award_emojis.md @msedlakjakubowski
/doc/user/clusters/ @phillipwells
-/doc/user/compliance/ @eread
+/doc/user/compliance/compliance_report/ @eread
+/doc/user/compliance/index.md @eread
+/doc/user/compliance/license_approval_policies.md @dianalogan
+/doc/user/compliance/license_check_rules.md @dianalogan
/doc/user/compliance/license_compliance/ @rdickenson
+/doc/user/compliance/license_list.md @rdickenson
+/doc/user/compliance/license_scanning_of_cyclonedx_files/ @rdickenson
/doc/user/crm/ @msedlakjakubowski
/doc/user/discussions/ @aqualls
/doc/user/enterprise_user/ @jglassman1
/doc/user/feature_flags.md @sselhorn
-/doc/user/free_user_limit.md @phillipwells
/doc/user/group/ @lciutacu
/doc/user/group/clusters/ @phillipwells
/doc/user/group/compliance_frameworks.md @eread
@@ -894,7 +897,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/group/iterations/ @msedlakjakubowski
/doc/user/group/planning_hierarchy/ @msedlakjakubowski
/doc/user/group/reporting/ @phillipwells
-/doc/user/group/repositories_analytics/ @marcel.amirault
+/doc/user/group/repositories_analytics/ @drcatherinepope
/doc/user/group/roadmap/ @msedlakjakubowski
/doc/user/group/saml_sso/ @jglassman1
/doc/user/group/settings/ @jglassman1
@@ -903,22 +906,27 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/markdown.md @msedlakjakubowski
/doc/user/namespace/ @lciutacu
/doc/user/okrs.md @msedlakjakubowski
-/doc/user/operations_dashboard/ @rdickenson
-/doc/user/packages/ @dianalogan
+/doc/user/operations_dashboard/ @phillipwells
+/doc/user/organization/ @lciutacu
+/doc/user/packages/ @marcel.amirault
/doc/user/permissions.md @jglassman1
/doc/user/product_analytics/ @lciutacu
-/doc/user/profile/ @jglassman1
+/doc/user/profile/account/ @jglassman1
/doc/user/profile/contributions_calendar.md @lciutacu
+/doc/user/profile/index.md @jglassman1
/doc/user/profile/notifications.md @msedlakjakubowski
+/doc/user/profile/personal_access_tokens.md @jglassman1
+/doc/user/profile/saved_replies.md @aqualls
+/doc/user/profile/user_passwords.md @jglassman1
/doc/user/project/autocomplete_characters.md @aqualls
/doc/user/project/badges.md @lciutacu
/doc/user/project/changelogs.md @aqualls
/doc/user/project/clusters/ @phillipwells
/doc/user/project/code_intelligence.md @aqualls
/doc/user/project/code_owners.md @aqualls
-/doc/user/project/deploy_boards.md @rdickenson
-/doc/user/project/deploy_keys/ @rdickenson
-/doc/user/project/deploy_tokens/ @rdickenson
+/doc/user/project/deploy_boards.md @phillipwells
+/doc/user/project/deploy_keys/ @phillipwells
+/doc/user/project/deploy_tokens/ @phillipwells
/doc/user/project/description_templates.md @msedlakjakubowski
/doc/user/project/file_lock.md @aqualls
/doc/user/project/git_attributes.md @aqualls
@@ -945,7 +953,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/protected_tags.md @aqualls
/doc/user/project/push_options.md @aqualls
/doc/user/project/quick_actions.md @msedlakjakubowski
-/doc/user/project/releases/ @rdickenson
+/doc/user/project/releases/ @phillipwells
/doc/user/project/remote_development/ @ashrafkhamis
/doc/user/project/repository/ @aqualls
/doc/user/project/repository/file_finder.md @ashrafkhamis
@@ -965,7 +973,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/wiki/ @ashrafkhamis
/doc/user/project/working_with_projects.md @lciutacu
/doc/user/public_access.md @lciutacu
-/doc/user/read_only_namespaces.md @phillipwells
/doc/user/report_abuse.md @phillipwells
/doc/user/reserved_names.md @lciutacu
/doc/user/search/ @ashrafkhamis
@@ -975,7 +982,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/tasks.md @msedlakjakubowski
/doc/user/todos.md @msedlakjakubowski
/doc/user/usage_quotas.md @fneill
-/doc/user/workspace/ @lciutacu
# End rake-managed-docs-block
[Authentication and Authorization]
@@ -1396,7 +1402,6 @@ ee/lib/ee/api/entities/project.rb @gitlab-org/manage/manage-workspace/backend-ap
/ee/config/events/202108302307_profiles_controller_search_audit_event.yml @gitlab-org/govern/compliance
/ee/config/events/202108302307_projects__audit_events_controller_search_audit_event.yml @gitlab-org/govern/compliance
/ee/config/events/202111041910_admin__audit_logs_controller_search_audit_event.yml @gitlab-org/govern/compliance
-/ee/config/feature_flags/development/audit_log_group_level.yml @gitlab-org/govern/compliance
/ee/config/metrics/counts_28d/20210216183930_g_compliance_audit_events_monthly.yml @gitlab-org/govern/compliance
/ee/config/metrics/counts_28d/20210216183934_i_compliance_audit_events_monthly.yml @gitlab-org/govern/compliance
/ee/config/metrics/counts_28d/20210216183942_a_compliance_audit_events_api_monthly.yml @gitlab-org/govern/compliance
@@ -1421,5 +1426,5 @@ ee/lib/ee/api/entities/project.rb @gitlab-org/manage/manage-workspace/backend-ap
/ee/app/assets/javascripts/usage_quotas/storage/ @fulfillment-group/utilization-group/fe
[Manage::Foundations]
-/lib/sidebars/ @gitlab/ @gitlab-org/manage/foundations/engineering
-/ee/lib/sidebars/ @gitlab-org/manage/foundations/engineering \ No newline at end of file
+/lib/sidebars/ @gitlab-org/manage/foundations/engineering
+/ee/lib/sidebars/ @gitlab-org/manage/foundations/engineering
diff --git a/.gitlab/ci/as-if-jh.gitlab-ci.yml b/.gitlab/ci/as-if-jh.gitlab-ci.yml
index 6bd46bee770..2c90112bbf2 100644
--- a/.gitlab/ci/as-if-jh.gitlab-ci.yml
+++ b/.gitlab/ci/as-if-jh.gitlab-ci.yml
@@ -37,11 +37,19 @@ prepare-as-if-jh-branch:
stage: prepare
needs:
- add-jh-files
+ variables:
+ # We can't apply --filter=tree:0 for runner to set up the repository,
+ # so instead we tell runner to not clone anything, and we set up the
+ # repository by ourselves.
+ GIT_STRATEGY: "none"
script:
- # Fetch for the history of the branch so it does not cause the following error:
- # ! [remote rejected] ref -> ref (shallow update not allowed)
- - git fetch --unshallow --filter=tree:0 origin "${CI_COMMIT_SHA}"
- - git checkout -b "${AS_IF_JH_BRANCH}"
+ - git clone --filter=tree:0 "$CI_REPOSITORY_URL" gitlab
+ # We should checkout before moving/changing files
+ - cd gitlab
+ - git checkout -b "${AS_IF_JH_BRANCH}" "${CI_COMMIT_SHA}"
+ - cd ..
+ - mv $JH_FILES_TO_COMMIT gitlab/
+ - cd gitlab
- git add ${JH_FILES_TO_COMMIT}
- git commit -m 'Add JH files' # TODO: Mark which SHA we add
- git push -f "${SANDBOX_REPOSITORY}" "${AS_IF_JH_BRANCH}"
diff --git a/.gitlab/ci/database.gitlab-ci.yml b/.gitlab/ci/database.gitlab-ci.yml
index ace968ec249..941cb9224fb 100644
--- a/.gitlab/ci/database.gitlab-ci.yml
+++ b/.gitlab/ci/database.gitlab-ci.yml
@@ -1,13 +1,43 @@
include:
- local: .gitlab/ci/rails/shared.gitlab-ci.yml
+db:rollback single-db-ci-connection:
+ extends:
+ - db:rollback
+ - .single-db-ci-connection
+ - .rails:rules:single-db-ci-connection
+
+db:migrate:reset single-db-ci-connection:
+ extends:
+ - db:migrate:reset
+ - .single-db-ci-connection
+ - .rails:rules:single-db-ci-connection
+
+db:check-schema-single-db-ci-connection:
+ extends:
+ - db:check-schema
+ - .single-db-ci-connection
+ - .rails:rules:single-db-ci-connection
+
+db:post_deployment_migrations_validator-single-db-ci-connection:
+ extends:
+ - db:post_deployment_migrations_validator
+ - .single-db-ci-connection
+ - .rails:rules:db:check-migrations-single-db-ci-connection
+
+db:backup_and_restore single-db-ci-connection:
+ extends:
+ - db:backup_and_restore
+ - .single-db-ci-connection
+ - .rails:rules:db-backup
+
db:rollback:
extends:
- .db-job-base
- .rails:rules:db-rollback
script:
- - scripts/db_tasks db:migrate VERSION=20220502173045 # 14.10 (last 14.x version)
- - scripts/db_tasks db:migrate
+ - bundle exec rake db:migrate VERSION=20220502173045 # 14.10 (last 14.x version)
+ - bundle exec rake db:migrate
db:rollback single-db:
extends:
@@ -31,8 +61,7 @@ db:check-schema:
- .db-job-base
- .rails:rules:ee-mr-and-default-branch-only
script:
- - run_timed_command "bundle exec rake db:drop db:create"
- - run_timed_command "scripts/db_tasks db:migrate"
+ - run_timed_command "bundle exec rake db:drop db:create db:migrate"
db:check-schema-single-db:
extends:
@@ -97,7 +126,7 @@ db:backup_and_restore:
GITLAB_ASSUME_YES: "1"
script:
- . scripts/prepare_build.sh
- - bundle exec rake db:drop db:create db:structure:load db:seed_fu
+ - bundle exec rake db:drop db:create db:schema:load db:seed_fu
- mkdir -p tmp/tests/public/uploads tmp/tests/{artifacts,pages,lfs-objects,terraform_state,registry,packages}
- bundle exec rake gitlab:backup:create
- date
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index b404444f815..a52372a7bb4 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -42,7 +42,7 @@ review-docs-cleanup:
docs-lint links:
extends:
- .docs:rules:docs-lint
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-html:alpine-3.16-ruby-3.0.5-869cfc5d
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-html:alpine-3.17-ruby-3.2.1-f53af000
stage: lint
needs: []
script:
@@ -58,7 +58,7 @@ docs-lint links:
.docs-markdown-lint-image:
# When updating the image version here, update it in /scripts/lint-doc.sh too.
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-markdown:alpine-3.16-vale-2.22.0-markdownlint-0.32.2-markdownlint2-0.6.0
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-markdown:alpine-3.17-vale-2.24.0-markdownlint-0.33.0-markdownlint2-0.6.0
docs-lint markdown:
extends:
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index 2e0d83187cf..c5d992cab63 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -3,7 +3,7 @@
- .default-retry
- .default-before_script
- .assets-compile-cache
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-16.14:rubygems-3.2-git-2.33-lfs-2.9-yarn-1.22-graphicsmagick-1.3.36
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-16.14:rubygems-${RUBYGEMS_VERSION}-git-2.33-lfs-2.9-yarn-1.22-graphicsmagick-1.3.36
variables:
SETUP_DB: "false"
WEBPACK_VENDOR_DLL: "true"
@@ -49,6 +49,18 @@ compile-production-assets:
after_script:
- rm -f /etc/apt/sources.list.d/google*.list # We don't need to update Chrome here
+compile-production-assets-esbuild:
+ allow_failure: true
+ extends:
+ - .compile-assets-base
+ - .frontend:rules:compile-production-assets
+ variables:
+ NODE_ENV: "production"
+ RAILS_ENV: "production"
+ WEBPACK_USE_ESBUILD_LOADER: "true"
+ after_script:
+ - rm -f /etc/apt/sources.list.d/google*.list # We don't need to update Chrome here
+
compile-test-assets:
extends:
- .compile-assets-base
@@ -61,6 +73,14 @@ compile-test-assets:
- "${WEBPACK_COMPILE_LOG_PATH}"
when: always
+compile-test-assets-esbuild:
+ allow_failure: true
+ extends:
+ - .compile-assets-base
+ - .frontend:rules:compile-test-assets
+ variables:
+ WEBPACK_USE_ESBUILD_LOADER: "true"
+
compile-test-assets as-if-foss:
extends:
- compile-test-assets
@@ -141,6 +161,21 @@ rspec-all frontend_fixture as-if-foss:
- !reference [.frontend-fixtures-base, needs]
- "compile-test-assets as-if-foss"
+# Uploads EE fixtures in the EE project.
+# Uploads FOSS fixtures in the FOSS project.
+upload-frontend-fixtures:
+ extends:
+ - .frontend-fixtures-base
+ - .frontend:rules:upload-frontend-fixtures
+ stage: fixtures
+ needs: ["rspec-all frontend_fixture"]
+ script:
+ - source scripts/gitlab_component_helpers.sh
+ - 'fixtures_archive_doesnt_exist || { echoinfo "INFO: Exiting early as package exists."; exit 0; }'
+ - run_timed_command "create_fixtures_package"
+ - run_timed_command "upload_fixtures_package"
+ artifacts: {}
+
graphql-schema-dump:
variables:
SETUP_DB: "false"
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index ba623ef4cbe..14fa0fc3671 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -229,14 +229,6 @@
- *node-modules-cache # We don't push this cache as it's already rebuilt by `update-assets-compile-*-cache`
- *storybook-node-modules-cache-push
-.use-pg11:
- services:
- - name: postgres:11.6
- command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- - name: redis:5.0-alpine
- variables:
- POSTGRES_HOST_AUTH_METHOD: trust
- PG_VERSION: "11"
.use-pg12:
services:
@@ -256,21 +248,6 @@
POSTGRES_HOST_AUTH_METHOD: trust
PG_VERSION: "13"
-.use-pg11-es7-ee:
- services:
- - name: postgres:11.6
- command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- - name: redis:5.0-alpine
- - name: elasticsearch:7.17.6
- command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"]
- - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.0
- alias: zoekt-ci-image
- variables:
- POSTGRES_HOST_AUTH_METHOD: trust
- PG_VERSION: "11"
- ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060
- ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070
-
.use-pg12-es7-ee:
services:
- name: postgres:12
@@ -306,7 +283,7 @@
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:6.0-alpine
- - name: elasticsearch:8.5.3
+ - name: elasticsearch:8.6.2
- name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.0
alias: zoekt-ci-image
variables:
@@ -376,7 +353,7 @@
.use-buildx:
extends: .use-docker-in-docker
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-slim:docker-${DOCKER_VERSION}-buildx-0.8
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-slim:docker-${DOCKER_VERSION}
variables:
QEMU_IMAGE: tonistiigi/binfmt:qemu-v7.0.0
before_script:
diff --git a/.gitlab/ci/notify.gitlab-ci.yml b/.gitlab/ci/notify.gitlab-ci.yml
index 20f19978022..795a0cd6439 100644
--- a/.gitlab/ci/notify.gitlab-ci.yml
+++ b/.gitlab/ci/notify.gitlab-ci.yml
@@ -70,3 +70,28 @@ notify-pipeline-failure:
- ${FAILED_PIPELINE_SLACK_MESSAGE_FILE}
when: always
expire_in: 2 days
+
+create-issues-for-failing-tests:
+ extends:
+ - .notify-defaults
+ - .notify:rules:create-issues-for-failing-tests
+ image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}
+ variables:
+ FAILED_TESTS_DIR: "${CI_PROJECT_DIR}/tmp/failed_tests"
+ FAILING_ISSUES_PROJECT: "gitlab-org/quality/engineering-productivity/flaky-tests-playground"
+ FAILING_ISSUE_JSON_DIR: "${CI_PROJECT_DIR}/tmp/issues"
+ before_script:
+ - source ./scripts/utils.sh
+ - source ./scripts/rspec_helpers.sh
+ - install_gitlab_gem
+ script:
+ - mkdir -p "${FAILING_ISSUE_JSON_DIR}"
+ - retrieve_failed_tests "${FAILED_TESTS_DIR}" "json" "latest"
+ - scripts/pipeline/create_test_failure_issues.rb --project "${FAILING_ISSUES_PROJECT}" --tests-report-file "${FAILED_TESTS_DIR}/rspec_failed_tests.json" --issues-json-folder "${FAILING_ISSUE_JSON_DIR}" --api-token "${FAILING_ISSUES_PROJECT_TOKEN}"
+ - scripts/pipeline/create_test_failure_issues.rb --project "${FAILING_ISSUES_PROJECT}" --tests-report-file "${FAILED_TESTS_DIR}/rspec_ee_failed_tests.json" --issues-json-folder "${FAILING_ISSUE_JSON_DIR}" --api-token "${FAILING_ISSUES_PROJECT_TOKEN}"
+ artifacts:
+ paths:
+ - ${FAILED_TESTS_DIR}/
+ - ${FAILING_ISSUE_JSON_DIR}/
+ when: always
+ expire_in: 2 days
diff --git a/.gitlab/ci/package-and-test/main.gitlab-ci.yml b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
index 0d30cb78be7..4c89cbb721b 100644
--- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
@@ -8,7 +8,7 @@ include:
- local: .gitlab/ci/package-and-test/rules.gitlab-ci.yml
- local: .gitlab/ci/package-and-test/variables.gitlab-ci.yml
- project: gitlab-org/quality/pipeline-common
- ref: 2.0.0
+ ref: 2.2.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml
@@ -41,7 +41,8 @@ stages:
.update-script:
script:
- - export QA_COMMAND="bundle exec gitlab-qa Test::Omnibus::UpdateFromPrevious $RELEASE $GITLAB_VERSION $UPDATE_TYPE -- $QA_RSPEC_TAGS $RSPEC_REPORT_OPTS"
+ - !reference [.bundle-prefix]
+ - export QA_COMMAND="$BUNDLE_PREFIX gitlab-qa Test::Omnibus::UpdateFromPrevious $RELEASE $GITLAB_SEMVER_VERSION $UPDATE_TYPE -- $QA_RSPEC_TAGS $RSPEC_REPORT_OPTS"
- echo "Running - '$QA_COMMAND'"
- eval "$QA_COMMAND"
@@ -59,15 +60,16 @@ stages:
- job: download-knapsack-report
artifacts: true
optional: true
+ - job: check-release-set
variables:
QA_GENERATE_ALLURE_REPORT: "true"
QA_CAN_TEST_PRAEFECT: "false"
QA_INTERCEPT_REQUESTS: "true"
- QA_RUN_TYPE: e2e-package-and-test
+ GITLAB_LICENSE_MODE: test
+ GITLAB_QA_ADMIN_ACCESS_TOKEN: $QA_ADMIN_ACCESS_TOKEN
+ # todo: remove in 16.1 milestone when not needed for backwards compatibility anymore
EE_LICENSE: $QA_EE_LICENSE
GITHUB_ACCESS_TOKEN: $QA_GITHUB_ACCESS_TOKEN
- GITLAB_QA_ADMIN_ACCESS_TOKEN: $QA_ADMIN_ACCESS_TOKEN
- GITLAB_LICENSE_MODE: test
# ==========================================
# Prepare stage
@@ -122,8 +124,10 @@ trigger-omnibus-env:
echo "OMNIBUS_GITLAB_CACHE_UPDATE=${OMNIBUS_GITLAB_CACHE_UPDATE:-false}" >> $BUILD_ENV
for version_file in *_VERSION; do echo "$version_file=$(cat $version_file)" >> $BUILD_ENV; done
echo "OMNIBUS_GITLAB_RUBY3_BUILD=${OMNIBUS_GITLAB_RUBY3_BUILD:-false}" >> $BUILD_ENV
+ echo "OMNIBUS_GITLAB_RUBY2_BUILD=${OMNIBUS_GITLAB_RUBY2_BUILD:-false}" >> $BUILD_ENV
echo "OMNIBUS_GITLAB_CACHE_EDITION=${OMNIBUS_GITLAB_CACHE_EDITION:-GITLAB}" >> $BUILD_ENV
echo "GITLAB_ASSETS_TAG=$(assets_image_tag)" >> $BUILD_ENV
+ echo "EE=$([[ $FOSS_ONLY == 'true' ]] && echo 'false' || echo 'true')" >> $BUILD_ENV
echo "Built environment file for omnibus build:"
cat $BUILD_ENV
artifacts:
@@ -152,10 +156,10 @@ trigger-omnibus:
SECURITY_SOURCES: $SECURITY_SOURCES
CACHE_UPDATE: $OMNIBUS_GITLAB_CACHE_UPDATE
RUBY3_BUILD: $OMNIBUS_GITLAB_RUBY3_BUILD
+ RUBY2_BUILD: $OMNIBUS_GITLAB_RUBY2_BUILD
CACHE_EDITION: $OMNIBUS_GITLAB_CACHE_EDITION
- SKIP_QA_DOCKER: "true"
SKIP_QA_TEST: "true"
- ee: "true"
+ ee: $EE
trigger:
project: gitlab-org/build/omnibus-gitlab-mirror
strategy: depend
@@ -202,7 +206,7 @@ cache-gems:
# Run manual quarantine job
# this job requires passing QA_SCENARIO variable
# and optionally QA_TESTS to run specific quarantined tests
-_ee:quarantine:
+_quarantine:
extends:
- .qa
- .rules:test:manual
@@ -213,12 +217,33 @@ _ee:quarantine:
variables:
QA_RSPEC_TAGS: --tag quarantine
+# Temporary test job to support the effort of migrating to Super Sidebar
+# https://gitlab.com/groups/gitlab-org/-/epics/9044
+_super-sidebar-nav:
+ extends:
+ - .qa
+ - .parallel
+ variables:
+ QA_SCENARIO: Test::Instance::Image
+ QA_KNAPSACK_REPORT_NAME: ee-instance
+ QA_TESTS: ""
+ QA_SUPER_SIDEBAR_ENABLED: "true"
+ QA_ALLURE_RESULTS_DIRECTORY: tmp/allure-results-super-sidebar
+ QA_EXPORT_TEST_METRICS: "false"
+ GITLAB_QA_OPTS: --set-feature-flags super_sidebar_nav=enabled
+ RSPEC_REPORT_OPTS: "--format documentation"
+ SKIP_REPORT_IN_ISSUES: "true"
+ allow_failure: true
+ rules:
+ - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
+ - !reference [.rules:test:manual, rules]
+
# ------------------------------------------
# FF changes
# ------------------------------------------
# Run specs with feature flags set to the opposite of the default state
-ee:instance-ff-inverse:
+instance-ff-inverse:
extends:
- .qa
- .parallel
@@ -232,23 +257,23 @@ ee:instance-ff-inverse:
# ------------------------------------------
# Jobs with parallel variant
# ------------------------------------------
-ee:instance-selective:
+instance-selective:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::Image
rules:
- !reference [.rules:test:qa-selective, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:instance:
+instance:
extends:
- .parallel
- - ee:instance-selective
+ - instance-selective
rules:
- - !reference [.rules:test:feature-flags-set, rules] # always run ee:instance to validate ff change
+ - !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/
-ee:praefect-selective:
+praefect-selective:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::Praefect
@@ -256,30 +281,30 @@ ee:praefect-selective:
rules:
- !reference [.rules:test:qa-selective, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:praefect:
+praefect:
extends:
- .parallel
- - ee:praefect-selective
+ - praefect-selective
rules:
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:relative-url-selective:
+relative-url-selective:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::RelativeUrl
rules:
- !reference [.rules:test:qa-selective, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:relative-url:
+relative-url:
extends:
- .parallel
- - ee:relative-url-selective
+ - relative-url-selective
rules:
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:decomposition-single-db-selective:
+decomposition-single-db-selective:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::Image
@@ -287,15 +312,15 @@ ee:decomposition-single-db-selective:
rules:
- !reference [.rules:test:qa-selective, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:decomposition-single-db:
+decomposition-single-db:
extends:
- .parallel
- - ee:decomposition-single-db-selective
+ - decomposition-single-db-selective
rules:
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:decomposition-multiple-db-selective:
+decomposition-multiple-db-selective:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::Image
@@ -304,15 +329,15 @@ ee:decomposition-multiple-db-selective:
rules:
- !reference [.rules:test:qa-selective, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:decomposition-multiple-db:
+decomposition-multiple-db:
extends:
- .parallel
- - ee:decomposition-multiple-db-selective
+ - decomposition-multiple-db-selective
rules:
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
-ee:object-storage-selective:
+object-storage-selective:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::Image
@@ -321,42 +346,42 @@ ee:object-storage-selective:
rules:
- !reference [.rules:test:qa-selective, rules]
- if: $QA_SUITES =~ /Test::Instance::ObjectStorage/
-ee:object-storage:
- extends: ee:object-storage-selective
+object-storage:
+ extends: object-storage-selective
parallel: 2
rules:
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::ObjectStorage/
-ee:object-storage-aws-selective:
- extends: ee:object-storage-selective
+object-storage-aws-selective:
+ extends: object-storage-selective
variables:
AWS_S3_ACCESS_KEY: $QA_AWS_S3_ACCESS_KEY
AWS_S3_BUCKET_NAME: $QA_AWS_S3_BUCKET_NAME
AWS_S3_KEY_ID: $QA_AWS_S3_KEY_ID
AWS_S3_REGION: $QA_AWS_S3_REGION
GITLAB_QA_OPTS: --omnibus-config object_storage_aws
-ee:object-storage-aws:
- extends: ee:object-storage-aws-selective
+object-storage-aws:
+ extends: object-storage-aws-selective
parallel: 2
rules:
- - !reference [ee:object-storage, rules]
+ - !reference [object-storage, rules]
-ee:object-storage-gcs-selective:
- extends: ee:object-storage-selective
+object-storage-gcs-selective:
+ extends: object-storage-selective
variables:
GCS_BUCKET_NAME: $QA_GCS_BUCKET_NAME
GOOGLE_PROJECT: $QA_GOOGLE_PROJECT
GOOGLE_JSON_KEY: $QA_GOOGLE_JSON_KEY
GOOGLE_CLIENT_EMAIL: $QA_GOOGLE_CLIENT_EMAIL
GITLAB_QA_OPTS: --omnibus-config object_storage_gcs
-ee:object-storage-gcs:
- extends: ee:object-storage-gcs-selective
+object-storage-gcs:
+ extends: object-storage-gcs-selective
parallel: 2
rules:
- - !reference [ee:object-storage, rules]
+ - !reference [object-storage, rules]
-ee:packages-selective:
+packages-selective:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::Image
@@ -365,8 +390,8 @@ ee:packages-selective:
rules:
- !reference [.rules:test:qa-selective, rules]
- if: $QA_SUITES =~ /Test::Instance::Packages/
-ee:packages:
- extends: ee:packages-selective
+packages:
+ extends: packages-selective
parallel: 2
rules:
- !reference [.rules:test:qa-parallel, rules]
@@ -375,7 +400,7 @@ ee:packages:
# ------------------------------------------
# Non parallel jobs
# ------------------------------------------
-ee:update-minor:
+update-minor:
extends:
- .qa
- .update-script
@@ -387,7 +412,7 @@ ee:update-minor:
- if: $QA_SUITES =~ /Test::Instance::Smoke/
- !reference [.rules:test:manual, rules]
-ee:update-major:
+update-major:
extends:
- .qa
- .update-script
@@ -399,7 +424,7 @@ ee:update-major:
- if: $QA_SUITES =~ /Test::Instance::Smoke/
- !reference [.rules:test:manual, rules]
-ee:gitlab-pages:
+gitlab-pages:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::GitlabPages
@@ -408,7 +433,7 @@ ee:gitlab-pages:
- if: $QA_SUITES =~ /Test::Instance::GitlabPages/
- !reference [.rules:test:manual, rules]
-ee:gitaly-cluster:
+gitaly-cluster:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::GitalyCluster
@@ -417,16 +442,17 @@ ee:gitaly-cluster:
- if: $QA_SUITES =~ /Test::Integration::GitalyCluster/
- !reference [.rules:test:manual, rules]
-ee:group-saml:
+group-saml:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::GroupSAML
rules:
+ - !reference [.rules:test:ee-only, rules]
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::GroupSAML/
- !reference [.rules:test:manual, rules]
-ee:instance-saml:
+instance-saml:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::InstanceSAML
@@ -435,7 +461,7 @@ ee:instance-saml:
- if: $QA_SUITES =~ /Test::Integration::InstanceSAML/
- !reference [.rules:test:manual, rules]
-ee:jira:
+jira:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::Jira
@@ -446,7 +472,7 @@ ee:jira:
- if: $QA_SUITES =~ /Test::Integration::Jira/
- !reference [.rules:test:manual, rules]
-ee:integrations:
+integrations:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::Integrations
@@ -455,7 +481,7 @@ ee:integrations:
- if: $QA_SUITES =~ /Test::Integration::Integrations/
- !reference [.rules:test:manual, rules]
-ee:ldap-no-server:
+ldap-no-server:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::LDAPNoServer
@@ -464,7 +490,7 @@ ee:ldap-no-server:
- if: $QA_SUITES =~ /Test::Integration::LDAPNoServer/
- !reference [.rules:test:manual, rules]
-ee:ldap-tls:
+ldap-tls:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::LDAPTLS
@@ -473,7 +499,7 @@ ee:ldap-tls:
- if: $QA_SUITES =~ /Test::Integration::LDAPTLS/
- !reference [.rules:test:manual, rules]
-ee:ldap-no-tls:
+ldap-no-tls:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::LDAPNoTLS
@@ -482,7 +508,7 @@ ee:ldap-no-tls:
- if: $QA_SUITES =~ /Test::Integration::LDAPNoTLS/
- !reference [.rules:test:manual, rules]
-ee:mtls:
+mtls:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::MTLS
@@ -491,7 +517,7 @@ ee:mtls:
- if: $QA_SUITES =~ /Test::Integration::Mtls/
- !reference [.rules:test:manual, rules]
-ee:mattermost:
+mattermost:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::Mattermost
@@ -500,7 +526,7 @@ ee:mattermost:
- if: $QA_SUITES =~ /Test::Integration::Mattermost/
- !reference [.rules:test:manual, rules]
-ee:registry:
+registry:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::Registry
@@ -509,7 +535,7 @@ ee:registry:
- if: $QA_SUITES =~ /Test::Integration::Registry/
- !reference [.rules:test:manual, rules]
-ee:registry-with-cdn:
+registry-with-cdn:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::RegistryWithCDN
@@ -526,7 +552,7 @@ ee:registry-with-cdn:
- if: $QA_SUITES =~ /Test::Integration::RegistryWithCDN/
- !reference [.rules:test:manual, rules]
-ee:repository-storage:
+repository-storage:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::RepositoryStorage
@@ -535,7 +561,7 @@ ee:repository-storage:
- if: $QA_SUITES =~ /Test::Instance::RepositoryStorage/
- !reference [.rules:test:manual, rules]
-ee:service-ping-disabled:
+service-ping-disabled:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::ServicePingDisabled
@@ -544,7 +570,7 @@ ee:service-ping-disabled:
- if: $QA_SUITES =~ /Test::Integration::ServicePingDisabled/
- !reference [.rules:test:manual, rules]
-ee:smtp:
+smtp:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::SMTP
@@ -553,7 +579,7 @@ ee:smtp:
- if: $QA_SUITES =~ /Test::Integration::SMTP/
- !reference [.rules:test:manual, rules]
-ee:cloud-activation:
+cloud-activation:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::Image
@@ -563,7 +589,7 @@ ee:cloud-activation:
- if: $QA_SUITES =~ /Test::Instance::CloudActivation/
- !reference [.rules:test:manual, rules]
-ee:large-setup:
+large-setup:
extends: .qa
variables:
QA_SCENARIO: Test::Instance::Image
@@ -573,7 +599,7 @@ ee:large-setup:
- if: $QA_SUITES =~ /Test::Instance::LargeSetup/
- !reference [.rules:test:manual, rules]
-ee:metrics:
+metrics:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::Metrics
@@ -582,31 +608,31 @@ ee:metrics:
- if: $QA_SUITES =~ /Test::Instance::Metrics/
- !reference [.rules:test:manual, rules]
-ee:elasticsearch:
+elasticsearch:
extends: .qa
variables:
QA_SCENARIO: "Test::Integration::Elasticsearch"
before_script:
- !reference [.qa, before_script]
rules:
+ - !reference [.rules:test:ee-only, rules]
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::Elasticsearch/
- !reference [.rules:test:manual, rules]
-ee:registry-object-storage-tls:
- extends: ee:object-storage-aws-selective
+registry-object-storage-tls:
+ extends: object-storage-aws-selective
variables:
QA_SCENARIO: Test::Integration::RegistryTLS
QA_RSPEC_TAGS: ""
GITLAB_TLS_CERTIFICATE: $QA_GITLAB_TLS_CERTIFICATE
GITLAB_QA_OPTS: --omnibus-config registry_object_storage
-ee:importers:
+importers:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::Import
QA_MOCK_GITHUB: "true"
- GITLAB_QA_OPTS: --set-feature-flags bulk_import_projects=enabled
rules:
- !reference [.rules:test:qa, rules]
- if: $QA_SUITES =~ /Test::Integration::Import/
@@ -621,11 +647,26 @@ e2e-test-report:
- .rules:report:allure-report
stage: report
variables:
+ ALLURE_JOB_NAME: e2e-package-and-test
GITLAB_AUTH_TOKEN: $PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE
ALLURE_PROJECT_PATH: $CI_PROJECT_PATH
ALLURE_MERGE_REQUEST_IID: $CI_MERGE_REQUEST_IID
- ALLURE_JOB_NAME: e2e-package-and-test
- GIT_STRATEGY: none
+
+# Temporary separate test report for super-sidebar test job
+# TODO: remove once super-sidebar is on by default and enabled in tests
+# https://gitlab.com/groups/gitlab-org/-/epics/9044
+e2e-test-report-super-sidebar:
+ extends:
+ - .generate-allure-report-base
+ stage: report
+ needs:
+ - _super-sidebar-nav
+ variables:
+ ALLURE_JOB_NAME: e2e-super-sidebar
+ ALLURE_RESULTS_GLOB: gitlab-qa-run-*/**/allure-results-super-sidebar
+ rules:
+ - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
+ - !reference [.rules:test:manual, rules]
upload-knapsack-report:
extends:
diff --git a/.gitlab/ci/package-and-test/rules.gitlab-ci.yml b/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
index 50b07589040..4e597b042dd 100644
--- a/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
@@ -115,12 +115,18 @@
- *qa-run-all-tests
- *feature-flags-set-manual
+.rules:test:ee-only:
+ rules:
+ - if: $FOSS_ONLY == "true"
+ when: never
+
.rules:test:update:
rules:
- # skip upgrade jobs if gitlab version is not provided
+ # skip upgrade jobs if gitlab version is not in semver compatible format
# these jobs need gitlab version because we can't reliably detect it from just the image
- - if: $GITLAB_VERSION == null
+ - if: $GITLAB_SEMVER_VERSION !~ /^\d+\.\d+\.\d+/
when: never
+ - !reference [.rules:test:ee-only, rules]
- !reference [.rules:test:qa, rules]
# ------------------------------------------
diff --git a/.gitlab/ci/package-and-test/variables.gitlab-ci.yml b/.gitlab/ci/package-and-test/variables.gitlab-ci.yml
index c45807e5a23..b7c4e5519ca 100644
--- a/.gitlab/ci/package-and-test/variables.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/variables.gitlab-ci.yml
@@ -6,7 +6,9 @@ variables:
SKIP_REPORT_IN_ISSUES: "true"
OMNIBUS_GITLAB_CACHE_UPDATE: "false"
OMNIBUS_GITLAB_RUBY3_BUILD: "false"
+ OMNIBUS_GITLAB_RUBY2_BUILD: "false"
OMNIBUS_GITLAB_CACHE_EDITION: "GITLAB"
+ ALLURE_JOB_NAME: $CI_PROJECT_NAME
QA_LOG_LEVEL: "info"
QA_TESTS: ""
QA_FEATURE_FLAGS: ""
diff --git a/.gitlab/ci/preflight.gitlab-ci.yml b/.gitlab/ci/preflight.gitlab-ci.yml
index 05b05fde53b..8c1cb44807a 100644
--- a/.gitlab/ci/preflight.gitlab-ci.yml
+++ b/.gitlab/ci/preflight.gitlab-ci.yml
@@ -1,14 +1,63 @@
-rails-production-environment:
+.preflight-job-base:
+ stage: preflight
+ extends:
+ - .default-retry
+ needs: []
+
+.qa-preflight-job:
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-ruby-${RUBY_VERSION}:bundler-2.3-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}
extends:
+ - .preflight-job-base
+ - .qa-cache
+ variables:
+ USE_BUNDLE_INSTALL: "false"
+ SETUP_DB: "false"
+ before_script:
+ - !reference [.default-before_script, before_script]
+ - cd qa && bundle install
+
+rails-production-server-boot:
+ extends:
+ - .preflight-job-base
- .default-before_script
- .production
- .ruby-cache
- - .setup:rules:rails-production-environment
+ - .setup:rules:rails-production-server-boot
- .use-pg12
- stage: preflight
variables:
BUNDLE_WITHOUT: "development:test"
BUNDLE_WITH: "production"
needs: []
script:
- - bundle exec rails runner --environment=production 'puts Rails.env'
+ - source scripts/utils.sh
+ - bundle exec rails server -e production &
+ - sleep 40 # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114124#note_1309506358
+ - retry_times_sleep 10 5 "curl http://0.0.0.0:3000"
+ - kill $(jobs -p)
+
+no-ee-check:
+ extends:
+ - .preflight-job-base
+ - .setup:rules:no-ee-check
+ script:
+ - scripts/no-dir-check ee
+
+no-jh-check:
+ extends:
+ - .preflight-job-base
+ - .setup:rules:no-jh-check
+ script:
+ - scripts/no-dir-check jh
+
+qa:selectors:
+ extends:
+ - .qa-preflight-job
+ - .qa:rules:ee-and-foss
+ script:
+ - bundle exec bin/qa Test::Sanity::Selectors
+
+qa:selectors-as-if-foss:
+ extends:
+ - qa:selectors
+ - .qa:rules:as-if-foss
+ - .as-if-foss
diff --git a/.gitlab/ci/qa.gitlab-ci.yml b/.gitlab/ci/qa.gitlab-ci.yml
index a72e6fc0137..d935fecba01 100644
--- a/.gitlab/ci/qa.gitlab-ci.yml
+++ b/.gitlab/ci/qa.gitlab-ci.yml
@@ -25,13 +25,6 @@ qa:internal-as-if-foss:
- .qa:rules:internal-as-if-foss
- .as-if-foss
-qa:selectors:
- extends:
- - .qa-job-base
- - .qa:rules:ee-and-foss
- script:
- - bundle exec bin/qa Test::Sanity::Selectors
-
qa:master-auto-quarantine-dequarantine:
extends:
- .qa-job-base
@@ -50,12 +43,6 @@ qa:nightly-auto-quarantine-dequarantine:
- bundle exec confiner -r .confiner/nightly.yml
allow_failure: true
-qa:selectors-as-if-foss:
- extends:
- - qa:selectors
- - .qa:rules:as-if-foss
- - .as-if-foss
-
qa:update-qa-cache:
extends:
- .qa-job-base
@@ -65,7 +52,7 @@ qa:update-qa-cache:
script:
- echo "Cache has been updated and ready to be uploaded."
-e2e:package-and-test:
+e2e:package-and-test-ee:
extends:
- .production # this makes sure GITLAB_ALLOW_SEPARATE_CI_DATABASE is passed to the child pipeline
- .qa:rules:package-and-test
@@ -82,6 +69,7 @@ e2e:package-and-test:
GITLAB_QA_IMAGE: "${CI_REGISTRY_IMAGE}/gitlab-ee-qa:${CI_COMMIT_SHA}"
RUN_WITH_BUNDLE: "true" # instructs pipeline to install and run gitlab-qa gem via bundler
QA_PATH: qa # sets the optional path for bundler to run from
+ QA_RUN_TYPE: e2e-package-and-test
inherit:
variables:
- CHROME_VERSION
@@ -89,6 +77,9 @@ e2e:package-and-test:
- DOCKER_VERSION
- REGISTRY_GROUP
- REGISTRY_HOST
+ - OMNIBUS_GITLAB_CACHE_EDITION
+ - OMNIBUS_GITLAB_RUBY3_BUILD
+ - OMNIBUS_GITLAB_RUBY2_BUILD
trigger:
strategy: depend
forward:
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 23f38fddb80..95780116800 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -105,6 +105,18 @@ rspec background_migration pg12 single-db:
- .single-db-rspec
- .rails:rules:single-db
+rspec migration pg12 single-db-ci-connection:
+ extends:
+ - rspec migration pg12
+ - .single-db-ci-connection-rspec
+ - .rails:rules:single-db-ci-connection
+
+rspec background_migration pg12 single-db-ci-connection:
+ extends:
+ - rspec background_migration pg12
+ - .single-db-ci-connection-rspec
+ - .rails:rules:single-db-ci-connection
+
rspec migration pg12 praefect:
extends:
- rspec migration pg12
@@ -191,16 +203,6 @@ rspec system pg12 praefect:
- .praefect-with-db
- .rails:rules:praefect-with-db
-# Dedicated job to test DB library code against PG11.
-# Note that these are already tested against PG12 in the `rspec unit pg12` / `rspec-ee unit pg12` jobs.
-rspec db-library-code pg11:
- extends:
- - .rspec-base-pg11
- - .rails:rules:ee-and-foss-db-library-code
- script:
- - !reference [.base-script, script]
- - rspec_db_library_code
-
rspec fast_spec_helper:
extends:
- .rspec-base-pg12
@@ -438,6 +440,18 @@ rspec background_migration pg12-as-if-foss single-db:
- .single-db-rspec
- .rails:rules:single-db
+rspec migration pg12-as-if-foss single-db-ci-connection:
+ extends:
+ - rspec migration pg12-as-if-foss
+ - .single-db-ci-connection-rspec
+ - .rails:rules:single-db-ci-connection
+
+rspec background_migration pg12-as-if-foss single-db-ci-connection:
+ extends:
+ - rspec background_migration pg12-as-if-foss
+ - .single-db-ci-connection-rspec
+ - .rails:rules:single-db-ci-connection
+
rspec unit pg12-as-if-foss:
extends:
- .rspec-base-pg12-as-if-foss
@@ -530,6 +544,18 @@ rspec-ee background_migration pg12 single-db:
- .single-db-rspec
- .rails:rules:single-db
+rspec-ee migration pg12 single-db-ci-connection:
+ extends:
+ - rspec-ee migration pg12
+ - .single-db-ci-connection-rspec
+ - .rails:rules:single-db-ci-connection
+
+rspec-ee background_migration pg12 single-db-ci-connection:
+ extends:
+ - rspec-ee background_migration pg12
+ - .single-db-ci-connection-rspec
+ - .rails:rules:single-db-ci-connection
+
rspec-ee migration pg12 praefect:
extends:
- rspec migration pg12
@@ -616,39 +642,6 @@ rspec-ee system pg12 single-db:
##########################################
# EE/FOSS: default branch nightly scheduled jobs #
-# PG11
-rspec migration pg11:
- extends:
- - .rspec-base-pg11
- - .rspec-base-migration
- - .rails:rules:rspec-on-pg11
- - .rspec-migration-parallel
-
-rspec background_migration pg11:
- extends:
- - .rspec-base-pg11
- - .rspec-base-migration
- - .rails:rules:rspec-on-pg11
- - .rspec-background-migration-parallel
-
-rspec unit pg11:
- extends:
- - .rspec-base-pg11
- - .rails:rules:rspec-on-pg11
- - .rspec-unit-parallel
-
-rspec integration pg11:
- extends:
- - .rspec-base-pg11
- - .rails:rules:rspec-on-pg11
- - .rspec-integration-parallel
-
-rspec system pg11:
- extends:
- - .rspec-base-pg11
- - .rails:rules:rspec-on-pg11
- - .rspec-system-parallel
-
# PG13
rspec migration pg13:
extends:
@@ -687,75 +680,36 @@ rspec system pg13:
#####################################
# EE: default branch nightly scheduled jobs #
-# PG11
-rspec-ee migration pg11:
- extends:
- - .rspec-ee-base-pg11
- - .rspec-base-migration
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- - .rspec-ee-migration-parallel
-
-rspec-ee background_migration pg11:
- extends:
- - .rspec-ee-base-pg11
- - .rspec-base-migration
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- - .rspec-ee-background-migration-parallel
-
-rspec-ee unit pg11:
- extends:
- - .rspec-ee-base-pg11
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- - .rspec-ee-unit-parallel
-
-rspec-ee integration pg11:
- extends:
- - .rspec-ee-base-pg11
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- - .rspec-ee-integration-parallel
-
-rspec-ee system pg11:
- extends:
- - .rspec-ee-base-pg11
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- - .rspec-ee-system-parallel
-
# PG12
rspec-ee unit pg12 opensearch1:
extends:
- .rspec-ee-base-pg12-opensearch1
- .rspec-ee-unit-parallel
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee unit pg12 opensearch2:
extends:
- .rspec-ee-base-pg12-opensearch2
- .rspec-ee-unit-parallel
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee integration pg12 opensearch1:
extends:
- .rspec-ee-base-pg12-opensearch1
- .rspec-ee-integration-parallel
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee integration pg12 opensearch2:
extends:
- .rspec-ee-base-pg12-opensearch2
- .rspec-ee-integration-parallel
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg12 opensearch1:
extends:
- .rspec-ee-base-pg12-opensearch1
- .rspec-ee-system-parallel
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg12 opensearch2:
extends:
- .rspec-ee-base-pg12-opensearch2
- .rspec-ee-system-parallel
- - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# PG13
rspec-ee migration pg13:
@@ -821,13 +775,14 @@ rspec-foss-impact:pipeline-generate:
extends:
- .rails:rules:rspec-foss-impact
stage: prepare
- needs: ["detect-tests"]
+ needs: ["detect-tests", "retrieve-tests-metadata"]
script:
- - scripts/generate-rspec-foss-impact-pipeline "${RSPEC_MATCHING_TESTS_FOSS_PATH}" "${RSPEC_FOSS_IMPACT_PIPELINE_YML}"
+ - scripts/generate_rspec_pipeline.rb -f "${RSPEC_MATCHING_TESTS_FOSS_PATH}" -t "${RSPEC_FOSS_IMPACT_PIPELINE_TEMPLATE_YML}" -k "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}"
+ - cat "${RSPEC_FOSS_IMPACT_PIPELINE_TEMPLATE_YML}.yml"
artifacts:
expire_in: 1 day
paths:
- - $RSPEC_FOSS_IMPACT_PIPELINE_YML
+ - "${RSPEC_FOSS_IMPACT_PIPELINE_TEMPLATE_YML}.yml"
rspec-foss-impact:trigger:
extends:
@@ -850,7 +805,7 @@ rspec-foss-impact:trigger:
yaml_variables: true
pipeline_variables: true
include:
- - artifact: $RSPEC_FOSS_IMPACT_PIPELINE_YML
+ - artifact: "${RSPEC_FOSS_IMPACT_PIPELINE_TEMPLATE_YML}.yml"
job: rspec-foss-impact:pipeline-generate
fail-pipeline-early:
diff --git a/.gitlab/ci/rails/rspec-foss-impact.gitlab-ci.yml.erb b/.gitlab/ci/rails/rspec-foss-impact.gitlab-ci.yml.erb
index eb54fa25875..02b7d61a4fa 100644
--- a/.gitlab/ci/rails/rspec-foss-impact.gitlab-ci.yml.erb
+++ b/.gitlab/ci/rails/rspec-foss-impact.gitlab-ci.yml.erb
@@ -21,7 +21,7 @@ dont-interrupt-me:
script:
- echo "This jobs makes sure this pipeline won't be interrupted! See https://docs.gitlab.com/ee/ci/yaml/#interruptible."
-rspec foss-impact:
+.base-rspec-foss-impact:
extends: .rspec-base-pg12-as-if-foss
needs:
- pipeline: $PARENT_PIPELINE_ID
@@ -37,9 +37,6 @@ rspec foss-impact:
variables:
RSPEC_TESTS_FILTER_FILE: "${RSPEC_MATCHING_TESTS_FOSS_PATH}"
RSPEC_TESTS_MAPPING_ENABLED: "true"
-<% if Integer(parallel_value) > 1 %>
- parallel: <%= parallel_value %>
-<% end %>
script:
- !reference [.base-script, script]
- rspec_paralellized_job "--tag ~quarantine --tag ~level:migration --tag ~zoekt"
@@ -48,3 +45,46 @@ rspec foss-impact:
paths:
- "${RSPEC_MATCHING_TESTS_FOSS_PATH}"
- tmp/capybara/
+
+<% if rspec_files_per_test_level[:migration][:files].size > 0 %>
+rspec migration foss-impact:
+ extends: .base-rspec-foss-impact
+<% if rspec_files_per_test_level[:migration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:migration][:parallelization] %>
+<% end %>
+ script:
+ - !reference [.base-script, script]
+ - rspec_paralellized_job "--tag ~quarantine --tag ~zoekt"
+<% end %>
+
+<% if rspec_files_per_test_level[:background_migration][:files].size > 0 %>
+rspec background_migration foss-impact:
+ extends: .base-rspec-foss-impact
+<% if rspec_files_per_test_level[:background_migration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:background_migration][:parallelization] %>
+<% end %>
+<% end %>
+
+<% if rspec_files_per_test_level[:unit][:files].size > 0 %>
+rspec unit foss-impact:
+ extends: .base-rspec-foss-impact
+<% if rspec_files_per_test_level[:unit][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:unit][:parallelization] %>
+<% end %>
+<% end %>
+
+<% if rspec_files_per_test_level[:integration][:files].size > 0 %>
+rspec integration foss-impact:
+ extends: .base-rspec-foss-impact
+<% if rspec_files_per_test_level[:integration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:integration][:parallelization] %>
+<% end %>
+<% end %>
+
+<% if rspec_files_per_test_level[:system][:files].size > 0 %>
+rspec system foss-impact:
+ extends: .base-rspec-foss-impact
+<% if rspec_files_per_test_level[:system][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:system][:parallelization] %>
+<% end %>
+<% end %>
diff --git a/.gitlab/ci/rails/shared.gitlab-ci.yml b/.gitlab/ci/rails/shared.gitlab-ci.yml
index 4943f7c2e28..0fa65b0be90 100644
--- a/.gitlab/ci/rails/shared.gitlab-ci.yml
+++ b/.gitlab/ci/rails/shared.gitlab-ci.yml
@@ -36,9 +36,17 @@ include:
variables:
DECOMPOSED_DB: "false"
+.single-db-ci-connection:
+ extends: .single-db
+ variables:
+ CI_CONNECTION_DB: "true"
+
.single-db-rspec:
extends: .single-db
+.single-db-ci-connection-rspec:
+ extends: .single-db-ci-connection
+
.praefect-with-db:
variables:
GITALY_PRAEFECT_WITH_DB: '1'
@@ -92,11 +100,6 @@ include:
- !reference [.base-script, script]
- rspec_paralellized_job "--tag ~quarantine --tag ~zoekt"
-.rspec-base-pg11:
- extends:
- - .rspec-base
- - .use-pg11
-
.rspec-base-pg12:
extends:
- .rspec-base
@@ -119,11 +122,6 @@ include:
- .rspec-base
- .use-pg13
-.rspec-ee-base-pg11:
- extends:
- - .rspec-base
- - .use-pg11-es7-ee
-
.rspec-ee-base-pg12:
extends:
- .rspec-base
diff --git a/.gitlab/ci/release-environments.gitlab-ci.yml b/.gitlab/ci/release-environments.gitlab-ci.yml
index a9d9c938ee0..24eca1caf4c 100644
--- a/.gitlab/ci/release-environments.gitlab-ci.yml
+++ b/.gitlab/ci/release-environments.gitlab-ci.yml
@@ -9,7 +9,8 @@ start-release-environments-pipeline:
#
# https://gitlab.com/gitlab-org/gitlab/-/issues/387183
inherit:
- variables: false
+ variables:
+ - RUBY_VERSION
# These variables are set in the pipeline schedules.
# They need to be explicitly passed on to the child pipeline.
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index 3242ca29d75..c77ee0276c6 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -3,7 +3,6 @@ include:
- template: Jobs/SAST.gitlab-ci.yml
- template: Jobs/Secret-Detection.gitlab-ci.yml
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
- - template: Jobs/License-Scanning.gitlab-ci.yml
code_quality:
extends:
@@ -126,11 +125,3 @@ package_hunter-bundler:
- .reports:rules:package_hunter-bundler
variables:
PACKAGE_MANAGER: bundler
-
-license_scanning:
- extends: .default-retry
- stage: lint
- needs: []
- artifacts:
- expire_in: 1 week # GitLab-specific
- rules: !reference [".reports:rules:license_scanning", rules]
diff --git a/.gitlab/ci/review-apps/main.gitlab-ci.yml b/.gitlab/ci/review-apps/main.gitlab-ci.yml
index 369330f8189..6bd7542bcde 100644
--- a/.gitlab/ci/review-apps/main.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/main.gitlab-ci.yml
@@ -89,13 +89,13 @@ review-build-cng:
strategy: depend
.review-workflow-base:
- extends:
- - .default-retry
image: ${REVIEW_APPS_IMAGE}
+ retry:
+ max: 2 # This is confusing but this means "3 runs at max"
variables:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
- GITLAB_HELM_CHART_REF: "afcef7854ac72c5ff958035ef210ba6c68ec800b" # 6.8.0: https://gitlab.com/gitlab-org/charts/gitlab/-/commit/afcef7854ac72c5ff958035ef210ba6c68ec800b
+ GITLAB_HELM_CHART_REF: "febc4ad69acb7bba0eeb4a62daa577d0b7c3ee71" # 6.9.1: https://gitlab.com/gitlab-org/charts/gitlab/-/commit/febc4ad69acb7bba0eeb4a62daa577d0b7c3ee71
environment:
name: review/${CI_COMMIT_REF_SLUG}${SCHEDULE_TYPE} # No separator for SCHEDULE_TYPE so it's compatible as before and looks nice without it
url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
diff --git a/.gitlab/ci/review-apps/qa.gitlab-ci.yml b/.gitlab/ci/review-apps/qa.gitlab-ci.yml
index edca2cae1c6..12a7ddebc45 100644
--- a/.gitlab/ci/review-apps/qa.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/qa.gitlab-ci.yml
@@ -1,6 +1,6 @@
include:
- project: gitlab-org/quality/pipeline-common
- ref: 2.0.0
+ ref: 2.2.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 2762b4e5137..b4301c72347 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -85,9 +85,6 @@
.if-merge-request-labels-run-review-app: &if-merge-request-labels-run-review-app
if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-review-app/'
-.if-merge-request-labels-run-on-pg11: &if-merge-request-labels-run-on-pg11
- if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-on-pg11/'
-
.if-merge-request-labels-skip-undercoverage: &if-merge-request-labels-skip-undercoverage
if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:skip-undercoverage/'
@@ -127,6 +124,9 @@
.if-foss-schedule: &if-foss-schedule
if: '$CI_PROJECT_PATH == "gitlab-org/gitlab-foss" && $CI_PIPELINE_SOURCE == "schedule"'
+.if-foss-default-branch: &if-foss-default-branch
+ if: '$CI_PROJECT_PATH == "gitlab-org/gitlab-foss" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
+
.if-dot-com-gitlab-org-schedule: &if-dot-com-gitlab-org-schedule
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_PIPELINE_SOURCE == "schedule"'
@@ -310,6 +310,9 @@
.models-patterns: &models-patterns
- "{,ee/,jh/}{app/models}/**/*"
+.decomposed-db-models-patterns: &decomposed-db-models-patterns
+ - "{,ee/,jh/}app/models/{ci,geo}/**/*"
+
.lib-gitlab-patterns: &lib-gitlab-patterns
- "{,ee/,jh/}lib/{,ee/,jh/}gitlab/**/*"
@@ -349,11 +352,13 @@
- "{,ee/,jh/}{,spec/}lib/{,ee/,jh/}gitlab/background_migration/**/*"
- "{,ee/,jh/}{,spec/}lib/{,ee/,jh/}gitlab/database{,_spec}.rb"
- "{,ee/,jh/}{,spec/}lib/{,ee/,jh/}gitlab/database/**/*"
+ - "{,ee/,jh/}spec/support/db_cleaner.rb"
- "{,ee/,jh/}spec/support/helpers/database/**/*"
- "{,ee/,jh/}spec/support/helpers/migrations_helpers/**/*"
- "lib/api/admin/batched_background_migrations.rb"
- "lib/gitlab/markdown_cache/active_record/**/*"
- "spec/requests/api/admin/batched_background_migrations_spec.rb"
+ - "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
# Gitaly has interactions with background migrations: https://gitlab.com/gitlab-org/gitlab/-/issues/336538
@@ -618,6 +623,7 @@
.rails:rules:run-search-tests:
rules:
+ - !reference [".rails:rules:default-branch-schedule-nightly--code-backstage-ee-only", rules]
- <<: *if-merge-request-labels-group-global-search
changes: *search-backend-patterns
- <<: *if-merge-request-labels-group-global-search
@@ -968,6 +974,7 @@
.frontend:rules:default-frontend-jobs:
rules:
- <<: *if-merge-request-labels-run-all-rspec
+ - <<: *if-merge-request-labels-frontend-and-feature-flag
- <<: *if-default-refs
changes: *code-backstage-patterns
@@ -992,6 +999,22 @@
- <<: *if-merge-request
changes: *frontend-patterns-for-as-if-foss
+.frontend:rules:upload-frontend-fixtures:
+ rules:
+ # 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-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"
+ - "scripts/gitlab_component_helpers.sh"
+ when: manual
+ allow_failure: true
+
.frontend:rules:jest:
rules:
- <<: *if-fork-merge-request
@@ -1108,6 +1131,15 @@
when: on_failure
allow_failure: true
+.notify:rules:create-issues-for-failing-tests:
+ rules:
+ # Don't report child pipeline failures
+ - if: '$CI_PIPELINE_SOURCE == "parent_pipeline"'
+ when: never
+ - if: '$CREATE_ISSUES_FOR_FAILING_TESTS == "true"'
+ when: on_failure
+ allow_failure: true
+
###############
# Pages rules #
###############
@@ -1233,6 +1265,8 @@
- <<: *if-merge-request-labels-run-single-db
- <<: *if-merge-request
changes: *db-patterns
+ - <<: *if-merge-request
+ changes: *decomposed-db-models-patterns
- <<: *if-default-branch-schedule-nightly
.rails:rules:db:check-migrations-single-db:
@@ -1240,6 +1274,25 @@
- <<: *if-merge-request-labels-run-single-db
- <<: *if-merge-request
changes: *db-patterns
+ - <<: *if-merge-request
+ changes: *decomposed-db-models-patterns
+
+.rails:rules:single-db-ci-connection:
+ rules:
+ - <<: *if-merge-request-labels-run-single-db
+ - <<: *if-merge-request
+ changes: *db-patterns
+ - <<: *if-merge-request
+ changes: *decomposed-db-models-patterns
+ - <<: *if-default-branch-schedule-nightly
+
+.rails:rules:db:check-migrations-single-db-ci-connection:
+ rules:
+ - <<: *if-merge-request-labels-run-single-db
+ - <<: *if-merge-request
+ changes: *db-patterns
+ - <<: *if-merge-request
+ changes: *decomposed-db-models-patterns
.rails:rules:db-backup:
rules:
@@ -1326,6 +1379,8 @@
- !reference [".rails:rules:ee-and-foss-default-rules", rules]
- <<: *if-default-refs
changes: *backend-patterns
+ - <<: *if-default-refs
+ changes: *backstage-patterns
.rails:rules:ee-and-foss-unit:predictive:
rules:
@@ -1335,6 +1390,8 @@
- !reference [".rails:rules:unit-integration:predictive-default-rules", rules]
- <<: *if-merge-request
changes: *backend-patterns
+ - <<: *if-merge-request
+ changes: *backstage-patterns
.rails:rules:ee-and-foss-integration:
rules:
@@ -1605,7 +1662,6 @@
- <<: *if-default-refs
changes: *db-library-patterns
- <<: *if-merge-request-labels-run-all-rspec
- - <<: *if-merge-request-labels-run-on-pg11
.rails:rules:ee-mr-and-default-branch-only:
rules:
@@ -1695,11 +1751,6 @@
- <<: *if-merge-request
changes: *backend-patterns
-.rails:rules:rspec-on-pg11:
- rules:
- - <<: *if-merge-request-labels-run-on-pg11
- - !reference [".rails:rules:default-branch-schedule-nightly--code-backstage-default-rules", rules]
-
.rails:rules:default-branch-schedule-nightly--code-backstage-default-rules:
rules:
- <<: *if-default-branch-schedule-nightly
@@ -1892,6 +1943,12 @@
changes: ["vendor/gems/bundler-checksum/**/*"]
- <<: *if-merge-request-labels-run-all-rspec
+.vendor:rules:cloud_profiler_agent:
+ rules:
+ - <<: *if-merge-request
+ changes: ["vendor/gems/cloud_profiler_agent/**/*"]
+ - <<: *if-merge-request-labels-run-all-rspec
+
##################
# Releases rules #
##################
@@ -2014,13 +2071,6 @@
- <<: *if-merge-request
changes: ["Gemfile.lock"]
-.reports:rules:license_scanning:
- rules:
- - if: '$LICENSE_MANAGEMENT_DISABLED || $GITLAB_FEATURES !~ /\blicense_scanning\b/'
- when: never
- - <<: *if-default-refs
- changes: *dependency-patterns
-
################
# Review rules #
################
@@ -2185,7 +2235,7 @@
- <<: *if-default-refs
changes: *code-backstage-patterns
-.setup:rules:rails-production-environment:
+.setup:rules:rails-production-server-boot:
rules:
- <<: *if-default-refs
changes: *code-patterns
@@ -2242,6 +2292,7 @@
- <<: *if-default-refs
changes: *workhorse-patterns
- <<: *if-merge-request-labels-run-all-rspec
+ - <<: *if-merge-request-labels-frontend-and-feature-flag
.test-metadata:rules:update-tests-metadata:
rules:
diff --git a/.gitlab/ci/setup.gitlab-ci.yml b/.gitlab/ci/setup.gitlab-ci.yml
index 298d5c4ae08..76c7af2753e 100644
--- a/.gitlab/ci/setup.gitlab-ci.yml
+++ b/.gitlab/ci/setup.gitlab-ci.yml
@@ -51,22 +51,6 @@ gitlab_git_test:
script:
- spec/support/prepare-gitlab-git-test-for-commit --check-for-changes
-no-ee-check:
- extends:
- - .predictive-job
- - .setup:rules:no-ee-check
- stage: test
- script:
- - scripts/no-dir-check ee
-
-no-jh-check:
- extends:
- - .predictive-job
- - .setup:rules:no-jh-check
- stage: test
- script:
- - scripts/no-dir-check jh
-
verify-ruby-3.0:
extends:
- .absolutely-predictive-job
diff --git a/.gitlab/ci/vendored-gems.gitlab-ci.yml b/.gitlab/ci/vendored-gems.gitlab-ci.yml
index 1086d9074d2..e1b4960b262 100644
--- a/.gitlab/ci/vendored-gems.gitlab-ci.yml
+++ b/.gitlab/ci/vendored-gems.gitlab-ci.yml
@@ -93,3 +93,11 @@ vendor gitlab_active_record:
trigger:
include: vendor/gems/gitlab_active_record/.gitlab-ci.yml
strategy: depend
+
+vendor cloud_profiler_agent:
+ extends:
+ - .vendor:rules:cloud_profiler_agent
+ needs: []
+ trigger:
+ include: vendor/gems/cloud_profiler_agent/.gitlab-ci.yml
+ strategy: depend
diff --git a/.gitlab/issue_templates/Geo Replicate a new Git repository type.md b/.gitlab/issue_templates/Geo Replicate a new Git repository type.md
index eee989ed21e..c33e5f8eb68 100644
--- a/.gitlab/issue_templates/Geo Replicate a new Git repository type.md
+++ b/.gitlab/issue_templates/Geo Replicate a new Git repository type.md
@@ -54,7 +54,7 @@ Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org
```ruby
# frozen_string_literal: true
- class CreateCoolWidgetRegistry < Gitlab::Database::Migration[2.0]
+ class CreateCoolWidgetRegistry < Gitlab::Database::Migration[2.1]
def change
create_table :cool_widget_registry, id: :bigserial, force: :cascade do |t|
t.bigint :cool_widget_id, null: false
@@ -80,11 +80,19 @@ Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org
t.index :retry_at
t.index :state
# To optimize performance of CoolWidgetRegistry.verification_failed_batch
- t.index :verification_retry_at, name: :cool_widget_registry_failed_verification, order: "NULLS FIRST", where: "((state = 2) AND (verification_state = 3))"
+ t.index :verification_retry_at,
+ name: :cool_widget_registry_failed_verification,
+ order: "NULLS FIRST",
+ where: "((state = 2) AND (verification_state = 3))"
# To optimize performance of CoolWidgetRegistry.needs_verification_count
- t.index :verification_state, name: :cool_widget_registry_needs_verification, where: "((state = 2) AND (verification_state = ANY (ARRAY[0, 3])))"
+ t.index :verification_state,
+ name: :cool_widget_registry_needs_verification,
+ where: "((state = 2) AND (verification_state = ANY (ARRAY[0, 3])))"
# To optimize performance of CoolWidgetRegistry.verification_pending_batch
- t.index :verified_at, name: :cool_widget_registry_pending_verification, order: "NULLS FIRST", where: "((state = 2) AND (verification_state = 0))"
+ t.index :verified_at,
+ name: :cool_widget_registry_pending_verification,
+ order: "NULLS FIRST",
+ where: "((state = 2) AND (verification_state = 0))"
end
end
end
@@ -92,7 +100,7 @@ Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org
- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
-- [ ] Add the new table to the [database dictionary](database_dictionary.md) defined in [`ee/db/docs/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/db/docs):
+- [ ] Add the new table to the [database dictionary](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/database/database_dictionary.md) defined in [`ee/db/docs/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/db/docs):
```yaml
table_name: cool_widget_registry
@@ -129,7 +137,7 @@ The Geo primary site needs to checksum every replicable so secondaries can verif
```ruby
# frozen_string_literal: true
- class CreateCoolWidgetStates < Gitlab::Database::Migration[2.0]
+ class CreateCoolWidgetStates < Gitlab::Database::Migration[2.1]
VERIFICATION_STATE_INDEX_NAME = "index_cool_widget_states_on_verification_state"
PENDING_VERIFICATION_INDEX_NAME = "index_cool_widget_states_pending_verification"
FAILED_VERIFICATION_INDEX_NAME = "index_cool_widget_states_failed_verification"
@@ -149,9 +157,17 @@ The Geo primary site needs to checksum every replicable so secondaries can verif
t.text :verification_failure, limit: 255
t.index :verification_state, name: VERIFICATION_STATE_INDEX_NAME
- t.index :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME
- t.index :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME
- t.index :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME
+ t.index :verified_at,
+ where: "(verification_state = 0)",
+ order: { verified_at: 'ASC NULLS FIRST' },
+ name: PENDING_VERIFICATION_INDEX_NAME
+ t.index :verification_retry_at,
+ where: "(verification_state = 3)",
+ order: { verification_retry_at: 'ASC NULLS FIRST' },
+ name: FAILED_VERIFICATION_INDEX_NAME
+ t.index :verification_state,
+ where: "(verification_state = 0 OR verification_state = 3)",
+ name: NEEDS_VERIFICATION_INDEX_NAME
end
end
@@ -163,17 +179,20 @@ The Geo primary site needs to checksum every replicable so secondaries can verif
- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
-- [ ] Add the new table to the [database dictionary](database_dictionary.md) defined in [`db/docs/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/db/docs):
+- [ ] If `cool_widgets` is a high-traffic table, follow [the database documentation to use `with_lock_retries`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/migration_style_guide.md#when-to-use-the-helper-method)
+
+- [ ] Add the new table to the [database dictionary](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/database/database_dictionary.md) defined in [`db/docs/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/db/docs):
```yaml
+ ---
table_name: cool_widget_states
- description: Description example
- introduced_by_url: Merge request link
- milestone: Milestone example
+ description: Separate table for cool widget verification states
+ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/XXXXX
+ milestone: 'XX.Y'
feature_categories:
- - Feature category example
+ - geo_replication
classes:
- - Class example
+ - Geo::CoolWidgetState
gitlab_schema: gitlab_main
```
@@ -185,20 +204,6 @@ The Geo primary site needs to checksum every replicable so secondaries can verif
- [ ] Be sure to commit the relevant changes in `db/structure.sql` and the file under `db/schema_migrations`
-- [ ] Add an entry for the state table in `db/docs/cool_widget_states.yml`
-
- ```yaml
- ---
- table_name: cool_widget_states
- classes:
- - Geo::CoolWidgetState
- feature_categories:
- - geo_replication
- description: Separate table for cool widget verification states
- introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/XXXXX
- milestone: 'XX.Y'
- ```
-
That's all of the required database changes.
### Implement Geo support of Cool Widgets behind a feature flag
@@ -230,23 +235,30 @@ That's all of the required database changes.
with_replicator Geo::CoolWidgetReplicator
- mount_uploader :file, CoolWidgetUploader
-
has_one :cool_widget_state, autosave: false, inverse_of: :cool_widget, class_name: 'Geo::CoolWidgetState'
after_save :save_verification_details
- scope :with_verification_state, ->(state) { joins(:cool_widget_state).where(cool_widget_states: { verification_state: verification_state_value(state) }) }
- scope :checksummed, -> { joins(:cool_widget_state).where.not(cool_widget_states: { verification_checksum: nil } ) }
- scope :not_checksummed, -> { joins(:cool_widget_state).where(cool_widget_states: { verification_checksum: nil } ) }
-
- scope :available_verifiables, -> { joins(:cool_widget_state) }
-
# Override the `all` default if not all records can be replicated. For an
# example of an existing Model that needs to do this, see
# `EE::MergeRequestDiff`.
# scope :available_replicables, -> { all }
+ scope :available_verifiables, -> { joins(:cool_widget_state) }
+
+ scope :checksummed, -> {
+ joins(:cool_widget_state).where.not(cool_widget_states: { verification_checksum: nil })
+ }
+
+ scope :not_checksummed, -> {
+ joins(:cool_widget_state).where(cool_widget_states: { verification_checksum: nil })
+ }
+
+ scope :with_verification_state, ->(state) {
+ joins(:cool_widget_state)
+ .where(cool_widget_states: { verification_state: verification_state_value(state) })
+ }
+
def verification_state_object
cool_widget_state
end
@@ -257,7 +269,8 @@ That's all of the required database changes.
...
# @param primary_key_in [Range, CoolWidget] arg to pass to primary_key_in scope
- # @return [ActiveRecord::Relation<CoolWidget>] everything that should be synced to this node, restricted by primary key
+ # @return [ActiveRecord::Relation<CoolWidget>] everything that should be synced
+ # to this node, restricted by primary key
def replicables_for_current_secondary(primary_key_in)
# This issue template does not help you write this method.
#
@@ -265,7 +278,8 @@ That's all of the required database changes.
# we want to know which records to replicate. This is not easy to automate
# because for example:
#
- # * The "selective sync" feature allows admins to choose which namespaces # to replicate, per secondary site. Most Models are scoped to a
+ # * The "selective sync" feature allows admins to choose which namespaces
+ # to replicate, per secondary site. Most Models are scoped to a
# namespace, but the nature of the relationship to a namespace varies
# between Models.
# * The "selective sync" feature allows admins to choose which shards to
@@ -304,8 +318,8 @@ That's all of the required database changes.
```ruby
include_examples 'a replicable model with a separate table for verification state' do
- let(:verifiable_model_record) { build(:cool_widget) } # add extra params if needed to make sure the record is included in `available_verifiables`
- let(:unverifiable_model_record) { build(:cool_widget) } # add extra params if needed to make sure the record is NOT included in `available_verifiables`
+ let(:verifiable_model_record) { build(:cool_widget) } # add extra params if needed to make sure the record is in `Geo::ReplicableModel.verifiables` scope
+ let(:unverifiable_model_record) { build(:cool_widget) } # add extra params if needed to make sure the record is NOT included in `Geo::ReplicableModel.verifiables` scope
end
```
@@ -323,10 +337,6 @@ That's all of the required database changes.
::CoolWidget
end
- def repository
- model_record.repository
- end
-
def self.git_access_class
::Gitlab::GitAccessCoolWidget
end
@@ -353,6 +363,10 @@ That's all of the required database changes.
# (see `RepositoryReplicatorStrategy#before_housekeeping`)
false
end
+
+ def repository
+ model_record.repository
+ end
end
end
```
@@ -402,7 +416,7 @@ That's all of the required database changes.
require 'spec_helper'
- RSpec.describe Geo::CoolWidgetReplicator do
+ RSpec.describe Geo::CoolWidgetReplicator, feature_category: :geo_replication do
let(:model_record) { build(:cool_widget) }
include_examples 'a repository replicator'
@@ -476,7 +490,7 @@ That's all of the required database changes.
require 'spec_helper'
- RSpec.describe Geo::CoolWidgetRegistry, :geo, type: :model do
+ RSpec.describe Geo::CoolWidgetRegistry, :geo, type: :model, feature_category: :geo_replication do
let_it_be(:registry) { create(:geo_cool_widget_registry) }
specify 'factory is valid' do
@@ -491,17 +505,21 @@ That's all of the required database changes.
- [ ] Add the following to `ee/spec/factories/cool_widgets.rb`:
```ruby
+ # frozen_string_literal: true
+
FactoryBot.modify do
- trait :verification_succeeded do
- with_file
- verification_checksum { 'abc' }
- verification_state { CoolWidget.verification_state_value(:verification_succeeded) }
- end
+ factory :cool_widget do
+ trait :verification_succeeded do
+ with_file
+ verification_checksum { 'abc' }
+ verification_state { CoolWidget.verification_state_value(:verification_succeeded) }
+ end
- trait :verification_failed do
- with_file
- verification_failure { 'Could not calculate the checksum' }
- verification_state { CoolWidget.verification_state_value(:verification_failed) }
+ trait :verification_failed do
+ with_file
+ verification_failure { 'Could not calculate the checksum' }
+ verification_state { CoolWidget.verification_state_value(:verification_failed) }
+ end
end
end
```
@@ -549,7 +567,7 @@ That's all of the required database changes.
end
```
-- [ ] Add `[:cool_widget, :remote_store]` and `[:geo_cool_widget_state, any]` to `skipped` in `spec/models/factories_spec.rb`
+- [ ] Add `[:geo_cool_widget_state, any]` to `skipped` in `spec/models/factories_spec.rb`
#### Step 2. Implement metrics gathering
@@ -573,18 +591,18 @@ Metrics are gathered by `Geo::MetricsUpdateWorker`, persisted in `GeoNodeStatus`
- [ ] Add the following fields to the `Sidekiq metrics` table in `doc/administration/monitoring/prometheus/gitlab_metrics.md`:
```markdown
| `geo_cool_widgets` | Gauge | XX.Y | Number of Cool Widgets on primary | `url` |
- | `geo_cool_widgets_checksum_total` | Gauge | XX.Y | Number of Cool Widgets checksummed successfully on primary | `url` |
- | `geo_cool_widgets_checksummed` | Gauge | XX.Y | Number of Cool Widgets failed to calculate the checksum on primary | `url` |
- | `geo_cool_widgets_checksum_failed` | Gauge | XX.Y | Number of Cool Widgets tried to checksum on primary | `url` |
+ | `geo_cool_widgets_checksum_total` | Gauge | XX.Y | Number of Cool Widgets to checksum on primary | `url` |
+ | `geo_cool_widgets_checksummed` | Gauge | XX.Y | Number of Cool Widgets that successfully calculated the checksum on primary | `url` |
+ | `geo_cool_widgets_checksum_failed` | Gauge | XX.Y | Number of Cool Widgets that failed to calculate the checksum on primary | `url` |
| `geo_cool_widgets_synced` | Gauge | XX.Y | Number of syncable Cool Widgets synced on secondary | `url` |
| `geo_cool_widgets_failed` | Gauge | XX.Y | Number of syncable Cool Widgets failed to sync on secondary | `url` |
| `geo_cool_widgets_registry` | Gauge | XX.Y | Number of Cool Widgets in the registry | `url` |
- | `geo_cool_widgets_verification_total` | Gauge | XX.Y | Number of Cool Widgets verified on secondary | `url` |
- | `geo_cool_widgets_verified` | Gauge | XX.Y | Number of Cool Widgets' verifications failed on secondary | `url` |
- | `geo_cool_widgets_verification_failed` | Gauge | XX.Y | Number of Cool Widgets' verifications tried on secondary | `url` |
+ | `geo_cool_widgets_verification_total` | Gauge | XX.Y | Number of Cool Widgets to attempt to verify on secondary | `url` |
+ | `geo_cool_widgets_verified` | Gauge | XX.Y | Number of Cool Widgets successfully verified on secondary | `url` |
+ | `geo_cool_widgets_verification_failed` | Gauge | XX.Y | Number of Cool Widgets that failed verification on secondary | `url` |
```
-Cool Widget replication and verification metrics should now be available in the API, the `Admin > Geo > Nodes` view, and Prometheus.
+Cool Widget replication and verification metrics should now be available in the API, the `Admin > Geo > Sites` view, and Prometheus.
#### Step 3. Implement the GraphQL API
@@ -625,7 +643,7 @@ The GraphQL API is used by `Admin > Geo > Replication Details` views, and is dir
require 'spec_helper'
- RSpec.describe Resolvers::Geo::CoolWidgetRegistriesResolver do
+ RSpec.describe Resolvers::Geo::CoolWidgetRegistriesResolver, feature_category: :geo_replication do
it_behaves_like 'a Geo registries resolver', :geo_cool_widget_registry
end
```
@@ -649,7 +667,7 @@ The GraphQL API is used by `Admin > Geo > Replication Details` views, and is dir
require 'spec_helper'
- RSpec.describe Geo::CoolWidgetRegistryFinder do
+ RSpec.describe Geo::CoolWidgetRegistryFinder, feature_category: :geo_replication do
it_behaves_like 'a framework registry finder', :geo_cool_widget_registry
end
```
@@ -683,7 +701,7 @@ The GraphQL API is used by `Admin > Geo > Replication Details` views, and is dir
require 'spec_helper'
- RSpec.describe GitlabSchema.types['CoolWidgetRegistry'] do
+ RSpec.describe GitlabSchema.types['CoolWidgetRegistry'], feature_category: :geo_replication do
it_behaves_like 'a Geo registry type'
it 'has the expected fields (other than those included in RegistryType)' do
diff --git a/.gitlab/issue_templates/Geo Replicate a new blob type.md b/.gitlab/issue_templates/Geo Replicate a new blob type.md
index 88a7fad4975..0c5dbaebacf 100644
--- a/.gitlab/issue_templates/Geo Replicate a new blob type.md
+++ b/.gitlab/issue_templates/Geo Replicate a new blob type.md
@@ -56,7 +56,7 @@ Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org
```ruby
# frozen_string_literal: true
- class CreateCoolWidgetRegistry < Gitlab::Database::Migration[2.0]
+ class CreateCoolWidgetRegistry < Gitlab::Database::Migration[2.1]
def change
create_table :cool_widget_registry, id: :bigserial, force: :cascade do |t|
t.bigint :cool_widget_id, null: false
@@ -80,11 +80,19 @@ Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org
t.index :retry_at
t.index :state
# To optimize performance of CoolWidgetRegistry.verification_failed_batch
- t.index :verification_retry_at, name: :cool_widget_registry_failed_verification, order: "NULLS FIRST", where: "((state = 2) AND (verification_state = 3))"
+ t.index :verification_retry_at,
+ name: :cool_widget_registry_failed_verification,
+ order: "NULLS FIRST",
+ where: "((state = 2) AND (verification_state = 3))"
# To optimize performance of CoolWidgetRegistry.needs_verification_count
- t.index :verification_state, name: :cool_widget_registry_needs_verification, where: "((state = 2) AND (verification_state = ANY (ARRAY[0, 3])))"
+ t.index :verification_state,
+ name: :cool_widget_registry_needs_verification,
+ where: "((state = 2) AND (verification_state = ANY (ARRAY[0, 3])))"
# To optimize performance of CoolWidgetRegistry.verification_pending_batch
- t.index :verified_at, name: :cool_widget_registry_pending_verification, order: "NULLS FIRST", where: "((state = 2) AND (verification_state = 0))"
+ t.index :verified_at,
+ name: :cool_widget_registry_pending_verification,
+ order: "NULLS FIRST",
+ where: "((state = 2) AND (verification_state = 0))"
end
end
end
@@ -92,7 +100,7 @@ Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org
- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
-- [ ] Add the new table to the [database dictionary](database_dictionary.md) defined in [`ee/db/docs/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/db/docs):
+- [ ] Add the new table to the [database dictionary](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/database/database_dictionary.md) defined in [`ee/db/docs/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/db/docs):
```yaml
table_name: cool_widget_registry
@@ -131,7 +139,7 @@ The Geo primary site needs to checksum every replicable so secondaries can verif
```ruby
# frozen_string_literal: true
- class CreateCoolWidgetStates < Gitlab::Database::Migration[2.0]
+ class CreateCoolWidgetStates < Gitlab::Database::Migration[2.1]
VERIFICATION_STATE_INDEX_NAME = "index_cool_widget_states_on_verification_state"
PENDING_VERIFICATION_INDEX_NAME = "index_cool_widget_states_pending_verification"
FAILED_VERIFICATION_INDEX_NAME = "index_cool_widget_states_failed_verification"
@@ -144,16 +152,28 @@ The Geo primary site needs to checksum every replicable so secondaries can verif
t.datetime_with_timezone :verification_started_at
t.datetime_with_timezone :verification_retry_at
t.datetime_with_timezone :verified_at
- t.references :cool_widget, primary_key: true, default: nil, index: false, foreign_key: { on_delete: :cascade }
+ t.references :cool_widget,
+ primary_key: true,
+ default: nil,
+ index: false,
+ foreign_key: { on_delete: :cascade }
t.integer :verification_state, default: 0, limit: 2, null: false
t.integer :verification_retry_count, default: 0, limit: 2, null: false
t.binary :verification_checksum, using: 'verification_checksum::bytea'
t.text :verification_failure, limit: 255
t.index :verification_state, name: VERIFICATION_STATE_INDEX_NAME
- t.index :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME
- t.index :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME
- t.index :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME
+ t.index :verified_at,
+ where: "(verification_state = 0)",
+ order: { verified_at: 'ASC NULLS FIRST' },
+ name: PENDING_VERIFICATION_INDEX_NAME
+ t.index :verification_retry_at,
+ where: "(verification_state = 3)",
+ order: { verification_retry_at: 'ASC NULLS FIRST' },
+ name: FAILED_VERIFICATION_INDEX_NAME
+ t.index :verification_state,
+ where: "(verification_state = 0 OR verification_state = 3)",
+ name: NEEDS_VERIFICATION_INDEX_NAME
end
end
@@ -165,17 +185,20 @@ The Geo primary site needs to checksum every replicable so secondaries can verif
- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
-- [ ] Add the new table to the database dictionary defined in [`db/docs/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/db/docs):
+- [ ] If `cool_widgets` is a high-traffic table, follow [the database documentation to use `with_lock_retries`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/migration_style_guide.md#when-to-use-the-helper-method)
+
+- [ ] Add the new table to the [database dictionary](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/database/database_dictionary.md) defined in [`db/docs/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/db/docs):
```yaml
+ ---
table_name: cool_widget_states
- description: Description example
- introduced_by_url: Merge request link
- milestone: Milestone example
+ description: Separate table for cool widget verification states
+ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/XXXXX
+ milestone: 'XX.Y'
feature_categories:
- - Feature category example
+ - geo_replication
classes:
- - Class example
+ - Geo::CoolWidgetState
gitlab_schema: gitlab_main
```
@@ -185,24 +208,8 @@ The Geo primary site needs to checksum every replicable so secondaries can verif
bin/rake db:migrate
```
-- [ ] If `cool_widgets` is a high-traffic table, follow [the database documentation to use `with_lock_retries`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/migration_style_guide.md#when-to-use-the-helper-method)
-
- [ ] Be sure to commit the relevant changes in `db/structure.sql` and the file under `db/schema_migrations`
-- [ ] Add an entry for the state table in `db/docs/cool_widget_states.yml`
-
- ```yaml
- ---
- table_name: cool_widget_states
- classes:
- - Geo::CoolWidgetState
- feature_categories:
- - geo_replication
- description: Separate table for cool widget verification states
- introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/XXXXX
- milestone: 'XX.Y'
- ```
-
That's all of the required database changes.
### Implement Geo support of Cool Widgets behind a feature flag
@@ -238,17 +245,26 @@ That's all of the required database changes.
after_save :save_verification_details
- scope :with_verification_state, ->(state) { joins(:cool_widget_state).where(cool_widget_states: { verification_state: verification_state_value(state) }) }
- scope :checksummed, -> { joins(:cool_widget_state).where.not(cool_widget_states: { verification_checksum: nil } ) }
- scope :not_checksummed, -> { joins(:cool_widget_state).where(cool_widget_states: { verification_checksum: nil } ) }
-
- scope :available_verifiables, -> { joins(:cool_widget_state) }
-
# Override the `all` default if not all records can be replicated. For an
# example of an existing Model that needs to do this, see
# `EE::MergeRequestDiff`.
# scope :available_replicables, -> { all }
+ scope :available_verifiables, -> { joins(:cool_widget_state) }
+
+ scope :checksummed, -> {
+ joins(:cool_widget_state).where.not(cool_widget_states: { verification_checksum: nil })
+ }
+
+ scope :not_checksummed, -> {
+ joins(:cool_widget_state).where(cool_widget_states: { verification_checksum: nil })
+ }
+
+ scope :with_verification_state, ->(state) {
+ joins(:cool_widget_state)
+ .where(cool_widget_states: { verification_state: verification_state_value(state) })
+ }
+
def verification_state_object
cool_widget_state
end
@@ -259,7 +275,8 @@ That's all of the required database changes.
...
# @param primary_key_in [Range, CoolWidget] arg to pass to primary_key_in scope
- # @return [ActiveRecord::Relation<CoolWidget>] everything that should be synced to this node, restricted by primary key
+ # @return [ActiveRecord::Relation<CoolWidget>] everything that should be synced
+ # to this node, restricted by primary key
def replicables_for_current_secondary(primary_key_in)
# This issue template does not help you write this method.
#
@@ -301,8 +318,8 @@ That's all of the required database changes.
```ruby
include_examples 'a replicable model with a separate table for verification state' do
- let(:verifiable_model_record) { build(:cool_widget) } # add extra params if needed to make sure the record is included in `available_verifiables`
- let(:unverifiable_model_record) { build(:cool_widget) } # add extra params if needed to make sure the record is NOT included in `available_verifiables`
+ let(:verifiable_model_record) { build(:cool_widget) } # add extra params if needed to make sure the record is in `Geo::ReplicableModel.verifiables` scope
+ let(:unverifiable_model_record) { build(:cool_widget) } # add extra params if needed to make sure the record is NOT included in `Geo::ReplicableModel.verifiables` scope
end
```
@@ -332,7 +349,6 @@ That's all of the required database changes.
# (see `VerifiableReplicator.verification_enabled?`)
true
end
-
end
end
```
@@ -360,7 +376,7 @@ That's all of the required database changes.
require 'spec_helper'
- RSpec.describe Geo::CoolWidgetReplicator do
+ RSpec.describe Geo::CoolWidgetReplicator, feature_category: :geo_replication do
let(:model_record) { build(:cool_widget) }
include_examples 'a blob replicator'
@@ -434,7 +450,7 @@ That's all of the required database changes.
require 'spec_helper'
- RSpec.describe Geo::CoolWidgetRegistry, :geo, type: :model do
+ RSpec.describe Geo::CoolWidgetRegistry, :geo, type: :model, feature_category: :geo_replication do
let_it_be(:registry) { create(:geo_cool_widget_registry) }
specify 'factory is valid' do
@@ -449,17 +465,21 @@ That's all of the required database changes.
- [ ] Add the following to `spec/factories/cool_widgets.rb`:
```ruby
+ # frozen_string_literal: true
+
FactoryBot.modify do
- trait :verification_succeeded do
- with_file
- verification_checksum { 'abc' }
- verification_state { CoolWidget.verification_state_value(:verification_succeeded) }
- end
+ factory :cool_widget do
+ trait :verification_succeeded do
+ with_file
+ verification_checksum { 'abc' }
+ verification_state { CoolWidget.verification_state_value(:verification_succeeded) }
+ end
- trait :verification_failed do
- with_file
- verification_failure { 'Could not calculate the checksum' }
- verification_state { CoolWidget.verification_state_value(:verification_failed) }
+ trait :verification_failed do
+ with_file
+ verification_failure { 'Could not calculate the checksum' }
+ verification_state { CoolWidget.verification_state_value(:verification_failed) }
+ end
end
end
```
@@ -539,18 +559,18 @@ Metrics are gathered by `Geo::MetricsUpdateWorker`, persisted in `GeoNodeStatus`
```markdown
| `geo_cool_widgets` | Gauge | XX.Y | Number of Cool Widgets on primary | `url` |
- | `geo_cool_widgets_checksum_total` | Gauge | XX.Y | Number of Cool Widgets checksummed successfully on primary | `url` |
- | `geo_cool_widgets_checksummed` | Gauge | XX.Y | Number of Cool Widgets failed to calculate the checksum on primary | `url` |
- | `geo_cool_widgets_checksum_failed` | Gauge | XX.Y | Number of Cool Widgets tried to checksum on primary | `url` |
+ | `geo_cool_widgets_checksum_total` | Gauge | XX.Y | Number of Cool Widgets to checksum on primary | `url` |
+ | `geo_cool_widgets_checksummed` | Gauge | XX.Y | Number of Cool Widgets that successfully calculated the checksum on primary | `url` |
+ | `geo_cool_widgets_checksum_failed` | Gauge | XX.Y | Number of Cool Widgets that failed to calculate the checksum on primary | `url` |
| `geo_cool_widgets_synced` | Gauge | XX.Y | Number of syncable Cool Widgets synced on secondary | `url` |
| `geo_cool_widgets_failed` | Gauge | XX.Y | Number of syncable Cool Widgets failed to sync on secondary | `url` |
| `geo_cool_widgets_registry` | Gauge | XX.Y | Number of Cool Widgets in the registry | `url` |
- | `geo_cool_widgets_verification_total` | Gauge | XX.Y | Number of Cool Widgets verified on secondary | `url` |
- | `geo_cool_widgets_verified` | Gauge | XX.Y | Number of Cool Widgets' verifications failed on secondary | `url` |
- | `geo_cool_widgets_verification_failed` | Gauge | XX.Y | Number of Cool Widgets' verifications tried on secondary | `url` |
+ | `geo_cool_widgets_verification_total` | Gauge | XX.Y | Number of Cool Widgets to attempt to verify on secondary | `url` |
+ | `geo_cool_widgets_verified` | Gauge | XX.Y | Number of Cool Widgets successfully verified on secondary | `url` |
+ | `geo_cool_widgets_verification_failed` | Gauge | XX.Y | Number of Cool Widgets that failed verification on secondary | `url` |
```
- Cool Widget replication and verification metrics should now be available in the API, the `Admin > Geo > Nodes` view, and Prometheus.
+ Cool Widget replication and verification metrics should now be available in the API, the `Admin > Geo > Sites` view, and Prometheus.
#### Step 3. Implement the GraphQL API
@@ -591,7 +611,7 @@ The GraphQL API is used by `Admin > Geo > Replication Details` views, and is dir
require 'spec_helper'
- RSpec.describe Resolvers::Geo::CoolWidgetRegistriesResolver do
+ RSpec.describe Resolvers::Geo::CoolWidgetRegistriesResolver, feature_category: :geo_replication do
it_behaves_like 'a Geo registries resolver', :geo_cool_widget_registry
end
```
@@ -615,7 +635,7 @@ The GraphQL API is used by `Admin > Geo > Replication Details` views, and is dir
require 'spec_helper'
- RSpec.describe Geo::CoolWidgetRegistryFinder do
+ RSpec.describe Geo::CoolWidgetRegistryFinder, feature_category: :geo_replication do
it_behaves_like 'a framework registry finder', :geo_cool_widget_registry
end
```
@@ -649,7 +669,7 @@ The GraphQL API is used by `Admin > Geo > Replication Details` views, and is dir
require 'spec_helper'
- RSpec.describe GitlabSchema.types['CoolWidgetRegistry'] do
+ RSpec.describe GitlabSchema.types['CoolWidgetRegistry'], feature_category: :geo_replication do
it_behaves_like 'a Geo registry type'
it 'has the expected fields (other than those included in RegistryType)' do
diff --git a/.gitlab/issue_templates/UX Theme.md b/.gitlab/issue_templates/UX Theme.md
index b015c3d44e6..32e771735b1 100644
--- a/.gitlab/issue_templates/UX Theme.md
+++ b/.gitlab/issue_templates/UX Theme.md
@@ -1,39 +1,25 @@
-<!-- A majority of the work designers do will be on themes in the (Now) Next 1-3 milestone column of their UX Roadmap. These themes are comprised of high-confidence outcomes and validated needs. The UX theme issue is where collaboration should occur, including plans and discussion on subthemes, research, and design feedback. Related issues for design exploration and solution validation should stem from the theme issue.
+<!-- Most of the work designers do will be on themes in the (Now) Next 1-3 milestone column of their UX Roadmap. These themes are comprised of high-confidence outcomes and validated needs. The UX theme issue is where collaboration should occur, including plans and discussion on subthemes, research, and design feedback. Related design exploration and solution validation issues should stem from the theme issue.
-One of the advantages of working with UX themes is that it allows us to think and design holistically by designing the theme as a whole as opposed to a single issue at a time trying to piece them together as you go. For more details please refer to this section of the handbook when creating UX Themes: https://about.gitlab.com/handbook/product/ux/product-design/ux-roadmaps/#theme-structure -->
+One of the advantages of working with UX themes is that it allows us to think and design holistically by designing the theme as a whole instead of a single issue at a time, trying to piece them together as we go. For more details, please refer to this section of the handbook when creating UX Themes: https://about.gitlab.com/handbook/product/ux/product-design/ux-roadmaps/#ux-theme-structure -->
-<!-- Theme Issue Title {UX Theme: <theme statement here>} -->
-<!-- Theme Statement: A theme is written as a statement that combines the beneficiary, their need, and the expected outcome when the work is delivered. Well-defined statements are concise without sacrificing the substance of the theme so that anyone can understand it at a glance. (For instance; Reduce the effort for security teams to identify and escalate business-critical risks)
-
-!!Note: The theme statement is the defacto title that will be used to reference the theme and serve as the theme issue title.!! It should be something that is easily understood, that quickly communicates the intent of the theme allowing team members to easily understand and recognize the expected work that will be done.
+<!--
+!!Note: The theme statement is the defacto title that will reference the theme and serve as the theme issue title.!! It should be something that is easily understood that quickly communicates the intent of the theme allowing team members to easily understand and recognize the expected work that will be done.
-->
----
-### Problem to solve
-<!-- In a brief statement, summerize the problem we are intending to address with this theme. For instance, users are unable to complete [task], or, users struggle with the amount of steps required to complete [task] -->
-
+### Theme statement
+<!-- A theme statement combines the beneficiary, their job, and their expected outcome when the work is delivered and serves as the design goal for the team who owns the theme. Well-defined statements are concise without sacrificing the substance of the theme so that anyone can understand it at a glance. Well-defined statements are concise without sacrificing the substance of the theme so that anyone can understand it at a glance. (For instance, Reduce the effort for security teams when prioritizing business-critical risks in their assets.) -->
-### Beneficiary
-<!-- Who is the recipient(s) of the value this theme provides; a customer, end-user, or buyer. Who benefits from this theme being executed? This can be a role, a team, or a persona. For instance: "Development teams, [or] Developers, [or], Sasha the Software Engineer". -->
+<!-- Also Theme issue tile -->
+{`Need/outcome` } + {`Beneficiary`} + {`Job/Small Job`}
-- **[Direct beneficiary]**
-
-#### Need & Primary JTBD
-<!-- What is the JTBD and what are the needs related to the beneficiary and theme?
-- JTBD: The JTBD statement, for instance, (When I am triaging vulns, I want to address business-critical risks, So I can ensure there is no unattended risk in my orgs assets.)
-- Need: Abstracted from the JTBD, for instance, (Identify and escalate business-critical risks detected in my orgs assets.)
--->
-
-- **JTBD:**
-- **Need:**
-
-#### Expected outcome
-<!-- What will the user be able to achieve when this theme is executed? For instance, (Users will be able to effectively triage vulnerabilities at scale across all their orgs assets.) -->
+#### Main Job story
+<!-- What is the [Main Job story](https://about.gitlab.com/handbook/product/ux/jobs-to-be-done/#how-to-write-a-jtbd) that this theme was derived from? (For instance, When I am on triage rotation, I want to address all the business-critical risks in my assets, So I can minimize the likelihood of my organization being compromised by a security breach.) -->
#### Business objective
-<!-- What business objective will result from delivering this theme? This answers why we are working on this theme from a business perspective. Examples of objectives are but are not limited to: Sales rate / conversion rate, Success rate / completion rate, Traffic / visitor count, Engagement, or other business-oriented goals. -->
+<!-- Objectives (from a business point of view) that will be achieved upon completion. (For instance, Increase engagement by making the experience efficient while reducing the chances of users overlooking high-priority items. -->
#### Confidence
@@ -42,43 +28,24 @@ One of the advantages of working with UX themes is that it allows us to think an
| Confidence | Research |
| --- | --- |
-| [High/Medium/Low] | [research/insight issue](Link) |
-
-### User-stories
-<!-- Product designers should work with their PMs to gather up all of the relevant user stories. Look for alignment with the JTBD added above. Overall, the solution you and your team come up with should help to support the user stories. -->
+| [High/Medium/Low] | [research/insight issue](Link) |
-- [user-story here]
-- [user-story here]
-- [user-story here]
-- [etc.]
### Requirements
-<!-- Requirements can be taken from existing features or design issues that were used to build this theme. Any related issues should be linked with this issue in the Feature/solution issues section below. They are more granular validated needs, goals, and additional details that the theme encompasses. These are typically reserved for themes in the next (1-3 milestones) column. Requirements should answer “what†the beneficiary of this theme needs from the solution.
-
-Note: This is not a backlog. If the issue can not be delivered in the theme timeframe then the theme is too big and needs to be broken down into multiple themes. -->
-
-The beneficieray needs to be able to:
-- [need here]
-- [need here]
-- [need here]
-- [etc.]
+<!-- Requirements can be taken from existing features or design issues used to build this theme. Any related issues should be linked with this issue in the Feature/solution issues section below. They are more granular validated needs, goals, and additional details that the theme encompasses. These are typically reserved for themes in the next (1-3 milestones) column. Requirements should answer “what†the beneficiary of this theme needs from the solution.
-#### Feature/solution issues
-<!-- Use this table to track feature issues related to this theme (if applicable). Not all themes require sub-issues as they are typically discovered while working on the theme itself. Think of these issues as if they were the result of breaking down the design into discrete work items.
+Note: This is not a backlog. If the issue can not be delivered in the theme timeframe, then the theme is too big and needs to be broken down into multiple themes. -->
-Note: if feature issues already exist then you can add them to this table. Keep in mind that these issues will require validation if they are being added to a Theme that's in the Next (1-3 milestones) container and are assumptive.
+>âš ï¸ Related feature and research issues should be linked in the related issues section (Delete this line when this is done)
-Refer to https://about.gitlab.com/handbook/product/ux/product-designer/#ux-issue-weights for calculating UX weights.
--->
-
-| Issue | UX Weight |
-| ---------- | --------- |
-| [Issue](link) | `0 - 10` |
-| [Issue](link) | `0 - 10` |
-| [Issue](link) | `0 - 10` |
+#### The beneficiary needs to be able to:
+- [Small job statement]
+ - [Micro job statement]
+ - [Micro job statement]
+- [etc.]
#### Research
-<!-- Use this table to track UX research related to this theme. This may include, problem validation and/or solution validation activities.
+<!-- Researchers and Designers; Use this table to track UX research related to this theme. This may include problem validation and solution validation activities.
-->
| Issue | Research type | Research status |
@@ -87,16 +54,35 @@ Refer to https://about.gitlab.com/handbook/product/ux/product-designer/#ux-issue
| [Issue]() | <!--Solution validation, Problem validation, etc., --> | <!-- Planned, In Progress, Complete, etc.,--> |
#### Ready for design checklist
-The items are self-check suggestions; they could be contributed by designers, product managers or researchers
-* [ ] The stated `Problem to solve` has high confidence (derived from research or other data-gathering techniques)
-* [ ] Relevant issues, research, and other background information are linked to the Related issues section
-* [ ] The stated `Beneficiary` has been defined
-* [ ] There is high confidence in the stated `Need & Primary JTBD` (derived from research or other data gathering techniques)
-* [ ] The `Expected outcome` has been defined
+The items are self-check suggestions; they could be contributed by designers, product managers, or researchers
+* [ ] The `theme` has high confidence (derived from research or other data-gathering techniques)
+* [ ] The `Related issues`, features, research, and other background information are linked to the related issues section
* [ ] The `Business objective` has been defined
-* [ ] The theme `Confidence` has been defined as High
-* [ ] `User-stories` have been defined
-* [ ] The `Requirements` have been defined and the scope has been agreed upon
-* [ ] This UX Theme contains everyhting necessary to complete a design solution and is ready for design
+* [ ] The `Requirements` have been defined, and the scope has been agreed upon
+* [ ] This UX Theme contains everything necessary to complete a design solution and is ready for design
+
+#### [Thematic design workflow checklist](https://about.gitlab.com/handbook/product/ux/product-design/ux-roadmaps/#suggested-workflow)
+<!-- please refer to the [suggested workflow](https://about.gitlab.com/handbook/product/ux/product-design/ux-roadmaps/#suggested-workflow) when working on UX themes-->
+* [ ] **Theme assessed** Ready for design checklist complete
+* [ ] **Ideate and Iterate**
+ * [ ] User flow diagram generated
+ * [ ] Low-fidelity wireframes of the entire theme created
+ * [ ] [Feedback requested](https://about.gitlab.com/handbook/product/ux/product-designer/#design-reviews) and incorporated into flow diagram and wireframes
+* [ ] **Validate**
+ * [ ] [Solution validation](https://about.gitlab.com/handbook/product/ux/ux-research/solution-validation-and-methods/) conducted on Low/mid-fidelity flow
+* [ ] **Refine**
+ * [ ] Resaerch findings incorporated into design
+ * [ ] All micro-interactions are defined
+ * [ ] All edge-cases are accounted for and defined
+ * [ ] All copy has been reviewed by tech writing
+ * [ ] Accessibnility guidelines have been considered
+ * [ ] High-fidelity designs posted
+ * [ ] Feedback requested from counterparts
+ * [ ] (If necessary) Validate high-fidelity flow in a 2nd round of user testing
+ * [ ] Refine final design from feedback and user research
+* [ ] **Hand-off**
+ * [ ] Designs broken down based on the their ability to stand alone and that they provide value to the user.
+ * [ ] MVC plan agreement reached
+ * [ ] Planning breakdown complete
/label ~"UX" ~"UX Theme"
diff --git a/.gitlab/merge_request_templates/New Static Analysis Check.md b/.gitlab/merge_request_templates/New Static Analysis Check.md
index 6ad56cd5cd0..9cf21fa49e8 100644
--- a/.gitlab/merge_request_templates/New Static Analysis Check.md
+++ b/.gitlab/merge_request_templates/New Static Analysis Check.md
@@ -1,6 +1,6 @@
<!--
When creating a new cop that could be applied to multiple applications,
-we encourage you to add it to https://gitlab.com/gitlab-org/gitlab-styles gem.
+we encourage you to add it to https://gitlab.com/gitlab-org/ruby/gems/gitlab-styles gem.
-->
## Description of the proposal
diff --git a/.gitlab/merge_request_templates/Revert To Resolve Incident.md b/.gitlab/merge_request_templates/Revert To Resolve Incident.md
index 4e77846575a..c1980d70768 100644
--- a/.gitlab/merge_request_templates/Revert To Resolve Incident.md
+++ b/.gitlab/merge_request_templates/Revert To Resolve Incident.md
@@ -12,6 +12,7 @@
- [ ] Create an issue to reinstate the merge request and assign it to the author of the reverted merge request.
- [ ] If the revert is to resolve a [broken 'master' incident](https://about.gitlab.com/handbook/engineering/workflow/#broken-master), please read through the [Responsibilities of the Broken `master` resolution DRI](https://about.gitlab.com/handbook/engineering/workflow/#responsibilities-of-the-resolution-dri).
+- [ ] If the revert involves a database migration, please read through [Deleting existing migrations](https://docs.gitlab.com/ee/development/database/deleting_migrations.html).
- [ ] Add the appropriate labels **before** the MR is created. We can skip CI/CD jobs only if the labels are added **before** the CI/CD pipeline is created.
### Milestone info
diff --git a/.gitleaksignore b/.gitleaksignore
new file mode 100644
index 00000000000..eab7926138c
--- /dev/null
+++ b/.gitleaksignore
@@ -0,0 +1,2 @@
+7e07fe42d34916b276a7b068f4faa8bdc0ebc984:doc/architecture/blueprints/runner_tokens/index.md:gitlab-rrt:485
+f6504b498548380198ad38295d9caa71412115f0:doc/architecture/blueprints/runner_tokens/index.md:generic-api-key:506
diff --git a/.rubocop.yml b/.rubocop.yml
index 3489c2e2534..56c51bee0e3 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -19,6 +19,9 @@ inherit_from:
<% 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 %>
- ./rubocop/rubocop-migrations.yml
- ./rubocop/rubocop-usage-data.yml
- ./rubocop/rubocop-code_reuse.yml
@@ -30,6 +33,7 @@ inherit_mode:
merge:
- Include
- Exclude
+ - AllowedPatterns
AllCops:
# Target the current Ruby version. For example, "2.7" or "3.0".
@@ -97,6 +101,9 @@ InternalAffairs/DeprecateCopHelper:
Include:
- spec/rubocop/**/*.rb
+Layout/LineLength:
+ AllowedPatterns: ['^RSpec\.describe\s.*\sdo']
+
Lint/LastKeywordArgument:
Safe: false
@@ -436,6 +443,12 @@ BackgroundMigration/FeatureCategory:
Include:
- 'lib/gitlab/background_migration/*.rb'
+BackgroundMigration/MissingDictionaryFile:
+ Enabled: true
+ EnforcedSince: 20230307160251
+ Include:
+ - 'db/post_migrate/*.rb'
+
# See https://gitlab.com/gitlab-org/gitlab/-/issues/373194
Gitlab/RSpec/AvoidSetup:
Enabled: true
diff --git a/.rubocop_todo/background_migration/missing_dictionary_file.yml b/.rubocop_todo/background_migration/missing_dictionary_file.yml
new file mode 100644
index 00000000000..c065a1ac3aa
--- /dev/null
+++ b/.rubocop_todo/background_migration/missing_dictionary_file.yml
@@ -0,0 +1,4 @@
+---
+# Grace period will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/395354
+BackgroundMigration/MissingDictionaryFile:
+ Details: grace period
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml
index eec55aa7bbe..d1257e3ffac 100644
--- a/.rubocop_todo/gitlab/namespaced_class.yml
+++ b/.rubocop_todo/gitlab/namespaced_class.yml
@@ -133,7 +133,6 @@ Gitlab/NamespacedClass:
- 'app/models/commit_status.rb'
- 'app/models/commit_user_mention.rb'
- 'app/models/compare.rb'
- - 'app/models/concerns/uniquify.rb'
- 'app/models/container_expiration_policy.rb'
- 'app/models/container_repository.rb'
- 'app/models/context_commits_diff.rb'
diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml
index 1eeb7c69a96..3ecc1ef6bfc 100644
--- a/.rubocop_todo/gitlab/strong_memoize_attr.yml
+++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml
@@ -127,7 +127,6 @@ Gitlab/StrongMemoizeAttr:
- 'app/models/namespaces/traversal/linear.rb'
- 'app/models/namespaces/traversal/recursive.rb'
- 'app/models/note.rb'
- - 'app/models/onboarding/completion.rb'
- 'app/models/packages/go/module.rb'
- 'app/models/packages/go/module_version.rb'
- 'app/models/packages/package.rb'
@@ -230,7 +229,6 @@ Gitlab/StrongMemoizeAttr:
- 'app/services/packages/cleanup/update_policy_service.rb'
- 'app/services/packages/composer/create_package_service.rb'
- 'app/services/packages/debian/extract_changes_metadata_service.rb'
- - 'app/services/packages/debian/extract_metadata_service.rb'
- 'app/services/packages/debian/find_or_create_package_service.rb'
- 'app/services/packages/debian/generate_distribution_key_service.rb'
- 'app/services/packages/debian/generate_distribution_service.rb'
@@ -596,7 +594,6 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/ci/reports/accessibility_reports_comparer.rb'
- 'lib/gitlab/ci/reports/codequality_reports_comparer.rb'
- 'lib/gitlab/ci/reports/security/locations/base.rb'
- - 'lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb'
- 'lib/gitlab/ci/reports/test_reports_comparer.rb'
- 'lib/gitlab/ci/reports/test_suite_comparer.rb'
- 'lib/gitlab/ci/reports/test_suite_summary.rb'
@@ -647,7 +644,6 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/git_access_project.rb'
- 'lib/gitlab/gitaly_client/with_feature_flag_actors.rb'
- 'lib/gitlab/github_import/client.rb'
- - 'lib/gitlab/github_import/importer/repository_importer.rb'
- 'lib/gitlab/github_import/representation/diff_notes/suggestion_formatter.rb'
- 'lib/gitlab/gl_repository/identifier.rb'
- 'lib/gitlab/gpg/commit.rb'
diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml
index faa81abc0af..4c0f89e9400 100644
--- a/.rubocop_todo/layout/argument_alignment.yml
+++ b/.rubocop_todo/layout/argument_alignment.yml
@@ -3,54 +3,6 @@
Layout/ArgumentAlignment:
Details: grace period
Exclude:
- - 'app/controllers/admin/application_settings_controller.rb'
- - 'app/controllers/admin/ci/variables_controller.rb'
- - 'app/controllers/admin/groups_controller.rb'
- - 'app/controllers/admin/spam_logs_controller.rb'
- - 'app/controllers/admin/topics_controller.rb'
- - 'app/controllers/application_controller.rb'
- - 'app/controllers/chaos_controller.rb'
- - 'app/controllers/concerns/authenticates_with_two_factor.rb'
- - 'app/controllers/concerns/enforces_two_factor_authentication.rb'
- - 'app/controllers/concerns/invisible_captcha_on_signup.rb'
- - 'app/controllers/concerns/issuable_actions.rb'
- - 'app/controllers/concerns/known_sign_in.rb'
- - 'app/controllers/concerns/membership_actions.rb'
- - 'app/controllers/concerns/observability/content_security_policy.rb'
- - 'app/controllers/concerns/wiki_actions.rb'
- - 'app/controllers/dashboard/todos_controller.rb'
- - 'app/controllers/groups/children_controller.rb'
- - 'app/controllers/groups/group_members_controller.rb'
- - 'app/controllers/groups_controller.rb'
- - 'app/controllers/metrics_controller.rb'
- - 'app/controllers/oauth/authorizations_controller.rb'
- - 'app/controllers/oauth/authorized_applications_controller.rb'
- - 'app/controllers/oauth/jira_dvcs/authorizations_controller.rb'
- - 'app/controllers/profiles/emails_controller.rb'
- - 'app/controllers/projects/blob_controller.rb'
- - 'app/controllers/projects/commit_controller.rb'
- - 'app/controllers/projects/environments_controller.rb'
- - 'app/controllers/projects/error_tracking_controller.rb'
- - 'app/controllers/projects/feature_flags_controller.rb'
- - 'app/controllers/projects/google_cloud/base_controller.rb'
- - 'app/controllers/projects/jobs_controller.rb'
- - 'app/controllers/projects/labels_controller.rb'
- - 'app/controllers/projects/merge_requests/creations_controller.rb'
- - 'app/controllers/projects/merge_requests_controller.rb'
- - 'app/controllers/projects/pages_controller.rb'
- - 'app/controllers/projects/pages_domains_controller.rb'
- - 'app/controllers/projects/pipeline_schedules_controller.rb'
- - 'app/controllers/projects/pipelines_controller.rb'
- - 'app/controllers/projects/prometheus/metrics_controller.rb'
- - 'app/controllers/projects/repositories_controller.rb'
- - 'app/controllers/projects/security/configuration_controller.rb'
- - 'app/controllers/projects/tree_controller.rb'
- - 'app/controllers/projects/web_ide_terminals_controller.rb'
- - 'app/controllers/repositories/lfs_api_controller.rb'
- - 'app/controllers/repositories/lfs_locks_api_controller.rb'
- - 'app/controllers/search_controller.rb'
- - 'app/controllers/sessions_controller.rb'
- - 'app/controllers/users_controller.rb'
- 'app/finders/autocomplete/users_finder.rb'
- 'app/finders/group_descendants_finder.rb'
- 'app/graphql/mutations/achievements/create.rb'
@@ -150,7 +102,6 @@ Layout/ArgumentAlignment:
- 'app/graphql/mutations/jira_import/import_users.rb'
- 'app/graphql/mutations/jira_import/start.rb'
- 'app/graphql/mutations/labels/create.rb'
- - 'app/graphql/mutations/members/groups/bulk_update.rb'
- 'app/graphql/mutations/merge_requests/accept.rb'
- 'app/graphql/mutations/merge_requests/base.rb'
- 'app/graphql/mutations/merge_requests/create.rb'
@@ -557,23 +508,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/helpers/application_helper.rb'
- - 'app/helpers/application_settings_helper.rb'
- - 'app/helpers/blob_helper.rb'
- - 'app/helpers/ci/status_helper.rb'
- - 'app/helpers/commits_helper.rb'
- - 'app/helpers/dashboard_helper.rb'
- - 'app/helpers/events_helper.rb'
- - 'app/helpers/feature_flags_helper.rb'
- - 'app/helpers/issuables_helper.rb'
- - 'app/helpers/mirror_helper.rb'
- - 'app/helpers/notes_helper.rb'
- - 'app/helpers/projects/error_tracking_helper.rb'
- - 'app/helpers/snippets_helper.rb'
- - 'app/helpers/todos_helper.rb'
- - 'app/helpers/users/group_callouts_helper.rb'
- - 'app/helpers/users_helper.rb'
- - 'app/helpers/visibility_level_helper.rb'
- 'app/mailers/emails/projects.rb'
- 'app/mailers/notify.rb'
- 'app/models/abuse_report.rb'
@@ -673,11 +607,6 @@ Layout/ArgumentAlignment:
- 'app/models/wiki_page.rb'
- 'app/models/work_item.rb'
- 'app/policies/project_snippet_policy.rb'
- - 'app/presenters/ci/build_runner_presenter.rb'
- - 'app/presenters/label_presenter.rb'
- - 'app/presenters/merge_request_presenter.rb'
- - 'app/presenters/project_presenter.rb'
- - 'app/presenters/snippet_blob_presenter.rb'
- 'app/serializers/build_details_entity.rb'
- 'app/serializers/environment_serializer.rb'
- 'app/serializers/error_tracking/detailed_error_entity.rb'
@@ -924,22 +853,6 @@ Layout/ArgumentAlignment:
- 'ee/app/components/namespaces/free_user_cap/base_alert_component.rb'
- 'ee/app/components/namespaces/free_user_cap/enforcement_at_limit_alert_component.rb'
- 'ee/app/components/namespaces/free_user_cap/shared.rb'
- - 'ee/app/controllers/admin/credentials_controller.rb'
- - 'ee/app/controllers/concerns/ee/analytics/cycle_analytics/stage_actions.rb'
- - 'ee/app/controllers/ee/groups_controller.rb'
- - 'ee/app/controllers/ee/passwords_controller.rb'
- - 'ee/app/controllers/ee/registrations_controller.rb'
- - 'ee/app/controllers/ee/search_controller.rb'
- - 'ee/app/controllers/groups/analytics/ci_cd_analytics_controller.rb'
- - 'ee/app/controllers/groups/analytics/cycle_analytics_controller.rb'
- - 'ee/app/controllers/groups/saml_group_links_controller.rb'
- - 'ee/app/controllers/groups/security/credentials_controller.rb'
- - 'ee/app/controllers/groups/two_factor_auths_controller.rb'
- - 'ee/app/controllers/omniauth_kerberos_controller.rb'
- - 'ee/app/controllers/projects/integrations/zentao/issues_controller.rb'
- - 'ee/app/controllers/registrations/groups_projects_controller.rb'
- - 'ee/app/controllers/subscriptions_controller.rb'
- - 'ee/app/controllers/trials_controller.rb'
- 'ee/app/finders/security/findings_finder.rb'
- 'ee/app/finders/security/training_providers/base_url_finder.rb'
- 'ee/app/graphql/ee/mutations/alert_management/http_integration/create.rb'
@@ -1225,9 +1138,6 @@ Layout/ArgumentAlignment:
- 'ee/app/graphql/types/work_items/widgets/status_filter_input_type.rb'
- 'ee/app/graphql/types/work_items/widgets/status_input_type.rb'
- 'ee/app/graphql/types/work_items/widgets/weight_input_type.rb'
- - 'ee/app/helpers/billing_plans_helper.rb'
- - 'ee/app/helpers/ee/feature_flags_helper.rb'
- - 'ee/app/helpers/ee/search_helper.rb'
- 'ee/app/mailers/ee/emails/projects.rb'
- 'ee/app/mailers/emails/namespace_storage_usage_mailer.rb'
- 'ee/app/models/approval_wrapped_rule.rb'
@@ -1445,7 +1355,6 @@ Layout/ArgumentAlignment:
- 'ee/spec/features/admin/admin_emails_spec.rb'
- 'ee/spec/features/admin/admin_settings_spec.rb'
- 'ee/spec/features/billings/billing_plans_spec.rb'
- - 'ee/spec/features/billings/extend_reactivate_trial_spec.rb'
- 'ee/spec/features/boards/boards_spec.rb'
- 'ee/spec/features/boards/swimlanes/epics_swimlanes_drag_drop_spec.rb'
- 'ee/spec/features/burndown_charts_spec.rb'
@@ -1663,7 +1572,6 @@ Layout/ArgumentAlignment:
- 'ee/spec/policies/merge_request_policy_spec.rb'
- 'ee/spec/policies/vulnerabilities/feedback_policy_spec.rb'
- 'ee/spec/policies/vulnerabilities/merge_request_link_policy_spec.rb'
- - 'ee/spec/presenters/ci/pipeline_presenter_spec.rb'
- 'ee/spec/requests/admin/impersonation_tokens_controller_spec.rb'
- 'ee/spec/requests/api/analytics/product_analytics_spec.rb'
- 'ee/spec/requests/api/analytics/project_deployment_frequency_spec.rb'
@@ -2090,7 +1998,6 @@ Layout/ArgumentAlignment:
- 'lib/gitlab/import_export/snippets_repo_restorer.rb'
- 'lib/gitlab/import_export/snippets_repo_saver.rb'
- 'lib/gitlab/issuable/clone/copy_resource_events_service.rb'
- - 'lib/gitlab/legacy_github_import/importer.rb'
- 'lib/gitlab/mail_room.rb'
- 'lib/gitlab/markdown_cache/redis/store.rb'
- 'lib/gitlab/memory/reports_uploader.rb'
@@ -2248,69 +2155,6 @@ Layout/ArgumentAlignment:
- 'spec/components/previews/pajamas/alert_component_preview.rb'
- 'spec/components/previews/pajamas/banner_component_preview.rb'
- 'spec/components/previews/pajamas/button_component_preview.rb'
- - 'spec/controllers/admin/spam_logs_controller_spec.rb'
- - 'spec/controllers/admin/users_controller_spec.rb'
- - 'spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb'
- - 'spec/controllers/concerns/continue_params_spec.rb'
- - 'spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb'
- - 'spec/controllers/concerns/product_analytics_tracking_spec.rb'
- - 'spec/controllers/concerns/renders_commits_spec.rb'
- - 'spec/controllers/confirmations_controller_spec.rb'
- - 'spec/controllers/every_controller_spec.rb'
- - 'spec/controllers/graphql_controller_spec.rb'
- - 'spec/controllers/groups/group_members_controller_spec.rb'
- - 'spec/controllers/groups/milestones_controller_spec.rb'
- - 'spec/controllers/groups/variables_controller_spec.rb'
- - 'spec/controllers/help_controller_spec.rb'
- - 'spec/controllers/import/bitbucket_controller_spec.rb'
- - 'spec/controllers/import/bulk_imports_controller_spec.rb'
- - 'spec/controllers/import/fogbugz_controller_spec.rb'
- - 'spec/controllers/oauth/authorizations_controller_spec.rb'
- - 'spec/controllers/oauth/jira_dvcs/authorizations_controller_spec.rb'
- - 'spec/controllers/omniauth_callbacks_controller_spec.rb'
- - 'spec/controllers/passwords_controller_spec.rb'
- - 'spec/controllers/profiles_controller_spec.rb'
- - 'spec/controllers/projects/artifacts_controller_spec.rb'
- - 'spec/controllers/projects/blame_controller_spec.rb'
- - 'spec/controllers/projects/blob_controller_spec.rb'
- - 'spec/controllers/projects/branches_controller_spec.rb'
- - 'spec/controllers/projects/clusters_controller_spec.rb'
- - 'spec/controllers/projects/commit_controller_spec.rb'
- - 'spec/controllers/projects/commits_controller_spec.rb'
- - 'spec/controllers/projects/cycle_analytics_controller_spec.rb'
- - 'spec/controllers/projects/deploy_keys_controller_spec.rb'
- - 'spec/controllers/projects/deployments_controller_spec.rb'
- - 'spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb'
- - 'spec/controllers/projects/environments_controller_spec.rb'
- - 'spec/controllers/projects/feature_flags_controller_spec.rb'
- - 'spec/controllers/projects/find_file_controller_spec.rb'
- - 'spec/controllers/projects/forks_controller_spec.rb'
- - 'spec/controllers/projects/grafana_api_controller_spec.rb'
- - 'spec/controllers/projects/issues_controller_spec.rb'
- - 'spec/controllers/projects/jobs_controller_spec.rb'
- - 'spec/controllers/projects/mattermosts_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/diffs_controller_spec.rb'
- - 'spec/controllers/projects/merge_requests/drafts_controller_spec.rb'
- - 'spec/controllers/projects/merge_requests_controller_spec.rb'
- - 'spec/controllers/projects/notes_controller_spec.rb'
- - 'spec/controllers/projects/pipelines_controller_spec.rb'
- - 'spec/controllers/projects/prometheus/alerts_controller_spec.rb'
- - 'spec/controllers/projects/raw_controller_spec.rb'
- - 'spec/controllers/projects/refs_controller_spec.rb'
- - 'spec/controllers/projects/registry/repositories_controller_spec.rb'
- - 'spec/controllers/projects/registry/tags_controller_spec.rb'
- - 'spec/controllers/projects/settings/ci_cd_controller_spec.rb'
- - 'spec/controllers/projects/settings/merge_requests_controller_spec.rb'
- - 'spec/controllers/projects/snippets/blobs_controller_spec.rb'
- - 'spec/controllers/projects/snippets_controller_spec.rb'
- - 'spec/controllers/projects/tree_controller_spec.rb'
- - 'spec/controllers/projects_controller_spec.rb'
- - 'spec/controllers/registrations_controller_spec.rb'
- - 'spec/controllers/search_controller_spec.rb'
- - 'spec/controllers/sessions_controller_spec.rb'
- - 'spec/controllers/snippets/blobs_controller_spec.rb'
- 'spec/factories/ci/processable.rb'
- 'spec/factories/draft_note.rb'
- 'spec/factories/environments.rb'
@@ -2476,7 +2320,6 @@ Layout/ArgumentAlignment:
- 'spec/helpers/avatars_helper_spec.rb'
- 'spec/helpers/emoji_helper_spec.rb'
- 'spec/helpers/feature_flags_helper_spec.rb'
- - 'spec/helpers/ide_helper_spec.rb'
- 'spec/helpers/namespaces_helper_spec.rb'
- 'spec/helpers/notify_helper_spec.rb'
- 'spec/helpers/page_layout_helper_spec.rb'
@@ -2842,10 +2685,6 @@ Layout/ArgumentAlignment:
- 'spec/policies/ci/pipeline_schedule_policy_spec.rb'
- 'spec/policies/environment_policy_spec.rb'
- 'spec/policies/group_policy_spec.rb'
- - 'spec/presenters/blob_presenter_spec.rb'
- - 'spec/presenters/ci/build_runner_presenter_spec.rb'
- - 'spec/presenters/merge_request_presenter_spec.rb'
- - 'spec/presenters/packages/detail/package_presenter_spec.rb'
- 'spec/requests/admin/applications_controller_spec.rb'
- 'spec/requests/admin/impersonation_tokens_controller_spec.rb'
- 'spec/requests/api/access_requests_spec.rb'
diff --git a/.rubocop_todo/layout/empty_line_after_magic_comment.yml b/.rubocop_todo/layout/empty_line_after_magic_comment.yml
index 9c7b9f2c1a8..c96a0f4c0f6 100644
--- a/.rubocop_todo/layout/empty_line_after_magic_comment.yml
+++ b/.rubocop_todo/layout/empty_line_after_magic_comment.yml
@@ -555,7 +555,6 @@ Layout/EmptyLineAfterMagicComment:
- 'spec/components/previews/pajamas/card_component_preview.rb'
- 'spec/components/previews/pajamas/spinner_component_preview.rb'
- 'spec/controllers/application_controller_spec.rb'
- - 'spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb'
- 'spec/controllers/projects/jobs_controller_spec.rb'
- 'spec/controllers/projects/merge_requests/drafts_controller_spec.rb'
- 'spec/factories/airflow/dags.rb'
@@ -813,7 +812,6 @@ Layout/EmptyLineAfterMagicComment:
- 'spec/services/packages/create_package_file_service_spec.rb'
- 'spec/services/packages/debian/extract_changes_metadata_service_spec.rb'
- 'spec/services/packages/debian/extract_deb_metadata_service_spec.rb'
- - 'spec/services/packages/debian/extract_metadata_service_spec.rb'
- 'spec/services/packages/debian/parse_debian822_service_spec.rb'
- 'spec/services/packages/debian/process_changes_service_spec.rb'
- 'spec/services/packages/debian/process_package_file_service_spec.rb'
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index 772284a6ce7..cc2252ce579 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -1582,7 +1582,6 @@ Layout/LineLength:
- '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/billings/extend_reactivate_trial_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'
@@ -3062,7 +3061,6 @@ Layout/LineLength:
- 'lib/gitlab/kubernetes/helm/pod.rb'
- 'lib/gitlab/kubernetes/kubectl_cmd.rb'
- 'lib/gitlab/kubernetes/pod_cmd.rb'
- - 'lib/gitlab/legacy_github_import/importer.rb'
- 'lib/gitlab/legacy_github_import/project_creator.rb'
- 'lib/gitlab/local_and_remote_storage_migration/base_migrater.rb'
- 'lib/gitlab/lograge/custom_options.rb'
@@ -4036,7 +4034,6 @@ Layout/LineLength:
- 'spec/lib/error_tracking/sentry_client/projects_spec.rb'
- 'spec/lib/event_filter_spec.rb'
- 'spec/lib/feature_spec.rb'
- - 'spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb'
- 'spec/lib/generators/gitlab/usage_metric_definition/redis_hll_generator_spec.rb'
- 'spec/lib/generators/gitlab/usage_metric_definition_generator_spec.rb'
- 'spec/lib/generators/gitlab/usage_metric_generator_spec.rb'
@@ -4150,7 +4147,6 @@ Layout/LineLength:
- 'spec/lib/gitlab/ci/reports/codequality_mr_diff_spec.rb'
- 'spec/lib/gitlab/ci/reports/security/flag_spec.rb'
- 'spec/lib/gitlab/ci/reports/security/scanner_spec.rb'
- - 'spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb'
- 'spec/lib/gitlab/ci/runner_upgrade_check_spec.rb'
- 'spec/lib/gitlab/ci/status/bridge/factory_spec.rb'
- 'spec/lib/gitlab/ci/status/build/manual_spec.rb'
@@ -4930,7 +4926,6 @@ Layout/LineLength:
- 'spec/requests/groups/milestones_controller_spec.rb'
- 'spec/requests/groups/settings/access_tokens_controller_spec.rb'
- 'spec/requests/groups_controller_spec.rb'
- - 'spec/requests/ide_controller_spec.rb'
- 'spec/requests/jwt_controller_spec.rb'
- 'spec/requests/lfs_http_spec.rb'
- 'spec/requests/oauth/tokens_controller_spec.rb'
diff --git a/.rubocop_todo/layout/space_in_lambda_literal.yml b/.rubocop_todo/layout/space_in_lambda_literal.yml
index 3abff1e8788..362d9b20eb1 100644
--- a/.rubocop_todo/layout/space_in_lambda_literal.yml
+++ b/.rubocop_todo/layout/space_in_lambda_literal.yml
@@ -400,7 +400,6 @@ Layout/SpaceInLambdaLiteral:
- 'spec/models/ability_spec.rb'
- 'spec/models/broadcast_message_spec.rb'
- 'spec/models/concerns/participable_spec.rb'
- - 'spec/models/concerns/uniquify_spec.rb'
- 'spec/models/merge_request_spec.rb'
- 'spec/support/shared_examples/lib/cache_helpers_shared_examples.rb'
- 'spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb'
diff --git a/.rubocop_todo/layout/space_inside_parens.yml b/.rubocop_todo/layout/space_inside_parens.yml
index 131a56976a6..de88cdc49bc 100644
--- a/.rubocop_todo/layout/space_inside_parens.yml
+++ b/.rubocop_todo/layout/space_inside_parens.yml
@@ -128,7 +128,6 @@ Layout/SpaceInsideParens:
- 'spec/lib/gitlab/ci/parsers/security/common_spec.rb'
- 'spec/lib/gitlab/ci/parsers_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/seed/build_spec.rb'
- - 'spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb'
- 'spec/lib/gitlab/ci/reports/test_suite_spec.rb'
- 'spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb'
- 'spec/lib/gitlab/ci/templates/MATLAB_spec.rb'
diff --git a/.rubocop_todo/lint/unused_block_argument.yml b/.rubocop_todo/lint/unused_block_argument.yml
index f226f04445a..b9013f03bfa 100644
--- a/.rubocop_todo/lint/unused_block_argument.yml
+++ b/.rubocop_todo/lint/unused_block_argument.yml
@@ -138,7 +138,6 @@ Lint/UnusedBlockArgument:
- 'ee/spec/factories/protected_environments.rb'
- 'ee/spec/factories/slack_integrations.rb'
- 'ee/spec/factories/users.rb'
- - 'ee/spec/features/billings/extend_reactivate_trial_spec.rb'
- 'ee/spec/features/groups/group_settings_spec.rb'
- 'ee/spec/graphql/mutations/dast/profiles/update_spec.rb'
- 'ee/spec/graphql/resolvers/analytics/contribution_analytics/contributions_resolver_spec.rb'
@@ -376,7 +375,6 @@ Lint/UnusedBlockArgument:
- 'spec/models/concerns/ci/partitionable/switch_spec.rb'
- 'spec/models/concerns/ci/partitionable_spec.rb'
- 'spec/models/concerns/each_batch_spec.rb'
- - 'spec/models/concerns/uniquify_spec.rb'
- 'spec/models/container_repository_spec.rb'
- 'spec/models/network/graph_spec.rb'
- 'spec/models/packages/debian/file_metadatum_spec.rb'
diff --git a/.rubocop_todo/lint/unused_method_argument.yml b/.rubocop_todo/lint/unused_method_argument.yml
index 8c23a6ae84b..a4e48b35248 100644
--- a/.rubocop_todo/lint/unused_method_argument.yml
+++ b/.rubocop_todo/lint/unused_method_argument.yml
@@ -19,7 +19,6 @@ Lint/UnusedMethodArgument:
- 'app/graphql/mutations/base_mutation.rb'
- 'app/graphql/mutations/ci/runner/delete.rb'
- 'app/graphql/mutations/concerns/mutations/assignable.rb'
- - 'app/graphql/mutations/members/groups/bulk_update.rb'
- 'app/graphql/mutations/notes/create/base.rb'
- 'app/graphql/mutations/notes/create/diff_note.rb'
- 'app/graphql/mutations/notes/create/image_diff_note.rb'
diff --git a/.rubocop_todo/naming/heredoc_delimiter_naming.yml b/.rubocop_todo/naming/heredoc_delimiter_naming.yml
index ae71e06b6d3..b92d316b693 100644
--- a/.rubocop_todo/naming/heredoc_delimiter_naming.yml
+++ b/.rubocop_todo/naming/heredoc_delimiter_naming.yml
@@ -50,7 +50,6 @@ Naming/HeredocDelimiterNaming:
- 'rubocop/cop/default_scope.rb'
- 'rubocop/cop/file_decompression.rb'
- 'rubocop/cop/gitlab/httparty.rb'
- - 'rubocop/cop/gitlab/json.rb'
- 'rubocop/cop/gitlab/module_with_instance_variables.rb'
- 'rubocop/cop/gitlab/predicate_memoization.rb'
- 'spec/controllers/projects/pipelines_controller_spec.rb'
diff --git a/.rubocop_todo/performance/map_compact.yml b/.rubocop_todo/performance/map_compact.yml
index ca0e8d604fd..f47388609ea 100644
--- a/.rubocop_todo/performance/map_compact.yml
+++ b/.rubocop_todo/performance/map_compact.yml
@@ -97,30 +97,17 @@ Performance/MapCompact:
- 'lib/gitlab/analytics/usage_trends/workers_argument_builder.rb'
- 'lib/gitlab/auth/ip_rate_limiter.rb'
- 'lib/gitlab/background_migration/backfill_project_repositories.rb'
- - 'lib/gitlab/changes_list.rb'
- - 'lib/gitlab/checks/changes_access.rb'
- 'lib/gitlab/ci/parsers/security/common.rb'
- 'lib/gitlab/ci/reports/security/aggregated_report.rb'
- 'lib/gitlab/ci/reports/security/finding.rb'
- 'lib/gitlab/ci/reports/test_suite_summary.rb'
- - 'lib/gitlab/config/entry/validators.rb'
- 'lib/gitlab/database/load_balancing/service_discovery.rb'
- 'lib/gitlab/database/obsolete_ignored_columns.rb'
- - 'lib/gitlab/email/receiver.rb'
- 'lib/gitlab/git/commit.rb'
- 'lib/gitlab/git/conflict/file.rb'
- 'lib/gitlab/git/rugged_impl/commit.rb'
- - 'lib/gitlab/github_import/importer/pull_requests/review_request_importer.rb'
- - 'lib/gitlab/issuable/clone/copy_resource_events_service.rb'
- - 'lib/gitlab/issues/rebalancing/state.rb'
- - 'lib/gitlab/jira_import/metadata_collector.rb'
- - 'lib/gitlab/json_cache.rb'
- - 'lib/gitlab/language_detection.rb'
- - 'lib/gitlab/legacy_github_import/importer.rb'
- - 'lib/gitlab/private_commit_email.rb'
- 'lib/gitlab/sql/pattern.rb'
- 'lib/gitlab/url_blocker.rb'
- - 'lib/gitlab/verify/batch_verifier.rb'
- 'qa/qa/page/component/issuable/sidebar.rb'
- 'qa/qa/support/formatters/test_metrics_formatter.rb'
- 'qa/qa/tools/ci/ff_changes.rb'
diff --git a/.rubocop_todo/performance/string_include.yml b/.rubocop_todo/performance/string_include.yml
deleted file mode 100644
index f2e17d3576a..00000000000
--- a/.rubocop_todo/performance/string_include.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-# Cop supports --autocorrect.
-Performance/StringInclude:
- Details: grace period
- Exclude:
- - 'lib/gitlab/github_import/importer/repository_importer.rb'
- - 'lib/gitlab/legacy_github_import/importer.rb'
- - 'lib/gitlab/usage_data.rb'
- - 'rubocop/cop/gitlab/json.rb'
diff --git a/.rubocop_todo/rails/inverse_of.yml b/.rubocop_todo/rails/inverse_of.yml
index 31535699d2e..752b1d9b4d1 100644
--- a/.rubocop_todo/rails/inverse_of.yml
+++ b/.rubocop_todo/rails/inverse_of.yml
@@ -1,21 +1,6 @@
---
Rails/InverseOf:
Exclude:
- - 'app/models/alert_management/alert.rb'
- - 'app/models/alert_management/alert_assignee.rb'
- - 'app/models/application_setting.rb'
- - 'app/models/audit_event.rb'
- - 'app/models/board.rb'
- - 'app/models/bulk_imports/entity.rb'
- - 'app/models/bulk_imports/tracker.rb'
- - 'app/models/ci/build.rb'
- - 'app/models/ci/build_pending_state.rb'
- - 'app/models/ci/build_trace_chunk.rb'
- - 'app/models/ci/daily_build_group_report_result.rb'
- - 'app/models/ci/job_artifact.rb'
- - 'app/models/ci/job_variable.rb'
- - 'app/models/ci/pipeline.rb'
- - 'app/models/ci/pipeline_schedule.rb'
- 'app/models/ci/runner.rb'
- 'app/models/ci/runner_namespace.rb'
- 'app/models/ci/sources/pipeline.rb'
@@ -44,7 +29,6 @@ Rails/InverseOf:
- 'app/models/group_group_link.rb'
- 'app/models/group_label.rb'
- 'app/models/incident_management/timeline_event.rb'
- - 'app/models/integrations/base_slash_commands.rb'
- 'app/models/issue.rb'
- 'app/models/jira_connect_subscription.rb'
- 'app/models/members/group_member.rb'
@@ -59,7 +43,6 @@ Rails/InverseOf:
- 'app/models/project.rb'
- 'app/models/project_label.rb'
- 'app/models/resource_state_event.rb'
- - 'app/models/serverless/domain_cluster.rb'
- 'app/models/terraform/state_version.rb'
- 'app/models/time_tracking/timelog_category.rb'
- 'app/models/todo.rb'
diff --git a/.rubocop_todo/rake/require.yml b/.rubocop_todo/rake/require.yml
index e3cd483f056..b24dd1e6540 100644
--- a/.rubocop_todo/rake/require.yml
+++ b/.rubocop_todo/rake/require.yml
@@ -2,19 +2,5 @@
Rake/Require:
Details: grace period
Exclude:
- - 'lib/tasks/gitlab/assets.rake'
- - 'lib/tasks/gitlab/docs/redirect.rake'
- - 'lib/tasks/gitlab/graphql.rake'
- - 'lib/tasks/gitlab/lfs/migrate.rake'
- - 'lib/tasks/gitlab/metrics_exporter.rake'
- - 'lib/tasks/gitlab/openapi.rake'
- - 'lib/tasks/gitlab/packages/events.rake'
- - 'lib/tasks/gitlab/packages/migrate.rake'
- - 'lib/tasks/gitlab/pages.rake'
- - 'lib/tasks/gitlab/refresh_project_statistics_build_artifacts_size.rake'
- - 'lib/tasks/gitlab/terraform/migrate.rake'
- - 'lib/tasks/gitlab/tw/codeowners.rake'
- - 'lib/tasks/gitlab/x509/update.rake'
- - 'lib/tasks/import.rake'
- 'lib/tasks/tokens.rake'
- 'qa/tasks/webdrivers.rake'
diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml
index cb732ea307c..ccbbc10ad49 100644
--- a/.rubocop_todo/rspec/context_wording.yml
+++ b/.rubocop_todo/rspec/context_wording.yml
@@ -1494,7 +1494,6 @@ RSpec/ContextWording:
- 'spec/helpers/gitlab_routing_helper_spec.rb'
- 'spec/helpers/groups/group_members_helper_spec.rb'
- 'spec/helpers/groups_helper_spec.rb'
- - 'spec/helpers/ide_helper_spec.rb'
- 'spec/helpers/integrations_helper_spec.rb'
- 'spec/helpers/jira_connect_helper_spec.rb'
- 'spec/helpers/labels_helper_spec.rb'
@@ -1636,7 +1635,6 @@ RSpec/ContextWording:
- 'spec/lib/extracts_ref_spec.rb'
- 'spec/lib/feature/definition_spec.rb'
- 'spec/lib/feature_spec.rb'
- - 'spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb'
- 'spec/lib/gitlab/alert_management/fingerprint_spec.rb'
- 'spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb'
- 'spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb'
@@ -1732,7 +1730,6 @@ RSpec/ContextWording:
- 'spec/lib/gitlab/ci/pipeline_object_hierarchy_spec.rb'
- 'spec/lib/gitlab/ci/reports/reports_comparer_spec.rb'
- 'spec/lib/gitlab/ci/reports/security/aggregated_report_spec.rb'
- - 'spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb'
- 'spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb'
- 'spec/lib/gitlab/ci/runner_instructions_spec.rb'
- 'spec/lib/gitlab/ci/runner_upgrade_check_spec.rb'
@@ -2576,7 +2573,6 @@ RSpec/ContextWording:
- 'spec/requests/groups/settings/access_tokens_controller_spec.rb'
- 'spec/requests/groups_controller_spec.rb'
- 'spec/requests/health_controller_spec.rb'
- - 'spec/requests/ide_controller_spec.rb'
- 'spec/requests/jira_connect/installations_controller_spec.rb'
- 'spec/requests/jira_connect/oauth_application_ids_controller_spec.rb'
- 'spec/requests/jira_routing_spec.rb'
@@ -2847,7 +2843,6 @@ RSpec/ContextWording:
- 'spec/services/packages/conan/create_package_service_spec.rb'
- 'spec/services/packages/create_package_file_service_spec.rb'
- 'spec/services/packages/debian/create_distribution_service_spec.rb'
- - 'spec/services/packages/debian/extract_metadata_service_spec.rb'
- 'spec/services/packages/debian/find_or_create_incoming_service_spec.rb'
- 'spec/services/packages/debian/process_changes_service_spec.rb'
- 'spec/services/packages/helm/process_file_service_spec.rb'
diff --git a/.rubocop_todo/rspec/invalid_feature_category.yml b/.rubocop_todo/rspec/invalid_feature_category.yml
deleted file mode 100644
index 53ed05b881c..00000000000
--- a/.rubocop_todo/rspec/invalid_feature_category.yml
+++ /dev/null
@@ -1,66 +0,0 @@
----
-RSpec/InvalidFeatureCategory:
- Exclude:
- - 'ee/spec/controllers/admin/application_settings_controller_spec.rb'
- - 'ee/spec/controllers/admin/applications_controller_spec.rb'
- - 'ee/spec/controllers/admin/dashboard_controller_spec.rb'
- - 'ee/spec/controllers/admin/emails_controller_spec.rb'
- - 'ee/spec/controllers/countries_controller_spec.rb'
- - 'ee/spec/controllers/country_states_controller_spec.rb'
- - 'ee/spec/controllers/sitemap_controller_spec.rb'
- - 'ee/spec/features/admin/admin_dashboard_spec.rb'
- - 'ee/spec/features/dashboards/operations_spec.rb'
- - 'ee/spec/requests/api/award_emoji_spec.rb'
- - 'ee/spec/requests/api/settings_spec.rb'
- - 'spec/config/inject_enterprise_edition_module_spec.rb'
- - 'spec/config/object_store_settings_spec.rb'
- - 'spec/config/smime_signature_settings_spec.rb'
- - 'spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb'
- - 'spec/controllers/concerns/content_security_policy_patch_spec.rb'
- - 'spec/features/action_cable_logging_spec.rb'
- - 'spec/features/admin/admin_abuse_reports_spec.rb'
- - 'spec/features/admin/admin_appearance_spec.rb'
- - 'spec/features/admin/admin_browse_spam_logs_spec.rb'
- - 'spec/features/admin/admin_mode_spec.rb'
- - 'spec/features/admin/admin_settings_spec.rb'
- - 'spec/features/admin/admin_system_info_spec.rb'
- - 'spec/features/breadcrumbs_schema_markup_spec.rb'
- - 'spec/features/dashboard/root_explore_spec.rb'
- - 'spec/features/dashboard/shortcuts_spec.rb'
- - 'spec/features/display_system_header_and_footer_bar_spec.rb'
- - 'spec/features/frequently_visited_projects_and_groups_spec.rb'
- - 'spec/features/help_dropdown_spec.rb'
- - 'spec/features/help_pages_spec.rb'
- - 'spec/features/monitor_sidebar_link_spec.rb'
- - 'spec/features/unsubscribe_links_spec.rb'
- - 'spec/features/whats_new_spec.rb'
- - 'spec/lib/api/helpers_spec.rb'
- - 'spec/lib/gitlab/slug/path_spec.rb'
- - 'spec/lib/gitlab/utils/strong_memoize_spec.rb'
- - 'spec/models/application_setting_spec.rb'
- - 'spec/models/namespaces/randomized_suffix_path_spec.rb'
- - 'spec/requests/admin/version_check_controller_spec.rb'
- - 'spec/requests/api/admin/plan_limits_spec.rb'
- - 'spec/requests/api/admin/sidekiq_spec.rb'
- - 'spec/requests/api/api_guard/admin_mode_middleware_spec.rb'
- - 'spec/requests/api/api_guard/response_coercer_middleware_spec.rb'
- - 'spec/requests/api/award_emoji_spec.rb'
- - 'spec/requests/api/graphql/custom_emoji_query_spec.rb'
- - 'spec/requests/api/graphql/multiplexed_queries_spec.rb'
- - 'spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb'
- - 'spec/requests/api/graphql/mutations/award_emojis/add_spec.rb'
- - 'spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb'
- - 'spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb'
- - 'spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb'
- - 'spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb'
- - 'spec/requests/api/graphql/query_spec.rb'
- - 'spec/requests/api/graphql_spec.rb'
- - 'spec/requests/api/internal/workhorse_spec.rb'
- - 'spec/requests/api/metadata_spec.rb'
- - 'spec/requests/api/settings_spec.rb'
- - 'spec/requests/api/sidekiq_metrics_spec.rb'
- - 'spec/requests/projects/uploads_spec.rb'
- - 'spec/requests/sandbox_controller_spec.rb'
- - 'spec/rubocop/cop/gitlab/doc_url_spec.rb'
- - 'spec/rubocop/cop/lint/last_keyword_argument_spec.rb'
- - 'spec/rubocop/cop/rspec/avoid_test_prof_spec.rb'
diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml
index fa24075c566..bbd6cccef0f 100644
--- a/.rubocop_todo/rspec/missing_feature_category.yml
+++ b/.rubocop_todo/rspec/missing_feature_category.yml
@@ -1,7 +1,6 @@
---
RSpec/MissingFeatureCategory:
Exclude:
- - 'ee/spec/components/billing/plan_component_spec.rb'
- 'ee/spec/components/namespaces/free_user_cap/enforcement_alert_component_spec.rb'
- 'ee/spec/components/namespaces/free_user_cap/enforcement_at_limit_alert_component_spec.rb'
- 'ee/spec/components/namespaces/free_user_cap/non_owner_alert_component_spec.rb'
@@ -118,7 +117,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/finders/incident_management/oncall_users_finder_spec.rb'
- 'ee/spec/finders/issues_finder_spec.rb'
- 'ee/spec/finders/iterations/cadences_finder_spec.rb'
- - 'ee/spec/finders/iterations_finder_spec.rb'
- 'ee/spec/finders/license_template_finder_spec.rb'
- 'ee/spec/finders/licenses_finder_spec.rb'
- 'ee/spec/finders/merge_requests_finder_spec.rb'
@@ -138,7 +136,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/finders/security/vulnerability_feedbacks_finder_spec.rb'
- 'ee/spec/finders/security/vulnerability_reads_finder_spec.rb'
- 'ee/spec/finders/snippets_finder_spec.rb'
- - 'ee/spec/finders/software_license_policies_finder_spec.rb'
- 'ee/spec/finders/status_page/incident_comments_finder_spec.rb'
- 'ee/spec/finders/status_page/incidents_finder_spec.rb'
- 'ee/spec/finders/template_finder_spec.rb'
@@ -207,8 +204,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/graphql/graphql_triggers_spec.rb'
- 'ee/spec/graphql/mutations/app_sec/fuzzing/api/ci_configuration/create_spec.rb'
- 'ee/spec/graphql/mutations/app_sec/fuzzing/coverage/corpus/create_spec.rb'
- - 'ee/spec/graphql/mutations/audit_events/streaming/event_type_filters/create_spec.rb'
- - 'ee/spec/graphql/mutations/audit_events/streaming/event_type_filters/destroy_spec.rb'
- 'ee/spec/graphql/mutations/audit_events/streaming/headers/create_spec.rb'
- 'ee/spec/graphql/mutations/audit_events/streaming/headers/destroy_spec.rb'
- 'ee/spec/graphql/mutations/boards/epic_boards/create_spec.rb'
@@ -295,7 +290,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/graphql/resolvers/compliance_management/merge_requests/compliance_violation_resolver_spec.rb'
- 'ee/spec/graphql/resolvers/dast_site_profile_resolver_spec.rb'
- 'ee/spec/graphql/resolvers/dast_site_validation_resolver_spec.rb'
- - 'ee/spec/graphql/resolvers/dora_metrics_resolver_spec.rb'
- 'ee/spec/graphql/resolvers/epic_ancestors_resolver_spec.rb'
- 'ee/spec/graphql/resolvers/epic_issues_resolver_spec.rb'
- 'ee/spec/graphql/resolvers/epics/children_resolver_spec.rb'
@@ -397,7 +391,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/graphql/types/deployments/approval_type_spec.rb'
- 'ee/spec/graphql/types/dora_metric_bucketing_interval_enum_spec.rb'
- 'ee/spec/graphql/types/dora_metric_type_enum_spec.rb'
- - 'ee/spec/graphql/types/dora_metric_type_spec.rb'
- 'ee/spec/graphql/types/dora_type_spec.rb'
- 'ee/spec/graphql/types/epic_connection_type_spec.rb'
- 'ee/spec/graphql/types/epic_descendant_count_type_spec.rb'
@@ -495,7 +488,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/graphql/types/vulnerability_details/list_type_spec.rb'
- 'ee/spec/graphql/types/vulnerability_details/markdown_type_spec.rb'
- 'ee/spec/graphql/types/vulnerability_details/module_location_type_spec.rb'
- - 'ee/spec/graphql/types/vulnerability_details/table_type_spec.rb'
- 'ee/spec/graphql/types/vulnerability_details/text_type_spec.rb'
- 'ee/spec/graphql/types/vulnerability_details/url_type_spec.rb'
- 'ee/spec/graphql/types/vulnerability_evidence_source_type_spec.rb'
@@ -539,7 +531,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/helpers/analytics/code_review_helper_spec.rb'
- 'ee/spec/helpers/application_helper_spec.rb'
- 'ee/spec/helpers/audit_events_helper_spec.rb'
- - 'ee/spec/helpers/billing_plans_helper_spec.rb'
- 'ee/spec/helpers/boards_helper_spec.rb'
- 'ee/spec/helpers/compliance_management/compliance_framework/group_settings_helper_spec.rb'
- 'ee/spec/helpers/credentials_inventory_helper_spec.rb'
@@ -560,7 +551,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/helpers/ee/geo_helper_spec.rb'
- 'ee/spec/helpers/ee/gitlab_routing_helper_spec.rb'
- 'ee/spec/helpers/ee/graph_helper_spec.rb'
- - 'ee/spec/helpers/ee/groups/analytics/cycle_analytics_helper_spec.rb'
- 'ee/spec/helpers/ee/groups/group_members_helper_spec.rb'
- 'ee/spec/helpers/ee/groups/settings_helper_spec.rb'
- 'ee/spec/helpers/ee/groups_helper_spec.rb'
@@ -629,7 +619,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/initializers/session_store_spec.rb'
- 'ee/spec/lib/analytics/devops_adoption/snapshot_calculator_spec.rb'
- 'ee/spec/lib/analytics/group_activity_calculator_spec.rb'
- - 'ee/spec/lib/analytics/merge_request_metrics_refresh_spec.rb'
- 'ee/spec/lib/analytics/productivity_analytics_request_params_spec.rb'
- 'ee/spec/lib/analytics/refresh_approvals_data_spec.rb'
- 'ee/spec/lib/analytics/refresh_comments_data_spec.rb'
@@ -653,7 +642,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/audit/group_merge_request_approval_setting_changes_auditor_spec.rb'
- 'ee/spec/lib/audit/group_push_rules_changes_auditor_spec.rb'
- 'ee/spec/lib/banzai/filter/cross_project_issuable_information_filter_spec.rb'
- - 'ee/spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb'
- 'ee/spec/lib/banzai/filter/jira_private_image_link_filter_spec.rb'
- 'ee/spec/lib/banzai/filter/references/epic_reference_filter_spec.rb'
- 'ee/spec/lib/banzai/filter/references/iteration_reference_filter_spec.rb'
@@ -667,7 +655,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/bulk_imports/common/pipelines/wiki_pipeline_spec.rb'
- 'ee/spec/lib/bulk_imports/groups/graphql/get_iterations_query_spec.rb'
- 'ee/spec/lib/bulk_imports/groups/pipelines/epics_pipeline_spec.rb'
- - 'ee/spec/lib/bulk_imports/groups/pipelines/iterations_cadences_pipeline_spec.rb'
- 'ee/spec/lib/bulk_imports/groups/pipelines/iterations_pipeline_spec.rb'
- 'ee/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb'
- 'ee/spec/lib/bulk_imports/projects/pipelines/protected_branches_pipeline_spec.rb'
@@ -748,7 +735,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/ee/gitlab/background_migration/purge_stale_security_scans_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/recalculate_vulnerability_finding_signatures_for_findings_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/update_vulnerability_occurrences_location_spec.rb'
- - 'ee/spec/lib/ee/gitlab/checks/push_rule_check_spec.rb'
- 'ee/spec/lib/ee/gitlab/checks/push_rules/branch_check_spec.rb'
- 'ee/spec/lib/ee/gitlab/checks/push_rules/commit_check_spec.rb'
- 'ee/spec/lib/ee/gitlab/checks/push_rules/file_size_check_spec.rb'
@@ -773,7 +759,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/ee/gitlab/database/gitlab_schema_spec.rb'
- 'ee/spec/lib/ee/gitlab/database_spec.rb'
- 'ee/spec/lib/ee/gitlab/email/handler/service_desk_handler_spec.rb'
- - 'ee/spec/lib/ee/gitlab/etag_caching/router/rails_spec.rb'
- 'ee/spec/lib/ee/gitlab/event_store_spec.rb'
- 'ee/spec/lib/ee/gitlab/git_access_design_spec.rb'
- 'ee/spec/lib/ee/gitlab/git_access_project_spec.rb'
@@ -803,8 +788,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/ee/gitlab/repo_path_spec.rb'
- 'ee/spec/lib/ee/gitlab/repository_size_checker_spec.rb'
- 'ee/spec/lib/ee/gitlab/scim/attribute_transform_spec.rb'
- - 'ee/spec/lib/ee/gitlab/scim/filter_parser_spec.rb'
- - 'ee/spec/lib/ee/gitlab/scim/params_parser_spec.rb'
- 'ee/spec/lib/ee/gitlab/scim/value_parser_spec.rb'
- 'ee/spec/lib/ee/gitlab/search_results_spec.rb'
- 'ee/spec/lib/ee/gitlab/security/scan_configuration_spec.rb'
@@ -830,14 +813,11 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/ee/sidebars/projects/menus/issues_menu_spec.rb'
- 'ee/spec/lib/ee/sidebars/projects/menus/monitor_menu_spec.rb'
- 'ee/spec/lib/ee/sidebars/projects/menus/repository_menu_spec.rb'
- - 'ee/spec/lib/ee/sidebars/projects/menus/security_compliance_menu_spec.rb'
- 'ee/spec/lib/ee/sidebars/projects/panel_spec.rb'
- - 'ee/spec/lib/elastic/latest/application_instance_proxy_spec.rb'
- 'ee/spec/lib/elastic/latest/commit_config_spec.rb'
- 'ee/spec/lib/elastic/latest/config_spec.rb'
- 'ee/spec/lib/elastic/latest/custom_language_analyzers_spec.rb'
- 'ee/spec/lib/elastic/latest/git_instance_proxy_spec.rb'
- - 'ee/spec/lib/elastic/latest/issue_class_proxy_spec.rb'
- 'ee/spec/lib/elastic/latest/issue_config_spec.rb'
- 'ee/spec/lib/elastic/latest/merge_request_config_spec.rb'
- 'ee/spec/lib/elastic/latest/note_config_spec.rb'
@@ -856,7 +836,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/data_collector_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/data_for_duration_chart_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/distinct_stage_loader_spec.rb'
- - 'ee/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_closed_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_added_to_board_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_associated_with_milestone_spec.rb'
@@ -868,11 +847,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_label_added_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_label_removed_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_edited_spec.rb'
- - 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/base_dora_summary_spec.rb'
- - 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/change_failure_rate_spec.rb'
- - 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/lead_time_for_changes_spec.rb'
- - 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/lead_time_spec.rb'
- - 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/time_to_restore_service_spec.rb'
- 'ee/spec/lib/gitlab/analytics/type_of_work/tasks_by_type_spec.rb'
- 'ee/spec/lib/gitlab/audit/auditor_spec.rb'
- 'ee/spec/lib/gitlab/audit/events/preloader_spec.rb'
@@ -922,10 +896,8 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/ci/config/entry/vault/engine_spec.rb'
- 'ee/spec/lib/gitlab/ci/config/entry/vault/secret_spec.rb'
- 'ee/spec/lib/gitlab/ci/config/required/processor_spec.rb'
- - 'ee/spec/lib/gitlab/ci/minutes/build_consumption_spec.rb'
- 'ee/spec/lib/gitlab/ci/minutes/cached_quota_spec.rb'
- 'ee/spec/lib/gitlab/ci/minutes/cost_factor_spec.rb'
- - 'ee/spec/lib/gitlab/ci/minutes/gitlab_contribution_cost_factor_spec.rb'
- 'ee/spec/lib/gitlab/ci/minutes/runners_availability_spec.rb'
- 'ee/spec/lib/gitlab/ci/parsers/license_compliance/license_scanning_spec.rb'
- 'ee/spec/lib/gitlab/ci/parsers/metrics/generic_spec.rb'
@@ -936,7 +908,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/ci/parsers/security/dependency_scanning_spec.rb'
- 'ee/spec/lib/gitlab/ci/parsers/security/formatters/dependency_list_spec.rb'
- 'ee/spec/lib/gitlab/ci/parsers/security/validators/default_branch_image_validator_spec.rb'
- - 'ee/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb'
- 'ee/spec/lib/gitlab/ci/pipeline/chain/create_cross_database_associations_spec.rb'
- 'ee/spec/lib/gitlab/ci/pipeline/chain/limit/activity_spec.rb'
- 'ee/spec/lib/gitlab/ci/pipeline/chain/limit/size_spec.rb'
@@ -965,16 +936,7 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/ci/templates/secure_binaries_ci_yaml_spec.rb'
- 'ee/spec/lib/gitlab/ci/yaml_processor_spec.rb'
- 'ee/spec/lib/gitlab/cidr_spec.rb'
- - 'ee/spec/lib/gitlab/code_owners/entry_spec.rb'
- - 'ee/spec/lib/gitlab/code_owners/groups_loader_spec.rb'
- - 'ee/spec/lib/gitlab/code_owners/loader_spec.rb'
- - 'ee/spec/lib/gitlab/code_owners/reference_extractor_spec.rb'
- - 'ee/spec/lib/gitlab/code_owners/users_loader_spec.rb'
- - 'ee/spec/lib/gitlab/code_owners/validator_spec.rb'
- - 'ee/spec/lib/gitlab/code_owners_spec.rb'
- 'ee/spec/lib/gitlab/com_spec.rb'
- - 'ee/spec/lib/gitlab/console_spec.rb'
- - 'ee/spec/lib/gitlab/contribution_analytics/data_collector_spec.rb'
- 'ee/spec/lib/gitlab/custom_file_templates_spec.rb'
- 'ee/spec/lib/gitlab/customers_dot/jwt_spec.rb'
- 'ee/spec/lib/gitlab/data_builder/vulnerability_spec.rb'
@@ -1048,7 +1010,6 @@ RSpec/MissingFeatureCategory:
- '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/dora_executor_spec.rb'
- 'ee/spec/lib/gitlab/insights/executors/issuable_executor_spec.rb'
- 'ee/spec/lib/gitlab/insights/finders/projects_finder_spec.rb'
- 'ee/spec/lib/gitlab/insights/loader_spec.rb'
@@ -1109,7 +1070,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/status_page/usage_data_counters/incident_counter_spec.rb'
- 'ee/spec/lib/gitlab/status_page_spec.rb'
- 'ee/spec/lib/gitlab/subscription_portal/client_spec.rb'
- - 'ee/spec/lib/gitlab/subscription_portal/clients/graphql_spec.rb'
- 'ee/spec/lib/gitlab/subscription_portal/clients/rest_spec.rb'
- 'ee/spec/lib/gitlab/template/custom_templates_spec.rb'
- 'ee/spec/lib/gitlab/tracking/snowplow_schema_validation_spec.rb'
@@ -1164,11 +1124,8 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/omni_auth/strategies/kerberos_spec.rb'
- 'ee/spec/lib/peek/views/elasticsearch_spec.rb'
- 'ee/spec/lib/quality/seeders/vulnerabilities_spec.rb'
- - 'ee/spec/lib/sidebars/groups/menus/administration_menu_spec.rb'
- 'ee/spec/lib/sidebars/groups/menus/analytics_menu_spec.rb'
- - 'ee/spec/lib/sidebars/groups/menus/epics_menu_spec.rb'
- 'ee/spec/lib/sidebars/groups/menus/security_compliance_menu_spec.rb'
- - 'ee/spec/lib/sidebars/groups/menus/wiki_menu_spec.rb'
- 'ee/spec/lib/slack/api_spec.rb'
- 'ee/spec/lib/slack/block_kit/app_home_opened_spec.rb'
- 'ee/spec/lib/slack/block_kit/incident_management/incident_modal_opened_spec.rb'
@@ -1186,14 +1143,12 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/mailers/emails/free_user_cap_spec.rb'
- 'ee/spec/mailers/emails/group_memberships_spec.rb'
- 'ee/spec/mailers/emails/in_product_marketing_spec.rb'
- - 'ee/spec/mailers/emails/merge_commits_spec.rb'
- 'ee/spec/mailers/emails/namespace_storage_usage_mailer_spec.rb'
- 'ee/spec/mailers/emails/requirements_spec.rb'
- 'ee/spec/mailers/emails/user_cap_spec.rb'
- 'ee/spec/mailers/license_mailer_spec.rb'
- 'ee/spec/mailers/notify_spec.rb'
- 'ee/spec/models/alert_management/alert_payload_field_spec.rb'
- - 'ee/spec/models/allowed_email_domain_spec.rb'
- 'ee/spec/models/analytics/cycle_analytics/aggregation_context_spec.rb'
- 'ee/spec/models/analytics/cycle_analytics/runtime_limiter_spec.rb'
- 'ee/spec/models/analytics/devops_adoption/enabled_namespace_spec.rb'
@@ -1223,7 +1178,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/models/boards/epic_user_preference_spec.rb'
- 'ee/spec/models/broadcast_message_spec.rb'
- 'ee/spec/models/ci/bridge_spec.rb'
- - 'ee/spec/models/ci/build_spec.rb'
- 'ee/spec/models/ci/daily_build_group_report_result_spec.rb'
- 'ee/spec/models/ci/minutes/additional_pack_spec.rb'
- 'ee/spec/models/ci/minutes/context_spec.rb'
@@ -1250,8 +1204,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/models/concerns/ee/participable_spec.rb'
- 'ee/spec/models/concerns/ee/project_security_scanners_information_spec.rb'
- 'ee/spec/models/concerns/ee/weight_eventable_spec.rb'
- - 'ee/spec/models/concerns/elastic/application_versioned_search_spec.rb'
- - 'ee/spec/models/concerns/elastic/issue_spec.rb'
- 'ee/spec/models/concerns/elastic/merge_request_spec.rb'
- 'ee/spec/models/concerns/elastic/milestone_spec.rb'
- 'ee/spec/models/concerns/elastic/project_wiki_spec.rb'
@@ -1266,7 +1218,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/models/concerns/geo/verifiable_model_spec.rb'
- 'ee/spec/models/concerns/geo/verification_state_spec.rb'
- 'ee/spec/models/concerns/health_status_spec.rb'
- - 'ee/spec/models/concerns/identity_verifiable_spec.rb'
- 'ee/spec/models/concerns/incident_management/base_pending_escalation_spec.rb'
- 'ee/spec/models/concerns/mirror_configuration_spec.rb'
- 'ee/spec/models/concerns/password_complexity_spec.rb'
@@ -1359,22 +1310,11 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/models/epic/related_epic_link_spec.rb'
- 'ee/spec/models/epic_user_mention_spec.rb'
- 'ee/spec/models/geo/cache_invalidation_event_spec.rb'
- - '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/dependency_proxy_blob_registry_spec.rb'
- - 'ee/spec/models/geo/dependency_proxy_manifest_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'
- - 'ee/spec/models/geo/group_wiki_repository_registry_spec.rb'
- 'ee/spec/models/geo/hashed_storage_migrated_event_spec.rb'
- - 'ee/spec/models/geo/job_artifact_registry_spec.rb'
- - 'ee/spec/models/geo/lfs_object_registry_spec.rb'
- - 'ee/spec/models/geo/merge_request_diff_registry_spec.rb'
- - 'ee/spec/models/geo/pages_deployment_registry_spec.rb'
- - 'ee/spec/models/geo/pipeline_artifact_registry_spec.rb'
- - 'ee/spec/models/geo/project_wiki_repository_registry_spec.rb'
- 'ee/spec/models/geo/project_wiki_repository_state_spec.rb'
- 'ee/spec/models/geo/push_user_spec.rb'
- 'ee/spec/models/geo/repositories_changed_event_spec.rb'
@@ -1383,16 +1323,12 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/models/geo/repository_updated_event_spec.rb'
- 'ee/spec/models/geo/reset_checksum_event_spec.rb'
- 'ee/spec/models/geo/secondary_usage_data_spec.rb'
- - 'ee/spec/models/geo/snippet_repository_registry_spec.rb'
- - 'ee/spec/models/geo/terraform_state_version_registry_spec.rb'
- 'ee/spec/models/geo/tracking_base_spec.rb'
- - 'ee/spec/models/geo/upload_registry_spec.rb'
- 'ee/spec/models/geo/upload_state_spec.rb'
- 'ee/spec/models/geo_node_namespace_link_spec.rb'
- 'ee/spec/models/geo_node_spec.rb'
- 'ee/spec/models/gitlab/seat_link_data_spec.rb'
- 'ee/spec/models/gitlab_subscription_history_spec.rb'
- - 'ee/spec/models/gitlab_subscription_spec.rb'
- 'ee/spec/models/gitlab_subscriptions/features_spec.rb'
- 'ee/spec/models/gitlab_subscriptions/upcoming_reconciliation_spec.rb'
- 'ee/spec/models/group_deletion_schedule_spec.rb'
@@ -1468,20 +1404,17 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/models/requirements_management/requirement_spec.rb'
- 'ee/spec/models/saml_group_link_spec.rb'
- 'ee/spec/models/saml_provider_spec.rb'
- - 'ee/spec/models/sca/license_policy_spec.rb'
- 'ee/spec/models/scoped_label_set_spec.rb'
- 'ee/spec/models/security/orchestration_policy_rule_schedule_spec.rb'
- 'ee/spec/models/security/training_provider_spec.rb'
- 'ee/spec/models/security/training_spec.rb'
- 'ee/spec/models/snippet_repository_spec.rb'
- 'ee/spec/models/snippet_spec.rb'
- - 'ee/spec/models/software_license_policy_spec.rb'
- 'ee/spec/models/status_page/project_setting_spec.rb'
- 'ee/spec/models/status_page/published_incident_spec.rb'
- 'ee/spec/models/storage_shard_spec.rb'
- 'ee/spec/models/upload_spec.rb'
- 'ee/spec/models/uploads/local_spec.rb'
- - 'ee/spec/models/user_detail_spec.rb'
- 'ee/spec/models/user_permission_export_upload_spec.rb'
- 'ee/spec/models/user_preference_spec.rb'
- 'ee/spec/models/users_security_dashboard_project_spec.rb'
@@ -1514,7 +1447,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/policies/geo/registry_policy_spec.rb'
- 'ee/spec/policies/geo_node_policy_spec.rb'
- 'ee/spec/policies/group_hook_policy_spec.rb'
- - 'ee/spec/policies/group_policy_spec.rb'
- 'ee/spec/policies/identity_provider_policy_spec.rb'
- 'ee/spec/policies/incident_management/oncall_rotation_policy_spec.rb'
- 'ee/spec/policies/incident_management/oncall_schedule_policy_spec.rb'
@@ -1657,7 +1589,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/serializers/protected_environments/deploy_access_level_entity_spec.rb'
- 'ee/spec/serializers/protected_environments/entity_spec.rb'
- 'ee/spec/serializers/scim_oauth_access_token_entity_spec.rb'
- - 'ee/spec/serializers/security/license_policy_entity_spec.rb'
- 'ee/spec/serializers/security/vulnerability_report_data_entity_spec.rb'
- 'ee/spec/serializers/security/vulnerability_report_data_serializer_spec.rb'
- 'ee/spec/serializers/status_page/incident_comment_entity_spec.rb'
@@ -1722,7 +1653,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/arkose/blocked_users_report_service_spec.rb'
- 'ee/spec/services/arkose/record_user_data_service_spec.rb'
- 'ee/spec/services/arkose/token_verification_service_spec.rb'
- - 'ee/spec/services/audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/build_service_spec.rb'
- 'ee/spec/services/audit_events/custom_audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/impersonation_audit_event_service_spec.rb'
@@ -1732,11 +1662,8 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/audit_events/release_associate_milestone_audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/release_created_audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/release_updated_audit_event_service_spec.rb'
- - 'ee/spec/services/audit_events/repository_download_started_audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/runner_custom_audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/runners_token_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/audit_events/streaming/headers/base_spec.rb'
- 'ee/spec/services/audit_events/streaming/headers/create_service_spec.rb'
- 'ee/spec/services/audit_events/streaming/headers/destroy_service_spec.rb'
@@ -1748,7 +1675,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb'
- 'ee/spec/services/award_emojis/add_service_spec.rb'
- 'ee/spec/services/award_emojis/destroy_service_spec.rb'
- - 'ee/spec/services/base_count_service_spec.rb'
- 'ee/spec/services/billable_members/destroy_service_spec.rb'
- 'ee/spec/services/boards/create_service_spec.rb'
- 'ee/spec/services/boards/epic_boards/create_service_spec.rb'
@@ -1767,335 +1693,11 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/boards/update_service_spec.rb'
- 'ee/spec/services/boards/user_preferences/update_service_spec.rb'
- 'ee/spec/services/branches/delete_service_spec.rb'
- - 'ee/spec/services/ci/audit_variable_change_service_spec.rb'
- - 'ee/spec/services/ci/compare_metrics_reports_service_spec.rb'
- - 'ee/spec/services/ci/compare_security_reports_service_spec.rb'
- - 'ee/spec/services/ci/copy_cross_database_associations_service_spec.rb'
- - 'ee/spec/services/ci/create_pipeline_service/compliance_spec.rb'
- - 'ee/spec/services/ci/create_pipeline_service/cross_needs_artifacts_spec.rb'
- - 'ee/spec/services/ci/create_pipeline_service/dast_configuration_spec.rb'
- - 'ee/spec/services/ci/create_pipeline_service/needs_spec.rb'
- - 'ee/spec/services/ci/create_pipeline_service/runnable_builds_spec.rb'
- - 'ee/spec/services/ci/create_pipeline_service_spec.rb'
- - 'ee/spec/services/ci/destroy_pipeline_service_spec.rb'
- - 'ee/spec/services/ci/external_pull_requests/process_github_event_service_spec.rb'
- - 'ee/spec/services/ci/minutes/additional_packs/change_namespace_service_spec.rb'
- - 'ee/spec/services/ci/minutes/additional_packs/create_service_spec.rb'
- - 'ee/spec/services/ci/minutes/batch_reset_service_spec.rb'
- - 'ee/spec/services/ci/minutes/email_notification_service_spec.rb'
- - 'ee/spec/services/ci/minutes/refresh_cached_data_service_spec.rb'
- - 'ee/spec/services/ci/minutes/reset_usage_service_spec.rb'
- - 'ee/spec/services/ci/minutes/track_live_consumption_service_spec.rb'
- - 'ee/spec/services/ci/minutes/update_build_minutes_service_spec.rb'
- - 'ee/spec/services/ci/pipeline_bridge_status_service_spec.rb'
- - 'ee/spec/services/ci/pipeline_creation/drop_not_runnable_builds_service_spec.rb'
- - 'ee/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb'
- - 'ee/spec/services/ci/pipeline_trigger_service_spec.rb'
- - 'ee/spec/services/ci/play_bridge_service_spec.rb'
- - 'ee/spec/services/ci/play_build_service_spec.rb'
- - 'ee/spec/services/ci/process_build_service_spec.rb'
- - 'ee/spec/services/ci/process_pipeline_service_spec.rb'
- - 'ee/spec/services/ci/retry_job_service_spec.rb'
- - 'ee/spec/services/ci/retry_pipeline_service_spec.rb'
- - 'ee/spec/services/ci/subscribe_bridge_service_spec.rb'
- - 'ee/spec/services/ci/trigger_downstream_subscription_service_spec.rb'
- - 'ee/spec/services/ci_cd/github_integration_setup_service_spec.rb'
- - 'ee/spec/services/ci_cd/github_setup_service_spec.rb'
- - 'ee/spec/services/ci_cd/setup_project_spec.rb'
- - 'ee/spec/services/compliance_management/frameworks/create_service_spec.rb'
- - 'ee/spec/services/compliance_management/frameworks/destroy_service_spec.rb'
- - 'ee/spec/services/compliance_management/frameworks/update_service_spec.rb'
- - 'ee/spec/services/compliance_management/merge_requests/create_compliance_violations_service_spec.rb'
- - 'ee/spec/services/concerns/epics/related_epic_links/usage_data_helper_spec.rb'
- - 'ee/spec/services/dashboard/environments/list_service_spec.rb'
- - 'ee/spec/services/dashboard/operations/list_service_spec.rb'
- - 'ee/spec/services/dashboard/projects/create_service_spec.rb'
- - 'ee/spec/services/dashboard/projects/list_service_spec.rb'
- - 'ee/spec/services/deploy_keys/create_service_spec.rb'
- - 'ee/spec/services/deployments/auto_rollback_service_spec.rb'
- - 'ee/spec/services/ee/admin/set_feature_flag_service_spec.rb'
- - 'ee/spec/services/ee/alert_management/alerts/update_service_spec.rb'
- - 'ee/spec/services/ee/alert_management/create_alert_issue_service_spec.rb'
- - 'ee/spec/services/ee/alert_management/http_integrations/create_service_spec.rb'
- - 'ee/spec/services/ee/alert_management/http_integrations/update_service_spec.rb'
- - 'ee/spec/services/ee/allowed_email_domains/update_service_spec.rb'
- - 'ee/spec/services/ee/auth/container_registry_authentication_service_spec.rb'
- - 'ee/spec/services/ee/auto_merge_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/list_service_spec.rb'
- - 'ee/spec/services/ee/boards/lists/max_limits_spec.rb'
- - 'ee/spec/services/ee/ci/change_variable_service_spec.rb'
- - 'ee/spec/services/ee/ci/change_variables_service_spec.rb'
- - 'ee/spec/services/ee/ci/job_artifacts/create_service_spec.rb'
- - 'ee/spec/services/ee/ci/job_artifacts/destroy_all_expired_service_spec.rb'
- - 'ee/spec/services/ee/ci/job_artifacts/destroy_batch_service_spec.rb'
- - 'ee/spec/services/ee/ci/pipeline_processing/atomic_processing_service_spec.rb'
- - 'ee/spec/services/ee/commits/create_service_spec.rb'
- - 'ee/spec/services/ee/deployments/update_environment_service_spec.rb'
- - 'ee/spec/services/ee/design_management/delete_designs_service_spec.rb'
- - 'ee/spec/services/ee/design_management/save_designs_service_spec.rb'
- - 'ee/spec/services/ee/event_create_service_spec.rb'
- - 'ee/spec/services/ee/git/branch_push_service_spec.rb'
- - 'ee/spec/services/ee/git/wiki_push_service_spec.rb'
- - 'ee/spec/services/ee/gpg_keys/create_service_spec.rb'
- - 'ee/spec/services/ee/gpg_keys/destroy_service_spec.rb'
- - 'ee/spec/services/ee/groups/autocomplete_service_spec.rb'
- - 'ee/spec/services/ee/groups/deploy_tokens/create_service_spec.rb'
- - 'ee/spec/services/ee/groups/deploy_tokens/destroy_service_spec.rb'
- - 'ee/spec/services/ee/groups/deploy_tokens/revoke_service_spec.rb'
- - 'ee/spec/services/ee/groups/import_export/export_service_spec.rb'
- - 'ee/spec/services/ee/groups/import_export/import_service_spec.rb'
- - 'ee/spec/services/ee/incident_management/issuable_escalation_statuses/after_update_service_spec.rb'
- - 'ee/spec/services/ee/incident_management/issuable_escalation_statuses/create_service_spec.rb'
- - 'ee/spec/services/ee/incident_management/issuable_escalation_statuses/prepare_update_service_spec.rb'
- - 'ee/spec/services/ee/integrations/test/project_service_spec.rb'
- - 'ee/spec/services/ee/ip_restrictions/update_service_spec.rb'
- - 'ee/spec/services/ee/issuable/bulk_update_service_spec.rb'
- - 'ee/spec/services/ee/issuable/common_system_notes_service_spec.rb'
- - 'ee/spec/services/ee/issuable/destroy_service_spec.rb'
- - 'ee/spec/services/ee/issue_links/create_service_spec.rb'
- - 'ee/spec/services/ee/issues/after_create_service_spec.rb'
- - 'ee/spec/services/ee/issues/clone_service_spec.rb'
- - 'ee/spec/services/ee/issues/move_service_spec.rb'
- - 'ee/spec/services/ee/keys/destroy_service_spec.rb'
- - 'ee/spec/services/ee/labels/create_service_spec.rb'
- - 'ee/spec/services/ee/labels/promote_service_spec.rb'
- - 'ee/spec/services/ee/members/create_service_spec.rb'
- - 'ee/spec/services/ee/members/destroy_service_spec.rb'
- - 'ee/spec/services/ee/members/import_project_team_service_spec.rb'
- - 'ee/spec/services/ee/members/invite_service_spec.rb'
- - 'ee/spec/services/ee/members/update_service_spec.rb'
- - 'ee/spec/services/ee/merge_request_metrics_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/base_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/create_approval_event_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/create_from_vulnerability_data_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/create_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/execute_approval_hooks_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/handle_assignees_change_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/post_merge_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/namespace_settings/update_service_spec.rb'
- 'ee/spec/services/ee/notes/destroy_service_spec.rb'
- 'ee/spec/services/ee/notes/post_process_service_spec.rb'
- 'ee/spec/services/ee/notes/quick_actions_service_spec.rb'
- 'ee/spec/services/ee/notes/update_service_spec.rb'
- - 'ee/spec/services/ee/null_notification_service_spec.rb'
- - 'ee/spec/services/ee/personal_access_tokens/revoke_service_spec.rb'
- - 'ee/spec/services/ee/post_receive_service_spec.rb'
- - 'ee/spec/services/ee/preview_markdown_service_spec.rb'
- - 'ee/spec/services/ee/projects/autocomplete_service_spec.rb'
- - 'ee/spec/services/ee/projects/deploy_tokens/create_service_spec.rb'
- - 'ee/spec/services/ee/projects/deploy_tokens/destroy_service_spec.rb'
- - 'ee/spec/services/ee/projects/unlink_fork_service_spec.rb'
- - 'ee/spec/services/ee/protected_branches/update_service_spec.rb'
- - 'ee/spec/services/ee/quick_actions/target_service_spec.rb'
- - 'ee/spec/services/ee/releases/create_evidence_service_spec.rb'
- - 'ee/spec/services/ee/resource_events/change_iteration_service_spec.rb'
- - 'ee/spec/services/ee/resource_events/change_labels_service_spec.rb'
- - 'ee/spec/services/ee/resource_events/merge_into_notes_service_spec.rb'
- - 'ee/spec/services/ee/resource_events/synthetic_iteration_notes_builder_service_spec.rb'
- - 'ee/spec/services/ee/resource_events/synthetic_weight_notes_builder_service_spec.rb'
- - 'ee/spec/services/ee/system_notes/issuables_service_spec.rb'
- - 'ee/spec/services/ee/terraform/states/destroy_service_spec.rb'
- - 'ee/spec/services/ee/todos/destroy/entity_leave_service_spec.rb'
- - 'ee/spec/services/ee/users/approve_service_spec.rb'
- - 'ee/spec/services/ee/users/authorized_build_service_spec.rb'
- - 'ee/spec/services/ee/users/block_service_spec.rb'
- - 'ee/spec/services/ee/users/build_service_spec.rb'
- - 'ee/spec/services/ee/users/create_service_spec.rb'
- - 'ee/spec/services/ee/users/destroy_service_spec.rb'
- - 'ee/spec/services/ee/users/migrate_records_to_ghost_user_service_spec.rb'
- - 'ee/spec/services/ee/users/reject_service_spec.rb'
- - 'ee/spec/services/ee/users/update_service_spec.rb'
- - 'ee/spec/services/ee/vulnerability_feedback_module/update_service_spec.rb'
- - 'ee/spec/services/elastic/cluster_reindexing_service_spec.rb'
- - 'ee/spec/services/elastic/data_migration_service_spec.rb'
- - 'ee/spec/services/elastic/index_projects_by_id_service_spec.rb'
- - 'ee/spec/services/elastic/index_projects_by_range_service_spec.rb'
- - 'ee/spec/services/elastic/index_projects_service_spec.rb'
- - 'ee/spec/services/elastic/indexing_control_service_spec.rb'
- - 'ee/spec/services/elastic/metrics_update_service_spec.rb'
- - 'ee/spec/services/elastic/process_initial_bookkeeping_service_spec.rb'
- - 'ee/spec/services/emails/create_service_spec.rb'
- - 'ee/spec/services/emails/destroy_service_spec.rb'
- - 'ee/spec/services/epic_issues/destroy_service_spec.rb'
- - 'ee/spec/services/epic_issues/list_service_spec.rb'
- - 'ee/spec/services/epic_issues/update_service_spec.rb'
- - 'ee/spec/services/epics/close_service_spec.rb'
- - 'ee/spec/services/epics/create_service_spec.rb'
- - 'ee/spec/services/epics/descendant_count_service_spec.rb'
- - 'ee/spec/services/epics/epic_links/list_service_spec.rb'
- - 'ee/spec/services/epics/issue_promote_service_spec.rb'
- - 'ee/spec/services/epics/reopen_service_spec.rb'
- - 'ee/spec/services/epics/transfer_service_spec.rb'
- - 'ee/spec/services/epics/update_dates_service_spec.rb'
- - 'ee/spec/services/epics/update_service_spec.rb'
- 'ee/spec/services/external_status_checks/create_service_spec.rb'
- - 'ee/spec/services/external_status_checks/destroy_service_spec.rb'
- - 'ee/spec/services/external_status_checks/dispatch_service_spec.rb'
- - 'ee/spec/services/external_status_checks/update_service_spec.rb'
- - 'ee/spec/services/feature_flag_issues/destroy_service_spec.rb'
- - 'ee/spec/services/geo/base_file_service_spec.rb'
- - 'ee/spec/services/geo/blob_download_service_spec.rb'
- - 'ee/spec/services/geo/blob_upload_service_spec.rb'
- - 'ee/spec/services/geo/cache_invalidation_event_store_spec.rb'
- - 'ee/spec/services/geo/container_repository_registry_removal_service_spec.rb'
- - 'ee/spec/services/geo/container_repository_sync_service_spec.rb'
- - 'ee/spec/services/geo/container_repository_sync_spec.rb'
- - 'ee/spec/services/geo/event_service_spec.rb'
- - 'ee/spec/services/geo/file_registry_removal_service_spec.rb'
- - 'ee/spec/services/geo/files_expire_service_spec.rb'
- - 'ee/spec/services/geo/framework_repository_sync_service_spec.rb'
- - 'ee/spec/services/geo/graphql_request_service_spec.rb'
- - 'ee/spec/services/geo/hashed_storage_attachments_event_store_spec.rb'
- - 'ee/spec/services/geo/hashed_storage_attachments_migration_service_spec.rb'
- - 'ee/spec/services/geo/hashed_storage_migrated_event_store_spec.rb'
- - 'ee/spec/services/geo/hashed_storage_migration_service_spec.rb'
- - 'ee/spec/services/geo/metrics_update_service_spec.rb'
- - 'ee/spec/services/geo/move_repository_service_spec.rb'
- - 'ee/spec/services/geo/node_create_service_spec.rb'
- - 'ee/spec/services/geo/node_status_request_service_spec.rb'
- - 'ee/spec/services/geo/node_update_service_spec.rb'
- - 'ee/spec/services/geo/project_housekeeping_service_spec.rb'
- - 'ee/spec/services/geo/prune_event_log_service_spec.rb'
- - 'ee/spec/services/geo/rename_repository_service_spec.rb'
- - 'ee/spec/services/geo/replication_toggle_request_service_spec.rb'
- - 'ee/spec/services/geo/repositories_changed_event_store_spec.rb'
- - 'ee/spec/services/geo/repository_base_sync_service_spec.rb'
- - 'ee/spec/services/geo/repository_created_event_store_spec.rb'
- - 'ee/spec/services/geo/repository_deleted_event_store_spec.rb'
- - 'ee/spec/services/geo/repository_destroy_service_spec.rb'
- - 'ee/spec/services/geo/repository_registry_removal_service_spec.rb'
- - 'ee/spec/services/geo/repository_renamed_event_store_spec.rb'
- - 'ee/spec/services/geo/repository_updated_event_store_spec.rb'
- - 'ee/spec/services/geo/repository_updated_service_spec.rb'
- - 'ee/spec/services/geo/repository_verification_reset_spec.rb'
- - 'ee/spec/services/geo/reset_checksum_event_store_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_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/extend_reactivate_trial_service_spec.rb'
- - 'ee/spec/services/gitlab_subscriptions/fetch_purchase_eligible_namespaces_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/preview_billable_user_change_service_spec.rb'
- - 'ee/spec/services/gitlab_subscriptions/reconciliations/calculate_seat_count_data_service_spec.rb'
- - 'ee/spec/services/gitlab_subscriptions/reconciliations/check_seat_usage_alerts_eligibility_service_spec.rb'
- - 'ee/spec/services/gitlab_subscriptions/trials/apply_trial_service_spec.rb'
- - 'ee/spec/services/group_saml/group_managed_accounts/clean_up_members_service_spec.rb'
- - 'ee/spec/services/group_saml/group_managed_accounts/transfer_membership_service_spec.rb'
- - 'ee/spec/services/group_saml/identity/destroy_service_spec.rb'
- - 'ee/spec/services/group_saml/saml_group_links/create_service_spec.rb'
- - 'ee/spec/services/group_saml/saml_group_links/destroy_service_spec.rb'
- - 'ee/spec/services/group_saml/saml_provider/create_service_spec.rb'
- - 'ee/spec/services/group_saml/saml_provider/update_service_spec.rb'
- - 'ee/spec/services/group_saml/sign_up_service_spec.rb'
- - 'ee/spec/services/groups/create_service_spec.rb'
- - 'ee/spec/services/groups/epics_count_service_spec.rb'
- - 'ee/spec/services/groups/mark_for_deletion_service_spec.rb'
- - 'ee/spec/services/groups/memberships/export_service_spec.rb'
- - 'ee/spec/services/groups/participants_service_spec.rb'
- - 'ee/spec/services/groups/restore_service_spec.rb'
- - 'ee/spec/services/groups/schedule_bulk_repository_shard_moves_service_spec.rb'
- - 'ee/spec/services/groups/seat_usage_export_service_spec.rb'
- - 'ee/spec/services/groups/transfer_service_spec.rb'
- - 'ee/spec/services/groups/update_repository_storage_service_spec.rb'
- - 'ee/spec/services/groups/update_service_spec.rb'
- - 'ee/spec/services/historical_user_data/csv_service_spec.rb'
- - 'ee/spec/services/ide/schemas_config_service_spec.rb'
- - 'ee/spec/services/incident_management/create_incident_sla_exceeded_label_service_spec.rb'
- - 'ee/spec/services/incident_management/escalation_policies/create_service_spec.rb'
- - 'ee/spec/services/incident_management/escalation_policies/destroy_service_spec.rb'
- - 'ee/spec/services/incident_management/escalation_policies/update_service_spec.rb'
- - 'ee/spec/services/incident_management/escalation_rules/destroy_service_spec.rb'
- - 'ee/spec/services/incident_management/incidents/create_sla_service_spec.rb'
- - 'ee/spec/services/incident_management/incidents/upload_metric_service_spec.rb'
- - 'ee/spec/services/incident_management/issuable_resource_links/create_service_spec.rb'
- - 'ee/spec/services/incident_management/issuable_resource_links/destroy_service_spec.rb'
- - 'ee/spec/services/incident_management/issuable_resource_links/zoom_link_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_rotations/create_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_rotations/destroy_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_rotations/edit_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_rotations/remove_participant_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_rotations/remove_participants_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_schedules/create_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_schedules/destroy_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_schedules/update_service_spec.rb'
- - 'ee/spec/services/incident_management/oncall_shifts/read_service_spec.rb'
- - 'ee/spec/services/incident_management/pending_escalations/create_service_spec.rb'
- - 'ee/spec/services/incident_management/pending_escalations/process_service_spec.rb'
- - 'ee/spec/services/integrations/slack_event_service_spec.rb'
- - 'ee/spec/services/integrations/slack_events/app_home_opened_service_spec.rb'
- - 'ee/spec/services/integrations/slack_events/url_verification_service_spec.rb'
- - 'ee/spec/services/integrations/slack_interactions/incident_management/incident_modal_closed_service_spec.rb'
- - 'ee/spec/services/issuable/destroy_label_links_service_spec.rb'
- - 'ee/spec/services/issuable/discussions_list_service_spec.rb'
- - 'ee/spec/services/issue_feature_flags/list_service_spec.rb'
- - 'ee/spec/services/issues/build_service_spec.rb'
- - 'ee/spec/services/issues/duplicate_service_spec.rb'
- - 'ee/spec/services/iterations/cadences/create_iterations_in_advance_service_spec.rb'
- - 'ee/spec/services/iterations/cadences/create_service_spec.rb'
- - 'ee/spec/services/iterations/cadences/destroy_service_spec.rb'
- - 'ee/spec/services/iterations/cadences/update_service_spec.rb'
- - 'ee/spec/services/iterations/create_service_spec.rb'
- - 'ee/spec/services/iterations/delete_service_spec.rb'
- - 'ee/spec/services/iterations/update_service_spec.rb'
- - 'ee/spec/services/jira/jql_builder_service_spec.rb'
- - 'ee/spec/services/jira/requests/issues/list_service_spec.rb'
- - 'ee/spec/services/keys/create_service_spec.rb'
- - 'ee/spec/services/keys/last_used_service_spec.rb'
- - 'ee/spec/services/ldap_group_reset_service_spec.rb'
- - 'ee/spec/services/lfs/lock_file_service_spec.rb'
- - 'ee/spec/services/lfs/unlock_file_service_spec.rb'
- - 'ee/spec/services/licenses/destroy_service_spec.rb'
- - 'ee/spec/services/members/activate_service_spec.rb'
- - 'ee/spec/services/members/await_service_spec.rb'
- - 'ee/spec/services/merge_commits/export_csv_service_spec.rb'
- - 'ee/spec/services/merge_request_approval_settings/update_service_spec.rb'
- - 'ee/spec/services/merge_requests/approval_service_spec.rb'
- - 'ee/spec/services/merge_requests/build_service_spec.rb'
- - 'ee/spec/services/merge_requests/merge_service_spec.rb'
- - 'ee/spec/services/merge_requests/merge_to_ref_service_spec.rb'
- - 'ee/spec/services/merge_requests/mergeability/check_approved_service_spec.rb'
- - 'ee/spec/services/merge_requests/mergeability/check_blocked_by_other_mrs_service_spec.rb'
- - 'ee/spec/services/merge_requests/mergeability/check_denied_policies_service_spec.rb'
- - 'ee/spec/services/merge_requests/mergeability/check_external_status_checks_passed_service_spec.rb'
- - 'ee/spec/services/merge_requests/push_options_handler_service_spec.rb'
- - 'ee/spec/services/merge_requests/reload_merge_head_diff_service_spec.rb'
- - 'ee/spec/services/merge_requests/remove_approval_service_spec.rb'
- - 'ee/spec/services/merge_requests/stream_approval_audit_event_service_spec.rb'
- - 'ee/spec/services/merge_requests/sync_code_owner_approval_rules_spec.rb'
- - 'ee/spec/services/merge_requests/sync_report_approver_approval_rules_spec.rb'
- - 'ee/spec/services/merge_requests/update_blocks_service_spec.rb'
- - 'ee/spec/services/merge_trains/check_status_service_spec.rb'
- - 'ee/spec/services/merge_trains/refresh_merge_request_service_spec.rb'
- - 'ee/spec/services/merge_trains/refresh_service_spec.rb'
- - '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'
- - 'ee/spec/services/personal_access_tokens/create_service_audit_log_spec.rb'
- - 'ee/spec/services/personal_access_tokens/groups/update_lifetime_service_spec.rb'
- - 'ee/spec/services/personal_access_tokens/instance/update_lifetime_service_spec.rb'
- - 'ee/spec/services/personal_access_tokens/revoke_invalid_tokens_spec.rb'
- - 'ee/spec/services/personal_access_tokens/revoke_service_audit_log_spec.rb'
- - 'ee/spec/services/personal_access_tokens/rotation_verifier_service_spec.rb'
- - 'ee/spec/services/phone_verification/telesign_client/base_service_spec.rb'
- - 'ee/spec/services/phone_verification/telesign_client/risk_score_service_spec.rb'
- - 'ee/spec/services/phone_verification/telesign_client/send_verification_code_service_spec.rb'
- - 'ee/spec/services/phone_verification/telesign_client/verify_code_service_spec.rb'
- - 'ee/spec/services/phone_verification/users/send_verification_code_service_spec.rb'
- - 'ee/spec/services/product_analytics/initialize_stack_service_spec.rb'
- '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'
@@ -2135,102 +1737,7 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/requirements_management/process_test_reports_service_spec.rb'
- 'ee/spec/services/resource_access_tokens/create_service_spec.rb'
- 'ee/spec/services/resource_access_tokens/revoke_service_spec.rb'
- - 'ee/spec/services/search/snippet_service_spec.rb'
- - 'ee/spec/services/security/auto_fix_label_service_spec.rb'
- - 'ee/spec/services/security/auto_fix_service_spec.rb'
- - 'ee/spec/services/security/configuration/save_auto_fix_service_spec.rb'
- - 'ee/spec/services/security/dependency_list_service_spec.rb'
- - 'ee/spec/services/security/findings/dismiss_service_spec.rb'
- - 'ee/spec/services/security/ingestion/finding_map_collection_spec.rb'
- - 'ee/spec/services/security/ingestion/finding_map_spec.rb'
- - 'ee/spec/services/security/ingestion/ingest_report_service_spec.rb'
- - 'ee/spec/services/security/ingestion/ingest_report_slice_service_spec.rb'
- - 'ee/spec/services/security/ingestion/ingest_reports_service_spec.rb'
- - 'ee/spec/services/security/ingestion/mark_as_resolved_service_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/hooks_execution_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/ingest_finding_evidence_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/ingest_identifiers_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/ingest_remediations_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/ingest_vulnerabilities/mark_resolved_as_detected_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/ingest_vulnerabilities_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/ingest_vulnerability_statistics_spec.rb'
- - 'ee/spec/services/security/ingestion/tasks/update_vulnerability_uuids_spec.rb'
- - 'ee/spec/services/security/merge_reports_service_spec.rb'
- - 'ee/spec/services/security/orchestration/assign_service_spec.rb'
- - 'ee/spec/services/security/orchestration/unassign_service_spec.rb'
- - 'ee/spec/services/security/override_uuids_service_spec.rb'
- - 'ee/spec/services/security/purge_scans_service_spec.rb'
- - 'ee/spec/services/security/report_fetch_service_spec.rb'
- - 'ee/spec/services/security/report_summary_service_spec.rb'
- - 'ee/spec/services/security/scanned_resources_counting_service_spec.rb'
- - 'ee/spec/services/security/scanned_resources_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/fetch_policy_approvers_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/fetch_policy_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/on_demand_scan_pipeline_configuration_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/operational_vulnerabilities_configuration_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/policy_configuration_validation_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/process_policy_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/process_rule_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/project_create_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/rule_schedule_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/sync_open_merge_requests_head_pipeline_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/sync_opened_merge_requests_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/sync_scan_result_policies_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/validate_policy_service_spec.rb'
- - 'ee/spec/services/security/store_findings_service_spec.rb'
- - 'ee/spec/services/security/store_grouped_scans_service_spec.rb'
- - 'ee/spec/services/security/store_scan_service_spec.rb'
- - 'ee/spec/services/security/store_scans_service_spec.rb'
- - 'ee/spec/services/security/token_revocation_service_spec.rb'
- - 'ee/spec/services/security/track_scan_service_spec.rb'
- - 'ee/spec/services/security/update_training_service_spec.rb'
- - 'ee/spec/services/security/vulnerability_counting_service_spec.rb'
- - 'ee/spec/services/sitemap/create_service_spec.rb'
- - 'ee/spec/services/slash_commands/global_slack_handler_spec.rb'
- - 'ee/spec/services/software_license_policies/update_service_spec.rb'
- - 'ee/spec/services/start_pull_mirroring_service_spec.rb'
- - 'ee/spec/services/status_page/mark_for_publication_service_spec.rb'
- - 'ee/spec/services/status_page/publish_attachments_service_spec.rb'
- - 'ee/spec/services/status_page/publish_details_service_spec.rb'
- - 'ee/spec/services/status_page/publish_list_service_spec.rb'
- - 'ee/spec/services/status_page/publish_service_spec.rb'
- - 'ee/spec/services/status_page/trigger_publish_service_spec.rb'
- - 'ee/spec/services/status_page/unpublish_details_service_spec.rb'
- - 'ee/spec/services/system_note_service_spec.rb'
- - 'ee/spec/services/system_notes/epics_service_spec.rb'
- - 'ee/spec/services/system_notes/escalations_service_spec.rb'
- - 'ee/spec/services/system_notes/merge_train_service_spec.rb'
- - 'ee/spec/services/system_notes/vulnerabilities_service_spec.rb'
- 'ee/spec/services/timebox_report_service_spec.rb'
- - 'ee/spec/services/todo_service_spec.rb'
- - 'ee/spec/services/todos/allowed_target_filter_service_spec.rb'
- - 'ee/spec/services/todos/destroy/confidential_epic_service_spec.rb'
- - 'ee/spec/services/upcoming_reconciliations/update_service_spec.rb'
- - 'ee/spec/services/user_permissions/export_service_spec.rb'
- - 'ee/spec/services/users/abuse/namespace_bans/create_service_spec.rb'
- - 'ee/spec/services/users/abuse/namespace_bans/destroy_service_spec.rb'
- - 'ee/spec/services/users/abuse/projects_download_ban_check_service_spec.rb'
- - 'ee/spec/services/users/captcha_challenge_service_spec.rb'
- - 'ee/spec/services/users/update_highest_member_role_service_spec.rb'
- - 'ee/spec/services/users_ops_dashboard_projects/destroy_service_spec.rb'
- - 'ee/spec/services/vulnerability_exports/create_service_spec.rb'
- - 'ee/spec/services/vulnerability_exports/export_service_spec.rb'
- - 'ee/spec/services/vulnerability_exports/exporters/csv_service_spec.rb'
- - 'ee/spec/services/vulnerability_external_issue_links/create_service_spec.rb'
- - 'ee/spec/services/vulnerability_external_issue_links/destroy_service_spec.rb'
- - 'ee/spec/services/vulnerability_feedback/destroy_service_spec.rb'
- - 'ee/spec/services/vulnerability_issue_links/create_service_spec.rb'
- - 'ee/spec/services/vulnerability_issue_links/delete_service_spec.rb'
- - 'ee/spec/services/vulnerability_merge_request_links/create_service_spec.rb'
- - 'ee/spec/services/vulnerability_scanners/list_service_spec.rb'
- - 'ee/spec/services/web_hook_service_spec.rb'
- - 'ee/spec/services/wiki_pages/create_service_spec.rb'
- - 'ee/spec/services/wiki_pages/destroy_service_spec.rb'
- - 'ee/spec/services/wiki_pages/update_service_spec.rb'
- - 'ee/spec/services/wikis/create_attachment_service_spec.rb'
- - 'ee/spec/services/work_items/update_service_spec.rb'
- - 'ee/spec/services/work_items/widgets/status_service/update_service_spec.rb'
- - 'ee/spec/services/work_items/widgets/weight_service/update_service_spec.rb'
- 'ee/spec/tasks/geo/git_rake_spec.rb'
- 'ee/spec/tasks/gitlab/license_rake_spec.rb'
- 'ee/spec/tasks/gitlab/spdx_rake_spec.rb'
@@ -2255,8 +1762,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/views/compliance_management/compliance_framework/_project_settings.html.haml_spec.rb'
- 'ee/spec/views/devise/sessions/new.html.haml_spec.rb'
- 'ee/spec/views/groups/_compliance_frameworks.html.haml_spec.rb'
- - 'ee/spec/views/groups/analytics/dashboards/index.html.haml_spec.rb'
- - 'ee/spec/views/groups/billings/index.html.haml_spec.rb'
- 'ee/spec/views/groups/compliance_frameworks/edit.html.haml_spec.rb'
- 'ee/spec/views/groups/compliance_frameworks/new.html.haml_spec.rb'
- 'ee/spec/views/groups/edit.html.haml_spec.rb'
@@ -2284,7 +1789,6 @@ RSpec/MissingFeatureCategory:
- '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/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'
- 'ee/spec/views/projects/security/dast_scanner_profiles/edit.html.haml_spec.rb'
@@ -2327,160 +1831,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/views/subscriptions/groups/edit.html.haml_spec.rb'
- 'ee/spec/views/subscriptions/new.html.haml_spec.rb'
- 'ee/spec/views/trial_registrations/new.html.haml_spec.rb'
- - 'ee/spec/workers/active_user_count_threshold_worker_spec.rb'
- - 'ee/spec/workers/adjourned_group_deletion_worker_spec.rb'
- - 'ee/spec/workers/adjourned_project_deletion_worker_spec.rb'
- - 'ee/spec/workers/adjourned_projects_deletion_cron_worker_spec.rb'
- - 'ee/spec/workers/admin_emails_worker_spec.rb'
- - 'ee/spec/workers/analytics/code_review_metrics_worker_spec.rb'
- - 'ee/spec/workers/analytics/cycle_analytics/consistency_worker_spec.rb'
- - 'ee/spec/workers/analytics/cycle_analytics/incremental_worker_spec.rb'
- - 'ee/spec/workers/analytics/cycle_analytics/reaggregation_worker_spec.rb'
- - 'ee/spec/workers/analytics/devops_adoption/create_all_snapshots_worker_spec.rb'
- - 'ee/spec/workers/analytics/devops_adoption/create_snapshot_worker_spec.rb'
- - 'ee/spec/workers/app_sec/dast/scanner_profiles_builds/consistency_worker_spec.rb'
- - 'ee/spec/workers/app_sec/dast/scans/consistency_worker_spec.rb'
- - 'ee/spec/workers/app_sec/dast/site_profiles_builds/consistency_worker_spec.rb'
- - 'ee/spec/workers/approval_rules/external_approval_rule_payload_worker_spec.rb'
- - 'ee/spec/workers/audit_events/user_impersonation_event_create_worker_spec.rb'
- - 'ee/spec/workers/auth/saml_group_sync_worker_spec.rb'
- - 'ee/spec/workers/ci/batch_reset_minutes_worker_spec.rb'
- - 'ee/spec/workers/ci/initial_pipeline_process_worker_spec.rb'
- - 'ee/spec/workers/ci/minutes/refresh_cached_data_worker_spec.rb'
- - 'ee/spec/workers/ci/minutes/update_project_and_namespace_usage_worker_spec.rb'
- - 'ee/spec/workers/ci/runners/stale_group_runners_prune_cron_worker_spec.rb'
- - 'ee/spec/workers/ci/sync_reports_to_report_approval_rules_worker_spec.rb'
- - 'ee/spec/workers/ci/trigger_downstream_subscriptions_worker_spec.rb'
- - 'ee/spec/workers/ci/upstream_projects_subscriptions_cleanup_worker_spec.rb'
- - 'ee/spec/workers/clear_shared_runners_minutes_worker_spec.rb'
- - 'ee/spec/workers/compliance_management/chain_of_custody_report_worker_spec.rb'
- - 'ee/spec/workers/compliance_management/merge_requests/compliance_violations_worker_spec.rb'
- - 'ee/spec/workers/compliance_management/update_default_framework_worker_spec.rb'
- - 'ee/spec/workers/concerns/elastic/indexing_control_spec.rb'
- - 'ee/spec/workers/concerns/elastic/migration_obsolete_spec.rb'
- - 'ee/spec/workers/concerns/elastic/migration_options_spec.rb'
- - 'ee/spec/workers/concerns/geo_queue_spec.rb'
- - 'ee/spec/workers/concerns/update_orchestration_policy_configuration_spec.rb'
- - 'ee/spec/workers/create_github_webhook_worker_spec.rb'
- - 'ee/spec/workers/deployments/auto_rollback_worker_spec.rb'
- - 'ee/spec/workers/dora/daily_metrics/refresh_worker_spec.rb'
- - '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'
- - 'ee/spec/workers/ee/repository_check/single_repository_worker_spec.rb'
- - 'ee/spec/workers/elastic/migration_worker_spec.rb'
- - 'ee/spec/workers/elastic/project_transfer_worker_spec.rb'
- - 'ee/spec/workers/elastic_association_indexer_worker_spec.rb'
- - 'ee/spec/workers/elastic_cluster_reindexing_cron_worker_spec.rb'
- - 'ee/spec/workers/elastic_full_index_worker_spec.rb'
- - 'ee/spec/workers/elastic_index_initial_bulk_cron_worker_spec.rb'
- - 'ee/spec/workers/elastic_indexing_control_worker_spec.rb'
- - 'ee/spec/workers/elastic_namespace_indexer_worker_spec.rb'
- - 'ee/spec/workers/elastic_namespace_rollout_worker_spec.rb'
- - 'ee/spec/workers/elastic_remove_expired_namespace_subscriptions_from_index_cron_worker_spec.rb'
- - 'ee/spec/workers/epics/new_epic_issue_worker_spec.rb'
- - 'ee/spec/workers/epics/update_cached_metadata_worker_spec.rb'
- - 'ee/spec/workers/geo/batch/project_registry_scheduler_worker_spec.rb'
- - 'ee/spec/workers/geo/batch/project_registry_worker_spec.rb'
- - 'ee/spec/workers/geo/batch_event_create_worker_spec.rb'
- - 'ee/spec/workers/geo/container_repository_sync_worker_spec.rb'
- - 'ee/spec/workers/geo/create_repository_updated_event_worker_spec.rb'
- - 'ee/spec/workers/geo/design_repository_shard_sync_worker_spec.rb'
- - 'ee/spec/workers/geo/design_repository_sync_worker_spec.rb'
- - 'ee/spec/workers/geo/destroy_worker_spec.rb'
- - 'ee/spec/workers/geo/event_worker_spec.rb'
- - 'ee/spec/workers/geo/file_registry_removal_worker_spec.rb'
- - 'ee/spec/workers/geo/metrics_update_worker_spec.rb'
- - 'ee/spec/workers/geo/prune_event_log_worker_spec.rb'
- - 'ee/spec/workers/geo/repositories_clean_up_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_cleanup_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_shard_sync_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_sync_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_verification/primary/batch_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_verification/primary/shard_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_verification/primary/single_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_verification/secondary/scheduler_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_verification/secondary/shard_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_verification/secondary/single_worker_spec.rb'
- - 'ee/spec/workers/geo/reverification_batch_worker_spec.rb'
- - 'ee/spec/workers/geo/scheduler/per_shard_scheduler_worker_spec.rb'
- - 'ee/spec/workers/geo/scheduler/scheduler_worker_spec.rb'
- - 'ee/spec/workers/geo/secondary_usage_data_cron_worker_spec.rb'
- - 'ee/spec/workers/geo/sidekiq_cron_config_worker_spec.rb'
- - 'ee/spec/workers/geo/sync_timeout_cron_worker_spec.rb'
- - 'ee/spec/workers/geo/verification_batch_worker_spec.rb'
- - 'ee/spec/workers/geo/verification_cron_worker_spec.rb'
- - 'ee/spec/workers/geo/verification_state_backfill_service_spec.rb'
- - 'ee/spec/workers/geo/verification_state_backfill_worker_spec.rb'
- - 'ee/spec/workers/geo/verification_worker_spec.rb'
- - 'ee/spec/workers/geo_repository_destroy_worker_spec.rb'
- - 'ee/spec/workers/gitlab_subscriptions/trials/apply_trial_worker_spec.rb'
- - 'ee/spec/workers/group_saml_group_sync_worker_spec.rb'
- - 'ee/spec/workers/groups/create_event_worker_spec.rb'
- - 'ee/spec/workers/groups/export_memberships_worker_spec.rb'
- - 'ee/spec/workers/groups/schedule_bulk_repository_shard_moves_worker_spec.rb'
- - 'ee/spec/workers/groups/update_repository_storage_worker_spec.rb'
- - 'ee/spec/workers/historical_data_worker_spec.rb'
- - 'ee/spec/workers/import_software_licenses_worker_spec.rb'
- - 'ee/spec/workers/incident_management/apply_incident_sla_exceeded_label_worker_spec.rb'
- - 'ee/spec/workers/incident_management/incident_sla_exceeded_check_worker_spec.rb'
- - 'ee/spec/workers/incident_management/oncall_rotations/persist_all_rotations_shifts_job_spec.rb'
- - 'ee/spec/workers/incident_management/oncall_rotations/persist_shifts_job_spec.rb'
- - 'ee/spec/workers/incident_management/pending_escalations/alert_check_worker_spec.rb'
- - 'ee/spec/workers/incident_management/pending_escalations/alert_create_worker_spec.rb'
- - 'ee/spec/workers/incident_management/pending_escalations/issue_check_worker_spec.rb'
- - 'ee/spec/workers/incident_management/pending_escalations/issue_create_worker_spec.rb'
- - 'ee/spec/workers/incident_management/pending_escalations/schedule_check_cron_worker_spec.rb'
- - 'ee/spec/workers/integrations/slack_event_worker_spec.rb'
- - 'ee/spec/workers/iterations/cadences/create_iterations_worker_spec.rb'
- - 'ee/spec/workers/iterations/cadences/schedule_create_iterations_worker_spec.rb'
- - 'ee/spec/workers/iterations/roll_over_issues_worker_spec.rb'
- - 'ee/spec/workers/iterations_update_status_worker_spec.rb'
- - 'ee/spec/workers/ldap_all_groups_sync_worker_spec.rb'
- - 'ee/spec/workers/ldap_group_sync_worker_spec.rb'
- - 'ee/spec/workers/ldap_sync_worker_spec.rb'
- - 'ee/spec/workers/licenses/reset_submit_license_usage_data_banner_worker_spec.rb'
- - 'ee/spec/workers/merge_request_reset_approvals_worker_spec.rb'
- - 'ee/spec/workers/merge_requests/stream_approval_audit_event_worker_spec.rb'
- - 'ee/spec/workers/merge_requests/sync_code_owner_approval_rules_worker_spec.rb'
- - 'ee/spec/workers/merge_trains/refresh_worker_spec.rb'
- - 'ee/spec/workers/namespaces/sync_namespace_name_worker_spec.rb'
- - 'ee/spec/workers/new_epic_worker_spec.rb'
- - 'ee/spec/workers/personal_access_tokens/groups/policy_worker_spec.rb'
- - 'ee/spec/workers/personal_access_tokens/instance/policy_worker_spec.rb'
- - 'ee/spec/workers/post_receive_spec.rb'
- - 'ee/spec/workers/product_analytics/initialize_analytics_worker_spec.rb'
- - 'ee/spec/workers/project_cache_worker_spec.rb'
- - 'ee/spec/workers/project_template_export_worker_spec.rb'
- - 'ee/spec/workers/projects/disable_legacy_open_source_license_for_inactive_projects_worker_spec.rb'
- - 'ee/spec/workers/repository_update_mirror_worker_spec.rb'
- - 'ee/spec/workers/requirements_management/import_requirements_csv_worker_spec.rb'
- - 'ee/spec/workers/requirements_management/process_requirements_reports_worker_spec.rb'
- - 'ee/spec/workers/scan_security_report_secrets_worker_spec.rb'
- - 'ee/spec/workers/security/auto_fix_worker_spec.rb'
- - 'ee/spec/workers/security/create_orchestration_policy_worker_spec.rb'
- - 'ee/spec/workers/security/orchestration_policy_rule_schedule_namespace_worker_spec.rb'
- - 'ee/spec/workers/security/orchestration_policy_rule_schedule_worker_spec.rb'
- - 'ee/spec/workers/security/process_scan_result_policy_worker_spec.rb'
- - 'ee/spec/workers/security/scans/purge_by_job_id_worker_spec.rb'
- - 'ee/spec/workers/security/scans/purge_worker_spec.rb'
- - 'ee/spec/workers/security/store_scans_worker_spec.rb'
- - 'ee/spec/workers/security/sync_scan_policies_worker_spec.rb'
- - 'ee/spec/workers/security/track_secure_scans_worker_spec.rb'
- - 'ee/spec/workers/set_user_status_based_on_user_cap_setting_worker_spec.rb'
- - 'ee/spec/workers/status_page/publish_worker_spec.rb'
- - 'ee/spec/workers/store_security_reports_worker_spec.rb'
- - 'ee/spec/workers/sync_seat_link_request_worker_spec.rb'
- - 'ee/spec/workers/sync_seat_link_worker_spec.rb'
- - 'ee/spec/workers/todos_destroyer/confidential_epic_worker_spec.rb'
- - 'ee/spec/workers/update_all_mirrors_worker_spec.rb'
- - 'ee/spec/workers/update_max_seats_used_for_gitlab_com_subscriptions_worker_spec.rb'
- - 'ee/spec/workers/vulnerability_exports/export_deletion_worker_spec.rb'
- - 'ee/spec/workers/vulnerability_exports/export_worker_spec.rb'
- 'spec/benchmarks/banzai_benchmark.rb'
- 'spec/bin/audit_event_type_spec.rb'
- 'spec/bin/diagnostic_reports_uploader_spec.rb'
@@ -2489,7 +1839,6 @@ RSpec/MissingFeatureCategory:
- 'spec/channels/awareness_channel_spec.rb'
- 'spec/commands/diagnostic_reports/uploader_smoke_spec.rb'
- 'spec/commands/metrics_server/metrics_server_spec.rb'
- - 'spec/commands/sidekiq_cluster/cli_spec.rb'
- 'spec/components/diffs/overflow_warning_component_spec.rb'
- 'spec/components/diffs/stats_component_spec.rb'
- 'spec/components/layouts/horizontal_section_component_spec.rb'
@@ -2527,12 +1876,10 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/admin/plan_limits_controller_spec.rb'
- 'spec/controllers/admin/projects_controller_spec.rb'
- 'spec/controllers/admin/sessions_controller_spec.rb'
- - 'spec/controllers/admin/spam_logs_controller_spec.rb'
- 'spec/controllers/admin/topics/avatars_controller_spec.rb'
- 'spec/controllers/admin/topics_controller_spec.rb'
- 'spec/controllers/admin/usage_trends_controller_spec.rb'
- 'spec/controllers/admin/users_controller_spec.rb'
- - 'spec/controllers/application_controller_spec.rb'
- 'spec/controllers/autocomplete_controller_spec.rb'
- 'spec/controllers/chaos_controller_spec.rb'
- 'spec/controllers/concerns/check_rate_limit_spec.rb'
@@ -2566,7 +1913,6 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support_spec.rb'
- 'spec/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support_spec.rb'
- 'spec/controllers/concerns/static_object_external_storage_spec.rb'
- - 'spec/controllers/confirmations_controller_spec.rb'
- 'spec/controllers/dashboard/groups_controller_spec.rb'
- 'spec/controllers/dashboard/labels_controller_spec.rb'
- 'spec/controllers/dashboard/milestones_controller_spec.rb'
@@ -2615,10 +1961,8 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/oauth/applications_controller_spec.rb'
- 'spec/controllers/oauth/authorizations_controller_spec.rb'
- 'spec/controllers/oauth/authorized_applications_controller_spec.rb'
- - 'spec/controllers/oauth/jira_dvcs/authorizations_controller_spec.rb'
- 'spec/controllers/oauth/token_info_controller_spec.rb'
- 'spec/controllers/oauth/tokens_controller_spec.rb'
- - 'spec/controllers/omniauth_callbacks_controller_spec.rb'
- 'spec/controllers/passwords_controller_spec.rb'
- 'spec/controllers/profiles/accounts_controller_spec.rb'
- 'spec/controllers/profiles/active_sessions_controller_spec.rb'
@@ -2636,7 +1980,6 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/projects/analytics/cycle_analytics/stages_controller_spec.rb'
- 'spec/controllers/projects/analytics/cycle_analytics/summary_controller_spec.rb'
- 'spec/controllers/projects/analytics/cycle_analytics/value_streams_controller_spec.rb'
- - 'spec/controllers/projects/artifacts_controller_spec.rb'
- 'spec/controllers/projects/autocomplete_sources_controller_spec.rb'
- 'spec/controllers/projects/avatars_controller_spec.rb'
- 'spec/controllers/projects/badges_controller_spec.rb'
@@ -2646,7 +1989,6 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb'
- 'spec/controllers/projects/ci/lints_controller_spec.rb'
- 'spec/controllers/projects/ci/pipeline_editor_controller_spec.rb'
- - 'spec/controllers/projects/commit_controller_spec.rb'
- 'spec/controllers/projects/compare_controller_spec.rb'
- 'spec/controllers/projects/cycle_analytics/events_controller_spec.rb'
- 'spec/controllers/projects/cycle_analytics_controller_spec.rb'
@@ -2664,7 +2006,6 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/projects/feature_flags_user_lists_controller_spec.rb'
- 'spec/controllers/projects/find_file_controller_spec.rb'
- 'spec/controllers/projects/graphs_controller_spec.rb'
- - 'spec/controllers/projects/hooks_controller_spec.rb'
- 'spec/controllers/projects/import/jira_controller_spec.rb'
- 'spec/controllers/projects/imports_controller_spec.rb'
- 'spec/controllers/projects/incidents_controller_spec.rb'
@@ -2677,7 +2018,6 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/projects/mirrors_controller_spec.rb'
- 'spec/controllers/projects/packages/infrastructure_registry_controller_spec.rb'
- 'spec/controllers/projects/packages/packages_controller_spec.rb'
- - 'spec/controllers/projects/pages_controller_spec.rb'
- 'spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb'
- 'spec/controllers/projects/pipelines/stages_controller_spec.rb'
- 'spec/controllers/projects/pipelines/tests_controller_spec.rb'
@@ -2711,10 +2051,8 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/projects/web_ide_schemas_controller_spec.rb'
- 'spec/controllers/projects/web_ide_terminals_controller_spec.rb'
- 'spec/controllers/projects/wikis_controller_spec.rb'
- - 'spec/controllers/repositories/git_http_controller_spec.rb'
- 'spec/controllers/repositories/lfs_storage_controller_spec.rb'
- 'spec/controllers/root_controller_spec.rb'
- - 'spec/controllers/search_controller_spec.rb'
- 'spec/controllers/sent_notifications_controller_spec.rb'
- 'spec/controllers/sessions_controller_spec.rb'
- 'spec/controllers/snippets/blobs_controller_spec.rb'
@@ -2732,7 +2070,6 @@ RSpec/MissingFeatureCategory:
- 'spec/dependencies/omniauth_saml_spec.rb'
- 'spec/docs_screenshots/container_registry_docs.rb'
- 'spec/docs_screenshots/wiki_docs.rb'
- - 'spec/experiments/application_experiment_spec.rb'
- 'spec/experiments/concerns/project_commit_count_spec.rb'
- 'spec/experiments/force_company_trial_experiment_spec.rb'
- 'spec/experiments/in_product_guidance_environments_webide_experiment_spec.rb'
@@ -2741,7 +2078,6 @@ RSpec/MissingFeatureCategory:
- 'spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb'
- 'spec/features/admin/dashboard_spec.rb'
- 'spec/features/groups/integrations/group_integrations_spec.rb'
- - 'spec/features/markdown/observability_spec.rb'
- 'spec/features/milestones/user_views_milestones_spec.rb'
- 'spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb'
- 'spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb'
@@ -2878,7 +2214,6 @@ RSpec/MissingFeatureCategory:
- 'spec/finders/security/license_compliance_jobs_finder_spec.rb'
- 'spec/finders/security/security_jobs_finder_spec.rb'
- 'spec/finders/sentry_issue_finder_spec.rb'
- - 'spec/finders/serverless_domain_finder_spec.rb'
- 'spec/finders/snippets_finder_spec.rb'
- 'spec/finders/starred_projects_finder_spec.rb'
- 'spec/finders/tags_finder_spec.rb'
@@ -2935,7 +2270,6 @@ RSpec/MissingFeatureCategory:
- 'spec/frontend/fixtures/tags.rb'
- 'spec/frontend/fixtures/timezones.rb'
- 'spec/frontend/fixtures/todos.rb'
- - 'spec/frontend/fixtures/u2f.rb'
- 'spec/frontend/fixtures/webauthn.rb'
- 'spec/graphql/features/authorization_spec.rb'
- 'spec/graphql/gitlab_schema_spec.rb'
@@ -3011,9 +2345,6 @@ RSpec/MissingFeatureCategory:
- 'spec/graphql/mutations/namespace/package_settings/update_spec.rb'
- 'spec/graphql/mutations/notes/reposition_image_diff_note_spec.rb'
- 'spec/graphql/mutations/pages/mark_onboarding_complete_spec.rb'
- - 'spec/graphql/mutations/release_asset_links/create_spec.rb'
- - 'spec/graphql/mutations/release_asset_links/delete_spec.rb'
- - 'spec/graphql/mutations/release_asset_links/update_spec.rb'
- 'spec/graphql/mutations/releases/create_spec.rb'
- 'spec/graphql/mutations/releases/delete_spec.rb'
- 'spec/graphql/mutations/releases/update_spec.rb'
@@ -3095,7 +2426,6 @@ RSpec/MissingFeatureCategory:
- 'spec/graphql/resolvers/group_milestones_resolver_spec.rb'
- 'spec/graphql/resolvers/group_packages_resolver_spec.rb'
- 'spec/graphql/resolvers/group_resolver_spec.rb'
- - 'spec/graphql/resolvers/groups_resolver_spec.rb'
- 'spec/graphql/resolvers/incident_management/timeline_event_tags_resolver_spec.rb'
- 'spec/graphql/resolvers/incident_management/timeline_events_resolver_spec.rb'
- 'spec/graphql/resolvers/issue_status_counts_resolver_spec.rb'
@@ -3269,10 +2599,8 @@ RSpec/MissingFeatureCategory:
- 'spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb'
- 'spec/graphql/types/dependency_proxy/manifest_type_spec.rb'
- 'spec/graphql/types/deployment_tier_enum_spec.rb'
- - 'spec/graphql/types/design_management/design_at_version_type_spec.rb'
- 'spec/graphql/types/design_management/design_collection_copy_state_enum_spec.rb'
- 'spec/graphql/types/design_management/design_collection_type_spec.rb'
- - 'spec/graphql/types/design_management/design_type_spec.rb'
- 'spec/graphql/types/design_management/design_version_event_enum_spec.rb'
- 'spec/graphql/types/design_management/version_type_spec.rb'
- 'spec/graphql/types/design_management_type_spec.rb'
@@ -3452,7 +2780,6 @@ RSpec/MissingFeatureCategory:
- 'spec/helpers/admin/deploy_key_helper_spec.rb'
- 'spec/helpers/admin/identities_helper_spec.rb'
- 'spec/helpers/admin/user_actions_helper_spec.rb'
- - 'spec/helpers/analytics/cycle_analytics_helper_spec.rb'
- 'spec/helpers/appearances_helper_spec.rb'
- 'spec/helpers/application_helper_spec.rb'
- 'spec/helpers/application_settings_helper_spec.rb'
@@ -3467,7 +2794,6 @@ RSpec/MissingFeatureCategory:
- 'spec/helpers/boards_helper_spec.rb'
- 'spec/helpers/branches_helper_spec.rb'
- 'spec/helpers/breadcrumbs_helper_spec.rb'
- - 'spec/helpers/broadcast_messages_helper_spec.rb'
- 'spec/helpers/button_helper_spec.rb'
- 'spec/helpers/calendar_helper_spec.rb'
- 'spec/helpers/ci/builds_helper_spec.rb'
@@ -3534,7 +2860,6 @@ RSpec/MissingFeatureCategory:
- 'spec/helpers/numbers_helper_spec.rb'
- 'spec/helpers/one_trust_helper_spec.rb'
- 'spec/helpers/operations_helper_spec.rb'
- - 'spec/helpers/packages_helper_spec.rb'
- 'spec/helpers/page_layout_helper_spec.rb'
- 'spec/helpers/pagination_helper_spec.rb'
- 'spec/helpers/preferences_helper_spec.rb'
@@ -3708,7 +3033,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/api/validations/validators/limit_spec.rb'
- 'spec/lib/api/validations/validators/project_portable_spec.rb'
- 'spec/lib/api/validations/validators/untrusted_regexp_spec.rb'
- - 'spec/lib/atlassian/jira_issue_key_extractor_spec.rb'
- 'spec/lib/backup/database_backup_error_spec.rb'
- 'spec/lib/backup/file_backup_error_spec.rb'
- 'spec/lib/backup/files_spec.rb'
@@ -3722,7 +3046,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb'
- 'spec/lib/banzai/filter/inline_metrics_filter_spec.rb'
- 'spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb'
- - 'spec/lib/banzai/filter/inline_observability_filter_spec.rb'
- 'spec/lib/banzai/pipeline/incident_management/timeline_event_pipeline_spec.rb'
- 'spec/lib/bitbucket/collection_spec.rb'
- 'spec/lib/bitbucket/connection_spec.rb'
@@ -3756,7 +3079,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb'
- 'spec/lib/bulk_imports/common/transformers/prohibited_attributes_transformer_spec.rb'
- 'spec/lib/bulk_imports/common/transformers/user_reference_transformer_spec.rb'
- - 'spec/lib/bulk_imports/features_spec.rb'
- 'spec/lib/bulk_imports/file_downloads/filename_fetch_spec.rb'
- 'spec/lib/bulk_imports/file_downloads/validations_spec.rb'
- 'spec/lib/bulk_imports/groups/extractors/subgroups_extractor_spec.rb'
@@ -3768,7 +3090,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb'
- 'spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb'
- 'spec/lib/bulk_imports/groups/transformers/subgroup_to_entity_transformer_spec.rb'
- - 'spec/lib/bulk_imports/ndjson_pipeline_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'
@@ -3832,7 +3153,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/feature/gitaly_spec.rb'
- 'spec/lib/file_size_validator_spec.rb'
- 'spec/lib/forever_spec.rb'
- - 'spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb'
- 'spec/lib/generators/gitlab/usage_metric_definition/redis_hll_generator_spec.rb'
- 'spec/lib/generators/gitlab/usage_metric_definition_generator_spec.rb'
- 'spec/lib/generators/gitlab/usage_metric_generator_spec.rb'
@@ -3866,14 +3186,12 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb'
- 'spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb'
- 'spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb'
- - 'spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb'
- 'spec/lib/gitlab/analytics/date_filler_spec.rb'
- 'spec/lib/gitlab/analytics/usage_trends/workers_argument_builder_spec.rb'
- 'spec/lib/gitlab/anonymous_session_spec.rb'
- 'spec/lib/gitlab/api_authentication/builder_spec.rb'
- 'spec/lib/gitlab/api_authentication/sent_through_builder_spec.rb'
- 'spec/lib/gitlab/api_authentication/token_locator_spec.rb'
- - 'spec/lib/gitlab/api_authentication/token_resolver_spec.rb'
- 'spec/lib/gitlab/api_authentication/token_type_builder_spec.rb'
- 'spec/lib/gitlab/app_json_logger_spec.rb'
- 'spec/lib/gitlab/app_logger_spec.rb'
@@ -3886,7 +3204,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/asciidoc/html5_converter_spec.rb'
- 'spec/lib/gitlab/asciidoc/include_processor_spec.rb'
- 'spec/lib/gitlab/asset_proxy_spec.rb'
- - 'spec/lib/gitlab/audit/auditor_spec.rb'
- 'spec/lib/gitlab/audit/ci_runner_token_author_spec.rb'
- 'spec/lib/gitlab/audit/deploy_key_author_spec.rb'
- 'spec/lib/gitlab/audit/deploy_token_author_spec.rb'
@@ -3899,7 +3216,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/auth/atlassian/auth_hash_spec.rb'
- 'spec/lib/gitlab/auth/atlassian/identity_linker_spec.rb'
- 'spec/lib/gitlab/auth/atlassian/user_spec.rb'
- - 'spec/lib/gitlab/auth/auth_finders_spec.rb'
- 'spec/lib/gitlab/auth/blocked_user_tracker_spec.rb'
- 'spec/lib/gitlab/auth/crowd/authentication_spec.rb'
- 'spec/lib/gitlab/auth/current_user_mode_spec.rb'
@@ -4040,7 +3356,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/background_migration/update_timelogs_project_id_spec.rb'
- 'spec/lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group_spec.rb'
- 'spec/lib/gitlab/background_migration_spec.rb'
- - 'spec/lib/gitlab/background_task_spec.rb'
- 'spec/lib/gitlab/backtrace_cleaner_spec.rb'
- 'spec/lib/gitlab/bare_repository_import/importer_spec.rb'
- 'spec/lib/gitlab/bare_repository_import/repository_spec.rb'
@@ -4063,7 +3378,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/changelog/config_spec.rb'
- 'spec/lib/gitlab/changelog/generator_spec.rb'
- 'spec/lib/gitlab/changelog/release_spec.rb'
- - 'spec/lib/gitlab/changes_list_spec.rb'
- 'spec/lib/gitlab/chat/command_spec.rb'
- 'spec/lib/gitlab/chat/output_spec.rb'
- 'spec/lib/gitlab/chat/responder/base_spec.rb'
@@ -4072,9 +3386,7 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/chat_name_token_spec.rb'
- 'spec/lib/gitlab/chat_spec.rb'
- 'spec/lib/gitlab/checks/branch_check_spec.rb'
- - 'spec/lib/gitlab/checks/changes_access_spec.rb'
- 'spec/lib/gitlab/checks/container_moved_spec.rb'
- - 'spec/lib/gitlab/checks/diff_check_spec.rb'
- 'spec/lib/gitlab/checks/force_push_spec.rb'
- 'spec/lib/gitlab/checks/lfs_check_spec.rb'
- 'spec/lib/gitlab/checks/lfs_integrity_spec.rb'
@@ -4160,14 +3472,12 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/ci/config/entry/need_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/needs_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/paths_spec.rb'
- - 'spec/lib/gitlab/ci/config/entry/policy_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/port_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/ports_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/prefix_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/product/variables_spec.rb'
- - 'spec/lib/gitlab/ci/config/entry/pull_policy_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/release/assets/link_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/release/assets/links_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/release/assets_spec.rb'
@@ -4205,7 +3515,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/ci/parsers/coverage/cobertura_spec.rb'
- 'spec/lib/gitlab/ci/parsers/coverage/sax_document_spec.rb'
- 'spec/lib/gitlab/ci/parsers/instrumentation_spec.rb'
- - 'spec/lib/gitlab/ci/parsers/security/common_spec.rb'
- 'spec/lib/gitlab/ci/parsers/security/sast_spec.rb'
- 'spec/lib/gitlab/ci/parsers/security/secret_detection_spec.rb'
- 'spec/lib/gitlab/ci/parsers/terraform/tfplan_spec.rb'
@@ -4214,7 +3523,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/ci/pipeline/chain/assign_partition_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/build_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/command_spec.rb'
- - 'spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/create_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb'
@@ -4233,7 +3541,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb'
- - 'spec/lib/gitlab/ci/pipeline/duration_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb'
@@ -4254,8 +3561,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/ci/pipeline/seed/processable/resource_group_spec.rb'
- 'spec/lib/gitlab/ci/pipeline_object_hierarchy_spec.rb'
- 'spec/lib/gitlab/ci/processable_object_hierarchy_spec.rb'
- - 'spec/lib/gitlab/ci/project_config/repository_spec.rb'
- - 'spec/lib/gitlab/ci/project_config/source_spec.rb'
- 'spec/lib/gitlab/ci/project_config_spec.rb'
- 'spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb'
- 'spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb'
@@ -4278,7 +3583,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/ci/reports/security/scan_spec.rb'
- 'spec/lib/gitlab/ci/reports/security/scanned_resource_spec.rb'
- 'spec/lib/gitlab/ci/reports/security/scanner_spec.rb'
- - 'spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb'
- 'spec/lib/gitlab/ci/reports/terraform_reports_spec.rb'
- 'spec/lib/gitlab/ci/reports/test_case_spec.rb'
- 'spec/lib/gitlab/ci/reports/test_failure_history_spec.rb'
@@ -4410,7 +3714,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb'
- 'spec/lib/gitlab/conflict/file_collection_spec.rb'
- 'spec/lib/gitlab/conflict/file_spec.rb'
- - 'spec/lib/gitlab/console_spec.rb'
- 'spec/lib/gitlab/consul/internal_spec.rb'
- 'spec/lib/gitlab/container_repository/tags/cache_spec.rb'
- 'spec/lib/gitlab/content_security_policy/config_loader_spec.rb'
@@ -4457,7 +3760,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/database/count_spec.rb'
- 'spec/lib/gitlab/database/dynamic_model_helpers_spec.rb'
- 'spec/lib/gitlab/database/each_database_spec.rb'
- - 'spec/lib/gitlab/database/gitlab_schema_spec.rb'
- 'spec/lib/gitlab/database/grant_spec.rb'
- 'spec/lib/gitlab/database/load_balancing/action_cable_callbacks_spec.rb'
- 'spec/lib/gitlab/database/load_balancing/configuration_spec.rb'
@@ -4478,7 +3780,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/database/migration_helpers/cascading_namespace_settings_spec.rb'
- 'spec/lib/gitlab/database/migration_helpers/loose_foreign_key_helpers_spec.rb'
- 'spec/lib/gitlab/database/migration_helpers/v2_spec.rb'
- - 'spec/lib/gitlab/database/migration_helpers_spec.rb'
- 'spec/lib/gitlab/database/migration_spec.rb'
- 'spec/lib/gitlab/database/migrations/background_migration_helpers_spec.rb'
- 'spec/lib/gitlab/database/migrations/base_background_runner_spec.rb'
@@ -4509,7 +3810,6 @@ RSpec/MissingFeatureCategory:
- '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/foreign_key_helpers_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb'
- 'spec/lib/gitlab/database/partitioning_spec.rb'
@@ -4519,7 +3819,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/database/postgres_hll/buckets_spec.rb'
- 'spec/lib/gitlab/database/postgres_index_bloat_estimate_spec.rb'
- 'spec/lib/gitlab/database/postgres_index_spec.rb'
- - 'spec/lib/gitlab/database/postgres_partition_spec.rb'
- 'spec/lib/gitlab/database/postgres_partitioned_table_spec.rb'
- 'spec/lib/gitlab/database/postgresql_adapter/dump_schema_versions_mixin_spec.rb'
- 'spec/lib/gitlab/database/postgresql_adapter/empty_query_ping_spec.rb'
@@ -4641,7 +3940,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/empty_search_results_spec.rb'
- 'spec/lib/gitlab/encoding_helper_spec.rb'
- 'spec/lib/gitlab/encrypted_configuration_spec.rb'
- - 'spec/lib/gitlab/endpoint_attributes_spec.rb'
- 'spec/lib/gitlab/error_tracking/context_payload_generator_spec.rb'
- 'spec/lib/gitlab/error_tracking/error_repository/open_api_strategy_spec.rb'
- 'spec/lib/gitlab/error_tracking/log_formatter_spec.rb'
@@ -4772,7 +4070,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/github_import/importer/issue_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/note_attachments_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/note_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/protected_branch_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb'
@@ -4788,7 +4085,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/github_import/issuable_finder_spec.rb'
- 'spec/lib/gitlab/github_import/label_finder_spec.rb'
- 'spec/lib/gitlab/github_import/logger_spec.rb'
- - 'spec/lib/gitlab/github_import/markdown/attachment_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'
@@ -4904,7 +4200,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/i18n/metadata_entry_spec.rb'
- 'spec/lib/gitlab/i18n/po_linter_spec.rb'
- 'spec/lib/gitlab/i18n/translation_entry_spec.rb'
- - 'spec/lib/gitlab/i18n_spec.rb'
- 'spec/lib/gitlab/identifier_spec.rb'
- 'spec/lib/gitlab/import/database_helpers_spec.rb'
- 'spec/lib/gitlab/import/import_failure_service_spec.rb'
@@ -4917,36 +4212,27 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb'
- 'spec/lib/gitlab/import_export/after_export_strategy_builder_spec.rb'
- 'spec/lib/gitlab/import_export/attribute_cleaner_spec.rb'
- - 'spec/lib/gitlab/import_export/attribute_configuration_spec.rb'
- - 'spec/lib/gitlab/import_export/attributes_finder_spec.rb'
- - 'spec/lib/gitlab/import_export/attributes_permitter_spec.rb'
- 'spec/lib/gitlab/import_export/avatar_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/avatar_saver_spec.rb'
- 'spec/lib/gitlab/import_export/base/object_builder_spec.rb'
- 'spec/lib/gitlab/import_export/base/relation_factory_spec.rb'
- - 'spec/lib/gitlab/import_export/command_line_util_spec.rb'
- - 'spec/lib/gitlab/import_export/config_spec.rb'
- 'spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb'
- 'spec/lib/gitlab/import_export/design_repo_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/design_repo_saver_spec.rb'
- 'spec/lib/gitlab/import_export/duration_measuring_spec.rb'
- 'spec/lib/gitlab/import_export/error_spec.rb'
- - 'spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb'
- 'spec/lib/gitlab/import_export/file_importer_spec.rb'
- 'spec/lib/gitlab/import_export/fork_spec.rb'
- 'spec/lib/gitlab/import_export/group/object_builder_spec.rb'
- 'spec/lib/gitlab/import_export/group/relation_factory_spec.rb'
- - 'spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/group/tree_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/group/tree_saver_spec.rb'
- 'spec/lib/gitlab/import_export/hash_util_spec.rb'
- 'spec/lib/gitlab/import_export/import_export_spec.rb'
- - 'spec/lib/gitlab/import_export/import_failure_service_spec.rb'
- 'spec/lib/gitlab/import_export/import_test_coverage_spec.rb'
- 'spec/lib/gitlab/import_export/importer_spec.rb'
- 'spec/lib/gitlab/import_export/json/legacy_reader/file_spec.rb'
- 'spec/lib/gitlab/import_export/json/legacy_reader/hash_spec.rb'
- - 'spec/lib/gitlab/import_export/json/legacy_writer_spec.rb'
- 'spec/lib/gitlab/import_export/json/ndjson_reader_spec.rb'
- 'spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb'
- 'spec/lib/gitlab/import_export/legacy_relation_tree_saver_spec.rb'
@@ -4955,19 +4241,15 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/import_export/log_util_spec.rb'
- 'spec/lib/gitlab/import_export/members_mapper_spec.rb'
- 'spec/lib/gitlab/import_export/merge_request_parser_spec.rb'
- - 'spec/lib/gitlab/import_export/model_configuration_spec.rb'
- 'spec/lib/gitlab/import_export/project/export_task_spec.rb'
- 'spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb'
- - 'spec/lib/gitlab/import_export/project/import_task_spec.rb'
- 'spec/lib/gitlab/import_export/project/object_builder_spec.rb'
- 'spec/lib/gitlab/import_export/project/relation_saver_spec.rb'
- 'spec/lib/gitlab/import_export/project/sample/date_calculator_spec.rb'
- 'spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb'
- 'spec/lib/gitlab/import_export/project/sample/relation_tree_restorer_spec.rb'
- - 'spec/lib/gitlab/import_export/project/tree_saver_spec.rb'
- 'spec/lib/gitlab/import_export/reader_spec.rb'
- 'spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb'
- - 'spec/lib/gitlab/import_export/references_configuration_spec.rb'
- 'spec/lib/gitlab/import_export/remote_stream_upload_spec.rb'
- 'spec/lib/gitlab/import_export/repo_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/repo_saver_spec.rb'
@@ -5058,7 +4340,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/legacy_github_import/branch_formatter_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/client_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/comment_formatter_spec.rb'
- - 'spec/lib/gitlab/legacy_github_import/importer_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/issuable_formatter_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/label_formatter_spec.rb'
@@ -5100,14 +4381,12 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/memory/upload_and_cleanup_reports_spec.rb'
- 'spec/lib/gitlab/memory/watchdog/configuration_spec.rb'
- 'spec/lib/gitlab/memory/watchdog/monitor/heap_fragmentation_spec.rb'
- - 'spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb'
- 'spec/lib/gitlab/memory/watchdog/monitor/unique_memory_growth_spec.rb'
- 'spec/lib/gitlab/memory/watchdog/monitor_state_spec.rb'
- 'spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb'
- 'spec/lib/gitlab/merge_requests/mergeability/redis_interface_spec.rb'
- 'spec/lib/gitlab/merge_requests/mergeability/results_store_spec.rb'
- 'spec/lib/gitlab/metrics/background_transaction_spec.rb'
- - 'spec/lib/gitlab/metrics/boot_time_tracker_spec.rb'
- 'spec/lib/gitlab/metrics/dashboard/cache_spec.rb'
- 'spec/lib/gitlab/metrics/dashboard/defaults_spec.rb'
- 'spec/lib/gitlab/metrics/dashboard/finder_spec.rb'
@@ -5178,12 +4457,10 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/multi_destination_logger_spec.rb'
- 'spec/lib/gitlab/namespaced_session_store_spec.rb'
- 'spec/lib/gitlab/nav/top_nav_menu_header_spec.rb'
- - 'spec/lib/gitlab/net_http_adapter_spec.rb'
- 'spec/lib/gitlab/no_cache_headers_spec.rb'
- 'spec/lib/gitlab/noteable_metadata_spec.rb'
- 'spec/lib/gitlab/null_request_store_spec.rb'
- 'spec/lib/gitlab/object_hierarchy_spec.rb'
- - 'spec/lib/gitlab/observability_spec.rb'
- 'spec/lib/gitlab/omniauth_initializer_spec.rb'
- 'spec/lib/gitlab/optimistic_locking_spec.rb'
- 'spec/lib/gitlab/other_markup_spec.rb'
@@ -5260,7 +4537,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb'
- 'spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb'
- 'spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb'
- - 'spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb'
- 'spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb'
- 'spec/lib/gitlab/prometheus/queries/validate_query_spec.rb'
- 'spec/lib/gitlab/prometheus/query_variables_spec.rb'
@@ -5280,7 +4556,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/quick_actions/substitution_definition_spec.rb'
- 'spec/lib/gitlab/quick_actions/timeline_text_and_date_time_separator_spec.rb'
- 'spec/lib/gitlab/quick_actions/users_extractor_spec.rb'
- - 'spec/lib/gitlab/rack_attack/instrumented_cache_store_spec.rb'
- 'spec/lib/gitlab/rack_attack/request_spec.rb'
- 'spec/lib/gitlab/rack_attack/user_allowlist_spec.rb'
- 'spec/lib/gitlab/rack_attack_spec.rb'
@@ -5323,7 +4598,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/safe_request_purger_spec.rb'
- 'spec/lib/gitlab/safe_request_store_spec.rb'
- 'spec/lib/gitlab/sample_data_template_spec.rb'
- - 'spec/lib/gitlab/sanitizers/exception_message_spec.rb'
- 'spec/lib/gitlab/sanitizers/exif_spec.rb'
- 'spec/lib/gitlab/sanitizers/svg_spec.rb'
- 'spec/lib/gitlab/search/abuse_detection_spec.rb'
@@ -5343,7 +4617,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/seeders/ci/daily_build_group_report_result_spec.rb'
- 'spec/lib/gitlab/serializer/ci/variables_spec.rb'
- 'spec/lib/gitlab/serializer/pagination_spec.rb'
- - 'spec/lib/gitlab/serverless/service_spec.rb'
- 'spec/lib/gitlab/service_desk_email_spec.rb'
- 'spec/lib/gitlab/service_desk_spec.rb'
- 'spec/lib/gitlab/session_spec.rb'
@@ -5480,7 +4753,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/collected_data_categories_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/count_boards_metric_spec.rb'
- - 'spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/count_issues_metric_spec.rb'
@@ -5540,7 +4812,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/usage_data_counters/service_usage_data_counter_spec.rb'
- 'spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb'
- 'spec/lib/gitlab/usage_data_counters/source_code_counter_spec.rb'
- - 'spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb'
- 'spec/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter_spec.rb'
- 'spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb'
- 'spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb'
@@ -5629,7 +4900,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/mattermost/team_spec.rb'
- 'spec/lib/microsoft_teams/activity_spec.rb'
- 'spec/lib/microsoft_teams/notifier_spec.rb'
- - 'spec/lib/object_storage/config_spec.rb'
- 'spec/lib/object_storage/direct_upload_spec.rb'
- 'spec/lib/omni_auth/strategies/bitbucket_spec.rb'
- 'spec/lib/omni_auth/strategies/jwt_spec.rb'
@@ -5645,7 +4915,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/prometheus/cleanup_multiproc_dir_service_spec.rb'
- 'spec/lib/prometheus/pid_provider_spec.rb'
- 'spec/lib/quality/seeders/issues_spec.rb'
- - 'spec/lib/release_highlights/validator/entry_spec.rb'
- 'spec/lib/rouge/formatters/html_gitlab_spec.rb'
- 'spec/lib/safe_zip/entry_spec.rb'
- 'spec/lib/safe_zip/extract_params_spec.rb'
@@ -5662,41 +4931,21 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/sidebars/concerns/container_with_html_options_spec.rb'
- 'spec/lib/sidebars/concerns/link_with_html_options_spec.rb'
- 'spec/lib/sidebars/groups/menus/ci_cd_menu_spec.rb'
- - 'spec/lib/sidebars/groups/menus/group_information_menu_spec.rb'
- - 'spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb'
- - 'spec/lib/sidebars/groups/menus/issues_menu_spec.rb'
- - 'spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb'
- - 'spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb'
- 'spec/lib/sidebars/groups/menus/observability_menu_spec.rb'
- - 'spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb'
- - 'spec/lib/sidebars/groups/menus/scope_menu_spec.rb'
- 'spec/lib/sidebars/groups/menus/settings_menu_spec.rb'
- 'spec/lib/sidebars/menu_item_spec.rb'
- - 'spec/lib/sidebars/menu_spec.rb'
- - 'spec/lib/sidebars/panel_spec.rb'
- 'spec/lib/sidebars/projects/context_spec.rb'
- 'spec/lib/sidebars/projects/menus/analytics_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/ci_cd_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/confluence_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/deployments_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/external_issue_tracker_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/external_wiki_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/hidden_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/issues_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/monitor_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/project_information_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/scope_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/settings_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/shimo_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/snippets_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/wiki_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/zentao_menu_spec.rb'
- - 'spec/lib/sidebars/projects/panel_spec.rb'
- 'spec/lib/system_check/app/authorized_keys_permission_check_spec.rb'
- 'spec/lib/system_check/app/git_user_default_ssh_config_check_spec.rb'
- 'spec/lib/system_check/app/hashed_storage_all_projects_check_spec.rb'
@@ -5709,7 +4958,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/system_check/sidekiq_check_spec.rb'
- 'spec/lib/system_check/simple_executor_spec.rb'
- 'spec/lib/system_check_spec.rb'
- - 'spec/lib/tasks/gitlab/metrics_exporter_task_spec.rb'
- 'spec/lib/unnested_in_filters/dsl_spec.rb'
- 'spec/lib/unnested_in_filters/rewriter_spec.rb'
- 'spec/lib/uploaded_file_spec.rb'
@@ -5722,7 +4970,6 @@ RSpec/MissingFeatureCategory:
- 'spec/mailers/emails/groups_spec.rb'
- 'spec/mailers/emails/identity_verification_spec.rb'
- 'spec/mailers/emails/in_product_marketing_spec.rb'
- - 'spec/mailers/emails/issues_spec.rb'
- 'spec/mailers/emails/merge_requests_spec.rb'
- 'spec/mailers/emails/pages_domains_spec.rb'
- 'spec/mailers/emails/pipelines_spec.rb'
@@ -5779,7 +5026,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/board_project_recent_visit_spec.rb'
- 'spec/models/board_spec.rb'
- 'spec/models/broadcast_message_spec.rb'
- - 'spec/models/bulk_import_spec.rb'
- 'spec/models/bulk_imports/configuration_spec.rb'
- 'spec/models/bulk_imports/export_spec.rb'
- 'spec/models/bulk_imports/export_status_spec.rb'
@@ -5803,7 +5049,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/ci/daily_build_group_report_result_spec.rb'
- 'spec/models/ci/deleted_object_spec.rb'
- 'spec/models/ci/group_spec.rb'
- - 'spec/models/ci/group_variable_spec.rb'
- 'spec/models/ci/instance_variable_spec.rb'
- 'spec/models/ci/namespace_mirror_spec.rb'
- 'spec/models/ci/pending_build_spec.rb'
@@ -5825,19 +5070,16 @@ RSpec/MissingFeatureCategory:
- 'spec/models/ci/trigger_request_spec.rb'
- 'spec/models/ci/unit_test_failure_spec.rb'
- 'spec/models/ci/unit_test_spec.rb'
- - 'spec/models/ci/variable_spec.rb'
- 'spec/models/clusters/agent_spec.rb'
- 'spec/models/clusters/agent_token_spec.rb'
- 'spec/models/clusters/agents/activity_event_spec.rb'
- 'spec/models/clusters/agents/group_authorization_spec.rb'
- 'spec/models/clusters/agents/implicit_authorization_spec.rb'
- 'spec/models/clusters/agents/project_authorization_spec.rb'
- - 'spec/models/clusters/applications/crossplane_spec.rb'
- 'spec/models/clusters/applications/helm_spec.rb'
- 'spec/models/clusters/applications/ingress_spec.rb'
- 'spec/models/clusters/applications/jupyter_spec.rb'
- 'spec/models/clusters/applications/knative_spec.rb'
- - 'spec/models/clusters/applications/prometheus_spec.rb'
- 'spec/models/clusters/applications/runner_spec.rb'
- 'spec/models/clusters/cluster_enabled_grant_spec.rb'
- 'spec/models/clusters/clusters_hierarchy_spec.rb'
@@ -5848,7 +5090,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/clusters/project_spec.rb'
- 'spec/models/clusters/providers/aws_spec.rb'
- 'spec/models/clusters/providers/gcp_spec.rb'
- - 'spec/models/commit_collection_spec.rb'
- 'spec/models/commit_range_spec.rb'
- 'spec/models/commit_signatures/gpg_signature_spec.rb'
- 'spec/models/commit_signatures/x509_commit_signature_spec.rb'
@@ -5904,7 +5145,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/concerns/from_union_spec.rb'
- 'spec/models/concerns/group_descendant_spec.rb'
- 'spec/models/concerns/has_environment_scope_spec.rb'
- - 'spec/models/concerns/has_user_type_spec.rb'
- 'spec/models/concerns/id_in_ordered_spec.rb'
- 'spec/models/concerns/ignorable_columns_spec.rb'
- 'spec/models/concerns/integrations/enable_ssl_verification_spec.rb'
@@ -5951,13 +5191,10 @@ RSpec/MissingFeatureCategory:
- 'spec/models/concerns/subscribable_spec.rb'
- 'spec/models/concerns/taggable_queries_spec.rb'
- 'spec/models/concerns/token_authenticatable_spec.rb'
- - 'spec/models/concerns/token_authenticatable_strategies/base_spec.rb'
- 'spec/models/concerns/token_authenticatable_strategies/digest_spec.rb'
- - 'spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb'
- 'spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb'
- 'spec/models/concerns/transactions_spec.rb'
- 'spec/models/concerns/triggerable_hooks_spec.rb'
- - 'spec/models/concerns/uniquify_spec.rb'
- 'spec/models/concerns/usage_statistics_spec.rb'
- 'spec/models/concerns/vulnerability_finding_helpers_spec.rb'
- 'spec/models/concerns/vulnerability_finding_signature_helpers_spec.rb'
@@ -6005,7 +5242,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/error_tracking/client_key_spec.rb'
- 'spec/models/error_tracking/error_event_spec.rb'
- 'spec/models/error_tracking/error_spec.rb'
- - 'spec/models/error_tracking/project_error_tracking_setting_spec.rb'
- 'spec/models/event_collection_spec.rb'
- 'spec/models/exported_protected_branch_spec.rb'
- 'spec/models/external_issue_spec.rb'
@@ -6038,7 +5274,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/instance_configuration_spec.rb'
- 'spec/models/instance_metadata/kas_spec.rb'
- 'spec/models/instance_metadata_spec.rb'
- - 'spec/models/integration_spec.rb'
- 'spec/models/integrations/asana_spec.rb'
- 'spec/models/integrations/assembla_spec.rb'
- 'spec/models/integrations/bamboo_spec.rb'
@@ -6047,7 +5282,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/integrations/base_third_party_wiki_spec.rb'
- 'spec/models/integrations/bugzilla_spec.rb'
- 'spec/models/integrations/buildkite_spec.rb'
- - 'spec/models/integrations/campfire_spec.rb'
- 'spec/models/integrations/chat_message/alert_message_spec.rb'
- 'spec/models/integrations/chat_message/base_message_spec.rb'
- 'spec/models/integrations/chat_message/deployment_message_spec.rb'
@@ -6059,7 +5293,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/integrations/chat_message/wiki_page_message_spec.rb'
- 'spec/models/integrations/confluence_spec.rb'
- 'spec/models/integrations/custom_issue_tracker_spec.rb'
- - 'spec/models/integrations/datadog_spec.rb'
- 'spec/models/integrations/discord_spec.rb'
- 'spec/models/integrations/drone_ci_spec.rb'
- 'spec/models/integrations/emails_on_push_spec.rb'
@@ -6074,7 +5307,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/integrations/jenkins_spec.rb'
- 'spec/models/integrations/jira_spec.rb'
- 'spec/models/integrations/jira_tracker_data_spec.rb'
- - 'spec/models/integrations/mattermost_slash_commands_spec.rb'
- 'spec/models/integrations/mattermost_spec.rb'
- 'spec/models/integrations/microsoft_teams_spec.rb'
- 'spec/models/integrations/mock_ci_spec.rb'
@@ -6086,7 +5318,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/integrations/pushover_spec.rb'
- 'spec/models/integrations/redmine_spec.rb'
- 'spec/models/integrations/shimo_spec.rb'
- - 'spec/models/integrations/slack_slash_commands_spec.rb'
- 'spec/models/integrations/slack_spec.rb'
- 'spec/models/integrations/teamcity_spec.rb'
- 'spec/models/integrations/unify_circuit_spec.rb'
@@ -6155,7 +5386,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/notification_setting_spec.rb'
- 'spec/models/oauth_access_grant_spec.rb'
- 'spec/models/oauth_access_token_spec.rb'
- - 'spec/models/onboarding/completion_spec.rb'
- 'spec/models/onboarding/progress_spec.rb'
- 'spec/models/operations/feature_flag_spec.rb'
- 'spec/models/operations/feature_flags/strategy_spec.rb'
@@ -6254,7 +5484,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/protectable_dropdown_spec.rb'
- 'spec/models/protected_branch/merge_access_level_spec.rb'
- 'spec/models/protected_branch/push_access_level_spec.rb'
- - 'spec/models/protected_branch_spec.rb'
- 'spec/models/protected_tag_spec.rb'
- 'spec/models/push_event_payload_spec.rb'
- 'spec/models/push_event_spec.rb'
@@ -6271,9 +5500,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/route_spec.rb'
- 'spec/models/sent_notification_spec.rb'
- 'spec/models/sentry_issue_spec.rb'
- - 'spec/models/serverless/domain_cluster_spec.rb'
- - 'spec/models/serverless/domain_spec.rb'
- - 'spec/models/serverless/function_spec.rb'
- 'spec/models/shard_spec.rb'
- 'spec/models/snippet_blob_spec.rb'
- 'spec/models/snippet_input_action_collection_spec.rb'
@@ -6369,7 +5595,6 @@ RSpec/MissingFeatureCategory:
- 'spec/policies/deploy_key_policy_spec.rb'
- 'spec/policies/deploy_keys_project_policy_spec.rb'
- 'spec/policies/deploy_token_policy_spec.rb'
- - 'spec/policies/design_management/design_policy_spec.rb'
- 'spec/policies/environment_policy_spec.rb'
- 'spec/policies/group_deploy_key_policy_spec.rb'
- 'spec/policies/group_deploy_keys_group_policy_spec.rb'
@@ -6389,7 +5614,6 @@ RSpec/MissingFeatureCategory:
- 'spec/policies/packages/policies/project_policy_spec.rb'
- 'spec/policies/personal_access_token_policy_spec.rb'
- 'spec/policies/personal_snippet_policy_spec.rb'
- - 'spec/policies/project_hook_policy_spec.rb'
- 'spec/policies/project_member_policy_spec.rb'
- 'spec/policies/project_snippet_policy_spec.rb'
- 'spec/policies/project_statistics_policy_spec.rb'
@@ -6421,7 +5645,6 @@ RSpec/MissingFeatureCategory:
- 'spec/presenters/ci/variable_presenter_spec.rb'
- 'spec/presenters/clusterable_presenter_spec.rb'
- 'spec/presenters/clusters/cluster_presenter_spec.rb'
- - 'spec/presenters/commit_presenter_spec.rb'
- 'spec/presenters/commit_status_presenter_spec.rb'
- 'spec/presenters/deploy_key_presenter_spec.rb'
- 'spec/presenters/deployments/deployment_presenter_spec.rb'
@@ -6640,7 +5863,6 @@ RSpec/MissingFeatureCategory:
- 'spec/scripts/changed-feature-flags_spec.rb'
- 'spec/scripts/failed_tests_spec.rb'
- 'spec/scripts/lib/glfm/parse_examples_spec.rb'
- - 'spec/scripts/lib/glfm/shared_spec.rb'
- 'spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb'
- 'spec/scripts/setup/find_jh_branch_spec.rb'
- 'spec/serializers/access_token_entity_base_spec.rb'
@@ -6683,7 +5905,6 @@ RSpec/MissingFeatureCategory:
- 'spec/serializers/ci/trigger_entity_spec.rb'
- 'spec/serializers/ci/trigger_serializer_spec.rb'
- 'spec/serializers/ci/variable_entity_spec.rb'
- - 'spec/serializers/cluster_application_entity_spec.rb'
- 'spec/serializers/cluster_entity_spec.rb'
- 'spec/serializers/cluster_serializer_spec.rb'
- 'spec/serializers/clusters/kubernetes_error_entity_spec.rb'
@@ -6799,7 +6020,6 @@ RSpec/MissingFeatureCategory:
- 'spec/serializers/paginated_diff_entity_spec.rb'
- 'spec/serializers/personal_access_token_entity_spec.rb'
- 'spec/serializers/personal_access_token_serializer_spec.rb'
- - 'spec/serializers/pipeline_details_entity_spec.rb'
- 'spec/serializers/pipeline_serializer_spec.rb'
- 'spec/serializers/project_access_token_entity_spec.rb'
- 'spec/serializers/project_access_token_serializer_spec.rb'
@@ -6831,760 +6051,10 @@ 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/access_token_validation_service_spec.rb'
- - 'spec/services/admin/set_feature_flag_service_spec.rb'
- - 'spec/services/alert_management/alerts/todo/create_service_spec.rb'
- - 'spec/services/alert_management/alerts/update_service_spec.rb'
- - 'spec/services/alert_management/create_alert_issue_service_spec.rb'
- - 'spec/services/alert_management/http_integrations/create_service_spec.rb'
- - 'spec/services/alert_management/http_integrations/destroy_service_spec.rb'
- - 'spec/services/alert_management/http_integrations/update_service_spec.rb'
- - 'spec/services/alert_management/metric_images/upload_service_spec.rb'
- - 'spec/services/alert_management/process_prometheus_alert_service_spec.rb'
- - 'spec/services/analytics/cycle_analytics/stages/list_service_spec.rb'
- 'spec/services/application_settings/update_service_spec.rb'
- 'spec/services/applications/create_service_spec.rb'
- - 'spec/services/audit_event_service_spec.rb'
- - 'spec/services/audit_events/build_service_spec.rb'
- - 'spec/services/auth/container_registry_authentication_service_spec.rb'
- - 'spec/services/auth/dependency_proxy_authentication_service_spec.rb'
- - 'spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb'
- - 'spec/services/authorized_project_update/periodic_recalculate_service_spec.rb'
- - 'spec/services/authorized_project_update/project_access_changed_service_spec.rb'
- - 'spec/services/authorized_project_update/project_recalculate_per_user_service_spec.rb'
- - 'spec/services/authorized_project_update/project_recalculate_service_spec.rb'
- - 'spec/services/auto_merge/base_service_spec.rb'
- - 'spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb'
- - 'spec/services/auto_merge_service_spec.rb'
- - 'spec/services/award_emojis/add_service_spec.rb'
- - 'spec/services/award_emojis/base_service_spec.rb'
- - 'spec/services/award_emojis/collect_user_emoji_service_spec.rb'
- - 'spec/services/award_emojis/copy_service_spec.rb'
- - 'spec/services/award_emojis/destroy_service_spec.rb'
- - 'spec/services/award_emojis/toggle_service_spec.rb'
- - 'spec/services/base_container_service_spec.rb'
- - 'spec/services/base_count_service_spec.rb'
- - 'spec/services/boards/create_service_spec.rb'
- - 'spec/services/boards/destroy_service_spec.rb'
- - 'spec/services/boards/issues/create_service_spec.rb'
- - 'spec/services/boards/issues/list_service_spec.rb'
- - 'spec/services/boards/issues/move_service_spec.rb'
- - 'spec/services/boards/lists/create_service_spec.rb'
- - 'spec/services/boards/lists/destroy_service_spec.rb'
- - 'spec/services/boards/lists/list_service_spec.rb'
- - 'spec/services/boards/lists/move_service_spec.rb'
- - 'spec/services/boards/lists/update_service_spec.rb'
- - 'spec/services/boards/visits/create_service_spec.rb'
- - 'spec/services/branches/create_service_spec.rb'
- - 'spec/services/branches/delete_merged_service_spec.rb'
- - 'spec/services/branches/delete_service_spec.rb'
- - 'spec/services/branches/diverging_commit_counts_service_spec.rb'
- - 'spec/services/branches/validate_new_service_spec.rb'
- - 'spec/services/bulk_create_integration_service_spec.rb'
- - 'spec/services/bulk_imports/archive_extraction_service_spec.rb'
- - 'spec/services/bulk_imports/export_service_spec.rb'
- - 'spec/services/bulk_imports/file_decompression_service_spec.rb'
- - 'spec/services/bulk_imports/file_download_service_spec.rb'
- - 'spec/services/bulk_imports/file_export_service_spec.rb'
- - 'spec/services/bulk_imports/lfs_objects_export_service_spec.rb'
- - 'spec/services/bulk_imports/relation_export_service_spec.rb'
- - 'spec/services/bulk_imports/repository_bundle_export_service_spec.rb'
- - 'spec/services/bulk_imports/tree_export_service_spec.rb'
- - 'spec/services/bulk_imports/uploads_export_service_spec.rb'
- - 'spec/services/bulk_push_event_payload_service_spec.rb'
- - 'spec/services/bulk_update_integration_service_spec.rb'
- - 'spec/services/captcha/captcha_verification_service_spec.rb'
- - 'spec/services/chat_names/find_user_service_spec.rb'
- - 'spec/services/ci/abort_pipelines_service_spec.rb'
- - 'spec/services/ci/append_build_trace_service_spec.rb'
- - 'spec/services/ci/build_cancel_service_spec.rb'
- - 'spec/services/ci/build_erase_service_spec.rb'
- - 'spec/services/ci/build_report_result_service_spec.rb'
- - 'spec/services/ci/build_unschedule_service_spec.rb'
- - 'spec/services/ci/change_variable_service_spec.rb'
- - 'spec/services/ci/change_variables_service_spec.rb'
- - 'spec/services/ci/compare_accessibility_reports_service_spec.rb'
- - 'spec/services/ci/compare_codequality_reports_service_spec.rb'
- - 'spec/services/ci/compare_reports_base_service_spec.rb'
- - 'spec/services/ci/compare_test_reports_service_spec.rb'
- - 'spec/services/ci/copy_cross_database_associations_service_spec.rb'
- - 'spec/services/ci/create_pipeline_service/artifacts_spec.rb'
- - 'spec/services/ci/create_pipeline_service/cache_spec.rb'
- - 'spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb'
- - 'spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb'
- - 'spec/services/ci/create_pipeline_service/custom_config_content_spec.rb'
- - 'spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb'
- - 'spec/services/ci/create_pipeline_service/dry_run_spec.rb'
- - 'spec/services/ci/create_pipeline_service/environment_spec.rb'
- - 'spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb'
- - 'spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb'
- - 'spec/services/ci/create_pipeline_service/merge_requests_spec.rb'
- - 'spec/services/ci/create_pipeline_service/needs_spec.rb'
- - 'spec/services/ci/create_pipeline_service/parallel_spec.rb'
- - 'spec/services/ci/create_pipeline_service/parameter_content_spec.rb'
- - 'spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb'
- - 'spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb'
- - 'spec/services/ci/create_pipeline_service/rate_limit_spec.rb'
- - 'spec/services/ci/create_pipeline_service/scripts_spec.rb'
- - 'spec/services/ci/create_pipeline_service/tags_spec.rb'
- - 'spec/services/ci/create_pipeline_service/variables_spec.rb'
- - 'spec/services/ci/create_web_ide_terminal_service_spec.rb'
- - 'spec/services/ci/daily_build_group_report_result_service_spec.rb'
- - 'spec/services/ci/delete_objects_service_spec.rb'
- - 'spec/services/ci/delete_unit_tests_service_spec.rb'
- - 'spec/services/ci/deployments/destroy_service_spec.rb'
- - 'spec/services/ci/destroy_pipeline_service_spec.rb'
- - 'spec/services/ci/destroy_secure_file_service_spec.rb'
- - 'spec/services/ci/disable_user_pipeline_schedules_service_spec.rb'
- - 'spec/services/ci/drop_pipeline_service_spec.rb'
- - 'spec/services/ci/ensure_stage_service_spec.rb'
- - 'spec/services/ci/expire_pipeline_cache_service_spec.rb'
- - 'spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb'
- - 'spec/services/ci/find_exposed_artifacts_service_spec.rb'
- - 'spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb'
- - 'spec/services/ci/generate_coverage_reports_service_spec.rb'
- - 'spec/services/ci/generate_kubeconfig_service_spec.rb'
- - 'spec/services/ci/generate_terraform_reports_service_spec.rb'
- - 'spec/services/ci/job_artifacts/create_service_spec.rb'
- - 'spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb'
- - 'spec/services/ci/job_artifacts/delete_service_spec.rb'
- - 'spec/services/ci/job_artifacts/destroy_associations_service_spec.rb'
- - 'spec/services/ci/job_artifacts/destroy_batch_service_spec.rb'
- - 'spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb'
- - 'spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb'
- - 'spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb'
- - 'spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb'
- - 'spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb'
- - 'spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb'
- - 'spec/services/ci/pipeline_bridge_status_service_spec.rb'
- - 'spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb'
- - 'spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb'
- - 'spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb'
- - 'spec/services/ci/pipeline_trigger_service_spec.rb'
- - 'spec/services/ci/pipelines/add_job_service_spec.rb'
- - 'spec/services/ci/pipelines/hook_service_spec.rb'
- - 'spec/services/ci/play_bridge_service_spec.rb'
- - 'spec/services/ci/play_build_service_spec.rb'
- - 'spec/services/ci/play_manual_stage_service_spec.rb'
- - 'spec/services/ci/prepare_build_service_spec.rb'
- - 'spec/services/ci/process_build_service_spec.rb'
- - 'spec/services/ci/process_pipeline_service_spec.rb'
- - 'spec/services/ci/process_sync_events_service_spec.rb'
- - 'spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb'
- - 'spec/services/ci/queue/pending_builds_strategy_spec.rb'
- - 'spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb'
- - 'spec/services/ci/retry_pipeline_service_spec.rb'
- - 'spec/services/ci/run_scheduled_build_service_spec.rb'
- - 'spec/services/ci/stuck_builds/drop_pending_service_spec.rb'
- - 'spec/services/ci/stuck_builds/drop_running_service_spec.rb'
- - 'spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb'
- - 'spec/services/ci/test_failure_history_service_spec.rb'
- - 'spec/services/ci/track_failed_build_service_spec.rb'
- - 'spec/services/ci/unlock_artifacts_service_spec.rb'
- - 'spec/services/ci/update_build_queue_service_spec.rb'
- - 'spec/services/ci/update_instance_variables_service_spec.rb'
- - 'spec/services/ci/update_pending_build_service_spec.rb'
- - 'spec/services/clusters/agent_tokens/create_service_spec.rb'
- - 'spec/services/clusters/agent_tokens/track_usage_service_spec.rb'
- - 'spec/services/clusters/agents/create_activity_event_service_spec.rb'
- - 'spec/services/clusters/agents/create_service_spec.rb'
- - 'spec/services/clusters/agents/delete_expired_events_service_spec.rb'
- - 'spec/services/clusters/agents/delete_service_spec.rb'
- - 'spec/services/clusters/build_kubernetes_namespace_service_spec.rb'
- - 'spec/services/clusters/build_service_spec.rb'
- - 'spec/services/clusters/cleanup/project_namespace_service_spec.rb'
- - 'spec/services/clusters/cleanup/service_account_service_spec.rb'
- - 'spec/services/clusters/create_service_spec.rb'
- - 'spec/services/clusters/destroy_service_spec.rb'
- - 'spec/services/clusters/integrations/create_service_spec.rb'
- - 'spec/services/clusters/integrations/prometheus_health_check_service_spec.rb'
- - 'spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb'
- - 'spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb'
- - 'spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb'
- - 'spec/services/clusters/kubernetes_spec.rb'
- - 'spec/services/clusters/management/validate_management_project_permissions_service_spec.rb'
- - 'spec/services/clusters/update_service_spec.rb'
- - 'spec/services/cohorts_service_spec.rb'
- - 'spec/services/commits/cherry_pick_service_spec.rb'
- - 'spec/services/commits/commit_patch_service_spec.rb'
- - 'spec/services/commits/tag_service_spec.rb'
- - 'spec/services/compare_service_spec.rb'
- - 'spec/services/concerns/audit_event_save_type_spec.rb'
- - 'spec/services/concerns/exclusive_lease_guard_spec.rb'
- - 'spec/services/concerns/merge_requests/assigns_merge_params_spec.rb'
- - 'spec/services/concerns/rate_limited_service_spec.rb'
- - 'spec/services/container_expiration_policies/cleanup_service_spec.rb'
- - 'spec/services/container_expiration_policies/update_service_spec.rb'
- - 'spec/services/customer_relations/contacts/create_service_spec.rb'
- - 'spec/services/customer_relations/contacts/update_service_spec.rb'
- - 'spec/services/customer_relations/organizations/create_service_spec.rb'
- - 'spec/services/customer_relations/organizations/update_service_spec.rb'
- - 'spec/services/database/consistency_fix_service_spec.rb'
- - 'spec/services/dependency_proxy/auth_token_service_spec.rb'
- - 'spec/services/dependency_proxy/find_cached_manifest_service_spec.rb'
- - 'spec/services/dependency_proxy/group_settings/update_service_spec.rb'
- - 'spec/services/dependency_proxy/head_manifest_service_spec.rb'
- - 'spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb'
- - 'spec/services/dependency_proxy/request_token_service_spec.rb'
- - 'spec/services/deploy_keys/create_service_spec.rb'
- - 'spec/services/deployments/archive_in_project_service_spec.rb'
- - 'spec/services/deployments/create_for_build_service_spec.rb'
- - 'spec/services/deployments/create_service_spec.rb'
- - 'spec/services/deployments/link_merge_requests_service_spec.rb'
- - 'spec/services/deployments/older_deployments_drop_service_spec.rb'
- - 'spec/services/deployments/update_environment_service_spec.rb'
- - 'spec/services/deployments/update_service_spec.rb'
- - 'spec/services/design_management/copy_design_collection/copy_service_spec.rb'
- - 'spec/services/design_management/copy_design_collection/queue_service_spec.rb'
- - 'spec/services/design_management/delete_designs_service_spec.rb'
- - 'spec/services/design_management/design_user_notes_count_service_spec.rb'
- - 'spec/services/design_management/generate_image_versions_service_spec.rb'
- - 'spec/services/design_management/move_designs_service_spec.rb'
- - 'spec/services/discussions/capture_diff_note_position_service_spec.rb'
- - 'spec/services/discussions/capture_diff_note_positions_service_spec.rb'
- - 'spec/services/discussions/update_diff_position_service_spec.rb'
- - 'spec/services/draft_notes/create_service_spec.rb'
- - 'spec/services/draft_notes/destroy_service_spec.rb'
- - 'spec/services/draft_notes/publish_service_spec.rb'
- - 'spec/services/emails/confirm_service_spec.rb'
- - 'spec/services/emails/create_service_spec.rb'
- - 'spec/services/emails/destroy_service_spec.rb'
- - 'spec/services/environments/auto_stop_service_spec.rb'
- - 'spec/services/environments/canary_ingress/update_service_spec.rb'
- - 'spec/services/environments/create_for_build_service_spec.rb'
- - 'spec/services/environments/reset_auto_stop_service_spec.rb'
- - 'spec/services/environments/schedule_to_delete_review_apps_service_spec.rb'
- - 'spec/services/environments/stop_service_spec.rb'
- - 'spec/services/error_tracking/base_service_spec.rb'
- - 'spec/services/error_tracking/collect_error_service_spec.rb'
- - 'spec/services/error_tracking/issue_details_service_spec.rb'
- - 'spec/services/error_tracking/issue_latest_event_service_spec.rb'
- - 'spec/services/error_tracking/issue_update_service_spec.rb'
- - 'spec/services/error_tracking/list_issues_service_spec.rb'
- - 'spec/services/event_create_service_spec.rb'
- - 'spec/services/events/destroy_service_spec.rb'
- - 'spec/services/events/render_service_spec.rb'
- - 'spec/services/feature_flags/create_service_spec.rb'
- - 'spec/services/feature_flags/destroy_service_spec.rb'
- - 'spec/services/feature_flags/hook_service_spec.rb'
- - 'spec/services/feature_flags/update_service_spec.rb'
- - 'spec/services/files/create_service_spec.rb'
- - 'spec/services/files/delete_service_spec.rb'
- - 'spec/services/files/multi_service_spec.rb'
- - 'spec/services/files/update_service_spec.rb'
- - 'spec/services/git/base_hooks_service_spec.rb'
- - 'spec/services/git/branch_hooks_service_spec.rb'
- - 'spec/services/git/branch_push_service_spec.rb'
- - 'spec/services/git/process_ref_changes_service_spec.rb'
- - 'spec/services/git/tag_hooks_service_spec.rb'
- - 'spec/services/git/tag_push_service_spec.rb'
- - 'spec/services/git/wiki_push_service/change_spec.rb'
- - 'spec/services/google_cloud/create_cloudsql_instance_service_spec.rb'
- - 'spec/services/google_cloud/create_service_accounts_service_spec.rb'
- - 'spec/services/google_cloud/enable_cloud_run_service_spec.rb'
- - 'spec/services/google_cloud/enable_cloudsql_service_spec.rb'
- - 'spec/services/google_cloud/gcp_region_add_or_replace_service_spec.rb'
- - 'spec/services/google_cloud/generate_pipeline_service_spec.rb'
- - 'spec/services/google_cloud/get_cloudsql_instances_service_spec.rb'
- - 'spec/services/google_cloud/service_accounts_service_spec.rb'
- - 'spec/services/google_cloud/setup_cloudsql_instance_service_spec.rb'
- - 'spec/services/gpg_keys/create_service_spec.rb'
- 'spec/services/gpg_keys/destroy_service_spec.rb'
- - 'spec/services/grafana/proxy_service_spec.rb'
- - 'spec/services/gravatar_service_spec.rb'
- - 'spec/services/groups/auto_devops_service_spec.rb'
- - 'spec/services/groups/autocomplete_service_spec.rb'
- - 'spec/services/groups/deploy_tokens/create_service_spec.rb'
- - 'spec/services/groups/deploy_tokens/destroy_service_spec.rb'
- - 'spec/services/groups/deploy_tokens/revoke_service_spec.rb'
- - 'spec/services/groups/group_links/create_service_spec.rb'
- - 'spec/services/groups/group_links/destroy_service_spec.rb'
- - 'spec/services/groups/group_links/update_service_spec.rb'
- - 'spec/services/groups/import_export/export_service_spec.rb'
- - 'spec/services/groups/import_export/import_service_spec.rb'
- - 'spec/services/groups/merge_requests_count_service_spec.rb'
- - 'spec/services/groups/nested_create_service_spec.rb'
- - 'spec/services/groups/open_issues_count_service_spec.rb'
- - 'spec/services/groups/participants_service_spec.rb'
- - 'spec/services/groups/update_service_spec.rb'
- - 'spec/services/groups/update_shared_runners_service_spec.rb'
- - 'spec/services/groups/update_statistics_service_spec.rb'
- - 'spec/services/ide/base_config_service_spec.rb'
- - 'spec/services/ide/schemas_config_service_spec.rb'
- - 'spec/services/ide/terminal_config_service_spec.rb'
- - 'spec/services/import/bitbucket_server_service_spec.rb'
- - 'spec/services/import/fogbugz_service_spec.rb'
- - 'spec/services/import/github/cancel_project_import_service_spec.rb'
- - 'spec/services/import/github/notes/create_service_spec.rb'
- - 'spec/services/import/github_service_spec.rb'
- - 'spec/services/import/gitlab_projects/create_project_service_spec.rb'
- - 'spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb'
- - 'spec/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3_spec.rb'
- - 'spec/services/import/prepare_service_spec.rb'
- - 'spec/services/import/validate_remote_git_endpoint_service_spec.rb'
- - 'spec/services/import_export_clean_up_service_spec.rb'
- - 'spec/services/incident_management/incidents/create_service_spec.rb'
- - 'spec/services/incident_management/issuable_escalation_statuses/after_update_service_spec.rb'
- - 'spec/services/incident_management/issuable_escalation_statuses/build_service_spec.rb'
- - 'spec/services/incident_management/issuable_escalation_statuses/create_service_spec.rb'
- - 'spec/services/incident_management/issuable_escalation_statuses/prepare_update_service_spec.rb'
- - 'spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb'
- - 'spec/services/incident_management/pager_duty/process_webhook_service_spec.rb'
- - 'spec/services/incident_management/timeline_event_tags/create_service_spec.rb'
- - 'spec/services/incident_management/timeline_events/create_service_spec.rb'
- - 'spec/services/incident_management/timeline_events/destroy_service_spec.rb'
- - 'spec/services/integrations/propagate_service_spec.rb'
- - 'spec/services/integrations/test/project_service_spec.rb'
- - 'spec/services/issuable/bulk_update_service_spec.rb'
- - 'spec/services/issuable/common_system_notes_service_spec.rb'
- - 'spec/services/issuable/destroy_label_links_service_spec.rb'
- - 'spec/services/issuable/destroy_service_spec.rb'
- - 'spec/services/issuable/discussions_list_service_spec.rb'
- - 'spec/services/issuable/process_assignees_spec.rb'
- - 'spec/services/issue_links/create_service_spec.rb'
- - 'spec/services/issue_links/destroy_service_spec.rb'
- - 'spec/services/issue_links/list_service_spec.rb'
- - 'spec/services/issues/after_create_service_spec.rb'
- - 'spec/services/issues/build_service_spec.rb'
- - 'spec/services/issues/clone_service_spec.rb'
- - 'spec/services/issues/close_service_spec.rb'
- - 'spec/services/issues/create_service_spec.rb'
- - 'spec/services/issues/duplicate_service_spec.rb'
- - 'spec/services/issues/prepare_import_csv_service_spec.rb'
- - 'spec/services/issues/referenced_merge_requests_service_spec.rb'
- - 'spec/services/issues/related_branches_service_spec.rb'
- - 'spec/services/issues/relative_position_rebalancing_service_spec.rb'
- - 'spec/services/issues/reopen_service_spec.rb'
- - 'spec/services/issues/reorder_service_spec.rb'
- - 'spec/services/issues/resolve_discussions_spec.rb'
- - 'spec/services/issues/set_crm_contacts_service_spec.rb'
- - 'spec/services/issues/update_service_spec.rb'
- - 'spec/services/issues/zoom_link_service_spec.rb'
- - 'spec/services/jira/requests/projects/list_service_spec.rb'
- - 'spec/services/jira_connect/sync_service_spec.rb'
- - 'spec/services/jira_connect_installations/destroy_service_spec.rb'
- - 'spec/services/jira_connect_subscriptions/create_service_spec.rb'
- - 'spec/services/jira_import/cloud_users_mapper_service_spec.rb'
- - 'spec/services/jira_import/server_users_mapper_service_spec.rb'
- - 'spec/services/jira_import/start_import_service_spec.rb'
- - 'spec/services/jira_import/users_importer_spec.rb'
- - 'spec/services/keys/create_service_spec.rb'
- - 'spec/services/keys/destroy_service_spec.rb'
- - 'spec/services/keys/expiry_notification_service_spec.rb'
- - 'spec/services/keys/last_used_service_spec.rb'
- - 'spec/services/labels/available_labels_service_spec.rb'
- - 'spec/services/labels/create_service_spec.rb'
- - 'spec/services/labels/find_or_create_service_spec.rb'
- - 'spec/services/labels/promote_service_spec.rb'
- - 'spec/services/labels/transfer_service_spec.rb'
- - 'spec/services/labels/update_service_spec.rb'
- - 'spec/services/lfs/lock_file_service_spec.rb'
- - 'spec/services/lfs/locks_finder_service_spec.rb'
- - 'spec/services/lfs/push_service_spec.rb'
- - 'spec/services/lfs/unlock_file_service_spec.rb'
- - 'spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb'
- - 'spec/services/loose_foreign_keys/cleaner_service_spec.rb'
- - 'spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb'
- - 'spec/services/markdown_content_rewriter_service_spec.rb'
- - 'spec/services/markup/rendering_service_spec.rb'
- - 'spec/services/members/approve_access_request_service_spec.rb'
- - 'spec/services/members/create_service_spec.rb'
- - 'spec/services/members/creator_service_spec.rb'
- - 'spec/services/members/groups/creator_service_spec.rb'
- - 'spec/services/members/import_project_team_service_spec.rb'
- - 'spec/services/members/invitation_reminder_email_service_spec.rb'
- - 'spec/services/members/invite_member_builder_spec.rb'
- - 'spec/services/members/invite_service_spec.rb'
- - 'spec/services/members/projects/creator_service_spec.rb'
- - 'spec/services/members/request_access_service_spec.rb'
- - 'spec/services/members/standard_member_builder_spec.rb'
- - 'spec/services/members/unassign_issuables_service_spec.rb'
- - 'spec/services/members/update_service_spec.rb'
- - 'spec/services/merge_requests/add_context_service_spec.rb'
- - 'spec/services/merge_requests/add_spent_time_service_spec.rb'
- - 'spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb'
- - 'spec/services/merge_requests/approval_service_spec.rb'
- - 'spec/services/merge_requests/assign_issues_service_spec.rb'
- - 'spec/services/merge_requests/cleanup_refs_service_spec.rb'
- - 'spec/services/merge_requests/conflicts/list_service_spec.rb'
- - 'spec/services/merge_requests/conflicts/resolve_service_spec.rb'
- - 'spec/services/merge_requests/create_approval_event_service_spec.rb'
- - 'spec/services/merge_requests/create_pipeline_service_spec.rb'
- - 'spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb'
- - 'spec/services/merge_requests/execute_approval_hooks_service_spec.rb'
- - 'spec/services/merge_requests/ff_merge_service_spec.rb'
- - 'spec/services/merge_requests/get_urls_service_spec.rb'
- - 'spec/services/merge_requests/handle_assignees_change_service_spec.rb'
- - 'spec/services/merge_requests/mark_reviewer_reviewed_service_spec.rb'
- - 'spec/services/merge_requests/merge_orchestration_service_spec.rb'
- - 'spec/services/merge_requests/merge_service_spec.rb'
- - 'spec/services/merge_requests/merge_to_ref_service_spec.rb'
- - 'spec/services/merge_requests/mergeability/check_base_service_spec.rb'
- - 'spec/services/merge_requests/mergeability/check_broken_status_service_spec.rb'
- - 'spec/services/merge_requests/mergeability/check_ci_status_service_spec.rb'
- - 'spec/services/merge_requests/mergeability/check_discussions_status_service_spec.rb'
- - 'spec/services/merge_requests/mergeability/check_draft_status_service_spec.rb'
- - 'spec/services/merge_requests/mergeability/check_open_status_service_spec.rb'
- - 'spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb'
- - 'spec/services/merge_requests/mergeability/logger_spec.rb'
- - 'spec/services/merge_requests/mergeability/run_checks_service_spec.rb'
- - 'spec/services/merge_requests/mergeability_check_service_spec.rb'
- - 'spec/services/merge_requests/migrate_external_diffs_service_spec.rb'
- - 'spec/services/merge_requests/post_merge_service_spec.rb'
- - 'spec/services/merge_requests/push_options_handler_service_spec.rb'
- - 'spec/services/merge_requests/reload_diffs_service_spec.rb'
- - 'spec/services/merge_requests/reload_merge_head_diff_service_spec.rb'
- - 'spec/services/merge_requests/reopen_service_spec.rb'
- - 'spec/services/merge_requests/request_review_service_spec.rb'
- - 'spec/services/merge_requests/resolve_todos_service_spec.rb'
- - 'spec/services/merge_requests/resolved_discussion_notification_service_spec.rb'
- - 'spec/services/merge_requests/squash_service_spec.rb'
- - 'spec/services/merge_requests/update_assignees_service_spec.rb'
- - 'spec/services/merge_requests/update_reviewers_service_spec.rb'
- - 'spec/services/metrics/dashboard/annotations/create_service_spec.rb'
- - 'spec/services/metrics/dashboard/annotations/delete_service_spec.rb'
- - 'spec/services/metrics/dashboard/clone_dashboard_service_spec.rb'
- - 'spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb'
- - 'spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb'
- - 'spec/services/metrics/dashboard/custom_dashboard_service_spec.rb'
- - 'spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb'
- - 'spec/services/metrics/dashboard/default_embed_service_spec.rb'
- - 'spec/services/metrics/dashboard/dynamic_embed_service_spec.rb'
- - 'spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb'
- 'spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb'
- - 'spec/services/metrics/dashboard/panel_preview_service_spec.rb'
- - 'spec/services/metrics/dashboard/pod_dashboard_service_spec.rb'
- - 'spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb'
- - '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/metrics/sample_metrics_service_spec.rb'
- - 'spec/services/metrics/users_starred_dashboards/create_service_spec.rb'
- - 'spec/services/metrics/users_starred_dashboards/delete_service_spec.rb'
- - 'spec/services/milestones/close_service_spec.rb'
- - 'spec/services/milestones/closed_issues_count_service_spec.rb'
- - 'spec/services/milestones/create_service_spec.rb'
- - 'spec/services/milestones/destroy_service_spec.rb'
- - 'spec/services/milestones/find_or_create_service_spec.rb'
- - 'spec/services/milestones/issues_count_service_spec.rb'
- - 'spec/services/milestones/merge_requests_count_service_spec.rb'
- - 'spec/services/milestones/promote_service_spec.rb'
- - 'spec/services/milestones/transfer_service_spec.rb'
- - 'spec/services/milestones/update_service_spec.rb'
- - 'spec/services/ml/experiment_tracking/candidate_repository_spec.rb'
- - 'spec/services/ml/experiment_tracking/experiment_repository_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/note_summary_spec.rb'
- - 'spec/services/notes/build_service_spec.rb'
- - 'spec/services/notes/copy_service_spec.rb'
- - 'spec/services/notes/destroy_service_spec.rb'
- - 'spec/services/notes/post_process_service_spec.rb'
- - 'spec/services/notes/quick_actions_service_spec.rb'
- - 'spec/services/notes/render_service_spec.rb'
- - 'spec/services/notes/resolve_service_spec.rb'
- - 'spec/services/notes/update_service_spec.rb'
- - 'spec/services/notification_recipients/build_service_spec.rb'
- - 'spec/services/notification_recipients/builder/default_spec.rb'
- - 'spec/services/notification_recipients/builder/new_note_spec.rb'
- - 'spec/services/onboarding/progress_service_spec.rb'
- - 'spec/services/packages/cleanup/execute_policy_service_spec.rb'
- - 'spec/services/packages/cleanup/update_policy_service_spec.rb'
- - 'spec/services/packages/composer/composer_json_service_spec.rb'
- - 'spec/services/packages/composer/create_package_service_spec.rb'
- - 'spec/services/packages/composer/version_parser_service_spec.rb'
- - 'spec/services/packages/conan/create_package_file_service_spec.rb'
- - 'spec/services/packages/conan/create_package_service_spec.rb'
- - 'spec/services/packages/create_dependency_service_spec.rb'
- - 'spec/services/packages/create_event_service_spec.rb'
- - 'spec/services/packages/create_package_file_service_spec.rb'
- - 'spec/services/packages/create_temporary_package_service_spec.rb'
- - 'spec/services/packages/generic/create_package_file_service_spec.rb'
- - 'spec/services/packages/generic/find_or_create_package_service_spec.rb'
- - 'spec/services/packages/go/create_package_service_spec.rb'
- - 'spec/services/packages/go/sync_packages_service_spec.rb'
- - 'spec/services/packages/helm/extract_file_metadata_service_spec.rb'
- - 'spec/services/packages/helm/process_file_service_spec.rb'
- - 'spec/services/packages/mark_package_files_for_destruction_service_spec.rb'
- - 'spec/services/packages/mark_package_for_destruction_service_spec.rb'
- - 'spec/services/packages/mark_packages_for_destruction_service_spec.rb'
- - 'spec/services/packages/maven/create_package_service_spec.rb'
- - 'spec/services/packages/maven/find_or_create_package_service_spec.rb'
- - 'spec/services/packages/maven/metadata/append_package_file_service_spec.rb'
- - 'spec/services/packages/maven/metadata/create_plugins_xml_service_spec.rb'
- - 'spec/services/packages/maven/metadata/create_versions_xml_service_spec.rb'
- - 'spec/services/packages/maven/metadata/sync_service_spec.rb'
- - 'spec/services/packages/npm/create_package_service_spec.rb'
- - 'spec/services/packages/npm/create_tag_service_spec.rb'
- - 'spec/services/packages/nuget/create_dependency_service_spec.rb'
- - 'spec/services/packages/nuget/metadata_extraction_service_spec.rb'
- - 'spec/services/packages/nuget/search_service_spec.rb'
- - 'spec/services/packages/nuget/sync_metadatum_service_spec.rb'
- - 'spec/services/packages/nuget/update_package_from_metadata_service_spec.rb'
- - 'spec/services/packages/pypi/create_package_service_spec.rb'
- - 'spec/services/packages/remove_tag_service_spec.rb'
- - 'spec/services/packages/rpm/parse_package_service_spec.rb'
- - 'spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb'
- - 'spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb'
- - 'spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb'
- - 'spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb'
- - 'spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb'
- - 'spec/services/packages/rubygems/create_dependencies_service_spec.rb'
- - 'spec/services/packages/rubygems/create_gemspec_service_spec.rb'
- - 'spec/services/packages/rubygems/dependency_resolver_service_spec.rb'
- - 'spec/services/packages/rubygems/metadata_extraction_service_spec.rb'
- - 'spec/services/packages/rubygems/process_gem_service_spec.rb'
- - 'spec/services/packages/terraform_module/create_package_service_spec.rb'
- - 'spec/services/packages/update_package_file_service_spec.rb'
- - 'spec/services/packages/update_tags_service_spec.rb'
- - 'spec/services/pages/delete_service_spec.rb'
- - 'spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb'
- - 'spec/services/pages/zip_directory_service_spec.rb'
- - 'spec/services/pages_domains/create_acme_order_service_spec.rb'
- - 'spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb'
- - 'spec/services/personal_access_tokens/create_service_spec.rb'
- - 'spec/services/personal_access_tokens/last_used_service_spec.rb'
- - 'spec/services/personal_access_tokens/revoke_service_spec.rb'
- - 'spec/services/post_receive_service_spec.rb'
- - 'spec/services/preview_markdown_service_spec.rb'
- - 'spec/services/product_analytics/build_activity_graph_service_spec.rb'
- - 'spec/services/product_analytics/build_graph_service_spec.rb'
- - 'spec/services/projects/after_rename_service_spec.rb'
- - 'spec/services/projects/alerting/notify_service_spec.rb'
- - 'spec/services/projects/all_issues_count_service_spec.rb'
- - 'spec/services/projects/all_merge_requests_count_service_spec.rb'
- - 'spec/services/projects/android_target_platform_detector_service_spec.rb'
- - 'spec/services/projects/apple_target_platform_detector_service_spec.rb'
- - 'spec/services/projects/auto_devops/disable_service_spec.rb'
- - 'spec/services/projects/autocomplete_service_spec.rb'
- - 'spec/services/projects/batch_open_issues_count_service_spec.rb'
- - 'spec/services/projects/blame_service_spec.rb'
- - 'spec/services/projects/branches_by_mode_service_spec.rb'
- - 'spec/services/projects/cleanup_service_spec.rb'
- - 'spec/services/projects/container_repository/cleanup_tags_service_spec.rb'
- - 'spec/services/projects/container_repository/delete_tags_service_spec.rb'
- - 'spec/services/projects/container_repository/destroy_service_spec.rb'
- - 'spec/services/projects/container_repository/gitlab/cleanup_tags_service_spec.rb'
- - 'spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb'
- - 'spec/services/projects/container_repository/third_party/cleanup_tags_service_spec.rb'
- - 'spec/services/projects/container_repository/third_party/delete_tags_service_spec.rb'
- - 'spec/services/projects/count_service_spec.rb'
- - 'spec/services/projects/create_from_template_service_spec.rb'
- - 'spec/services/projects/deploy_tokens/create_service_spec.rb'
- - 'spec/services/projects/deploy_tokens/destroy_service_spec.rb'
- - 'spec/services/projects/detect_repository_languages_service_spec.rb'
- - 'spec/services/projects/download_service_spec.rb'
- - 'spec/services/projects/enable_deploy_key_service_spec.rb'
- - 'spec/services/projects/fork_service_spec.rb'
- - 'spec/services/projects/forks_count_service_spec.rb'
- - 'spec/services/projects/git_deduplication_service_spec.rb'
- - 'spec/services/projects/gitlab_projects_import_service_spec.rb'
- - 'spec/services/projects/group_links/create_service_spec.rb'
- - 'spec/services/projects/group_links/destroy_service_spec.rb'
- - 'spec/services/projects/group_links/update_service_spec.rb'
- - 'spec/services/projects/hashed_storage/base_attachment_service_spec.rb'
- - 'spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb'
- - 'spec/services/projects/hashed_storage/migrate_repository_service_spec.rb'
- - 'spec/services/projects/hashed_storage/migration_service_spec.rb'
- - 'spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb'
- - 'spec/services/projects/hashed_storage/rollback_repository_service_spec.rb'
- - 'spec/services/projects/hashed_storage/rollback_service_spec.rb'
- - 'spec/services/projects/import_error_filter_spec.rb'
- - 'spec/services/projects/import_export/relation_export_service_spec.rb'
- - 'spec/services/projects/in_product_marketing_campaign_emails_service_spec.rb'
- - 'spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb'
- - 'spec/services/projects/lfs_pointers/lfs_download_service_spec.rb'
- - 'spec/services/projects/lfs_pointers/lfs_import_service_spec.rb'
- - 'spec/services/projects/lfs_pointers/lfs_link_service_spec.rb'
- - 'spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb'
- - 'spec/services/projects/move_access_service_spec.rb'
- - 'spec/services/projects/move_deploy_keys_projects_service_spec.rb'
- - 'spec/services/projects/move_forks_service_spec.rb'
- - 'spec/services/projects/move_lfs_objects_projects_service_spec.rb'
- - 'spec/services/projects/move_notification_settings_service_spec.rb'
- - 'spec/services/projects/move_project_authorizations_service_spec.rb'
- - 'spec/services/projects/move_project_group_links_service_spec.rb'
- - 'spec/services/projects/move_project_members_service_spec.rb'
- - 'spec/services/projects/move_users_star_projects_service_spec.rb'
- - 'spec/services/projects/open_issues_count_service_spec.rb'
- - 'spec/services/projects/open_merge_requests_count_service_spec.rb'
- - 'spec/services/projects/operations/update_service_spec.rb'
- - 'spec/services/projects/overwrite_project_service_spec.rb'
- - 'spec/services/projects/participants_service_spec.rb'
- - 'spec/services/projects/prometheus/alerts/notify_service_spec.rb'
- - 'spec/services/projects/prometheus/metrics/destroy_service_spec.rb'
- - 'spec/services/projects/protect_default_branch_service_spec.rb'
- - 'spec/services/projects/readme_renderer_service_spec.rb'
- - 'spec/services/projects/record_target_platforms_service_spec.rb'
- - 'spec/services/projects/refresh_build_artifacts_size_statistics_service_spec.rb'
- - 'spec/services/projects/repository_languages_service_spec.rb'
- - 'spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb'
- - 'spec/services/projects/transfer_service_spec.rb'
- - 'spec/services/projects/unlink_fork_service_spec.rb'
- - 'spec/services/projects/update_pages_service_spec.rb'
- - 'spec/services/projects/update_remote_mirror_service_spec.rb'
- - 'spec/services/projects/update_repository_storage_service_spec.rb'
- - 'spec/services/projects/update_service_spec.rb'
- - 'spec/services/projects/update_statistics_service_spec.rb'
- - 'spec/services/prometheus/proxy_service_spec.rb'
- - 'spec/services/prometheus/proxy_variable_substitution_service_spec.rb'
- - 'spec/services/protected_branches/api_service_spec.rb'
- - 'spec/services/protected_branches/cache_service_spec.rb'
- - 'spec/services/protected_branches/destroy_service_spec.rb'
- - 'spec/services/protected_branches/update_service_spec.rb'
- - 'spec/services/protected_tags/create_service_spec.rb'
- - 'spec/services/protected_tags/destroy_service_spec.rb'
- - 'spec/services/protected_tags/update_service_spec.rb'
- - 'spec/services/push_event_payload_service_spec.rb'
- - 'spec/services/quick_actions/target_service_spec.rb'
- - 'spec/services/releases/create_evidence_service_spec.rb'
- - 'spec/services/releases/destroy_service_spec.rb'
- - 'spec/services/repositories/changelog_service_spec.rb'
- - 'spec/services/repositories/destroy_service_spec.rb'
- - 'spec/services/repository_archive_clean_up_service_spec.rb'
- - 'spec/services/reset_project_cache_service_spec.rb'
- - 'spec/services/resource_access_tokens/create_service_spec.rb'
- - 'spec/services/resource_access_tokens/revoke_service_spec.rb'
- - 'spec/services/resource_events/change_milestone_service_spec.rb'
- - 'spec/services/resource_events/change_state_service_spec.rb'
- - 'spec/services/resource_events/merge_into_notes_service_spec.rb'
- - 'spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb'
- - 'spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb'
- - 'spec/services/resource_events/synthetic_state_notes_builder_service_spec.rb'
- - 'spec/services/search/global_service_spec.rb'
- - 'spec/services/search/group_service_spec.rb'
- - 'spec/services/search/snippet_service_spec.rb'
- - 'spec/services/security/ci_configuration/container_scanning_create_service_spec.rb'
- - 'spec/services/security/ci_configuration/sast_iac_create_service_spec.rb'
- - 'spec/services/security/ci_configuration/sast_parser_service_spec.rb'
- - 'spec/services/security/ci_configuration/secret_detection_create_service_spec.rb'
- - 'spec/services/security/merge_reports_service_spec.rb'
- - 'spec/services/serverless/associate_domain_service_spec.rb'
- - 'spec/services/service_desk_settings/update_service_spec.rb'
- - 'spec/services/service_ping/submit_service_ping_service_spec.rb'
- - 'spec/services/service_response_spec.rb'
- - 'spec/services/snippets/bulk_destroy_service_spec.rb'
- - 'spec/services/snippets/count_service_spec.rb'
- - 'spec/services/snippets/create_service_spec.rb'
- - 'spec/services/snippets/destroy_service_spec.rb'
- - 'spec/services/snippets/repository_validation_service_spec.rb'
- - 'spec/services/snippets/schedule_bulk_repository_shard_moves_service_spec.rb'
- - 'spec/services/snippets/update_repository_storage_service_spec.rb'
- - 'spec/services/snippets/update_service_spec.rb'
- - 'spec/services/snippets/update_statistics_service_spec.rb'
- - 'spec/services/spam/akismet_mark_as_spam_service_spec.rb'
- - 'spec/services/spam/akismet_service_spec.rb'
- - 'spec/services/spam/ham_service_spec.rb'
- - 'spec/services/spam/spam_action_service_spec.rb'
- - 'spec/services/spam/spam_params_spec.rb'
- - 'spec/services/spam/spam_verdict_service_spec.rb'
- - 'spec/services/submodules/update_service_spec.rb'
- - 'spec/services/suggestions/apply_service_spec.rb'
- - 'spec/services/suggestions/create_service_spec.rb'
- - 'spec/services/suggestions/outdate_service_spec.rb'
- - 'spec/services/system_hooks_service_spec.rb'
- - 'spec/services/system_notes/alert_management_service_spec.rb'
- - 'spec/services/system_notes/base_service_spec.rb'
- - 'spec/services/system_notes/commit_service_spec.rb'
- - 'spec/services/system_notes/design_management_service_spec.rb'
- - 'spec/services/system_notes/incident_service_spec.rb'
- - 'spec/services/system_notes/incidents_service_spec.rb'
- - 'spec/services/system_notes/issuables_service_spec.rb'
- - 'spec/services/system_notes/merge_requests_service_spec.rb'
- - 'spec/services/system_notes/time_tracking_service_spec.rb'
- - 'spec/services/system_notes/zoom_service_spec.rb'
- - 'spec/services/tags/create_service_spec.rb'
- - 'spec/services/tags/destroy_service_spec.rb'
- - 'spec/services/task_list_toggle_service_spec.rb'
- - 'spec/services/tasks_to_be_done/base_service_spec.rb'
- - 'spec/services/terraform/remote_state_handler_spec.rb'
- - 'spec/services/terraform/states/destroy_service_spec.rb'
- - 'spec/services/terraform/states/trigger_destroy_service_spec.rb'
- - 'spec/services/test_hooks/project_service_spec.rb'
- - 'spec/services/test_hooks/system_service_spec.rb'
- - 'spec/services/timelogs/delete_service_spec.rb'
- - 'spec/services/todo_service_spec.rb'
- - 'spec/services/todos/allowed_target_filter_service_spec.rb'
- - 'spec/services/todos/destroy/confidential_issue_service_spec.rb'
- - 'spec/services/todos/destroy/design_service_spec.rb'
- - 'spec/services/todos/destroy/destroyed_issuable_service_spec.rb'
- - 'spec/services/todos/destroy/project_private_service_spec.rb'
- - 'spec/services/todos/destroy/unauthorized_features_service_spec.rb'
- - 'spec/services/topics/merge_service_spec.rb'
- - 'spec/services/two_factor/destroy_service_spec.rb'
- - 'spec/services/update_container_registry_info_service_spec.rb'
- - 'spec/services/update_merge_request_metrics_service_spec.rb'
- - 'spec/services/upload_service_spec.rb'
- - 'spec/services/uploads/destroy_service_spec.rb'
- - 'spec/services/user_preferences/update_service_spec.rb'
- - 'spec/services/users/activity_service_spec.rb'
- - 'spec/services/users/approve_service_spec.rb'
- - 'spec/services/users/authorized_build_service_spec.rb'
- - 'spec/services/users/ban_service_spec.rb'
- - 'spec/services/users/banned_user_base_service_spec.rb'
- - 'spec/services/users/batch_status_cleaner_service_spec.rb'
- - 'spec/services/users/block_service_spec.rb'
- - 'spec/services/users/build_service_spec.rb'
- - 'spec/services/users/create_service_spec.rb'
- - 'spec/services/users/destroy_service_spec.rb'
- - 'spec/services/users/dismiss_callout_service_spec.rb'
- - 'spec/services/users/dismiss_group_callout_service_spec.rb'
- - 'spec/services/users/dismiss_project_callout_service_spec.rb'
- - 'spec/services/users/email_verification/generate_token_service_spec.rb'
- - 'spec/services/users/email_verification/validate_token_service_spec.rb'
- - 'spec/services/users/in_product_marketing_email_records_spec.rb'
- - 'spec/services/users/keys_count_service_spec.rb'
- - 'spec/services/users/last_push_event_service_spec.rb'
- - 'spec/services/users/migrate_records_to_ghost_user_in_batches_service_spec.rb'
- - 'spec/services/users/migrate_records_to_ghost_user_service_spec.rb'
- - 'spec/services/users/refresh_authorized_projects_service_spec.rb'
- - 'spec/services/users/registrations_build_service_spec.rb'
- - 'spec/services/users/reject_service_spec.rb'
- - 'spec/services/users/repair_ldap_blocked_service_spec.rb'
- - 'spec/services/users/respond_to_terms_service_spec.rb'
- - 'spec/services/users/saved_replies/create_service_spec.rb'
- - 'spec/services/users/saved_replies/destroy_service_spec.rb'
- - 'spec/services/users/saved_replies/update_service_spec.rb'
- - 'spec/services/users/set_status_service_spec.rb'
- - 'spec/services/users/signup_service_spec.rb'
- - 'spec/services/users/unban_service_spec.rb'
- - 'spec/services/users/unblock_service_spec.rb'
- - 'spec/services/users/update_canonical_email_service_spec.rb'
- - 'spec/services/users/update_highest_member_role_service_spec.rb'
- - 'spec/services/users/update_service_spec.rb'
- - 'spec/services/users/update_todo_count_cache_service_spec.rb'
- - 'spec/services/users/upsert_credit_card_validation_service_spec.rb'
- - 'spec/services/users/validate_manual_otp_service_spec.rb'
- - 'spec/services/users/validate_push_otp_service_spec.rb'
- - 'spec/services/verify_pages_domain_service_spec.rb'
- - 'spec/services/web_hooks/destroy_service_spec.rb'
- - 'spec/services/web_hooks/log_destroy_service_spec.rb'
- - 'spec/services/web_hooks/log_execution_service_spec.rb'
- - 'spec/services/webauthn/authenticate_service_spec.rb'
- - 'spec/services/webauthn/register_service_spec.rb'
- - 'spec/services/wiki_pages/base_service_spec.rb'
- - 'spec/services/wiki_pages/create_service_spec.rb'
- - 'spec/services/wiki_pages/destroy_service_spec.rb'
- - 'spec/services/wiki_pages/event_create_service_spec.rb'
- - 'spec/services/wiki_pages/update_service_spec.rb'
- - 'spec/services/wikis/create_attachment_service_spec.rb'
- - 'spec/services/work_items/build_service_spec.rb'
- - 'spec/services/work_items/create_from_task_service_spec.rb'
- - 'spec/services/work_items/create_service_spec.rb'
- - 'spec/services/work_items/delete_service_spec.rb'
- - 'spec/services/work_items/delete_task_service_spec.rb'
- - 'spec/services/work_items/parent_links/destroy_service_spec.rb'
- - 'spec/services/work_items/task_list_reference_removal_service_spec.rb'
- - 'spec/services/work_items/task_list_reference_replacement_service_spec.rb'
- - 'spec/services/work_items/update_service_spec.rb'
- - 'spec/services/work_items/widgets/assignees_service/update_service_spec.rb'
- - 'spec/services/work_items/widgets/description_service/update_service_spec.rb'
- - 'spec/services/work_items/widgets/milestone_service/create_service_spec.rb'
- - 'spec/services/work_items/widgets/milestone_service/update_service_spec.rb'
- - 'spec/services/work_items/widgets/start_and_due_date_service/update_service_spec.rb'
- - 'spec/services/x509_certificate_revoke_service_spec.rb'
- 'spec/sidekiq/cron/job_gem_dependency_spec.rb'
- 'spec/sidekiq_cluster/sidekiq_cluster_spec.rb'
- 'spec/spam/concerns/has_spam_action_response_fields_spec.rb'
@@ -7679,7 +6149,6 @@ RSpec/MissingFeatureCategory:
- 'spec/uploaders/favicon_uploader_spec.rb'
- 'spec/uploaders/file_mover_spec.rb'
- 'spec/uploaders/file_uploader_spec.rb'
- - 'spec/uploaders/gitlab_uploader_spec.rb'
- 'spec/uploaders/import_export_uploader_spec.rb'
- 'spec/uploaders/job_artifact_uploader_spec.rb'
- 'spec/uploaders/lfs_object_uploader_spec.rb'
@@ -7855,353 +6324,6 @@ RSpec/MissingFeatureCategory:
- 'spec/views/shared/ssh_keys/_key_delete.html.haml_spec.rb'
- 'spec/views/shared/web_hooks/_web_hook_disabled_alert.html.haml_spec.rb'
- 'spec/views/shared/wikis/_sidebar.html.haml_spec.rb'
- - 'spec/workers/admin_email_worker_spec.rb'
- - 'spec/workers/analytics/usage_trends/count_job_trigger_worker_spec.rb'
- - 'spec/workers/analytics/usage_trends/counter_job_worker_spec.rb'
- - 'spec/workers/approve_blocked_pending_approval_users_worker_spec.rb'
- - 'spec/workers/authorized_keys_worker_spec.rb'
- - 'spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb'
- - 'spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb'
- - 'spec/workers/authorized_project_update/project_recalculate_worker_spec.rb'
- - 'spec/workers/authorized_project_update/user_refresh_from_replica_worker_spec.rb'
- - 'spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb'
- - 'spec/workers/authorized_project_update/user_refresh_with_low_urgency_worker_spec.rb'
- - 'spec/workers/authorized_projects_worker_spec.rb'
- - 'spec/workers/auto_devops/disable_worker_spec.rb'
- - 'spec/workers/auto_merge_process_worker_spec.rb'
- - 'spec/workers/background_migration/ci_database_worker_spec.rb'
- - 'spec/workers/background_migration_worker_spec.rb'
- - 'spec/workers/build_hooks_worker_spec.rb'
- - 'spec/workers/build_queue_worker_spec.rb'
- - 'spec/workers/build_success_worker_spec.rb'
- - 'spec/workers/bulk_imports/entity_worker_spec.rb'
- - 'spec/workers/bulk_imports/relation_export_worker_spec.rb'
- - 'spec/workers/bulk_imports/stuck_import_worker_spec.rb'
- - 'spec/workers/chat_notification_worker_spec.rb'
- - 'spec/workers/ci/archive_trace_worker_spec.rb'
- - 'spec/workers/ci/build_finished_worker_spec.rb'
- - 'spec/workers/ci/build_prepare_worker_spec.rb'
- - 'spec/workers/ci/build_schedule_worker_spec.rb'
- - 'spec/workers/ci/build_trace_chunk_flush_worker_spec.rb'
- - 'spec/workers/ci/cancel_pipeline_worker_spec.rb'
- - 'spec/workers/ci/create_cross_project_pipeline_worker_spec.rb'
- - 'spec/workers/ci/create_downstream_pipeline_worker_spec.rb'
- - 'spec/workers/ci/daily_build_group_report_results_worker_spec.rb'
- - 'spec/workers/ci/delete_objects_worker_spec.rb'
- - 'spec/workers/ci/delete_unit_tests_worker_spec.rb'
- - 'spec/workers/ci/drop_pipeline_worker_spec.rb'
- - 'spec/workers/ci/job_artifacts/expire_project_build_artifacts_worker_spec.rb'
- - 'spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb'
- - 'spec/workers/ci/merge_requests/add_todo_when_build_fails_worker_spec.rb'
- - 'spec/workers/ci/parse_secure_file_metadata_worker_spec.rb'
- - 'spec/workers/ci/pending_builds/update_group_worker_spec.rb'
- - 'spec/workers/ci/pending_builds/update_project_worker_spec.rb'
- - 'spec/workers/ci/pipeline_artifacts/coverage_report_worker_spec.rb'
- - 'spec/workers/ci/pipeline_artifacts/create_quality_report_worker_spec.rb'
- - 'spec/workers/ci/pipeline_artifacts/expire_artifacts_worker_spec.rb'
- - 'spec/workers/ci/pipeline_bridge_status_worker_spec.rb'
- - 'spec/workers/ci/pipeline_success_unlock_artifacts_worker_spec.rb'
- - 'spec/workers/ci/ref_delete_unlock_artifacts_worker_spec.rb'
- - 'spec/workers/ci/resource_groups/assign_resource_from_resource_group_worker_spec.rb'
- - 'spec/workers/ci/retry_pipeline_worker_spec.rb'
- - 'spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb'
- - 'spec/workers/ci/stuck_builds/drop_running_worker_spec.rb'
- - 'spec/workers/ci/stuck_builds/drop_scheduled_worker_spec.rb'
- - 'spec/workers/ci/test_failure_history_worker_spec.rb'
- - 'spec/workers/ci/track_failed_build_worker_spec.rb'
- - 'spec/workers/ci/update_locked_unknown_artifacts_worker_spec.rb'
- - 'spec/workers/ci_platform_metrics_update_cron_worker_spec.rb'
- - 'spec/workers/cleanup_container_repository_worker_spec.rb'
- - 'spec/workers/clusters/agents/delete_expired_events_worker_spec.rb'
- - 'spec/workers/clusters/applications/activate_integration_worker_spec.rb'
- - 'spec/workers/clusters/applications/deactivate_integration_worker_spec.rb'
- - 'spec/workers/clusters/cleanup/project_namespace_worker_spec.rb'
- - 'spec/workers/clusters/cleanup/service_account_worker_spec.rb'
- - 'spec/workers/clusters/integrations/check_prometheus_health_worker_spec.rb'
- - 'spec/workers/concerns/application_worker_spec.rb'
- - 'spec/workers/concerns/cluster_agent_queue_spec.rb'
- - 'spec/workers/concerns/cluster_queue_spec.rb'
- - 'spec/workers/concerns/cronjob_queue_spec.rb'
- - 'spec/workers/concerns/gitlab/github_import/object_importer_spec.rb'
- - 'spec/workers/concerns/gitlab/github_import/queue_spec.rb'
- - 'spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb'
- - 'spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb'
- - 'spec/workers/concerns/gitlab/notify_upon_death_spec.rb'
- - 'spec/workers/concerns/limited_capacity/job_tracker_spec.rb'
- - 'spec/workers/concerns/limited_capacity/worker_spec.rb'
- - 'spec/workers/concerns/packages/cleanup_artifact_worker_spec.rb'
- - 'spec/workers/concerns/pipeline_background_queue_spec.rb'
- - 'spec/workers/concerns/pipeline_queue_spec.rb'
- - 'spec/workers/concerns/project_import_options_spec.rb'
- 'spec/workers/concerns/reenqueuer_spec.rb'
- - 'spec/workers/concerns/repository_check_queue_spec.rb'
- - 'spec/workers/concerns/waitable_worker_spec.rb'
- - 'spec/workers/concerns/worker_attributes_spec.rb'
- - 'spec/workers/concerns/worker_context_spec.rb'
- - 'spec/workers/container_expiration_policies/cleanup_container_repository_worker_spec.rb'
- - 'spec/workers/container_expiration_policy_worker_spec.rb'
- - 'spec/workers/container_registry/cleanup_worker_spec.rb'
- - 'spec/workers/container_registry/delete_container_repository_worker_spec.rb'
- - 'spec/workers/container_registry/migration/enqueuer_worker_spec.rb'
- - 'spec/workers/container_registry/migration/guard_worker_spec.rb'
- - 'spec/workers/container_registry/migration/observer_worker_spec.rb'
- - 'spec/workers/counters/cleanup_refresh_worker_spec.rb'
- - 'spec/workers/create_commit_signature_worker_spec.rb'
- - 'spec/workers/create_note_diff_file_worker_spec.rb'
- - 'spec/workers/create_pipeline_worker_spec.rb'
- - 'spec/workers/database/batched_background_migration/ci_database_worker_spec.rb'
- - 'spec/workers/database/batched_background_migration_worker_spec.rb'
- - 'spec/workers/database/ci_namespace_mirrors_consistency_check_worker_spec.rb'
- - 'spec/workers/database/ci_project_mirrors_consistency_check_worker_spec.rb'
- - 'spec/workers/database/drop_detached_partitions_worker_spec.rb'
- - 'spec/workers/database/partition_management_worker_spec.rb'
- - 'spec/workers/delete_container_repository_worker_spec.rb'
- - 'spec/workers/delete_diff_files_worker_spec.rb'
- - 'spec/workers/delete_merged_branches_worker_spec.rb'
- - 'spec/workers/delete_user_worker_spec.rb'
- - 'spec/workers/dependency_proxy/cleanup_blob_worker_spec.rb'
- - 'spec/workers/dependency_proxy/cleanup_dependency_proxy_worker_spec.rb'
- - 'spec/workers/dependency_proxy/cleanup_manifest_worker_spec.rb'
- - 'spec/workers/dependency_proxy/image_ttl_group_policy_worker_spec.rb'
- - 'spec/workers/deployments/archive_in_project_worker_spec.rb'
- - 'spec/workers/deployments/drop_older_deployments_worker_spec.rb'
- - 'spec/workers/deployments/hooks_worker_spec.rb'
- - 'spec/workers/deployments/link_merge_request_worker_spec.rb'
- - 'spec/workers/deployments/update_environment_worker_spec.rb'
- - 'spec/workers/design_management/copy_design_collection_worker_spec.rb'
- - 'spec/workers/design_management/new_version_worker_spec.rb'
- - 'spec/workers/destroy_pages_deployments_worker_spec.rb'
- - 'spec/workers/detect_repository_languages_worker_spec.rb'
- - 'spec/workers/disallow_two_factor_for_group_worker_spec.rb'
- - 'spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb'
- - 'spec/workers/email_receiver_worker_spec.rb'
- - 'spec/workers/emails_on_push_worker_spec.rb'
- - 'spec/workers/environments/auto_delete_cron_worker_spec.rb'
- - 'spec/workers/environments/auto_stop_cron_worker_spec.rb'
- - 'spec/workers/environments/auto_stop_worker_spec.rb'
- - 'spec/workers/environments/canary_ingress/update_worker_spec.rb'
- - 'spec/workers/error_tracking_issue_link_worker_spec.rb'
- - 'spec/workers/every_sidekiq_worker_spec.rb'
- - 'spec/workers/expire_build_artifacts_worker_spec.rb'
- - 'spec/workers/export_csv_worker_spec.rb'
- - 'spec/workers/external_service_reactive_caching_worker_spec.rb'
- - 'spec/workers/file_hook_worker_spec.rb'
- - 'spec/workers/flush_counter_increments_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/advance_stage_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/attachments/import_issue_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/attachments/import_merge_request_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/attachments/import_note_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/attachments/import_release_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_issue_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_note_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_protected_branch_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_pull_request_merged_by_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_pull_request_review_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/import_release_attachments_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_attachments_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_issue_events_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_protected_branches_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb'
- - 'spec/workers/gitlab/import/stuck_import_job_spec.rb'
- - 'spec/workers/gitlab/import/stuck_project_import_jobs_worker_spec.rb'
- - 'spec/workers/gitlab/jira_import/import_issue_worker_spec.rb'
- - 'spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb'
- - 'spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb'
- - 'spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb'
- - 'spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb'
- - 'spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb'
- - 'spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb'
- - 'spec/workers/gitlab/jira_import/stuck_jira_import_jobs_worker_spec.rb'
- - 'spec/workers/gitlab/phabricator_import/base_worker_spec.rb'
- - 'spec/workers/gitlab/phabricator_import/import_tasks_worker_spec.rb'
- - 'spec/workers/gitlab_performance_bar_stats_worker_spec.rb'
- - 'spec/workers/gitlab_service_ping_worker_spec.rb'
- - 'spec/workers/gitlab_shell_worker_spec.rb'
- - 'spec/workers/google_cloud/create_cloudsql_instance_worker_spec.rb'
- - 'spec/workers/group_destroy_worker_spec.rb'
- - 'spec/workers/group_export_worker_spec.rb'
- - 'spec/workers/group_import_worker_spec.rb'
- - 'spec/workers/groups/update_statistics_worker_spec.rb'
- - 'spec/workers/groups/update_two_factor_requirement_for_members_worker_spec.rb'
- - 'spec/workers/hashed_storage/migrator_worker_spec.rb'
- - 'spec/workers/hashed_storage/project_migrate_worker_spec.rb'
- - 'spec/workers/hashed_storage/project_rollback_worker_spec.rb'
- - 'spec/workers/hashed_storage/rollbacker_worker_spec.rb'
- - 'spec/workers/import_issues_csv_worker_spec.rb'
- - 'spec/workers/incident_management/add_severity_system_note_worker_spec.rb'
- - 'spec/workers/incident_management/close_incident_worker_spec.rb'
- - 'spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb'
- - 'spec/workers/incident_management/process_alert_worker_v2_spec.rb'
- - 'spec/workers/integrations/create_external_cross_reference_worker_spec.rb'
- - 'spec/workers/integrations/execute_worker_spec.rb'
- - 'spec/workers/integrations/irker_worker_spec.rb'
- - 'spec/workers/invalid_gpg_signature_update_worker_spec.rb'
- - 'spec/workers/issuable/label_links_destroy_worker_spec.rb'
- - 'spec/workers/issuable_export_csv_worker_spec.rb'
- - 'spec/workers/issuables/clear_groups_issue_counter_worker_spec.rb'
- - 'spec/workers/issue_due_scheduler_worker_spec.rb'
- - 'spec/workers/issues/close_worker_spec.rb'
- - 'spec/workers/issues/placement_worker_spec.rb'
- - 'spec/workers/issues/rebalancing_worker_spec.rb'
- - 'spec/workers/issues/reschedule_stuck_issue_rebalances_worker_spec.rb'
- - 'spec/workers/jira_connect/forward_event_worker_spec.rb'
- - 'spec/workers/jira_connect/retry_request_worker_spec.rb'
- - 'spec/workers/jira_connect/sync_branch_worker_spec.rb'
- - 'spec/workers/jira_connect/sync_builds_worker_spec.rb'
- - 'spec/workers/jira_connect/sync_deployments_worker_spec.rb'
- - 'spec/workers/jira_connect/sync_feature_flags_worker_spec.rb'
- - 'spec/workers/jira_connect/sync_merge_request_worker_spec.rb'
- - 'spec/workers/jira_connect/sync_project_worker_spec.rb'
- - 'spec/workers/loose_foreign_keys/cleanup_worker_spec.rb'
- - 'spec/workers/mail_scheduler/issue_due_worker_spec.rb'
- - 'spec/workers/mail_scheduler/notification_service_worker_spec.rb'
- - 'spec/workers/member_invitation_reminder_emails_worker_spec.rb'
- - 'spec/workers/members_destroyer/unassign_issuables_worker_spec.rb'
- - 'spec/workers/merge_request_cleanup_refs_worker_spec.rb'
- - 'spec/workers/merge_request_mergeability_check_worker_spec.rb'
- - 'spec/workers/merge_requests/close_issue_worker_spec.rb'
- - 'spec/workers/merge_requests/create_approval_event_worker_spec.rb'
- - 'spec/workers/merge_requests/create_approval_note_worker_spec.rb'
- - 'spec/workers/merge_requests/delete_source_branch_worker_spec.rb'
- - 'spec/workers/merge_requests/execute_approval_hooks_worker_spec.rb'
- - 'spec/workers/merge_requests/handle_assignees_change_worker_spec.rb'
- - 'spec/workers/merge_requests/resolve_todos_after_approval_worker_spec.rb'
- - 'spec/workers/merge_requests/resolve_todos_worker_spec.rb'
- - 'spec/workers/merge_requests/update_head_pipeline_worker_spec.rb'
- - 'spec/workers/merge_worker_spec.rb'
- - 'spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb'
- - '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'
- - 'spec/workers/namespaces/schedule_aggregation_worker_spec.rb'
- - 'spec/workers/namespaces/update_root_statistics_worker_spec.rb'
- - 'spec/workers/new_issue_worker_spec.rb'
- - 'spec/workers/new_note_worker_spec.rb'
- - 'spec/workers/object_pool/create_worker_spec.rb'
- - 'spec/workers/object_pool/destroy_worker_spec.rb'
- - 'spec/workers/object_pool/join_worker_spec.rb'
- - 'spec/workers/onboarding/issue_created_worker_spec.rb'
- - 'spec/workers/onboarding/pipeline_created_worker_spec.rb'
- - 'spec/workers/onboarding/progress_worker_spec.rb'
- - 'spec/workers/onboarding/user_added_worker_spec.rb'
- - 'spec/workers/packages/cleanup/execute_policy_worker_spec.rb'
- - 'spec/workers/packages/cleanup_package_file_worker_spec.rb'
- - 'spec/workers/packages/cleanup_package_registry_worker_spec.rb'
- - 'spec/workers/packages/composer/cache_cleanup_worker_spec.rb'
- - 'spec/workers/packages/composer/cache_update_worker_spec.rb'
- - 'spec/workers/packages/go/sync_packages_worker_spec.rb'
- - 'spec/workers/packages/helm/extraction_worker_spec.rb'
- - 'spec/workers/packages/mark_package_files_for_destruction_worker_spec.rb'
- 'spec/workers/packages/maven/metadata/sync_worker_spec.rb'
- - 'spec/workers/packages/nuget/extraction_worker_spec.rb'
- - 'spec/workers/packages/rubygems/extraction_worker_spec.rb'
- - 'spec/workers/pages_domain_removal_cron_worker_spec.rb'
- - 'spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb'
- - 'spec/workers/pages_domain_ssl_renewal_worker_spec.rb'
- - 'spec/workers/pages_domain_verification_cron_worker_spec.rb'
- - 'spec/workers/pages_domain_verification_worker_spec.rb'
- - 'spec/workers/pages_worker_spec.rb'
- - 'spec/workers/partition_creation_worker_spec.rb'
- - 'spec/workers/personal_access_tokens/expired_notification_worker_spec.rb'
- - 'spec/workers/personal_access_tokens/expiring_worker_spec.rb'
- - 'spec/workers/pipeline_hooks_worker_spec.rb'
- - 'spec/workers/pipeline_metrics_worker_spec.rb'
- - 'spec/workers/pipeline_notification_worker_spec.rb'
- - 'spec/workers/pipeline_process_worker_spec.rb'
- - 'spec/workers/post_receive_spec.rb'
- - 'spec/workers/process_commit_worker_spec.rb'
- - 'spec/workers/project_cache_worker_spec.rb'
- - 'spec/workers/project_destroy_worker_spec.rb'
- - 'spec/workers/project_export_worker_spec.rb'
- - 'spec/workers/projects/after_import_worker_spec.rb'
- - 'spec/workers/projects/finalize_project_statistics_refresh_worker_spec.rb'
- - 'spec/workers/projects/import_export/relation_export_worker_spec.rb'
- - 'spec/workers/projects/inactive_projects_deletion_cron_worker_spec.rb'
- - 'spec/workers/projects/inactive_projects_deletion_notification_worker_spec.rb'
- - 'spec/workers/projects/post_creation_worker_spec.rb'
- - 'spec/workers/projects/process_sync_events_worker_spec.rb'
- - 'spec/workers/projects/record_target_platforms_worker_spec.rb'
- - 'spec/workers/projects/refresh_build_artifacts_size_statistics_worker_spec.rb'
- - 'spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb'
- - 'spec/workers/projects/schedule_refresh_build_artifacts_size_statistics_worker_spec.rb'
- - 'spec/workers/projects/update_repository_storage_worker_spec.rb'
- - 'spec/workers/propagate_integration_group_worker_spec.rb'
- - 'spec/workers/propagate_integration_inherit_descendant_worker_spec.rb'
- - 'spec/workers/propagate_integration_inherit_worker_spec.rb'
- 'spec/workers/propagate_integration_project_worker_spec.rb'
- - 'spec/workers/propagate_integration_worker_spec.rb'
- - 'spec/workers/prune_old_events_worker_spec.rb'
- - 'spec/workers/purge_dependency_proxy_cache_worker_spec.rb'
- - 'spec/workers/reactive_caching_worker_spec.rb'
- - 'spec/workers/rebase_worker_spec.rb'
- - 'spec/workers/releases/create_evidence_worker_spec.rb'
- - 'spec/workers/releases/manage_evidence_worker_spec.rb'
- - 'spec/workers/remote_mirror_notification_worker_spec.rb'
- - 'spec/workers/remove_expired_group_links_worker_spec.rb'
- - 'spec/workers/remove_expired_members_worker_spec.rb'
- - 'spec/workers/remove_unaccepted_member_invites_worker_spec.rb'
- - 'spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb'
- - 'spec/workers/repository_check/batch_worker_spec.rb'
- - 'spec/workers/repository_check/clear_worker_spec.rb'
- - 'spec/workers/repository_check/dispatch_worker_spec.rb'
- - 'spec/workers/repository_check/single_repository_worker_spec.rb'
- - 'spec/workers/repository_cleanup_worker_spec.rb'
- - 'spec/workers/repository_fork_worker_spec.rb'
- - 'spec/workers/repository_update_remote_mirror_worker_spec.rb'
- - 'spec/workers/schedule_merge_request_cleanup_refs_worker_spec.rb'
- - 'spec/workers/schedule_migrate_external_diffs_worker_spec.rb'
- - 'spec/workers/self_monitoring_project_create_worker_spec.rb'
- - 'spec/workers/self_monitoring_project_delete_worker_spec.rb'
- - 'spec/workers/service_desk_email_receiver_worker_spec.rb'
- - 'spec/workers/snippets/schedule_bulk_repository_shard_moves_worker_spec.rb'
- - 'spec/workers/snippets/update_repository_storage_worker_spec.rb'
- - 'spec/workers/ssh_keys/expired_notification_worker_spec.rb'
- - 'spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb'
- - 'spec/workers/stage_update_worker_spec.rb'
- - 'spec/workers/stuck_ci_jobs_worker_spec.rb'
- - 'spec/workers/stuck_export_jobs_worker_spec.rb'
- - 'spec/workers/stuck_merge_jobs_worker_spec.rb'
- - 'spec/workers/system_hook_push_worker_spec.rb'
- - 'spec/workers/tasks_to_be_done/create_worker_spec.rb'
- - 'spec/workers/terraform/states/destroy_worker_spec.rb'
- - 'spec/workers/todos_destroyer/confidential_issue_worker_spec.rb'
- - 'spec/workers/todos_destroyer/destroyed_designs_worker_spec.rb'
- - 'spec/workers/todos_destroyer/destroyed_issuable_worker_spec.rb'
- - 'spec/workers/todos_destroyer/entity_leave_worker_spec.rb'
- - 'spec/workers/todos_destroyer/group_private_worker_spec.rb'
- - 'spec/workers/todos_destroyer/private_features_worker_spec.rb'
- - 'spec/workers/todos_destroyer/project_private_worker_spec.rb'
- - 'spec/workers/trending_projects_worker_spec.rb'
- - 'spec/workers/update_container_registry_info_worker_spec.rb'
- - 'spec/workers/update_external_pull_requests_worker_spec.rb'
- - 'spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb'
- - 'spec/workers/update_highest_role_worker_spec.rb'
- - 'spec/workers/update_merge_requests_worker_spec.rb'
- - 'spec/workers/update_project_statistics_worker_spec.rb'
- - 'spec/workers/upload_checksum_worker_spec.rb'
- - 'spec/workers/user_status_cleanup/batch_worker_spec.rb'
- - 'spec/workers/users/create_statistics_worker_spec.rb'
- - 'spec/workers/users/deactivate_dormant_users_worker_spec.rb'
- - 'spec/workers/users/migrate_records_to_ghost_user_in_batches_worker_spec.rb'
- - 'spec/workers/web_hook_worker_spec.rb'
- - 'spec/workers/web_hooks/log_destroy_worker_spec.rb'
- - 'spec/workers/x509_certificate_revoke_worker_spec.rb'
- - 'spec/workers/x509_issuer_crl_check_worker_spec.rb'
diff --git a/.rubocop_todo/style/format_string.yml b/.rubocop_todo/style/format_string.yml
index 101a0b6429f..cb9ae6e9bd9 100644
--- a/.rubocop_todo/style/format_string.yml
+++ b/.rubocop_todo/style/format_string.yml
@@ -158,7 +158,6 @@ Style/FormatString:
- 'danger/roulette/Dangerfile'
- 'ee/app/components/billing/plan_component.rb'
- 'ee/app/components/namespaces/free_user_cap/enforcement_alert_component.rb'
- - 'ee/app/components/namespaces/free_user_cap/notification_alert_component.rb'
- 'ee/app/components/namespaces/free_user_cap/usage_quota_alert_component.rb'
- 'ee/app/components/namespaces/free_user_cap/usage_quota_trial_alert_component.rb'
- 'ee/app/controllers/admin/elasticsearch_controller.rb'
diff --git a/.rubocop_todo/style/guard_clause.yml b/.rubocop_todo/style/guard_clause.yml
index a6461e7b177..91c1999836e 100644
--- a/.rubocop_todo/style/guard_clause.yml
+++ b/.rubocop_todo/style/guard_clause.yml
@@ -490,7 +490,6 @@ Style/GuardClause:
- 'lib/gitlab/ci/pipeline/expression/lexeme/base.rb'
- 'lib/gitlab/ci/pipeline/expression/lexeme/pattern.rb'
- 'lib/gitlab/ci/reports/codequality_reports_comparer.rb'
- - 'lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb'
- 'lib/gitlab/ci/runner/backoff.rb'
- 'lib/gitlab/ci/runner_upgrade_check.rb'
- 'lib/gitlab/ci/trace.rb'
diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml
index efdb0df8341..19016646725 100644
--- a/.rubocop_todo/style/if_unless_modifier.yml
+++ b/.rubocop_todo/style/if_unless_modifier.yml
@@ -642,7 +642,6 @@ Style/IfUnlessModifier:
- 'ee/lib/gitlab/usage/metrics/instrumentations/count_users_creating_ci_builds_metric.rb'
- 'ee/lib/gitlab/usage/metrics/instrumentations/license_metric.rb'
- 'ee/lib/omni_auth/strategies/group_saml.rb'
- - 'ee/lib/sidebars/groups/menus/administration_menu.rb'
- 'ee/lib/sidebars/groups/menus/analytics_menu.rb'
- 'ee/lib/sidebars/groups/menus/security_compliance_menu.rb'
- 'ee/lib/tasks/geo.rake'
@@ -891,7 +890,6 @@ Style/IfUnlessModifier:
- 'lib/gitlab/jira_import.rb'
- 'lib/gitlab/jira_import/base_importer.rb'
- 'lib/gitlab/legacy_github_import/client.rb'
- - 'lib/gitlab/legacy_github_import/importer.rb'
- 'lib/gitlab/legacy_github_import/issuable_formatter.rb'
- 'lib/gitlab/legacy_github_import/project_creator.rb'
- 'lib/gitlab/lograge/custom_options.rb'
diff --git a/.rubocop_todo/style/mutable_constant.yml b/.rubocop_todo/style/mutable_constant.yml
index 2409d4f3521..8e6a0a2335b 100644
--- a/.rubocop_todo/style/mutable_constant.yml
+++ b/.rubocop_todo/style/mutable_constant.yml
@@ -5,7 +5,6 @@ Style/MutableConstant:
Exclude:
- 'app/finders/group_members_finder.rb'
- 'app/graphql/mutations/container_repositories/destroy_tags.rb'
- - 'app/graphql/mutations/members/groups/bulk_update.rb'
- 'app/graphql/mutations/packages/bulk_destroy.rb'
- 'app/helpers/blame_helper.rb'
- 'app/models/ci/build_trace_chunks/redis_base.rb'
diff --git a/.rubocop_todo/style/percent_literal_delimiters.yml b/.rubocop_todo/style/percent_literal_delimiters.yml
index 66de6a35092..bc3c41ae992 100644
--- a/.rubocop_todo/style/percent_literal_delimiters.yml
+++ b/.rubocop_todo/style/percent_literal_delimiters.yml
@@ -993,7 +993,6 @@ Style/PercentLiteralDelimiters:
- 'spec/requests/api/unleash_spec.rb'
- 'spec/requests/api/users_spec.rb'
- 'spec/requests/api/wikis_spec.rb'
- - 'spec/requests/ide_controller_spec.rb'
- 'spec/requests/jwt_controller_spec.rb'
- 'spec/requests/lfs_locks_api_spec.rb'
- 'spec/requests/users_controller_spec.rb'
diff --git a/.rubocop_todo/style/redundant_freeze.yml b/.rubocop_todo/style/redundant_freeze.yml
index 46609b0131a..cda2972c60c 100644
--- a/.rubocop_todo/style/redundant_freeze.yml
+++ b/.rubocop_todo/style/redundant_freeze.yml
@@ -78,7 +78,6 @@ Style/RedundantFreeze:
- 'ee/lib/ee/gitlab/path_regex.rb'
- 'ee/lib/ee/gitlab/web_hooks/rate_limiter.rb'
- 'ee/lib/elastic/latest/git_class_proxy.rb'
- - 'ee/lib/gitlab/code_owners/file.rb'
- 'ee/lib/gitlab/code_owners/reference_extractor.rb'
- 'ee/lib/gitlab/status_page/filter/image_filter.rb'
- 'ee/lib/system_check/geo/authorized_keys_check.rb'
diff --git a/.rubocop_todo/style/symbol_proc.yml b/.rubocop_todo/style/symbol_proc.yml
index e3bde84c7b8..bc4ecaa5400 100644
--- a/.rubocop_todo/style/symbol_proc.yml
+++ b/.rubocop_todo/style/symbol_proc.yml
@@ -105,7 +105,6 @@ Style/SymbolProc:
- 'ee/lib/gitlab/geo/oauth/logout_state.rb'
- 'ee/spec/elastic/migrate/20220118150500_delete_orphaned_commits_spec.rb'
- 'ee/spec/factories/issues.rb'
- - 'ee/spec/features/billings/extend_reactivate_trial_spec.rb'
- 'ee/spec/features/billings/qrtly_reconciliation_alert_spec.rb'
- 'ee/spec/helpers/ee/geo_helper_spec.rb'
- 'ee/spec/helpers/ee/registrations_helper_spec.rb'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 416c13b5db7..8d00761e265 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -758,6 +758,23 @@ entry.
- [Remove Gitlab::Redis::DuplicateJobs](gitlab-org/gitlab@73d863b0a49175cce7649c0936b2e16157f61665) ([merge request](gitlab-org/gitlab!109122))
- [Clean-up feature flag `hash_based_cache_for_protected_branches`](gitlab-org/gitlab@96e8a07564bac07a100556e00ce4af3f21dca293) ([merge request](gitlab-org/gitlab!108724))
+## 15.8.4 (2023-03-02)
+
+### Security (12 changes)
+
+- [Using builds metadata to determine debug_mode](gitlab-org/security/gitlab@169fdb3222a9701b5818ef7c00f8f292dc60495d) ([merge request](gitlab-org/security/gitlab!3035))
+- [Fix pagination limits for Commits API](gitlab-org/security/gitlab@3d58c0fef6429d1030d1dfce1ca523ef33a0054b) ([merge request](gitlab-org/security/gitlab!3072))
+- [Mask Google IAP account details in Prometheus integration](gitlab-org/security/gitlab@96426e4c799e9bf5e90e5e57b2e54235831819a3) ([merge request](gitlab-org/security/gitlab!3082))
+- [Stop Group Transfer Service if SAML Provider or SCIM token is present](gitlab-org/security/gitlab@9496a2ed22f73bf83e56b1ff502fefcfe777ad07) ([merge request](gitlab-org/security/gitlab!3097))
+- [Protect Datadog API key by changing Datadog site](gitlab-org/security/gitlab@c6804e50cb60fc4747ea573306eec17eb0dd25f9) ([merge request](gitlab-org/security/gitlab!3094))
+- [Protect integrations' sensitive information exposed via API](gitlab-org/security/gitlab@a408475163272b926e65b1cf56c9efde09eac8dd) ([merge request](gitlab-org/security/gitlab!3088))
+- [Disallow maintainer to create an owner access token](gitlab-org/security/gitlab@d184909f6ab9123a6131c5c37452ace5c4bc8d3d) ([merge request](gitlab-org/security/gitlab!3091))
+- [Paste only text content in work items title](gitlab-org/security/gitlab@d8c48ade46fd75ab62731fced05cdfa2451bcdfa) ([merge request](gitlab-org/security/gitlab!3075))
+- [Jira DVCS OAuth Open Redirect Vulnerability](gitlab-org/security/gitlab@91ee37eeaaae8cc6d923f6b4b28ce0d7914342dd) ([merge request](gitlab-org/security/gitlab!3063))
+- [Block private personal snippet from unauthorized users](gitlab-org/security/gitlab@d687866d69cbdf25a3ca7185974c02402345015d) ([merge request](gitlab-org/security/gitlab!3030))
+- [Verify Kroki diagram type](gitlab-org/security/gitlab@4ec26a4479e73233d0f77bc5a5e764d506c29faf) ([merge request](gitlab-org/security/gitlab!3055))
+- [Check read_release permission before showing releases in Tags API](gitlab-org/security/gitlab@32bf21efc32fcb6a3803993959b50d8a9cd07d25) ([merge request](gitlab-org/security/gitlab!3057))
+
## 15.8.3 (2023-02-15)
### Fixed (3 changes)
@@ -1252,6 +1269,23 @@ No changes.
- [Do not use _test when not necessary](gitlab-org/gitlab@1bde73aba2bd1d7f9e833c7325cffa0c90d1c106) ([merge request](gitlab-org/gitlab!107373))
- [Add config/redis.yml unified config file](gitlab-org/gitlab@ace8301236eecc07a511975b57f80e21ec7be3c2) ([merge request](gitlab-org/gitlab!106854))
+## 15.7.8 (2023-03-02)
+
+### Security (12 changes)
+
+- [Using builds metadata to determine debug_mode](gitlab-org/security/gitlab@12be0c159940a35899851f2867fde1237dae254b) ([merge request](gitlab-org/security/gitlab!3036))
+- [Fix pagination limits for Commits API](gitlab-org/security/gitlab@d507c5d906aff98a8bff943181299cbec5cc43db) ([merge request](gitlab-org/security/gitlab!3073))
+- [Mask Google IAP account details in Prometheus integration](gitlab-org/security/gitlab@54420f92a366e2a7648c10baaaf67492d6676746) ([merge request](gitlab-org/security/gitlab!3083))
+- [Stop Group Transfer Service if SAML Provider or SCIM token is present](gitlab-org/security/gitlab@52400160cd607fb30411dec04b516a1314e44996) ([merge request](gitlab-org/security/gitlab!3098))
+- [Protect Datadog API key by changing Datadog site](gitlab-org/security/gitlab@9aa3ba9f719a786238ae59914d5456666363940e) ([merge request](gitlab-org/security/gitlab!3096))
+- [Protect integrations' sensitive information exposed via API](gitlab-org/security/gitlab@60c22681f52c2aadcb55e1b9e92d358076e3c92c) ([merge request](gitlab-org/security/gitlab!3089))
+- [Disallow maintainer to create an owner access token](gitlab-org/security/gitlab@2adeb7fafb119a43c0bfe162fbc66d2740cb4168) ([merge request](gitlab-org/security/gitlab!3092))
+- [Paste only text content in work items title](gitlab-org/security/gitlab@5fa8a9bf683427af6f25e043b3f0a332719bc970) ([merge request](gitlab-org/security/gitlab!3076))
+- [Jira DVCS OAuth Open Redirect Vulnerability](gitlab-org/security/gitlab@3598b2558de92b0a775f09beb739c6e2f90ff7ab) ([merge request](gitlab-org/security/gitlab!3064))
+- [Block private personal snippet from unauthorized users](gitlab-org/security/gitlab@a106541570423480c9c510f512a2dc61acc5c01f) ([merge request](gitlab-org/security/gitlab!2994))
+- [Verify Kroki diagram type](gitlab-org/security/gitlab@eafe89b8be423e4828fe92769353b7f17ffe895e) ([merge request](gitlab-org/security/gitlab!3054))
+- [Check read_release permission before showing releases in Tags API](gitlab-org/security/gitlab@d56500c47754c7d5eb11f3c84bedbe60366eff0e) ([merge request](gitlab-org/security/gitlab!3058))
+
## 15.7.7 (2023-02-10)
No changes.
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index e99b2f49e96..175d99e2170 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-15.9.3 \ No newline at end of file
+534e1a1c783059ab7a24ede2c63a53867ba393a2
diff --git a/GITLAB_KAS_VERSION b/GITLAB_KAS_VERSION
index 3a6f2e99e48..1a42a9dbc96 100644
--- a/GITLAB_KAS_VERSION
+++ b/GITLAB_KAS_VERSION
@@ -1 +1 @@
-v15.9.0
+v15.10.0
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index e99b2f49e96..790fdbb0ebb 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-15.9.3 \ No newline at end of file
+affdc645175554504efdf19daad28900b5b43e87
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 62df50f1eef..c2324e8e468 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-14.17.0
+14.18.0
diff --git a/Gemfile b/Gemfile
index ed0c5127f73..8cafe3b8909 100644
--- a/Gemfile
+++ b/Gemfile
@@ -33,9 +33,6 @@ gem 'sprockets', '~> 3.7.0'
gem 'view_component', '~> 2.74.1'
-# Default values for AR models
-gem 'default_value_for', '~> 3.4.0'
-
# Supported DBs
gem 'pg', '~> 1.4.5'
@@ -143,14 +140,12 @@ gem 'carrierwave', '~> 1.3'
gem 'mini_magick', '~> 4.10.1'
# for backups
-gem 'fog-aws', '~> 3.15'
+gem 'fog-aws', '~> 3.18'
# Locked until fog-google resolves https://github.com/fog/fog-google/issues/421.
# Also see config/initializers/fog_core_patch.rb.
gem 'fog-core', '= 2.1.0'
gem 'fog-google', '~> 1.19', require: 'fog/google'
gem 'fog-local', '~> 0.8'
-gem 'fog-openstack', '~> 1.0'
-gem 'fog-rackspace', '~> 0.1.1'
# NOTE:
# the fog-aliyun gem since v0.4 pulls in aliyun-sdk transitively, which monkey-patches
# the rest-client gem to drop the Content-Length header field for chunked transfers,
@@ -182,7 +177,7 @@ 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.170.0'
+gem 'aws-sdk-core', '~> 3.170.1'
gem 'aws-sdk-cloudformation', '~> 1'
gem 'aws-sdk-s3', '~> 1.119.1'
gem 'faraday_middleware-aws-sigv4', '~>0.3.0'
@@ -199,13 +194,13 @@ gem 'rdoc', '~> 6.3.2'
gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1'
-gem 'asciidoctor', '~> 2.0.17'
+gem 'asciidoctor', '~> 2.0.18'
gem 'asciidoctor-include-ext', '~> 0.4.0', require: false
gem 'asciidoctor-plantuml', '~> 0.0.16'
-gem 'asciidoctor-kroki', '~> 0.7.0', require: false
-gem 'rouge', '~> 3.30.0'
+gem 'asciidoctor-kroki', '~> 0.8.0', require: false
+gem 'rouge', '~> 4.1.0'
gem 'truncato', '~> 0.7.12'
-gem 'nokogiri', '~> 1.14.1'
+gem 'nokogiri', '~> 1.14.2'
# Calendar rendering
gem 'icalendar'
@@ -292,7 +287,7 @@ gem 'asana', '~> 0.10.13'
gem 'ruby-fogbugz', '~> 0.3.0'
# Kubernetes integration
-gem 'kubeclient', '~> 4.9.3', path: 'vendor/gems/kubeclient'
+gem 'kubeclient', '~> 4.11.0'
# Sanitize user input
gem 'sanitize', '~> 6.0'
@@ -310,7 +305,7 @@ gem 'licensee', '~> 9.15'
gem 'charlock_holmes', '~> 0.7.7'
# Detect mime content type from content
-gem 'ruby-magic', '~> 0.5'
+gem 'ruby-magic', '~> 0.6'
# Faster blank
gem 'fast_blank'
@@ -348,7 +343,7 @@ gem 'pg_query', '~> 2.2', '>= 2.2.1'
gem 'premailer-rails', '~> 1.10.3'
-gem 'gitlab-labkit', '~> 0.30.1'
+gem 'gitlab-labkit', '~> 0.31.1'
gem 'thrift', '>= 0.16.0'
# I18n
@@ -363,17 +358,20 @@ gem 'batch-loader', '~> 2.0.1'
# Perf bar
gem 'peek', '~> 1.1'
+# Google Cloud Profiler support
+gem 'cloud_profiler_agent', '~> 0.0.0', path: 'vendor/gems/cloud_profiler_agent', require: false
+
# Snowplow events tracking
gem 'snowplow-tracker', '~> 0.8.0'
# Metrics
gem 'webrick', '~> 1.6.1', require: false
-gem 'prometheus-client-mmap', '~> 0.17', require: 'prometheus/client'
+gem 'prometheus-client-mmap', '~> 0.19', require: 'prometheus/client'
gem 'warning', '~> 1.3.0'
group :development do
- gem 'lefthook', '~> 1.2.9', require: false
+ gem 'lefthook', '~> 1.3.3', require: false
gem 'rubocop'
gem 'solargraph', '~> 0.47.2', require: false
@@ -416,7 +414,7 @@ group :development, :test do
gem 'bundler-audit', '~> 0.7.0.1', require: false
# Benchmarking & profiling
- gem 'benchmark-ips', '~> 2.3.0', require: false
+ gem 'benchmark-ips', '~> 2.11.0', require: false
gem 'benchmark-memory', '~> 0.1', require: false
gem 'knapsack', '~> 1.21.1'
@@ -436,7 +434,7 @@ group :development, :test do
end
group :development, :test, :danger do
- gem 'gitlab-dangerfiles', '~> 3.7.0', require: false
+ gem 'gitlab-dangerfiles', '~> 3.8.0', require: false
end
group :development, :test, :coverage do
@@ -456,7 +454,7 @@ group :test do
gem 'rspec-retry', '~> 0.6.1'
gem 'rspec_profiling', '~> 0.0.6'
gem 'rspec-benchmark', '~> 0.6.0'
- gem 'rspec-parameterized', require: false
+ gem 'rspec-parameterized', '~> 1.0', require: false
gem 'capybara', '~> 3.35.3'
gem 'capybara-screenshot', '~> 1.0.22'
@@ -472,6 +470,7 @@ group :test do
gem 'test-prof', '~> 1.0.7'
gem 'rspec_junit_formatter'
gem 'guard-rspec'
+ gem 'axe-core-rspec'
# Moved in `test` because https://gitlab.com/gitlab-org/gitlab/-/issues/217527
gem 'derailed_benchmarks', require: false
@@ -486,7 +485,7 @@ gem 'gitlab-mail_room', '~> 0.0.9', require: 'mail_room'
gem 'email_reply_trimmer', '~> 0.1'
gem 'html2text'
-gem 'stackprof', '~> 0.2.21', require: false
+gem 'stackprof', '~> 0.2.23', require: false
gem 'rbtrace', '~> 0.4', require: false
gem 'memory_profiler', '~> 1.0', require: false
gem 'activerecord-explain-analyze', '~> 0.1', require: false
@@ -518,7 +517,7 @@ gem 'kas-grpc', '~> 0.0.2'
gem 'grpc', '~> 1.42.0'
-gem 'google-protobuf', '~> 3.21', '>= 3.21.12'
+gem 'google-protobuf', '~> 3.22', '>= 3.22.2'
gem 'toml-rb', '~> 2.2.0'
@@ -566,7 +565,7 @@ gem 'oj-introspect', '~> 0.7'
gem 'multi_json', '~> 1.14.1'
gem 'yajl-ruby', '~> 1.4.3', require: 'yajl'
-gem 'webauthn', '~> 2.3'
+gem 'webauthn', '~> 3.0'
# IPAddress utilities
gem 'ipaddress', '~> 0.8.3'
@@ -588,8 +587,18 @@ gem 'cvss-suite', '~> 3.0.1', require: 'cvss_suite'
gem 'arr-pm', '~> 0.0.12'
# Apple plist parsing
-gem 'CFPropertyList'
+gem 'CFPropertyList', '~> 3.0.0'
gem 'app_store_connect'
# For phone verification
gem 'telesignenterprise', '~> 2.2'
+
+# Ruby 3 extracts net-protocol into a separate gem, while Ruby 2 has it built-in
+# This condition installs the gem only for Ruby 3 to avoid warnings on Ruby 2
+# Can be removed when support for Ruby 2 is dropped
+install_if -> { Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0.0") } do
+ # BufferedIO patch
+ gem 'net-protocol', '~> 0.1.3'
+end
+
+gem 'duo_api', '~> 1.3'
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 7813d319ee9..23b5df88a71 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -24,23 +24,26 @@
{"name":"app_store_connect","version":"0.29.0","platform":"ruby","checksum":"01d7a923825a4221892099acb5a72f86f6ee7d8aa95815d3c459ba6816ea430f"},
{"name":"arr-pm","version":"0.0.12","platform":"ruby","checksum":"fdff482f75239239201f4d667d93424412639aad0b3b0ad4d827e7c637e0ad39"},
{"name":"asana","version":"0.10.13","platform":"ruby","checksum":"36d0d37f8dd6118a54580f1b80224875d7b6a9027598938e1722a508bfc2d7ac"},
-{"name":"asciidoctor","version":"2.0.17","platform":"ruby","checksum":"ed5b5e399e8d64994cc16f0983f993d6e33990909a8415b6fc8b786cdeb00f3d"},
+{"name":"asciidoctor","version":"2.0.18","platform":"ruby","checksum":"bbd1e1d16deed8db94bf9624b9f4474fac32d9ca7225d377f076c08d9adde387"},
{"name":"asciidoctor-include-ext","version":"0.4.0","platform":"ruby","checksum":"406adb9d2fbfc25536609ca13b787ed704dc06a4e49d6709b83f3bad578f7878"},
-{"name":"asciidoctor-kroki","version":"0.7.0","platform":"ruby","checksum":"528ae4e49cae10e98c76e91f9aa40c67bf8540aa5ce4bbd44c5cd57af9f0b121"},
+{"name":"asciidoctor-kroki","version":"0.8.0","platform":"ruby","checksum":"e53b3f349167cebde990b0098863e8fe98fd235e35263a78c88cc4e0268b1a36"},
{"name":"asciidoctor-plantuml","version":"0.0.16","platform":"ruby","checksum":"407e47cd1186ded5ccc75f0c812e5524c26c571d542247c5132abb8f47bd1793"},
{"name":"ast","version":"2.4.2","platform":"ruby","checksum":"1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12"},
{"name":"atlassian-jwt","version":"0.2.0","platform":"ruby","checksum":"52e653e9d6062d7a740c3675b0e79fa08367927c6fc17f5476d1b6b3798c6eb2"},
{"name":"attr_required","version":"1.0.1","platform":"ruby","checksum":"024e10393bd30901e1adf6769bd756b873a5ef7da60f86f8f11066116b5742bc"},
{"name":"autoprefixer-rails","version":"10.2.5.1","platform":"ruby","checksum":"3711d67f1112361c7628847ac192d8aa6f3b8abe47527aee8a69dc8985e798ee"},
{"name":"awesome_print","version":"1.9.2","platform":"ruby","checksum":"e99b32b704acff16d768b3468680793ced40bfdc4537eb07e06a4be11133786e"},
-{"name":"awrence","version":"1.1.1","platform":"ruby","checksum":"9be584c97408ed92d5e1ca11740853646fe270de675f2f8dd44e8233226dfc97"},
+{"name":"awrence","version":"1.2.1","platform":"ruby","checksum":"dd1d214c12a91f449d1ef81d7ee3babc2816944e450752e7522c65521872483e"},
{"name":"aws-eventstream","version":"1.2.0","platform":"ruby","checksum":"ffa53482c92880b001ff2fb06919b9bb82fd847cbb0fa244985d2ebb6dd0d1df"},
-{"name":"aws-partitions","version":"1.703.0","platform":"ruby","checksum":"3d32fcdcb2799fe0472a9b30990035713d7a75ac8b77bd7767ef5ee2914ea748"},
+{"name":"aws-partitions","version":"1.730.0","platform":"ruby","checksum":"32aa84e7004c4b0c7cde0bd9641188a3eaf3001ec67019b201cbe47bde8e902b"},
{"name":"aws-sdk-cloudformation","version":"1.41.0","platform":"ruby","checksum":"31e47539719734413671edf9b1a31f8673fbf9688549f50c41affabbcb1c6b26"},
-{"name":"aws-sdk-core","version":"3.170.0","platform":"ruby","checksum":"59341e5cf39d70c4069201bd46f914efd2a0aaa257c5c4d02dfa602e36fc847d"},
+{"name":"aws-sdk-core","version":"3.170.1","platform":"ruby","checksum":"553ba7ea629f90cd00fb83de3f3636e9db0a38b6b48957cacdb0f63c9d69bea6"},
{"name":"aws-sdk-kms","version":"1.62.0","platform":"ruby","checksum":"b9111c698d783f3f092dcc6a8b9b7e3f53f00e6e501bdc5a4409afdcaf411a1c"},
{"name":"aws-sdk-s3","version":"1.119.1","platform":"ruby","checksum":"f7f5939f204839e20222c70823ec0dc5f10775e3538e102783f68b42f5a7f6e6"},
{"name":"aws-sigv4","version":"1.5.1","platform":"ruby","checksum":"d68c87fff4ee843b4b92b23c7f31f957f254ec6eb064181f7119124aab8b8bb4"},
+{"name":"axe-core-api","version":"4.6.0","platform":"ruby","checksum":"1b0ddec3353f108dc10363baf2282f43a5ff7f13d4e25f99071294e78f8a6c62"},
+{"name":"axe-core-rspec","version":"4.6.0","platform":"ruby","checksum":"11c25bc9dd388c137ba4e5e63d64d20092bf22c884d8ffc829a22acfbacd747f"},
+{"name":"axiom-types","version":"0.1.1","platform":"ruby","checksum":"c1ff113f3de516fa195b2db7e0a9a95fd1b08475a502ff660d04507a09980383"},
{"name":"azure-storage-blob","version":"2.0.3","platform":"ruby","checksum":"61b76118843c91776bd24bee22c74adafeb7c4bb3a858a325047dae3b59d0363"},
{"name":"azure-storage-common","version":"2.0.4","platform":"ruby","checksum":"608f4daab0e06b583b73dcffd3246ea39e78056de31630286b0cf97af7d6956b"},
{"name":"babosa","version":"1.0.4","platform":"ruby","checksum":"18dea450f595462ed7cb80595abd76b2e535db8c91b350f6c4b3d73986c5bc99"},
@@ -50,15 +53,14 @@
{"name":"bcrypt","version":"3.1.16","platform":"java","checksum":"2925a1546fa8e85bdb1b10f1fc95c4e1ea15992ada16adea4af82b0978ed662c"},
{"name":"bcrypt","version":"3.1.16","platform":"ruby","checksum":"0b8bf031ba81aa76c0f10c5a8dac779b6035d84b09af1dbb2b1a32a7e360210b"},
{"name":"benchmark","version":"0.2.0","platform":"ruby","checksum":"5f7087b794613abdd3ac9c13f4351f65b164bcb15ced2ad29508e365f9b28c77"},
-{"name":"benchmark-ips","version":"2.3.0","platform":"ruby","checksum":"12443aa327d3129aa965244f79d7d5cb0f692f0f92ba7db76fba61526a40062e"},
+{"name":"benchmark-ips","version":"2.11.0","platform":"ruby","checksum":"1eaa89841073895af0ee7ff72eb069e5c7dda01c6d6a8b3e79e363bace596dec"},
{"name":"benchmark-malloc","version":"0.2.0","platform":"ruby","checksum":"37c68f0435261634026f584d79956a35325a3027e3e6b4cc8d7575aa10537e6b"},
{"name":"benchmark-memory","version":"0.2.0","platform":"ruby","checksum":"ca1e436433b09535ee8f64f80600a5edb407cff1f6ac70e089ca238118e6ab5c"},
{"name":"benchmark-perf","version":"0.6.0","platform":"ruby","checksum":"fe2b01959f3de0f9dd34820d54ef881eb4f3589fccb7d17b63068ac92d7f9621"},
{"name":"benchmark-trend","version":"0.4.0","platform":"ruby","checksum":"de5a02a9f443babefbbd97784759820decee8554a0c273d859c02a0990845d81"},
{"name":"better_errors","version":"2.9.1","platform":"ruby","checksum":"39efc116ab04d6c4200052c5782936e4bd99906978d098992bce6bf81d054284"},
{"name":"bindata","version":"2.4.11","platform":"ruby","checksum":"c38e0c99ffcd80c10a0a7ae6c8586d2fe26bf245cbefac90bec8764523220f6a"},
-{"name":"binding_ninja","version":"0.2.3","platform":"java","checksum":"bbcf70b211d6e397493bf57c249bbec6aaf28fa7dafeb78e447b1b2f0610484f"},
-{"name":"binding_ninja","version":"0.2.3","platform":"ruby","checksum":"4a85550a0066ee4721506b4e150857486808e50c9ddfeed04bdc896bb61eca9d"},
+{"name":"binding_of_caller","version":"1.0.0","platform":"ruby","checksum":"3aad25d1d538fc6e7972978f9bf512ccd992784009947c81633bea776713161d"},
{"name":"bootsnap","version":"1.16.0","platform":"ruby","checksum":"f87410c00f69cd84a6e72a6c4bdba733f800d80d934f4315849d18ca9f288fed"},
{"name":"browser","version":"5.3.1","platform":"ruby","checksum":"62745301701ff2c6c5d32d077bb12532b20be261929dcb52c6781ed0d5658b3c"},
{"name":"builder","version":"3.2.4","platform":"ruby","checksum":"99caf08af60c8d7f3a6b004029c4c3c0bdaebced6c949165fe98f1db27fbbc10"},
@@ -80,29 +82,31 @@
{"name":"claide","version":"1.1.0","platform":"ruby","checksum":"6d3c5c089dde904d96aa30e73306d0d4bd444b1accb9b3125ce14a3c0183f82e"},
{"name":"claide-plugins","version":"0.9.2","platform":"ruby","checksum":"c7ea78bc067ab23bce8515497cdcdcb8f01c86dadfbe13c44644e382922c1c2e"},
{"name":"coderay","version":"1.1.3","platform":"ruby","checksum":"dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b"},
+{"name":"coercible","version":"1.0.0","platform":"ruby","checksum":"5081ad24352cc8435ce5472bc2faa30260c7ea7f2102cc6a9f167c4d9bffaadc"},
{"name":"colored2","version":"3.1.2","platform":"ruby","checksum":"b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a"},
{"name":"commonmarker","version":"0.23.6","platform":"ruby","checksum":"c8aeaaaff4ba497bf180f762db63a0069794fafb6eff221224c9c8199d337b38"},
{"name":"concurrent-ruby","version":"1.2.0","platform":"ruby","checksum":"a5e799f71e7490f24a534d58c91380267d0ae306af0cdc518d6848b93475dae2"},
{"name":"connection_pool","version":"2.3.0","platform":"ruby","checksum":"677985be912f33c90f98f229aaa0c0ddb2ef8776f21929a36eeeb25251c944da"},
{"name":"cork","version":"0.3.0","platform":"ruby","checksum":"a0a0ac50e262f8514d1abe0a14e95e71c98b24e3378690e5d044daf0013ad4bc"},
-{"name":"cose","version":"1.0.0","platform":"ruby","checksum":"520ebaad97b56d2873de02ff4e2c973f5e77ce2f8edbda454af9ee3073643bc0"},
+{"name":"cose","version":"1.3.0","platform":"ruby","checksum":"63247c66a5bc76e53926756574fe3724cc0a88707e358c90532ae2a320e98601"},
{"name":"countries","version":"4.0.1","platform":"ruby","checksum":"d32e8a3c0b22949f1a41ea6d9005f5168ffce226f8fe077d1d6be785fffa81c5"},
{"name":"crack","version":"0.4.3","platform":"ruby","checksum":"5318ba8cd9cf7e0b5feb38948048503ba4b1fdc1b6ff30a39f0a00feb6036b29"},
{"name":"crass","version":"1.0.6","platform":"ruby","checksum":"dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d"},
{"name":"creole","version":"0.5.0","platform":"ruby","checksum":"951701e2d80760f156b1cb2a93471ca97c076289becc067a33b745133ed32c03"},
{"name":"crystalball","version":"0.7.0","platform":"ruby","checksum":"6e729f372a5071daec877adb40c5df4cb25fe21f350635e2a9624373fc151ef2"},
-{"name":"css_parser","version":"1.12.0","platform":"ruby","checksum":"8b7c04bca32257da0c65bd7b1fa585df5a0fd9f5197ccd78498d5598dd900784"},
+{"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-gitlab","version":"8.0.0","platform":"ruby","checksum":"497dd7d0f6513913de651019223d8058cf494df10acbd17de92b175dfa04a3a8"},
{"name":"database_cleaner","version":"1.7.0","platform":"ruby","checksum":"bdf833c197afac7054015bcde2567c3834c366bbfe6a377c30151ca984b32016"},
{"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":"declarative","version":"0.0.20","platform":"ruby","checksum":"8021dd6cb17ab2b61233c56903d3f5a259c5cf43c80ff332d447d395b17d9ff9"},
{"name":"declarative_policy","version":"1.1.0","platform":"ruby","checksum":"9af4cf299ade03f2bbf63908f2ce6a117d132fc714c39a128596667fb13331cb"},
-{"name":"default_value_for","version":"3.4.0","platform":"ruby","checksum":"35d2dc51675a6bedfa875778628d44b823e0d7336da9432519477174ebb0f40f"},
{"name":"deprecation_toolkit","version":"1.5.1","platform":"ruby","checksum":"a8a1ab1a19ae40ea12560b65010e099f3459ebde390b76621ef0c21c516a04ba"},
{"name":"derailed_benchmarks","version":"2.1.2","platform":"ruby","checksum":"eaadc6206ceeb5538ff8f5e04a0023d54ebdd95d04f33e8960fb95a5f189a14f"},
+{"name":"descendants_tracker","version":"0.0.4","platform":"ruby","checksum":"e9c41dd4cfbb85829a9301ea7e7c48c2a03b26f09319db230e6479ccdc780897"},
{"name":"device_detector","version":"1.0.0","platform":"ruby","checksum":"b800fb3150b00c23e87b6768011808ac1771fffaae74c3238ebaf2b782947a7d"},
{"name":"devise","version":"4.8.1","platform":"ruby","checksum":"fdd48bbe79a89e7c1152236a70479842ede48bea4fa7f4f2d8da1f872559803e"},
{"name":"devise-two-factor","version":"4.0.2","platform":"ruby","checksum":"6548d2696ed090d27046f888f4fa7380f151e0f823902d46fd9b91e7d0cac511"},
@@ -123,6 +127,8 @@
{"name":"dry-inflector","version":"0.2.0","platform":"ruby","checksum":"c7cf29c3dc9d961c115aac873ac39a4ff6988fae7f7871c473a9694c1f6fb39e"},
{"name":"dry-logic","version":"1.1.0","platform":"ruby","checksum":"eca4b39084c9d22778144b7e4cf8db20e8bab7de6d89deb220d20a9fde60b69d"},
{"name":"dry-types","version":"1.4.0","platform":"ruby","checksum":"68003bb0db3077fecd0270f4ae486a82ee76bab6d666fdc4e094380a67c9a1df"},
+{"name":"dumb_delegator","version":"1.0.0","platform":"ruby","checksum":"ff5e411816d2d8ad8e260b269e712ae3839dddb0f9f8e18d3b1a3fe08f6d2e94"},
+{"name":"duo_api","version":"1.3.0","platform":"ruby","checksum":"87c9830e190fad32fdb086b023f555a3cf5cd4d6708a992f7a32efb2ce206176"},
{"name":"e2mmap","version":"0.1.0","platform":"ruby","checksum":"45ee6bba2d97a7d91ee0885774261feee87e28c598355df31e93b56196ec0f59"},
{"name":"ecma-re-validator","version":"0.3.0","platform":"ruby","checksum":"66a95bd8c2b0641baf1fbf9bd355a0dcf13c82c6883f6f496a722420a8b6e0d7"},
{"name":"ed25519","version":"1.3.0","platform":"java","checksum":"8e5d2f8a5325c7a463d61d1a48406ce54074c610f3dccd889e6532c9527a3894"},
@@ -179,18 +185,17 @@
{"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":"fog-aliyun","version":"0.4.0","platform":"ruby","checksum":"8f2334604beb781eafbb9cd5f50141fbb2c7eb77c7f2b01f45c2e04db0e5cc38"},
-{"name":"fog-aws","version":"3.15.0","platform":"ruby","checksum":"09752931ea0c6165b018e1a89253248d86b246645086ccf19bc44fabe3381e8c"},
+{"name":"fog-aws","version":"3.18.0","platform":"ruby","checksum":"f4c5880ecfbc4edbf711dfd41140f9f17dfc68b519546d121448d2d3a5584704"},
{"name":"fog-core","version":"2.1.0","platform":"ruby","checksum":"53e5d793554d7080d015ef13cd44b54027e421d924d9dba4ce3d83f95f37eda9"},
{"name":"fog-google","version":"1.19.0","platform":"ruby","checksum":"3c909a230837fe84117fffdfd927b523821b88f61d3aeab531e1417a9810f488"},
{"name":"fog-json","version":"1.2.0","platform":"ruby","checksum":"dd4f5ab362dbc72b687240bba9d2dd841d5dfe888a285797533f85c03ea548fe"},
{"name":"fog-local","version":"0.8.0","platform":"ruby","checksum":"263b2d09e54c69d1b87ad7f235a1a1e53c8a674edcedf7512c1715765ad7ef79"},
-{"name":"fog-openstack","version":"1.0.8","platform":"ruby","checksum":"8f174ab5e5b1bc107c7da90cc7c47a24930e1566cd88ab4df447026ea8b63d9c"},
-{"name":"fog-rackspace","version":"0.1.1","platform":"ruby","checksum":"4a8c7a2432dd32321958c869f3b1b8190cf4eac292024e6ea267bc6040a44b78"},
{"name":"fog-xml","version":"0.1.3","platform":"ruby","checksum":"5604c42649ebb0d8a31bd973aa000c2dd0127f1c1c4c174b69266a2e78e37410"},
{"name":"formatador","version":"0.2.5","platform":"ruby","checksum":"80821869ddacb79e72870ff4bb1531efacd278c04f2df26bc6b4529ee13582bd"},
{"name":"fugit","version":"1.8.1","platform":"ruby","checksum":"18ffb26813869610f71bb0b7d568c3624d2b3025aeebb6600a18df0c77a6a2b2"},
{"name":"fuubar","version":"2.2.0","platform":"ruby","checksum":"9b0263c4074f39c68b37f1e4e69a7d3cfc7523c41bea43601235daa723179b4a"},
{"name":"fuzzyurl","version":"0.9.0","platform":"ruby","checksum":"542efa80f2bcaadbdc402c2f0b572f2e335a1d53e375aecad68bbb3d86860c0f"},
+{"name":"gapic-common","version":"0.18.0","platform":"ruby","checksum":"6fd55a538ce2d63026fa05f379b1aec00788cc060f76903739516ab1ca1496ab"},
{"name":"gemoji","version":"3.0.1","platform":"ruby","checksum":"80553f2f4932a7a95fb1b3c7c63f7dd937e7c8c610164bbdea28fd06eba5f36d"},
{"name":"get_process_mem","version":"0.2.7","platform":"ruby","checksum":"4afd3c3641dd6a817c09806c7d6d509d8a9984512ac38dea8b917426bbf77eba"},
{"name":"gettext","version":"3.3.6","platform":"ruby","checksum":"ee6bbd1b2f833ee52d7797fa68acbfecc4726aec6b6280fd7eab92aa0190b413"},
@@ -200,10 +205,10 @@
{"name":"gitaly","version":"15.9.0.pre.rc3","platform":"ruby","checksum":"6ac64320a70417131a4b97f5dd45d4e203d60703cc3cba156561e7f8c50a4abe"},
{"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.7.0","platform":"ruby","checksum":"35c5bc42e60c575ab5701192ca2384ab414b14c2963602b39e143b1aaeb7e54d"},
+{"name":"gitlab-dangerfiles","version":"3.8.0","platform":"ruby","checksum":"7ef0c3205faa38a2ada19ee5b8e4012ea696611aa02564a4a95eaf3fb26d1a7e"},
{"name":"gitlab-experiment","version":"0.7.1","platform":"ruby","checksum":"166dddb3aa83428bcaa93c35684ed01dc4d61f321fd2ae40b020806dc54a7824"},
{"name":"gitlab-fog-azure-rm","version":"1.7.0","platform":"ruby","checksum":"969c67943c54ad4c259a6acd040493f13922fbdf2211bb4eca00e71505263dc2"},
-{"name":"gitlab-labkit","version":"0.30.1","platform":"ruby","checksum":"bdedbd86014c83dfd6a50d20dbc1709697bba2bb9e3666383e5f28cbd312b113"},
+{"name":"gitlab-labkit","version":"0.31.1","platform":"ruby","checksum":"3e3a39370966b5d2739c2d9d9005c0ea27541d32cb7292e856e8bd74c720bffb"},
{"name":"gitlab-license","version":"2.2.1","platform":"ruby","checksum":"39fcf6be8b2887df8afe01b5dcbae8d08b7c5d937ff56b0fb40484a8c4f02d30"},
{"name":"gitlab-mail_room","version":"0.0.9","platform":"ruby","checksum":"6700374b5c0aa9d9ad4e711aeb677f0b7d415a6d01d3baa699efab25349d851c"},
{"name":"gitlab-markup","version":"1.9.0","platform":"ruby","checksum":"7eda045a08ec2d110084252fa13a8c9eac8bdac0e302035ca7db4b82bcbd7ed4"},
@@ -231,16 +236,20 @@
{"name":"google-cloud-core","version":"1.6.0","platform":"ruby","checksum":"ea1744cd5a3085d3072de3fab9106afc769cd198609ebb5c6eeb5f13da46b72a"},
{"name":"google-cloud-env","version":"1.6.0","platform":"ruby","checksum":"6179acb946975892c7908748df5722a4ebadfc8cf5bb7b0d8d933ca67183fa15"},
{"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.21.12","platform":"java","checksum":"35362ef8abf98ad597dffee588390b8b3b2f0f3d70261c3eed3f99e564f3289d"},
-{"name":"google-protobuf","version":"3.21.12","platform":"ruby","checksum":"4b09bb7e3168cda689efebcd3373304e124b14aabf776fbf1f0a7615259c8fb5"},
-{"name":"google-protobuf","version":"3.21.12","platform":"x64-mingw-ucrt","checksum":"e4444119acd56bf4661b3f38dc2795abae2cd5c2ade88154d5fc405008fbdcf7"},
-{"name":"google-protobuf","version":"3.21.12","platform":"x64-mingw32","checksum":"e6a879e1100f04506aea352d22f70a0ed77899fc64af3ff8c24a242331be923d"},
-{"name":"google-protobuf","version":"3.21.12","platform":"x86-linux","checksum":"54bbacbca58323fab222746df30e60a55df89f699e319ce0774d5bdd637b3a54"},
-{"name":"google-protobuf","version":"3.21.12","platform":"x86-mingw32","checksum":"979e6388dd5f3171043c5a00ac2f66b2789d7fc67b18207d1aabfa1dc27d9558"},
-{"name":"google-protobuf","version":"3.21.12","platform":"x86_64-darwin","checksum":"d7e59bd1040e510fd67fb96d08be84a4e362641f5229bf3fd870e383b2913574"},
-{"name":"google-protobuf","version":"3.21.12","platform":"x86_64-linux","checksum":"cb6820a68c7807e12ca1e6b69689b833d675ed81435a2179d502575ed5db3de0"},
-{"name":"googleapis-common-protos-types","version":"1.3.0","platform":"ruby","checksum":"c5411f3197cc3e02547ded1858303b1f830b4dc89c588c142ad6c8a231050671"},
+{"name":"google-protobuf","version":"3.22.2","platform":"aarch64-linux","checksum":"21357d807fd4b7e6e423dafa98732bf9a2be2767c06ea81a8a7980e71659783a"},
+{"name":"google-protobuf","version":"3.22.2","platform":"arm64-darwin","checksum":"ee4026e3d24d2c584476dd0dd1ff4662589711709ef5a91b82d36c995bb711d1"},
+{"name":"google-protobuf","version":"3.22.2","platform":"java","checksum":"d3d5389755bcf788717f000c9de41bed64fc211c46687dd41ebf7f8545b57962"},
+{"name":"google-protobuf","version":"3.22.2","platform":"ruby","checksum":"d516c13248500fb4e1af469c2d71e8b6ecffacb6f55e9be203f01b7d0ff01eff"},
+{"name":"google-protobuf","version":"3.22.2","platform":"x64-mingw-ucrt","checksum":"c26f38dde5612793db886a19485db7d3037628edf1d35ee8b5ca1ba16c82d005"},
+{"name":"google-protobuf","version":"3.22.2","platform":"x64-mingw32","checksum":"5c36e9f519988af2ac52444f3881fc4f6f6181a6177c01bae7b8ea007c76f80b"},
+{"name":"google-protobuf","version":"3.22.2","platform":"x86-linux","checksum":"ab49eb312d414e9a7231542240a4fddc52ea8c78007b812132a2c1d9ba943e26"},
+{"name":"google-protobuf","version":"3.22.2","platform":"x86-mingw32","checksum":"7fa69f62e182bae2a32f499da9ce8e5d9412d0a5768764967a7c1d0d89492e2e"},
+{"name":"google-protobuf","version":"3.22.2","platform":"x86_64-darwin","checksum":"e716c0fc6c970d82febf2447de2c762d265c288dbc26c3043c30544c8a4d60d9"},
+{"name":"google-protobuf","version":"3.22.2","platform":"x86_64-linux","checksum":"8fd16e0115d01209494767b6182c2a9f5d257d5f3c495c513762555a46f1ab88"},
+{"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":"grape","version":"1.5.2","platform":"ruby","checksum":"1df3b734c3862e235174232bc629587eddda9ef3df648230827575186700ae29"},
@@ -279,7 +288,7 @@
{"name":"html2text","version":"0.2.0","platform":"ruby","checksum":"31c2f0be9ab7aa4fc780b07d5f84882ebc22a9024c29a45f4f5adfe42e92ad4f"},
{"name":"htmlbeautifier","version":"1.4.2","platform":"ruby","checksum":"9de0c98480fe80d795ed5734a11f183563cd969686f25a04609c0f5a446fa5f8"},
{"name":"htmlentities","version":"4.3.4","platform":"ruby","checksum":"125a73c6c9f2d1b62100b7c3c401e3624441b663762afa7fe428476435a673da"},
-{"name":"http","version":"5.1.0","platform":"ruby","checksum":"b21e4f0dac51f52df001f1fa3dd3b0a8aadf3d8468d3c520c0caddeeb4f1c14a"},
+{"name":"http","version":"5.1.1","platform":"ruby","checksum":"fcaec14a4f82de6d2f9cb978c07326814c6c2b42b8974f6ec166ff19c645ebaf"},
{"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"},
@@ -289,6 +298,7 @@
{"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":"ipaddr","version":"1.2.2","platform":"ruby","checksum":"27916ee6367d549850d3675bc020f1f1ddafbbe1cfc58635f17dfa56c42f9f79"},
@@ -313,8 +323,9 @@
{"name":"knapsack","version":"1.21.1","platform":"ruby","checksum":"82f70422adebcacec1b514f6ebff65265fc85d836e3c320718a160d8ac41cf14"},
{"name":"kramdown","version":"2.3.2","platform":"ruby","checksum":"cb4530c2e9d16481591df2c9336723683c354e5416a5dd3e447fa48215a6a71c"},
{"name":"kramdown-parser-gfm","version":"1.1.0","platform":"ruby","checksum":"fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729"},
+{"name":"kubeclient","version":"4.11.0","platform":"ruby","checksum":"4985fcd749fb8c364a668a8350a49821647f03aa52d9ee6cbc582beb8e883fcc"},
{"name":"launchy","version":"2.5.0","platform":"ruby","checksum":"954243c4255920982ce682f89a42e76372dba94770bf09c23a523e204bdebef5"},
-{"name":"lefthook","version":"1.2.9","platform":"ruby","checksum":"1fd4a768e08fc624e756597fc628b3c7991267325974a7a5cc169595b425701d"},
+{"name":"lefthook","version":"1.3.3","platform":"ruby","checksum":"8269a799d0abad6aaf188edb66a661c729abe6b74f3d8d660529d51f9ed2dc5d"},
{"name":"letter_opener","version":"1.7.0","platform":"ruby","checksum":"095bc0d58e006e5b43ea7d219e64ecf2de8d1f7d9dafc432040a845cf59b4725"},
{"name":"letter_opener_web","version":"2.0.0","platform":"ruby","checksum":"33860ad41e1785d75456500e8ca8bba8ed71ee6eaf08a98d06bbab67c5577b6f"},
{"name":"libyajl2","version":"1.2.0","platform":"ruby","checksum":"1117cd1e48db013b626e36269bbf1cef210538ca6d2e62d3fa3db9ded005b258"},
@@ -362,23 +373,24 @@
{"name":"net-http-persistent","version":"4.0.1","platform":"ruby","checksum":"2752f4cce05fd1c45e0537c6f3a98fa5a4899efd5f88e63c104ed5f05cbddef9"},
{"name":"net-ldap","version":"0.17.1","platform":"ruby","checksum":"52571b55f9157120833ac1667f2969ce0139251811d0a9b64657c1c135069cf9"},
{"name":"net-ntp","version":"2.1.3","platform":"ruby","checksum":"5bc73f4102bde0d1872bd3b293608ae99d9f5007d744f21919c6a565eda9267d"},
+{"name":"net-protocol","version":"0.1.3","platform":"ruby","checksum":"ad43e2be965ede676683c047b2c3d76762aa49a764779d98312a10da04622c14"},
{"name":"net-scp","version":"3.0.0","platform":"ruby","checksum":"8fc6c80365b95230c6bfc529dbea3893d2d81724855bfb01cbf385866e1c902c"},
{"name":"net-ssh","version":"6.0.0","platform":"ruby","checksum":"6290ddcb232380cae79b772af924e12f57fe1dcd0f71254411dd21c04f7b13d0"},
{"name":"netrc","version":"0.11.0","platform":"ruby","checksum":"de1ce33da8c99ab1d97871726cba75151113f117146becbe45aa85cb3dabee3f"},
{"name":"nio4r","version":"2.5.8","platform":"java","checksum":"b2b1800f6bf7ce4b797ca8b639ad278a99c9c904fb087a91d944f38e4bd71401"},
{"name":"nio4r","version":"2.5.8","platform":"ruby","checksum":"3becb4ad95ab8ac0a9bd2e1b16466869402be62848082bf6329ae9091f276676"},
{"name":"no_proxy_fix","version":"0.1.2","platform":"ruby","checksum":"4e9b4c31bb146de7fcf347dc1087bb13ac2039b56d50aa019e61036256abcd00"},
-{"name":"nokogiri","version":"1.14.1","platform":"aarch64-linux","checksum":"99594e8b94f576644ac640a223d74c79e840218948e963aa635f0254927bff10"},
-{"name":"nokogiri","version":"1.14.1","platform":"arm-linux","checksum":"1dc9b7821e1fa1f3fda40659662e51a4b3692acc4ee6342ee34a6a537fc1d5d8"},
-{"name":"nokogiri","version":"1.14.1","platform":"arm64-darwin","checksum":"1a693df86da8c4c97b01d614470f9c3e10b9c755de8803fbfcfffe0f9dff522a"},
-{"name":"nokogiri","version":"1.14.1","platform":"java","checksum":"c1f87a8f7bc56028deb2aecbb29e9b318405f7c468b29047aede78b41bc735a2"},
-{"name":"nokogiri","version":"1.14.1","platform":"ruby","checksum":"b2db3af7769c29cd77d5f39cd3d0b65ab10975bdecf04be71d683f9c9abe2663"},
-{"name":"nokogiri","version":"1.14.1","platform":"x64-mingw-ucrt","checksum":"2463a1ae0be5f06a10f3f3b374c2b743bff6280db993d488511a19bb7bc7cb7c"},
-{"name":"nokogiri","version":"1.14.1","platform":"x64-mingw32","checksum":"f3a2b0ceedf51d776b39dc759ce191a4df842d7d4f5900c64f33d4753db39877"},
-{"name":"nokogiri","version":"1.14.1","platform":"x86-linux","checksum":"f395d6c28c822b0877cfb0c71781f05243c034b4823359ab25b3288a73b9fc82"},
-{"name":"nokogiri","version":"1.14.1","platform":"x86-mingw32","checksum":"be34b32fe74e82bffca5b1f3df8727c8fdc828762b6dddab53a11cd8f8515785"},
-{"name":"nokogiri","version":"1.14.1","platform":"x86_64-darwin","checksum":"9b14091f77086c4f0f09451ba3acd1b5f7e0076fb34fc536682170fa9f1a5074"},
-{"name":"nokogiri","version":"1.14.1","platform":"x86_64-linux","checksum":"21d234c51582b292e2e1e02e6c30eea9188894348985d6910aa8e993749c0aff"},
+{"name":"nokogiri","version":"1.14.2","platform":"aarch64-linux","checksum":"966acf4f6c1fba10518f86498141cf44265564ac5a65dcc8496b65f8c354f776"},
+{"name":"nokogiri","version":"1.14.2","platform":"arm-linux","checksum":"8a3a35cadae4a800ddc0b967394257343d62196d9d059b54e38cf067981db428"},
+{"name":"nokogiri","version":"1.14.2","platform":"arm64-darwin","checksum":"81404cd014ecb597725c3847523c2ee365191a968d0b5f7d857e03f388c57631"},
+{"name":"nokogiri","version":"1.14.2","platform":"java","checksum":"0a39222af14e75eb0243e8d969345e03b90c0e02b0f33c61f1ebb6ae53538bb5"},
+{"name":"nokogiri","version":"1.14.2","platform":"ruby","checksum":"c765a74aac6cf430a710bb0b6038b8ee11f177393cd6ae8dadc7a44a6e2658b6"},
+{"name":"nokogiri","version":"1.14.2","platform":"x64-mingw-ucrt","checksum":"62a18f9213a0ceeaf563d1bc7ccfd93273323c4356ded58a5617c59bc4635bc5"},
+{"name":"nokogiri","version":"1.14.2","platform":"x64-mingw32","checksum":"54f6ac2c15a7a88f431bb5e23f4616aa8fc97a92eb63336bcf65b7050f2d3be0"},
+{"name":"nokogiri","version":"1.14.2","platform":"x86-linux","checksum":"c42fa0856f01f901954898e28c3c2b4dce0e843056b1b126f441d06e887e1b77"},
+{"name":"nokogiri","version":"1.14.2","platform":"x86-mingw32","checksum":"f940d9c8e47b0f19875465376f2d1c8911bc9489ac9a48c124579819dc4a7f19"},
+{"name":"nokogiri","version":"1.14.2","platform":"x86_64-darwin","checksum":"2508978f5ca28944919973f6300f0a7355fbe72604ab6a6913f1630be1030265"},
+{"name":"nokogiri","version":"1.14.2","platform":"x86_64-linux","checksum":"bc6405e1f3ddac6e401f82d775f1c0c24c6e58c371b3fadaca0596d5d511e476"},
{"name":"notiffany","version":"0.1.3","platform":"ruby","checksum":"d37669605b7f8dcb04e004e6373e2a780b98c776f8eb503ac9578557d7808738"},
{"name":"numerizer","version":"0.2.0","platform":"ruby","checksum":"e58076d5ee5370417b7e52d9cb25836d62acd1b8d9a194c308707986c1705d7b"},
{"name":"oauth","version":"0.5.6","platform":"ruby","checksum":"4085fe28e0c5e2434135e00a6555294fd2a4ff96a98d1bdecdcd619fc6368dff"},
@@ -405,7 +417,7 @@
{"name":"open4","version":"1.3.4","platform":"ruby","checksum":"a1df037310624ecc1ea1d81264b11c83e96d0c3c1c6043108d37d396dcd0f4b1"},
{"name":"openid_connect","version":"1.3.0","platform":"ruby","checksum":"a796855096850cc01140e37ea6ae9fd14f2be818b9b5bc698418063dfe228770"},
{"name":"openssl","version":"2.2.2","platform":"ruby","checksum":"53f72382bac046c36c37049c7ec9d5597d42628d140b5cfbcd61e0226c0ca077"},
-{"name":"openssl-signature_algorithm","version":"0.4.0","platform":"ruby","checksum":"e53a225b773784935249cf4c61238c6cf0e1e464e78ae2f8ddaf995fb22ca991"},
+{"name":"openssl-signature_algorithm","version":"1.3.0","platform":"ruby","checksum":"a3b40b5e8276162d4a6e50c7c97cdaf1446f9b2c3946a6fa2c14628e0c957e80"},
{"name":"opentracing","version":"0.5.0","platform":"ruby","checksum":"deb5d7abe6b0e7631d866d8cb5ee7bb9352650a504a32f61591302bc510b9286"},
{"name":"optimist","version":"3.0.1","platform":"ruby","checksum":"336b753676d6117cad9301fac7e91dab4228f747d4e7179891ad3a163c64e2ed"},
{"name":"org-ruby","version":"0.9.12","platform":"ruby","checksum":"93cbec3a4470cb9dca6a4a98dc276a6434ea9d9e7bc2d42ea33c3aedd5d1c974"},
@@ -430,7 +442,7 @@
{"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.17.0","platform":"ruby","checksum":"766d3706f7b26fed5a177843ab15b5b0dc108f9677d8bdbe0c4b5d9375c2af24"},
+{"name":"prometheus-client-mmap","version":"0.19.1","platform":"ruby","checksum":"718b5f1aacab79877b30ae2f897fbf0c6a6d15d7f6e03928abb50a76ba479c7d"},
{"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"},
@@ -491,7 +503,7 @@
{"name":"rexml","version":"3.2.5","platform":"ruby","checksum":"a33c3bf95fda7983ec7f05054f3a985af41dbc25a0339843bd2479e93cabb123"},
{"name":"rinku","version":"2.0.0","platform":"ruby","checksum":"3e695aaf9f24baba3af45823b5c427b58a624582132f18482320e2737f9f8a85"},
{"name":"rotp","version":"6.2.0","platform":"ruby","checksum":"239a2eefba6f1bd4157b2c735d0f975598e0ef94823eea2f35d103d2e5cc0787"},
-{"name":"rouge","version":"3.30.0","platform":"ruby","checksum":"a3d353222aa72e49e2c86726c0bcfd719f82592f57d494474655f48e669eceb6"},
+{"name":"rouge","version":"4.1.0","platform":"ruby","checksum":"0f6fc19a0d66db782f6fa67f56356af4ef001cd43bbd8ad5aa798a081de4dd10"},
{"name":"rqrcode","version":"0.7.0","platform":"ruby","checksum":"8b3a5cba9cc199ba2d781a7c767cb55679f29a3621aa0506a799cec3760d16a1"},
{"name":"rqrcode-rails3","version":"0.1.7","platform":"ruby","checksum":"6f0582f26485123e5ed6f2a8a2871f00d86d353e0f58c8429a5a13212bcf48c4"},
{"name":"rspec","version":"3.12.0","platform":"ruby","checksum":"ccc41799a43509dc0be84070e3f0410ac95cbd480ae7b6c245543eb64162399c"},
@@ -499,7 +511,9 @@
{"name":"rspec-core","version":"3.12.0","platform":"ruby","checksum":"c466f4137966526e177d2156ca45c249eeecc7ed519b23ae2fb80c4675406bc5"},
{"name":"rspec-expectations","version":"3.12.2","platform":"ruby","checksum":"8652db70b25ae3378b7274477a906b6ad1833a7b7cfbb001a03f49dd1c1d6a0d"},
{"name":"rspec-mocks","version":"3.12.3","platform":"ruby","checksum":"cc0a1176707e641a2c66c71fe769486fec57d7df8ec7e34320f8957a1363026b"},
-{"name":"rspec-parameterized","version":"0.5.0","platform":"ruby","checksum":"f163ac07b5edd1eeb13136480623db7020852c70cf0ad2fa98e31384ae162454"},
+{"name":"rspec-parameterized","version":"1.0.0","platform":"ruby","checksum":"9c07b043c72afbd23dd9a1dd48c06f46bc2fb1a6d875c6703e254932ba28b386"},
+{"name":"rspec-parameterized-core","version":"1.0.0","platform":"ruby","checksum":"287b494985e79821160af63aba4f91db8dbfa9a21cb200db34ba38f40e16ccc1"},
+{"name":"rspec-parameterized-table_syntax","version":"1.0.0","platform":"ruby","checksum":"d7df951eff9c5dd367ca7d5f9ae4853bb7ab7941f9d5b35bba361d112704988c"},
{"name":"rspec-rails","version":"6.0.1","platform":"ruby","checksum":"016c8ebd5b38ce5cbce949de2f5b28f2bde7bb78d4de26940516713597b26e34"},
{"name":"rspec-retry","version":"0.6.1","platform":"ruby","checksum":"86b7e8513c5b0c713c2e28854f4d996deb8efa6304eef50f0ad68ee6c563d8da"},
{"name":"rspec-support","version":"3.12.0","platform":"ruby","checksum":"dd4d44b247ff679b95b5607ac5641d197a5f9b1d33f916123cb98fc5f917c58b"},
@@ -513,7 +527,7 @@
{"name":"rubocop-rails","version":"2.17.4","platform":"ruby","checksum":"8004149a14372d3d6cededd000357879fa7eb0421403a7a26bc717e2a98bbedb"},
{"name":"rubocop-rspec","version":"2.18.1","platform":"ruby","checksum":"41c6455630fc98b809ebca047413389e2b7e3f68975028365c07bfea878db5ee"},
{"name":"ruby-fogbugz","version":"0.3.0","platform":"ruby","checksum":"5e04cde474648f498a71cf1e1a7ab42c66b953862fbe224f793ec0a7a1d5f657"},
-{"name":"ruby-magic","version":"0.5.4","platform":"ruby","checksum":"2c17b185130d10a83791f63a40baa358c4b138af37da3f4dab53690121c421d5"},
+{"name":"ruby-magic","version":"0.6.0","platform":"ruby","checksum":"7b2138877b7d23aff812c95564eba6473b74b815ef85beb0eb792e729a2b6101"},
{"name":"ruby-progressbar","version":"1.11.0","platform":"ruby","checksum":"cc127db3866dc414ffccbf92928a241e585b3aa2b758a5563e74a6ee0f57d50a"},
{"name":"ruby-saml","version":"1.13.0","platform":"ruby","checksum":"d31cbdf5fb8fdd6aa3187e48dba3085cfeb751af30276a5739aa3659a66f069c"},
{"name":"ruby-statistics","version":"3.0.0","platform":"ruby","checksum":"610301370346931cb701e3a8d3d3e28eb65681162cae6066c0c11abf20efdc81"},
@@ -533,7 +547,6 @@
{"name":"sassc-rails","version":"2.1.0","platform":"ruby","checksum":"764dcc74e06930e3483caf0d595084d11f2b0fefd6539abf487cdddfba6cafa2"},
{"name":"sawyer","version":"0.9.2","platform":"ruby","checksum":"fa3a72d62a4525517b18857ddb78926aab3424de0129be6772a8e2ba240e7aca"},
{"name":"sd_notify","version":"0.1.1","platform":"ruby","checksum":"cbc7ac6caa7cedd26b30a72b5eeb6f36050dc0752df263452ea24fb5a4ad3131"},
-{"name":"securecompare","version":"1.0.0","platform":"ruby","checksum":"cb0c6599deaaedf6d28f8d88538b06e7198c4826b1b8edb1dbeb44a2162fc62b"},
{"name":"seed-fu","version":"2.3.7","platform":"ruby","checksum":"f19673443e9af799b730e3d4eca6a89b39e5a36825015dffd00d02ea3365cf74"},
{"name":"selenium-webdriver","version":"3.142.7","platform":"ruby","checksum":"dea0993e0e4fdb364f0453144814c0e6099a411d17396807c6cac666d0ddac29"},
{"name":"sentry-rails","version":"5.1.1","platform":"ruby","checksum":"906ef0a776ddc35884ab8b548856ba81c607e3fdee7c9c9f7c44efccc16a657f"},
@@ -580,7 +593,7 @@
{"name":"sqlite3","version":"1.6.0","platform":"x86_64-linux","checksum":"a2488dcf0e72928bab2b15b934113ce8d7a3b4031277e362d66e40956d5c709e"},
{"name":"ssh_data","version":"1.3.0","platform":"ruby","checksum":"ec7c1e95a3aebeee412147998f4c147b4b05da6ed0aafda6083f9449318eaac0"},
{"name":"ssrf_filter","version":"1.0.8","platform":"ruby","checksum":"03f49f54837e407d43ee93ec733a8a94dc1bcf8185647ac61606e63aaedaa0db"},
-{"name":"stackprof","version":"0.2.21","platform":"ruby","checksum":"2b6406c55dc2e134b2789c4cc631d96e67da87821a166f4ae12f15bec5cff5ae"},
+{"name":"stackprof","version":"0.2.23","platform":"ruby","checksum":"5c930b229c27bc64a2a0eb5e7203d76756ba0567bad7bf5290921ee1ed50230b"},
{"name":"state_machines","version":"0.5.0","platform":"ruby","checksum":"23e6249d374a920b528dccade403518b4abbd83841a3e2c9ef13e6f1a009b102"},
{"name":"state_machines-activemodel","version":"0.8.0","platform":"ruby","checksum":"e932dab190d4be044fb5f9cab01a3ea0b092c5f113d4676c6c0a0d49bf738d2c"},
{"name":"state_machines-activerecord","version":"0.8.0","platform":"ruby","checksum":"072fb701b8ab03de0608297f6c55dc34ed096e556fa8f77e556f3c461c71aab6"},
@@ -601,20 +614,23 @@
{"name":"test_file_finder","version":"0.1.4","platform":"ruby","checksum":"bc36d8339eac4fb9dc36514a7c5f4d389ac2fb6d010716fc715c5c8fbb98eacd"},
{"name":"text","version":"1.3.1","platform":"ruby","checksum":"2fbbbc82c1ce79c4195b13018a87cbb00d762bda39241bb3cdc32792759dd3f4"},
{"name":"thor","version":"1.2.1","platform":"ruby","checksum":"b1752153dc9c6b8d3fcaa665e9e1a00a3e73f28da5e238b81c404502e539d446"},
+{"name":"thread_safe","version":"0.3.6","platform":"java","checksum":"bb28394cd0924c068981adee71f36a81c85c92e7d74d3f62372bd51489a0e0c2"},
+{"name":"thread_safe","version":"0.3.6","platform":"ruby","checksum":"9ed7072821b51c57e8d6b7011a8e282e25aeea3a4065eab326e43f66f063b05a"},
{"name":"thrift","version":"0.16.0","platform":"ruby","checksum":"d023286ea89e30444c9f1c28dd76107f87d8aaf85fe1742da1d8cd3b5417dcce"},
{"name":"tilt","version":"2.0.11","platform":"ruby","checksum":"7b180fc472cbdeb186c85d31c0f2d1e61a2c0d77e1d9fd0ca28482a9d972d6a0"},
{"name":"timeliness","version":"0.3.10","platform":"ruby","checksum":"c357233ce19dc53148e8b29dfddde134689f18f52b32928e9dfe12ebcf4a773f"},
+{"name":"timeout","version":"0.3.2","platform":"ruby","checksum":"269b765ea2fb052fc2bfb8d3be2c90d60fe1161f92bf971c91d6151b8a6bcddd"},
{"name":"timfel-krb5-auth","version":"0.8.3","platform":"ruby","checksum":"ab388c9d747fa3cd95baf2cc1c03253e372d8c680adcc543670f4f099854bb80"},
{"name":"tins","version":"1.31.1","platform":"ruby","checksum":"51c4a347c25c630d310cbc2c040ffb84e266c8227f2ade881f1130ee4f9fbecf"},
{"name":"toml-rb","version":"2.2.0","platform":"ruby","checksum":"a1e2c54ac3cc9d49861004f75f0648b3622ac03a76abe105358c31553227d9a6"},
{"name":"tomlrb","version":"1.3.0","platform":"ruby","checksum":"68666bf53fa70ba686a48a7435ce7e086f5227c58c4c993bd9792f4760f2a503"},
-{"name":"tpm-key_attestation","version":"0.9.0","platform":"ruby","checksum":"e469ad9111a68dab4d04596e1c0621d7c877c2e3e247f765af3c04f1adf2b8cd"},
+{"name":"tpm-key_attestation","version":"0.12.0","platform":"ruby","checksum":"e133d80cf24fef0e7a7dfad00fd6aeff01fc79875fbfc66cd8537bbd622b1e6d"},
{"name":"trailblazer-option","version":"0.1.2","platform":"ruby","checksum":"20e4f12ea4e1f718c8007e7944ca21a329eee4eed9e0fa5dde6e8ad8ac4344a3"},
{"name":"train-core","version":"3.4.9","platform":"ruby","checksum":"d7ad8fa9a379c43a30baaaf1141af1cb28349d386c054f7fc81d169a625d6edd"},
{"name":"truncato","version":"0.7.12","platform":"ruby","checksum":"fed9e8a04fa35fd1a64506cd2089761bae4adfe47e756c3ce98a5c43856c9c4c"},
{"name":"tty-color","version":"0.6.0","platform":"ruby","checksum":"6f9c37ca3a4e2367fb2e6d09722762647d6f455c111f05b59f35730eeb24332a"},
{"name":"tty-cursor","version":"0.7.1","platform":"ruby","checksum":"79534185e6a777888d88628b14b6a1fdf5154a603f285f80b1753e1908e0bf48"},
-{"name":"tty-markdown","version":"0.7.1","platform":"ruby","checksum":"062face5613adc2ec3d500e4c06e6b090699a97cad62d9dfa55d645f60ebdc92"},
+{"name":"tty-markdown","version":"0.7.2","platform":"ruby","checksum":"1ed81db97028d006ba81e2cfd9fe0a04b0eb28650ad0d4086ed6e5627f4ac511"},
{"name":"tty-prompt","version":"0.23.1","platform":"ruby","checksum":"fcdbce905238993f27eecfdf67597a636bc839d92192f6a0eef22b8166449ec8"},
{"name":"tty-reader","version":"0.9.0","platform":"ruby","checksum":"c62972c985c0b1566f0e56743b6a7882f979d3dc32ff491ed490a076f899c2b1"},
{"name":"tty-screen","version":"0.8.1","platform":"ruby","checksum":"6508657c38f32bdca64880abe201ce237d80c94146e1f9b911cba3c7823659a2"},
@@ -633,7 +649,7 @@
{"name":"unicode_utils","version":"1.4.0","platform":"ruby","checksum":"b922d0cf2313b6b7136ada6645ce7154ffc86418ca07d53b058efe9eb72f2a40"},
{"name":"uniform_notifier","version":"1.16.0","platform":"ruby","checksum":"99b39ee4a0864e3b49f375b5e5803eb26d35ed6eb1719c96407573a87bc4dbb5"},
{"name":"unleash","version":"3.2.2","platform":"ruby","checksum":"0f6e56498de920de66a01bceffb93933693ade646bb853fc70eb16bd1026b93b"},
-{"name":"unparser","version":"0.6.0","platform":"ruby","checksum":"4afa0540583032d28a623e65f057809fdbed6dc84bd8a1de93262e1aa4618608"},
+{"name":"unparser","version":"0.6.7","platform":"ruby","checksum":"ae42e73edfa273766e66c166368fb75ca5972cd8ec50c536253e0f6299a9dec8"},
{"name":"uri_template","version":"0.7.0","platform":"ruby","checksum":"312c8fe13700db86ac9d05ea997af3db03abdf50c65b1801d775bc7a695f185d"},
{"name":"valid_email","version":"0.1.3","platform":"ruby","checksum":"b81452b51b64c4beb67913f68db52c20ecb4d73d45512f5b282ab4a3f4416570"},
{"name":"validate_email","version":"0.1.6","platform":"ruby","checksum":"9dfe9016d527b17a8d3a6e95e4dc50a125400eef899d13d4cc2a254393f82ee4"},
@@ -642,10 +658,11 @@
{"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":"2.74.1","platform":"ruby","checksum":"0bbd47a9c11455a45043dc01aa604db708654718a4d8755c911425482e8392c0"},
+{"name":"virtus","version":"2.0.0","platform":"ruby","checksum":"8841dae4eb7fcc097320ba5ea516bf1839e5d056c61ee27138aa4bddd6e3d1c2"},
{"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":"2.3.0","platform":"ruby","checksum":"96fbee59f4a45219f1dae96f467b693de144f871be9ec6ea357168624dacd89e"},
+{"name":"webauthn","version":"3.0.0","platform":"ruby","checksum":"3f77d422c2a8a4b31e56cf42f83414bd066e0506e9896936e1730262dc4a20e6"},
{"name":"webfinger","version":"1.2.0","platform":"ruby","checksum":"7814ef1c85da47514f65c6e5ca14205fa9ce41ea2a70785e0c872842162852a2"},
{"name":"webmock","version":"3.9.1","platform":"ruby","checksum":"bcf6822456b234fb1bed2b0a89bff31fe0641214b44f6ba4ced2b824cf31337d"},
{"name":"webrick","version":"1.6.1","platform":"ruby","checksum":"0b4d1eab918f5f53333c690ad470825e51844ce9851e403a3fd47d6a84d9d67c"},
diff --git a/Gemfile.lock b/Gemfile.lock
index c988145616e..1f1f566be37 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -11,6 +11,15 @@ PATH
bundler
PATH
+ remote: vendor/gems/cloud_profiler_agent
+ specs:
+ cloud_profiler_agent (0.0.1.pre)
+ google-cloud-profiler-v2 (~> 0.3)
+ google-protobuf (~> 3.13)
+ googleauth (>= 0.14)
+ stackprof (~> 0.2)
+
+PATH
remote: vendor/gems/devise-pbkdf2-encryptable
specs:
devise-pbkdf2-encryptable (0.0.0)
@@ -31,15 +40,6 @@ PATH
oj (~> 3.13.16)
PATH
- remote: vendor/gems/kubeclient
- specs:
- kubeclient (4.9.4.pre.gitlab1)
- http (>= 3.0, < 6.0)
- jsonpath (~> 1.0)
- recursive-open-struct (~> 1.1, >= 1.1.1)
- rest-client (~> 2.0)
-
-PATH
remote: vendor/gems/mail-smtp_pool
specs:
mail-smtp_pool (0.1.0)
@@ -184,10 +184,10 @@ GEM
faraday_middleware (~> 1.0)
faraday_middleware-multi_json (~> 0.0)
oauth2 (>= 1.4, < 3)
- asciidoctor (2.0.17)
+ asciidoctor (2.0.18)
asciidoctor-include-ext (0.4.0)
asciidoctor (>= 1.5.6, < 3.0.0)
- asciidoctor-kroki (0.7.0)
+ asciidoctor-kroki (0.8.0)
asciidoctor (~> 2.0)
asciidoctor-plantuml (0.0.16)
asciidoctor (>= 2.0.17, < 3.0.0)
@@ -198,13 +198,13 @@ GEM
autoprefixer-rails (10.2.5.1)
execjs (> 0)
awesome_print (1.9.2)
- awrence (1.1.1)
+ awrence (1.2.1)
aws-eventstream (1.2.0)
- aws-partitions (1.703.0)
+ aws-partitions (1.730.0)
aws-sdk-cloudformation (1.41.0)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.1)
- aws-sdk-core (3.170.0)
+ aws-sdk-core (3.170.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
@@ -218,6 +218,17 @@ GEM
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.1)
aws-eventstream (~> 1, >= 1.0.2)
+ axe-core-api (4.6.0)
+ dumb_delegator
+ virtus
+ axe-core-rspec (4.6.0)
+ axe-core-api
+ dumb_delegator
+ virtus
+ axiom-types (0.1.1)
+ descendants_tracker (~> 0.0.4)
+ ice_nine (~> 0.11.0)
+ thread_safe (~> 0.3, >= 0.3.1)
azure-storage-blob (2.0.3)
azure-storage-common (~> 2.0)
nokogiri (~> 1, >= 1.10.8)
@@ -232,7 +243,7 @@ GEM
batch-loader (2.0.1)
bcrypt (3.1.16)
benchmark (0.2.0)
- benchmark-ips (2.3.0)
+ benchmark-ips (2.11.0)
benchmark-malloc (0.2.0)
benchmark-memory (0.2.0)
memory_profiler (~> 1)
@@ -243,7 +254,8 @@ GEM
erubi (>= 1.0.0)
rack (>= 0.9.0)
bindata (2.4.11)
- binding_ninja (0.2.3)
+ binding_of_caller (1.0.0)
+ debug_inspector (>= 0.0.1)
bootsnap (1.16.0)
msgpack (~> 1.2)
browser (5.3.1)
@@ -292,15 +304,17 @@ GEM
nap
open4 (~> 1.3)
coderay (1.1.3)
+ coercible (1.0.0)
+ descendants_tracker (~> 0.0.1)
colored2 (3.1.2)
commonmarker (0.23.6)
concurrent-ruby (1.2.0)
connection_pool (2.3.0)
cork (0.3.0)
colored2 (~> 3.1)
- cose (1.0.0)
+ cose (1.3.0)
cbor (~> 0.5.9)
- openssl-signature_algorithm (~> 0.4.0)
+ openssl-signature_algorithm (~> 1.0)
countries (4.0.1)
i18n_data (~> 0.13.0)
sixarm_ruby_unaccent (~> 1.1)
@@ -310,7 +324,7 @@ GEM
creole (0.5.0)
crystalball (0.7.0)
git
- css_parser (1.12.0)
+ css_parser (1.14.0)
addressable
cvss-suite (3.0.1)
danger (8.6.1)
@@ -331,12 +345,11 @@ GEM
gitlab (~> 4.2, >= 4.2.0)
database_cleaner (1.7.0)
dead_end (3.1.1)
+ debug_inspector (1.1.0)
deckar01-task_list (2.3.2)
html-pipeline
declarative (0.0.20)
declarative_policy (1.1.0)
- default_value_for (3.4.0)
- activerecord (>= 3.2.0, < 7.0)
deprecation_toolkit (1.5.1)
activesupport (>= 4.2)
derailed_benchmarks (2.1.2)
@@ -351,6 +364,8 @@ GEM
rake (> 10, < 14)
ruby-statistics (>= 2.1)
thor (>= 0.19, < 2)
+ descendants_tracker (0.0.4)
+ thread_safe (~> 0.3, >= 0.3.1)
device_detector (1.0.0)
devise (4.8.1)
bcrypt (~> 3.0)
@@ -400,6 +415,8 @@ GEM
dry-equalizer (~> 0.3)
dry-inflector (~> 0.1, >= 0.1.2)
dry-logic (~> 1.0, >= 1.0.2)
+ dumb_delegator (1.0.0)
+ duo_api (1.3.0)
e2mmap (0.1.0)
ecma-re-validator (0.3.0)
regexp_parser (~> 2.0)
@@ -502,7 +519,7 @@ GEM
fog-json
ipaddress (~> 0.8)
xml-simple (~> 1.1)
- fog-aws (3.15.0)
+ fog-aws (3.18.0)
fog-core (~> 2.1)
fog-json (~> 1.1)
fog-xml (~> 0.1)
@@ -528,15 +545,6 @@ GEM
multi_json (~> 1.10)
fog-local (0.8.0)
fog-core (>= 1.27, < 3.0)
- fog-openstack (1.0.8)
- fog-core (~> 2.1)
- fog-json (>= 1.0)
- ipaddress (>= 0.8)
- fog-rackspace (0.1.1)
- fog-core (>= 1.35)
- fog-json (>= 1.0)
- fog-xml (>= 0.1)
- ipaddress (>= 0.8)
fog-xml (0.1.3)
fog-core
nokogiri (>= 1.5.11, < 2.0.0)
@@ -548,6 +556,14 @@ GEM
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
fuzzyurl (0.9.0)
+ gapic-common (0.18.0)
+ faraday (>= 1.9, < 3.a)
+ faraday-retry (>= 1.0, < 3.a)
+ google-protobuf (~> 3.14)
+ googleapis-common-protos (>= 1.3.12, < 2.a)
+ googleapis-common-protos-types (>= 1.3.1, < 2.a)
+ googleauth (~> 1.0)
+ grpc (~> 1.36)
gemoji (3.0.1)
get_process_mem (0.2.7)
ffi (~> 1.0)
@@ -570,7 +586,7 @@ GEM
terminal-table (>= 1.5.1)
gitlab-chronic (0.10.5)
numerizer (~> 0.2)
- gitlab-dangerfiles (3.7.0)
+ gitlab-dangerfiles (3.8.0)
danger (>= 8.4.5)
danger-gitlab (>= 8.0.0)
rake
@@ -584,7 +600,7 @@ GEM
fog-json (~> 1.2.0)
mime-types
ms_rest_azure (~> 0.12.0)
- gitlab-labkit (0.30.1)
+ gitlab-labkit (0.31.1)
actionpack (>= 5.0.0, < 8.0.0)
activesupport (>= 5.0.0, < 8.0.0)
grpc (>= 1.37)
@@ -660,6 +676,9 @@ GEM
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.0)
+ google-cloud-profiler-v2 (0.4.0)
+ gapic-common (>= 0.18.0, < 2.a)
+ google-cloud-errors (~> 1.0)
google-cloud-storage (1.44.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
@@ -668,8 +687,12 @@ GEM
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
- google-protobuf (3.21.12)
- googleapis-common-protos-types (1.3.0)
+ google-protobuf (3.22.2)
+ googleapis-common-protos (1.4.0)
+ google-protobuf (~> 3.14)
+ googleapis-common-protos-types (~> 1.2)
+ grpc (~> 1.27)
+ googleapis-common-protos-types (1.5.0)
google-protobuf (~> 3.14)
googleauth (1.3.0)
faraday (>= 0.17.3, < 3.a)
@@ -770,7 +793,7 @@ GEM
nokogiri (~> 1.6)
htmlbeautifier (1.4.2)
htmlentities (4.3.4)
- http (5.1.0)
+ http (5.1.1)
addressable (~> 2.8)
http-cookie (~> 1.0)
http-form_data (~> 2.2)
@@ -789,6 +812,7 @@ GEM
icalendar (2.8.0)
ice_cube (~> 0.16)
ice_cube (0.16.4)
+ ice_nine (0.11.2)
imagen (0.1.8)
parser (>= 2.5, != 2.5.1.1)
invisible_captcha (2.0.0)
@@ -843,9 +867,14 @@ GEM
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
+ kubeclient (4.11.0)
+ http (>= 3.0, < 6.0)
+ jsonpath (~> 1.0)
+ recursive-open-struct (~> 1.1, >= 1.1.1)
+ rest-client (~> 2.0)
launchy (2.5.0)
addressable (~> 2.7)
- lefthook (1.2.9)
+ lefthook (1.3.3)
letter_opener (1.7.0)
launchy (~> 2.2)
letter_opener_web (2.0.0)
@@ -945,13 +974,15 @@ GEM
connection_pool (~> 2.2)
net-ldap (0.17.1)
net-ntp (2.1.3)
+ net-protocol (0.1.3)
+ timeout
net-scp (3.0.0)
net-ssh (>= 2.6.5, < 7.0.0)
net-ssh (6.0.0)
netrc (0.11.0)
nio4r (2.5.8)
no_proxy_fix (0.1.2)
- nokogiri (1.14.1)
+ nokogiri (1.14.2)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
notiffany (0.1.3)
@@ -1041,7 +1072,8 @@ GEM
webfinger (>= 1.0.1)
openssl (2.2.2)
ipaddr
- openssl-signature_algorithm (0.4.0)
+ openssl-signature_algorithm (1.3.0)
+ openssl (> 2.0)
opentracing (0.5.0)
optimist (3.0.1)
org-ruby (0.9.12)
@@ -1097,7 +1129,7 @@ GEM
coderay
parser
unparser
- prometheus-client-mmap (0.17.0)
+ prometheus-client-mmap (0.19.1)
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
@@ -1223,7 +1255,7 @@ GEM
rexml (3.2.5)
rinku (2.0.0)
rotp (6.2.0)
- rouge (3.30.0)
+ rouge (4.1.0)
rqrcode (0.7.0)
chunky_png
rqrcode-rails3 (0.1.7)
@@ -1245,12 +1277,17 @@ GEM
rspec-mocks (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
- rspec-parameterized (0.5.0)
- binding_ninja (>= 0.2.3)
+ rspec-parameterized (1.0.0)
+ rspec-parameterized-core (< 2)
+ rspec-parameterized-table_syntax (< 2)
+ rspec-parameterized-core (1.0.0)
parser
proc_to_ast
rspec (>= 2.13, < 4)
unparser
+ rspec-parameterized-table_syntax (1.0.0)
+ binding_of_caller
+ rspec-parameterized-core (< 2)
rspec-rails (6.0.1)
actionpack (>= 6.1)
activesupport (>= 6.1)
@@ -1298,8 +1335,8 @@ GEM
ruby-fogbugz (0.3.0)
crack (~> 0.4)
multipart-post (~> 2.0)
- ruby-magic (0.5.4)
- mini_portile2 (~> 2.6)
+ ruby-magic (0.6.0)
+ mini_portile2 (~> 2.8)
ruby-progressbar (1.11.0)
ruby-saml (1.13.0)
nokogiri (>= 1.10.5)
@@ -1335,7 +1372,6 @@ GEM
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
sd_notify (0.1.1)
- securecompare (1.0.0)
seed-fu (2.3.7)
activerecord (>= 3.1)
activesupport (>= 3.1)
@@ -1425,7 +1461,7 @@ GEM
mini_portile2 (~> 2.8.0)
ssh_data (1.3.0)
ssrf_filter (1.0.8)
- stackprof (0.2.21)
+ stackprof (0.2.23)
state_machines (0.5.0)
state_machines-activemodel (0.8.0)
activemodel (>= 5.1)
@@ -1463,18 +1499,21 @@ GEM
faraday (~> 1.0)
text (1.3.1)
thor (1.2.1)
+ thread_safe (0.3.6)
thrift (0.16.0)
tilt (2.0.11)
timeliness (0.3.10)
+ timeout (0.3.2)
timfel-krb5-auth (0.8.3)
tins (1.31.1)
sync
toml-rb (2.2.0)
citrus (~> 3.0, > 3.0)
tomlrb (1.3.0)
- tpm-key_attestation (0.9.0)
+ tpm-key_attestation (0.12.0)
bindata (~> 2.4)
- openssl-signature_algorithm (~> 0.4.0)
+ openssl (> 2.0)
+ openssl-signature_algorithm (~> 1.0)
trailblazer-option (0.1.2)
train-core (3.4.9)
addressable (~> 2.5)
@@ -1488,10 +1527,10 @@ GEM
nokogiri (>= 1.7.0, <= 2.0)
tty-color (0.6.0)
tty-cursor (0.7.1)
- tty-markdown (0.7.1)
+ tty-markdown (0.7.2)
kramdown (>= 1.16.2, < 3.0)
pastel (~> 0.8)
- rouge (~> 3.14)
+ rouge (>= 3.14, < 5.0)
strings (~> 0.2.0)
tty-color (~> 0.5)
tty-screen (~> 0.8)
@@ -1521,9 +1560,9 @@ GEM
uniform_notifier (1.16.0)
unleash (3.2.2)
murmurhash3 (~> 0.1.6)
- unparser (0.6.0)
+ unparser (0.6.7)
diff-lcs (~> 1.3)
- parser (>= 3.0.0)
+ parser (>= 3.2.0)
uri_template (0.7.0)
valid_email (0.1.3)
activemodel
@@ -1543,20 +1582,23 @@ GEM
activesupport (>= 5.0.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
+ virtus (2.0.0)
+ axiom-types (~> 0.1)
+ coercible (~> 1.0)
+ descendants_tracker (~> 0.0, >= 0.0.3)
vmstat (2.3.0)
warden (1.2.9)
rack (>= 2.0.9)
warning (1.3.0)
- webauthn (2.3.0)
+ webauthn (3.0.0)
android_key_attestation (~> 0.3.0)
awrence (~> 1.1)
bindata (~> 2.4)
cbor (~> 0.5.9)
- cose (~> 1.0)
- openssl (~> 2.0)
+ cose (~> 1.1)
+ openssl (>= 2.2)
safety_net_attestation (~> 0.4.0)
- securecompare (~> 1.0)
- tpm-key_attestation (~> 0.9.0)
+ tpm-key_attestation (~> 0.12.0)
webfinger (1.2.0)
activesupport
httpclient (>= 2.4)
@@ -1587,7 +1629,7 @@ PLATFORMS
ruby
DEPENDENCIES
- CFPropertyList
+ CFPropertyList (~> 3.0.0)
RedCloth (~> 4.3.2)
acme-client (~> 2.0)
activerecord-explain-analyze (~> 0.1)
@@ -1598,22 +1640,23 @@ DEPENDENCIES
app_store_connect
arr-pm (~> 0.0.12)
asana (~> 0.10.13)
- asciidoctor (~> 2.0.17)
+ asciidoctor (~> 2.0.18)
asciidoctor-include-ext (~> 0.4.0)
- asciidoctor-kroki (~> 0.7.0)
+ asciidoctor-kroki (~> 0.8.0)
asciidoctor-plantuml (~> 0.0.16)
atlassian-jwt (~> 0.2.0)
attr_encrypted (~> 3.2.4)!
autoprefixer-rails (= 10.2.5.1)
awesome_print
aws-sdk-cloudformation (~> 1)
- aws-sdk-core (~> 3.170.0)
+ aws-sdk-core (~> 3.170.1)
aws-sdk-s3 (~> 1.119.1)
+ axe-core-rspec
babosa (~> 1.0.4)
base32 (~> 0.3.0)
batch-loader (~> 2.0.1)
bcrypt (~> 3.1, >= 3.1.14)
- benchmark-ips (~> 2.3.0)
+ benchmark-ips (~> 2.11.0)
benchmark-memory (~> 0.1)
better_errors (~> 2.9.1)
bootsnap (~> 1.16.0)
@@ -1625,6 +1668,7 @@ DEPENDENCIES
capybara-screenshot (~> 1.0.22)
carrierwave (~> 1.3)
charlock_holmes (~> 0.7.7)
+ cloud_profiler_agent (~> 0.0.0)!
commonmarker (~> 0.23.6)
concurrent-ruby (~> 1.1)
connection_pool (~> 2.0)
@@ -1635,7 +1679,6 @@ DEPENDENCIES
database_cleaner (~> 1.7.0)
deckar01-task_list (= 2.3.2)
declarative_policy (~> 1.1.0)
- default_value_for (~> 3.4.0)
deprecation_toolkit (~> 1.5.1)
derailed_benchmarks
device_detector
@@ -1647,6 +1690,7 @@ DEPENDENCIES
discordrb-webhooks (~> 3.4)
doorkeeper (~> 5.5)
doorkeeper-openid_connect (~> 1.8)
+ duo_api (~> 1.3)
ed25519 (~> 1.3.0)
elasticsearch-api (= 7.13.3)
elasticsearch-model (~> 7.2)
@@ -1663,12 +1707,10 @@ DEPENDENCIES
flipper-active_record (~> 0.25.0)
flipper-active_support_cache_store (~> 0.25.0)
fog-aliyun (~> 0.4)
- fog-aws (~> 3.15)
+ fog-aws (~> 3.18)
fog-core (= 2.1.0)
fog-google (~> 1.19)
fog-local (~> 0.8)
- fog-openstack (~> 1.0)
- fog-rackspace (~> 0.1.1)
fugit (~> 1.8.1)
fuubar (~> 2.2.0)
gettext (~> 3.3)
@@ -1676,10 +1718,10 @@ DEPENDENCIES
gettext_i18n_rails_js (~> 1.3)
gitaly (~> 15.9.0.pre.rc3)
gitlab-chronic (~> 0.10.5)
- gitlab-dangerfiles (~> 3.7.0)
+ gitlab-dangerfiles (~> 3.8.0)
gitlab-experiment (~> 0.7.1)
gitlab-fog-azure-rm (~> 1.7.0)
- gitlab-labkit (~> 0.30.1)
+ gitlab-labkit (~> 0.31.1)
gitlab-license (~> 2.2.1)
gitlab-mail_room (~> 0.0.9)
gitlab-markup (~> 1.9.0)
@@ -1699,7 +1741,7 @@ DEPENDENCIES
google-apis-serviceusage_v1 (~> 0.28.0)
google-apis-sqladmin_v1beta4 (~> 0.41.0)
google-cloud-storage (~> 1.44.0)
- google-protobuf (~> 3.21, >= 3.21.12)
+ google-protobuf (~> 3.22, >= 3.22.2)
gpgme (~> 2.0.22)
grape (~> 1.5.2)
grape-entity (~> 0.10.0)
@@ -1737,8 +1779,8 @@ DEPENDENCIES
kas-grpc (~> 0.0.2)
knapsack (~> 1.21.1)
kramdown (~> 2.3.1)
- kubeclient (~> 4.9.3)!
- lefthook (~> 1.2.9)
+ kubeclient (~> 4.11.0)
+ lefthook (~> 1.3.3)
letter_opener_web (~> 2.0.0)
license_finder (~> 7.0)
licensee (~> 9.15)
@@ -1758,7 +1800,8 @@ DEPENDENCIES
multi_json (~> 1.14.1)
net-ldap (~> 0.17.1)
net-ntp
- nokogiri (~> 1.14.1)
+ net-protocol (~> 0.1.3)
+ nokogiri (~> 1.14.2)
oauth2 (~> 2.0)
octokit (~> 4.15)
ohai (~> 16.10)
@@ -1793,7 +1836,7 @@ DEPENDENCIES
pg_query (~> 2.2, >= 2.2.1)
png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3)
- prometheus-client-mmap (~> 0.17)
+ prometheus-client-mmap (~> 0.19)
pry-byebug
pry-rails (~> 0.3.9)
pry-shell (~> 0.6.1)
@@ -1820,17 +1863,17 @@ DEPENDENCIES
responders (~> 3.0)
retriable (~> 3.1.2)
rexml (~> 3.2.5)
- rouge (~> 3.30.0)
+ rouge (~> 4.1.0)
rqrcode-rails3 (~> 0.1.7)
rspec-benchmark (~> 0.6.0)
- rspec-parameterized
+ rspec-parameterized (~> 1.0)
rspec-rails (~> 6.0.1)
rspec-retry (~> 0.6.1)
rspec_junit_formatter
rspec_profiling (~> 0.0.6)
rubocop
ruby-fogbugz (~> 0.3.0)
- ruby-magic (~> 0.5)
+ ruby-magic (~> 0.6)
ruby-progressbar (~> 1.10)
ruby-saml (~> 1.13.0)
ruby_parser (~> 3.19)
@@ -1863,7 +1906,7 @@ DEPENDENCIES
sprite-factory (~> 1.7)
sprockets (~> 3.7.0)
ssh_data (~> 1.3)
- stackprof (~> 0.2.21)
+ stackprof (~> 0.2.23)
state_machines-activerecord (~> 0.8.0)
sys-filesystem (~> 1.4.3)
tanuki_emoji (~> 0.6)
@@ -1886,11 +1929,11 @@ DEPENDENCIES
view_component (~> 2.74.1)
vmstat (~> 2.3.0)
warning (~> 1.3.0)
- webauthn (~> 2.3)
+ webauthn (~> 3.0)
webmock (~> 3.9.1)
webrick (~> 1.6.1)
wikicloth (= 0.8.1)
yajl-ruby (~> 1.4.3)
BUNDLED WITH
- 2.4.6
+ 2.4.8
diff --git a/README.md b/README.md
index 29d5d599972..b61af1b1f42 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the
GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL/OpenSUSE
-- Ruby (MRI) 2.7.7
+- Ruby (MRI) 3.0.5
- Git 2.33+
- Redis 5.0+
- PostgreSQL 12+
diff --git a/app/assets/images/learn_gitlab/section_code.svg b/app/assets/images/learn_gitlab/section_code.svg
new file mode 100644
index 00000000000..da170c93be6
--- /dev/null
+++ b/app/assets/images/learn_gitlab/section_code.svg
@@ -0,0 +1,4 @@
+<svg width="25" height="30" viewBox="0 0 20 23" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M15 8L15 9.5C15 10.3284 15.6716 11 16.5 11C17.3284 11 18 10.3284 18 9.5V7.74264C18 6.94699 17.6839 6.18393 17.1213 5.62132L12.8787 1.37868C12.3161 0.816071 11.553 0.5 10.7574 0.5H1.5C0.671573 0.5 0 1.17157 0 2V20C0 20.8284 0.671573 21.5 1.5 21.5H6C6.82843 21.5 7.5 20.8284 7.5 20C7.5 19.1716 6.82843 18.5 6 18.5H3V3.5H10.5V6.5C10.5 7.32843 11.1716 8 12 8H15Z" fill="#6E49CB"/>
+<path d="M10.5 18.5C10.5 17.6716 11.1716 17 12 17H13.5V15.5C13.5 14.6716 14.1716 14 15 14C15.8284 14 16.5 14.6716 16.5 15.5V17H18C18.8284 17 19.5 17.6716 19.5 18.5C19.5 19.3284 18.8284 20 18 20H16.5V21.5C16.5 22.3284 15.8284 23 15 23C14.1716 23 13.5 22.3284 13.5 21.5V20H12C11.1716 20 10.5 19.3284 10.5 18.5Z" fill="#6E49CB"/>
+</svg>
diff --git a/app/assets/javascripts/access_tokens/components/new_access_token_app.vue b/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
index d24285af5c3..02159d4d524 100644
--- a/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
+++ b/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
@@ -1,6 +1,6 @@
<script>
import { GlAlert } from '@gitlab/ui';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { __, n__, sprintf } from '~/locale';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js
index 6fc37e9331f..d6fdcea468a 100644
--- a/app/assets/javascripts/activities.js
+++ b/app/assets/javascripts/activities.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import { setCookie } from '~/lib/utils/common_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import { localTimeAgo } from './lib/utils/datetime_utility';
import Pager from './pager';
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 a41ff42df20..c66b595ffdc 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
@@ -2,7 +2,7 @@
import { GlModal, GlTabs, GlTab, GlSearchBoxByType, GlSprintf, GlBadge } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import ReviewTabContainer from '~/add_context_commits_modal/components/review_tab_container.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
diff --git a/app/assets/javascripts/add_context_commits_modal/store/actions.js b/app/assets/javascripts/add_context_commits_modal/store/actions.js
index d4c9db2fa33..de9c7488ace 100644
--- a/app/assets/javascripts/add_context_commits_modal/store/actions.js
+++ b/app/assets/javascripts/add_context_commits_modal/store/actions.js
@@ -1,6 +1,6 @@
import _ from 'lodash';
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
import * as types from './mutation_types';
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
new file mode 100644
index 00000000000..a4211002f71
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
@@ -0,0 +1,41 @@
+<script>
+import { getTimeago } from '~/lib/utils/datetime_utility';
+import { __, sprintf } from '~/locale';
+import ListItem from '~/vue_shared/components/registry/list_item.vue';
+
+export default {
+ name: 'AbuseReportRow',
+ components: {
+ ListItem,
+ },
+ props: {
+ report: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ updatedAt() {
+ const template = __('Updated %{timeAgo}');
+ return sprintf(template, { timeAgo: getTimeago().format(this.report.updatedAt) });
+ },
+ title() {
+ const { reportedUser, reporter, category } = this.report;
+ const template = __('%{reported} reported for %{category} by %{reporter}');
+ return sprintf(template, { reported: reportedUser.name, reporter: reporter.name, category });
+ },
+ },
+};
+</script>
+
+<template>
+ <list-item data-testid="abuse-report-row">
+ <template #left-primary>
+ <div class="gl-font-weight-normal" data-testid="title">{{ title }}</div>
+ </template>
+
+ <template #right-secondary>
+ <div data-testid="updated-at">{{ updatedAt }}</div>
+ </template>
+ </list-item>
+</template>
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue
new file mode 100644
index 00000000000..b60fe3ae9b8
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue
@@ -0,0 +1,109 @@
+<script>
+import { setUrlParams, redirectTo, queryToObject, updateHistory } from '~/lib/utils/url_utility';
+import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
+import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
+import {
+ FILTERED_SEARCH_TOKENS,
+ DEFAULT_SORT,
+ SORT_OPTIONS,
+ isValidSortKey,
+} from '~/admin/abuse_reports/constants';
+import { buildFilteredSearchCategoryToken } from '~/admin/abuse_reports/utils';
+
+export default {
+ name: 'AbuseReportsFilteredSearchBar',
+ components: { FilteredSearchBar },
+ sortOptions: SORT_OPTIONS,
+ inject: ['categories'],
+ data() {
+ return {
+ initialFilterValue: [],
+ initialSortBy: DEFAULT_SORT,
+ };
+ },
+ computed: {
+ tokens() {
+ return [...FILTERED_SEARCH_TOKENS, buildFilteredSearchCategoryToken(this.categories)];
+ },
+ },
+ created() {
+ const query = queryToObject(window.location.search);
+
+ // Backend shows open reports by default if status param is not specified.
+ // To match that behavior, update the current URL to include status=open
+ // query when no status query is specified on load.
+ if (!query.status) {
+ query.status = 'open';
+ updateHistory({ url: setUrlParams(query), replace: true });
+ }
+
+ const sort = this.currentSortKey();
+ if (sort) {
+ this.initialSortBy = query.sort;
+ }
+
+ const tokens = this.tokens
+ .filter((token) => query[token.type])
+ .map((token) => ({
+ type: token.type,
+ value: {
+ data: query[token.type],
+ operator: '=',
+ },
+ }));
+
+ this.initialFilterValue = tokens;
+ },
+ methods: {
+ currentSortKey() {
+ const { sort } = queryToObject(window.location.search);
+
+ return isValidSortKey(sort) ? sort : undefined;
+ },
+ handleFilter(tokens) {
+ let params = tokens.reduce((accumulator, token) => {
+ const { type, value } = token;
+
+ // We don't support filtering reports by search term for now
+ if (!value || !type || type === FILTERED_SEARCH_TERM) {
+ return accumulator;
+ }
+
+ return {
+ ...accumulator,
+ [type]: value.data,
+ };
+ }, {});
+
+ const sort = this.currentSortKey();
+ if (sort) {
+ params = { ...params, sort };
+ }
+
+ redirectTo(setUrlParams(params, window.location.href, true));
+ },
+ handleSort(sort) {
+ const { page, ...query } = queryToObject(window.location.search);
+
+ redirectTo(setUrlParams({ ...query, sort }, window.location.href, true));
+ },
+ },
+ filteredSearchNamespace: 'abuse_reports',
+ recentSearchesStorageKey: 'abuse_reports',
+};
+</script>
+
+<template>
+ <filtered-search-bar
+ :namespace="$options.filteredSearchNamespace"
+ :tokens="tokens"
+ :recent-searches-storage-key="$options.recentSearchesStorageKey"
+ :search-input-placeholder="__('Filter reports')"
+ :initial-filter-value="initialFilterValue"
+ :initial-sort-by="initialSortBy"
+ :sort-options="$options.sortOptions"
+ data-testid="abuse-reports-filtered-search-bar"
+ @onFilter="handleFilter"
+ @onSort="handleSort"
+ />
+</template>
diff --git a/app/assets/javascripts/admin/abuse_reports/components/app.vue b/app/assets/javascripts/admin/abuse_reports/components/app.vue
new file mode 100644
index 00000000000..e1e75a4f8d0
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/components/app.vue
@@ -0,0 +1,63 @@
+<script>
+import { GlEmptyState, GlPagination } from '@gitlab/ui';
+import { mergeUrlParams } from '~/lib/utils/url_utility';
+import FilteredSearchBar from './abuse_reports_filtered_search_bar.vue';
+import AbuseReportRow from './abuse_report_row.vue';
+
+export default {
+ name: 'AbuseReportsApp',
+ components: {
+ AbuseReportRow,
+ FilteredSearchBar,
+ GlEmptyState,
+ GlPagination,
+ },
+ props: {
+ abuseReports: {
+ type: Array,
+ required: true,
+ },
+ pagination: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ showPagination() {
+ return this.pagination.totalItems > this.pagination.perPage;
+ },
+ },
+ methods: {
+ paginationLinkGenerator(page) {
+ return mergeUrlParams({ page }, window.location.href);
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <filtered-search-bar />
+
+ <gl-empty-state v-if="abuseReports.length == 0" :title="s__('AbuseReports|No reports found')" />
+ <abuse-report-row
+ v-for="(report, index) in abuseReports"
+ v-else
+ :key="index"
+ :report="report"
+ />
+
+ <gl-pagination
+ v-if="showPagination"
+ :value="pagination.currentPage"
+ :per-page="pagination.perPage"
+ :total-items="pagination.totalItems"
+ :link-gen="paginationLinkGenerator"
+ :prev-text="__('Prev')"
+ :next-text="__('Next')"
+ :label-next-page="__('Go to next page')"
+ :label-prev-page="__('Go to previous page')"
+ align="center"
+ class="gl-mt-3"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/admin/abuse_reports/constants.js b/app/assets/javascripts/admin/abuse_reports/constants.js
new file mode 100644
index 00000000000..ee2e9ab2cbf
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/constants.js
@@ -0,0 +1,81 @@
+import { getUsers } from '~/rest_api';
+import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
+import UserToken from '~/vue_shared/components/filtered_search_bar/tokens/user_token.vue';
+import {
+ OPERATORS_IS,
+ TOKEN_TITLE_STATUS,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import { __ } from '~/locale';
+
+const STATUS_OPTIONS = [
+ { value: 'closed', title: __('Closed') },
+ { value: 'open', title: __('Open') },
+];
+
+export const FILTERED_SEARCH_TOKEN_USER = {
+ type: 'user',
+ icon: 'user',
+ title: __('User'),
+ token: UserToken,
+ unique: true,
+ operators: OPERATORS_IS,
+ fetchUsers: getUsers,
+ defaultUsers: [],
+};
+
+export const FILTERED_SEARCH_TOKEN_REPORTER = {
+ ...FILTERED_SEARCH_TOKEN_USER,
+ type: 'reporter',
+ title: __('Reporter'),
+};
+
+export const FILTERED_SEARCH_TOKEN_STATUS = {
+ type: 'status',
+ icon: 'status',
+ title: TOKEN_TITLE_STATUS,
+ token: BaseToken,
+ unique: true,
+ options: STATUS_OPTIONS,
+ operators: OPERATORS_IS,
+};
+
+export const DEFAULT_SORT = 'created_at_desc';
+
+export const SORT_OPTIONS = [
+ {
+ id: 10,
+ title: __('Created date'),
+ sortDirection: {
+ descending: DEFAULT_SORT,
+ ascending: 'created_at_asc',
+ },
+ },
+ {
+ id: 20,
+ title: __('Updated date'),
+ sortDirection: {
+ descending: 'updated_at_desc',
+ ascending: 'updated_at_asc',
+ },
+ },
+];
+
+export const isValidSortKey = (key) =>
+ SORT_OPTIONS.some(
+ (sort) => sort.sortDirection.ascending === key || sort.sortDirection.descending === key,
+ );
+
+export const FILTERED_SEARCH_TOKEN_CATEGORY = {
+ type: 'category',
+ icon: 'label',
+ title: __('Category'),
+ token: BaseToken,
+ unique: true,
+ operators: OPERATORS_IS,
+};
+
+export const FILTERED_SEARCH_TOKENS = [
+ FILTERED_SEARCH_TOKEN_USER,
+ FILTERED_SEARCH_TOKEN_REPORTER,
+ FILTERED_SEARCH_TOKEN_STATUS,
+];
diff --git a/app/assets/javascripts/admin/abuse_reports/index.js b/app/assets/javascripts/admin/abuse_reports/index.js
new file mode 100644
index 00000000000..dbc466af2d2
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/index.js
@@ -0,0 +1,31 @@
+import Vue from 'vue';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import AbuseReportsApp from './components/app.vue';
+
+export const initAbuseReportsApp = () => {
+ const el = document.querySelector('#js-abuse-reports-list-app');
+
+ if (!el) {
+ return null;
+ }
+
+ const { abuseReportsData } = el.dataset;
+ const { categories, reports, pagination } = convertObjectPropsToCamelCase(
+ JSON.parse(abuseReportsData),
+ {
+ deep: true,
+ },
+ );
+
+ return new Vue({
+ el,
+ provide: { categories },
+ render: (createElement) =>
+ createElement(AbuseReportsApp, {
+ props: {
+ abuseReports: reports,
+ pagination,
+ },
+ }),
+ });
+};
diff --git a/app/assets/javascripts/admin/abuse_reports/utils.js b/app/assets/javascripts/admin/abuse_reports/utils.js
new file mode 100644
index 00000000000..84221901089
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/utils.js
@@ -0,0 +1,6 @@
+import { FILTERED_SEARCH_TOKEN_CATEGORY } from './constants';
+
+export const buildFilteredSearchCategoryToken = (categories) => {
+ const options = categories.map((c) => ({ value: c, title: c }));
+ return { ...FILTERED_SEARCH_TOKEN_CATEGORY, options };
+};
diff --git a/app/assets/javascripts/admin/application_settings/network_outbound.js b/app/assets/javascripts/admin/application_settings/network_outbound.js
new file mode 100644
index 00000000000..ad7ed85131c
--- /dev/null
+++ b/app/assets/javascripts/admin/application_settings/network_outbound.js
@@ -0,0 +1,28 @@
+export default () => {
+ const denyAllRequests = document.querySelector('.js-deny-all-requests');
+
+ if (!denyAllRequests) {
+ return;
+ }
+
+ denyAllRequests.addEventListener('change', () => {
+ const denyAll = denyAllRequests.checked;
+ const allowLocalRequests = document.querySelectorAll('.js-allow-local-requests');
+ const denyAllRequestsWarning = document.querySelector('.js-deny-all-requests-warning');
+
+ if (denyAll) {
+ denyAllRequestsWarning.classList.remove('gl-display-none');
+ } else {
+ denyAllRequestsWarning.classList.add('gl-display-none');
+ }
+
+ allowLocalRequests.forEach((allowLocalRequest) => {
+ /* eslint-disable no-param-reassign */
+ if (denyAll) {
+ allowLocalRequest.checked = false;
+ }
+ allowLocalRequest.disabled = denyAll;
+ /* eslint-enable no-param-reassign */
+ });
+ });
+};
diff --git a/app/assets/javascripts/admin/broadcast_messages/components/base.vue b/app/assets/javascripts/admin/broadcast_messages/components/base.vue
index f869d21d55f..c28cd266617 100644
--- a/app/assets/javascripts/admin/broadcast_messages/components/base.vue
+++ b/app/assets/javascripts/admin/broadcast_messages/components/base.vue
@@ -2,7 +2,7 @@
import { GlPagination } from '@gitlab/ui';
import { redirectTo } from '~/lib/utils/url_utility';
import { buildUrlWithCurrentLocation } from '~/lib/utils/common_utils';
-import { createAlert, VARIANT_DANGER } from '~/flash';
+import { createAlert, VARIANT_DANGER } from '~/alert';
import { s__ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import { NEW_BROADCAST_MESSAGE } from '../constants';
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 36796708e78..65aa4cba074 100644
--- a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue
+++ b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue
@@ -12,16 +12,25 @@ import {
} from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
-import { createAlert, VARIANT_DANGER } from '~/flash';
+import { createAlert, VARIANT_DANGER } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { BROADCAST_MESSAGES_PATH, THEMES, TYPES, TYPE_BANNER } from '../constants';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import {
+ BROADCAST_MESSAGES_PATH,
+ MESSAGES_PREVIEW_PATH,
+ THEMES,
+ TYPES,
+ TYPE_BANNER,
+} from '../constants';
import MessageFormGroup from './message_form_group.vue';
import DatetimePicker from './datetime_picker.vue';
const FORM_HEADERS = { headers: { 'Content-Type': 'application/json; charset=utf-8' } };
export default {
+ DEFAULT_DEBOUNCE_AND_THROTTLE_MS,
name: 'MessageForm',
components: {
DatetimePicker,
@@ -36,6 +45,9 @@ export default {
GlFormTextarea,
MessageFormGroup,
},
+ directives: {
+ SafeHtml,
+ },
mixins: [glFeatureFlagsMixin()],
inject: ['targetAccessLevelOptions'],
i18n: {
@@ -81,6 +93,7 @@ export default {
})),
startsAt: new Date(this.broadcastMessage.startsAt.getTime()),
endsAt: new Date(this.broadcastMessage.endsAt.getTime()),
+ renderedMessage: '',
};
},
computed: {
@@ -91,7 +104,7 @@ export default {
return this.message.trim() === '';
},
messagePreview() {
- return this.messageBlank ? this.$options.i18n.messagePlaceholder : this.message;
+ return this.messageBlank ? this.$options.i18n.messagePlaceholder : this.renderedMessage;
},
isAddForm() {
return !this.broadcastMessage.id;
@@ -114,6 +127,11 @@ export default {
});
},
},
+ watch: {
+ message() {
+ this.renderPreview();
+ },
+ },
methods: {
async onSubmit() {
this.loading = true;
@@ -140,13 +158,25 @@ export default {
}
return true;
},
+
+ async renderPreview() {
+ try {
+ const res = await axios.post(MESSAGES_PREVIEW_PATH, this.formPayload, FORM_HEADERS);
+ this.renderedMessage = res.data;
+ } catch (e) {
+ this.renderedMessage = '';
+ }
+ },
+ },
+ safeHtmlConfig: {
+ ADD_TAGS: ['use'],
},
};
</script>
<template>
<gl-form @submit.prevent="onSubmit">
<gl-broadcast-message class="gl-my-6" :type="type" :theme="theme" :dismissible="dismissable">
- {{ messagePreview }}
+ <div v-safe-html:[$options.safeHtmlConfig]="messagePreview"></div>
</gl-broadcast-message>
<message-form-group :label="$options.i18n.message" label-for="message-textarea">
@@ -154,6 +184,7 @@ export default {
id="message-textarea"
v-model="message"
size="sm"
+ :debounce="$options.DEFAULT_DEBOUNCE_AND_THROTTLE_MS"
:placeholder="$options.i18n.messagePlaceholder"
/>
</message-form-group>
diff --git a/app/assets/javascripts/admin/broadcast_messages/constants.js b/app/assets/javascripts/admin/broadcast_messages/constants.js
index 6250d5a943d..323ac6857f6 100644
--- a/app/assets/javascripts/admin/broadcast_messages/constants.js
+++ b/app/assets/javascripts/admin/broadcast_messages/constants.js
@@ -1,6 +1,7 @@
import { s__ } from '~/locale';
export const BROADCAST_MESSAGES_PATH = '/admin/broadcast_messages';
+export const MESSAGES_PREVIEW_PATH = '/admin/broadcast_messages/preview';
export const TYPE_BANNER = 'banner';
export const TYPE_NOTIFICATION = 'notification';
diff --git a/app/assets/javascripts/admin/deploy_keys/components/table.vue b/app/assets/javascripts/admin/deploy_keys/components/table.vue
index be85ee43891..134498af348 100644
--- a/app/assets/javascripts/admin/deploy_keys/components/table.vue
+++ b/app/assets/javascripts/admin/deploy_keys/components/table.vue
@@ -5,7 +5,7 @@ import { __ } from '~/locale';
import Api, { DEFAULT_PER_PAGE } from '~/api';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import csrf from '~/lib/utils/csrf';
export default {
diff --git a/app/assets/javascripts/admin/statistics_panel/store/actions.js b/app/assets/javascripts/admin/statistics_panel/store/actions.js
index 4f952698d7a..7372f03ec0b 100644
--- a/app/assets/javascripts/admin/statistics_panel/store/actions.js
+++ b/app/assets/javascripts/admin/statistics_panel/store/actions.js
@@ -1,5 +1,5 @@
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { s__ } from '~/locale';
import * as types from './mutation_types';
diff --git a/app/assets/javascripts/admin/users/components/actions/activate.vue b/app/assets/javascripts/admin/users/components/actions/activate.vue
index 3a54035c587..0099c8da8e6 100644
--- a/app/assets/javascripts/admin/users/components/actions/activate.vue
+++ b/app/assets/javascripts/admin/users/components/actions/activate.vue
@@ -41,7 +41,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.activate,
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
messageHtml,
},
diff --git a/app/assets/javascripts/admin/users/components/actions/approve.vue b/app/assets/javascripts/admin/users/components/actions/approve.vue
index 5a8c675822d..52560ebe5b1 100644
--- a/app/assets/javascripts/admin/users/components/actions/approve.vue
+++ b/app/assets/javascripts/admin/users/components/actions/approve.vue
@@ -43,7 +43,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.approve,
- attributes: [{ variant: 'confirm', 'data-qa-selector': 'approve_user_confirm_button' }],
+ attributes: { variant: 'confirm', 'data-qa-selector': 'approve_user_confirm_button' },
},
messageHtml,
},
diff --git a/app/assets/javascripts/admin/users/components/actions/ban.vue b/app/assets/javascripts/admin/users/components/actions/ban.vue
index 898a688c203..203d076914f 100644
--- a/app/assets/javascripts/admin/users/components/actions/ban.vue
+++ b/app/assets/javascripts/admin/users/components/actions/ban.vue
@@ -56,7 +56,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.ban,
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
messageHtml,
},
diff --git a/app/assets/javascripts/admin/users/components/actions/block.vue b/app/assets/javascripts/admin/users/components/actions/block.vue
index d25dd400f9b..d50b76aaa92 100644
--- a/app/assets/javascripts/admin/users/components/actions/block.vue
+++ b/app/assets/javascripts/admin/users/components/actions/block.vue
@@ -42,7 +42,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.block,
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
messageHtml,
},
diff --git a/app/assets/javascripts/admin/users/components/actions/deactivate.vue b/app/assets/javascripts/admin/users/components/actions/deactivate.vue
index c85f3f01675..ab1069601d2 100644
--- a/app/assets/javascripts/admin/users/components/actions/deactivate.vue
+++ b/app/assets/javascripts/admin/users/components/actions/deactivate.vue
@@ -51,7 +51,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.deactivate,
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
messageHtml,
},
diff --git a/app/assets/javascripts/admin/users/components/actions/reject.vue b/app/assets/javascripts/admin/users/components/actions/reject.vue
index bac08de1d5e..2b9c4acfcb5 100644
--- a/app/assets/javascripts/admin/users/components/actions/reject.vue
+++ b/app/assets/javascripts/admin/users/components/actions/reject.vue
@@ -54,7 +54,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.reject,
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
},
messageHtml,
},
diff --git a/app/assets/javascripts/admin/users/components/actions/unban.vue b/app/assets/javascripts/admin/users/components/actions/unban.vue
index beede2d37d7..42b6fb3bdd4 100644
--- a/app/assets/javascripts/admin/users/components/actions/unban.vue
+++ b/app/assets/javascripts/admin/users/components/actions/unban.vue
@@ -37,7 +37,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.unban,
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
messageHtml,
},
diff --git a/app/assets/javascripts/admin/users/components/actions/unblock.vue b/app/assets/javascripts/admin/users/components/actions/unblock.vue
index 720f2efd932..f94e128a945 100644
--- a/app/assets/javascripts/admin/users/components/actions/unblock.vue
+++ b/app/assets/javascripts/admin/users/components/actions/unblock.vue
@@ -32,7 +32,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.unblock,
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
},
});
diff --git a/app/assets/javascripts/admin/users/components/actions/unlock.vue b/app/assets/javascripts/admin/users/components/actions/unlock.vue
index 55ea3e0aba7..c78c260b4fe 100644
--- a/app/assets/javascripts/admin/users/components/actions/unlock.vue
+++ b/app/assets/javascripts/admin/users/components/actions/unlock.vue
@@ -31,7 +31,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.unlock,
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
},
});
diff --git a/app/assets/javascripts/admin/users/components/users_table.vue b/app/assets/javascripts/admin/users/components/users_table.vue
index f569cda0a4b..e55622d40ba 100644
--- a/app/assets/javascripts/admin/users/components/users_table.vue
+++ b/app/assets/javascripts/admin/users/components/users_table.vue
@@ -1,6 +1,6 @@
<script>
import { GlSkeletonLoader, GlTable } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { convertNodeIdsFromGraphQLIds } from '~/graphql_shared/utils';
import { thWidthPercent } from '~/lib/utils/table_utility';
import { s__, __ } from '~/locale';
diff --git a/app/assets/javascripts/airflow/dags/components/dags.vue b/app/assets/javascripts/airflow/dags/components/dags.vue
deleted file mode 100644
index 88eb3fd5aba..00000000000
--- a/app/assets/javascripts/airflow/dags/components/dags.vue
+++ /dev/null
@@ -1,111 +0,0 @@
-<script>
-import { GlTableLite, GlEmptyState, GlPagination, GlTooltipDirective } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { setUrlParams } from '~/lib/utils/url_utility';
-import { formatDate } from '~/lib/utils/datetime/date_format_utility';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
-
-export default {
- name: 'AirflowDags',
- components: {
- GlTableLite,
- GlEmptyState,
- IncubationAlert,
- GlPagination,
- TimeAgo,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- dags: {
- type: Array,
- required: true,
- },
- pagination: {
- type: Object,
- required: true,
- },
- },
- computed: {
- fields() {
- return [
- { key: 'dag_name', label: this.$options.i18n.dagLabel },
- { key: 'schedule', label: this.$options.scheduleLabel },
- { key: 'next_run', label: this.$options.nextRunLabel },
- { key: 'is_active', label: this.$options.isActiveLabel },
- { key: 'is_paused', label: this.$options.isPausedLabel },
- { key: 'fileloc', label: this.$options.fileLocLabel },
- ];
- },
- hasPagination() {
- return this.dags.length > 0;
- },
- prevPage() {
- return this.pagination.page > 1 ? this.pagination.page - 1 : null;
- },
- nextPage() {
- return !this.pagination.isLastPage ? this.pagination.page + 1 : null;
- },
- emptyState() {
- return {
- svgPath: '/assets/illustrations/empty-state/empty-dag-md.svg',
- };
- },
- },
- methods: {
- generateLink(page) {
- return setUrlParams({ page });
- },
- formatDate(dateString) {
- return formatDate(new Date(dateString));
- },
- },
- i18n: {
- emptyStateLabel: s__('Airflow|There are no DAGs to show'),
- emptyStateDescription: s__(
- 'Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured',
- ),
- dagLabel: s__('Airflow|DAG'),
- scheduleLabel: s__('Airflow|Schedule'),
- nextRunLabel: s__('Airflow|Next run'),
- isActiveLabel: s__('Airflow|Is active'),
- isPausedLabel: s__('Airflow|Is paused'),
- fileLocLabel: s__('Airflow|DAG file location'),
- featureName: s__('Airflow|GitLab Airflow integration'),
- },
- linkToFeedbackIssue:
- 'https://gitlab.com/gitlab-org/incubation-engineering/airflow/meta/-/issues/2',
-};
-</script>
-
-<template>
- <div>
- <incubation-alert
- :feature-name="$options.i18n.featureName"
- :link-to-feedback-issue="$options.linkToFeedbackIssue"
- />
- <gl-empty-state
- v-if="!dags.length"
- :title="$options.i18n.emptyStateLabel"
- :description="$options.i18n.emptyStateDescription"
- :svg-path="emptyState.svgPath"
- />
- <gl-table-lite v-else :items="dags" :fields="fields" class="gl-mt-0!">
- <template #cell(next_run)="data">
- <time-ago v-gl-tooltip.hover :time="data.value" :title="formatDate(data.value)" />
- </template>
- </gl-table-lite>
- <gl-pagination
- v-if="hasPagination"
- :value="pagination.page"
- :prev-page="prevPage"
- :next-page="nextPage"
- :total-items="pagination.totalItems"
- :per-page="pagination.perPage"
- :link-gen="generateLink"
- align="center"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/alert.js b/app/assets/javascripts/alert.js
new file mode 100644
index 00000000000..006c4f50d09
--- /dev/null
+++ b/app/assets/javascripts/alert.js
@@ -0,0 +1,137 @@
+import * as Sentry from '@sentry/browser';
+import Vue from 'vue';
+import { GlAlert } from '@gitlab/ui';
+import { __ } from '~/locale';
+
+export const VARIANT_SUCCESS = 'success';
+export const VARIANT_WARNING = 'warning';
+export const VARIANT_DANGER = 'danger';
+export const VARIANT_INFO = 'info';
+export const VARIANT_TIP = 'tip';
+
+/**
+ * Render an alert at the top of the page, or, optionally an
+ * arbitrary existing container. This alert is always dismissible.
+ *
+ * @example
+ * // Render a new alert
+ * import { createAlert, VARIANT_WARNING } from '~/alert';
+ *
+ * createAlert({ message: 'My error message' });
+ * createAlert({ message: 'My warning message', variant: VARIANT_WARNING });
+ *
+ * @example
+ * // Dismiss this alert programmatically
+ * const alert = createAlert({ message: 'Message' });
+ *
+ * // ...
+ *
+ * alert.dismiss();
+ *
+ * @example
+ * // Respond to the alert being dismissed
+ * createAlert({ message: 'Message', onDismiss: () => {} });
+ *
+ * @param {object} options - Options to control the flash message
+ * @param {string} options.message - Alert message text
+ * @param {string} [options.title] - Alert title
+ * @param {VARIANT_SUCCESS|VARIANT_WARNING|VARIANT_DANGER|VARIANT_INFO|VARIANT_TIP} [options.variant] - Which GlAlert variant to use; it defaults to VARIANT_DANGER.
+ * @param {object} [options.parent] - Reference to parent element under which alert needs to appear. Defaults to `document`.
+ * @param {Function} [options.onDismiss] - Handler to call when this alert is dismissed.
+ * @param {string} [options.containerSelector] - Selector for the container of the alert
+ * @param {boolean} [options.preservePrevious] - Set to `true` to preserve previous alerts. Defaults to `false`.
+ * @param {object} [options.primaryButton] - Object describing primary button of alert
+ * @param {string} [options.primaryButton.link] - Href of primary button
+ * @param {string} [options.primaryButton.text] - Text of primary button
+ * @param {Function} [options.primaryButton.clickHandler] - Handler to call when primary button is clicked on. The click event is sent as an argument.
+ * @param {object} [options.secondaryButton] - Object describing secondary button of alert
+ * @param {string} [options.secondaryButton.link] - Href of secondary button
+ * @param {string} [options.secondaryButton.text] - Text of secondary button
+ * @param {Function} [options.secondaryButton.clickHandler] - Handler to call when secondary button is clicked on. The click event is sent as an argument.
+ * @param {boolean} [options.captureError] - Whether to send error to Sentry
+ * @param {object} [options.error] - Error to be captured in Sentry
+ */
+export const createAlert = ({
+ message,
+ title,
+ variant = VARIANT_DANGER,
+ parent = document,
+ containerSelector = '.flash-container',
+ preservePrevious = false,
+ primaryButton = null,
+ secondaryButton = null,
+ onDismiss = null,
+ captureError = false,
+ error = null,
+}) => {
+ if (captureError && error) Sentry.captureException(error);
+
+ const alertContainer = parent.querySelector(containerSelector);
+ if (!alertContainer) return null;
+
+ const el = document.createElement('div');
+ if (preservePrevious) {
+ alertContainer.appendChild(el);
+ } else {
+ alertContainer.replaceChildren(el);
+ }
+
+ return new Vue({
+ el,
+ components: {
+ GlAlert,
+ },
+ methods: {
+ /**
+ * Public method to dismiss this alert and removes
+ * this Vue instance.
+ */
+ dismiss() {
+ if (onDismiss) {
+ onDismiss();
+ }
+ this.$destroy();
+ this.$el.parentNode?.removeChild(this.$el);
+ },
+ },
+ render(h) {
+ const on = {};
+
+ on.dismiss = () => {
+ this.dismiss();
+ };
+
+ if (primaryButton?.clickHandler) {
+ on.primaryAction = (e) => {
+ primaryButton.clickHandler(e);
+ };
+ }
+ if (secondaryButton?.clickHandler) {
+ on.secondaryAction = (e) => {
+ secondaryButton.clickHandler(e);
+ };
+ }
+
+ return h(
+ GlAlert,
+ {
+ props: {
+ title,
+ dismissible: true,
+ dismissLabel: __('Dismiss'),
+ variant,
+ primaryButtonLink: primaryButton?.link,
+ primaryButtonText: primaryButton?.text,
+ secondaryButtonLink: secondaryButton?.link,
+ secondaryButtonText: secondaryButton?.text,
+ },
+ attrs: {
+ 'data-testid': `alert-${variant}`,
+ },
+ on,
+ },
+ message,
+ );
+ },
+ });
+};
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_form.vue b/app/assets/javascripts/alerts_settings/components/alerts_form.vue
index 38bcdef3e04..b9e37b9ede7 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_form.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_form.vue
@@ -5,8 +5,7 @@ import {
GlLink,
GlFormGroup,
GlFormCheckbox,
- GlDropdown,
- GlDropdownItem,
+ GlCollapsibleListbox,
} from '@gitlab/ui';
import {
I18N_ALERT_SETTINGS_FORM,
@@ -22,8 +21,7 @@ export default {
GlLink,
GlFormGroup,
GlFormCheckbox,
- GlDropdown,
- GlDropdownItem,
+ GlCollapsibleListbox,
},
inject: ['service', 'alertSettings'],
data() {
@@ -40,9 +38,6 @@ export default {
TAKING_INCIDENT_ACTION_DOCS_LINK,
ISSUE_TEMPLATES_DOCS_LINK,
computed: {
- issueTemplateHeader() {
- return this.issueTemplate || NO_ISSUE_TEMPLATE_SELECTED.name;
- },
formData() {
return {
create_issue: this.createIssueEnabled,
@@ -53,12 +48,6 @@ export default {
},
},
methods: {
- selectIssueTemplate(templateKey) {
- this.issueTemplate = templateKey;
- },
- isTemplateSelected(templateKey) {
- return templateKey === this.issueTemplate;
- },
updateAlertsIntegrationSettings() {
this.loading = true;
@@ -99,23 +88,13 @@ export default {
<span class="gl-font-weight-normal gl-pl-2">{{ $options.i18n.introLinkText }}</span>
</gl-link>
</label>
- <gl-dropdown
+ <gl-collapsible-listbox
id="alert-integration-settings-issue-template"
+ v-model="issueTemplate"
+ :items="templates"
+ block
data-qa-selector="incident_templates_dropdown"
- :text="issueTemplateHeader"
- :block="true"
- >
- <gl-dropdown-item
- v-for="template in templates"
- :key="template.key"
- data-qa-selector="incident_templates_item"
- is-check-item
- :is-checked="isTemplateSelected(template.key)"
- @click="selectIssueTemplate(template.key)"
- >
- {{ template.name }}
- </gl-dropdown-item>
- </gl-dropdown>
+ />
</gl-form-group>
<gl-form-group class="gl-pl-0 gl-mb-5">
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 7dd33da435a..cc8913c2f45 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue
@@ -2,7 +2,7 @@
import { GlButton, GlAlert, GlTabs, GlTab } from '@gitlab/ui';
import createHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql';
import updateHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { fetchPolicies } from '~/lib/graphql';
import { HTTP_STATUS_FORBIDDEN } from '~/lib/utils/http_status';
import { typeSet, i18n, tabIndices } from '../constants';
diff --git a/app/assets/javascripts/alerts_settings/constants.js b/app/assets/javascripts/alerts_settings/constants.js
index b93119d6e6a..de7240009bc 100644
--- a/app/assets/javascripts/alerts_settings/constants.js
+++ b/app/assets/javascripts/alerts_settings/constants.js
@@ -183,7 +183,7 @@ export const I18N_ALERT_SETTINGS_FORM = {
},
};
-export const NO_ISSUE_TEMPLATE_SELECTED = { key: '', name: __('No template selected') };
+export const NO_ISSUE_TEMPLATE_SELECTED = { value: '', text: __('No template selected') };
export const TAKING_INCIDENT_ACTION_DOCS_LINK =
'/help/operations/metrics/alerts#trigger-actions-from-alerts';
export const ISSUE_TEMPLATES_DOCS_LINK =
diff --git a/app/assets/javascripts/alerts_settings/utils/cache_updates.js b/app/assets/javascripts/alerts_settings/utils/cache_updates.js
index 2e64312b0e0..e03ebffd17a 100644
--- a/app/assets/javascripts/alerts_settings/utils/cache_updates.js
+++ b/app/assets/javascripts/alerts_settings/utils/cache_updates.js
@@ -1,5 +1,5 @@
import produce from 'immer';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { DELETE_INTEGRATION_ERROR, ADD_INTEGRATION_ERROR } from './error_messages';
diff --git a/app/assets/javascripts/analytics/cycle_analytics/components/base.vue b/app/assets/javascripts/analytics/cycle_analytics/components/base.vue
index a688e2f497b..704b4ce9c8a 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/components/base.vue
+++ b/app/assets/javascripts/analytics/cycle_analytics/components/base.vue
@@ -4,7 +4,7 @@ import { mapActions, mapState, mapGetters } from 'vuex';
import { getCookie, setCookie } from '~/lib/utils/common_utils';
import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue';
import { VSA_METRICS_GROUPS } from '~/analytics/shared/constants';
-import { toYmd } from '~/analytics/shared/utils';
+import { toYmd, generateValueStreamsDashboardLink } from '~/analytics/shared/utils';
import PathNavigation from '~/analytics/cycle_analytics/components/path_navigation.vue';
import StageTable from '~/analytics/cycle_analytics/components/stage_table.vue';
import ValueStreamFilters from '~/analytics/cycle_analytics/components/value_stream_filters.vue';
@@ -48,12 +48,13 @@ export default {
'selectedStageEvents',
'selectedStageError',
'stageCounts',
- 'endpoints',
'features',
'createdBefore',
'createdAfter',
'pagination',
'hasNoAccessError',
+ 'groupPath',
+ 'namespace',
]),
...mapGetters(['pathNavigationData', 'filterParams']),
isLoaded() {
@@ -98,8 +99,25 @@ export default {
}
return 0;
},
+ hasCycleAnalyticsForGroups() {
+ return this.features?.cycleAnalyticsForGroups;
+ },
metricsRequests() {
- return this.features?.cycleAnalyticsForGroups ? METRICS_REQUESTS : SUMMARY_METRICS_REQUEST;
+ return this.hasCycleAnalyticsForGroups ? METRICS_REQUESTS : SUMMARY_METRICS_REQUEST;
+ },
+ showLinkToDashboard() {
+ return Boolean(
+ this.features?.groupLevelAnalyticsDashboard && this.features?.groupAnalyticsDashboardsPage,
+ );
+ },
+ dashboardsPath() {
+ const {
+ namespace: { fullPath },
+ groupPath,
+ } = this;
+ return this.showLinkToDashboard
+ ? generateValueStreamsDashboardLink(groupPath, [fullPath])
+ : null;
},
query() {
return {
@@ -150,8 +168,7 @@ export default {
<div>
<h3>{{ $options.i18n.pageTitle }}</h3>
<value-stream-filters
- :group-id="endpoints.groupId"
- :group-path="endpoints.groupPath"
+ :group-path="groupPath"
:has-project-filter="false"
:start-date="createdAfter"
:end-date="createdBefore"
@@ -169,10 +186,11 @@ export default {
/>
</div>
<value-stream-metrics
- :request-path="endpoints.fullPath"
+ :request-path="namespace.fullPath"
:request-params="filterParams"
:requests="metricsRequests"
:group-by="$options.VSA_METRICS_GROUPS"
+ :dashboards-path="dashboardsPath"
/>
<gl-loading-icon v-if="isLoading" size="lg" />
<stage-table
diff --git a/app/assets/javascripts/analytics/cycle_analytics/components/path_navigation.vue b/app/assets/javascripts/analytics/cycle_analytics/components/path_navigation.vue
index ac41bc4917c..d305132ae33 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/components/path_navigation.vue
+++ b/app/assets/javascripts/analytics/cycle_analytics/components/path_navigation.vue
@@ -66,33 +66,38 @@ export default {
<template #title>{{ pathItem.title }}</template>
<div class="gl-px-4">
<div class="gl-display-flex gl-justify-content-space-between">
- <div class="gl-pr-4 gl-pb-4">
+ <div class="gl-pr-4 gl-pb-3">
{{ s__('ValueStreamEvent|Stage time (median)') }}
</div>
- <div class="gl-pb-4 gl-font-weight-bold">{{ pathItem.metric }}</div>
+ <div class="gl-pb-3 gl-font-weight-bold">{{ pathItem.metric }}</div>
</div>
</div>
<div class="gl-px-4">
<div class="gl-display-flex gl-justify-content-space-between">
- <div class="gl-pr-4 gl-pb-4">
+ <div class="gl-pr-4 gl-pb-3">
{{ s__('ValueStreamEvent|Items in stage') }}
</div>
- <div class="gl-pb-4 gl-font-weight-bold">
+ <div class="gl-pb-3 gl-font-weight-bold">
<formatted-stage-count :stage-count="pathItem.stageCount" />
</div>
</div>
</div>
+ <div class="gl-px-4">
+ <div class="gl-pb-3 gl-font-style-italic">
+ {{ s__('ValueStreamEvent|Only items that reached their stop event.') }}
+ </div>
+ </div>
<div class="gl-px-4 gl-pt-4 gl-border-t-1 gl-border-t-solid gl-border-gray-50">
<div
v-if="pathItem.startEventHtmlDescription"
class="gl-display-flex gl-flex-direction-row"
>
- <div class="gl-display-flex gl-flex-direction-column gl-pr-4 gl-pb-4 metric-label">
+ <div class="gl-display-flex gl-flex-direction-column gl-pr-4 gl-pb-3 metric-label">
{{ s__('ValueStreamEvent|Start') }}
</div>
<div
v-safe-html="pathItem.startEventHtmlDescription"
- class="gl-display-flex gl-flex-direction-column gl-pb-4 stage-event-description"
+ class="gl-display-flex gl-flex-direction-column gl-pb-3 stage-event-description"
></div>
</div>
<div
diff --git a/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue b/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue
index 17decb6b448..4c7e18f9895 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue
+++ b/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue
@@ -31,10 +31,6 @@ export default {
required: false,
default: true,
},
- groupId: {
- type: Number,
- required: true,
- },
groupPath: {
type: String,
required: true,
@@ -82,9 +78,7 @@ export default {
<div>
<projects-dropdown-filter
v-if="hasProjectFilter"
- :key="groupId"
class="js-projects-dropdown-filter project-select gl-mb-2 gl-lg-mb-0"
- :group-id="groupId"
:group-namespace="groupPath"
:query-params="projectsQueryParams"
:multi-select="$options.multiProjectSelect"
diff --git a/app/assets/javascripts/analytics/cycle_analytics/constants.js b/app/assets/javascripts/analytics/cycle_analytics/constants.js
index 2758d686fb1..ebb2775b378 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/constants.js
+++ b/app/assets/javascripts/analytics/cycle_analytics/constants.js
@@ -32,11 +32,6 @@ export const I18N_VSA_ERROR_SELECTED_STAGE = __(
'There was an error fetching data for the selected stage',
);
-export const OVERVIEW_METRICS = {
- TIME_SUMMARY: 'TIME_SUMMARY',
- RECENT_ACTIVITY: 'RECENT_ACTIVITY',
-};
-
export const SUMMARY_METRICS_REQUEST = [
{ endpoint: METRIC_TYPE_SUMMARY, name: __('recent activity'), request: getValueStreamMetrics },
];
@@ -45,3 +40,6 @@ export const METRICS_REQUESTS = [
{ endpoint: METRIC_TYPE_TIME_SUMMARY, name: __('time summary'), request: getValueStreamMetrics },
...SUMMARY_METRICS_REQUEST,
];
+
+export const MILESTONES_ENDPOINT = '/-/milestones.json';
+export const LABELS_ENDPOINT = '/-/labels.json';
diff --git a/app/assets/javascripts/analytics/cycle_analytics/store/actions.js b/app/assets/javascripts/analytics/cycle_analytics/store/actions.js
index 4a201e00582..32fe0abe83e 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/store/actions.js
+++ b/app/assets/javascripts/analytics/cycle_analytics/store/actions.js
@@ -6,9 +6,15 @@ import {
getValueStreamStageCounts,
} from '~/api/analytics_api';
import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
-import { DEFAULT_VALUE_STREAM, I18N_VSA_ERROR_STAGE_MEDIAN } from '../constants';
+import {
+ DEFAULT_VALUE_STREAM,
+ I18N_VSA_ERROR_STAGE_MEDIAN,
+ LABELS_ENDPOINT,
+ MILESTONES_ENDPOINT,
+} from '../constants';
+import { constructPathWithNamespace } from '../utils';
import * as types from './mutation_types';
export const setSelectedValueStream = ({ commit, dispatch }, valueStream) => {
@@ -18,7 +24,7 @@ export const setSelectedValueStream = ({ commit, dispatch }, valueStream) => {
export const fetchValueStreamStages = ({ commit, state }) => {
const {
- endpoints: { fullPath },
+ namespace: { fullPath },
selectedValueStream: { id },
} = state;
commit(types.REQUEST_VALUE_STREAM_STAGES);
@@ -41,7 +47,7 @@ export const receiveValueStreamsSuccess = ({ commit, dispatch }, data = []) => {
export const fetchValueStreams = ({ commit, dispatch, state }) => {
const {
- endpoints: { fullPath },
+ namespace: { fullPath },
} = state;
commit(types.REQUEST_VALUE_STREAMS);
@@ -180,7 +186,8 @@ export const initializeVsa = async ({ commit, dispatch }, initialData = {}) => {
commit(types.INITIALIZE_VSA, initialData);
const {
- endpoints: { fullPath, groupPath, milestonesPath = '', labelsPath = '' },
+ groupPath,
+ namespace,
selectedAuthor,
selectedMilestone,
selectedAssigneeList,
@@ -189,10 +196,10 @@ export const initializeVsa = async ({ commit, dispatch }, initialData = {}) => {
} = initialData;
dispatch('filters/setEndpoints', {
- labelsEndpoint: labelsPath,
- milestonesEndpoint: milestonesPath,
+ labelsEndpoint: constructPathWithNamespace(namespace, LABELS_ENDPOINT),
+ milestonesEndpoint: constructPathWithNamespace(namespace, MILESTONES_ENDPOINT),
groupEndpoint: groupPath,
- projectEndpoint: fullPath,
+ projectEndpoint: namespace.fullPath,
});
dispatch('filters/initialize', {
diff --git a/app/assets/javascripts/analytics/cycle_analytics/store/getters.js b/app/assets/javascripts/analytics/cycle_analytics/store/getters.js
index 83068cabf0f..f5ed922c602 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/store/getters.js
+++ b/app/assets/javascripts/analytics/cycle_analytics/store/getters.js
@@ -15,11 +15,11 @@ export const pathNavigationData = ({ stages, medians, stageCounts, selectedStage
export const requestParams = (state) => {
const {
- endpoints: { fullPath },
+ namespace: { fullPath },
selectedValueStream: { id: valueStreamId },
selectedStage: { id: stageId = null },
} = state;
- return { requestPath: fullPath, valueStreamId, stageId };
+ return { namespacePath: fullPath, valueStreamId, stageId };
};
export const paginationParams = ({ pagination: { page, sort, direction } }) => ({
diff --git a/app/assets/javascripts/analytics/cycle_analytics/store/mutations.js b/app/assets/javascripts/analytics/cycle_analytics/store/mutations.js
index 8567529caf2..4af96fc96e3 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/store/mutations.js
+++ b/app/assets/javascripts/analytics/cycle_analytics/store/mutations.js
@@ -1,15 +1,16 @@
import Vue from 'vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import { PAGINATION_SORT_FIELD_END_EVENT, PAGINATION_SORT_DIRECTION_DESC } from '../constants';
import { formatMedianValues } from '../utils';
+import { PAGINATION_SORT_FIELD_END_EVENT, PAGINATION_SORT_DIRECTION_DESC } from '../constants';
import * as types from './mutation_types';
export default {
[types.INITIALIZE_VSA](
state,
- { endpoints, features, createdBefore, createdAfter, pagination = {} },
+ { groupPath, features, createdBefore, createdAfter, pagination = {}, namespace = {} },
) {
- state.endpoints = endpoints;
+ state.groupPath = groupPath;
+ state.namespace = namespace;
state.createdBefore = createdBefore;
state.createdAfter = createdAfter;
state.features = features;
diff --git a/app/assets/javascripts/analytics/cycle_analytics/store/state.js b/app/assets/javascripts/analytics/cycle_analytics/store/state.js
index 00dd2e53883..0c51656c59f 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/store/state.js
+++ b/app/assets/javascripts/analytics/cycle_analytics/store/state.js
@@ -6,7 +6,11 @@ import {
export default () => ({
id: null,
features: {},
- endpoints: {},
+ groupPath: {},
+ namespace: {
+ name: null,
+ fullPath: null,
+ },
createdAfter: null,
createdBefore: null,
stages: [],
diff --git a/app/assets/javascripts/analytics/cycle_analytics/utils.js b/app/assets/javascripts/analytics/cycle_analytics/utils.js
index 428bb11b950..9265ff952e0 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/utils.js
+++ b/app/assets/javascripts/analytics/cycle_analytics/utils.js
@@ -1,5 +1,6 @@
import { parseSeconds } from '~/lib/utils/datetime_utility';
import { formatTimeAsSummary } from '~/lib/utils/datetime/date_format_utility';
+import { joinPaths } from '~/lib/utils/url_utility';
/**
* Takes the stages and median data, combined with the selected stage, to build an
@@ -77,7 +78,11 @@ export const filterStagesByHiddenStatus = (stages = [], isHidden = true) =>
*/
const extractFeatures = (gon) => ({
+ // licensed feature toggles
cycleAnalyticsForGroups: Boolean(gon?.licensed_features?.cycleAnalyticsForGroups),
+ groupLevelAnalyticsDashboard: Boolean(gon?.licensed_features?.groupLevelAnalyticsDashboard),
+ // feature flags
+ groupAnalyticsDashboardsPage: Boolean(gon?.features?.groupAnalyticsDashboardsPage),
});
/**
@@ -87,27 +92,21 @@ const extractFeatures = (gon) => ({
* @returns {Object} - The initial data to load the app with
*/
export const buildCycleAnalyticsInitialData = ({
- fullPath,
- requestPath,
projectId,
- groupId,
groupPath,
- labelsPath,
- milestonesPath,
stage,
createdAfter,
createdBefore,
+ namespaceName,
+ namespaceFullPath,
gon,
} = {}) => {
return {
projectId: parseInt(projectId, 10),
- endpoints: {
- requestPath,
- fullPath,
- labelsPath,
- milestonesPath,
- groupId: parseInt(groupId, 10),
- groupPath,
+ groupPath: `groups/${groupPath}`,
+ namespace: {
+ name: namespaceName,
+ fullPath: namespaceFullPath,
},
createdAfter: new Date(createdAfter),
createdBefore: new Date(createdBefore),
@@ -115,3 +114,6 @@ export const buildCycleAnalyticsInitialData = ({
features: extractFeatures(gon),
};
};
+
+export const constructPathWithNamespace = ({ fullPath }, endpoint) =>
+ joinPaths('/', fullPath, endpoint);
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 5bb60d91f1e..98193de4a12 100644
--- a/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
+++ b/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
@@ -32,11 +32,6 @@ export default {
GlTruncate,
},
props: {
- groupId: {
- type: Number,
- required: false,
- default: null,
- },
groupNamespace: {
type: String,
required: true,
diff --git a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
index cc7b554f32c..3082897af76 100644
--- a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
+++ b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
@@ -1,9 +1,10 @@
<script>
import { GlSkeletonLoader } from '@gitlab/ui';
import { isEqual, keyBy } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { sprintf, s__ } from '~/locale';
import { fetchMetricsData, removeFlash } from '../utils';
+import ValueStreamsDashboardLink from './value_streams_dashboard_link.vue';
import MetricTile from './metric_tile.vue';
const extractMetricsGroupData = (keyList = [], data = []) => {
@@ -28,6 +29,7 @@ export default {
components: {
GlSkeletonLoader,
MetricTile,
+ ValueStreamsDashboardLink,
},
props: {
requestPath: {
@@ -52,6 +54,11 @@ export default {
required: false,
default: () => [],
},
+ dashboardsPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
data() {
return {
@@ -76,6 +83,10 @@ export default {
this.fetchData();
},
methods: {
+ shouldDisplayDashboardLink(index) {
+ // When we have groups of metrics, we should only display the link for the first group
+ return index === 0 && this.dashboardsPath;
+ },
fetchData() {
removeFlash();
this.isLoading = true;
@@ -110,7 +121,7 @@ export default {
<template v-else>
<div v-if="hasGroupedMetrics" class="gl-flex-direction-column">
<div
- v-for="group in groupedMetrics"
+ v-for="(group, groupIndex) in groupedMetrics"
:key="group.key"
class="gl-mb-7"
data-testid="vsa-metrics-group"
@@ -123,6 +134,11 @@ export default {
:metric="metric"
class="gl-mt-5 gl-pr-10"
/>
+ <value-streams-dashboard-link
+ v-if="shouldDisplayDashboardLink(groupIndex)"
+ class="gl-mt-5"
+ :request-path="dashboardsPath"
+ />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/analytics/shared/components/value_streams_dashboard_link.vue b/app/assets/javascripts/analytics/shared/components/value_streams_dashboard_link.vue
new file mode 100644
index 00000000000..95a6447ebaf
--- /dev/null
+++ b/app/assets/javascripts/analytics/shared/components/value_streams_dashboard_link.vue
@@ -0,0 +1,30 @@
+<script>
+import { GlIcon, GlLink } from '@gitlab/ui';
+import { __ } from '~/locale';
+
+export default {
+ name: 'ValueStreamsDashboardLink',
+ components: { GlIcon, GlLink },
+ props: {
+ requestPath: {
+ type: String,
+ required: true,
+ },
+ },
+ i18n: {
+ title: __('Related'),
+ linkText: __('Value Streams Dashboard | DORA'),
+ },
+};
+</script>
+<template>
+ <div class="gl-display-flex gl-flex-direction-column" data-testid="vsd-link">
+ <div class="gl-display-flex gl-mb-2">
+ <span>{{ $options.i18n.title }}</span>
+ </div>
+ <div class="gl-display-flex gl-align-items-baseline">
+ <gl-link :href="requestPath">{{ $options.i18n.linkText }}</gl-link
+ >&nbsp;<gl-icon name="dashboard" />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/analytics/shared/utils.js b/app/assets/javascripts/analytics/shared/utils.js
index aafbf642766..a85f3fb3730 100644
--- a/app/assets/javascripts/analytics/shared/utils.js
+++ b/app/assets/javascripts/analytics/shared/utils.js
@@ -1,6 +1,7 @@
import { flatten } from 'lodash';
import dateFormat from '~/lib/dateformat';
import { slugify } from '~/lib/utils/text_utility';
+import { joinPaths } from '~/lib/utils/url_utility';
import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { dateFormats, METRICS_POPOVER_CONTENT } from './constants';
@@ -119,3 +120,21 @@ export const fetchMetricsData = (requests = [], requestPath, params) => {
prepareTimeMetricsData(flatten(responses), METRICS_POPOVER_CONTENT),
);
};
+
+/**
+ * Generates a URL link to the VSD dashboard based on the group
+ * and project paths passed into the method.
+ *
+ * @param {String} groupPath - Path of the specified group
+ * @param {Array} projectPaths - Array of project paths to include in the `query` parameter
+ * @returns a URL or blank string if there is no groupPath set
+ */
+export const generateValueStreamsDashboardLink = (groupPath, projectPaths = []) => {
+ if (groupPath.length) {
+ const query = projectPaths.length ? `?query=${projectPaths.join(',')}` : '';
+ const dashboardsSlug = '/-/analytics/dashboards/value_streams_dashboard';
+ const segments = [gon.relative_url_root || '', '/', groupPath, dashboardsSlug];
+ return joinPaths(...segments).concat(query);
+ }
+ return '';
+};
diff --git a/app/assets/javascripts/analytics/usage_trends/components/usage_counts.vue b/app/assets/javascripts/analytics/usage_trends/components/usage_counts.vue
index 5651789e2c7..1fd1f91bda3 100644
--- a/app/assets/javascripts/analytics/usage_trends/components/usage_counts.vue
+++ b/app/assets/javascripts/analytics/usage_trends/components/usage_counts.vue
@@ -1,7 +1,7 @@
<script>
import { GlSkeletonLoader } from '@gitlab/ui';
import { GlSingleStat } from '@gitlab/ui/dist/charts';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { number } from '~/lib/utils/unit_format';
import { __, s__ } from '~/locale';
import usageTrendsCountQuery from '../graphql/queries/usage_trends_count.query.graphql';
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index b02dd9321b3..87c74438d00 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import axios from './lib/utils/axios_utils';
import { joinPaths } from './lib/utils/url_utility';
diff --git a/app/assets/javascripts/api/analytics_api.js b/app/assets/javascripts/api/analytics_api.js
index 66ed30130bb..35c9fa20e56 100644
--- a/app/assets/javascripts/api/analytics_api.js
+++ b/app/assets/javascripts/api/analytics_api.js
@@ -2,8 +2,8 @@ import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { buildApiUrl } from './api_utils';
-const PROJECT_VSA_METRICS_BASE = '/:request_path/-/analytics/value_stream_analytics';
-const PROJECT_VSA_PATH_BASE = '/:request_path/-/analytics/value_stream_analytics/value_streams';
+const PROJECT_VSA_METRICS_BASE = '/:namespace_path/-/analytics/value_stream_analytics';
+const PROJECT_VSA_PATH_BASE = '/:namespace_path/-/analytics/value_stream_analytics/value_streams';
const PROJECT_VSA_STAGES_PATH = `${PROJECT_VSA_PATH_BASE}/:value_stream_id/stages`;
const PROJECT_VSA_STAGE_DATA_PATH = `${PROJECT_VSA_STAGES_PATH}/:stage_id`;
@@ -15,71 +15,77 @@ export const DEPLOYS_METRIC_TYPE = 'deploys';
export const METRIC_TYPE_SUMMARY = 'summary';
export const METRIC_TYPE_TIME_SUMMARY = 'time_summary';
-const buildProjectMetricsPath = (requestPath) =>
- buildApiUrl(PROJECT_VSA_METRICS_BASE).replace(':request_path', requestPath);
+const buildProjectMetricsPath = (namespacePath) =>
+ buildApiUrl(PROJECT_VSA_METRICS_BASE).replace(':namespace_path', namespacePath);
-const buildProjectValueStreamPath = (requestPath, valueStreamId = null) => {
+const buildProjectValueStreamPath = (namespacePath, valueStreamId = null) => {
if (valueStreamId) {
return buildApiUrl(PROJECT_VSA_STAGES_PATH)
- .replace(':request_path', requestPath)
+ .replace(':namespace_path', namespacePath)
.replace(':value_stream_id', valueStreamId);
}
- return buildApiUrl(PROJECT_VSA_PATH_BASE).replace(':request_path', requestPath);
+ return buildApiUrl(PROJECT_VSA_PATH_BASE).replace(':namespace_path', namespacePath);
};
-const buildValueStreamStageDataPath = ({ requestPath, valueStreamId = null, stageId = null }) =>
+const buildValueStreamStageDataPath = ({ namespacePath, valueStreamId = null, stageId = null }) =>
buildApiUrl(PROJECT_VSA_STAGE_DATA_PATH)
- .replace(':request_path', requestPath)
+ .replace(':namespace_path', namespacePath)
.replace(':value_stream_id', valueStreamId)
.replace(':stage_id', stageId);
-export const getProjectValueStreams = (requestPath) => {
- const url = buildProjectValueStreamPath(requestPath);
+export const getProjectValueStreams = (namespacePath) => {
+ const url = buildProjectValueStreamPath(namespacePath);
return axios.get(url);
};
-export const getProjectValueStreamStages = (requestPath, valueStreamId) => {
- const url = buildProjectValueStreamPath(requestPath, valueStreamId);
+export const getProjectValueStreamStages = (namespacePath, valueStreamId) => {
+ const url = buildProjectValueStreamPath(namespacePath, valueStreamId);
return axios.get(url);
};
// NOTE: legacy VSA request use a different path
-// the `requestPath` provides a full url for the request
-export const getProjectValueStreamStageData = ({ requestPath, stageId, params }) =>
- axios.get(joinPaths(requestPath, 'events', stageId), { params });
+// the `namespacePath` provides a full url for the request
+export const getProjectValueStreamStageData = ({ namespacePath, stageId, params }) =>
+ axios.get(joinPaths(namespacePath, 'events', stageId), { params });
/**
* Dedicated project VSA paths
*/
-export const getValueStreamStageMedian = ({ requestPath, valueStreamId, stageId }, params = {}) => {
- const stageBase = buildValueStreamStageDataPath({ requestPath, valueStreamId, stageId });
+export const getValueStreamStageMedian = (
+ { namespacePath, valueStreamId, stageId },
+ params = {},
+) => {
+ const stageBase = buildValueStreamStageDataPath({ namespacePath, valueStreamId, stageId });
return axios.get(joinPaths(stageBase, 'median'), { params });
};
export const getValueStreamStageRecords = (
- { requestPath, valueStreamId, stageId },
+ { namespacePath, valueStreamId, stageId },
params = {},
) => {
- const stageBase = buildValueStreamStageDataPath({ requestPath, valueStreamId, stageId });
+ const stageBase = buildValueStreamStageDataPath({ namespacePath, valueStreamId, stageId });
return axios.get(joinPaths(stageBase, 'records'), { params });
};
-export const getValueStreamStageCounts = ({ requestPath, valueStreamId, stageId }, params = {}) => {
- const stageBase = buildValueStreamStageDataPath({ requestPath, valueStreamId, stageId });
+export const getValueStreamStageCounts = (
+ { namespacePath, valueStreamId, stageId },
+ params = {},
+) => {
+ const stageBase = buildValueStreamStageDataPath({ namespacePath, valueStreamId, stageId });
return axios.get(joinPaths(stageBase, 'count'), { params });
};
export const getValueStreamMetrics = ({
endpoint = METRIC_TYPE_SUMMARY,
- requestPath,
+ requestPath: namespacePath,
params = {},
}) => {
- const metricBase = buildProjectMetricsPath(requestPath);
+ const metricBase = buildProjectMetricsPath(namespacePath);
return axios.get(joinPaths(metricBase, endpoint), { params });
};
-export const getValueStreamSummaryMetrics = (requestPath, params = {}) => {
- const metricBase = buildProjectMetricsPath(requestPath);
+export const getValueStreamSummaryMetrics = (namespacePath, params = {}) => {
+ const metricBase = buildProjectMetricsPath(namespacePath);
return axios.get(joinPaths(metricBase, 'summary'), { params });
};
diff --git a/app/assets/javascripts/api/user_api.js b/app/assets/javascripts/api/user_api.js
index 45fddc3a696..bcb0f079d3d 100644
--- a/app/assets/javascripts/api/user_api.js
+++ b/app/assets/javascripts/api/user_api.js
@@ -1,5 +1,5 @@
import { DEFAULT_PER_PAGE } from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import axios from '../lib/utils/axios_utils';
import { buildApiUrl } from './api_utils';
diff --git a/app/assets/javascripts/artifacts/components/artifact_row.vue b/app/assets/javascripts/artifacts/components/artifact_row.vue
index fffdfce60a7..f37c4c6f107 100644
--- a/app/assets/javascripts/artifacts/components/artifact_row.vue
+++ b/app/assets/javascripts/artifacts/components/artifact_row.vue
@@ -1,7 +1,8 @@
<script>
-import { GlButtonGroup, GlButton, GlBadge, GlFriendlyWrap } from '@gitlab/ui';
+import { GlButtonGroup, GlButton, GlBadge, GlFriendlyWrap, GlFormCheckbox } from '@gitlab/ui';
import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { I18N_EXPIRED, I18N_DOWNLOAD, I18N_DELETE } from '../constants';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { I18N_EXPIRED, I18N_DOWNLOAD, I18N_DELETE, BULK_DELETE_FEATURE_FLAG } from '../constants';
export default {
name: 'ArtifactRow',
@@ -10,13 +11,19 @@ export default {
GlButton,
GlBadge,
GlFriendlyWrap,
+ GlFormCheckbox,
},
+ mixins: [glFeatureFlagsMixin()],
inject: ['canDestroyArtifacts'],
props: {
artifact: {
type: Object,
required: true,
},
+ isSelected: {
+ type: Boolean,
+ required: true,
+ },
isLastRow: {
type: Boolean,
required: true,
@@ -32,6 +39,16 @@ export default {
artifactSize() {
return numberToHumanSize(this.artifact.size);
},
+ canBulkDestroyArtifacts() {
+ return this.glFeatures[BULK_DELETE_FEATURE_FLAG] && this.canDestroyArtifacts;
+ },
+ },
+ methods: {
+ handleInput(checked) {
+ if (checked === this.isSelected) return;
+
+ this.$emit('selectArtifact', this.artifact, checked);
+ },
},
i18n: {
expired: I18N_EXPIRED,
@@ -46,6 +63,9 @@ export default {
:class="{ 'gl-border-b-solid gl-border-b-1 gl-border-gray-100': !isLastRow }"
>
<div class="gl-display-inline-flex gl-align-items-center gl-w-full">
+ <span v-if="canBulkDestroyArtifacts" class="gl-pl-5">
+ <gl-form-checkbox :checked="isSelected" @input="handleInput" />
+ </span>
<span
class="gl-w-half gl-pl-8 gl-display-flex gl-align-items-center"
data-testid="job-artifact-row-name"
diff --git a/app/assets/javascripts/artifacts/components/artifacts_bulk_delete.vue b/app/assets/javascripts/artifacts/components/artifacts_bulk_delete.vue
new file mode 100644
index 00000000000..cc08551fdb7
--- /dev/null
+++ b/app/assets/javascripts/artifacts/components/artifacts_bulk_delete.vue
@@ -0,0 +1,182 @@
+<script>
+import { GlButton, GlModal, GlSprintf } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import { TYPENAME_PROJECT } from '~/graphql_shared/constants';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import getJobArtifactsQuery from '../graphql/queries/get_job_artifacts.query.graphql';
+import bulkDestroyJobArtifactsMutation from '../graphql/mutations/bulk_destroy_job_artifacts.mutation.graphql';
+import { removeArtifactFromStore } from '../graphql/cache_update';
+import {
+ I18N_BULK_DELETE_BANNER,
+ I18N_BULK_DELETE_CLEAR_SELECTION,
+ I18N_BULK_DELETE_DELETE_SELECTED,
+ I18N_BULK_DELETE_MODAL_TITLE,
+ I18N_BULK_DELETE_BODY,
+ I18N_BULK_DELETE_ACTION,
+ I18N_BULK_DELETE_PARTIAL_ERROR,
+ I18N_BULK_DELETE_ERROR,
+ I18N_MODAL_CANCEL,
+ BULK_DELETE_MODAL_ID,
+} from '../constants';
+
+export default {
+ name: 'ArtifactsBulkDelete',
+ components: {
+ GlButton,
+ GlModal,
+ GlSprintf,
+ },
+ inject: ['projectId'],
+ props: {
+ selectedArtifacts: {
+ type: Array,
+ required: true,
+ },
+ queryVariables: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isModalVisible: false,
+ isDeleting: false,
+ };
+ },
+ computed: {
+ checkedCount() {
+ return this.selectedArtifacts.length || 0;
+ },
+ modalActionPrimary() {
+ return {
+ text: I18N_BULK_DELETE_ACTION(this.checkedCount),
+ attributes: {
+ loading: this.isDeleting,
+ variant: 'danger',
+ },
+ };
+ },
+ modalActionCancel() {
+ return {
+ text: I18N_MODAL_CANCEL,
+ attributes: {
+ loading: this.isDeleting,
+ },
+ };
+ },
+ },
+ methods: {
+ async onConfirmDelete(e) {
+ // don't close modal until deletion is complete
+ if (e) {
+ e.preventDefault();
+ }
+ this.isDeleting = true;
+
+ try {
+ await this.$apollo.mutate({
+ mutation: bulkDestroyJobArtifactsMutation,
+ variables: {
+ projectId: convertToGraphQLId(TYPENAME_PROJECT, this.projectId),
+ ids: this.selectedArtifacts,
+ },
+ update: (store, { data }) => {
+ const { errors, destroyedCount, destroyedIds } = data.bulkDestroyJobArtifacts;
+ if (errors?.length) {
+ createAlert({
+ message: I18N_BULK_DELETE_PARTIAL_ERROR,
+ captureError: true,
+ error: new Error(errors.join(' ')),
+ });
+ }
+ if (destroyedIds?.length) {
+ this.$emit('deleted', destroyedCount);
+
+ // Remove deleted artifacts from the cache
+ destroyedIds.forEach((id) => {
+ removeArtifactFromStore(store, id, getJobArtifactsQuery, this.queryVariables);
+ });
+ store.gc();
+
+ this.$emit('clearSelectedArtifacts');
+ }
+ },
+ });
+ } catch (error) {
+ this.onError(error);
+ } finally {
+ this.isDeleting = false;
+ this.isModalVisible = false;
+ }
+ },
+ onError(error) {
+ createAlert({
+ message: I18N_BULK_DELETE_ERROR,
+ captureError: true,
+ error,
+ });
+ },
+ handleClearSelection() {
+ this.$emit('clearSelectedArtifacts');
+ },
+ handleModalShow() {
+ this.isModalVisible = true;
+ },
+ handleModalHide() {
+ this.isModalVisible = false;
+ },
+ },
+ i18n: {
+ banner: I18N_BULK_DELETE_BANNER,
+ clearSelection: I18N_BULK_DELETE_CLEAR_SELECTION,
+ deleteSelected: I18N_BULK_DELETE_DELETE_SELECTED,
+ modalTitle: I18N_BULK_DELETE_MODAL_TITLE,
+ modalBody: I18N_BULK_DELETE_BODY,
+ },
+ BULK_DELETE_MODAL_ID,
+};
+</script>
+<template>
+ <div class="gl-my-4 gl-p-4 gl-border-1 gl-border-solid gl-border-gray-100">
+ <div class="gl-display-flex gl-align-items-center">
+ <div>
+ <gl-sprintf :message="$options.i18n.banner(checkedCount)">
+ <template #strong="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-ml-auto">
+ <gl-button
+ variant="default"
+ data-testid="bulk-delete-clear-button"
+ @click="handleClearSelection"
+ >
+ {{ $options.i18n.clearSelection }}
+ </gl-button>
+ <gl-button
+ variant="danger"
+ data-testid="bulk-delete-delete-button"
+ @click="handleModalShow"
+ >
+ {{ $options.i18n.deleteSelected }}
+ </gl-button>
+ </div>
+ </div>
+ <gl-modal
+ size="sm"
+ :modal-id="$options.BULK_DELETE_MODAL_ID"
+ :visible="isModalVisible"
+ :title="$options.i18n.modalTitle(checkedCount)"
+ :action-primary="modalActionPrimary"
+ :action-cancel="modalActionCancel"
+ @hide="handleModalHide"
+ @primary="onConfirmDelete"
+ >
+ <gl-sprintf
+ data-testid="bulk-delete-modal-content"
+ :message="$options.i18n.modalBody(checkedCount)"
+ />
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/artifacts/components/artifacts_table_row_details.vue b/app/assets/javascripts/artifacts/components/artifacts_table_row_details.vue
index 4a826d0d462..7d675251ffd 100644
--- a/app/assets/javascripts/artifacts/components/artifacts_table_row_details.vue
+++ b/app/assets/javascripts/artifacts/components/artifacts_table_row_details.vue
@@ -1,5 +1,5 @@
<script>
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller';
import getJobArtifactsQuery from '../graphql/queries/get_job_artifacts.query.graphql';
import destroyArtifactMutation from '../graphql/mutations/destroy_artifact.mutation.graphql';
@@ -25,6 +25,10 @@ export default {
type: Object,
required: true,
},
+ selectedArtifacts: {
+ type: Array,
+ required: true,
+ },
queryVariables: {
type: Object,
required: true,
@@ -52,6 +56,9 @@ export default {
isLastRow(index) {
return index === this.artifacts.nodes.length - 1;
},
+ isSelected(item) {
+ return this.selectedArtifacts.includes(item.id);
+ },
showModal(item) {
this.deletingArtifactId = item.id;
this.deletingArtifactName = item.name;
@@ -98,7 +105,9 @@ export default {
<dynamic-scroller-item :item="item" :active="active" :class="{ active }">
<artifact-row
:artifact="item"
+ :is-selected="isSelected(item)"
:is-last-row="isLastRow(index)"
+ v-on="$listeners"
@delete="showModal(item)"
/>
</dynamic-scroller-item>
diff --git a/app/assets/javascripts/artifacts/components/job_artifacts_table.vue b/app/assets/javascripts/artifacts/components/job_artifacts_table.vue
index 5743ff3ec9e..ba4026190a2 100644
--- a/app/assets/javascripts/artifacts/components/job_artifacts_table.vue
+++ b/app/assets/javascripts/artifacts/components/job_artifacts_table.vue
@@ -8,11 +8,13 @@ import {
GlBadge,
GlIcon,
GlPagination,
+ GlFormCheckbox,
} from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import getJobArtifactsQuery from '../graphql/queries/get_job_artifacts.query.graphql';
import { totalArtifactsSizeForJob, mapArchivesToJobNodes, mapBooleansToJobNodes } from '../utils';
import {
@@ -33,7 +35,11 @@ import {
INITIAL_NEXT_PAGE_CURSOR,
JOBS_PER_PAGE,
INITIAL_LAST_PAGE_SIZE,
+ BULK_DELETE_FEATURE_FLAG,
+ I18N_BULK_DELETE_CONFIRMATION_TOAST,
} from '../constants';
+import JobCheckbox from './job_checkbox.vue';
+import ArtifactsBulkDelete from './artifacts_bulk_delete.vue';
import ArtifactsTableRowDetails from './artifacts_table_row_details.vue';
import FeedbackBanner from './feedback_banner.vue';
@@ -56,11 +62,15 @@ export default {
GlBadge,
GlIcon,
GlPagination,
+ GlFormCheckbox,
CiIcon,
TimeAgo,
+ JobCheckbox,
+ ArtifactsBulkDelete,
ArtifactsTableRowDetails,
FeedbackBanner,
},
+ mixins: [glFeatureFlagsMixin()],
inject: ['projectPath', 'canDestroyArtifacts'],
apollo: {
jobArtifacts: {
@@ -68,9 +78,8 @@ export default {
variables() {
return this.queryVariables;
},
- update({ project: { jobs: { nodes = [], pageInfo = {}, count = 0 } = {} } }) {
+ update({ project: { jobs: { nodes = [], pageInfo = {} } = {} } }) {
this.pageInfo = pageInfo;
- this.count = count;
return nodes
.map(mapArchivesToJobNodes)
.map(mapBooleansToJobNodes)
@@ -93,9 +102,9 @@ export default {
data() {
return {
jobArtifacts: [],
- count: 0,
pageInfo: {},
expandedJobs: [],
+ selectedArtifacts: [],
pagination: INITIAL_PAGINATION_STATE,
};
},
@@ -110,7 +119,9 @@ export default {
};
},
showPagination() {
- return this.count > JOBS_PER_PAGE;
+ const { hasNextPage, hasPreviousPage } = this.pageInfo;
+
+ return hasNextPage || hasPreviousPage;
},
prevPage() {
return Number(this.pageInfo.hasPreviousPage);
@@ -118,6 +129,21 @@ export default {
nextPage() {
return Number(this.pageInfo.hasNextPage);
},
+ fields() {
+ return [
+ this.canBulkDestroyArtifacts && {
+ key: 'checkbox',
+ label: '',
+ },
+ ...this.$options.fields,
+ ];
+ },
+ anyArtifactsSelected() {
+ return Boolean(this.selectedArtifacts.length);
+ },
+ canBulkDestroyArtifacts() {
+ return this.glFeatures[BULK_DELETE_FEATURE_FLAG] && this.canDestroyArtifacts;
+ },
},
methods: {
refetchArtifacts() {
@@ -158,6 +184,19 @@ export default {
this.expandedJobs.splice(this.expandedJobs.indexOf(id), 1);
}
},
+ selectArtifact(artifactNode, checked) {
+ if (checked) {
+ this.selectedArtifacts.push(artifactNode.id);
+ } else {
+ this.selectedArtifacts.splice(this.selectedArtifacts.indexOf(artifactNode.id), 1);
+ }
+ },
+ clearSelectedArtifacts() {
+ this.selectedArtifacts = [];
+ },
+ showDeletedToast(deletedCount) {
+ this.$toast.show(I18N_BULK_DELETE_CONFIRMATION_TOAST(deletedCount));
+ },
downloadPath(job) {
return job.archive?.downloadPath;
},
@@ -217,9 +256,16 @@ export default {
<template>
<div>
<feedback-banner />
+ <artifacts-bulk-delete
+ v-if="canBulkDestroyArtifacts && anyArtifactsSelected"
+ :selected-artifacts="selectedArtifacts"
+ :query-variables="queryVariables"
+ @clearSelectedArtifacts="clearSelectedArtifacts"
+ @deleted="showDeletedToast"
+ />
<gl-table
:items="jobArtifacts"
- :fields="$options.fields"
+ :fields="fields"
:busy="$apollo.queries.jobArtifacts.loading"
stacked="sm"
details-td-class="gl-bg-gray-10! gl-p-0! gl-overflow-auto"
@@ -227,6 +273,29 @@ export default {
<template #table-busy>
<gl-loading-icon size="lg" />
</template>
+ <template v-if="canBulkDestroyArtifacts" #head(checkbox)>
+ <gl-form-checkbox
+ :disabled="!anyArtifactsSelected"
+ :checked="anyArtifactsSelected"
+ :indeterminate="anyArtifactsSelected"
+ @change="clearSelectedArtifacts"
+ />
+ </template>
+ <template
+ v-if="canBulkDestroyArtifacts"
+ #cell(checkbox)="{ item: { hasArtifacts, artifacts } }"
+ >
+ <job-checkbox
+ :has-artifacts="hasArtifacts"
+ :selected-artifacts="
+ artifacts.nodes.filter((node) => selectedArtifacts.includes(node.id))
+ "
+ :unselected-artifacts="
+ artifacts.nodes.filter((node) => !selectedArtifacts.includes(node.id))
+ "
+ @selectArtifact="selectArtifact"
+ />
+ </template>
<template
#cell(artifacts)="{ item: { id, artifacts, hasArtifacts }, toggleDetails, detailsShowing }"
>
@@ -323,8 +392,10 @@ export default {
<template #row-details="{ item: { artifacts } }">
<artifacts-table-row-details
:artifacts="artifacts"
+ :selected-artifacts="selectedArtifacts"
:query-variables="queryVariables"
@refetch="refetchArtifacts"
+ @selectArtifact="selectArtifact"
/>
</template>
</gl-table>
diff --git a/app/assets/javascripts/artifacts/components/job_checkbox.vue b/app/assets/javascripts/artifacts/components/job_checkbox.vue
new file mode 100644
index 00000000000..ce49b3f8678
--- /dev/null
+++ b/app/assets/javascripts/artifacts/components/job_checkbox.vue
@@ -0,0 +1,52 @@
+<script>
+import { GlFormCheckbox } from '@gitlab/ui';
+
+export default {
+ name: 'JobCheckbox',
+ components: {
+ GlFormCheckbox,
+ },
+ props: {
+ hasArtifacts: {
+ type: Boolean,
+ required: true,
+ },
+ selectedArtifacts: {
+ type: Array,
+ required: true,
+ },
+ unselectedArtifacts: {
+ type: Array,
+ required: true,
+ },
+ },
+ computed: {
+ disabled() {
+ return !this.hasArtifacts;
+ },
+ checked() {
+ return this.hasArtifacts && this.unselectedArtifacts.length === 0;
+ },
+ indeterminate() {
+ return this.selectedArtifacts.length > 0 && this.unselectedArtifacts.length > 0;
+ },
+ },
+ methods: {
+ handleInput(checked) {
+ if (checked) {
+ this.unselectedArtifacts.forEach((node) => this.$emit('selectArtifact', node, true));
+ } else {
+ this.selectedArtifacts.forEach((node) => this.$emit('selectArtifact', node, false));
+ }
+ },
+ },
+};
+</script>
+<template>
+ <gl-form-checkbox
+ :disabled="disabled"
+ :checked="checked"
+ :indeterminate="indeterminate"
+ @input="handleInput"
+ />
+</template>
diff --git a/app/assets/javascripts/artifacts/constants.js b/app/assets/javascripts/artifacts/constants.js
index da562b03bf8..4ac20d963d1 100644
--- a/app/assets/javascripts/artifacts/constants.js
+++ b/app/assets/javascripts/artifacts/constants.js
@@ -54,6 +54,45 @@ export const I18N_FEEDBACK_BANNER_BODY = s__(
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 BULK_DELETE_FEATURE_FLAG = 'ciJobArtifactBulkDestroy';
+export const I18N_BULK_DELETE_BANNER = (count) =>
+ sprintf(
+ n__(
+ 'Artifacts|%{strongStart}%{count}%{strongEnd} artifact selected',
+ 'Artifacts|%{strongStart}%{count}%{strongEnd} artifacts selected',
+ count,
+ ),
+ {
+ count,
+ },
+ );
+export const I18N_BULK_DELETE_CLEAR_SELECTION = s__('Artifacts|Clear selection');
+export const I18N_BULK_DELETE_DELETE_SELECTED = s__('Artifacts|Delete selected');
+
+export const BULK_DELETE_MODAL_ID = 'artifacts-bulk-delete-modal';
+export const I18N_BULK_DELETE_MODAL_TITLE = (count) =>
+ n__('Artifacts|Delete %d artifact?', 'Artifacts|Delete %d artifacts?', count);
+export const I18N_BULK_DELETE_BODY = (count) =>
+ sprintf(
+ n__(
+ 'Artifacts|The selected artifact will be permanently deleted. Any reports generated from these artifacts will be empty.',
+ 'Artifacts|The selected artifacts will be permanently deleted. Any reports generated from these artifacts will be empty.',
+ count,
+ ),
+ { count },
+ );
+export const I18N_BULK_DELETE_ACTION = (count) =>
+ n__('Artifacts|Delete %d artifact', 'Artifacts|Delete %d artifacts', count);
+
+export const I18N_BULK_DELETE_PARTIAL_ERROR = s__(
+ 'Artifacts|An error occurred while deleting. Some artifacts may not have been deleted.',
+);
+export const I18N_BULK_DELETE_ERROR = s__(
+ 'Artifacts|Something went wrong while deleting. Please refresh the page to try again.',
+);
+export const I18N_BULK_DELETE_CONFIRMATION_TOAST = (count) =>
+ n__('Artifacts|%d selected artifact deleted', 'Artifacts|%d selected artifacts deleted', count);
+
export const INITIAL_CURRENT_PAGE = 1;
export const INITIAL_PREVIOUS_PAGE_CURSOR = '';
export const INITIAL_NEXT_PAGE_CURSOR = '';
diff --git a/app/assets/javascripts/artifacts/graphql/mutations/bulk_destroy_job_artifacts.mutation.graphql b/app/assets/javascripts/artifacts/graphql/mutations/bulk_destroy_job_artifacts.mutation.graphql
new file mode 100644
index 00000000000..421b9258ca0
--- /dev/null
+++ b/app/assets/javascripts/artifacts/graphql/mutations/bulk_destroy_job_artifacts.mutation.graphql
@@ -0,0 +1,7 @@
+mutation bulkDestroyJobArtifacts($projectId: ProjectID!, $ids: [CiJobArtifactID!]!) {
+ bulkDestroyJobArtifacts(input: { projectId: $projectId, ids: $ids }) {
+ destroyedCount
+ destroyedIds
+ errors
+ }
+}
diff --git a/app/assets/javascripts/artifacts/index.js b/app/assets/javascripts/artifacts/index.js
index a62b3daa961..6e795fd9bd7 100644
--- a/app/assets/javascripts/artifacts/index.js
+++ b/app/assets/javascripts/artifacts/index.js
@@ -1,3 +1,4 @@
+import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
@@ -5,6 +6,7 @@ import { parseBoolean } from '~/lib/utils/common_utils';
import App from './components/app.vue';
Vue.use(VueApollo);
+Vue.use(GlToast);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
@@ -17,13 +19,19 @@ export const initArtifactsTable = () => {
return false;
}
- const { projectPath, canDestroyArtifacts, artifactsManagementFeedbackImagePath } = el.dataset;
+ const {
+ projectPath,
+ projectId,
+ canDestroyArtifacts,
+ artifactsManagementFeedbackImagePath,
+ } = el.dataset;
return new Vue({
el,
apolloProvider,
provide: {
projectPath,
+ projectId,
canDestroyArtifacts: parseBoolean(canDestroyArtifacts),
artifactsManagementFeedbackImagePath,
},
diff --git a/app/assets/javascripts/authentication/mount_2fa.js b/app/assets/javascripts/authentication/mount_2fa.js
index 52ed67b8c7b..29dcab9ed4d 100644
--- a/app/assets/javascripts/authentication/mount_2fa.js
+++ b/app/assets/javascripts/authentication/mount_2fa.js
@@ -1,29 +1,9 @@
-import $ from 'jquery';
-import initU2F from './u2f';
-import U2FRegister from './u2f/register';
-import initWebauthn from './webauthn';
-import WebAuthnRegister from './webauthn/register';
+import { initWebauthnAuthenticate, initWebauthnRegister } from './webauthn';
export const mount2faAuthentication = () => {
- if (gon.webauthn) {
- initWebauthn();
- } else {
- initU2F();
- }
+ initWebauthnAuthenticate();
};
export const mount2faRegistration = () => {
- const el = $('#js-register-token-2fa');
-
- if (!el.length) {
- return;
- }
-
- if (gon.webauthn) {
- const webauthnRegister = new WebAuthnRegister(el, gon.webauthn);
- webauthnRegister.start();
- } else {
- const u2fRegister = new U2FRegister(el, gon.u2f);
- u2fRegister.start();
- }
+ initWebauthnRegister();
};
diff --git a/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue b/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue
index 484c6524d0e..98ed2a31730 100644
--- a/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue
+++ b/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue
@@ -6,10 +6,8 @@ import { __ } from '~/locale';
export const i18n = {
currentPassword: __('Current password'),
confirmTitle: __('Are you sure?'),
- confirmWebAuthn: __(
- 'This will invalidate your registered applications and U2F / WebAuthn devices.',
- ),
- confirm: __('This will invalidate your registered applications and U2F devices.'),
+ confirmWebAuthn: __('This will invalidate your registered applications and WebAuthn devices.'),
+ confirm: __('This will invalidate your registered applications and WebAuthn devices.'),
disableTwoFactor: __('Disable two-factor authentication'),
disable: __('Disable'),
cancel: __('Cancel'),
diff --git a/app/assets/javascripts/authentication/u2f/authenticate.js b/app/assets/javascripts/authentication/u2f/authenticate.js
deleted file mode 100644
index 22eca904f32..00000000000
--- a/app/assets/javascripts/authentication/u2f/authenticate.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import $ from 'jquery';
-import { template as lodashTemplate, omit } from 'lodash';
-import U2FError from './error';
-import importU2FLibrary from './util';
-
-// Authenticate U2F (universal 2nd factor) devices for users to authenticate with.
-//
-// State Flow #1: setup -> in_progress -> authenticated -> POST to server
-// State Flow #2: setup -> in_progress -> error -> setup
-export default class U2FAuthenticate {
- constructor(container, form, u2fParams, fallbackButton, fallbackUI) {
- this.u2fUtils = null;
- this.container = container;
- this.renderAuthenticated = this.renderAuthenticated.bind(this);
- this.renderError = this.renderError.bind(this);
- this.renderInProgress = this.renderInProgress.bind(this);
- this.renderTemplate = this.renderTemplate.bind(this);
- this.authenticate = this.authenticate.bind(this);
- this.start = this.start.bind(this);
- this.appId = u2fParams.app_id;
- this.challenge = u2fParams.challenge;
- this.form = form;
- this.fallbackButton = fallbackButton;
- this.fallbackUI = fallbackUI;
- if (this.fallbackButton) {
- this.fallbackButton.addEventListener('click', this.switchToFallbackUI.bind(this));
- }
-
- // The U2F Javascript API v1.1 requires a single challenge, with
- // _no challenges per-request_. The U2F Javascript API v1.0 requires a
- // challenge per-request, which is done by copying the single challenge
- // into every request.
- //
- // In either case, we don't need the per-request challenges that the server
- // has generated, so we can remove them.
- //
- // Note: The server library fixes this behaviour in (unreleased) version 1.0.0.
- // This can be removed once we upgrade.
- // https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4
- this.signRequests = u2fParams.sign_requests.map((request) => omit(request, 'challenge'));
-
- this.templates = {
- inProgress: '#js-authenticate-token-2fa-in-progress',
- error: '#js-authenticate-token-2fa-error',
- authenticated: '#js-authenticate-token-2fa-authenticated',
- };
- }
-
- start() {
- return importU2FLibrary()
- .then((utils) => {
- this.u2fUtils = utils;
- this.renderInProgress();
- })
- .catch(() => this.switchToFallbackUI());
- }
-
- authenticate() {
- return this.u2fUtils.sign(
- this.appId,
- this.challenge,
- this.signRequests,
- (response) => {
- if (response.errorCode) {
- const error = new U2FError(response.errorCode, 'authenticate');
- return this.renderError(error);
- }
- return this.renderAuthenticated(JSON.stringify(response));
- },
- 10,
- );
- }
-
- renderTemplate(name, params) {
- const templateString = $(this.templates[name]).html();
- const template = lodashTemplate(templateString);
- return this.container.html(template(params));
- }
-
- renderInProgress() {
- this.renderTemplate('inProgress');
- return this.authenticate();
- }
-
- renderError(error) {
- this.renderTemplate('error', {
- error_message: error.message(),
- error_name: error.errorCode,
- });
- return this.container.find('#js-token-2fa-try-again').on('click', this.renderInProgress);
- }
-
- renderAuthenticated(deviceResponse) {
- this.renderTemplate('authenticated');
- const container = this.container[0];
- container.querySelector('#js-device-response').value = deviceResponse;
- container.querySelector(this.form).submit();
- this.fallbackButton.classList.add('hidden');
- }
-
- switchToFallbackUI() {
- this.fallbackButton.classList.add('hidden');
- this.container[0].classList.add('hidden');
- this.fallbackUI.classList.remove('hidden');
- }
-}
diff --git a/app/assets/javascripts/authentication/u2f/error.js b/app/assets/javascripts/authentication/u2f/error.js
deleted file mode 100644
index ca0fc0700ad..00000000000
--- a/app/assets/javascripts/authentication/u2f/error.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { __ } from '~/locale';
-
-export default class U2FError {
- constructor(errorCode, u2fFlowType) {
- this.errorCode = errorCode;
- this.message = this.message.bind(this);
- this.httpsDisabled = window.location.protocol !== 'https:';
- this.u2fFlowType = u2fFlowType;
- }
-
- message() {
- if (this.errorCode === window.u2f.ErrorCodes.BAD_REQUEST && this.httpsDisabled) {
- return __(
- 'U2F only works with HTTPS-enabled websites. Contact your administrator for more details.',
- );
- } else if (this.errorCode === window.u2f.ErrorCodes.DEVICE_INELIGIBLE) {
- if (this.u2fFlowType === 'authenticate') {
- return __('This device has not been registered with us.');
- }
- if (this.u2fFlowType === 'register') {
- return __('This device has already been registered with us.');
- }
- }
- return __('There was a problem communicating with your device.');
- }
-}
diff --git a/app/assets/javascripts/authentication/u2f/index.js b/app/assets/javascripts/authentication/u2f/index.js
deleted file mode 100644
index f129acca1c3..00000000000
--- a/app/assets/javascripts/authentication/u2f/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import $ from 'jquery';
-import U2FAuthenticate from './authenticate';
-
-export default () => {
- if (!gon.u2f) return;
-
- const u2fAuthenticate = new U2FAuthenticate(
- $('#js-authenticate-token-2fa'),
- '#js-login-token-2fa-form',
- gon.u2f,
- document.querySelector('#js-login-2fa-device'),
- document.querySelector('.js-2fa-form'),
- );
- u2fAuthenticate.start();
- // needed in rspec (FakeU2fDevice)
- gl.u2fAuthenticate = u2fAuthenticate;
-};
diff --git a/app/assets/javascripts/authentication/u2f/register.js b/app/assets/javascripts/authentication/u2f/register.js
deleted file mode 100644
index 6c98f0978bc..00000000000
--- a/app/assets/javascripts/authentication/u2f/register.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import $ from 'jquery';
-import { template as lodashTemplate } from 'lodash';
-import { __ } from '~/locale';
-import U2FError from './error';
-import importU2FLibrary from './util';
-
-// Register U2F (universal 2nd factor) devices for users to authenticate with.
-//
-// State Flow #1: setup -> in_progress -> registered -> POST to server
-// State Flow #2: setup -> in_progress -> error -> setup
-export default class U2FRegister {
- constructor(container, u2fParams) {
- this.u2fUtils = null;
- this.container = container;
- this.renderNotSupported = this.renderNotSupported.bind(this);
- this.renderRegistered = this.renderRegistered.bind(this);
- this.renderError = this.renderError.bind(this);
- this.renderInProgress = this.renderInProgress.bind(this);
- this.renderSetup = this.renderSetup.bind(this);
- this.renderTemplate = this.renderTemplate.bind(this);
- this.register = this.register.bind(this);
- this.start = this.start.bind(this);
- this.appId = u2fParams.app_id;
- this.registerRequests = u2fParams.register_requests;
- this.signRequests = u2fParams.sign_requests;
-
- this.templates = {
- message: '#js-register-2fa-message',
- setup: '#js-register-token-2fa-setup',
- error: '#js-register-token-2fa-error',
- registered: '#js-register-token-2fa-registered',
- };
- }
-
- start() {
- return importU2FLibrary()
- .then((utils) => {
- this.u2fUtils = utils;
- this.renderSetup();
- })
- .catch(() => this.renderNotSupported());
- }
-
- register() {
- return this.u2fUtils.register(
- this.appId,
- this.registerRequests,
- this.signRequests,
- (response) => {
- if (response.errorCode) {
- const error = new U2FError(response.errorCode, 'register');
- return this.renderError(error);
- }
- return this.renderRegistered(JSON.stringify(response));
- },
- 10,
- );
- }
-
- renderTemplate(name, params) {
- const templateString = $(this.templates[name]).html();
- const template = lodashTemplate(templateString);
- return this.container.html(template(params));
- }
-
- renderSetup() {
- this.renderTemplate('setup');
- return this.container.find('#js-setup-token-2fa-device').on('click', this.renderInProgress);
- }
-
- renderInProgress() {
- this.renderTemplate('message', {
- message: __(
- 'Trying to communicate with your device. Plug it in (if needed) and press the button on the device now.',
- ),
- });
- return this.register();
- }
-
- renderError(error) {
- this.renderTemplate('error', {
- error_message: error.message(),
- error_name: error.errorCode,
- });
- return this.container.find('#js-token-2fa-try-again').on('click', this.renderSetup);
- }
-
- renderRegistered(deviceResponse) {
- this.renderTemplate('registered');
- // Prefer to do this instead of interpolating using Underscore templates
- // because of JSON escaping issues.
- return this.container.find('#js-device-response').val(deviceResponse);
- }
-
- renderNotSupported() {
- return this.renderTemplate('message', {
- message: __(
- "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer).",
- ),
- });
- }
-}
diff --git a/app/assets/javascripts/authentication/u2f/util.js b/app/assets/javascripts/authentication/u2f/util.js
deleted file mode 100644
index b706481c02f..00000000000
--- a/app/assets/javascripts/authentication/u2f/util.js
+++ /dev/null
@@ -1,40 +0,0 @@
-function isOpera(userAgent) {
- return userAgent.indexOf('Opera') >= 0 || userAgent.indexOf('OPR') >= 0;
-}
-
-function getOperaVersion(userAgent) {
- const match = userAgent.match(/OPR[^0-9]*([0-9]+)[^0-9]+/);
- return match ? parseInt(match[1], 10) : false;
-}
-
-function isChrome(userAgent) {
- return userAgent.indexOf('Chrom') >= 0 && !isOpera(userAgent);
-}
-
-function getChromeVersion(userAgent) {
- const match = userAgent.match(/Chrom(?:e|ium)\/([0-9]+)\./);
- return match ? parseInt(match[1], 10) : false;
-}
-
-export function canInjectU2fApi(userAgent) {
- const isSupportedChrome = isChrome(userAgent) && getChromeVersion(userAgent) >= 41;
- const isSupportedOpera = isOpera(userAgent) && getOperaVersion(userAgent) >= 40;
- const isMobile =
- userAgent.indexOf('droid') >= 0 ||
- userAgent.indexOf('CriOS') >= 0 ||
- /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);
- return (isSupportedChrome || isSupportedOpera) && !isMobile;
-}
-
-export default function importU2FLibrary() {
- if (window.u2f) {
- return Promise.resolve(window.u2f);
- }
-
- const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : '';
- if (canInjectU2fApi(userAgent) || (gon && gon.test_env)) {
- return import(/* webpackMode: "eager" */ 'vendor/u2f').then(() => window.u2f);
- }
-
- return Promise.reject();
-}
diff --git a/app/assets/javascripts/authentication/webauthn/authenticate.js b/app/assets/javascripts/authentication/webauthn/authenticate.js
index 47cb7a40f76..748945a680b 100644
--- a/app/assets/javascripts/authentication/webauthn/authenticate.js
+++ b/app/assets/javascripts/authentication/webauthn/authenticate.js
@@ -1,3 +1,4 @@
+import { WEBAUTHN_AUTHENTICATE } from './constants';
import WebAuthnError from './error';
import WebAuthnFlow from './flow';
import { supported, convertGetParams, convertGetResponse } from './util';
@@ -44,7 +45,7 @@ export default class WebAuthnAuthenticate {
this.renderAuthenticated(JSON.stringify(convertedResponse));
})
.catch((err) => {
- this.flow.renderError(new WebAuthnError(err, 'authenticate'));
+ this.flow.renderError(new WebAuthnError(err, WEBAUTHN_AUTHENTICATE));
});
}
diff --git a/app/assets/javascripts/authentication/webauthn/components/registration.vue b/app/assets/javascripts/authentication/webauthn/components/registration.vue
new file mode 100644
index 00000000000..84132a7d062
--- /dev/null
+++ b/app/assets/javascripts/authentication/webauthn/components/registration.vue
@@ -0,0 +1,226 @@
+<script>
+import {
+ GlAlert,
+ GlButton,
+ GlForm,
+ GlFormInput,
+ GlFormGroup,
+ GlLink,
+ GlLoadingIcon,
+ GlSprintf,
+} from '@gitlab/ui';
+import {
+ I18N_BUTTON_REGISTER,
+ I18N_BUTTON_SETUP,
+ I18N_BUTTON_TRY_AGAIN,
+ I18N_DEVICE_NAME,
+ I18N_DEVICE_NAME_DESCRIPTION,
+ I18N_DEVICE_NAME_PLACEHOLDER,
+ I18N_ERROR_HTTP,
+ I18N_ERROR_UNSUPPORTED_BROWSER,
+ I18N_INFO_TEXT,
+ I18N_NOTICE,
+ I18N_PASSWORD,
+ I18N_PASSWORD_DESCRIPTION,
+ I18N_STATUS_SUCCESS,
+ I18N_STATUS_WAITING,
+ STATE_ERROR,
+ STATE_READY,
+ STATE_SUCCESS,
+ STATE_UNSUPPORTED,
+ STATE_WAITING,
+ WEBAUTHN_DOCUMENTATION_PATH,
+ WEBAUTHN_REGISTER,
+} from '~/authentication/webauthn/constants';
+import WebAuthnError from '~/authentication/webauthn/error';
+import {
+ convertCreateParams,
+ convertCreateResponse,
+ isHTTPS,
+ supported,
+} from '~/authentication/webauthn/util';
+import csrf from '~/lib/utils/csrf';
+
+export default {
+ name: 'WebAuthnRegistration',
+ components: {
+ GlAlert,
+ GlButton,
+ GlForm,
+ GlFormInput,
+ GlFormGroup,
+ GlLink,
+ GlLoadingIcon,
+ GlSprintf,
+ },
+ I18N_BUTTON_REGISTER,
+ I18N_BUTTON_SETUP,
+ I18N_BUTTON_TRY_AGAIN,
+ I18N_DEVICE_NAME,
+ I18N_DEVICE_NAME_DESCRIPTION,
+ I18N_DEVICE_NAME_PLACEHOLDER,
+ I18N_ERROR_HTTP,
+ I18N_ERROR_UNSUPPORTED_BROWSER,
+ I18N_INFO_TEXT,
+ I18N_NOTICE,
+ I18N_PASSWORD,
+ I18N_PASSWORD_DESCRIPTION,
+ I18N_STATUS_SUCCESS,
+ I18N_STATUS_WAITING,
+ STATE_ERROR,
+ STATE_READY,
+ STATE_SUCCESS,
+ STATE_UNSUPPORTED,
+ STATE_WAITING,
+ WEBAUTHN_DOCUMENTATION_PATH,
+ inject: ['initialError', 'passwordRequired', 'targetPath'],
+ data() {
+ return {
+ csrfToken: csrf.token,
+ form: { deviceName: '', password: '' },
+ state: STATE_UNSUPPORTED,
+ errorMessage: this.initialError,
+ credentials: null,
+ };
+ },
+ computed: {
+ disabled() {
+ const isEmptyDeviceName = this.form.deviceName.trim() === '';
+ const isEmptyPassword = this.form.password.trim() === '';
+
+ if (this.passwordRequired === false) {
+ return isEmptyDeviceName;
+ }
+
+ return isEmptyDeviceName || isEmptyPassword;
+ },
+ },
+ created() {
+ if (this.errorMessage) {
+ this.state = STATE_ERROR;
+ return;
+ }
+
+ if (supported()) {
+ this.state = STATE_READY;
+ return;
+ }
+
+ this.errorMessage = isHTTPS() ? I18N_ERROR_UNSUPPORTED_BROWSER : I18N_ERROR_HTTP;
+ },
+ methods: {
+ isCurrentState(state) {
+ return this.state === state;
+ },
+ async onRegister() {
+ this.state = STATE_WAITING;
+
+ try {
+ const credentials = await navigator.credentials.create({
+ publicKey: convertCreateParams(gon.webauthn.options),
+ });
+
+ this.credentials = JSON.stringify(convertCreateResponse(credentials));
+ this.state = STATE_SUCCESS;
+ } catch (error) {
+ this.errorMessage = new WebAuthnError(error, WEBAUTHN_REGISTER).message();
+ this.state = STATE_ERROR;
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <template v-if="isCurrentState($options.STATE_UNSUPPORTED)">
+ <gl-alert variant="danger" :dismissible="false">{{ errorMessage }}</gl-alert>
+ </template>
+
+ <template v-else-if="isCurrentState($options.STATE_READY)">
+ <div class="row">
+ <div class="col-md-5">
+ <gl-button variant="confirm" @click="onRegister">{{
+ $options.I18N_BUTTON_SETUP
+ }}</gl-button>
+ </div>
+ <div class="col-md-7">
+ <p>{{ $options.I18N_INFO_TEXT }}</p>
+ </div>
+ </div>
+ </template>
+
+ <template v-else-if="isCurrentState($options.STATE_WAITING)">
+ <gl-alert :dismissible="false">
+ {{ $options.I18N_STATUS_WAITING }}
+ <gl-loading-icon />
+ </gl-alert>
+ </template>
+
+ <template v-else-if="isCurrentState($options.STATE_SUCCESS)">
+ <p>{{ $options.I18N_STATUS_SUCCESS }}</p>
+ <gl-alert :dismissible="false" class="gl-mb-5">
+ <gl-sprintf :message="$options.I18N_NOTICE">
+ <template #link="{ content }">
+ <gl-link :href="$options.WEBAUTHN_DOCUMENTATION_PATH" target="_blank">{{
+ content
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-alert>
+
+ <div class="row">
+ <gl-form method="post" :action="targetPath" class="col-md-9" data-testid="create-webauthn">
+ <gl-form-group
+ v-if="passwordRequired"
+ :description="$options.I18N_PASSWORD_DESCRIPTION"
+ :label="$options.I18N_PASSWORD"
+ label-for="webauthn-registration-current-password"
+ >
+ <gl-form-input
+ id="webauthn-registration-current-password"
+ v-model="form.password"
+ name="current_password"
+ type="password"
+ autocomplete="current-password"
+ data-testid="current-password-input"
+ />
+ </gl-form-group>
+
+ <gl-form-group
+ :description="$options.I18N_DEVICE_NAME_DESCRIPTION"
+ :label="$options.I18N_DEVICE_NAME"
+ label-for="device-name"
+ >
+ <gl-form-input
+ id="device-name"
+ v-model="form.deviceName"
+ name="device_registration[name]"
+ :placeholder="$options.I18N_DEVICE_NAME_PLACEHOLDER"
+ data-testid="device-name-input"
+ />
+ </gl-form-group>
+
+ <input type="hidden" name="device_registration[device_response]" :value="credentials" />
+ <input :value="csrfToken" type="hidden" name="authenticity_token" />
+
+ <gl-button type="submit" :disabled="disabled" variant="confirm">{{
+ $options.I18N_BUTTON_REGISTER
+ }}</gl-button>
+ </gl-form>
+ </div>
+ </template>
+
+ <template v-else-if="isCurrentState($options.STATE_ERROR)">
+ <gl-alert
+ variant="danger"
+ :dismissible="false"
+ class="gl-mb-5"
+ :secondary-button-text="$options.I18N_BUTTON_TRY_AGAIN"
+ @secondaryAction="onRegister"
+ >
+ {{ errorMessage }}
+ </gl-alert>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/authentication/webauthn/constants.js b/app/assets/javascripts/authentication/webauthn/constants.js
new file mode 100644
index 00000000000..c41e6d2bd58
--- /dev/null
+++ b/app/assets/javascripts/authentication/webauthn/constants.js
@@ -0,0 +1,46 @@
+import { __ } from '~/locale';
+import { helpPagePath } from '~/helpers/help_page_helper';
+
+export const I18N_BUTTON_REGISTER = __('Register device');
+export const I18N_BUTTON_SETUP = __('Set up new device');
+export const I18N_BUTTON_TRY_AGAIN = __('Try again?');
+export const I18N_DEVICE_NAME = __('Device name');
+export const I18N_DEVICE_NAME_DESCRIPTION = __(
+ 'Excluding USB security keys, you should include the browser name together with the device name.',
+);
+export const I18N_DEVICE_NAME_PLACEHOLDER = __('Macbook Touch ID on Edge');
+export const I18N_ERROR_HTTP = __(
+ 'WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details.',
+);
+export const I18N_ERROR_UNSUPPORTED_BROWSER = __(
+ "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+).",
+);
+export const I18N_INFO_TEXT = __(
+ 'Your device needs to be set up. Plug it in (if needed) and click the button on the left.',
+);
+export const I18N_NOTICE = __(
+ '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}',
+);
+export const I18N_PASSWORD = __('Current password');
+export const I18N_PASSWORD_DESCRIPTION = __(
+ 'Your current password is required to register a new device.',
+);
+export const I18N_STATUS_SUCCESS = __(
+ 'Your device was successfully set up! Give it a name and register it with the GitLab server.',
+);
+export const I18N_STATUS_WAITING = __(
+ 'Trying to communicate with your device. Plug it in (if needed) and press the button on the device now.',
+);
+
+export const STATE_ERROR = 'error';
+export const STATE_READY = 'ready';
+export const STATE_SUCCESS = 'success';
+export const STATE_UNSUPPORTED = 'unsupported';
+export const STATE_WAITING = 'waiting';
+
+export const WEBAUTHN_AUTHENTICATE = 'authenticate';
+export const WEBAUTHN_REGISTER = 'register';
+export const WEBAUTHN_DOCUMENTATION_PATH = helpPagePath(
+ 'user/profile/account/two_factor_authentication',
+ { anchor: 'set-up-a-webauthn-device' },
+);
diff --git a/app/assets/javascripts/authentication/webauthn/error.js b/app/assets/javascripts/authentication/webauthn/error.js
index a1a3f861c25..40dbecd8bc9 100644
--- a/app/assets/javascripts/authentication/webauthn/error.js
+++ b/app/assets/javascripts/authentication/webauthn/error.js
@@ -1,5 +1,6 @@
import { __ } from '~/locale';
-import { isHTTPS, FLOW_AUTHENTICATE, FLOW_REGISTER } from './util';
+import { WEBAUTHN_AUTHENTICATE, WEBAUTHN_REGISTER } from './constants';
+import { isHTTPS } from './util';
export default class WebAuthnError {
constructor(error, flowType) {
@@ -13,9 +14,9 @@ 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 === FLOW_AUTHENTICATE) {
+ } else if (this.errorName === 'InvalidStateError' && this.flowType === WEBAUTHN_AUTHENTICATE) {
return __('This device has not been registered with us.');
- } else if (this.errorName === 'InvalidStateError' && this.flowType === FLOW_REGISTER) {
+ } else if (this.errorName === 'InvalidStateError' && this.flowType === WEBAUTHN_REGISTER) {
return __('This device has already been registered with us.');
} else if (this.errorName === 'SecurityError' && this.httpsDisabled) {
return __(
diff --git a/app/assets/javascripts/authentication/webauthn/index.js b/app/assets/javascripts/authentication/webauthn/index.js
index bbf694c7698..1fbe89d1097 100644
--- a/app/assets/javascripts/authentication/webauthn/index.js
+++ b/app/assets/javascripts/authentication/webauthn/index.js
@@ -1,7 +1,12 @@
import $ from 'jquery';
import WebAuthnAuthenticate from './authenticate';
+import WebAuthnRegister from './register';
+
+export const initWebauthnAuthenticate = () => {
+ if (!gon.webauthn) {
+ return;
+ }
-export default () => {
const webauthnAuthenticate = new WebAuthnAuthenticate(
$('#js-authenticate-token-2fa'),
'#js-login-token-2fa-form',
@@ -11,3 +16,14 @@ export default () => {
);
webauthnAuthenticate.start();
};
+
+export const initWebauthnRegister = () => {
+ const el = $('#js-register-token-2fa');
+
+ if (!el.length) {
+ return;
+ }
+
+ const webauthnRegister = new WebAuthnRegister(el, gon.webauthn);
+ webauthnRegister.start();
+};
diff --git a/app/assets/javascripts/authentication/webauthn/register.js b/app/assets/javascripts/authentication/webauthn/register.js
index 62ebf85abe4..c00d3ede2c1 100644
--- a/app/assets/javascripts/authentication/webauthn/register.js
+++ b/app/assets/javascripts/authentication/webauthn/register.js
@@ -2,6 +2,7 @@ import { __ } from '~/locale';
import WebAuthnError from './error';
import WebAuthnFlow from './flow';
import { supported, isHTTPS, convertCreateParams, convertCreateResponse } from './util';
+import { WEBAUTHN_REGISTER } from './constants';
// Register WebAuthn devices for users to authenticate with.
//
@@ -40,7 +41,7 @@ export default class WebAuthnRegister {
publicKey: this.webauthnOptions,
})
.then((cred) => this.renderRegistered(JSON.stringify(convertCreateResponse(cred))))
- .catch((err) => this.flow.renderError(new WebAuthnError(err, 'register')));
+ .catch((err) => this.flow.renderError(new WebAuthnError(err, WEBAUTHN_REGISTER)));
}
renderSetup() {
diff --git a/app/assets/javascripts/authentication/webauthn/registration.js b/app/assets/javascripts/authentication/webauthn/registration.js
new file mode 100644
index 00000000000..67906a24857
--- /dev/null
+++ b/app/assets/javascripts/authentication/webauthn/registration.js
@@ -0,0 +1,22 @@
+import Vue from 'vue';
+import WebAuthnRegistration from '~/authentication/webauthn/components/registration.vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+
+export const initWebAuthnRegistration = () => {
+ const el = document.querySelector('#js-device-registration');
+
+ if (!el) {
+ return null;
+ }
+
+ const { initialError, passwordRequired, targetPath } = el.dataset;
+
+ return new Vue({
+ el,
+ name: 'WebAuthnRegistrationRoot',
+ provide: { initialError, passwordRequired: parseBoolean(passwordRequired), targetPath },
+ render(h) {
+ return h(WebAuthnRegistration);
+ },
+ });
+};
diff --git a/app/assets/javascripts/authentication/webauthn/util.js b/app/assets/javascripts/authentication/webauthn/util.js
index 2a0740cf488..0ff0f0e6a29 100644
--- a/app/assets/javascripts/authentication/webauthn/util.js
+++ b/app/assets/javascripts/authentication/webauthn/util.js
@@ -1,9 +1,6 @@
export function supported() {
return Boolean(
- navigator.credentials &&
- navigator.credentials.create &&
- navigator.credentials.get &&
- window.PublicKeyCredential,
+ navigator.credentials?.create && navigator.credentials?.get && window.PublicKeyCredential,
);
}
@@ -11,9 +8,6 @@ export function isHTTPS() {
return window.location.protocol.startsWith('https');
}
-export const FLOW_AUTHENTICATE = 'authenticate';
-export const FLOW_REGISTER = 'register';
-
/**
* Converts a base64 string to an ArrayBuffer
*
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index 1855fb9ed8c..de67e01d650 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -7,7 +7,7 @@ import { getEmojiScoreWithIntent } from '~/emoji/utils';
import { getCookie, setCookie, scrollToElement } from '~/lib/utils/common_utils';
import * as Emoji from '~/emoji';
import { dispose, fixTitle } from '~/tooltips';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from './lib/utils/axios_utils';
import { isInVueNoteablePage } from './lib/utils/dom_utils';
import { __ } from './locale';
diff --git a/app/assets/javascripts/badges/components/badge_form.vue b/app/assets/javascripts/badges/components/badge_form.vue
index c95c90d5daf..1a80030c7e6 100644
--- a/app/assets/javascripts/badges/components/badge_form.vue
+++ b/app/assets/javascripts/badges/components/badge_form.vue
@@ -3,7 +3,7 @@ import { GlLoadingIcon, GlFormInput, GlFormGroup, GlButton } from '@gitlab/ui';
import { escape, debounce } from 'lodash';
import { mapActions, mapState } from 'vuex';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { s__, sprintf } from '~/locale';
import createEmptyBadge from '../empty_badge';
import { PLACEHOLDERS } from '../constants';
diff --git a/app/assets/javascripts/badges/components/badge_settings.vue b/app/assets/javascripts/badges/components/badge_settings.vue
index a7a21d65475..09f997d73aa 100644
--- a/app/assets/javascripts/badges/components/badge_settings.vue
+++ b/app/assets/javascripts/badges/components/badge_settings.vue
@@ -1,7 +1,7 @@
<script>
import { GlSprintf, GlModal } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { __, s__ } from '~/locale';
import Badge from './badge.vue';
import BadgeForm from './badge_form.vue';
@@ -26,7 +26,7 @@ export default {
primaryProps() {
return {
text: __('Delete badge'),
- attributes: [{ category: 'primary' }, { variant: 'danger' }],
+ attributes: { category: 'primary', variant: 'danger' },
};
},
cancelProps() {
diff --git a/app/assets/javascripts/batch_comments/components/draft_note.vue b/app/assets/javascripts/batch_comments/components/draft_note.vue
index cc524c71c1e..b78874d372c 100644
--- a/app/assets/javascripts/batch_comments/components/draft_note.vue
+++ b/app/assets/javascripts/batch_comments/components/draft_note.vue
@@ -1,5 +1,5 @@
<script>
-import { GlBadge } from '@gitlab/ui';
+import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import SafeHtml from '~/vue_shared/directives/safe_html';
import NoteableNote from '~/notes/components/noteable_note.vue';
@@ -11,6 +11,7 @@ export default {
},
directives: {
SafeHtml,
+ GlTooltip: GlTooltipDirective,
},
props: {
draft: {
@@ -95,7 +96,15 @@ export default {
@mouseleave.native="handleMouseLeave(draft)"
>
<template #note-header-info>
- <gl-badge variant="warning" class="gl-mr-2">{{ __('Pending') }}</gl-badge>
+ <gl-badge
+ v-gl-tooltip
+ variant="warning"
+ size="sm"
+ class="gl-mr-2"
+ :title="__('Pending comments are hidden until you submit your review.')"
+ >
+ {{ __('Pending') }}
+ </gl-badge>
</template>
<template v-if="!isEditingDraft" #after-note-body>
<div
diff --git a/app/assets/javascripts/batch_comments/components/preview_dropdown.vue b/app/assets/javascripts/batch_comments/components/preview_dropdown.vue
index 4ac0c8c4894..ca9cb03ca37 100644
--- a/app/assets/javascripts/batch_comments/components/preview_dropdown.vue
+++ b/app/assets/javascripts/batch_comments/components/preview_dropdown.vue
@@ -55,21 +55,25 @@ export default {
<template>
<gl-disclosure-dropdown :items="listItems" dropup data-qa-selector="review_preview_dropdown">
<template #toggle>
- <gl-button
- >{{ __('Pending comments') }} <drafts-count variant="neutral" /><gl-icon
- class="dropdown-chevron"
- name="chevron-up"
- /></gl-button>
+ <gl-button>
+ {{ __('Pending comments') }}
+ <drafts-count variant="neutral" />
+ <gl-icon class="dropdown-chevron" name="chevron-up" />
+ </gl-button>
</template>
<template #header>
- <p class="gl-dropdown-header-top">
- {{ n__('%d pending comment', '%d pending comments', draftsCount) }}
- </p>
+ <div
+ class="gl-display-flex gl-align-items-center gl-p-4! gl-min-h-8 gl-border-b-1 gl-border-b-solid gl-border-b-gray-200"
+ >
+ <span class="gl-flex-grow-1 gl-font-weight-bold gl-font-sm gl-pr-2">
+ {{ n__('%d pending comment', '%d pending comments', draftsCount) }}
+ </span>
+ </div>
</template>
<template #list-item="{ item }">
- <preview-item :draft="item" :is-last="item.last" @click="onClickDraft(item)" />
+ <preview-item :draft="item" :is-last="item.last" />
</template>
</gl-disclosure-dropdown>
</template>
diff --git a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
index ed0481e7a48..beda251aa1e 100644
--- a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
+++ b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
@@ -9,7 +9,7 @@ import {
GlFormCheckbox,
} from '@gitlab/ui';
import { mapGetters, mapActions } from 'vuex';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import { scrollToElement } from '~/lib/utils/common_utils';
import Autosave from '~/autosave';
diff --git a/app/assets/javascripts/batch_comments/index.js b/app/assets/javascripts/batch_comments/index.js
index 65fd34dcb00..2a8786134cc 100644
--- a/app/assets/javascripts/batch_comments/index.js
+++ b/app/assets/javascripts/batch_comments/index.js
@@ -1,17 +1,25 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import { mapActions, mapGetters } from 'vuex';
+import { apolloProvider } from '~/graphql_shared/issuable_client';
import store from '~/mr_notes/stores';
export const initReviewBar = () => {
const el = document.getElementById('js-review-bar');
+ Vue.use(VueApollo);
+
// eslint-disable-next-line no-new
new Vue({
el,
store,
+ apolloProvider,
components: {
ReviewBar: () => import('./components/review_bar.vue'),
},
+ provide: {
+ newSavedRepliesPath: el.dataset.savedRepliesNewPath,
+ },
computed: {
...mapGetters('batchComments', ['draftsCount']),
},
diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js
index feac6f10b1e..f6eae7c0c83 100644
--- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js
+++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js
@@ -1,5 +1,5 @@
import { isEmpty } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { scrollToElement } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import { CHANGES_TAB, DISCUSSION_TAB, SHOW_TAB } from '../../../constants';
@@ -167,3 +167,5 @@ export const expandAllDiscussions = ({ dispatch, state }) =>
export const toggleResolveDiscussion = ({ commit }, draftId) => {
commit(types.TOGGLE_RESOLVE_DISCUSSION, draftId);
};
+
+export const clearDrafts = ({ commit }) => commit(types.CLEAR_DRAFTS);
diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js
index df523a692d3..67bcc53ac7d 100644
--- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js
+++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js
@@ -14,3 +14,5 @@ export const RECEIVE_PUBLISH_REVIEW_ERROR = 'RECEIVE_PUBLISH_REVIEW_ERROR';
export const RECEIVE_DRAFT_UPDATE_SUCCESS = 'RECEIVE_DRAFT_UPDATE_SUCCESS';
export const TOGGLE_RESOLVE_DISCUSSION = 'TOGGLE_RESOLVE_DISCUSSION';
+
+export const CLEAR_DRAFTS = 'CLEAR_DRAFTS';
diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js
index dabfe864575..384d7904ac7 100644
--- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js
+++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js
@@ -62,4 +62,7 @@ export default {
return draft;
});
},
+ [types.CLEAR_DRAFTS](state) {
+ state.drafts = [];
+ },
};
diff --git a/app/assets/javascripts/behaviors/copy_code.js b/app/assets/javascripts/behaviors/copy_code.js
index 970864eef74..218a402772f 100644
--- a/app/assets/javascripts/behaviors/copy_code.js
+++ b/app/assets/javascripts/behaviors/copy_code.js
@@ -5,6 +5,8 @@ import { setAttributes } from '~/lib/utils/dom_utils';
class CopyCodeButton extends HTMLElement {
connectedCallback() {
+ if (this.querySelector('.btn')) return;
+
this.for = uniqueId('code-');
const target = this.parentNode.querySelector('pre');
diff --git a/app/assets/javascripts/behaviors/copy_to_clipboard.js b/app/assets/javascripts/behaviors/copy_to_clipboard.js
index 4b337dce8f3..834defe336b 100644
--- a/app/assets/javascripts/behaviors/copy_to_clipboard.js
+++ b/app/assets/javascripts/behaviors/copy_to_clipboard.js
@@ -10,10 +10,10 @@ const CLIPBOARD_ERROR_EVENT = 'clipboard-error';
const I18N_ERROR_MESSAGE = __('Copy failed. Please manually copy the value.');
function showTooltip(target, title) {
- const { title: originalTitle } = target.dataset;
+ const { originalTitle } = target.dataset;
once('hidden', (tooltip) => {
- if (tooltip.target === target) {
+ if (originalTitle && tooltip.target === target) {
target.setAttribute('title', originalTitle);
target.setAttribute('aria-label', originalTitle);
fixTitle(target);
diff --git a/app/assets/javascripts/behaviors/date_picker.js b/app/assets/javascripts/behaviors/date_picker.js
index efd89ec4330..11fe01ca48d 100644
--- a/app/assets/javascripts/behaviors/date_picker.js
+++ b/app/assets/javascripts/behaviors/date_picker.js
@@ -27,7 +27,10 @@ export default function initDatePickers() {
$('.js-clear-due-date,.js-clear-start-date').on('click', (e) => {
e.preventDefault();
- const calendar = $(e.target).siblings('.datepicker').data('pikaday');
+ const calendar = $(e.target)
+ .siblings('.issuable-form-select-holder')
+ .children('.datepicker')
+ .data('pikaday');
calendar.setDate(null);
});
}
diff --git a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
index 19ebab36481..36317444af9 100644
--- a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
@@ -164,7 +164,7 @@ export class CopyAsGFM {
static nodeToGFM(node) {
return Promise.all([
- import(/* webpackChunkName: 'gfm_copy_extra' */ 'prosemirror-model'),
+ import(/* webpackChunkName: 'gfm_copy_extra' */ '@tiptap/pm/model'),
import(/* webpackChunkName: 'gfm_copy_extra' */ './schema'),
import(/* webpackChunkName: 'gfm_copy_extra' */ './serializer'),
])
diff --git a/app/assets/javascripts/behaviors/markdown/render_json_table.js b/app/assets/javascripts/behaviors/markdown/render_json_table.js
index 4d9ac1d266b..aa0e7d38113 100644
--- a/app/assets/javascripts/behaviors/markdown/render_json_table.js
+++ b/app/assets/javascripts/behaviors/markdown/render_json_table.js
@@ -1,7 +1,7 @@
import { memoize } from 'lodash';
import Vue from 'vue';
import { __ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
// Async import component since we might not need it...
const JSONTable = memoize(() =>
diff --git a/app/assets/javascripts/behaviors/markdown/render_observability.js b/app/assets/javascripts/behaviors/markdown/render_observability.js
index 704d85cf22e..6346fb8ab48 100644
--- a/app/assets/javascripts/behaviors/markdown/render_observability.js
+++ b/app/assets/javascripts/behaviors/markdown/render_observability.js
@@ -1,25 +1,19 @@
import Vue from 'vue';
-import { darkModeEnabled } from '~/lib/utils/color_utils';
-import { setUrlParams } from '~/lib/utils/url_utility';
-
-export function getFrameSrc(url) {
- return `${setUrlParams({ theme: darkModeEnabled() ? 'dark' : 'light' }, url)}&kiosk`;
-}
+import ObservabilityApp from '~/observability/components/observability_app.vue';
+import { SKELETON_VARIANT_EMBED, INLINE_EMBED_DIMENSIONS } from '~/observability/constants';
const mountVueComponent = (element) => {
- const url = [element.dataset.frameUrl];
-
+ const url = element.dataset.frameUrl;
return new Vue({
el: element,
render(h) {
- return h('iframe', {
- style: {
- height: '366px',
- width: '768px',
- },
- attrs: {
- src: getFrameSrc(url),
- frameBorder: '0',
+ return h(ObservabilityApp, {
+ props: {
+ observabilityIframeSrc: url,
+ inlineEmbed: true,
+ skeletonVariant: SKELETON_VARIANT_EMBED,
+ height: INLINE_EMBED_DIMENSIONS.HEIGHT,
+ width: INLINE_EMBED_DIMENSIONS.WIDTH,
},
});
},
@@ -27,7 +21,5 @@ const mountVueComponent = (element) => {
};
export default function renderObservability(elements) {
- elements.forEach((element) => {
- mountVueComponent(element);
- });
+ return elements.map(mountVueComponent);
}
diff --git a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
index 66007aa9e3d..bd9e41ac0ba 100644
--- a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
@@ -8,7 +8,7 @@ import {
} from '~/lib/utils/url_utility';
import { darkModeEnabled } from '~/lib/utils/color_utils';
import { setAttributes, isElementVisible } from '~/lib/utils/dom_utils';
-import { createAlert, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/alert';
import { unrestrictedPages } from './constants';
// Renders diagrams and flowcharts from text using Mermaid in any element with the
diff --git a/app/assets/javascripts/behaviors/markdown/schema.js b/app/assets/javascripts/behaviors/markdown/schema.js
index 1b0f46ff4cb..31bab23c8b0 100644
--- a/app/assets/javascripts/behaviors/markdown/schema.js
+++ b/app/assets/javascripts/behaviors/markdown/schema.js
@@ -1,4 +1,4 @@
-import { Schema } from 'prosemirror-model';
+import { Schema } from '@tiptap/pm/model';
import editorExtensions from './editor_extensions';
const nodes = editorExtensions.nodes.reduce(
diff --git a/app/assets/javascripts/behaviors/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js
index 32e395e4f3c..dc408f5a950 100644
--- a/app/assets/javascripts/behaviors/preview_markdown.js
+++ b/app/assets/javascripts/behaviors/preview_markdown.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/behaviors/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts.js
index 12fdb2e2981..22a8be92e52 100644
--- a/app/assets/javascripts/behaviors/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts.js
@@ -26,12 +26,10 @@ export default function initPageShortcuts() {
// the pages above have their own shortcuts sub-classes instantiated elsewhere
// TODO: replace this whitelist with something more automated/maintainable
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/392845
if (page && !pagesWithCustomShortcuts.includes(page)) {
import(/* webpackChunkName: 'shortcutsBundle' */ './shortcuts/shortcuts')
- .then(({ default: Shortcuts }) => {
- const shortcuts = new Shortcuts();
- window.toggleShortcutsHelp = shortcuts.onToggleHelp;
- })
+ .then(({ default: Shortcuts }) => new Shortcuts())
.catch(() => {});
}
return false;
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 7a1577e97d5..6a7ce4f1c41 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -124,8 +124,11 @@ export default class Shortcuts {
e.preventDefault();
});
+ const shortcutsModalTriggerEvent = 'click.shortcutsModalTrigger';
// eslint-disable-next-line @gitlab/no-global-event-off
- $('.js-shortcuts-modal-trigger').off('click').on('click', this.onToggleHelp);
+ $(document)
+ .off(shortcutsModalTriggerEvent)
+ .on(shortcutsModalTriggerEvent, '.js-shortcuts-modal-trigger', this.onToggleHelp);
if (shouldDisableShortcuts()) {
disableShortcuts();
diff --git a/app/assets/javascripts/blame/blame_redirect.js b/app/assets/javascripts/blame/blame_redirect.js
index 155e2a3a2cd..f528fdb1f69 100644
--- a/app/assets/javascripts/blame/blame_redirect.js
+++ b/app/assets/javascripts/blame/blame_redirect.js
@@ -1,5 +1,5 @@
import { setUrlParams } from '~/lib/utils/url_utility';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
export default function redirectToCorrectBlamePage() {
diff --git a/app/assets/javascripts/blame/streaming/index.js b/app/assets/javascripts/blame/streaming/index.js
new file mode 100644
index 00000000000..935343cca2e
--- /dev/null
+++ b/app/assets/javascripts/blame/streaming/index.js
@@ -0,0 +1,56 @@
+import { renderHtmlStreams } from '~/streaming/render_html_streams';
+import { handleStreamedAnchorLink } from '~/streaming/handle_streamed_anchor_link';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { rateLimitStreamRequests } from '~/streaming/rate_limit_stream_requests';
+import { toPolyfillReadable } from '~/streaming/polyfills';
+
+export async function renderBlamePageStreams(firstStreamPromise) {
+ const element = document.querySelector('#blame-stream-container');
+
+ if (!element || !firstStreamPromise) return;
+
+ const stopAnchorObserver = handleStreamedAnchorLink(element);
+ const { dataset } = document.querySelector('#blob-content-holder');
+ const totalExtraPages = parseInt(dataset.totalExtraPages, 10);
+ const { pagesUrl } = dataset;
+
+ const remainingStreams = rateLimitStreamRequests({
+ factory: (index) => {
+ const url = new URL(pagesUrl);
+ // page numbers start with 1
+ // the first page is already rendered in the document
+ // the second page is passed with the 'firstStreamPromise'
+ url.searchParams.set('page', index + 3);
+ return fetch(url).then((response) => toPolyfillReadable(response.body));
+ },
+ // we don't want to overload gitaly with concurrent requests
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/391842#note_1281695095
+ // using 5 as a good starting point
+ maxConcurrentRequests: 5,
+ total: totalExtraPages,
+ });
+
+ try {
+ await renderHtmlStreams(
+ [firstStreamPromise.then(toPolyfillReadable), ...remainingStreams],
+ element,
+ );
+ } catch (error) {
+ createAlert({
+ message: __('Blame could not be loaded as a single page.'),
+ primaryButton: {
+ text: __('View blame as separate pages'),
+ clickHandler() {
+ const newUrl = new URL(window.location);
+ newUrl.searchParams.delete('streaming');
+ window.location.href = newUrl;
+ },
+ },
+ });
+ throw error;
+ } finally {
+ stopAnchorObserver();
+ document.querySelector('#blame-stream-loading').remove();
+ }
+}
diff --git a/app/assets/javascripts/blob/csv/index.js b/app/assets/javascripts/blob/csv/index.js
index 4cf6c169c68..ed8e1ffa318 100644
--- a/app/assets/javascripts/blob/csv/index.js
+++ b/app/assets/javascripts/blob/csv/index.js
@@ -10,6 +10,7 @@ export default () => {
return createElement(CsvViewer, {
props: {
csv: el.dataset.data,
+ remoteFile: true,
},
});
},
diff --git a/app/assets/javascripts/blob/file_template_mediator.js b/app/assets/javascripts/blob/file_template_mediator.js
index 2ea3c93625d..7ccb66f18a9 100644
--- a/app/assets/javascripts/blob/file_template_mediator.js
+++ b/app/assets/javascripts/blob/file_template_mediator.js
@@ -2,7 +2,7 @@ import $ from 'jquery';
import Api from '~/api';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import toast from '~/vue_shared/plugins/global_toast';
diff --git a/app/assets/javascripts/blob/notebook/notebook_viewer.vue b/app/assets/javascripts/blob/notebook/notebook_viewer.vue
index ade92f2562b..acbd231c94a 100644
--- a/app/assets/javascripts/blob/notebook/notebook_viewer.vue
+++ b/app/assets/javascripts/blob/notebook/notebook_viewer.vue
@@ -83,4 +83,9 @@ export default {
.output img {
min-width: 0; /* https://www.w3.org/TR/css-flexbox-1/#min-size-auto */
}
+
+.output .markdown {
+ display: block;
+ width: 100%;
+}
</style>
diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js
index 5e85e4cea38..bdaefe8383c 100644
--- a/app/assets/javascripts/blob/viewer/index.js
+++ b/app/assets/javascripts/blob/viewer/index.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import {
REPO_BLOB_LOAD_VIEWER_START,
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index 509d399273d..01d35a0980f 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { setCookie } from '~/lib/utils/common_utils';
import Tracking from '~/tracking';
import NewCommitForm from '../new_commit_form';
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index a3d11d90ed2..f021553ae98 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -4,7 +4,7 @@ import { SourceEditorExtension } from '~/editor/extensions/source_editor_extensi
import { FileTemplateExtension } from '~/editor/extensions/source_editor_file_template_ext';
import { ToolbarExtension } from '~/editor/extensions/source_editor_toolbar_ext';
import SourceEditor from '~/editor/source_editor';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
import { insertFinalNewline } from '~/lib/utils/text_utility';
@@ -68,9 +68,9 @@ export default class EditBlob {
blobContent: editorEl.innerText,
});
this.editor.use([
+ { definition: ToolbarExtension },
{ definition: SourceEditorExtension },
{ definition: FileTemplateExtension },
- { definition: ToolbarExtension },
]);
fileNameEl.addEventListener('change', () => {
diff --git a/app/assets/javascripts/boards/components/board_add_new_column.vue b/app/assets/javascripts/boards/components/board_add_new_column.vue
index c5411ec313a..90f7059da86 100644
--- a/app/assets/javascripts/boards/components/board_add_new_column.vue
+++ b/app/assets/javascripts/boards/components/board_add_new_column.vue
@@ -1,13 +1,24 @@
<script>
-import { GlFormRadio, GlFormRadioGroup, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
+import {
+ GlTooltipDirective as GlTooltip,
+ GlButton,
+ GlCollapsibleListbox,
+ GlIcon,
+} from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form.vue';
+import { __ } from '~/locale';
export default {
+ i18n: {
+ value: __('Value'),
+ noResults: __('No matching results'),
+ },
components: {
BoardAddNewColumnForm,
- GlFormRadio,
- GlFormRadioGroup,
+ GlButton,
+ GlCollapsibleListbox,
+ GlIcon,
},
directives: {
GlTooltip,
@@ -17,6 +28,7 @@ export default {
return {
selectedId: null,
selectedLabel: null,
+ selectedIdValid: true,
};
},
computed: {
@@ -25,6 +37,15 @@ export default {
columnForSelected() {
return this.getListByLabelId(this.selectedId);
},
+ items() {
+ return (
+ this.labels.map((i) => ({
+ ...i,
+ text: i.title,
+ value: i.id,
+ })) || []
+ );
+ },
},
created() {
this.filterItems();
@@ -33,6 +54,7 @@ export default {
...mapActions(['createList', 'fetchLabels', 'highlightList', 'setAddColumnFormVisibility']),
addList() {
if (!this.selectedLabel) {
+ this.selectedIdValid = false;
return;
}
@@ -61,53 +83,67 @@ export default {
this.selectedLabel = { ...label };
}
},
+ onHide() {
+ this.searchValue = '';
+ this.$emit('filter-items', '');
+ this.$emit('hide');
+ },
},
};
</script>
<template>
<board-add-new-column-form
- :loading="labelsLoading"
- :none-selected="__('Select a label')"
- :search-placeholder="__('Search labels')"
- :selected-id="selectedId"
+ :selected-id-valid="selectedIdValid"
@filter-items="filterItems"
@add-list="addList"
>
- <template #selected>
- <template v-if="selectedLabel">
- <span
- class="dropdown-label-box gl-top-0 gl-flex-shrink-0"
- :style="{
- backgroundColor: selectedLabel.color,
- }"
- ></span>
- <div class="gl-text-truncate">{{ selectedLabel.title }}</div>
- </template>
- </template>
-
- <template #items>
- <gl-form-radio-group
- v-if="labels.length > 0"
- class="gl-overflow-y-auto gl-px-5 gl-pt-3"
- :checked="selectedId"
- @change="setSelectedItem"
+ <template #dropdown>
+ <gl-collapsible-listbox
+ class="gl-mb-3 gl-max-w-full"
+ :items="items"
+ searchable
+ :search-placeholder="__('Search labels')"
+ :searching="labelsLoading"
+ :selected="selectedId"
+ :no-results-text="$options.i18n.noResults"
+ @select="setSelectedItem"
+ @search="filterItems"
+ @hidden="onHide"
>
- <label
- v-for="label in labels"
- :key="label.id"
- class="gl-display-flex gl-mb-5 gl-font-weight-normal gl-overflow-break-word"
- >
- <gl-form-radio :value="label.id" />
- <span
- class="dropdown-label-box gl-top-0 gl-flex-shrink-0"
- :style="{
- backgroundColor: label.color,
- }"
- ></span>
- <span>{{ label.title }}</span>
- </label>
- </gl-form-radio-group>
+ <template #toggle>
+ <gl-button
+ class="gl-max-w-full gl-display-flex gl-align-items-center gl-text-truncate"
+ :class="{ 'gl-inset-border-1-red-400!': !selectedIdValid }"
+ button-text-classes="gl-display-flex"
+ >
+ <template v-if="selectedLabel">
+ <span
+ class="dropdown-label-box gl-top-0 gl-flex-shrink-0"
+ :style="{
+ backgroundColor: selectedLabel.color,
+ }"
+ ></span>
+ <div class="gl-text-truncate">{{ selectedLabel.title }}</div>
+ </template>
+
+ <template v-else>{{ __('Select a label') }}</template>
+ <gl-icon class="dropdown-chevron gl-ml-2" name="chevron-down" />
+ </gl-button>
+ </template>
+
+ <template #list-item="{ item }">
+ <label class="gl-display-flex gl-font-weight-normal gl-overflow-break-word gl-mb-0">
+ <span
+ class="dropdown-label-box gl-top-0 gl-flex-shrink-0"
+ :style="{
+ backgroundColor: item.color,
+ }"
+ ></span>
+ <span>{{ item.title }}</span>
+ </label>
+ </template>
+ </gl-collapsible-listbox>
</template>
</board-add-new-column-form>
</template>
diff --git a/app/assets/javascripts/boards/components/board_add_new_column_form.vue b/app/assets/javascripts/boards/components/board_add_new_column_form.vue
index 1899d42fa4d..259423df07f 100644
--- a/app/assets/javascripts/boards/components/board_add_new_column_form.vue
+++ b/app/assets/javascripts/boards/components/board_add_new_column_form.vue
@@ -1,12 +1,5 @@
<script>
-import {
- GlButton,
- GlDropdown,
- GlFormGroup,
- GlIcon,
- GlSearchBoxByType,
- GlSkeletonLoader,
-} from '@gitlab/ui';
+import { GlButton, GlFormGroup } from '@gitlab/ui';
import { mapActions } from 'vuex';
import { __ } from '~/locale';
@@ -15,81 +8,34 @@ export default {
add: __('Add to board'),
cancel: __('Cancel'),
newList: __('New list'),
- noResults: __('No matching results'),
scope: __('Scope'),
scopeDescription: __('Issues must match this scope to appear in this list.'),
- selected: __('Selected'),
requiredFieldFeedback: __('This field is required.'),
},
components: {
GlButton,
- GlDropdown,
GlFormGroup,
- GlIcon,
- GlSearchBoxByType,
- GlSkeletonLoader,
},
props: {
- loading: {
- type: Boolean,
- required: true,
- },
searchLabel: {
type: String,
required: false,
default: null,
},
- noneSelected: {
- type: String,
- required: true,
- },
- searchPlaceholder: {
- type: String,
+ selectedIdValid: {
+ type: Boolean,
required: true,
},
- selectedId: {
- type: [Number, String],
- required: false,
- default: null,
- },
},
data() {
return {
searchValue: '',
- selectedIdValid: true,
};
},
- computed: {
- toggleClassList() {
- return `gl-max-w-full gl-display-flex gl-align-items-center gl-text-trunate ${
- this.selectedIdValid ? '' : 'gl-inset-border-1-red-400!'
- }`;
- },
- },
- watch: {
- selectedId(val) {
- if (val) {
- this.$refs.dropdown.hide(true);
- this.selectedIdValid = true;
- }
- },
- },
methods: {
...mapActions(['setAddColumnFormVisibility']),
- setFocus() {
- this.$refs.searchBox.focusInput();
- },
- onHide() {
- this.searchValue = '';
- this.$emit('filter-items', '');
- this.$emit('hide');
- },
onSubmit() {
- if (!this.selectedId) {
- this.selectedIdValid = false;
- } else {
- this.$emit('add-list');
- }
+ this.$emit('add-list');
},
},
};
@@ -126,44 +72,7 @@ export default {
:state="selectedIdValid"
:invalid-feedback="$options.i18n.requiredFieldFeedback"
>
- <gl-dropdown
- ref="dropdown"
- class="gl-mb-3 gl-max-w-full"
- :toggle-class="toggleClassList"
- boundary="viewport"
- @shown="setFocus"
- @hide="onHide"
- >
- <template #button-content>
- <slot name="selected">
- <div>{{ noneSelected }}</div>
- </slot>
- <gl-icon class="dropdown-chevron gl-flex-shrink-0" name="chevron-down" />
- </template>
-
- <template #header>
- <gl-search-box-by-type
- ref="searchBox"
- v-model="searchValue"
- debounce="250"
- class="gl-mt-0!"
- :placeholder="searchPlaceholder"
- @input="$emit('filter-items', $event)"
- />
- </template>
-
- <div v-if="loading" class="gl-px-5">
- <gl-skeleton-loader :width="400" :height="172">
- <rect width="380" height="20" x="10" y="15" rx="4" />
- <rect width="280" height="20" x="10" y="50" rx="4" />
- <rect width="330" height="20" x="10" y="85" rx="4" />
- </gl-skeleton-loader>
- </div>
-
- <slot v-else name="items">
- <p class="gl-mx-5">{{ $options.i18n.noResults }}</p>
- </slot>
- </gl-dropdown>
+ <slot name="dropdown"></slot>
</gl-form-group>
</div>
<div class="gl-display-flex gl-mb-4">
diff --git a/app/assets/javascripts/boards/components/board_app.vue b/app/assets/javascripts/boards/components/board_app.vue
index d41fc1e9300..48dfcf81f1e 100644
--- a/app/assets/javascripts/boards/components/board_app.vue
+++ b/app/assets/javascripts/boards/components/board_app.vue
@@ -1,6 +1,6 @@
<script>
import { mapGetters } from 'vuex';
-import { refreshCurrentPage } from '~/lib/utils/url_utility';
+import { refreshCurrentPage, queryToObject } from '~/lib/utils/url_utility';
import BoardContent from '~/boards/components/board_content.vue';
import BoardSettingsSidebar from '~/boards/components/board_settings_sidebar.vue';
import BoardTopBar from '~/boards/components/board_top_bar.vue';
@@ -11,14 +11,19 @@ export default {
BoardSettingsSidebar,
BoardTopBar,
},
- inject: ['initialBoardId'],
+ inject: ['initialBoardId', 'initialFilterParams'],
data() {
return {
boardId: this.initialBoardId,
+ filterParams: { ...this.initialFilterParams },
+ isShowingEpicsSwimlanes: Boolean(queryToObject(window.location.search).group_by),
};
},
computed: {
...mapGetters(['isSidebarOpen']),
+ isSwimlanesOn() {
+ return (gon?.licensed_features?.swimlanes && this.isShowingEpicsSwimlanes) ?? false;
+ },
},
created() {
window.addEventListener('popstate', refreshCurrentPage);
@@ -30,14 +35,29 @@ export default {
switchBoard(id) {
this.boardId = id;
},
+ setFilters(filters) {
+ const filterParams = { ...filters };
+ if (filterParams.groupBy) delete filterParams.groupBy;
+ this.filterParams = filterParams;
+ },
},
};
</script>
<template>
<div class="boards-app gl-relative" :class="{ 'is-compact': isSidebarOpen }">
- <board-top-bar :board-id="boardId" @switchBoard="switchBoard" />
- <board-content :board-id="boardId" />
+ <board-top-bar
+ :board-id="boardId"
+ :is-swimlanes-on="isSwimlanesOn"
+ @switchBoard="switchBoard"
+ @setFilters="setFilters"
+ @toggleSwimlanes="isShowingEpicsSwimlanes = $event"
+ />
+ <board-content
+ :board-id="boardId"
+ :is-swimlanes-on="isSwimlanesOn"
+ :filter-params="filterParams"
+ />
<board-settings-sidebar />
</div>
</template>
diff --git a/app/assets/javascripts/boards/components/board_column.vue b/app/assets/javascripts/boards/components/board_column.vue
index 708e1539c6e..83ba538168a 100644
--- a/app/assets/javascripts/boards/components/board_column.vue
+++ b/app/assets/javascripts/boards/components/board_column.vue
@@ -20,6 +20,10 @@ export default {
type: String,
required: true,
},
+ filters: {
+ type: Object,
+ required: true,
+ },
},
computed: {
...mapState(['filterParams', 'highlightedLists']),
@@ -33,11 +37,14 @@ export default {
isListDraggable() {
return isListDraggable(this.list);
},
+ filtersToUse() {
+ return this.isApolloBoard ? this.filters : this.filterParams;
+ },
},
watch: {
filterParams: {
handler() {
- if (this.list.id && !this.list.collapsed) {
+ if (!this.isApolloBoard && this.list.id && !this.list.collapsed) {
this.fetchItemsForList({ listId: this.list.id });
}
},
@@ -46,7 +53,7 @@ export default {
},
'list.id': {
handler(id) {
- if (id) {
+ if (!this.isApolloBoard && id) {
this.fetchItemsForList({ listId: this.list.id });
}
},
@@ -83,13 +90,13 @@ export default {
class="board-inner gl-display-flex gl-flex-direction-column gl-relative gl-h-full gl-rounded-base gl-bg-gray-50"
:class="{ 'board-column-highlighted': highlighted }"
>
- <board-list-header :list="list" />
+ <board-list-header :list="list" :filter-params="filtersToUse" />
<board-list
ref="board-list"
:board-id="boardId"
:board-items="listItems"
:list="list"
- :filter-params="filterParams"
+ :filter-params="filtersToUse"
/>
</div>
</div>
diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue
index 8a37719eae8..84a8781db1c 100644
--- a/app/assets/javascripts/boards/components/board_content.vue
+++ b/app/assets/javascripts/boards/components/board_content.vue
@@ -3,9 +3,10 @@ import { GlAlert } from '@gitlab/ui';
import { breakpoints } from '@gitlab/ui/dist/utils';
import { sortBy, throttle } from 'lodash';
import Draggable from 'vuedraggable';
-import { mapState, mapGetters, mapActions } from 'vuex';
+import { mapState, mapActions } from 'vuex';
import { contentTop } from '~/lib/utils/common_utils';
import { s__ } from '~/locale';
+import eventHub from '~/boards/eventhub';
import { formatBoardLists } from 'ee_else_ce/boards/boards_util';
import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column.vue';
import { defaultSortableOptions } from '~/sortable/constants';
@@ -44,6 +45,14 @@ export default {
type: String,
required: true,
},
+ filterParams: {
+ type: Object,
+ required: true,
+ },
+ isSwimlanesOn: {
+ type: Boolean,
+ required: true,
+ },
},
data() {
return {
@@ -80,7 +89,6 @@ export default {
},
computed: {
...mapState(['boardLists', 'error', 'addColumnForm']),
- ...mapGetters(['isSwimlanesOn']),
addColumnFormVisible() {
return this.addColumnForm?.visible;
},
@@ -92,7 +100,7 @@ export default {
}),
fullPath: this.fullPath,
boardId: this.boardId,
- filterParams: this.filterParams,
+ filters: this.filterParams,
};
},
boardListsToUse() {
@@ -126,6 +134,12 @@ export default {
return this.isApolloBoard ? this.apolloError : this.error;
},
},
+ created() {
+ eventHub.$on('updateBoard', this.refetchLists);
+ },
+ beforeDestroy() {
+ eventHub.$off('updateBoard', this.refetchLists);
+ },
mounted() {
this.setBoardHeight();
@@ -152,6 +166,9 @@ export default {
this.boardHeight = `${window.innerHeight - this.$el.getBoundingClientRect().top}px`;
}
},
+ refetchLists() {
+ this.$apollo.queries.boardListsApollo.refetch();
+ },
},
};
</script>
@@ -176,6 +193,7 @@ export default {
ref="board"
:board-id="boardId"
:list="list"
+ :filters="filterParams"
:data-draggable-item-type="$options.draggableItemTypes.list"
:class="{ 'gl-xs-display-none!': addColumnFormVisible }"
/>
@@ -190,6 +208,7 @@ export default {
ref="swimlanes"
:lists="boardListsToUse"
:can-admin-list="canAdminList"
+ :filters="filterParams"
:style="{ height: boardHeight }"
/>
diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue
index 6227f185eda..675878683ab 100644
--- a/app/assets/javascripts/boards/components/board_content_sidebar.vue
+++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue
@@ -6,9 +6,9 @@ import SidebarDropdownWidget from 'ee_else_ce/sidebar/components/sidebar_dropdow
import { __, sprintf } from '~/locale';
import BoardSidebarTimeTracker from '~/boards/components/sidebar/board_sidebar_time_tracker.vue';
import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
-import { BoardType, ISSUABLE, INCIDENT } from '~/boards/constants';
+import { ISSUABLE, INCIDENT } from '~/boards/constants';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
import SidebarDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue';
@@ -16,7 +16,6 @@ import SidebarSeverityWidget from '~/sidebar/components/severity/sidebar_severit
import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue';
import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue';
import SidebarLabelsWidget from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue';
-import { LabelType } from '~/sidebar/components/labels/labels_select_widget/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
@@ -98,7 +97,7 @@ export default {
return this.activeBoardItem?.referencePath?.split('#')[0] || '';
},
parentType() {
- return this.isGroupBoard ? BoardType.group : BoardType.project;
+ return this.isGroupBoard ? WORKSPACE_GROUP : WORKSPACE_PROJECT;
},
createLabelTitle() {
return sprintf(__('Create %{workspace} label'), {
@@ -114,7 +113,7 @@ export default {
return this.isGroupBoard ? this.groupPathForActiveIssue : this.projectPathForActiveIssue;
},
labelType() {
- return this.isGroupBoard ? LabelType.group : LabelType.project;
+ return this.isGroupBoard ? WORKSPACE_GROUP : WORKSPACE_PROJECT;
},
labelsFilterPath() {
return this.isGroupBoard
diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue
index 1bc5d910561..2e14afad963 100644
--- a/app/assets/javascripts/boards/components/board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/board_filtered_search.vue
@@ -1,7 +1,7 @@
<script>
import { pickBy, isEmpty, mapValues } from 'lodash';
import { mapActions } from 'vuex';
-import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
+import { getIdFromGraphQLId, isGid, convertToGraphQLId } from '~/graphql_shared/utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { updateHistory, setUrlParams, queryToObject } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -23,6 +23,7 @@ import {
} from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import { AssigneeFilterType } from '~/boards/constants';
+import { TYPENAME_ITERATION } from '~/graphql_shared/constants';
import eventHub from '../eventhub';
export default {
@@ -30,7 +31,7 @@ export default {
search: __('Search'),
},
components: { FilteredSearch },
- inject: ['initialFilterParams'],
+ inject: ['initialFilterParams', 'isApolloBoard'],
props: {
tokens: {
type: Array,
@@ -334,11 +335,23 @@ export default {
},
);
},
+ formattedFilterParams() {
+ const filtersCopy = { ...this.filterParams };
+ if (this.filterParams?.iterationId) {
+ filtersCopy.iterationId = convertToGraphQLId(
+ TYPENAME_ITERATION,
+ this.filterParams.iterationId,
+ );
+ }
+
+ return filtersCopy;
+ },
},
created() {
eventHub.$on('updateTokens', this.updateTokens);
if (!isEmpty(this.eeFilters)) {
this.filterParams = this.eeFilters;
+ this.$emit('setFilters', this.formattedFilterParams);
}
},
beforeDestroy() {
@@ -349,6 +362,7 @@ export default {
updateTokens() {
const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true });
this.filterParams = convertObjectPropsToCamelCase(rawFilterParams, {});
+ this.$emit('setFilters', this.formattedFilterParams);
this.filteredSearchKey += 1;
},
handleFilter(filters) {
@@ -360,7 +374,11 @@ export default {
replace: true,
});
- this.performSearch();
+ if (this.isApolloBoard) {
+ this.$emit('setFilters', this.formattedFilterParams);
+ } else {
+ this.performSearch();
+ }
},
getFilterParams(filters = []) {
const notFilters = filters.filter((item) => item.value.operator === '!=');
diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue
index a71bde54a8f..9ea801dc9a2 100644
--- a/app/assets/javascripts/boards/components/board_form.vue
+++ b/app/assets/javascripts/boards/components/board_form.vue
@@ -4,6 +4,7 @@ import { mapActions, mapState } from 'vuex';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { visitUrl, updateHistory, getParameterByName } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
+import eventHub from '~/boards/eventhub';
import { formType } from '../constants';
import createBoardMutation from '../graphql/board_create.mutation.graphql';
@@ -57,6 +58,9 @@ export default {
isProjectBoard: {
default: false,
},
+ isApolloBoard: {
+ default: false,
+ },
},
props: {
canAdminBoard: {
@@ -124,14 +128,12 @@ export default {
primaryProps() {
return {
text: this.buttonText,
- attributes: [
- {
- variant: this.buttonKind,
- disabled: this.submitDisabled,
- loading: this.isLoading,
- 'data-qa-selector': 'save_changes_button',
- },
- ],
+ attributes: {
+ variant: this.buttonKind,
+ disabled: this.submitDisabled,
+ loading: this.isLoading,
+ 'data-qa-selector': 'save_changes_button',
+ },
};
},
cancelProps() {
@@ -213,13 +215,23 @@ export default {
} else {
try {
const board = await this.createOrUpdateBoard();
- this.setBoard(board);
+ if (this.isApolloBoard) {
+ if (this.board.id) {
+ eventHub.$emit('updateBoard', board);
+ } else {
+ this.$emit('addBoard', board);
+ }
+ } else {
+ this.setBoard(board);
+ }
this.cancel();
- const param = getParameterByName('group_by')
- ? `?group_by=${getParameterByName('group_by')}`
- : '';
- updateHistory({ url: `${this.boardBaseUrl}/${getIdFromGraphQLId(board.id)}${param}` });
+ if (!this.isApolloBoard) {
+ const param = getParameterByName('group_by')
+ ? `?group_by=${getParameterByName('group_by')}`
+ : '';
+ updateHistory({ url: `${this.boardBaseUrl}/${getIdFromGraphQLId(board.id)}${param}` });
+ }
} catch {
this.setError({ message: this.$options.i18n.saveErrorMessage });
} finally {
@@ -278,7 +290,7 @@ export default {
@hide.prevent
>
<gl-alert
- v-if="error"
+ v-if="!isApolloBoard && error"
class="gl-mb-3"
variant="danger"
:dismissible="true"
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index 6f2b35f5191..a47db661445 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -59,6 +59,10 @@ export default {
type: Array,
required: true,
},
+ filterParams: {
+ type: Object,
+ required: true,
+ },
},
data() {
return {
@@ -108,7 +112,7 @@ export default {
},
},
computed: {
- ...mapState(['pageInfoByListId', 'listsFlags', 'filterParams', 'isUpdateIssueOrderInProgress']),
+ ...mapState(['pageInfoByListId', 'listsFlags', 'isUpdateIssueOrderInProgress']),
boardListItems() {
return this.isApolloBoard
? this.currentList?.[`${this.issuableType}s`].nodes || []
@@ -125,7 +129,7 @@ export default {
};
},
listItemsCount() {
- return this.isEpicBoard ? this.list.epicsCount : this.boardList?.issuesCount;
+ return this.isEpicBoard ? this.list.metadata.epicsCount : this.boardList?.issuesCount;
},
paginatedIssueText() {
return sprintf(__('Showing %{pageSize} of %{total} %{issuableType}'), {
@@ -260,6 +264,10 @@ export default {
this.showIssueForm = !this.showIssueForm;
}
},
+ isObservableItem(index) {
+ // observe every 6 item of 10 to achieve smooth loading state
+ return index !== 0 && index % 6 === 0;
+ },
onReachingListBottom() {
if (!this.loadingMore && this.hasNextPage) {
this.showCount = true;
@@ -393,8 +401,14 @@ export default {
:list="list"
:list-items-length="boardListItems.length"
/>
+ <gl-intersection-observer
+ v-if="isObservableItem(index)"
+ data-testid="board-card-gl-io"
+ @appear="onReachingListBottom"
+ />
</board-card>
- <gl-intersection-observer @appear="onReachingListBottom">
+ <div>
+ <!-- for supporting previous structure with intersection observer -->
<li
v-if="showCount"
class="board-list-count gl-text-center gl-text-secondary gl-py-4"
@@ -409,7 +423,7 @@ export default {
<span v-if="showingAllItems">{{ showingAllItemsText }}</span>
<span v-else>{{ paginatedIssueText }}</span>
</li>
- </gl-intersection-observer>
+ </div>
</component>
</div>
</template>
diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue
index 749fae0c426..f4358315d45 100644
--- a/app/assets/javascripts/boards/components/board_list_header.vue
+++ b/app/assets/javascripts/boards/components/board_list_header.vue
@@ -1,18 +1,18 @@
<script>
import {
GlButton,
- GlButtonGroup,
GlLabel,
GlTooltip,
GlIcon,
GlSprintf,
GlTooltipDirective,
+ GlDisclosureDropdown,
} from '@gitlab/ui';
-import { mapActions, mapGetters, mapState } from 'vuex';
+import { mapActions, mapState } from 'vuex';
import { isListDraggable } from '~/boards/boards_util';
import { isScopedLabel, parseBoolean } from '~/lib/utils/common_utils';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
-import { n__, s__, __ } from '~/locale';
+import { n__, s__ } from '~/locale';
import sidebarEventHub from '~/sidebar/event_hub';
import Tracking from '~/tracking';
import { formatDate } from '~/lib/utils/datetime_utility';
@@ -25,14 +25,15 @@ import ItemCount from './item_count.vue';
export default {
i18n: {
- newIssue: __('New issue'),
- newEpic: s__('Boards|New epic'),
- listSettings: __('List settings'),
+ newIssue: s__('Boards|Create new issue'),
+ listActions: s__('Boards|List actions'),
+ newEpic: s__('Boards|Create new epic'),
+ listSettings: s__('Boards|Edit list settings'),
expand: s__('Boards|Expand'),
collapse: s__('Boards|Collapse'),
},
components: {
- GlButtonGroup,
+ GlDisclosureDropdown,
GlButton,
GlLabel,
GlTooltip,
@@ -75,16 +76,22 @@ export default {
required: false,
default: false,
},
+ filterParams: {
+ type: Object,
+ required: true,
+ },
},
computed: {
- ...mapState(['activeId', 'filterParams', 'boardId']),
- ...mapGetters(['isSwimlanesOn']),
+ ...mapState(['activeId', 'boardId']),
isLoggedIn() {
return Boolean(this.currentUserId);
},
listType() {
return this.list.listType;
},
+ itemsCount() {
+ return this.isEpicBoard ? this.list.metadata.epicsCount : this.boardList?.issuesCount;
+ },
listAssignee() {
return this.list?.assignee?.username || '';
},
@@ -111,7 +118,10 @@ export default {
},
showListHeaderActions() {
if (this.isLoggedIn) {
- return this.isNewIssueShown || this.isNewEpicShown || this.isSettingsShown;
+ return (
+ (this.isNewIssueShown || this.isNewEpicShown || this.isSettingsShown) &&
+ !this.list.collapsed
+ );
}
return false;
},
@@ -162,6 +172,50 @@ export default {
canShowTotalWeight() {
return this.weightFeatureAvailable && !this.isLoading;
},
+ actionListItems() {
+ const items = [];
+
+ if (this.isNewIssueShown) {
+ const newIssueText = this.$options.i18n.newIssue;
+ items.push({
+ text: newIssueText,
+ action: this.showNewIssueForm,
+ extraAttrs: {
+ 'data-testid': 'newIssueBtn',
+ title: newIssueText,
+ 'aria-label': newIssueText,
+ },
+ });
+ }
+
+ if (this.isNewEpicShown) {
+ const newEpicText = this.$options.i18n.newEpic;
+ items.push({
+ text: newEpicText,
+ action: this.showNewEpicForm,
+ extraAttrs: {
+ 'data-testid': 'newEpicBtn',
+ title: newEpicText,
+ 'aria-label': newEpicText,
+ },
+ });
+ }
+
+ if (this.isSettingsShown) {
+ const listSettingsText = this.$options.i18n.listSettings;
+ items.push({
+ text: listSettingsText,
+ action: this.openSidebarSettings,
+ extraAttrs: {
+ 'data-testid': 'settingsBtn',
+ title: listSettingsText,
+ 'aria-label': listSettingsText,
+ },
+ });
+ }
+
+ return items;
+ },
},
apollo: {
boardList: {
@@ -188,6 +242,9 @@ export default {
},
methods: {
...mapActions(['updateList', 'setActiveId', 'toggleListCollapsed']),
+ closeListActions() {
+ this.$refs.headerListActions?.close();
+ },
openSidebarSettings() {
if (this.activeId === inactiveId) {
sidebarEventHub.$emit('sidebar.closeAll');
@@ -196,13 +253,14 @@ export default {
this.setActiveId({ id: this.list.id, sidebarType: LIST });
this.track('click_button', { label: 'list_settings' });
+
+ this.closeListActions();
},
showScopedLabels(label) {
return this.scopedLabelsAvailable && isScopedLabel(label);
},
-
showNewIssueForm() {
- if (this.isSwimlanesOn) {
+ if (this.isSwimlanesHeader) {
eventHub.$emit('open-unassigned-lane');
this.$nextTick(() => {
eventHub.$emit(`${toggleFormEventPrefix.issue}${this.list.id}`);
@@ -210,9 +268,13 @@ export default {
} else {
eventHub.$emit(`${toggleFormEventPrefix.issue}${this.list.id}`);
}
+
+ this.closeListActions();
},
showNewEpicForm() {
eventHub.$emit(`${toggleFormEventPrefix.epic}${this.list.id}`);
+
+ this.closeListActions();
},
toggleExpanded() {
const collapsed = !this.list.collapsed;
@@ -392,7 +454,7 @@ export default {
<gl-icon class="gl-mr-2" :name="countIcon" :size="14" />
<item-count
v-if="!isLoading"
- :items-size="isEpicBoard ? list.epicsCount : boardList.issuesCount"
+ :items-size="itemsCount"
:max-issue-count="list.maxIssueCount"
/>
</span>
@@ -407,44 +469,24 @@ export default {
<!-- EE end -->
</span>
</div>
- <gl-button-group v-if="showListHeaderActions" class="board-list-button-group gl-pl-2">
- <gl-button
- v-if="isNewIssueShown"
- v-show="!list.collapsed"
- ref="newIssueBtn"
- v-gl-tooltip.hover
- :aria-label="$options.i18n.newIssue"
- :title="$options.i18n.newIssue"
- class="no-drag"
- size="small"
- icon="plus"
- @click="showNewIssueForm"
- />
-
- <gl-button
- v-if="isNewEpicShown"
- v-show="!list.collapsed"
- v-gl-tooltip.hover
- :aria-label="$options.i18n.newEpic"
- :title="$options.i18n.newEpic"
- class="no-drag"
- size="small"
- icon="plus"
- @click="showNewEpicForm"
- />
-
- <gl-button
- v-if="isSettingsShown"
- ref="settingsBtn"
- v-gl-tooltip.hover
- :aria-label="$options.i18n.listSettings"
- class="no-drag"
- size="small"
- :title="$options.i18n.listSettings"
- icon="settings"
- @click="openSidebarSettings"
- />
- </gl-button-group>
+ <gl-disclosure-dropdown
+ v-if="showListHeaderActions"
+ ref="headerListActions"
+ v-gl-tooltip.hover.top="{
+ title: $options.i18n.listActions,
+ boundary: 'viewport',
+ }"
+ data-testid="header-list-actions"
+ class="gl-py-2 gl-ml-3"
+ :aria-label="$options.i18n.listActions"
+ :title="$options.i18n.listActions"
+ category="tertiary"
+ icon="ellipsis_v"
+ :text-sr-only="true"
+ :items="actionListItems"
+ no-caret
+ placement="right"
+ />
</h3>
</header>
</template>
diff --git a/app/assets/javascripts/boards/components/board_settings_sidebar.vue b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
index c0c2699b63d..afa20f63913 100644
--- a/app/assets/javascripts/boards/components/board_settings_sidebar.vue
+++ b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
@@ -136,11 +136,11 @@ export default {
size="sm"
:action-primary="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ {
text: $options.i18n.modalAction,
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
} /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
:action-secondary="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ {
text: $options.i18n.modalCancel,
- attributes: [{ variant: 'default' }],
+ attributes: { variant: 'default' },
} /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
@primary="handleModalPrimary"
>
diff --git a/app/assets/javascripts/boards/components/board_top_bar.vue b/app/assets/javascripts/boards/components/board_top_bar.vue
index 2e20ed70bb0..fad57758be1 100644
--- a/app/assets/javascripts/boards/components/board_top_bar.vue
+++ b/app/assets/javascripts/boards/components/board_top_bar.vue
@@ -35,6 +35,10 @@ export default {
type: String,
required: true,
},
+ isSwimlanesOn: {
+ type: Boolean,
+ required: true,
+ },
},
data() {
return {
@@ -56,10 +60,28 @@ export default {
return !this.isApolloBoard;
},
update(data) {
- return data.workspace.board;
+ const { board } = data.workspace;
+ return {
+ ...board,
+ labels: board.labels?.nodes,
+ };
},
},
},
+ computed: {
+ hasScope() {
+ if (this.board.labels?.length > 0) {
+ return true;
+ }
+ let hasScope = false;
+ ['assignee', 'iterationCadence', 'iteration', 'milestone', 'weight'].forEach((attr) => {
+ if (this.board[attr] !== null && this.board[attr] !== undefined) {
+ hasScope = true;
+ }
+ });
+ return hasScope;
+ },
+ },
};
</script>
@@ -73,15 +95,27 @@ export default {
>
<boards-selector :board-apollo="board" @switchBoard="$emit('switchBoard', $event)" />
<new-board-button />
- <issue-board-filtered-search v-if="isIssueBoard" />
- <epic-board-filtered-search v-else />
+ <issue-board-filtered-search
+ v-if="isIssueBoard"
+ :board="board"
+ @setFilters="$emit('setFilters', $event)"
+ />
+ <epic-board-filtered-search
+ v-else
+ :board="board"
+ @setFilters="$emit('setFilters', $event)"
+ />
</div>
<div
class="filter-dropdown-container gl-md-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-align-items-flex-start"
>
<toggle-labels />
- <toggle-epics-swimlanes v-if="swimlanesFeatureAvailable && isSignedIn" />
- <config-toggle />
+ <toggle-epics-swimlanes
+ v-if="swimlanesFeatureAvailable && isSignedIn"
+ :is-swimlanes-on="isSwimlanesOn"
+ @toggleSwimlanes="$emit('toggleSwimlanes', $event)"
+ />
+ <config-toggle :board-has-scope="hasScope" />
<board-add-new-column-trigger v-if="canAdminList" />
<toggle-focus />
</div>
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index a1a49386b37..4aec286a5f4 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -8,6 +8,7 @@ import {
GlDropdownItem,
GlModalDirective,
} from '@gitlab/ui';
+import { produce } from 'immer';
import { throttle } from 'lodash';
import { mapActions, mapState } from 'vuex';
@@ -89,6 +90,9 @@ export default {
parentType() {
return this.boardType;
},
+ boardQuery() {
+ return this.isGroupBoard ? groupBoardsQuery : projectBoardsQuery;
+ },
loading() {
return this.loadingRecentBoards || this.loadingBoards;
},
@@ -155,9 +159,6 @@ export default {
name: node.name,
}));
},
- boardQuery() {
- return this.isGroupBoard ? groupBoardsQuery : projectBoardsQuery;
- },
recentBoardsQuery() {
return this.isGroupBoard ? groupRecentBoardsQuery : projectRecentBoardsQuery;
},
@@ -191,6 +192,29 @@ export default {
},
});
},
+ addBoard(board) {
+ const { defaultClient: store } = this.$apollo.provider.clients;
+
+ const sourceData = store.readQuery({
+ query: this.boardQuery,
+ variables: { fullPath: this.fullPath },
+ });
+
+ const newData = produce(sourceData, (draftState) => {
+ draftState[this.parentType].boards.edges = [
+ ...draftState[this.parentType].boards.edges,
+ { node: board },
+ ];
+ });
+
+ store.writeQuery({
+ query: this.boardQuery,
+ variables: { fullPath: this.fullPath },
+ data: newData,
+ });
+
+ this.$emit('switchBoard', board.id);
+ },
isScrolledUp() {
const { content } = this.$refs;
@@ -226,14 +250,12 @@ export default {
boardType: this.boardType,
});
},
- fullBoardId(boardId) {
- return fullBoardId(boardId);
- },
async switchBoard(boardId, e) {
if (isMetaKey(e)) {
window.open(`${this.boardBaseUrl}/${boardId}`, '_blank');
} else if (this.isApolloBoard) {
- this.$emit('switchBoard', this.fullBoardId(boardId));
+ this.$emit('switchBoard', fullBoardId(boardId));
+ updateHistory({ url: `${this.boardBaseUrl}/${boardId}` });
} else {
this.unsetActiveId();
this.fetchCurrentBoard(boardId);
@@ -357,6 +379,7 @@ export default {
:weights="weights"
:current-board="boardToUse"
:current-page="currentPage"
+ @addBoard="addBoard"
@cancel="cancel"
/>
</span>
diff --git a/app/assets/javascripts/boards/components/config_toggle.vue b/app/assets/javascripts/boards/components/config_toggle.vue
index 7002fd44294..dd3b9472879 100644
--- a/app/assets/javascripts/boards/components/config_toggle.vue
+++ b/app/assets/javascripts/boards/components/config_toggle.vue
@@ -16,6 +16,13 @@ export default {
},
mixins: [Tracking.mixin()],
inject: ['canAdminList'],
+ props: {
+ boardHasScope: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
computed: {
...mapGetters(['hasScope']),
buttonText() {
@@ -40,7 +47,7 @@ export default {
v-gl-modal-directive="'board-config-modal'"
v-gl-tooltip
:title="tooltipTitle"
- :class="{ 'dot-highlight': hasScope }"
+ :class="{ 'dot-highlight': hasScope || boardHasScope }"
data-qa-selector="boards_config_button"
@click.prevent="showPage"
>
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 7749391ec6f..cdcc7b8e5a6 100644
--- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
@@ -1,12 +1,11 @@
<script>
import { GlFilteredSearchToken } from '@gitlab/ui';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
-import { mapActions } from 'vuex';
import { orderBy } from 'lodash';
import BoardFilteredSearch from 'ee_else_ce/boards/components/board_filtered_search.vue';
import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
-import issueBoardFilters from '~/boards/issue_board_filters';
+import issueBoardFilters from 'ee_else_ce/boards/issue_board_filters';
import { TYPENAME_USER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
@@ -47,11 +46,18 @@ export default {
},
components: { BoardFilteredSearch },
inject: ['isSignedIn', 'releasesFetchPath', 'fullPath', 'isGroupBoard'],
+ props: {
+ board: {
+ type: Object,
+ required: false,
+ default: () => {},
+ },
+ },
computed: {
tokensCE() {
const { issue, incident } = this.$options.i18n;
const { types } = this.$options;
- const { fetchUsers, fetchLabels } = issueBoardFilters(
+ const { fetchUsers, fetchLabels, fetchMilestones } = issueBoardFilters(
this.$apollo,
this.fullPath,
this.isGroupBoard,
@@ -135,7 +141,7 @@ export default {
token: MilestoneToken,
unique: true,
shouldSkipSort: true,
- fetchMilestones: this.fetchMilestones,
+ fetchMilestones,
},
{
icon: 'issues',
@@ -176,7 +182,6 @@ export default {
},
},
methods: {
- ...mapActions(['fetchMilestones']),
preloadedUsers() {
return gon?.current_user_id
? [
@@ -194,5 +199,10 @@ export default {
</script>
<template>
- <board-filtered-search data-testid="issue-board-filtered-search" :tokens="tokens" />
+ <board-filtered-search
+ data-testid="issue-board-filtered-search"
+ :tokens="tokens"
+ :board="board"
+ @setFilters="$emit('setFilters', $event)"
+ />
</template>
diff --git a/app/assets/javascripts/boards/constants.js b/app/assets/javascripts/boards/constants.js
index 712e3e1ac4a..b557dc9205e 100644
--- a/app/assets/javascripts/boards/constants.js
+++ b/app/assets/javascripts/boards/constants.js
@@ -1,5 +1,5 @@
import boardListsQuery from 'ee_else_ce/boards/graphql/board_lists.query.graphql';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_EPIC, TYPE_ISSUE, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import { s__, __ } from '~/locale';
import updateEpicSubscriptionMutation from '~/sidebar/queries/update_epic_subscription.mutation.graphql';
import updateEpicTitleMutation from '~/sidebar/queries/update_epic_title.mutation.graphql';
@@ -12,19 +12,6 @@ import groupBoardQuery from './graphql/group_board.query.graphql';
import projectBoardQuery from './graphql/project_board.query.graphql';
import listIssuesQuery from './graphql/lists_issues.query.graphql';
-/* eslint-disable-next-line @gitlab/require-i18n-strings */
-export const AssigneeIdParamValues = ['Any', 'None'];
-
-export const issuableTypes = {
- issue: 'issue',
- epic: 'epic',
-};
-
-export const BoardType = {
- project: 'project',
- group: 'group',
-};
-
export const ListType = {
assignee: 'assignee',
milestone: 'milestone',
@@ -64,10 +51,10 @@ export const INCIDENT = 'INCIDENT';
export const flashAnimationDuration = 2000;
export const boardQuery = {
- [BoardType.group]: {
+ [WORKSPACE_GROUP]: {
query: groupBoardQuery,
},
- [BoardType.project]: {
+ [WORKSPACE_PROJECT]: {
query: projectBoardQuery,
},
};
@@ -94,7 +81,7 @@ export const titleQueries = {
[TYPE_ISSUE]: {
mutation: issueSetTitleMutation,
},
- [issuableTypes.epic]: {
+ [TYPE_EPIC]: {
mutation: updateEpicTitleMutation,
},
};
@@ -103,7 +90,7 @@ export const subscriptionQueries = {
[TYPE_ISSUE]: {
mutation: issueSetSubscriptionMutation,
},
- [issuableTypes.epic]: {
+ [TYPE_EPIC]: {
mutation: updateEpicSubscriptionMutation,
},
};
@@ -143,6 +130,7 @@ export const MilestoneFilterType = {
started: 'Started',
upcoming: 'Upcoming',
};
+/* eslint-enable @gitlab/require-i18n-strings */
export const DraggableItemTypes = {
card: 'card',
@@ -155,7 +143,6 @@ export const MilestoneIDs = {
};
export default {
- BoardType,
ListType,
};
@@ -178,3 +165,5 @@ export const BOARD_CARD_MOVE_TO_POSITIONS_OPTIONS = [
action: () => {},
},
];
+
+export const GroupByParamType = {};
diff --git a/app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql b/app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql
index 9e6c26063e9..14811b435e1 100644
--- a/app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql
+++ b/app/assets/javascripts/boards/graphql/group_board_milestones.query.graphql
@@ -1,5 +1,5 @@
query GroupBoardMilestones($fullPath: ID!, $searchTerm: String, $state: MilestoneStateEnum) {
- group(fullPath: $fullPath) {
+ workspace: group(fullPath: $fullPath) {
id
milestones(
includeAncestors: true
diff --git a/app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql b/app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql
index 02aa08f90ef..9af92a6ff2d 100644
--- a/app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql
+++ b/app/assets/javascripts/boards/graphql/project_board_milestones.query.graphql
@@ -1,5 +1,5 @@
query ProjectBoardMilestones($fullPath: ID!, $searchTerm: String, $state: MilestoneStateEnum) {
- project(fullPath: $fullPath) {
+ workspace: project(fullPath: $fullPath) {
id
milestones(
searchTitle: $searchTerm
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index 4c6f341828c..67388284d31 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -3,9 +3,8 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import BoardApp from '~/boards/components/board_app.vue';
import '~/boards/filters/due_date_filters';
-import { BoardType } from '~/boards/constants';
import store from '~/boards/stores';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import {
NavigationType,
isLoggedIn,
@@ -68,8 +67,8 @@ function mountBoardApp(el) {
initialFilterParams,
boardBaseUrl: el.dataset.boardBaseUrl,
boardType,
- isGroupBoard: boardType === BoardType.group,
- isProjectBoard: boardType === BoardType.project,
+ isGroupBoard: boardType === WORKSPACE_GROUP,
+ isProjectBoard: boardType === WORKSPACE_PROJECT,
currentUserId: gon.current_user_id || null,
boardWeight: el.dataset.boardWeight ? parseInt(el.dataset.boardWeight, 10) : null,
labelsManagePath: el.dataset.labelsManagePath,
diff --git a/app/assets/javascripts/boards/issue_board_filters.js b/app/assets/javascripts/boards/issue_board_filters.js
index 7e9b68778d5..27efb3f775c 100644
--- a/app/assets/javascripts/boards/issue_board_filters.js
+++ b/app/assets/javascripts/boards/issue_board_filters.js
@@ -1,5 +1,7 @@
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 boardLabels from './graphql/board_labels.query.graphql';
export default function issueBoardFilters(apollo, fullPath, isGroupBoard) {
@@ -37,8 +39,27 @@ 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/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index 1b4e6334723..a144054d680 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -1,7 +1,6 @@
import * as Sentry from '@sentry/browser';
import { sortBy } from 'lodash';
import {
- BoardType,
ListType,
inactiveId,
flashAnimationDuration,
@@ -34,7 +33,7 @@ import totalCountAndWeightQuery from 'ee_else_ce/boards/graphql/board_lists_defe
import { fetchPolicies } from '~/lib/graphql';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { defaultClient as gqlClient } from '~/graphql_shared/issuable_client';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { queryToObject } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
@@ -61,7 +60,7 @@ export default {
return gqlClient
.query({
- query: boardType === BoardType.group ? groupBoardQuery : projectBoardQuery,
+ query: boardType === WORKSPACE_GROUP ? groupBoardQuery : projectBoardQuery,
variables,
})
.then(({ data }) => {
@@ -139,8 +138,8 @@ export default {
boardId: fullBoardId,
filters: filterParams,
...(issuableType === TYPE_ISSUE && {
- isGroup: boardType === BoardType.group,
- isProject: boardType === BoardType.project,
+ isGroup: boardType === WORKSPACE_GROUP,
+ isProject: boardType === WORKSPACE_PROJECT,
}),
};
@@ -234,8 +233,8 @@ export default {
const variables = {
fullPath,
searchTerm,
- isGroup: boardType === BoardType.group,
- isProject: boardType === BoardType.project,
+ isGroup: boardType === WORKSPACE_GROUP,
+ isProject: boardType === WORKSPACE_PROJECT,
};
commit(types.RECEIVE_LABELS_REQUEST);
@@ -268,10 +267,10 @@ export default {
};
let query;
- if (boardType === BoardType.project) {
+ if (boardType === WORKSPACE_PROJECT) {
query = projectBoardMilestonesQuery;
}
- if (boardType === BoardType.group) {
+ if (boardType === WORKSPACE_GROUP) {
query = groupBoardMilestonesQuery;
}
@@ -286,8 +285,8 @@ export default {
variables,
})
.then(({ data }) => {
- const errors = data[boardType]?.errors;
- const milestones = data[boardType]?.milestones.nodes;
+ const errors = data.workspace?.errors;
+ const milestones = data.workspace?.milestones.nodes;
if (errors?.[0]) {
throw new Error(errors[0]);
@@ -431,8 +430,8 @@ export default {
boardId: fullBoardId,
id: listId,
filters: filterParams,
- isGroup: boardType === BoardType.group,
- isProject: boardType === BoardType.project,
+ isGroup: boardType === WORKSPACE_GROUP,
+ isProject: boardType === WORKSPACE_PROJECT,
first: DEFAULT_BOARD_LIST_ITEMS_SIZE,
after: fetchNext ? state.pageInfoByListId[listId].endCursor : undefined,
};
@@ -710,7 +709,7 @@ export default {
) => {
const input = formatIssueInput(issueInput, boardConfig);
- if (boardType === BoardType.project) {
+ if (boardType === WORKSPACE_PROJECT) {
input.projectPath = fullPath;
}
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
index fef5862f319..505c011b034 100644
--- a/app/assets/javascripts/boards/stores/mutations.js
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -1,18 +1,19 @@
import { cloneDeep, pull, union } from 'lodash';
import Vue from 'vue';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { TYPE_EPIC } from '~/issues/constants';
import { s__, __ } from '~/locale';
import { formatIssue } from '../boards_util';
-import { issuableTypes } from '../constants';
import * as mutationTypes from './mutation_types';
const updateListItemsCount = ({ state, listId, value }) => {
const list = state.boardLists[listId];
- if (state.issuableType === issuableTypes.epic) {
- Vue.set(state.boardLists, listId, { ...list, epicsCount: list.epicsCount + value });
- } else {
- Vue.set(state.boardLists, listId, { ...list });
+ if (state.issuableType === TYPE_EPIC) {
+ const listItem = cloneDeep(state.boardLists[listId]);
+ listItem.metadataepicsCount += value;
+ Vue.set(state.boardLists[listId], listId, listItem);
}
+ Vue.set(state.boardLists, listId, { ...list });
};
export const removeItemFromList = ({ state, listId, itemId, reordering = false }) => {
diff --git a/app/assets/javascripts/branches/divergence_graph.js b/app/assets/javascripts/branches/divergence_graph.js
index d05b53f1a50..54abc9c45a7 100644
--- a/app/assets/javascripts/branches/divergence_graph.js
+++ b/app/assets/javascripts/branches/divergence_graph.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import DivergenceGraph from './components/divergence_graph.vue';
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 3c6114b38ce..257c3309e10 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
@@ -38,6 +38,10 @@ export default {
required: false,
default: 0,
},
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
variables: {
type: Array,
required: true,
@@ -87,8 +91,12 @@ export default {
:entity="entity"
:is-loading="isLoading"
:max-variable-limit="maxVariableLimit"
+ :page-info="pageInfo"
:variables="variables"
+ @handle-prev-page="$emit('handle-prev-page')"
+ @handle-next-page="$emit('handle-next-page')"
@set-selected-variable="setSelectedVariable"
+ @sort-changed="(val) => $emit('sort-changed', val)"
/>
<ci-variable-modal
v-if="showModal"
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 6e39bda0b07..9db9bea63b2 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
@@ -1,10 +1,12 @@
<script>
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { mapEnvironmentNames, reportMessageToSentry } from '../utils';
import {
ADD_MUTATION_ACTION,
DELETE_MUTATION_ACTION,
+ SORT_DIRECTIONS,
UPDATE_MUTATION_ACTION,
environmentFetchErrorText,
genericMutationErrorText,
@@ -16,6 +18,7 @@ export default {
components: {
CiVariableSettings,
},
+ mixins: [glFeatureFlagsMixin()],
inject: ['endpoint'],
props: {
areScopedVariablesAvailable: {
@@ -97,6 +100,7 @@ export default {
loadingCounter: 0,
maxVariableLimit: 0,
pageInfo: {},
+ sortDirection: SORT_DIRECTIONS.ASC,
};
},
apollo: {
@@ -107,6 +111,8 @@ export default {
variables() {
return {
fullPath: this.fullPath || undefined,
+ first: this.pageSize,
+ sort: this.sortDirection,
};
},
update(data) {
@@ -116,21 +122,23 @@ export default {
this.maxVariableLimit = this.queryData.ciVariables.lookup(data)?.limit || 0;
this.pageInfo = this.queryData.ciVariables.lookup(data)?.pageInfo || this.pageInfo;
- this.hasNextPage = this.pageInfo?.hasNextPage || false;
- // Because graphQL has a limit of 100 items,
- // we batch load all the variables by making successive queries
- // to keep the same UX. As a safeguard, we make sure that we cannot go over
- // 20 consecutive API calls, which means 2000 variables loaded maximum.
- if (!this.hasNextPage) {
- this.isLoadingMoreItems = false;
- } else if (this.loadingCounter < 20) {
- this.hasNextPage = false;
- this.fetchMoreVariables();
- this.loadingCounter += 1;
- } else {
- createAlert({ message: this.$options.tooManyCallsError });
- reportMessageToSentry(this.componentName, this.$options.tooManyCallsError, {});
+ if (!this.glFeatures?.ciVariablesPages) {
+ this.hasNextPage = this.pageInfo?.hasNextPage || false;
+ // Because graphQL has a limit of 100 items,
+ // we batch load all the variables by making successive queries
+ // to keep the same UX. As a safeguard, we make sure that we cannot go over
+ // 20 consecutive API calls, which means 2000 variables loaded maximum.
+ if (!this.hasNextPage) {
+ this.isLoadingMoreItems = false;
+ } else if (this.loadingCounter < 20) {
+ this.hasNextPage = false;
+ this.fetchMoreVariables();
+ this.loadingCounter += 1;
+ } else {
+ createAlert({ message: this.$options.tooManyCallsError });
+ reportMessageToSentry(this.componentName, this.$options.tooManyCallsError, {});
+ }
}
},
error() {
@@ -172,6 +180,9 @@ export default {
this.isLoadingMoreItems
);
},
+ pageSize() {
+ return this.glFeatures?.ciVariablesPages ? 20 : 100;
+ },
},
methods: {
addVariable(variable) {
@@ -189,6 +200,31 @@ export default {
},
});
},
+ handlePrevPage() {
+ this.$apollo.queries.ciVariables.fetchMore({
+ variables: {
+ before: this.pageInfo.startCursor,
+ first: null,
+ last: this.pageSize,
+ },
+ });
+ },
+ handleNextPage() {
+ this.$apollo.queries.ciVariables.fetchMore({
+ variables: {
+ after: this.pageInfo.endCursor,
+ first: this.pageSize,
+ last: null,
+ },
+ });
+ },
+ async handleSortChanged({ sortDesc }) {
+ this.sortDirection = sortDesc ? SORT_DIRECTIONS.DESC : SORT_DIRECTIONS.ASC;
+
+ // Wait for the new sort direction to be updated and then refetch
+ await this.$nextTick();
+ this.$apollo.queries.ciVariables.refetch();
+ },
updateVariable(variable) {
this.variableMutation(UPDATE_MUTATION_ACTION, variable);
},
@@ -230,13 +266,17 @@ export default {
<ci-variable-settings
:are-scoped-variables-available="areScopedVariablesAvailable"
:entity="entity"
+ :environments="environments"
:hide-environment-scope="hideEnvironmentScope"
:is-loading="isLoading"
- :variables="ciVariables"
:max-variable-limit="maxVariableLimit"
- :environments="environments"
+ :page-info="pageInfo"
+ :variables="ciVariables"
@add-variable="addVariable"
@delete-variable="deleteVariable"
+ @handle-prev-page="handlePrevPage"
+ @handle-next-page="handleNextPage"
+ @sort-changed="handleSortChanged"
@update-variable="updateVariable"
/>
</template>
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 345a8def49d..5e367ff33b2 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
@@ -4,6 +4,7 @@ import {
GlButton,
GlLoadingIcon,
GlModalDirective,
+ GlKeysetPagination,
GlTable,
GlTooltipDirective,
} from '@gitlab/ui';
@@ -56,6 +57,7 @@ export default {
components: {
GlAlert,
GlButton,
+ GlKeysetPagination,
GlLoadingIcon,
GlTable,
},
@@ -78,6 +80,10 @@ export default {
type: Number,
required: true,
},
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
variables: {
type: Array,
required: true,
@@ -165,6 +171,28 @@ export default {
>
{{ exceedsVariableLimitText }}
</gl-alert>
+ <div
+ v-if="glFeatures.ciVariablesPages"
+ class="ci-variable-actions gl-display-flex gl-justify-content-end gl-my-3"
+ >
+ <gl-button
+ v-if="!isTableEmpty"
+ data-qa-selector="reveal_ci_variable_value_button"
+ @click="toggleHiddenState"
+ >{{ valuesButtonText }}</gl-button
+ >
+ <gl-button
+ v-gl-modal-directive="$options.modalId"
+ class="gl-mx-3"
+ data-qa-selector="add_ci_variable_button"
+ variant="confirm"
+ category="primary"
+ :aria-label="__('Add')"
+ :disabled="exceedsVariableLimit"
+ @click="setSelectedVariable()"
+ >{{ __('Add variable') }}</gl-button
+ >
+ </div>
<gl-table
v-if="!isLoading"
:fields="fields"
@@ -174,11 +202,13 @@ export default {
sort-by="key"
sort-direction="asc"
stacked="lg"
- table-class="text-secondary"
+ table-class="gl-border-t"
fixed
show-empty
sort-icon-left
no-sort-reset
+ no-local-sorting
+ @sort-changed="(val) => $emit('sort-changed', val)"
>
<template #table-colgroup="scope">
<col v-for="field in scope.fields" :key="field.key" :style="field.customStyle" />
@@ -275,7 +305,7 @@ export default {
>
{{ exceedsVariableLimitText }}
</gl-alert>
- <div class="ci-variable-actions gl-display-flex gl-mt-5">
+ <div v-if="!glFeatures.ciVariablesPages" class="ci-variable-actions gl-display-flex gl-mt-5">
<gl-button
v-gl-modal-directive="$options.modalId"
class="gl-mr-3"
@@ -294,5 +324,14 @@ export default {
>{{ valuesButtonText }}</gl-button
>
</div>
+ <div v-else class="gl-display-flex gl-justify-content-center gl-mt-6">
+ <gl-keyset-pagination
+ v-bind="pageInfo"
+ :prev-text="__('Previous')"
+ :next-text="__('Next')"
+ @prev="$emit('handle-prev-page')"
+ @next="$emit('handle-next-page')"
+ />
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/ci/ci_variable_list/constants.js b/app/assets/javascripts/ci/ci_variable_list/constants.js
index 627ace1b28e..c77d8c67bc8 100644
--- a/app/assets/javascripts/ci/ci_variable_list/constants.js
+++ b/app/assets/javascripts/ci/ci_variable_list/constants.js
@@ -2,6 +2,11 @@ import { __, s__ } from '~/locale';
export const ADD_CI_VARIABLE_MODAL_ID = 'add-ci-variable';
+export const SORT_DIRECTIONS = {
+ ASC: 'KEY_ASC',
+ DESC: 'KEY_DESC',
+};
+
// This const will be deprecated once we remove VueX from the section
export const displayText = {
variableText: __('Variable'),
diff --git a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/group_variables.query.graphql b/app/assets/javascripts/ci/ci_variable_list/graphql/queries/group_variables.query.graphql
index 538502fdd3b..4a64a24573e 100644
--- a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/group_variables.query.graphql
+++ b/app/assets/javascripts/ci/ci_variable_list/graphql/queries/group_variables.query.graphql
@@ -1,10 +1,17 @@
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
-query getGroupVariables($after: String, $first: Int = 100, $fullPath: ID!) {
+query getGroupVariables(
+ $after: String
+ $before: String
+ $first: Int
+ $fullPath: ID!
+ $last: Int
+ $sort: CiVariableSort = KEY_ASC
+) {
group(fullPath: $fullPath) {
id
- ciVariables(after: $after, first: $first) {
+ ciVariables(after: $after, before: $before, first: $first, last: $last, sort: $sort) {
limit
pageInfo {
...PageInfo
diff --git a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/project_variables.query.graphql b/app/assets/javascripts/ci/ci_variable_list/graphql/queries/project_variables.query.graphql
index af0cd2d0b2c..03a7142080b 100644
--- a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/project_variables.query.graphql
+++ b/app/assets/javascripts/ci/ci_variable_list/graphql/queries/project_variables.query.graphql
@@ -1,10 +1,17 @@
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
-query getProjectVariables($after: String, $first: Int = 100, $fullPath: ID!) {
+query getProjectVariables(
+ $after: String
+ $before: String
+ $first: Int
+ $fullPath: ID!
+ $last: Int
+ $sort: CiVariableSort = KEY_ASC
+) {
project(fullPath: $fullPath) {
id
- ciVariables(after: $after, first: $first) {
+ ciVariables(after: $after, before: $before, first: $first, last: $last, sort: $sort) {
limit
pageInfo {
...PageInfo
diff --git a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/variables.query.graphql b/app/assets/javascripts/ci/ci_variable_list/graphql/queries/variables.query.graphql
index b8dd6f5f562..adf539a44ae 100644
--- a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/variables.query.graphql
+++ b/app/assets/javascripts/ci/ci_variable_list/graphql/queries/variables.query.graphql
@@ -1,8 +1,14 @@
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
-query getVariables($after: String, $first: Int = 100) {
- ciVariables(after: $after, first: $first) {
+query getVariables(
+ $after: String
+ $before: String
+ $first: Int
+ $last: Int
+ $sort: CiVariableSort = KEY_ASC
+) {
+ ciVariables(after: $after, before: $before, first: $first, last: $last, sort: $sort) {
pageInfo {
...PageInfo
}
diff --git a/app/assets/javascripts/ci/ci_variable_list/graphql/settings.js b/app/assets/javascripts/ci/ci_variable_list/graphql/settings.js
index cafe3df35d0..7ed0418d5f4 100644
--- a/app/assets/javascripts/ci/ci_variable_list/graphql/settings.js
+++ b/app/assets/javascripts/ci/ci_variable_list/graphql/settings.js
@@ -205,33 +205,40 @@ export const mergeVariables = (existing, incoming, { args }) => {
return result;
};
-export const cacheConfig = {
- cacheConfig: {
- typePolicies: {
- Query: {
- fields: {
- ciVariables: {
- keyArgs: false,
- merge: mergeVariables,
+export const mergeOnlyIncomings = (_, incoming) => {
+ return incoming;
+};
+
+export const generateCacheConfig = (isVariablePagesEnabled = false) => {
+ const merge = isVariablePagesEnabled ? mergeOnlyIncomings : mergeVariables;
+ return {
+ cacheConfig: {
+ typePolicies: {
+ Query: {
+ fields: {
+ ciVariables: {
+ keyArgs: false,
+ merge,
+ },
},
},
- },
- Project: {
- fields: {
- ciVariables: {
- keyArgs: ['fullPath', 'endpoint', 'id'],
- merge: mergeVariables,
+ Project: {
+ fields: {
+ ciVariables: {
+ keyArgs: ['fullPath'],
+ merge,
+ },
},
},
- },
- Group: {
- fields: {
- ciVariables: {
- keyArgs: ['fullPath'],
- merge: mergeVariables,
+ Group: {
+ fields: {
+ ciVariables: {
+ keyArgs: ['fullPath'],
+ merge,
+ },
},
},
},
},
- },
+ };
};
diff --git a/app/assets/javascripts/ci/ci_variable_list/index.js b/app/assets/javascripts/ci/ci_variable_list/index.js
index 4270c3c67fc..3ed56201f0d 100644
--- a/app/assets/javascripts/ci/ci_variable_list/index.js
+++ b/app/assets/javascripts/ci/ci_variable_list/index.js
@@ -5,7 +5,7 @@ import { parseBoolean } from '~/lib/utils/common_utils';
import CiAdminVariables from './components/ci_admin_variables.vue';
import CiGroupVariables from './components/ci_group_variables.vue';
import CiProjectVariables from './components/ci_project_variables.vue';
-import { cacheConfig, resolvers } from './graphql/settings';
+import { generateCacheConfig, resolvers } from './graphql/settings';
const mountCiVariableListApp = (containerEl) => {
const {
@@ -42,8 +42,13 @@ const mountCiVariableListApp = (containerEl) => {
Vue.use(VueApollo);
+ // If the feature flag `ci_variables_pages` is enabled,
+ // we are using the default cache config with pages.
const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(resolvers, cacheConfig),
+ defaultClient: createDefaultClient(
+ resolvers,
+ generateCacheConfig(window.gon?.features?.ciVariablesPages),
+ ),
});
return new Vue({
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/editor/text_editor.vue b/app/assets/javascripts/ci/pipeline_editor/components/editor/text_editor.vue
index 891c40482d3..1192f0bf418 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/editor/text_editor.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/editor/text_editor.vue
@@ -2,6 +2,7 @@
import { EDITOR_READY_EVENT } from '~/editor/constants';
import { CiSchemaExtension } from '~/editor/extensions/source_editor_ci_schema_ext';
import SourceEditor from '~/vue_shared/components/source_editor.vue';
+import eventHub, { SCROLL_EDITOR_TO_BOTTOM } from '~/ci/pipeline_editor/event_hub';
import { SOURCE_EDITOR_DEBOUNCE } from '../../constants';
export default {
@@ -16,6 +17,12 @@ export default {
},
inject: ['ciConfigPath'],
inheritAttrs: false,
+ created() {
+ eventHub.$on(SCROLL_EDITOR_TO_BOTTOM, this.scrollEditorToBottom);
+ },
+ beforeDestroy() {
+ eventHub.$off(SCROLL_EDITOR_TO_BOTTOM, this.scrollEditorToBottom);
+ },
methods: {
onCiConfigUpdate(content) {
this.$emit('updateCiConfig', content);
@@ -24,6 +31,10 @@ export default {
instance.use({ definition: CiSchemaExtension });
instance.registerCiSchema();
},
+ scrollEditorToBottom() {
+ const editor = this.$refs.editor.getEditor();
+ editor.setScrollTop(editor.getScrollHeight());
+ },
},
readyEvent: EDITOR_READY_EVENT,
};
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 84c0eef441f..8553256f13a 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
@@ -1,8 +1,7 @@
<script>
-import { GlIcon, GlLink, GlLoadingIcon } from '@gitlab/ui';
-import { __, s__, sprintf } from '~/locale';
+import { GlIcon, GlLink, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
import getAppStatus from '~/ci/pipeline_editor/graphql/queries/client/app_status.query.graphql';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import {
EDITOR_APP_STATUS_EMPTY,
EDITOR_APP_STATUS_LINT_UNAVAILABLE,
@@ -11,15 +10,20 @@ import {
} from '../../constants';
export const i18n = {
- empty: __(
- "We'll continuously validate your pipeline configuration. The validation results will appear here.",
+ empty: s__(
+ "Pipelines|We'll continuously validate your pipeline configuration. The validation results will appear here.",
),
- learnMore: __('Learn more'),
loading: s__('Pipelines|Validating GitLab CI configuration…'),
- invalid: s__('Pipelines|This GitLab CI configuration is invalid.'),
- invalidWithReason: s__('Pipelines|This GitLab CI configuration is invalid: %{reason}.'),
- unavailableValidation: s__('Pipelines|Configuration validation currently not available.'),
- valid: s__('Pipelines|Pipeline syntax is correct.'),
+ invalid: s__(
+ 'Pipelines|This GitLab CI configuration is invalid. %{linkStart}Learn more%{linkEnd}',
+ ),
+ invalidWithReason: s__(
+ 'Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}',
+ ),
+ unavailableValidation: s__(
+ 'Pipelines|Unable to validate CI/CD configuration. See the %{linkStart}GitLab CI/CD troubleshooting guide%{linkEnd} for more details.',
+ ),
+ valid: s__('Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}'),
};
export default {
@@ -28,10 +32,10 @@ export default {
GlIcon,
GlLink,
GlLoadingIcon,
- TooltipOnTruncate,
+ GlSprintf,
},
inject: {
- lintUnavailableHelpPagePath: {
+ ciTroubleshootingPath: {
default: '',
},
ymlHelpPagePath: {
@@ -54,49 +58,48 @@ export default {
},
},
computed: {
- helpPath() {
- return this.isLintUnavailable ? this.lintUnavailableHelpPagePath : this.ymlHelpPagePath;
+ APP_STATUS_CONFIG() {
+ return {
+ [EDITOR_APP_STATUS_EMPTY]: {
+ icon: 'check',
+ message: this.$options.i18n.empty,
+ },
+ [EDITOR_APP_STATUS_LINT_UNAVAILABLE]: {
+ icon: 'time-out',
+ link: this.ciTroubleshootingPath,
+ message: this.$options.i18n.unavailableValidation,
+ },
+ [EDITOR_APP_STATUS_VALID]: {
+ icon: 'check',
+ message: this.$options.i18n.valid,
+ },
+ };
},
- isEmpty() {
- return this.appStatus === EDITOR_APP_STATUS_EMPTY;
+ currentAppStatusConfig() {
+ return this.APP_STATUS_CONFIG[this.appStatus] || {};
},
- isLintUnavailable() {
- return this.appStatus === EDITOR_APP_STATUS_LINT_UNAVAILABLE;
+ hasLink() {
+ return this.appStatus !== EDITOR_APP_STATUS_EMPTY;
+ },
+ helpPath() {
+ return this.currentAppStatusConfig.link || this.ymlHelpPagePath;
},
isLoading() {
return this.appStatus === EDITOR_APP_STATUS_LOADING;
},
- isValid() {
- return this.appStatus === EDITOR_APP_STATUS_VALID;
- },
icon() {
- switch (this.appStatus) {
- case EDITOR_APP_STATUS_EMPTY:
- return 'check';
- case EDITOR_APP_STATUS_LINT_UNAVAILABLE:
- return 'time-out';
- case EDITOR_APP_STATUS_VALID:
- return 'check';
- default:
- return 'warning-solid';
- }
+ return this.currentAppStatusConfig.icon || 'warning-solid';
},
message() {
const [reason] = this.ciConfig?.errors || [];
- switch (this.appStatus) {
- case EDITOR_APP_STATUS_EMPTY:
- return this.$options.i18n.empty;
- case EDITOR_APP_STATUS_LINT_UNAVAILABLE:
- return this.$options.i18n.unavailableValidation;
- case EDITOR_APP_STATUS_VALID:
- return this.$options.i18n.valid;
- default:
- // Only display first error as a reason
- return this.ciConfig?.errors?.length > 0
- ? sprintf(this.$options.i18n.invalidWithReason, { reason }, false)
- : this.$options.i18n.invalid;
- }
+ return (
+ this.currentAppStatusConfig.message ||
+ // Only display first error as a reason
+ (reason
+ ? sprintf(this.$options.i18n.invalidWithReason, { reason }, false)
+ : this.$options.i18n.invalid)
+ );
},
},
};
@@ -108,18 +111,14 @@ export default {
<gl-loading-icon size="sm" inline />
{{ $options.i18n.loading }}
</template>
-
- <span v-else class="gl-display-inline-flex gl-white-space-nowrap gl-max-w-full">
- <tooltip-on-truncate :title="message" class="gl-text-truncate">
+ <span v-else data-testid="validation-segment">
+ <span class="gl-max-w-full" data-qa-selector="validation_message_content">
<gl-icon :name="icon" />
- <span data-qa-selector="validation_message_content" data-testid="validationMsg">
- {{ message }}
- </span>
- </tooltip-on-truncate>
- <span v-if="!isEmpty" class="gl-flex-shrink-0 gl-pl-2">
- <gl-link data-testid="learnMoreLink" :href="helpPath">
- {{ $options.i18n.learnMore }}
- </gl-link>
+ <gl-sprintf :message="message">
+ <template v-if="hasLink" #link="{ content }">
+ <gl-link :href="helpPath">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
</span>
</span>
</div>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item.vue b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item.vue
new file mode 100644
index 00000000000..c2ae7d7be49
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item.vue
@@ -0,0 +1,39 @@
+<script>
+import { GlFormGroup, GlAccordionItem, GlFormInput } from '@gitlab/ui';
+import { i18n } from '../constants';
+
+export default {
+ i18n,
+ components: {
+ GlAccordionItem,
+ GlFormInput,
+ GlFormGroup,
+ },
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+<template>
+ <gl-accordion-item :title="$options.i18n.IMAGE">
+ <div class="gl-display-flex">
+ <gl-form-group class="gl-flex-grow-1 gl-mr-3" :label="$options.i18n.IMAGE_NAME">
+ <gl-form-input
+ :value="job.image.name"
+ data-testid="image-name-input"
+ @input="$emit('update-job', 'image.name', $event)"
+ />
+ </gl-form-group>
+ <gl-form-group class="gl-flex-grow-1" :label="$options.i18n.IMAGE_ENTRYPOINT">
+ <gl-form-input
+ :value="job.image.entrypoint.join(' ')"
+ data-testid="image-entrypoint-input"
+ @input="$emit('update-job', 'image.entrypoint', $event.split(' '))"
+ />
+ </gl-form-group>
+ </div>
+ </gl-accordion-item>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item.vue b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item.vue
new file mode 100644
index 00000000000..a25b3ca09fd
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item.vue
@@ -0,0 +1,89 @@
+<script>
+import {
+ GlAccordionItem,
+ GlFormGroup,
+ GlFormInput,
+ GlFormTextarea,
+ GlTokenSelector,
+ GlFormCombobox,
+} from '@gitlab/ui';
+import { mapState } from 'vuex';
+import { i18n } from '../constants';
+
+export default {
+ i18n,
+ components: {
+ GlAccordionItem,
+ GlFormGroup,
+ GlFormInput,
+ GlFormTextarea,
+ GlFormCombobox,
+ GlTokenSelector,
+ },
+ props: {
+ tagOptions: {
+ type: Array,
+ required: true,
+ },
+ job: {
+ type: Object,
+ required: true,
+ },
+ isNameValid: {
+ type: Boolean,
+ required: true,
+ },
+ isScriptValid: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['availableStages']),
+ },
+};
+</script>
+<template>
+ <gl-accordion-item :title="$options.i18n.JOB_SETUP" visible>
+ <gl-form-group
+ :invalid-feedback="$options.i18n.THIS_FIELD_IS_REQUIRED"
+ :state="isNameValid"
+ :label="$options.i18n.JOB_NAME"
+ >
+ <gl-form-input
+ :value="job.name"
+ :state="isNameValid"
+ data-testid="job-name-input"
+ @input="$emit('update-job', 'name', $event)"
+ />
+ </gl-form-group>
+ <gl-form-combobox
+ :value="job.stage"
+ :token-list="availableStages"
+ :label-text="$options.i18n.STAGE"
+ data-testid="job-stage-input"
+ @input="$emit('update-job', 'stage', $event)"
+ />
+ <gl-form-group
+ :invalid-feedback="$options.i18n.THIS_FIELD_IS_REQUIRED"
+ :state="isScriptValid"
+ :label="$options.i18n.SCRIPT"
+ >
+ <gl-form-textarea
+ :value="job.script"
+ :state="isScriptValid"
+ :no-resize="false"
+ data-testid="job-script-input"
+ @input="$emit('update-job', 'script', $event)"
+ />
+ </gl-form-group>
+ <gl-form-group :label="$options.i18n.TAGS">
+ <gl-token-selector
+ :dropdown-items="tagOptions"
+ :selected-tokens="job.tags"
+ data-testid="job-tags-input"
+ @input="$emit('update-job', 'tags', $event)"
+ />
+ </gl-form-group>
+ </gl-accordion-item>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/constants.js b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/constants.js
index 1c122fd5e38..994a6e719fe 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/constants.js
+++ b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/constants.js
@@ -1,7 +1,41 @@
-import { s__ } from '~/locale';
+import { __, s__ } from '~/locale';
export const DRAWER_CONTAINER_CLASS = '.content-wrapper';
+export const JOB_TEMPLATE = {
+ name: '',
+ stage: '',
+ script: '',
+ tags: [],
+ image: {
+ name: '',
+ entrypoint: [''],
+ },
+ services: [
+ {
+ name: '',
+ entrypoint: [''],
+ },
+ ],
+ artifacts: {
+ paths: [''],
+ exclude: [''],
+ },
+ cache: {
+ paths: [''],
+ key: '',
+ },
+};
+
export const i18n = {
ADD_JOB: s__('JobAssistant|Add job'),
+ SCRIPT: s__('JobAssistant|Script'),
+ JOB_NAME: s__('JobAssistant|Job name'),
+ JOB_SETUP: s__('JobAssistant|Job Setup'),
+ STAGE: s__('JobAssistant|Stage (optional)'),
+ TAGS: s__('JobAssistant|Tags (optional)'),
+ IMAGE: s__('JobAssistant|Image'),
+ IMAGE_NAME: s__('JobAssistant|Image name (optional)'),
+ IMAGE_ENTRYPOINT: s__('JobAssistant|Image entrypoint (optional)'),
+ THIS_FIELD_IS_REQUIRED: __('This field is required'),
};
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer.vue b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer.vue
index 65c87df21cb..9f68b97b329 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer.vue
@@ -1,13 +1,25 @@
<script>
-import { GlDrawer, GlButton } from '@gitlab/ui';
+import { GlDrawer, GlAccordion, GlButton } from '@gitlab/ui';
+import { stringify } from 'yaml';
+import { mapMutations, mapState } from 'vuex';
+import { set, omit, trim } from 'lodash';
import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
-import { DRAWER_CONTAINER_CLASS, i18n } from './constants';
+import eventHub, { SCROLL_EDITOR_TO_BOTTOM } from '~/ci/pipeline_editor/event_hub';
+import { UPDATE_CI_CONFIG } from '~/ci/pipeline_editor/store/mutation_types';
+import getAllRunners from '~/ci/runner/graphql/list/all_runners.query.graphql';
+import { DRAWER_CONTAINER_CLASS, JOB_TEMPLATE, i18n } from './constants';
+import { removeEmptyObj, trimFields } from './utils';
+import JobSetupItem from './accordion_items/job_setup_item.vue';
+import ImageItem from './accordion_items/image_item.vue';
export default {
i18n,
components: {
GlDrawer,
+ GlAccordion,
GlButton,
+ JobSetupItem,
+ ImageItem,
},
props: {
isVisible: {
@@ -21,15 +33,84 @@ export default {
default: 200,
},
},
+ data() {
+ return {
+ isNameValid: true,
+ isScriptValid: true,
+ job: JSON.parse(JSON.stringify(JOB_TEMPLATE)),
+ };
+ },
+ apollo: {
+ runners: {
+ query: getAllRunners,
+ update(data) {
+ return data?.runners?.nodes || [];
+ },
+ },
+ },
computed: {
+ ...mapState(['currentCiFileContent']),
+ tagOptions() {
+ const options = [];
+ this.runners?.forEach((runner) => options.push(...runner.tagList));
+ return [...new Set(options)].map((tag) => {
+ return {
+ id: tag,
+ name: tag,
+ };
+ });
+ },
drawerHeightOffset() {
return getContentWrapperHeight(DRAWER_CONTAINER_CLASS);
},
},
methods: {
+ ...mapMutations({
+ updateCiConfig: UPDATE_CI_CONFIG,
+ }),
closeDrawer() {
+ this.clearJob();
this.$emit('close-job-assistant-drawer');
},
+ addCiConfig() {
+ this.isNameValid = this.validate(this.job.name);
+ this.isScriptValid = this.validate(this.job.script);
+
+ if (!this.isNameValid || !this.isScriptValid) {
+ return;
+ }
+
+ const newJobString = this.generateYmlString();
+ this.updateCiConfig(`${this.currentCiFileContent}\n${newJobString}`);
+ eventHub.$emit(SCROLL_EDITOR_TO_BOTTOM);
+
+ this.closeDrawer();
+ },
+ generateYmlString() {
+ let job = JSON.parse(JSON.stringify(this.job));
+ const jobName = job.name;
+ job = omit(job, ['name']);
+ job.tags = job.tags.map((tag) => tag.name); // Tag item is originally an option object, we need a string here to match `.gitlab-ci.yml` rules
+ const cleanedJob = trimFields(removeEmptyObj(job));
+ return stringify({ [jobName]: cleanedJob });
+ },
+ clearJob() {
+ this.job = JSON.parse(JSON.stringify(JOB_TEMPLATE));
+ this.isNameValid = true;
+ this.isScriptValid = true;
+ },
+ updateJob(key, value) {
+ set(this.job, key, value);
+ if (key === 'name') {
+ this.isNameValid = this.validate(this.job.name);
+ }
+ if (key === 'script') {
+ this.isScriptValid = this.validate(this.job.script);
+ }
+ },
+ validate(value) {
+ return trim(value) !== '';
+ },
},
};
</script>
@@ -44,6 +125,16 @@ export default {
<template #title>
<h2 class="gl-m-0 gl-font-lg">{{ $options.i18n.ADD_JOB }}</h2>
</template>
+ <gl-accordion :header-level="3">
+ <job-setup-item
+ :tag-options="tagOptions"
+ :job="job"
+ :is-name-valid="isNameValid"
+ :is-script-valid="isScriptValid"
+ @update-job="updateJob"
+ />
+ <image-item :job="job" @update-job="updateJob" />
+ </gl-accordion>
<template #footer>
<div class="gl-display-flex gl-justify-content-end">
<gl-button
@@ -51,11 +142,15 @@ export default {
class="gl-mr-3"
data-testid="cancel-button"
@click="closeDrawer"
- >{{ __('Cancel') }}</gl-button
- >
- <gl-button category="primary" variant="confirm" data-testid="confirm-button">{{
- __('Add')
- }}</gl-button>
+ >{{ __('Cancel') }}
+ </gl-button>
+ <gl-button
+ category="primary"
+ variant="confirm"
+ data-testid="confirm-button"
+ @click="addCiConfig"
+ >{{ __('Add') }}
+ </gl-button>
</div>
</template>
</gl-drawer>
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
new file mode 100644
index 00000000000..83e7574c4de
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/utils.js
@@ -0,0 +1,22 @@
+import { isEmpty, isObject, isArray, isString, reject, omitBy, mapValues, map, trim } from 'lodash';
+
+const isEmptyValue = (val) => (isObject(val) || isString(val)) && isEmpty(val);
+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)) {
+ return omitBy(mapValues(obj, removeEmptyObj), isEmptyValue);
+ }
+ return obj;
+};
+
+export const trimFields = (data) => {
+ if (isArray(data)) {
+ return data.map(trimFields);
+ } else if (isObject(data)) {
+ return mapValues(data, trimFields);
+ }
+ return trimText(data);
+};
diff --git a/app/assets/javascripts/ci/pipeline_editor/event_hub.js b/app/assets/javascripts/ci/pipeline_editor/event_hub.js
new file mode 100644
index 00000000000..c64eaf5ef5c
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/event_hub.js
@@ -0,0 +1,5 @@
+import createEventHub from '~/helpers/event_hub_factory';
+
+export default createEventHub();
+
+export const SCROLL_EDITOR_TO_BOTTOM = Symbol('scrollEditorToBottom');
diff --git a/app/assets/javascripts/ci/pipeline_editor/index.js b/app/assets/javascripts/ci/pipeline_editor/index.js
index 6d91c339833..d65a7c321ce 100644
--- a/app/assets/javascripts/ci/pipeline_editor/index.js
+++ b/app/assets/javascripts/ci/pipeline_editor/index.js
@@ -12,6 +12,7 @@ import getPipelineEtag from './graphql/queries/client/pipeline_etag.query.graphq
import { resolvers } from './graphql/resolvers';
import typeDefs from './graphql/typedefs.graphql';
import PipelineEditorApp from './pipeline_editor_app.vue';
+import createStore from './store';
export const initPipelineEditor = (selector = '#js-pipeline-editor') => {
const el = document.querySelector(selector);
@@ -29,12 +30,12 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => {
ciExamplesHelpPagePath,
ciHelpPagePath,
ciLintPath,
+ ciTroubleshootingPath,
defaultBranch,
emptyStateIllustrationPath,
helpPaths,
includesHelpPagePath,
lintHelpPagePath,
- lintUnavailableHelpPagePath,
needsHelpPagePath,
newMergeRequestPath,
pipelinePagePath,
@@ -111,14 +112,18 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => {
},
});
+ const store = createStore();
+
return new Vue({
el,
+ store,
apolloProvider,
provide: {
ciConfigPath,
ciExamplesHelpPagePath,
ciHelpPagePath,
ciLintPath,
+ ciTroubleshootingPath,
configurationPaths,
dataMethod: 'graphql',
defaultBranch,
@@ -126,7 +131,6 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => {
helpPaths,
includesHelpPagePath,
lintHelpPagePath,
- lintUnavailableHelpPagePath,
needsHelpPagePath,
newMergeRequestPath,
pipelinePagePath,
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 ff848a973e3..7b3c4d6f74f 100644
--- a/app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue
@@ -1,10 +1,12 @@
<script>
import { GlLoadingIcon, GlModal } from '@gitlab/ui';
+import { mapState, mapMutations } from 'vuex';
+import { parse } from 'yaml';
import { fetchPolicies } from '~/lib/graphql';
import { mergeUrlParams, queryToObject, redirectTo } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
-
import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
+import { UPDATE_CI_CONFIG, UPDATE_AVAILABLE_STAGES } from './store/mutation_types';
import ConfirmUnsavedChangesDialog from './components/ui/confirm_unsaved_changes_dialog.vue';
import PipelineEditorEmptyState from './components/ui/pipeline_editor_empty_state.vue';
@@ -44,7 +46,6 @@ export default {
data() {
return {
ciConfigData: {},
- currentCiFileContent: '',
failureType: null,
failureReasons: [],
hasBranchLoaded: false,
@@ -94,7 +95,7 @@ export default {
const fileContent = rawBlob ?? '';
this.lastCommittedContent = fileContent;
- this.currentCiFileContent = fileContent;
+ this.updateCiConfig(fileContent);
// If rawBlob is defined and returns a string, it means that there is
// a CI config file with empty content. If `rawBlob` is not defined
@@ -155,6 +156,10 @@ export default {
this.isLintUnavailable = false;
}
}
+
+ if (data?.ciConfig?.mergedYaml) {
+ this.updateAvailableStages(parse(data.ciConfig.mergedYaml).stages);
+ }
},
error() {
// We are not using `reportFailure` here because we don't
@@ -231,6 +236,7 @@ export default {
},
},
computed: {
+ ...mapState(['currentCiFileContent']),
hasUnsavedChanges() {
return this.lastCommittedContent !== this.currentCiFileContent;
},
@@ -294,6 +300,10 @@ export default {
this.checkShouldSkipStartScreen();
},
methods: {
+ ...mapMutations({
+ updateCiConfig: UPDATE_CI_CONFIG,
+ updateAvailableStages: UPDATE_AVAILABLE_STAGES,
+ }),
checkShouldSkipStartScreen() {
const params = queryToObject(window.location.search);
this.shouldSkipStartScreen = Boolean(params?.add_new_config_file);
@@ -344,7 +354,7 @@ export default {
},
resetContent() {
this.showResetConfirmationModal = false;
- this.currentCiFileContent = this.lastCommittedContent;
+ this.updateCiConfig(this.lastCommittedContent);
},
setAppStatus(appStatus) {
if (EDITOR_APP_VALID_STATUSES.includes(appStatus)) {
@@ -361,9 +371,6 @@ export default {
showErrorAlert({ type, reasons = [] }) {
this.reportFailure(type, reasons);
},
- updateCiConfig(ciFileContent) {
- this.currentCiFileContent = ciFileContent;
- },
updateCommitSha() {
this.isFetchingCommitSha = true;
this.$apollo.queries.commitSha.refetch();
diff --git a/app/assets/javascripts/ci/pipeline_editor/store/index.js b/app/assets/javascripts/ci/pipeline_editor/store/index.js
new file mode 100644
index 00000000000..d7d5aed79e2
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/store/index.js
@@ -0,0 +1,12 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import mutations from './mutations';
+import state from './state';
+
+Vue.use(Vuex);
+
+export default () =>
+ new Vuex.Store({
+ mutations,
+ state: state(),
+ });
diff --git a/app/assets/javascripts/ci/pipeline_editor/store/mutation_types.js b/app/assets/javascripts/ci/pipeline_editor/store/mutation_types.js
new file mode 100644
index 00000000000..035d3c90c14
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/store/mutation_types.js
@@ -0,0 +1,2 @@
+export const UPDATE_CI_CONFIG = 'UPDATE_CI_CONFIG';
+export const UPDATE_AVAILABLE_STAGES = 'UPDATE_AVAILABLE_STAGES';
diff --git a/app/assets/javascripts/ci/pipeline_editor/store/mutations.js b/app/assets/javascripts/ci/pipeline_editor/store/mutations.js
new file mode 100644
index 00000000000..552c1df9a2c
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/store/mutations.js
@@ -0,0 +1,10 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.UPDATE_CI_CONFIG](state, content) {
+ state.currentCiFileContent = content;
+ },
+ [types.UPDATE_AVAILABLE_STAGES](state, stages) {
+ state.availableStages = stages || [];
+ },
+};
diff --git a/app/assets/javascripts/ci/pipeline_editor/store/state.js b/app/assets/javascripts/ci/pipeline_editor/store/state.js
new file mode 100644
index 00000000000..34146cd54c4
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/store/state.js
@@ -0,0 +1,4 @@
+export default () => ({
+ currentCiFileContent: '',
+ availableStages: [],
+});
diff --git a/app/assets/javascripts/ci/pipeline_new/components/pipeline_new_form.vue b/app/assets/javascripts/ci/pipeline_new/components/pipeline_new_form.vue
index 8837b7a1917..5337d0da80c 100644
--- a/app/assets/javascripts/ci/pipeline_new/components/pipeline_new_form.vue
+++ b/app/assets/javascripts/ci/pipeline_new/components/pipeline_new_form.vue
@@ -43,6 +43,7 @@ const i18n = {
defaultError: __('Something went wrong on our end. Please try again.'),
refsLoadingErrorTitle: s__('Pipeline|Branches or tags could not be loaded.'),
submitErrorTitle: s__('Pipeline|Pipeline cannot be run.'),
+ configButtonTitle: s__('Pipelines|Go to the pipeline editor'),
warningTitle: __('The form contains the following warning:'),
maxWarningsSummary: __('%{total} warnings found: showing first %{warningsDisplayed}'),
removeVariableLabel: s__('CiVariables|Remove variable'),
@@ -81,6 +82,14 @@ export default {
type: String,
required: true,
},
+ pipelinesEditorPath: {
+ type: String,
+ required: true,
+ },
+ canViewPipelineEditor: {
+ type: Boolean,
+ required: true,
+ },
defaultBranch: {
type: String,
required: true,
@@ -373,9 +382,18 @@ export default {
:dismissible="false"
variant="danger"
class="gl-mb-4"
- data-testid="run-pipeline-error-alert"
>
- <span v-safe-html="error"></span>
+ <span v-safe-html="error" data-testid="run-pipeline-error-alert" class="block"></span>
+ <gl-button
+ v-if="canViewPipelineEditor"
+ class="gl-my-3"
+ data-testid="ci-cd-pipeline-configuration"
+ variant="confirm"
+ :aria-label="$options.i18n.configButtonTitle"
+ :href="pipelinesEditorPath"
+ >
+ {{ $options.i18n.configButtonTitle }}
+ </gl-button>
</gl-alert>
<gl-alert
v-if="shouldShowWarning"
diff --git a/app/assets/javascripts/ci/pipeline_new/index.js b/app/assets/javascripts/ci/pipeline_new/index.js
index 71c76aeab36..a466313a6cd 100644
--- a/app/assets/javascripts/ci/pipeline_new/index.js
+++ b/app/assets/javascripts/ci/pipeline_new/index.js
@@ -14,6 +14,8 @@ const mountPipelineNewForm = (el) => {
fileParam,
maxWarnings,
pipelinesPath,
+ pipelinesEditorPath,
+ canViewPipelineEditor,
projectId,
projectPath,
refParam,
@@ -43,6 +45,8 @@ const mountPipelineNewForm = (el) => {
fileParams,
maxWarnings: Number(maxWarnings),
pipelinesPath,
+ pipelinesEditorPath,
+ canViewPipelineEditor,
projectId,
projectPath,
refParam,
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue b/app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue
index 16bfc7f3abe..92c824fb5a1 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue
@@ -10,11 +10,11 @@ export default {
),
actionPrimary: {
text: s__('PipelineSchedules|Delete pipeline schedule'),
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
},
actionCancel: {
text: __('Cancel'),
- attributes: [],
+ attributes: {},
},
},
components: {
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue
index d03de91ea07..6695c6179cf 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue
@@ -70,10 +70,12 @@ export default {
},
update(data) {
const { pipelineSchedules: { nodes: list = [], count } = {} } = data.project || {};
+ const currentUser = data.currentUser || {};
return {
list,
count,
+ currentUser,
};
},
error() {
@@ -279,6 +281,7 @@ export default {
<pipeline-schedules-table
v-else
:schedules="schedules.list"
+ :current-user="schedules.currentUser"
@showTakeOwnershipModal="setTakeOwnershipModal"
@showDeleteModal="setDeleteModal"
@playPipelineSchedule="playPipelineSchedule"
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue
index 45b4f618e17..5bd58bfd95d 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue
@@ -23,13 +23,20 @@ export default {
type: Object,
required: true,
},
+ currentUser: {
+ type: Object,
+ required: true,
+ },
},
computed: {
canPlay() {
return this.schedule.userPermissions.playPipelineSchedule;
},
+ isCurrentUserOwner() {
+ return this.schedule.owner.username === this.currentUser.username;
+ },
canTakeOwnership() {
- return this.schedule.userPermissions.takeOwnershipPipelineSchedule;
+ return !this.isCurrentUserOwner && this.schedule.userPermissions.adminPipelineSchedule;
},
canUpdate() {
return this.schedule.userPermissions.updatePipelineSchedule;
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue
index e8cfc5b29f3..0b95e2037e8 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue
@@ -59,6 +59,10 @@ export default {
type: Array,
required: true,
},
+ currentUser: {
+ type: Object,
+ required: true,
+ },
},
};
</script>
@@ -94,6 +98,7 @@ export default {
<template #cell(actions)="{ item }">
<pipeline-schedule-actions
:schedule="item"
+ :current-user="currentUser"
@showTakeOwnershipModal="$emit('showTakeOwnershipModal', $event)"
@showDeleteModal="$emit('showDeleteModal', $event)"
@playPipelineSchedule="$emit('playPipelineSchedule', $event)"
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue
index 3ac52d4735d..7863b0e3ef0 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue
@@ -27,12 +27,10 @@ export default {
actionPrimary() {
return {
text: this.$options.i18n.takeOwnership,
- attributes: [
- {
- variant: 'confirm',
- category: 'primary',
- },
- ],
+ attributes: {
+ variant: 'confirm',
+ category: 'primary',
+ },
};
},
},
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
index 7ded3945a32..b4d84309c5f 100644
--- 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
@@ -27,14 +27,12 @@ export default {
actionPrimary() {
return {
text: this.$options.i18n.takeOwnership,
- attributes: [
- {
- variant: 'confirm',
- category: 'primary',
- href: this.ownershipUrl,
- 'data-method': 'post',
- },
- ],
+ attributes: {
+ variant: 'confirm',
+ category: 'primary',
+ href: this.ownershipUrl,
+ 'data-method': 'post',
+ },
};
},
},
diff --git a/app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql b/app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
index 9f6cb429cca..6167c7dc577 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
@@ -1,4 +1,8 @@
query getPipelineSchedulesQuery($projectPath: ID!, $status: PipelineScheduleStatus) {
+ currentUser {
+ id
+ username
+ }
project(fullPath: $projectPath) {
id
pipelineSchedules(status: $status) {
@@ -25,13 +29,13 @@ query getPipelineSchedulesQuery($projectPath: ID!, $status: PipelineScheduleStat
realNextRun
owner {
id
+ username
avatarUrl
name
webPath
}
userPermissions {
playPipelineSchedule
- takeOwnershipPipelineSchedule
updatePipelineSchedule
adminPipelineSchedule
}
diff --git a/app/assets/javascripts/ci/reports/constants.js b/app/assets/javascripts/ci/reports/constants.js
index bad6fa1e7b9..1137236d355 100644
--- a/app/assets/javascripts/ci/reports/constants.js
+++ b/app/assets/javascripts/ci/reports/constants.js
@@ -1,10 +1,3 @@
-export const fieldTypes = {
- codeBlock: 'codeBlock',
- link: 'link',
- seconds: 'seconds',
- text: 'text',
-};
-
export const LOADING = 'LOADING';
export const ERROR = 'ERROR';
export const SUCCESS = 'SUCCESS';
@@ -15,10 +8,6 @@ export const STATUS_NEUTRAL = 'neutral';
export const STATUS_NOT_FOUND = 'not_found';
export const ICON_WARNING = 'warning';
-export const ICON_SUCCESS = 'success';
-export const ICON_NOTFOUND = 'notfound';
-export const ICON_PENDING = 'pending';
-export const ICON_FAILED = 'failed';
export const status = {
LOADING,
@@ -26,9 +15,6 @@ export const status = {
SUCCESS,
};
-export const ACCESSIBILITY_ISSUE_ERROR = 'error';
-export const ACCESSIBILITY_ISSUE_WARNING = 'warning';
-
/**
* Slot names for the ReportSection component, corresponding to the success,
* loading and error statuses.
diff --git a/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue b/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
index 5401c7c1c28..79600012838 100644
--- a/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
+++ b/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
@@ -1,9 +1,13 @@
<script>
import { GlSprintf, GlLink, GlModalDirective } from '@gitlab/ui';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
+import { redirectTo, setUrlParams } from '~/lib/utils/url_utility';
+import { s__ } from '~/locale';
import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
import RunnerPlatformsRadioGroup from '~/ci/runner/components/runner_platforms_radio_group.vue';
-import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
-import { DEFAULT_PLATFORM, DEFAULT_ACCESS_LEVEL } from '../constants';
+import RunnerCreateForm from '~/ci/runner/components/runner_create_form.vue';
+import { DEFAULT_PLATFORM, PARAM_KEY_PLATFORM } from '../constants';
+import { saveAlertToLocalStorage } from '../local_storage_alert/save_alert_to_local_storage';
export default {
name: 'AdminNewRunnerApp',
@@ -12,7 +16,7 @@ export default {
GlSprintf,
RunnerInstructionsModal,
RunnerPlatformsRadioGroup,
- RunnerFormFields,
+ RunnerCreateForm,
},
directives: {
GlModal: GlModalDirective,
@@ -26,17 +30,24 @@ export default {
data() {
return {
platform: DEFAULT_PLATFORM,
- runner: {
- description: '',
- maintenanceNote: '',
- paused: false,
- accessLevel: DEFAULT_ACCESS_LEVEL,
- runUntagged: false,
- tagList: '',
- maximumTimeout: ' ',
- },
};
},
+ methods: {
+ onSaved(runner) {
+ const registerUrl = setUrlParams(
+ { [PARAM_KEY_PLATFORM]: this.platform },
+ runner.registerAdminUrl,
+ );
+ saveAlertToLocalStorage({
+ message: s__('Runners|Runner created.'),
+ variant: VARIANT_SUCCESS,
+ });
+ redirectTo(registerUrl);
+ },
+ onError(error) {
+ createAlert({ message: error.message });
+ },
+ },
modalId: 'runners-legacy-registration-instructions-modal',
};
</script>
@@ -73,6 +84,6 @@ export default {
<hr aria-hidden="true" />
- <runner-form-fields v-model="runner" />
+ <runner-create-form @saved="onSaved" @error="onError" />
</div>
</template>
diff --git a/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue b/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue
new file mode 100644
index 00000000000..cd38dc07157
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue
@@ -0,0 +1,69 @@
+<script>
+import { GlButton } from '@gitlab/ui';
+import { getParameterByName, updateHistory, mergeUrlParams } from '~/lib/utils/url_utility';
+import { PARAM_KEY_PLATFORM, DEFAULT_PLATFORM } from '../constants';
+import RegistrationInstructions from '../components/registration/registration_instructions.vue';
+import PlatformsDrawer from '../components/registration/platforms_drawer.vue';
+
+export default {
+ name: 'AdminRegisterRunnerApp',
+ components: {
+ GlButton,
+ RegistrationInstructions,
+ PlatformsDrawer,
+ },
+ props: {
+ runnerId: {
+ type: String,
+ required: true,
+ },
+ runnersPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ platform: getParameterByName(PARAM_KEY_PLATFORM) || DEFAULT_PLATFORM,
+ isDrawerOpen: false,
+ };
+ },
+ watch: {
+ platform(platform) {
+ updateHistory({
+ url: mergeUrlParams({ [PARAM_KEY_PLATFORM]: platform }, window.location.href),
+ });
+ },
+ },
+ methods: {
+ onSelectPlatform(platform) {
+ this.platform = platform;
+ },
+ onToggleDrawer(val = !this.isDrawerOpen) {
+ this.isDrawerOpen = val;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <registration-instructions
+ :runner-id="runnerId"
+ :platform="platform"
+ @toggleDrawer="onToggleDrawer"
+ >
+ <template #runner-list-name>{{ s__('Runners|Admin area › Runners') }}</template>
+ </registration-instructions>
+
+ <platforms-drawer
+ :platform="platform"
+ :open="isDrawerOpen"
+ @selectPlatform="onSelectPlatform"
+ @close="onToggleDrawer(false)"
+ />
+
+ <gl-button :href="runnersPath" variant="confirm">{{
+ s__('Runners|Go to runners page')
+ }}</gl-button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/admin_register_runner/index.js b/app/assets/javascripts/ci/runner/admin_register_runner/index.js
new file mode 100644
index 00000000000..bd43a5e8ce9
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/admin_register_runner/index.js
@@ -0,0 +1,36 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage';
+import AdminRegisterRunnerApp from './admin_register_runner_app.vue';
+
+Vue.use(VueApollo);
+
+export const initAdminRegisterRunner = (selector = '#js-admin-register-runner') => {
+ showAlertFromLocalStorage();
+
+ const el = document.querySelector(selector);
+
+ if (!el) {
+ return null;
+ }
+
+ const { runnerId, runnersPath } = el.dataset;
+
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+ });
+
+ return new Vue({
+ el,
+ apolloProvider,
+ render(h) {
+ return h(AdminRegisterRunnerApp, {
+ props: {
+ runnerId,
+ runnersPath,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue b/app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue
index 8d4303778af..36fb1cee525 100644
--- a/app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue
+++ b/app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue
@@ -1,5 +1,5 @@
<script>
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { TYPENAME_CI_RUNNER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { redirectTo } from '~/lib/utils/url_utility';
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 ce2c511ddd4..d452adb34d9 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
@@ -1,6 +1,6 @@
<script>
import { GlButton, GlLink } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { updateHistory } from '~/lib/utils/url_utility';
import { fetchPolicies } from '~/lib/graphql';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -128,8 +128,8 @@ export default {
return isSearchFiltered(this.search);
},
shouldShowCreateRunnerWorkflow() {
- // create_runner_workflow feature flag
- return this.glFeatures.createRunnerWorkflow;
+ // create_runner_workflow_for_admin feature flag
+ return this.glFeatures.createRunnerWorkflowForAdmin;
},
},
watch: {
diff --git a/app/assets/javascripts/ci/runner/components/registration/cli_command.vue b/app/assets/javascripts/ci/runner/components/registration/cli_command.vue
new file mode 100644
index 00000000000..95b135c83a7
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/cli_command.vue
@@ -0,0 +1,42 @@
+<script>
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+export default {
+ components: {
+ ClipboardButton,
+ },
+ props: {
+ prompt: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ command: {
+ type: [Array, String],
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ lines() {
+ if (typeof this.command === 'string') {
+ return [this.command];
+ }
+ return this.command;
+ },
+ clipboard() {
+ return this.lines.join('');
+ },
+ },
+};
+</script>
+<template>
+ <div class="gl-display-flex gl-gap-3 gl-align-items-flex-start">
+ <!-- eslint-disable vue/require-v-for-key-->
+ <pre
+ class="gl-w-full"
+ ><span v-if="prompt" class="gl-user-select-none">{{ prompt }} </span><template v-for="line in lines">{{ line }}<br class="gl-user-select-none"/></template></pre>
+ <!-- eslint-enable vue/require-v-for-key-->
+ <clipboard-button :text="clipboard" :title="__('Copy')" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/registration/platforms_drawer.vue b/app/assets/javascripts/ci/runner/components/registration/platforms_drawer.vue
new file mode 100644
index 00000000000..ff182c61ccf
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/platforms_drawer.vue
@@ -0,0 +1,135 @@
+<script>
+import { GlDrawer, GlFormGroup, GlFormSelect, GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
+import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
+import { DRAWER_Z_INDEX } from '~/lib/utils/constants';
+
+import {
+ DEFAULT_PLATFORM,
+ MACOS_PLATFORM,
+ LINUX_PLATFORM,
+ WINDOWS_PLATFORM,
+ INSTALL_HELP_URL,
+} from '../../constants';
+import { installScript, platformArchitectures } from './utils';
+
+import CliCommand from './cli_command.vue';
+
+export default {
+ components: {
+ GlDrawer,
+ GlFormGroup,
+ GlFormSelect,
+ GlIcon,
+ GlLink,
+ GlSprintf,
+ CliCommand,
+ },
+ props: {
+ open: {
+ type: Boolean,
+ required: true,
+ },
+ platform: {
+ type: String,
+ required: false,
+ default: DEFAULT_PLATFORM,
+ },
+ },
+ data() {
+ return {
+ selectedPlatform: this.platform,
+ selectedArchitecture: null,
+ };
+ },
+ computed: {
+ drawerHeightOffset() {
+ return getContentWrapperHeight('.content-wrapper');
+ },
+ architectureOptions() {
+ return platformArchitectures({ platform: this.selectedPlatform });
+ },
+ script() {
+ return installScript({
+ platform: this.selectedPlatform,
+ architecture: this.selectedArchitecture,
+ });
+ },
+ },
+ watch: {
+ selectedPlatform() {
+ this.selectedArchitecture =
+ this.architectureOptions.find((value) => value === this.selectedArchitecture) ||
+ this.architectureOptions[0];
+
+ this.$emit('selectPlatform', this.selectedPlatform);
+ },
+ },
+ created() {
+ [this.selectedArchitecture] = this.architectureOptions;
+ },
+ methods: {
+ onClose() {
+ this.$emit('close');
+ },
+ },
+ platformOptions: [
+ /* eslint-disable @gitlab/require-i18n-strings */
+ { value: LINUX_PLATFORM, text: 'Linux' },
+ { value: MACOS_PLATFORM, text: 'macOS' },
+ { value: WINDOWS_PLATFORM, text: 'Windows' },
+ /* eslint-enable @gitlab/require-i18n-strings */
+ ],
+ INSTALL_HELP_URL,
+ DRAWER_Z_INDEX,
+};
+</script>
+<template>
+ <gl-drawer
+ :open="open"
+ :header-height="drawerHeightOffset"
+ :z-index="$options.DRAWER_Z_INDEX"
+ data-testid="runner-platforms-drawer"
+ @close="onClose"
+ >
+ <template #title>
+ <h2 class="gl-my-0 gl-font-size-h2 gl-line-height-24">
+ {{ s__('Runners|Install GitLab Runner') }}
+ </h2>
+ </template>
+ <div>
+ <p>{{ s__('Runners|Select platform specifications to install GitLab Runner.') }}</p>
+
+ <gl-form-group :label="s__('Runners|Environment')" label-for="runner-environment-select">
+ <gl-form-select
+ id="runner-environment-select"
+ v-model="selectedPlatform"
+ :options="$options.platformOptions"
+ />
+ </gl-form-group>
+
+ <gl-form-group :label="s__('Runners|Architecture')" label-for="runner-architecture-select">
+ <gl-form-select
+ id="runner-architecture-select"
+ v-model="selectedArchitecture"
+ :options="architectureOptions"
+ />
+ </gl-form-group>
+
+ <cli-command :command="script" />
+
+ <p>
+ <gl-sprintf
+ :message="
+ s__('Runners|See more %{linkStart}installation methods and architectures%{linkEnd}.')
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="$options.INSTALL_HELP_URL">
+ {{ content }} <gl-icon name="external-link" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </div>
+ </gl-drawer>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue b/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue
new file mode 100644
index 00000000000..2f3c172666d
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue
@@ -0,0 +1,241 @@
+<script>
+import { GlIcon, GlLink, GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import { createAlert } from '~/alert';
+import { s__, sprintf } from '~/locale';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { TYPENAME_CI_RUNNER } from '~/graphql_shared/constants';
+
+import runnerForRegistrationQuery from '../../graphql/register/runner_for_registration.query.graphql';
+import {
+ STATUS_ONLINE,
+ EXECUTORS_HELP_URL,
+ SERVICE_COMMANDS_HELP_URL,
+ RUNNER_REGISTRATION_POLLING_INTERVAL_MS,
+ I18N_FETCH_ERROR,
+ I18N_REGISTRATION_SUCCESS,
+} from '../../constants';
+import { captureException } from '../../sentry_utils';
+
+import CliCommand from './cli_command.vue';
+import { commandPrompt, registerCommand, runCommand } from './utils';
+
+export default {
+ name: 'RegistrationInstructions',
+ components: {
+ GlIcon,
+ GlLink,
+ GlSkeletonLoader,
+ GlSprintf,
+ ClipboardButton,
+ CliCommand,
+ },
+ props: {
+ runnerId: {
+ type: String,
+ required: true,
+ },
+ platform: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ runner: null,
+ token: null,
+ };
+ },
+ apollo: {
+ runner: {
+ query: runnerForRegistrationQuery,
+ variables() {
+ return {
+ id: convertToGraphQLId(TYPENAME_CI_RUNNER, this.runnerId),
+ };
+ },
+ manual: true,
+ result({ data }) {
+ if (data?.runner) {
+ const { ephemeralAuthenticationToken, ...runner } = data.runner;
+ this.runner = runner;
+
+ // The token is available in the API for a limited amount of time
+ // preserve its original value if it is missing after polling.
+ this.token = ephemeralAuthenticationToken || this.token;
+ }
+ },
+ error(error) {
+ createAlert({ message: I18N_FETCH_ERROR });
+ captureException({ error, component: this.$options.name });
+ },
+ pollInterval() {
+ if (this.runner?.status === STATUS_ONLINE) {
+ // stop polling
+ return 0;
+ }
+ return RUNNER_REGISTRATION_POLLING_INTERVAL_MS;
+ },
+ },
+ },
+ computed: {
+ loading() {
+ return this.$apollo.queries.runner.loading;
+ },
+ description() {
+ return this.runner?.description;
+ },
+ heading() {
+ if (this.description) {
+ return sprintf(
+ s__('Runners|Register "%{runnerDescription}" runner'),
+ {
+ runnerDescription: this.description,
+ },
+ false,
+ );
+ }
+ return s__('Runners|Register runner');
+ },
+ status() {
+ return this.runner?.status;
+ },
+ tokenMessage() {
+ if (this.token) {
+ return s__(
+ '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.',
+ );
+ }
+ return s__(
+ '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.',
+ );
+ },
+ commandPrompt() {
+ return commandPrompt({ platform: this.platform });
+ },
+ registerCommand() {
+ return registerCommand({
+ platform: this.platform,
+ registrationToken: this.token,
+ description: this.description,
+ });
+ },
+ runCommand() {
+ return runCommand({ platform: this.platform });
+ },
+ },
+ methods: {
+ toggleDrawer() {
+ this.$emit('toggleDrawer');
+ },
+ },
+ EXECUTORS_HELP_URL,
+ SERVICE_COMMANDS_HELP_URL,
+ STATUS_ONLINE,
+ I18N_REGISTRATION_SUCCESS,
+};
+</script>
+<template>
+ <div>
+ <h1 class="gl-font-size-h1">{{ heading }}</h1>
+
+ <p>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|GitLab Runner must be installed before you can register a runner. %{linkStart}How do I install GitLab Runner?%{linkEnd}',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link data-testid="runner-install-link" @click="toggleDrawer">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+
+ <section>
+ <h2 class="gl-font-size-h2">{{ s__('Runners|Step 1') }}</h2>
+ <p>
+ {{
+ s__(
+ 'Runners|Copy and paste the following command into your command line to register the runner.',
+ )
+ }}
+ </p>
+ <gl-skeleton-loader v-if="loading" />
+ <template v-else>
+ <cli-command :prompt="commandPrompt" :command="registerCommand" />
+ <p>
+ <gl-icon name="information-o" class="gl-text-blue-600!" />
+ <gl-sprintf :message="tokenMessage">
+ <template #token>
+ <code data-testid="runner-token">{{ token }}</code>
+ <clipboard-button
+ :text="token"
+ :title="__('Copy')"
+ size="small"
+ category="tertiary"
+ class="gl-border-none!"
+ />
+ </template>
+ <template #bold="{ content }"
+ ><span class="gl-font-weight-bold">{{ content }}</span></template
+ >
+ <template #code="{ content }"
+ ><code>{{ content }}</code></template
+ >
+ </gl-sprintf>
+ </p>
+ </template>
+ </section>
+ <section>
+ <h2 class="gl-font-size-h2">{{ s__('Runners|Step 2') }}</h2>
+ <p>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|Choose an executor when prompted by the command line. Executors run builds in different environments. %{linkStart}Not sure which one to select?%{linkEnd}',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="$options.EXECUTORS_HELP_URL" target="_blank">
+ {{ content }} <gl-icon name="external-link" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </section>
+ <section>
+ <h2 class="gl-font-size-h2">{{ s__('Runners|Step 3 (optional)') }}</h2>
+ <p>{{ s__('Runners|Manually verify that the runner is available to pick up jobs.') }}</p>
+ <cli-command :prompt="commandPrompt" :command="runCommand" />
+ <p>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|This may not be needed if you manage your runner as a %{linkStart}system or user service%{linkEnd}.',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="$options.SERVICE_COMMANDS_HELP_URL" target="_blank">
+ {{ content }} <gl-icon name="external-link" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </section>
+ <section v-if="status == $options.STATUS_ONLINE">
+ <h2 class="gl-font-size-h2">🎉 {{ $options.I18N_REGISTRATION_SUCCESS }}</h2>
+
+ <p class="gl-pl-6">
+ <gl-sprintf :message="s__('Runners|To view the runner, go to %{runnerListName}.')">
+ <template #runnerListName>
+ <span class="gl-font-weight-bold"><slot name="runner-list-name"></slot></span>
+ </template>
+ </gl-sprintf>
+ </p>
+ </section>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue b/app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue
index ac2793654c8..6ce88fc54de 100644
--- a/app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue
@@ -1,6 +1,6 @@
<script>
import { GlDropdownItem, GlLoadingIcon, GlModal, GlModalDirective } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPENAME_GROUP, TYPENAME_PROJECT } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { __, s__ } from '~/locale';
@@ -73,13 +73,13 @@ export default {
actionPrimary() {
return {
text: i18n.modalAction,
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
};
},
actionSecondary() {
return {
text: i18n.modalCancel,
- attributes: [{ variant: 'default' }],
+ attributes: { variant: 'default' },
};
},
},
diff --git a/app/assets/javascripts/ci/runner/components/registration/scripts/linux/install.sh b/app/assets/javascripts/ci/runner/components/registration/scripts/linux/install.sh
new file mode 100644
index 00000000000..a8ba2592128
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/scripts/linux/install.sh
@@ -0,0 +1,12 @@
+# Download the binary for your system
+sudo curl -L --output /usr/local/bin/gitlab-runner ${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}
+
+# Give it permission to execute
+sudo chmod +x /usr/local/bin/gitlab-runner
+
+# Create a GitLab Runner user
+sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
+
+# Install and run as a service
+sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
+sudo gitlab-runner start
diff --git a/app/assets/javascripts/ci/runner/components/registration/scripts/osx/install.sh b/app/assets/javascripts/ci/runner/components/registration/scripts/osx/install.sh
new file mode 100644
index 00000000000..76c893bacfc
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/scripts/osx/install.sh
@@ -0,0 +1,11 @@
+# Download the binary for your system
+sudo curl --output /usr/local/bin/gitlab-runner ${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}
+
+# Give it permission to execute
+sudo chmod +x /usr/local/bin/gitlab-runner
+
+# The rest of the commands execute as the user who will run the runner
+# Register the runner (steps below), then run
+cd ~
+gitlab-runner install
+gitlab-runner start
diff --git a/app/assets/javascripts/ci/runner/components/registration/scripts/windows/install.ps1 b/app/assets/javascripts/ci/runner/components/registration/scripts/windows/install.ps1
new file mode 100644
index 00000000000..019363fc3f7
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/scripts/windows/install.ps1
@@ -0,0 +1,13 @@
+# Run PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/starting-windows-powershell?view=powershell-7#with-administrative-privileges-run-as-administrator
+# Create a folder somewhere on your system, for example: C:\GitLab-Runner
+New-Item -Path 'C:\GitLab-Runner' -ItemType Directory
+
+# Change to the folder
+cd 'C:\GitLab-Runner'
+
+# Download binary
+Invoke-WebRequest -Uri "${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}" -OutFile "gitlab-runner.exe"
+
+# Register the runner (steps below), then run
+.\gitlab-runner.exe install
+.\gitlab-runner.exe start
diff --git a/app/assets/javascripts/ci/runner/components/registration/utils.js b/app/assets/javascripts/ci/runner/components/registration/utils.js
new file mode 100644
index 00000000000..94d75bc4562
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/utils.js
@@ -0,0 +1,109 @@
+/* eslint-disable @gitlab/require-i18n-strings */
+import {
+ DEFAULT_PLATFORM,
+ LINUX_PLATFORM,
+ MACOS_PLATFORM,
+ WINDOWS_PLATFORM,
+ DOWNLOAD_LOCATIONS,
+} from '../../constants';
+import linuxInstall from './scripts/linux/install.sh?raw';
+import osxInstall from './scripts/osx/install.sh?raw';
+import windowsInstall from './scripts/windows/install.ps1?raw';
+
+const OS = {
+ [LINUX_PLATFORM]: {
+ shell: 'bash',
+ commandPrompt: '$',
+ executable: 'gitlab-runner',
+ },
+ [MACOS_PLATFORM]: {
+ shell: 'bash',
+ commandPrompt: '$',
+ executable: 'gitlab-runner',
+ },
+ [WINDOWS_PLATFORM]: {
+ shell: 'powershell',
+ commandPrompt: '>',
+ executable: '.\\gitlab-runner.exe',
+ },
+};
+
+const escapedParam = (param, shell = 'bash') => {
+ let escaped;
+ if (shell === 'bash') {
+ // replace single-quotes by the sequence '\''
+ escaped = param.replaceAll("'", "'\\''");
+ } else if (shell === 'powershell') {
+ // replace single-quotes by the sequence ''
+ // https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7.3
+ escaped = param.replaceAll("'", "''");
+ }
+ // surround with single quotes.
+ return `'${escaped}'`;
+};
+
+export const commandPrompt = ({ platform }) => {
+ return (OS[platform] || OS[DEFAULT_PLATFORM]).commandPrompt;
+};
+
+export const executable = ({ platform }) => {
+ return (OS[platform] || OS[DEFAULT_PLATFORM]).executable;
+};
+
+const shell = ({ platform }) => {
+ return (OS[platform] || OS[DEFAULT_PLATFORM]).shell;
+};
+
+export const registerCommand = ({
+ platform,
+ url = gon.gitlab_url,
+ registrationToken,
+ description,
+}) => {
+ const lines = [`${executable({ platform })} register`];
+ if (url) {
+ lines.push(` --url ${url}`);
+ }
+ if (registrationToken) {
+ lines.push(` --registration-token ${registrationToken}`);
+ }
+ if (description) {
+ const escapedDescription = escapedParam(description, shell({ platform }));
+ lines.push(` --description ${escapedDescription}`);
+ }
+ return lines;
+};
+
+export const runCommand = ({ platform }) => {
+ return `${executable({ platform })} run`;
+};
+
+const importInstallScript = ({ platform = DEFAULT_PLATFORM }) => {
+ switch (platform) {
+ case LINUX_PLATFORM:
+ return linuxInstall;
+ case MACOS_PLATFORM:
+ return osxInstall;
+ case WINDOWS_PLATFORM:
+ return windowsInstall;
+ default:
+ return '';
+ }
+};
+
+export const platformArchitectures = ({ platform }) => {
+ return DOWNLOAD_LOCATIONS[platform].map(({ arch }) => arch);
+};
+
+export const installScript = ({ platform, architecture }) => {
+ const downloadLocation = DOWNLOAD_LOCATIONS[platform].find(({ arch }) => arch === architecture)
+ .url;
+
+ return importInstallScript({ platform })
+ .replace(
+ // eslint-disable-next-line no-template-curly-in-string
+ '${GITLAB_CI_RUNNER_DOWNLOAD_LOCATION}',
+ downloadLocation,
+ )
+ .trim();
+};
diff --git a/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue b/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue
index 8dde3ac4e19..e7b26ec6d4e 100644
--- a/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue
@@ -1,6 +1,6 @@
<script>
import { GlButton, GlModalDirective, GlModal, GlSprintf } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, s__, n__, sprintf } from '~/locale';
import checkedRunnerIdsQuery from '../graphql/list/checked_runner_ids.query.graphql';
import BulkRunnerDelete from '../graphql/list/bulk_runner_delete.mutation.graphql';
diff --git a/app/assets/javascripts/ci/runner/components/runner_create_form.vue b/app/assets/javascripts/ci/runner/components/runner_create_form.vue
new file mode 100644
index 00000000000..5d2a3c53842
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_create_form.vue
@@ -0,0 +1,71 @@
+<script>
+import { GlForm, GlButton } from '@gitlab/ui';
+import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
+import runnerCreateMutation from '~/ci/runner/graphql/new/runner_create.mutation.graphql';
+import { modelToUpdateMutationVariables } from 'ee_else_ce/ci/runner/runner_update_form_utils';
+import { captureException } from '../sentry_utils';
+import { DEFAULT_ACCESS_LEVEL } from '../constants';
+
+export default {
+ name: 'RunnerCreateForm',
+ components: {
+ GlForm,
+ GlButton,
+ RunnerFormFields,
+ },
+ data() {
+ return {
+ saving: false,
+ runner: {
+ description: '',
+ maintenanceNote: '',
+ paused: false,
+ accessLevel: DEFAULT_ACCESS_LEVEL,
+ runUntagged: false,
+ tagList: '',
+ maximumTimeout: '',
+ },
+ };
+ },
+ methods: {
+ async onSubmit() {
+ this.saving = true;
+ try {
+ const {
+ data: {
+ runnerCreate: { errors, runner },
+ },
+ } = await this.$apollo.mutate({
+ mutation: runnerCreateMutation,
+ variables: modelToUpdateMutationVariables(this.runner),
+ });
+
+ if (errors?.length) {
+ this.$emit('error', new Error(errors.join(' ')));
+ } else {
+ this.onSuccess(runner);
+ }
+ } catch (error) {
+ captureException({ error, component: this.$options.name });
+ this.$emit('error', error);
+ } finally {
+ this.saving = false;
+ }
+ },
+ onSuccess(runner) {
+ this.$emit('saved', runner);
+ },
+ },
+};
+</script>
+<template>
+ <gl-form @submit.prevent="onSubmit">
+ <runner-form-fields v-model="runner" />
+
+ <div class="gl-display-flex">
+ <gl-button type="submit" variant="confirm" class="js-no-auto-disable" :loading="saving">
+ {{ __('Submit') }}
+ </gl-button>
+ </div>
+ </gl-form>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/runner_delete_button.vue b/app/assets/javascripts/ci/runner/components/runner_delete_button.vue
index f02e6bce5c3..020487fc727 100644
--- a/app/assets/javascripts/ci/runner/components/runner_delete_button.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_delete_button.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
import runnerDeleteMutation from '~/ci/runner/graphql/shared/runner_delete.mutation.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { sprintf, s__ } from '~/locale';
import { captureException } from '~/ci/runner/sentry_utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
diff --git a/app/assets/javascripts/ci/runner/components/runner_jobs.vue b/app/assets/javascripts/ci/runner/components/runner_jobs.vue
index 9003eba3636..f5287f597ab 100644
--- a/app/assets/javascripts/ci/runner/components/runner_jobs.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_jobs.vue
@@ -1,6 +1,6 @@
<script>
import { GlSkeletonLoader } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import runnerJobsQuery from '../graphql/show/runner_jobs.query.graphql';
import { I18N_FETCH_ERROR, I18N_NO_JOBS_FOUND, RUNNER_DETAILS_JOBS_PAGE_SIZE } from '../constants';
import { captureException } from '../sentry_utils';
diff --git a/app/assets/javascripts/ci/runner/components/runner_list_empty_state.vue b/app/assets/javascripts/ci/runner/components/runner_list_empty_state.vue
index d2f7912fabb..2cff11c1aa1 100644
--- a/app/assets/javascripts/ci/runner/components/runner_list_empty_state.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_list_empty_state.vue
@@ -43,8 +43,8 @@ export default {
},
computed: {
shouldShowCreateRunnerWorkflow() {
- // create_runner_workflow feature flag
- return this.newRunnerPath && this.glFeatures?.createRunnerWorkflow;
+ // create_runner_workflow_for_admin feature flag
+ return this.newRunnerPath && this.glFeatures?.createRunnerWorkflowForAdmin;
},
},
modalId: 'runners-empty-state-instructions-modal',
diff --git a/app/assets/javascripts/ci/runner/components/runner_pause_button.vue b/app/assets/javascripts/ci/runner/components/runner_pause_button.vue
index 2c80518e772..a27af232e97 100644
--- a/app/assets/javascripts/ci/runner/components/runner_pause_button.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_pause_button.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import runnerToggleActiveMutation from '~/ci/runner/graphql/shared/runner_toggle_active.mutation.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { captureException } from '~/ci/runner/sentry_utils';
import { I18N_PAUSE, I18N_PAUSE_TOOLTIP, I18N_RESUME, I18N_RESUME_TOOLTIP } from '../constants';
diff --git a/app/assets/javascripts/ci/runner/components/runner_projects.vue b/app/assets/javascripts/ci/runner/components/runner_projects.vue
index 4a6e90b44a9..4cfc57340f5 100644
--- a/app/assets/javascripts/ci/runner/components/runner_projects.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_projects.vue
@@ -1,7 +1,7 @@
<script>
import { GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
import { sprintf, formatNumber } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import runnerProjectsQuery from '../graphql/show/runner_projects.query.graphql';
import {
I18N_ASSIGNED_PROJECTS,
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 a9790d06ca7..dd8e965cecd 100644
--- a/app/assets/javascripts/ci/runner/components/runner_update_form.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_update_form.vue
@@ -13,7 +13,7 @@ import {
modelToUpdateMutationVariables,
runnerToModel,
} from 'ee_else_ce/ci/runner/runner_update_form_utils';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import { captureException } from '~/ci/runner/sentry_utils';
diff --git a/app/assets/javascripts/ci/runner/components/search_tokens/tag_token.vue b/app/assets/javascripts/ci/runner/components/search_tokens/tag_token.vue
index 6e7c41885f8..1de7775090a 100644
--- a/app/assets/javascripts/ci/runner/components/search_tokens/tag_token.vue
+++ b/app/assets/javascripts/ci/runner/components/search_tokens/tag_token.vue
@@ -1,6 +1,6 @@
<script>
import { GlFilteredSearchSuggestion, GlToken } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
diff --git a/app/assets/javascripts/ci/runner/constants.js b/app/assets/javascripts/ci/runner/constants.js
index 318eb7e74bd..6237dcd0c03 100644
--- a/app/assets/javascripts/ci/runner/constants.js
+++ b/app/assets/javascripts/ci/runner/constants.js
@@ -105,10 +105,15 @@ export const I18N_JOBS = s__('Runners|Jobs');
export const I18N_ASSIGNED_PROJECTS = s__('Runners|Assigned Projects (%{projectCount})');
export const I18N_FILTER_PROJECTS = s__('Runners|Filter projects');
export const I18N_CLEAR_FILTER_PROJECTS = __('Clear');
-export const I18N_NONE = __('None');
export const I18N_NO_JOBS_FOUND = s__('Runners|This runner has not run any jobs.');
export const I18N_NO_PROJECTS_FOUND = __('No projects found');
+// Runner registration
+
+export const I18N_REGISTRATION_SUCCESS = s__("Runners|You've created a new runner!");
+
+export const RUNNER_REGISTRATION_POLLING_INTERVAL_MS = 2000;
+
// Styles
export const RUNNER_TAG_BADGE_VARIANT = 'info';
@@ -129,6 +134,8 @@ export const PARAM_KEY_SORT = 'sort';
export const PARAM_KEY_AFTER = 'after';
export const PARAM_KEY_BEFORE = 'before';
+export const PARAM_KEY_PLATFORM = 'platform';
+
// CiRunnerType
export const INSTANCE_TYPE = 'INSTANCE_TYPE';
@@ -182,9 +189,62 @@ export const MACOS_PLATFORM = 'osx';
export const WINDOWS_PLATFORM = 'windows';
export const AWS_PLATFORM = 'aws';
+export const DOWNLOAD_LOCATIONS = {
+ [LINUX_PLATFORM]: [
+ {
+ arch: 'amd64',
+ url:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64',
+ },
+ {
+ arch: '386',
+ url:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-386',
+ },
+ {
+ arch: 'arm',
+ url:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm',
+ },
+ {
+ arch: 'arm64',
+ url:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm64',
+ },
+ ],
+ [MACOS_PLATFORM]: [
+ {
+ arch: 'amd64',
+ url:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64',
+ },
+ {
+ arch: 'arm64',
+ url:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-arm64',
+ },
+ ],
+ [WINDOWS_PLATFORM]: [
+ {
+ arch: 'amd64',
+ url:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe',
+ },
+ {
+ arch: '386',
+ url:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-386.exe',
+ },
+ ],
+};
+
export const DEFAULT_PLATFORM = LINUX_PLATFORM;
// Runner docs are in a separate repository and are not shipped with GitLab
// they are rendered as external URLs.
+export const INSTALL_HELP_URL = 'https://docs.gitlab.com/runner/install';
+export const EXECUTORS_HELP_URL = 'https://docs.gitlab.com/runner/executors/';
+export const SERVICE_COMMANDS_HELP_URL =
+ 'https://docs.gitlab.com/runner/commands/#service-related-commands';
export const DOCKER_HELP_URL = 'https://docs.gitlab.com/runner/install/docker.html';
export const KUBERNETES_HELP_URL = 'https://docs.gitlab.com/runner/install/kubernetes.html';
diff --git a/app/assets/javascripts/ci/runner/graphql/new/runner_create.mutation.graphql b/app/assets/javascripts/ci/runner/graphql/new/runner_create.mutation.graphql
new file mode 100644
index 00000000000..d14a594e378
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/new/runner_create.mutation.graphql
@@ -0,0 +1,9 @@
+mutation runnerCreate($input: RunnerCreateInput!) {
+ runnerCreate(input: $input) {
+ runner {
+ id
+ registerAdminUrl
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/ci/runner/graphql/register/runner_for_registration.query.graphql b/app/assets/javascripts/ci/runner/graphql/register/runner_for_registration.query.graphql
new file mode 100644
index 00000000000..f6cee807620
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/register/runner_for_registration.query.graphql
@@ -0,0 +1,8 @@
+query getRunnerForRegistration($id: CiRunnerID!) {
+ runner(id: $id) {
+ id
+ description
+ ephemeralAuthenticationToken
+ status
+ }
+}
diff --git a/app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue b/app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue
index 273a9aa823c..2db3a2f42a7 100644
--- a/app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue
+++ b/app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue
@@ -1,5 +1,5 @@
<script>
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { TYPENAME_CI_RUNNER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { redirectTo } from '~/lib/utils/url_utility';
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 e66a1c7b1aa..294d06a66e7 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
@@ -1,6 +1,6 @@
<script>
import { GlLink } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { updateHistory } from '~/lib/utils/url_utility';
import { fetchPolicies } from '~/lib/graphql';
import { upgradeStatusTokenConfig } from 'ee_else_ce/ci/runner/components/search_tokens/upgrade_status_token_config';
diff --git a/app/assets/javascripts/ci/runner/local_storage_alert/show_alert_from_local_storage.js b/app/assets/javascripts/ci/runner/local_storage_alert/show_alert_from_local_storage.js
index d768a06494a..bad3ca6024e 100644
--- a/app/assets/javascripts/ci/runner/local_storage_alert/show_alert_from_local_storage.js
+++ b/app/assets/javascripts/ci/runner/local_storage_alert/show_alert_from_local_storage.js
@@ -7,7 +7,7 @@ export const showAlertFromLocalStorage = async () => {
if (alertOptions) {
try {
- const { createAlert } = await import('~/flash');
+ const { createAlert } = await import('~/alert');
createAlert(JSON.parse(alertOptions));
} catch {
// ignore when the alert data cannot be parsed
diff --git a/app/assets/javascripts/ci/runner/runner_edit/runner_edit_app.vue b/app/assets/javascripts/ci/runner/runner_edit/runner_edit_app.vue
index 4593c9ae52b..843342b20df 100644
--- a/app/assets/javascripts/ci/runner/runner_edit/runner_edit_app.vue
+++ b/app/assets/javascripts/ci/runner/runner_edit/runner_edit_app.vue
@@ -1,5 +1,5 @@
<script>
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPENAME_CI_RUNNER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import RunnerHeader from '../components/runner_header.vue';
diff --git a/app/assets/javascripts/clusters/agents/components/revoke_token_button.vue b/app/assets/javascripts/clusters/agents/components/revoke_token_button.vue
index f0af0da4bb4..697162b50ae 100644
--- a/app/assets/javascripts/clusters/agents/components/revoke_token_button.vue
+++ b/app/assets/javascripts/clusters/agents/components/revoke_token_button.vue
@@ -78,16 +78,17 @@ export default {
primaryModalProps() {
return {
text: this.$options.i18n.revokeButton,
- attributes: [
- { disabled: this.loading || this.disableModalSubmit, loading: this.loading },
- { variant: 'danger' },
- ],
+ attributes: {
+ disabled: this.loading || this.disableModalSubmit,
+ loading: this.loading,
+ variant: 'danger',
+ },
};
},
cancelModalProps() {
return {
text: this.$options.i18n.modalCancel,
- attributes: [],
+ attributes: {},
};
},
disableModalSubmit() {
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index a788703fd08..c94c91654fc 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -1,7 +1,7 @@
import { GlToast } from '@gitlab/ui';
import Visibility from 'visibilityjs';
import Vue from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import AccessorUtilities from '~/lib/utils/accessor';
import Poll from '~/lib/utils/poll';
import { s__ } from '~/locale';
diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js
deleted file mode 100644
index c6ca895778d..00000000000
--- a/app/assets/javascripts/clusters/constants.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// These need to match the enum found in app/models/clusters/cluster.rb
-export const CLUSTER_TYPE = {
- INSTANCE: 'instance_type',
- GROUP: 'group_type',
- PROJECT: 'project_type',
-};
-
-// These need to match the available providers in app/models/clusters/providers/
-export const PROVIDER_TYPE = {
- GCP: 'gcp',
-};
-
-// These are only used client-side
-
-export const LOGGING_MODE = 'logging';
-export const BLOCKING_MODE = 'blocking';
diff --git a/app/assets/javascripts/clusters_list/components/delete_agent_button.vue b/app/assets/javascripts/clusters_list/components/delete_agent_button.vue
index 7a028858d10..913db87f019 100644
--- a/app/assets/javascripts/clusters_list/components/delete_agent_button.vue
+++ b/app/assets/javascripts/clusters_list/components/delete_agent_button.vue
@@ -77,16 +77,17 @@ export default {
primaryModalProps() {
return {
text: this.$options.i18n.modalAction,
- attributes: [
- { disabled: this.loading || this.disableModalSubmit, loading: this.loading },
- { variant: 'danger' },
- ],
+ attributes: {
+ disabled: this.loading || this.disableModalSubmit,
+ loading: this.loading,
+ variant: 'danger',
+ },
};
},
cancelModalProps() {
return {
text: this.$options.i18n.modalCancel,
- attributes: [],
+ attributes: {},
};
},
disableModalSubmit() {
diff --git a/app/assets/javascripts/clusters_list/store/actions.js b/app/assets/javascripts/clusters_list/store/actions.js
index 77d6d5eb009..1ea18dcc97d 100644
--- a/app/assets/javascripts/clusters_list/store/actions.js
+++ b/app/assets/javascripts/clusters_list/store/actions.js
@@ -1,5 +1,5 @@
import * as Sentry from '@sentry/browser';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import Poll from '~/lib/utils/poll';
diff --git a/app/assets/javascripts/commit/components/signature_badge.vue b/app/assets/javascripts/commit/components/signature_badge.vue
new file mode 100644
index 00000000000..344536df093
--- /dev/null
+++ b/app/assets/javascripts/commit/components/signature_badge.vue
@@ -0,0 +1,94 @@
+<script>
+import { GlBadge, GlLink, GlPopover } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { typeConfig, statusConfig } from '../constants';
+import X509CertificateDetails from './x509_certificate_details.vue';
+
+export default {
+ components: {
+ GlBadge,
+ GlPopover,
+ GlLink,
+ X509CertificateDetails,
+ },
+ props: {
+ signature: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ statusConfig() {
+ return this.$options.statusConfig?.[this.signature?.verificationStatus];
+ },
+ typeConfig() {
+ // eslint-disable-next-line no-underscore-dangle
+ return this.$options.typeConfig?.[this.signature?.__typename];
+ },
+ },
+ methods: {
+ helpPagePath,
+ getSubjectKeyIdentifierToDisplay(subjectKeyIdentifier) {
+ // we need to remove : to not trigger secret detection scan
+ return subjectKeyIdentifier.replaceAll(':', ' ');
+ },
+ },
+ typeConfig,
+ statusConfig,
+};
+</script>
+<template>
+ <span
+ v-if="statusConfig && typeConfig"
+ class="gl-display-flex gl-align-items-center gl-hover-cursor-pointer gl-ml-2"
+ >
+ <button
+ id="signature"
+ tabindex="0"
+ data-testid="signature-badge"
+ role="button"
+ variant="link"
+ class="gl-border-0 gl-outline-0! gl-p-0 gl-bg-transparent"
+ :aria-label="statusConfig.label"
+ >
+ <gl-badge :variant="statusConfig.variant" size="md" data-testid="signature-status">
+ {{ statusConfig.label }}
+ </gl-badge>
+ </button>
+ <gl-popover target="signature" triggers="focus" data-testid="signature-info">
+ <template #title>
+ {{ statusConfig.title }}
+ </template>
+ <p data-testid="signature-description">
+ {{ statusConfig.description }}
+ </p>
+ <p v-if="typeConfig.keyLabel" data-testid="signature-key-label">
+ {{ typeConfig.keyLabel }}
+ <span class="gl-font-monospace" data-testid="signature-key">
+ {{ signature[typeConfig.keyNamespace] || __('Unknown') }}
+ </span>
+ </p>
+ <x509-certificate-details
+ v-if="signature.x509Certificate"
+ :title="typeConfig.subjectTitle"
+ :subject="signature.x509Certificate.subject"
+ :subject-key-identifier="
+ getSubjectKeyIdentifierToDisplay(signature.x509Certificate.subjectKeyIdentifier)
+ "
+ />
+ <x509-certificate-details
+ v-if="signature.x509Certificate && signature.x509Certificate.x509Issuer"
+ :title="typeConfig.issuerTitle"
+ :subject="signature.x509Certificate.x509Issuer.subject"
+ :subject-key-identifier="
+ getSubjectKeyIdentifierToDisplay(
+ signature.x509Certificate.x509Issuer.subjectKeyIdentifier,
+ )
+ "
+ />
+ <gl-link :href="helpPagePath(typeConfig.helpLink.path)">
+ {{ typeConfig.helpLink.label }}
+ </gl-link>
+ </gl-popover>
+ </span>
+</template>
diff --git a/app/assets/javascripts/commit/components/x509_certificate_details.vue b/app/assets/javascripts/commit/components/x509_certificate_details.vue
new file mode 100644
index 00000000000..6880fab9043
--- /dev/null
+++ b/app/assets/javascripts/commit/components/x509_certificate_details.vue
@@ -0,0 +1,45 @@
+<script>
+import { X509_CERTIFICATE_KEY_IDENTIFIER_TITLE } from '../constants';
+
+export default {
+ props: {
+ subject: {
+ type: String,
+ required: true,
+ },
+ title: {
+ type: String,
+ required: true,
+ },
+ subjectKeyIdentifier: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ subjectValues() {
+ return this.subject.split(',');
+ },
+ subjectKeyIdentifierToDisplay() {
+ return this.subjectKeyIdentifier.replaceAll(':', ' ');
+ },
+ },
+ i18n: {
+ keyIdentifierTitle: X509_CERTIFICATE_KEY_IDENTIFIER_TITLE,
+ },
+};
+</script>
+
+<template>
+ <div>
+ <strong>{{ title }}</strong>
+ <ul class="gl-pl-5">
+ <li v-for="value in subjectValues" :key="value" data-testid="subject-value">
+ {{ value }}
+ </li>
+ <li data-testid="key-identifier">
+ {{ $options.i18n.keyIdentifierTitle }} {{ subjectKeyIdentifierToDisplay }}
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/commit/constants.js b/app/assets/javascripts/commit/constants.js
new file mode 100644
index 00000000000..4f865e99e46
--- /dev/null
+++ b/app/assets/javascripts/commit/constants.js
@@ -0,0 +1,104 @@
+import { __, s__ } from '~/locale';
+
+export const X509_CERTIFICATE_KEY_IDENTIFIER_TITLE = __('Subject Key Identifier:');
+
+export const verificationStatuses = {
+ VERIFIED: 'VERIFIED',
+ UNVERIFIED: 'UNVERIFIED',
+ UNVERIFIED_KEY: 'UNVERIFIED_KEY',
+ UNKNOWN_KEY: 'UNKNOWN_KEY',
+ OTHER_USER: 'OTHER_USER',
+ SAME_USER_DIFFERENT_EMAIL: 'SAME_USER_DIFFERENT_EMAIL',
+ MULTIPLE_SIGNATURES: 'MULTIPLE_SIGNATURES',
+ REVOKED_KEY: 'REVOKED_KEY',
+};
+
+export const signatureTypes = {
+ /* eslint-disable @gitlab/require-i18n-strings */
+ GPG: 'GpgSignature',
+ X509: 'X509Signature',
+ SSH: 'SshSignature',
+ /* eslint-enable @gitlab/require-i18n-strings */
+};
+
+const UNVERIFIED_CONFIG = {
+ variant: 'muted',
+ label: __('Unverified'),
+ title: __('Unverified signature'),
+ description: __('This commit was signed with an unverified signature.'),
+};
+
+export const statusConfig = {
+ [verificationStatuses.VERIFIED]: {
+ variant: 'success',
+ label: __('Verified'),
+ title: __('Verified commit'),
+ description: __(
+ 'This commit was signed with a verified signature and the committer email was verified to belong to the same user.',
+ ),
+ },
+ [verificationStatuses.UNVERIFIED]: {
+ ...UNVERIFIED_CONFIG,
+ },
+ [verificationStatuses.UNVERIFIED_KEY]: {
+ ...UNVERIFIED_CONFIG,
+ },
+ [verificationStatuses.UNKNOWN_KEY]: {
+ ...UNVERIFIED_CONFIG,
+ },
+ [verificationStatuses.OTHER_USER]: {
+ variant: 'muted',
+ label: __('Unverified'),
+ title: __("Different user's signature"),
+ description: __('This commit was signed with an unverified signature.'),
+ },
+ [verificationStatuses.SAME_USER_DIFFERENT_EMAIL]: {
+ variant: 'muted',
+ label: __('Unverified'),
+ title: __('GPG key mismatch'),
+ description: __(
+ 'This commit was signed with a verified signature, but the committer email is not associated with the GPG Key.',
+ ),
+ },
+ [verificationStatuses.MULTIPLE_SIGNATURES]: {
+ variant: 'muted',
+ label: __('Unverified'),
+ title: __('Multiple signatures'),
+ description: __('This commit was signed with multiple signatures.'),
+ },
+ [verificationStatuses.REVOKED_KEY]: {
+ variant: 'muted',
+ label: __('Unverified'),
+ title: s__('CommitSignature|Unverified signature'),
+ description: s__('CommitSignature|This commit was signed with a key that was revoked.'),
+ },
+};
+
+export const typeConfig = {
+ [signatureTypes.GPG]: {
+ keyLabel: __('GPG Key ID:'),
+ keyNamespace: 'gpgKeyPrimaryKeyid',
+ helpLink: {
+ label: __('Learn about signing commits'),
+ path: 'user/project/repository/gpg_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',
+ },
+ subjectTitle: __('Certificate Subject'),
+ issuerTitle: __('Certificate Issuer'),
+ keyIdentifierTitle: __('Subject Key Identifier:'),
+ },
+ [signatureTypes.SSH]: {
+ keyLabel: __('SSH key fingerprint:'),
+ keyNamespace: 'keyFingerprintSha256',
+ helpLink: {
+ label: __('Learn about signing commits with SSH keys.'),
+ path: '/user/project/repository/ssh_signed_commits/index.md',
+ },
+ },
+};
diff --git a/app/assets/javascripts/commit_merge_requests.js b/app/assets/javascripts/commit_merge_requests.js
index d40cbe589c0..38abb7bebb0 100644
--- a/app/assets/javascripts/commit_merge_requests.js
+++ b/app/assets/javascripts/commit_merge_requests.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from './lib/utils/axios_utils';
import { n__, s__ } from './locale';
diff --git a/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue b/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue
index 196f5537a90..97762ff549b 100644
--- a/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue
+++ b/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue
@@ -1,6 +1,6 @@
<script>
import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Api from '~/api';
import { __ } from '~/locale';
import state from '../state';
diff --git a/app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue b/app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue
index 354db88f11c..06b80a65528 100644
--- a/app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue
+++ b/app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue
@@ -7,6 +7,7 @@ import Heading from '../../extensions/heading';
import Audio from '../../extensions/audio';
import Video from '../../extensions/video';
import Image from '../../extensions/image';
+import DrawioDiagram from '../../extensions/drawio_diagram';
import ToolbarButton from '../toolbar_button.vue';
import BubbleMenu from './bubble_menu.vue';
@@ -26,7 +27,7 @@ export default {
if (from === to) return false;
const includes = [Paragraph.name, Heading.name];
- const excludes = [Image.name, Audio.name, Video.name];
+ const excludes = [Image.name, Audio.name, Video.name, DrawioDiagram.name];
return (
includes.some((type) => editor.isActive(type)) &&
diff --git a/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue b/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue
index 310bb1be81f..a14d49922fb 100644
--- a/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue
+++ b/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue
@@ -11,23 +11,26 @@ import {
} from '@gitlab/ui';
import { __ } from '~/locale';
import Audio from '../../extensions/audio';
+import DrawioDiagram from '../../extensions/drawio_diagram';
import Image from '../../extensions/image';
import Video from '../../extensions/video';
import EditorStateObserver from '../editor_state_observer.vue';
import { acceptedMimes } from '../../services/upload_helpers';
import BubbleMenu from './bubble_menu.vue';
-const MEDIA_TYPES = [Audio.name, Image.name, Video.name];
+const MEDIA_TYPES = [Audio.name, Image.name, Video.name, DrawioDiagram.name];
export default {
i18n: {
copySourceLabels: {
[Audio.name]: __('Copy audio URL'),
+ [DrawioDiagram.name]: __('Copy diagram URL'),
[Image.name]: __('Copy image URL'),
[Video.name]: __('Copy video URL'),
},
editLabels: {
[Audio.name]: __('Edit audio description'),
+ [DrawioDiagram.name]: __('Edit diagram description'),
[Image.name]: __('Edit image description'),
[Video.name]: __('Edit video description'),
},
@@ -38,6 +41,7 @@ export default {
},
deleteLabels: {
[Audio.name]: __('Delete audio'),
+ [DrawioDiagram.name]: __('Delete diagram'),
[Image.name]: __('Delete image'),
[Video.name]: __('Delete video'),
},
@@ -86,6 +90,9 @@ export default {
showProgressIndicator() {
return this.isUploading || this.isUpdating;
},
+ isDrawioDiagram() {
+ return this.mediaType === DrawioDiagram.name;
+ },
},
methods: {
shouldShow() {
@@ -156,10 +163,21 @@ export default {
this.isUpdating = false;
},
+ resetMediaInfo() {
+ this.mediaTitle = null;
+ this.mediaAlt = null;
+ this.mediaCanonicalSrc = null;
+ this.isUploading = false;
+ },
+
replaceMedia() {
this.$refs.fileSelector.click();
},
+ editDiagram() {
+ this.tiptapEditor.chain().focus().createOrEditDiagram().run();
+ },
+
onFileSelect(e) {
this.tiptapEditor
.chain()
@@ -191,6 +209,8 @@ export default {
class="gl-shadow gl-rounded-base gl-bg-white"
plugin-key="bubbleMenuMedia"
:should-show="shouldShow"
+ @show="updateMediaInfoToState"
+ @hidden="resetMediaInfo"
>
<editor-state-observer @transaction="updateMediaInfoToState">
<gl-button-group v-if="!isEditing" class="gl-display-flex gl-align-items-center">
@@ -240,6 +260,19 @@ export default {
@click="startEditingMedia"
/>
<gl-button
+ v-if="isDrawioDiagram"
+ v-gl-tooltip
+ variant="default"
+ category="tertiary"
+ size="medium"
+ data-testid="edit-diagram"
+ :aria-label="replaceLabel"
+ title="Edit diagram"
+ icon="diagram"
+ @click="editDiagram"
+ />
+ <gl-button
+ v-else
v-gl-tooltip
variant="default"
category="tertiary"
diff --git a/app/assets/javascripts/content_editor/components/content_editor.vue b/app/assets/javascripts/content_editor/components/content_editor.vue
index 237808983ee..9e08a257abf 100644
--- a/app/assets/javascripts/content_editor/components/content_editor.vue
+++ b/app/assets/javascripts/content_editor/components/content_editor.vue
@@ -1,7 +1,9 @@
<script>
import { EditorContent as TiptapEditorContent } from '@tiptap/vue-2';
-import { __ } from '~/locale';
-import { VARIANT_DANGER } from '~/flash';
+import { GlSprintf, GlLink } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+import { VARIANT_DANGER } from '~/alert';
+import EditorModeDropdown from '~/vue_shared/components/markdown/editor_mode_dropdown.vue';
import { createContentEditor } from '../services/create_content_editor';
import { ALERT_EVENT, TIPTAP_AUTOFOCUS_OPTIONS } from '../constants';
import ContentEditorAlert from './content_editor_alert.vue';
@@ -16,6 +18,8 @@ import LoadingIndicator from './loading_indicator.vue';
export default {
components: {
+ GlSprintf,
+ GlLink,
LoadingIndicator,
ContentEditorAlert,
ContentEditorProvider,
@@ -26,6 +30,7 @@ export default {
LinkBubbleMenu,
MediaBubbleMenu,
EditorStateObserver,
+ EditorModeDropdown,
},
props: {
renderMarkdown: {
@@ -51,17 +56,32 @@ export default {
required: false,
default: '',
},
+ placeholder: {
+ type: String,
+ required: false,
+ default: '',
+ },
autofocus: {
type: [String, Boolean],
required: false,
default: false,
validator: (autofocus) => TIPTAP_AUTOFOCUS_OPTIONS.includes(autofocus),
},
- useBottomToolbar: {
+ quickActionsDocsPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ drawioEnabled: {
type: Boolean,
required: false,
default: false,
},
+ editable: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
@@ -76,9 +96,20 @@ export default {
this.setSerializedContent(markdown);
}
},
+ editable(value) {
+ this.contentEditor.setEditable(value);
+ },
},
created() {
- const { renderMarkdown, uploadsPath, extensions, serializerConfig, autofocus } = this;
+ const {
+ renderMarkdown,
+ uploadsPath,
+ extensions,
+ serializerConfig,
+ autofocus,
+ drawioEnabled,
+ editable,
+ } = this;
// This is a non-reactive attribute intentionally since this is a complex object.
this.contentEditor = createContentEditor({
@@ -86,8 +117,10 @@ export default {
uploadsPath,
extensions,
serializerConfig,
+ drawioEnabled,
tiptapOptions: {
autofocus,
+ editable,
},
});
},
@@ -104,10 +137,10 @@ export default {
try {
await this.contentEditor.setSerializedContent(markdown);
- this.contentEditor.setEditable(true);
this.notifyLoadingSuccess();
this.latestMarkdown = markdown;
} catch {
+ this.contentEditor.setEditable(false);
this.contentEditor.eventHub.$emit(ALERT_EVENT, {
message: __(
'An error occurred while trying to render the content editor. Please try again.',
@@ -115,10 +148,10 @@ export default {
variant: VARIANT_DANGER,
actionLabel: __('Retry'),
action: () => {
+ this.contentEditor.setEditable(true);
this.setSerializedContent(markdown);
},
});
- this.contentEditor.setEditable(false);
this.notifyLoadingError();
}
},
@@ -149,6 +182,16 @@ export default {
markdown: this.latestMarkdown,
});
},
+ handleEditorModeChanged(mode) {
+ if (mode === 'markdown') {
+ this.$emit('enableMarkdownEditor');
+ }
+ },
+ },
+ i18n: {
+ quickActionsText: s__(
+ 'ContentEditor|For %{quickActionsDocsLinkStart}quick actions%{quickActionsDocsLinkEnd}, type %{keyboardStart}/%{keyboardEnd}.',
+ ),
},
};
</script>
@@ -168,30 +211,37 @@ export default {
class="md-area"
:class="{ 'is-focused': focused }"
>
- <formatting-toolbar
- v-if="!useBottomToolbar"
- ref="toolbar"
- class="gl-border-b"
- @enableMarkdownEditor="$emit('enableMarkdownEditor')"
- />
+ <formatting-toolbar ref="toolbar" @enableMarkdownEditor="$emit('enableMarkdownEditor')" />
<div class="gl-relative gl-mt-4">
<formatting-bubble-menu />
<code-block-bubble-menu />
<link-bubble-menu />
<media-bubble-menu />
+ <div v-if="placeholder && !markdown && !focused" class="gl-absolute gl-text-gray-400">
+ {{ placeholder }}
+ </div>
<tiptap-editor-content
class="md"
data-testid="content_editor_editablebox"
:editor="contentEditor.tiptapEditor"
/>
<loading-indicator v-if="isLoading" />
+ <div class="gl-display-flex gl-border-t gl-py-2 gl-text-secondary">
+ <div class="gl-w-full">
+ <template v-if="quickActionsDocsPath">
+ <gl-sprintf :message="$options.i18n.quickActionsText">
+ <template #keyboard="{ content }">
+ <kbd>{{ content }}</kbd>
+ </template>
+ <template #quickActionsDocsLink="{ content }">
+ <gl-link :href="quickActionsDocsPath" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
+ </div>
+ <editor-mode-dropdown size="small" value="richText" @input="handleEditorModeChanged" />
+ </div>
</div>
- <formatting-toolbar
- v-if="useBottomToolbar"
- ref="toolbar"
- class="gl-border-t"
- @enableMarkdownEditor="$emit('enableMarkdownEditor')"
- />
</div>
</div>
</content-editor-provider>
diff --git a/app/assets/javascripts/content_editor/components/formatting_toolbar.vue b/app/assets/javascripts/content_editor/components/formatting_toolbar.vue
index 36ca3b8cfb6..a5be63fa89f 100644
--- a/app/assets/javascripts/content_editor/components/formatting_toolbar.vue
+++ b/app/assets/javascripts/content_editor/components/formatting_toolbar.vue
@@ -1,5 +1,5 @@
<script>
-import EditorModeDropdown from '~/vue_shared/components/markdown/editor_mode_dropdown.vue';
+import { GlTabs, GlTab } from '@gitlab/ui';
import trackUIControl from '../services/track_ui_control';
import ToolbarButton from './toolbar_button.vue';
import ToolbarImageButton from './toolbar_image_button.vue';
@@ -10,7 +10,8 @@ import ToolbarMoreDropdown from './toolbar_more_dropdown.vue';
export default {
components: {
- EditorModeDropdown,
+ GlTabs,
+ GlTab,
ToolbarButton,
ToolbarTextStyleDropdown,
ToolbarLinkButton,
@@ -22,95 +23,88 @@ export default {
trackToolbarControlExecution({ contentType, value }) {
trackUIControl({ property: contentType, value });
},
- handleEditorModeChanged(mode) {
- if (mode === 'markdown') {
- this.$emit('enableMarkdownEditor');
- }
- },
},
};
</script>
<template>
- <div class="gl-display-flex gl-flex-wrap gl-pb-3 gl-pt-3">
- <toolbar-text-style-dropdown
- data-testid="text-styles"
- class="gl-mr-3"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-button
- data-testid="bold"
- content-type="bold"
- icon-name="bold"
- class="gl-mx-2"
- editor-command="toggleBold"
- :label="__('Bold text')"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-button
- data-testid="italic"
- content-type="italic"
- icon-name="italic"
- class="gl-mx-2"
- editor-command="toggleItalic"
- :label="__('Italic text')"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-button
- data-testid="blockquote"
- content-type="blockquote"
- icon-name="quote"
- class="gl-mx-2"
- editor-command="toggleBlockquote"
- :label="__('Insert a quote')"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-button
- data-testid="code"
- content-type="code"
- icon-name="code"
- class="gl-mx-2"
- editor-command="toggleCode"
- :label="__('Code')"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-link-button data-testid="link" @execute="trackToolbarControlExecution" />
- <toolbar-button
- data-testid="bullet-list"
- content-type="bulletList"
- icon-name="list-bulleted"
- class="gl-mx-2 gl-display-none gl-sm-display-inline"
- editor-command="toggleBulletList"
- :label="__('Add a bullet list')"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-button
- data-testid="ordered-list"
- content-type="orderedList"
- icon-name="list-numbered"
- class="gl-mx-2 gl-display-none gl-sm-display-inline"
- editor-command="toggleOrderedList"
- :label="__('Add a numbered list')"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-button
- data-testid="task-list"
- content-type="taskList"
- icon-name="list-task"
- class="gl-mx-2 gl-display-none gl-sm-display-inline"
- editor-command="toggleTaskList"
- :label="__('Add a checklist')"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-image-button
- ref="imageButton"
- data-testid="image"
- @execute="trackToolbarControlExecution"
- />
- <toolbar-table-button data-testid="table" @execute="trackToolbarControlExecution" />
- <toolbar-more-dropdown data-testid="more" @execute="trackToolbarControlExecution" />
-
- <editor-mode-dropdown class="gl-ml-auto" value="richText" @input="handleEditorModeChanged" />
- </div>
+ <gl-tabs content-class="gl-display-none">
+ <gl-tab title-link-class="gl-py-4 gl-px-3" :title="__('Write')" />
+ <template #tabs-end>
+ <div class="gl-ml-auto gl-py-2 gl-display-flex gl-flex-wrap gl-align-items-end">
+ <toolbar-text-style-dropdown
+ data-testid="text-styles"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-button
+ data-testid="bold"
+ content-type="bold"
+ icon-name="bold"
+ editor-command="toggleBold"
+ :label="__('Bold text')"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-button
+ data-testid="italic"
+ content-type="italic"
+ icon-name="italic"
+ editor-command="toggleItalic"
+ :label="__('Italic text')"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-button
+ data-testid="blockquote"
+ content-type="blockquote"
+ icon-name="quote"
+ editor-command="toggleBlockquote"
+ :label="__('Insert a quote')"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-button
+ data-testid="code"
+ content-type="code"
+ icon-name="code"
+ editor-command="toggleCode"
+ :label="__('Code')"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-link-button data-testid="link" @execute="trackToolbarControlExecution" />
+ <toolbar-button
+ data-testid="bullet-list"
+ content-type="bulletList"
+ icon-name="list-bulleted"
+ class="gl-display-none gl-sm-display-inline"
+ editor-command="toggleBulletList"
+ :label="__('Add a bullet list')"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-button
+ data-testid="ordered-list"
+ content-type="orderedList"
+ icon-name="list-numbered"
+ class="gl-display-none gl-sm-display-inline"
+ editor-command="toggleOrderedList"
+ :label="__('Add a numbered list')"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-button
+ data-testid="task-list"
+ content-type="taskList"
+ icon-name="list-task"
+ class="gl-display-none gl-sm-display-inline"
+ editor-command="toggleTaskList"
+ :label="__('Add a checklist')"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-image-button
+ ref="imageButton"
+ data-testid="image"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-table-button data-testid="table" @execute="trackToolbarControlExecution" />
+ <toolbar-more-dropdown data-testid="more" @execute="trackToolbarControlExecution" />
+ </div>
+ </template>
+ </gl-tabs>
</template>
<style>
.gl-spinner-container {
diff --git a/app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue b/app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue
index ca17443081c..99ba8c51948 100644
--- a/app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue
+++ b/app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue
@@ -9,7 +9,7 @@ export default {
GlDisclosureDropdown,
GlTooltip,
},
- inject: ['tiptapEditor'],
+ inject: ['tiptapEditor', 'contentEditor'],
data() {
return {
toggleId: uniqueId('dropdown-toggle-btn-'),
@@ -53,6 +53,14 @@ export default {
text: __('PlantUML diagram'),
action: () => this.insert('diagram', { language: 'plantuml' }),
},
+ ...(this.contentEditor.drawioEnabled
+ ? [
+ {
+ text: __('Create or edit diagram'),
+ action: () => this.execute('createOrEditDiagram', 'drawioDiagram'),
+ },
+ ]
+ : []),
{
text: __('Table of contents'),
action: () => this.execute('insertTableOfContents', 'tableOfContents'),
diff --git a/app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue b/app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue
index 9c1d1faca48..bd30bdcea0c 100644
--- a/app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue
+++ b/app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue
@@ -76,6 +76,8 @@ export default {
:disabled="!activeItem"
:data-qa-text-style="activeItemLabel"
data-qa-selector="text_style_dropdown"
+ size="small"
+ toggle-class="btn-default-tertiary"
@select="execute"
/>
</editor-state-observer>
diff --git a/app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue b/app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue
index 6456540a0dd..4d948f4ec05 100644
--- a/app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue
+++ b/app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue
@@ -1,7 +1,7 @@
<script>
import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2';
-import { selectedRect as getSelectedRect } from '@_ueberdosis/prosemirror-tables';
+import { selectedRect as getSelectedRect } from '@tiptap/pm/tables';
import { __ } from '~/locale';
const TABLE_CELL_HEADER = 'th';
diff --git a/app/assets/javascripts/content_editor/constants/index.js b/app/assets/javascripts/content_editor/constants/index.js
index 14862727811..6a3740a5952 100644
--- a/app/assets/javascripts/content_editor/constants/index.js
+++ b/app/assets/javascripts/content_editor/constants/index.js
@@ -47,6 +47,7 @@ export const KEYDOWN_EVENT = 'keydown';
export const PARSE_HTML_PRIORITY_LOWEST = 1;
export const PARSE_HTML_PRIORITY_DEFAULT = 50;
+export const PARSE_HTML_PRIORITY_HIGH = 75;
export const PARSE_HTML_PRIORITY_HIGHEST = 100;
export const EXTENSION_PRIORITY_LOWER = 75;
diff --git a/app/assets/javascripts/content_editor/extensions/attachment.js b/app/assets/javascripts/content_editor/extensions/attachment.js
index 9634730f637..0d5b8e56a6c 100644
--- a/app/assets/javascripts/content_editor/extensions/attachment.js
+++ b/app/assets/javascripts/content_editor/extensions/attachment.js
@@ -1,5 +1,5 @@
import { Extension } from '@tiptap/core';
-import { Plugin, PluginKey } from 'prosemirror-state';
+import { Plugin, PluginKey } from '@tiptap/pm/state';
import { handleFileEvent } from '../services/upload_helpers';
export default Extension.create({
diff --git a/app/assets/javascripts/content_editor/extensions/color_chip.js b/app/assets/javascripts/content_editor/extensions/color_chip.js
index deb5029a1f0..c49b541bbaf 100644
--- a/app/assets/javascripts/content_editor/extensions/color_chip.js
+++ b/app/assets/javascripts/content_editor/extensions/color_chip.js
@@ -1,6 +1,6 @@
import { Node } from '@tiptap/core';
-import { Plugin, PluginKey } from 'prosemirror-state';
-import { Decoration, DecorationSet } from 'prosemirror-view';
+import { Plugin, PluginKey } from '@tiptap/pm/state';
+import { Decoration, DecorationSet } from '@tiptap/pm/view';
import { isValidColorExpression } from '~/lib/utils/color_utils';
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
diff --git a/app/assets/javascripts/content_editor/extensions/drawio_diagram.js b/app/assets/javascripts/content_editor/extensions/drawio_diagram.js
new file mode 100644
index 00000000000..8c3012ecf59
--- /dev/null
+++ b/app/assets/javascripts/content_editor/extensions/drawio_diagram.js
@@ -0,0 +1,41 @@
+import { create } from '~/drawio/content_editor_facade';
+import { launchDrawioEditor } from '~/drawio/drawio_editor';
+import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
+import createAssetResolver from '../services/asset_resolver';
+import Image from './image';
+
+export default Image.extend({
+ name: 'drawioDiagram',
+ addOptions() {
+ return {
+ ...this.parent?.(),
+ uploadsPath: null,
+ renderMarkdown: null,
+ };
+ },
+ parseHTML() {
+ return [
+ {
+ priority: PARSE_HTML_PRIORITY_HIGHEST,
+ tag: 'a.no-attachment-icon[data-canonical-src$="drawio.svg"]',
+ },
+ {
+ tag: 'img[src]',
+ },
+ ];
+ },
+ addCommands() {
+ return {
+ createOrEditDiagram: () => () => {
+ launchDrawioEditor({
+ editorFacade: create({
+ tiptapEditor: this.editor,
+ drawioNodeName: this.name,
+ uploadsPath: this.options.uploadsPath,
+ assetResolver: createAssetResolver({ renderMarkdown: this.options.renderMarkdown }),
+ }),
+ });
+ },
+ };
+ },
+});
diff --git a/app/assets/javascripts/content_editor/extensions/external_keydown_handler.js b/app/assets/javascripts/content_editor/extensions/external_keydown_handler.js
index e940614083e..e48100c15a7 100644
--- a/app/assets/javascripts/content_editor/extensions/external_keydown_handler.js
+++ b/app/assets/javascripts/content_editor/extensions/external_keydown_handler.js
@@ -1,5 +1,5 @@
import { Extension } from '@tiptap/core';
-import { Plugin, PluginKey } from 'prosemirror-state';
+import { Plugin, PluginKey } from '@tiptap/pm/state';
import { KEYDOWN_EVENT } from '../constants';
/**
diff --git a/app/assets/javascripts/content_editor/extensions/image.js b/app/assets/javascripts/content_editor/extensions/image.js
index fc4c108b773..58c16297886 100644
--- a/app/assets/javascripts/content_editor/extensions/image.js
+++ b/app/assets/javascripts/content_editor/extensions/image.js
@@ -1,5 +1,5 @@
import { Image } from '@tiptap/extension-image';
-import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
+import { PARSE_HTML_PRIORITY_HIGH } from '../constants';
const resolveImageEl = (element) =>
element.nodeName === 'IMG' ? element : element.querySelector('img');
@@ -77,7 +77,7 @@ export default Image.extend({
parseHTML() {
return [
{
- priority: PARSE_HTML_PRIORITY_HIGHEST,
+ priority: PARSE_HTML_PRIORITY_HIGH,
tag: 'a.no-attachment-icon',
},
{
diff --git a/app/assets/javascripts/content_editor/extensions/paste_markdown.js b/app/assets/javascripts/content_editor/extensions/paste_markdown.js
index 848c4c12a9a..0a9a0d8d4c1 100644
--- a/app/assets/javascripts/content_editor/extensions/paste_markdown.js
+++ b/app/assets/javascripts/content_editor/extensions/paste_markdown.js
@@ -1,7 +1,7 @@
import { Extension } from '@tiptap/core';
-import { Plugin, PluginKey } from 'prosemirror-state';
+import { Plugin, PluginKey } from '@tiptap/pm/state';
import { __ } from '~/locale';
-import { VARIANT_DANGER } from '~/flash';
+import { VARIANT_DANGER } from '~/alert';
import createMarkdownDeserializer from '../services/gl_api_markdown_deserializer';
import { ALERT_EVENT, EXTENSION_PRIORITY_HIGHEST } from '../constants';
import CodeBlockHighlight from './code_block_highlight';
diff --git a/app/assets/javascripts/content_editor/extensions/suggestions.js b/app/assets/javascripts/content_editor/extensions/suggestions.js
index a9628c78add..eb53a3a61b3 100644
--- a/app/assets/javascripts/content_editor/extensions/suggestions.js
+++ b/app/assets/javascripts/content_editor/extensions/suggestions.js
@@ -2,7 +2,7 @@ import { Node } from '@tiptap/core';
import { VueRenderer } from '@tiptap/vue-2';
import tippy from 'tippy.js';
import Suggestion from '@tiptap/suggestion';
-import { PluginKey } from 'prosemirror-state';
+import { PluginKey } from '@tiptap/pm/state';
import { isFunction, uniqueId, memoize } from 'lodash';
import axios from '~/lib/utils/axios_utils';
import { initEmojiMap, getAllEmoji } from '~/emoji';
diff --git a/app/assets/javascripts/content_editor/extensions/table.js b/app/assets/javascripts/content_editor/extensions/table.js
index d7456ab4094..de8170eff93 100644
--- a/app/assets/javascripts/content_editor/extensions/table.js
+++ b/app/assets/javascripts/content_editor/extensions/table.js
@@ -1,6 +1,6 @@
import { Table } from '@tiptap/extension-table';
import { debounce } from 'lodash';
-import { VARIANT_WARNING } from '~/flash';
+import { VARIANT_WARNING } from '~/alert';
import { __ } from '~/locale';
import { getMarkdownSource } from '../services/markdown_sourcemap';
import { shouldRenderHTMLTable } from '../services/serialization_helpers';
diff --git a/app/assets/javascripts/content_editor/services/content_editor.js b/app/assets/javascripts/content_editor/services/content_editor.js
index 514ab9699bc..a988e1df2a6 100644
--- a/app/assets/javascripts/content_editor/services/content_editor.js
+++ b/app/assets/javascripts/content_editor/services/content_editor.js
@@ -1,12 +1,14 @@
/* eslint-disable no-underscore-dangle */
export class ContentEditor {
- constructor({ tiptapEditor, serializer, deserializer, assetResolver, eventHub }) {
+ constructor({ tiptapEditor, serializer, deserializer, assetResolver, eventHub, drawioEnabled }) {
this._tiptapEditor = tiptapEditor;
this._serializer = serializer;
this._deserializer = deserializer;
this._eventHub = eventHub;
this._assetResolver = assetResolver;
this._pristineDoc = null;
+
+ this.drawioEnabled = drawioEnabled;
}
get tiptapEditor() {
diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js
index 61c6be574d0..9d536793287 100644
--- a/app/assets/javascripts/content_editor/services/create_content_editor.js
+++ b/app/assets/javascripts/content_editor/services/create_content_editor.js
@@ -16,6 +16,7 @@ import DescriptionList from '../extensions/description_list';
import Details from '../extensions/details';
import DetailsContent from '../extensions/details_content';
import Diagram from '../extensions/diagram';
+import DrawioDiagram from '../extensions/drawio_diagram';
import Document from '../extensions/document';
import Dropcursor from '../extensions/dropcursor';
import Emoji from '../extensions/emoji';
@@ -74,7 +75,7 @@ const createTiptapEditor = ({ extensions = [], ...options } = {}) =>
extensions: [...extensions],
editorProps: {
attributes: {
- class: 'gl-outline-0!',
+ class: 'gl-shadow-none!',
},
},
...options,
@@ -86,6 +87,7 @@ export const createContentEditor = ({
extensions = [],
serializerConfig = { marks: {}, nodes: {} },
tiptapOptions,
+ drawioEnabled = false,
} = {}) => {
if (!isFunction(renderMarkdown)) {
throw new Error(PROVIDE_SERIALIZER_OR_RENDERER_ERROR);
@@ -157,6 +159,9 @@ export const createContentEditor = ({
];
const allExtensions = [...builtInContentEditorExtensions, ...extensions];
+
+ if (drawioEnabled) allExtensions.push(DrawioDiagram.configure({ uploadsPath, renderMarkdown }));
+
const trackedExtensions = allExtensions.map(trackInputRulesAndShortcuts);
const tiptapEditor = createTiptapEditor({ extensions: trackedExtensions, ...tiptapOptions });
const serializer = createMarkdownSerializer({ serializerConfig });
@@ -173,5 +178,6 @@ export const createContentEditor = ({
eventHub,
deserializer,
assetResolver,
+ drawioEnabled,
});
};
diff --git a/app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js b/app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js
index 796dc06ad93..91f8aaf6324 100644
--- a/app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js
+++ b/app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js
@@ -1,4 +1,4 @@
-import { DOMParser as ProseMirrorDOMParser } from 'prosemirror-model';
+import { DOMParser as ProseMirrorDOMParser } from '@tiptap/pm/model';
import { replaceCommentsWith } from '~/lib/utils/dom_utils';
export default ({ render }) => {
@@ -18,10 +18,7 @@ export default ({ render }) => {
*/
return {
deserialize: async ({ schema, markdown }) => {
- const html = await render(markdown);
-
- if (!html) return {};
-
+ const html = markdown ? await render(markdown) : '<p></p>';
const parser = new DOMParser();
const { body } = parser.parseFromString(`<body>${html}</body>`, 'text/html');
diff --git a/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js b/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
index 28a50adca6b..c8972515c25 100644
--- a/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
+++ b/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
@@ -19,7 +19,7 @@
* visit-parents documentation: https://github.com/syntax-tree/unist-util-visit-parents
*/
-import { Mark } from 'prosemirror-model';
+import { Mark } from '@tiptap/pm/model';
import { visitParents, SKIP } from 'unist-util-visit-parents';
import { isFunction, isString, noop, mapValues } from 'lodash';
diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js
index 4e29f85004b..e27a427372c 100644
--- a/app/assets/javascripts/content_editor/services/markdown_serializer.js
+++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js
@@ -12,6 +12,7 @@ import DescriptionItem from '../extensions/description_item';
import DescriptionList from '../extensions/description_list';
import Details from '../extensions/details';
import DetailsContent from '../extensions/details_content';
+import DrawioDiagram from '../extensions/drawio_diagram';
import Comment from '../extensions/comment';
import Diagram from '../extensions/diagram';
import Emoji from '../extensions/emoji';
@@ -134,6 +135,10 @@ const defaultSerializerConfig = {
[CodeBlockHighlight.name]: preserveUnchanged(renderCodeBlock),
[Comment.name]: renderComment,
[Diagram.name]: preserveUnchanged(renderCodeBlock),
+ [DrawioDiagram.name]: preserveUnchanged({
+ render: renderImage,
+ inline: true,
+ }),
[DescriptionList.name]: renderHTMLNode('dl', true),
[DescriptionItem.name]: (state, node, parent, index) => {
if (index === 1) state.ensureNewLine();
diff --git a/app/assets/javascripts/content_editor/services/upload_helpers.js b/app/assets/javascripts/content_editor/services/upload_helpers.js
index 09f0738b51b..de1a187b246 100644
--- a/app/assets/javascripts/content_editor/services/upload_helpers.js
+++ b/app/assets/javascripts/content_editor/services/upload_helpers.js
@@ -1,20 +1,30 @@
-import { VARIANT_DANGER } from '~/flash';
+import { VARIANT_DANGER } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import { extractFilename, readFileAsDataURL } from './utils';
export const acceptedMimes = {
- image: ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'],
- audio: [
- 'audio/basic',
- 'audio/mid',
- 'audio/mpeg',
- 'audio/x-aiff',
- 'audio/ogg',
- 'audio/vorbis',
- 'audio/vnd.wav',
- ],
- video: ['video/mp4', 'video/quicktime'],
+ drawioDiagram: {
+ mimes: ['image/svg+xml'],
+ ext: 'drawio.svg',
+ },
+ image: {
+ mimes: ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'],
+ },
+ audio: {
+ mimes: [
+ 'audio/basic',
+ 'audio/mid',
+ 'audio/mpeg',
+ 'audio/x-aiff',
+ 'audio/ogg',
+ 'audio/vorbis',
+ 'audio/vnd.wav',
+ ],
+ },
+ video: {
+ mimes: ['video/mp4', 'video/quicktime'],
+ },
};
const extractAttachmentLinkUrl = (html) => {
@@ -128,8 +138,8 @@ const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown, eve
export const handleFileEvent = ({ editor, file, uploadsPath, renderMarkdown, eventHub }) => {
if (!file) return false;
- for (const [type, mimes] of Object.entries(acceptedMimes)) {
- if (mimes.includes(file?.type)) {
+ for (const [type, { mimes, ext }] of Object.entries(acceptedMimes)) {
+ if (mimes.includes(file?.type) && (!ext || file?.name.endsWith(ext))) {
uploadContent({ type, editor, file, uploadsPath, renderMarkdown, eventHub });
return true;
diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js
index f2ff77daf02..ea444b5c146 100644
--- a/app/assets/javascripts/contextual_sidebar.js
+++ b/app/assets/javascripts/contextual_sidebar.js
@@ -38,9 +38,6 @@ export default class ContextualSidebar {
this.toggleCollapsedSidebar(value, true);
}
});
- this.$page.on('transitionstart transitionend', () => {
- $(document).trigger('content.resize');
- });
$(window).on(
'resize',
diff --git a/app/assets/javascripts/contributors/components/contributors.vue b/app/assets/javascripts/contributors/components/contributors.vue
index 17e6cc87ff8..ce99d5da3cc 100644
--- a/app/assets/javascripts/contributors/components/contributors.vue
+++ b/app/assets/javascripts/contributors/components/contributors.vue
@@ -9,7 +9,6 @@ import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import { __ } from '~/locale';
import RefSelector from '~/ref/components/ref_selector.vue';
import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants';
-import ResizableChartContainer from '~/vue_shared/components/resizable_chart/resizable_chart_container.vue';
import { xAxisLabelFormatter, dateFormatter } from '../utils';
const GRAPHS_PATH_REGEX = /^(.*?)\/-\/graphs/g;
@@ -26,7 +25,6 @@ export default {
GlAreaChart,
GlButton,
GlLoadingIcon,
- ResizableChartContainer,
RefSelector,
},
props: {
@@ -249,18 +247,15 @@ export default {
<div data-testid="contributors-charts">
<h4 class="gl-mb-2 gl-mt-5">{{ __('Commits to') }} {{ branch }}</h4>
<span>{{ __('Excluding merge commits. Limited to 6,000 commits.') }}</span>
- <resizable-chart-container>
- <template #default="{ width }">
- <gl-area-chart
- class="gl-mb-5"
- :width="width"
- :data="masterChartData"
- :option="masterChartOptions"
- :height="masterChartHeight"
- @created="onMasterChartCreated"
- />
- </template>
- </resizable-chart-container>
+ <gl-area-chart
+ class="gl-mb-5"
+ responsive
+ width="auto"
+ :data="masterChartData"
+ :option="masterChartOptions"
+ :height="masterChartHeight"
+ @created="onMasterChartCreated"
+ />
<div class="row">
<div
@@ -272,17 +267,14 @@ export default {
<p class="gl-mb-3">
{{ n__('%d commit', '%d commits', contributor.commits) }} ({{ contributor.email }})
</p>
- <resizable-chart-container>
- <template #default="{ width }">
- <gl-area-chart
- :width="width"
- :data="contributor.dates"
- :option="individualChartOptions"
- :height="individualChartHeight"
- @created="onIndividualChartCreated"
- />
- </template>
- </resizable-chart-container>
+ <gl-area-chart
+ responsive
+ width="auto"
+ :data="contributor.dates"
+ :option="individualChartOptions"
+ :height="individualChartHeight"
+ @created="onIndividualChartCreated"
+ />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/contributors/stores/actions.js b/app/assets/javascripts/contributors/stores/actions.js
index 3a6f4191031..5a8349aa1fd 100644
--- a/app/assets/javascripts/contributors/stores/actions.js
+++ b/app/assets/javascripts/contributors/stores/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import service from '../services/contributors_service';
import * as types from './mutation_types';
diff --git a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue
index c67b544eacd..b13b0ede9f0 100644
--- a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue
+++ b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue
@@ -48,15 +48,13 @@ export default {
addDeployFreezeButton() {
return {
text: this.isEditing ? __('Save deploy freeze') : __('Add deploy freeze'),
- attributes: [
- { variant: 'confirm' },
- {
- disabled:
- !isValidCron(this.freezeStartCron) ||
- !isValidCron(this.freezeEndCron) ||
- !this.selectedTimezone,
- },
- ],
+ attributes: {
+ variant: 'confirm',
+ disabled:
+ !isValidCron(this.freezeStartCron) ||
+ !isValidCron(this.freezeEndCron) ||
+ !this.selectedTimezone,
+ },
};
},
invalidFreezeStartCron() {
diff --git a/app/assets/javascripts/deploy_freeze/store/actions.js b/app/assets/javascripts/deploy_freeze/store/actions.js
index 76a4eaaff3f..77d3037ff57 100644
--- a/app/assets/javascripts/deploy_freeze/store/actions.js
+++ b/app/assets/javascripts/deploy_freeze/store/actions.js
@@ -1,5 +1,5 @@
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { logError } from '~/lib/logger';
import { __ } from '~/locale';
import * as types from './mutation_types';
diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue
index db5e9a954cf..5fc15578827 100644
--- a/app/assets/javascripts/deploy_keys/components/app.vue
+++ b/app/assets/javascripts/deploy_keys/components/app.vue
@@ -1,6 +1,6 @@
<script>
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
import eventHub from '../eventhub';
diff --git a/app/assets/javascripts/deploy_keys/components/confirm_modal.vue b/app/assets/javascripts/deploy_keys/components/confirm_modal.vue
index 1932435c42a..25551d7b5cb 100644
--- a/app/assets/javascripts/deploy_keys/components/confirm_modal.vue
+++ b/app/assets/javascripts/deploy_keys/components/confirm_modal.vue
@@ -22,11 +22,11 @@ export default {
title: __('Do you want to remove this deploy key?'),
actionPrimary: {
text: __('Remove deploy key'),
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
},
actionSecondary: {
text: __('Cancel'),
- attributes: [{ category: 'tertiary' }],
+ attributes: { category: 'tertiary' },
},
static: true,
modalId: 'confirm-remove-deploy-key',
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 57fae608efa..c49ab1ac43c 100644
--- a/app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue
+++ b/app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue
@@ -9,7 +9,7 @@ import {
GlSprintf,
GlLink,
} from '@gitlab/ui';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { formatDate } from '~/lib/utils/datetime_utility';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
@@ -66,6 +66,11 @@ export default {
},
},
methods: {
+ getWritePackageRegistryHelpText() {
+ return this.tokenType === 'group'
+ ? this.$options.translations.groupWritePackageRegistryHelp
+ : this.$options.translations.projectWritePackageRegistryHelp;
+ },
defaultData() {
return {
expiresAt: null,
@@ -110,7 +115,7 @@ export default {
id: 'deploy_token_write_package_registry',
isShown: this.$props.packagesRegistryEnabled,
value: false,
- helpText: this.$options.translations.writePackageRegistryHelp,
+ helpText: this.getWritePackageRegistryHelpText(),
scopeName: 'write_package_registry',
},
],
diff --git a/app/assets/javascripts/deploy_tokens/deploy_token_translations.js b/app/assets/javascripts/deploy_tokens/deploy_token_translations.js
index 3767e9e6170..410864a83a2 100644
--- a/app/assets/javascripts/deploy_tokens/deploy_token_translations.js
+++ b/app/assets/javascripts/deploy_tokens/deploy_token_translations.js
@@ -32,9 +32,12 @@ const translations = {
readRegistryHelp: s__('DeployTokens|Allows read-only access to registry images.'),
writeRegistryHelp: s__('DeployTokens|Allows read and write access to registry images.'),
readPackageRegistryHelp: s__('DeployTokens|Allows read-only access to the package registry.'),
- writePackageRegistryHelp: s__(
+ groupWritePackageRegistryHelp: s__(
'DeployTokens|Allows read and write access to the package registry.',
),
+ projectWritePackageRegistryHelp: s__(
+ 'DeployTokens|Allows read, write and delete access to the package registry.',
+ ),
createTokenFailedAlert: s__('DeployTokens|Failed to create a new deployment token'),
};
diff --git a/app/assets/javascripts/deprecated_notes.js b/app/assets/javascripts/deprecated_notes.js
index 7503df9194b..0008c3504ce 100644
--- a/app/assets/javascripts/deprecated_notes.js
+++ b/app/assets/javascripts/deprecated_notes.js
@@ -16,7 +16,7 @@ import $ from 'jquery';
import { escape, uniqueId } from 'lodash';
import Vue from 'vue';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { sanitize } from '~/lib/dompurify';
import '~/lib/utils/jquery_at_who';
import AjaxCache from '~/lib/utils/ajax_cache';
@@ -53,9 +53,9 @@ const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
export default class Notes {
- static initialize(notes_url, note_ids, last_fetched_at, view, enableGFM) {
+ static initialize(notes_url, last_fetched_at, view, enableGFM) {
if (!this.instance) {
- this.instance = new Notes(notes_url, note_ids, last_fetched_at, view, enableGFM);
+ this.instance = new Notes(notes_url, last_fetched_at, view, enableGFM);
}
}
@@ -63,7 +63,7 @@ export default class Notes {
return this.instance;
}
- constructor(notes_url, note_ids, last_fetched_at, view, enableGFM = defaultAutocompleteConfig) {
+ constructor(notes_url, last_fetched_at, view, enableGFM = defaultAutocompleteConfig) {
this.updateTargetButtons = this.updateTargetButtons.bind(this);
this.updateComment = this.updateComment.bind(this);
this.visibilityChange = this.visibilityChange.bind(this);
@@ -85,9 +85,9 @@ export default class Notes {
this.postComment = this.postComment.bind(this);
this.clearAlertWrapper = this.clearAlert.bind(this);
this.onHashChange = this.onHashChange.bind(this);
+ this.note_ids = [];
this.notes_url = notes_url;
- this.note_ids = note_ids;
this.enableGFM = enableGFM;
// Used to keep track of updated notes while people are editing things
this.updatedNotesTrackingMap = {};
@@ -449,8 +449,6 @@ export default class Notes {
return;
}
- this.note_ids.push(noteEntity.id);
-
if ($notesList.length) {
$notesList.find('.system-note.being-posted').remove();
}
@@ -497,7 +495,6 @@ export default class Notes {
if (!Notes.isNewNote(noteEntity, this.note_ids)) {
return;
}
- this.note_ids.push(noteEntity.id);
const form =
$form || $(`.js-discussion-note-form[data-discussion-id="${noteEntity.discussion_id}"]`);
@@ -745,7 +742,7 @@ export default class Notes {
$noteAvatar.append($targetNoteBadge);
this.revertNoteEditForm($targetNote);
- renderGFM($noteEntityEl.get(0));
+ renderGFM(Notes.getNodeToRender($noteEntityEl));
// Find the note's `li` element by ID and replace it with the updated HTML
const $note_li = $(`.note-row-${noteEntity.id}`);
@@ -1396,8 +1393,28 @@ export default class Notes {
/**
* Check if note does not exist on page
*/
- static isNewNote(noteEntity, noteIds) {
- return $.inArray(noteEntity.id, noteIds) === -1;
+ static isNewNote(noteEntity, note_ids) {
+ if (note_ids.length === 0) {
+ Notes.loadNotesIds(note_ids);
+ }
+ const isNewEntry = $.inArray(noteEntity.id, note_ids) === -1;
+ if (isNewEntry) {
+ note_ids.push(noteEntity.id);
+ }
+ return isNewEntry;
+ }
+
+ /**
+ * Load notes ids
+ */
+ static loadNotesIds(note_ids) {
+ const $notesList = $('.main-notes-list li[id^=note_]');
+ for (const $noteItem of $notesList) {
+ if (Notes.isNodeTypeElement($noteItem)) {
+ const noteId = parseInt($noteItem.id.split('_')[1], 10);
+ note_ids.push(noteId);
+ }
+ }
}
/**
@@ -1422,7 +1439,7 @@ export default class Notes {
const $note = $(noteHtml);
$note.addClass('fade-in-full');
- renderGFM($note.get(0));
+ renderGFM(Notes.getNodeToRender($note));
$notesList.append($note);
return $note;
}
@@ -1431,11 +1448,20 @@ export default class Notes {
const $updatedNote = $(noteHtml);
$updatedNote.addClass('fade-in');
- renderGFM($updatedNote.get(0));
+ renderGFM(Notes.getNodeToRender($updatedNote));
$note.replaceWith($updatedNote);
return $updatedNote;
}
+ static getNodeToRender($note) {
+ for (const $item of $note) {
+ if (Notes.isNodeTypeElement($item)) {
+ return $item;
+ }
+ }
+ return '';
+ }
+
/**
* Get data from Form attributes to use for saving/submitting comment.
*/
@@ -1829,4 +1855,11 @@ export default class Notes {
return $closeBtn.text($closeBtn.data('originalText'));
}
+
+ /**
+ * Function to check if node is element to avoid comment and text
+ */
+ static isNodeTypeElement($node) {
+ return $node.nodeType === Node.ELEMENT_NODE;
+ }
}
diff --git a/app/assets/javascripts/design_management/components/design_notes/design_discussion.vue b/app/assets/javascripts/design_management/components/design_notes/design_discussion.vue
index 3091c6703b4..680a101b118 100644
--- a/app/assets/javascripts/design_management/components/design_notes/design_discussion.vue
+++ b/app/assets/javascripts/design_management/components/design_notes/design_discussion.vue
@@ -1,16 +1,19 @@
<script>
import { GlButton, GlLink, GlTooltipDirective } from '@gitlab/ui';
-import { ApolloMutation } from 'vue-apollo';
-import { createAlert } from '~/flash';
-import { s__ } from '~/locale';
+import * as Sentry from '@sentry/browser';
+import { createAlert } from '~/alert';
+import { __, s__ } from '~/locale';
import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
import { updateGlobalTodoCount } from '~/sidebar/utils';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import DesignNotePin from '~/vue_shared/components/design_management/design_note_pin.vue';
import { isLoggedIn } from '~/lib/utils/common_utils';
-import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../../constants';
+import { TYPENAME_NOTE, TYPENAME_DISCUSSION } from '~/graphql_shared/constants';
+import { ACTIVE_DISCUSSION_SOURCE_TYPES, DELETE_NOTE_ERROR_MSG } from '../../constants';
import createNoteMutation from '../../graphql/mutations/create_note.mutation.graphql';
import toggleResolveDiscussionMutation from '../../graphql/mutations/toggle_resolve_discussion.mutation.graphql';
+import destroyNoteMutation from '../../graphql/mutations/destroy_note.mutation.graphql';
import activeDiscussionQuery from '../../graphql/queries/active_discussion.query.graphql';
import getDesignQuery from '../../graphql/queries/get_design.query.graphql';
import allVersionsMixin from '../../mixins/all_versions';
@@ -23,8 +26,14 @@ import DesignReplyForm from './design_reply_form.vue';
import ToggleRepliesWidget from './toggle_replies_widget.vue';
export default {
+ i18n: {
+ deleteNote: {
+ confirmationText: __('Are you sure you want to delete this comment?'),
+ primaryModalBtnText: __('Delete comment'),
+ errorText: DELETE_NOTE_ERROR_MSG,
+ },
+ },
components: {
- ApolloMutation,
DesignNote,
DesignNotePin,
DesignNoteSignedOut,
@@ -97,9 +106,9 @@ export default {
},
data() {
return {
- discussionComment: '',
isFormRendered: false,
activeDiscussion: {},
+ noteToDelete: null,
isResolving: false,
shouldChangeResolvedStatus: false,
areRepliesCollapsed: this.discussion.resolved,
@@ -107,10 +116,9 @@ export default {
};
},
computed: {
- mutationPayload() {
+ mutationVariables() {
return {
noteableId: this.noteableId,
- body: this.discussionComment,
discussionId: this.discussion.id,
};
},
@@ -156,19 +164,21 @@ export default {
onDone({ data: { createNote } }) {
if (hasErrors(createNote)) {
createAlert({ message: ADD_DISCUSSION_COMMENT_ERROR });
+ } else {
+ /**
+ * https://gitlab.com/gitlab-org/gitlab/-/issues/388314
+ *
+ * Hide the form once the create note mutation is completed.
+ */
+ this.hideForm();
}
- this.discussionComment = '';
- this.hideForm();
+
if (this.shouldChangeResolvedStatus) {
this.toggleResolvedStatus();
}
},
- onCreateNoteError(err) {
- this.$emit('create-note-error', err);
- },
hideForm() {
this.isFormRendered = false;
- this.discussionComment = '';
},
showForm() {
this.$emit('open-form', this.discussion.id);
@@ -219,13 +229,65 @@ export default {
const { source } = activeDiscussion;
return ALLOWED_ACTIVE_DISCUSSION_SOURCES.includes(source) && this.isDiscussionActive;
},
+ async showDeleteNoteConfirmationModal(note) {
+ const isLast = note?.discussion?.notes?.nodes.length === 1;
+ this.noteToDelete = { ...note, isLast };
+
+ const confirmed = await confirmAction(this.$options.i18n.deleteNote.confirmationText, {
+ primaryBtnVariant: 'danger',
+ primaryBtnText: this.$options.i18n.deleteNote.primaryModalBtnText,
+ });
+
+ if (confirmed) {
+ await this.deleteNote();
+ }
+ },
+ async deleteNote() {
+ const { id, discussion, isLast } = this.noteToDelete;
+ try {
+ await this.$apollo.mutate({
+ mutation: destroyNoteMutation,
+ variables: {
+ input: {
+ id,
+ },
+ },
+ update: (cache, { data }) => {
+ const { errors } = data.destroyNote;
+
+ if (errors?.length) {
+ this.$emit('delete-note-error', errors[0]);
+ }
+
+ const objectToIdentify = isLast
+ ? { __typename: TYPENAME_DISCUSSION, id: discussion?.id }
+ : { __typename: TYPENAME_NOTE, id };
+
+ cache.modify({
+ id: cache.identify(objectToIdentify),
+ fields: (_, { DELETE }) => DELETE,
+ });
+ },
+ optimisticResponse: {
+ destroyNote: {
+ note: null,
+ errors: [],
+ __typename: 'DestroyNotePayload',
+ },
+ },
+ });
+ } catch (error) {
+ this.$emit('delete-note-error', this.$options.i18n.deleteNote.errorText);
+ Sentry.captureException(error);
+ }
+ },
},
createNoteMutation,
};
</script>
<template>
- <div class="design-discussion-wrapper">
+ <div class="design-discussion-wrapper" @click="$emit('update-active-discussion')">
<design-note-pin :is-resolved="discussion.resolved" :label="discussion.index" />
<ul
class="design-discussion bordered-box gl-relative gl-p-0 gl-list-style-none"
@@ -235,9 +297,10 @@ export default {
:note="firstNote"
:markdown-preview-path="markdownPreviewPath"
:is-resolving="isResolving"
+ :is-discussion="true"
:noteable-id="noteableId"
:class="{ 'gl-bg-blue-50': isDiscussionActive }"
- @error="$emit('update-note-error', $event)"
+ @delete-note="showDeleteNoteConfirmationModal($event)"
>
<template v-if="isLoggedIn && discussion.resolvable" #resolve-discussion>
<gl-button
@@ -279,8 +342,9 @@ export default {
:markdown-preview-path="markdownPreviewPath"
:is-resolving="isResolving"
:noteable-id="noteableId"
+ :is-discussion="false"
:class="{ 'gl-bg-blue-50': isDiscussionActive }"
- @error="$emit('update-note-error', $event)"
+ @delete-note="showDeleteNoteConfirmationModal($event)"
/>
<li
v-show="isReplyPlaceholderVisible"
@@ -296,33 +360,24 @@ export default {
:placeholder-text="__('Reply…')"
@focus="showForm"
/>
- <apollo-mutation
+ <design-reply-form
v-else
- #default="{ mutate, loading }"
- :mutation="$options.createNoteMutation"
- :variables="{
- input: mutationPayload,
- }"
- @done="onDone"
- @error="onCreateNoteError"
+ :design-note-mutation="$options.createNoteMutation"
+ :mutation-variables="mutationVariables"
+ :markdown-preview-path="markdownPreviewPath"
+ :noteable-id="noteableId"
+ :discussion-id="discussion.id"
+ :is-discussion="false"
+ @note-submit-complete="onDone"
+ @cancel-form="hideForm"
>
- <design-reply-form
- v-model="discussionComment"
- :is-saving="loading"
- :markdown-preview-path="markdownPreviewPath"
- :noteable-id="noteableId"
- :discussion-id="discussion.id"
- @submit-form="mutate"
- @cancel-form="hideForm"
- >
- <template v-if="discussion.resolvable" #resolve-checkbox>
- <label data-testid="resolve-checkbox">
- <input v-model="shouldChangeResolvedStatus" type="checkbox" />
- {{ resolveCheckboxText }}
- </label>
- </template>
- </design-reply-form>
- </apollo-mutation>
+ <template v-if="discussion.resolvable" #resolve-checkbox>
+ <label data-testid="resolve-checkbox">
+ <input v-model="shouldChangeResolvedStatus" type="checkbox" />
+ {{ resolveCheckboxText }}
+ </label>
+ </template>
+ </design-reply-form>
</template>
</li>
</ul>
diff --git a/app/assets/javascripts/design_management/components/design_notes/design_note.vue b/app/assets/javascripts/design_management/components/design_notes/design_note.vue
index af4bf7eb14d..b92a2392948 100644
--- a/app/assets/javascripts/design_management/components/design_notes/design_note.vue
+++ b/app/assets/javascripts/design_management/components/design_notes/design_note.vue
@@ -1,6 +1,13 @@
<script>
-import { GlAvatar, GlAvatarLink, GlButton, GlLink, GlTooltipDirective } from '@gitlab/ui';
-import { ApolloMutation } from 'vue-apollo';
+import {
+ GlAvatar,
+ GlAvatarLink,
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
+ GlLink,
+ GlTooltipDirective,
+} from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
@@ -14,13 +21,16 @@ import DesignReplyForm from './design_reply_form.vue';
export default {
i18n: {
editCommentLabel: __('Edit comment'),
+ moreActionsLabel: __('More actions'),
+ deleteCommentText: __('Delete comment'),
},
components: {
- ApolloMutation,
DesignReplyForm,
GlAvatar,
GlAvatarLink,
GlButton,
+ GlDropdown,
+ GlDropdownItem,
GlLink,
TimeAgoTooltip,
TimelineEntryItem,
@@ -39,6 +49,11 @@ export default {
required: false,
default: '',
},
+ isDiscussion: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
noteableId: {
type: String,
required: true,
@@ -46,8 +61,8 @@ export default {
},
data() {
return {
- noteText: this.note.body,
isEditing: false,
+ isError: true,
};
},
computed: {
@@ -63,20 +78,24 @@ export default {
isNoteLinked() {
return extractDesignNoteId(this.$route.hash) === this.noteAnchorId;
},
- mutationPayload() {
+ mutationVariables() {
return {
id: this.note.id,
- body: this.noteText,
};
},
isEditButtonVisible() {
- return !this.isEditing && this.note.userPermissions.adminNote;
+ return !this.isEditing && this.adminPermissions;
+ },
+ isMoreActionsButtonVisible() {
+ return !this.isEditing && this.adminPermissions;
+ },
+ adminPermissions() {
+ return this.note.userPermissions.adminNote;
},
},
methods: {
hideForm() {
this.isEditing = false;
- this.noteText = this.note.body;
},
onDone({ data }) {
this.hideForm();
@@ -132,6 +151,30 @@ export default {
size="small"
@click="isEditing = true"
/>
+ <gl-dropdown
+ v-if="isMoreActionsButtonVisible"
+ v-gl-tooltip.hover
+ class="gl-display-none gl-sm-display-inline-flex! gl-ml-3"
+ icon="ellipsis_v"
+ category="tertiary"
+ data-qa-selector="design_discussion_actions_ellipsis_dropdown"
+ data-testid="more-actions-dropdown"
+ :text="$options.i18n.moreActionsLabel"
+ text-sr-only
+ :title="$options.i18n.moreActionsLabel"
+ :aria-label="$options.i18n.moreActionsLabel"
+ no-caret
+ left
+ >
+ <gl-dropdown-item
+ variant="danger"
+ data-qa-selector="delete_design_note_button"
+ data-testid="delete-note-button"
+ @click="$emit('delete-note', note)"
+ >
+ {{ $options.i18n.deleteCommentText }}
+ </gl-dropdown-item>
+ </gl-dropdown>
</div>
</div>
<template v-if="!isEditing">
@@ -143,26 +186,18 @@ export default {
></div>
<slot name="resolved-status"></slot>
</template>
- <apollo-mutation
+ <design-reply-form
v-else
- #default="{ mutate, loading }"
- :mutation="$options.updateNoteMutation"
- :variables="{
- input: mutationPayload,
- }"
- @error="$emit('error', $event)"
- @done="onDone"
- >
- <design-reply-form
- v-model="noteText"
- :is-saving="loading"
- :markdown-preview-path="markdownPreviewPath"
- :is-new-comment="false"
- :noteable-id="noteableId"
- class="gl-mt-5"
- @submit-form="mutate"
- @cancel-form="hideForm"
- />
- </apollo-mutation>
+ :markdown-preview-path="markdownPreviewPath"
+ :design-note-mutation="$options.updateNoteMutation"
+ :mutation-variables="mutationVariables"
+ :value="note.body"
+ :is-new-comment="false"
+ :is-discussion="isDiscussion"
+ :noteable-id="noteableId"
+ class="gl-mt-5"
+ @note-submit-complete="onDone"
+ @cancel-form="hideForm"
+ />
</timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue b/app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue
index 830f16b50ee..4fd90130284 100644
--- a/app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue
+++ b/app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlAlert } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { s__ } from '~/locale';
import Autosave from '~/autosave';
@@ -7,6 +7,12 @@ import { isLoggedIn } from '~/lib/utils/common_utils';
import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
+import {
+ ADD_DISCUSSION_COMMENT_ERROR,
+ ADD_IMAGE_DIFF_NOTE_ERROR,
+ UPDATE_IMAGE_DIFF_NOTE_ERROR,
+ UPDATE_NOTE_ERROR,
+} from '../../utils/error_messages';
export default {
name: 'DesignReplyForm',
@@ -23,22 +29,29 @@ export default {
components: {
MarkdownField,
GlButton,
+ GlAlert,
},
props: {
+ designNoteMutation: {
+ type: Object,
+ required: true,
+ },
+ mutationVariables: {
+ type: Object,
+ required: false,
+ default: null,
+ },
markdownPreviewPath: {
type: String,
required: false,
default: '',
},
- value: {
- type: String,
- required: true,
- },
- isSaving: {
+ isNewComment: {
type: Boolean,
- required: true,
+ required: false,
+ default: true,
},
- isNewComment: {
+ isDiscussion: {
type: Boolean,
required: false,
default: true,
@@ -52,16 +65,24 @@ export default {
required: false,
default: 'new',
},
+ value: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
return {
- formText: this.value,
+ noteText: this.value,
+ saving: false,
+ noteUpdateDirty: false,
isLoggedIn: isLoggedIn(),
+ errorMessage: '',
};
},
computed: {
hasValue() {
- return this.value.trim().length > 0;
+ return this.noteText.length > 0;
},
buttonText() {
return this.isNewComment
@@ -75,18 +96,69 @@ export default {
mounted() {
this.focusInput();
},
+ beforeDestroy() {
+ /**
+ * https://gitlab.com/gitlab-org/gitlab/-/issues/388314
+ * Reply form closes and component destroys
+ * only when comment submission was successful,
+ * so we're safe to clear autosave data here conditionally.
+ */
+ this.$nextTick(() => {
+ if (!this.noteUpdateDirty) {
+ this.autosaveDiscussion.reset();
+ }
+ });
+ },
methods: {
+ handleInput() {
+ /**
+ * While the form is saving using ctrl+enter
+ * Do not mark it as dirty.
+ *
+ */
+ if (!this.saving) {
+ this.noteUpdateDirty = true;
+ }
+ },
submitForm() {
if (this.hasValue) {
- this.$emit('submit-form');
- this.autosaveDiscussion.reset();
+ this.saving = true;
+ this.$apollo
+ .mutate({
+ mutation: this.designNoteMutation,
+ variables: {
+ input: {
+ ...this.mutationVariables,
+ body: this.noteText,
+ },
+ },
+ update: () => {
+ this.noteUpdateDirty = false;
+ },
+ })
+ .then((response) => {
+ this.$emit('note-submit-complete', response);
+ })
+ .catch(() => {
+ this.errorMessage = this.getErrorMessage();
+ })
+ .finally(() => {
+ this.saving = false;
+ });
}
},
+ getErrorMessage() {
+ if (this.isNewComment) {
+ return this.isDiscussion ? ADD_IMAGE_DIFF_NOTE_ERROR : ADD_DISCUSSION_COMMENT_ERROR;
+ }
+ return this.isDiscussion ? UPDATE_IMAGE_DIFF_NOTE_ERROR : UPDATE_NOTE_ERROR;
+ },
cancelComment() {
- if (this.hasValue && this.formText !== this.value) {
+ if (this.hasValue && this.noteUpdateDirty) {
this.confirmCancelCommentModal();
} else {
this.$emit('cancel-form');
+ this.noteUpdateDirty = false;
}
},
async confirmCancelCommentModal() {
@@ -130,24 +202,29 @@ export default {
<template>
<form class="new-note common-note-form" @submit.prevent>
+ <div v-if="errorMessage" class="gl-pb-3">
+ <gl-alert variant="danger" @dismiss="errorMessage = null">
+ {{ errorMessage }}
+ </gl-alert>
+ </div>
<markdown-field
:markdown-preview-path="markdownPreviewPath"
:enable-autocomplete="true"
- :textarea-value="value"
+ :textarea-value="noteText"
:markdown-docs-path="$options.markdownDocsPath"
class="bordered-box"
>
<template #textarea>
<textarea
ref="textarea"
- :value="value"
+ v-model.trim="noteText"
class="note-textarea js-gfm-input js-autosize markdown-area"
dir="auto"
data-supports-quick-actions="false"
data-qa-selector="note_textarea"
:aria-label="__('Description')"
:placeholder="__('Write a comment…')"
- @input="$emit('input', $event.target.value)"
+ @input="handleInput"
@keydown.meta.enter="submitForm"
@keydown.ctrl.enter="submitForm"
@keyup.esc.stop="cancelComment"
@@ -159,7 +236,8 @@ export default {
<div class="note-form-actions gl-display-flex">
<gl-button
ref="submitButton"
- :disabled="!hasValue || isSaving"
+ :disabled="!hasValue"
+ :loading="saving"
class="gl-mr-3 gl-w-auto!"
category="primary"
variant="confirm"
diff --git a/app/assets/javascripts/design_management/components/design_sidebar.vue b/app/assets/javascripts/design_management/components/design_sidebar.vue
index 24cc93f5eaf..c34d5cea0c2 100644
--- a/app/assets/javascripts/design_management/components/design_sidebar.vue
+++ b/app/assets/javascripts/design_management/components/design_sidebar.vue
@@ -57,7 +57,6 @@ export default {
},
data() {
return {
- isResolvedDiscussionsExpanded: this.resolvedDiscussionsExpanded,
discussionWithOpenForm: '',
isLoggedIn: isLoggedIn(),
};
@@ -87,13 +86,13 @@ export default {
unresolvedDiscussions() {
return this.discussions.filter((discussion) => !discussion.resolved);
},
- },
- watch: {
- resolvedDiscussionsExpanded(resolvedDiscussionsExpanded) {
- this.isResolvedDiscussionsExpanded = resolvedDiscussionsExpanded;
- },
- isResolvedDiscussionsExpanded() {
- this.$emit('toggleResolvedComments');
+ isResolvedDiscussionsExpanded: {
+ get() {
+ return this.resolvedDiscussionsExpanded;
+ },
+ set(isExpanded) {
+ this.$emit('toggleResolvedComments', isExpanded);
+ },
},
},
mounted() {
@@ -129,7 +128,7 @@ export default {
</script>
<template>
- <div class="image-notes gl-pt-0" @click="handleSidebarClick">
+ <div class="image-notes gl-pt-0" @click.self="handleSidebarClick">
<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"
>
@@ -179,8 +178,9 @@ export default {
data-testid="unresolved-discussion"
@create-note-error="$emit('onDesignDiscussionError', $event)"
@update-note-error="$emit('updateNoteError', $event)"
+ @delete-note-error="$emit('deleteNoteError', $event)"
@resolve-discussion-error="$emit('resolveDiscussionError', $event)"
- @click.native.stop="updateActiveDiscussion(discussion.notes[0].id)"
+ @update-active-discussion="updateActiveDiscussion(discussion.notes[0].id)"
@open-form="updateDiscussionWithOpenForm"
/>
<gl-accordion v-if="hasResolvedDiscussions" :header-level="3" class="gl-mb-5">
@@ -202,9 +202,10 @@ export default {
:discussion-with-open-form="discussionWithOpenForm"
data-testid="resolved-discussion"
@error="$emit('onDesignDiscussionError', $event)"
- @updateNoteError="$emit('updateNoteError', $event)"
+ @update-note-error="$emit('updateNoteError', $event)"
+ @delete-note-error="$emit('deleteNoteError', $event)"
@open-form="updateDiscussionWithOpenForm"
- @click.native.stop="updateActiveDiscussion(discussion.notes[0].id)"
+ @update-active-discussion="updateActiveDiscussion(discussion.notes[0].id)"
/>
</gl-accordion-item>
</gl-accordion>
diff --git a/app/assets/javascripts/design_management/components/toolbar/index.vue b/app/assets/javascripts/design_management/components/toolbar/index.vue
index 6d571365306..cd76b6c1885 100644
--- a/app/assets/javascripts/design_management/components/toolbar/index.vue
+++ b/app/assets/javascripts/design_management/components/toolbar/index.vue
@@ -60,7 +60,8 @@ export default {
},
image: {
type: String,
- required: true,
+ required: false,
+ default: '',
},
isLoading: {
type: Boolean,
diff --git a/app/assets/javascripts/design_management/constants.js b/app/assets/javascripts/design_management/constants.js
index afe621ac3c5..6720245b5f1 100644
--- a/app/assets/javascripts/design_management/constants.js
+++ b/app/assets/javascripts/design_management/constants.js
@@ -1,3 +1,4 @@
+import { __ } from '~/locale';
// WARNING: replace this with something
// more sensical as per https://gitlab.com/gitlab-org/gitlab/issues/118611
export const VALID_DESIGN_FILE_MIMETYPE = {
@@ -14,3 +15,7 @@ export const ACTIVE_DISCUSSION_SOURCE_TYPES = {
export const DESIGN_DETAIL_LAYOUT_CLASSLIST = ['design-detail-layout', 'overflow-hidden', 'm-0'];
export const MAXIMUM_FILE_UPLOAD_LIMIT = 10;
+
+export const DELETE_NOTE_ERROR_MSG = __(
+ 'Something went wrong when deleting a comment. Please try again.',
+);
diff --git a/app/assets/javascripts/design_management/graphql/mutations/destroy_note.mutation.graphql b/app/assets/javascripts/design_management/graphql/mutations/destroy_note.mutation.graphql
new file mode 100644
index 00000000000..58fb05e2140
--- /dev/null
+++ b/app/assets/javascripts/design_management/graphql/mutations/destroy_note.mutation.graphql
@@ -0,0 +1,8 @@
+mutation destroyNote($input: DestroyNoteInput!) {
+ destroyNote(input: $input) {
+ errors
+ note {
+ id
+ }
+ }
+}
diff --git a/app/assets/javascripts/design_management/index.js b/app/assets/javascripts/design_management/index.js
index b856ac6c627..80b146c9209 100644
--- a/app/assets/javascripts/design_management/index.js
+++ b/app/assets/javascripts/design_management/index.js
@@ -8,7 +8,14 @@ import createRouter from './router';
export default () => {
const el = document.querySelector('.js-design-management');
- const { issueIid, projectPath, issuePath, registerPath, signInPath } = el.dataset;
+ const {
+ issueIid,
+ projectPath,
+ issuePath,
+ registerPath,
+ signInPath,
+ savedRepliesNewPath,
+ } = el.dataset;
const router = createRouter(issuePath);
apolloProvider.clients.defaultClient.cache.writeQuery({
@@ -32,6 +39,7 @@ export default () => {
issueIid,
registerPath,
signInPath,
+ newSavedRepliesPath: savedRepliesNewPath,
},
mounted() {
performanceMarkAndMeasure({
diff --git a/app/assets/javascripts/design_management/mixins/all_designs.js b/app/assets/javascripts/design_management/mixins/all_designs.js
index b783ec43cd1..b182e68260a 100644
--- a/app/assets/javascripts/design_management/mixins/all_designs.js
+++ b/app/assets/javascripts/design_management/mixins/all_designs.js
@@ -1,6 +1,6 @@
import { propertyOf } from 'lodash';
import getDesignListQuery from 'shared_queries/design_management/get_design_list.query.graphql';
-import { createAlert, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/alert';
import { s__ } from '~/locale';
import { DESIGNS_ROUTE_NAME } from '../router/constants';
import allVersionsMixin from './all_versions';
diff --git a/app/assets/javascripts/design_management/pages/design/index.vue b/app/assets/javascripts/design_management/pages/design/index.vue
index f448e2f9e3d..0251ffe28f9 100644
--- a/app/assets/javascripts/design_management/pages/design/index.vue
+++ b/app/assets/javascripts/design_management/pages/design/index.vue
@@ -2,9 +2,8 @@
import { GlAlert } from '@gitlab/ui';
import { isNull } from 'lodash';
import Mousetrap from 'mousetrap';
-import { ApolloMutation } from 'vue-apollo';
import { keysFor, ISSUE_CLOSE_DESIGN } from '~/behaviors/shortcuts/keybindings';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { fetchPolicies } from '~/lib/graphql';
import { updateGlobalTodoCount } from '~/sidebar/utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -34,13 +33,11 @@ import {
getPageLayoutElement,
} from '../../utils/design_management_utils';
import {
- ADD_DISCUSSION_COMMENT_ERROR,
- ADD_IMAGE_DIFF_NOTE_ERROR,
UPDATE_IMAGE_DIFF_NOTE_ERROR,
DESIGN_NOT_FOUND_ERROR,
DESIGN_VERSION_NOT_EXIST_ERROR,
- UPDATE_NOTE_ERROR,
TOGGLE_TODO_ERROR,
+ DELETE_NOTE_ERROR,
designDeletionError,
} from '../../utils/error_messages';
import { trackDesignDetailView, servicePingDesignDetailView } from '../../utils/tracking';
@@ -50,7 +47,6 @@ const DEFAULT_MAX_SCALE = 2;
export default {
components: {
- ApolloMutation,
DesignReplyForm,
DesignPresentation,
DesignScaler,
@@ -90,7 +86,6 @@ export default {
data() {
return {
design: {},
- comment: '',
annotationCoordinates: null,
errorMessage: '',
scale: DEFAULT_SCALE,
@@ -129,9 +124,6 @@ export default {
markdownPreviewPath() {
return `/${this.projectPath}/preview_markdown?target_type=Issue`;
},
- isSubmitButtonDisabled() {
- return this.comment.trim().length === 0;
- },
designVariables() {
return {
fullPath: this.projectPath,
@@ -140,11 +132,10 @@ export default {
atVersion: this.designsVersion,
};
},
- mutationPayload() {
+ mutationVariables() {
const { x, y, width, height } = this.annotationCoordinates;
return {
noteableId: this.design.id,
- body: this.comment,
position: {
headSha: this.design.diffRefs.headSha,
baseSha: this.design.diffRefs.baseSha,
@@ -196,13 +187,23 @@ export default {
Mousetrap.unbind(keysFor(ISSUE_CLOSE_DESIGN));
},
methods: {
- addImageDiffNoteToStore(store, { data: { createImageDiffNote } }) {
+ addImageDiffNoteToStore({ data }) {
+ const { createImageDiffNote } = data;
+ /**
+ * https://gitlab.com/gitlab-org/gitlab/-/issues/388314
+ *
+ * The getClient method is not documented. In future,
+ * need to check for any alternative.
+ */
+ const { cache } = this.$apollo.getClient();
+
updateStoreAfterAddImageDiffNote(
- store,
+ cache,
createImageDiffNote,
getDesignQuery,
this.designVariables,
);
+ this.closeCommentForm(data);
},
updateImageDiffNoteInStore(store, { data: { repositionImageDiffNote } }) {
return updateStoreAfterRepositionImageDiffNote(
@@ -249,7 +250,7 @@ export default {
},
onQueryError(message) {
// because we redirect user to /designs (the issue page),
- // we want to create these flashes on the issue page
+ // we want to create these alerts on the issue page
createAlert({ message });
this.$router.push({ name: this.$options.DESIGNS_ROUTE_NAME });
},
@@ -257,14 +258,8 @@ export default {
this.errorMessage = message;
if (e) throw e;
},
- onCreateImageDiffNoteError(e) {
- this.onError(ADD_IMAGE_DIFF_NOTE_ERROR, e);
- },
- onUpdateNoteError(e) {
- this.onError(UPDATE_NOTE_ERROR, e);
- },
- onDesignDiscussionError(e) {
- this.onError(ADD_DISCUSSION_COMMENT_ERROR, e);
+ onDeleteNoteError(e) {
+ this.onError(DELETE_NOTE_ERROR, e);
},
onUpdateImageDiffNoteError(e) {
this.onError(UPDATE_IMAGE_DIFF_NOTE_ERROR, e);
@@ -285,7 +280,6 @@ export default {
}
},
closeCommentForm(data) {
- this.comment = '';
this.annotationCoordinates = null;
if (data?.data && !isNull(this.prevCurrentUserTodos)) {
@@ -324,8 +318,8 @@ export default {
const diffNoteGid = noteId ? toDiffNoteGid(noteId) : undefined;
return this.updateActiveDiscussion(diffNoteGid, ACTIVE_DISCUSSION_SOURCE_TYPES.url);
},
- toggleResolvedComments() {
- this.resolvedDiscussionsExpanded = !this.resolvedDiscussionsExpanded;
+ toggleResolvedComments(newValue) {
+ this.resolvedDiscussionsExpanded = newValue;
},
setMaxScale(event) {
this.maxScale = 1 / event;
@@ -394,35 +388,24 @@ export default {
:resolved-discussions-expanded="resolvedDiscussionsExpanded"
:markdown-preview-path="markdownPreviewPath"
:is-loading="isLoading"
- @onDesignDiscussionError="onDesignDiscussionError"
- @onCreateImageDiffNoteError="onCreateImageDiffNoteError"
- @updateNoteError="onUpdateNoteError"
+ @deleteNoteError="onDeleteNoteError"
@resolveDiscussionError="onResolveDiscussionError"
@toggleResolvedComments="toggleResolvedComments"
@todoError="onTodoError"
>
<template #reply-form>
- <apollo-mutation
+ <design-reply-form
v-if="isAnnotating"
- #default="{ mutate, loading }"
- :mutation="$options.createImageDiffNoteMutation"
- :variables="{
- input: mutationPayload,
- }"
- :update="addImageDiffNoteToStore"
- @done="closeCommentForm"
- @error="onCreateImageDiffNoteError"
- >
- <design-reply-form
- ref="newDiscussionForm"
- v-model="comment"
- :is-saving="loading"
- :markdown-preview-path="markdownPreviewPath"
- :noteable-id="design.id"
- @submit-form="mutate"
- @cancel-form="closeCommentForm"
- /> </apollo-mutation
- ></template>
+ ref="newDiscussionForm"
+ :design-note-mutation="$options.createImageDiffNoteMutation"
+ :mutation-variables="mutationVariables"
+ :markdown-preview-path="markdownPreviewPath"
+ :noteable-id="design.id"
+ :is-discussion="true"
+ @note-submit-complete="addImageDiffNoteToStore"
+ @cancel-form="closeCommentForm"
+ />
+ </template>
</design-sidebar>
</div>
</template>
diff --git a/app/assets/javascripts/design_management/utils/cache_update.js b/app/assets/javascripts/design_management/utils/cache_update.js
index cfec5828c85..9ef0f336d43 100644
--- a/app/assets/javascripts/design_management/utils/cache_update.js
+++ b/app/assets/javascripts/design_management/utils/cache_update.js
@@ -2,7 +2,7 @@
import produce from 'immer';
import { differenceBy } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { extractCurrentDiscussion, extractDesign, extractDesigns } from './design_management_utils';
import {
ADD_IMAGE_DIFF_NOTE_ERROR,
diff --git a/app/assets/javascripts/design_management/utils/error_messages.js b/app/assets/javascripts/design_management/utils/error_messages.js
index 42f752efc9e..1ed054abe22 100644
--- a/app/assets/javascripts/design_management/utils/error_messages.js
+++ b/app/assets/javascripts/design_management/utils/error_messages.js
@@ -13,7 +13,13 @@ export const UPDATE_IMAGE_DIFF_NOTE_ERROR = s__(
'DesignManagement|Could not update discussion. Please try again.',
);
-export const UPDATE_NOTE_ERROR = s__('DesignManagement|Could not update note. Please try again.');
+export const UPDATE_NOTE_ERROR = s__(
+ 'DesignManagement|Could not update comment. Please try again.',
+);
+
+export const DELETE_NOTE_ERROR = s__(
+ 'DesignManagement|Could not delete comment. Please try again.',
+);
export const UPLOAD_DESIGN_ERROR = s__(
'DesignManagement|Error uploading a new design. Please try again.',
diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js
index 65816495432..e3cd43ac22f 100644
--- a/app/assets/javascripts/diff.js
+++ b/app/assets/javascripts/diff.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { merge } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import FilesCommentButton from './files_comment_button';
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 35d1a564178..9ccba88f7e6 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -11,7 +11,7 @@ import {
MR_COMMITS_NEXT_COMMIT,
MR_COMMITS_PREVIOUS_COMMIT,
} from '~/behaviors/shortcuts/keybindings';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { isSingleViewStyle } from '~/helpers/diffs_helper';
import { helpPagePath } from '~/helpers/help_page_helper';
import { parseBoolean } from '~/lib/utils/common_utils';
@@ -21,6 +21,7 @@ import PanelResizer from '~/vue_shared/components/panel_resizer.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import notesEventHub from '~/notes/event_hub';
+import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller';
import {
TREE_LIST_WIDTH_STORAGE_KEY,
INITIAL_TREE_WIDTH,
@@ -53,15 +54,14 @@ import HiddenFilesWarning from './hidden_files_warning.vue';
import NoChanges from './no_changes.vue';
import TreeList from './tree_list.vue';
import VirtualScrollerScrollSync from './virtual_scroller_scroll_sync';
+import PreRenderer from './pre_renderer.vue';
export default {
name: 'DiffsApp',
components: {
- DynamicScroller: () =>
- import('vendor/vue-virtual-scroller').then(({ DynamicScroller }) => DynamicScroller),
- DynamicScrollerItem: () =>
- import('vendor/vue-virtual-scroller').then(({ DynamicScrollerItem }) => DynamicScrollerItem),
- PreRenderer: () => import('./pre_renderer.vue').then((PreRenderer) => PreRenderer),
+ DynamicScroller,
+ DynamicScrollerItem,
+ PreRenderer,
VirtualScrollerScrollSync,
CompareVersions,
DiffFile,
@@ -95,6 +95,10 @@ export default {
type: String,
required: true,
},
+ endpointDiffForPath: {
+ type: String,
+ required: true,
+ },
endpointCoverage: {
type: String,
required: false,
@@ -226,6 +230,7 @@ export default {
'isVirtualScrollingEnabled',
'isBatchLoading',
'isBatchLoadingError',
+ 'flatBlobsList',
]),
...mapGetters(['isNotesFetched', 'getNoteableData']),
diffs() {
@@ -241,7 +246,7 @@ export default {
return this.currentUser.can_fork === true && this.currentUser.can_create_merge_request;
},
renderDiffFiles() {
- return this.diffFiles.length > 0;
+ return this.flatBlobsList.length > 0;
},
renderFileTree() {
return this.renderDiffFiles && this.showTreeList;
@@ -253,7 +258,7 @@ export default {
return this.startVersion === null && this.latestDiff;
},
showFileByFileNavigation() {
- return this.diffFiles.length > 1 && this.viewDiffsFileByFile;
+ return this.flatBlobsList.length > 1 && this.viewDiffsFileByFile;
},
currentFileNumber() {
return this.currentDiffIndex + 1;
@@ -264,9 +269,9 @@ export default {
return currentDiffIndex >= 1 ? currentDiffIndex : null;
},
nextFileNumber() {
- const { currentFileNumber, diffFiles } = this;
+ const { currentFileNumber, flatBlobsList } = this;
- return currentFileNumber < diffFiles.length ? currentFileNumber + 1 : null;
+ return currentFileNumber < flatBlobsList.length ? currentFileNumber + 1 : null;
},
visibleWarning() {
let visible = false;
@@ -321,6 +326,7 @@ export default {
endpoint: this.endpoint,
endpointMetadata: this.endpointMetadata,
endpointBatch: this.endpointBatch,
+ endpointDiffForPath: this.endpointDiffForPath,
endpointCoverage: this.endpointCoverage,
endpointUpdateUser: this.endpointUpdateUser,
projectPath: this.projectPath,
@@ -385,7 +391,7 @@ export default {
this.subscribeToEvents();
this.unwatchDiscussions = this.$watch(
- () => `${this.diffFiles.length}:${this.$store.state.notes.discussions.length}`,
+ () => `${this.flatBlobsList.length}:${this.$store.state.notes.discussions.length}`,
() => {
this.setDiscussions();
@@ -572,8 +578,8 @@ export default {
},
jumpToFile(step) {
const targetIndex = this.currentDiffIndex + step;
- if (targetIndex >= 0 && targetIndex < this.diffFiles.length) {
- this.scrollToFile({ path: this.diffFiles[targetIndex].file_path });
+ if (targetIndex >= 0 && targetIndex < this.flatBlobsList.length) {
+ this.scrollToFile({ path: this.flatBlobsList[targetIndex].path });
}
},
setTreeDisplay() {
@@ -582,7 +588,7 @@ export default {
if (storedTreeShow !== null) {
showTreeList = parseBoolean(storedTreeShow);
- } else if (!bp.isDesktop() || (!this.isBatchLoading && this.diffFiles.length <= 1)) {
+ } else if (!bp.isDesktop() || (!this.isBatchLoading && this.flatBlobsList.length <= 1)) {
showTreeList = false;
}
@@ -753,7 +759,7 @@ export default {
/>
<gl-sprintf :message="__('File %{current} of %{total}')">
<template #current>{{ currentFileNumber }}</template>
- <template #total>{{ diffFiles.length }}</template>
+ <template #total>{{ flatBlobsList.length }}</template>
</gl-sprintf>
</div>
<gl-loading-icon v-else-if="retrievingBatches" size="lg" />
diff --git a/app/assets/javascripts/diffs/components/diff_code_quality.vue b/app/assets/javascripts/diffs/components/diff_code_quality.vue
index 11aa856619b..5392c631c14 100644
--- a/app/assets/javascripts/diffs/components/diff_code_quality.vue
+++ b/app/assets/javascripts/diffs/components/diff_code_quality.vue
@@ -28,7 +28,7 @@ export default {
<template>
<div
data-testid="diff-codequality"
- class="gl-relative codequality-findings-list gl-border-top-1 gl-border-bottom-1 gl-bg-gray-10 gl-pl-5 gl-pt-4 gl-pb-4"
+ class="gl-relative codequality-findings-list gl-border-top-1 gl-border-bottom-1 gl-bg-gray-10 gl-text-black-normal gl-pl-5 gl-pt-4 gl-pb-4"
>
<h4
data-testid="diff-codequality-findings-heading"
diff --git a/app/assets/javascripts/diffs/components/diff_expansion_cell.vue b/app/assets/javascripts/diffs/components/diff_expansion_cell.vue
index 8fcbc4b5cce..53a55aac1ec 100644
--- a/app/assets/javascripts/diffs/components/diff_expansion_cell.vue
+++ b/app/assets/javascripts/diffs/components/diff_expansion_cell.vue
@@ -2,7 +2,7 @@
import { GlTooltipDirective, GlIcon, GlLoadingIcon } from '@gitlab/ui';
import { mapActions } from 'vuex';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__, sprintf } from '~/locale';
import { UNFOLD_COUNT, INLINE_DIFF_LINES_KEY } from '../constants';
import * as utils from '../store/utils';
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index 564f776edd2..c19174dda8a 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -5,7 +5,7 @@ import { mapActions, mapGetters, mapState } from 'vuex';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { IdState } from 'vendor/vue-virtual-scroller';
import DiffContent from 'jh_else_ce/diffs/components/diff_content.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { hasDiff } from '~/helpers/diffs_helper';
import { diffViewerErrors } from '~/ide/constants';
import { scrollToElement } from '~/lib/utils/common_utils';
diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue
index dfca6d61270..1f5c9b4f2f5 100644
--- a/app/assets/javascripts/diffs/components/diff_row.vue
+++ b/app/assets/javascripts/diffs/components/diff_row.vue
@@ -6,6 +6,7 @@ https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57842
* */
import { memoize } from 'lodash';
import { isLoggedIn } from '~/lib/utils/common_utils';
+import { compatFunctionalMixin } from '~/lib/utils/vue3compat/compat_functional_mixin';
import {
PARALLEL_DIFF_VIEW_TYPE,
CONFLICT_MARKER_THEIR,
@@ -24,6 +25,10 @@ import * as utils from './diff_row_utils';
export default {
DiffGutterAvatars,
CodeQualityGutterIcon: () => import('ee_component/diffs/components/code_quality_gutter_icon.vue'),
+
+ // Temporary mixin for migration from Vue.js 2 to @vue/compat
+ mixins: [compatFunctionalMixin],
+
props: {
fileHash: {
type: String,
diff --git a/app/assets/javascripts/diffs/components/file_row_stats.vue b/app/assets/javascripts/diffs/components/file_row_stats.vue
index 784f74e498f..f99f363a6be 100644
--- a/app/assets/javascripts/diffs/components/file_row_stats.vue
+++ b/app/assets/javascripts/diffs/components/file_row_stats.vue
@@ -10,7 +10,7 @@ export default {
</script>
<template>
- <span v-once class="file-row-stats">
+ <span class="file-row-stats">
<span class="cgreen"> +{{ file.addedLines }} </span>
<span class="cred"> -{{ file.removedLines }} </span>
</span>
diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue
index 8bb1872567c..ab08c72b08f 100644
--- a/app/assets/javascripts/diffs/components/tree_list.vue
+++ b/app/assets/javascripts/diffs/components/tree_list.vue
@@ -2,9 +2,10 @@
import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import micromatch from 'micromatch';
+import { debounce } from 'lodash';
import { getModifierKey } from '~/constants';
import { s__, sprintf } from '~/locale';
-import FileTree from '~/vue_shared/components/file_tree.vue';
+import { RecycleScroller } from 'vendor/vue-virtual-scroller';
import DiffFileRow from './diff_file_row.vue';
const MODIFIER_KEY = getModifierKey();
@@ -15,7 +16,8 @@ export default {
},
components: {
GlIcon,
- FileTree,
+ DiffFileRow,
+ RecycleScroller,
},
props: {
hideFileStats: {
@@ -26,6 +28,10 @@ export default {
data() {
return {
search: '',
+ scrollerHeight: 0,
+ resizeObserver: null,
+ rowHeight: 0,
+ debouncedHeightCalc: null,
};
},
computed: {
@@ -61,12 +67,51 @@ export default {
return acc;
}, []);
},
+ // Flatten the treeList so there's no nested trees
+ // This gives us fixed row height for virtual scrolling
+ // in: [{ path: 'a', tree: [{ path: 'b' }] }, { path: 'c' }]
+ // out: [{ path: 'a', tree: [{ path: 'b' }] }, { path: 'b' }, { path: 'c' }]
+ flatFilteredTreeList() {
+ const result = [];
+ const createFlatten = (level) => (item) => {
+ result.push({
+ ...item,
+ level: item.isHeader ? 0 : level,
+ key: item.key || item.path,
+ });
+ if (item.opened || item.isHeader) {
+ item.tree.forEach(createFlatten(level + 1));
+ }
+ };
+
+ this.filteredTreeList.forEach(createFlatten(0));
+
+ return result;
+ },
+ },
+ created() {
+ this.debouncedHeightCalc = debounce(this.calculateScrollerHeight, 50);
+ },
+ mounted() {
+ const heightProp = getComputedStyle(this.$refs.wrapper).getPropertyValue('--file-row-height');
+ this.rowHeight = parseInt(heightProp, 10);
+ this.calculateScrollerHeight();
+ this.resizeObserver = new ResizeObserver(() => {
+ this.debouncedHeightCalc();
+ });
+ this.resizeObserver.observe(this.$refs.scrollRoot);
+ },
+ beforeDestroy() {
+ this.resizeObserver.disconnect();
},
methods: {
...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile']),
clearSearch() {
this.search = '';
},
+ calculateScrollerHeight() {
+ this.scrollerHeight = this.$refs.scrollRoot.clientHeight;
+ },
},
searchPlaceholder: sprintf(s__('MergeRequest|Search (e.g. *.vue) (%{MODIFIER_KEY}P)'), {
MODIFIER_KEY,
@@ -76,8 +121,12 @@ export default {
</script>
<template>
- <div class="tree-list-holder d-flex flex-column" data-qa-selector="file_tree_container">
- <div class="gl-mb-3 position-relative tree-list-search d-flex">
+ <div
+ ref="wrapper"
+ class="tree-list-holder d-flex flex-column"
+ data-qa-selector="file_tree_container"
+ >
+ <div class="gl-pb-3 position-relative tree-list-search d-flex">
<div class="flex-fill d-flex">
<gl-icon name="search" class="position-absolute tree-list-icon" />
<label for="diff-tree-search" class="sr-only">{{ $options.searchPlaceholder }}</label>
@@ -89,6 +138,7 @@ export default {
name="diff-tree-search"
class="form-control"
data-testid="diff-tree-search"
+ data-qa-selector="diff_tree_search"
/>
<button
v-show="search"
@@ -101,24 +151,37 @@ export default {
</button>
</div>
</div>
- <div :class="{ 'pt-0 tree-list-blobs': !renderTreeList || search }" class="tree-list-scroll">
- <template v-if="filteredTreeList.length">
- <file-tree
- v-for="file in filteredTreeList"
- :key="file.key"
- :file="file"
- :level="0"
- :viewed-files="viewedDiffFileIds"
- :hide-file-stats="hideFileStats"
- :file-row-component="$options.DiffFileRow"
- :current-diff-file-id="currentDiffFileId"
- :style="{ '--level': 0 }"
- :class="{ 'tree-list-parent': file.tree.length }"
- class="gl-relative"
- @toggleTreeOpen="toggleTreeOpen"
- @clickFile="(path) => scrollToFile({ path })"
- />
- </template>
+ <div
+ ref="scrollRoot"
+ :class="{ 'tree-list-blobs': !renderTreeList || search }"
+ class="gl-flex-grow-1"
+ >
+ <recycle-scroller
+ v-if="flatFilteredTreeList.length"
+ :style="{ height: `${scrollerHeight}px` }"
+ :items="flatFilteredTreeList"
+ :item-size="rowHeight"
+ :buffer="100"
+ key-field="key"
+ >
+ <template #default="{ item }">
+ <diff-file-row
+ :file="item"
+ :level="item.level"
+ :viewed-files="viewedDiffFileIds"
+ :hide-file-stats="hideFileStats"
+ :current-diff-file-id="currentDiffFileId"
+ :style="{ '--level': item.level }"
+ :class="{ 'tree-list-parent': item.tree.length }"
+ class="gl-relative"
+ @toggleTreeOpen="toggleTreeOpen"
+ @clickFile="(path) => scrollToFile({ path })"
+ />
+ </template>
+ <template #after>
+ <div class="tree-list-gutter"></div>
+ </template>
+ </recycle-scroller>
<p v-else class="prepend-top-20 append-bottom-20 text-center">
{{ s__('MergeRequest|No files found') }}
</p>
diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js
index 6c0c9c4e1d0..873c4819669 100644
--- a/app/assets/javascripts/diffs/constants.js
+++ b/app/assets/javascripts/diffs/constants.js
@@ -6,10 +6,8 @@ export const OLD_NO_NEW_LINE_TYPE = 'old-nonewline';
export const NEW_NO_NEW_LINE_TYPE = 'new-nonewline';
export const CONTEXT_LINE_TYPE = 'context';
export const EMPTY_CELL_TYPE = 'empty-cell';
-export const COMMENT_FORM_TYPE = 'commentForm';
export const DIFF_NOTE_TYPE = 'DiffNote';
export const LEGACY_DIFF_NOTE_TYPE = 'LegacyDiffNote';
-export const NOTE_TYPE = 'Note';
export const NEW_LINE_TYPE = 'new';
export const OLD_LINE_TYPE = 'old';
export const TEXT_DIFF_POSITION_TYPE = 'text';
@@ -17,14 +15,10 @@ export const IMAGE_DIFF_POSITION_TYPE = 'image';
export const LINE_POSITION_LEFT = 'left';
export const LINE_POSITION_RIGHT = 'right';
-export const LINE_SIDE_LEFT = 'left-side';
-export const LINE_SIDE_RIGHT = 'right-side';
export const DIFF_VIEW_COOKIE_NAME = 'diff_view';
export const DIFF_WHITESPACE_COOKIE_NAME = 'diff_whitespace';
export const LINE_HOVER_CLASS_NAME = 'is-over';
-export const LINE_UNFOLD_CLASS_NAME = 'unfold js-unfold';
-export const CONTEXT_LINE_CLASS_NAME = 'diff-expanded';
export const UNFOLD_COUNT = 20;
export const COUNT_OF_AVATARS_IN_GUTTER = 3;
@@ -46,14 +40,12 @@ export const TREE_HIDE_STATS_WIDTH = 260;
export const OLD_LINE_KEY = 'old_line';
export const NEW_LINE_KEY = 'new_line';
export const TYPE_KEY = 'type';
-export const LEFT_LINE_KEY = 'left';
export const MAX_RENDERING_DIFF_LINES = 500;
export const MAX_RENDERING_BULK_ROWS = 30;
export const MIN_RENDERING_MS = 2;
export const START_RENDERING_INDEX = 200;
export const INLINE_DIFF_LINES_KEY = 'highlighted_diff_lines';
-export const PARALLEL_DIFF_LINES_KEY = 'parallel_diff_lines';
export const DIFF_COMPARE_BASE_VERSION_INDEX = -1;
export const DIFF_COMPARE_HEAD_VERSION_INDEX = -2;
diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js
index 7da5ef54b80..00a08434dac 100644
--- a/app/assets/javascripts/diffs/index.js
+++ b/app/assets/javascripts/diffs/index.js
@@ -1,5 +1,7 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import { mapActions, mapState, mapGetters } from 'vuex';
+import { apolloProvider } from '~/graphql_shared/issuable_client';
import { getCookie, parseBoolean, removeCookie } from '~/lib/utils/common_utils';
import notesStore from '~/mr_notes/stores';
@@ -11,20 +13,28 @@ import { getReviewsForMergeRequest } from './utils/file_reviews';
import { getDerivedMergeRequestInformation } from './utils/merge_request';
export default function initDiffsApp(store = notesStore) {
+ const el = document.getElementById('js-diffs-app');
+ const { dataset } = el;
+
+ Vue.use(VueApollo);
+
const vm = new Vue({
- el: '#js-diffs-app',
+ el,
name: 'MergeRequestDiffs',
components: {
DiffsApp,
},
store,
+ apolloProvider,
+ provide: {
+ newSavedRepliesPath: dataset.savedRepliesNewPath,
+ },
data() {
- const { dataset } = document.querySelector(this.$options.el);
-
return {
endpoint: dataset.endpoint,
endpointMetadata: dataset.endpointMetadata || '',
endpointBatch: dataset.endpointBatch || '',
+ endpointDiffForPath: dataset.endpointDiffForPath || '',
endpointCoverage: dataset.endpointCoverage || '',
endpointCodequality: dataset.endpointCodequality || '',
endpointUpdateUser: dataset.updateCurrentUserPath,
@@ -86,6 +96,7 @@ export default function initDiffsApp(store = notesStore) {
endpoint: this.endpoint,
endpointMetadata: this.endpointMetadata,
endpointBatch: this.endpointBatch,
+ endpointDiffForPath: this.endpointDiffForPath,
endpointCoverage: this.endpointCoverage,
endpointCodequality: this.endpointCodequality,
endpointUpdateUser: this.endpointUpdateUser,
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 9f90de9abde..9236e14beb1 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -5,7 +5,7 @@ import {
historyPushState,
scrollToElement,
} from '~/lib/utils/common_utils';
-import { createAlert, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/alert';
import { diffViewerModes } from '~/ide/constants';
import axios from '~/lib/utils/axios_utils';
@@ -14,6 +14,8 @@ import Poll from '~/lib/utils/poll';
import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
import notesEventHub from '~/notes/event_hub';
+import { generateTreeList } from '~/diffs/utils/tree_worker_utils';
+import { sortTree } from '~/ide/stores/utils';
import {
PARALLEL_DIFF_VIEW_TYPE,
INLINE_DIFF_VIEW_TYPE,
@@ -52,7 +54,6 @@ import { isCollapsed } from '../utils/diff_file';
import { markFileReview, setReviewsForMergeRequest } from '../utils/file_reviews';
import { getDerivedMergeRequestInformation } from '../utils/merge_request';
import { queueRedisHllEvents } from '../utils/queue_events';
-import TreeWorker from '../workers/tree_worker?worker';
import * as types from './mutation_types';
import {
getDiffPositionByLineCode,
@@ -68,6 +69,7 @@ export const setBaseConfig = ({ commit }, options) => {
endpoint,
endpointMetadata,
endpointBatch,
+ endpointDiffForPath,
endpointCoverage,
endpointUpdateUser,
projectPath,
@@ -81,6 +83,7 @@ export const setBaseConfig = ({ commit }, options) => {
endpoint,
endpointMetadata,
endpointBatch,
+ endpointDiffForPath,
endpointCoverage,
endpointUpdateUser,
projectPath,
@@ -199,21 +202,12 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
};
export const fetchDiffFilesMeta = ({ commit, state }) => {
- const worker = new TreeWorker();
const urlParams = {
view: 'inline',
w: state.showWhitespace ? '0' : '1',
};
commit(types.SET_LOADING, true);
- eventHub.$emit(EVT_PERF_MARK_FILE_TREE_START);
-
- worker.addEventListener('message', ({ data }) => {
- commit(types.SET_TREE_DATA, data);
- eventHub.$emit(EVT_PERF_MARK_FILE_TREE_END);
-
- worker.terminate();
- });
return axios
.get(mergeUrlParams(urlParams, state.endpointMetadata))
@@ -225,18 +219,24 @@ export const fetchDiffFilesMeta = ({ commit, state }) => {
commit(types.SET_MERGE_REQUEST_DIFFS, data.merge_request_diffs || []);
commit(types.SET_DIFF_METADATA, strippedData);
- worker.postMessage(data.diff_files);
+ eventHub.$emit(EVT_PERF_MARK_FILE_TREE_START);
+ const { treeEntries, tree } = generateTreeList(data.diff_files);
+ eventHub.$emit(EVT_PERF_MARK_FILE_TREE_END);
+ commit(types.SET_TREE_DATA, {
+ treeEntries,
+ tree: sortTree(tree),
+ });
return data;
})
.catch((error) => {
- worker.terminate();
-
if (error.response.status === HTTP_STATUS_NOT_FOUND) {
createAlert({
message: __('Building your merge request. Wait a few moments, then refresh this page.'),
variant: VARIANT_WARNING,
});
+ } else {
+ throw error;
}
});
};
@@ -821,20 +821,20 @@ export function moveToNeighboringCommit({ dispatch, state }, { direction }) {
}
}
-export const setCurrentDiffFileIdFromNote = ({ commit, state, rootGetters }, noteId) => {
+export const setCurrentDiffFileIdFromNote = ({ commit, getters, rootGetters }, noteId) => {
const note = rootGetters.notesById[noteId];
if (!note) return;
const fileHash = rootGetters.getDiscussion(note.discussion_id).diff_file?.file_hash;
- if (fileHash && state.diffFiles.some((f) => f.file_hash === fileHash)) {
+ if (fileHash && getters.flatBlobsList.some((f) => f.fileHash === fileHash)) {
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
}
};
-export const navigateToDiffFileIndex = ({ commit, state }, index) => {
- const fileHash = state.diffFiles[index].file_hash;
+export const navigateToDiffFileIndex = ({ commit, getters }, index) => {
+ const { fileHash } = getters.flatBlobsList[index];
document.location.hash = fileHash;
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 3a85c1a9fe1..10a6a872fe4 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -90,6 +90,12 @@ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) =
export const getDiffFileByHash = (state) => (fileHash) =>
state.diffFiles.find((file) => file.file_hash === fileHash);
+export function isTreePathLoaded(state) {
+ return (path) => {
+ return Boolean(state.treeEntries[path]?.diffLoaded);
+ };
+}
+
export const flatBlobsList = (state) =>
Object.values(state.treeEntries).filter((f) => f.type === 'blob');
@@ -148,7 +154,7 @@ export const fileLineCodequality = () => () => {
export const currentDiffIndex = (state) =>
Math.max(
0,
- state.diffFiles.findIndex((diff) => diff.file_hash === state.currentDiffFileId),
+ flatBlobsList(state).findIndex((diff) => diff.fileHash === state.currentDiffFileId),
);
export const diffLines = (state) => (file) => {
diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js
index 329db1fe2cf..593c28f20ec 100644
--- a/app/assets/javascripts/diffs/store/modules/diff_state.js
+++ b/app/assets/javascripts/diffs/store/modules/diff_state.js
@@ -16,6 +16,7 @@ export default () => ({
removedLines: null,
endpoint: '',
endpointUpdateUser: '',
+ endpointDiffForPath: '',
basePath: '',
commit: null,
startVersion: null, // Null unless a target diff is selected for comparison that is not the "base" diff
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index d2b798245fc..5e7fe8b5cd8 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -15,6 +15,7 @@ import {
prepareDiffData,
isDiscussionApplicableToLine,
updateLineInFile,
+ markTreeEntriesLoaded,
} from './utils';
function updateDiffFilesInState(state, files) {
@@ -33,6 +34,7 @@ export default {
endpoint,
endpointMetadata,
endpointBatch,
+ endpointDiffForPath,
endpointCoverage,
endpointUpdateUser,
projectPath,
@@ -46,6 +48,7 @@ export default {
endpoint,
endpointMetadata,
endpointBatch,
+ endpointDiffForPath,
endpointCoverage,
endpointUpdateUser,
projectPath,
@@ -80,9 +83,15 @@ export default {
},
[types.SET_DIFF_DATA_BATCH](state, data) {
- state.diffFiles = prepareDiffData({
- diff: data,
- priorFiles: state.diffFiles,
+ Object.assign(state, {
+ diffFiles: prepareDiffData({
+ diff: data,
+ priorFiles: state.diffFiles,
+ }),
+ treeEntries: markTreeEntriesLoaded({
+ priorEntries: state.treeEntries,
+ loadedFiles: data.diff_files,
+ }),
});
},
diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js
index 0519ca3d715..3739ef0cd55 100644
--- a/app/assets/javascripts/diffs/store/utils.js
+++ b/app/assets/javascripts/diffs/store/utils.js
@@ -19,6 +19,8 @@ import {
} from '../constants';
import { prepareRawDiffFile } from '../utils/diff_file';
+const SHA1 = /\b([a-f0-9]{40})\b/;
+
export const isAdded = (line) => ['new', 'new-nonewline'].includes(line.type);
export const isRemoved = (line) => ['old', 'old-nonewline'].includes(line.type);
export const isUnchanged = (line) => !line.type;
@@ -556,3 +558,44 @@ export const allDiscussionWrappersExpanded = (diff) => {
return discussionsExpanded;
};
+
+export function isUrlHashNoteLink(urlHash) {
+ const id = urlHash.replace(/^#/, '');
+
+ return id.startsWith('note');
+}
+
+export function isUrlHashFileHeader(urlHash) {
+ const id = urlHash.replace(/^#/, '');
+
+ return id.startsWith('diff-content');
+}
+
+export function parseUrlHashAsFileHash(urlHash, currentDiffFileId = '') {
+ const isNoteLink = isUrlHashNoteLink(urlHash);
+ let id = urlHash.replace(/^#/, '');
+
+ if (isNoteLink && currentDiffFileId) {
+ id = currentDiffFileId;
+ } else if (isUrlHashFileHeader(urlHash)) {
+ id = id.replace('diff-content-', '');
+ } else if (!SHA1.test(id) || isNoteLink) {
+ id = null;
+ }
+
+ return id;
+}
+
+export function markTreeEntriesLoaded({ priorEntries, loadedFiles }) {
+ const newEntries = { ...priorEntries };
+
+ loadedFiles.forEach((newFile) => {
+ const entry = newEntries[newFile.new_path];
+
+ if (entry) {
+ entry.diffLoaded = true;
+ }
+ });
+
+ return newEntries;
+}
diff --git a/app/assets/javascripts/diffs/utils/tree_worker_utils.js b/app/assets/javascripts/diffs/utils/tree_worker_utils.js
index a90c1a5c64e..8689809cfa9 100644
--- a/app/assets/javascripts/diffs/utils/tree_worker_utils.js
+++ b/app/assets/javascripts/diffs/utils/tree_worker_utils.js
@@ -85,6 +85,11 @@ export const generateTreeList = (files) => {
if (type === 'blob') {
Object.assign(entry, {
changed: true,
+ diffLoaded: false,
+ filePaths: {
+ old: file.old_path,
+ new: file.new_path,
+ },
tempFile: file.new_file,
deleted: file.deleted_file,
fileHash: file.file_hash,
diff --git a/app/assets/javascripts/diffs/workers/tree_worker.js b/app/assets/javascripts/diffs/workers/tree_worker.js
deleted file mode 100644
index 04010a99b52..00000000000
--- a/app/assets/javascripts/diffs/workers/tree_worker.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { sortTree } from '~/ide/stores/utils';
-import { generateTreeList } from '../utils/tree_worker_utils';
-
-// eslint-disable-next-line no-restricted-globals
-self.addEventListener('message', (e) => {
- const { data } = e;
-
- if (data === undefined) {
- return;
- }
-
- const { treeEntries, tree } = generateTreeList(data);
-
- // eslint-disable-next-line no-restricted-globals
- self.postMessage({
- treeEntries,
- tree: sortTree(tree),
- });
-});
diff --git a/app/assets/javascripts/drawio/constants.js b/app/assets/javascripts/drawio/constants.js
new file mode 100644
index 00000000000..2e1e074db3b
--- /dev/null
+++ b/app/assets/javascripts/drawio/constants.js
@@ -0,0 +1,15 @@
+/*
+ * TODO: Make this URL configurable
+ */
+export const DRAWIO_EDITOR_URL =
+ 'https://embed.diagrams.net/?ui=sketch&noSaveBtn=1&saveAndExit=1&keepmodified=1&spin=1&embed=1&libraries=1&configure=1&proto=json&toSvg=1'; // TODO Make it configurable
+
+export const DRAWIO_FRAME_ID = 'drawio-frame';
+
+export const DARK_BACKGROUND_COLOR = '#202020';
+
+export const DIAGRAM_BACKGROUND_COLOR = '#ffffff';
+
+export const DRAWIO_IFRAME_TIMEOUT = 4000;
+
+export const DIAGRAM_MAX_SIZE = 10 * 1024 * 1024; // 1MB
diff --git a/app/assets/javascripts/drawio/content_editor_facade.js b/app/assets/javascripts/drawio/content_editor_facade.js
new file mode 100644
index 00000000000..1c41194c1f5
--- /dev/null
+++ b/app/assets/javascripts/drawio/content_editor_facade.js
@@ -0,0 +1,80 @@
+import axios from '~/lib/utils/axios_utils';
+
+/**
+ * A set of functions to decouple the content_editor component from
+ * the draw.io editor.
+ * It allows the draw.io editor to obtain a selected drawio_diagram
+ * and replace it or insert a new drawio_diagram node without coupling
+ * the drawio_editor to the Content Editor implementation details
+ * *
+ * @param {Object} params Factory function parameters
+ * @param {Object} params.tiptapEditor See https://tiptap.dev/api/editor
+ * @param {String} params.drawioNodeName Name of the drawio_diagram node in
+ * the ProseMirror document
+ * @param {String} params.uploadsPath API endpoint to upload files
+ * @param {Object} params.assetResolver See
+ * app/assets/javascripts/content_editor/services/asset_resolver.js
+ *
+ * @returns A content_editor_facade object with operations
+ * to get a selected diagram, upload a diagram, insert a new one in the
+ * Content Editor, and update an existing’s diagram URL.
+ */
+export const create = ({ tiptapEditor, drawioNodeName, uploadsPath, assetResolver }) => ({
+ getDiagram: async () => {
+ const { node } = tiptapEditor.state.selection;
+
+ if (!node || node.type.name !== drawioNodeName) {
+ return null;
+ }
+
+ const { src } = node.attrs;
+ const response = await axios.get(src, { responseType: 'text' });
+ const diagramSvg = response.data;
+ const contentType = response.headers['content-type'];
+ const filename = src.split('/').pop();
+
+ return {
+ diagramURL: src,
+ filename,
+ diagramSvg,
+ contentType,
+ };
+ },
+ updateDiagram: async ({ uploadResults: { file_path: canonicalSrc } }) => {
+ const src = await assetResolver.resolveUrl(canonicalSrc);
+
+ tiptapEditor
+ .chain()
+ .focus()
+ .updateAttributes(drawioNodeName, {
+ src,
+ canonicalSrc,
+ })
+ .run();
+ },
+ insertDiagram: async ({ uploadResults: { file_path: canonicalSrc } }) => {
+ const src = await assetResolver.resolveUrl(canonicalSrc);
+
+ tiptapEditor
+ .chain()
+ .focus()
+ .insertContent({
+ type: drawioNodeName,
+ attrs: {
+ src,
+ canonicalSrc,
+ },
+ })
+ .run();
+ },
+ uploadDiagram: async ({ filename, diagramSvg }) => {
+ const blob = new Blob([diagramSvg], { type: 'image/svg+xml' });
+ const formData = new FormData();
+
+ formData.append('file', blob, filename);
+
+ const response = await axios.post(uploadsPath, formData);
+
+ return response.data;
+ },
+});
diff --git a/app/assets/javascripts/drawio/drawio_editor.js b/app/assets/javascripts/drawio/drawio_editor.js
new file mode 100644
index 00000000000..38d1cadcc63
--- /dev/null
+++ b/app/assets/javascripts/drawio/drawio_editor.js
@@ -0,0 +1,277 @@
+import _ from 'lodash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
+import { darkModeEnabled } from '~/lib/utils/color_utils';
+import { __ } from '~/locale';
+import { setAttributes } from '~/lib/utils/dom_utils';
+import {
+ DARK_BACKGROUND_COLOR,
+ DRAWIO_EDITOR_URL,
+ DRAWIO_FRAME_ID,
+ DIAGRAM_BACKGROUND_COLOR,
+ DRAWIO_IFRAME_TIMEOUT,
+ DIAGRAM_MAX_SIZE,
+} from './constants';
+
+function updateDrawioEditorState(drawIOEditorState, data) {
+ Object.assign(drawIOEditorState, data);
+}
+
+function postMessageToDrawioEditor(drawIOEditorState, message) {
+ const { origin } = new URL(DRAWIO_EDITOR_URL);
+
+ drawIOEditorState.iframe.contentWindow.postMessage(JSON.stringify(message), origin);
+}
+
+function disposeDrawioEditor(drawIOEditorState) {
+ drawIOEditorState.disposeEventListener();
+ drawIOEditorState.iframe.remove();
+}
+
+function getSvg(data) {
+ const svgPath = atob(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\
+ ${svgPath}`;
+}
+
+async function saveDiagram(drawIOEditorState, editorFacade) {
+ const { newDiagram, diagramMarkdown, filename, diagramSvg } = drawIOEditorState;
+ const filenameWithExt = filename.endsWith('.drawio.svg') ? filename : `${filename}.drawio.svg`;
+
+ postMessageToDrawioEditor(drawIOEditorState, {
+ action: 'spinner',
+ show: true,
+ messageKey: 'saving',
+ });
+
+ try {
+ const uploadResults = await editorFacade.uploadDiagram({
+ filename: filenameWithExt,
+ diagramSvg,
+ });
+
+ if (newDiagram) {
+ editorFacade.insertDiagram({ uploadResults });
+ } else {
+ editorFacade.updateDiagram({ diagramMarkdown, uploadResults });
+ }
+
+ createAlert({
+ message: __('Diagram saved successfully.'),
+ variant: VARIANT_SUCCESS,
+ fadeTransition: true,
+ });
+ setTimeout(() => disposeDrawioEditor(drawIOEditorState), 10);
+ } catch {
+ postMessageToDrawioEditor(drawIOEditorState, { action: 'spinner', show: false });
+ postMessageToDrawioEditor(drawIOEditorState, {
+ action: 'dialog',
+ titleKey: 'error',
+ modified: true,
+ buttonKey: 'close',
+ messageKey: 'errorSavingFile',
+ });
+ }
+}
+
+function promptName(drawIOEditorState, name, errKey) {
+ postMessageToDrawioEditor(drawIOEditorState, {
+ action: 'prompt',
+ titleKey: 'filename',
+ okKey: 'save',
+ defaultValue: name || '',
+ });
+
+ if (errKey !== null) {
+ postMessageToDrawioEditor(drawIOEditorState, {
+ action: 'dialog',
+ titleKey: 'error',
+ messageKey: errKey,
+ buttonKey: 'ok',
+ });
+ }
+}
+
+function sendLoadDiagramMessage(drawIOEditorState) {
+ postMessageToDrawioEditor(drawIOEditorState, {
+ action: 'load',
+ xml: drawIOEditorState.diagramSvg,
+ border: 8,
+ background: DIAGRAM_BACKGROUND_COLOR,
+ dark: drawIOEditorState.dark,
+ title: drawIOEditorState.filename,
+ });
+}
+
+async function loadExistingDiagram(drawIOEditorState, editorFacade) {
+ let diagram = null;
+
+ try {
+ diagram = await editorFacade.getDiagram();
+ } catch (e) {
+ throw new Error(__('Cannot load the diagram into the diagrams.net editor'));
+ }
+
+ if (diagram) {
+ const { diagramMarkdown, filename, diagramSvg, contentType, diagramURL } = diagram;
+ const resolvedURL = new URL(diagramURL, window.location.origin);
+ const diagramSvgSize = new Blob([diagramSvg]).size;
+
+ if (contentType !== 'image/svg+xml') {
+ throw new Error(__('The selected image is not a valid SVG diagram'));
+ }
+
+ if (resolvedURL.origin !== window.location.origin) {
+ throw new Error(__('The selected image is not an asset uploaded in the application'));
+ }
+
+ if (diagramSvgSize > DIAGRAM_MAX_SIZE) {
+ throw new Error(__('The selected image is too large.'));
+ }
+
+ updateDrawioEditorState(drawIOEditorState, {
+ newDiagram: false,
+ filename,
+ diagramMarkdown,
+ diagramSvg,
+ });
+ } else {
+ updateDrawioEditorState(drawIOEditorState, {
+ newDiagram: true,
+ });
+ }
+
+ sendLoadDiagramMessage(drawIOEditorState);
+}
+
+async function prepareEditor(drawIOEditorState, editorFacade) {
+ const { iframe } = drawIOEditorState;
+
+ iframe.style.cursor = 'wait';
+
+ try {
+ await loadExistingDiagram(drawIOEditorState, editorFacade);
+
+ iframe.style.visibility = 'visible';
+ iframe.style.cursor = '';
+ window.scrollTo(0, 0);
+ } catch (e) {
+ createAlert({
+ message: e.message,
+ error: e,
+ });
+ disposeDrawioEditor(drawIOEditorState);
+ }
+}
+
+function configureDrawIOEditor(drawIOEditorState) {
+ postMessageToDrawioEditor(drawIOEditorState, {
+ action: 'configure',
+ config: {
+ darkColor: DARK_BACKGROUND_COLOR,
+ settingsName: 'gitlab',
+ },
+ colorSchemeMeta: drawIOEditorState.dark, // For transparent iframe background in dark mode
+ });
+ updateDrawioEditorState(drawIOEditorState, {
+ initialized: true,
+ });
+}
+
+function onDrawIOEditorMessage(drawIOEditorState, editorFacade, evt) {
+ if (_.isNil(evt) || evt.source !== drawIOEditorState.iframe.contentWindow) {
+ return;
+ }
+
+ const msg = JSON.parse(evt.data);
+
+ if (msg.event === 'configure') {
+ configureDrawIOEditor(drawIOEditorState);
+ } else if (msg.event === 'init') {
+ prepareEditor(drawIOEditorState, editorFacade);
+ } else if (msg.event === 'exit') {
+ disposeDrawioEditor(drawIOEditorState);
+ } else if (msg.event === 'prompt') {
+ updateDrawioEditorState(drawIOEditorState, {
+ filename: msg.value,
+ });
+
+ if (!drawIOEditorState.filename) {
+ promptName(drawIOEditorState, 'diagram.drawio.svg', 'filenameShort');
+ } else {
+ saveDiagram(drawIOEditorState, editorFacade);
+ }
+ } else if (msg.event === 'export') {
+ updateDrawioEditorState(drawIOEditorState, {
+ diagramSvg: getSvg(msg.data),
+ });
+ // TODO Add this to draw.io editor configuration
+ sendLoadDiagramMessage(drawIOEditorState); // Save removes diagram from the editor, so we need to reload it.
+ postMessageToDrawioEditor(drawIOEditorState, { action: 'status', modified: true }); // And set editor modified flag to true.
+ if (!drawIOEditorState.filename) {
+ promptName(drawIOEditorState, 'diagram.drawio.svg', null);
+ } else {
+ saveDiagram(drawIOEditorState, editorFacade);
+ }
+ }
+}
+
+function createEditorIFrame(drawIOEditorState) {
+ const iframe = document.createElement('iframe');
+
+ setAttributes(iframe, {
+ id: DRAWIO_FRAME_ID,
+ src: DRAWIO_EDITOR_URL,
+ class: 'drawio-editor',
+ });
+
+ document.body.appendChild(iframe);
+
+ setTimeout(() => {
+ if (drawIOEditorState.initialized === false) {
+ disposeDrawioEditor(drawIOEditorState);
+ createAlert({ message: __('The diagrams.net editor could not be loaded.') });
+ }
+ }, DRAWIO_IFRAME_TIMEOUT);
+
+ updateDrawioEditorState(drawIOEditorState, {
+ iframe,
+ });
+}
+
+function attachDrawioIFrameMessageListener(drawIOEditorState, editorFacade) {
+ const evtHandler = (evt) => {
+ onDrawIOEditorMessage(drawIOEditorState, editorFacade, evt);
+ };
+
+ window.addEventListener('message', evtHandler);
+
+ // Stores a function in the editor state object that allows disposing
+ // the message event listener when the editor exits.
+ updateDrawioEditorState(drawIOEditorState, {
+ disposeEventListener: () => {
+ window.removeEventListener('message', evtHandler);
+ },
+ });
+}
+
+const createDrawioEditorState = ({ filename = null }) => ({
+ newDiagram: true,
+ filename,
+ diagramSvg: null,
+ diagramMarkdown: null,
+ iframe: null,
+ isBusy: false,
+ initialized: false,
+ dark: darkModeEnabled(),
+ disposeEventListener: null,
+});
+
+export function launchDrawioEditor({ editorFacade, filename }) {
+ const drawIOEditorState = createDrawioEditorState({ filename });
+
+ // The execution order of these two functions matter
+ attachDrawioIFrameMessageListener(drawIOEditorState, editorFacade);
+ createEditorIFrame(drawIOEditorState);
+}
diff --git a/app/assets/javascripts/drawio/markdown_field_editor_facade.js b/app/assets/javascripts/drawio/markdown_field_editor_facade.js
new file mode 100644
index 00000000000..4ef203c7aa0
--- /dev/null
+++ b/app/assets/javascripts/drawio/markdown_field_editor_facade.js
@@ -0,0 +1,72 @@
+import { insertMarkdownText, resolveSelectedImage } from '~/lib/utils/text_markdown';
+import axios from '~/lib/utils/axios_utils';
+
+/**
+ * A set of functions to decouple the markdown_field component from
+ * the draw.io editor.
+ * It allows the draw.io editor to obtain a selected drawio_diagram
+ * and replace it or insert a new drawio_diagram node without coupling
+ * the drawio_editor to the Markdown Field implementation details
+ *
+ * @param {Object} params Factory function parameters
+ * @param {Object} params.textArea Textarea used to edit and display markdown source
+ * @param {String} params.markdownPreviewPath API endpoint to render Markdown
+ * @param {String} params.uploadsPath API endpoint to upload files
+ *
+ * @returns A markdown_field_facade object with operations
+ * with operations to get a selected diagram, upload a diagram,
+ * insert a new one in the Markdown Field, and update
+ * an existing’s diagram URL.
+ */
+export const create = ({ textArea, markdownPreviewPath, uploadsPath }) => ({
+ getDiagram: async () => {
+ const image = await resolveSelectedImage(textArea, markdownPreviewPath);
+
+ if (!image) {
+ return null;
+ }
+
+ const { imageURL, imageMarkdown, filename } = image;
+ const response = await axios.get(imageURL, { responseType: 'text' });
+ const diagramSvg = response.data;
+ const contentType = response.headers['content-type'];
+
+ return {
+ diagramURL: imageURL,
+ diagramMarkdown: imageMarkdown,
+ filename,
+ diagramSvg,
+ contentType,
+ };
+ },
+ updateDiagram: ({ uploadResults, diagramMarkdown }) => {
+ textArea.focus();
+
+ // eslint-disable-next-line no-param-reassign
+ textArea.value = textArea.value.replace(diagramMarkdown, uploadResults.link.markdown);
+ textArea.dispatchEvent(new Event('input'));
+ },
+ insertDiagram: ({ uploadResults }) => {
+ textArea.focus();
+ const markdown = textArea.value;
+ const selectedMD = markdown.substring(textArea.selectionStart, textArea.selectionEnd);
+
+ // This method dispatches the input event.
+ insertMarkdownText({
+ textArea,
+ text: markdown,
+ tag: uploadResults.link.markdown,
+ selected: selectedMD,
+ });
+ },
+ uploadDiagram: async ({ filename, diagramSvg }) => {
+ const blob = new Blob([diagramSvg], { type: 'image/svg+xml' });
+ const formData = new FormData();
+
+ formData.append('file', blob, filename);
+
+ const response = await axios.post(uploadsPath, formData);
+
+ return response.data;
+ },
+});
diff --git a/app/assets/javascripts/editor/components/source_editor_toolbar.vue b/app/assets/javascripts/editor/components/source_editor_toolbar.vue
index c72145f9d2f..67b909d37c3 100644
--- a/app/assets/javascripts/editor/components/source_editor_toolbar.vue
+++ b/app/assets/javascripts/editor/components/source_editor_toolbar.vue
@@ -2,7 +2,7 @@
import { isEmpty } from 'lodash';
import { GlButtonGroup } from '@gitlab/ui';
import getToolbarItemsQuery from '~/editor/graphql/get_items.query.graphql';
-import { EDITOR_TOOLBAR_LEFT_GROUP, EDITOR_TOOLBAR_RIGHT_GROUP } from '~/editor/constants';
+import { EDITOR_TOOLBAR_BUTTON_GROUPS } from '~/editor/constants';
import SourceEditorToolbarButton from './source_editor_toolbar_button.vue';
export default {
@@ -34,8 +34,7 @@ export default {
return nodes.map((item) => {
return {
...item,
- group:
- (this.$options.groups.includes(item.group) && item.group) || EDITOR_TOOLBAR_RIGHT_GROUP,
+ group: EDITOR_TOOLBAR_BUTTON_GROUPS[item.group] || EDITOR_TOOLBAR_BUTTON_GROUPS.settings,
};
});
},
@@ -46,24 +45,38 @@ export default {
return !isEmpty(this.getGroupItems(group));
},
},
- groups: [EDITOR_TOOLBAR_LEFT_GROUP, EDITOR_TOOLBAR_RIGHT_GROUP],
+ groups: EDITOR_TOOLBAR_BUTTON_GROUPS,
};
</script>
<template>
<section
v-if="isVisible"
id="se-toolbar"
- class="gl-py-3 gl-px-5 gl-bg-white gl-border-t gl-border-b gl-display-flex gl-justify-content-space-between gl-align-items-center"
+ class="gl-py-3 gl-px-5 gl-bg-white gl-border-t gl-border-b gl-display-flex gl-align-items-center"
>
- <div v-for="group in $options.groups" :key="group">
- <gl-button-group v-if="hasGroupItems(group)">
- <source-editor-toolbar-button
- v-for="item in getGroupItems(group)"
- :key="item.id"
- :button="item"
- @click="$emit('click', item)"
- />
- </gl-button-group>
- </div>
+ <gl-button-group v-if="hasGroupItems($options.groups.file)">
+ <source-editor-toolbar-button
+ v-for="item in getGroupItems($options.groups.file)"
+ :key="item.id"
+ :button="item"
+ @click="$emit('click', item)"
+ />
+ </gl-button-group>
+ <gl-button-group v-if="hasGroupItems($options.groups.edit)">
+ <source-editor-toolbar-button
+ v-for="item in getGroupItems($options.groups.edit)"
+ :key="item.id"
+ :button="item"
+ @click="$emit('click', item)"
+ />
+ </gl-button-group>
+ <gl-button-group v-if="hasGroupItems($options.groups.settings)" class="gl-ml-auto">
+ <source-editor-toolbar-button
+ v-for="item in getGroupItems($options.groups.settings)"
+ :key="item.id"
+ :button="item"
+ @click="$emit('click', item)"
+ />
+ </gl-button-group>
</section>
</template>
diff --git a/app/assets/javascripts/editor/constants.js b/app/assets/javascripts/editor/constants.js
index d235319dfd7..2be671ec7d8 100644
--- a/app/assets/javascripts/editor/constants.js
+++ b/app/assets/javascripts/editor/constants.js
@@ -1,3 +1,4 @@
+import { KeyMod, KeyCode } from 'monaco-editor';
import { getModifierKey } from '~/constants';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { s__, __, sprintf } from '~/locale';
@@ -15,15 +16,15 @@ export const EDITOR_TYPE_DIFF = 'vs.editor.IDiffEditor';
export const EDITOR_CODE_INSTANCE_FN = 'createInstance';
export const EDITOR_DIFF_INSTANCE_FN = 'createDiffInstance';
-export const EDITOR_TOOLBAR_LEFT_GROUP = 'left';
-export const EDITOR_TOOLBAR_RIGHT_GROUP = 'right';
+export const EDITOR_TOOLBAR_BUTTON_GROUPS = {
+ file: 'file', // external helpers (file-tree, etc.)
+ edit: 'edit', // formatting the text in the editor (bold, italic, add link, etc.)
+ settings: 'settings', // editor-wide settings (soft-wrap, full-screen, etc.)
+};
export const SOURCE_EDITOR_INSTANCE_ERROR_NO_EL = s__(
'SourceEditor|"el" parameter is required for createInstance()',
);
-export const ERROR_INSTANCE_REQUIRED_FOR_EXTENSION = s__(
- 'SourceEditor|Source Editor instance is required to set up an extension.',
-);
export const EDITOR_EXTENSION_DEFINITION_ERROR = s__(
'SourceEditor|Extension definition should be either a class or a function',
);
@@ -73,7 +74,8 @@ export const EXTENSION_MARKDOWN_BUTTONS = [
}),
data: {
mdTag: '**',
- mdShortcuts: '["mod+b"]',
+ // eslint-disable-next-line no-bitwise
+ mdShortcuts: [KeyMod.CtrlCmd | KeyCode.KeyB],
},
},
{
@@ -83,7 +85,8 @@ export const EXTENSION_MARKDOWN_BUTTONS = [
}),
data: {
mdTag: '_',
- mdShortcuts: '["mod+i"]',
+ // eslint-disable-next-line no-bitwise
+ mdShortcuts: [KeyMod.CtrlCmd | KeyCode.KeyI],
},
},
{
@@ -93,7 +96,8 @@ export const EXTENSION_MARKDOWN_BUTTONS = [
}),
data: {
mdTag: '~~',
- mdShortcuts: '["mod+shift+x]',
+ // eslint-disable-next-line no-bitwise
+ mdShortcuts: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyX],
},
},
{
@@ -114,13 +118,14 @@ export const EXTENSION_MARKDOWN_BUTTONS = [
},
{
id: 'link',
- label: sprintf(s__('MarkdownEditor|Add a link (%{modifier_key}K)'), {
+ label: sprintf(s__('MarkdownEditor|Add a link (%{modifierKey}K)'), {
modifierKey,
}),
data: {
mdTag: '[{text}](url)',
mdSelect: 'url',
- mdShortcuts: '["mod+k"]',
+ // eslint-disable-next-line no-bitwise
+ mdShortcuts: [KeyMod.CtrlCmd | KeyCode.KeyK],
},
},
{
@@ -166,3 +171,4 @@ export const EXTENSION_MARKDOWN_BUTTONS = [
},
},
];
+export const EXTENSION_SOFTWRAP_ID = 'soft-wrap';
diff --git a/app/assets/javascripts/editor/extensions/source_editor_extension_base.js b/app/assets/javascripts/editor/extensions/source_editor_extension_base.js
index 0590bb7455a..8ec83e4df1c 100644
--- a/app/assets/javascripts/editor/extensions/source_editor_extension_base.js
+++ b/app/assets/javascripts/editor/extensions/source_editor_extension_base.js
@@ -1,8 +1,11 @@
import { Range } from 'monaco-editor';
+import { __ } from '~/locale';
import {
EDITOR_TYPE_CODE,
EXTENSION_BASE_LINE_LINK_ANCHOR_CLASS,
EXTENSION_BASE_LINE_NUMBERS_CLASS,
+ EDITOR_TOOLBAR_BUTTON_GROUPS,
+ EXTENSION_SOFTWRAP_ID,
} from '../constants';
const hashRegexp = /#?L/g;
@@ -24,6 +27,13 @@ export class SourceEditorExtension {
return 'BaseExtension';
}
+ onSetup(instance) {
+ this.toolbarButtons = [];
+ if (instance.toolbar) {
+ this.setupToolbar(instance);
+ }
+ }
+
// eslint-disable-next-line class-methods-use-this
onUse(instance) {
SourceEditorExtension.highlightLines(instance);
@@ -32,6 +42,31 @@ export class SourceEditorExtension {
}
}
+ onBeforeUnuse(instance) {
+ const ids = this.toolbarButtons.map((item) => item.id);
+ if (instance.toolbar) {
+ instance.toolbar.removeItems(ids);
+ }
+ }
+
+ setupToolbar(instance) {
+ this.toolbarButtons = [
+ {
+ id: EXTENSION_SOFTWRAP_ID,
+ label: __('Soft wrap'),
+ icon: 'soft-wrap',
+ selected: instance.getOption(116) === 'on',
+ group: EDITOR_TOOLBAR_BUTTON_GROUPS.settings,
+ category: 'primary',
+ selectedLabel: __('No wrap'),
+ selectedIcon: 'soft-unwrap',
+ class: 'soft-wrap-toggle',
+ onClick: () => instance.toggleSoftwrap(),
+ },
+ ];
+ instance.toolbar.addItems(this.toolbarButtons);
+ }
+
static onMouseMoveHandler(e) {
const target = e.target.element;
if (target.classList.contains(EXTENSION_BASE_LINE_NUMBERS_CLASS)) {
@@ -108,6 +143,16 @@ export class SourceEditorExtension {
highlightLines(instance, bounds = null) {
SourceEditorExtension.highlightLines(instance, bounds);
},
+
+ toggleSoftwrap(instance) {
+ const isSoftWrapped = instance.getOption(116) === 'on';
+ instance.updateOptions({ wordWrap: isSoftWrapped ? 'off' : 'on' });
+ if (instance.toolbar) {
+ instance.toolbar.updateItem(EXTENSION_SOFTWRAP_ID, {
+ selected: !isSoftWrapped,
+ });
+ }
+ },
};
}
}
diff --git a/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js b/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
index 6105a577996..0a5843ec631 100644
--- a/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
+++ b/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
@@ -1,5 +1,5 @@
import { insertMarkdownText } from '~/lib/utils/text_markdown';
-import { EDITOR_TOOLBAR_RIGHT_GROUP, EXTENSION_MARKDOWN_BUTTONS } from '../constants';
+import { EDITOR_TOOLBAR_BUTTON_GROUPS, EXTENSION_MARKDOWN_BUTTONS } from '../constants';
export class EditorMarkdownExtension {
static get extensionName() {
@@ -8,6 +8,7 @@ export class EditorMarkdownExtension {
onSetup(instance) {
this.toolbarButtons = [];
+ this.actions = [];
if (instance.toolbar) {
this.setupToolbar(instance);
}
@@ -17,14 +18,30 @@ export class EditorMarkdownExtension {
if (instance.toolbar) {
instance.toolbar.removeItems(ids);
}
+ this.actions.forEach((action) => {
+ action.dispose();
+ });
+ this.actions = [];
}
setupToolbar(instance) {
this.toolbarButtons = EXTENSION_MARKDOWN_BUTTONS.map((btn) => {
+ if (btn.data.mdShortcuts) {
+ this.actions.push(
+ instance.addAction({
+ id: btn.id,
+ label: btn.label,
+ keybindings: btn.data.mdShortcuts,
+ run(inst) {
+ inst.insertMarkdown(btn.data);
+ },
+ }),
+ );
+ }
return {
...btn,
icon: btn.id,
- group: EDITOR_TOOLBAR_RIGHT_GROUP,
+ group: EDITOR_TOOLBAR_BUTTON_GROUPS.edit,
category: 'tertiary',
onClick: (e) => instance.insertMarkdown(e),
};
@@ -66,12 +83,8 @@ export class EditorMarkdownExtension {
instance.setPosition(pos);
},
insertMarkdown: (instance, e) => {
- const {
- mdTag: tag,
- mdBlock: blockTag,
- mdPrepend,
- mdSelect: select,
- } = e.currentTarget.dataset;
+ const { mdTag: tag, mdBlock: blockTag, mdPrepend, mdSelect: select } =
+ e.currentTarget?.dataset || e;
insertMarkdownText({
tag,
diff --git a/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js b/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js
index 58ddaa94d5e..f8ff533f53f 100644
--- a/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js
+++ b/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js
@@ -1,7 +1,7 @@
import { KeyMod, KeyCode, Emitter } from 'monaco-editor';
import { debounce } from 'lodash';
import { BLOB_PREVIEW_ERROR } from '~/blob_edit/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { sanitize } from '~/lib/dompurify';
import axios from '~/lib/utils/axios_utils';
import syntaxHighlight from '~/syntax_highlight';
@@ -14,7 +14,7 @@ import {
EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY,
EXTENSION_MARKDOWN_PREVIEW_LABEL,
EXTENSION_MARKDOWN_HIDE_PREVIEW_LABEL,
- EDITOR_TOOLBAR_RIGHT_GROUP,
+ EDITOR_TOOLBAR_BUTTON_GROUPS,
} from '../constants';
const fetchPreview = (text, previewMarkdownPath) => {
@@ -116,7 +116,7 @@ export class EditorMarkdownPreviewExtension {
label: EXTENSION_MARKDOWN_PREVIEW_LABEL,
icon: 'live-preview',
selected: false,
- group: EDITOR_TOOLBAR_RIGHT_GROUP,
+ group: EDITOR_TOOLBAR_BUTTON_GROUPS.settings,
category: 'primary',
selectedLabel: EXTENSION_MARKDOWN_HIDE_PREVIEW_LABEL,
onClick: () => instance.togglePreview(),
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 57477a993c5..a5080332b78 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -318,6 +318,10 @@
"cyclonedx": {
"$ref": "#/definitions/string_file_list",
"markdownDescription": "Path to file or list of files with cyclonedx report(s). [Learn More](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscyclonedx)."
+ },
+ "load_performance": {
+ "$ref": "#/definitions/string_file_list",
+ "markdownDescription": "Path to file or list of files with load performance testing report(s). [Learn More](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsload_performance)."
}
}
}
@@ -537,7 +541,7 @@
},
"entrypoint": {
"type": "array",
- "description": "Command or script that should be executed as the container's entrypoint. It will be translated to Docker's --entrypoint option while creating the container. The syntax is similar to Dockerfile's ENTRYPOINT directive, where each shell token is a separate string in the array.",
+ "markdownDescription": "Command or script that should be executed as the container's entrypoint. It will be translated to Docker's --entrypoint option while creating the container. The syntax is similar to Dockerfile's ENTRYPOINT directive, where each shell token is a separate string in the array. [Learn More](https://docs.gitlab.com/ee/ci/services/index.html#available-settings-for-services)",
"minItems": 1,
"items": {
"type": "string"
@@ -572,7 +576,7 @@
},
"command": {
"type": "array",
- "description": "Command or script that should be used as the container's command. It will be translated to arguments passed to Docker after the image's name. The syntax is similar to Dockerfile's CMD directive, where each shell token is a separate string in the array.",
+ "markdownDescription": "Command or script that should be used as the container's command. It will be translated to arguments passed to Docker after the image's name. The syntax is similar to Dockerfile's CMD directive, where each shell token is a separate string in the array. [Learn More](https://docs.gitlab.com/ee/ci/services/index.html#available-settings-for-services)",
"minItems": 1,
"items": {
"type": "string"
@@ -580,8 +584,12 @@
},
"alias": {
"type": "string",
- "description": "Additional alias that can be used to access the service from the job's container. Read Accessing the services for more information.",
+ "markdownDescription": "Additional alias that can be used to access the service from the job's container. Read Accessing the services for more information. [Learn More](https://docs.gitlab.com/ee/ci/services/index.html#available-settings-for-services)",
"minLength": 1
+ },
+ "variables": {
+ "$ref": "#/definitions/jobVariables",
+ "markdownDescription": "Additional environment variables that are passed exclusively to the service. Service variables cannot reference themselves. [Learn More](https://docs.gitlab.com/ee/ci/services/index.html#available-settings-for-services)"
}
},
"required": [
diff --git a/app/assets/javascripts/editor/utils.js b/app/assets/javascripts/editor/utils.js
index df9d3f2b9fb..cea9a8971b7 100644
--- a/app/assets/javascripts/editor/utils.js
+++ b/app/assets/javascripts/editor/utils.js
@@ -16,17 +16,18 @@ export const setupEditorTheme = () => {
monacoEditor.setTheme(theme ? themeName : DEFAULT_THEME);
};
-export const getBlobLanguage = (blobPath) => {
+export const getBlobLanguage = (path) => {
const defaultLanguage = 'plaintext';
- if (!blobPath) {
+ if (!path) {
return defaultLanguage;
}
- const ext = `.${blobPath.split('.').pop()}`;
+ const blobPath = path.split('/').pop();
+ const ext = blobPath.includes('.') ? `.${blobPath.split('.').pop()}` : blobPath;
const language = monacoLanguages
.getLanguages()
- .find((lang) => lang.extensions.indexOf(ext) !== -1);
+ .find((lang) => lang.extensions.indexOf(ext.toLowerCase()) !== -1);
return language ? language.id : defaultLanguage;
};
diff --git a/app/assets/javascripts/emoji/components/emoji_group.vue b/app/assets/javascripts/emoji/components/emoji_group.vue
index 4f4c32af113..bbac6866636 100644
--- a/app/assets/javascripts/emoji/components/emoji_group.vue
+++ b/app/assets/javascripts/emoji/components/emoji_group.vue
@@ -1,5 +1,10 @@
<script>
+import { compatFunctionalMixin } from '~/lib/utils/vue3compat/compat_functional_mixin';
+
export default {
+ // Temporary mixin for migration from Vue.js 2 to @vue/compat
+ mixins: [compatFunctionalMixin],
+
props: {
emojis: {
type: Array,
diff --git a/app/assets/javascripts/entrypoints/super_sidebar.js b/app/assets/javascripts/entrypoints/super_sidebar.js
new file mode 100644
index 00000000000..308077f98b1
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/super_sidebar.js
@@ -0,0 +1,5 @@
+import '~/webpack';
+import '~/commons';
+import { initSuperSidebar } from '~/super_sidebar/super_sidebar_bundle';
+
+initSuperSidebar();
diff --git a/app/assets/javascripts/environments/components/canary_update_modal.vue b/app/assets/javascripts/environments/components/canary_update_modal.vue
index cacd868bed0..aff7d34f191 100644
--- a/app/assets/javascripts/environments/components/canary_update_modal.vue
+++ b/app/assets/javascripts/environments/components/canary_update_modal.vue
@@ -42,7 +42,7 @@ export default {
modalId: CANARY_UPDATE_MODAL,
actionPrimary: {
text: s__('CanaryIngress|Change ratio'),
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
actionCancel: { text: __('Cancel') },
static: true,
diff --git a/app/assets/javascripts/environments/components/confirm_rollback_modal.vue b/app/assets/javascripts/environments/components/confirm_rollback_modal.vue
index 8259574f8e3..53a93bbce30 100644
--- a/app/assets/javascripts/environments/components/confirm_rollback_modal.vue
+++ b/app/assets/javascripts/environments/components/confirm_rollback_modal.vue
@@ -135,7 +135,7 @@ export default {
csrf,
cancelProps: {
text: __('Cancel'),
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
},
docsPath: helpPagePath('ci/environments/index.md', { anchor: 'retry-or-roll-back-a-deployment' }),
};
diff --git a/app/assets/javascripts/environments/components/delete_environment_modal.vue b/app/assets/javascripts/environments/components/delete_environment_modal.vue
index 78e1b8d5cb2..47f38980acc 100644
--- a/app/assets/javascripts/environments/components/delete_environment_modal.vue
+++ b/app/assets/javascripts/environments/components/delete_environment_modal.vue
@@ -1,6 +1,6 @@
<script>
import { GlTooltipDirective, GlModal } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, s__, sprintf } from '~/locale';
import eventHub from '../event_hub';
import deleteEnvironmentMutation from '../graphql/mutations/delete_environment.mutation.graphql';
@@ -29,7 +29,7 @@ export default {
primaryProps() {
return {
text: s__('Environments|Delete environment'),
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
};
},
cancelProps() {
diff --git a/app/assets/javascripts/environments/components/deployment.vue b/app/assets/javascripts/environments/components/deployment.vue
index b00a0777a03..01b8208fd55 100644
--- a/app/assets/javascripts/environments/components/deployment.vue
+++ b/app/assets/javascripts/environments/components/deployment.vue
@@ -10,7 +10,7 @@ import {
import { __, s__ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import deploymentDetails from '../graphql/queries/deployment_details.query.graphql';
import DeploymentStatusBadge from './deployment_status_badge.vue';
import Commit from './commit.vue';
diff --git a/app/assets/javascripts/environments/components/edit_environment.vue b/app/assets/javascripts/environments/components/edit_environment.vue
index 901d0f5b34d..b63a6897a39 100644
--- a/app/assets/javascripts/environments/components/edit_environment.vue
+++ b/app/assets/javascripts/environments/components/edit_environment.vue
@@ -1,5 +1,5 @@
<script>
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import EnvironmentForm from './environment_form.vue';
diff --git a/app/assets/javascripts/environments/components/environment_form.vue b/app/assets/javascripts/environments/components/environment_form.vue
index ee5d95ae6f0..62ceb66d803 100644
--- a/app/assets/javascripts/environments/components/environment_form.vue
+++ b/app/assets/javascripts/environments/components/environment_form.vue
@@ -17,7 +17,7 @@ export default {
GlLink,
GlSprintf,
},
- inject: ['protectedEnvironmentSettingsPath'],
+ inject: { protectedEnvironmentSettingsPath: { default: '' } },
props: {
environment: {
required: true,
diff --git a/app/assets/javascripts/environments/components/kubernetes_agent_info.vue b/app/assets/javascripts/environments/components/kubernetes_agent_info.vue
new file mode 100644
index 00000000000..c4f6d225444
--- /dev/null
+++ b/app/assets/javascripts/environments/components/kubernetes_agent_info.vue
@@ -0,0 +1,101 @@
+<script>
+import { GlIcon, GlLink, GlSprintf, GlLoadingIcon, GlAlert } from '@gitlab/ui';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import { getAgentLastContact, getAgentStatus } from '~/clusters_list/clusters_util';
+import { TOKEN_STATUS_ACTIVE } from '~/clusters/agents/constants';
+import { AGENT_STATUSES } from '~/clusters_list/constants';
+import { s__ } from '~/locale';
+import getK8sClusterAgentQuery from '../graphql/queries/k8s_cluster_agent.query.graphql';
+
+export default {
+ components: {
+ GlIcon,
+ GlLink,
+ GlSprintf,
+ GlLoadingIcon,
+ TimeAgoTooltip,
+ GlAlert,
+ },
+ props: {
+ agentName: {
+ required: true,
+ type: String,
+ },
+ agentId: {
+ required: true,
+ type: String,
+ },
+ agentProjectPath: {
+ required: true,
+ type: String,
+ },
+ },
+ apollo: {
+ clusterAgent: {
+ query: getK8sClusterAgentQuery,
+ variables() {
+ return {
+ agentName: this.agentName,
+ projectPath: this.agentProjectPath,
+ tokenStatus: TOKEN_STATUS_ACTIVE,
+ };
+ },
+ update: (data) => data?.project?.clusterAgent,
+ error() {
+ this.clusterAgent = null;
+ },
+ },
+ },
+ data() {
+ return {
+ clusterAgent: null,
+ };
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.clusterAgent.loading;
+ },
+ agentLastContact() {
+ return getAgentLastContact(this.clusterAgent.tokens.nodes);
+ },
+ agentStatus() {
+ return getAgentStatus(this.agentLastContact);
+ },
+ },
+ methods: {},
+ i18n: {
+ loadingError: s__('ClusterAgents|An error occurred while loading your agent'),
+ agentId: s__('ClusterAgents|Agent ID #%{agentId}'),
+ neverConnectedText: s__('ClusterAgents|Never'),
+ },
+ AGENT_STATUSES,
+};
+</script>
+<template>
+ <gl-loading-icon v-if="isLoading" inline />
+ <div v-else-if="clusterAgent" class="gl-text-gray-900">
+ <gl-icon name="kubernetes-agent" class="gl-text-gray-500" />
+ <gl-link :href="clusterAgent.webPath" class="gl-mr-3">
+ <gl-sprintf :message="$options.i18n.agentId"
+ ><template #agentId>{{ agentId }}</template></gl-sprintf
+ >
+ </gl-link>
+ <span class="gl-mr-3" data-testid="agent-status">
+ <gl-icon
+ :name="$options.AGENT_STATUSES[agentStatus].icon"
+ :class="$options.AGENT_STATUSES[agentStatus].class"
+ />
+ {{ $options.AGENT_STATUSES[agentStatus].name }}
+ </span>
+
+ <span data-testid="agent-last-used-date">
+ <gl-icon name="calendar" />
+ <time-ago-tooltip v-if="agentLastContact" :time="agentLastContact" />
+ <span v-else>{{ $options.i18n.neverConnectedText }}</span>
+ </span>
+ </div>
+
+ <gl-alert v-else variant="danger" :dismissible="false">
+ {{ $options.i18n.loadingError }}
+ </gl-alert>
+</template>
diff --git a/app/assets/javascripts/environments/components/kubernetes_overview.vue b/app/assets/javascripts/environments/components/kubernetes_overview.vue
new file mode 100644
index 00000000000..cfb18cc4f82
--- /dev/null
+++ b/app/assets/javascripts/environments/components/kubernetes_overview.vue
@@ -0,0 +1,73 @@
+<script>
+import { GlCollapse, GlButton } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+import KubernetesAgentInfo from './kubernetes_agent_info.vue';
+
+export default {
+ components: {
+ GlCollapse,
+ GlButton,
+ KubernetesAgentInfo,
+ },
+ props: {
+ agentName: {
+ required: true,
+ type: String,
+ },
+ agentId: {
+ required: true,
+ type: String,
+ },
+ agentProjectPath: {
+ required: true,
+ type: String,
+ },
+ },
+ data() {
+ return {
+ isVisible: false,
+ };
+ },
+ computed: {
+ chevronIcon() {
+ return this.isVisible ? 'chevron-down' : 'chevron-right';
+ },
+ label() {
+ return this.isVisible ? this.$options.i18n.collapse : this.$options.i18n.expand;
+ },
+ },
+ methods: {
+ toggleCollapse() {
+ this.isVisible = !this.isVisible;
+ },
+ },
+ i18n: {
+ collapse: __('Collapse'),
+ expand: __('Expand'),
+ sectionTitle: s__('Environment|Kubernetes overview'),
+ },
+};
+</script>
+<template>
+ <div class="gl-px-4">
+ <p class="gl-font-weight-bold gl-text-gray-500 gl-display-flex gl-mb-0">
+ <gl-button
+ :icon="chevronIcon"
+ :aria-label="label"
+ category="tertiary"
+ size="small"
+ class="gl-mr-3"
+ @click="toggleCollapse"
+ />{{ $options.i18n.sectionTitle }}
+ </p>
+ <gl-collapse :visible="isVisible" class="gl-md-pl-7 gl-md-pr-5 gl-mt-4">
+ <template v-if="isVisible">
+ <kubernetes-agent-info
+ :agent-name="agentName"
+ :agent-id="agentId"
+ :agent-project-path="agentProjectPath"
+ class="gl-mb-5"
+ /></template>
+ </gl-collapse>
+ </div>
+</template>
diff --git a/app/assets/javascripts/environments/components/new_environment.vue b/app/assets/javascripts/environments/components/new_environment.vue
index bb4d6ab3428..4b58d133817 100644
--- a/app/assets/javascripts/environments/components/new_environment.vue
+++ b/app/assets/javascripts/environments/components/new_environment.vue
@@ -1,5 +1,5 @@
<script>
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import EnvironmentForm from './environment_form.vue';
diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue
index 73dfd993c5b..2ec6e12b8b3 100644
--- a/app/assets/javascripts/environments/components/new_environment_item.vue
+++ b/app/assets/javascripts/environments/components/new_environment_item.vue
@@ -11,6 +11,7 @@ import {
import { __, s__ } from '~/locale';
import { truncate } from '~/lib/utils/text_utility';
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 ExternalUrl from './environment_external_url.vue';
import Actions from './environment_actions.vue';
@@ -22,6 +23,7 @@ import Terminal from './environment_terminal_button.vue';
import Delete from './environment_delete.vue';
import Deployment from './deployment.vue';
import DeployBoardWrapper from './deploy_board_wrapper.vue';
+import KubernetesOverview from './kubernetes_overview.vue';
export default {
components: {
@@ -42,6 +44,7 @@ export default {
Terminal,
TimeAgoTooltip,
Delete,
+ KubernetesOverview,
EnvironmentAlert: () => import('ee_component/environments/components/environment_alert.vue'),
EnvironmentApproval: () =>
import('ee_component/environments/components/environment_approval.vue'),
@@ -49,6 +52,7 @@ export default {
directives: {
GlTooltip,
},
+ mixins: [glFeatureFlagsMixin()],
inject: ['helpPagePath'],
props: {
environment: {
@@ -162,6 +166,18 @@ export default {
rolloutStatus() {
return this.environment?.rolloutStatus;
},
+ agent() {
+ return this.environment?.agent || {};
+ },
+ isKubernetesOverviewAvailable() {
+ return this.glFeatures?.kasUserAccessProject;
+ },
+ hasRequiredAgentData() {
+ return this.agent.project && this.agent.id && this.agent.name;
+ },
+ showKubernetesOverview() {
+ return this.isKubernetesOverviewAvailable && this.hasRequiredAgentData;
+ },
},
methods: {
toggleCollapse() {
@@ -184,6 +200,13 @@ export default {
'gl-md-pl-7',
'gl-bg-gray-10',
],
+ kubernetesOverviewClasses: [
+ 'gl-border-gray-100',
+ 'gl-border-t-solid',
+ 'gl-border-1',
+ 'gl-py-4',
+ 'gl-bg-gray-10',
+ ],
};
</script>
<template>
@@ -340,6 +363,13 @@ export default {
</template>
</gl-sprintf>
</div>
+ <div v-if="showKubernetesOverview" :class="$options.kubernetesOverviewClasses">
+ <kubernetes-overview
+ :agent-project-path="agent.project"
+ :agent-name="agent.name"
+ :agent-id="agent.id"
+ />
+ </div>
<div v-if="rolloutStatus" :class="$options.deployBoardClasses">
<deploy-board-wrapper
:rollout-status="rolloutStatus"
diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue
index 162ad598c8c..dc0c5dc0f46 100644
--- a/app/assets/javascripts/environments/components/stop_environment_modal.vue
+++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue
@@ -33,7 +33,7 @@ export default {
primaryProps() {
return {
text: s__('Environments|Stop environment'),
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
};
},
cancelProps() {
diff --git a/app/assets/javascripts/environments/graphql/queries/k8s_cluster_agent.query.graphql b/app/assets/javascripts/environments/graphql/queries/k8s_cluster_agent.query.graphql
new file mode 100644
index 00000000000..999ae74239f
--- /dev/null
+++ b/app/assets/javascripts/environments/graphql/queries/k8s_cluster_agent.query.graphql
@@ -0,0 +1,19 @@
+query getK8sClusterAgentQuery(
+ $projectPath: ID!
+ $agentName: String!
+ $tokenStatus: AgentTokenStatus!
+) {
+ project(fullPath: $projectPath) {
+ id
+ clusterAgent(name: $agentName) {
+ id
+ webPath
+ tokens(status: $tokenStatus) {
+ nodes {
+ id
+ lastUsedAt
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js
index 5e936ad8c96..f8e94cf3ea9 100644
--- a/app/assets/javascripts/environments/mixins/environments_mixin.js
+++ b/app/assets/javascripts/environments/mixins/environments_mixin.js
@@ -3,7 +3,7 @@
*/
import { isEqual, isFunction, omitBy } from 'lodash';
import Visibility from 'visibilityjs';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Poll from '~/lib/utils/poll';
import { getParameterByName } from '~/lib/utils/url_utility';
import { s__, __ } from '~/locale';
diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue
index b02c3cd2cba..61c0ddef639 100644
--- a/app/assets/javascripts/error_tracking/components/error_details.vue
+++ b/app/assets/javascripts/error_tracking/components/error_details.vue
@@ -13,7 +13,7 @@ import {
GlIcon,
} from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
-import { createAlert, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/alert';
import { __, sprintf, n__ } from '~/locale';
import Tracking from '~/tracking';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
diff --git a/app/assets/javascripts/error_tracking/store/actions.js b/app/assets/javascripts/error_tracking/store/actions.js
index 603f8611005..adbce7750fa 100644
--- a/app/assets/javascripts/error_tracking/store/actions.js
+++ b/app/assets/javascripts/error_tracking/store/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { visitUrl } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import service from '../services';
diff --git a/app/assets/javascripts/error_tracking/store/details/actions.js b/app/assets/javascripts/error_tracking/store/details/actions.js
index 1409399940a..89b9432c377 100644
--- a/app/assets/javascripts/error_tracking/store/details/actions.js
+++ b/app/assets/javascripts/error_tracking/store/details/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Poll from '~/lib/utils/poll';
import { __ } from '~/locale';
import service from '../../services';
diff --git a/app/assets/javascripts/error_tracking/store/list/actions.js b/app/assets/javascripts/error_tracking/store/list/actions.js
index f633711add3..84e4463ca21 100644
--- a/app/assets/javascripts/error_tracking/store/list/actions.js
+++ b/app/assets/javascripts/error_tracking/store/list/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Poll from '~/lib/utils/poll';
import { __ } from '~/locale';
import Service from '../../services';
diff --git a/app/assets/javascripts/error_tracking_settings/store/actions.js b/app/assets/javascripts/error_tracking_settings/store/actions.js
index 4d6fe767f3a..368dd438f89 100644
--- a/app/assets/javascripts/error_tracking_settings/store/actions.js
+++ b/app/assets/javascripts/error_tracking_settings/store/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue b/app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue
index 366ee6bb05b..9fb5d9f0943 100644
--- a/app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue
+++ b/app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue
@@ -84,11 +84,9 @@ export default {
cancelActionProps() {
return {
text: this.$options.translations.cancelActionLabel,
- attributes: [
- {
- category: 'secondary',
- },
- ],
+ attributes: {
+ category: 'secondary',
+ },
};
},
canRegenerateInstanceId() {
@@ -98,14 +96,12 @@ export default {
return this.canUserRotateToken
? {
text: this.$options.translations.instanceIdRegenerateActionLabel,
- attributes: [
- {
- category: 'secondary',
- disabled: !this.canRegenerateInstanceId,
- loading: this.isRotating,
- variant: 'danger',
- },
- ],
+ attributes: {
+ category: 'secondary',
+ disabled: !this.canRegenerateInstanceId,
+ loading: this.isRotating,
+ variant: 'danger',
+ },
}
: null;
},
diff --git a/app/assets/javascripts/feature_flags/components/environments_dropdown.vue b/app/assets/javascripts/feature_flags/components/environments_dropdown.vue
index ce5f7915dbf..57727cb945e 100644
--- a/app/assets/javascripts/feature_flags/components/environments_dropdown.vue
+++ b/app/assets/javascripts/feature_flags/components/environments_dropdown.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton, GlSearchBoxByType } from '@gitlab/ui';
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
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 89400bc4742..420c34a88f1 100644
--- a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
+++ b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
@@ -8,7 +8,7 @@ import {
GlSearchBoxByType,
} from '@gitlab/ui';
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __, sprintf } from '~/locale';
diff --git a/app/assets/javascripts/feature_flags/constants.js b/app/assets/javascripts/feature_flags/constants.js
index f697f203cf5..1993ec7abf2 100644
--- a/app/assets/javascripts/feature_flags/constants.js
+++ b/app/assets/javascripts/feature_flags/constants.js
@@ -1,4 +1,3 @@
-import { property } from 'lodash';
import { s__ } from '~/locale';
export const ROLLOUT_STRATEGY_ALL_USERS = 'default';
@@ -9,15 +8,8 @@ export const ROLLOUT_STRATEGY_GITLAB_USER_LIST = 'gitlabUserList';
export const PERCENT_ROLLOUT_GROUP_ID = 'default';
-export const DEFAULT_PERCENT_ROLLOUT = '100';
-
export const ALL_ENVIRONMENTS_NAME = '*';
-export const INTERNAL_ID_PREFIX = 'internal_';
-
-export const fetchPercentageParams = property(['parameters', 'percentage']);
-export const fetchUserIdParams = property(['parameters', 'userIds']);
-
export const NEW_VERSION_FLAG = 'new_version_flag';
export const LEGACY_FLAG = 'legacy_flag';
diff --git a/app/assets/javascripts/feature_flags/store/edit/actions.js b/app/assets/javascripts/feature_flags/store/edit/actions.js
index 97c22781ac5..585bb1be0c4 100644
--- a/app/assets/javascripts/feature_flags/store/edit/actions.js
+++ b/app/assets/javascripts/feature_flags/store/edit/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
index a9542a9667e..e2218c1ba2e 100644
--- a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
+++ b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js b/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js
index 397ba879866..50fca995c81 100644
--- a/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js
+++ b/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js
@@ -72,6 +72,38 @@ export default (IssuableTokenKeys, disableTargetBranchFilter = false) => {
IssuableTokenKeys.tokenKeysWithAlternative.push(targetBranchToken);
}
+ const approvedToken = {
+ token: {
+ formattedKey: __('Approved'),
+ key: 'approved',
+ type: 'string',
+ param: '',
+ symbol: '',
+ icon: 'approval',
+ tag: __('Yes or No'),
+ lowercaseValueOnSubmit: true,
+ capitalizeTokenValue: true,
+ hideNotEqual: true,
+ },
+ conditions: [
+ {
+ url: 'approved=yes',
+ tokenKey: 'approved',
+ value: __('Yes'),
+ operator: '=',
+ },
+ {
+ url: 'approved=no',
+ tokenKey: 'approved',
+ value: __('No'),
+ operator: '=',
+ },
+ ],
+ };
+
+ IssuableTokenKeys.tokenKeys.splice(3, 0, approvedToken.token);
+ IssuableTokenKeys.conditions.push(...approvedToken.conditions);
+
const approvedBy = {
token: {
formattedKey: TOKEN_TITLE_APPROVED_BY,
@@ -117,8 +149,8 @@ export default (IssuableTokenKeys, disableTargetBranchFilter = false) => {
],
};
- const tokenPosition = 3;
- IssuableTokenKeys.tokenKeys.splice(tokenPosition, 0, ...[approvedBy.token]);
+ const tokenPosition = 4;
+ IssuableTokenKeys.tokenKeys.splice(tokenPosition, 0, approvedBy.token);
IssuableTokenKeys.tokenKeysWithAlternative.splice(
tokenPosition,
0,
diff --git a/app/assets/javascripts/filtered_search/available_dropdown_mappings.js b/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
index 1f8baa470d8..892e9130fe8 100644
--- a/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
+++ b/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
@@ -138,6 +138,11 @@ export default class AvailableDropdownMappings {
gl: DropdownNonUser,
element: this.container.querySelector('#js-dropdown-wip'),
},
+ approved: {
+ reference: null,
+ gl: DropdownNonUser,
+ element: this.container.querySelector('#js-dropdown-approved'),
+ },
[TOKEN_TYPE_CONFIDENTIAL]: {
reference: null,
gl: DropdownNonUser,
diff --git a/app/assets/javascripts/filtered_search/dropdown_ajax_filter.js b/app/assets/javascripts/filtered_search/dropdown_ajax_filter.js
index 23591fc0667..e1330433362 100644
--- a/app/assets/javascripts/filtered_search/dropdown_ajax_filter.js
+++ b/app/assets/javascripts/filtered_search/dropdown_ajax_filter.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import AjaxFilter from './droplab/plugins/ajax_filter';
import DropdownUtils from './dropdown_utils';
diff --git a/app/assets/javascripts/filtered_search/dropdown_emoji.js b/app/assets/javascripts/filtered_search/dropdown_emoji.js
index 8c50c1860ec..bb33c3ad935 100644
--- a/app/assets/javascripts/filtered_search/dropdown_emoji.js
+++ b/app/assets/javascripts/filtered_search/dropdown_emoji.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import Ajax from './droplab/plugins/ajax';
import Filter from './droplab/plugins/filter';
diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js b/app/assets/javascripts/filtered_search/dropdown_non_user.js
index ab95986dc62..3046ad42e24 100644
--- a/app/assets/javascripts/filtered_search/dropdown_non_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import Ajax from './droplab/plugins/ajax';
import Filter from './droplab/plugins/filter';
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index 16c70fdd069..d865354881a 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -1,7 +1,8 @@
import { last } from 'lodash';
import recentSearchesStorageKeys from 'ee_else_ce/filtered_search/recent_searches_storage_keys';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { WORKSPACE_PROJECT } from '~/issues/constants';
import {
ENTER_KEY_CODE,
BACKSPACE_KEY_CODE,
@@ -82,7 +83,7 @@ export default class FilteredSearchManager {
);
const fullPath = this.searchHistoryDropdownElement
? this.searchHistoryDropdownElement.dataset.fullPath
- : 'project';
+ : WORKSPACE_PROJECT;
const recentSearchesKey = `${fullPath}-${recentSearchesStorageKeys[this.page]}`;
this.recentSearchesService = new RecentSearchesService(recentSearchesKey);
}
diff --git a/app/assets/javascripts/filtered_search/visual_token_value.js b/app/assets/javascripts/filtered_search/visual_token_value.js
index 33fda7533e4..409f6a4a9dc 100644
--- a/app/assets/javascripts/filtered_search/visual_token_value.js
+++ b/app/assets/javascripts/filtered_search/visual_token_value.js
@@ -4,7 +4,7 @@ import * as Emoji from '~/emoji';
import FilteredSearchContainer from '~/filtered_search/container';
import DropdownUtils from '~/filtered_search/dropdown_utils';
import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import AjaxCache from '~/lib/utils/ajax_cache';
import UsersCache from '~/lib/utils/users_cache';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js
deleted file mode 100644
index 483f1d2c7a0..00000000000
--- a/app/assets/javascripts/flash.js
+++ /dev/null
@@ -1,137 +0,0 @@
-import * as Sentry from '@sentry/browser';
-import Vue from 'vue';
-import { GlAlert } from '@gitlab/ui';
-import { __ } from '~/locale';
-
-export const VARIANT_SUCCESS = 'success';
-export const VARIANT_WARNING = 'warning';
-export const VARIANT_DANGER = 'danger';
-export const VARIANT_INFO = 'info';
-export const VARIANT_TIP = 'tip';
-
-/**
- * Render an alert at the top of the page, or, optionally an
- * arbitrary existing container. This alert is always dismissible.
- *
- * @example
- * // Render a new alert
- * import { createAlert, VARIANT_WARNING } from '~/flash';
- *
- * createAlert({ message: 'My error message' });
- * createAlert({ message: 'My warning message', variant: VARIANT_WARNING });
- *
- * @example
- * // Dismiss this alert programmatically
- * const alert = createAlert({ message: 'Message' });
- *
- * // ...
- *
- * alert.dismiss();
- *
- * @example
- * // Respond to the alert being dismissed
- * createAlert({ message: 'Message', onDismiss: () => {} });
- *
- * @param {object} options - Options to control the flash message
- * @param {string} options.message - Alert message text
- * @param {string} [options.title] - Alert title
- * @param {VARIANT_SUCCESS|VARIANT_WARNING|VARIANT_DANGER|VARIANT_INFO|VARIANT_TIP} [options.variant] - Which GlAlert variant to use; it defaults to VARIANT_DANGER.
- * @param {object} [options.parent] - Reference to parent element under which alert needs to appear. Defaults to `document`.
- * @param {Function} [options.onDismiss] - Handler to call when this alert is dismissed.
- * @param {string} [options.containerSelector] - Selector for the container of the alert
- * @param {boolean} [options.preservePrevious] - Set to `true` to preserve previous alerts. Defaults to `false`.
- * @param {object} [options.primaryButton] - Object describing primary button of alert
- * @param {string} [options.primaryButton.link] - Href of primary button
- * @param {string} [options.primaryButton.text] - Text of primary button
- * @param {Function} [options.primaryButton.clickHandler] - Handler to call when primary button is clicked on. The click event is sent as an argument.
- * @param {object} [options.secondaryButton] - Object describing secondary button of alert
- * @param {string} [options.secondaryButton.link] - Href of secondary button
- * @param {string} [options.secondaryButton.text] - Text of secondary button
- * @param {Function} [options.secondaryButton.clickHandler] - Handler to call when secondary button is clicked on. The click event is sent as an argument.
- * @param {boolean} [options.captureError] - Whether to send error to Sentry
- * @param {object} [options.error] - Error to be captured in Sentry
- */
-export const createAlert = ({
- message,
- title,
- variant = VARIANT_DANGER,
- parent = document,
- containerSelector = '.flash-container',
- preservePrevious = false,
- primaryButton = null,
- secondaryButton = null,
- onDismiss = null,
- captureError = false,
- error = null,
-}) => {
- if (captureError && error) Sentry.captureException(error);
-
- const alertContainer = parent.querySelector(containerSelector);
- if (!alertContainer) return null;
-
- const el = document.createElement('div');
- if (preservePrevious) {
- alertContainer.appendChild(el);
- } else {
- alertContainer.replaceChildren(el);
- }
-
- return new Vue({
- el,
- components: {
- GlAlert,
- },
- methods: {
- /**
- * Public method to dismiss this alert and removes
- * this Vue instance.
- */
- dismiss() {
- if (onDismiss) {
- onDismiss();
- }
- this.$destroy();
- this.$el.parentNode?.removeChild(this.$el);
- },
- },
- render(h) {
- const on = {};
-
- on.dismiss = () => {
- this.dismiss();
- };
-
- if (primaryButton?.clickHandler) {
- on.primaryAction = (e) => {
- primaryButton.clickHandler(e);
- };
- }
- if (secondaryButton?.clickHandler) {
- on.secondaryAction = (e) => {
- secondaryButton.clickHandler(e);
- };
- }
-
- return h(
- GlAlert,
- {
- props: {
- title,
- dismissible: true,
- dismissLabel: __('Dismiss'),
- variant,
- primaryButtonLink: primaryButton?.link,
- primaryButtonText: primaryButton?.text,
- secondaryButtonLink: secondaryButton?.link,
- secondaryButtonText: secondaryButton?.text,
- },
- attrs: {
- 'data-testid': `alert-${variant}`,
- },
- on,
- },
- message,
- );
- },
- });
-};
diff --git a/app/assets/javascripts/gpg_badges.js b/app/assets/javascripts/gpg_badges.js
index ad339155a59..b45c98b46f6 100644
--- a/app/assets/javascripts/gpg_badges.js
+++ b/app/assets/javascripts/gpg_badges.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { queryToObject } from '~/lib/utils/url_utility';
import { loadingIconForLegacyJS } from '~/loading_icon_for_legacy_js';
diff --git a/app/assets/javascripts/grafana_integration/store/actions.js b/app/assets/javascripts/grafana_integration/store/actions.js
index db2fd3cc256..76e21f09719 100644
--- a/app/assets/javascripts/grafana_integration/store/actions.js
+++ b/app/assets/javascripts/grafana_integration/store/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -29,7 +29,7 @@ export const updateGrafanaIntegration = ({ state, dispatch }) =>
export const receiveGrafanaIntegrationUpdateSuccess = () => {
/**
* The operations_controller currently handles successful requests
- * by creating a flash banner messsage to notify the user.
+ * by creating an alert banner message to notify the user.
*/
refreshCurrentPage();
};
diff --git a/app/assets/javascripts/graphql_shared/constants.js b/app/assets/javascripts/graphql_shared/constants.js
index 3c4ca4c197e..77fca45c949 100644
--- a/app/assets/javascripts/graphql_shared/constants.js
+++ b/app/assets/javascripts/graphql_shared/constants.js
@@ -26,3 +26,4 @@ export const TYPENAME_USER = 'User';
export const TYPENAME_VULNERABILITIES_SCANNER = 'Vulnerabilities::Scanner';
export const TYPENAME_VULNERABILITY = 'Vulnerability';
export const TYPENAME_WORK_ITEM = 'WorkItem';
+export const TYPE_USERS_SAVED_REPLY = 'Users::SavedReply';
diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json
index 4a5536986bd..22629dfb7d8 100644
--- a/app/assets/javascripts/graphql_shared/possible_types.json
+++ b/app/assets/javascripts/graphql_shared/possible_types.json
@@ -152,6 +152,7 @@
"WorkItemWidgetLabels",
"WorkItemWidgetMilestone",
"WorkItemWidgetNotes",
+ "WorkItemWidgetNotifications",
"WorkItemWidgetProgress",
"WorkItemWidgetRequirementLegacy",
"WorkItemWidgetStartAndDueDate",
@@ -159,4 +160,4 @@
"WorkItemWidgetTestReports",
"WorkItemWidgetWeight"
]
-} \ No newline at end of file
+}
diff --git a/app/assets/javascripts/graphql_shared/queries/get_users_by_usernames.query.graphql b/app/assets/javascripts/graphql_shared/queries/get_users_by_usernames.query.graphql
deleted file mode 100644
index 07398867544..00000000000
--- a/app/assets/javascripts/graphql_shared/queries/get_users_by_usernames.query.graphql
+++ /dev/null
@@ -1,9 +0,0 @@
-#import "../fragments/user.fragment.graphql"
-
-query getUsersByUsernames($usernames: [String!]) {
- users(usernames: $usernames) {
- nodes {
- ...User
- }
- }
-}
diff --git a/app/assets/javascripts/group.js b/app/assets/javascripts/group.js
index cc70d832edc..3b64606b141 100644
--- a/app/assets/javascripts/group.js
+++ b/app/assets/javascripts/group.js
@@ -1,6 +1,6 @@
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import { getGroupPathAvailability } from '~/rest_api';
import axios from '~/lib/utils/axios_utils';
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue
index 148bf0a98ee..82eddf5603f 100644
--- a/app/assets/javascripts/groups/components/app.vue
+++ b/app/assets/javascripts/groups/components/app.vue
@@ -1,6 +1,6 @@
<script>
import { GlLoadingIcon, GlModal, GlEmptyState } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_FORBIDDEN } from '~/lib/utils/http_status';
import { mergeUrlParams, getParameterByName } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale';
@@ -59,7 +59,7 @@ export default {
primaryProps() {
return {
text: __('Leave group'),
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
};
},
cancelProps() {
diff --git a/app/assets/javascripts/groups/components/group_name_and_path.vue b/app/assets/javascripts/groups/components/group_name_and_path.vue
index 5f997ecc7ba..1f9fc68a612 100644
--- a/app/assets/javascripts/groups/components/group_name_and_path.vue
+++ b/app/assets/javascripts/groups/components/group_name_and_path.vue
@@ -18,7 +18,7 @@ import { debounce } from 'lodash';
import { s__, __ } from '~/locale';
import { getGroupPathAvailability } from '~/rest_api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { slugify } from '~/lib/utils/text_utility';
import axios from '~/lib/utils/axios_utils';
import { helpPagePath } from '~/helpers/help_page_helper';
diff --git a/app/assets/javascripts/groups/components/invite_members_banner.vue b/app/assets/javascripts/groups/components/invite_members_banner.vue
index 7afea815197..a0a775e2916 100644
--- a/app/assets/javascripts/groups/components/invite_members_banner.vue
+++ b/app/assets/javascripts/groups/components/invite_members_banner.vue
@@ -45,10 +45,7 @@ export default {
});
},
openModal() {
- eventHub.$emit('openModal', {
- source: this.$options.openModalSource,
- });
- this.track(this.$options.buttonClickEvent);
+ eventHub.$emit('openModal', { source: this.$options.openModalSource });
},
},
i18n: {
@@ -59,7 +56,6 @@ export default {
button_text: s__('InviteMembersBanner|Invite your colleagues'),
},
displayEvent: 'invite_members_banner_displayed',
- buttonClickEvent: 'invite_members_banner_button_clicked',
openModalSource: 'invite_members_banner',
dismissEvent: 'invite_members_banner_dismissed',
};
diff --git a/app/assets/javascripts/groups/constants.js b/app/assets/javascripts/groups/constants.js
index 6fb12cd6270..6f5b03788a8 100644
--- a/app/assets/javascripts/groups/constants.js
+++ b/app/assets/javascripts/groups/constants.js
@@ -12,7 +12,6 @@ export const ACTIVE_TAB_SHARED = 'shared';
export const ACTIVE_TAB_ARCHIVED = 'archived';
export const GROUPS_LIST_HOLDER_CLASS = '.js-groups-list-holder';
-export const GROUPS_FILTER_FORM_CLASS = '.js-group-filter-form';
export const CONTENT_LIST_CLASS = '.groups-list';
export const COMMON_STR = {
diff --git a/app/assets/javascripts/groups/settings/components/access_dropdown.vue b/app/assets/javascripts/groups/settings/components/access_dropdown.vue
index db8e424e166..8bc5f28ebfb 100644
--- a/app/assets/javascripts/groups/settings/components/access_dropdown.vue
+++ b/app/assets/javascripts/groups/settings/components/access_dropdown.vue
@@ -1,7 +1,7 @@
<script>
import { GlDropdown, GlDropdownItem, GlDropdownSectionHeader, GlSearchBoxByType } from '@gitlab/ui';
import { debounce, intersectionWith, groupBy, differenceBy, intersectionBy } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, s__, n__ } from '~/locale';
import { getSubGroups } from '../api/access_dropdown_api';
import { LEVEL_TYPES } from '../constants';
diff --git a/app/assets/javascripts/groups/store/utils.js b/app/assets/javascripts/groups/store/utils.js
index 371b3aa9d52..d4b583483bd 100644
--- a/app/assets/javascripts/groups/store/utils.js
+++ b/app/assets/javascripts/groups/store/utils.js
@@ -1,3 +1,5 @@
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
+
export const getGroupItemMicrodata = ({ type }) => {
const defaultMicrodata = {
itemscope: true,
@@ -9,14 +11,14 @@ export const getGroupItemMicrodata = ({ type }) => {
};
switch (type) {
- case 'group':
+ case WORKSPACE_GROUP:
return {
...defaultMicrodata,
itemtype: 'https://schema.org/Organization',
itemprop: 'subOrganization',
imageItemprop: 'logo',
};
- case 'project':
+ case WORKSPACE_PROJECT:
return {
...defaultMicrodata,
itemtype: 'https://schema.org/SoftwareSourceCode',
diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js
index 6c9354b663f..9cb96283689 100644
--- a/app/assets/javascripts/header.js
+++ b/app/assets/javascripts/header.js
@@ -28,7 +28,7 @@ export default function initTodoToggle() {
});
}
-function initStatusTriggers() {
+export function initStatusTriggers() {
const setStatusModalTriggerEl = document.querySelector('.js-set-status-modal-trigger');
if (setStatusModalTriggerEl) {
diff --git a/app/assets/javascripts/header_search/components/app.vue b/app/assets/javascripts/header_search/components/app.vue
index ace0d77c431..c0a06706fc6 100644
--- a/app/assets/javascripts/header_search/components/app.vue
+++ b/app/assets/javascripts/header_search/components/app.vue
@@ -12,10 +12,20 @@ import { debounce } from 'lodash';
import { visitUrl } from '~/lib/utils/url_utility';
import { truncate } from '~/lib/utils/text_utility';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import { s__, sprintf } from '~/locale';
+import { sprintf } from '~/locale';
import Tracking from '~/tracking';
import DropdownKeyboardNavigation from '~/vue_shared/components/dropdown_keyboard_navigation.vue';
import {
+ SEARCH_GITLAB,
+ SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN,
+ SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN,
+ SEARCH_DESCRIBED_BY_DEFAULT,
+ SEARCH_DESCRIBED_BY_UPDATED,
+ SEARCH_RESULTS_LOADING,
+ SEARCH_RESULTS_SCOPE,
+ KBD_HELP,
+} from '~/vue_shared/global_search/constants';
+import {
FIRST_DROPDOWN_INDEX,
SEARCH_BOX_INDEX,
SEARCH_INPUT_DESCRIPTION,
@@ -34,26 +44,14 @@ import HeaderSearchScopedItems from './header_search_scoped_items.vue';
export default {
name: 'HeaderSearchApp',
i18n: {
- searchGitlab: s__('GlobalSearch|Search GitLab'),
- searchInputDescribeByNoDropdown: s__(
- 'GlobalSearch|Type and press the enter key to submit search.',
- ),
- searchInputDescribeByWithDropdown: s__(
- 'GlobalSearch|Type for new suggestions to appear below.',
- ),
- searchDescribedByDefault: s__(
- 'GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list.',
- ),
- searchDescribedByUpdated: s__(
- 'GlobalSearch|Results updated. %{count} results available. Use the up and down arrow keys to navigate search results list, or ENTER to submit.',
- ),
- searchResultsLoading: s__('GlobalSearch|Search results are loading'),
- searchResultsScope: s__('GlobalSearch|in %{scope}'),
- kbdHelp: sprintf(
- s__('GlobalSearch|Use the shortcut key %{kbdOpen}/%{kbdClose} to start a search'),
- { kbdOpen: '<kbd>', kbdClose: '</kbd>' },
- false,
- ),
+ SEARCH_GITLAB,
+ SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN,
+ SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN,
+ SEARCH_DESCRIBED_BY_DEFAULT,
+ SEARCH_DESCRIBED_BY_UPDATED,
+ SEARCH_RESULTS_LOADING,
+ SEARCH_RESULTS_SCOPE,
+ KBD_HELP,
},
directives: { Outside, GlTooltip: GlTooltipDirective, GlResizeObserverDirective },
components: {
@@ -113,9 +111,9 @@ export default {
searchInputDescribeBy() {
if (this.isLoggedIn) {
- return this.$options.i18n.searchInputDescribeByWithDropdown;
+ return this.$options.i18n.SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN;
}
- return this.$options.i18n.searchInputDescribeByNoDropdown;
+ return this.$options.i18n.SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN;
},
dropdownResultsDescription() {
if (!this.showSearchDropdown) {
@@ -123,14 +121,14 @@ export default {
}
if (this.showDefaultItems) {
- return sprintf(this.$options.i18n.searchDescribedByDefault, {
+ return sprintf(this.$options.i18n.SEARCH_DESCRIBED_BY_DEFAULT, {
count: this.searchOptions.length,
});
}
return this.loading
- ? this.$options.i18n.searchResultsLoading
- : sprintf(this.$options.i18n.searchDescribedByUpdated, {
+ ? this.$options.i18n.SEARCH_RESULTS_LOADING
+ : sprintf(this.$options.i18n.SEARCH_DESCRIBED_BY_UPDATED, {
count: this.searchOptions.length,
});
},
@@ -154,7 +152,7 @@ export default {
return this.searchBarItem?.icon;
},
scopeTokenTitle() {
- return sprintf(this.$options.i18n.searchResultsScope, {
+ return sprintf(this.$options.i18n.SEARCH_RESULTS_SCOPE, {
scope: this.infieldHelpContent,
});
},
@@ -230,7 +228,7 @@ export default {
<form
v-outside="closeDropdown"
role="search"
- :aria-label="$options.i18n.searchGitlab"
+ :aria-label="$options.i18n.SEARCH_GITLAB"
class="header-search gl-relative gl-rounded-base gl-w-full"
:class="searchBarClasses"
data-testid="header-search-form"
@@ -243,7 +241,7 @@ export default {
class="gl-z-index-1"
data-qa-selector="search_term_field"
autocomplete="off"
- :placeholder="$options.i18n.searchGitlab"
+ :placeholder="$options.i18n.SEARCH_GITLAB"
:aria-activedescendant="currentFocusedId"
:aria-describedby="$options.SEARCH_INPUT_DESCRIPTION"
@focus="openDropdown"
@@ -267,7 +265,7 @@ export default {
:size="16"
/>{{
getTruncatedScope(
- sprintf($options.i18n.searchResultsScope, {
+ sprintf($options.i18n.SEARCH_RESULTS_SCOPE, {
scope: infieldHelpContent,
}),
)
@@ -277,7 +275,7 @@ export default {
v-show="!isFocused"
v-gl-tooltip.bottom.hover.html
class="gl-absolute gl-right-3 gl-top-0 gl-z-index-1 keyboard-shortcut-helper"
- :title="$options.i18n.kbdHelp"
+ :title="$options.i18n.KBD_HELP"
>/</kbd
>
<span :id="$options.SEARCH_INPUT_DESCRIPTION" role="region" class="gl-sr-only">{{
diff --git a/app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue b/app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue
index c85fb4f4158..1838214def6 100644
--- a/app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue
+++ b/app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue
@@ -9,27 +9,23 @@ import {
} from '@gitlab/ui';
import { mapState, mapGetters } from 'vuex';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import { s__ } from '~/locale';
import highlight from '~/lib/utils/highlight';
import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
import { truncateNamespace } from '~/lib/utils/text_utility';
-
import {
GROUPS_CATEGORY,
PROJECTS_CATEGORY,
MERGE_REQUEST_CATEGORY,
ISSUES_CATEGORY,
RECENT_EPICS_CATEGORY,
- LARGE_AVATAR_PX,
- SMALL_AVATAR_PX,
-} from '../constants';
+ AUTOCOMPLETE_ERROR_MESSAGE,
+} from '~/vue_shared/global_search/constants';
+import { LARGE_AVATAR_PX, SMALL_AVATAR_PX } from '../constants';
export default {
name: 'HeaderSearchAutocompleteItems',
i18n: {
- autocompleteErrorMessage: s__(
- 'GlobalSearch|There was an error fetching search autocomplete suggestions.',
- ),
+ AUTOCOMPLETE_ERROR_MESSAGE,
},
components: {
GlDropdownItem,
@@ -165,7 +161,7 @@ export default {
:dismissible="false"
variant="danger"
>
- {{ $options.i18n.autocompleteErrorMessage }}
+ {{ $options.i18n.AUTOCOMPLETE_ERROR_MESSAGE }}
</gl-alert>
</div>
</template>
diff --git a/app/assets/javascripts/header_search/components/header_search_default_items.vue b/app/assets/javascripts/header_search/components/header_search_default_items.vue
index 04deaba7b0f..f0d398297e9 100644
--- a/app/assets/javascripts/header_search/components/header_search_default_items.vue
+++ b/app/assets/javascripts/header_search/components/header_search_default_items.vue
@@ -1,12 +1,12 @@
<script>
import { GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui';
import { mapState, mapGetters } from 'vuex';
-import { __ } from '~/locale';
+import { ALL_GITLAB } from '~/vue_shared/global_search/constants';
export default {
name: 'HeaderSearchDefaultItems',
i18n: {
- allGitLab: __('All GitLab'),
+ ALL_GITLAB,
},
components: {
GlDropdownSectionHeader,
@@ -26,7 +26,7 @@ export default {
return (
this.searchContext?.project?.name ||
this.searchContext?.group?.name ||
- this.$options.i18n.allGitLab
+ this.$options.i18n.ALL_GITLAB
);
},
},
diff --git a/app/assets/javascripts/header_search/components/header_search_scoped_items.vue b/app/assets/javascripts/header_search/components/header_search_scoped_items.vue
index f5be1bcb786..1ef88492b23 100644
--- a/app/assets/javascripts/header_search/components/header_search_scoped_items.vue
+++ b/app/assets/javascripts/header_search/components/header_search_scoped_items.vue
@@ -3,10 +3,14 @@ import { GlDropdownItem, GlIcon, GlToken } from '@gitlab/ui';
import { mapState, mapGetters } from 'vuex';
import { s__, sprintf } from '~/locale';
import { truncate } from '~/lib/utils/text_utility';
+import { SCOPED_SEARCH_ITEM_ARIA_LABEL } from '~/vue_shared/global_search/constants';
import { SCOPE_TOKEN_MAX_LENGTH } from '../constants';
export default {
name: 'HeaderSearchScopedItems',
+ i18n: {
+ SCOPED_SEARCH_ITEM_ARIA_LABEL,
+ },
components: {
GlDropdownItem,
GlIcon,
@@ -28,7 +32,7 @@ export default {
return this.currentFocusedOption?.html_id === option.html_id;
},
ariaLabel(option) {
- return sprintf(s__('GlobalSearch| %{search} %{description} %{scope}'), {
+ return sprintf(this.$options.i18n.SCOPED_SEARCH_ITEM_ARIA_LABEL, {
search: this.search,
description: option.description || option.icon,
scope: option.scope || '',
diff --git a/app/assets/javascripts/header_search/constants.js b/app/assets/javascripts/header_search/constants.js
index 65e113e5084..b9bb4e573fd 100644
--- a/app/assets/javascripts/header_search/constants.js
+++ b/app/assets/javascripts/header_search/constants.js
@@ -1,45 +1,9 @@
-import { s__ } from '~/locale';
-
-export const MSG_ISSUES_ASSIGNED_TO_ME = s__('GlobalSearch|Issues assigned to me');
-
-export const MSG_ISSUES_IVE_CREATED = s__("GlobalSearch|Issues I've created");
-
-export const MSG_MR_ASSIGNED_TO_ME = s__('GlobalSearch|Merge requests assigned to me');
-
-export const MSG_MR_IM_REVIEWER = s__("GlobalSearch|Merge requests that I'm a reviewer");
-
-export const MSG_MR_IVE_CREATED = s__("GlobalSearch|Merge requests I've created");
-
-export const MSG_IN_ALL_GITLAB = s__('GlobalSearch|all GitLab');
-
-export const MSG_IN_GROUP = s__('GlobalSearch|group');
-
-export const MSG_IN_PROJECT = s__('GlobalSearch|project');
-
export const ICON_PROJECT = 'project';
export const ICON_GROUP = 'group';
export const ICON_SUBGROUP = 'subgroup';
-export const GROUPS_CATEGORY = s__('GlobalSearch|Groups');
-
-export const PROJECTS_CATEGORY = s__('GlobalSearch|Projects');
-
-export const USERS_CATEGORY = s__('GlobalSearch|Users');
-
-export const ISSUES_CATEGORY = s__('GlobalSearch|Recent issues');
-
-export const MERGE_REQUEST_CATEGORY = s__('GlobalSearch|Recent merge requests');
-
-export const RECENT_EPICS_CATEGORY = s__('GlobalSearch|Recent epics');
-
-export const IN_THIS_PROJECT_CATEGORY = s__('GlobalSearch|In this project');
-
-export const SETTINGS_CATEGORY = s__('GlobalSearch|Settings');
-
-export const HELP_CATEGORY = s__('GlobalSearch|Help');
-
export const LARGE_AVATAR_PX = 32;
export const SMALL_AVATAR_PX = 16;
@@ -64,18 +28,6 @@ export const IS_SEARCHING = 'is-searching';
export const IS_FOCUSED = 'is-focused';
export const IS_NOT_FOCUSED = 'is-not-focused';
-export const DROPDOWN_ORDER = [
- MERGE_REQUEST_CATEGORY,
- ISSUES_CATEGORY,
- RECENT_EPICS_CATEGORY,
- GROUPS_CATEGORY,
- PROJECTS_CATEGORY,
- USERS_CATEGORY,
- IN_THIS_PROJECT_CATEGORY,
- SETTINGS_CATEGORY,
- HELP_CATEGORY,
-];
-
export const FETCH_TYPES = ['generic', 'search'];
export const SEARCH_INPUT_FIELD_MAX_WIDTH = '640px';
diff --git a/app/assets/javascripts/header_search/store/getters.js b/app/assets/javascripts/header_search/store/getters.js
index 3da9d2cd961..f86463b94d1 100644
--- a/app/assets/javascripts/header_search/store/getters.js
+++ b/app/assets/javascripts/header_search/store/getters.js
@@ -7,14 +7,16 @@ import {
MSG_MR_ASSIGNED_TO_ME,
MSG_MR_IM_REVIEWER,
MSG_MR_IVE_CREATED,
- ICON_GROUP,
- ICON_SUBGROUP,
- ICON_PROJECT,
MSG_IN_ALL_GITLAB,
PROJECTS_CATEGORY,
GROUPS_CATEGORY,
- SEARCH_SHORTCUTS_MIN_CHARACTERS,
DROPDOWN_ORDER,
+} from '~/vue_shared/global_search/constants';
+import {
+ ICON_GROUP,
+ ICON_SUBGROUP,
+ ICON_PROJECT,
+ SEARCH_SHORTCUTS_MIN_CHARACTERS,
} from '../constants';
export const searchQuery = (state) => {
@@ -36,6 +38,10 @@ export const searchQuery = (state) => {
};
export const scopedIssuesPath = (state) => {
+ if (state.searchContext?.project?.id && !state.searchContext?.project_metadata?.issues_path) {
+ return false;
+ }
+
return (
state.searchContext?.project_metadata?.issues_path ||
state.searchContext?.group_metadata?.issues_path ||
@@ -54,7 +60,7 @@ export const scopedMRPath = (state) => {
export const defaultSearchOptions = (state, getters) => {
const userName = gon.current_username;
- return [
+ const issues = [
{
html_id: 'default-issues-assigned',
title: MSG_ISSUES_ASSIGNED_TO_ME,
@@ -65,6 +71,9 @@ export const defaultSearchOptions = (state, getters) => {
title: MSG_ISSUES_IVE_CREATED,
url: `${getters.scopedIssuesPath}/?author_username=${userName}`,
},
+ ];
+
+ const mergeRequests = [
{
html_id: 'default-mrs-assigned',
title: MSG_MR_ASSIGNED_TO_ME,
@@ -81,6 +90,7 @@ export const defaultSearchOptions = (state, getters) => {
url: `${getters.scopedMRPath}/?author_username=${userName}`,
},
];
+ return [...(getters.scopedIssuesPath ? issues : []), ...mergeRequests];
};
export const projectUrl = (state) => {
diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue
index 838debf1ceb..6bbad88715f 100644
--- a/app/assets/javascripts/ide/components/ide.vue
+++ b/app/assets/javascripts/ide/components/ide.vue
@@ -82,7 +82,7 @@ export default {
eventHub.$on('skip-beforeunload', this.handleSkipBeforeUnload);
if (this.themeName)
- document.querySelector('.navbar-gitlab').classList.add(`theme-${this.themeName}`);
+ document.querySelector('.navbar-gitlab')?.classList.add(`theme-${this.themeName}`);
},
destroyed() {
eventHub.$off('skip-beforeunload', this.handleSkipBeforeUnload);
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
index dbfaeba9708..4d728bd35d4 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
@@ -1,7 +1,7 @@
<script>
import { GlModal, GlButton } from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, sprintf } from '~/locale';
import { modalTypes } from '../../constants';
import { trimPathComponents, getPathParent } from '../../utils';
@@ -50,13 +50,13 @@ export default {
actionPrimary() {
return {
text: this.buttonLabel,
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
};
},
actionCancel() {
return {
text: i18n.cancelButtonText,
- attributes: [{ variant: 'default' }],
+ attributes: { variant: 'default' },
};
},
isCreatingNewFile() {
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index b95f8bb5acb..9e29cd94a20 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -12,7 +12,7 @@ import {
import { SourceEditorExtension } from '~/editor/extensions/source_editor_extension_base';
import { EditorWebIdeExtension } from '~/editor/extensions/source_editor_webide_ext';
import SourceEditor from '~/editor/source_editor';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import ModelManager from '~/ide/lib/common/model_manager';
import { defaultDiffEditorOptions, defaultEditorOptions } from '~/ide/lib/editor_options';
import { __ } from '~/locale';
@@ -27,6 +27,8 @@ import { performanceMarkAndMeasure } from '~/performance/utils';
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
+import { markRaw } from '~/lib/utils/vue3compat/mark_raw';
+
import {
leftSidebarViews,
viewerTypes,
@@ -66,7 +68,7 @@ export default {
images: {},
rules: {},
globalEditor: null,
- modelManager: new ModelManager(),
+ modelManager: markRaw(new ModelManager()),
isEditorLoading: true,
unwatchCiYaml: null,
SELivepreviewExtension: null,
@@ -212,7 +214,7 @@ export default {
},
mounted() {
if (!this.globalEditor) {
- this.globalEditor = new SourceEditor();
+ this.globalEditor = markRaw(new SourceEditor());
}
this.initEditor();
@@ -284,14 +286,16 @@ export default {
const instanceOptions = isDiff ? defaultDiffEditorOptions : defaultEditorOptions;
const method = isDiff ? EDITOR_DIFF_INSTANCE_FN : EDITOR_CODE_INSTANCE_FN;
- this.editor = this.globalEditor[method]({
- el: this.$refs.editor,
- blobPath: this.file.path,
- blobGlobalId: this.file.key,
- blobContent: this.content || this.file.content,
- ...instanceOptions,
- ...this.editorOptions,
- });
+ this.editor = markRaw(
+ this.globalEditor[method]({
+ el: this.$refs.editor,
+ blobPath: this.file.path,
+ blobGlobalId: this.file.key,
+ blobContent: this.content || this.file.content,
+ ...instanceOptions,
+ ...this.editorOptions,
+ }),
+ );
this.editor.use([
{
definition: SourceEditorExtension,
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index 29c44d2f596..967c83b320f 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -72,6 +72,7 @@ export const initLegacyWebIDE = (el, options = {}) => {
environmentsGuidanceAlertDismissed: !parseBoolean(el.dataset.enableEnvironmentsGuidance),
previewMarkdownPath: el.dataset.previewMarkdownPath,
userPreferencesPath: el.dataset.userPreferencesPath,
+ learnGitlabSource: parseBoolean(el.dataset.learnGitlabSource),
});
},
beforeDestroy() {
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index b7445d3ad0a..0106eeae162 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -1,6 +1,6 @@
import { escape } from 'lodash';
import Vue from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js
index cd8088bf667..9f1eae03685 100644
--- a/app/assets/javascripts/ide/stores/actions/merge_request.js
+++ b/app/assets/javascripts/ide/stores/actions/merge_request.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import { leftSidebarViews, PERMISSION_READ_MR, MAX_MR_FILES_AUTO_OPEN } from '../../constants';
import service from '../../services';
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index 7a6a267e7d0..f4fa52b2d4d 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -1,5 +1,5 @@
import { escape } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, sprintf } from '~/locale';
import { logError } from '~/lib/logger';
import api from '~/api';
diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js
index d490b8c5dad..572465f7587 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js
@@ -1,6 +1,7 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { addNumericSuffix } from '~/ide/utils';
import { sprintf, __ } from '~/locale';
+import Tracking from '~/tracking';
import { leftSidebarViews } from '../../../constants';
import eventHub from '../../../eventhub';
import { parseCommitError } from '../../../lib/errors';
@@ -162,6 +163,10 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
);
}
+ if (rootState.learnGitlabSource) {
+ Tracking.event(undefined, 'commit', { label: 'web_ide_learn_gitlab_source' });
+ }
+
dispatch('setLastCommitMessage', data);
dispatch('updateCommitMessage', '');
return dispatch('updateFilesAfterCommit', {
diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js b/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js
index a7085c7d04c..b5bb2c7bdf8 100644
--- a/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js
+++ b/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js
@@ -2,9 +2,3 @@ export const scopes = {
assigned: 'assigned-to-me',
created: 'created-by-me',
};
-
-export const states = {
- opened: 'opened',
- closed: 'closed',
- merged: 'merged',
-};
diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/state.js b/app/assets/javascripts/ide/stores/modules/merge_requests/state.js
index 4748ccfa2e6..0a2f778c715 100644
--- a/app/assets/javascripts/ide/stores/modules/merge_requests/state.js
+++ b/app/assets/javascripts/ide/stores/modules/merge_requests/state.js
@@ -1,7 +1,7 @@
-import { states } from './constants';
+import { STATUS_OPEN } from '~/issues/constants';
export default () => ({
isLoading: false,
mergeRequests: [],
- state: states.opened,
+ state: STATUS_OPEN,
});
diff --git a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js
index 874cc5094d3..411ff0beaba 100644
--- a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js
+++ b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_UNPROCESSABLE_ENTITY } from '~/lib/utils/http_status';
import * as terminalService from '../../../../services/terminals';
diff --git a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js
index 4aa0768d394..463634c946d 100644
--- a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js
+++ b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import * as messages from '../messages';
import * as types from '../mutation_types';
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 356bbf28a48..013a0c3ce8f 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -32,4 +32,5 @@ export default () => ({
environmentsGuidanceAlertDetected: false,
previewMarkdownPath: '',
userPreferencesPath: '',
+ learnGitlabSource: false,
});
diff --git a/app/assets/javascripts/import_entities/components/group_dropdown.vue b/app/assets/javascripts/import_entities/components/group_dropdown.vue
index f351a9a392f..5b9e80f9d68 100644
--- a/app/assets/javascripts/import_entities/components/group_dropdown.vue
+++ b/app/assets/javascripts/import_entities/components/group_dropdown.vue
@@ -3,7 +3,7 @@ import { GlDropdown, GlSearchBoxByType } from '@gitlab/ui';
import { debounce } from 'lodash';
import { s__ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import searchNamespacesWhereUserCanCreateProjectsQuery from '~/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql';
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants';
diff --git a/app/assets/javascripts/import_entities/components/import_status.vue b/app/assets/javascripts/import_entities/components/import_status.vue
index 6dc0b2cec24..ec2ab9d0c3d 100644
--- a/app/assets/javascripts/import_entities/components/import_status.vue
+++ b/app/assets/javascripts/import_entities/components/import_status.vue
@@ -7,21 +7,22 @@ import { STATUSES } from '../constants';
const STATISTIC_ITEMS = {
diff_note: __('Diff notes'),
issue: __('Issues'),
- issue_attachment: s__('GithubImporter|Issue attachments'),
+ issue_attachment: s__('GithubImporter|Issue links'),
issue_event: __('Issue events'),
label: __('Labels'),
lfs_object: __('LFS objects'),
- merge_request_attachment: s__('GithubImporter|Merge request attachments'),
+ merge_request_attachment: s__('GithubImporter|Merge request links'),
milestone: __('Milestones'),
note: __('Notes'),
- note_attachment: s__('GithubImporter|Note attachments'),
+ note_attachment: s__('GithubImporter|Note links'),
protected_branch: __('Protected branches'),
+ collaborator: s__('GithubImporter|Collaborators'),
pull_request: s__('GithubImporter|Pull requests'),
pull_request_merged_by: s__('GithubImporter|PR mergers'),
pull_request_review: s__('GithubImporter|PR reviews'),
pull_request_review_request: s__('GithubImporter|PR reviews'),
release: __('Releases'),
- release_attachment: s__('GithubImporter|Release attachments'),
+ release_attachment: s__('GithubImporter|Release links'),
};
// support both camel case and snake case versions
diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue b/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue
index ed7c9e7abe9..d91f314a86c 100644
--- a/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue
+++ b/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue
@@ -1,16 +1,9 @@
<script>
-import {
- GlButton,
- GlDropdown,
- GlDropdownItem,
- GlIcon,
- GlTooltipDirective as GlTooltip,
-} from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem, GlIcon, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
export default {
components: {
GlIcon,
- GlButton,
GlDropdown,
GlDropdownItem,
},
@@ -18,10 +11,6 @@ export default {
GlTooltip,
},
props: {
- isProjectsImportEnabled: {
- type: Boolean,
- required: true,
- },
isFinished: {
type: Boolean,
required: true,
@@ -46,7 +35,7 @@ export default {
<template>
<span class="gl-white-space-nowrap gl-inline-flex gl-align-items-center">
<gl-dropdown
- v-if="isProjectsImportEnabled && (isAvailableForImport || isFinished)"
+ v-if="isAvailableForImport || isFinished"
:text="isFinished ? __('Re-import with projects') : __('Import with projects')"
:disabled="isInvalid"
variant="confirm"
@@ -59,16 +48,6 @@ export default {
isFinished ? __('Re-import without projects') : __('Import without projects')
}}</gl-dropdown-item>
</gl-dropdown>
- <gl-button
- v-else-if="isAvailableForImport || isFinished"
- :disabled="isInvalid"
- variant="confirm"
- category="secondary"
- data-qa-selector="import_group_button"
- @click="$emit('import-group')"
- >
- {{ isFinished ? __('Re-import') : __('Import') }}
- </gl-button>
<gl-icon
v-if="isFinished"
v-gl-tooltip
diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
index 7d2ddd2176b..2e6e7cddf8f 100644
--- a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
+++ b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
@@ -1,7 +1,6 @@
<script>
import {
GlAlert,
- GlButton,
GlDropdown,
GlDropdownItem,
GlEmptyState,
@@ -15,7 +14,7 @@ import {
GlTooltipDirective,
} from '@gitlab/ui';
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__, __, n__, sprintf } from '~/locale';
import { HTTP_STATUS_TOO_MANY_REQUESTS } from '~/lib/utils/http_status';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -50,7 +49,6 @@ const DEFAULT_TD_CLASSES = 'gl-vertical-align-top!';
export default {
components: {
GlAlert,
- GlButton,
GlDropdown,
GlDropdownItem,
GlEmptyState,
@@ -106,7 +104,7 @@ export default {
reimportRequests: [],
importTargets: {},
unavailableFeaturesAlertVisible: true,
- helpUrl: helpPagePath('ee/user/group/import', {
+ helpUrl: helpPagePath('user/group/import/index', {
anchor: 'visibility-rules',
}),
};
@@ -165,10 +163,6 @@ export default {
],
computed: {
- isProjectsImportEnabled() {
- return Boolean(this.glFeatures.bulkImportProjects);
- },
-
groups() {
return this.bulkImportSourceGroups?.nodes ?? [];
},
@@ -707,11 +701,11 @@ export default {
</gl-sprintf>
</span>
<gl-dropdown
- v-if="isProjectsImportEnabled"
:text="s__('BulkImport|Import with projects')"
:disabled="!hasSelectedGroups"
variant="confirm"
category="primary"
+ data-testid="import-selected-groups-dropdown"
class="gl-ml-4"
split
@click="importSelectedGroups({ migrateProjects: true })"
@@ -720,15 +714,6 @@ export default {
{{ s__('BulkImport|Import without projects') }}
</gl-dropdown-item>
</gl-dropdown>
- <gl-button
- v-else
- category="primary"
- variant="confirm"
- class="gl-ml-4"
- :disabled="!hasSelectedGroups"
- @click="importSelectedGroups"
- >{{ s__('BulkImport|Import selected') }}</gl-button
- >
<span class="gl-ml-3">
<gl-icon name="information-o" :size="12" class="gl-text-blue-600" />
<gl-sprintf
@@ -804,7 +789,6 @@ export default {
</template>
<template #cell(actions)="{ item: group, index }">
<import-actions-cell
- :is-projects-import-enabled="isProjectsImportEnabled"
:is-finished="group.flags.isFinished"
:is-available-for-import="group.flags.isAvailableForImport"
:is-invalid="group.flags.isInvalid"
diff --git a/app/assets/javascripts/import_entities/import_groups/index.js b/app/assets/javascripts/import_entities/import_groups/index.js
index 494a845b1f9..8efc6484794 100644
--- a/app/assets/javascripts/import_entities/import_groups/index.js
+++ b/app/assets/javascripts/import_entities/import_groups/index.js
@@ -31,6 +31,7 @@ export function mountImportGroupsApp(mountElement) {
return new Vue({
el: mountElement,
+ name: 'ImportGroupsRoot',
apolloProvider,
render(createElement) {
return createElement(ImportTable, {
diff --git a/app/assets/javascripts/import_entities/import_groups/services/status_poller.js b/app/assets/javascripts/import_entities/import_groups/services/status_poller.js
index 6ad5e448a40..10496fce11b 100644
--- a/app/assets/javascripts/import_entities/import_groups/services/status_poller.js
+++ b/app/assets/javascripts/import_entities/import_groups/services/status_poller.js
@@ -1,5 +1,5 @@
import Visibility from 'visibilityjs';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import Poll from '~/lib/utils/poll';
import { s__ } from '~/locale';
diff --git a/app/assets/javascripts/import_entities/import_projects/index.js b/app/assets/javascripts/import_entities/import_projects/index.js
index 485511510f7..66ffd378426 100644
--- a/app/assets/javascripts/import_entities/import_projects/index.js
+++ b/app/assets/javascripts/import_entities/import_projects/index.js
@@ -69,10 +69,13 @@ export default function mountImportProjectsTable({
return new Vue({
el: mountElement,
+ name: 'ImportProjectsRoot',
store,
apolloProvider,
render(createElement) {
- return createElement(Component, { props: { ...props, ...extraProps(mountElement.dataset) } });
+ // We are using attrs instead of props so root-level component with inheritAttrs
+ // will be able to pass them down
+ return createElement(Component, { attrs: { ...props, ...extraProps(mountElement.dataset) } });
},
});
}
diff --git a/app/assets/javascripts/import_entities/import_projects/store/actions.js b/app/assets/javascripts/import_entities/import_projects/store/actions.js
index e0db585eb3e..e3c32028b13 100644
--- a/app/assets/javascripts/import_entities/import_projects/store/actions.js
+++ b/app/assets/javascripts/import_entities/import_projects/store/actions.js
@@ -1,6 +1,6 @@
import Visibility from 'visibilityjs';
import _ from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { HTTP_STATUS_TOO_MANY_REQUESTS } from '~/lib/utils/http_status';
@@ -141,7 +141,7 @@ const fetchImportFactory = (importPath = isRequired()) => (
})
.catch((e) => {
const serverErrorMessage = e?.response?.data?.errors;
- const flashMessage = serverErrorMessage
+ const alertMessage = serverErrorMessage
? sprintf(
s__('ImportProjects|Importing the project failed: %{reason}'),
{
@@ -152,7 +152,7 @@ const fetchImportFactory = (importPath = isRequired()) => (
: s__('ImportProjects|Importing the project failed');
createAlert({
- message: flashMessage,
+ message: alertMessage,
});
commit(types.RECEIVE_IMPORT_ERROR, repoId);
@@ -179,7 +179,7 @@ export const cancelImportFactory = (cancelImportPath) => ({ state, commit }, { r
})
.catch((e) => {
const serverErrorMessage = e?.response?.data?.errors;
- const flashMessage = serverErrorMessage
+ const alertMessage = serverErrorMessage
? sprintf(
s__('ImportProjects|Cancelling project import failed: %{reason}'),
{
@@ -190,7 +190,7 @@ export const cancelImportFactory = (cancelImportPath) => ({ state, commit }, { r
: s__('ImportProjects|Cancelling project import failed');
createAlert({
- message: flashMessage,
+ message: alertMessage,
});
});
};
diff --git a/app/assets/javascripts/incidents/constants.js b/app/assets/javascripts/incidents/constants.js
index ee3f30de880..dde40ec2983 100644
--- a/app/assets/javascripts/incidents/constants.js
+++ b/app/assets/javascripts/incidents/constants.js
@@ -44,7 +44,6 @@ export const ESCALATION_STATUSES = {
RESOLVED: s__('AlertManagement|Resolved'),
};
-export const DEFAULT_PAGE_SIZE = 20;
export const TH_CREATED_AT_TEST_ID = { 'data-testid': 'incident-management-created-at-sort' };
export const TH_SEVERITY_TEST_ID = { 'data-testid': 'incident-management-severity-sort' };
export const TH_ESCALATION_STATUS_TEST_ID = { 'data-testid': 'incident-management-status-sort' };
diff --git a/app/assets/javascripts/incidents_settings/incidents_settings_service.js b/app/assets/javascripts/incidents_settings/incidents_settings_service.js
index d3850114350..195544c746e 100644
--- a/app/assets/javascripts/incidents_settings/incidents_settings_service.js
+++ b/app/assets/javascripts/incidents_settings/incidents_settings_service.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { ERROR_MSG } from './constants';
diff --git a/app/assets/javascripts/init_deprecated_notes.js b/app/assets/javascripts/init_deprecated_notes.js
index 5f918b0d2f5..8657a1dcb67 100644
--- a/app/assets/javascripts/init_deprecated_notes.js
+++ b/app/assets/javascripts/init_deprecated_notes.js
@@ -2,9 +2,9 @@ import Notes from './deprecated_notes';
export default () => {
const dataEl = document.querySelector('.js-notes-data');
- const { notesUrl, notesIds, now, diffView, enableGFM } = JSON.parse(dataEl.innerHTML);
+ const { notesUrl, now, diffView, enableGFM } = JSON.parse(dataEl.innerHTML);
// Create a singleton so that we don't need to assign
// into the window object, we can just access the current isntance with Notes.instance
- Notes.initialize(notesUrl, notesIds, now, diffView, enableGFM);
+ Notes.initialize(notesUrl, now, diffView, enableGFM);
};
diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js
index 5d08520bb5c..6b5a828c009 100644
--- a/app/assets/javascripts/integrations/constants.js
+++ b/app/assets/javascripts/integrations/constants.js
@@ -32,6 +32,8 @@ export const integrationFormSections = {
JIRA_TRIGGER: 'jira_trigger',
JIRA_ISSUES: 'jira_issues',
TRIGGER: 'trigger',
+ APPLE_APP_STORE: 'apple_app_store',
+ GOOGLE_PLAY: 'google_play',
};
export const integrationFormSectionComponents = {
@@ -40,6 +42,8 @@ export const integrationFormSectionComponents = {
[integrationFormSections.JIRA_TRIGGER]: 'IntegrationSectionJiraTrigger',
[integrationFormSections.JIRA_ISSUES]: 'IntegrationSectionJiraIssues',
[integrationFormSections.TRIGGER]: 'IntegrationSectionTrigger',
+ [integrationFormSections.APPLE_APP_STORE]: 'IntegrationSectionAppleAppStore',
+ [integrationFormSections.GOOGLE_PLAY]: 'IntegrationSectionGooglePlay',
};
export const integrationTriggerEvents = {
@@ -90,7 +94,7 @@ export const billingPlanNames = {
[billingPlans.ULTIMATE]: s__('BillingPlans|Ultimate'),
};
-export const INTEGRATION_TYPE_SLACK = 'slack';
+const INTEGRATION_TYPE_SLACK = 'slack';
const INTEGRATION_TYPE_SLACK_APPLICATION = 'gitlab_slack_application';
const INTEGRATION_TYPE_MATTERMOST = 'mattermost';
diff --git a/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue b/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue
index bc6aa231a93..024f562b71d 100644
--- a/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue
+++ b/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue
@@ -11,7 +11,7 @@ export default {
primaryProps() {
return {
text: __('Save'),
- attributes: [{ variant: 'confirm' }, { category: 'primary' }],
+ attributes: { variant: 'confirm', category: 'primary' },
};
},
cancelProps() {
diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue
index d671ec33bcb..f119668048d 100644
--- a/app/assets/javascripts/integrations/edit/components/integration_form.vue
+++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue
@@ -59,9 +59,6 @@ export default {
return this.propsSource.editable;
},
hasSections() {
- if (this.hasSlackNotificationsDisabled) {
- return false;
- }
return this.customState.sections.length !== 0;
},
fieldsWithoutSection() {
@@ -70,17 +67,11 @@ export default {
: this.propsSource.fields;
},
hasFieldsWithoutSection() {
- if (this.hasSlackNotificationsDisabled) {
- return false;
- }
return this.fieldsWithoutSection.length;
},
isSlackIntegration() {
return this.propsSource.type === INTEGRATION_FORM_TYPE_SLACK;
},
- hasSlackNotificationsDisabled() {
- return this.isSlackIntegration && !this.glFeatures.integrationSlackAppNotifications;
- },
showHelpHtml() {
if (this.isSlackIntegration) {
return this.helpHtml;
@@ -90,7 +81,6 @@ export default {
shouldUpgradeSlack() {
return (
this.isSlackIntegration &&
- this.glFeatures.integrationSlackAppNotifications &&
this.customState.shouldUpgradeSlack &&
(this.hasFieldsWithoutSection || this.hasSections)
);
diff --git a/app/assets/javascripts/integrations/edit/components/integration_forms/section.vue b/app/assets/javascripts/integrations/edit/components/integration_forms/section.vue
index ce39954735a..5335b7b6ee2 100644
--- a/app/assets/javascripts/integrations/edit/components/integration_forms/section.vue
+++ b/app/assets/javascripts/integrations/edit/components/integration_forms/section.vue
@@ -28,6 +28,14 @@ export default {
import(
/* webpackChunkName: 'integrationSectionTrigger' */ '~/integrations/edit/components/sections/trigger.vue'
),
+ IntegrationSectionAppleAppStore: () =>
+ import(
+ /* webpackChunkName: 'IntegrationSectionAppleAppStore' */ '~/integrations/edit/components/sections/apple_app_store.vue'
+ ),
+ IntegrationSectionGooglePlay: () =>
+ import(
+ /* webpackChunkName: 'IntegrationSectionGooglePlay' */ '~/integrations/edit/components/sections/google_play.vue'
+ ),
},
directives: {
SafeHtml,
diff --git a/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue b/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue
index 41cd650f932..e766064a69b 100644
--- a/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue
+++ b/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue
@@ -9,7 +9,7 @@ export default {
},
primaryProps: {
text: __('Reset'),
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
},
cancelProps: {
text: __('Cancel'),
diff --git a/app/assets/javascripts/integrations/edit/components/sections/apple_app_store.vue b/app/assets/javascripts/integrations/edit/components/sections/apple_app_store.vue
new file mode 100644
index 00000000000..775600a9a62
--- /dev/null
+++ b/app/assets/javascripts/integrations/edit/components/sections/apple_app_store.vue
@@ -0,0 +1,73 @@
+<script>
+import { mapGetters } from 'vuex';
+import { sprintf, s__ } from '~/locale';
+import UploadDropzoneField from '../upload_dropzone_field.vue';
+import Connection from './connection.vue';
+
+export default {
+ name: 'IntegrationSectionAppleAppStore',
+ components: {
+ Connection,
+ UploadDropzoneField,
+ },
+ data() {
+ return {
+ dropzoneAllowList: ['.p8'],
+ };
+ },
+ i18n: {
+ dropzoneDescription: s__(
+ 'AppleAppStore|Drag your Private Key file here or %{linkStart}click to upload%{linkEnd}.',
+ ),
+ dropzoneErrorMessage: s__(
+ 'AppleAppStore|Error: You are trying to upload something other than a Private Key file.',
+ ),
+ dropzoneConfirmMessage: s__('AppleAppStore|Drop your Private Key file to start the upload.'),
+ dropzoneEmptyInputName: s__('AppleAppStore|The Apple App Store Connect Private Key (.p8)'),
+ dropzoneNonEmptyInputName: s__(
+ 'AppleAppStore|Upload a new Apple App Store Connect Private Key (replace %{currentFileName})',
+ ),
+ dropzoneNonEmptyInputHelp: s__('AppleAppStore|Leave empty to use your current Private Key.'),
+ },
+ computed: {
+ ...mapGetters(['propsSource']),
+ dynamicFields() {
+ return this.propsSource.fields.filter(
+ (field) => field.name !== 'app_store_private_key_file_name',
+ );
+ },
+ fileNameField() {
+ return this.propsSource.fields.find(
+ (field) => field.name === 'app_store_private_key_file_name',
+ );
+ },
+ dropzoneLabel() {
+ return this.fileNameField.value
+ ? sprintf(this.$options.i18n.dropzoneNonEmptyInputName, {
+ currentFileName: this.fileNameField.value,
+ })
+ : this.$options.i18n.dropzoneEmptyInputName;
+ },
+ dropzoneHelpText() {
+ return this.fileNameField.value ? this.$options.i18n.dropzoneNonEmptyInputHelp : '';
+ },
+ },
+};
+</script>
+
+<template>
+ <span>
+ <connection :fields="dynamicFields" />
+
+ <upload-dropzone-field
+ name="service[app_store_private_key]"
+ :label="dropzoneLabel"
+ :help-text="dropzoneHelpText"
+ file-input-name="service[app_store_private_key_file_name]"
+ :allow-list="dropzoneAllowList"
+ :description="$options.i18n.dropzoneDescription"
+ :error-message="$options.i18n.dropzoneErrorMessage"
+ :confirm-message="$options.i18n.dropzoneConfirmMessage"
+ />
+ </span>
+</template>
diff --git a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue
new file mode 100644
index 00000000000..3094e24241a
--- /dev/null
+++ b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue
@@ -0,0 +1,75 @@
+<script>
+import { mapGetters } from 'vuex';
+import { sprintf, s__ } from '~/locale';
+import UploadDropzoneField from '../upload_dropzone_field.vue';
+import Connection from './connection.vue';
+
+export default {
+ name: 'IntegrationSectionGooglePlay',
+ components: {
+ Connection,
+ UploadDropzoneField,
+ },
+ data() {
+ return {
+ dropzoneAllowList: ['.json'],
+ };
+ },
+ i18n: {
+ dropzoneDescription: s__(
+ 'GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}.',
+ ),
+ dropzoneErrorMessage: s__(
+ "GooglePlay|Error: The file you're trying to upload is not a service account key.",
+ ),
+ dropzoneConfirmMessage: s__('GooglePlay|Drag your key file to start the upload.'),
+ dropzoneEmptyInputName: s__('GooglePlay|Service account key (.json)'),
+ dropzoneNonEmptyInputName: s__(
+ 'GooglePlay|Upload a new service account key (replace %{currentFileName})',
+ ),
+ dropzoneNoneEmpyInputHelp: s__(
+ 'GooglePlay|Leave empty to use your current service account key.',
+ ),
+ },
+ computed: {
+ ...mapGetters(['propsSource']),
+ dynamicFields() {
+ return this.propsSource.fields.filter(
+ (field) => field.name !== 'service_account_key_file_name',
+ );
+ },
+ fileNameField() {
+ return this.propsSource.fields.find(
+ (field) => field.name === 'service_account_key_file_name',
+ );
+ },
+ dropzoneLabel() {
+ return this.fileNameField.value
+ ? sprintf(this.$options.i18n.dropzoneNonEmptyInputName, {
+ currentFileName: this.fileNameField.value,
+ })
+ : this.$options.i18n.dropzoneEmptyInputName;
+ },
+ dropzoneHelpText() {
+ return this.fileNameField.value ? this.$options.i18n.dropzoneNoneEmpyInputHelp : '';
+ },
+ },
+};
+</script>
+
+<template>
+ <span>
+ <connection :fields="dynamicFields" />
+
+ <upload-dropzone-field
+ name="service[service_account_key]"
+ :label="dropzoneLabel"
+ :help-text="dropzoneHelpText"
+ file-input-name="service[service_account_key_file_name]"
+ :allow-list="dropzoneAllowList"
+ :description="$options.i18n.dropzoneDescription"
+ :error-message="$options.i18n.dropzoneErrorMessage"
+ :confirm-message="$options.i18n.dropzoneConfirmMessage"
+ />
+ </span>
+</template>
diff --git a/app/assets/javascripts/integrations/edit/components/upload_dropzone_field.vue b/app/assets/javascripts/integrations/edit/components/upload_dropzone_field.vue
new file mode 100644
index 00000000000..fbed2547c05
--- /dev/null
+++ b/app/assets/javascripts/integrations/edit/components/upload_dropzone_field.vue
@@ -0,0 +1,143 @@
+<script>
+import { GlLink, GlSprintf, GlAlert, GlFormGroup } from '@gitlab/ui';
+import { validateFileFromAllowList } from '~/lib/utils/file_upload';
+import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
+import { s__ } from '~/locale';
+
+const i18n = Object.freeze({
+ description: s__('Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}.'),
+ errorMessage: s__(
+ 'Integrations|Error: You are trying to upload something other than an allowed file.',
+ ),
+ confirmMessage: s__('Integrations|Drop your file to start the upload.'),
+});
+
+export default {
+ name: 'UploadDropzoneField',
+ components: {
+ UploadDropzone,
+ GlLink,
+ GlSprintf,
+ GlAlert,
+ GlFormGroup,
+ },
+ i18n,
+ props: {
+ name: {
+ type: String,
+ required: true,
+ default: null,
+ },
+ label: {
+ type: String,
+ required: true,
+ default: null,
+ },
+ helpText: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ fileInputName: {
+ type: String,
+ required: true,
+ default: null,
+ },
+ allowList: {
+ type: Array,
+ required: false,
+ default: null,
+ },
+ description: {
+ type: String,
+ required: false,
+ default: i18n.description,
+ },
+ errorMessage: {
+ type: String,
+ required: false,
+ default: i18n.errorMessage,
+ },
+ confirmMessage: {
+ type: String,
+ required: false,
+ default: i18n.confirmMessage,
+ },
+ },
+ data() {
+ return {
+ fileName: null,
+ fileContents: null,
+ uploadError: false,
+ inputDisabled: true,
+ };
+ },
+ computed: {
+ dropzoneDescription() {
+ return this.fileName ?? this.description;
+ },
+ },
+ methods: {
+ clearError() {
+ this.uploadError = false;
+ },
+ onChange(file) {
+ this.clearError();
+ this.inputDisabled = false;
+ this.fileName = file?.name;
+ this.readFile(file);
+ },
+ isValidFileType(file) {
+ return validateFileFromAllowList(file.name, this.allowList);
+ },
+ onError() {
+ this.uploadError = this.errorMessage;
+ },
+ readFile(file) {
+ const reader = new FileReader();
+ reader.readAsText(file);
+ reader.onload = (evt) => {
+ this.fileContents = evt.target.result;
+ };
+ },
+ },
+};
+</script>
+<template>
+ <gl-form-group :label="label" :label-for="name">
+ <upload-dropzone
+ input-field-name="service[dropzone_file_name]"
+ :is-file-valid="isValidFileType"
+ :valid-file-mimetypes="allowList"
+ :should-update-input-on-file-drop="true"
+ :single-file-selection="true"
+ :enable-drag-behavior="false"
+ :drop-to-start-message="confirmMessage"
+ @change="onChange"
+ @error="onError"
+ >
+ <template #upload-text="{ openFileUpload }">
+ <gl-sprintf :message="dropzoneDescription">
+ <template #link="{ content }">
+ <gl-link @click.stop="openFileUpload">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
+
+ <template #invalid-drag-data-slot>
+ {{ errorMessage }}
+ </template>
+ </upload-dropzone>
+ <gl-alert v-if="uploadError" variant="danger" :dismissible="true" @dismiss="clearError">
+ {{ uploadError }}
+ </gl-alert>
+ <input :name="name" type="hidden" :disabled="inputDisabled" :value="fileContents || false" />
+ <input
+ :name="fileInputName"
+ type="hidden"
+ :disabled="inputDisabled"
+ :value="fileName || false"
+ />
+ <span>{{ helpText }}</span>
+ </gl-form-group>
+</template>
diff --git a/app/assets/javascripts/integrations/index/components/integrations_table.vue b/app/assets/javascripts/integrations/index/components/integrations_table.vue
index 62f0fe4d6bf..439c243f418 100644
--- a/app/assets/javascripts/integrations/index/components/integrations_table.vue
+++ b/app/assets/javascripts/integrations/index/components/integrations_table.vue
@@ -1,9 +1,7 @@
<script>
import { GlIcon, GlLink, GlTable, GlTooltipDirective } from '@gitlab/ui';
-import { INTEGRATION_TYPE_SLACK } from '~/integrations/constants';
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: {
@@ -15,7 +13,6 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [glFeatureFlagsMixin()],
props: {
integrations: {
type: Array,
@@ -58,15 +55,6 @@ export default {
},
];
},
- filteredIntegrations() {
- if (this.glFeatures.integrationSlackAppNotifications) {
- return this.integrations.filter(
- (integration) =>
- !(integration.name === INTEGRATION_TYPE_SLACK && integration.active === false),
- );
- }
- return this.integrations;
- },
},
methods: {
getStatusTooltipTitle(integration) {
@@ -79,7 +67,7 @@ export default {
</script>
<template>
- <gl-table :items="filteredIntegrations" :fields="fields" :empty-text="emptyText" show-empty fixed>
+ <gl-table :items="integrations" :fields="fields" :empty-text="emptyText" show-empty fixed>
<template #cell(active)="{ item }">
<gl-icon
v-if="item.active"
diff --git a/app/assets/javascripts/invite_members/components/group_select.vue b/app/assets/javascripts/invite_members/components/group_select.vue
index e7f5211dc25..0e9781d77fe 100644
--- a/app/assets/javascripts/invite_members/components/group_select.vue
+++ b/app/assets/javascripts/invite_members/components/group_select.vue
@@ -114,6 +114,7 @@ export default {
defaultFetchOptions: {
exclude_internal: true,
active: true,
+ order_by: 'similarity',
},
};
</script>
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 607c888b85a..812e39e6392 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
@@ -51,6 +51,8 @@ export default {
MembersTokenSelect,
ModalConfetti,
UserLimitNotification,
+ ActiveTrialNotification: () =>
+ import('ee_component/invite_members/components/active_trial_notification.vue'),
},
mixins: [Tracking.mixin({ category: INVITE_MEMBER_MODAL_TRACKING_CATEGORY })],
inject: ['newProjectPath'],
@@ -421,7 +423,6 @@ export default {
:new-users-to-invite="newUsersToInvite"
:root-group-id="rootId"
:users-limit-dataset="usersLimitDataset"
- :active-trial-dataset="activeTrialDataset"
:full-path="fullPath"
@close="onClose"
@cancel="onCancel"
@@ -504,6 +505,10 @@ export default {
</div>
</template>
+ <template #active-trial-alert>
+ <active-trial-notification v-if="!isCelebration" :active-trial-dataset="activeTrialDataset" />
+ </template>
+
<template #select="{ exceptionState, inputId }">
<members-token-select
v-model="newUsersToInvite"
diff --git a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
index 42645110e48..6d1a3ceba16 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
@@ -1,15 +1,16 @@
<script>
-import { GlButton, GlLink, GlIcon } from '@gitlab/ui';
+import { GlButton, GlLink, GlDropdownItem } from '@gitlab/ui';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
import {
TRIGGER_ELEMENT_BUTTON,
- TRIGGER_ELEMENT_SIDE_NAV,
TRIGGER_DEFAULT_QA_SELECTOR,
+ TRIGGER_ELEMENT_WITH_EMOJI,
+ TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
} from '../constants';
export default {
- components: { GlButton, GlLink, GlIcon },
+ components: { GlButton, GlLink, GlDropdownItem },
props: {
displayText: {
type: String,
@@ -40,16 +41,6 @@ export default {
required: false,
default: 'button',
},
- event: {
- type: String,
- required: false,
- default: '',
- },
- label: {
- type: String,
- required: false,
- default: '',
- },
qaSelector: {
type: String,
required: false,
@@ -58,21 +49,11 @@ export default {
},
computed: {
componentAttributes() {
- const baseAttributes = {
+ return {
class: this.classes,
'data-qa-selector': this.qaSelector,
'data-test-id': 'invite-members-button',
};
-
- if (this.event && this.label) {
- return {
- ...baseAttributes,
- 'data-track-action': this.event,
- 'data-track-label': this.label,
- };
- }
-
- return baseAttributes;
},
},
methods: {
@@ -84,7 +65,8 @@ export default {
},
},
TRIGGER_ELEMENT_BUTTON,
- TRIGGER_ELEMENT_SIDE_NAV,
+ TRIGGER_ELEMENT_WITH_EMOJI,
+ TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
};
</script>
@@ -99,16 +81,22 @@ export default {
{{ displayText }}
</gl-button>
<gl-link
- v-else-if="checkTrigger($options.TRIGGER_ELEMENT_SIDE_NAV)"
+ v-else-if="checkTrigger($options.TRIGGER_ELEMENT_WITH_EMOJI)"
v-bind="componentAttributes"
- data-is-link="true"
@click="openModal"
>
- <span class="nav-icon-container">
- <gl-icon :name="icon" />
- </span>
- <span class="nav-item-name"> {{ displayText }} </span>
+ {{ displayText }}
+ <gl-emoji class="gl-vertical-align-baseline gl-reset-font-size gl-mr-1" :data-name="icon" />
</gl-link>
+ <gl-dropdown-item
+ v-else-if="checkTrigger($options.TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI)"
+ v-bind="componentAttributes"
+ button-class="top-nav-menu-item"
+ @click="openModal"
+ >
+ {{ displayText }}
+ <gl-emoji class="gl-vertical-align-baseline gl-reset-font-size gl-mr-1" :data-name="icon" />
+ </gl-dropdown-item>
<gl-link v-else v-bind="componentAttributes" data-is-link="true" @click="openModal">
{{ displayText }}
</gl-link>
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 1e3b6093f0b..20dc32b3c9b 100644
--- a/app/assets/javascripts/invite_members/components/invite_modal_base.vue
+++ b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
@@ -1,5 +1,14 @@
<script>
-import { GlFormGroup, GlFormSelect, GlModal, GlDatepicker, GlLink, GlSprintf } from '@gitlab/ui';
+import {
+ GlFormGroup,
+ GlFormSelect,
+ GlModal,
+ GlDatepicker,
+ GlLink,
+ GlSprintf,
+ GlButton,
+} from '@gitlab/ui';
+
import Tracking from '~/tracking';
import { sprintf } from '~/locale';
import ContentTransition from '~/vue_shared/components/content_transition.vue';
@@ -33,6 +42,7 @@ export default {
GlLink,
GlModal,
GlSprintf,
+ GlButton,
ContentTransition,
},
mixins: [Tracking.mixin()],
@@ -246,13 +256,10 @@ export default {
data-qa-selector="invite_members_modal_content"
data-testid="invite-modal"
size="sm"
+ dialog-class="gl-mx-5"
:title="modalTitle"
:header-close-label="$options.HEADER_CLOSE_LABEL"
- :action-primary="actionPrimary"
- :action-cancel="actionCancel"
@shown="onShowModal"
- @primary="onSubmit"
- @cancel="onCancel"
@close="onClose"
@hidden="onReset"
>
@@ -330,5 +337,29 @@ export default {
<slot :name="key"></slot>
</template>
</content-transition>
+
+ <template #modal-footer>
+ <div
+ class="gl-m-0 gl-xs-w-full gl-display-flex gl-xs-flex-direction-column! gl-flex-direction-row-reverse"
+ >
+ <gl-button
+ class="gl-xs-w-full gl-xs-mb-3! gl-sm-ml-3!"
+ data-testid="invite-modal-submit"
+ v-bind="actionPrimary.attributes"
+ @click="onSubmit"
+ >
+ {{ actionPrimary.text }}
+ </gl-button>
+
+ <gl-button
+ class="gl-xs-w-full"
+ data-testid="invite-modal-cancel"
+ v-bind="actionCancel.attributes"
+ @click="onCancel"
+ >
+ {{ actionCancel.text }}
+ </gl-button>
+ </div>
+ </template>
</gl-modal>
</template>
diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js
index ac0b708c55e..86badd16d6c 100644
--- a/app/assets/javascripts/invite_members/constants.js
+++ b/app/assets/javascripts/invite_members/constants.js
@@ -19,7 +19,9 @@ export const GROUP_FILTERS = {
export const USERS_FILTER_ALL = 'all';
export const USERS_FILTER_SAML_PROVIDER_ID = 'saml_provider_id';
export const TRIGGER_ELEMENT_BUTTON = 'button';
-export const TRIGGER_ELEMENT_SIDE_NAV = 'side-nav';
+export const TOP_NAV_INVITE_MEMBERS_COMPONENT = 'invite_members';
+export const TRIGGER_ELEMENT_WITH_EMOJI = 'text-emoji';
+export const TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI = 'dropdown-text-emoji';
export const INVITE_MEMBER_MODAL_TRACKING_CATEGORY = 'invite_members_modal';
export const TRIGGER_DEFAULT_QA_SELECTOR = 'invite_members_button';
export const MEMBERS_MODAL_DEFAULT_TITLE = s__('InviteMembersModal|Invite members');
@@ -76,7 +78,6 @@ export const READ_MORE_TEXT = s__(
export const INVITE_BUTTON_TEXT = s__('InviteMembersModal|Invite');
export const INVITE_BUTTON_TEXT_DISABLED = s__('InviteMembersModal|Manage members');
export const CANCEL_BUTTON_TEXT = s__('InviteMembersModal|Cancel');
-export const CANCEL_BUTTON_TEXT_DISABLED = s__('InviteMembersModal|Explore paid plans');
export const HEADER_CLOSE_LABEL = s__('InviteMembersModal|Close invite team members');
export const MEMBER_ERROR_LIST_TEXT = s__(
'InviteMembersModal|Review the invite errors and try again:',
diff --git a/app/assets/javascripts/invite_members/utils/trigger_successful_invite_alert.js b/app/assets/javascripts/invite_members/utils/trigger_successful_invite_alert.js
index 4d3a7951265..e556582742b 100644
--- a/app/assets/javascripts/invite_members/utils/trigger_successful_invite_alert.js
+++ b/app/assets/javascripts/invite_members/utils/trigger_successful_invite_alert.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import AccessorUtilities from '~/lib/utils/accessor';
import { TOAST_MESSAGE_LOCALSTORAGE_KEY, TOAST_MESSAGE_SUCCESSFUL } from '../constants';
diff --git a/app/assets/javascripts/issuable/components/csv_export_modal.vue b/app/assets/javascripts/issuable/components/csv_export_modal.vue
index 736da92fa9f..c1de507cd80 100644
--- a/app/assets/javascripts/issuable/components/csv_export_modal.vue
+++ b/app/assets/javascripts/issuable/components/csv_export_modal.vue
@@ -1,7 +1,7 @@
<script>
import { GlModal, GlSprintf, GlIcon } from '@gitlab/ui';
+import { TYPE_ISSUE } from '~/issues/constants';
import { __, n__ } from '~/locale';
-import { ISSUABLE_TYPE } from '../constants';
export default {
actionCancel: {
@@ -19,7 +19,7 @@ export default {
},
inject: {
issuableType: {
- default: ISSUABLE_TYPE.issues,
+ default: TYPE_ISSUE,
},
email: {
default: '',
@@ -47,14 +47,17 @@ export default {
href: this.exportCsvPath,
variant: 'confirm',
'data-method': 'post',
- 'data-qa-selector': `export_${this.issuableType}_button`,
+ 'data-qa-selector': `export_issues_button`,
'data-track-action': 'click_button',
- 'data-track-label': `export_${this.issuableType}_csv`,
+ 'data-track-label': this.dataTrackLabel,
},
};
},
isIssue() {
- return this.issuableType === ISSUABLE_TYPE.issues;
+ return this.issuableType === TYPE_ISSUE;
+ },
+ dataTrackLabel() {
+ return this.isIssue ? 'export_issues_csv' : 'export_merge-requests_csv';
},
exportText() {
return this.isIssue ? __('Export issues') : __('Export merge requests');
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 dadb1419649..2cc01c302ec 100644
--- a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue
+++ b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue
@@ -7,8 +7,8 @@ import {
GlTooltipDirective,
GlModalDirective,
} from '@gitlab/ui';
+import { TYPE_ISSUE } from '~/issues/constants';
import { __ } from '~/locale';
-import { ISSUABLE_TYPE } from '../constants';
import CsvExportModal from './csv_export_modal.vue';
import CsvImportModal from './csv_import_modal.vue';
@@ -34,7 +34,7 @@ export default {
},
inject: {
issuableType: {
- default: ISSUABLE_TYPE.issues,
+ default: TYPE_ISSUE,
},
showExportButton: {
default: false,
diff --git a/app/assets/javascripts/issuable/components/issuable_header_warnings.vue b/app/assets/javascripts/issuable/components/issuable_header_warnings.vue
index 0e58f3793bc..03f10e9e812 100644
--- a/app/assets/javascripts/issuable/components/issuable_header_warnings.vue
+++ b/app/assets/javascripts/issuable/components/issuable_header_warnings.vue
@@ -2,7 +2,7 @@
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { mapGetters } from 'vuex';
import { sprintf, __ } from '~/locale';
-import { TYPE_ISSUE, WorkspaceType } from '~/issues/constants';
+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';
@@ -13,7 +13,7 @@ const NoteableTypeText = {
export default {
TYPE_ISSUE,
- WorkspaceType,
+ WORKSPACE_PROJECT,
components: {
GlIcon,
ConfidentialityBadge,
@@ -32,7 +32,7 @@ export default {
return this.getNoteableData.confidential;
},
isMergeRequest() {
- return this.getNoteableData.targetType === 'merge_request';
+ return this.getNoteableData.targetType === TYPE_MERGE_REQUEST;
},
warningIconsMeta() {
return [
@@ -60,7 +60,7 @@ export default {
<confidentiality-badge
v-if="isConfidential"
data-testid="confidential"
- :workspace-type="$options.WorkspaceType.project"
+ :workspace-type="$options.WORKSPACE_PROJECT"
:issuable-type="$options.TYPE_ISSUE"
/>
<template v-for="meta in warningIconsMeta">
diff --git a/app/assets/javascripts/issuable/components/related_issuable_item.vue b/app/assets/javascripts/issuable/components/related_issuable_item.vue
index 608c1deac64..c4b9bdb150b 100644
--- a/app/assets/javascripts/issuable/components/related_issuable_item.vue
+++ b/app/assets/javascripts/issuable/components/related_issuable_item.vue
@@ -101,26 +101,22 @@ export default {
:class="{
'issuable-info-container': !canReorder,
'card-body': canReorder,
- 'gl-pr-2': canRemove,
}"
- class="item-body d-flex align-items-center gl-py-3 gl-px-5"
+ class="item-body gl-display-flex gl-align-items-center gl-gap-3 gl-mx-n2"
>
<div
- class="item-contents gl-display-flex gl-align-items-center gl-flex-wrap gl-flex-grow-1 flex-xl-nowrap gl-min-h-7"
+ class="item-contents gl-display-flex gl-align-items-center gl-flex-wrap gl-flex-grow-1 gl-gap-2 gl-px-3 gl-py-2 py-xl-0 flex-xl-nowrap gl-min-h-7"
>
<!-- Title area: Status icon (XL) and title -->
- <div class="item-title d-flex align-items-xl-center mb-xl-0 gl-min-w-0">
- <div ref="iconElementXL">
- <gl-icon
- v-if="hasState"
- ref="iconElementXL"
- class="gl-mr-3"
- :class="iconClasses"
- :name="iconName"
- :title="stateTitle"
- :aria-label="state"
- />
- </div>
+ <div class="item-title gl-display-flex gl-gap-3 gl-min-w-0">
+ <gl-icon
+ v-if="hasState"
+ ref="iconElementXL"
+ :class="iconClasses"
+ :name="iconName"
+ :title="stateTitle"
+ :aria-label="state"
+ />
<gl-tooltip :target="() => $refs.iconElementXL">
<span v-safe-html="stateTitle"></span>
</gl-tooltip>
@@ -129,42 +125,46 @@ export default {
v-gl-tooltip
name="eye-slash"
:title="__('Confidential')"
- class="confidential-icon gl-mr-2 align-self-baseline align-self-md-auto mt-xl-0"
+ class="confidential-icon"
:aria-label="__('Confidential')"
/>
- <gl-link
- :href="computedPath"
- class="sortable-link gl-font-weight-normal"
- @click="handleTitleClick"
- >
+ <gl-link :href="computedPath" class="sortable-link" @click="handleTitleClick">
{{ title }}
</gl-link>
</div>
<!-- Info area: meta, path, and assignees -->
- <div class="item-info-area d-flex flex-xl-grow-1 flex-shrink-0">
+ <div
+ class="item-info-area gl-display-flex gl-flex-grow-1 gl-flex-shrink-0 gl-gap-3 gl-ml-6 ml-xl-0"
+ >
<!-- Meta area: path and attributes -->
<!-- If there is no room beside the path, meta attributes are put ABOVE it (flex-wrap-reverse). -->
<!-- See design: https://gitlab-org.gitlab.io/gitlab-design/hosted/pedro/%2383-issue-mr-rows-cards-spec-previews/#artboard16 -->
<div
- class="item-meta d-flex flex-wrap-reverse justify-content-start justify-content-md-between"
+ class="item-meta gl-display-flex gl-md-justify-content-space-between gl-gap-3 gl-flex-wrap-wrap-reverse"
>
<!-- Path area: status icon (<XL), path, issue # -->
<div
- class="item-path-area item-path-id d-flex align-items-center mr-2 mt-2 mt-xl-0 ml-xl-2"
+ class="item-path-area item-path-id gl-display-flex gl-align-items-center gl-flex-wrap gl-gap-3"
>
<gl-tooltip :target="() => $refs.iconElement">
<span v-safe-html="stateTitle"></span>
</gl-tooltip>
- <span v-gl-tooltip :title="itemPath" class="path-id-text d-inline-block">{{
- itemPath
- }}</span>
+ <span
+ v-if="itemPath"
+ v-gl-tooltip
+ :title="itemPath"
+ class="path-id-text d-inline-block"
+ >{{ itemPath }}</span
+ >
<span>{{ pathIdSeparator }}{{ itemId }}</span>
</div>
<!-- Attributes area: CI, epic count, weight, milestone -->
<!-- They have a different order on large screen sizes -->
- <div class="item-attributes-area d-flex align-items-center mt-2 mt-xl-0">
+ <div
+ class="item-attributes-area gl-display-flex gl-align-items-center gl-flex-wrap gl-gap-3"
+ >
<span v-if="hasPipeline" class="mr-ci-status order-md-last">
<a :href="pipelineStatus.details_path">
<ci-icon v-gl-tooltip :status="pipelineStatus" :title="pipelineStatusTooltip" />
@@ -174,7 +174,7 @@ export default {
<issue-milestone
v-if="hasMilestone"
:milestone="milestone"
- class="d-flex align-items-center item-milestone order-md-first ml-md-0"
+ class="item-milestone gl-font-sm gl-display-flex gl-align-items-center order-md-first"
/>
<!-- Flex order for slots is defined in the parent component: e.g. related_issues_block.vue -->
@@ -198,24 +198,17 @@ export default {
<issue-assignees
v-if="hasAssignees"
:assignees="assignees"
- class="item-assignees align-items-center align-self-end flex-shrink-0 order-md-2 d-none d-md-flex"
+ class="item-assignees gl-display-flex gl-align-items-center gl-align-self-end gl-flex-shrink-0 order-md-2"
/>
</div>
</div>
-
- <!-- Assignees. On small layouts, these are put here, at the end of the card. -->
- <issue-assignees
- v-if="assignees.length !== 0"
- :assignees="assignees"
- class="item-assignees d-flex align-items-center align-self-end flex-shrink-0 d-md-none gl-ml-3"
- />
</div>
</div>
<span
v-if="isLocked"
v-gl-tooltip
- class="gl-px-3 gl-display-inline-block gl-cursor-not-allowed"
+ class="gl-display-inline-block gl-cursor-not-allowed"
:title="lockedMessage"
data-testid="lockIcon"
>
@@ -226,8 +219,9 @@ export default {
v-gl-tooltip
icon="close"
category="tertiary"
+ size="small"
:disabled="removeDisabled"
- class="js-issue-item-remove-button gl-ml-3"
+ class="js-issue-item-remove-button"
data-qa-selector="remove_related_issue_button"
:title="__('Remove')"
:aria-label="__('Remove')"
diff --git a/app/assets/javascripts/issuable/components/status_box.vue b/app/assets/javascripts/issuable/components/status_box.vue
index 0c75e44443d..9ffcf14c943 100644
--- a/app/assets/javascripts/issuable/components/status_box.vue
+++ b/app/assets/javascripts/issuable/components/status_box.vue
@@ -4,8 +4,7 @@ import Vue from 'vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { fetchPolicies } from '~/lib/graphql';
import { __ } from '~/locale';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
-import { IssuableStates } from '~/vue_shared/issuable/list/constants';
+import { STATUS_CLOSED, STATUS_OPEN, TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
export const badgeState = Vue.observable({
state: '',
@@ -76,15 +75,15 @@ export default {
return [
CLASSES[this.state],
{
- 'gl-vertical-align-bottom': this.issuableType === IssuableType.MergeRequest,
+ 'gl-vertical-align-bottom': this.issuableType === TYPE_MERGE_REQUEST,
},
];
},
badgeVariant() {
- if (this.state === IssuableStates.Opened) {
+ if (this.state === STATUS_OPEN) {
return 'success';
- } else if (this.state === IssuableStates.Closed) {
- return this.issuableType === IssuableType.MergeRequest ? 'danger' : 'info';
+ } else if (this.state === STATUS_CLOSED) {
+ return this.issuableType === TYPE_MERGE_REQUEST ? 'danger' : 'info';
}
return 'info';
},
diff --git a/app/assets/javascripts/issuable/constants.js b/app/assets/javascripts/issuable/constants.js
index 5327f251fda..88fc6859acd 100644
--- a/app/assets/javascripts/issuable/constants.js
+++ b/app/assets/javascripts/issuable/constants.js
@@ -1,11 +1 @@
export const EVENT_ISSUABLE_VUE_APP_CHANGE = 'issuable_vue_app:change';
-
-export const ISSUABLE_TYPE = {
- issues: 'issues',
- mergeRequests: 'merge-requests',
-};
-
-export const ISSUABLE_INDEX = {
- ISSUE: 'issue_',
- MERGE_REQUEST: 'merge_request_',
-};
diff --git a/app/assets/javascripts/issuable/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable/issuable_bulk_update_actions.js
index 201782a201a..e5a2388580b 100644
--- a/app/assets/javascripts/issuable/issuable_bulk_update_actions.js
+++ b/app/assets/javascripts/issuable/issuable_bulk_update_actions.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { difference, intersection, union } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/issuable/issuable_label_selector.js b/app/assets/javascripts/issuable/issuable_label_selector.js
index ad8bbf04d6f..76fd4cccf2e 100644
--- a/app/assets/javascripts/issuable/issuable_label_selector.js
+++ b/app/assets/javascripts/issuable/issuable_label_selector.js
@@ -1,11 +1,8 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
-import {
- DropdownVariant,
- LabelType,
-} from '~/sidebar/components/labels/labels_select_widget/constants';
-import { WorkspaceType } from '~/issues/constants';
+import { DropdownVariant } from '~/sidebar/components/labels/labels_select_widget/constants';
+import { WORKSPACE_PROJECT } from '~/issues/constants';
import IssuableLabelSelector from '~/vue_shared/issuable/create/components/issuable_label_selector.vue';
Vue.use(VueApollo);
@@ -43,11 +40,11 @@ export default () => {
fullPath,
initialLabels: JSON.parse(initialLabels),
issuableType,
- labelType: LabelType.project,
+ labelType: WORKSPACE_PROJECT,
labelsFilterBasePath,
labelsManagePath,
variant: DropdownVariant.Embedded,
- workspaceType: WorkspaceType.project,
+ workspaceType: WORKSPACE_PROJECT,
},
render(createElement) {
return createElement(IssuableLabelSelector);
diff --git a/app/assets/javascripts/issuable/popover/components/mr_popover.vue b/app/assets/javascripts/issuable/popover/components/mr_popover.vue
index 92994809362..af93430963e 100644
--- a/app/assets/javascripts/issuable/popover/components/mr_popover.vue
+++ b/app/assets/javascripts/issuable/popover/components/mr_popover.vue
@@ -1,14 +1,12 @@
<script>
-/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlBadge, GlPopover, GlSkeletonLoader } from '@gitlab/ui';
+import { STATUS_CLOSED, STATUS_MERGED } from '~/issues/constants';
+import { __ } from '~/locale';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
-import { mrStates, humanMRStates } from '../constants';
import query from '../queries/merge_request.query.graphql';
export default {
- // name: 'MRPopover' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/25
- name: 'MRPopover', // eslint-disable-line @gitlab/require-i18n-strings
components: {
GlBadge,
GlPopover,
@@ -48,9 +46,9 @@ export default {
},
badgeVariant() {
switch (this.mergeRequest.state) {
- case mrStates.merged:
+ case STATUS_MERGED:
return 'info';
- case mrStates.closed:
+ case STATUS_CLOSED:
return 'danger';
default:
return 'success';
@@ -58,12 +56,12 @@ export default {
},
stateHumanName() {
switch (this.mergeRequest.state) {
- case mrStates.merged:
- return humanMRStates.merged;
- case mrStates.closed:
- return humanMRStates.closed;
+ case STATUS_MERGED:
+ return __('Merged');
+ case STATUS_CLOSED:
+ return __('Closed');
default:
- return humanMRStates.open;
+ return __('Open');
}
},
title() {
@@ -101,7 +99,9 @@ export default {
<gl-badge class="gl-mr-3" :variant="badgeVariant">
{{ stateHumanName }}
</gl-badge>
- <span class="gl-text-secondary">Opened <time v-text="formattedTime"></time></span>
+ <span class="gl-text-secondary">
+ {{ __('Opened') }} <time v-text="formattedTime"></time
+ ></span>
</div>
<ci-icon v-if="detailedStatus" :status="detailedStatus" />
</div>
diff --git a/app/assets/javascripts/issuable/popover/constants.js b/app/assets/javascripts/issuable/popover/constants.js
deleted file mode 100644
index 352bc635293..00000000000
--- a/app/assets/javascripts/issuable/popover/constants.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { __ } from '~/locale';
-
-export const mrStates = {
- merged: 'merged',
- closed: 'closed',
- open: 'open',
-};
-
-export const humanMRStates = {
- merged: __('Merged'),
- closed: __('Closed'),
- open: __('Open'),
-};
diff --git a/app/assets/javascripts/issues/constants.js b/app/assets/javascripts/issues/constants.js
index ba05dd731f7..b7d885ed8a7 100644
--- a/app/assets/javascripts/issues/constants.js
+++ b/app/assets/javascripts/issues/constants.js
@@ -1,36 +1,25 @@
import { __ } from '~/locale';
+export const STATUS_ALL = 'all';
export const STATUS_CLOSED = 'closed';
+export const STATUS_MERGED = 'merged';
export const STATUS_OPEN = 'opened';
export const STATUS_REOPENED = 'reopened';
export const TITLE_LENGTH_MAX = 255;
+export const TYPE_ALERT = 'alert';
export const TYPE_EPIC = 'epic';
+export const TYPE_INCIDENT = 'incident';
export const TYPE_ISSUE = 'issue';
+export const TYPE_MERGE_REQUEST = 'merge_request';
+export const TYPE_TEST_CASE = 'test_case';
+
+export const WORKSPACE_GROUP = 'group';
+export const WORKSPACE_PROJECT = 'project';
export const IssuableStatusText = {
[STATUS_CLOSED]: __('Closed'),
[STATUS_OPEN]: __('Open'),
[STATUS_REOPENED]: __('Open'),
};
-
-// Deprecated - use individual constants instead like `TYPE_ISSUE` above
-export const IssuableType = {
- Issue: 'issue',
- Epic: 'epic',
- MergeRequest: 'merge_request',
- Alert: 'alert',
- TestCase: 'test_case',
-};
-
-export const IssueType = {
- Issue: 'issue',
- Incident: 'incident',
- TestCase: 'test_case',
-};
-
-export const WorkspaceType = {
- project: 'project',
- group: 'group',
-};
diff --git a/app/assets/javascripts/issues/create_merge_request_dropdown.js b/app/assets/javascripts/issues/create_merge_request_dropdown.js
index 977a505437d..c821c18bcb9 100644
--- a/app/assets/javascripts/issues/create_merge_request_dropdown.js
+++ b/app/assets/javascripts/issues/create_merge_request_dropdown.js
@@ -7,10 +7,14 @@ import {
import confidentialMergeRequestState from '~/confidential_merge_request/state';
import DropLab from '~/filtered_search/droplab/drop_lab_deprecated';
import ISetter from '~/filtered_search/droplab/plugins/input_setter';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __, sprintf } from '~/locale';
import { mergeUrlParams } from '~/lib/utils/url_utility';
+import {
+ findInvalidBranchNameCharacters,
+ humanizeBranchValidationErrors,
+} from '~/lib/utils/text_utility';
import api from '~/api';
// Todo: Remove this when fixing issue in input_setter plugin
@@ -19,6 +23,12 @@ const InputSetter = { ...ISetter };
const CREATE_MERGE_REQUEST = 'create-mr';
const CREATE_BRANCH = 'create-branch';
+const VALIDATION_TYPE_BRANCH_UNAVAILABLE = 'branch_unavailable';
+const VALIDATION_TYPE_INVALID_CHARS = 'invalid_chars';
+
+const INPUT_TARGET_BRANCH = 'branch';
+const INPUT_TARGET_REF = 'ref';
+
function createEndpoint(projectPath, endpoint) {
if (canCreateConfidentialMergeRequest()) {
return endpoint.replace(
@@ -30,6 +40,23 @@ function createEndpoint(projectPath, endpoint) {
return endpoint;
}
+function getValidationError(target, inputValue, validationType) {
+ const invalidChars = findInvalidBranchNameCharacters(inputValue.value);
+ let text;
+
+ if (invalidChars && validationType === VALIDATION_TYPE_INVALID_CHARS) {
+ text = humanizeBranchValidationErrors(invalidChars);
+ }
+
+ if (validationType === VALIDATION_TYPE_BRANCH_UNAVAILABLE) {
+ text =
+ target === INPUT_TARGET_BRANCH
+ ? __('Branch is already taken')
+ : __('Source is not available');
+ }
+
+ return text;
+}
export default class CreateMergeRequestDropdown {
constructor(wrapperEl) {
this.wrapperEl = wrapperEl;
@@ -124,18 +151,19 @@ export default class CreateMergeRequestDropdown {
.then(({ data }) => {
this.setUnavailableButtonState(false);
- if (data.can_create_branch) {
- this.available();
- this.enable();
- this.updateBranchName(data.suggested_branch_name);
-
- if (!this.droplabInitialized) {
- this.droplabInitialized = true;
- this.initDroplab();
- this.bindEvents();
- }
- } else {
+ if (!data.can_create_branch) {
this.hide();
+ return;
+ }
+
+ this.available();
+ this.enable();
+ this.updateBranchName(data.suggested_branch_name);
+
+ if (!this.droplabInitialized) {
+ this.droplabInitialized = true;
+ this.initDroplab();
+ this.bindEvents();
}
})
.catch(() => {
@@ -274,7 +302,7 @@ export default class CreateMergeRequestDropdown {
const tags = data[Object.keys(data)[1]];
let result;
- if (target === 'branch') {
+ if (target === INPUT_TARGET_BRANCH) {
result = CreateMergeRequestDropdown.findByValue(branches, ref);
} else {
result =
@@ -354,10 +382,10 @@ export default class CreateMergeRequestDropdown {
}
if (event.target === this.branchInput) {
- target = 'branch';
+ target = INPUT_TARGET_BRANCH;
({ value } = this.branchInput);
} else if (event.target === this.refInput) {
- target = 'ref';
+ target = INPUT_TARGET_REF;
if (event.target === document.activeElement) {
value =
event.target.value.slice(0, event.target.selectionStart) +
@@ -382,7 +410,7 @@ export default class CreateMergeRequestDropdown {
this.createBranchPath = this.wrapperEl.dataset.createBranchPath;
this.createMrPath = this.wrapperEl.dataset.createMrPath;
- if (target === 'branch') {
+ if (target === INPUT_TARGET_BRANCH) {
this.branchIsValid = true;
} else {
this.refIsValid = true;
@@ -473,7 +501,7 @@ export default class CreateMergeRequestDropdown {
showAvailableMessage(target) {
const { input, message } = this.getTargetData(target);
- const text = target === 'branch' ? __('Branch name') : __('Source');
+ const text = target === INPUT_TARGET_BRANCH ? __('Branch name') : __('Source');
this.removeMessage(target);
input.classList.add('gl-field-success-outline');
@@ -484,7 +512,7 @@ export default class CreateMergeRequestDropdown {
showCheckingMessage(target) {
const { message } = this.getTargetData(target);
- const text = target === 'branch' ? __('branch name') : __('source');
+ const text = target === INPUT_TARGET_BRANCH ? __('branch name') : __('source');
this.removeMessage(target);
message.classList.add('gl-text-gray-600');
@@ -492,10 +520,9 @@ export default class CreateMergeRequestDropdown {
message.style.display = 'inline-block';
}
- showNotAvailableMessage(target) {
+ showNotAvailableMessage(target, validationType = VALIDATION_TYPE_BRANCH_UNAVAILABLE) {
const { input, message } = this.getTargetData(target);
- const text =
- target === 'branch' ? __('Branch is already taken') : __('Source is not available');
+ const text = getValidationError(target, input, validationType);
this.removeMessage(target);
input.classList.add('gl-field-error-outline');
@@ -511,35 +538,35 @@ export default class CreateMergeRequestDropdown {
updateBranchName(suggestedBranchName) {
this.branchInput.value = suggestedBranchName;
- this.updateCreatePaths('branch', suggestedBranchName);
+ this.updateInputState(INPUT_TARGET_BRANCH, suggestedBranchName, '');
+ this.updateCreatePaths(INPUT_TARGET_BRANCH, suggestedBranchName);
}
updateInputState(target, ref, result) {
// target - 'branch' or 'ref' - which the input field we are searching a ref for.
// ref - string - what a user typed.
// result - string - what has been found on backend.
+ if (target === INPUT_TARGET_BRANCH) this.updateTargetBranchInput(ref, result);
+ if (target === INPUT_TARGET_REF) this.updateRefInput(ref, result);
+
+ if (this.inputsAreValid()) {
+ this.enable();
+ } else {
+ this.disableCreateAction();
+ }
+ }
- // If a found branch equals exact the same text a user typed,
- // that means a new branch cannot be created as it already exists.
+ updateRefInput(ref, result) {
+ this.refInput.dataset.value = ref;
if (ref === result) {
- if (target === 'branch') {
- this.branchIsValid = false;
- this.showNotAvailableMessage('branch');
- } else {
- this.refIsValid = true;
- this.refInput.dataset.value = ref;
- this.showAvailableMessage('ref');
- this.updateCreatePaths(target, ref);
- }
- } else if (target === 'branch') {
- this.branchIsValid = true;
- this.showAvailableMessage('branch');
- this.updateCreatePaths(target, ref);
+ this.refIsValid = true;
+ this.showAvailableMessage(INPUT_TARGET_REF);
+ this.updateCreatePaths(INPUT_TARGET_REF, ref);
} else {
this.refIsValid = false;
this.refInput.dataset.value = ref;
this.disableCreateAction();
- this.showNotAvailableMessage('ref');
+ this.showNotAvailableMessage(INPUT_TARGET_REF);
// Show ref hint.
if (result) {
@@ -547,11 +574,24 @@ export default class CreateMergeRequestDropdown {
this.refInput.setSelectionRange(ref.length, result.length);
}
}
+ }
- if (this.inputsAreValid()) {
- this.enable();
+ updateTargetBranchInput(ref, result) {
+ const branchNameErrors = findInvalidBranchNameCharacters(ref);
+ const isInvalidString = branchNameErrors.length;
+ if (ref !== result && !isInvalidString) {
+ this.branchIsValid = true;
+ // If a found branch equals exact the same text a user typed,
+ // Or user typed input contains invalid chars,
+ // that means a new branch cannot be created as it already exists.
+ this.showAvailableMessage(INPUT_TARGET_BRANCH, VALIDATION_TYPE_BRANCH_UNAVAILABLE);
+ this.updateCreatePaths(INPUT_TARGET_BRANCH, ref);
+ } else if (isInvalidString) {
+ this.branchIsValid = false;
+ this.showNotAvailableMessage(INPUT_TARGET_BRANCH, VALIDATION_TYPE_INVALID_CHARS);
} else {
- this.disableCreateAction();
+ this.branchIsValid = false;
+ this.showNotAvailableMessage(INPUT_TARGET_BRANCH);
}
}
@@ -569,6 +609,7 @@ export default class CreateMergeRequestDropdown {
pathReplacement,
);
+ this.wrapperEl.dataset.createBranchPath = this.createBranchPath;
this.wrapperEl.dataset.createMrPath = this.createMrPath;
}
}
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 a4a2feba716..2546bface58 100644
--- a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
+++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
@@ -4,12 +4,11 @@ import * as Sentry from '@sentry/browser';
import getIssuesQuery from 'ee_else_ce/issues/dashboard/queries/get_issues.query.graphql';
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_CLOSED } from '~/issues/constants';
+import { STATUS_ALL, STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import {
CREATED_DESC,
defaultTypeTokenOptions,
i18n,
- PAGE_SIZE,
PARAM_STATE,
UPDATED_DESC,
urlSortParams,
@@ -49,7 +48,7 @@ import {
TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/constants';
+import { DEFAULT_PAGE_SIZE, IssuableListTabs } from '~/vue_shared/issuable/list/constants';
import getIssuesCountsQuery from '../queries/get_issues_counts.query.graphql';
import { AutocompleteCache } from '../utils';
@@ -93,7 +92,7 @@ export default {
data() {
const state = getParameterByName(PARAM_STATE);
- const defaultSortKey = state === IssuableStates.Closed ? UPDATED_DESC : CREATED_DESC;
+ const defaultSortKey = state === STATUS_CLOSED ? UPDATED_DESC : CREATED_DESC;
const dashboardSortKey = getSortKey(this.initialSort);
const graphQLSortKey =
isSortKey(this.initialSort?.toUpperCase()) && this.initialSort.toUpperCase();
@@ -110,7 +109,7 @@ export default {
pageInfo: {},
pageParams: getInitialPageParams(),
sortKey,
- state: state || IssuableStates.Opened,
+ state: state || STATUS_OPEN,
};
},
apollo: {
@@ -132,7 +131,6 @@ export default {
skip() {
return !this.hasSearch;
},
- debounce: 200,
},
issuesCounts: {
query: getIssuesCountsQuery,
@@ -149,7 +147,6 @@ export default {
skip() {
return !this.hasSearch;
},
- debounce: 200,
context: {
isSingleRequest: true,
},
@@ -314,9 +311,9 @@ export default {
tabCounts() {
const { openedIssues, closedIssues, allIssues } = this.issuesCounts;
return {
- [IssuableStates.Opened]: openedIssues?.count,
- [IssuableStates.Closed]: closedIssues?.count,
- [IssuableStates.All]: allIssues?.count,
+ [STATUS_OPEN]: openedIssues?.count,
+ [STATUS_CLOSED]: closedIssues?.count,
+ [STATUS_ALL]: allIssues?.count,
};
},
urlFilterParams() {
@@ -388,14 +385,14 @@ export default {
handleNextPage() {
this.pageParams = {
afterCursor: this.pageInfo.endCursor,
- firstPageSize: PAGE_SIZE,
+ firstPageSize: DEFAULT_PAGE_SIZE,
};
scrollUp();
},
handlePreviousPage() {
this.pageParams = {
beforeCursor: this.pageInfo.startCursor,
- lastPageSize: PAGE_SIZE,
+ lastPageSize: DEFAULT_PAGE_SIZE,
};
scrollUp();
},
@@ -461,12 +458,20 @@ export default {
@sort="handleSort"
>
<template #nav-actions>
- <gl-button :href="rssPath" icon="rss">
- {{ $options.i18n.rssLabel }}
- </gl-button>
- <gl-button :href="calendarPath" icon="calendar">
- {{ $options.i18n.calendarLabel }}
- </gl-button>
+ <gl-button
+ v-gl-tooltip
+ :href="rssPath"
+ icon="rss"
+ :title="$options.i18n.rssLabel"
+ class="has-tooltip btn-icon"
+ />
+ <gl-button
+ v-gl-tooltip
+ :href="calendarPath"
+ icon="calendar"
+ :title="$options.i18n.calendarLabel"
+ class="has-tooltip btn-icon"
+ />
</template>
<template #timeframe="{ issuable = {} }">
diff --git a/app/assets/javascripts/issues/index.js b/app/assets/javascripts/issues/index.js
index 5b5f1d273d0..83387d3ac29 100644
--- a/app/assets/javascripts/issues/index.js
+++ b/app/assets/javascripts/issues/index.js
@@ -6,7 +6,7 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import GLForm from '~/gl_form';
import { initIssuableHeaderWarnings, initIssuableSidebar } from '~/issuable';
import IssuableTemplateSelectors from '~/issuable/issuable_template_selectors';
-import { IssueType } from '~/issues/constants';
+import { TYPE_INCIDENT } from '~/issues/constants';
import Issue from '~/issues/issue';
import { initTitleSuggestions, initTypePopover } from '~/issues/new';
import { initRelatedMergeRequests } from '~/issues/related_merge_requests';
@@ -59,11 +59,11 @@ export function initShow() {
const { issueType, ...issuableData } = parseIssuableData(el);
- if (issueType === IssueType.Incident) {
+ if (issueType === TYPE_INCIDENT) {
initIncidentApp({ ...issuableData, issuableId: el.dataset.issuableId }, store);
- initHeaderActions(store, IssueType.Incident);
+ initHeaderActions(store, TYPE_INCIDENT);
initLinkedResources();
- initRelatedIssues(IssueType.Incident);
+ initRelatedIssues(TYPE_INCIDENT);
} else {
initIssueApp(issuableData, store);
initHeaderActions(store);
diff --git a/app/assets/javascripts/issues/issue.js b/app/assets/javascripts/issues/issue.js
index de1c689e590..b7fd99d8042 100644
--- a/app/assets/javascripts/issues/issue.js
+++ b/app/assets/javascripts/issues/issue.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { joinPaths } from '~/lib/utils/url_utility';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { EVENT_ISSUABLE_VUE_APP_CHANGE } from '~/issuable/constants';
import axios from '~/lib/utils/axios_utils';
import { addDelimiter } from '~/lib/utils/text_utility';
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 6c46013e4f9..5c4bf8f19e4 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -2,17 +2,23 @@
import { GlButton, GlFilteredSearchToken, GlTooltipDirective } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
+import { isEmpty } from 'lodash';
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 getIssuesQuery from 'ee_else_ce/issues/list/queries/get_issues.query.graphql';
import getIssuesCountsQuery from 'ee_else_ce/issues/list/queries/get_issues_counts.query.graphql';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { TYPENAME_USER } from '~/graphql_shared/constants';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { ITEM_TYPE } from '~/groups/constants';
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
import IssuableByEmail from '~/issuable/components/issuable_by_email.vue';
-import { STATUS_CLOSED } from '~/issues/constants';
+import {
+ STATUS_ALL,
+ STATUS_CLOSED,
+ STATUS_OPEN,
+ WORKSPACE_GROUP,
+ WORKSPACE_PROJECT,
+} from '~/issues/constants';
import axios from '~/lib/utils/axios_utils';
import { fetchPolicies } from '~/lib/graphql';
import { isPositiveInteger } from '~/lib/utils/number_utils';
@@ -46,7 +52,7 @@ import {
TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/constants';
+import { DEFAULT_PAGE_SIZE, IssuableListTabs } from '~/vue_shared/issuable/list/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import NewResourceDropdown from '~/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue';
import {
@@ -56,7 +62,6 @@ import {
i18n,
ISSUE_REFERENCE,
MAX_LIST_SIZE,
- PAGE_SIZE,
PARAM_FIRST_PAGE_SIZE,
PARAM_LAST_PAGE_SIZE,
PARAM_PAGE_AFTER,
@@ -177,8 +182,8 @@ export default {
pageParams: {},
showBulkEditSidebar: false,
sortKey: CREATED_DESC,
- state: IssuableStates.Opened,
- pageSize: PAGE_SIZE,
+ state: STATUS_OPEN,
+ pageSize: DEFAULT_PAGE_SIZE,
};
},
apollo: {
@@ -206,9 +211,8 @@ export default {
Sentry.captureException(error);
},
skip() {
- return !this.hasAnyIssues;
+ return !this.hasAnyIssues || isEmpty(this.pageParams);
},
- debounce: 200,
},
issuesCounts: {
query: getIssuesCountsQuery,
@@ -223,9 +227,8 @@ export default {
Sentry.captureException(error);
},
skip() {
- return !this.hasAnyIssues;
+ return !this.hasAnyIssues || isEmpty(this.pageParams);
},
- debounce: 200,
context: {
isSingleRequest: true,
},
@@ -249,7 +252,7 @@ export default {
};
},
namespace() {
- return this.isProject ? ITEM_TYPE.PROJECT : ITEM_TYPE.GROUP;
+ return this.isProject ? WORKSPACE_PROJECT : WORKSPACE_GROUP;
},
defaultWorkItemTypes() {
return [...defaultWorkItemTypes, ...this.eeWorkItemTypes];
@@ -275,7 +278,7 @@ export default {
return this.sortKey === RELATIVE_POSITION_ASC;
},
isOpenTab() {
- return this.state === IssuableStates.Opened;
+ return this.state === STATUS_OPEN;
},
showCsvButtons() {
return this.isProject && this.isSignedIn;
@@ -449,7 +452,7 @@ export default {
return this.issues.length > 0 && (this.pageInfo.hasNextPage || this.pageInfo.hasPreviousPage);
},
showPageSizeControls() {
- return this.currentTabCount > PAGE_SIZE;
+ return this.currentTabCount > DEFAULT_PAGE_SIZE;
},
sortOptions() {
return getSortOptions({
@@ -461,9 +464,9 @@ export default {
tabCounts() {
const { openedIssues, closedIssues, allIssues } = this.issuesCounts;
return {
- [IssuableStates.Opened]: openedIssues?.count,
- [IssuableStates.Closed]: closedIssues?.count,
- [IssuableStates.All]: allIssues?.count,
+ [STATUS_OPEN]: openedIssues?.count,
+ [STATUS_CLOSED]: closedIssues?.count,
+ [STATUS_ALL]: allIssues?.count,
};
},
currentTabCount() {
@@ -726,7 +729,7 @@ export default {
const lastPageSize = getParameterByName(PARAM_LAST_PAGE_SIZE);
const state = getParameterByName(PARAM_STATE);
- const defaultSortKey = state === IssuableStates.Closed ? UPDATED_DESC : CREATED_DESC;
+ const defaultSortKey = state === STATUS_CLOSED ? UPDATED_DESC : CREATED_DESC;
const dashboardSortKey = getSortKey(sortValue);
const graphQLSortKey = isSortKey(sortValue?.toUpperCase()) && sortValue.toUpperCase();
@@ -750,7 +753,7 @@ export default {
getParameterByName(PARAM_PAGE_BEFORE),
);
this.sortKey = sortKey;
- this.state = state || IssuableStates.Opened;
+ this.state = state || STATUS_OPEN;
},
},
};
diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js
index 31a43c95f5e..99064a50e3f 100644
--- a/app/assets/javascripts/issues/list/constants.js
+++ b/app/assets/javascripts/issues/list/constants.js
@@ -33,7 +33,6 @@ import {
export const ISSUE_REFERENCE = /^#\d+$/;
export const MAX_LIST_SIZE = 10;
-export const PAGE_SIZE = 20;
export const PARAM_ASSIGNEE_ID = 'assignee_id';
export const PARAM_FIRST_PAGE_SIZE = 'first_page_size';
export const PARAM_LAST_PAGE_SIZE = 'last_page_size';
diff --git a/app/assets/javascripts/issues/list/utils.js b/app/assets/javascripts/issues/list/utils.js
index bbd081843ca..b086640cd12 100644
--- a/app/assets/javascripts/issues/list/utils.js
+++ b/app/assets/javascripts/issues/list/utils.js
@@ -16,6 +16,7 @@ import {
TOKEN_TYPE_HEALTH,
TOKEN_TYPE_LABEL,
} from '~/vue_shared/components/filtered_search_bar/constants';
+import { DEFAULT_PAGE_SIZE } from '~/vue_shared/issuable/list/constants';
import {
ALTERNATIVE_FILTER,
API_PARAM,
@@ -35,7 +36,6 @@ import {
MILESTONE_DUE_ASC,
MILESTONE_DUE_DESC,
NORMAL_FILTER,
- PAGE_SIZE,
PARAM_ASSIGNEE_ID,
POPULARITY_ASC,
POPULARITY_DESC,
@@ -56,7 +56,7 @@ import {
export const getInitialPageParams = (
pageSize,
- firstPageSize = pageSize ?? PAGE_SIZE,
+ firstPageSize = pageSize ?? DEFAULT_PAGE_SIZE,
lastPageSize,
afterCursor,
beforeCursor,
@@ -289,9 +289,9 @@ const formatData = (token) => {
};
export const convertToApiParams = (filterTokens) => {
- const params = {};
- const not = {};
- const or = {};
+ const params = new Map();
+ const not = new Map();
+ const or = new Map();
filterTokens
.filter((token) => token.type !== FILTERED_SEARCH_TERM)
@@ -307,32 +307,34 @@ export const convertToApiParams = (filterTokens) => {
obj = params;
}
const data = formatData(token);
- Object.assign(obj, {
- [apiField]: obj[apiField] ? [obj[apiField], data].flat() : data,
- });
+ obj.set(apiField, obj.has(apiField) ? [obj.get(apiField), data].flat() : data);
});
- if (Object.keys(not).length) {
- Object.assign(params, { not });
+ if (not.size) {
+ params.set('not', Object.fromEntries(not));
}
- if (Object.keys(or).length) {
- Object.assign(params, { or });
+ if (or.size) {
+ params.set('or', Object.fromEntries(or));
}
- return params;
+ return Object.fromEntries(params);
};
-export const convertToUrlParams = (filterTokens) =>
- filterTokens
+export const convertToUrlParams = (filterTokens) => {
+ const urlParamsMap = filterTokens
.filter((token) => token.type !== FILTERED_SEARCH_TERM)
.reduce((acc, token) => {
const filterType = getFilterType(token);
const urlParam = filters[token.type][URL_PARAM][token.value.operator]?.[filterType];
- return Object.assign(acc, {
- [urlParam]: acc[urlParam] ? [acc[urlParam], token.value.data].flat() : token.value.data,
- });
- }, {});
+ return acc.set(
+ urlParam,
+ acc.has(urlParam) ? [acc.get(urlParam), token.value.data].flat() : token.value.data,
+ );
+ }, new Map());
+
+ return Object.fromEntries(urlParamsMap);
+};
export const convertToSearchQuery = (filterTokens) =>
filterTokens
diff --git a/app/assets/javascripts/issues/manual_ordering.js b/app/assets/javascripts/issues/manual_ordering.js
index 1bb53dfd50d..f22062cf048 100644
--- a/app/assets/javascripts/issues/manual_ordering.js
+++ b/app/assets/javascripts/issues/manual_ordering.js
@@ -1,5 +1,5 @@
import Sortable from 'sortablejs';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
import { getSortableDefaultOptions, sortableStart } from '~/sortable/utils';
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 149049247fb..c3f87699d58 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
@@ -65,10 +65,10 @@ export default {
<template>
<div v-if="isFetchingMergeRequests || (!isFetchingMergeRequests && totalCount)">
- <div class="card card-slim gl-mt-5 gl-mb-0">
- <div class="card-header gl-bg-gray-10">
+ <div class="card card-slim gl-mt-5 gl-mb-0 gl-bg-gray-10">
+ <div class="card-header gl-px-5 gl-py-4 gl-bg-white">
<div
- class="card-title gl-relative gl-display-flex gl-align-items-center gl-line-height-20 gl-font-weight-bold gl-m-0"
+ class="card-title gl-relative gl-display-flex gl-flex-wrap gl-align-items-center gl-line-height-20 gl-font-weight-bold gl-m-0"
>
<gl-link
class="anchor gl-absolute gl-text-decoration-none"
@@ -79,19 +79,29 @@ export default {
{{ __('Related merge requests') }}
</h3>
<template v-if="totalCount">
- <gl-icon name="merge-request" class="gl-ml-5 gl-mr-2 gl-text-gray-500" />
- <span data-testid="count">{{ totalCount }}</span>
+ <gl-icon name="merge-request" class="gl-ml-3 gl-mr-2 gl-text-gray-500" />
+ <span data-testid="count" class="gl-text-gray-500">{{ totalCount }}</span>
</template>
+ <p
+ v-if="hasClosingMergeRequest && !isFetchingMergeRequests"
+ class="gl-font-sm gl-font-weight-normal gl-flex-basis-full gl-mb-0 gl-text-gray-500"
+ >
+ {{ closingMergeRequestsText }}
+ </p>
</div>
</div>
<gl-loading-icon
v-if="isFetchingMergeRequests"
size="sm"
label="Fetching related merge requests"
- class="gl-py-3"
+ class="gl-py-4"
/>
- <ul v-else class="content-list related-items-list">
- <li v-for="mr in mergeRequests" :key="mr.id" class="list-item gl-m-0! gl-p-0!">
+ <ul v-else class="content-list related-items-list gl-px-4! gl-py-3!">
+ <li
+ v-for="mr in mergeRequests"
+ :key="mr.id"
+ class="list-item gl-m-0! gl-p-0! gl-border-b-0!"
+ >
<related-issuable-item
:id-key="mr.id"
:display-reference="mr.reference"
@@ -110,11 +120,5 @@ export default {
</li>
</ul>
</div>
- <div
- v-if="hasClosingMergeRequest && !isFetchingMergeRequests"
- class="issue-closed-by-widget second-block gl-mt-3"
- >
- {{ closingMergeRequestsText }}
- </div>
</div>
</template>
diff --git a/app/assets/javascripts/issues/related_merge_requests/store/actions.js b/app/assets/javascripts/issues/related_merge_requests/store/actions.js
index 4c81f1d9bc1..ad5b61424dc 100644
--- a/app/assets/javascripts/issues/related_merge_requests/store/actions.js
+++ b/app/assets/javascripts/issues/related_merge_requests/store/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { normalizeHeaders } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/issues/show/components/app.vue b/app/assets/javascripts/issues/show/components/app.vue
index decb559ee81..15f97222971 100644
--- a/app/assets/javascripts/issues/show/components/app.vue
+++ b/app/assets/javascripts/issues/show/components/app.vue
@@ -1,19 +1,20 @@
<script>
import { GlIcon, GlBadge, GlIntersectionObserver, GlTooltipDirective } from '@gitlab/ui';
import Visibility from 'visibilityjs';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import {
IssuableStatusText,
STATUS_CLOSED,
TYPE_EPIC,
+ TYPE_INCIDENT,
TYPE_ISSUE,
- WorkspaceType,
+ WORKSPACE_PROJECT,
} from '~/issues/constants';
import Poll from '~/lib/utils/poll';
import { visitUrl } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
-import { ISSUE_TYPE_PATH, INCIDENT_TYPE_PATH, INCIDENT_TYPE, POLLING_DELAY } from '../constants';
+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';
@@ -25,7 +26,7 @@ import PinnedLinks from './pinned_links.vue';
import TitleComponent from './title.vue';
export default {
- WorkspaceType,
+ WORKSPACE_PROJECT,
components: {
GlIcon,
GlBadge,
@@ -52,11 +53,6 @@ export default {
required: true,
type: Boolean,
},
- showInlineEditButton: {
- type: Boolean,
- required: false,
- default: true,
- },
enableAutocomplete: {
type: Boolean,
required: false,
@@ -191,11 +187,6 @@ export default {
required: false,
default: null,
},
- issueIid: {
- type: Number,
- required: false,
- default: null,
- },
},
data() {
const store = new Store({
@@ -281,7 +272,7 @@ export default {
},
},
created() {
- this.flashContainer = null;
+ this.alert = null;
this.service = new Service(this.endpoint);
this.poll = new Poll({
resource: this.service,
@@ -399,7 +390,7 @@ export default {
? { ...formState, issue_type: issueState.issueType }
: formState;
- this.clearFlash();
+ this.alert?.dismiss();
return this.service
.updateIssuable(issuablePayload)
@@ -407,14 +398,14 @@ export default {
.then((data) => {
if (
!window.location.pathname.includes(data.web_url) &&
- issueState.issueType !== INCIDENT_TYPE
+ issueState.issueType !== TYPE_INCIDENT
) {
visitUrl(data.web_url);
}
if (issueState.isDirty) {
const URI =
- issueState.issueType === INCIDENT_TYPE
+ issueState.issueType === TYPE_INCIDENT
? data.web_url.replace(ISSUE_TYPE_PATH, INCIDENT_TYPE_PATH)
: data.web_url;
visitUrl(URI);
@@ -435,7 +426,7 @@ export default {
errMsg += `. ${message}`;
}
- this.flashContainer = createAlert({
+ this.alert = createAlert({
message: errMsg,
});
})
@@ -452,13 +443,6 @@ export default {
this.isStickyHeaderShowing = true;
},
- clearFlash() {
- if (this.flashContainer) {
- this.flashContainer.close();
- this.flashContainer = null;
- }
- },
-
handleSaveDescription(description) {
this.updateFormState();
this.setFormState({ description });
@@ -509,7 +493,6 @@ export default {
:can-update="canUpdate"
:title-html="state.titleHtml"
:title-text="state.titleText"
- :show-inline-edit-button="showInlineEditButton"
/>
<gl-intersection-observer
@@ -538,7 +521,7 @@ export default {
<confidentiality-badge
v-if="isConfidential"
data-testid="confidential"
- :workspace-type="$options.WorkspaceType.project"
+ :workspace-type="$options.WORKSPACE_PROJECT"
:issuable-type="issuableType"
/>
<span
@@ -570,7 +553,6 @@ export default {
<component
:is="descriptionComponent"
:issue-id="issueId"
- :issue-iid="issueIid"
:can-update="canUpdate"
:description-html="state.descriptionHtml"
:description-text="state.descriptionText"
diff --git a/app/assets/javascripts/issues/show/components/delete_issue_modal.vue b/app/assets/javascripts/issues/show/components/delete_issue_modal.vue
index f86ee11e64b..26e82f10c3d 100644
--- a/app/assets/javascripts/issues/show/components/delete_issue_modal.vue
+++ b/app/assets/javascripts/issues/show/components/delete_issue_modal.vue
@@ -1,5 +1,6 @@
<script>
import { GlModal } from '@gitlab/ui';
+import { TYPE_EPIC } from '~/issues/constants';
import csrf from '~/lib/utils/csrf';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { __, sprintf } from '~/locale';
@@ -40,7 +41,7 @@ export default {
};
},
bodyText() {
- return this.issueType.toLowerCase() === 'epic'
+ return this.issueType.toLowerCase() === TYPE_EPIC
? __('Delete this epic and all descendants?')
: sprintf(__('%{issuableType} will be removed! Are you sure?'), {
issuableType: capitalizeFirstCharacter(this.issueType),
diff --git a/app/assets/javascripts/issues/show/components/description.vue b/app/assets/javascripts/issues/show/components/description.vue
index bca895bf764..bdee6c5fe9a 100644
--- a/app/assets/javascripts/issues/show/components/description.vue
+++ b/app/assets/javascripts/issues/show/components/description.vue
@@ -1,35 +1,26 @@
<script>
-import { GlModalDirective, GlToast } from '@gitlab/ui';
+import { GlToast } from '@gitlab/ui';
import $ from 'jquery';
-import { uniqueId } from 'lodash';
import Sortable from 'sortablejs';
import Vue from 'vue';
import getIssueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils';
-import { TYPENAME_WORK_ITEM } from '~/graphql_shared/constants';
-import { createAlert } from '~/flash';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { TYPENAME_ISSUE, TYPENAME_WORK_ITEM } from '~/graphql_shared/constants';
+import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
-import { isMetaKey } from '~/lib/utils/common_utils';
-import { isPositiveInteger } from '~/lib/utils/number_utils';
-import { getParameterByName, setUrlParams, updateHistory } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale';
import { getSortableDefaultOptions, isDragging } from '~/sortable/utils';
import TaskList from '~/task_list';
-import Tracking from '~/tracking';
import addHierarchyChildMutation from '~/work_items/graphql/add_hierarchy_child.mutation.graphql';
import removeHierarchyChildMutation from '~/work_items/graphql/remove_hierarchy_child.mutation.graphql';
import createWorkItemMutation from '~/work_items/graphql/create_work_item.mutation.graphql';
import deleteWorkItemMutation from '~/work_items/graphql/delete_work_item.mutation.graphql';
-import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import projectWorkItemTypesQuery from '~/work_items/graphql/project_work_item_types.query.graphql';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
import {
sprintfWorkItem,
I18N_WORK_ITEM_ERROR_CREATING,
I18N_WORK_ITEM_ERROR_DELETING,
- TRACKING_CATEGORY_SHOW,
TASK_TYPE_NAME,
} from '~/work_items/constants';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
@@ -51,12 +42,8 @@ const workItemTypes = {
export default {
directives: {
SafeHtml,
- GlModal: GlModalDirective,
},
- components: {
- WorkItemDetailModal,
- },
- mixins: [animateMixin, glFeatureFlagMixin(), Tracking.mixin()],
+ mixins: [animateMixin],
inject: ['fullPath', 'hasIterationsFeature'],
props: {
canUpdate: {
@@ -97,11 +84,6 @@ export default {
required: false,
default: null,
},
- issueIid: {
- type: Number,
- required: false,
- default: null,
- },
isUpdating: {
type: Boolean,
required: false,
@@ -109,18 +91,12 @@ export default {
},
},
data() {
- const workItemId = getParameterByName('work_item_id');
-
return {
hasTaskListItemActions: false,
preAnimation: false,
pulseAnimation: false,
initialUpdate: true,
issueDetails: {},
- activeTask: {},
- workItemId: isPositiveInteger(workItemId)
- ? convertToGraphQLId(TYPENAME_WORK_ITEM, workItemId)
- : undefined,
workItemTypes: [],
};
},
@@ -129,21 +105,12 @@ export default {
query: getIssueDetailsQuery,
variables() {
return {
- fullPath: this.fullPath,
- iid: String(this.issueIid),
- };
- },
- update: (data) => data.workspace?.issuable,
- },
- workItem: {
- query: workItemQuery,
- variables() {
- return {
- id: this.workItemId,
+ id: convertToGraphQLId(TYPENAME_ISSUE, this.issueId),
};
},
+ update: (data) => data.issue,
skip() {
- return !this.workItemId;
+ return !this.canUpdate || !this.issueId;
},
},
workItemTypes: {
@@ -156,10 +123,13 @@ export default {
update(data) {
return data.workspace?.workItemTypes?.nodes;
},
+ skip() {
+ return !this.canUpdate;
+ },
},
},
computed: {
- taskWorkItemType() {
+ taskWorkItemTypeId() {
return this.workItemTypes.find((type) => type.name === TASK_TYPE_NAME)?.id;
},
issueGid() {
@@ -188,12 +158,6 @@ export default {
this.renderGFM();
this.updateTaskStatusText();
- if (this.workItemId) {
- const taskLink = this.$el.querySelector(
- `.gfm-issue[data-issue="${getIdFromGraphQLId(this.workItemId)}"]`,
- );
- this.openWorkItemDetailModal(taskLink);
- }
},
beforeDestroy() {
eventHub.$off('convert-task-list-item', this.convertTaskListItem);
@@ -226,10 +190,10 @@ export default {
},
renderSortableLists() {
// We exclude GLFM table of contents which have a `section-nav` class on the root `ul`.
- const lists = document.querySelectorAll(
+ const lists = this.$el.querySelectorAll?.(
'.description .md > ul:not(.section-nav), .description .md > ul:not(.section-nav) ul, .description ol',
);
- lists.forEach((list) => {
+ lists?.forEach((list) => {
if (list.children.length <= 1) {
return;
}
@@ -358,59 +322,17 @@ export default {
this.$emit('saveDescription', newDescription);
},
renderTaskListItemActions() {
- if (!this.$el?.querySelectorAll) {
- return;
- }
-
- const taskListFields = this.$el.querySelectorAll('.task-list-item:not(.inapplicable)');
-
- taskListFields.forEach((item) => {
- const taskLink = item.querySelector('.gfm-issue');
- if (taskLink) {
- const { issue, referenceType, issueType } = taskLink.dataset;
- if (issueType !== workItemTypes.TASK) {
- return;
- }
- const workItemId = convertToGraphQLId(TYPENAME_WORK_ITEM, issue);
- this.addHoverListeners(taskLink, workItemId);
- taskLink.classList.add('gl-link');
- taskLink.addEventListener('click', (e) => {
- if (isMetaKey(e)) {
- return;
- }
- e.preventDefault();
- this.openWorkItemDetailModal(taskLink);
- this.workItemId = workItemId;
- this.updateWorkItemIdUrlQuery(issue);
- this.track('viewed_work_item_from_modal', {
- category: TRACKING_CATEGORY_SHOW,
- label: 'work_item_view',
- property: `type_${referenceType}`,
- });
- });
- return;
- }
+ const taskListItems = this.$el.querySelectorAll?.(
+ '.task-list-item:not(.inapplicable, table .task-list-item)',
+ );
- const toggleClass = uniqueId('task-list-item-actions-');
- const dropdown = this.createTaskListItemActions({ canUpdate: this.canUpdate, toggleClass });
- this.addPointerEventListeners(item, `.${toggleClass}`);
+ taskListItems?.forEach((item) => {
+ const dropdown = this.createTaskListItemActions({ canUpdate: this.canUpdate });
this.insertNextToTaskListItemText(dropdown, item);
+ this.addPointerEventListeners(item, '.task-list-item-actions');
this.hasTaskListItemActions = true;
});
},
- addHoverListeners(taskLink, id) {
- let workItemPrefetch;
- taskLink.addEventListener('mouseover', () => {
- workItemPrefetch = setTimeout(() => {
- this.workItemId = id;
- }, 150);
- });
- taskLink.addEventListener('mouseout', () => {
- if (workItemPrefetch) {
- clearTimeout(workItemPrefetch);
- }
- });
- },
insertNextToTaskListItemText(element, listItem) {
const children = Array.from(listItem.children);
const paragraph = children.find((el) => el.tagName === 'P');
@@ -427,27 +349,6 @@ export default {
listItem.append(element);
}
},
- setActiveTask(el) {
- const { parentElement } = el;
- const lineNumbers = parentElement.dataset.sourcepos.match(/\b\d+(?=:)/g);
- this.activeTask = {
- title: parentElement.innerText,
- lineNumberStart: lineNumbers[0],
- lineNumberEnd: lineNumbers[1],
- };
- },
- openWorkItemDetailModal(el) {
- if (!el) {
- return;
- }
-
- this.setActiveTask(el);
- this.$refs.detailsModal.show();
- },
- closeWorkItemDetailModal() {
- this.workItemId = undefined;
- this.updateWorkItemIdUrlQuery(undefined);
- },
async createTask({ taskTitle, taskDescription, oldDescription }) {
try {
const { title, description } = extractTaskTitleAndDescription(taskTitle, taskDescription);
@@ -468,7 +369,7 @@ export default {
},
projectPath: this.fullPath,
title,
- workItemTypeId: this.taskWorkItemType,
+ workItemTypeId: this.taskWorkItemTypeId,
};
const { data } = await this.$apollo.mutate({
@@ -532,16 +433,6 @@ export default {
captureError: true,
});
},
- handleDeleteTask(description) {
- this.$emit('updateDescription', description);
- this.$toast.show(s__('WorkItem|Task deleted'));
- },
- updateWorkItemIdUrlQuery(workItemId) {
- updateHistory({
- url: setUrlParams({ work_item_id: workItemId }),
- replace: true,
- });
- },
},
safeHtmlConfig: { ADD_TAGS: ['gl-emoji', 'copy-code'] },
};
@@ -569,16 +460,5 @@ export default {
data-testid="textarea"
>
</textarea>
- <work-item-detail-modal
- ref="detailsModal"
- :can-update="canUpdate"
- :work-item-id="workItemId"
- :issue-gid="issueGid"
- :lock-version="lockVersion"
- :line-number-start="activeTask.lineNumberStart"
- :line-number-end="activeTask.lineNumberEnd"
- @workItemDeleted="handleDeleteTask"
- @close="closeWorkItemDetailModal"
- />
</div>
</template>
diff --git a/app/assets/javascripts/issues/show/components/edit_actions.vue b/app/assets/javascripts/issues/show/components/edit_actions.vue
index 120034b8d67..608e9aec1d7 100644
--- a/app/assets/javascripts/issues/show/components/edit_actions.vue
+++ b/app/assets/javascripts/issues/show/components/edit_actions.vue
@@ -1,17 +1,10 @@
<script>
import { GlButton } from '@gitlab/ui';
-import { __ } from '~/locale';
import Tracking from '~/tracking';
import eventHub from '../event_hub';
import updateMixin from '../mixins/update';
import getIssueStateQuery from '../queries/get_issue_state.query.graphql';
-const issuableTypes = {
- issue: __('Issue'),
- epic: __('Epic'),
- incident: __('Incident'),
-};
-
const trackingMixin = Tracking.mixin({ label: 'delete_issue' });
export default {
@@ -55,11 +48,6 @@ export default {
isSubmitEnabled() {
return this.formState.title.trim() !== '';
},
- typeToShow() {
- const { issueState, issuableType } = this;
- const type = issueState.issueType ?? issuableType;
- return issuableTypes[type];
- },
},
methods: {
closeForm() {
diff --git a/app/assets/javascripts/issues/show/components/fields/description.vue b/app/assets/javascripts/issues/show/components/fields/description.vue
index 3bc24e8ce01..43fe1a7b8ea 100644
--- a/app/assets/javascripts/issues/show/components/fields/description.vue
+++ b/app/assets/javascripts/issues/show/components/fields/description.vue
@@ -75,7 +75,6 @@ export default {
:quick-actions-docs-path="quickActionsDocsPath"
:enable-autocomplete="enableAutocomplete"
supports-quick-actions
- use-bottom-toolbar
autofocus
@input="$emit('input', $event)"
@keydown.meta.enter="updateIssuable"
diff --git a/app/assets/javascripts/issues/show/components/fields/type.vue b/app/assets/javascripts/issues/show/components/fields/type.vue
index 5ade1a86d30..775f25bdbc0 100644
--- a/app/assets/javascripts/issues/show/components/fields/type.vue
+++ b/app/assets/javascripts/issues/show/components/fields/type.vue
@@ -1,8 +1,8 @@
<script>
-import { GlFormGroup, GlIcon, GlListbox } from '@gitlab/ui';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { GlFormGroup, GlIcon, GlCollapsibleListbox } from '@gitlab/ui';
+import { TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import { __ } from '~/locale';
-import { issuableTypes, INCIDENT_TYPE } from '../../constants';
+import { issuableTypes } from '../../constants';
import getIssueStateQuery from '../../queries/get_issue_state.query.graphql';
import updateIssueStateMutation from '../../queries/update_issue_state.mutation.graphql';
@@ -16,7 +16,7 @@ export default {
components: {
GlFormGroup,
GlIcon,
- GlListbox,
+ GlCollapsibleListbox,
},
inject: {
canCreateIncident: {
@@ -46,7 +46,7 @@ export default {
},
computed: {
shouldShowIncident() {
- return this.issueType === INCIDENT_TYPE || this.canCreateIncident;
+ return this.issueType === TYPE_INCIDENT || this.canCreateIncident;
},
},
methods: {
@@ -60,7 +60,7 @@ export default {
});
},
isShown(type) {
- return type.value !== INCIDENT_TYPE || this.shouldShowIncident;
+ return type.value !== TYPE_INCIDENT || this.shouldShowIncident;
},
},
};
@@ -73,7 +73,7 @@ export default {
label-for="issuable-type"
class="mb-2 mb-md-0"
>
- <gl-listbox
+ <gl-collapsible-listbox
v-model="selectedIssueType"
toggle-class="gl-mb-0"
:items="$options.issuableTypes"
@@ -88,6 +88,6 @@ export default {
{{ item.text }}
</span>
</template>
- </gl-listbox>
+ </gl-collapsible-listbox>
</gl-form-group>
</template>
diff --git a/app/assets/javascripts/issues/show/components/header_actions.vue b/app/assets/javascripts/issues/show/components/header_actions.vue
index 9d92b5cf954..84def374d13 100644
--- a/app/assets/javascripts/issues/show/components/header_actions.vue
+++ b/app/assets/javascripts/issues/show/components/header_actions.vue
@@ -2,7 +2,6 @@
import {
GlButton,
GlDropdown,
- GlDropdownDivider,
GlDropdownItem,
GlLink,
GlModal,
@@ -10,9 +9,9 @@ import {
GlTooltipDirective,
} from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { EVENT_ISSUABLE_VUE_APP_CHANGE } from '~/issuable/constants';
-import { IssueType, STATUS_CLOSED } from '~/issues/constants';
+import { STATUS_CLOSED, TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import { ISSUE_STATE_EVENT_CLOSE, ISSUE_STATE_EVENT_REOPEN } from '~/issues/show/constants';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { visitUrl } from '~/lib/utils/url_utility';
@@ -20,6 +19,7 @@ import { s__, __, sprintf } from '~/locale';
import eventHub from '~/notes/event_hub';
import Tracking from '~/tracking';
import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
+import issuesEventHub from '../event_hub';
import promoteToEpicMutation from '../queries/promote_to_epic.mutation.graphql';
import updateIssueMutation from '../queries/update_issue.mutation.graphql';
import DeleteIssueModal from './delete_issue_modal.vue';
@@ -35,6 +35,8 @@ export default {
},
deleteModalId: 'delete-modal-id',
i18n: {
+ edit: __('Edit'),
+ editTitleAndDescription: __('Edit title and description'),
promoteErrorMessage: __(
'Something went wrong while promoting the issue to an epic. Please try again.',
),
@@ -47,7 +49,6 @@ export default {
DeleteIssueModal,
GlButton,
GlDropdown,
- GlDropdownDivider,
GlDropdownItem,
GlLink,
GlModal,
@@ -87,7 +88,7 @@ export default {
default: '',
},
issueType: {
- default: IssueType.Issue,
+ default: TYPE_ISSUE,
},
newIssuePath: {
default: '',
@@ -118,8 +119,8 @@ export default {
},
issueTypeText() {
const issueTypeTexts = {
- [IssueType.Issue]: s__('HeaderAction|issue'),
- [IssueType.Incident]: s__('HeaderAction|incident'),
+ [TYPE_ISSUE]: s__('HeaderAction|issue'),
+ [TYPE_INCIDENT]: s__('HeaderAction|incident'),
};
return issueTypeTexts[this.issueType] ?? this.issueType;
@@ -240,6 +241,9 @@ export default {
this.toggleStateButtonLoading(false);
});
},
+ edit() {
+ issuesEventHub.$emit('open.form');
+ },
},
};
</script>
@@ -255,6 +259,9 @@ export default {
data-testid="mobile-dropdown"
:loading="isToggleStateButtonLoading"
>
+ <gl-dropdown-item v-if="canUpdateIssue" @click="edit">
+ {{ $options.i18n.edit }}
+ </gl-dropdown-item>
<gl-dropdown-item
v-if="showToggleIssueStateButton"
:data-qa-selector="`mobile_${qaSelector}`"
@@ -280,7 +287,6 @@ export default {
{{ __('Submit as spam') }}
</gl-dropdown-item>
<template v-if="canDestroyIssue">
- <gl-dropdown-divider />
<gl-dropdown-item
v-gl-modal="$options.deleteModalId"
variant="danger"
@@ -292,10 +298,23 @@ export default {
</gl-dropdown>
<gl-button
+ v-if="canUpdateIssue"
+ v-gl-tooltip.bottom
+ :title="$options.i18n.editTitleAndDescription"
+ :aria-label="$options.i18n.editTitleAndDescription"
+ class="js-issuable-edit gl-display-none gl-sm-display-block"
+ data-testid="edit-button"
+ @click="edit"
+ >
+ {{ $options.i18n.edit }}
+ </gl-button>
+
+ <gl-button
v-if="showToggleIssueStateButton"
- class="gl-display-none gl-sm-display-inline-flex!"
+ class="gl-display-none gl-sm-display-inline-flex! gl-sm-ml-3"
:data-qa-selector="qaSelector"
:loading="isToggleStateButtonLoading"
+ data-testid="toggle-button"
@click="toggleIssueState"
>
{{ buttonText }}
@@ -304,7 +323,7 @@ export default {
<gl-dropdown
v-if="hasDesktopDropdown"
v-gl-tooltip.hover
- class="gl-display-none gl-sm-display-inline-flex! gl-ml-3"
+ class="gl-display-none gl-sm-display-inline-flex! gl-sm-ml-3"
icon="ellipsis_v"
category="tertiary"
data-qa-selector="issue_actions_ellipsis_dropdown"
@@ -338,8 +357,8 @@ export default {
>
{{ __('Submit as spam') }}
</gl-dropdown-item>
+
<template v-if="canDestroyIssue">
- <gl-dropdown-divider />
<gl-dropdown-item
v-gl-modal="$options.deleteModalId"
variant="danger"
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 40cb7fbb0ff..ac64c35bf15 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
@@ -3,7 +3,7 @@ import { produce } from 'immer';
import { sortBy } from 'lodash';
import { GlIcon } from '@gitlab/ui';
import { sprintf } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_ISSUE } from '~/graphql_shared/constants';
import { timelineFormI18n } from './constants';
@@ -113,7 +113,7 @@ export default {
>
<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-z-index-1"
+ 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"
>
<gl-icon name="comment" class="note-icon" />
</div>
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 997fadec602..4ec64ef838d 100644
--- a/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue
@@ -1,6 +1,6 @@
<script>
import { GlTab, GlTabs } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { trackIncidentDetailsViewsOptions } from '~/incidents/constants';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
@@ -35,7 +35,7 @@ export default {
IncidentMetricTab: () =>
import('ee_component/issues/show/components/incidents/incident_metric_tab.vue'),
},
- inject: ['fullPath', 'iid', 'uploadMetricsFeatureAvailable'],
+ inject: ['fullPath', 'iid', 'hasLinkedAlerts', 'uploadMetricsFeatureAvailable'],
i18n: incidentTabsI18n,
apollo: {
alert: {
@@ -59,20 +59,23 @@ export default {
data() {
return {
alert: null,
- activeTabIndex: 0,
};
},
computed: {
loading() {
return this.$apollo.queries.alert.loading;
},
+ activeTabIndex() {
+ const { tabId } = this.$route.params;
+ return tabId ? this.tabMapping.tabNamesToIndex[tabId] : 0;
+ },
tabMapping() {
const availableTabs = [TAB_NAMES.SUMMARY];
if (this.uploadMetricsFeatureAvailable) {
availableTabs.push(TAB_NAMES.METRICS);
}
- if (this.alert) {
+ if (this.hasLinkedAlerts) {
availableTabs.push(TAB_NAMES.ALERTS);
}
@@ -93,20 +96,25 @@ export default {
return this.activeTabIndex;
},
set(index) {
- this.handleTabChange(index);
- this.activeTabIndex = index;
+ const newPath = `/${this.tabMapping.tabIndexToName[index]}`;
+ // Only push if the new path differs from the old path.
+ if (newPath !== this.$route.path) {
+ this.$router.push(newPath);
+ this.updateJsIssueWidgets(index);
+ }
},
},
},
mounted() {
this.trackPageViews();
+ this.updateJsIssueWidgets(this.activeTabIndex);
},
methods: {
trackPageViews() {
const { category, action } = trackIncidentDetailsViewsOptions;
Tracking.event(category, action);
},
- handleTabChange(tabIndex) {
+ updateJsIssueWidgets(tabIndex) {
/**
* TODO: Implement a solution that does not violate Vue principles in using
* DOM manipulation directly (#361618)
@@ -153,7 +161,7 @@ export default {
<incident-metric-tab />
</gl-tab>
<gl-tab
- v-if="alert"
+ v-if="hasLinkedAlerts"
class="alert-management-details"
:title="$options.i18n.alertsTitle"
data-testid="alert-details-tab"
diff --git a/app/assets/javascripts/issues/show/components/incidents/router.js b/app/assets/javascripts/issues/show/components/incidents/router.js
new file mode 100644
index 00000000000..01326f3b5de
--- /dev/null
+++ b/app/assets/javascripts/issues/show/components/incidents/router.js
@@ -0,0 +1,20 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+
+Vue.use(VueRouter);
+
+export default (currentPath, currentTab = null) => {
+ // If navigating directly to a tab, determine the base
+ // path to initialize router, then set the current route.
+ const base = currentPath.replace(new RegExp(`/${currentTab}$`), '');
+
+ const router = new VueRouter({
+ mode: 'history',
+ base,
+ routes: [{ path: '/:tabId', name: 'tab' }],
+ });
+
+ if (currentTab) router.push(`/${currentTab}`);
+
+ return router;
+};
diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue
index 7944362a40f..243666b2323 100644
--- a/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue
@@ -255,11 +255,10 @@ export default {
</gl-form-group>
</div>
<gl-form-group class="gl-mb-0">
- <div class="gl-display-flex">
+ <div class="gl-display-flex gl-flex-wrap gl-gap-3">
<gl-button
variant="confirm"
category="primary"
- class="gl-mr-3"
data-testid="save-button"
:disabled="!isTimelineTextValid"
:loading="isEventProcessed"
@@ -271,7 +270,6 @@ export default {
v-if="showSaveAndAdd"
variant="confirm"
category="secondary"
- class="gl-mr-3 gl-ml-n2"
data-testid="save-and-add-button"
:disabled="!isTimelineTextValid"
:loading="isEventProcessed"
@@ -279,7 +277,7 @@ export default {
>
{{ $options.i18n.saveAndAdd }}
</gl-button>
- <gl-button class="gl-ml-n2" :disabled="isEventProcessed" @click="$emit('cancel')">
+ <gl-button :disabled="isEventProcessed" @click="$emit('cancel')">
{{ $options.i18n.cancel }}
</gl-button>
<gl-button
diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue
index 10b80529a66..5aef4b1b809 100644
--- a/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue
@@ -1,6 +1,6 @@
<script>
import { formatDate } from '~/lib/utils/datetime_utility';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { sprintf } from '~/locale';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending';
diff --git a/app/assets/javascripts/issues/show/components/incidents/utils.js b/app/assets/javascripts/issues/show/components/incidents/utils.js
index ce33e91c3b8..2072961ce29 100644
--- a/app/assets/javascripts/issues/show/components/incidents/utils.js
+++ b/app/assets/javascripts/issues/show/components/incidents/utils.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
export const displayAndLogError = (error) =>
diff --git a/app/assets/javascripts/issues/show/components/locked_warning.vue b/app/assets/javascripts/issues/show/components/locked_warning.vue
index 4414e693ed0..482aad32daa 100644
--- a/app/assets/javascripts/issues/show/components/locked_warning.vue
+++ b/app/assets/javascripts/issues/show/components/locked_warning.vue
@@ -1,7 +1,13 @@
<script>
import { GlSprintf, GlLink, GlAlert } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
-import { IssuableType } from '~/issues/constants';
+import {
+ TYPE_ALERT,
+ TYPE_EPIC,
+ TYPE_ISSUE,
+ TYPE_MERGE_REQUEST,
+ TYPE_TEST_CASE,
+} from '~/issues/constants';
export const i18n = Object.freeze({
alertMessage: __(
@@ -20,7 +26,9 @@ export default {
type: String,
required: true,
validator(value) {
- return Object.values(IssuableType).includes(value);
+ return [TYPE_ALERT, TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST, TYPE_TEST_CASE].includes(
+ value,
+ );
},
},
},
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 d0beb0f39b3..03d298e0ddf 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
@@ -13,7 +13,7 @@ export default {
GlDropdown,
GlDropdownItem,
},
- inject: ['canUpdate', 'toggleClass'],
+ inject: ['canUpdate'],
methods: {
convertToTask() {
eventHub.$emit('convert-task-list-item', this.$el.closest('li').dataset.sourcepos);
@@ -35,7 +35,7 @@ export default {
right
:text="$options.i18n.taskActions"
text-sr-only
- :toggle-class="`task-list-item-actions gl-opacity-0 gl-p-2! ${toggleClass}`"
+ toggle-class="task-list-item-actions gl-opacity-0 gl-p-2!"
>
<gl-dropdown-item v-if="canUpdate" @click="convertToTask">
{{ $options.i18n.convertToTask }}
diff --git a/app/assets/javascripts/issues/show/components/title.vue b/app/assets/javascripts/issues/show/components/title.vue
index 6978f730e1d..2d2ef327018 100644
--- a/app/assets/javascripts/issues/show/components/title.vue
+++ b/app/assets/javascripts/issues/show/components/title.vue
@@ -1,17 +1,9 @@
<script>
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import { __ } from '~/locale';
-import eventHub from '../event_hub';
import animateMixin from '../mixins/animate';
export default {
- i18n: {
- editTitleAndDescription: __('Edit title and description'),
- },
- components: {
- GlButton,
- },
directives: {
GlTooltip: GlTooltipDirective,
SafeHtml,
@@ -35,11 +27,6 @@ export default {
type: String,
required: true,
},
- showInlineEditButton: {
- type: Boolean,
- required: false,
- default: false,
- },
},
data() {
return {
@@ -60,9 +47,6 @@ export default {
currentPageTitleScope[0] = `${this.titleText} (${this.issuableRef}) `;
this.titleEl.textContent = currentPageTitleScope.join('·');
},
- edit() {
- eventHub.$emit('open.form');
- },
},
};
</script>
@@ -77,16 +61,8 @@ export default {
}"
class="title gl-font-size-h-display"
data-qa-selector="title_content"
+ data-testid="issue-title"
dir="auto"
></h1>
- <gl-button
- v-if="showInlineEditButton && canUpdate"
- v-gl-tooltip.bottom
- icon="pencil"
- class="btn-edit js-issuable-edit"
- :title="$options.i18n.editTitleAndDescription"
- :aria-label="$options.i18n.editTitleAndDescription"
- @click="edit"
- />
</div>
</template>
diff --git a/app/assets/javascripts/issues/show/constants.js b/app/assets/javascripts/issues/show/constants.js
index a100aaf88ad..4d8c11f9669 100644
--- a/app/assets/javascripts/issues/show/constants.js
+++ b/app/assets/javascripts/issues/show/constants.js
@@ -1,6 +1,5 @@
import { __ } from '~/locale';
-export const INCIDENT_TYPE = 'incident';
export const INCIDENT_TYPE_PATH = 'issues/incident';
export const ISSUE_STATE_EVENT_CLOSE = 'CLOSE';
export const ISSUE_STATE_EVENT_REOPEN = 'REOPEN';
diff --git a/app/assets/javascripts/issues/show/index.js b/app/assets/javascripts/issues/show/index.js
index 1793ce66ad4..e677328cd2e 100644
--- a/app/assets/javascripts/issues/show/index.js
+++ b/app/assets/javascripts/issues/show/index.js
@@ -2,14 +2,16 @@ import Vue from 'vue';
import { mapGetters } from 'vuex';
import errorTrackingStore from '~/error_tracking/store';
import { apolloProvider } from '~/graphql_shared/issuable_client';
+import { TYPE_INCIDENT } from '~/issues/constants';
import { parseBoolean } from '~/lib/utils/common_utils';
import { scrollToTargetOnResize } from '~/lib/utils/resize_observer';
import IssueApp from './components/app.vue';
import HeaderActions from './components/header_actions.vue';
import IncidentTabs from './components/incidents/incident_tabs.vue';
import SentryErrorStackTrace from './components/sentry_error_stack_trace.vue';
-import { INCIDENT_TYPE, issueState } from './constants';
+import { issueState } from './constants';
import getIssueStateQuery from './queries/get_issue_state.query.graphql';
+import createRouter from './components/incidents/router';
const bootstrapApollo = (state = {}) => {
return apolloProvider.clients.defaultClient.cache.writeQuery({
@@ -35,23 +37,28 @@ export function initIncidentApp(issueData = {}, store) {
canUpdateTimelineEvent,
iid,
issuableId,
+ currentPath,
+ currentTab,
projectNamespace,
projectPath,
projectId,
+ hasLinkedAlerts,
slaFeatureAvailable,
uploadMetricsFeatureAvailable,
state,
} = issueData;
const fullPath = `${projectNamespace}/${projectPath}`;
+ const router = createRouter(currentPath, currentTab);
return new Vue({
el,
name: 'DescriptionRoot',
apolloProvider,
store,
+ router,
provide: {
- issueType: INCIDENT_TYPE,
+ issueType: TYPE_INCIDENT,
canCreateIncident,
canUpdateTimelineEvent,
canUpdate,
@@ -59,6 +66,7 @@ export function initIncidentApp(issueData = {}, store) {
iid,
issuableId,
projectId,
+ hasLinkedAlerts: parseBoolean(hasLinkedAlerts),
slaFeatureAvailable: parseBoolean(slaFeatureAvailable),
uploadMetricsFeatureAvailable: parseBoolean(uploadMetricsFeatureAvailable),
contentEditorOnIssues: gon.features.contentEditorOnIssues,
@@ -125,7 +133,6 @@ export function initIssueApp(issueData, store) {
isLocked: this.getNoteableData?.discussion_locked,
issuableStatus: this.getNoteableData?.state,
issueId: this.getNoteableData?.id,
- issueIid: this.getNoteableData?.iid,
},
});
},
@@ -142,7 +149,7 @@ export function initHeaderActions(store, type = '') {
bootstrapApollo({ ...issueState, issueType: el.dataset.issueType });
const canCreate =
- type === INCIDENT_TYPE ? el.dataset.canCreateIncident : el.dataset.canCreateIssue;
+ type === TYPE_INCIDENT ? el.dataset.canCreateIncident : el.dataset.canCreateIssue;
return new Vue({
el,
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
new file mode 100644
index 00000000000..f4a0b10672e
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql
@@ -0,0 +1,11 @@
+#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/fragments/ci_variable.fragment.graphql b/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql
new file mode 100644
index 00000000000..0479df7bc4c
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql
@@ -0,0 +1,6 @@
+fragment ManualCiVariable on CiVariable {
+ __typename
+ id
+ key
+ value
+}
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
new file mode 100644
index 00000000000..520deef5136
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql
@@ -0,0 +1,11 @@
+#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
index 2b79892a072..e35d603ea71 100644
--- 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
@@ -1,14 +1,9 @@
+#import "~/jobs/components/job/graphql/fragments/ci_job.fragment.graphql"
+
mutation retryJobWithVariables($id: CiBuildID!, $variables: [CiVariableInput!]) {
jobRetry(input: { id: $id, variables: $variables }) {
job {
- id
- manualVariables {
- nodes {
- id
- key
- value
- }
- }
+ ...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
index aaf1dec8e0f..95e3521091d 100644
--- 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
@@ -1,16 +1,11 @@
+#import "~/jobs/components/job/graphql/fragments/ci_job.fragment.graphql"
+
query getJob($fullPath: ID!, $id: JobID!) {
project(fullPath: $fullPath) {
id
job(id: $id) {
- id
+ ...BaseCiJob
manualJob
- manualVariables {
- nodes {
- id
- key
- value
- }
- }
name
}
}
diff --git a/app/assets/javascripts/jobs/components/job/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job/job_log_controllers.vue
index e9809ac661b..ea7e13418f2 100644
--- a/app/assets/javascripts/jobs/components/job/job_log_controllers.vue
+++ b/app/assets/javascripts/jobs/components/job/job_log_controllers.vue
@@ -103,6 +103,8 @@ export default {
} else {
next();
}
+ }).catch(() => {
+ this.failureCount = null;
});
}
},
diff --git a/app/assets/javascripts/jobs/components/job/manual_variables_form.vue b/app/assets/javascripts/jobs/components/job/manual_variables_form.vue
index 763eb6705aa..19a75ffaa85 100644
--- a/app/assets/javascripts/jobs/components/job/manual_variables_form.vue
+++ b/app/assets/javascripts/jobs/components/job/manual_variables_form.vue
@@ -10,16 +10,17 @@ import {
GlTooltipDirective,
} from '@gitlab/ui';
import { cloneDeep, uniqueId } from 'lodash';
-import { mapActions } from 'vuex';
import { fetchPolicies } from '~/lib/graphql';
-import { createAlert } from '~/flash';
+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';
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
@@ -54,8 +55,9 @@ export default {
const jobVariables = cloneDeep(data?.project?.job?.manualVariables?.nodes);
return [...jobVariables.reverse(), ...this.variables];
},
- error() {
+ error(error) {
createAlert({ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText });
+ reportMessageToSentry(this.$options.name, error, {});
},
},
},
@@ -69,13 +71,14 @@ export default {
required: true,
},
},
- clearBtnSharedClasses: ['gl-flex-grow-0 gl-flex-basis-0'],
+ clearBtnSharedClasses: ['gl-flex-grow-0 gl-flex-basis-0 gl-m-0! gl-ml-3!'],
inputTypes: {
key: 'key',
value: 'value',
},
i18n: {
- clearInputs: s__('CiVariables|Clear inputs'),
+ 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.',
),
@@ -86,14 +89,10 @@ export default {
keyLabel: s__('CiVariables|Key'),
keyPlaceholder: s__('CiVariables|Input variable key'),
runAgainButtonText: s__('CiVariables|Run job again'),
- triggerButtonText: s__('CiVariables|Run job'),
+ runButtonText: s__('CiVariables|Run job'),
valueLabel: s__('CiVariables|Value'),
valuePlaceholder: s__('CiVariables|Input variable value'),
},
- variableValueKeys: {
- rest: 'secret_value',
- gql: 'value',
- },
data() {
return {
job: {},
@@ -104,30 +103,63 @@ export default {
value: '',
},
],
- runAgainBtnDisabled: false,
- triggerBtnDisabled: false,
+ runBtnDisabled: false,
};
},
computed: {
+ mutationVariables() {
+ return {
+ id: convertToGraphQLId(TYPENAME_CI_BUILD, this.jobId),
+ variables: this.preparedVariables,
+ };
+ },
preparedVariables() {
- // filtering out 'id' along with empty variables to send only key, value in the mutation.
- // This will be removed in: https://gitlab.com/gitlab-org/gitlab/-/issues/377268
-
return this.variables
.filter((variable) => variable.key !== '')
- .map(({ key, value }) => ({ key, [this.valueKey]: value }));
+ .map(({ key, value }) => ({ key, value }));
},
- valueKey() {
+ runBtnText() {
return this.isRetryable
- ? this.$options.variableValueKeys.gql
- : this.$options.variableValueKeys.rest;
+ ? this.$options.i18n.runAgainButtonText
+ : this.$options.i18n.runButtonText;
},
variableSettings() {
return helpPagePath('ci/variables/index', { anchor: 'add-a-cicd-variable-to-a-project' });
},
},
methods: {
- ...mapActions(['triggerManualJob']),
+ 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];
@@ -153,37 +185,17 @@ export default {
inputRef(type, id) {
return `${this.$options.inputTypes[type]}-${id}`;
},
- navigateToRetriedJob(retryPath) {
- redirectTo(retryPath);
+ navigateToJob(path) {
+ redirectTo(path);
},
- async retryJob() {
- try {
- const { data } = await this.$apollo.mutate({
- mutation: retryJobWithVariablesMutation,
- variables: {
- id: convertToGraphQLId(TYPENAME_CI_BUILD, this.jobId),
- // we need to ensure no empty variables are passed to the API
- variables: this.preparedVariables,
- },
- });
- if (data.jobRetry?.errors?.length) {
- createAlert({ message: data.jobRetry.errors[0] });
- } else {
- this.navigateToRetriedJob(data.jobRetry?.job?.webPath);
- }
- } catch (error) {
- createAlert({ message: JOB_GRAPHQL_ERRORS.retryMutationErrorText });
- }
- },
- runAgain() {
- this.runAgainBtnDisabled = true;
-
- this.retryJob();
- },
- triggerJob() {
- this.triggerBtnDisabled = true;
+ runJob() {
+ this.runBtnDisabled = true;
- this.triggerManualJob(this.preparedVariables);
+ if (this.isRetryable) {
+ this.retryJob();
+ } else {
+ this.playJob();
+ }
},
},
};
@@ -197,7 +209,7 @@ export default {
<div
v-for="(variable, index) in variables"
:key="variable.id"
- class="gl-display-flex gl-align-items-center gl-mb-4"
+ 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">
@@ -232,12 +244,11 @@ export default {
<gl-button
v-if="canRemove(index)"
v-gl-tooltip
- :aria-label="$options.i18n.clearInputs"
- :title="$options.i18n.clearInputs"
+ :aria-label="$options.i18n.removeInputs"
+ :title="$options.i18n.removeInputs"
:class="$options.clearBtnSharedClasses"
category="tertiary"
- variant="danger"
- icon="clear"
+ icon="remove"
data-testid="delete-variable-btn"
@click="deleteVariable(variable.id)"
/>
@@ -248,8 +259,7 @@ export default {
:class="$options.clearBtnSharedClasses"
data-testid="delete-variable-btn-placeholder"
category="tertiary"
- variant="danger"
- icon="clear"
+ icon="remove"
/>
</div>
@@ -271,37 +281,23 @@ export default {
</template>
</gl-sprintf>
</div>
- <div v-if="isRetryable" class="gl-display-flex gl-justify-content-center gl-mt-5">
+ <div class="gl-display-flex gl-justify-content-center gl-mt-5">
<gl-button
+ v-if="isRetryable"
class="gl-mt-5"
- :aria-label="__('Cancel')"
data-testid="cancel-btn"
@click="$emit('hideManualVariablesForm')"
- >{{ __('Cancel') }}</gl-button
+ >{{ $options.i18n.cancel }}</gl-button
>
<gl-button
class="gl-mt-5"
variant="confirm"
category="primary"
- :aria-label="__('Run manual job again')"
- :disabled="runAgainBtnDisabled"
+ :disabled="runBtnDisabled"
data-testid="run-manual-job-btn"
- @click="runAgain"
- >
- {{ $options.i18n.runAgainButtonText }}
- </gl-button>
- </div>
- <div v-else class="gl-display-flex gl-justify-content-center gl-mt-5">
- <gl-button
- class="gl-mt-5"
- variant="confirm"
- category="primary"
- :aria-label="__('Trigger manual job')"
- :disabled="triggerBtnDisabled"
- data-testid="trigger-manual-job-btn"
- @click="triggerJob"
+ @click="runJob"
>
- {{ $options.i18n.triggerButtonText }}
+ {{ runBtnText }}
</gl-button>
</div>
</div>
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
index 913924cc7b1..a3f1a2c4be8 100644
--- 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
@@ -30,18 +30,16 @@ export default {
return {
primaryProps: {
text: this.$options.i18n.primaryText,
- attributes: [
- {
- 'data-method': 'post',
- 'data-testid': 'retry-button-modal',
- href: this.href,
- variant: 'danger',
- },
- ],
+ 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' }],
+ attributes: { category: 'secondary', variant: 'default' },
},
};
},
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue
index 8100bc2d87a..d791705d80d 100644
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue
+++ b/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import { mapActions } from 'vuex';
-import { createAlert } from '~/flash';
+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';
diff --git a/app/assets/javascripts/jobs/components/table/constants.js b/app/assets/javascripts/jobs/components/table/constants.js
index 41ce6e4d64d..1b572e60c58 100644
--- a/app/assets/javascripts/jobs/components/table/constants.js
+++ b/app/assets/javascripts/jobs/components/table/constants.js
@@ -1,7 +1,6 @@
import { s__, __ } from '~/locale';
/* Error constants */
-export const POST_FAILURE = 'post_failure';
export const DEFAULT = 'default';
export const RAW_TEXT_WARNING = s__(
'Jobs|Raw text search is not currently supported for the jobs filtered search feature. Please use the available search tokens.',
diff --git a/app/assets/javascripts/jobs/components/table/graphql/cache_config.js b/app/assets/javascripts/jobs/components/table/graphql/cache_config.js
index 8bcd7ffd10f..5390c023da4 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/cache_config.js
+++ b/app/assets/javascripts/jobs/components/table/graphql/cache_config.js
@@ -11,42 +11,48 @@ export default {
},
CiJobConnection: {
merge(existing = {}, incoming, { args = {} }) {
- let nodes;
+ if (incoming.nodes) {
+ let nodes;
- const areNodesEqual = isEqual(existing.nodes, incoming.nodes);
- const statuses = Array.isArray(args.statuses) ? [...args.statuses] : args.statuses;
- const { pageInfo } = incoming;
+ const areNodesEqual = isEqual(existing.nodes, incoming.nodes);
+ const statuses = Array.isArray(args.statuses) ? [...args.statuses] : args.statuses;
+ const { pageInfo } = incoming;
- if (Object.keys(existing).length !== 0 && isEqual(existing?.statuses, args?.statuses)) {
- if (areNodesEqual) {
- if (incoming.pageInfo.hasNextPage) {
- nodes = [...existing.nodes, ...incoming.nodes];
+ if (Object.keys(existing).length !== 0 && isEqual(existing?.statuses, args?.statuses)) {
+ if (areNodesEqual) {
+ if (incoming.pageInfo.hasNextPage) {
+ nodes = [...existing.nodes, ...incoming.nodes];
+ } else {
+ nodes = [...incoming.nodes];
+ }
} else {
- nodes = [...incoming.nodes];
- }
- } else {
- if (!existing.pageInfo?.hasNextPage) {
- nodes = [...incoming.nodes];
+ if (!existing.pageInfo?.hasNextPage) {
+ nodes = [...incoming.nodes];
- return {
- nodes,
- statuses,
- pageInfo,
- count: incoming.count,
- };
- }
+ return {
+ nodes,
+ statuses,
+ pageInfo,
+ };
+ }
- nodes = [...existing.nodes, ...incoming.nodes];
+ nodes = [...existing.nodes, ...incoming.nodes];
+ }
+ } else {
+ nodes = [...incoming.nodes];
}
- } else {
- nodes = [...incoming.nodes];
+
+ return {
+ nodes,
+ statuses,
+ pageInfo,
+ };
}
return {
- nodes,
- statuses,
- pageInfo,
- count: incoming.count,
+ nodes: existing.nodes,
+ pageInfo: existing.pageInfo,
+ statuses: args.statuses,
};
},
},
diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
index 851be211b25..69719011079 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
+++ b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
@@ -2,7 +2,6 @@ query getJobs($fullPath: ID!, $after: String, $first: Int = 30, $statuses: [CiJo
project(fullPath: $fullPath) {
id
jobs(after: $after, first: $first, statuses: $statuses) {
- count
pageInfo {
endCursor
hasNextPage
diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql
new file mode 100644
index 00000000000..a4e02ae721a
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql
@@ -0,0 +1,8 @@
+query getJobsCount($fullPath: ID!, $statuses: [CiJobStatus!]) {
+ project(fullPath: $fullPath) {
+ id
+ jobs(statuses: $statuses) {
+ count
+ }
+ }
+}
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
index 3209fc4b90d..3d87cea6445 100644
--- a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
+++ b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
@@ -1,11 +1,12 @@
<script>
import { GlAlert, GlSkeletonLoader, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
import { __ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { setUrlParams, updateHistory, queryToObject } from '~/lib/utils/url_utility';
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';
@@ -13,7 +14,8 @@ import { RAW_TEXT_WARNING } from './constants';
export default {
i18n: {
- errorMsg: __('There was an error fetching the jobs for your project.'),
+ 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:
@@ -43,15 +45,32 @@ export default {
};
},
update(data) {
- const { jobs: { nodes: list = [], pageInfo = {}, count } = {} } = data.project || {};
+ const { jobs: { nodes: list = [], pageInfo = {} } = {} } = data.project || {};
return {
list,
pageInfo,
- count,
};
},
error() {
- this.hasError = true;
+ 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;
},
},
},
@@ -60,11 +79,11 @@ export default {
jobs: {
list: [],
},
- hasError: false,
- isAlertDismissed: false,
+ error: '',
scope: null,
infiniteScrollingTriggered: false,
filterSearchTriggered: false,
+ jobsCount: null,
count: 0,
};
},
@@ -72,9 +91,6 @@ export default {
loading() {
return this.$apollo.queries.jobs.loading;
},
- shouldShowAlert() {
- return this.hasError && !this.isAlertDismissed;
- },
// 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
@@ -95,9 +111,6 @@ export default {
showFilteredSearch() {
return !this.scope;
},
- jobsCount() {
- return this.jobs.count;
- },
validatedQueryString() {
const queryStringObject = queryToObject(window.location.search);
@@ -146,6 +159,7 @@ export default {
});
this.$apollo.queries.jobs.refetch({ statuses: filter.value.data });
+ this.$apollo.queries.jobsCount.refetch({ statuses: filter.value.data });
}
});
},
@@ -168,14 +182,14 @@ export default {
<template>
<div>
<gl-alert
- v-if="shouldShowAlert"
+ v-if="error"
class="gl-mt-2"
variant="danger"
data-testid="jobs-table-error-alert"
dismissible
- @dismiss="isAlertDismissed = true"
+ @dismiss="error = ''"
>
- {{ $options.i18n.errorMsg }}
+ {{ error }}
</gl-alert>
<jobs-table-tabs
diff --git a/app/assets/javascripts/jobs/constants.js b/app/assets/javascripts/jobs/constants.js
index 027d896ba0e..40b3de7edd9 100644
--- a/app/assets/javascripts/jobs/constants.js
+++ b/app/assets/javascripts/jobs/constants.js
@@ -19,7 +19,7 @@ export const JOB_SIDEBAR_COPY = {
};
export const JOB_GRAPHQL_ERRORS = {
- retryMutationErrorText: __('There was an error running the job. Please try again.'),
+ jobMutationErrorText: __('There was an error running the job. Please try again.'),
jobQueryErrorText: __('There was an error fetching the job.'),
};
diff --git a/app/assets/javascripts/jobs/store/actions.js b/app/assets/javascripts/jobs/store/actions.js
index af2d720643f..b348478ccda 100644
--- a/app/assets/javascripts/jobs/store/actions.js
+++ b/app/assets/javascripts/jobs/store/actions.js
@@ -1,5 +1,5 @@
import Visibility from 'visibilityjs';
-import { createAlert } from '~/flash';
+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';
@@ -22,7 +22,7 @@ export const init = ({ dispatch }, { endpoint, logState, pagePath }) => {
pagePath,
});
- return Promise.all([dispatch('fetchJob')]);
+ return dispatch('fetchJob');
};
export const setJobEndpoint = ({ commit }, endpoint) => commit(types.SET_JOB_ENDPOINT, endpoint);
diff --git a/app/assets/javascripts/labels/components/promote_label_modal.vue b/app/assets/javascripts/labels/components/promote_label_modal.vue
index 1b99a094c48..298cc20ab35 100644
--- a/app/assets/javascripts/labels/components/promote_label_modal.vue
+++ b/app/assets/javascripts/labels/components/promote_label_modal.vue
@@ -1,6 +1,6 @@
<script>
import { GlSprintf, GlModal } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import { s__, __, sprintf } from '~/locale';
@@ -9,7 +9,7 @@ import eventHub from '../event_hub';
export default {
primaryProps: {
text: s__('Labels|Promote Label'),
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
cancelProps: {
text: __('Cancel'),
diff --git a/app/assets/javascripts/labels/create_label_dropdown.js b/app/assets/javascripts/labels/create_label_dropdown.js
index 033ca9dd3ea..60ab0c92256 100644
--- a/app/assets/javascripts/labels/create_label_dropdown.js
+++ b/app/assets/javascripts/labels/create_label_dropdown.js
@@ -37,6 +37,8 @@ export default class CreateLabelDropdown {
// eslint-disable-next-line @gitlab/no-global-event-off
this.$newColorField.off('keyup change');
// eslint-disable-next-line @gitlab/no-global-event-off
+ this.$colorPreview.off('keyup change');
+ // eslint-disable-next-line @gitlab/no-global-event-off
this.$dropdownBack.off('click');
// eslint-disable-next-line @gitlab/no-global-event-off
this.$cancelButton.off('click');
@@ -54,6 +56,10 @@ export default class CreateLabelDropdown {
this.$newLabelField.on('keyup change', this.enableLabelCreateButton.bind(this));
this.$newColorField.on('keyup change', this.enableLabelCreateButton.bind(this));
+ this.$colorPreview.on('keyup change', this.enableLabelCreateButton.bind(this));
+
+ this.$newColorField.on('input', this.updateColorPreview.bind(this));
+ this.$colorPreview.on('input', this.updateColorPickerPreview.bind(this));
this.$dropdownBack.on('click', this.resetForm.bind(this));
@@ -73,7 +79,19 @@ export default class CreateLabelDropdown {
e.stopPropagation();
this.$newColorField.val($this.data('color')).trigger('change');
- this.$colorPreview.css('background-color', $this.data('color')).parent().addClass('is-active');
+ this.$colorPreview.val($this.data('color')).trigger('change');
+ }
+
+ updateColorPreview() {
+ const previewColor = this.$newColorField.val();
+ return this.$colorPreview.val(previewColor);
+ // Updates the preview color with the hex-color input
+ }
+
+ updateColorPickerPreview() {
+ const previewColor = this.$colorPreview.val();
+ return this.$newColorField.val(previewColor);
+ // Updates the input color with the hex-color from the picker
}
enableLabelCreateButton() {
@@ -92,7 +110,7 @@ export default class CreateLabelDropdown {
this.$addList.prop('checked', this.addListDefault);
- this.$colorPreview.css('background-color', '').parent().removeClass('is-active');
+ this.$colorPreview.val('');
}
saveLabel(e) {
diff --git a/app/assets/javascripts/labels/group_label_subscription.js b/app/assets/javascripts/labels/group_label_subscription.js
index c4f80d32a83..3683bb5d5e5 100644
--- a/app/assets/javascripts/labels/group_label_subscription.js
+++ b/app/assets/javascripts/labels/group_label_subscription.js
@@ -1,7 +1,8 @@
import $ from 'jquery';
import { __ } from '~/locale';
import { fixTitle, hide } from '~/tooltips';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import axios from '~/lib/utils/axios_utils';
const tooltipTitles = {
@@ -65,7 +66,7 @@ export default class GroupLabelSubscription {
static setNewTooltip($button) {
if (!$button.hasClass('js-subscribe-button')) return;
- const type = $button.hasClass('js-group-level') ? 'group' : 'project';
+ const type = $button.hasClass('js-group-level') ? WORKSPACE_GROUP : WORKSPACE_PROJECT;
const newTitle = tooltipTitles[type];
const $el = $('.js-unsubscribe-button', $button.closest('.label-actions-list'));
diff --git a/app/assets/javascripts/labels/label_manager.js b/app/assets/javascripts/labels/label_manager.js
index be515869bff..f4d7c610cae 100644
--- a/app/assets/javascripts/labels/label_manager.js
+++ b/app/assets/javascripts/labels/label_manager.js
@@ -3,7 +3,7 @@
import $ from 'jquery';
import Sortable from 'sortablejs';
import { dispose } from '~/tooltips';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/labels/labels.js b/app/assets/javascripts/labels/labels.js
index cd8cf0d354c..acb29e1a1f0 100644
--- a/app/assets/javascripts/labels/labels.js
+++ b/app/assets/javascripts/labels/labels.js
@@ -7,29 +7,39 @@ export default class Labels {
this.cleanBinding();
this.addBinding();
this.updateColorPreview();
+ this.updateColorPickerPreview();
}
addBinding() {
$(document).on('click', '.suggest-colors a', this.setSuggestedColor);
+ $(document).on('input', '.label-color-preview', this.updateColorPickerPreview);
return $(document).on('input', 'input#label_color', this.updateColorPreview);
}
// eslint-disable-next-line class-methods-use-this
cleanBinding() {
$(document).off('click', '.suggest-colors a');
+ $(document).off('input', '.label-color-preview');
return $(document).off('input', 'input#label_color');
}
// eslint-disable-next-line class-methods-use-this
updateColorPreview() {
const previewColor = $('input#label_color').val();
- return $('div.label-color-preview').css('background-color', previewColor);
+ return $('.label-color-preview').val(previewColor);
// Updates the preview color with the hex-color input
}
+ // eslint-disable-next-line class-methods-use-this
+ updateColorPickerPreview() {
+ const previewColor = $('.label-color-preview').val();
+ return $('input#label_color').val(previewColor);
+ // Updates the input color with the hex-color from the picker
+ }
// Updates the preview color with a click on a suggested color
setSuggestedColor(e) {
const color = $(e.currentTarget).data('color');
$('input#label_color').val(color);
this.updateColorPreview();
+ this.updateColorPickerPreview();
// Notify the form, that color has changed
$('.label-form').trigger('keyup');
return e.preventDefault();
diff --git a/app/assets/javascripts/labels/labels_select.js b/app/assets/javascripts/labels/labels_select.js
index 515b0a79a03..587cc82f0fa 100644
--- a/app/assets/javascripts/labels/labels_select.js
+++ b/app/assets/javascripts/labels/labels_select.js
@@ -6,7 +6,7 @@ import { difference, isEqual, escape, sortBy, template, union } from 'lodash';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
import IssuableBulkUpdateActions from '~/issuable/issuable_bulk_update_actions';
import { isScopedLabel } from '~/lib/utils/common_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { sprintf, __ } from '~/locale';
import CreateLabelDropdown from './create_label_dropdown';
diff --git a/app/assets/javascripts/labels/project_label_subscription.js b/app/assets/javascripts/labels/project_label_subscription.js
index 9ca6ee5609c..1629d3b4d88 100644
--- a/app/assets/javascripts/labels/project_label_subscription.js
+++ b/app/assets/javascripts/labels/project_label_subscription.js
@@ -1,6 +1,7 @@
import $ from 'jquery';
import { fixTitle } from '~/tooltips';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -68,7 +69,7 @@ export default class ProjectLabelSubscription {
}
static setNewTitle($button, originalTitle, newStatus) {
- const type = /group/.test(originalTitle) ? 'group' : 'project';
+ const type = /group/.test(originalTitle) ? WORKSPACE_GROUP : WORKSPACE_PROJECT;
const newTitle = tooltipTitles[type][newStatus];
$button.attr('title', newTitle);
diff --git a/app/assets/javascripts/layout_nav.js b/app/assets/javascripts/layout_nav.js
index b8138f34d45..f5078962b8f 100644
--- a/app/assets/javascripts/layout_nav.js
+++ b/app/assets/javascripts/layout_nav.js
@@ -70,10 +70,11 @@ function initDeferred() {
}
export default function initLayoutNav() {
- const contextualSidebar = new ContextualSidebar();
- contextualSidebar.bindEvents();
-
- initFlyOutNav();
+ if (!gon.use_new_navigation) {
+ const contextualSidebar = new ContextualSidebar();
+ contextualSidebar.bindEvents();
+ initFlyOutNav();
+ }
requestIdleCallback(initDeferred);
}
diff --git a/app/assets/javascripts/lib/utils/constants.js b/app/assets/javascripts/lib/utils/constants.js
index 2c8953237cf..fb69a61880a 100644
--- a/app/assets/javascripts/lib/utils/constants.js
+++ b/app/assets/javascripts/lib/utils/constants.js
@@ -26,3 +26,8 @@ export const DEFAULT_TH_CLASSES =
export const DRAWER_Z_INDEX = 252;
export const MIN_USERNAME_LENGTH = 2;
+
+export const BYTES_FORMAT_BYTES = 'Bytes';
+export const BYTES_FORMAT_KIB = 'KiB';
+export const BYTES_FORMAT_MIB = 'MiB';
+export const BYTES_FORMAT_GIB = 'GiB';
diff --git a/app/assets/javascripts/lib/utils/error_message.js b/app/assets/javascripts/lib/utils/error_message.js
new file mode 100644
index 00000000000..4cea4257e7b
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/error_message.js
@@ -0,0 +1,20 @@
+export const USER_FACING_ERROR_MESSAGE_PREFIX = 'UF:';
+
+const getMessageFromError = (error = '') => {
+ return error.message || error;
+};
+
+export const parseErrorMessage = (error = '') => {
+ const messageString = getMessageFromError(error);
+
+ if (messageString.startsWith(USER_FACING_ERROR_MESSAGE_PREFIX)) {
+ return {
+ message: messageString.replace(USER_FACING_ERROR_MESSAGE_PREFIX, '').trim(),
+ userFacing: true,
+ };
+ }
+ return {
+ message: messageString,
+ userFacing: false,
+ };
+};
diff --git a/app/assets/javascripts/lib/utils/file_upload.js b/app/assets/javascripts/lib/utils/file_upload.js
index f99a4927338..c80d3f24d07 100644
--- a/app/assets/javascripts/lib/utils/file_upload.js
+++ b/app/assets/javascripts/lib/utils/file_upload.js
@@ -29,3 +29,10 @@ export const validateImageName = (file) => {
const legalImageRegex = /^[\w.\-+]+\.(png|jpg|jpeg|gif|bmp|tiff|ico|webp)$/;
return legalImageRegex.test(fileName) ? fileName : 'image.png';
};
+
+export const validateFileFromAllowList = (fileName, allowList) => {
+ const parts = fileName.split('.');
+ const ext = `.${parts[parts.length - 1]}`;
+
+ return allowList.includes(ext);
+};
diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js
index b0e31fe729b..d64f84d2040 100644
--- a/app/assets/javascripts/lib/utils/number_utils.js
+++ b/app/assets/javascripts/lib/utils/number_utils.js
@@ -1,5 +1,12 @@
import { sprintf, __ } from '~/locale';
-import { BYTES_IN_KIB, THOUSAND } from './constants';
+import {
+ BYTES_IN_KIB,
+ THOUSAND,
+ BYTES_FORMAT_BYTES,
+ BYTES_FORMAT_KIB,
+ BYTES_FORMAT_MIB,
+ BYTES_FORMAT_GIB,
+} from './constants';
/**
* Function that allows a number with an X amount of decimals
@@ -64,25 +71,51 @@ export function bytesToGiB(number) {
}
/**
- * Port of rails number_to_human_size
* Formats the bytes in number into a more understandable
- * representation (e.g., giving it 1500 yields 1.5 KB).
+ * representation. Returns an array with the first value being the human size
+ * and the second value being the format (e.g., [1.5, 'KiB']).
*
* @param {Number} size
* @param {Number} digits - The number of digits to appear after the decimal point
* @returns {String}
*/
-export function numberToHumanSize(size, digits = 2) {
+export function numberToHumanSizeSplit(size, digits = 2) {
const abs = Math.abs(size);
if (abs < BYTES_IN_KIB) {
- return sprintf(__('%{size} bytes'), { size });
+ return [size.toString(), BYTES_FORMAT_BYTES];
} else if (abs < BYTES_IN_KIB ** 2) {
- return sprintf(__('%{size} KiB'), { size: bytesToKiB(size).toFixed(digits) });
+ return [bytesToKiB(size).toFixed(digits), BYTES_FORMAT_KIB];
} else if (abs < BYTES_IN_KIB ** 3) {
- return sprintf(__('%{size} MiB'), { size: bytesToMiB(size).toFixed(digits) });
+ return [bytesToMiB(size).toFixed(digits), BYTES_FORMAT_MIB];
+ }
+ return [bytesToGiB(size).toFixed(digits), BYTES_FORMAT_GIB];
+}
+
+/**
+ * Port of rails number_to_human_size
+ * Formats the bytes in number into a more understandable
+ * representation (e.g., giving it 1500 yields 1.5 KB).
+ *
+ * @param {Number} size
+ * @param {Number} digits - The number of digits to appear after the decimal point
+ * @returns {String}
+ */
+export function numberToHumanSize(size, digits = 2) {
+ const [humanSize, format] = numberToHumanSizeSplit(size, digits);
+
+ switch (format) {
+ case BYTES_FORMAT_BYTES:
+ return sprintf(__('%{size} bytes'), { size: humanSize });
+ case BYTES_FORMAT_KIB:
+ return sprintf(__('%{size} KiB'), { size: humanSize });
+ case BYTES_FORMAT_MIB:
+ return sprintf(__('%{size} MiB'), { size: humanSize });
+ case BYTES_FORMAT_GIB:
+ return sprintf(__('%{size} GiB'), { size: humanSize });
+ default:
+ return '';
}
- return sprintf(__('%{size} GiB'), { size: bytesToGiB(size).toFixed(digits) });
}
/**
diff --git a/app/assets/javascripts/lib/utils/ref_validator.js b/app/assets/javascripts/lib/utils/ref_validator.js
new file mode 100644
index 00000000000..d679a3b4198
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/ref_validator.js
@@ -0,0 +1,145 @@
+import { __, sprintf } from '~/locale';
+
+// this service validates tagName agains git ref format.
+// the git spec can be found here: https://git-scm.com/docs/git-check-ref-format#_description
+
+// the ruby counterpart of the validator is here:
+// lib/gitlab/git_ref_validator.rb
+
+const EXPANDED_PREFIXES = ['refs/heads/', 'refs/remotes/', 'refs/tags'];
+const DISALLOWED_PREFIXES = ['-', '/'];
+const DISALLOWED_POSTFIXES = ['/'];
+const DISALLOWED_NAMES = ['HEAD', '@'];
+const DISALLOWED_SUBSTRINGS = [' ', '\\', '~', ':', '..', '^', '?', '*', '[', '@{'];
+const DISALLOWED_SEQUENCE_POSTFIXES = ['.lock', '.'];
+const DISALLOWED_SEQUENCE_PREFIXES = ['.'];
+
+// eslint-disable-next-line no-control-regex
+const CONTROL_CHARACTERS_REGEX = /[\x00-\x19\x7f]/;
+
+const toReadableString = (array) => array.map((item) => `"${item}"`).join(', ');
+
+const DisallowedPrefixesValidationMessage = sprintf(
+ __('Tag name should not start with %{prefixes}'),
+ {
+ prefixes: toReadableString([...EXPANDED_PREFIXES, ...DISALLOWED_PREFIXES]),
+ },
+ false,
+);
+
+const DisallowedPostfixesValidationMessage = sprintf(
+ __('Tag name should not end with %{postfixes}'),
+ { postfixes: toReadableString(DISALLOWED_POSTFIXES) },
+ false,
+);
+
+const DisallowedNameValidationMessage = sprintf(
+ __('Tag name cannot be one of the following: %{names}'),
+ { names: toReadableString(DISALLOWED_NAMES) },
+ false,
+);
+
+const EmptyNameValidationMessage = __('Tag name should not be empty');
+
+const DisallowedSubstringsValidationMessage = sprintf(
+ __('Tag name should not contain any of the following: %{substrings}'),
+ { substrings: toReadableString(DISALLOWED_SUBSTRINGS) },
+ false,
+);
+
+const DisallowedSequenceEmptyValidationMessage = __(
+ `No slash-separated tag name component can be empty`,
+);
+
+const DisallowedSequencePrefixesValidationMessage = sprintf(
+ __('No slash-separated component can begin with %{sequencePrefixes}'),
+ { sequencePrefixes: toReadableString(DISALLOWED_SEQUENCE_PREFIXES) },
+ false,
+);
+
+const DisallowedSequencePostfixesValidationMessage = sprintf(
+ __('No slash-separated component can end with %{sequencePostfixes}'),
+ { sequencePostfixes: toReadableString(DISALLOWED_SEQUENCE_POSTFIXES) },
+ false,
+);
+
+const ControlCharactersValidationMessage = __('Tag name should not contain any control characters');
+
+export const validationMessages = {
+ EmptyNameValidationMessage,
+ DisallowedPrefixesValidationMessage,
+ DisallowedPostfixesValidationMessage,
+ DisallowedNameValidationMessage,
+ DisallowedSubstringsValidationMessage,
+ DisallowedSequenceEmptyValidationMessage,
+ DisallowedSequencePrefixesValidationMessage,
+ DisallowedSequencePostfixesValidationMessage,
+ ControlCharactersValidationMessage,
+};
+
+export class ValidationResult {
+ isValid = true;
+ validationErrors = [];
+
+ addValidationError = (errorMessage) => {
+ this.isValid = false;
+ this.validationErrors.push(errorMessage);
+ };
+}
+
+export const validateTag = (refName) => {
+ if (typeof refName !== 'string') {
+ throw new Error('refName argument must be a string');
+ }
+
+ const validationResult = new ValidationResult();
+
+ if (!refName || refName.trim() === '') {
+ validationResult.addValidationError(EmptyNameValidationMessage);
+ return validationResult;
+ }
+
+ if (CONTROL_CHARACTERS_REGEX.test(refName)) {
+ validationResult.addValidationError(ControlCharactersValidationMessage);
+ }
+
+ if (DISALLOWED_NAMES.some((name) => name === refName)) {
+ validationResult.addValidationError(DisallowedNameValidationMessage);
+ }
+
+ if ([...EXPANDED_PREFIXES, ...DISALLOWED_PREFIXES].some((prefix) => refName.startsWith(prefix))) {
+ validationResult.addValidationError(DisallowedPrefixesValidationMessage);
+ }
+
+ if (DISALLOWED_POSTFIXES.some((postfix) => refName.endsWith(postfix))) {
+ validationResult.addValidationError(DisallowedPostfixesValidationMessage);
+ }
+
+ if (DISALLOWED_SUBSTRINGS.some((substring) => refName.includes(substring))) {
+ validationResult.addValidationError(DisallowedSubstringsValidationMessage);
+ }
+
+ const refNameParts = refName.split('/');
+
+ if (refNameParts.some((part) => part === '')) {
+ validationResult.addValidationError(DisallowedSequenceEmptyValidationMessage);
+ }
+
+ if (
+ refNameParts.some((part) =>
+ DISALLOWED_SEQUENCE_PREFIXES.some((prefix) => part.startsWith(prefix)),
+ )
+ ) {
+ validationResult.addValidationError(DisallowedSequencePrefixesValidationMessage);
+ }
+
+ if (
+ refNameParts.some((part) =>
+ DISALLOWED_SEQUENCE_POSTFIXES.some((postfix) => part.endsWith(postfix)),
+ )
+ ) {
+ validationResult.addValidationError(DisallowedSequencePostfixesValidationMessage);
+ }
+
+ return validationResult;
+};
diff --git a/app/assets/javascripts/lib/utils/resize_observer.js b/app/assets/javascripts/lib/utils/resize_observer.js
index 5d194340b9e..1db863294f8 100644
--- a/app/assets/javascripts/lib/utils/resize_observer.js
+++ b/app/assets/javascripts/lib/utils/resize_observer.js
@@ -19,27 +19,31 @@ export function createResizeObserver() {
* @param {Object} options
* @param {string} options.targetId - id of element to scroll to
* @param {string} options.container - Selector of element containing target
+ * @param {Element} options.component - Element containing target
*
* @return {ResizeObserver|null} - ResizeObserver instance if target looks like a note DOM ID
*/
export function scrollToTargetOnResize({
targetId = window.location.hash.slice(1),
container = '#content-body',
+ containerId,
} = {}) {
if (!targetId) return null;
const ro = createResizeObserver();
- const containerEl = document.querySelector(container);
+ const containerEl =
+ document.querySelector(`#${containerId}`) || document.querySelector(container);
let interactionListenersAdded = false;
- function keepTargetAtTop() {
+ function keepTargetAtTop(evt) {
const anchorEl = document.getElementById(targetId);
+ const scrollContainer = containerId ? evt.target : document.documentElement;
if (!anchorEl) return;
const anchorTop = anchorEl.getBoundingClientRect().top + window.scrollY;
const top = anchorTop - contentTop();
- document.documentElement.scrollTo({
+ scrollContainer.scrollTo({
top,
});
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index 05ed08931bb..2d5e9bc91f2 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -2,6 +2,7 @@
import $ from 'jquery';
import Shortcuts from '~/behaviors/shortcuts/shortcuts';
import { insertText } from '~/lib/utils/common_utils';
+import axios from '~/lib/utils/axios_utils';
const LINK_TAG_PATTERN = '[{text}](url)';
const INDENT_CHAR = ' ';
@@ -625,11 +626,11 @@ export function addMarkdownListeners(form) {
Shortcuts.initMarkdownEditorShortcuts($(this), updateTextForToolbarBtn);
});
- // eslint-disable-next-line @gitlab/no-global-event-off
- const $allToolbarBtns = $('.js-md', form)
- .off('click')
- .on('click', function () {
- const $toolbarBtn = $(this);
+ const $allToolbarBtns = $(form)
+ .off('click', '.js-md, .saved-replies-dropdown li')
+ .on('click', '.js-md, .saved-replies-dropdown li', function () {
+ const $savedReplyContent = $('.js-saved-reply-content', this);
+ const $toolbarBtn = $savedReplyContent.length ? $savedReplyContent : $(this);
return updateTextForToolbarBtn($toolbarBtn);
});
@@ -669,3 +670,50 @@ export function removeMarkdownListeners(form) {
// eslint-disable-next-line @gitlab/no-global-event-off
return $('.js-md', form).off('click');
}
+
+/**
+ * If the textarea cursor is positioned in a Markdown image declaration,
+ * it uses the Markdown API to resolve the image’s absolute URL.
+ * @param {Object} textarea Textarea DOM element
+ * @param {String} markdownPreviewPath Markdown API path
+ * @returns {Object} an object containing the image’s absolute URL, filename,
+ * and the markdown declaration. If the textarea cursor is not positioned
+ * in an image, it returns null.
+ */
+export const resolveSelectedImage = async (textArea, markdownPreviewPath = '') => {
+ const { lines, startPos } = linesFromSelection(textArea);
+
+ // image declarations can’t span more than one line in Markdown
+ if (lines > 0) {
+ return null;
+ }
+
+ const selectedLine = lines[0];
+
+ if (!/!\[.+?\]\(.+?\)/.test(selectedLine)) return null;
+
+ const lineSelectionStart = textArea.selectionStart - startPos;
+ const preExlm = selectedLine.substring(0, lineSelectionStart).lastIndexOf('!');
+ const postClose = selectedLine.substring(lineSelectionStart).indexOf(')');
+
+ if (preExlm >= 0 && postClose >= 0) {
+ const imageMarkdown = selectedLine.substring(preExlm, lineSelectionStart + postClose + 1);
+ const { data } = await axios.post(markdownPreviewPath, { text: imageMarkdown });
+ const parser = new DOMParser();
+
+ const dom = parser.parseFromString(data.body, 'text/html');
+ const imageURL = dom.body.querySelector('a').getAttribute('href');
+
+ if (imageURL) {
+ const filename = imageURL.substring(imageURL.lastIndexOf('/') + 1);
+
+ return {
+ imageMarkdown,
+ imageURL,
+ filename,
+ };
+ }
+ }
+
+ return null;
+};
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index 367180714df..1bed38b7dbe 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -1,4 +1,5 @@
import { isString, memoize } from 'lodash';
+import { sprintf, __ } from '~/locale';
import { base64ToBuffer, bufferToBase64 } from '~/authentication/webauthn/util';
import {
TRUNCATE_WIDTH_DEFAULT_WIDTH,
@@ -525,3 +526,45 @@ export function base64DecodeUnicode(str) {
const decoder = new TextDecoder('utf8');
return decoder.decode(base64ToBuffer(str));
}
+
+// returns an array of errors (if there are any)
+const INVALID_BRANCH_NAME_CHARS = [' ', '~', '^', ':', '?', '*', '[', '..', '@{', '\\', '//'];
+
+/**
+ * Returns an array of invalid characters found in a branch name
+ *
+ * @param {String} name branch name to check
+ * @return {Array} Array of invalid characters found
+ */
+export const findInvalidBranchNameCharacters = (name) => {
+ const invalidChars = [];
+
+ INVALID_BRANCH_NAME_CHARS.forEach((pattern) => {
+ if (name.indexOf(pattern) > -1) {
+ invalidChars.push(pattern);
+ }
+ });
+
+ return invalidChars;
+};
+
+/**
+ * Returns a string describing validation errors for a branch name
+ *
+ * @param {Array} invalidChars Array of invalid characters that were found
+ * @return {String} Error message describing on the invalid characters found
+ */
+export const humanizeBranchValidationErrors = (invalidChars = []) => {
+ const chars = invalidChars.filter((c) => INVALID_BRANCH_NAME_CHARS.includes(c));
+
+ if (chars.length && !chars.includes(' ')) {
+ return sprintf(__("Can't contain %{chars}"), { chars: chars.join(', ') });
+ } else if (chars.includes(' ') && chars.length <= 1) {
+ return __("Can't contain spaces");
+ } else if (chars.includes(' ') && chars.length > 1) {
+ return sprintf(__("Can't contain spaces, %{chars}"), {
+ chars: chars.filter((c) => c !== ' ').join(', '),
+ });
+ }
+ return '';
+};
diff --git a/app/assets/javascripts/lib/utils/vue3compat/compat_functional_mixin.js b/app/assets/javascripts/lib/utils/vue3compat/compat_functional_mixin.js
new file mode 100644
index 00000000000..ec8feb7d2e6
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/vue3compat/compat_functional_mixin.js
@@ -0,0 +1,14 @@
+import Vue from 'vue';
+
+export const compatFunctionalMixin = Vue.version.startsWith('3')
+ ? {
+ created() {
+ this.props = this.$props;
+ this.listeners = this.$listeners;
+ },
+ }
+ : {
+ created() {
+ throw new Error('This mixin should not be executed in Vue.js 2');
+ },
+ };
diff --git a/app/assets/javascripts/lib/utils/vue3compat/mark_raw.js b/app/assets/javascripts/lib/utils/vue3compat/mark_raw.js
new file mode 100644
index 00000000000..daafbad8ba1
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/vue3compat/mark_raw.js
@@ -0,0 +1,9 @@
+// this will be replaced by markRaw from vue.js v3
+export function markRaw(obj) {
+ Object.defineProperty(obj, '__v_skip', {
+ value: true,
+ configurable: true,
+ });
+
+ return obj;
+}
diff --git a/app/assets/javascripts/locale/sprintf.js b/app/assets/javascripts/locale/sprintf.js
index c8c6b51f374..12df67670f9 100644
--- a/app/assets/javascripts/locale/sprintf.js
+++ b/app/assets/javascripts/locale/sprintf.js
@@ -22,7 +22,9 @@ export default (input, parameters, escapeParameters = true) => {
mappedParameters.forEach((key, parameterName) => {
const parameterValue = mappedParameters.get(parameterName);
const escapedParameterValue = escapeParameters ? escape(parameterValue) : parameterValue;
- output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), escapedParameterValue);
+ // Pass the param value as a function to ignore special replacement patterns like $` and $'.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#syntax
+ output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), () => escapedParameterValue);
});
}
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 4c715c4993f..a1539aba786 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -89,7 +89,7 @@ initRails();
function deferredInitialisation() {
const $body = $('body');
- initTopNav();
+ if (!gon.use_new_navigation) initTopNav();
initBreadcrumbs();
initTodoToggle();
initPrefetchLinks('.js-prefetch-document');
@@ -104,14 +104,6 @@ function deferredInitialisation() {
initCopyCodeButton();
initGitlabVersionCheck();
- // Init super sidebar
- if (gon.use_new_navigation) {
- // eslint-disable-next-line promise/catch-or-return
- import('./super_sidebar/super_sidebar_bundle').then(({ initSuperSidebar }) => {
- initSuperSidebar();
- });
- }
-
addSelectOnFocusBehaviour('.js-select-on-focus');
const glTooltipDelay = localStorage.getItem('gl-tooltip-delay');
diff --git a/app/assets/javascripts/members/constants.js b/app/assets/javascripts/members/constants.js
index 68c5831db62..8e5b88d362e 100644
--- a/app/assets/javascripts/members/constants.js
+++ b/app/assets/javascripts/members/constants.js
@@ -192,8 +192,6 @@ export const MEMBER_STATE_ACTIVE = 2;
export const BADGE_LABELS_AWAITING_SIGNUP = __('Awaiting user signup');
export const BADGE_LABELS_PENDING = __('Pending owner action');
-export const DAYS_TO_EXPIRE_SOON = 7;
-
export const LEAVE_MODAL_ID = 'member-leave-modal';
export const REMOVE_GROUP_LINK_MODAL_ID = 'remove-group-link-modal-id';
diff --git a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue
index 707e8a0645f..c6feb684795 100644
--- a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue
+++ b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue
@@ -2,7 +2,7 @@
import { GlButton } from '@gitlab/ui';
import { debounce } from 'lodash';
import { mapActions } from 'vuex';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import { INTERACTIVE_RESOLVE_MODE } from '../constants';
diff --git a/app/assets/javascripts/merge_conflicts/store/actions.js b/app/assets/javascripts/merge_conflicts/store/actions.js
index f84eaabf9e7..07a32a77c6a 100644
--- a/app/assets/javascripts/merge_conflicts/store/actions.js
+++ b/app/assets/javascripts/merge_conflicts/store/actions.js
@@ -1,5 +1,5 @@
import { setCookie } from '~/lib/utils/common_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import { INTERACTIVE_RESOLVE_MODE, EDIT_RESOLVE_MODE } from '../constants';
diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js
index 61abdca0a5b..4277e535d20 100644
--- a/app/assets/javascripts/merge_request.js
+++ b/app/assets/javascripts/merge_request.js
@@ -1,7 +1,8 @@
/* eslint-disable func-names, no-underscore-dangle, consistent-return */
import $ from 'jquery';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { TYPE_MERGE_REQUEST } from '~/issues/constants';
import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale';
import eventHub from '~/vue_merge_request_widget/event_hub';
@@ -27,7 +28,7 @@ function MergeRequest(opts) {
if ($('.description.js-task-list-container').length) {
this.taskList = new TaskList({
- dataType: 'merge_request',
+ dataType: TYPE_MERGE_REQUEST,
fieldName: 'description',
selector: '.detail-page-description',
lockVersion: this.$el.data('lockVersion'),
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 46ee8fecfc5..d55e942dafa 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -1,7 +1,7 @@
/* eslint-disable class-methods-use-this */
import $ from 'jquery';
import Vue from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { getCookie, isMetaClick, parseBoolean, scrollToElement } from '~/lib/utils/common_utils';
import { parseUrlPathname } from '~/lib/utils/url_utility';
import createEventHub from '~/helpers/event_hub_factory';
diff --git a/app/assets/javascripts/merge_requests/components/compare_dropdown.vue b/app/assets/javascripts/merge_requests/components/compare_dropdown.vue
index 1590e693c07..a5a4e683214 100644
--- a/app/assets/javascripts/merge_requests/components/compare_dropdown.vue
+++ b/app/assets/javascripts/merge_requests/components/compare_dropdown.vue
@@ -1,13 +1,13 @@
<script>
-import { GlListbox } from '@gitlab/ui';
+import { GlCollapsibleListbox } from '@gitlab/ui';
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
export default {
components: {
- GlListbox,
+ GlCollapsibleListbox,
},
props: {
staticData: {
@@ -124,7 +124,7 @@ export default {
:name="inputName"
data-testid="target-project-input"
/>
- <gl-listbox
+ <gl-collapsible-listbox
v-model="selected"
:items="filteredData"
:toggle-text="current.text || dropdownHeader"
diff --git a/app/assets/javascripts/milestones/components/delete_milestone_modal.vue b/app/assets/javascripts/milestones/components/delete_milestone_modal.vue
index 4b3c1bd7d10..8e7428089e2 100644
--- a/app/assets/javascripts/milestones/components/delete_milestone_modal.vue
+++ b/app/assets/javascripts/milestones/components/delete_milestone_modal.vue
@@ -1,6 +1,6 @@
<script>
import { GlSprintf, GlModal } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
import { redirectTo } from '~/lib/utils/url_utility';
@@ -103,7 +103,7 @@ Once deleted, it cannot be undone or recovered.`),
},
primaryProps: {
text: s__('Milestones|Delete milestone'),
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
},
cancelProps: {
text: __('Cancel'),
diff --git a/app/assets/javascripts/milestones/components/promote_milestone_modal.vue b/app/assets/javascripts/milestones/components/promote_milestone_modal.vue
index 9e537fa2c82..63791dcd011 100644
--- a/app/assets/javascripts/milestones/components/promote_milestone_modal.vue
+++ b/app/assets/javascripts/milestones/components/promote_milestone_modal.vue
@@ -1,6 +1,6 @@
<script>
import { GlModal } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale';
@@ -80,11 +80,11 @@ export default {
},
primaryAction: {
text: s__('Milestones|Promote Milestone'),
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
cancelAction: {
text: __('Cancel'),
- attributes: [],
+ attributes: {},
},
};
</script>
diff --git a/app/assets/javascripts/milestones/milestone.js b/app/assets/javascripts/milestones/milestone.js
index d9e72340d62..20cc0352c33 100644
--- a/app/assets/javascripts/milestones/milestone.js
+++ b/app/assets/javascripts/milestones/milestone.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { sanitize } from '~/lib/dompurify';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/mirrors/mirror_repos.js b/app/assets/javascripts/mirrors/mirror_repos.js
index 2995f19c470..299c9731ad7 100644
--- a/app/assets/javascripts/mirrors/mirror_repos.js
+++ b/app/assets/javascripts/mirrors/mirror_repos.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import { hide } from '~/tooltips';
diff --git a/app/assets/javascripts/mirrors/ssh_mirror.js b/app/assets/javascripts/mirrors/ssh_mirror.js
index 037120a0d81..68b18a34ded 100644
--- a/app/assets/javascripts/mirrors/ssh_mirror.js
+++ b/app/assets/javascripts/mirrors/ssh_mirror.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { escape } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { backOff } from '~/lib/utils/common_utils';
import { HTTP_STATUS_NO_CONTENT } from '~/lib/utils/http_status';
diff --git a/app/assets/javascripts/ml/experiment_tracking/components/ml_candidate.vue b/app/assets/javascripts/ml/experiment_tracking/components/ml_candidate.vue
deleted file mode 100644
index d0c42905ee2..00000000000
--- a/app/assets/javascripts/ml/experiment_tracking/components/ml_candidate.vue
+++ /dev/null
@@ -1,115 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-import { __ } from '~/locale';
-import { FEATURE_NAME, FEATURE_FEEDBACK_ISSUE } from '~/ml/experiment_tracking/constants';
-import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
-
-export default {
- name: 'MlCandidate',
- components: {
- IncubationAlert,
- GlLink,
- },
- props: {
- candidate: {
- type: Object,
- required: true,
- },
- },
- i18n: {
- titleLabel: __('Model candidate details'),
- infoLabel: __('Info'),
- idLabel: __('ID'),
- statusLabel: __('Status'),
- experimentLabel: __('Experiment'),
- artifactsLabel: __('Artifacts'),
- parametersLabel: __('Parameters'),
- metricsLabel: __('Metrics'),
- metadataLabel: __('Metadata'),
- },
- computed: {
- sections() {
- return [
- {
- sectionName: this.$options.i18n.parametersLabel,
- sectionValues: this.candidate.params,
- },
- {
- sectionName: this.$options.i18n.metricsLabel,
- sectionValues: this.candidate.metrics,
- },
- {
- sectionName: this.$options.i18n.metadataLabel,
- sectionValues: this.candidate.metadata,
- },
- ];
- },
- },
- FEATURE_NAME,
- FEATURE_FEEDBACK_ISSUE,
-};
-</script>
-
-<template>
- <div>
- <incubation-alert
- :feature-name="$options.FEATURE_NAME"
- :link-to-feedback-issue="$options.FEATURE_FEEDBACK_ISSUE"
- />
-
- <h3>
- {{ $options.i18n.titleLabel }}
- </h3>
-
- <table class="candidate-details">
- <tbody>
- <tr class="divider"></tr>
-
- <tr>
- <td class="gl-text-secondary gl-font-weight-bold">{{ $options.i18n.infoLabel }}</td>
- <td class="gl-font-weight-bold">{{ $options.i18n.idLabel }}</td>
- <td>{{ candidate.info.iid }}</td>
- </tr>
-
- <tr>
- <td></td>
- <td class="gl-font-weight-bold">{{ $options.i18n.statusLabel }}</td>
- <td>{{ candidate.info.status }}</td>
- </tr>
-
- <tr>
- <td></td>
- <td class="gl-font-weight-bold">{{ $options.i18n.experimentLabel }}</td>
- <td>
- <gl-link :href="candidate.info.path_to_experiment">{{
- candidate.info.experiment_name
- }}</gl-link>
- </td>
- </tr>
-
- <tr v-if="candidate.info.path_to_artifact">
- <td></td>
- <td class="gl-font-weight-bold">{{ $options.i18n.artifactsLabel }}</td>
- <td>
- <gl-link :href="candidate.info.path_to_artifact">{{
- $options.i18n.artifactsLabel
- }}</gl-link>
- </td>
- </tr>
-
- <template v-for="{ sectionName, sectionValues } in sections">
- <tr :key="sectionName" class="divider"></tr>
-
- <tr v-for="(item, index) in sectionValues" :key="item.name">
- <td v-if="index === 0" class="gl-text-secondary gl-font-weight-bold">
- {{ sectionName }}
- </td>
- <td v-else></td>
- <td class="gl-font-weight-bold">{{ item.name }}</td>
- <td>{{ item.value }}</td>
- </tr>
- </template>
- </tbody>
- </table>
- </div>
-</template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue b/app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue
deleted file mode 100644
index c09aabb0d40..00000000000
--- a/app/assets/javascripts/ml/experiment_tracking/components/ml_experiment.vue
+++ /dev/null
@@ -1,200 +0,0 @@
-<script>
-import { GlTable, GlLink, GlTooltipDirective } from '@gitlab/ui';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
-import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
-import {
- LIST_KEY_CREATED_AT,
- BASE_SORT_FIELDS,
- METRIC_KEY_PREFIX,
- FEATURE_NAME,
- FEATURE_FEEDBACK_ISSUE,
-} from '~/ml/experiment_tracking/constants';
-import { s__ } from '~/locale';
-import { queryToObject, setUrlParams, visitUrl } from '~/lib/utils/url_utility';
-import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
-import KeysetPagination from '~/vue_shared/components/incubation/pagination.vue';
-import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
-
-export default {
- name: 'MlExperiment',
- components: {
- GlTable,
- GlLink,
- TimeAgo,
- IncubationAlert,
- RegistrySearch,
- KeysetPagination,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- inject: ['candidates', 'metricNames', 'paramNames', 'pageInfo'],
- data() {
- const query = queryToObject(window.location.search);
-
- const filter = query.name ? [{ value: { data: query.name }, type: FILTERED_SEARCH_TERM }] : [];
-
- let orderBy = query.orderBy || LIST_KEY_CREATED_AT;
-
- if (query.orderByType === 'metric') {
- orderBy = `${METRIC_KEY_PREFIX}${orderBy}`;
- }
-
- return {
- filters: filter,
- sorting: {
- orderBy,
- sort: (query.sort || 'desc').toLowerCase(),
- },
- };
- },
- computed: {
- fields() {
- if (this.candidates.length === 0) return [];
-
- return [
- { key: 'name', label: this.$options.i18n.nameLabel },
- { key: 'created_at', label: this.$options.i18n.createdAtLabel },
- { key: 'user', label: this.$options.i18n.userLabel },
- ...this.paramNames,
- ...this.metricNames,
- { key: 'details', label: '' },
- { key: 'artifact', label: '' },
- ];
- },
- displayPagination() {
- return this.candidates.length > 0;
- },
- sortableFields() {
- return [
- ...BASE_SORT_FIELDS,
- ...this.metricNames.map((name) => ({
- orderBy: `${METRIC_KEY_PREFIX}${name}`,
- label: capitalizeFirstCharacter(name),
- })),
- ];
- },
- parsedQuery() {
- const name = this.filters
- .map((f) => f.value.data)
- .join(' ')
- .trim();
-
- const filterByQuery = name === '' ? {} : { name };
-
- let orderByType = 'column';
- let { orderBy } = this.sorting;
- const { sort } = this.sorting;
-
- if (orderBy.startsWith(METRIC_KEY_PREFIX)) {
- orderBy = this.sorting.orderBy.slice(METRIC_KEY_PREFIX.length);
- orderByType = 'metric';
- }
-
- return { ...filterByQuery, orderBy, orderByType, sort };
- },
- },
- methods: {
- submitFilters() {
- return visitUrl(setUrlParams({ ...this.parsedQuery }));
- },
- updateFilters(newValue) {
- this.filters = newValue;
- },
- updateSorting(newValue) {
- this.sorting = { ...this.sorting, ...newValue };
- },
- updateSortingAndEmitUpdate(newValue) {
- this.updateSorting(newValue);
- this.submitFilters();
- },
- },
- i18n: {
- titleLabel: s__('MlExperimentTracking|Experiment candidates'),
- emptyStateLabel: s__('MlExperimentTracking|No candidates to display'),
- artifactsLabel: s__('MlExperimentTracking|Artifacts'),
- detailsLabel: s__('MlExperimentTracking|Details'),
- userLabel: s__('MlExperimentTracking|User'),
- createdAtLabel: s__('MlExperimentTracking|Created at'),
- nameLabel: s__('MlExperimentTracking|Name'),
- noDataContent: s__('MlExperimentTracking|-'),
- filterCandidatesLabel: s__('MlExperimentTracking|Filter candidates'),
- },
- FEATURE_NAME,
- FEATURE_FEEDBACK_ISSUE,
-};
-</script>
-
-<template>
- <div>
- <incubation-alert
- :feature-name="$options.FEATURE_NAME"
- :link-to-feedback-issue="$options.FEATURE_FEEDBACK_ISSUE"
- />
-
- <h3>
- {{ $options.i18n.titleLabel }}
- </h3>
-
- <registry-search
- :filters="filters"
- :sorting="sorting"
- :sortable-fields="sortableFields"
- @sorting:changed="updateSortingAndEmitUpdate"
- @filter:changed="updateFilters"
- @filter:submit="submitFilters"
- @filter:clear="filters = []"
- />
-
- <gl-table
- :fields="fields"
- :items="candidates"
- :empty-text="$options.i18n.emptyStateLabel"
- show-empty
- small
- class="gl-mt-0! ml-candidate-table"
- >
- <template #cell()="data">
- <div v-gl-tooltip.hover :title="data.value">{{ data.value }}</div>
- </template>
-
- <template #cell(artifact)="data">
- <gl-link
- v-if="data.value"
- v-gl-tooltip.hover
- :href="data.value"
- target="_blank"
- :title="$options.i18n.artifactsLabel"
- >{{ $options.i18n.artifactsLabel }}</gl-link
- >
- <div v-else v-gl-tooltip.hover :title="$options.i18n.artifactsLabel">
- {{ $options.i18n.noDataContent }}
- </div>
- </template>
-
- <template #cell(details)="data">
- <gl-link v-gl-tooltip.hover :href="data.value" :title="$options.i18n.detailsLabel">{{
- $options.i18n.detailsLabel
- }}</gl-link>
- </template>
-
- <template #cell(created_at)="data">
- <time-ago v-gl-tooltip.hover :time="data.value" :title="data.value" />
- </template>
-
- <template #cell(user)="data">
- <gl-link
- v-if="data.value"
- v-gl-tooltip.hover
- :href="data.value.path"
- :title="data.value.username"
- >@{{ data.value.username }}</gl-link
- >
- <div v-else>{{ $options.i18n.noDataContent }}</div>
- </template>
- </gl-table>
-
- <keyset-pagination v-if="displayPagination" v-bind="pageInfo" />
- </div>
-</template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/constants.js b/app/assets/javascripts/ml/experiment_tracking/constants.js
index 15462b519e1..11cf321ad51 100644
--- a/app/assets/javascripts/ml/experiment_tracking/constants.js
+++ b/app/assets/javascripts/ml/experiment_tracking/constants.js
@@ -1,19 +1,4 @@
-import { __, s__ } from '~/locale';
-
-export const METRIC_KEY_PREFIX = 'metric.';
-
-export const LIST_KEY_CREATED_AT = 'created_at';
-
-export const BASE_SORT_FIELDS = Object.freeze([
- {
- orderBy: 'name',
- label: __('Name'),
- },
- {
- orderBy: LIST_KEY_CREATED_AT,
- label: __('Created at'),
- },
-]);
+import { s__ } from '~/locale';
export const EMPTY_STATE_SVG = '/assets/illustrations/empty-state/empty-dag-md.svg';
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/index.js b/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/index.js
new file mode 100644
index 00000000000..529bd6fe9f2
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/index.js
@@ -0,0 +1,3 @@
+import MlCandidatesShow from './ml_candidates_show.vue';
+
+export default MlCandidatesShow;
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/ml_candidates_show.vue b/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/ml_candidates_show.vue
new file mode 100644
index 00000000000..3c765de92a2
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/ml_candidates_show.vue
@@ -0,0 +1,125 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+import { FEATURE_NAME, FEATURE_FEEDBACK_ISSUE } from '~/ml/experiment_tracking/constants';
+import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
+import {
+ TITLE_LABEL,
+ INFO_LABEL,
+ ID_LABEL,
+ STATUS_LABEL,
+ EXPERIMENT_LABEL,
+ ARTIFACTS_LABEL,
+ PARAMETERS_LABEL,
+ METRICS_LABEL,
+ METADATA_LABEL,
+} from './translations';
+
+export default {
+ name: 'MlCandidatesShow',
+ components: {
+ IncubationAlert,
+ GlLink,
+ },
+ props: {
+ candidate: {
+ type: Object,
+ required: true,
+ },
+ },
+ i18n: {
+ TITLE_LABEL,
+ INFO_LABEL,
+ ID_LABEL,
+ STATUS_LABEL,
+ EXPERIMENT_LABEL,
+ ARTIFACTS_LABEL,
+ PARAMETERS_LABEL,
+ METRICS_LABEL,
+ METADATA_LABEL,
+ },
+ computed: {
+ sections() {
+ return [
+ {
+ sectionName: this.$options.i18n.PARAMETERS_LABEL,
+ sectionValues: this.candidate.params,
+ },
+ {
+ sectionName: this.$options.i18n.METRICS_LABEL,
+ sectionValues: this.candidate.metrics,
+ },
+ {
+ sectionName: this.$options.i18n.METADATA_LABEL,
+ sectionValues: this.candidate.metadata,
+ },
+ ];
+ },
+ },
+ FEATURE_NAME,
+ FEATURE_FEEDBACK_ISSUE,
+};
+</script>
+
+<template>
+ <div>
+ <incubation-alert
+ :feature-name="$options.FEATURE_NAME"
+ :link-to-feedback-issue="$options.FEATURE_FEEDBACK_ISSUE"
+ />
+
+ <h3>
+ {{ $options.i18n.TITLE_LABEL }}
+ </h3>
+
+ <table class="candidate-details">
+ <tbody>
+ <tr class="divider"></tr>
+
+ <tr>
+ <td class="gl-text-secondary gl-font-weight-bold">{{ $options.i18n.INFO_LABEL }}</td>
+ <td class="gl-font-weight-bold">{{ $options.i18n.ID_LABEL }}</td>
+ <td>{{ candidate.info.iid }}</td>
+ </tr>
+
+ <tr>
+ <td></td>
+ <td class="gl-font-weight-bold">{{ $options.i18n.STATUS_LABEL }}</td>
+ <td>{{ candidate.info.status }}</td>
+ </tr>
+
+ <tr>
+ <td></td>
+ <td class="gl-font-weight-bold">{{ $options.i18n.EXPERIMENT_LABEL }}</td>
+ <td>
+ <gl-link :href="candidate.info.path_to_experiment">{{
+ candidate.info.experiment_name
+ }}</gl-link>
+ </td>
+ </tr>
+
+ <tr v-if="candidate.info.path_to_artifact">
+ <td></td>
+ <td class="gl-font-weight-bold">{{ $options.i18n.ARTIFACTS_LABEL }}</td>
+ <td>
+ <gl-link :href="candidate.info.path_to_artifact">{{
+ $options.i18n.ARTIFACTS_LABEL
+ }}</gl-link>
+ </td>
+ </tr>
+
+ <template v-for="{ sectionName, sectionValues } in sections">
+ <tr :key="sectionName" class="divider"></tr>
+
+ <tr v-for="(item, index) in sectionValues" :key="item.name">
+ <td v-if="index === 0" class="gl-text-secondary gl-font-weight-bold">
+ {{ sectionName }}
+ </td>
+ <td v-else></td>
+ <td class="gl-font-weight-bold">{{ item.name }}</td>
+ <td>{{ item.value }}</td>
+ </tr>
+ </template>
+ </tbody>
+ </table>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/translations.js b/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/translations.js
new file mode 100644
index 00000000000..caad145873e
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/translations.js
@@ -0,0 +1,11 @@
+import { s__ } from '~/locale';
+
+export const TITLE_LABEL = s__('MlExperimentTracking|Model candidate details');
+export const INFO_LABEL = s__('MlExperimentTracking|Info');
+export const ID_LABEL = s__('MlExperimentTracking|ID');
+export const STATUS_LABEL = s__('MlExperimentTracking|Status');
+export const EXPERIMENT_LABEL = s__('MlExperimentTracking|Experiment');
+export const ARTIFACTS_LABEL = s__('MlExperimentTracking|Artifacts');
+export const PARAMETERS_LABEL = s__('MlExperimentTracking|Parameters');
+export const METRICS_LABEL = s__('MlExperimentTracking|Metrics');
+export const METADATA_LABEL = s__('MlExperimentTracking|Metadata');
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/constants.js b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/constants.js
new file mode 100644
index 00000000000..4d34555ac2f
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/constants.js
@@ -0,0 +1,21 @@
+import { s__ } from '~/locale';
+import { helpPagePath } from '~/helpers/help_page_helper';
+
+export const METRIC_KEY_PREFIX = 'metric.';
+export const LIST_KEY_CREATED_AT = 'created_at';
+export const BASE_SORT_FIELDS = Object.freeze([
+ {
+ orderBy: 'name',
+ label: s__('MlExperimentTracking|Name'),
+ },
+ {
+ orderBy: LIST_KEY_CREATED_AT,
+ label: s__('MlExperimentTracking|Created at'),
+ },
+]);
+export const CREATE_CANDIDATE_HELP_PATH = helpPagePath(
+ 'user/project/ml/experiment_tracking/index.md',
+ {
+ anchor: 'tracking-new-experiments-and-trials',
+ },
+);
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/index.js b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/index.js
new file mode 100644
index 00000000000..5903866b6dd
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/index.js
@@ -0,0 +1,3 @@
+import MlExperimentsShow from './ml_experiments_show.vue';
+
+export default MlExperimentsShow;
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
new file mode 100644
index 00000000000..ca0a42fda10
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
@@ -0,0 +1,221 @@
+<script>
+import { GlTableLite, GlLink, GlEmptyState } from '@gitlab/ui';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
+import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ FEATURE_NAME,
+ FEATURE_FEEDBACK_ISSUE,
+ EMPTY_STATE_SVG,
+} from '~/ml/experiment_tracking/constants';
+import { queryToObject, setUrlParams, visitUrl } from '~/lib/utils/url_utility';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import KeysetPagination from '~/vue_shared/components/incubation/pagination.vue';
+import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
+import {
+ LIST_KEY_CREATED_AT,
+ BASE_SORT_FIELDS,
+ METRIC_KEY_PREFIX,
+ CREATE_CANDIDATE_HELP_PATH,
+} from './constants';
+import * as translations from './translations';
+
+export default {
+ name: 'MlExperimentsShow',
+ components: {
+ GlTableLite,
+ GlLink,
+ GlEmptyState,
+ TimeAgo,
+ IncubationAlert,
+ RegistrySearch,
+ KeysetPagination,
+ },
+ props: {
+ candidates: {
+ type: Array,
+ required: true,
+ },
+ metricNames: {
+ type: Array,
+ required: true,
+ },
+ paramNames: {
+ type: Array,
+ required: true,
+ },
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ const query = queryToObject(window.location.search);
+
+ const filter = query.name ? [{ value: { data: query.name }, type: FILTERED_SEARCH_TERM }] : [];
+
+ let orderBy = query.orderBy || LIST_KEY_CREATED_AT;
+
+ if (query.orderByType === 'metric') {
+ orderBy = `${METRIC_KEY_PREFIX}${orderBy}`;
+ }
+
+ return {
+ filters: filter,
+ sorting: {
+ orderBy,
+ sort: (query.sort || 'desc').toLowerCase(),
+ },
+ };
+ },
+ computed: {
+ fields() {
+ if (this.candidates.length === 0) return [];
+
+ return [
+ { key: 'nameColumn', label: this.$options.i18n.NAME_LABEL },
+ { key: 'created_at', label: this.$options.i18n.CREATED_AT_LABEL },
+ { key: 'user', label: this.$options.i18n.USER_LABEL },
+ ...this.paramNames,
+ ...this.metricNames,
+ { key: 'artifact', label: this.$options.i18n.ARTIFACTS_LABEL },
+ ];
+ },
+ displayPagination() {
+ return this.candidates.length > 0;
+ },
+ sortableFields() {
+ return [
+ ...BASE_SORT_FIELDS,
+ ...this.metricNames.map((name) => ({
+ orderBy: `${METRIC_KEY_PREFIX}${name}`,
+ label: capitalizeFirstCharacter(name),
+ })),
+ ];
+ },
+ parsedQuery() {
+ const name = this.filters
+ .map((f) => f.value.data)
+ .join(' ')
+ .trim();
+
+ const filterByQuery = name === '' ? {} : { name };
+
+ let orderByType = 'column';
+ let { orderBy } = this.sorting;
+ const { sort } = this.sorting;
+
+ if (orderBy.startsWith(METRIC_KEY_PREFIX)) {
+ orderBy = this.sorting.orderBy.slice(METRIC_KEY_PREFIX.length);
+ orderByType = 'metric';
+ }
+
+ return { ...filterByQuery, orderBy, orderByType, sort };
+ },
+ tableItems() {
+ return this.candidates.map((candidate) => ({
+ ...candidate,
+ nameColumn: {
+ name: candidate.name,
+ details_path: candidate.details,
+ },
+ }));
+ },
+ hasItems() {
+ return this.candidates.length > 0;
+ },
+ },
+ methods: {
+ submitFilters() {
+ return visitUrl(setUrlParams({ ...this.parsedQuery }));
+ },
+ updateFilters(newValue) {
+ this.filters = newValue;
+ },
+ updateSorting(newValue) {
+ this.sorting = { ...this.sorting, ...newValue };
+ },
+ updateSortingAndEmitUpdate(newValue) {
+ this.updateSorting(newValue);
+ this.submitFilters();
+ },
+ },
+ i18n: translations,
+ constants: {
+ FEATURE_NAME,
+ FEATURE_FEEDBACK_ISSUE,
+ CREATE_CANDIDATE_HELP_PATH,
+ EMPTY_STATE_SVG,
+ },
+};
+</script>
+
+<template>
+ <div>
+ <incubation-alert
+ :feature-name="$options.constants.FEATURE_NAME"
+ :link-to-feedback-issue="$options.constants.FEATURE_FEEDBACK_ISSUE"
+ />
+
+ <registry-search
+ :filters="filters"
+ :sorting="sorting"
+ :sortable-fields="sortableFields"
+ @sorting:changed="updateSortingAndEmitUpdate"
+ @filter:changed="updateFilters"
+ @filter:submit="submitFilters"
+ @filter:clear="filters = []"
+ />
+
+ <div v-if="hasItems" class="gl-overflow-x-auto">
+ <gl-table-lite
+ :fields="fields"
+ :items="tableItems"
+ show-empty
+ small
+ class="gl-mt-0! ml-candidate-table"
+ >
+ <template #cell()="data">
+ <div>{{ data.value }}</div>
+ </template>
+
+ <template #cell(nameColumn)="data">
+ <gl-link :href="data.value.details_path">
+ <span v-if="data.value.name"> {{ data.value.name }}</span>
+ <span v-else class="gl-font-style-italic">{{ $options.i18n.NO_CANDIDATE_NAME }}</span>
+ </gl-link>
+ </template>
+
+ <template #cell(artifact)="data">
+ <gl-link v-if="data.value" :href="data.value" target="_blank">{{
+ $options.i18n.ARTIFACTS_LABEL
+ }}</gl-link>
+ <div v-else class="gl-font-style-italic gl-text-gray-500">
+ {{ $options.i18n.NO_ARTIFACT }}
+ </div>
+ </template>
+
+ <template #cell(created_at)="data">
+ <time-ago :time="data.value" />
+ </template>
+
+ <template #cell(user)="data">
+ <gl-link v-if="data.value" :href="data.value.path">@{{ data.value.username }}</gl-link>
+ <div v-else>{{ $options.i18n.NO_DATA_CONTENT }}</div>
+ </template>
+ </gl-table-lite>
+ </div>
+
+ <gl-empty-state
+ v-else
+ :title="$options.i18n.EMPTY_STATE_TITLE_LABEL"
+ :primary-button-text="$options.i18n.CREATE_NEW_LABEL"
+ :primary-button-link="$options.constants.CREATE_CANDIDATE_HELP_PATH"
+ :svg-path="$options.constants.EMPTY_STATE_SVG"
+ :description="$options.i18n.EMPTY_STATE_DESCRIPTION_LABEL"
+ class="gl-py-8"
+ />
+
+ <keyset-pagination v-if="displayPagination" v-bind="pageInfo" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js
new file mode 100644
index 00000000000..63b0d902b72
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js
@@ -0,0 +1,16 @@
+import { s__ } from '~/locale';
+
+export const ARTIFACTS_LABEL = s__('MlExperimentTracking|Artifacts');
+export const DETAILS_LABEL = s__('MlExperimentTracking|Details');
+export const USER_LABEL = s__('MlExperimentTracking|Author');
+export const CREATED_AT_LABEL = s__('MlExperimentTracking|Created at');
+export const NAME_LABEL = s__('MlExperimentTracking|Name');
+export const NO_DATA_CONTENT = s__('MlExperimentTracking|-');
+export const FILTER_CANDIDATES_LABEL = s__('MlExperimentTracking|Filter candidates');
+export const NO_CANDIDATE_NAME = s__('MlExperimentTracking|No name');
+export const NO_ARTIFACT = s__('MlExperimentTracking|No artifacts');
+export const CREATE_NEW_LABEL = s__('MlExperimentTracking|Create new candidates');
+export const EMPTY_STATE_DESCRIPTION_LABEL = s__(
+ 'MlExperimentTracking|No candidates logged for the query. Create new candidates using the MLflow client.',
+);
+export const EMPTY_STATE_TITLE_LABEL = s__('MlExperimentTracking|No candidates');
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 2c185794d17..ab2b713ac9f 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -11,7 +11,7 @@ import {
import Mousetrap from 'mousetrap';
import VueDraggable from 'vuedraggable';
import { mapActions, mapState, mapGetters } from 'vuex';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import invalidUrl from '~/lib/utils/invalid_url';
import { ESC_KEY } from '~/lib/utils/keys';
import { mergeUrlParams, updateHistory } from '~/lib/utils/url_utility';
diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js
index 1b506c6564b..faef4b01c27 100644
--- a/app/assets/javascripts/monitoring/constants.js
+++ b/app/assets/javascripts/monitoring/constants.js
@@ -226,12 +226,6 @@ export const OVERVIEW_DASHBOARD_PATH = 'config/prometheus/common_metrics.yml';
*/
export const OUT_OF_THE_BOX_DASHBOARDS_PATH_PREFIX = 'config/prometheus/';
-export const OPERATORS = {
- greaterThan: '>',
- equalTo: '==',
- lessThan: '<',
-};
-
/**
* Dashboard yml files support custom user-defined variables that
* are rendered as input elements in the monitoring dashboard.
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 0ef365c6368..4fdc08487f2 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -1,5 +1,5 @@
import * as Sentry from '@sentry/browser';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { convertToFixedRange } from '~/lib/utils/datetime_range';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
diff --git a/app/assets/javascripts/mr_notes/init_notes.js b/app/assets/javascripts/mr_notes/init_notes.js
index d968c125068..2488c8aee9c 100644
--- a/app/assets/javascripts/mr_notes/init_notes.js
+++ b/app/assets/javascripts/mr_notes/init_notes.js
@@ -1,5 +1,8 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import { mapActions, mapState, mapGetters } from 'vuex';
+import { apolloProvider } from '~/graphql_shared/issuable_client';
+
import { renderGFM } from '~/behaviors/markdown/render_gfm';
import { parseBoolean } from '~/lib/utils/common_utils';
import store from '~/mr_notes/stores';
@@ -22,6 +25,8 @@ export default () => {
return;
}
+ Vue.use(VueApollo);
+
const notesFilterProps = getNotesFilterData(el);
const notesDataset = el.dataset;
@@ -33,8 +38,10 @@ export default () => {
NotesApp,
},
store,
+ apolloProvider,
provide: {
reportAbusePath: notesDataset.reportAbusePath,
+ newSavedRepliesPath: notesDataset.savedRepliesNewPath,
},
data() {
const noteableData = JSON.parse(notesDataset.noteableData);
diff --git a/app/assets/javascripts/namespaces/leave_by_url.js b/app/assets/javascripts/namespaces/leave_by_url.js
index 09757ce17fa..b7dd509f7f2 100644
--- a/app/assets/javascripts/namespaces/leave_by_url.js
+++ b/app/assets/javascripts/namespaces/leave_by_url.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { initRails } from '~/lib/utils/rails_ujs';
import { getParameterByName } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
diff --git a/app/assets/javascripts/nav/components/new_nav_toggle.vue b/app/assets/javascripts/nav/components/new_nav_toggle.vue
index da22a8d2fb7..ca6232fa4c4 100644
--- a/app/assets/javascripts/nav/components/new_nav_toggle.vue
+++ b/app/assets/javascripts/nav/components/new_nav_toggle.vue
@@ -1,7 +1,7 @@
<script>
-import { GlBadge, GlToggle } from '@gitlab/ui';
+import { GlBadge, GlToggle, GlDisclosureDropdownItem } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
@@ -18,6 +18,7 @@ export default {
components: {
GlBadge,
GlToggle,
+ GlDisclosureDropdownItem,
},
props: {
enabled: {
@@ -28,6 +29,11 @@ export default {
type: String,
required: true,
},
+ newNavigation: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -61,7 +67,18 @@ export default {
</script>
<template>
- <li>
+ <gl-disclosure-dropdown-item v-if="newNavigation" @action="toggleNav">
+ <div class="gl-new-dropdown-item-content">
+ <div
+ class="gl-new-dropdown-item-text-wrapper gl-display-flex! gl-justify-content-space-between gl-align-items-center gl-py-2!"
+ >
+ {{ $options.i18n.toggleMenuItemLabel }}
+ <gl-toggle :value="isEnabled" :label="$options.i18n.toggleLabel" label-position="hidden" />
+ </div>
+ </div>
+ </gl-disclosure-dropdown-item>
+
+ <li v-else>
<div
class="gl-px-4 gl-py-2 gl-display-flex gl-justify-content-space-between gl-align-items-center"
>
@@ -74,7 +91,12 @@ export default {
@click.prevent.stop="toggleNav"
>
{{ $options.i18n.toggleMenuItemLabel }}
- <gl-toggle :value="isEnabled" :label="$options.i18n.toggleLabel" label-position="hidden" />
+ <gl-toggle
+ :value="isEnabled"
+ :label="$options.i18n.toggleLabel"
+ label-position="hidden"
+ data-qa-selector="new_navigation_toggle"
+ />
</div>
</li>
</template>
diff --git a/app/assets/javascripts/nav/components/top_nav_new_dropdown.vue b/app/assets/javascripts/nav/components/top_nav_new_dropdown.vue
index bfcdcfc7292..2dfd77bc02e 100644
--- a/app/assets/javascripts/nav/components/top_nav_new_dropdown.vue
+++ b/app/assets/javascripts/nav/components/top_nav_new_dropdown.vue
@@ -1,5 +1,7 @@
<script>
import { GlDropdown, GlDropdownDivider, GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui';
+import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
+import { TOP_NAV_INVITE_MEMBERS_COMPONENT } from '~/invite_members/constants';
export default {
components: {
@@ -7,6 +9,7 @@ export default {
GlDropdownDivider,
GlDropdownItem,
GlDropdownSectionHeader,
+ InviteMembersTrigger,
},
props: {
viewModel: {
@@ -22,6 +25,11 @@ export default {
return this.sections.length > 1;
},
},
+ methods: {
+ isInvitedMembers(menuItem) {
+ return menuItem.component === TOP_NAV_INVITE_MEMBERS_COMPONENT;
+ },
+ },
};
</script>
@@ -41,7 +49,16 @@ export default {
{{ title }}
</gl-dropdown-section-header>
<template v-for="menuItem in menu_items">
+ <invite-members-trigger
+ v-if="isInvitedMembers(menuItem)"
+ :key="`${index}_item_${menuItem.id}`"
+ :trigger-element="`dropdown-${menuItem.data.trigger_element}`"
+ :display-text="menuItem.title"
+ :icon="menuItem.icon"
+ :trigger-source="menuItem.data.trigger_source"
+ />
<gl-dropdown-item
+ v-else
:key="`${index}_item_${menuItem.id}`"
link-class="top-nav-menu-item"
:href="menuItem.href"
diff --git a/app/assets/javascripts/notebook/cells/output/error.vue b/app/assets/javascripts/notebook/cells/output/error.vue
new file mode 100644
index 00000000000..9afc89cde4f
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/output/error.vue
@@ -0,0 +1,40 @@
+<script>
+import Prompt from '../prompt.vue';
+import Markdown from '../markdown.vue';
+
+export default {
+ name: 'ErrorOutput',
+ components: {
+ Prompt,
+ Markdown,
+ },
+ props: {
+ count: {
+ type: Number,
+ required: true,
+ },
+ rawCode: {
+ type: Array,
+ required: true,
+ },
+ index: {
+ type: Number,
+ required: true,
+ },
+ },
+ computed: {
+ parsedError() {
+ let parsed = this.rawCode.map((l) => l.replace(/\u001B\[[0-9][0-9;]*m/g, '')); // eslint-disable-line no-control-regex
+ parsed = ['```error', ...parsed, '```'].join('\n'); // eslint-disable-line @gitlab/require-i18n-strings
+ return { source: [parsed] };
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="output">
+ <prompt type="Out" :count="count" />
+ <markdown :cell="parsedError" :hide-prompt="true" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index bd01534089e..22bcb5dd66a 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -4,8 +4,10 @@ import HtmlOutput from './html.vue';
import ImageOutput from './image.vue';
import LatexOutput from './latex.vue';
import MarkdownOutput from './markdown.vue';
+import ErrorOutput from './error.vue';
const TEXT_MARKDOWN = 'text/markdown';
+const ERROR_OUTPUT_TYPE = 'error';
export default {
props: {
@@ -28,6 +30,8 @@ export default {
outputType(output) {
if (output.text) {
return 'text/plain';
+ } else if (output.output_type === ERROR_OUTPUT_TYPE) {
+ return 'error';
} else if (output.data['image/png']) {
return 'image/png';
} else if (output.data['image/jpeg']) {
@@ -56,6 +60,8 @@ export default {
getComponent(output) {
if (output.text) {
return CodeOutput;
+ } else if (output.output_type === ERROR_OUTPUT_TYPE) {
+ return ErrorOutput;
} else if (output.data['image/png']) {
return ImageOutput;
} else if (output.data['image/jpeg']) {
@@ -80,6 +86,10 @@ export default {
return output.text.join('');
}
+ if (output.output_type === ERROR_OUTPUT_TYPE) {
+ return output.traceback;
+ }
+
return this.dataForType(output, this.outputType(output));
},
},
diff --git a/app/assets/javascripts/notebook/index.vue b/app/assets/javascripts/notebook/index.vue
index df9694b7cd8..5f254cae73d 100644
--- a/app/assets/javascripts/notebook/index.vue
+++ b/app/assets/javascripts/notebook/index.vue
@@ -60,6 +60,10 @@ export default {
margin-bottom: 10px;
}
+.output .text-cell {
+ overflow-x: auto;
+}
+
.cell pre {
margin: 0;
width: 100%;
diff --git a/app/assets/javascripts/notes/components/comment_field_layout.vue b/app/assets/javascripts/notes/components/comment_field_layout.vue
index cc372520c70..02d128eb119 100644
--- a/app/assets/javascripts/notes/components/comment_field_layout.vue
+++ b/app/assets/javascripts/notes/components/comment_field_layout.vue
@@ -76,7 +76,7 @@ export default {
></div>
<noteable-warning
v-if="hasWarning"
- class="gl-border-b-1 gl-border-b-solid gl-border-b-gray-100 gl-rounded-base gl-rounded-bottom-left-none gl-rounded-bottom-right-none"
+ class="gl-py-4 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100 gl-rounded-base gl-rounded-bottom-left-none gl-rounded-bottom-right-none"
:is-locked="isLocked"
:is-confidential="isConfidential"
:noteable-type="noteableType"
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 4f7256d0b0e..d78b48e0a6d 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -1,12 +1,11 @@
<script>
import { GlAlert, GlButton, GlIcon, GlFormCheckbox, GlTooltipDirective } from '@gitlab/ui';
-import Autosize from 'autosize';
import $ from 'jquery';
import { mapActions, mapGetters, mapState } from 'vuex';
-import Autosave from '~/autosave';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
-import { createAlert } from '~/flash';
+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 { HTTP_STATUS_UNPROCESSABLE_ENTITY } from '~/lib/utils/http_status';
import {
capitalizeFirstCharacter,
@@ -14,7 +13,7 @@ import {
slugifyWithUnderscore,
} from '~/lib/utils/text_utility';
import { sprintf } from '~/locale';
-import MarkdownField from '~/vue_shared/components/markdown/field.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';
@@ -35,7 +34,7 @@ export default {
components: {
NoteSignedOutWidget,
DiscussionLockedWidget,
- MarkdownField,
+ MarkdownEditor,
GlAlert,
GlButton,
TimelineEntryItem,
@@ -61,6 +60,14 @@ export default {
errors: [],
noteIsInternal: false,
isSubmitting: false,
+ formFieldProps: {
+ 'aria-label': this.$options.i18n.comment,
+ placeholder: this.$options.i18n.bodyPlaceholder,
+ id: 'note-body',
+ name: 'note[note]',
+ class: 'js-note-text note-textarea js-gfm-input markdown-area',
+ 'data-qa-selector': 'comment_field',
+ },
};
},
computed: {
@@ -95,16 +102,11 @@ export default {
}
return this.noteType === constants.COMMENT ? comment : startThread;
},
- textareaPlaceholder() {
- return this.noteIsInternal
- ? this.$options.i18n.bodyPlaceholderInternal
- : this.$options.i18n.bodyPlaceholder;
- },
discussionsRequireResolution() {
return this.getNoteableData.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE;
},
isOpen() {
- return this.openState === constants.OPENED || this.openState === constants.REOPENED;
+ return this.openState === STATUS_OPEN || this.openState === STATUS_REOPENED;
},
canCreateNote() {
return this.getNoteableData.current_user.can_create_note;
@@ -152,7 +154,7 @@ export default {
canToggleIssueState() {
return (
this.getNoteableData.current_user.can_update &&
- this.openState !== constants.MERGED &&
+ this.openState !== STATUS_MERGED &&
!this.closedAndLocked
);
},
@@ -180,14 +182,27 @@ export default {
containsLink() {
return ATTACHMENT_REGEXP.test(this.note);
},
+ autosaveKey() {
+ if (this.isLoggedIn) {
+ const noteableType = capitalizeFirstCharacter(convertToCamelCase(this.noteableType));
+ return `${this.$options.i18n.note}/${noteableType}/${this.getNoteableData.id}`;
+ }
+
+ return null;
+ },
+ },
+ watch: {
+ noteIsInternal(val) {
+ this.formFieldProps.placeholder = val
+ ? this.$options.i18n.bodyPlaceholderInternal
+ : this.$options.i18n.bodyPlaceholder;
+ },
},
mounted() {
// jQuery is needed here because it is a custom event being dispatched with jQuery.
$(document).on('issuable:change', (e, isClosed) => {
- this.toggleIssueLocalState(isClosed ? constants.CLOSED : constants.REOPENED);
+ this.toggleIssueLocalState(isClosed ? STATUS_CLOSED : STATUS_REOPENED);
});
-
- this.initAutoSave();
},
methods: {
...mapActions([
@@ -232,7 +247,6 @@ export default {
}
this.note = ''; // Empty textarea while being requested. Repopulate in catch
- this.resizeTextarea();
this.stopPolling();
this.isSubmitting = true;
@@ -249,7 +263,6 @@ export default {
.catch(({ response }) => {
this.handleSaveError(response);
- this.discard(false);
this.note = noteData.data.note.note; // Restore textarea content.
this.removePlaceholderNotes();
})
@@ -286,20 +299,10 @@ export default {
}),
);
},
- discard(shouldClear = true) {
- // `blur` is needed to clear slash commands autocomplete cache if event fired.
- // `focus` is needed to remain cursor in the textarea.
- this.$refs.textarea.blur();
- this.$refs.textarea.focus();
-
- if (shouldClear) {
- this.note = '';
- this.noteIsInternal = false;
- this.resizeTextarea();
- this.$refs.markdownField.previewMarkdown = false;
- }
-
- this.autosave.reset();
+ discard() {
+ this.note = '';
+ this.noteIsInternal = false;
+ this.$refs.markdownEditor.togglePreview(false);
},
editCurrentUserLastNote() {
if (this.note === '') {
@@ -312,28 +315,15 @@ export default {
}
}
},
- initAutoSave() {
- if (this.isLoggedIn) {
- const noteableType = capitalizeFirstCharacter(convertToCamelCase(this.noteableType));
-
- this.autosave = new Autosave(this.$refs.textarea, [
- this.$options.i18n.note,
- noteableType,
- this.getNoteableData.id,
- ]);
- }
- },
- resizeTextarea() {
- this.$nextTick(() => {
- Autosize.update(this.$refs.textarea);
- });
- },
hasEmailParticipants() {
return this.getNoteableData.issue_email_participants?.length;
},
dismissError(index) {
this.errors.splice(index, 1);
},
+ onInput(value) {
+ this.note = value;
+ },
},
};
</script>
@@ -362,35 +352,24 @@ export default {
:noteable-type="noteableType"
:contains-link="containsLink"
>
- <markdown-field
- ref="markdownField"
- :is-submitting="isSubmitting"
- :markdown-preview-path="markdownPreviewPath"
+ <markdown-editor
+ ref="markdownEditor"
+ :enable-content-editor="Boolean(glFeatures.contentEditorOnIssues)"
+ :value="note"
+ :render-markdown-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
- :quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false"
- :textarea-value="note"
- >
- <template #textarea>
- <textarea
- id="note-body"
- ref="textarea"
- v-model="note"
- dir="auto"
- :disabled="isSubmitting"
- name="note[note]"
- class="note-textarea js-vue-comment-form js-note-text js-gfm-input js-autosize markdown-area"
- data-qa-selector="comment_field"
- data-testid="comment-field"
- data-supports-quick-actions="true"
- :aria-label="$options.i18n.comment"
- :placeholder="textareaPlaceholder"
- @keydown.up="editCurrentUserLastNote()"
- @keydown.meta.enter="handleEnter()"
- @keydown.ctrl.enter="handleEnter()"
- ></textarea>
- </template>
- </markdown-field>
+ :quick-actions-docs-path="quickActionsDocsPath"
+ :form-field-props="formFieldProps"
+ :autosave-key="autosaveKey"
+ :disabled="isSubmitting"
+ supports-quick-actions
+ autofocus
+ @keydown.up="editCurrentUserLastNote()"
+ @keydown.meta.enter="handleEnter()"
+ @keydown.ctrl.enter="handleEnter()"
+ @input="onInput"
+ />
</comment-field-layout>
<div class="note-form-actions">
<template v-if="hasDrafts">
diff --git a/app/assets/javascripts/notes/components/discussion_locked_widget.vue b/app/assets/javascripts/notes/components/discussion_locked_widget.vue
index 8ac3f6bea68..bcf9b4cf893 100644
--- a/app/assets/javascripts/notes/components/discussion_locked_widget.vue
+++ b/app/assets/javascripts/notes/components/discussion_locked_widget.vue
@@ -33,8 +33,10 @@ export default {
</script>
<template>
- <div class="disabled-comment text-center">
- <span class="issuable-note-warning inline">
+ <div class="disabled-comments gl-mt-3">
+ <span
+ class="issuable-note-warning gl-display-inline-block gl-w-full gl-px-5 gl-py-4 gl-rounded-base"
+ >
<gl-icon :size="16" name="lock" class="icon" />
<span v-if="isProjectArchived">
{{ projectArchivedWarning }}
diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue
index abed95a9706..89cd252b94b 100644
--- a/app/assets/javascripts/notes/components/note_actions.vue
+++ b/app/assets/javascripts/notes/components/note_actions.vue
@@ -3,7 +3,7 @@ import { GlTooltipDirective, GlIcon, GlButton, GlDropdownItem } from '@gitlab/ui
import { mapActions, mapGetters, mapState } from 'vuex';
import Api from '~/api';
import resolvedStatusMixin from '~/batch_comments/mixins/resolved_status';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { __, sprintf } from '~/locale';
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index 9d59994788e..21841680cab 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -1,6 +1,6 @@
<script>
import { mapActions, mapGetters } from 'vuex';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import AwardsList from '~/vue_shared/components/awards_list.vue';
diff --git a/app/assets/javascripts/notes/components/note_body.vue b/app/assets/javascripts/notes/components/note_body.vue
index 20cf21cd1b6..eef011db7d2 100644
--- a/app/assets/javascripts/notes/components/note_body.vue
+++ b/app/assets/javascripts/notes/components/note_body.vue
@@ -208,7 +208,7 @@ export default {
v-if="note.last_edited_at"
:edited-at="note.last_edited_at"
:edited-by="note.last_edited_by"
- action-text="Edited"
+ :action-text="__('Edited')"
class="note_edited_ago"
/>
<note-awards-list
diff --git a/app/assets/javascripts/notes/components/note_edited_text.vue b/app/assets/javascripts/notes/components/note_edited_text.vue
index e0c3ed0c67a..25c82c29a29 100644
--- a/app/assets/javascripts/notes/components/note_edited_text.vue
+++ b/app/assets/javascripts/notes/components/note_edited_text.vue
@@ -1,10 +1,13 @@
<script>
-/* eslint-disable @gitlab/vue-require-i18n-strings */
+import { GlSprintf, GlLink } from '@gitlab/ui';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import { EDITED_TEXT } from '../i18n';
export default {
name: 'EditedNoteText',
components: {
+ GlSprintf,
+ GlLink,
TimeAgoTooltip,
},
props: {
@@ -33,19 +36,42 @@ export default {
default: 'edited-text',
},
},
+ i18n: EDITED_TEXT,
};
</script>
<template>
<div :class="className">
- {{ actionText }}
- <template v-if="editedBy">
- by
- <a :href="editedBy.path" :data-user-id="editedBy.id" class="js-user-link author-link">
- {{ editedBy.name }}
- </a>
- </template>
- {{ actionDetailText }}
- <time-ago-tooltip :time="editedAt" tooltip-placement="bottom" />
+ <gl-sprintf v-if="editedBy" :message="$options.i18n.actionWithAuthor">
+ <template #actionText>
+ {{ actionText }}
+ </template>
+ <template #actionDetail>
+ {{ actionDetailText }}
+ </template>
+ <template #timeago>
+ <time-ago-tooltip :time="editedAt" tooltip-placement="bottom" />
+ </template>
+ <template #author>
+ <gl-link
+ :href="editedBy.path"
+ :data-user-id="editedBy.id"
+ class="js-user-link author-link gl-hover-text-decoration-underline"
+ >
+ {{ editedBy.name }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ <gl-sprintf v-else :message="$options.i18n.actionWithoutAuthor">
+ <template #actionText>
+ {{ actionText }}
+ </template>
+ <template #actionDetail>
+ {{ actionDetailText }}
+ </template>
+ <template #timeago>
+ <time-ago-tooltip :time="editedAt" tooltip-placement="bottom" />
+ </template>
+ </gl-sprintf>
</div>
</template>
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index c83b3d870d7..7dc6b045b4d 100644
--- a/app/assets/javascripts/notes/components/note_header.vue
+++ b/app/assets/javascripts/notes/components/note_header.vue
@@ -68,6 +68,11 @@ export default {
required: false,
default: false,
},
+ noteUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
return {
@@ -85,7 +90,9 @@ export default {
return this.expanded ? 'chevron-up' : 'chevron-down';
},
noteTimestampLink() {
- return this.noteId ? `#note_${this.noteId}` : undefined;
+ if (this.noteUrl) return this.noteUrl;
+
+ return this.noteId ? `#note_${getIdFromGraphQLId(this.noteId)}` : undefined;
},
hasAuthor() {
return this.author && Object.keys(this.author).length;
@@ -159,15 +166,13 @@ export default {
:data-user-id="authorId"
:data-username="author.username"
>
- <span class="note-header-author-name gl-font-weight-bold">
- {{ authorName }}
- </span>
+ <span class="note-header-author-name gl-font-weight-bold" v-text="authorName"></span>
</a>
<span v-if="!isSystemNote" class="text-nowrap author-username">
<a
ref="authorUsernameLink"
class="author-username-link"
- :href="author.path"
+ :href="authorHref"
@mouseenter="handleUsernameMouseEnter"
@mouseleave="handleUsernameMouseLeave"
><span class="note-headline-light">@{{ author.username }}</span>
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index ff801cdccea..60ae573bae7 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -2,7 +2,7 @@
import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { mapActions, mapGetters } from 'vuex';
import DraftNote from '~/batch_comments/components/draft_note.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { clearDraft, getDiscussionReplyKey } from '~/lib/utils/autosave';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index 93575ad57ff..80025d6f98a 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -6,7 +6,7 @@ import { mapGetters, mapActions } from 'vuex';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import { INLINE_DIFF_LINES_KEY } from '~/diffs/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_GONE } from '~/lib/utils/http_status';
import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending';
import { truncateSha } from '~/lib/utils/text_utility';
diff --git a/app/assets/javascripts/notes/components/toggle_replies_widget.vue b/app/assets/javascripts/notes/components/toggle_replies_widget.vue
index 4437d461308..b0f7a4a4732 100644
--- a/app/assets/javascripts/notes/components/toggle_replies_widget.vue
+++ b/app/assets/javascripts/notes/components/toggle_replies_widget.vue
@@ -39,7 +39,7 @@ export default {
},
liClasses() {
return this.collapsed
- ? 'gl-text-gray-500 gl-rounded-bottom-left-base gl-rounded-bottom-right-base'
+ ? 'gl-text-gray-500 gl-rounded-bottom-left-base! gl-rounded-bottom-right-base! replies-widget-collapsed'
: 'gl-border-b';
},
buttonIcon() {
@@ -76,7 +76,7 @@ export default {
v-for="author in uniqueAuthors"
:key="author.username"
class="gl-mr-3 reply-author-avatar"
- :link-href="author.path"
+ :link-href="author.path || author.webUrl"
:img-alt="author.name"
img-css-classes="gl-mr-0!"
:img-src="author.avatar_url || author.avatarUrl"
@@ -95,7 +95,7 @@ export default {
<gl-sprintf :message="$options.i18n.lastReplyBy">
<template #name>
<gl-link
- :href="lastReply.author.path"
+ :href="lastReply.author.path || lastReply.author.webUrl"
class="gl-text-body! gl-text-decoration-none! gl-mx-2"
>
{{ lastReply.author.name }}
diff --git a/app/assets/javascripts/notes/constants.js b/app/assets/javascripts/notes/constants.js
index 88f438975f6..15eb4f95910 100644
--- a/app/assets/javascripts/notes/constants.js
+++ b/app/assets/javascripts/notes/constants.js
@@ -1,3 +1,4 @@
+import { STATUS_CLOSED, STATUS_OPEN, STATUS_REOPENED } from '~/issues/constants';
import { __ } from '~/locale';
export const DISCUSSION_NOTE = 'DiscussionNote';
@@ -6,10 +7,6 @@ export const DISCUSSION = 'discussion';
export const NOTE = 'note';
export const SYSTEM_NOTE = 'systemNote';
export const COMMENT = 'comment';
-export const OPENED = 'opened';
-export const REOPENED = 'reopened';
-export const CLOSED = 'closed';
-export const MERGED = 'merged';
export const ISSUE_NOTEABLE_TYPE = 'Issue';
export const EPIC_NOTEABLE_TYPE = 'Epic';
export const MERGE_REQUEST_NOTEABLE_TYPE = 'MergeRequest';
@@ -43,13 +40,19 @@ export const DISCUSSION_FILTER_TYPES = {
export const toggleStateErrorMessage = {
Epic: {
- [CLOSED]: __('Something went wrong while reopening the epic. Please try again later.'),
- [OPENED]: __('Something went wrong while closing the epic. Please try again later.'),
- [REOPENED]: __('Something went wrong while closing the epic. Please try again later.'),
+ [STATUS_CLOSED]: __('Something went wrong while reopening the epic. Please try again later.'),
+ [STATUS_OPEN]: __('Something went wrong while closing the epic. Please try again later.'),
+ [STATUS_REOPENED]: __('Something went wrong while closing the epic. Please try again later.'),
},
MergeRequest: {
- [CLOSED]: __('Something went wrong while reopening the merge request. Please try again later.'),
- [OPENED]: __('Something went wrong while closing the merge request. Please try again later.'),
- [REOPENED]: __('Something went wrong while closing the merge request. Please try again later.'),
+ [STATUS_CLOSED]: __(
+ 'Something went wrong while reopening the merge request. Please try again later.',
+ ),
+ [STATUS_OPEN]: __(
+ 'Something went wrong while closing the merge request. Please try again later.',
+ ),
+ [STATUS_REOPENED]: __(
+ 'Something went wrong while closing the merge request. Please try again later.',
+ ),
},
};
diff --git a/app/assets/javascripts/notes/i18n.js b/app/assets/javascripts/notes/i18n.js
index a758a55014a..4bf2a8d70a7 100644
--- a/app/assets/javascripts/notes/i18n.js
+++ b/app/assets/javascripts/notes/i18n.js
@@ -49,3 +49,8 @@ export const COMMENT_FORM = {
'Notes|Attachments are sent by email. Attachments over 10 MB are sent as links to your GitLab instance, and only accessible to project members.',
),
};
+
+export const EDITED_TEXT = {
+ actionWithAuthor: __('%{actionText} %{actionDetail} %{timeago} by %{author}'),
+ actionWithoutAuthor: __('%{actionText} %{actionDetail}'),
+};
diff --git a/app/assets/javascripts/notes/index.js b/app/assets/javascripts/notes/index.js
index 2e09c9f2288..b884c6b6d19 100644
--- a/app/assets/javascripts/notes/index.js
+++ b/app/assets/javascripts/notes/index.js
@@ -1,4 +1,6 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { apolloProvider } from '~/graphql_shared/issuable_client';
import { parseBoolean } from '~/lib/utils/common_utils';
import { getLocationHash } from '~/lib/utils/url_utility';
import NotesApp from './components/notes_app.vue';
@@ -11,6 +13,8 @@ export default () => {
return;
}
+ Vue.use(VueApollo);
+
const notesFilterProps = getNotesFilterData(el);
const showTimelineViewToggle = parseBoolean(el.dataset.showTimelineViewToggle);
@@ -50,9 +54,11 @@ export default () => {
NotesApp,
},
store,
+ apolloProvider,
provide: {
showTimelineViewToggle,
reportAbusePath: notesDataset.reportAbusePath,
+ newSavedRepliesPath: notesDataset.savedRepliesNewPath,
},
data() {
return {
diff --git a/app/assets/javascripts/notes/mixins/diff_line_note_form.js b/app/assets/javascripts/notes/mixins/diff_line_note_form.js
index 9a140029c07..0509ff24959 100644
--- a/app/assets/javascripts/notes/mixins/diff_line_note_form.js
+++ b/app/assets/javascripts/notes/mixins/diff_line_note_form.js
@@ -1,7 +1,7 @@
import { mapActions, mapGetters, mapState } from 'vuex';
import { getDraftReplyFormData, getDraftFormData } from '~/batch_comments/utils';
import { TEXT_DIFF_POSITION_TYPE, IMAGE_DIFF_POSITION_TYPE } from '~/diffs/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { clearDraft } from '~/lib/utils/autosave';
import { s__ } from '~/locale';
import { formatLineRange } from '~/notes/components/multiline_comment_utils';
diff --git a/app/assets/javascripts/notes/mixins/resolvable.js b/app/assets/javascripts/notes/mixins/resolvable.js
index 44751020173..63822a31cd1 100644
--- a/app/assets/javascripts/notes/mixins/resolvable.js
+++ b/app/assets/javascripts/notes/mixins/resolvable.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
export default {
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index f6b9be6ee9b..cdfa0d11f56 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -2,9 +2,9 @@ import $ from 'jquery';
import Visibility from 'visibilityjs';
import Vue from 'vue';
import Api from '~/api';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { EVENT_ISSUABLE_VUE_APP_CHANGE } from '~/issuable/constants';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { STATUS_CLOSED, STATUS_REOPENED, TYPE_ISSUE } from '~/issues/constants';
import axios from '~/lib/utils/axios_utils';
import { __, sprintf } from '~/locale';
import toast from '~/vue_shared/plugins/global_toast';
@@ -19,7 +19,6 @@ import { mergeUrlParams } from '~/lib/utils/url_utility';
import sidebarTimeTrackingEventHub from '~/sidebar/event_hub';
import TaskList from '~/task_list';
import mrWidgetEventHub from '~/vue_merge_request_widget/event_hub';
-import SidebarStore from '~/sidebar/stores/sidebar_store';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_NOTE } from '~/graphql_shared/constants';
import notesEventHub from '../event_hub';
@@ -407,7 +406,7 @@ export const emitStateChangedEvent = ({ getters }, data) => {
const event = new CustomEvent(EVENT_ISSUABLE_VUE_APP_CHANGE, {
detail: {
data,
- isClosed: getters.openState === constants.CLOSED,
+ isClosed: getters.openState === STATUS_CLOSED,
},
});
@@ -415,9 +414,9 @@ export const emitStateChangedEvent = ({ getters }, data) => {
};
export const toggleIssueLocalState = ({ commit }, newState) => {
- if (newState === constants.CLOSED) {
+ if (newState === STATUS_CLOSED) {
commit(types.CLOSE_ISSUE);
- } else if (newState === constants.REOPENED) {
+ } else if (newState === STATUS_REOPENED) {
commit(types.REOPEN_ISSUE);
}
};
@@ -467,12 +466,17 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
const processQuickActions = (res) => {
const {
- errors: { commands_only: commandsOnly, command_names: commandNames } = {
+ errors: { commands_only: commandsOnly } = {
commands_only: null,
command_names: [],
},
+ command_names: commandNames,
} = res;
- let message = commandsOnly;
+ const message = commandsOnly;
+
+ if (commandNames?.indexOf('submit_review') >= 0) {
+ dispatch('batchComments/clearDrafts');
+ }
/*
The following reply means that quick actions have been successfully applied:
@@ -491,13 +495,6 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
confidentialWidget.setConfidentiality();
}
- const commands = ['approve', 'merge', 'assign_reviewer', 'assign'];
- const commandUpdatesAttentionRequest = commandNames[0].some((c) => commands.includes(c));
-
- if (commandUpdatesAttentionRequest && SidebarStore.singleton.currentUserHasAttention) {
- message = sprintf(__('%{message}. Your attention request was removed.'), { message });
- }
-
$('.js-gfm-input').trigger('clear-commands-cache.atwho');
createAlert({
@@ -759,10 +756,10 @@ export const submitSuggestion = (
const errorMessage = err.response.data?.message;
- const flashMessage = errorMessage || defaultMessage;
+ const alertMessage = errorMessage || defaultMessage;
createAlert({
- message: flashMessage,
+ message: alertMessage,
parent: flashContainer,
});
})
@@ -795,10 +792,10 @@ export const submitSuggestionBatch = ({ commit, dispatch, state }, { message, fl
const errorMessage = err.response.data?.message;
- const flashMessage = errorMessage || defaultMessage;
+ const alertMessage = errorMessage || defaultMessage;
createAlert({
- message: flashMessage,
+ message: alertMessage,
parent: flashContainer,
});
})
diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js
index 5d532b68f1b..7a7aa0deb1d 100644
--- a/app/assets/javascripts/notes/stores/mutations.js
+++ b/app/assets/javascripts/notes/stores/mutations.js
@@ -1,4 +1,5 @@
import { isEqual } from 'lodash';
+import { STATUS_CLOSED, STATUS_REOPENED } from '~/issues/constants';
import { isInMRPage } from '~/lib/utils/common_utils';
import * as constants from '../constants';
import * as types from './mutation_types';
@@ -319,11 +320,11 @@ export default {
},
[types.CLOSE_ISSUE](state) {
- Object.assign(state.noteableData, { state: constants.CLOSED });
+ Object.assign(state.noteableData, { state: STATUS_CLOSED });
},
[types.REOPEN_ISSUE](state) {
- Object.assign(state.noteableData, { state: constants.REOPENED });
+ Object.assign(state.noteableData, { state: STATUS_REOPENED });
},
[types.TOGGLE_STATE_BUTTON_LOADING](state, value) {
diff --git a/app/assets/javascripts/observability/components/observability_app.vue b/app/assets/javascripts/observability/components/observability_app.vue
index ff9cf6ff6c5..36cbe715149 100644
--- a/app/assets/javascripts/observability/components/observability_app.vue
+++ b/app/assets/javascripts/observability/components/observability_app.vue
@@ -2,7 +2,7 @@
import { darkModeEnabled } from '~/lib/utils/color_utils';
import { setUrlParams } from '~/lib/utils/url_utility';
-import { MESSAGE_EVENT_TYPE, SKELETON_VARIANTS_BY_ROUTE } from '../constants';
+import { MESSAGE_EVENT_TYPE, FULL_APP_DIMENSIONS } from '../constants';
import ObservabilitySkeleton from './skeleton/index.vue';
export default {
@@ -14,25 +14,33 @@ export default {
type: String,
required: true,
},
+ inlineEmbed: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ skeletonVariant: {
+ type: String,
+ required: false,
+ default: 'dashboards',
+ },
+ height: {
+ type: String,
+ required: false,
+ default: FULL_APP_DIMENSIONS.HEIGHT,
+ },
+ width: {
+ type: String,
+ required: false,
+ default: FULL_APP_DIMENSIONS.WIDTH,
+ },
},
computed: {
iframeSrcWithParams() {
- return setUrlParams(
+ return `${setUrlParams(
{ theme: darkModeEnabled() ? 'dark' : 'light', username: gon?.current_username },
this.observabilityIframeSrc,
- );
- },
- getSkeletonVariant() {
- const [, variant] =
- Object.entries(SKELETON_VARIANTS_BY_ROUTE).find(([path]) =>
- this.$route.path.endsWith(path),
- ) || [];
-
- const DEFAULT_SKELETON = 'dashboards';
-
- if (!variant) return DEFAULT_SKELETON;
-
- return variant;
+ )}${this.inlineEmbed ? '&kiosk=inline-embed' : ''}`;
},
},
mounted() {
@@ -54,38 +62,24 @@ export default {
this.$refs.observabilitySkeleton.onContentLoaded();
break;
case MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE:
- this.routeUpdateHandler(payload);
+ this.$emit('route-update', payload);
break;
default:
break;
}
},
- routeUpdateHandler(payload) {
- const isNewObservabilityPath = this.$route?.query?.observability_path !== payload?.url;
-
- const shouldNotHandleMessage = !payload.url || !isNewObservabilityPath;
-
- if (shouldNotHandleMessage) {
- return;
- }
-
- // this will update the `observability_path` query param on each route change inside Observability UI
- this.$router.replace({
- name: this.$route.pathname,
- query: { ...this.$route.query, observability_path: payload.url },
- });
- },
},
};
</script>
<template>
- <observability-skeleton ref="observabilitySkeleton" :variant="getSkeletonVariant">
+ <observability-skeleton ref="observabilitySkeleton" :variant="skeletonVariant">
<iframe
id="observability-ui-iframe"
data-testid="observability-ui-iframe"
frameborder="0"
- height="100%"
+ :width="width"
+ :height="height"
:src="iframeSrcWithParams"
sandbox="allow-same-origin allow-forms allow-scripts"
></iframe>
diff --git a/app/assets/javascripts/observability/components/skeleton/embed.vue b/app/assets/javascripts/observability/components/skeleton/embed.vue
new file mode 100644
index 00000000000..7abaf2b1bc7
--- /dev/null
+++ b/app/assets/javascripts/observability/components/skeleton/embed.vue
@@ -0,0 +1,15 @@
+<script>
+import { GlSkeletonLoader } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlSkeletonLoader,
+ },
+};
+</script>
+<template>
+ <gl-skeleton-loader>
+ <rect y="5" width="400" height="30" rx="2" ry="2" />
+ <rect y="50" width="400" height="80" rx="2" ry="2" />
+ </gl-skeleton-loader>
+</template>
diff --git a/app/assets/javascripts/observability/components/skeleton/index.vue b/app/assets/javascripts/observability/components/skeleton/index.vue
index c8f196a43f4..d91f2874943 100644
--- a/app/assets/javascripts/observability/components/skeleton/index.vue
+++ b/app/assets/javascripts/observability/components/skeleton/index.vue
@@ -8,10 +8,12 @@ import {
OBSERVABILITY_ROUTES,
TIMEOUT_ERROR_LABEL,
TIMEOUT_ERROR_MESSAGE,
+ SKELETON_VARIANT_EMBED,
} from '../../constants';
import DashboardsSkeleton from './dashboards.vue';
import ExploreSkeleton from './explore.vue';
import ManageSkeleton from './manage.vue';
+import EmbedSkeleton from './embed.vue';
export default {
components: {
@@ -19,11 +21,13 @@ export default {
DashboardsSkeleton,
ExploreSkeleton,
ManageSkeleton,
+ EmbedSkeleton,
GlAlert,
},
SKELETON_VARIANTS_BY_ROUTE,
SKELETON_STATE,
OBSERVABILITY_ROUTES,
+ SKELETON_VARIANT_EMBED,
i18n: {
TIMEOUT_ERROR_LABEL,
TIMEOUT_ERROR_MESSAGE,
@@ -102,6 +106,7 @@ export default {
<dashboards-skeleton v-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.DASHBOARDS)" />
<explore-skeleton v-else-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.EXPLORE)" />
<manage-skeleton v-else-if="isSkeletonShown($options.OBSERVABILITY_ROUTES.MANAGE)" />
+ <embed-skeleton v-else-if="variant === $options.SKELETON_VARIANT_EMBED" />
<gl-skeleton-loader v-else>
<rect y="2" width="10" height="8" />
@@ -122,12 +127,14 @@ export default {
{{ $options.i18n.TIMEOUT_ERROR_MESSAGE }}
</gl-alert>
- <div
- v-show="state === $options.SKELETON_STATE.HIDDEN"
- data-testid="observability-wrapper"
- class="gl-flex-grow-1 gl-display-flex gl-flex-direction-column gl-flex-align-items-stretch"
- >
- <slot></slot>
- </div>
+ <transition>
+ <div
+ v-show="state === $options.SKELETON_STATE.HIDDEN"
+ data-testid="observability-wrapper"
+ class="gl-flex-grow-1 gl-display-flex gl-flex-direction-column gl-flex-align-items-stretch"
+ >
+ <slot></slot>
+ </div>
+ </transition>
</div>
</template>
diff --git a/app/assets/javascripts/observability/constants.js b/app/assets/javascripts/observability/constants.js
index e4827dd169f..6b97c51e997 100644
--- a/app/assets/javascripts/observability/constants.js
+++ b/app/assets/javascripts/observability/constants.js
@@ -17,6 +17,8 @@ export const SKELETON_VARIANTS_BY_ROUTE = Object.freeze({
[OBSERVABILITY_ROUTES.MANAGE]: 'manage',
});
+export const SKELETON_VARIANT_EMBED = 'embed';
+
export const SKELETON_STATE = Object.freeze({
ERROR: 'error',
VISIBLE: 'visible',
@@ -30,3 +32,13 @@ export const DEFAULT_TIMERS = Object.freeze({
export const TIMEOUT_ERROR_LABEL = __('Unable to load the page');
export const TIMEOUT_ERROR_MESSAGE = __('Reload the page to try again.');
+
+export const INLINE_EMBED_DIMENSIONS = Object.freeze({
+ HEIGHT: '366px',
+ WIDTH: '768px',
+});
+
+export const FULL_APP_DIMENSIONS = Object.freeze({
+ HEIGHT: '100%',
+ WIDTH: '100%',
+});
diff --git a/app/assets/javascripts/observability/index.js b/app/assets/javascripts/observability/index.js
index cd342ebee3e..72ff1357551 100644
--- a/app/assets/javascripts/observability/index.js
+++ b/app/assets/javascripts/observability/index.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import VueRouter from 'vue-router';
import ObservabilityApp from './components/observability_app.vue';
+import { SKELETON_VARIANTS_BY_ROUTE } from './constants';
Vue.use(VueRouter);
@@ -17,10 +18,41 @@ export default () => {
return new Vue({
el,
router,
+ computed: {
+ skeletonVariant() {
+ const [, variant] =
+ Object.entries(SKELETON_VARIANTS_BY_ROUTE).find(([path]) =>
+ this.$route.path.endsWith(path),
+ ) || [];
+
+ return variant;
+ },
+ },
+ methods: {
+ routeUpdateHandler(payload) {
+ const isNewObservabilityPath = this.$route?.query?.observability_path !== payload?.url;
+
+ const shouldNotHandleMessage = !payload.url || !isNewObservabilityPath;
+
+ if (shouldNotHandleMessage) {
+ return;
+ }
+
+ // this will update the `observability_path` query param on each route change inside Observability UI
+ this.$router.replace({
+ name: this.$route?.pathname,
+ query: { ...this.$route.query, observability_path: payload.url },
+ });
+ },
+ },
render(h) {
return h(ObservabilityApp, {
props: {
observabilityIframeSrc: el.dataset.observabilityIframeSrc,
+ skeletonVariant: this.skeletonVariant,
+ },
+ on: {
+ 'route-update': (payload) => this.routeUpdateHandler(payload),
},
});
},
diff --git a/app/assets/javascripts/operation_settings/store/actions.js b/app/assets/javascripts/operation_settings/store/actions.js
index 5f60cab8bdd..7fa79da59c4 100644
--- a/app/assets/javascripts/operation_settings/store/actions.js
+++ b/app/assets/javascripts/operation_settings/store/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -26,7 +26,7 @@ export const saveChanges = ({ state, dispatch }) =>
export const receiveSaveChangesSuccess = () => {
/**
* The operations_controller currently handles successful requests
- * by creating a flash banner messsage to notify the user.
+ * by creating an alert banner message to notify the user.
*/
refreshCurrentPage();
};
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/delete_modal.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/delete_modal.vue
index 2da8ca2d8a8..0757ac5522a 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/delete_modal.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/delete_modal.vue
@@ -85,7 +85,7 @@ export default {
size="sm"
:action-primary="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ {
text: __('Delete'),
- attributes: [{ variant: 'danger' }, { disabled: disablePrimaryButton }],
+ attributes: { variant: 'danger', disabled: disablePrimaryButton },
} /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
:action-cancel="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ {
text: __('Cancel'),
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue
index c10d8be69a0..863d1c2629b 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue
@@ -1,6 +1,6 @@
<script>
import { GlEmptyState } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { n__ } from '~/locale';
import { joinPaths } from '~/lib/utils/url_utility';
import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
@@ -87,6 +87,9 @@ export default {
tags() {
return this.containerRepository?.tags?.nodes || [];
},
+ hideBulkDelete() {
+ return !(this.containerRepository?.canDelete || false);
+ },
tagsPageInfo() {
return this.containerRepository?.tags?.pageInfo;
},
@@ -98,9 +101,6 @@ export default {
sort: this.sort,
};
},
- showMultiDeleteButton() {
- return this.tags.some((tag) => tag.canDelete) && !this.isMobile;
- },
hasNoTags() {
return this.tags.length === 0;
},
@@ -186,6 +186,7 @@ export default {
/>
<template v-else>
<registry-list
+ :hidden-delete="hideBulkDelete"
:title="listTitle"
:pagination="tagsPageInfo"
:items="tags"
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue
index 38b601ac3ec..8e89128a382 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue
@@ -109,9 +109,6 @@ export default {
isInvalidTag() {
return !this.tag.digest;
},
- isDeleteDisabled() {
- return this.disabled || !this.tag.canDelete;
- },
},
};
</script>
@@ -179,16 +176,16 @@ export default {
</gl-sprintf>
</span>
</template>
- <template #right-action>
+ <template v-if="tag.canDelete" #right-action>
<gl-dropdown
- :disabled="isDeleteDisabled"
+ :disabled="disabled"
icon="ellipsis_v"
:text="$options.i18n.MORE_ACTIONS_TEXT"
:text-sr-only="true"
category="tertiary"
no-caret
right
- :class="{ 'gl-opacity-0 gl-pointer-events-none': isDeleteDisabled }"
+ :class="{ 'gl-opacity-0 gl-pointer-events-none': disabled }"
data-testid="additional-actions"
data-qa-selector="more_actions_menu"
>
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
index 4f89d217623..f6f816f435c 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective, GlIcon, GlSprintf, GlSkeletonLoader, GlButton } from '@gitlab/ui';
+import { GlTooltipDirective, GlSprintf, GlSkeletonLoader, GlButton } from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { n__ } from '~/locale';
import Tracking from '~/tracking';
@@ -28,7 +28,6 @@ export default {
DeleteButton,
GlSprintf,
GlButton,
- GlIcon,
ListItem,
GlSkeletonLoader,
CleanupStatus,
@@ -80,8 +79,8 @@ export default {
},
tagsCountText() {
return n__(
- 'ContainerRegistry|%{count} Tag',
- 'ContainerRegistry|%{count} Tags',
+ 'ContainerRegistry|%{count} tag',
+ 'ContainerRegistry|%{count} tags',
this.item.tagsCount,
);
},
@@ -152,7 +151,6 @@ export default {
<span v-if="deleting">{{ $options.i18n.ROW_SCHEDULED_FOR_DELETION }}</span>
<template v-else>
<span class="gl-display-flex gl-align-items-center" data-testid="tags-count">
- <gl-icon name="tag" class="gl-mr-2" />
<gl-sprintf :message="tagsCountText">
<template #count>
{{ item.tagsCount }}
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql
index e57ac2a9efe..a0a80600603 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql
@@ -12,6 +12,7 @@ query getContainerRepositoryTags(
containerRepository(id: $id) {
id
tagsCount
+ canDelete
tags(after: $after, before: $before, first: $first, last: $last, name: $name, sort: $sort) {
nodes {
digest
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue
index 83c0d2cdfca..2b5fb1a70ed 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue
@@ -1,7 +1,7 @@
<script>
import { GlResizeObserverDirective, GlEmptyState } from '@gitlab/ui';
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import Tracking from '~/tracking';
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue
index 8a038d7c974..6d9273d543f 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue
@@ -10,7 +10,8 @@ import {
} from '@gitlab/ui';
import { get } from 'lodash';
import getContainerRepositoriesQuery from 'shared_queries/container_registry/get_container_repositories.query.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import Tracking from '~/tracking';
import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
@@ -145,7 +146,7 @@ export default {
return [];
},
graphqlResource() {
- return this.config.isGroupPage ? 'group' : 'project';
+ return this.config.isGroupPage ? WORKSPACE_GROUP : WORKSPACE_PROJECT;
},
queryVariables() {
return {
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 45dc217b9e3..b24ec65464f 100644
--- a/app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue
+++ b/app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue
@@ -55,7 +55,7 @@ export default {
modalButtons: {
primary: {
text: s__('DependencyProxy|Clear cache'),
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
},
secondary: {
text: __('Cancel'),
diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/details.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/details.vue
index bafcd78ad5d..bff32a124bc 100644
--- a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/details.vue
+++ b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/details.vue
@@ -9,7 +9,7 @@ import {
TAG_LABEL,
} from '~/packages_and_registries/harbor_registry/constants/index';
import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import TagsLoader from '~/packages_and_registries/shared/components/tags_loader.vue';
import ArtifactsList from '~/packages_and_registries/harbor_registry/components/details/artifacts_list.vue';
diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue
index 1323d347d10..8bc1ecba5fe 100644
--- a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue
+++ b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue
@@ -4,7 +4,7 @@ import TagsList from '~/packages_and_registries/harbor_registry/components/tags/
import { getHarborTags } from '~/rest_api';
import { FETCH_TAGS_ERROR_MESSAGE } from '~/packages_and_registries/harbor_registry/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { formatPagination } from '~/packages_and_registries/harbor_registry/utils';
export default {
diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue
index 931a99649cb..1d8cb0f1360 100644
--- a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue
+++ b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue
@@ -12,7 +12,7 @@ import {
dockerPushCommand,
dockerLoginCommand,
} from '~/packages_and_registries/harbor_registry/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import {
SORT_FIELDS,
CONNECTION_ERROR_TITLE,
diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue
index fd099ee4e69..fdc58e4bd05 100644
--- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue
+++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue
@@ -122,15 +122,15 @@ export default {
modal: {
packageDeletePrimaryAction: {
text: __('Delete'),
- attributes: [
- { variant: 'danger' },
- { category: 'primary' },
- { 'data-qa-selector': 'delete_modal_button' },
- ],
+ attributes: {
+ variant: 'danger',
+ category: 'primary',
+ 'data-qa-selector': 'delete_modal_button',
+ },
},
fileDeletePrimaryAction: {
text: __('Delete'),
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
},
cancelAction: {
text: __('Cancel'),
diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/store/actions.js b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/store/actions.js
index 223f427ce0e..62c4f96eff7 100644
--- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/store/actions.js
+++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/store/actions.js
@@ -1,5 +1,5 @@
import Api from '~/api';
-import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/alert';
import {
DELETE_PACKAGE_ERROR_MESSAGE,
DELETE_PACKAGE_FILE_ERROR_MESSAGE,
diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue
index 0aeeb2c3d15..6ea1fff9ef0 100644
--- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue
+++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue
@@ -1,7 +1,7 @@
<script>
import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
import { mapActions, mapState } from 'vuex';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { historyReplaceState } from '~/lib/utils/common_utils';
import { s__ } from '~/locale';
import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages_and_registries/shared/constants';
diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js
index 7af3fc1c2db..05673215a66 100644
--- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js
+++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js
@@ -6,7 +6,6 @@ export const FETCH_PACKAGES_LIST_ERROR_MESSAGE = __(
export const DELETE_PACKAGE_SUCCESS_MESSAGE = __('Package deleted successfully');
export const DEFAULT_PAGE = 1;
-export const DEFAULT_PAGE_SIZE = 20;
export const GROUP_PAGE_TYPE = 'groups';
diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js
index 7a452abdc26..122123f49cd 100644
--- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js
+++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js
@@ -1,13 +1,13 @@
import Api from '~/api';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { DELETE_PACKAGE_ERROR_MESSAGE } from '~/packages_and_registries/shared/constants';
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
+import { DEFAULT_PAGE_SIZE } from '~/vue_shared/issuable/list/constants';
import {
FETCH_PACKAGES_LIST_ERROR_MESSAGE,
DELETE_PACKAGE_SUCCESS_MESSAGE,
DEFAULT_PAGE,
- DEFAULT_PAGE_SIZE,
MISSING_DELETE_PATH_ERROR,
TERRAFORM_SEARCH_TYPE,
} from '../constants';
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/delete_modal.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/delete_modal.vue
index 011a2668a8b..b167fff26b0 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/delete_modal.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/delete_modal.vue
@@ -32,7 +32,7 @@ export default {
modal: {
packagesDeletePrimaryAction: {
text: DELETE_PACKAGE_MODAL_PRIMARY_ACTION,
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
},
cancelAction: {
text: __('Cancel'),
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/maven_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/maven_installation.vue
index 4510c7a7322..95b83d87792 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/maven_installation.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/maven_installation.vue
@@ -13,6 +13,7 @@ import {
TRACKING_LABEL_CODE_INSTRUCTION,
TRACKING_LABEL_MAVEN_INSTALLATION,
MAVEN_HELP_PATH,
+ MAVEN_INSTALLATION_COMMAND,
} from '~/packages_and_registries/package_registry/constants';
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
@@ -55,11 +56,6 @@ export default {
<version>${this.appVersion}</version>
</dependency>`;
},
-
- mavenInstallationCommand() {
- return `mvn dependency:get -Dartifact=${this.appGroup}:${this.appName}:${this.appVersion}`;
- },
-
mavenSetupXml() {
return `<repositories>
<repository>
@@ -135,6 +131,7 @@ export default {
{ value: 'groovy', label: s__('PackageRegistry|Gradle Groovy DSL') },
{ value: 'kotlin', label: s__('PackageRegistry|Gradle Kotlin DSL') },
],
+ MAVEN_INSTALLATION_COMMAND,
};
</script>
@@ -164,8 +161,9 @@ export default {
/>
<code-instruction
+ class="gl-w-20 gl-mt-5"
:label="s__('PackageRegistry|Maven Command')"
- :instruction="mavenInstallationCommand"
+ :instruction="$options.MAVEN_INSTALLATION_COMMAND"
:copy-text="s__('PackageRegistry|Copy Maven command')"
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_MAVEN_COMMAND"
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue
index d982df4f984..3d5ac528920 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue
@@ -4,16 +4,22 @@ import VersionRow from '~/packages_and_registries/package_registry/components/de
import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
import DeleteModal from '~/packages_and_registries/package_registry/components/delete_modal.vue';
+import DeletePackageModal from '~/packages_and_registries/shared/components/delete_package_modal.vue';
import {
+ CANCEL_DELETE_PACKAGE_VERSION_TRACKING_ACTION,
CANCEL_DELETE_PACKAGE_VERSIONS_TRACKING_ACTION,
+ DELETE_PACKAGE_VERSION_TRACKING_ACTION,
DELETE_PACKAGE_VERSIONS_TRACKING_ACTION,
+ REQUEST_DELETE_PACKAGE_VERSION_TRACKING_ACTION,
REQUEST_DELETE_PACKAGE_VERSIONS_TRACKING_ACTION,
} from '~/packages_and_registries/package_registry/constants';
import Tracking from '~/tracking';
+import { packageTypeToTrackCategory } from '~/packages_and_registries/package_registry/utils';
export default {
components: {
DeleteModal,
+ DeletePackageModal,
VersionRow,
PackagesListLoader,
RegistryList,
@@ -42,6 +48,7 @@ export default {
},
data() {
return {
+ itemToBeDeleted: null,
itemsToBeDeleted: [],
};
},
@@ -52,8 +59,25 @@ export default {
isListEmpty() {
return this.versions.length === 0;
},
+ tracking() {
+ const category = this.itemToBeDeleted
+ ? packageTypeToTrackCategory(this.itemToBeDeleted.packageType)
+ : undefined;
+ return {
+ category,
+ };
+ },
},
methods: {
+ deleteItemConfirmation() {
+ this.$emit('delete', [this.itemToBeDeleted]);
+ this.track(DELETE_PACKAGE_VERSION_TRACKING_ACTION);
+ this.itemToBeDeleted = null;
+ },
+ deleteItemCanceled() {
+ this.track(CANCEL_DELETE_PACKAGE_VERSION_TRACKING_ACTION);
+ this.itemToBeDeleted = null;
+ },
deleteItemsCanceled() {
this.track(CANCEL_DELETE_PACKAGE_VERSIONS_TRACKING_ACTION);
this.itemsToBeDeleted = [];
@@ -63,7 +87,16 @@ export default {
this.track(DELETE_PACKAGE_VERSIONS_TRACKING_ACTION);
this.itemsToBeDeleted = [];
},
+ setItemToBeDeleted(item) {
+ this.itemToBeDeleted = { ...item };
+ this.track(REQUEST_DELETE_PACKAGE_VERSION_TRACKING_ACTION);
+ },
setItemsToBeDeleted(items) {
+ if (items.length === 1) {
+ const [item] = items;
+ this.setItemToBeDeleted(item);
+ return;
+ }
this.itemsToBeDeleted = items;
this.track(REQUEST_DELETE_PACKAGE_VERSIONS_TRACKING_ACTION);
this.$refs.deletePackagesModal.show();
@@ -89,18 +122,22 @@ export default {
@next-page="$emit('next-page')"
>
<template #default="{ first, item, isSelected, selectItem }">
- <!-- `first` prop is used to decide whether to show the top border
- for the first element. We want to show the top border only when
- user has permission to bulk delete versions. -->
<version-row
- :first="canDestroy && first"
+ :first="first"
:package-entity="item"
:selected="isSelected(item)"
+ @delete="setItemToBeDeleted(item)"
@select="selectItem(item)"
/>
</template>
</registry-list>
+ <delete-package-modal
+ :item-to-be-deleted="itemToBeDeleted"
+ @ok="deleteItemConfirmation"
+ @cancel="deleteItemCanceled"
+ />
+
<delete-modal
ref="deletePackagesModal"
:items-to-be-deleted="itemsToBeDeleted"
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue
index fdc6e75c932..ea6ebb614f4 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue
@@ -28,6 +28,9 @@ export default {
},
},
computed: {
+ isPrivatePackage() {
+ return !this.packageEntity.publicPackage;
+ },
pypiPipCommand() {
// eslint-disable-next-line @gitlab/require-i18n-strings
return `pip install ${this.packageEntity.name} --index-url ${this.packageEntity.pypiUrl}`;
@@ -75,7 +78,7 @@ password = <your personal access token>`;
:tracking-action="$options.tracking.TRACKING_ACTION_COPY_PIP_INSTALL_COMMAND"
:tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION"
/>
- <template #description>
+ <template v-if="isPrivatePackage" #description>
<gl-sprintf :message="$options.i18n.tokenText">
<template #link="{ content }">
<gl-link
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/version_row.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/version_row.vue
index 9f8f6328970..193a222853f 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/version_row.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/version_row.vue
@@ -1,5 +1,7 @@
<script>
import {
+ GlDropdown,
+ GlDropdownItem,
GlFormCheckbox,
GlIcon,
GlLink,
@@ -13,6 +15,7 @@ import PublishMethod from '~/packages_and_registries/shared/components/publish_m
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import {
+ DELETE_PACKAGE_TEXT,
ERRORED_PACKAGE_TEXT,
ERROR_PUBLISHING,
PACKAGE_ERROR_STATUS,
@@ -22,6 +25,8 @@ import {
export default {
name: 'PackageVersionRow',
components: {
+ GlDropdown,
+ GlDropdownItem,
GlFormCheckbox,
GlIcon,
GlLink,
@@ -58,6 +63,7 @@ export default {
},
},
i18n: {
+ deletePackage: DELETE_PACKAGE_TEXT,
erroredPackageText: ERRORED_PACKAGE_TEXT,
errorPublishing: ERROR_PUBLISHING,
warningText: WARNING_TEXT,
@@ -121,5 +127,19 @@ export default {
</gl-sprintf>
</span>
</template>
+
+ <template v-if="packageEntity.canDestroy" #right-action>
+ <gl-dropdown
+ icon="ellipsis_v"
+ :text="$options.i18n.moreActions"
+ :text-sr-only="true"
+ category="tertiary"
+ no-caret
+ >
+ <gl-dropdown-item variant="danger" @click="$emit('delete')">{{
+ $options.i18n.deletePackage
+ }}</gl-dropdown-item>
+ </gl-dropdown>
+ </template>
</list-item>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/functional/delete_packages.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/functional/delete_packages.vue
index 0914c013108..b7e66d20e78 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/functional/delete_packages.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/functional/delete_packages.vue
@@ -1,6 +1,6 @@
<script>
import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
-import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/alert';
import {
DELETE_PACKAGE_ERROR_MESSAGE,
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue
index 16f21bfe61d..c5354b7e7df 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue
@@ -8,9 +8,10 @@ import {
GlTooltipDirective,
GlTruncate,
} from '@gitlab/ui';
-import { s__, __ } from '~/locale';
+import { __ } from '~/locale';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import {
+ DELETE_PACKAGE_TEXT,
ERRORED_PACKAGE_TEXT,
ERROR_PUBLISHING,
PACKAGE_ERROR_STATUS,
@@ -91,7 +92,7 @@ export default {
i18n: {
erroredPackageText: ERRORED_PACKAGE_TEXT,
createdAt: __('Created %{timestamp}'),
- deletePackage: s__('PackageRegistry|Delete package'),
+ deletePackage: DELETE_PACKAGE_TEXT,
errorPublishing: ERROR_PUBLISHING,
warning: WARNING_TEXT,
moreActions: __('More actions'),
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/constants.js b/app/assets/javascripts/packages_and_registries/package_registry/constants.js
index d979ae5c08c..eda8d9e0066 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/constants.js
+++ b/app/assets/javascripts/packages_and_registries/package_registry/constants.js
@@ -27,15 +27,8 @@ export const PACKAGE_TYPE_DEBIAN = 'DEBIAN';
export const PACKAGE_TYPE_HELM = 'HELM';
export const TRACKING_LABEL_CODE_INSTRUCTION = 'code_instruction';
-export const TRACKING_LABEL_CONAN_INSTALLATION = 'conan_installation';
export const TRACKING_LABEL_MAVEN_INSTALLATION = 'maven_installation';
-export const TRACKING_LABEL_NPM_INSTALLATION = 'npm_installation';
-export const TRACKING_LABEL_NUGET_INSTALLATION = 'nuget_installation';
-export const TRACKING_LABEL_PYPI_INSTALLATION = 'pypi_installation';
-export const TRACKING_LABEL_COMPOSER_INSTALLATION = 'composer_installation';
-
-export const TRACKING_ACTION_INSTALLATION = 'installation';
-export const TRACKING_ACTION_REGISTRY_SETUP = 'registry_setup';
+export const MAVEN_INSTALLATION_COMMAND = 'mvn install';
export const TRACKING_ACTION_COPY_CONAN_COMMAND = 'copy_conan_command';
export const TRACKING_ACTION_COPY_CONAN_SETUP_COMMAND = 'copy_conan_setup_command';
@@ -68,7 +61,6 @@ export const TRACKING_ACTION_COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND =
export const TRACKING_LABEL_PACKAGE_ASSET = 'package_assets';
-export const TRACKING_ACTION_DOWNLOAD_PACKAGE_ASSET = 'download_package_asset';
export const TRACKING_ACTION_EXPAND_PACKAGE_ASSET = 'expand_package_asset';
export const TRACKING_ACTION_COPY_PACKAGE_ASSET_SHA = 'copy_package_asset_sha';
@@ -119,6 +111,10 @@ export const DELETE_PACKAGE_VERSIONS_TRACKING_ACTION = 'delete_package_versions'
export const REQUEST_DELETE_PACKAGE_VERSIONS_TRACKING_ACTION = 'request_delete_package_versions';
export const CANCEL_DELETE_PACKAGE_VERSIONS_TRACKING_ACTION = 'cancel_delete_package_versions';
+export const DELETE_PACKAGE_VERSION_TRACKING_ACTION = 'delete_package_version';
+export const REQUEST_DELETE_PACKAGE_VERSION_TRACKING_ACTION = 'request_delete_package_version';
+export const CANCEL_DELETE_PACKAGE_VERSION_TRACKING_ACTION = 'cancel_delete_package_version';
+
export const DELETE_PACKAGES_ERROR_MESSAGE = s__(
'PackageRegistry|Something went wrong while deleting packages.',
);
@@ -127,6 +123,7 @@ export const DELETE_PACKAGES_SUCCESS_MESSAGE = s__('PackageRegistry|Packages del
export const DELETE_PACKAGES_MODAL_TITLE = s__('PackageRegistry|Delete packages');
export const DELETE_PACKAGE_MODAL_PRIMARY_ACTION = s__('PackageRegistry|Permanently delete');
+export const DELETE_PACKAGE_TEXT = s__('PackageRegistry|Delete package');
export const DELETE_PACKAGE_SUCCESS_MESSAGE = s__('PackageRegistry|Package deleted successfully');
export const DELETE_PACKAGE_ERROR_MESSAGE = s__(
'PackageRegistry|Something went wrong while deleting the package.',
@@ -142,8 +139,6 @@ export const PACKAGE_REGISTRY_TITLE = __('Package Registry');
export const PACKAGE_ERROR_STATUS = 'ERROR';
export const PACKAGE_DEFAULT_STATUS = 'DEFAULT';
-export const PACKAGE_HIDDEN_STATUS = 'HIDDEN';
-export const PACKAGE_PROCESSING_STATUS = 'PROCESSING';
export const NPM_PACKAGE_MANAGER = 'npm';
export const YARN_PACKAGE_MANAGER = 'yarn';
@@ -151,8 +146,6 @@ export const YARN_PACKAGE_MANAGER = 'yarn';
export const PROJECT_PACKAGE_ENDPOINT_TYPE = 'project';
export const INSTANCE_PACKAGE_ENDPOINT_TYPE = 'instance';
-export const PROJECT_RESOURCE_TYPE = 'project';
-export const GROUP_RESOURCE_TYPE = 'group';
export const GRAPHQL_PAGE_SIZE = 20;
export const LIST_KEY_NAME = 'name';
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql
index 109d535469b..b5313f929f8 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql
+++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql
@@ -15,6 +15,7 @@ query getPackageDetails(
updatedAt
status
canDestroy
+ publicPackage
npmUrl
mavenUrl
conanUrl
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue
index 4591c2eca87..1ce2140894e 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue
@@ -10,7 +10,7 @@ import {
GlTabs,
GlSprintf,
} from '@gitlab/ui';
-import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/alert';
import { TYPENAME_PACKAGES_PACKAGE } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { numberToHumanSize } from '~/lib/utils/number_utils';
@@ -314,19 +314,19 @@ export default {
modal: {
packageDeletePrimaryAction: {
text: s__('PackageRegistry|Permanently delete'),
- attributes: [
- { variant: 'danger' },
- { category: 'primary' },
- { 'data-qa-selector': 'delete_modal_button' },
- ],
+ attributes: {
+ variant: 'danger',
+ category: 'primary',
+ 'data-qa-selector': 'delete_modal_button',
+ },
},
fileDeletePrimaryAction: {
text: __('Delete'),
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
},
filesDeletePrimaryAction: {
text: s__('PackageRegistry|Permanently delete assets'),
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
},
cancelAction: {
text: __('Cancel'),
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 31c76c95e45..6e92a6420ac 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
@@ -1,12 +1,11 @@
<script>
import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import { historyReplaceState } from '~/lib/utils/common_utils';
import { s__ } from '~/locale';
import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages_and_registries/shared/constants';
import {
- PROJECT_RESOURCE_TYPE,
- GROUP_RESOURCE_TYPE,
GRAPHQL_PAGE_SIZE,
DELETE_PACKAGE_SUCCESS_MESSAGE,
EMPTY_LIST_HELP_URL,
@@ -44,7 +43,7 @@ export default {
return this.queryVariables;
},
update(data) {
- return data[this.graphqlResource].packages;
+ return data[this.graphqlResource]?.packages ?? {};
},
skip() {
return !this.sort;
@@ -64,7 +63,7 @@ export default {
};
},
graphqlResource() {
- return this.isGroupPage ? GROUP_RESOURCE_TYPE : PROJECT_RESOURCE_TYPE;
+ return this.isGroupPage ? WORKSPACE_GROUP : WORKSPACE_PROJECT;
},
pageInfo() {
return this.packages?.pageInfo ?? {};
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue
index 36eb65c623b..4c25c0f97de 100644
--- a/app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue
+++ b/app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue
@@ -72,7 +72,7 @@ export default {
</script>
<template>
- <div>
+ <div data-testid="packages-and-registries-group-settings">
<gl-alert v-if="alertMessage" variant="warning" class="gl-mt-4" @dismiss="dismissAlert">
{{ alertMessage }}
</gl-alert>
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/constants.js b/app/assets/javascripts/packages_and_registries/settings/group/constants.js
index c93cd7f7d78..b47759df35f 100644
--- a/app/assets/javascripts/packages_and_registries/settings/group/constants.js
+++ b/app/assets/javascripts/packages_and_registries/settings/group/constants.js
@@ -78,8 +78,4 @@ export const MAVEN_FORWARDING_FIELDS = {
// Parameters
-export const PACKAGES_DOCS_PATH = helpPagePath('user/packages/index');
-export const MAVEN_DUPLICATES_ALLOWED = 'mavenDuplicatesAllowed';
-export const MAVEN_DUPLICATE_EXCEPTION_REGEX = 'mavenDuplicateExceptionRegex';
-
export const DEPENDENCY_PROXY_DOCS_PATH = helpPagePath('user/packages/dependency_proxy/index');
diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy_form.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy_form.vue
index 11d8732426d..dd22d29d9a7 100644
--- a/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy_form.vue
+++ b/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy_form.vue
@@ -312,7 +312,7 @@ export default {
>
{{ __('Cancel') }}
</gl-button>
- <span class="gl-font-style-italic gl-text-gray-400">{{
+ <span class="gl-font-style-italic gl-text-gray-500">{{
$options.i18n.EXPIRATION_POLICY_FOOTER_NOTE
}}</span>
</div>
diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue
index f06e3a41bd0..0bbb501011a 100644
--- a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue
+++ b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue
@@ -64,7 +64,7 @@ export default {
</gl-form-select>
</div>
<template v-if="description" #description>
- <span data-testid="description" class="gl-text-gray-400">
+ <span data-testid="description" class="gl-text-gray-500">
{{ description }}
</span>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue
index 3fbbfd75ffb..749650e1060 100644
--- a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue
+++ b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue
@@ -101,7 +101,7 @@ export default {
trim
/>
<template #description>
- <span data-testid="description" class="gl-text-gray-400">
+ <span data-testid="description" class="gl-text-gray-500">
<gl-sprintf :message="description">
<template #link="{ content }">
<gl-link :href="tagsRegexHelpPagePath">{{ content }}</gl-link>
diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue
index 2c1368262f2..4cc9cc190e8 100644
--- a/app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue
+++ b/app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue
@@ -42,7 +42,7 @@ export default {
</script>
<template>
- <div>
+ <div data-testid="packages-and-registries-project-settings">
<gl-alert
v-if="showAlert"
variant="success"
diff --git a/app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue b/app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue
index 7485f8282ee..1c8f80972df 100644
--- a/app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue
+++ b/app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue
@@ -125,7 +125,7 @@ export default {
:select-item="selectItem"
:is-selected="isSelected"
:item="item"
- :first="index === 0"
+ :first="!hiddenDelete && index === 0"
></slot>
</div>
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/index.js b/app/assets/javascripts/pages/admin/abuse_reports/index.js
index ab29f9149f7..7634f131e4d 100644
--- a/app/assets/javascripts/pages/admin/abuse_reports/index.js
+++ b/app/assets/javascripts/pages/admin/abuse_reports/index.js
@@ -1,3 +1,4 @@
+import { initAbuseReportsApp } from '~/admin/abuse_reports';
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
import UsersSelect from '~/users_select';
import AbuseReports from './abuse_reports';
@@ -6,3 +7,4 @@ 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/components/signup_form.vue b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue
index 96477b9f476..7e6654140a9 100644
--- a/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue
+++ b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue
@@ -207,6 +207,10 @@ export default {
emailConfirmationSettingsOffHelpText: s__(
'ApplicationSettings|New users can sign up without confirming their email address.',
),
+ emailConfirmationSettingsSoftLabel: s__('ApplicationSettings|Soft'),
+ emailConfirmationSettingsSoftHelpText: s__(
+ 'ApplicationSettings|Send a confirmation email during sign up. New users can log in immediately, but must confirm their email within three days.',
+ ),
emailConfirmationSettingsHardLabel: s__('ApplicationSettings|Hard'),
emailConfirmationSettingsHardHelpText: s__(
'ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in.',
@@ -286,16 +290,23 @@ export default {
v-model="form.emailConfirmationSetting"
name="application_setting[email_confirmation_setting]"
>
- <gl-form-radio value="hard">
- {{ $options.i18n.emailConfirmationSettingsHardLabel }}
-
- <template #help> {{ $options.i18n.emailConfirmationSettingsHardHelpText }} </template>
- </gl-form-radio>
<gl-form-radio value="off">
{{ $options.i18n.emailConfirmationSettingsOffLabel }}
<template #help> {{ $options.i18n.emailConfirmationSettingsOffHelpText }} </template>
</gl-form-radio>
+
+ <gl-form-radio value="soft">
+ {{ $options.i18n.emailConfirmationSettingsSoftLabel }}
+
+ <template #help> {{ $options.i18n.emailConfirmationSettingsSoftHelpText }} </template>
+ </gl-form-radio>
+
+ <gl-form-radio value="hard">
+ {{ $options.i18n.emailConfirmationSettingsHardLabel }}
+
+ <template #help> {{ $options.i18n.emailConfirmationSettingsHardHelpText }} </template>
+ </gl-form-radio>
</gl-form-radio-group>
</gl-form-group>
diff --git a/app/assets/javascripts/pages/admin/application_settings/network/index.js b/app/assets/javascripts/pages/admin/application_settings/network/index.js
new file mode 100644
index 00000000000..841c68c5cd0
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/application_settings/network/index.js
@@ -0,0 +1,3 @@
+import initNetworkOutbound from '~/admin/application_settings/network_outbound';
+
+initNetworkOutbound();
diff --git a/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js b/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
index 97fb64f9971..54c1e37d899 100644
--- a/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
+++ b/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js b/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
index 1cd19fc09a8..41862789185 100644
--- a/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
+++ b/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs_modal.vue b/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs_modal.vue
index d5857294617..3bc785ee1b6 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs_modal.vue
+++ b/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs_modal.vue
@@ -1,6 +1,6 @@
<script>
import { GlModal } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { redirectTo } from '~/lib/utils/url_utility';
import {
@@ -43,7 +43,7 @@ export default {
},
primaryAction: {
text: PRIMARY_ACTION_TEXT,
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
},
cancelAction: {
text: CANCEL_TEXT,
diff --git a/app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue b/app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue
index 48241a213ef..3a91f8e2c55 100644
--- a/app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue
+++ b/app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue
@@ -72,7 +72,7 @@ export default {
primaryProps() {
return {
text: __('Delete project'),
- attributes: [{ variant: 'danger' }, { category: 'primary' }, { disabled: !this.canSubmit }],
+ attributes: { variant: 'danger', category: 'primary', disabled: !this.canSubmit },
};
},
},
diff --git a/app/assets/javascripts/pages/admin/runners/register/index.js b/app/assets/javascripts/pages/admin/runners/register/index.js
new file mode 100644
index 00000000000..d7ee2ee369a
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/runners/register/index.js
@@ -0,0 +1,3 @@
+import { initAdminRegisterRunner } from '~/ci/runner/admin_register_runner';
+
+initAdminRegisterRunner();
diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
index 2fdf3c42935..f57b6144b69 100644
--- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js
+++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
@@ -4,7 +4,7 @@ import $ from 'jquery';
import { getGroups } from '~/api/groups_api';
import { getProjects } from '~/api/projects_api';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { addDelimiter } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/pages/groups/new/components/app.vue b/app/assets/javascripts/pages/groups/new/components/app.vue
index f01e5e595a3..8b68cb5f3bf 100644
--- a/app/assets/javascripts/pages/groups/new/components/app.vue
+++ b/app/assets/javascripts/pages/groups/new/components/app.vue
@@ -2,7 +2,7 @@
import importGroupIllustration from '@gitlab/svgs/dist/illustrations/group-import.svg';
import newGroupIllustration from '@gitlab/svgs/dist/illustrations/group-new.svg';
-import { __, s__ } from '~/locale';
+import { s__ } from '~/locale';
import NewNamespacePage from '~/vue_shared/new_namespace/new_namespace_page.vue';
import createGroupDescriptionDetails from './create_group_description_details.vue';
@@ -11,6 +11,15 @@ export default {
NewNamespacePage,
},
props: {
+ groupsUrl: {
+ type: String,
+ required: true,
+ },
+ parentGroupUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
parentGroupName: {
type: String,
required: false,
@@ -28,8 +37,16 @@ export default {
},
},
computed: {
- initialBreadcrumb() {
- return this.parentGroupName || __('New group');
+ initialBreadcrumbs() {
+ return this.parentGroupUrl
+ ? [
+ { text: this.parentGroupName, href: this.parentGroupUrl },
+ { text: s__('GroupsNew|New subgroup'), href: '#' },
+ ]
+ : [
+ { text: s__('GroupsNew|Groups'), href: this.groupsUrl },
+ { text: s__('GroupsNew|New group'), href: '#' },
+ ];
},
panels() {
return [
@@ -68,7 +85,7 @@ export default {
<template>
<new-namespace-page
:jump-to-last-persisted-panel="hasErrors"
- :initial-breadcrumb="initialBreadcrumb"
+ :initial-breadcrumbs="initialBreadcrumbs"
:panels="panels"
:title="s__('GroupsNew|Create new group')"
persistence-key="new_group_last_active_tab"
diff --git a/app/assets/javascripts/pages/groups/new/group_path_validator.js b/app/assets/javascripts/pages/groups/new/group_path_validator.js
index fa111032b2e..16f4f7b7f7e 100644
--- a/app/assets/javascripts/pages/groups/new/group_path_validator.js
+++ b/app/assets/javascripts/pages/groups/new/group_path_validator.js
@@ -1,6 +1,6 @@
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import InputValidator from '~/validators/input_validator';
import { getGroupPathAvailability } from '~/rest_api';
diff --git a/app/assets/javascripts/pages/groups/new/index.js b/app/assets/javascripts/pages/groups/new/index.js
index a555038ed5c..b16c5f3da9f 100644
--- a/app/assets/javascripts/pages/groups/new/index.js
+++ b/app/assets/javascripts/pages/groups/new/index.js
@@ -22,6 +22,8 @@ initFilePickers();
function initNewGroupCreation(el) {
const {
hasErrors,
+ groupsUrl,
+ parentGroupUrl,
parentGroupName,
importExistingGroupPath,
verificationRequired,
@@ -30,6 +32,8 @@ function initNewGroupCreation(el) {
} = el.dataset;
const props = {
+ groupsUrl,
+ parentGroupUrl,
parentGroupName,
importExistingGroupPath,
hasErrors: parseBoolean(hasErrors),
diff --git a/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue b/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue
index 3dcababb4fd..582aee3c9a3 100644
--- a/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue
+++ b/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue
@@ -10,11 +10,12 @@ import {
} from '@gitlab/ui';
import { s__, __ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { getBulkImportsHistory } from '~/rest_api';
import ImportStatus from '~/import_entities/components/import_status.vue';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import PaginationBar from '~/vue_shared/components/pagination_bar/pagination_bar.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
@@ -131,15 +132,15 @@ export default {
},
getPresentationUrl(item) {
- const suffix = item.entity_type === 'group' ? '/' : '';
+ const suffix = item.entity_type === WORKSPACE_GROUP ? '/' : '';
return `${item.destination_full_path}${suffix}`;
},
getEntityTooltip(item) {
switch (item.entity_type) {
- case 'project':
+ case WORKSPACE_PROJECT:
return __('Project');
- case 'group':
+ case WORKSPACE_GROUP:
return __('Group');
default:
return '';
diff --git a/app/assets/javascripts/pages/import/history/components/import_error_details.vue b/app/assets/javascripts/pages/import/history/components/import_error_details.vue
index 6af137cd722..9c26804f73d 100644
--- a/app/assets/javascripts/pages/import/history/components/import_error_details.vue
+++ b/app/assets/javascripts/pages/import/history/components/import_error_details.vue
@@ -1,7 +1,7 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import API from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { DEFAULT_ERROR } from '../utils/error_messages';
export default {
diff --git a/app/assets/javascripts/pages/import/history/components/import_history_app.vue b/app/assets/javascripts/pages/import/history/components/import_history_app.vue
index 09b1b3a9c0f..938c2be89c5 100644
--- a/app/assets/javascripts/pages/import/history/components/import_history_app.vue
+++ b/app/assets/javascripts/pages/import/history/components/import_history_app.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton, GlEmptyState, GlIcon, GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui';
import { s__, __ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { getProjects } from '~/rest_api';
import ImportStatus from '~/import_entities/components/import_status.vue';
diff --git a/app/assets/javascripts/pages/profiles/index.js b/app/assets/javascripts/pages/profiles/index.js
index 91b20a05196..b576aab9291 100644
--- a/app/assets/javascripts/pages/profiles/index.js
+++ b/app/assets/javascripts/pages/profiles/index.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import '~/profile/gl_crop';
import Profile from '~/profile/profile';
import initSearchSettings from '~/search_settings';
+import LengthValidator from '~/validators/length_validator';
import initPasswordPrompt from './password_prompt';
import { initTimezoneDropdown } from './init_timezone_dropdown';
@@ -19,6 +20,7 @@ $(document).on('input.ssh_key', '#key_key', function () {
});
new Profile(); // eslint-disable-line no-new
+new LengthValidator(); // eslint-disable-line no-new
initSearchSettings();
initPasswordPrompt();
diff --git a/app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue b/app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue
index 44728ea9cdf..7db94ea435e 100644
--- a/app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue
+++ b/app/assets/javascripts/pages/profiles/password_prompt/password_prompt_modal.vue
@@ -33,7 +33,7 @@ export default {
primaryProps() {
return {
text: I18N_PASSWORD_PROMPT_CONFIRM_BUTTON,
- attributes: [{ variant: 'danger' }, { category: 'primary' }, { disabled: !this.isValid }],
+ attributes: { variant: 'danger', category: 'primary', disabled: !this.isValid },
};
},
},
diff --git a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
index 96c4d0e0670..ea6bca644ed 100644
--- a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
+++ b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
@@ -1,4 +1,5 @@
import { mount2faRegistration } from '~/authentication/mount_2fa';
+import { initWebAuthnRegistration } from '~/authentication/webauthn/registration';
import { initRecoveryCodes, initManageTwoFactorForm } from '~/authentication/two_factor_auth';
import { parseBoolean } from '~/lib/utils/common_utils';
@@ -15,6 +16,7 @@ if (skippable) {
}
mount2faRegistration();
+initWebAuthnRegistration();
initRecoveryCodes();
diff --git a/app/assets/javascripts/pages/projects/airflow/dags/index/index.js b/app/assets/javascripts/pages/projects/airflow/dags/index/index.js
deleted file mode 100644
index 1d7cf4a5b8e..00000000000
--- a/app/assets/javascripts/pages/projects/airflow/dags/index/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import Vue from 'vue';
-import AirflowDags from '~/airflow/dags/components/dags.vue';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-
-const initShowDags = () => {
- const element = document.querySelector('#js-show-airflow-dags');
- if (!element) {
- return null;
- }
-
- const dags = JSON.parse(element.dataset.dags);
- const pagination = convertObjectPropsToCamelCase(JSON.parse(element.dataset.pagination));
-
- return new Vue({
- el: element,
- render(h) {
- return h(AirflowDags, {
- props: {
- dags,
- pagination,
- },
- });
- },
- });
-};
-
-initShowDags();
diff --git a/app/assets/javascripts/pages/projects/blame/show/index.js b/app/assets/javascripts/pages/projects/blame/show/index.js
index 1e4b9de90f2..f0fdd18c828 100644
--- a/app/assets/javascripts/pages/projects/blame/show/index.js
+++ b/app/assets/javascripts/pages/projects/blame/show/index.js
@@ -1,5 +1,10 @@
import initBlob from '~/pages/projects/init_blob';
import redirectToCorrectPage from '~/blame/blame_redirect';
+import { renderBlamePageStreams } from '~/blame/streaming';
-redirectToCorrectPage();
+if (new URLSearchParams(window.location.search).get('streaming')) {
+ renderBlamePageStreams(window.blamePageStream);
+} else {
+ redirectToCorrectPage();
+}
initBlob();
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index e45f9a10294..a0f391c912b 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -13,6 +13,9 @@ import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_sta
import BlobContentViewer from '~/repository/components/blob_content_viewer.vue';
import '~/sourcegraph/load';
import createStore from '~/code_navigation/store';
+import { generateRefDestinationPath } from '~/repository/utils/ref_switcher_utils';
+import RefSelector from '~/ref/components/ref_selector.vue';
+import { visitUrl } from '~/lib/utils/url_utility';
Vue.use(Vuex);
Vue.use(VueApollo);
@@ -26,6 +29,33 @@ const router = new VueRouter({ mode: 'history' });
const viewBlobEl = document.querySelector('#js-view-blob-app');
+const initRefSwitcher = () => {
+ const refSwitcherEl = document.getElementById('js-tree-ref-switcher');
+
+ if (!refSwitcherEl) return false;
+
+ const { projectId, projectRootPath, ref } = refSwitcherEl.dataset;
+
+ return new Vue({
+ el: refSwitcherEl,
+ render(createElement) {
+ return createElement(RefSelector, {
+ props: {
+ projectId,
+ value: ref,
+ },
+ on: {
+ input(selectedRef) {
+ visitUrl(generateRefDestinationPath(projectRootPath, ref, selectedRef));
+ },
+ },
+ });
+ },
+ });
+};
+
+initRefSwitcher();
+
if (viewBlobEl) {
const { blobPath, projectPath, targetBranch, originalBranch } = viewBlobEl.dataset;
diff --git a/app/assets/javascripts/pages/projects/boards/index.js b/app/assets/javascripts/pages/projects/boards/index.js
index bde0007ec6a..23f5b083589 100644
--- a/app/assets/javascripts/pages/projects/boards/index.js
+++ b/app/assets/javascripts/pages/projects/boards/index.js
@@ -1,7 +1,5 @@
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import initBoards from '~/boards';
-import UsersSelect from '~/users_select';
-new UsersSelect(); // eslint-disable-line no-new
new ShortcutsNavigation(); // eslint-disable-line no-new
initBoards();
diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js
index 667fd89af55..f871cd804e7 100644
--- a/app/assets/javascripts/pages/projects/commit/show/index.js
+++ b/app/assets/javascripts/pages/projects/commit/show/index.js
@@ -4,7 +4,7 @@ import Vue from 'vue';
import loadAwardsHandler from '~/awards_handler';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import Diff from '~/diff';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import initDeprecatedNotes from '~/init_deprecated_notes';
import { initDiffStatsDropdown } from '~/init_diff_stats_dropdown';
import axios from '~/lib/utils/axios_utils';
@@ -20,7 +20,9 @@ import { initReportAbuse } from '~/projects/report_abuse';
const hasPerfBar = document.querySelector('.with-performance-bar');
const performanceHeight = hasPerfBar ? 35 : 0;
-initDiffStatsDropdown(document.querySelector('.navbar-gitlab').offsetHeight + performanceHeight);
+initDiffStatsDropdown(
+ (document.querySelector('.navbar-gitlab')?.offsetHeight ?? 0) + performanceHeight,
+);
new ZenMode();
new ShortcutsNavigation();
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
index 85fe3477d7c..2cfedd78bd8 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
@@ -12,7 +12,7 @@ import {
} from '@gitlab/ui';
import { kebabCase } from 'lodash';
import { buildApiUrl } from '~/api/api_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import csrf from '~/lib/utils/csrf';
import { redirectTo } from '~/lib/utils/url_utility';
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
index 5e0c5735bc0..12ddf538775 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
@@ -1,6 +1,6 @@
<script>
import { GlButton, GlButtonGroup, GlCollapsibleListbox } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants';
import { s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
diff --git a/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue b/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue
index 10bfcdc2294..b2e96471769 100644
--- a/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue
+++ b/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue
@@ -1,5 +1,5 @@
<script>
-import { GlAlert, GlButton, GlListbox, GlSprintf } from '@gitlab/ui';
+import { GlAlert, GlButton, GlCollapsibleListbox, GlSprintf } from '@gitlab/ui';
import { GlAreaChart } from '@gitlab/ui/dist/charts';
import { get } from 'lodash';
import { formatDate } from '~/lib/utils/datetime_utility';
@@ -12,7 +12,7 @@ export default {
GlAlert,
GlAreaChart,
GlButton,
- GlListbox,
+ GlCollapsibleListbox,
GlSprintf,
},
props: {
@@ -98,7 +98,7 @@ export default {
mappedCoverages() {
return this.dailyCoverageData?.map((item, index) => ({
// A numerical index makes an item into a group header, so
- // convert these to strings to get non-header GlListbox items
+ // convert these to strings to get non-header GlCollapsibleListbox items
value: index.toString(),
text: item.group_name,
}));
@@ -182,7 +182,7 @@ export default {
{{ __('It seems that there is currently no available data for code coverage') }}
</span>
</gl-alert>
- <gl-listbox
+ <gl-collapsible-listbox
v-if="canShowData"
:items="mappedCoverages"
:selected="selectedCoverageIndex.toString()"
diff --git a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
index 406959c80ea..f8cb8b30250 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
index af75c05b300..3ae8018714a 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
@@ -3,10 +3,9 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
import { FILTERED_SEARCH } from '~/filtered_search/constants';
import { initBulkUpdateSidebar, initCsvImportExportButtons, initIssuableByEmail } from '~/issuable';
-import { ISSUABLE_INDEX } from '~/issuable/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
-initBulkUpdateSidebar(ISSUABLE_INDEX.MERGE_REQUEST);
+initBulkUpdateSidebar('merge_request_');
addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys);
IssuableFilteredSearchTokenKeys.removeTokensForKeys('iteration');
diff --git a/app/assets/javascripts/pages/projects/ml/candidates/show/index.js b/app/assets/javascripts/pages/projects/ml/candidates/show/index.js
index fee6258eddc..9dc85cded0e 100644
--- a/app/assets/javascripts/pages/projects/ml/candidates/show/index.js
+++ b/app/assets/javascripts/pages/projects/ml/candidates/show/index.js
@@ -1,4 +1,4 @@
import { initSimpleApp } from '~/helpers/init_simple_app_helper';
-import MlCandidate from '~/ml/experiment_tracking/components/ml_candidate.vue';
+import MlCandidateShow from '~/ml/experiment_tracking/routes/candidates/show';
-initSimpleApp('#js-show-ml-candidate', MlCandidate);
+initSimpleApp('#js-show-ml-candidate', MlCandidateShow);
diff --git a/app/assets/javascripts/pages/projects/ml/experiments/show/index.js b/app/assets/javascripts/pages/projects/ml/experiments/show/index.js
index 0e64d8c17db..a90cabb3c68 100644
--- a/app/assets/javascripts/pages/projects/ml/experiments/show/index.js
+++ b/app/assets/javascripts/pages/projects/ml/experiments/show/index.js
@@ -1,32 +1,24 @@
import Vue from 'vue';
-import MlExperiment from '~/ml/experiment_tracking/components/ml_experiment.vue';
+import MlExperimentsShow from '~/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
const initShowExperiment = () => {
const element = document.querySelector('#js-show-ml-experiment');
if (!element) {
- return;
+ return undefined;
}
- const container = document.createElement('div');
- element.appendChild(container);
+ const props = {
+ candidates: JSON.parse(element.dataset.candidates),
+ metricNames: JSON.parse(element.dataset.metrics),
+ paramNames: JSON.parse(element.dataset.params),
+ pageInfo: convertObjectPropsToCamelCase(JSON.parse(element.dataset.pageInfo)),
+ };
- const candidates = JSON.parse(element.dataset.candidates);
- const metricNames = JSON.parse(element.dataset.metrics);
- const paramNames = JSON.parse(element.dataset.params);
- const pageInfo = convertObjectPropsToCamelCase(JSON.parse(element.dataset.pageInfo));
-
- // eslint-disable-next-line no-new
- new Vue({
- el: container,
- provide: {
- candidates,
- metricNames,
- paramNames,
- pageInfo,
- },
+ return new Vue({
+ el: element,
render(h) {
- return h(MlExperiment);
+ return h(MlExperimentsShow, { props });
},
});
};
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index 5773737c41b..5f15a11e708 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -4,7 +4,7 @@ import $ from 'jquery';
import { setCookie } from '~/lib/utils/common_utils';
import initClonePanel from '~/clone_panel';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { serializeForm } from '~/lib/utils/forms';
import { mergeUrlParams } from '~/lib/utils/url_utility';
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 964c6ca9792..9ec56015405 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
@@ -6,6 +6,7 @@ import initDeployFreeze from '~/deploy_freeze';
import registrySettingsApp from '~/packages_and_registries/settings/project/registry_settings_bundle';
import { initInstallRunner } from '~/pages/shared/mount_runner_instructions';
import initSharedRunnersToggle from '~/projects/settings/mount_shared_runners_toggle';
+import initRefSwitcherBadges from '~/projects/settings/mount_ref_switcher_badges';
import initSettingsPanels from '~/settings_panels';
import { initTokenAccess } from '~/token_access';
import { initCiSecureFiles } from '~/ci_secure_files';
@@ -42,6 +43,7 @@ initArtifactsSettings();
initProjectRunners();
initSharedRunnersToggle();
+initRefSwitcherBadges();
initInstallRunner();
initTokenAccess();
initCiSecureFiles();
diff --git a/app/assets/javascripts/pages/projects/settings/repository/form.js b/app/assets/javascripts/pages/projects/settings/repository/form.js
index 380091a3501..f64de693188 100644
--- a/app/assets/javascripts/pages/projects/settings/repository/form.js
+++ b/app/assets/javascripts/pages/projects/settings/repository/form.js
@@ -10,8 +10,8 @@ import ProtectedTagEditList from '~/protected_tags/protected_tag_edit_list';
import initSettingsPanels from '~/settings_panels';
export default () => {
- new ProtectedTagCreate();
- new ProtectedTagEditList();
+ new ProtectedTagCreate({ hasLicense: false });
+ new ProtectedTagEditList({ hasLicense: false });
initDeployKeys();
initSettingsPanels();
new ProtectedBranchCreate({ hasLicense: false });
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
index f2bc4796324..2f29d96d85e 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
@@ -65,7 +65,7 @@ export default {
releasesHelpText: s__(
'ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release.',
),
- securityAndComplianceLabel: s__('ProjectSettings|Security & Compliance'),
+ securityAndComplianceLabel: s__('ProjectSettings|Security and Compliance'),
snippetsLabel: s__('ProjectSettings|Snippets'),
wikiLabel: s__('ProjectSettings|Wiki'),
pucWarningLabel: s__('ProjectSettings|Warn about Potentially Unwanted Characters'),
@@ -825,7 +825,7 @@ export default {
</project-setting-row>
<project-setting-row
:label="$options.i18n.securityAndComplianceLabel"
- :help-text="s__('ProjectSettings|Security & Compliance for this project')"
+ :help-text="s__('ProjectSettings|Security and compliance for this project.')"
>
<project-feature-setting
v-model="securityAndComplianceAccessLevel"
diff --git a/app/assets/javascripts/pages/registrations/new/index.js b/app/assets/javascripts/pages/registrations/new/index.js
index eaafc0235a8..b8de2757284 100644
--- a/app/assets/javascripts/pages/registrations/new/index.js
+++ b/app/assets/javascripts/pages/registrations/new/index.js
@@ -1,7 +1,7 @@
import { trackNewRegistrations } from '~/google_tag_manager';
import NoEmojiValidator from '~/emoji/no_emoji_validator';
-import LengthValidator from '~/pages/sessions/new/length_validator';
+import LengthValidator from '~/validators/length_validator';
import UsernameValidator from '~/pages/sessions/new/username_validator';
import EmailFormatValidator from '~/pages/sessions/new/email_format_validator';
import { initLanguageSwitcher } from '~/language_switcher';
@@ -10,10 +10,7 @@ import Tracking from '~/tracking';
new UsernameValidator(); // eslint-disable-line no-new
new LengthValidator(); // eslint-disable-line no-new
new NoEmojiValidator(); // eslint-disable-line no-new
-
-if (gon.features.trialEmailValidation) {
- new EmailFormatValidator(); // eslint-disable-line no-new
-}
+new EmailFormatValidator(); // eslint-disable-line no-new
trackNewRegistrations();
diff --git a/app/assets/javascripts/pages/sessions/new/index.js b/app/assets/javascripts/pages/sessions/new/index.js
index a84ed5f01ad..a8b4dca0845 100644
--- a/app/assets/javascripts/pages/sessions/new/index.js
+++ b/app/assets/javascripts/pages/sessions/new/index.js
@@ -2,7 +2,7 @@ import $ from 'jquery';
import initVueAlerts from '~/vue_alerts';
import NoEmojiValidator from '~/emoji/no_emoji_validator';
import { initLanguageSwitcher } from '~/language_switcher';
-import LengthValidator from './length_validator';
+import LengthValidator from '~/validators/length_validator';
import OAuthRememberMe from './oauth_remember_me';
import preserveUrlFragment from './preserve_url_fragment';
import SigninTabsMemoizer from './signin_tabs_memoizer';
diff --git a/app/assets/javascripts/pages/sessions/new/length_validator.js b/app/assets/javascripts/pages/sessions/new/length_validator.js
deleted file mode 100644
index b2074fb1e39..00000000000
--- a/app/assets/javascripts/pages/sessions/new/length_validator.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import InputValidator from '~/validators/input_validator';
-
-const errorMessageClass = 'gl-field-error';
-
-export default class LengthValidator extends InputValidator {
- constructor(opts = {}) {
- super();
-
- const container = opts.container || '';
- const validateLengthElements = document.querySelectorAll(`${container} .js-validate-length`);
-
- validateLengthElements.forEach((element) =>
- element.addEventListener('input', this.eventHandler.bind(this)),
- );
- }
-
- eventHandler(event) {
- this.inputDomElement = event.target;
- this.inputErrorMessage = this.inputDomElement.parentElement.querySelector(
- `.${errorMessageClass}`,
- );
-
- const { value } = this.inputDomElement;
- const {
- minLength,
- minLengthMessage,
- maxLengthMessage,
- maxLength,
- } = this.inputDomElement.dataset;
-
- this.invalidInput = false;
-
- if (value.length > parseInt(maxLength, 10)) {
- this.invalidInput = true;
- this.errorMessage = maxLengthMessage;
- }
-
- if (value.length < parseInt(minLength, 10)) {
- this.invalidInput = true;
- this.errorMessage = minLengthMessage;
- }
-
- this.setValidationStateAndMessage();
- }
-}
diff --git a/app/assets/javascripts/pages/sessions/new/username_validator.js b/app/assets/javascripts/pages/sessions/new/username_validator.js
index 1848aa70cf0..664909a9012 100644
--- a/app/assets/javascripts/pages/sessions/new/username_validator.js
+++ b/app/assets/javascripts/pages/sessions/new/username_validator.js
@@ -1,6 +1,6 @@
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import InputValidator from '~/validators/input_validator';
diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
index b19809aff53..8491d667213 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
@@ -1,7 +1,7 @@
<script>
import { GlSkeletonLoader, GlAlert } from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import { handleLocationHash } from '~/lib/utils/common_utils';
diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
index 0d2bbfbbc43..549c964cce4 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
@@ -351,6 +351,7 @@ export default {
:enable-content-editor="isMarkdownFormat"
:enable-preview="isMarkdownFormat"
:autofocus="pageInfo.persisted"
+ :drawio-enabled="true"
@contentEditor="notifyContentEditorActive"
@markdownField="notifyContentEditorInactive"
@keydown.ctrl.enter="submitFormShortcut"
diff --git a/app/assets/javascripts/pages/shared/wikis/wikis.js b/app/assets/javascripts/pages/shared/wikis/wikis.js
index 8d0105bc681..ec085eae199 100644
--- a/app/assets/javascripts/pages/shared/wikis/wikis.js
+++ b/app/assets/javascripts/pages/shared/wikis/wikis.js
@@ -16,6 +16,17 @@ export default class Wikis {
sidebarToggles[i].addEventListener('click', (e) => this.handleToggleSidebar(e));
}
+ const listToggles = document.querySelectorAll('.js-wiki-list-toggle');
+
+ listToggles.forEach((listToggle) => {
+ listToggle.querySelector('.js-wiki-list-expand-button')?.addEventListener('click', () => {
+ listToggle.classList.remove('collapsed');
+ });
+ listToggle.querySelector('.js-wiki-list-collapse-button')?.addEventListener('click', () => {
+ listToggle.classList.add('collapsed');
+ });
+ });
+
window.addEventListener('resize', () => this.renderSidebar());
this.renderSidebar();
diff --git a/app/assets/javascripts/pages/users/activity_calendar.js b/app/assets/javascripts/pages/users/activity_calendar.js
index fb761725c43..13bba06d425 100644
--- a/app/assets/javascripts/pages/users/activity_calendar.js
+++ b/app/assets/javascripts/pages/users/activity_calendar.js
@@ -1,7 +1,7 @@
import { select } from 'd3-selection';
import $ from 'jquery';
import { last } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import dateFormat from '~/lib/dateformat';
import axios from '~/lib/utils/axios_utils';
import { getDayName, getDayDifference } from '~/lib/utils/datetime_utility';
@@ -58,7 +58,7 @@ export const getLevelFromContributions = (count) => {
};
export default class ActivityCalendar {
- constructor(
+ constructor({
container,
activitiesContainer,
timestamps,
@@ -66,7 +66,8 @@ export default class ActivityCalendar {
utcOffset = 0,
firstDayOfWeek = firstDayOfWeekChoices.sunday,
monthsAgo = 12,
- ) {
+ onClickDay,
+ }) {
this.calendarActivitiesPath = calendarActivitiesPath;
this.clickDay = this.clickDay.bind(this);
this.currentSelectedDate = '';
@@ -91,6 +92,7 @@ export default class ActivityCalendar {
this.firstDayOfWeek = firstDayOfWeek;
this.activitiesContainer = activitiesContainer;
this.container = container;
+ this.onClickDay = onClickDay;
// Loop through the timestamps to create a group of objects
// The group of objects will be grouped based on the day of the week they are
@@ -152,7 +154,8 @@ export default class ActivityCalendar {
.append('svg')
.attr('width', width)
.attr('height', 169)
- .attr('class', 'contrib-calendar');
+ .attr('class', 'contrib-calendar')
+ .attr('data-testid', 'contrib-calendar');
}
dayYPos(day) {
@@ -181,6 +184,7 @@ export default class ActivityCalendar {
});
return `translate(${this.daySizeWithSpace * i + 1 + this.daySizeWithSpace}, 18)`;
})
+ .attr('data-testid', 'user-contrib-cell-group')
.selectAll('rect')
.data((stamp) => stamp)
.enter()
@@ -192,6 +196,7 @@ export default class ActivityCalendar {
.attr('data-level', (stamp) => getLevelFromContributions(stamp.count))
.attr('title', (stamp) => formatTooltipText(stamp))
.attr('class', 'user-contrib-cell has-tooltip')
+ .attr('data-testid', 'user-contrib-cell')
.attr('data-html', true)
.attr('data-container', 'body')
.on('click', this.clickDay);
@@ -281,6 +286,12 @@ export default class ActivityCalendar {
this.currentSelectedDate.getDate(),
].join('-');
+ if (this.onClickDay) {
+ this.onClickDay(date);
+
+ return;
+ }
+
$(this.activitiesContainer)
.empty()
.append(loadingIconForLegacyJS({ size: 'lg' }));
diff --git a/app/assets/javascripts/pages/users/show/index.js b/app/assets/javascripts/pages/users/show/index.js
index f1b4e00c810..c213753257d 100644
--- a/app/assets/javascripts/pages/users/show/index.js
+++ b/app/assets/javascripts/pages/users/show/index.js
@@ -1,16 +1,7 @@
-import { s__ } from '~/locale';
-import { createAlert } from '~/flash';
+import { initProfileTabs, initUserAchievements } from '~/profile';
-if (window.gon.features?.profileTabsVue) {
- import('~/profile')
- .then(({ initProfileTabs }) => {
- initProfileTabs();
- })
- .catch(() => {
- createAlert({
- message: s__(
- 'UserProfile|An error occurred loading the profile. Please refresh the page to try again.',
- ),
- });
- });
+if (gon.features?.profileTabsVue) {
+ initProfileTabs();
}
+
+initUserAchievements();
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index 90eafa85886..430022f9a9b 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -247,15 +247,15 @@ export default class UserTabs {
$calendarWrap.find('.calendar-hint').text(calendarHint);
// eslint-disable-next-line no-new
- new ActivityCalendar(
- '.tab-pane.active .js-contrib-calendar',
- '.tab-pane.active .user-calendar-activities',
- data,
+ new ActivityCalendar({
+ container: '.tab-pane.active .js-contrib-calendar',
+ activitiesContainer: '.tab-pane.active .user-calendar-activities',
+ timestamps: data,
calendarActivitiesPath,
utcOffset,
- gon.first_day_of_week,
+ firstDayOfWeek: gon.first_day_of_week,
monthsAgo,
- );
+ });
}
toggleLoading(status) {
diff --git a/app/assets/javascripts/persistent_user_callout.js b/app/assets/javascripts/persistent_user_callout.js
index 6ee33902a01..71dc8c3d020 100644
--- a/app/assets/javascripts/persistent_user_callout.js
+++ b/app/assets/javascripts/persistent_user_callout.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from './lib/utils/axios_utils';
import { parseBoolean } from './lib/utils/common_utils';
import { __ } from './locale';
diff --git a/app/assets/javascripts/persistent_user_callouts.js b/app/assets/javascripts/persistent_user_callouts.js
index e37f63d4053..3130fe42c3c 100644
--- a/app/assets/javascripts/persistent_user_callouts.js
+++ b/app/assets/javascripts/persistent_user_callouts.js
@@ -22,6 +22,8 @@ const PERSISTENT_USER_CALLOUTS = [
'.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',
];
const initCallouts = () => {
diff --git a/app/assets/javascripts/pipeline_wizard/components/editor.vue b/app/assets/javascripts/pipeline_wizard/components/editor.vue
index 0c063241173..c08d825e6af 100644
--- a/app/assets/javascripts/pipeline_wizard/components/editor.vue
+++ b/app/assets/javascripts/pipeline_wizard/components/editor.vue
@@ -5,6 +5,7 @@ import { CONTENT_UPDATE_DEBOUNCE } from '~/editor/constants';
import SourceEditor from '~/editor/source_editor';
import { YamlEditorExtension } from '~/editor/extensions/source_editor_yaml_ext';
import { SourceEditorExtension } from '~/editor/extensions/source_editor_extension_base';
+import { markRaw } from '~/lib/utils/vue3compat/mark_raw';
export default {
name: 'YamlEditor',
@@ -43,11 +44,13 @@ export default {
},
},
mounted() {
- this.editor = new SourceEditor().createInstance({
- el: this.$el,
- blobPath: this.filename,
- language: 'yaml',
- });
+ this.editor = markRaw(
+ new SourceEditor().createInstance({
+ el: this.$el,
+ blobPath: this.filename,
+ language: 'yaml',
+ }),
+ );
[, this.yamlEditorExtension] = this.editor.use([
{ definition: SourceEditorExtension },
{
diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue
index 992e3d2f552..22895a31082 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_item.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue
@@ -39,6 +39,9 @@ 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}?'),
@@ -288,6 +291,10 @@ export default {
},
pipelineActionRequestComplete() {
this.$emit('pipelineActionRequestComplete');
+
+ if (this.isBridge) {
+ this.$toast.show(this.$options.i18n.bridgeRetryText);
+ }
},
executePendingAction() {
this.shouldTriggerActionClick = true;
diff --git a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue
index 605d40eddee..16f6aa5aaa4 100644
--- a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue
+++ b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue
@@ -1,7 +1,7 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import { s__ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import GetFailedJobsQuery from '../../graphql/queries/get_failed_jobs.query.graphql';
import { prepareFailedJobs } from './utils';
diff --git a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
index 041b62e02ec..778f014bcd3 100644
--- a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
+++ b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
@@ -2,7 +2,7 @@
import { GlButton, GlLink, GlTableLite } from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { __, s__ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
import RetryFailedJobMutation from '../../graphql/mutations/retry_failed_job.mutation.graphql';
diff --git a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
index f1ad312dcaa..661de43fe3c 100644
--- a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
+++ b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
@@ -1,7 +1,7 @@
<script>
import { GlIntersectionObserver, GlLoadingIcon, GlSkeletonLoader } from '@gitlab/ui';
import produce from 'immer';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import eventHub from '~/jobs/components/table/event_hub';
import JobsTable from '~/jobs/components/table/jobs_table.vue';
diff --git a/app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue b/app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue
index 7020bfc1e65..ffb6ab71b22 100644
--- a/app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue
+++ b/app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue
@@ -1,6 +1,6 @@
<script>
import { GlTooltipDirective, GlButton, GlLoadingIcon, GlIcon } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+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';
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
index ec42b738e03..936cd6f0be5 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue
@@ -14,7 +14,7 @@
import { GlDropdown, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __, sprintf } from '~/locale';
import eventHub from '../../event_hub';
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue
index eb70b5fbb7a..9f38be668f2 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue
@@ -42,7 +42,7 @@ export default {
primaryProps() {
return {
text: s__('Pipeline|Stop pipeline'),
- attributes: [{ variant: 'danger' }],
+ attributes: { variant: 'danger' },
};
},
cancelProps() {
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue
index 4111823e0bb..640129b9c4c 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue
@@ -1,7 +1,7 @@
<script>
import { GlEmptyState, GlIcon, GlLoadingIcon, GlCollapsibleListbox } from '@gitlab/ui';
import { isEqual } from 'lodash';
-import { createAlert, VARIANT_INFO, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_INFO, VARIANT_WARNING } from '~/alert';
import { getParameterByName } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
import Tracking from '~/tracking';
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
index f34b3f56c5b..50d34070e61 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions.vue
@@ -1,6 +1,6 @@
<script>
import { GlDropdown, GlDropdownItem, GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+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';
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
index b57d0ac1fd7..81f46d5f2f9 100644
--- 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
@@ -2,7 +2,7 @@
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
import { debounce } from 'lodash';
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { FETCH_BRANCH_ERROR_MESSAGE, FILTER_PIPELINES_SEARCH_DELAY } from '../../../constants';
export default {
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
index 5846a1f6ed9..b32f5de2d7e 100644
--- 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
@@ -2,7 +2,7 @@
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
import { debounce } from 'lodash';
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { FETCH_TAG_ERROR_MESSAGE, FILTER_PIPELINES_SEARCH_DELAY } from '../../../constants';
export default {
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
index 73f7d3f52c3..a89354c671a 100644
--- 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
@@ -8,7 +8,7 @@ import {
} from '@gitlab/ui';
import { debounce } from 'lodash';
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import {
ANY_TRIGGER_AUTHOR,
FETCH_AUTHOR_ERROR_MESSAGE,
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
index 2d1f1945e5a..10db3e1c56b 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue
+++ b/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue
@@ -66,7 +66,7 @@ export default {
},
modalCloseButton: {
text: __('Close'),
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
};
</script>
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
index 1cd28e027f3..2974bd2dd37 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
+++ b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
@@ -100,7 +100,7 @@ export default {
{{ __('Duration') }}
</div>
<div role="rowheader" class="table-section section-10">
- {{ __('Details'), }}
+ {{ __('Details') }}
</div>
</div>
@@ -162,7 +162,7 @@ export default {
</div>
<div class="table-section section-10 section-wrap">
- <div role="rowheader" class="table-mobile-header">{{ __('Details'), }}</div>
+ <div role="rowheader" class="table-mobile-header">{{ __('Details') }}</div>
<div class="table-mobile-content">
<gl-button v-gl-modal-directive="`test-case-details-${index}`">{{
__('View details')
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue
index 7ab48da1a9d..2b7b2d78424 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue
+++ b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue
@@ -50,13 +50,13 @@ export default {
{{ __('Failed') }}
</div>
<div role="rowheader" class="table-section section-10 gl-text-center">
- {{ __('Errors'), }}
+ {{ __('Errors') }}
</div>
<div role="rowheader" class="table-section section-10 gl-text-center">
- {{ __('Skipped'), }}
+ {{ __('Skipped') }}
</div>
<div role="rowheader" class="table-section section-10 gl-text-center">
- {{ __('Passed'), }}
+ {{ __('Passed') }}
</div>
<div role="rowheader" class="table-section section-10 gl-pr-5 gl-text-right">
{{ __('Total') }}
diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js
index 820501089ed..ca146ac1e87 100644
--- a/app/assets/javascripts/pipelines/constants.js
+++ b/app/assets/javascripts/pipelines/constants.js
@@ -1,7 +1,6 @@
import { s__, __ } from '~/locale';
export const CANCEL_REQUEST = 'CANCEL_REQUEST';
-export const LAYOUT_CHANGE_DELAY = 300;
export const FILTER_PIPELINES_SEARCH_DELAY = 200;
export const ANY_TRIGGER_AUTHOR = 'Any';
export const SUPPORTED_FILTER_PARAMETERS = ['username', 'ref', 'status', 'source'];
@@ -35,8 +34,6 @@ export const RAW_TEXT_WARNING = s__(
export const DEFAULT = 'default';
export const DELETE_FAILURE = 'delete_pipeline_failure';
export const DRAW_FAILURE = 'draw_failure';
-export const EMPTY_PIPELINE_DATA = 'empty_data';
-export const INVALID_CI_CONFIG = 'invalid_ci_config';
export const LOAD_FAILURE = 'load_failure';
export const PARSE_FAILURE = 'parse_failure';
export const POST_FAILURE = 'post_failure';
diff --git a/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js b/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js
index e6770b71113..481953608e9 100644
--- a/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js
+++ b/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js
@@ -1,5 +1,5 @@
import Visibility from 'visibilityjs';
-import { createAlert } from '~/flash';
+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';
diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
index ba51347ad69..61847affa1f 100644
--- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js
+++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
@@ -1,5 +1,5 @@
import VueRouter from 'vue-router';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import { pipelineTabName } from './constants';
import { createPipelineHeaderApp } from './pipeline_details_header';
diff --git a/app/assets/javascripts/pipelines/pipeline_tabs.js b/app/assets/javascripts/pipelines/pipeline_tabs.js
index 6360ccc41bc..d94602c23b4 100644
--- a/app/assets/javascripts/pipelines/pipeline_tabs.js
+++ b/app/assets/javascripts/pipelines/pipeline_tabs.js
@@ -2,11 +2,13 @@ import Vue from 'vue';
import VueRouter from 'vue-router';
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);
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/actions.js b/app/assets/javascripts/pipelines/stores/test_reports/actions.js
index c77b4813e33..1b51bb804d0 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/actions.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
import * as types from './mutation_types';
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/mutations.js b/app/assets/javascripts/pipelines/stores/test_reports/mutations.js
index bff30acfe36..466574157f5 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/mutations.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/mutations.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import * as types from './mutation_types';
diff --git a/app/assets/javascripts/profile/account/components/delete_account_modal.vue b/app/assets/javascripts/profile/account/components/delete_account_modal.vue
index 3cb2dce87d3..c64fbc91d12 100644
--- a/app/assets/javascripts/profile/account/components/delete_account_modal.vue
+++ b/app/assets/javascripts/profile/account/components/delete_account_modal.vue
@@ -38,11 +38,12 @@ export default {
primaryProps() {
return {
text: __('Delete account'),
- attributes: [
- { variant: 'danger', 'data-qa-selector': 'confirm_delete_account_button' },
- { category: 'primary' },
- { disabled: !this.canSubmit },
- ],
+ attributes: {
+ variant: 'danger',
+ 'data-qa-selector': 'confirm_delete_account_button',
+ category: 'primary',
+ disabled: !this.canSubmit,
+ },
};
},
cancelProps() {
diff --git a/app/assets/javascripts/profile/account/components/update_username.vue b/app/assets/javascripts/profile/account/components/update_username.vue
index 51e62984715..d96b5748abc 100644
--- a/app/assets/javascripts/profile/account/components/update_username.vue
+++ b/app/assets/javascripts/profile/account/components/update_username.vue
@@ -2,7 +2,7 @@
import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
import { escape } from 'lodash';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __, s__, sprintf } from '~/locale';
@@ -60,11 +60,7 @@ Please update your Git repository remotes as soon as possible.`),
primaryProps() {
return {
text: __('Update username'),
- attributes: [
- { variant: 'confirm' },
- { category: 'primary' },
- { disabled: this.isRequestPending },
- ],
+ attributes: { variant: 'confirm', category: 'primary', disabled: this.isRequestPending },
};
},
cancelProps() {
@@ -117,6 +113,7 @@ Please update your Git repository remotes as soon as possible.`),
<input
:id="$options.inputId"
v-model="newUsername"
+ data-testid="new-username-input"
:disabled="isRequestPending"
class="form-control"
required="required"
diff --git a/app/assets/javascripts/profile/components/activity_calendar.vue b/app/assets/javascripts/profile/components/activity_calendar.vue
new file mode 100644
index 00000000000..d359b478d35
--- /dev/null
+++ b/app/assets/javascripts/profile/components/activity_calendar.vue
@@ -0,0 +1,100 @@
+<script>
+import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
+import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import { debounce } from 'lodash';
+
+import { __ } from '~/locale';
+import AjaxCache from '~/lib/utils/ajax_cache';
+import ActivityCalendar from '~/pages/users/activity_calendar';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+import { getVisibleCalendarPeriod } from '../utils';
+
+export default {
+ i18n: {
+ errorAlertTitle: __('There was an error loading users activity calendar.'),
+ retry: __('Retry'),
+ calendarHint: __('Issues, merge requests, pushes, and comments.'),
+ },
+ components: { GlLoadingIcon, GlAlert },
+ inject: ['userCalendarPath', 'utcOffset'],
+ data() {
+ return {
+ isLoading: true,
+ showCalendar: true,
+ hasError: false,
+ };
+ },
+ mounted() {
+ this.renderActivityCalendar();
+ window.addEventListener('resize', this.handleResize);
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.handleResize);
+ },
+ methods: {
+ async renderActivityCalendar() {
+ if (bp.getBreakpointSize() === 'xs') {
+ this.showCalendar = false;
+
+ return;
+ }
+
+ this.showCalendar = true;
+ this.isLoading = true;
+ this.hasError = false;
+
+ try {
+ const data = await AjaxCache.retrieve(this.userCalendarPath);
+
+ this.isLoading = false;
+
+ // Wait for `calendarContainer` to render
+ await this.$nextTick();
+ const monthsAgo = getVisibleCalendarPeriod(this.$refs.calendarContainer);
+
+ // eslint-disable-next-line no-new
+ new ActivityCalendar({
+ container: this.$refs.calendarSvgContainer,
+ timestamps: data,
+ utcOffset: this.utcOffset,
+ firstDayOfWeek: gon.first_day_of_week,
+ monthsAgo,
+ onClickDay: this.handleClickDay,
+ });
+ } catch {
+ this.isLoading = false;
+ this.hasError = true;
+ }
+ },
+ handleResize: debounce(function debouncedHandleResize() {
+ this.renderActivityCalendar();
+ }, DEFAULT_DEBOUNCE_AND_THROTTLE_MS),
+ handleClickDay() {
+ // Render activities for specific day.
+ // Blocked by https://gitlab.com/gitlab-org/gitlab/-/issues/378695
+ },
+ },
+};
+</script>
+
+<template>
+ <div v-if="showCalendar" ref="calendarContainer">
+ <gl-loading-icon v-if="isLoading" size="md" />
+ <gl-alert
+ v-else-if="hasError"
+ :title="$options.i18n.errorAlertTitle"
+ :dismissible="false"
+ variant="danger"
+ :primary-button-text="$options.i18n.retry"
+ @primaryAction="renderActivityCalendar"
+ />
+ <div v-else class="gl-text-center">
+ <div class="gl-display-inline-block gl-relative">
+ <div ref="calendarSvgContainer"></div>
+ <p class="gl-absolute gl-right-0 gl-bottom-0 gl-mb-0 gl-font-sm">
+ {{ $options.i18n.calendarHint }}
+ </p>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/profile/components/followers_tab.vue b/app/assets/javascripts/profile/components/followers_tab.vue
index 47651c33eb8..5b69f835294 100644
--- a/app/assets/javascripts/profile/components/followers_tab.vue
+++ b/app/assets/javascripts/profile/components/followers_tab.vue
@@ -1,17 +1,24 @@
<script>
-import { GlTab } from '@gitlab/ui';
+import { GlBadge, GlTab } from '@gitlab/ui';
import { s__ } from '~/locale';
export default {
i18n: {
title: s__('UserProfile|Followers'),
},
- components: { GlTab },
+ components: {
+ GlBadge,
+ GlTab,
+ },
+ inject: ['followers'],
};
</script>
<template>
- <gl-tab :title="$options.i18n.title">
- <!-- placeholder -->
+ <gl-tab>
+ <template #title>
+ <span>{{ $options.i18n.title }}</span>
+ <gl-badge size="sm" class="gl-ml-2">{{ followers }}</gl-badge>
+ </template>
</gl-tab>
</template>
diff --git a/app/assets/javascripts/profile/components/following_tab.vue b/app/assets/javascripts/profile/components/following_tab.vue
index 6d9631c5e89..d39d15a08f3 100644
--- a/app/assets/javascripts/profile/components/following_tab.vue
+++ b/app/assets/javascripts/profile/components/following_tab.vue
@@ -1,17 +1,24 @@
<script>
-import { GlTab } from '@gitlab/ui';
+import { GlBadge, GlTab } from '@gitlab/ui';
import { s__ } from '~/locale';
export default {
i18n: {
title: s__('UserProfile|Following'),
},
- components: { GlTab },
+ components: {
+ GlBadge,
+ GlTab,
+ },
+ inject: ['followees'],
};
</script>
<template>
- <gl-tab :title="$options.i18n.title">
- <!-- placeholder -->
+ <gl-tab>
+ <template #title>
+ <span>{{ $options.i18n.title }}</span>
+ <gl-badge size="sm" class="gl-ml-2">{{ followees }}</gl-badge>
+ </template>
</gl-tab>
</template>
diff --git a/app/assets/javascripts/profile/components/graphql/get_user_achievements.query.graphql b/app/assets/javascripts/profile/components/graphql/get_user_achievements.query.graphql
new file mode 100644
index 00000000000..e60f383ad1c
--- /dev/null
+++ b/app/assets/javascripts/profile/components/graphql/get_user_achievements.query.graphql
@@ -0,0 +1,21 @@
+query getUserAchievements($id: UserID!) {
+ user(id: $id) {
+ id
+ userAchievements {
+ nodes {
+ id
+ createdAt
+ achievement {
+ id
+ name
+ description
+ avatarUrl
+ namespace {
+ id
+ fullPath
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/profile/components/overview_tab.vue b/app/assets/javascripts/profile/components/overview_tab.vue
index e884c2d7083..76fb13919df 100644
--- a/app/assets/javascripts/profile/components/overview_tab.vue
+++ b/app/assets/javascripts/profile/components/overview_tab.vue
@@ -1,17 +1,18 @@
<script>
import { GlTab } from '@gitlab/ui';
import { s__ } from '~/locale';
+import ActivityCalendar from './activity_calendar.vue';
export default {
i18n: {
title: s__('UserProfile|Overview'),
},
- components: { GlTab },
+ components: { GlTab, ActivityCalendar },
};
</script>
<template>
<gl-tab :title="$options.i18n.title">
- <!-- placeholder -->
+ <activity-calendar />
</gl-tab>
</template>
diff --git a/app/assets/javascripts/profile/components/profile_tabs.vue b/app/assets/javascripts/profile/components/profile_tabs.vue
index 2425d56c52a..b39bfabb832 100644
--- a/app/assets/javascripts/profile/components/profile_tabs.vue
+++ b/app/assets/javascripts/profile/components/profile_tabs.vue
@@ -66,7 +66,12 @@ export default {
</script>
<template>
- <gl-tabs>
- <component :is="component" v-for="{ key, component } in $options.tabs" :key="key" />
+ <gl-tabs nav-class="gl-bg-gray-10" align="center">
+ <component
+ :is="component"
+ v-for="{ key, component } in $options.tabs"
+ :key="key"
+ class="container-fluid container-limited"
+ />
</gl-tabs>
</template>
diff --git a/app/assets/javascripts/profile/components/user_achievements.vue b/app/assets/javascripts/profile/components/user_achievements.vue
new file mode 100644
index 00000000000..790b0e9f303
--- /dev/null
+++ b/app/assets/javascripts/profile/components/user_achievements.vue
@@ -0,0 +1,100 @@
+<script>
+import { GlPopover, GlSprintf } from '@gitlab/ui';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { s__ } from '~/locale';
+import { TYPENAME_USER } from '~/graphql_shared/constants';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+import getUserAchievements from './graphql/get_user_achievements.query.graphql';
+
+export default {
+ name: 'UserAchievements',
+ components: { GlPopover, GlSprintf },
+ mixins: [timeagoMixin],
+ inject: ['rootUrl', 'userId'],
+ apollo: {
+ userAchievements: {
+ query: getUserAchievements,
+ variables() {
+ return {
+ id: convertToGraphQLId(TYPENAME_USER, this.userId),
+ };
+ },
+ update(data) {
+ return this.processNodes(data.user.userAchievements.nodes);
+ },
+ error() {
+ return [];
+ },
+ },
+ },
+ methods: {
+ processNodes(nodes) {
+ return nodes.slice(0, 3).map(
+ ({
+ achievement,
+ createdAt,
+ achievement: {
+ namespace: { fullPath },
+ },
+ }) => {
+ return {
+ id: `user-achievement-${getIdFromGraphQLId(achievement.id)}`,
+ name: achievement.name,
+ timeAgo: this.timeFormatted(createdAt),
+ avatarUrl: achievement.avatarUrl || gon.gitlab_logo,
+ description: achievement.description,
+ namespace: {
+ fullPath,
+ webUrl: this.rootUrl + fullPath,
+ },
+ };
+ },
+ );
+ },
+ },
+ i18n: {
+ awardedBy: s__('Achievements|Awarded %{timeAgo} by %{namespace}'),
+ },
+};
+</script>
+
+<template>
+ <div class="gl-mb-3">
+ <div
+ v-for="userAchievement in userAchievements"
+ :key="userAchievement.id"
+ class="gl-display-inline-block"
+ data-testid="user-achievement"
+ >
+ <img
+ :id="userAchievement.id"
+ :src="userAchievement.avatarUrl"
+ :alt="''"
+ tabindex="0"
+ class="gl-avatar gl-avatar-s32 gl-mx-2"
+ />
+ <gl-popover triggers="hover focus" placement="top" :target="userAchievement.id">
+ <div class="gl-font-weight-bold">{{ userAchievement.name }}</div>
+ <div>
+ <gl-sprintf :message="$options.i18n.awardedBy">
+ <template #timeAgo>
+ <span>{{ userAchievement.timeAgo }}</span>
+ </template>
+ <template #namespace>
+ <a :href="userAchievement.namespace.webUrl">{{
+ userAchievement.namespace.fullPath
+ }}</a>
+ </template>
+ </gl-sprintf>
+ </div>
+ <div
+ v-if="userAchievement.description"
+ class="gl-mt-5"
+ data-testid="achievement-description"
+ >
+ {{ userAchievement.description }}
+ </div>
+ </gl-popover>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/profile/constants.js b/app/assets/javascripts/profile/constants.js
new file mode 100644
index 00000000000..e19994c6784
--- /dev/null
+++ b/app/assets/javascripts/profile/constants.js
@@ -0,0 +1,7 @@
+export const CALENDAR_PERIOD_6_MONTHS = 6;
+export const CALENDAR_PERIOD_12_MONTHS = 12;
+/* computation based on
+ * width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
+ * (see activity_calendar.js)
+ */
+export const OVERVIEW_CALENDAR_BREAKPOINT = 918;
diff --git a/app/assets/javascripts/profile/index.js b/app/assets/javascripts/profile/index.js
index 5378ed3d743..fbe0e3534d8 100644
--- a/app/assets/javascripts/profile/index.js
+++ b/app/assets/javascripts/profile/index.js
@@ -1,16 +1,52 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+
+import createDefaultClient from '~/lib/graphql';
import ProfileTabs from './components/profile_tabs.vue';
+import UserAchievements from './components/user_achievements.vue';
+
+Vue.use(VueApollo);
export const initProfileTabs = () => {
const el = document.getElementById('js-profile-tabs');
if (!el) return false;
+ const { followees, followers, userCalendarPath, utcOffset } = el.dataset;
+
return new Vue({
el,
+ provide: {
+ followees: parseInt(followers, 10),
+ followers: parseInt(followees, 10),
+ userCalendarPath,
+ utcOffset,
+ },
render(createElement) {
return createElement(ProfileTabs);
},
});
};
+
+export const initUserAchievements = () => {
+ const el = document.getElementById('js-user-achievements');
+
+ if (!el) return false;
+
+ const { rootUrl, userId } = el.dataset;
+
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+ });
+
+ return new Vue({
+ el,
+ apolloProvider,
+ name: 'UserAchievements',
+ provide: { rootUrl, userId: parseInt(userId, 10) },
+ render(createElement) {
+ return createElement(UserAchievements);
+ },
+ });
+};
diff --git a/app/assets/javascripts/profile/preferences/components/profile_preferences.vue b/app/assets/javascripts/profile/preferences/components/profile_preferences.vue
index a33a20b49f6..d0d947ddd6e 100644
--- a/app/assets/javascripts/profile/preferences/components/profile_preferences.vue
+++ b/app/assets/javascripts/profile/preferences/components/profile_preferences.vue
@@ -1,6 +1,6 @@
<script>
import { GlButton } from '@gitlab/ui';
-import { createAlert, VARIANT_DANGER, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_DANGER, VARIANT_INFO } from '~/alert';
import { INTEGRATION_VIEW_CONFIGS, i18n } from '../constants';
import IntegrationView from './integration_view.vue';
diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js
index c031c5e5e8e..e21f8557d68 100644
--- a/app/assets/javascripts/profile/profile.js
+++ b/app/assets/javascripts/profile/profile.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import Vue from 'vue';
-import { VARIANT_DANGER, VARIANT_INFO, createAlert } from '~/flash';
+import { VARIANT_DANGER, VARIANT_INFO, createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { parseBoolean } from '~/lib/utils/common_utils';
import { parseRailsFormFields } from '~/lib/utils/forms';
diff --git a/app/assets/javascripts/profile/utils.js b/app/assets/javascripts/profile/utils.js
new file mode 100644
index 00000000000..5b757120544
--- /dev/null
+++ b/app/assets/javascripts/profile/utils.js
@@ -0,0 +1,13 @@
+import {
+ OVERVIEW_CALENDAR_BREAKPOINT,
+ CALENDAR_PERIOD_6_MONTHS,
+ CALENDAR_PERIOD_12_MONTHS,
+} from './constants';
+
+export const getVisibleCalendarPeriod = (calendarContainer) => {
+ const { width } = calendarContainer.getBoundingClientRect();
+
+ return width < OVERVIEW_CALENDAR_BREAKPOINT
+ ? CALENDAR_PERIOD_6_MONTHS
+ : CALENDAR_PERIOD_12_MONTHS;
+};
diff --git a/app/assets/javascripts/projects/commit/components/branches_dropdown.vue b/app/assets/javascripts/projects/commit/components/branches_dropdown.vue
index 0ed154c47dd..77e809e88ce 100644
--- a/app/assets/javascripts/projects/commit/components/branches_dropdown.vue
+++ b/app/assets/javascripts/projects/commit/components/branches_dropdown.vue
@@ -1,7 +1,7 @@
<script>
import { GlCollapsibleListbox } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
-import { debounce } from 'lodash';
+import { debounce, uniqBy } from 'lodash';
import {
I18N_NO_RESULTS_MESSAGE,
I18N_BRANCH_HEADER,
@@ -19,11 +19,6 @@ export default {
required: false,
default: '',
},
- blanked: {
- type: Boolean,
- required: false,
- default: false,
- },
},
i18n: {
noResultsMessage: I18N_NO_RESULTS_MESSAGE,
@@ -32,26 +27,26 @@ export default {
},
data() {
return {
- searchTerm: this.blanked ? '' : this.value,
+ searchTerm: '',
};
},
computed: {
...mapGetters(['joinedBranches']),
- ...mapState(['isFetching']),
+ ...mapState(['isFetching', 'branch']),
listboxItems() {
- return this.joinedBranches.map((value) => ({ value, text: value }));
- },
- },
- watch: {
- // Parent component can set the branch value (e.g. when the user selects a different project)
- // and we need to keep the search term in sync with the selected value
- value(val) {
- this.searchTerm = val;
- this.fetchBranches(this.searchTerm);
+ const selectedItem = { value: this.branch, text: this.branch };
+ const transformedList = this.joinedBranches.map((value) => ({ value, text: value }));
+
+ if (this.searchTerm) {
+ return transformedList;
+ }
+
+ // Add selected item to top of list if not searching
+ return uniqBy([selectedItem].concat(transformedList), 'value');
},
},
mounted() {
- this.fetchBranches(this.searchTerm);
+ this.fetchBranches();
},
methods: {
...mapActions(['fetchBranches']),
@@ -70,8 +65,10 @@ export default {
</script>
<template>
<gl-collapsible-listbox
+ class="gl-max-w-full"
:header-text="$options.i18n.branchHeaderTitle"
:toggle-text="value"
+ toggle-class="gl-w-full"
:items="listboxItems"
searchable
:search-placeholder="$options.i18n.branchSearchPlaceholder"
diff --git a/app/assets/javascripts/projects/commit/components/form_modal.vue b/app/assets/javascripts/projects/commit/components/form_modal.vue
index f78afef1c17..28bbf67c090 100644
--- a/app/assets/javascripts/projects/commit/components/form_modal.vue
+++ b/app/assets/javascripts/projects/commit/components/form_modal.vue
@@ -41,11 +41,6 @@ export default {
required: false,
default: false,
},
- isRevert: {
- type: Boolean,
- required: false,
- default: false,
- },
primaryActionEventName: {
type: String,
required: false,
@@ -57,16 +52,16 @@ export default {
checked: true,
actionPrimary: {
text: this.i18n.actionPrimaryText,
- attributes: [
- { variant: 'confirm' },
- { category: 'primary' },
- { 'data-testid': 'submit-commit' },
- { 'data-qa-selector': 'submit_commit_button' },
- ],
+ attributes: {
+ variant: 'confirm',
+ category: 'primary',
+ 'data-testid': 'submit-commit',
+ 'data-qa-selector': 'submit_commit_button',
+ },
},
actionCancel: {
text: this.i18n.actionCancelText,
- attributes: [{ 'data-testid': 'cancel-commit' }],
+ attributes: { 'data-testid': 'cancel-commit' },
},
};
},
@@ -85,7 +80,6 @@ export default {
]),
},
mounted() {
- this.setSelectedProject(this.targetProjectId);
eventHub.$on(this.openModal, this.show);
},
methods: {
@@ -141,7 +135,7 @@ export default {
:value="targetProjectId"
/>
- <projects-dropdown :value="targetProjectName" @selectProject="setSelectedProject" />
+ <projects-dropdown :value="targetProjectName" @input="setSelectedProject" />
</gl-form-group>
<gl-form-group
@@ -151,7 +145,7 @@ export default {
>
<input id="start_branch" type="hidden" name="start_branch" :value="branch" />
- <branches-dropdown :value="branch" :blanked="isRevert" @input="setBranch" />
+ <branches-dropdown :value="branch" @input="setBranch" />
</gl-form-group>
<gl-form-checkbox
diff --git a/app/assets/javascripts/projects/commit/components/projects_dropdown.vue b/app/assets/javascripts/projects/commit/components/projects_dropdown.vue
index d43f5b99e2c..fe54b62e2c8 100644
--- a/app/assets/javascripts/projects/commit/components/projects_dropdown.vue
+++ b/app/assets/javascripts/projects/commit/components/projects_dropdown.vue
@@ -1,6 +1,7 @@
<script>
import { GlCollapsibleListbox } from '@gitlab/ui';
import { mapGetters, mapState } from 'vuex';
+import { debounce, uniqBy } from 'lodash';
import {
I18N_NO_RESULTS_MESSAGE,
I18N_PROJECT_HEADER,
@@ -26,7 +27,7 @@ export default {
},
data() {
return {
- filterTerm: this.value,
+ filterTerm: '',
};
},
computed: {
@@ -39,7 +40,18 @@ export default {
);
},
listboxItems() {
- return this.filteredResults.map(({ id, name }) => ({ value: id, text: name }));
+ const selectedItem = { value: this.selectedProject.id, text: this.selectedProject.name };
+ const transformedList = this.filteredResults.map(({ id, name }) => ({
+ value: id,
+ text: name,
+ }));
+
+ if (this.filterTerm) {
+ return transformedList;
+ }
+
+ // Add selected item to top of list if not searching
+ return uniqBy([selectedItem].concat(transformedList), 'value');
},
selectedProject() {
return this.sortedProjects.find((project) => project.id === this.targetProjectId) || {};
@@ -47,28 +59,26 @@ export default {
},
methods: {
selectProject(value) {
- this.$emit('selectProject', value);
-
- // when we select a project, we want the dropdown to filter to the selected project
- const project = this.listboxItems.find((x) => x.value === value);
- this.filterTerm = project?.text || '';
- },
- filterTermChanged(value) {
- this.filterTerm = value;
+ this.$emit('input', value);
},
+ debouncedSearch: debounce(function debouncedSearch(value) {
+ this.filterTerm = value.trim();
+ }, 250),
},
};
</script>
<template>
<gl-collapsible-listbox
+ class="gl-max-w-full"
:header-text="$options.i18n.projectHeaderTitle"
:items="listboxItems"
searchable
:search-placeholder="$options.i18n.projectSearchPlaceholder"
:selected="selectedProject.id"
:toggle-text="selectedProject.name"
+ toggle-class="gl-w-full"
:no-results-text="$options.i18n.noResultsMessage"
- @search="filterTermChanged"
+ @search="debouncedSearch"
@select="selectProject"
/>
</template>
diff --git a/app/assets/javascripts/projects/commit/init_revert_commit_modal.js b/app/assets/javascripts/projects/commit/init_revert_commit_modal.js
index 41be71932e5..849b2f4858c 100644
--- a/app/assets/javascripts/projects/commit/init_revert_commit_modal.js
+++ b/app/assets/javascripts/projects/commit/init_revert_commit_modal.js
@@ -49,7 +49,6 @@ export default function initInviteMembersModal(primaryActionEventName) {
i18n: { ...I18N_REVERT_MODAL, ...I18N_MODAL },
openModal: OPEN_REVERT_MODAL,
modalId: REVERT_MODAL_ID,
- isRevert: true,
primaryActionEventName,
},
}),
diff --git a/app/assets/javascripts/projects/commit/store/actions.js b/app/assets/javascripts/projects/commit/store/actions.js
index cfff93eac5a..501006a8be5 100644
--- a/app/assets/javascripts/projects/commit/store/actions.js
+++ b/app/assets/javascripts/projects/commit/store/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { PROJECT_BRANCHES_ERROR } from '../constants';
import * as types from './mutation_types';
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 dafc4bc5abf..54d13ecc9c8 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
@@ -1,6 +1,6 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import {
getQueryHeaders,
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 62b1209131c..71f53613a3b 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
@@ -1,7 +1,7 @@
<script>
import { GlLoadingIcon, GlLink } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import {
getQueryHeaders,
toggleQueryPollingByVisibility,
diff --git a/app/assets/javascripts/projects/commits/store/actions.js b/app/assets/javascripts/projects/commits/store/actions.js
index 9365066418b..5175f7f9151 100644
--- a/app/assets/javascripts/projects/commits/store/actions.js
+++ b/app/assets/javascripts/projects/commits/store/actions.js
@@ -1,5 +1,5 @@
import * as Sentry from '@sentry/browser';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/projects/compare/components/revision_dropdown.vue b/app/assets/javascripts/projects/compare/components/revision_dropdown.vue
index 10531e950f9..8af1667e26b 100644
--- a/app/assets/javascripts/projects/compare/components/revision_dropdown.vue
+++ b/app/assets/javascripts/projects/compare/components/revision_dropdown.vue
@@ -1,7 +1,7 @@
<script>
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlDropdownSectionHeader } from '@gitlab/ui';
import { debounce } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
@@ -149,6 +149,7 @@ export default {
:key="branch"
is-check-item
:is-checked="selectedRevision === branch"
+ data-testid="branches-dropdown-item"
@click="onClick(branch)"
>
{{ branch }}
@@ -161,6 +162,7 @@ export default {
:key="tag"
is-check-item
:is-checked="selectedRevision === tag"
+ data-testid="tags-dropdown-item"
@click="onClick(tag)"
>
{{ tag }}
diff --git a/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue b/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue
index 1e1677e947c..034bae3066d 100644
--- a/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue
+++ b/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue
@@ -1,6 +1,6 @@
<script>
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlDropdownSectionHeader } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
@@ -132,6 +132,7 @@ export default {
:key="`branch${index}`"
is-check-item
:is-checked="selectedRevision === branch"
+ data-testid="branches-dropdown-item"
@click="onClick(branch)"
>
{{ branch }}
@@ -144,6 +145,7 @@ export default {
:key="`tag${index}`"
is-check-item
:is-checked="selectedRevision === tag"
+ data-testid="tags-dropdown-item"
@click="onClick(tag)"
>
{{ tag }}
diff --git a/app/assets/javascripts/projects/components/shared/delete_button.vue b/app/assets/javascripts/projects/components/shared/delete_button.vue
index 64a16b462f5..06c0230c8e0 100644
--- a/app/assets/javascripts/projects/components/shared/delete_button.vue
+++ b/app/assets/javascripts/projects/components/shared/delete_button.vue
@@ -62,11 +62,11 @@ export default {
return {
primary: {
text: __('Yes, delete project'),
- attributes: [
- { variant: 'danger' },
- { disabled: this.confirmDisabled },
- { 'data-qa-selector': 'confirm_delete_button' },
- ],
+ attributes: {
+ variant: 'danger',
+ disabled: this.confirmDisabled,
+ 'data-qa-selector': 'confirm_delete_button',
+ },
},
cancel: {
text: __('Cancel, keep project'),
diff --git a/app/assets/javascripts/projects/new/components/app.vue b/app/assets/javascripts/projects/new/components/app.vue
index 3100029eb31..1599661505f 100644
--- a/app/assets/javascripts/projects/new/components/app.vue
+++ b/app/assets/javascripts/projects/new/components/app.vue
@@ -59,6 +59,20 @@ export default {
SafeHtml,
},
props: {
+ projectsUrl: {
+ type: String,
+ required: true,
+ },
+ parentGroupUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ parentGroupName: {
+ type: String,
+ required: false,
+ default: '',
+ },
hasErrors: {
type: Boolean,
required: false,
@@ -77,6 +91,14 @@ export default {
},
computed: {
+ initialBreadcrumbs() {
+ return [
+ this.parentGroupUrl
+ ? { text: this.parentGroupName, href: this.parentGroupUrl }
+ : { text: s__('ProjectsNew|Projects'), href: this.projectsUrl },
+ { text: s__('ProjectsNew|New project'), href: '#' },
+ ];
+ },
availablePanels() {
return this.isCiCdAvailable ? PANELS : PANELS.filter((p) => p.name !== CI_CD_PANEL);
},
@@ -95,7 +117,7 @@ export default {
<template>
<new-namespace-page
- :initial-breadcrumb="__('New project')"
+ :initial-breadcrumbs="initialBreadcrumbs"
:panels="availablePanels"
:jump-to-last-persisted-panel="hasErrors"
:title="s__('ProjectsNew|Create new project')"
diff --git a/app/assets/javascripts/projects/new/index.js b/app/assets/javascripts/projects/new/index.js
index 910244c657b..7330874eefe 100644
--- a/app/assets/javascripts/projects/new/index.js
+++ b/app/assets/javascripts/projects/new/index.js
@@ -15,12 +15,18 @@ export function initNewProjectCreation() {
newProjectGuidelines,
hasErrors,
isCiCdAvailable,
+ parentGroupUrl,
+ parentGroupName,
+ projectsUrl,
} = el.dataset;
const props = {
hasErrors: parseBoolean(hasErrors),
isCiCdAvailable: parseBoolean(isCiCdAvailable),
newProjectGuidelines,
+ parentGroupUrl,
+ parentGroupName,
+ projectsUrl,
};
const provide = {
diff --git a/app/assets/javascripts/projects/project_find_file.js b/app/assets/javascripts/projects/project_find_file.js
index 71329c4f461..a8b884a68a0 100644
--- a/app/assets/javascripts/projects/project_find_file.js
+++ b/app/assets/javascripts/projects/project_find_file.js
@@ -2,7 +2,7 @@
import fuzzaldrinPlus from 'fuzzaldrin-plus';
import $ from 'jquery';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { sanitize } from '~/lib/dompurify';
import axios from '~/lib/utils/axios_utils';
import { spriteIcon } from '~/lib/utils/common_utils';
diff --git a/app/assets/javascripts/projects/settings/access_dropdown.js b/app/assets/javascripts/projects/settings/access_dropdown.js
index dcf7415a444..71c9e580420 100644
--- a/app/assets/javascripts/projects/settings/access_dropdown.js
+++ b/app/assets/javascripts/projects/settings/access_dropdown.js
@@ -1,7 +1,7 @@
/* eslint-disable no-underscore-dangle, class-methods-use-this */
import { escape, find, countBy } from 'lodash';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { n__, s__, __, sprintf } from '~/locale';
import { getUsers, getGroups, getDeployKeys } from './api/access_dropdown_api';
import { LEVEL_TYPES, LEVEL_ID_PROP, ACCESS_LEVELS, ACCESS_LEVEL_NONE } from './constants';
@@ -469,6 +469,14 @@ export default class AccessDropdown {
}
}
+ if (this.accessLevel === ACCESS_LEVELS.CREATE && deployKeys.length) {
+ consolidatedData = consolidatedData.concat(
+ [{ type: 'divider' }],
+ [{ type: 'header', content: s__('AccessDropdown|Deploy Keys') }],
+ deployKeys,
+ );
+ }
+
return consolidatedData;
}
@@ -506,7 +514,10 @@ export default class AccessDropdown {
break;
case LEVEL_TYPES.DEPLOY_KEY:
groupRowEl =
- this.accessLevel === ACCESS_LEVELS.PUSH ? this.deployKeyRowHtml(item, isActive) : '';
+ this.accessLevel === ACCESS_LEVELS.PUSH || this.accessLevel === ACCESS_LEVELS.CREATE
+ ? this.deployKeyRowHtml(item, isActive)
+ : '';
+
break;
case LEVEL_TYPES.GROUP:
groupRowEl = this.groupRowHtml(item, isActive);
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/edit/branch_dropdown.vue b/app/assets/javascripts/projects/settings/branch_rules/components/edit/branch_dropdown.vue
index f2b1c749abc..3dcacf9eb34 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/edit/branch_dropdown.vue
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/edit/branch_dropdown.vue
@@ -7,7 +7,7 @@ import {
GlSprintf,
GlLink,
} from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__, sprintf } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import branchesQuery from '../../queries/branches.query.graphql';
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js b/app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js
index a98c2439cde..b71c33d2b91 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js
@@ -14,11 +14,6 @@ export const I18N = {
wildcardsHelpText: s__(
'BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/ are supported',
),
- forcePushTitle: s__('BranchRules|Force push'),
- allowForcePushDescription: s__(
- 'BranchRules|All users with push access are allowed to force push.',
- ),
- disallowForcePushDescription: s__('BranchRules|Force push is not allowed.'),
approvalsTitle: s__('BranchRules|Approvals'),
manageApprovalsLinkTitle: s__('BranchRules|Manage in merge request approvals'),
approvalsDescription: s__(
@@ -33,6 +28,19 @@ export const I18N = {
allowedToPushHeader: s__('BranchRules|Allowed to push and merge (%{total})'),
allowedToMergeHeader: s__('BranchRules|Allowed to merge (%{total})'),
approvalsHeader: s__('BranchRules|Required approvals (%{total})'),
+ allowForcePushTitle: s__('BranchRules|Allows force push'),
+ doesNotAllowForcePushTitle: s__('BranchRules|Does not allow force push'),
+ forcePushDescription: s__('BranchRules|From users with push access.'),
+ requiresCodeOwnerApprovalTitle: s__('BranchRules|Requires approval from code owners'),
+ doesNotRequireCodeOwnerApprovalTitle: s__(
+ 'BranchRules|Does not require approval from code owners',
+ ),
+ requiresCodeOwnerApprovalDescription: s__(
+ 'BranchRules|Also rejects code pushes that change files listed in CODEOWNERS file.',
+ ),
+ doesNotRequireCodeOwnerApprovalDescription: s__(
+ 'BranchRules|Also accepts code pushes that change files listed in CODEOWNERS file.',
+ ),
noData: s__('BranchRules|No data to display'),
};
@@ -48,3 +56,9 @@ export const PROTECTED_BRANCHES_HELP_PATH = 'user/project/protected_branches';
export const APPROVALS_HELP_PATH = 'user/project/merge_requests/approvals/index.md';
export const STATUS_CHECKS_HELP_PATH = 'user/project/merge_requests/status_checks.md';
+
+export const REQUIRED_ICON = 'check-circle-filled';
+export const NOT_REQUIRED_ICON = 'status-failed';
+
+export const REQUIRED_ICON_CLASS = 'gl-fill-green-500';
+export const NOT_REQUIRED_ICON_CLASS = 'gl-text-red-500';
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue b/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
index 740868e1d75..b0abe7ac463 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
@@ -1,5 +1,5 @@
<script>
-import { GlSprintf, GlLink, GlLoadingIcon } from '@gitlab/ui';
+import { GlSprintf, GlLink, GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { sprintf, n__ } from '~/locale';
import { getParameterByName, mergeUrlParams } from '~/lib/utils/url_utility';
import { helpPagePath } from '~/helpers/help_page_helper';
@@ -12,6 +12,10 @@ import {
BRANCH_PARAM_NAME,
WILDCARDS_HELP_PATH,
PROTECTED_BRANCHES_HELP_PATH,
+ REQUIRED_ICON,
+ NOT_REQUIRED_ICON,
+ REQUIRED_ICON_CLASS,
+ NOT_REQUIRED_ICON_CLASS,
} from './constants';
const wildcardsHelpDocLink = helpPagePath(WILDCARDS_HELP_PATH);
@@ -22,7 +26,7 @@ export default {
i18n: I18N,
wildcardsHelpDocLink,
protectedBranchesHelpDocLink,
- components: { Protection, GlSprintf, GlLink, GlLoadingIcon },
+ components: { Protection, GlSprintf, GlLink, GlLoadingIcon, GlIcon },
inject: {
projectPath: {
default: '',
@@ -33,6 +37,9 @@ export default {
branchesPath: {
default: '',
},
+ showStatusChecks: { default: false },
+ showApprovers: { default: false },
+ showCodeOwners: { default: false },
},
apollo: {
project: {
@@ -63,10 +70,28 @@ export default {
};
},
computed: {
- forcePushDescription() {
- return this.branchProtection?.allowForcePush
- ? this.$options.i18n.allowForcePushDescription
- : this.$options.i18n.disallowForcePushDescription;
+ forcePushAttributes() {
+ const { allowForcePush } = this.branchProtection || {};
+ const icon = allowForcePush ? REQUIRED_ICON : NOT_REQUIRED_ICON;
+ const iconClass = allowForcePush ? REQUIRED_ICON_CLASS : NOT_REQUIRED_ICON_CLASS;
+ const title = allowForcePush
+ ? this.$options.i18n.allowForcePushTitle
+ : this.$options.i18n.doesNotAllowForcePushTitle;
+
+ return { icon, iconClass, title };
+ },
+ codeOwnersApprovalAttributes() {
+ const { codeOwnerApprovalRequired } = this.branchProtection || {};
+ const icon = codeOwnerApprovalRequired ? REQUIRED_ICON : NOT_REQUIRED_ICON;
+ const iconClass = codeOwnerApprovalRequired ? REQUIRED_ICON_CLASS : NOT_REQUIRED_ICON_CLASS;
+ const title = codeOwnerApprovalRequired
+ ? this.$options.i18n.requiresCodeOwnerApprovalTitle
+ : this.$options.i18n.doesNotRequireCodeOwnerApprovalTitle;
+ const description = codeOwnerApprovalRequired
+ ? this.$options.i18n.requiresCodeOwnerApprovalDescription
+ : this.$options.i18n.doesNotRequireCodeOwnerApprovalDescription;
+
+ return { icon, iconClass, title, description };
},
mergeAccessLevels() {
const { mergeAccessLevels } = this.branchProtection || {};
@@ -98,7 +123,7 @@ export default {
: this.$options.i18n.branchNameOrPattern;
},
matchingBranchesLinkHref() {
- return mergeUrlParams({ state: 'all', search: this.branch }, this.branchesPath);
+ return mergeUrlParams({ state: 'all', search: `^${this.branch}$` }, this.branchesPath);
},
matchingBranchesLinkTitle() {
const total = this.matchingBranchesCount;
@@ -164,10 +189,6 @@ export default {
:groups="pushAccessLevels.groups"
/>
- <!-- Force push -->
- <strong>{{ $options.i18n.forcePushTitle }}</strong>
- <p>{{ forcePushDescription }}</p>
-
<!-- Allowed to merge -->
<protection
:header="allowedToMergeHeader"
@@ -178,9 +199,37 @@ export default {
:groups="mergeAccessLevels.groups"
/>
+ <!-- Force push -->
+ <div class="gl-display-flex gl-align-items-center">
+ <gl-icon
+ :size="14"
+ data-testid="force-push-icon"
+ :name="forcePushAttributes.icon"
+ :class="forcePushAttributes.iconClass"
+ />
+ <strong class="gl-ml-2">{{ forcePushAttributes.title }}</strong>
+ </div>
+
+ <div class="gl-text-gray-400 gl-mb-2">{{ $options.i18n.forcePushDescription }}</div>
+
<!-- EE start -->
+ <!-- Code Owners -->
+ <div v-if="showCodeOwners">
+ <div class="gl-display-flex gl-align-items-center">
+ <gl-icon
+ data-testid="code-owners-icon"
+ :size="14"
+ :name="codeOwnersApprovalAttributes.icon"
+ :class="codeOwnersApprovalAttributes.iconClass"
+ />
+ <strong class="gl-ml-2">{{ codeOwnersApprovalAttributes.title }}</strong>
+ </div>
+
+ <div class="gl-text-gray-400">{{ codeOwnersApprovalAttributes.description }}</div>
+ </div>
+
<!-- Approvals -->
- <template v-if="approvalsHeader">
+ <template v-if="showApprovers">
<h4 class="gl-mb-1 gl-mt-5">{{ $options.i18n.approvalsTitle }}</h4>
<gl-sprintf :message="$options.i18n.approvalsDescription">
<template #link="{ content }">
@@ -200,7 +249,7 @@ export default {
</template>
<!-- Status checks -->
- <template v-if="statusChecksHeader">
+ <template v-if="showStatusChecks">
<h4 class="gl-mb-1 gl-mt-5">{{ $options.i18n.statusChecksTitle }}</h4>
<gl-sprintf :message="$options.i18n.statusChecksDescription">
<template #link="{ content }">
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue b/app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue
index 9bff2f5506c..721248e53e3 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue
@@ -101,12 +101,7 @@ export default {
<div v-if="statusCheckUrl" class="gl-ml-7 gl-flex-grow-1">{{ statusCheckUrl }}</div>
- <div
- v-for="(item, index) in accessLevels"
- :key="index"
- data-testid="access-level"
- class="gl-w-quarter"
- >
+ <div v-for="(item, index) in accessLevels" :key="index" data-testid="access-level">
<span v-if="commaSeparateList && index > 0" data-testid="comma-separator">,</span>
{{ item.accessLevelDescription }}
</div>
diff --git a/app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js b/app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js
index 081d6cec958..c429c352bfa 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js
+++ b/app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
+import { parseBoolean } from '~/lib/utils/common_utils';
import View from 'ee_else_ce/projects/settings/branch_rules/components/view/index.vue';
export default function mountBranchRules(el) {
@@ -20,6 +21,9 @@ export default function mountBranchRules(el) {
approvalRulesPath,
statusChecksPath,
branchesPath,
+ showStatusChecks,
+ showApprovers,
+ showCodeOwners,
} = el.dataset;
return new Vue({
@@ -31,6 +35,9 @@ export default function mountBranchRules(el) {
approvalRulesPath,
statusChecksPath,
branchesPath,
+ showStatusChecks: parseBoolean(showStatusChecks),
+ showApprovers: parseBoolean(showApprovers),
+ showCodeOwners: parseBoolean(showCodeOwners),
},
render(h) {
return h(View);
diff --git a/app/assets/javascripts/projects/settings/components/access_dropdown.vue b/app/assets/javascripts/projects/settings/components/access_dropdown.vue
index cc47496971d..08a1c586f69 100644
--- a/app/assets/javascripts/projects/settings/components/access_dropdown.vue
+++ b/app/assets/javascripts/projects/settings/components/access_dropdown.vue
@@ -9,7 +9,7 @@ import {
GlSprintf,
} from '@gitlab/ui';
import { debounce, intersectionWith, groupBy, differenceBy, intersectionBy } from 'lodash';
-import { createAlert } from '~/flash';
+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';
@@ -86,7 +86,10 @@ export default {
return groupBy(this.preselectedItems, 'type');
},
showDeployKeys() {
- return this.accessLevel === ACCESS_LEVELS.PUSH && this.deployKeys.length;
+ return (
+ (this.accessLevel === ACCESS_LEVELS.PUSH || this.accessLevel === ACCESS_LEVELS.CREATE) &&
+ this.deployKeys.length
+ );
},
toggleLabel() {
const counts = Object.entries(this.selected).reduce((acc, [key, value]) => {
diff --git a/app/assets/javascripts/projects/settings/constants.js b/app/assets/javascripts/projects/settings/constants.js
index 9cf1afd334f..595cbc9c991 100644
--- a/app/assets/javascripts/projects/settings/constants.js
+++ b/app/assets/javascripts/projects/settings/constants.js
@@ -17,6 +17,7 @@ export const LEVEL_ID_PROP = {
export const ACCESS_LEVELS = {
MERGE: 'merge_access_levels',
PUSH: 'push_access_levels',
+ CREATE: 'create_access_levels',
};
export const ACCESS_LEVEL_NONE = 0;
diff --git a/app/assets/javascripts/projects/settings/mount_ref_switcher_badges.js b/app/assets/javascripts/projects/settings/mount_ref_switcher_badges.js
new file mode 100644
index 00000000000..527678250fb
--- /dev/null
+++ b/app/assets/javascripts/projects/settings/mount_ref_switcher_badges.js
@@ -0,0 +1,31 @@
+import Vue from 'vue';
+import RefSelector from '~/ref/components/ref_selector.vue';
+import { visitUrl } from '~/lib/utils/url_utility';
+import { generateRefDestinationPath } from './utils';
+
+export default function initRefSwitcherBadges() {
+ const refSwitcherElements = document.getElementsByClassName('js-ref-switcher-badge');
+
+ if (refSwitcherElements.length === 0) return false;
+
+ return Array.from(refSwitcherElements).forEach((element) => {
+ const { projectId, ref } = element.dataset;
+
+ return new Vue({
+ el: element,
+ render(createElement) {
+ return createElement(RefSelector, {
+ props: {
+ projectId,
+ value: ref,
+ },
+ on: {
+ input(selectedRef) {
+ visitUrl(generateRefDestinationPath(selectedRef));
+ },
+ },
+ });
+ },
+ });
+ });
+}
diff --git a/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue b/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
index f3d392a0ec4..7709419b6f8 100644
--- a/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
+++ b/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
@@ -1,6 +1,6 @@
<script>
import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import branchRulesQuery from 'ee_else_ce/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql';
import { expandSection } from '~/settings_panels';
import { scrollToElement } from '~/lib/utils/common_utils';
diff --git a/app/assets/javascripts/projects/settings/repository/branch_rules/components/branch_rule.vue b/app/assets/javascripts/projects/settings/repository/branch_rules/components/branch_rule.vue
index fa96eee5f92..b565bda247d 100644
--- a/app/assets/javascripts/projects/settings/repository/branch_rules/components/branch_rule.vue
+++ b/app/assets/javascripts/projects/settings/repository/branch_rules/components/branch_rule.vue
@@ -27,6 +27,9 @@ export default {
branchRulesPath: {
default: '',
},
+ showCodeOwners: { default: false },
+ showStatusChecks: { default: false },
+ showApprovers: { default: false },
},
props: {
name: {
@@ -70,7 +73,7 @@ export default {
return this.approvalDetails.length;
},
detailsPath() {
- return `${this.branchRulesPath}?branch=${this.name}`;
+ return `${this.branchRulesPath}?branch=${encodeURIComponent(this.name)}`;
},
statusChecksText() {
return sprintf(this.$options.i18n.statusChecks, {
@@ -112,13 +115,13 @@ export default {
if (this.branchProtection?.allowForcePush) {
approvalDetails.push(this.$options.i18n.allowForcePush);
}
- if (this.branchProtection?.codeOwnerApprovalRequired) {
+ if (this.showCodeOwners && this.branchProtection?.codeOwnerApprovalRequired) {
approvalDetails.push(this.$options.i18n.codeOwnerApprovalRequired);
}
- if (this.statusChecksTotal) {
+ if (this.showStatusChecks && this.statusChecksTotal) {
approvalDetails.push(this.statusChecksText);
}
- if (this.approvalRulesTotal) {
+ if (this.showApprovers && this.approvalRulesTotal) {
approvalDetails.push(this.approvalRulesText);
}
if (this.mergeAccessLevels.total > 0) {
diff --git a/app/assets/javascripts/projects/settings/repository/branch_rules/mount_branch_rules.js b/app/assets/javascripts/projects/settings/repository/branch_rules/mount_branch_rules.js
index 042be089e09..a8736c87e22 100644
--- a/app/assets/javascripts/projects/settings/repository/branch_rules/mount_branch_rules.js
+++ b/app/assets/javascripts/projects/settings/repository/branch_rules/mount_branch_rules.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import BranchRulesApp from '~/projects/settings/repository/branch_rules/app.vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
Vue.use(VueApollo);
@@ -12,7 +13,13 @@ const apolloProvider = new VueApollo({
export default function mountBranchRules(el) {
if (!el) return null;
- const { projectPath, branchRulesPath } = el.dataset;
+ const {
+ projectPath,
+ branchRulesPath,
+ showCodeOwners,
+ showStatusChecks,
+ showApprovers,
+ } = el.dataset;
return new Vue({
el,
@@ -20,6 +27,9 @@ export default function mountBranchRules(el) {
provide: {
projectPath,
branchRulesPath,
+ showCodeOwners: parseBoolean(showCodeOwners),
+ showStatusChecks: parseBoolean(showStatusChecks),
+ showApprovers: parseBoolean(showApprovers),
},
render(createElement) {
return createElement(BranchRulesApp);
diff --git a/app/assets/javascripts/projects/settings/topics/components/topics_token_selector.vue b/app/assets/javascripts/projects/settings/topics/components/topics_token_selector.vue
index 3d553e71f71..47477d39b8a 100644
--- a/app/assets/javascripts/projects/settings/topics/components/topics_token_selector.vue
+++ b/app/assets/javascripts/projects/settings/topics/components/topics_token_selector.vue
@@ -1,5 +1,6 @@
<script>
-import { GlTokenSelector, GlAvatarLabeled } from '@gitlab/ui';
+import { GlTokenSelector, GlAvatarLabeled, GlFormGroup, GlLink, GlSprintf } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
import { s__ } from '~/locale';
import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
import searchProjectTopics from '~/graphql_shared/queries/project_topics_search.query.graphql';
@@ -8,8 +9,15 @@ export default {
components: {
GlTokenSelector,
GlAvatarLabeled,
+ GlFormGroup,
+ GlLink,
+ GlSprintf,
},
i18n: {
+ topicsTitle: s__('ProjectSettings|Topics'),
+ topicsHelpText: s__(
+ 'ProjectSettings|Topics are publicly visible even on private projects. Do not include sensitive information in topic names. %{linkStart}Learn more%{linkEnd}.',
+ ),
placeholder: s__('ProjectSettings|Search for topic'),
},
props: {
@@ -51,6 +59,11 @@ export default {
placeholderText() {
return this.selectedTokens.length ? '' : this.$options.i18n.placeholder;
},
+ topicsHelpUrl() {
+ return helpPagePath('user/admin_area/index.html', {
+ anchor: 'administering-topics',
+ });
+ },
},
methods: {
handleEnter(event) {
@@ -70,25 +83,34 @@ export default {
};
</script>
<template>
- <gl-token-selector
- ref="tokenSelector"
- v-model="selectedTokens"
- :dropdown-items="topics"
- :loading="loading"
- allow-user-defined-tokens
- :placeholder="placeholderText"
- @keydown.enter="handleEnter"
- @text-input="filterTopics"
- @input="onTokensUpdate"
- >
- <template #dropdown-item-content="{ dropdownItem }">
- <gl-avatar-labeled
- :src="dropdownItem.avatarUrl"
- :entity-name="dropdownItem.name"
- :label="dropdownItem.title"
- :size="32"
- :shape="$options.AVATAR_SHAPE_OPTION_RECT"
- />
+ <gl-form-group id="project_topics" :label="$options.i18n.topicsTitle">
+ <gl-token-selector
+ ref="tokenSelector"
+ v-model="selectedTokens"
+ :dropdown-items="topics"
+ :loading="loading"
+ allow-user-defined-tokens
+ :placeholder="placeholderText"
+ @keydown.enter="handleEnter"
+ @text-input="filterTopics"
+ @input="onTokensUpdate"
+ >
+ <template #dropdown-item-content="{ dropdownItem }">
+ <gl-avatar-labeled
+ :src="dropdownItem.avatarUrl"
+ :entity-name="dropdownItem.name"
+ :label="dropdownItem.title"
+ :size="32"
+ :shape="$options.AVATAR_SHAPE_OPTION_RECT"
+ />
+ </template>
+ </gl-token-selector>
+ <template #description>
+ <gl-sprintf :message="$options.i18n.topicsHelpText">
+ <template #link="{ content }">
+ <gl-link :href="topicsHelpUrl" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
</template>
- </gl-token-selector>
+ </gl-form-group>
</template>
diff --git a/app/assets/javascripts/projects/settings/utils.js b/app/assets/javascripts/projects/settings/utils.js
index ea4574119c0..9c19657bb39 100644
--- a/app/assets/javascripts/projects/settings/utils.js
+++ b/app/assets/javascripts/projects/settings/utils.js
@@ -1,3 +1,24 @@
+import { joinPaths } from '~/lib/utils/url_utility';
+
+export const generateRefDestinationPath = (selectedRef) => {
+ const namespace = '-/settings/ci_cd';
+ const { pathname } = window.location;
+
+ if (!selectedRef || !pathname.includes(namespace)) {
+ return window.location.href;
+ }
+
+ const [projectRootPath] = pathname.split(namespace);
+
+ const destinationPath = joinPaths(projectRootPath, namespace);
+
+ const newURL = new URL(window.location);
+ newURL.pathname = destinationPath;
+ newURL.searchParams.set('ref', selectedRef);
+
+ return newURL.href;
+};
+
export const getAccessLevels = (accessLevels = {}) => {
const total = accessLevels.edges?.length;
const accessLevelTypes = { total, users: [], groups: [], roles: [] };
diff --git a/app/assets/javascripts/projects/star.js b/app/assets/javascripts/projects/star.js
index 55c3d68cd11..f294811dfff 100644
--- a/app/assets/javascripts/projects/star.js
+++ b/app/assets/javascripts/projects/star.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { spriteIcon } from '~/lib/utils/common_utils';
import { __, s__ } from '~/locale';
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
index 9f9b6424125..5b620aa2300 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
@@ -1,7 +1,7 @@
<script>
import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import Visibility from 'visibilityjs';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Poll from '~/lib/utils/poll';
import { __, s__, sprintf } from '~/locale';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
diff --git a/app/assets/javascripts/protected_branches/constants.js b/app/assets/javascripts/protected_branches/constants.js
index ae5eaa8e622..b5d00cb7e82 100644
--- a/app/assets/javascripts/protected_branches/constants.js
+++ b/app/assets/javascripts/protected_branches/constants.js
@@ -9,12 +9,3 @@ export const LEVEL_TYPES = {
GROUP: 'group',
DEPLOY_KEY: 'deploy_key',
};
-
-export const LEVEL_ID_PROP = {
- ROLE: 'access_level',
- USER: 'user_id',
- GROUP: 'group_id',
- DEPLOY_KEY: 'deploy_key_id',
-};
-
-export const ACCESS_LEVEL_NONE = 0;
diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js b/app/assets/javascripts/protected_branches/protected_branch_create.js
index 120f75d4f0c..cd37c0de6a5 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_create.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_create.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import CreateItemDropdown from '~/create_item_dropdown';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import AccessorUtilities from '~/lib/utils/accessor';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit.js b/app/assets/javascripts/protected_branches/protected_branch_edit.js
index 1693d869b54..b6c86750723 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_edit.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_edit.js
@@ -1,5 +1,5 @@
import { find } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import AccessDropdown from '~/projects/settings/access_dropdown';
diff --git a/app/assets/javascripts/protected_tags/constants.js b/app/assets/javascripts/protected_tags/constants.js
index 3e71ba62877..758b820c4c4 100644
--- a/app/assets/javascripts/protected_tags/constants.js
+++ b/app/assets/javascripts/protected_tags/constants.js
@@ -1,3 +1,14 @@
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',
+};
+
+export const LEVEL_TYPES = {
+ ROLE: 'role',
+ USER: 'user',
+ GROUP: 'group',
+ DEPLOY_KEY: 'deploy_key',
+};
diff --git a/app/assets/javascripts/protected_tags/protected_tag_create.js b/app/assets/javascripts/protected_tags/protected_tag_create.js
index 75fd11cd074..365b9a3b142 100644
--- a/app/assets/javascripts/protected_tags/protected_tag_create.js
+++ b/app/assets/javascripts/protected_tags/protected_tag_create.js
@@ -1,12 +1,21 @@
import $ from 'jquery';
-import { __ } from '~/locale';
-import CreateItemDropdown from '../create_item_dropdown';
-import ProtectedTagAccessDropdown from './protected_tag_access_dropdown';
+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';
export default class ProtectedTagCreate {
- constructor() {
+ constructor({ hasLicense }) {
+ this.hasLicense = hasLicense;
this.$form = $('.js-new-protected-tag');
this.buildDropdowns();
+ this.bindEvents();
+ }
+
+ bindEvents() {
+ this.$form.on('submit', this.onFormSubmit.bind(this));
}
buildDropdowns() {
@@ -16,15 +25,14 @@ export default class ProtectedTagCreate {
this.onSelectCallback = this.onSelect.bind(this);
// Allowed to Create dropdown
- this.protectedTagAccessDropdown = new ProtectedTagAccessDropdown({
+ this.protectedTagAccessDropdown = new AccessDropdown({
$dropdown: $allowedToCreateDropdown,
- data: gon.create_access_levels,
+ accessLevelsData: gon.create_access_levels,
onSelect: this.onSelectCallback,
+ accessLevel: ACCESS_LEVELS.CREATE,
+ hasLicense: this.hasLicense,
});
- // Select default
- $allowedToCreateDropdown.data('deprecatedJQueryDropdown').selectRowAtIndex(0);
-
// Protected tag dropdown
this.createItemDropdown = new CreateItemDropdown({
$dropdown: this.$form.find('.js-protected-tag-select'),
@@ -39,7 +47,7 @@ export default class ProtectedTagCreate {
onSelect() {
// Enable submit button
const $tagInput = this.$form.find('input[name="protected_tag[name]"]');
- const $allowedToCreateInput = this.$form.find('#create_access_levels_attributes');
+ const $allowedToCreateInput = this.protectedTagAccessDropdown.getSelectedItems();
this.$form
.find('button[type="submit"]')
@@ -49,4 +57,57 @@ export default class ProtectedTagCreate {
static getProtectedTags(term, callback) {
callback(gon.open_tags);
}
+
+ getFormData() {
+ const formData = {
+ authenticity_token: this.$form.find('input[name="authenticity_token"]').val(),
+ protected_tag: {
+ 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;
+ });
+
+ return formData;
+ }
+
+ onFormSubmit(e) {
+ e.preventDefault();
+
+ axios[this.$form.attr('method')](this.$form.attr('action'), this.getFormData())
+ .then(() => {
+ window.location.reload();
+ })
+ .catch(() =>
+ createAlert({
+ message: s__('ProjectSettings|Failed to protect the tag'),
+ }),
+ );
+ }
}
diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit.js b/app/assets/javascripts/protected_tags/protected_tag_edit.js
index 40c52eba99e..4fa3ac3be4b 100644
--- a/app/assets/javascripts/protected_tags/protected_tag_edit.js
+++ b/app/assets/javascripts/protected_tags/protected_tag_edit.js
@@ -1,57 +1,115 @@
-import { createAlert } from '~/flash';
-import axios from '../lib/utils/axios_utils';
-import { FAILED_TO_UPDATE_TAG_MESSAGE } from './constants';
-import ProtectedTagAccessDropdown from './protected_tag_access_dropdown';
+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.onSelectCallback = this.onSelect.bind(this);
+
+ this.$allowedToCreateDropdownContainer = this.$allowedToCreateDropdownButton.closest(
+ '.create_access_levels-container',
+ );
this.buildDropdowns();
}
buildDropdowns() {
// Allowed to create dropdown
- this.protectedTagAccessDropdown = new ProtectedTagAccessDropdown({
+ this.protectedTagAccessDropdown = new AccessDropdown({
+ accessLevel: ACCESS_LEVELS.CREATE,
+ accessLevelsData: gon.create_access_levels,
$dropdown: this.$allowedToCreateDropdownButton,
- data: gon.create_access_levels,
- onSelect: this.onSelectCallback,
+ onSelect: this.onSelectOption.bind(this),
+ onHide: this.onDropdownHide.bind(this),
+ hasLicense: this.hasLicense,
});
}
- onSelect() {
- const $allowedToCreateInput = this.$wrap.find(
- `input[name="${this.$allowedToCreateDropdownButton.data('fieldName')}"]`,
- );
+ onSelectOption() {
+ this.hasChanges = true;
+ }
- // Do not update if one dropdown has not selected any option
- if (!$allowedToCreateInput.length) return;
+ onDropdownHide() {
+ if (!this.hasChanges) {
+ return;
+ }
- this.$allowedToCreateDropdownButton.disable();
+ 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: {
- create_access_levels_attributes: [
- {
- id: this.$allowedToCreateDropdownButton.data('accessLevelId'),
- access_level: $allowedToCreateInput.val(),
- },
- ],
- },
+ protected_tag: formData,
})
- .then(() => {
- this.$allowedToCreateDropdownButton.enable();
+ .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(() => {
- this.$allowedToCreateDropdownButton.enable();
-
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_list.js b/app/assets/javascripts/protected_tags/protected_tag_edit_list.js
index b35bf4d4606..8ceb970bf03 100644
--- a/app/assets/javascripts/protected_tags/protected_tag_edit_list.js
+++ b/app/assets/javascripts/protected_tags/protected_tag_edit_list.js
@@ -4,7 +4,8 @@ import $ from 'jquery';
import ProtectedTagEdit from './protected_tag_edit';
export default class ProtectedTagEditList {
- constructor() {
+ constructor(options) {
+ this.hasLicense = options.hasLicense;
this.$wrap = $('.protected-tags-list');
this.initEditForm();
}
@@ -13,6 +14,7 @@ export default class ProtectedTagEditList {
this.$wrap.find('.js-protected-tag-edit-form').each((i, el) => {
new ProtectedTagEdit({
$wrap: $(el),
+ hasLicense: this.hasLicense,
});
});
}
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 adae92a92e9..7ecc39a56e7 100644
--- a/app/assets/javascripts/related_issues/components/add_issuable_form.vue
+++ b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
@@ -182,7 +182,7 @@ export default {
:checked="linkedIssueType"
/>
</gl-form-group>
- <p class="bold">
+ <p class="bold gl-mb-2">
{{ issuableInputText }}
</p>
</template>
diff --git a/app/assets/javascripts/related_issues/components/related_issuable_input.vue b/app/assets/javascripts/related_issues/components/related_issuable_input.vue
index 8d6a3110f35..1846b9cf8f4 100644
--- a/app/assets/javascripts/related_issues/components/related_issuable_input.vue
+++ b/app/assets/javascripts/related_issues/components/related_issuable_input.vue
@@ -182,7 +182,7 @@ export default {
<div
ref="issuableFormWrapper"
:class="{ focus: isInputFocused }"
- class="add-issuable-form-input-wrapper form-control gl-field-error-outline gl-h-auto gl-p-3 gl-pb-2"
+ class="add-issuable-form-input-wrapper form-control gl-field-error-outline gl-h-auto gl-px-3 gl-pt-2 gl-pb-0"
role="button"
@click="onIssuableFormWrapperClick"
>
diff --git a/app/assets/javascripts/related_issues/components/related_issues_block.vue b/app/assets/javascripts/related_issues/components/related_issues_block.vue
index 4a130ade631..043d925198c 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_block.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_block.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink, GlIcon, GlButton } from '@gitlab/ui';
+import { GlLink, GlIcon, GlLoadingIcon, GlButton, GlCard } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import {
issuableIconMap,
@@ -16,8 +16,10 @@ export default {
name: 'RelatedIssuesBlock',
components: {
GlLink,
- GlButton,
GlIcon,
+ GlLoadingIcon,
+ GlButton,
+ GlCard,
AddIssuableForm,
RelatedIssuesList,
},
@@ -181,64 +183,69 @@ export default {
<template>
<div id="related-issues" class="related-issues-block">
- <div class="card card-slim gl-overflow-hidden gl-mt-5 gl-mb-0">
- <div
- :class="{
- 'gl-border-b-1': isOpen,
- 'gl-border-b-0': !isOpen,
- }"
- class="gl-display-flex gl-justify-content-space-between gl-line-height-24 gl-py-3 gl-px-5 gl-bg-gray-10 gl-border-b-solid gl-border-b-gray-100"
- >
- <h3 class="card-title h5 gl-my-0 gl-display-flex gl-align-items-center gl-flex-grow-1">
- <gl-link
- id="user-content-related-issues"
- class="anchor position-absolute gl-text-decoration-none"
- href="#related-issues"
- aria-hidden="true"
- />
- <slot name="header-text">{{ headerText }}</slot>
-
- <div class="js-related-issues-header-issue-count gl-display-inline-flex gl-mx-3">
- <span class="gl-display-inline-flex gl-align-items-center">
- <gl-icon :name="issuableTypeIcon" class="gl-mr-2 gl-text-gray-500" />
- {{ badgeLabel }}
- </span>
- </div>
- </h3>
- <slot name="header-actions"></slot>
- <gl-button
- v-if="canAdmin"
- size="small"
- data-qa-selector="related_issues_plus_button"
- data-testid="related-issues-plus-button"
- :aria-label="addIssuableButtonText"
- class="gl-ml-3"
- @click="addButtonClick"
+ <gl-card
+ class="gl-overflow-hidden gl-mt-5 gl-mb-0"
+ header-class="gl-p-0 gl-border-0"
+ body-class="gl-p-0 gl-bg-gray-10"
+ >
+ <template #header>
+ <div
+ :class="{
+ 'gl-border-b-1': isOpen,
+ 'gl-border-b-0': !isOpen,
+ }"
+ class="gl-display-flex gl-justify-content-space-between gl-line-height-24 gl-pl-5 gl-pr-4 gl-py-4 gl-bg-white gl-border-b-solid gl-border-b-gray-100"
>
- <slot name="add-button-text">{{ __('Add') }}</slot>
- </gl-button>
- <div class="gl-pl-3 gl-ml-3 gl-border-l-1 gl-border-l-solid gl-border-l-gray-100">
+ <h3 class="card-title h5 gl-my-0 gl-display-flex gl-align-items-center gl-flex-grow-1">
+ <gl-link
+ id="user-content-related-issues"
+ class="anchor position-absolute gl-text-decoration-none"
+ href="#related-issues"
+ aria-hidden="true"
+ />
+ <slot name="header-text">{{ headerText }}</slot>
+
+ <div
+ class="js-related-issues-header-issue-count gl-display-inline-flex gl-mx-3 gl-text-gray-500"
+ >
+ <span class="gl-display-inline-flex gl-align-items-center">
+ <gl-icon :name="issuableTypeIcon" class="gl-mr-2 gl-text-gray-500" />
+ {{ badgeLabel }}
+ </span>
+ </div>
+ </h3>
+ <slot name="header-actions"></slot>
<gl-button
- category="tertiary"
+ v-if="canAdmin"
size="small"
- :icon="toggleIcon"
- :aria-label="toggleLabel"
- data-testid="toggle-links"
- @click="handleToggle"
- />
+ data-qa-selector="related_issues_plus_button"
+ data-testid="related-issues-plus-button"
+ :aria-label="addIssuableButtonText"
+ class="gl-ml-3"
+ @click="addButtonClick"
+ >
+ <slot name="add-button-text">{{ __('Add') }}</slot>
+ </gl-button>
+ <div class="gl-pl-3 gl-ml-3 gl-border-l-1 gl-border-l-solid gl-border-l-gray-100">
+ <gl-button
+ category="tertiary"
+ size="small"
+ :icon="toggleIcon"
+ :aria-label="toggleLabel"
+ data-testid="toggle-links"
+ @click="handleToggle"
+ />
+ </div>
</div>
- </div>
+ </template>
<div
v-if="isOpen"
- class="linked-issues-card-body gl-bg-gray-10"
- :class="{
- 'gl-p-5': isFormVisible || shouldShowTokenBody,
- }"
+ class="linked-issues-card-body gl-py-3 gl-px-4 gl-bg-gray-10"
data-testid="related-issues-body"
>
<div
v-if="isFormVisible"
- class="js-add-related-issues-form-area card-body bordered-box bg-white"
+ class="js-add-related-issues-form-area card-body bg-white gl-mt-2 gl-border-1 gl-border-solid gl-border-gray-100 gl-rounded-base"
:class="{ 'gl-mb-5': shouldShowTokenBody, 'gl-show-field-errors': hasError }"
>
<add-issuable-form
@@ -261,6 +268,7 @@ export default {
/>
</div>
<template v-if="shouldShowTokenBody">
+ <gl-loading-icon v-if="isFetching" size="sm" class="gl-py-2" />
<related-issues-list
v-for="(category, index) in categorisedIssues"
:key="category.linkType"
@@ -272,13 +280,16 @@ export default {
:issuable-type="issuableType"
:path-id-separator="pathIdSeparator"
:related-issues="category.issues"
- :class="{ 'gl-mt-5': index > 0 }"
+ :class="{
+ 'gl-pb-3 gl-mb-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100':
+ index !== categorisedIssues.length - 1,
+ }"
@relatedIssueRemoveRequest="$emit('relatedIssueRemoveRequest', $event)"
@saveReorder="$emit('saveReorder', $event)"
/>
</template>
<div v-if="!shouldShowTokenBody && !isFormVisible" data-testid="related-items-empty">
- <p class="gl-my-5 gl-px-5">
+ <p class="gl-p-2 gl-mb-0 gl-text-gray-500">
{{ emptyStateMessage }}
<gl-link
v-if="hasHelpPath"
@@ -292,6 +303,6 @@ export default {
</p>
</div>
</div>
- </div>
+ </gl-card>
</div>
</template>
diff --git a/app/assets/javascripts/related_issues/components/related_issues_list.vue b/app/assets/javascripts/related_issues/components/related_issues_list.vue
index 7387b9ab87c..4429c1beb00 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_list.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_list.vue
@@ -97,11 +97,13 @@ export default {
<template>
<div :data-link-type="listLinkType">
- <h4 v-if="heading" class="gl-font-base mt-0">{{ heading }}</h4>
- <div
- class="related-issues-token-body bordered-box bg-white"
- :class="{ 'sortable-container': canReorder }"
+ <h4
+ v-if="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="related-issues-token-body" :class="{ 'sortable-container': canReorder }">
<div v-if="isFetching" class="gl-mb-2" data-qa-selector="related_issues_loading_placeholder">
<gl-loading-icon
ref="loadingIcon"
@@ -121,7 +123,7 @@ export default {
}"
:data-key="issue.id"
:data-ordering-id="issuableOrderingId(issue)"
- class="js-related-issues-token-list-item list-item pt-0 pb-0"
+ class="js-related-issues-token-list-item list-item pt-0 pb-0 gl-border-b-0!"
>
<related-issuable-item
:id-key="issue.id"
diff --git a/app/assets/javascripts/related_issues/components/related_issues_root.vue b/app/assets/javascripts/related_issues/components/related_issues_root.vue
index ed70e1ce8a8..51f4e4f7d7b 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_root.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_root.vue
@@ -23,7 +23,7 @@ Your caret can stop touching a `rawReference` can happen in a variety of ways:
and hide the `AddIssuableForm` area.
*/
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
import { TYPE_ISSUE } from '~/issues/constants';
import { HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
diff --git a/app/assets/javascripts/related_issues/constants.js b/app/assets/javascripts/related_issues/constants.js
index 2a4ce70511b..25fc875db65 100644
--- a/app/assets/javascripts/related_issues/constants.js
+++ b/app/assets/javascripts/related_issues/constants.js
@@ -1,12 +1,5 @@
import { __, sprintf } from '~/locale';
-import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
-
-export const issuableTypesMap = {
- ISSUE: 'issue',
- INCIDENT: 'incident',
- EPIC: 'epic',
- MERGE_REQUEST: 'merge_request',
-};
+import { TYPE_EPIC, TYPE_INCIDENT, TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
export const linkedIssueTypesMap = {
BLOCKS: 'blocks',
@@ -27,7 +20,7 @@ export const autoCompleteTextMap = {
{ emphasisStart: '<', emphasisEnd: '>' },
false,
),
- [issuableTypesMap.INCIDENT]: sprintf(
+ [TYPE_INCIDENT]: sprintf(
__(' or %{emphasisStart}#id%{emphasisEnd}'),
{ emphasisStart: '<', emphasisEnd: '>' },
false,
@@ -37,7 +30,7 @@ export const autoCompleteTextMap = {
{ emphasisStart: '<', emphasisEnd: '>' },
false,
),
- [issuableTypesMap.MERGE_REQUEST]: sprintf(
+ [TYPE_MERGE_REQUEST]: sprintf(
__(' or %{emphasisStart}!merge request id%{emphasisEnd}'),
{ emphasisStart: '<', emphasisEnd: '>' },
false,
@@ -46,21 +39,21 @@ export const autoCompleteTextMap = {
false: {
[TYPE_ISSUE]: '',
[TYPE_EPIC]: '',
- [issuableTypesMap.MERGE_REQUEST]: __(' or references'),
+ [TYPE_MERGE_REQUEST]: __(' or references'),
},
};
export const inputPlaceholderTextMap = {
[TYPE_ISSUE]: __('Paste issue link'),
- [issuableTypesMap.INCIDENT]: __('Paste link'),
+ [TYPE_INCIDENT]: __('Paste link'),
[TYPE_EPIC]: __('Paste epic link'),
- [issuableTypesMap.MERGE_REQUEST]: __('Enter merge request URLs'),
+ [TYPE_MERGE_REQUEST]: __('Enter merge request URLs'),
};
export const inputPlaceholderConfidentialTextMap = {
[TYPE_ISSUE]: __('Paste confidential issue link'),
[TYPE_EPIC]: __('Paste confidential epic link'),
- [issuableTypesMap.MERGE_REQUEST]: __('Enter merge request URLs'),
+ [TYPE_MERGE_REQUEST]: __('Enter merge request URLs'),
};
export const relatedIssuesRemoveErrorMap = {
@@ -96,7 +89,7 @@ export const addRelatedItemErrorMap = {
*/
export const issuableIconMap = {
[TYPE_ISSUE]: 'issues',
- [issuableTypesMap.INCIDENT]: 'issues',
+ [TYPE_INCIDENT]: 'issues',
[TYPE_EPIC]: 'epic',
};
@@ -107,13 +100,13 @@ export const PathIdSeparator = {
export const issuablesBlockHeaderTextMap = {
[TYPE_ISSUE]: __('Linked items'),
- [issuableTypesMap.INCIDENT]: __('Linked incidents or issues'),
+ [TYPE_INCIDENT]: __('Linked incidents or issues'),
[TYPE_EPIC]: __('Linked epics'),
};
export const issuablesBlockHelpTextMap = {
[TYPE_ISSUE]: __('Learn more about linking issues'),
- [issuableTypesMap.INCIDENT]: __('Learn more about linking issues and incidents'),
+ [TYPE_INCIDENT]: __('Learn more about linking issues and incidents'),
[TYPE_EPIC]: __('Learn more about linking epics'),
};
@@ -124,12 +117,12 @@ export const issuablesBlockAddButtonTextMap = {
export const issuablesFormCategoryHeaderTextMap = {
[TYPE_ISSUE]: __('The current issue'),
- [issuableTypesMap.INCIDENT]: __('The current incident'),
+ [TYPE_INCIDENT]: __('The current incident'),
[TYPE_EPIC]: __('The current epic'),
};
export const issuablesFormInputTextMap = {
[TYPE_ISSUE]: __('the following issues'),
- [issuableTypesMap.INCIDENT]: __('the following incidents or issues'),
+ [TYPE_INCIDENT]: __('the following incidents or issues'),
[TYPE_EPIC]: __('the following epics'),
};
diff --git a/app/assets/javascripts/releases/components/app_index.vue b/app/assets/javascripts/releases/components/app_index.vue
index 9f200856db3..515d9efaefd 100644
--- a/app/assets/javascripts/releases/components/app_index.vue
+++ b/app/assets/javascripts/releases/components/app_index.vue
@@ -1,6 +1,6 @@
<script>
import { GlButton } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { historyPushState } from '~/lib/utils/common_utils';
import { scrollUp } from '~/lib/utils/scroll_utils';
import { setUrlParams, getParameterByName } from '~/lib/utils/url_utility';
diff --git a/app/assets/javascripts/releases/components/app_show.vue b/app/assets/javascripts/releases/components/app_show.vue
index 544f2de5132..111d9e232c5 100644
--- a/app/assets/javascripts/releases/components/app_show.vue
+++ b/app/assets/javascripts/releases/components/app_show.vue
@@ -1,5 +1,5 @@
<script>
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import { popCreateReleaseNotification } from '~/releases/release_notification_service';
import oneReleaseQuery from '../graphql/queries/one_release.query.graphql';
diff --git a/app/assets/javascripts/releases/components/tag_field_new.vue b/app/assets/javascripts/releases/components/tag_field_new.vue
index 2ddab5dddea..2ac61988393 100644
--- a/app/assets/javascripts/releases/components/tag_field_new.vue
+++ b/app/assets/javascripts/releases/components/tag_field_new.vue
@@ -68,10 +68,7 @@ export default {
},
},
showTagNameValidationError() {
- return (
- this.isInputDirty &&
- (this.validationErrors.isTagNameEmpty || this.validationErrors.existingRelease)
- );
+ return this.isInputDirty && !this.validationErrors.tagNameValidation.isValid;
},
tagNameInputId() {
return uniqueId('tag-name-input-');
@@ -80,9 +77,7 @@ export default {
return uniqueId('create-from-selector-');
},
tagFeedback() {
- return this.validationErrors.existingRelease
- ? __('Selected tag is already in use. Choose another option.')
- : __('Tag name is required.');
+ return this.validationErrors.tagNameValidation.validationErrors[0];
},
},
methods: {
diff --git a/app/assets/javascripts/releases/constants.js b/app/assets/javascripts/releases/constants.js
index 4f862741e11..5e9e65a01b3 100644
--- a/app/assets/javascripts/releases/constants.js
+++ b/app/assets/javascripts/releases/constants.js
@@ -49,3 +49,8 @@ export const SORT_MAP = {
};
export const DEFAULT_SORT = RELEASED_AT_DESC;
+
+export const i18n = {
+ tagNameIsRequiredMessage: __('Tag name is required.'),
+ tagIsAlredyInUseMessage: __('Selected tag is already in use. Choose another option.'),
+};
diff --git a/app/assets/javascripts/releases/release_notification_service.js b/app/assets/javascripts/releases/release_notification_service.js
index a4f926d7561..775c62802d4 100644
--- a/app/assets/javascripts/releases/release_notification_service.js
+++ b/app/assets/javascripts/releases/release_notification_service.js
@@ -1,5 +1,5 @@
import { s__, sprintf } from '~/locale';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
const createReleaseSessionKey = (projectPath) => `createRelease:${projectPath}`;
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/actions.js b/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
index 42ceed81c00..a7d8825ed33 100644
--- a/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
@@ -1,5 +1,5 @@
import { getTag } from '~/rest_api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import createReleaseMutation from '~/releases/graphql/mutations/create_release.mutation.graphql';
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/getters.js b/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
index 0d77095d099..8ff479058f2 100644
--- a/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
@@ -2,6 +2,8 @@ import { isEmpty } from 'lodash';
import { s__ } from '~/locale';
import { hasContent } from '~/lib/utils/text_utility';
import { getDuplicateItemsFromArray } from '~/lib/utils/array_utility';
+import { validateTag, ValidationResult } from '~/lib/utils/ref_validator';
+import { i18n } from '~/releases/constants';
/**
* @param {Object} link The link to test
@@ -35,18 +37,21 @@ export const validationErrors = (state) => {
assets: {
links: {},
},
+ tagNameValidation: new ValidationResult(),
};
if (!state.release) {
return errors;
}
- if (!state.release.tagName?.trim?.().length) {
- errors.isTagNameEmpty = true;
+ if (!state.release.tagName || typeof state.release.tagName !== 'string') {
+ errors.tagNameValidation.addValidationError(i18n.tagNameIsRequiredMessage);
+ } else {
+ errors.tagNameValidation = validateTag(state.release.tagName);
}
if (state.existingRelease) {
- errors.existingRelease = true;
+ errors.tagNameValidation.addValidationError(i18n.tagIsAlredyInUseMessage);
}
// Each key of this object is a URL, and the value is an
diff --git a/app/assets/javascripts/repository/commits_service.js b/app/assets/javascripts/repository/commits_service.js
index d029f8cf89f..e26036b5620 100644
--- a/app/assets/javascripts/repository/commits_service.js
+++ b/app/assets/javascripts/repository/commits_service.js
@@ -1,7 +1,7 @@
import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { normalizeData } from 'ee_else_ce/repository/utils/commit';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { COMMIT_BATCH_SIZE, I18N_COMMIT_DATA_FETCH_ERROR } from './constants';
let requestedOffsets = [];
diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue
index 101625a4b72..236351005e7 100644
--- a/app/assets/javascripts/repository/components/blob_content_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue
@@ -4,7 +4,7 @@ import { uniqueId } from 'lodash';
import BlobContent from '~/blob/components/blob_content.vue';
import BlobHeader from '~/blob/components/blob_header.vue';
import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { isLoggedIn, handleLocationHash } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
diff --git a/app/assets/javascripts/repository/components/blob_controls.vue b/app/assets/javascripts/repository/components/blob_controls.vue
index 29c2c3762fc..d3e306619bf 100644
--- a/app/assets/javascripts/repository/components/blob_controls.vue
+++ b/app/assets/javascripts/repository/components/blob_controls.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import getRefMixin from '~/repository/mixins/get_ref';
import initSourcegraph from '~/sourcegraph';
import ShortcutsBlob from '~/behaviors/shortcuts/shortcuts_blob';
diff --git a/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue
index 1114a0942ec..53dad19028d 100644
--- a/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue
@@ -1,11 +1,15 @@
<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import notebookLoader from '~/blob/notebook';
import { stripPathTail } from '~/lib/utils/url_utility';
+import NotebookViewer from '~/blob/notebook/notebook_viewer.vue';
export default {
- components: {
- GlLoadingIcon,
+ components: { NotebookViewer },
+ provide() {
+ // `relativeRawPath` is injected in app/assets/javascripts/notebook/cells/markdown.vue
+ // It is needed for images in Markdown cells that reference local files to work.
+ // See the following MR for more context:
+ // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69075
+ return { relativeRawPath: stripPathTail(this.url) };
},
props: {
blob: {
@@ -18,14 +22,9 @@ export default {
url: this.blob.rawPath,
};
},
- mounted() {
- notebookLoader({ el: this.$refs.viewer, relativeRawPath: stripPathTail(this.url) });
- },
};
</script>
<template>
- <div ref="viewer" :data-endpoint="url" data-testid="notebook">
- <gl-loading-icon class="gl-my-4" size="lg" />
- </div>
+ <notebook-viewer :endpoint="url" />
</template>
diff --git a/app/assets/javascripts/repository/components/delete_blob_modal.vue b/app/assets/javascripts/repository/components/delete_blob_modal.vue
index baf8449b188..cbdf6ef9ccd 100644
--- a/app/assets/javascripts/repository/components/delete_blob_modal.vue
+++ b/app/assets/javascripts/repository/components/delete_blob_modal.vue
@@ -101,23 +101,19 @@ export default {
primaryOptions() {
return {
text: this.$options.i18n.PRIMARY_OPTIONS_TEXT,
- attributes: [
- {
- variant: 'danger',
- loading: this.loading,
- disabled: this.loading || !this.form.state,
- },
- ],
+ attributes: {
+ variant: 'danger',
+ loading: this.loading,
+ disabled: this.loading || !this.form.state,
+ },
};
},
cancelOptions() {
return {
text: this.$options.i18n.SECONDARY_OPTIONS_TEXT,
- attributes: [
- {
- disabled: this.loading,
- },
- ],
+ attributes: {
+ disabled: this.loading,
+ },
};
},
showCreateNewMrToggle() {
diff --git a/app/assets/javascripts/repository/components/fork_info.vue b/app/assets/javascripts/repository/components/fork_info.vue
index 9804837b200..1a834ba1d82 100644
--- a/app/assets/javascripts/repository/components/fork_info.vue
+++ b/app/assets/javascripts/repository/components/fork_info.vue
@@ -1,8 +1,16 @@
<script>
-import { GlIcon, GlLink, GlSkeletonLoader, GlSprintf } from '@gitlab/ui';
+import { GlIcon, GlLink, GlSkeletonLoader, GlLoadingIcon, GlSprintf, GlButton } from '@gitlab/ui';
import { s__, sprintf, n__ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import syncForkMutation from '~/repository/mutations/sync_fork.mutation.graphql';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import {
+ POLLING_INTERVAL_DEFAULT,
+ POLLING_INTERVAL_BACKOFF,
+ FIVE_MINUTES_IN_MS,
+} from '../constants';
import forkDetailsQuery from '../queries/fork_details.query.graphql';
+import ConflictsModal from './fork_sync_conflicts_modal.vue';
export const i18n = {
forkedFrom: s__('ForkedFromProjectPath|Forked from'),
@@ -12,7 +20,9 @@ export const i18n = {
behind: s__('ForksDivergence|%{behindLinkStart}%{behind} %{commit_word} behind%{behindLinkEnd}'),
ahead: s__('ForksDivergence|%{aheadLinkStart}%{ahead} %{commit_word} ahead%{aheadLinkEnd} of'),
behindAhead: s__('ForksDivergence|%{messages} the upstream repository.'),
+ limitedVisibility: s__('ForksDivergence|Source project has a limited visibility.'),
error: s__('ForksDivergence|Failed to fetch fork details. Try again later.'),
+ sync: s__('ForksDivergence|Update fork'),
};
export default {
@@ -20,17 +30,19 @@ export default {
components: {
GlIcon,
GlLink,
+ GlButton,
GlSprintf,
GlSkeletonLoader,
+ ConflictsModal,
+ GlLoadingIcon,
},
+ mixins: [glFeatureFlagMixin()],
apollo: {
project: {
query: forkDetailsQuery,
+ notifyOnNetworkStatusChange: true,
variables() {
- return {
- projectPath: this.projectPath,
- ref: this.selectedBranch,
- };
+ return this.forkDetailsQueryVariables;
},
skip() {
return !this.sourceName;
@@ -42,6 +54,12 @@ export default {
error,
});
},
+ result({ loading }) {
+ this.handlePolingInterval(loading);
+ },
+ pollInterval() {
+ return this.pollInterval;
+ },
},
},
props: {
@@ -53,6 +71,11 @@ export default {
type: String,
required: true,
},
+ sourceDefaultBranch: {
+ type: String,
+ required: false,
+ default: '',
+ },
sourceName: {
type: String,
required: false,
@@ -76,18 +99,33 @@ export default {
},
data() {
return {
- project: {
- forkDetails: {
- ahead: null,
- behind: null,
- },
- },
+ project: {},
+ currentPollInterval: null,
+ isSyncTriggered: false,
};
},
computed: {
+ forkDetailsQueryVariables() {
+ return {
+ projectPath: this.projectPath,
+ ref: this.selectedBranch,
+ };
+ },
+ pollInterval() {
+ return this.isSyncing ? this.currentPollInterval : 0;
+ },
isLoading() {
return this.$apollo.queries.project.loading;
},
+ forkDetails() {
+ return this.project?.forkDetails;
+ },
+ hasConflicts() {
+ return this.forkDetails?.hasConflicts;
+ },
+ isSyncing() {
+ return this.forkDetails?.isSyncing;
+ },
ahead() {
return this.project?.forkDetails?.ahead;
},
@@ -107,7 +145,10 @@ export default {
});
},
isUnknownDivergence() {
- return (!this.ahead && this.ahead !== 0) || (!this.behind && this.behind !== 0);
+ return this.sourceName && this.ahead === null && this.behind === null;
+ },
+ isUpToDate() {
+ return this.ahead === 0 && this.behind === 0;
},
behindAheadMessage() {
const messages = [];
@@ -122,7 +163,16 @@ export default {
hasBehindAheadMessage() {
return this.behindAheadMessage.length > 0;
},
+ isSyncButtonAvailable() {
+ return (
+ this.glFeatures.synchronizeFork &&
+ ((this.sourceName && this.forkDetails && this.behind) || this.isUnknownDivergence)
+ );
+ },
forkDivergenceMessage() {
+ if (!this.forkDetails) {
+ return this.$options.i18n.limitedVisibility;
+ }
if (this.isUnknownDivergence) {
return this.$options.i18n.unknown;
}
@@ -134,6 +184,73 @@ export default {
return this.$options.i18n.upToDate;
},
},
+ watch: {
+ hasConflicts(newVal) {
+ if (newVal && this.isSyncTriggered) {
+ this.showConflictsModal();
+ this.isSyncTriggered = false;
+ }
+ },
+ },
+ methods: {
+ async syncForkWithPolling() {
+ await this.$apollo.mutate({
+ mutation: syncForkMutation,
+ variables: {
+ projectPath: this.projectPath,
+ targetBranch: this.selectedBranch,
+ },
+ error(error) {
+ createAlert({
+ message: error.message,
+ captureError: true,
+ error,
+ });
+ },
+ update: (store, { data: { projectSyncFork } }) => {
+ const { details } = projectSyncFork;
+
+ store.writeQuery({
+ query: forkDetailsQuery,
+ variables: this.forkDetailsQueryVariables,
+ data: {
+ project: {
+ id: this.project.id,
+ forkDetails: details,
+ },
+ },
+ });
+ },
+ });
+ },
+ showConflictsModal() {
+ this.$refs.modal.show();
+ },
+ startSyncing() {
+ this.isSyncTriggered = true;
+ this.syncForkWithPolling();
+ },
+ checkIfSyncIsPossible() {
+ if (this.hasConflicts) {
+ this.showConflictsModal();
+ } else {
+ this.startSyncing();
+ }
+ },
+ handlePolingInterval(loading) {
+ if (!loading && this.isSyncing) {
+ const backoff = POLLING_INTERVAL_BACKOFF;
+ const interval = this.currentPollInterval;
+ const newInterval = Math.min(interval * backoff, FIVE_MINUTES_IN_MS);
+ this.currentPollInterval = this.currentPollInterval
+ ? newInterval
+ : POLLING_INTERVAL_DEFAULT;
+ }
+ if (this.currentPollInterval === FIVE_MINUTES_IN_MS) {
+ this.$apollo.queries.forkDetailsQuery.stopPolling();
+ }
+ },
+ },
};
</script>
@@ -141,23 +258,45 @@ export default {
<div class="info-well gl-sm-display-flex gl-flex-direction-column">
<div class="well-segment gl-p-5 gl-w-full gl-display-flex">
<gl-icon name="fork" :size="16" class="gl-display-block gl-m-4 gl-text-center" />
- <div v-if="sourceName">
- {{ $options.i18n.forkedFrom }}
- <gl-link data-qa-selector="forked_from_link" :href="sourcePath">{{ sourceName }}</gl-link>
- <gl-skeleton-loader v-if="isLoading" :lines="1" />
- <div v-else class="gl-text-secondary" data-testid="divergence-message">
- <gl-sprintf :message="forkDivergenceMessage">
- <template #aheadLink="{ content }">
- <gl-link :href="aheadComparePath">{{ content }}</gl-link>
- </template>
- <template #behindLink="{ content }">
- <gl-link :href="behindComparePath">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
+ <div
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-flex-grow-1"
+ >
+ <div v-if="sourceName">
+ {{ $options.i18n.forkedFrom }}
+ <gl-link data-qa-selector="forked_from_link" :href="sourcePath">{{ sourceName }}</gl-link>
+ <gl-skeleton-loader v-if="isLoading" :lines="1" />
+ <div v-else class="gl-text-secondary" data-testid="divergence-message">
+ <gl-sprintf :message="forkDivergenceMessage">
+ <template #aheadLink="{ content }">
+ <gl-link :href="aheadComparePath">{{ content }}</gl-link>
+ </template>
+ <template #behindLink="{ content }">
+ <gl-link :href="behindComparePath">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
</div>
- </div>
- <div v-else data-testid="inaccessible-project" class="gl-align-items-center gl-display-flex">
- {{ $options.i18n.inaccessibleProject }}
+ <div
+ v-else
+ data-testid="inaccessible-project"
+ class="gl-align-items-center gl-display-flex"
+ >
+ {{ $options.i18n.inaccessibleProject }}
+ </div>
+ <gl-button
+ v-if="isSyncButtonAvailable"
+ :disabled="forkDetails.isSyncing"
+ @click="checkIfSyncIsPossible"
+ >
+ <gl-loading-icon v-if="forkDetails.isSyncing" class="gl-display-inline" size="sm" />
+ <span>{{ $options.i18n.sync }}</span>
+ </gl-button>
+ <conflicts-modal
+ ref="modal"
+ :source-name="sourceName"
+ :source-path="sourcePath"
+ :source-default-branch="sourceDefaultBranch"
+ />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/repository/components/fork_sync_conflicts_modal.vue b/app/assets/javascripts/repository/components/fork_sync_conflicts_modal.vue
new file mode 100644
index 00000000000..0bfb90bb3ec
--- /dev/null
+++ b/app/assets/javascripts/repository/components/fork_sync_conflicts_modal.vue
@@ -0,0 +1,137 @@
+<script>
+/* eslint-disable @gitlab/require-i18n-strings */
+import { GlModal, GlButton } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { getBaseURL } from '~/lib/utils/url_utility';
+
+export const i18n = {
+ modalTitle: s__('ForksDivergence|Resolve merge conflicts manually'),
+ modalMessage: s__(
+ '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:',
+ ),
+ step1: __('Step 1.'),
+ step2: __('Step 2.'),
+ step3: __('Step 3.'),
+ step4: __('Step 4.'),
+ step1Text: s__(
+ "ForksDivergence|Fetch the latest changes from the upstream repository's default branch:",
+ ),
+ step2Text: s__(
+ "ForksDivergence|Check out to a new branch, and merge the changes from the upstream project's default branch. You likely need to resolve conflicts during this step.",
+ ),
+ step3Text: s__('ForksDivergence|Push the updates to remote:'),
+ step4Text: s__("ForksDivergence|Create a merge request to your project's default branch."),
+ copyToClipboard: __('Copy to clipboard'),
+ close: __('Close'),
+};
+
+export default {
+ name: 'ForkSyncConflictsModal',
+ components: {
+ GlModal,
+ GlButton,
+ ModalCopyButton,
+ },
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ sourceDefaultBranch: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ sourceName: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ sourcePath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ instructionsStep1() {
+ const baseUrl = getBaseURL();
+ return `git fetch ${baseUrl}${this.sourcePath} ${this.sourceDefaultBranch}`;
+ },
+ },
+ methods: {
+ show() {
+ this.$refs.modal.show();
+ },
+ hide() {
+ this.$refs.modal.hide();
+ },
+ },
+ i18n,
+ instructionsStep2: 'git checkout -b &lt;new-branch-name&gt;\ngit merge FETCH_HEAD',
+ instructionsStep2Clipboard: 'git checkout -b <new-branch-name>\ngit merge FETCH_HEAD',
+ instructionsStep3: 'git commit\ngit push',
+};
+</script>
+<template>
+ <gl-modal
+ ref="modal"
+ modal-id="fork-sync-conflicts-modal"
+ :title="$options.i18n.modalTitle"
+ size="md"
+ >
+ <p>{{ $options.i18n.modalMessage }}</p>
+ <p>
+ <b> {{ $options.i18n.step1 }}</b> {{ $options.i18n.modalMessage }}
+ </p>
+ <div class="gl-display-flex gl-mb-4">
+ <pre class="gl-w-full gl-mb-0 gl-mr-3" data-testid="resolve-conflict-instructions">{{
+ instructionsStep1
+ }}</pre>
+ <modal-copy-button
+ modal-id="fork-sync-conflicts-modal"
+ :text="instructionsStep1"
+ :title="$options.i18n.copyToClipboard"
+ class="gl-shadow-none! gl-bg-transparent! gl-flex-shrink-0"
+ />
+ </div>
+ <p>
+ <b> {{ $options.i18n.step2 }}</b> {{ $options.i18n.step2Text }}
+ </p>
+ <div class="gl-display-flex gl-mb-4">
+ <pre
+ class="gl-w-full gl-mb-0 gl-mr-3"
+ data-testid="resolve-conflict-instructions"
+ v-html="$options.instructionsStep2 /* eslint-disable-line vue/no-v-html */"
+ ></pre>
+ <modal-copy-button
+ modal-id="fork-sync-conflicts-modal"
+ :text="$options.instructionsStep2Clipboard"
+ :title="$options.i18n.copyToClipboard"
+ class="gl-shadow-none! gl-bg-transparent! gl-flex-shrink-0"
+ />
+ </div>
+ <p>
+ <b> {{ $options.i18n.step3 }}</b> {{ $options.i18n.step3Text }}
+ </p>
+ <div class="gl-display-flex gl-mb-4">
+ <pre class="gl-w-full gl-mb-0" data-testid="resolve-conflict-instructions"
+ >{{ $options.instructionsStep3 }}
+</pre
+ >
+ <modal-copy-button
+ modal-id="fork-sync-conflicts-modal"
+ :text="$options.instructionsStep3"
+ :title="$options.i18n.copyToClipboard"
+ class="gl-shadow-none! gl-bg-transparent! gl-flex-shrink-0 gl-ml-3"
+ />
+ </div>
+ <p>
+ <b> {{ $options.i18n.step4 }}</b> {{ $options.i18n.step4Text }}
+ </p>
+ <template #modal-footer>
+ <gl-button @click="hide" @keydown.esc="hide">{{ $options.i18n.close }}</gl-button>
+ </template>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue
index 4d3c1521559..2d2e21dfd92 100644
--- a/app/assets/javascripts/repository/components/last_commit.vue
+++ b/app/assets/javascripts/repository/components/last_commit.vue
@@ -9,6 +9,7 @@ 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';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
+import SignatureBadge from '~/commit/components/signature_badge.vue';
import getRefMixin from '../mixins/get_ref';
import projectPathQuery from '../queries/project_path.query.graphql';
@@ -23,6 +24,7 @@ export default {
GlLink,
GlLoadingIcon,
UserAvatarImage,
+ SignatureBadge,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -170,10 +172,7 @@ export default {
<div
class="commit-actions gl-display-flex gl-flex-align gl-align-items-center gl-flex-direction-row"
>
- <div
- v-if="commit.signatureHtml"
- v-html="commit.signatureHtml /* eslint-disable-line vue/no-v-html */"
- ></div>
+ <signature-badge v-if="commit.signature" :signature="commit.signature" />
<div v-if="commit.pipeline" class="ci-status-link">
<gl-link
v-gl-tooltip.left
diff --git a/app/assets/javascripts/repository/components/new_directory_modal.vue b/app/assets/javascripts/repository/components/new_directory_modal.vue
index b28ebe7bb1e..f36a700c902 100644
--- a/app/assets/javascripts/repository/components/new_directory_modal.vue
+++ b/app/assets/javascripts/repository/components/new_directory_modal.vue
@@ -8,7 +8,7 @@ import {
GlFormTextarea,
GlToggle,
} from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -93,23 +93,19 @@ export default {
primaryOptions() {
return {
text: this.primaryBtnText,
- attributes: [
- {
- variant: 'confirm',
- loading: this.loading,
- disabled: !this.formCompleted || this.loading,
- },
- ],
+ attributes: {
+ variant: 'confirm',
+ loading: this.loading,
+ disabled: !this.formCompleted || this.loading,
+ },
};
},
cancelOptions() {
return {
text: SECONDARY_OPTIONS_TEXT,
- attributes: [
- {
- disabled: this.loading,
- },
- ],
+ attributes: {
+ disabled: this.loading,
+ },
};
},
showCreateNewMrToggle() {
diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue
index f6d6004ba96..0c9b46344c5 100644
--- a/app/assets/javascripts/repository/components/tree_content.vue
+++ b/app/assets/javascripts/repository/components/tree_content.vue
@@ -1,10 +1,8 @@
<script>
import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql';
-import { createAlert } from '~/flash';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { createAlert } from '~/alert';
import {
TREE_PAGE_SIZE,
- TREE_INITIAL_FETCH_COUNT,
TREE_PAGE_LIMIT,
COMMIT_BATCH_SIZE,
GITALY_UNAVAILABLE_CODE,
@@ -23,7 +21,7 @@ export default {
FileTable,
FilePreview,
},
- mixins: [getRefMixin, glFeatureFlagMixin()],
+ mixins: [getRefMixin],
apollo: {
projectPath: {
query: projectPathQuery,
@@ -59,13 +57,6 @@ export default {
};
},
computed: {
- pageSize() {
- // we want to exponentially increase the page size to reduce the load on the frontend
- const exponentialSize = (TREE_PAGE_SIZE / TREE_INITIAL_FETCH_COUNT) * (this.fetchCounter + 1);
- return exponentialSize < TREE_PAGE_SIZE && this.glFeatures.increasePageSizeExponentially
- ? exponentialSize
- : TREE_PAGE_SIZE;
- },
totalEntries() {
return Object.values(this.entries).flat().length;
},
@@ -110,7 +101,7 @@ export default {
ref: this.ref,
path: originalPath,
nextPageCursor: this.nextPageCursor,
- pageSize: this.pageSize,
+ pageSize: TREE_PAGE_SIZE,
},
})
.then(({ data }) => {
diff --git a/app/assets/javascripts/repository/components/upload_blob_modal.vue b/app/assets/javascripts/repository/components/upload_blob_modal.vue
index 4603ea2710d..4ca625bc0de 100644
--- a/app/assets/javascripts/repository/components/upload_blob_modal.vue
+++ b/app/assets/javascripts/repository/components/upload_blob_modal.vue
@@ -9,7 +9,7 @@ import {
GlButton,
GlAlert,
} from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { ContentTypeMultipartFormData } from '~/lib/utils/headers';
import { numberToHumanSize } from '~/lib/utils/number_utils';
@@ -106,23 +106,19 @@ export default {
primaryOptions() {
return {
text: this.primaryBtnText,
- attributes: [
- {
- variant: 'confirm',
- loading: this.loading,
- disabled: !this.formCompleted || this.loading,
- },
- ],
+ attributes: {
+ variant: 'confirm',
+ loading: this.loading,
+ disabled: !this.formCompleted || this.loading,
+ },
};
},
cancelOptions() {
return {
text: SECONDARY_OPTIONS_TEXT,
- attributes: [
- {
- disabled: this.loading,
- },
- ],
+ attributes: {
+ disabled: this.loading,
+ },
};
},
formattedFileSize() {
diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js
index 5098053c4f7..a6191203b2f 100644
--- a/app/assets/javascripts/repository/constants.js
+++ b/app/assets/javascripts/repository/constants.js
@@ -3,7 +3,6 @@ import { __ } from '~/locale';
export const GITALY_UNAVAILABLE_CODE = 'unavailable';
export const TREE_PAGE_LIMIT = 1000; // the maximum amount of items per page
export const TREE_PAGE_SIZE = 100; // the amount of items to be fetched per (batch) request
-export const TREE_INITIAL_FETCH_COUNT = TREE_PAGE_LIMIT / TREE_PAGE_SIZE; // the amount of (batch) requests to make
export const COMMIT_BATCH_SIZE = 25; // we request commit data in batches of 25
@@ -106,3 +105,10 @@ export const i18n = {
generalError: __('An error occurred while fetching folder content.'),
gitalyError: __('Error: Gitaly is unavailable. Contact your administrator.'),
};
+
+export const FIVE_MINUTES_IN_MS = 1000 * 60 * 5;
+
+export const POLLING_INTERVAL_DEFAULT = 2500;
+export const POLLING_INTERVAL_BACKOFF = 2;
+
+export const CONFLICTS_MODAL_ID = 'fork-sync-conflicts-modal';
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
index 494e270a66c..6cedc606a37 100644
--- a/app/assets/javascripts/repository/index.js
+++ b/app/assets/javascripts/repository/index.js
@@ -69,7 +69,13 @@ export default function setupVueRepositoryList() {
if (!forkEl) {
return null;
}
- const { sourceName, sourcePath, aheadComparePath, behindComparePath } = forkEl.dataset;
+ const {
+ sourceName,
+ sourcePath,
+ sourceDefaultBranch,
+ aheadComparePath,
+ behindComparePath,
+ } = forkEl.dataset;
return new Vue({
el: forkEl,
apolloProvider,
@@ -80,6 +86,7 @@ export default function setupVueRepositoryList() {
selectedBranch: ref,
sourceName,
sourcePath,
+ sourceDefaultBranch,
aheadComparePath,
behindComparePath,
},
diff --git a/app/assets/javascripts/repository/mutations/sync_fork.mutation.graphql b/app/assets/javascripts/repository/mutations/sync_fork.mutation.graphql
new file mode 100644
index 00000000000..b3426038694
--- /dev/null
+++ b/app/assets/javascripts/repository/mutations/sync_fork.mutation.graphql
@@ -0,0 +1,11 @@
+mutation syncFork($projectPath: ID!, $targetBranch: String!) {
+ projectSyncFork(input: { projectPath: $projectPath, targetBranch: $targetBranch }) {
+ details {
+ ahead
+ behind
+ isSyncing
+ hasConflicts
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/repository/queries/fork_details.query.graphql b/app/assets/javascripts/repository/queries/fork_details.query.graphql
index d1a37d00d55..3d37f69b48d 100644
--- a/app/assets/javascripts/repository/queries/fork_details.query.graphql
+++ b/app/assets/javascripts/repository/queries/fork_details.query.graphql
@@ -4,6 +4,8 @@ query getForkDetails($projectPath: ID!, $ref: String) {
forkDetails(ref: $ref) {
ahead
behind
+ isSyncing
+ hasConflicts
}
}
}
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 3256e13f4da..297b8ae1fc2 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -70,7 +70,7 @@ Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
const $expandIcon = $('.js-sidebar-expand');
const $toggleContainer = $('.js-sidebar-toggle-container');
const isExpanded = $toggleContainer.data('is-expanded');
- const tooltipLabel = isExpanded ? __('Expand sidebar') : __('Collapse sidebar');
+ const tooltipLabel = isExpanded ? __('Collapse sidebar') : __('Expand sidebar');
e.preventDefault();
if (isExpanded) {
diff --git a/app/assets/javascripts/saved_replies/components/app.vue b/app/assets/javascripts/saved_replies/components/app.vue
index db8476c44f3..e4b481f0908 100644
--- a/app/assets/javascripts/saved_replies/components/app.vue
+++ b/app/assets/javascripts/saved_replies/components/app.vue
@@ -17,7 +17,7 @@ export default {};
</p>
</div>
<div class="col-lg-8">
- <router-view />
+ <keep-alive><router-view /></keep-alive>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/saved_replies/components/form.vue b/app/assets/javascripts/saved_replies/components/form.vue
new file mode 100644
index 00000000000..efec9b96764
--- /dev/null
+++ b/app/assets/javascripts/saved_replies/components/form.vue
@@ -0,0 +1,182 @@
+<script>
+import { GlButton, GlForm, GlFormGroup, GlFormInput, GlAlert } from '@gitlab/ui';
+import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { logError } from '~/lib/logger';
+import { __ } from '~/locale';
+import createSavedReplyMutation from '../queries/create_saved_reply.mutation.graphql';
+import updateSavedReplyMutation from '../queries/update_saved_reply.mutation.graphql';
+
+export default {
+ components: {
+ GlButton,
+ GlForm,
+ GlFormGroup,
+ GlFormInput,
+ GlAlert,
+ MarkdownField,
+ },
+ props: {
+ id: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ name: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ content: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ errors: [],
+ saving: false,
+ showValidation: false,
+ updateSavedReply: {
+ name: this.name,
+ content: this.content,
+ },
+ };
+ },
+ computed: {
+ isNameValid() {
+ if (this.showValidation) return Boolean(this.updateSavedReply.name);
+
+ return true;
+ },
+ isContentValid() {
+ if (this.showValidation) return Boolean(this.updateSavedReply.content);
+
+ return true;
+ },
+ isValid() {
+ return this.isNameValid && this.isContentValid;
+ },
+ },
+ methods: {
+ onSubmit() {
+ this.showValidation = true;
+
+ if (!this.isValid) return;
+
+ this.errors = [];
+ this.saving = true;
+
+ this.$apollo
+ .mutate({
+ mutation: this.id ? updateSavedReplyMutation : createSavedReplyMutation,
+ variables: {
+ id: this.id,
+ name: this.updateSavedReply.name,
+ content: this.updateSavedReply.content,
+ },
+ update: (store, { data: { savedReplyMutation } }) => {
+ if (savedReplyMutation.errors.length) {
+ this.errors = savedReplyMutation.errors.map((e) => e);
+ } else {
+ this.$emit('saved');
+ this.updateSavedReply = { name: '', content: '' };
+ this.showValidation = false;
+ }
+ },
+ })
+ .catch((error) => {
+ const errors = error.graphQLErrors;
+
+ if (errors?.length) {
+ this.errors = errors.map((e) => e.message);
+ } else {
+ // Let's be sure to log the original error so it isn't just swallowed.
+ // Also, we don't want to translate console messages.
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ logError('Unexpected error while saving reply', error);
+
+ this.errors = [__('An unexpected error occurred. Please try again.')];
+ }
+ })
+ .finally(() => {
+ this.saving = false;
+ });
+ },
+ },
+ restrictedToolbarItems: ['full-screen'],
+ markdownDocsPath: helpPagePath('user/markdown'),
+};
+</script>
+
+<template>
+ <gl-form
+ class="new-note common-note-form"
+ data-testid="saved-reply-form"
+ @submit.prevent="onSubmit"
+ >
+ <gl-alert
+ v-for="error in errors"
+ :key="error"
+ variant="danger"
+ class="gl-mb-3"
+ :dismissible="false"
+ >
+ {{ error }}
+ </gl-alert>
+ <gl-form-group
+ :label="__('Name')"
+ :state="isNameValid"
+ :invalid-feedback="__('Please enter a name for the saved reply.')"
+ data-testid="saved-reply-name-form-group"
+ >
+ <gl-form-input
+ v-model="updateSavedReply.name"
+ :placeholder="__('Enter a name for your saved reply')"
+ data-testid="saved-reply-name-input"
+ />
+ </gl-form-group>
+ <gl-form-group
+ :label="__('Content')"
+ :state="isContentValid"
+ :invalid-feedback="__('Please enter the saved reply content.')"
+ data-testid="saved-reply-content-form-group"
+ >
+ <markdown-field
+ :enable-preview="false"
+ :is-submitting="saving"
+ :add-spacing-classes="false"
+ :textarea-value="updateSavedReply.content"
+ :markdown-docs-path="$options.markdownDocsPath"
+ :restricted-tool-bar-items="$options.restrictedToolbarItems"
+ :force-autosize="false"
+ class="js-no-autosize gl-border-gray-400!"
+ >
+ <template #textarea>
+ <textarea
+ v-model="updateSavedReply.content"
+ dir="auto"
+ class="note-textarea js-gfm-input js-autosize markdown-area"
+ data-supports-quick-actions="false"
+ :aria-label="__('Content')"
+ :placeholder="__('Write saved reply content here…')"
+ data-testid="saved-reply-content-input"
+ @keydown.meta.enter="onSubmit"
+ @keydown.ctrl.enter="onSubmit"
+ ></textarea>
+ </template>
+ </markdown-field>
+ </gl-form-group>
+ <gl-button
+ variant="confirm"
+ class="gl-mr-3 js-no-auto-disable"
+ type="submit"
+ :loading="saving"
+ data-testid="saved-reply-form-submit-btn"
+ >
+ {{ __('Save') }}
+ </gl-button>
+ <gl-button v-if="id" :to="{ path: '/' }">{{ __('Cancel') }}</gl-button>
+ </gl-form>
+</template>
diff --git a/app/assets/javascripts/saved_replies/components/list.vue b/app/assets/javascripts/saved_replies/components/list.vue
index 30089cfa53f..dbe326d429a 100644
--- a/app/assets/javascripts/saved_replies/components/list.vue
+++ b/app/assets/javascripts/saved_replies/components/list.vue
@@ -1,43 +1,51 @@
<script>
import { GlKeysetPagination, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
-import savedRepliesQuery from '../queries/saved_replies.query.graphql';
import ListItem from './list_item.vue';
export default {
- apollo: {
- savedReplies: {
- query: savedRepliesQuery,
- update: (r) => r.currentUser?.savedReplies?.nodes,
- result({ data }) {
- const pageInfo = data.currentUser?.savedReplies?.pageInfo;
-
- this.count = data.currentUser?.savedReplies?.count;
-
- if (pageInfo) {
- this.pageInfo = pageInfo;
- }
- },
- },
- },
components: {
GlLoadingIcon,
GlKeysetPagination,
GlSprintf,
ListItem,
},
- data() {
- return {
- savedReplies: [],
- count: 0,
- pageInfo: {},
- };
+ props: {
+ loading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ savedReplies: {
+ type: Array,
+ required: true,
+ },
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
+ count: {
+ type: Number,
+ required: true,
+ },
+ },
+ methods: {
+ prevPage() {
+ this.$emit('input', {
+ before: this.pageInfo.beforeCursor,
+ });
+ },
+ nextPage() {
+ this.$emit('input', {
+ after: this.pageInfo.endCursor,
+ });
+ },
},
};
</script>
<template>
<div>
- <gl-loading-icon v-if="$apollo.queries.savedReplies.loading" size="lg" />
+ <gl-loading-icon v-if="loading" size="lg" />
<template v-else>
<h5 class="gl-font-lg" data-testid="title">
<gl-sprintf :message="__('My saved replies (%{count})')">
@@ -51,6 +59,8 @@ export default {
v-if="pageInfo.hasPreviousPage || pageInfo.hasNextPage"
v-bind="pageInfo"
class="gl-mt-4"
+ @prev="prevPage"
+ @next="nextPage"
/>
</template>
</div>
diff --git a/app/assets/javascripts/saved_replies/components/list_item.vue b/app/assets/javascripts/saved_replies/components/list_item.vue
index dfa9a405dee..3ad5642afc7 100644
--- a/app/assets/javascripts/saved_replies/components/list_item.vue
+++ b/app/assets/javascripts/saved_replies/components/list_item.vue
@@ -1,19 +1,101 @@
<script>
+import { uniqueId } from 'lodash';
+import { GlButton, GlModal, GlModalDirective, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import deleteSavedReplyMutation from '../queries/delete_saved_reply.mutation.graphql';
+
export default {
+ components: {
+ GlButton,
+ GlModal,
+ GlSprintf,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ GlTooltip: GlTooltipDirective,
+ },
props: {
reply: {
type: Object,
required: true,
},
},
+ data() {
+ return {
+ isDeleting: false,
+ modalId: uniqueId('delete-saved-reply-'),
+ };
+ },
+ computed: {
+ id() {
+ return getIdFromGraphQLId(this.reply.id);
+ },
+ },
+ methods: {
+ onDelete() {
+ this.isDeleting = true;
+
+ this.$apollo.mutate({
+ mutation: deleteSavedReplyMutation,
+ variables: {
+ id: this.reply.id,
+ },
+ update: (cache) => {
+ const cacheId = cache.identify(this.reply);
+ cache.evict({ id: cacheId });
+ },
+ });
+ },
+ },
+ actionPrimary: { text: __('Delete'), attributes: { variant: 'danger' } },
+ actionSecondary: { text: __('Cancel'), attributes: { variant: 'default' } },
};
</script>
<template>
<li class="gl-mb-5">
<div class="gl-display-flex gl-align-items-center">
- <strong>{{ reply.name }}</strong>
+ <strong data-testid="saved-reply-name">{{ reply.name }}</strong>
+ <div class="gl-ml-auto">
+ <gl-button
+ v-gl-tooltip
+ :to="{ name: 'edit', params: { id: id } }"
+ icon="pencil"
+ :title="__('Edit')"
+ :aria-label="__('Edit')"
+ class="gl-mr-3"
+ data-testid="saved-reply-edit-btn"
+ />
+ <gl-button
+ v-gl-modal="modalId"
+ v-gl-tooltip
+ icon="remove"
+ :aria-label="__('Delete')"
+ :title="__('Delete')"
+ variant="danger"
+ category="secondary"
+ data-testid="saved-reply-delete-btn"
+ :loading="isDeleting"
+ />
+ </div>
</div>
<div class="gl-mt-3 gl-font-monospace">{{ reply.content }}</div>
+ <gl-modal
+ :title="__('Delete saved reply')"
+ :action-primary="$options.actionPrimary"
+ :action-secondary="$options.actionSecondary"
+ :modal-id="modalId"
+ size="sm"
+ @primary="onDelete"
+ >
+ <gl-sprintf
+ :message="__('Are you sure you want to delete %{name}? This action cannot be undone.')"
+ >
+ <template #name
+ ><strong>{{ reply.name }}</strong></template
+ >
+ </gl-sprintf>
+ </gl-modal>
</li>
</template>
diff --git a/app/assets/javascripts/saved_replies/pages/edit.vue b/app/assets/javascripts/saved_replies/pages/edit.vue
new file mode 100644
index 00000000000..94215389844
--- /dev/null
+++ b/app/assets/javascripts/saved_replies/pages/edit.vue
@@ -0,0 +1,68 @@
+<script>
+import { GlLoadingIcon } from '@gitlab/ui';
+import { fetchPolicies } from '~/lib/graphql';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { TYPE_USERS_SAVED_REPLY } from '~/graphql_shared/constants';
+import CreateForm from '../components/form.vue';
+import getSavedReply from '../queries/get_saved_reply.query.graphql';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ CreateForm,
+ },
+ apollo: {
+ savedReply: {
+ fetchPolicy: fetchPolicies.NETWORK_ONLY,
+ query: getSavedReply,
+ variables() {
+ return {
+ id: convertToGraphQLId(TYPE_USERS_SAVED_REPLY, this.$route.params.id),
+ };
+ },
+ update: (r) => r.currentUser.savedReply,
+ skip() {
+ return !this.$route.params.id;
+ },
+ result({
+ data: {
+ currentUser: { savedReply },
+ },
+ }) {
+ if (!savedReply) {
+ createAlert({ message: __('Unable to find saved reply') });
+ this.redirectToRoot();
+ }
+ },
+ },
+ },
+ data() {
+ return {
+ savedReply: null,
+ };
+ },
+ methods: {
+ redirectToRoot() {
+ this.$router.push({ path: '/' });
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <h5 class="gl-mt-0 gl-font-lg">
+ {{ __('Edit saved reply') }}
+ </h5>
+ <gl-loading-icon v-if="$apollo.queries.savedReply.loading" size="lg" />
+ <create-form
+ v-else-if="savedReply"
+ :id="savedReply.id"
+ :name="savedReply.name"
+ :content="savedReply.content"
+ @saved="redirectToRoot"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/saved_replies/pages/index.vue b/app/assets/javascripts/saved_replies/pages/index.vue
index 38f51dbc365..3e96fc0714e 100644
--- a/app/assets/javascripts/saved_replies/pages/index.vue
+++ b/app/assets/javascripts/saved_replies/pages/index.vue
@@ -1,15 +1,67 @@
<script>
+import { fetchPolicies } from '~/lib/graphql';
+import CreateForm from '../components/form.vue';
+import savedRepliesQuery from '../queries/saved_replies.query.graphql';
import List from '../components/list.vue';
export default {
+ apollo: {
+ savedReplies: {
+ fetchPolicy: fetchPolicies.NETWORK_ONLY,
+ query: savedRepliesQuery,
+ update: (r) => r.currentUser?.savedReplies?.nodes,
+ variables() {
+ return {
+ ...this.pagination,
+ };
+ },
+ result({ data }) {
+ const pageInfo = data.currentUser?.savedReplies?.pageInfo;
+
+ this.count = data.currentUser?.savedReplies?.count;
+
+ if (pageInfo) {
+ this.pageInfo = pageInfo;
+ }
+ },
+ },
+ },
components: {
+ CreateForm,
List,
},
+ data() {
+ return {
+ savedReplies: [],
+ count: 0,
+ pageInfo: {},
+ pagination: {},
+ };
+ },
+ methods: {
+ refetchSavedReplies() {
+ this.pagination = {};
+ this.$apollo.queries.savedReplies.refetch();
+ },
+ changePage(pageInfo) {
+ this.pagination = pageInfo;
+ },
+ },
};
</script>
<template>
<div>
- <list />
+ <h5 class="gl-mt-0 gl-font-lg">
+ {{ __('Add new saved reply') }}
+ </h5>
+ <create-form @saved="refetchSavedReplies" />
+ <list
+ :loading="$apollo.queries.savedReplies.loading"
+ :saved-replies="savedReplies"
+ :page-info="pageInfo"
+ :count="count"
+ @input="changePage"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/saved_replies/queries/create_saved_reply.mutation.graphql b/app/assets/javascripts/saved_replies/queries/create_saved_reply.mutation.graphql
new file mode 100644
index 00000000000..c4e632d0f16
--- /dev/null
+++ b/app/assets/javascripts/saved_replies/queries/create_saved_reply.mutation.graphql
@@ -0,0 +1,10 @@
+mutation savedReplyCreate($name: String!, $content: String!) {
+ savedReplyMutation: savedReplyCreate(input: { name: $name, content: $content }) {
+ errors
+ savedReply {
+ id
+ name
+ content
+ }
+ }
+}
diff --git a/app/assets/javascripts/saved_replies/queries/delete_saved_reply.mutation.graphql b/app/assets/javascripts/saved_replies/queries/delete_saved_reply.mutation.graphql
new file mode 100644
index 00000000000..76571ba628c
--- /dev/null
+++ b/app/assets/javascripts/saved_replies/queries/delete_saved_reply.mutation.graphql
@@ -0,0 +1,5 @@
+mutation deleteSavedReply($id: UsersSavedReplyID!) {
+ savedReplyDestroy(input: { id: $id }) {
+ errors
+ }
+}
diff --git a/app/assets/javascripts/saved_replies/queries/get_saved_reply.query.graphql b/app/assets/javascripts/saved_replies/queries/get_saved_reply.query.graphql
new file mode 100644
index 00000000000..66f5f43af49
--- /dev/null
+++ b/app/assets/javascripts/saved_replies/queries/get_saved_reply.query.graphql
@@ -0,0 +1,10 @@
+query getSavedReply($id: UsersSavedReplyID!) {
+ currentUser {
+ id
+ savedReply(id: $id) {
+ id
+ name
+ content
+ }
+ }
+}
diff --git a/app/assets/javascripts/saved_replies/queries/saved_replies.query.graphql b/app/assets/javascripts/saved_replies/queries/saved_replies.query.graphql
index af1f12f3ceb..d8e76b5e2a8 100644
--- a/app/assets/javascripts/saved_replies/queries/saved_replies.query.graphql
+++ b/app/assets/javascripts/saved_replies/queries/saved_replies.query.graphql
@@ -1,7 +1,7 @@
-query savedReplies {
+query savedReplies($after: String = "", $before: String = "") {
currentUser {
id
- savedReplies {
+ savedReplies(after: $after, before: $before) {
nodes {
id
name
diff --git a/app/assets/javascripts/saved_replies/queries/update_saved_reply.mutation.graphql b/app/assets/javascripts/saved_replies/queries/update_saved_reply.mutation.graphql
new file mode 100644
index 00000000000..14a47d7bc9c
--- /dev/null
+++ b/app/assets/javascripts/saved_replies/queries/update_saved_reply.mutation.graphql
@@ -0,0 +1,10 @@
+mutation savedReplyUpdate($id: UsersSavedReplyID!, $name: String!, $content: String!) {
+ savedReplyMutation: savedReplyUpdate(input: { id: $id, name: $name, content: $content }) {
+ errors
+ savedReply {
+ id
+ name
+ content
+ }
+ }
+}
diff --git a/app/assets/javascripts/saved_replies/routes.js b/app/assets/javascripts/saved_replies/routes.js
index bd582a5ed86..7687c6f335a 100644
--- a/app/assets/javascripts/saved_replies/routes.js
+++ b/app/assets/javascripts/saved_replies/routes.js
@@ -1,8 +1,15 @@
import IndexComponent from './pages/index.vue';
+import EditComponent from './pages/edit.vue';
+
export default [
{
path: '/',
component: IndexComponent,
},
+ {
+ name: 'edit',
+ path: '/:id',
+ component: EditComponent,
+ },
];
diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue
index 2efc80fef75..60de63c7d7a 100644
--- a/app/assets/javascripts/search/sidebar/components/app.vue
+++ b/app/assets/javascripts/search/sidebar/components/app.vue
@@ -1,5 +1,5 @@
<script>
-import { mapState } from 'vuex';
+import { mapState, mapGetters } from 'vuex';
import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { SCOPE_ISSUES, SCOPE_MERGE_REQUESTS, SCOPE_BLOB } from '../constants';
@@ -16,18 +16,21 @@ export default {
mixins: [glFeatureFlagsMixin()],
computed: {
...mapState(['urlQuery']),
+ ...mapGetters(['currentScope']),
showIssueAndMergeFilters() {
- return this.urlQuery.scope === SCOPE_ISSUES || this.urlQuery.scope === SCOPE_MERGE_REQUESTS;
+ return this.currentScope === SCOPE_ISSUES || this.currentScope === SCOPE_MERGE_REQUESTS;
},
showBlobFilter() {
- return this.urlQuery.scope === SCOPE_BLOB && this.glFeatures.searchBlobsLanguageAggregation;
+ return this.currentScope === SCOPE_BLOB;
},
},
};
</script>
<template>
- <section class="search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4 gl-mb-6 gl-mt-5">
+ <section
+ class="search-sidebar gl-display-flex gl-flex-direction-column gl-md-mr-5 gl-mb-6 gl-mt-5"
+ >
<scope-navigation />
<results-filters v-if="showIssueAndMergeFilters" />
<language-filter v-if="showBlobFilter" />
diff --git a/app/assets/javascripts/search/sidebar/components/checkbox_filter.vue b/app/assets/javascripts/search/sidebar/components/checkbox_filter.vue
index b580d58b21b..f7873a994aa 100644
--- a/app/assets/javascripts/search/sidebar/components/checkbox_filter.vue
+++ b/app/assets/javascripts/search/sidebar/components/checkbox_filter.vue
@@ -1,6 +1,6 @@
<script>
import { GlFormCheckboxGroup, GlFormCheckbox } from '@gitlab/ui';
-import { mapState, mapActions } from 'vuex';
+import { mapState, mapActions, mapGetters } from 'vuex';
import { intersection } from 'lodash';
import { NAV_LINK_COUNT_DEFAULT_CLASSES, LABEL_DEFAULT_CLASSES } from '../constants';
import { formatSearchResultCount } from '../../store/utils';
@@ -12,31 +12,26 @@ export default {
GlFormCheckbox,
},
props: {
- filterData: {
+ filtersData: {
type: Object,
required: true,
},
},
computed: {
...mapState(['query']),
- scope() {
- return this.query.scope;
- },
- queryFilters() {
- return this.query[this.filterData?.filterParam] || [];
- },
+ ...mapGetters(['queryLanguageFilters']),
dataFilters() {
- return Object.values(this.filterData?.filters || []);
+ return Object.values(this.filtersData?.filters || []);
},
flatDataFilterValues() {
return this.dataFilters.map(({ value }) => value);
},
selectedFilter: {
get() {
- return intersection(this.flatDataFilterValues, this.queryFilters);
+ return intersection(this.flatDataFilterValues, this.queryLanguageFilters);
},
set(value) {
- this.setQuery({ key: this.filterData?.filterParam, value });
+ this.setQuery({ key: this.filtersData?.filterParam, value });
},
},
labelCountClasses() {
@@ -56,7 +51,7 @@ export default {
<template>
<div class="gl-mx-5">
- <h5 class="gl-mt-0">{{ filterData.header }}</h5>
+ <h5 class="gl-mt-0">{{ filtersData.header }}</h5>
<gl-form-checkbox-group v-model="selectedFilter">
<gl-form-checkbox
v-for="f in dataFilters"
diff --git a/app/assets/javascripts/search/sidebar/components/language_filter.vue b/app/assets/javascripts/search/sidebar/components/language_filter.vue
index 26ce204cb5c..b2f8d3e1f5f 100644
--- a/app/assets/javascripts/search/sidebar/components/language_filter.vue
+++ b/app/assets/javascripts/search/sidebar/components/language_filter.vue
@@ -27,19 +27,24 @@ export default {
apply: __('Apply'),
showingMax: sprintf(s__('GlobalSearch|Showing top %{maxItems}'), { maxItems: MAX_ITEM_LENGTH }),
loadError: s__('GlobalSearch|Aggregations load error.'),
+ reset: s__('GlobalSearch|Reset filters'),
},
computed: {
...mapState(['aggregations', 'sidebarDirty']),
- ...mapGetters(['langugageAggregationBuckets']),
+ ...mapGetters([
+ 'languageAggregationBuckets',
+ 'currentUrlQueryHasLanguageFilters',
+ 'queryLanguageFilters',
+ ]),
hasBuckets() {
- return this.langugageAggregationBuckets.length > 0;
+ return this.languageAggregationBuckets.length > 0;
},
filtersData() {
return convertFiltersData(this.shortenedLanguageFilters);
},
shortenedLanguageFilters() {
if (!this.hasShowMore) {
- return this.langugageAggregationBuckets;
+ return this.languageAggregationBuckets;
}
if (this.showAll) {
return this.trimBuckets(MAX_ITEM_LENGTH);
@@ -47,25 +52,40 @@ export default {
return this.trimBuckets(DEFAULT_ITEM_LENGTH);
},
hasShowMore() {
- return this.langugageAggregationBuckets.length > DEFAULT_ITEM_LENGTH;
+ return this.languageAggregationBuckets.length > DEFAULT_ITEM_LENGTH;
},
hasOverMax() {
- return this.langugageAggregationBuckets.length > MAX_ITEM_LENGTH;
+ return this.languageAggregationBuckets.length > MAX_ITEM_LENGTH;
},
dividerClasses() {
return [...HR_DEFAULT_CLASSES, ...ONLY_SHOW_MD];
},
+ hasQueryFilters() {
+ return this.queryLanguageFilters.length > 0;
+ },
},
async created() {
await this.fetchLanguageAggregation();
},
methods: {
- ...mapActions(['applyQuery', 'fetchLanguageAggregation']),
+ ...mapActions([
+ 'applyQuery',
+ 'resetLanguageQuery',
+ 'resetLanguageQueryWithRedirect',
+ 'fetchLanguageAggregation',
+ ]),
onShowMore() {
this.showAll = true;
},
trimBuckets(length) {
- return this.langugageAggregationBuckets.slice(0, length);
+ return this.languageAggregationBuckets.slice(0, length);
+ },
+ cleanResetFilters() {
+ if (this.currentUrlQueryHasLanguageFilters) {
+ return this.resetLanguageQueryWithRedirect();
+ }
+ this.showAll = false;
+ return this.resetLanguageQuery();
},
},
HR_DEFAULT_CLASSES,
@@ -84,7 +104,7 @@ export default {
class="gl-overflow-x-hidden gl-overflow-y-auto"
:class="{ 'language-filter-max-height': showAll }"
>
- <checkbox-filter class="gl-px-5" :filter-data="filtersData" />
+ <checkbox-filter :filters-data="filtersData" />
<span v-if="showAll && hasOverMax" data-testid="has-over-max-text">{{
$options.i18n.showingMax
}}</span>
@@ -106,7 +126,9 @@ export default {
</div>
<div v-if="!aggregations.error">
<hr :class="$options.HR_DEFAULT_CLASSES" />
- <div class="gl-display-flex gl-align-items-center gl-mt-4 gl-mx-5 gl-px-5">
+ <div
+ class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-mt-4 gl-mx-5"
+ >
<gl-button
category="primary"
variant="confirm"
@@ -116,6 +138,16 @@ export default {
>
{{ $options.i18n.apply }}
</gl-button>
+ <gl-button
+ category="tertiary"
+ variant="link"
+ size="small"
+ :disabled="!hasQueryFilters && !sidebarDirty"
+ data-testid="reset-button"
+ @click="cleanResetFilters"
+ >
+ {{ $options.i18n.reset }}
+ </gl-button>
</div>
</div>
</gl-form>
diff --git a/app/assets/javascripts/search/sidebar/components/radio_filter.vue b/app/assets/javascripts/search/sidebar/components/radio_filter.vue
index aa7c26b8044..0733dc72d2e 100644
--- a/app/assets/javascripts/search/sidebar/components/radio_filter.vue
+++ b/app/assets/javascripts/search/sidebar/components/radio_filter.vue
@@ -1,6 +1,6 @@
<script>
import { GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
-import { mapState, mapActions } from 'vuex';
+import { mapState, mapActions, mapGetters } from 'vuex';
import { sprintf, __ } from '~/locale';
export default {
@@ -17,12 +17,10 @@ export default {
},
computed: {
...mapState(['query']),
+ ...mapGetters(['currentScope']),
ANY() {
return this.filterData.filters.ANY;
},
- scope() {
- return this.query.scope;
- },
initialFilter() {
return this.query[this.filterData.filterParam];
},
@@ -30,7 +28,7 @@ export default {
return this.initialFilter || this.ANY.value;
},
filtersArray() {
- return this.filterData.filterByScope[this.scope];
+ return this.filterData.filterByScope[this.currentScope];
},
selectedFilter: {
get() {
diff --git a/app/assets/javascripts/search/sidebar/components/results_filters.vue b/app/assets/javascripts/search/sidebar/components/results_filters.vue
index 4d9cc9d6450..7d995f26684 100644
--- a/app/assets/javascripts/search/sidebar/components/results_filters.vue
+++ b/app/assets/javascripts/search/sidebar/components/results_filters.vue
@@ -1,6 +1,6 @@
<script>
import { GlButton, GlLink } from '@gitlab/ui';
-import { mapActions, mapState } from 'vuex';
+import { mapActions, mapState, mapGetters } from 'vuex';
import { confidentialFilterData } from '../constants/confidential_filter_data';
import { stateFilterData } from '../constants/state_filter_data';
import ConfidentialityFilter from './confidentiality_filter.vue';
@@ -16,14 +16,15 @@ export default {
},
computed: {
...mapState(['urlQuery', 'sidebarDirty']),
+ ...mapGetters(['currentScope']),
showReset() {
return this.urlQuery.state || this.urlQuery.confidential;
},
showConfidentialityFilter() {
- return Object.values(confidentialFilterData.scopes).includes(this.urlQuery.scope);
+ return Object.values(confidentialFilterData.scopes).includes(this.currentScope);
},
showStatusFilter() {
- return Object.values(stateFilterData.scopes).includes(this.urlQuery.scope);
+ return Object.values(stateFilterData.scopes).includes(this.currentScope);
},
},
methods: {
diff --git a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
index 5863381e2ef..02a3870f499 100644
--- a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
+++ b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
@@ -44,9 +44,6 @@ export default {
isHighlighted ? 'gl-text-gray-900' : 'gl-text-gray-500',
];
},
- isActive(scope, index) {
- return this.urlQuery.scope ? this.urlQuery.scope === scope : index === 0;
- },
qaSelectorValue(item) {
return `${slugifyWithUnderscore(item.label)}_tab`;
},
@@ -60,16 +57,17 @@ export default {
<nav data-testid="search-filter">
<gl-nav vertical pills>
<gl-nav-item
- v-for="(item, scope, index) in navigation"
+ v-for="(item, scope) in navigation"
:key="scope"
- :link-classes="linkClasses(isActive(scope, index))"
+ :link-classes="linkClasses(item.active)"
class="gl-mb-1"
:href="item.link"
- :active="isActive(scope, index)"
+ :active="item.active"
:data-qa-selector="qaSelectorValue(item)"
+ :data-testid="qaSelectorValue(item)"
@click="handleClick(scope)"
- ><span>{{ item.label }}</span
- ><span v-if="item.count" :class="countClasses(isActive(scope, index))">
+ ><span data-testid="label">{{ item.label }}</span
+ ><span v-if="item.count" data-testid="count" :class="countClasses(item.active)">
{{ showFormatedCount(item.count)
}}<gl-icon
v-if="isCountOverLimit(item.count)"
diff --git a/app/assets/javascripts/search/sidebar/utils.js b/app/assets/javascripts/search/sidebar/utils.js
index 5c08ad2f959..4357d6202df 100644
--- a/app/assets/javascripts/search/sidebar/utils.js
+++ b/app/assets/javascripts/search/sidebar/utils.js
@@ -1,20 +1,17 @@
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
-export const convertFiltersData = (rawBuckets) => {
- return rawBuckets.reduce(
- (acc, bucket) => {
- return {
- ...acc,
- filters: {
- ...acc.filters,
- [bucket.key.toUpperCase()]: {
- label: bucket.key,
- value: bucket.key,
- count: bucket.count,
- },
+export const convertFiltersData = (rawBuckets) =>
+ rawBuckets.reduce(
+ (acc, bucket) => ({
+ ...acc,
+ filters: {
+ ...acc.filters,
+ [bucket.key.toUpperCase()]: {
+ label: bucket.key,
+ value: bucket.key,
+ count: bucket.count,
},
- };
- },
+ },
+ }),
{ ...languageFilterData, filters: {} },
);
-};
diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js
index fc0817be882..da2bf4b602e 100644
--- a/app/assets/javascripts/search/store/actions.js
+++ b/app/assets/javascripts/search/store/actions.js
@@ -1,9 +1,10 @@
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import { logError } from '~/lib/logger';
import { __ } from '~/locale';
+import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY, SIDEBAR_PARAMS } from './constants';
import * as types from './mutation_types';
import {
@@ -12,6 +13,7 @@ import {
mergeById,
isSidebarDirty,
getAggregationsUrl,
+ prepareSearchAggregations,
} from './utils';
export const fetchGroups = ({ commit }, search) => {
@@ -105,17 +107,27 @@ export const applyQuery = ({ state }) => {
};
export const resetQuery = ({ state }) => {
- visitUrl(setUrlParams({ ...state.query, page: null, state: null, confidential: null }));
+ visitUrl(
+ setUrlParams({ ...state.query, page: null, state: null, confidential: null }, undefined, true),
+ );
+};
+
+export const resetLanguageQueryWithRedirect = ({ state }) => {
+ visitUrl(setUrlParams({ ...state.query, language: null }, undefined, true));
+};
+
+export const resetLanguageQuery = ({ commit }) => {
+ commit(types.SET_QUERY, { key: languageFilterData?.filterParam, value: [] });
};
export const fetchSidebarCount = ({ commit, state }) => {
- const promises = Object.keys(state.navigation).map((scope) => {
+ const promises = Object.values(state.navigation).map((navItem) => {
// active nav item has count already so we skip it
- if (scope !== state.urlQuery.scope) {
+ if (!navItem.active) {
return axios
- .get(state.navigation[scope].count_link)
+ .get(navItem.count_link)
.then(({ data: { count } }) => {
- commit(types.RECEIVE_NAVIGATION_COUNT, { key: scope, count });
+ commit(types.RECEIVE_NAVIGATION_COUNT, { key: navItem.scope, count });
})
.catch((e) => logError(e));
}
@@ -124,12 +136,13 @@ export const fetchSidebarCount = ({ commit, state }) => {
return Promise.all(promises);
};
-export const fetchLanguageAggregation = ({ commit }) => {
+export const fetchLanguageAggregation = ({ commit, state }) => {
commit(types.REQUEST_AGGREGATIONS);
return axios
.get(getAggregationsUrl())
- .then(({ data }) => {
- commit(types.RECEIVE_AGGREGATIONS_SUCCESS, data);
+ .then((result) => {
+ const { data } = result;
+ commit(types.RECEIVE_AGGREGATIONS_SUCCESS, prepareSearchAggregations(state, data));
})
.catch((e) => {
logError(e);
diff --git a/app/assets/javascripts/search/store/getters.js b/app/assets/javascripts/search/store/getters.js
index 0278239c144..36d98233e28 100644
--- a/app/assets/javascripts/search/store/getters.js
+++ b/app/assets/javascripts/search/store/getters.js
@@ -1,4 +1,6 @@
+import { findKey, has } from 'lodash';
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
+
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants';
export const frequentGroups = (state) => {
@@ -9,10 +11,18 @@ export const frequentProjects = (state) => {
return state.frequentItems[PROJECTS_LOCAL_STORAGE_KEY];
};
-export const langugageAggregationBuckets = (state) => {
+export const languageAggregationBuckets = (state) => {
return (
state.aggregations.data.find(
(aggregation) => aggregation.name === languageFilterData.filterParam,
)?.buckets || []
);
};
+
+export const currentScope = (state) => findKey(state.navigation, { active: true });
+
+export const queryLanguageFilters = (state) => state.query[languageFilterData.filterParam] || [];
+
+export const currentUrlQueryHasLanguageFilters = (state) =>
+ has(state.urlQuery, languageFilterData.filterParam) &&
+ state.urlQuery[languageFilterData.filterParam]?.length > 0;
diff --git a/app/assets/javascripts/search/store/mutations.js b/app/assets/javascripts/search/store/mutations.js
index f9fd69d2211..b2f9f5ab225 100644
--- a/app/assets/javascripts/search/store/mutations.js
+++ b/app/assets/javascripts/search/store/mutations.js
@@ -24,7 +24,7 @@ export default {
state.projects = [];
},
[types.SET_QUERY](state, { key, value }) {
- state.query[key] = value;
+ state.query = { ...state.query, [key]: value };
},
[types.SET_SIDEBAR_DIRTY](state, value) {
state.sidebarDirty = value;
diff --git a/app/assets/javascripts/search/store/utils.js b/app/assets/javascripts/search/store/utils.js
index acb99c60426..8e484e69646 100644
--- a/app/assets/javascripts/search/store/utils.js
+++ b/app/assets/javascripts/search/store/utils.js
@@ -1,6 +1,8 @@
+import { isEqual, orderBy } from 'lodash';
import AccessorUtilities from '~/lib/utils/accessor';
import { formatNumber } from '~/locale';
import { joinPaths } from '~/lib/utils/url_utility';
+import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
import {
MAX_FREQUENT_ITEMS,
MAX_FREQUENCY,
@@ -8,6 +10,8 @@ import {
NUMBER_FORMATING_OPTIONS,
} from './constants';
+const LANGUAGE_AGGREGATION_NAME = languageFilterData.filterParam;
+
function extractKeys(object, keyList) {
return Object.fromEntries(keyList.map((key) => [key, object[key]]));
}
@@ -94,6 +98,10 @@ export const isSidebarDirty = (currentQuery, urlQuery) => {
const userAddedParam = !urlQuery[param] && currentQuery[param];
const userChangedExistingParam = urlQuery[param] && urlQuery[param] !== currentQuery[param];
+ if (Array.isArray(currentQuery[param]) || Array.isArray(urlQuery[param])) {
+ return !isEqual(currentQuery[param], urlQuery[param]);
+ }
+
return userAddedParam || userChangedExistingParam;
});
};
@@ -112,3 +120,27 @@ export const getAggregationsUrl = () => {
currentUrl.pathname = joinPaths('/search', 'aggregations');
return currentUrl.toString();
};
+
+const sortLanguages = (state, entries) => {
+ const queriedLanguages = state.query?.[LANGUAGE_AGGREGATION_NAME] || [];
+
+ if (!Array.isArray(queriedLanguages) || !queriedLanguages.length) {
+ return entries;
+ }
+
+ const queriedLanguagesSet = new Set(queriedLanguages);
+
+ return orderBy(entries, [({ key }) => queriedLanguagesSet.has(key), 'count'], ['desc', 'desc']);
+};
+
+export const prepareSearchAggregations = (state, aggregationData) =>
+ aggregationData.map((item) => {
+ if (item?.name === LANGUAGE_AGGREGATION_NAME) {
+ return {
+ ...item,
+ buckets: sortLanguages(state, item.buckets),
+ };
+ }
+
+ return item;
+ });
diff --git a/app/assets/javascripts/search/topbar/components/app.vue b/app/assets/javascripts/search/topbar/components/app.vue
index da6039f4758..16ff8c94885 100644
--- a/app/assets/javascripts/search/topbar/components/app.vue
+++ b/app/assets/javascripts/search/topbar/components/app.vue
@@ -86,45 +86,50 @@ export default {
</script>
<template>
- <section class="search-page-form gl-lg-display-flex gl-flex-direction-column">
- <div class="gl-lg-display-flex gl-flex-direction-row gl-align-items-flex-end">
- <div class="gl-flex-grow-1 gl-mb-4 gl-lg-mb-0 gl-lg-mr-2">
- <div
- class="gl-sm-display-flex gl-flex-direction-row gl-justify-content-space-between gl-mb-4 gl-md-mb-0"
- >
- <label>{{ $options.i18n.searchLabel }}</label>
- <template v-if="showSyntaxOptions">
- <gl-button
- category="tertiary"
- variant="link"
- size="small"
- button-text-classes="gl-font-sm!"
- @click="onToggleDrawer"
- >{{ $options.i18n.syntaxOptionsLabel }}
- </gl-button>
- <markdown-drawer
- ref="markdownDrawer"
- :document-path="$options.SYNTAX_OPTIONS_DOCUMENT"
- />
- </template>
+ <section class="gl-p-5 gl-bg-gray-10 gl-border-b gl-border-t">
+ <div class="search-page-form gl-lg-display-flex gl-flex-direction-column">
+ <div class="gl-lg-display-flex gl-flex-direction-row gl-align-items-flex-end">
+ <div class="gl-flex-grow-1 gl-mb-4 gl-lg-mb-0 gl-lg-mr-2">
+ <div
+ class="gl-display-flex gl-flex-direction-row gl-justify-content-space-between gl-mb-0 gl-md-mb-4"
+ >
+ <label class="gl-mb-1 gl-md-pb-2">{{ $options.i18n.searchLabel }}</label>
+ <template v-if="showSyntaxOptions">
+ <gl-button
+ category="tertiary"
+ variant="link"
+ size="small"
+ button-text-classes="gl-font-sm!"
+ @click="onToggleDrawer"
+ >{{ $options.i18n.syntaxOptionsLabel }}
+ </gl-button>
+ <markdown-drawer
+ ref="markdownDrawer"
+ :document-path="$options.SYNTAX_OPTIONS_DOCUMENT"
+ />
+ </template>
+ </div>
+ <gl-search-box-by-click
+ id="dashboard_search"
+ v-model="search"
+ name="search"
+ :placeholder="$options.i18n.searchPlaceholder"
+ @submit="applyQuery"
+ />
+ </div>
+ <div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-mx-3">
+ <label class="gl-display-block gl-mb-1 gl-md-pb-2">{{
+ $options.i18n.groupFieldLabel
+ }}</label>
+ <group-filter :initial-data="groupInitialJson" />
+ </div>
+ <div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-ml-3">
+ <label class="gl-display-block gl-mb-1 gl-md-pb-2">{{
+ $options.i18n.projectFieldLabel
+ }}</label>
+ <project-filter :initial-data="projectInitialJson" />
</div>
- <gl-search-box-by-click
- id="dashboard_search"
- v-model="search"
- name="search"
- :placeholder="$options.i18n.searchPlaceholder"
- @submit="applyQuery"
- />
- </div>
- <div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-mx-3">
- <label class="gl-display-block">{{ $options.i18n.groupFieldLabel }}</label>
- <group-filter :initial-data="groupInitialJson" />
- </div>
- <div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-ml-3">
- <label class="gl-display-block">{{ $options.i18n.projectFieldLabel }}</label>
- <project-filter :initial-data="projectInitialJson" />
</div>
</div>
- <hr class="gl-mt-5 gl-mb-0 gl-border-gray-100" />
</section>
</template>
diff --git a/app/assets/javascripts/security_configuration/components/app.vue b/app/assets/javascripts/security_configuration/components/app.vue
index 3ebd21609a6..ccfaa678201 100644
--- a/app/assets/javascripts/security_configuration/components/app.vue
+++ b/app/assets/javascripts/security_configuration/components/app.vue
@@ -1,6 +1,7 @@
<script>
import { GlTab, GlTabs, GlSprintf, GlLink, GlAlert } from '@gitlab/ui';
import { __, s__ } from '~/locale';
+import { parseErrorMessage } from '~/lib/utils/error_message';
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';
@@ -26,13 +27,16 @@ export const i18n = {
scanner will not be reflected as such until the pipeline has been
successfully executed and it has generated valid artifacts.`,
),
- securityConfiguration: __('Security Configuration'),
+ securityConfiguration: __('Security configuration'),
vulnerabilityManagement: s__('SecurityConfiguration|Vulnerability Management'),
securityTraining: s__('SecurityConfiguration|Security training'),
securityTrainingDescription: s__(
'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.',
),
securityTrainingDoc: s__('SecurityConfiguration|Learn more about vulnerability training'),
+ genericErrorText: s__(
+ `SecurityConfiguration|Something went wrong. Please refresh the page, or try again later.`,
+ ),
};
export default {
@@ -124,8 +128,9 @@ export default {
dismissedProjects.add(this.projectFullPath);
this.autoDevopsEnabledAlertDismissedProjects = Array.from(dismissedProjects);
},
- onError(message) {
- this.errorMessage = message;
+ onError(error) {
+ const { message, userFacing } = parseErrorMessage(error);
+ this.errorMessage = userFacing ? message : i18n.genericErrorText;
},
dismissAlert() {
this.errorMessage = '';
diff --git a/app/assets/javascripts/security_configuration/components/constants.js b/app/assets/javascripts/security_configuration/components/constants.js
index c87dcef6a93..6beb6cd4d34 100644
--- a/app/assets/javascripts/security_configuration/components/constants.js
+++ b/app/assets/javascripts/security_configuration/components/constants.js
@@ -35,7 +35,7 @@ export const SAST_CONFIG_HELP_PATH = helpPagePath('user/application_security/sas
});
export const SAST_IAC_NAME = __('Infrastructure as Code (IaC) Scanning');
-export const SAST_IAC_SHORT_NAME = s__('ciReport|IaC Scanning');
+export const SAST_IAC_SHORT_NAME = s__('ciReport|SAST IaC');
export const SAST_IAC_DESCRIPTION = __(
'Analyze your infrastructure as code configuration files for known vulnerabilities.',
);
@@ -65,7 +65,6 @@ export const DAST_PROFILES_NAME = __('DAST profiles');
export const DAST_PROFILES_DESCRIPTION = s__(
'SecurityConfiguration|Manage profiles for use by DAST scans.',
);
-export const DAST_PROFILES_HELP_PATH = helpPagePath('user/application_security/dast/index');
export const DAST_PROFILES_CONFIG_TEXT = s__('SecurityConfiguration|Manage profiles');
export const SECRET_DETECTION_NAME = __('Secret Detection');
diff --git a/app/assets/javascripts/self_monitor/components/self_monitor_form.vue b/app/assets/javascripts/self_monitor/components/self_monitor_form.vue
index d9e969e2278..e5a11487c90 100644
--- a/app/assets/javascripts/self_monitor/components/self_monitor_form.vue
+++ b/app/assets/javascripts/self_monitor/components/self_monitor_form.vue
@@ -1,5 +1,5 @@
<script>
-import { GlFormGroup, GlButton, GlModal, GlToast, GlToggle, GlLink } from '@gitlab/ui';
+import { GlFormGroup, GlButton, GlModal, GlToast, GlToggle, GlLink, GlAlert } from '@gitlab/ui';
import Vue from 'vue';
import { mapState, mapActions } from 'vuex';
import SafeHtml from '~/vue_shared/directives/safe_html';
@@ -17,6 +17,7 @@ export default {
GlModal,
GlToggle,
GlLink,
+ GlAlert,
},
directives: {
SafeHtml,
@@ -27,6 +28,7 @@ export default {
data() {
return {
modalId: 'delete-self-monitor-modal',
+ showDeprecationNotice: true,
};
},
computed: {
@@ -49,6 +51,20 @@ export default {
selfMonitorProjectFullUrl() {
return `${getBaseURL()}/${this.projectPath}`;
},
+ selfMonitoringDeprecationNotice() {
+ return sprintf(
+ s__(
+ 'SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}.',
+ ),
+ {
+ deprecation: `<a href="${this.deprecationPath}">`,
+ removal: `<a href="https://gitlab.com/gitlab-org/gitlab/-/issues/348909">`,
+ opstrace: `<a href="https://gitlab.com/groups/gitlab-org/-/epics/6976">`,
+ link_end: `</a>`,
+ },
+ false,
+ );
+ },
selfMonitoringFormText() {
if (this.projectCreated) {
return sprintf(
@@ -70,6 +86,9 @@ export default {
helpDocsPath() {
return helpPagePath('administration/monitoring/gitlab_self_monitoring_project/index');
},
+ deprecationPath() {
+ return helpPagePath('update/deprecations.md', { anchor: 'gitlab-self-monitoring-project' });
+ },
},
watch: {
selfMonitorEnabled() {
@@ -123,6 +142,9 @@ export default {
viewSelfMonitorProject() {
visitUrl(this.selfMonitorProjectFullUrl);
},
+ hideDeprecationNotice() {
+ this.showDeprecationNotice = false;
+ },
},
};
</script>
@@ -140,6 +162,16 @@ export default {
<gl-link :href="helpDocsPath">{{ __('Learn more.') }}</gl-link>
</p>
</div>
+ <gl-alert
+ v-if="showDeprecationNotice"
+ class="gl-mb-3"
+ :title="s__('SelfMonitoring|Deprecation notice')"
+ :dismissible="true"
+ variant="danger"
+ @dismiss="hideDeprecationNotice"
+ >
+ <div v-safe-html="selfMonitoringDeprecationNotice"></div>
+ </gl-alert>
<div class="settings-content">
<form name="self-monitoring-form">
<p ref="selfMonitoringFormText" v-safe-html="selfMonitoringFormText"></p>
diff --git a/app/assets/javascripts/sentry/constants.js b/app/assets/javascripts/sentry/constants.js
deleted file mode 100644
index 5531c4f56db..00000000000
--- a/app/assets/javascripts/sentry/constants.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { __ } from '~/locale';
-
-// TODO: Remove in favor of https://gitlab.com/gitlab-org/gitlab/issues/35144
-export const IGNORE_ERRORS = [
- // Random plugins/extensions
- 'top.GLOBALS',
- // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error. html
- 'originalCreateNotification',
- 'canvas.contentDocument',
- 'MyApp_RemoveAllHighlights',
- 'http://tt.epicplay.com',
- __("Can't find variable: ZiteReader"),
- __('jigsaw is not defined'),
- __('ComboSearch is not defined'),
- 'http://loading.retry.widdit.com/',
- 'atomicFindClose',
- // Facebook borked
- 'fb_xd_fragment',
- // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to
- // reduce this. (thanks @acdha)
- 'bmi_SafeAddOnload',
- 'EBCallBackMessageReceived',
- // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
- 'conduitPage',
-];
-
-export const DENY_URLS = [
- // Facebook flakiness
- /graph\.facebook\.com/i,
- // Facebook blocked
- /connect\.facebook\.net\/en_US\/all\.js/i,
- // Woopra flakiness
- /eatdifferent\.com\.woopra-ns\.com/i,
- /static\.woopra\.com\/js\/woopra\.js/i,
- // Chrome extensions
- /extensions\//i,
- /^chrome:\/\//i,
- // Other plugins
- /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
- /webappstoolbarba\.texthelp\.com\//i,
- /metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
-];
-
-export const SAMPLE_RATE = 0.95;
diff --git a/app/assets/javascripts/sentry/legacy_constants.js b/app/assets/javascripts/sentry/legacy_constants.js
new file mode 100644
index 00000000000..d04011dab2f
--- /dev/null
+++ b/app/assets/javascripts/sentry/legacy_constants.js
@@ -0,0 +1,46 @@
+import { __ } from '~/locale';
+
+// https://docs.sentry.io/platforms/javascript/configuration/filtering/#decluttering-sentry
+export const IGNORE_ERRORS = [
+ // Random plugins/extensions
+ 'top.GLOBALS',
+ // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error. html
+ 'originalCreateNotification',
+ 'canvas.contentDocument',
+ 'MyApp_RemoveAllHighlights',
+ 'http://tt.epicplay.com',
+ __("Can't find variable: ZiteReader"),
+ __('jigsaw is not defined'),
+ __('ComboSearch is not defined'),
+ 'http://loading.retry.widdit.com/',
+ 'atomicFindClose',
+ // Facebook borked
+ 'fb_xd_fragment',
+ // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to
+ // reduce this. (thanks @acdha)
+ 'bmi_SafeAddOnload',
+ 'EBCallBackMessageReceived',
+ // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
+ 'conduitPage',
+ // Exclude errors from polling when navigating away from a page
+ 'TypeError: Failed to fetch',
+];
+
+export const DENY_URLS = [
+ // Facebook flakiness
+ /graph\.facebook\.com/i,
+ // Facebook blocked
+ /connect\.facebook\.net\/en_US\/all\.js/i,
+ // Woopra flakiness
+ /eatdifferent\.com\.woopra-ns\.com/i,
+ /static\.woopra\.com\/js\/woopra\.js/i,
+ // Chrome extensions
+ /extensions\//i,
+ /^chrome:\/\//i,
+ // Other plugins
+ /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
+ /webappstoolbarba\.texthelp\.com\//i,
+ /metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
+];
+
+export const SAMPLE_RATE = 0.95;
diff --git a/app/assets/javascripts/sentry/legacy_sentry_config.js b/app/assets/javascripts/sentry/legacy_sentry_config.js
index 50a943886db..ae9ae327544 100644
--- a/app/assets/javascripts/sentry/legacy_sentry_config.js
+++ b/app/assets/javascripts/sentry/legacy_sentry_config.js
@@ -1,7 +1,7 @@
import * as Sentry5 from 'sentrybrowser5';
import $ from 'jquery';
import { __ } from '~/locale';
-import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './constants';
+import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './legacy_constants';
const SentryConfig = {
IGNORE_ERRORS,
diff --git a/app/assets/javascripts/sentry/sentry_config.js b/app/assets/javascripts/sentry/sentry_config.js
index ed8a55b7d44..80f087691f4 100644
--- a/app/assets/javascripts/sentry/sentry_config.js
+++ b/app/assets/javascripts/sentry/sentry_config.js
@@ -1,5 +1,4 @@
import * as Sentry from 'sentrybrowser7';
-import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './constants';
const SentryConfig = {
init(options = {}) {
@@ -17,9 +16,6 @@ const SentryConfig = {
release,
allowUrls,
environment,
- ignoreErrors: IGNORE_ERRORS,
- denyUrls: DENY_URLS,
- sampleRate: SAMPLE_RATE,
});
Sentry.setTags(tags);
diff --git a/app/assets/javascripts/service_ping_consent.js b/app/assets/javascripts/service_ping_consent.js
index 654263ba27b..7d6e7e81f3b 100644
--- a/app/assets/javascripts/service_ping_consent.js
+++ b/app/assets/javascripts/service_ping_consent.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import { createAlert } from './flash';
+import { createAlert } from '~/alert';
import axios from './lib/utils/axios_utils';
import { parseBoolean } from './lib/utils/common_utils';
import { __ } from './locale';
diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
index e7d028e8d23..270d7f0d182 100644
--- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
+++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
@@ -1,7 +1,7 @@
<script>
import { GlToast, GlTooltipDirective, GlModal } from '@gitlab/ui';
import Vue from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants';
import { s__ } from '~/locale';
import { updateUserStatus } from '~/rest_api';
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue
index 323f6f23df6..d65c950b33a 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue
@@ -1,6 +1,6 @@
<script>
import { GlIcon } from '@gitlab/ui';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { __, sprintf } from '~/locale';
export default {
@@ -32,7 +32,7 @@ export default {
);
},
isMergeRequest() {
- return this.issuableType === IssuableType.MergeRequest;
+ return this.issuableType === TYPE_MERGE_REQUEST;
},
hasMergeIcon() {
const canMerge = this.user.mergeRequestInteraction?.canMerge || this.user.can_merge;
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue
index 73cd0044c16..2c6eb0e5001 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue
@@ -1,6 +1,6 @@
<script>
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import { isUserBusy } from '~/set_status_modal/utils';
@@ -73,7 +73,7 @@ export default {
},
computed: {
isMergeRequest() {
- return this.issuableType === IssuableType.MergeRequest;
+ return this.issuableType === TYPE_MERGE_REQUEST;
},
cannotMerge() {
const canMerge = this.user.mergeRequestInteraction?.canMerge || this.user.can_merge;
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue b/app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue
index 93fcf2cf1c9..319699b88f3 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue
@@ -1,6 +1,5 @@
<script>
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { IssuableType } from '~/issues/constants';
import { assigneesQueries } from '../../constants';
export default {
@@ -22,9 +21,6 @@ export default {
},
},
computed: {
- issuableClass() {
- return Object.keys(IssuableType).find((key) => IssuableType[key] === this.issuableType);
- },
issuableId() {
return this.issuable?.id;
},
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 d2f0ceb19c9..884edc97016 100644
--- a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue
@@ -1,6 +1,6 @@
<script>
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { __, sprintf } from '~/locale';
import { isUserBusy } from '~/set_status_modal/utils';
import CollapsedAssignee from './collapsed_assignee.vue';
@@ -47,7 +47,7 @@ export default {
},
computed: {
isMergeRequest() {
- return this.issuableType === 'merge_request';
+ return this.issuableType === TYPE_MERGE_REQUEST;
},
hasNoUsers() {
return !this.users.length;
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
index caf3bb2f798..062f63175a7 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
@@ -1,6 +1,6 @@
<script>
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
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 8893e90b1e5..ae81dcb95de 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue
@@ -1,8 +1,8 @@
<script>
import { GlDropdownItem } from '@gitlab/ui';
import Vue from 'vue';
-import { createAlert } from '~/flash';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { createAlert } from '~/alert';
+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';
@@ -60,7 +60,7 @@ export default {
required: false,
default: TYPE_ISSUE,
validator(value) {
- return [TYPE_ISSUE, IssuableType.MergeRequest, IssuableType.Alert].includes(value);
+ return [TYPE_ISSUE, TYPE_MERGE_REQUEST, TYPE_ALERT].includes(value);
},
},
issuableId: {
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 28bc5afc1a4..b41d126be68 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_invite_members.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_invite_members.vue
@@ -4,8 +4,6 @@ import { __ } from '~/locale';
export default {
displayText: __('Invite members'),
- dataTrackLabel: 'edit_assignee',
- dataTrackEvent: 'click_invite_members',
components: {
InviteMembersTrigger,
},
@@ -27,8 +25,6 @@ export default {
<invite-members-trigger
trigger-element="anchor"
:display-text="$options.displayText"
- :event="$options.dataTrackEvent"
- :label="$options.dataTrackLabel"
:trigger-source="triggerSource"
classes="gl-display-block gl-pl-0 gl-hover-text-decoration-none gl-hover-text-blue-800!"
/>
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue
index ddbd8866680..8b40b48b54a 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue
@@ -1,6 +1,6 @@
<script>
import { GlAvatarLabeled, GlIcon } from '@gitlab/ui';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { s__, sprintf } from '~/locale';
const AVAILABILITY_STATUS = {
@@ -39,7 +39,7 @@ export default {
);
},
hasCannotMergeIcon() {
- return this.issuableType === IssuableType.MergeRequest && !this.user.canMerge;
+ return this.issuableType === TYPE_MERGE_REQUEST && !this.user.canMerge;
},
},
};
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 71f349bb87e..b424d9074d0 100644
--- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
@@ -1,6 +1,6 @@
<script>
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { __, sprintf } from '~/locale';
import AssigneeAvatarLink from './assignee_avatar_link.vue';
import UserNameWithStatus from './user_name_with_status.vue';
@@ -53,7 +53,7 @@ export default {
return `@${this.firstUser.username}`;
},
isMergeRequest() {
- return this.issuableType === IssuableType.MergeRequest;
+ return this.issuableType === TYPE_MERGE_REQUEST;
},
},
methods: {
@@ -61,7 +61,7 @@ export default {
this.showLess = !this.showLess;
},
userAvailability(u) {
- if (this.issuableType === IssuableType.MergeRequest) {
+ if (this.issuableType === TYPE_MERGE_REQUEST) {
return u?.availability || '';
}
return u?.status?.availability || '';
diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue
index 1eeb725d5c9..196a86a931a 100644
--- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue
@@ -1,7 +1,7 @@
<script>
import { GlIcon, GlAlert, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
-import { TYPE_EPIC, WorkspaceType } from '~/issues/constants';
+import { TYPE_EPIC, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import { confidentialityInfoText } from '~/vue_shared/constants';
export default {
@@ -25,7 +25,7 @@ export default {
computed: {
confidentialBodyText() {
return confidentialityInfoText(
- this.issuableType === TYPE_EPIC ? WorkspaceType.group : WorkspaceType.project,
+ this.issuableType === TYPE_EPIC ? WORKSPACE_GROUP : WORKSPACE_PROJECT,
this.issuableType,
);
},
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 f7526bcff3d..3038cec03eb 100644
--- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue
@@ -1,6 +1,6 @@
<script>
import { GlSprintf, GlButton } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
import { __, sprintf } from '~/locale';
import { confidentialityQueries } from '../../constants';
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 c2f239b56c7..9177baec246 100644
--- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue
@@ -1,7 +1,7 @@
<script>
import produce from 'immer';
import Vue from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, sprintf } from '~/locale';
import { confidentialityQueries, Tracking } from '../../constants';
import SidebarEditableItem from '../sidebar_editable_item.vue';
diff --git a/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue b/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue
index c9ecaf4102f..916ff70a5ea 100644
--- a/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue
+++ b/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue
@@ -1,7 +1,7 @@
<script>
import { GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab/ui';
import { __, n__, sprintf } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_ISSUE } from '~/graphql_shared/constants';
import getIssueCrmContactsQuery from '../../queries/get_issue_crm_contacts.query.graphql';
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 77be8022ec0..190b8c1de62 100644
--- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
+++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
@@ -1,6 +1,6 @@
<script>
import { GlIcon, GlDatepicker, GlTooltipDirective, GlLink, GlPopover } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
import { dateInWords, formatDate, parsePikadayDate } from '~/lib/utils/datetime_utility';
import { __, sprintf } from '~/locale';
@@ -54,6 +54,16 @@ export default {
type: Boolean,
default: false,
},
+ minDate: {
+ required: false,
+ type: Date,
+ default: null,
+ },
+ maxDate: {
+ required: false,
+ type: Date,
+ default: null,
+ },
},
data() {
return {
@@ -292,6 +302,8 @@ export default {
v-if="!isLoading"
ref="datePicker"
class="gl-relative"
+ :min-date="minDate"
+ :max-date="maxDate"
:default-date="parsedDate"
:first-day="firstDay"
show-clear-button
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 f7daad63f45..6db332a82da 100644
--- a/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue
+++ b/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue
@@ -1,6 +1,6 @@
<script>
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { logError } from '~/lib/logger';
import EscalationStatus from 'ee_else_ce/sidebar/components/incidents/escalation_status.vue';
import {
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view.vue
index b8afa67a947..227d85d952b 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view.vue
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view.vue
@@ -92,10 +92,14 @@ export default {
/>
</div>
<div class="color-input-container gl-display-flex">
- <span
- class="dropdown-label-color-preview position-relative position-relative d-inline-block"
- :style="{ backgroundColor: selectedColor }"
- ></span>
+ <gl-form-input
+ v-model.trim="selectedColor"
+ class="gl-rounded-top-right-none gl-rounded-bottom-right-none gl-mr-n1 gl-mb-2 gl-w-8"
+ type="color"
+ :value="selectedColor"
+ :placeholder="__('Open color picker')"
+ data-testid="selected-color"
+ />
<gl-form-input
v-model.trim="selectedColor"
class="gl-rounded-top-left-none gl-rounded-bottom-left-none gl-mb-2"
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js b/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js
index 2dab97826b9..06030003f3c 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import * as types from './mutation_types';
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/constants.js b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/constants.js
index cd671b4d8f5..852ef0c6283 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/constants.js
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/constants.js
@@ -6,8 +6,3 @@ export const DropdownVariant = {
Standalone: 'standalone',
Embedded: 'embedded',
};
-
-export const LabelType = {
- group: 'group',
- project: 'project',
-};
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 aa1184ed314..1174ec3f01e 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
@@ -8,11 +8,11 @@ import {
GlLoadingIcon,
} from '@gitlab/ui';
import produce from 'immer';
-import { createAlert } from '~/flash';
+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 { LabelType } from './constants';
const errorMessage = __('Error creating label.');
@@ -62,7 +62,7 @@ export default {
return Object.keys(colorsMap).map((color) => ({ [color]: colorsMap[color] }));
},
mutationVariables() {
- const attributePath = this.labelCreateType === LabelType.group ? 'groupPath' : 'projectPath';
+ const attributePath = this.labelCreateType === WORKSPACE_GROUP ? 'groupPath' : 'projectPath';
return {
title: this.labelTitle,
@@ -163,11 +163,14 @@ export default {
/>
</div>
<div class="color-input-container gl-display-flex">
- <span
- class="dropdown-label-color-preview gl-relative gl-display-inline-block"
+ <gl-form-input
+ v-model.trim="selectedColor"
+ class="gl-rounded-top-right-none gl-rounded-bottom-right-none gl-mr-n1 gl-mb-2 gl-w-8"
+ type="color"
+ :value="selectedColor"
+ :placeholder="__('Select color')"
data-testid="selected-color"
- :style="{ backgroundColor: selectedColor }"
- ></span>
+ />
<gl-form-input
v-model.trim="selectedColor"
class="gl-rounded-top-left-none gl-rounded-bottom-left-none gl-mb-2"
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 c1939dc7785..e664d6b4bd6 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
@@ -1,7 +1,7 @@
<script>
import { GlDropdownForm, GlDropdownItem, GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import { workspaceLabelsQueries } from '../../../constants';
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 bf916e26a15..3aa4215443e 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
@@ -2,9 +2,9 @@
import { debounce } from 'lodash';
import issuableLabelsSubscription from 'ee_else_ce/sidebar/queries/issuable_labels.subscription.graphql';
import { MutationOperationMode, getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { IssuableType, TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST, TYPE_TEST_CASE } from '~/issues/constants';
import { __ } from '~/locale';
import { issuableLabelsQueries } from '../../../constants';
@@ -166,7 +166,7 @@ export default {
fullPath: this.fullPath,
};
- if (this.issuableType === IssuableType.TestCase) {
+ if (this.issuableType === TYPE_TEST_CASE) {
queryVariables.types = ['TEST_CASE'];
}
@@ -262,9 +262,9 @@ export default {
switch (this.issuableType) {
case TYPE_ISSUE:
- case IssuableType.TestCase:
+ case TYPE_TEST_CASE:
return updateVariables;
- case IssuableType.MergeRequest:
+ case TYPE_MERGE_REQUEST:
return {
...updateVariables,
operationMode: MutationOperationMode.Replace,
@@ -319,12 +319,12 @@ export default {
switch (this.issuableType) {
case TYPE_ISSUE:
- case IssuableType.TestCase:
+ case TYPE_TEST_CASE:
return {
...removeVariables,
removeLabelIds: [labelId],
};
- case IssuableType.MergeRequest:
+ case TYPE_MERGE_REQUEST:
return {
...removeVariables,
labelIds: [labelId],
diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
index df03af346c0..606d374158b 100644
--- a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
+++ b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
@@ -2,7 +2,7 @@
import { GlButton } from '@gitlab/ui';
import $ from 'jquery';
import { mapActions } from 'vuex';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, sprintf } from '~/locale';
import eventHub from '../../event_hub';
@@ -49,11 +49,11 @@ export default {
fullPath: this.fullPath,
})
.catch(() => {
- const flashMessage = __(
+ const alertMessage = __(
'Something went wrong trying to change the locked state of this %{issuableDisplayName}',
);
createAlert({
- message: sprintf(flashMessage, { issuableDisplayName: this.issuableDisplayName }),
+ message: sprintf(alertMessage, { issuableDisplayName: this.issuableDisplayName }),
});
})
.finally(() => {
diff --git a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue
index 9d8f1304911..1eff4db3970 100644
--- a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue
+++ b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue
@@ -1,10 +1,10 @@
<script>
import { GlIcon, GlTooltipDirective, GlOutsideDirective as Outside } from '@gitlab/ui';
import { mapGetters, mapActions } from 'vuex';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { __, sprintf } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import toast from '~/vue_shared/plugins/global_toast';
import eventHub from '../../event_hub';
import EditForm from './edit_form.vue';
@@ -46,7 +46,9 @@ export default {
computed: {
...mapGetters(['getNoteableData']),
isMergeRequest() {
- return this.getNoteableData.targetType === 'merge_request' && this.glFeatures.movedMrSidebar;
+ return (
+ this.getNoteableData.targetType === TYPE_MERGE_REQUEST && this.glFeatures.movedMrSidebar
+ );
},
issuableDisplayName() {
const isInIssuePage = this.getNoteableData.targetType === TYPE_ISSUE;
@@ -92,11 +94,11 @@ export default {
}
})
.catch(() => {
- const flashMessage = __(
+ const alertMessage = __(
'Something went wrong trying to change the locked state of this %{issuableDisplayName}',
);
createAlert({
- message: sprintf(flashMessage, { issuableDisplayName: this.issuableDisplayName }),
+ message: sprintf(alertMessage, { issuableDisplayName: this.issuableDisplayName }),
});
})
.finally(() => {
diff --git a/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue b/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue
index 8072154cd28..24afb25e403 100644
--- a/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue
+++ b/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue
@@ -2,7 +2,12 @@
import { GlDropdownItem } from '@gitlab/ui';
import { TYPENAME_MILESTONE } from '~/graphql_shared/constants';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { IssuableType, TYPE_ISSUE, WorkspaceType } from '~/issues/constants';
+import {
+ TYPE_ISSUE,
+ TYPE_MERGE_REQUEST,
+ WORKSPACE_GROUP,
+ WORKSPACE_PROJECT,
+} from '~/issues/constants';
import { __ } from '~/locale';
import { IssuableAttributeType } from '../../constants';
import SidebarDropdown from '../sidebar_dropdown.vue';
@@ -37,7 +42,7 @@ export default {
type: String,
required: true,
validator(value) {
- return [TYPE_ISSUE, IssuableType.MergeRequest].includes(value);
+ return [TYPE_ISSUE, TYPE_MERGE_REQUEST].includes(value);
},
},
inputName: {
@@ -64,7 +69,7 @@ export default {
type: String,
required: true,
validator(value) {
- return [WorkspaceType.group, WorkspaceType.project].includes(value);
+ return [WORKSPACE_GROUP, WORKSPACE_PROJECT].includes(value);
},
},
},
diff --git a/app/assets/javascripts/sidebar/components/move/move_issue_button.vue b/app/assets/javascripts/sidebar/components/move/move_issue_button.vue
index e1259fad6a7..76c47305369 100644
--- a/app/assets/javascripts/sidebar/components/move/move_issue_button.vue
+++ b/app/assets/javascripts/sidebar/components/move/move_issue_button.vue
@@ -1,7 +1,7 @@
<script>
import ProjectSelect from '~/sidebar/components/move/issuable_move_dropdown.vue';
import { __ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { visitUrl } from '~/lib/utils/url_utility';
import moveIssueMutation from '../../queries/move_issue.mutation.graphql';
diff --git a/app/assets/javascripts/sidebar/components/move/move_issues_button.vue b/app/assets/javascripts/sidebar/components/move/move_issues_button.vue
index ab4ac9500ad..68c8b35c009 100644
--- a/app/assets/javascripts/sidebar/components/move/move_issues_button.vue
+++ b/app/assets/javascripts/sidebar/components/move/move_issues_button.vue
@@ -1,6 +1,6 @@
<script>
import { GlAlert } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { logError } from '~/lib/logger';
import { s__ } from '~/locale';
import {
diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue
index 2f25c2fd4b0..a9d102eb303 100644
--- a/app/assets/javascripts/sidebar/components/participants/participants.vue
+++ b/app/assets/javascripts/sidebar/components/participants/participants.vue
@@ -99,7 +99,7 @@ export default {
>
<gl-icon name="users" />
<gl-loading-icon v-if="loading" size="sm" />
- <span v-else data-testid="collapsed-count" class="gl-pt-2 gl-px-3 gl-font-sm">
+ <span v-else class="gl-pt-2 gl-px-3 gl-font-sm">
{{ participantCount }}
</span>
</div>
@@ -114,9 +114,12 @@ export default {
<div
v-for="participant in visibleParticipants"
:key="participant.id"
- class="participants-author gl-display-inline-block gl-pr-3 gl-pb-3"
+ class="participants-author gl-display-inline-block gl-mr-3 gl-mb-3"
>
- <a :href="participant.web_url || participant.webUrl" class="author-link">
+ <a
+ :href="participant.web_url || participant.webUrl"
+ class="author-link gl-display-inline-block gl-rounded-full"
+ >
<user-avatar-image
:lazy="lazy"
:img-src="participant.avatar_url || participant.avatarUrl"
@@ -133,7 +136,6 @@ export default {
<gl-button
variant="link"
button-text-classes="gl-text-secondary"
- data-testid="more-participants"
@click="toggleMoreParticipants"
>{{ toggleLabel }}</gl-button
>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue
index 56ac4c39e84..80c051f86b5 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue
@@ -2,7 +2,7 @@
// NOTE! For the first iteration, we are simply copying the implementation of Assignees
// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { __, sprintf } from '~/locale';
import ReviewerAvatar from './reviewer_avatar.vue';
@@ -41,7 +41,9 @@ export default {
},
computed: {
cannotMerge() {
- return this.issuableType === 'merge_request' && !this.user.mergeRequestInteraction?.canMerge;
+ return (
+ this.issuableType === TYPE_MERGE_REQUEST && !this.user.mergeRequestInteraction?.canMerge
+ );
},
tooltipTitle() {
if (this.cannotMerge && this.tooltipHasName) {
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
index 8dd58d33ecf..9c23f239b4c 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
@@ -3,7 +3,7 @@
// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
import Vue from 'vue';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
import { __ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
diff --git a/app/assets/javascripts/sidebar/components/severity/sidebar_severity_widget.vue b/app/assets/javascripts/sidebar/components/severity/sidebar_severity_widget.vue
index ecb9a2809a0..55de0ceb388 100644
--- a/app/assets/javascripts/sidebar/components/severity/sidebar_severity_widget.vue
+++ b/app/assets/javascripts/sidebar/components/severity/sidebar_severity_widget.vue
@@ -1,9 +1,10 @@
<script>
import { GlDropdown, GlDropdownItem, GlTooltip, GlSprintf } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { TYPE_INCIDENT } from '~/issues/constants';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import updateIssuableSeverity from '../../queries/update_issuable_severity.mutation.graphql';
-import { INCIDENT_SEVERITY, ISSUABLE_TYPES, SEVERITY_I18N as I18N } from '../../constants';
+import { INCIDENT_SEVERITY, SEVERITY_I18N as I18N } from '../../constants';
import SeverityToken from './severity.vue';
export default {
@@ -34,10 +35,10 @@ export default {
issuableType: {
type: String,
required: false,
- default: ISSUABLE_TYPES.INCIDENT,
+ default: TYPE_INCIDENT,
validator: (value) => {
// currently severity is supported only for incidents, but this list might be extended
- return [ISSUABLE_TYPES.INCIDENT].includes(value);
+ return [TYPE_INCIDENT].includes(value);
},
},
},
@@ -50,7 +51,7 @@ export default {
computed: {
severitiesList() {
switch (this.issuableType) {
- case ISSUABLE_TYPES.INCIDENT:
+ case TYPE_INCIDENT:
return Object.values(INCIDENT_SEVERITY);
default:
return [];
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
index d68e4974ea4..50b4284cde0 100644
--- a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
@@ -8,7 +8,13 @@ import {
GlSearchBoxByType,
} from '@gitlab/ui';
import { kebabCase, snakeCase } from 'lodash';
-import { IssuableType, TYPE_EPIC, TYPE_ISSUE, WorkspaceType } from '~/issues/constants';
+import {
+ TYPE_EPIC,
+ TYPE_ISSUE,
+ TYPE_MERGE_REQUEST,
+ WORKSPACE_GROUP,
+ WORKSPACE_PROJECT,
+} from '~/issues/constants';
import { __ } from '~/locale';
import {
defaultEpicSort,
@@ -21,7 +27,7 @@ import {
LocalizedIssuableAttributeType,
noAttributeId,
} from 'ee_else_ce/sidebar/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { PathIdSeparator } from '~/related_issues/constants';
export default {
@@ -70,15 +76,15 @@ export default {
type: String,
required: true,
validator(value) {
- return [TYPE_ISSUE, IssuableType.MergeRequest].includes(value);
+ return [TYPE_ISSUE, TYPE_MERGE_REQUEST].includes(value);
},
},
workspaceType: {
type: String,
required: false,
- default: WorkspaceType.project,
+ default: WORKSPACE_PROJECT,
validator(value) {
- return [WorkspaceType.group, WorkspaceType.project].includes(value);
+ return [WORKSPACE_GROUP, WORKSPACE_PROJECT].includes(value);
},
},
},
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
index 5df65c4aaaf..19e72da65f2 100644
--- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
@@ -1,9 +1,9 @@
<script>
import { GlButton, GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab/ui';
import { kebabCase, snakeCase } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { IssuableType, TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { timeFor } from '~/lib/utils/datetime_utility';
import { __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -71,7 +71,7 @@ export default {
type: String,
required: true,
validator(value) {
- return [TYPE_ISSUE, IssuableType.MergeRequest].includes(value);
+ return [TYPE_ISSUE, TYPE_MERGE_REQUEST].includes(value);
},
},
icon: {
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 cbe839d1112..344fa880131 100644
--- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue
+++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue
@@ -1,7 +1,12 @@
<script>
import { GlDropdownForm, GlIcon, GlLoadingIcon, GlToggle, GlTooltipDirective } from '@gitlab/ui';
-import { createAlert } from '~/flash';
-import { IssuableType, TYPE_EPIC } from '~/issues/constants';
+import { createAlert } from '~/alert';
+import {
+ TYPE_EPIC,
+ TYPE_MERGE_REQUEST,
+ WORKSPACE_GROUP,
+ WORKSPACE_PROJECT,
+} from '~/issues/constants';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { __, sprintf } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -87,7 +92,7 @@ export default {
},
computed: {
isMergeRequest() {
- return this.issuableType === IssuableType.MergeRequest && this.glFeatures.movedMrSidebar;
+ return this.issuableType === TYPE_MERGE_REQUEST && this.glFeatures.movedMrSidebar;
},
isLoading() {
return this.$apollo.queries?.subscribed?.loading || this.loading;
@@ -109,7 +114,7 @@ export default {
},
subscribeDisabledDescription() {
return sprintf(__('Disabled by %{parent} owner'), {
- parent: this.parentIsGroup ? 'group' : 'project',
+ parent: this.parentIsGroup ? WORKSPACE_GROUP : WORKSPACE_PROJECT,
});
},
isLoggedIn() {
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue b/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue
index 964da3b6138..9b582ba41ed 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue
@@ -29,7 +29,11 @@ export default {
GlLink,
GlSprintf,
},
- inject: ['issuableType'],
+ inject: {
+ issuableType: {
+ default: null,
+ },
+ },
props: {
issuableId: {
type: String,
@@ -52,13 +56,11 @@ export default {
primaryProps() {
return {
text: s__('CreateTimelogForm|Save'),
- attributes: [
- {
- variant: 'confirm',
- disabled: this.submitDisabled,
- loading: this.isLoading,
- },
- ],
+ attributes: {
+ variant: 'confirm',
+ disabled: this.submitDisabled,
+ loading: this.isLoading,
+ },
};
},
cancelProps() {
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/report.vue b/app/assets/javascripts/sidebar/components/time_tracking/report.vue
index cffbb6466f2..109e1af85ec 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/report.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/report.vue
@@ -1,6 +1,6 @@
<script>
import { GlLoadingIcon, GlTableLite, GlButton, GlTooltipDirective } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPENAME_ISSUE, TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPE_ISSUE } from '~/issues/constants';
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 c645b1649d2..f6968558122 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
@@ -8,7 +8,7 @@ import {
GlLoadingIcon,
GlTooltipDirective,
} from '@gitlab/ui';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import { s__, __ } from '~/locale';
@@ -173,7 +173,7 @@ export default {
return Boolean(this.showHelp);
},
isTimeReportSupported() {
- return [TYPE_ISSUE, IssuableType.MergeRequest].includes(this.issuableType) && this.issuableId;
+ return [TYPE_ISSUE, TYPE_MERGE_REQUEST].includes(this.issuableType) && this.issuableId;
},
timeTrackingIconTitle() {
return this.showHelpState ? '' : HOW_TO_TRACK_TIME;
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 b86ff279fd8..551d306a9c4 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
@@ -1,7 +1,8 @@
<script>
import { GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { produce } from 'immer';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+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';
@@ -83,7 +84,7 @@ export default {
},
computed: {
isMergeRequest() {
- return this.glFeatures.movedMrSidebar && this.issuableType === 'merge_request';
+ return this.glFeatures.movedMrSidebar && this.issuableType === TYPE_MERGE_REQUEST;
},
todoIdQuery() {
return todoQueries[this.issuableType].query;
diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js
index 14491226b15..7bca83c4142 100644
--- a/app/assets/javascripts/sidebar/constants.js
+++ b/app/assets/javascripts/sidebar/constants.js
@@ -3,7 +3,15 @@ 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 { IssuableType, TYPE_EPIC, TYPE_ISSUE, WorkspaceType } from '~/issues/constants';
+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 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';
@@ -69,11 +77,11 @@ export const assigneesQueries = {
subscription: issuableAssigneesSubscription,
mutation: updateIssueAssigneesMutation,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: getMergeRequestAssignees,
mutation: updateMergeRequestAssigneesMutation,
},
- [IssuableType.Alert]: {
+ [TYPE_ALERT]: {
query: getAlertAssignees,
mutation: updateAlertAssigneesMutation,
},
@@ -83,13 +91,13 @@ export const participantsQueries = {
[TYPE_ISSUE]: {
query: issueParticipantsQuery,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: getMergeRequestParticipants,
},
[TYPE_EPIC]: {
query: epicParticipantsQuery,
},
- [IssuableType.Alert]: {
+ [TYPE_ALERT]: {
query: '',
skipQuery: true,
},
@@ -99,7 +107,7 @@ export const userSearchQueries = {
[TYPE_ISSUE]: {
query: userSearchQuery,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: userSearchWithMRPermissionsQuery,
},
};
@@ -119,7 +127,7 @@ export const referenceQueries = {
[TYPE_ISSUE]: {
query: issueReferenceQuery,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: mergeRequestReferenceQuery,
},
[TYPE_EPIC]: {
@@ -128,10 +136,10 @@ export const referenceQueries = {
};
export const workspaceLabelsQueries = {
- [WorkspaceType.project]: {
+ [WORKSPACE_PROJECT]: {
query: projectLabelsQuery,
},
- [WorkspaceType.group]: {
+ [WORKSPACE_GROUP]: {
query: groupLabelsQuery,
},
};
@@ -142,7 +150,7 @@ export const issuableLabelsQueries = {
mutation: updateIssueLabelsMutation,
mutationName: 'updateIssue',
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
issuableQuery: mergeRequestLabelsQuery,
mutation: updateMergeRequestLabelsMutation,
mutationName: 'mergeRequestSetLabels',
@@ -152,7 +160,7 @@ export const issuableLabelsQueries = {
mutation: updateEpicLabelsMutation,
mutationName: 'updateEpic',
},
- [IssuableType.TestCase]: {
+ [TYPE_TEST_CASE]: {
issuableQuery: issueLabelsQuery,
mutation: updateTestCaseLabelsMutation,
mutationName: 'updateTestCaseLabels',
@@ -186,7 +194,7 @@ export const subscribedQueries = {
query: epicSubscribedQuery,
mutation: updateEpicSubscriptionMutation,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: mergeRequestSubscribed,
mutation: updateMergeRequestSubscriptionMutation,
},
@@ -201,7 +209,7 @@ export const timeTrackingQueries = {
[TYPE_ISSUE]: {
query: issueTimeTrackingQuery,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: mergeRequestTimeTrackingQuery,
},
};
@@ -228,7 +236,7 @@ export const timelogQueries = {
[TYPE_ISSUE]: {
query: getIssueTimelogsQuery,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: getMrTimelogsQuery,
},
};
@@ -240,7 +248,7 @@ export const issuableMilestoneQueries = {
query: projectIssueMilestoneQuery,
mutation: projectIssueMilestoneMutation,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: mergeRequestMilestone,
mutation: mergeRequestMilestoneMutation,
},
@@ -249,14 +257,14 @@ export const issuableMilestoneQueries = {
export const milestonesQueries = {
[TYPE_ISSUE]: {
query: {
- [WorkspaceType.group]: groupMilestonesQuery,
- [WorkspaceType.project]: projectMilestonesQuery,
+ [WORKSPACE_GROUP]: groupMilestonesQuery,
+ [WORKSPACE_PROJECT]: projectMilestonesQuery,
},
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: {
- [WorkspaceType.group]: groupMilestonesQuery,
- [WorkspaceType.project]: projectMilestonesQuery,
+ [WORKSPACE_GROUP]: groupMilestonesQuery,
+ [WORKSPACE_PROJECT]: projectMilestonesQuery,
},
},
};
@@ -289,7 +297,7 @@ export const todoQueries = {
[TYPE_ISSUE]: {
query: issueTodoQuery,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: mergeRequestTodoQuery,
},
};
@@ -407,10 +415,6 @@ export const INCIDENT_SEVERITY = {
},
};
-export const ISSUABLE_TYPES = {
- INCIDENT: 'incident',
-};
-
export const MILESTONE_STATE = {
ACTIVE: 'active',
CLOSED: 'closed',
diff --git a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
index b908cf0cd9e..b0060e4c28d 100644
--- a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
@@ -1,5 +1,4 @@
import Vue from 'vue';
-import { IssuableType } from '~/issues/constants';
import { parseBoolean } from '~/lib/utils/common_utils';
import TimeTracker from './components/time_tracking/time_tracker.vue';
@@ -25,9 +24,6 @@ export default class SidebarMilestone {
components: {
TimeTracker,
},
- provide: {
- issuableType: IssuableType.Milestone,
- },
render: (createElement) =>
createElement('time-tracker', {
props: {
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index fb024d818da..99c3fdf82d4 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -4,7 +4,7 @@ import { TYPENAME_ISSUE, TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constan
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST, WORKSPACE_PROJECT } from '~/issues/constants';
import { gqlClient } from '~/issues/list/graphql';
import {
isInDesignPage,
@@ -25,7 +25,6 @@ import CopyEmailToClipboard from './components/copy/copy_email_to_clipboard.vue'
import SidebarDueDateWidget from './components/date/sidebar_date_widget.vue';
import SidebarEscalationStatus from './components/incidents/sidebar_escalation_status.vue';
import { DropdownVariant } from './components/labels/labels_select_vue/constants';
-import { LabelType } from './components/labels/labels_select_widget/constants';
import LabelsSelectWidget from './components/labels/labels_select_widget/labels_select_root.vue';
import IssuableLockForm from './components/lock/issuable_lock_form.vue';
import MilestoneDropdown from './components/milestone/milestone_dropdown.vue';
@@ -81,7 +80,7 @@ function mountSidebarTodoWidget() {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
? TYPE_ISSUE
- : IssuableType.MergeRequest,
+ : TYPE_MERGE_REQUEST,
},
}),
});
@@ -125,7 +124,7 @@ function mountSidebarAssigneesDeprecated(mediator) {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
? TYPE_ISSUE
- : IssuableType.MergeRequest,
+ : TYPE_MERGE_REQUEST,
issuableId: id,
assigneeAvailabilityStatus,
},
@@ -142,7 +141,7 @@ function mountSidebarAssigneesWidget() {
const { id, iid, fullPath, editable } = getSidebarOptions();
const isIssuablePage = isInIssuePage() || isInIncidentPage() || isInDesignPage();
- const issuableType = isIssuablePage ? TYPE_ISSUE : IssuableType.MergeRequest;
+ const issuableType = isIssuablePage ? TYPE_ISSUE : TYPE_MERGE_REQUEST;
// eslint-disable-next-line no-new
new Vue({
el,
@@ -204,8 +203,7 @@ function mountSidebarReviewers(mediator) {
issuableIid: String(iid),
projectPath: fullPath,
field: el.dataset.field,
- issuableType:
- isInIssuePage() || isInDesignPage() ? TYPE_ISSUE : IssuableType.MergeRequest,
+ issuableType: isInIssuePage() || isInDesignPage() ? TYPE_ISSUE : TYPE_MERGE_REQUEST,
},
}),
});
@@ -275,8 +273,7 @@ function mountSidebarMilestoneWidget() {
attrWorkspacePath: projectPath,
workspacePath: projectPath,
iid: issueIid,
- issuableType:
- isInIssuePage() || isInDesignPage() ? TYPE_ISSUE : IssuableType.MergeRequest,
+ issuableType: isInIssuePage() || isInDesignPage() ? TYPE_ISSUE : TYPE_MERGE_REQUEST,
issuableAttribute: IssuableAttributeType.Milestone,
icon: 'clock',
},
@@ -313,7 +310,7 @@ export function mountMilestoneDropdown() {
attrWorkspacePath: fullPath,
canAdminMilestone,
inputName,
- issuableType: isInIssuePage() ? TYPE_ISSUE : IssuableType.MergeRequest,
+ issuableType: isInIssuePage() ? TYPE_ISSUE : TYPE_MERGE_REQUEST,
milestoneId,
milestoneTitle,
projectMilestonesPath,
@@ -358,10 +355,10 @@ export function mountSidebarLabelsWidget() {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
? TYPE_ISSUE
- : IssuableType.MergeRequest,
- workspaceType: 'project',
+ : TYPE_MERGE_REQUEST,
+ workspaceType: WORKSPACE_PROJECT,
attrWorkspacePath: el.dataset.projectPath,
- labelCreateType: LabelType.project,
+ labelCreateType: WORKSPACE_PROJECT,
},
class: ['block labels js-labels-block'],
scopedSlots: {
@@ -398,7 +395,7 @@ function mountSidebarConfidentialityWidget() {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
? TYPE_ISSUE
- : IssuableType.MergeRequest,
+ : TYPE_MERGE_REQUEST,
},
}),
});
@@ -454,7 +451,7 @@ function mountSidebarReferenceWidget() {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
? TYPE_ISSUE
- : IssuableType.MergeRequest,
+ : TYPE_MERGE_REQUEST,
},
}),
});
@@ -506,7 +503,7 @@ function mountSidebarParticipantsWidget() {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
? TYPE_ISSUE
- : IssuableType.MergeRequest,
+ : TYPE_MERGE_REQUEST,
},
}),
});
@@ -536,7 +533,7 @@ function mountSidebarSubscriptionsWidget() {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
? TYPE_ISSUE
- : IssuableType.MergeRequest,
+ : TYPE_MERGE_REQUEST,
},
}),
});
diff --git a/app/assets/javascripts/sidebar/queries/update_epic_due_date.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_epic_due_date.mutation.graphql
index 9b0a8b4a8f7..690eb75f8f4 100644
--- a/app/assets/javascripts/sidebar/queries/update_epic_due_date.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/update_epic_due_date.mutation.graphql
@@ -4,6 +4,7 @@ mutation updateEpicDueDate($input: UpdateEpicInput!) {
id
dueDateIsFixed
dueDateFixed
+ dueDate
dueDateFromMilestones
}
errors
diff --git a/app/assets/javascripts/sidebar/queries/update_epic_start_date.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_epic_start_date.mutation.graphql
index 9b4bb9159c3..d2a598a00fa 100644
--- a/app/assets/javascripts/sidebar/queries/update_epic_start_date.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/update_epic_start_date.mutation.graphql
@@ -4,6 +4,7 @@ mutation updateEpicStartDate($input: UpdateEpicInput!) {
id
startDateIsFixed
startDateFixed
+ startDate
startDateFromMilestones
}
errors
diff --git a/app/assets/javascripts/sidebar/sidebar_mediator.js b/app/assets/javascripts/sidebar/sidebar_mediator.js
index c6a66ab2275..7353694a324 100644
--- a/app/assets/javascripts/sidebar/sidebar_mediator.js
+++ b/app/assets/javascripts/sidebar/sidebar_mediator.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import toast from '~/vue_shared/plugins/global_toast';
import { visitUrl } from '~/lib/utils/url_utility';
diff --git a/app/assets/javascripts/single_file_diff.js b/app/assets/javascripts/single_file_diff.js
index 6e5b2ce4dbe..b613e356a7a 100644
--- a/app/assets/javascripts/single_file_diff.js
+++ b/app/assets/javascripts/single_file_diff.js
@@ -1,7 +1,7 @@
/* eslint-disable consistent-return */
import $ from 'jquery';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { loadingIconForLegacyJS } from '~/loading_icon_for_legacy_js';
import { spriteIcon } from '~/lib/utils/common_utils';
import FilesCommentButton from './files_comment_button';
diff --git a/app/assets/javascripts/snippets/components/edit.vue b/app/assets/javascripts/snippets/components/edit.vue
index 4a7528d9c8e..151c38d01dc 100644
--- a/app/assets/javascripts/snippets/components/edit.vue
+++ b/app/assets/javascripts/snippets/components/edit.vue
@@ -2,7 +2,7 @@
import { GlButton, GlLoadingIcon, GlFormInput, GlFormGroup } from '@gitlab/ui';
import eventHub from '~/blob/components/eventhub';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { redirectTo, joinPaths } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
import {
@@ -141,7 +141,7 @@ export default {
Object.assign(e, { returnValue });
return returnValue;
},
- flashAPIFailure(err) {
+ alertAPIFailure(err) {
const defaultErrorMsg = this.newSnippet
? SNIPPET_CREATE_MUTATION_ERROR
: SNIPPET_UPDATE_MUTATION_ERROR;
@@ -190,7 +190,7 @@ export default {
const errors = baseObj?.errors;
if (errors?.length) {
- this.flashAPIFailure(errors[0]);
+ this.alertAPIFailure(errors[0]);
} else {
redirectTo(baseObj.snippet.webUrl);
}
@@ -199,7 +199,7 @@ export default {
// eslint-disable-next-line no-console
console.error('[gitlab] unexpected error while updating snippet', e);
- this.flashAPIFailure(getErrorMessage(e));
+ this.alertAPIFailure(getErrorMessage(e));
});
},
updateActions(actions) {
diff --git a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue
index 7e80928cbea..021bd23781e 100644
--- a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue
+++ b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue
@@ -1,7 +1,7 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { getBaseURL, joinPaths } from '~/lib/utils/url_utility';
import { sprintf } from '~/locale';
@@ -60,9 +60,9 @@ export default {
.then((res) => {
this.notifyAboutUpdates({ content: res.data });
})
- .catch((e) => this.flashAPIFailure(e));
+ .catch((e) => this.alertAPIFailure(e));
},
- flashAPIFailure(err) {
+ alertAPIFailure(err) {
createAlert({ message: sprintf(SNIPPET_BLOB_CONTENT_FETCH_ERROR, { err }) });
},
},
diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue
index 759a3f31a05..881e06113d9 100644
--- a/app/assets/javascripts/snippets/components/snippet_header.vue
+++ b/app/assets/javascripts/snippets/components/snippet_header.vue
@@ -19,7 +19,7 @@ import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/alert';
import DeleteSnippetMutation from '../mutations/delete_snippet.mutation.graphql';
@@ -78,6 +78,7 @@ export default {
isSubmittingSpam: false,
errorMessage: '',
canCreateSnippet: false,
+ isDeleteModalVisible: false,
};
},
computed: {
@@ -164,10 +165,10 @@ export default {
: `${gon.relative_url_root}dashboard/snippets`;
},
closeDeleteModal() {
- this.$refs.deleteModal.hide();
+ this.isDeleteModalVisible = false;
},
showDeleteModal() {
- this.$refs.deleteModal.show();
+ this.isDeleteModalVisible = true;
},
deleteSnippet() {
this.isLoading = true;
@@ -291,12 +292,22 @@ export default {
</div>
</div>
- <gl-modal ref="deleteModal" modal-id="delete-modal" title="Example title">
+ <gl-modal
+ ref="deleteModal"
+ v-model="isDeleteModalVisible"
+ modal-id="delete-modal"
+ title="Example title"
+ >
<template #modal-title>{{ __('Delete snippet?') }}</template>
- <gl-alert v-if="errorMessage" variant="danger" class="mb-2" @dismiss="errorMessage = ''">{{
- errorMessage
- }}</gl-alert>
+ <gl-alert
+ v-if="errorMessage"
+ variant="danger"
+ class="mb-2"
+ data-testid="delete-alert"
+ @dismiss="errorMessage = ''"
+ >{{ errorMessage }}</gl-alert
+ >
<gl-sprintf :message="__('Are you sure you want to delete %{name}?')">
<template #name>
@@ -311,6 +322,7 @@ export default {
category="primary"
:disabled="isLoading"
data-qa-selector="delete_snippet_button"
+ data-testid="delete-snippet"
@click="deleteSnippet"
>
<gl-loading-icon v-if="isLoading" size="sm" inline />
diff --git a/app/assets/javascripts/streaming/chunk_writer.js b/app/assets/javascripts/streaming/chunk_writer.js
new file mode 100644
index 00000000000..4bbd0a5f843
--- /dev/null
+++ b/app/assets/javascripts/streaming/chunk_writer.js
@@ -0,0 +1,144 @@
+import { throttle } from 'lodash';
+import { RenderBalancer } from '~/streaming/render_balancer';
+import {
+ BALANCE_RATE,
+ HIGH_FRAME_TIME,
+ LOW_FRAME_TIME,
+ MAX_CHUNK_SIZE,
+ MIN_CHUNK_SIZE,
+ TIMEOUT,
+} from '~/streaming/constants';
+
+const defaultConfig = {
+ balanceRate: BALANCE_RATE,
+ minChunkSize: MIN_CHUNK_SIZE,
+ maxChunkSize: MAX_CHUNK_SIZE,
+ lowFrameTime: LOW_FRAME_TIME,
+ highFrameTime: HIGH_FRAME_TIME,
+ timeout: TIMEOUT,
+};
+
+function concatUint8Arrays(a, b) {
+ const array = new Uint8Array(a.length + b.length);
+ array.set(a, 0);
+ array.set(b, a.length);
+ return array;
+}
+
+// This class is used to write chunks with a balanced size
+// to avoid blocking main thread for too long.
+//
+// A chunk can be:
+// 1. Too small
+// 2. Too large
+// 3. Delayed in time
+//
+// This class resolves all these problems by
+// 1. Splitting or concatenating chunks to met the size criteria
+// 2. Rendering current chunk buffer immediately if enough time has passed
+//
+// The size of the chunk is determined by RenderBalancer,
+// It measures execution time for each chunk write and adjusts next chunk size.
+export class ChunkWriter {
+ buffer = null;
+ decoder = new TextDecoder('utf-8');
+ timeout = null;
+
+ constructor(htmlStream, config) {
+ this.htmlStream = htmlStream;
+
+ const { balanceRate, minChunkSize, maxChunkSize, lowFrameTime, highFrameTime, timeout } = {
+ ...defaultConfig,
+ ...config,
+ };
+
+ // ensure we still render chunks over time if the size criteria is not met
+ this.scheduleAccumulatorFlush = throttle(this.flushAccumulator.bind(this), timeout);
+
+ const averageSize = Math.round((maxChunkSize + minChunkSize) / 2);
+ this.size = Math.max(averageSize, minChunkSize);
+
+ this.balancer = new RenderBalancer({
+ lowFrameTime,
+ highFrameTime,
+ decrease: () => {
+ this.size = Math.round(Math.max(this.size / balanceRate, minChunkSize));
+ },
+ increase: () => {
+ this.size = Math.round(Math.min(this.size * balanceRate, maxChunkSize));
+ },
+ });
+ }
+
+ write(chunk) {
+ this.scheduleAccumulatorFlush.cancel();
+
+ if (this.buffer) {
+ this.buffer = concatUint8Arrays(this.buffer, chunk);
+ } else {
+ this.buffer = chunk;
+ }
+
+ // accumulate chunks until the size is fulfilled
+ if (this.size > this.buffer.length) {
+ this.scheduleAccumulatorFlush();
+ return Promise.resolve();
+ }
+
+ return this.balancedWrite();
+ }
+
+ balancedWrite() {
+ let cursor = 0;
+
+ return this.balancer.render(() => {
+ const chunkPart = this.buffer.subarray(cursor, cursor + this.size);
+ // accumulate chunks until the size is fulfilled
+ // this is a hot path for the last chunkPart of the chunk
+ if (chunkPart.length < this.size) {
+ this.buffer = chunkPart;
+ this.scheduleAccumulatorFlush();
+ return false;
+ }
+
+ this.writeToDom(chunkPart);
+
+ cursor += this.size;
+ if (cursor >= this.buffer.length) {
+ this.buffer = null;
+ return false;
+ }
+ // continue render
+ return true;
+ });
+ }
+
+ writeToDom(chunk, stream = true) {
+ // stream: true allows us to split chunks with multi-part words
+ const decoded = this.decoder.decode(chunk, { stream });
+ this.htmlStream.write(decoded);
+ }
+
+ flushAccumulator() {
+ if (this.buffer) {
+ this.writeToDom(this.buffer);
+ this.buffer = null;
+ }
+ }
+
+ close() {
+ this.scheduleAccumulatorFlush.cancel();
+ if (this.buffer) {
+ // last chunk should have stream: false to indicate the end of the stream
+ this.writeToDom(this.buffer, false);
+ this.buffer = null;
+ }
+ this.htmlStream.close();
+ }
+
+ abort() {
+ this.scheduleAccumulatorFlush.cancel();
+ this.buffer = null;
+ this.htmlStream.abort();
+ }
+}
diff --git a/app/assets/javascripts/streaming/constants.js b/app/assets/javascripts/streaming/constants.js
new file mode 100644
index 00000000000..224d93a7ac1
--- /dev/null
+++ b/app/assets/javascripts/streaming/constants.js
@@ -0,0 +1,9 @@
+// Lower min chunk numbers can make the page loading take incredibly long
+export const MIN_CHUNK_SIZE = 128 * 1024;
+export const MAX_CHUNK_SIZE = 2048 * 1024;
+export const LOW_FRAME_TIME = 32;
+// Tasks that take more than 50ms are considered Long
+// https://web.dev/optimize-long-tasks/
+export const HIGH_FRAME_TIME = 64;
+export const BALANCE_RATE = 1.2;
+export const TIMEOUT = 500;
diff --git a/app/assets/javascripts/streaming/handle_streamed_anchor_link.js b/app/assets/javascripts/streaming/handle_streamed_anchor_link.js
new file mode 100644
index 00000000000..315dc9bb0a0
--- /dev/null
+++ b/app/assets/javascripts/streaming/handle_streamed_anchor_link.js
@@ -0,0 +1,26 @@
+import { throttle } from 'lodash';
+import { scrollToElement } from '~/lib/utils/common_utils';
+import LineHighlighter from '~/blob/line_highlighter';
+
+const noop = () => {};
+
+export function handleStreamedAnchorLink(rootElement) {
+ // "#L100-200" → ['L100', 'L200']
+ const [anchorStart, end] = window.location.hash.substring(1).split('-');
+ const anchorEnd = end ? `L${end}` : anchorStart;
+ if (!anchorStart || document.getElementById(anchorEnd)) return noop;
+
+ const handler = throttle((mutationList, instance) => {
+ if (!document.getElementById(anchorEnd)) return;
+ scrollToElement(document.getElementById(anchorStart));
+ // eslint-disable-next-line no-new
+ new LineHighlighter();
+ instance.disconnect();
+ }, 300);
+
+ const observer = new MutationObserver(handler);
+
+ observer.observe(rootElement, { childList: true, subtree: true });
+
+ return () => observer.disconnect();
+}
diff --git a/app/assets/javascripts/streaming/html_stream.js b/app/assets/javascripts/streaming/html_stream.js
new file mode 100644
index 00000000000..8182f69a607
--- /dev/null
+++ b/app/assets/javascripts/streaming/html_stream.js
@@ -0,0 +1,33 @@
+import { ChunkWriter } from '~/streaming/chunk_writer';
+
+export class HtmlStream {
+ constructor(element) {
+ const streamDocument = document.implementation.createHTMLDocument('stream');
+
+ streamDocument.open();
+ streamDocument.write('<streaming-element>');
+
+ const virtualStreamingElement = streamDocument.querySelector('streaming-element');
+ element.appendChild(document.adoptNode(virtualStreamingElement));
+
+ this.streamDocument = streamDocument;
+ }
+
+ withChunkWriter(config) {
+ return new ChunkWriter(this, config);
+ }
+
+ write(chunk) {
+ // eslint-disable-next-line no-unsanitized/method
+ this.streamDocument.write(chunk);
+ }
+
+ close() {
+ this.streamDocument.write('</streaming-element>');
+ this.streamDocument.close();
+ }
+
+ abort() {
+ this.streamDocument.close();
+ }
+}
diff --git a/app/assets/javascripts/streaming/polyfills.js b/app/assets/javascripts/streaming/polyfills.js
new file mode 100644
index 00000000000..a9a044a3e99
--- /dev/null
+++ b/app/assets/javascripts/streaming/polyfills.js
@@ -0,0 +1,5 @@
+import { createReadableStreamWrapper } from '@mattiasbuelens/web-streams-adapter';
+import { ReadableStream as PolyfillReadableStream } from 'web-streams-polyfill';
+
+// TODO: remove this when our WebStreams API reaches 100% support
+export const toPolyfillReadable = createReadableStreamWrapper(PolyfillReadableStream);
diff --git a/app/assets/javascripts/streaming/rate_limit_stream_requests.js b/app/assets/javascripts/streaming/rate_limit_stream_requests.js
new file mode 100644
index 00000000000..04a592baa16
--- /dev/null
+++ b/app/assets/javascripts/streaming/rate_limit_stream_requests.js
@@ -0,0 +1,87 @@
+const consumeReadableStream = (stream) => {
+ return new Promise((resolve, reject) => {
+ stream.pipeTo(
+ new WritableStream({
+ close: resolve,
+ abort: reject,
+ }),
+ );
+ });
+};
+
+const wait = (timeout) =>
+ new Promise((resolve) => {
+ setTimeout(resolve, timeout);
+ });
+
+// this rate-limiting approach is specific to Web Streams
+// because streams only resolve when they're fully consumed
+// so we need to split each stream into two pieces:
+// one for the rate-limiter (wait for all the bytes to be sent)
+// another for the original consumer
+export const rateLimitStreamRequests = ({
+ factory,
+ total,
+ maxConcurrentRequests,
+ immediateCount = maxConcurrentRequests,
+ timeout = 0,
+}) => {
+ if (total === 0) return [];
+
+ const unsettled = [];
+
+ const pushUnsettled = (promise) => {
+ let res;
+ let rej;
+ const consume = new Promise((resolve, reject) => {
+ res = resolve;
+ rej = reject;
+ });
+ unsettled.push(consume);
+ return promise.then((stream) => {
+ const [first, second] = stream.tee();
+ // eslint-disable-next-line promise/no-nesting
+ consumeReadableStream(first)
+ .then(() => {
+ unsettled.splice(unsettled.indexOf(consume), 1);
+ res();
+ })
+ .catch(rej);
+ return second;
+ }, rej);
+ };
+
+ const immediate = Array.from({ length: Math.min(immediateCount, total) }, (_, i) =>
+ pushUnsettled(factory(i)),
+ );
+
+ const queue = [];
+ const flushQueue = () => {
+ const promises =
+ unsettled.length > maxConcurrentRequests ? unsettled : [...unsettled, wait(timeout)];
+ // errors are handled by the caller
+ // eslint-disable-next-line promise/catch-or-return
+ Promise.race(promises).then(() => {
+ const cb = queue.shift();
+ cb?.();
+ if (queue.length !== 0) {
+ // wait for stream consumer promise to be removed from unsettled
+ queueMicrotask(flushQueue);
+ }
+ });
+ };
+
+ const throttled = Array.from({ length: total - immediateCount }, (_, i) => {
+ return new Promise((resolve, reject) => {
+ queue.push(() => {
+ pushUnsettled(factory(i + immediateCount))
+ .then(resolve)
+ .catch(reject);
+ });
+ });
+ });
+
+ flushQueue();
+
+ return [...immediate, ...throttled];
+};
diff --git a/app/assets/javascripts/streaming/render_balancer.js b/app/assets/javascripts/streaming/render_balancer.js
new file mode 100644
index 00000000000..66929ff3a54
--- /dev/null
+++ b/app/assets/javascripts/streaming/render_balancer.js
@@ -0,0 +1,36 @@
+export class RenderBalancer {
+ previousTimestamp = undefined;
+
+ constructor({ increase, decrease, highFrameTime, lowFrameTime }) {
+ this.increase = increase;
+ this.decrease = decrease;
+ this.highFrameTime = highFrameTime;
+ this.lowFrameTime = lowFrameTime;
+ }
+
+ render(fn) {
+ return new Promise((resolve) => {
+ const callback = (timestamp) => {
+ this.throttle(timestamp);
+ if (fn()) requestAnimationFrame(callback);
+ else resolve();
+ };
+ requestAnimationFrame(callback);
+ });
+ }
+
+ throttle(timestamp) {
+ const { previousTimestamp } = this;
+ this.previousTimestamp = timestamp;
+ if (previousTimestamp === undefined) return;
+
+ const duration = Math.round(timestamp - previousTimestamp);
+ if (!duration) return;
+
+ if (duration >= this.highFrameTime) {
+ this.decrease();
+ } else if (duration < this.lowFrameTime) {
+ this.increase();
+ }
+ }
+}
diff --git a/app/assets/javascripts/streaming/render_html_streams.js b/app/assets/javascripts/streaming/render_html_streams.js
new file mode 100644
index 00000000000..7201e541777
--- /dev/null
+++ b/app/assets/javascripts/streaming/render_html_streams.js
@@ -0,0 +1,40 @@
+import { HtmlStream } from '~/streaming/html_stream';
+
+async function pipeStreams(domWriter, streamPromises) {
+ try {
+ for await (const stream of streamPromises.slice(0, -1)) {
+ await stream.pipeTo(domWriter, { preventClose: true });
+ }
+ const stream = await streamPromises[streamPromises.length - 1];
+ await stream.pipeTo(domWriter);
+ } catch (error) {
+ domWriter.abort(error);
+ }
+}
+
+// this function (and the rest of the pipeline) expects polyfilled streams
+// do not pass native streams here unless our browser support allows for it
+// TODO: remove this notice when our WebStreams API support reaches 100%
+export function renderHtmlStreams(streamPromises, element, config) {
+ if (streamPromises.length === 0) return Promise.resolve();
+
+ const chunkedHtmlStream = new HtmlStream(element).withChunkWriter(config);
+
+ return new Promise((resolve, reject) => {
+ const domWriter = new WritableStream({
+ write(chunk) {
+ return chunkedHtmlStream.write(chunk);
+ },
+ close() {
+ chunkedHtmlStream.close();
+ resolve();
+ },
+ abort(error) {
+ chunkedHtmlStream.abort();
+ reject(error);
+ },
+ });
+
+ pipeStreams(domWriter, streamPromises);
+ });
+}
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher.vue b/app/assets/javascripts/super_sidebar/components/context_switcher.vue
index f1ddb8290a0..b3d4ecdda47 100644
--- a/app/assets/javascripts/super_sidebar/components/context_switcher.vue
+++ b/app/assets/javascripts/super_sidebar/components/context_switcher.vue
@@ -1,82 +1,136 @@
<script>
-import { GlAvatar, GlSearchBoxByType } from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
+import { GlSearchBoxByType } 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 { contextSwitcherItems } from '../mock_data';
+import { trackContextAccess, formatContextSwitcherItems } from '../utils';
import NavItem from './nav_item.vue';
+import ProjectsList from './projects_list.vue';
+import GroupsList from './groups_list.vue';
export default {
+ i18n: {
+ contextNavigation: s__('Navigation|Context navigation'),
+ switchTo: s__('Navigation|Switch to...'),
+ searchPlaceholder: s__('Navigation|Search for projects or groups'),
+ },
+ apollo: {
+ groupsAndProjects: {
+ query: searchUserProjectsAndGroups,
+ debounce: DEFAULT_DEBOUNCE_AND_THROTTLE_MS,
+ manual: true,
+ variables() {
+ return {
+ username: this.username,
+ search: this.searchString,
+ };
+ },
+ result(response) {
+ try {
+ const {
+ data: {
+ projects: { nodes: projects },
+ user: {
+ groups: { nodes: groups },
+ },
+ },
+ } = response;
+
+ this.projects = formatContextSwitcherItems(projects);
+ this.groups = formatContextSwitcherItems(groups);
+ } catch (e) {
+ Sentry.captureException(e);
+ }
+ },
+ error(e) {
+ Sentry.captureException(e);
+ },
+ skip() {
+ return !this.searchString;
+ },
+ },
+ },
components: {
- GlAvatar,
GlSearchBoxByType,
NavItem,
+ ProjectsList,
+ GroupsList,
},
- i18n: {
- contextNavigation: s__('Navigation|Context navigation'),
- switchTo: s__('Navigation|Switch to...'),
- recentProjects: s__('Navigation|Recent projects'),
- recentGroups: s__('Navigation|Recent groups'),
+ props: {
+ username: {
+ type: String,
+ required: true,
+ },
+ projectsPath: {
+ type: String,
+ required: true,
+ },
+ groupsPath: {
+ type: String,
+ required: true,
+ },
+ currentContext: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
},
- contextSwitcherItems,
- viewAllProjectsItem: {
- title: s__('Navigation|View all projects'),
- link: '/projects',
- icon: 'project',
+ data() {
+ return {
+ searchString: '',
+ projects: [],
+ groups: [],
+ };
},
- viewAllGroupsItem: {
- title: s__('Navigation|View all groups'),
- link: '/groups',
- icon: 'group',
+ computed: {
+ isSearch() {
+ return Boolean(this.searchString);
+ },
+ },
+ contextSwitcherItems,
+ created() {
+ if (this.currentContext.namespace) {
+ trackContextAccess(this.username, this.currentContext);
+ }
},
};
</script>
<template>
<div>
- <gl-search-box-by-type />
+ <div class="gl-p-1 gl-border-b gl-border-gray-50 gl-bg-white">
+ <gl-search-box-by-type
+ v-model="searchString"
+ class="context-switcher-search-box"
+ :placeholder="$options.i18n.searchPlaceholder"
+ borderless
+ />
+ </div>
<nav :aria-label="$options.i18n.contextNavigation">
<ul class="gl-p-0 gl-list-style-none">
- <li>
+ <li v-if="!isSearch">
<div aria-hidden="true" class="gl-font-weight-bold gl-px-3 gl-py-3">
{{ $options.i18n.switchTo }}
</div>
<ul :aria-label="$options.i18n.switchTo" class="gl-p-0">
<nav-item :item="$options.contextSwitcherItems.yourWork" />
+ <nav-item :item="$options.contextSwitcherItems.explore" />
</ul>
</li>
- <li>
- <div aria-hidden="true" class="gl-font-weight-bold gl-px-3 gl-py-3">
- {{ $options.i18n.recentProjects }}
- </div>
- <ul :aria-label="$options.i18n.recentProjects" class="gl-p-0">
- <nav-item
- v-for="project in $options.contextSwitcherItems.recentProjects"
- :key="project.title"
- :item="project"
- >
- <template #icon>
- <gl-avatar shape="rect" :size="32" :src="project.avatar" />
- </template>
- </nav-item>
- <nav-item :item="$options.viewAllProjectsItem" />
- </ul>
- </li>
- <li>
- <div aria-hidden="true" class="gl-font-weight-bold gl-px-3 gl-py-3">
- {{ $options.i18n.recentGroups }}
- </div>
- <ul :aria-label="$options.i18n.recentGroups" class="gl-p-0">
- <nav-item
- v-for="project in $options.contextSwitcherItems.recentGroups"
- :key="project.title"
- :item="project"
- >
- <template #icon>
- <gl-avatar shape="rect" :size="32" :src="project.avatar" />
- </template>
- </nav-item>
- <nav-item :item="$options.viewAllGroupsItem" />
- </ul>
- </li>
+ <projects-list
+ :username="username"
+ :view-all-link="projectsPath"
+ :is-search="isSearch"
+ :search-results="projects"
+ />
+ <groups-list
+ :username="username"
+ :view-all-link="groupsPath"
+ :is-search="isSearch"
+ :search-results="groups"
+ />
</ul>
</nav>
</div>
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
index b6f058f7aee..e0b6870872c 100644
--- a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
+++ b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
@@ -11,6 +11,9 @@ export default {
CollapseToggle: GlCollapseToggleDirective,
},
props: {
+ /*
+ * Contains metadata about the current view, e.g. `id`, `title` and `avatar`
+ */
context: {
type: Object,
required: true,
@@ -24,6 +27,9 @@ export default {
collapseIcon() {
return this.expanded ? 'chevron-up' : 'chevron-down';
},
+ avatarShape() {
+ return this.context.avatar_shape || 'rect';
+ },
},
};
</script>
@@ -32,13 +38,27 @@ export default {
<button
v-collapse-toggle.context-switcher
type="button"
- class="context-switcher-toggle gl-bg-transparent gl-border-0 border-top border-bottom gl-border-gray-a-08 gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-pl-3 gl-pr-5 gl-h-8"
+ class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-border-0 border-top border-bottom gl-border-gray-a-08 gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-h-8"
>
- <gl-avatar :size="32" shape="rect" :src="context.avatar" class="gl-mr-3" />
+ <span
+ v-if="context.icon"
+ class="gl-avatar avatar-container gl-bg-t-gray-a-08 icon-avatar rect-avatar s24 gl-mr-3 gl-ml-4"
+ >
+ <gl-icon :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"
+ class="gl-mr-3 gl-ml-4"
+ />
<div class="gl-overflow-auto">
<gl-truncate :text="context.title" />
</div>
- <span class="gl-flex-grow-1 gl-text-right">
+ <span class="gl-flex-grow-1 gl-text-right gl-mr-4">
<gl-icon :name="collapseIcon" />
</span>
</button>
diff --git a/app/assets/javascripts/super_sidebar/components/counter.vue b/app/assets/javascripts/super_sidebar/components/counter.vue
index 62a1e5a6b20..e79b609545e 100644
--- a/app/assets/javascripts/super_sidebar/components/counter.vue
+++ b/app/assets/javascripts/super_sidebar/components/counter.vue
@@ -40,7 +40,7 @@ export default {
:is="component"
:aria-label="ariaLabel"
:href="href"
- class="counter gl-display-block gl-flex-grow-1 gl-text-center gl-py-3 gl-bg-gray-10 gl-rounded-base gl-text-gray-900 gl-border gl-border-gray-a-08 gl-font-sm gl-hover-text-gray-900 gl-hover-text-decoration-none"
+ class="counter gl-display-block gl-flex-grow-1 gl-text-center 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-font-sm gl-hover-text-gray-900 gl-hover-text-decoration-none"
>
<gl-icon aria-hidden="true" :name="icon" />
<span v-if="count" aria-hidden="true" class="gl-ml-1">{{ count }}</span>
diff --git a/app/assets/javascripts/super_sidebar/components/create_menu.vue b/app/assets/javascripts/super_sidebar/components/create_menu.vue
index e92a6cbf5f5..d3bb31a69fa 100644
--- a/app/assets/javascripts/super_sidebar/components/create_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/create_menu.vue
@@ -30,6 +30,7 @@ export default {
text-sr-only
:toggle-text="$options.i18n.createNew"
:toggle-id="$options.toggleId"
+ data-qa-selector="new_menu_toggle"
/>
<gl-tooltip :target="`#${$options.toggleId}`" placement="bottom" container="#super-sidebar">
{{ $options.i18n.createNew }}
diff --git a/app/assets/javascripts/super_sidebar/components/frequent_items_list.vue b/app/assets/javascripts/super_sidebar/components/frequent_items_list.vue
new file mode 100644
index 00000000000..5269c7f8d5e
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/frequent_items_list.vue
@@ -0,0 +1,77 @@
+<script>
+import * as Sentry from '@sentry/browser';
+import AccessorUtilities from '~/lib/utils/accessor';
+import { getTopFrequentItems, formatContextSwitcherItems } from '../utils';
+import ItemsList from './items_list.vue';
+
+export default {
+ components: {
+ ItemsList,
+ },
+ 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.getItemsFromLocalStorage();
+ },
+ methods: {
+ getItemsFromLocalStorage() {
+ if (!AccessorUtilities.canUseLocalStorage()) {
+ return;
+ }
+ try {
+ const parsedCachedFrequentItems = JSON.parse(localStorage.getItem(this.storageKey));
+ const topFrequentItems = getTopFrequentItems(parsedCachedFrequentItems, this.maxItems);
+ this.cachedFrequentItems = formatContextSwitcherItems(topFrequentItems);
+ } catch (e) {
+ Sentry.captureException(e);
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <li class="gl-border-t gl-border-gray-50 gl-mx-3 gl-py-3">
+ <div
+ data-testid="list-title"
+ aria-hidden="true"
+ class="gl-text-transform-uppercase gl-text-secondary gl-font-weight-bold gl-font-xs gl-line-height-12 gl-letter-spacing-06em gl-my-3"
+ >
+ {{ title }}
+ </div>
+ <div v-if="isEmpty" data-testid="empty-text" class="gl-text-gray-500 gl-font-sm gl-my-3">
+ {{ pristineText }}
+ </div>
+ <items-list :aria-label="title" :items="cachedFrequentItems">
+ <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/components/global_search.vue b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue
new file mode 100644
index 00000000000..6798607b954
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue
@@ -0,0 +1,320 @@
+<script>
+import {
+ GlSearchBoxByType,
+ GlOutsideDirective as Outside,
+ GlIcon,
+ GlToken,
+ GlTooltipDirective,
+ GlResizeObserverDirective,
+} from '@gitlab/ui';
+import { mapState, mapActions, mapGetters } from 'vuex';
+import { debounce } from 'lodash';
+import { visitUrl } from '~/lib/utils/url_utility';
+import { truncate } from '~/lib/utils/text_utility';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+import { sprintf } from '~/locale';
+import Tracking from '~/tracking';
+import DropdownKeyboardNavigation from '~/vue_shared/components/dropdown_keyboard_navigation.vue';
+import {
+ SEARCH_GITLAB,
+ SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN,
+ SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN,
+ SEARCH_DESCRIBED_BY_DEFAULT,
+ SEARCH_DESCRIBED_BY_UPDATED,
+ SEARCH_RESULTS_LOADING,
+ SEARCH_RESULTS_SCOPE,
+ KBD_HELP,
+} from '~/vue_shared/global_search/constants';
+import {
+ FIRST_DROPDOWN_INDEX,
+ SEARCH_BOX_INDEX,
+ SEARCH_INPUT_DESCRIPTION,
+ SEARCH_RESULTS_DESCRIPTION,
+ SEARCH_SHORTCUTS_MIN_CHARACTERS,
+ SCOPE_TOKEN_MAX_LENGTH,
+ INPUT_FIELD_PADDING,
+ IS_SEARCHING,
+ IS_FOCUSED,
+ IS_NOT_FOCUSED,
+} from '../constants';
+import HeaderSearchAutocompleteItems from './global_search_autocomplete_items.vue';
+import HeaderSearchDefaultItems from './global_search_default_items.vue';
+import HeaderSearchScopedItems from './global_search_scoped_items.vue';
+
+export default {
+ name: 'HeaderSearchApp',
+ i18n: {
+ SEARCH_GITLAB,
+ SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN,
+ SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN,
+ SEARCH_DESCRIBED_BY_DEFAULT,
+ SEARCH_DESCRIBED_BY_UPDATED,
+ SEARCH_RESULTS_LOADING,
+ SEARCH_RESULTS_SCOPE,
+ KBD_HELP,
+ },
+ directives: { Outside, GlTooltip: GlTooltipDirective, GlResizeObserverDirective },
+ components: {
+ GlSearchBoxByType,
+ HeaderSearchDefaultItems,
+ HeaderSearchScopedItems,
+ HeaderSearchAutocompleteItems,
+ DropdownKeyboardNavigation,
+ GlIcon,
+ GlToken,
+ },
+ data() {
+ return {
+ showDropdown: false,
+ isFocused: false,
+ currentFocusIndex: SEARCH_BOX_INDEX,
+ };
+ },
+ computed: {
+ ...mapState(['search', 'loading', 'searchContext']),
+ ...mapGetters(['searchQuery', 'searchOptions']),
+ searchText: {
+ get() {
+ return this.search;
+ },
+ set(value) {
+ this.setSearch(value);
+ },
+ },
+ currentFocusedOption() {
+ return this.searchOptions[this.currentFocusIndex];
+ },
+ currentFocusedId() {
+ return this.currentFocusedOption?.html_id;
+ },
+ isLoggedIn() {
+ return Boolean(gon?.current_username);
+ },
+ showSearchDropdown() {
+ if (!this.showDropdown || !this.isLoggedIn) {
+ return false;
+ }
+ return this.searchOptions?.length > 0;
+ },
+ showDefaultItems() {
+ return !this.searchText;
+ },
+ searchTermOverMin() {
+ return this.searchText?.length > SEARCH_SHORTCUTS_MIN_CHARACTERS;
+ },
+ defaultIndex() {
+ if (this.showDefaultItems) {
+ return SEARCH_BOX_INDEX;
+ }
+ return FIRST_DROPDOWN_INDEX;
+ },
+
+ searchInputDescribeBy() {
+ if (this.isLoggedIn) {
+ return this.$options.i18n.SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN;
+ }
+ return this.$options.i18n.SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN;
+ },
+ dropdownResultsDescription() {
+ if (!this.showSearchDropdown) {
+ return ''; // This allows aria-live to see register an update when the dropdown is shown
+ }
+
+ if (this.showDefaultItems) {
+ return sprintf(this.$options.i18n.SEARCH_DESCRIBED_BY_DEFAULT, {
+ count: this.searchOptions.length,
+ });
+ }
+
+ return this.loading
+ ? this.$options.i18n.SEARCH_RESULTS_LOADING
+ : sprintf(this.$options.i18n.SEARCH_DESCRIBED_BY_UPDATED, {
+ count: this.searchOptions.length,
+ });
+ },
+ searchBarClasses() {
+ return {
+ [IS_SEARCHING]: this.searchTermOverMin,
+ [IS_FOCUSED]: this.isFocused,
+ [IS_NOT_FOCUSED]: !this.isFocused,
+ };
+ },
+ showScopeHelp() {
+ return this.searchTermOverMin && this.isFocused;
+ },
+ searchBarItem() {
+ return this.searchOptions?.[0];
+ },
+ infieldHelpContent() {
+ return this.searchBarItem?.scope || this.searchBarItem?.description;
+ },
+ infieldHelpIcon() {
+ return this.searchBarItem?.icon;
+ },
+ scopeTokenTitle() {
+ return sprintf(this.$options.i18n.SEARCH_RESULTS_SCOPE, {
+ scope: this.infieldHelpContent,
+ });
+ },
+ },
+ methods: {
+ ...mapActions(['setSearch', 'fetchAutocompleteOptions', 'clearAutocomplete']),
+ openDropdown() {
+ this.showDropdown = true;
+
+ // check isFocused state to avoid firing duplicate events
+ if (!this.isFocused) {
+ this.isFocused = true;
+ this.$emit('expandSearchBar', true);
+
+ Tracking.event(undefined, 'focus_input', {
+ label: 'global_search',
+ property: 'navigation_top',
+ });
+ }
+ },
+ closeDropdown() {
+ this.showDropdown = false;
+ },
+ collapseAndCloseSearchBar() {
+ // we need a delay on this method
+ // for the search bar not to remove
+ // the clear button from dom
+ // and register clicks on dropdown items
+ setTimeout(() => {
+ this.showDropdown = false;
+ this.isFocused = false;
+ this.$emit('collapseSearchBar');
+
+ Tracking.event(undefined, 'blur_input', {
+ label: 'global_search',
+ property: 'navigation_top',
+ });
+ }, 200);
+ },
+ submitSearch() {
+ if (this.search?.length <= SEARCH_SHORTCUTS_MIN_CHARACTERS && this.currentFocusIndex < 0) {
+ return null;
+ }
+ return visitUrl(this.currentFocusedOption?.url || this.searchQuery);
+ },
+ getAutocompleteOptions: debounce(function debouncedSearch(searchTerm) {
+ this.openDropdown();
+ if (!searchTerm) {
+ this.clearAutocomplete();
+ } else {
+ this.fetchAutocompleteOptions();
+ }
+ }, DEFAULT_DEBOUNCE_AND_THROTTLE_MS),
+ getTruncatedScope(scope) {
+ return truncate(scope, SCOPE_TOKEN_MAX_LENGTH);
+ },
+ observeTokenWidth({ contentRect: { width } }) {
+ const inputField = this.$refs?.searchInputBox?.$el?.querySelector('input');
+ if (!inputField) {
+ return;
+ }
+ inputField.style.paddingRight = `${width + INPUT_FIELD_PADDING}px`;
+ },
+ },
+ SEARCH_BOX_INDEX,
+ FIRST_DROPDOWN_INDEX,
+ SEARCH_INPUT_DESCRIPTION,
+ SEARCH_RESULTS_DESCRIPTION,
+};
+</script>
+
+<template>
+ <form
+ v-outside="closeDropdown"
+ role="search"
+ :aria-label="$options.i18n.SEARCH_GITLAB"
+ class="header-search gl-relative gl-rounded-base gl-w-full"
+ :class="searchBarClasses"
+ data-testid="header-search-form"
+ >
+ <gl-search-box-by-type
+ id="search"
+ ref="searchInputBox"
+ v-model="searchText"
+ role="searchbox"
+ class="gl-z-index-1"
+ data-qa-selector="search_term_field"
+ autocomplete="off"
+ :placeholder="$options.i18n.SEARCH_GITLAB"
+ :aria-activedescendant="currentFocusedId"
+ :aria-describedby="$options.SEARCH_INPUT_DESCRIPTION"
+ @focus="openDropdown"
+ @click="openDropdown"
+ @blur="collapseAndCloseSearchBar"
+ @input="getAutocompleteOptions"
+ @keydown.enter.stop.prevent="submitSearch"
+ @keydown.esc.stop.prevent="closeDropdown"
+ />
+ <gl-token
+ v-if="showScopeHelp"
+ v-gl-resize-observer-directive="observeTokenWidth"
+ class="in-search-scope-help"
+ :view-only="true"
+ :title="scopeTokenTitle"
+ ><gl-icon
+ v-if="infieldHelpIcon"
+ class="gl-mr-2"
+ :aria-label="infieldHelpContent"
+ :name="infieldHelpIcon"
+ :size="16"
+ />{{
+ getTruncatedScope(
+ sprintf($options.i18n.SEARCH_RESULTS_SCOPE, {
+ scope: infieldHelpContent,
+ }),
+ )
+ }}
+ </gl-token>
+ <kbd
+ v-show="!isFocused"
+ v-gl-tooltip.bottom.hover.html
+ class="gl-absolute gl-right-3 gl-top-0 gl-z-index-1 keyboard-shortcut-helper"
+ :title="$options.i18n.KBD_HELP"
+ >/</kbd
+ >
+ <span :id="$options.SEARCH_INPUT_DESCRIPTION" role="region" class="gl-sr-only">{{
+ searchInputDescribeBy
+ }}</span>
+ <span
+ role="region"
+ :data-testid="$options.SEARCH_RESULTS_DESCRIPTION"
+ class="gl-sr-only"
+ aria-live="polite"
+ aria-atomic="true"
+ >
+ {{ dropdownResultsDescription }}
+ </span>
+ <div
+ v-if="showSearchDropdown"
+ data-testid="header-search-dropdown-menu"
+ class="header-search-dropdown-menu gl-overflow-y-auto gl-absolute gl-w-full gl-bg-white gl-border-1 gl-rounded-base gl-border-solid gl-border-gray-200 gl-shadow-x0-y2-b4-s0 gl-mt-3"
+ >
+ <div class="header-search-dropdown-content gl-py-2">
+ <dropdown-keyboard-navigation
+ v-model="currentFocusIndex"
+ :max="searchOptions.length - 1"
+ :min="$options.FIRST_DROPDOWN_INDEX"
+ :default-index="defaultIndex"
+ @tab="closeDropdown"
+ />
+ <header-search-default-items
+ v-if="showDefaultItems"
+ :current-focused-option="currentFocusedOption"
+ />
+ <template v-else>
+ <header-search-scoped-items
+ v-if="searchTermOverMin"
+ :current-focused-option="currentFocusedOption"
+ />
+ <header-search-autocomplete-items :current-focused-option="currentFocusedOption" />
+ </template>
+ </div>
+ </div>
+ </form>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue
new file mode 100644
index 00000000000..1838214def6
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue
@@ -0,0 +1,167 @@
+<script>
+import {
+ GlDropdownItem,
+ GlDropdownSectionHeader,
+ GlDropdownDivider,
+ GlAvatar,
+ GlAlert,
+ GlLoadingIcon,
+} from '@gitlab/ui';
+import { mapState, mapGetters } from 'vuex';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import highlight from '~/lib/utils/highlight';
+import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
+import { truncateNamespace } from '~/lib/utils/text_utility';
+import {
+ GROUPS_CATEGORY,
+ PROJECTS_CATEGORY,
+ MERGE_REQUEST_CATEGORY,
+ ISSUES_CATEGORY,
+ RECENT_EPICS_CATEGORY,
+ AUTOCOMPLETE_ERROR_MESSAGE,
+} from '~/vue_shared/global_search/constants';
+import { LARGE_AVATAR_PX, SMALL_AVATAR_PX } from '../constants';
+
+export default {
+ name: 'HeaderSearchAutocompleteItems',
+ i18n: {
+ AUTOCOMPLETE_ERROR_MESSAGE,
+ },
+ components: {
+ GlDropdownItem,
+ GlDropdownSectionHeader,
+ GlDropdownDivider,
+ GlAvatar,
+ GlAlert,
+ GlLoadingIcon,
+ },
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ currentFocusedOption: {
+ type: Object,
+ required: false,
+ default: () => null,
+ },
+ },
+ computed: {
+ ...mapState(['search', 'loading', 'autocompleteError', 'searchContext']),
+ ...mapGetters(['autocompleteGroupedSearchOptions']),
+ },
+ watch: {
+ currentFocusedOption() {
+ const focusedElement = this.$refs[this.currentFocusedOption?.html_id]?.[0]?.$el;
+
+ if (focusedElement) {
+ focusedElement.scrollIntoView(false);
+ }
+ },
+ },
+ methods: {
+ truncateNamespace(string) {
+ if (string.split(' / ').length > 2) {
+ return truncateNamespace(string);
+ }
+
+ return string;
+ },
+ highlightedName(val) {
+ return highlight(val, this.search);
+ },
+ avatarSize(data) {
+ if (data.category === GROUPS_CATEGORY || data.category === PROJECTS_CATEGORY) {
+ return LARGE_AVATAR_PX;
+ }
+
+ return SMALL_AVATAR_PX;
+ },
+ isOptionFocused(data) {
+ return this.currentFocusedOption?.html_id === data.html_id;
+ },
+ isProjectsCategory(data) {
+ return data.category === PROJECTS_CATEGORY;
+ },
+ getEntityId(data) {
+ switch (data.category) {
+ case GROUPS_CATEGORY:
+ case RECENT_EPICS_CATEGORY:
+ return data.group_id || data.id || this.searchContext?.group?.id;
+ case PROJECTS_CATEGORY:
+ case ISSUES_CATEGORY:
+ case MERGE_REQUEST_CATEGORY:
+ return data.project_id || data.id || this.searchContext?.project?.id;
+ default:
+ return data.id;
+ }
+ },
+ getEntitytName(data) {
+ switch (data.category) {
+ case GROUPS_CATEGORY:
+ case RECENT_EPICS_CATEGORY:
+ return data.group_name || data.value || data.label || this.searchContext?.group?.name;
+ case PROJECTS_CATEGORY:
+ case ISSUES_CATEGORY:
+ case MERGE_REQUEST_CATEGORY:
+ return data.project_name || data.value || data.label || this.searchContext?.project?.name;
+ default:
+ return data.label;
+ }
+ },
+ },
+ AVATAR_SHAPE_OPTION_RECT,
+};
+</script>
+
+<template>
+ <div>
+ <template v-if="!loading">
+ <div v-for="(option, index) in autocompleteGroupedSearchOptions" :key="option.category">
+ <gl-dropdown-divider v-if="index > 0" />
+ <gl-dropdown-section-header>{{ option.category }}</gl-dropdown-section-header>
+ <gl-dropdown-item
+ v-for="data in option.data"
+ :id="data.html_id"
+ :ref="data.html_id"
+ :key="data.html_id"
+ :class="{ 'gl-bg-gray-50': isOptionFocused(data) }"
+ :aria-selected="isOptionFocused(data)"
+ :aria-label="data.label"
+ tabindex="-1"
+ :href="data.url"
+ >
+ <div class="gl-display-flex gl-align-items-center" aria-hidden="true">
+ <gl-avatar
+ v-if="data.avatar_url !== undefined"
+ :src="data.avatar_url"
+ :entity-id="getEntityId(data)"
+ :entity-name="getEntitytName(data)"
+ :size="avatarSize(data)"
+ :shape="$options.AVATAR_SHAPE_OPTION_RECT"
+ />
+ <span class="gl-display-flex gl-flex-direction-column">
+ <span
+ v-safe-html="highlightedName(data.value || data.label)"
+ class="gl-text-gray-900"
+ ></span>
+ <span
+ v-if="data.value"
+ v-safe-html="truncateNamespace(data.label)"
+ class="gl-font-sm gl-text-gray-500"
+ ></span>
+ </span>
+ </div>
+ </gl-dropdown-item>
+ </div>
+ </template>
+ <gl-loading-icon v-else size="lg" class="my-4" />
+ <gl-alert
+ v-if="autocompleteError"
+ class="gl-text-body gl-mt-2"
+ :dismissible="false"
+ variant="danger"
+ >
+ {{ $options.i18n.AUTOCOMPLETE_ERROR_MESSAGE }}
+ </gl-alert>
+ </div>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_items.vue b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_items.vue
new file mode 100644
index 00000000000..f0d398297e9
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_items.vue
@@ -0,0 +1,58 @@
+<script>
+import { GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui';
+import { mapState, mapGetters } from 'vuex';
+import { ALL_GITLAB } from '~/vue_shared/global_search/constants';
+
+export default {
+ name: 'HeaderSearchDefaultItems',
+ i18n: {
+ ALL_GITLAB,
+ },
+ components: {
+ GlDropdownSectionHeader,
+ GlDropdownItem,
+ },
+ props: {
+ currentFocusedOption: {
+ type: Object,
+ required: false,
+ default: () => null,
+ },
+ },
+ computed: {
+ ...mapState(['searchContext']),
+ ...mapGetters(['defaultSearchOptions']),
+ sectionHeader() {
+ return (
+ this.searchContext?.project?.name ||
+ this.searchContext?.group?.name ||
+ this.$options.i18n.ALL_GITLAB
+ );
+ },
+ },
+ methods: {
+ isOptionFocused(option) {
+ return this.currentFocusedOption?.html_id === option.html_id;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-dropdown-section-header>{{ sectionHeader }}</gl-dropdown-section-header>
+ <gl-dropdown-item
+ v-for="option in defaultSearchOptions"
+ :id="option.html_id"
+ :ref="option.html_id"
+ :key="option.html_id"
+ :class="{ 'gl-bg-gray-50': isOptionFocused(option) }"
+ :aria-selected="isOptionFocused(option)"
+ :aria-label="option.title"
+ tabindex="-1"
+ :href="option.url"
+ >
+ <span aria-hidden="true">{{ option.title }}</span>
+ </gl-dropdown-item>
+ </div>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_scoped_items.vue b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_scoped_items.vue
new file mode 100644
index 00000000000..1ef88492b23
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_scoped_items.vue
@@ -0,0 +1,87 @@
+<script>
+import { GlDropdownItem, GlIcon, GlToken } from '@gitlab/ui';
+import { mapState, mapGetters } from 'vuex';
+import { s__, sprintf } from '~/locale';
+import { truncate } from '~/lib/utils/text_utility';
+import { SCOPED_SEARCH_ITEM_ARIA_LABEL } from '~/vue_shared/global_search/constants';
+import { SCOPE_TOKEN_MAX_LENGTH } from '../constants';
+
+export default {
+ name: 'HeaderSearchScopedItems',
+ i18n: {
+ SCOPED_SEARCH_ITEM_ARIA_LABEL,
+ },
+ components: {
+ GlDropdownItem,
+ GlIcon,
+ GlToken,
+ },
+ props: {
+ currentFocusedOption: {
+ type: Object,
+ required: false,
+ default: () => null,
+ },
+ },
+ computed: {
+ ...mapState(['search']),
+ ...mapGetters(['scopedSearchOptions', 'autocompleteGroupedSearchOptions']),
+ },
+ methods: {
+ isOptionFocused(option) {
+ return this.currentFocusedOption?.html_id === option.html_id;
+ },
+ ariaLabel(option) {
+ return sprintf(this.$options.i18n.SCOPED_SEARCH_ITEM_ARIA_LABEL, {
+ search: this.search,
+ description: option.description || option.icon,
+ scope: option.scope || '',
+ });
+ },
+ titleLabel(option) {
+ return sprintf(s__('GlobalSearch|in %{scope}'), {
+ search: this.search,
+ scope: option.scope || option.description,
+ });
+ },
+ getTruncatedScope(scope) {
+ return truncate(scope, SCOPE_TOKEN_MAX_LENGTH);
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-dropdown-item
+ v-for="option in scopedSearchOptions"
+ :id="option.html_id"
+ :ref="option.html_id"
+ :key="option.html_id"
+ class="gl-max-w-full"
+ :class="{ 'gl-bg-gray-50': isOptionFocused(option) }"
+ :aria-selected="isOptionFocused(option)"
+ :aria-label="ariaLabel(option)"
+ tabindex="-1"
+ :href="option.url"
+ :title="titleLabel(option)"
+ >
+ <span
+ ref="token-text-content"
+ class="gl-display-flex gl-justify-content-start search-text-content gl-line-height-24 gl-align-items-start gl-flex-direction-row gl-w-full"
+ >
+ <gl-icon name="search" class="gl-flex-shrink-0 gl-mr-2 gl-relative gl-pt-2" />
+ <span class="gl-flex-grow-1 gl-relative">
+ <gl-token
+ class="in-dropdown-scope-help has-icon gl-flex-shrink-0 gl-relative gl-white-space-nowrap gl-float-right gl-mr-n3!"
+ :view-only="true"
+ >
+ <gl-icon v-if="option.icon" :name="option.icon" class="gl-mr-2" />
+ <span>{{ getTruncatedScope(titleLabel(option)) }}</span>
+ </gl-token>
+ {{ search }}
+ </span>
+ </span>
+ </gl-dropdown-item>
+ </div>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/constants.js b/app/assets/javascripts/super_sidebar/components/global_search/constants.js
new file mode 100644
index 00000000000..b9bb4e573fd
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/constants.js
@@ -0,0 +1,33 @@
+export const ICON_PROJECT = 'project';
+
+export const ICON_GROUP = 'group';
+
+export const ICON_SUBGROUP = 'subgroup';
+
+export const LARGE_AVATAR_PX = 32;
+
+export const SMALL_AVATAR_PX = 16;
+
+export const FIRST_DROPDOWN_INDEX = 0;
+
+export const SEARCH_BOX_INDEX = -1;
+
+export const SEARCH_SHORTCUTS_MIN_CHARACTERS = 2;
+
+export const SEARCH_INPUT_DESCRIPTION = 'search-input-description';
+
+export const SEARCH_RESULTS_DESCRIPTION = 'search-results-description';
+
+export const SCOPE_TOKEN_MAX_LENGTH = 36;
+
+export const INPUT_FIELD_PADDING = 52;
+
+export const HEADER_INIT_EVENTS = ['input', 'focus'];
+
+export const IS_SEARCHING = 'is-searching';
+export const IS_FOCUSED = 'is-focused';
+export const IS_NOT_FOCUSED = 'is-not-focused';
+
+export const FETCH_TYPES = ['generic', 'search'];
+
+export const SEARCH_INPUT_FIELD_MAX_WIDTH = '640px';
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/store/actions.js b/app/assets/javascripts/super_sidebar/components/global_search/store/actions.js
new file mode 100644
index 00000000000..a0f9e594506
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/store/actions.js
@@ -0,0 +1,45 @@
+import { omitBy, isNil } from 'lodash';
+import { objectToQuery } from '~/lib/utils/url_utility';
+import axios from '~/lib/utils/axios_utils';
+import { FETCH_TYPES } from '../constants';
+import * as types from './mutation_types';
+
+export const autocompleteQuery = ({ state, fetchType }) => {
+ const query = omitBy(
+ {
+ term: state.search,
+ project_id: state.searchContext?.project?.id,
+ project_ref: state.searchContext?.ref,
+ filter: fetchType,
+ },
+ isNil,
+ );
+
+ return `${state.autocompletePath}?${objectToQuery(query)}`;
+};
+
+const doFetch = ({ commit, state, fetchType }) => {
+ return axios
+ .get(autocompleteQuery({ state, fetchType }))
+ .then(({ data }) => {
+ commit(types.RECEIVE_AUTOCOMPLETE_SUCCESS, data);
+ })
+ .catch(() => {
+ commit(types.RECEIVE_AUTOCOMPLETE_ERROR);
+ });
+};
+
+export const fetchAutocompleteOptions = ({ commit, state }) => {
+ commit(types.REQUEST_AUTOCOMPLETE);
+ const promises = FETCH_TYPES.map((fetchType) => doFetch({ commit, state, fetchType }));
+
+ return Promise.all(promises);
+};
+
+export const clearAutocomplete = ({ commit }) => {
+ commit(types.CLEAR_AUTOCOMPLETE);
+};
+
+export const setSearch = ({ commit }, value) => {
+ commit(types.SET_SEARCH, value);
+};
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
new file mode 100644
index 00000000000..f86463b94d1
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js
@@ -0,0 +1,220 @@
+import { omitBy, isNil } from 'lodash';
+import { objectToQuery } from '~/lib/utils/url_utility';
+
+import {
+ MSG_ISSUES_ASSIGNED_TO_ME,
+ MSG_ISSUES_IVE_CREATED,
+ MSG_MR_ASSIGNED_TO_ME,
+ MSG_MR_IM_REVIEWER,
+ MSG_MR_IVE_CREATED,
+ MSG_IN_ALL_GITLAB,
+ PROJECTS_CATEGORY,
+ GROUPS_CATEGORY,
+ DROPDOWN_ORDER,
+} from '~/vue_shared/global_search/constants';
+import {
+ ICON_GROUP,
+ ICON_SUBGROUP,
+ ICON_PROJECT,
+ SEARCH_SHORTCUTS_MIN_CHARACTERS,
+} from '../constants';
+
+export const searchQuery = (state) => {
+ const query = omitBy(
+ {
+ search: state.search,
+ nav_source: 'navbar',
+ project_id: state.searchContext?.project?.id,
+ group_id: state.searchContext?.group?.id,
+ scope: state.searchContext?.scope,
+ snippets: state.searchContext?.for_snippets ? true : null,
+ search_code: state.searchContext?.code_search ? true : null,
+ repository_ref: state.searchContext?.ref,
+ },
+ isNil,
+ );
+
+ return `${state.searchPath}?${objectToQuery(query)}`;
+};
+
+export const scopedIssuesPath = (state) => {
+ if (state.searchContext?.project?.id && !state.searchContext?.project_metadata?.issues_path) {
+ return false;
+ }
+
+ return (
+ state.searchContext?.project_metadata?.issues_path ||
+ state.searchContext?.group_metadata?.issues_path ||
+ state.issuesPath
+ );
+};
+
+export const scopedMRPath = (state) => {
+ return (
+ state.searchContext?.project_metadata?.mr_path ||
+ state.searchContext?.group_metadata?.mr_path ||
+ state.mrPath
+ );
+};
+
+export const defaultSearchOptions = (state, getters) => {
+ const userName = gon.current_username;
+
+ const issues = [
+ {
+ html_id: 'default-issues-assigned',
+ title: MSG_ISSUES_ASSIGNED_TO_ME,
+ url: `${getters.scopedIssuesPath}/?assignee_username=${userName}`,
+ },
+ {
+ html_id: 'default-issues-created',
+ title: MSG_ISSUES_IVE_CREATED,
+ url: `${getters.scopedIssuesPath}/?author_username=${userName}`,
+ },
+ ];
+
+ const mergeRequests = [
+ {
+ html_id: 'default-mrs-assigned',
+ title: MSG_MR_ASSIGNED_TO_ME,
+ url: `${getters.scopedMRPath}/?assignee_username=${userName}`,
+ },
+ {
+ html_id: 'default-mrs-reviewer',
+ title: MSG_MR_IM_REVIEWER,
+ url: `${getters.scopedMRPath}/?reviewer_username=${userName}`,
+ },
+ {
+ html_id: 'default-mrs-created',
+ title: MSG_MR_IVE_CREATED,
+ url: `${getters.scopedMRPath}/?author_username=${userName}`,
+ },
+ ];
+ return [...(getters.scopedIssuesPath ? issues : []), ...mergeRequests];
+};
+
+export const projectUrl = (state) => {
+ const query = omitBy(
+ {
+ search: state.search,
+ nav_source: 'navbar',
+ project_id: state.searchContext?.project?.id,
+ group_id: state.searchContext?.group?.id,
+ scope: state.searchContext?.scope,
+ snippets: state.searchContext?.for_snippets ? true : null,
+ search_code: state.searchContext?.code_search ? true : null,
+ repository_ref: state.searchContext?.ref,
+ },
+ isNil,
+ );
+
+ return `${state.searchPath}?${objectToQuery(query)}`;
+};
+
+export const groupUrl = (state) => {
+ const query = omitBy(
+ {
+ search: state.search,
+ nav_source: 'navbar',
+ group_id: state.searchContext?.group?.id,
+ scope: state.searchContext?.scope,
+ snippets: state.searchContext?.for_snippets ? true : null,
+ search_code: state.searchContext?.code_search ? true : null,
+ repository_ref: state.searchContext?.ref,
+ },
+ isNil,
+ );
+
+ return `${state.searchPath}?${objectToQuery(query)}`;
+};
+
+export const allUrl = (state) => {
+ const query = omitBy(
+ {
+ search: state.search,
+ nav_source: 'navbar',
+ scope: state.searchContext?.scope,
+ snippets: state.searchContext?.for_snippets ? true : null,
+ search_code: state.searchContext?.code_search ? true : null,
+ repository_ref: state.searchContext?.ref,
+ },
+ isNil,
+ );
+
+ return `${state.searchPath}?${objectToQuery(query)}`;
+};
+
+export const scopedSearchOptions = (state, getters) => {
+ const options = [];
+
+ if (state.searchContext?.project) {
+ options.push({
+ html_id: 'scoped-in-project',
+ scope: state.searchContext.project?.name || '',
+ scopeCategory: PROJECTS_CATEGORY,
+ icon: ICON_PROJECT,
+ url: getters.projectUrl,
+ });
+ }
+
+ if (state.searchContext?.group) {
+ options.push({
+ html_id: 'scoped-in-group',
+ scope: state.searchContext.group?.name || '',
+ scopeCategory: GROUPS_CATEGORY,
+ icon: state.searchContext.group?.full_name?.includes('/') ? ICON_SUBGROUP : ICON_GROUP,
+ url: getters.groupUrl,
+ });
+ }
+
+ options.push({
+ html_id: 'scoped-in-all',
+ description: MSG_IN_ALL_GITLAB,
+ url: getters.allUrl,
+ });
+
+ return options;
+};
+
+export const autocompleteGroupedSearchOptions = (state) => {
+ const groupedOptions = {};
+ const results = [];
+
+ state.autocompleteOptions.forEach((option) => {
+ const category = groupedOptions[option.category];
+
+ if (category) {
+ category.data.push(option);
+ } else {
+ groupedOptions[option.category] = {
+ category: option.category,
+ data: [option],
+ };
+
+ results.push(groupedOptions[option.category]);
+ }
+ });
+
+ return results.sort(
+ (a, b) => DROPDOWN_ORDER.indexOf(a.category) - DROPDOWN_ORDER.indexOf(b.category),
+ );
+};
+
+export const searchOptions = (state, getters) => {
+ if (!state.search) {
+ return getters.defaultSearchOptions;
+ }
+
+ const sortedAutocompleteOptions = Object.values(getters.autocompleteGroupedSearchOptions).reduce(
+ (options, group) => {
+ return [...options, ...group.data];
+ },
+ [],
+ );
+
+ if (state.search?.length <= SEARCH_SHORTCUTS_MIN_CHARACTERS) {
+ return sortedAutocompleteOptions;
+ }
+
+ return getters.scopedSearchOptions.concat(sortedAutocompleteOptions);
+};
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/store/index.js b/app/assets/javascripts/super_sidebar/components/global_search/store/index.js
new file mode 100644
index 00000000000..b83433c5b49
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/store/index.js
@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import * as actions from './actions';
+import * as getters from './getters';
+import mutations from './mutations';
+import createState from './state';
+
+Vue.use(Vuex);
+
+export const getStoreConfig = ({
+ searchPath,
+ issuesPath,
+ mrPath,
+ autocompletePath,
+ searchContext,
+ search,
+}) => ({
+ actions,
+ getters,
+ mutations,
+ state: createState({ searchPath, issuesPath, mrPath, autocompletePath, searchContext, search }),
+});
+
+const createStore = (config) => new Vuex.Store(getStoreConfig(config));
+export default createStore;
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/store/mutation_types.js b/app/assets/javascripts/super_sidebar/components/global_search/store/mutation_types.js
new file mode 100644
index 00000000000..6e65345757f
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/store/mutation_types.js
@@ -0,0 +1,6 @@
+export const REQUEST_AUTOCOMPLETE = 'REQUEST_AUTOCOMPLETE';
+export const RECEIVE_AUTOCOMPLETE_SUCCESS = 'RECEIVE_AUTOCOMPLETE_SUCCESS';
+export const RECEIVE_AUTOCOMPLETE_ERROR = 'RECEIVE_AUTOCOMPLETE_ERROR';
+export const CLEAR_AUTOCOMPLETE = 'CLEAR_AUTOCOMPLETE';
+
+export const SET_SEARCH = 'SET_SEARCH';
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/store/mutations.js b/app/assets/javascripts/super_sidebar/components/global_search/store/mutations.js
new file mode 100644
index 00000000000..19b4d4ec330
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/store/mutations.js
@@ -0,0 +1,30 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.REQUEST_AUTOCOMPLETE](state) {
+ state.loading = true;
+ state.autocompleteOptions = [];
+ state.autocompleteError = false;
+ },
+ [types.RECEIVE_AUTOCOMPLETE_SUCCESS](state, data) {
+ state.loading = false;
+ state.autocompleteOptions = [...state.autocompleteOptions].concat(
+ data.map((d, i) => {
+ return { html_id: `autocomplete-${d.category}-${i}`, ...d };
+ }),
+ );
+ state.autocompleteError = false;
+ },
+ [types.RECEIVE_AUTOCOMPLETE_ERROR](state) {
+ state.loading = false;
+ state.autocompleteOptions = [];
+ state.autocompleteError = true;
+ },
+ [types.CLEAR_AUTOCOMPLETE](state) {
+ state.autocompleteOptions = [];
+ state.autocompleteError = false;
+ },
+ [types.SET_SEARCH](state, value) {
+ state.search = value;
+ },
+};
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/store/state.js b/app/assets/javascripts/super_sidebar/components/global_search/store/state.js
new file mode 100644
index 00000000000..bebdbc7b92e
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/global_search/store/state.js
@@ -0,0 +1,19 @@
+const createState = ({
+ searchPath,
+ issuesPath,
+ mrPath,
+ autocompletePath,
+ searchContext,
+ search,
+}) => ({
+ searchPath,
+ issuesPath,
+ mrPath,
+ autocompletePath,
+ searchContext,
+ search,
+ autocompleteOptions: [],
+ autocompleteError: false,
+ loading: false,
+});
+export default createState;
diff --git a/app/assets/javascripts/super_sidebar/components/groups_list.vue b/app/assets/javascripts/super_sidebar/components/groups_list.vue
new file mode 100644
index 00000000000..78b5ed2d31e
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/groups_list.vue
@@ -0,0 +1,78 @@
+<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`;
+ },
+ viewAllItem() {
+ return {
+ link: this.viewAllLink,
+ title: s__('Navigation|View all groups'),
+ icon: 'group',
+ };
+ },
+ },
+ i18n: {
+ title: s__('Navigation|Frequent 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 :item="viewAllItem" />
+ </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 :item="viewAllItem" />
+ </template>
+ </frequent-items-list>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/help_center.vue b/app/assets/javascripts/super_sidebar/components/help_center.vue
index 8e7c7efa631..fb23a4f2deb 100644
--- a/app/assets/javascripts/super_sidebar/components/help_center.vue
+++ b/app/assets/javascripts/super_sidebar/components/help_center.vue
@@ -68,6 +68,9 @@ export default {
{
text: this.$options.i18n.shortcuts,
action: this.showKeyboardShortcuts,
+ extraAttrs: {
+ class: 'js-shortcuts-modal-trigger',
+ },
shortcut: '?',
},
this.sidebarData.display_whats_new && {
@@ -96,15 +99,8 @@ export default {
return true;
},
- handleAction({ action }) {
- if (action) {
- action();
- }
- },
-
showKeyboardShortcuts() {
this.$refs.dropdown.close();
- window?.toggleShortcutsHelp();
},
async showWhatsNew() {
@@ -130,7 +126,7 @@ export default {
<gl-disclosure-dropdown ref="dropdown">
<template #toggle>
<gl-button category="tertiary" icon="question-o" class="btn-with-notification">
- <span v-if="showWhatsNewNotification" class="notification"></span>
+ <span v-if="showWhatsNewNotification" class="notification-dot-info"></span>
{{ $options.i18n.help }}
</gl-button>
</template>
@@ -140,11 +136,7 @@ export default {
:group="itemGroups.versionCheck"
>
<template #list-item="{ item }">
- <a
- :href="item.href"
- tabindex="-1"
- class="gl-display-flex gl-flex-direction-column gl-line-height-24 gl-text-gray-900 gl-hover-text-gray-900 gl-hover-text-decoration-none"
- >
+ <span class="gl-display-flex gl-flex-direction-column gl-line-height-24">
<span class="gl-font-sm gl-font-weight-bold">
{{ item.text }}
<gl-emoji data-name="rocket" />
@@ -153,7 +145,7 @@ export default {
<span class="gl-mr-2">{{ item.version }}</span>
<gitlab-version-check-badge v-if="updateSeverity" :status="updateSeverity" size="sm" />
</span>
- </a>
+ </span>
</template>
</gl-disclosure-dropdown-group>
@@ -162,16 +154,15 @@ export default {
:bordered="sidebarData.show_version_check"
/>
- <gl-disclosure-dropdown-group :group="itemGroups.helpActions" bordered @action="handleAction">
+ <gl-disclosure-dropdown-group :group="itemGroups.helpActions" bordered>
<template #list-item="{ item }">
- <button
- tabindex="-1"
- class="gl-bg-transparent gl-w-full gl-border-none gl-display-flex gl-justify-content-space-between gl-p-0 gl-text-gray-900"
+ <span
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-my-n1"
>
{{ item.text }}
<gl-badge v-if="item.count" pill size="sm" variant="info">{{ item.count }}</gl-badge>
<kbd v-else-if="item.shortcut" class="flat">?</kbd>
- </button>
+ </span>
</template>
</gl-disclosure-dropdown-group>
</gl-disclosure-dropdown>
diff --git a/app/assets/javascripts/super_sidebar/components/items_list.vue b/app/assets/javascripts/super_sidebar/components/items_list.vue
new file mode 100644
index 00000000000..0a72105fcc4
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/items_list.vue
@@ -0,0 +1,40 @@
+<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"
+ :link-classes="{ 'gl-py-2!': true }"
+ >
+ <template #icon>
+ <project-avatar
+ :project-id="item.id"
+ :project-name="item.title"
+ :project-avatar-url="item.avatar"
+ :size="24"
+ aria-hidden="true"
+ />
+ </template>
+ </nav-item>
+ <slot name="view-all-items"></slot>
+ </ul>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/merge_request_menu.vue b/app/assets/javascripts/super_sidebar/components/merge_request_menu.vue
index edc13e305cf..94fc6aedcc0 100644
--- a/app/assets/javascripts/super_sidebar/components/merge_request_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/merge_request_menu.vue
@@ -12,29 +12,19 @@ export default {
required: true,
},
},
- methods: {
- navigate() {
- this.$refs.link.click();
- },
- },
};
</script>
<template>
- <gl-disclosure-dropdown :items="items" placement="center" @action="navigate">
+ <gl-disclosure-dropdown :items="items" placement="center">
<template #toggle>
<slot></slot>
</template>
<template #list-item="{ item }">
- <a
- ref="link"
- class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-hover-text-gray-900 gl-hover-text-decoration-none gl-text-gray-900"
- :href="item.href"
- tabindex="-1"
- >
+ <span class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
{{ item.text }}
<gl-badge pill size="sm" variant="neutral">{{ item.count || 0 }}</gl-badge>
- </a>
+ </span>
</template>
</gl-disclosure-dropdown>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue
index 4fd6918fd6f..cd5363ad7a5 100644
--- a/app/assets/javascripts/super_sidebar/components/nav_item.vue
+++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue
@@ -1,37 +1,141 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { kebabCase } from 'lodash';
+import { GlCollapse, GlIcon, GlBadge } from '@gitlab/ui';
export default {
name: 'NavItem',
components: {
+ GlCollapse,
GlIcon,
+ GlBadge,
},
props: {
item: {
type: Object,
required: true,
},
+ linkClasses: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ },
+ data() {
+ return {
+ expanded: this.item.is_active,
+ };
+ },
+ computed: {
+ elem() {
+ return this.isSection ? 'button' : 'a';
+ },
+ collapseIcon() {
+ return this.expanded ? 'chevron-up' : 'chevron-down';
+ },
+ isSection() {
+ return Boolean(this.item?.items?.length);
+ },
+ itemId() {
+ return kebabCase(this.item.title);
+ },
+ pillData() {
+ return this.item.pill_count;
+ },
+ hasPill() {
+ return (
+ Number.isFinite(this.pillData) ||
+ (typeof this.pillData === 'string' && this.pillData !== '')
+ );
+ },
+ isActive() {
+ if (this.isSection) {
+ return !this.expanded && this.item.is_active;
+ }
+ return this.item.is_active;
+ },
+ linkProps() {
+ if (this.isSection) {
+ return {
+ 'aria-controls': this.itemId,
+ 'aria-expanded': String(this.expanded),
+ };
+ }
+ return {
+ ...this.$attrs,
+ href: this.item.link,
+ 'aria-current': this.isActive ? 'page' : null,
+ };
+ },
+ computedLinkClasses() {
+ return {
+ // Reset user agent styles on <button>
+ 'gl-appearance-none gl-border-0 gl-bg-transparent gl-text-left': this.isSection,
+ 'gl-w-full gl-focus': this.isSection,
+ 'gl-bg-t-gray-a-08': this.isActive,
+ ...this.linkClasses,
+ };
+ },
+ },
+ methods: {
+ click(event) {
+ if (this.isSection) {
+ event.preventDefault();
+ this.expanded = !this.expanded;
+ }
+ },
},
};
</script>
<template>
<li>
- <a
- :href="item.link"
- class="gl-display-flex gl-pl-3 gl-py-3 gl-line-height-normal gl-text-black-normal gl-hover-bg-t-gray-a-08"
+ <component
+ :is="elem"
+ v-bind="linkProps"
+ class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-py-3 gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-text-decoration-none!"
+ :class="computedLinkClasses"
+ data-qa-selector="sidebar_menu_link"
+ data-testid="nav-item-link"
+ :data-qa-menu-item="item.title"
+ @click="click"
>
- <div class="gl-mr-3">
+ <div
+ :class="[isActive ? 'gl-bg-blue-500' : 'gl-bg-transparent']"
+ class="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"
+ ></div>
+ <div class="gl-flex-shrink-0 gl-w-6 gl-mx-3">
<slot name="icon">
- <gl-icon v-if="item.icon" :name="item.icon" />
+ <gl-icon v-if="item.icon" :name="item.icon" class="gl-ml-2" />
</slot>
</div>
- <div class="gl-pr-3">
+ <div class="gl-pr-3 gl-text-gray-900">
{{ item.title }}
- <div v-if="item.subtitle" class="gl-font-sm gl-text-gray-500 gl-mt-1">
+ <div v-if="item.subtitle" class="gl-font-sm gl-text-gray-500">
{{ item.subtitle }}
</div>
</div>
- </a>
+ <span v-if="isSection || hasPill" class="gl-flex-grow-1 gl-text-right gl-mr-3">
+ <gl-badge v-if="hasPill" size="sm" variant="info">
+ {{ pillData }}
+ </gl-badge>
+ <gl-icon v-else-if="isSection" :name="collapseIcon" />
+ </span>
+ </component>
+ <gl-collapse
+ v-if="isSection"
+ :id="itemId"
+ v-model="expanded"
+ :aria-label="item.title"
+ class="gl-list-style-none gl-p-0"
+ tag="ul"
+ >
+ <nav-item
+ v-for="subItem of item.items"
+ :key="`${item.title}-${subItem.title}`"
+ :item="subItem"
+ />
+ </gl-collapse>
</li>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/projects_list.vue b/app/assets/javascripts/super_sidebar/components/projects_list.vue
new file mode 100644
index 00000000000..a545de06bd4
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/projects_list.vue
@@ -0,0 +1,79 @@
+<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`;
+ },
+ viewAllItem() {
+ return {
+ link: this.viewAllLink,
+ title: s__('Navigation|View all projects'),
+ icon: 'project',
+ };
+ },
+ },
+ i18n: {
+ title: s__('Navigation|Frequent 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 :item="viewAllItem" />
+ </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 :item="viewAllItem" />
+ </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
new file mode 100644
index 00000000000..7c172110bad
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/search_results.vue
@@ -0,0 +1,49 @@
+<script>
+import ItemsList from './items_list.vue';
+
+export default {
+ components: {
+ ItemsList,
+ },
+ props: {
+ title: {
+ type: String,
+ required: true,
+ },
+ noResultsText: {
+ type: String,
+ required: true,
+ },
+ searchResults: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ computed: {
+ isEmpty() {
+ return !this.searchResults.length;
+ },
+ },
+};
+</script>
+
+<template>
+ <li class="gl-border-t gl-border-gray-50 gl-mx-3 gl-py-3">
+ <div
+ data-testid="list-title"
+ aria-hidden="true"
+ class="gl-text-transform-uppercase gl-text-secondary gl-font-weight-bold gl-font-xs gl-line-height-12 gl-letter-spacing-06em gl-my-3"
+ >
+ {{ title }}
+ </div>
+ <div v-if="isEmpty" data-testid="empty-text" class="gl-text-gray-500 gl-font-sm gl-my-3">
+ {{ noResultsText }}
+ </div>
+ <items-list :aria-label="title" :items="searchResults">
+ <template #view-all-items>
+ <slot name="view-all-items"></slot>
+ </template>
+ </items-list>
+ </li>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue b/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue
new file mode 100644
index 00000000000..fc8968c50ea
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue
@@ -0,0 +1,24 @@
+<script>
+import NavItem from './nav_item.vue';
+
+export default {
+ name: 'SidebarMenu',
+ components: {
+ NavItem,
+ },
+ props: {
+ items: {
+ type: Array,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <nav class="gl-py-2 gl-relative">
+ <ul class="gl-px-2 gl-list-style-none">
+ <nav-item v-for="item in items" :key="`menu-${item.title}`" :item="item" />
+ </ul>
+ </nav>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_portal.vue b/app/assets/javascripts/super_sidebar/components/sidebar_portal.vue
new file mode 100644
index 00000000000..2a805c86a3b
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/sidebar_portal.vue
@@ -0,0 +1,30 @@
+<script>
+import { MountingPortal } from 'portal-vue';
+import { SIDEBAR_PORTAL_ID, portalState } from '../constants';
+
+/**
+ * Use this component to render content into the sidebar.
+ *
+ * Arbitrary content is allowed, but nav items should be added using a Ruby
+ * Sidebars::Panel subclass instead.
+ *
+ * Only one instance of this component on a given page is supported. This is to
+ * avoid ordering issues and cluttering the sidebar.
+ */
+export default {
+ components: {
+ MountingPortal,
+ },
+ data() {
+ // This is shared state, by design. Do not mutate this state here.
+ return portalState;
+ },
+ mountSelector: `#${SIDEBAR_PORTAL_ID}`,
+};
+</script>
+
+<template>
+ <mounting-portal v-if="ready" :mount-to="$options.mountSelector" append>
+ <slot></slot>
+ </mounting-portal>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_portal_target.vue b/app/assets/javascripts/super_sidebar/components/sidebar_portal_target.vue
new file mode 100644
index 00000000000..1154a4357e0
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/sidebar_portal_target.vue
@@ -0,0 +1,17 @@
+<script>
+import { SIDEBAR_PORTAL_ID, portalState } from '../constants';
+
+export default {
+ mounted() {
+ portalState.ready = true;
+ },
+ beforeDestroy() {
+ portalState.ready = false;
+ },
+ mountId: SIDEBAR_PORTAL_ID,
+};
+</script>
+
+<template>
+ <div v-once :id="$options.mountId"></div>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
index c4b769dcf24..e8df534346b 100644
--- a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
+++ b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
@@ -1,19 +1,27 @@
<script>
-import { GlCollapse } from '@gitlab/ui';
-import { context } from '../mock_data';
+import { GlButton, GlCollapse } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { isCollapsed, toggleSuperSidebarCollapsed } from '../super_sidebar_collapsed_state_manager';
import UserBar from './user_bar.vue';
+import SidebarPortalTarget from './sidebar_portal_target.vue';
import ContextSwitcherToggle from './context_switcher_toggle.vue';
import ContextSwitcher from './context_switcher.vue';
import HelpCenter from './help_center.vue';
+import SidebarMenu from './sidebar_menu.vue';
export default {
- context,
components: {
+ GlButton,
GlCollapse,
UserBar,
ContextSwitcherToggle,
ContextSwitcher,
HelpCenter,
+ SidebarMenu,
+ SidebarPortalTarget,
+ },
+ i18n: {
+ skipToMainContent: __('Skip to main content'),
},
props: {
sidebarData: {
@@ -24,28 +32,65 @@ export default {
data() {
return {
contextSwitcherOpened: false,
+ isCollapased: isCollapsed(),
};
},
+ computed: {
+ menuItems() {
+ return this.sidebarData.current_menu_items || [];
+ },
+ },
+ methods: {
+ collapseSidebar() {
+ toggleSuperSidebarCollapsed(true, false);
+ },
+ },
};
</script>
<template>
- <aside
- id="super-sidebar"
- class="super-sidebar gl-fixed gl-bottom-0 gl-left-0 gl-display-flex gl-flex-direction-column gl-bg-gray-10 gl-border-r gl-border-gray-a-08"
- data-testid="super-sidebar"
- >
- <user-bar :sidebar-data="sidebarData" />
- <div class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-overflow-hidden">
- <div class="gl-flex-grow-1 gl-overflow-auto">
- <context-switcher-toggle :context="$options.context" :expanded="contextSwitcherOpened" />
- <gl-collapse id="context-switcher" v-model="contextSwitcherOpened">
- <context-switcher />
- </gl-collapse>
- </div>
- <div class="gl-p-3">
- <help-center :sidebar-data="sidebarData" />
+ <div>
+ <div class="super-sidebar-overlay" @click="collapseSidebar"></div>
+ <aside
+ id="super-sidebar"
+ :aria-hidden="String(isCollapased)"
+ class="super-sidebar"
+ data-testid="super-sidebar"
+ data-qa-selector="navbar"
+ :inert="isCollapased"
+ tabindex="-1"
+ >
+ <gl-button
+ class="super-sidebar-skip-to gl-sr-only-focusable gl-absolute gl-left-3 gl-right-3 gl-top-3"
+ href="#content-body"
+ variant="confirm"
+ >
+ {{ $options.i18n.skipToMainContent }}
+ </gl-button>
+ <user-bar :sidebar-data="sidebarData" />
+ <div class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-overflow-hidden">
+ <div class="gl-flex-grow-1 gl-overflow-auto">
+ <context-switcher-toggle
+ :context="sidebarData.current_context_header"
+ :expanded="contextSwitcherOpened"
+ />
+ <gl-collapse id="context-switcher" v-model="contextSwitcherOpened">
+ <context-switcher
+ :username="sidebarData.username"
+ :projects-path="sidebarData.projects_path"
+ :groups-path="sidebarData.groups_path"
+ :current-context="sidebarData.current_context"
+ />
+ </gl-collapse>
+ <gl-collapse :visible="!contextSwitcherOpened">
+ <sidebar-menu :items="menuItems" />
+ <sidebar-portal-target />
+ </gl-collapse>
+ </div>
+ <div class="gl-p-3">
+ <help-center :sidebar-data="sidebarData" />
+ </div>
</div>
- </div>
- </aside>
+ </aside>
+ </div>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue
index ee72e8eafb4..e27acb60372 100644
--- a/app/assets/javascripts/super_sidebar/components/user_bar.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue
@@ -1,60 +1,89 @@
<script>
-import { GlAvatar, GlDropdown, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { GlBadge, GlButton, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
import logo from '../../../../views/shared/_logo.svg';
+import { toggleSuperSidebarCollapsed } from '../super_sidebar_collapsed_state_manager';
import CreateMenu from './create_menu.vue';
import Counter from './counter.vue';
import MergeRequestMenu from './merge_request_menu.vue';
+import UserMenu from './user_menu.vue';
export default {
+ // "GitLab Next" is a proper noun, so don't translate "Next"
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
+ NEXT_LABEL: 'Next',
logo,
components: {
- GlAvatar,
- GlDropdown,
- GlIcon,
- CreateMenu,
- NewNavToggle,
Counter,
+ CreateMenu,
+ GlBadge,
+ GlButton,
MergeRequestMenu,
+ UserMenu,
},
i18n: {
+ collapseSidebar: __('Collapse sidebar'),
createNew: __('Create new...'),
issues: __('Issues'),
mergeRequests: __('Merge requests'),
+ search: __('Search'),
todoList: __('To-Do list'),
},
directives: {
GlTooltip: GlTooltipDirective,
SafeHtml,
},
- inject: ['rootPath', 'toggleNewNavEndpoint'],
+ inject: ['rootPath'],
props: {
sidebarData: {
type: Object,
required: true,
},
},
+ methods: {
+ collapseSidebar() {
+ toggleSuperSidebarCollapsed(true, true, true);
+ },
+ },
};
</script>
<template>
<div class="user-bar">
- <div class="gl-display-flex gl-align-items-center gl-px-3 gl-py-2 gl-gap-3">
- <div class="gl-flex-grow-1">
- <a v-safe-html="$options.logo" :href="rootPath"></a>
- </div>
+ <div class="gl-display-flex gl-align-items-center gl-px-3 gl-py-2 gl-gap-2">
+ <a :href="rootPath">
+ <img
+ v-if="sidebarData.logo_url"
+ data-testid="brand-header-custom-logo"
+ :src="sidebarData.logo_url"
+ class="gl-h-6"
+ />
+ <span v-else v-safe-html="$options.logo"></span>
+ </a>
+ <gl-badge
+ v-if="sidebarData.gitlab_com_and_canary"
+ variant="success"
+ :href="sidebarData.canary_toggle_com_url"
+ size="sm"
+ >{{ $options.NEXT_LABEL }}</gl-badge
+ >
+ <div class="gl-flex-grow-1"></div>
+ <gl-button
+ v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.collapseSidebar"
+ :aria-label="$options.i18n.collapseSidebar"
+ icon="sidebar"
+ category="tertiary"
+ @click="collapseSidebar"
+ />
<create-menu :groups="sidebarData.create_new_menu_groups" />
- <button class="gl-border-none">
- <gl-icon name="search" class="gl-vertical-align-middle" />
- </button>
- <gl-dropdown data-testid="user-dropdown" variant="link" no-caret>
- <template #button-content>
- <gl-avatar :entity-name="sidebarData.name" :src="sidebarData.avatar_url" :size="32" />
- </template>
- <new-nav-toggle :endpoint="toggleNewNavEndpoint" enabled />
- </gl-dropdown>
+ <gl-button
+ icon="search"
+ :aria-label="$options.i18n.search"
+ category="tertiary"
+ href="/search"
+ />
+ <user-menu :data="sidebarData" />
</div>
<div class="gl-display-flex gl-justify-content-space-between gl-px-3 gl-py-2 gl-gap-2">
<counter
@@ -72,7 +101,6 @@ export default {
<counter
v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.mergeRequests"
class="gl-w-full"
- tabindex="-1"
icon="merge-request-open"
:count="sidebarData.total_merge_requests_count"
:label="$options.i18n.mergeRequests"
@@ -85,6 +113,7 @@ export default {
:count="sidebarData.todos_pending_count"
href="/dashboard/todos"
:label="$options.i18n.todoList"
+ data-qa-selector="todos_shortcut_button"
/>
</div>
</div>
diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue
new file mode 100644
index 00000000000..34bbb3ce177
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue
@@ -0,0 +1,291 @@
+<script>
+import {
+ GlAvatar,
+ GlBadge,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownGroup,
+ GlDisclosureDropdownItem,
+} from '@gitlab/ui';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { s__, __, sprintf } from '~/locale';
+import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
+import Tracking from '~/tracking';
+import PersistentUserCallout from '~/persistent_user_callout';
+import UserNameGroup from './user_name_group.vue';
+
+export default {
+ feedbackUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391533',
+ i18n: {
+ newNavigation: {
+ badgeLabel: s__('NorthstarNavigation|Alpha'),
+ sectionTitle: s__('NorthstarNavigation|Navigation redesign'),
+ },
+ setStatus: s__('SetStatusModal|Set status'),
+ editStatus: s__('SetStatusModal|Edit status'),
+ editProfile: s__('CurrentUser|Edit profile'),
+ preferences: s__('CurrentUser|Preferences'),
+ 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'),
+ },
+ components: {
+ GlAvatar,
+ GlBadge,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownGroup,
+ GlDisclosureDropdownItem,
+ NewNavToggle,
+ UserNameGroup,
+ },
+ directives: {
+ SafeHtml,
+ },
+ mixins: [Tracking.mixin()],
+ inject: ['toggleNewNavEndpoint'],
+ props: {
+ data: {
+ required: true,
+ type: Object,
+ },
+ },
+ computed: {
+ toggleText() {
+ return sprintf(__('%{user} user’s menu'), { user: this.data.name });
+ },
+ statusItem() {
+ const { busy, customized } = this.data.status;
+
+ const statusLabel =
+ busy || customized ? this.$options.i18n.editStatus : this.$options.i18n.setStatus;
+
+ return {
+ text: statusLabel,
+ extraAttrs: {
+ class: 'js-set-status-modal-trigger',
+ },
+ };
+ },
+ trialItem() {
+ return {
+ text: this.$options.i18n.startTrial,
+ href: this.data.trial.url,
+ };
+ },
+ editProfileItem() {
+ return {
+ text: this.$options.i18n.editProfile,
+ href: this.data.settings.profile_path,
+ extraAttrs: {
+ 'data-qa-selector': 'edit_profile_link',
+ },
+ };
+ },
+ preferencesItem() {
+ return {
+ text: this.$options.i18n.preferences,
+ href: this.data.settings.profile_preferences_path,
+ };
+ },
+ addBuyPipelineMinutesMenuItem() {
+ return this.data.pipeline_minutes?.show_buy_pipeline_minutes;
+ },
+ buyPipelineMinutesItem() {
+ return {
+ text: this.$options.i18n.buyPipelineMinutes,
+ warningText: this.$options.i18n.oneOfGroupsRunningOutOfPipelineMinutes,
+ href: this.data.pipeline_minutes?.buy_pipeline_minutes_path,
+ extraAttrs: {
+ class: 'js-follow-link',
+ },
+ };
+ },
+ gitlabNextItem() {
+ return {
+ text: this.$options.i18n.gitlabNext,
+ href: this.data.canary_toggle_com_url,
+ };
+ },
+ feedbackItem() {
+ return {
+ text: this.$options.i18n.provideFeedback,
+ href: this.$options.feedbackUrl,
+ extraAttrs: {
+ target: '_blank',
+ },
+ };
+ },
+ signOutGroup() {
+ return {
+ items: [
+ {
+ text: this.$options.i18n.signOut,
+ href: this.data.sign_out_link,
+ extraAttrs: {
+ 'data-method': 'post',
+ 'data-qa-selector': 'sign_out_link',
+ class: 'sign-out-link',
+ },
+ },
+ ],
+ };
+ },
+ statusModalData() {
+ const defaultData = {
+ 'data-current-emoji': '',
+ 'data-current-message': '',
+ 'data-default-emoji': 'speech_balloon',
+ };
+
+ if (!this.data.status.customized) {
+ return defaultData;
+ }
+ return {
+ ...defaultData,
+ 'data-current-emoji': this.data.status.emoji,
+ 'data-current-message': this.data.status.message,
+ 'data-current-availability': this.data.status.availability,
+ 'data-current-clear-status-after': this.data.status.clear_after,
+ };
+ },
+ buyPipelineMinutesCalloutData() {
+ return this.showNotificationDot
+ ? {
+ 'data-feature-id': this.data.pipeline_minutes.callout_attrs.feature_id,
+ 'data-dismiss-endpoint': this.data.pipeline_minutes.callout_attrs.dismiss_endpoint,
+ }
+ : {};
+ },
+ showNotificationDot() {
+ return this.data.pipeline_minutes?.show_notification_dot;
+ },
+ },
+ methods: {
+ onShow() {
+ this.trackEvents();
+ this.initCallout();
+ },
+ initCallout() {
+ if (this.showNotificationDot) {
+ PersistentUserCallout.factory(this.$refs?.buyPipelineMinutesNotificationCallout.$el);
+ }
+ },
+ trackEvents() {
+ if (this.addBuyPipelineMinutesMenuItem) {
+ const {
+ 'track-action': trackAction,
+ 'track-label': label,
+ 'track-property': property,
+ } = this.data.pipeline_minutes.tracking_attrs;
+ this.track(trackAction, { label, property });
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-disclosure-dropdown
+ placement="right"
+ data-testid="user-dropdown"
+ data-qa-selector="user_menu"
+ @shown="onShow"
+ >
+ <template #toggle>
+ <button class="user-bar-item btn-with-notification">
+ <span class="gl-sr-only">{{ toggleText }}</span>
+ <gl-avatar
+ :size="24"
+ :entity-name="data.name"
+ :src="data.avatar_url"
+ aria-hidden="true"
+ data-qa-selector="user_avatar_content"
+ />
+ <span
+ v-if="showNotificationDot"
+ class="notification-dot-warning"
+ data-testid="buy-pipeline-minutes-notification-dot"
+ v-bind="data.pipeline_minutes.notification_dot_attrs"
+ >
+ </span>
+ </button>
+ </template>
+
+ <user-name-group :user="data" />
+ <gl-disclosure-dropdown-group bordered>
+ <gl-disclosure-dropdown-item
+ v-if="data.status.can_update"
+ :item="statusItem"
+ data-testid="status-item"
+ />
+
+ <gl-disclosure-dropdown-item
+ v-if="data.trial.has_start_trial"
+ :item="trialItem"
+ data-testid="start-trial-item"
+ >
+ <template #list-item>
+ {{ trialItem.text }}
+ <gl-emoji data-name="rocket" />
+ </template>
+ </gl-disclosure-dropdown-item>
+
+ <gl-disclosure-dropdown-item :item="editProfileItem" data-testid="edit-profile-item" />
+
+ <gl-disclosure-dropdown-item :item="preferencesItem" data-testid="preferences-item" />
+
+ <gl-disclosure-dropdown-item
+ v-if="addBuyPipelineMinutesMenuItem"
+ ref="buyPipelineMinutesNotificationCallout"
+ :item="buyPipelineMinutesItem"
+ v-bind="buyPipelineMinutesCalloutData"
+ data-testid="buy-pipeline-minutes-item"
+ >
+ <template #list-item>
+ <span class="gl-display-flex gl-flex-direction-column">
+ <span>{{ buyPipelineMinutesItem.text }} <gl-emoji data-name="clock9" /></span>
+ <span
+ v-if="data.pipeline_minutes.show_with_subtext"
+ class="gl-font-sm small gl-pt-2 gl-text-orange-800"
+ >{{ buyPipelineMinutesItem.warningText }}</span
+ >
+ </span>
+ </template>
+ </gl-disclosure-dropdown-item>
+
+ <gl-disclosure-dropdown-item
+ v-if="data.gitlab_com_but_not_canary"
+ :item="gitlabNextItem"
+ data-testid="gitlab-next-item"
+ />
+ </gl-disclosure-dropdown-group>
+
+ <gl-disclosure-dropdown-group bordered>
+ <template #group-label>
+ <span class="gl-font-sm">{{ $options.i18n.newNavigation.sectionTitle }}</span>
+ <gl-badge size="sm" variant="info"
+ >{{ $options.i18n.newNavigation.badgeLabel }}
+ </gl-badge>
+ </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
+ v-if="data.can_sign_out"
+ bordered
+ :group="signOutGroup"
+ data-testid="sign-out-group"
+ />
+ </gl-disclosure-dropdown>
+
+ <div
+ v-if="data.status.can_update"
+ class="js-set-status-modal-wrapper"
+ v-bind="statusModalData"
+ ></div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_name_group.vue b/app/assets/javascripts/super_sidebar/components/user_name_group.vue
new file mode 100644
index 00000000000..2489f462122
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/user_name_group.vue
@@ -0,0 +1,77 @@
+<script>
+import { GlDisclosureDropdownGroup, GlDisclosureDropdownItem, GlTooltip } from '@gitlab/ui';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+
+import { s__ } from '~/locale';
+
+export default {
+ i18n: {
+ user: {
+ busy: s__('UserProfile|(Busy)'),
+ },
+ },
+ components: {
+ GlDisclosureDropdownGroup,
+ GlDisclosureDropdownItem,
+ GlTooltip,
+ },
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ user: {
+ required: true,
+ type: Object,
+ },
+ },
+ computed: {
+ menuItem() {
+ const item = {
+ text: this.user.name,
+ };
+ if (this.user.has_link_to_profile) {
+ item.href = this.user.link_to_profile;
+ }
+ return item;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-disclosure-dropdown-group>
+ <gl-disclosure-dropdown-item :item="menuItem">
+ <template #list-item>
+ <span class="gl-display-flex gl-flex-direction-column">
+ <span>
+ <span class="gl-font-weight-bold">
+ {{ user.name }}
+ </span>
+ <span v-if="user.status.busy" class="gl-text-gray-500">{{
+ $options.i18n.user.busy
+ }}</span>
+ </span>
+
+ <span class="gl-text-gray-400">@{{ user.username }}</span>
+
+ <span
+ 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"
+ >
+ <gl-emoji :data-name="user.status.emoji" class="gl-mr-1" />
+ <span v-safe-html="user.status.message" class="gl-text-truncate"></span>
+ <gl-tooltip
+ :target="() => $refs.statusTooltipTarget"
+ boundary="viewport"
+ placement="bottom"
+ >
+ <span v-safe-html="user.status.message"></span>
+ </gl-tooltip>
+ </span>
+ </span>
+ </template>
+ </gl-disclosure-dropdown-item>
+ </gl-disclosure-dropdown-group>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/constants.js b/app/assets/javascripts/super_sidebar/constants.js
new file mode 100644
index 00000000000..acc03bc48c7
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/constants.js
@@ -0,0 +1,14 @@
+// Note: all constants defined here are considered internal implementation
+// details for the sidebar. They should not be imported by anything outside of
+// the super_sidebar directory.
+
+import Vue from 'vue';
+
+export const SIDEBAR_PORTAL_ID = 'sidebar-portal-mount';
+
+export const portalState = Vue.observable({
+ ready: false,
+});
+
+export const MAX_FREQUENT_PROJECTS_COUNT = 5;
+export const MAX_FREQUENT_GROUPS_COUNT = 3;
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
new file mode 100644
index 00000000000..4b1e65be3fa
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/graphql/queries/search_user_groups_and_projects.query.graphql
@@ -0,0 +1,24 @@
+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/mock_data.js b/app/assets/javascripts/super_sidebar/mock_data.js
index 0d1ac006df7..5e5ad97eb68 100644
--- a/app/assets/javascripts/super_sidebar/mock_data.js
+++ b/app/assets/javascripts/super_sidebar/mock_data.js
@@ -1,13 +1,8 @@
import { s__ } from '~/locale';
-export const context = {
- title: 'Typeahead.js',
- link: '/',
- avatar: 'https://gitlab.com/uploads/-/system/project/avatar/278964/project_avatar.png?width=32',
-};
-
export const contextSwitcherItems = {
yourWork: { title: s__('Navigation|Your work'), link: '/', icon: 'work' },
+ explore: { title: s__('Navigation|Explore'), link: '/explore', icon: 'compass' },
recentProjects: [
{
// eslint-disable-next-line @gitlab/require-i18n-strings
diff --git a/app/assets/javascripts/super_sidebar/super_sidebar_bundle.js b/app/assets/javascripts/super_sidebar/super_sidebar_bundle.js
index b9c7073df8c..4395cc2f5f0 100644
--- a/app/assets/javascripts/super_sidebar/super_sidebar_bundle.js
+++ b/app/assets/javascripts/super_sidebar/super_sidebar_bundle.js
@@ -1,16 +1,33 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import { initStatusTriggers } from '../header';
+import {
+ bindSuperSidebarCollapsedEvents,
+ initSuperSidebarCollapsedState,
+} from './super_sidebar_collapsed_state_manager';
import SuperSidebar from './components/super_sidebar.vue';
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
export const initSuperSidebar = () => {
const el = document.querySelector('.js-super-sidebar');
if (!el) return false;
+ bindSuperSidebarCollapsedEvents();
+ initSuperSidebarCollapsedState();
+
const { rootPath, sidebar, toggleNewNavEndpoint } = el.dataset;
return new Vue({
el,
name: 'SuperSidebarRoot',
+ apolloProvider,
provide: {
rootPath,
toggleNewNavEndpoint,
@@ -24,3 +41,5 @@ export const initSuperSidebar = () => {
},
});
};
+
+requestIdleCallback(initStatusTriggers);
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
new file mode 100644
index 00000000000..549c6c17e44
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/super_sidebar_collapsed_state_manager.js
@@ -0,0 +1,51 @@
+import { GlBreakpointInstance as bp, breakpoints } from '@gitlab/ui/dist/utils';
+import { debounce } from 'lodash';
+import { setCookie, getCookie } from '~/lib/utils/common_utils';
+
+export const SIDEBAR_COLLAPSED_CLASS = 'page-with-super-sidebar-collapsed';
+export const SIDEBAR_COLLAPSED_COOKIE = 'super_sidebar_collapsed';
+export const SIDEBAR_COLLAPSED_COOKIE_EXPIRATION = 365 * 10;
+
+export const findPage = () => document.querySelector('.page-with-super-sidebar');
+export const findSidebar = () => document.querySelector('.super-sidebar');
+export const findToggles = () => document.querySelectorAll('.js-super-sidebar-toggle');
+
+export const isCollapsed = () => findPage().classList.contains(SIDEBAR_COLLAPSED_CLASS);
+
+// See documentation: https://design.gitlab.com/patterns/navigation#left-sidebar
+// NOTE: at 1200px nav sidebar should not overlap the content
+// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24555#note_134136110
+export const isDesktopBreakpoint = () => bp.windowWidth() >= breakpoints.xl;
+
+export const getCollapsedCookie = () => getCookie(SIDEBAR_COLLAPSED_COOKIE) === 'true';
+
+export const toggleSuperSidebarCollapsed = (collapsed, saveCookie, isUserAction) => {
+ const sidebar = findSidebar();
+ sidebar.ariaHidden = collapsed;
+ sidebar.inert = collapsed;
+
+ if (!collapsed && isUserAction) sidebar.focus();
+
+ findPage().classList.toggle(SIDEBAR_COLLAPSED_CLASS, collapsed);
+
+ if (saveCookie && isDesktopBreakpoint()) {
+ setCookie(SIDEBAR_COLLAPSED_COOKIE, collapsed, {
+ expires: SIDEBAR_COLLAPSED_COOKIE_EXPIRATION,
+ });
+ }
+};
+
+export const initSuperSidebarCollapsedState = () => {
+ const collapsed = isDesktopBreakpoint() ? getCollapsedCookie() : true;
+ toggleSuperSidebarCollapsed(collapsed, false);
+};
+
+export const bindSuperSidebarCollapsedEvents = () => {
+ findToggles().forEach((elem) => {
+ elem.addEventListener('click', () => {
+ toggleSuperSidebarCollapsed(!isCollapsed(), true, true);
+ });
+ });
+
+ window.addEventListener('resize', debounce(initSuperSidebarCollapsedState, 100));
+};
diff --git a/app/assets/javascripts/super_sidebar/utils.js b/app/assets/javascripts/super_sidebar/utils.js
new file mode 100644
index 00000000000..8e4250d0e39
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/utils.js
@@ -0,0 +1,83 @@
+import AccessorUtilities from '~/lib/utils/accessor';
+import { FREQUENT_ITEMS, FIFTEEN_MINUTES_IN_MS } from '~/frequent_items/constants';
+import { truncateNamespace } from '~/lib/utils/text_utility';
+
+/**
+ * This takes an array of project or groups that were stored in the local storage, to be shown in
+ * the context switcher, and sorts them by frequency and last access date.
+ * In the resulting array, the most popular item (highest frequency and most recent access date) is
+ * placed at the first index, while the least popular is at the last index.
+ *
+ * @param {Array} items The projects or groups stored in the local storage
+ * @returns The items, sorted by frequency and last access date
+ */
+const sortItemsByFrequencyAndLastAccess = (items) =>
+ items.sort((itemA, itemB) => {
+ // Sort all frequent items in decending order of frequency
+ // and then by lastAccessedOn with recent most first
+ if (itemA.frequency !== itemB.frequency) {
+ return itemB.frequency - itemA.frequency;
+ } else if (itemA.lastAccessedOn !== itemB.lastAccessedOn) {
+ return itemB.lastAccessedOn - itemA.lastAccessedOn;
+ }
+
+ return 0;
+ });
+
+// This imitates getTopFrequentItems from app/assets/javascripts/frequent_items/utils.js, but
+// adjusts the rules to accommodate for the context switcher's designs.
+export const getTopFrequentItems = (items = [], maxCount) => {
+ const frequentItems = items.filter((item) => item.frequency >= FREQUENT_ITEMS.ELIGIBLE_FREQUENCY);
+ sortItemsByFrequencyAndLastAccess(frequentItems);
+
+ return frequentItems.slice(0, maxCount);
+};
+
+const updateItemAccess = (item) => {
+ const now = Date.now();
+ const neverAccessed = !item.lastAccessedOn;
+ const shouldUpdate =
+ neverAccessed || Math.abs(now - item.lastAccessedOn) / FIFTEEN_MINUTES_IN_MS > 1;
+ const currentFrequency = item.frequency ?? 0;
+
+ return {
+ ...item,
+ frequency: shouldUpdate ? currentFrequency + 1 : currentFrequency,
+ lastAccessedOn: shouldUpdate ? now : item.lastAccessedOn,
+ };
+};
+
+export const trackContextAccess = (username, context) => {
+ if (!AccessorUtilities.canUseLocalStorage()) {
+ return false;
+ }
+
+ const storageKey = `${username}/frequent-${context.namespace}`;
+ const storedRawItems = localStorage.getItem(storageKey);
+ const storedItems = storedRawItems ? JSON.parse(storedRawItems) : [];
+ const existingItemIndex = storedItems.findIndex(
+ (cachedItem) => cachedItem.id === context.item.id,
+ );
+
+ if (existingItemIndex > -1) {
+ storedItems[existingItemIndex] = updateItemAccess(storedItems[existingItemIndex]);
+ } else {
+ const newItem = updateItemAccess(context.item);
+ if (storedItems.length === FREQUENT_ITEMS.MAX_COUNT) {
+ sortItemsByFrequencyAndLastAccess(storedItems);
+ storedItems.pop();
+ }
+ storedItems.push(newItem);
+ }
+
+ 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,
+ }));
diff --git a/app/assets/javascripts/syntax_highlight.js b/app/assets/javascripts/syntax_highlight.js
index cb2bf24abc7..065e1080897 100644
--- a/app/assets/javascripts/syntax_highlight.js
+++ b/app/assets/javascripts/syntax_highlight.js
@@ -15,6 +15,10 @@ export default function syntaxHighlight($els = null) {
const els = $els.get ? $els.get() : $els;
const handler = (el) => {
+ if (el.classList === undefined) {
+ return el;
+ }
+
if (el.classList.contains('js-syntax-highlight')) {
// Given the element itself, apply highlighting
return el.classList.add(gon.user_color_scheme);
diff --git a/app/assets/javascripts/task_list.js b/app/assets/javascripts/task_list.js
index a7760ad5d0b..bb344ade344 100644
--- a/app/assets/javascripts/task_list.js
+++ b/app/assets/javascripts/task_list.js
@@ -1,7 +1,7 @@
import $ from 'jquery';
import 'deckar01-task_list';
import { __ } from '~/locale';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from './lib/utils/axios_utils';
export default class TaskList {
diff --git a/app/assets/javascripts/terraform/components/init_command_modal.vue b/app/assets/javascripts/terraform/components/init_command_modal.vue
index 0d8a883972f..ad7f4774bd2 100644
--- a/app/assets/javascripts/terraform/components/init_command_modal.vue
+++ b/app/assets/javascripts/terraform/components/init_command_modal.vue
@@ -33,7 +33,7 @@ export default {
closeModalProps() {
return {
text: this.$options.i18n.closeText,
- attributes: [],
+ attributes: {},
};
},
},
diff --git a/app/assets/javascripts/terraform/components/states_table_actions.vue b/app/assets/javascripts/terraform/components/states_table_actions.vue
index 773ecf1d5d5..586b3e96e44 100644
--- a/app/assets/javascripts/terraform/components/states_table_actions.vue
+++ b/app/assets/javascripts/terraform/components/states_table_actions.vue
@@ -69,7 +69,7 @@ export default {
cancelModalProps() {
return {
text: this.$options.i18n.modalCancel,
- attributes: [],
+ attributes: {},
};
},
disableModalSubmit() {
@@ -81,7 +81,7 @@ export default {
primaryModalProps() {
return {
text: this.$options.i18n.modalRemove,
- attributes: [{ disabled: this.disableModalSubmit }, { variant: 'danger' }],
+ attributes: { disabled: this.disableModalSubmit, variant: 'danger' },
};
},
commandModalId() {
diff --git a/app/assets/javascripts/toggles/index.js b/app/assets/javascripts/toggles/index.js
index 5848b3a424c..500fe8c1150 100644
--- a/app/assets/javascripts/toggles/index.js
+++ b/app/assets/javascripts/toggles/index.js
@@ -17,20 +17,12 @@ export const initToggle = (el) => {
return new Vue({
el,
- props: {
- disabled: {
- type: Boolean,
- required: false,
- default: parseBoolean(disabled),
- },
- isLoading: {
- type: Boolean,
- required: false,
- default: parseBoolean(isLoading),
- },
- },
+ name: 'ToggleFromHtml',
+
data() {
return {
+ disabled: parseBoolean(disabled),
+ isLoading: parseBoolean(isLoading),
value: parseBoolean(isChecked),
};
},
diff --git a/app/assets/javascripts/token_access/components/inbound_token_access.vue b/app/assets/javascripts/token_access/components/inbound_token_access.vue
index feaf9072ee2..1904846fcbc 100644
--- a/app/assets/javascripts/token_access/components/inbound_token_access.vue
+++ b/app/assets/javascripts/token_access/components/inbound_token_access.vue
@@ -9,7 +9,7 @@ import {
GlSprintf,
GlToggle,
} from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import inboundAddProjectCIJobTokenScopeMutation from '../graphql/mutations/inbound_add_project_ci_job_token_scope.mutation.graphql';
diff --git a/app/assets/javascripts/token_access/components/opt_in_jwt.vue b/app/assets/javascripts/token_access/components/opt_in_jwt.vue
index c774f37b1e4..9485e0c3667 100644
--- a/app/assets/javascripts/token_access/components/opt_in_jwt.vue
+++ b/app/assets/javascripts/token_access/components/opt_in_jwt.vue
@@ -1,7 +1,7 @@
<script>
import { GlLink, GlLoadingIcon, GlSprintf, GlToggle } from '@gitlab/ui';
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, s__ } from '~/locale';
import updateOptInJwtMutation from '../graphql/mutations/update_opt_in_jwt.mutation.graphql';
import getOptInJwtSettingQuery from '../graphql/queries/get_opt_in_jwt_setting.query.graphql';
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 0deae1a1d82..d9c23c6c7f3 100644
--- a/app/assets/javascripts/token_access/components/outbound_token_access.vue
+++ b/app/assets/javascripts/token_access/components/outbound_token_access.vue
@@ -9,7 +9,7 @@ import {
GlSprintf,
GlToggle,
} from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import addProjectCIJobTokenScopeMutation from '../graphql/mutations/add_project_ci_job_token_scope.mutation.graphql';
diff --git a/app/assets/javascripts/token_access/components/token_access_app.vue b/app/assets/javascripts/token_access/components/token_access_app.vue
index 59d59757735..089159ac87b 100644
--- a/app/assets/javascripts/token_access/components/token_access_app.vue
+++ b/app/assets/javascripts/token_access/components/token_access_app.vue
@@ -1,5 +1,4 @@
<script>
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import OutboundTokenAccess from './outbound_token_access.vue';
import InboundTokenAccess from './inbound_token_access.vue';
import OptInJwt from './opt_in_jwt.vue';
@@ -10,17 +9,11 @@ export default {
InboundTokenAccess,
OptInJwt,
},
- mixins: [glFeatureFlagMixin()],
- computed: {
- inboundTokenAccessEnabled() {
- return this.glFeatures.ciInboundJobTokenScope;
- },
- },
};
</script>
<template>
<div>
- <inbound-token-access v-if="inboundTokenAccessEnabled" class="gl-pb-5" />
+ <inbound-token-access class="gl-pb-5" />
<outbound-token-access class="gl-py-5" />
<opt-in-jwt />
</div>
diff --git a/app/assets/javascripts/token_access/components/token_projects_table.vue b/app/assets/javascripts/token_access/components/token_projects_table.vue
index c00dd882895..ee88b4ec339 100644
--- a/app/assets/javascripts/token_access/components/token_projects_table.vue
+++ b/app/assets/javascripts/token_access/components/token_projects_table.vue
@@ -29,6 +29,9 @@ export default {
removeProject(project) {
this.$emit('removeProject', project);
},
+ namespaceFallback(namespace) {
+ return namespace?.fullPath || '';
+ },
},
};
</script>
@@ -51,7 +54,9 @@ export default {
</template>
<template #cell(namespace)="{ item }">
- <span data-testid="token-access-project-namespace">{{ item.namespace.fullPath }}</span>
+ <span data-testid="token-access-project-namespace">
+ {{ namespaceFallback(item.namespace) }}
+ </span>
</template>
<template #cell(actions)="{ item }">
diff --git a/app/assets/javascripts/usage_quotas/storage/constants.js b/app/assets/javascripts/usage_quotas/storage/constants.js
index fab18cefc60..bd8cd372ecf 100644
--- a/app/assets/javascripts/usage_quotas/storage/constants.js
+++ b/app/assets/javascripts/usage_quotas/storage/constants.js
@@ -26,7 +26,6 @@ export const uploadsPopoverContent = s__(
'NamespaceStorage|Uploads are not counted in namespace storage quotas.',
);
-export const PROJECT_TABLE_LABEL_PROJECT = __('Project');
export const PROJECT_TABLE_LABEL_STORAGE_TYPE = s__('UsageQuota|Storage type');
export const PROJECT_TABLE_LABEL_USAGE = s__('UsageQuota|Usage');
diff --git a/app/assets/javascripts/user_lists/components/add_user_modal.vue b/app/assets/javascripts/user_lists/components/add_user_modal.vue
index e982d10f63b..37c9548ad64 100644
--- a/app/assets/javascripts/user_lists/components/add_user_modal.vue
+++ b/app/assets/javascripts/user_lists/components/add_user_modal.vue
@@ -19,11 +19,11 @@ export default {
modalOptions: {
actionPrimary: {
text: s__('UserLists|Add'),
- attributes: [{ 'data-testid': 'confirm-add-user-ids', variant: 'confirm' }],
+ attributes: { 'data-testid': 'confirm-add-user-ids', variant: 'confirm' },
},
actionCancel: {
text: s__('UserLists|Cancel'),
- attributes: [{ 'data-testid': 'cancel-add-user-ids' }],
+ attributes: { 'data-testid': 'cancel-add-user-ids' },
},
modalId: ADD_USER_MODAL_ID,
static: true,
diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js
index 1af47b020f7..a401a9bbf2f 100644
--- a/app/assets/javascripts/users_select/index.js
+++ b/app/assets/javascripts/users_select/index.js
@@ -6,6 +6,7 @@ import $ from 'jquery';
import { escape, template, uniqBy } from 'lodash';
import { AJAX_USERS_SELECT_PARAMS_MAP } from 'ee_else_ce/users_select/constants';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
+import { TYPE_MERGE_REQUEST } from '~/issues/constants';
import { isUserBusy } from '~/set_status_modal/utils';
import { fixTitle, dispose } from '~/tooltips';
import axios from '~/lib/utils/axios_utils';
@@ -647,7 +648,7 @@ UsersSelect.prototype.users = function (query, options, callback) {
...getAjaxUsersSelectParams(options, AJAX_USERS_SELECT_PARAMS_MAP),
};
- const isMergeRequest = options.issuableType === 'merge_request';
+ const isMergeRequest = options.issuableType === TYPE_MERGE_REQUEST;
const isEditMergeRequest = !options.issuableType && options.iid && options.targetBranch;
const isNewMergeRequest = !options.issuableType && !options.iid && options.targetBranch;
@@ -684,7 +685,7 @@ UsersSelect.prototype.renderRow = function (
img,
elsClassName,
) {
- const tooltip = issuableType === 'merge_request' && !user.can_merge ? __('Cannot merge') : '';
+ const tooltip = issuableType === TYPE_MERGE_REQUEST && !user.can_merge ? __('Cannot merge') : '';
const tooltipClass = tooltip ? `has-tooltip` : '';
const selectedClass = selected === true ? 'is-active' : '';
const linkClasses = `${selectedClass} ${tooltipClass}`;
@@ -725,7 +726,7 @@ UsersSelect.prototype.renderRowAvatar = function (issuableType, user, img) {
}
const mergeIcon =
- issuableType === 'merge_request' && !user.can_merge
+ issuableType === TYPE_MERGE_REQUEST && !user.can_merge
? spriteIcon('warning-solid', 's12 merge-icon')
: '';
diff --git a/app/assets/javascripts/validators/length_validator.js b/app/assets/javascripts/validators/length_validator.js
new file mode 100644
index 00000000000..6ce453fe40b
--- /dev/null
+++ b/app/assets/javascripts/validators/length_validator.js
@@ -0,0 +1,56 @@
+import InputValidator from '~/validators/input_validator';
+
+const errorMessageClass = 'gl-field-error';
+
+export const isAboveMaxLength = (str, maxLength) => {
+ return str.length > parseInt(maxLength, 10);
+};
+
+export const isBelowMinLength = (value, minLength, allowEmpty) => {
+ const isValueNotAllowedOrNotEmpty = allowEmpty !== 'true' || value.length !== 0;
+ const isValueBelowMinLength = value.length < parseInt(minLength, 10);
+ return isValueBelowMinLength && isValueNotAllowedOrNotEmpty;
+};
+
+export default class LengthValidator extends InputValidator {
+ constructor(opts = {}) {
+ super();
+
+ const container = opts.container || '';
+ const validateLengthElements = document.querySelectorAll(`${container} .js-validate-length`);
+
+ validateLengthElements.forEach((element) =>
+ element.addEventListener('input', this.eventHandler.bind(this)),
+ );
+ }
+
+ eventHandler(event) {
+ this.inputDomElement = event.target;
+ this.inputErrorMessage = this.inputDomElement.parentElement.querySelector(
+ `.${errorMessageClass}`,
+ );
+
+ const { value } = this.inputDomElement;
+ const {
+ minLength,
+ minLengthMessage,
+ maxLengthMessage,
+ maxLength,
+ allowEmpty,
+ } = this.inputDomElement.dataset;
+
+ this.invalidInput = false;
+
+ if (isAboveMaxLength(value, maxLength)) {
+ this.invalidInput = true;
+ this.errorMessage = maxLengthMessage;
+ }
+
+ if (isBelowMinLength(value, minLength, allowEmpty)) {
+ this.invalidInput = true;
+ this.errorMessage = minLengthMessage;
+ }
+
+ this.setValidationStateAndMessage();
+ }
+}
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 917ed259dd0..f2ec8f589ce 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
@@ -142,7 +142,7 @@ export default {
:title="setTooltip(btn)"
:href="btn.href"
:target="btn.target"
- :class="[{ 'gl-mr-3': index !== tertiaryButtons.length - 1 }, btn.class]"
+ :class="[{ 'gl-mr-1': index !== tertiaryButtons.length - 1 }, btn.class]"
:data-clipboard-text="btn.dataClipboardText"
:data-qa-selector="actionButtonQaSelector(btn)"
:data-method="btn.dataMethod"
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 4b65d6fd9ac..74922dd922c 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
@@ -1,10 +1,11 @@
<script>
-import { GlButton, GlSprintf, GlLink } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { GlButton, GlSprintf } from '@gitlab/ui';
+import { createAlert } from '~/alert';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import { HTTP_STATUS_UNAUTHORIZED } from '~/lib/utils/http_status';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { s__, __ } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import eventHub from '../../event_hub';
import approvalsMixin from '../../mixins/approvals';
import MrWidgetContainer from '../mr_widget_container.vue';
@@ -12,8 +13,7 @@ import MrWidgetIcon from '../mr_widget_icon.vue';
import { INVALID_RULES_DOCS_PATH } from '../../constants';
import ApprovalsSummary from './approvals_summary.vue';
import ApprovalsSummaryOptional from './approvals_summary_optional.vue';
-import { FETCH_LOADING, FETCH_ERROR, APPROVE_ERROR, UNAPPROVE_ERROR } from './messages';
-import { humanizeInvalidApproversRules } from './humanized_text';
+import { FETCH_LOADING, APPROVE_ERROR, UNAPPROVE_ERROR } from './messages';
export default {
name: 'MRWidgetApprovals',
@@ -24,7 +24,6 @@ export default {
ApprovalsSummaryOptional,
GlButton,
GlSprintf,
- GlLink,
},
mixins: [approvalsMixin, glFeatureFlagsMixin()],
props: {
@@ -59,10 +58,8 @@ export default {
},
data() {
return {
- fetchingApprovals: true,
hasApprovalAuthError: false,
isApproving: false,
- updatedCount: 0,
};
},
computed: {
@@ -70,7 +67,7 @@ export default {
return this.mr.approvalsWidgetType === 'base';
},
isApproved() {
- return Boolean(this.approvals.approved);
+ return Boolean(this.approvals.approved || this.approvedBy.length);
},
isOptional() {
return this.isOptionalDefault !== null ? this.isOptionalDefault : !this.approvedBy.length;
@@ -78,26 +75,25 @@ export default {
hasAction() {
return Boolean(this.action);
},
- approvals() {
- return this.mr.approvals || {};
- },
invalidRules() {
- return this.approvals.invalid_approvers_rules || [];
+ return this.approvals.approvalState?.invalidApproversRules || [];
},
hasInvalidRules() {
- return this.approvals.merge_request_approvers_available && this.invalidRules.length;
+ return this.mr.mergeRequestApproversAvailable && this.invalidRules.length;
},
invalidRulesText() {
- return humanizeInvalidApproversRules(this.invalidRules);
+ return this.invalidRules.length;
},
approvedBy() {
- return this.approvals.approved_by ? this.approvals.approved_by.map((x) => x.user) : [];
+ return this.approvals.approvedBy?.nodes || [];
},
userHasApproved() {
- return Boolean(this.approvals.user_has_approved);
+ return this.approvedBy.some(
+ (approver) => getIdFromGraphQLId(approver.id) === gon.current_user_id,
+ );
},
userCanApprove() {
- return Boolean(this.approvals.user_can_approve);
+ return Boolean(this.approvals.userPermissions.canApprove);
},
showApprove() {
return !this.userHasApproved && this.userCanApprove && this.mr.isOpen;
@@ -135,19 +131,6 @@ export default {
: this.$options.i18n.invalidRuleSingular;
},
},
- created() {
- this.refreshApprovals()
- .then(() => {
- this.fetchingApprovals = false;
- })
- .catch(() =>
- this.alerts.push(
- createAlert({
- message: FETCH_ERROR,
- }),
- ),
- );
- },
methods: {
approve() {
if (this.requirePasswordToApprove) {
@@ -196,16 +179,14 @@ export default {
this.isApproving = true;
this.clearError();
return serviceFn()
- .then((data) => {
- this.mr.setApprovals(data);
- this.updatedCount += 1;
-
+ .then(() => {
if (!window.gon?.features?.realtimeMrStatusChange) {
eventHub.$emit('MRWidgetUpdateRequested');
eventHub.$emit('ApprovalUpdated');
}
- this.$emit('updated');
+ // TODO: Remove this line when we move to Apollo subscriptions
+ this.$apollo.queries.approvals.refetch();
})
.catch(errFn)
.then(() => {
@@ -217,10 +198,10 @@ export default {
linkToInvalidRules: INVALID_RULES_DOCS_PATH,
i18n: {
invalidRuleSingular: s__(
- 'mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}',
+ 'mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it.',
),
invalidRulesPlural: s__(
- 'mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}',
+ 'mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them.',
),
learnMore: __('Learn more.'),
},
@@ -230,7 +211,7 @@ export default {
<mr-widget-container>
<div class="js-mr-approvals d-flex align-items-start align-items-md-center">
<mr-widget-icon name="approval" />
- <div v-if="fetchingApprovals">{{ $options.FETCH_LOADING }}</div>
+ <div v-if="$apollo.queries.approvals.loading">{{ $options.FETCH_LOADING }}</div>
<template v-else>
<div class="gl-display-flex gl-flex-direction-column">
<div class="gl-display-flex gl-flex-direction-row gl-align-items-center">
@@ -252,22 +233,13 @@ export default {
/>
<approvals-summary
v-else
- :project-path="mr.targetProjectFullPath"
- :iid="`${mr.iid}`"
- :updated-count="updatedCount"
+ :approval-state="approvals"
:multiple-approval-rules-available="mr.multipleApprovalRulesAvailable"
/>
</div>
<div v-if="hasInvalidRules" class="gl-text-gray-400 gl-mt-2" data-testid="invalid-rules">
<gl-sprintf :message="pluralizedRuleText">
- <template #rules>
- {{ invalidRulesText }}
- </template>
- <template #link>
- <gl-link :href="$options.linkToInvalidRules" target="_blank">
- {{ $options.i18n.learnMore }}
- </gl-link>
- </template>
+ <template #rules>{{ invalidRulesText }}</template>
</gl-sprintf>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
index 697d953874c..2af033bb80f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
@@ -1,5 +1,4 @@
<script>
-import { GlSkeletonLoader } from '@gitlab/ui';
import { toNounSeriesText } from '~/lib/utils/grammar';
import { n__, sprintf } from '~/locale';
import {
@@ -10,49 +9,21 @@ import {
import UserAvatarList from '~/vue_shared/components/user_avatar/user_avatar_list.vue';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { getApprovalRuleNamesLeft } from 'ee_else_ce/vue_merge_request_widget/mappers';
-import approvedByQuery from 'ee_else_ce/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql';
export default {
- apollo: {
- approvalState: {
- query: approvedByQuery,
- variables() {
- return {
- projectPath: this.projectPath,
- iid: this.iid,
- };
- },
- update: (data) => data.project.mergeRequest,
- },
- },
components: {
- GlSkeletonLoader,
UserAvatarList,
},
props: {
- projectPath: {
- type: String,
- required: true,
- },
- iid: {
- type: String,
- required: true,
- },
- updatedCount: {
- type: Number,
- required: false,
- default: 0,
- },
multipleApprovalRulesAvailable: {
type: Boolean,
required: false,
default: false,
},
- },
- data() {
- return {
- approvalState: {},
- };
+ approvalState: {
+ type: Object,
+ required: true,
+ },
},
computed: {
approvers() {
@@ -134,37 +105,20 @@ export default {
return gon.current_user_id;
},
},
- watch: {
- updatedCount() {
- this.$apollo.queries.approvalState.refetch();
- },
- },
};
</script>
<template>
<div data-qa-selector="approvals_summary_content">
- <div
- v-if="$apollo.queries.approvalState.loading"
- class="gl-display-inline-block gl-vertical-align-middle"
- style="width: 132px; height: 24px"
- >
- <gl-skeleton-loader :width="132" :height="24">
- <rect width="100" height="24" x="0" y="0" rx="4" />
- <circle cx="120" cy="12" r="12" />
- </gl-skeleton-loader>
- </div>
- <template v-else>
- <span class="gl-font-weight-bold">{{ approvalLeftMessage }}</span>
- <template v-if="hasApprovers">
- <span v-if="approvalLeftMessage">{{ message }}</span>
- <span v-else class="gl-font-weight-bold">{{ message }}</span>
- <user-avatar-list
- class="gl-display-inline-block gl-vertical-align-middle gl-pt-1"
- :img-size="24"
- :items="approvers"
- />
- </template>
+ <span class="gl-font-weight-bold">{{ approvalLeftMessage }}</span>
+ <template v-if="hasApprovers">
+ <span v-if="approvalLeftMessage">{{ message }}</span>
+ <span v-else class="gl-font-weight-bold">{{ message }}</span>
+ <user-avatar-list
+ class="gl-display-inline-block gl-vertical-align-middle gl-pt-1"
+ :img-size="24"
+ :items="approvers"
+ />
</template>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approvals.query.graphql b/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approvals.query.graphql
new file mode 100644
index 00000000000..437ae578cd0
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approvals.query.graphql
@@ -0,0 +1,18 @@
+#import "~/graphql_shared/fragments/user.fragment.graphql"
+
+query approvedBy($projectPath: ID!, $iid: String!) {
+ project(fullPath: $projectPath) {
+ id
+ mergeRequest(iid: $iid) {
+ id
+ approvedBy {
+ nodes {
+ ...User
+ }
+ }
+ userPermissions {
+ canApprove
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql b/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql
deleted file mode 100644
index c8cae6a8885..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql
+++ /dev/null
@@ -1,16 +0,0 @@
-query approvedBy($projectPath: ID!, $iid: String!) {
- project(fullPath: $projectPath) {
- id
- mergeRequest(iid: $iid) {
- id
- approvedBy {
- nodes {
- id
- name
- avatarUrl
- webUrl
- }
- }
- }
- }
-}
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 d6d1cae4029..306ed664326 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,5 +1,5 @@
<script>
-import { createAlert } from '~/flash';
+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';
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 b78293a9815..028f5370028 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
@@ -313,7 +313,7 @@ export default {
:status="statusIconName"
:is-loading="isLoadingSummary"
:class="{ 'gl-cursor-pointer': isCollapsible }"
- class="gl-p-5"
+ class="gl-pl-5 gl-pr-4 gl-py-4"
@mousedown="onRowMouseDown"
@mouseup="onRowMouseUp"
>
@@ -381,7 +381,7 @@ export default {
v-else-if="hasFullData"
:items="fullData"
:min-item-size="32"
- class="report-block-container gl-px-5 gl-py-0"
+ class="report-block-container gl-p-0"
>
<template #default="{ item, index, active }">
<dynamic-scroller-item :item="item" :active="active" :class="{ active }">
@@ -389,7 +389,7 @@ export default {
:class="{
'gl-border-b-solid gl-border-b-1 gl-border-gray-100': index !== fullData.length - 1,
}"
- class="gl-py-3 gl-pl-7"
+ class="gl-py-3 gl-pl-9"
data-testid="extension-list-item"
>
<gl-intersection-observer
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
index c762922d890..b192ccfa379 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
@@ -31,7 +31,7 @@ export default {
};
</script>
<template>
- <h4 class="js-mr-widget-author">
+ <h4 class="js-mr-widget-author gl-flex-grow-1">
{{ actionText }}
<mr-widget-author :author="author" />
<span class="sr-only">{{ dateReadable }} ({{ dateTitle }})</span>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/state_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/state_container.vue
index f7d6f7b4345..3e79c49994f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/state_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/state_container.vue
@@ -62,7 +62,7 @@ export default {
<slot name="loading">
<div class="gl-display-flex">
<status-icon status="loading" />
- <div class="media-body">
+ <div class="media-body gl-display-flex gl-align-items-center">
<slot></slot>
</div>
</div>
@@ -78,7 +78,7 @@ export default {
'gl-display-flex gl-align-items-center': actions.length,
'gl-md-display-flex gl-align-items-center gl-flex-wrap gl-gap-3': !actions.length,
}"
- class="media-body gl-line-height-24"
+ class="media-body gl-line-height-normal"
>
<slot></slot>
<div
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
index 38f7d3d2c96..bcae1a12344 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
@@ -2,7 +2,7 @@
import { GlSkeletonLoader, GlSprintf } from '@gitlab/ui';
import autoMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/auto_merge';
import autoMergeEnabledQuery from 'ee_else_ce/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import { AUTO_MERGE_STRATEGIES } from '../../constants';
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
index 46392565088..4e2b12799d0 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
@@ -1,7 +1,7 @@
<script>
import { GlTooltipDirective } from '@gitlab/ui';
import api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__, __ } from '~/locale';
import { OPEN_REVERT_MODAL, OPEN_CHERRY_PICK_MODAL } from '~/projects/commit/constants';
import modalEventHub from '~/projects/commit/event_hub';
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
index ec6c2cf34c0..fac8d37712a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -1,6 +1,7 @@
<script>
-import { GlButton, GlSkeletonLoader } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { GlButton, GlLink, GlModal, GlSkeletonLoader } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { createAlert } from '~/alert';
import { __, s__ } from '~/locale';
import toast from '~/vue_shared/plugins/global_toast';
import simplePoll from '~/lib/utils/simple_poll';
@@ -19,6 +20,28 @@ const i18n = {
export default {
name: 'MRWidgetRebase',
i18n,
+ modal: {
+ id: 'rebase-security-risk-modal',
+ title: s__('mrWidget|Are you sure you want to rebase?'),
+ actionPrimary: {
+ text: s__('mrWidget|Rebase'),
+ attributes: {
+ variant: 'danger',
+ },
+ },
+ actionCancel: {
+ text: __('Cancel'),
+ attributes: {
+ variant: 'default',
+ },
+ },
+ },
+ runPipelinesInTheParentProjectHelpPath: helpPagePath(
+ '/ci/pipelines/merge_request_pipelines.html',
+ {
+ anchor: 'run-pipelines-in-the-parent-project',
+ },
+ ),
apollo: {
state: {
query: rebaseQuery,
@@ -30,11 +53,18 @@ export default {
},
components: {
BoldText,
- GlSkeletonLoader,
GlButton,
+ GlLink,
+ GlModal,
+ GlSkeletonLoader,
StateContainer,
},
mixins: [mergeRequestQueryVariablesMixin],
+ inject: {
+ canCreatePipelineInTargetProject: {
+ default: false,
+ },
+ },
props: {
mr: {
type: Object,
@@ -84,6 +114,21 @@ export default {
(this.mr.onlyAllowMergeIfPipelineSucceeds && this.mr.allowMergeOnSkippedPipeline)
);
},
+ isForkMergeRequest() {
+ return this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath;
+ },
+ isLatestPipelineCreatedInTargetProject() {
+ const latestPipeline = this.state.pipelines.nodes[0];
+
+ return latestPipeline?.project?.fullPath === this.mr.targetProjectFullPath;
+ },
+ shouldShowSecurityWarning() {
+ return (
+ this.canCreatePipelineInTargetProject &&
+ this.isForkMergeRequest &&
+ !this.isLatestPipelineCreatedInTargetProject
+ );
+ },
},
methods: {
rebase({ skipCi = false } = {}) {
@@ -110,6 +155,13 @@ export default {
rebaseWithoutCi() {
return this.rebase({ skipCi: true });
},
+ tryRebase() {
+ if (this.shouldShowSecurityWarning) {
+ this.$refs.modal.show();
+ } else {
+ this.rebase();
+ }
+ },
checkRebaseStatus(continuePolling, stopPolling) {
this.service
.poll()
@@ -142,71 +194,103 @@ export default {
};
</script>
<template>
- <state-container :mr="mr" :status="status" :is-loading="isLoading">
- <template #loading>
- <gl-skeleton-loader :width="334" :height="30">
- <rect x="0" y="3" width="24" height="24" rx="4" />
- <rect x="32" y="5" width="302" height="20" rx="4" />
- </gl-skeleton-loader>
- </template>
- <template v-if="!isLoading">
- <span
- v-if="rebaseInProgress || isMakingRequest"
- class="gl-ml-0! gl-text-body!"
- data-testid="rebase-message"
- >{{ s__('mrWidget|Rebase in progress') }}</span
- >
- <span
- v-if="!rebaseInProgress && !canPushToSourceBranch"
- class="gl-text-body! gl-ml-0!"
- data-testid="rebase-message"
- >
- <bold-text :message="$options.i18n.rebaseError" />
- </span>
- <div
- v-if="!rebaseInProgress && canPushToSourceBranch && !isMakingRequest"
- class="accept-merge-holder clearfix js-toggle-container media gl-md-display-flex gl-flex-wrap gl-flex-grow-1"
- >
+ <div>
+ <state-container :mr="mr" :status="status" :is-loading="isLoading">
+ <template #loading>
+ <gl-skeleton-loader :width="334" :height="30">
+ <rect x="0" y="3" width="24" height="24" rx="4" />
+ <rect x="32" y="5" width="302" height="20" rx="4" />
+ </gl-skeleton-loader>
+ </template>
+ <template v-if="!isLoading">
<span
- v-if="!rebasingError"
- class="gl-w-100 gl-md-w-auto gl-flex-grow-1 gl-ml-0! gl-text-body! gl-md-mr-3"
+ v-if="rebaseInProgress || isMakingRequest"
+ class="gl-ml-0! gl-text-body!"
data-testid="rebase-message"
- data-qa-selector="no_fast_forward_message_content"
+ >{{ s__('mrWidget|Rebase in progress') }}</span
>
- <bold-text :message="$options.i18n.rebaseError" />
- </span>
<span
- v-else
- class="gl-font-weight-bold danger gl-w-100 gl-md-w-auto gl-flex-grow-1 gl-md-mr-3"
+ v-if="!rebaseInProgress && !canPushToSourceBranch"
+ class="gl-text-body! gl-ml-0!"
data-testid="rebase-message"
- >{{ rebasingError }}</span
>
- </div>
- </template>
- <template v-if="!isLoading" #actions>
- <gl-button
- :loading="isMakingRequest"
- variant="confirm"
- size="small"
- data-qa-selector="mr_rebase_button"
- data-testid="standard-rebase-button"
- class="gl-align-self-start"
- @click="rebase"
- >
- {{ s__('mrWidget|Rebase') }}
- </gl-button>
- <gl-button
- v-if="showRebaseWithoutPipeline"
- :loading="isMakingRequest"
- variant="confirm"
- size="small"
- category="secondary"
- data-testid="rebase-without-ci-button"
- class="gl-align-self-start gl-mr-2"
- @click="rebaseWithoutCi"
- >
- {{ s__('mrWidget|Rebase without pipeline') }}
- </gl-button>
- </template>
- </state-container>
+ <bold-text :message="$options.i18n.rebaseError" />
+ </span>
+ <div
+ v-if="!rebaseInProgress && canPushToSourceBranch && !isMakingRequest"
+ class="accept-merge-holder clearfix js-toggle-container media gl-md-display-flex gl-flex-wrap gl-flex-grow-1"
+ >
+ <span
+ v-if="!rebasingError"
+ class="gl-w-100 gl-md-w-auto gl-flex-grow-1 gl-ml-0! gl-text-body! gl-md-mr-3"
+ data-testid="rebase-message"
+ data-qa-selector="no_fast_forward_message_content"
+ >
+ <bold-text :message="$options.i18n.rebaseError" />
+ </span>
+ <span
+ v-else
+ class="gl-font-weight-bold danger gl-w-100 gl-md-w-auto gl-flex-grow-1 gl-md-mr-3"
+ data-testid="rebase-message"
+ >{{ rebasingError }}</span
+ >
+ </div>
+ </template>
+ <template v-if="!isLoading" #actions>
+ <gl-button
+ :loading="isMakingRequest"
+ variant="confirm"
+ size="small"
+ data-qa-selector="mr_rebase_button"
+ data-testid="standard-rebase-button"
+ class="gl-align-self-start"
+ @click="tryRebase"
+ >
+ {{ s__('mrWidget|Rebase') }}
+ </gl-button>
+ <gl-button
+ v-if="showRebaseWithoutPipeline"
+ :loading="isMakingRequest"
+ variant="confirm"
+ size="small"
+ category="secondary"
+ data-testid="rebase-without-ci-button"
+ class="gl-align-self-start gl-mr-2"
+ @click="rebaseWithoutCi"
+ >
+ {{ s__('mrWidget|Rebase without pipeline') }}
+ </gl-button>
+ </template>
+ </state-container>
+
+ <gl-modal
+ ref="modal"
+ :modal-id="$options.modal.id"
+ :title="$options.modal.title"
+ :action-primary="$options.modal.actionPrimary"
+ :action-cancel="$options.modal.actionCancel"
+ @primary="rebase"
+ >
+ <p>
+ {{
+ s__(
+ '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.',
+ )
+ }}
+ </p>
+ <p>
+ {{
+ s__(
+ "Pipelines|You should review the code thoroughly before running this pipeline with the parent project's CI/CD resources.",
+ )
+ }}
+ </p>
+ <p>
+ {{ s__('Pipelines|If you are unsure, 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>
+ </div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
index 850a4e2fd56..e6a0b5fd8be 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
@@ -1,7 +1,6 @@
<script>
import { GlButton, GlSprintf, GlLink } from '@gitlab/ui';
-import SafeHtml from '~/vue_shared/directives/safe_html';
-import emptyStateSVG from 'icons/_mr_widget_empty_state.svg';
+import EMPTY_STATE_SVG_URL from '@gitlab/svgs/dist/illustrations/merge_requests.svg?url';
import api from '~/api';
import { helpPagePath } from '~/helpers/help_page_helper';
@@ -12,25 +11,19 @@ export default {
GlSprintf,
GlLink,
},
- directives: {
- SafeHtml,
- },
props: {
mr: {
type: Object,
required: true,
},
},
- data() {
- return { emptyStateSVG };
- },
methods: {
onClickNewFile() {
api.trackRedisHllUserEvent('i_code_review_widget_nothing_merge_click_new_file');
},
},
ciHelpPage: helpPagePath('ci/quick_start/index.html'),
- safeHtmlConfig: { ADD_TAGS: ['use'] },
+ EMPTY_STATE_SVG_URL,
};
</script>
@@ -38,15 +31,18 @@ export default {
<div class="mr-widget-body mr-widget-empty-state">
<div class="row">
<div
- class="artwork col-md-5 order-md-last col-12 text-center d-flex justify-content-center align-items-center"
+ class="col-md-5 order-md-last col-12 text-center d-flex justify-content-center align-items-center svg-content svg-250 pb-0"
>
- <span v-safe-html:[$options.safeHtmlConfig]="emptyStateSVG"></span>
+ <img
+ :alt="s__('mrWidgetNothingToMerge|This merge request contains no changes.')"
+ :src="$options.EMPTY_STATE_SVG_URL"
+ />
</div>
<div class="text col-md-7 order-md-first col-12">
<p class="highlight">
{{ s__('mrWidgetNothingToMerge|This merge request contains no changes.') }}
</p>
- <p>
+ <p data-testid="nothing-to-merge-body">
<gl-sprintf
:message="
s__(
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 bb8990a48b1..9e67791afc0 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
@@ -11,10 +11,10 @@ import {
GlTooltipDirective,
GlSkeletonLoader,
} from '@gitlab/ui';
-import { isEmpty } from 'lodash';
+import { isEmpty, isNil } from 'lodash';
import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge';
import readyToMergeQuery from 'ee_else_ce/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants';
import { secondsToMilliseconds } from '~/lib/utils/datetime_utility';
import simplePoll from '~/lib/utils/simple_poll';
@@ -86,7 +86,7 @@ export default {
this.squashCommitMessage = this.state.defaultSquashCommitMessage;
}
- if (this.state.mergeTrainsCount !== null && this.state.mergeTrainsCount !== undefined) {
+ if (!isNil(this.state.mergeTrainsCount) && !this.pollingInterval) {
this.initPolling();
}
},
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
index 02d4f2499fe..7163e54985e 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton } from '@gitlab/ui';
import { produce } from 'immer';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __, s__ } from '~/locale';
import MergeRequest from '~/merge_request';
import BoldText from '~/vue_merge_request_widget/components/bold_text.vue';
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 73129a86877..a754d4e80ea 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
@@ -287,7 +287,7 @@ export default {
<template>
<section class="media-section" data-testid="widget-extension">
- <div class="gl-p-5 gl-align-items-center gl-display-flex">
+ <div class="gl-px-5 gl-py-4 gl-align-items-center gl-display-flex">
<status-icon
:level="1"
:name="widgetName"
diff --git a/app/assets/javascripts/vue_merge_request_widget/constants.js b/app/assets/javascripts/vue_merge_request_widget/constants.js
index 85ae298fcea..18503720814 100644
--- a/app/assets/javascripts/vue_merge_request_widget/constants.js
+++ b/app/assets/javascripts/vue_merge_request_widget/constants.js
@@ -2,6 +2,11 @@ import { s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import { stateToComponentMap as classStateMap, stateKey } from './stores/state_maps';
+export const FOUR_MINUTES_IN_MS = 1000 * 60 * 4;
+
+export const STATE_QUERY_POLLING_INTERVAL_DEFAULT = 5000;
+export const STATE_QUERY_POLLING_INTERVAL_BACKOFF = 2;
+
export const SUCCESS = 'success';
export const WARNING = 'warning';
export const INFO = 'info';
@@ -163,9 +168,6 @@ export const EXTENSION_ICON_CLASS = {
severityUnknown: 'gl-text-gray-400',
};
-export const EXTENSION_SUMMARY_FAILED_CLASS = 'gl-text-red-500';
-export const EXTENSION_SUMMARY_NEUTRAL_CLASS = 'gl-text-gray-700';
-
export const TELEMETRY_WIDGET_VIEWED = 'WIDGET_VIEWED';
export const TELEMETRY_WIDGET_EXPANDED = 'WIDGET_EXPANDED';
export const TELEMETRY_WIDGET_FULL_REPORT_CLICKED = 'WIDGET_FULL_REPORT_CLICKED';
diff --git a/app/assets/javascripts/vue_merge_request_widget/index.js b/app/assets/javascripts/vue_merge_request_widget/index.js
index 8d596465970..183f450854a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/index.js
@@ -13,7 +13,18 @@ Vue.use(Translate);
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
+ defaultClient: createDefaultClient(
+ {},
+ {
+ cacheConfig: {
+ typePolicies: {
+ MergeRequestApprovalState: {
+ merge: true,
+ },
+ },
+ },
+ },
+ ),
});
export default () => {
@@ -29,6 +40,9 @@ export default () => {
artifactsEndpointPlaceholder: gl.mrWidgetData.artifacts_endpoint_placeholder,
falsePositiveDocUrl: gl.mrWidgetData.false_positive_doc_url,
canViewFalsePositive: parseBoolean(gl.mrWidgetData.can_view_false_positive),
+ canCreatePipelineInTargetProject: parseBoolean(
+ gl.mrWidgetData.can_create_pipeline_in_target_project,
+ ),
},
...MrWidgetOptions,
apolloProvider,
diff --git a/app/assets/javascripts/vue_merge_request_widget/mixins/approvals.js b/app/assets/javascripts/vue_merge_request_widget/mixins/approvals.js
index 7d0871f696b..ae9111b9504 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mixins/approvals.js
+++ b/app/assets/javascripts/vue_merge_request_widget/mixins/approvals.js
@@ -1,7 +1,34 @@
+import { createAlert } from '~/alert';
+import approvedByQuery from 'ee_else_ce/vue_merge_request_widget/components/approvals/queries/approvals.query.graphql';
+import { FETCH_ERROR } from '../components/approvals/messages';
+
export default {
+ apollo: {
+ approvals: {
+ query: approvedByQuery,
+ variables() {
+ return {
+ projectPath: this.mr.targetProjectFullPath,
+ iid: `${this.mr.iid}`,
+ };
+ },
+ update: (data) => data.project.mergeRequest,
+ result({ data }) {
+ const { mergeRequest } = data.project;
+
+ this.mr.setApprovals(mergeRequest);
+ },
+ error() {
+ createAlert({
+ message: FETCH_ERROR,
+ });
+ },
+ },
+ },
data() {
return {
alerts: [],
+ approvals: {},
};
},
methods: {
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 ecbee6544ab..bbad2c13220 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
@@ -1,5 +1,5 @@
<script>
-import { isEmpty } from 'lodash';
+import { isEmpty, clamp } from 'lodash';
import {
registerExtension,
registeredExtensions,
@@ -9,8 +9,7 @@ import MrWidgetApprovals from 'ee_else_ce/vue_merge_request_widget/components/ap
import MRWidgetService from 'ee_else_ce/vue_merge_request_widget/services/mr_widget_service';
import MRWidgetStore from 'ee_else_ce/vue_merge_request_widget/stores/mr_widget_store';
import { stateToComponentMap as classState } from 'ee_else_ce/vue_merge_request_widget/stores/state_maps';
-import { createAlert } from '~/flash';
-import { secondsToMilliseconds } from '~/lib/utils/datetime_utility';
+import { createAlert } from '~/alert';
import notify from '~/lib/utils/notify';
import { sprintf, s__, __ } from '~/locale';
import Project from '~/pages/projects/project';
@@ -44,7 +43,13 @@ import UnresolvedDiscussionsState from './components/states/unresolved_discussio
import WorkInProgressState from './components/states/work_in_progress.vue';
import ExtensionsContainer from './components/extensions/container';
import WidgetContainer from './components/widget/app.vue';
-import { STATE_MACHINE, stateToComponentMap } from './constants';
+import {
+ STATE_MACHINE,
+ stateToComponentMap,
+ STATE_QUERY_POLLING_INTERVAL_DEFAULT,
+ STATE_QUERY_POLLING_INTERVAL_BACKOFF,
+ FOUR_MINUTES_IN_MS,
+} from './constants';
import eventHub from './event_hub';
import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variables';
import getStateQuery from './queries/get_state.query.graphql';
@@ -99,6 +104,7 @@ export default {
apollo: {
state: {
query: getStateQuery,
+ notifyOnNetworkStatusChange: true,
manual: true,
skip() {
return !this.mr;
@@ -106,10 +112,19 @@ export default {
variables() {
return this.mergeRequestQueryVariables;
},
- result({ data: { project } }) {
- if (project) {
- this.mr.setGraphqlData(project);
- this.loading = false;
+ pollInterval() {
+ return this.pollInterval;
+ },
+ result(response) {
+ if (!response.loading) {
+ this.pollInterval = this.apolloStateQueryPollingInterval;
+
+ if (response.data?.project) {
+ this.mr.setGraphqlData(response.data.project);
+ this.loading = false;
+ }
+ } else {
+ this.checkStatus(undefined, undefined, false);
}
},
subscribeToMore: {
@@ -158,9 +173,27 @@ export default {
loading: true,
recomputeComponentName: 0,
issuableId: false,
+ startingPollInterval: STATE_QUERY_POLLING_INTERVAL_DEFAULT,
+ pollInterval: STATE_QUERY_POLLING_INTERVAL_DEFAULT,
};
},
computed: {
+ apolloStateQueryMaxPollingInterval() {
+ return this.startingPollInterval + FOUR_MINUTES_IN_MS;
+ },
+ apolloStateQueryPollingInterval() {
+ if (this.startingPollInterval < 0) {
+ return 0;
+ }
+
+ const unboundedInterval = STATE_QUERY_POLLING_INTERVAL_BACKOFF * this.pollInterval;
+
+ return clamp(
+ unboundedInterval,
+ this.startingPollInterval,
+ this.apolloStateQueryMaxPollingInterval,
+ );
+ },
shouldRenderApprovals() {
return this.mr.state !== 'nothingToMerge';
},
@@ -284,7 +317,8 @@ export default {
mounted() {
MRWidgetService.fetchInitialData()
.then(({ data, headers }) => {
- this.startingPollInterval = Number(headers['POLL-INTERVAL']);
+ this.startingPollInterval =
+ Number(headers['POLL-INTERVAL']) || STATE_QUERY_POLLING_INTERVAL_DEFAULT;
this.initWidget(data);
})
.catch(() =>
@@ -295,9 +329,6 @@ export default {
},
beforeDestroy() {
eventHub.$off('mr.discussion.updated', this.checkStatus);
- if (this.pollingInterval) {
- this.pollingInterval.destroy();
- }
if (this.deploymentsInterval) {
this.deploymentsInterval.destroy();
@@ -332,7 +363,6 @@ export default {
this.initPostMergeDeploymentsPolling();
}
- this.initPolling();
this.bindEventHubListeners();
eventHub.$on('mr.discussion.updated', this.checkStatus);
@@ -363,8 +393,10 @@ export default {
createService(store) {
return new MRWidgetService(this.getServiceEndpoints(store));
},
- checkStatus(cb, isRebased) {
- this.$apollo.queries.state.refetch();
+ checkStatus(cb, isRebased, refetch = true) {
+ if (refetch) {
+ this.$apollo.queries.state.refetch();
+ }
return this.service
.checkStatus()
@@ -389,17 +421,6 @@ export default {
}
return Promise.resolve();
},
- initPolling() {
- if (this.startingPollInterval <= 0) return;
-
- this.pollingInterval = new SmartInterval({
- callback: this.checkStatus,
- startingInterval: this.startingPollInterval,
- maxInterval: this.startingPollInterval + secondsToMilliseconds(4 * 60),
- hiddenInterval: secondsToMilliseconds(6 * 60),
- incrementByFactorOf: 2,
- });
- },
initDeploymentsPolling() {
this.deploymentsInterval = this.deploymentsPoll(this.fetchPreMergeDeployments);
},
@@ -476,10 +497,10 @@ export default {
notify.notifyMe(title, message, this.mr.gitlabLogo);
},
resumePolling() {
- this.pollingInterval?.resume();
+ this.$apollo.queries.state.startPolling(this.pollInterval);
},
stopPolling() {
- this.pollingInterval?.stopTimer();
+ this.$apollo.queries.state.stopPolling();
},
bindEventHubListeners() {
eventHub.$on('MRWidgetUpdateRequested', (cb) => {
diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/get_state.subscription.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/get_state.subscription.graphql
index c7b53db1221..a6b35f20776 100644
--- a/app/assets/javascripts/vue_merge_request_widget/queries/get_state.subscription.graphql
+++ b/app/assets/javascripts/vue_merge_request_widget/queries/get_state.subscription.graphql
@@ -1,6 +1,7 @@
subscription getStateSubscription($issuableId: IssuableID!) {
mergeRequestMergeStatusUpdated(issuableId: $issuableId) {
... on MergeRequest {
+ id
detailedMergeStatus
}
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql
index 283177267d4..79ac87b7c37 100644
--- a/app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql
+++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/rebase.query.graphql
@@ -8,6 +8,15 @@ query rebaseQuery($projectPath: ID!, $iid: String!) {
userPermissions {
pushToSourceBranch
}
+ pipelines {
+ nodes {
+ id
+ project {
+ id
+ fullPath
+ }
+ }
+ }
}
}
}
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 81cb20475cc..cead42b12ae 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
@@ -32,5 +32,5 @@ export default function deviseState() {
) {
return stateKey.readyToMerge;
}
- return null;
+ return stateKey.checking;
}
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 f6a7ef58c10..13009651550 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
@@ -294,6 +294,9 @@ export default class MergeRequestStore {
// Security reports
this.sastComparisonPath = data.sast_comparison_path;
this.secretDetectionComparisonPath = data.secret_detection_comparison_path;
+
+ this.sastComparisonPathV2 = data.new_sast_comparison_path;
+ this.secretDetectionComparisonPathV2 = data.new_secret_detection_comparison_path;
}
get isNothingToMergeState() {
@@ -356,12 +359,11 @@ export default class MergeRequestStore {
initApprovals() {
this.isApproved = this.isApproved || false;
- this.approvals = this.approvals || null;
}
setApprovals(data) {
- this.approvals = data;
this.isApproved = data.approved || false;
+ this.approvals = true;
this.setState();
}
diff --git a/app/assets/javascripts/vue_shared/alert_details/components/system_notes/system_note.vue b/app/assets/javascripts/vue_shared/alert_details/components/system_notes/system_note.vue
index 634b7da3def..93581dbbd40 100644
--- a/app/assets/javascripts/vue_shared/alert_details/components/system_notes/system_note.vue
+++ b/app/assets/javascripts/vue_shared/alert_details/components/system_notes/system_note.vue
@@ -33,7 +33,11 @@ export default {
</script>
<template>
- <li :id="noteAnchorId" class="timeline-entry note system-note note-wrapper gl-p-0!">
+ <li
+ :id="noteAnchorId"
+ class="timeline-entry note system-note note-wrapper gl-p-0!"
+ data-qa-selector="alert_system_note_container"
+ >
<div class="gl-display-inline-flex gl-align-items-center gl-relative">
<div
class="gl-display-inline gl-bg-white gl-text-gray-200 gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-full gl-box-sizing-content-box gl-p-3 gl-mt-n2 gl-mr-6"
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 52a5d6e1b86..7b5ded9348f 100644
--- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
@@ -71,7 +71,7 @@ export default {
<ci-icon :status="status" />
<template v-if="showText">
- <span class="gl-ml-2">{{ status.text }}</span>
+ <span class="gl-ml-2 gl-white-space-nowrap">{{ status.text }}</span>
</template>
</gl-link>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/ci_cd_analytics/ci_cd_analytics_area_chart.vue b/app/assets/javascripts/vue_shared/components/ci_cd_analytics/ci_cd_analytics_area_chart.vue
index fb7105bd416..c89e843b660 100644
--- a/app/assets/javascripts/vue_shared/components/ci_cd_analytics/ci_cd_analytics_area_chart.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_cd_analytics/ci_cd_analytics_area_chart.vue
@@ -1,13 +1,11 @@
<script>
import { GlAreaChart } from '@gitlab/ui/dist/charts';
-import ResizableChartContainer from '~/vue_shared/components/resizable_chart/resizable_chart_container.vue';
import { CHART_CONTAINER_HEIGHT } from './constants';
export default {
name: 'CiCdAnalyticsAreaChart',
components: {
GlAreaChart,
- ResizableChartContainer,
},
props: {
chartData: {
@@ -27,24 +25,21 @@ export default {
<p>
<slot></slot>
</p>
- <resizable-chart-container>
- <template #default="{ width }">
- <gl-area-chart
- v-bind="$attrs"
- :width="width"
- :height="$options.chartContainerHeight"
- :data="chartData"
- :include-legend-avg-max="false"
- :option="areaChartOptions"
- >
- <template #tooltip-title>
- <slot name="tooltip-title"></slot>
- </template>
- <template #tooltip-content>
- <slot name="tooltip-content"></slot>
- </template>
- </gl-area-chart>
+ <gl-area-chart
+ v-bind="$attrs"
+ responsive
+ width="auto"
+ :height="$options.chartContainerHeight"
+ :data="chartData"
+ :include-legend-avg-max="false"
+ :option="areaChartOptions"
+ >
+ <template #tooltip-title>
+ <slot name="tooltip-title"></slot>
</template>
- </resizable-chart-container>
+ <template #tooltip-content>
+ <slot name="tooltip-content"></slot>
+ </template>
+ </gl-area-chart>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue b/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue
index 75386a3cd01..2f28ae5e0e2 100644
--- a/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue
@@ -1,6 +1,6 @@
<script>
import { isString } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import { DEFAULT_COLOR, COLOR_WIDGET_COLOR, DROPDOWN_VARIANT, ISSUABLE_COLORS } from './constants';
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 d0a634d8e54..65a601ed927 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
@@ -60,13 +60,11 @@ export default {
actionPrimary() {
return {
text: this.confirmButtonText,
- attributes: [
- {
- variant: 'danger',
- disabled: !this.isValid,
- 'data-qa-selector': 'confirm_danger_modal_button',
- },
- ],
+ attributes: {
+ variant: 'danger',
+ disabled: !this.isValid,
+ 'data-qa-selector': 'confirm_danger_modal_button',
+ },
};
},
actionCancel() {
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index dfeb12d5cf5..721f87ff4d6 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -168,7 +168,7 @@ export default {
.file-row {
display: flex;
align-items: center;
- height: 32px;
+ height: var(--file-row-height, 32px);
padding: 4px 8px;
margin-left: -8px;
margin-right: -8px;
diff --git a/app/assets/javascripts/vue_shared/components/file_row_header.vue b/app/assets/javascripts/vue_shared/components/file_row_header.vue
index 5afb2408c7e..b436872e463 100644
--- a/app/assets/javascripts/vue_shared/components/file_row_header.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row_header.vue
@@ -15,7 +15,7 @@ export default {
</script>
<template>
- <div class="file-row-header bg-white sticky-top p-2 js-file-row-header" :title="path">
+ <div class="file-row-header bg-white sticky-top gl-px-2 js-file-row-header" :title="path">
<gl-truncate :text="path" position="middle" class="bold" />
</div>
</template>
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 34f64dddc41..fe4f2d407f7 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
@@ -12,7 +12,7 @@ import {
import RecentSearchesStorageKeys from 'ee_else_ce/filtered_search/recent_searches_storage_keys';
import RecentSearchesService from '~/filtered_search/services/recent_searches_service';
import RecentSearchesStore from '~/filtered_search/stores/recent_searches_store';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import { SORT_DIRECTION } from './constants';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js
index 8a6053b7001..f3d46de3437 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js
@@ -1,5 +1,5 @@
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import * as types from './mutation_types';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue
index 741395b3193..fff8a95c193 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue
@@ -1,6 +1,6 @@
<script>
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue
index c8aeac75645..63ffded9e8e 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue
@@ -1,10 +1,10 @@
<script>
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { ITEM_TYPE } from '~/groups/constants';
import { TYPENAME_CRM_CONTACT } from '~/graphql_shared/constants';
import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import { isPositiveInteger } from '~/lib/utils/number_utils';
import { __ } from '~/locale';
import searchCrmContactsQuery from '../queries/search_crm_contacts.query.graphql';
@@ -43,7 +43,7 @@ export default {
return this.config.defaultContacts || OPTIONS_NONE_ANY;
},
namespace() {
- return this.config.isProject ? ITEM_TYPE.PROJECT : ITEM_TYPE.GROUP;
+ return this.config.isProject ? WORKSPACE_PROJECT : WORKSPACE_GROUP;
},
},
methods: {
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue
index ff0571031b5..126066fbbbe 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue
@@ -1,10 +1,10 @@
<script>
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { ITEM_TYPE } from '~/groups/constants';
import { TYPENAME_CRM_ORGANIZATION } from '~/graphql_shared/constants';
import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import { isPositiveInteger } from '~/lib/utils/number_utils';
import { __ } from '~/locale';
import searchCrmOrganizationsQuery from '../queries/search_crm_organizations.query.graphql';
@@ -43,7 +43,7 @@ export default {
return this.config.defaultOrganizations || OPTIONS_NONE_ANY;
},
namespace() {
- return this.config.isProject ? ITEM_TYPE.PROJECT : ITEM_TYPE.GROUP;
+ return this.config.isProject ? WORKSPACE_PROJECT : WORKSPACE_GROUP;
},
},
methods: {
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue
index 9c30ec67d5a..c69a2927ec9 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue
@@ -1,6 +1,6 @@
<script>
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { OPTIONS_NONE_ANY } from '../constants';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue
index 9449e071a0d..6a7dd6131e2 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue
@@ -1,7 +1,7 @@
<script>
import { GlToken, GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
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 b9ee4d51db1..81b8a6c78fc 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
@@ -1,6 +1,6 @@
<script>
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import { sortMilestonesByDueDate } from '~/milestones/utils';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue
index 6d681aab3ca..a251035b683 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue
@@ -1,6 +1,6 @@
<script>
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { OPTIONS_NONE_ANY } from '../constants';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue
index 28e65c1185f..c294c23abfc 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue
@@ -1,7 +1,7 @@
<script>
import { GlAvatar, GlFilteredSearchSuggestion } from '@gitlab/ui';
import { compact } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import { OPTIONS_NONE_ANY } from '../constants';
diff --git a/app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue b/app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue
index 26c50345c19..fe221d2fefa 100644
--- a/app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue
+++ b/app/assets/javascripts/vue_shared/components/form/form_footer_actions.vue
@@ -1,5 +1,4 @@
-<!-- eslint-disable-next-line vue/no-deprecated-functional-template -->
-<template functional>
+<template>
<footer class="form-actions d-flex justify-content-between">
<div><slot name="prepend"></slot></div>
<div><slot></slot></div>
diff --git a/app/assets/javascripts/vue_shared/components/issuable_blocked_icon/constants.js b/app/assets/javascripts/vue_shared/components/issuable_blocked_icon/constants.js
index 9a88ab44f3d..e3eacf4495d 100644
--- a/app/assets/javascripts/vue_shared/components/issuable_blocked_icon/constants.js
+++ b/app/assets/javascripts/vue_shared/components/issuable_blocked_icon/constants.js
@@ -1,5 +1,4 @@
-import { issuableTypes } from '~/boards/constants';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
import blockingIssuesQuery from './graphql/blocking_issues.query.graphql';
import blockingEpicsQuery from './graphql/blocking_epics.query.graphql';
@@ -7,7 +6,7 @@ export const blockingIssuablesQueries = {
[TYPE_ISSUE]: {
query: blockingIssuesQuery,
},
- [issuableTypes.epic]: {
+ [TYPE_EPIC]: {
query: blockingEpicsQuery,
},
};
diff --git a/app/assets/javascripts/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue b/app/assets/javascripts/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue
index f5b4870d59f..7bea4409c03 100644
--- a/app/assets/javascripts/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue
@@ -1,9 +1,8 @@
<script>
import { GlIcon, GlLink, GlPopover, GlLoadingIcon } from '@gitlab/ui';
-import { issuableTypes } from '~/boards/constants';
import { TYPENAME_ISSUE, TYPENAME_EPIC } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
import { truncate } from '~/lib/utils/text_utility';
import { __, n__, s__, sprintf } from '~/locale';
import { blockingIssuablesQueries } from './constants';
@@ -12,12 +11,12 @@ export default {
i18n: {
issuableType: {
[TYPE_ISSUE]: __('issue'),
- [issuableTypes.epic]: __('epic'),
+ [TYPE_EPIC]: __('epic'),
},
},
graphQLIdType: {
[TYPE_ISSUE]: TYPENAME_ISSUE,
- [issuableTypes.epic]: TYPENAME_EPIC,
+ [TYPE_EPIC]: TYPENAME_EPIC,
},
referenceFormatter: {
[TYPE_ISSUE]: (r) => r.split('/')[1],
@@ -43,7 +42,7 @@ export default {
type: String,
required: true,
validator(value) {
- return [TYPE_ISSUE, issuableTypes.epic].includes(value);
+ return [TYPE_ISSUE, TYPE_EPIC].includes(value);
},
},
},
@@ -88,7 +87,7 @@ export default {
},
computed: {
isEpic() {
- return this.issuableType === issuableTypes.epic;
+ return this.issuableType === TYPE_EPIC;
},
displayedIssuables() {
const { defaultDisplayLimit, referenceFormatter } = this.$options;
diff --git a/app/assets/javascripts/vue_shared/components/listbox_input/listbox_input.vue b/app/assets/javascripts/vue_shared/components/listbox_input/listbox_input.vue
index bc6b5d3176f..0f8ff5291a4 100644
--- a/app/assets/javascripts/vue_shared/components/listbox_input/listbox_input.vue
+++ b/app/assets/javascripts/vue_shared/components/listbox_input/listbox_input.vue
@@ -1,5 +1,5 @@
<script>
-import { GlFormGroup, GlListbox } from '@gitlab/ui';
+import { GlFormGroup, GlCollapsibleListbox } from '@gitlab/ui';
import { __ } from '~/locale';
const MIN_ITEMS_COUNT_FOR_SEARCHING = 10;
@@ -10,9 +10,9 @@ export default {
},
components: {
GlFormGroup,
- GlListbox,
+ GlCollapsibleListbox,
},
- model: GlListbox.model,
+ model: GlCollapsibleListbox.model,
props: {
label: {
type: String,
@@ -39,7 +39,7 @@ export default {
default: null,
},
items: {
- type: GlListbox.props.items.type,
+ type: GlCollapsibleListbox.props.items.type,
required: true,
},
disabled: {
@@ -116,7 +116,7 @@ export default {
<template>
<component :is="wrapperComponent" :label="label" :description="description" v-bind="$attrs">
- <gl-listbox
+ <gl-collapsible-listbox
:selected="selected"
:toggle-text="toggleText"
:items="filteredItems"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/drawio_toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/drawio_toolbar_button.vue
new file mode 100644
index 00000000000..a66becb5c92
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/markdown/drawio_toolbar_button.vue
@@ -0,0 +1,48 @@
+<script>
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import { launchDrawioEditor } from '~/drawio/drawio_editor';
+import { create } from '~/drawio/markdown_field_editor_facade';
+
+export default {
+ components: {
+ GlButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ uploadsPath: {
+ type: String,
+ required: true,
+ },
+ markdownPreviewPath: {
+ type: String,
+ required: true,
+ },
+ },
+ methods: {
+ getTextArea() {
+ return document.querySelector('.js-gfm-input');
+ },
+ launchDrawioEditor() {
+ launchDrawioEditor({
+ editorFacade: create({
+ uploadsPath: this.uploadsPath,
+ textArea: this.getTextArea(),
+ markdownPreviewPath: this.markdownPreviewPath,
+ }),
+ });
+ },
+ },
+};
+</script>
+<template>
+ <gl-button
+ v-gl-tooltip
+ :title="__('Insert or edit diagram')"
+ :aria-label="__('Insert or edit diagram')"
+ category="tertiary"
+ icon="diagram"
+ @click="launchDrawioEditor"
+ />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/editor_mode_dropdown.vue b/app/assets/javascripts/vue_shared/components/markdown/editor_mode_dropdown.vue
index 6702a81e747..9ebf782a1d9 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/editor_mode_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/editor_mode_dropdown.vue
@@ -23,7 +23,7 @@ export default {
return this.value === 'markdown';
},
text() {
- return this.markdownEditorSelected ? __('View rich text') : __('View markdown');
+ return this.markdownEditorSelected ? __('Viewing markdown') : __('Viewing rich text');
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index 6f4cddbdfa2..9623c51d51c 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -2,7 +2,7 @@
import { GlIcon } from '@gitlab/ui';
import $ from 'jquery';
import { debounce, unescape } from 'lodash';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import GLForm from '~/gl_form';
import SafeHtml from '~/vue_shared/directives/safe_html';
import axios from '~/lib/utils/axios_utils';
@@ -132,6 +132,11 @@ export default {
required: false,
default: false,
},
+ drawioEnabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -355,6 +360,10 @@ export default {
:enable-preview="enablePreview"
:show-suggest-popover="showSuggestPopover"
:suggestion-start-index="suggestionsStartIndex"
+ :uploads-path="uploadsPath"
+ :markdown-preview-path="markdownPreviewPath"
+ :drawio-enabled="drawioEnabled"
+ data-testid="markdownHeader"
:restricted-tool-bar-items="restrictedToolBarItems"
@preview-markdown="showPreviewTab"
@write-markdown="showWriteTab"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue
index e83441e59a2..eeeb0fce55d 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue
@@ -10,11 +10,14 @@ import {
INDENT_LINE,
OUTDENT_LINE,
} from '~/behaviors/shortcuts/keybindings';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { getModifierKey } from '~/constants';
import { getSelectedFragment } from '~/lib/utils/common_utils';
import { s__, __ } from '~/locale';
import { CopyAsGFM } from '~/behaviors/markdown/copy_as_gfm';
import ToolbarButton from './toolbar_button.vue';
+import DrawioToolbarButton from './drawio_toolbar_button.vue';
+import SavedRepliesDropdown from './saved_replies_dropdown.vue';
export default {
components: {
@@ -23,10 +26,18 @@ export default {
GlButton,
GlTabs,
GlTab,
+ DrawioToolbarButton,
+ SavedRepliesDropdown,
},
directives: {
GlTooltip: GlTooltipDirective,
},
+ mixins: [glFeatureFlagsMixin()],
+ inject: {
+ newSavedRepliesPath: {
+ default: null,
+ },
+ },
props: {
previewMarkdown: {
type: Boolean,
@@ -62,6 +73,21 @@ export default {
required: false,
default: () => [],
},
+ uploadsPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ markdownPreviewPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ drawioEnabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -369,6 +395,15 @@ export default {
icon="paperclip"
@click="handleAttachFile"
/>
+ <drawio-toolbar-button
+ v-if="drawioEnabled"
+ :uploads-path="uploadsPath"
+ :markdown-preview-path="markdownPreviewPath"
+ />
+ <saved-replies-dropdown
+ v-if="newSavedRepliesPath && glFeatures.savedReplies"
+ :new-saved-replies-path="newSavedRepliesPath"
+ />
<toolbar-button
v-if="!restrictedToolBarItems.includes('full-screen')"
class="js-zen-enter"
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 7e6b0e4a63b..93583907a11 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
@@ -1,6 +1,8 @@
<script>
+import Autosize from 'autosize';
import axios from '~/lib/utils/axios_utils';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
+import { updateDraft, clearDraft, getDraft } from '~/lib/utils/autosave';
import { EDITING_MODE_MARKDOWN_FIELD, EDITING_MODE_CONTENT_EDITOR } from '../../constants';
import MarkdownField from './field.vue';
@@ -22,15 +24,6 @@ export default {
type: String,
required: true,
},
- markdownDocsPath: {
- type: String,
- required: true,
- },
- quickActionsDocsPath: {
- type: String,
- required: false,
- default: '',
- },
uploadsPath: {
type: String,
required: false,
@@ -41,21 +34,6 @@ export default {
required: false,
default: true,
},
- enablePreview: {
- type: Boolean,
- required: false,
- default: true,
- },
- autocompleteDataSources: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- enableAutocomplete: {
- type: Boolean,
- required: false,
- default: true,
- },
formFieldProps: {
type: Object,
required: true,
@@ -71,7 +49,22 @@ export default {
required: false,
default: false,
},
- useBottomToolbar: {
+ autosaveKey: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ quickActionsDocsPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ drawioEnabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ disabled: {
type: Boolean,
required: false,
default: false,
@@ -79,6 +72,7 @@ export default {
},
data() {
return {
+ markdown: this.value || (this.autosaveKey ? getDraft(this.autosaveKey) : '') || '',
editingMode: EDITING_MODE_MARKDOWN_FIELD,
autofocused: false,
};
@@ -92,15 +86,32 @@ export default {
return this.autofocus && !this.autofocused ? 'end' : false;
},
},
+ watch: {
+ value(val) {
+ this.markdown = val;
+
+ this.saveDraft();
+ this.autosizeTextarea();
+ },
+ },
mounted() {
this.autofocusTextarea();
+
+ this.saveDraft();
},
methods: {
updateMarkdownFromContentEditor({ markdown }) {
+ this.markdown = markdown;
this.$emit('input', markdown);
+
+ this.saveDraft();
},
updateMarkdownFromMarkdownField({ target }) {
+ this.markdown = target.value;
this.$emit('input', target.value);
+
+ this.saveDraft();
+ this.autosizeTextarea();
},
renderMarkdown(markdown) {
return axios.post(this.renderMarkdownPath, { text: markdown }).then(({ data }) => data.body);
@@ -126,6 +137,23 @@ export default {
setEditorAsAutofocused() {
this.autofocused = true;
},
+ saveDraft() {
+ if (!this.autosaveKey) return;
+ if (this.markdown) updateDraft(this.autosaveKey, this.markdown);
+ else clearDraft(this.autosaveKey);
+ },
+ togglePreview(value) {
+ if (this.editingMode === EDITING_MODE_MARKDOWN_FIELD) {
+ this.$refs.markdownField.previewMarkdown = value;
+ }
+ },
+ autosizeTextarea() {
+ if (this.editingMode === EDITING_MODE_MARKDOWN_FIELD) {
+ this.$nextTick(() => {
+ Autosize.update(this.$refs.textarea);
+ });
+ }
+ },
},
};
</script>
@@ -138,16 +166,16 @@ export default {
/>
<markdown-field
v-if="!isContentEditorActive"
+ ref="markdownField"
+ v-bind="$attrs"
+ data-testid="markdown-field"
:markdown-preview-path="renderMarkdownPath"
can-attach-file
- :enable-autocomplete="enableAutocomplete"
- :textarea-value="value"
- :markdown-docs-path="markdownDocsPath"
- :quick-actions-docs-path="quickActionsDocsPath"
- :autocomplete-data-sources="autocompleteDataSources"
+ :textarea-value="markdown"
:uploads-path="uploadsPath"
- :enable-preview="enablePreview"
- show-content-editor-switcher
+ :quick-actions-docs-path="quickActionsDocsPath"
+ :show-content-editor-switcher="enableContentEditor"
+ :drawio-enabled="drawioEnabled"
class="bordered-box"
@enableContentEditor="onEditingModeChange('contentEditor')"
>
@@ -155,11 +183,12 @@ export default {
<textarea
v-bind="formFieldProps"
ref="textarea"
- :value="value"
- class="note-textarea js-gfm-input js-autosize markdown-area"
+ :value="markdown"
+ class="note-textarea js-gfm-input markdown-area"
dir="auto"
:data-supports-quick-actions="supportsQuickActions"
- data-qa-selector="markdown_editor_form_field"
+ :data-qa-selector="formFieldProps['data-qa-selector'] || 'markdown_editor_form_field'"
+ :disabled="disabled"
@input="updateMarkdownFromMarkdownField"
@keydown="$emit('keydown', $event)"
>
@@ -168,11 +197,15 @@ export default {
</markdown-field>
<div v-else>
<content-editor
+ ref="contentEditor"
:render-markdown="renderMarkdown"
:uploads-path="uploadsPath"
- :markdown="value"
+ :markdown="markdown"
+ :quick-actions-docs-path="quickActionsDocsPath"
:autofocus="contentEditorAutofocused"
- :use-bottom-toolbar="useBottomToolbar"
+ :placeholder="formFieldProps.placeholder"
+ :drawio-enabled="drawioEnabled"
+ :editable="!disabled"
@initialized="setEditorAsAutofocused"
@change="updateMarkdownFromContentEditor"
@keydown="$emit('keydown', $event)"
@@ -180,7 +213,7 @@ export default {
/>
<input
v-bind="formFieldProps"
- :value="value"
+ :value="markdown"
data-qa-selector="markdown_editor_form_field"
type="hidden"
/>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/saved_replies.query.graphql b/app/assets/javascripts/vue_shared/components/markdown/saved_replies.query.graphql
new file mode 100644
index 00000000000..9b9d4c89254
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/markdown/saved_replies.query.graphql
@@ -0,0 +1,12 @@
+query getSavedReplies {
+ currentUser {
+ id
+ savedReplies {
+ nodes {
+ id
+ name
+ content
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/vue_shared/components/markdown/saved_replies_dropdown.vue b/app/assets/javascripts/vue_shared/components/markdown/saved_replies_dropdown.vue
new file mode 100644
index 00000000000..989b14f8711
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/markdown/saved_replies_dropdown.vue
@@ -0,0 +1,120 @@
+<script>
+import { GlCollapsibleListbox, GlIcon, GlButton, GlTooltipDirective } from '@gitlab/ui';
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
+import savedRepliesQuery from './saved_replies.query.graphql';
+
+export default {
+ apollo: {
+ savedReplies: {
+ query: savedRepliesQuery,
+ update: (r) => r.currentUser?.savedReplies?.nodes,
+ skip() {
+ return !this.shouldFetchSavedReplies;
+ },
+ },
+ },
+ components: {
+ GlCollapsibleListbox,
+ GlIcon,
+ GlButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ newSavedRepliesPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ shouldFetchSavedReplies: false,
+ savedReplies: [],
+ savedRepliesSearch: '',
+ loadingSavedReplies: false,
+ };
+ },
+ computed: {
+ filteredSavedReplies() {
+ const savedReplies = this.savedRepliesSearch
+ ? fuzzaldrinPlus.filter(this.savedReplies, this.savedRepliesSearch, { key: ['name'] })
+ : this.savedReplies;
+
+ return savedReplies.map((r) => ({ value: r.id, text: r.name, content: r.content }));
+ },
+ },
+ methods: {
+ fetchSavedReplies() {
+ this.shouldFetchSavedReplies = true;
+ },
+ setSavedRepliesSearch(search) {
+ this.savedRepliesSearch = search;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-collapsible-listbox
+ :header-text="__('Insert saved reply')"
+ :items="filteredSavedReplies"
+ placement="right"
+ searchable
+ class="saved-replies-dropdown"
+ :searching="$apollo.queries.savedReplies.loading"
+ @shown="fetchSavedReplies"
+ @search="setSavedRepliesSearch"
+ >
+ <template #toggle>
+ <gl-button
+ v-gl-tooltip
+ :title="__('Insert saved reply')"
+ :aria-label="__('Insert saved reply')"
+ category="tertiary"
+ class="gl-px-3!"
+ data-testid="saved-replies-dropdown-toggle"
+ >
+ <gl-icon name="symlink" class="gl-mr-0!" />
+ <gl-icon name="chevron-down" />
+ </gl-button>
+ </template>
+ <template #list-item="{ item }">
+ <div
+ class="gl-display-flex js-saved-reply-content"
+ :data-md-tag="item.content"
+ data-md-cursor-offset="0"
+ data-md-prepend="true"
+ data-testid="saved-reply-dropdown-item"
+ >
+ <div class="gl-text-truncate">
+ <strong>{{ item.text }}</strong
+ ><span class="gl-ml-2">{{ item.content }}</span>
+ </div>
+ </div>
+ </template>
+ <template #footer>
+ <div
+ class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-100 gl-display-flex gl-justify-content-center gl-p-3"
+ >
+ <gl-button
+ :href="newSavedRepliesPath"
+ category="tertiary"
+ block
+ class="gl-justify-content-start! gl-mt-0! gl-mb-0! gl-px-3!"
+ >{{ __('Add a new saved reply') }}</gl-button
+ >
+ </div>
+ </template>
+ </gl-collapsible-listbox>
+</template>
+
+<style>
+.saved-replies-dropdown .gl-new-dropdown-panel {
+ width: 350px;
+}
+
+.saved-replies-dropdown .gl-new-dropdown-item-check-icon {
+ display: none;
+}
+</style>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
index c307601e670..49eb11f8081 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
@@ -1,7 +1,7 @@
<script>
import Vue from 'vue';
import SafeHtml from '~/vue_shared/directives/safe_html';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
import SuggestionDiff from './suggestion_diff.vue';
diff --git a/app/assets/javascripts/vue_shared/components/metric_images/store/actions.js b/app/assets/javascripts/vue_shared/components/metric_images/store/actions.js
index 1c4e8d332a9..6f91463365b 100644
--- a/app/assets/javascripts/vue_shared/components/metric_images/store/actions.js
+++ b/app/assets/javascripts/vue_shared/components/metric_images/store/actions.js
@@ -1,4 +1,4 @@
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import * as types from './mutation_types';
diff --git a/app/assets/javascripts/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue b/app/assets/javascripts/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue
index b079181bd10..e09a6e2e811 100644
--- a/app/assets/javascripts/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue
@@ -6,7 +6,7 @@ import {
GlLoadingIcon,
GlSearchBoxByType,
} from '@gitlab/ui';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { DASH_SCOPE, joinPaths } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
diff --git a/app/assets/javascripts/vue_shared/components/pagination/constants.js b/app/assets/javascripts/vue_shared/components/pagination/constants.js
index 748ad178c70..f8a6d37dea1 100644
--- a/app/assets/javascripts/vue_shared/components/pagination/constants.js
+++ b/app/assets/javascripts/vue_shared/components/pagination/constants.js
@@ -1,8 +1,5 @@
import { s__ } from '~/locale';
-export const PAGINATION_UI_BUTTON_LIMIT = 4;
-export const UI_LIMIT = 6;
-export const SPREAD = '...';
export const PREV = s__('Pagination|Prev');
export const NEXT = s__('Pagination|Next');
export const FIRST = s__('Pagination|« First');
diff --git a/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue b/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue
index 16bc8070dc1..bdc8ffee90a 100644
--- a/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue
+++ b/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue
@@ -52,7 +52,7 @@ export default {
<div
class="gl-display-flex gl-align-items-center gl-flex-wrap project-namespace-name-container"
>
- <gl-icon v-if="selected" class="js-selected-icon" name="mobile-issue-close" />
+ <gl-icon v-if="selected" data-testid="selected-icon" name="mobile-issue-close" />
<project-avatar
:project-id="project.id"
:project-avatar-url="projectAvatarUrl"
@@ -61,16 +61,18 @@ export default {
/>
<div
v-if="truncatedNamespace"
+ data-testid="project-namespace"
:title="projectNameWithNamespace"
- class="text-secondary text-truncate js-project-namespace"
+ class="text-secondary text-truncate"
>
{{ truncatedNamespace }}
<span v-if="truncatedNamespace" class="text-secondary">/&nbsp;</span>
</div>
<div
v-safe-html="highlightedProjectName"
+ data-testid="project-name"
:title="project.name"
- class="js-project-name text-truncate"
+ class="text-truncate"
></div>
</div>
</gl-button>
diff --git a/app/assets/javascripts/vue_shared/components/resizable_chart/resizable_chart_container.vue b/app/assets/javascripts/vue_shared/components/resizable_chart/resizable_chart_container.vue
deleted file mode 100644
index 02cb7785ef4..00000000000
--- a/app/assets/javascripts/vue_shared/components/resizable_chart/resizable_chart_container.vue
+++ /dev/null
@@ -1,40 +0,0 @@
-<script>
-import $ from 'jquery';
-import { debounceByAnimationFrame } from '~/lib/utils/common_utils';
-
-export default {
- data() {
- return {
- width: 0,
- height: 0,
- };
- },
- beforeDestroy() {
- this.contentResizeHandler.off('content.resize', this.debouncedResize);
- window.removeEventListener('resize', this.debouncedResize);
- },
- created() {
- this.debouncedResize = debounceByAnimationFrame(this.onResize);
-
- // Handle when we explicictly trigger a custom resize event
- this.contentResizeHandler = $(document).on('content.resize', this.debouncedResize);
-
- // Handle window resize
- window.addEventListener('resize', this.debouncedResize);
- },
- methods: {
- onResize() {
- // Slot dimensions
- const { clientWidth, clientHeight } = this.$refs.chartWrapper;
- this.width = clientWidth;
- this.height = clientHeight;
- },
- },
-};
-</script>
-
-<template>
- <div ref="chartWrapper">
- <slot :width="width" :height="height"> </slot>
- </div>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/source_editor.vue b/app/assets/javascripts/vue_shared/components/source_editor.vue
index 1925c5d4064..7b7d3d48d9e 100644
--- a/app/assets/javascripts/vue_shared/components/source_editor.vue
+++ b/app/assets/javascripts/vue_shared/components/source_editor.vue
@@ -2,6 +2,7 @@
import { debounce, isEmpty } from 'lodash';
import { CONTENT_UPDATE_DEBOUNCE, EDITOR_READY_EVENT } from '~/editor/constants';
import Editor from '~/editor/source_editor';
+import { markRaw } from '~/lib/utils/vue3compat/mark_raw';
function initSourceEditor({ el, ...args }) {
const editor = new Editor({
@@ -10,10 +11,12 @@ function initSourceEditor({ el, ...args }) {
},
});
- return editor.createInstance({
- el,
- ...args,
- });
+ return markRaw(
+ editor.createInstance({
+ el,
+ ...args,
+ }),
+ );
}
export default {
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/constants.js b/app/assets/javascripts/vue_shared/components/source_viewer/constants.js
index 15335ea6edc..514b626ed95 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/constants.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/constants.js
@@ -141,8 +141,6 @@ export const BIDI_CHARS_CLASS_LIST = 'unicode-bidi has-tooltip';
export const BIDI_CHAR_TOOLTIP = 'Potentially unwanted character detected: Unicode BiDi Control';
-export const HLJS_ON_AFTER_HIGHLIGHT = 'after:highlight';
-
// We fallback to highlighting these languages with Rouge, see the following issue for more detail:
// https://gitlab.com/gitlab-org/gitlab/-/issues/384375#note_1212752013
export const LEGACY_FALLBACKS = ['python'];
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 09414e679bb..bda88a48e48 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
@@ -21,6 +21,11 @@ export default {
required: false,
default: 'top',
},
+ boundary: {
+ type: String,
+ required: false,
+ default: '',
+ },
truncateTarget: {
type: [String, Function],
required: false,
@@ -44,6 +49,8 @@ export default {
title: this.title,
placement: this.placement,
disabled: this.tooltipDisabled,
+ // Only set the tooltip boundary if it's truthy
+ ...(this.boundary && { boundary: this.boundary }),
};
},
},
diff --git a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
index a001b6bdf24..23fbf211d54 100644
--- a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
+++ b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
@@ -149,7 +149,7 @@ export default {
>
<slot>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ 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"
type="button"
@click="openFileUpload"
>
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
index 1a81da3eb0d..ab308d11a79 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
@@ -105,7 +105,7 @@ export default {
v-gl-tooltip
:title="tooltipText"
:tooltip-placement="tooltipPlacement"
- class="gl-ml-3"
+ class="gl-ml-1"
data-testid="user-avatar-link-username"
>
{{ username }}
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 d06bc7b8f98..dd9d2ce66cd 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
@@ -10,7 +10,7 @@ import {
} from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { glEmojiTag } from '~/emoji';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { followUser, unfollowUser } from '~/rest_api';
import { isUserBusy } from '~/set_status_modal/utils';
import Tracking from '~/tracking';
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 edcfabe7da3..abd3575d020 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
@@ -11,7 +11,7 @@ import {
} from '@gitlab/ui';
import { __ } from '~/locale';
import SidebarParticipant from '~/sidebar/components/assignees/sidebar_participant.vue';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+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 { TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants';
@@ -149,7 +149,7 @@ export default {
},
computed: {
isMergeRequest() {
- return this.issuableType === IssuableType.MergeRequest;
+ return this.issuableType === TYPE_MERGE_REQUEST;
},
searchUsersVariables() {
const variables = {
diff --git a/app/assets/javascripts/vue_shared/constants.js b/app/assets/javascripts/vue_shared/constants.js
index fd151751372..29a31503840 100644
--- a/app/assets/javascripts/vue_shared/constants.js
+++ b/app/assets/javascripts/vue_shared/constants.js
@@ -1,5 +1,5 @@
import { __, n__, sprintf } from '~/locale';
-import { TYPE_ISSUE, WorkspaceType } from '~/issues/constants';
+import { TYPE_ISSUE, WORKSPACE_PROJECT } from '~/issues/constants';
const INTERVALS = {
minute: 'minute',
@@ -75,8 +75,6 @@ export const timeRanges = [
/* eslint-enable @gitlab/require-i18n-strings */
export const defaultTimeRange = timeRanges.find((tr) => tr.default);
-export const getTimeWindow = (timeWindowName) =>
- timeRanges.find((tr) => tr.name === timeWindowName);
export const AVATAR_SHAPE_OPTION_CIRCLE = 'circle';
export const AVATAR_SHAPE_OPTION_RECT = 'rect';
@@ -87,7 +85,7 @@ export const confidentialityInfoText = (workspaceType, issuableType) =>
'Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}.',
),
{
- workspaceType: workspaceType === WorkspaceType.project ? __('project') : __('group'),
+ workspaceType: workspaceType === WORKSPACE_PROJECT ? __('project') : __('group'),
issuableType: issuableType === TYPE_ISSUE ? __('issue') : __('epic'),
permissions:
issuableType === TYPE_ISSUE
diff --git a/app/assets/javascripts/vue_shared/gl_feature_flags_plugin.js b/app/assets/javascripts/vue_shared/gl_feature_flags_plugin.js
index c12ffaac40a..79946ebaecd 100644
--- a/app/assets/javascripts/vue_shared/gl_feature_flags_plugin.js
+++ b/app/assets/javascripts/vue_shared/gl_feature_flags_plugin.js
@@ -1,12 +1,14 @@
export default (Vue) => {
Vue.mixin({
- provide: {
- glFeatures:
- {
- ...window.gon?.features,
- // TODO: extract into glLicensedFeatures https://gitlab.com/gitlab-org/gitlab/-/issues/322460
- ...window.gon?.licensed_features,
- } || {},
+ provide() {
+ return {
+ glFeatures:
+ {
+ ...window.gon?.features,
+ // TODO: extract into glLicensedFeatures https://gitlab.com/gitlab-org/gitlab/-/issues/322460
+ ...window.gon?.licensed_features,
+ } || {},
+ };
},
});
};
diff --git a/app/assets/javascripts/vue_shared/global_search/constants.js b/app/assets/javascripts/vue_shared/global_search/constants.js
new file mode 100644
index 00000000000..388e7c92f03
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/global_search/constants.js
@@ -0,0 +1,73 @@
+import { s__, __, sprintf } from '~/locale';
+
+export const AUTOCOMPLETE_ERROR_MESSAGE = s__(
+ 'GlobalSearch|There was an error fetching search autocomplete suggestions.',
+);
+
+export const ALL_GITLAB = __('All GitLab');
+export const SEARCH_GITLAB = s__('GlobalSearch|Search GitLab');
+
+export const SEARCH_DESCRIBED_BY_DEFAULT = s__(
+ 'GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list.',
+);
+export const SEARCH_DESCRIBED_BY_WITH_RESULTS = s__(
+ 'GlobalSearch|Type for new suggestions to appear below.',
+);
+export const SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN = s__(
+ 'GlobalSearch|Type and press the enter key to submit search.',
+);
+export const SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN = SEARCH_DESCRIBED_BY_WITH_RESULTS;
+export const SEARCH_DESCRIBED_BY_UPDATED = s__(
+ 'GlobalSearch|Results updated. %{count} results available. Use the up and down arrow keys to navigate search results list, or ENTER to submit.',
+);
+export const SEARCH_RESULTS_LOADING = s__('GlobalSearch|Search results are loading');
+export const SEARCH_RESULTS_SCOPE = s__('GlobalSearch|in %{scope}');
+export const KBD_HELP = sprintf(
+ s__('GlobalSearch|Use the shortcut key %{kbdOpen}/%{kbdClose} to start a search'),
+ { kbdOpen: '<kbd>', kbdClose: '</kbd>' },
+ false,
+);
+export const SCOPED_SEARCH_ITEM_ARIA_LABEL = s__('GlobalSearch| %{search} %{description} %{scope}');
+
+export const MSG_ISSUES_ASSIGNED_TO_ME = s__('GlobalSearch|Issues assigned to me');
+
+export const MSG_ISSUES_IVE_CREATED = s__("GlobalSearch|Issues I've created");
+
+export const MSG_MR_ASSIGNED_TO_ME = s__('GlobalSearch|Merge requests assigned to me');
+
+export const MSG_MR_IM_REVIEWER = s__("GlobalSearch|Merge requests that I'm a reviewer");
+
+export const MSG_MR_IVE_CREATED = s__("GlobalSearch|Merge requests I've created");
+
+export const MSG_IN_ALL_GITLAB = s__('GlobalSearch|all GitLab');
+
+export const GROUPS_CATEGORY = s__('GlobalSearch|Groups');
+
+export const PROJECTS_CATEGORY = s__('GlobalSearch|Projects');
+
+export const USERS_CATEGORY = s__('GlobalSearch|Users');
+
+export const ISSUES_CATEGORY = s__('GlobalSearch|Recent issues');
+
+export const MERGE_REQUEST_CATEGORY = s__('GlobalSearch|Recent merge requests');
+
+export const RECENT_EPICS_CATEGORY = s__('GlobalSearch|Recent epics');
+
+export const IN_THIS_PROJECT_CATEGORY = s__('GlobalSearch|In this project');
+
+export const SETTINGS_CATEGORY = s__('GlobalSearch|Settings');
+
+export const HELP_CATEGORY = s__('GlobalSearch|Help');
+
+export const SEARCH_RESULTS_ORDER = [
+ MERGE_REQUEST_CATEGORY,
+ ISSUES_CATEGORY,
+ RECENT_EPICS_CATEGORY,
+ GROUPS_CATEGORY,
+ PROJECTS_CATEGORY,
+ USERS_CATEGORY,
+ IN_THIS_PROJECT_CATEGORY,
+ SETTINGS_CATEGORY,
+ HELP_CATEGORY,
+];
+export const DROPDOWN_ORDER = SEARCH_RESULTS_ORDER;
diff --git a/app/assets/javascripts/vue_shared/issuable/list/constants.js b/app/assets/javascripts/vue_shared/issuable/list/constants.js
index f6b864dfde0..1b71819bdc2 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/constants.js
+++ b/app/assets/javascripts/vue_shared/issuable/list/constants.js
@@ -1,27 +1,22 @@
+import { STATUS_ALL, STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import { __ } from '~/locale';
-export const IssuableStates = {
- Opened: 'opened',
- Closed: 'closed',
- All: 'all',
-};
-
export const IssuableListTabs = [
{
id: 'state-opened',
- name: IssuableStates.Opened,
+ name: STATUS_OPEN,
title: __('Open'),
titleTooltip: __('Filter by issues that are currently opened.'),
},
{
id: 'state-closed',
- name: IssuableStates.Closed,
+ name: STATUS_CLOSED,
title: __('Closed'),
titleTooltip: __('Filter by issues that are currently closed.'),
},
{
id: 'state-all',
- name: IssuableStates.All,
+ name: STATUS_ALL,
title: __('All'),
titleTooltip: __('Show all issues.'),
},
diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_body.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_body.vue
index d78530239a5..a8d5f72373c 100644
--- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_body.vue
+++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_body.vue
@@ -3,6 +3,7 @@ import { GlLink } from '@gitlab/ui';
import TaskList from '~/task_list';
+import { TYPE_ISSUE } from '~/issues/constants';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import IssuableDescription from './issuable_description.vue';
@@ -112,7 +113,7 @@ export default {
* task lists in Issue, Test Cases and Incidents
* as all of those are derived from `issue`.
*/
- dataType: 'issue',
+ dataType: TYPE_ISSUE,
fieldName: 'description',
lockVersion: this.taskListLockVersion,
selector: '.js-detail-page-description',
@@ -138,7 +139,7 @@ export default {
<template>
<div class="issue-details issuable-details">
- <div class="detail-page-description js-detail-page-description content-block">
+ <div class="detail-page-description js-detail-page-description content-block gl-pt-2">
<issuable-edit-form
v-if="editFormVisible"
:issuable="issuable"
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 1f23fdfaafd..3d4eebb9524 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
@@ -9,11 +9,11 @@ import {
} from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { STATUS_OPEN } from '~/issues/constants';
import { isExternal } from '~/lib/utils/url_utility';
import { n__, sprintf } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
-import { IssuableStates } from '~/vue_shared/issuable/list/constants';
export default {
components: {
@@ -80,7 +80,7 @@ export default {
},
computed: {
badgeVariant() {
- return this.issuableState === IssuableStates.Opened ? 'success' : 'info';
+ return this.issuableState === STATUS_OPEN ? 'success' : 'info';
},
authorId() {
return getIdFromGraphQLId(`${this.author.id}`);
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 fd94245b7c9..c33e803c7e1 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
@@ -1,8 +1,8 @@
<script>
import { GlIcon, GlBadge, GlButton, GlIntersectionObserver, GlTooltipDirective } from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
+import { STATUS_OPEN } from '~/issues/constants';
import { __ } from '~/locale';
-import { IssuableStates } from '~/vue_shared/issuable/list/constants';
export default {
i18n: {
@@ -39,7 +39,7 @@ export default {
},
computed: {
badgeVariant() {
- return this.issuable.state === IssuableStates.Opened ? 'success' : 'info';
+ return this.issuable.state === STATUS_OPEN ? 'success' : 'info';
},
},
methods: {
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 318adec2319..2533b3b5489 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
@@ -29,8 +29,8 @@ export default {
type: String,
required: true,
},
- initialBreadcrumb: {
- type: String,
+ initialBreadcrumbs: {
+ type: Array,
required: true,
},
panels: {
@@ -60,6 +60,10 @@ export default {
return this.panels.find((p) => p.name === this.activePanelName);
},
+ detailProps() {
+ return this.activePanel.detailProps || {};
+ },
+
details() {
return this.activePanel.details || this.activePanel.description;
},
@@ -69,14 +73,15 @@ export default {
},
breadcrumbs() {
- if (!this.activePanel) {
- return null;
- }
-
- return [
- { text: this.initialBreadcrumb, href: '#' },
- { text: this.activePanel.title, href: `#${this.activePanel.name}` },
- ];
+ return this.activePanel
+ ? [
+ ...this.initialBreadcrumbs,
+ {
+ text: this.activePanel.title,
+ href: `#${this.activePanel.name}`,
+ },
+ ]
+ : this.initialBreadcrumbs;
},
shouldVerify() {
@@ -125,24 +130,29 @@ export default {
<template>
<credit-card-verification v-if="shouldVerify" @verified="onVerified" />
- <welcome-page v-else-if="!activePanelName" :panels="panels" :title="title">
- <template #footer>
- <slot name="welcome-footer"> </slot>
- </template>
- </welcome-page>
- <div v-else class="row">
- <div class="col-lg-3">
- <div v-safe-html="activePanel.illustration" class="gl-text-white"></div>
- <h4>{{ activePanel.title }}</h4>
-
- <p v-if="hasTextDetails">{{ details }}</p>
- <component :is="details" v-else v-bind="activePanel.detailProps || {}" />
+ <div v-else-if="!activePanelName">
+ <gl-breadcrumb :items="breadcrumbs" />
+ <welcome-page :panels="panels" :title="title">
+ <template #footer>
+ <slot name="welcome-footer"> </slot>
+ </template>
+ </welcome-page>
+ </div>
+ <div v-else>
+ <gl-breadcrumb :items="breadcrumbs" />
+ <div class="gl-display-flex gl-py-5 gl-align-items-center">
+ <div v-safe-html="activePanel.illustration" class="gl-text-white col-auto"></div>
+ <div class="col">
+ <h4>{{ activePanel.title }}</h4>
+
+ <p v-if="hasTextDetails">{{ details }}</p>
+ <component :is="details" v-else v-bind="detailProps" />
+ </div>
<slot name="extra-description"></slot>
</div>
- <div class="col-lg-9">
+ <div>
<new-top-level-group-alert v-if="showNewTopLevelGroupAlert" />
- <gl-breadcrumb v-if="breadcrumbs" :items="breadcrumbs" />
<legacy-container :key="activePanel.name" :selector="activePanel.selector" />
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/plugins/global_toast.js b/app/assets/javascripts/vue_shared/plugins/global_toast.js
index fb52b31c2c8..bfea2bedd40 100644
--- a/app/assets/javascripts/vue_shared/plugins/global_toast.js
+++ b/app/assets/javascripts/vue_shared/plugins/global_toast.js
@@ -2,7 +2,7 @@ import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
Vue.use(GlToast);
-export const instance = new Vue();
+const instance = new Vue();
export default function showGlobalToast(...args) {
return instance.$toast.show(...args);
diff --git a/app/assets/javascripts/vue_shared/security_reports/components/artifact_downloads/merge_request_artifact_download.vue b/app/assets/javascripts/vue_shared/security_reports/components/artifact_downloads/merge_request_artifact_download.vue
index a4fb30a03a1..4c2b082242b 100644
--- a/app/assets/javascripts/vue_shared/security_reports/components/artifact_downloads/merge_request_artifact_download.vue
+++ b/app/assets/javascripts/vue_shared/security_reports/components/artifact_downloads/merge_request_artifact_download.vue
@@ -1,6 +1,6 @@
<script>
import { reportTypeToSecurityReportTypeEnum } from 'ee_else_ce/vue_shared/security_reports/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import SecurityReportDownloadDropdown from '~/vue_shared/security_reports/components/security_report_download_dropdown.vue';
import securityReportMergeRequestDownloadPathsQuery from '~/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql';
diff --git a/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue b/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue
index b739baad5d7..0cff5edf628 100644
--- a/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue
+++ b/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue
@@ -1,6 +1,6 @@
<script>
import { mapActions, mapGetters } from 'vuex';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import ReportSection from '~/ci/reports/components/report_section.vue';
import { ERROR, SLOT_SUCCESS, SLOT_LOADING, SLOT_ERROR } from '~/ci/reports/constants';
diff --git a/app/assets/javascripts/work_items/components/item_state.vue b/app/assets/javascripts/work_items/components/item_state.vue
index 8ec8482657d..8bb8b6101d4 100644
--- a/app/assets/javascripts/work_items/components/item_state.vue
+++ b/app/assets/javascripts/work_items/components/item_state.vue
@@ -63,7 +63,7 @@ export default {
:options="$options.states"
:disabled="disabled"
data-testid="work-item-state-select"
- class="gl-w-auto hide-select-decoration gl-pl-3"
+ class="gl-w-auto hide-select-decoration gl-pl-4 gl-my-1"
:class="{ 'gl-bg-transparent! gl-cursor-text!': disabled }"
@change="setState"
/>
diff --git a/app/assets/javascripts/work_items/components/item_title.vue b/app/assets/javascripts/work_items/components/item_title.vue
index 1c0fed2dde9..1dc6d341811 100644
--- a/app/assets/javascripts/work_items/components/item_title.vue
+++ b/app/assets/javascripts/work_items/components/item_title.vue
@@ -48,6 +48,7 @@ export default {
id="item-title"
ref="titleEl"
role="textbox"
+ data-testid="work-item-title"
:aria-label="__('Title')"
:data-placeholder="placeholder"
:contenteditable="!disabled"
diff --git a/app/assets/javascripts/work_items/components/notes/activity_filter.vue b/app/assets/javascripts/work_items/components/notes/activity_filter.vue
deleted file mode 100644
index 71784d3a807..00000000000
--- a/app/assets/javascripts/work_items/components/notes/activity_filter.vue
+++ /dev/null
@@ -1,113 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { __ } from '~/locale';
-import Tracking from '~/tracking';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-import { ASC, DESC } from '~/notes/constants';
-import { TRACKING_CATEGORY_SHOW, WORK_ITEM_NOTES_SORT_ORDER_KEY } from '~/work_items/constants';
-
-const SORT_OPTIONS = [
- { key: DESC, text: __('Newest first'), dataid: 'js-newest-first' },
- { key: ASC, text: __('Oldest first'), dataid: 'js-oldest-first' },
-];
-
-export default {
- SORT_OPTIONS,
- components: {
- GlDropdown,
- GlDropdownItem,
- LocalStorageSync,
- },
- mixins: [Tracking.mixin()],
- props: {
- sortOrder: {
- type: String,
- default: ASC,
- required: false,
- },
- loading: {
- type: Boolean,
- default: false,
- required: false,
- },
- workItemType: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- persistSortOrder: true,
- };
- },
- computed: {
- tracking() {
- return {
- category: TRACKING_CATEGORY_SHOW,
- label: 'item_track_notes_sorting',
- property: `type_${this.workItemType}`,
- };
- },
- selectedSortOption() {
- const isSortOptionValid = this.sortOrder === ASC || this.sortOrder === DESC;
- return isSortOptionValid ? SORT_OPTIONS.find(({ key }) => this.sortOrder === key) : ASC;
- },
- getDropdownSelectedText() {
- return this.selectedSortOption.text;
- },
- },
- methods: {
- setDiscussionSortDirection(direction) {
- this.$emit('updateSavedSortOrder', direction);
- },
- fetchSortedDiscussions(direction) {
- if (this.isSortDropdownItemActive(direction)) {
- return;
- }
- this.track('notes_sort_order_changed');
- this.$emit('changeSortOrder', direction);
- },
- isSortDropdownItemActive(sortDir) {
- return sortDir === this.sortOrder;
- },
- },
- WORK_ITEM_NOTES_SORT_ORDER_KEY,
-};
-</script>
-
-<template>
- <div
- id="discussion-preferences"
- data-testid="discussion-preferences"
- class="gl-display-inline-block gl-vertical-align-bottom gl-w-full gl-sm-w-auto"
- >
- <local-storage-sync
- :value="sortOrder"
- :storage-key="$options.WORK_ITEM_NOTES_SORT_ORDER_KEY"
- :persist="persistSortOrder"
- as-string
- @input="setDiscussionSortDirection"
- />
- <gl-dropdown
- :id="`discussion-preferences-dropdown-${workItemType}`"
- class="gl-xs-w-full"
- size="small"
- :text="getDropdownSelectedText"
- :disabled="loading"
- right
- >
- <div id="discussion-sort">
- <gl-dropdown-item
- v-for="{ text, key, dataid } in $options.SORT_OPTIONS"
- :key="text"
- :data-testid="dataid"
- is-check-item
- :is-checked="isSortDropdownItemActive(key)"
- @click="fetchSortedDiscussions(key)"
- >
- {{ text }}
- </gl-dropdown-item>
- </div>
- </gl-dropdown>
- </div>
-</template>
diff --git a/app/assets/javascripts/work_items/components/notes/system_note.vue b/app/assets/javascripts/work_items/components/notes/system_note.vue
index bca061f5e01..ab4691a4a4e 100644
--- a/app/assets/javascripts/work_items/components/notes/system_note.vue
+++ b/app/assets/javascripts/work_items/components/notes/system_note.vue
@@ -70,7 +70,7 @@ export default {
return [];
},
noteAnchorId() {
- return `note_${this.note.id}`;
+ return `note_${this.noteId}`;
},
isTargetNote() {
return this.targetNoteHash === this.noteAnchorId;
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
new file mode 100644
index 00000000000..1ead16c944b
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/notes/work_item_activity_sort_filter.vue
@@ -0,0 +1,116 @@
+<script>
+import { GlDropdown, GlDropdownItem } 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,
+ LocalStorageSync,
+ },
+ mixins: [Tracking.mixin()],
+ props: {
+ loading: {
+ type: Boolean,
+ default: false,
+ required: false,
+ },
+ workItemType: {
+ type: String,
+ required: true,
+ },
+ sortFilterProp: {
+ type: String,
+ required: true,
+ },
+ filterOptions: {
+ type: Array,
+ required: true,
+ },
+ trackingLabel: {
+ type: String,
+ required: true,
+ },
+ trackingAction: {
+ type: String,
+ required: true,
+ },
+ filterEvent: {
+ type: String,
+ required: true,
+ },
+ defaultSortFilterProp: {
+ type: String,
+ required: true,
+ },
+ storageKey: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ tracking() {
+ return {
+ category: TRACKING_CATEGORY_SHOW,
+ label: this.trackingLabel,
+ property: `type_${this.workItemType}`,
+ };
+ },
+ getDropdownSelectedText() {
+ return this.selectedSortOption.text;
+ },
+ selectedSortOption() {
+ return (
+ this.filterOptions.find(({ key }) => this.sortFilterProp === key) ||
+ this.defaultSortFilterProp
+ );
+ },
+ },
+ methods: {
+ setDiscussionFilterOption(filterValue) {
+ this.$emit(this.filterEvent, filterValue);
+ },
+ fetchFilteredDiscussions(filterValue) {
+ if (this.isSortDropdownItemActive(filterValue)) {
+ return;
+ }
+ this.track(this.trackingAction);
+ this.$emit(this.filterEvent, filterValue);
+ },
+ isSortDropdownItemActive(value) {
+ return value === this.sortFilterProp;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-inline-block gl-vertical-align-bottom">
+ <local-storage-sync
+ :value="sortFilterProp"
+ :storage-key="storageKey"
+ as-string
+ @input="setDiscussionFilterOption"
+ />
+ <gl-dropdown
+ class="gl-xs-w-full"
+ size="small"
+ :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>
+ </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 b3f17aff2ae..1762344ea9e 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
@@ -5,7 +5,6 @@ import { clearDraft } from '~/lib/utils/autosave';
import Tracking from '~/tracking';
import { ASC } from '~/notes/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { updateCommentState } from '~/work_items/graphql/cache_utils';
import { getWorkItemQuery } from '../../utils';
import createNoteMutation from '../../graphql/notes/create_work_item_note.mutation.graphql';
import { TRACKING_CATEGORY_SHOW, i18n } from '../../constants';
@@ -115,10 +114,35 @@ export default {
this.workItemType
}`;
},
+ isLockedOutOrSignedOut() {
+ return !this.signedIn || !this.canUpdate;
+ },
+ lockedOutUserWarningInReplies() {
+ return this.addPadding && this.isLockedOutOrSignedOut;
+ },
timelineEntryClass() {
return {
- 'timeline-entry gl-mb-3': true,
- 'gl-p-4': this.addPadding,
+ 'timeline-entry gl-mb-3 note note-wrapper note-comment': true,
+ 'gl-bg-gray-10 gl-rounded-bottom-left-base gl-rounded-bottom-right-base gl-p-5! gl-mx-n3 gl-mb-n2!': this
+ .lockedOutUserWarningInReplies,
+ };
+ },
+ timelineEntryInnerClass() {
+ return {
+ 'timeline-entry-inner': true,
+ 'gl-pb-3': this.addPadding,
+ };
+ },
+ timelineContentClass() {
+ return {
+ 'timeline-content': true,
+ 'gl-border-0! gl-pl-0!': !this.addPadding,
+ };
+ },
+ parentClass() {
+ return {
+ 'gl-relative gl-display-flex gl-align-items-flex-start gl-flex-wrap-nowrap': !this
+ .isEditing,
};
},
isProjectArchived() {
@@ -142,7 +166,6 @@ export default {
async updateWorkItem(commentText) {
this.isSubmitting = true;
this.$emit('replying', commentText);
- const { queryVariables, fetchByIid } = this;
try {
this.track('add_work_item_comment');
@@ -160,7 +183,6 @@ export default {
if (createNoteData.data?.createNote?.errors?.length) {
throw new Error(createNoteData.data?.createNote?.errors[0]);
}
- updateCommentState(store, createNoteData, fetchByIid, queryVariables);
},
});
clearDraft(this.autosaveKey);
@@ -189,23 +211,29 @@ export default {
:work-item-type="workItemType"
:is-project-archived="isProjectArchived"
/>
- <div v-else class="gl-relative gl-display-flex gl-align-items-flex-start gl-flex-wrap-nowrap">
- <gl-avatar :src="$options.constantOptions.avatarUrl" :size="32" class="gl-mr-3" />
- <work-item-comment-form
- v-if="isEditing"
- :work-item-type="workItemType"
- :aria-label="__('Add a comment')"
- :is-submitting="isSubmitting"
- :autosave-key="autosaveKey"
- @submitForm="updateWorkItem"
- @cancelEditing="cancelEditing"
- />
- <gl-button
- v-else
- class="gl-flex-grow-1 gl-justify-content-start! gl-text-secondary!"
- @click="isEditing = true"
- >{{ __('Add a comment') }}</gl-button
- >
+ <div v-else :class="timelineEntryInnerClass">
+ <div class="timeline-avatar gl-float-left">
+ <gl-avatar :src="$options.constantOptions.avatarUrl" :size="32" class="gl-mr-3" />
+ </div>
+ <div :class="timelineContentClass">
+ <div :class="parentClass">
+ <work-item-comment-form
+ v-if="isEditing"
+ :work-item-type="workItemType"
+ :aria-label="__('Add a reply')"
+ :is-submitting="isSubmitting"
+ :autosave-key="autosaveKey"
+ @submitForm="updateWorkItem"
+ @cancelEditing="cancelEditing"
+ />
+ <gl-button
+ v-else
+ class="gl-flex-grow-1 gl-justify-content-start! gl-text-secondary!"
+ @click="isEditing = true"
+ >{{ __('Add a reply') }}</gl-button
+ >
+ </div>
+ </div>
</div>
</li>
</template>
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 fd407fd9d9f..a3ebd51f76d 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
@@ -96,31 +96,39 @@ export default {
</script>
<template>
- <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"
- :form-field-props="formFieldProps"
- data-testid="work-item-add-comment"
- class="gl-mb-3"
- autofocus
- use-bottom-toolbar
- @input="setCommentText"
- @keydown.meta.enter="$emit('submitForm', commentText)"
- @keydown.ctrl.enter="$emit('submitForm', commentText)"
- @keydown.esc.stop="cancelEditing"
- />
- <gl-button
- category="primary"
- variant="confirm"
- data-testid="confirm-button"
- :loading="isSubmitting"
- @click="$emit('submitForm', commentText)"
- >{{ commentButtonText }}
- </gl-button>
- <gl-button data-testid="cancel-button" category="primary" class="gl-ml-3" @click="cancelEditing"
- >{{ __('Cancel') }}
- </gl-button>
- </form>
+ <div class="timeline-discussion-body">
+ <div class="note-body">
+ <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"
+ :form-field-props="formFieldProps"
+ data-testid="work-item-add-comment"
+ class="gl-mb-3"
+ autofocus
+ use-bottom-toolbar
+ @input="setCommentText"
+ @keydown.meta.enter="$emit('submitForm', commentText)"
+ @keydown.ctrl.enter="$emit('submitForm', commentText)"
+ @keydown.esc.stop="cancelEditing"
+ />
+ <gl-button
+ category="primary"
+ variant="confirm"
+ data-testid="confirm-button"
+ :loading="isSubmitting"
+ @click="$emit('submitForm', commentText)"
+ >{{ commentButtonText }}
+ </gl-button>
+ <gl-button
+ data-testid="cancel-button"
+ category="primary"
+ class="gl-ml-3"
+ @click="cancelEditing"
+ >{{ __('Cancel') }}
+ </gl-button>
+ </form>
+ </div>
+ </div>
</template>
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_comment_locked.vue b/app/assets/javascripts/work_items/components/notes/work_item_comment_locked.vue
index f837d025b7f..c1b6903cf17 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_comment_locked.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_comment_locked.vue
@@ -45,8 +45,10 @@ export default {
</script>
<template>
- <div class="disabled-comment text-center">
- <span class="issuable-note-warning gl-display-inline-block">
+ <div class="disabled-comment gl-text-center gl-relative gl-mt-3">
+ <span
+ class="issuable-note-warning gl-display-inline-block gl-w-full gl-px-5 gl-py-4 gl-rounded-base"
+ >
<gl-icon name="lock" class="gl-mr-2" />
<template v-if="isProjectArchived">
{{ $options.constantOptions.projectArchivedWarning }}
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 bda00f978b9..1e08fecaf3d 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
@@ -1,5 +1,6 @@
<script>
-import { GlAvatarLink, GlAvatar } from '@gitlab/ui';
+import { getLocationHash } from '~/lib/utils/url_utility';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { ASC } from '~/notes/constants';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import DiscussionNotesRepliesWrapper from '~/notes/components/discussion_notes_replies_wrapper.vue';
@@ -11,8 +12,6 @@ import WorkItemAddNote from './work_item_add_note.vue';
export default {
components: {
TimelineEntryItem,
- GlAvatarLink,
- GlAvatar,
WorkItemNote,
WorkItemAddNote,
ToggleRepliesWidget,
@@ -50,13 +49,19 @@ export default {
default: ASC,
required: false,
},
+ isModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
- isExpanded: false,
+ isExpanded: true,
autofocus: false,
isReplying: false,
replyingText: '',
+ showForm: false,
};
},
computed: {
@@ -66,11 +71,20 @@ export default {
author() {
return this.note.author;
},
+ noteId() {
+ return getIdFromGraphQLId(this.note.id);
+ },
noteAnchorId() {
- return `note_${this.note.id}`;
+ return `note_${this.noteId}`;
+ },
+ isTarget() {
+ return this.targetNoteHash === this.noteAnchorId;
+ },
+ targetNoteHash() {
+ return getLocationHash();
},
hasReplies() {
- return this.replies?.length;
+ return Boolean(this.replies?.length);
},
replies() {
if (this.discussion?.length > 1) {
@@ -81,19 +95,26 @@ export default {
discussionId() {
return this.discussion[0]?.discussion?.id || '';
},
+ shouldShowReplyForm() {
+ return this.showForm || this.hasReplies;
+ },
+ isOnlyCommentOfAThread() {
+ return !this.hasReplies && !this.showForm;
+ },
},
methods: {
showReplyForm() {
+ this.showForm = true;
this.isExpanded = true;
this.autofocus = true;
},
hideReplyForm() {
+ this.showForm = false;
this.isExpanded = this.hasReplies;
this.autofocus = false;
},
toggleDiscussion() {
this.isExpanded = !this.isExpanded;
- this.autofocus = this.isExpanded;
},
threadKey(note) {
/* eslint-disable @gitlab/require-i18n-strings */
@@ -113,76 +134,85 @@ export default {
</script>
<template>
+ <work-item-note
+ v-if="isOnlyCommentOfAThread"
+ :is-first-note="true"
+ :note="note"
+ :discussion-id="discussionId"
+ :has-replies="hasReplies"
+ :work-item-type="workItemType"
+ :is-modal="isModal"
+ :class="{ 'gl-mb-4': hasReplies }"
+ @startReplying="showReplyForm"
+ @deleteNote="$emit('deleteNote', note)"
+ @error="$emit('error', $event)"
+ />
<timeline-entry-item
- :id="noteAnchorId"
+ v-else
:class="{ 'internal-note': note.internal }"
- :data-note-id="note.id"
- class="note note-wrapper note-comment gl-px-0"
+ :data-note-id="noteId"
+ class="note note-discussion gl-px-0"
>
- <div class="timeline-avatar gl-float-left">
- <gl-avatar-link :href="author.webUrl">
- <gl-avatar
- :src="author.avatarUrl"
- :entity-name="author.username"
- :alt="author.name"
- :size="32"
- />
- </gl-avatar-link>
- </div>
-
<div class="timeline-content">
- <div class="discussion-body">
- <div class="discussion-wrapper">
- <div class="discussion-notes">
- <ul class="notes">
- <work-item-note
- :is-first-note="true"
- :note="note"
- :discussion-id="discussionId"
- :work-item-type="workItemType"
- :class="{ 'gl-mb-5': hasReplies }"
- @startReplying="showReplyForm"
- @deleteNote="$emit('deleteNote', note)"
- @error="$emit('error', $event)"
- />
- <discussion-notes-replies-wrapper>
- <toggle-replies-widget
- v-if="hasReplies"
- :collapsed="!isExpanded"
- :replies="replies"
- @toggle="toggleDiscussion({ discussionId })"
+ <div class="discussion">
+ <div class="discussion-body">
+ <div class="discussion-wrapper">
+ <div class="discussion-notes">
+ <ul class="notes">
+ <work-item-note
+ :is-first-note="true"
+ :note="note"
+ :discussion-id="discussionId"
+ :has-replies="hasReplies"
+ :work-item-type="workItemType"
+ :is-modal="isModal"
+ :class="{ 'gl-mb-4': hasReplies }"
+ @startReplying="showReplyForm"
+ @deleteNote="$emit('deleteNote', note)"
+ @error="$emit('error', $event)"
/>
- <template v-if="isExpanded">
- <template v-for="reply in replies">
- <work-item-note
- :key="threadKey(reply)"
+ <discussion-notes-replies-wrapper>
+ <toggle-replies-widget
+ v-if="hasReplies"
+ :collapsed="!isExpanded"
+ :replies="replies"
+ @toggle="toggleDiscussion({ discussionId })"
+ />
+ <template v-if="isExpanded">
+ <template v-for="reply in replies">
+ <work-item-note
+ :key="threadKey(reply)"
+ :discussion-id="discussionId"
+ :note="reply"
+ :work-item-type="workItemType"
+ :is-modal="isModal"
+ @startReplying="showReplyForm"
+ @deleteNote="$emit('deleteNote', reply)"
+ @error="$emit('error', $event)"
+ />
+ </template>
+ <work-item-note-replying v-if="isReplying" :body="replyingText" />
+ <work-item-add-note
+ v-if="shouldShowReplyForm"
+ :notes-form="false"
+ :autofocus="autofocus"
+ :query-variables="queryVariables"
+ :full-path="fullPath"
+ :work-item-id="workItemId"
+ :fetch-by-iid="fetchByIid"
:discussion-id="discussionId"
- :note="reply"
:work-item-type="workItemType"
- @startReplying="showReplyForm"
- @deleteNote="$emit('deleteNote', reply)"
+ :sort-order="sortOrder"
+ :add-padding="true"
+ @cancelEditing="hideReplyForm"
+ @replied="onReplied"
+ @replying="onReplying"
@error="$emit('error', $event)"
/>
</template>
- <work-item-note-replying v-if="isReplying" :body="replyingText" />
- <work-item-add-note
- :autofocus="autofocus"
- :query-variables="queryVariables"
- :full-path="fullPath"
- :work-item-id="workItemId"
- :fetch-by-iid="fetchByIid"
- :discussion-id="discussionId"
- :work-item-type="workItemType"
- :sort-order="sortOrder"
- :add-padding="true"
- @cancelEditing="hideReplyForm"
- @replied="onReplied"
- @replying="onReplying"
- @error="$emit('error', $event)"
- />
- </template>
- </discussion-notes-replies-wrapper>
- </ul>
+ </discussion-notes-replies-wrapper>
+ </ul>
+ </div>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_history_only_filter_note.vue b/app/assets/javascripts/work_items/components/notes/work_item_history_only_filter_note.vue
new file mode 100644
index 00000000000..07e25312f87
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/notes/work_item_history_only_filter_note.vue
@@ -0,0 +1,61 @@
+<script>
+import { GlButton, GlIcon, GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+import {
+ WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS,
+} from '~/work_items/constants';
+
+export default {
+ WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS,
+ i18n: {
+ information: s__(
+ "WorkItem|You're only seeing %{boldStart}other activity%{boldEnd} in the feed. To add a comment, switch to one of the following options.",
+ ),
+ },
+ components: {
+ GlButton,
+ GlIcon,
+ GlSprintf,
+ },
+ methods: {
+ selectFilter(value) {
+ this.$emit('changeFilter', value);
+ },
+ },
+};
+</script>
+
+<template>
+ <li class="timeline-entry note note-wrapper discussion-filter-note">
+ <div class="timeline-icon gl-display-none gl-lg-display-flex">
+ <gl-icon name="comment" />
+ </div>
+ <div class="timeline-content gl-pl-8">
+ <gl-sprintf :message="$options.i18n.information">
+ <template #bold="{ content }">
+ <b>{{ content }}</b>
+ </template>
+ </gl-sprintf>
+
+ <div class="discussion-filter-actions">
+ <gl-button
+ class="gl-mr-2 gl-mt-3"
+ data-testid="show-all-activity"
+ @click="selectFilter($options.WORK_ITEM_NOTES_FILTER_ALL_NOTES)"
+ >
+ {{ __('Show all activity') }}
+ </gl-button>
+ <gl-button
+ class="gl-mt-3"
+ data-testid="show-comments-only"
+ @click="selectFilter($options.WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS)"
+ >
+ {{ __('Show comments only') }}
+ </gl-button>
+ </div>
+ </div>
+ </li>
+</template>
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 5dd21a5f76f..dcb6557600e 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
@@ -1,9 +1,12 @@
<script>
import { GlAvatarLink, GlAvatar, GlDropdown, GlDropdownItem, GlTooltipDirective } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
+import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale';
import { updateDraft, clearDraft } from '~/lib/utils/autosave';
import { renderMarkdown } from '~/notes/utils';
+import { getLocationHash } from '~/lib/utils/url_utility';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import EditedAt from '~/issues/show/components/edited.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import NoteBody from '~/work_items/components/notes/work_item_note_body.vue';
@@ -17,6 +20,7 @@ export default {
i18n: {
moreActionsText: __('More actions'),
deleteNoteText: __('Delete comment'),
+ copyLinkText: __('Copy link'),
},
components: {
TimelineEntryItem,
@@ -43,10 +47,20 @@ export default {
required: false,
default: false,
},
+ hasReplies: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
workItemType: {
type: String,
required: true,
},
+ isModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -60,12 +74,18 @@ export default {
entryClass() {
return {
'note note-wrapper note-comment': true,
- 'gl-p-4': !this.isFirstNote,
+ target: this.isTarget,
+ 'inner-target': this.isTarget && !this.isFirstNote,
};
},
showReply() {
return this.note.userPermissions.createNote && this.isFirstNote;
},
+ noteHeaderClass() {
+ return {
+ 'note-header': true,
+ };
+ },
autosaveKey() {
// eslint-disable-next-line @gitlab/require-i18n-strings
return `${this.note.id}-comment`;
@@ -76,6 +96,21 @@ export default {
hasAdminPermission() {
return this.note.userPermissions.adminNote;
},
+ noteAnchorId() {
+ return `note_${getIdFromGraphQLId(this.note.id)}`;
+ },
+ isTarget() {
+ return this.targetNoteHash === this.noteAnchorId;
+ },
+ targetNoteHash() {
+ return getLocationHash();
+ },
+ noteUrl() {
+ return this.note.url;
+ },
+ hasAwardEmojiPermission() {
+ return this.note.userPermissions.awardEmoji;
+ },
},
methods: {
showReplyForm() {
@@ -114,13 +149,19 @@ export default {
Sentry.captureException(error);
}
},
+ notifyCopyDone() {
+ if (this.isModal) {
+ navigator.clipboard.writeText(this.noteUrl);
+ }
+ toast(__('Link copied to clipboard.'));
+ },
},
};
</script>
<template>
- <timeline-entry-item :class="entryClass">
- <div v-if="!isFirstNote" :key="note.id" class="timeline-avatar gl-float-left">
+ <timeline-entry-item :id="noteAnchorId" :class="entryClass">
+ <div :key="note.id" class="timeline-avatar gl-float-left">
<gl-avatar-link :href="author.webUrl">
<gl-avatar
:src="author.avatarUrl"
@@ -130,57 +171,73 @@ export default {
/>
</gl-avatar-link>
</div>
- <work-item-comment-form
- v-if="isEditing"
- :work-item-type="workItemType"
- :aria-label="__('Edit comment')"
- :autosave-key="autosaveKey"
- :initial-value="note.body"
- :comment-button-text="__('Save comment')"
- :class="{ 'gl-pl-8': !isFirstNote }"
- @cancelEditing="isEditing = false"
- @submitForm="updateNote"
- />
- <div v-else class="timeline-content-inner" data-testid="note-wrapper">
- <div class="note-header">
- <note-header :author="author" :created-at="note.createdAt" :note-id="note.id" />
- <note-actions
- :show-reply="showReply"
- :show-edit="hasAdminPermission"
- @startReplying="showReplyForm"
- @startEditing="startEditing"
- />
- <!-- v-if condition should be moved to "delete" dropdown item as soon as we implement copying the link -->
- <gl-dropdown
- v-if="hasAdminPermission"
- v-gl-tooltip
- icon="ellipsis_v"
- text-sr-only
- right
- :text="$options.i18n.moreActionsText"
- :title="$options.i18n.moreActionsText"
- category="tertiary"
- no-caret
- >
- <gl-dropdown-item
- variant="danger"
- data-testid="delete-note-action"
- @click="$emit('deleteNote')"
+ <div class="timeline-content">
+ <work-item-comment-form
+ v-if="isEditing"
+ :work-item-type="workItemType"
+ :aria-label="__('Edit comment')"
+ :autosave-key="autosaveKey"
+ :initial-value="note.body"
+ :comment-button-text="__('Save comment')"
+ @cancelEditing="isEditing = false"
+ @submitForm="updateNote"
+ />
+ <div v-else data-testid="note-wrapper">
+ <div :class="noteHeaderClass">
+ <note-header
+ :author="author"
+ :created-at="note.createdAt"
+ :note-id="note.id"
+ :note-url="note.url"
>
- {{ $options.i18n.deleteNoteText }}
- </gl-dropdown-item>
- </gl-dropdown>
- </div>
- <div class="timeline-discussion-body">
- <note-body ref="noteBody" :note="note" />
+ <span v-if="note.createdAt" class="d-none d-sm-inline">&middot;</span>
+ </note-header>
+ <div class="gl-display-inline-flex">
+ <note-actions
+ :show-award-emoji="hasAwardEmojiPermission"
+ :note-url="noteUrl"
+ :show-reply="showReply"
+ :show-edit="hasAdminPermission"
+ :note-id="note.id"
+ @startReplying="showReplyForm"
+ @startEditing="startEditing"
+ @error="($event) => $emit('error', $event)"
+ />
+ <gl-dropdown
+ v-gl-tooltip
+ icon="ellipsis_v"
+ text-sr-only
+ right
+ :text="$options.i18n.moreActionsText"
+ :title="$options.i18n.moreActionsText"
+ category="tertiary"
+ no-caret
+ >
+ <gl-dropdown-item :data-clipboard-text="noteUrl" @click="notifyCopyDone">
+ <span>{{ $options.i18n.copyLinkText }}</span>
+ </gl-dropdown-item>
+ <gl-dropdown-item
+ v-if="hasAdminPermission"
+ variant="danger"
+ data-testid="delete-note-action"
+ @click="$emit('deleteNote')"
+ >
+ {{ $options.i18n.deleteNoteText }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
+ </div>
+ <div class="timeline-discussion-body">
+ <note-body ref="noteBody" :note="note" :has-replies="hasReplies" />
+ </div>
+ <edited-at
+ v-if="note.lastEditedBy"
+ :updated-at="note.lastEditedAt"
+ :updated-by-name="lastEditedBy.name"
+ :updated-by-path="lastEditedBy.webPath"
+ :class="isFirstNote ? 'gl-pl-3' : 'gl-pl-8'"
+ />
</div>
- <edited-at
- v-if="note.lastEditedBy"
- :updated-at="note.lastEditedAt"
- :updated-by-name="lastEditedBy.name"
- :updated-by-path="lastEditedBy.webPath"
- :class="isFirstNote ? 'gl-pl-3' : 'gl-pl-8'"
- />
</div>
</timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue b/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue
index c17e855e527..6bea7953698 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue
@@ -1,7 +1,10 @@
<script>
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-import { __ } from '~/locale';
+import { GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
+import { __, s__ } from '~/locale';
import ReplyButton from '~/notes/components/note_actions/reply_button.vue';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import addAwardEmojiMutation from '../../graphql/notes/work_item_note_add_award_emoji.mutation.graphql';
export default {
name: 'WorkItemNoteActions',
@@ -10,11 +13,14 @@ export default {
},
components: {
GlButton,
+ GlIcon,
ReplyButton,
+ EmojiPicker: () => import('~/emoji/components/picker.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
showReply: {
type: Boolean,
@@ -24,12 +30,63 @@ export default {
type: Boolean,
required: true,
},
+ noteId: {
+ type: String,
+ required: true,
+ },
+ showAwardEmoji: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ methods: {
+ async setAwardEmoji(name) {
+ try {
+ const {
+ data: {
+ awardEmojiAdd: { errors = [] },
+ },
+ } = await this.$apollo.mutate({
+ mutation: addAwardEmojiMutation,
+ variables: {
+ awardableId: this.noteId,
+ name,
+ },
+ });
+
+ if (errors.length > 0) {
+ throw new Error(errors[0].message);
+ }
+ } catch (error) {
+ this.$emit('error', s__('WorkItem|Failed to award emoji'));
+ Sentry.captureException(error);
+ }
+ },
},
};
</script>
<template>
<div class="note-actions">
+ <emoji-picker
+ v-if="showAwardEmoji && glFeatures.workItemsMvc2"
+ toggle-class="note-action-button note-emoji-button btn-icon btn-default-tertiary"
+ data-testid="note-emoji-button"
+ @click="setAwardEmoji"
+ >
+ <template #button-content>
+ <gl-icon class="award-control-icon-neutral gl-button-icon gl-icon" name="slight-smile" />
+ <gl-icon
+ class="award-control-icon-positive gl-button-icon gl-icon gl-left-3!"
+ name="smiley"
+ />
+ <gl-icon
+ class="award-control-icon-super-positive gl-button-icon gl-icon gl-left-3!"
+ name="smile"
+ />
+ </template>
+ </emoji-picker>
<reply-button v-if="showReply" ref="replyButton" @startReplying="$emit('startReplying')" />
<gl-button
v-if="showEdit"
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note_body.vue b/app/assets/javascripts/work_items/components/notes/work_item_note_body.vue
index 95397b58925..bec902fd325 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_note_body.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_note_body.vue
@@ -12,6 +12,11 @@ export default {
type: Object,
required: true,
},
+ hasReplies: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
watch: {
'note.bodyHtml': {
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note_replying.vue b/app/assets/javascripts/work_items/components/notes/work_item_note_replying.vue
index 46f61ccd204..f053f6e1d7c 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_note_replying.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_note_replying.vue
@@ -41,13 +41,23 @@ export default {
</script>
<template>
- <timeline-entry-item class="note note-wrapper note-comment gl-p-4 being-posted">
+ <timeline-entry-item class="note note-wrapper note-comment being-posted">
<div class="timeline-avatar gl-float-left">
- <gl-avatar :src="$options.constantOptions.avatarUrl" :size="32" class="gl-mr-3" />
+ <gl-avatar :src="$options.constantOptions.avatarUrl" :size="32" />
</div>
- <div class="note-header">
- <note-header :author="author" />
+ <div class="timeline-content" data-testid="note-wrapper">
+ <div class="note-header">
+ <note-header :author="author" />
+ </div>
+ <div ref="note-body" class="timeline-discussion-body">
+ <div class="note-body">
+ <div
+ v-safe-html:[$options.safeHtmlConfig]="body"
+ class="note-text md"
+ data-testid="work-item-note-body"
+ ></div>
+ </div>
+ </div>
</div>
- <div ref="note-body" v-safe-html:[$options.safeHtmlConfig]="body" class="note-body"></div>
</timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note_signed_out.vue b/app/assets/javascripts/work_items/components/notes/work_item_note_signed_out.vue
index 3ef4a16bc57..bccbec903b4 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_note_signed_out.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_note_signed_out.vue
@@ -27,5 +27,5 @@ export default {
</script>
<template>
- <div v-safe-html="signedOutText" class="disabled-comment gl-text-center"></div>
+ <div v-safe-html="signedOutText" class="disabled-comment gl-text-center gl-relative"></div>
</template>
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
new file mode 100644
index 00000000000..0c1419e983f
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/notes/work_item_notes_activity_header.vue
@@ -0,0 +1,91 @@
+<script>
+import WorkItemActivitySortFilter from '~/work_items/components/notes/work_item_activity_sort_filter.vue';
+import { s__ } from '~/locale';
+import { ASC } from '~/notes/constants';
+import {
+ WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ WORK_ITEM_ACTIVITY_FILTER_OPTIONS,
+ WORK_ITEM_NOTES_FILTER_KEY,
+ WORK_ITEM_ACTIVITY_SORT_OPTIONS,
+ WORK_ITEM_NOTES_SORT_ORDER_KEY,
+} from '~/work_items/constants';
+
+export default {
+ i18n: {
+ activityLabel: s__('WorkItem|Activity'),
+ },
+ components: {
+ WorkItemActivitySortFilter,
+ },
+ props: {
+ disableActivityFilterSort: {
+ type: Boolean,
+ required: true,
+ },
+ sortOrder: {
+ type: String,
+ default: ASC,
+ required: false,
+ },
+ workItemType: {
+ type: String,
+ required: true,
+ },
+ discussionFilter: {
+ type: String,
+ default: WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ required: false,
+ },
+ },
+ methods: {
+ changeNotesSortOrder(direction) {
+ this.$emit('changeSort', direction);
+ },
+ filterDiscussions(filterValue) {
+ this.$emit('changeFilter', filterValue);
+ },
+ },
+ WORK_ITEM_ACTIVITY_FILTER_OPTIONS,
+ WORK_ITEM_NOTES_FILTER_KEY,
+ WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ WORK_ITEM_ACTIVITY_SORT_OPTIONS,
+ WORK_ITEM_NOTES_SORT_ORDER_KEY,
+ ASC,
+};
+</script>
+
+<template>
+ <div
+ class="gl-display-flex gl-justify-content-space-between gl-flex-wrap gl-pb-3 gl-align-items-center"
+ >
+ <h3 class="gl-font-base gl-m-0">{{ $options.i18n.activityLabel }}</h3>
+ <div class="gl-display-flex gl-gap-3">
+ <work-item-activity-sort-filter
+ :work-item-type="workItemType"
+ :loading="disableActivityFilterSort"
+ :sort-filter-prop="discussionFilter"
+ :filter-options="$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"
+ tracking-label="item_track_notes_filtering"
+ filter-event="changeFilter"
+ data-testid="work-item-filter"
+ @changeFilter="filterDiscussions"
+ />
+ <work-item-activity-sort-filter
+ :work-item-type="workItemType"
+ :loading="disableActivityFilterSort"
+ :sort-filter-prop="sortOrder"
+ :filter-options="$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"
+ tracking-label="item_track_notes_sorting"
+ filter-event="changeSort"
+ data-testid="work-item-sort"
+ @changeSort="changeNotesSortOrder"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/work_items/components/widget_wrapper.vue b/app/assets/javascripts/work_items/components/widget_wrapper.vue
index 355f17e970b..db36b4e1bbe 100644
--- a/app/assets/javascripts/work_items/components/widget_wrapper.vue
+++ b/app/assets/javascripts/work_items/components/widget_wrapper.vue
@@ -44,8 +44,10 @@ export default {
<template>
<div class="gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-bg-gray-10 gl-mt-4">
<div
- class="gl-px-5 gl-py-3 gl-display-flex gl-justify-content-space-between"
- :class="{ 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100': isOpen }"
+ class="gl-pl-5 gl-pr-4 gl-py-4 gl-display-flex gl-justify-content-space-between gl-bg-white gl-rounded-base"
+ :class="{
+ 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100 gl-rounded-bottom-left-none! gl-rounded-bottom-right-none!': isOpen,
+ }"
>
<div class="gl-display-flex gl-flex-grow-1">
<h5 class="gl-m-0 gl-line-height-24">
@@ -71,7 +73,7 @@ export default {
<div
v-if="isOpen"
class="gl-bg-gray-10 gl-rounded-bottom-left-base gl-rounded-bottom-right-base"
- :class="{ 'gl-p-5 gl-pb-3': !error }"
+ :class="{ 'gl-p-3': !error }"
data-testid="widget-body"
>
<slot name="body"></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 9f9d94ec3c2..3c56b627673 100644
--- a/app/assets/javascripts/work_items/components/work_item_actions.vue
+++ b/app/assets/javascripts/work_items/components/work_item_actions.vue
@@ -115,6 +115,7 @@ export default {
v-if="canDelete"
v-gl-modal="'work-item-confirm-delete'"
data-testid="delete-action"
+ variant="danger"
>{{ i18n.deleteWorkItem }}</gl-dropdown-item
>
</gl-dropdown>
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 fc4c05d96b2..95527dda1d4 100644
--- a/app/assets/javascripts/work_items/components/work_item_assignees.vue
+++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue
@@ -298,7 +298,7 @@ export default {
<div class="form-row gl-mb-5 work-item-assignees gl-relative gl-flex-nowrap">
<span
:id="assigneesTitleId"
- class="gl-font-weight-bold col-lg-2 col-3 gl-pt-2 min-w-fit-content gl-overflow-wrap-break"
+ class="gl-font-weight-bold gl-mt-2 col-lg-2 col-3 gl-pt-2 min-w-fit-content gl-overflow-wrap-break"
data-testid="assignees-title"
>{{ assigneeText }}</span
>
diff --git a/app/assets/javascripts/work_items/components/work_item_description.vue b/app/assets/javascripts/work_items/components/work_item_description.vue
index 399c220bc96..ddfaa376028 100644
--- a/app/assets/javascripts/work_items/components/work_item_description.vue
+++ b/app/assets/javascripts/work_items/components/work_item_description.vue
@@ -255,7 +255,6 @@ export default {
enable-autocomplete
supports-quick-actions
init-on-autofocus
- use-bottom-toolbar
@input="setDescriptionText"
@keydown.meta.enter="updateWorkItem"
@keydown.ctrl.enter="updateWorkItem"
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 262c093a1d0..ad7a54aaf16 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -215,6 +215,9 @@ export default {
workItemType() {
return this.workItem.workItemType?.name;
},
+ workItemBreadcrumbReference() {
+ return this.workItemType ? `${this.workItemType} #${this.workItem.iid}` : '';
+ },
canUpdate() {
return this.workItem?.userPermissions?.updateWorkItem;
},
@@ -245,6 +248,9 @@ export default {
parentWorkItemConfidentiality() {
return this.parentWorkItem?.confidential;
},
+ parentWorkItemReference() {
+ return this.parentWorkItem ? `${this.parentWorkItem.title} #${this.parentWorkItem.iid}` : '';
+ },
parentUrl() {
// Once more types are moved to have Work Items involved
// we need to handle this properly.
@@ -293,10 +299,7 @@ export default {
return this.isWidgetPresent(WIDGET_TYPE_NOTES);
},
fetchByIid() {
- return (
- (this.glFeatures.useIidInWorkItemsPath && parseBoolean(getParameterByName('iid_path'))) ||
- false
- );
+ return parseBoolean(getParameterByName('iid_path'));
},
queryVariables() {
return this.fetchByIid
@@ -314,6 +317,11 @@ export default {
);
return widgetHierarchy.children.nodes;
},
+ workItemBodyClass() {
+ return {
+ 'gl-pt-5': !this.updateError && !this.isModal,
+ };
+ },
},
mounted() {
if (this.modalWorkItemId || this.modalWorkItemIid) {
@@ -445,6 +453,9 @@ export default {
Sentry.captureException(error);
}
},
+ updateHasNotes() {
+ this.$emit('has-notes');
+ },
updateUrl(modalWorkItem) {
const params = this.fetchByIid
? { work_item_iid: modalWorkItem?.iid }
@@ -480,221 +491,217 @@ export default {
</script>
<template>
- <section class="gl-pt-5">
- <gl-alert
- v-if="updateError"
- class="gl-mb-3"
- variant="danger"
- @dismiss="updateError = undefined"
- >
- {{ updateError }}
- </gl-alert>
-
- <div v-if="workItemLoading" class="gl-max-w-26 gl-py-5">
- <gl-skeleton-loader :height="65" :width="240">
- <rect width="240" height="20" x="5" y="0" rx="4" />
- <rect width="100" height="20" x="5" y="45" rx="4" />
- </gl-skeleton-loader>
- </div>
- <template v-else>
- <div class="gl-display-flex gl-align-items-center" data-testid="work-item-body">
- <ul
- v-if="parentWorkItem"
- class="list-unstyled gl-display-flex gl-mr-auto gl-max-w-26 gl-md-max-w-50p gl-min-w-0 gl-mb-0 gl-z-index-0"
- data-testid="work-item-parent"
- >
- <li class="gl-ml-n4 gl-display-flex gl-align-items-center gl-overflow-hidden">
- <gl-button
- v-gl-tooltip.hover
- class="gl-text-truncate gl-max-w-full"
- :icon="parentWorkItemIconName"
- category="tertiary"
- :href="parentUrl"
- :title="parentWorkItem.title"
- @click="openInModal($event, parentWorkItem)"
- >{{ parentWorkItem.title }}</gl-button
+ <section>
+ <section v-if="updateError" class="flash-container flash-container-page sticky">
+ <gl-alert class="gl-mb-3" variant="danger" @dismiss="updateError = undefined">
+ {{ updateError }}
+ </gl-alert>
+ </section>
+ <section :class="workItemBodyClass">
+ <div v-if="workItemLoading" class="gl-max-w-26 gl-py-5">
+ <gl-skeleton-loader :height="65" :width="240">
+ <rect width="240" height="20" x="5" y="0" rx="4" />
+ <rect width="100" height="20" x="5" y="45" rx="4" />
+ </gl-skeleton-loader>
+ </div>
+ <template v-else>
+ <div class="gl-display-flex gl-align-items-center" data-testid="work-item-body">
+ <ul
+ v-if="parentWorkItem"
+ class="list-unstyled gl-display-flex gl-mr-auto gl-max-w-26 gl-md-max-w-50p gl-min-w-0 gl-mb-0 gl-z-index-0"
+ data-testid="work-item-parent"
+ >
+ <li class="gl-ml-n4 gl-display-flex gl-align-items-center gl-overflow-hidden">
+ <gl-button
+ v-gl-tooltip.hover
+ class="gl-text-truncate gl-max-w-full"
+ :icon="parentWorkItemIconName"
+ category="tertiary"
+ :href="parentUrl"
+ :title="parentWorkItemReference"
+ @click="openInModal($event, parentWorkItem)"
+ >{{ parentWorkItemReference }}</gl-button
+ >
+ <gl-icon name="chevron-right" :size="16" class="gl-flex-shrink-0" />
+ </li>
+ <li
+ class="gl-px-4 gl-py-3 gl-line-height-0 gl-display-flex gl-align-items-center gl-overflow-hidden gl-flex-shrink-0"
>
- <gl-icon name="chevron-right" :size="16" class="gl-flex-shrink-0" />
- </li>
- <li
- class="gl-px-4 gl-py-3 gl-line-height-0 gl-display-flex gl-align-items-center gl-overflow-hidden gl-flex-shrink-0"
+ <work-item-type-icon
+ :work-item-icon-name="workItemIconName"
+ :work-item-type="workItemType && workItemType.toUpperCase()"
+ />
+ {{ workItemBreadcrumbReference }}
+ </li>
+ </ul>
+ <work-item-type-icon
+ v-else-if="!error"
+ :work-item-icon-name="workItemIconName"
+ :work-item-type="workItemType && workItemType.toUpperCase()"
+ show-text
+ class="gl-font-weight-bold gl-text-secondary gl-mr-auto"
+ data-testid="work-item-type"
+ />
+ <gl-loading-icon v-if="updateInProgress" :inline="true" class="gl-mr-3" />
+ <gl-badge
+ v-if="workItem.confidential"
+ v-gl-tooltip.bottom
+ :title="confidentialTooltip"
+ variant="warning"
+ icon="eye-slash"
+ class="gl-mr-3 gl-cursor-help"
+ >{{ __('Confidential') }}</gl-badge
>
- <work-item-type-icon
- :work-item-icon-name="workItemIconName"
- :work-item-type="workItemType && workItemType.toUpperCase()"
- />
- {{ workItemType }}
- </li>
- </ul>
- <work-item-type-icon
- v-else-if="!error"
- :work-item-icon-name="workItemIconName"
- :work-item-type="workItemType && workItemType.toUpperCase()"
- show-text
- class="gl-font-weight-bold gl-text-secondary gl-mr-auto"
- data-testid="work-item-type"
+ <work-item-actions
+ v-if="canUpdate || canDelete"
+ :work-item-id="workItem.id"
+ :work-item-type="workItemType"
+ :can-delete="canDelete"
+ :can-update="canUpdate"
+ :is-confidential="workItem.confidential"
+ :is-parent-confidential="parentWorkItemConfidentiality"
+ @deleteWorkItem="$emit('deleteWorkItem', { workItemType, workItemId: workItem.id })"
+ @toggleWorkItemConfidentiality="toggleConfidentiality"
+ @error="updateError = $event"
+ />
+ <gl-button
+ v-if="isModal"
+ category="tertiary"
+ data-testid="work-item-close"
+ icon="close"
+ :aria-label="__('Close')"
+ @click="$emit('close')"
+ />
+ </div>
+ <work-item-title
+ v-if="workItem.title"
+ :work-item-id="workItem.id"
+ :work-item-title="workItem.title"
+ :work-item-type="workItemType"
+ :work-item-parent-id="workItemParentId"
+ :can-update="canUpdate"
+ @error="updateError = $event"
+ />
+ <work-item-created-updated
+ :work-item-id="workItem.id"
+ :work-item-iid="workItemIid"
+ :full-path="fullPath"
+ :fetch-by-iid="fetchByIid"
+ />
+ <work-item-state
+ :work-item="workItem"
+ :work-item-parent-id="workItemParentId"
+ :can-update="canUpdate"
+ @error="updateError = $event"
/>
- <gl-loading-icon v-if="updateInProgress" :inline="true" class="gl-mr-3" />
- <gl-badge
- v-if="workItem.confidential"
- v-gl-tooltip.bottom
- :title="confidentialTooltip"
- variant="warning"
- icon="eye-slash"
- class="gl-mr-3 gl-cursor-help"
- >{{ __('Confidential') }}</gl-badge
- >
- <work-item-actions
- v-if="canUpdate || canDelete"
+ <work-item-assignees
+ v-if="workItemAssignees"
+ :can-update="canUpdate"
:work-item-id="workItem.id"
+ :assignees="workItemAssignees.assignees.nodes"
+ :allows-multiple-assignees="workItemAssignees.allowsMultipleAssignees"
:work-item-type="workItemType"
- :can-delete="canDelete"
+ :can-invite-members="workItemAssignees.canInviteMembers"
+ :full-path="fullPath"
+ @error="updateError = $event"
+ />
+ <work-item-labels
+ v-if="workItemLabels"
+ :work-item-id="workItem.id"
:can-update="canUpdate"
- :is-confidential="workItem.confidential"
- :is-parent-confidential="parentWorkItemConfidentiality"
- @deleteWorkItem="$emit('deleteWorkItem', { workItemType, workItemId: workItem.id })"
- @toggleWorkItemConfidentiality="toggleConfidentiality"
+ :full-path="fullPath"
+ :fetch-by-iid="fetchByIid"
+ :query-variables="queryVariables"
@error="updateError = $event"
/>
- <gl-button
- v-if="isModal"
- category="tertiary"
- data-testid="work-item-close"
- icon="close"
- :aria-label="__('Close')"
- @click="$emit('close')"
+ <work-item-due-date
+ v-if="workItemDueDate"
+ :can-update="canUpdate"
+ :due-date="workItemDueDate.dueDate"
+ :start-date="workItemDueDate.startDate"
+ :work-item-id="workItem.id"
+ :work-item-type="workItemType"
+ @error="updateError = $event"
+ />
+ <work-item-milestone
+ v-if="workItemMilestone"
+ :work-item-id="workItem.id"
+ :work-item-milestone="workItemMilestone.milestone"
+ :work-item-type="workItemType"
+ :fetch-by-iid="fetchByIid"
+ :query-variables="queryVariables"
+ :can-update="canUpdate"
+ :full-path="fullPath"
+ @error="updateError = $event"
+ />
+ <work-item-weight
+ v-if="workItemWeight"
+ class="gl-mb-5"
+ :can-update="canUpdate"
+ :weight="workItemWeight.weight"
+ :work-item-id="workItem.id"
+ :work-item-type="workItemType"
+ :fetch-by-iid="fetchByIid"
+ :query-variables="queryVariables"
+ @error="updateError = $event"
+ />
+ <work-item-progress
+ v-if="workItemProgress"
+ class="gl-mb-5"
+ :can-update="canUpdate"
+ :progress="workItemProgress.progress"
+ :work-item-id="workItem.id"
+ :work-item-type="workItemType"
+ :fetch-by-iid="fetchByIid"
+ :query-variables="queryVariables"
+ @error="updateError = $event"
+ />
+ <work-item-iteration
+ v-if="workItemIteration"
+ class="gl-mb-5"
+ :iteration="workItemIteration.iteration"
+ :can-update="canUpdate"
+ :work-item-id="workItem.id"
+ :work-item-type="workItemType"
+ :fetch-by-iid="fetchByIid"
+ :query-variables="queryVariables"
+ :full-path="fullPath"
+ @error="updateError = $event"
+ />
+ <work-item-health-status
+ v-if="workItemHealthStatus"
+ class="gl-mb-5"
+ :health-status="workItemHealthStatus.healthStatus"
+ :can-update="canUpdate"
+ :work-item-id="workItem.id"
+ :work-item-type="workItemType"
+ :fetch-by-iid="fetchByIid"
+ :query-variables="queryVariables"
+ :full-path="fullPath"
+ @error="updateError = $event"
+ />
+ <work-item-description
+ v-if="hasDescriptionWidget"
+ :work-item-id="workItem.id"
+ :full-path="fullPath"
+ :fetch-by-iid="fetchByIid"
+ :query-variables="queryVariables"
+ class="gl-pt-5"
+ @error="updateError = $event"
+ />
+ <work-item-tree
+ v-if="workItemType === $options.WORK_ITEM_TYPE_VALUE_OBJECTIVE"
+ :work-item-type="workItemType"
+ :parent-work-item-type="workItem.workItemType.name"
+ :work-item-id="workItem.id"
+ :children="children"
+ :can-update="canUpdate"
+ :project-path="fullPath"
+ :confidential="workItem.confidential"
+ @addWorkItemChild="addChild"
+ @removeChild="removeChild"
+ @show-modal="openInModal"
/>
- </div>
- <work-item-title
- v-if="workItem.title"
- :work-item-id="workItem.id"
- :work-item-title="workItem.title"
- :work-item-type="workItemType"
- :work-item-parent-id="workItemParentId"
- :can-update="canUpdate"
- @error="updateError = $event"
- />
- <work-item-created-updated
- :work-item-id="workItem.id"
- :work-item-iid="workItemIid"
- :full-path="fullPath"
- :fetch-by-iid="fetchByIid"
- />
- <work-item-state
- :work-item="workItem"
- :work-item-parent-id="workItemParentId"
- :can-update="canUpdate"
- @error="updateError = $event"
- />
- <work-item-assignees
- v-if="workItemAssignees"
- :can-update="canUpdate"
- :work-item-id="workItem.id"
- :assignees="workItemAssignees.assignees.nodes"
- :allows-multiple-assignees="workItemAssignees.allowsMultipleAssignees"
- :work-item-type="workItemType"
- :can-invite-members="workItemAssignees.canInviteMembers"
- :full-path="fullPath"
- @error="updateError = $event"
- />
- <work-item-labels
- v-if="workItemLabels"
- :work-item-id="workItem.id"
- :can-update="canUpdate"
- :full-path="fullPath"
- :fetch-by-iid="fetchByIid"
- :query-variables="queryVariables"
- @error="updateError = $event"
- />
- <work-item-due-date
- v-if="workItemDueDate"
- :can-update="canUpdate"
- :due-date="workItemDueDate.dueDate"
- :start-date="workItemDueDate.startDate"
- :work-item-id="workItem.id"
- :work-item-type="workItemType"
- @error="updateError = $event"
- />
- <work-item-milestone
- v-if="workItemMilestone"
- :work-item-id="workItem.id"
- :work-item-milestone="workItemMilestone.milestone"
- :work-item-type="workItemType"
- :fetch-by-iid="fetchByIid"
- :query-variables="queryVariables"
- :can-update="canUpdate"
- :full-path="fullPath"
- @error="updateError = $event"
- />
- <work-item-weight
- v-if="workItemWeight"
- class="gl-mb-5"
- :can-update="canUpdate"
- :weight="workItemWeight.weight"
- :work-item-id="workItem.id"
- :work-item-type="workItemType"
- :fetch-by-iid="fetchByIid"
- :query-variables="queryVariables"
- @error="updateError = $event"
- />
- <work-item-progress
- v-if="workItemProgress"
- class="gl-mb-5"
- :can-update="canUpdate"
- :progress="workItemProgress.progress"
- :work-item-id="workItem.id"
- :work-item-type="workItemType"
- :fetch-by-iid="fetchByIid"
- :query-variables="queryVariables"
- @error="updateError = $event"
- />
- <work-item-iteration
- v-if="workItemIteration"
- class="gl-mb-5"
- :iteration="workItemIteration.iteration"
- :can-update="canUpdate"
- :work-item-id="workItem.id"
- :work-item-type="workItemType"
- :fetch-by-iid="fetchByIid"
- :query-variables="queryVariables"
- :full-path="fullPath"
- @error="updateError = $event"
- />
- <work-item-health-status
- v-if="workItemHealthStatus"
- class="gl-mb-5"
- :health-status="workItemHealthStatus.healthStatus"
- :can-update="canUpdate"
- :work-item-id="workItem.id"
- :work-item-type="workItemType"
- :fetch-by-iid="fetchByIid"
- :query-variables="queryVariables"
- :full-path="fullPath"
- @error="updateError = $event"
- />
- <work-item-description
- v-if="hasDescriptionWidget"
- :work-item-id="workItem.id"
- :full-path="fullPath"
- :fetch-by-iid="fetchByIid"
- :query-variables="queryVariables"
- class="gl-pt-5"
- @error="updateError = $event"
- />
- <work-item-tree
- v-if="workItemType === $options.WORK_ITEM_TYPE_VALUE_OBJECTIVE"
- :work-item-type="workItemType"
- :parent-work-item-type="workItem.workItemType.name"
- :work-item-id="workItem.id"
- :children="children"
- :can-update="canUpdate"
- :project-path="fullPath"
- :confidential="workItem.confidential"
- @addWorkItemChild="addChild"
- @removeChild="removeChild"
- @show-modal="openInModal"
- />
- <template v-if="workItemsMvcEnabled">
<work-item-notes
v-if="workItemNotes"
:work-item-id="workItem.id"
@@ -705,21 +712,21 @@ export default {
class="gl-pt-5"
@error="updateError = $event"
/>
+ <gl-empty-state
+ v-if="error"
+ :title="$options.i18n.fetchErrorTitle"
+ :description="error"
+ :svg-path="noAccessSvgPath"
+ />
</template>
- <gl-empty-state
- v-if="error"
- :title="$options.i18n.fetchErrorTitle"
- :description="error"
- :svg-path="noAccessSvgPath"
+ <work-item-detail-modal
+ v-if="!isModal"
+ ref="modal"
+ :work-item-id="modalWorkItemId"
+ :work-item-iid="modalWorkItemIid"
+ :show="true"
+ @close="updateUrl"
/>
- </template>
- <work-item-detail-modal
- v-if="!isModal"
- ref="modal"
- :work-item-id="modalWorkItemId"
- :work-item-iid="modalWorkItemIid"
- :show="true"
- @close="updateUrl"
- />
+ </section>
</section>
</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_detail_modal.vue b/app/assets/javascripts/work_items/components/work_item_detail_modal.vue
index 1b8e97bf717..730bdb4e7c7 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail_modal.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail_modal.vue
@@ -1,10 +1,12 @@
<script>
import { GlAlert, GlModal } from '@gitlab/ui';
import { s__ } from '~/locale';
+import { scrollToTargetOnResize } from '~/lib/utils/resize_observer';
import deleteWorkItemFromTaskMutation from '../graphql/delete_task_from_work_item.mutation.graphql';
import deleteWorkItemMutation from '../graphql/delete_work_item.mutation.graphql';
export default {
+ WORK_ITEM_DETAIL_MODAL_ID: 'work-item-detail-modal',
i18n: {
errorMessage: s__('WorkItem|Something went wrong when deleting the task. Please try again.'),
},
@@ -51,6 +53,8 @@ export default {
error: undefined,
updatedWorkItemId: null,
updatedWorkItemIid: null,
+ isModalShown: false,
+ hasNotes: false,
};
},
computed: {
@@ -61,6 +65,13 @@ export default {
return this.updatedWorkItemIid || this.workItemIid;
},
},
+ watch: {
+ hasNotes(newVal) {
+ if (newVal && this.isModalShown) {
+ scrollToTargetOnResize({ containerId: this.$options.WORK_ITEM_DETAIL_MODAL_ID });
+ }
+ },
+ },
methods: {
deleteWorkItem() {
if (this.lockVersion != null && this.lineNumberStart && this.lineNumberEnd) {
@@ -128,6 +139,7 @@ export default {
this.updatedWorkItemId = null;
this.updatedWorkItemIid = null;
this.error = '';
+ this.isModalShown = false;
this.$emit('close');
},
hide() {
@@ -144,6 +156,12 @@ export default {
this.updatedWorkItemIid = workItem.iid;
this.$emit('update-modal', $event, workItem);
},
+ onModalShow() {
+ this.isModalShown = true;
+ },
+ updateHasNotes() {
+ this.hasNotes = true;
+ },
},
};
</script>
@@ -151,13 +169,15 @@ export default {
<template>
<gl-modal
ref="modal"
+ static
hide-footer
size="lg"
- modal-id="work-item-detail-modal"
+ :modal-id="$options.WORK_ITEM_DETAIL_MODAL_ID"
header-class="gl-p-0 gl-pb-2!"
scrollable
- data-testid="work-item-detail-modal"
+ :data-testid="$options.WORK_ITEM_DETAIL_MODAL_ID"
@hide="closeModal"
+ @shown="onModalShow"
>
<gl-alert v-if="error" variant="danger" @dismiss="error = false">
{{ error }}
@@ -172,6 +192,7 @@ export default {
@close="hide"
@deleteWorkItem="deleteWorkItem"
@update-modal="updateModal"
+ @has-notes="updateHasNotes"
/>
</gl-modal>
</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_due_date.vue b/app/assets/javascripts/work_items/components/work_item_due_date.vue
index 03c5b7096b2..3e546598dc2 100644
--- a/app/assets/javascripts/work_items/components/work_item_due_date.vue
+++ b/app/assets/javascripts/work_items/components/work_item_due_date.vue
@@ -223,7 +223,12 @@ export default {
@clear="clearStartDatePicker"
@close="handleStartDateInput"
/>
- <gl-button v-if="showStartDateButton" category="tertiary" @click="clickShowStartDate">
+ <gl-button
+ v-if="showStartDateButton"
+ category="tertiary"
+ class="gl-text-gray-500!"
+ @click="clickShowStartDate"
+ >
{{ $options.i18n.addStartDate }}
</gl-button>
</gl-form-group>
@@ -250,7 +255,12 @@ export default {
@clear="clearDueDatePicker"
@close="updateDates"
/>
- <gl-button v-if="showDueDateButton" category="tertiary" @click="clickShowDueDate">
+ <gl-button
+ v-if="showDueDateButton"
+ category="tertiary"
+ class="gl-text-gray-500!"
+ @click="clickShowDueDate"
+ >
{{ $options.i18n.addDueDate }}
</gl-button>
</gl-form-group>
diff --git a/app/assets/javascripts/work_items/components/work_item_links/index.js b/app/assets/javascripts/work_items/components/work_item_links/index.js
index a7405b6d86c..6b097f6b1ed 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/index.js
+++ b/app/assets/javascripts/work_items/components/work_item_links/index.js
@@ -15,7 +15,6 @@ export default function initWorkItemLinks() {
const {
projectPath,
wiHasIssueWeightsFeature,
- iid,
wiHasIterationsFeature,
wiHasIssuableHealthStatusFeature,
registerPath,
@@ -32,7 +31,6 @@ export default function initWorkItemLinks() {
},
provide: {
projectPath,
- iid,
fullPath: projectPath,
hasIssueWeightsFeature: wiHasIssueWeightsFeature,
hasIterationsFeature: wiHasIterationsFeature,
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 3a3a846bce5..d119cdc2785 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
@@ -2,8 +2,7 @@
import { GlButton, GlLink, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { __, s__ } from '~/locale';
-import { createAlert } from '~/flash';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { createAlert } from '~/alert';
import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue';
import WorkItemLinkChildMetadata from 'ee_else_ce/work_items/components/work_item_links/work_item_link_child_metadata.vue';
@@ -110,7 +109,9 @@ export default {
return this.isItemOpen ? __('Created') : __('Closed');
},
childPath() {
- return `/${this.projectPath}/-/work_items/${getIdFromGraphQLId(this.childItem.id)}`;
+ return `${gon?.relative_url_root || ''}/${this.projectPath}/-/work_items/${
+ this.childItem.iid
+ }?iid_path=true`;
},
hasChildren() {
return this.getWidgetByType(this.childItem, WIDGET_TYPE_HIERARCHY)?.hasChildren;
@@ -172,7 +173,7 @@ export default {
<template>
<div>
<div
- class="gl-display-flex gl-align-items-flex-start gl-mb-3"
+ class="gl-display-flex gl-align-items-flex-start"
:class="{ 'gl-ml-6': canHaveChildren && !hasChildren && hasIndirectChildren }"
>
<gl-button
@@ -182,18 +183,20 @@ export default {
:aria-label="chevronTooltip"
:icon="chevronType"
category="tertiary"
+ size="small"
:loading="isLoadingChildren"
class="gl-px-0! gl-py-3! gl-mr-3"
data-testid="expand-child"
@click="toggleItem"
/>
<div
- class="gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-bg-white gl-py-3 gl-px-4 gl-border gl-border-gray-100 gl-rounded-base gl-line-height-32"
+ class="work-item-link-child gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-pl-3 gl-pr-2 gl-rounded-base"
+ :class="[hasMetadata ? 'gl-py-3' : 'gl-py-0']"
data-testid="links-child"
>
<span
:id="`stateIcon-${childItem.id}`"
- class="gl-mr-3"
+ class="gl-cursor-help gl-mr-3 gl-line-height-32"
:class="{ 'gl-display-flex': hasMetadata }"
data-testid="item-status-icon"
>
@@ -240,7 +243,7 @@ export default {
<work-item-link-child-metadata
v-if="hasMetadata"
:metadata-widgets="metadataWidgets"
- class="gl-mt-3"
+ class="gl-mt-1"
/>
</div>
<div
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child_metadata.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child_metadata.vue
index 6974804523a..80802cb3858 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child_metadata.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child_metadata.vue
@@ -70,7 +70,7 @@ export default {
<item-milestone
v-if="milestone"
:milestone="milestone"
- class="gl-display-flex gl-align-items-center gl-mr-5 gl-max-w-15 gl-text-secondary! gl-cursor-help! gl-text-decoration-none!"
+ class="gl-display-flex gl-align-items-center gl-mr-5 gl-max-w-15 gl-line-height-normal gl-text-secondary! gl-cursor-help! gl-text-decoration-none!"
/>
<gl-avatars-inline
v-if="assignees.length"
@@ -97,7 +97,7 @@ export default {
:background-color="label.color"
:description="label.description"
:scoped="showScopedLabel(label)"
- class="gl-mt-3 gl-sm-mt-0 gl-mr-2 gl-mb-auto gl-label-sm"
+ class="gl-my-2 gl-mr-2 gl-mb-auto gl-label-sm"
tooltip-placement="top"
/>
</div>
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 e8578a6d49a..8f0e429234f 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
@@ -4,7 +4,7 @@ import { isEmpty } from 'lodash';
import { s__ } from '~/locale';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import { TYPENAME_WORK_ITEM } from '~/graphql_shared/constants';
+import { TYPENAME_ISSUE, TYPENAME_WORK_ITEM } from '~/graphql_shared/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import getIssueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql';
import { isMetaKey, parseBoolean } from '~/lib/utils/common_utils';
@@ -42,7 +42,7 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [glFeatureFlagMixin()],
- inject: ['projectPath', 'iid'],
+ inject: ['projectPath'],
props: {
workItemId: {
type: String,
@@ -63,6 +63,9 @@ export default {
id: this.issuableGid,
};
},
+ context: {
+ isSingleRequest: true,
+ },
skip() {
return !this.issuableId;
},
@@ -86,13 +89,10 @@ export default {
query: getIssueDetailsQuery,
variables() {
return {
- fullPath: this.projectPath,
- iid: String(this.iid),
+ id: convertToGraphQLId(TYPENAME_ISSUE, this.issuableId),
};
},
- update(data) {
- return data.workspace?.issuable;
- },
+ update: (data) => data.issue,
},
},
data() {
@@ -143,7 +143,7 @@ export default {
return this.isLoading && this.children.length === 0 ? '...' : this.children.length;
},
fetchByIid() {
- return this.glFeatures.useIidInWorkItemsPath && parseBoolean(getParameterByName('iid_path'));
+ return parseBoolean(getParameterByName('iid_path'));
},
childUrlParams() {
const params = {};
@@ -304,10 +304,10 @@ export default {
<template #header>{{ $options.i18n.title }}</template>
<template #header-suffix>
<span
- class="gl-display-inline-flex gl-align-items-center gl-line-height-24 gl-ml-3"
+ class="gl-display-inline-flex gl-align-items-center gl-line-height-24 gl-ml-3 gl-font-weight-bold gl-text-gray-500"
data-testid="children-count"
>
- <gl-icon :name="$options.WIDGET_TYPE_TASK_ICON" class="gl-mr-2 gl-text-secondary" />
+ <gl-icon :name="$options.WIDGET_TYPE_TASK_ICON" class="gl-mr-2" />
{{ childrenCountLabel }}
</span>
</template>
@@ -334,11 +334,11 @@ export default {
</gl-dropdown>
</template>
<template #body>
- <gl-loading-icon v-if="isLoading" color="dark" class="gl-my-3" />
+ <gl-loading-icon v-if="isLoading" color="dark" class="gl-my-2" />
<template v-else>
<div v-if="isChildrenEmpty && !isShownAddForm && !error" data-testid="links-empty">
- <p class="gl-mb-3">
+ <p class="gl-px-3 gl-py-2 gl-mb-0 gl-text-gray-500">
{{ $options.i18n.emptyStateMessage }}
</p>
</div>
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 5169a77dd33..af475496075 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
@@ -340,7 +340,7 @@ export default {
<template>
<gl-form
- class="gl-bg-white gl-mb-3 gl-p-4 gl-border gl-border-gray-100 gl-rounded-base"
+ class="gl-bg-white gl-mt-1 gl-mb-3 gl-p-4 gl-border gl-border-gray-100 gl-rounded-base"
@submit.prevent="addOrCreateMethod"
>
<gl-alert v-if="error" variant="danger" class="gl-mb-3" @dismiss="unsetError">
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue
index 1aa4a433a58..fb3ed7af736 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue
@@ -11,8 +11,8 @@ export default {
</script>
<template>
- <span class="gl-ml-2">
- <gl-dropdown category="tertiary" toggle-class="btn-icon" :right="true">
+ <span class="gl-ml-5">
+ <gl-dropdown category="tertiary" toggle-class="btn-icon btn-sm" :right="true">
<template #button-content>
<gl-icon name="ellipsis_v" :size="14" />
</template>
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 aa12df424f1..97eaf2c0422 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
@@ -78,7 +78,7 @@ export default {
},
computed: {
fetchByIid() {
- return this.glFeatures.useIidInWorkItemsPath && parseBoolean(getParameterByName('iid_path'));
+ return parseBoolean(getParameterByName('iid_path'));
},
childrenIds() {
return this.children.map((c) => c.id);
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree_children.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree_children.vue
index 71de6867680..e233a2219fa 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree_children.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree_children.vue
@@ -1,5 +1,5 @@
<script>
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import updateWorkItemMutation from '../../graphql/update_work_item.mutation.graphql';
diff --git a/app/assets/javascripts/work_items/components/work_item_milestone.vue b/app/assets/javascripts/work_items/components/work_item_milestone.vue
index 6ed230b8ad4..e75a429ebec 100644
--- a/app/assets/javascripts/work_items/components/work_item_milestone.vue
+++ b/app/assets/javascripts/work_items/components/work_item_milestone.vue
@@ -234,6 +234,7 @@ export default {
<gl-dropdown
v-else
id="milestone-value"
+ data-testid="work-item-milestone-dropdown"
class="gl-pl-0 gl-max-w-full"
:toggle-class="dropdownClasses"
:text="dropdownText"
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 02b94c5331c..4ca8054fa5f 100644
--- a/app/assets/javascripts/work_items/components/work_item_notes.vue
+++ b/app/assets/javascripts/work_items/components/work_item_notes.vue
@@ -1,21 +1,34 @@
<script>
import { GlSkeletonLoader, GlModal } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
-import { s__, __ } from '~/locale';
+import { __ } from '~/locale';
+import { scrollToTargetOnResize } from '~/lib/utils/resize_observer';
import { TYPENAME_DISCUSSION, TYPENAME_NOTE } from '~/graphql_shared/constants';
import SystemNote from '~/work_items/components/notes/system_note.vue';
-import ActivityFilter from '~/work_items/components/notes/activity_filter.vue';
-import { i18n, DEFAULT_PAGE_SIZE_NOTES } from '~/work_items/constants';
+import WorkItemNotesActivityHeader from '~/work_items/components/notes/work_item_notes_activity_header.vue';
+import {
+ i18n,
+ DEFAULT_PAGE_SIZE_NOTES,
+ WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS,
+ WORK_ITEM_NOTES_FILTER_ONLY_HISTORY,
+} from '~/work_items/constants';
import { ASC, DESC } from '~/notes/constants';
import { getWorkItemNotesQuery } from '~/work_items/utils';
+import {
+ updateCacheAfterCreatingNote,
+ updateCacheAfterDeletingNote,
+} from '~/work_items/graphql/cache_utils';
+import { getLocationHash } from '~/lib/utils/url_utility';
import WorkItemDiscussion from '~/work_items/components/notes/work_item_discussion.vue';
+import WorkItemHistoryOnlyFilterNote from '~/work_items/components/notes/work_item_history_only_filter_note.vue';
+import workItemNoteCreatedSubscription from '~/work_items/graphql/notes/work_item_note_created.subscription.graphql';
+import workItemNoteUpdatedSubscription from '~/work_items/graphql/notes/work_item_note_updated.subscription.graphql';
+import workItemNoteDeletedSubscription from '~/work_items/graphql/notes/work_item_note_deleted.subscription.graphql';
import deleteNoteMutation from '../graphql/notes/delete_work_item_notes.mutation.graphql';
import WorkItemAddNote from './notes/work_item_add_note.vue';
export default {
- i18n: {
- ACTIVITY_LABEL: s__('WorkItem|Activity'),
- },
loader: {
repeat: 10,
width: 1000,
@@ -24,10 +37,11 @@ export default {
components: {
GlSkeletonLoader,
GlModal,
- ActivityFilter,
SystemNote,
WorkItemAddNote,
WorkItemDiscussion,
+ WorkItemNotesActivityHeader,
+ WorkItemHistoryOnlyFilterNote,
},
props: {
workItemId: {
@@ -51,6 +65,11 @@ export default {
required: false,
default: false,
},
+ isModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -58,6 +77,7 @@ export default {
perPage: DEFAULT_PAGE_SIZE_NOTES,
sortOrder: ASC,
noteToDelete: null,
+ discussionFilter: WORK_ITEM_NOTES_FILTER_ALL_NOTES,
};
},
computed: {
@@ -76,7 +96,7 @@ export default {
showLoadingMoreSkeleton() {
return this.isLoadingMore && !this.changeNotesSortOrderAfterLoading;
},
- disableActivityFilter() {
+ disableActivityFilterSort() {
return this.initialLoading || this.isLoadingMore;
},
formAtTop() {
@@ -95,10 +115,30 @@ export default {
notesArray() {
const notes = this.workItemNotes?.nodes || [];
+ const visibleNotes = notes.filter((note) => {
+ const isSystemNote = this.isSystemNote(note);
+
+ if (this.discussionFilter === WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS && isSystemNote) {
+ return false;
+ }
+
+ if (this.discussionFilter === WORK_ITEM_NOTES_FILTER_ONLY_HISTORY && !isSystemNote) {
+ return false;
+ }
+
+ return true;
+ });
+
if (this.sortOrder === DESC) {
- return [...notes].reverse();
+ return [...visibleNotes].reverse();
}
- return notes;
+ return visibleNotes;
+ },
+ commentsDisabled() {
+ return this.discussionFilter === WORK_ITEM_NOTES_FILTER_ONLY_HISTORY;
+ },
+ targetNoteHash() {
+ return getLocationHash();
},
},
apollo: {
@@ -135,8 +175,55 @@ export default {
if (this.hasNextPage) {
this.fetchMoreNotes();
+ } else if (this.targetNoteHash) {
+ if (this.isModal) {
+ this.$emit('has-notes');
+ } else {
+ scrollToTargetOnResize();
+ }
}
},
+ subscribeToMore: [
+ {
+ document: workItemNoteCreatedSubscription,
+ updateQuery(previousResult, { subscriptionData }) {
+ return updateCacheAfterCreatingNote(previousResult, subscriptionData, this.fetchByIid);
+ },
+ variables() {
+ return {
+ noteableId: this.workItemId,
+ };
+ },
+ skip() {
+ return !this.workItemId || this.hasNextPage;
+ },
+ },
+ {
+ document: workItemNoteDeletedSubscription,
+ updateQuery(previousResult, { subscriptionData }) {
+ return updateCacheAfterDeletingNote(previousResult, subscriptionData, this.fetchByIid);
+ },
+ variables() {
+ return {
+ noteableId: this.workItemId,
+ };
+ },
+ skip() {
+ return !this.workItemId || this.hasNextPage;
+ },
+ },
+ {
+ document: workItemNoteUpdatedSubscription,
+ variables() {
+ return {
+ noteableId: this.workItemId,
+ };
+ },
+ skip() {
+ return !this.workItemId;
+ },
+ },
+ ],
},
},
methods: {
@@ -162,6 +249,9 @@ export default {
changeNotesSortOrder(direction) {
this.sortOrder = direction;
},
+ filterDiscussions(filterValue) {
+ this.discussionFilter = filterValue;
+ },
async fetchMoreNotes() {
this.isLoadingMore = true;
// copied from discussions batch logic - every fetchMore call has a higher
@@ -223,17 +313,14 @@ export default {
<template>
<div class="gl-border-t gl-mt-5 work-item-notes">
- <div class="gl-display-flex gl-justify-content-space-between gl-flex-wrap">
- <label class="gl-mb-0">{{ $options.i18n.ACTIVITY_LABEL }}</label>
- <activity-filter
- class="gl-min-h-5 gl-pb-3"
- :loading="disableActivityFilter"
- :sort-order="sortOrder"
- :work-item-type="workItemType"
- @changeSortOrder="changeNotesSortOrder"
- @updateSavedSortOrder="changeNotesSortOrder"
- />
- </div>
+ <work-item-notes-activity-header
+ :sort-order="sortOrder"
+ :disable-activity-filter-sort="disableActivityFilterSort"
+ :work-item-type="workItemType"
+ :discussion-filter="discussionFilter"
+ @changeSort="changeNotesSortOrder"
+ @changeFilter="filterDiscussions"
+ />
<div v-if="initialLoading" class="gl-mt-5">
<gl-skeleton-loader
v-for="index in $options.loader.repeat"
@@ -250,11 +337,10 @@ export default {
<template v-if="!initialLoading">
<ul class="notes main-notes-list timeline gl-clearfix!">
<work-item-add-note
- v-if="formAtTop"
+ v-if="formAtTop && !commentsDisabled"
v-bind="workItemCommentFormProps"
@error="$emit('error', $event)"
/>
-
<template v-for="discussion in notesArray">
<system-note
v-if="isSystemNote(discussion)"
@@ -270,6 +356,7 @@ export default {
:work-item-id="workItemId"
:fetch-by-iid="fetchByIid"
:work-item-type="workItemType"
+ :is-modal="isModal"
@deleteNote="showDeleteNoteModal($event, discussion)"
@error="$emit('error', $event)"
/>
@@ -277,10 +364,15 @@ export default {
</template>
<work-item-add-note
- v-if="!formAtTop"
+ v-if="!formAtTop && !commentsDisabled"
v-bind="workItemCommentFormProps"
@error="$emit('error', $event)"
/>
+
+ <work-item-history-only-filter-note
+ v-if="commentsDisabled"
+ @changeFilter="filterDiscussions"
+ />
</ul>
</template>
diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js
index 81f9bf04bc8..bbcf78e23aa 100644
--- a/app/assets/javascripts/work_items/constants.js
+++ b/app/assets/javascripts/work_items/constants.js
@@ -1,5 +1,6 @@
-import { s__, sprintf } from '~/locale';
+import { __, s__, sprintf } from '~/locale';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import { ASC, DESC } from '~/notes/constants';
export const STATE_OPEN = 'OPEN';
export const STATE_CLOSED = 'CLOSED';
@@ -176,3 +177,31 @@ export const DEFAULT_PAGE_SIZE_ASSIGNEES = 10;
export const DEFAULT_PAGE_SIZE_NOTES = 30;
export const WORK_ITEM_NOTES_SORT_ORDER_KEY = 'sort_direction_work_item';
+
+export const WORK_ITEM_NOTES_FILTER_ALL_NOTES = 'ALL_NOTES';
+export const WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS = 'ONLY_COMMENTS';
+export const WORK_ITEM_NOTES_FILTER_ONLY_HISTORY = 'ONLY_HISTORY';
+
+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,
+ text: s__('WorkItem|All activity'),
+ },
+ {
+ key: WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS,
+ text: s__('WorkItem|Comments only'),
+ testid: 'comments-activity',
+ },
+ {
+ key: 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') },
+];
diff --git a/app/assets/javascripts/work_items/graphql/cache_utils.js b/app/assets/javascripts/work_items/graphql/cache_utils.js
index 16b892b3476..95d68b69745 100644
--- a/app/assets/javascripts/work_items/graphql/cache_utils.js
+++ b/app/assets/javascripts/work_items/graphql/cache_utils.js
@@ -1,62 +1,100 @@
import { produce } from 'immer';
import { WIDGET_TYPE_NOTES } from '~/work_items/constants';
-import { getWorkItemNotesQuery } from '~/work_items/utils';
+
+const isNotesWidget = (widget) => widget.type === WIDGET_TYPE_NOTES;
+
+const getNotesWidgetFromSourceData = (draftData, fetchByIid) => {
+ return fetchByIid
+ ? draftData.workspace.workItems.nodes[0].widgets.find(isNotesWidget)
+ : draftData.workItem.widgets.find(isNotesWidget);
+};
+
+const updateNotesWidgetDataInDraftData = (draftData, notesWidget, fetchByIid) => {
+ const noteWidgetIndex = fetchByIid
+ ? draftData.workspace.workItems.nodes[0].widgets.findIndex(isNotesWidget)
+ : draftData.workItem.widgets.findIndex(isNotesWidget);
+
+ if (fetchByIid) {
+ draftData.workspace.workItems.nodes[0].widgets[noteWidgetIndex] = notesWidget;
+ } else {
+ draftData.workItem.widgets[noteWidgetIndex] = notesWidget;
+ }
+};
/**
- * Updates the cache manually when adding a main comment
+ * Work Item note create subscription update query callback
*
- * @param store
- * @param createNoteData
+ * @param currentNotes
+ * @param subscriptionData
* @param fetchByIid
- * @param queryVariables
- * @param sortOrder
*/
-export const updateCommentState = (store, { data: { createNote } }, fetchByIid, queryVariables) => {
- const notesQuery = getWorkItemNotesQuery(fetchByIid);
- const variables = {
- ...queryVariables,
- pageSize: 100,
- };
- const sourceData = store.readQuery({
- query: notesQuery,
- variables,
+
+export const updateCacheAfterCreatingNote = (currentNotes, subscriptionData, fetchByIid) => {
+ if (!subscriptionData.data?.workItemNoteCreated) {
+ return currentNotes;
+ }
+ const newNote = subscriptionData.data.workItemNoteCreated;
+
+ return produce(currentNotes, (draftData) => {
+ const notesWidget = getNotesWidgetFromSourceData(draftData, fetchByIid);
+
+ if (!notesWidget.discussions) {
+ return;
+ }
+
+ const discussion = notesWidget.discussions.nodes.find((d) => d.id === newNote.discussion.id);
+
+ // handle the case where discussion already exists - we don't need to do anything, update will happen automatically
+ if (discussion) {
+ return;
+ }
+
+ notesWidget.discussions.nodes.push(newNote.discussion);
+ updateNotesWidgetDataInDraftData(draftData, notesWidget, fetchByIid);
});
+};
+
+/**
+ * Work Item note delete subscription update query callback
+ *
+ * @param currentNotes
+ * @param subscriptionData
+ * @param fetchByIid
+ */
- const finalData = produce(sourceData, (draftData) => {
- const notesWidget = fetchByIid
- ? draftData.workspace.workItems.nodes[0].widgets.find(
- (widget) => widget.type === WIDGET_TYPE_NOTES,
- )
- : draftData.workItem.widgets.find((widget) => widget.type === WIDGET_TYPE_NOTES);
-
- // as notes are currently sorted/reversed on the frontend rather than in the query
- // we only ever push.
- // const arrayPushMethod = sortOrder === ASC ? 'push' : 'unshift';
- const arrayPushMethod = 'push';
-
- // manual update of cache with a completely new discussion
- if (createNote.note.discussion.notes.nodes.length === 1) {
- notesWidget.discussions.nodes[arrayPushMethod]({
- id: createNote.note.discussion.id,
- notes: {
- nodes: createNote.note.discussion.notes.nodes,
- __typename: 'NoteConnection',
- },
- // eslint-disable-next-line @gitlab/require-i18n-strings
- __typename: 'Discussion',
- });
+export const updateCacheAfterDeletingNote = (currentNotes, subscriptionData, fetchByIid) => {
+ if (!subscriptionData.data?.workItemNoteDeleted) {
+ return currentNotes;
+ }
+ const deletedNote = subscriptionData.data.workItemNoteDeleted;
+ const { id, discussionId, lastDiscussionNote } = deletedNote;
+
+ return produce(currentNotes, (draftData) => {
+ const notesWidget = getNotesWidgetFromSourceData(draftData, fetchByIid);
+
+ if (!notesWidget.discussions) {
+ return;
+ }
+
+ const discussionIndex = notesWidget.discussions.nodes.findIndex(
+ (discussion) => discussion.id === discussionId,
+ );
+
+ if (discussionIndex === -1) {
+ return;
}
- if (fetchByIid) {
- draftData.workspace.workItems.nodes[0].widgets[6] = notesWidget;
+ if (lastDiscussionNote) {
+ notesWidget.discussions.nodes.splice(discussionIndex, 1);
} else {
- draftData.workItem.widgets[6] = notesWidget;
+ const deletedThreadDiscussion = notesWidget.discussions.nodes[discussionIndex];
+ const deletedThreadIndex = deletedThreadDiscussion.notes.nodes.findIndex(
+ (note) => note.id === id,
+ );
+ deletedThreadDiscussion.notes.nodes.splice(deletedThreadIndex, 1);
+ notesWidget.discussions.nodes[discussionIndex] = deletedThreadDiscussion;
}
- });
- store.writeQuery({
- query: notesQuery,
- variables,
- data: finalData,
+ updateNotesWidgetDataInDraftData(draftData, notesWidget, fetchByIid);
});
};
diff --git a/app/assets/javascripts/work_items/graphql/get_issue_details.query.graphql b/app/assets/javascripts/work_items/graphql/get_issue_details.query.graphql
index daeb58c0947..43dbe8fc2dd 100644
--- a/app/assets/javascripts/work_items/graphql/get_issue_details.query.graphql
+++ b/app/assets/javascripts/work_items/graphql/get_issue_details.query.graphql
@@ -1,12 +1,9 @@
-query issuableDetails($fullPath: ID!, $iid: String) {
- workspace: project(fullPath: $fullPath) {
+query issuableDetails($id: IssueID!) {
+ issue(id: $id) {
id
- issuable: issue(iid: $iid) {
+ confidential
+ milestone {
id
- confidential
- milestone {
- id
- }
}
}
}
diff --git a/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql b/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
index 52a7a1f8e23..93616c39e55 100644
--- a/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
+++ b/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
@@ -9,6 +9,7 @@ fragment WorkItemNote on Note {
systemNoteIconName
createdAt
lastEditedAt
+ url
lastEditedBy {
...User
webPath
diff --git a/app/assets/javascripts/work_items/graphql/notes/work_item_note_add_award_emoji.mutation.graphql b/app/assets/javascripts/work_items/graphql/notes/work_item_note_add_award_emoji.mutation.graphql
new file mode 100644
index 00000000000..dc51c53428b
--- /dev/null
+++ b/app/assets/javascripts/work_items/graphql/notes/work_item_note_add_award_emoji.mutation.graphql
@@ -0,0 +1,17 @@
+#import "~/graphql_shared/fragments/user.fragment.graphql"
+
+mutation workItemNoteAddAwardEmoji($awardableId: AwardableID!, $name: String!) {
+ awardEmojiAdd(input: { awardableId: $awardableId, name: $name }) {
+ awardEmoji {
+ name
+ description
+ unicode
+ emoji
+ unicodeVersion
+ user {
+ ...User
+ }
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql b/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql
index 7d7bb9c7fc5..b9d4bb29bbf 100644
--- a/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql
+++ b/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql
@@ -1,40 +1,7 @@
+#import "./work_item.fragment.graphql"
+
query workItemLinksQuery($id: WorkItemID!) {
workItem(id: $id) {
- id
- workItemType {
- id
- name
- }
- title
- userPermissions {
- deleteWorkItem
- updateWorkItem
- }
- confidential
- widgets {
- type
- ... on WorkItemWidgetHierarchy {
- type
- parent {
- id
- }
- children {
- nodes {
- id
- iid
- confidential
- workItemType {
- id
- name
- iconName
- }
- title
- state
- createdAt
- closedAt
- }
- }
- }
- }
+ ...WorkItem
}
}
diff --git a/app/assets/javascripts/work_items/index.js b/app/assets/javascripts/work_items/index.js
index 6aa63aae172..95709b36594 100644
--- a/app/assets/javascripts/work_items/index.js
+++ b/app/assets/javascripts/work_items/index.js
@@ -18,6 +18,7 @@ export const initWorkItemsRoot = () => {
hasIterationsFeature,
hasOkrsFeature,
hasIssuableHealthStatusFeature,
+ savedRepliesNewPath,
} = el.dataset;
return new Vue({
@@ -35,6 +36,7 @@ export const initWorkItemsRoot = () => {
signInPath,
hasIterationsFeature: parseBoolean(hasIterationsFeature),
hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature),
+ newSavedRepliesPath: savedRepliesNewPath,
},
render(createElement) {
return createElement(App);
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 2245f984174..ed0163ced3c 100644
--- a/app/assets/javascripts/work_items/pages/create_work_item.vue
+++ b/app/assets/javascripts/work_items/pages/create_work_item.vue
@@ -74,7 +74,7 @@ export default {
return sprintfWorkItem(I18N_WORK_ITEM_ERROR_CREATING, workItemType);
},
fetchByIid() {
- return this.glFeatures.useIidInWorkItemsPath;
+ return true;
},
},
methods: {
diff --git a/app/assets/javascripts/work_items/router/index.js b/app/assets/javascripts/work_items/router/index.js
index 777badeb5be..8d67bcaf84f 100644
--- a/app/assets/javascripts/work_items/router/index.js
+++ b/app/assets/javascripts/work_items/router/index.js
@@ -11,6 +11,6 @@ export function createRouter(fullPath) {
return new VueRouter({
routes: routes(),
mode: 'history',
- base: joinPaths(fullPath, '-', 'work_items'),
+ base: joinPaths(gon?.relative_url_root, fullPath, '-', 'work_items'),
});
}
diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js
index 134c2858849..1aa3baca165 100644
--- a/app/assets/javascripts/zen_mode.js
+++ b/app/assets/javascripts/zen_mode.js
@@ -5,6 +5,7 @@
/*= provides zen_mode:enter */
/*= provides zen_mode:leave */
+import autosize from 'autosize';
import Dropzone from 'dropzone';
import $ from 'jquery';
import Mousetrap from 'mousetrap';
@@ -39,6 +40,7 @@ export default class ZenMode {
constructor() {
this.active_backdrop = null;
this.active_textarea = null;
+ this.storedStyle = null;
$(document).on('click', '.js-zen-enter', (e) => {
e.preventDefault();
return $(e.currentTarget).trigger('zen_mode:enter');
@@ -68,6 +70,7 @@ export default class ZenMode {
this.active_backdrop.addClass('fullscreen');
this.active_textarea = this.active_backdrop.find('textarea');
// Prevent a user-resized textarea from persisting to fullscreen
+ this.storedStyle = this.active_textarea.attr('style');
this.active_textarea.removeAttr('style');
this.active_textarea.focus();
}
@@ -77,6 +80,11 @@ export default class ZenMode {
Mousetrap.unpause();
this.active_textarea.closest('.zen-backdrop').removeClass('fullscreen');
scrollToElement(this.active_textarea, { duration: 0, offset: -100 });
+ this.active_textarea.attr('style', this.storedStyle);
+
+ autosize(this.active_textarea);
+ autosize.update(this.active_textarea);
+
this.active_textarea = null;
this.active_backdrop = null;
diff --git a/app/assets/stylesheets/_page_specific_files.scss b/app/assets/stylesheets/_page_specific_files.scss
index fa5d2bf7972..1a998f89c68 100644
--- a/app/assets/stylesheets/_page_specific_files.scss
+++ b/app/assets/stylesheets/_page_specific_files.scss
@@ -7,7 +7,6 @@
@import './pages/issues';
@import './pages/labels';
@import './pages/login';
-@import './pages/ml_experiment_tracking';
@import './pages/merge_requests';
@import './pages/note_form';
@import './pages/notes';
diff --git a/app/assets/stylesheets/components/content_editor.scss b/app/assets/stylesheets/components/content_editor.scss
index 44b06c0ff12..3381de52120 100644
--- a/app/assets/stylesheets/components/content_editor.scss
+++ b/app/assets/stylesheets/components/content_editor.scss
@@ -1,4 +1,5 @@
.ProseMirror {
+ min-height: 128px;
max-height: 55vh;
overflow-y: auto;
diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss
index 293caf6fc87..0b30b4c3ef0 100644
--- a/app/assets/stylesheets/components/related_items_list.scss
+++ b/app/assets/stylesheets/components/related_items_list.scss
@@ -6,6 +6,8 @@ $item-remove-button-space: 42px;
.related-items-list {
padding: $gl-padding-4;
padding-right: $gl-padding-6;
+ border-bottom-left-radius: $gl-border-size-3;
+ border-bottom-right-radius: $gl-border-size-3;
&,
.list-item:last-child {
@@ -33,6 +35,14 @@ $item-remove-button-space: 42px;
.item-body {
position: relative;
line-height: $gl-line-height;
+ border: 1px solid transparent;
+ border-radius: $gl-border-radius-base;
+
+ &:hover,
+ &:focus-within {
+ background-color: $white;
+ border-color: $gray-50;
+ }
.merge-request-status.closed {
color: $red-500;
@@ -61,6 +71,7 @@ $item-remove-button-space: 42px;
.sortable-link {
color: $gray-900;
+ font-weight: 500;
}
}
@@ -87,16 +98,6 @@ $item-remove-button-space: 42px;
}
}
- .item-attributes-area {
- > * {
- margin-left: 8px;
- }
-
- @include media-breakpoint-down(sm) {
- margin-left: -8px;
- }
- }
-
.item-milestone,
.item-weight {
cursor: help;
@@ -147,7 +148,7 @@ $item-remove-button-space: 42px;
}
.item-path-id {
- font-size: $gl-font-size-xs;
+ font-size: $gl-font-size-small;
white-space: nowrap;
.path-id-text {
@@ -156,34 +157,15 @@ $item-remove-button-space: 42px;
}
}
-.btn-item-remove {
- position: absolute;
- top: $gl-padding-4 / 2;
- right: 0;
- padding: $gl-padding-4;
- margin-right: $gl-padding-4 / 2;
+.mr-ci-status {
line-height: 0;
- border-color: transparent;
- background-color: transparent;
- color: $gl-text-color-secondary;
-
- .related-items-tree & {
- position: relative;
- top: initial;
- padding: $btn-sm-side-margin;
- margin-right: initial;
- }
- &:hover {
- color: $gl-text-color;
- border-color: $border-color;
+ a:focus {
+ @include gl-rounded-full;
+ @include gl-focus;
}
}
-.mr-ci-status {
- line-height: 0;
-}
-
@include media-breakpoint-down(xs) {
.btn-sm.dropdown-toggle-split {
max-width: 40px;
@@ -191,10 +173,6 @@ $item-remove-button-space: 42px;
}
@include media-breakpoint-up(sm) {
- .item-info-area {
- flex-basis: 100%;
- }
-
.sortable-link {
max-width: 90%;
}
@@ -265,18 +243,7 @@ $item-remove-button-space: 42px;
}
}
- .btn-item-remove {
- position: relative;
- top: initial;
- padding: $btn-sm-side-margin;
- margin-right: $gl-padding-4 / 2;
- }
-
.sortable-link {
line-height: 1.3;
}
-
- .item-info-area {
- flex-basis: auto;
- }
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 5fa1923af7c..8059164782f 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -261,7 +261,6 @@
.btn-block {
width: 100%;
margin: 0;
- @include gl-mb-5;
&.btn {
padding: 6px 0;
diff --git a/app/assets/stylesheets/framework/diffs.scss b/app/assets/stylesheets/framework/diffs.scss
index 4eb26d533c2..cd0ea84cff4 100644
--- a/app/assets/stylesheets/framework/diffs.scss
+++ b/app/assets/stylesheets/framework/diffs.scss
@@ -944,6 +944,19 @@ table.code {
}
}
+// Remove border from collapsed replies widget only on diffs
+.diff-grid-comments {
+ .replies-widget-collapsed {
+ border-bottom: 0;
+ }
+ // Rounded border radius only on diff comments with no replies
+ .discussion-collapsible {
+ .discussion-reply-holder:first-of-type {
+ border-radius: $gl-border-radius-base;
+ }
+ }
+}
+
.discussion-body .image .frame {
position: relative;
}
@@ -999,7 +1012,7 @@ table.code {
}
// Note: Prevents tall files from appearing above sticky tabs
-.diffs .vue-recycle-scroller__item-view > div:not(.active) {
+.diff-files-holder .vue-recycle-scroller__item-view > div:not(.active) {
position: absolute;
bottom: 100vh;
}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index ebb9466eb15..5fa7fbdef99 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -96,7 +96,7 @@
color: $gl-text-color;
font-size: 14px;
text-align: left;
- border: 1px solid $border-color;
+ border: 1px solid $gray-200;
border-radius: $border-radius-base;
white-space: nowrap;
@@ -143,11 +143,24 @@
.dropdown-menu-toggle.dropdown-menu-toggle {
justify-content: flex-start;
overflow: hidden;
+ padding-top: #{$gl-padding-8 - 1};
+ padding-bottom: #{$gl-padding-8 - 1};
padding-right: 25px;
position: relative;
text-overflow: ellipsis;
+ line-height: $gl-line-height;
width: 160px;
+ &:hover {
+ @include gl-inset-border-1-gray-400;
+ }
+
+ &:hover,
+ &:focus {
+ background-color: $gray-50;
+ border-color: $gray-400;
+ }
+
.gl-spinner {
position: absolute;
top: 9px;
@@ -157,7 +170,7 @@
.dropdown-menu-toggle-icon {
position: absolute;
right: $gl-padding-8;
- color: $gray-darkest;
+ color: $gray-500;
}
}
@@ -984,17 +997,6 @@
.label-item {
padding: 8px 20px;
}
-
- .color-input-container {
- .dropdown-label-color-preview {
- border: 1px solid $gray-100;
- border-right: 0;
-
- &[style] {
- border-color: transparent;
- }
- }
- }
}
.bulk-update {
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 9ea5a66b3bc..b292adf9eac 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -580,3 +580,31 @@ span.idiff {
padding: 0;
border-radius: 0 0 $border-radius-default $border-radius-default;
}
+
+.blame-stream-container {
+ border-top: 1px solid $border-color;
+}
+
+.blame-stream-loading {
+ $gradient-size: 16px;
+ position: sticky;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-top: -$gradient-size;
+ height: $gl-spacing-scale-10;
+ border-top: $gradient-size solid transparent;
+ background-color: $white;
+ box-sizing: content-box;
+ background-clip: content-box;
+
+ .gradient {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: -$gradient-size;
+ height: $gradient-size;
+ background: linear-gradient(to top, $white, transparentize($white, 1));
+ }
+}
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index b35175f4ef6..16c0a67f137 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -197,7 +197,7 @@
min-width: 0;
border: 1px solid $border-color;
background-color: $white;
- border-radius: $border-radius-default 0 0 $border-radius-default;
+ border-radius: $border-radius-default;
@include media-breakpoint-down(sm) {
flex: 1 1 auto;
@@ -227,7 +227,7 @@
min-width: 200px;
padding-right: 25px;
padding-left: 0;
- height: $input-height - 2;
+ height: $input-height;
line-height: inherit;
&,
@@ -263,6 +263,7 @@
min-width: 0;
height: 2rem;
background-color: $input-bg;
+ border-radius: $border-radius-default;
}
.filtered-search-input-dropdown-menu {
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index c0fe8ca6f76..3e1dff18f2a 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -148,7 +148,10 @@ label {
width: $input-short-md-width;
}
}
+}
+.form-control,
+[contenteditable=true] {
&:focus {
border-color: $gray-400;
@include gl-focus;
@@ -156,6 +159,7 @@ label {
}
.select-control {
+ line-height: 1.3;
padding-left: 10px;
padding-right: 10px;
appearance: none;
@@ -208,7 +212,7 @@ label {
.gl-show-field-errors {
.form-control:not(textarea) {
- height: 34px;
+ height: $input-height;
}
.gl-field-success-outline {
@@ -246,7 +250,7 @@ label {
.show-password-complexity-errors {
.form-control:not(textarea) {
- height: 34px;
+ height: $input-height;
}
.password-complexity-error-outline {
@@ -286,3 +290,22 @@ label {
.input-group-text {
max-height: $input-height;
}
+
+.add-issuable-form-input-wrapper {
+ &.focus {
+ border-color: var(--gray-700, $gray-700);
+
+ input {
+ @include gl-shadow-none;
+ }
+ }
+
+ .gl-show-field-errors &.form-control:not(textarea) {
+ height: auto;
+ }
+}
+
+.add-issuable-form-input-wrapper.focus,
+.issue-token-remove-button:focus {
+ @include gl-focus;
+}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 7baf84198e4..d1231da83d4 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -321,11 +321,9 @@ $search-input-field-x-min-width: 200px;
.breadcrumbs-container {
display: flex;
width: 100%;
- position: relative;
padding-top: $gl-padding / 2;
padding-bottom: $gl-padding / 2;
align-items: center;
- border-bottom: 1px solid $border-color;
}
.breadcrumbs-links {
@@ -375,14 +373,11 @@ $search-input-field-x-min-width: 200px;
display: flex;
align-items: center;
position: relative;
+ min-width: 0;
padding: 2px 0;
&:not(:last-child) {
padding-right: 20px;
-
- &:not(.dropdown) {
- overflow: hidden;
- }
}
&:last-child {
@@ -558,25 +553,16 @@ $search-input-field-x-min-width: 200px;
}
.toggle-mobile-nav {
- display: none;
- background-color: transparent;
- border: 0;
- padding: 6px 16px;
- margin: 0 0 0 -15px;
- height: 46px;
- color: $gl-text-color;
+ @include gl-display-none;
@include media-breakpoint-down(sm) {
- display: flex;
- align-items: center;
-
- i {
- font-size: 18px;
- }
+ @include gl-display-block;
+ .breadcrumbs-links {
- padding-left: $gl-padding;
- border-left: 1px solid $gl-text-color-quaternary;
+ @include gl-pl-4;
+ @include gl-border-l-1;
+ @include gl-border-l-solid;
+ @include gl-border-gray-100;
}
}
}
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index c5e50299e6d..b20ec1dc50a 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -223,6 +223,18 @@
}
/*
+* Mixin that handles the position of sticky alerts at the top. It accounts for the performance bar
+*/
+// stylelint-disable-next-line length-zero-no-unit
+@mixin sticky-top-positioning($extra: 0px) {
+ top: calc(#{$header-height} + #{$extra});
+
+ .with-performance-bar & {
+ top: calc(#{$header-height} + #{$performance-bar-height} + #{$extra});
+ }
+}
+
+/*
* Mixin that handles the container for the job logs (CI/CD and kubernetes pod logs)
*/
@mixin build-log($background: $black) {
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
index c9b17f5d5c4..f76a9cf0373 100644
--- a/app/assets/stylesheets/framework/modal.scss
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -45,7 +45,7 @@
margin: #{2 * $grid-size} #{-2 * $grid-size} #{-2 * $grid-size};
}
- .text-danger {
+ .text-danger:not(.dropdown-item) {
font-weight: $gl-font-weight-bold;
}
}
diff --git a/app/assets/stylesheets/framework/page_title.scss b/app/assets/stylesheets/framework/page_title.scss
index 5ed5b1e1445..f11864f14af 100644
--- a/app/assets/stylesheets/framework/page_title.scss
+++ b/app/assets/stylesheets/framework/page_title.scss
@@ -1,6 +1,4 @@
.page-title-holder {
- border-bottom: 1px solid $border-color;
-
.page-title {
margin: $gl-padding 0;
color: $gl-text-color;
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index a07a57f40f7..7c3e346f4e6 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -140,6 +140,11 @@
.issuable-sidebar {
padding: 0 3px;
}
+
+ .block {
+ border-bottom: 0;
+ padding-top: 0;
+ }
}
.issuable-sidebar .labels {
@@ -786,7 +791,7 @@
.participants-author {
&:nth-of-type(8n) {
- padding-right: 0;
+ margin-right: 0;
}
.avatar.avatar-inline {
diff --git a/app/assets/stylesheets/framework/super_sidebar.scss b/app/assets/stylesheets/framework/super_sidebar.scss
index 4b55b39d6f3..6b339f857cb 100644
--- a/app/assets/stylesheets/framework/super_sidebar.scss
+++ b/app/assets/stylesheets/framework/super_sidebar.scss
@@ -1,7 +1,56 @@
+@mixin active-toggle {
+ background-color: $gray-50 !important;
+ mix-blend-mode: multiply;
+
+ .gl-dark & {
+ mix-blend-mode: screen;
+ }
+
+ .notification {
+ border-color: $gray-50;
+ }
+}
+
+@mixin notification-dot($color, $size, $top, $left) {
+ background-color: $color;
+ border: 2px solid $gray-10; // Same as the sidebar's background color.
+ position: absolute;
+ height: $size;
+ width: $size;
+ top: $top;
+ left: $left;
+ border-radius: 50%;
+ transition: background-color 100ms linear, border-color 100ms linear;
+}
+
.super-sidebar {
+ display: flex;
+ flex-direction: column;
+ position: fixed;
top: 0;
- width: $contextual-sidebar-width;
- z-index: 600;
+ bottom: 0;
+ left: 0;
+ background-color: var(--gray-10, $gray-10);
+ border-right: 1px solid $t-gray-a-08;
+ transform: translate3d(0, 0, 0);
+ width: $super-sidebar-width;
+ z-index: $super-sidebar-z-index;
+
+ &:focus {
+ @include gl-focus;
+ }
+
+ &.super-sidebar-loading {
+ transform: translate3d(-100%, 0, 0);
+
+ @include media-breakpoint-up(xl) {
+ transform: translate3d(0, 0, 0);
+ }
+ }
+
+ &:not(.super-sidebar-loading) {
+ transition: transform $gl-transition-duration-medium;
+ }
.user-bar {
background-color: $t-gray-a-04;
@@ -9,6 +58,24 @@
.tanuki-logo {
@include gl-vertical-align-middle;
}
+
+ .user-bar-item {
+ @include gl-rounded-base;
+ @include gl-p-2;
+ @include gl-bg-transparent;
+ @include gl-border-none;
+
+ &:hover,
+ &:focus,
+ &:active {
+ @include active-toggle;
+ }
+
+ &:focus,
+ &:active {
+ @include gl-focus;
+ }
+ }
}
.counter .gl-icon {
@@ -17,18 +84,25 @@
.counter:hover,
.counter:focus,
- .gl-dropdown-custom-toggle:hover .counter,
- .gl-dropdown-custom-toggle:focus .counter,
- .gl-dropdown-custom-toggle[aria-expanded='true'] .counter {
+ .counter[aria-expanded='true'] {
background-color: $gray-50;
border-color: transparent;
+ box-shadow: none;
mix-blend-mode: multiply;
+ .gl-dark & {
+ mix-blend-mode: screen;
+ }
+
.gl-icon {
color: var(--gray-700, $gray-700);
}
}
+ .context-switcher-search-box input {
+ @include gl-font-sm;
+ }
+
.context-switcher-toggle {
&[aria-expanded='true'] {
background-color: $t-gray-a-08;
@@ -36,19 +110,14 @@
}
.btn-with-notification {
- mix-blend-mode: unset !important; // Our tertiary buttons otherwise use another mix-blend mode, making border-color semi-transparent.
position: relative;
- .notification {
- background-color: $blue-500;
- border: 2px solid $gray-10; // Same as the sidebar's background color.
- position: absolute;
- height: 9px;
- width: 9px;
- top: 5px;
- left: 22px;
- border-radius: 50%;
- transition: background-color 100ms linear, border-color 100ms linear;
+ .notification-dot-info {
+ @include notification-dot($blue-500, 9px, 5px, 22px);
+ }
+
+ .notification-dot-warning {
+ @include notification-dot($orange-300, 12px, 1px, 19px);
}
&:hover,
@@ -58,8 +127,93 @@
}
}
}
+
+ .gl-new-dropdown-toggle[aria-expanded='true'] {
+ @include active-toggle;
+ }
+
+ .gl-new-dropdown-custom-toggle {
+ .btn-with-notification {
+ mix-blend-mode: unset; // Our tertiary buttons otherwise use another mix-blend mode, making border-color semi-transparent.
+ }
+
+ [aria-expanded='true'] {
+ @include active-toggle;
+ }
+ }
+}
+
+.super-sidebar-skip-to {
+ z-index: $super-sidebar-z-index;
+}
+
+.super-sidebar-overlay {
+ display: none;
+}
+
+.page-with-super-sidebar {
+ padding-left: 0;
+ transition: padding-left $gl-transition-duration-medium;
+
+ &:not(.page-with-super-sidebar-collapsed) {
+ .super-sidebar-overlay {
+ display: block;
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: $black-transparent;
+ z-index: $super-sidebar-z-index - 1;
+
+ @include media-breakpoint-up(md) {
+ display: none;
+ }
+ }
+ }
+
+ @include media-breakpoint-up(xl) {
+ padding-left: $super-sidebar-width;
+
+ .super-sidebar-toggle {
+ display: none;
+ }
+ }
+}
+
+.page-with-super-sidebar-collapsed {
+ .super-sidebar {
+ transform: translate3d(-100%, 0, 0);
+ }
+
+ @include media-breakpoint-up(xl) {
+ padding-left: 0;
+
+ .super-sidebar-toggle {
+ display: block;
+ }
+ }
+}
+
+.container-limited .super-sidebar-toggle {
+ @media (min-width: $super-sidebar-toggle-position-breakpoint) {
+ position: absolute;
+ left: $gl-spacing-scale-3;
+ top: $gl-spacing-scale-3;
+ margin: 0;
+ }
}
.with-performance-bar .super-sidebar {
top: $performance-bar-height;
}
+
+.gl-dark {
+ .super-sidebar {
+ .gl-new-dropdown-custom-toggle {
+ .btn-with-notification.btn-with-notification {
+ mix-blend-mode: unset;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/framework/system_messages.scss b/app/assets/stylesheets/framework/system_messages.scss
index 89585fd96ae..590a66ff28e 100644
--- a/app/assets/stylesheets/framework/system_messages.scss
+++ b/app/assets/stylesheets/framework/system_messages.scss
@@ -48,6 +48,7 @@
// left sidebar eg: project page
// right sidebar eg: MR page
.nav-sidebar,
+ .super-sidebar,
.right-sidebar {
top: calc(#{$system-header-height} + #{$header-height});
}
@@ -72,6 +73,7 @@
// left sidebar eg: project page
// right sidebar eg: MR page
.nav-sidebar,
+ .super-sidebar,
.right-sidebar {
top: calc(#{$header-height} + #{$performance-bar-height} + #{$system-header-height});
}
@@ -83,6 +85,7 @@
// left sidebar eg: project page
// right sidebar eg: mr page
.nav-sidebar,
+ .super-sidebar,
.right-sidebar,
// navless pages' footer eg: login page
// navless pages' footer border eg: login page
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index 8b2a494527b..a288701595e 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -41,7 +41,7 @@ table {
}
th {
- @include gl-bg-gray-50;
+ @include gl-bg-gray-10;
border-bottom: 0;
&.wide {
diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss
index 32e9bba8712..699693bd354 100644
--- a/app/assets/stylesheets/framework/timeline.scss
+++ b/app/assets/stylesheets/framework/timeline.scss
@@ -31,6 +31,7 @@
&:not(.note-form).internal-note .timeline-content,
&:not(.note-form).draft-note .timeline-content {
background-color: $orange-50 !important;
+ border-radius: 3px;
}
.timeline-entry-inner {
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 9b5897b7df9..8edf5fc834a 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -494,6 +494,7 @@
outline: none;
&::after {
+ @include gl-dark-invert-keep-hue;
content: image-url('icon_anchor.svg');
visibility: hidden;
}
@@ -631,7 +632,7 @@ body {
}
.page-title {
- margin: #{2 * $grid-size} 0;
+ margin: 0 0 #{2 * $grid-size};
line-height: 1.3;
&.with-button {
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index c616915073e..0bc2e0583bb 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -10,6 +10,10 @@ $default-transition-duration: 0.15s;
$contextual-sidebar-width: 256px;
$contextual-sidebar-collapsed-width: 56px;
$toggle-sidebar-height: 48px;
+$super-sidebar-width: 256px;
+$super-sidebar-toggle-position-breakpoint: 1360px;
+$super-sidebar-z-index: 600;
+$super-sidebar-overlay-z-index: 599;
/**
🚨 Do not use this spacing scale — it is deprecated and being removed. 🚨
@@ -741,7 +745,7 @@ $logs-p-color: #333;
/*
* Forms
*/
-$input-height: 34px;
+$input-height: 32px;
$input-danger-bg: #f2dede;
$input-group-addon-bg: $gray-10;
$gl-field-focus-shadow: rgba(0, 0, 0, 0.075);
@@ -906,6 +910,11 @@ Compare Branches
*/
$compare-branches-sticky-header-height: 68px;
+/*
+Board Swimlanes
+*/
+$board-swimlanes-headers-height: 64px;
+
/**
Bootstrap 4.2.0 introduced new icons for validating forms.
Our design system does not use those, so we are disabling them for now:
diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss
index cb9c623c8fc..1434c16b68f 100644
--- a/app/assets/stylesheets/framework/wells.scss
+++ b/app/assets/stylesheets/framework/wells.scss
@@ -1,7 +1,7 @@
.info-well {
- background: $gray-light;
+ background: $gray-10;
color: $gl-text-color;
- border: 1px solid $border-color;
+ border: 1px solid $gray-100;
border-radius: $border-radius-default;
.card.card-body-segment {
diff --git a/app/assets/stylesheets/highlight/diff_custom_colors_addition.scss b/app/assets/stylesheets/highlight/diff_custom_colors_addition.scss
index 30895a55711..5f195bc47bf 100644
--- a/app/assets/stylesheets/highlight/diff_custom_colors_addition.scss
+++ b/app/assets/stylesheets/highlight/diff_custom_colors_addition.scss
@@ -25,7 +25,7 @@
}
}
- .gd {
+ .gi {
background-color: var(--diff-addition-color);
}
}
diff --git a/app/assets/stylesheets/page_bundles/admin/geo_nodes.scss b/app/assets/stylesheets/page_bundles/admin/geo_nodes.scss
deleted file mode 100644
index b0aaa48569a..00000000000
--- a/app/assets/stylesheets/page_bundles/admin/geo_nodes.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-@import '../mixins_and_variables_and_functions';
-
-.geo-node-header-grid-columns {
- grid-template-columns: 1fr auto;
- grid-gap: $gl-spacing-scale-5;
-
- @include media-breakpoint-up(md) {
- grid-template-columns: 3fr 1fr;
- }
-}
-
-.geo-node-details-grid-columns {
- grid-gap: $gl-spacing-scale-5;
-
- @include media-breakpoint-up(lg) {
- grid-template-columns: 1fr 3fr;
- }
-}
-
-.geo-node-core-details-grid-columns {
- grid-template-columns: 1fr 1fr;
- grid-gap: $gl-spacing-scale-5;
-}
-
-.geo-node-replication-details-grid-columns {
- grid-template-columns: 1fr 1fr;
- grid-gap: 1rem;
-
- @include media-breakpoint-up(md) {
- grid-template-columns: 1fr 1fr 2fr 2fr;
- }
-}
-
-.geo-node-filter-grid-columns {
- grid-template-columns: 1fr;
-
- @include media-breakpoint-up(md) {
- grid-template-columns: 3fr 1fr;
- }
-}
-
-.geo-node-replication-counts-grid {
- grid-template-columns: 2fr 1fr 1fr;
- grid-gap: 1rem;
-}
diff --git a/app/assets/stylesheets/page_bundles/admin/geo_sites.scss b/app/assets/stylesheets/page_bundles/admin/geo_sites.scss
new file mode 100644
index 00000000000..37bc2394d58
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/admin/geo_sites.scss
@@ -0,0 +1,45 @@
+@import '../mixins_and_variables_and_functions';
+
+.geo-site-header-grid-columns {
+ grid-template-columns: 1fr auto;
+ grid-gap: $gl-spacing-scale-5;
+
+ @include media-breakpoint-up(md) {
+ grid-template-columns: 3fr 1fr;
+ }
+}
+
+.geo-site-details-grid-columns {
+ grid-gap: $gl-spacing-scale-5;
+
+ @include media-breakpoint-up(lg) {
+ grid-template-columns: 1fr 3fr;
+ }
+}
+
+.geo-site-core-details-grid-columns {
+ grid-template-columns: 1fr 1fr;
+ grid-gap: $gl-spacing-scale-5;
+}
+
+.geo-site-replication-details-grid-columns {
+ grid-template-columns: 1fr 1fr;
+ grid-gap: 1rem;
+
+ @include media-breakpoint-up(md) {
+ grid-template-columns: 1fr 1fr 2fr 2fr;
+ }
+}
+
+.geo-site-filter-grid-columns {
+ grid-template-columns: 1fr;
+
+ @include media-breakpoint-up(md) {
+ grid-template-columns: 3fr 1fr;
+ }
+}
+
+.geo-site-replication-counts-grid {
+ grid-template-columns: 2fr 1fr 1fr;
+ grid-gap: 1rem;
+}
diff --git a/app/assets/stylesheets/page_bundles/incidents.scss b/app/assets/stylesheets/page_bundles/incidents.scss
index 493add1ea0f..fde35ab3d39 100644
--- a/app/assets/stylesheets/page_bundles/incidents.scss
+++ b/app/assets/stylesheets/page_bundles/incidents.scss
@@ -57,8 +57,6 @@
}
.timeline-entry:not(:last-child) {
- @include gl-pb-0;
-
.timeline-event-border {
@include gl-pb-3;
@include gl-border-gray-50;
diff --git a/app/assets/stylesheets/page_bundles/issuable.scss b/app/assets/stylesheets/page_bundles/issuable.scss
index f364170c99f..79595fa3a98 100644
--- a/app/assets/stylesheets/page_bundles/issuable.scss
+++ b/app/assets/stylesheets/page_bundles/issuable.scss
@@ -81,8 +81,6 @@
}
.detail-page-description {
- padding: 16px 0;
-
small {
color: var(--gray-500, $gray-500);
}
@@ -92,10 +90,11 @@
color: var(--gray-500, $gray-500);
display: block;
margin: 16px 0 0;
- font-size: 85%;
+ font-size: $gl-font-size-small;
.author-link {
- color: var(--gray-500, $gray-500);
+ color: var(--gray-700, $gray-700);
+ font-size: $gl-font-size-small;
}
}
@@ -138,21 +137,6 @@
}
}
-.add-issuable-form-input-wrapper {
- &.focus {
- border-color: var(--gray-700, $gray-700);
- @include gl-focus;
-
- input {
- @include gl-shadow-none;
- }
- }
-
- .gl-show-field-errors &.form-control:not(textarea) {
- height: auto;
- }
-}
-
/*
* Following overrides are done to prevent
* legacy dropdown styles from influencing
diff --git a/app/assets/stylesheets/page_bundles/jira_connect.scss b/app/assets/stylesheets/page_bundles/jira_connect.scss
index 0a2b3175aa9..2c54c819543 100644
--- a/app/assets/stylesheets/page_bundles/jira_connect.scss
+++ b/app/assets/stylesheets/page_bundles/jira_connect.scss
@@ -16,12 +16,12 @@
@import '@gitlab/ui/src/components/base/pagination/pagination';
@import '@gitlab/ui/src/components/base/table/table';
@import '@gitlab/ui/src/components/base/tooltip/tooltip';
-@import '@gitlab/ui/src/components/base/search_box_by_type/search_box_by_type';
@import '@gitlab/ui/src/components/base/form/form_input/form_input';
@import '@gitlab/ui/src/components/base/form/form_radio/form_radio';
@import '@gitlab/ui/src/components/base/form/form_radio_group/form_radio_group';
@import '@gitlab/ui/src/components/base/form/form_checkbox/form_checkbox';
@import '@gitlab/ui/src/components/base/form/form_group/form_group';
+@import '@gitlab/ui/src/components/base/search_box_by_type/search_box_by_type';
$header-height: 40px;
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index fe64e4f2fe8..396c590d912 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -270,7 +270,8 @@ $tabs-holder-z-index: 250;
position: -webkit-sticky;
position: sticky;
top: calc(var(--top-pos) + var(--performance-bar-height, 0px));
- max-height: calc(100vh - var(--top-pos) - var(--system-header-height, 0px) - var(--performance-bar-height, 0px) - var(--review-bar-height, 0px));
+ min-height: 300px;
+ height: calc(100vh - var(--top-pos) - var(--system-header-height, 0px) - var(--performance-bar-height, 0px) - var(--review-bar-height, 0px));
.drag-handle {
bottom: 16px;
@@ -282,6 +283,7 @@ $tabs-holder-z-index: 250;
}
.tree-list-holder {
+ --file-row-height: 32px;
height: 100%;
.file-row {
@@ -297,6 +299,10 @@ $tabs-holder-z-index: 250;
overflow-x: auto;
}
+.tree-list-gutter {
+ height: $grid-size;
+}
+
.tree-list-search {
flex: 0 0 34px;
@@ -322,6 +328,12 @@ $tabs-holder-z-index: 250;
line-height: 0;
}
+.file-row-header {
+ display: flex;
+ align-items: center;
+ height: var(--file-row-height);
+}
+
@media (max-width: map-get($grid-breakpoints, lg)-1) {
.diffs .files {
.diff-tree-list {
@@ -807,7 +819,7 @@ $tabs-holder-z-index: 250;
.mr-widget-body,
.mr-widget-content {
- padding: $gl-padding;
+ padding: $gl-padding-12 $gl-padding;
}
.mr-widget-body-ready-merge {
@@ -828,6 +840,11 @@ $tabs-holder-z-index: 250;
}
}
+.mr-widget-grouped-section .report-block-container {
+ border-bottom-left-radius: $border-radius-default;
+ border-bottom-right-radius: $border-radius-default;
+}
+
.mr-widget-extension {
border-top: 1px solid var(--border-color, $border-color);
background-color: var(--gray-10, $gray-10);
@@ -901,10 +918,10 @@ $tabs-holder-z-index: 250;
&:not(:last-child)::before {
content: '';
- border-left: 2px solid var(--gray-10, $gray-10);
+ border-left: 2px solid var(--border-color, $border-color);
position: absolute;
bottom: -17px;
- left: calc(1rem - 1px);
+ left: 26px;
height: 16px;
}
}
@@ -994,7 +1011,7 @@ $tabs-holder-z-index: 250;
.submit-review-dropdown {
&.show .dropdown-menu {
width: calc(100vw - 20px);
- max-width: 650px;
+ max-width: 680px;
max-height: calc(100vh - 50px);
.gl-dropdown-inner {
@@ -1004,7 +1021,8 @@ $tabs-holder-z-index: 250;
.md-header {
.gl-tab-nav-item {
color: var(--gl-text-color, $gl-text-color);
- @include gl-pb-5;
+ @include gl-py-4;
+ @include gl-px-3;
&:hover {
@include gl-bg-none;
@@ -1070,6 +1088,9 @@ $tabs-holder-z-index: 250;
.merge-request-sticky-header {
z-index: 204;
box-shadow: 0 1px 2px $issue-boards-card-shadow;
+}
+
+.page-with-contextual-sidebar .merge-request-sticky-header {
--width: calc(100% - #{$contextual-sidebar-width});
@include media-breakpoint-down(lg) {
@@ -1081,6 +1102,18 @@ $tabs-holder-z-index: 250;
--width: calc(100% - #{$contextual-sidebar-collapsed-width});
}
+.page-with-super-sidebar .merge-request-sticky-header {
+ @include media-breakpoint-up(xl) {
+ --width: calc(100% - #{$super-sidebar-width});
+ }
+}
+
+.page-with-super-sidebar-collapsed .merge-request-sticky-header {
+ @include media-breakpoint-up(xl) {
+ --width: 100%;
+ }
+}
+
.merge-request-notification-toggle {
.gl-toggle {
@include gl-ml-auto;
diff --git a/app/assets/stylesheets/page_bundles/milestone.scss b/app/assets/stylesheets/page_bundles/milestone.scss
index 9ee6d17cb50..708d1a2895e 100644
--- a/app/assets/stylesheets/page_bundles/milestone.scss
+++ b/app/assets/stylesheets/page_bundles/milestone.scss
@@ -120,10 +120,6 @@
}
}
-.milestone-detail {
- border-bottom: 1px solid var(--border-color, $border-color);
-}
-
@include media-breakpoint-down(md) {
.milestone-actions {
@include clearfix();
diff --git a/app/assets/stylesheets/page_bundles/ml_experiment_tracking.scss b/app/assets/stylesheets/page_bundles/ml_experiment_tracking.scss
new file mode 100644
index 00000000000..d6f71b12cd9
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/ml_experiment_tracking.scss
@@ -0,0 +1,20 @@
+@import '../page_bundles/mixins_and_variables_and_functions';
+
+table.ml-candidate-table {
+ tr td,
+ tr th {
+ padding: $gl-padding-8;
+ min-width: 100px;
+
+ > * {
+ @include gl-display-block;
+ @include gl-text-truncate;
+ }
+ }
+}
+
+table.candidate-details {
+ td {
+ padding: $gl-spacing-scale-3;
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss
index fc745433f1b..dfc86a73635 100644
--- a/app/assets/stylesheets/page_bundles/profile.scss
+++ b/app/assets/stylesheets/page_bundles/profile.scss
@@ -135,10 +135,9 @@
}
}
+// Limits the width of the user bio for readability.
.profile-user-bio {
- // Limits the width of the user bio for readability.
max-width: 600px;
- margin: 10px auto;
}
.user-calendar {
@@ -172,7 +171,6 @@
}
.avatar-holder {
- width: 90px;
margin: 0 auto 10px;
}
}
diff --git a/app/assets/stylesheets/page_bundles/settings.scss b/app/assets/stylesheets/page_bundles/settings.scss
index 8978b8d798b..9a0d7880734 100644
--- a/app/assets/stylesheets/page_bundles/settings.scss
+++ b/app/assets/stylesheets/page_bundles/settings.scss
@@ -138,42 +138,32 @@
border-radius: $gl-border-radius-base;
}
-.prometheus-metrics-monitoring {
- .card {
- .card-toggle {
- width: 14px;
- }
+.prometheus-metrics-monitoring {
+ .gl-card {
.badge.badge-pill {
font-size: 12px;
line-height: 12px;
}
- .card-header .label-count {
+ .gl-card-header .label-count {
color: var(--white, $white);
background: var(--gray-800, $gray-800);
}
- .card-body {
- padding: 0;
- }
-
.flash-container {
margin-bottom: 0;
cursor: default;
- .flash-notice {
+ .flash-notice,
+ .flash-warning {
+ margin-top: 0;
border-radius: 0;
}
}
}
.custom-monitored-metrics {
- .card-header {
- display: flex;
- align-items: center;
- }
-
.custom-metric {
display: flex;
align-items: center;
diff --git a/app/assets/stylesheets/page_bundles/tree.scss b/app/assets/stylesheets/page_bundles/tree.scss
index 50d9684c7d2..a13b8704095 100644
--- a/app/assets/stylesheets/page_bundles/tree.scss
+++ b/app/assets/stylesheets/page_bundles/tree.scss
@@ -6,7 +6,7 @@
.tree-holder {
.nav-block {
- margin: 16px 0;
+ margin: $gl-spacing-scale-2 0 $gl-spacing-scale-5;
.tree-ref-holder {
margin-right: 15px;
@@ -103,7 +103,6 @@
tr {
border-bottom: 1px solid var(--gray-50, $gray-50);
- border-top: 1px solid var(--gray-50, $gray-50);
&:last-of-type {
border-bottom-color: transparent;
diff --git a/app/assets/stylesheets/page_bundles/wiki.scss b/app/assets/stylesheets/page_bundles/wiki.scss
index 9bbea48d2c0..d7d454bde45 100644
--- a/app/assets/stylesheets/page_bundles/wiki.scss
+++ b/app/assets/stylesheets/page_bundles/wiki.scss
@@ -106,6 +106,23 @@
color: var(--black, $black);
}
+ .active > .wiki-list {
+ a,
+ .wiki-list-expand-button,
+ .wiki-list-collapse-button {
+ color: var(--black, $black);
+ }
+ }
+
+ .wiki-list-expand-button,
+ .wiki-list-collapse-button {
+ color: var(--gray-400, $gray-400);
+
+ &:hover {
+ color: var(--black, $black);
+ }
+ }
+
ul.wiki-pages,
ul.wiki-pages li {
list-style: none;
@@ -118,7 +135,7 @@
}
ul.wiki-pages ul {
- padding-left: 15px;
+ padding-left: 20px;
}
.wiki-sidebar-header {
@@ -153,3 +170,45 @@ ul.wiki-pages-list.content-list {
.wiki-form .markdown-area {
max-height: 55vh;
}
+
+.wiki-list {
+ .wiki-list-expand-button,
+ .wiki-list-collapse-button {
+ left: -$gl-spacing-scale-5;
+ }
+
+ .wiki-list-expand-button {
+ display: none;
+ }
+
+ &.collapsed {
+ .wiki-list-collapse-button {
+ display: none;
+ }
+
+ .wiki-list-expand-button {
+ display: block;
+ }
+ }
+
+ &.collapsed + ul {
+ display: none;
+ }
+}
+
+.drawio-editor {
+ position: fixed;
+ top: calc(var(--header-height, 48px));
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: calc(100% - var(--header-height, 48px));
+ border: 0;
+ z-index: 1100;
+ visibility: hidden;
+}
+
+.with-performance-bar .drawio-editor {
+ top: calc(var(--header-height, 48px) + 35px);
+ height: calc(100% - var(--header-height, 48px) - 35px);
+}
diff --git a/app/assets/stylesheets/page_bundles/work_items.scss b/app/assets/stylesheets/page_bundles/work_items.scss
index 07a0cf3f367..00c86c46ac8 100644
--- a/app/assets/stylesheets/page_bundles/work_items.scss
+++ b/app/assets/stylesheets/page_bundles/work_items.scss
@@ -87,9 +87,22 @@
}
}
-.work-item-notes {
- .discussion-notes ul.notes li.toggle-replies-widget {
- // offset for .timeline-content padding + an extra 1px for border width
- margin: -5px -9px;
+.work-item-link-child {
+ @include gl-border-1;
+ @include gl-border-solid;
+ @include gl-border-transparent;
+ @include gl-rounded-base;
+
+ &:hover,
+ &:focus-within {
+ @include gl-bg-white;
+ @include gl-border-gray-50;
+ }
+}
+
+// sticky error placement for errors in modals , by default it is 83px for full view
+#work-item-detail-modal {
+ .flash-container.flash-container-page.sticky {
+ top: -8px;
}
}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 7d465dbcc04..225c32c1989 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -270,6 +270,10 @@
&:hover {
@include gl-text-decoration-none;
}
+
+ .header-main-content & {
+ @include gl-mr-2;
+ }
}
.gpg-popover-certificate-details {
diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss
index 909de9d57f2..7736f1012a5 100644
--- a/app/assets/stylesheets/pages/detail_page.scss
+++ b/app/assets/stylesheets/pages/detail_page.scss
@@ -1,6 +1,4 @@
.detail-page-header {
- padding: $gl-padding-top 0;
- border-bottom: 1px solid $border-color;
color: $gl-text-color;
line-height: 34px;
display: flex;
@@ -55,6 +53,10 @@
}
}
+.detail-page-header-meta {
+ @include gl-flex-basis-full;
+}
+
.detail-page-description {
.title {
margin: 0 0 16px;
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 75c81b74ba7..0151446321a 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -236,6 +236,7 @@ ul.related-merge-requests > li gl-emoji {
outline: none;
&::after {
+ @include gl-dark-invert-keep-hue;
content: image-url('icon_anchor.svg');
visibility: hidden;
}
@@ -272,20 +273,30 @@ ul.related-merge-requests > li gl-emoji {
@include media-breakpoint-up(md) {
// collapsed left sidebar + collapsed right sidebar
- .issue-sticky-header {
+ .page-with-contextual-sidebar .issue-sticky-header {
left: $contextual-sidebar-collapsed-width;
--width: calc(100% - #{$contextual-sidebar-collapsed-width} - #{$gutter-collapsed-width});
}
// collapsed left sidebar + expanded right sidebar
- .right-sidebar-expanded .issue-sticky-header {
+ .page-with-contextual-sidebar.right-sidebar-expanded .issue-sticky-header {
--width: calc(100% - #{$contextual-sidebar-collapsed-width} - #{$gutter-width});
}
+
+ // collapsed super sidebar + collapsed right sidebar
+ .page-with-super-sidebar .issue-sticky-header {
+ --width: calc(100% - #{$gutter-collapsed-width});
+ }
+
+ // collapsed super sidebar + expanded right sidebar
+ .page-with-super-sidebar.right-sidebar-expanded .issue-sticky-header {
+ --width: calc(100% - #{$gutter-width});
+ }
}
@include media-breakpoint-up(xl) {
// expanded left sidebar + collapsed right sidebar
- .issue-sticky-header {
+ .page-with-contextual-sidebar .issue-sticky-header {
left: $contextual-sidebar-width;
--width: calc(100% - #{$contextual-sidebar-width} - #{$gutter-collapsed-width});
}
@@ -297,14 +308,38 @@ ul.related-merge-requests > li gl-emoji {
}
// expanded left sidebar + expanded right sidebar
- .right-sidebar-expanded .issue-sticky-header {
+ .page-with-contextual-sidebar.right-sidebar-expanded .issue-sticky-header {
--width: calc(100% - #{$contextual-sidebar-width} - #{$gutter-width});
}
// collapsed left sidebar + expanded right sidebar
- .right-sidebar-expanded.page-with-icon-sidebar .issue-sticky-header {
+ .page-with-contextual-sidebar.right-sidebar-expanded.page-with-icon-sidebar .issue-sticky-header {
--width: calc(100% - #{$contextual-sidebar-collapsed-width} - #{$gutter-width});
}
+
+ // expanded super sidebar + collapsed right sidebar
+ .page-with-super-sidebar .issue-sticky-header {
+ left: $super-sidebar-width;
+ --width: calc(100% - #{$super-sidebar-width} - #{$gutter-collapsed-width});
+ }
+
+ // collapsed super sidebar + collapsed right sidebar
+ .page-with-super-sidebar-collapsed .issue-sticky-header {
+ left: 0;
+ --width: calc(100% - #{$gutter-collapsed-width});
+ }
+
+ // expanded super sidebar + expanded right sidebar
+ .page-with-super-sidebar.right-sidebar-expanded .issue-sticky-header {
+ left: $super-sidebar-width;
+ --width: calc(100% - #{$super-sidebar-width} - #{$gutter-width});
+ }
+
+ // collapsed super sidebar + expanded right sidebar
+ .page-with-super-sidebar-collapsed.right-sidebar-expanded .issue-sticky-header {
+ left: 0;
+ --width: calc(100% - #{$gutter-width});
+ }
}
.issuable-header-slide-enter-active,
diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss
index bd66319d78f..7c5054a6964 100644
--- a/app/assets/stylesheets/pages/labels.scss
+++ b/app/assets/stylesheets/pages/labels.scss
@@ -1,5 +1,5 @@
.suggest-colors {
- margin-top: 5px;
+ padding-top: 3px;
a {
border-radius: 4px;
@@ -9,23 +9,50 @@
margin-right: 10px;
margin-bottom: 10px;
text-decoration: none;
+
+ &:focus,
+ &:focus:active {
+ position: relative;
+ z-index: 1;
+ @include gl-focus;
+ }
}
&.suggest-colors-dropdown {
margin-top: 10px;
margin-bottom: 10px;
- border-radius: $border-radius-base;
- overflow: hidden;
a {
border-radius: 0;
width: (100% / 7);
margin-right: 0;
margin-bottom: -5px;
+
+ &:first-of-type {
+ border-top-left-radius: $border-radius-base;
+ }
+
+ &:nth-of-type(7) {
+ border-top-right-radius: $border-radius-base;
+ }
+
+ &:nth-last-child(7) {
+ border-bottom-left-radius: $border-radius-base;
+ }
+
+ &:last-of-type {
+ border-bottom-right-radius: $border-radius-base;
+ }
}
}
}
+.labels-select-contents-create {
+ .dropdown-input {
+ margin-bottom: 4px;
+ }
+}
+
.dropdown-menu-labels {
.dropdown-content {
max-height: 135px;
@@ -44,21 +71,7 @@
.dropdown-label-color-input {
position: relative;
- margin-bottom: 10px;
-
- &.is-active {
- padding-left: 32px;
- }
-}
-
-.dropdown-label-color-preview {
- position: absolute;
- left: 0;
- top: 0;
- width: 32px;
- height: 32px;
- border-top-left-radius: $border-radius-base;
- border-bottom-left-radius: $border-radius-base;
+ margin-bottom: 8px;
}
.color-label {
diff --git a/app/assets/stylesheets/pages/ml_experiment_tracking.scss b/app/assets/stylesheets/pages/ml_experiment_tracking.scss
deleted file mode 100644
index 3c025b5d23f..00000000000
--- a/app/assets/stylesheets/pages/ml_experiment_tracking.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-@import '../page_bundles/mixins_and_variables_and_functions';
-
-.ml-experiment-row {
- .title {
- margin-bottom: $gl-spacing-scale-1;
- font-weight: $gl-font-weight-bold;
- }
-
- .ml-experiment-info {
- color: $gl-text-color-secondary;
- }
-
- a {
- color: $gl-text-color;
- }
-}
-
-table.ml-candidate-table {
- table-layout: fixed;
-
- tr td,
- tr th {
- padding: $gl-padding-8;
-
- > * {
- @include gl-display-block;
- @include gl-text-truncate;
- }
- }
-}
-
-table.candidate-details {
- td {
- padding: $gl-spacing-scale-3;
- }
-}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 5d03281a30a..68a5176ad4b 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -1,5 +1,14 @@
-$system-note-icon-size: 2rem;
+$avatar-icon-size: 2rem;
+$avatar-m-top: 0.5rem;
+$avatar-m-ratio: 2;
+$avatar-m-left: $avatar-m-top * $avatar-m-ratio;
+
+$system-note-icon-size: 1.5rem;
$system-note-svg-size: 1rem;
+$icon-size-diff: $avatar-icon-size - $system-note-icon-size;
+
+$system-note-icon-m-top: $avatar-m-top + $icon-size-diff - 0.1rem;
+$system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio;
@mixin vertical-line($left) {
&::before {
@@ -36,6 +45,15 @@ $system-note-svg-size: 1rem;
&.timeline > .timeline-entry {
margin: $gl-padding 0;
+ &.system-note {
+ margin-top: $gl-spacing-scale-1;
+ margin-bottom: 0;
+
+ .note-header-info {
+ padding-left: $gl-spacing-scale-4;
+ }
+ }
+
&.system-note,
&.note-form {
border: 0;
@@ -113,7 +131,7 @@ $system-note-svg-size: 1rem;
background-color: $white;
.timeline-content:not(.flash-container) {
- padding: $gl-padding-8 $gl-padding-8 $gl-padding-8 $gl-padding;
+ padding: $gl-padding-8 $gl-padding-8 $gl-padding-8 18px;
}
.timeline-discussion-body-footer {
@@ -270,7 +288,7 @@ $system-note-svg-size: 1rem;
}
&.is-editing {
- .note-header,
+ .note-actions,
.note-text,
.edited-text {
display: none;
@@ -447,7 +465,7 @@ $system-note-svg-size: 1rem;
height: $system-note-icon-size;
border: 1px solid $gray-50;
border-radius: $system-note-icon-size;
- margin: -6px 0 0;
+ margin: -$gl-spacing-scale-1 0 0 $gl-spacing-scale-2;
svg {
width: $system-note-svg-size;
@@ -591,8 +609,8 @@ $system-note-svg-size: 1rem;
}
.timeline-entry-inner .timeline-icon {
- margin-top: $grid-size;
- margin-left: 14px;
+ margin-top: $system-note-icon-m-top;
+ margin-left: $system-note-icon-m-left;
}
}
}
@@ -672,7 +690,7 @@ $system-note-svg-size: 1rem;
.discussion-reply-holder {
border-top: 0;
- border-radius: 0 0 $border-radius-default $border-radius-default;
+ border-radius: 0 0 $gl-border-radius-base $gl-border-radius-base;
position: relative;
.discussion-form {
@@ -1134,7 +1152,7 @@ $system-note-svg-size: 1rem;
}
.timeline-avatar {
- margin: $gl-padding-8 0 0 $gl-padding;
+ margin: $avatar-m-top 0 0 $avatar-m-left;
}
}
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 8e4dd39e498..41b022437bb 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -64,13 +64,6 @@
}
}
-table.u2f-registrations {
- th:not(:last-child),
- td:not(:last-child) {
- border-right: solid 1px transparent;
- }
-}
-
.codes {
padding-top: 14px;
}
diff --git a/app/assets/stylesheets/print.scss b/app/assets/stylesheets/print.scss
index ab86a2f69dd..265f27f21fa 100644
--- a/app/assets/stylesheets/print.scss
+++ b/app/assets/stylesheets/print.scss
@@ -25,6 +25,7 @@ nav,
nav.navbar-collapse,
nav.navbar-collapse.collapse,
.nav-sidebar,
+.super-sidebar,
.profiler-results,
.tree-ref-holder,
.tree-holder .breadcrumb,
diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss
index 3b28025053b..b4e896325d6 100644
--- a/app/assets/stylesheets/startup/startup-dark.scss
+++ b/app/assets/stylesheets/startup/startup-dark.scss
@@ -119,7 +119,7 @@ kbd kbd {
.form-control {
display: block;
width: 100%;
- height: 34px;
+ height: 32px;
padding: 0.375rem 0.75rem;
font-size: 0.875rem;
font-weight: 400;
@@ -132,10 +132,6 @@ kbd kbd {
}
@media (prefers-reduced-motion: reduce) {
}
-.form-control:-moz-focusring {
- color: transparent;
- text-shadow: 0 0 0 #ececef;
-}
.form-control::placeholder {
color: #a4a3a8;
opacity: 1;
@@ -655,7 +651,7 @@ html {
color: #ececef;
font-size: 14px;
text-align: left;
- border: 1px solid #434248;
+ border: 1px solid #535158;
border-radius: 0.25rem;
white-space: nowrap;
}
@@ -665,9 +661,12 @@ html {
.dropdown-menu-toggle.dropdown-menu-toggle {
justify-content: flex-start;
overflow: hidden;
+ padding-top: 7px;
+ padding-bottom: 7px;
padding-right: 25px;
position: relative;
text-overflow: ellipsis;
+ line-height: 16px;
width: 160px;
}
.dropdown-menu {
@@ -1493,6 +1492,43 @@ kbd {
display: none;
}
}
+.super-sidebar {
+ display: flex;
+ flex-direction: column;
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ background-color: var(--gray-10, #1f1e24);
+ border-right: 1px solid rgba(251, 250, 253, 0.08);
+ transform: translate3d(0, 0, 0);
+ width: 256px;
+ z-index: 600;
+}
+.super-sidebar.super-sidebar-loading {
+ transform: translate3d(-100%, 0, 0);
+}
+@media (min-width: 1200px) {
+ .super-sidebar.super-sidebar-loading {
+ transform: translate3d(0, 0, 0);
+ }
+}
+.page-with-super-sidebar {
+ padding-left: 0;
+}
+@media (min-width: 1200px) {
+ .page-with-super-sidebar {
+ padding-left: 256px;
+ }
+}
+.page-with-super-sidebar-collapsed .super-sidebar {
+ transform: translate3d(-100%, 0, 0);
+}
+@media (min-width: 1200px) {
+ .page-with-super-sidebar-collapsed {
+ padding-left: 0;
+ }
+}
input::-moz-placeholder {
color: #737278;
opacity: 1;
diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss
index adafe719892..0a0fa83ff67 100644
--- a/app/assets/stylesheets/startup/startup-general.scss
+++ b/app/assets/stylesheets/startup/startup-general.scss
@@ -119,7 +119,7 @@ kbd kbd {
.form-control {
display: block;
width: 100%;
- height: 34px;
+ height: 32px;
padding: 0.375rem 0.75rem;
font-size: 0.875rem;
font-weight: 400;
@@ -132,10 +132,6 @@ kbd kbd {
}
@media (prefers-reduced-motion: reduce) {
}
-.form-control:-moz-focusring {
- color: transparent;
- text-shadow: 0 0 0 #333238;
-}
.form-control::placeholder {
color: #626168;
opacity: 1;
@@ -655,7 +651,7 @@ html {
color: #333238;
font-size: 14px;
text-align: left;
- border: 1px solid #dcdcde;
+ border: 1px solid #bfbfc3;
border-radius: 0.25rem;
white-space: nowrap;
}
@@ -665,9 +661,12 @@ html {
.dropdown-menu-toggle.dropdown-menu-toggle {
justify-content: flex-start;
overflow: hidden;
+ padding-top: 7px;
+ padding-bottom: 7px;
padding-right: 25px;
position: relative;
text-overflow: ellipsis;
+ line-height: 16px;
width: 160px;
}
.dropdown-menu {
@@ -1493,6 +1492,43 @@ kbd {
display: none;
}
}
+.super-sidebar {
+ display: flex;
+ flex-direction: column;
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ background-color: var(--gray-10, #fbfafd);
+ border-right: 1px solid rgba(31, 30, 36, 0.08);
+ transform: translate3d(0, 0, 0);
+ width: 256px;
+ z-index: 600;
+}
+.super-sidebar.super-sidebar-loading {
+ transform: translate3d(-100%, 0, 0);
+}
+@media (min-width: 1200px) {
+ .super-sidebar.super-sidebar-loading {
+ transform: translate3d(0, 0, 0);
+ }
+}
+.page-with-super-sidebar {
+ padding-left: 0;
+}
+@media (min-width: 1200px) {
+ .page-with-super-sidebar {
+ padding-left: 256px;
+ }
+}
+.page-with-super-sidebar-collapsed .super-sidebar {
+ transform: translate3d(-100%, 0, 0);
+}
+@media (min-width: 1200px) {
+ .page-with-super-sidebar-collapsed {
+ padding-left: 0;
+ }
+}
input::-moz-placeholder {
color: #89888d;
opacity: 1;
diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss
index 3aace601c45..57f61508178 100644
--- a/app/assets/stylesheets/startup/startup-signin.scss
+++ b/app/assets/stylesheets/startup/startup-signin.scss
@@ -192,7 +192,7 @@ hr {
.form-control {
display: block;
width: 100%;
- height: 34px;
+ height: 32px;
padding: 0.375rem 0.75rem;
font-size: 0.875rem;
font-weight: 400;
@@ -205,10 +205,6 @@ hr {
}
@media (prefers-reduced-motion: reduce) {
}
-.form-control:-moz-focusring {
- color: transparent;
- text-shadow: 0 0 0 #333238;
-}
.form-control::placeholder {
color: #626168;
opacity: 1;
@@ -262,7 +258,7 @@ input.btn-block[type="button"] {
display: block;
min-height: 1.5rem;
padding-left: 1.5rem;
- color-adjust: exact;
+ print-color-adjust: exact;
}
.custom-control-input {
position: absolute;
@@ -303,7 +299,7 @@ input.btn-block[type="button"] {
pointer-events: none;
content: "";
background-color: #fff;
- border: #737278 solid 1px;
+ border: 1px solid #737278;
}
.custom-control-label::after {
position: absolute;
@@ -313,7 +309,7 @@ input.btn-block[type="button"] {
width: 1rem;
height: 1rem;
content: "";
- background: no-repeat 50% / 50% 50%;
+ background: 50% / 50% 50% no-repeat;
}
.custom-checkbox .custom-control-label::before {
border-radius: 0.25rem;
@@ -663,7 +659,6 @@ body.navless {
.btn-block {
width: 100%;
margin: 0;
- margin-bottom: 1rem;
}
.btn-block.btn {
padding: 6px 0;
@@ -726,7 +721,7 @@ label.label-bold {
color: #89888d;
}
.gl-show-field-errors .form-control:not(textarea) {
- height: 34px;
+ height: 32px;
}
.navbar-empty {
justify-content: center;
diff --git a/app/assets/stylesheets/themes/dark_mode_overrides.scss b/app/assets/stylesheets/themes/dark_mode_overrides.scss
index bb97261a1ca..89a49b2cf86 100644
--- a/app/assets/stylesheets/themes/dark_mode_overrides.scss
+++ b/app/assets/stylesheets/themes/dark_mode_overrides.scss
@@ -143,6 +143,17 @@ body.gl-dark {
background-color: $gray-200;
}
}
+
+ .gl-new-dropdown-item {
+ &:active,
+ &:hover,
+ &:focus,
+ &:focus:active {
+ .gl-new-dropdown-item-content {
+ @include gl-bg-gray-10;
+ }
+ }
+ }
}
// Some hacks and overrides for things that don't properly support dark mode
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index af98d59251f..11f73b592fc 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -252,31 +252,60 @@ to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1709
}
}
+.gl-font-xs {
+ font-size: px-to-rem(10px);
+}
+
+.gl-line-height-12 {
+ line-height: px-to-rem(12px);
+}
+
+.gl-letter-spacing-06em {
+ letter-spacing: 0.06em;
+}
+
+.gl-flex-flow-row-wrap {
+ flex-flow: row wrap;
+}
+
+.gl-isolate {
+ isolation: isolate;
+}
+
+.gl-text-transform-uppercase {
+ text-transform: uppercase;
+}
+/*
+ * The below style will be moved to @gitlab/ui by
+ * https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2177
+ */
.gl-gap-2 {
gap: $gl-spacing-scale-2;
}
+.gl-bg-t-gray-a-08 {
+ background-color: $t-gray-a-08;
+}
+
.gl-hover-bg-t-gray-a-08:hover {
background-color: $t-gray-a-08;
}
-/* End gitlab-ui#1709 */
+.gl-inset-border-1-gray-a-08 {
+ box-shadow: inset 0 0 0 $gl-border-size-1 $t-gray-a-08;
+}
-/*
- * The below style will be moved to @gitlab/ui by
- * https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1751
- */
-.gl-filter-blur-1 {
- backdrop-filter: blur(2px);
- /* stylelint-disable property-no-vendor-prefix */
- -webkit-backdrop-filter: blur(2px); // still required by Safari
+.gl-line-height-1 {
+ line-height: 1;
}
-.gl-flex-flow-row-wrap {
- flex-flow: row wrap;
+.gl-focus:focus {
+ @include gl-focus;
}
-.gl-isolate {
- isolation: isolate;
+.gl-md-justify-content-space-between {
+ @include gl-media-breakpoint-up(md) {
+ justify-content: space-between;
+ }
}
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index 5357558434e..49079461698 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -3,6 +3,8 @@
class Admin::AbuseReportsController < Admin::ApplicationController
feature_category :insider_threat
+ before_action :set_status_param, only: :index, if: -> { Feature.enabled?(:abuse_reports_list) }
+
def index
@abuse_reports = AbuseReportsFinder.new(params).execute
end
@@ -15,4 +17,10 @@ class Admin::AbuseReportsController < Admin::ApplicationController
head :ok
end
+
+ private
+
+ def set_status_param
+ params[:status] ||= 'open'
+ end
end
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index ade58ca0970..0bbfeae6656 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -13,6 +13,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
before_action :disable_query_limiting, only: [:usage_data]
+ before_action do
+ push_frontend_feature_flag(:ci_variables_pages, current_user)
+ end
+
feature_category :not_owned, [ # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
:general, :reporting, :metrics_and_profiling, :network,
:preferences, :update, :reset_health_check_token
@@ -101,8 +105,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def reset_error_tracking_access_token
@application_setting.reset_error_tracking_access_token!
- redirect_to general_admin_application_settings_path,
- notice: _('New error tracking access token has been generated!')
+ redirect_to general_admin_application_settings_path, notice: _('New error tracking access token has been generated!')
end
def clear_repository_check_states
diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb
index d66b3cb4366..76564981c9b 100644
--- a/app/controllers/admin/applications_controller.rb
+++ b/app/controllers/admin/applications_controller.rb
@@ -3,19 +3,17 @@
class Admin::ApplicationsController < Admin::ApplicationController
include OauthApplications
- before_action :set_application, only: [:show, :edit, :update, :destroy]
+ before_action :set_application, only: [:show, :edit, :update, :renew, :destroy]
before_action :load_scopes, only: [:new, :create, :edit, :update]
- feature_category :authentication_and_authorization
+ feature_category :system_access
def index
applications = ApplicationsFinder.new.execute
@applications = Kaminari.paginate_array(applications).page(params[:page])
end
- def show
- @created = get_created_session if Feature.disabled?('hash_oauth_secrets')
- end
+ def show; end
def new
@application = Doorkeeper::Application.new
@@ -30,14 +28,8 @@ class Admin::ApplicationsController < Admin::ApplicationController
if @application.persisted?
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
- if Feature.enabled?('hash_oauth_secrets')
- @created = true
- render :show
- else
- set_created_session
-
- redirect_to admin_application_url(@application)
- end
+ @created = true
+ render :show
else
render :new
end
@@ -51,6 +43,17 @@ class Admin::ApplicationsController < Admin::ApplicationController
end
end
+ def renew
+ @application.renew_secret
+
+ if @application.save
+ flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
+ render :show
+ else
+ redirect_to admin_application_url(@application)
+ end
+ end
+
def destroy
@application.destroy
redirect_to admin_applications_url, status: :found, notice: _('Application was successfully destroyed.')
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index d641a26c9fb..654b8309937 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -72,7 +72,7 @@ module Admin
def preview
@broadcast_message = BroadcastMessage.new(broadcast_message_params)
- render partial: 'admin/broadcast_messages/preview'
+ render plain: render_broadcast_message(@broadcast_message), status: :ok
end
protected
diff --git a/app/controllers/admin/ci/variables_controller.rb b/app/controllers/admin/ci/variables_controller.rb
index ef50d7362c4..c811de12914 100644
--- a/app/controllers/admin/ci/variables_controller.rb
+++ b/app/controllers/admin/ci/variables_controller.rb
@@ -3,7 +3,7 @@
module Admin
module Ci
class VariablesController < ApplicationController
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
def show
respond_to do |format|
@@ -32,10 +32,7 @@ module Admin
end
def render_instance_variables
- render status: :ok,
- json: {
- variables: ::Ci::InstanceVariableSerializer.new.represent(variables)
- }
+ render status: :ok, json: { variables: ::Ci::InstanceVariableSerializer.new.represent(variables) }
end
def render_error(errors)
diff --git a/app/controllers/admin/cohorts_controller.rb b/app/controllers/admin/cohorts_controller.rb
index ce3d769f35e..3948d3635fe 100644
--- a/app/controllers/admin/cohorts_controller.rb
+++ b/app/controllers/admin/cohorts_controller.rb
@@ -7,7 +7,7 @@ class Admin::CohortsController < Admin::ApplicationController
urgency :low
- track_custom_event :index,
+ track_event :index,
name: 'i_analytics_cohorts',
action: 'perform_analytics_usage_action',
label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly',
diff --git a/app/controllers/admin/dev_ops_report_controller.rb b/app/controllers/admin/dev_ops_report_controller.rb
index 71ee19ddf39..2e47dfcb0db 100644
--- a/app/controllers/admin/dev_ops_report_controller.rb
+++ b/app/controllers/admin/dev_ops_report_controller.rb
@@ -5,7 +5,7 @@ class Admin::DevOpsReportController < Admin::ApplicationController
helper_method :show_adoption?
- track_custom_event :show,
+ track_event :show,
name: 'i_analytics_dev_ops_score',
action: 'perform_analytics_usage_action',
label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly',
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index e3a33bafb62..ef45eaac437 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -65,8 +65,8 @@ class Admin::GroupsController < Admin::ApplicationController
Groups::DestroyService.new(@group, current_user).async_execute
redirect_to admin_groups_path,
- status: :found,
- alert: format(_('Group %{group_name} was scheduled for deletion.'), group_name: @group.name)
+ status: :found,
+ alert: format(_('Group %{group_name} was scheduled for deletion.'), group_name: @group.name)
end
private
diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb
index dcec50e882d..0745ba328c6 100644
--- a/app/controllers/admin/identities_controller.rb
+++ b/app/controllers/admin/identities_controller.rb
@@ -4,7 +4,7 @@ class Admin::IdentitiesController < Admin::ApplicationController
before_action :user
before_action :identity, except: [:index, :new, :create]
- feature_category :authentication_and_authorization
+ feature_category :system_access
def new
@identity = Identity.new
diff --git a/app/controllers/admin/impersonation_tokens_controller.rb b/app/controllers/admin/impersonation_tokens_controller.rb
index ddc555add5c..dae3337d19b 100644
--- a/app/controllers/admin/impersonation_tokens_controller.rb
+++ b/app/controllers/admin/impersonation_tokens_controller.rb
@@ -4,7 +4,7 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController
before_action :user
before_action :verify_impersonation_enabled!
- feature_category :authentication_and_authorization
+ feature_category :user_management
def index
set_index_vars
diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb
index 6c45b03455e..c1a6cb350ec 100644
--- a/app/controllers/admin/impersonations_controller.rb
+++ b/app/controllers/admin/impersonations_controller.rb
@@ -4,7 +4,7 @@ class Admin::ImpersonationsController < Admin::ApplicationController
skip_before_action :authenticate_admin!
before_action :authenticate_impersonator!
- feature_category :authentication_and_authorization
+ feature_category :user_management
def destroy
original_user = stop_impersonation
diff --git a/app/controllers/admin/keys_controller.rb b/app/controllers/admin/keys_controller.rb
index 03383604e30..e4a756ec12d 100644
--- a/app/controllers/admin/keys_controller.rb
+++ b/app/controllers/admin/keys_controller.rb
@@ -3,7 +3,7 @@
class Admin::KeysController < Admin::ApplicationController
before_action :user, only: [:show, :destroy]
- feature_category :authentication_and_authorization
+ feature_category :user_management
def show
@key = user.keys.find(params[:id])
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 5d37bd27302..70c2d262b72 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -3,10 +3,10 @@
class Admin::ProjectsController < Admin::ApplicationController
include MembersPresentation
- before_action :project, only: [:show, :transfer, :repository_check, :destroy]
+ before_action :project, only: [:show, :transfer, :repository_check, :destroy, :edit, :update]
before_action :group, only: [:show, :transfer]
- feature_category :projects, [:index, :show, :transfer, :destroy]
+ feature_category :projects, [:index, :show, :transfer, :destroy, :edit, :update]
feature_category :source_code_management, [:repository_check]
def index
@@ -62,6 +62,18 @@ class Admin::ProjectsController < Admin::ApplicationController
end
# rubocop: enable CodeReuse/ActiveRecord
+ def edit; end
+
+ def update
+ result = ::Projects::UpdateService.new(@project, current_user, project_params).execute
+
+ if result[:status] == :success
+ redirect_to [:admin, @project], notice: format(_("Project '%{project_name}' was successfully updated."), project_name: @project.name)
+ else
+ render "edit"
+ end
+ end
+
def repository_check
RepositoryCheck::SingleRepositoryWorker.perform_async(@project.id) # rubocop:disable CodeReuse/Worker
@@ -83,6 +95,17 @@ class Admin::ProjectsController < Admin::ApplicationController
def group
@group ||= @project.group
end
+
+ def project_params
+ params.require(:project).permit(allowed_project_params)
+ end
+
+ def allowed_project_params
+ [
+ :description,
+ :name
+ ]
+ end
end
Admin::ProjectsController.prepend_mod_with('Admin::ProjectsController')
diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb
index 21a3a0aea0b..f63616a2bea 100644
--- a/app/controllers/admin/runners_controller.rb
+++ b/app/controllers/admin/runners_controller.rb
@@ -6,7 +6,7 @@ class Admin::RunnersController < Admin::ApplicationController
before_action :runner, except: [:index, :new, :tag_list, :runner_setup_scripts]
before_action only: [:index] do
- push_frontend_feature_flag(:create_runner_workflow, current_user)
+ push_frontend_feature_flag(:create_runner_workflow_for_admin, current_user)
end
feature_category :runner
@@ -23,7 +23,12 @@ class Admin::RunnersController < Admin::ApplicationController
end
def new
- render_404 unless Feature.enabled?(:create_runner_workflow, current_user)
+ render_404 unless Feature.enabled?(:create_runner_workflow_for_admin, current_user)
+ end
+
+ def register
+ render_404 unless Feature.enabled?(:create_runner_workflow_for_admin, current_user) &&
+ runner.registration_available?
end
def update
diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb
index 63579421573..bb275532170 100644
--- a/app/controllers/admin/sessions_controller.rb
+++ b/app/controllers/admin/sessions_controller.rb
@@ -7,7 +7,7 @@ class Admin::SessionsController < ApplicationController
before_action :user_is_admin!
- feature_category :authentication_and_authorization
+ feature_category :system_access
def new
if current_user_mode.admin_mode?
diff --git a/app/controllers/admin/spam_logs_controller.rb b/app/controllers/admin/spam_logs_controller.rb
index 984ae736697..b27185a6add 100644
--- a/app/controllers/admin/spam_logs_controller.rb
+++ b/app/controllers/admin/spam_logs_controller.rb
@@ -5,7 +5,7 @@ class Admin::SpamLogsController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def index
- @spam_logs = SpamLog.includes(:user).order(id: :desc).page(params[:page])
+ @spam_logs = SpamLog.includes(:user).order(id: :desc).page(params[:page]).without_count
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -15,8 +15,8 @@ class Admin::SpamLogsController < Admin::ApplicationController
if params[:remove_user]
spam_log.remove_user(deleted_by: current_user)
redirect_to admin_spam_logs_path,
- status: :found,
- notice: format(_('User %{username} was successfully removed.'), username: spam_log.user.username)
+ status: :found,
+ notice: format(_('User %{username} was successfully removed.'), username: spam_log.user.username)
else
spam_log.destroy
head :ok
diff --git a/app/controllers/admin/topics_controller.rb b/app/controllers/admin/topics_controller.rb
index 345a778772d..94d084932ad 100644
--- a/app/controllers/admin/topics_controller.rb
+++ b/app/controllers/admin/topics_controller.rb
@@ -41,8 +41,8 @@ class Admin::TopicsController < Admin::ApplicationController
@topic.destroy!
redirect_to admin_topics_path,
- status: :found,
- notice: format(_('Topic %{topic_name} was successfully removed.'), topic_name: @topic.title_or_name)
+ status: :found,
+ notice: format(_('Topic %{topic_name} was successfully removed.'), topic_name: @topic.title_or_name)
end
def merge
diff --git a/app/controllers/admin/usage_trends_controller.rb b/app/controllers/admin/usage_trends_controller.rb
index 082b38ac3a8..f88028535c1 100644
--- a/app/controllers/admin/usage_trends_controller.rb
+++ b/app/controllers/admin/usage_trends_controller.rb
@@ -3,7 +3,7 @@
class Admin::UsageTrendsController < Admin::ApplicationController
include ProductAnalyticsTracking
- track_custom_event :index,
+ track_event :index,
name: 'i_analytics_instance_statistics',
action: 'perform_analytics_usage_action',
label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly',
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 353f9098b95..ff888cf9d72 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -33,7 +33,6 @@ class ApplicationController < ActionController::Base
before_action :check_password_expiration, if: :html_request?
before_action :ldap_security_check
before_action :default_headers
- before_action :default_cache_headers
before_action :add_gon_variables, if: :html_request?
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :require_email, unless: :devise_controller?
@@ -260,10 +259,7 @@ class ApplicationController < ActionController::Base
respond_to do |format|
format.html do
- render template,
- layout: "errors",
- status: status,
- locals: { message: message }
+ render template, layout: "errors", status: status, locals: { message: message }
end
format.any { head status }
end
@@ -319,10 +315,6 @@ class ApplicationController < ActionController::Base
headers['X-Content-Type-Options'] = 'nosniff'
end
- def default_cache_headers
- headers['Pragma'] = 'no-cache' # HTTP 1.0 compatibility
- end
-
def stream_csv_headers(csv_filename)
no_cache_headers
stream_headers
diff --git a/app/controllers/chaos_controller.rb b/app/controllers/chaos_controller.rb
index 6139168d29f..7328b793b09 100644
--- a/app/controllers/chaos_controller.rb
+++ b/app/controllers/chaos_controller.rb
@@ -52,13 +52,14 @@ class ChaosController < ActionController::Base
def validate_chaos_secret
unless chaos_secret_configured
render plain: "chaos misconfigured: please configure GITLAB_CHAOS_SECRET",
- status: :internal_server_error
+ status: :internal_server_error
+
return
end
unless Devise.secure_compare(chaos_secret_configured, chaos_secret_request)
render plain: "To experience chaos, please set a valid `X-Chaos-Secret` header or `token` param",
- status: :unauthorized
+ status: :unauthorized
end
end
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index b4a36b7db22..691b4f4e21f 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -25,13 +25,7 @@ module AuthenticatesWithTwoFactor
session[:user_password_hash] = Digest::SHA256.hexdigest(user.encrypted_password)
add_gon_variables
- push_frontend_feature_flag(:webauthn)
-
- if Feature.enabled?(:webauthn)
- setup_webauthn_authentication(user)
- else
- setup_u2f_authentication(user)
- end
+ setup_webauthn_authentication(user)
render 'devise/sessions/two_factor'
end
@@ -54,11 +48,7 @@ module AuthenticatesWithTwoFactor
if user_params[:otp_attempt].present? && session[:otp_user_id]
authenticate_with_two_factor_via_otp(user)
elsif user_params[:device_response].present? && session[:otp_user_id]
- if user.two_factor_webauthn_enabled?
- authenticate_with_two_factor_via_webauthn(user)
- else
- authenticate_with_two_factor_via_u2f(user)
- end
+ authenticate_with_two_factor_via_webauthn(user)
elsif user && user.valid_password?(user_params[:password])
prompt_for_two_factor(user)
end
@@ -96,15 +86,6 @@ module AuthenticatesWithTwoFactor
end
end
- # Authenticate using the response from a U2F (universal 2nd factor) device
- def authenticate_with_two_factor_via_u2f(user)
- if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge])
- handle_two_factor_success(user)
- else
- handle_two_factor_failure(user, 'U2F', _('Authentication via U2F device failed.'))
- end
- end
-
def authenticate_with_two_factor_via_webauthn(user)
if Webauthn::AuthenticateService.new(user, user_params[:device_response], session[:challenge]).execute
handle_two_factor_success(user)
@@ -133,11 +114,11 @@ module AuthenticatesWithTwoFactor
webauthn_registration_ids = user.webauthn_registrations.pluck(:credential_xid)
- get_options = WebAuthn::Credential.options_for_get(allow: webauthn_registration_ids,
- user_verification: 'discouraged',
- extensions: { appid: WebAuthn.configuration.origin })
-
- session[:credentialRequestOptions] = get_options
+ get_options = WebAuthn::Credential.options_for_get(
+ allow: webauthn_registration_ids,
+ user_verification: 'discouraged',
+ extensions: { appid: WebAuthn.configuration.origin }
+ )
session[:challenge] = get_options.challenge
gon.push(webauthn: { options: Gitlab::Json.dump(get_options) })
end
diff --git a/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb
index 574fc6c0f37..045ccf1e5b8 100644
--- a/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb
@@ -11,13 +11,7 @@ module AuthenticatesWithTwoFactorForAdminMode
return handle_locked_user(user) unless user.can?(:log_in)
session[:otp_user_id] = user.id
- push_frontend_feature_flag(:webauthn)
-
- if user.two_factor_webauthn_enabled?
- setup_webauthn_authentication(user)
- else
- setup_u2f_authentication(user)
- end
+ setup_webauthn_authentication(user)
render 'admin/sessions/two_factor', layout: 'application'
end
@@ -30,11 +24,7 @@ module AuthenticatesWithTwoFactorForAdminMode
if user_params[:otp_attempt].present? && session[:otp_user_id]
admin_mode_authenticate_with_two_factor_via_otp(user)
elsif user_params[:device_response].present? && session[:otp_user_id]
- if user.two_factor_webauthn_enabled?
- admin_mode_authenticate_with_two_factor_via_webauthn(user)
- else
- admin_mode_authenticate_with_two_factor_via_u2f(user)
- end
+ admin_mode_authenticate_with_two_factor_via_webauthn(user)
elsif user && user.valid_password?(user_params[:password])
admin_mode_prompt_for_two_factor(user)
else
@@ -56,14 +46,6 @@ module AuthenticatesWithTwoFactorForAdminMode
end
end
- def admin_mode_authenticate_with_two_factor_via_u2f(user)
- if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge])
- admin_handle_two_factor_success
- else
- admin_handle_two_factor_failure(user, 'U2F', _('Authentication via U2F device failed.'))
- end
- end
-
def admin_mode_authenticate_with_two_factor_via_webauthn(user)
if Webauthn::AuthenticateService.new(user, user_params[:device_response], session[:challenge]).execute
admin_handle_two_factor_success
diff --git a/app/controllers/concerns/confirm_email_warning.rb b/app/controllers/concerns/confirm_email_warning.rb
index ec5140bf223..8b7371cbc17 100644
--- a/app/controllers/concerns/confirm_email_warning.rb
+++ b/app/controllers/concerns/confirm_email_warning.rb
@@ -10,7 +10,7 @@ module ConfirmEmailWarning
protected
def show_confirm_warning?
- html_request? && request.get? && Feature.enabled?(:soft_email_confirmation)
+ html_request? && request.get? && Gitlab::CurrentSettings.email_confirmation_setting_soft?
end
def set_confirm_warning
diff --git a/app/controllers/concerns/cycle_analytics_params.rb b/app/controllers/concerns/cycle_analytics_params.rb
index 5199d879595..8aac3874499 100644
--- a/app/controllers/concerns/cycle_analytics_params.rb
+++ b/app/controllers/concerns/cycle_analytics_params.rb
@@ -19,7 +19,6 @@ module CycleAnalyticsParams
@options ||= {}.tap do |opts|
opts[:current_user] = current_user
opts[:projects] = params[:project_ids] if params[:project_ids]
- opts[:group] = params[:group_id] if params[:group_id]
opts[:from] = params[:from] || start_date(params)
opts[:to] = params[:to] if params[:to]
opts[:end_event_filter] = params[:end_event_filter] if params[:end_event_filter]
@@ -78,5 +77,3 @@ module CycleAnalyticsParams
end
end
end
-
-CycleAnalyticsParams.prepend_mod_with('CycleAnalyticsParams')
diff --git a/app/controllers/concerns/enforces_two_factor_authentication.rb b/app/controllers/concerns/enforces_two_factor_authentication.rb
index cdef1a45a27..8068913eea2 100644
--- a/app/controllers/concerns/enforces_two_factor_authentication.rb
+++ b/app/controllers/concerns/enforces_two_factor_authentication.rb
@@ -27,7 +27,8 @@ module EnforcesTwoFactorAuthentication
render_error(
format(
_("Authentication error: enable 2FA in your profile settings to continue using GitLab: %{mfa_help_page}"),
- mfa_help_page: mfa_help_page_url),
+ mfa_help_page: mfa_help_page_url
+ ),
status: :unauthorized
)
else
diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb
index 4d181ded071..7e1ba49d442 100644
--- a/app/controllers/concerns/integrations/params.rb
+++ b/app/controllers/concerns/integrations/params.rb
@@ -8,6 +8,7 @@ module Integrations
:app_store_issuer_id,
:app_store_key_id,
:app_store_private_key,
+ :app_store_private_key_file_name,
:active,
:alert_events,
:api_key,
@@ -72,6 +73,8 @@ module Integrations
:server,
:server_host,
:server_port,
+ :service_account_key,
+ :service_account_key_file_name,
:sound,
:subdomain,
:teamcity_url,
diff --git a/app/controllers/concerns/invisible_captcha_on_signup.rb b/app/controllers/concerns/invisible_captcha_on_signup.rb
index b78869e02d0..a704ff251b3 100644
--- a/app/controllers/concerns/invisible_captcha_on_signup.rb
+++ b/app/controllers/concerns/invisible_captcha_on_signup.rb
@@ -26,15 +26,17 @@ module InvisibleCaptchaOnSignup
end
def invisible_captcha_honeypot_counter
- @invisible_captcha_honeypot_counter ||=
- Gitlab::Metrics.counter(:bot_blocked_by_invisible_captcha_honeypot,
- 'Counter of blocked sign up attempts with filled honeypot')
+ @invisible_captcha_honeypot_counter ||= Gitlab::Metrics.counter(
+ :bot_blocked_by_invisible_captcha_honeypot,
+ 'Counter of blocked sign up attempts with filled honeypot'
+ )
end
def invisible_captcha_timestamp_counter
- @invisible_captcha_timestamp_counter ||=
- Gitlab::Metrics.counter(:bot_blocked_by_invisible_captcha_timestamp,
- 'Counter of blocked sign up attempts with invalid timestamp')
+ @invisible_captcha_timestamp_counter ||= Gitlab::Metrics.counter(
+ :bot_blocked_by_invisible_captcha_timestamp,
+ 'Counter of blocked sign up attempts with invalid timestamp'
+ )
end
def log_request(message)
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index e1381b4173f..d364daf93c3 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -151,9 +151,7 @@ module IssuableActions
end
case issuable
- when MergeRequest
- render_mr_discussions(discussion_notes, discussion_serializer, discussion_cache_context)
- when Issue
+ when MergeRequest, Issue
if stale?(etag: [discussion_cache_context, discussion_notes])
render json: discussion_serializer.represent(discussion_notes, context: self)
end
@@ -164,23 +162,6 @@ module IssuableActions
private
- def render_mr_discussions(discussions, serializer, cache_context)
- return unless stale?(etag: [cache_context, discussions])
-
- if Feature.enabled?(:disabled_mr_discussions_redis_cache, project)
- render json: serializer.represent(discussions, context: self)
- else
- render_cached_discussions(discussions, serializer, cache_context)
- end
- end
-
- def render_cached_discussions(discussions, serializer, cache_context)
- render_cached(discussions,
- with: serializer,
- cache_context: ->(_) { cache_context },
- context: self)
- end
-
def notes_filter
strong_memoize(:notes_filter) do
notes_filter_param = params[:notes_filter]&.to_i
diff --git a/app/controllers/concerns/kas_cookie.rb b/app/controllers/concerns/kas_cookie.rb
new file mode 100644
index 00000000000..ef58ab1972b
--- /dev/null
+++ b/app/controllers/concerns/kas_cookie.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module KasCookie
+ extend ActiveSupport::Concern
+
+ def set_kas_cookie
+ return unless ::Gitlab::Kas::UserAccess.enabled?
+
+ public_session_id = Gitlab::Session.current&.id&.public_id
+ return unless public_session_id
+
+ cookie_data = ::Gitlab::Kas::UserAccess.cookie_data(public_session_id)
+
+ cookies[::Gitlab::Kas::COOKIE_KEY] = cookie_data
+ end
+end
diff --git a/app/controllers/concerns/known_sign_in.rb b/app/controllers/concerns/known_sign_in.rb
index cacc7e4628f..997f26fa959 100644
--- a/app/controllers/concerns/known_sign_in.rb
+++ b/app/controllers/concerns/known_sign_in.rb
@@ -26,8 +26,13 @@ module KnownSignIn
end
def update_cookie
- set_secure_cookie(KNOWN_SIGN_IN_COOKIE, current_user.id,
- type: COOKIE_TYPE_ENCRYPTED, httponly: true, expires: KNOWN_SIGN_IN_COOKIE_EXPIRY)
+ set_secure_cookie(
+ KNOWN_SIGN_IN_COOKIE,
+ current_user.id,
+ type: COOKIE_TYPE_ENCRYPTED,
+ httponly: true,
+ expires: KNOWN_SIGN_IN_COOKIE_EXPIRY
+ )
end
def sessions
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index 773e4c15d6e..da2ed9d62e7 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -63,10 +63,10 @@ module MembershipActions
if access_requester.persisted?
redirect_to polymorphic_path(membershipable),
- notice: _('Your request for access has been queued for review.')
+ notice: _('Your request for access has been queued for review.')
else
redirect_to polymorphic_path(membershipable),
- alert: format(_("Your request for access could not be processed: %{error_message}"), error_message: access_requester.errors.full_messages.to_sentence)
+ alert: format(_("Your request for access could not be processed: %{error_message}"), error_message: access_requester.errors.full_messages.to_sentence)
end
end
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index 512dbf0de5d..06b9c901e4a 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -45,7 +45,8 @@ module NotesActions
respond_to do |format|
format.json do
json = {
- commands_changes: @note.commands_changes&.slice(:emoji_award, :time_estimate, :spend_time)
+ commands_changes: @note.commands_changes&.slice(:emoji_award, :time_estimate, :spend_time),
+ command_names: @note.command_names
}
if @note.persisted? && return_discussion?
diff --git a/app/controllers/concerns/observability/content_security_policy.rb b/app/controllers/concerns/observability/content_security_policy.rb
index 3865e3b606d..1e25dc492a0 100644
--- a/app/controllers/concerns/observability/content_security_policy.rb
+++ b/app/controllers/concerns/observability/content_security_policy.rb
@@ -12,17 +12,17 @@ module Observability
defined?(project) ? project&.group : nil
end
- next if p.directives.blank? || !Gitlab::Observability.observability_enabled?(current_user, current_group)
+ next if p.directives.blank? || !Feature.enabled?(:observability_group_tab, current_group)
default_frame_src = p.directives['frame-src'] || p.directives['default-src']
# When ObservabilityUI is not authenticated, it needs to be able
# to redirect to the GL sign-in page, hence '/users/sign_in' and '/oauth/authorize'
- frame_src_values = Array.wrap(default_frame_src) | [Gitlab::Observability.observability_url,
- Gitlab::Utils.append_path(Gitlab.config.gitlab.url,
-'/users/sign_in'),
- Gitlab::Utils.append_path(Gitlab.config.gitlab.url,
-'/oauth/authorize')]
+ frame_src_values = Array.wrap(default_frame_src) | [
+ Gitlab::Observability.observability_url,
+ Gitlab::Utils.append_path(Gitlab.config.gitlab.url, '/users/sign_in'),
+ Gitlab::Utils.append_path(Gitlab.config.gitlab.url, '/oauth/authorize')
+ ]
p.frame_src(*frame_src_values)
end
diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb
index 5696e441ad0..5ed2b2a82eb 100644
--- a/app/controllers/concerns/product_analytics_tracking.rb
+++ b/app/controllers/concerns/product_analytics_tracking.rb
@@ -5,48 +5,48 @@ module ProductAnalyticsTracking
include RedisTracking
extend ActiveSupport::Concern
- MIGRATED_EVENTS = ['g_analytics_valuestream'].freeze
+ MIGRATED_EVENTS = %w[
+ g_analytics_valuestream
+ i_search_paid
+ i_search_total
+ i_search_advanced
+ i_ecosystem_jira_service_list_issues
+ users_viewing_analytics_group_devops_adoption
+ i_analytics_dev_ops_adoption
+ i_analytics_dev_ops_score
+ p_analytics_merge_request
+ i_analytics_instance_statistics
+ g_analytics_contribution
+ p_analytics_pipelines
+ p_analytics_code_reviews
+ p_analytics_valuestream
+ p_analytics_insights
+ p_analytics_issues
+ p_analytics_repo
+ g_analytics_insights
+ g_analytics_issues
+ g_analytics_productivity
+ i_analytics_cohorts
+ ].freeze
class_methods do
- # TODO: Remove once all the events are migrated to #track_custom_event
- # during https://gitlab.com/groups/gitlab-org/-/epics/8641
- def track_event(*controller_actions, name:, conditions: nil, destinations: [:redis_hll], &block)
+ def track_event(*controller_actions, name:, action: nil, label: nil, conditions: nil, destinations: [:redis_hll], &block)
custom_conditions = [:trackable_html_request?, *conditions]
after_action only: controller_actions, if: custom_conditions do
- route_events_to(destinations, name, &block)
- end
- end
-
- def track_custom_event(*controller_actions, name:, action:, label:, conditions: nil, destinations: [:redis_hll], &block)
- custom_conditions = [:trackable_html_request?, *conditions]
-
- after_action only: controller_actions, if: custom_conditions do
- route_custom_events_to(destinations, name, action, label, &block)
+ route_events_to(destinations, name, action, label, &block)
end
end
end
private
- def route_events_to(destinations, name, &block)
- track_unique_redis_hll_event(name, &block) if destinations.include?(:redis_hll)
-
- return unless destinations.include?(:snowplow) && event_enabled?(name)
-
- Gitlab::Tracking.event(
- self.class.to_s,
- name,
- namespace: tracking_namespace_source,
- user: current_user,
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: name).to_context]
- )
- end
-
- def route_custom_events_to(destinations, name, action, label, &block)
+ def route_events_to(destinations, name, action, label, &block)
track_unique_redis_hll_event(name, &block) if destinations.include?(:redis_hll)
return unless destinations.include?(:snowplow) && event_enabled?(name)
+ raise "action is required when destination is snowplow" unless action
+ raise "label is required when destination is snowplow" unless label
optional_arguments = {
namespace: tracking_namespace_source,
@@ -68,28 +68,11 @@ module ProductAnalyticsTracking
return true if MIGRATED_EVENTS.include?(event)
events_to_ff = {
- i_search_paid: :_phase2,
- i_search_total: :_phase2,
- i_search_advanced: :_phase2,
- i_ecosystem_jira_service_list_issues: :_phase2,
- users_viewing_analytics_group_devops_adoption: :_phase2,
- i_analytics_dev_ops_adoption: :_phase2,
- i_analytics_dev_ops_score: :_phase2,
- p_analytics_merge_request: :_phase2,
- i_analytics_instance_statistics: :_phase2,
- g_analytics_contribution: :_phase2,
- p_analytics_pipelines: :_phase2,
- p_analytics_code_reviews: :_phase2,
- p_analytics_valuestream: :_phase2,
- p_analytics_insights: :_phase2,
- p_analytics_issues: :_phase2,
- p_analytics_repo: :_phase2,
- g_analytics_insights: :_phase2,
- g_analytics_issues: :_phase2,
- g_analytics_productivity: :_phase2,
- i_analytics_cohorts: :_phase2,
-
- g_compliance_dashboard: :_phase4
+ g_edit_by_sfe: :_phase4,
+ g_compliance_dashboard: :_phase4,
+ g_compliance_audit_events: :_phase4,
+ i_compliance_audit_events: :_phase4,
+ i_compliance_credential_inventory: :_phase4
}
Feature.enabled?("route_hll_to_snowplow#{events_to_ff[event.to_sym]}", tracking_namespace_source)
diff --git a/app/controllers/concerns/registrations_tracking.rb b/app/controllers/concerns/registrations_tracking.rb
index 14743349c1a..6c83c57d9dd 100644
--- a/app/controllers/concerns/registrations_tracking.rb
+++ b/app/controllers/concerns/registrations_tracking.rb
@@ -13,3 +13,5 @@ module RegistrationsTracking
params.permit(:glm_source, :glm_content)
end
end
+
+RegistrationsTracking.prepend_mod
diff --git a/app/controllers/concerns/renders_notes.rb b/app/controllers/concerns/renders_notes.rb
index f8e3717acee..889d3f0a9d2 100644
--- a/app/controllers/concerns/renders_notes.rb
+++ b/app/controllers/concerns/renders_notes.rb
@@ -24,13 +24,13 @@ module RendersNotes
# rubocop: disable CodeReuse/ActiveRecord
def preload_noteable_for_regular_notes(notes)
- ActiveRecord::Associations::Preloader.new.preload(notes.reject(&:for_commit?), :noteable)
+ ActiveRecord::Associations::Preloader.new(records: notes.reject(&:for_commit?), associations: :noteable).call
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def preload_author_status(notes)
- ActiveRecord::Associations::Preloader.new.preload(notes, { author: :status })
+ ActiveRecord::Associations::Preloader.new(records: notes, associations: { author: :status }).call
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/controllers/concerns/renders_projects_list.rb b/app/controllers/concerns/renders_projects_list.rb
index 05bd9972ee7..739b2be3fe9 100644
--- a/app/controllers/concerns/renders_projects_list.rb
+++ b/app/controllers/concerns/renders_projects_list.rb
@@ -8,6 +8,7 @@ module RendersProjectsList
# once when the entities are rendered
projects.each(&:forks_count)
projects.each(&:open_issues_count)
+ projects.each(&:open_merge_requests_count)
projects
end
diff --git a/app/controllers/concerns/sorting_preference.rb b/app/controllers/concerns/sorting_preference.rb
index 300c1d6d779..3dc1780d6fe 100644
--- a/app/controllers/concerns/sorting_preference.rb
+++ b/app/controllers/concerns/sorting_preference.rb
@@ -90,6 +90,10 @@ module SortingPreference
return false unless sort_order
return can_sort_by_issue_weight?(action_name == 'issues') if sort_order.include?('weight')
+ if sort_order.include?('merged_at')
+ return can_sort_by_merged_date?(controller_name == 'merge_requests' || action_name == 'merge_requests')
+ end
+
true
end
end
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index 308da018a42..e53d0bc65a0 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -9,7 +9,6 @@ module UploadsActions
included do
prepend_before_action :set_request_format_from_path_extension
- skip_before_action :default_cache_headers, only: :show
rescue_from FileUploader::InvalidSecret, with: :render_404
end
diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb
index 2b781c528ad..ebcce635945 100644
--- a/app/controllers/concerns/wiki_actions.rb
+++ b/app/controllers/concerns/wiki_actions.rb
@@ -11,6 +11,15 @@ module WikiActions
RESCUE_GIT_TIMEOUTS_IN = %w[show edit history diff pages].freeze
included do
+ content_security_policy do |p|
+ next if p.directives.blank?
+
+ default_frame_src = p.directives['frame-src'] || p.directives['default-src']
+ frame_src_values = Array.wrap(default_frame_src) | ['https://embed.diagrams.net'].compact
+
+ p.frame_src(*frame_src_values)
+ end
+
before_action { respond_to :html }
before_action :authorize_read_wiki!
@@ -37,9 +46,7 @@ module WikiActions
end
end
- # NOTE: We want to include wiki page views in the same counter as the other
- # Event-based wiki actions tracked through TrackUniqueEvents, so we use the same event name.
- track_redis_hll_event :show, name: Gitlab::UsageDataCounters::TrackUniqueEvents::WIKI_ACTION.to_s
+ track_redis_hll_event :show, name: 'wiki_action'
helper_method :view_file_button, :diff_file_html_data
@@ -142,8 +149,7 @@ module WikiActions
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def history
if page
- @commits = Kaminari.paginate_array(page.versions(page: params[:page].to_i),
- total_count: page.count_versions)
+ @commits = Kaminari.paginate_array(page.versions(page: params[:page].to_i), total_count: page.count_versions)
.page(params[:page])
render 'shared/wikis/history'
@@ -178,8 +184,7 @@ module WikiActions
if response.success?
flash[:toast] = _("Wiki page was successfully deleted.")
- redirect_to wiki_path(wiki),
- status: :found
+ redirect_to wiki_path(wiki), status: :found
else
@error = response.message
render 'shared/wikis/edit'
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index 6dd4d72bbc7..e94138c4d9b 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -10,7 +10,7 @@ class ConfirmationsController < Devise::ConfirmationsController
prepend_before_action :check_recaptcha, only: :create
before_action :load_recaptcha, only: :new
- feature_category :authentication_and_authorization
+ feature_category :user_management
def almost_there
flash[:notice] = nil
@@ -20,12 +20,12 @@ class ConfirmationsController < Devise::ConfirmationsController
protected
def after_resending_confirmation_instructions_path_for(resource)
- return users_almost_there_path unless Feature.enabled?(:soft_email_confirmation)
+ return users_almost_there_path unless Gitlab::CurrentSettings.email_confirmation_setting_soft?
stored_location_for(resource) || dashboard_projects_path
end
- def after_confirmation_path_for(resource_name, resource)
+ def after_confirmation_path_for(_resource_name, resource)
accept_pending_invitations
# incoming resource can either be a :user or an :email
@@ -34,10 +34,14 @@ class ConfirmationsController < Devise::ConfirmationsController
else
Gitlab::AppLogger.info("Email Confirmed: username=#{resource.username} email=#{resource.email} ip=#{request.remote_ip}")
flash[:notice] = flash[:notice] + _(" Please sign in.")
- new_session_path(:user, anchor: 'login-pane', invite_email: resource.email)
+ sign_in_path(resource)
end
end
+ def sign_in_path(user)
+ new_session_path(:user, anchor: 'login-pane', invite_email: resource.email)
+ end
+
def check_recaptcha
return unless resource_params[:email].present?
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 89d362c88a4..645b3eb9eb5 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -66,8 +66,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
def load_projects(finder_params)
- @total_user_projects_count = ProjectsFinder.new(params: { non_public: true, not_aimed_for_deletion: true }, current_user: current_user).execute
- @total_starred_projects_count = ProjectsFinder.new(params: { starred: true, not_aimed_for_deletion: true }, current_user: current_user).execute
+ @total_user_projects_count = ProjectsFinder.new(params: { non_public: true, archived: false, not_aimed_for_deletion: true }, current_user: current_user).execute
+ @total_starred_projects_count = ProjectsFinder.new(params: { starred: true, archived: false, not_aimed_for_deletion: true }, current_user: current_user).execute
finder_params[:use_cte] = true if use_cte_for_finder?
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 3005d19f8ed..a1b8dbcd304 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -29,9 +29,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
respond_to do |format|
format.html do
- redirect_to dashboard_todos_path,
- status: :found,
- notice: _('To-do item successfully marked as done.')
+ redirect_to dashboard_todos_path, status: :found, notice: _('To-do item successfully marked as done.')
end
format.js { head :ok }
format.json { render json: todos_counts }
diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb
index ac355b861b3..96a7b5b144d 100644
--- a/app/controllers/explore/groups_controller.rb
+++ b/app/controllers/explore/groups_controller.rb
@@ -7,7 +7,12 @@ class Explore::GroupsController < Explore::ApplicationController
urgency :low
def index
- user = Feature.enabled?(:generic_explore_groups, current_user, type: :experiment) ? nil : current_user
+ # For gitlab.com, including internal visibility groups here causes
+ # a major performance issue: https://gitlab.com/gitlab-org/gitlab/-/issues/358944
+ #
+ # For self-hosted users, not including internal groups here causes
+ # a lack of visibility: https://gitlab.com/gitlab-org/gitlab/-/issues/389041
+ user = Gitlab.com? ? nil : current_user
render_group_tree GroupsFinder.new(user).execute
end
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 2f01bdecd23..bf59a0a2400 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -102,6 +102,10 @@ class GraphqlController < ApplicationController
private
+ def permitted_params
+ params.permit(_json: [:query, :operationName, { variables: {} }])
+ end
+
def disallow_mutations_for_get
return unless request.get? || request.head?
return unless any_mutating_query?
@@ -111,7 +115,7 @@ class GraphqlController < ApplicationController
def limit_query_size
total_size = if multiplex?
- params[:_json].sum { _1[:query].size }
+ multiplex_param.sum { _1[:query].size }
else
query.size
end
@@ -178,8 +182,12 @@ class GraphqlController < ApplicationController
params.fetch(:query, '')
end
+ def multiplex_param
+ permitted_params[:_json]
+ end
+
def multiplex_queries
- params[:_json].map do |single_query_info|
+ multiplex_param.map do |single_query_info|
{
query: single_query_info[:query],
variables: build_variables(single_query_info[:variables]),
@@ -207,7 +215,7 @@ class GraphqlController < ApplicationController
end
def multiplex?
- params[:_json].present?
+ multiplex_param.present?
end
def authorize_access_api!
diff --git a/app/controllers/groups/children_controller.rb b/app/controllers/groups/children_controller.rb
index d10c52f0301..ca3be1542aa 100644
--- a/app/controllers/groups/children_controller.rb
+++ b/app/controllers/groups/children_controller.rb
@@ -5,6 +5,8 @@ module Groups
extend ::Gitlab::Utils::Override
before_action :group
+ before_action :validate_per_page
+
skip_cross_project_access_check :index
feature_category :subgroups
@@ -41,10 +43,11 @@ module Groups
protected
def setup_children(parent)
- @children = GroupDescendantsFinder.new(current_user: current_user,
- parent_group: parent,
- params: params.to_unsafe_h).execute
- @children = @children.page(params[:page])
+ @children = GroupDescendantsFinder.new(
+ current_user: current_user,
+ parent_group: parent,
+ params: group_descendants_params
+ ).execute.page(params[:page])
end
private
@@ -53,5 +56,25 @@ module Groups
def has_project_list?
true
end
+
+ def group_descendants_params
+ @group_descendants_params ||= params.to_unsafe_h.compact
+ end
+
+ def validate_per_page
+ return unless group_descendants_params.key?(:per_page)
+
+ per_page = begin
+ Integer(group_descendants_params[:per_page])
+ rescue ArgumentError, TypeError
+ 0
+ end
+
+ respond_to do |format|
+ format.json do
+ render status: :bad_request, json: { message: 'per_page does not have a valid value' } if per_page < 1
+ end
+ end
+ end
end
end
diff --git a/app/controllers/groups/dependency_proxy_for_containers_controller.rb b/app/controllers/groups/dependency_proxy_for_containers_controller.rb
index 427df9a7129..1b1aed0ec2e 100644
--- a/app/controllers/groups/dependency_proxy_for_containers_controller.rb
+++ b/app/controllers/groups/dependency_proxy_for_containers_controller.rb
@@ -172,6 +172,6 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy
end
def manifest_header
- token_header.merge(Accept: ::ContainerRegistry::Client::ACCEPTED_TYPES)
+ token_header.merge(Accept: ::DependencyProxy::Manifest::ACCEPTED_TYPES)
end
end
diff --git a/app/controllers/groups/group_links_controller.rb b/app/controllers/groups/group_links_controller.rb
index cc2ca728592..c74c48a960d 100644
--- a/app/controllers/groups/group_links_controller.rb
+++ b/app/controllers/groups/group_links_controller.rb
@@ -7,7 +7,7 @@ class Groups::GroupLinksController < Groups::ApplicationController
feature_category :subgroups
def update
- Groups::GroupLinks::UpdateService.new(@group_link).execute(group_link_params)
+ Groups::GroupLinks::UpdateService.new(@group_link, current_user).execute(group_link_params)
if @group_link.expires?
render json: {
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index f0b857ca4c9..685c8292787 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -18,8 +18,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
skip_before_action :check_two_factor_requirement, only: :leave
skip_cross_project_access_check :index, :update, :destroy, :request_access,
- :approve_access_request, :leave, :resend_invite,
- :override
+ :approve_access_request, :leave, :resend_invite, :override
feature_category :subgroups
urgency :low
@@ -73,7 +72,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
end
def filter_params
- params.permit(:two_factor, :search).merge(sort: @sort)
+ params.permit(:two_factor, :search, :user_type).merge(sort: @sort)
end
def membershipable_members
diff --git a/app/controllers/groups/observability_controller.rb b/app/controllers/groups/observability_controller.rb
index 726af00a10e..525407f5849 100644
--- a/app/controllers/groups/observability_controller.rb
+++ b/app/controllers/groups/observability_controller.rb
@@ -30,7 +30,7 @@ module Groups
end
def check_observability_allowed
- render_404 unless Gitlab::Observability.observability_enabled?(current_user, group)
+ render_404 unless Gitlab::Observability.allowed_for_action?(current_user, group, params[:action])
end
end
end
diff --git a/app/controllers/groups/settings/access_tokens_controller.rb b/app/controllers/groups/settings/access_tokens_controller.rb
index d86ddcfe2d0..ff07e881bfa 100644
--- a/app/controllers/groups/settings/access_tokens_controller.rb
+++ b/app/controllers/groups/settings/access_tokens_controller.rb
@@ -7,7 +7,7 @@ module Groups
include AccessTokensActions
layout 'group_settings'
- feature_category :authentication_and_authorization
+ feature_category :system_access
alias_method :resource, :group
diff --git a/app/controllers/groups/settings/applications_controller.rb b/app/controllers/groups/settings/applications_controller.rb
index 3557d485422..2bf5c95937b 100644
--- a/app/controllers/groups/settings/applications_controller.rb
+++ b/app/controllers/groups/settings/applications_controller.rb
@@ -6,18 +6,16 @@ module Groups
include OauthApplications
prepend_before_action :authorize_admin_group!
- before_action :set_application, only: [:show, :edit, :update, :destroy]
+ before_action :set_application, only: [:show, :edit, :update, :renew, :destroy]
before_action :load_scopes, only: [:index, :create, :edit, :update]
- feature_category :authentication_and_authorization
+ feature_category :system_access
def index
set_index_vars
end
- def show
- @created = get_created_session if Feature.disabled?('hash_oauth_secrets')
- end
+ def show; end
def edit
end
@@ -28,15 +26,8 @@ module Groups
if @application.persisted?
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
- if Feature.enabled?('hash_oauth_secrets')
-
- @created = true
- render :show
- else
- set_created_session
-
- redirect_to group_settings_application_url(@group, @application)
- end
+ @created = true
+ render :show
else
set_index_vars
render :index
@@ -51,6 +42,17 @@ module Groups
end
end
+ def renew
+ @application.renew_secret
+
+ if @application.save
+ flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
+ render :show
+ else
+ redirect_to group_settings_application_url(@group, @application)
+ end
+ end
+
def destroy
@application.destroy
redirect_to group_settings_applications_url(@group), status: :found, notice: _('Application was successfully destroyed.')
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index 78e3ffa4af9..4bbaf92b126 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -12,6 +12,11 @@ module Groups
before_action :assign_variables_to_gon, only: [:show]
feature_category :continuous_integration
+
+ before_action do
+ push_frontend_feature_flag(:ci_variables_pages, current_user)
+ end
+
urgency :low
def show
diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb
index 9ddf6c80c70..7aea5e1a5c9 100644
--- a/app/controllers/groups/variables_controller.rb
+++ b/app/controllers/groups/variables_controller.rb
@@ -6,7 +6,7 @@ module Groups
skip_cross_project_access_check :show, :update
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
urgency :low, [:show]
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 8f7a2c177b7..a0c82998108 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -46,8 +46,7 @@ class GroupsController < Groups::ApplicationController
helper_method :captcha_required?
- skip_cross_project_access_check :index, :new, :create, :edit, :update,
- :destroy, :projects
+ skip_cross_project_access_check :index, :new, :create, :edit, :update, :destroy, :projects
# When loading show as an atom feed, we render events that could leak cross
# project information
skip_cross_project_access_check :show, if: -> { request.format.html? }
@@ -76,6 +75,7 @@ class GroupsController < Groups::ApplicationController
end
def new
+ @parent_group = Group.find_by_id(params[:parent_id])
@group = Group.new(params.permit(:parent_id))
@group.build_namespace_settings
end
@@ -201,7 +201,7 @@ class GroupsController < Groups::ApplicationController
send_upload(@group.export_file, attachment: @group.export_file.filename)
else
redirect_to edit_group_path(@group),
- alert: _('The file containing the export is not available yet; it may still be transferring. Please try again later.')
+ alert: _('The file containing the export is not available yet; it may still be transferring. Please try again later.')
end
else
redirect_to edit_group_path(@group),
diff --git a/app/controllers/ide_controller.rb b/app/controllers/ide_controller.rb
index d0e14000d8e..18c6f0bb9d3 100644
--- a/app/controllers/ide_controller.rb
+++ b/app/controllers/ide_controller.rb
@@ -10,7 +10,6 @@ class IdeController < ApplicationController
before_action do
push_frontend_feature_flag(:build_service_proxy)
push_frontend_feature_flag(:reject_unsigned_commits_by_gitlab)
- define_index_vars
end
feature_category :web_ide
@@ -20,9 +19,9 @@ class IdeController < ApplicationController
def index
Gitlab::UsageDataCounters::WebIdeCounter.increment_views_count
- if project && Feature.enabled?(:route_hll_to_snowplow_phase2, project&.namespace)
- Gitlab::Tracking.event(self.class.to_s, 'web_ide_views',
- namespace: project&.namespace, user: current_user)
+ if project
+ Gitlab::Tracking.event(self.class.to_s, 'web_ide_views', namespace: project.namespace, user: current_user)
+ @fork_info = fork_info(project, params[:branch])
end
render layout: 'fullscreen', locals: { minimal: helpers.use_new_web_ide? }
@@ -34,15 +33,6 @@ class IdeController < ApplicationController
render_404 unless can?(current_user, :read_project, project)
end
- def define_index_vars
- return unless project
-
- @branch = params[:branch]
- @path = params[:path]
- @merge_request = params[:merge_request_id]
- @fork_info = fork_info(project, @branch)
- end
-
def fork_info(project, branch)
return if can?(current_user, :push_code, project)
diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb
index f4eea3abd32..d7d7ad84bc8 100644
--- a/app/controllers/import/bulk_imports_controller.rb
+++ b/app/controllers/import/bulk_imports_controller.rb
@@ -5,9 +5,6 @@ class Import::BulkImportsController < ApplicationController
before_action :ensure_bulk_import_enabled
before_action :verify_blocked_uri, only: :status
- before_action only: :status do
- push_frontend_feature_flag(:bulk_import_projects)
- end
feature_category :importers
urgency :low
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
index 77043e174b4..9ee8e59053f 100644
--- a/app/controllers/import/fogbugz_controller.rb
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -19,7 +19,7 @@ class Import::FogbugzController < Import::BaseController
# If the URI is invalid various errors can occur
return redirect_to new_import_fogbugz_path(namespace_id: params[:namespace_id]), alert: _('Could not connect to FogBugz, check your URL')
end
- session[:fogbugz_token] = res.get_token
+ session[:fogbugz_token] = res.get_token.to_s
session[:fogbugz_uri] = params[:uri]
redirect_to new_user_map_import_fogbugz_path(namespace_id: params[:namespace_id])
diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb
index 61e32650db3..047c273969c 100644
--- a/app/controllers/import/gitea_controller.rb
+++ b/app/controllers/import/gitea_controller.rb
@@ -71,6 +71,11 @@ class Import::GiteaController < Import::GithubController
end
end
+ override :serialized_imported_projects
+ def serialized_imported_projects(projects = already_added_projects)
+ ProjectSerializer.new.represent(projects, serializer: :import, provider_url: provider_url)
+ end
+
override :client_repos
def client_repos
@client_repos ||= filtered(client.repos)
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index 0bee1faccf5..f0a80593926 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -53,7 +53,8 @@ class Import::GithubController < Import::BaseController
render json: { imported_projects: serialized_imported_projects,
provider_repos: serialized_provider_repos,
incompatible_repos: serialized_incompatible_repos,
- page_info: client_repos_response[:page_info] }
+ page_info: client_repos_response[:page_info],
+ provider_repo_count: client_repos_response[:count] }
end
format.html do
@@ -110,6 +111,14 @@ class Import::GithubController < Import::BaseController
render json: canceled
end
+ def counts
+ render json: {
+ owned: client_proxy.count_repos_by('owned', current_user.id),
+ collaborated: client_proxy.count_repos_by('collaborated', current_user.id),
+ organization: client_proxy.count_repos_by('organization', current_user.id)
+ }
+ end
+
protected
override :importable_repos
@@ -145,7 +154,10 @@ class Import::GithubController < Import::BaseController
end
def serialized_imported_projects(projects = already_added_projects)
- ProjectSerializer.new.represent(projects, serializer: :import, provider_url: provider_url)
+ ProjectSerializer.new.represent(
+ projects,
+ serializer: :import, provider_url: provider_url, client: client_proxy
+ )
end
def expire_etag_cache
@@ -245,11 +257,7 @@ class Import::GithubController < Import::BaseController
{
before: params[:before].presence,
after: params[:after].presence,
- first: PAGE_LENGTH,
- # TODO: remove after rollout FF github_client_fetch_repos_via_graphql
- # https://gitlab.com/gitlab-org/gitlab/-/issues/385649
- page: [1, params[:page].to_i].max,
- per_page: PAGE_LENGTH
+ first: PAGE_LENGTH
}
end
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index 2a7f2d42e2a..0a2c98af8ec 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -13,7 +13,7 @@ class InvitesController < ApplicationController
respond_to :html
- feature_category :authentication_and_authorization
+ feature_category :system_access
def show
accept if skip_invitation_prompt?
diff --git a/app/controllers/jira_connect/public_keys_controller.rb b/app/controllers/jira_connect/public_keys_controller.rb
index 4505ab16926..8cb932c087f 100644
--- a/app/controllers/jira_connect/public_keys_controller.rb
+++ b/app/controllers/jira_connect/public_keys_controller.rb
@@ -22,8 +22,6 @@ module JiraConnect
end
def public_key_storage_enabled?
- return true if Gitlab.config.jira_connect.enable_public_keys_storage
-
Gitlab::CurrentSettings.jira_connect_public_key_storage_enabled?
end
end
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index 7211eebdb4b..d299613f498 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -8,7 +8,7 @@ class JwtController < ApplicationController
# Add this before other actions, since we want to have the user or project
prepend_before_action :auth_user, :authenticate_project_or_user
- feature_category :authentication_and_authorization
+ feature_category :system_access
# https://gitlab.com/gitlab-org/gitlab/-/issues/357037
urgency :low
diff --git a/app/controllers/metrics_controller.rb b/app/controllers/metrics_controller.rb
index bfd6181a940..3dfa8d7b11e 100644
--- a/app/controllers/metrics_controller.rb
+++ b/app/controllers/metrics_controller.rb
@@ -10,9 +10,10 @@ class MetricsController < ActionController::Base
response = if Gitlab::Metrics.prometheus_metrics_enabled?
metrics_service.metrics_text
else
- help_page = help_page_url('administration/monitoring/prometheus/gitlab_metrics',
- anchor: 'gitlab-prometheus-metrics'
- )
+ help_page = help_page_url(
+ 'administration/monitoring/prometheus/gitlab_metrics',
+ anchor: 'gitlab-prometheus-metrics'
+ )
"# Metrics are disabled, see: #{help_page}\n"
end
diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb
index 3b78b997da1..7a31738188a 100644
--- a/app/controllers/oauth/applications_controller.rb
+++ b/app/controllers/oauth/applications_controller.rb
@@ -23,9 +23,7 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
set_index_vars
end
- def show
- @created = get_created_session if Feature.disabled?('hash_oauth_secrets')
- end
+ def show; end
def create
@application = Applications::CreateService.new(current_user, application_params).execute(request)
@@ -33,20 +31,27 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
if @application.persisted?
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
- if Feature.enabled?('hash_oauth_secrets')
- @created = true
- render :show
- else
- set_created_session
-
- redirect_to oauth_application_url(@application)
- end
+ @created = true
+ render :show
else
set_index_vars
render :index
end
end
+ def renew
+ set_application
+
+ @application.renew_secret
+
+ if @application.save
+ flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
+ render :show
+ else
+ redirect_to oauth_application_url(@application)
+ end
+ end
+
private
def verify_user_oauth_applications_enabled
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
index 43bf895ea76..96a3fab7e1a 100644
--- a/app/controllers/oauth/authorizations_controller.rb
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -108,8 +108,10 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
end
def dangerous_scopes?
- doorkeeper_application&.includes_scope?(*::Gitlab::Auth::API_SCOPE, *::Gitlab::Auth::READ_API_SCOPE,
- *::Gitlab::Auth::ADMIN_SCOPES, *::Gitlab::Auth::REPOSITORY_SCOPES,
- *::Gitlab::Auth::REGISTRY_SCOPES) && !doorkeeper_application&.trusted?
+ doorkeeper_application&.includes_scope?(
+ *::Gitlab::Auth::API_SCOPE, *::Gitlab::Auth::READ_API_SCOPE,
+ *::Gitlab::Auth::ADMIN_SCOPES, *::Gitlab::Auth::REPOSITORY_SCOPES,
+ *::Gitlab::Auth::REGISTRY_SCOPES
+ ) && !doorkeeper_application&.trusted?
end
end
diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb
index 3f476c0d717..6fc2eb6bc45 100644
--- a/app/controllers/oauth/authorized_applications_controller.rb
+++ b/app/controllers/oauth/authorized_applications_controller.rb
@@ -20,7 +20,7 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
end
redirect_to applications_profile_url,
- status: :found,
- notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
+ status: :found,
+ notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
end
end
diff --git a/app/controllers/oauth/jira_dvcs/authorizations_controller.rb b/app/controllers/oauth/jira_dvcs/authorizations_controller.rb
index 03921761f45..82a6784d2d1 100644
--- a/app/controllers/oauth/jira_dvcs/authorizations_controller.rb
+++ b/app/controllers/oauth/jira_dvcs/authorizations_controller.rb
@@ -16,10 +16,12 @@ class Oauth::JiraDvcs::AuthorizationsController < ApplicationController
def new
session[:redirect_uri] = params['redirect_uri']
- redirect_to oauth_authorization_path(client_id: params['client_id'],
- response_type: 'code',
- scope: normalize_scope(params['scope']),
- redirect_uri: oauth_jira_dvcs_callback_url)
+ redirect_to oauth_authorization_path(
+ client_id: params['client_id'],
+ response_type: 'code',
+ scope: normalize_scope(params['scope']),
+ redirect_uri: oauth_jira_dvcs_callback_url
+ )
end
# 2. Handle the callback call as we were a Github Enterprise instance client.
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 4046433f8ea..daed4023d02 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -12,7 +12,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
protect_from_forgery except: [:cas3, :failure] + AuthHelper.saml_providers, with: :exception, prepend: true
- feature_category :authentication_and_authorization
+ feature_category :system_access
def handle_omniauth
omniauth_flow(Gitlab::Auth::OAuth)
@@ -22,6 +22,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
alias_method provider, :handle_omniauth
end
+ # overridden in EE
+ def openid_connect
+ handle_omniauth
+ end
+
# Extend the standard implementation to also increment
# the number of failed sign in attempts
def failure
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index 38cdb16c350..38839497fb6 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -12,7 +12,7 @@ class PasswordsController < Devise::PasswordsController
before_action :check_password_authentication_available, only: [:create]
before_action :throttle_reset, only: [:create]
- feature_category :authentication_and_authorization
+ feature_category :system_access
# rubocop: disable CodeReuse/ActiveRecord
def edit
diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb
index cb8b2783000..eb64016379d 100644
--- a/app/controllers/profiles/accounts_controller.rb
+++ b/app/controllers/profiles/accounts_controller.rb
@@ -3,7 +3,7 @@
class Profiles::AccountsController < Profiles::ApplicationController
include AuthHelper
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :low, [:show]
def show
diff --git a/app/controllers/profiles/active_sessions_controller.rb b/app/controllers/profiles/active_sessions_controller.rb
index 2607ba7d404..5a86179b89f 100644
--- a/app/controllers/profiles/active_sessions_controller.rb
+++ b/app/controllers/profiles/active_sessions_controller.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Profiles::ActiveSessionsController < Profiles::ApplicationController
- feature_category :authentication_and_authorization
+ feature_category :system_access
def index
@sessions = ActiveSession.list(current_user).reject(&:is_impersonated)
diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb
index c88616b6d6c..28a57ef19f6 100644
--- a/app/controllers/profiles/emails_controller.rb
+++ b/app/controllers/profiles/emails_controller.rb
@@ -3,9 +3,9 @@
class Profiles::EmailsController < Profiles::ApplicationController
before_action :find_email, only: [:destroy, :resend_confirmation_instructions]
before_action -> { check_rate_limit!(:profile_add_new_email, scope: current_user, redirect_back: true) },
- only: [:create]
+ only: [:create]
before_action -> { check_rate_limit!(:profile_resend_email_confirmation, scope: current_user, redirect_back: true) },
- only: [:resend_confirmation_instructions]
+ only: [:resend_confirmation_instructions]
feature_category :user_profile
urgency :low, [:index]
diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb
index 9323d266cd5..b663a75f04a 100644
--- a/app/controllers/profiles/notifications_controller.rb
+++ b/app/controllers/profiles/notifications_controller.rb
@@ -43,7 +43,10 @@ class Profiles::NotificationsController < Profiles::ApplicationController
.preload_source_route
projects = project_notifications.map(&:source)
- ActiveRecord::Associations::Preloader.new.preload(projects, { namespace: [:route, :owner], group: [] })
+ ActiveRecord::Associations::Preloader.new(
+ records: projects,
+ associations: { namespace: [:route, :owner], group: [] }
+ ).call
Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects, current_user).execute
project_notifications.select { |notification| current_user.can?(:read_project, notification.source) }
diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb
index 738c41207d5..7a0dfbbba0d 100644
--- a/app/controllers/profiles/passwords_controller.rb
+++ b/app/controllers/profiles/passwords_controller.rb
@@ -11,7 +11,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController
layout :determine_layout
- feature_category :authentication_and_authorization
+ feature_category :system_access
def new
end
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index 1663aa61f62..4b6e2f768fa 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -3,7 +3,7 @@
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
include RenderAccessTokens
- feature_category :authentication_and_authorization
+ feature_category :system_access
before_action :check_personal_access_tokens_enabled
@@ -25,7 +25,10 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
def create
result = ::PersonalAccessTokens::CreateService.new(
- current_user: current_user, target_user: current_user, params: personal_access_token_params
+ current_user: current_user,
+ target_user: current_user,
+ params: personal_access_token_params,
+ concatenate_errors: false
).execute
@personal_access_token = result.payload[:personal_access_token]
diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb
index aded295bfab..8f482cf6e2f 100644
--- a/app/controllers/profiles/two_factor_auths_controller.rb
+++ b/app/controllers/profiles/two_factor_auths_controller.rb
@@ -8,11 +8,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
helper_method :current_password_required?
- before_action do
- push_frontend_feature_flag(:webauthn)
- end
-
- feature_category :authentication_and_authorization
+ feature_category :system_access
def show
setup_show_page
@@ -41,32 +37,12 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
@error = { message: _('Invalid pin code.') }
@qr_code = build_qr_code
@account_string = account_string
-
- if Feature.enabled?(:webauthn)
- setup_webauthn_registration
- else
- setup_u2f_registration
- end
+ setup_webauthn_registration
render 'show'
end
end
- # A U2F (universal 2nd factor) device's information is stored after successful
- # registration, which is then used while 2FA authentication is taking place.
- def create_u2f
- @u2f_registration = U2fRegistration.register(current_user, u2f_app_id, device_registration_params, session[:challenges])
-
- if @u2f_registration.persisted?
- session.delete(:challenges)
- redirect_to profile_two_factor_auth_path, notice: s_("Your U2F device was registered!")
- else
- @qr_code = build_qr_code
- setup_u2f_registration
- render :show
- end
- end
-
def create_webauthn
@webauthn_registration = Webauthn::RegisterService.new(current_user, device_registration_params, session[:challenge]).execute
@@ -175,22 +151,6 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
Gitlab.config.gitlab.host
end
- # Setup in preparation of communication with a U2F (universal 2nd factor) device
- # Actual communication is performed using a Javascript API
- def setup_u2f_registration
- @u2f_registration ||= U2fRegistration.new
- @registrations = u2f_registrations
- u2f = U2F::U2F.new(u2f_app_id)
-
- registration_requests = u2f.registration_requests
- sign_requests = u2f.authentication_requests(current_user.u2f_registrations.map(&:key_handle))
- session[:challenges] = registration_requests.map(&:challenge)
-
- gon.push(u2f: { challenges: session[:challenges], app_id: u2f_app_id,
- register_requests: registration_requests,
- sign_requests: sign_requests })
- end
-
def device_registration_params
params.require(:device_registration).permit(:device_response, :name)
end
diff --git a/app/controllers/profiles/u2f_registrations_controller.rb b/app/controllers/profiles/u2f_registrations_controller.rb
deleted file mode 100644
index 32ca303e722..00000000000
--- a/app/controllers/profiles/u2f_registrations_controller.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-class Profiles::U2fRegistrationsController < Profiles::ApplicationController
- feature_category :authentication_and_authorization
-
- def destroy
- u2f_registration = current_user.u2f_registrations.find(params[:id])
- u2f_registration.destroy
- redirect_to profile_two_factor_auth_path, status: :found, notice: _("Successfully deleted U2F device.")
- end
-end
diff --git a/app/controllers/profiles/webauthn_registrations_controller.rb b/app/controllers/profiles/webauthn_registrations_controller.rb
index a4a6d84f1ae..345d7bdbca8 100644
--- a/app/controllers/profiles/webauthn_registrations_controller.rb
+++ b/app/controllers/profiles/webauthn_registrations_controller.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Profiles::WebauthnRegistrationsController < Profiles::ApplicationController
- feature_category :authentication_and_authorization
+ feature_category :system_access
def destroy
webauthn_registration = current_user.webauthn_registrations.find(params[:id])
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 45b274fc920..70487915707 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -17,7 +17,7 @@ class ProfilesController < Profiles::ApplicationController
feature_category :user_profile, [:show, :update, :reset_incoming_email_token, :reset_feed_token,
:reset_static_object_token, :update_username]
- feature_category :authentication_and_authorization, [:audit_log]
+ feature_category :system_access, [:audit_log]
urgency :low, [:show, :update]
def show
diff --git a/app/controllers/projects/airflow/dags_controller.rb b/app/controllers/projects/airflow/dags_controller.rb
deleted file mode 100644
index 9d1f0b0d63b..00000000000
--- a/app/controllers/projects/airflow/dags_controller.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module Projects
- module Airflow
- class DagsController < ::Projects::ApplicationController
- before_action :check_feature_flag
- before_action :authorize_read_airflow_dags!
-
- feature_category :dataops
-
- MAX_DAGS_PER_PAGE = 15
- def index
- page = params[:page].to_i
- page = 1 if page <= 0
-
- @dags = ::Airflow::Dags.by_project_id(@project.id)
-
- return unless @dags.any?
-
- @dags = @dags.page(page).per(MAX_DAGS_PER_PAGE)
- return redirect_to(url_for(page: @dags.total_pages)) if @dags.out_of_range?
-
- @pagination = {
- page: page,
- is_last_page: @dags.last_page?,
- per_page: MAX_DAGS_PER_PAGE,
- total_items: @dags.total_count
- }
- end
-
- private
-
- def check_feature_flag
- render_404 unless Feature.enabled?(:airflow_dags, @project)
- end
- end
- end
-end
diff --git a/app/controllers/projects/analytics/cycle_analytics/stages_controller.rb b/app/controllers/projects/analytics/cycle_analytics/stages_controller.rb
index a61b774f9c8..e9477ee3221 100644
--- a/app/controllers/projects/analytics/cycle_analytics/stages_controller.rb
+++ b/app/controllers/projects/analytics/cycle_analytics/stages_controller.rb
@@ -20,6 +20,11 @@ class Projects::Analytics::CycleAnalytics::StagesController < Projects::Applicat
@project.project_namespace
end
+ override :all_cycle_analytics_params
+ def all_cycle_analytics_params
+ super.merge({ namespace: @project.project_namespace })
+ end
+
override :cycle_analytics_configuration
def cycle_analytics_configuration(stages)
super(stages.select { |stage| permitted_stage?(stage) })
diff --git a/app/controllers/projects/analytics/cycle_analytics/summary_controller.rb b/app/controllers/projects/analytics/cycle_analytics/summary_controller.rb
index 69327feeb02..96d7ad79e88 100644
--- a/app/controllers/projects/analytics/cycle_analytics/summary_controller.rb
+++ b/app/controllers/projects/analytics/cycle_analytics/summary_controller.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class Projects::Analytics::CycleAnalytics::SummaryController < Projects::ApplicationController
+ extend ::Gitlab::Utils::Override
include CycleAnalyticsParams
respond_to :json
@@ -17,6 +18,11 @@ class Projects::Analytics::CycleAnalytics::SummaryController < Projects::Applica
private
+ override :all_cycle_analytics_params
+ def all_cycle_analytics_params
+ super.merge({ namespace: @project.project_namespace })
+ end
+
def project_level
@project_level ||= Analytics::CycleAnalytics::ProjectLevel.new(project: @project, options: options(allowed_params))
end
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index 5f8060ad756..65576bcade6 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -19,6 +19,10 @@ class Projects::ArtifactsController < Projects::ApplicationController
before_action :validate_artifacts!, except: [:index, :download, :raw, :destroy]
before_action :entry, only: [:external_file, :file]
+ before_action only: :index do
+ push_frontend_feature_flag(:ci_job_artifact_bulk_destroy, @project)
+ end
+
MAX_PER_PAGE = 20
feature_category :build_artifacts
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index 70d9b524e4d..5db7609e07a 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -3,8 +3,6 @@
class Projects::AvatarsController < Projects::ApplicationController
include SendsBlob
- skip_before_action :default_cache_headers, only: :show
-
before_action :authorize_admin_project!, only: [:destroy]
feature_category :projects
diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb
index dbbffc4c283..372da64cdfa 100644
--- a/app/controllers/projects/badges_controller.rb
+++ b/app/controllers/projects/badges_controller.rb
@@ -40,6 +40,7 @@ class Projects::BadgesController < Projects::ApplicationController
.new(project, current_user, opts: {
key_text: params[:key_text],
key_width: params[:key_width],
+ value_width: params[:value_width],
order_by: params[:order_by]
})
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index cfff281604e..d41b347dc5a 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -23,13 +23,47 @@ class Projects::BlameController < Projects::ApplicationController
environment_params[:find_latest] = true
@environment = ::Environments::EnvironmentsByDeploymentsFinder.new(@project, current_user, environment_params).execute.last
- blame_service = Projects::BlameService.new(@blob, @commit, params.permit(:page, :no_pagination))
+ permitted_params = params.permit(:page, :no_pagination, :streaming)
+ blame_service = Projects::BlameService.new(@blob, @commit, permitted_params)
@blame = Gitlab::View::Presenter::Factory.new(blame_service.blame, project: @project, path: @path, page: blame_service.page).fabricate!
- @blame_pagination = blame_service.pagination
+ @entire_blame_path = full_blame_path(no_pagination: true)
+ @blame_pages_url = blame_pages_url(permitted_params)
+ if blame_service.streaming_possible
+ @entire_blame_path = full_blame_path(streaming: true)
+ end
+
+ @streaming_enabled = blame_service.streaming_enabled
+ @blame_pagination = blame_service.pagination unless @streaming_enabled
@blame_per_page = blame_service.per_page
+
+ render locals: { total_extra_pages: blame_service.total_extra_pages }
+ end
+
+ def page
+ @blob = @repository.blob_at(@commit.id, @path)
+
+ environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
+ environment_params[:find_latest] = true
+ @environment = ::Environments::EnvironmentsByDeploymentsFinder.new(@project, current_user, environment_params).execute.last
+
+ blame_service = Projects::BlameService.new(@blob, @commit, params.permit(:page, :streaming))
+
+ @blame = Gitlab::View::Presenter::Factory.new(blame_service.blame, project: @project, path: @path, page: blame_service.page).fabricate!
+
+ render partial: 'page'
+ end
+
+ private
+
+ def full_blame_path(params)
+ namespace_project_blame_path(namespace_id: @project.namespace, project_id: @project, id: @id, **params)
+ end
+
+ def blame_pages_url(params)
+ namespace_project_blame_page_url(namespace_id: @project.namespace, project_id: @project, id: @id, **params)
end
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 59cea00e26b..3413aeb6f8a 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -10,7 +10,7 @@ class Projects::BlobController < Projects::ApplicationController
include RedirectsForMissingPathOnTree
include SourcegraphDecorator
include DiffHelper
- include RedisTracking
+ include ProductAnalyticsTracking
extend ::Gitlab::Utils::Override
prepend_before_action :authenticate_user!, only: [:edit]
@@ -37,7 +37,11 @@ class Projects::BlobController < Projects::ApplicationController
before_action :validate_diff_params, only: :diff
before_action :set_last_commit_sha, only: [:edit, :update]
- track_redis_hll_event :create, :update, name: 'g_edit_by_sfe'
+ track_event :create, :update,
+ name: 'g_edit_by_sfe',
+ action: 'perform_sfe_action',
+ label: 'usage_activity_by_stage_monthly.create.action_monthly_active_users_sfe_edit',
+ destinations: [:redis_hll, :snowplow]
feature_category :source_code_management
urgency :low, [:create, :show, :edit, :update, :diff]
@@ -53,10 +57,13 @@ class Projects::BlobController < Projects::ApplicationController
end
def create
- create_commit(Files::CreateService, success_notice: _("The file has been successfully created."),
- success_path: -> { project_blob_path(@project, File.join(@branch_name, @file_path)) },
- failure_view: :new,
- failure_path: project_new_blob_path(@project, @ref))
+ create_commit(
+ Files::CreateService,
+ success_notice: _("The file has been successfully created."),
+ success_path: -> { project_blob_path(@project, File.join(@branch_name, @file_path)) },
+ failure_view: :new,
+ failure_path: project_new_blob_path(@project, @ref)
+ )
end
def show
@@ -86,9 +93,11 @@ class Projects::BlobController < Projects::ApplicationController
def update
@path = params[:file_path] if params[:file_path].present?
- create_commit(Files::UpdateService, success_path: -> { after_edit_path },
- failure_view: :edit,
- failure_path: project_blob_path(@project, @id))
+ create_commit(
+ Files::UpdateService, success_path: -> { after_edit_path },
+ failure_view: :edit,
+ failure_path: project_blob_path(@project, @id)
+ )
rescue Files::UpdateService::FileChangedError
@conflict = true
render :edit
@@ -106,9 +115,12 @@ class Projects::BlobController < Projects::ApplicationController
end
def destroy
- create_commit(Files::DeleteService, success_notice: _("The file has been successfully deleted."),
- success_path: -> { after_delete_path },
- failure_path: project_blob_path(@project, @id))
+ create_commit(
+ Files::DeleteService,
+ success_notice: _("The file has been successfully deleted."),
+ success_path: -> { after_delete_path },
+ failure_path: project_blob_path(@project, @id)
+ )
end
def diff
@@ -308,6 +320,12 @@ class Projects::BlobController < Projects::ApplicationController
file = file.cdn_enabled_url(request.remote_ip) if file.respond_to?(:cdn_enabled_url)
file.url
end
+
+ alias_method :tracking_project_source, :project
+
+ def tracking_namespace_source
+ project&.namespace
+ end
end
Projects::BlobController.prepend_mod
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index f19f143816f..1e17dd586c7 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -98,7 +98,7 @@ class Projects::BranchesController < Projects::ApplicationController
if success
render json: { name: branch_name, url: project_tree_url(@project, branch_name) }
else
- render json: result[:messsage], status: :unprocessable_entity
+ render json: result[:message], status: :unprocessable_entity
end
end
end
diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb
index 7ef5016ac00..6762f1c7110 100644
--- a/app/controllers/projects/ci/lints_controller.rb
+++ b/app/controllers/projects/ci/lints_controller.rb
@@ -3,7 +3,7 @@
class Projects::Ci::LintsController < Projects::ApplicationController
before_action :authorize_create_pipeline!
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
respond_to :json, only: [:create]
urgency :low, [:create]
diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb
index 3a2bc445737..45584f3048a 100644
--- a/app/controllers/projects/ci/pipeline_editor_controller.rb
+++ b/app/controllers/projects/ci/pipeline_editor_controller.rb
@@ -6,7 +6,7 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController
push_frontend_feature_flag(:ci_job_assistant_drawer, @project)
end
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
urgency :low, [:show]
diff --git a/app/controllers/projects/ci/prometheus_metrics/histograms_controller.rb b/app/controllers/projects/ci/prometheus_metrics/histograms_controller.rb
index 003441d4b91..72a07269d79 100644
--- a/app/controllers/projects/ci/prometheus_metrics/histograms_controller.rb
+++ b/app/controllers/projects/ci/prometheus_metrics/histograms_controller.rb
@@ -4,7 +4,7 @@ module Projects
module Ci
module PrometheusMetrics
class HistogramsController < Projects::ApplicationController
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
respond_to :json, only: [:create]
diff --git a/app/controllers/projects/cluster_agents_controller.rb b/app/controllers/projects/cluster_agents_controller.rb
index 3f759e5c18c..e0c9763abb6 100644
--- a/app/controllers/projects/cluster_agents_controller.rb
+++ b/app/controllers/projects/cluster_agents_controller.rb
@@ -1,7 +1,10 @@
# frozen_string_literal: true
class Projects::ClusterAgentsController < Projects::ApplicationController
+ include KasCookie
+
before_action :authorize_can_read_cluster_agent!
+ before_action :set_kas_cookie, only: [:show], if: -> { current_user }
feature_category :kubernetes_management
urgency :low
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 252b203b38a..a86a0fb3bd2 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -115,8 +115,12 @@ class Projects::CommitController < Projects::ApplicationController
@branch_name = create_new_branch? ? @commit.revert_branch_name : @start_branch
- create_commit(Commits::RevertService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully reverted.",
- success_path: -> { successful_change_path(@project) }, failure_path: failed_change_path)
+ create_commit(
+ Commits::RevertService,
+ success_notice: "The #{@commit.change_type_title(current_user)} has been successfully reverted.",
+ success_path: -> { successful_change_path(@project) },
+ failure_path: failed_change_path
+ )
end
def cherry_pick
@@ -131,10 +135,13 @@ class Projects::CommitController < Projects::ApplicationController
@branch_name = create_new_branch? ? @commit.cherry_pick_branch_name : @start_branch
- create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully cherry-picked into #{@branch_name}.",
- success_path: -> { successful_change_path(target_project) },
- failure_path: failed_change_path,
- target_project: target_project)
+ create_commit(
+ Commits::CherryPickService,
+ success_notice: "The #{@commit.change_type_title(current_user)} has been successfully cherry-picked into #{@branch_name}.",
+ success_path: -> { successful_change_path(target_project) },
+ failure_path: failed_change_path,
+ target_project: target_project
+ )
end
private
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 3acc71d5dd3..c2f1d1ed362 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -7,7 +7,6 @@ class Projects::CommitsController < Projects::ApplicationController
include RendersCommits
COMMITS_DEFAULT_LIMIT = 40
-
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
around_action :allow_gitaly_ref_name_caching
before_action :require_non_empty_project
@@ -77,15 +76,22 @@ class Projects::CommitsController < Projects::ApplicationController
# fully_qualified_ref is available in some situations from ExtractsRef
ref = @fully_qualified_ref || @ref
+
@commits =
if search.present?
@repository.find_commits_by_message(search, ref, @path, @limit, @offset)
- elsif author.present?
- @repository.commits(ref, author: author, path: @path, limit: @limit, offset: @offset)
else
- @repository.commits(ref, path: @path, limit: @limit, offset: @offset)
+ options = {
+ path: @path,
+ limit: @limit,
+ offset: @offset
+ }
+ options[:author] = author if author.present?
+
+ @repository.commits(ref, **options)
end
+ @commits.load_tags if Feature.enabled?(:show_tags_on_commits_view, @project)
@commits.each(&:lazy_author) # preload authors
@commits = @commits.with_markdown_cache.with_latest_pipeline(ref)
diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb
index 9fe44659250..dbed5adf2e8 100644
--- a/app/controllers/projects/cycle_analytics_controller.rb
+++ b/app/controllers/projects/cycle_analytics_controller.rb
@@ -11,7 +11,7 @@ class Projects::CycleAnalyticsController < Projects::ApplicationController
before_action :authorize_read_cycle_analytics!
before_action :load_value_stream, only: :show
- track_custom_event :show,
+ track_event :show,
name: 'p_analytics_valuestream',
action: 'perform_analytics_usage_action',
label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly',
@@ -22,6 +22,8 @@ class Projects::CycleAnalyticsController < Projects::ApplicationController
before_action do
push_licensed_feature(:cycle_analytics_for_groups) if project.licensed_feature_available?(:cycle_analytics_for_groups)
+ push_licensed_feature(:group_level_analytics_dashboard) if project.licensed_feature_available?(:group_level_analytics_dashboard)
+ push_frontend_feature_flag(:group_analytics_dashboards_page, @project.namespace)
end
def show
@@ -44,7 +46,7 @@ class Projects::CycleAnalyticsController < Projects::ApplicationController
override :all_cycle_analytics_params
def all_cycle_analytics_params
- super.merge({ project: @project, value_stream: @value_stream })
+ super.merge({ namespace: @project.project_namespace, value_stream: @value_stream })
end
def load_value_stream
diff --git a/app/controllers/projects/design_management/designs/raw_images_controller.rb b/app/controllers/projects/design_management/designs/raw_images_controller.rb
index beb7e9d294b..ea406d2f2ef 100644
--- a/app/controllers/projects/design_management/designs/raw_images_controller.rb
+++ b/app/controllers/projects/design_management/designs/raw_images_controller.rb
@@ -7,8 +7,6 @@ module Projects
class RawImagesController < Projects::DesignManagement::DesignsController
include SendsBlob
- skip_before_action :default_cache_headers, only: :show
-
def show
blob = design_repository.blob_at(ref, design.full_path)
diff --git a/app/controllers/projects/design_management/designs/resized_image_controller.rb b/app/controllers/projects/design_management/designs/resized_image_controller.rb
index 6bf304419e1..a09d8a73892 100644
--- a/app/controllers/projects/design_management/designs/resized_image_controller.rb
+++ b/app/controllers/projects/design_management/designs/resized_image_controller.rb
@@ -10,8 +10,6 @@ module Projects
before_action :validate_size!
before_action :validate_sha!
- skip_before_action :default_cache_headers, only: :show
-
def show
relation = design.actions
relation = relation.up_to_version(version) if version
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 9a88a8160b6..ad498a4ac86 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -20,6 +20,10 @@ class Projects::EnvironmentsController < Projects::ApplicationController
push_frontend_feature_flag(:environment_details_vue, @project)
end
+ before_action only: [:index] do
+ push_frontend_feature_flag(:kas_user_access_project, @project)
+ end
+
before_action :authorize_read_environment!, except: [:metrics, :additional_metrics, :metrics_dashboard, :metrics_redirect]
before_action :authorize_create_environment!, only: [:new, :create]
before_action :authorize_stop_environment!, only: [:stop]
@@ -30,17 +34,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController
before_action :expire_etag_cache, only: [:index], unless: -> { request.format.json? }
after_action :expire_etag_cache, only: [:cancel_auto_stop]
- track_event :index,
- :folder,
- :show,
- :new,
- :edit,
- :create,
- :update,
- :stop,
- :cancel_auto_stop,
- :terminal,
- name: 'users_visiting_environments_pages'
+ track_event :index, :folder, :show, :new, :edit, :create, :update, :stop, :cancel_auto_stop, :terminal,
+ name: 'users_visiting_environments_pages'
feature_category :continuous_delivery
urgency :low
@@ -255,11 +250,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
def search_environments(type: nil)
search = params[:search] if params[:search] && params[:search].length >= MIN_SEARCH_LENGTH
- @search_environments ||=
- Environments::EnvironmentsFinder.new(project,
- current_user,
- type: type,
- search: search).execute
+ @search_environments ||= Environments::EnvironmentsFinder.new(project, current_user, type: type, search: search).execute
end
def metrics_params
@@ -301,16 +292,6 @@ class Projects::EnvironmentsController < Projects::ApplicationController
def authorize_update_environment!
access_denied! unless can?(current_user, :update_environment, environment)
end
-
- def append_info_to_payload(payload)
- super
-
- return unless Feature.enabled?(:environments_search_logging) && params[:search].present?
-
- # Merging to :metadata will ensure these are logged as top level keys
- payload[:metadata] ||= {}
- payload[:metadata]['meta.environment.search'] = params[:search]
- end
end
Projects::EnvironmentsController.prepend_mod_with('Projects::EnvironmentsController')
diff --git a/app/controllers/projects/error_tracking_controller.rb b/app/controllers/projects/error_tracking_controller.rb
index d2e36ef5496..d70ee0fabea 100644
--- a/app/controllers/projects/error_tracking_controller.rb
+++ b/app/controllers/projects/error_tracking_controller.rb
@@ -74,8 +74,7 @@ class Projects::ErrorTrackingController < Projects::ErrorTracking::BaseControlle
def render_errors(result)
unless result[:status] == :success
- render json: { message: result[:message] },
- status: result[:http_status] || :bad_request
+ render json: { message: result[:message] }, status: result[:http_status] || :bad_request
end
end
diff --git a/app/controllers/projects/feature_flags_controller.rb b/app/controllers/projects/feature_flags_controller.rb
index 16392775c09..83923965a45 100644
--- a/app/controllers/projects/feature_flags_controller.rb
+++ b/app/controllers/projects/feature_flags_controller.rb
@@ -97,23 +97,45 @@ class Projects::FeatureFlagsController < Projects::ApplicationController
end
def create_params
- params.require(:operations_feature_flag)
- .permit(:name, :description, :active, :version,
- scopes_attributes: [:environment_scope, :active,
- strategies: [:name, parameters: [:groupId, :percentage, :userIds]]],
- strategies_attributes: [:name, :user_list_id,
- parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness],
- scopes_attributes: [:environment_scope]])
+ params.require(:operations_feature_flag).permit(
+ :name,
+ :description,
+ :active,
+ :version,
+ scopes_attributes: [
+ :environment_scope, :active,
+ strategies: [:name, parameters: [:groupId, :percentage, :userIds]]
+ ],
+ strategies_attributes: [
+ :name,
+ :user_list_id,
+ parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness],
+ scopes_attributes: [:environment_scope]
+ ]
+ )
end
def update_params
- params.require(:operations_feature_flag)
- .permit(:name, :description, :active,
- scopes_attributes: [:id, :environment_scope, :active, :_destroy,
- strategies: [:name, parameters: [:groupId, :percentage, :userIds]]],
- strategies_attributes: [:id, :name, :user_list_id, :_destroy,
- parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness],
- scopes_attributes: [:id, :environment_scope, :_destroy]])
+ params.require(:operations_feature_flag).permit(
+ :name,
+ :description,
+ :active,
+ scopes_attributes: [
+ :id,
+ :environment_scope,
+ :active,
+ :_destroy,
+ strategies: [:name, parameters: [:groupId, :percentage, :userIds]]
+ ],
+ strategies_attributes: [
+ :id,
+ :name,
+ :user_list_id,
+ :_destroy,
+ parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness],
+ scopes_attributes: [:id, :environment_scope, :_destroy]
+ ]
+ )
end
def feature_flag_json(feature_flag)
@@ -144,7 +166,6 @@ class Projects::FeatureFlagsController < Projects::ApplicationController
end
def render_error_json(messages, status = :bad_request)
- render json: { message: messages },
- status: status
+ render json: { message: messages }, status: status
end
end
diff --git a/app/controllers/projects/google_cloud/base_controller.rb b/app/controllers/projects/google_cloud/base_controller.rb
index dfb73821b0f..7eccc0c1c77 100644
--- a/app/controllers/projects/google_cloud/base_controller.rb
+++ b/app/controllers/projects/google_cloud/base_controller.rb
@@ -45,8 +45,8 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController
return_url = project_google_cloud_configuration_path(project)
state = generate_session_key_redirect(request.url, return_url)
@authorize_url = GoogleApi::CloudPlatform::Client.new(nil,
- callback_google_api_auth_url,
- state: state).authorize_url
+ callback_google_api_auth_url,
+ state: state).authorize_url
redirect_to @authorize_url
end
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index d072381933a..e73e2a38149 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -9,7 +9,7 @@ class Projects::GraphsController < Projects::ApplicationController
before_action :assign_ref_vars
before_action :authorize_read_repository_graphs!
- track_custom_event :charts,
+ track_event :charts,
name: 'p_analytics_repo',
action: 'perform_analytics_usage_action',
label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly',
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 22b6bf6faf0..4dcc9a3a43f 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -4,7 +4,8 @@ class Projects::HooksController < Projects::ApplicationController
include ::WebHooks::HookActions
# Authorize
- before_action :authorize_admin_project!
+ before_action :authorize_admin_project!, except: :destroy
+ before_action :authorize_destroy_project_hook!, only: :destroy
before_action :hook_logs, only: :edit
before_action -> { check_rate_limit!(:project_testing_hook, scope: [@project, current_user]) }, only: :test
@@ -41,4 +42,8 @@ class Projects::HooksController < Projects::ApplicationController
def trigger_values
ProjectHook.triggers.values
end
+
+ def authorize_destroy_project_hook!
+ render_404 unless can?(current_user, :destroy_web_hook, hook)
+ end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 21227d62023..6e38de8b0ea 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -21,6 +21,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :check_issues_available!
before_action :issue, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) }
before_action :redirect_if_work_item, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) }
+ before_action :require_incident_for_incident_routes, only: :show
after_action :log_issue_show, only: :show
@@ -47,6 +48,7 @@ class Projects::IssuesController < Projects::ApplicationController
push_frontend_feature_flag(:preserve_unchanged_markdown, project)
push_frontend_feature_flag(:content_editor_on_issues, project)
push_frontend_feature_flag(:service_desk_new_note_email_native_attachments, project)
+ push_frontend_feature_flag(:saved_replies, current_user)
end
before_action only: [:index, :show] do
@@ -64,7 +66,6 @@ class Projects::IssuesController < 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_frontend_feature_flag(:epic_widget_edit_confirmation, project)
- push_frontend_feature_flag(:use_iid_in_work_items_path, project&.group)
push_frontend_feature_flag(:incident_event_tags, project)
end
@@ -443,11 +444,16 @@ class Projects::IssuesController < Projects::ApplicationController
def redirect_if_work_item
return unless use_work_items_path?(issue)
- if Feature.enabled?(:use_iid_in_work_items_path, project.group)
- redirect_to project_work_items_path(project, issue.iid, params: request.query_parameters.merge(iid_path: true))
- else
- redirect_to project_work_items_path(project, issue.id, params: request.query_parameters)
- end
+ redirect_to project_work_items_path(project, issue.iid, params: request.query_parameters.merge(iid_path: true))
+ end
+
+ def require_incident_for_incident_routes
+ return unless params[:incident_tab].present?
+ return if issue.incident?
+
+ # Redirect instead of 404 to gracefully handle
+ # issue type changes
+ redirect_to project_issue_path(project, issue)
end
end
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index 3fea5c694f7..36fa1fab68f 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -128,8 +128,7 @@ class Projects::JobsController < Projects::ApplicationController
service_response = Ci::BuildEraseService.new(@build, current_user).execute
if service_response.success?
- redirect_to project_job_path(project, @build),
- notice: _("Job has been successfully erased!")
+ redirect_to project_job_path(project, @build), notice: _("Job has been successfully erased!")
else
head service_response.http_status
end
@@ -138,9 +137,7 @@ class Projects::JobsController < Projects::ApplicationController
def raw
if @build.trace.archived?
workhorse_set_content_type!
- send_upload(@build.job_artifacts_trace.file,
- send_params: raw_send_params,
- redirect_params: raw_redirect_params)
+ send_upload(@build.job_artifacts_trace.file, send_params: raw_send_params, redirect_params: raw_redirect_params)
else
@build.trace.read do |stream|
if stream.file?
@@ -234,10 +231,12 @@ class Projects::JobsController < Projects::ApplicationController
end
def build_service_specification
- @build.service_specification(service: params['service'],
- port: params['port'],
- path: params['path'],
- subprotocols: proxy_subprotocol)
+ @build.service_specification(
+ service: params['service'],
+ port: params['port'],
+ path: params['path'],
+ subprotocols: proxy_subprotocol
+ )
end
def proxy_subprotocol
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 14f2e372bc5..649bead0b6d 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -82,9 +82,7 @@ class Projects::LabelsController < Projects::ApplicationController
@label.destroy
@labels = find_labels
- redirect_to project_labels_path(@project),
- status: :found,
- notice: 'Label was removed'
+ redirect_to project_labels_path(@project), status: :found, notice: 'Label was removed'
end
def remove_priority
@@ -138,8 +136,9 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to do |format|
format.html do
- redirect_to(project_labels_path(@project),
- notice: _('Failed to promote label due to internal error. Please contact administrators.'))
+ redirect_to(
+ project_labels_path(@project),
+ notice: _('Failed to promote label due to internal error. Please contact administrators.'))
end
format.js
end
@@ -165,13 +164,14 @@ class Projects::LabelsController < Projects::ApplicationController
end
def find_labels
- @available_labels ||=
- LabelsFinder.new(current_user,
- project_id: @project.id,
- include_ancestor_groups: true,
- search: params[:search],
- subscribed: params[:subscribed],
- sort: sort).execute
+ @available_labels ||= LabelsFinder.new(
+ current_user,
+ project_id: @project.id,
+ include_ancestor_groups: true,
+ search: params[:search],
+ subscribed: params[:subscribed],
+ sort: sort
+ ).execute
end
def sort
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index 3b399e3294e..3a03831ab88 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -114,11 +114,10 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
@target_project = @merge_request.target_project
@source_project = @merge_request.source_project
- @commits =
- set_commits_for_rendering(
- @merge_request.recent_commits.with_latest_pipeline(@merge_request.source_branch),
- commits_count: @merge_request.commits_count
- )
+ @commits = set_commits_for_rendering(
+ @merge_request.recent_commits.with_latest_pipeline(@merge_request.source_branch),
+ commits_count: @merge_request.commits_count
+ )
@commit = @merge_request.diff_head_commit
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index d92ef3de6d9..a204023e34d 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -33,6 +33,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
before_action only: [:show, :diffs] do
+ push_frontend_feature_flag(:content_editor_on_issues, project)
push_frontend_feature_flag(:core_security_mr_widget_counts, project)
push_frontend_feature_flag(:issue_assignees_widget, @project)
push_frontend_feature_flag(:refactor_security_extension, @project)
@@ -40,10 +41,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:moved_mr_sidebar, project)
push_frontend_feature_flag(:mr_experience_survey, project)
push_frontend_feature_flag(:realtime_mr_status_change, project)
- end
-
- before_action do
- push_frontend_feature_flag(:permit_all_shared_groups_for_approval, @project)
+ push_frontend_feature_flag(:saved_replies, current_user)
end
around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :diffs, :discussions]
@@ -383,10 +381,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@merge_request.merge_request_reviewers.map(&:cache_key)
]
- render_cached(@merge_request,
- with: serializer,
- cache_context: ->(_) { [Digest::SHA256.hexdigest(cache_context.to_s)] },
- serializer: params[:serializer])
+ render_cached(
+ @merge_request,
+ with: serializer,
+ cache_context: ->(_) { [Digest::SHA256.hexdigest(cache_context.to_s)] },
+ serializer: params[:serializer]
+ )
else
render json: serializer.represent(@merge_request, serializer: params[:serializer])
end
@@ -485,8 +485,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
AutoMergeService.new(project, current_user, merge_params).update(merge_request)
else
AutoMergeService.new(project, current_user, merge_params)
- .execute(merge_request,
- params[:auto_merge_strategy] || AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS)
+ .execute(merge_request, params[:auto_merge_strategy] || AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS)
end
else
@merge_request.merge_async(current_user.id, merge_params)
diff --git a/app/controllers/projects/pages_controller.rb b/app/controllers/projects/pages_controller.rb
index db0762a6cff..13c2a3ab750 100644
--- a/app/controllers/projects/pages_controller.rb
+++ b/app/controllers/projects/pages_controller.rb
@@ -43,9 +43,7 @@ class Projects::PagesController < Projects::ApplicationController
respond_to do |format|
format.html do
- redirect_to project_pages_path(@project),
- status: :found,
- notice: 'Pages were scheduled for removal'
+ redirect_to project_pages_path(@project), status: :found, notice: 'Pages were scheduled for removal'
end
end
end
@@ -77,7 +75,15 @@ class Projects::PagesController < Projects::ApplicationController
end
def project_params_attributes
- %i[pages_https_only]
+ attributes = %i[pages_https_only]
+
+ return attributes unless Feature.enabled?(:pages_unique_domain)
+
+ attributes + [
+ project_setting_attributes: [
+ :pages_unique_domain_enabled
+ ]
+ ]
end
end
diff --git a/app/controllers/projects/pages_domains_controller.rb b/app/controllers/projects/pages_domains_controller.rb
index 43952a2efe4..5cb69e8bf99 100644
--- a/app/controllers/projects/pages_domains_controller.rb
+++ b/app/controllers/projects/pages_domains_controller.rb
@@ -69,9 +69,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController
respond_to do |format|
format.html do
- redirect_to project_pages_path(@project),
- status: :found,
- notice: 'Domain was removed'
+ redirect_to project_pages_path(@project), status: :found, notice: 'Domain was removed'
end
format.js
end
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
index 19d031bd59b..fb332fec3b5 100644
--- a/app/controllers/projects/pipeline_schedules_controller.rb
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -8,8 +8,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
before_action :authorize_read_pipeline_schedule!
before_action :authorize_create_pipeline_schedule!, only: [:new, :create]
before_action :authorize_update_pipeline_schedule!, only: [:edit, :update]
- before_action :authorize_take_ownership_pipeline_schedule!, only: [:take_ownership]
- before_action :authorize_admin_pipeline_schedule!, only: [:destroy]
+ before_action :authorize_admin_pipeline_schedule!, only: [:take_ownership, :destroy]
before_action :push_schedule_feature_flag, only: [:index, :new, :edit]
feature_category :continuous_integration
@@ -78,9 +77,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
if schedule.destroy
redirect_to pipeline_schedules_path(@project), status: :found
else
- redirect_to pipeline_schedules_path(@project),
- status: :forbidden,
- alert: _("Failed to remove the pipeline schedule")
+ redirect_to pipeline_schedules_path(@project), status: :forbidden, alert: _("Failed to remove the pipeline schedule")
end
end
@@ -113,10 +110,6 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
return access_denied! unless can?(current_user, :update_pipeline_schedule, schedule)
end
- def authorize_take_ownership_pipeline_schedule!
- return access_denied! unless can?(current_user, :take_ownership_pipeline_schedule, schedule)
- end
-
def authorize_admin_pipeline_schedule!
return access_denied! unless can?(current_user, :admin_pipeline_schedule, schedule)
end
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 10f58a9f479..6fdd4906613 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -22,13 +22,14 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action :ensure_pipeline, only: [:show, :downloadable_artifacts]
before_action :reject_if_build_artifacts_size_refreshing!, only: [:destroy]
+ before_action :push_frontend_feature_flags, only: [:show]
# Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/225596
before_action :redirect_for_legacy_scope_filter, only: [:index], if: -> { request.format.html? }
around_action :allow_gitaly_ref_name_caching, only: [:index, :show]
- track_custom_event :charts,
+ track_event :charts,
name: 'p_analytics_pipelines',
action: 'perform_analytics_usage_action',
label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly',
@@ -98,15 +99,15 @@ class Projects::PipelinesController < Projects::ApplicationController
end
format.json do
if service_response.success?
- render json: PipelineSerializer
- .new(project: project, current_user: current_user)
- .represent(@pipeline),
- status: :created
+ render json: PipelineSerializer.new(project: project, current_user: current_user).represent(@pipeline),
+ status: :created
else
- render json: { errors: @pipeline.error_messages.map(&:content),
- warnings: @pipeline.warning_messages(limit: ::Gitlab::Ci::Warnings::MAX_LIMIT).map(&:content),
- total_warnings: @pipeline.warning_messages.length },
- status: :bad_request
+ bad_request_json = {
+ errors: @pipeline.error_messages.map(&:content),
+ warnings: @pipeline.warning_messages(limit: ::Gitlab::Ci::Warnings::MAX_LIMIT).map(&:content),
+ total_warnings: @pipeline.warning_messages.length
+ }
+ render json: bad_request_json, status: :bad_request
end
end
end
@@ -241,7 +242,12 @@ class Projects::PipelinesController < Projects::ApplicationController
PipelineSerializer
.new(project: @project, current_user: @current_user)
.with_pagination(request, response)
- .represent(@pipelines, disable_coverage: true, preload: true)
+ .represent(
+ @pipelines,
+ disable_coverage: true,
+ preload: true,
+ disable_manual_and_scheduled_actions: Feature.enabled?(:lazy_load_pipeline_dropdown_actions, @project)
+ )
end
def render_show
@@ -364,6 +370,10 @@ class Projects::PipelinesController < Projects::ApplicationController
def tracking_project_source
project
end
+
+ def push_frontend_feature_flags
+ push_frontend_feature_flag(:refactor_ci_minutes_consumption, @project)
+ end
end
Projects::PipelinesController.prepend_mod_with('Projects::PipelinesController')
diff --git a/app/controllers/projects/prometheus/metrics_controller.rb b/app/controllers/projects/prometheus/metrics_controller.rb
index db5471ea322..c20c80ba334 100644
--- a/app/controllers/projects/prometheus/metrics_controller.rb
+++ b/app/controllers/projects/prometheus/metrics_controller.rb
@@ -68,7 +68,7 @@ module Projects
if @metric.persisted?
redirect_to edit_project_settings_integration_path(project, ::Integrations::Prometheus),
- notice: _('Metric was successfully added.')
+ notice: _('Metric was successfully added.')
else
render 'new'
end
@@ -79,7 +79,7 @@ module Projects
if @metric.update(metrics_params)
redirect_to edit_project_settings_integration_path(project, ::Integrations::Prometheus),
- notice: _('Metric was successfully updated.')
+ notice: _('Metric was successfully updated.')
else
render 'edit'
end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 895a9a00624..79b5990abba 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -6,8 +6,6 @@ class Projects::RawController < Projects::ApplicationController
include SendsBlob
include StaticObjectExternalStorage
- skip_before_action :default_cache_headers, only: :show
-
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:blob) }
before_action :assign_ref_vars
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index 1cd4c5b6137..80bc92c0b69 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -8,8 +8,6 @@ class Projects::RepositoriesController < Projects::ApplicationController
prepend_before_action(only: [:archive]) { authenticate_sessionless_user!(:archive) }
- skip_before_action :default_cache_headers, only: :archive
-
# Authorize
before_action :check_archive_rate_limiting!, only: :archive
before_action :require_non_empty_project, except: :create
@@ -49,9 +47,14 @@ class Projects::RepositoriesController < Projects::ApplicationController
def set_cache_headers
commit_id = archive_metadata['CommitId']
- expires_in(cache_max_age(commit_id),
- public: Guest.can?(:download_code, project), must_revalidate: true, stale_if_error: 5.minutes,
- stale_while_revalidate: 1.minute, 's-maxage': 1.minute)
+ expires_in(
+ cache_max_age(commit_id),
+ public: Guest.can?(:download_code, project),
+ must_revalidate: true,
+ stale_if_error: 5.minutes,
+ stale_while_revalidate: 1.minute,
+ 's-maxage': 1.minute
+ )
fresh_when(strong_etag: [commit_id, archive_metadata['ArchivePath']])
end
diff --git a/app/controllers/projects/security/configuration_controller.rb b/app/controllers/projects/security/configuration_controller.rb
index 00a2a5d1193..ee2e60b5a1a 100644
--- a/app/controllers/projects/security/configuration_controller.rb
+++ b/app/controllers/projects/security/configuration_controller.rb
@@ -32,9 +32,7 @@ module Projects
end
def configuration_presenter
- ::Projects::Security::ConfigurationPresenter.new(project,
- **presenter_attributes,
- current_user: current_user)
+ ::Projects::Security::ConfigurationPresenter.new(project, **presenter_attributes, current_user: current_user)
end
def presenter_attributes
diff --git a/app/controllers/projects/settings/access_tokens_controller.rb b/app/controllers/projects/settings/access_tokens_controller.rb
index 0884816ef62..af1527ba6a3 100644
--- a/app/controllers/projects/settings/access_tokens_controller.rb
+++ b/app/controllers/projects/settings/access_tokens_controller.rb
@@ -7,7 +7,7 @@ module Projects
include AccessTokensActions
layout 'project_settings'
- feature_category :authentication_and_authorization
+ feature_category :system_access
alias_method :resource, :project
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index 4ca665679c0..f5588a35ad5 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -13,7 +13,7 @@ module Projects
before_action :define_variables
before_action do
- push_frontend_feature_flag(:ci_inbound_job_token_scope, @project)
+ push_frontend_feature_flag(:ci_variables_pages, current_user)
end
helper_method :highlight_badge
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 737a6290431..ba18a2e0dce 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -40,9 +40,12 @@ class Projects::TreeController < Projects::ApplicationController
def create_dir
return render_404 unless @commit_params.values.all?
- create_commit(Files::CreateDirService, success_notice: _("The directory has been successfully created."),
- success_path: project_tree_path(@project, File.join(@branch_name, @dir_name)),
- failure_path: project_tree_path(@project, @ref))
+ create_commit(
+ Files::CreateDirService,
+ success_notice: _("The directory has been successfully created."),
+ success_path: project_tree_path(@project, File.join(@branch_name, @dir_name)),
+ failure_path: project_tree_path(@project, @ref)
+ )
end
private
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index a83ccccbeae..e50ddf75183 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -3,7 +3,7 @@
class Projects::VariablesController < Projects::ApplicationController
before_action :authorize_admin_build!
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
urgency :low, [:show, :update]
diff --git a/app/controllers/projects/web_ide_terminals_controller.rb b/app/controllers/projects/web_ide_terminals_controller.rb
index cfccc949244..be7423e3919 100644
--- a/app/controllers/projects/web_ide_terminals_controller.rb
+++ b/app/controllers/projects/web_ide_terminals_controller.rb
@@ -29,10 +29,7 @@ class Projects::WebIdeTerminalsController < Projects::ApplicationController
end
def create
- result = ::Ci::CreateWebIdeTerminalService.new(project,
- current_user,
- ref: params[:branch])
- .execute
+ result = ::Ci::CreateWebIdeTerminalService.new(project, current_user, ref: params[:branch]).execute
if result[:status] == :error
render status: :bad_request, json: result[:message]
diff --git a/app/controllers/projects/work_items_controller.rb b/app/controllers/projects/work_items_controller.rb
index db9dca14aab..34a71dbbb91 100644
--- a/app/controllers/projects/work_items_controller.rb
+++ b/app/controllers/projects/work_items_controller.rb
@@ -5,7 +5,7 @@ class Projects::WorkItemsController < 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_frontend_feature_flag(:use_iid_in_work_items_path, project&.group)
+ push_force_frontend_feature_flag(:saved_replies, current_user)
end
feature_category :team_planning
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 71ad747b6b1..f18055f80b7 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -39,7 +39,7 @@ class ProjectsController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:highlight_js, @project)
push_frontend_feature_flag(:file_line_blame, @project)
- push_frontend_feature_flag(:increase_page_size_exponentially, @project)
+ push_frontend_feature_flag(:synchronize_fork, @project)
push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks)
push_licensed_feature(:security_orchestration_policies) if @project.present? && @project.licensed_feature_available?(:security_orchestration_policies)
push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?)
@@ -78,6 +78,8 @@ class ProjectsController < Projects::ApplicationController
@namespace = Namespace.find_by(id: params[:namespace_id]) if params[:namespace_id]
return access_denied! if @namespace && !can?(current_user, :create_projects, @namespace)
+ @parent_group = Group.find_by(id: params[:namespace_id])
+
@current_user_group =
if current_user.manageable_groups(include_groups_with_developer_maintainer_access: true).count == 1
current_user.manageable_groups(include_groups_with_developer_maintainer_access: true).first
diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb
index cfb4e939b35..87fcb499d21 100644
--- a/app/controllers/registrations/welcome_controller.rb
+++ b/app/controllers/registrations/welcome_controller.rb
@@ -10,7 +10,7 @@ module Registrations
skip_before_action :authenticate_user!, :required_signup_info, :check_two_factor_requirement, only: [:show, :update]
before_action :require_current_user
- feature_category :authentication_and_authorization
+ feature_category :user_management
def show
return redirect_to path_for_signed_in_user(current_user) if completed_welcome_step?
@@ -50,7 +50,7 @@ module Registrations
def requires_confirmation?(user)
return false if user.confirmed?
- return false if Feature.enabled?(:soft_email_confirmation)
+ return false unless Gitlab::CurrentSettings.email_confirmation_setting_hard?
true
end
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index ed0e019d02b..b4eee3549a0 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -25,10 +25,11 @@ class RegistrationsController < Devise::RegistrationsController
before_action only: [:new] do
push_frontend_feature_flag(:gitlab_gtm_datalayer, type: :ops)
- push_frontend_feature_flag(:trial_email_validation, type: :development)
end
- feature_category :authentication_and_authorization
+ feature_category :user_management
+
+ helper_method :arkose_labs_enabled?
def new
@resource = build_resource
@@ -128,13 +129,16 @@ class RegistrationsController < Devise::RegistrationsController
def after_inactive_sign_up_path_for(resource)
Gitlab::AppLogger.info(user_created_message)
return new_user_session_path(anchor: 'login-pane') if resource.blocked_pending_approval?
- return dashboard_projects_path if Feature.enabled?(:soft_email_confirmation)
+ return dashboard_projects_path if Gitlab::CurrentSettings.email_confirmation_setting_soft?
- # when email confirmation is enabled, path to redirect is saved
+ # when email_confirmation_setting is set to `hard`, path to redirect is saved
# after user confirms and comes back, he will be redirected
store_location_for(:redirect, after_sign_up_path)
- return identity_verification_redirect_path if custom_confirmation_enabled?
+ if custom_confirmation_enabled?
+ session[:verification_user_id] = resource.id # This is needed to find the user on the identity verification page
+ return identity_verification_redirect_path
+ end
Gitlab::Tracking.event(self.class.name, 'render', user: resource)
users_almost_there_path(email: resource.email)
@@ -221,7 +225,7 @@ class RegistrationsController < Devise::RegistrationsController
def resource
@resource ||= Users::RegistrationsBuildService
- .new(current_user, sign_up_params.merge({ skip_confirmation: registered_with_invite_email?,
+ .new(current_user, sign_up_params.merge({ skip_confirmation: skip_confirmation?,
preferred_language: preferred_language }))
.execute
end
@@ -230,6 +234,10 @@ class RegistrationsController < Devise::RegistrationsController
@devise_mapping ||= Devise.mappings[:user]
end
+ def skip_confirmation?
+ registered_with_invite_email?
+ end
+
def registered_with_invite_email?
invite_email = session.delete(:invite_email)
@@ -293,6 +301,10 @@ class RegistrationsController < Devise::RegistrationsController
def send_custom_confirmation_instructions
# overridden by EE module
end
+
+ def arkose_labs_enabled?
+ false
+ end
end
RegistrationsController.prepend_mod_with('RegistrationsController')
diff --git a/app/controllers/repositories/git_http_controller.rb b/app/controllers/repositories/git_http_controller.rb
index bd3461d8331..4f228ced542 100644
--- a/app/controllers/repositories/git_http_controller.rb
+++ b/app/controllers/repositories/git_http_controller.rb
@@ -8,6 +8,7 @@ module Repositories
prepend_before_action :deny_head_requests, only: [:info_refs]
rescue_from Gitlab::GitAccess::ForbiddenError, with: :render_403_with_exception
+ rescue_from JWT::DecodeError, with: :render_403_with_exception
rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404_with_exception
rescue_from Gitlab::GitAccessProject::CreationError, with: :render_422_with_exception
rescue_from Gitlab::GitAccess::TimeoutError, with: :render_503_with_exception
@@ -19,6 +20,7 @@ module Repositories
# GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
def info_refs
log_user_activity if upload_pack?
+ log_user_activity if receive_pack? && Feature.enabled?(:log_user_git_push_activity)
render_ok
end
@@ -49,6 +51,10 @@ module Repositories
git_command == 'git-upload-pack'
end
+ def receive_pack?
+ git_command == 'git-receive-pack'
+ end
+
def git_command
if action_name == 'info_refs'
params[:service]
diff --git a/app/controllers/repositories/lfs_api_controller.rb b/app/controllers/repositories/lfs_api_controller.rb
index 83973d07a17..d52ae723eee 100644
--- a/app/controllers/repositories/lfs_api_controller.rb
+++ b/app/controllers/repositories/lfs_api_controller.rb
@@ -172,13 +172,15 @@ module Repositories
LfsObjectsProject.link_to_project!(lfs_object, project)
- Gitlab::AppJsonLogger.info(message: "LFS object auto-linked to forked project",
- lfs_object_oid: lfs_object.oid,
- lfs_object_size: lfs_object.size,
- source_project_id: project.fork_source.id,
- source_project_path: project.fork_source.full_path,
- target_project_id: project.project_id,
- target_project_path: project.full_path)
+ Gitlab::AppJsonLogger.info(
+ message: "LFS object auto-linked to forked project",
+ lfs_object_oid: lfs_object.oid,
+ lfs_object_size: lfs_object.size,
+ source_project_id: project.fork_source.id,
+ source_project_path: project.fork_source.full_path,
+ target_project_id: project.project_id,
+ target_project_path: project.full_path
+ )
end
end
end
diff --git a/app/controllers/repositories/lfs_locks_api_controller.rb b/app/controllers/repositories/lfs_locks_api_controller.rb
index ea858d63236..52ae9068c75 100644
--- a/app/controllers/repositories/lfs_locks_api_controller.rb
+++ b/app/controllers/repositories/lfs_locks_api_controller.rb
@@ -37,9 +37,7 @@ module Repositories
private
def render_json(data, process = true)
- render json: build_payload(data, process),
- content_type: LfsRequest::CONTENT_TYPE,
- status: @result[:http_status]
+ render json: build_payload(data, process), content_type: LfsRequest::CONTENT_TYPE, status: @result[:http_status]
end
def build_payload(data, process)
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 1ca34dee3d6..688c56e56e0 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -10,11 +10,11 @@ class SearchController < ApplicationController
RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show, :autocomplete, :aggregations].freeze
CODE_SEARCH_LITERALS = %w[blob: extension: path: filename:].freeze
- track_custom_event :show,
- name: 'i_search_total',
- label: 'redis_hll_counters.search.search_total_unique_counts_monthly',
- action: 'executed',
- destinations: [:redis_hll, :snowplow]
+ track_event :show,
+ name: 'i_search_total',
+ label: 'redis_hll_counters.search.search_total_unique_counts_monthly',
+ action: 'executed',
+ destinations: [:redis_hll, :snowplow]
def self.search_rate_limited_endpoints
%i[show count autocomplete]
@@ -24,7 +24,6 @@ class SearchController < ApplicationController
before_action :block_anonymous_global_searches, :check_scope_global_search_enabled, except: :opensearch
skip_before_action :authenticate_user!
- skip_before_action :default_cache_headers, only: :count
requires_cross_project_access if: -> do
search_term_present = params[:search].present? || params[:term].present?
@@ -33,9 +32,6 @@ class SearchController < ApplicationController
before_action :check_search_rate_limit!, only: search_rate_limited_endpoints
before_action only: :show do
- push_frontend_feature_flag(:search_blobs_language_aggregation, current_user)
- end
- before_action only: :show do
update_scope_for_code_search
end
rescue_from ActiveRecord::QueryCanceled, with: :render_timeout
@@ -116,6 +112,9 @@ class SearchController < ApplicationController
@ref = params[:project_ref] if params[:project_ref].present?
@filter = params[:filter]
+ # Cache the response on the frontend
+ expires_in 1.minute
+
render json: Gitlab::Json.dump(search_autocomplete_opts(term, filter: @filter))
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index b6aba04c877..8a79353f490 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -36,9 +36,6 @@ class SessionsController < Devise::SessionsController
before_action :save_failed_login, if: :action_new_and_failed_login?
before_action :load_recaptcha
before_action :set_invite_params, only: [:new]
- before_action do
- push_frontend_feature_flag(:webauthn)
- end
after_action :log_failed_login, if: :action_new_and_failed_login?
after_action :verify_known_sign_in, only: [:create]
@@ -56,7 +53,7 @@ class SessionsController < Devise::SessionsController
# token mismatch.
protect_from_forgery with: :exception, prepend: true, except: :destroy
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :low
CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha'
@@ -72,8 +69,7 @@ class SessionsController < Devise::SessionsController
super do |resource|
# User has successfully signed in, so clear any unused reset token
if resource.reset_password_token.present?
- resource.update(reset_password_token: nil,
- reset_password_sent_at: nil)
+ resource.update(reset_password_token: nil, reset_password_sent_at: nil)
end
if resource.deactivated?
@@ -311,10 +307,8 @@ class SessionsController < Devise::SessionsController
def authentication_method
if user_params[:otp_attempt]
AuthenticationEvent::TWO_FACTOR
- elsif user_params[:device_response] && Feature.enabled?(:webauthn)
+ elsif user_params[:device_response]
AuthenticationEvent::TWO_FACTOR_WEBAUTHN
- elsif user_params[:device_response] && !Feature.enabled?(:webauthn)
- AuthenticationEvent::TWO_FACTOR_U2F
else
AuthenticationEvent::STANDARD
end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index e81868faa6e..3f20e1c0e86 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -14,7 +14,7 @@ class SnippetsController < Snippets::ApplicationController
skip_before_action :authenticate_user!, only: [:index, :show, :raw]
- layout 'snippets'
+ layout :determine_layout
def index
if params[:username].present?
@@ -48,4 +48,12 @@ class SnippetsController < Snippets::ApplicationController
def spammable_path
snippet_path(@snippet)
end
+
+ def determine_layout
+ if action_name == 'show' && @snippet.author != current_user
+ 'explore'
+ else
+ 'snippets'
+ end
+ end
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 9546f71cd37..e4354eaa452 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -9,20 +9,21 @@ class UsersController < ApplicationController
include Gitlab::NoteableMetadata
requires_cross_project_access show: false,
- groups: false,
- projects: false,
- contributed: false,
- snippets: true,
- calendar: false,
- followers: false,
- following: false,
- calendar_activities: true
+ groups: false,
+ projects: false,
+ contributed: false,
+ snippets: true,
+ calendar: false,
+ followers: false,
+ following: false,
+ calendar_activities: true
skip_before_action :authenticate_user!
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
before_action :user, except: [:exists]
- before_action :authorize_read_user_profile!,
- only: [:calendar, :calendar_activities, :groups, :projects, :contributed, :starred, :snippets, :followers, :following]
+ before_action :authorize_read_user_profile!, only: [
+ :calendar, :calendar_activities, :groups, :projects, :contributed, :starred, :snippets, :followers, :following
+ ]
before_action only: [:exists] do
check_rate_limit!(:username_exists, scope: request.ip)
end
@@ -71,7 +72,19 @@ class UsersController < ApplicationController
format.json do
load_events
- pager_json("events/_events", @events.count, events: @events)
+
+ if Feature.enabled?(:profile_tabs_vue, current_user)
+ @events = if user.include_private_contributions?
+ @events
+ else
+ @events.select { |event| event.visible_to_user?(current_user) }
+ end
+
+ render json: ::Profile::EventSerializer.new(current_user: current_user, target_user: user)
+ .represent(@events)
+ else
+ pager_json("events/_events", @events.count, events: @events)
+ end
end
end
end
diff --git a/app/finders/abuse_reports_finder.rb b/app/finders/abuse_reports_finder.rb
index 04043f36426..c3159198261 100644
--- a/app/finders/abuse_reports_finder.rb
+++ b/app/finders/abuse_reports_finder.rb
@@ -1,18 +1,88 @@
# frozen_string_literal: true
class AbuseReportsFinder
- attr_reader :params
+ attr_reader :params, :reports
+
+ DEFAULT_SORT = 'created_at_desc'
+ ALLOWED_SORT = [DEFAULT_SORT, *%w[created_at_asc updated_at_desc updated_at_asc]].freeze
def initialize(params = {})
@params = params
+ @reports = AbuseReport.all
end
def execute
- reports = AbuseReport.all
- reports = reports.by_user(params[:user_id]) if params[:user_id].present?
+ filter_reports
+ sort_reports
+
+ reports.with_users.page(params[:page])
+ end
+
+ private
+
+ def filter_reports
+ filter_by_user_id
+
+ filter_by_user
+ filter_by_reporter
+ filter_by_status
+ filter_by_category
+ end
+
+ def filter_by_status
+ return unless params[:status].present?
+
+ case params[:status]
+ when 'open'
+ @reports = @reports.open
+ when 'closed'
+ @reports = @reports.closed
+ end
+ end
+
+ def filter_by_category
+ return unless params[:category].present?
+
+ @reports = @reports.by_category(params[:category])
+ end
+
+ def filter_by_user
+ return unless params[:user].present?
+
+ user_id = find_user_id(params[:user])
+ return unless user_id
+
+ @reports = @reports.by_user_id(user_id)
+ end
+
+ def filter_by_reporter
+ return unless params[:reporter].present?
+
+ user_id = find_user_id(params[:reporter])
+ return unless user_id
+
+ @reports = @reports.by_reporter_id(user_id)
+ end
+
+ def filter_by_user_id
+ return unless params[:user_id].present?
+
+ @reports = @reports.by_user_id(params[:user_id])
+ end
+
+ def sort_reports
+ if Feature.disabled?(:abuse_reports_list)
+ @reports = @reports.with_order_id_desc
+ return
+ end
+
+ sort_by = params[:sort]
+ sort_by = DEFAULT_SORT unless sort_by.in?(ALLOWED_SORT)
+
+ @reports = @reports.order_by(sort_by)
+ end
- reports.with_order_id_desc
- .with_users
- .page(params[:page])
+ def find_user_id(username)
+ User.by_username(username).pick(:id)
end
end
diff --git a/app/finders/autocomplete/users_finder.rb b/app/finders/autocomplete/users_finder.rb
index bb91f84de99..99e68991836 100644
--- a/app/finders/autocomplete/users_finder.rb
+++ b/app/finders/autocomplete/users_finder.rb
@@ -98,7 +98,7 @@ module Autocomplete
# rubocop: disable CodeReuse/ActiveRecord
def preload_associations(items)
- ActiveRecord::Associations::Preloader.new.preload(items, :status)
+ ActiveRecord::Associations::Preloader.new(records: items, associations: :status).call
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/ci/pipelines_finder.rb b/app/finders/ci/pipelines_finder.rb
index a2d1805286d..e52fc510628 100644
--- a/app/finders/ci/pipelines_finder.rb
+++ b/app/finders/ci/pipelines_finder.rb
@@ -2,6 +2,8 @@
module Ci
class PipelinesFinder
+ include UpdatedAtFilter
+
attr_reader :project, :pipelines, :params, :current_user
ALLOWED_INDEXED_COLUMNS = %w[id status ref updated_at user_id].freeze
@@ -146,13 +148,6 @@ module Ci
end
# rubocop: enable CodeReuse/ActiveRecord
- def by_updated_at(items)
- items = items.updated_before(params[:updated_before]) if params[:updated_before].present?
- items = items.updated_after(params[:updated_after]) if params[:updated_after].present?
-
- items
- end
-
def by_name(items)
return items unless
Feature.enabled?(:pipeline_name_search, project) &&
diff --git a/app/finders/concerns/updated_at_filter.rb b/app/finders/concerns/updated_at_filter.rb
new file mode 100644
index 00000000000..2d6bd7bf9f3
--- /dev/null
+++ b/app/finders/concerns/updated_at_filter.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module UpdatedAtFilter
+ def by_updated_at(items)
+ items = items.updated_before(params[:updated_before]) if params[:updated_before].present?
+ items = items.updated_after(params[:updated_after]) if params[:updated_after].present?
+
+ items
+ end
+end
diff --git a/app/finders/deployments_finder.rb b/app/finders/deployments_finder.rb
index 21869f6f31d..c5f8510ca16 100644
--- a/app/finders/deployments_finder.rb
+++ b/app/finders/deployments_finder.rb
@@ -14,6 +14,8 @@
# order_by: String (see ALLOWED_SORT_VALUES constant)
# sort: String (asc | desc)
class DeploymentsFinder
+ include UpdatedAtFilter
+
attr_reader :params
# Warning:
@@ -109,13 +111,6 @@ class DeploymentsFinder
items.order(sort_params) # rubocop: disable CodeReuse/ActiveRecord
end
- def by_updated_at(items)
- items = items.updated_before(params[:updated_before]) if params[:updated_before].present?
- items = items.updated_after(params[:updated_after]) if params[:updated_after].present?
-
- items
- end
-
def by_finished_at(items)
items = items.finished_before(params[:finished_before]) if params[:finished_before].present?
items = items.finished_after(params[:finished_after]) if params[:finished_after].present?
diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb
index 47ed623b252..05645dacab9 100644
--- a/app/finders/group_members_finder.rb
+++ b/app/finders/group_members_finder.rb
@@ -64,6 +64,7 @@ class GroupMembersFinder < UnionFinder
members = members.by_access_level(params[:access_levels])
end
+ members = filter_by_user_type(members)
members = apply_additional_filters(members)
by_created_at(members)
@@ -91,6 +92,12 @@ class GroupMembersFinder < UnionFinder
end
end
+ def filter_by_user_type(members)
+ return members unless params[:user_type] && can_manage_members
+
+ members.filter_by_user_type(params[:user_type])
+ end
+
def apply_additional_filters(members)
# overridden in EE to include additional filtering conditions.
members
diff --git a/app/finders/groups/accepting_project_shares_finder.rb b/app/finders/groups/accepting_project_shares_finder.rb
index c4963fcc352..253961b8e52 100644
--- a/app/finders/groups/accepting_project_shares_finder.rb
+++ b/app/finders/groups/accepting_project_shares_finder.rb
@@ -25,7 +25,7 @@ module Groups
groups_with_guest_access_plus
end
- groups = groups.search(params[:search]) if params[:search].present?
+ groups = by_search(groups)
sort(groups).with_route
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 159836062cb..478a2ba622c 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -43,6 +43,7 @@ class IssuableFinder
include FinderMethods
include CreatedAtFilter
include Gitlab::Utils::StrongMemoize
+ include UpdatedAtFilter
requires_cross_project_access unless: -> { params.project? }
@@ -289,13 +290,6 @@ class IssuableFinder
end
# rubocop: enable CodeReuse/ActiveRecord
- def by_updated_at(items)
- items = items.updated_after(params[:updated_after]) if params[:updated_after].present?
- items = items.updated_before(params[:updated_before]) if params[:updated_before].present?
-
- items
- end
-
def by_closed_at(items)
items = items.closed_after(params[:closed_after]) if params[:closed_after].present?
items = items.closed_before(params[:closed_before]) if params[:closed_before].present?
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb
index ffa912afd1e..0ce2d52f168 100644
--- a/app/finders/merge_requests_finder.rb
+++ b/app/finders/merge_requests_finder.rb
@@ -36,6 +36,7 @@ class MergeRequestsFinder < IssuableFinder
def self.scalar_params
@scalar_params ||= super + [
+ :approved,
:approved_by_ids,
:deployed_after,
:deployed_before,
@@ -71,8 +72,9 @@ class MergeRequestsFinder < IssuableFinder
items = by_approvals(items)
items = by_deployments(items)
items = by_reviewer(items)
+ items = by_source_project_id(items)
- by_source_project_id(items)
+ by_approved(items)
end
def filter_negated_items(items)
@@ -183,6 +185,17 @@ class MergeRequestsFinder < IssuableFinder
end
# rubocop: enable CodeReuse/Finder
+ def by_approved(items)
+ approved_param = Gitlab::Utils.to_boolean(params.fetch(:approved, nil))
+ return items if approved_param.nil?
+
+ if approved_param
+ items.with_approvals
+ else
+ items.without_approvals
+ end
+ end
+
def by_deployments(items)
env = params[:environment]
before = parse_datetime(params[:deployed_before])
diff --git a/app/finders/milestones_finder.rb b/app/finders/milestones_finder.rb
index 5fe55e88086..9ffd623338f 100644
--- a/app/finders/milestones_finder.rb
+++ b/app/finders/milestones_finder.rb
@@ -15,6 +15,7 @@
class MilestonesFinder
include FinderMethods
include TimeFrameFilter
+ include UpdatedAtFilter
attr_reader :params
@@ -30,9 +31,12 @@ class MilestonesFinder
items = by_groups_and_projects(items)
items = by_title(items)
items = by_search_title(items)
+ items = by_search(items)
items = by_state(items)
items = by_timeframe(items)
items = containing_date(items)
+ items = by_updated_at(items)
+ items = by_iids(items)
order(items)
end
@@ -67,6 +71,12 @@ class MilestonesFinder
end
end
+ def by_search(items)
+ return items if params[:search].blank?
+
+ items.search(params[:search])
+ end
+
def by_state(items)
Milestone.filter_by_state(items, params[:state])
end
@@ -84,4 +94,10 @@ class MilestonesFinder
def sort_by_expired_last?(sort_by)
EXPIRED_LAST_SORTS.include?(sort_by)
end
+
+ def by_iids(items)
+ return items unless params[:iids].present? && !params[:include_parent_milestones]
+
+ items.by_iid(params[:iids])
+ end
end
diff --git a/app/finders/serverless_domain_finder.rb b/app/finders/serverless_domain_finder.rb
deleted file mode 100644
index 661cd0ca363..00000000000
--- a/app/finders/serverless_domain_finder.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-class ServerlessDomainFinder
- attr_reader :match, :serverless_domain_cluster, :environment
-
- def initialize(uri)
- @match = ::Serverless::Domain::REGEXP.match(uri)
- end
-
- def execute
- return unless serverless?
-
- @serverless_domain_cluster = ::Serverless::DomainCluster.for_uuid(serverless_domain_cluster_uuid)
- return unless serverless_domain_cluster&.knative&.external_ip
-
- @environment = ::Environment.for_id_and_slug(match[:environment_id].to_i(16), match[:environment_slug])
- return unless environment
-
- ::Serverless::Domain.new(
- function_name: match[:function_name],
- serverless_domain_cluster: serverless_domain_cluster,
- environment: environment
- )
- end
-
- def serverless_domain_cluster_uuid
- return unless serverless?
-
- match[:cluster_left] + match[:cluster_middle] + match[:cluster_right]
- end
-
- def serverless?
- !!match
- end
-end
diff --git a/app/graphql/mutations/achievements/award.rb b/app/graphql/mutations/achievements/award.rb
new file mode 100644
index 00000000000..b486049594d
--- /dev/null
+++ b/app/graphql/mutations/achievements/award.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Achievements
+ class Award < BaseMutation
+ graphql_name 'AchievementsAward'
+
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ field :user_achievement,
+ ::Types::Achievements::UserAchievementType,
+ null: true,
+ description: 'Achievement award.'
+
+ argument :achievement_id, ::Types::GlobalIDType[::Achievements::Achievement],
+ required: true,
+ description: 'Global ID of the achievement being awarded.'
+
+ argument :user_id, ::Types::GlobalIDType[::User],
+ required: true,
+ description: 'Global ID of the user being awarded the achievement.'
+
+ authorize :award_achievement
+
+ def resolve(args)
+ achievement = authorized_find!(id: args[:achievement_id])
+
+ recipient_id = args[:user_id].model_id
+ result = ::Achievements::AwardService.new(current_user, achievement.id, recipient_id).execute
+ { user_achievement: result.payload, errors: result.errors }
+ end
+
+ def find_object(id:)
+ GitlabSchema.object_from_id(id, expected_type: ::Achievements::Achievement)
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/achievements/revoke.rb b/app/graphql/mutations/achievements/revoke.rb
new file mode 100644
index 00000000000..9d21b1c3741
--- /dev/null
+++ b/app/graphql/mutations/achievements/revoke.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Achievements
+ class Revoke < BaseMutation
+ graphql_name 'AchievementsRevoke'
+
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ field :user_achievement,
+ ::Types::Achievements::UserAchievementType,
+ null: true,
+ description: 'Achievement award.'
+
+ argument :user_achievement_id, ::Types::GlobalIDType[::Achievements::UserAchievement],
+ required: true,
+ description: 'Global ID of the user achievement being revoked.'
+
+ authorize :award_achievement
+
+ def resolve(args)
+ user_achievement = authorized_find!(id: args[:user_achievement_id])
+
+ result = ::Achievements::RevokeService.new(current_user, user_achievement).execute
+ { user_achievement: result.payload, errors: result.errors }
+ end
+
+ def find_object(id:)
+ GitlabSchema.object_from_id(id, expected_type: ::Achievements::UserAchievement)
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/alert_management/base.rb b/app/graphql/mutations/alert_management/base.rb
index 2eef6bb9db7..771ace5510f 100644
--- a/app/graphql/mutations/alert_management/base.rb
+++ b/app/graphql/mutations/alert_management/base.rb
@@ -45,8 +45,6 @@ module Mutations
namespace = project.namespace
track_usage_event(event, current_user.id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, namespace)
-
Gitlab::Tracking.event(
self.class.to_s,
event,
diff --git a/app/graphql/mutations/ci/job_artifact/bulk_destroy.rb b/app/graphql/mutations/ci/job_artifact/bulk_destroy.rb
new file mode 100644
index 00000000000..53036496de4
--- /dev/null
+++ b/app/graphql/mutations/ci/job_artifact/bulk_destroy.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module JobArtifact
+ class BulkDestroy < BaseMutation
+ graphql_name 'BulkDestroyJobArtifacts'
+
+ authorize :destroy_artifacts
+
+ ArtifactId = ::Types::GlobalIDType[::Ci::JobArtifact]
+ ProjectId = ::Types::GlobalIDType[::Project]
+
+ argument :ids, [ArtifactId],
+ required: true,
+ description: 'Global IDs of the job artifacts to destroy.',
+ prepare: ->(global_ids, _ctx) { GitlabSchema.parse_gids(global_ids, expected_type: ::Ci::JobArtifact) }
+
+ argument :project_id, ProjectId,
+ required: true,
+ description: 'Global Project ID of the job artifacts to destroy. Incompatible with projectPath.'
+
+ field :destroyed_count, ::GraphQL::Types::Int,
+ null: true,
+ description: 'Number of job artifacts deleted.'
+
+ field :destroyed_ids, [ArtifactId],
+ null: true,
+ description: 'IDs of job artifacts that were deleted.'
+
+ def find_object(id:)
+ GlobalID::Locator.locate(id)
+ end
+
+ def resolve(**args)
+ ids = args[:ids]
+ project_id = args[:project_id]
+
+ project = authorized_find!(id: project_id)
+
+ if Feature.disabled?(:ci_job_artifact_bulk_destroy, project)
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable,
+ '`ci_job_artifact_bulk_destroy` feature flag is disabled.'
+ end
+
+ raise Gitlab::Graphql::Errors::ArgumentError, 'IDs array of job artifacts can not be empty' if ids.empty?
+
+ result = ::Ci::JobArtifacts::BulkDeleteByProjectService.new(
+ job_artifact_ids: model_ids_of(ids),
+ current_user: current_user,
+ project: project
+ ).execute
+
+ if result.success?
+ result.payload.slice(:destroyed_count, :destroyed_ids).merge(errors: [])
+ else
+ { errors: result.errors }
+ end
+ end
+
+ private
+
+ def model_ids_of(global_ids)
+ global_ids.filter_map { |gid| gid.model_id.to_i }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb b/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb
index 2e4312f0045..d71ef738cab 100644
--- a/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb
+++ b/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb
@@ -6,7 +6,7 @@ module Mutations
class TakeOwnership < Base
graphql_name 'PipelineScheduleTakeOwnership'
- authorize :take_ownership_pipeline_schedule
+ authorize :admin_pipeline_schedule
field :pipeline_schedule,
Types::Ci::PipelineScheduleType,
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 d214aa46cfc..fcba729d460 100644
--- a/app/graphql/mutations/ci/project_ci_cd_settings_update.rb
+++ b/app/graphql/mutations/ci/project_ci_cd_settings_update.rb
@@ -39,8 +39,6 @@ module Mutations
def resolve(full_path:, **args)
project = authorized_find!(full_path)
- args.delete(:inbound_job_token_scope_enabled) unless Feature.enabled?(:ci_inbound_job_token_scope, project)
-
settings = project.ci_cd_settings
settings.update(args)
diff --git a/app/graphql/mutations/ci/runner/common_mutation_arguments.rb b/app/graphql/mutations/ci/runner/common_mutation_arguments.rb
new file mode 100644
index 00000000000..bfeed4881c6
--- /dev/null
+++ b/app/graphql/mutations/ci/runner/common_mutation_arguments.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module Runner
+ module CommonMutationArguments
+ extend ActiveSupport::Concern
+
+ included do
+ argument :description, GraphQL::Types::String,
+ required: false,
+ description: 'Description of the runner.'
+
+ argument :maintenance_note, GraphQL::Types::String,
+ required: false,
+ description: 'Runner\'s maintenance notes.'
+
+ argument :maximum_timeout, GraphQL::Types::Int,
+ required: false,
+ description: 'Maximum timeout (in seconds) for jobs processed by the runner.'
+
+ argument :access_level, ::Types::Ci::RunnerAccessLevelEnum,
+ required: false,
+ description: 'Access level of the runner.'
+
+ argument :paused, GraphQL::Types::Boolean,
+ required: false,
+ description: 'Indicates the runner is not allowed to receive jobs.'
+
+ argument :locked, GraphQL::Types::Boolean,
+ required: false,
+ description: 'Indicates the runner is locked.'
+
+ argument :run_untagged, GraphQL::Types::Boolean,
+ required: false,
+ description: 'Indicates the runner is able to run untagged jobs.'
+
+ argument :tag_list, [GraphQL::Types::String],
+ required: false,
+ description: 'Tags associated with the runner.'
+
+ argument :associated_projects, [::Types::GlobalIDType[::Project]],
+ required: false,
+ description: 'Projects associated with the runner. Available only for project runners.',
+ prepare: ->(global_ids, _ctx) { global_ids&.filter_map { |gid| gid.model_id.to_i } }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/runner/create.rb b/app/graphql/mutations/ci/runner/create.rb
new file mode 100644
index 00000000000..98300ee4c38
--- /dev/null
+++ b/app/graphql/mutations/ci/runner/create.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module Runner
+ class Create < BaseMutation
+ graphql_name 'RunnerCreate'
+
+ authorize :create_runner
+
+ include Mutations::Ci::Runner::CommonMutationArguments
+
+ field :runner,
+ Types::Ci::RunnerType,
+ null: true,
+ description: 'Runner after mutation.'
+
+ def resolve(**args)
+ if Feature.disabled?(:create_runner_workflow_for_admin, current_user)
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable,
+ '`create_runner_workflow_for_admin` feature flag is disabled.'
+ end
+
+ create_runner(args)
+ end
+
+ private
+
+ def create_runner(params)
+ response = { runner: nil, errors: [] }
+ result = ::Ci::Runners::CreateRunnerService.new(user: current_user, type: nil, params: params).execute
+
+ if result.success?
+ response[:runner] = result.payload[:runner]
+ else
+ response[:errors] = result.errors
+ end
+
+ response
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/runner/update.rb b/app/graphql/mutations/ci/runner/update.rb
index 4f0bf19f09c..70f08e03553 100644
--- a/app/graphql/mutations/ci/runner/update.rb
+++ b/app/graphql/mutations/ci/runner/update.rb
@@ -8,54 +8,19 @@ module Mutations
authorize :update_runner
+ include Mutations::Ci::Runner::CommonMutationArguments
+
RunnerID = ::Types::GlobalIDType[::Ci::Runner]
argument :id, RunnerID,
required: true,
description: 'ID of the runner to update.'
- argument :description, GraphQL::Types::String,
- required: false,
- description: 'Description of the runner.'
-
- argument :maintenance_note, GraphQL::Types::String,
- required: false,
- description: 'Runner\'s maintenance notes.'
-
- argument :maximum_timeout, GraphQL::Types::Int,
- required: false,
- description: 'Maximum timeout (in seconds) for jobs processed by the runner.'
-
- argument :access_level, ::Types::Ci::RunnerAccessLevelEnum,
- required: false,
- description: 'Access level of the runner.'
-
argument :active, GraphQL::Types::Boolean,
required: false,
description: 'Indicates the runner is allowed to receive jobs.',
deprecated: { reason: :renamed, replacement: 'paused', milestone: '14.8' }
- argument :paused, GraphQL::Types::Boolean,
- required: false,
- description: 'Indicates the runner is not allowed to receive jobs.'
-
- argument :locked, GraphQL::Types::Boolean,
- required: false,
- description: 'Indicates the runner is locked.'
-
- argument :run_untagged, GraphQL::Types::Boolean,
- required: false,
- description: 'Indicates the runner is able to run untagged jobs.'
-
- argument :tag_list, [GraphQL::Types::String],
- required: false,
- description: 'Tags associated with the runner.'
-
- argument :associated_projects, [::Types::GlobalIDType[::Project]],
- required: false,
- description: 'Projects associated with the runner. Available only for project runners.',
- prepare: ->(global_ids, ctx) { global_ids&.filter_map { |gid| gid.model_id.to_i } }
-
field :runner,
Types::Ci::RunnerType,
null: true,
diff --git a/app/graphql/mutations/clusters/agent_tokens/create.rb b/app/graphql/mutations/clusters/agent_tokens/create.rb
index c10e1633350..1b104652bd2 100644
--- a/app/graphql/mutations/clusters/agent_tokens/create.rb
+++ b/app/graphql/mutations/clusters/agent_tokens/create.rb
@@ -40,9 +40,9 @@ module Mutations
result = ::Clusters::AgentTokens::CreateService
.new(
- container: cluster_agent.project,
+ agent: cluster_agent,
current_user: current_user,
- params: args.merge(agent_id: cluster_agent.id)
+ params: args
)
.execute
diff --git a/app/graphql/mutations/clusters/agent_tokens/revoke.rb b/app/graphql/mutations/clusters/agent_tokens/revoke.rb
index 974db976f1d..6e988799921 100644
--- a/app/graphql/mutations/clusters/agent_tokens/revoke.rb
+++ b/app/graphql/mutations/clusters/agent_tokens/revoke.rb
@@ -16,7 +16,8 @@ module Mutations
def resolve(id:)
token = authorized_find!(id: id)
- token.update(status: token.class.statuses[:revoked])
+
+ ::Clusters::AgentTokens::RevokeService.new(token: token, current_user: current_user).execute
{ errors: errors_on_object(token) }
end
diff --git a/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb b/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb
index 6738f268e92..72daaf3ee44 100644
--- a/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb
+++ b/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb
@@ -36,6 +36,10 @@ module Mutations
argument :milestone_widget, ::Types::WorkItems::Widgets::MilestoneInputType,
required: false,
description: 'Input for milestone widget.'
+ argument :notifications_widget,
+ ::Types::WorkItems::Widgets::NotificationsUpdateInputType,
+ required: false,
+ description: 'Input for notifications widget.'
end
end
end
diff --git a/app/graphql/mutations/design_management/update.rb b/app/graphql/mutations/design_management/update.rb
new file mode 100644
index 00000000000..5dc20730a90
--- /dev/null
+++ b/app/graphql/mutations/design_management/update.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Mutations
+ module DesignManagement
+ class Update < ::Mutations::BaseMutation
+ graphql_name "DesignManagementUpdate"
+
+ authorize :update_design
+
+ argument :id, ::Types::GlobalIDType[::DesignManagement::Design],
+ required: true,
+ description: "ID of the design to update."
+
+ argument :description, GraphQL::Types::String,
+ required: false,
+ description: copy_field_description(Types::DesignManagement::DesignType, :description)
+
+ field :design, Types::DesignManagement::DesignType,
+ null: false,
+ description: "Updated design."
+
+ def resolve(id:, description:)
+ design = authorized_find!(id: id)
+ design.update(description: description)
+
+ {
+ design: design.reset,
+ errors: errors_on_object(design)
+ }
+ end
+
+ private
+
+ def find_object(id:)
+ GitlabSchema.find_by_gid(id)
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/issues/bulk_update.rb b/app/graphql/mutations/issues/bulk_update.rb
index 3d80f119079..9c9dd3cf2fc 100644
--- a/app/graphql/mutations/issues/bulk_update.rb
+++ b/app/graphql/mutations/issues/bulk_update.rb
@@ -14,7 +14,8 @@ module Mutations
argument :parent_id, ::Types::GlobalIDType[::IssueParent],
required: true,
- description: 'Global ID of the parent that the bulk update will be scoped to . ' \
+ 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)**. ' \
'Example `IssueParentID` are `"gid://gitlab/Project/1"` and `"gid://gitlab/Group/1"`.'
argument :ids, [::Types::GlobalIDType[::Issue]],
@@ -31,6 +32,22 @@ module Mutations
required: false,
description: 'Global ID of the milestone that will be assigned to the issues.'
+ argument :state_event, Types::IssueStateEventEnum,
+ description: 'Close or reopen an issue.',
+ required: false
+
+ argument :add_label_ids, [::Types::GlobalIDType[::Label]],
+ description: 'Global ID array of the labels that will be added to the issues. ',
+ required: false
+
+ argument :remove_label_ids, [::Types::GlobalIDType[::Label]],
+ description: 'Global ID array of the labels that will be removed from the issues. ',
+ required: false
+
+ argument :subscription_event, Types::IssuableSubscriptionEventEnum,
+ description: 'Subscribe to or unsubscribe from issue notifications.',
+ required: false
+
field :updated_issue_count, GraphQL::Types::Int,
null: true,
description: 'Number of issues that were successfully updated.'
@@ -74,7 +91,7 @@ module Mutations
end
def prepared_params(attributes, ids)
- prepared = { issuable_ids: model_ids_from(ids).uniq }
+ prepared = attributes.except(*global_id_arguments).merge(issuable_ids: model_ids_from(ids).uniq)
global_id_arguments.each do |argument|
next unless attributes.key?(argument)
@@ -92,7 +109,7 @@ module Mutations
end
def global_id_arguments
- %i[assignee_ids milestone_id]
+ %i[assignee_ids milestone_id add_label_ids remove_label_ids]
end
def model_ids_from(attributes)
diff --git a/app/graphql/mutations/members/bulk_update_base.rb b/app/graphql/mutations/members/bulk_update_base.rb
new file mode 100644
index 00000000000..1e0208e864d
--- /dev/null
+++ b/app/graphql/mutations/members/bulk_update_base.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Members
+ class BulkUpdateBase < BaseMutation
+ include ::API::Helpers::MembersHelpers
+
+ argument :user_ids,
+ [::Types::GlobalIDType[::User]],
+ required: true,
+ description: 'Global IDs of the members.'
+
+ argument :access_level,
+ ::Types::MemberAccessLevelEnum,
+ required: true,
+ description: 'Access level to update the members to.'
+
+ argument :expires_at,
+ Types::TimeType,
+ required: false,
+ description: 'Date and time the membership expires.'
+
+ MAX_MEMBERS_UPDATE_LIMIT = 50
+ MAX_MEMBERS_UPDATE_ERROR = "Count of members to be updated should be less than #{MAX_MEMBERS_UPDATE_LIMIT}."
+ .freeze
+ INVALID_MEMBERS_ERROR = 'Only access level of direct members can be updated.'
+
+ def resolve(**args)
+ result = ::Members::UpdateService
+ .new(current_user, args.except(:user_ids, source_id_param_name))
+ .execute(@updatable_members)
+
+ {
+ source_members_key => result[:members],
+ errors: Array.wrap(result[:message])
+ }
+ rescue Gitlab::Access::AccessDeniedError
+ {
+ errors: ["Unable to update members, please check user permissions."]
+ }
+ end
+
+ private
+
+ def ready?(**args)
+ source = authorized_find!(source_id: args[source_id_param_name])
+ user_ids = args.fetch(:user_ids, {}).map(&:model_id)
+ @updatable_members = only_direct_members(source, user_ids)
+
+ if @updatable_members.size > MAX_MEMBERS_UPDATE_LIMIT
+ raise Gitlab::Graphql::Errors::InvalidMemberCountError, MAX_MEMBERS_UPDATE_ERROR
+ end
+
+ if @updatable_members.size != user_ids.size
+ raise Gitlab::Graphql::Errors::InvalidMembersError, INVALID_MEMBERS_ERROR
+ end
+
+ super
+ end
+
+ def find_object(source_id:)
+ GitlabSchema.object_from_id(source_id, expected_type: source_type)
+ end
+
+ def only_direct_members(source, user_ids)
+ source_members(source)
+ .with_user(user_ids)
+ .to_a
+ end
+
+ def source_id_param_name
+ "#{source_name}_id".to_sym
+ end
+
+ def source_members_key
+ "#{source_name}_members".to_sym
+ end
+
+ def source_name
+ source_type.name.downcase
+ end
+
+ def source_type
+ raise NotImplementedError
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/members/groups/bulk_update.rb b/app/graphql/mutations/members/groups/bulk_update.rb
index d0b19bd9634..fe3c7521c20 100644
--- a/app/graphql/mutations/members/groups/bulk_update.rb
+++ b/app/graphql/mutations/members/groups/bulk_update.rb
@@ -3,81 +3,22 @@
module Mutations
module Members
module Groups
- class BulkUpdate < ::Mutations::BaseMutation
+ class BulkUpdate < BulkUpdateBase
graphql_name 'GroupMemberBulkUpdate'
-
- include Gitlab::Utils::StrongMemoize
-
authorize :admin_group_member
field :group_members,
- [Types::GroupMemberType],
- null: true,
- description: 'Group members after mutation.'
+ [Types::GroupMemberType],
+ null: true,
+ description: 'Group members after mutation.'
argument :group_id,
- ::Types::GlobalIDType[::Group],
- required: true,
- description: 'Global ID of the group.'
-
- argument :user_ids,
- [::Types::GlobalIDType[::User]],
- required: true,
- description: 'Global IDs of the group members.'
-
- argument :access_level,
- ::Types::MemberAccessLevelEnum,
- required: true,
- description: 'Access level to update the members to.'
-
- argument :expires_at,
- Types::TimeType,
- required: false,
- description: 'Date and time the membership expires.'
-
- MAX_MEMBERS_UPDATE_LIMIT = 50
- MAX_MEMBERS_UPDATE_ERROR = "Count of members to be updated should be less than #{MAX_MEMBERS_UPDATE_LIMIT}."
- INVALID_MEMBERS_ERROR = 'Only access level of direct members can be updated.'
-
- def resolve(group_id:, **args)
- result = ::Members::UpdateService.new(current_user, args.except(:user_ids)).execute(@updatable_group_members)
-
- {
- group_members: result[:members],
- errors: Array.wrap(result[:message])
- }
- rescue Gitlab::Access::AccessDeniedError
- {
- errors: ["Unable to update members, please check user permissions."]
- }
- end
-
- private
-
- def ready?(**args)
- group = authorized_find!(group_id: args[:group_id])
- user_ids = args.fetch(:user_ids, {}).map(&:model_id)
- @updatable_group_members = only_direct_group_members(group, user_ids)
-
- if @updatable_group_members.size > MAX_MEMBERS_UPDATE_LIMIT
- raise Gitlab::Graphql::Errors::InvalidMemberCountError, MAX_MEMBERS_UPDATE_ERROR
- end
-
- if @updatable_group_members.size != user_ids.size
- raise Gitlab::Graphql::Errors::InvalidMembersError, INVALID_MEMBERS_ERROR
- end
-
- super
- end
-
- def find_object(group_id:)
- GitlabSchema.object_from_id(group_id, expected_type: ::Group)
- end
+ ::Types::GlobalIDType[::Group],
+ required: true,
+ description: 'Global ID of the group.'
- def only_direct_group_members(group, user_ids)
- group
- .members
- .with_user(user_ids).to_a
+ def source_type
+ ::Group
end
end
end
diff --git a/app/graphql/mutations/members/projects/bulk_update.rb b/app/graphql/mutations/members/projects/bulk_update.rb
new file mode 100644
index 00000000000..cfb88e60c44
--- /dev/null
+++ b/app/graphql/mutations/members/projects/bulk_update.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Members
+ module Projects
+ class BulkUpdate < BulkUpdateBase
+ graphql_name 'ProjectMemberBulkUpdate'
+ authorize :admin_project_member
+
+ field :project_members,
+ [Types::ProjectMemberType],
+ null: true,
+ description: 'Project members after mutation.'
+
+ argument :project_id,
+ ::Types::GlobalIDType[::Project],
+ required: true,
+ description: 'Global ID of the project.'
+
+ def source_type
+ ::Project
+ 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 2e7c0c5a2f9..d458bdcf82b 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
@@ -10,7 +10,7 @@ module Mutations
ANNOTATION_SOURCE_ARGUMENT_ERROR = 'Either a cluster or environment global id is required'
INVALID_ANNOTATION_SOURCE_ERROR = 'Invalid cluster or environment id'
- authorize :create_metrics_dashboard_annotation
+ authorize :admin_metrics_dashboard_annotation
field :annotation,
Types::Metrics::Dashboards::AnnotationType,
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/delete.rb b/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
index e0fadff13d4..0ee2791f78b 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
@@ -7,7 +7,7 @@ module Mutations
class Delete < Base
graphql_name 'DeleteAnnotation'
- authorize :delete_metrics_dashboard_annotation
+ authorize :admin_metrics_dashboard_annotation
argument :id, ::Types::GlobalIDType[::Metrics::Dashboard::Annotation],
required: true,
diff --git a/app/graphql/mutations/projects/sync_fork.rb b/app/graphql/mutations/projects/sync_fork.rb
new file mode 100644
index 00000000000..121c16df87b
--- /dev/null
+++ b/app/graphql/mutations/projects/sync_fork.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Projects
+ class SyncFork < BaseMutation
+ graphql_name 'ProjectSyncFork'
+
+ include FindsProject
+
+ authorize :push_code
+
+ argument :project_path, GraphQL::Types::ID,
+ required: true,
+ description: 'Full path of the project to initialize.'
+
+ argument :target_branch, GraphQL::Types::String,
+ required: true,
+ description: 'Ref of the fork to fetch into.'
+
+ field :details, Types::Projects::ForkDetailsType,
+ null: true,
+ description: 'Updated fork details.'
+
+ def resolve(project_path:, target_branch:)
+ project = authorized_find!(project_path)
+
+ return respond(nil, ['Feature flag is disabled']) unless Feature.enabled?(:synchronize_fork, project)
+
+ details_resolver = Resolvers::Projects::ForkDetailsResolver.new(object: project, context: context, field: nil)
+ details = details_resolver.resolve(ref: target_branch)
+
+ return respond(nil, ['This branch of this project cannot be updated from the upstream']) unless details
+
+ enqueue_sync_fork(project, target_branch, details)
+ end
+
+ def enqueue_sync_fork(project, target_branch, details)
+ return respond(details, []) if details.counts[:behind] == 0
+
+ if details.has_conflicts?
+ return respond(details, ['The synchronization cannot happen due to the merge conflict'])
+ end
+
+ return respond(details, ['This service has been called too many times.']) if rate_limit_throttled?(project)
+ return respond(details, ['Another fork sync is already in progress']) unless details.exclusive_lease.try_obtain
+
+ ::Projects::Forks::SyncWorker.perform_async(project.id, current_user.id, target_branch) # rubocop:disable CodeReuse/Worker
+
+ respond(details, [])
+ end
+
+ def rate_limit_throttled?(project)
+ Gitlab::ApplicationRateLimiter.throttled?(:project_fork_sync, scope: [project, current_user])
+ end
+
+ def respond(details, errors)
+ { details: details, errors: errors }
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/release_asset_links/create.rb b/app/graphql/mutations/release_asset_links/create.rb
index f6445514ce9..bda998764b9 100644
--- a/app/graphql/mutations/release_asset_links/create.rb
+++ b/app/graphql/mutations/release_asset_links/create.rb
@@ -36,13 +36,15 @@ module Mutations
raise_resource_not_available_error!
end
- new_link = release.links.create(link_attrs)
-
- unless new_link.persisted?
- return { link: nil, errors: new_link.errors.full_messages }
+ result = ::Releases::Links::CreateService
+ .new(release, current_user, link_attrs)
+ .execute
+
+ if result.success?
+ { link: result.payload[:link], errors: [] }
+ else
+ { link: nil, errors: result.message }
end
-
- { link: new_link, errors: [] }
end
end
end
diff --git a/app/graphql/mutations/release_asset_links/delete.rb b/app/graphql/mutations/release_asset_links/delete.rb
index 91fa74859f6..9a75b472411 100644
--- a/app/graphql/mutations/release_asset_links/delete.rb
+++ b/app/graphql/mutations/release_asset_links/delete.rb
@@ -21,11 +21,15 @@ module Mutations
def resolve(id:)
link = authorized_find!(id)
- unless link.destroy
- return { link: nil, errors: link.errors.full_messages }
+ result = ::Releases::Links::DestroyService
+ .new(link.release, current_user)
+ .execute(link)
+
+ if result.success?
+ { link: result.payload[:link], errors: [] }
+ else
+ { link: nil, errors: result.message }
end
-
- { link: link, errors: [] }
end
def find_object(id)
diff --git a/app/graphql/mutations/release_asset_links/update.rb b/app/graphql/mutations/release_asset_links/update.rb
index f9368927371..2e9054c290d 100644
--- a/app/graphql/mutations/release_asset_links/update.rb
+++ b/app/graphql/mutations/release_asset_links/update.rb
@@ -46,11 +46,15 @@ module Mutations
def resolve(id:, **link_attrs)
link = authorized_find!(id)
- unless link.update(link_attrs)
- return { link: nil, errors: link.errors.full_messages }
- end
+ result = ::Releases::Links::UpdateService
+ .new(link.release, current_user, link_attrs)
+ .execute(link)
- { link: link, errors: [] }
+ if result.success?
+ { link: result.payload[:link], errors: [] }
+ else
+ { link: nil, errors: result.message }
+ end
end
def find_object(id)
diff --git a/app/graphql/mutations/work_items/export.rb b/app/graphql/mutations/work_items/export.rb
new file mode 100644
index 00000000000..5ba50aa6cb2
--- /dev/null
+++ b/app/graphql/mutations/work_items/export.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module Mutations
+ module WorkItems
+ class Export < BaseMutation
+ graphql_name 'WorkItemExport'
+
+ include FindsProject
+ include ::WorkItems::SharedFilterArguments
+ include ::SearchArguments
+
+ authorize :export_work_items
+
+ argument :project_path,
+ GraphQL::Types::ID,
+ required: true,
+ description: 'Full project path.'
+
+ argument :selected_fields,
+ [::Types::WorkItems::AvailableExportFieldsEnum],
+ required: false,
+ description: 'List of selected fields to be exported. Omit to export all available fields.'
+
+ def resolve(args)
+ project_path = args.delete(:project_path)
+ project = authorized_find!(project_path)
+
+ check_export_available_for!(project)
+
+ # rubocop:disable CodeReuse/Worker
+ IssuableExportCsvWorker.perform_async(:work_item, current_user.id, project.id, args)
+ # rubocop:enable CodeReuse/Worker
+
+ {
+ errors: []
+ }
+ end
+
+ def check_export_available_for!(project)
+ return if Feature.enabled?(:import_export_work_items_csv, project)
+
+ error = '`import_export_work_items_csv` feature flag is disabled.'
+
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable, error
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/work_items/update.rb b/app/graphql/mutations/work_items/update.rb
index db6af38d82e..60b5536df56 100644
--- a/app/graphql/mutations/work_items/update.rb
+++ b/app/graphql/mutations/work_items/update.rb
@@ -60,21 +60,10 @@ module Mutations
description_param[:description] = description if description && description != original_description
- # Widgets have a set of quick action params that they must process.
- # Map them to widget_params so they can be picked up by widget services.
- work_item.work_item_type.widgets
- .filter { |widget| widget.respond_to?(:quick_action_params) }
- .each do |widget|
- widget.quick_action_params
- .filter { |param_name| command_params.key?(param_name) }
- .each do |param_name|
- widget_params[widget.api_symbol] ||= {}
- widget_params[widget.api_symbol][param_name] = command_params.delete(param_name)
- end
- end
-
- # The command_params not processed by widgets (e.g. title) should be placed in 'attributes'.
- attributes.merge!(command_params || {})
+ parsed_params = work_item.transform_quick_action_params(command_params)
+
+ widget_params.merge!(parsed_params[:widgets])
+ attributes.merge!(parsed_params[:common])
end
end
end
diff --git a/app/graphql/queries/repository/path_last_commit.query.graphql b/app/graphql/queries/repository/path_last_commit.query.graphql
index 914be3a72c1..facbf1555fc 100644
--- a/app/graphql/queries/repository/path_last_commit.query.graphql
+++ b/app/graphql/queries/repository/path_last_commit.query.graphql
@@ -27,7 +27,30 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
avatarUrl
webPath
}
- signatureHtml
+ signature {
+ __typename
+ ... on GpgSignature {
+ gpgKeyPrimaryKeyid
+ verificationStatus
+ }
+ ... on X509Signature {
+ verificationStatus
+ x509Certificate {
+ id
+ subject
+ subjectKeyIdentifier
+ x509Issuer {
+ id
+ subject
+ subjectKeyIdentifier
+ }
+ }
+ }
+ ... on SshSignature {
+ verificationStatus
+ keyFingerprintSha256
+ }
+ }
pipelines(ref: $ref, first: 1) {
__typename
edges {
diff --git a/app/graphql/resolvers/achievements/achievements_resolver.rb b/app/graphql/resolvers/achievements/achievements_resolver.rb
new file mode 100644
index 00000000000..1d71fa1d9c1
--- /dev/null
+++ b/app/graphql/resolvers/achievements/achievements_resolver.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Achievements
+ class AchievementsResolver < BaseResolver
+ include LooksAhead
+
+ type ::Types::Achievements::AchievementType.connection_type, null: true
+
+ alias_method :namespace, :object
+
+ def resolve_with_lookahead
+ return ::Achievements::Achievement.none if Feature.disabled?(:achievements, namespace)
+
+ apply_lookahead(namespace.achievements)
+ end
+
+ private
+
+ def preloads
+ {
+ user_achievements: [{ user_achievements: [:user, :awarded_by_user, :revoked_by_user] }]
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/achievements/user_achievements_resolver.rb b/app/graphql/resolvers/achievements/user_achievements_resolver.rb
new file mode 100644
index 00000000000..bf09d80afc1
--- /dev/null
+++ b/app/graphql/resolvers/achievements/user_achievements_resolver.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Achievements
+ class UserAchievementsResolver < BaseResolver
+ include LooksAhead
+
+ type ::Types::Achievements::UserAchievementType.connection_type, null: true
+
+ def resolve_with_lookahead
+ user_achievements = object.user_achievements.not_revoked
+
+ apply_lookahead(user_achievements)
+ end
+
+ private
+
+ def unconditional_includes
+ [
+ { achievement: [:namespace] }
+ ]
+ end
+
+ def preloads
+ {
+ user: [:user],
+ awarded_by_user: [:awarded_by_user],
+ revoked_by_user: [:revoked_by_user]
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb b/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb
new file mode 100644
index 00000000000..f08de3c5d7e
--- /dev/null
+++ b/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Analytics
+ module CycleAnalytics
+ class BaseIssueResolver < BaseResolver
+ type Types::Analytics::CycleAnalytics::MetricType, null: true
+
+ argument :assignee_usernames, [GraphQL::Types::String],
+ required: false,
+ description: 'Usernames of users assigned to the issue.'
+
+ argument :author_username, GraphQL::Types::String,
+ required: false,
+ description: 'Username of the author of the issue.'
+
+ argument :milestone_title, GraphQL::Types::String,
+ required: false,
+ description: 'Milestone applied to the issue.'
+
+ argument :label_names, [GraphQL::Types::String],
+ required: false,
+ description: 'Labels applied to the issue.'
+
+ argument :from, Types::TimeType,
+ required: true,
+ description: 'Issues created after the date.'
+
+ argument :to, Types::TimeType,
+ required: true,
+ description: 'Issues created before the date.'
+
+ def finder_params
+ { project_id: object.project.id }
+ end
+
+ # :project level: no customization, returning the original resolver
+ # :group level: add the project_ids argument
+ def self.[](context = :project)
+ case context
+ when :project
+ self
+ when :group
+ Class.new(self) do
+ argument :project_ids, [GraphQL::Types::ID],
+ required: false,
+ description: 'Project IDs within the group hierarchy.'
+
+ define_method :finder_params do
+ { group_id: object.id, include_subgroups: true }
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb b/app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb
new file mode 100644
index 00000000000..be17601e7a2
--- /dev/null
+++ b/app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Analytics
+ module CycleAnalytics
+ class DeploymentCountResolver < BaseResolver
+ type Types::Analytics::CycleAnalytics::MetricType, null: true
+
+ argument :from, Types::TimeType,
+ required: true,
+ description: 'Deployments finished after the date.'
+
+ argument :to, Types::TimeType,
+ required: true,
+ description: 'Deployments finished before the date.'
+
+ def resolve(**args)
+ value = count(args)
+ {
+ value: value,
+ title: n_('Deploy', 'Deploys', value.to_i),
+ identifier: 'deploys',
+ links: []
+ }
+ end
+
+ private
+
+ def count(args)
+ finder = DeploymentsFinder.new({
+ finished_after: args[:from],
+ finished_before: args[:to],
+ project: object.project,
+ status: :success,
+ order_by: :finished_at
+ })
+
+ finder.execute.count
+ end
+
+ # :project level: no customization, returning the original resolver
+ # :group level: add the project_ids argument
+ def self.[](context = :project)
+ case context
+ when :project
+ self
+ when :group
+ Class.new(self) do
+ argument :project_ids, [GraphQL::Types::ID],
+ required: false,
+ description: 'Project IDs within the group hierarchy.'
+ end
+
+ end
+ end
+ end
+ end
+ end
+end
+
+mod = Resolvers::Analytics::CycleAnalytics::DeploymentCountResolver
+mod.prepend_mod_with('Resolvers::Analytics::CycleAnalytics::DeploymentCountResolver')
diff --git a/app/graphql/resolvers/analytics/cycle_analytics/issue_count_resolver.rb b/app/graphql/resolvers/analytics/cycle_analytics/issue_count_resolver.rb
new file mode 100644
index 00000000000..fd20800ee16
--- /dev/null
+++ b/app/graphql/resolvers/analytics/cycle_analytics/issue_count_resolver.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+# rubocop:disable Graphql/ResolverType (inherited from Resolvers::Analytics::CycleAnalytics::BaseIssueResolver)
+module Resolvers
+ module Analytics
+ module CycleAnalytics
+ class IssueCountResolver < BaseIssueResolver
+ def resolve(**args)
+ value = IssuesFinder
+ .new(current_user, process_params(args))
+ .execute
+ .count
+
+ {
+ value: value,
+ title: n_('New Issue', 'New Issues', value),
+ identifier: 'issues',
+ links: []
+ }
+ end
+
+ private
+
+ def process_params(params)
+ params[:assignee_username] = params.delete(:assignee_usernames) if params[:assignee_usernames]
+ params[:label_name] = params.delete(:label_names) if params[:label_names]
+ params[:created_after] = params.delete(:from)
+ params[:created_before] = params.delete(:to)
+ params[:projects] = params[:project_ids] if params[:project_ids]
+
+ params.merge(finder_params)
+ end
+ end
+ end
+ end
+end
+# rubocop:enable Graphql/ResolverType
diff --git a/app/graphql/resolvers/ci/pipeline_job_artifacts_resolver.rb b/app/graphql/resolvers/ci/pipeline_job_artifacts_resolver.rb
index 35d30827561..561c61e3b27 100644
--- a/app/graphql/resolvers/ci/pipeline_job_artifacts_resolver.rb
+++ b/app/graphql/resolvers/ci/pipeline_job_artifacts_resolver.rb
@@ -15,7 +15,7 @@ module Resolvers
def find_job_artifacts
BatchLoader::GraphQL.for(pipeline).batch do |pipelines, loader|
- ActiveRecord::Associations::Preloader.new.preload(pipelines, :job_artifacts) # rubocop: disable CodeReuse/ActiveRecord
+ ActiveRecord::Associations::Preloader.new(records: pipelines, associations: :job_artifacts).call # rubocop: disable CodeReuse/ActiveRecord
pipelines.each { |pl| loader.call(pl, pl.job_artifacts) }
end
diff --git a/app/graphql/resolvers/ci/runner_projects_resolver.rb b/app/graphql/resolvers/ci/runner_projects_resolver.rb
index 2a2d63f85de..13a493c42a5 100644
--- a/app/graphql/resolvers/ci/runner_projects_resolver.rb
+++ b/app/graphql/resolvers/ci/runner_projects_resolver.rb
@@ -68,9 +68,9 @@ module Resolvers
def preloads
super.merge({
- full_path: [:route, { namespace: [:route] }],
- web_url: [:route, { namespace: [:route] }]
- })
+ full_path: [:route, { namespace: [:route] }],
+ web_url: [:route, { namespace: [:route] }]
+ })
end
end
end
diff --git a/app/graphql/resolvers/ci/runner_resolver.rb b/app/graphql/resolvers/ci/runner_resolver.rb
index ca94e28b2e9..4250b069d20 100644
--- a/app/graphql/resolvers/ci/runner_resolver.rb
+++ b/app/graphql/resolvers/ci/runner_resolver.rb
@@ -22,11 +22,15 @@ module Resolvers
def find_runner(id:)
runner_id = GitlabSchema.parse_gid(id, expected_type: ::Ci::Runner).model_id.to_i
- preload_tag_list = lookahead.selects?(:tag_list)
+ key = {
+ preload_tag_list: lookahead.selects?(:tag_list),
+ preload_creator: lookahead.selects?(:created_by)
+ }
- BatchLoader::GraphQL.for(runner_id).batch(key: { preload_tag_list: preload_tag_list }) do |ids, loader, batch|
+ BatchLoader::GraphQL.for(runner_id).batch(key: key) do |ids, loader, batch|
results = ::Ci::Runner.id_in(ids)
results = results.with_tags if batch[:key][:preload_tag_list]
+ results = results.with_creator if batch[:key][:preload_creator]
results.each { |record| loader.call(record.id, record) }
end
diff --git a/app/graphql/resolvers/ci/runners_resolver.rb b/app/graphql/resolvers/ci/runners_resolver.rb
index b52a4cc0ab4..735e38c1a5c 100644
--- a/app/graphql/resolvers/ci/runners_resolver.rb
+++ b/app/graphql/resolvers/ci/runners_resolver.rb
@@ -61,9 +61,7 @@ module Resolvers
upgrade_status: params[:upgrade_status],
search: params[:search],
sort: params[:sort]&.to_s,
- preload: {
- tag_name: node_selection&.selects?(:tag_list)
- }
+ preload: false # we'll handle preloading ourselves
}.compact
.merge(parent_param)
end
@@ -79,6 +77,31 @@ module Resolvers
def parent
object.respond_to?(:sync) ? object.sync : object
end
+
+ def preloads
+ super.merge({
+ created_by: [:creator],
+ 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/concerns/work_items/shared_filter_arguments.rb b/app/graphql/resolvers/concerns/work_items/shared_filter_arguments.rb
new file mode 100644
index 00000000000..ecb105a64d0
--- /dev/null
+++ b/app/graphql/resolvers/concerns/work_items/shared_filter_arguments.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module SharedFilterArguments
+ extend ActiveSupport::Concern
+
+ included do
+ argument :author_username,
+ GraphQL::Types::String,
+ required: false,
+ description: 'Filter work items by author username.',
+ alpha: { milestone: '15.9' }
+ argument :iids,
+ [GraphQL::Types::String],
+ required: false,
+ description: 'List of IIDs of work items. For example, `["1", "2"]`.'
+ argument :state,
+ Types::IssuableStateEnum,
+ required: false,
+ description: 'Current state of the work item.'
+ argument :types,
+ [Types::IssueTypeEnum],
+ as: :issue_types,
+ description: 'Filter work items by the given work item types.',
+ required: false
+ end
+ end
+end
diff --git a/app/graphql/resolvers/project_merge_requests_resolver.rb b/app/graphql/resolvers/project_merge_requests_resolver.rb
index 66c020a0c14..6a240541341 100644
--- a/app/graphql/resolvers/project_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/project_merge_requests_resolver.rb
@@ -22,7 +22,13 @@ module Resolvers
def only_count_is_selected_with_merged_at_filter?(args)
return unless lookahead
- argument_names = args.compact.except(:lookahead, :sort, :merged_before, :merged_after).keys
+ # Filter out all elements with blank values. If any of the values are not
+ # scalars, e.g. hashes or array, filter blank values from them and remove
+ # them if the resulting collection is empty.
+ argument_names = args.except(:lookahead, :sort, :merged_before, :merged_after).filter_map do |key, value|
+ value = value.to_hash.compact if value.respond_to?(:to_hash)
+ key if value.present?
+ end
# no extra filtering arguments are provided
return unless argument_names.empty?
diff --git a/app/graphql/resolvers/projects/fork_details_resolver.rb b/app/graphql/resolvers/projects/fork_details_resolver.rb
index fcc13a1bc1e..a3c60f55e14 100644
--- a/app/graphql/resolvers/projects/fork_details_resolver.rb
+++ b/app/graphql/resolvers/projects/fork_details_resolver.rb
@@ -13,8 +13,17 @@ module Resolvers
def resolve(**args)
return unless project.forked?
+ return unless authorized_fork_source?
+ return unless project.repository.branch_exists?(args[:ref])
+ return unless Feature.enabled?(:fork_divergence_counts, project)
- ::Projects::Forks::DivergenceCounts.new(project, args[:ref]).counts
+ ::Projects::Forks::Details.new(project, args[:ref])
+ end
+
+ private
+
+ def authorized_fork_source?
+ Ability.allowed?(current_user, :read_code, project.fork_source)
end
end
end
diff --git a/app/graphql/resolvers/work_items_resolver.rb b/app/graphql/resolvers/work_items_resolver.rb
index 0c9aac80274..7115b028481 100644
--- a/app/graphql/resolvers/work_items_resolver.rb
+++ b/app/graphql/resolvers/work_items_resolver.rb
@@ -4,30 +4,19 @@ module Resolvers
class WorkItemsResolver < BaseResolver
include SearchArguments
include LooksAhead
+ include ::WorkItems::SharedFilterArguments
- type Types::WorkItemType.connection_type, null: true
+ argument :iid,
+ GraphQL::Types::String,
+ required: false,
+ description: 'IID of the work item. For example, "1".'
+ argument :sort,
+ Types::WorkItemSortEnum,
+ description: 'Sort work items by criteria.',
+ required: false,
+ default_value: :created_desc
- argument :author_username, GraphQL::Types::String,
- required: false,
- description: 'Filter work items by author username.',
- alpha: { milestone: '15.9' }
- argument :iid, GraphQL::Types::String,
- required: false,
- description: 'IID of the issue. For example, "1".'
- argument :iids, [GraphQL::Types::String],
- required: false,
- description: 'List of IIDs of work items. For example, `["1", "2"]`.'
- argument :sort, Types::WorkItemSortEnum,
- description: 'Sort work items by this criteria.',
- required: false,
- default_value: :created_desc
- argument :state, Types::IssuableStateEnum,
- required: false,
- description: 'Current state of this work item.'
- argument :types, [Types::IssueTypeEnum],
- as: :issue_types,
- description: 'Filter work items by the given work item types.',
- required: false
+ type Types::WorkItemType.connection_type, null: true
def resolve_with_lookahead(**args)
return WorkItem.none if resource_parent.nil?
@@ -66,7 +55,8 @@ module Resolvers
parent: :work_item_parent,
children: { work_item_children_by_relative_position: [:author, { project: :project_feature }] },
labels: :labels,
- milestone: { milestone: [:project, :group] }
+ milestone: { milestone: [:project, :group] },
+ subscribed: [:assignees, :award_emoji, { notes: [:author, :award_emoji] }]
}
end
diff --git a/app/graphql/types/achievements/achievement_type.rb b/app/graphql/types/achievements/achievement_type.rb
index 67cc9778797..71f51b9b741 100644
--- a/app/graphql/types/achievements/achievement_type.rb
+++ b/app/graphql/types/achievements/achievement_type.rb
@@ -42,6 +42,12 @@ module Types
null: false,
description: 'Timestamp the achievement was last updated.'
+ field :user_achievements,
+ Types::Achievements::UserAchievementType.connection_type,
+ null: true,
+ alpha: { milestone: '15.10' },
+ description: "Recipients for the achievement."
+
def avatar_url
object.avatar_url(only_path: false)
end
diff --git a/app/graphql/types/achievements/user_achievement_type.rb b/app/graphql/types/achievements/user_achievement_type.rb
new file mode 100644
index 00000000000..d2146807445
--- /dev/null
+++ b/app/graphql/types/achievements/user_achievement_type.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Types
+ module Achievements
+ class UserAchievementType < BaseObject
+ graphql_name 'UserAchievement'
+
+ authorize :read_achievement
+
+ field :id,
+ ::Types::GlobalIDType[::Achievements::UserAchievement],
+ null: false,
+ description: 'ID of the user achievement.'
+
+ field :achievement,
+ ::Types::Achievements::AchievementType,
+ null: false,
+ description: 'Achievement awarded.'
+
+ field :user,
+ ::Types::UserType,
+ null: false,
+ description: 'Achievement recipient.'
+
+ field :awarded_by_user,
+ ::Types::UserType,
+ null: false,
+ description: 'Awarded by.'
+
+ field :revoked_by_user,
+ ::Types::UserType,
+ null: true,
+ description: 'Revoked by.'
+
+ field :created_at,
+ Types::TimeType,
+ null: false,
+ description: 'Timestamp the achievement was created.'
+
+ field :updated_at,
+ Types::TimeType,
+ null: false,
+ description: 'Timestamp the achievement was last updated.'
+
+ field :revoked_at,
+ Types::TimeType,
+ null: true,
+ description: 'Timestamp the achievement was revoked.'
+ end
+ end
+end
diff --git a/app/graphql/types/analytics/cycle_analytics/flow_metrics.rb b/app/graphql/types/analytics/cycle_analytics/flow_metrics.rb
new file mode 100644
index 00000000000..c9a28767e11
--- /dev/null
+++ b/app/graphql/types/analytics/cycle_analytics/flow_metrics.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Types
+ module Analytics
+ module CycleAnalytics
+ module FlowMetrics
+ def self.[](context = :project)
+ Class.new(BaseObject) do
+ graphql_name "#{context.capitalize}ValueStreamAnalyticsFlowMetrics"
+ description 'Exposes aggregated value stream flow metrics'
+
+ field :issue_count,
+ Types::Analytics::CycleAnalytics::MetricType,
+ null: true,
+ description: 'Number of issues opened in the given period.',
+ resolver: Resolvers::Analytics::CycleAnalytics::IssueCountResolver[context]
+ field :deployment_count,
+ Types::Analytics::CycleAnalytics::MetricType,
+ null: true,
+ description: 'Number of production deployments in the given period.',
+ resolver: Resolvers::Analytics::CycleAnalytics::DeploymentCountResolver[context]
+ end
+ end
+ end
+ end
+ end
+end
+
+mod = Types::Analytics::CycleAnalytics::FlowMetrics
+mod.prepend_mod_with('Types::Analytics::CycleAnalytics::FlowMetrics')
diff --git a/app/graphql/types/analytics/cycle_analytics/link_type.rb b/app/graphql/types/analytics/cycle_analytics/link_type.rb
new file mode 100644
index 00000000000..3db6b58ac55
--- /dev/null
+++ b/app/graphql/types/analytics/cycle_analytics/link_type.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Types
+ module Analytics
+ module CycleAnalytics
+ # rubocop: disable Graphql/AuthorizeTypes
+ class LinkType < BaseObject
+ graphql_name 'ValueStreamMetricLinkType'
+
+ field :name,
+ GraphQL::Types::String,
+ null: false,
+ description: 'Name of the link group.'
+
+ field :label,
+ GraphQL::Types::String,
+ null: false,
+ description: 'Label for the link.'
+
+ field :url,
+ GraphQL::Types::String,
+ null: false,
+ description: 'Drill-down URL.'
+
+ field :docs_link,
+ GraphQL::Types::Boolean,
+ null: true,
+ description: 'Link to the metric documentation.'
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/analytics/cycle_analytics/metric_type.rb b/app/graphql/types/analytics/cycle_analytics/metric_type.rb
new file mode 100644
index 00000000000..3f1a239019f
--- /dev/null
+++ b/app/graphql/types/analytics/cycle_analytics/metric_type.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Types
+ module Analytics
+ module CycleAnalytics
+ # rubocop: disable Graphql/AuthorizeTypes
+ class MetricType < BaseObject
+ graphql_name 'ValueStreamAnalyticsMetric'
+ description ''
+
+ field :value,
+ GraphQL::Types::Float,
+ null: true,
+ description: 'Value for the metric.'
+
+ field :identifier,
+ GraphQL::Types::String,
+ null: false,
+ description: 'Identifier for the metric.'
+
+ field :unit,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Unit of measurement.'
+
+ field :title,
+ GraphQL::Types::String,
+ null: false,
+ description: 'Title for the metric.'
+
+ field :links,
+ [LinkType],
+ null: false,
+ description: 'Optional links for drilling down.'
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/board_list_type.rb b/app/graphql/types/board_list_type.rb
index 2352a21bd87..20661da8d94 100644
--- a/app/graphql/types/board_list_type.rb
+++ b/app/graphql/types/board_list_type.rb
@@ -55,7 +55,7 @@ module Types
# board lists have a data dependency on label - so we batch load them here
def title
BatchLoader::GraphQL.for(object).batch do |lists, callback|
- ActiveRecord::Associations::Preloader.new.preload(lists, :label) # rubocop: disable CodeReuse/ActiveRecord
+ ActiveRecord::Associations::Preloader.new(records: lists, associations: :label).call # rubocop: disable CodeReuse/ActiveRecord
# all list titles are preloaded at this point
lists.each { |list| callback.call(list, list.title) }
diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb
index a97e9cee4b1..60c1c2e601d 100644
--- a/app/graphql/types/ci/job_type.rb
+++ b/app/graphql/types/ci/job_type.rb
@@ -25,6 +25,9 @@ module Types
description: 'References to builds that must complete before the jobs run.'
field :pipeline, Types::Ci::PipelineType, null: true,
description: 'Pipeline the job belongs to.'
+ field :runner_machine, ::Types::Ci::RunnerMachineType, null: true,
+ description: 'Runner machine assigned to the job.',
+ alpha: { milestone: '15.11' }
field :stage, Types::Ci::StageType, null: true,
description: 'Stage of the job.'
field :status,
@@ -76,6 +79,8 @@ module Types
description: 'Whether the job has a manual action.'
field :manual_variables, ManualVariableType.connection_type, null: true,
description: 'Variables added to a manual job when the job is triggered.'
+ field :play_path, GraphQL::Types::String, null: true,
+ 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_or_needs, Types::Ci::JobNeedUnion.connection_type, null: true,
@@ -88,6 +93,8 @@ module Types
description: 'Indicates that the job has been retried.'
field :retryable, GraphQL::Types::Boolean, null: false, method: :retryable?,
description: 'Indicates the job can be retried.'
+ field :scheduled, GraphQL::Types::Boolean, null: false, method: :scheduled?,
+ description: 'Indicates the job is scheduled.'
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,
@@ -101,6 +108,14 @@ module Types
field :project, Types::ProjectType, null: true, description: 'Project that the job belongs to.'
+ field :can_play_job, GraphQL::Types::Boolean,
+ null: false, resolver_method: :can_play_job?,
+ description: 'Indicates whether the current user can play the job.'
+
+ def can_play_job?
+ object.playable? && Ability.allowed?(current_user, :play_job, object)
+ end
+
def kind
return ::Ci::Build unless [::Ci::Build, ::Ci::Bridge].include?(object.class)
@@ -157,6 +172,21 @@ module Types
::Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Stage, object.stage_id).find
end
+ def runner_machine
+ BatchLoader::GraphQL.for(object.id).batch(key: :runner_machines) do |build_ids, loader|
+ plucked_build_to_machine_ids = ::Ci::RunnerMachineBuild.for_build(build_ids).pluck_build_id_and_runner_machine_id
+ runner_machines = ::Ci::RunnerMachine.id_in(plucked_build_to_machine_ids.values.uniq)
+ Preloaders::RunnerMachinePolicyPreloader.new(runner_machines, current_user).execute
+ runner_machines_by_id = runner_machines.index_by(&:id)
+
+ build_ids.each do |build_id|
+ runner_machine_id = plucked_build_to_machine_ids[build_id]
+
+ loader.call(build_id, runner_machines_by_id[runner_machine_id])
+ end
+ end
+ end
+
# This class is a secret union!
# TODO: turn this into an actual union, so that fields can be referenced safely!
def id
@@ -183,6 +213,10 @@ module Types
::Gitlab::Routing.url_helpers.project_job_path(object.project, object)
end
+ def play_path
+ ::Gitlab::Routing.url_helpers.play_project_job_path(object.project, object)
+ end
+
def browse_artifacts_path
::Gitlab::Routing.url_helpers.browse_project_job_artifacts_path(object.project, object)
end
diff --git a/app/graphql/types/ci/runner_machine_type.rb b/app/graphql/types/ci/runner_machine_type.rb
new file mode 100644
index 00000000000..8e6656288d9
--- /dev/null
+++ b/app/graphql/types/ci/runner_machine_type.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ class RunnerMachineType < BaseObject
+ graphql_name 'CiRunnerMachine'
+
+ connection_type_class(::Types::CountableConnectionType)
+
+ authorize :read_runner_machine
+
+ alias_method :runner_machine, :object
+
+ field :architecture_name, GraphQL::Types::String, null: true,
+ description: 'Architecture provided by the runner machine.',
+ method: :architecture
+ field :contacted_at, Types::TimeType, null: true,
+ description: 'Timestamp of last contact from the runner machine.',
+ method: :contacted_at
+ field :created_at, Types::TimeType, null: true,
+ description: 'Timestamp of creation of the runner machine.'
+ field :executor_name, GraphQL::Types::String, null: true,
+ description: 'Executor last advertised by the runner.',
+ method: :executor_name
+ field :id, ::Types::GlobalIDType[::Ci::RunnerMachine], null: false,
+ description: 'ID of the runner machine.'
+ field :ip_address, GraphQL::Types::String, null: true,
+ description: 'IP address of the runner machine.'
+ field :platform_name, GraphQL::Types::String, null: true,
+ description: 'Platform provided by the runner machine.',
+ method: :platform
+ field :revision, GraphQL::Types::String, null: true, description: 'Revision of the runner.'
+ field :runner, RunnerType, null: true, description: 'Runner configuration for the runner machine.'
+ field :status,
+ Types::Ci::RunnerStatusEnum,
+ null: false,
+ description: 'Status of the runner machine.'
+ field :system_id, GraphQL::Types::String,
+ null: false,
+ description: 'System ID associated with the runner machine.',
+ method: :system_xid
+ field :version, GraphQL::Types::String, null: true, description: 'Version of the runner.'
+
+ def executor_name
+ ::Ci::Runner::EXECUTOR_TYPE_TO_NAMES[runner_machine.executor_type&.to_sym]
+ end
+ end
+ end
+end
+
+Types::Ci::RunnerType.prepend_mod_with('Types::Ci::RunnerType')
diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb
index 10d18f9ad2a..60ea78752ca 100644
--- a/app/graphql/types/ci/runner_type.rb
+++ b/app/graphql/types/ci/runner_type.rb
@@ -14,9 +14,6 @@ module Types
JOB_COUNT_LIMIT = 1000
- # Only allow ephemeral_authentication_token to be visible for a short while
- RUNNER_EPHEMERAL_TOKEN_AVAILABILITY_TIME = 3.hours
-
alias_method :runner, :object
field :access_level, ::Types::Ci::RunnerAccessLevelEnum, null: false,
@@ -34,12 +31,15 @@ module Types
method: :contacted_at
field :created_at, Types::TimeType, null: true,
description: 'Timestamp of creation of this runner.'
+ field :created_by, Types::UserType, null: true,
+ description: 'User that created this runner.',
+ method: :creator
field :description, GraphQL::Types::String, null: true,
description: 'Description of the runner.'
field :edit_admin_url, GraphQL::Types::String, null: true,
description: 'Admin form URL of the runner. Only available for administrators.'
field :ephemeral_authentication_token, GraphQL::Types::String, null: true,
- description: 'Ephemeral authentication token used for runner machine registration.',
+ description: 'Ephemeral authentication token used for runner machine registration. Only available for the creator of the runner for a limited time during registration.',
authorize: :read_ephemeral_token,
alpha: { milestone: '15.9' }
field :executor_name, GraphQL::Types::String, null: true,
@@ -58,13 +58,17 @@ module Types
Types::Ci::RunnerJobExecutionStatusEnum,
null: true,
description: 'Job execution status of the runner.',
- deprecated: { milestone: '15.7', reason: :alpha }
+ alpha: { milestone: '15.7' }
field :jobs, ::Types::Ci::JobType.connection_type, null: true,
description: 'Jobs assigned to the runner. This field can only be resolved for one runner in any single request.',
authorize: :read_builds,
resolver: ::Resolvers::Ci::RunnerJobsResolver
field :locked, GraphQL::Types::Boolean, null: true,
description: 'Indicates the runner is locked.'
+ field :machines, ::Types::Ci::RunnerMachineType.connection_type, null: true,
+ description: 'Machines associated with the runner configuration.',
+ method: :runner_machines,
+ alpha: { milestone: '15.10' }
field :maintenance_note, GraphQL::Types::String, null: true,
description: 'Runner\'s maintenance notes.'
field :maximum_timeout, GraphQL::Types::Int, null: true,
@@ -84,6 +88,8 @@ module Types
null: true,
resolver: ::Resolvers::Ci::RunnerProjectsResolver,
description: 'Find projects the runner is associated with. For project runners only.'
+ field :register_admin_url, GraphQL::Types::String, null: true,
+ description: 'URL of the temporary registration page of the runner. Only available before the runner is registered. Only available for administrators.'
field :revision, GraphQL::Types::String, null: true,
description: 'Revision of the runner.'
field :run_untagged, GraphQL::Types::Boolean, null: false,
@@ -141,12 +147,14 @@ module Types
Gitlab::Routing.url_helpers.edit_admin_runner_url(runner) if can_admin_runners?
end
- def ephemeral_authentication_token
- return unless runner.authenticated_user_registration_type?
- return unless runner.created_at > RUNNER_EPHEMERAL_TOKEN_AVAILABILITY_TIME.ago
- return if runner.runner_machines.any?
+ def register_admin_url
+ return unless can_admin_runners? && runner.registration_available?
- runner.token
+ Gitlab::Routing.url_helpers.register_admin_runner_url(runner)
+ end
+
+ def ephemeral_authentication_token
+ runner.token if runner.registration_available?
end
def project_count
diff --git a/app/graphql/types/commit_signatures/ssh_signature_type.rb b/app/graphql/types/commit_signatures/ssh_signature_type.rb
index 92eb4f7949a..d5db98c39a0 100644
--- a/app/graphql/types/commit_signatures/ssh_signature_type.rb
+++ b/app/graphql/types/commit_signatures/ssh_signature_type.rb
@@ -10,14 +10,19 @@ module Types
authorize :download_code
- field :user, Types::UserType, null: true,
- method: :signed_by_user,
- calls_gitaly: true,
- description: 'User associated with the key.'
+ field :user, Types::UserType,
+ null: true,
+ method: :signed_by_user,
+ calls_gitaly: true,
+ description: 'User associated with the key.'
field :key, Types::KeyType,
- null: true,
- description: 'SSH key used for the signature.'
+ null: true,
+ description: 'SSH key used for the signature.'
+
+ field :key_fingerprint_sha256, String,
+ null: true,
+ description: 'Fingerprint of the key.'
end
end
end
diff --git a/app/graphql/types/design_management/design_type.rb b/app/graphql/types/design_management/design_type.rb
index cc4c0e19ec7..be5edd17643 100644
--- a/app/graphql/types/design_management/design_type.rb
+++ b/app/graphql/types/design_management/design_type.rb
@@ -15,6 +15,11 @@ module Types
implements(Types::CurrentUserTodos)
implements(Types::TodoableInterface)
+ field :description,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Description of the design.'
+
field :web_url,
GraphQL::Types::String,
null: false,
@@ -25,6 +30,8 @@ module Types
resolver: Resolvers::DesignManagement::VersionsResolver,
description: "All versions related to this design ordered newest first."
+ markdown_field :description_html, null: true
+
# Returns a `DesignManagement::Version` for this query based on the
# `atVersion` argument passed to a parent node if present, or otherwise
# the most recent `Version` for the issue.
diff --git a/app/graphql/types/issuable_subscription_event_enum.rb b/app/graphql/types/issuable_subscription_event_enum.rb
new file mode 100644
index 00000000000..0f56fab8b46
--- /dev/null
+++ b/app/graphql/types/issuable_subscription_event_enum.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Types
+ class IssuableSubscriptionEventEnum < BaseEnum
+ graphql_name 'IssuableSubscriptionEvent'
+ description 'Values for subscribing and unsubscribing from issuables'
+
+ value 'SUBSCRIBE', 'Subscribe to an issuable.', value: 'subscribe'
+ value 'UNSUBSCRIBE', 'Unsubscribe from an issuable.', value: 'unsubscribe'
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index e48e9deae96..9bdbdad4386 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -6,7 +6,9 @@ module Types
include Gitlab::Graphql::MountMutation
- mount_mutation Mutations::Achievements::Create
+ mount_mutation Mutations::Achievements::Award, alpha: { milestone: '15.10' }
+ mount_mutation Mutations::Achievements::Create, alpha: { milestone: '15.8' }
+ mount_mutation Mutations::Achievements::Revoke, alpha: { milestone: '15.10' }
mount_mutation Mutations::Admin::SidekiqQueues::DeleteJobs
mount_mutation Mutations::AlertManagement::CreateAlertIssue
mount_mutation Mutations::AlertManagement::UpdateAlertStatus
@@ -69,6 +71,7 @@ module Types
mount_mutation Mutations::Issues::BulkUpdate, alpha: { milestone: '15.9' }
mount_mutation Mutations::Labels::Create
mount_mutation Mutations::Members::Groups::BulkUpdate
+ mount_mutation Mutations::Members::Projects::BulkUpdate
mount_mutation Mutations::MergeRequests::Accept
mount_mutation Mutations::MergeRequests::Create
mount_mutation Mutations::MergeRequests::Update
@@ -89,6 +92,7 @@ module Types
mount_mutation Mutations::Notes::Update::ImageDiffNote
mount_mutation Mutations::Notes::RepositionImageDiffNote
mount_mutation Mutations::Notes::Destroy
+ mount_mutation Mutations::Projects::SyncFork, calls_gitaly: true, alpha: { milestone: '15.9' }
mount_mutation Mutations::Releases::Create
mount_mutation Mutations::Releases::Update
mount_mutation Mutations::Releases::Delete
@@ -114,6 +118,7 @@ module Types
mount_mutation Mutations::DesignManagement::Upload, calls_gitaly: true
mount_mutation Mutations::DesignManagement::Delete, calls_gitaly: true
mount_mutation Mutations::DesignManagement::Move
+ mount_mutation Mutations::DesignManagement::Update
mount_mutation Mutations::ContainerExpirationPolicies::Update
mount_mutation Mutations::ContainerRepositories::Destroy
mount_mutation Mutations::ContainerRepositories::DestroyTags
@@ -137,8 +142,10 @@ module Types
mount_mutation Mutations::Ci::Job::Cancel
mount_mutation Mutations::Ci::Job::Unschedule
mount_mutation Mutations::Ci::JobArtifact::Destroy
+ mount_mutation Mutations::Ci::JobArtifact::BulkDestroy, alpha: { milestone: '15.10' }
mount_mutation Mutations::Ci::JobTokenScope::AddProject
mount_mutation Mutations::Ci::JobTokenScope::RemoveProject
+ mount_mutation Mutations::Ci::Runner::Create, alpha: { milestone: '15.10' }
mount_mutation Mutations::Ci::Runner::Update
mount_mutation Mutations::Ci::Runner::Delete
mount_mutation Mutations::Ci::Runner::BulkDelete, alpha: { milestone: '15.3' }
@@ -160,6 +167,7 @@ module Types
mount_mutation Mutations::WorkItems::DeleteTask, alpha: { milestone: '15.1' }
mount_mutation Mutations::WorkItems::Update, alpha: { milestone: '15.1' }
mount_mutation Mutations::WorkItems::UpdateTask, alpha: { milestone: '15.1' }
+ mount_mutation Mutations::WorkItems::Export, alpha: { milestone: '15.10' }
mount_mutation Mutations::SavedReplies::Create
mount_mutation Mutations::SavedReplies::Update
mount_mutation Mutations::Pages::MarkOnboardingComplete
diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb
index fc55ff512b6..3420f16213f 100644
--- a/app/graphql/types/namespace_type.rb
+++ b/app/graphql/types/namespace_type.rb
@@ -68,7 +68,9 @@ module Types
null: true,
alpha: { milestone: '15.8' },
description: "Achievements for the namespace. " \
- "Returns `null` if the `achievements` feature flag is disabled."
+ "Returns `null` if the `achievements` feature flag is disabled.",
+ extras: [:lookahead],
+ resolver: ::Resolvers::Achievements::AchievementsResolver
markdown_field :description_html, null: true
@@ -83,10 +85,6 @@ module Types
def root_storage_statistics
Gitlab::Graphql::Loaders::BatchRootStorageStatisticsLoader.new(object.id).find
end
-
- def achievements
- object.achievements if Feature.enabled?(:achievements, object)
- end
end
end
diff --git a/app/graphql/types/packages/package_details_type.rb b/app/graphql/types/packages/package_details_type.rb
index f63b41b3c92..e00d6eac72f 100644
--- a/app/graphql/types/packages/package_details_type.rb
+++ b/app/graphql/types/packages/package_details_type.rb
@@ -63,11 +63,11 @@ module Types
end
def pypi_url
- pypi_registry_url(object.project.id)
+ pypi_registry_url(object.project)
end
def public_package
- object.project.public? || object.project.project_feature.package_registry_access_level == ProjectFeature::PUBLIC
+ object.project.project_feature.public_packages?
end
end
end
diff --git a/app/graphql/types/permission_types/ci/pipeline_schedules.rb b/app/graphql/types/permission_types/ci/pipeline_schedules.rb
index 268ac6096d0..dd9d94aa578 100644
--- a/app/graphql/types/permission_types/ci/pipeline_schedules.rb
+++ b/app/graphql/types/permission_types/ci/pipeline_schedules.rb
@@ -6,11 +6,16 @@ module Types
class PipelineSchedules < BasePermissionType
graphql_name 'PipelineSchedulePermissions'
- abilities :take_ownership_pipeline_schedule,
- :update_pipeline_schedule,
+ abilities :update_pipeline_schedule,
:admin_pipeline_schedule
ability_field :play_pipeline_schedule, calls_gitaly: true
+ ability_field :take_ownership_pipeline_schedule,
+ deprecated: {
+ reason: 'Use admin_pipeline_schedule permission to determine if the user can take ownership ' \
+ 'of a pipeline schedule',
+ milestone: '15.9'
+ }
end
end
end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index c105ab9814c..4ca2bc8b1b5 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -581,6 +581,14 @@ module Types
description: 'Minimum access level.'
end
+ field :flow_metrics,
+ ::Types::Analytics::CycleAnalytics::FlowMetrics[:project],
+ null: true,
+ description: 'Flow metrics for value stream analytics.',
+ method: :project_namespace,
+ authorize: :read_cycle_analytics,
+ alpha: { milestone: '15.10' }
+
def timelog_categories
object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories)
end
@@ -657,7 +665,7 @@ module Types
if project.repository.empty?
raise Gitlab::Graphql::Errors::MutationError,
- _(format('You must %s before using Security features.', add_file_docs_link.html_safe)).html_safe
+ Gitlab::Utils::ErrorMessage.to_user_facing(_(format('You must %s before using Security features.', add_file_docs_link.html_safe)).html_safe)
end
::Security::CiConfiguration::SastParserService.new(object).configuration
diff --git a/app/graphql/types/projects/fork_details_type.rb b/app/graphql/types/projects/fork_details_type.rb
index 88c17d89620..6157dc47255 100644
--- a/app/graphql/types/projects/fork_details_type.rb
+++ b/app/graphql/types/projects/fork_details_type.rb
@@ -9,11 +9,37 @@ module Types
field :ahead, GraphQL::Types::Int,
null: true,
+ calls_gitaly: true,
+ method: :ahead,
description: 'Number of commits ahead of upstream.'
field :behind, GraphQL::Types::Int,
null: true,
+ calls_gitaly: true,
+ method: :behind,
description: 'Number of commits behind upstream.'
+
+ field :is_syncing, GraphQL::Types::Boolean,
+ null: true,
+ method: :syncing?,
+ description: 'Indicates if there is a synchronization in progress.'
+
+ field :has_conflicts, GraphQL::Types::Boolean,
+ null: true,
+ method: :has_conflicts?,
+ description: 'Indicates if the fork conflicts with its upstream project.'
+
+ def ahead
+ counts[:ahead]
+ end
+
+ def behind
+ counts[:behind]
+ end
+
+ def counts
+ @counts ||= object.counts
+ end
end
# rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/projects/namespace_project_sort_enum.rb b/app/graphql/types/projects/namespace_project_sort_enum.rb
index 7c7b54226d3..14a315781ef 100644
--- a/app/graphql/types/projects/namespace_project_sort_enum.rb
+++ b/app/graphql/types/projects/namespace_project_sort_enum.rb
@@ -7,8 +7,9 @@ module Types
description 'Values for sorting projects'
value 'SIMILARITY', 'Most similar to the search query.', value: :similarity
- value 'STORAGE', 'Sort by storage size.', value: :storage
- value 'ACTIVITY_DESC', 'Sort by latest activity, in descending order.', value: :latest_activity_desc
+ value 'ACTIVITY_DESC', 'Sort by latest activity, descending order.', value: :latest_activity_desc
end
end
end
+
+Types::Projects::NamespaceProjectSortEnum.prepend_mod
diff --git a/app/graphql/types/root_storage_statistics_type.rb b/app/graphql/types/root_storage_statistics_type.rb
index 64aaf3e73a0..67ee0589882 100644
--- a/app/graphql/types/root_storage_statistics_type.rb
+++ b/app/graphql/types/root_storage_statistics_type.rb
@@ -12,6 +12,7 @@ module Types
field :lfs_objects_size, GraphQL::Types::Float, null: false, description: 'LFS objects size in bytes.'
field :packages_size, GraphQL::Types::Float, null: false, description: 'Packages size in bytes.'
field :pipeline_artifacts_size, GraphQL::Types::Float, null: false, description: 'CI pipeline artifacts size in bytes.'
+ field :registry_size_estimated, GraphQL::Types::Boolean, null: false, description: 'Indicates whether the deduplicated Container Registry size for the namespace is an estimated value or not.'
field :repository_size, GraphQL::Types::Float, null: false, description: 'Git repository size in bytes.'
field :snippets_size, GraphQL::Types::Float, null: false, description: 'Snippets size in bytes.'
field :storage_size, GraphQL::Types::Float, null: false, description: 'Total storage in bytes.'
diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb
index 9115b5a4760..83d2f3f830a 100644
--- a/app/graphql/types/user_interface.rb
+++ b/app/graphql/types/user_interface.rb
@@ -153,6 +153,15 @@ module Types
field :profile_enable_gitpod_path, GraphQL::Types::String, null: true,
description: 'Web path to enable Gitpod for the user.'
+ field :user_achievements,
+ Types::Achievements::UserAchievementType.connection_type,
+ null: true,
+ alpha: { milestone: '15.10' },
+ description: "Achievements for the user. " \
+ "Only returns for namespaces where the `achievements` feature flag is enabled.",
+ extras: [:lookahead],
+ resolver: ::Resolvers::Achievements::UserAchievementsResolver
+
definition_methods do
def resolve_type(object, context)
# in the absense of other information, we cannot tell - just default to
diff --git a/app/graphql/types/work_items/available_export_fields_enum.rb b/app/graphql/types/work_items/available_export_fields_enum.rb
new file mode 100644
index 00000000000..59dd7ba89b1
--- /dev/null
+++ b/app/graphql/types/work_items/available_export_fields_enum.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Types
+ module WorkItems
+ class AvailableExportFieldsEnum < BaseEnum
+ graphql_name 'AvailableExportFields'
+ description 'Available fields to be exported as CSV'
+
+ value 'ID', value: 'id', description: 'Unique identifier.'
+ value 'TITLE', value: 'title', description: 'Title.'
+ value 'TYPE', value: 'type', description: 'Type of the work item.'
+ value 'AUTHOR', value: 'author', description: 'Author name.'
+ value 'AUTHOR_USERNAME', value: 'author username', description: 'Author username.'
+ value 'CREATED_AT', value: 'created_at', description: 'Date of creation.'
+ end
+ end
+end
diff --git a/app/graphql/types/work_items/widget_interface.rb b/app/graphql/types/work_items/widget_interface.rb
index 672a78f12e1..50f8e4f7d8a 100644
--- a/app/graphql/types/work_items/widget_interface.rb
+++ b/app/graphql/types/work_items/widget_interface.rb
@@ -18,7 +18,8 @@ module Types
::Types::WorkItems::Widgets::AssigneesType,
::Types::WorkItems::Widgets::StartAndDueDateType,
::Types::WorkItems::Widgets::MilestoneType,
- ::Types::WorkItems::Widgets::NotesType
+ ::Types::WorkItems::Widgets::NotesType,
+ ::Types::WorkItems::Widgets::NotificationsType
].freeze
def self.ce_orphan_types
@@ -44,6 +45,8 @@ module Types
::Types::WorkItems::Widgets::MilestoneType
when ::WorkItems::Widgets::Notes
::Types::WorkItems::Widgets::NotesType
+ when ::WorkItems::Widgets::Notifications
+ ::Types::WorkItems::Widgets::NotificationsType
else
raise "Unknown GraphQL type for widget #{object}"
end
diff --git a/app/graphql/types/work_items/widgets/notifications_type.rb b/app/graphql/types/work_items/widgets/notifications_type.rb
new file mode 100644
index 00000000000..85928817d07
--- /dev/null
+++ b/app/graphql/types/work_items/widgets/notifications_type.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Types
+ module WorkItems
+ module Widgets
+ # Disabling widget level authorization as it might be too granular
+ # and we already authorize the parent work item
+ # rubocop:disable Graphql/AuthorizeTypes
+ class NotificationsType < BaseObject
+ graphql_name 'WorkItemWidgetNotifications'
+ description 'Represents the notifications widget'
+
+ implements Types::WorkItems::WidgetInterface
+
+ field :subscribed, GraphQL::Types::Boolean,
+ null: false,
+ description: 'Whether the current user is subscribed to notifications on the work item.'
+
+ def subscribed
+ object.work_item.subscribed?(current_user, object.work_item.project)
+ end
+ end
+ # rubocop:enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/graphql/types/work_items/widgets/notifications_update_input_type.rb b/app/graphql/types/work_items/widgets/notifications_update_input_type.rb
new file mode 100644
index 00000000000..2f3b46c3f45
--- /dev/null
+++ b/app/graphql/types/work_items/widgets/notifications_update_input_type.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Types
+ module WorkItems
+ module Widgets
+ class NotificationsUpdateInputType < BaseInputObject
+ graphql_name 'WorkItemWidgetNotificationsUpdateInput'
+
+ argument :subscribed,
+ GraphQL::Types::Boolean,
+ required: true,
+ description: 'Desired state of the subscription.'
+ end
+ end
+ end
+end
diff --git a/app/helpers/admin/abuse_reports_helper.rb b/app/helpers/admin/abuse_reports_helper.rb
new file mode 100644
index 00000000000..3218ecfd1db
--- /dev/null
+++ b/app/helpers/admin/abuse_reports_helper.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Admin
+ module AbuseReportsHelper
+ def abuse_reports_list_data(reports)
+ {
+ abuse_reports_data: {
+ categories: AbuseReport.categories.keys,
+ reports: Admin::AbuseReportSerializer.new.represent(reports),
+ pagination: {
+ current_page: reports.current_page,
+ per_page: reports.limit_value,
+ total_items: reports.total_count
+ }
+ }.to_json
+ }
+ end
+ end
+end
diff --git a/app/helpers/analytics/cycle_analytics_helper.rb b/app/helpers/analytics/cycle_analytics_helper.rb
deleted file mode 100644
index 35a5d4f469d..00000000000
--- a/app/helpers/analytics/cycle_analytics_helper.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-module Analytics
- module CycleAnalyticsHelper
- def cycle_analytics_default_stage_config
- Gitlab::Analytics::CycleAnalytics::DefaultStages.all.map do |stage_params|
- Analytics::CycleAnalytics::StagePresenter.new(stage_params)
- end
- end
-
- def cycle_analytics_initial_data(project, group = nil)
- base_data = { project_id: project.id, group_path: project.group&.path, request_path: project_cycle_analytics_path(project), full_path: project.full_path }
- svgs = { empty_state_svg_path: image_path("illustrations/analytics/cycle-analytics-empty-chart.svg"), no_data_svg_path: image_path("illustrations/analytics/cycle-analytics-empty-chart.svg"), no_access_svg_path: image_path("illustrations/analytics/no-access.svg") }
- api_paths = group.present? ? cycle_analytics_group_api_paths(group) : cycle_analytics_project_api_paths(project)
-
- base_data.merge(svgs, api_paths)
- end
-
- private
-
- def cycle_analytics_group_api_paths(group)
- { milestones_path: group_milestones_path(group, format: :json), labels_path: group_labels_path(group, format: :json), group_path: group_path(group), group_id: group&.id }
- end
-
- def cycle_analytics_project_api_paths(project)
- { milestones_path: project_milestones_path(project, format: :json), labels_path: project_labels_path(project, format: :json), group_path: project.parent&.path, group_id: project.parent&.id }
- end
- end
-end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 93b7c8c0b94..d0602952f9a 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -181,14 +181,14 @@ module ApplicationHelper
css_classes << html_class unless html_class.blank?
content_tag :time, l(time, format: "%b %d, %Y"),
- class: css_classes.join(' '),
- title: l(time.to_time.in_time_zone, format: :timeago_tooltip),
- datetime: time.to_time.getutc.iso8601,
- data: {
- toggle: 'tooltip',
- placement: placement,
- container: 'body'
- }
+ class: css_classes.join(' '),
+ title: l(time.to_time.in_time_zone, format: :timeago_tooltip),
+ datetime: time.to_time.getutc.iso8601,
+ data: {
+ toggle: 'tooltip',
+ placement: placement,
+ container: 'body'
+ }
end
def edited_time_ago_with_tooltip(object, placement: 'top', html_class: 'time_ago', exclude_author: false)
@@ -200,7 +200,7 @@ module ApplicationHelper
if !exclude_author && object.last_edited_by
output << content_tag(:span, ' by ')
- output << link_to_member(object.project, object.last_edited_by, avatar: false, author_class: nil)
+ output << link_to_member(object.project, object.last_edited_by, avatar: false, extra_class: 'gl-hover-text-decoration-underline', author_class: nil)
end
output
@@ -374,6 +374,10 @@ module ApplicationHelper
cookies["sidebar_collapsed"] == "true"
end
+ def collapsed_super_sidebar?
+ cookies["super_sidebar_collapsed"] == "true"
+ end
+
def locale_path
asset_path("locale/#{Gitlab::I18n.locale}/app.js")
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 3abaae98c29..fd684ee5ecb 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -4,11 +4,11 @@ module ApplicationSettingsHelper
extend self
delegate :allow_signup?,
- :gravatar_enabled?,
- :password_authentication_enabled_for_web?,
- :akismet_enabled?,
- :spam_check_endpoint_enabled?,
- to: :'Gitlab::CurrentSettings.current_application_settings'
+ :gravatar_enabled?,
+ :password_authentication_enabled_for_web?,
+ :akismet_enabled?,
+ :spam_check_endpoint_enabled?,
+ to: :'Gitlab::CurrentSettings.current_application_settings'
def user_oauth_applications?
Gitlab::CurrentSettings.user_oauth_applications
@@ -248,7 +248,9 @@ module ApplicationSettingsHelper
:default_project_visibility,
:default_projects_limit,
:default_snippet_visibility,
+ :default_syntax_highlighting_theme,
:delete_inactive_projects,
+ :deny_all_requests_except_allowed,
:disable_admin_oauth_scopes,
:disable_feed_token,
:disabled_oauth_sign_in_sources,
@@ -401,6 +403,7 @@ module ApplicationSettingsHelper
:protected_paths_raw,
:time_tracking_limit_to_hours,
:two_factor_grace_period,
+ :update_runner_versions_enabled,
:unique_ips_limit_enabled,
:unique_ips_limit_per_user,
:unique_ips_limit_time_window,
@@ -478,7 +481,9 @@ module ApplicationSettingsHelper
:bulk_import_enabled,
:allow_runner_registration_token,
:user_defaults_to_private_profile,
- :deactivation_email_additional_text
+ :deactivation_email_additional_text,
+ :projects_api_rate_limit_unauthenticated,
+ :gitlab_dedicated_instance
].tap do |settings|
next if Gitlab.com?
diff --git a/app/helpers/artifacts_helper.rb b/app/helpers/artifacts_helper.rb
index df0432105d5..f90d59409ed 100644
--- a/app/helpers/artifacts_helper.rb
+++ b/app/helpers/artifacts_helper.rb
@@ -4,6 +4,7 @@ module ArtifactsHelper
def artifacts_app_data(project)
{
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')
}
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 281d5c923d0..bb6fd6c3dad 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -2,9 +2,7 @@
module BlobHelper
def edit_blob_path(project = @project, ref = @ref, path = @path, options = {})
- project_edit_blob_path(project,
- tree_join(ref, path),
- options[:link_opts])
+ project_edit_blob_path(project, tree_join(ref, path), options[:link_opts])
end
def ide_edit_path(project = @project, ref = @ref, path = @path)
@@ -52,9 +50,11 @@ module BlobHelper
def fork_path_for_current_user(project, path, with_notice: true)
return unless current_user
- project_forks_path(project,
- namespace_key: current_user.namespace&.id,
- continue: edit_blob_fork_params(path, with_notice: with_notice))
+ project_forks_path(
+ project,
+ namespace_key: current_user.namespace&.id,
+ continue: edit_blob_fork_params(path, with_notice: with_notice)
+ )
end
def encode_ide_path(path)
@@ -66,12 +66,14 @@ module BlobHelper
common_classes = "btn gl-button btn-confirm js-edit-blob gl-ml-3 #{options[:extra_class]}"
- edit_button_tag(blob,
- common_classes,
- _('Edit'),
- edit_blob_path(project, ref, path, options),
- project,
- ref)
+ edit_button_tag(
+ blob,
+ common_classes,
+ _('Edit'),
+ edit_blob_path(project, ref, path, options),
+ project,
+ ref
+ )
end
def can_modify_blob?(blob, project = @project, ref = @ref)
@@ -282,8 +284,8 @@ module BlobHelper
fork_path = project_forks_path(project, namespace_key: current_user.namespace.id, continue: params)
button_tag label,
- class: "#{common_classes} js-edit-blob-link-fork-toggler",
- data: { action: action, fork_path: fork_path }
+ class: "#{common_classes} js-edit-blob-link-fork-toggler",
+ data: { action: action, fork_path: fork_path }
end
def edit_disabled_button_tag(button_text, common_classes)
diff --git a/app/helpers/ci/catalog/resources_helper.rb b/app/helpers/ci/catalog/resources_helper.rb
new file mode 100644
index 00000000000..46d78cd6b24
--- /dev/null
+++ b/app/helpers/ci/catalog/resources_helper.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Ci
+ module Catalog
+ module ResourcesHelper
+ def can_view_private_catalog?(_project)
+ false
+ end
+
+ def js_ci_catalog_data
+ {}
+ end
+ end
+ end
+end
diff --git a/app/helpers/ci/pipeline_editor_helper.rb b/app/helpers/ci/pipeline_editor_helper.rb
index 99a92ba9b59..4d1bdf5fa7f 100644
--- a/app/helpers/ci/pipeline_editor_helper.rb
+++ b/app/helpers/ci/pipeline_editor_helper.rb
@@ -18,12 +18,12 @@ module Ci
"ci-examples-help-page-path" => help_page_path('ci/examples/index'),
"ci-help-page-path" => help_page_path('ci/index'),
"ci-lint-path" => project_ci_lint_path(project),
+ "ci-troubleshooting-path" => help_page_path('ci/troubleshooting', anchor: 'common-cicd-issues'),
"default-branch" => project.default_branch_or_main,
"empty-state-illustration-path" => image_path('illustrations/empty-state/empty-dag-md.svg'),
"initial-branch-name" => initial_branch,
"includes-help-page-path" => help_page_path('ci/yaml/includes'),
"lint-help-page-path" => help_page_path('ci/lint', anchor: 'check-cicd-syntax'),
- "lint-unavailable-help-page-path" => help_page_path('ci/pipeline_editor/index', anchor: 'configuration-validation-currently-not-available-message'),
"needs-help-page-path" => help_page_path('ci/yaml/index', anchor: 'needs'),
"new-merge-request-path" => namespace_project_new_merge_request_path,
"pipeline_etag" => latest_commit ? graphql_etag_pipeline_sha_path(latest_commit.sha) : '',
diff --git a/app/helpers/ci/status_helper.rb b/app/helpers/ci/status_helper.rb
index bca49324a19..ea5b613cb78 100644
--- a/app/helpers/ci/status_helper.rb
+++ b/app/helpers/ci/status_helper.rb
@@ -131,10 +131,10 @@ module Ci
if path
link_to ci_icon_for_status(status, size: icon_size), path,
- class: klass, title: title, data: data
+ class: klass, title: title, data: data
else
content_tag :span, ci_icon_for_status(status, size: icon_size),
- class: klass, title: title, data: data
+ class: klass, title: title, data: data
end
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index f75d3657986..519508f1c02 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -27,12 +27,11 @@ module CommitsHelper
end
def commit_to_html(commit, ref, project)
- render partial: 'projects/commits/commit', formats: :html,
- locals: {
- commit: commit,
- ref: ref,
- project: project
- }
+ render partial: 'projects/commits/commit', formats: :html, locals: {
+ commit: commit,
+ ref: ref,
+ project: project
+ }
end
# Breadcrumb links for a Project and, if applicable, a tree path
@@ -161,17 +160,23 @@ module CommitsHelper
# This includes a keyed hash for values that can be nil, to prevent invalid cache entries
# being served if the order should change in future.
def commit_partial_cache_key(commit, ref:, merge_request:, request:)
+ keyed_hash = {
+ merge_request: merge_request&.cache_key,
+ pipeline_status: commit.detailed_status_for(ref)&.cache_key,
+ xhr: request.xhr?,
+ controller: controller.controller_path,
+ path: @path # referred to in #link_to_browse_code
+ }
+
+ if Feature.enabled?(:show_tags_on_commits_view, commit.project)
+ keyed_hash[:referenced_by] = tag_checksum(commit.referenced_by)
+ end
+
[
commit,
commit.author,
ref,
- {
- merge_request: merge_request&.cache_key,
- pipeline_status: commit.detailed_status_for(ref)&.cache_key,
- xhr: request.xhr?,
- controller: controller.controller_path,
- path: @path # referred to in #link_to_browse_code
- }
+ keyed_hash
]
end
@@ -188,16 +193,22 @@ module CommitsHelper
entity = mode == 'raw' ? 'rawButton' : 'renderedButton'
title = "Display #{mode} diff"
- link_to("##{mode}-diff-#{file_hash}",
- class: "btn gl-button btn-default btn-file-option has-tooltip btn-show-#{mode}-diff",
- title: title,
- data: { file_hash: file_hash, diff_toggle_entity: entity }) do
+ link_to(
+ "##{mode}-diff-#{file_hash}",
+ class: "btn gl-button btn-default btn-file-option has-tooltip btn-show-#{mode}-diff",
+ title: title,
+ data: { file_hash: file_hash, diff_toggle_entity: entity }
+ ) do
sprite_icon(icon)
end
end
protected
+ def tag_checksum(tags_array)
+ ::Zlib.crc32(tags_array.sort.join)
+ end
+
# Private: Returns a link to a person. If the person has a matching user and
# is a member of the current @project it will link to the team member page.
# Otherwise it will link to the person email as specified in the commit.
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index f0e1f252917..0352f5a1dfc 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -40,9 +40,14 @@ module DashboardHelper
end)
if doc_href.present?
- link_to_doc = link_to(sprite_icon('question'), doc_href,
- class: 'gl-ml-2', title: _('Documentation'),
- target: '_blank', rel: 'noopener noreferrer')
+ link_to_doc = link_to(
+ sprite_icon('question'),
+ doc_href,
+ class: 'gl-ml-2',
+ title: _('Documentation'),
+ target: '_blank',
+ rel: 'noopener noreferrer'
+ )
concat(link_to_doc)
end
@@ -52,7 +57,7 @@ module DashboardHelper
private
def get_dashboard_nav_links
- links = [:projects, :groups, :snippets]
+ links = [:projects, :groups, :snippets, :your_work, :explore]
if can?(current_user, :read_cross_project)
links += [:activity, :milestones]
diff --git a/app/helpers/device_registration_helper.rb b/app/helpers/device_registration_helper.rb
new file mode 100644
index 00000000000..bbdcab76bf5
--- /dev/null
+++ b/app/helpers/device_registration_helper.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module DeviceRegistrationHelper
+ def device_registration_data(current_password_required:, target_path:, webauthn_error:)
+ {
+ initial_error: webauthn_error && webauthn_error[:message],
+ target_path: target_path,
+ password_required: current_password_required.to_s
+ }
+ end
+end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index e0a1697cfa9..c5df53ec606 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -34,6 +34,12 @@ module DiffHelper
options[:expanded] = true
options[:paths] = params.values_at(:old_path, :new_path)
options[:use_extra_viewer_as_main] = false
+
+ if Feature.enabled?(:large_ipynb_diffs, @project) && params[:file_identifier]&.include?('.ipynb')
+ options[:max_patch_bytes_for_file_extension] = {
+ '.ipynb' => 1.megabyte
+ }
+ end
end
options
diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb
index 427cbe18fbf..475ba3dcba8 100644
--- a/app/helpers/dropdowns_helper.rb
+++ b/app/helpers/dropdowns_helper.rb
@@ -54,7 +54,7 @@ module DropdownsHelper
default_label = data_attr[:default_label]
content_tag(:button, disabled: options[:disabled], class: "dropdown-menu-toggle #{options[:toggle_class] if options.key?(:toggle_class)}", id: (options[:id] if options.key?(:id)), type: "button", data: data_attr) do
output = content_tag(:span, toggle_text, class: "dropdown-toggle-text #{'is-default' if toggle_text == default_label}")
- output << sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
+ output << sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon")
output.html_safe
end
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index bef2da495b0..795d35ec81f 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -29,10 +29,11 @@ module EventsHelper
opened: s_('Event|opened'),
updated: s_('Event|updated'),
'removed due to membership expiration from': s_('Event|removed due to membership expiration from')
- }.merge(localized_push_action_name_map,
- localized_created_project_action_name_map,
- localized_design_action_names
- ).freeze
+ }.merge(
+ localized_push_action_name_map,
+ localized_created_project_action_name_map,
+ localized_design_action_names
+ ).freeze
end
def localized_push_action_name_map
@@ -183,13 +184,11 @@ module EventsHelper
def event_feed_url(event)
if event.issue?
- project_issue_url(event.project,
- event.issue)
+ project_issue_url(event.project, event.issue)
elsif event.merge_request?
project_merge_request_url(event.project, event.merge_request)
elsif event.commit_note?
- project_commit_url(event.project,
- event.note_target)
+ project_commit_url(event.project, event.note_target)
elsif event.note?
if event.note_target
event_note_target_url(event)
@@ -204,16 +203,12 @@ module EventsHelper
def push_event_feed_url(event)
if event.push_with_commits? && event.md_ref?
if event.commits_count > 1
- project_compare_url(event.project,
- from: event.commit_from, to:
- event.commit_to)
+ project_compare_url(event.project, from: event.commit_from, to: event.commit_to)
else
- project_commit_url(event.project,
- id: event.commit_to)
+ project_commit_url(event.project, id: event.commit_to)
end
elsif event.ref_name
- project_commits_url(event.project,
- event.ref_name)
+ project_commits_url(event.project, event.ref_name)
end
end
@@ -241,26 +236,31 @@ module EventsHelper
elsif event.design_note?
design_url(event.note_target, anchor: dom_id(event.note))
else
- polymorphic_url([event.project, event.note_target],
- anchor: dom_id(event.target))
+ polymorphic_url([event.project, event.note_target], anchor: dom_id(event.target))
end
end
def event_wiki_title_html(event)
capture do
concat content_tag(:span, _('wiki page'), class: "event-target-type gl-mr-2")
- concat link_to(event.target_title, event_wiki_page_target_url(event),
- title: event.target_title,
- class: 'has-tooltip event-target-link gl-mr-2')
+ concat link_to(
+ event.target_title,
+ event_wiki_page_target_url(event),
+ title: event.target_title,
+ class: 'has-tooltip event-target-link gl-mr-2'
+ )
end
end
def event_design_title_html(event)
capture do
concat content_tag(:span, _('design'), class: "event-target-type gl-mr-2")
- concat link_to(event.design.reference_link_text, design_url(event.design),
- title: event.target_title,
- class: 'has-tooltip event-design event-target-link gl-mr-2')
+ concat link_to(
+ event.design.reference_link_text,
+ design_url(event.design),
+ title: event.target_title,
+ class: 'has-tooltip event-design event-target-link gl-mr-2'
+ )
end
end
diff --git a/app/helpers/explore_helper.rb b/app/helpers/explore_helper.rb
index 2967501f628..ed24f2509e8 100644
--- a/app/helpers/explore_helper.rb
+++ b/app/helpers/explore_helper.rb
@@ -57,7 +57,7 @@ module ExploreHelper
private
def get_explore_nav_links
- [:projects, :groups, :snippets]
+ [:projects, :groups, :topics, :snippets]
end
def request_path_with_options(options = {})
diff --git a/app/helpers/feature_flags_helper.rb b/app/helpers/feature_flags_helper.rb
index 3dde29dce91..fe8d8e6b5d9 100644
--- a/app/helpers/feature_flags_helper.rb
+++ b/app/helpers/feature_flags_helper.rb
@@ -18,8 +18,10 @@ module FeatureFlagsHelper
feature_flags_path: project_feature_flags_path(@project),
environments_endpoint: search_project_environments_path(@project, format: :json),
strategy_type_docs_page_path: help_page_path('operations/feature_flags', anchor: 'feature-flag-strategies'),
- environments_scope_docs_path: help_page_path('ci/environments/index.md',
- anchor: 'limit-the-environment-scope-of-a-cicd-variable')
+ environments_scope_docs_path: help_page_path(
+ 'ci/environments/index.md',
+ anchor: 'limit-the-environment-scope-of-a-cicd-variable'
+ )
}
end
end
diff --git a/app/helpers/groups/observability_helper.rb b/app/helpers/groups/observability_helper.rb
index 6cd6566cee1..7661817da7b 100644
--- a/app/helpers/groups/observability_helper.rb
+++ b/app/helpers/groups/observability_helper.rb
@@ -22,19 +22,8 @@ module Groups
}.freeze
def observability_iframe_src(group)
- # Format: https://observe.gitlab.com/GROUP_ID
-
- # When running Observability UI in standalone mode (i.e. not backed by Observability Backend)
- # the group-id is not required. This is mostly used for local dev
- base_url = ENV['STANDALONE_OBSERVABILITY_UI'] == 'true' ? observability_url : "#{observability_url}/-/#{group.id}"
-
- sanitized_path = if params[:observability_path] && sanitize(params[:observability_path]) != ''
- CGI.unescapeHTML(sanitize(params[:observability_path]))
- else
- observability_config_for(params).fetch(:path)
- end
-
- "#{base_url}#{sanitized_path}"
+ Gitlab::Observability.build_full_url(group, params[:observability_path],
+ observability_config_for(params).fetch(:path))
end
def observability_page_title
@@ -43,10 +32,6 @@ module Groups
private
- def observability_url
- Gitlab::Observability.observability_url
- end
-
def observability_config_for(params)
ACTION_TO_PATH.fetch(params[:action], ACTION_TO_PATH['dashboards'])
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 129871ca3fd..ce64ac1f21f 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -126,6 +126,7 @@ module GroupsHelper
def subgroup_creation_data(group)
{
+ parent_group_url: group.parent && group_url(group.parent),
parent_group_name: group.parent&.name,
import_existing_group_path: new_group_path(parent_id: group.parent_id, anchor: 'import-group-pane')
}
diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb
index c5be044a27b..063eef41f77 100644
--- a/app/helpers/ide_helper.rb
+++ b/app/helpers/ide_helper.rb
@@ -1,20 +1,26 @@
# frozen_string_literal: true
module IdeHelper
- def ide_data(project:, branch:, path:, merge_request:, fork_info:)
- {
+ # Overridden in EE
+ def ide_data(project:, fork_info:, params:)
+ base_data = {
'can-use-new-web-ide' => can_use_new_web_ide?.to_s,
'use-new-web-ide' => use_new_web_ide?.to_s,
'new-web-ide-help-page-path' => help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'),
'user-preferences-path' => profile_preferences_path,
- 'branch-name' => branch,
- 'file-path' => path,
- 'fork-info' => fork_info&.to_json,
'editor-font-src-url' => font_url('jetbrains-mono/JetBrainsMono.woff2'),
'editor-font-family' => 'JetBrains Mono',
- 'editor-font-format' => 'woff2',
- 'merge-request' => merge_request
+ 'editor-font-format' => 'woff2'
}.merge(use_new_web_ide? ? new_ide_data(project: project) : legacy_ide_data(project: project))
+
+ return base_data unless project
+
+ base_data.merge(
+ 'fork-info' => fork_info&.to_json,
+ 'branch-name' => params[:branch],
+ 'file-path' => params[:path],
+ 'merge-request' => params[:merge_request_id]
+ )
end
def can_use_new_web_ide?
@@ -76,3 +82,5 @@ module IdeHelper
current_user.dismissed_callout?(feature_name: 'web_ide_ci_environments_guidance')
end
end
+
+IdeHelper.prepend_mod_with('IdeHelper')
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 46d2d2c42d9..9c68f54f42e 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -156,7 +156,7 @@ module IssuablesHelper
end
output << content_tag(:strong) do
- author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "d-none d-sm-inline")
+ 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_slot(issuable.author, css_class: 'ml-1')
@@ -281,7 +281,9 @@ module IssuablesHelper
{
hasLinkedAlerts: issue.alert_management_alerts.any?,
- canUpdateTimelineEvent: can?(current_user, :admin_incident_management_timeline_event, issue)
+ canUpdateTimelineEvent: can?(current_user, :admin_incident_management_timeline_event, issue),
+ currentPath: url_for(safe_params),
+ currentTab: safe_params[:incident_tab]
}
end
@@ -378,8 +380,10 @@ module IssuablesHelper
end
def hidden_issuable_icon(issuable)
- title = format(_('This %{issuable} is hidden because its author has been banned'),
- issuable: issuable.is_a?(Issue) ? _('issue') : _('merge request'))
+ title = format(
+ _('This %{issuable} is hidden because its author has been banned'),
+ issuable: issuable.is_a?(Issue) ? _('issue') : _('merge request')
+ )
content_tag(:span, class: 'has-tooltip', title: title) do
sprite_icon('spam', css_class: 'gl-vertical-align-text-bottom')
end
diff --git a/app/helpers/jira_connect_helper.rb b/app/helpers/jira_connect_helper.rb
index 50e3c3cc5fe..28b30ae051c 100644
--- a/app/helpers/jira_connect_helper.rb
+++ b/app/helpers/jira_connect_helper.rb
@@ -12,7 +12,7 @@ module JiraConnectHelper
users_path: current_user ? nil : jira_connect_users_path, # users_path is used to determine if user is signed in
gitlab_user_path: current_user ? user_path(current_user) : nil,
oauth_metadata: Feature.enabled?(:jira_connect_oauth, current_user) ? jira_connect_oauth_data(installation).to_json : nil,
- public_key_storage_enabled: Gitlab.config.jira_connect.enable_public_keys_storage || Gitlab::CurrentSettings.jira_connect_public_key_storage_enabled?
+ public_key_storage_enabled: Gitlab::CurrentSettings.jira_connect_public_key_storage_enabled?
}
end
diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb
index 4a5720e757d..bec6cccb977 100644
--- a/app/helpers/markup_helper.rb
+++ b/app/helpers/markup_helper.rb
@@ -80,9 +80,7 @@ module MarkupHelper
)
)
- # since <img> tags are stripped, this can leave empty <a> tags hanging around
- # (as our markdown wraps images in links)
- strip_empty_link_tags(text).html_safe
+ render_links(text)
end
def markdown(text, context = {})
@@ -171,9 +169,22 @@ module MarkupHelper
{ project: wiki.container }
end
- def strip_empty_link_tags(text)
+ # Sanitize and style user references links
+ #
+ # @param String text the string to be sanitized
+ #
+ # 1. Remove empty <a> tags which are caused by the <img> tags being stripped
+ # (as our markdown wraps images in links)
+ # 2. Strip all link tags, except user references, leaving just the link text
+ # 3. Add a highlight class for current user's references
+ #
+ # @return sanitized HTML string
+ def render_links(text)
scrubber = Loofah::Scrubber.new do |node|
- node.remove if node.name == 'a' && node.children.empty?
+ next unless node.name == 'a'
+ next node.remove if node.children.empty?
+ next node.replace(node.children) if node['data-reference-type'] != 'user'
+ next node.append_class('current-user') if current_user && node['data-user'] == current_user.id.to_s
end
sanitize text, scrubber: scrubber
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index ec395baef9e..7d9be2f93fd 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -2,6 +2,7 @@
module MergeRequestsHelper
include Gitlab::Utils::StrongMemoize
+ include CompareHelper
def create_mr_button_from_event?(event)
create_mr_button?(from: event.branch_name, source_project: event.project)
@@ -185,6 +186,7 @@ module MergeRequestsHelper
endpoint_metadata: @endpoint_metadata_url,
endpoint_batch: diffs_batch_project_json_merge_request_path(project, merge_request, 'json', params),
endpoint_coverage: @coverage_path,
+ endpoint_diff_for_path: diff_for_path_namespace_project_merge_request_path(format: 'json', id: merge_request.iid, namespace_id: project.namespace.path, project_id: project.path),
help_page_path: help_page_path('user/project/merge_requests/reviews/suggestions.md'),
current_user_data: @current_user_data,
update_current_user_path: @update_current_user_path,
@@ -198,7 +200,8 @@ module MergeRequestsHelper
default_suggestion_commit_message: default_suggestion_commit_message,
source_project_default_url: @merge_request.source_project && default_url_to_repo(@merge_request.source_project),
source_project_full_path: @merge_request.source_project&.full_path,
- is_forked: @project.forked?.to_s
+ is_forked: @project.forked?.to_s,
+ saved_replies_new_path: profile_saved_replies_path
}
end
diff --git a/app/helpers/mirror_helper.rb b/app/helpers/mirror_helper.rb
index 3dfd30f07db..06deaeb5e9e 100644
--- a/app/helpers/mirror_helper.rb
+++ b/app/helpers/mirror_helper.rb
@@ -13,7 +13,7 @@ module MirrorHelper
docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: docs_link_url }
html_escape(_('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.')) %
- { docs_link_start: docs_link_start, docs_link_end: '</a>'.html_safe, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
+ { docs_link_start: docs_link_start, docs_link_end: '</a>'.html_safe, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
end
end
diff --git a/app/helpers/nav/new_dropdown_helper.rb b/app/helpers/nav/new_dropdown_helper.rb
index ddd6469a9e4..201007863b2 100644
--- a/app/helpers/nav/new_dropdown_helper.rb
+++ b/app/helpers/nav/new_dropdown_helper.rb
@@ -6,19 +6,19 @@ module Nav
return unless current_user
menu_sections = []
+ data = { title: _('Create new...') }
- if group&.persisted?
- menu_sections.push(group_menu_section(group))
- elsif project&.persisted?
+ if project&.persisted?
menu_sections.push(project_menu_section(project))
+ elsif group&.persisted?
+ menu_sections.push(group_menu_section(group))
end
menu_sections.push(general_menu_section)
- {
- title: _("Create new..."),
- menu_sections: menu_sections.select { |x| x.fetch(:menu_items).any? }
- }
+ data[:menu_sections] = menu_sections.select { |x| x.fetch(:menu_items).any? }
+
+ data
end
private
@@ -51,11 +51,7 @@ module Nav
menu_items.push(create_epic_menu_item(group))
if can?(current_user, :admin_group_member, group)
- menu_items.push(
- invite_members_menu_item(
- href: group_group_members_path(group)
- )
- )
+ menu_items.push(invite_members_menu_item(partial: 'groups/invite_members_top_nav_link'))
end
{
@@ -102,11 +98,7 @@ module Nav
end
if can_admin_project_member?(project)
- menu_items.push(
- invite_members_menu_item(
- href: project_project_members_path(project)
- )
- )
+ menu_items.push(invite_members_menu_item(partial: 'projects/invite_members_top_nav_link'))
end
{
@@ -157,16 +149,16 @@ module Nav
}
end
- def invite_members_menu_item(href:)
+ def invite_members_menu_item(partial:)
::Gitlab::Nav::TopNavMenuItem.build(
id: 'invite',
title: s_('InviteMember|Invite members'),
- emoji: 'shaking_hands',
- href: href,
+ icon: 'shaking_hands',
+ partial: partial,
+ component: 'invite_members',
data: {
- track_action: 'click_link_invite_members',
- track_label: 'plus_menu_dropdown',
- track_property: 'navigation_top'
+ trigger_source: 'top-nav',
+ trigger_element: 'text-emoji'
}
)
end
diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb
index fb11c183aeb..756baabd249 100644
--- a/app/helpers/nav/top_nav_helper.rb
+++ b/app/helpers/nav/top_nav_helper.rb
@@ -64,7 +64,6 @@ module Nav
end
def build_anonymous_view_model(builder:)
- # These come from `app/views/layouts/nav/_explore.html.ham`
if explore_nav_link?(:projects)
builder.add_primary_menu_item_with_shortcut(
header: top_nav_localized_headers[:explore],
@@ -83,6 +82,15 @@ module Nav
)
end
+ if explore_nav_link?(:topics)
+ builder.add_primary_menu_item_with_shortcut(
+ header: top_nav_localized_headers[:explore],
+ active: active_nav_link?(page: topics_explore_projects_path, path: 'projects#topic'),
+ href: topics_explore_projects_path,
+ **topics_menu_item_attrs
+ )
+ end
+
if explore_nav_link?(:snippets)
builder.add_primary_menu_item_with_shortcut(
header: top_nav_localized_headers[:explore],
@@ -123,39 +131,54 @@ module Nav
builder.add_view(GROUPS_VIEW, container_view_props(namespace: 'groups', current_item: current_item, submenu: groups_submenu))
end
+ if dashboard_nav_link?(:your_work)
+ builder.add_primary_menu_item(
+ id: 'your-work',
+ header: top_nav_localized_headers[:switch_to],
+ title: _('Your work'),
+ href: dashboard_projects_path,
+ active: active_nav_link?(controller: []),
+ icon: 'work',
+ data: { **menu_data_tracking_attrs('your-work') }
+ )
+ end
+
+ if dashboard_nav_link?(:explore)
+ builder.add_primary_menu_item(
+ id: 'explore',
+ header: top_nav_localized_headers[:switch_to],
+ title: _('Explore'),
+ href: explore_projects_path,
+ active: active_nav_link?(controller: ["explore/groups", "explore/snippets"], page: ["/explore/projects", "/explore", "/explore/projects/topics"], path: ["projects#topic"]),
+ icon: 'compass',
+ data: { **menu_data_tracking_attrs('explore') }
+ )
+ end
+
if dashboard_nav_link?(:milestones)
- builder.add_primary_menu_item_with_shortcut(
- id: 'milestones',
- header: top_nav_localized_headers[:explore],
+ builder.add_shortcut(
+ id: 'milestones-shortcut',
title: _('Milestones'),
href: dashboard_milestones_path,
- active: active_nav_link?(controller: 'dashboard/milestones'),
- icon: 'clock',
- data: { **menu_data_tracking_attrs('milestones') },
- shortcut_class: 'dashboard-shortcuts-milestones'
+ css_class: 'dashboard-shortcuts-milestones'
)
end
if dashboard_nav_link?(:snippets)
- builder.add_primary_menu_item_with_shortcut(
- header: top_nav_localized_headers[:explore],
- active: active_nav_link?(controller: 'dashboard/snippets'),
- data: { qa_selector: 'snippets_link', **menu_data_tracking_attrs('snippets') },
+ builder.add_shortcut(
+ id: 'snippets-shortcut',
+ title: _('Snippets'),
href: dashboard_snippets_path,
- **snippets_menu_item_attrs
+ css_class: 'dashboard-shortcuts-snippets'
)
end
if dashboard_nav_link?(:activity)
- builder.add_primary_menu_item_with_shortcut(
- id: 'activity',
- header: top_nav_localized_headers[:explore],
+ builder.add_shortcut(
+ id: 'activity-shortcut',
title: _('Activity'),
href: activity_dashboard_path,
- active: active_nav_link?(path: 'dashboard#activity'),
- icon: 'history',
- data: { **menu_data_tracking_attrs('activity') },
- shortcut_class: 'dashboard-shortcuts-activity'
+ css_class: 'dashboard-shortcuts-activity'
)
end
@@ -220,6 +243,15 @@ module Nav
}
end
+ def topics_menu_item_attrs
+ {
+ id: 'topics',
+ title: _('Topics'),
+ icon: 'labels',
+ shortcut_class: 'dashboard-shortcuts-topics'
+ }
+ end
+
def snippets_menu_item_attrs
{
id: 'snippets',
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index d0421cd5184..59ffe6a183e 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -9,10 +9,29 @@ module NavHelper
header_links.include?(link)
end
+ def page_has_sidebar?
+ defined?(@left_sidebar) && @left_sidebar
+ end
+
+ def page_has_collapsed_sidebar?
+ page_has_sidebar? && collapsed_sidebar?
+ end
+
+ def page_has_collapsed_super_sidebar?
+ page_has_sidebar? && collapsed_super_sidebar?
+ end
+
def page_with_sidebar_class
class_name = page_gutter_class
- class_name << 'page-with-contextual-sidebar' if defined?(@left_sidebar) && @left_sidebar
- class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @left_sidebar
+
+ if show_super_sidebar?
+ class_name << 'page-with-super-sidebar' if page_has_sidebar?
+ class_name << 'page-with-super-sidebar-collapsed' if page_has_collapsed_super_sidebar?
+ else
+ class_name << 'page-with-contextual-sidebar' if page_has_sidebar?
+ class_name << 'page-with-icon-sidebar' if page_has_collapsed_sidebar?
+ end
+
class_name -= ['right-sidebar-expanded'] if defined?(@right_sidebar) && !@right_sidebar
class_name
@@ -66,11 +85,21 @@ module NavHelper
end
def show_super_sidebar?
- Feature.enabled?(:super_sidebar_nav, current_user) && current_user&.use_new_navigation
+ Feature.enabled?(:super_sidebar_nav, current_user) && current_user&.use_new_navigation && super_sidebar_supported?
end
private
+ # This is a temporary measure until we support all other existing sidebars:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/391500
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/391501
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/391502
+ def super_sidebar_supported?
+ return true if @nav.nil?
+
+ %w(your_work explore project group profile user_profile).include?(@nav)
+ end
+
def get_header_links
links = if current_user
[:user_dropdown]
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index b47f4633348..3e8872dc199 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -77,8 +77,10 @@ module NotesHelper
line_type: line_type
}
- button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
- data: data, title: 'Add a reply'
+ button_tag 'Reply...',
+ class: 'btn btn-text-field js-discussion-reply-button',
+ data: data,
+ title: 'Add a reply'
end
def note_max_access_for_user(note)
@@ -151,7 +153,6 @@ module NotesHelper
def initial_notes_data(autocomplete)
{
notesUrl: notes_url,
- notesIds: @noteable.notes.pluck(:id), # rubocop: disable CodeReuse/ActiveRecord
now: Time.now.to_i,
diffView: diff_view,
enableGFM: {
diff --git a/app/helpers/operations_helper.rb b/app/helpers/operations_helper.rb
index baeb9a477c3..8528f5f04f7 100644
--- a/app/helpers/operations_helper.rb
+++ b/app/helpers/operations_helper.rb
@@ -12,7 +12,7 @@ module OperationsHelper
def alerts_settings_data(disabled: false)
setting = project_incident_management_setting
- templates = setting.available_issue_templates.map { |t| { key: t.key, name: t.name } }
+ templates = setting.available_issue_templates.map { |t| { value: t.key, text: t.name } }
{
'prometheus_activated' => prometheus_integration.manual_configuration?.to_s,
diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb
index f9ec20bdd01..dec1943db54 100644
--- a/app/helpers/packages_helper.rb
+++ b/app/helpers/packages_helper.rb
@@ -27,9 +27,14 @@ module PackagesHelper
presenter.detail_view.to_json
end
- def pypi_registry_url(project_id)
- full_url = expose_url(api_v4_projects_packages_pypi_simple_package_name_path({ id: project_id, package_name: '' }, true))
- full_url.sub!('://', '://__token__:<your_personal_token>@')
+ def pypi_registry_url(project)
+ full_url = expose_url(api_v4_projects_packages_pypi_simple_package_name_path({ id: project.id, package_name: '' }, true))
+
+ if project.project_feature.public_packages?
+ full_url
+ else
+ full_url.sub!('://', '://__token__:<your_personal_token>@')
+ end
end
def composer_registry_url(group_id)
diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb
index 4a218984af1..9bcabd7d9c6 100644
--- a/app/helpers/page_layout_helper.rb
+++ b/app/helpers/page_layout_helper.rb
@@ -175,7 +175,7 @@ module PageLayoutHelper
current_emoji: user.status.emoji.to_s,
current_message: user.status.message.to_s,
current_availability: user.status.availability.to_s,
- current_clear_status_after: user.status.clear_status_at&.to_s(:iso8601)
+ current_clear_status_after: user_clear_status_at(user)
})
end
diff --git a/app/helpers/plan_limits_helper.rb b/app/helpers/plan_limits_helper.rb
new file mode 100644
index 00000000000..71869b3ba30
--- /dev/null
+++ b/app/helpers/plan_limits_helper.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module PlanLimitsHelper
+ def plan_limit_setting_description(limit_name)
+ case limit_name
+ when :ci_pipeline_size
+ s_('AdminSettings|Maximum number of jobs in a single pipeline')
+ when :ci_active_jobs
+ s_('AdminSettings|Total number of jobs in currently active pipelines')
+ when :ci_active_pipelines
+ s_('AdminSettings|Maximum number of active pipelines per project')
+ when :ci_project_subscriptions
+ s_('AdminSettings|Maximum number of pipeline subscriptions to and from a project')
+ when :ci_pipeline_schedules
+ s_('AdminSettings|Maximum number of pipeline schedules')
+ when :ci_needs_size_limit
+ s_('AdminSettings|Maximum number of DAG dependencies that a job can have')
+ when :ci_registered_group_runners
+ s_('AdminSettings|Maximum number of runners registered per group')
+ when :ci_registered_project_runners
+ s_('AdminSettings|Maximum number of runners registered per project')
+ when :pipeline_hierarchy_size
+ s_("AdminSettings|Maximum number of downstream pipelines in a pipeline's hierarchy tree")
+ else
+ raise ArgumentError, "No description available for plan limit #{limit_name}"
+ end
+ end
+end
diff --git a/app/helpers/projects/error_tracking_helper.rb b/app/helpers/projects/error_tracking_helper.rb
index 471565d162c..fc4ad10db21 100644
--- a/app/helpers/projects/error_tracking_helper.rb
+++ b/app/helpers/projects/error_tracking_helper.rb
@@ -5,8 +5,7 @@ module Projects::ErrorTrackingHelper
error_tracking_enabled = !!project.error_tracking_setting&.enabled?
{
- 'index-path' => project_error_tracking_index_path(project,
- format: :json),
+ 'index-path' => project_error_tracking_index_path(project, format: :json),
'user-can-enable-error-tracking' => can?(current_user, :admin_operations, project).to_s,
'enable-error-tracking-link' => project_settings_operations_path(project),
'error-tracking-enabled' => error_tracking_enabled.to_s,
diff --git a/app/helpers/projects/settings/branch_rules_helper.rb b/app/helpers/projects/settings/branch_rules_helper.rb
new file mode 100644
index 00000000000..e53275d8183
--- /dev/null
+++ b/app/helpers/projects/settings/branch_rules_helper.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Projects
+ module Settings
+ module BranchRulesHelper
+ def branch_rules_data(project)
+ {
+ project_path: project.full_path,
+ protected_branches_path: project_settings_repository_path(project, anchor: 'js-protected-branches-settings'),
+ approval_rules_path: project_settings_merge_requests_path(project,
+ anchor: 'js-merge-request-approval-settings'),
+ status_checks_path: project_settings_merge_requests_path(project, anchor: 'js-merge-request-settings'),
+ branches_path: project_branches_path(project),
+ show_status_checks: 'false',
+ show_approvers: 'false',
+ show_code_owners: 'false'
+ }
+ end
+ end
+ end
+end
+
+Projects::Settings::BranchRulesHelper.prepend_mod
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 04190bc442b..a854b9990d2 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -133,6 +133,7 @@ module ProjectsHelper
{
source_name: source_project.full_name,
source_path: project_path(source_project),
+ source_default_branch: source_default_branch,
ahead_compare_path: project_compare_path(
project, from: source_default_branch, to: ref, from_project_id: source_project.id
),
@@ -474,7 +475,7 @@ module ProjectsHelper
def clusters_deprecation_alert_message
if has_active_license?
- s_('ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support.')
+ s_('ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions.')
else
s_('ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}.')
end
@@ -498,6 +499,18 @@ module ProjectsHelper
format_cached_count(1000, number)
end
+ def remote_mirror_setting_enabled?
+ false
+ end
+
+ def http_clone_url_to_repo(project)
+ project.http_url_to_repo
+ end
+
+ def ssh_clone_url_to_repo(project)
+ project.ssh_url_to_repo
+ end
+
private
def localized_access_names
@@ -753,7 +766,7 @@ module ProjectsHelper
end
def show_visibility_confirm_modal?(project)
- project.unlink_forks_upon_visibility_decrease_enabled? && project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && project.forks_count > 0
+ project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && project.forks_count > 0
end
def confirm_reduce_visibility_message(project)
diff --git a/app/helpers/registrations_helper.rb b/app/helpers/registrations_helper.rb
index 1724e11a6f1..fcd560dbe8c 100644
--- a/app/helpers/registrations_helper.rb
+++ b/app/helpers/registrations_helper.rb
@@ -11,8 +11,8 @@ module RegistrationsHelper
}
end
- def arkose_labs_challenge_enabled?
- false
+ def signup_box_template
+ 'devise/shared/signup_box'
end
end
diff --git a/app/helpers/routing/projects_helper.rb b/app/helpers/routing/projects_helper.rb
index f4732e398f0..a0073f9c5ba 100644
--- a/app/helpers/routing/projects_helper.rb
+++ b/app/helpers/routing/projects_helper.rb
@@ -43,9 +43,10 @@ module Routing
end
def work_item_url(entity, *args)
- unless Feature.enabled?(:use_iid_in_work_items_path, entity.project.group)
- return project_work_items_url(entity.project, entity.id, *args)
- end
+ # 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?iid_path=true
+ return unless entity.project.present?
options = args.first || {}
options[:iid_path] = true
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index ca5436ff019..d62dc038388 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -204,7 +204,9 @@ module SearchHelper
if search_has_project?
hash[:project] = { id: @project.id, name: @project.name }
- hash[:project_metadata] = { issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project) }
+ hash[:project_metadata] = { mr_path: project_merge_requests_path(@project) }
+ hash[:project_metadata][:issues_path] = project_issues_path(@project) if @project.feature_available?(:issues, current_user)
+
hash[:code_search] = search_scope.nil?
hash[:ref] = @ref if @ref && can?(current_user, :read_code, @project)
end
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index 27020738515..6c9688b0f9d 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -23,38 +23,100 @@ module SidebarsHelper
end
end
- def project_sidebar_context(project, user, current_ref, ref_type: nil)
+ def project_sidebar_context(project, user, current_ref, ref_type: nil, **args)
context_data = project_sidebar_context_data(project, user, current_ref, ref_type: ref_type)
- Sidebars::Projects::Context.new(**context_data)
+ Sidebars::Projects::Context.new(**context_data, **args)
end
- def group_sidebar_context(group, user)
+ def group_sidebar_context(group, user, **args)
context_data = group_sidebar_context_data(group, user)
- Sidebars::Groups::Context.new(**context_data)
+ Sidebars::Groups::Context.new(**context_data, **args)
end
- def super_sidebar_context(user, group:, project:)
+ def your_work_sidebar_context(user, **args)
+ context_data = your_work_context_data(user)
+
+ Sidebars::Context.new(**context_data, **args)
+ end
+
+ def super_sidebar_context(user, group:, project:, panel:)
{
+ current_menu_items: panel.super_sidebar_menu_items,
+ current_context_header: panel.super_sidebar_context_header,
name: user.name,
username: user.username,
avatar_url: user.avatar_url,
+ has_link_to_profile: current_user_menu?(:profile),
+ link_to_profile: user_url(user),
+ logo_url: current_appearance&.header_logo_path,
+ status: {
+ can_update: can?(current_user, :update_user_status, current_user),
+ busy: user.status&.busy?,
+ customized: user.status&.customized?,
+ availability: user.status&.availability.to_s,
+ emoji: user.status&.emoji,
+ message: user.status&.message_html&.html_safe,
+ clear_after: user_clear_status_at(user)
+ },
+ trial: {
+ has_start_trial: current_user_menu?(:start_trial),
+ url: trials_link_url
+ },
+ settings: {
+ has_settings: current_user_menu?(:settings),
+ profile_path: profile_path,
+ profile_preferences_path: profile_preferences_path
+ },
+ can_sign_out: current_user_menu?(:sign_out),
+ sign_out_link: destroy_user_session_path,
assigned_open_issues_count: user.assigned_open_issues_count,
todos_pending_count: user.todos_pending_count,
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username),
total_merge_requests_count: user_merge_requests_counts[:total],
create_new_menu_groups: create_new_menu_groups(group: group, project: project),
merge_request_menu: create_merge_request_menu(user),
+ projects_path: projects_path,
+ groups_path: groups_path,
support_path: support_url,
display_whats_new: display_whats_new?,
whats_new_most_recent_release_items_count: whats_new_most_recent_release_items_count,
whats_new_version_digest: whats_new_version_digest,
show_version_check: show_version_check?,
gitlab_version: Gitlab.version_info,
- gitlab_version_check: gitlab_version_check
+ gitlab_version_check: gitlab_version_check,
+ gitlab_com_but_not_canary: Gitlab.com_but_not_canary?,
+ gitlab_com_and_canary: Gitlab.com_and_canary?,
+ canary_toggle_com_url: Gitlab::Saas.canary_toggle_com_url,
+ current_context: super_sidebar_current_context(project: project, group: group)
}
end
+ def super_sidebar_nav_panel(
+ nav: nil, project: nil, user: nil, group: nil, current_ref: nil, ref_type: nil,
+ viewed_user: 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))
+ else
+ context = your_work_sidebar_context(user, **context_adds)
+ Sidebars::YourWork::Panel.new(context)
+ end
+ end
+
private
def create_new_menu_groups(group:, project:)
@@ -160,6 +222,44 @@ module SidebarsHelper
container: group
}
end
+
+ def your_work_context_data(user)
+ {
+ current_user: user,
+ container: user,
+ show_security_dashboard: false
+ }
+ end
+
+ def super_sidebar_current_context(project: nil, group: nil)
+ if project&.persisted?
+ return {
+ namespace: 'projects',
+ item: {
+ id: project.id,
+ name: project.name,
+ namespace: project.full_name,
+ webUrl: project_path(project),
+ avatarUrl: project.avatar_url
+ }
+ }
+ end
+
+ if group&.persisted?
+ return {
+ namespace: 'groups',
+ item: {
+ id: group.id,
+ name: group.name,
+ namespace: group.full_name,
+ webUrl: group_path(group),
+ avatarUrl: group.avatar_url
+ }
+ }
+ end
+
+ {}
+ end
end
SidebarsHelper.prepend_mod_with('SidebarsHelper')
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index 8558c664977..2f9117a74be 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -45,30 +45,35 @@ module SnippetsHelper
def embedded_raw_snippet_button(snippet, blob)
return if blob.empty? || blob.binary? || blob.stored_externally?
- link_to(external_snippet_icon('doc-code'),
- gitlab_raw_snippet_blob_url(snippet, blob.path),
- class: 'gl-button btn btn-default',
- target: '_blank',
- rel: 'noopener noreferrer',
- title: 'Open raw')
+ link_to(
+ external_snippet_icon('doc-code'),
+ gitlab_raw_snippet_blob_url(snippet, blob.path),
+ class: 'gl-button btn btn-default',
+ target: '_blank',
+ rel: 'noopener noreferrer',
+ title: 'Open raw'
+ )
end
def embedded_snippet_download_button(snippet, blob)
- link_to(external_snippet_icon('download'),
- gitlab_raw_snippet_blob_url(snippet, blob.path, nil, inline: false),
- class: 'gl-button btn btn-default',
- target: '_blank',
- title: 'Download',
- rel: 'noopener noreferrer')
+ link_to(
+ external_snippet_icon('download'),
+ gitlab_raw_snippet_blob_url(snippet, blob.path, nil, inline: false),
+ class: 'gl-button btn btn-default',
+ target: '_blank',
+ title: 'Download',
+ rel: 'noopener noreferrer'
+ )
end
def embedded_copy_snippet_button(blob)
return unless blob.rendered_as_text?(ignore_errors: false)
- content_tag(:button,
- class: 'gl-button btn btn-default copy-to-clipboard-btn',
- title: 'Copy snippet contents',
- onclick: "copyToClipboard('.blob-content[data-blob-id=\"#{blob.id}\"] > pre')"
+ content_tag(
+ :button,
+ class: 'gl-button btn btn-default copy-to-clipboard-btn',
+ title: 'Copy snippet contents',
+ onclick: "copyToClipboard('.blob-content[data-blob-id=\"#{blob.id}\"] > pre')"
) do
external_snippet_icon('copy-to-clipboard')
end
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 4a9596a1347..9038d972f65 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -227,7 +227,7 @@ module SortingHelper
options.concat([due_date_option]) if viewing_issues
options.concat([popularity_option, label_priority_option])
- options.concat([merged_option]) if viewing_merge_requests
+ options.concat([merged_option]) if can_sort_by_merged_date?(viewing_merge_requests)
options.concat([relative_position_option]) if viewing_issues
options.concat([title_option])
@@ -237,6 +237,10 @@ module SortingHelper
false
end
+ def can_sort_by_merged_date?(viewing_merge_requests)
+ viewing_merge_requests && %w[all merged].include?(params[:state])
+ end
+
def due_date_option
{ value: sort_value_due_date, text: sort_title_due_date, href: page_filter_path(sort: sort_value_due_date) }
end
diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb
index 3e5f63796b2..a1b6e896475 100644
--- a/app/helpers/system_note_helper.rb
+++ b/app/helpers/system_note_helper.rb
@@ -42,8 +42,6 @@ module SystemNoteHelper
'severity' => 'information-o',
'cloned' => 'documents',
'issue_type' => 'pencil',
- 'attention_requested' => 'user',
- 'attention_request_removed' => 'user',
'contact' => 'users',
'timeline_event' => 'clock',
'relate_to_child' => 'link',
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 4a9dd30a5a2..9b0810f3d17 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -232,13 +232,15 @@ module TodosHelper
''
end
+ due_date =
+ if is_due_today
+ _("today")
+ else
+ l(todo.target.due_date, format: Date::DATE_FORMATS[:medium])
+ end
+
content = content_tag(:span, class: css_class) do
- format(s_("Todos|Due %{due_date}"), due_date: if is_due_today
- _("today")
- else
- l(todo.target.due_date,
- format: Date::DATE_FORMATS[:medium])
- end)
+ format(s_("Todos|Due %{due_date}"), due_date: due_date)
end
"#{content} &middot;".html_safe
diff --git a/app/helpers/users/callouts_helper.rb b/app/helpers/users/callouts_helper.rb
index 2b8368dd29f..af3ac495164 100644
--- a/app/helpers/users/callouts_helper.rb
+++ b/app/helpers/users/callouts_helper.rb
@@ -11,9 +11,11 @@ module Users
UNFINISHED_TAG_CLEANUP_CALLOUT = 'unfinished_tag_cleanup_callout'
SECURITY_NEWSLETTER_CALLOUT = 'security_newsletter_callout'
MERGE_REQUEST_SETTINGS_MOVED_CALLOUT = 'merge_request_settings_moved_callout'
+ 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'
def show_gke_cluster_integration_callout?(project)
active_nav_link?(controller: sidebar_operations_paths) &&
@@ -59,42 +61,47 @@ module Users
!user_dismissed?(SECURITY_NEWSLETTER_CALLOUT)
end
- def web_hook_disabled_dismissed?(project)
- return false unless project
-
- last_failure = Gitlab::Redis::SharedState.with do |redis|
- key = "web_hooks:last_failure:project-#{project.id}"
- redis.get(key)
- end
+ def web_hook_disabled_dismissed?(object)
+ return false unless object.is_a?(::WebHooks::HasWebHooks)
- last_failure = DateTime.parse(last_failure) if last_failure
-
- user_dismissed?(WEB_HOOK_DISABLED, last_failure, project: project)
+ user_dismissed?(WEB_HOOK_DISABLED, object.last_webhook_failure, object: object)
end
def show_merge_request_settings_callout?(project)
!user_dismissed?(MERGE_REQUEST_SETTINGS_MOVED_CALLOUT) && project.merge_requests_enabled?
end
+ def show_pages_menu_callout?
+ !user_dismissed?(PAGES_MOVED_CALLOUT)
+ end
+
+ def show_branch_rules_info?
+ !user_dismissed?(BRANCH_RULES_INFO_CALLOUT)
+ end
+
def ultimate_feature_removal_banner_dismissed?(project)
return false unless project
- user_dismissed?(ULTIMATE_FEATURE_REMOVAL_BANNER, project: project)
+ user_dismissed?(ULTIMATE_FEATURE_REMOVAL_BANNER, object: project)
end
private
- def user_dismissed?(feature_name, ignore_dismissal_earlier_than = nil, project: nil)
+ def user_dismissed?(feature_name, ignore_dismissal_earlier_than = nil, object: nil)
return false unless current_user
query = { feature_name: feature_name, ignore_dismissal_earlier_than: ignore_dismissal_earlier_than }
- if project
- current_user.dismissed_callout_for_project?(project: project, **query)
+ if object
+ dismissed_callout?(object, query)
else
current_user.dismissed_callout?(**query)
end
end
+
+ def dismissed_callout?(object, query)
+ current_user.dismissed_callout_for_project?(project: object, **query)
+ end
end
end
diff --git a/app/helpers/users/group_callouts_helper.rb b/app/helpers/users/group_callouts_helper.rb
index 0aa4eb89499..92cf41400e7 100644
--- a/app/helpers/users/group_callouts_helper.rb
+++ b/app/helpers/users/group_callouts_helper.rb
@@ -17,9 +17,11 @@ module Users
def user_dismissed_for_group(feature_name, group, ignore_dismissal_earlier_than = nil)
return false unless current_user
- current_user.dismissed_callout_for_group?(feature_name: feature_name,
- group: group,
- ignore_dismissal_earlier_than: ignore_dismissal_earlier_than)
+ current_user.dismissed_callout_for_group?(
+ feature_name: feature_name,
+ group: group,
+ ignore_dismissal_earlier_than: ignore_dismissal_earlier_than
+ )
end
def just_created?
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index 62b9eb2b506..e0cf7aa61ee 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -8,10 +8,15 @@ module UsersHelper
}
end
+ def user_clear_status_at(user)
+ # The user.status can be nil when the user has no status, so we need to protect against that case.
+ # iso8601 is the official RFC supported format for frontend parsing of date:
+ # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date
+ user.status&.clear_status_at&.to_s(:iso8601)
+ end
+
def user_link(user)
- link_to(user.name, user_path(user),
- title: user.email,
- class: 'has-tooltip commit-committer-link')
+ link_to(user.name, user_path(user), title: user.email, class: 'has-tooltip commit-committer-link')
end
def user_email_help_text(user)
@@ -79,9 +84,9 @@ module UsersHelper
return unless user.status
content_tag :span,
- class: 'user-status-emoji has-tooltip',
- title: user.status.message_html,
- data: { html: true, placement: 'top' } do
+ class: 'user-status-emoji has-tooltip',
+ title: user.status.message_html,
+ data: { html: true, placement: 'top' } do
emoji_icon user.status.emoji
end
end
@@ -168,6 +173,19 @@ module UsersHelper
user.public_email.present?
end
+ def trials_link_url
+ 'https://about.gitlab.com/free-trial/'
+ end
+
+ def user_profile_tabs_app_data(user)
+ {
+ followees: user.followees.count,
+ followers: user.followers.count,
+ user_calendar_path: user_calendar_path(user, :json),
+ utc_offset: local_timezone_instance(user.timezone).now.utc_offset
+ }
+ end
+
private
def admin_users_paths
@@ -211,10 +229,6 @@ module UsersHelper
tabs
end
- def trials_link_url
- 'https://about.gitlab.com/free-trial/'
- end
-
def trials_allowed?(user)
false
end
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index 5ed341ee5e5..c577e2da1bb 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -44,9 +44,8 @@ module VisibilityLevelHelper
Gitlab::CurrentSettings.restricted_visibility_levels || []
end
- delegate :default_project_visibility,
- :default_group_visibility,
- to: :'Gitlab::CurrentSettings.current_application_settings'
+ delegate :default_project_visibility, :default_group_visibility,
+ to: :'Gitlab::CurrentSettings.current_application_settings'
def disallowed_visibility_level?(form_model, level)
return false unless form_model.respond_to?(:visibility_level_allowed?)
diff --git a/app/helpers/web_hooks/web_hooks_helper.rb b/app/helpers/web_hooks/web_hooks_helper.rb
index 514db6ba8a2..ad792f761f8 100644
--- a/app/helpers/web_hooks/web_hooks_helper.rb
+++ b/app/helpers/web_hooks/web_hooks_helper.rb
@@ -4,19 +4,31 @@ module WebHooks
module WebHooksHelper
def show_project_hook_failed_callout?(project:)
return false if project_hook_page?
+
+ show_hook_failed_callout?(project)
+ end
+
+ private
+
+ def show_hook_failed_callout?(object)
return false unless current_user
- return false unless Ability.allowed?(current_user, :read_web_hooks, project)
+
+ return false unless can_access_web_hooks?(object)
# Assumes include of Users::CalloutsHelper
- return false if web_hook_disabled_dismissed?(project)
+ return false if web_hook_disabled_dismissed?(object)
- project.fetch_web_hook_failure
+ object.fetch_web_hook_failure
end
- private
-
def project_hook_page?
current_controller?('projects/hooks') || current_controller?('projects/hook_logs')
end
+
+ def can_access_web_hooks?(object)
+ Ability.allowed?(current_user, :admin_project, object)
+ end
end
end
+
+WebHooks::WebHooksHelper.prepend_mod
diff --git a/app/helpers/work_items_helper.rb b/app/helpers/work_items_helper.rb
index efa9a2bd463..bc270380fca 100644
--- a/app/helpers/work_items_helper.rb
+++ b/app/helpers/work_items_helper.rb
@@ -6,7 +6,8 @@ module WorkItemsHelper
full_path: project.full_path,
issues_list_path: project_issues_path(project),
register_path: new_user_registration_path(redirect_to_referer: 'yes'),
- sign_in_path: new_session_path(:user, redirect_to_referer: 'yes')
+ sign_in_path: new_session_path(:user, redirect_to_referer: 'yes'),
+ saved_replies_new_path: profile_saved_replies_path
}
end
end
diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb
index 58843435fa0..e053fc0453c 100644
--- a/app/mailers/emails/issues.rb
+++ b/app/mailers/emails/issues.rb
@@ -100,18 +100,7 @@ module Emails
end
def issues_csv_email(user, project, csv_data, export_status)
- @project = project
- @count = export_status.fetch(:rows_expected)
- @written_count = export_status.fetch(:rows_written)
- @truncated = export_status.fetch(:truncated)
- @size_limit = ActiveSupport::NumberHelper
- .number_to_human_size(ExportCsv::BaseService::TARGET_FILESIZE)
-
- filename = "#{project.full_path.parameterize}_issues_#{Date.today.iso8601}.csv"
- attachments[filename] = { content: csv_data, mime_type: 'text/csv' }
- email_with_layout(
- to: user.notification_email_for(@project.group),
- subject: subject("Exported issues"))
+ csv_email(user, project, csv_data, export_status, 'issues')
end
private
diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb
index 5b1750400d8..a191bd4a8f6 100644
--- a/app/mailers/emails/profile.rb
+++ b/app/mailers/emails/profile.rb
@@ -153,7 +153,7 @@ module Emails
Gitlab::I18n.with_locale(@user.preferred_language) do
email_with_layout(
to: @user.notification_email_or_default,
- subject: subject(_("Attempted sign in to %{host} using a wrong two-factor authentication code") % { host: Gitlab.config.gitlab.host }))
+ subject: subject(_("Attempted sign in to %{host} using an incorrect verification code") % { host: Gitlab.config.gitlab.host }))
end
end
diff --git a/app/mailers/emails/shared.rb b/app/mailers/emails/shared.rb
new file mode 100644
index 00000000000..09876c0960a
--- /dev/null
+++ b/app/mailers/emails/shared.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Emails
+ module Shared
+ def csv_email(user, project, csv_data, export_status, type)
+ @project = project
+ @count = export_status.fetch(:rows_expected)
+ @written_count = export_status.fetch(:rows_written)
+ @truncated = export_status.fetch(:truncated)
+ @size_limit = ActiveSupport::NumberHelper
+ .number_to_human_size(ExportCsv::BaseService::TARGET_FILESIZE)
+
+ filename = "#{project.full_path.parameterize}_#{type}_#{Date.today.iso8601}.csv"
+ attachments[filename] = { content: csv_data, mime_type: 'text/csv' }
+ email_with_layout(
+ to: user.notification_email_for(@project.group),
+ subject: subject("Exported #{type.humanize.downcase}"))
+ end
+ end
+end
diff --git a/app/mailers/emails/work_items.rb b/app/mailers/emails/work_items.rb
new file mode 100644
index 00000000000..b14111c94eb
--- /dev/null
+++ b/app/mailers/emails/work_items.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Emails
+ module WorkItems
+ def import_work_items_csv_email(user_id, project_id, results)
+ @user = User.find(user_id)
+ @project = Project.find(project_id)
+ @results = results
+
+ email_with_layout(
+ to: @user.notification_email_for(@project.group),
+ subject: subject('Imported work items'))
+ end
+
+ def export_work_items_csv_email(user, project, csv_data, export_status)
+ csv_email(user, project, csv_data, export_status, 'work_items')
+ end
+ end
+end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 28ef6d8d6c6..2d6b2a3099c 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -7,6 +7,7 @@ class Notify < ApplicationMailer
include ReminderEmailsHelper
include IssuablesHelper
+ include Emails::Shared
include Emails::Issues
include Emails::MergeRequests
include Emails::Notes
@@ -25,6 +26,7 @@ class Notify < ApplicationMailer
include Emails::AdminNotification
include Emails::IdentityVerification
include Emails::Imports
+ include Emails::WorkItems
helper TimeboxesHelper
helper MergeRequestsHelper
diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb
index 7ed594bf571..17b225c5e9b 100644
--- a/app/mailers/previews/notify_preview.rb
+++ b/app/mailers/previews/notify_preview.rb
@@ -60,6 +60,14 @@ class NotifyPreview < ActionMailer::Preview
end
end
+ def access_token_created_email
+ Notify.access_token_created_email(user, 'token_name').message
+ end
+
+ def access_token_revoked_email
+ Notify.access_token_revoked_email(user, 'token_name').message
+ end
+
def new_mention_in_merge_request_email
Notify.new_mention_in_merge_request_email(user.id, merge_request.id, user.id).message
end
@@ -84,6 +92,10 @@ class NotifyPreview < ActionMailer::Preview
Notify.import_issues_csv_email(user.id, project.id, { success: 3, errors: [5, 6, 7], valid_file: true })
end
+ def import_work_items_csv_email
+ Notify.import_work_items_csv_email(user.id, project.id, { success: 4, error_lines: [2, 3, 4], parse_error: false })
+ end
+
def issues_csv_email
Notify.issues_csv_email(user, project, '1997,Ford,E350', { truncated: false, rows_expected: 3, rows_written: 3 }).message
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index eb645bcd653..4da4d113a7f 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -77,6 +77,8 @@ class Ability
policy = policy_for(user, subject)
+ before_check(policy, ability.to_sym, user, subject, opts)
+
case opts[:scope]
when :user
DeclarativePolicy.user_scope { policy.allowed?(ability) }
@@ -92,6 +94,11 @@ class Ability
forget_runner_result(policy.runner(ability)) if policy && ability_forgetting?
end
+ # Hook call right before ability check.
+ def before_check(policy, ability, user, subject, opts)
+ # See Support::AbilityCheck and Support::PermissionsCheck.
+ end
+
def policy_for(user, subject = :global)
DeclarativePolicy.policy_for(user, subject, cache: ::Gitlab::SafeRequestStore.storage)
end
diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb
index dbcdfa5e946..5ae5367ca5a 100644
--- a/app/models/abuse_report.rb
+++ b/app/models/abuse_report.rb
@@ -42,7 +42,9 @@ class AbuseReport < ApplicationRecord
before_validation :filter_empty_strings_from_links_to_spam
validate :links_to_spam_contains_valid_urls
- scope :by_user, ->(user) { where(user_id: user) }
+ scope :by_user_id, ->(id) { where(user_id: id) }
+ scope :by_reporter_id, ->(id) { where(reporter_id: id) }
+ scope :by_category, ->(category) { where(category: category) }
scope :with_users, -> { includes(:reporter, :user) }
enum category: {
@@ -56,6 +58,11 @@ class AbuseReport < ApplicationRecord
other: 8
}
+ enum status: {
+ open: 1,
+ closed: 2
+ }
+
# For CacheMarkdownField
alias_method :author, :reporter
diff --git a/app/models/achievements/user_achievement.rb b/app/models/achievements/user_achievement.rb
index 885ec660cc9..bc5d10923d7 100644
--- a/app/models/achievements/user_achievement.rb
+++ b/app/models/achievements/user_achievement.rb
@@ -8,10 +8,16 @@ module Achievements
belongs_to :awarded_by_user,
class_name: 'User',
inverse_of: :awarded_user_achievements,
- optional: true
+ optional: false
belongs_to :revoked_by_user,
class_name: 'User',
inverse_of: :revoked_user_achievements,
optional: true
+
+ scope :not_revoked, -> { where(revoked_by_user_id: nil) }
+
+ def revoked?
+ revoked_by_user_id.present?
+ end
end
end
diff --git a/app/models/airflow.rb b/app/models/airflow.rb
deleted file mode 100644
index 2e5642a2639..00000000000
--- a/app/models/airflow.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-module Airflow
- def self.table_name_prefix
- 'airflow_'
- end
-end
diff --git a/app/models/airflow/dags.rb b/app/models/airflow/dags.rb
deleted file mode 100644
index d17d4a4f3db..00000000000
--- a/app/models/airflow/dags.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-module Airflow
- class Dags < ApplicationRecord
- belongs_to :project
-
- validates :project, presence: true
- validates :dag_name, length: { maximum: 255 }, presence: true
- validates :schedule, length: { maximum: 255 }
- validates :fileloc, length: { maximum: 255 }
-
- scope :by_project_id, ->(project_id) { where(project_id: project_id).order(id: :asc) }
- end
-end
diff --git a/app/models/alert_management/alert.rb b/app/models/alert_management/alert.rb
index a5a539eae75..74edcf12ac2 100644
--- a/app/models/alert_management/alert.rb
+++ b/app/models/alert_management/alert.rb
@@ -25,8 +25,9 @@ module AlertManagement
has_many :assignees, through: :alert_assignees
has_many :notes, as: :noteable, inverse_of: :noteable, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
- has_many :ordered_notes, -> { fresh }, as: :noteable, class_name: 'Note'
- has_many :user_mentions, class_name: 'AlertManagement::AlertUserMention', foreign_key: :alert_management_alert_id
+ has_many :ordered_notes, -> { fresh }, as: :noteable, class_name: 'Note', inverse_of: :noteable
+ has_many :user_mentions, class_name: 'AlertManagement::AlertUserMention', foreign_key: :alert_management_alert_id,
+ inverse_of: :alert
has_many :metric_images, class_name: '::AlertManagement::MetricImage'
has_internal_id :iid, scope: :project
@@ -139,7 +140,7 @@ module AlertManagement
end
def self.link_reference_pattern
- @link_reference_pattern ||= super("alert_management", %r{(?<alert>\d+)/details(\#)?})
+ @link_reference_pattern ||= compose_link_reference_pattern('alert_management', %r{(?<alert>\d+)/details(\#)?})
end
def self.reference_valid?(reference)
diff --git a/app/models/alert_management/alert_assignee.rb b/app/models/alert_management/alert_assignee.rb
index c74b2699182..27e720c3262 100644
--- a/app/models/alert_management/alert_assignee.rb
+++ b/app/models/alert_management/alert_assignee.rb
@@ -3,7 +3,7 @@
module AlertManagement
class AlertAssignee < ApplicationRecord
belongs_to :alert, inverse_of: :alert_assignees
- belongs_to :assignee, class_name: 'User', foreign_key: :user_id
+ belongs_to :assignee, class_name: 'User', foreign_key: :user_id, inverse_of: :alert_assignees
validates :alert, presence: true
validates :assignee, presence: true, uniqueness: { scope: :alert_id }
diff --git a/app/models/alert_management/alert_user_mention.rb b/app/models/alert_management/alert_user_mention.rb
index d36aa80ee05..1ab71127677 100644
--- a/app/models/alert_management/alert_user_mention.rb
+++ b/app/models/alert_management/alert_user_mention.rb
@@ -2,7 +2,10 @@
module AlertManagement
class AlertUserMention < UserMention
- belongs_to :alert_management_alert, class_name: '::AlertManagement::Alert'
+ belongs_to :alert, class_name: '::AlertManagement::Alert',
+ foreign_key: :alert_management_alert_id,
+ inverse_of: :user_mentions
+
belongs_to :note
end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 98adbd3ab06..71434931d8c 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -22,6 +22,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
KROKI_URL_ERROR_MESSAGE = 'Please check your Kroki URL setting in ' \
'Admin Area > Settings > General > Kroki'
+ # Validate URIs in this model according to the current value of the `deny_all_requests_except_allowed` property,
+ # rather than the persisted value.
+ ADDRESSABLE_URL_VALIDATION_OPTIONS = { deny_all_requests_except_allowed: ->(settings) { settings.deny_all_requests_except_allowed } }.freeze
+
enum whats_new_variant: { all_tiers: 0, current_tier: 1, disabled: 2 }, _prefix: true
enum email_confirmation_setting: { off: 0, soft: 1, hard: 2 }, _prefix: true
@@ -30,11 +34,13 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
add_authentication_token_field :static_objects_external_storage_auth_token, encrypted: :required
add_authentication_token_field :error_tracking_access_token, encrypted: :required
- belongs_to :self_monitoring_project, class_name: "Project", foreign_key: 'instance_administration_project_id'
+ belongs_to :self_monitoring_project, class_name: "Project", foreign_key: :instance_administration_project_id,
+ inverse_of: :application_setting
belongs_to :push_rule
alias_attribute :self_monitoring_project_id, :instance_administration_project_id
- belongs_to :instance_group, class_name: "Group", foreign_key: 'instance_administrators_group_id'
+ belongs_to :instance_group, class_name: "Group", foreign_key: :instance_administrators_group_id,
+ inverse_of: :application_setting
alias_attribute :instance_group_id, :instance_administrators_group_id
alias_attribute :instance_administrators_group, :instance_group
alias_attribute :housekeeping_optimize_repository_period, :housekeeping_incremental_repack_period
@@ -90,9 +96,9 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
chronic_duration_attr :project_runner_token_expiration_interval_human_readable, :project_runner_token_expiration_interval
validates :grafana_url,
- system_hook_url: {
+ system_hook_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({
blocked_message: "is blocked: %{exception_message}. #{GRAFANA_URL_ERROR_MESSAGE}"
- },
+ }),
if: :grafana_url_absolute?
validate :validate_grafana_url
@@ -116,22 +122,22 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
validates :home_page_url,
allow_blank: true,
- addressable_url: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS,
if: :home_page_url_column_exists?
validates :help_page_support_url,
allow_blank: true,
- addressable_url: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS,
if: :help_page_support_url_column_exists?
validates :help_page_documentation_base_url,
length: { maximum: 255, message: N_("is too long (maximum is %{count} characters)") },
allow_blank: true,
- addressable_url: true
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS
validates :after_sign_out_path,
allow_blank: true,
- addressable_url: true
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS
validates :abuse_notification_email,
devise_email: true,
@@ -188,7 +194,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
validates :gitpod_url,
presence: true,
- addressable_url: { enforce_sanitization: true },
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({ enforce_sanitization: true }),
if: :gitpod_enabled
validates :mailgun_signing_key,
@@ -348,7 +354,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
if: :asset_proxy_enabled?
validates :static_objects_external_storage_url,
- addressable_url: true, allow_blank: true
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, allow_blank: true
validates :static_objects_external_storage_auth_token,
presence: true,
@@ -421,6 +427,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
allow_nil: false,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ validates :deny_all_requests_except_allowed,
+ allow_nil: false,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
+
Gitlab::SSHPublicKey.supported_types.each do |type|
validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type }
end
@@ -452,7 +462,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
if: :external_authorization_service_enabled
validates :external_authorization_service_url,
- addressable_url: true, allow_blank: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, allow_blank: true,
if: :external_authorization_service_enabled
validates :external_authorization_service_timeout,
@@ -460,7 +470,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
if: :external_authorization_service_enabled
validates :spam_check_endpoint_url,
- addressable_url: { 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,
@@ -534,7 +544,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
validates :jira_connect_proxy_url,
length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
allow_blank: true,
- public_url: true
+ public_url: ADDRESSABLE_URL_VALIDATION_OPTIONS
with_options(presence: true, numericality: { only_integer: true, greater_than: 0 }) do
validates :throttle_unauthenticated_api_requests_per_period
@@ -563,14 +573,12 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
validates :throttle_protected_paths_period_in_seconds
end
- validates :notes_create_limit,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
-
- validates :search_rate_limit,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
-
- validates :search_rate_limit_unauthenticated,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ with_options(numericality: { only_integer: true, greater_than_or_equal_to: 0 }) do
+ validates :notes_create_limit
+ validates :search_rate_limit
+ validates :search_rate_limit_unauthenticated
+ validates :projects_api_rate_limit_unauthenticated
+ end
validates :notes_create_limit_allowlist,
length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
@@ -580,7 +588,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :external_pipeline_validation_service_url,
- addressable_url: true, allow_blank: true
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, allow_blank: true
validates :external_pipeline_validation_service_timeout,
allow_nil: true,
@@ -607,10 +615,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
validates :sentry_enabled,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :sentry_dsn,
- addressable_url: true, presence: true, length: { maximum: 255 },
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, presence: true, length: { maximum: 255 },
if: :sentry_enabled?
validates :sentry_clientside_dsn,
- addressable_url: true, allow_blank: true, length: { maximum: 255 },
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS, allow_blank: true, length: { maximum: 255 },
if: :sentry_enabled?
validates :sentry_environment,
presence: true, length: { maximum: 255 },
@@ -620,7 +628,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :error_tracking_api_url,
presence: true,
- addressable_url: true,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS,
length: { maximum: 255 },
if: :error_tracking_enabled?
@@ -630,7 +638,12 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
allow_nil: false
- validates :public_runner_releases_url, addressable_url: true, presence: true
+ validates :update_runner_versions_enabled,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ validates :public_runner_releases_url,
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS,
+ presence: true,
+ if: :update_runner_versions_enabled?
validates :inactive_projects_min_size_mb,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
@@ -698,6 +711,15 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
allow_nil: false,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ validates :default_syntax_highlighting_theme,
+ allow_nil: false,
+ numericality: { only_integer: true, greater_than: 0 },
+ inclusion: { in: Gitlab::ColorSchemes.valid_ids, message: N_('must be a valid syntax highlighting theme ID') }
+
+ validates :gitlab_dedicated_instance,
+ allow_nil: false,
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
+
before_validation :ensure_uuid!
before_validation :coerce_repository_storages_weighted, if: :repository_storages_weighted_changed?
before_validation :normalize_default_branch_name
@@ -822,6 +844,33 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
false
end
+ # Overriding the enum check for `email_confirmation_setting` as the feature flag is being removed and is taking a
+ # release M, M.N+1 strategy as noted in:
+ # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107302#note_1286005956
+ def email_confirmation_setting_off?
+ if Feature.enabled?(:soft_email_confirmation)
+ false
+ else
+ super
+ end
+ end
+
+ def email_confirmation_setting_soft?
+ if Feature.enabled?(:soft_email_confirmation)
+ true
+ else
+ super
+ end
+ end
+
+ def email_confirmation_setting_hard?
+ if Feature.enabled?(:soft_email_confirmation)
+ false
+ else
+ super
+ end
+ end
+
private
def parsed_grafana_url
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index a5f262f2e1e..b8d6434d9c9 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -60,6 +60,7 @@ module ApplicationSettingImplementation
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_projects_limit: Settings.gitlab['default_projects_limit'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
+ deny_all_requests_except_allowed: false,
diff_max_patch_bytes: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES,
diff_max_files: Commit::DEFAULT_MAX_DIFF_FILES_SETTING,
diff_max_lines: Commit::DEFAULT_MAX_DIFF_LINES_SETTING,
@@ -249,7 +250,9 @@ module ApplicationSettingImplementation
can_create_group: true,
bulk_import_enabled: false,
allow_runner_registration_token: true,
- user_defaults_to_private_profile: false
+ user_defaults_to_private_profile: false,
+ projects_api_rate_limit_unauthenticated: 400,
+ gitlab_dedicated_instance: false
}.tap do |hsh|
hsh.merge!(non_production_defaults) unless Rails.env.production?
end
diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb
index 3312216932b..163e741d990 100644
--- a/app/models/audit_event.rb
+++ b/app/models/audit_event.rb
@@ -21,7 +21,7 @@ class AuditEvent < ApplicationRecord
serialize :details, Hash # rubocop:disable Cop/ActiveRecordSerialize
- belongs_to :user, foreign_key: :author_id
+ belongs_to :user, foreign_key: :author_id, inverse_of: :audit_events
validates :author_id, presence: true
validates :entity_id, presence: true
diff --git a/app/models/badge.rb b/app/models/badge.rb
index 0676de10d02..23e6f305c32 100644
--- a/app/models/badge.rb
+++ b/app/models/badge.rb
@@ -42,7 +42,7 @@ class Badge < ApplicationRecord
private
def build_rendered_url(url, project = nil)
- return url unless valid? && project
+ return url unless project
Gitlab::StringPlaceholderReplacer.replace_string_placeholders(url, PLACEHOLDERS_REGEX) do |arg|
replace_placeholder_action(PLACEHOLDERS[arg], project)
diff --git a/app/models/board.rb b/app/models/board.rb
index 2181b2f0545..702ae0cc9f5 100644
--- a/app/models/board.rb
+++ b/app/models/board.rb
@@ -6,8 +6,8 @@ class Board < ApplicationRecord
belongs_to :group
belongs_to :project
- has_many :lists, -> { ordered }, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
- has_many :destroyable_lists, -> { destroyable.ordered }, class_name: "List"
+ has_many :lists, -> { ordered }, dependent: :delete_all, inverse_of: :board # rubocop:disable Cop/ActiveRecordDependent
+ has_many :destroyable_lists, -> { destroyable.ordered }, class_name: "List", inverse_of: :board
validates :name, presence: true
validates :project, presence: true, if: :project_needed?
diff --git a/app/models/bulk_import.rb b/app/models/bulk_import.rb
index 2565ad5f2b8..c2d7529f468 100644
--- a/app/models/bulk_import.rb
+++ b/app/models/bulk_import.rb
@@ -42,6 +42,12 @@ class BulkImport < ApplicationRecord
event :fail_op do
transition any => :failed
end
+
+ # rubocop:disable Style/SymbolProc
+ after_transition any => [:finished, :failed, :timeout] do |bulk_import|
+ bulk_import.update_has_failures
+ end
+ # rubocop:enable Style/SymbolProc
end
def source_version_info
@@ -55,4 +61,11 @@ class BulkImport < ApplicationRecord
def self.all_human_statuses
state_machine.states.map(&:human_name)
end
+
+ def update_has_failures
+ return if has_failures
+ return unless entities.any?(&:has_failures)
+
+ update!(has_failures: true)
+ end
end
diff --git a/app/models/bulk_imports/batch_tracker.rb b/app/models/bulk_imports/batch_tracker.rb
new file mode 100644
index 00000000000..df1fab89ee6
--- /dev/null
+++ b/app/models/bulk_imports/batch_tracker.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module BulkImports
+ class BatchTracker < ApplicationRecord
+ self.table_name = 'bulk_import_batch_trackers'
+
+ belongs_to :tracker, class_name: 'BulkImports::Tracker'
+
+ validates :batch_number, presence: true, uniqueness: { scope: :tracker_id }
+
+ state_machine :status, initial: :created do
+ state :created, value: 0
+ state :started, value: 1
+ state :finished, value: 2
+ state :timeout, value: 3
+ state :failed, value: -1
+ state :skipped, value: -2
+
+ event :start do
+ transition created: :started
+ end
+
+ event :retry do
+ transition started: :created
+ end
+
+ event :finish do
+ transition started: :finished
+ transition failed: :failed
+ transition skipped: :skipped
+ end
+
+ event :skip do
+ transition any => :skipped
+ end
+
+ event :fail_op do
+ transition any => :failed
+ end
+
+ event :cleanup_stale do
+ transition [:created, :started] => :timeout
+ end
+ end
+ end
+end
diff --git a/app/models/bulk_imports/entity.rb b/app/models/bulk_imports/entity.rb
index 6fc24c77f1d..ae2d3758110 100644
--- a/app/models/bulk_imports/entity.rb
+++ b/app/models/bulk_imports/entity.rb
@@ -26,10 +26,11 @@ class BulkImports::Entity < ApplicationRecord
belongs_to :parent, class_name: 'BulkImports::Entity', optional: true
belongs_to :project, optional: true
- belongs_to :group, foreign_key: :namespace_id, optional: true
+ belongs_to :group, foreign_key: :namespace_id, optional: true, inverse_of: :bulk_import_entities
has_many :trackers,
class_name: 'BulkImports::Tracker',
+ inverse_of: :entity,
foreign_key: :bulk_import_entity_id
has_many :failures,
@@ -104,6 +105,12 @@ class BulkImports::Entity < ApplicationRecord
transition created: :timeout
transition started: :timeout
end
+
+ # rubocop:disable Style/SymbolProc
+ after_transition any => [:finished, :failed, :timeout] do |entity|
+ entity.update_has_failures
+ end
+ # rubocop:enable Style/SymbolProc
end
def self.all_human_statuses
@@ -185,6 +192,13 @@ class BulkImports::Entity < ApplicationRecord
default_project_visibility
end
+ def update_has_failures
+ return if has_failures
+ return unless failures.any?
+
+ update!(has_failures: true)
+ end
+
private
def validate_parent_is_a_group
@@ -194,13 +208,6 @@ class BulkImports::Entity < ApplicationRecord
end
def validate_imported_entity_type
- if project_entity? && !BulkImports::Features.project_migration_enabled?(destination_namespace)
- errors.add(
- :base,
- s_('BulkImport|invalid entity source type')
- )
- end
-
if group.present? && project_entity?
errors.add(
:group,
diff --git a/app/models/bulk_imports/export.rb b/app/models/bulk_imports/export.rb
index 8d4d31ee92d..1ea317a100a 100644
--- a/app/models/bulk_imports/export.rb
+++ b/app/models/bulk_imports/export.rb
@@ -14,6 +14,7 @@ module BulkImports
belongs_to :group, optional: true
has_one :upload, class_name: 'BulkImports::ExportUpload'
+ has_many :batches, class_name: 'BulkImports::ExportBatch'
validates :project, presence: true, unless: :group
validates :group, presence: true, unless: :project
diff --git a/app/models/bulk_imports/export_batch.rb b/app/models/bulk_imports/export_batch.rb
new file mode 100644
index 00000000000..9d34dae12d0
--- /dev/null
+++ b/app/models/bulk_imports/export_batch.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module BulkImports
+ class ExportBatch < ApplicationRecord
+ self.table_name = 'bulk_import_export_batches'
+
+ BATCH_SIZE = 1000
+
+ belongs_to :export, class_name: 'BulkImports::Export'
+ has_one :upload, class_name: 'BulkImports::ExportUpload', foreign_key: :batch_id, inverse_of: :batch
+
+ validates :batch_number, presence: true, uniqueness: { scope: :export_id }
+
+ state_machine :status, initial: :started do
+ state :started, value: 0
+ state :finished, value: 1
+ state :failed, value: -1
+
+ event :start do
+ transition any => :started
+ end
+
+ event :finish do
+ transition started: :finished
+ transition failed: :failed
+ end
+
+ event :fail_op do
+ transition any => :failed
+ end
+ end
+ end
+end
diff --git a/app/models/bulk_imports/export_upload.rb b/app/models/bulk_imports/export_upload.rb
index 4304032b28c..00f8e8f1304 100644
--- a/app/models/bulk_imports/export_upload.rb
+++ b/app/models/bulk_imports/export_upload.rb
@@ -7,6 +7,7 @@ module BulkImports
self.table_name = 'bulk_import_export_uploads'
belongs_to :export, class_name: 'BulkImports::Export'
+ belongs_to :batch, class_name: 'BulkImports::ExportBatch', optional: true
mount_uploader :export_file, ExportUploader
diff --git a/app/models/bulk_imports/file_transfer.rb b/app/models/bulk_imports/file_transfer.rb
index 5be954b98da..c6af4e0c833 100644
--- a/app/models/bulk_imports/file_transfer.rb
+++ b/app/models/bulk_imports/file_transfer.rb
@@ -9,9 +9,9 @@ module BulkImports
def config_for(portable)
case portable
when ::Project
- FileTransfer::ProjectConfig.new(portable)
+ ::BulkImports::FileTransfer::ProjectConfig.new(portable)
when ::Group
- FileTransfer::GroupConfig.new(portable)
+ ::BulkImports::FileTransfer::GroupConfig.new(portable)
else
raise(UnsupportedObjectType, "Unsupported object type: #{portable.class}")
end
diff --git a/app/models/bulk_imports/file_transfer/base_config.rb b/app/models/bulk_imports/file_transfer/base_config.rb
index 036d511bc59..67c4e7400b3 100644
--- a/app/models/bulk_imports/file_transfer/base_config.rb
+++ b/app/models/bulk_imports/file_transfer/base_config.rb
@@ -51,7 +51,8 @@ module BulkImports
end
def portable_relations_tree
- @portable_relations_tree ||= attributes_finder.find_relations_tree(portable_class_sym).deep_stringify_keys
+ @portable_relations_tree ||= attributes_finder
+ .find_relations_tree(portable_class_sym, include_import_only_tree: true).deep_stringify_keys
end
private
diff --git a/app/models/bulk_imports/tracker.rb b/app/models/bulk_imports/tracker.rb
index b04ef1cb7ae..55502721a76 100644
--- a/app/models/bulk_imports/tracker.rb
+++ b/app/models/bulk_imports/tracker.rb
@@ -7,9 +7,12 @@ class BulkImports::Tracker < ApplicationRecord
belongs_to :entity,
class_name: 'BulkImports::Entity',
+ inverse_of: :trackers,
foreign_key: :bulk_import_entity_id,
optional: false
+ has_many :batches, class_name: 'BulkImports::BatchTracker', inverse_of: :tracker
+
validates :relation,
presence: true,
uniqueness: { scope: :bulk_import_entity_id }
diff --git a/app/models/chat_name.rb b/app/models/chat_name.rb
index 9bd618c1008..cda19273f52 100644
--- a/app/models/chat_name.rb
+++ b/app/models/chat_name.rb
@@ -3,7 +3,9 @@
class ChatName < ApplicationRecord
LAST_USED_AT_INTERVAL = 1.hour
- belongs_to :integration
+ 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 1e70dd171ed..627604ec26c 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -18,7 +18,7 @@ module Ci
belongs_to :runner
belongs_to :trigger_request
belongs_to :erased_by, class_name: 'User'
- belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id
+ belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id, inverse_of: :builds
RUNNER_FEATURES = {
upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? },
@@ -35,8 +35,8 @@ module Ci
has_one :deployment, as: :deployable, class_name: 'Deployment', inverse_of: :deployable
has_one :pending_state, class_name: 'Ci::BuildPendingState', foreign_key: :build_id, inverse_of: :build
- has_one :queuing_entry, class_name: 'Ci::PendingBuild', foreign_key: :build_id
- has_one :runtime_metadata, class_name: 'Ci::RunningBuild', foreign_key: :build_id
+ has_one :queuing_entry, class_name: 'Ci::PendingBuild', foreign_key: :build_id, inverse_of: :build
+ has_one :runtime_metadata, class_name: 'Ci::RunningBuild', foreign_key: :build_id, inverse_of: :build
has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id, inverse_of: :build
has_many :report_results, class_name: 'Ci::BuildReportResult', foreign_key: :build_id, inverse_of: :build
has_one :namespace, through: :project
@@ -47,7 +47,7 @@ module Ci
# Details: https://gitlab.com/gitlab-org/gitlab/-/issues/24644#note_689472685
has_many :job_artifacts, class_name: 'Ci::JobArtifact', foreign_key: :job_id, dependent: :destroy, inverse_of: :job # rubocop:disable Cop/ActiveRecordDependent
has_many :job_variables, class_name: 'Ci::JobVariable', foreign_key: :job_id, inverse_of: :job
- has_many :sourced_pipelines, class_name: 'Ci::Sources::Pipeline', foreign_key: :source_job_id
+ has_many :sourced_pipelines, class_name: 'Ci::Sources::Pipeline', foreign_key: :source_job_id, inverse_of: :build
has_many :pages_deployments, foreign_key: :ci_build_id, inverse_of: :ci_build
@@ -55,7 +55,9 @@ module Ci
has_one :"job_artifacts_#{key}", -> { where(file_type: value) }, class_name: 'Ci::JobArtifact', foreign_key: :job_id, inverse_of: :job
end
- has_one :runner_machine, through: :metadata, class_name: 'Ci::RunnerMachine'
+ has_one :runner_machine_build, class_name: 'Ci::RunnerMachineBuild', foreign_key: :build_id, inverse_of: :build,
+ autosave: true
+ has_one :runner_machine, through: :runner_machine_build, class_name: 'Ci::RunnerMachine'
has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, foreign_key: :build_id, inverse_of: :build
has_one :trace_metadata, class_name: 'Ci::BuildTraceMetadata', foreign_key: :build_id, inverse_of: :build
@@ -71,6 +73,7 @@ module Ci
delegate :gitlab_deploy_token, to: :project
delegate :harbor_integration, to: :project
delegate :apple_app_store_integration, to: :project
+ delegate :google_play_integration, to: :project
delegate :trigger_short_token, to: :trigger_request, allow_nil: true
delegate :ensure_persistent_ref, to: :pipeline
delegate :enable_debug_trace!, to: :metadata
@@ -132,7 +135,7 @@ module Ci
scope :eager_load_job_artifacts, -> { includes(:job_artifacts) }
scope :eager_load_tags, -> { includes(:tags) }
- scope :eager_load_for_archiving_trace, -> { includes(:project, :pending_state) }
+ scope :eager_load_for_archiving_trace, -> { preload(:project, :pending_state) }
scope :eager_load_everything, -> do
includes(
@@ -180,7 +183,9 @@ module Ci
acts_as_taggable
- add_authentication_token_field :token, encrypted: :required
+ add_authentication_token_field :token,
+ encrypted: :required,
+ format_with_prefix: :partition_id_prefix_in_16_bit_encode
after_save :stick_build_if_status_changed
@@ -600,6 +605,7 @@ module Ci
.concat(deploy_token_variables)
.concat(harbor_variables)
.concat(apple_app_store_variables)
+ .concat(google_play_variables)
end
end
@@ -650,6 +656,13 @@ module Ci
Gitlab::Ci::Variables::Collection.new(apple_app_store_integration.ci_variables)
end
+ def google_play_variables
+ return [] unless google_play_integration.try(:activated?)
+ return [] unless pipeline.protected_ref?
+
+ Gitlab::Ci::Variables::Collection.new(google_play_integration.ci_variables)
+ end
+
def features
{
trace_sections: true,
@@ -757,9 +770,7 @@ module Ci
end
def remove_token!
- if Feature.enabled?(:remove_job_token_on_completion, project)
- update!(token_encrypted: nil)
- end
+ update!(token_encrypted: nil)
end
# acts_as_taggable uses this method create/remove tags with contexts
@@ -802,7 +813,7 @@ module Ci
return unless project
return if user&.blocked?
- ActiveRecord::Associations::Preloader.new.preload([self], { runner: :tags })
+ ActiveRecord::Associations::Preloader.new(records: [self], associations: { runner: :tags }).call
project.execute_hooks(build_data.dup, :job_hooks) if project.has_active_hooks?(:job_hooks)
project.execute_integrations(build_data.dup, :job_hooks) if project.has_active_integrations?(:job_hooks)
@@ -1091,10 +1102,6 @@ module Ci
::Ci::PendingBuild.upsert_from_build!(self)
end
- def create_runtime_metadata!
- ::Ci::RunningBuild.upsert_shared_runner_build!(self)
- end
-
##
# We can have only one queuing entry or running build tracking entry,
# because there is a unique index on `build_id` in each table, but we need
@@ -1161,11 +1168,6 @@ module Ci
end
end
- override :format_token
- def format_token(token)
- "#{partition_id.to_s(16)}_#{token}"
- end
-
protected
def run_status_commit_hooks!
@@ -1308,6 +1310,10 @@ module Ci
).to_context]
)
end
+
+ def partition_id_prefix_in_16_bit_encode
+ "#{partition_id.to_s(16)}_"
+ end
end
end
diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb
index b294afd405d..4b2be446fe3 100644
--- a/app/models/ci/build_metadata.rb
+++ b/app/models/ci/build_metadata.rb
@@ -10,15 +10,17 @@ module Ci
include Presentable
include ChronicDurationAttribute
include Gitlab::Utils::StrongMemoize
+ include IgnorableColumns
self.table_name = 'p_ci_builds_metadata'
self.primary_key = 'id'
partitionable scope: :build
+ ignore_column :runner_machine_id, remove_with: '16.0', remove_after: '2023-04-22'
+
belongs_to :build, class_name: 'CommitStatus'
belongs_to :project
- belongs_to :runner_machine, class_name: 'Ci::RunnerMachine'
before_create :set_build_project
diff --git a/app/models/ci/build_pending_state.rb b/app/models/ci/build_pending_state.rb
index 3684dac06c7..966884ae158 100644
--- a/app/models/ci/build_pending_state.rb
+++ b/app/models/ci/build_pending_state.rb
@@ -3,7 +3,7 @@
class Ci::BuildPendingState < Ci::ApplicationRecord
include Ci::Partitionable
- belongs_to :build, class_name: 'Ci::Build', foreign_key: :build_id
+ belongs_to :build, class_name: 'Ci::Build', foreign_key: :build_id, inverse_of: :pending_state
partitionable scope: :build
diff --git a/app/models/ci/build_trace_chunk.rb b/app/models/ci/build_trace_chunk.rb
index 541a8b5bffa..03b59b19ef1 100644
--- a/app/models/ci/build_trace_chunk.rb
+++ b/app/models/ci/build_trace_chunk.rb
@@ -9,7 +9,7 @@ module Ci
include ::Gitlab::ExclusiveLeaseHelpers
include ::Gitlab::OptimisticLocking
- belongs_to :build, class_name: "Ci::Build", foreign_key: :build_id
+ belongs_to :build, class_name: "Ci::Build", foreign_key: :build_id, inverse_of: :trace_chunks
partitionable scope: :build
diff --git a/app/models/ci/catalog/listing.rb b/app/models/ci/catalog/listing.rb
new file mode 100644
index 00000000000..92464cb645f
--- /dev/null
+++ b/app/models/ci/catalog/listing.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Ci
+ module Catalog
+ class Listing
+ # This class is the SSoT to displaying the list of resources in the
+ # CI/CD Catalog given a namespace as a scope.
+ # This model is not directly backed by a table and joins catalog resources
+ # with projects to return relevant data.
+ def initialize(namespace, current_user)
+ raise ArgumentError, 'Namespace is not a root namespace' unless namespace.root?
+
+ @namespace = namespace
+ @current_user = current_user
+ end
+
+ def resources
+ Ci::Catalog::Resource
+ .joins(:project).includes(:project)
+ .merge(projects_in_namespace_visible_to_user)
+ end
+
+ private
+
+ attr_reader :namespace, :current_user
+
+ def projects_in_namespace_visible_to_user
+ Project
+ .in_namespace(namespace.self_and_descendant_ids)
+ .public_or_visible_to_user(current_user)
+ end
+ end
+ end
+end
diff --git a/app/models/ci/catalog/resource.rb b/app/models/ci/catalog/resource.rb
new file mode 100644
index 00000000000..1b3dec5f54d
--- /dev/null
+++ b/app/models/ci/catalog/resource.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Ci
+ module Catalog
+ # This class represents a CI/CD Catalog resource.
+ # A Catalog resource is normally associated to a project.
+ # This model connects to the `main` database because of its
+ # dependency on the Project model and its need to join with that table
+ # in order to generate the CI/CD catalog.
+ class Resource < ::ApplicationRecord
+ self.table_name = 'catalog_resources'
+
+ belongs_to :project
+ end
+ end
+end
diff --git a/app/models/ci/daily_build_group_report_result.rb b/app/models/ci/daily_build_group_report_result.rb
index 598d1456a48..5ec54ee2983 100644
--- a/app/models/ci/daily_build_group_report_result.rb
+++ b/app/models/ci/daily_build_group_report_result.rb
@@ -4,9 +4,10 @@ module Ci
class DailyBuildGroupReportResult < Ci::ApplicationRecord
PARAM_TYPES = %w[coverage].freeze
- belongs_to :last_pipeline, class_name: 'Ci::Pipeline', foreign_key: :last_pipeline_id
+ belongs_to :last_pipeline, class_name: 'Ci::Pipeline', foreign_key: :last_pipeline_id,
+ inverse_of: :daily_build_group_report_results
belongs_to :project
- belongs_to :group
+ belongs_to :group, class_name: '::Group'
validates :data, json_schema: { filename: "daily_build_group_report_result_data" }
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 89a3d269a43..5a7860174ff 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -132,7 +132,7 @@ module Ci
PLAN_LIMIT_PREFIX = 'ci_max_artifact_size_'
belongs_to :project
- belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
+ belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id, inverse_of: :job_artifacts
mount_file_store_uploader JobArtifactUploader, skip_store_file: true
@@ -177,6 +177,8 @@ module Ci
where(file_type: self.erasable_file_types)
end
+ scope :non_trace, -> { where.not(file_type: [:trace]) }
+
scope :downloadable, -> { where(file_type: DOWNLOADABLE_TYPES) }
scope :unlocked, -> { joins(job: :pipeline).merge(::Ci::Pipeline.unlocked) }
scope :order_expired_asc, -> { order(expire_at: :asc) }
diff --git a/app/models/ci/job_token/scope.rb b/app/models/ci/job_token/scope.rb
index 20775077bd8..f389c642fd8 100644
--- a/app/models/ci/job_token/scope.rb
+++ b/app/models/ci/job_token/scope.rb
@@ -58,8 +58,7 @@ module Ci
end
def inbound_accessible?(accessed_project)
- # if the flag or setting is disabled any project is considered to be in scope.
- return true unless Feature.enabled?(:ci_inbound_job_token_scope, accessed_project)
+ # if the setting is disabled any project is considered to be in scope.
return true unless accessed_project.ci_inbound_job_token_scope_enabled?
inbound_linked_as_accessible?(accessed_project)
diff --git a/app/models/ci/job_variable.rb b/app/models/ci/job_variable.rb
index 998f0647ad5..573999995bc 100644
--- a/app/models/ci/job_variable.rb
+++ b/app/models/ci/job_variable.rb
@@ -7,7 +7,7 @@ module Ci
include Ci::RawVariable
include BulkInsertSafe
- belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
+ belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id, inverse_of: :job_variables
partitionable scope: :job
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index bd426e02b9c..2b0c79aab87 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -11,7 +11,6 @@ module Ci
include Gitlab::OptimisticLocking
include Gitlab::Utils::StrongMemoize
include AtomicInternalId
- include EnumWithNil
include Ci::HasRef
include ShaAttribute
include FromUnion
@@ -46,7 +45,7 @@ module Ci
belongs_to :project, inverse_of: :all_pipelines
belongs_to :user
- belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline'
+ belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline', inverse_of: :auto_canceled_pipelines
belongs_to :pipeline_schedule, class_name: 'Ci::PipelineSchedule'
belongs_to :merge_request, class_name: 'MergeRequest'
belongs_to :external_pull_request
@@ -67,14 +66,15 @@ module Ci
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :latest_statuses_ordered_by_stage, -> { latest.order(:stage_idx, :stage) }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :latest_statuses, -> { latest }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
- has_many :statuses_order_id_desc, -> { order_id_desc }, class_name: 'CommitStatus', foreign_key: :commit_id
+ has_many :statuses_order_id_desc, -> { order_id_desc }, class_name: 'CommitStatus', foreign_key: :commit_id,
+ inverse_of: :pipeline
has_many :processables, class_name: 'Ci::Processable', foreign_key: :commit_id, inverse_of: :pipeline
has_many :bridges, class_name: 'Ci::Bridge', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
has_many :generic_commit_statuses, foreign_key: :commit_id, inverse_of: :pipeline, class_name: 'GenericCommitStatus'
has_many :job_artifacts, through: :builds
has_many :build_trace_chunks, class_name: 'Ci::BuildTraceChunk', through: :builds, source: :trace_chunks
- has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
+ has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id, inverse_of: :pipeline # rubocop:disable Cop/ActiveRecordDependent
has_many :variables, class_name: 'Ci::PipelineVariable'
has_many :latest_builds, -> { latest.with_project_and_metadata }, foreign_key: :commit_id, inverse_of: :pipeline, class_name: 'Ci::Build'
has_many :downloadable_artifacts, -> do
@@ -86,17 +86,24 @@ module Ci
# Merge requests for which the current pipeline is running against
# the merge request's latest commit.
- has_many :merge_requests_as_head_pipeline, foreign_key: "head_pipeline_id", class_name: 'MergeRequest'
+ has_many :merge_requests_as_head_pipeline, foreign_key: :head_pipeline_id, class_name: 'MergeRequest',
+ inverse_of: :head_pipeline
+
has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
- has_many :failed_builds, -> { latest.failed }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
+ has_many :failed_builds, -> { latest.failed }, foreign_key: :commit_id, class_name: 'Ci::Build',
+ inverse_of: :pipeline
has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
- has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus'
+ has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus',
+ inverse_of: :pipeline
has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
has_many :scheduled_actions, -> { latest.scheduled_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
- has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id'
- has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id'
- has_many :sourced_pipelines, class_name: 'Ci::Sources::Pipeline', foreign_key: :source_pipeline_id
+ has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: :auto_canceled_by_id,
+ inverse_of: :auto_canceled_by
+ has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: :auto_canceled_by_id,
+ inverse_of: :auto_canceled_by
+ has_many :sourced_pipelines, class_name: 'Ci::Sources::Pipeline', foreign_key: :source_pipeline_id,
+ inverse_of: :source_pipeline
has_one :source_pipeline, class_name: 'Ci::Sources::Pipeline', inverse_of: :pipeline
@@ -114,7 +121,9 @@ module Ci
has_one :pipeline_metadata, class_name: 'Ci::PipelineMetadata', inverse_of: :pipeline
- has_many :daily_build_group_report_results, class_name: 'Ci::DailyBuildGroupReportResult', foreign_key: :last_pipeline_id
+ has_many :daily_build_group_report_results, class_name: 'Ci::DailyBuildGroupReportResult',
+ foreign_key: :last_pipeline_id, inverse_of: :last_pipeline
+
has_many :latest_builds_report_results, through: :latest_builds, source: :report_results
has_many :pipeline_artifacts, class_name: 'Ci::PipelineArtifact', inverse_of: :pipeline, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -143,9 +152,9 @@ module Ci
# We use `Enums::Ci::Pipeline.sources` here so that EE can more easily extend
# this `Hash` with new values.
- enum_with_nil source: Enums::Ci::Pipeline.sources
+ enum source: Enums::Ci::Pipeline.sources
- enum_with_nil config_source: Enums::Ci::Pipeline.config_sources
+ enum config_source: Enums::Ci::Pipeline.config_sources
# We use `Enums::Ci::Pipeline.failure_reasons` here so that EE can more easily
# extend this `Hash` with new values.
@@ -336,6 +345,22 @@ module Ci
AutoDevops::DisableWorker.perform_async(pipeline.id) if pipeline.auto_devops_source?
end
end
+
+ after_transition any => [:running, *::Ci::Pipeline.completed_statuses] do |pipeline|
+ project = pipeline&.project
+
+ next unless project
+ next unless Feature.enabled?(:pipeline_trigger_merge_status, project)
+
+ pipeline.run_after_commit do
+ next if pipeline.child?
+ next unless project.only_allow_merge_if_pipeline_succeeds?(inherit_group_setting: true)
+
+ pipeline.all_merge_requests.opened.each do |merge_request|
+ GraphqlTriggers.merge_request_merge_status_updated(merge_request)
+ end
+ end
+ end
end
scope :internal, -> { where(source: internal_sources) }
@@ -1282,7 +1307,7 @@ module Ci
types_to_collect = report_types.empty? ? ::Ci::JobArtifact::SECURITY_REPORT_FILE_TYPES : report_types
::Gitlab::Ci::Reports::Security::Reports.new(self).tap do |security_reports|
- latest_report_builds(reports_scope).each do |build|
+ latest_report_builds_in_self_and_project_descendants(reports_scope).includes(pipeline: { project: :route }).each do |build| # rubocop:disable Rails/FindEach
build.collect_security_reports!(security_reports, report_types: types_to_collect)
end
end
diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb
index 20ff07e88ba..83e6fa2f862 100644
--- a/app/models/ci/pipeline_schedule.rb
+++ b/app/models/ci/pipeline_schedule.rb
@@ -8,14 +8,15 @@ module Ci
include CronSchedulable
include Limitable
include EachBatch
+ include BatchNullifyDependentAssociations
self.limit_name = 'ci_pipeline_schedules'
self.limit_scope = :project
belongs_to :project
belongs_to :owner, class_name: 'User'
- has_one :last_pipeline, -> { order(id: :desc) }, class_name: 'Ci::Pipeline'
- has_many :pipelines
+ has_one :last_pipeline, -> { order(id: :desc) }, class_name: 'Ci::Pipeline', inverse_of: :pipeline_schedule
+ has_many :pipelines, dependent: :nullify # rubocop:disable Cop/ActiveRecordDependent
has_many :variables, class_name: 'Ci::PipelineScheduleVariable'
validates :cron, unless: :importing?, cron: true, presence: { unless: :importing? }
@@ -81,6 +82,12 @@ module Ci
def worker_cron_expression
Settings.cron_jobs['pipeline_schedule_worker']['cron']
end
+
+ def destroy
+ nullify_dependent_associations_in_batches
+
+ super
+ end
end
end
diff --git a/app/models/ci/resource_group.rb b/app/models/ci/resource_group.rb
index b788e4f58c1..a220aa7bb18 100644
--- a/app/models/ci/resource_group.rb
+++ b/app/models/ci/resource_group.rb
@@ -29,13 +29,19 @@ module Ci
partition_id: processable.partition_id
}
- resources.free.limit(1).update_all(attrs) > 0
+ success = resources.free.limit(1).update_all(attrs) > 0
+ log_event(success: success, processable: processable, action: "assign resource to processable")
+
+ success
end
def release_resource_from(processable)
attrs = { build_id: nil, partition_id: nil }
- resources.retained_by(processable).update_all(attrs) > 0
+ success = resources.retained_by(processable).update_all(attrs) > 0
+ log_event(success: success, processable: processable, action: "release resource from processable")
+
+ success
end
def upcoming_processables
@@ -72,5 +78,14 @@ module Ci
# belong to the same resource group are executed once at time.
self.resources.build if self.resources.empty?
end
+
+ def log_event(success:, processable:, action:)
+ Gitlab::Ci::ResourceGroups::Logger.build.info({
+ resource_group_id: self.id,
+ processable_id: processable.id,
+ message: "attempted to #{action}",
+ success: success
+ })
+ end
end
end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 09ac0fa69e7..6fefe95769b 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -17,7 +17,10 @@ module Ci
extend ::Gitlab::Utils::Override
- add_authentication_token_field :token, encrypted: :optional, expires_at: :compute_token_expiration
+ add_authentication_token_field :token,
+ encrypted: :optional,
+ expires_at: :compute_token_expiration,
+ format_with_prefix: :prefix_for_new_and_legacy_runner
enum access_level: {
not_protected: 0,
@@ -54,6 +57,9 @@ module Ci
# 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
+ # Only allow authentication token to be visible for a short while
+ REGISTRATION_AVAILABILITY_TIME = 1.hour
+
AVAILABLE_TYPES_LEGACY = %w[specific shared].freeze
AVAILABLE_TYPES = runner_types.keys.freeze
AVAILABLE_STATUSES = %w[active paused online offline never_contacted stale].freeze # TODO: Remove in %16.0: active, paused. Relevant issue: https://gitlab.com/gitlab-org/gitlab/-/issues/344648
@@ -81,8 +87,13 @@ module Ci
scope :active, -> (value = true) { where(active: value) }
scope :paused, -> { active(false) }
scope :online, -> { where('contacted_at > ?', online_contact_time_deadline) }
- scope :recent, -> { where('ci_runners.created_at >= :date OR ci_runners.contacted_at >= :date', date: stale_deadline) }
- scope :stale, -> { where('ci_runners.created_at < :date AND (ci_runners.contacted_at IS NULL OR ci_runners.contacted_at < :date)', date: stale_deadline) }
+ scope :recent, -> do
+ where('ci_runners.created_at >= :datetime OR ci_runners.contacted_at >= :datetime', datetime: stale_deadline)
+ end
+ scope :stale, -> do
+ where('ci_runners.created_at <= :datetime AND ' \
+ '(ci_runners.contacted_at IS NULL OR ci_runners.contacted_at <= :datetime)', datetime: stale_deadline)
+ end
scope :offline, -> { where(arel_table[:contacted_at].lteq(online_contact_time_deadline)) }
scope :never_contacted, -> { where(contacted_at: nil) }
scope :ordered, -> { order(id: :desc) }
@@ -185,6 +196,7 @@ module Ci
scope :order_token_expires_at_asc, -> { order(token_expires_at: :asc) }
scope :order_token_expires_at_desc, -> { order(token_expires_at: :desc) }
scope :with_tags, -> { preload(:tags) }
+ scope :with_creator, -> { preload(:creator) }
validate :tag_constraints
validates :access_level, presence: true
@@ -332,7 +344,7 @@ module Ci
def stale?
return false unless created_at
- [created_at, contacted_at].compact.max < self.class.stale_deadline
+ [created_at, contacted_at].compact.max <= self.class.stale_deadline
end
def status(legacy_mode = nil)
@@ -434,7 +446,7 @@ module Ci
ensure_runner_queue_value == value if value.present?
end
- def heartbeat(values)
+ def heartbeat(values, update_contacted_at: true)
##
# We can safely ignore writes performed by a runner heartbeat. We do
# not want to upgrade database connection proxy to use the primary
@@ -442,20 +454,18 @@ module Ci
#
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
values = values&.slice(:version, :revision, :platform, :architecture, :ip_address, :config, :executor) || {}
- values[:contacted_at] = Time.current
+ values[:contacted_at] = Time.current if update_contacted_at
if values.include?(:executor)
values[:executor_type] = EXECUTOR_NAME_TO_TYPES.fetch(values.delete(:executor), :unknown)
end
- cache_attributes(values)
+ new_version = values[:version]
+ schedule_runner_version_update(new_version) if new_version && values[:version] != version
- # We save data without validation, it will always change due to `contacted_at`
- if persist_cached_data?
- version_updated = values.include?(:version) && values[:version] != version
+ merge_cache_attributes(values)
- update_columns(values)
- schedule_runner_version_update if version_updated
- end
+ # We save data without validation, it will always change due to `contacted_at`
+ update_columns(values) if persist_cached_data?
end
end
@@ -488,17 +498,16 @@ module Ci
end
end
- override :format_token
- def format_token(token)
- return token if registration_token_registration_type?
-
- "#{CREATED_RUNNER_TOKEN_PREFIX}#{token}"
- end
-
def ensure_machine(system_xid, &blk)
RunnerMachine.safe_find_or_create_by!(runner_id: id, system_xid: system_xid.to_s, &blk) # rubocop: disable Performance/ActiveRecordSubtransactionMethods
end
+ def registration_available?
+ authenticated_user_registration_type? &&
+ created_at > REGISTRATION_AVAILABILITY_TIME.ago &&
+ !runner_machines.any?
+ end
+
private
scope :with_upgrade_status, ->(upgrade_status) do
@@ -594,10 +603,16 @@ module Ci
# TODO Remove in 16.0 when runners are known to send a system_id
# For now, heartbeats with version updates might result in two Sidekiq jobs being queued if a runner has a system_id
# This is not a problem since the jobs are deduplicated on the version
- def schedule_runner_version_update
- return unless version
+ def schedule_runner_version_update(new_version)
+ return unless new_version && Gitlab::Ci::RunnerReleases.instance.enabled?
+
+ Ci::Runners::ProcessRunnerVersionUpdateWorker.perform_async(new_version)
+ end
+
+ def prefix_for_new_and_legacy_runner
+ return if registration_token_registration_type?
- Ci::Runners::ProcessRunnerVersionUpdateWorker.perform_async(version)
+ CREATED_RUNNER_TOKEN_PREFIX
end
end
end
diff --git a/app/models/ci/runner_machine.rb b/app/models/ci/runner_machine.rb
index e52659a011f..8cf395aadb4 100644
--- a/app/models/ci/runner_machine.rb
+++ b/app/models/ci/runner_machine.rb
@@ -5,17 +5,14 @@ module Ci
include FromUnion
include RedisCacheable
include Ci::HasRunnerExecutor
- include IgnorableColumns
-
- ignore_column :machine_xid, remove_with: '15.11', remove_after: '2022-03-22'
# The `UPDATE_CONTACT_COLUMN_EVERY` defines how often the Runner Machine DB entry can be updated
- UPDATE_CONTACT_COLUMN_EVERY = 40.minutes..55.minutes
+ UPDATE_CONTACT_COLUMN_EVERY = (40.minutes)..(55.minutes)
belongs_to :runner
- has_many :build_metadata, class_name: 'Ci::BuildMetadata'
- has_many :builds, through: :build_metadata, class_name: 'Ci::Build'
+ has_many :runner_machine_builds, inverse_of: :runner_machine, class_name: 'Ci::RunnerMachineBuild'
+ has_many :builds, through: :runner_machine_builds, class_name: 'Ci::Build'
belongs_to :runner_version, inverse_of: :runner_machines, primary_key: :version, foreign_key: :version,
class_name: 'Ci::RunnerVersion'
@@ -44,7 +41,15 @@ module Ci
remove_duplicates: false).where(created_some_time_ago)
end
- def heartbeat(values)
+ def self.online_contact_time_deadline
+ Ci::Runner.online_contact_time_deadline
+ end
+
+ def self.stale_deadline
+ STALE_TIMEOUT.ago
+ end
+
+ def heartbeat(values, update_contacted_at: true)
##
# We can safely ignore writes performed by a runner heartbeat. We do
# not want to upgrade database connection proxy to use the primary
@@ -52,24 +57,40 @@ module Ci
#
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
values = values&.slice(:version, :revision, :platform, :architecture, :ip_address, :config, :executor) || {}
- values[:contacted_at] = Time.current
+ values[:contacted_at] = Time.current if update_contacted_at
if values.include?(:executor)
values[:executor_type] = Ci::Runner::EXECUTOR_NAME_TO_TYPES.fetch(values.delete(:executor), :unknown)
end
- version_changed = values.include?(:version) && values[:version] != version
-
- cache_attributes(values)
+ new_version = values[:version]
+ schedule_runner_version_update(new_version) if new_version && values[:version] != version
- schedule_runner_version_update if version_changed
+ merge_cache_attributes(values)
# We save data without validation, it will always change due to `contacted_at`
update_columns(values) if persist_cached_data?
end
end
+ def status
+ return :stale if stale?
+ return :never_contacted unless contacted_at
+
+ online? ? :online : :offline
+ end
+
private
+ def online?
+ contacted_at && contacted_at > self.class.online_contact_time_deadline
+ end
+
+ def stale?
+ return false unless created_at
+
+ [created_at, contacted_at].compact.max <= self.class.stale_deadline
+ end
+
def persist_cached_data?
# Use a random threshold to prevent beating DB updates.
contacted_at_max_age = Random.rand(UPDATE_CONTACT_COLUMN_EVERY)
@@ -79,10 +100,10 @@ module Ci
(Time.current - real_contacted_at) >= contacted_at_max_age
end
- def schedule_runner_version_update
- return unless version
+ def schedule_runner_version_update(new_version)
+ return unless new_version && Gitlab::Ci::RunnerReleases.instance.enabled?
- Ci::Runners::ProcessRunnerVersionUpdateWorker.perform_async(version)
+ Ci::Runners::ProcessRunnerVersionUpdateWorker.perform_async(new_version)
end
end
end
diff --git a/app/models/ci/runner_machine_build.rb b/app/models/ci/runner_machine_build.rb
new file mode 100644
index 00000000000..d4f2c403337
--- /dev/null
+++ b/app/models/ci/runner_machine_build.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Ci
+ class RunnerMachineBuild < Ci::ApplicationRecord
+ include Ci::Partitionable
+
+ self.table_name = :p_ci_runner_machine_builds
+ self.primary_key = :build_id
+
+ partitionable scope: :build, partitioned: true
+
+ belongs_to :build, inverse_of: :runner_machine_build, class_name: 'Ci::Build'
+ belongs_to :runner_machine, inverse_of: :runner_machine_builds, class_name: 'Ci::RunnerMachine'
+
+ validates :build, presence: true
+ validates :runner_machine, presence: true
+
+ scope :for_build, ->(build_id) { where(build_id: build_id) }
+
+ def self.pluck_build_id_and_runner_machine_id
+ select(:build_id, :runner_machine_id)
+ .pluck(:build_id, :runner_machine_id)
+ .to_h
+ end
+ end
+end
diff --git a/app/models/ci/runner_version.rb b/app/models/ci/runner_version.rb
index ec42f46b165..41e7a2b8e8a 100644
--- a/app/models/ci/runner_version.rb
+++ b/app/models/ci/runner_version.rb
@@ -3,9 +3,8 @@
module Ci
class RunnerVersion < Ci::ApplicationRecord
include EachBatch
- include EnumWithNil
- enum_with_nil status: {
+ enum status: {
not_processed: nil,
invalid_version: -1,
unavailable: 1,
diff --git a/app/models/ci/sources/pipeline.rb b/app/models/ci/sources/pipeline.rb
index 855e68d1db1..719d19f4169 100644
--- a/app/models/ci/sources/pipeline.rb
+++ b/app/models/ci/sources/pipeline.rb
@@ -10,6 +10,7 @@ module Ci
belongs_to :project, class_name: "::Project"
belongs_to :pipeline, class_name: "Ci::Pipeline", inverse_of: :source_pipeline
+ belongs_to :build, class_name: "Ci::Build", foreign_key: :source_job_id, inverse_of: :sourced_pipelines
belongs_to :source_project, class_name: "::Project", foreign_key: :source_project_id
belongs_to :source_job, class_name: "CommitStatus", foreign_key: :source_job_id
diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb
index 46a9e3f6494..02093bdf153 100644
--- a/app/models/ci/stage.rb
+++ b/app/models/ci/stage.rb
@@ -27,6 +27,7 @@ module Ci
has_many :processables, class_name: 'Ci::Processable', foreign_key: :stage_id, inverse_of: :ci_stage
has_many :builds, foreign_key: :stage_id, inverse_of: :ci_stage
has_many :bridges, foreign_key: :stage_id, inverse_of: :ci_stage
+ has_many :generic_commit_statuses, foreign_key: :stage_id, inverse_of: :ci_stage
scope :ordered, -> { order(position: :asc) }
scope :in_pipelines, ->(pipelines) { where(pipeline: pipelines) }
@@ -117,6 +118,7 @@ module Ci
end
end
+ # This will be removed with ci_remove_ensure_stage_service
def update_legacy_status
set_status(latest_stage_status.to_s)
end
@@ -150,6 +152,7 @@ module Ci
blocked? || skipped?
end
+ # This will be removed with ci_remove_ensure_stage_service
def latest_stage_status
statuses.latest.composite_status || 'skipped'
end
diff --git a/app/models/clusters/applications/crossplane.rb b/app/models/clusters/applications/crossplane.rb
deleted file mode 100644
index a7b4fb57149..00000000000
--- a/app/models/clusters/applications/crossplane.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- # DEPRECATED for removal in %14.0
- # See https://gitlab.com/groups/gitlab-org/-/epics/4280
- class Crossplane < ApplicationRecord
- VERSION = '0.4.1'
-
- self.table_name = 'clusters_applications_crossplane'
-
- include ::Clusters::Concerns::ApplicationCore
- include ::Clusters::Concerns::ApplicationStatus
- include ::Clusters::Concerns::ApplicationVersion
- include ::Clusters::Concerns::ApplicationData
-
- attribute :version, default: VERSION
- attribute :stack, default: ""
-
- validates :stack, presence: true
-
- def chart
- 'crossplane/crossplane'
- end
-
- def repository
- 'https://charts.crossplane.io/alpha'
- end
-
- def install_command
- helm_command_module::InstallCommand.new(
- name: 'crossplane',
- repository: repository,
- version: VERSION,
- rbac: cluster.platform_kubernetes_rbac?,
- chart: chart,
- files: files
- )
- end
-
- def values
- crossplane_values.to_yaml
- end
-
- private
-
- def crossplane_values
- {
- "clusterStacks" => {
- self.stack => {
- "deploy" => true
- }
- }
- }
- end
- end
- end
-end
diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb
index 64366594583..c8c043f3312 100644
--- a/app/models/clusters/applications/knative.rb
+++ b/app/models/clusters/applications/knative.rb
@@ -13,8 +13,6 @@ module Clusters
self.table_name = 'clusters_applications_knative'
- has_one :serverless_domain_cluster, class_name: '::Serverless::DomainCluster', foreign_key: 'clusters_applications_knative_id', inverse_of: :knative
-
include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion
@@ -49,8 +47,6 @@ module Clusters
scope :for_cluster, -> (cluster) { where(cluster: cluster) }
- has_one :pages_domain, through: :serverless_domain_cluster
-
def chart
'knative/knative'
end
@@ -140,16 +136,14 @@ module Clusters
@api_groups ||= YAML.safe_load(File.read(Rails.root.join(API_GROUPS_PATH)))
end
+ # Relied on application_prometheus which is now removed
def install_knative_metrics
- return [] unless cluster.application_prometheus&.available?
-
- [Gitlab::Kubernetes::KubectlCmd.apply_file(METRICS_CONFIG)]
+ []
end
+ # Relied on application_prometheus which is now removed
def delete_knative_istio_metrics
- return [] unless cluster.application_prometheus&.available?
-
- [Gitlab::Kubernetes::KubectlCmd.delete("--ignore-not-found", "-f", METRICS_CONFIG)]
+ []
end
end
end
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
deleted file mode 100644
index a076c871824..00000000000
--- a/app/models/clusters/applications/prometheus.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class Prometheus < ApplicationRecord
- include ::Clusters::Concerns::PrometheusClient
-
- VERSION = '10.4.1'
-
- self.table_name = 'clusters_applications_prometheus'
-
- include ::Clusters::Concerns::ApplicationCore
- include ::Clusters::Concerns::ApplicationStatus
- include ::Clusters::Concerns::ApplicationVersion
- include ::Clusters::Concerns::ApplicationData
- include AfterCommitQueue
-
- attribute :version, default: VERSION
-
- scope :preload_cluster_platform, -> { preload(cluster: [:platform_kubernetes]) }
-
- attr_encrypted :alert_manager_token,
- mode: :per_attribute_iv,
- key: Settings.attr_encrypted_db_key_base_32,
- algorithm: 'aes-256-gcm'
-
- after_initialize :set_alert_manager_token, if: :new_record?
-
- after_destroy do
- cluster.find_or_build_integration_prometheus.destroy
- end
-
- state_machine :status do
- after_transition any => [:installed, :externally_installed] do |application|
- application.cluster.find_or_build_integration_prometheus.update(enabled: true, alert_manager_token: application.alert_manager_token)
- end
-
- after_transition any => :updating do |application|
- application.update(last_update_started_at: Time.current)
- end
- end
-
- def managed_prometheus?
- !externally_installed? && !uninstalled?
- end
-
- def updated_since?(timestamp)
- last_update_started_at &&
- last_update_started_at > timestamp &&
- !update_errored?
- end
-
- def chart
- "#{name}/prometheus"
- end
-
- def repository
- 'https://gitlab-org.gitlab.io/cluster-integration/helm-stable-archive'
- end
-
- def install_command
- helm_command_module::InstallCommand.new(
- name: name,
- repository: repository,
- version: VERSION,
- rbac: cluster.platform_kubernetes_rbac?,
- chart: chart,
- files: files,
- postinstall: install_knative_metrics
- )
- end
-
- # Deprecated, to be removed in %14.0 as part of https://gitlab.com/groups/gitlab-org/-/epics/4280
- def patch_command(values)
- helm_command_module::PatchCommand.new(
- name: name,
- repository: repository,
- version: version,
- rbac: cluster.platform_kubernetes_rbac?,
- chart: chart,
- files: files_with_replaced_values(values)
- )
- end
-
- def uninstall_command
- helm_command_module::DeleteCommand.new(
- name: name,
- rbac: cluster.platform_kubernetes_rbac?,
- files: files,
- predelete: delete_knative_istio_metrics
- )
- end
-
- # Returns a copy of files where the values of 'values.yaml'
- # are replaced by the argument.
- #
- # See #values for the data format required
- def files_with_replaced_values(replaced_values)
- files.merge('values.yaml': replaced_values)
- end
-
- private
-
- def set_alert_manager_token
- self.alert_manager_token = SecureRandom.hex
- end
-
- def install_knative_metrics
- return [] unless cluster.application_knative_available?
-
- [Gitlab::Kubernetes::KubectlCmd.apply_file(Clusters::Applications::Knative::METRICS_CONFIG)]
- end
-
- def delete_knative_istio_metrics
- return [] unless cluster.application_knative_available?
-
- [
- Gitlab::Kubernetes::KubectlCmd.delete(
- "-f", Clusters::Applications::Knative::METRICS_CONFIG,
- "--ignore-not-found"
- )
- ]
- end
- end
- end
-end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index a35ea6ddb46..5cd11265808 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -14,8 +14,6 @@ module Clusters
APPLICATIONS = {
Clusters::Applications::Helm.application_name => Clusters::Applications::Helm,
Clusters::Applications::Ingress.application_name => Clusters::Applications::Ingress,
- Clusters::Applications::Crossplane.application_name => Clusters::Applications::Crossplane,
- Clusters::Applications::Prometheus.application_name => Clusters::Applications::Prometheus,
Clusters::Applications::Runner.application_name => Clusters::Applications::Runner,
Clusters::Applications::Jupyter.application_name => Clusters::Applications::Jupyter,
Clusters::Applications::Knative.application_name => Clusters::Applications::Knative
@@ -56,8 +54,6 @@ module Clusters
has_one_cluster_application :helm
has_one_cluster_application :ingress
- has_one_cluster_application :crossplane
- has_one_cluster_application :prometheus
has_one_cluster_application :runner
has_one_cluster_application :jupyter
has_one_cluster_application :knative
@@ -365,12 +361,6 @@ module Clusters
end
end
- def serverless_domain
- strong_memoize(:serverless_domain) do
- self.application_knative&.serverless_domain_cluster
- end
- end
-
def prometheus_adapter
integration_prometheus
end
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 165285b34b2..123ad0ebfaf 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -4,7 +4,6 @@ module Clusters
module Platforms
class Kubernetes < ApplicationRecord
include Gitlab::Kubernetes
- include EnumWithNil
include AfterCommitQueue
include ReactiveCaching
include NullifyIfBlank
@@ -63,7 +62,7 @@ module Clusters
alias_attribute :ca_pem, :ca_cert
- enum_with_nil authorization_type: {
+ enum authorization_type: {
unknown_authorization: nil,
rbac: 1,
abac: 2
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 4517b3ef216..ea90b4e4dda 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -206,7 +206,8 @@ class Commit
def self.link_reference_pattern
@link_reference_pattern ||=
- super("commit", /(?<commit>#{COMMIT_SHA_PATTERN})?(\.(?<extension>#{LINK_EXTENSION_PATTERN}))?/o)
+ compose_link_reference_pattern('commit',
+ /(?<commit>#{COMMIT_SHA_PATTERN})?(\.(?<extension>#{LINK_EXTENSION_PATTERN}))?/o)
end
def to_reference(from = nil, full: false)
diff --git a/app/models/commit_collection.rb b/app/models/commit_collection.rb
index 47ecdfa8574..eb7db0fc9b4 100644
--- a/app/models/commit_collection.rb
+++ b/app/models/commit_collection.rb
@@ -118,4 +118,21 @@ class CommitCollection
def next_page
@pagination.next_page
end
+
+ def load_tags
+ oids = commits.map(&:id)
+ references = repository.list_refs([Gitlab::Git::TAG_REF_PREFIX], pointing_at_oids: oids, peel_tags: true)
+ oid_to_references = references.group_by { |reference| reference.peeled_target.presence || reference.target }
+
+ return self if oid_to_references.empty?
+
+ commits.each do |commit|
+ grouped_references = oid_to_references[commit.id]
+ next unless grouped_references
+
+ commit.referenced_by = grouped_references.map(&:name)
+ end
+
+ self
+ end
end
diff --git a/app/models/commit_range.rb b/app/models/commit_range.rb
index 87029cb2033..90cdd267cbd 100644
--- a/app/models/commit_range.rb
+++ b/app/models/commit_range.rb
@@ -50,7 +50,7 @@ class CommitRange
end
def self.link_reference_pattern
- @link_reference_pattern ||= super("compare", /(?<commit_range>#{PATTERN})/o)
+ @link_reference_pattern ||= compose_link_reference_pattern('compare', /(?<commit_range>#{PATTERN})/o)
end
# Initialize a CommitRange
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 333a176b8f3..716be080851 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -6,17 +6,17 @@ class CommitStatus < Ci::ApplicationRecord
include Importable
include AfterCommitQueue
include Presentable
- include EnumWithNil
include BulkInsertableAssociations
include TaggableQueries
self.table_name = 'ci_builds'
+ self.primary_key = :id
partitionable scope: :pipeline
belongs_to :user
belongs_to :project
- belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id
- belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline'
+ belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id, inverse_of: :statuses
+ belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline', inverse_of: :auto_canceled_jobs
belongs_to :ci_stage, class_name: 'Ci::Stage', foreign_key: :stage_id
has_many :needs, class_name: 'Ci::BuildNeed', foreign_key: :build_id, inverse_of: :build
@@ -26,7 +26,7 @@ class CommitStatus < Ci::ApplicationRecord
enum scheduling_type: { stage: 0, dag: 1 }, _prefix: true
# We use `Enums::Ci::CommitStatus.failure_reasons` here so that EE can more easily
# extend this `Hash` with new values.
- enum_with_nil failure_reason: Enums::Ci::CommitStatus.failure_reasons
+ enum failure_reason: Enums::Ci::CommitStatus.failure_reasons
delegate :commit, to: :pipeline
delegate :sha, :short_sha, :before_sha, to: :pipeline
@@ -43,14 +43,6 @@ class CommitStatus < Ci::ApplicationRecord
scope :order_id_desc, -> { order(id: :desc) }
- scope :exclude_ignored, -> do
- # We want to ignore failed but allowed to fail jobs.
- #
- # TODO, we also skip ignored optional manual actions.
- where("allow_failure = ? OR status IN (?)",
- false, all_state_names - [:failed, :canceled, :manual])
- end
-
scope :latest, -> { where(retried: [false, nil]) }
scope :retried, -> { where(retried: true) }
scope :ordered, -> { order(:name) }
@@ -239,10 +231,6 @@ class CommitStatus < Ci::ApplicationRecord
name.to_s.sub(regex, '').strip
end
- def failed_but_allowed?
- allow_failure? && (failed? || canceled?)
- end
-
# Time spent running.
def duration
calculate_duration(started_at, finished_at)
diff --git a/app/models/concerns/analytics/cycle_analytics/stageable.rb b/app/models/concerns/analytics/cycle_analytics/stageable.rb
index caac4f31e1a..d1dd46883e3 100644
--- a/app/models/concerns/analytics/cycle_analytics/stageable.rb
+++ b/app/models/concerns/analytics/cycle_analytics/stageable.rb
@@ -7,8 +7,8 @@ module Analytics
include Gitlab::Utils::StrongMemoize
included do
- belongs_to :start_event_label, class_name: 'GroupLabel', optional: true
- belongs_to :end_event_label, class_name: 'GroupLabel', optional: true
+ belongs_to :start_event_label, class_name: 'Label', optional: true
+ belongs_to :end_event_label, class_name: 'Label', optional: true
belongs_to :stage_event_hash, class_name: 'Analytics::CycleAnalytics::StageEventHash', optional: true
validates :name, presence: true
@@ -119,10 +119,11 @@ module Analytics
end
def label_available_for_namespace?(label_id)
- subject = is_a?(::Analytics::CycleAnalytics::Stage) ? namespace : project.group
+ subject = namespace.is_a?(Namespaces::ProjectNamespace) ? namespace.project.group : namespace
return unless subject
- LabelsFinder.new(nil, { group_id: subject.id, include_ancestor_groups: true, only_group_labels: true })
+ LabelsFinder.new(nil,
+ { group_id: subject.id, include_ancestor_groups: true, only_group_labels: namespace.is_a?(Group) })
.execute(skip_authorization: true)
.id_in(label_id)
.exists?
diff --git a/app/models/concerns/atomic_internal_id.rb b/app/models/concerns/atomic_internal_id.rb
index 14be924f9da..ec4ee7985fe 100644
--- a/app/models/concerns/atomic_internal_id.rb
+++ b/app/models/concerns/atomic_internal_id.rb
@@ -61,6 +61,8 @@ module AtomicInternalId
AtomicInternalId.project_init(self)
when :group
AtomicInternalId.group_init(self)
+ when :namespace
+ AtomicInternalId.namespace_init(self)
else
# We require init here to retain the ability to recalculate in the absence of a
# InternalId record (we may delete records in `internal_ids` for example).
@@ -241,6 +243,16 @@ module AtomicInternalId
end
end
+ def self.namespace_init(klass, column_name = :iid)
+ ->(instance, scope) do
+ if instance
+ klass.where(namespace_id: instance.namespace_id).maximum(column_name)
+ elsif scope.present?
+ klass.where(**scope).maximum(column_name)
+ end
+ end
+ end
+
def internal_id_read_scope(scope)
association(scope).reader
end
diff --git a/app/models/concerns/cached_commit.rb b/app/models/concerns/cached_commit.rb
index 0fb72552dd5..8a53fec0612 100644
--- a/app/models/concerns/cached_commit.rb
+++ b/app/models/concerns/cached_commit.rb
@@ -14,4 +14,9 @@ module CachedCommit
def parent_ids
[]
end
+
+ # These are not saved
+ def referenced_by
+ []
+ end
end
diff --git a/app/models/concerns/cascading_namespace_setting_attribute.rb b/app/models/concerns/cascading_namespace_setting_attribute.rb
index 731729a1ed5..d0ee4f33ce6 100644
--- a/app/models/concerns/cascading_namespace_setting_attribute.rb
+++ b/app/models/concerns/cascading_namespace_setting_attribute.rb
@@ -57,11 +57,13 @@ module CascadingNamespaceSettingAttribute
# private methods
define_validator_methods(attribute)
+ define_attr_before_save(attribute)
define_after_update(attribute)
validate :"#{attribute}_changeable?"
validate :"lock_#{attribute}_changeable?"
+ before_save :"before_save_#{attribute}", if: -> { will_save_change_to_attribute?(attribute) }
after_update :"clear_descendant_#{attribute}_locks", if: -> { saved_change_to_attribute?("lock_#{attribute}", to: true) }
end
end
@@ -92,13 +94,26 @@ module CascadingNamespaceSettingAttribute
def define_attr_writer(attribute)
define_method("#{attribute}=") do |value|
- return value if value == cascaded_ancestor_value(attribute)
+ return value if read_attribute(attribute).nil? && to_bool(value) == cascaded_ancestor_value(attribute)
clear_memoization(attribute)
super(value)
end
end
+ def define_attr_before_save(attribute)
+ # rubocop:disable GitlabSecurity/PublicSend
+ define_method("before_save_#{attribute}") do
+ new_value = public_send(attribute)
+ if public_send("#{attribute}_was").nil? && new_value == cascaded_ancestor_value(attribute)
+ write_attribute(attribute, nil)
+ end
+ end
+ # rubocop:enable GitlabSecurity/PublicSend
+
+ private :"before_save_#{attribute}"
+ end
+
def define_lock_attr_writer(attribute)
define_method("lock_#{attribute}=") do |value|
attr_value = public_send(attribute) # rubocop:disable GitlabSecurity/PublicSend
@@ -239,4 +254,8 @@ module CascadingNamespaceSettingAttribute
namespace.descendants.pluck(:id)
end
end
+
+ def to_bool(value)
+ ActiveModel::Type::Boolean.new.cast(value)
+ end
end
diff --git a/app/models/concerns/ci/has_status.rb b/app/models/concerns/ci/has_status.rb
index 9a04776f1c6..2971ecb04b8 100644
--- a/app/models/concerns/ci/has_status.rb
+++ b/app/models/concerns/ci/has_status.rb
@@ -13,7 +13,7 @@ module Ci
STOPPED_STATUSES = COMPLETED_STATUSES + BLOCKED_STATUS
ORDERED_STATUSES = %w[failed preparing pending running waiting_for_resource manual scheduled canceled success skipped created].freeze
PASSED_WITH_WARNINGS_STATUSES = %w[failed canceled].to_set.freeze
- EXCLUDE_IGNORED_STATUSES = %w[manual failed canceled].to_set.freeze
+ IGNORED_STATUSES = %w[manual].to_set.freeze
ALIVE_STATUSES = (ACTIVE_STATUSES + ['created']).freeze
CANCELABLE_STATUSES = (ALIVE_STATUSES + ['scheduled']).freeze
STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3,
@@ -23,6 +23,7 @@ module Ci
UnknownStatusError = Class.new(StandardError)
class_methods do
+ # This will be removed with ci_remove_ensure_stage_service
def composite_status
Gitlab::Ci::Status::Composite
.new(all, with_allow_failure: columns_hash.key?('allow_failure'))
diff --git a/app/models/concerns/ci/partitionable.rb b/app/models/concerns/ci/partitionable.rb
index d6ba0f4488f..28cc17432bc 100644
--- a/app/models/concerns/ci/partitionable.rb
+++ b/app/models/concerns/ci/partitionable.rb
@@ -36,6 +36,7 @@ module Ci
Ci::Pipeline
Ci::PendingBuild
Ci::RunningBuild
+ Ci::RunnerMachineBuild
Ci::PipelineVariable
Ci::Sources::Pipeline
Ci::Stage
@@ -70,8 +71,8 @@ module Ci
class_methods do
def partitionable(scope:, through: nil, partitioned: false)
handle_partitionable_through(through)
- handle_partitionable_dml(partitioned)
handle_partitionable_scope(scope)
+ handle_partitionable_ddl(partitioned)
end
private
@@ -85,13 +86,6 @@ module Ci
include Partitionable::Switch
end
- def handle_partitionable_dml(partitioned)
- define_singleton_method(:partitioned?) { partitioned }
- return unless partitioned
-
- include Partitionable::PartitionedFilter
- end
-
def handle_partitionable_scope(scope)
define_method(:partition_scope_value) do
strong_memoize(:partition_scope_value) do
@@ -102,6 +96,17 @@ module Ci
end
end
end
+
+ def handle_partitionable_ddl(partitioned)
+ return unless partitioned
+
+ include ::PartitionedTable
+
+ partitioned_by :partition_id,
+ strategy: :ci_sliding_list,
+ next_partition_if: proc { false },
+ detach_partition_if: proc { false }
+ end
end
end
end
diff --git a/app/models/concerns/ci/partitionable/partitioned_filter.rb b/app/models/concerns/ci/partitionable/partitioned_filter.rb
deleted file mode 100644
index 4adae3be26a..00000000000
--- a/app/models/concerns/ci/partitionable/partitioned_filter.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-module Ci
- module Partitionable
- # Used to patch the save, update, delete, destroy methods to use the
- # partition_id attributes for their SQL queries.
- module PartitionedFilter
- extend ActiveSupport::Concern
-
- if Rails::VERSION::MAJOR >= 7
- # These methods are updated in Rails 7 to use `_primary_key_constraints_hash`
- # by default, so this patch will no longer be required.
- #
- # rubocop:disable Gitlab/NoCodeCoverageComment
- # :nocov:
- raise "`#{__FILE__}` should be double checked" if Rails.env.test?
-
- warn "Update `#{__FILE__}`. Patches Rails internals for partitioning"
- # :nocov:
- # rubocop:enable Gitlab/NoCodeCoverageComment
- else
- def _update_row(attribute_names, attempted_action = "update")
- self.class._update_record(
- attributes_with_values(attribute_names),
- _primary_key_constraints_hash
- )
- end
-
- def _delete_row
- self.class._delete_record(_primary_key_constraints_hash)
- end
- end
-
- # Introduced in Rails 7, but updated to include `partition_id` filter.
- # https://github.com/rails/rails/blob/a4dbb153fd390ac31bb9808809e7ac4d3a2c5116/activerecord/lib/active_record/persistence.rb#L1031-L1033
- def _primary_key_constraints_hash
- { @primary_key => id_in_database, partition_id: partition_id } # rubocop:disable Gitlab/ModuleWithInstanceVariables
- end
- end
- end
-end
diff --git a/app/models/concerns/counter_attribute.rb b/app/models/concerns/counter_attribute.rb
index 58ea57962c5..d7ee533b53c 100644
--- a/app/models/concerns/counter_attribute.rb
+++ b/app/models/concerns/counter_attribute.rb
@@ -5,7 +5,7 @@
# after a period of time (10 minutes).
# When an attribute is incremented by a value, the increment is added
# to a Redis key. Then, FlushCounterIncrementsWorker will execute
-# `flush_increments_to_database!` which removes increments from Redis for a
+# `commit_increment!` which removes increments from Redis for a
# given model attribute and updates the values in the database.
#
# @example:
@@ -29,8 +29,24 @@
# counter_attribute :conditional_one, if: -> { |object| object.use_counter_attribute? }
# end
#
+# The `counter_attribute` by default will return last persisted value.
+# It's possible to always return accurate (real) value instead by using `returns_current: true`.
+# While doing this the `counter_attribute` will overwrite attribute accessor to fetch
+# the buffered information added to the last persisted value. This will incur cost a Redis call per attribute fetched.
+#
+# @example:
+#
+# class ProjectStatistics
+# include CounterAttribute
+#
+# counter_attribute :commit_count, returns_current: true
+# end
+#
+# in that case
+# model.commit_count => persisted value + buffered amount to be added
+#
# To increment the counter we can use the method:
-# increment_counter(:commit_count, 3)
+# increment_amount(:commit_count, 3)
#
# This method would determine whether it would increment the counter using Redis,
# or fallback to legacy increment on ActiveRecord counters.
@@ -50,11 +66,22 @@ module CounterAttribute
include Gitlab::Utils::StrongMemoize
class_methods do
- def counter_attribute(attribute, if: nil)
+ def counter_attribute(attribute, if: nil, returns_current: false)
counter_attributes << {
attribute: attribute,
- if_proc: binding.local_variable_get(:if) # can't read `if` directly
+ if_proc: binding.local_variable_get(:if), # can't read `if` directly
+ returns_current: returns_current
}
+
+ if returns_current
+ define_method(attribute) do
+ current_counter(attribute)
+ end
+ end
+
+ define_method("increment_#{attribute}") do |amount|
+ increment_amount(attribute, amount)
+ end
end
def counter_attributes
@@ -87,6 +114,15 @@ module CounterAttribute
end
end
+ def increment_amount(attribute, amount)
+ counter = Gitlab::Counters::Increment.new(amount: amount)
+ increment_counter(attribute, counter)
+ end
+
+ def current_counter(attribute)
+ read_attribute(attribute) + counter(attribute).get
+ end
+
def increment_counter(attribute, increment)
return if increment.amount == 0
@@ -172,7 +208,8 @@ module CounterAttribute
Gitlab::AppLogger.info(
message: 'Acquiring lease for project statistics update',
- project_statistics_id: id,
+ model: self.class.name,
+ model_id: id,
project_id: project.id,
**log_fields,
**Gitlab::ApplicationContext.current
@@ -184,7 +221,8 @@ module CounterAttribute
rescue Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError
Gitlab::AppLogger.warn(
message: 'Concurrent project statistics update detected',
- project_statistics_id: id,
+ model: self.class.name,
+ model_id: id,
project_id: project.id,
**log_fields,
**Gitlab::ApplicationContext.current
diff --git a/app/models/concerns/each_batch.rb b/app/models/concerns/each_batch.rb
index dbc0887dc97..79fb81e7820 100644
--- a/app/models/concerns/each_batch.rb
+++ b/app/models/concerns/each_batch.rb
@@ -161,5 +161,81 @@ module EachBatch
break unless stop
end
end
+
+ # Iterates over the relation and counts the rows. The counting
+ # logic is combined with the iteration query which saves one query
+ # compared to a standard each_batch approach.
+ #
+ # Basic usage:
+ # count, _last_value = Project.each_batch_count
+ #
+ # The counting can be stopped by passing a block and making the last statement true.
+ # Example:
+ #
+ # query_count = 0
+ # count, last_value = Project.each_batch_count do
+ # query_count += 1
+ # query_count == 5 # stop counting after 5 loops
+ # end
+ #
+ # Resume where the previous counting has stopped:
+ #
+ # count, last_value = Project.each_batch_count(last_count: count, last_value: last_value)
+ #
+ # Another example, counting issues in project:
+ #
+ # project = Project.find(1)
+ # count, _ = project.issues.each_batch_count(column: :iid)
+ def each_batch_count(of: 1000, column: :id, last_count: 0, last_value: nil)
+ arel_table = self.arel_table
+ window = Arel::Nodes::Window.new.order(arel_table[column])
+ last_value_column = Arel::Nodes::NamedFunction
+ .new('LAST_VALUE', [arel_table[column]])
+ .over(window)
+ .as(column.to_s)
+
+ loop do
+ count_column = Arel::Nodes::Addition
+ .new(Arel::Nodes::NamedFunction.new('ROW_NUMBER', []).over(window), last_count)
+ .as('count')
+
+ projections = [count_column, last_value_column]
+ scope = limit(1).offset(of - 1)
+ scope = scope.where(arel_table[column].gt(last_value)) if last_value
+ new_count, last_value = scope.pick(*projections)
+
+ # When reaching the last batch the offset query might return no data, to address this
+ # problem, we invoke a specialized query that takes the last row out of the resultset.
+ # We could do this for each batch, however it would add unnecessary overhead to all
+ # queries.
+ if new_count.nil?
+ inner_query = scope
+ .select(*projections)
+ .limit(nil)
+ .offset(nil)
+ .arel
+ .as(quoted_table_name)
+
+ new_count, last_value =
+ unscoped
+ .from(inner_query)
+ .order(count: :desc)
+ .limit(1)
+ .pick(:count, column)
+
+ last_count = new_count if new_count
+ last_value = nil
+ break
+ end
+
+ last_count = new_count
+
+ if block_given?
+ should_break = yield(last_count, last_value)
+ break if should_break
+ end
+ end
+ [last_count, last_value]
+ end
end
end
diff --git a/app/models/concerns/enum_with_nil.rb b/app/models/concerns/enum_with_nil.rb
deleted file mode 100644
index c66942025d7..00000000000
--- a/app/models/concerns/enum_with_nil.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-module EnumWithNil
- extend ActiveSupport::Concern
-
- included do
- def self.enum_with_nil(definitions)
- # use original `enum` to auto-define all methods
- enum(definitions)
-
- # override auto-defined methods only for the
- # key which uses nil value
- definitions.each do |name, values|
- # E.g. for enum_with_nil failure_reason: { unknown_failure: nil }
- # this overrides auto-generated method `failure_reason`
- define_method(name) do
- orig = super()
-
- return orig unless orig.nil?
-
- self.class.public_send(name.to_s.pluralize).key(nil) # rubocop:disable GitlabSecurity/PublicSend
- end
- end
- end
- end
-end
diff --git a/app/models/concerns/has_unique_internal_users.rb b/app/models/concerns/has_unique_internal_users.rb
index 4d60cfa03b0..25b56f6d70f 100644
--- a/app/models/concerns/has_unique_internal_users.rb
+++ b/app/models/concerns/has_unique_internal_users.rb
@@ -28,7 +28,7 @@ module HasUniqueInternalUsers
existing_user = uncached { scope.first }
return existing_user if existing_user.present?
- uniquify = Uniquify.new
+ uniquify = Gitlab::Utils::Uniquify.new
username = uniquify.string(username) { |s| User.find_by_username(s) }
diff --git a/app/models/concerns/has_user_type.rb b/app/models/concerns/has_user_type.rb
index b02c95c9662..0b1c6780db8 100644
--- a/app/models/concerns/has_user_type.rb
+++ b/app/models/concerns/has_user_type.rb
@@ -14,8 +14,10 @@ module HasUserType
migration_bot: 7,
security_bot: 8,
automation_bot: 9,
+ security_policy_bot: 10, # Currently not in use. See https://gitlab.com/gitlab-org/gitlab/-/issues/384174
admin_bot: 11,
- suggested_reviewers_bot: 12
+ suggested_reviewers_bot: 12,
+ service_account: 13
}.with_indifferent_access.freeze
BOT_USER_TYPES = %w[
@@ -26,11 +28,15 @@ module HasUserType
migration_bot
security_bot
automation_bot
+ security_policy_bot
admin_bot
suggested_reviewers_bot
+ service_account
].freeze
- NON_INTERNAL_USER_TYPES = %w[human project_bot service_user].freeze
+ # `service_account` allows instance/namespaces to configure a user for external integrations/automations
+ # `service_user` is an internal, `gitlab-com`-specific user type for integrations like suggested reviewers
+ NON_INTERNAL_USER_TYPES = %w[human project_bot service_user service_account].freeze
INTERNAL_USER_TYPES = (USER_TYPES.keys - NON_INTERNAL_USER_TYPES).freeze
included do
@@ -53,10 +59,8 @@ module HasUserType
BOT_USER_TYPES.include?(user_type)
end
- # The explicit check for project_bot will be removed with Bot Categorization
- # Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/213945
def internal?
- ghost? || (bot? && !project_bot?)
+ INTERNAL_USER_TYPES.include?(user_type)
end
def redacted_name(viewing_user)
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 50696c7b5e1..c1c1691e424 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -640,10 +640,6 @@ module Issuable
false
end
- def ensure_metrics
- self.metrics || create_metrics
- end
-
##
# Overridden in MergeRequest
#
@@ -658,6 +654,10 @@ module Issuable
{ name: name, subject: self }
end
+
+ def supports_health_status?
+ false
+ end
end
Issuable.prepend_mod_with('Issuable')
diff --git a/app/models/concerns/noteable.rb b/app/models/concerns/noteable.rb
index 7addcf9e2ec..0333cfc5f9e 100644
--- a/app/models/concerns/noteable.rb
+++ b/app/models/concerns/noteable.rb
@@ -169,6 +169,7 @@ module Noteable
def expire_note_etag_cache
return unless discussions_rendered_on_frontend?
return unless etag_caching_enabled?
+ return unless project.present?
Gitlab::EtagCaching::Store.new.touch(note_etag_key)
end
diff --git a/app/models/concerns/packages/debian/component_file.rb b/app/models/concerns/packages/debian/component_file.rb
index 77409549e85..5905670227c 100644
--- a/app/models/concerns/packages/debian/component_file.rb
+++ b/app/models/concerns/packages/debian/component_file.rb
@@ -88,6 +88,10 @@ module Packages
end
end
+ def empty?
+ size == 0
+ end
+
private
def extension
diff --git a/app/models/concerns/partitioned_table.rb b/app/models/concerns/partitioned_table.rb
index f95f9dd8ad7..c322a736e79 100644
--- a/app/models/concerns/partitioned_table.rb
+++ b/app/models/concerns/partitioned_table.rb
@@ -8,7 +8,8 @@ module PartitionedTable
PARTITIONING_STRATEGIES = {
monthly: Gitlab::Database::Partitioning::MonthlyStrategy,
- sliding_list: Gitlab::Database::Partitioning::SlidingListStrategy
+ sliding_list: Gitlab::Database::Partitioning::SlidingListStrategy,
+ ci_sliding_list: Gitlab::Database::Partitioning::CiSlidingListStrategy
}.freeze
def partitioned_by(partitioning_key, strategy:, **kwargs)
diff --git a/app/models/concerns/redis_cacheable.rb b/app/models/concerns/redis_cacheable.rb
index f1d29ad5a90..460cb529715 100644
--- a/app/models/concerns/redis_cacheable.rb
+++ b/app/models/concerns/redis_cacheable.rb
@@ -33,6 +33,14 @@ module RedisCacheable
clear_memoization(:cached_attributes)
end
+ def merge_cache_attributes(values)
+ existing_attributes = Hash(cached_attributes)
+ merged_attributes = existing_attributes.merge(values.symbolize_keys)
+ return if merged_attributes == existing_attributes
+
+ cache_attributes(merged_attributes)
+ end
+
private
def cache_attribute_key
diff --git a/app/models/concerns/referable.rb b/app/models/concerns/referable.rb
index 9a17131c91c..5303d110078 100644
--- a/app/models/concerns/referable.rb
+++ b/app/models/concerns/referable.rb
@@ -76,7 +76,11 @@ module Referable
true
end
- def link_reference_pattern(route, pattern)
+ def link_reference_pattern
+ raise NotImplementedError, "#{self} does not implement #{__method__}"
+ end
+
+ def compose_link_reference_pattern(route, pattern)
%r{
(?<url>
#{Regexp.escape(Gitlab.config.gitlab.url)}
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index 262839a3fa6..d70aad4e9ae 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -99,39 +99,11 @@ module Routable
end
def full_name
- # We have to test for persistence as the cache key uses #updated_at
- return (route&.name || build_full_name) unless persisted? && Feature.enabled?(:cached_route_lookups, self, type: :ops)
-
- # Return the name as-is if the parent is missing
- return name if route.nil? && parent.nil? && name.present?
-
- # If the route is already preloaded, return directly, preventing an extra load
- return route.name if route_loaded? && route.present?
-
- # Similarly, we can allow the build if the parent is loaded
- return build_full_name if parent_loaded?
-
- Gitlab::Cache.fetch_once([cache_key, :full_name]) do
- route&.name || build_full_name
- end
+ full_attribute(:name)
end
def full_path
- # We have to test for persistence as the cache key uses #updated_at
- return (route&.path || build_full_path) unless persisted? && Feature.enabled?(:cached_route_lookups, self, type: :ops)
-
- # Return the path as-is if the parent is missing
- return path if route.nil? && parent.nil? && path.present?
-
- # If the route is already preloaded, return directly, preventing an extra load
- return route.path if route_loaded? && route.present?
-
- # Similarly, we can allow the build if the parent is loaded
- return build_full_path if parent_loaded?
-
- Gitlab::Cache.fetch_once([cache_key, :full_path]) do
- route&.path || build_full_path
- end
+ full_attribute(:path)
end
# Overriden in the Project model
@@ -163,6 +135,31 @@ module Routable
private
+ # rubocop: disable GitlabSecurity/PublicSend
+ def full_attribute(attribute)
+ attribute_from_route_or_self = ->(attribute) do
+ route&.public_send(attribute) || send("build_full_#{attribute}")
+ end
+
+ unless persisted? && Feature.enabled?(:cached_route_lookups, self, type: :ops)
+ return attribute_from_route_or_self.call(attribute)
+ end
+
+ # Return the attribute as-is if the parent is missing
+ return public_send(attribute) if route.nil? && parent.nil? && public_send(attribute).present?
+
+ # If the route is already preloaded, return directly, preventing an extra load
+ return route.public_send(attribute) if route_loaded? && route.present? && route.public_send(attribute)
+
+ # Similarly, we can allow the build if the parent is loaded
+ return send("build_full_#{attribute}") if parent_loaded?
+
+ Gitlab::Cache.fetch_once([cache_key, :"full_#{attribute}"]) do
+ attribute_from_route_or_self.call(attribute)
+ end
+ end
+ # rubocop: enable GitlabSecurity/PublicSend
+
def set_path_errors
route_path_errors = self.errors.delete(:"route.path")
route_path_errors&.each do |msg|
diff --git a/app/models/concerns/subscribable.rb b/app/models/concerns/subscribable.rb
index 5a10ea7a248..fe47393c554 100644
--- a/app/models/concerns/subscribable.rb
+++ b/app/models/concerns/subscribable.rb
@@ -27,8 +27,6 @@ module Subscribable
def lazy_subscription(user, project = nil)
return unless user
- # handle project and group labels as well as issuable subscriptions
- subscribable_type = self.class.ancestors.include?(Label) ? 'Label' : self.class.name
BatchLoader.for(id: id, subscribable_type: subscribable_type, project_id: project&.id).batch do |items, loader|
values = items.each_with_object({ ids: Set.new, subscribable_types: Set.new, project_ids: Set.new }) do |item, result|
result[:ids] << item[:id]
@@ -121,4 +119,15 @@ module Subscribable
subscriptions
.where(t[:project_id].eq(nil).or(t[:project_id].eq(project.try(:id))))
end
+
+ def subscribable_type
+ # handle project and group labels as well as issuable subscriptions
+ if self.class.ancestors.include?(Label)
+ 'Label'
+ elsif self.class.ancestors.include?(Issue)
+ 'Issue'
+ else
+ self.class.name
+ end
+ end
end
diff --git a/app/models/concerns/token_authenticatable_strategies/base.rb b/app/models/concerns/token_authenticatable_strategies/base.rb
index 2b677f37c89..d0085b60d98 100644
--- a/app/models/concerns/token_authenticatable_strategies/base.rb
+++ b/app/models/concerns/token_authenticatable_strategies/base.rb
@@ -31,9 +31,13 @@ module TokenAuthenticatableStrategies
result
end
- # Default implementation returns the token as-is
+ # If a `format_with_prefix` option is provided, it applies and returns the formatted token.
+ # Otherwise, default implementation returns the token as-is
def format_token(instance, token)
- instance.send("format_#{@token_field}", token) # rubocop:disable GitlabSecurity/PublicSend
+ prefix = prefix_for(instance)
+ prefixed_token = prefix ? "#{prefix}#{token}" : token
+
+ instance.send("format_#{@token_field}", prefixed_token) # rubocop:disable GitlabSecurity/PublicSend
end
def ensure_token(instance)
@@ -88,6 +92,17 @@ module TokenAuthenticatableStrategies
protected
+ def prefix_for(instance)
+ case prefix_option = options[:format_with_prefix]
+ when nil
+ nil
+ when Symbol
+ instance.send(prefix_option) # rubocop:disable GitlabSecurity/PublicSend
+ else
+ raise NotImplementedError
+ end
+ end
+
def write_new_token(instance)
new_token = generate_available_token
formatted_token = format_token(instance, new_token)
diff --git a/app/models/concerns/token_authenticatable_strategies/encrypted.rb b/app/models/concerns/token_authenticatable_strategies/encrypted.rb
index 1db88c27181..4b3b80437db 100644
--- a/app/models/concerns/token_authenticatable_strategies/encrypted.rb
+++ b/app/models/concerns/token_authenticatable_strategies/encrypted.rb
@@ -106,11 +106,7 @@ module TokenAuthenticatableStrategies
end
def matches_prefix?(instance, token)
- prefix = options[:prefix]
- prefix = prefix.call(instance) if prefix.is_a?(Proc)
- prefix = '' unless prefix.is_a?(String)
-
- token.start_with?(prefix)
+ !options[:require_prefix_for_validation] || token.start_with?(prefix_for(instance))
end
def token_set?(instance)
diff --git a/app/models/concerns/token_authenticatable_strategies/encryption_helper.rb b/app/models/concerns/token_authenticatable_strategies/encryption_helper.rb
index 447521ad8c1..5e77dfde397 100644
--- a/app/models/concerns/token_authenticatable_strategies/encryption_helper.rb
+++ b/app/models/concerns/token_authenticatable_strategies/encryption_helper.rb
@@ -20,8 +20,6 @@ module TokenAuthenticatableStrategies
end
def self.encrypt_token(plaintext_token)
- return Gitlab::CryptoHelper.aes256_gcm_encrypt(plaintext_token) unless Feature.enabled?(:dynamic_nonce, type: :ops)
-
iv = ::Digest::SHA256.hexdigest(plaintext_token).bytes.take(NONCE_SIZE).pack('c*')
token = Gitlab::CryptoHelper.aes256_gcm_encrypt(plaintext_token, nonce: iv)
"#{DYNAMIC_NONCE_IDENTIFIER}#{token}#{iv}"
diff --git a/app/models/concerns/uniquify.rb b/app/models/concerns/uniquify.rb
deleted file mode 100644
index 382e826ec58..00000000000
--- a/app/models/concerns/uniquify.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-# Uniquify
-#
-# Return a version of the given 'base' string that is unique
-# by appending a counter to it. Uniqueness is determined by
-# repeated calls to the passed block.
-#
-# You can pass an initial value for the counter, if not given
-# counting starts from 1.
-#
-# If `base` is a function/proc, we expect that calling it with a
-# candidate counter returns a string to test/return.
-class Uniquify
- def initialize(counter = nil)
- @counter = counter
- end
-
- def string(base)
- @base = base
-
- increment_counter! while yield(base_string)
- base_string
- end
-
- private
-
- def base_string
- if @base.respond_to?(:call)
- @base.call(@counter)
- else
- "#{@base}#{@counter}"
- end
- end
-
- def increment_counter!
- @counter ||= 0
- @counter += 1
- end
-end
diff --git a/app/models/concerns/web_hooks/auto_disabling.rb b/app/models/concerns/web_hooks/auto_disabling.rb
index 2cc17a6f185..05aaca32f35 100644
--- a/app/models/concerns/web_hooks/auto_disabling.rb
+++ b/app/models/concerns/web_hooks/auto_disabling.rb
@@ -4,7 +4,32 @@ module WebHooks
module AutoDisabling
extend ActiveSupport::Concern
+ ENABLED_HOOK_TYPES = %w[ProjectHook].freeze
+ MAX_FAILURES = 100
+ FAILURE_THRESHOLD = 3
+ EXCEEDED_FAILURE_THRESHOLD = FAILURE_THRESHOLD + 1
+ INITIAL_BACKOFF = 1.minute.freeze
+ MAX_BACKOFF = 1.day.freeze
+ BACKOFF_GROWTH_FACTOR = 2.0
+
+ class_methods do
+ def auto_disabling_enabled?
+ enabled_hook_types.include?(name) &&
+ Gitlab::SafeRequestStore.fetch(:auto_disabling_web_hooks) do
+ Feature.enabled?(:auto_disabling_web_hooks, type: :ops)
+ end
+ end
+
+ private
+
+ def enabled_hook_types
+ ENABLED_HOOK_TYPES
+ end
+ end
+
included do
+ delegate :auto_disabling_enabled?, to: :class, private: true
+
# A hook is disabled if:
#
# - we are no longer in the grace-perod (recent_failures > ?)
@@ -12,8 +37,10 @@ module WebHooks
# - disabled_until is nil (i.e. this was set by WebHook#fail!)
# - or disabled_until is in the future (i.e. this was set by WebHook#backoff!)
scope :disabled, -> do
+ return none unless auto_disabling_enabled?
+
where('recent_failures > ? AND (disabled_until IS NULL OR disabled_until >= ?)',
- WebHook::FAILURE_THRESHOLD, Time.current)
+ FAILURE_THRESHOLD, Time.current)
end
# A hook is executable if:
@@ -23,40 +50,81 @@ module WebHooks
# - disabled_until is nil (i.e. this was set by WebHook#fail!)
# - disabled_until is in the future (i.e. this was set by WebHook#backoff!)
scope :executable, -> do
+ return all unless auto_disabling_enabled?
+
where('recent_failures <= ? OR (recent_failures > ? AND (disabled_until IS NOT NULL) AND (disabled_until < ?))',
- WebHook::FAILURE_THRESHOLD, WebHook::FAILURE_THRESHOLD, Time.current)
+ FAILURE_THRESHOLD, FAILURE_THRESHOLD, Time.current)
end
end
def executable?
+ return true unless auto_disabling_enabled?
+
!temporarily_disabled? && !permanently_disabled?
end
def temporarily_disabled?
- return false if recent_failures <= WebHook::FAILURE_THRESHOLD
+ return false unless auto_disabling_enabled?
- disabled_until.present? && disabled_until >= Time.current
+ disabled_until.present? && disabled_until >= Time.current && recent_failures > FAILURE_THRESHOLD
end
def permanently_disabled?
- return false if disabled_until.present?
+ return false unless auto_disabling_enabled?
- recent_failures > WebHook::FAILURE_THRESHOLD
+ recent_failures > FAILURE_THRESHOLD && disabled_until.blank?
end
def disable!
- return if permanently_disabled?
+ return if !auto_disabling_enabled? || permanently_disabled?
- super
+ update_attribute(:recent_failures, EXCEEDED_FAILURE_THRESHOLD)
end
+ def enable!
+ return unless auto_disabling_enabled?
+ return if recent_failures == 0 && disabled_until.nil? && backoff_count == 0
+
+ assign_attributes(recent_failures: 0, disabled_until: nil, backoff_count: 0)
+ save(validate: false)
+ end
+
+ # Don't actually back-off until FAILURE_THRESHOLD failures have been seen
+ # we mark the grace-period using the recent_failures counter
def backoff!
- return if permanently_disabled? || (backoff_count >= WebHook::MAX_FAILURES && temporarily_disabled?)
+ return unless auto_disabling_enabled?
+ return if permanently_disabled? || (backoff_count >= MAX_FAILURES && temporarily_disabled?)
+
+ attrs = { recent_failures: next_failure_count }
- super
+ if recent_failures >= FAILURE_THRESHOLD
+ attrs[:backoff_count] = next_backoff_count
+ attrs[:disabled_until] = next_backoff.from_now
+ end
+
+ assign_attributes(attrs)
+ save(validate: false) if changed?
+ end
+
+ def failed!
+ return unless auto_disabling_enabled?
+ return unless recent_failures < MAX_FAILURES
+
+ assign_attributes(disabled_until: nil, backoff_count: 0, recent_failures: next_failure_count)
+ save(validate: false)
+ end
+
+ def next_backoff
+ return MAX_BACKOFF if backoff_count >= 8 # optimization to prevent expensive exponentiation and possible overflows
+
+ (INITIAL_BACKOFF * (BACKOFF_GROWTH_FACTOR**backoff_count))
+ .clamp(INITIAL_BACKOFF, MAX_BACKOFF)
+ .seconds
end
def alert_status
+ return :executable unless auto_disabling_enabled?
+
if temporarily_disabled?
:temporarily_disabled
elsif permanently_disabled?
@@ -65,5 +133,18 @@ module WebHooks
:executable
end
end
+
+ private
+
+ def next_failure_count
+ recent_failures.succ.clamp(1, MAX_FAILURES)
+ end
+
+ def next_backoff_count
+ backoff_count.succ.clamp(1, MAX_FAILURES)
+ end
end
end
+
+WebHooks::AutoDisabling.prepend_mod
+WebHooks::AutoDisabling::ClassMethods.prepend_mod
diff --git a/app/models/concerns/web_hooks/has_web_hooks.rb b/app/models/concerns/web_hooks/has_web_hooks.rb
index 161ce106b9b..2183cc3c44b 100644
--- a/app/models/concerns/web_hooks/has_web_hooks.rb
+++ b/app/models/concerns/web_hooks/has_web_hooks.rb
@@ -2,8 +2,6 @@
module WebHooks
module HasWebHooks
- extend ActiveSupport::Concern
-
WEB_HOOK_CACHE_EXPIRY = 1.hour
def any_hook_failed?
@@ -15,7 +13,7 @@ module WebHooks
end
def last_failure_redis_key
- "web_hooks:last_failure:project-#{id}"
+ "web_hooks:last_failure:#{self.class.name.underscore}-#{id}"
end
def get_web_hook_failure
@@ -42,5 +40,13 @@ module WebHooks
state
end
end
+
+ def last_webhook_failure
+ last_failure = Gitlab::Redis::SharedState.with do |redis|
+ redis.get(last_failure_redis_key)
+ end
+
+ DateTime.parse(last_failure) if last_failure
+ end
end
end
diff --git a/app/models/concerns/web_hooks/unstoppable.rb b/app/models/concerns/web_hooks/unstoppable.rb
deleted file mode 100644
index 26284fe3c36..00000000000
--- a/app/models/concerns/web_hooks/unstoppable.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-module WebHooks
- module Unstoppable
- extend ActiveSupport::Concern
-
- included do
- scope :executable, -> { all }
-
- scope :disabled, -> { none }
- end
-
- def executable?
- true
- end
-
- def temporarily_disabled?
- false
- end
-
- def permanently_disabled?
- false
- end
-
- def alert_status
- :executable
- end
- end
-end
diff --git a/app/models/container_registry/data_repair_detail.rb b/app/models/container_registry/data_repair_detail.rb
new file mode 100644
index 00000000000..09e617e69f5
--- /dev/null
+++ b/app/models/container_registry/data_repair_detail.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module ContainerRegistry
+ class DataRepairDetail < ApplicationRecord
+ self.table_name = 'container_registry_data_repair_details'
+ self.primary_key = :project_id
+
+ belongs_to :project, optional: false
+ end
+end
diff --git a/app/models/container_registry/event.rb b/app/models/container_registry/event.rb
index c4d06be8841..dd2675e17d8 100644
--- a/app/models/container_registry/event.rb
+++ b/app/models/container_registry/event.rb
@@ -8,7 +8,7 @@ module ContainerRegistry
PUSH_ACTION = 'push'
DELETE_ACTION = 'delete'
EVENT_TRACKING_CATEGORY = 'container_registry:notification'
- EVENT_PREFIX = "i_container_registry"
+ EVENT_PREFIX = 'i_container_registry'
ALLOWED_ACTOR_TYPES = %w(
personal_access_token
@@ -48,8 +48,12 @@ module ContainerRegistry
::Gitlab::Tracking.event(EVENT_TRACKING_CATEGORY, tracking_action)
- event = usage_data_event_for(tracking_action)
- ::Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event, values: originator.id) if event
+ if manifest_delete_event?
+ ::Gitlab::UsageDataCounters::ContainerRegistryEventCounter.count("#{EVENT_PREFIX}_delete_manifest")
+ else
+ event = usage_data_event_for(tracking_action)
+ ::Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event, values: originator.id) if event
+ end
end
private
@@ -122,9 +126,13 @@ module ContainerRegistry
end
end
+ def manifest_delete_event?
+ action_delete? && target_digest?
+ end
+
def update_project_statistics
return unless supported?
- return unless target_tag? || (action_delete? && target_digest?)
+ return unless target_tag? || manifest_delete_event?
return unless project
Rails.cache.delete(project.root_ancestor.container_repositories_size_cache_key)
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index 98ce981ad8e..b3cbe498551 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -69,7 +69,7 @@ class ContainerRepository < ApplicationRecord
scope :with_migration_import_started_at_nil_or_before, ->(timestamp) { where("COALESCE(migration_import_started_at, '01-01-1970') < ?", timestamp) }
scope :with_migration_pre_import_started_at_nil_or_before, ->(timestamp) { where("COALESCE(migration_pre_import_started_at, '01-01-1970') < ?", timestamp) }
scope :with_migration_pre_import_done_at_nil_or_before, ->(timestamp) { where("COALESCE(migration_pre_import_done_at, '01-01-1970') < ?", timestamp) }
- scope :with_stale_ongoing_cleanup, ->(threshold) { cleanup_ongoing.where('expiration_policy_started_at < ?', threshold) }
+ scope :with_stale_ongoing_cleanup, ->(threshold) { cleanup_ongoing.expiration_policy_started_at_nil_or_before(threshold) }
scope :with_stale_delete_at, ->(threshold) { where('delete_started_at < ?', threshold) }
scope :import_in_process, -> { where(migration_state: %w[pre_importing pre_import_done importing]) }
@@ -395,7 +395,7 @@ class ContainerRepository < ApplicationRecord
end
def migrated?
- (self.created_at && MIGRATION_PHASE_1_ENDED_AT < self.created_at) || import_done?
+ Gitlab.com?
end
def last_import_step_done_at
@@ -509,7 +509,11 @@ class ContainerRepository < ApplicationRecord
end
def start_expiration_policy!
- update!(expiration_policy_started_at: Time.zone.now, last_cleanup_deleted_tags_count: nil)
+ update!(
+ expiration_policy_started_at: Time.zone.now,
+ last_cleanup_deleted_tags_count: nil,
+ expiration_policy_cleanup_status: :cleanup_ongoing
+ )
end
def size
diff --git a/app/models/dependency_proxy/manifest.rb b/app/models/dependency_proxy/manifest.rb
index 5ad746e4cd1..11fe0503f50 100644
--- a/app/models/dependency_proxy/manifest.rb
+++ b/app/models/dependency_proxy/manifest.rb
@@ -12,6 +12,11 @@ class DependencyProxy::Manifest < ApplicationRecord
MAX_FILE_SIZE = 10.megabytes.freeze
DIGEST_HEADER = 'Docker-Content-Digest'
+ ACCEPTED_TYPES = [
+ ContainerRegistry::BaseClient::DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE,
+ ContainerRegistry::BaseClient::OCI_MANIFEST_V1_TYPE,
+ ContainerRegistry::BaseClient::OCI_DISTRIBUTION_INDEX_TYPE
+ ].freeze
validates :group, presence: true
validates :file, presence: true
diff --git a/app/models/dependency_proxy/registry.rb b/app/models/dependency_proxy/registry.rb
index 6492acf325a..3073dd59c7b 100644
--- a/app/models/dependency_proxy/registry.rb
+++ b/app/models/dependency_proxy/registry.rb
@@ -33,3 +33,5 @@ class DependencyProxy::Registry
end
end
end
+
+::DependencyProxy::Registry.prepend_mod
diff --git a/app/models/design_management/design.rb b/app/models/design_management/design.rb
index 317399e780a..cb6d4e72c80 100644
--- a/app/models/design_management/design.rb
+++ b/app/models/design_management/design.rb
@@ -13,6 +13,9 @@ module DesignManagement
include RelativePositioning
include Todoable
include Participable
+ include CacheMarkdownField
+
+ cache_markdown_field :description
belongs_to :project, inverse_of: :designs
belongs_to :issue
@@ -34,6 +37,7 @@ module DesignManagement
validates :project, :filename, presence: true
validates :issue, presence: true, unless: :importing?
validates :filename, uniqueness: { scope: :issue_id }, length: { maximum: 255 }
+ validates :description, length: { maximum: Gitlab::Database::MAX_TEXT_SIZE_LIMIT }
validate :validate_file_is_image
alias_attribute :title, :filename
@@ -43,7 +47,7 @@ module DesignManagement
# Pre-fetching scope to include the data necessary to construct a
# reference using `to_reference`.
- scope :for_reference, -> { includes(issue: [{ project: [:route, :namespace] }]) }
+ scope :for_reference, -> { includes(issue: [{ namespace: :project }, { project: [:route, :namespace] }]) }
# A design can be uniquely identified by issue_id and filename
# Takes one or more sets of composite IDs of the form:
@@ -174,7 +178,7 @@ module DesignManagement
(?<url_filename> #{valid_char}+ \. #{ext})
}x
- super(path_segment, filename_pattern)
+ compose_link_reference_pattern(path_segment, filename_pattern)
end
end
@@ -182,10 +186,6 @@ module DesignManagement
File.join(DesignManagement.designs_directory, "issue-#{issue.iid}", design.filename)
end
- def description
- ''
- end
-
def new_design?
strong_memoize(:new_design) { actions.none? }
end
diff --git a/app/models/draft_note.rb b/app/models/draft_note.rb
index 9f7977fce68..ffc04f9bf90 100644
--- a/app/models/draft_note.rb
+++ b/app/models/draft_note.rb
@@ -108,7 +108,7 @@ class DraftNote < ApplicationRecord
end
def self.preload_author(draft_notes)
- ActiveRecord::Associations::Preloader.new.preload(draft_notes, { author: :status })
+ ActiveRecord::Associations::Preloader.new(records: draft_notes, associations: { author: :status }).call
end
def diff_file
diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb
index 1c7a8d93e6e..c52f8a58c00 100644
--- a/app/models/error_tracking/project_error_tracking_setting.rb
+++ b/app/models/error_tracking/project_error_tracking_setting.rb
@@ -145,7 +145,7 @@ module ErrorTracking
ensure_issue_belongs_to_project!(issue_to_be_updated.project_id)
handle_exceptions do
- { updated: sentry_client.update_issue(opts) }
+ { updated: sentry_client.update_issue(**opts) }
end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 7e09280dfff..01e2c220dbe 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -7,7 +7,6 @@ class Group < Namespace
include AfterCommitQueue
include AccessRequestable
include Avatarable
- include Referable
include SelectForProjectAuthorization
include LoadedInGroupList
include GroupDescendant
@@ -21,7 +20,6 @@ class Group < Namespace
include ChronicDurationAttribute
include RunnerTokenExpirationInterval
include Todoable
- include IssueParent
extend ::Gitlab::Utils::Override
@@ -110,7 +108,10 @@ class Group < Namespace
has_one :import_state, class_name: 'GroupImportState', inverse_of: :group
+ has_many :application_setting, foreign_key: :instance_administrators_group_id, inverse_of: :instance_group
+
has_many :bulk_import_exports, class_name: 'BulkImports::Export', inverse_of: :group
+ has_many :bulk_import_entities, class_name: 'BulkImports::Entity', foreign_key: :namespace_id, inverse_of: :group
has_many :group_deploy_keys_groups, inverse_of: :group
has_many :group_deploy_keys, through: :group_deploy_keys_groups
@@ -162,7 +163,8 @@ class Group < Namespace
add_authentication_token_field :runners_token,
encrypted: -> { Feature.enabled?(:groups_tokens_optional_encryption) ? :optional : :required },
- prefix: RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX
+ format_with_prefix: :runners_token_prefix,
+ require_prefix_for_validation: true
after_create :post_create_hook
after_create -> { create_or_load_association(:group_feature) }
@@ -240,14 +242,6 @@ class Group < Namespace
end
end
- def reference_prefix
- User.reference_prefix
- end
-
- def reference_pattern
- User.reference_pattern
- end
-
# WARNING: This method should never be used on its own
# please do make sure the number of rows you are filtering is small
# enough for this query
@@ -364,10 +358,6 @@ class Group < Namespace
notification_settings.find { |n| n.notification_email.present? }&.notification_email
end
- def to_reference(_from = nil, target_project: nil, full: nil)
- "#{self.class.reference_prefix}#{full_path}"
- end
-
def web_url(only_path: nil)
Gitlab::UrlBuilder.build(self, only_path: only_path)
end
@@ -762,11 +752,6 @@ class Group < Namespace
ensure_runners_token!
end
- override :format_runners_token
- def format_runners_token(token)
- "#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}#{token}"
- end
-
def project_creation_level
super || ::Gitlab::CurrentSettings.default_project_creation
end
@@ -814,8 +799,10 @@ class Group < Namespace
end
def preload_shared_group_links
- preloader = ActiveRecord::Associations::Preloader.new
- preloader.preload(self, shared_with_group_links: [shared_with_group: :route])
+ ActiveRecord::Associations::Preloader.new(
+ records: [self],
+ associations: { shared_with_group_links: [shared_with_group: :route] }
+ ).call
end
def update_shared_runners_setting!(state)
@@ -1095,6 +1082,10 @@ class Group < Namespace
def enable_shared_runners!
update!(shared_runners_enabled: true)
end
+
+ def runners_token_prefix
+ RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX
+ end
end
Group.prepend_mod_with('Group')
diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb
index 8e9a74a68d0..695041f0247 100644
--- a/app/models/hooks/project_hook.rb
+++ b/app/models/hooks/project_hook.rb
@@ -2,7 +2,6 @@
class ProjectHook < WebHook
include TriggerableHooks
- include WebHooks::AutoDisabling
include Presentable
include Limitable
extend ::Gitlab::Utils::Override
diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb
index 6af70c249a0..453b986ca4d 100644
--- a/app/models/hooks/service_hook.rb
+++ b/app/models/hooks/service_hook.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
class ServiceHook < WebHook
- include WebHooks::Unstoppable
include Presentable
extend ::Gitlab::Utils::Override
diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb
index eaffe83cab3..3c7f0ef9ffc 100644
--- a/app/models/hooks/system_hook.rb
+++ b/app/models/hooks/system_hook.rb
@@ -2,7 +2,6 @@
class SystemHook < WebHook
include TriggerableHooks
- include WebHooks::Unstoppable
triggerable_hooks [
:repository_update_hooks,
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 819152a38c8..7e55ffe2e5e 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -2,15 +2,10 @@
class WebHook < ApplicationRecord
include Sortable
+ include WebHooks::AutoDisabling
InterpolationError = Class.new(StandardError)
- MAX_FAILURES = 100
- FAILURE_THRESHOLD = 3 # three strikes
- EXCEEDED_FAILURE_THRESHOLD = FAILURE_THRESHOLD + 1
- INITIAL_BACKOFF = 1.minute
- MAX_BACKOFF = 1.day
- BACKOFF_GROWTH_FACTOR = 2.0
SECRET_MASK = '************'
attr_encrypted :token,
@@ -78,46 +73,6 @@ class WebHook < ApplicationRecord
'user/project/integrations/webhooks'
end
- def next_backoff
- return MAX_BACKOFF if backoff_count >= 8 # optimization to prevent expensive exponentiation and possible overflows
-
- (INITIAL_BACKOFF * (BACKOFF_GROWTH_FACTOR**backoff_count))
- .clamp(INITIAL_BACKOFF, MAX_BACKOFF)
- .seconds
- end
-
- def disable!
- update_attribute(:recent_failures, EXCEEDED_FAILURE_THRESHOLD)
- end
-
- def enable!
- return if recent_failures == 0 && disabled_until.nil? && backoff_count == 0
-
- assign_attributes(recent_failures: 0, disabled_until: nil, backoff_count: 0)
- save(validate: false)
- end
-
- # Don't actually back-off until FAILURE_THRESHOLD failures have been seen
- # we mark the grace-period using the recent_failures counter
- def backoff!
- attrs = { recent_failures: next_failure_count }
-
- if recent_failures >= FAILURE_THRESHOLD
- attrs[:backoff_count] = next_backoff_count
- attrs[:disabled_until] = next_backoff.from_now
- end
-
- assign_attributes(attrs)
- save(validate: false) if changed?
- end
-
- def failed!
- return unless recent_failures < MAX_FAILURES
-
- assign_attributes(disabled_until: nil, backoff_count: 0, recent_failures: next_failure_count)
- save(validate: false)
- end
-
# @return [Boolean] Whether or not the WebHook is currently throttled.
def rate_limited?
rate_limiter.rate_limited?
@@ -179,14 +134,6 @@ class WebHook < ApplicationRecord
self.url_variables = {} if url_changed? && !encrypted_url_variables_changed?
end
- def next_failure_count
- recent_failures.succ.clamp(1, MAX_FAILURES)
- end
-
- def next_backoff_count
- backoff_count.succ.clamp(1, MAX_FAILURES)
- end
-
def initialize_url_variables
self.url_variables = {} if encrypted_url_variables.nil?
end
diff --git a/app/models/import_failure.rb b/app/models/import_failure.rb
index 109c0c82487..0ca99faeb71 100644
--- a/app/models/import_failure.rb
+++ b/app/models/import_failure.rb
@@ -6,6 +6,7 @@ class ImportFailure < ApplicationRecord
validates :project, presence: true, unless: :group
validates :group, presence: true, unless: :project
+ validates :external_identifiers, json_schema: { filename: "import_failure_external_identifiers" }
# Returns any `import_failures` for relations that were unrecoverable errors or failed after
# several retries. An import can be successful even if some relations failed to import correctly.
@@ -13,4 +14,8 @@ class ImportFailure < ApplicationRecord
scope :hard_failures_by_correlation_id, ->(correlation_id) {
where(correlation_id_value: correlation_id, retry_count: 0).order(created_at: :desc)
}
+
+ scope :failures_by_correlation_id, ->(correlation_id) {
+ where(correlation_id_value: correlation_id).order(created_at: :desc)
+ }
end
diff --git a/app/models/integration.rb b/app/models/integration.rb
index d3006f00ba1..860739fe5aa 100644
--- a/app/models/integration.rb
+++ b/app/models/integration.rb
@@ -21,13 +21,14 @@ class Integration < ApplicationRecord
asana assembla bamboo bugzilla buildkite campfire confluence custom_issue_tracker datadog discord
drone_ci emails_on_push ewm external_wiki hangouts_chat harbor irker jira
mattermost mattermost_slash_commands microsoft_teams packagist pipelines_email
- pivotaltracker prometheus pumble pushover redmine slack slack_slash_commands teamcity unify_circuit webex_teams youtrack zentao
+ pivotaltracker prometheus pumble pushover redmine slack slack_slash_commands squash_tm teamcity
+ unify_circuit webex_teams youtrack zentao
].freeze
# TODO Shimo is temporary disabled on group and instance-levels.
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/345677
PROJECT_SPECIFIC_INTEGRATION_NAMES = %w[
- apple_app_store jenkins shimo
+ apple_app_store google_play jenkins shimo
].freeze
# Fake integrations to help with local development.
diff --git a/app/models/integrations/apple_app_store.rb b/app/models/integrations/apple_app_store.rb
index 84185542939..34da4c0f4b8 100644
--- a/app/models/integrations/apple_app_store.rb
+++ b/app/models/integrations/apple_app_store.rb
@@ -7,10 +7,13 @@ module Integrations
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
+ SECTION_TYPE_APPLE_APP_STORE = 'apple_app_store'
+
with_options if: :activated? do
validates :app_store_issuer_id, presence: true, format: { with: ISSUER_ID_REGEX }
validates :app_store_key_id, presence: true, format: { with: KEY_ID_REGEX }
validates :app_store_private_key, presence: true, certificate_key: true
+ validates :app_store_private_key_file_name, presence: true
end
field :app_store_issuer_id,
@@ -24,13 +27,12 @@ module Integrations
title: -> { s_('AppleAppStore|The Apple App Store Connect Key ID.') },
is_secret: false
- field :app_store_private_key,
+ field :app_store_private_key_file_name,
section: SECTION_TYPE_CONNECTION,
- required: true,
- type: 'textarea',
- title: -> { s_('AppleAppStore|The Apple App Store Connect Private Key.') },
is_secret: false
+ field :app_store_private_key, api_only: true, is_secret: false
+
def title
'Apple App Store Connect'
end
@@ -69,7 +71,7 @@ module Integrations
def sections
[
{
- type: SECTION_TYPE_CONNECTION,
+ type: SECTION_TYPE_APPLE_APP_STORE,
title: s_('Integrations|Integration details'),
description: help
}
@@ -99,13 +101,11 @@ module Integrations
private
def client
- config = {
+ AppStoreConnect::Client.new(
issuer_id: app_store_issuer_id,
key_id: app_store_key_id,
private_key: app_store_private_key
- }
-
- AppStoreConnect::Client.new(config)
+ )
end
end
end
diff --git a/app/models/integrations/base_slack_notification.rb b/app/models/integrations/base_slack_notification.rb
index 7a2a91aa0d2..c83a559e0da 100644
--- a/app/models/integrations/base_slack_notification.rb
+++ b/app/models/integrations/base_slack_notification.rb
@@ -44,8 +44,6 @@ module Integrations
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(key, values: user_id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2)
-
optional_arguments = {
project: project,
namespace: group || project&.namespace
diff --git a/app/models/integrations/base_slash_commands.rb b/app/models/integrations/base_slash_commands.rb
index 619579a543a..7662da933ba 100644
--- a/app/models/integrations/base_slash_commands.rb
+++ b/app/models/integrations/base_slash_commands.rb
@@ -6,10 +6,6 @@ module Integrations
class BaseSlashCommands < Integration
attribute :category, default: 'chat'
- prop_accessor :token
-
- has_many :chat_names, foreign_key: :integration_id, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
-
def valid_token?(token)
self.respond_to?(:token) &&
self.token.present? &&
@@ -24,18 +20,6 @@ module Integrations
false
end
- def fields
- [
- {
- type: 'password',
- name: 'token',
- non_empty_password_title: s_('ProjectService|Enter new token'),
- non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'),
- placeholder: 'XXxxXXxxXXxxXXxxXXxxXXxx'
- }
- ]
- end
-
def trigger(params)
return unless valid_token?(params[:token])
diff --git a/app/models/integrations/campfire.rb b/app/models/integrations/campfire.rb
index 3f7fa1c51b2..9b837faf79b 100644
--- a/app/models/integrations/campfire.rb
+++ b/app/models/integrations/campfire.rb
@@ -68,7 +68,7 @@ module Integrations
def execute(data)
return unless supported_events.include?(data[:object_kind])
- message = build_message(data)
+ message = create_message(data)
speak(self.room, message, auth)
end
@@ -116,7 +116,7 @@ module Integrations
res.code == 200 ? res["rooms"] : []
end
- def build_message(push)
+ def create_message(push)
ref = Gitlab::Git.ref_name(push[:ref])
before = push[:before]
after = push[:after]
diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb
new file mode 100644
index 00000000000..8f1d2e7e1ec
--- /dev/null
+++ b/app/models/integrations/google_play.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Integrations
+ class GooglePlay < Integration
+ SECTION_TYPE_GOOGLE_PLAY = 'google_play'
+
+ with_options if: :activated? do
+ validates :service_account_key, presence: true, json_schema: {
+ filename: "google_service_account_key", parse_json: true
+ }
+ validates :service_account_key_file_name, presence: true
+ end
+
+ field :service_account_key_file_name,
+ section: SECTION_TYPE_CONNECTION,
+ required: true,
+ is_secret: false
+
+ field :service_account_key, api_only: true, is_secret: false
+
+ def title
+ s_('GooglePlay|Google Play')
+ end
+
+ def description
+ s_('GooglePlay|Use GitLab to build and release an app in Google Play.')
+ end
+
+ def help
+ variable_list = [
+ '<code>SUPPLY_JSON_KEY_DATA</code>'
+ ]
+
+ # rubocop:disable Layout/LineLength
+ texts = [
+ s_("Use the Google Play integration to connect to Google Play with fastlane in CI/CD pipelines."),
+ s_("After you enable the integration, the following protected variable is created for CI/CD use:"),
+ variable_list.join('<br>'),
+ s_(format("To generate a Google Play service account key and use this integration, see the <a href='%{url}' target='_blank'>integration documentation</a>.", url: "#")).html_safe
+ ]
+ # rubocop:enable Layout/LineLength
+
+ texts.join('<br><br>'.html_safe)
+ end
+
+ def self.to_param
+ 'google_play'
+ end
+
+ def self.supported_events
+ []
+ end
+
+ def sections
+ [
+ {
+ type: SECTION_TYPE_GOOGLE_PLAY,
+ title: s_('Integrations|Integration details'),
+ description: help
+ }
+ ]
+ end
+
+ def test(*_args)
+ client.fetch_access_token!
+ { success: true }
+ rescue Signet::AuthorizationError => error
+ { success: false, message: error }
+ end
+
+ def ci_variables
+ return [] unless activated?
+
+ [
+ { key: 'SUPPLY_JSON_KEY_DATA', value: service_account_key, masked: true, public: false }
+ ]
+ end
+
+ private
+
+ def client
+ Google::Auth::ServiceAccountCredentials.make_creds(
+ json_key_io: StringIO.new(service_account_key),
+ scope: ['https://www.googleapis.com/auth/androidpublisher']
+ )
+ end
+ end
+end
diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb
index d96a848c72e..a1cdd55ceae 100644
--- a/app/models/integrations/jira.rb
+++ b/app/models/integrations/jira.rb
@@ -391,8 +391,6 @@ module Integrations
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(key, values: user.id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2)
-
optional_arguments = {
project: project,
namespace: group || project&.namespace
diff --git a/app/models/integrations/mattermost_slash_commands.rb b/app/models/integrations/mattermost_slash_commands.rb
index 30a8ba973c1..f5079b9b907 100644
--- a/app/models/integrations/mattermost_slash_commands.rb
+++ b/app/models/integrations/mattermost_slash_commands.rb
@@ -4,7 +4,11 @@ module Integrations
class MattermostSlashCommands < BaseSlashCommands
include Ci::TriggersHelper
- prop_accessor :token
+ field :token,
+ type: 'password',
+ non_empty_password_title: -> { s_('ProjectService|Enter new token') },
+ non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
+ placeholder: ''
def testable?
false
@@ -37,10 +41,6 @@ module Integrations
[[], e.message]
end
- def chat_responder
- ::Gitlab::Chat::Responder::Mattermost
- end
-
private
def command(params)
diff --git a/app/models/integrations/slack_slash_commands.rb b/app/models/integrations/slack_slash_commands.rb
index 72e3c4a8cbc..343c8d68166 100644
--- a/app/models/integrations/slack_slash_commands.rb
+++ b/app/models/integrations/slack_slash_commands.rb
@@ -4,6 +4,12 @@ module Integrations
class SlackSlashCommands < BaseSlashCommands
include Ci::TriggersHelper
+ field :token,
+ type: 'password',
+ non_empty_password_title: -> { s_('ProjectService|Enter new token') },
+ non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
+ placeholder: ''
+
def title
'Slack slash commands'
end
@@ -23,10 +29,6 @@ module Integrations
end
end
- def chat_responder
- ::Gitlab::Chat::Responder::Slack
- end
-
private
def format(text)
diff --git a/app/models/integrations/squash_tm.rb b/app/models/integrations/squash_tm.rb
new file mode 100644
index 00000000000..e0a63b5ae6a
--- /dev/null
+++ b/app/models/integrations/squash_tm.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+module Integrations
+ class SquashTm < Integration
+ include HasWebHook
+
+ field :url,
+ placeholder: 'https://your-instance.squashcloud.io/squash/plugin/xsquash4gitlab/webhook/issue',
+ title: -> { s_('SquashTmIntegration|Squash TM webhook URL') },
+ exposes_secrets: true,
+ required: true
+
+ field :token,
+ type: 'password',
+ title: -> { s_('SquashTmIntegration|Secret token (optional)') },
+ non_empty_password_title: -> { s_('ProjectService|Enter new token') },
+ non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
+ required: false
+
+ with_options if: :activated? do
+ validates :url, presence: true, public_url: true
+ validates :token, length: { maximum: 255 }, allow_blank: true
+ end
+
+ def title
+ 'Squash TM'
+ end
+
+ def description
+ s_("SquashTmIntegration|Update Squash TM requirements when GitLab issues are modified.")
+ end
+
+ def help
+ docs_link = ActionController::Base.helpers.link_to(
+ _('Learn more.'),
+ Rails.application.routes.url_helpers.help_page_url('user/project/integrations/squash_tm'),
+ target: '_blank',
+ rel: 'noopener noreferrer'
+ )
+
+ Kernel.format(
+ s_('SquashTmIntegration|Update Squash TM requirements when GitLab issues are modified. %{docs_link}'),
+ { docs_link: docs_link.html_safe }
+ ).html_safe
+ end
+
+ def self.supported_events
+ %w[issue confidential_issue]
+ end
+
+ def self.to_param
+ 'squash_tm'
+ end
+
+ def self.default_test_event
+ 'issue'
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
+ execute_web_hook!(data, "#{data[:object_kind]} Hook")
+ end
+
+ def test(data)
+ result = execute_web_hook!(data, "Test Configuration Hook")
+
+ { success: result.payload[:http_status] == 200, result: result.message }
+ rescue StandardError => error
+ { success: false, result: error.message }
+ end
+
+ override :hook_url
+ def hook_url
+ format("#{url}%s", ('?token={token}' unless token.blank?))
+ end
+
+ def url_variables
+ { 'token' => token }.compact
+ end
+ end
+end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index bea86168c8d..a19b5809ff8 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -63,7 +63,24 @@ class Issue < ApplicationRecord
belongs_to :moved_to, class_name: 'Issue'
has_one :moved_from, class_name: 'Issue', foreign_key: :moved_to_id
- has_internal_id :iid, scope: :project, track_if: -> { !importing? }
+ has_internal_id :iid, scope: :namespace, track_if: -> { !importing? }, init: ->(issue, scope) do
+ # we need this init for the case where the IID allocation in internal_ids#last_value
+ # is higher than the actual issues.max(iid) value for a given project. For instance
+ # in case of an import where a batch of IIDs may be prealocated
+ #
+ # TODO: remove this once the UpdateIssuesInternalIdScope migration completes
+ if issue
+ [
+ InternalId.where(project: issue.project, usage: :issues).pick(:last_value).to_i,
+ issue.namespace&.issues&.maximum(:iid).to_i
+ ].max
+ else
+ [
+ InternalId.where(**scope, usage: :issues).pick(:last_value).to_i,
+ where(**scope).maximum(:iid).to_i
+ ].max
+ end
+ end
has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
@@ -104,10 +121,11 @@ class Issue < ApplicationRecord
accepts_nested_attributes_for :sentry_issue
accepts_nested_attributes_for :incident_management_issuable_escalation_status, update_only: true
- validates :project, presence: true
+ validates :project, presence: true, if: -> { !namespace || namespace.is_a?(Namespaces::ProjectNamespace) }
validates :issue_type, presence: true
validates :namespace, presence: true
validates :work_item_type, presence: true
+ validates :confidential, inclusion: { in: [true, false], message: 'must be a boolean' }
validate :allowed_work_item_type_change, on: :update, if: :work_item_type_id_changed?
validate :due_date_after_start_date
@@ -136,7 +154,7 @@ class Issue < ApplicationRecord
scope :order_due_date_asc, -> { reorder(arel_table[:due_date].asc.nulls_last) }
scope :order_due_date_desc, -> { reorder(arel_table[:due_date].desc.nulls_last) }
- scope :order_closest_future_date, -> { reorder(Arel.sql('CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC')) }
+ scope :order_closest_future_date, -> { reorder(Arel.sql("CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC")) }
scope :order_created_at_desc, -> { reorder(created_at: :desc) }
scope :order_severity_asc, -> do
build_keyset_order_on_joined_column(
@@ -162,15 +180,15 @@ class Issue < ApplicationRecord
scope :order_closed_at_desc, -> { reorder(arel_table[:closed_at].desc.nulls_last) }
scope :preload_associated_models, -> { preload(:assignees, :labels, project: :namespace) }
- scope :with_web_entity_associations, -> { preload(:author, project: [:project_feature, :route, namespace: :route]) }
+ scope :with_web_entity_associations, -> { preload(:author, :namespace, project: [:project_feature, :route, namespace: :route]) }
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(:timelogs, :closed_by, :assignees, :author, :labels, :issuable_severity,
+ preload(:timelogs, :closed_by, :assignees, :author, :labels, :issuable_severity, namespace: [{ parent: :route }, :route],
milestone: { project: [:route, { namespace: :route }] },
- project: [:project_feature, :route, { namespace: :route }],
+ project: [:project_namespace, :project_feature, :route, { group: :route }, { namespace: :route }],
duplicated_to: { project: [:project_feature] })
}
scope :with_issue_type, ->(types) { where(issue_type: types) }
@@ -214,7 +232,7 @@ class Issue < ApplicationRecord
before_validation :ensure_namespace_id, :ensure_work_item_type
- after_save :ensure_metrics, unless: :importing?
+ after_save :ensure_metrics!, unless: :importing?
after_commit :expire_etag_cache, unless: :importing?
after_create_commit :record_create_action, unless: :importing?
@@ -345,7 +363,7 @@ class Issue < ApplicationRecord
end
def self.link_reference_pattern
- @link_reference_pattern ||= super(%r{issues(?:\/incident)?}, Gitlab::Regex.issue)
+ @link_reference_pattern ||= compose_link_reference_pattern(%r{issues(?:\/incident)?}, Gitlab::Regex.issue)
end
def self.reference_valid?(reference)
@@ -450,7 +468,7 @@ class Issue < ApplicationRecord
def to_reference(from = nil, full: false)
reference = "#{self.class.reference_prefix}#{iid}"
- "#{project.to_reference_base(from, full: full)}#{reference}"
+ "#{namespace.to_reference_base(from, full: full)}#{reference}"
end
def suggested_branch_name
@@ -463,7 +481,7 @@ class Issue < ApplicationRecord
"#{to_branch_name}-#{suffix}"
end
- Uniquify.new(start_counting_from).string(branch_name_generator) do |suggested_branch_name|
+ Gitlab::Utils::Uniquify.new(start_counting_from).string(branch_name_generator) do |suggested_branch_name|
project.repository.branch_exists?(suggested_branch_name)
end
end
@@ -722,8 +740,7 @@ class Issue < ApplicationRecord
confidential_changed?(from: true, to: false)
end
- override :ensure_metrics
- def ensure_metrics
+ def ensure_metrics!
Issue::Metrics.record!(self)
end
diff --git a/app/models/member.rb b/app/models/member.rb
index e97c9e929ac..4329b61fc3d 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -320,6 +320,12 @@ class Member < ApplicationRecord
end
end
+ def filter_by_user_type(value)
+ return unless ::User.user_types.key?(value)
+
+ left_join_users.merge(::User.where(user_type: value))
+ end
+
def sort_by_attribute(method)
case method.to_s
when 'access_level_asc' then reorder(access_level: :asc)
diff --git a/app/models/members/member_role.rb b/app/models/members/member_role.rb
deleted file mode 100644
index 42ce228c318..00000000000
--- a/app/models/members/member_role.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# frozen_string_literal: true
-
-class MemberRole < ApplicationRecord # rubocop:disable Gitlab/NamespacedClass
- include IgnorableColumns
- ignore_column :download_code, remove_with: '15.9', remove_after: '2023-01-22'
-
- has_many :members
- belongs_to :namespace
-
- validates :namespace, presence: true
- validates :base_access_level, presence: true
- validate :belongs_to_top_level_namespace
- validate :validate_namespace_locked, on: :update
- validate :attributes_locked_after_member_associated, on: :update
-
- validates_associated :members
-
- before_destroy :prevent_delete_after_member_associated
-
- private
-
- def belongs_to_top_level_namespace
- return if !namespace || namespace.root?
-
- errors.add(:namespace, s_("MemberRole|must be top-level namespace"))
- end
-
- def validate_namespace_locked
- return unless namespace_id_changed?
-
- errors.add(:namespace, s_("MemberRole|can't be changed"))
- end
-
- def attributes_locked_after_member_associated
- return unless members.present?
-
- errors.add(:base, s_("MemberRole|cannot be changed because it is already assigned to a user. "\
- "Please create a new Member Role instead"))
- end
-
- def prevent_delete_after_member_associated
- return unless members.present?
-
- errors.add(:base, s_("MemberRole|cannot be deleted because it is already assigned to a user. "\
- "Please disassociate the member role from all users before deletion."))
-
- throw :abort # rubocop:disable Cop/BanCatchThrow
- end
-end
diff --git a/app/models/members_preloader.rb b/app/models/members_preloader.rb
index ba7e4b39989..f6617fa0888 100644
--- a/app/models/members_preloader.rb
+++ b/app/models/members_preloader.rb
@@ -8,12 +8,17 @@ class MembersPreloader
end
def preload_all
- ActiveRecord::Associations::Preloader.new.preload(members, :user)
- ActiveRecord::Associations::Preloader.new.preload(members, :source)
- ActiveRecord::Associations::Preloader.new.preload(members, :created_by)
- ActiveRecord::Associations::Preloader.new.preload(members, user: :status)
- ActiveRecord::Associations::Preloader.new.preload(members, user: :u2f_registrations)
- ActiveRecord::Associations::Preloader.new.preload(members, user: :webauthn_registrations) if Feature.enabled?(:webauthn)
+ user_associations = [:status]
+ user_associations << :webauthn_registrations if Feature.enabled?(:webauthn)
+
+ ActiveRecord::Associations::Preloader.new(
+ records: members,
+ associations: [
+ :source,
+ :created_by,
+ { user: user_associations }
+ ]
+ ).call
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 485ca3a3850..85e95a556a8 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -92,7 +92,7 @@ class MergeRequest < ApplicationRecord
fallback || super || MergeRequestDiff.new(merge_request_id: id)
end
- belongs_to :head_pipeline, foreign_key: "head_pipeline_id", class_name: "Ci::Pipeline"
+ belongs_to :head_pipeline, class_name: "Ci::Pipeline", inverse_of: :merge_requests_as_head_pipeline
has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
@@ -141,7 +141,7 @@ class MergeRequest < ApplicationRecord
after_update :clear_memoized_shas
after_update :reload_diff_if_branch_changed
after_save :keep_around_commit, unless: :importing?
- after_commit :ensure_metrics, on: [:create, :update], unless: :importing?
+ after_commit :ensure_metrics!, on: [:create, :update], unless: :importing?
after_commit :expire_etag_cache, unless: :importing?
# When this attribute is true some MR validation is ignored
@@ -156,6 +156,9 @@ class MergeRequest < ApplicationRecord
# when creating new merge request
attr_accessor :can_be_created, :compare_commits, :diff_options, :compare
+ # Flag to skip triggering mergeRequestMergeStatusUpdated GraphQL subscription.
+ attr_accessor :skip_merge_status_trigger
+
participant :reviewers
# Keep states definition to be evaluated before the state_machine block to avoid spec failures.
@@ -252,6 +255,8 @@ class MergeRequest < ApplicationRecord
end
after_transition any => [:unchecked, :cannot_be_merged_recheck, :checking, :cannot_be_merged_rechecking, :can_be_merged, :cannot_be_merged] do |merge_request, transition|
+ next if merge_request.skip_merge_status_trigger
+
merge_request.run_after_commit do
GraphqlTriggers.merge_request_merge_status_updated(merge_request)
end
@@ -451,7 +456,12 @@ class MergeRequest < ApplicationRecord
def self.total_time_to_merge
join_metrics
- .merge(MergeRequest::Metrics.with_valid_time_to_merge)
+ .where(
+ # Replicating the scope MergeRequest::Metrics.with_valid_time_to_merge
+ MergeRequest::Metrics.arel_table[:merged_at].gt(
+ MergeRequest::Metrics.arel_table[:created_at]
+ )
+ )
.pick(MergeRequest::Metrics.time_to_merge_expression)
end
@@ -558,7 +568,7 @@ class MergeRequest < ApplicationRecord
end
def self.link_reference_pattern
- @link_reference_pattern ||= super("merge_requests", Gitlab::Regex.merge_request)
+ @link_reference_pattern ||= compose_link_reference_pattern('merge_requests', Gitlab::Regex.merge_request)
end
def self.reference_valid?(reference)
@@ -1943,8 +1953,7 @@ class MergeRequest < ApplicationRecord
super.merge(label_url_method: :project_merge_requests_url)
end
- override :ensure_metrics
- def ensure_metrics
+ def ensure_metrics!
MergeRequest::Metrics.record!(self)
end
diff --git a/app/models/merge_request_diff_commit.rb b/app/models/merge_request_diff_commit.rb
index 7e2efa2049b..fc08dd4d9c8 100644
--- a/app/models/merge_request_diff_commit.rb
+++ b/app/models/merge_request_diff_commit.rb
@@ -80,7 +80,7 @@ class MergeRequestDiffCommit < ApplicationRecord
def self.prepare_commits_for_bulk_insert(commits)
user_tuples = Set.new
hashes = commits.map do |commit|
- hash = commit.to_hash.except(:parent_ids)
+ hash = commit.to_hash.except(:parent_ids, :referenced_by)
TRIM_USER_KEYS.each do |key|
hash[key] = MergeRequest::DiffCommitUser.prepare(hash[key])
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index b0676c25f8e..10d70eaa24e 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -8,6 +8,7 @@ class Milestone < ApplicationRecord
include FromUnion
include Importable
include IidRoutes
+ include UpdatedAtFilterable
prepend_mod_with('Milestone') # rubocop: disable Cop/InjectEnterpriseEditionModule
@@ -26,6 +27,7 @@ class Milestone < ApplicationRecord
has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
+ scope :by_iid, ->(iid) { where(iid: iid) }
scope :active, -> { with_state(:active) }
scope :started, -> { active.where('milestones.start_date <= CURRENT_DATE') }
scope :not_started, -> { active.where('milestones.start_date > CURRENT_DATE') }
@@ -112,7 +114,7 @@ class Milestone < ApplicationRecord
end
def self.link_reference_pattern
- @link_reference_pattern ||= super("milestones", /(?<milestone>\d+)/)
+ @link_reference_pattern ||= compose_link_reference_pattern('milestones', /(?<milestone>\d+)/)
end
def self.upcoming_ids(projects, groups)
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 9d9b09e3562..b972d6688af 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -16,6 +16,7 @@ class Namespace < ApplicationRecord
include EachBatch
include BlocksUnsafeSerialization
include Ci::NamespaceSettings
+ include Referable
# Tells ActiveRecord not to store the full class name, in order to save some space
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69794
@@ -51,7 +52,8 @@ class Namespace < ApplicationRecord
has_one :namespace_statistics
has_one :namespace_route, foreign_key: :namespace_id, autosave: false, inverse_of: :namespace, class_name: 'Route'
has_many :namespace_members, foreign_key: :member_namespace_id, inverse_of: :member_namespace, class_name: 'Member'
- has_many :member_roles
+
+ has_one :namespace_ldap_settings, inverse_of: :namespace, class_name: 'Namespaces::LdapSetting', autosave: true
has_many :runner_namespaces, inverse_of: :namespace, class_name: 'Ci::RunnerNamespace'
has_many :runners, through: :runner_namespaces, source: :runner, class_name: 'Ci::Runner'
@@ -97,6 +99,7 @@ class Namespace < ApplicationRecord
validates :path,
presence: true,
length: { maximum: URL_MAX_LENGTH }
+ validate :container_registry_namespace_path_validation
validates :path, namespace_path: true, if: ->(n) { !n.project_namespace? }
# Project path validator is used for project namespaces for now to assure
@@ -244,27 +247,42 @@ class Namespace < ApplicationRecord
def clean_path(path, limited_to: Namespace.all)
slug = Gitlab::Slug::Path.new(path).generate
path = Namespaces::RandomizedSuffixPath.new(slug)
- Uniquify.new.string(path) { |s| limited_to.find_by_path_or_name(s) }
+ Gitlab::Utils::Uniquify.new.string(path) { |s| limited_to.find_by_path_or_name(s) }
end
def clean_name(value)
value.scan(Gitlab::Regex.group_name_regex_chars).join(' ')
end
- def find_by_pages_host(host)
- gitlab_host = "." + Settings.pages.host.downcase
- host = host.downcase
- return unless host.ends_with?(gitlab_host)
+ def top_most
+ by_parent(nil)
+ end
- name = host.delete_suffix(gitlab_host)
- Namespace.top_most.by_path(name)
+ def reference_prefix
+ User.reference_prefix
end
- def top_most
- by_parent(nil)
+ def reference_pattern
+ User.reference_pattern
end
end
+ def to_reference_base(from = nil, full: false)
+ return full_path if full || cross_namespace_reference?(from)
+ return path if cross_project_reference?(from)
+ end
+
+ def to_reference(*)
+ "#{self.class.reference_prefix}#{full_path}"
+ end
+
+ def container_registry_namespace_path_validation
+ return if Feature.disabled?(:restrict_special_characters_in_namespace_path, self)
+ return if !path_changed? || path.match?(Gitlab::Regex.oci_repository_path_regex)
+
+ errors.add(:path, Gitlab::Regex.oci_repository_path_regex_message)
+ end
+
def package_settings
package_setting_relation || build_package_setting_relation
end
@@ -286,11 +304,15 @@ class Namespace < ApplicationRecord
end
def any_project_has_container_registry_tags?
- all_projects.includes(:container_repositories).any?(&:has_container_registry_tags?)
+ first_project_with_container_registry_tags.present?
end
def first_project_with_container_registry_tags
- all_projects.find(&:has_container_registry_tags?)
+ if ContainerRegistry::GitlabApiClient.supports_gitlab_api? && Feature.enabled?(:use_sub_repositories_api)
+ ContainerRegistry::GitlabApiClient.one_project_with_container_registry_tag(full_path)
+ else
+ all_projects.includes(:container_repositories).find(&:has_container_registry_tags?)
+ end
end
def send_update_instructions
@@ -473,18 +495,6 @@ class Namespace < ApplicationRecord
ContainerRepository.for_project_id(all_projects)
end
- def pages_virtual_domain
- cache = if Feature.enabled?(:cache_pages_domain_api, root_ancestor)
- ::Gitlab::Pages::CacheControl.for_namespace(root_ancestor.id)
- end
-
- Pages::VirtualDomain.new(
- projects: all_projects_with_pages.includes(:route, :project_feature, pages_metadatum: :pages_deployment),
- trim_prefix: full_path,
- cache: cache
- )
- end
-
def any_project_with_pages_deployed?
all_projects.with_pages_deployed.any?
end
@@ -599,8 +609,44 @@ class Namespace < ApplicationRecord
namespace_settings&.all_ancestors_have_runner_registration_enabled?
end
+ def all_projects_with_pages
+ all_projects.with_pages_deployed.includes(
+ :route,
+ :project_setting,
+ :project_feature,
+ pages_metadatum: :pages_deployment
+ )
+ end
+
private
+ def cross_namespace_reference?(from)
+ return false if from == self
+
+ comparable_namespace_id = project_namespace? ? parent_id : id
+
+ case from
+ when Project
+ from.namespace_id != comparable_namespace_id
+ when Namespaces::ProjectNamespace
+ from.parent_id != comparable_namespace_id
+ when Namespace
+ parent != from
+ when User
+ true
+ end
+ end
+
+ # Check if a reference is being done cross-project
+ def cross_project_reference?(from)
+ case from
+ when Project
+ from.project_namespace_id != id
+ else
+ from && self != from
+ end
+ end
+
def update_new_emails_created_column
return if namespace_settings.nil?
return if namespace_settings.emails_enabled == !emails_disabled
@@ -630,10 +676,6 @@ class Namespace < ApplicationRecord
end
end
- def all_projects_with_pages
- all_projects.with_pages_deployed
- end
-
def parent_changed?
parent_id_changed?
end
diff --git a/app/models/namespaces/ldap_setting.rb b/app/models/namespaces/ldap_setting.rb
new file mode 100644
index 00000000000..73125d347cc
--- /dev/null
+++ b/app/models/namespaces/ldap_setting.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Namespaces
+ class LdapSetting < ApplicationRecord
+ belongs_to :namespace, inverse_of: :namespace_ldap_settings
+ validates :namespace, presence: true
+
+ self.primary_key = :namespace_id
+ self.table_name = 'namespace_ldap_settings'
+ end
+end
diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb
index 0e9760832af..0fae66b18ca 100644
--- a/app/models/namespaces/traversal/linear.rb
+++ b/app/models/namespaces/traversal/linear.rb
@@ -127,9 +127,13 @@ module Namespaces
return super unless use_traversal_ids_for_root_ancestor?
strong_memoize(:root_ancestor) do
- if parent_id.nil?
+ if association(:parent).loaded? && parent.present?
+ # This case is possible when parent has not been persisted or we're inside a transaction.
+ parent.root_ancestor
+ elsif parent_id.nil?
+ # There is no parent, so we are the root ancestor.
self
- else
+ elsif traversal_ids.present?
Namespace.find_by(id: traversal_ids.first)
end
end
@@ -215,6 +219,16 @@ module Namespaces
hierarchy_order == :desc ? traversal_ids : traversal_ids.reverse
end
+ def parent=(obj)
+ super(obj)
+ set_traversal_ids
+ end
+
+ def parent_id=(id)
+ super(id)
+ set_traversal_ids
+ end
+
private
attr_accessor :transient_traversal_ids
@@ -232,11 +246,11 @@ module Namespaces
end
def set_traversal_ids
+ return if id.blank?
+
# This is a temporary guard and will be removed.
return if is_a?(Namespaces::ProjectNamespace)
- return unless Feature.enabled?(:set_traversal_ids_on_save, root_ancestor)
-
self.transient_traversal_ids = if parent_id
parent.traversal_ids + [id]
else
@@ -244,7 +258,7 @@ module Namespaces
end
# Clear root_ancestor memo if changed.
- if read_attribute(traversal_ids)&.first != transient_traversal_ids.first
+ if read_attribute(:traversal_ids)&.first != transient_traversal_ids.first
clear_memoization(:root_ancestor)
end
diff --git a/app/models/note.rb b/app/models/note.rb
index a64f7311725..b9b884b88c5 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -60,6 +60,9 @@ class Note < ApplicationRecord
# Attribute used to store the attributes that have been changed by quick actions.
attr_writer :commands_changes
+ # Attribute used to store the quick action command names.
+ attr_accessor :command_names
+
# Attribute used to determine whether keep_around_commits will be skipped for diff notes.
attr_accessor :skip_keep_around_commits
@@ -169,7 +172,6 @@ class Note < ApplicationRecord
project: [:project_members, :namespace, { group: [:group_members] }])
end
scope :with_metadata, -> { includes(:system_note_metadata) }
- scope :with_web_entity_associations, -> { preload(:project, :author, :noteable) }
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) }
@@ -288,6 +290,10 @@ class Note < ApplicationRecord
def cherry_picked_merge_requests(shas)
where(noteable_type: 'MergeRequest', commit_id: shas).select(:noteable_id)
end
+
+ def with_web_entity_associations
+ preload(:project, :author, :noteable)
+ end
end
# rubocop: disable CodeReuse/ServiceClass
@@ -330,6 +336,10 @@ class Note < ApplicationRecord
noteable_type == "Issue"
end
+ def for_work_item?
+ noteable.is_a?(WorkItem)
+ end
+
def for_merge_request?
noteable_type == "MergeRequest"
end
diff --git a/app/models/oauth_access_token.rb b/app/models/oauth_access_token.rb
index 8e79a750793..601381f1c65 100644
--- a/app/models/oauth_access_token.rb
+++ b/app/models/oauth_access_token.rb
@@ -4,6 +4,8 @@ class OauthAccessToken < Doorkeeper::AccessToken
belongs_to :resource_owner, class_name: 'User'
belongs_to :application, class_name: 'Doorkeeper::Application'
+ validates :expires_in, presence: true
+
alias_attribute :user, :resource_owner
scope :latest_per_application, -> { select('distinct on(application_id) *').order(application_id: :desc, created_at: :desc) }
diff --git a/app/models/onboarding/completion.rb b/app/models/onboarding/completion.rb
index 269283df826..0966a9f2912 100644
--- a/app/models/onboarding/completion.rb
+++ b/app/models/onboarding/completion.rb
@@ -5,52 +5,65 @@ module Onboarding
include Gitlab::Utils::StrongMemoize
include Gitlab::Experiment::Dsl
- ACTION_ISSUE_IDS = {
- trial_started: 2,
- required_mr_approvals_enabled: 11,
- code_owners_enabled: 10
- }.freeze
-
ACTION_PATHS = [
:pipeline_created,
+ :trial_started,
+ :required_mr_approvals_enabled,
+ :code_owners_enabled,
:issue_created,
:git_write,
:merge_request_created,
:user_added
].freeze
- def initialize(namespace, current_user = nil)
- @namespace = namespace
+ def initialize(project, current_user = nil)
+ @project = project
+ @namespace = project.namespace
@current_user = current_user
end
def percentage
return 0 unless onboarding_progress
- attributes = onboarding_progress.attributes.symbolize_keys
-
total_actions = action_columns.count
- completed_actions = action_columns.count { |column| attributes[column].present? }
+ completed_actions = action_columns.count { |column| completed?(column) }
(completed_actions.to_f / total_actions * 100).round
end
+ def completed?(column)
+ if column == :code_added
+ repository.commit_count > 1 || repository.branch_count > 1
+ else
+ attributes[column].present?
+ end
+ end
+
private
+ def repository
+ project.repository
+ end
+ strong_memoize_attr :repository
+
+ def attributes
+ onboarding_progress.attributes.symbolize_keys
+ end
+ strong_memoize_attr :attributes
+
def onboarding_progress
- strong_memoize(:onboarding_progress) do
- ::Onboarding::Progress.find_by(namespace: namespace)
- end
+ ::Onboarding::Progress.find_by(namespace: namespace)
end
+ strong_memoize_attr :onboarding_progress
def action_columns
- strong_memoize(:action_columns) do
+ [:code_added] +
tracked_actions.map { |action_key| ::Onboarding::Progress.column_name(action_key) }
- end
end
+ strong_memoize_attr :action_columns
def tracked_actions
- ACTION_ISSUE_IDS.keys + ACTION_PATHS + deploy_section_tracked_actions
+ ACTION_PATHS + deploy_section_tracked_actions
end
def deploy_section_tracked_actions
@@ -65,6 +78,6 @@ module Onboarding
end.run
end
- attr_reader :namespace, :current_user
+ attr_reader :project, :namespace, :current_user
end
end
diff --git a/app/models/operations/feature_flag.rb b/app/models/operations/feature_flag.rb
index 0df8c87f73f..6876af09c2c 100644
--- a/app/models/operations/feature_flag.rb
+++ b/app/models/operations/feature_flag.rb
@@ -72,7 +72,7 @@ module Operations
end
def link_reference_pattern
- @link_reference_pattern ||= super("feature_flags", %r{(?<feature_flag>\d+)/edit})
+ @link_reference_pattern ||= compose_link_reference_pattern('feature_flags', %r{(?<feature_flag>\d+)/edit})
end
def reference_postfix
diff --git a/app/models/packages/debian.rb b/app/models/packages/debian.rb
index 9c615c20250..887a5695530 100644
--- a/app/models/packages/debian.rb
+++ b/app/models/packages/debian.rb
@@ -10,6 +10,8 @@ module Packages
LETTER_REGEX = %r{(lib)?[a-z0-9]}.freeze
+ EMPTY_FILE_SHA256 = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'.freeze
+
def self.table_name_prefix
'packages_debian_'
end
diff --git a/app/models/packages/debian/file_metadatum.rb b/app/models/packages/debian/file_metadatum.rb
index eb1b03a8e9d..77ce8e265ff 100644
--- a/app/models/packages/debian/file_metadatum.rb
+++ b/app/models/packages/debian/file_metadatum.rb
@@ -9,14 +9,14 @@ class Packages::Debian::FileMetadatum < ApplicationRecord
validate :valid_debian_package_type
enum file_type: {
- unknown: 1, source: 2, dsc: 3, deb: 4, udeb: 5, buildinfo: 6, changes: 7
+ unknown: 1, source: 2, dsc: 3, deb: 4, udeb: 5, buildinfo: 6, changes: 7, ddeb: 8
}
validates :file_type, presence: true
validates :file_type, inclusion: { in: %w[unknown] },
if: -> { package_file&.package&.debian_incoming? || package_file&.package&.processing? }
validates :file_type,
- inclusion: { in: %w[source dsc deb udeb buildinfo changes] },
+ inclusion: { in: %w[source dsc deb udeb buildinfo changes ddeb] },
if: -> { package_file&.package&.debian_package? && !package_file&.package&.processing? }
validates :component,
@@ -46,7 +46,7 @@ class Packages::Debian::FileMetadatum < ApplicationRecord
end
def requires_architecture?
- deb? || udeb?
+ deb? || udeb? || ddeb?
end
def requires_component?
diff --git a/app/models/packages/rpm/repository_file.rb b/app/models/packages/rpm/repository_file.rb
index 614ec9b3e56..bbd435691d2 100644
--- a/app/models/packages/rpm/repository_file.rb
+++ b/app/models/packages/rpm/repository_file.rb
@@ -13,7 +13,7 @@ module Packages
enum status: { default: 0, pending_destruction: 1, processing: 2, error: 3 }
- belongs_to :project, inverse_of: :repository_files
+ belongs_to :project, inverse_of: :rpm_repository_files
validates :project, presence: true
validates :file, presence: true
diff --git a/app/models/pages/lookup_path.rb b/app/models/pages/lookup_path.rb
index a1ba48f3ab0..222cde19da7 100644
--- a/app/models/pages/lookup_path.rb
+++ b/app/models/pages/lookup_path.rb
@@ -49,19 +49,25 @@ module Pages
if project.pages_namespace_url == project.pages_url
'/'
else
- project.full_path.delete_prefix(trim_prefix) + '/'
+ "#{project.full_path.delete_prefix(trim_prefix)}/"
end
end
strong_memoize_attr :prefix
+ def unique_domain
+ return unless project.project_setting.pages_unique_domain_enabled?
+
+ project.project_setting.pages_unique_domain
+ end
+ strong_memoize_attr :unique_domain
+
private
attr_reader :project, :trim_prefix, :domain
def deployment
- strong_memoize(:deployment) do
- project.pages_metadatum.pages_deployment
- end
+ project.pages_metadatum.pages_deployment
end
+ strong_memoize_attr :deployment
end
end
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index 909658214fd..446c4a6187c 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -15,7 +15,6 @@ class PagesDomain < ApplicationRecord
belongs_to :project
has_many :acme_orders, class_name: "PagesDomainAcmeOrder"
- has_many :serverless_domain_clusters, class_name: 'Serverless::DomainCluster', inverse_of: :pages_domain
after_initialize :set_verification_code
before_validation :clear_auto_ssl_failure, unless: :auto_ssl_enabled
@@ -209,20 +208,6 @@ class PagesDomain < ApplicationRecord
self.certificate_source = 'gitlab_provided' if attribute_changed?(:key)
end
- def pages_virtual_domain
- return unless pages_deployed?
-
- cache = if Feature.enabled?(:cache_pages_domain_api, project.root_namespace)
- ::Gitlab::Pages::CacheControl.for_domain(id)
- end
-
- Pages::VirtualDomain.new(
- projects: [project],
- domain: self,
- cache: cache
- )
- end
-
def clear_auto_ssl_failure
self.auto_ssl_failed = false
end
@@ -237,14 +222,14 @@ class PagesDomain < ApplicationRecord
end
end
- private
-
def pages_deployed?
return false unless project
project.pages_metadatum&.deployed?
end
+ private
+
def set_verification_code
return if self.verification_code.present?
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index f99c4c6c39d..2e613768873 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -9,7 +9,9 @@ class PersonalAccessToken < ApplicationRecord
include Gitlab::SQL::Pattern
extend ::Gitlab::Utils::Override
- add_authentication_token_field :token, digest: true
+ add_authentication_token_field :token,
+ digest: true,
+ format_with_prefix: :prefix_from_application_current_settings
# PATs are 20 characters + optional configurable settings prefix (0..20)
TOKEN_LENGTH_RANGE = (20..40).freeze
@@ -72,11 +74,6 @@ class PersonalAccessToken < ApplicationRecord
fuzzy_search(query, [:name])
end
- override :format_token
- def format_token(token)
- "#{self.class.token_prefix}#{token}"
- end
-
def project_access_token?
user&.project_bot?
end
@@ -107,6 +104,10 @@ class PersonalAccessToken < ApplicationRecord
def add_admin_mode_scope
self.scopes += [Gitlab::Auth::ADMIN_MODE_SCOPE.to_s]
end
+
+ def prefix_from_application_current_settings
+ self.class.token_prefix
+ end
end
PersonalAccessToken.prepend_mod_with('PersonalAccessToken')
diff --git a/app/models/preloaders/commit_status_preloader.rb b/app/models/preloaders/commit_status_preloader.rb
index 535dd24ba6b..79c2549e371 100644
--- a/app/models/preloaders/commit_status_preloader.rb
+++ b/app/models/preloaders/commit_status_preloader.rb
@@ -9,10 +9,11 @@ module Preloaders
end
def execute(relations)
- preloader = ActiveRecord::Associations::Preloader.new
-
CLASSES.each do |klass|
- preloader.preload(objects(klass), associations(klass, relations))
+ ActiveRecord::Associations::Preloader.new(
+ records: objects(klass),
+ associations: associations(klass, relations)
+ ).call
end
end
diff --git a/app/models/preloaders/labels_preloader.rb b/app/models/preloaders/labels_preloader.rb
index b6e73c1cd02..2a3175be420 100644
--- a/app/models/preloaders/labels_preloader.rb
+++ b/app/models/preloaders/labels_preloader.rb
@@ -19,11 +19,20 @@ module Preloaders
end
def preload_all
- preloader = ActiveRecord::Associations::Preloader.new
+ ActiveRecord::Associations::Preloader.new(
+ records: labels,
+ associations: { parent_container: :route }
+ ).call
- preloader.preload(labels, parent_container: :route)
- preloader.preload(labels.select { |l| l.is_a? ProjectLabel }, { project: [:project_feature, namespace: :route] })
- preloader.preload(labels.select { |l| l.is_a? GroupLabel }, { group: :route })
+ ActiveRecord::Associations::Preloader.new(
+ records: labels.select { |l| l.is_a? ProjectLabel },
+ associations: { project: [:project_feature, namespace: :route] }
+ ).call
+
+ ActiveRecord::Associations::Preloader.new(
+ records: labels.select { |l| l.is_a? GroupLabel },
+ associations: { group: :route }
+ ).call
labels.each do |label|
label.lazy_subscription(user)
diff --git a/app/models/preloaders/project_policy_preloader.rb b/app/models/preloaders/project_policy_preloader.rb
index fe9db3464c7..e16eabf40a1 100644
--- a/app/models/preloaders/project_policy_preloader.rb
+++ b/app/models/preloaders/project_policy_preloader.rb
@@ -10,7 +10,10 @@ module Preloaders
def execute
return if projects.is_a?(ActiveRecord::NullRelation)
- ActiveRecord::Associations::Preloader.new.preload(projects, { group: :route, namespace: :owner })
+ ActiveRecord::Associations::Preloader.new(
+ records: projects,
+ associations: { group: :route, namespace: :owner }
+ ).call
::Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects, current_user).execute
end
diff --git a/app/models/preloaders/project_root_ancestor_preloader.rb b/app/models/preloaders/project_root_ancestor_preloader.rb
index 6192f79ce2c..ccb9d2eab98 100644
--- a/app/models/preloaders/project_root_ancestor_preloader.rb
+++ b/app/models/preloaders/project_root_ancestor_preloader.rb
@@ -19,7 +19,7 @@ module Preloaders
root_ancestors_by_id = root_query.group_by(&:source_id)
- ActiveRecord::Associations::Preloader.new.preload(@projects, :namespace)
+ ActiveRecord::Associations::Preloader.new(records: @projects, associations: :namespace).call
@projects.each do |project|
root_ancestor = root_ancestors_by_id[project.id]&.first
project.namespace.root_ancestor = root_ancestor if root_ancestor.present?
diff --git a/app/models/preloaders/runner_machine_policy_preloader.rb b/app/models/preloaders/runner_machine_policy_preloader.rb
new file mode 100644
index 00000000000..52864eeba8d
--- /dev/null
+++ b/app/models/preloaders/runner_machine_policy_preloader.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Preloaders
+ class RunnerMachinePolicyPreloader
+ def initialize(runner_machines, current_user)
+ @runner_machines = runner_machines
+ @current_user = current_user
+ end
+
+ def execute
+ return if runner_machines.is_a?(ActiveRecord::NullRelation)
+
+ ActiveRecord::Associations::Preloader.new(
+ records: runner_machines,
+ associations: [:runner]
+ ).call
+ end
+
+ private
+
+ attr_reader :runner_machines, :current_user
+ end
+end
diff --git a/app/models/preloaders/user_max_access_level_in_groups_preloader.rb b/app/models/preloaders/user_max_access_level_in_groups_preloader.rb
index 0c747ad9c84..16d46facb96 100644
--- a/app/models/preloaders/user_max_access_level_in_groups_preloader.rb
+++ b/app/models/preloaders/user_max_access_level_in_groups_preloader.rb
@@ -46,14 +46,10 @@ module Preloaders
end
def all_memberships
- if Feature.enabled?(:include_memberships_from_group_shares_in_preloader)
- [
- direct_memberships.select(*GroupMember.cached_column_list),
- memberships_from_group_shares
- ]
- else
- [direct_memberships]
- end
+ [
+ direct_memberships.select(*GroupMember.cached_column_list),
+ memberships_from_group_shares
+ ]
end
def direct_memberships
diff --git a/app/models/project.rb b/app/models/project.rb
index 43ec26be786..cb218c0a49f 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -19,6 +19,7 @@ class Project < ApplicationRecord
include Presentable
include HasRepository
include HasWiki
+ include WebHooks::HasWebHooks
include CanMoveRepositoryStorage
include Routable
include GroupDescendant
@@ -41,7 +42,6 @@ class Project < ApplicationRecord
include BlocksUnsafeSerialization
include Subquery
include IssueParent
- include WebHooks::HasWebHooks
extend Gitlab::Cache::RequestCache
extend Gitlab::Utils::Override
@@ -89,6 +89,14 @@ class Project < ApplicationRecord
DEFAULT_SQUASH_COMMIT_TEMPLATE = '%{title}'
+ PROJECT_FEATURES_DEFAULTS = {
+ issues: gitlab_config_features.issues,
+ merge_requests: gitlab_config_features.merge_requests,
+ builds: gitlab_config_features.builds,
+ wiki: gitlab_config_features.wiki,
+ snippets: gitlab_config_features.snippets
+ }.freeze
+
cache_markdown_field :description, pipeline: :description
attribute :packages_enabled, default: true
@@ -101,18 +109,14 @@ class Project < ApplicationRecord
attribute :autoclose_referenced_issues, default: true
attribute :ci_config_path, default: -> { Gitlab::CurrentSettings.default_ci_config_path }
- default_value_for :issues_enabled, gitlab_config_features.issues
- default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests
- default_value_for :builds_enabled, gitlab_config_features.builds
- default_value_for :wiki_enabled, gitlab_config_features.wiki
- default_value_for :snippets_enabled, gitlab_config_features.snippets
-
add_authentication_token_field :runners_token,
encrypted: -> { Feature.enabled?(:projects_tokens_optional_encryption) ? :optional : :required },
- prefix: RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX
+ format_with_prefix: :runners_token_prefix,
+ require_prefix_for_validation: true
# Storage specific hooks
after_initialize :use_hashed_storage
+ after_initialize :set_project_feature_defaults, if: :new_record?
before_validation :mark_remote_mirrors_for_removal, if: -> { RemoteMirror.table_exists? }
before_validation :ensure_project_namespace_in_sync
@@ -128,7 +132,6 @@ class Project < ApplicationRecord
after_create -> { create_or_load_association(:pages_metadatum) }
after_create :set_timestamps_for_create
after_create :check_repository_absence!
- after_update :update_forks_visibility_level
before_destroy :remove_private_deploy_keys
after_destroy :remove_exports
after_save :update_project_statistics, if: :saved_change_to_namespace_id?
@@ -168,6 +171,8 @@ class Project < ApplicationRecord
has_one :last_event, -> { order 'events.created_at DESC' }, class_name: 'Event'
has_many :boards
+ has_many :application_setting, inverse_of: :self_monitoring_project
+
def self.integration_association_name(name)
"#{name}_integration"
end
@@ -188,6 +193,7 @@ class Project < ApplicationRecord
has_one :emails_on_push_integration, class_name: 'Integrations::EmailsOnPush'
has_one :ewm_integration, class_name: 'Integrations::Ewm'
has_one :external_wiki_integration, class_name: 'Integrations::ExternalWiki'
+ has_one :google_play_integration, class_name: 'Integrations::GooglePlay'
has_one :hangouts_chat_integration, class_name: 'Integrations::HangoutsChat'
has_one :harbor_integration, class_name: 'Integrations::Harbor'
has_one :irker_integration, class_name: 'Integrations::Irker'
@@ -208,6 +214,7 @@ class Project < ApplicationRecord
has_one :shimo_integration, class_name: 'Integrations::Shimo'
has_one :slack_integration, class_name: 'Integrations::Slack'
has_one :slack_slash_commands_integration, class_name: 'Integrations::SlackSlashCommands'
+ has_one :squash_tm_integration, class_name: 'Integrations::SquashTm'
has_one :teamcity_integration, class_name: 'Integrations::Teamcity'
has_one :unify_circuit_integration, class_name: 'Integrations::UnifyCircuit'
has_one :webex_teams_integration, class_name: 'Integrations::WebexTeams'
@@ -238,14 +245,22 @@ class Project < ApplicationRecord
has_many :fork_network_projects, through: :fork_network, source: :projects
# Packages
- has_many :packages, class_name: 'Packages::Package'
- has_many :package_files, through: :packages, class_name: 'Packages::PackageFile'
+ has_many :packages,
+ class_name: 'Packages::Package'
+ has_many :package_files,
+ through: :packages, class_name: 'Packages::PackageFile'
# repository_files must be destroyed by ruby code in order to properly remove carrierwave uploads
- has_many :repository_files, inverse_of: :project, class_name: 'Packages::Rpm::RepositoryFile',
- dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_many :rpm_repository_files,
+ inverse_of: :project,
+ class_name: 'Packages::Rpm::RepositoryFile',
+ dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
# debian_distributions and associated component_files must be destroyed by ruby code in order to properly remove carrierwave uploads
- has_many :debian_distributions, class_name: 'Packages::Debian::ProjectDistribution', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
- has_one :packages_cleanup_policy, class_name: 'Packages::Cleanup::Policy', inverse_of: :project
+ has_many :debian_distributions,
+ class_name: 'Packages::Debian::ProjectDistribution',
+ dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_one :packages_cleanup_policy,
+ class_name: 'Packages::Cleanup::Policy',
+ 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
@@ -259,6 +274,7 @@ class Project < ApplicationRecord
has_one :project_setting, inverse_of: :project, autosave: true
has_one :alerting_setting, inverse_of: :project, class_name: 'Alerting::ProjectAlertingSetting'
has_one :service_desk_setting, class_name: 'ServiceDeskSetting'
+ has_one :service_desk_custom_email_verification, class_name: 'ServiceDesk::CustomEmailVerification'
# Merge requests for target project should be removed with it
has_many :merge_requests, foreign_key: 'target_project_id', inverse_of: :target_project, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -371,7 +387,6 @@ class Project < ApplicationRecord
inverse_of: :project
has_many :stages, class_name: 'Ci::Stage', inverse_of: :project
has_many :ci_refs, class_name: 'Ci::Ref', inverse_of: :project
-
has_many :pipeline_metadata, class_name: 'Ci::PipelineMetadata', inverse_of: :project
has_many :pending_builds, class_name: 'Ci::PendingBuild'
has_many :builds, class_name: 'Ci::Build', inverse_of: :project
@@ -874,7 +889,7 @@ class Project < ApplicationRecord
def reference_pattern
%r{
(?<!#{Gitlab::PathRegex::PATH_START_CHAR})
- ((?<namespace>#{Gitlab::PathRegex::FULL_NAMESPACE_FORMAT_REGEX})\/)?
+ ((?<namespace>#{Gitlab::PathRegex::FULL_NAMESPACE_FORMAT_REGEX})/)?
(?<project>#{Gitlab::PathRegex::PROJECT_PATH_FORMAT_REGEX})
}xo
end
@@ -950,27 +965,44 @@ class Project < ApplicationRecord
.where(pending_delete: false)
.where(archived: false)
end
+
+ def project_features_defaults
+ PROJECT_FEATURES_DEFAULTS
+ end
+
+ def by_pages_enabled_unique_domain(domain)
+ without_deleted
+ .joins(:project_setting)
+ .find_by(project_setting: {
+ pages_unique_domain_enabled: true,
+ pages_unique_domain: domain
+ })
+ end
end
def initialize(attributes = nil)
- # We can't use default_value_for because the database has a default
- # value of 0 for visibility_level. If someone attempts to create a
- # private project, default_value_for will assume that the
- # visibility_level hasn't changed and will use the application
- # setting default, which could be internal or public. For projects
- # inside a private group, those levels are invalid.
- #
- # To fix the problem, we assign the actual default in the application if
- # no explicit visibility has been initialized.
+ # We assign the actual snippet default if no explicit visibility has been initialized.
attributes ||= {}
unless visibility_attribute_present?(attributes)
attributes[:visibility_level] = Gitlab::CurrentSettings.default_project_visibility
end
+ @init_attributes = attributes
+
super
end
+ # Remove along with ProjectFeaturesCompatibility module
+ def set_project_feature_defaults
+ self.class.project_features_defaults.each do |attr, value|
+ # If the deprecated _enabled or the accepted _access_level attribute is specified, we don't need to set the default
+ next unless @init_attributes[:"#{attr}_enabled"].nil? && @init_attributes[:"#{attr}_access_level"].nil?
+
+ public_send("#{attr}_enabled=", value) # rubocop:disable GitlabSecurity/PublicSend
+ end
+ end
+
def parent_loaded?
association(:namespace).loaded?
end
@@ -1077,8 +1109,10 @@ class Project < ApplicationRecord
end
def preload_protected_branches
- preloader = ActiveRecord::Associations::Preloader.new
- preloader.preload(self, protected_branches: [:push_access_levels, :merge_access_levels])
+ ActiveRecord::Associations::Preloader.new(
+ records: [self],
+ associations: { protected_branches: [:push_access_levels, :merge_access_levels] }
+ ).call
end
# returns all ancestor-groups upto but excluding the given namespace
@@ -1089,11 +1123,7 @@ class Project < ApplicationRecord
end
def ancestors(hierarchy_order: nil)
- if Feature.enabled?(:linear_project_ancestors, self)
- group&.self_and_ancestors(hierarchy_order: hierarchy_order) || Group.none
- else
- ancestors_upto(hierarchy_order: hierarchy_order)
- end
+ group&.self_and_ancestors(hierarchy_order: hierarchy_order) || Group.none
end
def ancestors_upto_ids(...)
@@ -1154,10 +1184,6 @@ class Project < ApplicationRecord
{ scope: :project, status: auto_devops&.enabled || Feature.enabled?(:force_autodevops_on_by_default, self) }
end
- def unlink_forks_upon_visibility_decrease_enabled?
- Feature.enabled?(:unlink_fork_network_upon_visibility_decrease, self)
- end
-
# LFS and hashed repository storage are required for using Design Management.
def design_management_enabled?
lfs_enabled? && hashed_storage?(:repository)
@@ -1177,15 +1203,6 @@ class Project < ApplicationRecord
end
end
- # Because we use default_value_for we need to be sure
- # packages_enabled= method does exist even if we rollback migration.
- # Otherwise many tests from spec/migrations will fail.
- def packages_enabled=(value)
- if has_attribute?(:packages_enabled)
- write_attribute(:packages_enabled, value)
- end
- end
-
def cleanup
@repository = nil
end
@@ -1272,6 +1289,18 @@ class Project < ApplicationRecord
import_state&.human_status_name || 'none'
end
+ def beautified_import_status_name
+ if import_finished?
+ return 'completed' unless import_checksums.present?
+
+ fetched = import_checksums['fetched']
+ imported = import_checksums['imported']
+ fetched.keys.any? { |key| fetched[key] != imported[key] } ? 'partially completed' : 'completed'
+ else
+ import_status
+ end
+ end
+
def add_import_job
job_id =
if forked?
@@ -1314,6 +1343,11 @@ class Project < ApplicationRecord
super(value&.delete("\0"))
end
+ # Used by Import/Export to export commit notes
+ def commit_notes
+ notes.where(noteable_type: "Commit")
+ end
+
def import_url=(value)
if Gitlab::UrlSanitizer.valid?(value)
import_url = Gitlab::UrlSanitizer.new(value)
@@ -1631,7 +1665,7 @@ class Project < ApplicationRecord
def disabled_integrations
disabled_integrations = []
- disabled_integrations << 'apple_app_store' unless Feature.enabled?(:apple_app_store_integration, self)
+ disabled_integrations << 'google_play' unless Feature.enabled?(:google_play_integration, self)
disabled_integrations
end
@@ -1935,19 +1969,6 @@ class Project < ApplicationRecord
create_repository(force: true) unless repository_exists?
end
- # update visibility_level of forks
- def update_forks_visibility_level
- return if unlink_forks_upon_visibility_decrease_enabled?
- return unless visibility_level < visibility_level_before_last_save
-
- forks.each do |forked_project|
- if forked_project.visibility_level > visibility_level
- forked_project.visibility_level = visibility_level
- forked_project.save!
- end
- end
- end
-
def allowed_to_share_with_group?
!namespace.share_with_group_lock
end
@@ -2080,7 +2101,11 @@ class Project < ApplicationRecord
# rubocop: disable CodeReuse/ServiceClass
def open_merge_requests_count(_current_user = nil)
- Projects::OpenMergeRequestsCountService.new(self).count
+ BatchLoader.for(self).batch do |projects, loader|
+ ::Projects::BatchOpenMergeRequestsCountService.new(projects)
+ .refresh_cache_and_retrieve_data
+ .each { |project, count| loader.call(project, count) }
+ end
end
# rubocop: enable CodeReuse/ServiceClass
@@ -2107,23 +2132,13 @@ class Project < ApplicationRecord
ensure_runners_token!
end
- override :format_runners_token
- def format_runners_token(token)
- "#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}#{token}"
- end
-
def pages_deployed?
pages_metadatum&.deployed?
end
- def pages_namespace_url
- # The host in URL always needs to be downcased
- Gitlab.config.pages.url.sub(%r{^https?://}) do |prefix|
- "#{prefix}#{pages_subdomain}."
- end.downcase
- end
-
def pages_url
+ return pages_unique_url if pages_unique_domain_enabled?
+
url = pages_namespace_url
url_path = full_path.partition('/').last
namespace_url = "#{Settings.pages.protocol}://#{url_path}".downcase
@@ -2141,6 +2156,14 @@ class Project < ApplicationRecord
"#{url}/#{url_path}"
end
+ def pages_unique_url
+ pages_url_for(project_setting.pages_unique_domain)
+ end
+
+ def pages_namespace_url
+ pages_url_for(pages_subdomain)
+ end
+
def pages_subdomain
full_path.partition('/').first
end
@@ -2809,7 +2832,7 @@ class Project < ApplicationRecord
end
def all_protected_branches
- if Feature.enabled?(:group_protected_branches)
+ if Feature.enabled?(:group_protected_branches, group)
@all_protected_branches ||= ProtectedBranch.from_union([protected_branches, group_protected_branches])
else
protected_branches
@@ -2971,7 +2994,7 @@ class Project < ApplicationRecord
end
def ci_inbound_job_token_scope_enabled?
- return false unless ci_cd_settings
+ return true unless ci_cd_settings
ci_cd_settings.inbound_job_token_scope_enabled?
end
@@ -3121,6 +3144,18 @@ class Project < ApplicationRecord
private
+ def pages_unique_domain_enabled?
+ Feature.enabled?(:pages_unique_domain) &&
+ project_setting.pages_unique_domain_enabled?
+ end
+
+ def pages_url_for(domain)
+ # The host in URL always needs to be downcased
+ Gitlab.config.pages.url.sub(%r{^https?://}) do |prefix|
+ "#{prefix}#{domain}."
+ end.downcase
+ end
+
# overridden in EE
def project_group_links_with_preload
project_group_links
@@ -3224,6 +3259,8 @@ class Project < ApplicationRecord
case from
when Project
namespace_id != from.namespace_id
+ when Namespaces::ProjectNamespace
+ namespace_id != from.parent_id
when Namespace
namespace != from
when User
@@ -3233,9 +3270,14 @@ class Project < ApplicationRecord
# Check if a reference is being done cross-project
def cross_project_reference?(from)
- return true if from.is_a?(Namespace)
-
- from && self != from
+ case from
+ when Namespaces::ProjectNamespace
+ project_namespace_id != from.id
+ when Namespace
+ true
+ else
+ from && self != from
+ end
end
def update_project_statistics
@@ -3401,6 +3443,10 @@ class Project < ApplicationRecord
project_setting.emails_enabled = !emails_disabled
end
end
+
+ def runners_token_prefix
+ RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX
+ end
end
Project.prepend_mod_with('Project')
diff --git a/app/models/project_ci_cd_setting.rb b/app/models/project_ci_cd_setting.rb
index 8741a341ad3..cc9003423be 100644
--- a/app/models/project_ci_cd_setting.rb
+++ b/app/models/project_ci_cd_setting.rb
@@ -20,10 +20,6 @@ class ProjectCiCdSetting < ApplicationRecord
attribute :forward_deployment_enabled, default: true
attribute :separated_caches, default: true
- default_value_for :inbound_job_token_scope_enabled do |settings|
- Feature.enabled?(:ci_inbound_job_token_scope, settings.project)
- end
-
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
def keep_latest_artifacts_available?
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index 168646bbe41..053ccfac050 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -162,6 +162,12 @@ class ProjectFeature < ApplicationRecord
end
end
+ def public_packages?
+ return false unless Gitlab.config.packages.enabled
+
+ package_registry_access_level == PUBLIC || project.public?
+ end
+
private
def set_pages_access_level
diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb
index db86bb5e1fb..379b94b3af5 100644
--- a/app/models/project_setting.rb
+++ b/app/models/project_setting.rb
@@ -25,6 +25,10 @@ class ProjectSetting < ApplicationRecord
validates :target_platforms, inclusion: { in: ALLOWED_TARGET_PLATFORMS }
validates :suggested_reviewers_enabled, inclusion: { in: [true, false] }
+ validates :pages_unique_domain,
+ uniqueness: { if: -> { pages_unique_domain.present? } },
+ presence: { if: :require_unique_domain? }
+
validate :validates_mr_default_target_self
attribute :legacy_open_source_license_available, default: -> do
@@ -68,6 +72,11 @@ class ProjectSetting < ApplicationRecord
errors.add :mr_default_target_self, _('This setting is allowed for forked projects only')
end
end
+
+ def require_unique_domain?
+ pages_unique_domain_enabled ||
+ pages_unique_domain_in_database.present?
+ end
end
ProjectSetting.prepend_mod
diff --git a/app/models/projects/data_transfer.rb b/app/models/projects/data_transfer.rb
index a93aea55781..faab0bb6db2 100644
--- a/app/models/projects/data_transfer.rb
+++ b/app/models/projects/data_transfer.rb
@@ -4,6 +4,9 @@
# This class ensures that we keep 1 record per project per month.
module Projects
class DataTransfer < ApplicationRecord
+ include AfterCommitQueue
+ include CounterAttribute
+
self.table_name = 'project_data_transfers'
belongs_to :project
@@ -11,6 +14,11 @@ module Projects
scope :current_month, -> { where(date: beginning_of_month) }
+ counter_attribute :repository_egress, returns_current: true
+ counter_attribute :artifacts_egress, returns_current: true
+ counter_attribute :packages_egress, returns_current: true
+ counter_attribute :registry_egress, returns_current: true
+
def self.beginning_of_month(time = Time.current)
time.utc.beginning_of_month
end
diff --git a/app/models/projects/forks/details.rb b/app/models/projects/forks/details.rb
new file mode 100644
index 00000000000..9e09ef09022
--- /dev/null
+++ b/app/models/projects/forks/details.rb
@@ -0,0 +1,102 @@
+# frozen_string_literal: true
+
+module Projects
+ module Forks
+ # Class for calculating the divergence of a fork with the source project
+ class Details
+ include Gitlab::Utils::StrongMemoize
+
+ LATEST_COMMITS_COUNT = 10
+ LEASE_TIMEOUT = 15.minutes.to_i
+ EXPIRATION_TIME = 8.hours
+
+ def initialize(project, ref)
+ @project = project
+ @fork_repo = project.repository
+ @source_repo = project.fork_source.repository
+ @ref = ref
+ end
+
+ def counts
+ ahead, behind = divergence_counts
+
+ { ahead: ahead, behind: behind }
+ end
+
+ def exclusive_lease
+ key = ['project_details', project.id, ref].join(':')
+ uuid = Gitlab::ExclusiveLease.get_uuid(key)
+
+ Gitlab::ExclusiveLease.new(key, uuid: uuid, timeout: LEASE_TIMEOUT)
+ end
+ strong_memoize_attr :exclusive_lease
+
+ def syncing?
+ exclusive_lease.exists?
+ end
+
+ def has_conflicts?
+ !(attrs && attrs[:has_conflicts]).nil?
+ end
+
+ def update!(params)
+ Rails.cache.write(cache_key, params, expires_in: EXPIRATION_TIME)
+
+ @attrs = nil
+ end
+
+ private
+
+ attr_reader :project, :fork_repo, :source_repo, :ref
+
+ def cache_key
+ @cache_key ||= ['project_fork_details', project.id, ref].join(':')
+ end
+
+ def divergence_counts
+ sha = fork_repo.commit(ref)&.sha
+ source_sha = source_repo.commit&.sha
+
+ return if sha.blank? || source_sha.blank?
+
+ return attrs[:counts] if attrs.present? && attrs[:source_sha] == source_sha && attrs[:sha] == sha
+
+ counts = calculate_divergence_counts(sha, source_sha)
+
+ update!({ sha: sha, source_sha: source_sha, counts: counts })
+
+ counts
+ end
+
+ def calculate_divergence_counts(sha, source_sha)
+ # If the upstream latest commit exists in the fork repo, then
+ # it's possible to calculate divergence counts within the fork repository.
+ return fork_repo.diverging_commit_count(sha, source_sha) if fork_repo.commit(source_sha)
+
+ # Otherwise, we need to find a commit that exists both in the fork and upstream
+ # in order to use this commit as a base for calculating divergence counts.
+ # Considering the fact that a user usually creates a fork to contribute to the upstream,
+ # it is expected that they have a limited number of commits ahead of upstream.
+ # Let's take the latest N commits and check their existence upstream.
+ last_commits_shas = fork_repo.commits(ref, limit: LATEST_COMMITS_COUNT).map(&:sha)
+ existence_hash = source_repo.check_objects_exist(last_commits_shas)
+ first_matched_commit_sha = last_commits_shas.find { |sha| existence_hash[sha] }
+
+ # If we can't find such a commit, we return early and tell the user that the branches
+ # have diverged and action is required.
+ return unless first_matched_commit_sha
+
+ # Otherwise, we use upstream to calculate divergence counts from the matched commit
+ ahead, behind = source_repo.diverging_commit_count(first_matched_commit_sha, source_sha)
+ # And add the number of commits a fork is ahead of the first matched commit
+ ahead += last_commits_shas.index(first_matched_commit_sha)
+
+ [ahead, behind]
+ end
+
+ def attrs
+ @attrs ||= Rails.cache.read(cache_key)
+ end
+ end
+ end
+end
diff --git a/app/models/projects/forks/divergence_counts.rb b/app/models/projects/forks/divergence_counts.rb
deleted file mode 100644
index 7d630b00083..00000000000
--- a/app/models/projects/forks/divergence_counts.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# frozen_string_literal: true
-
-module Projects
- module Forks
- # Class for calculating the divergence of a fork with the source project
- class DivergenceCounts
- LATEST_COMMITS_COUNT = 10
- EXPIRATION_TIME = 8.hours
-
- def initialize(project, ref)
- @project = project
- @fork_repo = project.repository
- @source_repo = project.fork_source.repository
- @ref = ref
- end
-
- def counts
- ahead, behind = divergence_counts
-
- { ahead: ahead, behind: behind }
- end
-
- private
-
- attr_reader :project, :fork_repo, :source_repo, :ref
-
- def cache_key
- @cache_key ||= ['project_forks', project.id, ref, 'divergence_counts']
- end
-
- def divergence_counts
- fork_sha = fork_repo.commit(ref).sha
- source_sha = source_repo.commit.sha
-
- cached_source_sha, cached_fork_sha, counts = Rails.cache.read(cache_key)
- return counts if cached_source_sha == source_sha && cached_fork_sha == fork_sha
-
- counts = calculate_divergence_counts(fork_sha, source_sha)
-
- Rails.cache.write(cache_key, [source_sha, fork_sha, counts], expires_in: EXPIRATION_TIME)
-
- counts
- end
-
- def calculate_divergence_counts(fork_sha, source_sha)
- # If the upstream latest commit exists in the fork repo, then
- # it's possible to calculate divergence counts within the fork repository.
- return fork_repo.diverging_commit_count(fork_sha, source_sha) if fork_repo.commit(source_sha)
-
- # Otherwise, we need to find a commit that exists both in the fork and upstream
- # in order to use this commit as a base for calculating divergence counts.
- # Considering the fact that a user usually creates a fork to contribute to the upstream,
- # it is expected that they have a limited number of commits ahead of upstream.
- # Let's take the latest N commits and check their existence upstream.
- last_commits_shas = fork_repo.commits(ref, limit: LATEST_COMMITS_COUNT).map(&:sha)
- existence_hash = source_repo.check_objects_exist(last_commits_shas)
- first_matched_commit_sha = last_commits_shas.find { |sha| existence_hash[sha] }
-
- # If we can't find such a commit, we return early and tell the user that the branches
- # have diverged and action is required.
- return unless first_matched_commit_sha
-
- # Otherwise, we use upstream to calculate divergence counts from the matched commit
- ahead, behind = source_repo.diverging_commit_count(first_matched_commit_sha, source_sha)
- # And add the number of commits a fork is ahead of the first matched commit
- ahead += last_commits_shas.index(first_matched_commit_sha)
-
- [ahead, behind]
- end
- end
- end
-end
diff --git a/app/models/projects/import_export/relation_export.rb b/app/models/projects/import_export/relation_export.rb
index 9bdf10d7c0e..2771c5131b2 100644
--- a/app/models/projects/import_export/relation_export.rb
+++ b/app/models/projects/import_export/relation_export.rb
@@ -51,12 +51,16 @@ module Projects
transition queued: :started
end
+ event :retry do
+ transition started: :queued
+ end
+
event :finish do
transition started: :finished
end
event :fail_op do
- transition [:queued, :started] => :failed
+ transition [:queued, :started, :failed] => :failed
end
end
@@ -65,6 +69,14 @@ module Projects
project_tree_relation_names + EXTRA_RELATION_LIST
end
+
+ def mark_as_failed(export_error)
+ sanitized_error = Gitlab::UrlSanitizer.sanitize(export_error)
+
+ fail_op
+
+ update_column(:export_error, sanitized_error)
+ end
end
end
end
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
index b3331b99a6b..22eaac94897 100644
--- a/app/models/protected_branch.rb
+++ b/app/models/protected_branch.rb
@@ -37,38 +37,13 @@ class ProtectedBranch < ApplicationRecord
return true if project.empty_repo? && project.default_branch_protected?
return false if ref_name.blank?
- dry_run = Feature.disabled?(:rely_on_protected_branches_cache, project)
-
- new_cache_result = new_cache(project, ref_name, dry_run: dry_run)
-
- return new_cache_result unless new_cache_result.nil?
-
- deprecated_cache(project, ref_name)
- end
-
- def self.new_cache(project, ref_name, dry_run: true)
- ProtectedBranches::CacheService.new(project).fetch(ref_name, dry_run: dry_run) do # rubocop: disable CodeReuse/ServiceClass
- self.matching(ref_name, protected_refs: protected_refs(project)).present?
- end
- end
-
- # Deprecated: https://gitlab.com/gitlab-org/gitlab/-/issues/370608
- # ----------------------------------------------------------------
- CACHE_EXPIRE_IN = 1.hour
-
- def self.deprecated_cache(project, ref_name)
- Rails.cache.fetch(protected_ref_cache_key(project, ref_name), expires_in: CACHE_EXPIRE_IN) do
+ ProtectedBranches::CacheService.new(project).fetch(ref_name) do # rubocop: disable CodeReuse/ServiceClass
self.matching(ref_name, protected_refs: protected_refs(project)).present?
end
end
- def self.protected_ref_cache_key(project, ref_name)
- "protected_ref-#{project.cache_key}-#{Digest::SHA1.hexdigest(ref_name)}"
- end
- # End of deprecation --------------------------------------------
-
def self.allow_force_push?(project, ref_name)
- if Feature.enabled?(:group_protected_branches)
+ if Feature.enabled?(:group_protected_branches, project.group)
protected_branches = project.all_protected_branches.matching(ref_name)
project_protected_branches, group_protected_branches = protected_branches.partition(&:project_id)
@@ -92,11 +67,7 @@ class ProtectedBranch < ApplicationRecord
end
def self.protected_refs(project)
- if Feature.enabled?(:group_protected_branches)
- project.all_protected_branches
- else
- project.protected_branches
- end
+ project.all_protected_branches
end
# overridden in EE
diff --git a/app/models/repository.rb b/app/models/repository.rb
index d15f2a430fa..587b71315c2 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -48,7 +48,7 @@ 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 commit_count readme_path contribution_guide
- changelog license_blob license_licensee license_gitaly gitignore
+ 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
@@ -60,7 +60,7 @@ class Repository
METHOD_CACHES_FOR_FILE_TYPES = {
readme: %i(readme_path),
changelog: :changelog,
- license: %i(license_blob license_licensee license_gitaly),
+ license: %i(license_blob license_gitaly),
contributing: :contribution_guide,
gitignore: :gitignore,
gitlab_ci: :gitlab_ci_yml,
@@ -161,7 +161,8 @@ class Repository
first_parent: !!opts[:first_parent],
order: opts[:order],
literal_pathspec: opts.fetch(:literal_pathspec, true),
- trailers: opts[:trailers]
+ trailers: opts[:trailers],
+ include_referenced_by: opts[:include_referenced_by]
}
commits = Gitlab::Git::Commit.where(options)
@@ -655,24 +656,13 @@ class Repository
end
def license
- if Feature.enabled?(:license_from_gitaly)
- license_gitaly
- else
- license_licensee
- end
- end
-
- def license_licensee
- return unless exists?
-
- raw_repository.license(false)
+ license_gitaly
end
- cache_method :license_licensee
def license_gitaly
return unless exists?
- raw_repository.license(true)
+ raw_repository.license
end
cache_method :license_gitaly
@@ -844,6 +834,26 @@ class Repository
commit_files(user, **options)
end
+ def move_dir_files(user, path, previous_path, **options)
+ regex = Regexp.new("^#{Regexp.escape(previous_path + '/')}", 'i')
+ files = ls_files(options[:branch_name])
+
+ options[:actions] = files.each_with_object([]) do |item, list|
+ next unless item =~ regex
+
+ list.push(
+ action: :move,
+ file_path: "#{path}/#{item[regex.match(item)[0].size..]}",
+ previous_path: item,
+ infer_content: true
+ )
+ end
+
+ return if options[:actions].blank?
+
+ commit_files(user, **options)
+ end
+
def delete_file(user, path, **options)
options[:actions] = [{ action: :delete, file_path: path }]
@@ -948,6 +958,8 @@ class Repository
end
def merged_to_root_ref?(branch_or_name)
+ return unless head_commit
+
branch = Gitlab::Git::Branch.find(self, branch_or_name)
if branch
@@ -960,7 +972,7 @@ class Repository
end
def root_ref_sha
- @root_ref_sha ||= commit(root_ref).sha
+ @root_ref_sha ||= head_commit.sha
end
# If this method is not provided a set of branch names to check merge status,
diff --git a/app/models/resource_label_event.rb b/app/models/resource_label_event.rb
index efffc1bd6dc..13610d37a74 100644
--- a/app/models/resource_label_event.rb
+++ b/app/models/resource_label_event.rb
@@ -29,9 +29,8 @@ class ResourceLabelEvent < ResourceEvent
labels = events.map(&:label).compact
project_labels, group_labels = labels.partition { |label| label.is_a? ProjectLabel }
- preloader = ActiveRecord::Associations::Preloader.new
- preloader.preload(project_labels, { project: :project_feature })
- preloader.preload(group_labels, :group)
+ ActiveRecord::Associations::Preloader.new(records: project_labels, associations: { project: :project_feature }).call
+ ActiveRecord::Associations::Preloader.new(records: group_labels, associations: :group).call
end
def issuable
diff --git a/app/models/resource_milestone_event.rb b/app/models/resource_milestone_event.rb
index def7e91af3f..f3301ee2051 100644
--- a/app/models/resource_milestone_event.rb
+++ b/app/models/resource_milestone_event.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
class ResourceMilestoneEvent < ResourceTimeboxEvent
- include IgnorableColumns
-
belongs_to :milestone
scope :include_relations, -> { includes(:user, milestone: [:project, :group]) }
@@ -10,8 +8,6 @@ class ResourceMilestoneEvent < ResourceTimeboxEvent
# state is used for issue and merge request states.
enum state: Issue.available_states.merge(MergeRequest.available_states)
- ignore_columns %i[reference reference_html cached_markdown_version], remove_with: '13.1', remove_after: '2020-06-22'
-
def milestone_title
milestone&.title
end
diff --git a/app/models/serverless/domain.rb b/app/models/serverless/domain.rb
deleted file mode 100644
index 164f93afa9a..00000000000
--- a/app/models/serverless/domain.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-module Serverless
- class Domain
- include ActiveModel::Model
-
- REGEXP = %r{^(?<scheme>https?://)?(?<function_name>[^.]+)-(?<cluster_left>\h{2})a1(?<cluster_middle>\h{10})f2(?<cluster_right>\h{2})(?<environment_id>\h+)-(?<environment_slug>[^.]+)\.(?<pages_domain_name>.+)}.freeze
- UUID_LENGTH = 14
-
- attr_accessor :function_name, :serverless_domain_cluster, :environment
-
- validates :function_name, presence: true, allow_blank: false
- validates :serverless_domain_cluster, presence: true
- validates :environment, presence: true
-
- def self.generate_uuid
- SecureRandom.hex(UUID_LENGTH / 2)
- end
-
- def uri
- URI("https://#{function_name}-#{serverless_domain_cluster_uuid}#{"%x" % environment.id}-#{environment.slug}.#{serverless_domain_cluster.domain}")
- end
-
- def knative_uri
- URI("http://#{function_name}.#{namespace}.#{serverless_domain_cluster.knative.hostname}")
- end
-
- private
-
- def namespace
- serverless_domain_cluster.cluster.kubernetes_namespace_for(environment)
- end
-
- def serverless_domain_cluster_uuid
- [
- serverless_domain_cluster.uuid[0..1],
- 'a1',
- serverless_domain_cluster.uuid[2..-3],
- 'f2',
- serverless_domain_cluster.uuid[-2..]
- ].join
- end
- end
-end
diff --git a/app/models/serverless/domain_cluster.rb b/app/models/serverless/domain_cluster.rb
deleted file mode 100644
index 561bfc65b2b..00000000000
--- a/app/models/serverless/domain_cluster.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-
-module Serverless
- class DomainCluster < ApplicationRecord
- self.table_name = 'serverless_domain_cluster'
-
- HEX_REGEXP = %r{\A\h+\z}.freeze
-
- belongs_to :pages_domain
- belongs_to :knative, class_name: 'Clusters::Applications::Knative', foreign_key: 'clusters_applications_knative_id'
- belongs_to :creator, class_name: 'User', optional: true
-
- attr_encrypted :key,
- mode: :per_attribute_iv,
- key: Settings.attr_encrypted_db_key_base_32,
- algorithm: 'aes-256-gcm'
-
- validates :pages_domain, :knative, presence: true
- validates :uuid, presence: true, uniqueness: true, length: { is: ::Serverless::Domain::UUID_LENGTH },
- format: { with: HEX_REGEXP, message: 'only allows hex characters' }
-
- after_initialize :set_uuid, if: :new_record?
-
- delegate :domain, to: :pages_domain
- delegate :cluster, to: :knative
-
- def self.for_uuid(uuid)
- joins(:pages_domain, :knative)
- .includes(:pages_domain, :knative)
- .find_by(uuid: uuid)
- end
-
- private
-
- def set_uuid
- self.uuid = ::Serverless::Domain.generate_uuid
- end
- end
-end
diff --git a/app/models/serverless/function.rb b/app/models/serverless/function.rb
deleted file mode 100644
index 5d4f8e0c9e2..00000000000
--- a/app/models/serverless/function.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-module Serverless
- class Function
- attr_accessor :name, :namespace
-
- def initialize(project, name, namespace)
- @project = project
- @name = name
- @namespace = namespace
- end
-
- def id
- @project.id.to_s + "/" + @name + "/" + @namespace
- end
-
- def self.find_by_id(id)
- array = id.split("/")
- project = Project.find_by_id(array[0])
- name = array[1]
- namespace = array[2]
-
- self.new(project, name, namespace)
- end
- end
-end
diff --git a/app/models/serverless/lookup_path.rb b/app/models/serverless/lookup_path.rb
deleted file mode 100644
index c09b3718651..00000000000
--- a/app/models/serverless/lookup_path.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-module Serverless
- class LookupPath
- attr_reader :serverless_domain
-
- delegate :serverless_domain_cluster, to: :serverless_domain
- delegate :knative, to: :serverless_domain_cluster
- delegate :certificate, to: :serverless_domain_cluster
- delegate :key, to: :serverless_domain_cluster
-
- def initialize(serverless_domain)
- @serverless_domain = serverless_domain
- end
-
- def source
- {
- type: 'serverless',
- service: serverless_domain.knative_uri.host,
- cluster: {
- hostname: knative.hostname,
- address: knative.external_ip,
- port: 443,
- cert: certificate,
- key: key
- }
- }
- end
- end
-end
diff --git a/app/models/serverless/virtual_domain.rb b/app/models/serverless/virtual_domain.rb
deleted file mode 100644
index d6a23a4c0ce..00000000000
--- a/app/models/serverless/virtual_domain.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-module Serverless
- class VirtualDomain
- attr_reader :serverless_domain
-
- delegate :serverless_domain_cluster, to: :serverless_domain
- delegate :pages_domain, to: :serverless_domain_cluster
- delegate :certificate, to: :pages_domain
- delegate :key, to: :pages_domain
-
- def initialize(serverless_domain)
- @serverless_domain = serverless_domain
- end
-
- def lookup_paths
- [
- ::Serverless::LookupPath.new(serverless_domain)
- ]
- end
- end
-end
diff --git a/app/models/service_desk.rb b/app/models/service_desk.rb
new file mode 100644
index 00000000000..cb9c924c01f
--- /dev/null
+++ b/app/models/service_desk.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module ServiceDesk
+ def self.table_name_prefix
+ 'service_desk_'
+ end
+end
diff --git a/app/models/service_desk/custom_email_verification.rb b/app/models/service_desk/custom_email_verification.rb
new file mode 100644
index 00000000000..b3b9390bb82
--- /dev/null
+++ b/app/models/service_desk/custom_email_verification.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+module ServiceDesk
+ class CustomEmailVerification < ApplicationRecord
+ enum state: {
+ running: 0,
+ verified: 1,
+ error: 2
+ }, _default: 'running'
+
+ enum error: {
+ incorrect_token: 0,
+ incorrect_from: 1,
+ mail_not_received_within_timeframe: 2,
+ invalid_credentials: 3,
+ smtp_host_issue: 4
+ }
+
+ TIMEFRAME = 30.minutes
+
+ attr_encrypted :token,
+ mode: :per_attribute_iv,
+ algorithm: 'aes-256-gcm',
+ key: Settings.attr_encrypted_db_key_base_32,
+ encode: false,
+ encode_iv: false
+
+ belongs_to :project
+ belongs_to :triggerer, class_name: 'User', optional: true
+
+ validates :project, presence: true
+ validates :state, presence: true
+
+ delegate :service_desk_setting, to: :project
+
+ class << self
+ def generate_token
+ SecureRandom.alphanumeric(12)
+ end
+ end
+
+ def accepted_until
+ return unless running?
+ return unless triggered_at.present?
+
+ TIMEFRAME.since(triggered_at)
+ end
+
+ def in_timeframe?
+ return false unless running?
+
+ !!accepted_until&.future?
+ end
+ end
+end
diff --git a/app/models/service_desk_setting.rb b/app/models/service_desk_setting.rb
index 5152746abb4..69afb445734 100644
--- a/app/models/service_desk_setting.rb
+++ b/app/models/service_desk_setting.rb
@@ -3,6 +3,8 @@
class ServiceDeskSetting < ApplicationRecord
include Gitlab::Utils::StrongMemoize
+ CUSTOM_EMAIL_VERIFICATION_SUBADDRESS = '+verify'
+
attribute :custom_email_enabled, default: false
attr_encrypted :custom_email_smtp_password,
mode: :per_attribute_iv,
@@ -12,6 +14,7 @@ class ServiceDeskSetting < ApplicationRecord
encode_iv: false
belongs_to :project
+
validates :project_id, presence: true
validate :valid_issue_template
validate :valid_project_key
@@ -32,21 +35,25 @@ class ServiceDeskSetting < ApplicationRecord
validates :custom_email,
presence: true,
devise_email: true,
- if: :custom_email_enabled?
+ if: :needs_custom_email_smtp_credentials?
validates :custom_email_smtp_address,
presence: true,
hostname: { allow_numeric_hostname: true, require_valid_tld: true },
- if: :custom_email_enabled?
+ if: :needs_custom_email_smtp_credentials?
validates :custom_email_smtp_username,
presence: true,
- if: :custom_email_enabled?
+ if: :needs_custom_email_smtp_credentials?
validates :custom_email_smtp_port,
presence: true,
numericality: { only_integer: true, greater_than: 0 },
- if: :custom_email_enabled?
+ if: :needs_custom_email_smtp_credentials?
scope :with_project_key, ->(key) { where(project_key: key) }
+ def custom_email_verification
+ project&.service_desk_custom_email_verification
+ end
+
def custom_email_delivery_options
{
user_name: custom_email_smtp_username,
@@ -57,6 +64,12 @@ class ServiceDeskSetting < ApplicationRecord
}
end
+ def custom_email_address_for_verification
+ return unless custom_email.present?
+
+ custom_email.sub("@", "#{CUSTOM_EMAIL_VERIFICATION_SUBADDRESS}@")
+ end
+
def issue_template_content
strong_memoize(:issue_template_content) do
next unless issue_template_key.present?
@@ -102,6 +115,10 @@ class ServiceDeskSetting < ApplicationRecord
setting.project.full_path_slug == project_slug
end
end
+
+ def needs_custom_email_smtp_credentials?
+ custom_email_enabled? || custom_email_verification.present?
+ end
end
ServiceDeskSetting.prepend_mod
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 9ec685c5580..8ed5513aab9 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -183,7 +183,7 @@ class Snippet < ApplicationRecord
end
def link_reference_pattern
- @link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/)
+ @link_reference_pattern ||= compose_link_reference_pattern('snippets', /(?<snippet>\d+)/)
end
def find_by_id_and_project(id:, project:)
@@ -203,14 +203,7 @@ class Snippet < ApplicationRecord
end
def initialize(attributes = {})
- # We can't use default_value_for because the database has a default
- # value of 0 for visibility_level. If someone attempts to create a
- # private snippet, default_value_for will assume that the
- # visibility_level hasn't changed and will use the application
- # setting default, which could be internal or public.
- #
- # To fix the problem, we assign the actual snippet default if no
- # explicit visibility has been initialized.
+ # We assign the actual snippet default if no explicit visibility has been initialized.
attributes ||= {}
unless visibility_attribute_present?(attributes)
diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb
index bb8527d8c01..0e0534d45ae 100644
--- a/app/models/system_note_metadata.rb
+++ b/app/models/system_note_metadata.rb
@@ -26,8 +26,7 @@ class SystemNoteMetadata < ApplicationRecord
title time_tracking branch milestone discussion task moved cloned
opened closed merged duplicate locked unlocked outdated reviewer
tag due_date start_date_or_due_date pinned_embed cherry_pick health_status approved unapproved
- status alert_issue_added relate unrelate new_alert_added severity
- attention_requested attention_request_removed contact timeline_event
+ status alert_issue_added relate unrelate new_alert_added severity contact timeline_event
issue_type relate_to_child unrelate_from_child relate_to_parent unrelate_from_parent
].freeze
diff --git a/app/models/user.rb b/app/models/user.rb
index f3e8f14adf5..3bd8a035357 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -28,6 +28,7 @@ class User < ApplicationRecord
include UpdateHighestRole
include HasUserType
include Gitlab::Auth::Otp::Fortinet
+ include Gitlab::Auth::Otp::DuoAuth
include RestrictedSignup
include StripAttribute
include EachBatch
@@ -71,6 +72,7 @@ class User < ApplicationRecord
attribute :notified_of_own_activity, default: false
attribute :preferred_language, default: -> { Gitlab::CurrentSettings.default_preferred_language }
attribute :theme_id, default: -> { gitlab_config.default_theme }
+ attribute :color_scheme_id, default: -> { Gitlab::CurrentSettings.default_syntax_highlighting_theme }
attr_encrypted :otp_secret,
key: Gitlab::Application.secrets.otp_key_base,
@@ -101,8 +103,6 @@ class User < ApplicationRecord
MINIMUM_DAYS_CREATED = 7
- ignore_columns %i[linkedin twitter skype website_url location organization], remove_with: '15.10', remove_after: '2023-02-22'
-
# Override Devise::Models::Trackable#update_tracked_fields!
# to limit database writes to at most once every hour
# rubocop: disable CodeReuse/ServiceClass
@@ -227,7 +227,9 @@ class User < ApplicationRecord
has_many :notification_settings
has_many :award_emoji, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :triggers, class_name: 'Ci::Trigger', foreign_key: :owner_id
+ has_many :audit_events, foreign_key: :author_id, inverse_of: :user
+ has_many :alert_assignees, class_name: '::AlertManagement::AlertAssignee', inverse_of: :assignee
has_many :issue_assignees, inverse_of: :assignee
has_many :merge_request_assignees, inverse_of: :assignee, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :merge_request_reviewers, inverse_of: :reviewer, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -289,7 +291,7 @@ class User < ApplicationRecord
validate :check_password_weakness, if: :encrypted_password_changed?
validates :namespace, presence: true
- validate :namespace_move_dir_allowed, if: :username_changed?
+ validate :namespace_move_dir_allowed, if: :username_changed?, unless: :new_record?
validate :unique_email, if: :email_changed?
validate :notification_email_verified, if: :notification_email_changed?
@@ -614,13 +616,12 @@ class User < ApplicationRecord
def self.with_two_factor
where(otp_required_for_login: true)
- .or(where_exists(U2fRegistration.where(U2fRegistration.arel_table[:user_id].eq(arel_table[:id]))))
.or(where_exists(WebauthnRegistration.where(WebauthnRegistration.arel_table[:user_id].eq(arel_table[:id]))))
end
def self.without_two_factor
where
- .missing(:u2f_registrations, :webauthn_registrations)
+ .missing(:webauthn_registrations)
.where(otp_required_for_login: false)
end
@@ -1062,27 +1063,14 @@ class User < ApplicationRecord
end
def two_factor_enabled?
- two_factor_otp_enabled? || two_factor_webauthn_u2f_enabled?
+ two_factor_otp_enabled? || two_factor_webauthn_enabled?
end
def two_factor_otp_enabled?
otp_required_for_login? ||
forti_authenticator_enabled?(self) ||
- forti_token_cloud_enabled?(self)
- end
-
- def two_factor_u2f_enabled?
- return false if Feature.enabled?(:webauthn)
-
- if u2f_registrations.loaded?
- u2f_registrations.any?
- else
- u2f_registrations.exists?
- end
- end
-
- def two_factor_webauthn_u2f_enabled?
- two_factor_u2f_enabled? || two_factor_webauthn_enabled?
+ forti_token_cloud_enabled?(self) ||
+ duo_auth_enabled?(self)
end
def two_factor_webauthn_enabled?
@@ -1725,11 +1713,7 @@ class User < ApplicationRecord
end
def manageable_groups(include_groups_with_developer_maintainer_access: false)
- owned_and_maintainer_group_hierarchy = if Feature.enabled?(:linear_user_manageable_groups, self)
- owned_or_maintainers_groups.self_and_descendants
- else
- Gitlab::ObjectHierarchy.new(owned_or_maintainers_groups).base_and_descendants
- end
+ owned_and_maintainer_group_hierarchy = owned_or_maintainers_groups.self_and_descendants
if include_groups_with_developer_maintainer_access
union_sql = ::Gitlab::SQL::Union.new(
@@ -2136,7 +2120,15 @@ class User < ApplicationRecord
end
def confirmation_required_on_sign_in?
- !confirmed? && !confirmation_period_valid?
+ return false if confirmed?
+
+ if ::Gitlab::CurrentSettings.email_confirmation_setting_off?
+ false
+ elsif ::Gitlab::CurrentSettings.email_confirmation_setting_soft?
+ !in_confirmation_period?
+ elsif ::Gitlab::CurrentSettings.email_confirmation_setting_hard?
+ true
+ end
end
def impersonated?
@@ -2217,10 +2209,13 @@ class User < ApplicationRecord
# override from Devise::Confirmable
def confirmation_period_valid?
- return false if Feature.disabled?(:soft_email_confirmation)
+ return super if ::Gitlab::CurrentSettings.email_confirmation_setting_soft?
- super
+ # Following devise logic for method, we want to return `true`
+ # See: https://github.com/heartcombo/devise/blob/main/lib/devise/models/confirmable.rb#L191-L218
+ true
end
+ alias_method :in_confirmation_period?, :confirmation_period_valid?
# This is copied from Devise::Models::TwoFactorAuthenticatable#consume_otp!
#
diff --git a/app/models/user_status.rb b/app/models/user_status.rb
index 0c66f465356..da24ef47a2a 100644
--- a/app/models/user_status.rb
+++ b/app/models/user_status.rb
@@ -17,7 +17,7 @@ class UserStatus < ApplicationRecord
'30_days' => 30.days
}.freeze
- belongs_to :user
+ belongs_to :user, inverse_of: :status
enum availability: { not_set: 0, busy: 1 }
diff --git a/app/models/users/banned_user.rb b/app/models/users/banned_user.rb
index 615668e2b55..466fc71f83a 100644
--- a/app/models/users/banned_user.rb
+++ b/app/models/users/banned_user.rb
@@ -10,3 +10,5 @@ module Users
validates :user_id, uniqueness: { message: N_("banned user already exists") }
end
end
+
+Users::BannedUser.prepend_mod_with('Users::BannedUser')
diff --git a/app/models/users/callout.rb b/app/models/users/callout.rb
index 3f9353214ee..70c31f0a8ec 100644
--- a/app/models/users/callout.rb
+++ b/app/models/users/callout.rb
@@ -65,7 +65,8 @@ module Users
new_top_level_group_alert: 61,
artifacts_management_page_feedback_banner: 62,
vscode_web_ide: 63,
- vscode_web_ide_callout: 64
+ vscode_web_ide_callout: 64,
+ branch_rules_info_callout: 65
}
validates :feature_name,
diff --git a/app/models/users/group_callout.rb b/app/models/users/group_callout.rb
index 2552407fa4c..fe04800539c 100644
--- a/app/models/users/group_callout.rb
+++ b/app/models/users/group_callout.rb
@@ -24,7 +24,9 @@ module Users
namespace_storage_limit_banner_error_threshold: 13, # EE-only
usage_quota_trial_alert: 14, # EE-only
preview_usage_quota_free_plan_alert: 15, # EE-only
- enforcement_at_limit_alert: 16 # EE-only
+ enforcement_at_limit_alert: 16, # EE-only
+ web_hook_disabled: 17, # EE-only
+ unlimited_members_during_trial_alert: 18 # EE-only
}
validates :group, presence: true
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
index 57488749b76..33b2b3b7c87 100644
--- a/app/models/wiki.rb
+++ b/app/models/wiki.rb
@@ -326,6 +326,11 @@ class Wiki
content,
previous_path: page.path,
**multi_commit_options(:updated, message, title))
+ repository.move_dir_files(
+ user,
+ sluggified_title(title),
+ page.url_path,
+ **multi_commit_options(:moved, message, title))
after_wiki_activity
diff --git a/app/models/wiki_directory.rb b/app/models/wiki_directory.rb
index 76fe664f23d..e57d186a3e3 100644
--- a/app/models/wiki_directory.rb
+++ b/app/models/wiki_directory.rb
@@ -7,34 +7,48 @@ class WikiDirectory
validates :slug, presence: true
alias_method :to_param, :slug
- # Groups a list of wiki pages into a nested collection of WikiPage and WikiDirectory objects,
- # preserving the order of the passed pages.
- #
- # Returns an array with all entries for the toplevel directory.
- #
- # @param [Array<WikiPage>] pages
- # @return [Array<WikiPage, WikiDirectory>]
- #
- def self.group_pages(pages)
- # Build a hash to map paths to created WikiDirectory objects,
- # and recursively create them for each level of the path.
- # For the toplevel directory we use '' as path, as that's what WikiPage#directory returns.
- directories = Hash.new do |_, path|
- directories[path] = new(path).tap do |directory|
- if path.present?
- parent = File.dirname(path)
- parent = '' if parent == '.'
- directories[parent].entries << directory
- directories[parent].entries.delete_if { |item| item.is_a?(WikiPage) && item.slug == directory.slug }
+ class << self
+ # Groups a list of wiki pages into a nested collection of WikiPage and WikiDirectory objects,
+ # preserving the order of the passed pages.
+ #
+ # Returns an array with all entries for the toplevel directory.
+ #
+ # @param [Array<WikiPage>] pages
+ # @return [Array<WikiPage, WikiDirectory>]
+ #
+ def group_pages(pages)
+ # Build a hash to map paths to created WikiDirectory objects,
+ # and recursively create them for each level of the path.
+ # For the toplevel directory we use '' as path, as that's what WikiPage#directory returns.
+ directories = Hash.new do |_, path|
+ directories[path] = new(path).tap do |directory|
+ if path.present?
+ parent = File.dirname(path)
+ parent = '' if parent == '.'
+ directories[parent].entries << directory
+ directories[parent].entries.delete_if do |item|
+ item.is_a?(WikiPage) && item.slug.casecmp?(directory.slug)
+ end
+ end
end
end
- end
- pages.each do |page|
- directories[page.directory].entries << page
+ pages.each do |page|
+ next unless directory_for_page?(directories[page.directory], page)
+
+ directories[page.directory].entries << page
+ end
+
+ directories[''].entries
end
- directories[''].entries
+ private
+
+ def directory_for_page?(directory, page)
+ directory.entries.none? do |item|
+ item.is_a?(WikiDirectory) && item.slug.casecmp?(page.slug)
+ end
+ end
end
def initialize(slug, entries = [])
diff --git a/app/models/work_item.rb b/app/models/work_item.rb
index 5ae3fb6cf78..a7cd522f023 100644
--- a/app/models/work_item.rb
+++ b/app/models/work_item.rb
@@ -85,6 +85,26 @@ class WorkItem < Issue
COMMON_QUICK_ACTIONS_COMMANDS + commands_for_widgets
end
+ # Widgets have a set of quick action params that they must process.
+ # Map them to widget_params so they can be picked up by widget services.
+ def transform_quick_action_params(command_params)
+ common_params = command_params.deep_dup
+ widget_params = {}
+
+ work_item_type.widgets
+ .filter { |widget| widget.respond_to?(:quick_action_params) }
+ .each do |widget|
+ widget.quick_action_params
+ .filter { |param_name| common_params.key?(param_name) }
+ .each do |param_name|
+ widget_params[widget.api_symbol] ||= {}
+ widget_params[widget.api_symbol][param_name] = common_params.delete(param_name)
+ end
+ end
+
+ { common: common_params, widgets: widget_params }
+ end
+
private
override :parent_link_confidentiality
diff --git a/app/models/work_items/widget_definition.rb b/app/models/work_items/widget_definition.rb
index 5d4414e95d8..9e8c421d740 100644
--- a/app/models/work_items/widget_definition.rb
+++ b/app/models/work_items/widget_definition.rb
@@ -28,7 +28,8 @@ module WorkItems
progress: 10, # EE-only
status: 11, # EE-only
requirement_legacy: 12, # EE-only
- test_reports: 13 # EE-only
+ test_reports: 13, # EE-only
+ notifications: 14
}
def self.available_widgets
diff --git a/app/models/work_items/widgets/notifications.rb b/app/models/work_items/widgets/notifications.rb
new file mode 100644
index 00000000000..9a13e5ebbea
--- /dev/null
+++ b/app/models/work_items/widgets/notifications.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ class Notifications < Base
+ delegate :subscribed?, to: :work_item
+ end
+ end
+end
diff --git a/app/policies/achievements/user_achievement_policy.rb b/app/policies/achievements/user_achievement_policy.rb
new file mode 100644
index 00000000000..b500d0a25c8
--- /dev/null
+++ b/app/policies/achievements/user_achievement_policy.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module Achievements
+ class UserAchievementPolicy < ::BasePolicy
+ delegate { @subject.achievement.namespace }
+ end
+end
diff --git a/app/policies/ci/pipeline_schedule_policy.rb b/app/policies/ci/pipeline_schedule_policy.rb
index 3a674bfef92..7b0d484f9f7 100644
--- a/app/policies/ci/pipeline_schedule_policy.rb
+++ b/app/policies/ci/pipeline_schedule_policy.rb
@@ -23,6 +23,10 @@ module Ci
enable :update_pipeline_schedule
end
+ # `take_ownership_pipeline_schedule` is deprecated, and should not be used. It can be removed in 17.0
+ # once the deprecated field `take_ownership_pipeline_schedule` is removed from the GraphQL type
+ # `PermissionTypes::Ci::PipelineSchedules`.
+ # Use `admin_pipeline_schedule` to decide if a user has the ability to take ownership of a pipeline schedule.
rule { can?(:admin_pipeline_schedule) & ~owner_of_schedule }.policy do
enable :take_ownership_pipeline_schedule
end
diff --git a/app/policies/ci/runner_machine_policy.rb b/app/policies/ci/runner_machine_policy.rb
new file mode 100644
index 00000000000..9893d7dee14
--- /dev/null
+++ b/app/policies/ci/runner_machine_policy.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Ci
+ class RunnerMachinePolicy < BasePolicy
+ with_options scope: :subject, score: 0
+
+ condition(:can_read_runner, scope: :subject) do
+ can?(:read_runner, @subject.runner)
+ end
+
+ rule { anonymous }.prevent_all
+
+ rule { can_read_runner }.policy do
+ enable :read_builds
+ enable :read_runner_machine
+ end
+ end
+end
diff --git a/app/policies/clusters/instance_policy.rb b/app/policies/clusters/instance_policy.rb
index 3c5ca4bf4e1..2781e943bae 100644
--- a/app/policies/clusters/instance_policy.rb
+++ b/app/policies/clusters/instance_policy.rb
@@ -9,6 +9,7 @@ module Clusters
enable :update_cluster
enable :admin_cluster
enable :read_prometheus
+ enable :use_k8s_proxies
end
end
end
diff --git a/app/policies/concerns/archived_abilities.rb b/app/policies/concerns/archived_abilities.rb
index b4dfad599c7..7d61f83528e 100644
--- a/app/policies/concerns/archived_abilities.rb
+++ b/app/policies/concerns/archived_abilities.rb
@@ -37,6 +37,7 @@ module ArchivedAbilities
pages
cluster
release
+ timelog
].freeze
class_methods do
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index d028738ccc9..b64e7e16433 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -23,9 +23,11 @@ class GlobalPolicy < BasePolicy
condition(:migration_bot, scope: :user) { @user&.migration_bot? }
condition(:create_runner_workflow_enabled) do
- Feature.enabled?(:create_runner_workflow)
+ Feature.enabled?(:create_runner_workflow_for_admin, @user)
end
+ condition(:service_account, scope: :user) { @user&.service_account? }
+
rule { anonymous }.policy do
prevent :log_in
prevent :receive_notifications
@@ -64,7 +66,7 @@ class GlobalPolicy < BasePolicy
prevent :access_git
end
- rule { project_bot }.policy do
+ rule { project_bot | service_account }.policy do
prevent :log_in
prevent :receive_notifications
end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 6cc65248914..ee1140b8405 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -85,7 +85,11 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
condition(:crm_enabled, score: 0, scope: :subject) { @subject.crm_enabled? }
condition(:create_runner_workflow_enabled) do
- Feature.enabled?(:create_runner_workflow)
+ Feature.enabled?(:create_runner_workflow_for_namespace, group)
+ end
+
+ condition(:achievements_enabled, scope: :subject) do
+ Feature.enabled?(:achievements, @subject)
end
condition(:group_runner_registration_allowed, scope: :subject) do
@@ -131,9 +135,17 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :read_group_member
enable :read_custom_emoji
enable :read_counts
+ end
+
+ rule { can?(:read_group) & achievements_enabled }.policy do
enable :read_achievement
end
+ rule { can?(:maintainer_access) & achievements_enabled }.policy do
+ enable :admin_achievement
+ enable :award_achievement
+ end
+
rule { ~public_group & ~has_access }.prevent :read_counts
rule { ~can_read_group_member }.policy do
@@ -147,17 +159,15 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
rule { has_access }.enable :read_namespace
rule { developer }.policy do
- enable :create_metrics_dashboard_annotation
- enable :delete_metrics_dashboard_annotation
- enable :update_metrics_dashboard_annotation
+ enable :admin_metrics_dashboard_annotation
enable :create_custom_emoji
enable :create_package
enable :developer_access
enable :admin_crm_organization
enable :admin_crm_contact
enable :read_cluster
-
enable :read_group_all_available_runners
+ enable :use_k8s_proxies
end
rule { reporter }.policy do
@@ -191,7 +201,6 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :maintainer_access
enable :read_upload
enable :destroy_upload
- enable :admin_achievement
end
rule { owner }.policy do
@@ -246,7 +255,9 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
rule { ~can?(:view_globally) }.prevent :request_access
rule { has_access }.prevent :request_access
- rule { owner & (~share_with_group_locked | ~has_parent | ~parent_share_with_group_locked | can_change_parent_share_with_group_lock) }.enable :change_share_with_group_lock
+ rule do
+ owner & (~share_with_group_locked | ~has_parent | ~parent_share_with_group_locked | can_change_parent_share_with_group_lock)
+ end.enable :change_share_with_group_lock
rule { developer & developer_maintainer_access }.enable :create_projects
rule { create_projects_disabled }.prevent :create_projects
@@ -325,6 +336,10 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :read_observability
end
+ rule { can?(:maintainer_access) & observability_enabled }.policy do
+ enable :admin_observability
+ end
+
rule { ~create_runner_workflow_enabled }.policy do
prevent :create_group_runners
end
diff --git a/app/policies/issue_policy.rb b/app/policies/issue_policy.rb
index d1e35793c64..804709ed072 100644
--- a/app/policies/issue_policy.rb
+++ b/app/policies/issue_policy.rb
@@ -59,6 +59,7 @@ class IssuePolicy < IssuablePolicy
rule { ~can?(:read_issue) }.policy do
prevent :read_design
prevent :create_design
+ prevent :update_design
prevent :destroy_design
end
diff --git a/app/policies/project_hook_policy.rb b/app/policies/project_hook_policy.rb
index c177fabb1ba..b4590c13670 100644
--- a/app/policies/project_hook_policy.rb
+++ b/app/policies/project_hook_policy.rb
@@ -1,10 +1,9 @@
# frozen_string_literal: true
class ProjectHookPolicy < ::BasePolicy
- delegate(:project)
+ delegate { @subject.project }
rule { can?(:admin_project) }.policy do
- enable :read_web_hook
enable :destroy_web_hook
end
end
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 875520d24be..a955de77309 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -234,8 +234,12 @@ class ProjectPolicy < BasePolicy
Gitlab.config.packages.enabled
end
+ condition :terraform_state_disabled do
+ !Gitlab.config.terraform_state.enabled
+ end
+
condition(:create_runner_workflow_enabled) do
- Feature.enabled?(:create_runner_workflow)
+ Feature.enabled?(:create_runner_workflow_for_namespace, project.namespace)
end
# `:read_project` may be prevented in EE, but `:read_project_for_iids` should
@@ -257,6 +261,7 @@ class ProjectPolicy < BasePolicy
enable :reporter_access
enable :developer_access
enable :maintainer_access
+ enable :add_catalog_resource
enable :change_namespace
enable :change_visibility_level
@@ -353,6 +358,7 @@ class ProjectPolicy < BasePolicy
enable :read_ci_cd_analytics
enable :read_external_emails
enable :read_grafana
+ enable :export_work_items
end
# We define `:public_user_access` separately because there are cases in gitlab-ee
@@ -404,11 +410,15 @@ class ProjectPolicy < BasePolicy
end
rule { infrastructure_disabled }.policy do
- prevent(*create_read_update_admin_destroy(:terraform_state))
prevent(*create_read_update_admin_destroy(:cluster))
prevent(:read_pod_logs)
prevent(:read_prometheus)
prevent(:admin_project_google_cloud)
+ prevent(:admin_project_aws)
+ end
+
+ rule { infrastructure_disabled | terraform_state_disabled }.policy do
+ prevent(*create_read_update_admin_destroy(:terraform_state))
end
rule { can?(:metrics_dashboard) }.policy do
@@ -429,6 +439,7 @@ class ProjectPolicy < BasePolicy
rule { ~request_access_enabled }.prevent :request_access
rule { can?(:developer_access) & can?(:create_issue) }.enable :import_issues
+ rule { can?(:reporter_access) & can?(:create_work_item) }.enable :import_work_items
rule { can?(:developer_access) }.policy do
enable :create_package
@@ -455,15 +466,15 @@ class ProjectPolicy < BasePolicy
enable :create_deployment
enable :update_deployment
enable :read_cluster
+ enable :use_k8s_proxies
enable :create_release
enable :update_release
enable :destroy_release
- enable :create_metrics_dashboard_annotation
- enable :delete_metrics_dashboard_annotation
- enable :update_metrics_dashboard_annotation
+ enable :admin_metrics_dashboard_annotation
enable :read_alert_management_alert
enable :update_alert_management_alert
enable :create_design
+ enable :update_design
enable :move_design
enable :destroy_design
enable :read_terraform_state
@@ -477,7 +488,6 @@ class ProjectPolicy < BasePolicy
enable :update_escalation_status
enable :read_secure_files
enable :update_sentry_issue
- enable :read_airflow_dags
end
rule { can?(:developer_access) & user_confirmed? }.policy do
@@ -531,8 +541,8 @@ class ProjectPolicy < BasePolicy
enable :create_project_runners
enable :update_runners_registration_token
enable :admin_project_google_cloud
+ enable :admin_project_aws
enable :admin_secure_files
- enable :read_web_hooks
enable :read_upload
enable :destroy_upload
enable :admin_incident_management_timeline_event_tag
@@ -752,6 +762,7 @@ class ProjectPolicy < BasePolicy
prevent :read_design
prevent :read_design_activity
prevent :create_design
+ prevent :update_design
prevent :destroy_design
prevent :move_design
end
@@ -780,6 +791,7 @@ class ProjectPolicy < BasePolicy
rule { write_package_registry_deploy_token }.policy do
enable :create_package
enable :read_package
+ enable :destroy_package
enable :read_project
end
diff --git a/app/presenters/README.md b/app/presenters/README.md
index e2461580107..5b600e8f2b2 100644
--- a/app/presenters/README.md
+++ b/app/presenters/README.md
@@ -165,15 +165,15 @@ however, there is a risk that it accidentally overrides important logic.
For example, [this production incident](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/5498)
was caused by [including `ActionView::Helpers::UrlHelper` in a presenter](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69537/diffs#4b581cff00ef3cc9780efd23682af383de302e7d_3_3).
-The `tag` accesor in `Ci::Build` was accidentally overridden by `ActionView::Helpers::TagHelper#tag`,
-and as a conseuqence, a wrong `tag` value was persited into database.
+The `tag` accessor in `Ci::Build` was accidentally overridden by `ActionView::Helpers::TagHelper#tag`,
+and as a consequence, a wrong `tag` value was persisted into database.
-Starting from GitLab 14.4, we validate the presenters (specifically all of the subclasses of `Gitlab::View::Presenter::Delegated`)
+Starting from GitLab 14.4, we [validate](../../lib/gitlab/utils/delegator_override/validator.rb) the presenters (specifically all of the subclasses of `Gitlab::View::Presenter::Delegated`)
that they do not accidentally override core/backend logic. In such case, a pipeline in merge requests fails with an error message,
here is an example:
```plaintext
-We've detected that a presetner is overriding a specific method(s) on a subject model.
+We've detected that a presenter is overriding a specific method(s) on a subject model.
There is a risk that it accidentally modifies the backend/core logic that leads to production incident.
Please follow https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/presenters/README.md#validate-accidental-overrides
to resolve this error with caution.
@@ -193,7 +193,7 @@ Here are the potential solutions:
### How to use the `Gitlab::Utils::DelegatorOverride` validator
-If a presenter class inhertis from `Gitlab::View::Presenter::Delegated`,
+If a presenter class inherits from `Gitlab::View::Presenter::Delegated`,
you should define what object class is presented:
```ruby
@@ -201,7 +201,7 @@ class WebHookLogPresenter < Gitlab::View::Presenter::Delegated
presents ::WebHookLog, as: :web_hook_log # This defines that the presenter presents `WebHookLog` Active Record model.
```
-These presenters are validated not to accidentaly override the methods in the presented object.
+These presenters are validated not to accidentally override the methods in the presented object.
You can run the validation locally with:
```shell
diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb
index 9a586a1733f..79c1946f3d2 100644
--- a/app/presenters/ci/build_runner_presenter.rb
+++ b/app/presenters/ci/build_runner_presenter.rb
@@ -34,9 +34,7 @@ module Ci
def runner_variables
variables
- .sort_and_expand_all(keep_undefined: true,
- expand_file_refs: false,
- expand_raw_refs: false)
+ .sort_and_expand_all(keep_undefined: true, expand_file_refs: false, expand_raw_refs: false)
.to_runner_variables
end
@@ -58,7 +56,7 @@ module Ci
# rubocop: disable CodeReuse/ActiveRecord
def all_dependencies
dependencies = super
- ActiveRecord::Associations::Preloader.new.preload(dependencies, :job_artifacts_archive)
+ ActiveRecord::Associations::Preloader.new(records: dependencies, associations: :job_artifacts_archive).call
dependencies
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/presenters/commit_presenter.rb b/app/presenters/commit_presenter.rb
index 2cb88179845..2f505901901 100644
--- a/app/presenters/commit_presenter.rb
+++ b/app/presenters/commit_presenter.rb
@@ -25,6 +25,10 @@ class CommitPresenter < Gitlab::View::Presenter::Delegated
commit.pipelines.any?
end
+ def tags_for_display
+ commit.referenced_by&.map { |tag| tag.delete_prefix(Gitlab::Git::TAG_REF_PREFIX) }
+ end
+
def signature_html
return unless commit.has_signature?
diff --git a/app/presenters/event_presenter.rb b/app/presenters/event_presenter.rb
index 2f2fb1aa3ba..a098db7fbbc 100644
--- a/app/presenters/event_presenter.rb
+++ b/app/presenters/event_presenter.rb
@@ -9,7 +9,7 @@ class EventPresenter < Gitlab::View::Presenter::Delegated
@visible_to_user_cache = ActiveSupport::Cache::MemoryStore.new
end
- # Caching `visible_to_user?` method in the presenter beause it might be called multiple times.
+ # Caching `visible_to_user?` method in the presenter because it might be called multiple times.
delegator_override :visible_to_user?
def visible_to_user?(user = nil)
@visible_to_user_cache.fetch(user&.id) { super(user) }
diff --git a/app/presenters/label_presenter.rb b/app/presenters/label_presenter.rb
index e60cdf4088c..56d986a9c23 100644
--- a/app/presenters/label_presenter.rb
+++ b/app/presenters/label_presenter.rb
@@ -27,14 +27,18 @@ class LabelPresenter < Gitlab::View::Presenter::Delegated
def filter_path(type: :issue)
case context_subject
when Group
- send("#{type.to_s.pluralize}_group_path", # rubocop:disable GitlabSecurity/PublicSend
- context_subject,
- label_name: [label.name])
+ send( # rubocop:disable GitlabSecurity/PublicSend
+ "#{type.to_s.pluralize}_group_path",
+ context_subject,
+ label_name: [label.name]
+ )
when Project
- send("namespace_project_#{type.to_s.pluralize}_path", # rubocop:disable GitlabSecurity/PublicSend
- context_subject.namespace,
- context_subject,
- label_name: [label.name])
+ send( # rubocop:disable GitlabSecurity/PublicSend
+ "namespace_project_#{type.to_s.pluralize}_path",
+ context_subject.namespace,
+ context_subject,
+ label_name: [label.name]
+ )
end
end
diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb
index 353e0fad6fb..12f4b0496e4 100644
--- a/app/presenters/merge_request_presenter.rb
+++ b/app/presenters/merge_request_presenter.rb
@@ -57,9 +57,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
notice_now: edit_in_new_fork_notice_now
}
- project_forks_path(merge_request.project,
- namespace_key: current_user.namespace.id,
- continue: continue_params)
+ project_forks_path(merge_request.project, namespace_key: current_user.namespace.id, continue: continue_params)
end
end
@@ -71,9 +69,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
notice_now: edit_in_new_fork_notice_now
}
- project_forks_path(project,
- namespace_key: current_user.namespace.id,
- continue: continue_params)
+ project_forks_path(project, namespace_key: current_user.namespace.id, continue: continue_params)
end
end
@@ -155,12 +151,12 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
def assign_to_closing_issues_count
# rubocop: disable CodeReuse/ServiceClass
- issues = MergeRequests::AssignIssuesService.new(project: project,
- current_user: current_user,
- params: {
- merge_request: merge_request,
- closes_issues: closing_issues
- }).assignable_issues
+ issues = MergeRequests::AssignIssuesService.new(
+ project: project,
+ current_user: current_user,
+ params: { merge_request: merge_request, closes_issues: closing_issues }
+ ).assignable_issues
+
issues.count
# rubocop: enable CodeReuse/ServiceClass
end
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
index 392a2fcd390..c02f3021069 100644
--- a/app/presenters/project_presenter.rb
+++ b/app/presenters/project_presenter.rb
@@ -99,11 +99,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def contribution_guide_path
if project && contribution_guide = repository.contribution_guide
- project_blob_path(
- project,
- tree_join(project.default_branch,
- contribution_guide.name)
- )
+ project_blob_path(project, tree_join(project.default_branch, contribution_guide.name))
end
end
@@ -166,14 +162,16 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def storage_anchor_data
can_show_quota = can?(current_user, :admin_project, project) && !empty_repo?
- AnchorData.new(true,
- statistic_icon('disk') +
- _('%{strong_start}%{human_size}%{strong_end} Project Storage').html_safe % {
- human_size: storage_counter(statistics.storage_size),
- strong_start: '<strong class="project-stat-value">'.html_safe,
- strong_end: '</strong>'.html_safe
- },
- can_show_quota ? project_usage_quotas_path(project) : nil)
+ AnchorData.new(
+ true,
+ statistic_icon('disk') +
+ _('%{strong_start}%{human_size}%{strong_end} Project Storage').html_safe % {
+ human_size: storage_counter(statistics.storage_size),
+ strong_start: '<strong class="project-stat-value">'.html_safe,
+ strong_end: '</strong>'.html_safe
+ },
+ can_show_quota ? project_usage_quotas_path(project) : nil
+ )
end
def releases_anchor_data
@@ -182,14 +180,16 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
releases_count = project.releases.count
return if releases_count < 1
- AnchorData.new(true,
- statistic_icon('deployments') +
- n_('%{strong_start}%{release_count}%{strong_end} Release', '%{strong_start}%{release_count}%{strong_end} Releases', releases_count).html_safe % {
- release_count: number_with_delimiter(releases_count),
- strong_start: '<strong class="project-stat-value">'.html_safe,
- strong_end: '</strong>'.html_safe
- },
- project_releases_path(project))
+ AnchorData.new(
+ true,
+ statistic_icon('deployments') +
+ n_('%{strong_start}%{release_count}%{strong_end} Release', '%{strong_start}%{release_count}%{strong_end} Releases', releases_count).html_safe % {
+ release_count: number_with_delimiter(releases_count),
+ strong_start: '<strong class="project-stat-value">'.html_safe,
+ strong_end: '</strong>'.html_safe
+ },
+ project_releases_path(project)
+ )
end
def environments_anchor_data
@@ -198,67 +198,76 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
environments_count = project.environments.available.count
return if environments_count == 0
- AnchorData.new(true,
- statistic_icon('environment') +
- n_('%{strong_start}%{count}%{strong_end} Environment', '%{strong_start}%{count}%{strong_end} Environments', environments_count).html_safe % {
- count: number_with_delimiter(environments_count),
- strong_start: '<strong class="project-stat-value">'.html_safe,
- strong_end: '</strong>'.html_safe
- },
- project_environments_path(project))
+ AnchorData.new(
+ true,
+ statistic_icon('environment') +
+ n_('%{strong_start}%{count}%{strong_end} Environment', '%{strong_start}%{count}%{strong_end} Environments', environments_count).html_safe % {
+ count: number_with_delimiter(environments_count),
+ strong_start: '<strong class="project-stat-value">'.html_safe,
+ strong_end: '</strong>'.html_safe
+ },
+ project_environments_path(project)
+ )
end
def commits_anchor_data
- AnchorData.new(true,
- statistic_icon('commit') +
- n_('%{strong_start}%{commit_count}%{strong_end} Commit', '%{strong_start}%{commit_count}%{strong_end} Commits', statistics.commit_count).html_safe % {
- commit_count: number_with_delimiter(statistics.commit_count),
- strong_start: '<strong class="project-stat-value">'.html_safe,
- strong_end: '</strong>'.html_safe
- },
- empty_repo? ? nil : project_commits_path(project, default_branch_or_main))
+ AnchorData.new(
+ true,
+ statistic_icon('commit') +
+ n_('%{strong_start}%{commit_count}%{strong_end} Commit', '%{strong_start}%{commit_count}%{strong_end} Commits', statistics.commit_count).html_safe % {
+ commit_count: number_with_delimiter(statistics.commit_count),
+ strong_start: '<strong class="project-stat-value">'.html_safe,
+ strong_end: '</strong>'.html_safe
+ },
+ empty_repo? ? nil : project_commits_path(project, default_branch_or_main)
+ )
end
def branches_anchor_data
- AnchorData.new(true,
- statistic_icon('branch') +
- n_('%{strong_start}%{branch_count}%{strong_end} Branch', '%{strong_start}%{branch_count}%{strong_end} Branches', repository.branch_count).html_safe % {
- branch_count: number_with_delimiter(repository.branch_count),
- strong_start: '<strong class="project-stat-value">'.html_safe,
- strong_end: '</strong>'.html_safe
- },
- empty_repo? ? nil : project_branches_path(project))
+ AnchorData.new(
+ true,
+ statistic_icon('branch') +
+ n_('%{strong_start}%{branch_count}%{strong_end} Branch', '%{strong_start}%{branch_count}%{strong_end} Branches', repository.branch_count).html_safe % {
+ branch_count: number_with_delimiter(repository.branch_count),
+ strong_start: '<strong class="project-stat-value">'.html_safe,
+ strong_end: '</strong>'.html_safe
+ },
+ empty_repo? ? nil : project_branches_path(project)
+ )
end
def tags_anchor_data
- AnchorData.new(true,
- statistic_icon('label') +
- n_('%{strong_start}%{tag_count}%{strong_end} Tag', '%{strong_start}%{tag_count}%{strong_end} Tags', repository.tag_count).html_safe % {
- tag_count: number_with_delimiter(repository.tag_count),
- strong_start: '<strong class="project-stat-value">'.html_safe,
- strong_end: '</strong>'.html_safe
- },
- empty_repo? ? nil : project_tags_path(project))
+ AnchorData.new(
+ true,
+ statistic_icon('label') +
+ n_('%{strong_start}%{tag_count}%{strong_end} Tag', '%{strong_start}%{tag_count}%{strong_end} Tags', repository.tag_count).html_safe % {
+ tag_count: number_with_delimiter(repository.tag_count),
+ strong_start: '<strong class="project-stat-value">'.html_safe,
+ strong_end: '</strong>'.html_safe
+ },
+ empty_repo? ? nil : project_tags_path(project)
+ )
end
def upload_anchor_data
strong_memoize(:upload_anchor_data) do
next unless can_current_user_push_to_default_branch?
- AnchorData.new(false,
- statistic_icon('upload') + _('Upload file'),
- '#modal-upload-blob',
- 'js-upload-file-trigger',
- nil,
- nil,
- {
- 'target_branch' => default_branch_or_main,
- 'original_branch' => default_branch_or_main,
- 'can_push_code' => 'true',
- 'path' => project_create_blob_path(project, default_branch_or_main),
- 'project_path' => project.full_path
- }
- )
+ AnchorData.new(
+ false,
+ statistic_icon('upload') + _('Upload file'),
+ '#modal-upload-blob',
+ 'js-upload-file-trigger',
+ nil,
+ nil,
+ {
+ 'target_branch' => default_branch_or_main,
+ 'original_branch' => default_branch_or_main,
+ 'can_push_code' => 'true',
+ 'path' => project_create_blob_path(project, default_branch_or_main),
+ 'project_path' => project.full_path
+ }
+ )
end
end
@@ -266,37 +275,38 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if can_current_user_push_to_default_branch?
new_file_path = empty_repo? ? ide_edit_path(project, default_branch_or_main) : project_new_blob_path(project, default_branch_or_main)
- AnchorData.new(false,
- statistic_icon + _('New file'),
- new_file_path,
- 'btn-dashed')
+ AnchorData.new(false, statistic_icon + _('New file'), new_file_path, 'btn-dashed')
end
end
def readme_anchor_data
if can_current_user_push_to_default_branch? && readme_path.nil?
- AnchorData.new(false,
- statistic_icon + _('Add README'),
- empty_repo? ? add_readme_ide_path : add_readme_path)
+ AnchorData.new(false, statistic_icon + _('Add README'), empty_repo? ? add_readme_ide_path : add_readme_path)
elsif readme_path
- AnchorData.new(false,
- statistic_icon('doc-text') + _('README'),
- default_view != 'readme' ? readme_path : '#readme',
- 'btn-default',
- 'doc-text')
+ AnchorData.new(
+ false,
+ statistic_icon('doc-text') + _('README'),
+ default_view != 'readme' ? readme_path : '#readme',
+ 'btn-default',
+ 'doc-text'
+ )
end
end
def changelog_anchor_data
if can_current_user_push_to_default_branch? && repository.changelog.blank?
- AnchorData.new(false,
- statistic_icon + _('Add CHANGELOG'),
- empty_repo? ? add_changelog_ide_path : add_changelog_path)
+ AnchorData.new(
+ false,
+ statistic_icon + _('Add CHANGELOG'),
+ empty_repo? ? add_changelog_ide_path : add_changelog_path
+ )
elsif repository.changelog.present?
- AnchorData.new(false,
- statistic_icon('doc-text') + _('CHANGELOG'),
- changelog_path,
- 'btn-default')
+ AnchorData.new(
+ false,
+ statistic_icon('doc-text') + _('CHANGELOG'),
+ changelog_path,
+ 'btn-default'
+ )
end
end
@@ -304,29 +314,37 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
icon = statistic_icon('scale')
if repository.license_blob.present?
- AnchorData.new(false,
- icon + content_tag(:span, license_short_name, class: 'project-stat-value'),
- license_path,
- 'btn-default',
- nil,
- 'license')
+ AnchorData.new(
+ false,
+ icon + content_tag(:span, license_short_name, class: 'project-stat-value'),
+ license_path,
+ 'btn-default',
+ nil,
+ 'license'
+ )
elsif can_current_user_push_to_default_branch?
- AnchorData.new(false,
- content_tag(:span, statistic_icon + _('Add LICENSE'), class: 'add-license-link d-flex'),
- empty_repo? ? add_license_ide_path : add_license_path)
+ AnchorData.new(
+ false,
+ content_tag(:span, statistic_icon + _('Add LICENSE'), class: 'add-license-link d-flex'),
+ empty_repo? ? add_license_ide_path : add_license_path
+ )
end
end
def contribution_guide_anchor_data
if can_current_user_push_to_default_branch? && repository.contribution_guide.blank?
- AnchorData.new(false,
- statistic_icon + _('Add CONTRIBUTING'),
- empty_repo? ? add_contribution_guide_ide_path : add_contribution_guide_path)
+ AnchorData.new(
+ false,
+ statistic_icon + _('Add CONTRIBUTING'),
+ empty_repo? ? add_contribution_guide_ide_path : add_contribution_guide_path
+ )
elsif repository.contribution_guide.present?
- AnchorData.new(false,
- statistic_icon('doc-text') + _('CONTRIBUTING'),
- contribution_guide_path,
- 'btn-default')
+ AnchorData.new(
+ false,
+ statistic_icon('doc-text') + _('CONTRIBUTING'),
+ contribution_guide_path,
+ 'btn-default'
+ )
end
end
@@ -335,35 +353,32 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout
if auto_devops_enabled?
- AnchorData.new(false,
- statistic_icon('settings') + _('Auto DevOps enabled'),
- project_settings_ci_cd_path(project, anchor: 'autodevops-settings'),
- 'btn-default')
+ AnchorData.new(
+ false,
+ statistic_icon('settings') + _('Auto DevOps enabled'),
+ project_settings_ci_cd_path(project, anchor: 'autodevops-settings'),
+ 'btn-default'
+ )
else
- AnchorData.new(false,
- statistic_icon + _('Enable Auto DevOps'),
- project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ AnchorData.new(
+ false,
+ statistic_icon + _('Enable Auto DevOps'),
+ project_settings_ci_cd_path(project, anchor: 'autodevops-settings')
+ )
end
elsif auto_devops_enabled?
- AnchorData.new(false,
- _('Auto DevOps enabled'),
- nil)
+ AnchorData.new(false, _('Auto DevOps enabled'), nil)
end
end
def kubernetes_cluster_anchor_data
if can_instantiate_cluster?
if clusters.empty?
- AnchorData.new(false,
- statistic_icon + _('Add Kubernetes cluster'),
- project_clusters_path(project))
+ AnchorData.new(false, statistic_icon + _('Add Kubernetes cluster'), project_clusters_path(project))
else
cluster_link = clusters.count == 1 ? project_cluster_path(project, clusters.first) : project_clusters_path(project)
- AnchorData.new(false,
- _('Kubernetes'),
- cluster_link,
- 'btn-default')
+ AnchorData.new(false, _('Kubernetes'), cluster_link, 'btn-default')
end
end
end
@@ -372,14 +387,9 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
return unless can_view_pipeline_editor?(project)
if cicd_missing?
- AnchorData.new(false,
- statistic_icon + _('Set up CI/CD'),
- project_ci_pipeline_editor_path(project))
+ AnchorData.new(false, statistic_icon + _('Set up CI/CD'), project_ci_pipeline_editor_path(project))
elsif repository.gitlab_ci_yml.present?
- AnchorData.new(false,
- statistic_icon('doc-text') + _('CI/CD configuration'),
- project_ci_pipeline_editor_path(project),
- 'btn-default')
+ AnchorData.new(false, statistic_icon('doc-text') + _('CI/CD configuration'), project_ci_pipeline_editor_path(project), 'btn-default')
end
end
diff --git a/app/presenters/snippet_blob_presenter.rb b/app/presenters/snippet_blob_presenter.rb
index 2e5d3ae21d9..84e98e18e32 100644
--- a/app/presenters/snippet_blob_presenter.rb
+++ b/app/presenters/snippet_blob_presenter.rb
@@ -40,9 +40,11 @@ class SnippetBlobPresenter < BlobPresenter
end
def render_rich_partial
- renderer.render("projects/blob/viewers/_#{blob.rich_viewer.partial_name}",
- locals: { viewer: blob.rich_viewer, blob: blob, blob_raw_path: raw_path, blob_raw_url: raw_url, parent_dir_raw_path: raw_directory },
- layout: false)
+ renderer.render(
+ "projects/blob/viewers/_#{blob.rich_viewer.partial_name}",
+ locals: { viewer: blob.rich_viewer, blob: blob, blob_raw_path: raw_path, blob_raw_url: raw_url, parent_dir_raw_path: raw_directory },
+ layout: false
+ )
end
def renderer
diff --git a/app/serializers/admin/abuse_report_entity.rb b/app/serializers/admin/abuse_report_entity.rb
new file mode 100644
index 00000000000..a550763f0ff
--- /dev/null
+++ b/app/serializers/admin/abuse_report_entity.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Admin
+ class AbuseReportEntity < Grape::Entity
+ expose :category
+ expose :updated_at
+
+ expose :reported_user do |report|
+ UserEntity.represent(report.user, only: [:name])
+ end
+
+ expose :reporter do |report|
+ UserEntity.represent(report.reporter, only: [:name])
+ end
+ end
+end
diff --git a/app/serializers/admin/abuse_report_serializer.rb b/app/serializers/admin/abuse_report_serializer.rb
new file mode 100644
index 00000000000..af43e459482
--- /dev/null
+++ b/app/serializers/admin/abuse_report_serializer.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module Admin
+ class AbuseReportSerializer < BaseSerializer
+ entity Admin::AbuseReportEntity
+ end
+end
diff --git a/app/serializers/cluster_application_entity.rb b/app/serializers/cluster_application_entity.rb
deleted file mode 100644
index f57ac4af113..00000000000
--- a/app/serializers/cluster_application_entity.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-class ClusterApplicationEntity < Grape::Entity
- expose :name
- expose :status_name, as: :status
- expose :status_reason
- expose :version, if: -> (e, _) { e.respond_to?(:version) }
- expose :external_ip, if: -> (e, _) { e.respond_to?(:external_ip) }
- expose :external_hostname, if: -> (e, _) { e.respond_to?(:external_hostname) }
- expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) }
- expose :email, if: -> (e, _) { e.respond_to?(:email) }
- expose :stack, if: -> (e, _) { e.respond_to?(:stack) }
- expose :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) }
- expose :can_uninstall?, as: :can_uninstall
- expose :available_domains, using: Serverless::DomainEntity, if: -> (e, _) { e.respond_to?(:available_domains) }
- expose :pages_domain, using: Serverless::DomainEntity, if: -> (e, _) { e.respond_to?(:pages_domain) }
- expose :host, if: -> (e, _) { e.respond_to?(:host) }
- expose :port, if: -> (e, _) { e.respond_to?(:port) }
- expose :protocol, if: -> (e, _) { e.respond_to?(:protocol) }
-end
diff --git a/app/serializers/cluster_entity.rb b/app/serializers/cluster_entity.rb
index 8e256863bcd..161758debca 100644
--- a/app/serializers/cluster_entity.rb
+++ b/app/serializers/cluster_entity.rb
@@ -13,7 +13,6 @@ class ClusterEntity < Grape::Entity
expose :provider_type
expose :status_name, as: :status
expose :status_reason
- expose :applications, using: ClusterApplicationEntity
expose :path do |cluster|
Clusters::ClusterPresenter.new(cluster).show_path # rubocop: disable CodeReuse/Presenter
diff --git a/app/serializers/cluster_serializer.rb b/app/serializers/cluster_serializer.rb
index 30b8863efa2..a4e12e51f69 100644
--- a/app/serializers/cluster_serializer.rb
+++ b/app/serializers/cluster_serializer.rb
@@ -22,6 +22,6 @@ class ClusterSerializer < BaseSerializer
end
def represent_status(resource)
- represent(resource, { only: [:status, :status_reason, :applications] })
+ represent(resource, { only: [:status, :status_reason] })
end
end
diff --git a/app/serializers/pipeline_details_entity.rb b/app/serializers/pipeline_details_entity.rb
index 76797a773b5..6c20f665bfa 100644
--- a/app/serializers/pipeline_details_entity.rb
+++ b/app/serializers/pipeline_details_entity.rb
@@ -8,8 +8,14 @@ class PipelineDetailsEntity < Ci::PipelineEntity
end
expose :details do
- expose :manual_actions, using: BuildActionEntity
- expose :scheduled_actions, using: BuildActionEntity
+ expose :manual_actions, unless: proc { options[:disable_manual_and_scheduled_actions] }, using: BuildActionEntity
+ expose :scheduled_actions, unless: proc { options[:disable_manual_and_scheduled_actions] }, using: BuildActionEntity
+ expose :has_manual_actions do |pipeline|
+ pipeline.manual_actions.any?
+ end
+ expose :has_scheduled_actions do |pipeline|
+ pipeline.scheduled_actions.any?
+ end
end
expose :triggered_by_pipeline, as: :triggered_by, with: TriggeredPipelineEntity
diff --git a/app/serializers/profile/event_entity.rb b/app/serializers/profile/event_entity.rb
new file mode 100644
index 00000000000..fe90265c888
--- /dev/null
+++ b/app/serializers/profile/event_entity.rb
@@ -0,0 +1,125 @@
+# frozen_string_literal: true
+
+module Profile
+ class EventEntity < Grape::Entity
+ include ActionView::Helpers::SanitizeHelper
+ include RequestAwareEntity
+ include MarkupHelper
+ include MergeRequestsHelper
+ include EventsHelper
+
+ expose :created_at, if: ->(event) { include_private_event?(event) }
+ expose(:action, if: ->(event) { include_private_event?(event) }) { |event| event_action(event) }
+
+ expose :ref, if: ->(event) { event.visible_to_user?(current_user) && event.push_action? } do
+ expose(:type) { |event| event.ref_type } # rubocop:disable Style/SymbolProc
+ expose(:count) { |event| event.ref_count } # rubocop:disable Style/SymbolProc
+ expose(:name) { |event| event.ref_name } # rubocop:disable Style/SymbolProc
+ expose(:path) { |event| ref_path(event) }
+ end
+
+ expose :commit, if: ->(event) { event.visible_to_user?(current_user) && event.push_action? } do
+ expose(:truncated_sha) { |event| Commit.truncate_sha(event.commit_id) }
+ expose(:path) { |event| project_commit_path(event.project, event.commit_id) }
+ expose(:title) { |event| event_commit_title(event.commit_title) }
+ expose(:count) { |event| event.commits_count } # rubocop:disable Style/SymbolProc
+ expose(:create_mr_path) { |event| commit_create_mr_path(event) }
+ expose(:from_truncated_sha) { |event| commit_from(event) if event.commit_from }
+ expose(:to_truncated_sha) { |event| Commit.truncate_sha(event.commit_to) if event.commit_to }
+
+ expose :compare_path, if: ->(event) { event.push_with_commits? && event.commits_count > 1 } do |event|
+ project = event.project
+ from = event.md_ref? ? event.commit_from : project.default_branch
+ project_compare_path(project, from: from, to: event.commit_to)
+ end
+ end
+
+ expose :author, if: ->(event) { include_private_event?(event) } do
+ expose(:id) { |event| event.author.id }
+ expose(:name) { |event| event.author.name }
+ expose(:path) { |event| event.author.username }
+ end
+
+ expose :target, if: ->(event) { event.visible_to_user?(current_user) } do
+ expose :target_type
+
+ expose(:title) { |event| event.target_title } # rubocop:disable Style/SymbolProc
+ expose :target_url, if: ->(event) { event.target } do |event|
+ Gitlab::UrlBuilder.build(event.target, only_path: true)
+ end
+ expose :reference_link_text, if: ->(event) { event.target&.respond_to?(:reference_link_text) } do |event|
+ event.target.reference_link_text
+ end
+ expose :first_line_in_markdown, if: ->(event) { event.note? && event.target && event.project } do |event|
+ first_line_in_markdown(event.target, :note, 150, project: event.project)
+ end
+ expose :attachment, if: ->(event) { event.note? && event.target&.attachment } do
+ expose(:url) { |event| event.target.attachment.url }
+ end
+ end
+
+ expose :resource_parent, if: ->(event) { event.visible_to_user?(current_user) } do
+ expose(:type) { |event| resource_parent_type(event) }
+ expose(:full_name) { |event| event.resource_parent&.full_name }
+ expose(:full_path) { |event| event.resource_parent&.full_path }
+ end
+
+ private
+
+ def current_user
+ request.current_user
+ end
+
+ def target_user
+ request.target_user
+ end
+
+ def include_private_event?(event)
+ event.visible_to_user?(current_user) || target_user.include_private_contributions?
+ end
+
+ def commit_from(event)
+ if event.md_ref?
+ Commit.truncate_sha(event.commit_from)
+ else
+ event.project.default_branch
+ end
+ end
+
+ def event_action(event)
+ if event.visible_to_user?(current_user)
+ event.action
+ elsif target_user.include_private_contributions?
+ 'private'
+ end
+ end
+
+ def ref_path(event)
+ project = event.project
+ commits_link = project_commits_path(project, event.ref_name)
+ should_link = if event.tag?
+ project.repository.tag_exists?(event.ref_name)
+ else
+ project.repository.branch_exists?(event.ref_name)
+ end
+
+ should_link ? commits_link : nil
+ end
+
+ def commit_create_mr_path(event)
+ if event.new_ref? &&
+ create_mr_button_from_event?(event) &&
+ event.authored_by?(current_user)
+ create_mr_path_from_push_event(event)
+ end
+ end
+
+ def resource_parent_type(event)
+ if event.project
+ "project"
+ elsif event.group
+ "group"
+ end
+ end
+ end
+end
diff --git a/app/serializers/profile/event_serializer.rb b/app/serializers/profile/event_serializer.rb
new file mode 100644
index 00000000000..c7f23d61fe1
--- /dev/null
+++ b/app/serializers/profile/event_serializer.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module Profile
+ class EventSerializer < BaseSerializer
+ entity Profile::EventEntity
+ end
+end
diff --git a/app/serializers/project_import_entity.rb b/app/serializers/project_import_entity.rb
index 58360321f7c..302086143c1 100644
--- a/app/serializers/project_import_entity.rb
+++ b/app/serializers/project_import_entity.rb
@@ -16,4 +16,11 @@ class ProjectImportEntity < ProjectEntity
expose :import_error, if: ->(project) { project.import_state&.failed? } do |project|
project.import_failures.last&.exception_message
end
+
+ # Only for GitHub importer where we pass client through
+ expose :relation_type do |project, options|
+ next nil if options[:client].nil? || Feature.disabled?(:remove_legacy_github_client)
+
+ ::Gitlab::GithubImport::ProjectRelationType.new(options[:client]).for(project.import_source)
+ end
end
diff --git a/app/services/achievements/award_service.rb b/app/services/achievements/award_service.rb
new file mode 100644
index 00000000000..674bb8837fb
--- /dev/null
+++ b/app/services/achievements/award_service.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module Achievements
+ class AwardService
+ attr_reader :current_user, :achievement_id, :recipient_id
+
+ def initialize(current_user, achievement_id, recipient_id)
+ @current_user = current_user
+ @achievement_id = achievement_id
+ @recipient_id = recipient_id
+ end
+
+ def execute
+ achievement = Achievements::Achievement.find(achievement_id)
+ return error_no_permissions unless allowed?(achievement)
+
+ recipient = User.find(recipient_id)
+
+ user_achievement = Achievements::UserAchievement.create(
+ achievement: achievement,
+ user: recipient,
+ awarded_by_user: current_user)
+ return error_awarding(user_achievement) unless user_achievement.persisted?
+
+ ServiceResponse.success(payload: user_achievement)
+ rescue ActiveRecord::RecordNotFound => e
+ error(e.message)
+ end
+
+ private
+
+ def allowed?(achievement)
+ current_user&.can?(:award_achievement, achievement)
+ end
+
+ def error_no_permissions
+ error('You have insufficient permissions to award this achievement')
+ end
+
+ def error_awarding(user_achievement)
+ error(user_achievement&.errors&.full_messages || 'Failed to award achievement')
+ end
+
+ def error(message)
+ ServiceResponse.error(message: Array(message))
+ end
+ end
+end
diff --git a/app/services/achievements/revoke_service.rb b/app/services/achievements/revoke_service.rb
new file mode 100644
index 00000000000..4601622f517
--- /dev/null
+++ b/app/services/achievements/revoke_service.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Achievements
+ class RevokeService
+ attr_reader :current_user, :user_achievement
+
+ def initialize(current_user, user_achievement)
+ @current_user = current_user
+ @user_achievement = user_achievement
+ end
+
+ def execute
+ return error_no_permissions unless allowed?(user_achievement.achievement)
+ return error_already_revoked if user_achievement.revoked?
+
+ user_achievement.assign_attributes({
+ revoked_by_user_id: current_user.id,
+ revoked_at: Time.zone.now
+ })
+ return error_awarding unless user_achievement.save
+
+ ServiceResponse.success(payload: user_achievement)
+ end
+
+ private
+
+ def allowed?(achievement)
+ current_user&.can?(:award_achievement, achievement)
+ end
+
+ def error_no_permissions
+ error('You have insufficient permissions to revoke this achievement')
+ end
+
+ def error_already_revoked
+ error('This achievement has already been revoked')
+ end
+
+ def error_awarding
+ error(user_achievement&.errors&.full_messages || 'Failed to revoke achievement')
+ end
+
+ def error(message)
+ ServiceResponse.error(message: Array(message))
+ end
+ end
+end
diff --git a/app/services/authorized_project_update/project_recalculate_service.rb b/app/services/authorized_project_update/project_recalculate_service.rb
index 8d60fffd959..cb83dc57478 100644
--- a/app/services/authorized_project_update/project_recalculate_service.rb
+++ b/app/services/authorized_project_update/project_recalculate_service.rb
@@ -82,3 +82,5 @@ module AuthorizedProjectUpdate
end
end
end
+
+AuthorizedProjectUpdate::ProjectRecalculateService.prepend_mod
diff --git a/app/services/base_container_service.rb b/app/services/base_container_service.rb
index 86df0236a7f..f46e8d5ec42 100644
--- a/app/services/base_container_service.rb
+++ b/app/services/base_container_service.rb
@@ -10,13 +10,17 @@
# the top of the original BaseService.
class BaseContainerService
include BaseServiceUtility
+ include ::Gitlab::Utils::StrongMemoize
+ attr_accessor :project, :group
attr_reader :container, :current_user, :params
def initialize(container:, current_user: nil, params: {})
@container = container
@current_user = current_user
@params = params.dup
+
+ handle_container_type(container)
end
def project_container?
@@ -30,4 +34,22 @@ class BaseContainerService
def namespace_container?
container.is_a?(::Namespace)
end
+
+ def project_group
+ project&.group
+ end
+ strong_memoize_attr :project_group
+
+ private
+
+ def handle_container_type(container)
+ case container
+ when Project
+ @project = container
+ when Group
+ @group = container
+ when Namespaces::ProjectNamespace
+ @project = container.project
+ end
+ end
end
diff --git a/app/services/bulk_imports/archive_extraction_service.rb b/app/services/bulk_imports/archive_extraction_service.rb
index caa40d98a76..fec8fd0e1f5 100644
--- a/app/services/bulk_imports/archive_extraction_service.rb
+++ b/app/services/bulk_imports/archive_extraction_service.rb
@@ -33,7 +33,6 @@ module BulkImports
validate_symlink
extract_archive
- remove_symlinks
tmpdir
end
@@ -60,15 +59,5 @@ module BulkImports
def extract_archive
untar_xf(archive: filepath, dir: tmpdir)
end
-
- def extracted_files
- Dir.glob(File.join(tmpdir, '**', '*'))
- end
-
- def remove_symlinks
- extracted_files.each do |path|
- FileUtils.rm(path) if symlink?(path)
- end
- end
end
end
diff --git a/app/services/ci/catalog/add_resource_service.rb b/app/services/ci/catalog/add_resource_service.rb
new file mode 100644
index 00000000000..1f53513b7d1
--- /dev/null
+++ b/app/services/ci/catalog/add_resource_service.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Ci
+ module Catalog
+ class AddResourceService
+ include Gitlab::Allowable
+
+ attr_reader :project, :current_user
+
+ def initialize(project, user)
+ @current_user = user
+ @project = project
+ end
+
+ def execute
+ raise Gitlab::Access::AccessDeniedError unless can?(current_user, :add_catalog_resource, project)
+
+ validation_response = Ci::Catalog::ValidateResourceService.new(project, project.default_branch).execute
+
+ if validation_response.success?
+ create_catalog_resource
+ else
+ ServiceResponse.error(message: validation_response.message)
+ end
+ end
+
+ private
+
+ def create_catalog_resource
+ catalog_resource = Ci::Catalog::Resource.new(project: project)
+
+ if catalog_resource.valid?
+ catalog_resource.save!
+ ServiceResponse.success(payload: catalog_resource)
+ else
+ ServiceResponse.error(message: catalog_resource.errors.full_messages.join(', '))
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/ci/catalog/validate_resource_service.rb b/app/services/ci/catalog/validate_resource_service.rb
new file mode 100644
index 00000000000..f166c220869
--- /dev/null
+++ b/app/services/ci/catalog/validate_resource_service.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Ci
+ module Catalog
+ class ValidateResourceService
+ attr_reader :project
+
+ def initialize(project, ref)
+ @project = project
+ @ref = ref
+ @errors = []
+ end
+
+ def execute
+ check_project_readme
+ check_project_description
+
+ if errors.empty?
+ ServiceResponse.success
+ else
+ ServiceResponse.error(message: errors.join(' , '))
+ end
+ end
+
+ private
+
+ attr_reader :ref, :errors
+
+ def check_project_description
+ return if project.description.present?
+
+ errors << 'Project must have a description'
+ end
+
+ def check_project_readme
+ return if project_has_readme?
+
+ errors << 'Project must have a README'
+ end
+
+ def project_has_readme?
+ project.repository.blob_data_at(ref, 'README.md')
+ end
+ end
+ end
+end
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index 390675ab80b..7cad7e8301c 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -7,7 +7,6 @@ module Ci
LOG_MAX_DURATION_THRESHOLD = 3.seconds
LOG_MAX_PIPELINE_SIZE = 2_000
LOG_MAX_CREATION_THRESHOLD = 20.seconds
-
SEQUENCE = [Gitlab::Ci::Pipeline::Chain::Build,
Gitlab::Ci::Pipeline::Chain::Build::Associations,
Gitlab::Ci::Pipeline::Chain::Validate::Abilities,
@@ -161,7 +160,7 @@ module Ci
pipeline_includes_count = observations['pipeline_includes_count']
next false unless pipeline_includes_count
- pipeline_includes_count.to_i > Gitlab::Ci::Config::External::Context::MAX_INCLUDES
+ pipeline_includes_count.to_i > Gitlab::Ci::Config::External::Context::TEMP_MAX_INCLUDES
end
end
end
diff --git a/app/services/ci/job_artifacts/bulk_delete_by_project_service.rb b/app/services/ci/job_artifacts/bulk_delete_by_project_service.rb
new file mode 100644
index 00000000000..738fa19e29b
--- /dev/null
+++ b/app/services/ci/job_artifacts/bulk_delete_by_project_service.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module Ci
+ module JobArtifacts
+ class BulkDeleteByProjectService
+ include BaseServiceUtility
+
+ JOB_ARTIFACTS_COUNT_LIMIT = 50
+
+ def initialize(job_artifact_ids:, project:, current_user:)
+ @job_artifact_ids = job_artifact_ids
+ @project = project
+ @current_user = current_user
+ end
+
+ def execute
+ if exceeds_limits?
+ return ServiceResponse.error(
+ message: "Can only delete up to #{JOB_ARTIFACTS_COUNT_LIMIT} job artifacts per call"
+ )
+ end
+
+ find_result = find_artifacts
+
+ return ServiceResponse.error(message: find_result[:error_message]) if find_result[:error_message]
+
+ @job_artifact_scope = find_result[:scope]
+
+ unless all_job_artifacts_belong_to_project?
+ return ServiceResponse.error(message: 'Not all artifacts belong to requested project')
+ end
+
+ result = Ci::JobArtifacts::DestroyBatchService.new(job_artifact_scope).execute
+
+ destroyed_artifacts_count = result.fetch(:destroyed_artifacts_count)
+ destroyed_ids = result.fetch(:destroyed_ids)
+
+ ServiceResponse.success(
+ payload: {
+ destroyed_count: destroyed_artifacts_count,
+ destroyed_ids: destroyed_ids,
+ errors: []
+ })
+ end
+
+ private
+
+ def find_artifacts
+ job_artifacts = ::Ci::JobArtifact.id_in(job_artifact_ids)
+
+ error_message = nil
+ if job_artifacts.count != job_artifact_ids.count
+ not_found_artifacts = job_artifact_ids - job_artifacts.map(&:id)
+ error_message = "Artifacts (#{not_found_artifacts.join(',')}) not found"
+ end
+
+ { scope: job_artifacts, error_message: error_message }
+ end
+
+ def exceeds_limits?
+ job_artifact_ids.count > JOB_ARTIFACTS_COUNT_LIMIT
+ end
+
+ def all_job_artifacts_belong_to_project?
+ # rubocop:disable CodeReuse/ActiveRecord
+ job_artifact_scope.pluck(:project_id).all?(project.id)
+ # rubocop:enable CodeReuse/ActiveRecord
+ end
+
+ attr_reader :job_artifact_ids, :job_artifact_scope, :current_user, :project
+ end
+ end
+end
diff --git a/app/services/ci/job_artifacts/create_service.rb b/app/services/ci/job_artifacts/create_service.rb
index 3d19fec6617..30d310dec7f 100644
--- a/app/services/ci/job_artifacts/create_service.rb
+++ b/app/services/ci/job_artifacts/create_service.rb
@@ -113,7 +113,13 @@ module Ci
end
def accessibility(params)
- params[:accessibility] || 'public'
+ accessibility = params[:accessibility]
+
+ return :public if Feature.disabled?(:non_public_artifacts, type: :development)
+
+ return accessibility if accessibility.present?
+
+ job.artifacts_public? ? :public : :private
end
def parse_artifact(artifact)
@@ -125,11 +131,13 @@ module Ci
def persist_artifact(artifact, artifact_metadata, params)
Ci::JobArtifact.transaction do
- artifact.save!
- artifact_metadata&.save!
-
# NOTE: The `artifacts_expire_at` column is already deprecated and to be removed in the near future.
+ # Running it first because in migrations we lock the `ci_builds` table
+ # first and then the others. This reduces the chances of deadlocks.
job.update_column(:artifacts_expire_at, artifact.expire_at)
+
+ artifact.save!
+ artifact_metadata&.save!
end
success(artifact: artifact)
diff --git a/app/services/ci/job_artifacts/destroy_all_expired_service.rb b/app/services/ci/job_artifacts/destroy_all_expired_service.rb
index b5dd5b843c6..57b95e59d7d 100644
--- a/app/services/ci/job_artifacts/destroy_all_expired_service.rb
+++ b/app/services/ci/job_artifacts/destroy_all_expired_service.rb
@@ -25,11 +25,7 @@ module Ci
# which is scheduled every 7 minutes.
def execute
in_lock(EXCLUSIVE_LOCK_KEY, ttl: LOCK_TIMEOUT, retries: 1) do
- if ::Feature.enabled?(:ci_destroy_unlocked_job_artifacts)
- destroy_unlocked_job_artifacts
- else
- destroy_job_artifacts_with_slow_iteration
- end
+ destroy_unlocked_job_artifacts
end
@removed_artifacts_count
@@ -39,26 +35,12 @@ module Ci
def destroy_unlocked_job_artifacts
loop_until(timeout: LOOP_TIMEOUT, limit: LOOP_LIMIT) do
- artifacts = Ci::JobArtifact.expired_before(@start_at).artifact_unlocked.limit(BATCH_SIZE)
+ artifacts = Ci::JobArtifact.expired_before(@start_at).non_trace.artifact_unlocked.limit(BATCH_SIZE)
service_response = destroy_batch(artifacts)
@removed_artifacts_count += service_response[:destroyed_artifacts_count]
end
end
- def destroy_job_artifacts_with_slow_iteration
- Ci::JobArtifact.expired_before(@start_at).each_batch(of: BATCH_SIZE, column: :expire_at, order: :desc) do |relation, index|
- # For performance reasons, join with ci_pipelines after the batch is queried.
- # See: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47496
- artifacts = relation.unlocked
-
- service_response = destroy_batch(artifacts)
- @removed_artifacts_count += service_response[:destroyed_artifacts_count]
-
- break if loop_timeout?
- break if index >= LOOP_LIMIT
- end
- end
-
def destroy_batch(artifacts)
Ci::JobArtifacts::DestroyBatchService.new(artifacts, skip_projects_on_refresh: true).execute
end
diff --git a/app/services/ci/job_artifacts/destroy_batch_service.rb b/app/services/ci/job_artifacts/destroy_batch_service.rb
index 7cb1be95a3e..81cbeb31711 100644
--- a/app/services/ci/job_artifacts/destroy_batch_service.rb
+++ b/app/services/ci/job_artifacts/destroy_batch_service.rb
@@ -21,6 +21,7 @@ module Ci
@job_artifacts = job_artifacts.with_destroy_preloads.to_a
@pick_up_at = pick_up_at
@skip_projects_on_refresh = skip_projects_on_refresh
+ @destroyed_ids = []
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -31,16 +32,17 @@ module Ci
track_artifacts_undergoing_stats_refresh
end
- exclude_trace_artifacts
-
- return success(destroyed_artifacts_count: 0, statistics_updates: {}) if @job_artifacts.empty?
+ if @job_artifacts.empty?
+ return success(destroyed_ids: @destroyed_ids, destroyed_artifacts_count: 0, statistics_updates: {})
+ end
destroy_related_records(@job_artifacts)
destroy_around_hook(@job_artifacts) do
+ @destroyed_ids = @job_artifacts.map(&:id)
Ci::DeletedObject.transaction do
Ci::DeletedObject.bulk_import(@job_artifacts, @pick_up_at)
- Ci::JobArtifact.id_in(@job_artifacts.map(&:id)).delete_all
+ Ci::JobArtifact.id_in(@destroyed_ids).delete_all
end
end
@@ -52,7 +54,11 @@ module Ci
Gitlab::Ci::Artifacts::Logger.log_deleted(@job_artifacts, 'Ci::JobArtifacts::DestroyBatchService#execute')
- success(destroyed_artifacts_count: artifacts_count, statistics_updates: statistics_updates_per_project)
+ success(
+ destroyed_ids: @destroyed_ids,
+ destroyed_artifacts_count: artifacts_count,
+ statistics_updates: statistics_updates_per_project
+ )
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -110,11 +116,6 @@ module Ci
end
end
- # Traces should never be destroyed.
- def exclude_trace_artifacts
- _trace_artifacts, @job_artifacts = @job_artifacts.partition(&:trace?)
- end
-
def track_artifacts_undergoing_stats_refresh
project_ids = @job_artifacts.find_all do |artifact|
artifact.project.refreshing_build_artifacts_size?
diff --git a/app/services/ci/job_token_scope/add_project_service.rb b/app/services/ci/job_token_scope/add_project_service.rb
index 15553ad6e92..4f745042f07 100644
--- a/app/services/ci/job_token_scope/add_project_service.rb
+++ b/app/services/ci/job_token_scope/add_project_service.rb
@@ -6,8 +6,6 @@ module Ci
include EditScopeValidations
def execute(target_project, direction: :outbound)
- direction = :outbound if Feature.disabled?(:ci_inbound_job_token_scope)
-
validate_edit!(project, target_project, current_user)
link = allowlist(direction)
diff --git a/app/services/ci/pipeline_processing/atomic_processing_service.rb b/app/services/ci/pipeline_processing/atomic_processing_service.rb
index 2b8eb104be5..4f2230ea1fc 100644
--- a/app/services/ci/pipeline_processing/atomic_processing_service.rb
+++ b/app/services/ci/pipeline_processing/atomic_processing_service.rb
@@ -48,10 +48,10 @@ module Ci
def update_stage!(stage)
# Update processables for a given stage in bulk/slices
@collection
- .created_processable_ids_for_stage_position(stage.position)
+ .created_processable_ids_in_stage(stage.position)
.in_groups_of(BATCH_SIZE, false) { |ids| update_processables!(ids) }
- status = @collection.status_for_stage_position(stage.position)
+ status = @collection.status_of_stage(stage.position)
stage.set_status(status)
end
@@ -79,29 +79,27 @@ module Ci
end
def update_processable!(processable)
- status = processable_status(processable)
- return unless Ci::HasStatus::COMPLETED_STATUSES.include?(status)
+ previous_status = status_of_previous_processables(processable)
+ # We do not continue to process the processable if the previous status is not completed
+ return unless Ci::HasStatus::COMPLETED_STATUSES.include?(previous_status)
- # transition status if possible
Gitlab::OptimisticLocking.retry_lock(processable, name: 'atomic_processing_update_processable') do |subject|
Ci::ProcessBuildService.new(project, subject.user)
- .execute(subject, status)
+ .execute(subject, previous_status)
# update internal representation of status
- # to make the status change of processable
- # to be taken into account during further processing
- @collection.set_processable_status(
- processable.id, processable.status, processable.lock_version)
+ # to make the status change of processable to be taken into account during further processing
+ @collection.set_processable_status(processable.id, processable.status, processable.lock_version)
end
end
- def processable_status(processable)
+ def status_of_previous_processables(processable)
if processable.scheduling_type_dag?
# Processable uses DAG, get status of all dependent needs
- @collection.status_for_names(processable.aggregated_needs_names.to_a, dag: true)
+ @collection.status_of_processables(processable.aggregated_needs_names.to_a, dag: true)
else
# Processable uses Stages, get status of prior stage
- @collection.status_for_prior_stage_position(processable.stage_idx.to_i)
+ @collection.status_of_processables_prior_to_stage(processable.stage_idx.to_i)
end
end
diff --git a/app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb b/app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb
index 676c2ecb257..9738e4e65b7 100644
--- a/app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb
+++ b/app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb
@@ -35,40 +35,40 @@ module Ci
status_for_array(all_statuses, dag: false)
end
+ # This methods gets composite status for processables at a given stage
+ def status_of_stage(stage_position)
+ strong_memoize("status_of_stage_#{stage_position}") do
+ stage_statuses = all_statuses_grouped_by_stage_position[stage_position].to_a
+
+ status_for_array(stage_statuses.flatten, dag: false)
+ end
+ end
+
# This methods gets composite status for processables with given names
- def status_for_names(names, dag:)
+ def status_of_processables(names, dag:)
name_statuses = all_statuses_by_name.slice(*names)
status_for_array(name_statuses.values, dag: dag)
end
# This methods gets composite status for processables before given stage
- def status_for_prior_stage_position(position)
- strong_memoize("status_for_prior_stage_position_#{position}") do
+ def status_of_processables_prior_to_stage(stage_position)
+ strong_memoize("status_of_processables_prior_to_stage_#{stage_position}") do
stage_statuses = all_statuses_grouped_by_stage_position
- .select { |stage_position, _| stage_position < position }
+ .select { |position, _| position < stage_position }
status_for_array(stage_statuses.values.flatten, dag: false)
end
end
# This methods gets a list of processables for a given stage
- def created_processable_ids_for_stage_position(current_position)
- all_statuses_grouped_by_stage_position[current_position]
+ def created_processable_ids_in_stage(stage_position)
+ all_statuses_grouped_by_stage_position[stage_position]
.to_a
.select { |processable| processable[:status] == 'created' }
.map { |processable| processable[:id] }
end
- # This methods gets composite status for processables at a given stage
- def status_for_stage_position(current_position)
- strong_memoize("status_for_stage_position_#{current_position}") do
- stage_statuses = all_statuses_grouped_by_stage_position[current_position].to_a
-
- status_for_array(stage_statuses.flatten, dag: false)
- end
- end
-
# This method returns a list of all processable, that are to be processed
def processing_processables
all_statuses.lazy.reject { |status| status[:processed] }
diff --git a/app/services/ci/pipeline_schedules/take_ownership_service.rb b/app/services/ci/pipeline_schedules/take_ownership_service.rb
index 9b4001c74bd..b4d193cb875 100644
--- a/app/services/ci/pipeline_schedules/take_ownership_service.rb
+++ b/app/services/ci/pipeline_schedules/take_ownership_service.rb
@@ -23,7 +23,7 @@ module Ci
attr_reader :schedule, :user
def allowed?
- user.can?(:take_ownership_pipeline_schedule, schedule)
+ user.can?(:admin_pipeline_schedule, schedule)
end
def forbidden
diff --git a/app/services/ci/process_build_service.rb b/app/services/ci/process_build_service.rb
index a5300cfd29f..afaf18a4de2 100644
--- a/app/services/ci/process_build_service.rb
+++ b/app/services/ci/process_build_service.rb
@@ -2,40 +2,40 @@
module Ci
class ProcessBuildService < BaseService
- def execute(build, current_status)
- if valid_statuses_for_build(build).include?(current_status)
- process(build)
+ def execute(processable, current_status)
+ if valid_statuses_for_processable(processable).include?(current_status)
+ process(processable)
true
else
- build.skip
+ processable.skip
false
end
end
private
- def process(build)
- return enqueue(build) if build.enqueue_immediately?
+ def process(processable)
+ return enqueue(processable) if processable.enqueue_immediately?
- if build.schedulable?
- build.schedule
- elsif build.action?
- build.actionize
+ if processable.schedulable?
+ processable.schedule
+ elsif processable.action?
+ processable.actionize
else
- enqueue(build)
+ enqueue(processable)
end
end
- def enqueue(build)
- return build.drop!(:failed_outdated_deployment_job) if build.outdated_deployment?
+ def enqueue(processable)
+ return processable.drop!(:failed_outdated_deployment_job) if processable.outdated_deployment?
- build.enqueue
+ processable.enqueue
end
- def valid_statuses_for_build(build)
- case build.when
+ def valid_statuses_for_processable(processable)
+ case processable.when
when 'on_success', 'manual', 'delayed'
- build.scheduling_type_dag? ? %w[success] : %w[success skipped]
+ processable.scheduling_type_dag? ? %w[success] : %w[success skipped]
when 'on_failure'
%w[failed]
when 'always'
diff --git a/app/services/ci/queue/pending_builds_strategy.rb b/app/services/ci/queue/pending_builds_strategy.rb
index cfafe66d10b..b2929390e58 100644
--- a/app/services/ci/queue/pending_builds_strategy.rb
+++ b/app/services/ci/queue/pending_builds_strategy.rb
@@ -57,9 +57,10 @@ module Ci
# if disaster recovery is enabled, we fallback to FIFO scheduling
relation.order('ci_pending_builds.build_id ASC')
else
- # Implement fair scheduling
- # this returns builds that are ordered by number of running builds
- # we prefer projects that don't use shared runners at all
+ # Implements Fair Scheduling
+ # Builds are ordered by projects that have the fewest running builds.
+ # This keeps projects that create many builds at once from hogging capacity but
+ # has the downside of penalizing projects with lots of builds created in a short period of time
relation
.with(running_builds_for_shared_runners_cte.to_arel)
.joins("LEFT JOIN project_builds ON ci_pending_builds.project_id = project_builds.project_id")
diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb
index 205da2632c2..228a246f480 100644
--- a/app/services/ci/register_job_service.rb
+++ b/app/services/ci/register_job_service.rb
@@ -244,7 +244,6 @@ module Ci
def assign_runner!(build, params)
build.runner_id = runner.id
build.runner_session_attributes = params[:session] if params[:session].present?
- build.ensure_metadata.runner_machine = runner_machine if runner_machine
failure_reason, _ = pre_assign_runner_checks.find { |_, check| check.call(build, params) }
@@ -256,6 +255,7 @@ module Ci
@metrics.increment_queue_operation(:runner_pre_assign_checks_success)
build.run!
+ build.runner_machine = runner_machine if runner_machine
end
!failure_reason
diff --git a/app/services/ci/runners/create_runner_service.rb b/app/services/ci/runners/create_runner_service.rb
index 2de9ee4d38e..5906cdce99d 100644
--- a/app/services/ci/runners/create_runner_service.rb
+++ b/app/services/ci/runners/create_runner_service.rb
@@ -33,7 +33,7 @@ module Ci
def normalize_params
params[:registration_type] = :authenticated_user
params[:runner_type] = type
- params[:active] = !params.delete(:paused) if params[:paused].present?
+ params[:active] = !params.delete(:paused) if params.key?(:paused)
params[:creator] = user
strategy.normalize_params
diff --git a/app/services/ci/runners/process_runner_version_update_service.rb b/app/services/ci/runners/process_runner_version_update_service.rb
index c8a5e42ccab..5c42a2ab018 100644
--- a/app/services/ci/runners/process_runner_version_update_service.rb
+++ b/app/services/ci/runners/process_runner_version_update_service.rb
@@ -8,6 +8,7 @@ module Ci
end
def execute
+ return ServiceResponse.error(message: 'version update disabled') unless enabled?
return ServiceResponse.error(message: 'version not present') unless @version
_, status = upgrade_check_service.check_runner_upgrade_suggestion(@version)
@@ -22,6 +23,10 @@ module Ci
def upgrade_check_service
@runner_upgrade_check ||= Gitlab::Ci::RunnerUpgradeCheck.new(::Gitlab::VERSION)
end
+
+ def enabled?
+ Gitlab::Ci::RunnerReleases.instance.enabled?
+ end
end
end
end
diff --git a/app/services/ci/update_build_queue_service.rb b/app/services/ci/update_build_queue_service.rb
index 58927a90b6e..40941dd4cd0 100644
--- a/app/services/ci/update_build_queue_service.rb
+++ b/app/services/ci/update_build_queue_service.rb
@@ -37,7 +37,7 @@ module Ci
end
##
- # Force recemove build from the queue, without checking a transition state
+ # Force remove build from the queue, without checking a transition state
#
def remove!(build)
removed = build.all_queuing_entries.delete_all
diff --git a/app/services/clusters/agent_tokens/create_service.rb b/app/services/clusters/agent_tokens/create_service.rb
index 2539ffdc5ba..66a3cb04d98 100644
--- a/app/services/clusters/agent_tokens/create_service.rb
+++ b/app/services/clusters/agent_tokens/create_service.rb
@@ -2,16 +2,24 @@
module Clusters
module AgentTokens
- class CreateService < ::BaseContainerService
+ class CreateService
ALLOWED_PARAMS = %i[agent_id description name].freeze
+ attr_reader :agent, :current_user, :params
+
+ def initialize(agent:, current_user:, params:)
+ @agent = agent
+ @current_user = current_user
+ @params = params
+ end
+
def execute
- return error_no_permissions unless current_user.can?(:create_cluster, container)
+ return error_no_permissions unless current_user.can?(:create_cluster, agent.project)
- token = ::Clusters::AgentToken.new(filtered_params.merge(created_by_user: current_user))
+ token = ::Clusters::AgentToken.new(filtered_params.merge(agent_id: agent.id, created_by_user: current_user))
if token.save
- log_activity_event!(token)
+ log_activity_event(token)
ServiceResponse.success(payload: { secret: token.token, token: token })
else
@@ -29,7 +37,7 @@ module Clusters
params.slice(*ALLOWED_PARAMS)
end
- def log_activity_event!(token)
+ def log_activity_event(token)
Clusters::Agents::CreateActivityEventService.new(
token.agent,
kind: :token_created,
@@ -42,3 +50,5 @@ module Clusters
end
end
end
+
+Clusters::AgentTokens::CreateService.prepend_mod
diff --git a/app/services/clusters/agent_tokens/revoke_service.rb b/app/services/clusters/agent_tokens/revoke_service.rb
new file mode 100644
index 00000000000..5d89b405969
--- /dev/null
+++ b/app/services/clusters/agent_tokens/revoke_service.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Clusters
+ module AgentTokens
+ class RevokeService
+ attr_reader :current_project, :current_user, :token
+
+ def initialize(token:, current_user:)
+ @token = token
+ @current_user = current_user
+ end
+
+ def execute
+ return error_no_permissions unless current_user.can?(:create_cluster, token.agent.project)
+
+ if token.update(status: token.class.statuses[:revoked])
+ log_activity_event(token)
+
+ ServiceResponse.success
+ else
+ ServiceResponse.error(message: token.errors.full_messages)
+ end
+ end
+
+ private
+
+ def error_no_permissions
+ ServiceResponse.error(
+ message: s_('ClusterAgent|User has insufficient permissions to revoke the token for this project'))
+ end
+
+ def log_activity_event(token)
+ Clusters::Agents::CreateActivityEventService.new(
+ token.agent,
+ kind: :token_revoked,
+ level: :info,
+ recorded_at: token.updated_at,
+ user: current_user,
+ agent_token: token
+ ).execute
+ end
+ end
+ end
+end
+
+Clusters::AgentTokens::RevokeService.prepend_mod
diff --git a/app/services/clusters/agents/authorize_proxy_user_service.rb b/app/services/clusters/agents/authorize_proxy_user_service.rb
new file mode 100644
index 00000000000..ec6645b2db4
--- /dev/null
+++ b/app/services/clusters/agents/authorize_proxy_user_service.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ class AuthorizeProxyUserService < ::BaseService
+ include ::Gitlab::Utils::StrongMemoize
+
+ def initialize(current_user, agent)
+ @current_user = current_user
+ @agent = agent
+ end
+
+ def execute
+ return forbidden unless user_access_config.present?
+
+ access_as = user_access_config[:access_as]
+ return forbidden unless access_as.present?
+ return forbidden if access_as.size != 1
+
+ if authorizations = handle_access(access_as, user_access_config)
+ return success(payload: authorizations)
+ end
+
+ forbidden
+ end
+
+ private
+
+ attr_reader :current_user, :agent
+
+ # Override in EE
+ def handle_access(access_as, user_access)
+ access_as_agent(user_access) if access_as.key?(:agent)
+ end
+
+ def response_base
+ {
+ agent: {
+ id: agent.id,
+ config_project: { id: agent.project.id }
+ },
+ user: {
+ id: current_user.id,
+ username: current_user.username
+ }
+ }
+ end
+
+ def access_as_agent(user_access)
+ projects = authorized_projects(user_access)
+ groups = authorized_groups(user_access)
+ return unless projects.size + groups.size > 0
+
+ response_base.merge(access_as: { agent: {} })
+ end
+
+ def authorized_projects(user_access)
+ strong_memoize_with(:authorized_projects, user_access) do
+ user_access.fetch(:projects, [])
+ .first(::Clusters::Agents::RefreshAuthorizationService::AUTHORIZED_ENTITY_LIMIT)
+ .map { |project| ::Project.find_by_full_path(project[:id]) }
+ .select { |project| current_user.can?(:use_k8s_proxies, project) }
+ end
+ end
+
+ def authorized_groups(user_access)
+ strong_memoize_with(:authorized_groups, user_access) do
+ user_access.fetch(:groups, [])
+ .first(::Clusters::Agents::RefreshAuthorizationService::AUTHORIZED_ENTITY_LIMIT)
+ .map { |group| ::Group.find_by_full_path(group[:id]) }
+ .select { |group| current_user.can?(:use_k8s_proxies, group) }
+ end
+ end
+
+ def user_access_config
+ # TODO: Read the configuration from the database once it has been
+ # indexed. See https://gitlab.com/gitlab-org/gitlab/-/issues/389430
+ branch = agent.project.default_branch_or_main
+ path = ".gitlab/agents/#{agent.name}/config.yaml"
+ config_yaml = agent.project.repository
+ &.blob_at_branch(branch, path)
+ &.data
+ return unless config_yaml.present?
+
+ config = YAML.safe_load(config_yaml, aliases: true, symbolize_names: true)
+ config[:user_access]
+ end
+ strong_memoize_attr :user_access_config
+
+ delegate :success, to: ServiceResponse, private: true
+
+ def forbidden
+ ServiceResponse.error(reason: :forbidden, message: '403 Forbidden')
+ end
+ end
+ end
+end
+
+Clusters::Agents::AuthorizeProxyUserService.prepend_mod
diff --git a/app/services/clusters/agents/create_activity_event_service.rb b/app/services/clusters/agents/create_activity_event_service.rb
index 886dddf1a52..87554f0e495 100644
--- a/app/services/clusters/agents/create_activity_event_service.rb
+++ b/app/services/clusters/agents/create_activity_event_service.rb
@@ -14,6 +14,10 @@ module Clusters
DeleteExpiredEventsWorker.perform_at(schedule_cleanup_at, agent.id)
ServiceResponse.success
+ rescue StandardError => e
+ Gitlab::ErrorTracking.track_exception(e, agent_id: agent.id)
+
+ ServiceResponse.error(message: e.message)
end
private
diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb
index dc7f84ab807..0b97aae9972 100644
--- a/app/services/commits/change_service.rb
+++ b/app/services/commits/change_service.rb
@@ -29,12 +29,24 @@ module Commits
dry_run: @dry_run
)
rescue Gitlab::Git::Repository::CreateTreeError => ex
- act = action.to_s.dasherize
type = @commit.change_type_title(current_user)
- error_msg = "Sorry, we cannot #{act} this #{type} automatically. " \
- "This #{type} may already have been #{act}ed, or a more recent " \
- "commit may have updated some of its content."
+ status = case [type, action]
+ when ['commit', :cherry_pick]
+ s_("MergeRequests|Commit cherry-pick failed")
+ when ['commit', :revert]
+ s_("MergeRequests|Commit revert failed")
+ when ['merge request', :cherry_pick]
+ s_("MergeRequests|Merge request cherry-pick failed")
+ when ['merge request', :revert]
+ s_("MergeRequests|Merge request revert failed")
+ end
+
+ detail = s_("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.")
+
+ error_msg = "#{status}: #{detail}"
raise ChangeError.new(error_msg, ex.error_code)
end
diff --git a/app/services/concerns/incident_management/usage_data.rb b/app/services/concerns/incident_management/usage_data.rb
index 40183085344..775dea9b949 100644
--- a/app/services/concerns/incident_management/usage_data.rb
+++ b/app/services/concerns/incident_management/usage_data.rb
@@ -13,8 +13,6 @@ module IncidentManagement
namespace = target.try(:namespace)
project = target.try(:project)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, target.try(:namespace))
-
Gitlab::Tracking.event(
self.class.to_s,
event,
diff --git a/app/services/concerns/update_repository_storage_methods.rb b/app/services/concerns/update_repository_storage_methods.rb
index b21d05f4178..a0b4040cff7 100644
--- a/app/services/concerns/update_repository_storage_methods.rb
+++ b/app/services/concerns/update_repository_storage_methods.rb
@@ -28,10 +28,7 @@ module UpdateRepositoryStorageMethods
track_repository(destination_storage_name)
end
- unless same_filesystem?
- remove_old_paths
- enqueue_housekeeping
- end
+ remove_old_paths unless same_filesystem?
repository_storage_move.finish_cleanup!
@@ -95,10 +92,6 @@ module UpdateRepositoryStorageMethods
end
end
- def enqueue_housekeeping
- # no-op
- end
-
def wait_for_pushes(type)
reference_counter = container.reference_counter(type: type)
diff --git a/app/services/container_expiration_policies/cleanup_service.rb b/app/services/container_expiration_policies/cleanup_service.rb
index 1123b29f217..6c2b41a4daf 100644
--- a/app/services/container_expiration_policies/cleanup_service.rb
+++ b/app/services/container_expiration_policies/cleanup_service.rb
@@ -19,7 +19,6 @@ module ContainerExpirationPolicies
return ServiceResponse.error(message: 'invalid policy')
end
- repository.start_expiration_policy!
schedule_next_run_if_needed
begin
diff --git a/app/services/dependency_proxy/head_manifest_service.rb b/app/services/dependency_proxy/head_manifest_service.rb
index cd575b83a98..5bc5cb45a12 100644
--- a/app/services/dependency_proxy/head_manifest_service.rb
+++ b/app/services/dependency_proxy/head_manifest_service.rb
@@ -2,7 +2,7 @@
module DependencyProxy
class HeadManifestService < DependencyProxy::BaseService
- ACCEPT_HEADERS = ::ContainerRegistry::Client::ACCEPTED_TYPES.join(',')
+ ACCEPT_HEADERS = DependencyProxy::Manifest::ACCEPTED_TYPES.join(',')
def initialize(image, tag, token)
@image = image
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index d848f694598..96edaa06fc2 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -28,7 +28,7 @@ class EventCreateService
def open_mr(merge_request, current_user)
create_record_event(merge_request, current_user, :created).tap do
- track_event(event_action: :created, event_target: MergeRequest, author_id: current_user.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: current_user.id)
track_snowplow_event(
action: :created,
project: merge_request.project,
@@ -41,7 +41,7 @@ class EventCreateService
def close_mr(merge_request, current_user)
create_record_event(merge_request, current_user, :closed).tap do
- track_event(event_action: :closed, event_target: MergeRequest, author_id: current_user.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: current_user.id)
track_snowplow_event(
action: :closed,
project: merge_request.project,
@@ -58,7 +58,7 @@ class EventCreateService
def merge_mr(merge_request, current_user)
create_record_event(merge_request, current_user, :merged).tap do
- track_event(event_action: :merged, event_target: MergeRequest, author_id: current_user.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: current_user.id)
track_snowplow_event(
action: :merged,
project: merge_request.project,
@@ -88,7 +88,7 @@ class EventCreateService
def leave_note(note, current_user)
create_record_event(note, current_user, :commented).tap do
if note.is_a?(DiffNote) && note.for_merge_request?
- track_event(event_action: :commented, event_target: MergeRequest, author_id: current_user.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: current_user.id)
track_snowplow_event(
action: :commented,
project: note.project,
@@ -128,12 +128,17 @@ class EventCreateService
records = create.zip([:created].cycle) + update.zip([:updated].cycle)
return [] if records.empty?
- event_meta = { user: current_user, label: DEGIGN_EVENT_LABEL, property: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION }
+ event_meta = { user: current_user, label: DEGIGN_EVENT_LABEL, property: :design_action }
track_snowplow_event(action: :create, project: create.first.project, **event_meta) if create.any?
track_snowplow_event(action: :update, project: update.first.project, **event_meta) if update.any?
- create_record_events(records, current_user)
+ inserted_events = create_record_events(records, current_user)
+
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:design_action, values: current_user.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:git_write_action, values: current_user.id)
+
+ inserted_events
end
def destroy_designs(designs, current_user)
@@ -144,9 +149,15 @@ class EventCreateService
project: designs.first.project,
user: current_user,
label: DEGIGN_EVENT_LABEL,
- property: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION
+ property: :design_action
)
- create_record_events(designs.zip([:destroyed].cycle), current_user)
+
+ inserted_events = create_record_events(designs.zip([:destroyed].cycle), current_user)
+
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:design_action, values: current_user.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:git_write_action, values: current_user.id)
+
+ inserted_events
end
# Create a new wiki page event
@@ -163,7 +174,8 @@ class EventCreateService
def wiki_event(wiki_page_meta, author, action, fingerprint)
raise IllegalActionError, action unless Event::WIKI_ACTIONS.include?(action)
- track_event(event_action: action, event_target: wiki_page_meta.class, author_id: author.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:wiki_action, values: author.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:git_write_action, values: author.id)
duplicate = Event.for_wiki_meta(wiki_page_meta).for_fingerprint(fingerprint).first
return duplicate if duplicate.present?
@@ -205,13 +217,7 @@ class EventCreateService
.merge(action: action, fingerprint: fingerprint, target_id: record.id, target_type: record.class.name)
end
- result = Event.insert_all(attribute_sets, returning: %w[id])
-
- tuples.each do |record, status, _|
- track_event(event_action: status, event_target: record.class, author_id: current_user.id)
- end
-
- result
+ Event.insert_all(attribute_sets, returning: %w[id])
end
def create_push_event(service_class, project, current_user, push_data)
@@ -226,7 +232,8 @@ class EventCreateService
new_event
end
- track_event(event_action: :pushed, event_target: Project, author_id: current_user.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:project_action, values: current_user.id)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:git_write_action, values: current_user.id)
namespace = project.namespace
Gitlab::Tracking.event(
@@ -273,13 +280,7 @@ class EventCreateService
{ resource_parent_attr => resource_parent.id }
end
- def track_event(...)
- Gitlab::UsageDataCounters::TrackUniqueEvents.track_event(...)
- end
-
def track_snowplow_event(action:, project:, user:, label:, property:)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2)
-
Gitlab::Tracking.event(
self.class.to_s,
action.to_s,
diff --git a/app/services/feature_flags/base_service.rb b/app/services/feature_flags/base_service.rb
index 59db1a5f12f..028906a0b43 100644
--- a/app/services/feature_flags/base_service.rb
+++ b/app/services/feature_flags/base_service.rb
@@ -7,42 +7,24 @@ module FeatureFlags
AUDITABLE_ATTRIBUTES = %w(name description active).freeze
def success(**args)
- audit_event = args.fetch(:audit_event) { audit_event(args[:feature_flag]) }
- save_audit_event(audit_event)
sync_to_jira(args[:feature_flag])
+
+ audit_event(args[:feature_flag], args[:audit_context])
super
end
protected
- def update_last_feature_flag_updated_at!
- Operations::FeatureFlagsClient.update_last_feature_flag_updated_at!(project)
- end
-
- def audit_event(feature_flag)
- message = audit_message(feature_flag)
+ def audit_event(feature_flag, context = nil)
+ context ||= audit_context(feature_flag)
- return if message.blank?
+ return if context[:message].blank?
- details =
- {
- custom_message: message,
- target_id: feature_flag.id,
- target_type: feature_flag.class.name,
- target_details: feature_flag.name
- }
-
- ::AuditEventService.new(
- current_user,
- feature_flag.project,
- details
- )
+ ::Gitlab::Audit::Auditor.audit(context)
end
- def save_audit_event(audit_event)
- return unless audit_event
-
- audit_event.security_event
+ def update_last_feature_flag_updated_at!
+ Operations::FeatureFlagsClient.update_last_feature_flag_updated_at!(project)
end
def sync_to_jira(feature_flag)
diff --git a/app/services/feature_flags/create_service.rb b/app/services/feature_flags/create_service.rb
index 6ea40345191..2a3153e6a54 100644
--- a/app/services/feature_flags/create_service.rb
+++ b/app/services/feature_flags/create_service.rb
@@ -21,6 +21,16 @@ module FeatureFlags
private
+ def audit_context(feature_flag)
+ {
+ name: 'feature_flag_created',
+ message: audit_message(feature_flag),
+ author: current_user,
+ scope: feature_flag.project,
+ target: feature_flag
+ }
+ end
+
def audit_message(feature_flag)
message_parts = ["Created feature flag #{feature_flag.name} with description \"#{feature_flag.description}\"."]
diff --git a/app/services/feature_flags/destroy_service.rb b/app/services/feature_flags/destroy_service.rb
index 0fdc890b8a3..fdcbb802b16 100644
--- a/app/services/feature_flags/destroy_service.rb
+++ b/app/services/feature_flags/destroy_service.rb
@@ -22,6 +22,16 @@ module FeatureFlags
end
end
+ def audit_context(feature_flag)
+ {
+ name: 'feature_flag_deleted',
+ message: audit_message(feature_flag),
+ author: current_user,
+ scope: feature_flag.project,
+ target: feature_flag
+ }
+ end
+
def audit_message(feature_flag)
"Deleted feature flag #{feature_flag.name}."
end
diff --git a/app/services/feature_flags/update_service.rb b/app/services/feature_flags/update_service.rb
index a465ca1dd5f..555b5a93d23 100644
--- a/app/services/feature_flags/update_service.rb
+++ b/app/services/feature_flags/update_service.rb
@@ -25,13 +25,13 @@ module FeatureFlags
end
end
- # We generate the audit event before the feature flag is saved as #changed_strategies_messages depends on the strategies' states before save
- audit_event = audit_event(feature_flag)
+ # We generate the audit context before the feature flag is saved as #changed_strategies_messages depends on the strategies' states before save
+ saved_audit_context = audit_context feature_flag
if feature_flag.save
update_last_feature_flag_updated_at!
- success(feature_flag: feature_flag, audit_event: audit_event)
+ success(feature_flag: feature_flag, audit_context: saved_audit_context)
else
error(feature_flag.errors.full_messages, :bad_request)
end
@@ -50,6 +50,16 @@ module FeatureFlags
end
end
+ def audit_context(feature_flag)
+ {
+ name: 'feature_flag_updated',
+ message: audit_message(feature_flag),
+ author: current_user,
+ scope: feature_flag.project,
+ target: feature_flag
+ }
+ end
+
def audit_message(feature_flag)
changes = changed_attributes_messages(feature_flag)
changes += changed_strategies_messages(feature_flag)
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index 8f722de2019..613785d01cc 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -26,16 +26,23 @@ module Files
def file_has_changed?(path, commit_id)
return false unless commit_id
- last_commit = Gitlab::Git::Commit
- .last_for_path(@start_project.repository, @start_branch, path, literal_pathspec: true)
+ last_commit_from_branch = get_last_commit_for_path(ref: @start_branch, path: path)
- return false unless last_commit
+ return false unless last_commit_from_branch
- last_commit.sha != commit_id
+ last_commit_from_commit_id = get_last_commit_for_path(ref: commit_id, path: path)
+
+ return false unless last_commit_from_commit_id
+
+ last_commit_from_branch.sha != last_commit_from_commit_id.sha
end
private
+ def get_last_commit_for_path(ref:, path:)
+ Gitlab::Git::Commit.last_for_path(@start_project.repository, ref, path, literal_pathspec: true)
+ end
+
def commit_email(git_user)
return params[:author_email] if params[:author_email].present?
return unless current_user
diff --git a/app/services/groups/autocomplete_service.rb b/app/services/groups/autocomplete_service.rb
index 92b05d9ac08..5b9d60495e9 100644
--- a/app/services/groups/autocomplete_service.rb
+++ b/app/services/groups/autocomplete_service.rb
@@ -13,7 +13,7 @@ module Groups
IssuesFinder.new(current_user, finder_params)
.execute
.preload(project: :namespace)
- .select(:iid, :title, :project_id)
+ .select(:iid, :title, :project_id, :namespace_id)
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/services/groups/group_links/create_service.rb b/app/services/groups/group_links/create_service.rb
index 9c1a003ff36..a6e2c0b952e 100644
--- a/app/services/groups/group_links/create_service.rb
+++ b/app/services/groups/group_links/create_service.rb
@@ -36,3 +36,5 @@ module Groups
end
end
end
+
+Groups::GroupLinks::CreateService.prepend_mod
diff --git a/app/services/groups/group_links/destroy_service.rb b/app/services/groups/group_links/destroy_service.rb
index dc3cab927be..8eed46b28ca 100644
--- a/app/services/groups/group_links/destroy_service.rb
+++ b/app/services/groups/group_links/destroy_service.rb
@@ -24,7 +24,11 @@ module Groups
Gitlab::AppLogger.info(
"Failed to delete GroupGroupLinks with ids: #{links.map(&:id)}.")
end
+
+ links
end
end
end
end
+
+Groups::GroupLinks::DestroyService.prepend_mod
diff --git a/app/services/groups/group_links/update_service.rb b/app/services/groups/group_links/update_service.rb
index 66d0d63cb9b..913bf2bfce7 100644
--- a/app/services/groups/group_links/update_service.rb
+++ b/app/services/groups/group_links/update_service.rb
@@ -15,6 +15,8 @@ module Groups
if requires_authorization_refresh?(group_link_params)
group_link.shared_with_group.refresh_members_authorized_projects(direct_members_only: true)
end
+
+ group_link
end
private
@@ -27,3 +29,5 @@ module Groups
end
end
end
+
+Groups::GroupLinks::UpdateService.prepend_mod
diff --git a/app/services/import/github/cancel_project_import_service.rb b/app/services/import/github/cancel_project_import_service.rb
index 5dce5e73662..62cd0c95eaf 100644
--- a/app/services/import/github/cancel_project_import_service.rb
+++ b/app/services/import/github/cancel_project_import_service.rb
@@ -9,6 +9,8 @@ module Import
if project.import_in_progress?
project.import_state.cancel
+ metrics.track_canceled_import
+
success(project: project)
else
error(cannot_cancel_error_message, :bad_request)
@@ -31,6 +33,10 @@ module Import
project_status: project.import_state.status
)
end
+
+ def metrics
+ @metrics ||= Gitlab::Import::Metrics.new(:github_importer, project)
+ end
end
end
end
diff --git a/app/services/import/validate_remote_git_endpoint_service.rb b/app/services/import/validate_remote_git_endpoint_service.rb
index 1b8fa45e979..2886bd5c9b7 100644
--- a/app/services/import/validate_remote_git_endpoint_service.rb
+++ b/app/services/import/validate_remote_git_endpoint_service.rb
@@ -21,7 +21,9 @@ module Import
def execute
uri = Gitlab::Utils.parse_url(@params[:url])
- return ServiceResponse.error(message: "#{@params[:url]} is not a valid URL") unless uri
+ if !uri || !uri.hostname || Project::VALID_IMPORT_PROTOCOLS.exclude?(uri.scheme)
+ return ServiceResponse.error(message: "#{@params[:url]} is not a valid URL")
+ end
return ServiceResponse.success if uri.scheme == 'git'
diff --git a/app/services/import_csv/base_service.rb b/app/services/import_csv/base_service.rb
index feb76425fb4..1d27a5811c7 100644
--- a/app/services/import_csv/base_service.rb
+++ b/app/services/import_csv/base_service.rb
@@ -2,6 +2,8 @@
module ImportCsv
class BaseService
+ include Gitlab::Utils::StrongMemoize
+
def initialize(user, project, csv_io)
@user = user
@project = project
@@ -9,6 +11,8 @@ module ImportCsv
@results = { success: 0, error_lines: [], parse_error: false }
end
+ PreprocessError = Class.new(StandardError)
+
def execute
process_csv
email_results_to_user
@@ -36,7 +40,22 @@ module ImportCsv
raise NotImplementedError
end
+ def validate_structure!
+ header_line = csv_data.lines.first
+
+ validate_headers_presence!(header_line)
+ detect_col_sep
+ end
+
+ def preprocess!
+ # any logic can be added in subclasses if needed
+ # hence just a no-op rather than NotImplementedError
+ end
+
def process_csv
+ validate_structure!
+ preprocess!
+
with_csv_lines.each do |row, line_no|
attributes = attributes_for(row)
@@ -46,23 +65,30 @@ module ImportCsv
results[:error_lines].push(line_no)
end
end
- rescue ArgumentError, CSV::MalformedCSVError
+ rescue ArgumentError, CSV::MalformedCSVError => e
results[:parse_error] = true
+ results[:error_lines].push(e.line_number) if e.respond_to?(:line_number)
+ rescue PreprocessError
+ results[:parse_error] = false
end
def with_csv_lines
- csv_data = @csv_io.open(&:read).force_encoding(Encoding::UTF_8)
- validate_headers_presence!(csv_data.lines.first)
-
CSV.new(
csv_data,
- col_sep: detect_col_sep(csv_data.lines.first),
+ col_sep: detect_col_sep,
headers: true,
header_converters: :symbol
).each.with_index(2)
end
- def detect_col_sep(header)
+ def csv_data
+ @csv_io.open(&:read).force_encoding(Encoding::UTF_8)
+ end
+ strong_memoize_attr :csv_data
+
+ def detect_col_sep
+ header = csv_data.lines.first
+
if header.include?(",")
","
elsif header.include?(";")
@@ -73,6 +99,7 @@ module ImportCsv
raise CSV::MalformedCSVError.new('Invalid CSV format', 1)
end
end
+ strong_memoize_attr :detect_col_sep
def create_object(attributes)
# NOTE: CSV imports are performed by workers, so we do not have a request context in order
diff --git a/app/services/incident_management/timeline_events/base_service.rb b/app/services/incident_management/timeline_events/base_service.rb
index e997d940ed4..75a3811af2d 100644
--- a/app/services/incident_management/timeline_events/base_service.rb
+++ b/app/services/incident_management/timeline_events/base_service.rb
@@ -29,8 +29,6 @@ module IncidentManagement
namespace = project.namespace
track_usage_event(event, user.id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, namespace)
-
Gitlab::Tracking.event(
self.class.to_s,
event,
diff --git a/app/services/issuable/clone/base_service.rb b/app/services/issuable/clone/base_service.rb
index 02beaaf5d83..a4e815e70fc 100644
--- a/app/services/issuable/clone/base_service.rb
+++ b/app/services/issuable/clone/base_service.rb
@@ -7,11 +7,6 @@ module Issuable
alias_method :old_project, :project
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
def execute(original_entity, target_parent)
@original_entity = original_entity
@target_parent = target_parent
diff --git a/app/services/issuable/destroy_service.rb b/app/services/issuable/destroy_service.rb
index 4c3e518d62b..261afb767bb 100644
--- a/app/services/issuable/destroy_service.rb
+++ b/app/services/issuable/destroy_service.rb
@@ -4,7 +4,7 @@ module Issuable
class DestroyService < IssuableBaseService
# TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
+ super(container: container, current_user: current_user, params: params)
end
def execute(issuable)
diff --git a/app/services/issuable/import_csv/base_service.rb b/app/services/issuable/import_csv/base_service.rb
index 83cf5a67453..9ef9fb76e3c 100644
--- a/app/services/issuable/import_csv/base_service.rb
+++ b/app/services/issuable/import_csv/base_service.rb
@@ -21,7 +21,7 @@ module Issuable
headers.downcase! if headers
return if headers && headers.include?('title') && headers.include?('description')
- raise CSV::MalformedCSVError
+ raise CSV::MalformedCSVError.new('Invalid CSV format - missing required headers.', 1)
end
end
end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 911d04d6b7a..c630d01cd84 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class IssuableBaseService < ::BaseProjectService
+class IssuableBaseService < ::BaseContainerService
private
def self.constructor_container_arg(value)
@@ -10,13 +10,15 @@ class IssuableBaseService < ::BaseProjectService
# Follow on issue to address this:
# https://gitlab.com/gitlab-org/gitlab/-/issues/328438
- { project: value }
+ { container: value }
end
attr_accessor :params, :skip_milestone_email
- def initialize(project:, current_user: nil, params: {})
- super
+ def initialize(container:, current_user: nil, params: {})
+ # we need to exclude project params since they may come from external requests. project should always
+ # be passed as part of the service's initializer
+ super(container: container, current_user: current_user, params: params.except(:project, :project_id))
@skip_milestone_email = @params.delete(:skip_milestone_email)
end
diff --git a/app/services/issues/after_create_service.rb b/app/services/issues/after_create_service.rb
index 011a78029c8..5d10eca2979 100644
--- a/app/services/issues/after_create_service.rb
+++ b/app/services/issues/after_create_service.rb
@@ -2,11 +2,6 @@
module Issues
class AfterCreateService < Issues::BaseService
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
def execute(issue)
todo_service.new_issue(issue, current_user)
delete_milestone_total_issue_counter_cache(issue.milestone)
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 553fb6e2ac9..75ef9f735ab 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -33,6 +33,14 @@ module Issues
private
+ # overriding this because IssuableBaseService#constructor_container_arg returns { project: value }
+ # Issues::ReopenService constructor signature is different now, it takes container instead of project also
+ # IssuableBaseService#change_state dynamically picks one of the `Issues::ReopenService`, `Epics::ReopenService` or
+ # MergeRequests::ReopenService, so we need this method to return { }container: value } for Issues::ReopenService
+ def self.constructor_container_arg(value)
+ { container: value }
+ end
+
def find_work_item_type_id(issue_type)
work_item_type = WorkItems::Type.default_by_type(issue_type)
work_item_type ||= WorkItems::Type.default_issue_type
diff --git a/app/services/issues/build_service.rb b/app/services/issues/build_service.rb
index 877ce09e065..75bd2b88e86 100644
--- a/app/services/issues/build_service.rb
+++ b/app/services/issues/build_service.rb
@@ -4,11 +4,6 @@ module Issues
class BuildService < Issues::BaseService
include ResolveDiscussions
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
def execute
filter_resolve_discussion_params
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index 9fde1cc2ac2..4f6a859e20e 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -2,11 +2,6 @@
module Issues
class CloseService < Issues::BaseService
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
# Closes the supplied issue if the current user is able to do so.
def execute(issue, commit: nil, notifications: true, system_note: true, skip_authorization: false)
return issue unless can_close?(issue, skip_authorization: skip_authorization)
@@ -56,11 +51,6 @@ module Issues
private
- # TODO: remove once MergeRequests::CloseService or IssuableBaseService method is changed.
- def self.constructor_container_arg(value)
- { container: value }
- end
-
def can_close?(issue, skip_authorization: false)
skip_authorization || can?(current_user, :update_issue, issue) || issue.is_a?(ExternalIssue)
end
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index fa5233da489..ec5f9ea8167 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -15,9 +15,10 @@ module Issues
# SpamParams constructor are not otherwise available, spam_params: must be explicitly passed as nil.
def initialize(container:, spam_params:, current_user: nil, params: {}, build_service: nil)
@extra_params = params.delete(:extra_params) || {}
- super(project: container, current_user: current_user, params: params)
+ super(container: container, current_user: current_user, params: params)
@spam_params = spam_params
- @build_service = build_service || BuildService.new(container: project, current_user: current_user, params: params)
+ @build_service = build_service ||
+ BuildService.new(container: project, current_user: current_user, params: params)
end
def execute(skip_system_notes: false)
@@ -100,10 +101,6 @@ module Issues
private
- def self.constructor_container_arg(value)
- { container: value }
- end
-
def handle_quick_actions(issue)
# Do not handle quick actions unless the work item is the default Issue.
# The available quick actions for a work item depend on its type and widgets.
diff --git a/app/services/issues/duplicate_service.rb b/app/services/issues/duplicate_service.rb
index a3213c50f86..1fff9a4a684 100644
--- a/app/services/issues/duplicate_service.rb
+++ b/app/services/issues/duplicate_service.rb
@@ -2,11 +2,6 @@
module Issues
class DuplicateService < Issues::BaseService
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
def execute(duplicate_issue, canonical_issue)
return if canonical_issue == duplicate_issue
return unless can?(current_user, :update_issue, duplicate_issue)
diff --git a/app/services/issues/referenced_merge_requests_service.rb b/app/services/issues/referenced_merge_requests_service.rb
index ba03927136a..ff7cf65e757 100644
--- a/app/services/issues/referenced_merge_requests_service.rb
+++ b/app/services/issues/referenced_merge_requests_service.rb
@@ -2,19 +2,15 @@
module Issues
class ReferencedMergeRequestsService < Issues::BaseService
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
# rubocop: disable CodeReuse/ActiveRecord
def execute(issue)
referenced = referenced_merge_requests(issue)
closed_by = closed_by_merge_requests(issue)
- preloader = ActiveRecord::Associations::Preloader.new
- preloader.preload(referenced + closed_by,
- head_pipeline: { project: [:route, { namespace: :route }] })
+ ActiveRecord::Associations::Preloader.new(
+ records: referenced + closed_by,
+ associations: { head_pipeline: { project: [:route, { namespace: :route }] } }
+ ).call
[sort_by_iid(referenced), sort_by_iid(closed_by)]
end
diff --git a/app/services/issues/related_branches_service.rb b/app/services/issues/related_branches_service.rb
index 3f4413fdfd7..ef6de83fcf4 100644
--- a/app/services/issues/related_branches_service.rb
+++ b/app/services/issues/related_branches_service.rb
@@ -4,11 +4,6 @@
# those with a merge request open referencing the current issue.
module Issues
class RelatedBranchesService < Issues::BaseService
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
def execute(issue)
branch_names_with_mrs = branches_with_merge_request_for(issue)
branches = branches_with_iid_of(issue).reject { |b| branch_names_with_mrs.include?(b[:name]) }
diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb
index ebcf2fb5c83..f4f81e9455a 100644
--- a/app/services/issues/reopen_service.rb
+++ b/app/services/issues/reopen_service.rb
@@ -2,11 +2,6 @@
module Issues
class ReopenService < Issues::BaseService
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
def execute(issue, skip_authorization: false)
return issue unless can_reopen?(issue, skip_authorization: skip_authorization)
@@ -27,14 +22,6 @@ module Issues
private
- # overriding this because IssuableBaseService#constructor_container_arg returns { project: value }
- # Issues::ReopenService constructor signature is different now, it takes container instead of project also
- # IssuableBaseService#change_state dynamically picks one of the `Issues::ReopenService`, `Epics::ReopenService` or
- # MergeRequests::ReopenService, so we need this method to return { }container: value } for Issues::ReopenService
- def self.constructor_container_arg(value)
- { container: value }
- end
-
def can_reopen?(issue, skip_authorization: false)
skip_authorization || can?(current_user, :reopen_issue, issue)
end
diff --git a/app/services/issues/reorder_service.rb b/app/services/issues/reorder_service.rb
index 059b4196b23..1afec4c94f4 100644
--- a/app/services/issues/reorder_service.rb
+++ b/app/services/issues/reorder_service.rb
@@ -4,11 +4,6 @@ module Issues
class ReorderService < Issues::BaseService
include Gitlab::Utils::StrongMemoize
- # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
- def initialize(container:, current_user: nil, params: {})
- super(project: container, current_user: current_user, params: params)
- end
-
def execute(issue)
return false unless can?(current_user, :update_issue, issue)
return false unless move_between_ids
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 71324b3f044..322065c5b7c 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -6,7 +6,7 @@ module Issues
# necessary in many cases, and we don't want to require every caller to explicitly pass it as nil
# to disable spam checking.
def initialize(container:, current_user: nil, params: {}, spam_params: nil)
- super(project: container, current_user: current_user, params: params)
+ super(container: container, current_user: current_user, params: params)
@spam_params = spam_params
end
@@ -116,15 +116,6 @@ module Issues
attr_reader :spam_params
- # TODO: remove this once MergeRequests::UpdateService#initialize is changed to take container as named argument.
- #
- # Issues::UpdateService is used together with MergeRequests::UpdateService in Mutations::Assignable#assign! method
- # however MergeRequests::UpdateService#initialize still takes `project` as param and Issues::UpdateService is being
- # changed to take `container` as param. So we are adding this workaround in the meantime.
- def self.constructor_container_arg(value)
- { container: value }
- end
-
def handle_quick_actions(issue)
# Do not handle quick actions unless the work item is the default Issue.
# The available quick actions for a work item depend on its type and widgets.
diff --git a/app/services/issues/zoom_link_service.rb b/app/services/issues/zoom_link_service.rb
index 4144c293990..bfd3e6a945f 100644
--- a/app/services/issues/zoom_link_service.rb
+++ b/app/services/issues/zoom_link_service.rb
@@ -3,7 +3,7 @@
module Issues
class ZoomLinkService < Issues::BaseService
def initialize(container:, current_user:, params:)
- super(project: container, current_user: current_user, params: params)
+ super
@issue = params.fetch(:issue)
@added_meeting = ZoomMeeting.canonical_meeting(@issue)
diff --git a/app/services/jira_connect_installations/proxy_lifecycle_event_service.rb b/app/services/jira_connect_installations/proxy_lifecycle_event_service.rb
index d94d9e1324e..9f3b4a37672 100644
--- a/app/services/jira_connect_installations/proxy_lifecycle_event_service.rb
+++ b/app/services/jira_connect_installations/proxy_lifecycle_event_service.rb
@@ -82,9 +82,9 @@ module JiraConnectInstallations
Gitlab::IntegrationsLogger.info(
integration: 'JiraConnect',
message: 'Proxy lifecycle event received error response',
- event_type: event,
- status_code: status_code,
- body: body
+ jira_event_type: event,
+ jira_status_code: status_code,
+ jira_body: body
)
end
end
diff --git a/app/services/keys/revoke_service.rb b/app/services/keys/revoke_service.rb
index 42ea9ab73be..9684d4e461e 100644
--- a/app/services/keys/revoke_service.rb
+++ b/app/services/keys/revoke_service.rb
@@ -13,8 +13,6 @@ module Keys
private
def unverify_associated_signatures(key)
- return unless Feature.enabled?(:revoke_ssh_signatures)
-
key.ssh_signatures.each_batch do |batch|
batch.update_all(
verification_status: CommitSignatures::SshSignature.verification_statuses[:revoked_key],
diff --git a/app/services/markup/rendering_service.rb b/app/services/markup/rendering_service.rb
index cd89c170efa..104bdb6dd41 100644
--- a/app/services/markup/rendering_service.rb
+++ b/app/services/markup/rendering_service.rb
@@ -52,6 +52,8 @@ module Markup
def other_markup_unsafe
Gitlab::OtherMarkup.render(file_name, text, context)
+ rescue GitHub::Markup::CommandError
+ ActionController::Base.helpers.simple_format(text)
end
def postprocess(html)
diff --git a/app/services/mattermost/create_team_service.rb b/app/services/mattermost/create_team_service.rb
index 9f6efab1e43..dc448cbc5eb 100644
--- a/app/services/mattermost/create_team_service.rb
+++ b/app/services/mattermost/create_team_service.rb
@@ -9,7 +9,7 @@ module Mattermost
def execute
# The user that creates the team will be Team Admin
- ::Mattermost::Team.new(current_user).create(@group.mattermost_team_params)
+ ::Mattermost::Team.new(current_user).create(**@group.mattermost_team_params)
rescue ::Mattermost::ClientError => e
@group.errors.add(:mattermost_team, e.message)
end
diff --git a/app/services/merge_requests/add_context_service.rb b/app/services/merge_requests/add_context_service.rb
index 2ce6073050e..a9ef3e85911 100644
--- a/app/services/merge_requests/add_context_service.rb
+++ b/app/services/merge_requests/add_context_service.rb
@@ -57,7 +57,7 @@ module MergeRequests
def build_context_commit_rows(merge_request_id, commits)
commits.map.with_index do |commit, index|
# generate context commit information for given commit
- commit_hash = commit.to_hash.except(:parent_ids)
+ commit_hash = commit.to_hash.except(:parent_ids, :referenced_by)
sha = Gitlab::Database::ShaAttribute.serialize(commit_hash.delete(:id))
commit_hash.merge(
merge_request_id: merge_request_id,
@@ -75,7 +75,7 @@ module MergeRequests
diff_order = 0
commits.flat_map.with_index do |commit, index|
- commit_hash = commit.to_hash.except(:parent_ids)
+ commit_hash = commit.to_hash.except(:parent_ids, :referenced_by)
sha = Gitlab::Database::ShaAttribute.serialize(commit_hash.delete(:id))
# generate context commit diff information for given commit
diffs = commit.diffs
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index f6cbe889128..97ca96043fb 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -5,6 +5,12 @@ module MergeRequests
extend ::Gitlab::Utils::Override
include MergeRequests::AssignsMergeParams
+ delegate :repository, to: :project
+
+ def initialize(project:, current_user: nil, params: {})
+ super(container: project, current_user: current_user, params: params)
+ end
+
def create_note(merge_request, state = merge_request.state)
SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, state, nil)
end
@@ -94,6 +100,10 @@ module MergeRequests
private
+ def self.constructor_container_arg(value)
+ { project: value }
+ end
+
def refresh_pipelines_on_merge_requests(merge_request, allow_duplicate: false)
create_pipeline_for(merge_request, current_user, async: true, allow_duplicate: allow_duplicate)
end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 61831a624c7..21e0d9a6e6b 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -127,16 +127,23 @@ module MergeRequests
merge_requests_array = merge_requests.to_a + merge_requests_from_forks.to_a
filter_merge_requests(merge_requests_array).each do |merge_request|
+ skip_merge_status_trigger = true
+
if branch_and_project_match?(merge_request) || @push.force_push?
merge_request.reload_diff(current_user)
# Clear existing merge error if the push were directed at the
# source branch. Clearing the error when the target branch
# changes will hide the error from the user.
merge_request.merge_error = nil
+
+ # Don't skip trigger since we to update the MR's merge status in real-time
+ # when the push if for the MR's source branch and project.
+ skip_merge_status_trigger = false
elsif merge_request.merge_request_diff.includes_any_commits?(push_commit_ids)
merge_request.reload_diff(current_user)
end
+ merge_request.skip_merge_status_trigger = skip_merge_status_trigger
merge_request.mark_as_unchecked
end
diff --git a/app/services/metrics/dashboard/annotations/create_service.rb b/app/services/metrics/dashboard/annotations/create_service.rb
index b86fa82a5e8..47e9afa36b9 100644
--- a/app/services/metrics/dashboard/annotations/create_service.rb
+++ b/app/services/metrics/dashboard/annotations/create_service.rb
@@ -26,7 +26,7 @@ module Metrics
attr_reader :user, :params
def authorize_environment_access(options)
- if environment.nil? || Ability.allowed?(user, :create_metrics_dashboard_annotation, project)
+ if environment.nil? || Ability.allowed?(user, :admin_metrics_dashboard_annotation, project)
options[:environment] = environment
success(options)
else
@@ -35,7 +35,7 @@ module Metrics
end
def authorize_cluster_access(options)
- if cluster.nil? || Ability.allowed?(user, :create_metrics_dashboard_annotation, cluster)
+ if cluster.nil? || Ability.allowed?(user, :admin_metrics_dashboard_annotation, cluster)
options[:cluster] = cluster
success(options)
else
diff --git a/app/services/metrics/dashboard/annotations/delete_service.rb b/app/services/metrics/dashboard/annotations/delete_service.rb
index 3cb22f8d3da..34918c89304 100644
--- a/app/services/metrics/dashboard/annotations/delete_service.rb
+++ b/app/services/metrics/dashboard/annotations/delete_service.rb
@@ -24,7 +24,7 @@ module Metrics
attr_reader :user, :annotation
def authorize_action(_options)
- if Ability.allowed?(user, :delete_metrics_dashboard_annotation, annotation)
+ if Ability.allowed?(user, :admin_metrics_dashboard_annotation, annotation)
success
else
error(s_('MetricsDashboardAnnotation|You are not authorized to delete this annotation'))
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index f5efc480fef..8898f7feb17 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -54,6 +54,7 @@ module Notes
content, update_params, message, command_names = quick_actions_service.execute(note, quick_action_options)
only_commands = content.empty?
note.note = content
+ note.command_names = command_names
yield(only_commands)
@@ -161,10 +162,7 @@ module Notes
track_note_creation_usage_for_merge_requests(note) if note.for_merge_request?
track_incident_action(user, note.noteable, 'incident_comment') if note.for_issue?
track_note_creation_in_ipynb(note)
-
- if Feature.enabled?(:notes_create_service_tracking, project)
- Gitlab::Tracking.event('Notes::CreateService', 'execute', **tracking_data_for(note))
- end
+ track_note_creation_visual_review(note)
if Feature.enabled?(:route_hll_to_snowplow_phase4, project&.namespace) && note.for_commit?
metric_key_path = 'counts.commit_comment'
@@ -208,6 +206,10 @@ module Notes
Gitlab::UsageDataCounters::IpynbDiffActivityCounter.note_created(note)
end
+
+ def track_note_creation_visual_review(note)
+ Gitlab::Tracking.event('Notes::CreateService', 'execute', **tracking_data_for(note))
+ end
end
end
diff --git a/app/services/notes/quick_actions_service.rb b/app/services/notes/quick_actions_service.rb
index 900ace24ab4..ce1204298aa 100644
--- a/app/services/notes/quick_actions_service.rb
+++ b/app/services/notes/quick_actions_service.rb
@@ -14,6 +14,7 @@ module Notes
delegate :commands_executed_count, to: :interpret_service, allow_nil: true
UPDATE_SERVICES = {
+ 'WorkItem' => WorkItems::UpdateService,
'Issue' => Issues::UpdateService,
'MergeRequest' => MergeRequests::UpdateService,
'Commit' => Commits::TagService
@@ -25,6 +26,8 @@ module Notes
end
def self.noteable_update_service_class(note)
+ return update_services['WorkItem'] if note.for_work_item?
+
update_services[note.noteable_type]
end
@@ -63,7 +66,11 @@ module Notes
# Follow-on issue to address this is here:
# https://gitlab.com/gitlab-org/gitlab/-/issues/328734
service =
- if noteable_update_service_class.respond_to?(:constructor_container_arg)
+ if noteable_update_service_class == WorkItems::UpdateService
+ parsed_params = note.noteable.transform_quick_action_params(update_params)
+
+ noteable_update_service_class.new(container: note.resource_parent, current_user: current_user, params: parsed_params[:common], widget_params: parsed_params[:widgets])
+ elsif noteable_update_service_class.respond_to?(:constructor_container_arg)
noteable_update_service_class.new(**noteable_update_service_class.constructor_container_arg(note.resource_parent), current_user: current_user, params: update_params)
else
noteable_update_service_class.new(note.resource_parent, current_user, update_params)
diff --git a/app/services/packages/debian/extract_metadata_service.rb b/app/services/packages/debian/extract_metadata_service.rb
index eb8227d1296..cc9defd2e73 100644
--- a/app/services/packages/debian/extract_metadata_service.rb
+++ b/app/services/packages/debian/extract_metadata_service.rb
@@ -14,6 +14,10 @@ module Packages
def execute
raise ExtractionError, 'invalid package file' unless valid_package_file?
+ if file_type == :unsupported
+ raise ExtractionError, "unsupported file extension for file #{package_file.file_name}"
+ end
+
extract_metadata
end
@@ -28,7 +32,7 @@ module Packages
end
def file_type_basic
- %i[dsc deb udeb buildinfo changes].each do |format|
+ %i[dsc deb udeb buildinfo changes ddeb].each do |format|
return format if package_file.file_name.end_with?(".#{format}")
end
@@ -36,8 +40,8 @@ module Packages
end
def file_type_source
- # https://manpages.debian.org/buster/dpkg-dev/dpkg-source.1.en.html
- %i[gzip bzip2 lzma xz].each do |format|
+ # https://manpages.debian.org/buster/dpkg-dev/dpkg-source.1.en.html#Format:_3.0_(quilt)
+ %i[gz bz2 lzma xz].each do |format|
return :source if package_file.file_name.end_with?(".tar.#{format}")
end
@@ -45,13 +49,12 @@ module Packages
end
def file_type
- strong_memoize(:file_type) do
- file_type_basic || file_type_source || :unknown
- end
+ file_type_basic || file_type_source || :unsupported
end
+ strong_memoize_attr :file_type
def file_type_debian?
- file_type == :deb || file_type == :udeb
+ file_type == :deb || file_type == :udeb || file_type == :ddeb
end
def file_type_meta?
@@ -59,18 +62,17 @@ module Packages
end
def fields
- strong_memoize(:fields) do
- if file_type_debian?
- package_file.file.use_open_file(unlink_early: false) do |file|
- ::Packages::Debian::ExtractDebMetadataService.new(file.file_path).execute
- end
- elsif file_type_meta?
- package_file.file.use_open_file do |file|
- ::Packages::Debian::ParseDebian822Service.new(file.read).execute.each_value.first
- end
+ if file_type_debian?
+ package_file.file.use_open_file(unlink_early: false) do |file|
+ ::Packages::Debian::ExtractDebMetadataService.new(file.file_path).execute
+ end
+ elsif file_type_meta?
+ package_file.file.use_open_file do |file|
+ ::Packages::Debian::ParseDebian822Service.new(file.read).execute.each_value.first
end
end
end
+ strong_memoize_attr :fields
def extract_metadata
architecture = fields['Architecture'] if file_type_debian?
diff --git a/app/services/packages/debian/generate_distribution_service.rb b/app/services/packages/debian/generate_distribution_service.rb
index 12ae6c68918..ee43fe208c9 100644
--- a/app/services/packages/debian/generate_distribution_service.rb
+++ b/app/services/packages/debian/generate_distribution_service.rb
@@ -165,16 +165,29 @@ module Packages
def reuse_or_create_component_file(component, component_file_type, architecture, content)
file_md5 = Digest::MD5.hexdigest(content)
file_sha256 = Digest::SHA256.hexdigest(content)
- component_file = component.files
- .with_file_type(component_file_type)
- .with_architecture(architecture)
- .with_compression_type(nil)
- .with_file_sha256(file_sha256)
- .last
-
- if component_file
+ component_files = component.files
+ .with_file_type(component_file_type)
+ .with_architecture(architecture)
+ .with_compression_type(nil)
+ .order_updated_asc
+ component_file = component_files.with_file_sha256(file_sha256).last
+ last_component_file = component_files.last
+
+ if content.empty? && (!last_component_file || last_component_file.file_sha256 == file_sha256)
+ # Do not create empty component file for empty content
+ # when there is no last component file or when the last component file is empty too
+ component_file = last_component_file || component.files.build(
+ updated_at: release_date,
+ file_type: component_file_type,
+ architecture: architecture,
+ compression_type: nil,
+ size: 0
+ )
+ elsif component_file
+ # Reuse existing component file
component_file.touch(time: release_date)
else
+ # Create a new component file
component_file = component.files.create!(
updated_at: release_date,
file_type: component_file_type,
@@ -182,7 +195,8 @@ module Packages
compression_type: nil,
file: CarrierWaveStringFile.new(content),
file_md5: file_md5,
- file_sha256: file_sha256
+ file_sha256: file_sha256,
+ size: content.size
)
end
@@ -255,7 +269,7 @@ module Packages
# used by ExclusiveLeaseGuard
def lease_key
- "packages:debian:generate_distribution_service:distribution:#{@distribution.id}"
+ "packages:debian:generate_distribution_service:#{@distribution.class.container_type}_distribution:#{@distribution.id}"
end
# used by ExclusiveLeaseGuard
diff --git a/app/services/packages/debian/process_package_file_service.rb b/app/services/packages/debian/process_package_file_service.rb
index 7d2d71184e6..dc16d38902b 100644
--- a/app/services/packages/debian/process_package_file_service.rb
+++ b/app/services/packages/debian/process_package_file_service.rb
@@ -41,7 +41,9 @@ module Packages
raise ArgumentError, 'package file without Debian metadata' unless @package_file.debian_file_metadatum
raise ArgumentError, 'already processed package file' unless @package_file.debian_file_metadatum.unknown?
- return if file_metadata[:file_type] == :deb || file_metadata[:file_type] == :udeb
+ if file_metadata[:file_type] == :deb || file_metadata[:file_type] == :udeb || file_metadata[:file_type] == :ddeb
+ return
+ end
raise ArgumentError, "invalid package file type: #{file_metadata[:file_type]}"
end
diff --git a/app/services/packages/mark_package_for_destruction_service.rb b/app/services/packages/mark_package_for_destruction_service.rb
index 3417febe79a..8ccc242ae36 100644
--- a/app/services/packages/mark_package_for_destruction_service.rb
+++ b/app/services/packages/mark_package_for_destruction_service.rb
@@ -13,7 +13,8 @@ module Packages
package.sync_maven_metadata(current_user)
service_response_success('Package was successfully marked as pending destruction')
- rescue StandardError
+ rescue StandardError => e
+ track_exception(e)
service_response_error('Failed to mark the package as pending destruction', 400)
end
@@ -30,5 +31,13 @@ module Packages
def user_can_delete_package?
can?(current_user, :destroy_package, package.project)
end
+
+ def track_exception(error)
+ Gitlab::ErrorTracking.track_exception(
+ error,
+ project_id: package.project_id,
+ package_id: package.id
+ )
+ end
end
end
diff --git a/app/services/packages/mark_packages_for_destruction_service.rb b/app/services/packages/mark_packages_for_destruction_service.rb
index 023392cf2d9..ade9ad2c974 100644
--- a/app/services/packages/mark_packages_for_destruction_service.rb
+++ b/app/services/packages/mark_packages_for_destruction_service.rb
@@ -31,13 +31,15 @@ module Packages
def execute(batch_size: BATCH_SIZE)
no_access = false
min_batch_size = [batch_size, BATCH_SIZE].min
+ package_ids = []
@packages.each_batch(of: min_batch_size) do |batched_packages|
loaded_packages = batched_packages.including_project_route.to_a
+ package_ids = loaded_packages.map(&:id)
break no_access = true unless can_destroy_packages?(loaded_packages)
- ::Packages::Package.id_in(loaded_packages.map(&:id))
+ ::Packages::Package.id_in(package_ids)
.update_all(status: :pending_destruction)
sync_maven_metadata(loaded_packages)
@@ -47,7 +49,8 @@ module Packages
return UNAUTHORIZED_RESPONSE if no_access
SUCCESS_RESPONSE
- rescue StandardError
+ rescue StandardError => e
+ track_exception(e, package_ids)
ERROR_RESPONSE
end
@@ -75,5 +78,9 @@ module Packages
can?(@current_user, :destroy_package, package)
end
end
+
+ def track_exception(error, package_ids)
+ Gitlab::ErrorTracking.track_exception(error, package_ids: package_ids)
+ end
end
end
diff --git a/app/services/packages/maven/find_or_create_package_service.rb b/app/services/packages/maven/find_or_create_package_service.rb
index b29adf4e11a..ac0c77391d7 100644
--- a/app/services/packages/maven/find_or_create_package_service.rb
+++ b/app/services/packages/maven/find_or_create_package_service.rb
@@ -3,10 +3,13 @@ module Packages
module Maven
class FindOrCreatePackageService < BaseService
SNAPSHOT_TERM = '-SNAPSHOT'
+ MAX_FILE_NAME_LENGTH = 5000
def execute
+ return ServiceResponse.error(message: 'File name is too long') if file_name_too_long?
+
package =
- ::Packages::Maven::PackageFinder.new(current_user, project, path: params[:path])
+ ::Packages::Maven::PackageFinder.new(current_user, project, path: path)
.execute
unless Namespace::PackageSetting.duplicates_allowed?(package)
@@ -32,16 +35,16 @@ module Packages
# - my-company/my-app/maven-metadata.xml
#
# The first upload has to create the proper package (the one with the version set).
- if params[:file_name] == Packages::Maven::Metadata.filename && !params[:path]&.ends_with?(SNAPSHOT_TERM)
- package_name = params[:path]
+ if file_name == Packages::Maven::Metadata.filename && !snapshot_version?
+ package_name = path
version = nil
else
- package_name, _, version = params[:path].rpartition('/')
+ package_name, _, version = path.rpartition('/')
end
package_params = {
name: package_name,
- path: params[:path],
+ path: path,
status: params[:status],
version: version
}
@@ -58,21 +61,55 @@ module Packages
private
- def extname(filename)
- return if filename.blank?
+ def file_name_too_long?
+ return false unless file_name
- File.extname(filename)
+ file_name.size > MAX_FILE_NAME_LENGTH
end
def target_package_is_duplicate?(package)
# duplicate metadata files can be uploaded multiple times
return false if package.version.nil?
- package
- .package_files
- .map { |file| extname(file.file_name) }
- .compact
- .include?(extname(params[:file_name]))
+ existing_file_names = strip_snapshot_parts(
+ package.package_files
+ .map(&:file_name)
+ .compact
+ )
+
+ published_file_name = strip_snapshot_parts_from(file_name)
+ existing_file_names.include?(published_file_name)
+ end
+
+ def strip_snapshot_parts(file_names)
+ return file_names unless snapshot_version?
+
+ Array.wrap(file_names).map { |f| strip_snapshot_parts_from(f) }
+ end
+
+ def strip_snapshot_parts_from(file_name)
+ return file_name unless snapshot_version?
+ return unless file_name
+
+ match_data = file_name.match(Gitlab::Regex::Packages::MAVEN_SNAPSHOT_DYNAMIC_PARTS)
+
+ if match_data
+ file_name.gsub(match_data.captures.last, "")
+ else
+ file_name
+ end
+ end
+
+ def snapshot_version?
+ path&.ends_with?(SNAPSHOT_TERM)
+ end
+
+ def path
+ params[:path]
+ end
+
+ def file_name
+ params[:file_name]
end
end
end
diff --git a/app/services/personal_access_tokens/create_service.rb b/app/services/personal_access_tokens/create_service.rb
index e2f2e220750..adb7924f35e 100644
--- a/app/services/personal_access_tokens/create_service.rb
+++ b/app/services/personal_access_tokens/create_service.rb
@@ -2,11 +2,12 @@
module PersonalAccessTokens
class CreateService < BaseService
- def initialize(current_user:, target_user:, params: {})
+ def initialize(current_user:, target_user:, params: {}, concatenate_errors: true)
@current_user = current_user
@target_user = target_user
@params = params.dup
@ip_address = @params.delete(:ip_address)
+ @concatenate_errors = concatenate_errors
end
def execute
@@ -19,7 +20,10 @@ module PersonalAccessTokens
notification_service.access_token_created(target_user, token.name)
ServiceResponse.success(payload: { personal_access_token: token })
else
- ServiceResponse.error(message: token.errors.full_messages.to_sentence, payload: { personal_access_token: token })
+ message = token.errors.full_messages
+ message = message.to_sentence if @concatenate_errors
+
+ ServiceResponse.error(message: message, payload: { personal_access_token: token })
end
end
diff --git a/app/services/projects/batch_open_merge_requests_count_service.rb b/app/services/projects/batch_open_merge_requests_count_service.rb
new file mode 100644
index 00000000000..62d1b018a55
--- /dev/null
+++ b/app/services/projects/batch_open_merge_requests_count_service.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+# Service class for getting and caching the number of merge requests of several projects
+# Warning: do not user this service with a really large set of projects
+# because the service use maps to retrieve the project ids
+module Projects
+ class BatchOpenMergeRequestsCountService < Projects::BatchCountService
+ # rubocop: disable CodeReuse/ActiveRecord
+ def global_count
+ @global_count ||= count_service.query(project_ids).group(:project_id).count
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def count_service
+ ::Projects::OpenMergeRequestsCountService
+ end
+ end
+end
diff --git a/app/services/projects/blame_service.rb b/app/services/projects/blame_service.rb
index 58e146e5a32..1ea16040655 100644
--- a/app/services/projects/blame_service.rb
+++ b/app/services/projects/blame_service.rb
@@ -5,15 +5,19 @@
module Projects
class BlameService
PER_PAGE = 1000
+ STREAMING_FIRST_PAGE_SIZE = 200
+ STREAMING_PER_PAGE = 2000
def initialize(blob, commit, params)
@blob = blob
@commit = commit
- @page = extract_page(params)
+ @streaming_enabled = streaming_state(params)
@pagination_enabled = pagination_state(params)
+ @page = extract_page(params)
+ @params = params
end
- attr_reader :page
+ attr_reader :page, :streaming_enabled
def blame
Gitlab::Blame.new(blob, commit, range: blame_range)
@@ -28,7 +32,22 @@ module Projects
end
def per_page
- PER_PAGE
+ streaming_enabled ? STREAMING_PER_PAGE : PER_PAGE
+ end
+
+ def total_pages
+ total = (blob_lines_count.to_f / per_page).ceil
+ return total unless streaming_enabled
+
+ ([blob_lines_count - STREAMING_FIRST_PAGE_SIZE, 0].max.to_f / per_page).ceil + 1
+ end
+
+ def total_extra_pages
+ [total_pages - 1, 0].max
+ end
+
+ def streaming_possible
+ Feature.enabled?(:blame_page_streaming, commit.project)
end
private
@@ -36,9 +55,16 @@ module Projects
attr_reader :blob, :commit, :pagination_enabled
def blame_range
- return unless pagination_enabled
+ return unless pagination_enabled || streaming_enabled
first_line = (page - 1) * per_page + 1
+
+ if streaming_enabled
+ return 1..STREAMING_FIRST_PAGE_SIZE if page == 1
+
+ first_line = STREAMING_FIRST_PAGE_SIZE + (page - 2) * per_page + 1
+ end
+
last_line = (first_line + per_page).to_i - 1
first_line..last_line
@@ -52,6 +78,12 @@ module Projects
page
end
+ def streaming_state(params)
+ return false unless streaming_possible
+
+ Gitlab::Utils.to_boolean(params[:streaming], default: false)
+ end
+
def pagination_state(params)
return false if Gitlab::Utils.to_boolean(params[:no_pagination], default: false)
@@ -59,7 +91,7 @@ module Projects
end
def overlimit?(page)
- page * per_page >= blob_lines_count + per_page
+ page > total_pages
end
def blob_lines_count
diff --git a/app/services/projects/container_repository/gitlab/cleanup_tags_service.rb b/app/services/projects/container_repository/gitlab/cleanup_tags_service.rb
index b69a3cc1a2c..714a9d43333 100644
--- a/app/services/projects/container_repository/gitlab/cleanup_tags_service.rb
+++ b/app/services/projects/container_repository/gitlab/cleanup_tags_service.rb
@@ -45,12 +45,12 @@ module Projects
end
def with_timeout
- result = {
+ result = success(
original_size: 0,
before_delete_size: 0,
deleted_size: 0,
deleted: []
- }
+ )
yield Time.zone.now, result
diff --git a/app/services/projects/forks/sync_service.rb b/app/services/projects/forks/sync_service.rb
new file mode 100644
index 00000000000..4c70d7f17f5
--- /dev/null
+++ b/app/services/projects/forks/sync_service.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+module Projects
+ module Forks
+ # A service for fetching upstream default branch and merging it to the fork's specified branch.
+ class SyncService < BaseService
+ ONGOING_MERGE_ERROR = 'The synchronization did not happen due to another merge in progress'
+
+ MergeError = Class.new(StandardError)
+
+ def initialize(project, user, target_branch)
+ super(project, user)
+
+ @source_project = project.fork_source
+ @head_sha = project.repository.commit(target_branch).sha
+ @target_branch = target_branch
+ @details = Projects::Forks::Details.new(project, target_branch)
+ end
+
+ def execute
+ execute_service
+
+ ServiceResponse.success
+ rescue MergeError => e
+ Gitlab::ErrorTracking.log_exception(e, { project_id: project.id, user_id: current_user.id })
+
+ ServiceResponse.error(message: e.message)
+ ensure
+ details.exclusive_lease.cancel
+ end
+
+ private
+
+ attr_reader :source_project, :head_sha, :target_branch, :details
+
+ # The method executes multiple steps:
+ #
+ # 1. Gitlab::Git::CrossRepo fetches upstream default branch into a temporary ref and returns new source sha.
+ # 2. New divergence counts are calculated using the source sha.
+ # 3. If the fork is not behind, there is nothing to merge -> exit.
+ # 4. Otherwise, continue with the new source sha.
+ # 5. If Gitlab::Git::CommandError is raised it means that merge couldn't happen due to a merge conflict. The
+ # details are updated to transfer this error to the user.
+ def execute_service
+ counts = []
+ source_sha = source_project.commit.sha
+
+ Gitlab::Git::CrossRepo.new(repository, source_project.repository)
+ .execute(source_sha) do |cross_repo_source_sha|
+ counts = repository.diverging_commit_count(head_sha, cross_repo_source_sha)
+ ahead, behind = counts
+ next if behind == 0
+
+ execute_with_fetched_source(cross_repo_source_sha, ahead)
+ end
+ rescue Gitlab::Git::CommandError => e
+ details.update!({ sha: head_sha, source_sha: source_sha, counts: counts, has_conflicts: true })
+
+ raise MergeError, e.message
+ end
+
+ def execute_with_fetched_source(cross_repo_source_sha, ahead)
+ with_linked_lfs_pointers(cross_repo_source_sha) do
+ merge_commit_id = perform_merge(cross_repo_source_sha, ahead)
+ raise MergeError, ONGOING_MERGE_ERROR unless merge_commit_id
+ end
+ end
+
+ # This method merges the upstream default branch to the fork specified branch.
+ # Depending on whether the fork branch is ahead of upstream or not, a different type of
+ # merge is performed.
+ #
+ # If the fork's branch is not ahead of the upstream (only behind), fast-forward merge is performed.
+ # However, if the fork's branch contains commits that don't exist upstream, a merge commit is created.
+ # In this case, a conflict may happen, which interrupts the merge and returns a message to the user.
+ def perform_merge(cross_repo_source_sha, ahead)
+ if ahead > 0
+ message = "Merge branch #{source_project.path}:#{source_project.default_branch} into #{target_branch}"
+
+ repository.merge_to_branch(current_user,
+ source_sha: cross_repo_source_sha,
+ target_branch: target_branch,
+ target_sha: head_sha,
+ message: message)
+ else
+ repository.ff_merge(current_user, cross_repo_source_sha, target_branch, target_sha: head_sha)
+ end
+ end
+
+ # This method links the newly merged lfs objects (if any) with the existing ones upstream.
+ # The LfsLinkService service has a limit and may raise an error if there are too many lfs objects to link.
+ # This is the reason why the block is passed:
+ #
+ # 1. Verify that there are not too many lfs objects to link
+ # 2. Execute the block (which basically performs the merge)
+ # 3. Link lfs objects
+ def with_linked_lfs_pointers(newrev, &block)
+ return yield unless project.lfs_enabled?
+
+ oldrev = head_sha
+ new_lfs_oids =
+ Gitlab::Git::LfsChanges
+ .new(repository, newrev)
+ .new_pointers(not_in: [oldrev])
+ .map(&:lfs_oid)
+
+ Projects::LfsPointers::LfsLinkService.new(project).execute(new_lfs_oids, &block)
+ rescue Projects::LfsPointers::LfsLinkService::TooManyOidsError => e
+ raise MergeError, e.message
+ end
+ end
+ end
+end
diff --git a/app/services/projects/import_export/relation_export_service.rb b/app/services/projects/import_export/relation_export_service.rb
index dce40cf18ba..33da5b39c20 100644
--- a/app/services/projects/import_export/relation_export_service.rb
+++ b/app/services/projects/import_export/relation_export_service.rb
@@ -85,6 +85,7 @@ module Projects
logger.error(
message: 'Project relation export failed',
export_error: error_message,
+ relation: relation_export.relation,
project_export_job_id: project_export_job.id,
project_name: project.name,
project_id: project.id
diff --git a/app/services/projects/lfs_pointers/lfs_link_service.rb b/app/services/projects/lfs_pointers/lfs_link_service.rb
index cf3cc5cd8e0..f8f03d481af 100644
--- a/app/services/projects/lfs_pointers/lfs_link_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_link_service.rb
@@ -15,9 +15,9 @@ module Projects
def execute(oids)
return [] unless project&.lfs_enabled?
- if oids.size > MAX_OIDS
- raise TooManyOidsError, 'Too many LFS object ids to link, please push them manually'
- end
+ validate!(oids)
+
+ yield if block_given?
# Search and link existing LFS Object
link_existing_lfs_objects(oids)
@@ -25,6 +25,12 @@ module Projects
private
+ def validate!(oids)
+ return if oids.size <= MAX_OIDS
+
+ raise TooManyOidsError, 'Too many LFS object ids to link, please push them manually'
+ end
+
def link_existing_lfs_objects(oids)
linked_existing_objects = []
iterations = 0
diff --git a/app/services/projects/open_merge_requests_count_service.rb b/app/services/projects/open_merge_requests_count_service.rb
index 76ec13952ab..c67ebf2f26a 100644
--- a/app/services/projects/open_merge_requests_count_service.rb
+++ b/app/services/projects/open_merge_requests_count_service.rb
@@ -4,12 +4,12 @@ module Projects
# Service class for counting and caching the number of open merge requests of
# a project.
class OpenMergeRequestsCountService < Projects::CountService
- def relation_for_count
- @project.merge_requests.opened
- end
-
def cache_key_name
'open_merge_requests_count'
end
+
+ def self.query(project_ids)
+ MergeRequest.opened.of_projects(project_ids)
+ end
end
end
diff --git a/app/services/projects/protect_default_branch_service.rb b/app/services/projects/protect_default_branch_service.rb
index 5360902038b..0aca525921c 100644
--- a/app/services/projects/protect_default_branch_service.rb
+++ b/app/services/projects/protect_default_branch_service.rb
@@ -45,11 +45,7 @@ module Projects
end
def protected_branch_exists?
- if Feature.enabled?(:group_protected_branches)
- project.all_protected_branches.find_by_name(default_branch).present?
- else
- project.protected_branches.find_by_name(default_branch).present?
- end
+ project.all_protected_branches.find_by_name(default_branch).present?
end
def default_branch
diff --git a/app/services/projects/update_repository_storage_service.rb b/app/services/projects/update_repository_storage_service.rb
index 7c63216af5e..cadf3012131 100644
--- a/app/services/projects/update_repository_storage_service.rb
+++ b/app/services/projects/update_repository_storage_service.rb
@@ -25,19 +25,6 @@ module Projects
end
end
- # The underlying FetchInternalRemote call uses a `git fetch` to move data
- # to the new repository, which leaves it in a less-well-packed state,
- # lacking bitmaps and commit graphs. Housekeeping will boost performance
- # significantly.
- def enqueue_housekeeping
- return unless Gitlab::CurrentSettings.housekeeping_enabled?
- return unless Feature.enabled?(:repack_after_shard_migration, project)
-
- Repositories::HousekeepingService.new(project, :gc).execute
- rescue Repositories::HousekeepingService::LeaseTaken
- # No action required
- end
-
def remove_old_paths
super
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 301d11d841c..bea994e8bb2 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -10,6 +10,8 @@ module Projects
def execute
build_topics
remove_unallowed_params
+ add_pages_unique_domain
+
validate!
ensure_wiki_exists if enabling_wiki?
@@ -48,6 +50,24 @@ module Projects
private
+ def add_pages_unique_domain
+ if Feature.disabled?(:pages_unique_domain)
+ params[:project_setting_attributes]&.delete(:pages_unique_domain_enabled)
+
+ return
+ end
+
+ 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
+ )
+ end
+
def validate!
unless valid_visibility_level_change?(project, project.visibility_attribute_value(params))
raise ValidationError, s_('UpdateProject|New visibility level not allowed!')
diff --git a/app/services/protected_branches/base_service.rb b/app/services/protected_branches/base_service.rb
index 951017b2d01..6906ab2b642 100644
--- a/app/services/protected_branches/base_service.rb
+++ b/app/services/protected_branches/base_service.rb
@@ -21,3 +21,5 @@ module ProtectedBranches
end
end
end
+
+ProtectedBranches::BaseService.prepend_mod
diff --git a/app/services/protected_branches/cache_service.rb b/app/services/protected_branches/cache_service.rb
index 4a9fc335421..ac02bf25617 100644
--- a/app/services/protected_branches/cache_service.rb
+++ b/app/services/protected_branches/cache_service.rb
@@ -73,7 +73,8 @@ module ProtectedBranches
end
def redis_key
- @redis_key ||= if Feature.enabled?(:group_protected_branches)
+ group = project_or_group.is_a?(Group) ? project_or_group : project_or_group.group
+ @redis_key ||= if Feature.enabled?(:group_protected_branches, group)
[CACHE_ROOT_KEY, project_or_group.class.name, project_or_group.id].join(':')
else
[CACHE_ROOT_KEY, project_or_group.id].join(':')
diff --git a/app/services/releases/links/base_service.rb b/app/services/releases/links/base_service.rb
new file mode 100644
index 00000000000..8bab258f80a
--- /dev/null
+++ b/app/services/releases/links/base_service.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Releases
+ module Links
+ REASON_BAD_REQUEST = :bad_request
+ REASON_NOT_FOUND = :not_found
+ REASON_FORBIDDEN = :forbidden
+
+ class BaseService
+ attr_accessor :release, :current_user, :params
+
+ def initialize(release, current_user = nil, params = {})
+ @release = release
+ @current_user = current_user
+ @params = params.dup
+ end
+
+ private
+
+ def allowed_params
+ @allowed_params ||= params.slice(:name, :url, :link_type).tap do |hash|
+ hash[:filepath] = filepath if provided_filepath?
+ end
+ end
+
+ def provided_filepath?
+ params.key?(:direct_asset_path) || params.key?(:filepath)
+ end
+
+ def filepath
+ params[:direct_asset_path] || params[:filepath]
+ end
+ end
+ end
+end
diff --git a/app/services/releases/links/create_service.rb b/app/services/releases/links/create_service.rb
new file mode 100644
index 00000000000..94823c54596
--- /dev/null
+++ b/app/services/releases/links/create_service.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Releases
+ module Links
+ class CreateService < BaseService
+ def execute
+ return ServiceResponse.error(reason: REASON_FORBIDDEN, message: _('Access Denied')) unless allowed?
+
+ link = release.links.create(allowed_params)
+
+ if link.persisted?
+ ServiceResponse.success(payload: { link: link })
+ else
+ ServiceResponse.error(reason: REASON_BAD_REQUEST, message: link.errors.full_messages)
+ end
+ end
+
+ private
+
+ def allowed?
+ Ability.allowed?(current_user, :create_release, release)
+ end
+ end
+ end
+end
diff --git a/app/services/releases/links/destroy_service.rb b/app/services/releases/links/destroy_service.rb
new file mode 100644
index 00000000000..1c1158017bb
--- /dev/null
+++ b/app/services/releases/links/destroy_service.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Releases
+ module Links
+ class DestroyService < BaseService
+ def execute(link)
+ return ServiceResponse.error(reason: REASON_FORBIDDEN, message: _('Access Denied')) unless allowed?
+ return ServiceResponse.error(reason: REASON_NOT_FOUND, message: _('Link does not exist')) unless link
+
+ if link.destroy
+ ServiceResponse.success(payload: { link: link })
+ else
+ ServiceResponse.error(reason: REASON_BAD_REQUEST, message: link.errors.full_messages)
+ end
+ end
+
+ private
+
+ def allowed?
+ Ability.allowed?(current_user, :destroy_release, release)
+ end
+ end
+ end
+end
diff --git a/app/services/releases/links/update_service.rb b/app/services/releases/links/update_service.rb
new file mode 100644
index 00000000000..c29de86f31b
--- /dev/null
+++ b/app/services/releases/links/update_service.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Releases
+ module Links
+ class UpdateService < BaseService
+ def execute(link)
+ return ServiceResponse.error(reason: REASON_FORBIDDEN, message: _('Access Denied')) unless allowed?
+ return ServiceResponse.error(reason: REASON_NOT_FOUND, message: _('Link does not exist')) unless link
+
+ if link.update(allowed_params)
+ ServiceResponse.success(payload: { link: link })
+ else
+ ServiceResponse.error(reason: REASON_BAD_REQUEST, message: link.errors.full_messages)
+ end
+ end
+
+ private
+
+ def allowed?
+ Ability.allowed?(current_user, :update_release, release)
+ end
+ end
+ end
+end
diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb
index f6fe23b4555..cfa43f5d9c8 100644
--- a/app/services/resource_access_tokens/create_service.rb
+++ b/app/services/resource_access_tokens/create_service.rb
@@ -2,6 +2,8 @@
module ResourceAccessTokens
class CreateService < BaseService
+ include Gitlab::Utils::StrongMemoize
+
def initialize(current_user, resource, params = {})
@resource_type = resource.class.name.downcase
@resource = resource
@@ -25,7 +27,7 @@ module ResourceAccessTokens
unless member.persisted?
delete_failed_user(user)
- return error("Could not provision #{Gitlab::Access.human_access(access_level).downcase} access to project access token")
+ return error("Could not provision #{Gitlab::Access.human_access(access_level.to_i).downcase} access to the access token. ERROR: #{member.errors.full_messages.to_sentence}")
end
token_response = create_personal_access_token(user)
@@ -43,6 +45,14 @@ module ResourceAccessTokens
attr_reader :resource_type, :resource
+ def username_and_email_generator
+ Gitlab::Utils::UsernameAndEmailGenerator.new(
+ username_prefix: "#{resource_type}_#{resource.id}_bot",
+ email_domain: "noreply.#{Gitlab.config.gitlab.host}"
+ )
+ end
+ 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)
end
@@ -63,31 +73,13 @@ module ResourceAccessTokens
def default_user_params
{
name: params[:name] || "#{resource.name.to_s.humanize} bot",
- email: generate_email,
- username: generate_username,
+ email: username_and_email_generator.email,
+ username: username_and_email_generator.username,
user_type: :project_bot,
skip_confirmation: true # Bot users should always have their emails confirmed.
}
end
- def generate_username
- base_username = "#{resource_type}_#{resource.id}_bot"
-
- uniquify.string(base_username) { |s| User.find_by_username(s) }
- end
-
- def generate_email
- email_pattern = "#{resource_type}#{resource.id}_bot%s@noreply.#{Gitlab.config.gitlab.host}"
-
- uniquify.string(-> (n) { Kernel.sprintf(email_pattern, n) }) do |s|
- User.find_by_email(s)
- end
- end
-
- def uniquify
- Uniquify.new
- end
-
def create_personal_access_token(user)
PersonalAccessTokens::CreateService.new(
current_user: user, target_user: user, params: personal_access_token_params
diff --git a/app/services/security/ci_configuration/base_create_service.rb b/app/services/security/ci_configuration/base_create_service.rb
index 3e8865d3dff..0534925aaec 100644
--- a/app/services/security/ci_configuration/base_create_service.rb
+++ b/app/services/security/ci_configuration/base_create_service.rb
@@ -19,7 +19,8 @@ module Security
target: '_blank',
rel: 'noopener noreferrer'
raise Gitlab::Graphql::Errors::MutationError,
- _(format('You must %s before using Security features.', docs_link.html_safe)).html_safe
+ Gitlab::Utils::ErrorMessage.to_user_facing(
+ _(format('You must %s before using Security features.', docs_link.html_safe)).html_safe)
end
project.repository.add_branch(current_user, branch_name, project.default_branch)
@@ -51,7 +52,7 @@ module Security
end
def existing_gitlab_ci_content
- root_ref = root_ref_sha(project)
+ root_ref = root_ref_sha(project.repository)
return if root_ref.nil?
@gitlab_ci_yml ||= project.ci_config_for(root_ref)
@@ -82,13 +83,10 @@ module Security
)
end
- def root_ref_sha(project)
- project.repository.root_ref_sha
- rescue StandardError => e
- # this might fail on the very first commit,
- # and unfortunately it raises a StandardError
- Gitlab::ErrorTracking.track_exception(e, project_id: project.id)
- nil
+ def root_ref_sha(repository)
+ commit = repository.commit(repository.root_ref)
+
+ commit&.sha
end
end
end
diff --git a/app/services/serverless/associate_domain_service.rb b/app/services/serverless/associate_domain_service.rb
deleted file mode 100644
index 0c6ee58924c..00000000000
--- a/app/services/serverless/associate_domain_service.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-module Serverless
- class AssociateDomainService
- PLACEHOLDER_HOSTNAME = 'example.com'
-
- def initialize(knative, pages_domain_id:, creator:)
- @knative = knative
- @pages_domain_id = pages_domain_id
- @creator = creator
- end
-
- def execute
- return if unchanged?
-
- knative.hostname ||= PLACEHOLDER_HOSTNAME
-
- knative.pages_domain = knative.find_available_domain(pages_domain_id)
- knative.serverless_domain_cluster.update(creator: creator) if knative.pages_domain
- end
-
- private
-
- attr_reader :knative, :pages_domain_id, :creator
-
- def unchanged?
- knative.pages_domain&.id == pages_domain_id
- end
- end
-end
diff --git a/app/services/system_notes/commit_service.rb b/app/services/system_notes/commit_service.rb
index 592351079aa..e4d89ecb930 100644
--- a/app/services/system_notes/commit_service.rb
+++ b/app/services/system_notes/commit_service.rb
@@ -2,6 +2,8 @@
module SystemNotes
class CommitService < ::SystemNotes::BaseService
+ NEW_COMMIT_DISPLAY_LIMIT = 10
+
# Called when commits are added to a merge request
#
# new_commits - Array of Commits added since last push
@@ -36,25 +38,73 @@ module SystemNotes
create_note(NoteSummary.new(noteable, project, author, body, action: 'tag'))
end
+ private
+
# Build an Array of lines detailing each commit added in a merge request
#
# new_commits - Array of new Commit objects
#
# Returns an Array of Strings
- def new_commit_summary(new_commits)
+ def new_commits_list(new_commits)
new_commits.collect do |commit|
content_tag('li', "#{commit.short_id} - #{commit.title}")
end
end
- private
+ # Builds an Array of lines describing each commit and truncate them based on the limit
+ # to avoid creating a note with a large number of commits.
+ #
+ # commits - Array of Commit objects
+ #
+ # Returns an Array of Strings
+ #
+ # rubocop: disable CodeReuse/ActiveRecord
+ def new_commit_summary(commits, start_rev)
+ if commits.size > NEW_COMMIT_DISPLAY_LIMIT
+ no_of_commits_to_truncate = commits.size - NEW_COMMIT_DISPLAY_LIMIT
+ commits_to_truncate = commits.take(no_of_commits_to_truncate)
+ remaining_commits = commits.drop(no_of_commits_to_truncate)
+
+ [truncated_new_commits(commits_to_truncate, start_rev)] + new_commits_list(remaining_commits)
+ else
+ new_commits_list(commits)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # Builds a summary line that describes given truncated commits.
+ #
+ # commits - Array of Commit objects
+ # start_rev - String SHA of a Commit that will be used as the starting SHA of the range
+ #
+ # Returns a String wrapped in 'li' tag.
+ def truncated_new_commits(commits, start_rev)
+ count = commits.size
+
+ commit_ids = if count == 1
+ commits.first.short_id
+ elsif start_rev && !Gitlab::Git.blank_ref?(start_rev)
+ "#{Commit.truncate_sha(start_rev)}...#{commits.last.short_id}"
+ else
+ # This two-dots notation seems to be not functioning as expected, but we should
+ # fallback to it as start_rev can be empty.
+ #
+ # For more information, please see https://gitlab.com/gitlab-org/gitlab/-/issues/391809
+ "#{commits.first.short_id}..#{commits.last.short_id}"
+ end
+
+ commits_text = "#{count} earlier commit".pluralize(count)
+
+ content_tag('li', "#{commit_ids} - #{commits_text}")
+ end
# Builds a list of existing and new commits according to existing_commits and
# new_commits methods.
# Returns a String wrapped in `ul` and `li` tags.
def commits_list(noteable, new_commits, existing_commits, oldrev)
existing_commit_summary = existing_commit_summary(noteable, existing_commits, oldrev)
- new_commit_summary = new_commit_summary(new_commits).join
+ start_rev = existing_commits.empty? ? oldrev : existing_commits.last.id
+ new_commit_summary = new_commit_summary(new_commits, start_rev).join
content_tag('ul', "#{existing_commit_summary}#{new_commit_summary}".html_safe)
end
diff --git a/app/services/tasks_to_be_done/base_service.rb b/app/services/tasks_to_be_done/base_service.rb
index 5851a2cb9e5..ba52e9abeb2 100644
--- a/app/services/tasks_to_be_done/base_service.rb
+++ b/app/services/tasks_to_be_done/base_service.rb
@@ -11,7 +11,7 @@ module TasksToBeDone
description: description,
add_labels: label_name
}
- super(project: container, current_user: current_user, params: params)
+ super(container: container, current_user: current_user, params: params)
end
def execute
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index 42a8aca17d3..2025d438ae7 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -428,8 +428,6 @@ class TodoService
event = "incident_management_incident_todo"
track_usage_event(event, user.id)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, namespace)
-
Gitlab::Tracking.event(
self.class.to_s,
event,
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index 934dccf2f76..9d221119985 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -70,7 +70,7 @@ module Users
@user_params[:created_by_id] = current_user&.id
@user_params[:external] = user_external? if set_external_param?
- @user_params.delete(:user_type) unless project_bot?
+ @user_params.delete(:user_type) unless allowed_user_type?
end
def set_external_param?
@@ -81,7 +81,7 @@ module Users
user_default_internal_regex_instance.match(params[:email]).nil?
end
- def project_bot?
+ def allowed_user_type?
user_params[:user_type]&.to_sym == :project_bot
end
diff --git a/app/services/users/refresh_authorized_projects_service.rb b/app/services/users/refresh_authorized_projects_service.rb
index b1ffd006795..d01fa29d8d4 100644
--- a/app/services/users/refresh_authorized_projects_service.rb
+++ b/app/services/users/refresh_authorized_projects_service.rb
@@ -92,3 +92,5 @@ module Users
end
end
end
+
+Users::RefreshAuthorizedProjectsService.prepend_mod
diff --git a/app/services/users/validate_manual_otp_service.rb b/app/services/users/validate_manual_otp_service.rb
index 96a827db13c..8ba76f5f593 100644
--- a/app/services/users/validate_manual_otp_service.rb
+++ b/app/services/users/validate_manual_otp_service.rb
@@ -3,6 +3,7 @@
module Users
class ValidateManualOtpService < BaseService
include ::Gitlab::Auth::Otp::Fortinet
+ include ::Gitlab::Auth::Otp::DuoAuth
def initialize(current_user)
@current_user = current_user
@@ -10,6 +11,8 @@ module Users
::Gitlab::Auth::Otp::Strategies::FortiAuthenticator::ManualOtp.new(current_user)
elsif forti_token_cloud_enabled?(current_user)
::Gitlab::Auth::Otp::Strategies::FortiTokenCloud.new(current_user)
+ elsif duo_auth_enabled?(current_user)
+ ::Gitlab::Auth::Otp::Strategies::DuoAuth::ManualOtp.new(current_user)
else
::Gitlab::Auth::Otp::Strategies::Devise.new(current_user)
end
diff --git a/app/services/work_items/export_csv_service.rb b/app/services/work_items/export_csv_service.rb
index 9bef75e2c40..a715aab1b30 100644
--- a/app/services/work_items/export_csv_service.rb
+++ b/app/services/work_items/export_csv_service.rb
@@ -11,7 +11,7 @@ module WorkItems
end
def email(mail_to_user)
- # TODO - will be implemented as part of https://gitlab.com/gitlab-org/gitlab/-/issues/379082
+ Notify.export_work_items_csv_email(mail_to_user, resource_parent, csv_data, csv_builder.status).deliver_now
end
private
diff --git a/app/services/work_items/import_csv_service.rb b/app/services/work_items/import_csv_service.rb
new file mode 100644
index 00000000000..e7043cc882a
--- /dev/null
+++ b/app/services/work_items/import_csv_service.rb
@@ -0,0 +1,116 @@
+# frozen_string_literal: true
+
+module WorkItems
+ class ImportCsvService < ImportCsv::BaseService
+ extend ::Gitlab::Utils::Override
+
+ FeatureNotAvailableError = StandardError.new(
+ 'This feature is currently behind a feature flag and it is not available.'
+ )
+ NotAuthorizedError = StandardError.new('You do not have permission to import work items in this project.')
+
+ override :initialize
+ def initialize(*args)
+ super
+
+ @type_errors = {
+ blank: [],
+ missing: {},
+ disallowed: {}
+ }
+ end
+
+ def self.required_headers
+ %w[title type].freeze
+ end
+
+ def execute
+ raise FeatureNotAvailableError if ::Feature.disabled?(:import_export_work_items_csv, project)
+ raise NotAuthorizedError unless Ability.allowed?(user, :import_work_items, project)
+
+ super
+ end
+
+ def email_results_to_user
+ Notify.import_work_items_csv_email(user.id, project.id, results).deliver_later
+ end
+
+ private
+
+ attr_accessor :type_errors
+
+ def create_object(attributes)
+ super[:work_item]
+ end
+
+ def create_object_class
+ ::WorkItems::CreateService
+ end
+
+ override :attributes_for
+ def attributes_for(row)
+ {
+ title: row[:title],
+ work_item_type: match_work_item_type(row[:type])
+ }
+ end
+
+ override :validate_headers_presence!
+ def validate_headers_presence!(headers)
+ required_headers = self.class.required_headers
+
+ headers.downcase!
+ return if headers && required_headers.all? { |rh| headers.include?(rh) }
+
+ required_headers_message = "Required headers are missing. Required headers are #{required_headers.join(', ')}"
+ raise CSV::MalformedCSVError.new(required_headers_message, 1)
+ end
+
+ def match_work_item_type(work_item_type)
+ match = available_work_item_types[work_item_type&.downcase]
+ match[:type] if match
+ end
+
+ def available_work_item_types
+ {
+ issue: {
+ allowed: Ability.allowed?(user, :create_issue, project),
+ type: WorkItems::Type.default_by_type(:issue)
+ }
+ }.with_indifferent_access
+ end
+ strong_memoize_attr :available_work_item_types
+
+ def preprocess!
+ with_csv_lines.each do |row, line_no|
+ work_item_type = row[:type]&.strip&.downcase
+
+ if work_item_type.blank?
+ type_errors[:blank] << line_no
+ elsif missing?(work_item_type)
+ # does this work item exist in the range of work items we support?
+ (type_errors[:missing][work_item_type] ||= []) << line_no
+ elsif !allowed?(work_item_type)
+ (type_errors[:disallowed][work_item_type] ||= []) << line_no
+ end
+ end
+
+ return if type_errors[:blank].empty? &&
+ type_errors[:missing].blank? &&
+ type_errors[:disallowed].blank?
+
+ results[:type_errors] = type_errors
+ raise PreprocessError
+ end
+
+ def missing?(work_item_type_name)
+ !available_work_item_types.key?(work_item_type_name)
+ end
+
+ def allowed?(work_item_type_name)
+ !!available_work_item_types[work_item_type_name][:allowed]
+ end
+ end
+end
+
+WorkItems::ImportCsvService.prepend_mod
diff --git a/app/services/work_items/parent_links/create_service.rb b/app/services/work_items/parent_links/create_service.rb
index 288ca152f93..85b470c47ca 100644
--- a/app/services/work_items/parent_links/create_service.rb
+++ b/app/services/work_items/parent_links/create_service.rb
@@ -10,6 +10,8 @@ module WorkItems
link = WorkItems::ParentLink.find_or_initialize_by(work_item: work_item)
link.work_item_parent = issuable
+ link.move_to_end
+
if link.changed? && link.save
create_notes(work_item)
end
diff --git a/app/services/work_items/widgets/notifications_service/update_service.rb b/app/services/work_items/widgets/notifications_service/update_service.rb
new file mode 100644
index 00000000000..b301e2ca7db
--- /dev/null
+++ b/app/services/work_items/widgets/notifications_service/update_service.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ module NotificationsService
+ class UpdateService < WorkItems::Widgets::BaseService
+ def before_update_in_transaction(params:)
+ return unless params.present? && params.key?(:subscribed)
+ return unless has_permission?(:update_subscription)
+
+ update_subscription(work_item, params)
+ end
+
+ private
+
+ def update_subscription(work_item, subscription_params)
+ work_item.set_subscription(
+ current_user,
+ subscription_params[:subscribed],
+ work_item.project
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/app/uploaders/ci/pipeline_artifact_uploader.rb b/app/uploaders/ci/pipeline_artifact_uploader.rb
index d3a83c5d633..62e00fe1a66 100644
--- a/app/uploaders/ci/pipeline_artifact_uploader.rb
+++ b/app/uploaders/ci/pipeline_artifact_uploader.rb
@@ -4,7 +4,7 @@ module Ci
class PipelineArtifactUploader < GitlabUploader
include ObjectStorage::Concern
- storage_options Gitlab.config.artifacts
+ storage_location :artifacts
alias_method :upload, :model
diff --git a/app/uploaders/ci/secure_file_uploader.rb b/app/uploaders/ci/secure_file_uploader.rb
index 11cbfc6c1f2..09d9b3abafb 100644
--- a/app/uploaders/ci/secure_file_uploader.rb
+++ b/app/uploaders/ci/secure_file_uploader.rb
@@ -4,7 +4,7 @@ module Ci
class SecureFileUploader < GitlabUploader
include ObjectStorage::Concern
- storage_options Gitlab.config.ci_secure_files
+ storage_location :ci_secure_files
# Use Lockbox to encrypt/decrypt the stored file (registers CarrierWave callbacks)
encrypt(key: :key)
diff --git a/app/uploaders/deleted_object_uploader.rb b/app/uploaders/deleted_object_uploader.rb
index fc0f62b920c..eaf584c5dfa 100644
--- a/app/uploaders/deleted_object_uploader.rb
+++ b/app/uploaders/deleted_object_uploader.rb
@@ -3,7 +3,7 @@
class DeletedObjectUploader < GitlabUploader
include ObjectStorage::Concern
- storage_options Gitlab.config.artifacts
+ storage_location :artifacts
def store_dir
model.store_dir
diff --git a/app/uploaders/dependency_proxy/file_uploader.rb b/app/uploaders/dependency_proxy/file_uploader.rb
index f0222d4cf06..d4e486bfe84 100644
--- a/app/uploaders/dependency_proxy/file_uploader.rb
+++ b/app/uploaders/dependency_proxy/file_uploader.rb
@@ -5,7 +5,7 @@ class DependencyProxy::FileUploader < GitlabUploader
include ObjectStorage::Concern
before :cache, :set_content_type
- storage_options Gitlab.config.dependency_proxy
+ storage_location :dependency_proxy
alias_method :upload, :model
diff --git a/app/uploaders/external_diff_uploader.rb b/app/uploaders/external_diff_uploader.rb
index d2707cd0777..86c3d734174 100644
--- a/app/uploaders/external_diff_uploader.rb
+++ b/app/uploaders/external_diff_uploader.rb
@@ -3,7 +3,7 @@
class ExternalDiffUploader < GitlabUploader
include ObjectStorage::Concern
- storage_options Gitlab.config.external_diffs
+ storage_location :external_diffs
alias_method :upload, :model
diff --git a/app/uploaders/gitlab_uploader.rb b/app/uploaders/gitlab_uploader.rb
index 62024bff4c0..2eb34288bd7 100644
--- a/app/uploaders/gitlab_uploader.rb
+++ b/app/uploaders/gitlab_uploader.rb
@@ -3,7 +3,7 @@
class GitlabUploader < CarrierWave::Uploader::Base
include ContentTypeWhitelist::Concern
- class_attribute :options
+ class_attribute :storage_location_identifier
PROTECTED_METHODS = %i(filename cache_dir work_dir store_dir).freeze
@@ -11,8 +11,13 @@ class GitlabUploader < CarrierWave::Uploader::Base
class << self
# DSL setter
- def storage_options(options)
- self.options = options
+ def storage_location(location)
+ self.storage_location_identifier = location
+ _ = options # Ensures that we have a valid storage_location_identifier
+ end
+
+ def options
+ ObjectStorage::Config::LOCATIONS.fetch(storage_location_identifier)
end
def root
@@ -41,7 +46,7 @@ class GitlabUploader < CarrierWave::Uploader::Base
end
end
- storage_options Gitlab.config.uploads
+ storage_location :uploads
delegate :base_dir, :file_storage?, to: :class
@@ -51,6 +56,10 @@ class GitlabUploader < CarrierWave::Uploader::Base
super(model, mounted_as)
end
+ def options
+ self.class.options
+ end
+
def file_cache_storage?
cache_storage.is_a?(CarrierWave::Storage::File)
end
diff --git a/app/uploaders/job_artifact_uploader.rb b/app/uploaders/job_artifact_uploader.rb
index b38e7d93eac..5ee8c42f510 100644
--- a/app/uploaders/job_artifact_uploader.rb
+++ b/app/uploaders/job_artifact_uploader.rb
@@ -7,7 +7,7 @@ class JobArtifactUploader < GitlabUploader
UnknownFileLocationError = Class.new(StandardError)
- storage_options Gitlab.config.artifacts
+ storage_location :artifacts
alias_method :upload, :model
diff --git a/app/uploaders/lfs_object_uploader.rb b/app/uploaders/lfs_object_uploader.rb
index 027857500f4..4111bb92322 100644
--- a/app/uploaders/lfs_object_uploader.rb
+++ b/app/uploaders/lfs_object_uploader.rb
@@ -4,7 +4,7 @@ class LfsObjectUploader < GitlabUploader
extend Workhorse::UploadPath
include ObjectStorage::Concern
- storage_options Gitlab.config.lfs
+ storage_location :lfs
alias_method :upload, :model
diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb
index 1b47400d5e8..ab5c46d14f9 100644
--- a/app/uploaders/object_storage.rb
+++ b/app/uploaders/object_storage.rb
@@ -277,8 +277,7 @@ module ObjectStorage
end
# Set ACL of uploaded objects to not-public (fog-aws)[1] or no ACL at all
- # (fog-google). Value is ignored by other supported backends (fog-aliyun,
- # fog-openstack, fog-rackspace)
+ # (fog-google). Value is ignored by fog-aliyun
# [1]: https://github.com/fog/fog-aws/blob/daa50bb3717a462baf4d04d0e0cbfc18baacb541/lib/fog/aws/models/storage/file.rb#L152-L159
def fog_public
nil
diff --git a/app/uploaders/packages/composer/cache_uploader.rb b/app/uploaders/packages/composer/cache_uploader.rb
index ad7c017c4ba..ef581b5d6a1 100644
--- a/app/uploaders/packages/composer/cache_uploader.rb
+++ b/app/uploaders/packages/composer/cache_uploader.rb
@@ -2,7 +2,7 @@
class Packages::Composer::CacheUploader < GitlabUploader
include ObjectStorage::Concern
- storage_options Gitlab.config.packages
+ storage_location :packages
alias_method :upload, :model
diff --git a/app/uploaders/packages/debian/component_file_uploader.rb b/app/uploaders/packages/debian/component_file_uploader.rb
index 2de4743d7f7..b1ed8d853f1 100644
--- a/app/uploaders/packages/debian/component_file_uploader.rb
+++ b/app/uploaders/packages/debian/component_file_uploader.rb
@@ -3,7 +3,7 @@ class Packages::Debian::ComponentFileUploader < GitlabUploader
extend Workhorse::UploadPath
include ObjectStorage::Concern
- storage_options Gitlab.config.packages
+ storage_location :packages
alias_method :upload, :model
diff --git a/app/uploaders/packages/debian/distribution_release_file_uploader.rb b/app/uploaders/packages/debian/distribution_release_file_uploader.rb
index 268d42796e9..fe10861b77f 100644
--- a/app/uploaders/packages/debian/distribution_release_file_uploader.rb
+++ b/app/uploaders/packages/debian/distribution_release_file_uploader.rb
@@ -3,7 +3,7 @@ class Packages::Debian::DistributionReleaseFileUploader < GitlabUploader
extend Workhorse::UploadPath
include ObjectStorage::Concern
- storage_options Gitlab.config.packages
+ storage_location :packages
alias_method :upload, :model
diff --git a/app/uploaders/packages/package_file_uploader.rb b/app/uploaders/packages/package_file_uploader.rb
index c8a09c50dc6..57feee9f19d 100644
--- a/app/uploaders/packages/package_file_uploader.rb
+++ b/app/uploaders/packages/package_file_uploader.rb
@@ -3,7 +3,7 @@ class Packages::PackageFileUploader < GitlabUploader
extend Workhorse::UploadPath
include ObjectStorage::Concern
- storage_options Gitlab.config.packages
+ storage_location :packages
alias_method :upload, :model
diff --git a/app/uploaders/packages/rpm/repository_file_uploader.rb b/app/uploaders/packages/rpm/repository_file_uploader.rb
index f95f861585c..399e9fa07d5 100644
--- a/app/uploaders/packages/rpm/repository_file_uploader.rb
+++ b/app/uploaders/packages/rpm/repository_file_uploader.rb
@@ -4,7 +4,7 @@ module Packages
class RepositoryFileUploader < GitlabUploader
include ObjectStorage::Concern
- storage_options Gitlab.config.packages
+ storage_location :packages
alias_method :upload, :model
diff --git a/app/uploaders/pages/deployment_uploader.rb b/app/uploaders/pages/deployment_uploader.rb
index c5ba65673ab..bb4f1a2235d 100644
--- a/app/uploaders/pages/deployment_uploader.rb
+++ b/app/uploaders/pages/deployment_uploader.rb
@@ -4,7 +4,7 @@ module Pages
class DeploymentUploader < GitlabUploader
include ObjectStorage::Concern
- storage_options Gitlab.config.pages
+ storage_location :pages
alias_method :upload, :model
diff --git a/app/uploaders/terraform/state_uploader.rb b/app/uploaders/terraform/state_uploader.rb
index 61e7ed7b0e6..5fe3048f7b0 100644
--- a/app/uploaders/terraform/state_uploader.rb
+++ b/app/uploaders/terraform/state_uploader.rb
@@ -4,7 +4,7 @@ module Terraform
class StateUploader < GitlabUploader
include ObjectStorage::Concern
- storage_options Gitlab.config.terraform_state
+ storage_location :terraform_state
# TODO: Remove this line
# See https://gitlab.com/gitlab-org/gitlab/-/issues/232917
diff --git a/app/validators/addressable_url_validator.rb b/app/validators/addressable_url_validator.rb
index c6d9bd73566..3e6ec0b6f29 100644
--- a/app/validators/addressable_url_validator.rb
+++ b/app/validators/addressable_url_validator.rb
@@ -31,6 +31,8 @@
# * <tt>allow_blank</tt> - Allow urls to be +blank+. Default: +false+
# * <tt>allow_nil</tt> - Allow urls to be +nil+. Default: +false+
# * <tt>ports</tt> - Allowed ports. Default: +all+.
+# * <tt>deny_all_requests_except_allowed</tt> - Deny all requests. Default: Respects the instance app setting.
+# Note: Regardless of whether enforced during validation, an HTTP request that uses the URI may still be blocked.
# * <tt>enforce_user</tt> - Validate user format. Default: +false+
# * <tt>enforce_sanitization</tt> - Validate that there are no html/css/js tags. Default: +false+
#
@@ -54,6 +56,7 @@ class AddressableUrlValidator < ActiveModel::EachValidator
allow_localhost: true,
allow_local_network: true,
ascii_only: false,
+ deny_all_requests_except_allowed: Gitlab::UrlBlocker::DENY_ALL_REQUESTS_EXCEPT_ALLOWED_DEFAULT,
enforce_user: false,
enforce_sanitization: false,
dns_rebind_protection: false
diff --git a/app/validators/json_schema_validator.rb b/app/validators/json_schema_validator.rb
index 4896c2ea2ef..9c246a114f6 100644
--- a/app/validators/json_schema_validator.rb
+++ b/app/validators/json_schema_validator.rb
@@ -25,6 +25,7 @@ class JsonSchemaValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
value = value.to_h.stringify_keys if options[:hash_conversion] == true
+ value = Gitlab::Json.parse(value.to_s) if options[:parse_json] == true && !value.nil?
unless valid_schema?(value)
record.errors.add(attribute, _("must be a valid json schema"))
diff --git a/app/validators/json_schemas/google_service_account_key.json b/app/validators/json_schemas/google_service_account_key.json
new file mode 100644
index 00000000000..d040ef19f66
--- /dev/null
+++ b/app/validators/json_schemas/google_service_account_key.json
@@ -0,0 +1,48 @@
+{
+ "description": "Google service account key",
+ "type": "object",
+ "required": [
+ "type",
+ "project_id",
+ "private_key_id",
+ "private_key",
+ "client_email",
+ "client_id",
+ "auth_uri",
+ "token_uri",
+ "auth_provider_x509_cert_url",
+ "client_x509_cert_url"
+ ],
+ "properties": {
+ "type": {
+ "const": "service_account"
+ },
+ "project_id": {
+ "type": "string"
+ },
+ "private_key_id": {
+ "type": "string"
+ },
+ "private_key": {
+ "type": "string"
+ },
+ "client_email": {
+ "type": "string"
+ },
+ "client_id": {
+ "type": "string"
+ },
+ "auth_uri": {
+ "type": "string"
+ },
+ "token_uri": {
+ "type": "string"
+ },
+ "auth_provider_x509_cert_url": {
+ "type": "string"
+ },
+ "client_x509_cert_url": {
+ "type": "string"
+ }
+ }
+}
diff --git a/app/validators/json_schemas/import_failure_external_identifiers.json b/app/validators/json_schemas/import_failure_external_identifiers.json
new file mode 100644
index 00000000000..3756e712de5
--- /dev/null
+++ b/app/validators/json_schemas/import_failure_external_identifiers.json
@@ -0,0 +1,18 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "description": "Import failure external identifiers",
+ "type": "object",
+ "maxProperties": 3,
+ "patternProperties": {
+ ".*": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "integer"
+ }
+ ]
+ }
+ }
+}
diff --git a/app/views/admin/abuse_reports/_abuse_report.html.haml b/app/views/admin/abuse_reports/_abuse_report.html.haml
index eeedd58ec15..1a0f4132d49 100644
--- a/app/views/admin/abuse_reports/_abuse_report.html.haml
+++ b/app/views/admin/abuse_reports/_abuse_report.html.haml
@@ -24,13 +24,13 @@
= markdown_field(abuse_report, :message)
%td
- if 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 gl-mb-5" }) do
+ = 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 && !user.blocked?
- = 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 }, class: "gl-mb-5" }) do
+ = 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')
- else
- = 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 }, class: "gl-mb-5" }) do
+ = 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')
= 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 20499a2e3bf..fee3a846849 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -2,31 +2,35 @@
%h1.page-title.gl-font-size-h-display= _('Abuse Reports')
-.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' }})
+- 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')
+ .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')
diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml
index 8fafa52cd4c..fd671f72238 100644
--- a/app/views/admin/application_settings/_ci_cd.html.haml
+++ b/app/views/admin/application_settings/_ci_cd.html.haml
@@ -77,31 +77,31 @@
%fieldset
= f.hidden_field(:plan_id, value: plan.id)
.form-group
- = f.label :ci_pipeline_size, s_('AdminSettings|Maximum number of jobs in a single pipeline')
+ = f.label :ci_pipeline_size, plan_limit_setting_description(:ci_pipeline_size)
= f.number_field :ci_pipeline_size, class: 'form-control gl-form-input'
.form-group
- = f.label :ci_active_jobs, s_('AdminSettings|Total number of jobs in currently active pipelines')
+ = f.label :ci_active_jobs, plan_limit_setting_description(:ci_active_jobs)
= f.number_field :ci_active_jobs, class: 'form-control gl-form-input'
.form-group
- = f.label :ci_active_pipelines, s_('AdminSettings|Maximum number of active pipelines per project')
+ = f.label :ci_active_pipelines, plan_limit_setting_description(:ci_active_pipelines)
= f.number_field :ci_active_pipelines, class: 'form-control gl-form-input'
.form-group
- = f.label :ci_project_subscriptions, s_('AdminSettings|Maximum number of pipeline subscriptions to and from a project')
+ = f.label :ci_project_subscriptions, plan_limit_setting_description(:ci_project_subscriptions)
= f.number_field :ci_project_subscriptions, class: 'form-control gl-form-input'
.form-group
- = f.label :ci_pipeline_schedules, s_('AdminSettings|Maximum number of pipeline schedules')
+ = f.label :ci_pipeline_schedules, plan_limit_setting_description(:ci_pipeline_schedules)
= f.number_field :ci_pipeline_schedules, class: 'form-control gl-form-input'
.form-group
- = f.label :ci_needs_size_limit, s_('AdminSettings|Maximum number of DAG dependencies that a job can have')
+ = f.label :ci_needs_size_limit, plan_limit_setting_description(:ci_needs_size_limit)
= f.number_field :ci_needs_size_limit, class: 'form-control gl-form-input'
.form-text.text-muted= s_('AdminSettings|This limit cannot be disabled. Set to 0 to block all DAG dependencies.')
.form-group
- = f.label :ci_registered_group_runners, s_('AdminSettings|Maximum number of runners registered per group')
+ = f.label :ci_registered_group_runners, plan_limit_setting_description(:ci_registered_group_runners)
= f.number_field :ci_registered_group_runners, class: 'form-control gl-form-input'
.form-group
- = f.label :ci_registered_project_runners, s_('AdminSettings|Maximum number of runners registered per project')
+ = f.label :ci_registered_project_runners, plan_limit_setting_description(:ci_registered_project_runners)
= f.number_field :ci_registered_project_runners, class: 'form-control gl-form-input'
.form-group
- = f.label :pipeline_hierarchy_size, s_("AdminSettings|Maximum number of downstream pipelines in a pipeline's hierarchy tree")
+ = f.label :pipeline_hierarchy_size, plan_limit_setting_description(:pipeline_hierarchy_size)
= f.number_field :pipeline_hierarchy_size, class: 'form-control gl-form-input'
= f.submit s_('AdminSettings|Save %{name} limits').html_safe % { name: plan.name.capitalize }, pajamas_button: true
diff --git a/app/views/admin/application_settings/_outbound.html.haml b/app/views/admin/application_settings/_outbound.html.haml
index 1821c8ef4bb..6efafa3c415 100644
--- a/app/views/admin/application_settings/_outbound.html.haml
+++ b/app/views/admin/application_settings/_outbound.html.haml
@@ -1,25 +1,36 @@
+- deny_all_requests = @application_setting.deny_all_requests_except_allowed
+
= gitlab_ui_form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-outbound-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
+ = f.gitlab_ui_checkbox_component :deny_all_requests_except_allowed,
+ s_('OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist'),
+ checkbox_options: { class: 'js-deny-all-requests' }
+ = render Pajamas::AlertComponent.new(variant: :warning,
+ dismissible: false,
+ alert_options: { class: "gl-mb-3 js-deny-all-requests-warning #{'gl-display-none' unless deny_all_requests}" }) do |c|
+ = c.body do
+ = s_('OutboundRequests|Webhooks and integrations might not work properly.')
= f.gitlab_ui_checkbox_component :allow_local_requests_from_web_hooks_and_services,
- s_('OutboundRequests|Allow requests to the local network from web hooks and services'),
- checkbox_options: { data: { qa_selector: 'allow_requests_from_services_checkbox' } }
+ s_('OutboundRequests|Allow requests to the local network from webhooks and integrations'),
+ checkbox_options: { disabled: deny_all_requests, class: 'js-allow-local-requests', data: { qa_selector: 'allow_requests_from_services_checkbox' } }
= f.gitlab_ui_checkbox_component :allow_local_requests_from_system_hooks,
- s_('OutboundRequests|Allow requests to the local network from system hooks')
+ s_('OutboundRequests|Allow requests to the local network from system hooks'),
+ checkbox_options: { disabled: deny_all_requests, class: 'js-allow-local-requests' }
.form-group
= f.label :outbound_local_requests_allowlist_raw, class: 'label-bold' do
- = s_('OutboundRequests|Local IP addresses and domain names that hooks and services may access')
+ = s_('OutboundRequests|Local IP addresses and domain names that hooks and integrations can access')
= f.text_area :outbound_local_requests_allowlist_raw, placeholder: "example.com, 192.168.1.1, xn--itlab-j1a.com", class: 'form-control gl-form-input', rows: 8
%span.form-text.text-muted
- = s_('OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded.')
- = link_to _('Learn more.'), help_page_path('security/webhooks.md', anchor: 'create-an-allowlist-for-local-requests'), target: '_blank', rel: 'noopener noreferrer'
+ = s_('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.').html_safe % { code_start: '<code>'.html_safe, code_end: '</code>'.html_safe }
+ = link_to _('Learn more.'), help_page_path('security/webhooks.md', anchor: 'allow-outbound-requests-to-certain-ip-addresses-and-domains'), target: '_blank', rel: 'noopener noreferrer'
.form-group
= f.gitlab_ui_checkbox_component :dns_rebinding_protection_enabled,
- s_('OutboundRequests|Enforce DNS rebinding attack protection'),
- help_text: s_('OutboundRequests|Resolve IP addresses once and uses them to submit requests.')
+ s_('OutboundRequests|Enforce DNS-rebinding attack protection'),
+ help_text: s_('OutboundRequests|Resolve IP addresses for outbound requests to prevent DNS-rebinding attacks.')
= f.submit _('Save changes'), pajamas_button: true, data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_projects_api_limits.html.haml b/app/views/admin/application_settings/_projects_api_limits.html.haml
new file mode 100644
index 00000000000..4efab4d77a9
--- /dev/null
+++ b/app/views/admin/application_settings/_projects_api_limits.html.haml
@@ -0,0 +1,21 @@
+%section.settings.as-projects-api-limits.no-animate#js-projects-api-limits-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
+ = _('Projects API rate limit')
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Set the per-IP address rate limit applicable to unauthenticated requests for getting a list of projects via the API.')
+ = link_to _('Learn more.'), help_page_path('user/admin_area/settings/rate_limit_on_projects_api.md'), target: '_blank', rel: 'noopener noreferrer'
+ .settings-content
+ = gitlab_ui_form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-projects-api-limits-settings'), html: { class: 'fieldset-form' } do |f|
+ = form_errors(@application_setting)
+
+ %fieldset
+ .form-group
+ = f.label :projects_api_rate_limit_unauthenticated, _('Maximum requests per 10 minutes per IP address'), class: 'label-bold'
+ = f.number_field :projects_api_rate_limit_unauthenticated, class: 'form-control gl-form-input'
+ .form-text.gl-text-gray-600
+ = _("Set this number to 0 to disable the limit.")
+
+ = f.submit _('Save changes'), data: { qa_selector: 'save_changes_button' }, pajamas_button: true
diff --git a/app/views/admin/application_settings/_realtime.html.haml b/app/views/admin/application_settings/_realtime.html.haml
index 6a7ec05d206..2b8b023baea 100644
--- a/app/views/admin/application_settings/_realtime.html.haml
+++ b/app/views/admin/application_settings/_realtime.html.haml
@@ -1,4 +1,4 @@
-= form_for @application_setting, url: preferences_admin_application_settings_path(anchor: 'js-realtime-settings'), html: { class: 'fieldset-form' } do |f|
+= gitlab_ui_form_for @application_setting, url: preferences_admin_application_settings_path(anchor: 'js-realtime-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
@@ -8,4 +8,4 @@
.form-text.text-muted
= _('Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1.')
- = f.submit _('Save changes'), class: "gl-button btn btn-confirm"
+ = f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/_repository_check.html.haml b/app/views/admin/application_settings/_repository_check.html.haml
index b67cc29f296..5751ae9059a 100644
--- a/app/views/admin/application_settings/_repository_check.html.haml
+++ b/app/views/admin/application_settings/_repository_check.html.haml
@@ -13,7 +13,9 @@
= _("If you get a lot of false alarms from repository checks, you can clear all repository check information from the database.")
- clear_repository_checks_link = _('Clear all repository checks')
- clear_repository_checks_message = _('This clears repository check states for all projects in the database and cannot be undone. Are you sure?')
- = link_to clear_repository_checks_link, clear_repository_check_states_admin_application_settings_path, data: { confirm: clear_repository_checks_message, confirm_btn_variant: 'danger' }, aria: { label: _('Clear repository checks') }, method: :put, class: "gl-button btn btn-sm btn-danger gl-mt-3"
+ = render Pajamas::ButtonComponent.new(variant: :danger, href: clear_repository_check_states_admin_application_settings_path, method: :put, button_options: { class: 'btn-sm gl-mt-3', data: { confirm: clear_repository_checks_message, confirm_btn_variant: 'danger' }, aria: { label: _('Clear repository checks') } }) do
+ = clear_repository_checks_link
+
.sub-section
%h4= _("Housekeeping")
diff --git a/app/views/admin/application_settings/_runner_registrars_form.html.haml b/app/views/admin/application_settings/_runner_registrars_form.html.haml
index baf7c5de7b9..53832e93ed2 100644
--- a/app/views/admin/application_settings/_runner_registrars_form.html.haml
+++ b/app/views/admin/application_settings/_runner_registrars_form.html.haml
@@ -2,7 +2,18 @@
= form_errors(@application_setting)
%fieldset
+ .form-group
+ %h5
+ = s_('Runners|Runner version management')
+ %span.form-text.gl-mb-3.gl-mt-0
+ - help_text = s_('Runners|Official runner version data is periodically fetched from GitLab.com to determine whether the runners need upgrades.')
+ - learn_more_link = link_to _('Learn more.'), help_page_path('ci/runners/configure_runners.md', anchor: 'determine-which-runners-need-to-be-upgraded'), target: '_blank', rel: 'noopener noreferrer'
+ = f.gitlab_ui_checkbox_component :update_runner_versions_enabled,
+ s_('Runners|Fetch GitLab Runner release version data from GitLab.com'),
+ help_text: '%{help_text} %{learn_more_link}'.html_safe % { help_text: help_text, learn_more_link: learn_more_link }
.gl-form-group
+ %h5
+ = s_('Runners|Runner registration')
%span.form-text.gl-mb-3.gl-mt-0
= s_('Runners|If both settings are disabled, new runners cannot be registered.')
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'restrict-runner-registration-by-all-users-in-an-instance'), target: '_blank', rel: 'noopener noreferrer'
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 0305a9487ca..b64617f3f11 100644
--- a/app/views/admin/application_settings/_visibility_and_access.html.haml
+++ b/app/views/admin/application_settings/_visibility_and_access.html.haml
@@ -38,6 +38,8 @@
= 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')
diff --git a/app/views/admin/application_settings/appearances/_form.html.haml b/app/views/admin/application_settings/appearances/_form.html.haml
index 6c6334905ca..1b0e974a0ca 100644
--- a/app/views/admin/application_settings/appearances/_form.html.haml
+++ b/app/views/admin/application_settings/appearances/_form.html.haml
@@ -16,7 +16,8 @@
= image_tag @appearance.header_logo_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
- = link_to _('Remove header logo'), header_logos_admin_application_settings_appearances_path, data: { confirm: _("Header logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove header logo') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm"
+ = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: header_logos_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Header logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove header logo') } }) do
+ = _('Remove header logo')
%hr
= f.hidden_field :header_logo_cache
= f.file_field :header_logo, class: "", accept: 'image/*'
@@ -35,7 +36,8 @@
= image_tag @appearance.favicon_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
- = link_to _('Remove favicon'), favicon_admin_application_settings_appearances_path, data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm"
+ = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: favicon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') } }) do
+ = _('Remove favicon')
%hr
= f.hidden_field :favicon_cache
= f.file_field :favicon, class: '', accept: 'image/*'
@@ -67,7 +69,8 @@
= image_tag @appearance.logo_path, class: 'appearance-logo-preview'
- if @appearance.persisted?
%br
- = link_to _('Remove logo'), logo_admin_application_settings_appearances_path, data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm remove-logo"
+ = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: logo_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') } }) do
+ = _('Remove logo')
%hr
= f.hidden_field :logo_cache
= f.file_field :logo, class: "", accept: 'image/*'
@@ -98,7 +101,8 @@
= image_tag @appearance.pwa_icon_path, class: 'appearance-pwa-icon-preview'
- if @appearance.persisted?
%br
- = link_to _('Remove icon'), pwa_icon_admin_application_settings_appearances_path, data: { confirm: _("Icon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove icon') }, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm remove-logo"
+ = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: pwa_icon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Icon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove icon') } }) do
+ = _('Remove icon')
%hr
= f.hidden_field :pwa_icon_cache
= f.file_field :pwa_icon, class: "", accept: 'image/*'
diff --git a/app/views/admin/application_settings/appearances/show.html.haml b/app/views/admin/application_settings/appearances/show.html.haml
index 1e55190d53b..cd255d961f4 100644
--- a/app/views/admin/application_settings/appearances/show.html.haml
+++ b/app/views/admin/application_settings/appearances/show.html.haml
@@ -1,5 +1,4 @@
- page_title _("Appearance")
-- @content_class = "limit-container-width" unless fluid_layout
- add_page_specific_style 'page_bundles/settings'
= render 'form'
diff --git a/app/views/admin/application_settings/ci_cd.html.haml b/app/views/admin/application_settings/ci_cd.html.haml
index bd0ce766f81..c2dc3c3707e 100644
--- a/app/views/admin/application_settings/ci_cd.html.haml
+++ b/app/views/admin/application_settings/ci_cd.html.haml
@@ -1,7 +1,6 @@
- breadcrumb_title _("CI/CD")
- page_title _("CI/CD")
- add_page_specific_style 'page_bundles/settings'
-- @content_class = "limit-container-width" unless fluid_layout
%section.settings.no-animate#js-ci-cd-variables{ class: ('expanded' if expanded_by_default?) }
.settings-header
@@ -42,7 +41,7 @@
%section.settings.as-runner.no-animate#js-runner-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
- = s_('Runners|Runner registration')
+ = s_('Runners|Runners')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? 'Collapse' : 'Expand'
.settings-content
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index a4af1913d22..a7c80abdbc9 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -1,7 +1,6 @@
- breadcrumb_title _("General")
- page_title _("General")
- add_page_specific_style 'page_bundles/settings'
-- @content_class = "limit-container-width" unless fluid_layout
%section.settings.as-visibility-access.no-animate#js-visibility-settings{ class: ('expanded' if expanded_by_default?), data: { testid: 'admin-visibility-access-settings' } }
.settings-header
diff --git a/app/views/admin/application_settings/integrations.html.haml b/app/views/admin/application_settings/integrations.html.haml
index fd1ad5cd304..396e6f3e7d6 100644
--- a/app/views/admin/application_settings/integrations.html.haml
+++ b/app/views/admin/application_settings/integrations.html.haml
@@ -1,7 +1,6 @@
- breadcrumb_title s_('Integrations|Instance-level integration management')
- page_title s_('Integrations|Instance-level integration management')
- add_page_specific_style 'page_bundles/settings'
-- @content_class = 'limit-container-width' unless fluid_layout
%h3= s_('Integrations|Instance-level integration management')
diff --git a/app/views/admin/application_settings/metrics_and_profiling.html.haml b/app/views/admin/application_settings/metrics_and_profiling.html.haml
index b5981578866..711b2c97d65 100644
--- a/app/views/admin/application_settings/metrics_and_profiling.html.haml
+++ b/app/views/admin/application_settings/metrics_and_profiling.html.haml
@@ -3,7 +3,6 @@
- breadcrumb_title _("Metrics and profiling")
- page_title _("Metrics and profiling")
- add_page_specific_style 'page_bundles/settings'
-- @content_class = "limit-container-width" unless fluid_layout
%section.settings.as-prometheus.no-animate#js-prometheus-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
diff --git a/app/views/admin/application_settings/network.html.haml b/app/views/admin/application_settings/network.html.haml
index 779263b439f..32b10fd36e8 100644
--- a/app/views/admin/application_settings/network.html.haml
+++ b/app/views/admin/application_settings/network.html.haml
@@ -1,7 +1,6 @@
- breadcrumb_title _("Network")
- page_title _("Network")
- add_page_specific_style 'page_bundles/settings'
-- @content_class = "limit-container-width" unless fluid_layout
%section.settings.as-performance.no-animate#js-performance-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
@@ -92,7 +91,7 @@
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
- = s_('OutboundRequests|Allow requests to the local network from hooks and services.')
+ = s_('OutboundRequests|Allow requests to the local network from hooks and integrations.')
= link_to _('Learn more.'), help_page_path('security/webhooks.md'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
= render 'outbound'
@@ -146,6 +145,9 @@
.settings-content
= render 'users_api_limits'
+- if Feature.enabled?(:rate_limit_for_unauthenticated_projects_api_access)
+ = render 'projects_api_limits'
+
%section.settings.as-import-export-limits.no-animate#js-import-export-limits-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
diff --git a/app/views/admin/application_settings/preferences.html.haml b/app/views/admin/application_settings/preferences.html.haml
index dd6666542ca..3843fc8e863 100644
--- a/app/views/admin/application_settings/preferences.html.haml
+++ b/app/views/admin/application_settings/preferences.html.haml
@@ -1,7 +1,6 @@
- breadcrumb_title _("Preferences")
- page_title _("Preferences")
- add_page_specific_style 'page_bundles/settings'
-- @content_class = "limit-container-width" unless fluid_layout
%section.settings.as-email.no-animate#js-email-settings{ class: ('expanded' if expanded_by_default?), data: { qa_selector: 'email_content' } }
.settings-header
diff --git a/app/views/admin/application_settings/reporting.html.haml b/app/views/admin/application_settings/reporting.html.haml
index 3d803e95cd0..0046275c7d1 100644
--- a/app/views/admin/application_settings/reporting.html.haml
+++ b/app/views/admin/application_settings/reporting.html.haml
@@ -1,7 +1,6 @@
- breadcrumb_title _("Reporting")
- page_title _("Reporting")
- add_page_specific_style 'page_bundles/settings'
-- @content_class = "limit-container-width" unless fluid_layout
%section.settings.as-spam.no-animate#js-spam-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
diff --git a/app/views/admin/application_settings/repository.html.haml b/app/views/admin/application_settings/repository.html.haml
index 50798ad476c..518b40a0326 100644
--- a/app/views/admin/application_settings/repository.html.haml
+++ b/app/views/admin/application_settings/repository.html.haml
@@ -1,7 +1,6 @@
- breadcrumb_title _("Repository")
- page_title _("Repository")
- add_page_specific_style 'page_bundles/settings'
-- @content_class = "limit-container-width" unless fluid_layout
%section.settings.as-default-branch-name.no-animate#js-default-branch-name{ class: ('expanded' if expanded_by_default?) }
.settings-header
diff --git a/app/views/admin/application_settings/service_usage_data.html.haml b/app/views/admin/application_settings/service_usage_data.html.haml
index d6860cc08ac..af646d79c29 100644
--- a/app/views/admin/application_settings/service_usage_data.html.haml
+++ b/app/views/admin/application_settings/service_usage_data.html.haml
@@ -3,7 +3,6 @@
- breadcrumb_title name
- page_title name
- add_page_specific_style 'page_bundles/settings'
-- @content_class = "limit-container-width" unless fluid_layout
- payload_class = 'js-service-ping-payload'
%section.js-search-settings-section
diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml
index 212e3eeb951..b93a3c5d7fe 100644
--- a/app/views/admin/applications/show.html.haml
+++ b/app/views/admin/applications/show.html.haml
@@ -7,4 +7,5 @@
edit_path: edit_admin_application_path(@application),
delete_path: admin_application_path(@application),
index_path: admin_applications_path,
+ renew_path: renew_admin_application_path(@application),
show_trusted_row: true
diff --git a/app/views/admin/background_migrations/index.html.haml b/app/views/admin/background_migrations/index.html.haml
index 0f76fdce416..00859bf6b66 100644
--- a/app/views/admin/background_migrations/index.html.haml
+++ b/app/views/admin/background_migrations/index.html.haml
@@ -5,7 +5,7 @@
.gl-flex-grow-1
%h3= s_('BackgroundMigrations|Background Migrations')
%p.light.gl-mb-0
- - learnmore_link = help_page_path('user/admin_area/monitoring/background_migrations')
+ - learnmore_link = help_page_path('update/background_migrations')
- learnmore_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: learnmore_link }
= html_escape(s_('BackgroundMigrations|Background migrations are used to perform data migrations whenever a migration exceeds the time limits in our guidelines. %{linkStart}Learn more%{linkEnd}')) % { linkStart: learnmore_link_start, linkEnd: '</a>'.html_safe }
diff --git a/app/views/admin/broadcast_messages/_preview.html.haml b/app/views/admin/broadcast_messages/_preview.html.haml
deleted file mode 100644
index 56168926a6e..00000000000
--- a/app/views/admin/broadcast_messages/_preview.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-.js-broadcast-banner-message-preview
- = render "shared/broadcast_message", { message: @broadcast_message, preview: true } do
- = _('Your message here')
diff --git a/app/views/admin/dev_ops_report/show.html.haml b/app/views/admin/dev_ops_report/show.html.haml
index a2425b93ad3..d92d13260fe 100644
--- a/app/views/admin/dev_ops_report/show.html.haml
+++ b/app/views/admin/dev_ops_report/show.html.haml
@@ -1,5 +1,5 @@
- page_title _('DevOps Reports')
-- add_page_specific_style 'page_bundles/dev_ops_report'
+- add_page_specific_style 'page_bundles/dev_ops_reports'
.container
.gl-mt-3
diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml
index f9ebda2bc21..20d24161c57 100644
--- a/app/views/admin/groups/_group.html.haml
+++ b/app/views/admin/groups/_group.html.haml
@@ -1,10 +1,9 @@
- 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' } }
- .avatar-container.rect-avatar.s40.gl-flex-shrink-0
- = group_icon(group, class: "avatar s40")
+ = render Pajamas::AvatarComponent.new(group, size: 32, alt: '')
- .gl-min-w-0.gl-flex-grow-1
+ .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
= group.full_name
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index c8b0704c35d..73fe1941818 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -20,8 +20,7 @@
- c.body do
%ul.content-list.content-list-items-padding
%li
- .avatar-container.rect-avatar.s60
- = group_icon(@group, class: "avatar s60")
+ = render Pajamas::AvatarComponent.new(@group, size: 64, alt: '')
%li
%span.light= _('Name:')
%strong
diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml
index 98427cb6419..e7aa4f38634 100644
--- a/app/views/admin/health_check/show.html.haml
+++ b/app/views/admin/health_check/show.html.haml
@@ -8,9 +8,8 @@
#{ s_('HealthCheck|Access token is') }
%code#health-check-token= Gitlab::CurrentSettings.health_check_access_token
.gl-mt-3
- = button_to _("Reset health check access token"), reset_health_check_token_admin_application_settings_path,
- method: :put, class: 'gl-button btn btn-default',
- data: { confirm: _('Are you sure you want to reset the health check token?') }
+ = render Pajamas::ButtonComponent.new(href: reset_health_check_token_admin_application_settings_path, method: :put, button_options: { data: { confirm: _('Are you sure you want to reset the health check token?') } }) do
+ = _("Reset health check access token")
%p.light
#{ _('Health information can be retrieved from the following endpoints. More information is available') }
= link_to s_('More information is available|here'), help_page_path('user/admin_area/monitoring/health_check')
diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml
new file mode 100644
index 00000000000..18bef523168
--- /dev/null
+++ b/app/views/admin/projects/_form.html.haml
@@ -0,0 +1,23 @@
+= gitlab_ui_form_for [:admin, @project] do |f|
+ = form_errors(@project)
+ = render ::Layouts::HorizontalSectionComponent.new(options: { class: 'gl-pb-3 gl-mb-6' }) do |c|
+ = c.title { _('Naming') }
+ = c.description do
+ = _('Update your project name and description.')
+ = c.body do
+ .form-group.gl-form-group
+ = f.label :name, _('Project name')
+ = f.text_field :name, class: 'form-control gl-form-input gl-md-form-input-md'
+
+ .form-group.gl-form-group
+ = f.label :id, _('Project ID')
+ = f.text_field :id, class: 'form-control gl-form-input gl-md-form-input-sm', readonly: true
+
+ .form-group.gl-form-group
+ = f.label :description, _('Project description (optional)')
+ = f.text_area :description, class: 'form-control gl-form-input gl-form-textarea gl-lg-form-input-xl', rows: 5
+
+ .gl-mt-5
+ = f.submit _('Save changes'), pajamas_button: true
+ = render Pajamas::ButtonComponent.new(href: admin_project_path(@project)) do
+ = _('Cancel')
diff --git a/app/views/admin/projects/_projects.html.haml b/app/views/admin/projects/_projects.html.haml
index cf1bd2a8022..df1653cdd71 100644
--- a/app/views/admin/projects/_projects.html.haml
+++ b/app/views/admin/projects/_projects.html.haml
@@ -3,9 +3,8 @@
%ul.content-list
- @projects.each do |project|
%li.project-row.gl-align-items-center{ class: 'gl-display-flex!' }
- .avatar-container.rect-avatar.s40.gl-flex-shrink-0
- = project_icon(project, alt: '', class: 'avatar project-avatar s40', width: 40, height: 40)
- .gl-min-w-0.gl-flex-grow-1
+ = render Pajamas::AvatarComponent.new(project, size: 32, alt: '')
+ .gl-min-w-0.gl-flex-grow-1.gl-ml-3
.title
= link_to(admin_project_path(project)) do
%span.project-full-name
@@ -24,7 +23,7 @@
= render_if_exists 'admin/projects/archived', project: project
.controls.gl-flex-shrink-0.gl-ml-5
- = render Pajamas::ButtonComponent.new(href: edit_project_path(project), button_options: { id: dom_id(project, :edit) }) do
+ = render Pajamas::ButtonComponent.new(href: edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param }), button_options: { id: dom_id(project) }) do
= _('Edit')
= render Pajamas::ButtonComponent.new(variant: :danger, button_options: { class: 'delete-project-button', data: { delete_project_url: admin_project_path(project), project_name: project.name } }) do
= s_('AdminProjects|Delete')
diff --git a/app/views/admin/projects/edit.html.haml b/app/views/admin/projects/edit.html.haml
new file mode 100644
index 00000000000..ade0f543d58
--- /dev/null
+++ b/app/views/admin/projects/edit.html.haml
@@ -0,0 +1,4 @@
+- page_title _("Edit"), @project.name, _("Projects")
+%h1.page-title.gl-font-size-h-display= _('Edit project: %{project_name}') % { project_name: @project.name }
+%hr
+= render 'form'
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 464027e73f4..2803bec49c3 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -6,7 +6,9 @@
%h1.page-title.gl-font-size-h-display
= _('Project: %{name}') % { name: @project.full_name }
- = render Pajamas::ButtonComponent.new(href: edit_project_path(@project), icon: 'pencil', button_options: { class: 'gl-float-right' }) do
+ = render Pajamas::ButtonComponent.new(href: edit_admin_namespace_project_path({ id: @project.to_param, namespace_id: @project.namespace.to_param }),
+ icon: 'pencil',
+ button_options: { class: 'gl-float-right'}) do
= _('Edit')
%hr
- if @project.last_repository_check_failed?
diff --git a/app/views/admin/runners/register.html.haml b/app/views/admin/runners/register.html.haml
new file mode 100644
index 00000000000..662bb9ea00e
--- /dev/null
+++ b/app/views/admin/runners/register.html.haml
@@ -0,0 +1,7 @@
+- runner_name = "##{@runner.id} (#{@runner.short_sha})"
+- breadcrumb_title s_('Runners|Register')
+- page_title s_('Runners|Register'), "##{@runner.id} (#{@runner.short_sha})"
+- add_to_breadcrumbs _('Runners'), admin_runners_path
+- add_to_breadcrumbs runner_name, register_admin_runner_path(@runner)
+
+#js-admin-register-runner{ data: { runner_id: @runner.id, runners_path: admin_runners_path } }
diff --git a/app/views/admin/sessions/_two_factor_otp.html.haml b/app/views/admin/sessions/_two_factor_otp.html.haml
index 40ba79d1a65..f7b4035488d 100644
--- a/app/views/admin/sessions/_two_factor_otp.html.haml
+++ b/app/views/admin/sessions/_two_factor_otp.html.haml
@@ -1,9 +1,9 @@
-= form_tag(admin_session_path, { method: :post, class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if current_user.two_factor_webauthn_u2f_enabled?}" }) do
+= form_tag(admin_session_path, { method: :post, class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if current_user.two_factor_webauthn_enabled?}" }) do
.form-group
- = label_tag :user_otp_attempt, _('Two-Factor Authentication code')
- = text_field_tag 'user[otp_attempt]', nil, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', title: _('This field is required.')
+ = label_tag :user_otp_attempt, _('Enter verification code')
+ = text_field_tag 'user[otp_attempt]', nil, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', inputmode: 'numeric', title: _('This field is required.')
%p.form-text.text-muted.hint
- = _("Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.")
+ = _("Enter the code from your two-factor authenticator app. If you've lost your device, you can enter one of your recovery codes.")
.submit-container.move-submit-down
= submit_tag 'Verify code', class: 'gl-button btn btn-confirm'
diff --git a/app/views/admin/sessions/new.html.haml b/app/views/admin/sessions/new.html.haml
index 7d07b49c98e..3950170e486 100644
--- a/app/views/admin/sessions/new.html.haml
+++ b/app/views/admin/sessions/new.html.haml
@@ -1,4 +1,3 @@
-- @hide_breadcrumbs = true
- page_title _('Enter Admin Mode')
.row.justify-content-center
diff --git a/app/views/admin/sessions/two_factor.html.haml b/app/views/admin/sessions/two_factor.html.haml
index 3f915846dd8..d05cc51af41 100644
--- a/app/views/admin/sessions/two_factor.html.haml
+++ b/app/views/admin/sessions/two_factor.html.haml
@@ -1,4 +1,3 @@
-- @hide_breadcrumbs = true
- page_title _('Enter 2FA for Admin Mode')
.row.justify-content-center
@@ -11,5 +10,5 @@
.login-body
- if current_user.two_factor_otp_enabled?
= render 'admin/sessions/two_factor_otp'
- - if current_user.two_factor_webauthn_u2f_enabled?
+ - if current_user.two_factor_webauthn_enabled?
= render 'authentication/authenticate', render_remember_me: false, target_path: admin_session_path
diff --git a/app/views/admin/spam_logs/index.html.haml b/app/views/admin/spam_logs/index.html.haml
index c974f455112..001662c4015 100644
--- a/app/views/admin/spam_logs/index.html.haml
+++ b/app/views/admin/spam_logs/index.html.haml
@@ -17,6 +17,6 @@
%th= _('Primary Action')
%th
= render @spam_logs
- = paginate @spam_logs, theme: 'gitlab'
+ = paginate_collection @spam_logs
- else
%h4= _('There are no Spam Logs')
diff --git a/app/views/admin/topics/_topic.html.haml b/app/views/admin/topics/_topic.html.haml
index 869194a21f6..c63828cf41f 100644
--- a/app/views/admin/topics/_topic.html.haml
+++ b/app/views/admin/topics/_topic.html.haml
@@ -2,10 +2,9 @@
- title = topic.title || topic.name
%li.topic-row.gl-py-3.gl-align-items-center{ class: 'gl-display-flex!', data: { qa_selector: 'topic_row_content' } }
- .avatar-container.rect-avatar.s40.gl-flex-shrink-0
- = topic_icon(topic, class: "avatar s40")
+ = render Pajamas::AvatarComponent.new(topic, size: 32, alt: '')
- .gl-min-w-0.gl-flex-grow-1
+ .gl-min-w-0.gl-flex-grow-1.gl-ml-3
.title
= link_to title, topic_explore_projects_path(topic_name: topic.name)
%div
diff --git a/app/views/authentication/_register.html.haml b/app/views/authentication/_register.html.haml
index d6fe20e48bf..dc4511a8159 100644
--- a/app/views/authentication/_register.html.haml
+++ b/app/views/authentication/_register.html.haml
@@ -1,47 +1,50 @@
-#js-register-token-2fa
+- if Feature.enabled?(:webauthn) && Feature.enabled?(:webauthn_without_totp)
+ #js-device-registration{ data: device_registration_data(current_password_required: current_password_required?, target_path: target_path, webauthn_error: @webauthn_error) }
+- else
+ #js-register-token-2fa
--# haml-lint:disable InlineJavaScript
-%script#js-register-2fa-message{ type: "text/template" }
- %p <%= message %>
+ -# haml-lint:disable InlineJavaScript
+ %script#js-register-2fa-message{ type: "text/template" }
+ %p <%= message %>
--# haml-lint:disable InlineJavaScript
-%script#js-register-token-2fa-setup{ type: "text/template" }
- - if current_user.two_factor_otp_enabled?
- .row.gl-mb-3
- .col-md-5
- = render Pajamas::ButtonComponent.new(variant: :confirm,
- button_options: { id: 'js-setup-token-2fa-device' }) do
- = _("Set up new device")
- .col-md-7
- %p= _("Your device needs to be set up. Plug it in (if needed) and click the button on the left.")
- - else
- .row.gl-mb-3
- .col-md-4
- = render Pajamas::ButtonComponent.new(variant: :confirm,
- disabled: true,
- button_options: { id: 'js-setup-token-2fa-device' }) do
- = _("Set up new device")
- .col-md-8
- %p= _("You need to register a two-factor authentication app before you can set up a device.")
+ -# haml-lint:disable InlineJavaScript
+ %script#js-register-token-2fa-setup{ type: "text/template" }
+ - if current_user.two_factor_otp_enabled?
+ .row.gl-mb-3
+ .col-md-5
+ = render Pajamas::ButtonComponent.new(variant: :confirm,
+ button_options: { id: 'js-setup-token-2fa-device' }) do
+ = _("Set up new device")
+ .col-md-7
+ %p= _("Your device needs to be set up. Plug it in (if needed) and click the button on the left.")
+ - else
+ .row.gl-mb-3
+ .col-md-4
+ = render Pajamas::ButtonComponent.new(variant: :confirm,
+ disabled: true,
+ button_options: { id: 'js-setup-token-2fa-device' }) do
+ = _("Set up new device")
+ .col-md-8
+ %p= _("You need to register a two-factor authentication app before you can set up a device.")
--# haml-lint:disable InlineJavaScript
-%script#js-register-token-2fa-error{ type: "text/template" }
- %div
- %p
- %span <%= error_message %> (<%= error_name %>)
- = render Pajamas::ButtonComponent.new(button_options: { id: 'js-token-2fa-try-again' }) do
- = _("Try again?")
+ -# haml-lint:disable InlineJavaScript
+ %script#js-register-token-2fa-error{ type: "text/template" }
+ %div
+ %p
+ %span <%= error_message %> (<%= error_name %>)
+ = render Pajamas::ButtonComponent.new(button_options: { id: 'js-token-2fa-try-again' }) do
+ = _("Try again?")
--# haml-lint:disable InlineJavaScript
-%script#js-register-token-2fa-registered{ type: "text/template" }
- .row.gl-mb-3
- .col-md-12
- %p= _("Your device was successfully set up! Give it a name and register it with the GitLab server.")
- = form_tag(target_path, method: :post) do
- .row.gl-mb-3
- .col-md-3
- = text_field_tag 'device_registration[name]', nil, class: 'form-control', placeholder: _("Pick a name")
- .col-md-3
- = hidden_field_tag 'device_registration[device_response]', nil, class: 'form-control', required: true, id: "js-device-response"
- = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm) do
- = _("Register device")
+ -# haml-lint:disable InlineJavaScript
+ %script#js-register-token-2fa-registered{ type: "text/template" }
+ .row.gl-mb-3
+ .col-md-12
+ %p= _("Your device was successfully set up! Give it a name and register it with the GitLab server.")
+ = form_tag(target_path, method: :post) do
+ .row.gl-mb-3
+ .col-md-3
+ = text_field_tag 'device_registration[name]', nil, class: 'form-control', placeholder: _("Pick a name")
+ .col-md-3
+ = hidden_field_tag 'device_registration[device_response]', nil, class: 'form-control', required: true, id: "js-device-response"
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm) do
+ = _("Register device")
diff --git a/app/views/clusters/clusters/_integrations.html.haml b/app/views/clusters/clusters/_integrations.html.haml
index 4a3062def8c..0f62b640b97 100644
--- a/app/views/clusters/clusters/_integrations.html.haml
+++ b/app/views/clusters/clusters/_integrations.html.haml
@@ -6,7 +6,7 @@
- if can?(current_user, :admin_cluster, @cluster)
.sub-section.form-group
= gitlab_ui_form_for @prometheus_integration, as: :integration, namespace: :prometheus, url: @cluster.integrations_path, method: :post, html: { class: 'js-cluster-integrations-form' } do |prometheus_form|
- = prometheus_form.hidden_field :application_type
+ = prometheus_form.hidden_field :application_type, value: @prometheus_integration.application_type
.form-group.gl-form-group
- help_text = s_('ClusterIntegration|Allows GitLab to query a specifically configured in-cluster Prometheus for metrics.')
- help_link = link_to(_('More information.'), help_page_path("user/clusters/integrations", anchor: "prometheus-cluster-integration"), target: '_blank', rel: 'noopener noreferrer')
diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml
index 09e2e35c617..7734c0a7c9a 100644
--- a/app/views/dashboard/_groups_head.html.haml
+++ b/app/views/dashboard/_groups_head.html.haml
@@ -1,14 +1,13 @@
.page-title-holder.d-flex.align-items-center
%h1.page-title.gl-font-size-h-display= _('Groups')
- - if current_user.can_create_group?
- .page-title-controls
+ .page-title-controls.gl-display-flex.gl-align-items-center.gl-gap-5
+ = link_to _("Explore groups"), explore_groups_path
+ - if current_user.can_create_group?
= render Pajamas::ButtonComponent.new(href: new_group_path, variant: :confirm, button_options: { data: { qa_selector: "new_group_button", testid: "new-group-button" } }) do
= _("New group")
-.top-area
- = gl_tabs_nav({ class: 'gl-flex-grow-1 gl-border-0' }) do
- = gl_tab_link_to _("Your groups"), dashboard_groups_path
- = gl_tab_link_to _("Explore public groups"), explore_groups_path, data: { qa_selector: "public_groups_tab" }
+
+.top-area.gl-p-3.gl-justify-content-end
.nav-controls
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml
index c58d4cff034..e600d84f492 100644
--- a/app/views/dashboard/_projects_head.html.haml
+++ b/app/views/dashboard/_projects_head.html.haml
@@ -4,8 +4,9 @@
.page-title-holder.gl-display-flex.gl-align-items-center
%h1.page-title.gl-font-size-h-display= _('Projects')
- - if current_user.can_create_project?
- .page-title-controls
+ .page-title-controls.gl-display-flex.gl-align-items-center.gl-gap-5
+ = link_to _("Explore projects"), explore_projects_path
+ - if current_user.can_create_project?
= render Pajamas::ButtonComponent.new(href: new_project_path, variant: :confirm, button_options: { data: { qa_selector: 'new_project_button' } }) do
= _("New project")
diff --git a/app/views/dashboard/_projects_nav.html.haml b/app/views/dashboard/_projects_nav.html.haml
index 7cbd2fb14ec..87bd5209fdf 100644
--- a/app/views/dashboard/_projects_nav.html.haml
+++ b/app/views/dashboard/_projects_nav.html.haml
@@ -1,5 +1,4 @@
- is_your_projects_path = current_page?(dashboard_projects_path) || current_page?(root_path)
-- is_explore_projects_path = current_page?(explore_root_path) || current_page?(trending_explore_projects_path) || current_page?(starred_explore_projects_path) || current_page?(explore_projects_path)
= gl_tabs_nav({ class: 'scrolling-tabs nav-links gl-display-flex gl-flex-grow-1 gl-w-full nav gl-tabs-nav' }) do
= gl_tab_link_to dashboard_projects_path, { item_active: is_your_projects_path, class: 'shortcuts-activity', data: { placement: 'right' } } do
@@ -8,6 +7,4 @@
= gl_tab_link_to starred_dashboard_projects_path, { data: { placement: 'right' } } do
= s_("ProjectList|Starred")
= gl_tab_counter_badge(limited_counter_with_delimiter(@total_starred_projects_count))
- = gl_tab_link_to s_("ProjectList|Explore"), explore_root_path, { item_active: is_explore_projects_path, data: { placement: 'right' } }
- = gl_tab_link_to s_("ProjectList|Topics"), topics_explore_projects_path, { data: { placement: 'right' } }
= render_if_exists "dashboard/removed_projects_tab"
diff --git a/app/views/dashboard/_snippets_head.html.haml b/app/views/dashboard/_snippets_head.html.haml
index 5a798c249d1..e0e8aaa0fd9 100644
--- a/app/views/dashboard/_snippets_head.html.haml
+++ b/app/views/dashboard/_snippets_head.html.haml
@@ -1,13 +1,8 @@
.page-title-holder.d-flex.align-items-center
%h1.page-title.gl-font-size-h-display= _('Snippets')
- - if current_user && current_user.snippets.any? || @snippets.any?
- .page-title-controls
- - if can?(current_user, :create_snippet)
- = render Pajamas::ButtonComponent.new(href: new_snippet_path, variant: :confirm, button_options: { title: _("New snippet") }) do
- = _("New snippet")
-
-.top-area
- = gl_tabs_nav({ class: 'gl-border-0' }) do
- = gl_tab_link_to _('Your snippets'), dashboard_snippets_path, { title: _('Your snippets') }
- = gl_tab_link_to _('Explore snippets'), explore_snippets_path, { title: _('Explore snippets') }
+ .page-title-controls.gl-display-flex.gl-align-items-center.gl-gap-5
+ = link_to _("Explore snippets"), explore_snippets_path
+ - if can?(current_user, :create_snippet)
+ = render Pajamas::ButtonComponent.new(href: new_snippet_path, variant: :confirm, button_options: { title: _("New snippet") }) do
+ = _("New snippet")
diff --git a/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml b/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml
index eba5e7c6e9b..855177fd836 100644
--- a/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml
+++ b/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml
@@ -7,7 +7,7 @@
= link_to new_project_path, class: link_classes do
.blank-state-icon
= custom_icon("add_new_project", size: 50)
- .blank-state-body.gl-sm-pl-0.gl-pl-6
+ .blank-state-body.gl-sm-pl-6
%h3.gl-font-size-h2.gl-mt-0
= _('Create a project')
%p
@@ -17,7 +17,7 @@
= link_to new_group_path, class: link_classes do
.blank-state-icon
= custom_icon("add_new_group", size: 50)
- .blank-state-body.gl-sm-pl-0.gl-pl-6
+ .blank-state-body.gl-sm-pl-6
%h3.gl-font-size-h2.gl-mt-0
= _('Create a group')
%p
@@ -26,7 +26,7 @@
= link_to new_admin_user_path, class: link_classes do
.blank-state-icon
= custom_icon("add_new_user", size: 50)
- .blank-state-body.gl-sm-pl-0.gl-pl-6
+ .blank-state-body.gl-sm-pl-6
%h3.gl-font-size-h2.gl-mt-0
= _('Add people')
%p
@@ -35,7 +35,7 @@
= link_to admin_root_path, class: link_classes do
.blank-state-icon
= custom_icon("configure_server", size: 50)
- .blank-state-body.gl-sm-pl-0.gl-pl-6
+ .blank-state-body.gl-sm-pl-6
%h3.gl-font-size-h2.gl-mt-0
= _('Configure GitLab')
%p
diff --git a/app/views/dashboard/projects/_blank_state_welcome.html.haml b/app/views/dashboard/projects/_blank_state_welcome.html.haml
index a9a34af3f96..c5fdc31a775 100644
--- a/app/views/dashboard/projects/_blank_state_welcome.html.haml
+++ b/app/views/dashboard/projects/_blank_state_welcome.html.haml
@@ -5,7 +5,7 @@
= link_to new_project_path, class: link_classes do
.blank-state-icon
= custom_icon("add_new_project", size: 50)
- .blank-state-body.gl-sm-pl-0.gl-pl-6
+ .blank-state-body.gl-sm-pl-6
%h3.gl-font-size-h2.gl-mt-0
= _('Create a project')
%p
@@ -19,7 +19,7 @@
= link_to new_group_path, class: link_classes do
.blank-state-icon
= custom_icon("add_new_group", size: 50)
- .blank-state-body.gl-sm-pl-0.gl-pl-6
+ .blank-state-body.gl-sm-pl-6
%h3.gl-font-size-h2.gl-mt-0
= _('Create a group')
%p
@@ -28,7 +28,7 @@
= link_to trending_explore_projects_path, class: link_classes do
.blank-state-icon
= custom_icon("globe", size: 50)
- .blank-state-body.gl-sm-pl-0.gl-pl-6
+ .blank-state-body.gl-sm-pl-6
%h3.gl-font-size-h2.gl-mt-0
= _('Explore public projects')
%p
@@ -37,7 +37,7 @@
= link_to Gitlab::Saas::doc_url, class: link_classes do
.blank-state-icon
= custom_icon("lightbulb", size: 50)
- .blank-state-body.gl-sm-pl-0.gl-pl-6
+ .blank-state-body.gl-sm-pl-6
%h3.gl-font-size-h2.gl-mt-0
= _('Learn more about GitLab')
%p
diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml
index 68457ab33f7..42386e5b9cc 100644
--- a/app/views/dashboard/snippets/index.html.haml
+++ b/app/views/dashboard/snippets/index.html.haml
@@ -5,7 +5,7 @@
= render 'dashboard/snippets_head'
- if current_user.snippets.exists?
- = render partial: 'snippets/snippets_scope_menu', locals: { include_private: true, counts: @snippet_counts }
+ .top-area= render partial: 'snippets/snippets_scope_menu', locals: { include_private: true, counts: @snippet_counts }
= render partial: 'shared/snippets/list', locals: { link_project: true }
- else
= render 'shared/empty_states/snippets', button_path: button_path
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 9e59f9d700f..7ca89651282 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -62,7 +62,7 @@
= sort_options_hash[@sort]
- else
= sort_title_recently_created
- = sprite_icon('chevron-down', css_class: 'dropdown-menu-toggle-icon gl-top-3')
+ = sprite_icon('chevron-down', css_class: 'dropdown-menu-toggle-icon')
%ul.dropdown-menu.dropdown-menu-sort.dropdown-menu-right
%li
= link_to todos_filter_path(sort: sort_value_label_priority) do
@@ -82,15 +82,15 @@
= render @allowed_todos
= paginate @todos, theme: "gitlab"
.js-nothing-here-container.empty-state.hidden
- .svg-content
- = image_tag 'illustrations/todos_all_done.svg'
+ .svg-content.svg-150
+ = image_tag 'illustrations/empty-todos-all-done-md.svg'
.text-content.gl-text-center
%h4
= s_("Todos|You're all done!")
- elsif current_user.todos.any?
.col.todos-all-done.empty-state
- .svg-content.svg-250
- = image_tag 'illustrations/todos_all_done.svg'
+ .svg-content.svg-150
+ = image_tag 'illustrations/empty-todos-all-done-md.svg'
.text-content.gl-text-center
- if todos_filter_empty?
%h4
@@ -102,8 +102,8 @@
= s_("Todos|Nothing is on your to-do list. Nice work!")
- else
.col.empty-state
- .svg-content
- = image_tag 'illustrations/todos_empty.svg'
+ .svg-content.svg-150
+ = image_tag 'illustrations/empty-todos-md.svg'
.text-content.gl-text-center
%h4
= s_("Todos|Your To-Do List shows what to work on next")
diff --git a/app/views/devise/confirmations/almost_there.haml b/app/views/devise/confirmations/almost_there.haml
index 01f9595f35c..c22eeba2f01 100644
--- a/app/views/devise/confirmations/almost_there.haml
+++ b/app/views/devise/confirmations/almost_there.haml
@@ -1,6 +1,7 @@
- user_email = "(#{params[:email]})" if Devise.email_regexp.match?(params[:email])
- request_link_start = '<a href="%{new_user_confirmation_path}">'.html_safe % { new_user_confirmation_path: new_user_confirmation_path }
-- request_link_end = '</a>'.html_safe
+- registration_link_start = '<a href="%{new_user_registration_path}">'.html_safe % { new_user_registration_path: new_user_registration_path }
+- link_end = '</a>'.html_safe
- content_for :page_specific_javascripts do
= render "layouts/google_tag_manager_head"
= render "layouts/one_trust"
@@ -12,9 +13,11 @@
= _("Almost there...")
%p{ class: 'gl-mb-6 gl-font-lg!' }
= _('Please check your email %{email} to confirm your account') % { email: user_email }
+ %br
+ = _('If the email address is incorrect, you can %{registration_link_start}register again with a different email%{registration_link_end}.').html_safe % { registration_link_start: registration_link_start, registration_link_end: link_end }
%hr
- if Gitlab::CurrentSettings.after_sign_up_text.present?
.well-confirmation.gl-text-center
= markdown_field(Gitlab::CurrentSettings, :after_sign_up_text)
%p.gl-text-center
- = _("No confirmation email received? Check your spam folder or %{request_link_start}request new confirmation email%{request_link_end}.").html_safe % { request_link_start: request_link_start, request_link_end: request_link_end }
+ = _("No confirmation email received? Check your spam folder or %{request_link_start}request new confirmation email%{request_link_end}.").html_safe % { request_link_start: request_link_start, request_link_end: link_end }
diff --git a/app/views/devise/confirmations/new.html.haml b/app/views/devise/confirmations/new.html.haml
index d3bd1d58d21..4b586b2f580 100644
--- a/app/views/devise/confirmations/new.html.haml
+++ b/app/views/devise/confirmations/new.html.haml
@@ -1,7 +1,7 @@
= render 'devise/shared/tab_single', tab_title: 'Resend confirmation instructions'
.login-box.gl-p-5
.login-body
- = form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post, class: 'gl-show-field-errors' }) do |f|
+ = gitlab_ui_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post, class: 'gl-show-field-errors' }) do |f|
.devise-errors
= render "devise/shared/error_messages", resource: resource
.form-group
@@ -13,7 +13,8 @@
= recaptcha_tags nonce: content_security_policy_nonce
.gl-mt-5
- = f.submit _("Resend"), class: 'gl-button btn btn-confirm'
+ = render Pajamas::ButtonComponent.new(block: true, type: :submit, variant: :confirm) do
+ = _("Resend")
.clearfix.prepend-top-20
= render 'devise/shared/sign_in_link'
diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml
index 8a960602536..3bd7147f195 100644
--- a/app/views/devise/registrations/new.html.haml
+++ b/app/views/devise/registrations/new.html.haml
@@ -8,7 +8,7 @@
= render "layouts/google_tag_manager_body"
.signup-page
- = render 'devise/shared/signup_box',
+ = render signup_box_template,
url: registration_path(resource_name, glm_tracking_params.to_hash),
button_text: _('Register'),
borderless: Feature.enabled?(:restyle_login_page, @project),
diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml
index f63f1aa9197..12e5a7263f7 100644
--- a/app/views/devise/sessions/two_factor.html.haml
+++ b/app/views/devise/sessions/two_factor.html.haml
@@ -2,15 +2,15 @@
= render 'devise/shared/tab_single', tab_title: _('Two-Factor Authentication') if Feature.disabled?(:restyle_login_page, @project)
.login-box.gl-p-5
.login-body
- - if @user.two_factor_otp_enabled?
- = gitlab_ui_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if @user.two_factor_webauthn_u2f_enabled?}" }) do |f|
+ - if @user.two_factor_otp_enabled? || (Feature.enabled?(:webauthn_without_totp) && @user.two_factor_enabled?)
+ = gitlab_ui_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if @user.two_factor_webauthn_enabled?}" }) do |f|
- resource_params = params[resource_name].presence || params
= f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0)
%div
- = f.label _('Two-Factor Authentication code'), name: :otp_attempt, class: Feature.enabled?(:restyle_login_page, @project) ? 'gl-mb-1' : ''
- = f.text_field :otp_attempt, class: 'form-control gl-form-input', required: true, autofocus: true, autocomplete: 'off', title: _('This field is required.'), data: { qa_selector: 'two_fa_code_field' }
- %p.form-text.text-muted.hint= _("Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.")
+ = f.label _('Enter verification code'), name: :otp_attempt, class: Feature.enabled?(:restyle_login_page, @project) ? 'gl-mb-1' : ''
+ = f.text_field :otp_attempt, class: 'form-control gl-form-input', required: true, autofocus: true, autocomplete: 'off', inputmode: 'numeric', title: _('This field is required.'), data: { qa_selector: 'two_fa_code_field' }
+ %p.form-text.text-muted.hint= _("Enter the code from your two-factor authenticator app. If you've lost your device, you can enter one of your recovery codes.")
.prepend-top-20
= f.submit _("Verify code"), pajamas_button: true, data: { qa_selector: 'verify_code_button' }
- - if @user.two_factor_webauthn_u2f_enabled?
+ - if @user.two_factor_webauthn_enabled?
= render "authentication/authenticate", params: params, resource: resource, resource_name: resource_name, render_remember_me: true, target_path: new_user_session_path
diff --git a/app/views/devise/shared/_error_messages.html.haml b/app/views/devise/shared/_error_messages.html.haml
new file mode 100644
index 00000000000..b7589a4460e
--- /dev/null
+++ b/app/views/devise/shared/_error_messages.html.haml
@@ -0,0 +1,9 @@
+- if resource.errors.any?
+ = render Pajamas::AlertComponent.new(title: I18n.t("errors.messages.not_saved", count: resource.errors.count, resource: resource.class.model_name.human.downcase),
+ variant: :danger,
+ dismissible: false,
+ alert_options: { id: 'error_explanation', class: 'gl-mb-3'}) do |c|
+ = c.body do
+ %ul.gl-pl-4
+ - resource.errors.full_messages.each do |message|
+ %li= message
diff --git a/app/views/devise/shared/_sign_in_link.html.haml b/app/views/devise/shared/_sign_in_link.html.haml
index 0a48c342502..a1d10898c5b 100644
--- a/app/views/devise/shared/_sign_in_link.html.haml
+++ b/app/views/devise/shared/_sign_in_link.html.haml
@@ -1,6 +1,6 @@
%p.text-center
%span.light
- = _('Already have login and password?')
+ = _('Already have an account?')
- path_params = { redirect_to_referer: 'yes' }
- path_params[:invite_email] = @invite_email if @invite_email.present?
= link_to _('Sign in'), new_session_path(:user, path_params)
diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml
index f4f3965bdc1..57cd819cb89 100644
--- a/app/views/devise/shared/_signup_box.html.haml
+++ b/app/views/devise/shared/_signup_box.html.haml
@@ -66,7 +66,7 @@
= render_if_exists 'devise/shared/phone_verification', form: f
%div
- - if arkose_labs_challenge_enabled?
+ - if arkose_labs_enabled?
= render_if_exists 'devise/registrations/arkose_labs'
- elsif show_recaptcha_sign_up?
= recaptcha_tags nonce: content_security_policy_nonce
diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml
index 0428b9c340c..d087d85a94e 100644
--- a/app/views/doorkeeper/applications/show.html.haml
+++ b/app/views/doorkeeper/applications/show.html.haml
@@ -9,4 +9,5 @@
= render 'shared/doorkeeper/applications/show',
edit_path: edit_oauth_application_path(@application),
delete_path: oauth_application_path(@application),
- index_path: oauth_applications_path
+ index_path: oauth_applications_path,
+ renew_path: renew_oauth_application_path(@application)
diff --git a/app/views/explore/groups/_nav.html.haml b/app/views/explore/groups/_nav.html.haml
index 3c9c4e9f76b..176bfd307b2 100644
--- a/app/views/explore/groups/_nav.html.haml
+++ b/app/views/explore/groups/_nav.html.haml
@@ -1,6 +1,4 @@
-.top-area
- = gl_tabs_nav({ class: 'gl-display-flex gl-flex-grow-1 gl-border-none'}) do
- = gl_tab_link_to _("Explore Groups"), explore_groups_path
+.top-area.gl-p-3.gl-justify-content-end
.nav-controls
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml
index 60132818193..213346b4cc2 100644
--- a/app/views/explore/groups/index.html.haml
+++ b/app/views/explore/groups/index.html.haml
@@ -1,14 +1,17 @@
-- @hide_top_links = true
-- page_title _("Groups")
+- breadcrumb_title _("Groups")
+- page_title _("Explore groups")
- header_title _("Groups"), dashboard_groups_path
= render_dashboard_ultimate_trial(current_user)
-- if current_user
- = render 'dashboard/groups_head'
-- else
- = render 'explore/head'
- = render 'nav'
+.page-title-holder.gl-display-flex.gl-align-items-center
+ %h1.page-title.gl-font-size-h-display= page_title
+ .page-title-controls
+ - if current_user&.can_create_group?
+ = render Pajamas::ButtonComponent.new(href: new_group_path, variant: :confirm) do
+ = _("New group")
+
+= render 'nav'
- if cookies[:explore_groups_landing_dismissed] != 'true'
.explore-groups.landing.content-block.js-explore-groups-landing.hide
diff --git a/app/views/explore/projects/_nav.html.haml b/app/views/explore/projects/_nav.html.haml
index 9119026320a..ab565279238 100644
--- a/app/views/explore/projects/_nav.html.haml
+++ b/app/views/explore/projects/_nav.html.haml
@@ -1,10 +1,8 @@
.top-area
= gl_tabs_nav({ class: 'gl-display-flex gl-flex-grow-1 gl-border-none'}) do
= gl_tab_link_to _('All'), explore_projects_path, { item_active: current_page?(explore_projects_path) || current_page?(explore_root_path) }
- = gl_tab_link_to _('Most stars'), starred_explore_projects_path
+ = gl_tab_link_to _('Most starred'), starred_explore_projects_path
= gl_tab_link_to _('Trending'), trending_explore_projects_path
.nav-controls
- - unless current_user
- = render 'shared/projects/search_form'
- = render 'filter'
+ = render 'shared/projects/search_form'
diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml
index 9585eb76912..53b252db4fe 100644
--- a/app/views/explore/projects/index.html.haml
+++ b/app/views/explore/projects/index.html.haml
@@ -1,14 +1,15 @@
-- @hide_top_links = true
-- page_title _("Projects")
-- header_title _("Projects"), dashboard_projects_path
+- breadcrumb_title _("Projects")
+- page_title _("Explore projects")
- page_canonical_link explore_projects_url
= render_dashboard_ultimate_trial(current_user)
-- if current_user
- = render 'dashboard/projects_head', project_tab_filter: :explore
-- else
- = render 'explore/head'
+.page-title-holder.gl-display-flex.gl-align-items-center
+ %h1.page-title.gl-font-size-h-display= page_title
+ .page-title-controls
+ - if current_user&.can_create_project?
+ = render Pajamas::ButtonComponent.new(href: new_project_path, variant: :confirm) do
+ = _("New project")
= render 'explore/projects/nav'
= render 'projects', projects: @projects
diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml
index ec7eefea264..c765c086027 100644
--- a/app/views/explore/projects/starred.html.haml
+++ b/app/views/explore/projects/starred.html.haml
@@ -1,13 +1,14 @@
- @hide_top_links = true
-- page_title _("Projects")
+- page_title _("Explore projects")
- header_title _("Projects"), dashboard_projects_path
= render_dashboard_ultimate_trial(current_user)
-- if current_user
- = render 'dashboard/projects_head', project_tab_filter: :starred
-- else
- = render 'explore/head'
+.page-title-holder.gl-display-flex.gl-align-items-center
+ %h1.page-title.gl-font-size-h-display= page_title
+ .page-title-controls
+ = render Pajamas::ButtonComponent.new(href: new_project_path, variant: :confirm) do
+ = _("New project")
= render 'explore/projects/nav'
= render 'projects', projects: @projects
diff --git a/app/views/explore/projects/topic.html.haml b/app/views/explore/projects/topic.html.haml
index 7b2c5683482..b26abefcb0e 100644
--- a/app/views/explore/projects/topic.html.haml
+++ b/app/views/explore/projects/topic.html.haml
@@ -1,23 +1,23 @@
-- @hide_top_links = false
-- @no_container = true
+- add_to_breadcrumbs _("Topics"), topics_explore_projects_path
+- breadcrumb_title @topic.title_or_name
- page_title @topic.title_or_name, _("Topics")
- max_topic_title_length = 50
= render_dashboard_ultimate_trial(current_user)
-.gl-text-center.gl-bg-gray-10.gl-pb-2.gl-pt-6
- .gl-pb-5.gl-align-items-center.gl-justify-content-center.gl-display-flex
- .avatar-container.rect-avatar.s60.gl-flex-shrink-0
- = topic_icon(@topic, alt: _('Topic avatar'), class: 'avatar topic-avatar s60')
- - if @topic.title_or_name.length > max_topic_title_length
- %h1.gl-mt-3.gl-str-truncated.has-tooltip{ title: @topic.title_or_name }
- = truncate(@topic.title_or_name, length: max_topic_title_length)
- - else
- %h1.gl-mt-3
- = @topic.title_or_name
- - if @topic.description.present?
- .topic-description.gl-ml-4.gl-mr-4
- = markdown(@topic.description)
+.gl-text-center.gl-bg-gray-10.gl-pb-3.gl-pt-6
+ %div{ class: container_class }
+ .gl-pb-5.gl-align-items-center.gl-justify-content-center.gl-display-flex
+ = render Pajamas::AvatarComponent.new(@topic, size: 64, alt: '')
+ - if @topic.title_or_name.length > max_topic_title_length
+ %h1.gl-mt-3.gl-ml-5.gl-str-truncated.has-tooltip{ title: @topic.title_or_name }
+ = truncate(@topic.title_or_name, length: max_topic_title_length)
+ - else
+ %h1.gl-mt-3.gl-ml-5
+ = @topic.title_or_name
+ - if @topic.description.present?
+ .topic-description
+ = markdown(@topic.description)
%div{ class: container_class }
.gl-py-5.gl-border-gray-100.gl-border-b-solid.gl-border-b-1
diff --git a/app/views/explore/projects/topics.html.haml b/app/views/explore/projects/topics.html.haml
index 228304d25b6..08cd122c6aa 100644
--- a/app/views/explore/projects/topics.html.haml
+++ b/app/views/explore/projects/topics.html.haml
@@ -1,12 +1,9 @@
-- @hide_top_links = true
-- page_title _("Topics")
+- breadcrumb_title _("Topics")
+- page_title _("Explore topics")
- header_title _("Topics"), topics_explore_projects_path
= render_dashboard_ultimate_trial(current_user)
-- if current_user
- = render 'explore/topics/head'
-- else
- = render 'explore/head'
+= render 'explore/topics/head'
= render partial: 'shared/topics/list'
diff --git a/app/views/explore/projects/trending.html.haml b/app/views/explore/projects/trending.html.haml
index 8a92ec31b22..043189315b4 100644
--- a/app/views/explore/projects/trending.html.haml
+++ b/app/views/explore/projects/trending.html.haml
@@ -1,13 +1,15 @@
- @hide_top_links = true
-- page_title _("Projects")
+- page_title _("Explore projects")
- header_title _("Projects"), dashboard_projects_path
= render_dashboard_ultimate_trial(current_user)
-- if current_user
- = render 'dashboard/projects_head', project_tab_filter: :explore_trending
-- else
- = render 'explore/head'
+.page-title-holder.gl-display-flex.gl-align-items-center
+ %h1.page-title.gl-font-size-h-display= page_title
+ .page-title-controls
+ - if current_user&.can_create_project?
+ = render Pajamas::ButtonComponent.new(href: new_project_path, variant: :confirm) do
+ = _("New project")
= render 'explore/projects/nav'
= render 'projects', projects: @projects
diff --git a/app/views/explore/snippets/index.html.haml b/app/views/explore/snippets/index.html.haml
index bf861e30b3a..bd8b9c29389 100644
--- a/app/views/explore/snippets/index.html.haml
+++ b/app/views/explore/snippets/index.html.haml
@@ -1,10 +1,12 @@
-- @hide_top_links = true
-- page_title _("Snippets")
+- breadcrumb_title _("Snippets")
+- page_title _("Explore snippets")
- header_title _("Snippets"), snippets_path
-- if current_user
- = render 'dashboard/snippets_head'
-- else
- = render 'explore/head'
+.page-title-holder.gl-display-flex.gl-align-items-center
+ %h1.page-title.gl-font-size-h-display= page_title
+ .page-title-controls
+ - if can?(current_user, :create_snippet)
+ = render Pajamas::ButtonComponent.new(href: new_snippet_path, variant: :confirm) do
+ = _("New snippet")
= render partial: 'shared/snippets/list', locals: { link_project: true }
diff --git a/app/views/explore/topics/_head.html.haml b/app/views/explore/topics/_head.html.haml
index f7d80d63c45..db8de333517 100644
--- a/app/views/explore/topics/_head.html.haml
+++ b/app/views/explore/topics/_head.html.haml
@@ -1,10 +1,6 @@
-.page-title-holder.d-flex.align-items-center
- %h1.page-title.gl-font-size-h-display= _('Projects')
+.page-title-holder.gl-display-flex.gl-align-items-center
+ %h1.page-title.gl-font-size-h-display= page_title
-.top-area
- .scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
- .fade-left= sprite_icon('chevron-lg-left', size: 12)
- .fade-right= sprite_icon('chevron-lg-right', size: 12)
- = render 'dashboard/projects_nav'
+.top-area.gl-p-4
.nav-controls
= render 'shared/topics/search_form'
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 24ba060a89a..4a34e124c4c 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
@@ -25,9 +25,9 @@
= render Pajamas::AlertComponent.new(dismissible: false,
variant: :warning) do |c|
= c.body do
- - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index.md') }
+ - 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 related objects are migrated. %{docs_link_start}More info%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: docs_link_end }
+ = 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 }
%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.')
diff --git a/app/views/groups/_import_group_from_file_panel.html.haml b/app/views/groups/_import_group_from_file_panel.html.haml
index 35e8b7dc977..775b9c79817 100644
--- a/app/views/groups/_import_group_from_file_panel.html.haml
+++ b/app/views/groups/_import_group_from_file_panel.html.haml
@@ -10,14 +10,14 @@
alert_options: { class: 'gl-mb-5' },
dismissible: false) do |c|
= c.body do
- - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index.md') }
+ - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index.md', anchor: 'migrate-groups-by-direct-transfer-recommended') }
- link_end = '</a>'.html_safe
- = s_('GroupsNew|This feature is deprecated and replaced by %{docs_link_start}group migration%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: link_end }
+ = s_('GroupsNew|This feature is deprecated and replaced by group migration by direct transfer. %{docs_link_start}Learn more%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: link_end }
= render 'shared/groups/group_name_and_path_fields', f: f
.form-group
= f.label :file, s_('GroupsNew|Upload file')
.gl-font-weight-normal
- - import_export_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: help_page_path('user/group/settings/import_export') }
+ - import_export_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: help_page_path('user/group/import/index') }
= s_('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.').html_safe % { link_start: import_export_link_start, link_end: '</a>'.html_safe }
.gl-mt-3
= render 'shared/file_picker_button', f: f, field: :file, help_text: nil, classes: 'gl-button btn-confirm-secondary gl-mr-2'
diff --git a/app/views/groups/_invite_members_modal.html.haml b/app/views/groups/_invite_members_modal.html.haml
index f0fd9026b30..cd3327ba9ec 100644
--- a/app/views/groups/_invite_members_modal.html.haml
+++ b/app/views/groups/_invite_members_modal.html.haml
@@ -2,5 +2,5 @@
.js-invite-members-modal{ data: { is_project: 'false',
access_levels: group.access_level_roles.to_json,
- reload_page_on_submit: local_assigns.fetch(:reload_page_on_submit, false).to_s,
+ reload_page_on_submit: current_path?('group_members#index').to_s,
help_link: help_page_url('user/permissions') }.merge(common_invite_modal_dataset(group)).merge(users_filter_data(group)) }
diff --git a/app/views/groups/_invite_members_side_nav_link.html.haml b/app/views/groups/_invite_members_side_nav_link.html.haml
deleted file mode 100644
index 978ef01984c..00000000000
--- a/app/views/groups/_invite_members_side_nav_link.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-.js-invite-members-trigger{ data: { trigger_source: 'group-side-nav',
- icon: 'users',
- display_text: title,
- trigger_element: 'side-nav',
- qa_selector: 'invite_members_sidebar_button' } }
-
-= render partial: 'shared/nav/sidebar_submenu', locals: { sidebar_menu: sidebar_menu }
-= render 'groups/invite_members_modal', group: group
diff --git a/app/views/groups/_invite_members_top_nav_link.html.haml b/app/views/groups/_invite_members_top_nav_link.html.haml
new file mode 100644
index 00000000000..35a8d4d9944
--- /dev/null
+++ b/app/views/groups/_invite_members_top_nav_link.html.haml
@@ -0,0 +1,5 @@
+- data = local_assigns.fetch(:data)
+- data[:display_text] = local_assigns.fetch(:display_text)
+- data[:icon] = local_assigns.fetch(:icon)
+
+.js-invite-members-trigger{ data: data }
diff --git a/app/views/groups/_new_group_fields.html.haml b/app/views/groups/_new_group_fields.html.haml
index 95990e8937c..ddf6e52796f 100644
--- a/app/views/groups/_new_group_fields.html.haml
+++ b/app/views/groups/_new_group_fields.html.haml
@@ -31,6 +31,5 @@
.row
.col-sm-12
= f.submit submit_label, pajamas_button: true, data: { qa_selector: 'create_group_button' }
- = render Pajamas::ButtonComponent.new(href: dashboard_groups_path) do
+ = render Pajamas::ButtonComponent.new(href: @parent_group || dashboard_groups_path) do
= _('Cancel')
-
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index 298ed2c0806..a2a5f519221 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -1,6 +1,9 @@
- add_page_specific_style 'page_bundles/members'
- page_title _('Group members')
+= content_for :page_level_alert do
+ = render_if_exists 'shared/unlimited_members_during_trial_alert', group: @group.root_ancestor
+
.row.gl-mt-3
.col-lg-12
.gl-display-flex.gl-flex-wrap
@@ -16,7 +19,6 @@
trigger_source: 'group-members-page',
display_text: _('Invite members') } }
= render 'groups/invite_groups_modal', group: @group, reload_page_on_submit: true
- = render 'groups/invite_members_modal', group: @group, reload_page_on_submit: true
= render_if_exists 'groups/group_members/ldap_sync'
diff --git a/app/views/groups/milestones/_form.html.haml b/app/views/groups/milestones/_form.html.haml
index a99d76f99a7..1fd8e12016c 100644
--- a/app/views/groups/milestones/_form.html.haml
+++ b/app/views/groups/milestones/_form.html.haml
@@ -1,30 +1,25 @@
= gitlab_ui_form_for [@group, @milestone], html: { class: 'milestone-form common-note-form js-quick-submit js-requires-input' } do |f|
= form_errors(@milestone)
- .form-group.row
- .col-form-label.col-sm-2
- = f.label :title, _("Title")
- .col-sm-10
- = f.text_field :title, maxlength: 255, class: "form-control", data: { qa_selector: "milestone_title_field" }, required: true, autofocus: true
+ .form-group
+ = f.label :title, _("Title")
+ = f.text_field :title, maxlength: 255, class: "form-control", data: { qa_selector: "milestone_title_field" }, required: true, autofocus: true
= render "shared/milestones/form_dates", f: f
- .form-group.row.milestone-description
- .col-form-label.col-sm-2
- = f.label :description, _("Description")
- .col-sm-10
- = render layout: 'shared/md_preview', locals: { url: group_preview_markdown_path } do
- = render 'shared/zen', f: f, attr: :description,
- classes: 'note-textarea',
- qa_selector: 'milestone_description_field',
- supports_autocomplete: true,
- placeholder: _('Write milestone description...')
+ .form-group
+ = f.label :description, _("Description")
+ = render layout: 'shared/md_preview', locals: { url: group_preview_markdown_path } do
+ = render 'shared/zen', f: f, attr: :description,
+ classes: 'note-textarea',
+ qa_selector: 'milestone_description_field',
+ supports_autocomplete: true,
+ placeholder: _('Write milestone description...')
.clearfix
.error-alert
- .form-actions
- - if @milestone.new_record?
- = f.submit _('Create milestone'), data: { qa_selector: "create_milestone_button" }, pajamas_button: true
- = render Pajamas::ButtonComponent.new(href: group_milestones_path(@group)) do
- = _("Cancel")
- - else
- = f.submit _('Update milestone'), pajamas_button: true
- = render Pajamas::ButtonComponent.new(href: group_milestone_path(@group, @milestone)) do
- = _("Cancel")
+ - if @milestone.new_record?
+ = f.submit _('Create milestone'), data: { qa_selector: "create_milestone_button" }, class: 'gl-mr-2', pajamas_button: true
+ = render Pajamas::ButtonComponent.new(href: group_milestones_path(@group)) do
+ = _("Cancel")
+ - else
+ = f.submit _('Save changes'), class: 'gl-mr-2', pajamas_button: true
+ = render Pajamas::ButtonComponent.new(href: group_milestone_path(@group, @milestone)) do
+ = _("Cancel")
diff --git a/app/views/groups/milestones/new.html.haml b/app/views/groups/milestones/new.html.haml
index 8bceb1ddd5c..e1837bdd6fa 100644
--- a/app/views/groups/milestones/new.html.haml
+++ b/app/views/groups/milestones/new.html.haml
@@ -5,6 +5,5 @@
%h1.page-title.gl-font-size-h-display
= _("New Milestone")
-%hr
-
-= render "form"
+.gl-mt-3
+ = render "form"
diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml
index b75fda2f344..a5cbc443fa4 100644
--- a/app/views/groups/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -4,9 +4,9 @@
- header_title _("Groups"), dashboard_groups_path
- add_page_specific_style 'page_bundles/new_namespace'
-.group-edit-container.gl-mt-5
+.group-edit-container
- .js-new-group-creation{ data: { has_errors: @group.errors.any?.to_s }.merge(subgroup_creation_data(@group),
+ .js-new-group-creation{ data: { has_errors: @group.errors.any?.to_s, groups_url: dashboard_groups_url }.merge(subgroup_creation_data(@group),
verification_for_group_creation_data) }
.row{ 'v-cloak': true }
diff --git a/app/views/groups/settings/_export.html.haml b/app/views/groups/settings/_export.html.haml
index 5d79d0f8e79..6b505755727 100644
--- a/app/views/groups/settings/_export.html.haml
+++ b/app/views/groups/settings/_export.html.haml
@@ -5,13 +5,12 @@
%p= _('Export this group with all related data.')
= render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-4' }) do |c|
= c.body do
- - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index.md') }
+ - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index', anchor: 'migrate-groups-by-direct-transfer-recommended') }
- docs_link_end = '</a>'.html_safe
- = s_('GroupsNew|This feature is deprecated and replaced by %{docs_link_start}group migration%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: docs_link_end }
+ = s_('GroupsNew|This feature is deprecated and replaced by group migration by direct transfer. %{docs_link_start}Learn more%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: docs_link_end }
%p
- export_information = _('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.') % { strong_text_start: '<strong>'.html_safe, strong_text_end: '</strong>'.html_safe}
= export_information.html_safe
- = link_to _('Learn more.'), help_page_path('user/group/settings/import_export.md'), target: '_blank', rel: 'noopener noreferrer'
= render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c|
= c.body do
%p.gl-mb-0
diff --git a/app/views/groups/settings/_general.html.haml b/app/views/groups/settings/_general.html.haml
index 658109fde64..5258854c931 100644
--- a/app/views/groups/settings/_general.html.haml
+++ b/app/views/groups/settings/_general.html.haml
@@ -23,8 +23,7 @@
= render_if_exists 'shared/repository_size_limit_setting', form: f, type: :group
.form-group.gl-mt-3.gl-mb-6
- .avatar-container.rect-avatar.s90
- = group_icon(@group, alt: '', class: 'avatar group-avatar s90')
+ = render Pajamas::AvatarComponent.new(@group, size: 96, alt: '', class: 'gl-float-left gl-mr-5')
= f.label :avatar, s_('Groups|Group avatar'), class: 'label-bold d-block'
= render 'shared/choose_avatar_button', f: f
- if @group.avatar?
diff --git a/app/views/groups/settings/_transfer.html.haml b/app/views/groups/settings/_transfer.html.haml
index a4a83330fa9..415459f1584 100644
--- a/app/views/groups/settings/_transfer.html.haml
+++ b/app/views/groups/settings/_transfer.html.haml
@@ -10,7 +10,7 @@
- learn_more_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: learn_more_link }
- warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended side effects. %{learn_more_link_start}Learn more.%{learn_more_link_end}") % { learn_more_link_start: learn_more_link_start, learn_more_link_end: '</a>'.html_safe }
%li= warning_text.html_safe
- %li= s_('GroupSettings|You can only transfer the group to a group you manage.')
+ %li= s_('GroupSettings|You must have the Owner role in the target group')
%li= s_('GroupSettings|You will need to update your local repositories to point to the new location.')
%li= s_("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.")
- if group.paid?
diff --git a/app/views/groups/settings/applications/show.html.haml b/app/views/groups/settings/applications/show.html.haml
index 4a83d96aae4..e24aa993b26 100644
--- a/app/views/groups/settings/applications/show.html.haml
+++ b/app/views/groups/settings/applications/show.html.haml
@@ -9,4 +9,5 @@
= render 'shared/doorkeeper/applications/show',
edit_path: edit_group_settings_application_path(@group, @application),
delete_path: group_settings_application_path(@group, @application),
- index_path: group_settings_applications_path
+ index_path: group_settings_applications_path,
+ renew_path: renew_group_settings_application_path(@group, @application)
diff --git a/app/views/groups/settings/ci_cd/_auto_devops_form.html.haml b/app/views/groups/settings/ci_cd/_auto_devops_form.html.haml
index 06cb9893196..8c45809261c 100644
--- a/app/views/groups/settings/ci_cd/_auto_devops_form.html.haml
+++ b/app/views/groups/settings/ci_cd/_auto_devops_form.html.haml
@@ -2,8 +2,8 @@
= form_errors(group)
%fieldset
.form-group
- .card.gl-mb-3
- .card-body
+ = render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-3' }) do |c|
+ - c.body do
- learn_more_link = link_to _('Learn more.'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer'
- help_text = s_('GroupSettings|The Auto DevOps pipeline runs if no alternative CI configuration file is found.')
- badge = gl_badge_tag badge_for_auto_devops_scope(group), variant: :info
@@ -13,4 +13,5 @@
help_text: '%{help_text} %{learn_more_link}'.html_safe % { help_text: help_text, learn_more_link: learn_more_link },
checkbox_options: { checked: group.auto_devops_enabled? }
- = f.submit _('Save changes'), class: 'gl-mt-5', pajamas_button: true
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, button_options: { class: 'gl-mt-5' }) do
+ = _('Save changes')
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 72b7bec1b92..7983274f319 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -14,7 +14,6 @@
callouts_path: group_callouts_path,
callouts_feature_id: Users::GroupCalloutsHelper::INVITE_MEMBERS_BANNER,
group_id: @group.id } }
- = render 'groups/invite_members_modal', group: @group
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
diff --git a/app/views/help/instance_configuration/_ci_cd_limits.html.haml b/app/views/help/instance_configuration/_ci_cd_limits.html.haml
index bd5b8a6f10d..0a5cbb710e3 100644
--- a/app/views/help/instance_configuration/_ci_cd_limits.html.haml
+++ b/app/views/help/instance_configuration/_ci_cd_limits.html.haml
@@ -19,34 +19,34 @@
%th= title.to_s.humanize
%tbody
%tr
- %td= s_('AdminSettings|Maximum number of jobs in a single pipeline')
+ %td= plan_limit_setting_description(:ci_pipeline_size)
- ci_cd_limits.each_value do |limits|
%td= instance_configuration_disabled_cell_html(limits[:ci_pipeline_size])
%tr
- %td= s_('AdminSettings|Total number of jobs in currently active pipelines')
+ %td= plan_limit_setting_description(:ci_active_jobs)
- ci_cd_limits.each_value do |limits|
%td= instance_configuration_disabled_cell_html(limits[:ci_active_jobs])
%tr
- %td= s_('AdminSettings|Maximum number of active pipelines per project')
+ %td= plan_limit_setting_description(:ci_active_pipelines)
- ci_cd_limits.each_value do |limits|
%td= instance_configuration_disabled_cell_html(limits[:ci_active_pipelines])
%tr
- %td= s_('AdminSettings|Maximum number of pipeline subscriptions to and from a project')
+ %td= plan_limit_setting_description(:ci_project_subscriptions)
- ci_cd_limits.each_value do |limits|
%td= instance_configuration_disabled_cell_html(limits[:ci_project_subscriptions])
%tr
- %td= s_('AdminSettings|Maximum number of pipeline schedules')
+ %td= plan_limit_setting_description(:ci_pipeline_schedules)
- ci_cd_limits.each_value do |limits|
%td= instance_configuration_disabled_cell_html(limits[:ci_pipeline_schedules])
%tr
- %td= s_('AdminSettings|Maximum number of DAG dependencies that a job can have')
+ %td= plan_limit_setting_description(:ci_needs_size_limit)
- ci_cd_limits.each_value do |limits|
%td= instance_configuration_disabled_cell_html(limits[:ci_needs_size_limit])
%tr
- %td= s_('AdminSettings|Maximum number of runners registered per group')
+ %td= plan_limit_setting_description(:ci_registered_group_runners)
- ci_cd_limits.each_value do |limits|
%td= instance_configuration_disabled_cell_html(limits[:ci_registered_group_runners])
%tr
- %td= s_('AdminSettings|Maximum number of runners registered per project')
+ %td= plan_limit_setting_description(:ci_registered_project_runners)
- ci_cd_limits.each_value do |limits|
%td= instance_configuration_disabled_cell_html(limits[:ci_registered_project_runners])
diff --git a/app/views/ide/_show.html.haml b/app/views/ide/_show.html.haml
index 5a6e93c3573..eb6d5668807 100644
--- a/app/views/ide/_show.html.haml
+++ b/app/views/ide/_show.html.haml
@@ -7,4 +7,6 @@
- content_for :prefetch_asset_tags do
- webpack_preload_asset_tag('monaco')
-= render partial: 'shared/ide_root', locals: { data: ide_data(project: @project, branch: @branch, path: @path, merge_request: @merge_request, fork_info: @fork_info), loading_text: _('Loading the GitLab IDE...') }
+- data = ide_data(project: @project, fork_info: @fork_info, params: params)
+
+= render partial: 'shared/ide_root', locals: { data: data, loading_text: _('Loading the GitLab IDE...') }
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index dd441d0d155..2dd6eab2e17 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -10,6 +10,7 @@
%meta{ 'http-equiv' => 'X-UA-Compatible', content: 'IE=edge' }
= render 'layouts/startup_js'
+ = yield :startup_js
- if page_canonical_link
%link{ rel: 'canonical', href: page_canonical_link }
@@ -57,6 +58,8 @@
= yield :page_specific_javascripts
+ = webpack_bundle_tag 'super_sidebar' if show_super_sidebar?
+
= webpack_controller_bundle_tags
= yield :project_javascripts
diff --git a/app/views/layouts/_loading_hints.html.haml b/app/views/layouts/_loading_hints.html.haml
index 9026bec84c3..b20b95cade8 100644
--- a/app/views/layouts/_loading_hints.html.haml
+++ b/app/views/layouts/_loading_hints.html.haml
@@ -12,7 +12,8 @@
= preload_link_tag(path_to_stylesheet('application'), crossorigin: css_crossorigin)
= preload_link_tag(path_to_stylesheet("highlight/themes/#{user_color_scheme}"), crossorigin: css_crossorigin)
- if Gitlab::Tracking.enabled? && Gitlab::Tracking.collector_hostname
- %link{ rel: 'preconnect', href: "https://#{Gitlab::Tracking.collector_hostname}", crossorigin: '' }
+ - unless Rails.env.development?
+ %link{ rel: 'preconnect', href: "https://#{Gitlab::Tracking.collector_hostname}", crossorigin: '' }
-# Do not use preload_link_tag for fonts, to work around Firefox double-fetch bug.
-# See https://github.com/web-platform-tests/wpt/pull/36930
%link{ rel: 'preload', href: font_path('gitlab-sans/GitLabSans.woff2'), as: 'font', crossorigin: css_crossorigin }
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index d2ed70d6b48..74567af3554 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -2,8 +2,12 @@
- @left_sidebar = true
.layout-page.hide-when-top-nav-responsive-open{ class: page_with_sidebar_class }
- if show_super_sidebar?
- - sidebar_data = super_sidebar_context(current_user, group: @group, project: @project).to_json
- %aside.js-super-sidebar.nav-sidebar{ data: { root_path: root_path, sidebar: sidebar_data, toggle_new_nav_endpoint: profile_preferences_url } }
+ -# Render the parent group sidebar while creating a new subgroup/project, see GroupsController#new.
+ - group = @parent_group || @group
+
+ - sidebar_panel = super_sidebar_nav_panel(nav: nav, user: current_user, group: group, project: @project, current_ref: current_ref, ref_type: @ref_type, viewed_user: @user)
+ - sidebar_data = super_sidebar_context(current_user, group: group, project: @project, panel: sidebar_panel).to_json
+ %aside.js-super-sidebar.super-sidebar.super-sidebar-loading{ data: { root_path: root_path, sidebar: sidebar_data, toggle_new_nav_endpoint: profile_preferences_url } }
- if display_whats_new?
#whats-new-app{ data: { version_digest: whats_new_version_digest } }
@@ -44,4 +48,4 @@
-# This is needed by [GitLab JH](https://gitlab.com/gitlab-jh/jh-team/gitlab-cn/-/issues/81)
= render_if_exists "shared/footer/global_footer"
-= render "layouts/nav/top_nav_responsive", class: 'layout-page content-wrapper-margin'
+= render "layouts/nav/top_nav_responsive", class: 'layout-page content-wrapper-margin' unless show_super_sidebar?
diff --git a/app/views/layouts/component_preview.html.haml b/app/views/layouts/component_preview.html.haml
index a1b1304f994..8217ac13c52 100644
--- a/app/views/layouts/component_preview.html.haml
+++ b/app/views/layouts/component_preview.html.haml
@@ -1,12 +1,12 @@
%head
- - if params[:lookbook][:display][:theme] == 'light'
+ - if params[:lookbook][:display][:theme] == "light"
= stylesheet_link_tag "application"
= stylesheet_link_tag "application_utilities"
- else
= stylesheet_link_tag "application_dark"
= stylesheet_link_tag "application_utilities_dark"
%body
- .container.gl-mt-6
+ .gl-mt-6{ class: (params[:lookbook][:display][:layout] == "fluid" ? "container-fluid" : "container") }
- if params[:lookbook][:display][:bg_dark]
.bg-dark.rounded.shadow.p-4
= yield
diff --git a/app/views/layouts/dashboard.html.haml b/app/views/layouts/dashboard.html.haml
index 89f238eb6b3..1ac5f0a8497 100644
--- a/app/views/layouts/dashboard.html.haml
+++ b/app/views/layouts/dashboard.html.haml
@@ -2,6 +2,6 @@
- header_title _("Dashboard"), root_path unless header_title
- @left_sidebar = true
-- nav "your_work"
+- nav (@parent_group ? "group" : "your_work")
= render template: "layouts/application"
diff --git a/app/views/layouts/explore.html.haml b/app/views/layouts/explore.html.haml
index c495bab4547..02c00a53316 100644
--- a/app/views/layouts/explore.html.haml
+++ b/app/views/layouts/explore.html.haml
@@ -1,11 +1,6 @@
-- page_title _("Explore")
+- header_title _("Explore"), explore_root_path
-- if current_user
- - @left_sidebar = true
- - nav "your_work"
-
-- unless current_user
- - @hide_breadcrumbs = true
- - header_title _("Explore GitLab"), explore_root_path
+- @left_sidebar = true
+- nav "explore"
= render template: "layouts/application"
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 95934f43a51..40ec1ff199b 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -16,6 +16,10 @@
:plain
window.uploads_path = "#{group_uploads_path(@group)}";
+- content_for :before_content do
+ = render 'groups/invite_members_modal', group: @group
+
+= dispensable_render_if_exists "shared/web_hooks/group_web_hook_disabled_alert"
= dispensable_render_if_exists "shared/free_user_cap_alert", source: @group
= render template: base_layout || "layouts/application"
diff --git a/app/views/layouts/header/_new_dropdown.html.haml b/app/views/layouts/header/_new_dropdown.html.haml
index 372babea18e..50a2b45aa7e 100644
--- a/app/views/layouts/header/_new_dropdown.html.haml
+++ b/app/views/layouts/header/_new_dropdown.html.haml
@@ -26,8 +26,13 @@
= section.fetch(:title)
- section.fetch(:menu_items).each do |menu_item|
%li<
- = link_to menu_item.fetch(:href), class: menu_item.fetch(:css_class), data: menu_item.fetch(:data) do
- = menu_item.fetch(:title)
- - if menu_item.fetch(:emoji)
- -# We need to insert a space between the title and emoji
- = " #{emoji_icon(menu_item.fetch(:emoji), 'aria-hidden': true, class: 'gl-font-base gl-vertical-align-baseline')}".html_safe
+ - if menu_item.fetch(:partial).present?
+ = render partial: menu_item.fetch(:partial),
+ locals: { display_text: menu_item.fetch(:title),
+ icon: menu_item.fetch(:icon),
+ data: menu_item.fetch(:data) }
+ - else
+ = link_to menu_item.fetch(:title),
+ menu_item.fetch(:href),
+ class: menu_item.fetch(:css_class),
+ data: menu_item.fetch(:data)
diff --git a/app/views/layouts/nav/_breadcrumbs.html.haml b/app/views/layouts/nav/_breadcrumbs.html.haml
index 98d6af28cf5..06dff99718c 100644
--- a/app/views/layouts/nav/_breadcrumbs.html.haml
+++ b/app/views/layouts/nav/_breadcrumbs.html.haml
@@ -3,25 +3,26 @@
- unless @skip_current_level_breadcrumb
- push_to_schema_breadcrumb(@breadcrumb_title, breadcrumb_title_link)
-%nav.breadcrumbs{ class: [container, @content_class], 'aria-label': _('Breadcrumbs') }
- .breadcrumbs-container{ class: ("border-bottom-0" if @no_breadcrumb_border) }
- - if defined?(@left_sidebar)
- = button_tag class: 'toggle-mobile-nav', data: { qa_selector: 'toggle_mobile_nav_button' }, type: 'button' do
- %span.sr-only= _("Open sidebar")
- = sprite_icon('sidebar', size: 18)
- .breadcrumbs-links{ data: { testid: 'breadcrumb-links', qa_selector: 'breadcrumb_links_content' } }
- %ul.list-unstyled.breadcrumbs-list.js-breadcrumbs-list
- - unless hide_top_links
- = header_title
- - if @breadcrumbs_extra_links
- - @breadcrumbs_extra_links.each do |extra|
- = breadcrumb_list_item link_to(extra[:text], extra[:link])
- = render "layouts/nav/breadcrumbs/collapsed_inline_list", location: :after
- - unless @skip_current_level_breadcrumb
- %li{ data: { testid: 'breadcrumb-current-link', qa_selector: 'breadcrumb_current_link' } }
- = link_to @breadcrumb_title, breadcrumb_title_link
- -# haml-lint:disable InlineJavaScript
- %script{ type: 'application/ld+json' }
- :plain
- #{schema_breadcrumb_json}
- = yield :header_content
+.gl-relative
+ .breadcrumbs{ class: [container, @content_class] }
+ .breadcrumbs-container{ class: ("border-bottom-0" if @no_breadcrumb_border) }
+ - if show_super_sidebar?
+ = render Pajamas::ButtonComponent.new(icon: 'sidebar', category: :tertiary, button_options: { class: 'js-super-sidebar-toggle super-sidebar-toggle gl-ml-n3 gl-mr-2', title: _('Expand sidebar'), aria: { label: _('Expand sidebar') }, data: {toggle: 'tooltip', placement: 'right' } })
+ - elsif defined?(@left_sidebar)
+ = render Pajamas::ButtonComponent.new(icon: 'sidebar', category: :tertiary, button_options: { class: 'toggle-mobile-nav gl-ml-n3 gl-mr-2', data: { qa_selector: 'toggle_mobile_nav_button' }, aria: { label: _('Open sidebar') } })
+ %nav.breadcrumbs-links{ 'aria-label': _('Breadcrumbs'), data: { testid: 'breadcrumb-links', qa_selector: 'breadcrumb_links_content' } }
+ %ul.list-unstyled.breadcrumbs-list.js-breadcrumbs-list
+ - unless hide_top_links
+ = header_title
+ - if @breadcrumbs_extra_links
+ - @breadcrumbs_extra_links.each do |extra|
+ = breadcrumb_list_item link_to(extra[:text], extra[:link])
+ = render "layouts/nav/breadcrumbs/collapsed_inline_list", location: :after
+ - unless @skip_current_level_breadcrumb
+ %li{ data: { testid: 'breadcrumb-current-link', qa_selector: 'breadcrumb_current_link' } }
+ = link_to @breadcrumb_title, breadcrumb_title_link
+ -# haml-lint:disable InlineJavaScript
+ %script{ type: 'application/ld+json' }
+ :plain
+ #{schema_breadcrumb_json}
+ = yield :header_content
diff --git a/app/views/layouts/nav/sidebar/_explore.html.haml b/app/views/layouts/nav/sidebar/_explore.html.haml
new file mode 100644
index 00000000000..ccbcb434af1
--- /dev/null
+++ b/app/views/layouts/nav/sidebar/_explore.html.haml
@@ -0,0 +1 @@
+= render partial: 'shared/nav/sidebar', object: Sidebars::Explore::Panel.new(Sidebars::Context.new(current_user: current_user, container: nil))
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index c2b50bc0e52..fd0e47b543f 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -1 +1,2 @@
-= render partial: 'shared/nav/sidebar', object: Sidebars::Groups::Panel.new(group_sidebar_context(@group, current_user))
+- group = @parent_group || @group
+= render partial: 'shared/nav/sidebar', object: Sidebars::Groups::Panel.new(group_sidebar_context(group, current_user))
diff --git a/app/views/layouts/nav/sidebar/_profile.html.haml b/app/views/layouts/nav/sidebar/_profile.html.haml
index 087eca3ba35..d53316442f8 100644
--- a/app/views/layouts/nav/sidebar/_profile.html.haml
+++ b/app/views/layouts/nav/sidebar/_profile.html.haml
@@ -1,169 +1 @@
-%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **sidebar_tracking_attributes_by_object(current_user), 'aria-label': _('User settings') }
- .nav-sidebar-inner-scroll
- .context-header
- = link_to profile_path, title: _('Profile Settings'), class: 'has-tooltip', data: { container: 'body', placement: 'right' } do
- = render Pajamas::AvatarComponent.new(current_user, size: 32, alt: current_user.name, class: 'gl-mr-3 js-sidebar-user-avatar', avatar_options: { data: { testid: 'sidebar-user-avatar' } })
- %span.sidebar-context-title= _('User Settings')
- %ul.sidebar-top-level-items
- = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
- = link_to profile_path do
- .nav-icon-container
- = sprite_icon('profile')
- %span.nav-item-name
- = _('Profile')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(path: 'profiles#show', html_options: { class: "fly-out-top-item" }) do
- = link_to profile_path do
- %strong.fly-out-top-item-name
- = _('Profile')
- = nav_link(controller: [:accounts, :two_factor_auths]) do
- = link_to profile_account_path, data: { qa_selector: 'profile_account_link' } do
- .nav-icon-container
- = sprite_icon('account')
- %span.nav-item-name
- = _('Account')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: [:accounts, :two_factor_auths], html_options: { class: "fly-out-top-item" }) do
- = link_to profile_account_path do
- %strong.fly-out-top-item-name
- = _('Account')
-
- = render_if_exists 'layouts/nav/sidebar/profile_billing_link'
- = nav_link(controller: 'oauth/applications') do
- = link_to applications_profile_path do
- .nav-icon-container
- = sprite_icon('applications')
- %span.nav-item-name
- = _('Applications')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: 'oauth/applications', html_options: { class: "fly-out-top-item" }) do
- = link_to applications_profile_path do
- %strong.fly-out-top-item-name
- = _('Applications')
- = nav_link(controller: :chat_names) do
- = link_to profile_chat_names_path do
- .nav-icon-container
- = sprite_icon('comment')
- %span.nav-item-name
- = _('Chat')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :chat_names, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_chat_names_path do
- %strong.fly-out-top-item-name
- = _('Chat')
- - unless Gitlab::CurrentSettings.personal_access_tokens_disabled?
- = nav_link(controller: :personal_access_tokens) do
- = link_to profile_personal_access_tokens_path do
- .nav-icon-container
- = sprite_icon('token')
- %span.nav-item-name
- = _('Access Tokens')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :personal_access_tokens, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_personal_access_tokens_path do
- %strong.fly-out-top-item-name
- = _('Access Tokens')
- = nav_link(controller: :emails) do
- = link_to profile_emails_path, data: { qa_selector: 'profile_emails_link' } do
- .nav-icon-container
- = sprite_icon('mail')
- %span.nav-item-name
- = _('Emails')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :emails, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_emails_path do
- %strong.fly-out-top-item-name
- = _('Emails')
- - if current_user.allow_password_authentication?
- = nav_link(controller: :passwords) do
- = link_to edit_profile_password_path , data: { qa_selector: 'profile_password_link' } do
- .nav-icon-container
- = sprite_icon('lock')
- %span.nav-item-name
- = _('Password')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :passwords, html_options: { class: "fly-out-top-item" }) do
- = link_to edit_profile_password_path do
- %strong.fly-out-top-item-name
- = _('Password')
- = nav_link(controller: :notifications) do
- = link_to profile_notifications_path do
- .nav-icon-container
- = sprite_icon('notifications')
- %span.nav-item-name
- = _('Notifications')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :notifications, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_notifications_path do
- %strong.fly-out-top-item-name
- = _('Notifications')
- = nav_link(controller: :keys) do
- = link_to profile_keys_path do
- .nav-icon-container
- = sprite_icon('key')
- %span.nav-item-name
- = _('SSH Keys')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :keys, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_keys_path do
- %strong.fly-out-top-item-name
- = _('SSH Keys')
- = nav_link(controller: :gpg_keys) do
- = link_to profile_gpg_keys_path do
- .nav-icon-container
- = sprite_icon('key')
- %span.nav-item-name
- = _('GPG Keys')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :gpg_keys, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_gpg_keys_path do
- %strong.fly-out-top-item-name
- = _('GPG Keys')
- = nav_link(controller: :preferences) do
- = link_to profile_preferences_path do
- .nav-icon-container
- = sprite_icon('preferences')
- %span.nav-item-name
- = _('Preferences')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :preferences, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_preferences_path do
- %strong.fly-out-top-item-name
- = _('Preferences')
- - if saved_replies_enabled?
- = nav_link(controller: :saved_replies) do
- = link_to profile_saved_replies_path do
- .nav-icon-container
- = sprite_icon('symlink')
- %span.nav-item-name
- = _('Saved Replies')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :saved_replies, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_saved_replies_path do
- %strong.fly-out-top-item-name
- = _('Saved Replies')
- = nav_link(controller: :active_sessions) do
- = link_to profile_active_sessions_path do
- .nav-icon-container
- = sprite_icon('monitor-lines')
- %span.nav-item-name
- = _('Active Sessions')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :active_sessions, html_options: { class: "fly-out-top-item" }) do
- = link_to profile_active_sessions_path do
- %strong.fly-out-top-item-name
- = _('Active Sessions')
- = nav_link(path: 'profiles#audit_log') do
- = link_to audit_log_profile_path do
- .nav-icon-container
- = sprite_icon('log')
- %span.nav-item-name
- = _('Authentication log')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(path: 'profiles#audit_log', html_options: { class: "fly-out-top-item" }) do
- = link_to audit_log_profile_path do
- %strong.fly-out-top-item-name
- = _('Authentication Log')
- = render_if_exists 'layouts/nav/sidebar/profile_usage_quotas_link'
-
- = render 'shared/sidebar_toggle_button'
+= render partial: 'shared/nav/sidebar', object: Sidebars::UserSettings::Panel.new(Sidebars::Context.new(current_user: current_user, container: current_user))
diff --git a/app/views/layouts/nav/sidebar/_user_profile.html.haml b/app/views/layouts/nav/sidebar/_user_profile.html.haml
new file mode 100644
index 00000000000..b24334f48c4
--- /dev/null
+++ b/app/views/layouts/nav/sidebar/_user_profile.html.haml
@@ -0,0 +1 @@
+= render partial: 'shared/nav/sidebar', object: Sidebars::UserProfile::Panel.new(Sidebars::Context.new(current_user: current_user, container: @user))
diff --git a/app/views/layouts/nav/sidebar/_your_work.html.haml b/app/views/layouts/nav/sidebar/_your_work.html.haml
index 0eba5045ab1..0da66c2e14e 100644
--- a/app/views/layouts/nav/sidebar/_your_work.html.haml
+++ b/app/views/layouts/nav/sidebar/_your_work.html.haml
@@ -1 +1 @@
-= render partial: 'shared/nav/sidebar', object: Sidebars::YourWork::Panel.new(Sidebars::Context.new(current_user: current_user, container: nil))
+= render partial: 'shared/nav/sidebar', object: Sidebars::YourWork::Panel.new(your_work_sidebar_context(current_user))
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 6ad6696b313..09fa8575106 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -18,6 +18,9 @@
:plain
window.uploads_path = "#{project_uploads_path(project)}";
+- content_for :before_content do
+ = render 'projects/invite_members_modal', project: @project
+
= dispensable_render_if_exists "shared/web_hooks/web_hook_disabled_alert"
= dispensable_render_if_exists "projects/free_user_cap_alert", project: @project
diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml
index 95a204a3319..e396f38499a 100644
--- a/app/views/layouts/snippets.html.haml
+++ b/app/views/layouts/snippets.html.haml
@@ -1,9 +1,10 @@
- page_title _("Snippets")
-- header_title _("Snippets"), snippets_path
+- header_title _("Snippets"), dashboard_snippets_path
- snippets_upload_path = snippets_upload_path(@snippet, current_user)
+- @left_sidebar = true
+
- if current_user
- - @left_sidebar = true
- nav "your_work"
- content_for :page_specific_javascripts do
diff --git a/app/views/notify/_issuable_csv_export.html.haml b/app/views/notify/_issuable_csv_export.html.haml
index 3b1fe90eaee..f7c6168ecb6 100644
--- a/app/views/notify/_issuable_csv_export.html.haml
+++ b/app/views/notify/_issuable_csv_export.html.haml
@@ -1,6 +1,8 @@
+- type = type.to_s.humanize.downcase
+
%p{ style: 'font-size:18px; text-align:center; line-height:30px;' }
- project_link = link_to(@project.full_name, project_url(@project), style: "color:#3777b0; text-decoration:none; display:block;")
- = _('Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment.').html_safe % { count: pluralize(@written_count, type.to_s.titleize.downcase), project_link: project_link }
+ = _('Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment.').html_safe % { count: pluralize(@written_count, type.titleize.downcase), project_link: project_link }
- if @truncated
%p
- = _('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}.') % { written_count: @written_count, count: @count, issuables: type.to_s.pluralize, size_limit: @size_limit }
+ = _('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}.') % { written_count: @written_count, count: @count, issuables: type.pluralize, size_limit: @size_limit }
diff --git a/app/views/notify/_issuable_csv_export.text.erb b/app/views/notify/_issuable_csv_export.text.erb
new file mode 100644
index 00000000000..a6e908803f5
--- /dev/null
+++ b/app/views/notify/_issuable_csv_export.text.erb
@@ -0,0 +1,7 @@
+<% type = type.to_s.humanize.downcase %>
+
+<%= _('Your CSV export of %{exported_objects} from project %{project_name} (%{project_url}) has been added to this email as an attachment.') % { exported_objects: pluralize(@written_count, type), project_name: @project.full_name, project_url: project_url(@project) } %>
+
+<% if @truncated %>
+ <%= _('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}.') % { written_count: @written_count, total_count: @count, size_limit: @size_limit, object_type: type.pluralize } %>
+<% end %>
diff --git a/app/views/notify/export_work_items_csv_email.html.haml b/app/views/notify/export_work_items_csv_email.html.haml
new file mode 100644
index 00000000000..db842262049
--- /dev/null
+++ b/app/views/notify/export_work_items_csv_email.html.haml
@@ -0,0 +1 @@
+= render 'issuable_csv_export', type: :work_item
diff --git a/app/views/notify/export_work_items_csv_email.text.erb b/app/views/notify/export_work_items_csv_email.text.erb
new file mode 100644
index 00000000000..ec4aaa38886
--- /dev/null
+++ b/app/views/notify/export_work_items_csv_email.text.erb
@@ -0,0 +1 @@
+<%= render 'issuable_csv_export', type: :work_item %>
diff --git a/app/views/notify/import_work_items_csv_email.html.haml b/app/views/notify/import_work_items_csv_email.html.haml
new file mode 100644
index 00000000000..d4326d6bdf9
--- /dev/null
+++ b/app/views/notify/import_work_items_csv_email.html.haml
@@ -0,0 +1,49 @@
+- info_style = 'font-size:16px; text-align:center; line-height:24px;'
+- error_style = 'font-size:13px; text-align:center; line-height:16px; color:#dd2b0e;'
+
+%p{ style: info_style }
+ - project_link = link_to(@project.full_name, project_url(@project), style: "color:#3777b0; text-decoration:none;")
+ = s_('Notify|Here are the results for your CSV import for %{project_link}.').html_safe % { project_link: project_link }
+
+- success_lines = @results[:success]
+%p{ style: info_style }
+ - if success_lines > 0
+ - work_items = n_('%d work item', '%d work items', success_lines) % success_lines
+ = s_('Notify|%{work_items} successfully imported.') % { work_items: work_items }
+ - else
+ = s_('Notify|No work items have been imported.')
+
+ - if @results[:parse_error]
+ %p{ style: info_style }
+ = s_('Notify|Error parsing CSV file. Please make sure it has the correct format: a delimited text file that uses a comma to separate values.')
+
+- type_errors = @results[:type_errors]
+- if type_errors
+ %p{ style: info_style }
+ = s_('Notify|Some values in the "type" column could not be matched with supported work item types:')
+
+ - blank_lines = type_errors[:blank]
+ - missing_lines = type_errors[:missing]
+ - disallowed_lines = type_errors[:disallowed]
+
+ - if blank_lines.present?
+ %p{ style: error_style }
+ = s_('Notify|%{singular_or_plural_line} %{error_lines}: Work item type is empty.') % { singular_or_plural_line: n_('Line', 'Lines', blank_lines.size), error_lines: blank_lines.join(', ') }
+
+ - if missing_lines.present?
+ %p{ style: error_style }
+ = s_('Notify|%{singular_or_plural_line} %{error_lines}: Work item type cannot be found or is not supported.') % { singular_or_plural_line: n_('Line', 'Lines', missing_lines.size), error_lines: missing_lines.join(', ') }
+
+ - if disallowed_lines.present?
+ %p{ style: error_style }
+ = s_('Notify|%{singular_or_plural_line} %{error_lines}: Work item type is not available. Please check your license and permissions.') % { singular_or_plural_line: n_('Line', 'Lines', disallowed_lines.size), error_lines: disallowed_lines.join(', ') }
+
+- error_lines = @results[:error_lines]
+- if error_lines.present?
+ %p{ style: error_style }
+ = s_('Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check that these lines have the following fields: %{required_headers}.') % { singular_or_plural_line: n_('line', 'lines', error_lines.size), required_headers: WorkItems::ImportCsvService.required_headers.join(', '),
+ error_lines: error_lines.join(', ') }
+
+- if error_lines.present? || type_errors
+ %p{ style: info_style }
+ = s_('Notify|Please fix the lines with errors and try the CSV import again.')
diff --git a/app/views/notify/import_work_items_csv_email.text.erb b/app/views/notify/import_work_items_csv_email.text.erb
new file mode 100644
index 00000000000..059dbc95cbc
--- /dev/null
+++ b/app/views/notify/import_work_items_csv_email.text.erb
@@ -0,0 +1,48 @@
+<%= s_('Notify|Here are the results for your CSV import for %{project_name} (%{project_link}).') % { project_name: @project.full_name, project_link: project_url(@project) } %>
+
+<% success_lines = @results[:success] %>
+<% if success_lines > 0 %>
+ <% work_items = n_('%d work item', '%d work items', success_lines) % success_lines %>
+ <%= s_('Notify|%{work_items} successfully imported.') % { work_items: work_items } %>
+<% else %>
+ <%= s_('Notify|No work items have been imported.') %>
+
+ <% if @results[:parse_error] %>
+ <%= s_('Notify|Error parsing CSV file. Please make sure it has the correct format: a delimited text file that uses a comma to separate values.') %>
+ <% end %>
+<% end %>
+
+<% type_errors = @results[:type_errors] %>
+<%
+ if type_errors
+ blank_lines = type_errors[:blank]
+ missing_lines = type_errors[:missing]
+ disallowed_lines = type_errors[:disallowed]
+%>
+ <%= s_('Notify|Some values in the "type" column could not be matched with supported work item types:') %>
+
+ <% if blank_lines.present? %>
+ <%= s_('Notify|%{singular_or_plural_line} %{error_lines}: Work item type is empty.') % { singular_or_plural_line: n_('Line', 'Lines', blank_lines.size), error_lines: blank_lines.join(', ') } %>
+ <% end %>
+
+ <% if missing_lines.present? %>
+ <%= s_('Notify|%{singular_or_plural_line} %{error_lines}: Work item type cannot be found or is not supported.') % { singular_or_plural_line: n_('Line', 'Lines', missing_lines.size), error_lines: missing_lines.join(', ') } %>
+ <% end %>
+
+ <% if disallowed_lines.present? %>
+ <%= s_('Notify|%{singular_or_plural_line} %{error_lines}: Work item type is not available. Please check your license and permissions.') % { singular_or_plural_line: n_('Line', 'Lines', disallowed_lines.size), error_lines: disallowed_lines.join(', ') } %>
+ <% end %>
+<% end %>
+
+<%
+ error_lines = @results[:error_lines]
+ if error_lines.present?
+%>
+ <%= s_('Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check that these lines have the following fields: %{required_headers}.') % { singular_or_plural_line: n_('line', 'lines', error_lines.size), required_headers: WorkItems::ImportCsvService.required_headers.join(', '),
+ error_lines: error_lines.join(', ') } %>
+<% end %>
+
+<% if error_lines.present? || type_errors %>
+ <%= s_('Notify|Please fix the lines with errors and try the CSV import again.') %>
+<% end %>
+
diff --git a/app/views/notify/issues_csv_email.text.erb b/app/views/notify/issues_csv_email.text.erb
index cf2910c4014..5b6c151e4ce 100644
--- a/app/views/notify/issues_csv_email.text.erb
+++ b/app/views/notify/issues_csv_email.text.erb
@@ -1,5 +1 @@
-<%= _('Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment.') % { written_count: pluralize(@written_count, 'issue'), project_name: @project.full_name, project_url: project_url(@project) } %>
-
-<% if @truncated %>
- <%= _('This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues.') % { written_count: @written_count, issues_count: @issues_count, size_limit: @size_limit } %>
-<% end %>
+<%= render 'issuable_csv_export', type: :issue %>
diff --git a/app/views/notify/merge_request_status_email.text.haml b/app/views/notify/merge_request_status_email.text.haml
index 61c9b130da8..7d10bc77126 100644
--- a/app/views/notify/merge_request_status_email.text.haml
+++ b/app/views/notify/merge_request_status_email.text.haml
@@ -1,4 +1,4 @@
-= sprintf(s_('Notify|Merge request %{merge_request} was %{mr_status}'), { merge_request: @merge_request.to_reference, mr_status: sanitize_name(@updated_by.name) })
+= sprintf(s_('Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}'), { merge_request: @merge_request.to_reference, mr_status: @mr_status, updated_by: sanitize_name(@updated_by.name) })
= sprintf(s_('Notify|Merge request URL: %{merge_request_url}'), { merge_request_url: project_merge_request_url(@merge_request.target_project, @merge_request) })
diff --git a/app/views/notify/merge_requests_csv_email.text.erb b/app/views/notify/merge_requests_csv_email.text.erb
index 78d11dde69f..c5dec164a4d 100644
--- a/app/views/notify/merge_requests_csv_email.text.erb
+++ b/app/views/notify/merge_requests_csv_email.text.erb
@@ -1,5 +1 @@
-<%= _('Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment.') % { written_count: pluralize(@written_count, 'merge request'), project_name: @project.full_name, project_url: project_url(@project) } %>
-
-<% if @truncated %>
- <%= _('This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests.') % { written_count: @written_count, merge_requests_count: @merge_requests_count, size_limit: @size_limit} %>
-<% end %>
+<%= render 'issuable_csv_export', type: :merge_request %>
diff --git a/app/views/notify/new_review_email.text.erb b/app/views/notify/new_review_email.text.erb
index 7bf878aefd0..69cb33b05df 100644
--- a/app/views/notify/new_review_email.text.erb
+++ b/app/views/notify/new_review_email.text.erb
@@ -4,7 +4,6 @@
--
<% @notes.each_with_index do |note, index| %>
- <!-- Get preloaded note discussion-->
<% discussion = @discussions[note.discussion_id] if note.part_of_discussion?%>
<% target_url = project_merge_request_url(@project, @merge_request, anchor: "note_#{note.id}") %>
<%= render 'note_email', note: note, diff_limit: 3, target_url: target_url, discussion: discussion, author: @author %>
diff --git a/app/views/notify/two_factor_otp_attempt_failed_email.html.haml b/app/views/notify/two_factor_otp_attempt_failed_email.html.haml
index 83f028af500..968d84f700d 100644
--- a/app/views/notify/two_factor_otp_attempt_failed_email.html.haml
+++ b/app/views/notify/two_factor_otp_attempt_failed_email.html.haml
@@ -9,7 +9,7 @@
%tr
%td{ style: "#{default_font}vertical-align:middle;color:#ffffff;text-align:center;" }
%span
- = _("We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code") % { host: Gitlab.config.gitlab.host }
+ = _("GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code") % { host: Gitlab.config.gitlab.host }
%tr.spacer
%td{ style: spacer_style }
&nbsp;
@@ -43,7 +43,7 @@
%tr{ style: 'width:100%;' }
%td{ style: "#{default_style}text-align:center;" }
- password_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_url('user/profile/user_passwords', anchor: 'change-your-password') }
- = _('If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email.')
+ = _('If you recently tried to sign in, but mistakenly entered an incorrect verification code, you can ignore this email.')
- if password_authentication_enabled_for_web?
%p
diff --git a/app/views/notify/two_factor_otp_attempt_failed_email.text.haml b/app/views/notify/two_factor_otp_attempt_failed_email.text.haml
index 8718ab034ff..9760dd3d985 100644
--- a/app/views/notify/two_factor_otp_attempt_failed_email.text.haml
+++ b/app/views/notify/two_factor_otp_attempt_failed_email.text.haml
@@ -1,7 +1,7 @@
= _('Hi %{username}!') % { username: sanitize_name(@user.name) }
-= _('We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}') % { host: Gitlab.config.gitlab.host, ip: @ip, time: @time }
+= _('GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code from the following IP address: %{ip}, at %{time}') % { host: Gitlab.config.gitlab.host, ip: @ip, time: @time }
-= _('If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email.')
+= _('If you recently tried to sign in, but mistakenly entered an incorrect verification code, you can ignore this email.')
= _('If you did not recently try to sign in, you should immediately change your password: %{password_link}.') % { password_link: help_page_url('user/profile/user_passwords', anchor: 'change-your-password') }
= _('Make sure you choose a strong, unique password.')
diff --git a/app/views/notify/unknown_sign_in_email.html.haml b/app/views/notify/unknown_sign_in_email.html.haml
index f8a0ae1352c..e252af78060 100644
--- a/app/views/notify/unknown_sign_in_email.html.haml
+++ b/app/views/notify/unknown_sign_in_email.html.haml
@@ -24,6 +24,11 @@
= Gitlab.config.gitlab.host
%tr
%td{ style: "#{default_style}border-top:1px solid #ededed;" }
+ = _('User')
+ %td{ style: "#{default_style}color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" }
+ #{sanitize_name(@user.name)} (#{@user.username})
+ %tr
+ %td{ style: "#{default_style}border-top:1px solid #ededed;" }
= _('IP Address')
%td{ style: "#{default_style}color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" }
%span.muted{ style: "color:#333333;text-decoration:none;" }
diff --git a/app/views/notify/unknown_sign_in_email.text.haml b/app/views/notify/unknown_sign_in_email.text.haml
index f3e318f0d15..fbe35c502da 100644
--- a/app/views/notify/unknown_sign_in_email.text.haml
+++ b/app/views/notify/unknown_sign_in_email.text.haml
@@ -1,4 +1,4 @@
-= _('Hi %{username}!') % { username: sanitize_name(@user.name) }
+= _('Hi %{user_name} (%{user_username})!') % { user_name: sanitize_name(@user.name), user_username: @user.username }
= _('A sign-in to your account has been made from the following IP address: %{ip}') % { ip: @ip }
diff --git a/app/views/profiles/chat_names/_chat_name.html.haml b/app/views/profiles/chat_names/_chat_name.html.haml
index ce2fc2098c5..afc3894c23b 100644
--- a/app/views/profiles/chat_names/_chat_name.html.haml
+++ b/app/views/profiles/chat_names/_chat_name.html.haml
@@ -1,21 +1,5 @@
-- integration = chat_name.integration
-- project = integration&.project
%tr
%td
- %strong
- - if project.present? && can?(current_user, :read_project, project)
- = link_to project.full_name, project_path(project)
- - else
- .light= _('Not applicable.')
- %td
- %strong
- - if integration.present? && can?(current_user, :admin_project, project)
- = link_to integration.title, edit_project_settings_integration_path(project, integration)
- - elsif integration.present?
- = integration.title
- - else
- .light= _('Not applicable.')
- %td
= chat_name.team_domain
%td
= chat_name.chat_name
diff --git a/app/views/profiles/chat_names/index.html.haml b/app/views/profiles/chat_names/index.html.haml
index 41bd81d0250..6de5f183981 100644
--- a/app/views/profiles/chat_names/index.html.haml
+++ b/app/views/profiles/chat_names/index.html.haml
@@ -1,7 +1,8 @@
- page_title _('Chat')
- @content_class = "limit-container-width" unless fluid_layout
+- @hide_search_settings = true
-.row.gl-mt-3.js-search-settings-section
+.row.gl-mt-5.js-search-settings-section
.col-lg-4.profile-settings-sidebar
%h4.gl-mt-0
= page_title
@@ -14,11 +15,9 @@
- if @chat_names.present?
.table-responsive
- %table.table.chat-names
+ %table.table
%thead
%tr
- %th= _('Project')
- %th= _('Service')
%th= _('Team domain')
%th= _('Nickname')
%th= _('Last used')
diff --git a/app/views/profiles/chat_names/new.html.haml b/app/views/profiles/chat_names/new.html.haml
index 303b8b10027..8ff2e6f34a0 100644
--- a/app/views/profiles/chat_names/new.html.haml
+++ b/app/views/profiles/chat_names/new.html.haml
@@ -1,14 +1,28 @@
-%h1.page-title.gl-font-size-h-display
- = _("Authorization required")
-%main{ :role => "main" }
- %p.h4
- = html_escape(_("Authorize %{user} to use your account?")) % { user: tag.strong(@chat_name_params[:chat_name]) }
+- @hide_search_settings = true
- %hr
- .actions
- = form_tag profile_chat_names_path, method: :post do
- = hidden_field_tag :token, @chat_name_token.token
- = submit_tag _("Authorize"), class: "gl-button btn btn-confirm wide float-left"
- = form_tag deny_profile_chat_names_path, method: :delete do
- = hidden_field_tag :token, @chat_name_token.token
- = submit_tag _("Deny"), class: "gl-button btn btn-danger gl-ml-3"
+%main{ role: 'main' }
+ .gl-max-w-80.gl-mx-auto.gl-mt-6
+ = render Pajamas::CardComponent.new do |c|
+ - c.header do
+ %h4.gl-m-0= s_('SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?').html_safe % { user: @chat_name_params[:chat_name] }
+ - c.body do
+ %p
+ = s_('SlackIntegration|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc.')
+ %p
+ = _('This application will be able to:')
+ %ul
+ %li= s_('SlackIntegration|Create and read issue data and comments.')
+ %li= s_('SlackIntegration|Perform deployments.')
+ %li= s_('SlackIntegration|Run ChatOps jobs.')
+ %p.gl-mb-0
+ = s_("SlackIntegration|You don't have to reauthorize this application if the permission scope changes in future releases.")
+ - c.footer do
+ .gl-display-flex
+ = form_tag profile_chat_names_path, method: :post do
+ = hidden_field_tag :token, @chat_name_token.token
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :danger) do
+ = _('Authorize')
+ = form_tag deny_profile_chat_names_path, method: :delete do
+ = hidden_field_tag :token, @chat_name_token.token
+ = render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-ml-3' }) do
+ = _('Deny')
diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml
index ec48a611377..d52b16814c0 100644
--- a/app/views/profiles/gpg_keys/_key.html.haml
+++ b/app/views/profiles/gpg_keys/_key.html.haml
@@ -18,7 +18,7 @@
%code= subkey.fingerprint
.float-right
%span.key-created-at
- = s_('Profiles|Created %{time_ago}'.html_safe) % { time_ago: time_ago_with_tooltip(key.created_at) }
+ = html_escape(s_('Profiles|Created %{time_ago}')) % { time_ago: time_ago_with_tooltip(key.created_at) }
= link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "gl-button btn btn-icon btn-danger gl-ml-3" do
%span.sr-only= _('Remove')
= sprite_icon('remove')
diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml
index 825fb98782a..288007ec806 100644
--- a/app/views/profiles/keys/_key.html.haml
+++ b/app/views/profiles/keys/_key.html.haml
@@ -35,7 +35,7 @@
= ssh_key_usage_types.invert[key.usage_type]
.gl-display-flex.gl-float-right
- if key.can_delete?
- - if key.signing? && !is_admin && Feature.enabled?(:revoke_ssh_signatures)
+ - if key.signing? && !is_admin
= render Pajamas::ButtonComponent.new(size: :small, button_options: { class: 'js-confirm-modal-button', data: ssh_key_revoke_modal_data(key, revoke_profile_key_path(key)) }) do
= _('Revoke')
.gl-pl-3
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index b10d05efc4f..5f74a4c4427 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -17,6 +17,9 @@
= s_('Preferences|Color theme')
%p
= s_('Preferences|Customize the color of GitLab.')
+ - if show_super_sidebar?
+ %p
+ = s_('Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab\'s appearance.')
.col-lg-8.application-theme
.row
- Gitlab::Themes.each do |theme|
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 5ffffb80d97..659b218bdef 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -53,7 +53,9 @@
= status_form.hidden_field :emoji, data: { js_name: 'emoji' }
= status_form.hidden_field :message, data: { js_name: 'message' }
= status_form.hidden_field :availability, data: { js_name: 'availability' }
- = status_form.hidden_field :clear_status_after, value: @user.status&.clear_status_at&.to_s(:iso8601), data: { js_name: 'clearStatusAfter' }
+ = status_form.hidden_field :clear_status_after,
+ value: user_clear_status_at(@user),
+ data: { js_name: 'clearStatusAfter' }
.col-lg-12
%hr
.row.user-time-preferences.js-search-settings-section
@@ -106,9 +108,18 @@
.form-group.gl-form-group
- external_accounts_help_url = help_page_path('user/profile/index', anchor: 'add-external-accounts-to-your-user-profile-page')
- external_accounts_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: external_accounts_help_url }
- - external_accounts_docs_link = s_('Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}').html_safe % { min: '17', max: '20', external_accounts_link_start: external_accounts_link_start, external_accounts_link_end: '</a>'.html_safe }
+ - external_accounts_docs_link = s_('Profiles|Your Discord user ID. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}').html_safe % { external_accounts_link_start: external_accounts_link_start, external_accounts_link_end: '</a>'.html_safe }
+ - min_discord_length = 17
+ - max_discord_length = 20
= f.label :discord
- = f.text_field :discord, class: 'gl-form-input form-control gl-md-form-input-lg', placeholder: s_("Profiles|User ID")
+ = f.text_field :discord,
+ class: 'gl-form-input form-control gl-md-form-input-lg js-validate-length',
+ placeholder: s_("Profiles|User ID"),
+ data: { min_length: min_discord_length,
+ min_length_message: s_('Profiles|Discord ID is too short (minimum is %{min_length} characters).') % { min_length: min_discord_length },
+ max_length: max_discord_length,
+ max_length_message: s_('Profiles|Discord ID is too long (maximum is %{max_length} characters).') % { max_length: max_discord_length },
+ allow_empty: true}
%small.form-text.text-gl-muted
= external_accounts_docs_link
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index 3add3af3c65..61fe6ba8e47 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -8,24 +8,13 @@
.row.gl-mt-3
.col-lg-4
%h4.gl-mt-0
- = _('Register Two-Factor Authenticator')
+ = _('Register a one-time password authenticator')
%p
= _('Use a one-time password authenticator on your mobile device or computer to enable two-factor authentication (2FA).')
.col-lg-8
- if current_user.two_factor_otp_enabled?
%p
= _("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.")
- %p
- = _('If you lose your recovery codes you can generate new ones, invalidating all previous codes.')
- - if @error
- = render Pajamas::AlertComponent.new(title: @error[:message],
- variant: :danger,
- alert_options: { class: 'gl-mb-3' },
- dismissible: false) do |c|
- = c.body do
- = link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
- .js-manage-two-factor-form{ data: { webauthn_enabled: webauthn_enabled, current_password_required: current_password_required?.to_s, profile_two_factor_auth_path: profile_two_factor_auth_path, profile_two_factor_auth_method: 'delete', codes_profile_two_factor_auth_path: codes_profile_two_factor_auth_path, codes_profile_two_factor_auth_method: 'post' } }
-
- else
%p
- register_2fa_token = _('We recommend using cloud-based authenticator applications that can restore access if you lose your hardware device.')
@@ -36,8 +25,8 @@
.gl-p-2.gl-mb-3{ style: 'background: #fff' }
= raw @qr_code
.col-md-8
- .gl-card
- .gl-card-body
+ = render Pajamas::CardComponent.new do |c|
+ - c.body do
%p.gl-mt-0.gl-mb-3.gl-font-weight-bold
= _("Can't scan the code?")
%p.gl-mt-0.gl-mb-3
@@ -58,15 +47,15 @@
= c.body do
= link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
- .form-group
- = label_tag :pin_code, _('Pin code'), class: "label-bold"
- = text_field_tag :pin_code, nil, class: "form-control gl-form-input", required: true, data: { qa_selector: 'pin_code_field' }
- if current_password_required?
.form-group
= label_tag :current_password, _('Current password'), class: 'label-bold'
= password_field_tag :current_password, nil, autocomplete: 'current-password', required: true, class: 'form-control gl-form-input', data: { qa_selector: 'current_password_field' }
%p.form-text.text-muted
= _('Your current password is required to register a two-factor authenticator app.')
+ .form-group
+ = label_tag :pin_code, _('Enter verification code'), class: "label-bold"
+ = text_field_tag :pin_code, nil, autocomplete: 'off', inputmode: 'numeric', class: "form-control gl-form-input", required: true, data: { qa_selector: 'pin_code_field' }
.gl-mt-3
= submit_tag _('Register with two-factor app'), class: 'gl-button btn btn-confirm', data: { qa_selector: 'register_2fa_app_button' }
@@ -75,37 +64,27 @@
.row.gl-mt-3
.col-lg-4
%h4.gl-mt-0
- - if webauthn_enabled
- = _('Register WebAuthn Device')
- - else
- = _('Register Universal Two-Factor (U2F) Device')
+ = _('Register a WebAuthn device')
%p
- = _('Set up a hardware device as a second factor to sign in.')
+ = _('Set up a hardware device to enable two-factor authentication (2FA).')
%p
- - if webauthn_enabled
- = _("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.")
+ - if webauthn_enabled && Feature.enabled?(:webauthn_without_totp)
+ = _("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.")
- else
- = _("Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser.")
+ = _("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.")
.col-lg-8
- - registration = webauthn_enabled ? @webauthn_registration : @u2f_registration
- - if registration.errors.present?
- = form_errors(registration)
- - if webauthn_enabled
- = render "authentication/register", target_path: create_webauthn_profile_two_factor_auth_path
- - else
- = render "authentication/register", target_path: create_u2f_profile_two_factor_auth_path
+ - if @webauthn_registration.errors.present?
+ = form_errors(@webauthn_registration)
+ = render "authentication/register", target_path: create_webauthn_profile_two_factor_auth_path
%hr
%h5
- - if webauthn_enabled
- = _('WebAuthn Devices (%{length})') % { length: @registrations.length }
- - else
- = _('U2F Devices (%{length})') % { length: @registrations.length }
+ = _('WebAuthn Devices (%{length})') % { length: @registrations.length }
- if @registrations.present?
.table-responsive
- %table.table.table-bordered.u2f-registrations
+ %table.table
%colgroup
%col{ width: "50%" }
%col{ width: "30%" }
@@ -134,7 +113,28 @@
- else
.settings-message.text-center
- - if webauthn_enabled
- = _("You don't have any WebAuthn devices registered yet.")
- - else
- = _("You don't have any U2F devices registered yet.")
+ = _("You don't have any WebAuthn devices registered yet.")
+
+ %hr
+
+ .row.gl-mt-3
+ .col-lg-4
+ %h4.gl-mt-0
+ = _('Disable two-factor authentication')
+ %p
+ = _('Use this section to disable your one-time password authenticator and WebAuthn devices. You can also generate new recovery codes.')
+ .col-lg-8
+ - if current_user.two_factor_enabled?
+ %p
+ = _('If you lose your recovery codes you can generate new ones, invalidating all previous codes.')
+ - if @error
+ = render Pajamas::AlertComponent.new(title: @error[:message],
+ variant: :danger,
+ alert_options: { class: 'gl-mb-3' },
+ dismissible: false) do |c|
+ = c.body do
+ = link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
+ .js-manage-two-factor-form{ data: { webauthn_enabled: webauthn_enabled, current_password_required: current_password_required?.to_s, profile_two_factor_auth_path: profile_two_factor_auth_path, profile_two_factor_auth_method: 'delete', codes_profile_two_factor_auth_path: codes_profile_two_factor_auth_path, codes_profile_two_factor_auth_method: 'post' } }
+ - else
+ %p
+ = _("Register a one-time password authenticator or a WebAuthn device first.")
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
index e2d1a50ae5e..6ac084b7749 100644
--- a/app/views/projects/_files.html.haml
+++ b/app/views/projects/_files.html.haml
@@ -8,7 +8,7 @@
- add_page_startup_api_call project_blob_path(@project, tree_join(@ref, readme_path), viewer: "rich", format: "json")
#tree-holder.tree-holder.clearfix.js-per-page{ data: { blame_per_page: Projects::BlameService::PER_PAGE } }
- .info-well.gl-display-none.gl-sm-display-flex.project-last-commit.gl-flex-direction-column
+ .info-well.gl-display-none.gl-sm-display-flex.project-last-commit.gl-flex-direction-column.gl-mt-2
#js-last-commit.gl-m-auto
= gl_loading_icon(size: 'md')
#js-code-owners
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index b9aeed188fa..65fd02b291c 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -3,7 +3,7 @@
- emails_disabled = @project.emails_disabled?
- cache_enabled = Feature.enabled?(:cache_home_panel, @project, type: :development)
-.project-home-panel.js-show-on-project-root.gl-my-5{ class: [("empty-project" if empty_repo)] }
+.project-home-panel.js-show-on-project-root.gl-mt-2.gl-mb-5{ class: [("empty-project" if empty_repo)] }
.gl-display-flex.gl-justify-content-space-between.gl-flex-wrap.gl-sm-flex-direction-column.gl-mb-3.gl-gap-5
.home-panel-title-row.gl-display-flex.gl-align-items-center
%div{ class: 'avatar-container rect-avatar s64 home-panel-avatar gl-flex-shrink-0 gl-w-11 gl-h-11 gl-mr-3! float-none' }
diff --git a/app/views/projects/_invite_members_empty_project.html.haml b/app/views/projects/_invite_members_empty_project.html.haml
index 5bc53339bf0..18d06c7d0bb 100644
--- a/app/views/projects/_invite_members_empty_project.html.haml
+++ b/app/views/projects/_invite_members_empty_project.html.haml
@@ -6,8 +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',
- event: 'click_button',
- label: 'invite_members_empty_project' } }
-
-= render 'projects/invite_members_modal', project: @project
+ trigger_source: 'project-empty-page' } }
diff --git a/app/views/projects/_invite_members_modal.html.haml b/app/views/projects/_invite_members_modal.html.haml
index 53f74a0f270..a1b0bdd6c56 100644
--- a/app/views/projects/_invite_members_modal.html.haml
+++ b/app/views/projects/_invite_members_modal.html.haml
@@ -2,5 +2,5 @@
.js-invite-members-modal{ data: { is_project: 'true',
access_levels: ProjectMember.permissible_access_level_roles(current_user, project).to_json,
- reload_page_on_submit: local_assigns.fetch(:reload_page_on_submit, false).to_s,
+ reload_page_on_submit: current_path?('project_members#index').to_s,
help_link: help_page_url('user/permissions') }.merge(common_invite_modal_dataset(project)).merge(users_filter_data(project.group)) }
diff --git a/app/views/projects/_invite_members_side_nav_link.html.haml b/app/views/projects/_invite_members_side_nav_link.html.haml
deleted file mode 100644
index b96a7608ce2..00000000000
--- a/app/views/projects/_invite_members_side_nav_link.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-.js-invite-members-trigger{ data: { trigger_source: 'project-side-nav',
- icon: 'users',
- display_text: title,
- trigger_element: 'side-nav',
- qa_selector: 'invite_members_sidebar_button' } }
-
-= render partial: 'shared/nav/sidebar_submenu', locals: { sidebar_menu: sidebar_menu }
-= render 'projects/invite_members_modal', project: project
diff --git a/app/views/projects/_invite_members_top_nav_link.html.haml b/app/views/projects/_invite_members_top_nav_link.html.haml
new file mode 100644
index 00000000000..35a8d4d9944
--- /dev/null
+++ b/app/views/projects/_invite_members_top_nav_link.html.haml
@@ -0,0 +1,5 @@
+- data = local_assigns.fetch(:data)
+- data[:display_text] = local_assigns.fetch(:display_text)
+- data[:icon] = local_assigns.fetch(:icon)
+
+.js-invite-members-trigger{ data: data }
diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml
index 53a1abdff33..27211ffb1e5 100644
--- a/app/views/projects/_new_project_fields.html.haml
+++ b/app/views/projects/_new_project_fields.html.haml
@@ -98,4 +98,4 @@
-# this partial is from JiHu, see details in https://jihulab.com/gitlab-cn/gitlab/-/merge_requests/675
= render_if_exists 'shared/other_project_options', f: f, visibility_level: visibility_level, track_label: track_label
= f.submit _('Create project'), class: "js-create-project-button", data: { qa_selector: 'project_create_button', track_label: "#{track_label}", track_action: "click_button", track_property: "create_project", track_value: "" }, pajamas_button: true
-= link_to _('Cancel'), dashboard_projects_path, class: 'btn gl-button btn-default btn-cancel', data: { track_label: "#{track_label}", track_action: "click_button", track_property: "cancel", track_value: "" }
+= link_to _('Cancel'), @parent_group || dashboard_groups_path, class: 'btn gl-button btn-default btn-cancel', data: { track_label: "#{track_label}", track_action: "click_button", track_property: "cancel", track_value: "" }
diff --git a/app/views/projects/_self_monitoring_deprecation_notice.html.haml b/app/views/projects/_self_monitoring_deprecation_notice.html.haml
new file mode 100644
index 00000000000..b9e32356688
--- /dev/null
+++ b/app/views/projects/_self_monitoring_deprecation_notice.html.haml
@@ -0,0 +1,13 @@
+- return unless project.self_monitoring?
+
+= content_for :page_level_alert do
+ .flash-container.flash-container-page.sticky
+ %div{ class: [container_class, 'limit-container-width', 'gl-pt-5!'] }
+ = render Pajamas::AlertComponent.new(title: _('Deprecation notice'),
+ variant: :danger,
+ alert_options: { class: 'gl-mb-3 gl-sticky' }) do |c|
+ = c.body do
+ - deprecation_link = '<a href="%{url}">'.html_safe % { url: help_page_path('update/deprecations', anchor: 'gitlab-self-monitoring-project') }
+ - removal_link = '<a href="%{url}">'.html_safe % { url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/348909' }
+ - opstrace_link = '<a href="%{url}">'.html_safe % { url: 'https://gitlab.com/groups/gitlab-org/-/epics/6976' }
+ = _("Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}.").html_safe % { deprecation: deprecation_link, removal: removal_link, opstrace: opstrace_link, link_end: '</a>'.html_safe }
diff --git a/app/views/projects/airflow/dags/index.html.haml b/app/views/projects/airflow/dags/index.html.haml
deleted file mode 100644
index d631d084db1..00000000000
--- a/app/views/projects/airflow/dags/index.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-- breadcrumb_title s_('Airflow|Airflow DAGs')
-- page_title s_('Airflow|Airflow DAGs')
-
-.page-title-holder
- %h1.page-title.gl-font-size-h-display= s_('Airflow|Airflow DAGs')
-
-#js-show-airflow-dags{ data: {
- dags: @dags.to_json,
- pagination: @pagination.to_json
- }
-}
diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml
index 3359ea5f63b..ccda06c7e4c 100644
--- a/app/views/projects/artifacts/browse.html.haml
+++ b/app/views/projects/artifacts/browse.html.haml
@@ -12,7 +12,7 @@
.nav-block
%ul.breadcrumb.repo-breadcrumb
%li.breadcrumb-item
- = link_to 'Artifacts', browse_project_job_artifacts_path(@project, @build)
+ = link_to _('Artifacts'), browse_project_job_artifacts_path(@project, @build)
- path_breadcrumbs do |title, path|
%li.breadcrumb-item
= link_to truncate(title, length: 40), browse_project_job_artifacts_path(@project, @build, path)
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index 74b85a93c8e..ee7ca9cd351 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -1,6 +1,15 @@
- page_title _("Blame"), @blob.path, @ref
- add_page_specific_style 'page_bundles/tree'
-- dataset = { testid: 'blob-content-holder', qa_selector: 'blame_file_content', per_page: @blame_per_page }
+- if @streaming_enabled && total_extra_pages > 0
+ - content_for :startup_js do
+ = javascript_tag do
+ :plain
+ window.blamePageStream = (() => {
+ const url = new URL("#{@blame_pages_url}");
+ url.searchParams.set('page', 2);
+ return fetch(url).then(response => response.body);
+ })();
+- dataset = { testid: 'blob-content-holder', qa_selector: 'blame_file_content', per_page: @blame_per_page, total_extra_pages: total_extra_pages - 1, pages_url: @blame_pages_url }
#blob-content-holder.tree-holder.js-per-page{ data: dataset }
= render "projects/blob/breadcrumb", blob: @blob, blame: true
@@ -26,11 +35,21 @@
.blame-table-wrapper
= render partial: 'page'
+ - if @streaming_enabled
+ #blame-stream-container.blame-stream-container
+
- if @blame_pagination && @blame_pagination.total_pages > 1
.gl-display-flex.gl-justify-content-center.gl-flex-direction-column.gl-align-items-center.gl-p-3.gl-bg-gray-50.gl-border-t-solid.gl-border-t-1.gl-border-gray-100
- = _('For faster browsing, not all history is shown.')
- = render Pajamas::ButtonComponent.new(href: namespace_project_blame_path(namespace_id: @project.namespace, project_id: @project, id: @id, no_pagination: true), size: :small, button_options: { class: 'gl-mt-3' }) do |c|
- = _('View entire blame')
+ = render Pajamas::ButtonComponent.new(href: @entire_blame_path, size: :small, button_options: { class: 'gl-mt-3' }) do |c|
+ = _('Show full blame')
+
+ - if @streaming_enabled
+ #blame-stream-loading.blame-stream-loading
+ .gradient
+ = gl_loading_icon(size: 'sm')
+ %span.gl-mx-2
+ = _('Loading full blame...')
- if @blame_pagination
= paginate(@blame_pagination, theme: "gitlab")
+
diff --git a/app/views/projects/blob/_breadcrumb.html.haml b/app/views/projects/blob/_breadcrumb.html.haml
index 7c2caf34fd1..e77367a7b42 100644
--- a/app/views/projects/blob/_breadcrumb.html.haml
+++ b/app/views/projects/blob/_breadcrumb.html.haml
@@ -2,7 +2,7 @@
.nav-block
.tree-ref-container
.tree-ref-holder
- = render 'shared/ref_switcher', destination: 'blob'
+ #js-tree-ref-switcher{ data: { project_id: @project.id, project_root_path: project_path(@project), ref: current_ref } }
%ul.breadcrumb.repo-breadcrumb
%li.breadcrumb-item
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index 87a6b54d697..ff95e9a1088 100644
--- a/app/views/projects/blob/_editor.html.haml
+++ b/app/views/projects/blob/_editor.html.haml
@@ -16,7 +16,7 @@
- if current_action?(:new) || current_action?(:create)
%span.float-left.gl-mr-3
\/
- = text_field_tag 'file_name', params[:file_name], placeholder: "File name", data: { qa_selector: 'file_name_field' },
+ = text_field_tag 'file_name', params[:file_name], placeholder: "Filename", data: { qa_selector: 'file_name_field' },
required: true, class: 'form-control gl-form-input new-file-name js-file-path-name-input', value: params[:file_name] || (should_suggest_gitlab_ci_yml? ? '.gitlab-ci.yml' : '')
= render 'template_selectors'
- if should_suggest_gitlab_ci_yml?
@@ -26,15 +26,15 @@
dismiss_key: @project.id,
human_access: human_access } }
- .file-buttons.gl-display-flex.gl-align-items-center.gl-justify-content-end
- - if is_markdown
- - unless Feature.enabled?(:source_editor_toolbar, current_user)
+ - unless Feature.enabled?(:source_editor_toolbar, current_user)
+ .file-buttons.gl-display-flex.gl-align-items-center.gl-justify-content-end
+ - if is_markdown
= render 'shared/blob/markdown_buttons', show_fullscreen_button: false, supports_file_upload: false
- %span.soft-wrap-toggle
- = render Pajamas::ButtonComponent.new(icon: 'soft-unwrap', button_options: { class: 'no-wrap' }) do
- = _("No wrap")
- = render Pajamas::ButtonComponent.new(icon: 'soft-wrap', button_options: { class: 'soft-wrap' }) do
- = _("Soft wrap")
+ %span.soft-wrap-toggle
+ = render Pajamas::ButtonComponent.new(icon: 'soft-unwrap', button_options: { class: 'no-wrap' }) do
+ = _("No wrap")
+ = render Pajamas::ButtonComponent.new(icon: 'soft-wrap', button_options: { class: 'soft-wrap' }) do
+ = _("Soft wrap")
.file-editor.code
- if Feature.enabled?(:source_editor_toolbar, current_user)
diff --git a/app/views/projects/blob/viewers/_csv.html.haml b/app/views/projects/blob/viewers/_csv.html.haml
index 3a58bc9902c..3538ba1dd0d 100644
--- a/app/views/projects/blob/viewers/_csv.html.haml
+++ b/app/views/projects/blob/viewers/_csv.html.haml
@@ -1 +1 @@
-.file-content#js-csv-viewer{ data: { data: viewer.blob.data } }
+.file-content#js-csv-viewer{ data: { data: blob_raw_path } }
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 393b19e6c5a..3bdb81f02ad 100644
--- a/app/views/projects/branch_defaults/_branch_names_fields.html.haml
+++ b/app/views/projects/branch_defaults/_branch_names_fields.html.haml
@@ -12,3 +12,4 @@
= sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Issue::MAX_BRANCH_TEMPLATE })
- branch_name_help_link = help_page_path('user/project/merge_requests/creating_merge_requests.md', anchor: 'from-an-issue')
= link_to _('What variables can I use?'), branch_name_help_link, target: "_blank"
+ = render_if_exists 'projects/branch_defaults/branch_names_help'
diff --git a/app/views/projects/branch_rules/_show.html.haml b/app/views/projects/branch_rules/_show.html.haml
index 27525b441ab..6e70dc42776 100644
--- a/app/views/projects/branch_rules/_show.html.haml
+++ b/app/views/projects/branch_rules/_show.html.haml
@@ -1,4 +1,7 @@
- expanded = expanded_by_default?
+- show_code_owners = @project.licensed_feature_available?(:code_owner_approval_required)
+- show_status_checks = @project.licensed_feature_available?(:external_status_checks)
+- show_approvers = @project.licensed_feature_available?(:merge_request_approvers)
%section.settings.no-animate#branch-rules{ class: ('expanded' if expanded) }
.settings-header
@@ -7,6 +10,7 @@
= expanded ? _('Collapse') : _('Expand')
%p
= _('Define rules for who can push, merge, and the required approvals for each branch.')
+ = link_to(_('Leave feedback.'), 'https://gitlab.com/gitlab-org/gitlab/-/issues/388149', target: '_blank', rel: 'noopener noreferrer')
.settings-content.gl-pr-0
- #js-branch-rules{ data: { project_path: @project.full_path, branch_rules_path: project_settings_repository_branch_rules_path(@project) } }
+ #js-branch-rules{ data: { project_path: @project.full_path, branch_rules_path: project_settings_repository_branch_rules_path(@project), show_code_owners: show_code_owners.to_s, show_status_checks: show_status_checks.to_s, show_approvers: show_approvers.to_s } }
diff --git a/app/views/projects/branches/_branch_rules_info.haml b/app/views/projects/branches/_branch_rules_info.haml
new file mode 100644
index 00000000000..15bee31c596
--- /dev/null
+++ b/app/views/projects/branches/_branch_rules_info.haml
@@ -0,0 +1,12 @@
+- return unless show_branch_rules_info?
+= render Pajamas::AlertComponent.new(variant: :info,
+ title: s_("Branches|See all branch-related settings together with branch rules"),
+ alert_options: { class: 'js-branch-rules-info-callout gl-mb-6 gl-mt-4', data: { feature_id: Users::CalloutsHelper::BRANCH_RULES_INFO_CALLOUT, dismiss_endpoint: callouts_path, defer_links: 'true' } }) do |c|
+ = c.body do
+ = s_("Branches|You can now find an overview of settings for protected branches, merge request approvals, status checks, and security approvals conveniently in one spot.")
+
+ = c.actions do
+ = render Pajamas::ButtonComponent.new(variant: :confirm, href: project_settings_repository_path(@project, anchor: 'js-branch-rules'), button_options: { class: 'deferred-link gl-alert-action' }) do
+ = s_("Branches|View branch rules")
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-close'}) do
+ = _('Dismiss')
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index f43d19e2542..518292effd8 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -1,6 +1,8 @@
- add_page_specific_style 'page_bundles/branches'
- page_title _('Branches')
- add_to_breadcrumbs(_('Repository'), project_tree_path(@project))
+- is_branch_rules_available = (can? current_user, :maintainer_access, @project) && Feature.enabled?(:branch_rules, @project)
+- can_push_code = (can? current_user, :push_code, @project)
-# Possible values for variables passed down from the projects/branches_controller.rb
-#
@@ -22,16 +24,24 @@
sorted_by: @sort }
}
- - if can? current_user, :push_code, @project
+ - if can_push_code
.js-delete-merged-branches{ data: {
default_branch: @project.repository.root_ref,
form_path: project_merged_branches_path(@project) }
}
+ - if is_branch_rules_available
+ = link_to project_settings_repository_path(@project, anchor: 'js-branch-rules'), class: 'gl-button btn btn-default' do
+ = s_('Branches|View branch rules')
+
+ - if can_push_code
= link_to new_project_branch_path(@project), class: 'gl-button btn btn-confirm' do
= s_('Branches|New branch')
= render_if_exists 'projects/commits/mirror_status'
+- if is_branch_rules_available
+ = render 'branch_rules_info'
+
.js-branch-list{ data: { diverging_counts_endpoint: diverging_commit_counts_namespace_project_branches_path(@project.namespace, @project, format: :json), default_branch: @project.default_branch } }
- if @gitaly_unavailable
diff --git a/app/views/projects/buttons/_clone.html.haml b/app/views/projects/buttons/_clone.html.haml
index a8a911adb7d..ab026d9c6ac 100644
--- a/app/views/projects/buttons/_clone.html.haml
+++ b/app/views/projects/buttons/_clone.html.haml
@@ -13,7 +13,7 @@
%label.label-bold
= _('Clone with SSH')
.input-group.btn-group
- = text_field_tag :ssh_project_clone, project.ssh_url_to_repo, class: "js-select-on-focus form-control", readonly: true, aria: { label: _('Repository clone URL') }, data: { qa_selector: 'ssh_clone_url_content' }
+ = 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")
= render_if_exists 'projects/buttons/geo'
@@ -22,7 +22,7 @@
%label.label-bold
= _('Clone with %{http_label}') % { http_label: gitlab_config.protocol.upcase }
.input-group.btn-group
- = text_field_tag :http_project_clone, project.http_url_to_repo, class: "js-select-on-focus form-control", readonly: true, aria: { label: _('Repository clone URL') }, data: { qa_selector: 'http_clone_url_content' }
+ = 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")
= render_if_exists 'projects/buttons/geo'
@@ -32,12 +32,12 @@
%label.label-bold{ class: 'gl-px-4!' }
= _('Open in your IDE')
- if ssh_enabled?
- - escaped_ssh_url_to_repo = CGI.escape(project.ssh_url_to_repo)
+ - escaped_ssh_url_to_repo = CGI.escape(ssh_clone_url_to_repo(project))
%a.dropdown-item.open-with-link{ href: 'vscode://vscode.git/clone?url=' + escaped_ssh_url_to_repo }
.gl-dropdown-item-text-wrapper
= _('Visual Studio Code (SSH)')
- if http_enabled?
- - escaped_http_url_to_repo = CGI.escape(project.http_url_to_repo)
+ - escaped_http_url_to_repo = CGI.escape(http_clone_url_to_repo(project))
%a.dropdown-item.open-with-link{ href: 'vscode://vscode.git/clone?url=' + escaped_http_url_to_repo }
.gl-dropdown-item-text-wrapper
= _('Visual Studio Code (HTTPS)')
diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml
index 88631f14e56..9cca928e794 100644
--- a/app/views/projects/commit/_signature_badge.html.haml
+++ b/app/views/projects/commit/_signature_badge.html.haml
@@ -29,5 +29,5 @@
= 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')
-%a.signature-badge.gl-display-flex{ role: 'button', tabindex: 0, data: { toggle: 'popover', html: 'true', placement: 'top', title: title, content: content } }
+%a.signature-badge.gl-display-inline-block{ 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/commit/diff_files.html.haml b/app/views/projects/commit/diff_files.html.haml
index 0c52c1a15a4..7287d10a109 100644
--- a/app/views/projects/commit/diff_files.html.haml
+++ b/app/views/projects/commit/diff_files.html.haml
@@ -1 +1,5 @@
-= render partial: 'projects/diffs/file', collection: diffs.diff_files, as: :diff_file, locals: { project: diffs.project, environment: environment, diff_page_context: 'is-commit' }
+- diff_files = conditionally_paginate_diff_files(diffs, paginate: true, page: params[:page], per: Projects::CommitController::COMMIT_DIFFS_PER_PAGE)
+
+= render partial: 'projects/diffs/file', collection: diff_files, as: :diff_file, locals: { project: diffs.project, environment: environment, diff_page_context: 'is-commit' }
+
+= paginate(diff_files, theme: "gitlab", params: { action: :show })
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index b5481f19352..6209ef48f96 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -15,6 +15,7 @@
- ref = local_assigns.fetch(:ref) { merge_request&.source_branch }
- commit = commit.present(current_user: current_user)
- commit_status = commit.detailed_status_for(ref)
+- tags = commit.tags_for_display
- collapsible = local_assigns.fetch(:collapsible, true)
- link_data_attrs = local_assigns.fetch(:link_data_attrs, {})
- link = commit_path(project, commit, merge_request: merge_request)
@@ -55,6 +56,13 @@
= preserve(markdown_field(commit, :description))
.commit-actions.flex-row
+ - if tags.present?
+ = gl_badge_tag(variant: :neutral, icon: 'tag', class: 'gl-font-monospace') do
+ - if tags.size > 1
+ = link_to _('%{count} tags') % { count: tags.size } , project_commit_path(project, commit.id)
+ - else
+ = link_to tags.first, project_commits_path(project, tags.first, ref_type: 'tags'), class: 'gl-text-truncate gl-max-w-15'
+
- if request.xhr?
= render partial: 'projects/commit/signature', object: commit.signature
- else
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index b3590eea631..58da76a3231 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,5 +1,5 @@
-- breadcrumb_title _("Compare Revisions")
-- page_title _("Compare")
+- breadcrumb_title _("Compare revisions")
+- page_title _("Compare revisions")
%h1.page-title.gl-font-size-h-display
= _("Compare Git revisions")
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 1bdf3d1e6e3..bc378182057 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -1,4 +1,4 @@
-- add_to_breadcrumbs _("Compare Revisions"), project_compare_index_path(@project)
+- add_to_breadcrumbs _("Compare revisions"), project_compare_index_path(@project)
- page_title "#{params[:from]}...#{params[:to]}"
.sub-header-block.gl-border-b-0.gl-mb-0
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index ba79f0ee3cb..1e8b1255f0c 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1,6 +1,5 @@
- page_title _("Value Stream Analytics")
- data_attributes = @request_params.valid? ? @request_params.to_data_attributes : {}
-- data_attributes.merge!(cycle_analytics_initial_data(@project, @group))
- add_page_specific_style 'page_bundles/cycle_analytics'
#js-cycle-analytics{ data: data_attributes }
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 8ff6d348d95..03e26fd4456 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -3,7 +3,7 @@
- can_create_note = !@diff_notes_disabled && can?(current_user, :create_note, diffs.project)
- diff_page_context = local_assigns.fetch(:diff_page_context, nil)
- load_diff_files_async = Feature.enabled?(:async_commit_diff_files, @project) && diff_page_context == "is-commit"
-- paginate_diffs = local_assigns.fetch(:paginate_diffs, false) && !load_diff_files_async
+- paginate_diffs = local_assigns.fetch(:paginate_diffs, false)
- paginate_diffs_per_page = local_assigns.fetch(:paginate_diffs_per_page, nil)
- page = local_assigns.fetch(:page, nil)
- diff_files = conditionally_paginate_diff_files(diffs, paginate: paginate_diffs, page: page, per: paginate_diffs_per_page)
@@ -32,7 +32,7 @@
.files{ data: { can_create_note: can_create_note } }
- if load_diff_files_async
- - url = url_for(safe_params.merge(action: 'diff_files'))
+ - url = url_for(safe_params.merge(action: 'diff_files', page: page))
.js-diffs-batch{ data: { diff_files_path: url } }
= gl_loading_icon(size: "md", css_class: "gl-mt-4")
- else
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index e87005434e4..b2270e0faf7 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -7,6 +7,13 @@
= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
+- if Feature.enabled?(:show_pages_in_deployments_menu, current_user, type: :experiment)
+ = render Pajamas::AlertComponent.new(variant: :info,
+ 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.body do
+ = _('To go to GitLab Pages, on the left sidebar, select %{pages_link}.').html_safe % {pages_link: link_to('Deployments > Pages', project_pages_path(@project)).html_safe}
+
%section.settings.general-settings.no-animate.expanded#js-general-settings
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Naming, topics, avatar')
@@ -27,7 +34,6 @@
%input{ name: 'update_section', type: 'hidden', value: 'js-shared-permissions' }
%template.js-project-permissions-form-data{ type: "application/json" }= project_permissions_panel_data(@project).to_json.html_safe
.js-project-permissions-form{ data: visibility_confirm_modal_data(@project, reduce_visibility_form_id) }
-
- if show_merge_request_settings_callout?(@project)
%section.settings.expanded
= render Pajamas::AlertComponent.new(variant: :info,
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 43159a759f4..ca3f49bae95 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -8,6 +8,7 @@
= render "home_panel"
= render "archived_notice", project: @project
+= render "self_monitoring_deprecation_notice", project: @project
= render "invite_members_empty_project" if can_admin_project_member?(@project)
diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml
index 53b2af88511..4666ee738d7 100644
--- a/app/views/projects/environments/show.html.haml
+++ b/app/views/projects/environments/show.html.haml
@@ -20,7 +20,9 @@
%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
- = link_to _("Read more"), help_page_path("ci/environments/index.md"), class: "gl-button btn btn-confirm"
+ = render Pajamas::ButtonComponent.new(variant: :confirm, href: help_page_path("ci/environments/index.md")) do
+ = s_('Read more')
+
- else
.table-holder.gl-overflow-visible
.ci-table.environments{ role: 'grid' }
diff --git a/app/views/projects/feature_flags/index.html.haml b/app/views/projects/feature_flags/index.html.haml
index 53fe30422ca..a6eaeacc61f 100644
--- a/app/views/projects/feature_flags/index.html.haml
+++ b/app/views/projects/feature_flags/index.html.haml
@@ -6,7 +6,7 @@
"error-state-svg-path" => image_path('illustrations/feature_flag.svg'),
"feature-flags-help-page-path" => help_page_path("operations/feature_flags"),
"feature-flags-client-libraries-help-page-path" => help_page_path("operations/feature_flags", anchor: "choose-a-client-library"),
- "feature-flags-client-example-help-page-path" => help_page_path("operations/feature_flags", anchor: "golang-application-example"),
+ "feature-flags-client-example-help-page-path" => help_page_path("operations/feature_flags", anchor: "go-application-example"),
"feature-flags-limit-exceeded" => @project.actual_limits.exceeded?(:project_feature_flags, @project.operations_feature_flags.count),
"feature-flags-limit" => @project.actual_limits.project_feature_flags,
"unleash-api-url" => (unleash_api_url(@project) if can?(current_user, :admin_feature_flag, @project)),
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 754de2db8f3..9d6f67bd190 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -1,4 +1,4 @@
-- page_title _('Contributors')
+- page_title _('Contributor statistics')
- graph_path = project_graph_path(@project, current_ref, ref_type: @ref_type, format: :json)
- commits_path = project_commits_path(@project, current_ref, ref_type: @ref_type)
diff --git a/app/views/projects/issues/_design_management.html.haml b/app/views/projects/issues/_design_management.html.haml
index c5ce0549816..5e2b2bbfcc4 100644
--- a/app/views/projects/issues/_design_management.html.haml
+++ b/app/views/projects/issues/_design_management.html.haml
@@ -12,7 +12,8 @@
issue_iid: @issue.iid,
issue_path: project_issue_path(@project, @issue),
register_path: new_user_registration_path(redirect_to_referer: 'yes'),
- sign_in_path: new_session_path(:user, redirect_to_referer: 'yes') } }
+ sign_in_path: new_session_path(:user, redirect_to_referer: 'yes'),
+ saved_replies_new_path: profile_saved_replies_path } }
- else
.gl-border-solid.gl-border-1.gl-border-gray-100.gl-rounded-base.gl-mt-5.gl-p-3.gl-text-center
= enable_lfs_message
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index c86f9c79912..8f259fe73e1 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -12,4 +12,5 @@
show_timeline_view_toggle: show_timeline_view_toggle?(@issue).to_s,
current_user_data: UserSerializer.new.represent(current_user, {only_path: true}, CurrentUserEntity).to_json,
can_add_timeline_events: "#{can?(current_user, :admin_incident_management_timeline_event, @issue)}",
- report_abuse_path: add_category_abuse_reports_path } }
+ report_abuse_path: add_category_abuse_reports_path,
+ saved_replies_new_path: profile_saved_replies_path } }
diff --git a/app/views/projects/issues/_work_item_links.html.haml b/app/views/projects/issues/_work_item_links.html.haml
index 3deceacec8d..911260308b4 100644
--- a/app/views/projects/issues/_work_item_links.html.haml
+++ b/app/views/projects/issues/_work_item_links.html.haml
@@ -1,4 +1,4 @@
-.js-work-item-links-root{ data: { issuable_id: @issue.id, iid: @issue.iid,
+.js-work-item-links-root{ data: { issuable_id: @issue.id,
project_path: @project.full_path,
wi: work_items_index_data(@project),
register_path: new_user_registration_path(redirect_to_referer: 'yes'),
diff --git a/app/views/projects/issues/service_desk/_nav_btns.html.haml b/app/views/projects/issues/service_desk/_nav_btns.html.haml
index 8d16c3d978f..818de77dc89 100644
--- a/app/views/projects/issues/service_desk/_nav_btns.html.haml
+++ b/app/views/projects/issues/service_desk/_nav_btns.html.haml
@@ -1,7 +1,7 @@
- show_feed_buttons = local_assigns.fetch(:show_feed_buttons, true)
- show_import_button = local_assigns.fetch(:show_import_button, true) && can?(current_user, :import_issues, @project)
- show_export_button = local_assigns.fetch(:show_export_button, true)
-- issuable_type = 'issues'
+- issuable_type = 'issue'
- can_edit = can?(current_user, :admin_project, @project)
- notification_email = @current_user.present? ? @current_user.notification_email_or_default : nil
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index a8edf87b696..7e8bf4ae57f 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -8,4 +8,3 @@
- add_page_specific_style 'page_bundles/work_items'
= render 'projects/issuable/show', issuable: @issue, api_awards_path: award_emoji_issue_api_path(@issue)
-= render 'projects/invite_members_modal', project: @project
diff --git a/app/views/projects/merge_requests/_mr_title.html.haml b/app/views/projects/merge_requests/_mr_title.html.haml
index 9d25603994a..d0bd176028f 100644
--- a/app/views/projects/merge_requests/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/_mr_title.html.haml
@@ -27,7 +27,8 @@
.detail-page-header-actions.gl-align-self-start.is-merge-request.js-issuable-actions.gl-display-flex
- if can_update_merge_request
- = link_to _('Edit'), edit_project_merge_request_path(@project, @merge_request), class: "gl-display-none gl-md-display-block btn gl-button btn-default js-issuable-edit", data: { qa_selector: "edit_button" }
+ = render Pajamas::ButtonComponent.new(href: edit_project_merge_request_path(@project, @merge_request), button_options: {class: "gl-display-none gl-md-display-block js-issuable-edit", data: { qa_selector: "edit_button" }}) do
+ = _('Edit')
- if @merge_request.source_project
= render 'projects/merge_requests/code_dropdown'
diff --git a/app/views/projects/merge_requests/_nav_btns.html.haml b/app/views/projects/merge_requests/_nav_btns.html.haml
index 1efea6a1d37..beb6de4698c 100644
--- a/app/views/projects/merge_requests/_nav_btns.html.haml
+++ b/app/views/projects/merge_requests/_nav_btns.html.haml
@@ -1,4 +1,4 @@
-- issuable_type = 'merge-requests'
+- issuable_type = 'merge_request'
- notification_email = @current_user.present? ? @current_user.notification_email_or_default : nil
= render 'shared/issuable/feed_buttons', show_calendar_button: false
diff --git a/app/views/projects/merge_requests/_page.html.haml b/app/views/projects/merge_requests/_page.html.haml
index 880bffc43ab..5bd33cd210d 100644
--- a/app/views/projects/merge_requests/_page.html.haml
+++ b/app/views/projects/merge_requests/_page.html.haml
@@ -81,7 +81,8 @@
help_page_path: suggest_changes_help_path,
current_user_data: @current_user_data,
is_locked: @merge_request.discussion_locked.to_s,
- report_abuse_path: add_category_abuse_reports_path } }
+ report_abuse_path: add_category_abuse_reports_path,
+ saved_replies_new_path: profile_saved_replies_path } }
- if moved_mr_sidebar_enabled?
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees, reviewers: @merge_request.reviewers, source_branch: @merge_request.source_branch
@@ -90,7 +91,7 @@
= render "projects/merge_requests/tabs/pane", name: "pipelines", id: "pipelines", class: "pipelines" do
- if @project.builds_enabled?
= render 'projects/commit/pipelines_list', disable_initialization: true, endpoint: pipelines_project_merge_request_path(@project, @merge_request)
- - params = request.query_parameters.merge(diff_head: true)
+ - params = request.query_parameters.merge(ck: @diffs_batch_cache_key, diff_head: true)
= render "projects/merge_requests/tabs/pane", name: "diffs", id: "js-diffs-app", class: "diffs", data: diffs_tab_pane_data(@project, @merge_request, params)
.mr-loading-status
@@ -105,10 +106,9 @@
- if @merge_request.can_be_cherry_picked?
= render "projects/commit/change", type: 'cherry-pick', commit: @merge_request.merge_commit
-#js-review-bar
+#js-review-bar{ data: { saved_replies_new_path: profile_saved_replies_path } }
- if current_user && Feature.enabled?(:mr_experience_survey, current_user)
#js-mr-experience-survey{ data: { account_age: current_user.account_age_in_days } }
-= render 'projects/invite_members_modal', project: @project
= render 'shared/web_ide_path'
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index cdb8a63bca9..91c161e8602 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -1,32 +1,26 @@
-= gitlab_ui_form_for [@project, @milestone],
- html: { class: 'milestone-form common-note-form js-quick-submit js-requires-input' } do |f|
+= gitlab_ui_form_for [@project, @milestone], html: { class: 'milestone-form common-note-form js-quick-submit js-requires-input' } do |f|
= form_errors(@milestone)
- if @redirect_path.present?
= f.hidden_field(:redirect_path, name: :redirect_path, id: :redirect_path, value: @redirect_path)
- .form-group.row
- .col-form-label.col-sm-2
- = f.label :title, _('Title')
- .col-sm-10
- = f.text_field :title, maxlength: 255, class: 'form-control gl-form-input', data: { qa_selector: 'milestone_title_field' }, required: true, autofocus: true
+ .form-group
+ = f.label :title, _('Title')
+ = f.text_field :title, maxlength: 255, class: 'form-control gl-form-input', data: { qa_selector: 'milestone_title_field' }, required: true, autofocus: true
= render 'shared/milestones/form_dates', f: f
- .form-group.row.milestone-description
- .col-form-label.col-sm-2
- = f.label :description, _('Description')
- .col-sm-10
- = render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project) } do
- = render 'shared/zen', f: f, attr: :description,
- classes: 'note-textarea',
- qa_selector: 'milestone_description_field',
- supports_autocomplete: true,
- placeholder: _('Write milestone description...')
- = render 'shared/notes/hints'
- .clearfix
- .error-alert
+ .form-group
+ = f.label :description, _('Description')
+ = render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project) } do
+ = render 'shared/zen', f: f, attr: :description,
+ classes: 'note-textarea',
+ qa_selector: 'milestone_description_field',
+ supports_autocomplete: true,
+ placeholder: _('Write milestone description...')
+ = render 'shared/notes/hints'
+ .clearfix
+ .error-alert
- .form-actions
- - if @milestone.new_record?
- = f.submit _('Create milestone'), data: { qa_selector: 'create_milestone_button' }, pajamas_button: true
- = link_to _('Cancel'), project_milestones_path(@project), class: 'gl-button btn btn-default btn-cancel'
- - else
- = f.submit _('Save changes'), pajamas_button: true
- = link_to _('Cancel'), project_milestone_path(@project, @milestone), class: 'gl-button btn btn-default btn-cancel'
+ - if @milestone.new_record?
+ = f.submit _('Create milestone'), data: { qa_selector: 'create_milestone_button' }, class: 'gl-mr-2', pajamas_button: true
+ = link_to _('Cancel'), project_milestones_path(@project), class: 'gl-button btn btn-default btn-cancel'
+ - else
+ = f.submit _('Save changes'), class: 'gl-mr-2', pajamas_button: true
+ = link_to _('Cancel'), project_milestone_path(@project, @milestone), class: 'gl-button btn btn-default btn-cancel'
diff --git a/app/views/projects/mirrors/_mirror_repos_list.html.haml b/app/views/projects/mirrors/_mirror_repos_list.html.haml
index 46833b5986b..5dbbb72db56 100644
--- a/app/views/projects/mirrors/_mirror_repos_list.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos_list.html.haml
@@ -3,11 +3,11 @@
.panel.panel-default
.table-responsive
- if !@project.mirror? && @project.remote_mirrors.count == 0
- .gl-card.gl-mt-5
- .gl-card-header
+ = render Pajamas::CardComponent.new(card_options: { class: 'gl-mt-5' }) do |c|
+ - c.header do
%strong
= _('Mirrored repositories') + ' (0)'
- .gl-card-body
+ - c.body do
= _('There are currently no mirrored repositories.')
- else
%table.table.push-pull-table
diff --git a/app/views/projects/ml/candidates/show.html.haml b/app/views/projects/ml/candidates/show.html.haml
index 77262243efb..aea74ecfb48 100644
--- a/app/views/projects/ml/candidates/show.html.haml
+++ b/app/views/projects/ml/candidates/show.html.haml
@@ -2,5 +2,6 @@
- add_to_breadcrumbs _("Experiments"), project_ml_experiments_path(@project)
- add_to_breadcrumbs experiment.name, project_ml_experiment_path(@project, experiment.iid)
- breadcrumb_title "Candidate #{@candidate.iid}"
+- add_page_specific_style 'page_bundles/ml_experiment_tracking'
#js-show-ml-candidate{ data: { view_model: show_candidate_view_model(@candidate) } }
diff --git a/app/views/projects/ml/experiments/_experiment.html.haml b/app/views/projects/ml/experiments/_experiment.html.haml
deleted file mode 100644
index 42823f47469..00000000000
--- a/app/views/projects/ml/experiments/_experiment.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-%li.ml-experiment-row.py-3
- = link_to project_ml_experiment_path(@project, experiment.iid), class: "title" do
- = experiment.name
diff --git a/app/views/projects/ml/experiments/_experiment_list.html.haml b/app/views/projects/ml/experiments/_experiment_list.html.haml
deleted file mode 100644
index a25e814b2b5..00000000000
--- a/app/views/projects/ml/experiments/_experiment_list.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-- if experiments.blank?
- .nothing-here-block= s_('MlExperimentsEmptyState|No Experiments to Show')
-- else
- .ml-experiments-list-holder
- %ul.content-list
- = render partial: 'experiment', collection: experiments, as: :experiment
- = paginate_collection @experiments
diff --git a/app/views/projects/ml/experiments/_incubation_banner.html.haml b/app/views/projects/ml/experiments/_incubation_banner.html.haml
deleted file mode 100644
index e34f3fd2d2f..00000000000
--- a/app/views/projects/ml/experiments/_incubation_banner.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-= render Pajamas::AlertComponent.new(variant: :warning,
- title: _('Machine Learning Experiment Tracking is in Incubating Phase'),
- alert_options: { class: 'gl-my-3' }) do |c|
- = c.body do
- = _('GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited')
- = link_to _('Learn more.'), 'https://about.gitlab.com/handbook/engineering/incubation/', target: "_blank"
- = c.actions do
- = link_to _('Feedback and Updates'), 'https://gitlab.com/groups/gitlab-org/-/epics/8560', target: "_blank"
diff --git a/app/views/projects/ml/experiments/show.html.haml b/app/views/projects/ml/experiments/show.html.haml
index 4433d1fafe9..52145eb0964 100644
--- a/app/views/projects/ml/experiments/show.html.haml
+++ b/app/views/projects/ml/experiments/show.html.haml
@@ -1,6 +1,8 @@
- add_to_breadcrumbs _("Experiments"), project_ml_experiments_path(@project)
- breadcrumb_title @experiment.name
- page_title @experiment.name
+- add_page_specific_style 'page_bundles/ml_experiment_tracking'
+
- items = candidates_table_items(@candidates)
- metrics = unique_logged_names(@candidates, &:latest_metrics)
- params = unique_logged_names(@candidates, &:params)
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 56581fe7b18..f4a5862b2c0 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -4,11 +4,19 @@
- header_title _("Projects"), dashboard_projects_path
- add_page_specific_style 'page_bundles/new_namespace'
-.project-edit-container.gl-mt-5
+.project-edit-container
.project-edit-errors
= render 'projects/errors'
- .js-new-project-creation{ data: { is_ci_cd_available: (ci_cd_projects_available? if Gitlab.ee?).to_s, has_errors: @project.errors.any?.to_s, new_project_guidelines: brand_new_project_guidelines, push_to_create_project_command: push_to_create_project_command, working_with_projects_help_path: help_page_path("user/project/working_with_projects") } }
+ .js-new-project-creation{ data: {
+ is_ci_cd_available: remote_mirror_setting_enabled?.to_s,
+ has_errors: @project.errors.any?.to_s,
+ new_project_guidelines: brand_new_project_guidelines,
+ push_to_create_project_command: push_to_create_project_command,
+ working_with_projects_help_path: help_page_path("user/project/working_with_projects"),
+ parent_group_url: @project.parent && group_url(@project.parent),
+ parent_group_name: @project.parent&.name,
+ projects_url: dashboard_projects_url } }
.row{ 'v-cloak': true }
#blank-project-pane.tab-pane.active
diff --git a/app/views/projects/pages/_pages_settings.html.haml b/app/views/projects/pages/_pages_settings.html.haml
index 0010564081e..11e105d349d 100644
--- a/app/views/projects/pages/_pages_settings.html.haml
+++ b/app/views/projects/pages/_pages_settings.html.haml
@@ -17,5 +17,14 @@
%p.gl-pl-6
= s_("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}").html_safe % { docs_link_start: docs_link_start, link_end: link_end }
+ - if Feature.enabled?(:pages_unique_domain)
+ .form-group
+ = f.fields_for :project_setting do |settings|
+ = settings.gitlab_ui_checkbox_component :pages_unique_domain_enabled,
+ s_('GitLabPages|Use unique domain'),
+ label_options: { class: 'label-bold' }
+ %p.gl-pl-6
+ = s_("GitLabPages|When enabled, a unique domain is generated to access pages.").html_safe
+
.gl-mt-3
- = f.submit s_('GitLabPages|Save changes'), class: 'btn btn-confirm gl-button'
+ = f.submit s_('GitLabPages|Save changes'), pajamas_button: true
diff --git a/app/views/projects/pages_domains/_certificate.html.haml b/app/views/projects/pages_domains/_certificate.html.haml
index 4ba3e084dc4..3433958a397 100644
--- a/app/views/projects/pages_domains/_certificate.html.haml
+++ b/app/views/projects/pages_domains/_certificate.html.haml
@@ -30,10 +30,10 @@
- if has_user_defined_certificate
.row
.col-sm-10.offset-sm-2
- .card
- .card-header
- = _('Certificate')
- .d-flex.justify-content-between.align-items-center.p-3
+ = render Pajamas::CardComponent.new(body_options: { class: 'gl-display-flex gl-align-items-center gl-justify-content-space-between gl-p-5' }) do |c|
+ - c.header do
+ = s_('Certificate')
+ - c.body do
%span
= domain_presenter.pages_domain.subject || _('missing')
= link_to _('Remove'),
diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
index 0de31f59033..37b2b3ecfde 100644
--- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
+++ b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
@@ -37,7 +37,7 @@
- if can?(current_user, :play_pipeline_schedule, pipeline_schedule)
= link_to play_pipeline_schedule_path(pipeline_schedule), method: :post, title: _('Play'), class: 'btn gl-button btn-default btn-icon' do
= sprite_icon('play')
- - if can?(current_user, :take_ownership_pipeline_schedule, pipeline_schedule)
+ - 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)
diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml
index 8f7f0a15e69..7a889570f56 100644
--- a/app/views/projects/pipelines/_info.html.haml
+++ b/app/views/projects/pipelines/_info.html.haml
@@ -11,17 +11,20 @@
= preserve(markdown(commit.description, pipeline: :single_line))
.info-well
- .well-segment.pipeline-info{ class: "gl-align-items-baseline!" }
- .icon-container
- = sprite_icon('clock', css_class: 'gl-top-0!')
- - jobs = n_('%d job', '%d jobs', @pipeline.total_size) % @pipeline.total_size
- - if @pipeline.duration
- = s_('Pipelines|%{jobs} %{ref_text} in %{duration}').html_safe % { jobs: jobs, ref_text: @pipeline.ref_text, duration: time_interval_in_words(@pipeline.duration) }
- - else
- = jobs
+ .well-segment.pipeline-info{ class: "gl-align-items-baseline! gl-flex-direction-column" }
+ %div
+ .icon-container
+ = sprite_icon('clock', css_class: 'gl-top-0!')
+ = n_('%d job', '%d jobs', @pipeline.total_size) % @pipeline.total_size
= @pipeline.ref_text
- - if @pipeline.queued_duration
- = s_("Pipelines|(queued for %{queued_duration})") % { queued_duration: time_interval_in_words(@pipeline.queued_duration)}
+ - if @pipeline.finished_at
+ - duration = time_interval_in_words(@pipeline.duration)
+ - queued_duration = time_interval_in_words(@pipeline.queued_duration)
+ %span.gl-pl-7{ 'data-testid': 'pipeline-stats-text' }
+ - if Feature.enabled?(:refactor_ci_minutes_consumption, @project)
+ = render_if_exists 'projects/pipelines/pipeline_stats_text', duration: duration, pipeline: @pipeline, queued_duration: queued_duration
+ - else
+ = s_("in %{duration} and was queued for %{queued_duration}").html_safe % { duration: duration, queued_duration: queued_duration }
- if has_pipeline_badges?(@pipeline)
.well-segment
diff --git a/app/views/projects/pipelines/_pipeline_stats_text.html.haml b/app/views/projects/pipelines/_pipeline_stats_text.html.haml
new file mode 100644
index 00000000000..8adf94e61c4
--- /dev/null
+++ b/app/views/projects/pipelines/_pipeline_stats_text.html.haml
@@ -0,0 +1 @@
+= s_("in %{duration} and was queued for %{queued_duration}").html_safe % { duration: duration, queued_duration: queued_duration }
diff --git a/app/views/projects/pipelines/new.html.haml b/app/views/projects/pipelines/new.html.haml
index d2b2a58fcf8..ee51ee9b0e2 100644
--- a/app/views/projects/pipelines/new.html.haml
+++ b/app/views/projects/pipelines/new.html.haml
@@ -9,6 +9,8 @@
pipelines_path: project_pipelines_path(@project),
config_variables_path: config_variables_namespace_project_pipelines_path(@project.namespace, @project),
default_branch: @project.default_branch,
+ pipelines_editor_path: project_ci_pipeline_editor_path(@project),
+ can_view_pipeline_editor: can_view_pipeline_editor?(@project),
ref_param: params[:ref] || @project.default_branch,
var_param: params[:var].to_json,
file_param: params[:file_var].to_json,
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
index 9b0a81a2f60..15d729c89b9 100644
--- a/app/views/projects/pipelines/show.html.haml
+++ b/app/views/projects/pipelines/show.html.haml
@@ -17,11 +17,17 @@
= render "projects/pipelines/info", commit: @pipeline.commit
- if pipeline_has_errors
- .bs-callout.bs-callout-danger
- %h4= _('Unable to create pipeline')
- %ul
- - @pipeline.yaml_errors.split("\n").each do |error|
- %li= error
+ = render Pajamas::AlertComponent.new(title: s_('Pipelines|Unable to create pipeline'),
+ variant: :danger,
+ dismissible: false,
+ alert_options: { class: 'gl-mb-5' }) do |c|
+ = c.body do
+ %ul
+ - @pipeline.yaml_errors.split("\n").each do |error|
+ %li= error
+ - if can_view_pipeline_editor?(@project)
+ = render Pajamas::ButtonComponent.new(href: project_ci_pipeline_editor_path(@project), variant: :confirm) do
+ = s_("Pipelines|Go to the pipeline editor")
- else
#js-pipeline-tabs{ data: js_pipeline_tabs_data(@project, @pipeline, @current_user) }
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index 4ac0e28d386..0cfb5ff6a3d 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -3,6 +3,10 @@
= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
+= content_for :page_level_alert do
+ - if can_invite_members_for_project?(@project)
+ = render_if_exists 'shared/unlimited_members_during_trial_alert', group: @project.root_ancestor
+
.row.gl-mt-3
.col-lg-12
.gl-display-flex.gl-flex-wrap
@@ -25,7 +29,6 @@
classes: 'gl-md-w-auto gl-w-full gl-md-ml-3 gl-md-mt-0 gl-mt-3',
trigger_source: 'project-members-page',
display_text: _('Invite members') } }
- = render 'projects/invite_members_modal', project: @project, reload_page_on_submit: true
- else
- if project_can_be_shared?
%h4
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 d19a6401fc8..ef3974b04b5 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,9 @@
- content_for :create_access_levels do
.create_access_levels-container
= dropdown_tag('Select',
- options: { toggle_class: 'js-allowed-to-create wide',
+ options: { toggle_class: 'js-allowed-to-create js-multiselect wide',
dropdown_class: 'dropdown-menu-selectable capitalize-header',
- dropdown_qa_selector: 'access_levels_content',
+ 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' }})
= render 'projects/protected_tags/shared/create_protected_tag'
diff --git a/app/views/projects/protected_tags/_protected_tag.html.haml b/app/views/projects/protected_tags/_protected_tag.html.haml
index e0912bf39c0..68e4a5e97a3 100644
--- a/app/views/projects/protected_tags/_protected_tag.html.haml
+++ b/app/views/projects/protected_tags/_protected_tag.html.haml
@@ -1,4 +1,4 @@
= render layout: 'projects/protected_tags/shared/protected_tag', locals: { protected_tag: protected_tag } do
- %td
- = render 'projects/protected_tags/protected_tag_create_access_levels', protected_tag: protected_tag, create_access_level: protected_tag.create_access_levels.for_role.first
+ %td.create_access_levels-container
+ = render 'projects/protected_tags/protected_tag_create_access_levels', protected_tag: protected_tag, create_access_level: protected_tag.create_access_levels.for_role
= render_if_exists 'projects/protected_tags/protected_tag_extra_create_access_levels', protected_tag: 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 1d4e9565156..30b9e3e9005 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,8 @@
- protected_tag = local_assigns.fetch(:protected_tag)
- create_access_level = local_assigns.fetch(:create_access_level)
-- dropdown_label = create_access_level&.humanize || 'Select'
+- dropdown_label = create_access_level.first&.humanize || 'Select'
-= hidden_field_tag "allowed_to_create_#{protected_tag.id}", create_access_level&.access_level
+= 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', dropdown_class: 'dropdown-menu-selectable capitalize-header js-allowed-to-create-container',
- data: { field_name: "allowed_to_create_#{protected_tag.id}", access_level_id: create_access_level&.id }})
+ 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) }})
diff --git a/app/views/projects/security/configuration/show.html.haml b/app/views/projects/security/configuration/show.html.haml
index 4b82f74d035..2904fb81afe 100644
--- a/app/views/projects/security/configuration/show.html.haml
+++ b/app/views/projects/security/configuration/show.html.haml
@@ -1,5 +1,5 @@
-- breadcrumb_title _("Security Configuration")
-- page_title _("Security Configuration")
+- breadcrumb_title _("Security configuration")
+- page_title _("Security configuration")
- @content_class = "limit-container-width" unless fluid_layout
#js-security-configuration{ data: { **@configuration.to_html_data_attribute,
diff --git a/app/views/projects/settings/_general.html.haml b/app/views/projects/settings/_general.html.haml
index 5f1dee39e25..847f9ad3e2a 100644
--- a/app/views/projects/settings/_general.html.haml
+++ b/app/views/projects/settings/_general.html.haml
@@ -16,7 +16,6 @@
.row
.form-group.col-md-9
- = f.label :topics, _('Topics'), class: 'label-bold'
.js-topics-selector{ data: { hidden_input_id: hidden_topics_field_id } }
= f.hidden_field :topics, value: @project.topic_list.join(', '), id: hidden_topics_field_id
@@ -31,8 +30,7 @@
= render_if_exists 'shared/repository_size_limit_setting', form: f, type: :project
.form-group.gl-mt-3.gl-mb-3
- .avatar-container.rect-avatar.s90
- = project_icon(@project, alt: _('Project avatar'), class: 'avatar project-avatar s90')
+ = render Pajamas::AvatarComponent.new(@project, size: 96, alt: '', class: 'gl-float-left gl-mr-5')
= f.label :avatar, _('Project avatar'), class: 'label-bold d-block'
= render 'shared/choose_avatar_button', f: f
- if @project.avatar?
diff --git a/app/views/projects/settings/branch_rules/index.html.haml b/app/views/projects/settings/branch_rules/index.html.haml
index 80a41bb579b..f05a528745c 100644
--- a/app/views/projects/settings/branch_rules/index.html.haml
+++ b/app/views/projects/settings/branch_rules/index.html.haml
@@ -3,4 +3,4 @@
%h3.gl-mb-5= s_('BranchRules|Branch rules details')
-#js-branch-rules{ data: { project_path: @project.full_path, protected_branches_path: project_settings_repository_path(@project, anchor: 'js-protected-branches-settings'), approval_rules_path: project_settings_merge_requests_path(@project, anchor: 'js-merge-request-approval-settings'), status_checks_path: project_settings_merge_requests_path(@project, anchor: 'js-merge-request-settings'), branches_path: project_branches_path(@project) } }
+#js-branch-rules{ data: branch_rules_data(@project) }
diff --git a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
index 86238a41f0b..5afbace3f26 100644
--- a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
@@ -20,15 +20,15 @@
%fieldset.builds-feature.js-auto-devops-settings
.form-group
= f.fields_for :auto_devops_attributes, @auto_devops do |form|
- .card.gl-mb-3
- .card-body
+ = render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-3' }, footer_options: { class: auto_devops_enabled || 'hidden' }) do |c|
+ - c.body do
- autodevops_help_link = link_to _('Learn more.'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer'
- auto_devops_badge = auto_devops_enabled ? (gl_badge_tag badge_for_auto_devops_scope(@project), { variant: :info }, { class: 'js-instance-default-badge gl-ml-3 gl-mt-n1'}) : ''
= form.gitlab_ui_checkbox_component :enabled,
(s_('CICD|Default to Auto DevOps pipeline') + auto_devops_badge).html_safe,
checkbox_options: { class: 'js-toggle-extra-settings', checked: auto_devops_enabled, data: { qa_selector: 'enable_autodevops_checkbox' } },
help_text: (s_('CICD|The Auto DevOps pipeline runs if no alternative CI configuration file is found.') + ' ' + autodevops_help_link).html_safe
- .card-footer.js-extra-settings{ class: auto_devops_enabled || 'hidden' }
+ - c.footer do
- if @project.all_clusters.empty?
%p.settings-message.text-center
= s_('CICD|Add a %{kubernetes_cluster_link_start}Kubernetes cluster integration%{link_end} with a domain, or create an AUTO_DEVOPS_PLATFORM_TARGET CI variable.').html_safe % { kubernetes_cluster_link_start: kubernetes_cluster_link_start, link_end: link_end }
diff --git a/app/views/projects/settings/ci_cd/_badge.html.haml b/app/views/projects/settings/ci_cd/_badge.html.haml
index 99eef38827b..76a7b42e0e5 100644
--- a/app/views/projects/settings/ci_cd/_badge.html.haml
+++ b/app/views/projects/settings/ci_cd/_badge.html.haml
@@ -9,7 +9,7 @@
= badge.title.capitalize
&middot;
= badge.to_html
- = render 'shared/ref_switcher', destination: 'badges', align_right: true
+ .js-ref-switcher-badge{ id: "js-project-ci-cd-ref-switcher-#{badge.title.parameterize(separator: '-') }", data: { project_id: @project.id, ref: @ref } }
- c.body do
.row
.col-md-2.gl-text-center
diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml
index 68dc7f2be8d..6f64d3f3f76 100644
--- a/app/views/projects/settings/ci_cd/_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_form.html.haml
@@ -18,7 +18,7 @@
_("Auto-cancel redundant pipelines"),
checked_value: 'enabled',
unchecked_value: 'disabled',
- help_text: (_('New pipelines cause older pending or running pipelines on the same branch to be cancelled.') + ' ' + help_link_auto_canceling).html_safe
+ help_text: (_('Pipelines for new changes cause older pending or running pipelines on the same branch to be cancelled.') + ' ' + help_link_auto_canceling).html_safe
.form-group
= f.fields_for :ci_cd_settings_attributes, @project.ci_cd_settings do |form|
diff --git a/app/views/projects/settings/integrations/_form.html.haml b/app/views/projects/settings/integrations/_form.html.haml
index 9d74f99bb19..97d90976f18 100644
--- a/app/views/projects/settings/integrations/_form.html.haml
+++ b/app/views/projects/settings/integrations/_form.html.haml
@@ -11,6 +11,9 @@
= c.body do
= s_('ExternalIssueIntegration|Only one issue tracker integration can be active at a time. Please disable the active tracker first and try again.')
+- if integration.to_param === 'slack'
+ = render 'shared/integrations/slack_notifications_deprecation_alert'
+
%h2.gl-mb-4
= integration.title
- if integration.operating?
diff --git a/app/views/projects/settings/integrations/index.html.haml b/app/views/projects/settings/integrations/index.html.haml
index 2077d244b24..c316b4e9cac 100644
--- a/app/views/projects/settings/integrations/index.html.haml
+++ b/app/views/projects/settings/integrations/index.html.haml
@@ -2,6 +2,8 @@
- breadcrumb_title _('Integration Settings')
- page_title _('Integrations')
+= render 'shared/integrations/slack_notifications_deprecation_alert'
+
%section.js-search-settings-section
%h3= _('Integrations')
- integrations_link_start = '<a href="%{url}">'.html_safe % { url: help_page_url('user/project/integrations/index') }
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 5fa70c3af32..f47f4ebc7ee 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -9,6 +9,8 @@
= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
= render partial: 'flash_messages', locals: { project: @project }
+= render "self_monitoring_deprecation_notice", project: @project
+
= render 'clusters_deprecation_alert'
= render "projects/last_push"
diff --git a/app/views/projects/starrers/_starrer.html.haml b/app/views/projects/starrers/_starrer.html.haml
index c1cd2488142..d9fda2a6e36 100644
--- a/app/views/projects/starrers/_starrer.html.haml
+++ b/app/views/projects/starrers/_starrer.html.haml
@@ -1,8 +1,8 @@
- starrer = local_assigns.fetch(:starrer)
.col-lg-3.col-md-4.col-sm-12
- .card
- .card-body.gl-display-flex
+ = render Pajamas::CardComponent.new(body_options: { class: 'gl-display-flex' }) do |c|
+ - c.body do
= render Pajamas::AvatarComponent.new(starrer.user, size: 48, alt: "", class: 'gl-mr-3')
.user-info
diff --git a/app/views/projects/work_items/index.html.haml b/app/views/projects/work_items/index.html.haml
index 69597aab7ef..dad8bb09ff6 100644
--- a/app/views/projects/work_items/index.html.haml
+++ b/app/views/projects/work_items/index.html.haml
@@ -4,4 +4,3 @@
- @noteable_type = 'WorkItem'
#js-work-items{ data: work_items_index_data(@project) }
-= render 'projects/invite_members_modal', project: @project
diff --git a/app/views/registrations/welcome/show.html.haml b/app/views/registrations/welcome/show.html.haml
index f4e9a597fe2..2796f0c0a7e 100644
--- a/app/views/registrations/welcome/show.html.haml
+++ b/app/views/registrations/welcome/show.html.haml
@@ -38,4 +38,5 @@
- if partial_exists? "registrations/welcome/button"
= render "registrations/welcome/button"
- else
- = f.submit _('Get started!'), class: 'btn-confirm gl-button btn btn-block gl-mb-0 gl-p-3', data: { qa_selector: 'get_started_button' }
+ = render Pajamas::ButtonComponent.new(block: true, type: :submit, variant: :confirm, button_options: { class: 'gl-mb-0', data: { qa_selector: 'get_started_button' }}) do
+ = _('Get started!')
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index fee943042f9..3280dcf2cd4 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -5,5 +5,5 @@
.results.gl-md-display-flex.gl-mt-0
#js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
.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' if @search_objects.present?
= render partial: 'search/results_list'
diff --git a/app/views/search/_results_list.html.haml b/app/views/search/_results_list.html.haml
index 7a57b5cc0fc..c36acaf9ea8 100644
--- a/app/views/search/_results_list.html.haml
+++ b/app/views/search/_results_list.html.haml
@@ -2,19 +2,20 @@
= render partial: "search/results/timeout"
- elsif @search_results.respond_to?(:failed?) && @search_results.failed?
= render partial: "search/results/error"
-- elsif @search_objects.to_a.empty?
+- elsif @search_objects.blank?
= render partial: "search/results/empty"
- else
- - if @scope == 'commits'
- %ul.content-list.commit-list
- = render partial: "search/results/commit", collection: @search_objects
- - else
- .search-results.js-search-results
- - if @scope == 'projects'
- .term
- = render 'shared/projects/list', projects: @search_objects, pipeline_status: false
- - else
- = render_if_exists partial: "search/results/#{@scope.singularize}", collection: @search_objects
+ .gl-md-pl-5
+ - if @scope == 'commits'
+ %ul.content-list.commit-list
+ = render partial: "search/results/commit", collection: @search_objects
+ - else
+ .search-results.js-search-results
+ - if @scope == 'projects'
+ .term
+ = render 'shared/projects/list', projects: @search_objects, pipeline_status: false
+ - else
+ = render_if_exists partial: "search/results/#{@scope.singularize}", collection: @search_objects
- - if @scope != 'projects'
- = paginate_collection(@search_objects)
+ - if @scope != 'projects'
+ = paginate_collection(@search_objects)
diff --git a/app/views/search/_results_status.html.haml b/app/views/search/_results_status.html.haml
index 27405631360..4ab68caaf22 100644
--- a/app/views/search/_results_status.html.haml
+++ b/app/views/search/_results_status.html.haml
@@ -1,25 +1,26 @@
- return unless @search_service_presenter.show_results_status?
-
-.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?
- = 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-md-pl-5
+ .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
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index 3681f823ef5..115bb6cc9fa 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -1,6 +1,8 @@
- project = blob.project
- return unless project
-- blob_link = project_blob_path(project, tree_join(repository_ref(project), blob.path))
-- blame_link = project_blame_path(project, tree_join(repository_ref(project), blob.path))
+- project_repository_ref = repository_ref(project) || ''
+- blob_path = blob.path || ''
+- blob_link = project_blob_path(project, tree_join(project_repository_ref, blob_path))
+- blame_link = project_blame_path(project, tree_join(project_repository_ref, blob_path))
-= render partial: 'search/results/blob_data', locals: { blob: blob, project: project, path: blob.path, blob_link: blob_link, blame_link: blame_link }
+= render partial: 'search/results/blob_data', locals: { blob: blob, project: project, path: blob_path, blob_link: blob_link, blame_link: blame_link }
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 04103794e60..826d78c470d 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -1,6 +1,6 @@
- @hide_top_links = true
+- breadcrumb_title _('Search')
- page_title @search_term
-- @hide_breadcrumbs = true
- if params[:group_id].present?
= hidden_field_tag :group_id, params[:group_id]
- if params[:project_id].present?
@@ -19,7 +19,6 @@
%h1.page-title.gl-font-size-h-display.gl-mr-5= _('Search')
= render_if_exists 'search/form_elasticsearch', attrs: { class: 'mb-2 mb-sm-0 align-self-center' }
-.gl-mt-3
- #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 } }
+#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 } }
- if @search_term
= render 'search/results'
diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml
index 8a626f1620b..547f12ac8fc 100644
--- a/app/views/shared/_label.html.haml
+++ b/app/views/shared/_label.html.haml
@@ -31,14 +31,13 @@
%ul
- if label.project_label? && label.project.group && can?(current_user, :admin_label, label.project.group)
%li
- = render Pajamas::ButtonComponent.new(category: :tertiary,
+ = render Pajamas::ButtonComponent.new(category: :tertiary, variant: :link,
button_options: { class: 'js-promote-project-label-button', data: { url: promote_project_label_path(label.project, label), label_title: label.title, label_color: label.color, label_text_color: label.text_color, group_name: label.project.group.name } }) do
= _('Promote to group label')
%li
- %span
- = render Pajamas::ButtonComponent.new(category: :tertiary,
- button_options: { class: 'text-danger js-delete-label-modal-button', data: { label_name: label.name, subject_name: label.subject_name, destroy_path: label.destroy_path } }) do
- = _('Delete')
+ = render Pajamas::ButtonComponent.new(category: :tertiary, variant: :link,
+ button_options: { class: 'text-danger js-delete-label-modal-button', data: { label_name: label.name, subject_name: label.subject_name, destroy_path: label.destroy_path } }) do
+ = _('Delete')
- if current_user
%li.gl-display-inline-block.label-subscription.js-label-subscription.gl-ml-3
- if label.can_subscribe_to_label_in_different_levels?
diff --git a/app/views/shared/_mobile_clone_panel.html.haml b/app/views/shared/_mobile_clone_panel.html.haml
index 8b7ef838d2b..aa3043b8fd6 100644
--- a/app/views/shared/_mobile_clone_panel.html.haml
+++ b/app/views/shared/_mobile_clone_panel.html.haml
@@ -9,8 +9,8 @@
%ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown{ data: { dropdown: true } }
- if ssh_enabled?
%li
- = dropdown_item_with_description(ssh_copy_label, project.ssh_url_to_repo, href: project.ssh_url_to_repo, data: { clone_type: 'ssh' }, default: true)
+ = dropdown_item_with_description(ssh_copy_label, ssh_clone_url_to_repo(project), href: ssh_clone_url_to_repo(project), data: { clone_type: 'ssh' }, default: true)
- if http_enabled?
%li
- = dropdown_item_with_description(http_copy_label, project.http_url_to_repo, href: project.http_url_to_repo, data: { clone_type: 'http' })
+ = dropdown_item_with_description(http_copy_label, http_clone_url_to_repo(project), href: http_clone_url_to_repo(project), data: { clone_type: 'http' })
= render_if_exists 'shared/mobile_kerberos_clone'
diff --git a/app/views/shared/doorkeeper/applications/_show.html.haml b/app/views/shared/doorkeeper/applications/_show.html.haml
index 5b0cff2c1c0..19f4c971c1d 100644
--- a/app/views/shared/doorkeeper/applications/_show.html.haml
+++ b/app/views/shared/doorkeeper/applications/_show.html.haml
@@ -15,14 +15,17 @@
%td
= _('Secret')
%td
- - if Feature.enabled?('hash_oauth_secrets')
- - if @application.plaintext_secret
- = clipboard_button(clipboard_text: @application.plaintext_secret, button_text: _('Copy'), title: _("Copy secret"), class: "btn btn-default btn-md gl-button")
- %span= _('This is the only time the secret is accessible. Copy the secret and store it securely.')
- - else
- = _('The secret is only available when you first create the application.')
+ - if @application.plaintext_secret
+ = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-5'}) do |c|
+ = c.body do
+ = _('This is the only time the secret is accessible. Copy the secret and store it securely.')
+ = clipboard_button(clipboard_text: @application.plaintext_secret, button_text: _('Copy'), title: _("Copy secret"), class: "btn btn-default btn-md gl-button")
- else
- = clipboard_button(clipboard_text: @application.secret, button_text: _('Copy'), title: _("Copy secret"), class: "btn btn-default btn-md gl-button")
+ = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-5'}) do |c|
+ = c.body do
+ = _('The secret is only available when you create the application or renew the secret.')
+ = render 'shared/doorkeeper/applications/update_form', path: renew_path
+
%tr
%td
= _('Callback URL')
diff --git a/app/views/shared/doorkeeper/applications/_update_form.html.haml b/app/views/shared/doorkeeper/applications/_update_form.html.haml
new file mode 100644
index 00000000000..1bee3288639
--- /dev/null
+++ b/app/views/shared/doorkeeper/applications/_update_form.html.haml
@@ -0,0 +1,3 @@
+- path = local_assigns.fetch(:path)
+= form_for(@application, url: path, html: {class: 'gl-display-inline-block', method: "put"}) do |f|
+ = submit_tag s_('AuthorizedApplication|Renew secret'), data: { confirm: s_("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."), confirm_btn_variant: "danger" }, aria: { label: s_('AuthorizedApplication|Renew secret') }, class: 'gl-button btn btn-md btn-default'
diff --git a/app/views/shared/empty_states/_issues.html.haml b/app/views/shared/empty_states/_issues.html.haml
index 37f7fbc0de5..ad6e5578878 100644
--- a/app/views/shared/empty_states/_issues.html.haml
+++ b/app/views/shared/empty_states/_issues.html.haml
@@ -4,7 +4,6 @@
- opened_issues_count = issuables_count_for_state(:issues, :opened)
- is_opened_state = params[:state] == 'opened'
- is_closed_state = params[:state] == 'closed'
-- issuable_type = 'issues'
- can_edit = can?(current_user, :admin_project, @project)
.row.empty-state
@@ -43,7 +42,7 @@
= link_to _('New issue'), button_path, class: 'gl-button btn btn-confirm', id: 'new_issue_link'
- if show_import_button
- .js-csv-import-export-buttons{ data: { show_import_button: 'true', issuable_type: issuable_type, import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), container_class: 'gl-w-full gl-sm-w-auto gl-sm-mr-3 gl-display-inline-flex gl-vertical-align-middle', show_label: 'true' } }
+ .js-csv-import-export-buttons{ data: { show_import_button: 'true', issuable_type: 'issue', import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), container_class: 'gl-w-full gl-sm-w-auto gl-sm-mr-3 gl-display-inline-flex gl-vertical-align-middle', show_label: 'true' } }
%hr
%p.gl-text-center.gl-mb-0
%strong
diff --git a/app/views/shared/icons/_mr_widget_empty_state.svg b/app/views/shared/icons/_mr_widget_empty_state.svg
deleted file mode 100644
index a75eee846c9..00000000000
--- a/app/views/shared/icons/_mr_widget_empty_state.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="256" height="146" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><mask id="d" x="0" y="0" width="178.7" height="115.4" fill="#FFF"><use xlink:href="#a"/></mask><mask id="e" x="0" y="0" width="43.1" height="36.4" fill="#FFF"><use xlink:href="#b"/></mask><mask id="f" x="0" y="0" width="43.1" height="36.4" fill="#FFF"><use xlink:href="#c"/></mask><path d="M8.8 31.5H33a10 10 0 0 0 10-10V10A10 10 0 0 0 33 0H10A10 10 0 0 0 0 10v11.6c0 1.2.2 2.4.7 3.5H0v7.5c0 4 2.4 5 5.3 2.2l3.5-3.3z" id="b"/><path d="M8.8 31.5H33a10 10 0 0 0 10-10V10A10 10 0 0 0 33 0H10A10 10 0 0 0 0 10v11.6c0 1.2.2 2.4.7 3.5H0v7.5c0 4 2.4 5 5.3 2.2l3.5-3.3z" id="c"/><rect id="a" width="178.7" height="115.4" rx="10"/></defs><g fill="none" fill-rule="evenodd"><g transform="translate(0 3.9)" fill="var(--gray-10, #f9f9f9)"><rect x="19.3" width="77.1" height="14.2" rx="7.1"/><rect y="28.4" width="84.9" height="14.2" rx="7.1"/><rect x="133.7" y="42.5" width="122.1" height="14.2" rx="7.1"/><rect x="82.9" y="127" width="101.6" height="14.2" rx="7.1"/><rect x="42.4" y="99.3" width="101.6" height="14.2" rx="7.1"/><rect x="19.9" y="70.9" width="225" height="14.2" rx="7.1"/><path d="M98.4 14.2h-85 13.9a7.1 7.1 0 0 1 7 7 7 7 0 0 1-7 7.2H13.5h84.9-23.5a7.1 7.1 0 0 1-7-7.1 7 7 0 0 1 7-7.1h23.5zm162 42.5H185h23.5a7.1 7.1 0 0 1 7 7.1 7 7 0 0 1-7 7.1H185h75.3-23.5a7.1 7.1 0 0 1-7-7 7 7 0 0 1 7-7.2h23.5zM103.5 85.1H28.3h23.4a7.1 7.1 0 0 1 7.1 7 7 7 0 0 1-7 7.2H28.2h75.2H80a7.1 7.1 0 0 1-7.1-7.1 7 7 0 0 1 7-7.1h23.5zm48.2 28.4H76.5h13.8a7.1 7.1 0 0 1 7 7 7 7 0 0 1-7 7.1H76.5h75.2-33a7.1 7.1 0 0 1-7.2-7 7 7 0 0 1 7.1-7.1h33.1z"/></g><g transform="translate(38.6 12.2)"><use stroke="var(--gray-200, #EEE)" mask="url(#d)" stroke-width="8" fill="var(--white, #fff)" xlink:href="#a"/><path fill="var(--gray-200, #EEE)" d="M2.6 18.7h174.2v2.6H2.6z"/><g fill="var(--gray-100, #EEE)"><g transform="translate(21.9 38.7)"><g fill="var(--dark-icon-color-purple-2, #B5A7DD)"><rect y=".6" width="3.9" height="1.3" rx=".6"/><rect y="7.7" width="3.9" height="1.3" rx=".6"/><rect y="14.8" width="3.9" height="1.3" rx=".6"/></g><rect x="9.6" width="9.6" height="2.6" rx="1.3"/><rect x="46.3" width="9.6" height="2.6" rx="1.3"/><rect x="25.1" y="14.2" width="9.6" height="2.6" rx="1.3"/><rect fill="#FC6D26" x="34.1" y="7.1" width="9.6" height="2.6" rx="1.3"/><rect fill="#FC6D26" opacity=".5" x="30.9" width="12.9" height="2.6" rx="1.3"/><rect x="9.6" y="14.2" width="12.9" height="2.6" rx="1.3"/><rect x="18.6" y="7.1" width="12.9" height="2.6" rx="1.3"/><rect fill="#FC6D26" x="21.9" width="6.4" height="2.6" rx="1.3"/><rect x="9.6" y="7.1" width="6.4" height="2.6" rx="1.3"/></g><g transform="translate(21.9 60)"><g fill="var(--dark-icon-color-purple-2, #B5A7DD)"><rect y=".6" width="3.9" height="1.3" rx=".6"/><rect y="7.7" width="3.9" height="1.3" rx=".6"/><rect y="14.8" width="3.9" height="1.3" rx=".6"/></g><rect fill="#FC6D26" x="9.6" width="9.6" height="2.6" rx="1.3"/><rect x="46.3" width="9.6" height="2.6" rx="1.3"/><rect fill="#FC6D26" opacity=".5" x="25.1" y="14.2" width="9.6" height="2.6" rx="1.3"/><rect x="34.1" y="7.1" width="9.6" height="2.6" rx="1.3"/><rect fill="#FC6D26" x="30.9" width="12.9" height="2.6" rx="1.3"/><rect fill="#FC6D26" x="9.6" y="14.2" width="12.9" height="2.6" rx="1.3"/><rect x="18.6" y="7.1" width="12.9" height="2.6" rx="1.3"/><rect fill="#FC6D26" opacity=".5" x="21.9" width="6.4" height="2.6" rx="1.3"/><rect x="9.6" y="7.1" width="6.4" height="2.6" rx="1.3"/></g><g transform="translate(21.9 81.2)"><g fill="var(--dark-icon-color-purple-2, #B5A7DD)"><rect y=".6" width="3.9" height="1.3" rx=".6"/><rect y="7.7" width="3.9" height="1.3" rx=".6"/><rect y="14.8" width="3.9" height="1.3" rx=".6"/></g><rect x="9.6" width="9.6" height="2.6" rx="1.3"/><rect x="46.3" width="9.6" height="2.6" rx="1.3"/><rect x="25.1" y="14.2" width="9.6" height="2.6" rx="1.3"/><rect x="34.1" y="7.1" width="9.6" height="2.6" rx="1.3"/><rect fill="#FC6D26" x="30.9" width="12.9" height="2.6" rx="1.3"/><rect x="9.6" y="14.2" width="12.9" height="2.6" rx="1.3"/><rect x="18.6" y="7.1" width="12.9" height="2.6" rx="1.3"/><rect fill="#FC6D26" opacity=".5" x="21.9" width="6.4" height="2.6" rx="1.3"/><rect x="9.6" y="7.1" width="6.4" height="2.6" rx="1.3"/></g><g transform="translate(101 38)"><g fill="var(--dark-icon-color-purple-3, #6B4FBB)"><rect opacity=".5" x="25.1" y="14.2" width="9.6" height="2.6" rx="1.3"/><rect x="34.1" y="7.1" width="9.6" height="2.6" rx="1.3"/><rect opacity=".5" x="30.9" width="12.9" height="2.6" rx="1.3"/><rect x="9.6" y="14.2" width="12.9" height="2.6" rx="1.3"/><rect x="21.9" width="6.4" height="2.6" rx="1.3"/><rect opacity=".5" x="25.1" y="35.5" width="9.6" height="2.6" rx="1.3"/><rect x="18.6" y="28.4" width="9.6" height="2.6" rx="1.3"/><rect x="30.9" y="21.3" width="12.9" height="2.6" rx="1.3"/><rect x="9.6" y="42.5" width="9.6" height="2.6" rx="1.3"/><rect opacity=".5" x="34.1" y="49.6" width="9.6" height="2.6" rx="1.3"/><rect x="18.6" y="49.6" width="12.9" height="2.6" rx="1.3"/></g><g fill="var(--dark-icon-color-orange-1, #FDE5D8)"><rect y=".6" width="3.9" height="1.3" rx=".6"/><rect y="7.7" width="3.9" height="1.3" rx=".6"/><rect y="14.8" width="3.9" height="1.3" rx=".6"/><rect y="21.9" width="3.9" height="1.3" rx=".6"/><rect y="29" width="3.9" height="1.3" rx=".6"/><rect y="36.1" width="3.9" height="1.3" rx=".6"/><rect y="43.2" width="3.9" height="1.3" rx=".6"/><rect y="50.3" width="3.9" height="1.3" rx=".6"/><rect y="57.4" width="3.9" height="1.3" rx=".6"/></g><rect x="9.6" width="9.6" height="2.6" rx="1.3"/><rect x="46.3" width="9.6" height="2.6" rx="1.3"/><rect x="18.6" y="7.1" width="12.9" height="2.6" rx="1.3"/><rect x="9.6" y="7.1" width="6.4" height="2.6" rx="1.3"/><rect x="9.6" y="21.3" width="9.6" height="2.6" rx="1.3"/><rect x="37.3" y="14.2" width="9.6" height="2.6" rx="1.3"/><rect x="9.6" y="35.5" width="12.9" height="2.6" rx="1.3"/><rect x="21.9" y="21.3" width="6.4" height="2.6" rx="1.3"/><rect x="9.6" y="28.4" width="6.4" height="2.6" rx="1.3"/><rect x="30.9" y="28.4" width="6.4" height="2.6" rx="1.3"/><rect x="39.9" y="28.4" width="6.4" height="2.6" rx="1.3"/><rect x="49.5" y="14.2" width="6.4" height="2.6" rx="1.3"/><rect x="25.1" y="56.7" width="9.6" height="2.6" rx="1.3"/><rect x="9.6" y="56.7" width="12.9" height="2.6" rx="1.3"/><rect x="21.9" y="42.5" width="6.4" height="2.6" rx="1.3"/><rect x="46.3" y="49.6" width="6.4" height="2.6" rx="1.3"/><rect x="9.6" y="49.6" width="6.4" height="2.6" rx="1.3"/></g></g></g><g transform="translate(196)"><use stroke="var(--dark-icon-color-orange-1, #FDE5D8)" mask="url(#e)" stroke-width="8" fill="var(--white, #fff)" xlink:href="#b"/><g fill="var(--dark-icon-color-orange-2, #FDB692)"><rect x="9" y="9" width="18.6" height="1.9" rx="1"/><rect x="9" y="14.8" width="25.1" height="1.9" rx="1"/><rect x="9" y="20.6" width="18.6" height="1.9" rx="1"/></g></g><g transform="translate(189 41.3)"><ellipse stroke="#FC6D26" stroke-width="3" fill="#fde5d8" cx="10.3" cy="9.7" rx="9.6" ry="9.7"/><path d="M0 9a8.4 8.4 0 0 0 8-4.3m1-4V0" stroke="#FC6D26" stroke-width="2"/><path d="M5 2a10.3 10.3 0 0 0 8.5 4.4c2.1 0 4-.6 5.7-1.7" stroke="#FC6D26" stroke-width="2"/><circle fill="#FC6D26" cx="6.8" cy="11.3" r="1"/><circle fill="#FC6D26" cx="13.8" cy="11.3" r="1"/></g><g transform="translate(47 96)"><ellipse stroke="var(--dark-icon-color-purple-3, #6B4FBB)" stroke-width="3" fill="#F4F1FA" cx="9.6" cy="10.3" rx="9.6" ry="9.7"/><path d="m12.9 4.5-1.7-2-1.6 2-1.6-2-1.6 2-1.6-2-1.6 2H1.5A9.6 9.6 0 0 1 9.6 0c3.5 0 6.5 1.8 8.2 4.5h-1.7l-1.6-2-1.6 2z" fill="var(--dark-icon-color-purple-3, #6B4FBB)"/><circle fill="var(--dark-icon-color-purple-3, #6B4FBB)" cx="6.1" cy="11.3" r="1"/><circle fill="var(--dark-icon-color-purple-3, #6B4FBB)" cx="13.2" cy="11.3" r="1"/></g><g transform="matrix(-1 0 0 1 56.6 54.8)" fill="var(--dark-icon-color-purple-2, #b5a8dd)"><use stroke="var(--dark-icon-color-purple-1, #E2DCF2)" mask="url(#f)" stroke-width="8" fill="var(--white, #fff)" xlink:href="#c"/><rect x="15.4" y="9" width="18.6" height="1.9" rx="1"/><rect x="21.9" y="14.8" width="12.2" height="1.9" rx="1"/><rect x="21.9" y="20.6" width="12.2" height="1.9" rx="1"/></g></g></svg>
diff --git a/app/views/shared/integrations/_slack_notifications_deprecation_alert.html.haml b/app/views/shared/integrations/_slack_notifications_deprecation_alert.html.haml
new file mode 100644
index 00000000000..de4439a8fde
--- /dev/null
+++ b/app/views/shared/integrations/_slack_notifications_deprecation_alert.html.haml
@@ -0,0 +1,20 @@
+- if Gitlab.com?
+ = render Pajamas::AlertComponent.new(title: _('Slack notifications integration is deprecated'),
+ variant: :warning,
+ dismissible: false,
+ alert_options: { class: 'gl-mt-5', data: { testid: "slack-notifications-deprecation" } }) do |c|
+ = c.body do
+ - help_page_link = help_page_url('user/project/integrations/gitlab_slack_application')
+ - learn_more_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_link }
+
+ = html_escape(s_('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}.')) % { learn_more_link_start: learn_more_link, link_end: '</a>'.html_safe }
+- else
+ = render Pajamas::AlertComponent.new(title: _('Slack notifications will be deprecated'),
+ variant: :warning,
+ dismissible: false,
+ alert_options: { class: 'gl-mt-5', data: { testid: "slack-notifications-deprecation" } }) do |c|
+ = c.body do
+ - help_page_link = help_page_url('user/project/integrations/gitlab_slack_application')
+ - learn_more_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_link }
+
+ = html_escape(s_('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}.')) % { learn_more_link_start: learn_more_link, link_end: '</a>'.html_safe }
diff --git a/app/views/shared/integrations/prometheus/_custom_metrics.html.haml b/app/views/shared/integrations/prometheus/_custom_metrics.html.haml
index dda84e0fb9e..e5ddc055aef 100644
--- a/app/views/shared/integrations/prometheus/_custom_metrics.html.haml
+++ b/app/views/shared/integrations/prometheus/_custom_metrics.html.haml
@@ -6,13 +6,13 @@
= link_to s_('PrometheusService|More information'), help_page_path('operations/metrics/index.md', anchor: 'adding-custom-metrics'), target: '_blank', rel: "noopener noreferrer"
.col-lg-9
- .card.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}" } }
- .card-header
+ = 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|
+ - c.header do
%strong
= s_('PrometheusService|Custom metrics')
- = gl_badge_tag 0, nil, class: 'js-custom-monitored-count'
+ = gl_badge_tag 0, nil, class: 'gl-ml-2 js-custom-monitored-count'
= link_to s_('PrometheusService|New metric'), new_project_prometheus_metric_path(project), class: 'btn gl-button btn-confirm gl-ml-auto js-new-metric-button hidden'
- .card-body
+ - c.body do
.flash-container.hidden
.flash-warning
.flash-text
diff --git a/app/views/shared/integrations/prometheus/_metrics.html.haml b/app/views/shared/integrations/prometheus/_metrics.html.haml
index c74dbfd8b15..a8125c3e3ec 100644
--- a/app/views/shared/integrations/prometheus/_metrics.html.haml
+++ b/app/views/shared/integrations/prometheus/_metrics.html.haml
@@ -8,12 +8,12 @@
= link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus'), target: '_blank', rel: "noopener noreferrer"
.col-lg-9
- .card.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') } }
- .card-header
+ = 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|
+ - c.header do
%strong
= s_('PrometheusService|Common metrics')
- = gl_badge_tag 0, nil, class: 'js-monitored-count'
- .card-body
+ = gl_badge_tag 0, nil, class: 'js-monitored-count'
+ - c.body do
.loading-metrics.js-loading-metrics
%p.m-3
= gl_loading_icon(inline: true, css_class: 'metrics-load-spinner')
@@ -23,13 +23,13 @@
= s_('PrometheusService|Waiting for your first deployment to an environment to find common metrics')
%ul.list-unstyled.metrics-list.hidden.js-metrics-list
- .card.hidden.js-panel-missing-env-vars
- .card-header
+ = render Pajamas::CardComponent.new(body_options: { class: 'hidden gl-p-0' }, card_options: { class: 'hidden js-panel-missing-env-vars' }) do |c|
+ - c.header do
= sprite_icon('chevron-lg-right', css_class: 'panel-toggle js-panel-toggle-right')
= sprite_icon('chevron-lg-down', css_class: 'panel-toggle js-panel-toggle-down hidden')
= s_('PrometheusService|Missing environment variable')
= gl_badge_tag 0, nil, class: 'js-env-var-count'
- .card-body.hidden
+ - c.body do
.flash-container
.flash-notice
.flash-text
diff --git a/app/views/shared/issuable/_feed_buttons.html.haml b/app/views/shared/issuable/_feed_buttons.html.haml
index 94b7fe14721..e0f676021a1 100644
--- a/app/views/shared/issuable/_feed_buttons.html.haml
+++ b/app/views/shared/issuable/_feed_buttons.html.haml
@@ -1,8 +1,8 @@
- show_calendar_button = local_assigns.fetch(:show_calendar_button, true)
-= render Pajamas::ButtonComponent.new(href: safe_params.merge(rss_url_options), icon: 'rss', button_options: { class: 'has-tooltip', 'aria-label': _('Subscribe to RSS feed'), data: { container: 'body', testid: 'rss-feed-link' } }) do
- = _('Subscribe to RSS feed')
+= render Pajamas::ButtonComponent.new(href: safe_params.merge(rss_url_options), button_options: { class: 'has-tooltip btn-icon', title: _('Subscribe to RSS feed'), 'aria-label': _('Subscribe to RSS feed'), data: { container: 'body', testid: 'rss-feed-link' } }) do
+ = sprite_icon('rss')
- if show_calendar_button
- = render Pajamas::ButtonComponent.new(href: safe_params.merge(calendar_url_options), icon: 'calendar', button_options: { class: 'has-tooltip', 'aria-label': _('Subscribe to calendar'), data: { container: 'body' } }) do
- = _('Subscribe to calendar')
+ = render Pajamas::ButtonComponent.new(href: safe_params.merge(calendar_url_options), button_options: { class: 'has-tooltip btn-icon', title: _('Subscribe to calendar'), 'aria-label': _('Subscribe to calendar'), data: { container: 'body' } }) do
+ = sprite_icon('calendar')
diff --git a/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml
index af63839d7c1..3c4ee01d04f 100644
--- a/app/views/shared/issuable/_label_dropdown.html.haml
+++ b/app/views/shared/issuable/_label_dropdown.html.haml
@@ -26,7 +26,7 @@
- apply_is_default_styles = (selected.nil? || selected.empty?) && !no_default_styles
%span.dropdown-toggle-text{ class: ("is-default" if apply_is_default_styles) }
= multi_label_name(selected, label_name)
- = sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
+ = sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon")
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable.dropdown-extended-height
= render partial: "shared/issuable/label_page_default", locals: { title: dropdown_title, show_footer: show_footer, show_create: show_create }
- if show_create && project && can?(current_user, :admin_label, project)
diff --git a/app/views/shared/issuable/_label_page_create.html.haml b/app/views/shared/issuable/_label_page_create.html.haml
index eb3acd8e055..96167db80b4 100644
--- a/app/views/shared/issuable/_label_page_create.html.haml
+++ b/app/views/shared/issuable/_label_page_create.html.haml
@@ -10,9 +10,9 @@
%input#new_label_name.default-dropdown-input{ type: "text", placeholder: _('Name new label') }
.suggest-colors.suggest-colors-dropdown
= render_suggested_colors
- .dropdown-label-color-input
- .dropdown-label-color-preview.js-dropdown-label-color-preview
- %input#new_label_color.default-dropdown-input{ type: "text", placeholder: _('Assign custom color like #FF0000') }
+ .dropdown-label-color-input.gl-display-flex
+ %input.dropdown-label-color-preview.js-dropdown-label-color-preview.gl-w-7.gl-h-7.gl-border-1.gl-border-solid.gl-border-gray-500.gl-rounded-top-right-none.gl-rounded-bottom-right-none{ class: "gl-border-r-0!", type: "color", placeholder: _('Select color') }
+ %input#new_label_color.default-dropdown-input.gl-rounded-top-left-none.gl-rounded-bottom-left-none{ type: "text", placeholder: _('Assign custom color like #FF0000') }
- if show_add_list
.dropdown-label-input{ class: add_list_class }
%label
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index 72940b64801..95c5f51c339 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -162,6 +162,14 @@
%li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
%button.gl-button.btn.btn-link{ type: 'button' }
= _('No')
+ #js-dropdown-approved.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul.filter-dropdown{ data: { dropdown: true } }
+ %li.filter-dropdown-item{ data: { value: 'yes', capitalize: true } }
+ %button.gl-button.btn.btn-link{ type: 'button' }
+ = _('Yes')
+ %li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
+ %button.gl-button.btn.btn-link{ type: 'button' }
+ = _('No')
#js-dropdown-confidential.filtered-search-input-dropdown-menu.dropdown-menu
%ul.filter-dropdown{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'yes', capitalize: true } }
diff --git a/app/views/shared/issuable/_sidebar_user_dropdown.html.haml b/app/views/shared/issuable/_sidebar_user_dropdown.html.haml
index c058e7ebe3e..9bfdacc8cfd 100644
--- a/app/views/shared/issuable/_sidebar_user_dropdown.html.haml
+++ b/app/views/shared/issuable/_sidebar_user_dropdown.html.haml
@@ -14,8 +14,6 @@
%li
.js-invite-members-trigger{ data: { trigger_element: 'anchor',
display_text: _('Invite Members'),
- event: 'click_invite_members',
- trigger_source: local_assigns.fetch(:trigger_source),
- label: data['track-label'] } }
+ trigger_source: local_assigns.fetch(:trigger_source) } }
- else
= dropdown_tag(data['dropdown-title'], options: options)
diff --git a/app/views/shared/issuable/form/_type_selector.html.haml b/app/views/shared/issuable/form/_type_selector.html.haml
index a94ef70b2d5..6d4cd83d55b 100644
--- a/app/views/shared/issuable/form/_type_selector.html.haml
+++ b/app/views/shared/issuable/form/_type_selector.html.haml
@@ -10,7 +10,7 @@
%button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
%span.dropdown-toggle-text.is-default
= issuable.issue_type.capitalize || _("Select type")
- = sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
+ = sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon")
.dropdown-menu.dropdown-menu-selectable.dropdown-select
.dropdown-title.gl-display-flex
%span.gl-ml-auto
diff --git a/app/views/shared/issue_type/_details_content.html.haml b/app/views/shared/issue_type/_details_content.html.haml
index e1a9b30ef67..e189cc34899 100644
--- a/app/views/shared/issue_type/_details_content.html.haml
+++ b/app/views/shared/issue_type/_details_content.html.haml
@@ -2,7 +2,7 @@
- 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-pb-0.gl-border-none
+ .detail-page-description.content-block.js-detail-page-description.gl-pt-2.gl-pb-0.gl-border-none
#js-issuable-app{ data: { initial: issuable_initial_data(issuable).to_json,
issuable_id: issuable.id,
full_path: @project.full_path,
diff --git a/app/views/shared/labels/_form.html.haml b/app/views/shared/labels/_form.html.haml
index 9ef4b9e084d..5d749b16eee 100644
--- a/app/views/shared/labels/_form.html.haml
+++ b/app/views/shared/labels/_form.html.haml
@@ -16,7 +16,7 @@
= f.label :color, _("Background color")
.input-group
.input-group-prepend
- .input-group-text.label-color-preview &nbsp;
+ %input.label-color-preview.gl-w-7.gl-h-full.gl-border-1.gl-border-solid.gl-border-gray-500.gl-border-r-0.gl-rounded-top-right-none.gl-rounded-bottom-right-none{ type: "color", placeholder: _('Select color') }
= f.text_field :color, class: "gl-form-input form-control", data: { qa_selector: 'label_color_field' }
.form-text.text-muted
= _('Choose any color.')
diff --git a/app/views/shared/milestones/_description.html.haml b/app/views/shared/milestones/_description.html.haml
index fc25c7e8f89..d7908b1c210 100644
--- a/app/views/shared/milestones/_description.html.haml
+++ b/app/views/shared/milestones/_description.html.haml
@@ -1,4 +1,4 @@
-.detail-page-description.milestone-detail
+.detail-page-description.milestone-detail.gl-py-5
%h2.gl-m-0{ data: { qa_selector: "milestone_title_content" } }
= markdown_field(milestone, :title)
.gl-font-sm.gl-text-secondary.gl-font-base.gl-font-weight-normal.gl-line-height-normal{ data: { qa_selector: 'milestone_id_content' }, itemprop: 'identifier' }
@@ -9,5 +9,5 @@
- if milestone.try(:description).present?
%div{ data: { qa_selector: "milestone_description_content" } }
- .description.md.gl-px-0.gl-pt-4.gl-border-1.gl-border-t-solid.gl-border-gray-100
+ .description.md.gl-px-0.gl-pt-4
= markdown_field(milestone, :description)
diff --git a/app/views/shared/milestones/_form_dates.html.haml b/app/views/shared/milestones/_form_dates.html.haml
index 50e3e8e195c..3e75775bf73 100644
--- a/app/views/shared/milestones/_form_dates.html.haml
+++ b/app/views/shared/milestones/_form_dates.html.haml
@@ -1,11 +1,14 @@
-.form-group.row
- .col-form-label.col-sm-2
+.gl-form-group
+ %div
= f.label :start_date, _('Start Date')
- .col-sm-4
- = f.gitlab_ui_datepicker :start_date, data: { qa_selector: "start_date_field" }, placeholder: _('Select start date'), autocomplete: 'off'
- %a.inline.float-right.gl-mt-2.js-clear-start-date{ href: "#" }= _('Clear start date')
- .col-form-label.col-sm-2
+ %div
+ .issuable-form-select-holder
+ = f.gitlab_ui_datepicker :start_date, data: { qa_selector: "start_date_field" }, placeholder: _('Select start date'), autocomplete: 'off'
+ %a.gl-white-space-nowrap.gl-pl-4.js-clear-start-date{ href: "#" }= _('Clear start date')
+.gl-form-group
+ %div
= f.label :due_date, _('Due Date')
- .col-sm-4
- = f.gitlab_ui_datepicker :due_date, data: { qa_selector: "due_date_field" }, placeholder: _('Select due date'), autocomplete: 'off'
- %a.inline.float-right.gl-mt-2.js-clear-due-date{ href: "#" }= _('Clear due date')
+ %div
+ .issuable-form-select-holder
+ = f.gitlab_ui_datepicker :due_date, data: { qa_selector: "due_date_field" }, placeholder: _('Select due date'), autocomplete: 'off'
+ %a.gl-white-space-nowrap.gl-pl-4.js-clear-due-date{ href: "#" }= _('Clear due date')
diff --git a/app/views/shared/nav/_explore_scope_header.html.haml b/app/views/shared/nav/_explore_scope_header.html.haml
new file mode 100644
index 00000000000..da22d6dbcf2
--- /dev/null
+++ b/app/views/shared/nav/_explore_scope_header.html.haml
@@ -0,0 +1,6 @@
+%li.context-header
+ = link_to explore_root_url, title: _('Explore'), class: 'has-tooltip', data: { container: 'body', placement: 'right' } do
+ %span.avatar-container.icon-avatar.rect-avatar.s32
+ = sprite_icon('compass', size: 18)
+ %span.sidebar-context-title
+ = _('Explore')
diff --git a/app/views/shared/nav/_user_settings_scope_header.html.haml b/app/views/shared/nav/_user_settings_scope_header.html.haml
new file mode 100644
index 00000000000..c1601822736
--- /dev/null
+++ b/app/views/shared/nav/_user_settings_scope_header.html.haml
@@ -0,0 +1,4 @@
+%li.context-header
+ = link_to profile_path, title: _('User Settings'), class: 'has-tooltip', data: { container: 'body', placement: 'right' } do
+ = render Pajamas::AvatarComponent.new(current_user, size: 32, alt: current_user.name, class: 'gl-mr-3 js-sidebar-user-avatar', avatar_options: { data: { testid: 'sidebar-user-avatar' } })
+ %span.sidebar-context-title= _('User Settings')
diff --git a/app/views/shared/topics/_topic.html.haml b/app/views/shared/topics/_topic.html.haml
index 83d5ecdb833..9b9630733fd 100644
--- a/app/views/shared/topics/_topic.html.haml
+++ b/app/views/shared/topics/_topic.html.haml
@@ -5,9 +5,8 @@
= render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-5' },
body_options: { class: 'gl-display-flex gl-align-items-center' }) do |c|
= c.body do
- .avatar-container.rect-avatar.s40.gl-flex-shrink-0
- = link_to detail_page_link do
- = topic_icon(topic, class: "avatar s40")
+ = link_to detail_page_link do
+ = render Pajamas::AvatarComponent.new(topic, size: 48, alt: '', class: 'gl-mr-3')
= link_to detail_page_link do
- if topic.title_or_name.length > max_topic_title_length
%h5.gl-str-truncated.has-tooltip{ title: topic.title_or_name }
diff --git a/app/views/shared/wikis/_wiki_directory.html.haml b/app/views/shared/wikis/_wiki_directory.html.haml
index 5c2233a4db2..ced51e1f697 100644
--- a/app/views/shared/wikis/_wiki_directory.html.haml
+++ b/app/views/shared/wikis/_wiki_directory.html.haml
@@ -1,6 +1,9 @@
%li{ class: active_when(params[:id] == wiki_directory.slug), data: { qa_selector: 'wiki_directory_content' } }
- = link_to wiki_page_path(@wiki, wiki_directory), data: { qa_selector: 'wiki_dir_page_link', qa_page_name: wiki_directory.title } do
- = wiki_directory.title
+ .gl-relative.gl-display-flex.gl-align-items-center.js-wiki-list-toggle.wiki-list<
+ = sprite_icon('chevron-right', css_class: 'js-wiki-list-expand-button wiki-list-expand-button gl-mr-2 gl-cursor-pointer')
+ = sprite_icon('chevron-down', css_class: 'js-wiki-list-collapse-button wiki-list-collapse-button gl-mr-2 gl-cursor-pointer')
+ = link_to wiki_page_path(@wiki, wiki_directory), data: { qa_selector: 'wiki_dir_page_link', qa_page_name: wiki_directory.title } do
+ = wiki_directory.title
%ul
- wiki_directory.entries.each do |entry|
= render partial: entry.to_partial_path, object: entry, locals: { context: context }
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index eb9465a409f..583f25b68eb 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -4,8 +4,9 @@
- add_page_startup_graphql_call('snippet/project_permissions', { fullPath: @snippet.project_id })
- else
- add_page_startup_graphql_call('snippet/user_permissions')
-- @hide_top_links = true
-- add_to_breadcrumbs _("Snippets"), dashboard_snippets_path
+- if @snippet.author != current_user
+ -# Different breadcrumbs if this page is rendered as part of the Explore section
+ - add_to_breadcrumbs _("Snippets"), explore_snippets_path
- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
- content_for :prefetch_asset_tags do
diff --git a/app/views/users/_profile_basic_info.html.haml b/app/views/users/_profile_basic_info.html.haml
index b62440fcbde..c916b6c3d45 100644
--- a/app/views/users/_profile_basic_info.html.haml
+++ b/app/views/users/_profile_basic_info.html.haml
@@ -1,9 +1,9 @@
-.gl-text-gray-900.gl-mt-4
- = render 'middle_dot_divider' do
+.gl-text-gray-900
+ = render 'middle_dot_divider', stacking: true do
@#{@user.username}
- if can?(current_user, :read_user_profile, @user)
- = render 'middle_dot_divider' do
+ = 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)
- = render 'middle_dot_divider' do
+ = render 'middle_dot_divider', stacking: true do
= s_('Member since %{date}') % { date: @user.created_at.to_date.to_s(:long) }
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index b9290972656..3543d5c4336 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -6,6 +6,9 @@
- page_itemtype 'http://schema.org/Person'
- add_page_specific_style 'page_bundles/profile'
- link_classes = "flex-grow-1 mx-1 "
+- if show_super_sidebar?
+ - @left_sidebar = true
+ - nav "user_profile"
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity")
@@ -43,137 +46,129 @@
= _('Follow')
.profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?)] }
- .avatar-holder
- = link_to avatar_icon_for_user(@user, 400, current_user: current_user), target: '_blank', rel: 'noopener noreferrer' do
- = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" })
-
- - if @user.blocked? || !@user.confirmed?
- .user-info
- %h1.cover-title
- = user_display_name(@user)
- = render "users/profile_basic_info"
- - else
- .user-info
- %h1.cover-title{ itemprop: 'name' }
- = @user.name
- - if @user.pronouns.present?
- %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle
- = "(#{@user.pronouns})"
- - if @user.status&.busy?
- %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle= s_("UserProfile|(Busy)")
-
- - if @user.pronunciation.present?
- .gl-align-items-center
- %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
- = emoji_icon(@user.status.emoji, class: 'gl-mr-2')
- = markdown_field(@user.status, :message)
+ .gl-display-inline-block.gl-mx-8.gl-vertical-align-top
+ .avatar-holder
+ = link_to avatar_icon_for_user(@user, 400, current_user: current_user), target: '_blank', rel: 'noopener noreferrer' do
+ = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" })
+ #js-user-achievements{ data: { root_url: root_url, user_id: @user.id } }
+ .gl-display-inline-block.gl-vertical-align-top.gl-text-left
+ - if @user.blocked? || !@user.confirmed?
+ .user-info
+ %h1.cover-title.gl-my-0
+ = user_display_name(@user)
= render "users/profile_basic_info"
- .gl-text-gray-900.mb-1.mb-sm-2
- - unless @user.location.blank?
- = render 'middle_dot_divider', stacking: true, itemprop: 'address', itemscope: true, itemtype: 'https://schema.org/PostalAddress' do
- = sprite_icon('location', css_class: 'fgray')
- %span{ itemprop: 'addressLocality' }
- = @user.location
+ - else
+ .user-info
+ %h1.cover-title.gl-my-0{ itemprop: 'name' }
+ = @user.name
+ - if @user.pronouns.present?
+ %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle
+ = "(#{@user.pronouns})"
+ - if @user.status&.busy?
+ %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle= s_("UserProfile|(Busy)")
+
+ - if @user.pronunciation.present?
+ .gl-align-items-center
+ %p.gl-mb-4.gl-text-gray-500.gl-max-w-80.gl-mx-auto= 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
+ = emoji_icon(@user.status.emoji, class: 'gl-mr-2')
+ = markdown_field(@user.status, :message)
+ = render "users/profile_basic_info"
- user_local_time = local_time(@user.timezone)
- - unless user_local_time.nil?
- = render 'middle_dot_divider', stacking: true, data: { testid: 'user-local-time' } do
- = sprite_icon('clock', css_class: 'fgray')
- %span
- = user_local_time
- - unless work_information(@user).blank?
- = render 'middle_dot_divider', stacking: true do
- = sprite_icon('work', css_class: 'fgray')
- %span
- = work_information(@user, with_schema_markup: true)
- .gl-text-gray-900
- - unless @user.skype.blank?
- = render 'middle_dot_divider' do
- = link_to "skype:#{@user.skype}", class: 'gl-hover-text-decoration-none', title: "Skype" do
- = sprite_icon('skype', css_class: 'skype-icon')
- - unless @user.linkedin.blank?
- = render 'middle_dot_divider' do
- = link_to linkedin_url(@user), class: 'gl-hover-text-decoration-none', title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do
- = sprite_icon('linkedin', css_class: 'linkedin-icon')
- - unless @user.twitter.blank?
- = render 'middle_dot_divider', breakpoint: 'sm' do
- = link_to twitter_url(@user), class: 'gl-hover-text-decoration-none', title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do
- = sprite_icon('twitter', css_class: 'twitter-icon')
- - unless @user.discord.blank?
- = render 'middle_dot_divider', breakpoint: 'sm' do
- = link_to discord_url(@user), class: 'gl-hover-text-decoration-none', title: "Discord", target: '_blank', rel: 'noopener noreferrer nofollow' do
- = sprite_icon('discord', css_class: 'discord-icon')
- - unless @user.website_url.blank?
- = render 'middle_dot_divider', stacking: true do
- - if Feature.enabled?(:security_auto_fix) && @user.bot?
- = sprite_icon('question', css_class: 'gl-text-blue-600')
- = link_to @user.short_website_url, @user.full_website_url, target: '_blank', rel: 'me noopener noreferrer nofollow', itemprop: 'url'
- - if display_public_email?(@user)
- = render 'middle_dot_divider', stacking: true do
- = link_to @user.public_email, "mailto:#{@user.public_email}", itemprop: 'email'
- .gl-text-gray-900
- = sprite_icon('users', css_class: 'gl-vertical-align-middle gl-text-gray-500')
- = render 'middle_dot_divider' do
- = link_to user_followers_path do
- - count = @user.followers.count
- = n_('1 follower', '%{count} followers', count) % { count: count }
- = render 'middle_dot_divider' do
- = link_to user_following_path, data: { qa_selector: 'following_link' } do
- = @user.followees.count
- = _('following')
- - if @user.bio.present?
- .gl-text-gray-900
- .profile-user-bio
- = @user.bio
-
- - unless profile_tabs.empty?
- - if Feature.enabled?(:profile_tabs_vue, current_user)
- #js-profile-tabs
- - else
- .scrolling-tabs-container
- .fade-left= sprite_icon('chevron-lg-left', size: 12)
- .fade-right= sprite_icon('chevron-lg-right', size: 12)
- %ul.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs
- - if profile_tab?(:overview)
- %li.js-overview-tab
- = link_to user_path, data: { target: 'div#js-overview', action: 'overview', toggle: 'tab' } do
- = s_('UserProfile|Overview')
- - if profile_tab?(:activity)
- %li.js-activity-tab
- = link_to user_activity_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do
- = s_('UserProfile|Activity')
- - unless Feature.enabled?(:security_auto_fix) && @user.bot?
- - if profile_tab?(:groups)
- %li.js-groups-tab
- = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do
- = s_('UserProfile|Groups')
- - if profile_tab?(:contributed)
- %li.js-contributed-tab
- = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do
- = s_('UserProfile|Contributed projects')
- - if profile_tab?(:projects)
- %li.js-projects-tab
- = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do
- = s_('UserProfile|Personal projects')
- - if profile_tab?(:starred)
- %li.js-starred-tab
- = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do
- = s_('UserProfile|Starred projects')
- - if profile_tab?(:snippets)
- %li.js-snippets-tab
- = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do
- = s_('UserProfile|Snippets')
- - if profile_tab?(:followers)
- %li.js-followers-tab
- = link_to user_followers_path, data: { target: 'div#followers', action: 'followers', toggle: 'tab', endpoint: user_followers_path(format: :json) } do
- = s_('UserProfile|Followers')
- - if profile_tab?(:following)
- %li.js-following-tab
- = link_to user_following_path, data: { target: 'div#following', action: 'following', toggle: 'tab', endpoint: user_following_path(format: :json) } do
- = s_('UserProfile|Following')
-
+ - if @user.location.present? || user_local_time.present? || work_information(@user).present?
+ .gl-text-gray-900
+ - if @user.location.present?
+ = render 'middle_dot_divider', stacking: true, itemprop: 'address', itemscope: true, itemtype: 'https://schema.org/PostalAddress' do
+ = sprite_icon('location', css_class: 'fgray')
+ %span{ itemprop: 'addressLocality' }
+ = @user.location
+ - if user_local_time.present?
+ = render 'middle_dot_divider', stacking: true, data: { testid: 'user-local-time' } do
+ = sprite_icon('clock', css_class: 'fgray')
+ %span
+ = user_local_time
+ - if work_information(@user).present?
+ = render 'middle_dot_divider', stacking: true do
+ = sprite_icon('work', css_class: 'fgray')
+ %span
+ = work_information(@user, with_schema_markup: true)
+ .gl-text-gray-900
+ - if @user.skype.present?
+ = render 'middle_dot_divider' do
+ = link_to "skype:#{@user.skype}", class: 'gl-hover-text-decoration-none', title: "Skype" do
+ = sprite_icon('skype', css_class: 'skype-icon')
+ - if @user.linkedin.present?
+ = render 'middle_dot_divider' do
+ = link_to linkedin_url(@user), class: 'gl-hover-text-decoration-none', title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do
+ = sprite_icon('linkedin', css_class: 'linkedin-icon')
+ - if @user.twitter.present?
+ = render 'middle_dot_divider', breakpoint: 'sm' do
+ = link_to twitter_url(@user), class: 'gl-hover-text-decoration-none', title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do
+ = sprite_icon('twitter', css_class: 'twitter-icon')
+ - if @user.discord.present?
+ = render 'middle_dot_divider', breakpoint: 'sm' do
+ = link_to discord_url(@user), class: 'gl-hover-text-decoration-none', title: "Discord", target: '_blank', rel: 'noopener noreferrer nofollow' do
+ = sprite_icon('discord', css_class: 'discord-icon')
+ - if @user.website_url.present?
+ = render 'middle_dot_divider', stacking: true do
+ - if Feature.enabled?(:security_auto_fix) && @user.bot?
+ = sprite_icon('question', css_class: 'gl-text-blue-600')
+ = link_to @user.short_website_url, @user.full_website_url, target: '_blank', rel: 'me noopener noreferrer nofollow', itemprop: 'url'
+ - if display_public_email?(@user)
+ = render 'middle_dot_divider', stacking: true do
+ = link_to @user.public_email, "mailto:#{@user.public_email}", itemprop: 'email'
+ - if @user.bio.present? && @user.confirmed? && !@user.blocked?
+ %p.profile-user-bio.gl-mb-3
+ = @user.bio
+
+ - if !profile_tabs.empty? && !Feature.enabled?(:profile_tabs_vue, current_user)
+ .scrolling-tabs-container{ class: [('gl-display-none' if show_super_sidebar?)] }
+ .fade-left= sprite_icon('chevron-lg-left', size: 12)
+ .fade-right= sprite_icon('chevron-lg-right', size: 12)
+ %ul.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs
+ - if profile_tab?(:overview)
+ %li.js-overview-tab
+ = link_to user_path, data: { target: 'div#js-overview', action: 'overview', toggle: 'tab' } do
+ = s_('UserProfile|Overview')
+ - if profile_tab?(:activity)
+ %li.js-activity-tab
+ = link_to user_activity_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do
+ = s_('UserProfile|Activity')
+ - unless Feature.enabled?(:security_auto_fix) && @user.bot?
+ - if profile_tab?(:groups)
+ %li.js-groups-tab
+ = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do
+ = s_('UserProfile|Groups')
+ - if profile_tab?(:contributed)
+ %li.js-contributed-tab
+ = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do
+ = s_('UserProfile|Contributed projects')
+ - if profile_tab?(:projects)
+ %li.js-projects-tab
+ = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do
+ = s_('UserProfile|Personal projects')
+ - if profile_tab?(:starred)
+ %li.js-starred-tab
+ = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do
+ = s_('UserProfile|Starred projects')
+ - if profile_tab?(:snippets)
+ %li.js-snippets-tab
+ = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do
+ = s_('UserProfile|Snippets')
+ - if profile_tab?(:followers)
+ %li.js-followers-tab
+ = link_to user_followers_path, data: { target: 'div#followers', action: 'followers', toggle: 'tab', endpoint: user_followers_path(format: :json) } do
+ = s_('UserProfile|Followers')
+ = gl_badge_tag @user.followers.count, size: :sm
+ - if profile_tab?(:following)
+ %li.js-following-tab
+ = link_to user_following_path, data: { target: 'div#following', action: 'following', toggle: 'tab', endpoint: user_following_path(format: :json), qa_selector: 'following_tab' } do
+ = s_('UserProfile|Following')
+ = gl_badge_tag @user.followees.count, size: :sm
+ - if !profile_tabs.empty? && Feature.enabled?(:profile_tabs_vue, current_user)
+ #js-profile-tabs{ data: user_profile_tabs_app_data(@user) }
%div{ class: container_class }
- unless Feature.enabled?(:profile_tabs_vue, current_user)
.tab-content
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index c660243d336..1624538152e 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -5,7 +5,7 @@
---
- :name: authorized_project_update:authorized_project_update_project_recalculate
:worker_name: AuthorizedProjectUpdate::ProjectRecalculateWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :high
:resource_boundary: :unknown
@@ -14,7 +14,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_project_recalculate_per_user
:worker_name: AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :high
:resource_boundary: :unknown
@@ -23,7 +23,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_user_refresh_from_replica
:worker_name: AuthorizedProjectUpdate::UserRefreshFromReplicaWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -32,7 +32,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_user_refresh_over_user_range
:worker_name: AuthorizedProjectUpdate::UserRefreshOverUserRangeWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -41,7 +41,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_user_refresh_with_low_urgency
:worker_name: AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -617,7 +617,7 @@
:tags: []
- :name: cronjob:personal_access_tokens_expired_notification
:worker_name: PersonalAccessTokens::ExpiredNotificationWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -626,7 +626,7 @@
:tags: []
- :name: cronjob:personal_access_tokens_expiring
:worker_name: PersonalAccessTokens::ExpiringWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -680,7 +680,7 @@
:tags: []
- :name: cronjob:remove_expired_group_links
:worker_name: RemoveExpiredGroupLinksWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -689,7 +689,7 @@
:tags: []
- :name: cronjob:remove_expired_members
:worker_name: RemoveExpiredMembersWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :cpu
@@ -698,7 +698,7 @@
:tags: []
- :name: cronjob:remove_unaccepted_member_invites
:worker_name: RemoveUnacceptedMemberInvitesWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -1137,6 +1137,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: github_importer:github_import_import_collaborator
+ :worker_name: Gitlab::GithubImport::ImportCollaboratorWorker
+ :feature_category: :importers
+ :has_external_dependencies: true
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
- :name: github_importer:github_import_import_diff_note
:worker_name: Gitlab::GithubImport::ImportDiffNoteWorker
:feature_category: :importers
@@ -1272,6 +1281,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: github_importer:github_import_stage_import_collaborators
+ :worker_name: Gitlab::GithubImport::Stage::ImportCollaboratorsWorker
+ :feature_category: :importers
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
- :name: github_importer:github_import_stage_import_issue_events
:worker_name: Gitlab::GithubImport::Stage::ImportIssueEventsWorker
:feature_category: :importers
@@ -2165,7 +2183,7 @@
:tags: []
- :name: unassign_issuables:members_destroyer_unassign_issuables
:worker_name: MembersDestroyer::UnassignIssuablesWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :user_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -2219,7 +2237,7 @@
:tags: []
- :name: authorized_projects
:worker_name: AuthorizedProjectsWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :high
:resource_boundary: :unknown
@@ -2417,7 +2435,7 @@
:tags: []
- :name: delete_user
:worker_name: DeleteUserWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :user_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -2611,7 +2629,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent: false
+ :idempotent: true
:tags: []
- :name: group_export
:worker_name: GroupExportWorker
@@ -2642,7 +2660,7 @@
:tags: []
- :name: groups_update_two_factor_requirement_for_members
:worker_name: Groups::UpdateTwoFactorRequirementForMembersWorker
- :feature_category: :authentication_and_authorization
+ :feature_category: :system_access
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -3070,7 +3088,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent: false
+ :idempotent: true
:tags: []
- :name: project_export
:worker_name: ProjectExportWorker
@@ -3108,6 +3126,15 @@
:weight: 1
:idempotent: true
:tags: []
+- :name: projects_forks_sync
+ :worker_name: Projects::Forks::SyncWorker
+ :feature_category: :source_code_management
+ :has_external_dependencies: false
+ :urgency: :high
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: projects_git_garbage_collect
:worker_name: Projects::GitGarbageCollectWorker
:feature_category: :gitaly
@@ -3117,6 +3144,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: projects_import_export_create_relation_exports
+ :worker_name: Projects::ImportExport::CreateRelationExportsWorker
+ :feature_category: :importers
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :cpu
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: projects_import_export_parallel_project_export
:worker_name: Projects::ImportExport::ParallelProjectExportWorker
:feature_category: :importers
@@ -3135,6 +3171,15 @@
:weight: 1
:idempotent: true
:tags: []
+- :name: projects_import_export_wait_relation_exports
+ :worker_name: Projects::ImportExport::WaitRelationExportsWorker
+ :feature_category: :importers
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :cpu
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: projects_inactive_projects_deletion_notification
:worker_name: Projects::InactiveProjectsDeletionNotificationWorker
:feature_category: :compliance_management
diff --git a/app/workers/authorized_project_update/project_recalculate_per_user_worker.rb b/app/workers/authorized_project_update/project_recalculate_per_user_worker.rb
index 352c82e5021..96647cc671c 100644
--- a/app/workers/authorized_project_update/project_recalculate_per_user_worker.rb
+++ b/app/workers/authorized_project_update/project_recalculate_per_user_worker.rb
@@ -4,7 +4,7 @@ module AuthorizedProjectUpdate
class ProjectRecalculatePerUserWorker < ProjectRecalculateWorker
data_consistency :always
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :high
queue_namespace :authorized_project_update
diff --git a/app/workers/authorized_project_update/project_recalculate_worker.rb b/app/workers/authorized_project_update/project_recalculate_worker.rb
index 1b5faee0b6f..cbf068f0b85 100644
--- a/app/workers/authorized_project_update/project_recalculate_worker.rb
+++ b/app/workers/authorized_project_update/project_recalculate_worker.rb
@@ -9,7 +9,7 @@ module AuthorizedProjectUpdate
prepend WaitableWorker
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :high
queue_namespace :authorized_project_update
diff --git a/app/workers/authorized_project_update/user_refresh_from_replica_worker.rb b/app/workers/authorized_project_update/user_refresh_from_replica_worker.rb
index daebb23baae..cdc0a097c92 100644
--- a/app/workers/authorized_project_update/user_refresh_from_replica_worker.rb
+++ b/app/workers/authorized_project_update/user_refresh_from_replica_worker.rb
@@ -5,7 +5,7 @@ module AuthorizedProjectUpdate
include ApplicationWorker
sidekiq_options retry: 3
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :low
data_consistency :always
queue_namespace :authorized_project_update
diff --git a/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb b/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
index 8452f2a7821..ae243a94d3d 100644
--- a/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
+++ b/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
@@ -16,7 +16,7 @@ module AuthorizedProjectUpdate
sidekiq_options retry: 3
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :low
queue_namespace :authorized_project_update
diff --git a/app/workers/authorized_project_update/user_refresh_with_low_urgency_worker.rb b/app/workers/authorized_project_update/user_refresh_with_low_urgency_worker.rb
index 7ca59a72adf..d6b41ba949c 100644
--- a/app/workers/authorized_project_update/user_refresh_with_low_urgency_worker.rb
+++ b/app/workers/authorized_project_update/user_refresh_with_low_urgency_worker.rb
@@ -2,7 +2,7 @@
module AuthorizedProjectUpdate
class UserRefreshWithLowUrgencyWorker < ::AuthorizedProjectsWorker
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :low
queue_namespace :authorized_project_update
deduplicate :until_executing, including_scheduled: true
diff --git a/app/workers/authorized_projects_worker.rb b/app/workers/authorized_projects_worker.rb
index 4312ba41367..b553a2cd14e 100644
--- a/app/workers/authorized_projects_worker.rb
+++ b/app/workers/authorized_projects_worker.rb
@@ -8,7 +8,7 @@ class AuthorizedProjectsWorker
sidekiq_options retry: 3
prepend WaitableWorker
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :high
weight 2
idempotent!
diff --git a/app/workers/ci/archive_traces_cron_worker.rb b/app/workers/ci/archive_traces_cron_worker.rb
index fe23d10c2ac..879192e67c4 100644
--- a/app/workers/ci/archive_traces_cron_worker.rb
+++ b/app/workers/ci/archive_traces_cron_worker.rb
@@ -11,20 +11,12 @@ module Ci
feature_category :continuous_integration
deduplicate :until_executed, including_scheduled: true
- # rubocop: disable CodeReuse/ActiveRecord
def perform
# Archive stale live traces which still resides in redis or database
# This could happen when Ci::ArchiveTraceWorker sidekiq jobs were lost by receiving SIGKILL
# More details in https://gitlab.com/gitlab-org/gitlab-foss/issues/36791
- if Feature.enabled?(:deduplicate_archive_traces_cron_worker)
- Ci::ArchiveTraceService.new.batch_execute(worker_name: self.class.name)
- else
- Ci::Build.with_stale_live_trace.find_each(batch_size: 100) do |build|
- Ci::ArchiveTraceService.new.execute(build, worker_name: self.class.name)
- end
- end
+ Ci::ArchiveTraceService.new.batch_execute(worker_name: self.class.name)
end
- # rubocop: enable CodeReuse/ActiveRecord
end
end
diff --git a/app/workers/concerns/application_worker.rb b/app/workers/concerns/application_worker.rb
index e2e31b0a5bd..ce77592daac 100644
--- a/app/workers/concerns/application_worker.rb
+++ b/app/workers/concerns/application_worker.rb
@@ -11,6 +11,7 @@ module ApplicationWorker
include WorkerAttributes
include WorkerContext
include Gitlab::SidekiqVersioning::Worker
+ include Gitlab::Loggable
LOGGING_EXTRA_KEY = 'extra'
SAFE_PUSH_BULK_LIMIT = 1000
@@ -28,7 +29,7 @@ module ApplicationWorker
'jid' => jid
)
- payload.stringify_keys.merge(context)
+ build_structured_payload(**payload).merge(context)
end
def log_extra_metadata_on_done(key, value)
diff --git a/app/workers/concerns/gitlab/github_import/object_importer.rb b/app/workers/concerns/gitlab/github_import/object_importer.rb
index c5c7da23892..7e488862696 100644
--- a/app/workers/concerns/gitlab/github_import/object_importer.rb
+++ b/app/workers/concerns/gitlab/github_import/object_importer.rb
@@ -13,12 +13,27 @@ module Gitlab
sidekiq_options retry: 3
include GithubImport::Queue
include ReschedulingMethods
- include Gitlab::NotifyUponDeath
feature_category :importers
worker_has_external_dependencies!
+
+ sidekiq_retries_exhausted do |msg|
+ args = msg['args']
+ correlation_id = msg['correlation_id']
+ jid = msg['jid']
+
+ new.perform_failure(args[0], args[1], correlation_id)
+
+ # 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)
+ end
+ end
end
+ NotRetriableError = Class.new(StandardError)
+
# project - An instance of `Project` to import the data into.
# client - An instance of `Gitlab::GithubImport::Client`
# hash - A Hash containing the details of the object to import.
@@ -47,13 +62,27 @@ module Gitlab
# Representation is created but the developer forgot to add a
# `:github_identifiers` field.
track_and_raise_exception(project, e, fail_import: true)
- rescue ActiveRecord::RecordInvalid => e
+ rescue ActiveRecord::RecordInvalid, NotRetriableError => e
# We do not raise exception to prevent job retry
- track_exception(project, e)
+ failure = track_exception(project, e)
+ add_identifiers_to_failure(failure, object.github_identifiers)
rescue StandardError => e
track_and_raise_exception(project, e)
end
+ # hash - A Hash containing the details of the object to import.
+ def perform_failure(project_id, hash, correlation_id)
+ project = Project.find_by_id(project_id)
+ return unless project
+
+ failure = project.import_failures.failures_by_correlation_id(correlation_id).first
+ return unless failure
+
+ object = representation_class.from_json_hash(hash)
+
+ add_identifiers_to_failure(failure, object.github_identifiers)
+ end
+
def increment_object_counter?(_object)
true
end
@@ -103,6 +132,10 @@ module Gitlab
raise(exception)
end
+
+ def add_identifiers_to_failure(failure, external_identifiers)
+ failure.update_column(:external_identifiers, external_identifiers)
+ end
end
end
end
diff --git a/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb b/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb
index f40855a7455..53e3ac3a1b0 100644
--- a/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb
+++ b/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb
@@ -68,7 +68,7 @@ module ContainerExpirationPolicies
container_repository_id: repo.id
)
- repo.cleanup_ongoing!
+ repo.start_expiration_policy!
end
end
end
@@ -95,10 +95,9 @@ module ContainerExpirationPolicies
def cleanup_scheduled_count
strong_memoize(:cleanup_scheduled_count) do
limit = max_running_jobs + 1
- ContainerExpirationPolicy.with_container_repositories
- .runnable_schedules
- .limit(limit)
- .count
+ ContainerRepository.requiring_cleanup
+ .limit(limit)
+ .count
end
end
diff --git a/app/workers/delete_user_worker.rb b/app/workers/delete_user_worker.rb
index 0af084caf86..bca156ff84c 100644
--- a/app/workers/delete_user_worker.rb
+++ b/app/workers/delete_user_worker.rb
@@ -7,7 +7,7 @@ class DeleteUserWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: 3
- feature_category :authentication_and_authorization
+ feature_category :user_management
loggable_arguments 2
def perform(current_user_id, delete_user_id, options = {})
diff --git a/app/workers/gitlab/github_import/advance_stage_worker.rb b/app/workers/gitlab/github_import/advance_stage_worker.rb
index a9f645bd634..45f4bf486d7 100644
--- a/app/workers/gitlab/github_import/advance_stage_worker.rb
+++ b/app/workers/gitlab/github_import/advance_stage_worker.rb
@@ -20,6 +20,7 @@ module Gitlab
# The known importer stages and their corresponding Sidekiq workers.
STAGES = {
+ collaborators: Stage::ImportCollaboratorsWorker,
pull_requests_merged_by: Stage::ImportPullRequestsMergedByWorker,
pull_request_review_requests: Stage::ImportPullRequestsReviewRequestsWorker,
pull_request_reviews: Stage::ImportPullRequestsReviewsWorker,
diff --git a/app/workers/gitlab/github_import/import_collaborator_worker.rb b/app/workers/gitlab/github_import/import_collaborator_worker.rb
new file mode 100644
index 00000000000..35cb3fa6830
--- /dev/null
+++ b/app/workers/gitlab/github_import/import_collaborator_worker.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ class ImportCollaboratorWorker # rubocop:disable Scalability/IdempotentWorker
+ include ObjectImporter
+
+ def representation_class
+ Representation::Collaborator
+ end
+
+ def importer_class
+ Importer::CollaboratorImporter
+ end
+
+ def object_type
+ :collaborator
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab/github_import/stage/import_collaborators_worker.rb b/app/workers/gitlab/github_import/stage/import_collaborators_worker.rb
new file mode 100644
index 00000000000..d63d1fd3f5f
--- /dev/null
+++ b/app/workers/gitlab/github_import/stage/import_collaborators_worker.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module Stage
+ class ImportCollaboratorsWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+
+ data_consistency :always
+
+ sidekiq_options retry: 3
+ include GithubImport::Queue
+ include StageMethods
+
+ # client - An instance of Gitlab::GithubImport::Client.
+ # project - An instance of Project.
+ def import(client, project)
+ info(project.id, message: 'starting importer', importer: 'Importer::CollaboratorsImporter')
+ return skip_to_next_stage(project) unless has_push_access?(client, project.import_source)
+
+ waiter = Importer::CollaboratorsImporter.new(project, client).execute
+ project.import_state.refresh_jid_expiration
+
+ move_to_next_stage(project, { waiter.key => waiter.jobs_remaining })
+ rescue StandardError => e
+ Gitlab::Import::ImportFailureService.track(
+ project_id: project.id,
+ error_source: self.class.name,
+ exception: e,
+ fail_import: abort_on_failure,
+ metrics: true
+ )
+
+ raise(e)
+ end
+
+ private
+
+ def has_push_access?(client, repo)
+ client.repository(repo).dig(:permissions, :push)
+ end
+
+ def skip_to_next_stage(project)
+ Gitlab::GithubImport::Logger.warn(
+ log_attributes(
+ project.id,
+ message: 'no push access rights to fetch collaborators',
+ importer: 'Importer::CollaboratorsImporter'
+ )
+ )
+ move_to_next_stage(project, {})
+ end
+
+ def move_to_next_stage(project, waiters = {})
+ AdvanceStageWorker.perform_async(
+ project.id, waiters, :pull_requests_merged_by
+ )
+ end
+
+ def abort_on_failure
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb b/app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb
index 71d0247bae0..e7eee0915d5 100644
--- a/app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb
+++ b/app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb
@@ -25,7 +25,7 @@ module Gitlab
AdvanceStageWorker.perform_async(
project.id,
{ waiter.key => waiter.jobs_remaining },
- :pull_requests_merged_by
+ :collaborators
)
rescue StandardError => e
Gitlab::Import::ImportFailureService.track(
diff --git a/app/workers/gitlab/github_import/stage/import_repository_worker.rb b/app/workers/gitlab/github_import/stage/import_repository_worker.rb
index 8c1a2cd2677..e13f43ee1f3 100644
--- a/app/workers/gitlab/github_import/stage/import_repository_worker.rb
+++ b/app/workers/gitlab/github_import/stage/import_repository_worker.rb
@@ -72,7 +72,7 @@ module Gitlab
return unless last_github_issue
- Issue.track_project_iid!(project, last_github_issue[:number])
+ Issue.track_namespace_iid!(project.project_namespace, last_github_issue[:number])
end
end
end
diff --git a/app/workers/gitlab_service_ping_worker.rb b/app/workers/gitlab_service_ping_worker.rb
index b02e7318585..53a4361fb48 100644
--- a/app/workers/gitlab_service_ping_worker.rb
+++ b/app/workers/gitlab_service_ping_worker.rb
@@ -52,3 +52,5 @@ class GitlabServicePingWorker # rubocop:disable Scalability/IdempotentWorker
nil
end
end
+
+GitlabServicePingWorker.prepend_mod
diff --git a/app/workers/group_destroy_worker.rb b/app/workers/group_destroy_worker.rb
index 92195d3fe16..a116944feb9 100644
--- a/app/workers/group_destroy_worker.rb
+++ b/app/workers/group_destroy_worker.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class GroupDestroyWorker # rubocop:disable Scalability/IdempotentWorker
+class GroupDestroyWorker
include ApplicationWorker
data_consistency :always
@@ -10,6 +10,9 @@ class GroupDestroyWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :subgroups
+ idempotent!
+ deduplicate :until_executed, ttl: 2.hours
+
def perform(group_id, user_id)
begin
group = Group.find(group_id)
diff --git a/app/workers/groups/update_two_factor_requirement_for_members_worker.rb b/app/workers/groups/update_two_factor_requirement_for_members_worker.rb
index ac1d3589516..ca68a82ec66 100644
--- a/app/workers/groups/update_two_factor_requirement_for_members_worker.rb
+++ b/app/workers/groups/update_two_factor_requirement_for_members_worker.rb
@@ -9,7 +9,7 @@ module Groups
idempotent!
- feature_category :authentication_and_authorization
+ feature_category :system_access
def perform(group_id)
group = Group.find_by_id(group_id)
diff --git a/app/workers/issuable_export_csv_worker.rb b/app/workers/issuable_export_csv_worker.rb
index 1c5fab8c4c0..d5e3a86eac1 100644
--- a/app/workers/issuable_export_csv_worker.rb
+++ b/app/workers/issuable_export_csv_worker.rb
@@ -25,7 +25,13 @@ class IssuableExportCsvWorker # rubocop:disable Scalability/IdempotentWorker
def export_service(type, user, project, params)
issuable_classes = issuable_classes_for(type.to_sym)
issuables = issuable_classes[:finder].new(user, parse_params(params, project.id, type)).execute
- issuable_classes[:service].new(issuables, project)
+
+ if type.to_sym == :issue # issues do not support field selection for export
+ issuable_classes[:service].new(issuables, project, user)
+ else
+ fields = params.with_indifferent_access.delete(:selected_fields) || []
+ issuable_classes[:service].new(issuables, project, fields)
+ end
end
def issuable_classes_for(type)
@@ -34,6 +40,8 @@ class IssuableExportCsvWorker # rubocop:disable Scalability/IdempotentWorker
{ finder: IssuesFinder, service: Issues::ExportCsvService }
when :merge_request
{ finder: MergeRequestsFinder, service: MergeRequests::ExportCsvService }
+ when :work_item
+ { finder: WorkItems::WorkItemsFinder, service: WorkItems::ExportCsvService }
else
raise ArgumentError, type_error_message(type)
end
@@ -47,7 +55,13 @@ class IssuableExportCsvWorker # rubocop:disable Scalability/IdempotentWorker
end
def type_error_message(type)
- "Type parameter must be :issue or :merge_request, it was #{type}"
+ types_sentence = allowed_types.to_sentence(last_word_connector: ' or ')
+
+ "Type parameter must be #{types_sentence}, it was #{type}"
+ end
+
+ def allowed_types
+ %w[:issue :merge_request :work_item]
end
end
diff --git a/app/workers/issues/placement_worker.rb b/app/workers/issues/placement_worker.rb
index ec29a754128..0a4f2612912 100644
--- a/app/workers/issues/placement_worker.rb
+++ b/app/workers/issues/placement_worker.rb
@@ -40,7 +40,7 @@ module Issues
leftover = to_place.pop if to_place.count > QUERY_LIMIT
Issue.move_nulls_to_end(to_place)
- Issues::BaseService.new(project: nil).rebalance_if_needed(to_place.max_by(&:relative_position))
+ Issues::BaseService.new(container: nil).rebalance_if_needed(to_place.max_by(&:relative_position))
Issues::PlacementWorker.perform_async(nil, leftover.project_id) if leftover.present?
rescue RelativePositioning::NoSpaceLeft => e
Gitlab::ErrorTracking.log_exception(e, issue_id: issue_id, project_id: project_id)
diff --git a/app/workers/members_destroyer/unassign_issuables_worker.rb b/app/workers/members_destroyer/unassign_issuables_worker.rb
index 915551d6e30..2e6ce0005fc 100644
--- a/app/workers/members_destroyer/unassign_issuables_worker.rb
+++ b/app/workers/members_destroyer/unassign_issuables_worker.rb
@@ -11,7 +11,7 @@ module MembersDestroyer
ENTITY_TYPES = %w(Group Project).freeze
queue_namespace :unassign_issuables
- feature_category :authentication_and_authorization
+ feature_category :user_management
idempotent!
diff --git a/app/workers/new_merge_request_worker.rb b/app/workers/new_merge_request_worker.rb
index a32a414c0ba..74239c5d968 100644
--- a/app/workers/new_merge_request_worker.rb
+++ b/app/workers/new_merge_request_worker.rb
@@ -18,7 +18,6 @@ class NewMergeRequestWorker # rubocop:disable Scalability/IdempotentWorker
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/packages/debian/generate_distribution_worker.rb b/app/workers/packages/debian/generate_distribution_worker.rb
index 1eff3ea02dd..f0c753c3a9b 100644
--- a/app/workers/packages/debian/generate_distribution_worker.rb
+++ b/app/workers/packages/debian/generate_distribution_worker.rb
@@ -20,7 +20,7 @@ module Packages
loggable_arguments 0
def perform(container_type, distribution_id)
- @container_type = container_type
+ @container_type = container_type.to_sym
@distribution_id = distribution_id
return unless distribution
diff --git a/app/workers/personal_access_tokens/expired_notification_worker.rb b/app/workers/personal_access_tokens/expired_notification_worker.rb
index b119957fa2c..f86bd604cdf 100644
--- a/app/workers/personal_access_tokens/expired_notification_worker.rb
+++ b/app/workers/personal_access_tokens/expired_notification_worker.rb
@@ -8,7 +8,7 @@ module PersonalAccessTokens
include CronjobQueue
- feature_category :authentication_and_authorization
+ feature_category :system_access
MAX_TOKENS = 100
diff --git a/app/workers/personal_access_tokens/expiring_worker.rb b/app/workers/personal_access_tokens/expiring_worker.rb
index f4afa9f8994..de0bda82573 100644
--- a/app/workers/personal_access_tokens/expiring_worker.rb
+++ b/app/workers/personal_access_tokens/expiring_worker.rb
@@ -8,7 +8,7 @@ module PersonalAccessTokens
include CronjobQueue
- feature_category :authentication_and_authorization
+ feature_category :system_access
MAX_TOKENS = 100
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index f95176da252..676a834d79d 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -140,8 +140,6 @@ class PostReceive
end
def emit_snowplow_event(project, user)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, project.namespace)
-
metric_path = 'counts.source_code_pushes'
Gitlab::Tracking.event(
'PostReceive',
diff --git a/app/workers/project_destroy_worker.rb b/app/workers/project_destroy_worker.rb
index 45d0ebd2b65..181eebe56e8 100644
--- a/app/workers/project_destroy_worker.rb
+++ b/app/workers/project_destroy_worker.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ProjectDestroyWorker # rubocop:disable Scalability/IdempotentWorker
+class ProjectDestroyWorker
include ApplicationWorker
data_consistency :always
@@ -10,6 +10,9 @@ class ProjectDestroyWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :source_code_management
+ idempotent!
+ deduplicate :until_executed, ttl: 2.hours
+
def perform(project_id, user_id, params)
project = Project.find(project_id)
user = User.find(user_id)
diff --git a/app/workers/projects/forks/sync_worker.rb b/app/workers/projects/forks/sync_worker.rb
new file mode 100644
index 00000000000..2fa6785bc91
--- /dev/null
+++ b/app/workers/projects/forks/sync_worker.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Projects
+ module Forks
+ class SyncWorker
+ include ApplicationWorker
+
+ data_consistency :sticky
+ idempotent!
+ urgency :high
+ feature_category :source_code_management
+
+ def perform(project_id, user_id, ref)
+ project = Project.find_by_id(project_id)
+ user = User.find_by_id(user_id)
+ return unless project && user
+
+ ::Projects::Forks::SyncService.new(project, user, ref).execute
+ end
+ end
+ end
+end
diff --git a/app/workers/projects/import_export/create_relation_exports_worker.rb b/app/workers/projects/import_export/create_relation_exports_worker.rb
new file mode 100644
index 00000000000..9ca69a5500a
--- /dev/null
+++ b/app/workers/projects/import_export/create_relation_exports_worker.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module Projects
+ module ImportExport
+ class CreateRelationExportsWorker
+ include ApplicationWorker
+ include ExceptionBacktrace
+
+ idempotent!
+ data_consistency :always
+ deduplicate :until_executed
+ feature_category :importers
+ worker_resource_boundary :cpu
+ sidekiq_options status_expiration: StuckExportJobsWorker::EXPORT_JOBS_EXPIRATION
+
+ # This delay is an arbitrary number to finish the export quicker in case all relations
+ # are exported before the first execution of the WaitRelationExportsWorker worker.
+ INITIAL_DELAY = 10.seconds
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def perform(user_id, project_id, after_export_strategy = {})
+ project = Project.find_by_id(project_id)
+ return unless project
+
+ project_export_job = project.export_jobs.find_or_create_by!(jid: jid)
+ return if project_export_job.started?
+
+ relation_exports = RelationExport.relation_names_list.map do |relation_name|
+ project_export_job.relation_exports.find_or_create_by!(relation: relation_name)
+ end
+
+ relation_exports.each do |relation_export|
+ RelationExportWorker.with_status.perform_async(relation_export.id)
+ end
+
+ WaitRelationExportsWorker.perform_in(
+ INITIAL_DELAY,
+ project_export_job.id,
+ user_id,
+ after_export_strategy
+ )
+
+ project_export_job.start!
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+ end
+end
diff --git a/app/workers/projects/import_export/relation_export_worker.rb b/app/workers/projects/import_export/relation_export_worker.rb
index 13ca33c4457..7747d4f4099 100644
--- a/app/workers/projects/import_export/relation_export_worker.rb
+++ b/app/workers/projects/import_export/relation_export_worker.rb
@@ -10,13 +10,34 @@ module Projects
data_consistency :always
deduplicate :until_executed
feature_category :importers
- sidekiq_options status_expiration: StuckExportJobsWorker::EXPORT_JOBS_EXPIRATION
+ sidekiq_options dead: false, status_expiration: StuckExportJobsWorker::EXPORT_JOBS_EXPIRATION
urgency :low
worker_resource_boundary :memory
+ sidekiq_retries_exhausted do |job, exception|
+ relation_export = Projects::ImportExport::RelationExport.find(job['args'].first)
+ project_export_job = relation_export.project_export_job
+ project = project_export_job.project
+
+ relation_export.mark_as_failed(job['error_message'])
+
+ log_payload = {
+ message: 'Project relation export failed',
+ export_error: job['error_message'],
+ relation: relation_export.relation,
+ project_export_job_id: project_export_job.id,
+ project_name: project.name,
+ project_id: project.id
+ }
+ Gitlab::ExceptionLogFormatter.format!(exception, log_payload)
+ Gitlab::Export::Logger.error(log_payload)
+ end
+
def perform(project_relation_export_id)
relation_export = Projects::ImportExport::RelationExport.find(project_relation_export_id)
+ relation_export.retry! if relation_export.started?
+
if relation_export.queued?
Projects::ImportExport::RelationExportService.new(relation_export, jid).execute
end
diff --git a/app/workers/projects/import_export/wait_relation_exports_worker.rb b/app/workers/projects/import_export/wait_relation_exports_worker.rb
new file mode 100644
index 00000000000..4250073edce
--- /dev/null
+++ b/app/workers/projects/import_export/wait_relation_exports_worker.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+module Projects
+ module ImportExport
+ class WaitRelationExportsWorker
+ include ApplicationWorker
+ include ExceptionBacktrace
+
+ idempotent!
+ data_consistency :always
+ deduplicate :until_executed
+ feature_category :importers
+ loggable_arguments 1, 2
+ worker_resource_boundary :cpu
+ sidekiq_options dead: false, status_expiration: StuckExportJobsWorker::EXPORT_JOBS_EXPIRATION
+
+ INTERVAL = 1.minute
+
+ def perform(project_export_job_id, user_id, after_export_strategy = {})
+ @export_job = ProjectExportJob.find(project_export_job_id)
+
+ return unless @export_job.started?
+
+ @export_job.update_attribute(:jid, jid)
+ @relation_exports = @export_job.relation_exports
+
+ if queued_relation_exports.any? || started_relation_exports.any?
+ fail_started_jobs_no_longer_running
+
+ self.class.perform_in(INTERVAL, project_export_job_id, user_id, after_export_strategy)
+ return
+ end
+
+ if all_relation_export_finished?
+ ParallelProjectExportWorker.perform_async(project_export_job_id, user_id, after_export_strategy)
+ return
+ end
+
+ fail_and_notify_user(user_id)
+ end
+
+ private
+
+ def relation_exports_with_status(status)
+ @relation_exports.select { |relation_export| relation_export.status == status }
+ end
+
+ def queued_relation_exports
+ relation_exports_with_status(RelationExport::STATUS[:queued])
+ end
+
+ def started_relation_exports
+ @started_relation_exports ||= relation_exports_with_status(RelationExport::STATUS[:started])
+ end
+
+ def all_relation_export_finished?
+ @relation_exports.all? { |relation_export| relation_export.status == RelationExport::STATUS[:finished] }
+ end
+
+ def fail_started_jobs_no_longer_running
+ started_relation_exports.each do |relation_export|
+ next if Gitlab::SidekiqStatus.running?(relation_export.jid)
+ next if relation_export.reset.finished?
+
+ relation_export.mark_as_failed("Exausted number of retries to export: #{relation_export.relation}")
+ end
+ end
+
+ def fail_and_notify_user(user_id)
+ @export_job.fail_op!
+
+ @user = User.find_by_id(user_id)
+ return unless @user
+
+ failed_relation_exports = relation_exports_with_status(RelationExport::STATUS[:failed])
+ errors = failed_relation_exports.map(&:export_error)
+
+ NotificationService.new.project_not_exported(@export_job.project, @user, errors)
+ end
+ end
+ end
+end
diff --git a/app/workers/prune_old_events_worker.rb b/app/workers/prune_old_events_worker.rb
index c8dfb2ade0a..927c21d9c53 100644
--- a/app/workers/prune_old_events_worker.rb
+++ b/app/workers/prune_old_events_worker.rb
@@ -15,9 +15,13 @@ class PruneOldEventsWorker # rubocop:disable Scalability/IdempotentWorker
DELETE_LIMIT = 10_000
def perform
- # Contribution calendar shows maximum 12 months of events, we retain 3 years for data integrity.
- cutoff_date = (3.years + 1.day).ago
+ if Feature.enabled?(:ops_prune_old_events, type: :ops)
+ # Contribution calendar shows maximum 12 months of events, we retain 3 years for data integrity.
+ cutoff_date = (3.years + 1.day).ago
- Event.unscoped.created_before(cutoff_date).delete_with_limit(DELETE_LIMIT)
+ Event.unscoped.created_before(cutoff_date).delete_with_limit(DELETE_LIMIT)
+ else
+ Gitlab::AppLogger.info(":ops_prune_old_events is disabled, skipping.")
+ end
end
end
diff --git a/app/workers/remove_expired_group_links_worker.rb b/app/workers/remove_expired_group_links_worker.rb
index 37298c53a5c..f1da5f37945 100644
--- a/app/workers/remove_expired_group_links_worker.rb
+++ b/app/workers/remove_expired_group_links_worker.rb
@@ -7,7 +7,7 @@ class RemoveExpiredGroupLinksWorker # rubocop:disable Scalability/IdempotentWork
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
- feature_category :authentication_and_authorization
+ feature_category :system_access
def perform
ProjectGroupLink.expired.find_each do |link|
diff --git a/app/workers/remove_expired_members_worker.rb b/app/workers/remove_expired_members_worker.rb
index c9eb715a522..b5031f4cda6 100644
--- a/app/workers/remove_expired_members_worker.rb
+++ b/app/workers/remove_expired_members_worker.rb
@@ -7,7 +7,7 @@ class RemoveExpiredMembersWorker # rubocop:disable Scalability/IdempotentWorker
include CronjobQueue
- feature_category :authentication_and_authorization
+ feature_category :system_access
worker_resource_boundary :cpu
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/workers/remove_unaccepted_member_invites_worker.rb b/app/workers/remove_unaccepted_member_invites_worker.rb
index 7fe45b26094..96f60b5fa12 100644
--- a/app/workers/remove_unaccepted_member_invites_worker.rb
+++ b/app/workers/remove_unaccepted_member_invites_worker.rb
@@ -7,7 +7,7 @@ class RemoveUnacceptedMemberInvitesWorker # rubocop:disable Scalability/Idempote
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
- feature_category :authentication_and_authorization
+ feature_category :system_access
urgency :low
idempotent!
diff --git a/app/workers/stage_update_worker.rb b/app/workers/stage_update_worker.rb
index e0d8958fc80..97da76346b6 100644
--- a/app/workers/stage_update_worker.rb
+++ b/app/workers/stage_update_worker.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
+# This will be scheduled to be removed after removing the FF ci_remove_ensure_stage_service
class StageUpdateWorker
include ApplicationWorker
diff --git a/config/application.rb b/config/application.rb
index c6ecfcc0cb1..781b6e042b1 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -32,7 +32,6 @@ module Gitlab
# Rails 6.1
config.action_dispatch.cookies_same_site_protection = nil # New default is :lax
ActiveSupport.utc_to_local_returns_utc_offset_times = false
- config.action_controller.urlsafe_csrf_tokens = false
config.action_view.preload_links_header = false
# Rails 5.2
@@ -258,7 +257,7 @@ module Gitlab
config.assets.precompile << "page_bundles/_mixins_and_variables_and_functions.css"
config.assets.precompile << "page_bundles/admin/application_settings_metrics_and_profiling.css"
config.assets.precompile << "page_bundles/admin/elasticsearch_form.css"
- config.assets.precompile << "page_bundles/admin/geo_nodes.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"
@@ -268,6 +267,7 @@ module Gitlab
config.assets.precompile << "page_bundles/branches.css"
config.assets.precompile << "page_bundles/build.css"
config.assets.precompile << "page_bundles/ci_status.css"
+ config.assets.precompile << "page_bundles/ci_cd_settings.css"
config.assets.precompile << "page_bundles/cluster_agents.css"
config.assets.precompile << "page_bundles/clusters.css"
config.assets.precompile << "page_bundles/cycle_analytics.css"
@@ -300,6 +300,7 @@ module Gitlab
config.assets.precompile << "page_bundles/merge_request_analytics.css"
config.assets.precompile << "page_bundles/merge_requests.css"
config.assets.precompile << "page_bundles/milestone.css"
+ config.assets.precompile << "page_bundles/ml_experiment_tracking.css"
config.assets.precompile << "page_bundles/new_namespace.css"
config.assets.precompile << "page_bundles/notifications.css"
config.assets.precompile << "page_bundles/oncall_schedules.css"
@@ -403,7 +404,7 @@ module Gitlab
config.middleware.insert_before ActionDispatch::RemoteIp, ::Gitlab::Middleware::HandleIpSpoofAttackError
- config.middleware.insert_after ActionDispatch::ActionableExceptions, ::Gitlab::Middleware::HandleMalformedStrings
+ config.middleware.insert_after Rails::Rack::Logger, ::Gitlab::Middleware::HandleMalformedStrings
config.middleware.insert_after Rack::Sendfile, ::Gitlab::Middleware::RackMultipartTempfileFactory
diff --git a/config/audit_events/types/feature_flag_created.yml b/config/audit_events/types/feature_flag_created.yml
new file mode 100644
index 00000000000..053580879fd
--- /dev/null
+++ b/config/audit_events/types/feature_flag_created.yml
@@ -0,0 +1,9 @@
+---
+name: feature_flag_created
+description: Triggered when a feature flag is created.
+introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/374109
+introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113453
+feature_category: feature_flags
+milestone: '15.10'
+saved_to_database: true
+streamed: true
diff --git a/config/audit_events/types/feature_flag_deleted.yml b/config/audit_events/types/feature_flag_deleted.yml
new file mode 100644
index 00000000000..3de626409d5
--- /dev/null
+++ b/config/audit_events/types/feature_flag_deleted.yml
@@ -0,0 +1,9 @@
+---
+name: feature_flag_deleted
+description: Triggered when a feature flag is deleted.
+introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/374109
+introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113453
+feature_category: feature_flags
+milestone: '15.10'
+saved_to_database: true
+streamed: true
diff --git a/config/audit_events/types/feature_flag_updated.yml b/config/audit_events/types/feature_flag_updated.yml
new file mode 100644
index 00000000000..0314684cb48
--- /dev/null
+++ b/config/audit_events/types/feature_flag_updated.yml
@@ -0,0 +1,9 @@
+---
+name: feature_flag_updated
+description: Triggered when a feature flag is updated.
+introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/374109
+introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113453
+feature_category: feature_flags
+milestone: '15.10'
+saved_to_database: true
+streamed: true
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 6b44af3b658..3823b76d0f2 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -47,6 +47,7 @@ Rails.application.configure do
config.lookbook.page_paths = ["#{config.root}/spec/components/docs"]
config.lookbook.preview_params_options_eval = true
config.lookbook.preview_display_options = {
+ layout: %w[fixed fluid],
theme: ["light", "dark (alpha)"]
}
@@ -74,6 +75,8 @@ Rails.application.configure do
# BetterErrors live shell (REPL) on every stack frame
BetterErrors::Middleware.allow_ip!("127.0.0.1/0")
+ # Disable REPL due to security concerns.
+ BetterErrors.binding_of_caller_available = false
# Reassign some performance related settings when we profile the app
if Gitlab::Utils.to_boolean(ENV['RAILS_PROFILE'].to_s)
diff --git a/config/esbuild.config.js b/config/esbuild.config.js
index e876436e864..b17548d8300 100644
--- a/config/esbuild.config.js
+++ b/config/esbuild.config.js
@@ -56,4 +56,10 @@ module.exports = {
'class-field': false,
},
implementation: esbuild,
+ /**
+ * It's necessary to tell esbuild to use the 'js' loader
+ * because esbuild cannot auto-detect which loader to use
+ * based on the .vue extension.
+ */
+ loader: 'js',
};
diff --git a/config/events/1655841083_projects_settings_cicd_show_render.yml b/config/events/1655841083_projects_settings_cicd_show_render.yml
index 45f0037443b..81612662a0d 100644
--- a/config/events/1655841083_projects_settings_cicd_show_render.yml
+++ b/config/events/1655841083_projects_settings_cicd_show_render.yml
@@ -19,7 +19,7 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90449
distributions:
- ce
- ee
-tiers:
+tiers:
- free
- premium
- ultimate
diff --git a/config/events/1655841352_projects_settings_cicd_show_upload.yml b/config/events/1655841352_projects_settings_cicd_show_upload.yml
index a19462d671e..12dd9fd8850 100644
--- a/config/events/1655841352_projects_settings_cicd_show_upload.yml
+++ b/config/events/1655841352_projects_settings_cicd_show_upload.yml
@@ -19,7 +19,7 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90449
distributions:
- ce
- ee
-tiers:
+tiers:
- free
- premium
- ultimate
diff --git a/config/events/1655841364_projects_settings_cicd_show_delete.yml b/config/events/1655841364_projects_settings_cicd_show_delete.yml
index c106ab376e3..f4504d5df63 100644
--- a/config/events/1655841364_projects_settings_cicd_show_delete.yml
+++ b/config/events/1655841364_projects_settings_cicd_show_delete.yml
@@ -19,7 +19,7 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90449
distributions:
- ce
- ee
-tiers:
+tiers:
- free
- premium
- ultimate
diff --git a/config/events/1666038724_Gitlab__Tracking__Helpers__WeakPasswordErrorEvent_track_weak_password_error.yml b/config/events/1666038724_Gitlab__Tracking__Helpers__WeakPasswordErrorEvent_track_weak_password_error.yml
index d19db52074b..4fc127ebfb1 100644
--- a/config/events/1666038724_Gitlab__Tracking__Helpers__WeakPasswordErrorEvent_track_weak_password_error.yml
+++ b/config/events/1666038724_Gitlab__Tracking__Helpers__WeakPasswordErrorEvent_track_weak_password_error.yml
@@ -16,7 +16,7 @@ identifiers:
product_section: dev
product_stage: manage
product_group: group::authentication and authorization
-product_category: authentication_and_authorization
+product_category: system_access
milestone: "15.6"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100237
distributions:
diff --git a/config/events/1674843937_Ci__Build_create_id_tokens.yml b/config/events/1674843937_Ci__Build_create_id_tokens.yml
index a6cc03c2bad..ca9f9c04213 100644
--- a/config/events/1674843937_Ci__Build_create_id_tokens.yml
+++ b/config/events/1674843937_Ci__Build_create_id_tokens.yml
@@ -19,7 +19,7 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110422
distributions:
- ce
- ee
-tiers:
+tiers:
- free
- premium
- ultimate
diff --git a/config/events/1676085590_Admin__AuditLogsController_visit_instance_compliance_audit_events.yml b/config/events/1676085590_Admin__AuditLogsController_visit_instance_compliance_audit_events.yml
new file mode 100644
index 00000000000..28c80a4cbc7
--- /dev/null
+++ b/config/events/1676085590_Admin__AuditLogsController_visit_instance_compliance_audit_events.yml
@@ -0,0 +1,26 @@
+---
+description: Mirrored `i_compliance_audit_events` Redis HLL metric as a Snowplow event. Emitted when audit logs page is visited in Admin area.
+category: Admin::AuditLogsController
+action: visit_instance_compliance_audit_events
+label_description: Mirrored Service Ping metric key path
+property_description: Mirrored Service Ping Redis HLL event name
+value_description:
+extra_properties:
+identifiers:
+#- project
+- user
+#- namespace
+product_section: dev
+product_stage: manage
+product_group: compliance
+product_category: compliance_management
+milestone: "15.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107120
+distributions:
+#- ce
+- ee
+tiers:
+#- free
+- premium
+- ultimate
+
diff --git a/config/events/1676085625_Admin__CredentialsController_visit_compliance_credential_inventory.yml b/config/events/1676085625_Admin__CredentialsController_visit_compliance_credential_inventory.yml
new file mode 100644
index 00000000000..ce1000556a7
--- /dev/null
+++ b/config/events/1676085625_Admin__CredentialsController_visit_compliance_credential_inventory.yml
@@ -0,0 +1,26 @@
+---
+description: Mirrored `i_compliance_credential_inventory` Redis HLL metric as a Snowplow event. Emitted when credentials page is visited in Admin area.
+category: Admin::CredentialsController
+action: visit_compliance_credential_inventory
+label_description: Mirrored Service Ping metric key path
+property_description: Mirrored Service Ping Redis HLL event name
+value_description:
+extra_properties:
+identifiers:
+#- project
+- user
+#- namespace
+product_section: dev
+product_stage: manage
+product_group: compliance
+product_category: compliance_management
+milestone: "15.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107120
+distributions:
+#- ce
+- ee
+tiers:
+#- free
+- premium
+- ultimate
+
diff --git a/config/events/1676085737_Groups__AuditEventsController_visit_group_compliance_audit_events.yml b/config/events/1676085737_Groups__AuditEventsController_visit_group_compliance_audit_events.yml
new file mode 100644
index 00000000000..c2b8dd03ac2
--- /dev/null
+++ b/config/events/1676085737_Groups__AuditEventsController_visit_group_compliance_audit_events.yml
@@ -0,0 +1,26 @@
+---
+description: Mirrored `g_compliance_audit_events` Redis HLL metric as a Snowplow event. Emitted when group audit events page is visited.
+category: Groups::AuditEventsController
+action: visit_group_compliance_audit_events
+label_description: Mirrored Service Ping metric key path
+property_description: Mirrored Service Ping Redis HLL event name
+value_description:
+extra_properties:
+identifiers:
+#- project
+- user
+- namespace
+product_section: dev
+product_stage: manage
+product_group: compliance
+product_category: compliance_management
+milestone: "15.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107120
+distributions:
+#- ce
+- ee
+tiers:
+#- free
+- premium
+- ultimate
+
diff --git a/config/events/1676085856_API__AuditEvents_admin_audit_event_request.yml b/config/events/1676085856_API__AuditEvents_admin_audit_event_request.yml
new file mode 100644
index 00000000000..4a0db5f83a8
--- /dev/null
+++ b/config/events/1676085856_API__AuditEvents_admin_audit_event_request.yml
@@ -0,0 +1,26 @@
+---
+description: Mirrored `a_compliance_audit_events_api` Redis HLL metric as a Snowplow event. Emitted when Instance Audit Events REST API endpoint is called.
+category: API::AuditEvents
+action: admin_audit_event_request
+label_description: Mirrored Service Ping metric key path
+property_description: Mirrored Service Ping Redis HLL event name
+value_description:
+extra_properties:
+identifiers:
+#- project
+- user
+#- namespace
+product_section: dev
+product_stage: manage
+product_group: compliance
+product_category: compliance_management
+milestone: "15.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107120
+distributions:
+#- ce
+- ee
+tiers:
+#- free
+- premium
+- ultimate
+
diff --git a/config/events/1676085891_EE__API__Groups_group_audit_event_request.yml b/config/events/1676085891_EE__API__Groups_group_audit_event_request.yml
new file mode 100644
index 00000000000..cbc12d58ed1
--- /dev/null
+++ b/config/events/1676085891_EE__API__Groups_group_audit_event_request.yml
@@ -0,0 +1,26 @@
+---
+description: Mirrored `a_compliance_audit_events_api` Redis HLL metric as a Snowplow event. Emitted when Group Audit Events REST API endpoint is called.
+category: EE::API::Groups
+action: group_audit_event_request
+label_description: Mirrored Service Ping metric key path
+property_description: Mirrored Service Ping Redis HLL event name
+value_description:
+extra_properties:
+identifiers:
+#- project
+- user
+- namespace
+product_section: dev
+product_stage: manage
+product_group: compliance
+product_category: compliance_management
+milestone: "15.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107120
+distributions:
+#- ce
+- ee
+tiers:
+#- free
+- premium
+- ultimate
+
diff --git a/config/events/1676085919_EE__API__Projects_project_audit_event_request.yml b/config/events/1676085919_EE__API__Projects_project_audit_event_request.yml
new file mode 100644
index 00000000000..8b895871275
--- /dev/null
+++ b/config/events/1676085919_EE__API__Projects_project_audit_event_request.yml
@@ -0,0 +1,26 @@
+---
+description: Mirrored `a_compliance_audit_events_api` Redis HLL metric as a Snowplow event. Emitted when Project Audit Events REST API endpoint is called.
+category: EE::API::Projects
+action: project_audit_event_request
+label_description: Mirrored Service Ping metric key path
+property_description: Mirrored Service Ping Redis HLL event name
+value_description:
+extra_properties:
+identifiers:
+- project
+- user
+- namespace
+product_section: dev
+product_stage: manage
+product_group: compliance
+product_category: compliance_management
+milestone: "15.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107120
+distributions:
+#- ce
+- ee
+tiers:
+#- free
+- premium
+- ultimate
+
diff --git a/config/events/202109151015_notes__create_service_execute.yml b/config/events/202109151015_notes__create_service_execute.yml
index 12da6da02f0..5ca57011bb9 100644
--- a/config/events/202109151015_notes__create_service_execute.yml
+++ b/config/events/202109151015_notes__create_service_execute.yml
@@ -8,7 +8,7 @@ extra_properties:
identifiers:
product_section: ops
product_stage: verify
-product_group: group::pipeline insights
+product_group: group::pipeline execution
product_category:
milestone: "12.5"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18890
diff --git a/config/events/20211215022206_default_review_app_open_review_app.yml b/config/events/20211215022206_default_review_app_open_review_app.yml
index c77b904bc01..67e7e9be15d 100644
--- a/config/events/20211215022206_default_review_app_open_review_app.yml
+++ b/config/events/20211215022206_default_review_app_open_review_app.yml
@@ -8,7 +8,7 @@ extra_properties:
identifiers:
product_section: ops
product_stage: verify
-product_group: group::pipeline insights
+product_group: group::pipeline execution
product_category:
milestone: "12.6"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18141
diff --git a/config/events/20230228151130_invite_members_modal_click_cancel.yml b/config/events/20230228151130_invite_members_modal_click_cancel.yml
new file mode 100644
index 00000000000..76ae982fd8b
--- /dev/null
+++ b/config/events/20230228151130_invite_members_modal_click_cancel.yml
@@ -0,0 +1,26 @@
+---
+description: Invite members modal is canceled
+category: invite_members_modal
+action: click_cancel
+label_description: area/source of invite members modal being triggered
+property_description:
+value_description:
+extra_properties:
+identifiers:
+- project
+- user
+- namespace
+product_section: growth
+product_stage: growth
+product_group: activation
+product_category:
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112958
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
+
diff --git a/config/events/20230228151130_invite_members_modal_click_x.yml b/config/events/20230228151130_invite_members_modal_click_x.yml
new file mode 100644
index 00000000000..6b9830add5f
--- /dev/null
+++ b/config/events/20230228151130_invite_members_modal_click_x.yml
@@ -0,0 +1,26 @@
+---
+description: Invite members modal is dismissed
+category: invite_members_modal
+action: click_x
+label_description: area/source of invite members modal being triggered
+property_description:
+value_description:
+extra_properties:
+identifiers:
+- project
+- user
+- namespace
+product_section: growth
+product_stage: growth
+product_group: activation
+product_category:
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112958
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
+
diff --git a/config/events/20230228151130_invite_members_modal_invite_successful.yml b/config/events/20230228151130_invite_members_modal_invite_successful.yml
new file mode 100644
index 00000000000..5f0beed721f
--- /dev/null
+++ b/config/events/20230228151130_invite_members_modal_invite_successful.yml
@@ -0,0 +1,26 @@
+---
+description: Invite members modal is submitted successfully
+category: invite_members_modal
+action: invite_successful
+label_description: area/source of invite members modal being triggered
+property_description:
+value_description:
+extra_properties:
+identifiers:
+- project
+- user
+- namespace
+product_section: growth
+product_stage: growth
+product_group: activation
+product_category:
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112958
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
+
diff --git a/config/events/20230228151130_invite_members_modal_render.yml b/config/events/20230228151130_invite_members_modal_render.yml
new file mode 100644
index 00000000000..5417d64c6e7
--- /dev/null
+++ b/config/events/20230228151130_invite_members_modal_render.yml
@@ -0,0 +1,26 @@
+---
+description: Invite members modal is opened from top nav
+category: invite_members_modal
+action: render
+label_description: area/source of invite members modal being triggered
+property_description:
+value_description:
+extra_properties:
+identifiers:
+- project
+- user
+- namespace
+product_section: growth
+product_stage: growth
+product_group: activation
+product_category:
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112958
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
+
diff --git a/config/feature_categories.yml b/config/feature_categories.yml
index 64a4eeaaea3..1a4d6e59f2d 100644
--- a/config/feature_categories.yml
+++ b/config/feature_categories.yml
@@ -15,12 +15,12 @@
- application_performance
- attack_emulation
- audit_events
-- authentication_and_authorization
- auto_devops
- backup_restore
- billing_and_payments
- build
- build_artifacts
+- capacity_planning
- cloud_native_installation
- cluster_cost_management
- code_quality
@@ -35,7 +35,6 @@
- continuous_delivery
- continuous_integration
- continuous_verification
-- credential_management
- customersdot_application
- database
- dataops
@@ -67,6 +66,7 @@
- geo_replication
- gitaly
- gitlab_cli
+- gitlab_docs
- global_search
- helm_chart_registry
- importers
@@ -93,9 +93,7 @@
- onboarding
- package_registry
- pages
-- performance_testing
-- permissions
-- pipeline_authoring
+- pipeline_composition
- planning_analytics
- pods
- portfolio_management
diff --git a/config/feature_flags/development/abuse_reports_list.yml b/config/feature_flags/development/abuse_reports_list.yml
new file mode 100644
index 00000000000..21954797720
--- /dev/null
+++ b/config/feature_flags/development/abuse_reports_list.yml
@@ -0,0 +1,8 @@
+---
+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/achievements.yml b/config/feature_flags/development/achievements.yml
index 853a8133351..ef4842b45bb 100644
--- a/config/feature_flags/development/achievements.yml
+++ b/config/feature_flags/development/achievements.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106909
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386817
milestone: '15.8'
type: development
-group: group::organization
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/add_refresh_pull_mirror_worker.yml b/config/feature_flags/development/add_refresh_pull_mirror_worker.yml
deleted file mode 100644
index f59f0ff3d8e..00000000000
--- a/config/feature_flags/development/add_refresh_pull_mirror_worker.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: add_refresh_pull_mirror_worker
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103665
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382226
-milestone: '15.7'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/config/feature_flags/development/airflow_dags.yml b/config/feature_flags/development/airflow_dags.yml
deleted file mode 100644
index e32035e7d2a..00000000000
--- a/config/feature_flags/development/airflow_dags.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: airflow_dags
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108900
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387529
-milestone: '15.9'
-type: development
-group: group::incubation
-default_enabled: false
diff --git a/config/feature_flags/development/always_perform_delayed_deletion.yml b/config/feature_flags/development/always_perform_delayed_deletion.yml
new file mode 100644
index 00000000000..6708b5b9f90
--- /dev/null
+++ b/config/feature_flags/development/always_perform_delayed_deletion.yml
@@ -0,0 +1,8 @@
+---
+name: always_perform_delayed_deletion
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393622
+milestone: '15.10'
+type: development
+group: group::tenant scale
+default_enabled: false
diff --git a/config/feature_flags/development/apple_app_store_integration.yml b/config/feature_flags/development/apple_app_store_integration.yml
deleted file mode 100644
index ec55f1ef932..00000000000
--- a/config/feature_flags/development/apple_app_store_integration.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: apple_app_store_integration
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104888
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/385335
-milestone: '15.8'
-type: development
-group: group::incubation
-default_enabled: false
diff --git a/config/feature_flags/development/artifacts_management_page.yml b/config/feature_flags/development/artifacts_management_page.yml
index 94ef885f4b9..078e18a703f 100644
--- a/config/feature_flags/development/artifacts_management_page.yml
+++ b/config/feature_flags/development/artifacts_management_page.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16654
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/254938
milestone: '12.4'
type: development
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: false
diff --git a/config/feature_flags/development/blame_page_streaming.yml b/config/feature_flags/development/blame_page_streaming.yml
new file mode 100644
index 00000000000..44d64800dab
--- /dev/null
+++ b/config/feature_flags/development/blame_page_streaming.yml
@@ -0,0 +1,8 @@
+---
+name: blame_page_streaming
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110208
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392890
+milestone: '15.10'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/bulk_import_projects.yml b/config/feature_flags/development/bulk_import_projects.yml
deleted file mode 100644
index 853389577cf..00000000000
--- a/config/feature_flags/development/bulk_import_projects.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: bulk_import_projects
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68873
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339941
-milestone: '14.3'
-type: development
-group: group::import
-default_enabled: false
diff --git a/config/feature_flags/development/ci_batch_project_includes_context.yml b/config/feature_flags/development/ci_batch_project_includes_context.yml
new file mode 100644
index 00000000000..634ed19bf34
--- /dev/null
+++ b/config/feature_flags/development/ci_batch_project_includes_context.yml
@@ -0,0 +1,8 @@
+---
+name: ci_batch_project_includes_context
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112570
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392746
+milestone: '15.10'
+type: development
+group: group::pipeline authoring
+default_enabled: false
diff --git a/config/feature_flags/development/ci_destroy_unlocked_job_artifacts.yml b/config/feature_flags/development/ci_destroy_unlocked_job_artifacts.yml
deleted file mode 100644
index eba1c4ead3b..00000000000
--- a/config/feature_flags/development/ci_destroy_unlocked_job_artifacts.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_destroy_unlocked_job_artifacts
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72406
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338165
-milestone: '14.5'
-type: development
-group: group::pipeline insights
-default_enabled: true
diff --git a/config/feature_flags/development/ci_fix_max_includes.yml b/config/feature_flags/development/ci_fix_max_includes.yml
new file mode 100644
index 00000000000..b70fb3f1222
--- /dev/null
+++ b/config/feature_flags/development/ci_fix_max_includes.yml
@@ -0,0 +1,8 @@
+---
+name: ci_fix_max_includes
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112963
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390909
+milestone: '15.10'
+type: development
+group: group::pipeline authoring
+default_enabled: true
diff --git a/config/feature_flags/development/ci_hooks_pre_get_sources_script.yml b/config/feature_flags/development/ci_hooks_pre_get_sources_script.yml
deleted file mode 100644
index 42afd4235cc..00000000000
--- a/config/feature_flags/development/ci_hooks_pre_get_sources_script.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_hooks_pre_get_sources_script
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102332
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381840
-milestone: '15.6'
-type: development
-group: group::pipeline authoring
-default_enabled: false
diff --git a/config/feature_flags/development/ci_inbound_job_token_scope.yml b/config/feature_flags/development/ci_inbound_job_token_scope.yml
deleted file mode 100644
index a0e2e09dde5..00000000000
--- a/config/feature_flags/development/ci_inbound_job_token_scope.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_inbound_job_token_scope
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99165
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/376063
-milestone: '15.5'
-type: development
-group: group::pipeline execution
-default_enabled: true
diff --git a/config/feature_flags/development/ci_includes_count_duplicates.yml b/config/feature_flags/development/ci_includes_count_duplicates.yml
deleted file mode 100644
index 5e33edddc03..00000000000
--- a/config/feature_flags/development/ci_includes_count_duplicates.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_includes_count_duplicates
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111726
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/391517
-milestone: '15.9'
-type: development
-group: group::pipeline authoring
-default_enabled: false
diff --git a/config/feature_flags/development/ci_job_artifact_bulk_destroy.yml b/config/feature_flags/development/ci_job_artifact_bulk_destroy.yml
new file mode 100644
index 00000000000..a99c892020f
--- /dev/null
+++ b/config/feature_flags/development/ci_job_artifact_bulk_destroy.yml
@@ -0,0 +1,8 @@
+---
+name: ci_job_artifact_bulk_destroy
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110026
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386768
+milestone: '15.10'
+type: development
+group: group::pipeline security
+default_enabled: false
diff --git a/config/feature_flags/development/ci_private_catalog_beta.yml b/config/feature_flags/development/ci_private_catalog_beta.yml
new file mode 100644
index 00000000000..8e4cf3168b1
--- /dev/null
+++ b/config/feature_flags/development/ci_private_catalog_beta.yml
@@ -0,0 +1,8 @@
+name: ci_private_catalog_beta
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113407
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/394772
+milestone: '15.10'
+type: development
+group: group::pipeline authoring
+default_enabled: false
+
diff --git a/config/feature_flags/development/ci_variables_pages.yml b/config/feature_flags/development/ci_variables_pages.yml
new file mode 100644
index 00000000000..49fc081ede4
--- /dev/null
+++ b/config/feature_flags/development/ci_variables_pages.yml
@@ -0,0 +1,8 @@
+name: ci_variables_pages
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110817
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392874
+milestone: '15.10'
+type: development
+group: group::pipeline security
+default_enabled: false
+
diff --git a/config/feature_flags/development/cloudseed_aws.yml b/config/feature_flags/development/cloudseed_aws.yml
new file mode 100644
index 00000000000..eba4bede372
--- /dev/null
+++ b/config/feature_flags/development/cloudseed_aws.yml
@@ -0,0 +1,8 @@
+---
+name: cloudseed_aws
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114245
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/395777
+milestone: '15.10'
+type: development
+group: group::incubation
+default_enabled: false
diff --git a/config/feature_flags/development/code_basic_search_files_by_regexp.yml b/config/feature_flags/development/code_basic_search_files_by_regexp.yml
deleted file mode 100644
index e68581bdfbd..00000000000
--- a/config/feature_flags/development/code_basic_search_files_by_regexp.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-name: code_basic_search_files_by_regexp
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109987
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389551
-milestone: '15.9'
-type: development
-group: group::global search
-default_enabled: false
-
diff --git a/config/feature_flags/development/codeowners_default_owners.yml b/config/feature_flags/development/codeowners_default_owners.yml
new file mode 100644
index 00000000000..df8c24ed689
--- /dev/null
+++ b/config/feature_flags/development/codeowners_default_owners.yml
@@ -0,0 +1,8 @@
+---
+name: codeowners_default_owners
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113594
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/394811
+milestone: '15.11'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/counter_attribute_db_lease_for_update.yml b/config/feature_flags/development/counter_attribute_db_lease_for_update.yml
index 7c30bb3e913..8a991dd7aea 100644
--- a/config/feature_flags/development/counter_attribute_db_lease_for_update.yml
+++ b/config/feature_flags/development/counter_attribute_db_lease_for_update.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97912
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/374596
milestone: '15.5'
type: development
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: false
diff --git a/config/feature_flags/development/create_runner_workflow.yml b/config/feature_flags/development/create_runner_workflow.yml
deleted file mode 100644
index 1a0c8b3e847..00000000000
--- a/config/feature_flags/development/create_runner_workflow.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: create_runner_workflow
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109497
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389269
-milestone: '15.9'
-type: development
-group: group::runner
-default_enabled: false
diff --git a/config/feature_flags/development/create_runner_workflow_for_admin.yml b/config/feature_flags/development/create_runner_workflow_for_admin.yml
new file mode 100644
index 00000000000..8fd9c350ff5
--- /dev/null
+++ b/config/feature_flags/development/create_runner_workflow_for_admin.yml
@@ -0,0 +1,8 @@
+---
+name: create_runner_workflow_for_admin
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109497
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389269
+milestone: '15.9'
+type: development
+group: group::runner
+default_enabled: false
diff --git a/config/feature_flags/development/create_runner_workflow_for_namespace.yml b/config/feature_flags/development/create_runner_workflow_for_namespace.yml
new file mode 100644
index 00000000000..783bb9803a1
--- /dev/null
+++ b/config/feature_flags/development/create_runner_workflow_for_namespace.yml
@@ -0,0 +1,8 @@
+---
+name: create_runner_workflow_for_namespace
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113535
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393919
+milestone: '15.10'
+type: development
+group: group::runner
+default_enabled: false
diff --git a/config/feature_flags/development/deduplicate_archive_traces_cron_worker.yml b/config/feature_flags/development/deduplicate_archive_traces_cron_worker.yml
deleted file mode 100644
index c26968381ae..00000000000
--- a/config/feature_flags/development/deduplicate_archive_traces_cron_worker.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: deduplicate_archive_traces_cron_worker
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110305
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389632
-milestone: '15.9'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/delayed_repository_update_mirror_worker.yml b/config/feature_flags/development/delayed_repository_update_mirror_worker.yml
deleted file mode 100644
index acf5902716e..00000000000
--- a/config/feature_flags/development/delayed_repository_update_mirror_worker.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: delayed_repository_update_mirror_worker
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89501
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/362894
-milestone: '15.1'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/config/feature_flags/development/disable_update_max_seats_worker.yml b/config/feature_flags/development/disable_update_max_seats_worker.yml
new file mode 100644
index 00000000000..ae0fe482ee9
--- /dev/null
+++ b/config/feature_flags/development/disable_update_max_seats_worker.yml
@@ -0,0 +1,8 @@
+---
+name: disable_update_max_seats_worker
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114127
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725
+milestone: '15.10'
+type: development
+group: group::utilization
+default_enabled: false
diff --git a/config/feature_flags/development/disabled_mr_discussions_redis_cache.yml b/config/feature_flags/development/disabled_mr_discussions_redis_cache.yml
deleted file mode 100644
index c4f0ca0effe..00000000000
--- a/config/feature_flags/development/disabled_mr_discussions_redis_cache.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: disabled_mr_discussions_redis_cache
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92752
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368366
-milestone: '15.3'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/do_not_run_safety_net_auth_refresh_jobs.yml b/config/feature_flags/development/do_not_run_safety_net_auth_refresh_jobs.yml
index 30790841695..a7e34682278 100644
--- a/config/feature_flags/development/do_not_run_safety_net_auth_refresh_jobs.yml
+++ b/config/feature_flags/development/do_not_run_safety_net_auth_refresh_jobs.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110986
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390336
milestone: '15.9'
type: development
-group: group::organization
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/enable_environments_search_within_folder.yml b/config/feature_flags/development/enable_environments_search_within_folder.yml
index a03b31ffbfc..18edc467293 100644
--- a/config/feature_flags/development/enable_environments_search_within_folder.yml
+++ b/config/feature_flags/development/enable_environments_search_within_folder.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102227/
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382108
milestone: '15.7'
type: development
-group: group::release
+group: group::configure
default_enabled: true
diff --git a/config/feature_flags/development/enforce_max_attachment_size_upload_api.yml b/config/feature_flags/development/enforce_max_attachment_size_upload_api.yml
deleted file mode 100644
index 25e193aa590..00000000000
--- a/config/feature_flags/development/enforce_max_attachment_size_upload_api.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: enforce_max_attachment_size_upload_api
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57250
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/325787
-milestone: '13.11'
-type: development
-group: group::source code
-default_enabled: true
diff --git a/config/feature_flags/development/environment_details_vue.yml b/config/feature_flags/development/environment_details_vue.yml
index 5a647f65a7a..c757329c271 100644
--- a/config/feature_flags/development/environment_details_vue.yml
+++ b/config/feature_flags/development/environment_details_vue.yml
@@ -4,5 +4,5 @@ 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::release
+group: group::configure
default_enabled: false
diff --git a/config/feature_flags/development/environment_search_api_min_chars.yml b/config/feature_flags/development/environment_search_api_min_chars.yml
index 2d719a41cd0..4df65792218 100644
--- a/config/feature_flags/development/environment_search_api_min_chars.yml
+++ b/config/feature_flags/development/environment_search_api_min_chars.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108277
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387244
milestone: '15.8'
type: development
-group: group::release
+group: group::configure
default_enabled: false
diff --git a/config/feature_flags/development/environments_search_logging.yml b/config/feature_flags/development/environments_search_logging.yml
deleted file mode 100644
index 76f6c78154b..00000000000
--- a/config/feature_flags/development/environments_search_logging.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: environments_search_logging
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107866
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386778
-milestone: '15.8'
-type: development
-group: group::release
-default_enabled: false
diff --git a/config/feature_flags/development/fe_epic_board_total_weight.yml b/config/feature_flags/development/fe_epic_board_total_weight.yml
index 5550d7fa01d..4fbb7c2daf4 100644
--- a/config/feature_flags/development/fe_epic_board_total_weight.yml
+++ b/config/feature_flags/development/fe_epic_board_total_weight.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364503
milestone: '15.1'
type: development
group: group::product planning
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/file_line_blame.yml b/config/feature_flags/development/file_line_blame.yml
index f763d436041..b0762b18fed 100644
--- a/config/feature_flags/development/file_line_blame.yml
+++ b/config/feature_flags/development/file_line_blame.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370818
milestone: '15.3'
type: development
group: group::source code
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/full_path_project_search.yml b/config/feature_flags/development/full_path_project_search.yml
index 83c52a20995..19ce8d05502 100644
--- a/config/feature_flags/development/full_path_project_search.yml
+++ b/config/feature_flags/development/full_path_project_search.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/388473
milestone: '15.9'
type: development
group: group::threat insights
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/github_client_fetch_repos_via_graphql.yml b/config/feature_flags/development/github_client_fetch_repos_via_graphql.yml
deleted file mode 100644
index 2d045e8ca06..00000000000
--- a/config/feature_flags/development/github_client_fetch_repos_via_graphql.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: github_client_fetch_repos_via_graphql
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105824
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/385649
-milestone: '15.7'
-type: development
-group: group::import
-default_enabled: true
diff --git a/config/feature_flags/development/github_import_gists.yml b/config/feature_flags/development/github_import_gists.yml
index 8e6e5825362..a8d1483f26f 100644
--- a/config/feature_flags/development/github_import_gists.yml
+++ b/config/feature_flags/development/github_import_gists.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386579
milestone: '15.8'
type: development
group: group::import
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/google_play_integration.yml b/config/feature_flags/development/google_play_integration.yml
new file mode 100644
index 00000000000..81c509cdab7
--- /dev/null
+++ b/config/feature_flags/development/google_play_integration.yml
@@ -0,0 +1,8 @@
+---
+name: google_play_integration
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110440
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389611
+milestone: '15.10'
+type: development
+group: group::incubation
+default_enabled: false
diff --git a/config/feature_flags/development/hash_oauth_secrets.yml b/config/feature_flags/development/hash_oauth_secrets.yml
deleted file mode 100644
index 4f42dc6883c..00000000000
--- a/config/feature_flags/development/hash_oauth_secrets.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: hash_oauth_secrets
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96252
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/374588
-milestone: '15.4'
-type: development
-group: group::authentication and authorization
-default_enabled: true
diff --git a/config/feature_flags/development/hide_public_email_on_profile.yml b/config/feature_flags/development/hide_public_email_on_profile.yml
index acf8e4e9ca7..5bf5a203e49 100644
--- a/config/feature_flags/development/hide_public_email_on_profile.yml
+++ b/config/feature_flags/development/hide_public_email_on_profile.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79717
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351731
milestone: '14.8'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/improved_spread_parallel_import.yml b/config/feature_flags/development/improved_spread_parallel_import.yml
deleted file mode 100644
index a1d7caf12b0..00000000000
--- a/config/feature_flags/development/improved_spread_parallel_import.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: improved_spread_parallel_import
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109264
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/388665
-milestone: '15.9'
-type: development
-group: group::import
-default_enabled: true
diff --git a/config/feature_flags/development/incident_event_tags.yml b/config/feature_flags/development/incident_event_tags.yml
index 68101b21569..69a7b67a186 100644
--- a/config/feature_flags/development/incident_event_tags.yml
+++ b/config/feature_flags/development/incident_event_tags.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387647
milestone: '15.8'
type: development
group: group::respond
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/include_memberships_from_group_shares_in_preloader.yml b/config/feature_flags/development/include_memberships_from_group_shares_in_preloader.yml
deleted file mode 100644
index d7f2d1f5552..00000000000
--- a/config/feature_flags/development/include_memberships_from_group_shares_in_preloader.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: include_memberships_from_group_shares_in_preloader
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111157
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390780
-milestone: '15.9'
-type: development
-group: group::organization
-default_enabled: false
diff --git a/config/feature_flags/development/increase_page_size_exponentially.yml b/config/feature_flags/development/increase_page_size_exponentially.yml
deleted file mode 100644
index 8297a4078fa..00000000000
--- a/config/feature_flags/development/increase_page_size_exponentially.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: increase_page_size_exponentially
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66174
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369434
-milestone: '14.1'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/config/feature_flags/development/integration_slack_app_notifications.yml b/config/feature_flags/development/integration_slack_app_notifications.yml
deleted file mode 100644
index 4b9903b25c9..00000000000
--- a/config/feature_flags/development/integration_slack_app_notifications.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: integration_slack_app_notifications
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98663
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381012
-milestone: '15.5'
-type: development
-group: group::integrations
-default_enabled: false
diff --git a/config/feature_flags/development/invitation_flow_enforcement_setting.yml b/config/feature_flags/development/invitation_flow_enforcement_setting.yml
index 39da6c40bed..d5b5d57c933 100644
--- a/config/feature_flags/development/invitation_flow_enforcement_setting.yml
+++ b/config/feature_flags/development/invitation_flow_enforcement_setting.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92218
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367666
milestone: '15.4'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/kas_user_access.yml b/config/feature_flags/development/kas_user_access.yml
new file mode 100644
index 00000000000..efcf0c15227
--- /dev/null
+++ b/config/feature_flags/development/kas_user_access.yml
@@ -0,0 +1,8 @@
+---
+name: kas_user_access
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104504'
+rollout_issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391201'
+milestone: '15.10'
+type: development
+group: group::configure
+default_enabled: false
diff --git a/config/feature_flags/development/kas_user_access_project.yml b/config/feature_flags/development/kas_user_access_project.yml
new file mode 100644
index 00000000000..34a4ac1271a
--- /dev/null
+++ b/config/feature_flags/development/kas_user_access_project.yml
@@ -0,0 +1,8 @@
+---
+name: kas_user_access_project
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104504'
+rollout_issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391211'
+milestone: '15.10'
+type: development
+group: group::configure
+default_enabled: false
diff --git a/config/feature_flags/development/large_ipynb_diffs.yml b/config/feature_flags/development/large_ipynb_diffs.yml
new file mode 100644
index 00000000000..fd1f8f487e6
--- /dev/null
+++ b/config/feature_flags/development/large_ipynb_diffs.yml
@@ -0,0 +1,8 @@
+---
+name: large_ipynb_diffs
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113370
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393886
+milestone: '15.10'
+type: development
+group: group::incubation
+default_enabled: false
diff --git a/config/feature_flags/development/lazy_load_pipeline_dropdown_actions.yml b/config/feature_flags/development/lazy_load_pipeline_dropdown_actions.yml
new file mode 100644
index 00000000000..136cb9a3615
--- /dev/null
+++ b/config/feature_flags/development/lazy_load_pipeline_dropdown_actions.yml
@@ -0,0 +1,8 @@
+---
+name: lazy_load_pipeline_dropdown_actions
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114490
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393846
+milestone: '15.10'
+type: development
+group: group::pipeline execution
+default_enabled: false
diff --git a/config/feature_flags/development/license_from_gitaly.yml b/config/feature_flags/development/license_from_gitaly.yml
deleted file mode 100644
index ad79d56a8ab..00000000000
--- a/config/feature_flags/development/license_from_gitaly.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: license_from_gitaly
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77041
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/374300
-milestone: '15.5'
-type: development
-group: group::gitaly
-default_enabled: false
diff --git a/config/feature_flags/development/limited_capacity_seat_refresh_worker_high.yml b/config/feature_flags/development/limited_capacity_seat_refresh_worker_high.yml
deleted file mode 100644
index 28f1c8a988e..00000000000
--- a/config/feature_flags/development/limited_capacity_seat_refresh_worker_high.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: limited_capacity_seat_refresh_worker_high
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104099
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725
-milestone: '15.9'
-type: development
-group: group::utilization
-default_enabled: false
diff --git a/config/feature_flags/development/limited_capacity_seat_refresh_worker_low.yml b/config/feature_flags/development/limited_capacity_seat_refresh_worker_low.yml
deleted file mode 100644
index a0b306ac792..00000000000
--- a/config/feature_flags/development/limited_capacity_seat_refresh_worker_low.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: limited_capacity_seat_refresh_worker_low
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104099
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725
-milestone: '15.9'
-type: development
-group: group::utilization
-default_enabled: false
diff --git a/config/feature_flags/development/limited_capacity_seat_refresh_worker_medium.yml b/config/feature_flags/development/limited_capacity_seat_refresh_worker_medium.yml
deleted file mode 100644
index 1df482e0624..00000000000
--- a/config/feature_flags/development/limited_capacity_seat_refresh_worker_medium.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: limited_capacity_seat_refresh_worker_medium
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104099
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725
-milestone: '15.9'
-type: development
-group: group::utilization
-default_enabled: false
diff --git a/config/feature_flags/development/linear_group_descendants_finder_upto.yml b/config/feature_flags/development/linear_group_descendants_finder_upto.yml
index db3a37191ff..f2f4bec57da 100644
--- a/config/feature_flags/development/linear_group_descendants_finder_upto.yml
+++ b/config/feature_flags/development/linear_group_descendants_finder_upto.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78991
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350972
milestone: '14.8'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/linear_project_ancestors.yml b/config/feature_flags/development/linear_project_ancestors.yml
deleted file mode 100644
index 00b04b20b30..00000000000
--- a/config/feature_flags/development/linear_project_ancestors.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: linear_project_ancestors
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68072
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338403
-milestone: '14.2'
-type: development
-group: group::authentication and authorization
-default_enabled: false
diff --git a/config/feature_flags/development/linear_user_manageable_groups.yml b/config/feature_flags/development/linear_user_manageable_groups.yml
deleted file mode 100644
index 8d59d689f6e..00000000000
--- a/config/feature_flags/development/linear_user_manageable_groups.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: linear_user_manageable_groups
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68845
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339434
-milestone: '14.3'
-type: development
-group: group::authentication and authorization
-default_enabled: false
diff --git a/config/feature_flags/development/log_response_length.yml b/config/feature_flags/development/log_response_length.yml
index 1ade057204c..689a262bec1 100644
--- a/config/feature_flags/development/log_response_length.yml
+++ b/config/feature_flags/development/log_response_length.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91448
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/366854
milestone: '15.3'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/log_user_git_push_activity.yml b/config/feature_flags/development/log_user_git_push_activity.yml
new file mode 100644
index 00000000000..5e45670a8cd
--- /dev/null
+++ b/config/feature_flags/development/log_user_git_push_activity.yml
@@ -0,0 +1,8 @@
+---
+name: log_user_git_push_activity
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112527
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393283
+milestone: "15.10"
+type: development
+group: group::utilization
+default_enabled: false
diff --git a/config/feature_flags/development/mr_show_reports_immediately.yml b/config/feature_flags/development/mr_show_reports_immediately.yml
index 23ac381a521..08cc49bcfd3 100644
--- a/config/feature_flags/development/mr_show_reports_immediately.yml
+++ b/config/feature_flags/development/mr_show_reports_immediately.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76612
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367027
milestone: '15.2'
type: development
-group: group::pipeline insights
+group: group::pipeline execution
default_enabled: false
diff --git a/config/feature_flags/development/multiple_environment_approval_rules_fe.yml b/config/feature_flags/development/multiple_environment_approval_rules_fe.yml
index c282313f409..d97c6114a67 100644
--- a/config/feature_flags/development/multiple_environment_approval_rules_fe.yml
+++ b/config/feature_flags/development/multiple_environment_approval_rules_fe.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105719
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/384334
milestone: '15.7'
type: development
-group: group::release
+group: group::configure
default_enabled: false
diff --git a/config/feature_flags/development/non_public_artifacts.yml b/config/feature_flags/development/non_public_artifacts.yml
index e2a2fd49df7..74826abd7df 100644
--- a/config/feature_flags/development/non_public_artifacts.yml
+++ b/config/feature_flags/development/non_public_artifacts.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49775
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/294503
milestone: '13.8'
type: development
-group: group::configure
+group: group::pipeline security
default_enabled: false
diff --git a/config/feature_flags/development/notes_create_service_tracking.yml b/config/feature_flags/development/notes_create_service_tracking.yml
deleted file mode 100644
index 578c1e2a707..00000000000
--- a/config/feature_flags/development/notes_create_service_tracking.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: notes_create_service_tracking
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18890
-rollout_issue_url:
-milestone: '12.5'
-type: development
-group: group::pipeline insights
-default_enabled: false
diff --git a/config/feature_flags/development/npm_allow_packages_in_multiple_projects.yml b/config/feature_flags/development/npm_allow_packages_in_multiple_projects.yml
new file mode 100644
index 00000000000..7541a0dd24e
--- /dev/null
+++ b/config/feature_flags/development/npm_allow_packages_in_multiple_projects.yml
@@ -0,0 +1,8 @@
+---
+name: npm_allow_packages_in_multiple_projects
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111775
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/391692
+milestone: '15.10'
+type: development
+group: group::package registry
+default_enabled: false
diff --git a/config/feature_flags/development/pages_unique_domain.yml b/config/feature_flags/development/pages_unique_domain.yml
new file mode 100644
index 00000000000..7894cf5ceed
--- /dev/null
+++ b/config/feature_flags/development/pages_unique_domain.yml
@@ -0,0 +1,8 @@
+---
+name: pages_unique_domain
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109011
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/388151
+milestone: '15.9'
+type: development
+group: group::editor
+default_enabled: false
diff --git a/config/feature_flags/development/permit_all_shared_groups_for_approval.yml b/config/feature_flags/development/permit_all_shared_groups_for_approval.yml
deleted file mode 100644
index 4ea3b7f696b..00000000000
--- a/config/feature_flags/development/permit_all_shared_groups_for_approval.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: permit_all_shared_groups_for_approval
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80655
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/352766
-milestone: '14.8'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/config/feature_flags/development/pipeline_trigger_merge_status.yml b/config/feature_flags/development/pipeline_trigger_merge_status.yml
new file mode 100644
index 00000000000..13c3996cbc0
--- /dev/null
+++ b/config/feature_flags/development/pipeline_trigger_merge_status.yml
@@ -0,0 +1,8 @@
+---
+name: pipeline_trigger_merge_status
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112525
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392989
+milestone: '15.10'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/present_groups_select_all.yml b/config/feature_flags/development/present_groups_select_all.yml
index 4d8ac160fa0..76445fd9b95 100644
--- a/config/feature_flags/development/present_groups_select_all.yml
+++ b/config/feature_flags/development/present_groups_select_all.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93633
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370306
milestone: '15.5'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/profile_tabs_vue.yml b/config/feature_flags/development/profile_tabs_vue.yml
index 95fd4bbde27..7a8a30fed4b 100644
--- a/config/feature_flags/development/profile_tabs_vue.yml
+++ b/config/feature_flags/development/profile_tabs_vue.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109422
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/388708
milestone: '15.9'
type: development
-group: group::organization
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/project_members_index_by_project_namespace.yml b/config/feature_flags/development/project_members_index_by_project_namespace.yml
index 0727c32143a..54735275869 100644
--- a/config/feature_flags/development/project_members_index_by_project_namespace.yml
+++ b/config/feature_flags/development/project_members_index_by_project_namespace.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105781
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/384521
milestone: '15.7'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: true
diff --git a/config/feature_flags/development/project_statistics_bulk_increment.yml b/config/feature_flags/development/project_statistics_bulk_increment.yml
index 6e8b9083a4d..2fa2b6d2611 100644
--- a/config/feature_flags/development/project_statistics_bulk_increment.yml
+++ b/config/feature_flags/development/project_statistics_bulk_increment.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103879
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/385845
milestone: '15.7'
type: development
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: false
diff --git a/config/feature_flags/development/rate_limit_for_unauthenticated_projects_api_access.yml b/config/feature_flags/development/rate_limit_for_unauthenticated_projects_api_access.yml
new file mode 100644
index 00000000000..57b086f52be
--- /dev/null
+++ b/config/feature_flags/development/rate_limit_for_unauthenticated_projects_api_access.yml
@@ -0,0 +1,8 @@
+---
+name: rate_limit_for_unauthenticated_projects_api_access
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112283
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/391922
+milestone: '15.10'
+type: development
+group: group::tenant scale
+default_enabled: false
diff --git a/config/feature_flags/development/reduce_sub_batch_size_on_timeouts.yml b/config/feature_flags/development/reduce_sub_batch_size_on_timeouts.yml
new file mode 100644
index 00000000000..507fce9cfe5
--- /dev/null
+++ b/config/feature_flags/development/reduce_sub_batch_size_on_timeouts.yml
@@ -0,0 +1,8 @@
+---
+name: reduce_sub_batch_size_on_timeouts
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109354
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393556
+milestone: '15.10'
+type: development
+group: group::database
+default_enabled: false
diff --git a/config/feature_flags/development/refactor_ci_minutes_consumption.yml b/config/feature_flags/development/refactor_ci_minutes_consumption.yml
new file mode 100644
index 00000000000..b24cf3d30b2
--- /dev/null
+++ b/config/feature_flags/development/refactor_ci_minutes_consumption.yml
@@ -0,0 +1,8 @@
+---
+name: refactor_ci_minutes_consumption
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112352
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392949
+milestone: '15.10'
+type: development
+group: group::pipeline execution
+default_enabled: false
diff --git a/config/feature_flags/development/rely_on_protected_branches_cache.yml b/config/feature_flags/development/rely_on_protected_branches_cache.yml
deleted file mode 100644
index 5154d4cee08..00000000000
--- a/config/feature_flags/development/rely_on_protected_branches_cache.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: rely_on_protected_branches_cache
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92937
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370608
-milestone: '15.4'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/config/feature_flags/development/remove_job_token_on_completion.yml b/config/feature_flags/development/remove_job_token_on_completion.yml
deleted file mode 100644
index 4ab5ffc27ee..00000000000
--- a/config/feature_flags/development/remove_job_token_on_completion.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: remove_job_token_on_completion
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108021
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386871
-milestone: '15.8'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/repack_after_shard_migration.yml b/config/feature_flags/development/repack_after_shard_migration.yml
deleted file mode 100644
index 15b7a3e67b0..00000000000
--- a/config/feature_flags/development/repack_after_shard_migration.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: repack_after_shard_migration
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21502
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/195597
-milestone: '12.6'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/config/feature_flags/development/restrict_special_characters_in_namespace_path.yml b/config/feature_flags/development/restrict_special_characters_in_namespace_path.yml
new file mode 100644
index 00000000000..fb04e8310e5
--- /dev/null
+++ b/config/feature_flags/development/restrict_special_characters_in_namespace_path.yml
@@ -0,0 +1,8 @@
+---
+name: restrict_special_characters_in_namespace_path
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111017
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390954
+milestone: '15.9'
+type: development
+group: group::tenant scale
+default_enabled: false
diff --git a/config/feature_flags/development/revoke_ssh_signatures.yml b/config/feature_flags/development/revoke_ssh_signatures.yml
deleted file mode 100644
index de50bae7d1d..00000000000
--- a/config/feature_flags/development/revoke_ssh_signatures.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: revoke_ssh_signatures
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108344
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/388986
-milestone: '15.9'
-type: development
-group: group::source code
-default_enabled: true
diff --git a/config/feature_flags/development/route_hll_to_snowplow_phase2.yml b/config/feature_flags/development/route_hll_to_snowplow_phase2.yml
deleted file mode 100644
index 2a3a820afd2..00000000000
--- a/config/feature_flags/development/route_hll_to_snowplow_phase2.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: route_hll_to_snowplow_phase2
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88482
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/363562
-milestone: '15.1'
-type: development
-group: group::product intelligence
-default_enabled: true
diff --git a/config/feature_flags/development/runner_machine_heartbeat.yml b/config/feature_flags/development/runner_machine_heartbeat.yml
new file mode 100644
index 00000000000..6f00fa47821
--- /dev/null
+++ b/config/feature_flags/development/runner_machine_heartbeat.yml
@@ -0,0 +1,8 @@
+---
+name: runner_machine_heartbeat
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114859
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390261
+milestone: '15.10'
+type: development
+group: group::runner
+default_enabled: false
diff --git a/config/feature_flags/development/s3_multithreaded_uploads.yml b/config/feature_flags/development/s3_multithreaded_uploads.yml
index 6c3ecac4143..f2019f53275 100644
--- a/config/feature_flags/development/s3_multithreaded_uploads.yml
+++ b/config/feature_flags/development/s3_multithreaded_uploads.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50922
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/296772
milestone: '13.8'
type: development
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: true
diff --git a/config/feature_flags/development/search_blobs_language_aggregation.yml b/config/feature_flags/development/search_blobs_language_aggregation.yml
deleted file mode 100644
index da1b81dc52c..00000000000
--- a/config/feature_flags/development/search_blobs_language_aggregation.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: search_blobs_language_aggregation
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71937
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/342621
-milestone: '14.4'
-type: development
-group: group::global search
-default_enabled: false
diff --git a/config/feature_flags/development/search_index_integrity.yml b/config/feature_flags/development/search_index_integrity.yml
new file mode 100644
index 00000000000..84e1e4b65c8
--- /dev/null
+++ b/config/feature_flags/development/search_index_integrity.yml
@@ -0,0 +1,8 @@
+---
+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: false
diff --git a/config/feature_flags/development/search_index_partitioning_notes.yml b/config/feature_flags/development/search_index_partitioning_notes.yml
new file mode 100644
index 00000000000..1abd3be35c5
--- /dev/null
+++ b/config/feature_flags/development/search_index_partitioning_notes.yml
@@ -0,0 +1,8 @@
+---
+name: search_index_partitioning_notes
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112402
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392376
+milestone: '15.10'
+type: development
+group: group::global search
+default_enabled: false
diff --git a/config/feature_flags/development/sec_mark_dropped_findings_as_resolved_scheduler.yml b/config/feature_flags/development/sec_mark_dropped_findings_as_resolved_scheduler.yml
deleted file mode 100644
index 1f26ffb28ae..00000000000
--- a/config/feature_flags/development/sec_mark_dropped_findings_as_resolved_scheduler.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: sec_mark_dropped_findings_as_resolved_scheduler
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108486
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387577
-milestone: '15.8'
-type: development
-group: group::static analysis
-default_enabled: false
diff --git a/config/feature_flags/development/service_desk_new_note_email_native_attachments.yml b/config/feature_flags/development/service_desk_new_note_email_native_attachments.yml
index 2299b33db84..89f0804ad39 100644
--- a/config/feature_flags/development/service_desk_new_note_email_native_attachments.yml
+++ b/config/feature_flags/development/service_desk_new_note_email_native_attachments.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386860
milestone: '15.8'
type: development
group: group::respond
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/set_traversal_ids_on_save.yml b/config/feature_flags/development/set_traversal_ids_on_save.yml
deleted file mode 100644
index ea07dafd9e4..00000000000
--- a/config/feature_flags/development/set_traversal_ids_on_save.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: set_traversal_ids_on_save
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104328
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/383217
-milestone: '15.8'
-type: development
-group: group::organization
-default_enabled: false
diff --git a/config/feature_flags/development/show_group_readme.yml b/config/feature_flags/development/show_group_readme.yml
index b5764b9195f..6d581f79463 100644
--- a/config/feature_flags/development/show_group_readme.yml
+++ b/config/feature_flags/development/show_group_readme.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109480
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390230
milestone: '15.9'
type: development
-group: group::organization
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/show_tags_on_commits_view.yml b/config/feature_flags/development/show_tags_on_commits_view.yml
new file mode 100644
index 00000000000..1dba952c33f
--- /dev/null
+++ b/config/feature_flags/development/show_tags_on_commits_view.yml
@@ -0,0 +1,8 @@
+---
+name: show_tags_on_commits_view
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111493
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392003
+milestone: '15.10'
+type: development
+group: group::source code
+default_enabled: true
diff --git a/config/feature_flags/development/skip_group_share_unlink_auth_refresh.yml b/config/feature_flags/development/skip_group_share_unlink_auth_refresh.yml
index cd7acaceaf5..d6a0848d80b 100644
--- a/config/feature_flags/development/skip_group_share_unlink_auth_refresh.yml
+++ b/config/feature_flags/development/skip_group_share_unlink_auth_refresh.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90871
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/366086
milestone: '15.2'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/synchronize_fork.yml b/config/feature_flags/development/synchronize_fork.yml
new file mode 100644
index 00000000000..46307136c33
--- /dev/null
+++ b/config/feature_flags/development/synchronize_fork.yml
@@ -0,0 +1,8 @@
+---
+name: synchronize_fork
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114299
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/395793
+milestone: '15.10'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/trial_email_validation.yml b/config/feature_flags/development/trial_email_validation.yml
deleted file mode 100644
index c658a49f195..00000000000
--- a/config/feature_flags/development/trial_email_validation.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: trial_email_validation
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92762
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368999
-milestone: '15.3'
-type: development
-group: group::acquisition
-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
index 14d7b4921c1..933e8ace9cc 100644
--- a/config/feature_flags/development/ultimate_feature_removal_banner.yml
+++ b/config/feature_flags/development/ultimate_feature_removal_banner.yml
@@ -4,5 +4,5 @@ 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::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/unlink_fork_network_upon_visibility_decrease.yml b/config/feature_flags/development/unlink_fork_network_upon_visibility_decrease.yml
deleted file mode 100644
index e7e220c310b..00000000000
--- a/config/feature_flags/development/unlink_fork_network_upon_visibility_decrease.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: unlink_fork_network_upon_visibility_decrease
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20466
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369438
-milestone: '12.6'
-type: development
-group: group::source code
-default_enabled: true
diff --git a/config/feature_flags/development/use_iid_in_work_items_path.yml b/config/feature_flags/development/use_iid_in_work_items_path.yml
deleted file mode 100644
index d2d328bbbc1..00000000000
--- a/config/feature_flags/development/use_iid_in_work_items_path.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: use_iid_in_work_items_path
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101451
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378349
-milestone: '15.5'
-type: development
-group: group::project management
-default_enabled: false
diff --git a/config/feature_flags/development/use_response_url_for_chat_responder.yml b/config/feature_flags/development/use_response_url_for_chat_responder.yml
deleted file mode 100644
index 84ac2a27fab..00000000000
--- a/config/feature_flags/development/use_response_url_for_chat_responder.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: use_response_url_for_chat_responder
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110625
-rollout_issue_url:
-milestone: '15.9'
-type: development
-group: group::integrations
-default_enabled: false
diff --git a/config/feature_flags/development/use_sub_repositories_api.yml b/config/feature_flags/development/use_sub_repositories_api.yml
new file mode 100644
index 00000000000..1ce845b46bf
--- /dev/null
+++ b/config/feature_flags/development/use_sub_repositories_api.yml
@@ -0,0 +1,8 @@
+---
+name: use_sub_repositories_api
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110664
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392372
+milestone: '15.10'
+type: development
+group: group::container registry
+default_enabled: false
diff --git a/config/feature_flags/development/use_traversal_ids.yml b/config/feature_flags/development/use_traversal_ids.yml
index 3d566ddc3c0..51f0ba39025 100644
--- a/config/feature_flags/development/use_traversal_ids.yml
+++ b/config/feature_flags/development/use_traversal_ids.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56296
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321948
milestone: '13.11'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: true
diff --git a/config/feature_flags/development/use_traversal_ids_for_ancestor_scopes.yml b/config/feature_flags/development/use_traversal_ids_for_ancestor_scopes.yml
index e2619ef5231..0ac765b6ab3 100644
--- a/config/feature_flags/development/use_traversal_ids_for_ancestor_scopes.yml
+++ b/config/feature_flags/development/use_traversal_ids_for_ancestor_scopes.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67652
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340159
milestone: '14.3'
type: development
-group: group::workspace
-default_enabled: false
+group: group::tenant scale
+default_enabled: true
diff --git a/config/feature_flags/development/use_traversal_ids_for_ancestors.yml b/config/feature_flags/development/use_traversal_ids_for_ancestors.yml
index 4a89aac140d..64ba5b17513 100644
--- a/config/feature_flags/development/use_traversal_ids_for_ancestors.yml
+++ b/config/feature_flags/development/use_traversal_ids_for_ancestors.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57137
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334952
milestone: '13.12'
type: development
-group: group::workspace
-default_enabled: false
+group: group::tenant scale
+default_enabled: true
diff --git a/config/feature_flags/development/use_traversal_ids_for_ancestors_upto.yml b/config/feature_flags/development/use_traversal_ids_for_ancestors_upto.yml
index 9da967f87ea..910cf3e2d83 100644
--- a/config/feature_flags/development/use_traversal_ids_for_ancestors_upto.yml
+++ b/config/feature_flags/development/use_traversal_ids_for_ancestors_upto.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72662
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343619
milestone: '14.6'
type: development
-group: group::workspace
-default_enabled: false
+group: group::tenant scale
+default_enabled: true
diff --git a/config/feature_flags/development/use_traversal_ids_for_descendants_scopes.yml b/config/feature_flags/development/use_traversal_ids_for_descendants_scopes.yml
index 3eece0b906a..74b6d6d2f70 100644
--- a/config/feature_flags/development/use_traversal_ids_for_descendants_scopes.yml
+++ b/config/feature_flags/development/use_traversal_ids_for_descendants_scopes.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78542
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350637
milestone: '14.8'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: true
diff --git a/config/feature_flags/development/use_traversal_ids_for_root_ancestor.yml b/config/feature_flags/development/use_traversal_ids_for_root_ancestor.yml
index 00c6edfc148..be9fd0a25f0 100644
--- a/config/feature_flags/development/use_traversal_ids_for_root_ancestor.yml
+++ b/config/feature_flags/development/use_traversal_ids_for_root_ancestor.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61163
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331907
milestone: '14.0'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: true
diff --git a/config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy.yml b/config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy.yml
index 06bddc2aa1c..e1f1ec0df35 100644
--- a/config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy.yml
+++ b/config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76814
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/348527
milestone: '14.7'
type: development
-group: group::workspace
-default_enabled: false
+group: group::tenant scale
+default_enabled: true
diff --git a/config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy_scopes.yml b/config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy_scopes.yml
index bdbfe33b16d..094534abc4d 100644
--- a/config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy_scopes.yml
+++ b/config/feature_flags/development/use_traversal_ids_for_self_and_hierarchy_scopes.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80045
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/352120
milestone: '14.8'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/use_traversal_ids_groups_finder.yml b/config/feature_flags/development/use_traversal_ids_groups_finder.yml
index 2f35ede7e87..f8a90bef1e6 100644
--- a/config/feature_flags/development/use_traversal_ids_groups_finder.yml
+++ b/config/feature_flags/development/use_traversal_ids_groups_finder.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67650
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345666
milestone: '14.6'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/use_traversal_ids_roots.yml b/config/feature_flags/development/use_traversal_ids_roots.yml
index 3c0685dc872..d1f4cec7517 100644
--- a/config/feature_flags/development/use_traversal_ids_roots.yml
+++ b/config/feature_flags/development/use_traversal_ids_roots.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74148
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345438
milestone: '14.5'
type: development
-group: group::workspace
-default_enabled: false
+group: group::tenant scale
+default_enabled: true
diff --git a/config/feature_flags/development/user_time_settings.yml b/config/feature_flags/development/user_time_settings.yml
index 77ee79fe80a..08a94fa80ce 100644
--- a/config/feature_flags/development/user_time_settings.yml
+++ b/config/feature_flags/development/user_time_settings.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/25
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321407
milestone: '11.11'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/development/validate_environment_tier_presence.yml b/config/feature_flags/development/validate_environment_tier_presence.yml
index 78593e338a4..5cc16b36f19 100644
--- a/config/feature_flags/development/validate_environment_tier_presence.yml
+++ b/config/feature_flags/development/validate_environment_tier_presence.yml
@@ -3,5 +3,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111011
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/391293
milestone: '15.9'
type: development
-group: group::release
+group: group::configure
default_enabled: true
diff --git a/config/feature_flags/development/vue_issues_dashboard.yml b/config/feature_flags/development/vue_issues_dashboard.yml
index 133343b3a3c..3091cf8b8b4 100644
--- a/config/feature_flags/development/vue_issues_dashboard.yml
+++ b/config/feature_flags/development/vue_issues_dashboard.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/379025
milestone: '15.6'
type: development
group: group::project management
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/webui_members_inherited_users.yml b/config/feature_flags/development/webui_members_inherited_users.yml
index 14704fd8341..a3efb05c140 100644
--- a/config/feature_flags/development/webui_members_inherited_users.yml
+++ b/config/feature_flags/development/webui_members_inherited_users.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83214
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364078
milestone: '15.4'
type: development
-group: group::workspace
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/experiment/generic_explore_groups.yml b/config/feature_flags/experiment/generic_explore_groups.yml
deleted file mode 100644
index d928dcd4189..00000000000
--- a/config/feature_flags/experiment/generic_explore_groups.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: generic_explore_groups
-introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103019"
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381564
-milestone: '15.6'
-type: experiment
-group: group::source code
-default_enabled: true
diff --git a/config/feature_flags/experiment/invite_members_in_side_nav.yml b/config/feature_flags/experiment/invite_members_in_side_nav.yml
deleted file mode 100644
index 1cb8d6d2b0a..00000000000
--- a/config/feature_flags/experiment/invite_members_in_side_nav.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: invite_members_in_side_nav
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70451
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/342951
-milestone: '14.5'
-type: experiment
-group: group::acquisition
-default_enabled: false
diff --git a/config/feature_flags/ops/advanced_user_index.yml b/config/feature_flags/ops/advanced_user_index.yml
deleted file mode 100644
index 2aa33aa265a..00000000000
--- a/config/feature_flags/ops/advanced_user_index.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: advanced_user_index
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110946
-rollout_issue_url:
-milestone: '15.9'
-type: ops
-group: group::global_search
-default_enabled: true
diff --git a/config/feature_flags/ops/advanced_user_search.yml b/config/feature_flags/ops/advanced_user_search.yml
deleted file mode 100644
index 0f52e9f22f0..00000000000
--- a/config/feature_flags/ops/advanced_user_search.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: advanced_user_search
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102724
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382542
-milestone: '15.7'
-type: ops
-group: group::global search
-default_enabled: false
diff --git a/config/feature_flags/ops/auto_disabling_web_hooks.yml b/config/feature_flags/ops/auto_disabling_web_hooks.yml
new file mode 100644
index 00000000000..2eebdd3d1d9
--- /dev/null
+++ b/config/feature_flags/ops/auto_disabling_web_hooks.yml
@@ -0,0 +1,9 @@
+---
+name: auto_disabling_web_hooks
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113479
+rollout_issue_url:
+milestone: '15.10'
+type: ops
+group: group::integrations
+default_enabled: false # Keep this value as false, as feature should be disabled by default for self-managed
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/390157.
diff --git a/config/feature_flags/ops/automatic_lock_writes_on_table.yml b/config/feature_flags/ops/automatic_lock_writes_on_table.yml
index 4e9ba8824a6..116814a1738 100644
--- a/config/feature_flags/ops/automatic_lock_writes_on_table.yml
+++ b/config/feature_flags/ops/automatic_lock_writes_on_table.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99287
rollout_issue_url:
milestone: '15.7'
type: ops
-group: group::pods
+group: group::tenant scale
default_enabled: true
diff --git a/config/feature_flags/ops/ci_build_dependencies_artifacts_logger.yml b/config/feature_flags/ops/ci_build_dependencies_artifacts_logger.yml
index 533900efdac..1e4e5ac3438 100644
--- a/config/feature_flags/ops/ci_build_dependencies_artifacts_logger.yml
+++ b/config/feature_flags/ops/ci_build_dependencies_artifacts_logger.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93179
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369441
milestone: '15.3'
type: ops
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: false
diff --git a/config/feature_flags/ops/detect_cross_database_modification.yml b/config/feature_flags/ops/detect_cross_database_modification.yml
index 5f496118c4b..6c94e81ba82 100644
--- a/config/feature_flags/ops/detect_cross_database_modification.yml
+++ b/config/feature_flags/ops/detect_cross_database_modification.yml
@@ -3,5 +3,5 @@ name: detect_cross_database_modification
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73316
milestone: '14.5'
type: ops
-group: group::sharding
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/ops/dynamic_image_resizing.yml b/config/feature_flags/ops/dynamic_image_resizing.yml
index 2b83b043a22..7ecf97d34a5 100644
--- a/config/feature_flags/ops/dynamic_image_resizing.yml
+++ b/config/feature_flags/ops/dynamic_image_resizing.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45050
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/266986
milestone: '13.6'
type: ops
-group: group::workspace
+group: group::tenant scale
default_enabled: true
diff --git a/config/feature_flags/ops/dynamic_nonce.yml b/config/feature_flags/ops/dynamic_nonce.yml
deleted file mode 100644
index ad8c63f9fa3..00000000000
--- a/config/feature_flags/ops/dynamic_nonce.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: dynamic_nonce
-introduced_by_url:
-rollout_issue_url:
-milestone: '14.0'
-type: ops
-group: group::authentication and authorization
-default_enabled: false
diff --git a/config/feature_flags/ops/legacy_open_source_license_available.yml b/config/feature_flags/ops/legacy_open_source_license_available.yml
index 36ee6c230bf..903212e90a0 100644
--- a/config/feature_flags/ops/legacy_open_source_license_available.yml
+++ b/config/feature_flags/ops/legacy_open_source_license_available.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79855
rollout_issue_url:
milestone: '14.8'
type: ops
-group: 'group::workspace'
+group: 'group::tenant scale'
default_enabled: true
diff --git a/config/feature_flags/ops/ops_prune_old_events.yml b/config/feature_flags/ops/ops_prune_old_events.yml
new file mode 100644
index 00000000000..3148afa633d
--- /dev/null
+++ b/config/feature_flags/ops/ops_prune_old_events.yml
@@ -0,0 +1,8 @@
+---
+name: ops_prune_old_events
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115100
+rollout_issue_url:
+milestone: '15.10'
+type: ops
+group: group::tenant scale
+default_enabled: true
diff --git a/config/feature_flags/ops/projects_build_artifacts_size_refresh.yml b/config/feature_flags/ops/projects_build_artifacts_size_refresh.yml
index 8b54a0e3ff5..e3b27dfe8ea 100644
--- a/config/feature_flags/ops/projects_build_artifacts_size_refresh.yml
+++ b/config/feature_flags/ops/projects_build_artifacts_size_refresh.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84701
rollout_issue_url:
milestone: '15.1'
type: ops
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: true
diff --git a/config/feature_flags/ops/projects_build_artifacts_size_refresh_high.yml b/config/feature_flags/ops/projects_build_artifacts_size_refresh_high.yml
index d16ee72ab71..5289bacae8e 100644
--- a/config/feature_flags/ops/projects_build_artifacts_size_refresh_high.yml
+++ b/config/feature_flags/ops/projects_build_artifacts_size_refresh_high.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84701
rollout_issue_url:
milestone: '15.8'
type: ops
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: false
diff --git a/config/feature_flags/ops/projects_build_artifacts_size_refresh_medium.yml b/config/feature_flags/ops/projects_build_artifacts_size_refresh_medium.yml
index 73bfd16ec94..0c38b67a9cc 100644
--- a/config/feature_flags/ops/projects_build_artifacts_size_refresh_medium.yml
+++ b/config/feature_flags/ops/projects_build_artifacts_size_refresh_medium.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84701
rollout_issue_url:
milestone: '15.8'
type: ops
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: false
diff --git a/config/feature_flags/ops/query_analyzer_gitlab_schema_metrics.yml b/config/feature_flags/ops/query_analyzer_gitlab_schema_metrics.yml
index 9793eebb014..3fe041105dd 100644
--- a/config/feature_flags/ops/query_analyzer_gitlab_schema_metrics.yml
+++ b/config/feature_flags/ops/query_analyzer_gitlab_schema_metrics.yml
@@ -3,5 +3,5 @@ name: query_analyzer_gitlab_schema_metrics
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73839
milestone: '14.5'
type: ops
-group: group::sharding
+group: group::tenant scale
default_enabled: false
diff --git a/config/feature_flags/ops/split_log_bulk_increment_counter.yml b/config/feature_flags/ops/split_log_bulk_increment_counter.yml
index ba8c3a7d22e..efc3f77b77b 100644
--- a/config/feature_flags/ops/split_log_bulk_increment_counter.yml
+++ b/config/feature_flags/ops/split_log_bulk_increment_counter.yml
@@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111147
rollout_issue_url:
milestone: '15.9'
type: ops
-group: group::pipeline insights
+group: group::pipeline security
default_enabled: false
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index c89db25c347..e8a88628a8a 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -495,7 +495,6 @@ production: &base
## To switch to a Jira connect development environment
jira_connect:
# atlassian_js_url: 'http://localhost:9292/atlassian.js'
- # enable_public_keys_storage: true
# enforce_jira_base_url_https: false
# additional_iframe_ancestors: ['localhost:*']
@@ -1168,6 +1167,16 @@ production: &base
# client_id: 'YOUR_FORTI_TOKEN_CLOUD_CLIENT_ID'
# client_secret: 'YOUR_FORTI_TOKEN_CLOUD_CLIENT_SECRET'
+ # Duo Auth settings
+ duo_auth:
+ # Allow using Duo as an OTP provider
+ enabled: false
+
+ # Client ID and Secret to access Duo's API
+ # integration_key: 'YOUR_DUO_INTEGRATION_KEY'
+ # secret_key: 'YOUR_DUO_SECRET_KEY'
+ # hostname: 'YOUR_DUO_API_FQDN'
+
# Shared file storage settings
shared:
# path: /mnt/gitlab # Default: shared
diff --git a/config/gitlab_loose_foreign_keys.yml b/config/gitlab_loose_foreign_keys.yml
index c4be4cc1800..2c630c9c1be 100644
--- a/config/gitlab_loose_foreign_keys.yml
+++ b/config/gitlab_loose_foreign_keys.yml
@@ -244,6 +244,10 @@ p_ci_builds_metadata:
- table: projects
column: project_id
on_delete: async_delete
+p_ci_runner_machine_builds:
+ - table: ci_runner_machines
+ column: runner_machine_id
+ on_delete: async_delete
packages_build_infos:
- table: ci_pipelines
column: pipeline_id
@@ -280,6 +284,10 @@ vulnerability_occurrence_pipelines:
- table: ci_pipelines
column: pipeline_id
on_delete: async_delete
+vulnerability_state_transitions:
+ - table: ci_pipelines
+ column: state_changed_at_pipeline_id
+ on_delete: async_nullify
vulnerability_statistics:
- table: ci_pipelines
column: latest_pipeline_id
diff --git a/config/initializers/0_1_yaml_safe_load_file_patch.rb b/config/initializers/0_1_yaml_safe_load_file_patch.rb
new file mode 100644
index 00000000000..f43712900eb
--- /dev/null
+++ b/config/initializers/0_1_yaml_safe_load_file_patch.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+# TODO: Remove this once we're on Ruby 3
+# https://gitlab.com/gitlab-org/gitlab/-/issues/393651
+unless YAML.respond_to?(:safe_load_file)
+ module YAML
+ # Temporary Ruby 2 back-compat workaround.
+ #
+ # This method only exists as of stdlib 3.0.0:
+ # https://ruby-doc.org/stdlib-3.0.0/libdoc/psych/rdoc/Psych.html
+ def self.safe_load_file(path, **options)
+ YAML.safe_load(File.read(path), **options)
+ end
+ end
+end
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index a1637d8c339..9cb1be45b68 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -449,8 +449,6 @@ Settings.mattermost['host'] = nil unless Settings.mattermost.enabled
Settings['jira_connect'] ||= Settingslogic.new({})
Settings.jira_connect['atlassian_js_url'] ||= 'https://connect-cdn.atl-paas.net/all.js'
-Settings.jira_connect['enable_public_keys_storage'] ||= false
-Settings.jira_connect['enable_public_keys_storage'] = true if Gitlab.com?
Settings.jira_connect['enforce_jira_base_url_https'] = true if Settings.jira_connect['enforce_jira_base_url_https'].nil?
Settings.jira_connect['additional_iframe_ancestors'] ||= []
@@ -779,7 +777,7 @@ Gitlab.ee do
Settings.cron_jobs['elastic_remove_expired_namespace_subscriptions_from_index_cron_worker']['cron'] ||= '10 3 * * *'
Settings.cron_jobs['elastic_remove_expired_namespace_subscriptions_from_index_cron_worker']['job_class'] ||= 'ElasticRemoveExpiredNamespaceSubscriptionsFromIndexCronWorker'
Settings.cron_jobs['elastic_migration_worker'] ||= Settingslogic.new({})
- Settings.cron_jobs['elastic_migration_worker']['cron'] ||= '*/30 * * * *'
+ Settings.cron_jobs['elastic_migration_worker']['cron'] ||= '*/5 * * * *'
Settings.cron_jobs['elastic_migration_worker']['job_class'] ||= 'Elastic::MigrationWorker'
Settings.cron_jobs['search_index_curation_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['search_index_curation_worker']['cron'] ||= '*/1 * * * *'
@@ -833,8 +831,11 @@ Gitlab.ee do
Settings.cron_jobs['abandoned_trial_emails']['cron'] ||= "0 1 * * *"
Settings.cron_jobs['abandoned_trial_emails']['job_class'] = 'Emails::AbandonedTrialEmailsCronWorker'
Settings.cron_jobs['package_metadata_sync_worker'] ||= Settingslogic.new({})
- Settings.cron_jobs['package_metadata_sync_worker']['cron'] ||= "0 1 * * *"
+ Settings.cron_jobs['package_metadata_sync_worker']['cron'] ||= "*/5 * * * *"
Settings.cron_jobs['package_metadata_sync_worker']['job_class'] = 'PackageMetadata::SyncWorker'
+ Settings.cron_jobs['compliance_violations_consistency_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['compliance_violations_consistency_worker']['cron'] ||= '0 1 * * *'
+ Settings.cron_jobs['compliance_violations_consistency_worker']['job_class'] = 'ComplianceManagement::MergeRequests::ComplianceViolationsConsistencyWorker'
Gitlab.com do
Settings.cron_jobs['free_user_cap_backfill_notification_jobs_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['free_user_cap_backfill_notification_jobs_worker']['cron'] ||= '*/5 * * * *'
@@ -856,7 +857,7 @@ end
#
Settings['sidekiq'] ||= Settingslogic.new({})
Settings['sidekiq']['log_format'] ||= 'default'
-Settings['sidekiq']['routing_rules'] ||= []
+Settings['sidekiq']['routing_rules'] = Settings.build_sidekiq_routing_rules(Settings['sidekiq']['routing_rules'])
#
# GitLab Shell
@@ -1015,6 +1016,12 @@ Settings['forti_token_cloud'] ||= Settingslogic.new({})
Settings.forti_token_cloud['enabled'] = false if Settings.forti_token_cloud['enabled'].nil?
#
+# DuoAuth
+#
+Settings['duo_auth'] ||= Settingslogic.new({})
+Settings.duo_auth['enabled'] = false if Settings.duo_auth['enabled'].nil?
+
+#
# Extra customization
#
Settings['extra'] ||= Settingslogic.new({})
diff --git a/config/initializers/7_redis.rb b/config/initializers/7_redis.rb
index 7773740fec4..85dee02cf01 100644
--- a/config/initializers/7_redis.rb
+++ b/config/initializers/7_redis.rb
@@ -5,6 +5,7 @@ require 'gitlab/redis'
Redis.raise_deprecations = true unless Rails.env.production?
Redis::Client.prepend(Gitlab::Instrumentation::RedisInterceptor)
+Redis::Cluster::NodeLoader.prepend(Gitlab::Patch::NodeLoader)
# Make sure we initialize a Redis connection pool before multi-threaded
# execution starts by
diff --git a/config/initializers/active_record_preloader.rb b/config/initializers/active_record_preloader.rb
index 198c97cb849..19ca380a866 100644
--- a/config/initializers/active_record_preloader.rb
+++ b/config/initializers/active_record_preloader.rb
@@ -3,6 +3,17 @@
module ActiveRecord
module Associations
class Preloader
+ def initialize(records: nil, associations: nil)
+ super()
+
+ @records = records
+ @associations = associations
+ end
+
+ def call
+ preload(@records, @associations)
+ end
+
class NullPreloader
def self.new(*args, **kwargs)
self
diff --git a/config/initializers/carrierwave_patch.rb b/config/initializers/carrierwave_patch.rb
index 6053154489f..cb476d9f01a 100644
--- a/config/initializers/carrierwave_patch.rb
+++ b/config/initializers/carrierwave_patch.rb
@@ -43,7 +43,7 @@ module CarrierWave
end
def authenticated_url(options = {})
- if %w[AWS Google Rackspace OpenStack AzureRM].include?(@uploader.fog_credentials[:provider])
+ if %w[AWS Google AzureRM].include?(@uploader.fog_credentials[:provider])
# avoid a get by using local references
local_directory = connection.directories.new(key: @uploader.fog_directory)
local_file = local_directory.files.new(key: path)
@@ -51,10 +51,6 @@ module CarrierWave
case @uploader.fog_credentials[:provider]
when 'AWS', 'Google', 'AzureRM'
local_file.url(expire_at, options)
- when 'Rackspace'
- connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
- when 'OpenStack'
- connection.get_object_https_url(@uploader.fog_directory, path, expire_at)
else
local_file.url(expire_at)
end
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index d24c5431f53..918b2767c4d 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -121,17 +121,3 @@ 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
end
-
-module Doorkeeper
- class AccessToken
- # Doorkeeper OAuth Token refresh uses expires_in of refresh token for new token
- # https://github.com/doorkeeper-gem/doorkeeper/pull/1366
- # This override ensures that tokens with expires_in: nil do not create new
- # tokens with expires_in: nil during refresh flow.
- # Can be removed after https://gitlab.com/gitlab-org/gitlab/-/issues/386094 is
- # closed
- def expires_in
- super || 2.hours
- end
- end
-end
diff --git a/config/initializers/fog_core_patch.rb b/config/initializers/fog_core_patch.rb
index 053e0460a19..f7d81f26be5 100644
--- a/config/initializers/fog_core_patch.rb
+++ b/config/initializers/fog_core_patch.rb
@@ -27,12 +27,11 @@
# closed:
#
# fog-google: https://github.com/fog/fog-google/issues/421
-# fog-rackspace: https://github.com/fog/fog-rackspace/issues/29
# fog-aliyun: https://github.com/fog/fog-aliyun/issues/23
module Fog
module ServicesMixin
# Gems that have not yet updated with the new fog-core namespace
- LEGACY_FOG_PROVIDERS = %w(google rackspace 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/google_cloud_profiler.rb b/config/initializers/google_cloud_profiler.rb
new file mode 100644
index 00000000000..8254f6d0e02
--- /dev/null
+++ b/config/initializers/google_cloud_profiler.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+return unless Gitlab::Utils.to_boolean(ENV['GITLAB_GOOGLE_CLOUD_PROFILER_ENABLED'])
+return unless ENV['GITLAB_GOOGLE_CLOUD_PROFILER_PROJECT_ID']
+
+# For the initial iteration, we enable it only for `web`.
+# This is because we have global service accounts configured this way, details:
+# https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/17492#note_1303914983
+return unless Gitlab::Runtime.puma?
+
+Gitlab::Cluster::LifecycleEvents.on_worker_start do
+ require 'cloud_profiler_agent'
+
+ agent = CloudProfilerAgent::Agent.new(
+ service: 'gitlab-web',
+ project_id: ENV['GITLAB_GOOGLE_CLOUD_PROFILER_PROJECT_ID'],
+ logger: ::Gitlab::AppJsonLogger.build,
+ log_labels: {
+ message: 'Google Cloud Profiler Ruby',
+ pid: $$,
+ worker_id: ::Prometheus::PidProvider.worker_id
+ }
+ )
+ agent.start
+end
diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb
index 61e357808d9..e5abc0b919b 100644
--- a/config/initializers/lograge.rb
+++ b/config/initializers/lograge.rb
@@ -8,7 +8,7 @@ unless Gitlab::Runtime.sidekiq?
Rails.application.configure do
config.lograge.enabled = true
# Store the lograge JSON files in a separate file
- config.lograge.keep_original_rails_log = Gitlab::Utils.to_boolean(ENV.fetch('UNSTRUCTURED_RAILS_LOG', 'true'))
+ config.lograge.keep_original_rails_log = Gitlab::Utils.to_boolean(ENV.fetch('UNSTRUCTURED_RAILS_LOG', 'false'))
# Don't use the Logstash formatter since this requires logstash-event, an
# unmaintained gem that monkey patches `Time`
config.lograge.formatter = Lograge::Formatters::Json.new
diff --git a/config/initializers/postgres_partitioning.rb b/config/initializers/postgres_partitioning.rb
index e7f29ee1a84..572c8439ec1 100644
--- a/config/initializers/postgres_partitioning.rb
+++ b/config/initializers/postgres_partitioning.rb
@@ -5,7 +5,8 @@ Gitlab::Database::Partitioning.register_models(
AuditEvent,
WebHookLog,
LooseForeignKeys::DeletedRecord,
- Gitlab::Database::BackgroundMigration::BatchedJobTransitionLog
+ Gitlab::Database::BackgroundMigration::BatchedJobTransitionLog,
+ Ci::RunnerMachineBuild
])
if Gitlab.ee?
diff --git a/config/initializers/safe_session_store_patch.rb b/config/initializers/safe_session_store_patch.rb
new file mode 100644
index 00000000000..7d3b9d0ae36
--- /dev/null
+++ b/config/initializers/safe_session_store_patch.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+# The Rails and Rack session stores allow developers to store arbitrary
+# Ruby objects in the Hash, which gets serialized to Redis. However,
+# serializing objects may lead to multi-version incompatibilities
+# (https://docs.gitlab.com/ee/development/multi_version_compatibility.html)
+# because there is no guarantee that the Ruby object is present in an
+# older version.
+#
+# To safeguard against this problem, this patch checks that objects
+# stored in the session are in an allow list. Note that these checks are
+# restricted to test and development environments at the moment. Only
+# add to the allow list if you know that the object should be handled
+# gracefully in a mixed deployment.
+return unless Rails.env.test? || Rails.env.development?
+
+module Rack
+ module Session
+ module Abstract
+ class SessionHash
+ module BlockRubyObjectSerialization
+ ALLOWED_OBJECTS = [
+ Symbol, String, Integer, Float, NilClass, TrueClass, FalseClass, ActiveSupport::SafeBuffer,
+ # Used in app/controllers/import/bitbucket_controller.rb
+ ActiveSupport::Duration, ActiveSupport::TimeWithZone,
+ # Used in ee/app/controllers/groups/omniauth_callbacks_controller.rb
+ OmniAuth::AuthHash, OmniAuth::AuthHash::InfoHash, OneLogin::RubySaml::Attributes,
+ OneLogin::RubySaml::Response
+ ].freeze
+
+ def []=(key, value)
+ unless safe_object?(value)
+ # rubocop:disable Gitlab/DocUrl
+ raise "Session attempted to store type #{value.class} with key '#{key}': #{value.inspect}.\n" \
+ "Serializing novel Ruby objects can cause uninitialized constants in mixed deployments.\n" \
+ "See https://docs.gitlab.com/ee/development/multi_version_compatibility.html"
+ # rubocop:enable Gitlab/DocUrl
+ end
+
+ super
+ end
+
+ private
+
+ def safe_object?(value)
+ return allowed_mock?(value) if Rails.env.test? && value.is_a?(RSpec::Mocks::InstanceVerifyingDouble)
+
+ case value
+ when Array
+ value.all? { |entry| safe_object?(entry) }
+ when Hash
+ safe_hash?(value)
+ else
+ ALLOWED_OBJECTS.include?(value.class)
+ end
+ end
+
+ def safe_hash?(value)
+ value.each do |key, val|
+ return false unless safe_object?(key)
+ return false unless safe_object?(val)
+ end
+ end
+
+ def allowed_mock?(value)
+ doubled_module = value.to_s
+
+ # We don't have access to the @doubled_module variable, but the output
+ # string will be in the form: "#[InstanceDouble(OneLogin::RubySaml::Response) (anonymous)]"
+ ALLOWED_OBJECTS.any? { |allowed| doubled_module.include?("InstanceDouble(#{allowed})") }
+ end
+ end
+
+ prepend BlockRubyObjectSerialization
+ end
+ end
+ end
+end
+
+ActionDispatch::Request::Session.prepend(Rack::Session::Abstract::SessionHash::BlockRubyObjectSerialization)
diff --git a/config/initializers_before_autoloader/001_fast_gettext.rb b/config/initializers_before_autoloader/001_fast_gettext.rb
index 3d54ed8f32f..01aec95ce53 100644
--- a/config/initializers_before_autoloader/001_fast_gettext.rb
+++ b/config/initializers_before_autoloader/001_fast_gettext.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
require_relative '../../lib/gitlab/i18n'
+require_relative '../../lib/gitlab/i18n/pluralization'
Gitlab::I18n.setup(domain: 'gitlab', default_locale: :en)
diff --git a/config/initializers_before_autoloader/004_zeitwerk.rb b/config/initializers_before_autoloader/004_zeitwerk.rb
index 8b3cdf1a80c..72e471d25f2 100644
--- a/config/initializers_before_autoloader/004_zeitwerk.rb
+++ b/config/initializers_before_autoloader/004_zeitwerk.rb
@@ -65,7 +65,6 @@ Rails.autoloaders.each do |autoloader|
'function_uri' => 'FunctionURI',
'uuid' => 'UUID',
'occurrence_uuid' => 'OccurrenceUUID',
- 'vulnerability_uuid' => 'VulnerabilityUUID',
- 'vs_code_extension_activity_unique_counter' => 'VSCodeExtensionActivityUniqueCounter'
+ 'vulnerability_uuid' => 'VulnerabilityUUID'
)
end
diff --git a/config/metrics/counts_28d/20210216175101_merge_requests_users.yml b/config/metrics/counts_28d/20210216175101_merge_requests_users.yml
index 07ad35e45bf..3029047f4ad 100644
--- a/config/metrics/counts_28d/20210216175101_merge_requests_users.yml
+++ b/config/metrics/counts_28d/20210216175101_merge_requests_users.yml
@@ -17,7 +17,5 @@ tier:
- free
- premium
- ultimate
-performance_indicator_type:
-- gmau
-- paid_gmau
+performance_indicator_type: []
milestone: "<13.9"
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 a6bfeed7059..d4411c5e153 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
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: redis_hll_counters.code_review.i_code_review_user_create_mr_monthly
description: Count of unique users per month who created a MR
product_section: dev
diff --git a/config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml b/config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml
index 8a57e5989c4..ac55cb82f8f 100644
--- a/config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml
+++ b/config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.verify.ci_pipeline_schedules
description: Distinct users creating pipeline schedules in a month
product_section: ops
diff --git a/config/metrics/counts_28d/20210216180312_snippets.yml b/config/metrics/counts_28d/20210216180312_snippets.yml
index dfe24039f52..616368ec513 100644
--- a/config/metrics/counts_28d/20210216180312_snippets.yml
+++ b/config/metrics/counts_28d/20210216180312_snippets.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts_monthly.snippets
description: Monthly count of All Snippets
product_section: dev
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 dd66f4a3b47..9d56815712f 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
@@ -7,7 +7,9 @@ product_stage: create
product_group: editor
product_category: web_ide
value_type: number
-status: active
+status: removed
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111351
+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 8dbf5e5ba41..592b02c84bc 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
@@ -7,7 +7,9 @@ product_stage: create
product_group: editor
product_category: web_ide
value_type: number
-status: active
+status: removed
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113551
+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 5a2d9c197ce..012f9db8c80 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
@@ -7,7 +7,9 @@ product_stage: create
product_group: editor
product_category: snippets
value_type: number
-status: active
+status: removed
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113551
+milestone_removed: 15.10
time_frame: 28d
data_source: redis_hll
distribution:
diff --git a/config/metrics/counts_28d/20210216180334_g_edit_by_sfe_monthly.yml b/config/metrics/counts_28d/20210216180334_g_edit_by_sfe_monthly.yml
index 78622d0fc18..1eda8cb2467 100644
--- a/config/metrics/counts_28d/20210216180334_g_edit_by_sfe_monthly.yml
+++ b/config/metrics/counts_28d/20210216180334_g_edit_by_sfe_monthly.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: redis_hll_counters.ide_edit.g_edit_by_sfe_monthly
description: Number of users editing a file from the single file editor
product_section: dev
diff --git a/config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml b/config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml
index 12b9e922a1c..2bcd22eb7fc 100644
--- a/config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml
+++ b/config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml
@@ -5,7 +5,7 @@ description: Internal Tracking to count number of unit tests parsed for planning
future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0)
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: code_testing
value_type: number
status: active
diff --git a/config/metrics/counts_28d/20210216183627_omniauth_providers.yml b/config/metrics/counts_28d/20210216183627_omniauth_providers.yml
index b65141906e8..ab7e89ce449 100644
--- a/config/metrics/counts_28d/20210216183627_omniauth_providers.yml
+++ b/config/metrics/counts_28d/20210216183627_omniauth_providers.yml
@@ -5,7 +5,7 @@ description: List of unique OmniAuth providers
product_section: dev
product_stage: manage
product_group: authentication_and_authorization
-product_category: authentication_and_authorization
+product_category: system_access
value_type: object
status: active
time_frame: 28d
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 90c053612cf..ac6500672c2 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
@@ -7,7 +7,9 @@ product_group: code_review
product_category: code_review
product_section: 'TBD'
value_type: number
-status: active
+status: removed
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113422
+milestone_removed: 15.10
time_frame: 28d
data_source: redis_hll
instrumentation_class: AggregatedMetric
diff --git a/config/metrics/counts_28d/20210216184458_p_ci_templates_implicit_auto_devops_monthly.yml b/config/metrics/counts_28d/20210216184458_p_ci_templates_implicit_auto_devops_monthly.yml
index 43a8a2340eb..c219ea4dbfd 100644
--- a/config/metrics/counts_28d/20210216184458_p_ci_templates_implicit_auto_devops_monthly.yml
+++ b/config/metrics/counts_28d/20210216184458_p_ci_templates_implicit_auto_devops_monthly.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_auto_devops_monthly
description: Count of pipelines with implicit Auto DevOps runs
product_section: ops
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 a5a6bcd1a93..ff4231231aa 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
@@ -57,6 +57,7 @@ options:
- p_ci_templates_security_dependency_scanning
- p_ci_templates_security_api_fuzzing
- p_ci_templates_security_dast
+ - p_ci_templates_security_api_discovery
- p_ci_templates_ios_fastlane
- p_ci_templates_composer
- p_ci_templates_c
diff --git a/config/metrics/counts_28d/20210409100451_users_expanding_testing_code_quality_report_monthly.yml b/config/metrics/counts_28d/20210409100451_users_expanding_testing_code_quality_report_monthly.yml
index 65b9764cf10..498569c95aa 100644
--- a/config/metrics/counts_28d/20210409100451_users_expanding_testing_code_quality_report_monthly.yml
+++ b/config/metrics/counts_28d/20210409100451_users_expanding_testing_code_quality_report_monthly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.testing.users_expanding_testing_code_quality_report
description: Count of expanding the code quality widget
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: code_quality
value_type: number
status: active
diff --git a/config/metrics/counts_28d/20210409100628_users_expanding_testing_accessibility_report_monthly.yml b/config/metrics/counts_28d/20210409100628_users_expanding_testing_accessibility_report_monthly.yml
index 601fc6fdab3..d800cd2f3e9 100644
--- a/config/metrics/counts_28d/20210409100628_users_expanding_testing_accessibility_report_monthly.yml
+++ b/config/metrics/counts_28d/20210409100628_users_expanding_testing_accessibility_report_monthly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.testing.users_expanding_testing_accessibility_repor
description: Count of expanding the accessibility report widget
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: accessibility_testing
value_type: number
status: active
diff --git a/config/metrics/counts_28d/20210413205507_i_testing_summary_widget_total_monthly.yml b/config/metrics/counts_28d/20210413205507_i_testing_summary_widget_total_monthly.yml
index 49cab313fc8..ed25f2c18a8 100644
--- a/config/metrics/counts_28d/20210413205507_i_testing_summary_widget_total_monthly.yml
+++ b/config/metrics/counts_28d/20210413205507_i_testing_summary_widget_total_monthly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.testing.i_testing_summary_widget_total_monthly
description: Unique users that expand the test summary merge request widget by month
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: testing
value_type: number
status: active
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 8a0005a5c5c..802fc03bee4 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
@@ -16,7 +16,9 @@ tier:
- free
- premium
- ultimate
-performance_indicator_type: []
+performance_indicator_type:
+- gmau
+- paid_gmau
time_frame: 28d
instrumentation_class: AggregatedMetric
data_source: redis_hll
diff --git a/config/metrics/counts_28d/20210910132229_user_auth_by_provider.yml b/config/metrics/counts_28d/20210910132229_user_auth_by_provider.yml
index 0ee3d694317..7aad160f01d 100644
--- a/config/metrics/counts_28d/20210910132229_user_auth_by_provider.yml
+++ b/config/metrics/counts_28d/20210910132229_user_auth_by_provider.yml
@@ -5,7 +5,7 @@ description: Number of unique user logins using two factor authentication for av
product_section: dev
product_stage: manage
product_group: authentication_and_authorization
-product_category: authentication_and_authorization
+product_category: system_access
value_type: object
status: active
milestone: "14.3"
diff --git a/config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml b/config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml
index 341d3810318..cd124735153 100644
--- a/config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml
+++ b/config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml
@@ -3,7 +3,7 @@ key_path: redis_hll_counters.testing.i_testing_test_report_uploaded_monthly
description: "MAU of junit test reports uploaded by customers per pipeline"
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: testing
value_type: number
status: active
diff --git a/config/metrics/counts_28d/20221101190915_i_testing_coverage_report_uploaded_monthly.yml b/config/metrics/counts_28d/20221101190915_i_testing_coverage_report_uploaded_monthly.yml
index ef51a24bc1e..a3d47aa4c49 100644
--- a/config/metrics/counts_28d/20221101190915_i_testing_coverage_report_uploaded_monthly.yml
+++ b/config/metrics/counts_28d/20221101190915_i_testing_coverage_report_uploaded_monthly.yml
@@ -3,7 +3,7 @@ key_path: redis_hll_counters.testing.i_testing_coverage_report_uploaded_monthly
description: "MAU of coverage test reports uploaded by customers per pipeline"
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: testing
value_type: number
status: active
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 dca8545691a..e081e74b967 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
@@ -11,7 +11,7 @@ milestone: "15.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106869
time_frame: 28d
data_source: redis_hll
-data_category: optional
+data_category: operational
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
options:
diff --git a/config/metrics/counts_28d/20230112174745_i_testing_active_user_monthly.yml b/config/metrics/counts_28d/20230112174745_i_testing_active_user_monthly.yml
index 8f73011a6ed..97a74e44f65 100644
--- a/config/metrics/counts_28d/20230112174745_i_testing_active_user_monthly.yml
+++ b/config/metrics/counts_28d/20230112174745_i_testing_active_user_monthly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.testing.i_testing_active_user_monthly
description: Count of monthly active users for pipeline insights features
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: testing
value_type: number
status: active
diff --git a/config/metrics/counts_28d/20230215180530_p_ci_templates_security_api_discovery_monthly.yml b/config/metrics/counts_28d/20230215180530_p_ci_templates_security_api_discovery_monthly.yml
new file mode 100644
index 00000000000..1fa9772ae67
--- /dev/null
+++ b/config/metrics/counts_28d/20230215180530_p_ci_templates_security_api_discovery_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_security_api_discovery_monthly
+description: Monthly counts for API Discovery CI template
+product_section: sec
+product_stage: secure
+product_group: dynamic_analysis
+product_category: dynamic_application_security_testing
+value_type: number
+status: active
+milestone: "15.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110493
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_security_api_discovery
diff --git a/config/metrics/counts_28d/20230217215050_ci_internal_pipelines.yml b/config/metrics/counts_28d/20230217215050_ci_internal_pipelines.yml
new file mode 100644
index 00000000000..5d927562f42
--- /dev/null
+++ b/config/metrics/counts_28d/20230217215050_ci_internal_pipelines.yml
@@ -0,0 +1,23 @@
+---
+key_path: counts_monthly.ci_internal_pipelines
+description: Total monthly (28D) pipelines in Gitlab repositories for all project and project types
+product_section: ops
+product_stage: verify
+product_group: pipeline_execution
+product_category: continuous_integration
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112370
+time_frame: 28d
+data_source: database
+data_category: operational
+instrumentation_class: CountCiInternalPipelinesMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20230224095530_bulk_import_entities_group_finished_with_failures.yml b/config/metrics/counts_28d/20230224095530_bulk_import_entities_group_finished_with_failures.yml
new file mode 100644
index 00000000000..4304dcd0c25
--- /dev/null
+++ b/config/metrics/counts_28d/20230224095530_bulk_import_entities_group_finished_with_failures.yml
@@ -0,0 +1,27 @@
+---
+data_category: optional
+key_path: usage_activity_by_stage_monthly.manage.group_imports.gitlab_migration_finished_with_failures
+description: Count of group entities with finished status and failures in GitLab Migration
+product_section: dev
+product_stage: manage
+product_group: import
+product_category: importers
+value_type: number
+status: active
+time_frame: 28d
+data_source: database
+instrumentation_class: CountBulkImportsEntitiesMetric
+options:
+ source_type: group_entity
+ status: 2
+ has_failures: true
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+milestone: "15.10"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112837"
diff --git a/config/metrics/counts_28d/20230224095530_bulk_import_entities_group_finished_without_failures.yml b/config/metrics/counts_28d/20230224095530_bulk_import_entities_group_finished_without_failures.yml
new file mode 100644
index 00000000000..376e9bd5baa
--- /dev/null
+++ b/config/metrics/counts_28d/20230224095530_bulk_import_entities_group_finished_without_failures.yml
@@ -0,0 +1,27 @@
+---
+data_category: optional
+key_path: usage_activity_by_stage_monthly.manage.group_imports.gitlab_migration_finished_without_failures
+description: Count of group entities with finished status and without failures in GitLab Migration
+product_section: dev
+product_stage: manage
+product_group: import
+product_category: importers
+value_type: number
+status: active
+time_frame: 28d
+data_source: database
+instrumentation_class: CountBulkImportsEntitiesMetric
+options:
+ source_type: group_entity
+ status: 2
+ has_failures: false
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+milestone: "15.10"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112837"
diff --git a/config/metrics/counts_28d/20230224095530_bulk_import_entities_project_finished_with_failures.yml b/config/metrics/counts_28d/20230224095530_bulk_import_entities_project_finished_with_failures.yml
new file mode 100644
index 00000000000..5b0e4db64ad
--- /dev/null
+++ b/config/metrics/counts_28d/20230224095530_bulk_import_entities_project_finished_with_failures.yml
@@ -0,0 +1,27 @@
+---
+data_category: optional
+key_path: usage_activity_by_stage_monthly.manage.project_imports.gitlab_migration_finished_with_failures
+description: Count of project entities with finished status and failures in GitLab Migration
+product_section: dev
+product_stage: manage
+product_group: import
+product_category: importers
+value_type: number
+status: active
+time_frame: 28d
+data_source: database
+instrumentation_class: CountBulkImportsEntitiesMetric
+options:
+ source_type: project_entity
+ status: 2
+ has_failures: true
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+milestone: "15.10"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112837"
diff --git a/config/metrics/counts_28d/20230224095530_bulk_import_entities_project_finished_without_failures.yml b/config/metrics/counts_28d/20230224095530_bulk_import_entities_project_finished_without_failures.yml
new file mode 100644
index 00000000000..163a7f0ccd6
--- /dev/null
+++ b/config/metrics/counts_28d/20230224095530_bulk_import_entities_project_finished_without_failures.yml
@@ -0,0 +1,27 @@
+---
+data_category: optional
+key_path: usage_activity_by_stage_monthly.manage.project_imports.gitlab_migration_finished_without_failures
+description: Count of project entities with finished status and without failures in GitLab Migration
+product_section: dev
+product_stage: manage
+product_group: import
+product_category: importers
+value_type: number
+status: active
+time_frame: 28d
+data_source: database
+instrumentation_class: CountBulkImportsEntitiesMetric
+options:
+ source_type: project_entity
+ status: 2
+ has_failures: false
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+milestone: "15.10"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112837"
diff --git a/config/metrics/counts_28d/20230306134018_github_import_project_cancelled_monthly.yml b/config/metrics/counts_28d/20230306134018_github_import_project_cancelled_monthly.yml
new file mode 100644
index 00000000000..f398fa3c16f
--- /dev/null
+++ b/config/metrics/counts_28d/20230306134018_github_import_project_cancelled_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.importer.github_import_project_cancelled_monthly
+description: The number of github projects that were cancelled monthly
+product_section: dev
+product_stage: manage
+product_group: import
+product_category: importers
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113724
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - github_import_project_cancelled
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20230306134609_github_import_project_partially_completed_monthly.yml b/config/metrics/counts_28d/20230306134609_github_import_project_partially_completed_monthly.yml
new file mode 100644
index 00000000000..10344cffe5f
--- /dev/null
+++ b/config/metrics/counts_28d/20230306134609_github_import_project_partially_completed_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.importer.github_import_project_partially_completed_monthly
+description: The number of github projects that were partially completed monthly
+product_section: dev
+product_stage: manage
+product_group: import
+product_category: importers
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113724
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - github_import_project_partially_completed
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml b/config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml
index 49d882f893b..d7c2bf1ad31 100644
--- a/config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml
+++ b/config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml
@@ -5,7 +5,7 @@ description: Internal Tracking to count number of unit tests parsed for planning
future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0)
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: code_testing
value_type: number
status: active
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 07985c3e56e..4c12bd72f94 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
@@ -7,7 +7,9 @@ product_group: code_review
product_category: code_review
product_section: 'TBD'
value_type: number
-status: active
+status: removed
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113422
+milestone_removed: 15.10
time_frame: 7d
data_source: redis_hll
instrumentation_class: AggregatedMetric
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 71c02fc5681..eb46f571691 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
@@ -57,6 +57,7 @@ options:
- p_ci_templates_security_dependency_scanning
- p_ci_templates_security_api_fuzzing
- p_ci_templates_security_dast
+ - p_ci_templates_security_api_discovery
- p_ci_templates_ios_fastlane
- p_ci_templates_composer
- p_ci_templates_c
diff --git a/config/metrics/counts_7d/20210409100451_users_expanding_testing_code_quality_report_weekly.yml b/config/metrics/counts_7d/20210409100451_users_expanding_testing_code_quality_report_weekly.yml
index a8686e59e13..f3e90cb077b 100644
--- a/config/metrics/counts_7d/20210409100451_users_expanding_testing_code_quality_report_weekly.yml
+++ b/config/metrics/counts_7d/20210409100451_users_expanding_testing_code_quality_report_weekly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.testing.users_expanding_testing_code_quality_report
description: Count of expanding the code quality widget
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: code_quality
value_type: number
status: active
diff --git a/config/metrics/counts_7d/20210409100628_users_expanding_testing_accessibility_report_weekly.yml b/config/metrics/counts_7d/20210409100628_users_expanding_testing_accessibility_report_weekly.yml
index bbad1715f98..096f2f0c7f6 100644
--- a/config/metrics/counts_7d/20210409100628_users_expanding_testing_accessibility_report_weekly.yml
+++ b/config/metrics/counts_7d/20210409100628_users_expanding_testing_accessibility_report_weekly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.testing.users_expanding_testing_accessibility_repor
description: Count of expanding the accessibility report widget
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: accessibility_testing
value_type: number
status: active
diff --git a/config/metrics/counts_7d/20210413205507_i_testing_summary_widget_total_weekly.yml b/config/metrics/counts_7d/20210413205507_i_testing_summary_widget_total_weekly.yml
index f9c34ab4fe9..015fd1e99b0 100644
--- a/config/metrics/counts_7d/20210413205507_i_testing_summary_widget_total_weekly.yml
+++ b/config/metrics/counts_7d/20210413205507_i_testing_summary_widget_total_weekly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.testing.i_testing_summary_widget_total_weekly
description: Unique users that expand the test summary merge request widget by week
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: testing
value_type: number
status: active
diff --git a/config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml b/config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml
index 814a50554c1..650f85f765b 100644
--- a/config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml
+++ b/config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml
@@ -3,7 +3,7 @@ key_path: redis_hll_counters.testing.i_testing_test_report_uploaded_weekly
description: "MAU of junit test reports uploaded by customers per pipeline"
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: testing
value_type: number
status: active
diff --git a/config/metrics/counts_7d/20221101190913_i_testing_coverage_report_uploaded_weekly.yml b/config/metrics/counts_7d/20221101190913_i_testing_coverage_report_uploaded_weekly.yml
index be6ba98c10c..86fefb257f6 100644
--- a/config/metrics/counts_7d/20221101190913_i_testing_coverage_report_uploaded_weekly.yml
+++ b/config/metrics/counts_7d/20221101190913_i_testing_coverage_report_uploaded_weekly.yml
@@ -3,7 +3,7 @@ key_path: redis_hll_counters.testing.i_testing_coverage_report_uploaded_weekly
description: "MAU of coverage test reports uploaded by customers per pipeline"
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: testing
value_type: number
status: active
diff --git a/config/metrics/counts_7d/20221213183300_i_code_review_create_mr_weekly.yml b/config/metrics/counts_7d/20221213183300_i_code_review_create_mr_weekly.yml
index 43405d5bd2c..0ab553a7b5c 100644
--- a/config/metrics/counts_7d/20221213183300_i_code_review_create_mr_weekly.yml
+++ b/config/metrics/counts_7d/20221213183300_i_code_review_create_mr_weekly.yml
@@ -11,7 +11,7 @@ milestone: "15.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106869
time_frame: 7d
data_source: redis_hll
-data_category: optional
+data_category: operational
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
options:
diff --git a/config/metrics/counts_7d/20230112174745_i_testing_active_user_weekly.yml b/config/metrics/counts_7d/20230112174745_i_testing_active_user_weekly.yml
index d1c553601e6..38e6e0469f4 100644
--- a/config/metrics/counts_7d/20230112174745_i_testing_active_user_weekly.yml
+++ b/config/metrics/counts_7d/20230112174745_i_testing_active_user_weekly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.testing.i_testing_active_user_weekly
description: Count of weekly active users for pipeline insights features
product_section: ops
product_stage: verify
-product_group: pipeline_insights
+product_group: pipeline_execution
product_category: testing
value_type: number
status: active
diff --git a/config/metrics/counts_7d/20230215180530_p_ci_templates_security_api_discovery_weekly.yml b/config/metrics/counts_7d/20230215180530_p_ci_templates_security_api_discovery_weekly.yml
new file mode 100644
index 00000000000..ca16ef38e82
--- /dev/null
+++ b/config/metrics/counts_7d/20230215180530_p_ci_templates_security_api_discovery_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_security_api_discovery_weekly
+description: Weekly counts for API Discovery CI template
+product_section: sec
+product_stage: secure
+product_group: dynamic_analysis
+product_category: dynamic_application_security_testing
+value_type: number
+status: active
+milestone: "15.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110493
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_security_api_discovery
diff --git a/config/metrics/counts_7d/20230306133608_github_import_project_cancelled_weekly.yml b/config/metrics/counts_7d/20230306133608_github_import_project_cancelled_weekly.yml
new file mode 100644
index 00000000000..2d76d88e2e7
--- /dev/null
+++ b/config/metrics/counts_7d/20230306133608_github_import_project_cancelled_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.importer.github_import_project_cancelled_weekly
+description: The number of github projects that were cancelled weekly
+product_section: dev
+product_stage: manage
+product_group: import
+product_category: importers
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113724
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - github_import_project_cancelled
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20230306134308_github_import_project_partially_completed_weekly.yml b/config/metrics/counts_7d/20230306134308_github_import_project_partially_completed_weekly.yml
new file mode 100644
index 00000000000..9bc42eafd23
--- /dev/null
+++ b/config/metrics/counts_7d/20230306134308_github_import_project_partially_completed_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.importer.github_import_project_partially_completed_weekly
+description: The number of github projects that were partially completed weekly
+product_section: dev
+product_stage: manage
+product_group: import
+product_category: importers
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113724
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - github_import_project_partially_completed
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180228_projects_jira_server_active.yml b/config/metrics/counts_all/20210216180228_projects_jira_server_active.yml
index cc000031e83..a22520cb97d 100644
--- a/config/metrics/counts_all/20210216180228_projects_jira_server_active.yml
+++ b/config/metrics/counts_all/20210216180228_projects_jira_server_active.yml
@@ -7,7 +7,7 @@ product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
-status: active
+status: removed
time_frame: all
data_source: database
distribution:
@@ -19,3 +19,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112571
+milestone_removed: "15.10"
diff --git a/config/metrics/counts_all/20210216180230_projects_jira_cloud_active.yml b/config/metrics/counts_all/20210216180230_projects_jira_cloud_active.yml
index d607f3d6aea..092036b3a5b 100644
--- a/config/metrics/counts_all/20210216180230_projects_jira_cloud_active.yml
+++ b/config/metrics/counts_all/20210216180230_projects_jira_cloud_active.yml
@@ -7,7 +7,7 @@ product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
-status: active
+status: removed
time_frame: all
data_source: database
distribution:
@@ -19,3 +19,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112571
+milestone_removed: "15.10"
diff --git a/config/metrics/counts_all/20210216180242_web_ide_commits.yml b/config/metrics/counts_all/20210216180242_web_ide_commits.yml
index f86b5bd5f84..44585ed6916 100644
--- a/config/metrics/counts_all/20210216180242_web_ide_commits.yml
+++ b/config/metrics/counts_all/20210216180242_web_ide_commits.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.web_ide_commits
description: Count of commits made from the Web IDE
product_section: dev
diff --git a/config/metrics/counts_all/20210216180752_keys.yml b/config/metrics/counts_all/20210216180752_keys.yml
index dad2a777d26..afa2559310d 100644
--- a/config/metrics/counts_all/20210216180752_keys.yml
+++ b/config/metrics/counts_all/20210216180752_keys.yml
@@ -5,7 +5,7 @@ description: Number of keys.
product_section: dev
product_stage: manage
product_group: authentication_and_authorization
-product_category: authentication_and_authorization
+product_category: system_access
value_type: number
status: active
time_frame: all
diff --git a/config/metrics/counts_all/20210216183400_omniauth_providers.yml b/config/metrics/counts_all/20210216183400_omniauth_providers.yml
index f4d6e2bc57b..aa314730665 100644
--- a/config/metrics/counts_all/20210216183400_omniauth_providers.yml
+++ b/config/metrics/counts_all/20210216183400_omniauth_providers.yml
@@ -5,7 +5,7 @@ description: List of unique OmniAuth providers
product_section: dev
product_stage: manage
product_group: authentication_and_authorization
-product_category: authentication_and_authorization
+product_category: system_access
value_type: object
status: active
time_frame: all
diff --git a/config/metrics/counts_all/20210910132001_user_auth_by_provider.yml b/config/metrics/counts_all/20210910132001_user_auth_by_provider.yml
index 98ac9ace52f..c183edf1836 100644
--- a/config/metrics/counts_all/20210910132001_user_auth_by_provider.yml
+++ b/config/metrics/counts_all/20210910132001_user_auth_by_provider.yml
@@ -5,7 +5,7 @@ description: Number of unique user logins using two factor authentication for av
product_section: dev
product_stage: manage
product_group: authentication_and_authorization
-product_category: authentication_and_authorization
+product_category: system_access
value_type: object
status: active
milestone: "14.3"
diff --git a/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml b/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml
new file mode 100644
index 00000000000..9a24543390a
--- /dev/null
+++ b/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.projects_inheriting_google_play_active
+description: Count of active projects inheriting integrations for Google Play
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230222192643_projects_google_play_active.yml b/config/metrics/counts_all/20230222192643_projects_google_play_active.yml
new file mode 100644
index 00000000000..712a9b9cac1
--- /dev/null
+++ b/config/metrics/counts_all/20230222192643_projects_google_play_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.projects_google_play_active
+description: Count of projects with active integrations for Google Play
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230222193011_instances_google_play_active.yml b/config/metrics/counts_all/20230222193011_instances_google_play_active.yml
new file mode 100644
index 00000000000..00f99ed13f4
--- /dev/null
+++ b/config/metrics/counts_all/20230222193011_instances_google_play_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.instances_google_play_active
+description: Count of instances with active integrations for Google Play
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230222193151_groups_inheriting_google_play_active.yml b/config/metrics/counts_all/20230222193151_groups_inheriting_google_play_active.yml
new file mode 100644
index 00000000000..1dad27560b6
--- /dev/null
+++ b/config/metrics/counts_all/20230222193151_groups_inheriting_google_play_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.groups_inheriting_google_play_active
+description: Count of active groups inheriting integrations for Google Play
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230222193255_groups_google_play_active.yml b/config/metrics/counts_all/20230222193255_groups_google_play_active.yml
new file mode 100644
index 00000000000..fe83398f9ec
--- /dev/null
+++ b/config/metrics/counts_all/20230222193255_groups_google_play_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.groups_google_play_active
+description: Count of active groups inheriting integrations for Google Play
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230303131933_groups_inheriting_squash_tm_active.yml b/config/metrics/counts_all/20230303131933_groups_inheriting_squash_tm_active.yml
new file mode 100644
index 00000000000..294c044affb
--- /dev/null
+++ b/config/metrics/counts_all/20230303131933_groups_inheriting_squash_tm_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.groups_inheriting_squash_tm_active
+description: Count of active groups inheriting integrations for Squash TM
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110909
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230303131936_groups_squash_tm_active.yml b/config/metrics/counts_all/20230303131936_groups_squash_tm_active.yml
new file mode 100644
index 00000000000..0ccadb78bf0
--- /dev/null
+++ b/config/metrics/counts_all/20230303131936_groups_squash_tm_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.groups_squash_tm_active
+description: Count of groups with active integrations for Squash TM
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110909
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230303132041_instances_squash_tm_active.yml b/config/metrics/counts_all/20230303132041_instances_squash_tm_active.yml
new file mode 100644
index 00000000000..9f35216ddaf
--- /dev/null
+++ b/config/metrics/counts_all/20230303132041_instances_squash_tm_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.instances_squash_tm_active
+description: Count of instance-level integrations for Squash TM
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110909
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230303132048_projects_inheriting_squash_tm_active.yml b/config/metrics/counts_all/20230303132048_projects_inheriting_squash_tm_active.yml
new file mode 100644
index 00000000000..25944bfe05a
--- /dev/null
+++ b/config/metrics/counts_all/20230303132048_projects_inheriting_squash_tm_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.projects_inheriting_squash_tm_active
+description: Count of active projects inheriting integrations for Squash TM
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110909
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230303132352_projects_squash_tm_active.yml b/config/metrics/counts_all/20230303132352_projects_squash_tm_active.yml
new file mode 100644
index 00000000000..fedc0a801ba
--- /dev/null
+++ b/config/metrics/counts_all/20230303132352_projects_squash_tm_active.yml
@@ -0,0 +1,22 @@
+---
+key_path: counts.projects_squash_tm_active
+description: Count of projects with active integrations for Squash TM
+product_section: dev
+product_stage: manage
+product_group: integrations
+product_category: integrations
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110909
+time_frame: all
+data_source: database
+data_category: optional
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230306191328_i_container_registry_delete_manifest.yml b/config/metrics/counts_all/20230306191328_i_container_registry_delete_manifest.yml
new file mode 100644
index 00000000000..1c1d126e458
--- /dev/null
+++ b/config/metrics/counts_all/20230306191328_i_container_registry_delete_manifest.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.container_registry_events_i_container_registry_delete_manifest
+name: manifest_delete_events
+description: A count of manifests that have been deleted
+product_section: ops
+product_stage: package
+product_group: package
+product_category: container registry
+value_type: number
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113440
+time_frame: all
+data_source: redis
+instrumentation_class: RedisMetric
+options:
+ prefix: container_registry_events
+ event: i_container_registry_delete_manifest
+data_category: optional
+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
new file mode 100644
index 00000000000..53f9438ba0f
--- /dev/null
+++ b/config/metrics/license/20230228110448_installation_creation_date.yml
@@ -0,0 +1,22 @@
+---
+key_path: installation_creation_date
+description: "The date and time the instance was installed"
+product_section: analytics
+product_stage: analytics
+product_group: product_intelligence
+value_type: string
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113090
+time_frame: none
+data_source: database
+data_category: operational
+instrumentation_class: InstallationCreationDateMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/license/20230314161014_gitlab_dedicated.yml b/config/metrics/license/20230314161014_gitlab_dedicated.yml
new file mode 100644
index 00000000000..0495277077f
--- /dev/null
+++ b/config/metrics/license/20230314161014_gitlab_dedicated.yml
@@ -0,0 +1,20 @@
+---
+key_path: gitlab_dedicated
+description: Is the instance a Gitlab Dedicated instance
+product_section: analytics
+product_stage: analytics
+product_group: product_intelligence
+product_category: collection
+value_type: boolean
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114717
+time_frame: none
+data_source: database
+data_category: optional
+instrumentation_class: GitlabDedicatedMetric
+performance_indicator_type: []
+distribution:
+- ee
+tier:
+- ultimate
diff --git a/config/metrics/objects_schemas/index_inconsistencies_metric.json b/config/metrics/objects_schemas/index_inconsistencies_metric.json
new file mode 100644
index 00000000000..635cfa64d95
--- /dev/null
+++ b/config/metrics/objects_schemas/index_inconsistencies_metric.json
@@ -0,0 +1,19 @@
+{
+ "type": "array",
+ "items": {
+ "type": [
+ {
+ "type": "object",
+ "properties": {
+ "object_name": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of index inconsistency"
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/config/metrics/settings/20210204124906_ldap_enabled.yml b/config/metrics/settings/20210204124906_ldap_enabled.yml
index 2c506cb40fc..d25cb1d2628 100644
--- a/config/metrics/settings/20210204124906_ldap_enabled.yml
+++ b/config/metrics/settings/20210204124906_ldap_enabled.yml
@@ -5,7 +5,7 @@ description: Whether LDAP is enabled
product_section: dev
product_stage: manage
product_group: authentication_and_authorization
-product_category: authentication_and_authorization
+product_category: system_access
value_type: boolean
status: active
time_frame: none
diff --git a/config/metrics/settings/20210204124910_omniauth_enabled.yml b/config/metrics/settings/20210204124910_omniauth_enabled.yml
index 83ea666a331..0939ce43903 100644
--- a/config/metrics/settings/20210204124910_omniauth_enabled.yml
+++ b/config/metrics/settings/20210204124910_omniauth_enabled.yml
@@ -5,7 +5,7 @@ description: Whether OmniAuth is enabled
product_section: dev
product_stage: manage
product_group: authentication_and_authorization
-product_category: authentication_and_authorization
+product_category: system_access
value_type: boolean
status: active
time_frame: none
diff --git a/config/metrics/settings/20210204124918_signup_enabled.yml b/config/metrics/settings/20210204124918_signup_enabled.yml
index df7f03a7d2e..9371a08613d 100644
--- a/config/metrics/settings/20210204124918_signup_enabled.yml
+++ b/config/metrics/settings/20210204124918_signup_enabled.yml
@@ -5,7 +5,7 @@ description: Whether public signup is enabled
product_section: dev
product_stage: manage
product_group: authentication_and_authorization
-product_category: authentication_and_authorization
+product_category: system_access
value_type: boolean
status: active
time_frame: none
diff --git a/config/metrics/settings/20230203164341_index_inconsistencies_metric.yml b/config/metrics/settings/20230203164341_index_inconsistencies_metric.yml
new file mode 100644
index 00000000000..5076eb9cdd8
--- /dev/null
+++ b/config/metrics/settings/20230203164341_index_inconsistencies_metric.yml
@@ -0,0 +1,25 @@
+---
+key_path: index_inconsistencies
+name: "index_inconsistencies"
+description: "List the index inconsistencies in the database"
+product_section: enablement
+product_stage: enablement
+product_group: database
+product_category: database
+value_type: object
+status: active
+milestone: "15.10"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111015
+time_frame: none
+data_source: system
+data_category: optional
+instrumentation_class: IndexInconsistenciesMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+value_json_schema: "config/metrics/objects_schemas/index_inconsistencies_metric.json"
diff --git a/config/routes.rb b/config/routes.rb
index 8530923aa1a..589d44c3de6 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -29,6 +29,7 @@ InitializerConnections.raise_if_new_database_connection do
token_info: 'oauth/token_info',
tokens: 'oauth/tokens'
end
+ put '/oauth/applications/:id/renew(.:format)' => 'oauth/applications#renew', as: :renew_oauth_application
# This prefixless path is required because Jira gets confused if we set it up with a path
# More information: https://gitlab.com/gitlab-org/gitlab/issues/6752
@@ -87,6 +88,7 @@ InitializerConnections.raise_if_new_database_connection do
# JSON Web Token
get 'jwt/auth' => 'jwt#auth'
+ post 'jwt/auth', to: proc { [404, {}, ['']] }
# Health check
get 'health_check(/:checks)' => 'health_check#index', as: :health_check
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 9181c1c94cf..85c7951e1ea 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -44,7 +44,9 @@ namespace :admin do
end
end
- resources :applications
+ resources :applications do
+ put 'renew', on: :member
+ end
resources :groups, only: [:index, :new, :create]
@@ -121,6 +123,10 @@ namespace :admin do
member do
put :transfer
post :repository_check
+ get :edit, action: :edit
+ get '/', action: :show
+ patch '/', action: :update
+ put '/', action: :update
end
resources :runner_projects, only: [:create, :destroy]
@@ -168,6 +174,7 @@ namespace :admin do
resources :runners, only: [:index, :new, :show, :edit, :update, :destroy] do
member do
+ get :register
post :resume
post :pause
end
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 582f8bf9471..22c63482afa 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -56,7 +56,9 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
end
end
- resources :applications
+ resources :applications do
+ put 'renew', on: :member
+ end
resource :packages_and_registries, only: [:show]
end
diff --git a/config/routes/import.rb b/config/routes/import.rb
index 2513cd04cfb..a1f441c4e51 100644
--- a/config/routes/import.rb
+++ b/config/routes/import.rb
@@ -23,6 +23,7 @@ namespace :import do
get :realtime_changes
post :cancel
post :cancel_all
+ get :counts
end
resource :gitea, only: [:create, :new], controller: :gitea do
diff --git a/config/routes/issues.rb b/config/routes/issues.rb
index 25e59022272..13fdde5841b 100644
--- a/config/routes/issues.rb
+++ b/config/routes/issues.rb
@@ -14,6 +14,10 @@ resources :issues, concerns: :awardable, constraints: { id: /\d+/ } do
post :create_merge_request
get :discussions, format: :json
get '/designs(/*vueroute)', to: 'issues#designs', as: :designs, format: false
+ get '/:incident_tab',
+ action: :show,
+ as: :incident_issue,
+ constraints: { incident_tab: /timeline|metrics|alerts/ }
end
collection do
@@ -23,9 +27,10 @@ resources :issues, concerns: :awardable, constraints: { id: /\d+/ } do
post :export_csv
scope :incident do
- get '/:id',
+ get '/:id(/:incident_tab)',
to: 'incidents#show',
- as: :incident
+ as: :incident,
+ constraints: { incident_tab: /timeline|metrics|alerts/ }
end
end
diff --git a/config/routes/profile.rb b/config/routes/profile.rb
index bee1a0f108e..2d0d3fb66f0 100644
--- a/config/routes/profile.rb
+++ b/config/routes/profile.rb
@@ -39,7 +39,7 @@ resource :profile, only: [:show, :update] do
end
resource :preferences, only: [:show, :update]
- resources :saved_replies, only: [:index], action: :index
+ resources :saved_replies, only: [:index, :show], action: :index
resources :keys, only: [:index, :show, :create, :destroy] do
member do
@@ -75,7 +75,6 @@ resource :profile, only: [:show, :update] do
resource :two_factor_auth, only: [:show, :create, :destroy] do
member do
- post :create_u2f
post :codes
patch :skip
post :create_webauthn
diff --git a/config/routes/project.rb b/config/routes/project.rb
index cf19111b2e2..ceb0671c034 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -473,10 +473,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resources :experiments, only: [:index, :show], controller: 'experiments'
resources :candidates, only: [:show], controller: 'candidates', param: :iid
end
-
- namespace :airflow do
- resources :dags, only: [:index, :show], controller: 'dags'
- end
end
# End of the /-/ scope.
diff --git a/config/routes/repository.rb b/config/routes/repository.rb
index 0202eb80b23..60d3d37bdc8 100644
--- a/config/routes/repository.rb
+++ b/config/routes/repository.rb
@@ -75,6 +75,7 @@ scope format: false do
get '/tree/*id', to: 'tree#show', as: :tree
get '/raw/*id', to: 'raw#show', as: :raw
+ get '/blame_page/*id', to: 'blame#page', as: :blame_page
get '/blame/*id', to: 'blame#show', as: :blame
get '/commits', to: 'commits#commits_root', as: :commits_root
diff --git a/config/settings.rb b/config/settings.rb
index ae95af802c4..a76889f34ae 100644
--- a/config/settings.rb
+++ b/config/settings.rb
@@ -172,6 +172,13 @@ class Settings < Settingslogic
cron_jobs['gitlab_service_ping_worker']['cron'] ||= cron_for_service_ping
end
+ # Route jobs to queue based on worker name.
+ def build_sidekiq_routing_rules(rules)
+ return rules unless rules.nil? || rules&.empty?
+
+ [[Gitlab::SidekiqConfig::WorkerMatcher::WILDCARD_MATCH, nil]]
+ end
+
private
def base_url(config)
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 17440acddc3..e1de1b5d7c9 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -177,6 +177,8 @@
- 1
- - elastic_namespace_rollout
- 1
+- - elastic_namespace_update
+ - 1
- - elastic_project_transfer
- 1
- - email_receiver
@@ -419,12 +421,18 @@
- 1
- - projects_finalize_project_statistics_refresh
- 1
+- - projects_forks_sync
+ - 1
- - projects_git_garbage_collect
- 1
+- - projects_import_export_create_relation_exports
+ - 1
- - projects_import_export_parallel_project_export
- 1
- - projects_import_export_relation_export
- 1
+- - projects_import_export_wait_relation_exports
+ - 1
- - projects_inactive_projects_deletion_notification
- 1
- - projects_post_creation
@@ -481,6 +489,10 @@
- 1
- - sbom_reports
- 1
+- - search_namespace_index_integrity
+ - 1
+- - search_project_index_integrity
+ - 1
- - security_auto_fix
- 1
- - security_orchestration_policy_rule_schedule_namespace
diff --git a/config/vue3migration/compiler.js b/config/vue3migration/compiler.js
new file mode 100644
index 00000000000..bb92e1e2356
--- /dev/null
+++ b/config/vue3migration/compiler.js
@@ -0,0 +1,50 @@
+const { parse, compile: compilerDomCompile } = require('@vue/compiler-dom');
+
+const getPropIndex = (node, prop) => node.props?.findIndex((p) => p.name === prop) ?? -1;
+
+function modifyKeysInsideTemplateTag(templateNode) {
+ let keyCandidate = null;
+ for (const node of templateNode.children) {
+ const keyBindingIndex = node.props
+ ? node.props.findIndex((prop) => prop.arg && prop.arg.content === 'key')
+ : -1;
+
+ if (keyBindingIndex !== -1 && getPropIndex(node, 'for') === -1) {
+ if (!keyCandidate) {
+ keyCandidate = node.props[keyBindingIndex];
+ }
+ node.props.splice(keyBindingIndex, 1);
+ }
+ }
+
+ if (keyCandidate) {
+ templateNode.props.push(keyCandidate);
+ }
+}
+
+module.exports = {
+ parse,
+ compile(template, options) {
+ const rootNode = parse(template, options);
+ const pendingNodes = [rootNode];
+ while (pendingNodes.length) {
+ const currentNode = pendingNodes.pop();
+ if (getPropIndex(currentNode, 'for') !== -1) {
+ if (currentNode.tag === 'template') {
+ // This one will be dropped all together with compiler when we drop Vue.js 2 support
+ modifyKeysInsideTemplateTag(currentNode);
+ }
+
+ // This one will be dropped when https://github.com/vuejs/core/issues/7725 will be fixed
+ const vOncePropIndex = getPropIndex(currentNode, 'once');
+ if (vOncePropIndex !== -1) {
+ currentNode.props.splice(vOncePropIndex, 1);
+ }
+ }
+
+ currentNode.children?.forEach((child) => pendingNodes.push(child));
+ }
+
+ return compilerDomCompile(rootNode, options);
+ },
+};
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 8ae803ca738..3308fa3d210 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -1,6 +1,19 @@
// eslint-disable-next-line import/order
const crypto = require('./helpers/patched_crypto');
+const { VUE_VERSION: EXPLICIT_VUE_VERSION } = process.env;
+if (![undefined, '2', '3'].includes(EXPLICIT_VUE_VERSION)) {
+ throw new Error(
+ `Invalid VUE_VERSION value: ${EXPLICIT_VUE_VERSION}. Only '2' and '3' are supported`,
+ );
+}
+const USE_VUE3 = EXPLICIT_VUE_VERSION === '3';
+
+if (USE_VUE3) {
+ console.log('[V] Using Vue.js 3');
+}
+const VUE_LOADER_MODULE = USE_VUE3 ? 'vue-loader-vue3' : 'vue-loader';
+
const fs = require('fs');
const path = require('path');
@@ -12,11 +25,13 @@ const BABEL_LOADER_VERSION = require('babel-loader/package.json').version;
const CompressionPlugin = require('compression-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const glob = require('glob');
-const VueLoaderPlugin = require('vue-loader/lib/plugin');
-const VUE_LOADER_VERSION = require('vue-loader/package.json').version;
+// eslint-disable-next-line import/no-dynamic-require
+const { VueLoaderPlugin } = require(VUE_LOADER_MODULE);
+// eslint-disable-next-line import/no-dynamic-require
+const VUE_LOADER_VERSION = require(`${VUE_LOADER_MODULE}/package.json`).version;
const VUE_VERSION = require('vue/package.json').version;
-const { ESBuildMinifyPlugin } = require('esbuild-loader');
+const { EsbuildPlugin } = require('esbuild-loader');
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
@@ -167,6 +182,7 @@ function generateEntries() {
sandboxed_mermaid: './lib/mermaid.js',
redirect_listbox: './entrypoints/behaviors/redirect_listbox.js',
sandboxed_swagger: './lib/swagger.js',
+ super_sidebar: './entrypoints/super_sidebar.js',
};
return Object.assign(manualEntries, incrementalCompiler.filterEntryPoints(autoEntries));
@@ -282,6 +298,47 @@ if (WEBPACK_USE_ESBUILD_LOADER) {
console.log('esbuild-loader is active');
}
+const vueLoaderOptions = {
+ ident: 'vue-loader-options',
+
+ cacheDirectory: path.join(CACHE_PATH, 'vue-loader'),
+ cacheIdentifier: [
+ process.env.NODE_ENV || 'development',
+ webpack.version,
+ VUE_VERSION,
+ VUE_LOADER_VERSION,
+ EXPLICIT_VUE_VERSION,
+ ].join('|'),
+};
+
+let shouldExcludeFromCompliling = (modulePath) =>
+ /node_modules|vendor[\\/]assets/.test(modulePath) && !/\.vue\.js/.test(modulePath);
+// We explicitly set VUE_VERSION
+// Use @gitlab-ui from source to allow us to dig differences
+// between Vue.js 2 and Vue.js 3 while using built gitlab-ui by default
+if (EXPLICIT_VUE_VERSION) {
+ Object.assign(alias, {
+ '@gitlab/ui/scss_to_js': path.join(ROOT_PATH, 'node_modules/@gitlab/ui/scss_to_js'),
+ '@gitlab/ui/dist': '@gitlab/ui/src',
+ '@gitlab/ui': '@gitlab/ui/src',
+ });
+
+ const originalShouldExcludeFromCompliling = shouldExcludeFromCompliling;
+
+ shouldExcludeFromCompliling = (modulePath) =>
+ originalShouldExcludeFromCompliling(modulePath) &&
+ !/node_modules[\\/]@gitlab[\\/]ui/.test(modulePath) &&
+ !/node_modules[\\/]bootstrap-vue[\\/]src[\\/]vue\.js/.test(modulePath);
+}
+
+if (USE_VUE3) {
+ Object.assign(alias, {
+ vue: '@vue/compat',
+ });
+
+ vueLoaderOptions.compiler = require.resolve('./vue3migration/compiler');
+}
+
module.exports = {
mode: IS_PRODUCTION ? 'production' : 'development',
@@ -319,17 +376,28 @@ module.exports = {
},
WEBPACK_USE_ESBUILD_LOADER && {
test: /\.(js|cjs)$/,
- exclude: (modulePath) =>
- /node_modules|vendor[\\/]assets/.test(modulePath) && !/\.vue\.js/.test(modulePath),
+ exclude: shouldExcludeFromCompliling,
loader: 'esbuild-loader',
options: esbuildConfiguration,
},
!WEBPACK_USE_ESBUILD_LOADER && {
test: /\.(js|cjs)$/,
- exclude: (modulePath) =>
- /node_modules|vendor[\\/]assets/.test(modulePath) && !/\.vue\.js/.test(modulePath),
- loader: 'babel-loader',
- options: defaultJsOptions,
+ exclude: shouldExcludeFromCompliling,
+ use: [
+ {
+ loader: 'thread-loader',
+ options: {
+ workerParallelJobs: 20,
+ poolRespawn: false,
+ poolParallelJobs: 200,
+ poolTimeout: DEV_SERVER_LIVERELOAD ? Infinity : 5000,
+ },
+ },
+ {
+ loader: 'babel-loader',
+ options: defaultJsOptions,
+ },
+ ],
},
WEBPACK_USE_ESBUILD_LOADER && {
test: /\.(js|cjs)$/,
@@ -354,16 +422,8 @@ module.exports = {
},
{
test: /\.vue$/,
- loader: 'vue-loader',
- options: {
- cacheDirectory: path.join(CACHE_PATH, 'vue-loader'),
- cacheIdentifier: [
- process.env.NODE_ENV || 'development',
- webpack.version,
- VUE_VERSION,
- VUE_LOADER_VERSION,
- ].join('|'),
- },
+ loader: VUE_LOADER_MODULE,
+ options: vueLoaderOptions,
},
{
test: /\.(graphql|gql)$/,
@@ -424,7 +484,7 @@ module.exports = {
{
test: /.css$/,
use: [
- 'vue-style-loader',
+ 'style-loader',
{
loader: 'css-loader',
options: {
@@ -452,7 +512,6 @@ module.exports = {
},
},
{
- test: /\.(yml|yaml)$/,
resourceQuery: /raw/,
loader: 'raw-loader',
},
@@ -527,9 +586,7 @@ module.exports = {
},
},
},
- ...(WEBPACK_USE_ESBUILD_LOADER
- ? { minimizer: [new ESBuildMinifyPlugin(esbuildConfiguration)] }
- : {}),
+ ...(WEBPACK_USE_ESBUILD_LOADER ? { minimizer: [new EsbuildPlugin(esbuildConfiguration)] } : {}),
},
plugins: [
diff --git a/danger/plugins/sidekiq_args.rb b/danger/plugins/sidekiq_args.rb
new file mode 100644
index 00000000000..2210aa66b07
--- /dev/null
+++ b/danger/plugins/sidekiq_args.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require_relative '../../tooling/danger/sidekiq_args'
+
+module Danger
+ class SidekiqArgs < ::Danger::Plugin
+ # Put the helper code somewhere it can be tested
+ include Tooling::Danger::SidekiqArgs
+ end
+end
diff --git a/danger/roulette/Dangerfile b/danger/roulette/Dangerfile
index ca5a671ef29..32899c4d74f 100644
--- a/danger/roulette/Dangerfile
+++ b/danger/roulette/Dangerfile
@@ -96,7 +96,7 @@ categories = Set.new(changes.keys - [:unknown])
categories << :database if helper.mr_labels.include?('database')
# Ensure to spin for UX reviewer when ~UX is applied (e.g. to review changes to the UI) except when it's from wider community contribution where we want to assign from the corresponding group
-categories << :ux if helper.mr_labels.include?('UX') && !helper.mr_labels.include?('Community contribution')
+categories << :ux if helper.mr_labels.include?('UX') && !helper.mr_labels.include?('Community contribution') # rubocop:disable Rails/NegateInclude
# Ensure to spin for Product Intelligence reviewer when ~"product intelligence::review pending" is applied
categories << :product_intelligence if helper.mr_labels.include?("product intelligence::review pending")
diff --git a/danger/sidekiq_args/Dangerfile b/danger/sidekiq_args/Dangerfile
new file mode 100644
index 00000000000..fdd582889f3
--- /dev/null
+++ b/danger/sidekiq_args/Dangerfile
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+sidekiq_args.changed_worker_files.each do |filename|
+ sidekiq_args.add_comment_for_matched_line(filename)
+end
diff --git a/data/deprecations/14-10-old-search-migration-removal.yml b/data/deprecations/14-10-old-search-migration-removal.yml
index 1991c0ef177..4700063e68f 100644
--- a/data/deprecations/14-10-old-search-migration-removal.yml
+++ b/data/deprecations/14-10-old-search-migration-removal.yml
@@ -7,4 +7,4 @@
stage: enablement
tiers: premium, ultimate
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/359133
- documentation_url: https://docs.gitlab.com/ee/development/elasticsearch.html#deleting-advanced-search-migrations-in-a-major-version-upgrade
+ documentation_url: https://docs.gitlab.com/ee/development/search/advanced_search_migration_styleguide.html#deleting-advanced-search-migrations-in-a-major-version-upgrade
diff --git a/data/deprecations/14-7-deprecate-merged_by-api-field.yml b/data/deprecations/14-7-deprecate-merged_by-api-field.yml
deleted file mode 100644
index b49b8bf5271..00000000000
--- a/data/deprecations/14-7-deprecate-merged_by-api-field.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-# This is a template for a feature deprecation
-# A deprecation typically occurs when a feature or capability is planned to be removed in a future release.
-# Deprecations should be announced at least two releases prior to removal. Any breaking changes should only be done in major releases.
-#
-# Below is an example of what a single entry should look like, it's required attributes,
-# and what types we expect those attribute values to be.
-#
-# For more information please refer to the handbook documentation here:
-# https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations
-#
-# Please delete this line and above before submitting your merge request.
-
-- title: "merged_by API field" # The name of the feature to be deprecated
- announcement_milestone: "14.7" # The milestone when this feature was first announced as deprecated.
- removal_milestone: "16.0" # The milestone when this feature is planned to be removed
- breaking_change: true # If this deprecation is a breaking change, set this value to true
- body: | # Do not modify this line, instead modify the lines below.
- The `merged_by` field in the [merge request API](https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-requests) has been deprecated in favor of the `merge_user` field which more correctly identifies who merged a merge request when performing actions (merge when pipeline succeeds, add to merge train) other than a simple merge. API users are encouraged to use the new `merge_user` field instead. The `merged_by` field will be removed in v5 of the GitLab REST API.
-# The following items are not published on the docs page, but may be used in the future.
- stage: create # (optional - may be required in the future) String value of the stage that the feature was created in. e.g., Growth
- 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]
- issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350534 # (optional) This is a link to the deprecation issue in GitLab
- 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/14-8-runner-api-active-field-replaced-with-paused-breaking-change.yml b/data/deprecations/14-8-runner-api-active-field-replaced-with-paused-breaking-change.yml
deleted file mode 100644
index 22cc199c704..00000000000
--- a/data/deprecations/14-8-runner-api-active-field-replaced-with-paused-breaking-change.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-- title: "REST and GraphQL API Runner usage of `active` replaced by `paused`"
- announcement_milestone: "14.8"
- removal_milestone: "16.0"
- breaking_change: true
- reporter: pedropombeiro
- body: |
- Occurrences of the `active` identifier in the GitLab Runner GraphQL API endpoints will be
- renamed to `paused` in GitLab 16.0.
-
- - For the GraphQL API, this change affects:
- - the `CiRunner` property
- - the `RunnerUpdateInput` input type for the `runnerUpdate` mutation
- - the `runners` and `Group.runners` queries
- - In v4 of the REST API, starting in GitLab 14.8, you can use the `paused` property in place of `active`
- - In v5 of the REST API, this change will affect:
- - endpoints taking or returning `active` property, such as:
- - `GET /runners`
- - `GET /runners/all`
- - `GET /runners/:id` / `PUT /runners/:id`
- - `PUT --form "active=false" /runners/:runner_id`
- - `GET /projects/:id/runners` / `POST /projects/:id/runners`
- - `GET /groups/:id/runners`
-
- The 16.0 release of GitLab Runner will start using the `paused` property when registering runners.
- stage: Verify
- tiers: [Core, Premium, Ultimate]
- issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351109
- documentation_url: https://docs.gitlab.com/ee/api/graphql/reference/#cirunner
- 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/14-8-runner-api-status-filter-does-accept-active-or-paused.yml b/data/deprecations/14-8-runner-api-status-filter-does-accept-active-or-paused.yml
deleted file mode 100644
index ce372a36f69..00000000000
--- a/data/deprecations/14-8-runner-api-status-filter-does-accept-active-or-paused.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-- title: "GraphQL API Runner will not accept `status` filter values of `active` or `paused`"
- announcement_milestone: "14.8" # The milestone when this feature was first announced as deprecated.
- removal_milestone: "16.0"
- breaking_change: true
- body: | # Do not modify this line, instead modify the lines below.
- The GitLab Runner GraphQL endpoints will stop accepting `paused` or `active` as a status value in GitLab 16.0.
-
- A runner's status will only relate to runner contact status, such as: `online`, `offline`.
- Status values `paused` or `active` will no longer be accepted and will be replaced by the `paused` query parameter.
-
- When checking for paused runners, API users are advised to specify `paused: true` as the query parameter.
- When checking for active runners, specify `paused: false`.
-
- The REST API endpoints will follow in the same direction in a future REST v5 API, however the new `paused`
- status value can be used in place of `active` since GitLab 14.8.
- stage: Verify
- tiers: [Core, Premium, Ultimate]
- issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351109
- documentation_url: https://docs.gitlab.com/ee/api/graphql/reference/#queryrunners
diff --git a/data/deprecations/15-1-deprecate-maintainer_note.yml b/data/deprecations/15-1-deprecate-maintainer_note.yml
deleted file mode 100644
index 175f85e997f..00000000000
--- a/data/deprecations/15-1-deprecate-maintainer_note.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-- title: "REST API Runner maintainer_note" # (required) The name of the feature to be deprecated
- announcement_milestone: "15.1" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "16.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: 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/363192 # (required) Link to the deprecation issue in GitLab
- body: | # (required) Do not modify this line, instead modify the lines below.
- The `maintainer_note` argument in the `POST /runners` REST endpoint was deprecated in GitLab 14.8 and replaced with the `maintenance_note` argument.
- The `maintainer_note` argument will be removed in GitLab 16.0.
-# The following items are not published on the docs page, but may be used in the future.
- 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
- 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/15-10-consul-legacy-metrics-disable.yml b/data/deprecations/15-10-consul-legacy-metrics-disable.yml
new file mode 100644
index 00000000000..7510f26585f
--- /dev/null
+++ b/data/deprecations/15-10-consul-legacy-metrics-disable.yml
@@ -0,0 +1,15 @@
+- title: "Deprecated Consul http metrics" # (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.10" # (required) The milestone when this feature was first announced as deprecated.
+ removal_milestone: "16.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: twk3 # (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/omnibus-gitlab/-/issues/7278 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ The Consul provided in the GitLab Omnibus package will no longer provide older deprecated Consul metrics starting in GitLab 16.0.
+
+ In GitLab 14.0, [Consul was updated to 1.9.6](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5344),
+ which deprecated some telemetry metrics from being at the `consul.http` path. In GitLab 16.0, the `consul.http` path will be removed.
+
+ If you have monitoring that consumes Consul metrics, update them to use `consul.api.http` instead of `consul.http`.
+ For more information, see [the deprecation notes for Consul 1.9.0](https://github.com/hashicorp/consul/releases/tag/v1.9.0).
diff --git a/data/deprecations/15-10-gitaly-legacy-config.yml b/data/deprecations/15-10-gitaly-legacy-config.yml
new file mode 100644
index 00000000000..77f045defb1
--- /dev/null
+++ b/data/deprecations/15-10-gitaly-legacy-config.yml
@@ -0,0 +1,35 @@
+#
+# REQUIRED FIELDS
+#
+- title: "Legacy Gitaly configuration method"
+ announcement_milestone: "15.10"
+ removal_milestone: "16.0"
+ breaking_change: true
+ reporter: mjwood
+ stage: Systems
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393574
+ body: |
+ Gitaly configuration within Omnibus GitLab has been updated such that all Gitaly related configuration keys are in a single
+ configuration structure that matches the standard Gitaly configuration. As such, the previous configuration structure is deprecated.
+
+ The single configuration structure is available from GitLab 15.10, though backwards compatibility is maintained. Once removed, Gitaly must be configured using the single
+ configuration structure. You should update the configuration of Gitaly at your earliest convenience.
+
+ The change improves consistency between Omnibus GitLab and source installs and enables us to provide better documentation and tooling for both.
+
+ You should update to the new configuration structure as soon as possible using
+ [the upgrade instructions](https://docs.gitlab.com/ee/update/#gitaly-omnibus-gitlab-configuration-structure-change).
+#
+# 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: https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html # (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/15-10-omniauth-dingtalk.yml b/data/deprecations/15-10-omniauth-dingtalk.yml
new file mode 100644
index 00000000000..a591b619146
--- /dev/null
+++ b/data/deprecations/15-10-omniauth-dingtalk.yml
@@ -0,0 +1,41 @@
+# Please refer to the deprecation guidelines to confirm your understanding of GitLab's definitions.
+# https://docs.gitlab.com/ee/development/deprecation_guidelines/#terminology
+#
+# Deprecations and other future breaking changes must be announced at least
+# three releases prior to removal.
+#
+# Breaking changes must happen in a major release.
+#
+# See the OPTIONAL END OF SUPPORT FIELDS section below if an End of Support period also applies.
+#
+# For more information please refer to the handbook documentation here:
+# https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-and-other-planned-breaking-change-announcements
+#
+# Please delete this line and above before submitting your merge request.
+#
+# REQUIRED FIELDS
+#
+- title: "DingTalk OmniAuth provider" # (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.10" # (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) Change to false if this is not a breaking change.
+ reporter: ifarkas # (required) GitLab username of the person reporting the change
+ stage: manage # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390855 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ The `omniauth-dingtalk` gem that provides GitLab with the DingTalk OmniAuth provider will be removed in our next
+ major release, GitLab 17.0. This gem sees very little use and is better suited for JiHu edition.
+#
+# 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/15-6-deprecate-merge_status-api-field.yml b/data/deprecations/15-6-deprecate-merge_status-api-field.yml
deleted file mode 100644
index 48b7824a13d..00000000000
--- a/data/deprecations/15-6-deprecate-merge_status-api-field.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-- title: "merge_status API field"
- announcement_milestone: "15.6"
- removal_milestone: "16.0"
- breaking_change: true
- body: |
- The `merge_status` field in the [merge request API](https://docs.gitlab.com/ee/api/merge_requests.html#merge-status) has been deprecated in favor of the `detailed_merge_status` field which more correctly identifies all of the potential statuses that a merge request can be in. API users are encouraged to use the new `detailed_merge_status` field instead. The `merge_status` field will be removed in v5 of the GitLab REST API.
- stage: create
- tiers:
- issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382032
- documentation_url: https://docs.gitlab.com/ee/api/merge_requests.html#merge-status
- image_url:
- video_url:
diff --git a/data/deprecations/15-6-deprecate-post-api-v4-runner.yml b/data/deprecations/15-6-deprecate-post-api-v4-runner.yml
index f71b8726de9..b841451b1d1 100644
--- a/data/deprecations/15-6-deprecate-post-api-v4-runner.yml
+++ b/data/deprecations/15-6-deprecate-post-api-v4-runner.yml
@@ -1,6 +1,7 @@
- title: "Registration tokens and server-side runner arguments in `POST /api/v4/runners` endpoint" # (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"
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
@@ -11,11 +12,12 @@
with a GitLab instance at the instance, group, or project level through the API. We plan to remove the support for
registration tokens and certain configuration arguments in this endpoint in GitLab 17.0.
- In GitLab 15.10, we plan to implement a new method to bind runners to a GitLab instance,
+ 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.
- end_of_support_milestone: "16.6" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_milestone: "17.0" # (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-6-deprecate-runner-reg-token-helm.yml b/data/deprecations/15-6-deprecate-runner-reg-token-helm.yml
index cbc50918c39..a01c995ae4f 100644
--- a/data/deprecations/15-6-deprecate-runner-reg-token-helm.yml
+++ b/data/deprecations/15-6-deprecate-runner-reg-token-helm.yml
@@ -1,6 +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"
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
@@ -8,10 +9,9 @@
body: | # (required) Do not modify this line, instead modify the lines below.
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.
- As part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/), in GitLab 15.8 we plan to introduce:
-
- - A new method to bind runners to a GitLab instance leveraging `runnerToken`.
- - A unique system ID saved to the `config.toml`, which will ensure traceability between jobs and runners.
+ 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.
- end_of_support_milestone: "16.6" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_milestone: "17.0" # (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 a908e126bc8..1311451abb8 100644
--- a/data/deprecations/15-6-deprecate-runner-register-command.yml
+++ b/data/deprecations/15-6-deprecate-runner-register-command.yml
@@ -1,16 +1,17 @@
- 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"
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/380872 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The support for registration tokens and certain configuration arguments in the command to [register](https://docs.gitlab.com/runner/register/) a runner, `gitlab-runner register` is deprecated.
- GitLab plans to introduce a new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/) in GitLab 15.10,
- which introduces a new method for registering runners and eliminates the legacy
- [runner registration token](https://docs.gitlab.com/ee/security/token_overview.html#runner-registration-tokens).
+ 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).
The new method will involve creating the runner in the GitLab UI and passing the
[runner authentication token](https://docs.gitlab.com/ee/security/token_overview.html#runner-authentication-tokens-also-called-runner-tokens)
to the `gitlab-runner register` command.
- end_of_support_milestone: "16.6" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_milestone: "17.0" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
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 7b66978f492..56d40620047 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,13 +1,17 @@
- 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"
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 k8s Vanilla Operator to install a runner on Kubernetes is deprecated. GitLab plans to introduce a new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/) in GitLab 15.8, which introduces a new method for registering runners and eliminates the legacy runner registration token.
- end_of_support_milestone: "16.6" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ The [`runner-registration-token`](https://docs.gitlab.com/runner/install/operator.html#install-the-kubernetes-operator) parameter that uses the OpenShift and k8s Vanilla Operator to install a runner on Kubernetes is deprecated.
+ 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).
+ end_of_support_milestone: "17.0" # (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/runner/install/operator.html#install-the-kubernetes-operator # (optional) This is a link to the current documentation page
image_url: # (optional) This is a link to a thumbnail image depicting the feature
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 25b2e046f01..b3031850ca3 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,6 +1,7 @@
- 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"
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
@@ -14,11 +15,12 @@
- `POST /projects/:id/runners/reset_registration_token`
- `POST /groups/:id/runners/reset_registration_token`
- In GitLab 15.8, we plan to implement a new method to bind runners to a GitLab instance,
+ 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.
- end_of_support_milestone: "16.6" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_milestone: "17.0" # (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-7-deprecate-gitlab-runner-exec-cmd.yml b/data/deprecations/15-7-deprecate-gitlab-runner-exec-cmd.yml
index cfc1362b0b6..0b52fa4d72d 100644
--- a/data/deprecations/15-7-deprecate-gitlab-runner-exec-cmd.yml
+++ b/data/deprecations/15-7-deprecate-gitlab-runner-exec-cmd.yml
@@ -3,16 +3,16 @@
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: DarrenEastman # (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/385235 # (required) Link to the deprecation issue in GitLab
+ 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/385235 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The [`gitlab-runner exec`](https://docs.gitlab.com/runner/commands/#gitlab-runner-exec) command is deprecated and will be fully removed from GitLab Runner in 16.0. The `gitlab-runner exec` feature was initially developed to provide the ability to validate a GitLab CI pipeline on a local system without needing to commit the updates to a GitLab instance. However, with the continued evolution of GitLab CI, replicating all GitLab CI features into `gitlab-runner exec` was no longer viable. Pipeline syntax and validation [simulation](https://docs.gitlab.com/ee/ci/pipeline_editor/#simulate-a-cicd-pipeline) are available in the GitLab pipeline editor.
end_of_support_milestone: "17.0" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
-# OTHER OPTIONAL FIELDS
-#
+ # 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/runner/commands/#gitlab-runner-exec # (optional) This is a link to the current documentation page
+ documentation_url: https://docs.gitlab.com/runner/commands/#gitlab-runner-exec # (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/15-7-deprecate-kas-metrics-port-in-gitlab-chart.yml b/data/deprecations/15-7-deprecate-kas-metrics-port-in-gitlab-chart.yml
index ce26849879a..921bea87b38 100644
--- a/data/deprecations/15-7-deprecate-kas-metrics-port-in-gitlab-chart.yml
+++ b/data/deprecations/15-7-deprecate-kas-metrics-port-in-gitlab-chart.yml
@@ -2,9 +2,9 @@
announcement_milestone: "15.7" # (required) The milestone when this feature was first announced as deprecated.
removal_milestone: "16.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: timofurrer # (required) GitLab username of the person reporting the deprecation
- stage: Configure # (required) String value of the stage that the feature was created in. e.g., Growth
- issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/383039 # (required) Link to the deprecation issue in GitLab
+ reporter: timofurrer # (required) GitLab username of the person reporting the deprecation
+ stage: Configure # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/383039 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The `gitlab.kas.metrics.port` has been deprecated in favor of the new `gitlab.kas.observability.port` configuration field for the [GitLab Helm Chart](https://gitlab.com/gitlab-org/charts/gitlab/-/merge_requests/2839).
This port is used for much more than just metrics, which warranted this change to avoid confusion in configuration.
@@ -13,7 +13,7 @@
# OTHER OPTIONAL FIELDS
#
- tiers: [Core, Premium, Ultimate] # (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/charts/charts/gitlab/kas/index.html # (optional) This is a link to the current documentation page
+ tiers: [Core, Premium, Ultimate] # (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/charts/charts/gitlab/kas/index.html # (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/15-7-deprecate-shimo-integration.yml b/data/deprecations/15-7-deprecate-shimo-integration.yml
index 95bb4ec141d..aa92bdf943a 100644
--- a/data/deprecations/15-7-deprecate-shimo-integration.yml
+++ b/data/deprecations/15-7-deprecate-shimo-integration.yml
@@ -2,7 +2,7 @@
announcement_milestone: "15.7" # (required) The milestone when this feature was first announced as deprecated.
removal_milestone: "16.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: arturoherrero # (required) GitLab username of the person reporting the deprecation
+ reporter: arturoherrero # (required) GitLab username of the person reporting the deprecation
stage: Manage # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/377824 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
diff --git a/data/deprecations/15-7-deprecate-single-merge-request-changes-api-endpoint.yml b/data/deprecations/15-7-deprecate-single-merge-request-changes-api-endpoint.yml
deleted file mode 100644
index 9e567322eca..00000000000
--- a/data/deprecations/15-7-deprecate-single-merge-request-changes-api-endpoint.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-- title: 'Single merge request changes API endpoint'
- announcement_milestone: '15.7'
- removal_milestone: '16.0'
- breaking_change: true
- body: |
- The endpoint to get [changes from a single merge request](https://docs.gitlab.com/ee/api/merge_requests.html#get-single-merge-request-changes) has been deprecated in favor the [list merge request diffs](https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-request-diffs) endpoint. API users are encouraged to switch to the new diffs endpoint instead. The `changes from a single merge request` endpoint will be removed in v5 of the GitLab REST API.
- stage: create
- tiers:
- issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/322117
- documentation_url: https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-request-diffs
- image_url:
- video_url:
diff --git a/data/deprecations/15-7-deprecate-zentao-integration.yml b/data/deprecations/15-7-deprecate-zentao-integration.yml
index 0925be8de60..332aaefdf04 100644
--- a/data/deprecations/15-7-deprecate-zentao-integration.yml
+++ b/data/deprecations/15-7-deprecate-zentao-integration.yml
@@ -2,7 +2,7 @@
announcement_milestone: "15.7" # (required) The milestone when this feature was first announced as deprecated.
removal_milestone: "16.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: arturoherrero # (required) GitLab username of the person reporting the deprecation
+ reporter: arturoherrero # (required) GitLab username of the person reporting the deprecation
stage: Manage # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/377825 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
diff --git a/data/deprecations/15-8-deprecate-merge-request-approvals-fields.yml b/data/deprecations/15-8-deprecate-merge-request-approvals-fields.yml
deleted file mode 100644
index 3e0e10b54db..00000000000
--- a/data/deprecations/15-8-deprecate-merge-request-approvals-fields.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-- title: 'Approvers and Approver Group fields in Merge Request Approval API'
- announcement_milestone: '15.8'
- announcement_date: '2023-01-22'
- removal_milestone: '16.0'
- removal_date: '2023-05-22'
- breaking_change: true
- body: |
- The endpoint to get the configuration of approvals for a project returns empty arrays for `approvers` and `approval_groups`. These fields were deprecated in favor of the endpoint to [get project-level rules](https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-project-level-rules) for a merge request. API users are encouraged to switch to this endpoint instead. These fields will be removed from the `get configuration` endpoint in v5 of the GitLab REST API.
- stage: create
- tiers:
- issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/353097
- documentation_url: https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-project-level-rules
- image_url:
- video_url:
diff --git a/data/deprecations/15-8-deprecate-slack-notifications-integration.yml b/data/deprecations/15-8-deprecate-slack-notifications-integration.yml
index 3cbcbc83925..8ac12d64a77 100644
--- a/data/deprecations/15-8-deprecate-slack-notifications-integration.yml
+++ b/data/deprecations/15-8-deprecate-slack-notifications-integration.yml
@@ -4,7 +4,7 @@
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: manage # (required) String value of the stage that the feature was created in. e.g., Growth
- issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372411 # (required) Link to the deprecation issue in GitLab
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372411 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
As we're consolidating all Slack capabilities into the
GitLab for Slack app, we're [deprecating the Slack notifications
diff --git a/data/deprecations/15-8-deprecate-system-hook-test-endpoint.yml b/data/deprecations/15-8-deprecate-system-hook-test-endpoint.yml
index afde85f03d9..f3b2b11e63c 100644
--- a/data/deprecations/15-8-deprecate-system-hook-test-endpoint.yml
+++ b/data/deprecations/15-8-deprecate-system-hook-test-endpoint.yml
@@ -2,7 +2,7 @@
announcement_milestone: "15.8" # (required) The milestone when this feature was first announced as deprecated.
removal_milestone: "16.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: arturoherrero # (required) GitLab username of the person reporting the deprecation
+ reporter: arturoherrero # (required) GitLab username of the person reporting the deprecation
stage: Manage # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381572 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
diff --git a/data/deprecations/15-8-deprecate-updated-at-error.yml b/data/deprecations/15-8-deprecate-updated-at-error.yml
index 9b4c5c3e007..6985803c12e 100644
--- a/data/deprecations/15-8-deprecate-updated-at-error.yml
+++ b/data/deprecations/15-8-deprecate-updated-at-error.yml
@@ -21,7 +21,7 @@
announcement_milestone: "15.8" # (required) The milestone when this feature was first announced as deprecated.
announcement_date: "2023-01-22" # (required) The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed
- removal_date: 2023-05-22 # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ removal_date: 2023-05-22 # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
breaking_change: true # (required) Change to false if this is not a breaking change.
reporter: cbalane # (required) GitLab username of the person reporting the change
stage: Release # (required) String value of the stage that the feature was created in. e.g., Growth
diff --git a/data/deprecations/15-8-jira-connect-app-cookie-auth.yml b/data/deprecations/15-8-jira-connect-app-cookie-auth.yml
index 324bcb83ae9..a9fe6e727ea 100644
--- a/data/deprecations/15-8-jira-connect-app-cookie-auth.yml
+++ b/data/deprecations/15-8-jira-connect-app-cookie-auth.yml
@@ -9,4 +9,4 @@
Cookie authentication in the GitLab for Jira Cloud app is now deprecated in favor of OAuth authentication.
You must [set up OAuth authentication](https://docs.gitlab.com/ee/integration/jira/connect-app.html#set-up-oauth-authentication)
to continue to use the GitLab for Jira Cloud app. Without OAuth, you will not be able to manage linked namespaces.
- tiers: [Core, Premium, Ultimate] # (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]
+ tiers: [Core, Premium, Ultimate] # (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]
diff --git a/data/deprecations/15-8-live-preview.yml b/data/deprecations/15-8-live-preview.yml
index 05ec5111e4a..a8fbb0e038e 100644
--- a/data/deprecations/15-8-live-preview.yml
+++ b/data/deprecations/15-8-live-preview.yml
@@ -2,7 +2,7 @@
announcement_milestone: "15.8" # (required) The milestone when this feature was first announced as deprecated.
announcement_date: "2023-01-22" # (required) The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
removal_milestone: "15.9" # (required) The milestone when this feature is planned to be removed
- removal_date: "2023-02-22" # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ removal_date: "2023-02-22" # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
breaking_change: true # (required) Change to false if this is not a breaking change.
reporter: ericschurter # (required) GitLab username of the person reporting the change
stage: create # (required) String value of the stage that the feature was created in. e.g., Growth
diff --git a/data/deprecations/15-8-projects-api-ops-access-level.yml b/data/deprecations/15-8-projects-api-ops-access-level.yml
index 4e0fbbe63ab..06fb1b76232 100644
--- a/data/deprecations/15-8-projects-api-ops-access-level.yml
+++ b/data/deprecations/15-8-projects-api-ops-access-level.yml
@@ -21,7 +21,7 @@
announcement_milestone: "15.8" # (required) The milestone when this feature was first announced as deprecated.
announcement_date: "2023-01-22" # (required) The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed
- removal_date: 2023-05-22 # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ removal_date: 2023-05-22 # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
breaking_change: true # (required) Change to false if this is not a breaking change.
reporter: cbalane # (required) GitLab username of the person reporting the change
stage: Release # (required) String value of the stage that the feature was created in. e.g., Growth
diff --git a/data/deprecations/15-8-visual-review-tool.yml b/data/deprecations/15-8-visual-review-tool.yml
index 4833bc314d8..ced41ff3cbd 100644
--- a/data/deprecations/15-8-visual-review-tool.yml
+++ b/data/deprecations/15-8-visual-review-tool.yml
@@ -18,6 +18,6 @@
# OTHER OPTIONAL FIELDS
#
tiers: Premium # (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/review_apps/#visual-reviews # (optional) This is a link to the current documentation page
+ documentation_url: https://docs.gitlab.com/ee/ci/review_apps/#visual-reviews # (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/15-9-accessibility-testing-deprecation.yml b/data/deprecations/15-9-accessibility-testing-deprecation.yml
index 17863cf78af..74fb61ed2fc 100644
--- a/data/deprecations/15-9-accessibility-testing-deprecation.yml
+++ b/data/deprecations/15-9-accessibility-testing-deprecation.yml
@@ -21,6 +21,6 @@
# 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/testing/accessibility_testing.html # (optional) This is a link to the current documentation page
+ documentation_url: https://docs.gitlab.com/ee/ci/testing/accessibility_testing.html # (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/15-9-ci-builds-column-validations.yml b/data/deprecations/15-9-ci-builds-column-validations.yml
new file mode 100644
index 00000000000..b94200dce8d
--- /dev/null
+++ b/data/deprecations/15-9-ci-builds-column-validations.yml
@@ -0,0 +1,29 @@
+#
+# REQUIRED FIELDS
+#
+- title: "Enforced validation of CI/CD parameter character lengths" # (required) Clearly explain the change. For example, "The `confidential` field for a `Note` is removed" or "CI/CD job names are limited to 250 characters."
+ announcement_milestone: "15.9" # (required) The milestone when this feature was deprecated.
+ announcement_date: "2023-02-22" # (required) The date of the milestone release when this feature was deprecated. This should almost always be the 22nd of a month (YYYY-MM-DD), unless you did an out of band blog post.
+ removal_milestone: "16.0" # (required) The milestone when this feature is being removed.
+ removal_date: "2023-05-22" # (required) This should almost always be the 22nd of a month (YYYY-MM-DD), the date of the milestone release when this feature will be removed.
+ breaking_change: true # (required) Change to false if this is not a breaking change.
+ reporter: jheimbuck_gl # (required) GitLab username of the person reporting the removal
+ 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/372770 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ While CI/CD [job names](https://docs.gitlab.com/ee/ci/jobs/index.html#job-name-limitations) have a strict 255 character limit, other CI/CD parameters do not yet have validations ensuring they also stay under the limit.
+
+ In GitLab 16.0, validation will be added to strictly limit the following to 255 characters as well:
+
+ - The `stage` keyword.
+ - The `ref`, which is the Git branch or tag name for the pipeline.
+ - The `description` and `target_url` parameter, used by external CI/CD integrations.
+
+ Users on self-managed instances should update their pipelines to ensure they do not use parameters that exceed 255 characters. Users on GitLab.com do not need to make any changes, as these are already limited in that database.
+#
+# 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/yaml/#stages" # (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/15-9-deprecate-ci-pre-clone-script.yml b/data/deprecations/15-9-deprecate-ci-pre-clone-script.yml
new file mode 100644
index 00000000000..bb1dcc9412a
--- /dev/null
+++ b/data/deprecations/15-9-deprecate-ci-pre-clone-script.yml
@@ -0,0 +1,23 @@
+- title: "Deprecation and planned removal for `CI_PRE_CLONE_SCRIPT` variable on GitLab SaaS" # (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: "16.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: DarrenEastman # (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/391896 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ The [`CI_PRE_CLONE_SCRIPT` variable](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html#pre-clone-script) supported by GitLab SaaS Runners is deprecated as of GitLab 15.9 and will be removed in 16.0. The `CI_PRE_CLONE_SCRIPT` variable enables you to run commands in your CI/CD job prior to the runner executing Git init and get fetch. For more information about how this feature works, see [Pre-clone script](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html#pre-clone-script). As an alternative, you can use the [`pre_get_sources_script`](https://docs.gitlab.com/ee/ci/yaml/#hookspre_get_sources_script).
+ #
+ # 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: 16.0 # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ #
+ # OTHER OPTIONAL FIELDS
+ #
+ tiers: Free, Premium, Ultimate # (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/runners/saas/linux_saas_runner.html#pre-clone-script # (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/15-9-deprecate-option-to-remove-project-immediately.yml b/data/deprecations/15-9-deprecate-option-to-remove-project-immediately.yml
index 687270fbb71..3c5cc4901ab 100644
--- a/data/deprecations/15-9-deprecate-option-to-remove-project-immediately.yml
+++ b/data/deprecations/15-9-deprecate-option-to-remove-project-immediately.yml
@@ -6,8 +6,8 @@
stage: manage # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389557 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
- The project deletion protection setting in the Admin Area had an option to delete projects immediately. Starting with 16.0, this option will no longer be available, and delayed project deletion will become the default behavior.
+ The group and project deletion protection setting in the Admin Area had an option to delete groups and projects immediately. Starting with 16.0, this option will no longer be available, and delayed group and project deletion will become the default behavior.
- The option will no longer appear as a group setting. Self-managed users will still have the option to define the deletion delay period, and SaaS users have a non-adjustable default retention period of 7 days. Users can still delete the project immediately from the project settings.
+ The option will no longer appear as a group setting. Self-managed users will still have the option to define the deletion delay period, and SaaS users have a non-adjustable default retention period of 7 days. Users can still immediately delete the project from the project settings, and the group from the group settings.
- The option to delete projects immediately by default was deprecated to prevent users from accidentally taking this action and permanently losing projects.
+ The option to delete groups and projects immediately by default was deprecated to prevent users from accidentally taking this action and permanently losing groups and projects.
diff --git a/data/deprecations/15-9-env-search-char-limit.yml b/data/deprecations/15-9-env-search-char-limit.yml
new file mode 100644
index 00000000000..5dbba6ec5e1
--- /dev/null
+++ b/data/deprecations/15-9-env-search-char-limit.yml
@@ -0,0 +1,9 @@
+- title: "Environment search query requires at least three characters" # (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.10" # (required) The milestone when this feature was first announced as deprecated.
+ removal_milestone: "16.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: cbalane # (required) GitLab username of the person reporting the change
+ stage: release # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382532 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ From GitLab 16.0, when you search for environments with the API, you must use at least three characters. This change helps us ensure the scalability of the search operation.
diff --git a/data/deprecations/15-9-insecure-ci-job-token.yml b/data/deprecations/15-9-insecure-ci-job-token.yml
index eb40224335c..a5ccffe897b 100644
--- a/data/deprecations/15-9-insecure-ci-job-token.yml
+++ b/data/deprecations/15-9-insecure-ci-job-token.yml
@@ -14,18 +14,18 @@
In 15.9 we extended this functionality with a better solution, an "inbound" scope limit. You can prevent the job tokens from _other_ projects from being used to access your project. With this feature, you can optionally list specific projects that you want to allow to access your project with _their_ job token.
In 16.0, this inbound scope limit will be the only option available for all projects, and the outbound limit setting will be removed. To prepare for this change, you can enable the ["inbound" CI/CD job token limit](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#configure-the-job-token-scope-limit) feature now, and list any projects that need to access your 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.
-#
+ #
+ # 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
-#
+ #
+ # 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
+ 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/deprecations/15-9-legacy-praefect-configuration.yml b/data/deprecations/15-9-legacy-praefect-configuration.yml
index 666a6d4f56a..247fc05f2d5 100644
--- a/data/deprecations/15-9-legacy-praefect-configuration.yml
+++ b/data/deprecations/15-9-legacy-praefect-configuration.yml
@@ -13,8 +13,8 @@
Praefect configuration so the previous configuration method is deprecated.
The single configuration structure available from GitLab 15.9, though backwards compatibility is maintained. Once removed, Praefect must be configured using the single
- configuration structure. You should update the configuration of Praefect at your earliest convenience. See
- [GitLab 15.9 upgrade information](https://docs.gitlab.com/ee/update/#1590).
+ configuration structure. You should update your Praefect configuration as soon as possible using
+ [the upgrade instructions](https://docs.gitlab.com/ee/update/#praefect-omnibus-gitlab-configuration-structure-change).
This change brings Praefect configuration in Omnibus GitLab in line with the configuration structure of Praefect. Previously, the hierarchies and configuration keys
didn't match. The change improves consistency between Omnibus GitLab and source installs and enables us to provide better documentation and tooling for both.
@@ -29,6 +29,6 @@
# 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/administration/gitaly/praefect.html # (optional) This is a link to the current documentation page
+ documentation_url: https://docs.gitlab.com/ee/administration/gitaly/praefect.html # (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/15-9-managed-licenses-api.yml b/data/deprecations/15-9-managed-licenses-api.yml
new file mode 100644
index 00000000000..cbba35c465c
--- /dev/null
+++ b/data/deprecations/15-9-managed-licenses-api.yml
@@ -0,0 +1,9 @@
+- title: "Managed Licenses API"
+ announcement_milestone: "15.9"
+ removal_milestone: "16.0"
+ breaking_change: true
+ reporter: sam.white
+ stage: govern
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390417
+ body: |
+ The [Managed Licenses API](https://docs.gitlab.com/ee/api/managed_licenses.html) is now deprecated and is scheduled for removal in GitLab 16.0.
diff --git a/data/deprecations/15-9-rails-error-tracking.yml b/data/deprecations/15-9-rails-error-tracking.yml
index 42ec004afa9..4d9fc371213 100644
--- a/data/deprecations/15-9-rails-error-tracking.yml
+++ b/data/deprecations/15-9-rails-error-tracking.yml
@@ -1,12 +1,12 @@
- title: "Error Tracking UI in GitLab Rails is deprecated"
announcement_milestone: "15.9"
- removal_milestone: "16.0"
+ removal_milestone: "16.6"
breaking_change: true
reporter: kbychu
stage: monitor
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389991
body: |
- The [Error Tracking UI](https://docs.gitlab.com/ee/operations/error_tracking.html) is deprecated in 15.9 and will be removed in 16.0. In future versions, you should use the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui/), which will gradually be made available on GitLab.com over the next few releases.
+ The [Error Tracking UI](https://docs.gitlab.com/ee/operations/error_tracking.html) is deprecated in 15.9 and will be removed in 16.6 (milestone might change) once GitLab Observability UI is made available. In future versions, you should use the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui/), which will gradually be made available on GitLab.com over the next few releases.
During the transition to the GitLab Observability UI, we will migrate the [GitLab Observability Backend](https://gitlab.com/gitlab-org/opstrace/opstrace) from a per-cluster deployment model to a per-tenant deployment model. Because [Integrated Error Tracking](https://docs.gitlab.com/ee/operations/error_tracking.html#integrated-error-tracking) is in Open Beta, we will not migrate any existing user data. For more details about the migration, see the direction pages for:
diff --git a/data/deprecations/15-9-remove-offset-pagination-jobs-api.yml b/data/deprecations/15-9-remove-offset-pagination-jobs-api.yml
index 8c3406a34e3..2e748f56695 100644
--- a/data/deprecations/15-9-remove-offset-pagination-jobs-api.yml
+++ b/data/deprecations/15-9-remove-offset-pagination-jobs-api.yml
@@ -18,6 +18,6 @@
# 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/api/jobs.html#list-project-jobs" # (optional) This is a link to the current documentation page
+ documentation_url: "https://docs.gitlab.com/ee/api/jobs.html#list-project-jobs" # (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/15-9-secure-analyzers-bump.yml b/data/deprecations/15-9-secure-analyzers-bump.yml
index 339b0ecd78a..b144986da4a 100644
--- a/data/deprecations/15-9-secure-analyzers-bump.yml
+++ b/data/deprecations/15-9-secure-analyzers-bump.yml
@@ -45,11 +45,11 @@
# 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_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
#
# OTHER OPTIONAL FIELDS
#
- tiers: [Free, Silver, Gold, Core, Premium, Ultimate] # (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
+ tiers: [Free, Silver, Gold, Core, Premium, Ultimate] # (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/15-9-trigger-job-status.yml b/data/deprecations/15-9-trigger-job-status.yml
index 66681de7f56..fb9d93bfb81 100644
--- a/data/deprecations/15-9-trigger-job-status.yml
+++ b/data/deprecations/15-9-trigger-job-status.yml
@@ -19,13 +19,13 @@
#
- title: "Trigger jobs can mirror downstream pipeline status exactly" # (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: "16.0" # (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
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/285493 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
- In some cases, like when a downstream pipeline had the `passed with warnings` status, trigger jobs that were using [`strategy: depend`](https://docs.gitlab.com/ee/ci/yaml/index.html#strategydepend) did not mirror the status of the downstream pipeline exactly. In GitLab 16.0 trigger jobs will show the exact same status as the the downstream pipeline. If your pipeline relied on this behavior, you should update your pipeline to handle the more accurate status.
+ In some cases, like when a downstream pipeline had the `passed with warnings` status, trigger jobs that were using [`strategy: depend`](https://docs.gitlab.com/ee/ci/yaml/index.html#strategydepend) did not mirror the status of the downstream pipeline exactly. In GitLab 17.0 trigger jobs will show the exact same status as the the downstream pipeline. If your pipeline relied on this behavior, you should update your pipeline to handle the more accurate status.
#
# OPTIONAL END OF SUPPORT FIELDS
#
diff --git a/data/deprecations/templates/_deprecation_template.md.erb b/data/deprecations/templates/_deprecation_template.md.erb
index 89e14c20050..ecba9a099f7 100644
--- a/data/deprecations/templates/_deprecation_template.md.erb
+++ b/data/deprecations/templates/_deprecation_template.md.erb
@@ -18,14 +18,14 @@ For deprecation authors (usually Product Managers and Engineering Managers):
- To add a deprecation, use the example.yml file in `/data/deprecations/templates` as a template.
- For more information about authoring deprecations, check the the deprecation item guidance:
- https://about.gitlab.com/handbook/marketing/blog/release-posts/#creating-a-deprecation-entry
+ https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-deprecations-and-removals-docs
For deprecation reviewers (Technical Writers only):
- To update the deprecation doc, run: `bin/rake gitlab:docs:compile_deprecations`
- To verify the deprecations doc is up to date, run: `bin/rake gitlab:docs:check_deprecations`
- For more information about updating the deprecation doc, see the deprecation doc update guidance:
- https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-deprecations-doc
+ https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-deprecations-and-removals-docs
-->
{::options parse_block_html="true" /}
@@ -37,13 +37,8 @@ Some features cause breaking changes when they are removed.
**{rss}** **To be notified of upcoming breaking changes**,
add this URL to your RSS feed reader: `https://about.gitlab.com/breaking-changes.xml`
-DISCLAIMER:
-This page contains information related to upcoming products, features, and functionality.
-It is important to note that the information presented is for informational purposes only.
-Please do not rely on this information for purchasing or planning purposes.
-As with all projects, the items mentioned on this page are subject to change or delay.
-The development, release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+You can also view [REST API](https://docs.gitlab.com/ee/api/rest/deprecations.html)
+and [GraphQL](https://docs.gitlab.com/ee/api/graphql/removed_items.html) deprecations/removals.
<div class="js-deprecation-filters"></div>
<% if milestones.any? -%>
<%- milestones.each do |milestone| %>
@@ -77,3 +72,11 @@ Review the details carefully before upgrading.
Deprecated features scheduled for removal will be listed here, sorted by GitLab milestone.
<% end -%>
+
+DISCLAIMER:
+This page contains information related to upcoming products, features, and functionality.
+It is important to note that the information presented is for informational purposes only.
+Please do not rely on this information for purchasing or planning purposes.
+As with all projects, the items mentioned on this page are subject to change or delay.
+The development, release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
diff --git a/data/removals/15_10/15_10-non-public-artifacts.yml b/data/removals/15_10/15_10-non-public-artifacts.yml
new file mode 100644
index 00000000000..bea672d2f22
--- /dev/null
+++ b/data/removals/15_10/15_10-non-public-artifacts.yml
@@ -0,0 +1,25 @@
+#
+# REQUIRED FIELDS
+#
+- title: "`artifacts:public` CI/CD keyword refactored" # (required) Clearly explain the change. For example, "The `confidential` field for a `Note` is removed" or "CI/CD job names are limited to 250 characters."
+ announcement_milestone: "15.10" # (required) The milestone when this feature was deprecated.
+ announcement_date: "2023-03-22" # (required) The date of the milestone release when this feature was deprecated. This should almost always be the 22nd of a month (YYYY-MM-DD), unless you did an out of band blog post.
+ removal_milestone: "15.8" # (required) The milestone when this feature is being removed.
+ removal_date: "2023-01-22" # (required) This should almost always be the 22nd of a month (YYYY-MM-DD), the date of the milestone release when this feature will be removed.
+ breaking_change: true # (required) Change to false if this is not a breaking change.
+ reporter: jocelynjane # (required) GitLab username of the person reporting the removal
+ 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/322454 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ The [`artifacts:public` CI/CD keyword](https://docs.gitlab.com/ee/ci/yaml/#artifactspublic) was discovered to be not working properly since GitLab 15.8 and needed to be refactored. This feature is disabled on GitLab.com, and disabled by default on self-managed instances. If an administrator for an instance running GitLab 15.8 or 15.9 enabled this feature via the `non_public_artifacts` feature flag, it is likely that artifacts created with the `public:false` setting are being treated as `public:true`.
+
+ If you have projects that use this setting, you should delete artifacts that must not be public, or [change the visibility](https://docs.gitlab.com/ee/user/public_access.html#change-project-visibility) of affected projects to private, before updating to GitLab 15.8 or later.
+
+ In GitLab 15.10, this feature's code was refactored. On instances with this feature enabled, new artifacts created with `public:false` are now working as expected, though still disabled by default. Avoid testing this feature with production data until it is enabled by default and made generally available.
+#
+# OPTIONAL FIELDS
+#
+ tiers: Free # (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/yaml/#artifactspublic # (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/removals/15_9/15-9-live-preview.yml b/data/removals/15_9/15-9-live-preview.yml
new file mode 100644
index 00000000000..139d7829d72
--- /dev/null
+++ b/data/removals/15_9/15-9-live-preview.yml
@@ -0,0 +1,11 @@
+- title: "Live Preview no longer available in the Web IDE" # (required) Clearly explain the change. For example, "The `confidential` field for a `Note` is removed" or "CI/CD job names are limited to 250 characters."
+ announcement_milestone: "15.8" # (required) The milestone when this feature was deprecated.
+ announcement_date: "2023-01-22" # (required) The date of the milestone release when this feature was deprecated. This should almost always be the 22nd of a month (YYYY-MM-DD), unless you did an out of band blog post.
+ removal_milestone: "15.9" # (required) The milestone when this feature is being removed.
+ removal_date: "2023-02-22" # (required) This should almost always be the 22nd of a month (YYYY-MM-DD), the date of the milestone release when this feature will be removed.
+ breaking_change: true # (required) Change to false if this is not a breaking change.
+ reporter: ericschurter # (required) GitLab username of the person reporting the removal
+ stage: create # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/383889 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ The Live Preview feature of the Web IDE was intended to provide a client-side preview of static web applications. However, complex configuration steps and a narrow set of supported project types have limited its utility. With the introduction of the Web IDE Beta in GitLab 15.7, you can now connect to a full server-side runtime environment. With upcoming support for installing extensions in the Web IDE, we’ll also support more advanced workflows than those available with Live Preview. As of GitLab 15.9, Live Preview is no longer available in the Web IDE.
diff --git a/data/whats_new/20230222001_15_09.yml b/data/whats_new/20230222001_15_09.yml
new file mode 100644
index 00000000000..217212297bb
--- /dev/null
+++ b/data/whats_new/20230222001_15_09.yml
@@ -0,0 +1,75 @@
+- name: Users with the Guest role can view private repositories
+ description: | # Do not modify this line, instead modify the lines below.
+ Users with the Guest role and an Ultimate license can now view private repository content if their administrator gives them permission. Administrators must create a new role through the API, and assign that role to users who the administrator wants to have view repository permissions. Previously, users with the Guest role could not view code in private projects, limiting their utility.
+ stage: manage
+ self-managed: true
+ gitlab-com: true
+ available_in: [Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/user/permissions.html#custom-roles
+ image_url: https://img.youtube.com/vi/46cp_-Rtxps/hqdefault.jpg
+ published_at: 2023-02-02 # YYYY-MM-DD
+ release: 15.9
+- name: Manage license approval policies
+ description: | # Do not modify this line, instead modify the lines below.
+ GitLab now supports flexible license approval policies as the replacement for the [deprecated License-Check feature](https://docs.gitlab.com/ee/update/deprecations.html#license-check-and-the-policies-tab-on-the-license-compliance-page). License approval policies improve the experience over the License-check feature in several ways:
+
+ - Users can choose who is allowed to edit license approval policies.
+ - Multiple policy rules can be created and chained together.
+ - A two-step approval process can be enforced for any desired changes to license approval policies.
+ - A single set of license policies can be applied to multiple development projects, or can be applied at the group or subgroup level, to allow for ease in maintaining a single, centralized ruleset.
+ - Policies can be used to require approval for any license that is not specifically allowed.
+
+ License approval policies can be used alongside the existing License-Check feature, as the two policies are additive and don't conflict. To get started, verify that the `license_scanning_policies` feature flag is enabled for your instance and then navigate to **Security & Compliance > Policies**, create a new Scan Result type policy, and select **License scanning** for your policy rule.
+ stage: manage
+ self-managed: true
+ gitlab-com: true
+ available_in: [Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/user/compliance/license_approval_policies.html
+ image_url: https://img.youtube.com/vi/34qBQ9t8qO8/hqdefault.jpg
+ published_at: 2023-02-02 # YYYY-MM-DD
+ release: 15.9
+- name: New License Compliance scanner
+ description: | # Do not modify this line, instead modify the lines below.
+ GitLab now supports a new method of detecting licenses that is capable of parsing and identifying over 500 different types of licenses and can extract license information from packages that are dual-licensed or have multiple different licenses that apply. In GitLab's development testing, this has empirically resulted in dramatically improved accuracy and completeness of results. Fewer CI pipeline minutes are consumed because the License Compliance job is no longer required. Additionally the new method has support for the same languages and versions as GitLab Dependency Scanning.
+
+ To use this new scanner, remove the inclusion of the `Jobs/License-Scanning.yml` template in your CI configuration and instead include the `Jobs/Dependency-Scanning.yml` template. After GitLab 16.0, the old method of scanning with the `Jobs/License-Scanning.yml` template will no longer be supported.
+
+ Currently this feature is available for GitLab SaaS users behind the `license_scanning_sbom_scanner` and `package_metadata_synchronization` feature flags. Users can follow along in GitLab to track the work to enable the [license_scanning_sbom_scanner](https://gitlab.com/gitlab-org/gitlab/-/issues/385173) and the [package_metadata_synchronization](https://gitlab.com/gitlab-org/gitlab/-/issues/390836) feature flags by default along with work to add support for [self-managed instances](https://gitlab.com/gitlab-org/gitlab/-/issues/391904) and [offline instances](https://gitlab.com/gitlab-org/gitlab/-/issues/384047).
+ stage: secure
+ self-managed: false
+ gitlab-com: true
+ available_in: [Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/
+ image_url: https://about.gitlab.com/images/15_9/new_license_scanner.png
+ published_at: 2023-02-02 # YYYY-MM-DD
+ release: 15.9
+- name: Notifications now available in the GitLab for Slack app
+ description: | # Do not modify this line, instead modify the lines below.
+ The GitLab for Slack app is the new home for managing notifications from GitLab to your Slack workspace. Not only can you use existing app features such as [slash commands](https://docs.gitlab.com/ee/user/project/integrations/slack_slash_commands.html), but you can now also specify which Slack channels you want to notify based on merge request changes, push events, issue changes, and many other GitLab events.
+
+ The [Slack notifications integration](https://docs.gitlab.com/ee/user/project/integrations/slack.html) is now deprecated for SaaS customers and will eventually [be removed](https://gitlab.com/groups/gitlab-org/-/epics/8673) as we continue to expand support for our GitLab for Slack app to better meet your needs.
+
+ To keep your teams in sync with what's happening in GitLab, get the [GitLab for Slack app](https://gitlab.slack.com/apps/A676ADMV5-gitlab) today!
+ stage: manage
+ self-managed: false
+ gitlab-com: true
+ available_in: [Free, Premium, Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/user/project/integrations/gitlab_slack_application.html#slack-notifications
+ image_url: https://about.gitlab.com/images/15_9/slack_notifications_jan_31-optimized.png
+ published_at: 2023-02-02 # YYYY-MM-DD
+ release: 15.9
+- name: Code Suggestions available in closed beta
+ description: | # Do not modify this line, instead modify the lines below.
+ Every day millions of developers use GitLab to contribute code. We’re starting to empower developers to code more efficiently and effectively with a closed beta of Gitlab Code Suggestions.
+
+ Closed beta participants can use the GitLab Workflow VSCode extension to get code suggestions as they type. Depending on the prompt, the extension either provides entire code snippets like generating functions, or completes the current line. Simply pressing the tab key allows you to accept the suggestions.
+
+ GitLab Code Suggestions can improve developer productivity, focus, and innovation without context switching and within a single DevSecOps platform. While currently limited in closed beta, interested Ultimate customers can express interest by filling out this form to be considered for early access.
+ stage: modelops
+ self-managed: false
+ gitlab-com: true
+ available_in: [Ultimate]
+ documentation_link: https://about.gitlab.com/releases/2023/02/22/gitlab-15-9-released/#code-suggestions-available-in-closed-beta
+ image_url: https://about.gitlab.com/images/15_9/DemoFastApi.gif
+ published_at: 2023-02-02 # YYYY-MM-DD
+ release: 15.9
diff --git a/db/docs/airflow_dags.yml b/db/docs/airflow_dags.yml
deleted file mode 100644
index 6ed6c9753a8..00000000000
--- a/db/docs/airflow_dags.yml
+++ /dev/null
@@ -1,10 +0,0 @@
----
-table_name: airflow_dags
-classes:
- - Airflow::Dags
-feature_categories:
- - dataops
-description: An Airflow DAG is a record of the current status of a DAG from an Airflow instance
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108900
-milestone: '15.9'
-gitlab_schema: gitlab_main
diff --git a/db/docs/application_setting_terms.yml b/db/docs/application_setting_terms.yml
index 046231b13a4..d58d4d67569 100644
--- a/db/docs/application_setting_terms.yml
+++ b/db/docs/application_setting_terms.yml
@@ -3,7 +3,7 @@ table_name: application_setting_terms
classes:
- ApplicationSetting::Term
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/cf37bef287d7dd5d2dce3e2276489767b8c0671f
milestone: '10.8'
diff --git a/db/docs/atlassian_identities.yml b/db/docs/atlassian_identities.yml
index e43c8018d5c..e24c316c0f6 100644
--- a/db/docs/atlassian_identities.yml
+++ b/db/docs/atlassian_identities.yml
@@ -3,7 +3,7 @@ table_name: atlassian_identities
classes:
- Atlassian::Identity
feature_categories:
-- authentication_and_authorization
+- system_access
description: Stores Atlassian credentials that are used to integrate with Atlassian API
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40176
milestone: '13.4'
diff --git a/db/docs/authentication_events.yml b/db/docs/authentication_events.yml
index eaede3b7cd4..440ca695ad2 100644
--- a/db/docs/authentication_events.yml
+++ b/db/docs/authentication_events.yml
@@ -3,7 +3,7 @@ table_name: authentication_events
classes:
- AuthenticationEvent
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39652
milestone: '13.4'
diff --git a/db/docs/banned_users.yml b/db/docs/banned_users.yml
index d14b6d77234..33c5c9024cd 100644
--- a/db/docs/banned_users.yml
+++ b/db/docs/banned_users.yml
@@ -3,7 +3,7 @@ table_name: banned_users
classes:
- Users::BannedUser
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64728
milestone: '14.2'
diff --git a/db/docs/bulk_import_batch_trackers.yml b/db/docs/bulk_import_batch_trackers.yml
new file mode 100644
index 00000000000..6e6ee123588
--- /dev/null
+++ b/db/docs/bulk_import_batch_trackers.yml
@@ -0,0 +1,11 @@
+---
+table_name: bulk_import_batch_trackers
+classes:
+- BulkImports::BatchTracker
+feature_categories:
+- importers
+description: Used to store and track the import status of a batch of relations for the migration
+ of groups or projects
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111708
+milestone: '15.10'
+gitlab_schema: gitlab_main
diff --git a/db/docs/bulk_import_export_batches.yml b/db/docs/bulk_import_export_batches.yml
new file mode 100644
index 00000000000..8cbd032a23a
--- /dev/null
+++ b/db/docs/bulk_import_export_batches.yml
@@ -0,0 +1,11 @@
+---
+table_name: bulk_import_export_batches
+classes:
+- BulkImports::ExportBatch
+feature_categories:
+- importers
+description: Used to track the generation status of export batch files for groups
+ or projects
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111708
+milestone: '15.10'
+gitlab_schema: gitlab_main
diff --git a/db/docs/catalog_resources.yml b/db/docs/catalog_resources.yml
new file mode 100644
index 00000000000..5bc689c308e
--- /dev/null
+++ b/db/docs/catalog_resources.yml
@@ -0,0 +1,8 @@
+---
+table_name: catalog_resources
+feature_categories:
+- pipeline_composition
+description: Projects containing a catalog resource.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112482
+milestone: '15.10'
+gitlab_schema: gitlab_main
diff --git a/db/docs/ci_build_needs.yml b/db/docs/ci_build_needs.yml
index 7253e83601a..0a84efb5598 100644
--- a/db/docs/ci_build_needs.yml
+++ b/db/docs/ci_build_needs.yml
@@ -3,7 +3,7 @@ table_name: ci_build_needs
classes:
- Ci::BuildNeed
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: Dependencies for a specific CI/CD job.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31328
milestone: '12.2'
diff --git a/db/docs/ci_cost_settings.yml b/db/docs/ci_cost_settings.yml
new file mode 100644
index 00000000000..3c5fc00cee0
--- /dev/null
+++ b/db/docs/ci_cost_settings.yml
@@ -0,0 +1,10 @@
+---
+table_name: ci_cost_settings
+classes:
+- Ci::Minutes::CostSetting
+feature_categories:
+- continuous_integration
+description: A set of cost factors per runner which are applied to ci job duration based on project type.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111977
+milestone: '15.10'
+gitlab_schema: gitlab_ci
diff --git a/db/docs/ci_group_variables.yml b/db/docs/ci_group_variables.yml
index c504a601c4c..b98cbe92c83 100644
--- a/db/docs/ci_group_variables.yml
+++ b/db/docs/ci_group_variables.yml
@@ -3,7 +3,7 @@ table_name: ci_group_variables
classes:
- Ci::GroupVariable
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/5b0954759cc24bdba97be89bb117c5440174f859
milestone: '9.4'
diff --git a/db/docs/ci_instance_variables.yml b/db/docs/ci_instance_variables.yml
index c39fe03b993..297477de562 100644
--- a/db/docs/ci_instance_variables.yml
+++ b/db/docs/ci_instance_variables.yml
@@ -3,7 +3,7 @@ table_name: ci_instance_variables
classes:
- Ci::InstanceVariable
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: CI/CD variables available to all projects and groups in an instance.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30156
milestone: '13.0'
diff --git a/db/docs/ci_job_variables.yml b/db/docs/ci_job_variables.yml
index 1cbabb4fcbb..4a933f65479 100644
--- a/db/docs/ci_job_variables.yml
+++ b/db/docs/ci_job_variables.yml
@@ -3,7 +3,7 @@ table_name: ci_job_variables
classes:
- Ci::JobVariable
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: CI/CD variables set to a job when running it manually.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/14784
milestone: '12.2'
diff --git a/db/docs/ci_pipeline_variables.yml b/db/docs/ci_pipeline_variables.yml
index aaf49b17c99..7e83009b3d8 100644
--- a/db/docs/ci_pipeline_variables.yml
+++ b/db/docs/ci_pipeline_variables.yml
@@ -3,7 +3,7 @@ table_name: ci_pipeline_variables
classes:
- Ci::PipelineVariable
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/56418e85ac6b667d19495665860092ce4d74f55d
milestone: '9.5'
diff --git a/db/docs/ci_secure_file_states.yml b/db/docs/ci_secure_file_states.yml
index 5734f040f2f..eacbea878e0 100644
--- a/db/docs/ci_secure_file_states.yml
+++ b/db/docs/ci_secure_file_states.yml
@@ -3,7 +3,7 @@ table_name: ci_secure_file_states
classes:
- Geo::CiSecureFileState
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: Stores verification state for Geo replicated Project-level Secure Files.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90510
milestone: '15.2'
diff --git a/db/docs/ci_secure_files.yml b/db/docs/ci_secure_files.yml
index 6124eeade28..198326a0e25 100644
--- a/db/docs/ci_secure_files.yml
+++ b/db/docs/ci_secure_files.yml
@@ -3,7 +3,7 @@ table_name: ci_secure_files
classes:
- Ci::SecureFile
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77886
milestone: '14.7'
diff --git a/db/docs/ci_sources_pipelines.yml b/db/docs/ci_sources_pipelines.yml
index 7e0121ab66e..034c3bd7db7 100644
--- a/db/docs/ci_sources_pipelines.yml
+++ b/db/docs/ci_sources_pipelines.yml
@@ -3,7 +3,7 @@ table_name: ci_sources_pipelines
classes:
- Ci::Sources::Pipeline
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: It stores parent-child and cross-project pipeline relationships.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/163983e0d7d1dab622846441bd0dd9086c78a69f
milestone: '9.3'
diff --git a/db/docs/ci_variables.yml b/db/docs/ci_variables.yml
index bcb6b3f3753..e083217db13 100644
--- a/db/docs/ci_variables.yml
+++ b/db/docs/ci_variables.yml
@@ -3,7 +3,7 @@ table_name: ci_variables
classes:
- Ci::Variable
feature_categories:
-- pipeline_authoring
+- pipeline_composition
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/046b28312704f3131e72dcd2dbdacc5264d4aa62
milestone: '8.0'
diff --git a/db/docs/clusters_applications_crossplane.yml b/db/docs/clusters_applications_crossplane.yml
index f633f746e70..c440eb2487b 100644
--- a/db/docs/clusters_applications_crossplane.yml
+++ b/db/docs/clusters_applications_crossplane.yml
@@ -1,7 +1,5 @@
---
table_name: clusters_applications_crossplane
-classes:
-- Clusters::Applications::Crossplane
feature_categories:
- kubernetes_management
description: "(Deprecated) A GitLab managed Crossplane installation in a Kubernetes cluster"
diff --git a/db/docs/clusters_applications_prometheus.yml b/db/docs/clusters_applications_prometheus.yml
index 9b99ffba5db..3c36d953726 100644
--- a/db/docs/clusters_applications_prometheus.yml
+++ b/db/docs/clusters_applications_prometheus.yml
@@ -1,7 +1,5 @@
---
table_name: clusters_applications_prometheus
-classes:
-- Clusters::Applications::Prometheus
feature_categories:
- kubernetes_management
description: Information about installed instance of Prometheus in the cluster
diff --git a/db/docs/container_registry_data_repair_details.yml b/db/docs/container_registry_data_repair_details.yml
new file mode 100644
index 00000000000..c258fff4832
--- /dev/null
+++ b/db/docs/container_registry_data_repair_details.yml
@@ -0,0 +1,10 @@
+---
+table_name: container_registry_data_repair_details
+classes:
+- ContainerRegistry::DataRepairDetail
+feature_categories:
+- container_registry
+description: Contains details for the container registry data repair
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113029
+milestone: '15.10'
+gitlab_schema: gitlab_main
diff --git a/db/docs/container_repository_states.yml b/db/docs/container_repository_states.yml
new file mode 100644
index 00000000000..300bf7bdd41
--- /dev/null
+++ b/db/docs/container_repository_states.yml
@@ -0,0 +1,11 @@
+---
+table_name: container_repository_states
+description: Checksum states of container repositories for Geo verification
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111077
+milestone: 15.10
+classes:
+- Geo::ContainerRepositoryState
+feature_categories:
+- geo_replication
+gitlab_schema: gitlab_main
+
diff --git a/db/docs/deleted_tables/airflow_dags.yml b/db/docs/deleted_tables/airflow_dags.yml
new file mode 100644
index 00000000000..4942e71d3bf
--- /dev/null
+++ b/db/docs/deleted_tables/airflow_dags.yml
@@ -0,0 +1,12 @@
+---
+table_name: airflow_dags
+classes:
+ - Airflow::Dags
+feature_categories:
+ - dataops
+description: An Airflow DAG is a record of the current status of a DAG from an Airflow instance
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108900
+milestone: '15.9'
+gitlab_schema: gitlab_main
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112192
+removed_in_milestone: '15.10'
diff --git a/db/docs/elastic_reindexing_slices.yml b/db/docs/elastic_reindexing_slices.yml
index 84e42b16d57..9b8cc69e73b 100644
--- a/db/docs/elastic_reindexing_slices.yml
+++ b/db/docs/elastic_reindexing_slices.yml
@@ -3,7 +3,7 @@ table_name: elastic_reindexing_slices
classes:
- Elastic::ReindexingSlice
feature_categories:
-- application_performance
+- global_search
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55681
milestone: '13.12'
diff --git a/db/docs/elasticsearch_indexed_projects.yml b/db/docs/elasticsearch_indexed_projects.yml
index 17e2e116fdd..17fc5d0f779 100644
--- a/db/docs/elasticsearch_indexed_projects.yml
+++ b/db/docs/elasticsearch_indexed_projects.yml
@@ -3,7 +3,7 @@ table_name: elasticsearch_indexed_projects
classes:
- ElasticsearchIndexedProject
feature_categories:
-- application_performance
+- global_search
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9861
milestone: '11.10'
diff --git a/db/docs/group_group_links.yml b/db/docs/group_group_links.yml
index f1541871795..1fa70ec02a6 100644
--- a/db/docs/group_group_links.yml
+++ b/db/docs/group_group_links.yml
@@ -3,7 +3,7 @@ table_name: group_group_links
classes:
- GroupGroupLink
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17117
milestone: '12.5'
diff --git a/db/docs/identities.yml b/db/docs/identities.yml
index 149907a419e..f2790c53466 100644
--- a/db/docs/identities.yml
+++ b/db/docs/identities.yml
@@ -3,7 +3,7 @@ table_name: identities
classes:
- Identity
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/1a80d13a3990937580c97e2b0ba8fb98f69bc055
milestone: '7.6'
diff --git a/db/docs/integrations.yml b/db/docs/integrations.yml
index 5bb4f448541..91675f8de35 100644
--- a/db/docs/integrations.yml
+++ b/db/docs/integrations.yml
@@ -26,6 +26,7 @@ classes:
- Integrations::ExternalWiki
- Integrations::Github
- Integrations::GitlabSlackApplication
+- Integrations::GooglePlay
- Integrations::HangoutsChat
- Integrations::Harbor
- Integrations::Irker
@@ -46,6 +47,7 @@ classes:
- Integrations::Shimo
- Integrations::Slack
- Integrations::SlackSlashCommands
+- Integrations::SquashTm
- Integrations::Teamcity
- Integrations::UnifyCircuit
- Integrations::WebexTeams
diff --git a/db/docs/ip_restrictions.yml b/db/docs/ip_restrictions.yml
index 93f0da0505a..fbf90135d0a 100644
--- a/db/docs/ip_restrictions.yml
+++ b/db/docs/ip_restrictions.yml
@@ -3,7 +3,7 @@ table_name: ip_restrictions
classes:
- IpRestriction
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/12669
milestone: '12.0'
diff --git a/db/docs/keys.yml b/db/docs/keys.yml
index 4e626b1465c..41f6786a6cc 100644
--- a/db/docs/keys.yml
+++ b/db/docs/keys.yml
@@ -5,7 +5,7 @@ classes:
- Key
- LDAPKey
feature_categories:
-- authentication_and_authorization
+- system_access
- continuous_delivery
description: SSH keys used by users or for deployments.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9ba1224867665844b117fa037e1465bb706b3685
diff --git a/db/docs/ldap_group_links.yml b/db/docs/ldap_group_links.yml
index d9a1b0acca5..74cc1a13d69 100644
--- a/db/docs/ldap_group_links.yml
+++ b/db/docs/ldap_group_links.yml
@@ -3,7 +3,7 @@ table_name: ldap_group_links
classes:
- LdapGroupLink
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/b017947ac91655f8ae6593fb63c3423cd1b439f4
milestone: '7.3'
diff --git a/db/docs/namespace_admin_notes.yml b/db/docs/namespace_admin_notes.yml
index 6d6710f7ee4..50ca72b270c 100644
--- a/db/docs/namespace_admin_notes.yml
+++ b/db/docs/namespace_admin_notes.yml
@@ -3,7 +3,7 @@ table_name: namespace_admin_notes
classes:
- Namespace::AdminNote
feature_categories:
-- authentication_and_authorization
+- system_access
- subgroups
description: Contains notes about groups that are visible to server administrators.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47825
diff --git a/db/docs/namespace_ldap_settings.yml b/db/docs/namespace_ldap_settings.yml
new file mode 100644
index 00000000000..e2ebbf54fde
--- /dev/null
+++ b/db/docs/namespace_ldap_settings.yml
@@ -0,0 +1,10 @@
+---
+table_name: namespace_ldap_settings
+classes:
+ - Namespaces::LdapSetting
+feature_categories:
+ - system_access
+description: Used to store LDAP settings for namespaces
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108908
+milestone: '15.10'
+gitlab_schema: gitlab_main
diff --git a/db/docs/oauth_access_grants.yml b/db/docs/oauth_access_grants.yml
index 197d4fc59bd..8339863cca7 100644
--- a/db/docs/oauth_access_grants.yml
+++ b/db/docs/oauth_access_grants.yml
@@ -4,7 +4,7 @@ classes:
- Doorkeeper::AccessGrant
- OauthAccessGrant
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/e41dadcb33fda44ee274daa673bd933e13aa90eb
milestone: '7.7'
diff --git a/db/docs/oauth_access_tokens.yml b/db/docs/oauth_access_tokens.yml
index f409762f483..4f68fe5b6c6 100644
--- a/db/docs/oauth_access_tokens.yml
+++ b/db/docs/oauth_access_tokens.yml
@@ -4,7 +4,7 @@ classes:
- Doorkeeper::AccessToken
- OauthAccessToken
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/e41dadcb33fda44ee274daa673bd933e13aa90eb
milestone: '7.7'
diff --git a/db/docs/oauth_applications.yml b/db/docs/oauth_applications.yml
index ac13ab3319a..e24578c3272 100644
--- a/db/docs/oauth_applications.yml
+++ b/db/docs/oauth_applications.yml
@@ -3,7 +3,7 @@ table_name: oauth_applications
classes:
- Doorkeeper::Application
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/e41dadcb33fda44ee274daa673bd933e13aa90eb
milestone: '7.7'
diff --git a/db/docs/oauth_openid_requests.yml b/db/docs/oauth_openid_requests.yml
index 011b91a758a..59de50597c3 100644
--- a/db/docs/oauth_openid_requests.yml
+++ b/db/docs/oauth_openid_requests.yml
@@ -3,7 +3,7 @@ table_name: oauth_openid_requests
classes:
- Doorkeeper::OpenidConnect::Request
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/c4982890489d254da2fe998aab30bf257767ed5e
milestone: '9.0'
diff --git a/db/docs/p_ci_runner_machine_builds.yml b/db/docs/p_ci_runner_machine_builds.yml
new file mode 100644
index 00000000000..8ffac67fb94
--- /dev/null
+++ b/db/docs/p_ci_runner_machine_builds.yml
@@ -0,0 +1,9 @@
+table_name: p_ci_runner_machine_builds
+classes:
+- Ci::RunnerMachineBuild
+feature_categories:
+- runner_fleet
+description: Relationships between builds and runner machines
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111476
+milestone: '15.9'
+gitlab_schema: gitlab_ci
diff --git a/db/docs/personal_access_tokens.yml b/db/docs/personal_access_tokens.yml
index 8241f4234d8..2739db8371f 100644
--- a/db/docs/personal_access_tokens.yml
+++ b/db/docs/personal_access_tokens.yml
@@ -3,7 +3,7 @@ table_name: personal_access_tokens
classes:
- PersonalAccessToken
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/3a609038748055a27c7e01cf4b55d8249709c9cc
milestone: '8.9'
diff --git a/db/docs/postgres_async_foreign_key_validations.yml b/db/docs/postgres_async_foreign_key_validations.yml
index 0b9608a3ace..587dd7d69a2 100644
--- a/db/docs/postgres_async_foreign_key_validations.yml
+++ b/db/docs/postgres_async_foreign_key_validations.yml
@@ -1,7 +1,7 @@
---
table_name: postgres_async_foreign_key_validations
classes:
-- Gitlab::Database::AsyncForeignKeys::PostgresAsyncForeignKeyValidation
+- Gitlab::Database::AsyncConstraints::PostgresAsyncConstraintValidation
feature_categories:
- database
description: >-
diff --git a/db/docs/project_access_tokens.yml b/db/docs/project_access_tokens.yml
index ddaca744571..3c19e4dc19f 100644
--- a/db/docs/project_access_tokens.yml
+++ b/db/docs/project_access_tokens.yml
@@ -2,7 +2,7 @@
table_name: project_access_tokens
classes: []
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33272
milestone: '13.1'
diff --git a/db/docs/project_authorizations.yml b/db/docs/project_authorizations.yml
index b37634047f0..b81235d4aac 100644
--- a/db/docs/project_authorizations.yml
+++ b/db/docs/project_authorizations.yml
@@ -4,7 +4,7 @@ classes:
- ProjectAuthorization
feature_categories:
- projects
-- authentication_and_authorization
+- system_access
description: Stores maximal access to the project per user
introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/6839
milestone: '8.14'
diff --git a/db/docs/project_group_links.yml b/db/docs/project_group_links.yml
index c03141058b6..aa981adb745 100644
--- a/db/docs/project_group_links.yml
+++ b/db/docs/project_group_links.yml
@@ -3,7 +3,7 @@ table_name: project_group_links
classes:
- ProjectGroupLink
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/3ac5a759e93e632539438d4564582c645a9f6799
milestone: "<6.0"
diff --git a/db/docs/saml_group_links.yml b/db/docs/saml_group_links.yml
index 5fd2372a22d..4dfb33e37a5 100644
--- a/db/docs/saml_group_links.yml
+++ b/db/docs/saml_group_links.yml
@@ -3,7 +3,7 @@ table_name: saml_group_links
classes:
- SamlGroupLink
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45061
milestone: '13.5'
diff --git a/db/docs/saml_providers.yml b/db/docs/saml_providers.yml
index 6fcc0e0e370..21ef2ed3a26 100644
--- a/db/docs/saml_providers.yml
+++ b/db/docs/saml_providers.yml
@@ -3,7 +3,7 @@ table_name: saml_providers
classes:
- SamlProvider
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4549
milestone: '10.7'
diff --git a/db/docs/scim_identities.yml b/db/docs/scim_identities.yml
index 6ad69d9b4cc..16fec8da041 100644
--- a/db/docs/scim_identities.yml
+++ b/db/docs/scim_identities.yml
@@ -3,7 +3,7 @@ table_name: scim_identities
classes:
- ScimIdentity
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26124
milestone: '12.9'
diff --git a/db/docs/scim_oauth_access_tokens.yml b/db/docs/scim_oauth_access_tokens.yml
index e26cd94f4cd..addd4c49ed5 100644
--- a/db/docs/scim_oauth_access_tokens.yml
+++ b/db/docs/scim_oauth_access_tokens.yml
@@ -3,7 +3,7 @@ table_name: scim_oauth_access_tokens
classes:
- ScimOauthAccessToken
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/e9b2253fe3538234d1c4d173c4549a955233d836
milestone: '11.10'
diff --git a/db/docs/serverless_domain_cluster.yml b/db/docs/serverless_domain_cluster.yml
index 23c77b2c043..72b231171ba 100644
--- a/db/docs/serverless_domain_cluster.yml
+++ b/db/docs/serverless_domain_cluster.yml
@@ -1,7 +1,5 @@
---
table_name: serverless_domain_cluster
-classes:
-- Serverless::DomainCluster
feature_categories:
- kubernetes_management
description: "(Deprecated) A custom domain for a GitLab managed Knative installation"
diff --git a/db/docs/service_desk_custom_email_verifications.yml b/db/docs/service_desk_custom_email_verifications.yml
new file mode 100644
index 00000000000..cec5db374d9
--- /dev/null
+++ b/db/docs/service_desk_custom_email_verifications.yml
@@ -0,0 +1,11 @@
+---
+table_name: service_desk_custom_email_verifications
+classes:
+- ServiceDesk::CustomEmailVerification
+feature_categories:
+- service_desk
+description: Holds the verification state and additional information for custom email
+ addresses for Service Desk
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112938
+milestone: '15.10'
+gitlab_schema: gitlab_main
diff --git a/db/docs/smartcard_identities.yml b/db/docs/smartcard_identities.yml
index 76b8d1a1368..905811768c1 100644
--- a/db/docs/smartcard_identities.yml
+++ b/db/docs/smartcard_identities.yml
@@ -3,7 +3,7 @@ table_name: smartcard_identities
classes:
- SmartcardIdentity
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/b6316689fdc2d142af85b17d511d39e50712b420
milestone: '11.6'
diff --git a/db/docs/term_agreements.yml b/db/docs/term_agreements.yml
index 502adad8ac0..bc2abea809e 100644
--- a/db/docs/term_agreements.yml
+++ b/db/docs/term_agreements.yml
@@ -3,7 +3,7 @@ table_name: term_agreements
classes:
- TermAgreement
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/82eeb72c8c03727540b902d40e7e657d0a5ecb4c
milestone: '10.8'
diff --git a/db/docs/token_with_ivs.yml b/db/docs/token_with_ivs.yml
index 2acdff0dad1..521e26baac0 100644
--- a/db/docs/token_with_ivs.yml
+++ b/db/docs/token_with_ivs.yml
@@ -3,7 +3,7 @@ table_name: token_with_ivs
classes:
- TokenWithIv
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/37b80b4048190c2e1a35ec399e4aeb35d511090e
milestone: '13.9'
diff --git a/db/docs/u2f_registrations.yml b/db/docs/u2f_registrations.yml
index 27b0ca3f2f5..b1aaa8148bd 100644
--- a/db/docs/u2f_registrations.yml
+++ b/db/docs/u2f_registrations.yml
@@ -3,7 +3,7 @@ table_name: u2f_registrations
classes:
- U2fRegistration
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/791cc9138be6ea1783e3c3853370cf0290f4d41e
milestone: '8.9'
diff --git a/db/docs/user_canonical_emails.yml b/db/docs/user_canonical_emails.yml
index aeb1c3d830f..df3240b52fa 100644
--- a/db/docs/user_canonical_emails.yml
+++ b/db/docs/user_canonical_emails.yml
@@ -3,7 +3,7 @@ table_name: user_canonical_emails
classes:
- UserCanonicalEmail
feature_categories:
-- authentication_and_authorization
+- system_access
description: stores the canonical version of user's primary email address
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27722
milestone: '13.0'
diff --git a/db/docs/user_highest_roles.yml b/db/docs/user_highest_roles.yml
index cc12e3080ff..cfe4c2e5ce0 100644
--- a/db/docs/user_highest_roles.yml
+++ b/db/docs/user_highest_roles.yml
@@ -3,7 +3,7 @@ table_name: user_highest_roles
classes:
- UserHighestRole
feature_categories:
-- authentication_and_authorization
+- system_access
description: Stores highest role per User they have in a Group or a Project. If a User has an open invite or pending access request or no membership the highest role will be set to nil.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26987
milestone: '12.9'
diff --git a/db/docs/user_permission_export_uploads.yml b/db/docs/user_permission_export_uploads.yml
index 217ede5bad2..fe76f1fa618 100644
--- a/db/docs/user_permission_export_uploads.yml
+++ b/db/docs/user_permission_export_uploads.yml
@@ -3,7 +3,7 @@ table_name: user_permission_export_uploads
classes:
- UserPermissionExportUpload
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47846
milestone: '13.7'
diff --git a/db/docs/user_synced_attributes_metadata.yml b/db/docs/user_synced_attributes_metadata.yml
index efc0ad1ec95..a2162c071c9 100644
--- a/db/docs/user_synced_attributes_metadata.yml
+++ b/db/docs/user_synced_attributes_metadata.yml
@@ -3,7 +3,7 @@ table_name: user_synced_attributes_metadata
classes:
- UserSyncedAttributesMetadata
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/4df54f260751a832ebf0b8c18524020d6604994b
milestone: '10.0'
diff --git a/db/docs/webauthn_registrations.yml b/db/docs/webauthn_registrations.yml
index fc983ea60ca..1ec27e1bb3b 100644
--- a/db/docs/webauthn_registrations.yml
+++ b/db/docs/webauthn_registrations.yml
@@ -3,7 +3,7 @@ table_name: webauthn_registrations
classes:
- WebauthnRegistration
feature_categories:
-- authentication_and_authorization
+- system_access
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35797
milestone: '13.2'
diff --git a/db/docs/work_item_types.yml b/db/docs/work_item_types.yml
index 37d2c47de25..9c3da6a1b9d 100644
--- a/db/docs/work_item_types.yml
+++ b/db/docs/work_item_types.yml
@@ -1,6 +1,7 @@
---
table_name: work_item_types
classes:
+- AddNotificationsWorkItemWidget::WorkItemType
- AddWidgetsForWorkItemTypes::WorkItemType
- WorkItems::Type
feature_categories:
diff --git a/db/docs/work_item_widget_definitions.yml b/db/docs/work_item_widget_definitions.yml
index 59cbca14908..a11fbfd34ae 100644
--- a/db/docs/work_item_widget_definitions.yml
+++ b/db/docs/work_item_widget_definitions.yml
@@ -1,6 +1,7 @@
---
table_name: work_item_widget_definitions
classes:
+- AddNotificationsWorkItemWidget::WidgetDefinition
- AddWidgetsForWorkItemTypes::WidgetDefinition
- WorkItems::WidgetDefinition
feature_categories:
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index fa890531861..50155668dca 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -18,7 +18,8 @@ require 'active_support/testing/time_helpers'
#
# VSA_SEED_PROJECT_ID=10 FILTER=cycle_analytics SEED_VSA=1 bundle exec rake db:seed_fu
-class Gitlab::Seeder::CycleAnalytics
+# rubocop:disable Rails/Output
+class Gitlab::Seeder::CycleAnalytics # rubocop:disable Style/ClassAndModuleChildren
include ActiveSupport::Testing::TimeHelpers
attr_reader :project, :issues, :merge_requests, :developers
@@ -26,18 +27,21 @@ class Gitlab::Seeder::CycleAnalytics
FLAG = 'SEED_VSA'
PERF_TEST = 'VSA_PERF_TEST'
- ISSUE_STAGE_MAX_DURATION_IN_HOURS = 72
- PLAN_STAGE_MAX_DURATION_IN_HOURS = 48
- CODE_STAGE_MAX_DURATION_IN_HOURS = 72
- TEST_STAGE_MAX_DURATION_IN_HOURS = 5
- REVIEW_STAGE_MAX_DURATION_IN_HOURS = 72
- DEPLOYMENT_MAX_DURATION_IN_HOURS = 48
+ MAX_DURATIONS = { # in hours
+ issue: 72,
+ plan: 48,
+ code: 72,
+ test: 5,
+ review: 72,
+ deployment: 48,
+ lead_time: 32
+ }.freeze
def self.seeder_based_on_env(project)
if ENV[FLAG]
- self.new(project: project)
+ new(project: project)
elsif ENV[PERF_TEST]
- self.new(project: project, perf: true)
+ new(project: project, perf: true)
end
end
@@ -54,8 +58,10 @@ class Gitlab::Seeder::CycleAnalytics
puts
puts 'WARNING'
puts '======='
- puts "Seeding #{self.class} is not possible because the given project (#{project.full_path}) doesn't have a repository."
- puts 'Try specifying a project with working repository or omit the VSA_SEED_PROJECT_ID parameter so the seed script will automatically create one.'
+ puts "Seeding #{self.class} is not possible because the given project " \
+ "(#{project.full_path}) doesn't have a repository."
+ puts 'Try specifying a project with working repository or omit the VSA_SEED_PROJECT_ID parameter ' \
+ 'so the seed script will automatically create one.'
puts
return
@@ -64,6 +70,7 @@ class Gitlab::Seeder::CycleAnalytics
create_developers!
create_issues!
+ seed_lead_time!
seed_issue_stage!
seed_plan_stage!
seed_code_stage!
@@ -79,7 +86,7 @@ class Gitlab::Seeder::CycleAnalytics
def seed_issue_stage!
issues.each do |issue|
- time = within_end_time(issue.created_at + rand(ISSUE_STAGE_MAX_DURATION_IN_HOURS).hours)
+ time = within_end_time(issue.created_at + rand(MAX_DURATIONS[:issue]).hours)
if issue.id.even?
issue.metrics.update!(first_associated_with_milestone_at: time)
@@ -93,7 +100,7 @@ class Gitlab::Seeder::CycleAnalytics
issues.each do |issue|
plan_stage_start = issue.metrics.first_associated_with_milestone_at || issue.metrics.first_added_to_board_at
- first_mentioned_in_commit_at = within_end_time(plan_stage_start + rand(PLAN_STAGE_MAX_DURATION_IN_HOURS).hours)
+ first_mentioned_in_commit_at = within_end_time(plan_stage_start + rand(MAX_DURATIONS[:plan]).hours)
issue.metrics.update!(first_mentioned_in_commit_at: first_mentioned_in_commit_at)
end
end
@@ -107,7 +114,7 @@ class Gitlab::Seeder::CycleAnalytics
source_branch: "#{issue.iid}-feature-branch",
target_branch: 'master',
author: developers.sample,
- created_at: within_end_time(issue.metrics.first_mentioned_in_commit_at + rand(CODE_STAGE_MAX_DURATION_IN_HOURS).hours)
+ created_at: within_end_time(issue.metrics.first_mentioned_in_commit_at + rand(MAX_DURATIONS[:code]).hours)
)
@merge_requests << merge_request
@@ -118,16 +125,17 @@ class Gitlab::Seeder::CycleAnalytics
def seed_test_stage!
merge_requests.each do |merge_request|
- pipeline = FactoryBot.create(:ci_pipeline, :success, project: project, partition_id: Ci::Pipeline.current_partition_value)
+ pipeline = FactoryBot.create(:ci_pipeline, :success, project: project,
+ partition_id: Ci::Pipeline.current_partition_value)
build = FactoryBot.create(:ci_build, pipeline: pipeline, project: project, user: developers.sample)
# Required because seeds run in a transaction and these are now
# created in an `after_commit` hook.
- merge_request.ensure_metrics
+ merge_request.ensure_metrics!
merge_request.metrics.update!(
latest_build_started_at: merge_request.created_at,
- latest_build_finished_at: within_end_time(merge_request.created_at + TEST_STAGE_MAX_DURATION_IN_HOURS.hours),
+ latest_build_finished_at: within_end_time(merge_request.created_at + MAX_DURATIONS[:test].hours),
pipeline_id: build.commit_id
)
end
@@ -135,13 +143,25 @@ class Gitlab::Seeder::CycleAnalytics
def seed_review_stage!
merge_requests.each do |merge_request|
- merge_request.metrics.update!(merged_at: within_end_time(merge_request.created_at + REVIEW_STAGE_MAX_DURATION_IN_HOURS.hours))
+ merge_request.metrics.update!(
+ merged_at: within_end_time(merge_request.created_at + MAX_DURATIONS[:review].hours)
+ )
end
end
def seed_staging_stage!
merge_requests.each do |merge_request|
- merge_request.metrics.update!(first_deployed_to_production_at: within_end_time(merge_request.metrics.merged_at + DEPLOYMENT_MAX_DURATION_IN_HOURS.hours))
+ first_deployed_to_production_at = merge_request.metrics.merged_at + MAX_DURATIONS[:deployment].hours
+ merge_request.metrics.update!(
+ first_deployed_to_production_at: within_end_time(first_deployed_to_production_at)
+ )
+ end
+ end
+
+ def seed_lead_time!
+ issues.each do |issue|
+ created_at = issue.created_at - MAX_DURATIONS[:lead_time].hours
+ issue.update!(created_at: created_at, closed_at: Time.now)
end
end
@@ -224,3 +244,4 @@ Gitlab::Seeder.quiet do
puts "Skipped. Use the `#{Gitlab::Seeder::CycleAnalytics::FLAG}` environment variable to enable."
end
end
+# rubocop:enable Rails/Output
diff --git a/db/fixtures/development/36_achievements.rb b/db/fixtures/development/36_achievements.rb
new file mode 100644
index 00000000000..9bb485afe38
--- /dev/null
+++ b/db/fixtures/development/36_achievements.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+class Gitlab::Seeder::Achievements
+ attr_reader :group, :user_ids, :maintainer_ids
+
+ def initialize(group, user_ids)
+ @group = group
+ @maintainer_ids = group.members.maintainers.pluck(:user_id)
+ @maintainer_ids << User.admins.first.id
+ @user_ids = user_ids
+ end
+
+ def seed!
+ achievement_ids = Achievements::Achievement.pluck(:id)
+ achievement_ids = seed_achievements if achievement_ids.empty?
+
+ user_ids.reverse.each_with_index do |user_id, user_index|
+ (user_index + 1).times do |achievement_index|
+ ::Achievements::UserAchievement.create!(
+ user_id: user_id,
+ achievement_id: achievement_ids[achievement_index],
+ awarded_by_user_id: maintainer_ids.sample,
+ revoked_by_user_id: achievement_index == 0 ? maintainer_ids.sample : nil,
+ revoked_at: achievement_index == 0 ? DateTime.current : nil
+ )
+
+ print '.'
+ end
+ end
+ end
+
+ def seed_achievements
+ achievement_ids = []
+
+
+ ['revoked', 'first mr', 'hero', 'legend'].each do |achievement_name|
+ achievement_ids << ::Achievements::Achievement.create!(
+ namespace_id: group.id,
+ name: achievement_name,
+ description: achievement_name == 'hero' ? 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry''s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.' : nil,
+ avatar: seed_avatar(achievement_name)
+ ).id
+
+ print '.'
+ end
+
+ achievement_ids
+ end
+
+ def seed_avatar(achievement_name)
+ case achievement_name
+ when 'first mr'
+ File.new(Rails.root.join('db', 'fixtures', 'development', 'rocket.jpg'), 'r')
+ when 'hero'
+ File.new(Rails.root.join('db', 'fixtures', 'development', 'heart.png'), 'r')
+ end
+ end
+end
+
+Gitlab::Seeder.quiet do
+ puts "\nGenerating ahievements"
+
+ group = Group.first
+ users = User.first(4).pluck(:id)
+ Gitlab::Seeder::Achievements.new(group, users).seed!
+rescue => e
+ warn "\nError seeding achievements: #{e}"
+end
diff --git a/db/fixtures/development/heart.png b/db/fixtures/development/heart.png
new file mode 100644
index 00000000000..23ad1c76ffa
--- /dev/null
+++ b/db/fixtures/development/heart.png
Binary files differ
diff --git a/db/fixtures/development/rocket.jpg b/db/fixtures/development/rocket.jpg
new file mode 100644
index 00000000000..ab843fe057c
--- /dev/null
+++ b/db/fixtures/development/rocket.jpg
Binary files differ
diff --git a/db/migrate/20230113164245_create_namespace_ldap_settings.rb b/db/migrate/20230113164245_create_namespace_ldap_settings.rb
new file mode 100644
index 00000000000..5ad72c00b47
--- /dev/null
+++ b/db/migrate/20230113164245_create_namespace_ldap_settings.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class CreateNamespaceLdapSettings < Gitlab::Database::Migration[2.1]
+ def change
+ create_table :namespace_ldap_settings, if_not_exists: true, id: false do |t|
+ t.references :namespace, primary_key: true, default: nil,
+ type: :bigint, index: false, foreign_key: { on_delete: :cascade }
+ t.timestamps_with_timezone null: false
+ t.column :sync_last_start_at, :datetime_with_timezone
+ t.column :sync_last_update_at, :datetime_with_timezone
+ t.column :sync_last_successful_at, :datetime_with_timezone
+ t.integer :sync_status, null: false, default: 0, limit: 2
+ t.text :sync_error, limit: 255
+ end
+ end
+end
diff --git a/db/migrate/20230118135145_add_service_desk_custom_email_verifications.rb b/db/migrate/20230118135145_add_service_desk_custom_email_verifications.rb
new file mode 100644
index 00000000000..32f7f3392e6
--- /dev/null
+++ b/db/migrate/20230118135145_add_service_desk_custom_email_verifications.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class AddServiceDeskCustomEmailVerifications < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ create_table(:service_desk_custom_email_verifications, id: false, primary_key: :project_id) do |t|
+ t.references :project, index: false, foreign_key: { on_delete: :cascade }, null: false
+ t.references :triggerer, index: true, foreign_key: { to_table: :users, on_delete: :nullify }
+ t.timestamps_with_timezone
+ t.datetime_with_timezone :triggered_at
+ t.integer :state, limit: 2, null: false, default: 0
+ t.integer :error, limit: 2
+ t.binary :encrypted_token
+ t.binary :encrypted_token_iv
+ end
+
+ execute "ALTER TABLE service_desk_custom_email_verifications ADD PRIMARY KEY (project_id);"
+ end
+
+ def down
+ drop_table :service_desk_custom_email_verifications
+ end
+end
diff --git a/db/migrate/20230127030015_add_deny_all_outgoing_requests_to_application_settings.rb b/db/migrate/20230127030015_add_deny_all_outgoing_requests_to_application_settings.rb
new file mode 100644
index 00000000000..b12176a5541
--- /dev/null
+++ b/db/migrate/20230127030015_add_deny_all_outgoing_requests_to_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddDenyAllOutgoingRequestsToApplicationSettings < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :application_settings, :deny_all_requests_except_allowed, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20230127155217_add_id_column_to_package_metadata_join_table.rb b/db/migrate/20230127155217_add_id_column_to_package_metadata_join_table.rb
index 960421ae38e..4ce3643208e 100644
--- a/db/migrate/20230127155217_add_id_column_to_package_metadata_join_table.rb
+++ b/db/migrate/20230127155217_add_id_column_to_package_metadata_join_table.rb
@@ -6,6 +6,10 @@ class AddIdColumnToPackageMetadataJoinTable < Gitlab::Database::Migration[2.1]
COMPOSITE_UNIQUE_INDEX = :i_pm_package_version_licenses_join_ids
def up
+ if Gitlab::Database::PostgresPartitionedTable.where(name: 'pm_package_version_licenses').exists?
+ recreate_unpartitioned_tables
+ end
+
drop_constraint(:pm_package_version_licenses, :pm_package_version_licenses_pkey, cascade: true)
add_column(:pm_package_version_licenses, :id, :primary_key)
add_concurrent_index(:pm_package_version_licenses, [:pm_package_version_id, :pm_license_id], unique: true,
@@ -13,8 +17,60 @@ class AddIdColumnToPackageMetadataJoinTable < Gitlab::Database::Migration[2.1]
end
def down
+ return if Gitlab::Database::PostgresPartitionedTable.where(name: 'pm_package_version_licenses').exists?
+
remove_column(:pm_package_version_licenses, :id)
add_primary_key_using_index(:pm_package_version_licenses, :pm_package_version_licenses_pkey, COMPOSITE_UNIQUE_INDEX)
remove_concurrent_index_by_name(:pm_package_version_licenses, COMPOSITE_UNIQUE_INDEX)
end
+
+ private
+
+ def recreate_unpartitioned_tables
+ drop_table(:pm_package_version_licenses, force: :cascade) # rubocop:disable Migration/DropTable
+ drop_table(:pm_package_versions, force: :cascade) # rubocop:disable Migration/DropTable
+ drop_table(:pm_packages, force: :cascade) # rubocop:disable Migration/DropTable
+
+ create_table :pm_packages do |t|
+ t.integer :purl_type, limit: 2, null: false
+ t.text :name, null: false, limit: 255
+ t.timestamps_with_timezone null: false
+ t.index [:purl_type, :name], name: 'i_pm_packages_purl_type_and_name', unique: true
+ end
+
+ create_table :pm_package_versions do |t|
+ t.references :pm_package,
+ index: false,
+ null: false,
+ foreign_key: {
+ to_table: :pm_packages,
+ column: :pm_package_id,
+ name: 'fk_rails_cf94c3e601',
+ on_delete: :cascade
+ }
+ t.text :version, null: false, limit: 255
+ t.timestamps_with_timezone null: false
+ t.index [:pm_package_id, :version], name: 'i_pm_package_versions_on_package_id_and_version', unique: true
+ t.index :pm_package_id, name: 'index_pm_package_versions_on_pm_package_id'
+ end
+
+ create_table :pm_package_version_licenses, primary_key: [:pm_package_version_id, :pm_license_id] do |t|
+ t.references :pm_package_version,
+ index: false,
+ null: false,
+ foreign_key: {
+ to_table: :pm_package_versions,
+ column: :pm_package_version_id,
+ name: 'fk_rails_30ddb7f837',
+ on_delete: :cascade
+ }
+ t.references :pm_license,
+ index: false,
+ null: false,
+ foreign_key: { name: 'fk_rails_7520ea026d', on_delete: :cascade }
+ t.timestamps_with_timezone null: false
+ t.index :pm_license_id, name: 'index_pm_package_version_licenses_on_pm_license_id'
+ t.index :pm_package_version_id, name: 'index_pm_package_version_licenses_on_pm_package_version_id'
+ end
+ end
end
diff --git a/db/migrate/20230201165656_create_container_repository_states.rb b/db/migrate/20230201165656_create_container_repository_states.rb
new file mode 100644
index 00000000000..0e84faf11ee
--- /dev/null
+++ b/db/migrate/20230201165656_create_container_repository_states.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+class CreateContainerRepositoryStates < Gitlab::Database::Migration[2.1]
+ VERIFICATION_STATE_INDEX_NAME = "index_container_repository_states_on_verification_state"
+ PENDING_VERIFICATION_INDEX_NAME = "index_container_repository_states_pending_verification"
+ FAILED_VERIFICATION_INDEX_NAME = "index_container_repository_states_failed_verification"
+ NEEDS_VERIFICATION_INDEX_NAME = "index_container_repository_states_needs_verification"
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :container_repository_states, id: false do |t|
+ t.datetime_with_timezone :verification_started_at
+ t.datetime_with_timezone :verification_retry_at
+ t.datetime_with_timezone :verified_at
+ t.references :container_repository,
+ primary_key: true,
+ default: nil,
+ index: false,
+ foreign_key: { on_delete: :cascade }
+ t.integer :verification_state, default: 0, limit: 2, null: false
+ t.integer :verification_retry_count, default: 0, limit: 2, null: false
+ t.binary :verification_checksum, using: 'verification_checksum::bytea'
+ t.text :verification_failure, limit: 255
+
+ t.index :verification_state, name: VERIFICATION_STATE_INDEX_NAME
+ t.index :verified_at,
+ where: "(verification_state = 0)",
+ order: { verified_at: 'ASC NULLS FIRST' },
+ name: PENDING_VERIFICATION_INDEX_NAME
+ t.index :verification_retry_at,
+ where: "(verification_state = 3)",
+ order: { verification_retry_at: 'ASC NULLS FIRST' },
+ name: FAILED_VERIFICATION_INDEX_NAME
+ t.index :verification_state,
+ where: "(verification_state = 0 OR verification_state = 3)",
+ name: NEEDS_VERIFICATION_INDEX_NAME
+ end
+ end
+
+ def down
+ drop_table :container_repository_states
+ end
+end
diff --git a/db/migrate/20230202094723_add_default_syntax_highlighting_theme_to_application_settings.rb b/db/migrate/20230202094723_add_default_syntax_highlighting_theme_to_application_settings.rb
new file mode 100644
index 00000000000..048afb51f26
--- /dev/null
+++ b/db/migrate/20230202094723_add_default_syntax_highlighting_theme_to_application_settings.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddDefaultSyntaxHighlightingThemeToApplicationSettings < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :application_settings, :default_syntax_highlighting_theme, :integer, default: 1, null: false
+ end
+end
diff --git a/db/migrate/20230210152109_add_bulk_import_export_batches.rb b/db/migrate/20230210152109_add_bulk_import_export_batches.rb
new file mode 100644
index 00000000000..380f8a43aae
--- /dev/null
+++ b/db/migrate/20230210152109_add_bulk_import_export_batches.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddBulkImportExportBatches < Gitlab::Database::Migration[2.1]
+ def up
+ create_table :bulk_import_export_batches do |t|
+ t.references :export, index: true, null: false, foreign_key: {
+ to_table: :bulk_import_exports, on_delete: :cascade
+ }
+ t.timestamps_with_timezone null: false
+ t.integer :status, limit: 2, null: false, default: 0
+ t.integer :batch_number, null: false, default: 0
+ t.integer :objects_count, null: false, default: 0
+ t.text :error, limit: 255
+ t.index [:export_id, :batch_number], unique: true, name: 'i_bulk_import_export_batches_id_batch_number'
+ end
+ end
+
+ def down
+ drop_table :bulk_import_export_batches
+ end
+end
diff --git a/db/migrate/20230210153420_add_batched_column_to_bulk_import_exports.rb b/db/migrate/20230210153420_add_batched_column_to_bulk_import_exports.rb
new file mode 100644
index 00000000000..cfe4a2059bb
--- /dev/null
+++ b/db/migrate/20230210153420_add_batched_column_to_bulk_import_exports.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddBatchedColumnToBulkImportExports < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :bulk_import_exports, :batched, :boolean, null: false, default: false
+ add_column :bulk_import_exports, :batches_count, :integer, null: false, default: 0
+ add_column :bulk_import_exports, :total_objects_count, :integer, null: false, default: 0
+ end
+end
diff --git a/db/migrate/20230210155715_add_batch_id_to_bulk_import_export_uploads.rb b/db/migrate/20230210155715_add_batch_id_to_bulk_import_export_uploads.rb
new file mode 100644
index 00000000000..986d31a5839
--- /dev/null
+++ b/db/migrate/20230210155715_add_batch_id_to_bulk_import_export_uploads.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddBatchIdToBulkImportExportUploads < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :bulk_import_export_uploads, :batch_id, :bigint
+ end
+end
diff --git a/db/migrate/20230210160037_add_batch_foreign_key_to_bulk_import_export_uploads.rb b/db/migrate/20230210160037_add_batch_foreign_key_to_bulk_import_export_uploads.rb
new file mode 100644
index 00000000000..de0286f27ed
--- /dev/null
+++ b/db/migrate/20230210160037_add_batch_foreign_key_to_bulk_import_export_uploads.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddBatchForeignKeyToBulkImportExportUploads < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :bulk_import_export_uploads, :bulk_import_export_batches, column: :batch_id
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key_if_exists :bulk_import_export_uploads, column: :batch_id
+ end
+ end
+end
diff --git a/db/migrate/20230210160351_add_bulk_import_batch_trackers.rb b/db/migrate/20230210160351_add_bulk_import_batch_trackers.rb
new file mode 100644
index 00000000000..40f6341680f
--- /dev/null
+++ b/db/migrate/20230210160351_add_bulk_import_batch_trackers.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class AddBulkImportBatchTrackers < Gitlab::Database::Migration[2.1]
+ def up
+ create_table :bulk_import_batch_trackers do |t|
+ t.references :tracker, index: true, null: false, foreign_key: {
+ to_table: :bulk_import_trackers, on_delete: :cascade
+ }
+ t.timestamps_with_timezone null: false
+ t.integer :status, limit: 2, null: false, default: 0
+ t.integer :batch_number, null: false, default: 0
+ t.integer :fetched_objects_count, null: false, default: 0
+ t.integer :imported_objects_count, null: false, default: 0
+ t.text :error, limit: 255
+ t.index [:tracker_id, :batch_number], unique: true, name: 'i_bulk_import_trackers_id_batch_number'
+ end
+ end
+
+ def down
+ drop_table :bulk_import_batch_trackers
+ end
+end
diff --git a/db/migrate/20230210161002_add_batched_column_to_bulk_import_trackers.rb b/db/migrate/20230210161002_add_batched_column_to_bulk_import_trackers.rb
new file mode 100644
index 00000000000..5640164a117
--- /dev/null
+++ b/db/migrate/20230210161002_add_batched_column_to_bulk_import_trackers.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddBatchedColumnToBulkImportTrackers < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :bulk_import_trackers, :batched, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20230210171012_add_batch_id_index_to_bulk_import_export_uploads.rb b/db/migrate/20230210171012_add_batch_id_index_to_bulk_import_export_uploads.rb
new file mode 100644
index 00000000000..c2fd4198762
--- /dev/null
+++ b/db/migrate/20230210171012_add_batch_id_index_to_bulk_import_export_uploads.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddBatchIdIndexToBulkImportExportUploads < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'bulk_import_export_uploads_batch_id'
+
+ def up
+ add_concurrent_index :bulk_import_export_uploads, :batch_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index :bulk_import_export_uploads, :batch_id, name: INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230213213559_add_index_on_project_id_and_scanner_id_and_vulnerability_id_on_vulnerability_reads.rb b/db/migrate/20230213213559_add_index_on_project_id_and_scanner_id_and_vulnerability_id_on_vulnerability_reads.rb
new file mode 100644
index 00000000000..ee9e15d2484
--- /dev/null
+++ b/db/migrate/20230213213559_add_index_on_project_id_and_scanner_id_and_vulnerability_id_on_vulnerability_reads.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexOnProjectIdAndScannerIdAndVulnerabilityIdOnVulnerabilityReads < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = "idx_vulnerability_reads_project_id_scanner_id_vulnerability_id"
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :vulnerability_reads, [:project_id, :scanner_id, :vulnerability_id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerability_reads, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230215074223_add_ci_runner_machine_builds_partitioned_table.rb b/db/migrate/20230215074223_add_ci_runner_machine_builds_partitioned_table.rb
new file mode 100644
index 00000000000..4e47d35d804
--- /dev/null
+++ b/db/migrate/20230215074223_add_ci_runner_machine_builds_partitioned_table.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class AddCiRunnerMachineBuildsPartitionedTable < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers
+
+ enable_lock_retries!
+
+ TABLE_NAME = :ci_runner_machine_builds
+ PARENT_TABLE_NAME = :p_ci_runner_machine_builds
+ FIRST_PARTITION = 100
+
+ def up
+ execute(<<~SQL)
+ CREATE TABLE #{PARENT_TABLE_NAME} (
+ partition_id bigint NOT NULL,
+ build_id bigint NOT NULL,
+ runner_machine_id bigint NOT NULL,
+ PRIMARY KEY (partition_id, build_id),
+ CONSTRAINT fk_bb490f12fe_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE
+ )
+ PARTITION BY LIST (partition_id);
+
+ CREATE INDEX index_ci_runner_machine_builds_on_runner_machine_id ON #{PARENT_TABLE_NAME} USING btree (runner_machine_id);
+ SQL
+ end
+
+ def down
+ drop_table PARENT_TABLE_NAME
+ end
+end
diff --git a/db/migrate/20230215124011_add_provisioned_by_group_at_to_user_details.rb b/db/migrate/20230215124011_add_provisioned_by_group_at_to_user_details.rb
new file mode 100644
index 00000000000..3ff1cf6c6d4
--- /dev/null
+++ b/db/migrate/20230215124011_add_provisioned_by_group_at_to_user_details.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddProvisionedByGroupAtToUserDetails < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :user_details, :provisioned_by_group_at, :datetime_with_timezone
+ end
+end
diff --git a/db/migrate/20230215131026_add_has_failures_column_to_bulk_imports.rb b/db/migrate/20230215131026_add_has_failures_column_to_bulk_imports.rb
new file mode 100644
index 00000000000..52517244f3e
--- /dev/null
+++ b/db/migrate/20230215131026_add_has_failures_column_to_bulk_imports.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddHasFailuresColumnToBulkImports < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :bulk_imports, :has_failures, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20230215180605_index_sbom_occurrences_on_project_id_and_id.rb b/db/migrate/20230215180605_index_sbom_occurrences_on_project_id_and_id.rb
new file mode 100644
index 00000000000..34538a1a7ff
--- /dev/null
+++ b/db/migrate/20230215180605_index_sbom_occurrences_on_project_id_and_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class IndexSbomOccurrencesOnProjectIdAndId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_sbom_occurrences_on_project_id_and_id'
+
+ def up
+ add_concurrent_index :sbom_occurrences, [:project_id, :id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :sbom_occurrences, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230216040505_add_status_and_resolved_at_to_abuse_reports.rb b/db/migrate/20230216040505_add_status_and_resolved_at_to_abuse_reports.rb
new file mode 100644
index 00000000000..3cfd082b465
--- /dev/null
+++ b/db/migrate/20230216040505_add_status_and_resolved_at_to_abuse_reports.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+class AddStatusAndResolvedAtToAbuseReports < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :abuse_reports, :status, :integer, limit: 2, default: 1, null: false
+ add_timestamps_with_timezone(:abuse_reports, columns: [:resolved_at], null: true)
+ end
+end
diff --git a/db/migrate/20230216071312_add_status_category_and_id_index_to_abuse_reports.rb b/db/migrate/20230216071312_add_status_category_and_id_index_to_abuse_reports.rb
new file mode 100644
index 00000000000..0c529f15b1b
--- /dev/null
+++ b/db/migrate/20230216071312_add_status_category_and_id_index_to_abuse_reports.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddStatusCategoryAndIdIndexToAbuseReports < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_abuse_reports_on_status_category_and_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :abuse_reports, [:status, :category, :id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :abuse_reports, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230216142836_update_vulnerability_reads_trigger_to_set_has_issue.rb b/db/migrate/20230216142836_update_vulnerability_reads_trigger_to_set_has_issue.rb
new file mode 100644
index 00000000000..73afa176b97
--- /dev/null
+++ b/db/migrate/20230216142836_update_vulnerability_reads_trigger_to_set_has_issue.rb
@@ -0,0 +1,185 @@
+# frozen_string_literal: true
+
+class UpdateVulnerabilityReadsTriggerToSetHasIssue < 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;
+ 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
+
+ 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;
+ 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;
+
+ 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)
+ 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))
+ 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;
+ 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;
+
+ 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)
+ 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)
+ ON CONFLICT(vulnerability_id) DO NOTHING;
+ RETURN NULL;
+ END
+ $$;
+ SQL
+ end
+end
diff --git a/db/migrate/20230216144719_drop_table_airflow_dags.rb b/db/migrate/20230216144719_drop_table_airflow_dags.rb
new file mode 100644
index 00000000000..ed80ca16703
--- /dev/null
+++ b/db/migrate/20230216144719_drop_table_airflow_dags.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class DropTableAirflowDags < Gitlab::Database::Migration[2.1]
+ def up
+ # the table is not in use
+ drop_table :airflow_dags, if_exists: true # rubocop: disable Migration/DropTable
+ end
+
+ def down
+ create_table :airflow_dags do |t|
+ t.references :project, index: true, foreign_key: { on_delete: :cascade }, null: false
+ t.timestamps_with_timezone null: false
+ t.datetime_with_timezone :next_run
+ t.boolean :has_import_errors
+ t.boolean :is_active
+ t.boolean :is_paused
+ t.text :dag_name, null: false, limit: 255
+ t.text :schedule, limit: 255
+ t.text :fileloc, limit: 255
+ end
+ end
+end
diff --git a/db/migrate/20230216152912_add_has_failures_column_to_bulk_import_entities.rb b/db/migrate/20230216152912_add_has_failures_column_to_bulk_import_entities.rb
new file mode 100644
index 00000000000..4c48acd9dce
--- /dev/null
+++ b/db/migrate/20230216152912_add_has_failures_column_to_bulk_import_entities.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddHasFailuresColumnToBulkImportEntities < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :bulk_import_entities, :has_failures, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20230216171309_create_ci_runner_cost_settings.rb b/db/migrate/20230216171309_create_ci_runner_cost_settings.rb
new file mode 100644
index 00000000000..5bc624c635a
--- /dev/null
+++ b/db/migrate/20230216171309_create_ci_runner_cost_settings.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class CreateCiRunnerCostSettings < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ create_table :ci_cost_settings, id: false do |t|
+ t.timestamps_with_timezone null: false
+ t.references :runner, null: false, primary_key: true, index: false,
+ foreign_key: { to_table: :ci_runners, on_delete: :cascade },
+ type: :bigint, default: nil
+ t.float :standard_factor, null: false, default: 1.00
+ t.float :os_contribution_factor, null: false, default: 0.008
+ t.float :os_plan_factor, null: false, default: 0.5
+ end
+ end
+end
diff --git a/db/migrate/20230217065736_add_projects_api_rate_limit_unauthenticated_to_application_settings.rb b/db/migrate/20230217065736_add_projects_api_rate_limit_unauthenticated_to_application_settings.rb
new file mode 100644
index 00000000000..f11560c33e9
--- /dev/null
+++ b/db/migrate/20230217065736_add_projects_api_rate_limit_unauthenticated_to_application_settings.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddProjectsApiRateLimitUnauthenticatedToApplicationSettings < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :application_settings, :projects_api_rate_limit_unauthenticated, :integer, default: 400, null: false
+ end
+end
diff --git a/db/migrate/20230217144421_add_check_type_to_pre_scan_step.rb b/db/migrate/20230217144421_add_check_type_to_pre_scan_step.rb
new file mode 100644
index 00000000000..e4b59c28d73
--- /dev/null
+++ b/db/migrate/20230217144421_add_check_type_to_pre_scan_step.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddCheckTypeToPreScanStep < Gitlab::Database::Migration[2.1]
+ def up
+ add_column :dast_pre_scan_verification_steps, :check_type, :integer, limit: 2, default: 0, null: false
+ end
+
+ def down
+ remove_column :dast_pre_scan_verification_steps, :check_type
+ end
+end
diff --git a/db/migrate/20230217232554_add_state_changed_in_to_vulnerability_state_transitions.rb b/db/migrate/20230217232554_add_state_changed_in_to_vulnerability_state_transitions.rb
new file mode 100644
index 00000000000..6a8b3b87e21
--- /dev/null
+++ b/db/migrate/20230217232554_add_state_changed_in_to_vulnerability_state_transitions.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddStateChangedInToVulnerabilityStateTransitions < Gitlab::Database::Migration[2.1]
+ def up
+ add_column :vulnerability_state_transitions, :state_changed_at_pipeline_id, :bigint
+ end
+
+ def down
+ remove_column :vulnerability_state_transitions, :state_changed_at_pipeline_id
+ end
+end
diff --git a/db/migrate/20230220035034_add_status_and_id_index_to_abuse_reports.rb b/db/migrate/20230220035034_add_status_and_id_index_to_abuse_reports.rb
new file mode 100644
index 00000000000..cea01572e37
--- /dev/null
+++ b/db/migrate/20230220035034_add_status_and_id_index_to_abuse_reports.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddStatusAndIdIndexToAbuseReports < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_abuse_reports_on_status_and_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :abuse_reports, [:status, :id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :abuse_reports, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230220163141_create_catalog_resources_table.rb b/db/migrate/20230220163141_create_catalog_resources_table.rb
new file mode 100644
index 00000000000..9a60a68415a
--- /dev/null
+++ b/db/migrate/20230220163141_create_catalog_resources_table.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class CreateCatalogResourcesTable < Gitlab::Database::Migration[2.1]
+ def change
+ create_table :catalog_resources do |t|
+ t.references :project, index: true, null: false, foreign_key: { on_delete: :cascade }
+
+ t.datetime_with_timezone :created_at, null: false
+ end
+ end
+end
diff --git a/db/migrate/20230221110256_create_initial_partition_for_ci_runner_machine_builds.rb b/db/migrate/20230221110256_create_initial_partition_for_ci_runner_machine_builds.rb
new file mode 100644
index 00000000000..9aa7049dde1
--- /dev/null
+++ b/db/migrate/20230221110256_create_initial_partition_for_ci_runner_machine_builds.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class CreateInitialPartitionForCiRunnerMachineBuilds < Gitlab::Database::Migration[2.1]
+ PARTITION_NAME = 'gitlab_partitions_dynamic.ci_runner_machine_builds_100'
+ TABLE_NAME = 'p_ci_runner_machine_builds'
+ FIRST_PARTITION = 100
+ BUILDS_TABLE = 'ci_builds'
+
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries(**lock_args) do
+ connection.execute(<<~SQL)
+ LOCK TABLE #{BUILDS_TABLE} IN SHARE UPDATE EXCLUSIVE MODE;
+ LOCK TABLE ONLY #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE;
+ SQL
+
+ connection.execute(<<~SQL)
+ CREATE TABLE IF NOT EXISTS #{PARTITION_NAME}
+ PARTITION OF #{TABLE_NAME}
+ FOR VALUES IN (#{FIRST_PARTITION});
+ SQL
+ end
+ end
+
+ def down
+ # no-op
+ #
+ # The migration should not remove the partition table since it might
+ # have been created by 20230215074223_add_ci_runner_machine_builds_partitioned_table.rb.
+ # In that case, the rollback would result in a different state.
+ end
+
+ private
+
+ def lock_args
+ {
+ raise_on_exhaustion: true,
+ timing_configuration: lock_timing_configuration
+ }
+ end
+
+ def lock_timing_configuration
+ iterations = Gitlab::Database::WithLockRetries::DEFAULT_TIMING_CONFIGURATION
+ aggressive_iterations = Array.new(5) { [10.seconds, 1.minute] }
+
+ iterations + aggressive_iterations
+ end
+end
diff --git a/db/migrate/20230222153048_add_registry_size_estimated_to_namespace_root_storage_statistics.rb b/db/migrate/20230222153048_add_registry_size_estimated_to_namespace_root_storage_statistics.rb
new file mode 100644
index 00000000000..50fcf6fd113
--- /dev/null
+++ b/db/migrate/20230222153048_add_registry_size_estimated_to_namespace_root_storage_statistics.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddRegistrySizeEstimatedToNamespaceRootStorageStatistics < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_ns_root_stor_stats_on_registry_size_estimated'
+
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ add_column :namespace_root_storage_statistics, :registry_size_estimated, :boolean, default: false, null: false
+ end
+
+ add_concurrent_index :namespace_root_storage_statistics, :registry_size_estimated, name: INDEX_NAME
+ end
+
+ def down
+ with_lock_retries do
+ remove_column :namespace_root_storage_statistics, :registry_size_estimated
+ end
+ end
+end
diff --git a/db/migrate/20230222193845_change_public_projects_minutes_cost_factor_default_to_1.rb b/db/migrate/20230222193845_change_public_projects_minutes_cost_factor_default_to_1.rb
new file mode 100644
index 00000000000..c86c16f692a
--- /dev/null
+++ b/db/migrate/20230222193845_change_public_projects_minutes_cost_factor_default_to_1.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class ChangePublicProjectsMinutesCostFactorDefaultTo1 < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ change_column_default :ci_runners, :public_projects_minutes_cost_factor, from: 0.0, to: 1.0
+ end
+ end
+
+ def down
+ with_lock_retries do
+ change_column_default :ci_runners, :public_projects_minutes_cost_factor, from: 1.0, to: 0.0
+ end
+ end
+end
diff --git a/db/migrate/20230224130315_add_constraint_type_to_postgres_async_constraint_validation.rb b/db/migrate/20230224130315_add_constraint_type_to_postgres_async_constraint_validation.rb
new file mode 100644
index 00000000000..dee5810d0d1
--- /dev/null
+++ b/db/migrate/20230224130315_add_constraint_type_to_postgres_async_constraint_validation.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddConstraintTypeToPostgresAsyncConstraintValidation < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :postgres_async_foreign_key_validations, :constraint_type, :integer, null: false, default: 0, limit: 2
+ end
+end
diff --git a/db/migrate/20230224161346_add_saml_group_lock_to_application_settings.rb b/db/migrate/20230224161346_add_saml_group_lock_to_application_settings.rb
new file mode 100644
index 00000000000..003dd5c5b61
--- /dev/null
+++ b/db/migrate/20230224161346_add_saml_group_lock_to_application_settings.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddSamlGroupLockToApplicationSettings < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :application_settings, :lock_memberships_to_saml, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20230228092612_add_index_next_over_limit_check_at_asc_order_synchronously.rb b/db/migrate/20230228092612_add_index_next_over_limit_check_at_asc_order_synchronously.rb
new file mode 100644
index 00000000000..a811b67bb43
--- /dev/null
+++ b/db/migrate/20230228092612_add_index_next_over_limit_check_at_asc_order_synchronously.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexNextOverLimitCheckAtAscOrderSynchronously < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'namespace_details'
+ INDEX_NAME = 'index_next_over_limit_check_at_asc_order'
+ COLUMN = 'next_over_limit_check_at'
+
+ def up
+ add_concurrent_index TABLE_NAME, COLUMN, name: INDEX_NAME, order: { next_over_limit_check_at: 'ASC NULLS FIRST' }
+ end
+
+ def down
+ remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230228133011_add_design_description.rb b/db/migrate/20230228133011_add_design_description.rb
new file mode 100644
index 00000000000..bff9a25f2ac
--- /dev/null
+++ b/db/migrate/20230228133011_add_design_description.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddDesignDescription < Gitlab::Database::Migration[2.1]
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # text limit is added in a separate migration
+ def up
+ add_column :design_management_designs, :cached_markdown_version, :integer
+ add_column :design_management_designs, :description, :text
+ add_column :design_management_designs, :description_html, :text
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+
+ def down
+ remove_column :design_management_designs, :cached_markdown_version
+ remove_column :design_management_designs, :description
+ remove_column :design_management_designs, :description_html
+ end
+end
diff --git a/db/migrate/20230228135034_add_design_description_limit.rb b/db/migrate/20230228135034_add_design_description_limit.rb
new file mode 100644
index 00000000000..47c5f8c6ab1
--- /dev/null
+++ b/db/migrate/20230228135034_add_design_description_limit.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddDesignDescriptionLimit < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :design_management_designs, :description, 1_000_000
+ end
+
+ def down
+ remove_text_limit :design_management_designs, :description
+ end
+end
diff --git a/db/migrate/20230228142350_add_notifications_work_item_widget.rb b/db/migrate/20230228142350_add_notifications_work_item_widget.rb
new file mode 100644
index 00000000000..1bc89a6875c
--- /dev/null
+++ b/db/migrate/20230228142350_add_notifications_work_item_widget.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+class AddNotificationsWorkItemWidget < Gitlab::Database::Migration[2.1]
+ class WorkItemType < MigrationRecord
+ self.table_name = 'work_item_types'
+ end
+
+ class WidgetDefinition < MigrationRecord
+ self.table_name = 'work_item_widget_definitions'
+ end
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ WIDGET_NAME = 'Notifications'
+ WIDGET_ENUM_VALUE = 14
+ WORK_ITEM_TYPES = [
+ 'Issue',
+ 'Incident',
+ 'Test Case',
+ 'Requirement',
+ 'Task',
+ 'Objective',
+ 'Key Result'
+ ].freeze
+
+ def up
+ widgets = []
+
+ WORK_ITEM_TYPES.each do |type_name|
+ type = WorkItemType.find_by_name_and_namespace_id(type_name, nil)
+
+ unless type
+ Gitlab::AppLogger.warn("type #{type_name} is missing, not adding widget")
+
+ next
+ end
+
+ widgets << {
+ work_item_type_id: type.id,
+ name: WIDGET_NAME,
+ widget_type: WIDGET_ENUM_VALUE
+ }
+ end
+
+ return if widgets.empty?
+
+ WidgetDefinition.upsert_all(
+ widgets,
+ unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
+ )
+ end
+
+ def down
+ WidgetDefinition.where(name: WIDGET_NAME).delete_all
+ end
+end
diff --git a/db/migrate/20230228212427_add_index_user_details_on_user_id_for_enterprise_users_without_date.rb b/db/migrate/20230228212427_add_index_user_details_on_user_id_for_enterprise_users_without_date.rb
new file mode 100644
index 00000000000..198aee2201c
--- /dev/null
+++ b/db/migrate/20230228212427_add_index_user_details_on_user_id_for_enterprise_users_without_date.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddIndexUserDetailsOnUserIdForEnterpriseUsersWithoutDate < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_user_details_on_user_id_for_enterprise_users_without_date'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index(
+ :user_details, :user_id,
+ where: 'provisioned_by_group_id IS NOT NULL AND provisioned_by_group_at IS NULL',
+ name: INDEX_NAME
+ )
+ end
+
+ def down
+ remove_concurrent_index_by_name :user_details, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230228212905_add_index_user_details_on_user_id_for_enterprise_users_with_date.rb b/db/migrate/20230228212905_add_index_user_details_on_user_id_for_enterprise_users_with_date.rb
new file mode 100644
index 00000000000..e57d4fc4261
--- /dev/null
+++ b/db/migrate/20230228212905_add_index_user_details_on_user_id_for_enterprise_users_with_date.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddIndexUserDetailsOnUserIdForEnterpriseUsersWithDate < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_user_details_on_user_id_for_enterprise_users_with_date'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index(
+ :user_details, :user_id,
+ where: 'provisioned_by_group_id IS NOT NULL AND provisioned_by_group_at IS NOT NULL',
+ name: INDEX_NAME
+ )
+ end
+
+ def down
+ remove_concurrent_index_by_name :user_details, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230303144424_unique_index_on_catalog_resources_project.rb b/db/migrate/20230303144424_unique_index_on_catalog_resources_project.rb
new file mode 100644
index 00000000000..6ac2e72616a
--- /dev/null
+++ b/db/migrate/20230303144424_unique_index_on_catalog_resources_project.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class UniqueIndexOnCatalogResourcesProject < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_catalog_resources_on_project_id'
+
+ def up
+ remove_concurrent_index :catalog_resources, :project_id, name: INDEX_NAME
+ add_concurrent_index :catalog_resources, :project_id, unique: true, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index :catalog_resources, :project_id, name: INDEX_NAME
+ add_concurrent_index :catalog_resources, :project_id, name: INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230306145230_add_product_analytics_data_collector_host_to_application_settings.rb b/db/migrate/20230306145230_add_product_analytics_data_collector_host_to_application_settings.rb
new file mode 100644
index 00000000000..4ae2479b1e6
--- /dev/null
+++ b/db/migrate/20230306145230_add_product_analytics_data_collector_host_to_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddProductAnalyticsDataCollectorHostToApplicationSettings < Gitlab::Database::Migration[2.1]
+ # rubocop:disable Migration/AddLimitToTextColumns
+ def change
+ add_column :application_settings, :product_analytics_data_collector_host, :text
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20230307091216_add_status_reporter_id_and_id_index_to_abuse_reports.rb b/db/migrate/20230307091216_add_status_reporter_id_and_id_index_to_abuse_reports.rb
new file mode 100644
index 00000000000..cfd077368c8
--- /dev/null
+++ b/db/migrate/20230307091216_add_status_reporter_id_and_id_index_to_abuse_reports.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddStatusReporterIdAndIdIndexToAbuseReports < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_abuse_reports_on_status_reporter_id_and_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :abuse_reports, [:status, :reporter_id, :id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :abuse_reports, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230307122838_add_text_limit_to_application_settings_product_analytics_data_collector_host.rb b/db/migrate/20230307122838_add_text_limit_to_application_settings_product_analytics_data_collector_host.rb
new file mode 100644
index 00000000000..4f87cc9aee0
--- /dev/null
+++ b/db/migrate/20230307122838_add_text_limit_to_application_settings_product_analytics_data_collector_host.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddTextLimitToApplicationSettingsProductAnalyticsDataCollectorHost < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :application_settings, :product_analytics_data_collector_host, 255
+ end
+
+ def down
+ remove_text_limit :application_settings, :product_analytics_data_collector_host
+ end
+end
diff --git a/db/migrate/20230307233631_add_public_runner_release_version_fetch_setting.rb b/db/migrate/20230307233631_add_public_runner_release_version_fetch_setting.rb
new file mode 100644
index 00000000000..584774d58ad
--- /dev/null
+++ b/db/migrate/20230307233631_add_public_runner_release_version_fetch_setting.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class AddPublicRunnerReleaseVersionFetchSetting < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ add_column :application_settings, :update_runner_versions_enabled, :boolean,
+ default: true, null: false, if_not_exists: true
+ end
+
+ def down
+ remove_column :application_settings, :update_runner_versions_enabled, if_exists: true
+ end
+end
diff --git a/db/migrate/20230308163018_create_container_registry_data_repair_details.rb b/db/migrate/20230308163018_create_container_registry_data_repair_details.rb
new file mode 100644
index 00000000000..b682eb6ee7e
--- /dev/null
+++ b/db/migrate/20230308163018_create_container_registry_data_repair_details.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class CreateContainerRegistryDataRepairDetails < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ create_table :container_registry_data_repair_details, id: false do |t|
+ t.integer :missing_count, default: 0
+ t.references :project,
+ primary_key: true,
+ default: nil,
+ index: false,
+ foreign_key: { to_table: :projects, on_delete: :cascade }
+ t.timestamps_with_timezone null: false
+ end
+ end
+end
diff --git a/db/migrate/20230309000957_add_external_identifiers_to_import_failures.rb b/db/migrate/20230309000957_add_external_identifiers_to_import_failures.rb
new file mode 100644
index 00000000000..f95cf0035d4
--- /dev/null
+++ b/db/migrate/20230309000957_add_external_identifiers_to_import_failures.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddExternalIdentifiersToImportFailures < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :import_failures, :external_identifiers, :jsonb, default: {}, null: false
+ end
+end
diff --git a/db/migrate/20230313054226_add_status_created_at_and_updated_at_indexes_to_abuse_reports.rb b/db/migrate/20230313054226_add_status_created_at_and_updated_at_indexes_to_abuse_reports.rb
new file mode 100644
index 00000000000..b619d6b8732
--- /dev/null
+++ b/db/migrate/20230313054226_add_status_created_at_and_updated_at_indexes_to_abuse_reports.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddStatusCreatedAtAndUpdatedAtIndexesToAbuseReports < Gitlab::Database::Migration[2.1]
+ STATUS_AND_CREATED_AT_INDEX = 'index_abuse_reports_on_status_and_created_at'
+ STATUS_AND_UPDATED_AT_INDEX = 'index_abuse_reports_on_status_and_updated_at'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :abuse_reports, [:status, :created_at], name: STATUS_AND_CREATED_AT_INDEX
+ add_concurrent_index :abuse_reports, [:status, :updated_at], name: STATUS_AND_UPDATED_AT_INDEX
+ end
+
+ def down
+ remove_concurrent_index_by_name :abuse_reports, STATUS_AND_CREATED_AT_INDEX
+ remove_concurrent_index_by_name :abuse_reports, STATUS_AND_UPDATED_AT_INDEX
+ end
+end
diff --git a/db/migrate/20230313100920_add_gitlab_dedicated_instance_to_application_settings.rb b/db/migrate/20230313100920_add_gitlab_dedicated_instance_to_application_settings.rb
new file mode 100644
index 00000000000..ce83c022661
--- /dev/null
+++ b/db/migrate/20230313100920_add_gitlab_dedicated_instance_to_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddGitlabDedicatedInstanceToApplicationSettings < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :application_settings, :gitlab_dedicated_instance, :boolean, default: false, null: false
+ end
+end
diff --git a/db/post_migrate/20230113201308_backfill_namespace_ldap_settings.rb b/db/post_migrate/20230113201308_backfill_namespace_ldap_settings.rb
new file mode 100644
index 00000000000..19020fecad5
--- /dev/null
+++ b/db/post_migrate/20230113201308_backfill_namespace_ldap_settings.rb
@@ -0,0 +1,33 @@
+# 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 BackfillNamespaceLdapSettings < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ DOWNTIME = false
+ MIGRATION = 'BackfillNamespaceLdapSettings'
+ TABLE_NAME = 'namespaces'
+ PRIMARY_KEY = :id
+ INTERVAL = 2.minutes
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ TABLE_NAME,
+ PRIMARY_KEY,
+ job_interval: INTERVAL
+ )
+ end
+
+ def down
+ delete_batched_background_migration(
+ MIGRATION,
+ TABLE_NAME,
+ PRIMARY_KEY,
+ []
+ )
+ end
+end
diff --git a/db/post_migrate/20230118144623_schedule_migration_for_remediation.rb b/db/post_migrate/20230118144623_schedule_migration_for_remediation.rb
new file mode 100644
index 00000000000..ed95ecfaad3
--- /dev/null
+++ b/db/post_migrate/20230118144623_schedule_migration_for_remediation.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class ScheduleMigrationForRemediation < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'MigrateRemediationsForVulnerabilityFindings'
+ DELAY_INTERVAL = 2.minutes
+ SUB_BATCH_SIZE = 500
+ BATCH_SIZE = 5000
+
+ def up
+ # no-op as described in https://docs.gitlab.com/ee/development/database/batched_background_migrations.html
+ end
+
+ def down
+ # no-op as described in https://docs.gitlab.com/ee/development/database/batched_background_migrations.html
+ end
+end
diff --git a/db/post_migrate/20230125195503_queue_backfill_compliance_violations.rb b/db/post_migrate/20230125195503_queue_backfill_compliance_violations.rb
new file mode 100644
index 00000000000..5f797421bd5
--- /dev/null
+++ b/db/post_migrate/20230125195503_queue_backfill_compliance_violations.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class QueueBackfillComplianceViolations < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'BackfillComplianceViolations'
+ INTERVAL = 2.minutes
+ BATCH_SIZE = 10_000
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :merge_requests_compliance_violations,
+ :id,
+ job_interval: INTERVAL,
+ batch_size: BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :merge_requests_compliance_violations, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230126101907_add_partition_index_to_web_hook_logs.rb b/db/post_migrate/20230126101907_add_partition_index_to_web_hook_logs.rb
new file mode 100644
index 00000000000..4196767033c
--- /dev/null
+++ b/db/post_migrate/20230126101907_add_partition_index_to_web_hook_logs.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddPartitionIndexToWebHookLogs < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_web_hook_logs_on_web_hook_id_and_created_at'
+
+ def up
+ add_concurrent_partitioned_index(
+ :web_hook_logs,
+ [:web_hook_id, :created_at],
+ name: INDEX_NAME
+ )
+ end
+
+ def down
+ remove_concurrent_partitioned_index_by_name :web_hook_logs, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230130182412_schedule_create_vulnerability_links_migration.rb b/db/post_migrate/20230130182412_schedule_create_vulnerability_links_migration.rb
new file mode 100644
index 00000000000..a1162ce98d5
--- /dev/null
+++ b/db/post_migrate/20230130182412_schedule_create_vulnerability_links_migration.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class ScheduleCreateVulnerabilityLinksMigration < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'CreateVulnerabilityLinks'
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 250
+ SUB_BATCH_SIZE = 5
+
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :vulnerability_feedback,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :vulnerability_feedback, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230131184319_update_billable_users_index_for_service_accounts.rb b/db/post_migrate/20230131184319_update_billable_users_index_for_service_accounts.rb
new file mode 100644
index 00000000000..e86a2476156
--- /dev/null
+++ b/db/post_migrate/20230131184319_update_billable_users_index_for_service_accounts.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class UpdateBillableUsersIndexForServiceAccounts < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ OLD_INDEX = 'index_users_for_billable_users'
+ NEW_INDEX = 'index_users_for_active_billable_users'
+
+ OLD_INDEX_CONDITION = <<~QUERY
+ ((state)::text = 'active'::text) AND ((user_type IS NULL)
+ OR (user_type = ANY (ARRAY[6, 4]))) AND
+ ((user_type IS NULL) OR (user_type = ANY (ARRAY[4, 5])))
+ QUERY
+ NEW_INDEX_CONDITION = <<~QUERY
+ state = 'active' AND (user_type IS NULL OR user_type IN (6, 4, 13)) AND (user_type IS NULL OR user_type IN (4, 5))
+ QUERY
+
+ def up
+ add_concurrent_index(:users, :id, where: NEW_INDEX_CONDITION, name: NEW_INDEX)
+ remove_concurrent_index_by_name(:users, OLD_INDEX)
+ end
+
+ def down
+ add_concurrent_index(:users, :id, where: OLD_INDEX_CONDITION, name: OLD_INDEX)
+ remove_concurrent_index_by_name(:users, NEW_INDEX)
+ end
+end
diff --git a/db/post_migrate/20230202135758_queue_backfill_prepared_at_data.rb b/db/post_migrate/20230202135758_queue_backfill_prepared_at_data.rb
new file mode 100644
index 00000000000..227b469b625
--- /dev/null
+++ b/db/post_migrate/20230202135758_queue_backfill_prepared_at_data.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class QueueBackfillPreparedAtData < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'BackfillPreparedAtMergeRequests'
+ DELAY_INTERVAL = 2.minutes
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :merge_requests,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: 5000,
+ sub_batch_size: 250
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :merge_requests, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230202211434_migrate_redis_slot_keys.rb b/db/post_migrate/20230202211434_migrate_redis_slot_keys.rb
new file mode 100644
index 00000000000..e1d3787cbb3
--- /dev/null
+++ b/db/post_migrate/20230202211434_migrate_redis_slot_keys.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+class MigrateRedisSlotKeys < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ BackupHLLRedisCounter.known_events.each do |event|
+ if event[:aggregation].to_sym == :daily
+ migrate_daily_aggregated(event)
+ else
+ migrate_weekly_aggregated(event)
+ end
+ end
+ end
+
+ def down
+ # no-op
+ end
+
+ private
+
+ def migrate_daily_aggregated(event)
+ days_back = BackupHLLRedisCounter::DEFAULT_DAILY_KEY_EXPIRY_LENGTH
+ start_date = Date.today - days_back - 1.day
+ end_date = Date.today + 1.day
+
+ (start_date..end_date).each do |date|
+ rename_key(event, date)
+ end
+ end
+
+ def migrate_weekly_aggregated(event)
+ weeks_back = BackupHLLRedisCounter::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH
+ start_date = (Date.today - weeks_back).beginning_of_week - 1.day
+ end_date = Date.today.end_of_week + 1.day
+
+ (start_date..end_date).each { |date| rename_key(event, date) }
+ end
+
+ def rename_key(event, date)
+ old_key = old_redis_key(event, date)
+ new_key = BackupHLLRedisCounter.redis_key(event, date)
+
+ # cannot simply rename due to different slots
+ Gitlab::Redis::SharedState.with do |r|
+ break unless r.exists?(old_key)
+
+ Gitlab::Redis::HLL.add(
+ key: new_key,
+ value: r.pfcount(old_key),
+ expiry: r.ttl(old_key)
+ )
+ end
+ end
+
+ def old_redis_key(event, time)
+ name_with_slot = if event[:redis_slot].present?
+ event[:name].to_s.gsub(event[:redis_slot], "{#{event[:redis_slot]}}")
+ else
+ "{#{event[:name]}}"
+ end
+
+ BackupHLLRedisCounter.apply_time_aggregation(name_with_slot, time, event)
+ end
+
+ # :nocov: Existing backed up class # rubocop:disable Gitlab/NoCodeCoverageComment
+ module BackupHLLRedisCounter
+ DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH = 6.weeks
+ DEFAULT_DAILY_KEY_EXPIRY_LENGTH = 29.days
+ REDIS_SLOT = 'hll_counters'
+
+ KNOWN_EVENTS_PATH = File.expand_path('known_events/*.yml', __dir__)
+ ALLOWED_AGGREGATIONS = %i[daily weekly].freeze
+
+ class << self
+ def known_events
+ @known_events ||= load_events(KNOWN_EVENTS_PATH)
+ end
+
+ def load_events(wildcard)
+ Dir[wildcard].each_with_object([]) do |path, events|
+ events.push(*load_yaml_from_path(path))
+ end
+ end
+
+ def load_yaml_from_path(path)
+ YAML.safe_load(File.read(path))&.map(&:with_indifferent_access)
+ end
+
+ def known_events_names
+ known_events.map { |event| event[:name] } # rubocop:disable Rails/Pluck
+ end
+
+ def redis_key(event, time, context = '')
+ key = "{#{REDIS_SLOT}}_#{event[:name]}"
+ key = apply_time_aggregation(key, time, event)
+ key = "#{context}_#{key}" if context.present?
+ key
+ end
+
+ def apply_time_aggregation(key, time, event)
+ if event[:aggregation].to_sym == :daily
+ year_day = time.strftime('%G-%j')
+ "#{year_day}-#{key}"
+ else
+ year_week = time.strftime('%G-%V')
+ "#{key}-#{year_week}"
+ end
+ end
+ end
+ end
+ # :nocov: # rubocop:disable Gitlab/NoCodeCoverageComment
+end
diff --git a/db/post_migrate/20230208125736_schedule_migration_for_links.rb b/db/post_migrate/20230208125736_schedule_migration_for_links.rb
new file mode 100644
index 00000000000..c1bd1bbbe51
--- /dev/null
+++ b/db/post_migrate/20230208125736_schedule_migration_for_links.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class ScheduleMigrationForLinks < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'MigrateLinksForVulnerabilityFindings'
+ DELAY_INTERVAL = 2.minutes
+ SUB_BATCH_SIZE = 500
+ BATCH_SIZE = 10000
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :vulnerability_occurrences,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230213103019_add_index_for_next_over_limit_check_at.rb b/db/post_migrate/20230213103019_add_index_for_next_over_limit_check_at.rb
new file mode 100644
index 00000000000..29c59cea3ff
--- /dev/null
+++ b/db/post_migrate/20230213103019_add_index_for_next_over_limit_check_at.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexForNextOverLimitCheckAt < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = 'namespace_details'
+ INDEX_NAME = 'index_next_over_limit_check_at_asc_order'
+
+ def up
+ prepare_async_index TABLE_NAME,
+ :next_over_limit_check_at,
+ order: { next_over_limit_check_at: 'ASC NULLS FIRST' },
+ name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index TABLE_NAME, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230214181633_finalize_ci_build_needs_big_int_conversion.rb b/db/post_migrate/20230214181633_finalize_ci_build_needs_big_int_conversion.rb
new file mode 100644
index 00000000000..63b6148df6b
--- /dev/null
+++ b/db/post_migrate/20230214181633_finalize_ci_build_needs_big_int_conversion.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class FinalizeCiBuildNeedsBigIntConversion < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ TABLE_NAME = 'ci_build_needs'
+
+ def up
+ return unless should_run?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: TABLE_NAME,
+ column_name: 'id',
+ job_arguments: [['id'], ['id_convert_to_bigint']]
+ )
+ end
+
+ def down; end
+
+ private
+
+ def should_run?
+ !Gitlab.jh? && (Gitlab.com? || Gitlab.dev_or_test_env?)
+ end
+end
diff --git a/db/post_migrate/20230215213349_add_sync_index_on_packages_package_file_filename.rb b/db/post_migrate/20230215213349_add_sync_index_on_packages_package_file_filename.rb
new file mode 100644
index 00000000000..9a2e7abbbc1
--- /dev/null
+++ b/db/post_migrate/20230215213349_add_sync_index_on_packages_package_file_filename.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddSyncIndexOnPackagesPackageFileFilename < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_packages_package_files_on_file_name'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index(
+ :packages_package_files,
+ :file_name,
+ name: INDEX_NAME,
+ using: :gin,
+ opclass: { description: :gin_trgm_ops }
+ )
+ end
+
+ def down
+ remove_concurrent_index_by_name :packages_package_files, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230216060333_prepare_async_foreign_key_validation_for_ci_build_trace_metadata.rb b/db/post_migrate/20230216060333_prepare_async_foreign_key_validation_for_ci_build_trace_metadata.rb
new file mode 100644
index 00000000000..1d5999acc61
--- /dev/null
+++ b/db/post_migrate/20230216060333_prepare_async_foreign_key_validation_for_ci_build_trace_metadata.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class PrepareAsyncForeignKeyValidationForCiBuildTraceMetadata < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_build_trace_metadata
+ COLUMN_NAMES = [:partition_id, :build_id]
+ FOREIGN_KEY_NAME = :fk_rails_aebc78111f_p
+
+ def up
+ prepare_async_foreign_key_validation(TABLE_NAME, COLUMN_NAMES, name: FOREIGN_KEY_NAME)
+ end
+
+ def down
+ unprepare_async_foreign_key_validation(TABLE_NAME, COLUMN_NAMES, name: FOREIGN_KEY_NAME)
+ end
+end
diff --git a/db/post_migrate/20230216191507_delete_incorrectly_onboarded_namespaces.rb b/db/post_migrate/20230216191507_delete_incorrectly_onboarded_namespaces.rb
new file mode 100644
index 00000000000..5da485fd442
--- /dev/null
+++ b/db/post_migrate/20230216191507_delete_incorrectly_onboarded_namespaces.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class DeleteIncorrectlyOnboardedNamespaces < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ # Changed to a no-op, this migration was reverted after
+ # an incident during a deploy to production on gitlab.com
+ # https://gitlab.com/gitlab-com/gl-infra/production/-/issues/8436
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230216222956_add_sync_index_on_lfs_objects_file.rb b/db/post_migrate/20230216222956_add_sync_index_on_lfs_objects_file.rb
new file mode 100644
index 00000000000..8eda3345713
--- /dev/null
+++ b/db/post_migrate/20230216222956_add_sync_index_on_lfs_objects_file.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddSyncIndexOnLfsObjectsFile < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_lfs_objects_on_file'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :lfs_objects, :file, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :lfs_objects, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230216232404_add_sync_index_on_merge_request_diffs_external_diff.rb b/db/post_migrate/20230216232404_add_sync_index_on_merge_request_diffs_external_diff.rb
new file mode 100644
index 00000000000..2f9b12f89c1
--- /dev/null
+++ b/db/post_migrate/20230216232404_add_sync_index_on_merge_request_diffs_external_diff.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddSyncIndexOnMergeRequestDiffsExternalDiff < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_merge_request_diffs_on_external_diff'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :merge_request_diffs, :external_diff, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :merge_request_diffs, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230216233937_remove_application_settings_send_user_confirmation_email_column.rb b/db/post_migrate/20230216233937_remove_application_settings_send_user_confirmation_email_column.rb
new file mode 100644
index 00000000000..d7720ebccbd
--- /dev/null
+++ b/db/post_migrate/20230216233937_remove_application_settings_send_user_confirmation_email_column.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class RemoveApplicationSettingsSendUserConfirmationEmailColumn < Gitlab::Database::Migration[2.1]
+ def change
+ remove_column :application_settings, :send_user_confirmation_email, :boolean, default: false
+ end
+end
diff --git a/db/post_migrate/20230218145930_add_index_users_on_updated_at.rb b/db/post_migrate/20230218145930_add_index_users_on_updated_at.rb
new file mode 100644
index 00000000000..229c3e1babd
--- /dev/null
+++ b/db/post_migrate/20230218145930_add_index_users_on_updated_at.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddIndexUsersOnUpdatedAt < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = 'users'
+ INDEX_NAME = 'index_users_on_updated_at'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index TABLE_NAME, :updated_at, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230218145940_add_index_namespaces_on_updated_at.rb b/db/post_migrate/20230218145940_add_index_namespaces_on_updated_at.rb
new file mode 100644
index 00000000000..cbad26fb142
--- /dev/null
+++ b/db/post_migrate/20230218145940_add_index_namespaces_on_updated_at.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddIndexNamespacesOnUpdatedAt < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = 'namespaces'
+ INDEX_NAME = 'index_namespaces_on_updated_at'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index TABLE_NAME, :updated_at, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230218152729_validate_fk_on_ci_job_artifacts_partition_id_and_job_id.rb b/db/post_migrate/20230218152729_validate_fk_on_ci_job_artifacts_partition_id_and_job_id.rb
new file mode 100644
index 00000000000..9a9cb0d9487
--- /dev/null
+++ b/db/post_migrate/20230218152729_validate_fk_on_ci_job_artifacts_partition_id_and_job_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ValidateFkOnCiJobArtifactsPartitionIdAndJobId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_job_artifacts
+ FK_NAME = :fk_rails_c5137cb2c1_p
+ COLUMNS = [:partition_id, :job_id]
+
+ def up
+ validate_foreign_key(TABLE_NAME, COLUMNS, name: FK_NAME)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230218152730_remove_fk_to_ci_builds_ci_job_artifacts_on_job_id.rb b/db/post_migrate/20230218152730_remove_fk_to_ci_builds_ci_job_artifacts_on_job_id.rb
new file mode 100644
index 00000000000..02747d57eab
--- /dev/null
+++ b/db/post_migrate/20230218152730_remove_fk_to_ci_builds_ci_job_artifacts_on_job_id.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildsCiJobArtifactsOnJobId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :ci_job_artifacts
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :job_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_rails_c5137cb2c1
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: COLUMN,
+ target_column: TARGET_COLUMN,
+ validate: true,
+ reverse_lock_order: true,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230219191034_add_pipeline_fk_to_vulnerability_state_transitions.rb b/db/post_migrate/20230219191034_add_pipeline_fk_to_vulnerability_state_transitions.rb
new file mode 100644
index 00000000000..5c09c75861a
--- /dev/null
+++ b/db/post_migrate/20230219191034_add_pipeline_fk_to_vulnerability_state_transitions.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddPipelineFkToVulnerabilityStateTransitions < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_vulnerability_state_transitions_on_pipeline_id'
+
+ def up
+ add_concurrent_index :vulnerability_state_transitions, :state_changed_at_pipeline_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerability_state_transitions, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230220102212_swap_columns_ci_build_needs_big_int_conversion.rb b/db/post_migrate/20230220102212_swap_columns_ci_build_needs_big_int_conversion.rb
new file mode 100644
index 00000000000..de98847fad4
--- /dev/null
+++ b/db/post_migrate/20230220102212_swap_columns_ci_build_needs_big_int_conversion.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+class SwapColumnsCiBuildNeedsBigIntConversion < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'ci_build_needs'
+
+ def up
+ return unless should_run?
+
+ swap
+ end
+
+ def down
+ return unless should_run?
+
+ swap
+ end
+
+ private
+
+ def should_run?
+ !Gitlab.jh? && (Gitlab.com? || Gitlab.dev_or_test_env?)
+ end
+
+ def swap
+ add_concurrent_index TABLE_NAME, :id_convert_to_bigint, unique: true, name:
+ 'index_ci_build_needs_on_id_convert_to_bigint'
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ id_name = quote_column_name(:id)
+ temp_name = quote_column_name('id_tmp')
+ id_convert_to_bigint_name = quote_column_name(:id_convert_to_bigint)
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{id_name} TO #{temp_name}"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{id_convert_to_bigint_name} TO #{id_name}"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{temp_name} TO #{id_convert_to_bigint_name}"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger.on_table(
+ TABLE_NAME, connection: Ci::ApplicationRecord.connection
+ ).name(
+ :id, :id_convert_to_bigint
+ )
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ execute "ALTER SEQUENCE ci_build_needs_id_seq OWNED BY #{TABLE_NAME}.id"
+ change_column_default TABLE_NAME, :id, -> { "nextval('ci_build_needs_id_seq'::regclass)" }
+ change_column_default TABLE_NAME, :id_convert_to_bigint, 0
+
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT ci_build_needs_pkey CASCADE"
+ rename_index TABLE_NAME, 'index_ci_build_needs_on_id_convert_to_bigint', 'ci_build_needs_pkey'
+ execute "ALTER TABLE #{TABLE_NAME} ADD CONSTRAINT ci_build_needs_pkey PRIMARY KEY USING INDEX ci_build_needs_pkey"
+ end
+ end
+end
diff --git a/db/post_migrate/20230220112930_replace_uniq_index_on_postgres_async_foreign_key_validations.rb b/db/post_migrate/20230220112930_replace_uniq_index_on_postgres_async_foreign_key_validations.rb
new file mode 100644
index 00000000000..1adc275e1e9
--- /dev/null
+++ b/db/post_migrate/20230220112930_replace_uniq_index_on_postgres_async_foreign_key_validations.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class ReplaceUniqIndexOnPostgresAsyncForeignKeyValidations < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ NEW_INDEX_NAME = 'unique_postgres_async_fk_validations_name_and_table_name'
+ OLD_INDEX_NAME = 'index_postgres_async_foreign_key_validations_on_name'
+ TABLE_NAME = 'postgres_async_foreign_key_validations'
+
+ def up
+ add_concurrent_index TABLE_NAME, [:name, :table_name], unique: true, name: NEW_INDEX_NAME
+ remove_concurrent_index_by_name TABLE_NAME, OLD_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index TABLE_NAME, :name, unique: true, name: OLD_INDEX_NAME
+ remove_concurrent_index_by_name TABLE_NAME, NEW_INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230220132409_validate_fk_on_ci_build_report_results_partition_id_and_build_id.rb b/db/post_migrate/20230220132409_validate_fk_on_ci_build_report_results_partition_id_and_build_id.rb
new file mode 100644
index 00000000000..5186f5f397e
--- /dev/null
+++ b/db/post_migrate/20230220132409_validate_fk_on_ci_build_report_results_partition_id_and_build_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ValidateFkOnCiBuildReportResultsPartitionIdAndBuildId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_build_report_results
+ FK_NAME = :fk_rails_16cb1ff064_p
+ COLUMNS = [:partition_id, :build_id]
+
+ def up
+ validate_foreign_key(TABLE_NAME, COLUMNS, name: FK_NAME)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230220132410_remove_fk_to_ci_builds_ci_build_report_results_on_build_id.rb b/db/post_migrate/20230220132410_remove_fk_to_ci_builds_ci_build_report_results_on_build_id.rb
new file mode 100644
index 00000000000..8cbcdf27374
--- /dev/null
+++ b/db/post_migrate/20230220132410_remove_fk_to_ci_builds_ci_build_report_results_on_build_id.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildsCiBuildReportResultsOnBuildId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :ci_build_report_results
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :build_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_rails_16cb1ff064
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: COLUMN,
+ target_column: TARGET_COLUMN,
+ validate: true,
+ reverse_lock_order: true,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230220134145_validate_fk_on_ci_build_needs_partition_id_and_build_id.rb b/db/post_migrate/20230220134145_validate_fk_on_ci_build_needs_partition_id_and_build_id.rb
new file mode 100644
index 00000000000..eec60a51834
--- /dev/null
+++ b/db/post_migrate/20230220134145_validate_fk_on_ci_build_needs_partition_id_and_build_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ValidateFkOnCiBuildNeedsPartitionIdAndBuildId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_build_needs
+ FK_NAME = :fk_rails_3cf221d4ed_p
+ COLUMNS = [:partition_id, :build_id]
+
+ def up
+ validate_foreign_key(TABLE_NAME, COLUMNS, name: FK_NAME)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230220134146_remove_fk_to_ci_builds_ci_build_needs_on_build_id.rb b/db/post_migrate/20230220134146_remove_fk_to_ci_builds_ci_build_needs_on_build_id.rb
new file mode 100644
index 00000000000..04e7ec11ee6
--- /dev/null
+++ b/db/post_migrate/20230220134146_remove_fk_to_ci_builds_ci_build_needs_on_build_id.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildsCiBuildNeedsOnBuildId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :ci_build_needs
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :build_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_rails_3cf221d4ed
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: COLUMN,
+ target_column: TARGET_COLUMN,
+ validate: true,
+ reverse_lock_order: true,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230220165240_add_index_to_approval_rules_on_scan_result_policy_id.rb b/db/post_migrate/20230220165240_add_index_to_approval_rules_on_scan_result_policy_id.rb
new file mode 100644
index 00000000000..b510fdb0f86
--- /dev/null
+++ b/db/post_migrate/20230220165240_add_index_to_approval_rules_on_scan_result_policy_id.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddIndexToApprovalRulesOnScanResultPolicyId < Gitlab::Database::Migration[2.1]
+ PROJECT_INDEX_NAME = 'idx_approval_project_rules_on_scan_result_policy_id'
+ MERGE_REQUEST_INDEX_NAME = 'idx_approval_merge_request_rules_on_scan_result_policy_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :approval_project_rules, :scan_result_policy_id, name: PROJECT_INDEX_NAME
+ add_concurrent_index :approval_merge_request_rules, :scan_result_policy_id, name: MERGE_REQUEST_INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :approval_project_rules, :scan_result_policy_id, name: PROJECT_INDEX_NAME
+ remove_concurrent_index_by_name :approval_merge_request_rules, :scan_result_policy_id,
+ name: MERGE_REQUEST_INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230221010522_prepare_async_foreign_key_validation_for_ci_sources_pipelines.rb b/db/post_migrate/20230221010522_prepare_async_foreign_key_validation_for_ci_sources_pipelines.rb
new file mode 100644
index 00000000000..e25bbca5c80
--- /dev/null
+++ b/db/post_migrate/20230221010522_prepare_async_foreign_key_validation_for_ci_sources_pipelines.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class PrepareAsyncForeignKeyValidationForCiSourcesPipelines < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_sources_pipelines
+ COLUMN_NAMES = [:source_partition_id, :source_job_id]
+ FOREIGN_KEY_NAME = :fk_be5624bf37_p
+
+ def up
+ prepare_async_foreign_key_validation(TABLE_NAME, COLUMN_NAMES, name: FOREIGN_KEY_NAME)
+ end
+
+ def down
+ unprepare_async_foreign_key_validation(TABLE_NAME, COLUMN_NAMES, name: FOREIGN_KEY_NAME)
+ end
+end
diff --git a/db/post_migrate/20230221011750_prepare_async_foreign_key_validation_for_ci_job_variables.rb b/db/post_migrate/20230221011750_prepare_async_foreign_key_validation_for_ci_job_variables.rb
new file mode 100644
index 00000000000..973c4c7316d
--- /dev/null
+++ b/db/post_migrate/20230221011750_prepare_async_foreign_key_validation_for_ci_job_variables.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class PrepareAsyncForeignKeyValidationForCiJobVariables < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_job_variables
+ COLUMN_NAMES = [:partition_id, :job_id]
+ FOREIGN_KEY_NAME = :fk_rails_fbf3b34792_p
+
+ def up
+ prepare_async_foreign_key_validation(TABLE_NAME, COLUMN_NAMES, name: FOREIGN_KEY_NAME)
+ end
+
+ def down
+ unprepare_async_foreign_key_validation(TABLE_NAME, COLUMN_NAMES, name: FOREIGN_KEY_NAME)
+ end
+end
diff --git a/db/post_migrate/20230221093533_add_tmp_partial_index_on_vulnerability_report_types.rb b/db/post_migrate/20230221093533_add_tmp_partial_index_on_vulnerability_report_types.rb
new file mode 100644
index 00000000000..4800ce5ed4c
--- /dev/null
+++ b/db/post_migrate/20230221093533_add_tmp_partial_index_on_vulnerability_report_types.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddTmpPartialIndexOnVulnerabilityReportTypes < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'tmp_idx_vulnerability_occurrences_on_id_where_report_type_7_99'
+ CLAUSE = 'report_type IN (7, 99)'
+
+ def up
+ # Temporary index to be removed in 15.11 https://gitlab.com/gitlab-org/gitlab/-/issues/393052
+ prepare_async_index :vulnerability_occurrences, :id, where: CLAUSE, name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index :vulnerability_occurrences, :id, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230221125148_add_fk_to_p_ci_builds_metadata_partitions_on_partition_id_and_build_id.rb b/db/post_migrate/20230221125148_add_fk_to_p_ci_builds_metadata_partitions_on_partition_id_and_build_id.rb
new file mode 100644
index 00000000000..9df03f03d2b
--- /dev/null
+++ b/db/post_migrate/20230221125148_add_fk_to_p_ci_builds_metadata_partitions_on_partition_id_and_build_id.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+class AddFkToPCiBuildsMetadataPartitionsOnPartitionIdAndBuildId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :p_ci_builds_metadata
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :build_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_e20479742e_p
+ PARTITION_COLUMN = :partition_id
+
+ def up
+ Gitlab::Database::PostgresPartitionedTable.each_partition(SOURCE_TABLE_NAME) do |partition|
+ add_concurrent_foreign_key(
+ partition.identifier,
+ TARGET_TABLE_NAME,
+ column: [PARTITION_COLUMN, COLUMN],
+ target_column: [PARTITION_COLUMN, TARGET_COLUMN],
+ validate: false,
+ reverse_lock_order: true,
+ on_update: :cascade,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+ end
+
+ def down
+ Gitlab::Database::PostgresPartitionedTable.each_partition(SOURCE_TABLE_NAME) do |partition|
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ partition.identifier,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+ end
+end
diff --git a/db/post_migrate/20230221162222_raise_ci_variable_limits_on_gitlab_com.rb b/db/post_migrate/20230221162222_raise_ci_variable_limits_on_gitlab_com.rb
new file mode 100644
index 00000000000..084f89b2a5d
--- /dev/null
+++ b/db/post_migrate/20230221162222_raise_ci_variable_limits_on_gitlab_com.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+class RaiseCiVariableLimitsOnGitlabCom < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ create_or_update_plan_limit('project_ci_variables', 'free', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'bronze', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'silver', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'premium', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'premium_trial', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'gold', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'ultimate', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'ultimate_trial', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'early_adopter', 8000)
+ create_or_update_plan_limit('project_ci_variables', 'opensource', 8000)
+
+ create_or_update_plan_limit('group_ci_variables', 'free', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'bronze', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'silver', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'premium', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'premium_trial', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'gold', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'ultimate', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'ultimate_trial', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'early_adopter', 30000)
+ create_or_update_plan_limit('group_ci_variables', 'opensource', 30000)
+ end
+
+ def down
+ create_or_update_plan_limit('project_ci_variables', 'free', 200)
+ create_or_update_plan_limit('project_ci_variables', 'bronze', 200)
+ create_or_update_plan_limit('project_ci_variables', 'silver', 200)
+ create_or_update_plan_limit('project_ci_variables', 'premium', 200)
+ create_or_update_plan_limit('project_ci_variables', 'premium_trial', 200)
+ create_or_update_plan_limit('project_ci_variables', 'gold', 200)
+ create_or_update_plan_limit('project_ci_variables', 'ultimate', 200)
+ create_or_update_plan_limit('project_ci_variables', 'ultimate_trial', 200)
+ create_or_update_plan_limit('project_ci_variables', 'early_adopter', 200)
+ create_or_update_plan_limit('project_ci_variables', 'opensource', 200)
+
+ create_or_update_plan_limit('group_ci_variables', 'free', 200)
+ create_or_update_plan_limit('group_ci_variables', 'bronze', 200)
+ create_or_update_plan_limit('group_ci_variables', 'silver', 200)
+ create_or_update_plan_limit('group_ci_variables', 'premium', 200)
+ create_or_update_plan_limit('group_ci_variables', 'premium_trial', 200)
+ create_or_update_plan_limit('group_ci_variables', 'gold', 200)
+ create_or_update_plan_limit('group_ci_variables', 'ultimate', 200)
+ create_or_update_plan_limit('group_ci_variables', 'ultimate_trial', 200)
+ create_or_update_plan_limit('group_ci_variables', 'early_adopter', 200)
+ create_or_update_plan_limit('group_ci_variables', 'opensource', 200)
+ end
+end
diff --git a/db/post_migrate/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress.rb b/db/post_migrate/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress.rb
new file mode 100644
index 00000000000..5672fc42851
--- /dev/null
+++ b/db/post_migrate/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class RemoveIncorrectlyOnboardedNamespacesFromOnboardingProgress < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ class OnboardingProgress < MigrationRecord
+ include EachBatch
+
+ self.table_name = 'onboarding_progresses'
+ end
+
+ class Project < MigrationRecord
+ self.table_name = 'projects'
+ end
+
+ def up
+ names = ['Learn GitLab', 'Learn GitLab - Ultimate trial']
+
+ OnboardingProgress.each_batch(of: 500) do |batch|
+ namespaces_to_keep = Project.where(name: names, namespace_id: batch.select(:namespace_id)).select(:namespace_id)
+ batch.where.not(namespace_id: namespaces_to_keep).delete_all
+ end
+ end
+
+ def down
+ # no op
+ end
+end
diff --git a/db/post_migrate/20230222035805_prepare_async_index_removal_of_token_for_ci_builds.rb b/db/post_migrate/20230222035805_prepare_async_index_removal_of_token_for_ci_builds.rb
new file mode 100644
index 00000000000..6fd5bb18856
--- /dev/null
+++ b/db/post_migrate/20230222035805_prepare_async_index_removal_of_token_for_ci_builds.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class PrepareAsyncIndexRemovalOfTokenForCiBuilds < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_builds
+ COLUMN_NAME = :token_encrypted
+ INDEX_NAME = :index_ci_builds_on_token_encrypted
+
+ def up
+ prepare_async_index_removal(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/20230222055510_remove_concurrent_index_on_token_encrypted_for_ci_builds.rb b/db/post_migrate/20230222055510_remove_concurrent_index_on_token_encrypted_for_ci_builds.rb
new file mode 100644
index 00000000000..d3ed5a8fa2c
--- /dev/null
+++ b/db/post_migrate/20230222055510_remove_concurrent_index_on_token_encrypted_for_ci_builds.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RemoveConcurrentIndexOnTokenEncryptedForCiBuilds < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_builds
+ COLUMN_NAME = :token_encrypted
+ INDEX_NAME = :index_ci_builds_on_token_encrypted
+ WHERE_STATEMENT = 'token_encrypted IS NOT NULL'
+
+ def up
+ remove_concurrent_index_by_name TABLE_NAME, name: INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index TABLE_NAME, COLUMN_NAME, name: INDEX_NAME, where: WHERE_STATEMENT, unique: true
+ end
+end
diff --git a/db/post_migrate/20230222101420_remove_fk_to_ci_build_ci_pending_build_on_build_id.rb b/db/post_migrate/20230222101420_remove_fk_to_ci_build_ci_pending_build_on_build_id.rb
new file mode 100644
index 00000000000..36e2f0f34f3
--- /dev/null
+++ b/db/post_migrate/20230222101420_remove_fk_to_ci_build_ci_pending_build_on_build_id.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildCiPendingBuildOnBuildId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :ci_pending_builds
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :build_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_rails_725a2644a3
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: COLUMN,
+ target_column: TARGET_COLUMN,
+ validate: true,
+ reverse_lock_order: true,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230222102421_remove_fk_to_ci_build_ci_running_build_on_build_id.rb b/db/post_migrate/20230222102421_remove_fk_to_ci_build_ci_running_build_on_build_id.rb
new file mode 100644
index 00000000000..d3cbfa649c3
--- /dev/null
+++ b/db/post_migrate/20230222102421_remove_fk_to_ci_build_ci_running_build_on_build_id.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildCiRunningBuildOnBuildId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :ci_running_builds
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :build_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_rails_da45cfa165
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: COLUMN,
+ target_column: TARGET_COLUMN,
+ validate: true,
+ reverse_lock_order: true,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230223014251_validate_not_null_constraint_on_oauth_access_tokens_expires_in.rb b/db/post_migrate/20230223014251_validate_not_null_constraint_on_oauth_access_tokens_expires_in.rb
new file mode 100644
index 00000000000..b5085d24ab1
--- /dev/null
+++ b/db/post_migrate/20230223014251_validate_not_null_constraint_on_oauth_access_tokens_expires_in.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class ValidateNotNullConstraintOnOauthAccessTokensExpiresIn < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ validate_not_null_constraint :oauth_access_tokens, :expires_in
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230223065753_finalize_nullify_creator_id_of_orphaned_projects.rb b/db/post_migrate/20230223065753_finalize_nullify_creator_id_of_orphaned_projects.rb
new file mode 100644
index 00000000000..aa3ed4837e7
--- /dev/null
+++ b/db/post_migrate/20230223065753_finalize_nullify_creator_id_of_orphaned_projects.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class FinalizeNullifyCreatorIdOfOrphanedProjects < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'NullifyCreatorIdColumnOfOrphanedProjects'
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: MIGRATION,
+ table_name: :projects,
+ column_name: :id,
+ job_arguments: []
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230223082752_schedule_fk_validation_for_p_ci_builds_metadata_partitions_and_ci_builds.rb b/db/post_migrate/20230223082752_schedule_fk_validation_for_p_ci_builds_metadata_partitions_and_ci_builds.rb
new file mode 100644
index 00000000000..bcb1147605e
--- /dev/null
+++ b/db/post_migrate/20230223082752_schedule_fk_validation_for_p_ci_builds_metadata_partitions_and_ci_builds.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class ScheduleFkValidationForPCiBuildsMetadataPartitionsAndCiBuilds < Gitlab::Database::Migration[2.1]
+ # This migration was used to validate the foreign keys on partitions introduced by
+ # db/post_migrate/20230221125148_add_fk_to_p_ci_builds_metadata_partitions_on_partition_id_and_build_id.rb
+ # but executing the rollback of
+ # db/post_migrate/20230306072532_add_partitioned_fk_to_p_ci_builds_metadata_on_partition_id_and_build_id.rb
+ # would also remove the FKs on partitions and this would errors out.
+
+ def up
+ # No-op
+ end
+
+ def down
+ # No-op
+ end
+end
diff --git a/db/post_migrate/20230223093704_add_foreign_key_on_creator_id_on_projects.rb b/db/post_migrate/20230223093704_add_foreign_key_on_creator_id_on_projects.rb
new file mode 100644
index 00000000000..68fd6de3f23
--- /dev/null
+++ b/db/post_migrate/20230223093704_add_foreign_key_on_creator_id_on_projects.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddForeignKeyOnCreatorIdOnProjects < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :projects, :users, column: :creator_id, on_delete: :nullify, validate: false
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key_if_exists :projects, column: :creator_id
+ end
+ end
+end
diff --git a/db/post_migrate/20230224085743_update_issues_internal_id_scope.rb b/db/post_migrate/20230224085743_update_issues_internal_id_scope.rb
new file mode 100644
index 00000000000..71d16ccf2a6
--- /dev/null
+++ b/db/post_migrate/20230224085743_update_issues_internal_id_scope.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class UpdateIssuesInternalIdScope < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'IssuesInternalIdScopeUpdater'
+ INTERVAL = 2.minutes
+ BATCH_SIZE = 5_000
+ MAX_BATCH_SIZE = 20_000
+ SUB_BATCH_SIZE = 100
+
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :internal_ids,
+ :id,
+ job_interval: INTERVAL,
+ batch_size: BATCH_SIZE,
+ max_batch_size: MAX_BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :internal_ids, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230224144233_migrate_evidences_from_raw_metadata.rb b/db/post_migrate/20230224144233_migrate_evidences_from_raw_metadata.rb
new file mode 100644
index 00000000000..5d72a46f3c4
--- /dev/null
+++ b/db/post_migrate/20230224144233_migrate_evidences_from_raw_metadata.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class MigrateEvidencesFromRawMetadata < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'MigrateEvidencesForVulnerabilityFindings'
+ DELAY_INTERVAL = 2.minutes
+ SUB_BATCH_SIZE = 500
+ BATCH_SIZE = 10000
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :vulnerability_occurrences,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230227123949_validate_fk_on_ci_sources_pipelines_source_partition_id_and_source_job_id.rb b/db/post_migrate/20230227123949_validate_fk_on_ci_sources_pipelines_source_partition_id_and_source_job_id.rb
new file mode 100644
index 00000000000..630483ee1f8
--- /dev/null
+++ b/db/post_migrate/20230227123949_validate_fk_on_ci_sources_pipelines_source_partition_id_and_source_job_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ValidateFkOnCiSourcesPipelinesSourcePartitionIdAndSourceJobId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_sources_pipelines
+ FK_NAME = :fk_be5624bf37_p
+ COLUMNS = [:source_partition_id, :source_job_id]
+
+ def up
+ validate_foreign_key(TABLE_NAME, COLUMNS, name: FK_NAME)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230227123950_remove_fk_to_ci_builds_ci_sources_pipelines_on_source_job_id.rb b/db/post_migrate/20230227123950_remove_fk_to_ci_builds_ci_sources_pipelines_on_source_job_id.rb
new file mode 100644
index 00000000000..17ae2ad1325
--- /dev/null
+++ b/db/post_migrate/20230227123950_remove_fk_to_ci_builds_ci_sources_pipelines_on_source_job_id.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildsCiSourcesPipelinesOnSourceJobId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :ci_sources_pipelines
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :source_job_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_be5624bf37
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: COLUMN,
+ target_column: TARGET_COLUMN,
+ validate: true,
+ reverse_lock_order: true,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230227151608_validate_fk_on_ci_build_trace_metadata_partition_id_and_build_id.rb b/db/post_migrate/20230227151608_validate_fk_on_ci_build_trace_metadata_partition_id_and_build_id.rb
new file mode 100644
index 00000000000..b95c416c128
--- /dev/null
+++ b/db/post_migrate/20230227151608_validate_fk_on_ci_build_trace_metadata_partition_id_and_build_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ValidateFkOnCiBuildTraceMetadataPartitionIdAndBuildId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_build_trace_metadata
+ FK_NAME = :fk_rails_aebc78111f_p
+ COLUMNS = [:partition_id, :build_id]
+
+ def up
+ validate_foreign_key(TABLE_NAME, COLUMNS, name: FK_NAME)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230227151609_remove_fk_to_ci_builds_ci_build_trace_metadata_on_build_id.rb b/db/post_migrate/20230227151609_remove_fk_to_ci_builds_ci_build_trace_metadata_on_build_id.rb
new file mode 100644
index 00000000000..16e24d7ed4c
--- /dev/null
+++ b/db/post_migrate/20230227151609_remove_fk_to_ci_builds_ci_build_trace_metadata_on_build_id.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildsCiBuildTraceMetadataOnBuildId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :ci_build_trace_metadata
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :build_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_rails_aebc78111f
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: COLUMN,
+ target_column: TARGET_COLUMN,
+ validate: true,
+ reverse_lock_order: true,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230227153231_validate_fk_on_ci_job_variables_partition_id_and_job_id.rb b/db/post_migrate/20230227153231_validate_fk_on_ci_job_variables_partition_id_and_job_id.rb
new file mode 100644
index 00000000000..035d26dbe94
--- /dev/null
+++ b/db/post_migrate/20230227153231_validate_fk_on_ci_job_variables_partition_id_and_job_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ValidateFkOnCiJobVariablesPartitionIdAndJobId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_job_variables
+ FK_NAME = :fk_rails_fbf3b34792_p
+ COLUMNS = [:partition_id, :job_id]
+
+ def up
+ validate_foreign_key(TABLE_NAME, COLUMNS, name: FK_NAME)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230227153232_remove_fk_to_ci_builds_ci_job_variables_on_job_id.rb b/db/post_migrate/20230227153232_remove_fk_to_ci_builds_ci_job_variables_on_job_id.rb
new file mode 100644
index 00000000000..f5dae8b57e0
--- /dev/null
+++ b/db/post_migrate/20230227153232_remove_fk_to_ci_builds_ci_job_variables_on_job_id.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildsCiJobVariablesOnJobId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :ci_job_variables
+ TARGET_TABLE_NAME = :ci_builds
+ COLUMN = :job_id
+ TARGET_COLUMN = :id
+ FK_NAME = :fk_rails_fbf3b34792
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: COLUMN,
+ target_column: TARGET_COLUMN,
+ validate: true,
+ reverse_lock_order: true,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230228021910_ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb b/db/post_migrate/20230228021910_ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb
new file mode 100644
index 00000000000..238c7fd0bec
--- /dev/null
+++ b/db/post_migrate/20230228021910_ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class EnsureTimelogsNoteIdBigintBackfillIsFinishedForGitlabDotCom < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ return unless should_run?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'timelogs',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+
+ private
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230228023014_swap_timelogs_note_id_to_bigint_for_gitlab_dot_com.rb b/db/post_migrate/20230228023014_swap_timelogs_note_id_to_bigint_for_gitlab_dot_com.rb
new file mode 100644
index 00000000000..722a71863b0
--- /dev/null
+++ b/db/post_migrate/20230228023014_swap_timelogs_note_id_to_bigint_for_gitlab_dot_com.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+class SwapTimelogsNoteIdToBigintForGitlabDotCom < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'timelogs'
+
+ def up
+ return unless should_run?
+
+ swap
+ end
+
+ def down
+ return unless should_run?
+
+ swap
+ end
+
+ def swap
+ # This will replace the existing index_timelogs_on_note_id
+ add_concurrent_index TABLE_NAME, :note_id_convert_to_bigint, name: 'index_timelogs_on_note_id_convert_to_bigint'
+
+ # This will replace the existing fk_timelogs_note_id
+ add_concurrent_foreign_key :timelogs, :notes, column: :note_id_convert_to_bigint,
+ name: 'fk_timelogs_note_id_convert_to_bigint',
+ on_delete: :nullify
+
+ 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_timelogs_on_note_id"
+ rename_index TABLE_NAME, 'index_timelogs_on_note_id_convert_to_bigint', 'index_timelogs_on_note_id'
+
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS fk_timelogs_note_id"
+ rename_constraint(TABLE_NAME, 'fk_timelogs_note_id_convert_to_bigint', 'fk_timelogs_note_id')
+ end
+ end
+
+ private
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230301065107_add_index_on_expired_unlocked_non_trace_job_artifacts.rb b/db/post_migrate/20230301065107_add_index_on_expired_unlocked_non_trace_job_artifacts.rb
new file mode 100644
index 00000000000..feda6971a85
--- /dev/null
+++ b/db/post_migrate/20230301065107_add_index_on_expired_unlocked_non_trace_job_artifacts.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexOnExpiredUnlockedNonTraceJobArtifacts < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_ci_job_artifacts_expire_at_unlocked_non_trace'
+
+ def up
+ add_concurrent_index :ci_job_artifacts, :expire_at,
+ name: INDEX_NAME,
+ where: 'locked = 0 AND file_type != 3 AND expire_at IS NOT NULL'
+ end
+
+ def down
+ remove_concurrent_index_by_name :ci_job_artifacts, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230302090155_add_async_index_on_unlocked_non_trace_job_artifacts_expire_at.rb b/db/post_migrate/20230302090155_add_async_index_on_unlocked_non_trace_job_artifacts_expire_at.rb
new file mode 100644
index 00000000000..9f89b6916bd
--- /dev/null
+++ b/db/post_migrate/20230302090155_add_async_index_on_unlocked_non_trace_job_artifacts_expire_at.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddAsyncIndexOnUnlockedNonTraceJobArtifactsExpireAt < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_ci_job_artifacts_expire_at_unlocked_non_trace'
+
+ def up
+ prepare_async_index :ci_job_artifacts, :expire_at,
+ name: INDEX_NAME,
+ where: 'locked = 0 AND file_type != 3 AND expire_at IS NOT NULL'
+ end
+
+ def down
+ unprepare_async_index :ci_job_artifacts, :expire_at, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230302123258_drop_runner_machines_constraint_on_ci_builds_metadata.rb b/db/post_migrate/20230302123258_drop_runner_machines_constraint_on_ci_builds_metadata.rb
new file mode 100644
index 00000000000..c8f1b3be9bd
--- /dev/null
+++ b/db/post_migrate/20230302123258_drop_runner_machines_constraint_on_ci_builds_metadata.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class DropRunnerMachinesConstraintOnCiBuildsMetadata < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = 'p_ci_builds_metadata'
+ TARGET_TABLE_NAME = 'ci_runner_machines'
+ CONSTRAINT_NAME = 'fk_rails_fae01b2700'
+
+ def up
+ with_lock_retries(raise_on_exhaustion: true) do
+ remove_foreign_key_if_exists(SOURCE_TABLE_NAME, TARGET_TABLE_NAME, name: CONSTRAINT_NAME)
+ end
+ end
+
+ def down
+ with_lock_retries(raise_on_exhaustion: true) do
+ next if check_constraint_exists?(SOURCE_TABLE_NAME, CONSTRAINT_NAME)
+
+ execute(<<~SQL)
+ ALTER TABLE #{SOURCE_TABLE_NAME}
+ ADD CONSTRAINT #{CONSTRAINT_NAME} FOREIGN KEY (runner_machine_id)
+ REFERENCES #{TARGET_TABLE_NAME}(id) ON DELETE SET NULL
+ SQL
+ end
+ end
+end
diff --git a/db/post_migrate/20230302123259_ensure_ci_runner_machines_is_empty.rb b/db/post_migrate/20230302123259_ensure_ci_runner_machines_is_empty.rb
new file mode 100644
index 00000000000..9f7233f43f5
--- /dev/null
+++ b/db/post_migrate/20230302123259_ensure_ci_runner_machines_is_empty.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class EnsureCiRunnerMachinesIsEmpty < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ return unless Gitlab::Database.gitlab_schemas_for_connection(connection).include?(:gitlab_ci)
+
+ # Ensure that the ci_runner_machines table is empty to ensure that new builds
+ # don't try to create new join records until we add the missing FK.
+ execute('TRUNCATE TABLE ci_runner_machines, p_ci_runner_machine_builds')
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230302123301_add_index_on_runner_machine_id_on_runner_machine_builds.rb b/db/post_migrate/20230302123301_add_index_on_runner_machine_id_on_runner_machine_builds.rb
new file mode 100644
index 00000000000..035223382bd
--- /dev/null
+++ b/db/post_migrate/20230302123301_add_index_on_runner_machine_id_on_runner_machine_builds.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexOnRunnerMachineIdOnRunnerMachineBuilds < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_p_ci_runner_machine_builds_on_runner_machine_id'
+
+ def up
+ add_concurrent_partitioned_index :p_ci_runner_machine_builds, :runner_machine_id, unique: false, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_partitioned_index_by_name :p_ci_runner_machine_builds, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230302163339_add_index_to_oauth_access_grants_application_id.rb b/db/post_migrate/20230302163339_add_index_to_oauth_access_grants_application_id.rb
new file mode 100644
index 00000000000..0db6190e17d
--- /dev/null
+++ b/db/post_migrate/20230302163339_add_index_to_oauth_access_grants_application_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexToOauthAccessGrantsApplicationId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_oauth_access_grants_on_application_id'
+
+ def up
+ add_concurrent_index :oauth_access_grants, :application_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :oauth_access_grants, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230302185739_queue_fix_vulnerability_reads_has_issues.rb b/db/post_migrate/20230302185739_queue_fix_vulnerability_reads_has_issues.rb
new file mode 100644
index 00000000000..09a5f6e9478
--- /dev/null
+++ b/db/post_migrate/20230302185739_queue_fix_vulnerability_reads_has_issues.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class QueueFixVulnerabilityReadsHasIssues < Gitlab::Database::Migration[2.1]
+ MIGRATION = "FixVulnerabilityReadsHasIssues"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ MAX_BATCH_SIZE = 10_000
+ SUB_BATCH_SIZE = 200
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :vulnerability_issue_links,
+ :vulnerability_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, :vulnerability_issue_links, :vulnerability_id, [])
+ end
+end
diff --git a/db/post_migrate/20230303105806_queue_delete_orphaned_packages_dependencies.rb b/db/post_migrate/20230303105806_queue_delete_orphaned_packages_dependencies.rb
new file mode 100644
index 00000000000..8c741cf9868
--- /dev/null
+++ b/db/post_migrate/20230303105806_queue_delete_orphaned_packages_dependencies.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class QueueDeleteOrphanedPackagesDependencies < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'DeleteOrphanedPackagesDependencies'
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 6000
+ SUB_BATCH_SIZE = 100
+
+ disable_ddl_transaction!
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :packages_dependencies,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :packages_dependencies, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230303120531_schedule_temporary_partitioning_indexes_removal.rb b/db/post_migrate/20230303120531_schedule_temporary_partitioning_indexes_removal.rb
new file mode 100644
index 00000000000..73334be4214
--- /dev/null
+++ b/db/post_migrate/20230303120531_schedule_temporary_partitioning_indexes_removal.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+class ScheduleTemporaryPartitioningIndexesRemoval < Gitlab::Database::Migration[2.1]
+ INDEXES = [
+ [:ci_pipelines, :tmp_index_ci_pipelines_on_partition_id_and_id],
+ [:ci_stages, :tmp_index_ci_stages_on_partition_id_and_id],
+ [:ci_builds, :tmp_index_ci_builds_on_partition_id_and_id],
+ [:ci_build_needs, :tmp_index_ci_build_needs_on_partition_id_and_id],
+ [:ci_build_report_results, :tmp_index_ci_build_report_results_on_partition_id_and_build_id],
+ [:ci_build_trace_metadata, :tmp_index_ci_build_trace_metadata_on_partition_id_and_id],
+ [:ci_job_artifacts, :tmp_index_ci_job_artifacts_on_partition_id_and_id],
+ [:ci_pipeline_variables, :tmp_index_ci_pipeline_variables_on_partition_id_and_id],
+ [:ci_job_variables, :tmp_index_ci_job_variables_on_partition_id_and_id],
+ [:ci_sources_pipelines, :tmp_index_ci_sources_pipelines_on_partition_id_and_id],
+ [:ci_sources_pipelines, :tmp_index_ci_sources_pipelines_on_source_partition_id_and_id],
+ [:ci_running_builds, :tmp_index_ci_running_builds_on_partition_id_and_id],
+ [:ci_pending_builds, :tmp_index_ci_pending_builds_on_partition_id_and_id],
+ [:ci_builds_runner_session, :tmp_index_ci_builds_runner_session_on_partition_id_and_id]
+ ]
+
+ def up
+ INDEXES.each do |table_name, index_name|
+ prepare_async_index_removal table_name, nil, name: index_name
+ end
+ end
+
+ def down
+ INDEXES.each do |table_name, index_name|
+ unprepare_async_index table_name, nil, name: index_name
+ end
+ end
+end
diff --git a/db/post_migrate/20230303154314_add_user_type_migration_indexes.rb b/db/post_migrate/20230303154314_add_user_type_migration_indexes.rb
new file mode 100644
index 00000000000..8f9e193f0eb
--- /dev/null
+++ b/db/post_migrate/20230303154314_add_user_type_migration_indexes.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class AddUserTypeMigrationIndexes < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ BILLABLE_INDEX = 'index_users_for_active_billable_users_migration'
+ LAST_ACTIVITY_INDEX = 'i_users_on_last_activity_for_active_human_service_migration'
+
+ def up
+ # Temporary indexes to migrate human user_type. See https://gitlab.com/gitlab-org/gitlab/-/issues/386474
+ add_concurrent_index :users, :id, name: BILLABLE_INDEX,
+ where: "state = 'active' AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[6, 4, 13]))) " \
+ "AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[4, 5])))"
+ add_concurrent_index :users, [:id, :last_activity_on], name: LAST_ACTIVITY_INDEX,
+ where: "((state)::text = 'active'::text) AND ((user_type IS NULL OR user_type = 0) OR (user_type = 4))"
+ end
+
+ def down
+ remove_concurrent_index_by_name :users, BILLABLE_INDEX
+ remove_concurrent_index_by_name :users, LAST_ACTIVITY_INDEX
+ end
+end
diff --git a/db/post_migrate/20230304184416_drop_revokable_from_achievements.rb b/db/post_migrate/20230304184416_drop_revokable_from_achievements.rb
new file mode 100644
index 00000000000..bb6c8d65c57
--- /dev/null
+++ b/db/post_migrate/20230304184416_drop_revokable_from_achievements.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class DropRevokableFromAchievements < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ remove_column :achievements, :revokeable, :boolean, default: false, null: false
+ end
+end
diff --git a/db/post_migrate/20230306071456_validate_partitioning_fk_on_p_ci_builds_metadata_partitions.rb b/db/post_migrate/20230306071456_validate_partitioning_fk_on_p_ci_builds_metadata_partitions.rb
new file mode 100644
index 00000000000..f07175e82f9
--- /dev/null
+++ b/db/post_migrate/20230306071456_validate_partitioning_fk_on_p_ci_builds_metadata_partitions.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class ValidatePartitioningFkOnPCiBuildsMetadataPartitions < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :p_ci_builds_metadata
+ FK_NAME = :fk_e20479742e_p
+
+ def up
+ Gitlab::Database::PostgresPartitionedTable.each_partition(SOURCE_TABLE_NAME) do |partition|
+ next unless foreign_key_exists?(partition.identifier, name: FK_NAME)
+
+ validate_foreign_key(partition.identifier, nil, name: FK_NAME)
+ end
+ end
+
+ def down
+ # No-op
+ end
+end
diff --git a/db/post_migrate/20230306072532_add_partitioned_fk_to_p_ci_builds_metadata_on_partition_id_and_build_id.rb b/db/post_migrate/20230306072532_add_partitioned_fk_to_p_ci_builds_metadata_on_partition_id_and_build_id.rb
new file mode 100644
index 00000000000..d66950378d2
--- /dev/null
+++ b/db/post_migrate/20230306072532_add_partitioned_fk_to_p_ci_builds_metadata_on_partition_id_and_build_id.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+class AddPartitionedFkToPCiBuildsMetadataOnPartitionIdAndBuildId < Gitlab::Database::Migration[2.1]
+ SOURCE_TABLE_NAME = :p_ci_builds_metadata
+ TARGET_TABLE_NAME = :ci_builds
+ FK_NAME = :fk_e20479742e_p
+
+ disable_ddl_transaction!
+
+ def up
+ return if foreign_key_exists?(SOURCE_TABLE_NAME, TARGET_TABLE_NAME, name: FK_NAME)
+
+ with_lock_retries do
+ execute("LOCK TABLE #{TARGET_TABLE_NAME}, #{SOURCE_TABLE_NAME} IN ACCESS EXCLUSIVE MODE")
+
+ execute(<<~SQL.squish)
+ ALTER TABLE #{SOURCE_TABLE_NAME}
+ ADD CONSTRAINT #{FK_NAME}
+ FOREIGN KEY (partition_id, build_id)
+ REFERENCES #{TARGET_TABLE_NAME} (partition_id, id)
+ ON UPDATE CASCADE ON DELETE CASCADE;
+ SQL
+ end
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+end
diff --git a/db/post_migrate/20230306082852_remove_fk_to_ci_builds_p_ci_builds_metadata_on_build_id.rb b/db/post_migrate/20230306082852_remove_fk_to_ci_builds_p_ci_builds_metadata_on_build_id.rb
new file mode 100644
index 00000000000..108a92aec3b
--- /dev/null
+++ b/db/post_migrate/20230306082852_remove_fk_to_ci_builds_p_ci_builds_metadata_on_build_id.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+class RemoveFkToCiBuildsPCiBuildsMetadataOnBuildId < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :p_ci_builds_metadata
+ TARGET_TABLE_NAME = :ci_builds
+ FK_NAME = :fk_e20479742e
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ def down
+ add_concurrent_partitioned_foreign_key(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ column: :build_id,
+ on_delete: :cascade,
+ name: FK_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230306143322_prepare_ci_builds_primary_key_for_partitioning.rb b/db/post_migrate/20230306143322_prepare_ci_builds_primary_key_for_partitioning.rb
new file mode 100644
index 00000000000..99b52e4c443
--- /dev/null
+++ b/db/post_migrate/20230306143322_prepare_ci_builds_primary_key_for_partitioning.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+class PrepareCiBuildsPrimaryKeyForPartitioning < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_builds
+ PRIMARY_KEY = :ci_builds_pkey
+ NEW_INDEX_NAME = :index_ci_builds_on_id_partition_id_unique
+ OLD_INDEX_NAME = :index_ci_builds_on_id_unique
+
+ def up
+ swap_primary_key(TABLE_NAME, PRIMARY_KEY, NEW_INDEX_NAME)
+ end
+
+ def down
+ add_concurrent_index(TABLE_NAME, :id, unique: true, name: OLD_INDEX_NAME)
+ add_concurrent_index(TABLE_NAME, [:id, :partition_id], unique: true, name: NEW_INDEX_NAME)
+
+ unswap_primary_key(TABLE_NAME, PRIMARY_KEY, OLD_INDEX_NAME)
+
+ recreate_partitioned_foreign_keys
+ end
+
+ private
+
+ def recreate_partitioned_foreign_keys
+ add_partitioned_fk(:ci_job_variables, :fk_rails_fbf3b34792_p, column: :job_id)
+ add_partitioned_fk(:ci_job_artifacts, :fk_rails_c5137cb2c1_p, column: :job_id)
+ add_partitioned_fk(:ci_running_builds, :fk_rails_da45cfa165_p)
+ add_partitioned_fk(:ci_build_pending_states, :fk_861cd17da3_p)
+ add_partitioned_fk(:ci_build_trace_chunks, :fk_89e29fa5ee_p)
+ add_partitioned_fk(:ci_unit_test_failures, :fk_9e0fc58930_p)
+ add_partitioned_fk(:ci_build_trace_metadata, :fk_rails_aebc78111f_p)
+ add_partitioned_fk(:ci_pending_builds, :fk_rails_725a2644a3_p)
+ add_partitioned_fk(:ci_builds_runner_session, :fk_rails_70707857d3_p)
+ add_partitioned_fk(:ci_build_needs, :fk_rails_3cf221d4ed_p)
+ add_partitioned_fk(:ci_build_report_results, :fk_rails_16cb1ff064_p)
+ add_partitioned_fk(:ci_resources, :fk_e169a8e3d5_p, delete: :nullify)
+ add_partitioned_fk(:ci_sources_pipelines, :fk_be5624bf37_p, columns: %i[source_partition_id source_job_id])
+
+ add_routing_table_fk(:p_ci_builds_metadata, :fk_e20479742e_p)
+ add_routing_table_fk(:p_ci_runner_machine_builds, :fk_bb490f12fe_p)
+ end
+
+ def add_partitioned_fk(source_table, name, column: :build_id, columns: nil, delete: :cascade)
+ add_concurrent_foreign_key(source_table, :ci_builds,
+ column: columns || [:partition_id, column],
+ target_column: [:partition_id, :id],
+ reverse_lock_order: true,
+ on_update: :cascade,
+ on_delete: delete,
+ name: name)
+ end
+
+ def add_routing_table_fk(source_table, name)
+ add_concurrent_partitioned_foreign_key(source_table, :ci_builds,
+ column: [:partition_id, :build_id],
+ target_column: [:partition_id, :id],
+ reverse_lock_order: true,
+ on_update: :cascade,
+ on_delete: :cascade,
+ name: name)
+ end
+end
diff --git a/db/post_migrate/20230306195007_queue_backfill_project_wiki_repositories.rb b/db/post_migrate/20230306195007_queue_backfill_project_wiki_repositories.rb
new file mode 100644
index 00000000000..fd2dc0d16da
--- /dev/null
+++ b/db/post_migrate/20230306195007_queue_backfill_project_wiki_repositories.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class QueueBackfillProjectWikiRepositories < Gitlab::Database::Migration[2.1]
+ MIGRATION = "BackfillProjectWikiRepositories"
+ 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,
+ :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/20230307085644_track_ci_runner_machine_record_changes.rb b/db/post_migrate/20230307085644_track_ci_runner_machine_record_changes.rb
new file mode 100644
index 00000000000..deae1a57968
--- /dev/null
+++ b/db/post_migrate/20230307085644_track_ci_runner_machine_record_changes.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class TrackCiRunnerMachineRecordChanges < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::LooseForeignKeyHelpers
+
+ enable_lock_retries!
+
+ def up
+ track_record_deletions(:ci_runner_machines)
+ end
+
+ def down
+ untrack_record_deletions(:ci_runner_machines)
+ end
+end
diff --git a/db/post_migrate/20230307160251_rename_constraint_fk_rails_f601258b28_on_events_table.rb b/db/post_migrate/20230307160251_rename_constraint_fk_rails_f601258b28_on_events_table.rb
new file mode 100644
index 00000000000..6b5ba4c3825
--- /dev/null
+++ b/db/post_migrate/20230307160251_rename_constraint_fk_rails_f601258b28_on_events_table.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class RenameConstraintFkRailsF601258b28OnEventsTable < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ TABLE_NAME = :events
+ FK_OLD_NAME = :fk_rails_f601258b28
+ FK_NEW_NAME = :fk_rails_0434b48643
+
+ def up
+ return unless foreign_key_exists?(TABLE_NAME, name: FK_OLD_NAME)
+
+ rename_constraint(TABLE_NAME, FK_OLD_NAME, FK_NEW_NAME)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230309010000_add_unique_index_mr_user_mentions_note_id_convert_to_bigint.rb b/db/post_migrate/20230309010000_add_unique_index_mr_user_mentions_note_id_convert_to_bigint.rb
new file mode 100644
index 00000000000..9927bfb995a
--- /dev/null
+++ b/db/post_migrate/20230309010000_add_unique_index_mr_user_mentions_note_id_convert_to_bigint.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+class AddUniqueIndexMrUserMentionsNoteIdConvertToBigint < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = :merge_request_user_mentions
+ INDEX_NAME = :index_merge_request_user_mentions_note_id_convert_to_bigint
+
+ def up
+ return unless should_run?
+
+ # 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_NAME,
+ where: 'note_id_convert_to_bigint IS NOT NULL'
+ end
+
+ def down
+ return unless should_run?
+
+ remove_concurrent_index_by_name(TABLE_NAME, INDEX_NAME)
+ end
+
+ private
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230309010931_add_fk_on_mr_user_mentions_note_id_convert_to_id_bigint.rb b/db/post_migrate/20230309010931_add_fk_on_mr_user_mentions_note_id_convert_to_id_bigint.rb
new file mode 100644
index 00000000000..022e38460ae
--- /dev/null
+++ b/db/post_migrate/20230309010931_add_fk_on_mr_user_mentions_note_id_convert_to_id_bigint.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+class AddFkOnMrUserMentionsNoteIdConvertToIdBigint < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ SOURCE_TABLE_NAME = :merge_request_user_mentions
+ TARGET_TABLE_NAME = :notes
+ FK_NAME = :fk_merge_request_user_mentions_note_id_convert_to_bigint
+
+ def up
+ return unless should_run?
+
+ # This will replace the existing fk_rails_c440b9ea31
+ # when we swap the integer and bigint columns
+ add_concurrent_foreign_key SOURCE_TABLE_NAME, TARGET_TABLE_NAME,
+ column: :note_id_convert_to_bigint,
+ name: FK_NAME,
+ on_delete: :cascade,
+ reverse_lock_order: true,
+ validate: false
+ end
+
+ def down
+ return unless should_run?
+
+ with_lock_retries do
+ remove_foreign_key_if_exists(
+ SOURCE_TABLE_NAME,
+ TARGET_TABLE_NAME,
+ name: FK_NAME,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ private
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230309020422_validate_fk_on_mr_user_mentions_note_id_convert_to_id_bigint.rb b/db/post_migrate/20230309020422_validate_fk_on_mr_user_mentions_note_id_convert_to_id_bigint.rb
new file mode 100644
index 00000000000..104fb7edb7e
--- /dev/null
+++ b/db/post_migrate/20230309020422_validate_fk_on_mr_user_mentions_note_id_convert_to_id_bigint.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class ValidateFkOnMrUserMentionsNoteIdConvertToIdBigint < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ TABLE_NAME = :merge_request_user_mentions
+ COLUMN = :note_id_convert_to_bigint
+ FK_NAME = :fk_merge_request_user_mentions_note_id_convert_to_bigint
+
+ def up
+ return unless should_run?
+
+ prepare_async_foreign_key_validation TABLE_NAME, COLUMN, name: FK_NAME
+ end
+
+ def down
+ return unless should_run?
+
+ unprepare_async_foreign_key_validation TABLE_NAME, COLUMN, name: FK_NAME
+ end
+
+ private
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230309071242_delete_security_policy_bot_users.rb b/db/post_migrate/20230309071242_delete_security_policy_bot_users.rb
new file mode 100644
index 00000000000..0a9ace2574c
--- /dev/null
+++ b/db/post_migrate/20230309071242_delete_security_policy_bot_users.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class DeleteSecurityPolicyBotUsers < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ class User < MigrationRecord
+ self.table_name = 'users'
+
+ enum user_type: { security_policy_bot: 10 }
+ end
+
+ def up
+ User.where(user_type: :security_policy_bot).delete_all
+ end
+
+ def down
+ # no-op
+
+ # Deleted records can't be restored
+ end
+end
diff --git a/db/post_migrate/20230309103016_drop_id_partition_id_index_from_p_ci_build_metadata.rb b/db/post_migrate/20230309103016_drop_id_partition_id_index_from_p_ci_build_metadata.rb
new file mode 100644
index 00000000000..6e8866c0552
--- /dev/null
+++ b/db/post_migrate/20230309103016_drop_id_partition_id_index_from_p_ci_build_metadata.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class DropIdPartitionIdIndexFromPCiBuildMetadata < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = :p_ci_builds_metadata
+ INDEX_NAME = :p_ci_builds_metadata_id_partition_id_idx
+
+ def up
+ remove_concurrent_partitioned_index_by_name(TABLE_NAME, INDEX_NAME)
+ end
+
+ def down
+ add_concurrent_partitioned_index(TABLE_NAME, %i[id partition_id], unique: true, name: INDEX_NAME)
+ end
+end
diff --git a/db/post_migrate/20230310111859_recreate_user_type_migration_indexes.rb b/db/post_migrate/20230310111859_recreate_user_type_migration_indexes.rb
new file mode 100644
index 00000000000..539ce99a319
--- /dev/null
+++ b/db/post_migrate/20230310111859_recreate_user_type_migration_indexes.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class RecreateUserTypeMigrationIndexes < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INCORRECT_BILLABLE_INDEX = 'index_users_for_active_billable_users_migration'
+ BILLABLE_INDEX = 'migrate_index_users_for_active_billable_users'
+
+ def up
+ # Temporary index to migrate human user_type. See https://gitlab.com/gitlab-org/gitlab/-/issues/386474
+ add_concurrent_index :users, :id, name: BILLABLE_INDEX,
+ where: "state = 'active' AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[0, 6, 4, 13]))) " \
+ "AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[0, 4, 5])))"
+
+ remove_concurrent_index_by_name :users, INCORRECT_BILLABLE_INDEX
+ end
+
+ def down
+ add_concurrent_index :users, :id, name: INCORRECT_BILLABLE_INDEX,
+ where: "state = 'active' AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[6, 4, 13]))) " \
+ "AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[4, 5])))"
+ remove_concurrent_index_by_name :users, BILLABLE_INDEX
+ end
+end
diff --git a/db/post_migrate/20230313133001_ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb b/db/post_migrate/20230313133001_ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb
new file mode 100644
index 00000000000..ffda926c49e
--- /dev/null
+++ b/db/post_migrate/20230313133001_ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class EnsureMergeRequestMetricsIdBigintBackfillIsFinishedForGitlabDotCom < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ return unless should_run?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'merge_request_metrics',
+ column_name: 'id',
+ job_arguments: [['id'], ['id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+
+ private
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230313143033_swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com.rb b/db/post_migrate/20230313143033_swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com.rb
new file mode 100644
index 00000000000..089dd621033
--- /dev/null
+++ b/db/post_migrate/20230313143033_swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+class SwapMergeRequestMetricsIdToBigintForGitlabDotCom < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'merge_request_metrics'
+ TMP_INDEX_NAME = 'tmp_index_mr_metrics_on_target_project_id_merged_at_nulls_last'
+ INDEX_NAME = 'index_mr_metrics_on_target_project_id_merged_at_nulls_last'
+ CONSTRAINT_NAME = 'merge_request_metrics_pkey'
+
+ def up
+ return unless should_run?
+
+ swap
+ end
+
+ def down
+ return unless should_run?
+
+ swap
+ end
+
+ private
+
+ def swap
+ add_concurrent_index TABLE_NAME, :id_convert_to_bigint, unique: true,
+ name: 'index_merge_request_metrics_on_id_convert_to_bigint'
+ add_concurrent_index TABLE_NAME, 'target_project_id, merged_at DESC NULLS LAST, id_convert_to_bigint DESC',
+ name: TMP_INDEX_NAME
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ 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"
+
+ 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 columns, and change ownership of the sequence to the new id
+ execute "ALTER SEQUENCE merge_request_metrics_id_seq OWNED BY #{TABLE_NAME}.id"
+ change_column_default TABLE_NAME, :id, -> { "nextval('merge_request_metrics_id_seq'::regclass)" }
+ change_column_default TABLE_NAME, :id_convert_to_bigint, 0
+
+ # Swap PK constraint
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS #{CONSTRAINT_NAME}"
+ rename_index TABLE_NAME, 'index_merge_request_metrics_on_id_convert_to_bigint', CONSTRAINT_NAME
+ execute "ALTER TABLE #{TABLE_NAME} ADD CONSTRAINT #{CONSTRAINT_NAME} PRIMARY KEY USING INDEX #{CONSTRAINT_NAME}"
+
+ # Rename the rest of the indexes (we already hold an exclusive lock, so no need to use DROP INDEX CONCURRENTLY)
+ execute "DROP INDEX IF EXISTS #{INDEX_NAME}"
+ rename_index TABLE_NAME, TMP_INDEX_NAME, INDEX_NAME
+ end
+ end
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb b/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb
new file mode 100644
index 00000000000..ebb6e53341f
--- /dev/null
+++ b/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+# rubocop: disable BackgroundMigration/MissingDictionaryFile
+
+class RescheduleMigrationForRemediation < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'MigrateRemediationsForVulnerabilityFindings'
+ DELAY_INTERVAL = 2.minutes
+ SUB_BATCH_SIZE = 500
+ BATCH_SIZE = 5000
+
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, [])
+
+ queue_batched_background_migration(
+ MIGRATION,
+ :vulnerability_occurrences,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, [])
+ end
+end
+# rubocop: enable BackgroundMigration/MissingDictionaryFile
diff --git a/db/post_migrate/20230313184306_add_temp_index_for_software_license_cleanup.rb b/db/post_migrate/20230313184306_add_temp_index_for_software_license_cleanup.rb
new file mode 100644
index 00000000000..d2e35a0fa9e
--- /dev/null
+++ b/db/post_migrate/20230313184306_add_temp_index_for_software_license_cleanup.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddTempIndexForSoftwareLicenseCleanup < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'tmp_index_for_software_licenses_spdx_identifier_cleanup'
+
+ def up
+ add_concurrent_index :software_licenses, :spdx_identifier, where: 'spdx_identifier IS NULL', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :software_licenses, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230313185145_cleanup_orphan_software_licenses.rb b/db/post_migrate/20230313185145_cleanup_orphan_software_licenses.rb
new file mode 100644
index 00000000000..af971f692d6
--- /dev/null
+++ b/db/post_migrate/20230313185145_cleanup_orphan_software_licenses.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class CleanupOrphanSoftwareLicenses < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ class SoftwareLicense < MigrationRecord
+ self.table_name = 'software_licenses'
+ end
+
+ class SoftwareLicensePolicy < MigrationRecord
+ self.table_name = 'software_license_policies'
+ end
+
+ def up
+ SoftwareLicense
+ .where(spdx_identifier: nil)
+ .where.not(
+ id: SoftwareLicensePolicy.select(:software_license_id)
+ ).delete_all
+ end
+
+ def down
+ # NO-OP
+ end
+end
diff --git a/db/post_migrate/20230316014650_remove_index_on_events_action_async.rb b/db/post_migrate/20230316014650_remove_index_on_events_action_async.rb
new file mode 100644
index 00000000000..bc4bc4f941d
--- /dev/null
+++ b/db/post_migrate/20230316014650_remove_index_on_events_action_async.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class RemoveIndexOnEventsActionAsync < Gitlab::Database::Migration[2.1]
+ # TODO: Index to be destroyed synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/396830
+ def up
+ prepare_async_index_removal :events, :action, name: 'index_events_on_action'
+ end
+
+ def down
+ unprepare_async_index :events, :action, name: 'index_events_on_action'
+ end
+end
diff --git a/db/schema_migrations/20230113164245 b/db/schema_migrations/20230113164245
new file mode 100644
index 00000000000..2c8b04d4387
--- /dev/null
+++ b/db/schema_migrations/20230113164245
@@ -0,0 +1 @@
+eb2dfc21c5645e1f8aec9118a380c270525ce261a86ce13f89de891a8c4fa3a9 \ No newline at end of file
diff --git a/db/schema_migrations/20230113201308 b/db/schema_migrations/20230113201308
new file mode 100644
index 00000000000..df391813488
--- /dev/null
+++ b/db/schema_migrations/20230113201308
@@ -0,0 +1 @@
+775842b84022cf30d685060ea956c1e52722587f2be517d44ae44ca57f954538 \ No newline at end of file
diff --git a/db/schema_migrations/20230118135145 b/db/schema_migrations/20230118135145
new file mode 100644
index 00000000000..15c566a4058
--- /dev/null
+++ b/db/schema_migrations/20230118135145
@@ -0,0 +1 @@
+d6fdfc530a49b230aa041d4629a0484462abacb824f6bbf23d9740068e3ca781 \ No newline at end of file
diff --git a/db/schema_migrations/20230118144623 b/db/schema_migrations/20230118144623
new file mode 100644
index 00000000000..82c15116c45
--- /dev/null
+++ b/db/schema_migrations/20230118144623
@@ -0,0 +1 @@
+3ceeeeabb4ebae0f38e446c044fe6e6d929661b8689b461bed87660afd2e223b \ No newline at end of file
diff --git a/db/schema_migrations/20230125195503 b/db/schema_migrations/20230125195503
new file mode 100644
index 00000000000..ee8f7d47e16
--- /dev/null
+++ b/db/schema_migrations/20230125195503
@@ -0,0 +1 @@
+6321659d8f71127368dffd0bec122d4c32835da364a32cd6f276c641a70d10ff \ No newline at end of file
diff --git a/db/schema_migrations/20230126101907 b/db/schema_migrations/20230126101907
new file mode 100644
index 00000000000..e7006b46b1a
--- /dev/null
+++ b/db/schema_migrations/20230126101907
@@ -0,0 +1 @@
+f6fccc22b53fdc590d5af1b5924275b43334820b66d4f488b3ef6f6d70b4e415 \ No newline at end of file
diff --git a/db/schema_migrations/20230127030015 b/db/schema_migrations/20230127030015
new file mode 100644
index 00000000000..411b65dcf17
--- /dev/null
+++ b/db/schema_migrations/20230127030015
@@ -0,0 +1 @@
+c957902ecdc96e1ae22d514f932c22bc04e07fd3e11dfd1bdbd45b077b6ee017 \ No newline at end of file
diff --git a/db/schema_migrations/20230130182412 b/db/schema_migrations/20230130182412
new file mode 100644
index 00000000000..5d053b89d5e
--- /dev/null
+++ b/db/schema_migrations/20230130182412
@@ -0,0 +1 @@
+a5deb047ed3e0611ef10ce35d8f745f6d93d064a989488801c22d838d92ef780 \ No newline at end of file
diff --git a/db/schema_migrations/20230131184319 b/db/schema_migrations/20230131184319
new file mode 100644
index 00000000000..3028f92b316
--- /dev/null
+++ b/db/schema_migrations/20230131184319
@@ -0,0 +1 @@
+06a6005ecc7de9b6db9912b246aa27c30b308f47f23f1258043b7a7c636962b6 \ No newline at end of file
diff --git a/db/schema_migrations/20230201165656 b/db/schema_migrations/20230201165656
new file mode 100644
index 00000000000..8e401067403
--- /dev/null
+++ b/db/schema_migrations/20230201165656
@@ -0,0 +1 @@
+1f4e6f2b9e4461bb7dc663acedd08b2618f70e62ee8ae0a89bd9ccf11813f3b5 \ No newline at end of file
diff --git a/db/schema_migrations/20230202094723 b/db/schema_migrations/20230202094723
new file mode 100644
index 00000000000..6d18a0b1cf9
--- /dev/null
+++ b/db/schema_migrations/20230202094723
@@ -0,0 +1 @@
+54e3ad80c034d87621c266befc0a6d77b56927bb9afc71375767dcb647bb1aa9 \ No newline at end of file
diff --git a/db/schema_migrations/20230202135758 b/db/schema_migrations/20230202135758
new file mode 100644
index 00000000000..2afb3886ade
--- /dev/null
+++ b/db/schema_migrations/20230202135758
@@ -0,0 +1 @@
+877ea1462505cfc9986353e5fb5f8cfc68a7557140bdc162bcfbd7a68c266f97 \ No newline at end of file
diff --git a/db/schema_migrations/20230202211434 b/db/schema_migrations/20230202211434
new file mode 100644
index 00000000000..8389c248548
--- /dev/null
+++ b/db/schema_migrations/20230202211434
@@ -0,0 +1 @@
+be43b7dd3fffd70b9d1ee5a7c1950c938674f2bf1dfb23d0a709a46be2005b8c \ No newline at end of file
diff --git a/db/schema_migrations/20230208125736 b/db/schema_migrations/20230208125736
new file mode 100644
index 00000000000..bad75a7ffbe
--- /dev/null
+++ b/db/schema_migrations/20230208125736
@@ -0,0 +1 @@
+ce2100af8a397f9d2acfcdb9d8e4fefd82c42cecc78b1e762812738622bf76a9 \ No newline at end of file
diff --git a/db/schema_migrations/20230210152109 b/db/schema_migrations/20230210152109
new file mode 100644
index 00000000000..cc158d38529
--- /dev/null
+++ b/db/schema_migrations/20230210152109
@@ -0,0 +1 @@
+ed74efe6b6c5428f5d1be55d1ea4d11dfb23623d092483d0d474e82312379335 \ No newline at end of file
diff --git a/db/schema_migrations/20230210153420 b/db/schema_migrations/20230210153420
new file mode 100644
index 00000000000..8ace16a1e67
--- /dev/null
+++ b/db/schema_migrations/20230210153420
@@ -0,0 +1 @@
+07d3ef18df7faefc3b86d14b37b7254ab3301392053bbe322622be8a74a56f94 \ No newline at end of file
diff --git a/db/schema_migrations/20230210155715 b/db/schema_migrations/20230210155715
new file mode 100644
index 00000000000..68ff0072b83
--- /dev/null
+++ b/db/schema_migrations/20230210155715
@@ -0,0 +1 @@
+7d0b2686ec505eb7b08df119cbb8a3c1cf033d708050de474d627df68e72c3b4 \ No newline at end of file
diff --git a/db/schema_migrations/20230210160037 b/db/schema_migrations/20230210160037
new file mode 100644
index 00000000000..f9a1697411b
--- /dev/null
+++ b/db/schema_migrations/20230210160037
@@ -0,0 +1 @@
+db0d359d329b7578c676ee137380b53d84c77c5699adb76243eb25eceda7e7e5 \ No newline at end of file
diff --git a/db/schema_migrations/20230210160351 b/db/schema_migrations/20230210160351
new file mode 100644
index 00000000000..534b07f4371
--- /dev/null
+++ b/db/schema_migrations/20230210160351
@@ -0,0 +1 @@
+0504365806c9692fff3e9aa32e371a3ddacaf8a26549929e45e271dac60992ac \ No newline at end of file
diff --git a/db/schema_migrations/20230210161002 b/db/schema_migrations/20230210161002
new file mode 100644
index 00000000000..4ba016dc519
--- /dev/null
+++ b/db/schema_migrations/20230210161002
@@ -0,0 +1 @@
+9d300a27b9c5f3e1b157d5b741c605d9a8d80a886a0a574a5946addfc0ef4998 \ No newline at end of file
diff --git a/db/schema_migrations/20230210171012 b/db/schema_migrations/20230210171012
new file mode 100644
index 00000000000..e026a7fffa9
--- /dev/null
+++ b/db/schema_migrations/20230210171012
@@ -0,0 +1 @@
+f769362c0836821687c46f824e13b30ef7c8686eebf62da8f3e8a7d3c66c0f01 \ No newline at end of file
diff --git a/db/schema_migrations/20230213103019 b/db/schema_migrations/20230213103019
new file mode 100644
index 00000000000..e28052b7f58
--- /dev/null
+++ b/db/schema_migrations/20230213103019
@@ -0,0 +1 @@
+23979065610c4f361a639cdcf81e7ce491d111ed3752bd11081f9645b31e21f6 \ No newline at end of file
diff --git a/db/schema_migrations/20230213213559 b/db/schema_migrations/20230213213559
new file mode 100644
index 00000000000..cfe68dc78e4
--- /dev/null
+++ b/db/schema_migrations/20230213213559
@@ -0,0 +1 @@
+bd11c9514186437d2929b32f034256ee2442cf839b0bc6e64490ecff9978d017 \ No newline at end of file
diff --git a/db/schema_migrations/20230214181633 b/db/schema_migrations/20230214181633
new file mode 100644
index 00000000000..76d4cf10b5c
--- /dev/null
+++ b/db/schema_migrations/20230214181633
@@ -0,0 +1 @@
+a8c815d1d85a6690755623b53e15e5fb73f7e6be6a24ead3532f21d21c1de20f \ No newline at end of file
diff --git a/db/schema_migrations/20230215074223 b/db/schema_migrations/20230215074223
new file mode 100644
index 00000000000..db68438eaae
--- /dev/null
+++ b/db/schema_migrations/20230215074223
@@ -0,0 +1 @@
+c63c7e4cdb985d4607f442c9728a5b2699d6112054c03571cc47684af435c249 \ No newline at end of file
diff --git a/db/schema_migrations/20230215124011 b/db/schema_migrations/20230215124011
new file mode 100644
index 00000000000..88911b9faaf
--- /dev/null
+++ b/db/schema_migrations/20230215124011
@@ -0,0 +1 @@
+e8449ee3c54eb3ec1c4f2e302e7fceda950a16eb2bf57b0cd77ed955ad314eee \ No newline at end of file
diff --git a/db/schema_migrations/20230215131026 b/db/schema_migrations/20230215131026
new file mode 100644
index 00000000000..3bec8e04f4f
--- /dev/null
+++ b/db/schema_migrations/20230215131026
@@ -0,0 +1 @@
+095cc516f50dcb11e01ccda962a9776fddcec439520cef795f6c8715b5941aba \ No newline at end of file
diff --git a/db/schema_migrations/20230215180605 b/db/schema_migrations/20230215180605
new file mode 100644
index 00000000000..a3b222de10f
--- /dev/null
+++ b/db/schema_migrations/20230215180605
@@ -0,0 +1 @@
+879bee488f4089527de02ebfd6c9d6f6de7ab24d87361e29f998d86b62ca7461 \ No newline at end of file
diff --git a/db/schema_migrations/20230215213349 b/db/schema_migrations/20230215213349
new file mode 100644
index 00000000000..0512fd3c7ea
--- /dev/null
+++ b/db/schema_migrations/20230215213349
@@ -0,0 +1 @@
+9b8521de286e8c363497c7854c530c7fcaf5aecb193a89addf7e15704ae271f9 \ No newline at end of file
diff --git a/db/schema_migrations/20230216040505 b/db/schema_migrations/20230216040505
new file mode 100644
index 00000000000..d3cc858827f
--- /dev/null
+++ b/db/schema_migrations/20230216040505
@@ -0,0 +1 @@
+c6a905e29792b88f87810d267a4472886e0a1a22fe9531e3d7998abbd1035552 \ No newline at end of file
diff --git a/db/schema_migrations/20230216060333 b/db/schema_migrations/20230216060333
new file mode 100644
index 00000000000..5f9fa26b1f0
--- /dev/null
+++ b/db/schema_migrations/20230216060333
@@ -0,0 +1 @@
+c06d80c04bd661805f066412d750a651a0ead053cfff0e3314c03b3846a3f36d \ No newline at end of file
diff --git a/db/schema_migrations/20230216071312 b/db/schema_migrations/20230216071312
new file mode 100644
index 00000000000..2e92ecc19e6
--- /dev/null
+++ b/db/schema_migrations/20230216071312
@@ -0,0 +1 @@
+204503fcf9e5da7255677a9a82f11e860410048efc1ed75cc7ba97b3cdd273c3 \ No newline at end of file
diff --git a/db/schema_migrations/20230216142836 b/db/schema_migrations/20230216142836
new file mode 100644
index 00000000000..7f7d8230327
--- /dev/null
+++ b/db/schema_migrations/20230216142836
@@ -0,0 +1 @@
+8b8b1a55b2f82b4dc0dcbb2b618dbc4dabdcb21d091cd98f19c68cc6fb4fa493 \ No newline at end of file
diff --git a/db/schema_migrations/20230216144719 b/db/schema_migrations/20230216144719
new file mode 100644
index 00000000000..01ad731d72f
--- /dev/null
+++ b/db/schema_migrations/20230216144719
@@ -0,0 +1 @@
+cc74cddc9851a56cc98df1947ea1ea539358e9959b5c8f79aa1cea44979760b2 \ No newline at end of file
diff --git a/db/schema_migrations/20230216152912 b/db/schema_migrations/20230216152912
new file mode 100644
index 00000000000..e9f1dfb9db3
--- /dev/null
+++ b/db/schema_migrations/20230216152912
@@ -0,0 +1 @@
+66b74e0442763b2a05ec411344d8ca97b7d3d2e8cef9d2e04baba246b1c025a2 \ No newline at end of file
diff --git a/db/schema_migrations/20230216171309 b/db/schema_migrations/20230216171309
new file mode 100644
index 00000000000..1e25ca0d3b1
--- /dev/null
+++ b/db/schema_migrations/20230216171309
@@ -0,0 +1 @@
+ee00d6aba8a310c236dd16749228a42589657d060bbf1785c4358bf886fd59cc \ No newline at end of file
diff --git a/db/schema_migrations/20230216191507 b/db/schema_migrations/20230216191507
new file mode 100644
index 00000000000..7bc18f2fe42
--- /dev/null
+++ b/db/schema_migrations/20230216191507
@@ -0,0 +1 @@
+71a2a98341e2ee32e0ee9706854378e2b6bbda8af1ac7f325b770cf5ff67738f \ No newline at end of file
diff --git a/db/schema_migrations/20230216222956 b/db/schema_migrations/20230216222956
new file mode 100644
index 00000000000..a93e0602cd6
--- /dev/null
+++ b/db/schema_migrations/20230216222956
@@ -0,0 +1 @@
+6ebeadf8259911352813166646645320c3a238a68c1e8a4a97baa51b2bd182dd \ No newline at end of file
diff --git a/db/schema_migrations/20230216232404 b/db/schema_migrations/20230216232404
new file mode 100644
index 00000000000..e2fd3d7ae1f
--- /dev/null
+++ b/db/schema_migrations/20230216232404
@@ -0,0 +1 @@
+df059ad89887390a792f292b7062a2f04d901a049c2acea7b8ddaff677b8c9d5 \ No newline at end of file
diff --git a/db/schema_migrations/20230216233937 b/db/schema_migrations/20230216233937
new file mode 100644
index 00000000000..d3c85c7c981
--- /dev/null
+++ b/db/schema_migrations/20230216233937
@@ -0,0 +1 @@
+5088eccec1327f61cb80c5fca4f7e7710534179c2d6bf820f7021dfd079d51a5 \ No newline at end of file
diff --git a/db/schema_migrations/20230217065736 b/db/schema_migrations/20230217065736
new file mode 100644
index 00000000000..a355b107c40
--- /dev/null
+++ b/db/schema_migrations/20230217065736
@@ -0,0 +1 @@
+c772f3d2b46d48bfae68f2b420d38851ecea3105029e5154a58bed29359393f2 \ No newline at end of file
diff --git a/db/schema_migrations/20230217144421 b/db/schema_migrations/20230217144421
new file mode 100644
index 00000000000..1ab17fcfa99
--- /dev/null
+++ b/db/schema_migrations/20230217144421
@@ -0,0 +1 @@
+9a2ecdf9c37b13ebe5666ebadf2f27d4f52a0615337faaef221ff4fc6ae08cc4 \ No newline at end of file
diff --git a/db/schema_migrations/20230217232554 b/db/schema_migrations/20230217232554
new file mode 100644
index 00000000000..501e10db401
--- /dev/null
+++ b/db/schema_migrations/20230217232554
@@ -0,0 +1 @@
+56880a7008d06e9a30337cca7affbe4cdb796b8ef1ccc8b3fc8503af172281cb \ No newline at end of file
diff --git a/db/schema_migrations/20230218145930 b/db/schema_migrations/20230218145930
new file mode 100644
index 00000000000..17e1cb01703
--- /dev/null
+++ b/db/schema_migrations/20230218145930
@@ -0,0 +1 @@
+63c47c7a879d54b4773f672ce8b771b3d416d44740b4a56c2cc05d4486daffab \ No newline at end of file
diff --git a/db/schema_migrations/20230218145940 b/db/schema_migrations/20230218145940
new file mode 100644
index 00000000000..0017b48bd5c
--- /dev/null
+++ b/db/schema_migrations/20230218145940
@@ -0,0 +1 @@
+3e3fcc5b0f186e722dbd2fe7b89cd1d32c59830bc66e7efb3fe1513f9fa2ba03 \ No newline at end of file
diff --git a/db/schema_migrations/20230218152729 b/db/schema_migrations/20230218152729
new file mode 100644
index 00000000000..f78be055435
--- /dev/null
+++ b/db/schema_migrations/20230218152729
@@ -0,0 +1 @@
+ac404c1dd1b2a38b8d02563b4b9306076f35120448d78b130c0421364c11822c \ No newline at end of file
diff --git a/db/schema_migrations/20230218152730 b/db/schema_migrations/20230218152730
new file mode 100644
index 00000000000..55fb6069403
--- /dev/null
+++ b/db/schema_migrations/20230218152730
@@ -0,0 +1 @@
+f85595c6176426369f8558ba3dadf6ee2a5efa17f2d304dc8397862fc7d52545 \ No newline at end of file
diff --git a/db/schema_migrations/20230219191034 b/db/schema_migrations/20230219191034
new file mode 100644
index 00000000000..911869229b3
--- /dev/null
+++ b/db/schema_migrations/20230219191034
@@ -0,0 +1 @@
+f3be6612c3669066d9a805bf56cae7b3f9a1b6bdaee1bdb3e3f9a596ed3cecef \ No newline at end of file
diff --git a/db/schema_migrations/20230220035034 b/db/schema_migrations/20230220035034
new file mode 100644
index 00000000000..4cb8be66d8f
--- /dev/null
+++ b/db/schema_migrations/20230220035034
@@ -0,0 +1 @@
+f5636e464b16bfc201a3f3a21269c6d8686d2bc829aa80491bea120fd10e138a \ No newline at end of file
diff --git a/db/schema_migrations/20230220102212 b/db/schema_migrations/20230220102212
new file mode 100644
index 00000000000..a4432c7b517
--- /dev/null
+++ b/db/schema_migrations/20230220102212
@@ -0,0 +1 @@
+7df50689f7e9311ee8e5bd2513f4361be0fceef3962344d2d16bf511132c7a33 \ No newline at end of file
diff --git a/db/schema_migrations/20230220112930 b/db/schema_migrations/20230220112930
new file mode 100644
index 00000000000..0852b3fe5f7
--- /dev/null
+++ b/db/schema_migrations/20230220112930
@@ -0,0 +1 @@
+b58d0cf5df91d7abc4ba7ef4a1257f03aa6e9849624d43728ca0e008c5710e7c \ No newline at end of file
diff --git a/db/schema_migrations/20230220132409 b/db/schema_migrations/20230220132409
new file mode 100644
index 00000000000..417675aaf27
--- /dev/null
+++ b/db/schema_migrations/20230220132409
@@ -0,0 +1 @@
+b2aee06140d97dd9cd5d694b5d8538db92279aeba9e0e64375052ff455246647 \ No newline at end of file
diff --git a/db/schema_migrations/20230220132410 b/db/schema_migrations/20230220132410
new file mode 100644
index 00000000000..39ee3040802
--- /dev/null
+++ b/db/schema_migrations/20230220132410
@@ -0,0 +1 @@
+42814e8ab1b2ebb197f877736f8c9dddf5b9416c22f9c800c7a9d33cde164dd6 \ No newline at end of file
diff --git a/db/schema_migrations/20230220134145 b/db/schema_migrations/20230220134145
new file mode 100644
index 00000000000..91238639d78
--- /dev/null
+++ b/db/schema_migrations/20230220134145
@@ -0,0 +1 @@
+d20d4bd35b5e4132515c731e7df802c0fd6f3e88d4bee2d3b9fe42af4307977c \ No newline at end of file
diff --git a/db/schema_migrations/20230220134146 b/db/schema_migrations/20230220134146
new file mode 100644
index 00000000000..3d0745d3f22
--- /dev/null
+++ b/db/schema_migrations/20230220134146
@@ -0,0 +1 @@
+7fe8e5e2e9019ccb29f29df161f7b7c45aa2576188b326e60f758dd2d5f56a47 \ No newline at end of file
diff --git a/db/schema_migrations/20230220163141 b/db/schema_migrations/20230220163141
new file mode 100644
index 00000000000..ac2e348448d
--- /dev/null
+++ b/db/schema_migrations/20230220163141
@@ -0,0 +1 @@
+5f0c9945aaf1f34cb9c79b6c3634f4fd44ac538469b3f97147be67a6f16c0c75 \ No newline at end of file
diff --git a/db/schema_migrations/20230220165240 b/db/schema_migrations/20230220165240
new file mode 100644
index 00000000000..14cd3554464
--- /dev/null
+++ b/db/schema_migrations/20230220165240
@@ -0,0 +1 @@
+754b55e9465719edb5058c97cacf1f369347e15c7e6d7fa30dcbe5abd8addcae \ No newline at end of file
diff --git a/db/schema_migrations/20230221010522 b/db/schema_migrations/20230221010522
new file mode 100644
index 00000000000..57727695f5e
--- /dev/null
+++ b/db/schema_migrations/20230221010522
@@ -0,0 +1 @@
+474f2b46179134270dc65c2b32ef9acfb01edb976f5efefe9ab49352d3fc390f \ No newline at end of file
diff --git a/db/schema_migrations/20230221011750 b/db/schema_migrations/20230221011750
new file mode 100644
index 00000000000..9f43d53a1b2
--- /dev/null
+++ b/db/schema_migrations/20230221011750
@@ -0,0 +1 @@
+cca7c1c232fa56e85bb0fc120a5920f3cb75d0fea2657ed2e81a4fe69349134a \ No newline at end of file
diff --git a/db/schema_migrations/20230221093533 b/db/schema_migrations/20230221093533
new file mode 100644
index 00000000000..1d9ac2c72b4
--- /dev/null
+++ b/db/schema_migrations/20230221093533
@@ -0,0 +1 @@
+6a3453275435ebad3269b81f10bc75bf3aeb92f8c9a6769743acf2af78a1dc69 \ No newline at end of file
diff --git a/db/schema_migrations/20230221110256 b/db/schema_migrations/20230221110256
new file mode 100644
index 00000000000..2448c317588
--- /dev/null
+++ b/db/schema_migrations/20230221110256
@@ -0,0 +1 @@
+661fdc00029ab9bae8b4da6a8d92f172db89087aecc13f3ad65b2b3e8ad501d3 \ No newline at end of file
diff --git a/db/schema_migrations/20230221125148 b/db/schema_migrations/20230221125148
new file mode 100644
index 00000000000..35ec9b066bc
--- /dev/null
+++ b/db/schema_migrations/20230221125148
@@ -0,0 +1 @@
+f64a3cb1963dde07eaaae9d331ebf1e5e52050435b38f9b6727a53f04808b723 \ No newline at end of file
diff --git a/db/schema_migrations/20230221162222 b/db/schema_migrations/20230221162222
new file mode 100644
index 00000000000..be6d9c407b1
--- /dev/null
+++ b/db/schema_migrations/20230221162222
@@ -0,0 +1 @@
+f0fd872c7999879be5d433881e20855cc8e2418625374fc095cc74172b9f08c5 \ No newline at end of file
diff --git a/db/schema_migrations/20230221214519 b/db/schema_migrations/20230221214519
new file mode 100644
index 00000000000..aa630e64644
--- /dev/null
+++ b/db/schema_migrations/20230221214519
@@ -0,0 +1 @@
+b8eccb700af0593b94e26e0fbe8b4c680b9bae47ced111422dc400159a3f6b12 \ No newline at end of file
diff --git a/db/schema_migrations/20230222035805 b/db/schema_migrations/20230222035805
new file mode 100644
index 00000000000..a0dadf5c43a
--- /dev/null
+++ b/db/schema_migrations/20230222035805
@@ -0,0 +1 @@
+ffc433ce994ab67af36dfeddd19a29d8c35379f30c9a95c8bb2d0f3c7774e612 \ No newline at end of file
diff --git a/db/schema_migrations/20230222055510 b/db/schema_migrations/20230222055510
new file mode 100644
index 00000000000..5abc44779d9
--- /dev/null
+++ b/db/schema_migrations/20230222055510
@@ -0,0 +1 @@
+ff8b8d5448460302449025fc79cec95d0d3ae2eb335e9f786031d39caacf631a \ No newline at end of file
diff --git a/db/schema_migrations/20230222101420 b/db/schema_migrations/20230222101420
new file mode 100644
index 00000000000..f0cd65454ac
--- /dev/null
+++ b/db/schema_migrations/20230222101420
@@ -0,0 +1 @@
+74413d13062dd7a48d07f9839b4a22db3f7358cffda403a036dfa1686fb693c8 \ No newline at end of file
diff --git a/db/schema_migrations/20230222102421 b/db/schema_migrations/20230222102421
new file mode 100644
index 00000000000..2b186e0e34a
--- /dev/null
+++ b/db/schema_migrations/20230222102421
@@ -0,0 +1 @@
+52ca4df8ee309791bb7fc4078a1298555b962137f1d07585e361b008d591164c \ No newline at end of file
diff --git a/db/schema_migrations/20230222153048 b/db/schema_migrations/20230222153048
new file mode 100644
index 00000000000..66347d3252f
--- /dev/null
+++ b/db/schema_migrations/20230222153048
@@ -0,0 +1 @@
+ff11462b7e827b0ae66f54b131fa0d4099a6e7cc768fc9b400ee36346d1773fa \ No newline at end of file
diff --git a/db/schema_migrations/20230222193845 b/db/schema_migrations/20230222193845
new file mode 100644
index 00000000000..eaf26ae70f1
--- /dev/null
+++ b/db/schema_migrations/20230222193845
@@ -0,0 +1 @@
+b70150d44ca3f029fe987831a880017be9e8cd8f7833e6d4d3bb68929130b614 \ No newline at end of file
diff --git a/db/schema_migrations/20230223014251 b/db/schema_migrations/20230223014251
new file mode 100644
index 00000000000..7613e540112
--- /dev/null
+++ b/db/schema_migrations/20230223014251
@@ -0,0 +1 @@
+1d43fc6bfb88caf86d02b83c944c143bc87142a49f3fe1ec4c54e29c960060c5 \ No newline at end of file
diff --git a/db/schema_migrations/20230223065753 b/db/schema_migrations/20230223065753
new file mode 100644
index 00000000000..c1b7927515f
--- /dev/null
+++ b/db/schema_migrations/20230223065753
@@ -0,0 +1 @@
+789d72eef2573834bef2a2d20070000b580eba069c45f97fdec18a4d5af99605 \ No newline at end of file
diff --git a/db/schema_migrations/20230223082752 b/db/schema_migrations/20230223082752
new file mode 100644
index 00000000000..83789c7ffe8
--- /dev/null
+++ b/db/schema_migrations/20230223082752
@@ -0,0 +1 @@
+53f1003eeb8f961b37d90c73a71f75683077b9bcd0e495395033998530a363bd \ No newline at end of file
diff --git a/db/schema_migrations/20230223093704 b/db/schema_migrations/20230223093704
new file mode 100644
index 00000000000..bd35f5c493e
--- /dev/null
+++ b/db/schema_migrations/20230223093704
@@ -0,0 +1 @@
+39a17836884a6c07ff3f9df6e7328473f1dc2ac2d407f615821d29958f9b1808 \ No newline at end of file
diff --git a/db/schema_migrations/20230224085743 b/db/schema_migrations/20230224085743
new file mode 100644
index 00000000000..bda82e5e10c
--- /dev/null
+++ b/db/schema_migrations/20230224085743
@@ -0,0 +1 @@
+e6deb8645468ab4e90487211b14d5432b26fb4c06635b333776c1ac175187444 \ No newline at end of file
diff --git a/db/schema_migrations/20230224130315 b/db/schema_migrations/20230224130315
new file mode 100644
index 00000000000..44960762a62
--- /dev/null
+++ b/db/schema_migrations/20230224130315
@@ -0,0 +1 @@
+e54ddd26174440b453482d4c3d2dd8aa8cacbb2697162d9f976ed52a0d55f1a0 \ No newline at end of file
diff --git a/db/schema_migrations/20230224144233 b/db/schema_migrations/20230224144233
new file mode 100644
index 00000000000..ce588827227
--- /dev/null
+++ b/db/schema_migrations/20230224144233
@@ -0,0 +1 @@
+ec6c176dc707bcaa39747fb23add886c711e075b22823174bc9f0ebee2ec224e \ No newline at end of file
diff --git a/db/schema_migrations/20230224161346 b/db/schema_migrations/20230224161346
new file mode 100644
index 00000000000..1c939bdafaf
--- /dev/null
+++ b/db/schema_migrations/20230224161346
@@ -0,0 +1 @@
+191d7be803e9e3a2a5292bbcd562c34a67c07b73da2c429ac2f115b28d04f00c \ No newline at end of file
diff --git a/db/schema_migrations/20230227123949 b/db/schema_migrations/20230227123949
new file mode 100644
index 00000000000..ab216ad946c
--- /dev/null
+++ b/db/schema_migrations/20230227123949
@@ -0,0 +1 @@
+cf72b9c6cd86bf0fbb0599f16bfcfd360567a8cdf30275ba59c1aeaba8317f2a \ No newline at end of file
diff --git a/db/schema_migrations/20230227123950 b/db/schema_migrations/20230227123950
new file mode 100644
index 00000000000..e2b8672fb3f
--- /dev/null
+++ b/db/schema_migrations/20230227123950
@@ -0,0 +1 @@
+d7f195e2cb4ab9f7f4637ba7667605eea02e66ea417b4ae496a1acae9931be84 \ No newline at end of file
diff --git a/db/schema_migrations/20230227151608 b/db/schema_migrations/20230227151608
new file mode 100644
index 00000000000..333d71b1789
--- /dev/null
+++ b/db/schema_migrations/20230227151608
@@ -0,0 +1 @@
+b43ebf61392e2857bd38f783f1ae46c4adce76a94dd8e7aa64fc02f234991229 \ No newline at end of file
diff --git a/db/schema_migrations/20230227151609 b/db/schema_migrations/20230227151609
new file mode 100644
index 00000000000..ec320e3c256
--- /dev/null
+++ b/db/schema_migrations/20230227151609
@@ -0,0 +1 @@
+c2ac227a2e1a51423b043db9e992a519c096af8a309d3c1074fbd8bd744b4e3b \ No newline at end of file
diff --git a/db/schema_migrations/20230227153231 b/db/schema_migrations/20230227153231
new file mode 100644
index 00000000000..18e685b52b0
--- /dev/null
+++ b/db/schema_migrations/20230227153231
@@ -0,0 +1 @@
+a4ae1dd4a14b977302c61d0731e9d350fbdc089a909ca3151fb4b9699b0efbb8 \ No newline at end of file
diff --git a/db/schema_migrations/20230227153232 b/db/schema_migrations/20230227153232
new file mode 100644
index 00000000000..c605a0f5754
--- /dev/null
+++ b/db/schema_migrations/20230227153232
@@ -0,0 +1 @@
+a9082aa6b8cb86be9534fe41db5790b6cca876e6fcc284daf8e5b3163b92bd06 \ No newline at end of file
diff --git a/db/schema_migrations/20230228021910 b/db/schema_migrations/20230228021910
new file mode 100644
index 00000000000..813f8efc809
--- /dev/null
+++ b/db/schema_migrations/20230228021910
@@ -0,0 +1 @@
+2be11b13b0776de4185232030374e16f0e6fdb5e21cfb6e546f2b8e5c6126547 \ No newline at end of file
diff --git a/db/schema_migrations/20230228023014 b/db/schema_migrations/20230228023014
new file mode 100644
index 00000000000..39348c9471f
--- /dev/null
+++ b/db/schema_migrations/20230228023014
@@ -0,0 +1 @@
+68de7109072a6c6769d59100e5d17f2c35027cedfa365e8506951d985283f36b \ No newline at end of file
diff --git a/db/schema_migrations/20230228092612 b/db/schema_migrations/20230228092612
new file mode 100644
index 00000000000..ad52eedb797
--- /dev/null
+++ b/db/schema_migrations/20230228092612
@@ -0,0 +1 @@
+79c17f4dfb9a208057562c8a9898fda4c1fa8819a3b7a1e594037fd8263aba6f \ No newline at end of file
diff --git a/db/schema_migrations/20230228133011 b/db/schema_migrations/20230228133011
new file mode 100644
index 00000000000..cd0c683fbcf
--- /dev/null
+++ b/db/schema_migrations/20230228133011
@@ -0,0 +1 @@
+ab33a8ef7080890c31a51c6f2455399ccb17a43595c305d15b2b884b28803860 \ No newline at end of file
diff --git a/db/schema_migrations/20230228135034 b/db/schema_migrations/20230228135034
new file mode 100644
index 00000000000..13f007f7989
--- /dev/null
+++ b/db/schema_migrations/20230228135034
@@ -0,0 +1 @@
+3a704331dd2b45c202a42e188ee3ef9a0721b5798d218f5d3300fc18632201b6 \ No newline at end of file
diff --git a/db/schema_migrations/20230228142350 b/db/schema_migrations/20230228142350
new file mode 100644
index 00000000000..cd783d44b2a
--- /dev/null
+++ b/db/schema_migrations/20230228142350
@@ -0,0 +1 @@
+ae4c6d6d477f073981f9f4e431bcb93289cfb54569a3dc982434a2e805c7801b \ No newline at end of file
diff --git a/db/schema_migrations/20230228212427 b/db/schema_migrations/20230228212427
new file mode 100644
index 00000000000..1bad198ce7c
--- /dev/null
+++ b/db/schema_migrations/20230228212427
@@ -0,0 +1 @@
+78b4d88f861f65ece401f6207a12e4edd16e686ca15180eb9526014bf575084e \ No newline at end of file
diff --git a/db/schema_migrations/20230228212905 b/db/schema_migrations/20230228212905
new file mode 100644
index 00000000000..2465e5ce9a9
--- /dev/null
+++ b/db/schema_migrations/20230228212905
@@ -0,0 +1 @@
+63e7999f522a2fc4f220062b5424d711e985a3b78fc2aee3d7afcfe2f3514d73 \ No newline at end of file
diff --git a/db/schema_migrations/20230301065107 b/db/schema_migrations/20230301065107
new file mode 100644
index 00000000000..495cefad9d2
--- /dev/null
+++ b/db/schema_migrations/20230301065107
@@ -0,0 +1 @@
+7e464616bdef6e225fdd31db84c4c32e223dffb81e13f1d6a5c85c2cd0a16144 \ No newline at end of file
diff --git a/db/schema_migrations/20230302090155 b/db/schema_migrations/20230302090155
new file mode 100644
index 00000000000..af86ce4635d
--- /dev/null
+++ b/db/schema_migrations/20230302090155
@@ -0,0 +1 @@
+52b9428336c506a0bf698ea03215dd2b279b9e7d2ca56936df094aaad7934f96 \ No newline at end of file
diff --git a/db/schema_migrations/20230302123258 b/db/schema_migrations/20230302123258
new file mode 100644
index 00000000000..b4fe3ae9f34
--- /dev/null
+++ b/db/schema_migrations/20230302123258
@@ -0,0 +1 @@
+ecb6f601d4f47e7c4974e097c0e87ff37f96fad93b2ab02439bfa44a7eb481cd \ No newline at end of file
diff --git a/db/schema_migrations/20230302123259 b/db/schema_migrations/20230302123259
new file mode 100644
index 00000000000..6ef93fc8c73
--- /dev/null
+++ b/db/schema_migrations/20230302123259
@@ -0,0 +1 @@
+671fe2bcc6b45d7f312144d6c1ceb7c5e085dbc1ab1069c5a340849a08437d72 \ No newline at end of file
diff --git a/db/schema_migrations/20230302123301 b/db/schema_migrations/20230302123301
new file mode 100644
index 00000000000..d9af7fe9b69
--- /dev/null
+++ b/db/schema_migrations/20230302123301
@@ -0,0 +1 @@
+ca0e0d645cfd5f672d286e8977fc94d4c92579801cb4a781c495465cbc581a33 \ No newline at end of file
diff --git a/db/schema_migrations/20230302163339 b/db/schema_migrations/20230302163339
new file mode 100644
index 00000000000..25c611e57a6
--- /dev/null
+++ b/db/schema_migrations/20230302163339
@@ -0,0 +1 @@
+5cb36884c6422f9cf2db27c7922a8835b1db6d15e629066ca825c93df7437afa \ No newline at end of file
diff --git a/db/schema_migrations/20230302185739 b/db/schema_migrations/20230302185739
new file mode 100644
index 00000000000..a9f2426e7d9
--- /dev/null
+++ b/db/schema_migrations/20230302185739
@@ -0,0 +1 @@
+92b302a4fec802bb418f8a844f70c678af70cc9607331533392ce4b6e830e8d7 \ No newline at end of file
diff --git a/db/schema_migrations/20230303105806 b/db/schema_migrations/20230303105806
new file mode 100644
index 00000000000..46bf8fb2b2b
--- /dev/null
+++ b/db/schema_migrations/20230303105806
@@ -0,0 +1 @@
+5f2176abfc462e65c9ef2b9b28c9feb60cac868aa491d4d4207a8904deb60f18 \ No newline at end of file
diff --git a/db/schema_migrations/20230303120531 b/db/schema_migrations/20230303120531
new file mode 100644
index 00000000000..5c042677e67
--- /dev/null
+++ b/db/schema_migrations/20230303120531
@@ -0,0 +1 @@
+6af890fe88f25be54d18cf3b3caa14830a3d627e7ff256d7a4ae03f9f1c7170c \ No newline at end of file
diff --git a/db/schema_migrations/20230303144424 b/db/schema_migrations/20230303144424
new file mode 100644
index 00000000000..f0684710508
--- /dev/null
+++ b/db/schema_migrations/20230303144424
@@ -0,0 +1 @@
+c8ea35db8903fb627b3ed68b9d9a1e78c34ab40a5aed6fe19e329d13e371f652 \ No newline at end of file
diff --git a/db/schema_migrations/20230303154314 b/db/schema_migrations/20230303154314
new file mode 100644
index 00000000000..30a33a6efba
--- /dev/null
+++ b/db/schema_migrations/20230303154314
@@ -0,0 +1 @@
+c18a674b6df4baf6d81177df2eb4497dc73979ff71142a9ecda71ec515a588b4 \ No newline at end of file
diff --git a/db/schema_migrations/20230304184416 b/db/schema_migrations/20230304184416
new file mode 100644
index 00000000000..908fcd3bbc7
--- /dev/null
+++ b/db/schema_migrations/20230304184416
@@ -0,0 +1 @@
+c6c361ae0fea1ac200e0b4a6683bc9ff853ffb1f890f0555fe921ce72d2453f5 \ No newline at end of file
diff --git a/db/schema_migrations/20230306071456 b/db/schema_migrations/20230306071456
new file mode 100644
index 00000000000..b4ac086f125
--- /dev/null
+++ b/db/schema_migrations/20230306071456
@@ -0,0 +1 @@
+7f431d6dd4f9dc237623c18465995fa59c9902187f433375baa03194f7a6b88f \ No newline at end of file
diff --git a/db/schema_migrations/20230306072532 b/db/schema_migrations/20230306072532
new file mode 100644
index 00000000000..f1604aa84a7
--- /dev/null
+++ b/db/schema_migrations/20230306072532
@@ -0,0 +1 @@
+f6613d1fd3b99fa0e8ea059c6d53e8d226ce3fd8c07e44a024b065d8d110876f \ No newline at end of file
diff --git a/db/schema_migrations/20230306082852 b/db/schema_migrations/20230306082852
new file mode 100644
index 00000000000..bbbe7cb27ef
--- /dev/null
+++ b/db/schema_migrations/20230306082852
@@ -0,0 +1 @@
+580efa96f235c47de1bcea172544e51e8207dd0a81bd888567b30ce02e453f7d \ No newline at end of file
diff --git a/db/schema_migrations/20230306143322 b/db/schema_migrations/20230306143322
new file mode 100644
index 00000000000..d1b5080398c
--- /dev/null
+++ b/db/schema_migrations/20230306143322
@@ -0,0 +1 @@
+0f6c5bfbad3779c6d20984fb29e5494cf4c46d7992e1fa3f8a705913aa0f3b92 \ No newline at end of file
diff --git a/db/schema_migrations/20230306145230 b/db/schema_migrations/20230306145230
new file mode 100644
index 00000000000..d0fa5e5634b
--- /dev/null
+++ b/db/schema_migrations/20230306145230
@@ -0,0 +1 @@
+ca28b1355e5cc8c1e77c85a4d5e6a40b66767a8588068eb7e1528ba0e575f5da \ No newline at end of file
diff --git a/db/schema_migrations/20230306195007 b/db/schema_migrations/20230306195007
new file mode 100644
index 00000000000..bb28fbc5586
--- /dev/null
+++ b/db/schema_migrations/20230306195007
@@ -0,0 +1 @@
+f799b921663f3de04e0b8f5017305e186c4e418392256adf33f2408ea6d8d2ca \ No newline at end of file
diff --git a/db/schema_migrations/20230307085644 b/db/schema_migrations/20230307085644
new file mode 100644
index 00000000000..7176a19a788
--- /dev/null
+++ b/db/schema_migrations/20230307085644
@@ -0,0 +1 @@
+2b918f516a004d3b3f1b310ad9421a29a9675a7670f6a653ba73209f8e7f0f41 \ No newline at end of file
diff --git a/db/schema_migrations/20230307091216 b/db/schema_migrations/20230307091216
new file mode 100644
index 00000000000..4727747daa7
--- /dev/null
+++ b/db/schema_migrations/20230307091216
@@ -0,0 +1 @@
+0c13f0053959e1c3e66f0c87d55d4a9190b36d61f67bb1b3ec32f73fa699c961 \ No newline at end of file
diff --git a/db/schema_migrations/20230307122838 b/db/schema_migrations/20230307122838
new file mode 100644
index 00000000000..adf5d84a474
--- /dev/null
+++ b/db/schema_migrations/20230307122838
@@ -0,0 +1 @@
+5b147e92d42b7ec317106d905a3af4d1aee983bce8538c26a619ad32ad06c42e \ No newline at end of file
diff --git a/db/schema_migrations/20230307160251 b/db/schema_migrations/20230307160251
new file mode 100644
index 00000000000..7265c801b46
--- /dev/null
+++ b/db/schema_migrations/20230307160251
@@ -0,0 +1 @@
+a7cf83ea7e94cc3d6a581cd89aab8274e86f5c195f1537395d72b275b96bd31c \ No newline at end of file
diff --git a/db/schema_migrations/20230307233631 b/db/schema_migrations/20230307233631
new file mode 100644
index 00000000000..c05d21f2113
--- /dev/null
+++ b/db/schema_migrations/20230307233631
@@ -0,0 +1 @@
+be9ce74f455171c265135ffc105d5c69a660cdad7f71656615b3d8caf5831b32 \ No newline at end of file
diff --git a/db/schema_migrations/20230308163018 b/db/schema_migrations/20230308163018
new file mode 100644
index 00000000000..19815455ef3
--- /dev/null
+++ b/db/schema_migrations/20230308163018
@@ -0,0 +1 @@
+f9132e8d1d39307fc4f9ef17c6e044bab636d17ae7a7e5207f26ab3e38441638 \ No newline at end of file
diff --git a/db/schema_migrations/20230309000957 b/db/schema_migrations/20230309000957
new file mode 100644
index 00000000000..679d37f153b
--- /dev/null
+++ b/db/schema_migrations/20230309000957
@@ -0,0 +1 @@
+902e921099ed27cc1c8fd36eac192879ff6c68e4aa7ef4a0764381c0a01fd76e \ No newline at end of file
diff --git a/db/schema_migrations/20230309010000 b/db/schema_migrations/20230309010000
new file mode 100644
index 00000000000..9415a4b9f11
--- /dev/null
+++ b/db/schema_migrations/20230309010000
@@ -0,0 +1 @@
+de7622f865cc6216902d1f9964a645d74777e60072efa399683cd6a9c347d27b \ No newline at end of file
diff --git a/db/schema_migrations/20230309010931 b/db/schema_migrations/20230309010931
new file mode 100644
index 00000000000..c7ac631a427
--- /dev/null
+++ b/db/schema_migrations/20230309010931
@@ -0,0 +1 @@
+1976ef23f13343f1ae85b9c9c612dc43e4f4696c9cfad1f36a54e9368ded4f20 \ No newline at end of file
diff --git a/db/schema_migrations/20230309020422 b/db/schema_migrations/20230309020422
new file mode 100644
index 00000000000..b43cc93836f
--- /dev/null
+++ b/db/schema_migrations/20230309020422
@@ -0,0 +1 @@
+51ff7181e6ae2ed88e2d2d91d3f29a53c0342c3461ea55be1bf202a85709f6c6 \ No newline at end of file
diff --git a/db/schema_migrations/20230309071242 b/db/schema_migrations/20230309071242
new file mode 100644
index 00000000000..dd29a8006b1
--- /dev/null
+++ b/db/schema_migrations/20230309071242
@@ -0,0 +1 @@
+094eb5044e841050288c7362cc58c1b63ce4a349fe49a4c5ebee6b83a05feb56 \ No newline at end of file
diff --git a/db/schema_migrations/20230309103016 b/db/schema_migrations/20230309103016
new file mode 100644
index 00000000000..fae5bcc5a72
--- /dev/null
+++ b/db/schema_migrations/20230309103016
@@ -0,0 +1 @@
+e02ad3e7cfb386560e2e4d71332f1ced4a1827941b78012d974d9abcfea368d9 \ No newline at end of file
diff --git a/db/schema_migrations/20230310111859 b/db/schema_migrations/20230310111859
new file mode 100644
index 00000000000..0bc9268a311
--- /dev/null
+++ b/db/schema_migrations/20230310111859
@@ -0,0 +1 @@
+d1accdc2bbe9aa5266df98a893176fba94148f9754d2c0b2de04e9d8d66d8eba \ No newline at end of file
diff --git a/db/schema_migrations/20230313054226 b/db/schema_migrations/20230313054226
new file mode 100644
index 00000000000..7b174fe3570
--- /dev/null
+++ b/db/schema_migrations/20230313054226
@@ -0,0 +1 @@
+15c56632eafda4ab511368001a7bbfdf9f346049ab19a9df3ad2c96adc12f1a0 \ No newline at end of file
diff --git a/db/schema_migrations/20230313100920 b/db/schema_migrations/20230313100920
new file mode 100644
index 00000000000..bb04d2a9f72
--- /dev/null
+++ b/db/schema_migrations/20230313100920
@@ -0,0 +1 @@
+e2940977e8dfc2873751ae2c4b971b2d12cf79eb644c563b901f20d2e0c51649 \ No newline at end of file
diff --git a/db/schema_migrations/20230313133001 b/db/schema_migrations/20230313133001
new file mode 100644
index 00000000000..724003e3448
--- /dev/null
+++ b/db/schema_migrations/20230313133001
@@ -0,0 +1 @@
+96220e0bd8ebc4ed6ad5478d1bc8e08760e8d301667fad3cdbd9dce689a32d87 \ No newline at end of file
diff --git a/db/schema_migrations/20230313143033 b/db/schema_migrations/20230313143033
new file mode 100644
index 00000000000..81e9dd384b9
--- /dev/null
+++ b/db/schema_migrations/20230313143033
@@ -0,0 +1 @@
+6a2ae2db3b61652bdf29a1e851d4120fb31eb21edaa2ffa6ef44415dfea928c5 \ No newline at end of file
diff --git a/db/schema_migrations/20230313150531 b/db/schema_migrations/20230313150531
new file mode 100644
index 00000000000..94625561f6b
--- /dev/null
+++ b/db/schema_migrations/20230313150531
@@ -0,0 +1 @@
+e2f19bbc322127e439fffc4c1e2718288538aa6cb2d50a5248f12470b1c9491e \ No newline at end of file
diff --git a/db/schema_migrations/20230313184306 b/db/schema_migrations/20230313184306
new file mode 100644
index 00000000000..733217f705c
--- /dev/null
+++ b/db/schema_migrations/20230313184306
@@ -0,0 +1 @@
+457c9325bb8af653b179cb04a3332746b1caf0854b555f71fe8ceb4e323e8b20 \ No newline at end of file
diff --git a/db/schema_migrations/20230313185145 b/db/schema_migrations/20230313185145
new file mode 100644
index 00000000000..6eb3908d1da
--- /dev/null
+++ b/db/schema_migrations/20230313185145
@@ -0,0 +1 @@
+a5a630c2dbd94af837bff0056ee472360646306ca1c00e66fc3f68669006cf50 \ No newline at end of file
diff --git a/db/schema_migrations/20230316014650 b/db/schema_migrations/20230316014650
new file mode 100644
index 00000000000..590de1b6748
--- /dev/null
+++ b/db/schema_migrations/20230316014650
@@ -0,0 +1 @@
+f2263525d0e7569eb2ca639b83a7fa5704aba32268570191aee0fd421010d122 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index c277291e823..d0edfc515f9 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -68,6 +68,7 @@ DECLARE
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;
@@ -82,7 +83,7 @@ BEGIN
INTO
severity, state, report_type, resolved_on_default_branch, present_on_default_branch
FROM
- vulnerabilities
+ vulnerabilities
WHERE
vulnerabilities.id = NEW.vulnerability_id;
@@ -99,8 +100,13 @@ BEGIN
WHERE
projects.id = NEW.project_id;
- 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)
- 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))
+ 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
@@ -127,6 +133,7 @@ DECLARE
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
@@ -139,8 +146,13 @@ BEGIN
v_o.vulnerability_id = NEW.id
LIMIT 1;
- 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)
- 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)
+ 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
@@ -543,6 +555,13 @@ CREATE TABLE batched_background_migration_job_transition_logs (
)
PARTITION BY RANGE (created_at);
+CREATE TABLE p_ci_runner_machine_builds (
+ partition_id bigint NOT NULL,
+ build_id bigint NOT NULL,
+ runner_machine_id bigint NOT NULL
+)
+PARTITION BY LIST (partition_id);
+
CREATE TABLE incident_management_pending_alert_escalations (
id bigint NOT NULL,
rule_id bigint NOT NULL,
@@ -10733,6 +10752,8 @@ CREATE TABLE abuse_reports (
category smallint DEFAULT 1 NOT NULL,
reported_from_url text DEFAULT ''::text NOT NULL,
links_to_spam text[] DEFAULT '{}'::text[] NOT NULL,
+ status smallint DEFAULT 1 NOT NULL,
+ resolved_at timestamp with time zone,
CONSTRAINT abuse_reports_links_to_spam_length_check CHECK ((cardinality(links_to_spam) <= 20)),
CONSTRAINT check_ab1260fa6c CHECK ((char_length(reported_from_url) <= 512))
);
@@ -10754,7 +10775,6 @@ CREATE TABLE achievements (
name text NOT NULL,
avatar text,
description text,
- revokeable boolean DEFAULT false NOT NULL,
CONSTRAINT check_5171b03f22 CHECK ((char_length(name) <= 255)),
CONSTRAINT check_a7a7b84a80 CHECK ((char_length(description) <= 1024)),
CONSTRAINT check_e174e93a9e CHECK ((char_length(avatar) <= 255))
@@ -10825,32 +10845,6 @@ CREATE SEQUENCE agent_project_authorizations_id_seq
ALTER SEQUENCE agent_project_authorizations_id_seq OWNED BY agent_project_authorizations.id;
-CREATE TABLE airflow_dags (
- 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,
- next_run timestamp with time zone,
- has_import_errors boolean,
- is_active boolean,
- is_paused boolean,
- dag_name text NOT NULL,
- schedule text,
- fileloc text,
- CONSTRAINT check_6999a61016 CHECK ((char_length(schedule) <= 255)),
- CONSTRAINT check_6f52bee3a1 CHECK ((char_length(fileloc) <= 255)),
- CONSTRAINT check_e10ac15d52 CHECK ((char_length(dag_name) <= 255))
-);
-
-CREATE SEQUENCE airflow_dags_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-ALTER SEQUENCE airflow_dags_id_seq OWNED BY airflow_dags.id;
-
CREATE TABLE alert_management_alert_assignees (
id bigint NOT NULL,
user_id bigint NOT NULL,
@@ -11317,7 +11311,6 @@ CREATE TABLE application_settings (
metrics_packet_size integer DEFAULT 1,
disabled_oauth_sign_in_sources text,
health_check_access_token character varying,
- send_user_confirmation_email boolean DEFAULT false,
container_registry_token_expire_delay integer DEFAULT 5,
after_sign_up_text text,
user_default_external boolean DEFAULT false NOT NULL,
@@ -11741,6 +11734,7 @@ CREATE TABLE application_settings (
allow_runner_registration_token boolean DEFAULT true NOT NULL,
user_defaults_to_private_profile boolean DEFAULT false NOT NULL,
allow_possible_spam boolean DEFAULT false NOT NULL,
+ default_syntax_highlighting_theme integer DEFAULT 1 NOT NULL,
encrypted_product_analytics_clickhouse_connection_string bytea,
encrypted_product_analytics_clickhouse_connection_string_iv bytea,
search_max_shard_size_gb integer DEFAULT 50 NOT NULL,
@@ -11751,6 +11745,12 @@ CREATE TABLE application_settings (
git_rate_limit_users_alertlist integer[] DEFAULT '{}'::integer[] NOT NULL,
allow_deploy_tokens_and_keys_with_external_authn boolean DEFAULT false NOT NULL,
security_policy_global_group_approvers_enabled boolean DEFAULT true NOT NULL,
+ projects_api_rate_limit_unauthenticated integer DEFAULT 400 NOT NULL,
+ deny_all_requests_except_allowed boolean DEFAULT false NOT NULL,
+ product_analytics_data_collector_host text,
+ lock_memberships_to_saml boolean DEFAULT false NOT NULL,
+ gitlab_dedicated_instance boolean DEFAULT false NOT NULL,
+ update_runner_versions_enabled boolean DEFAULT true NOT NULL,
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)),
@@ -11781,6 +11781,7 @@ CREATE TABLE application_settings (
CONSTRAINT check_5bcba483c4 CHECK ((char_length(sentry_environment) <= 255)),
CONSTRAINT check_718b4458ae CHECK ((char_length(personal_access_token_prefix) <= 20)),
CONSTRAINT check_7227fad848 CHECK ((char_length(rate_limiting_response_text) <= 255)),
+ CONSTRAINT check_72c984b2a5 CHECK ((char_length(product_analytics_data_collector_host) <= 255)),
CONSTRAINT check_734cc9407a CHECK ((char_length(globally_allowed_ips) <= 255)),
CONSTRAINT check_7ccfe2764a CHECK ((char_length(arkose_labs_namespace) <= 255)),
CONSTRAINT check_85a39b68ff CHECK ((char_length(encrypted_ci_jwt_signing_key_iv) <= 255)),
@@ -12626,6 +12627,28 @@ CREATE SEQUENCE broadcast_messages_id_seq
ALTER SEQUENCE broadcast_messages_id_seq OWNED BY broadcast_messages.id;
+CREATE TABLE bulk_import_batch_trackers (
+ id bigint NOT NULL,
+ tracker_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ status smallint DEFAULT 0 NOT NULL,
+ batch_number integer DEFAULT 0 NOT NULL,
+ fetched_objects_count integer DEFAULT 0 NOT NULL,
+ imported_objects_count integer DEFAULT 0 NOT NULL,
+ error text,
+ CONSTRAINT check_3d6963a51f CHECK ((char_length(error) <= 255))
+);
+
+CREATE SEQUENCE bulk_import_batch_trackers_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE bulk_import_batch_trackers_id_seq OWNED BY bulk_import_batch_trackers.id;
+
CREATE TABLE bulk_import_configurations (
id bigint NOT NULL,
bulk_import_id integer NOT NULL,
@@ -12662,6 +12685,7 @@ CREATE TABLE bulk_import_entities (
updated_at timestamp with time zone NOT NULL,
source_xid integer,
migrate_projects boolean DEFAULT true NOT NULL,
+ has_failures boolean DEFAULT false,
CONSTRAINT check_13f279f7da CHECK ((char_length(source_full_path) <= 255)),
CONSTRAINT check_715d725ea2 CHECK ((char_length(destination_name) <= 255)),
CONSTRAINT check_796a4d9cc6 CHECK ((char_length(jid) <= 255)),
@@ -12677,11 +12701,33 @@ CREATE SEQUENCE bulk_import_entities_id_seq
ALTER SEQUENCE bulk_import_entities_id_seq OWNED BY bulk_import_entities.id;
+CREATE TABLE bulk_import_export_batches (
+ id bigint NOT NULL,
+ export_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ status smallint DEFAULT 0 NOT NULL,
+ batch_number integer DEFAULT 0 NOT NULL,
+ objects_count integer DEFAULT 0 NOT NULL,
+ error text,
+ CONSTRAINT check_046dc60dfe CHECK ((char_length(error) <= 255))
+);
+
+CREATE SEQUENCE bulk_import_export_batches_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE bulk_import_export_batches_id_seq OWNED BY bulk_import_export_batches.id;
+
CREATE TABLE bulk_import_export_uploads (
id bigint NOT NULL,
export_id bigint NOT NULL,
updated_at timestamp with time zone NOT NULL,
export_file text,
+ batch_id bigint,
CONSTRAINT check_5add76239d CHECK ((char_length(export_file) <= 255))
);
@@ -12704,6 +12750,9 @@ CREATE TABLE bulk_import_exports (
relation text NOT NULL,
jid text,
error text,
+ batched boolean DEFAULT false NOT NULL,
+ batches_count integer DEFAULT 0 NOT NULL,
+ total_objects_count integer DEFAULT 0 NOT NULL,
CONSTRAINT check_24cb010672 CHECK ((char_length(relation) <= 255)),
CONSTRAINT check_8f0f357334 CHECK ((char_length(error) <= 255)),
CONSTRAINT check_9ee6d14d33 CHECK ((char_length(jid) <= 255))
@@ -12754,6 +12803,7 @@ CREATE TABLE bulk_import_trackers (
status smallint DEFAULT 0 NOT NULL,
created_at timestamp with time zone,
updated_at timestamp with time zone,
+ batched boolean DEFAULT false,
CONSTRAINT check_2d45cae629 CHECK ((char_length(relation) <= 255)),
CONSTRAINT check_40aeaa600b CHECK ((char_length(next_page) <= 255)),
CONSTRAINT check_603f91cb06 CHECK ((char_length(jid) <= 255)),
@@ -12778,6 +12828,7 @@ CREATE TABLE bulk_imports (
updated_at timestamp with time zone NOT NULL,
source_version text,
source_enterprise boolean DEFAULT true NOT NULL,
+ has_failures boolean DEFAULT false,
CONSTRAINT check_ea4e58775a CHECK ((char_length(source_version) <= 63))
);
@@ -12790,6 +12841,21 @@ CREATE SEQUENCE bulk_imports_id_seq
ALTER SEQUENCE bulk_imports_id_seq OWNED BY bulk_imports.id;
+CREATE TABLE catalog_resources (
+ id bigint NOT NULL,
+ project_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL
+);
+
+CREATE SEQUENCE catalog_resources_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE catalog_resources_id_seq OWNED BY catalog_resources.id;
+
CREATE TABLE chat_names (
id integer NOT NULL,
user_id integer NOT NULL,
@@ -12831,13 +12897,13 @@ CREATE SEQUENCE chat_teams_id_seq
ALTER SEQUENCE chat_teams_id_seq OWNED BY chat_teams.id;
CREATE TABLE ci_build_needs (
- id integer NOT NULL,
+ id_convert_to_bigint integer DEFAULT 0 NOT NULL,
name text NOT NULL,
artifacts boolean DEFAULT true NOT NULL,
optional boolean DEFAULT false NOT NULL,
build_id bigint NOT NULL,
partition_id bigint DEFAULT 100 NOT NULL,
- id_convert_to_bigint bigint DEFAULT 0 NOT NULL
+ id bigint NOT NULL
);
CREATE SEQUENCE ci_build_needs_id_seq
@@ -13034,6 +13100,15 @@ CREATE SEQUENCE ci_builds_runner_session_id_seq
ALTER SEQUENCE ci_builds_runner_session_id_seq OWNED BY ci_builds_runner_session.id;
+CREATE TABLE ci_cost_settings (
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ runner_id bigint NOT NULL,
+ standard_factor double precision DEFAULT 1.0 NOT NULL,
+ os_contribution_factor double precision DEFAULT 0.008 NOT NULL,
+ os_plan_factor double precision DEFAULT 0.5 NOT NULL
+);
+
CREATE TABLE ci_daily_build_group_report_results (
id bigint NOT NULL,
date date NOT NULL,
@@ -13701,7 +13776,7 @@ CREATE TABLE ci_runners (
maximum_timeout integer,
runner_type smallint NOT NULL,
token_encrypted character varying,
- public_projects_minutes_cost_factor double precision DEFAULT 0.0 NOT NULL,
+ public_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
private_projects_minutes_cost_factor double precision DEFAULT 1.0 NOT NULL,
config jsonb DEFAULT '{}'::jsonb NOT NULL,
executor_type smallint,
@@ -14450,6 +14525,13 @@ CREATE TABLE container_expiration_policies (
CONSTRAINT container_expiration_policies_name_regex_keep CHECK ((char_length(name_regex_keep) <= 255))
);
+CREATE TABLE container_registry_data_repair_details (
+ missing_count integer DEFAULT 0,
+ project_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL
+);
+
CREATE TABLE container_repositories (
id integer NOT NULL,
project_id integer NOT NULL,
@@ -14488,6 +14570,18 @@ CREATE SEQUENCE container_repositories_id_seq
ALTER SEQUENCE container_repositories_id_seq OWNED BY container_repositories.id;
+CREATE TABLE container_repository_states (
+ verification_started_at timestamp with time zone,
+ verification_retry_at timestamp with time zone,
+ verified_at timestamp with time zone,
+ container_repository_id bigint NOT NULL,
+ verification_state smallint DEFAULT 0 NOT NULL,
+ verification_retry_count smallint DEFAULT 0 NOT NULL,
+ verification_checksum bytea,
+ verification_failure text,
+ CONSTRAINT check_c96417dbc5 CHECK ((char_length(verification_failure) <= 255))
+);
+
CREATE TABLE content_blocked_states (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -14671,6 +14765,7 @@ CREATE TABLE dast_pre_scan_verification_steps (
updated_at timestamp with time zone NOT NULL,
name text,
verification_errors text[] DEFAULT '{}'::text[] NOT NULL,
+ check_type smallint DEFAULT 0 NOT NULL,
CONSTRAINT check_cd216b95e4 CHECK ((char_length(name) <= 255))
);
@@ -15218,7 +15313,11 @@ CREATE TABLE design_management_designs (
filename character varying NOT NULL,
relative_position integer,
iid integer,
+ cached_markdown_version integer,
+ description text,
+ description_html text,
CONSTRAINT check_07155e2715 CHECK ((char_length((filename)::text) <= 255)),
+ CONSTRAINT check_aaf9fa6ae5 CHECK ((char_length(description) <= 1000000)),
CONSTRAINT check_cfb92df01a CHECK ((iid IS NOT NULL))
);
@@ -16663,7 +16762,8 @@ CREATE TABLE import_failures (
exception_message character varying(255),
retry_count integer,
group_id integer,
- source character varying(128)
+ source character varying(128),
+ external_identifiers jsonb DEFAULT '{}'::jsonb NOT NULL
);
CREATE SEQUENCE import_failures_id_seq
@@ -17948,7 +18048,7 @@ CREATE SEQUENCE merge_request_diffs_id_seq
ALTER SEQUENCE merge_request_diffs_id_seq OWNED BY merge_request_diffs.id;
CREATE TABLE merge_request_metrics (
- id integer NOT NULL,
+ id_convert_to_bigint integer DEFAULT 0 NOT NULL,
merge_request_id integer NOT NULL,
latest_build_started_at timestamp without time zone,
latest_build_finished_at timestamp without time zone,
@@ -17971,7 +18071,7 @@ CREATE TABLE merge_request_metrics (
added_lines integer,
removed_lines integer,
target_project_id integer,
- id_convert_to_bigint bigint DEFAULT 0 NOT NULL,
+ id bigint NOT NULL,
CONSTRAINT check_e03d0900bf CHECK ((target_project_id IS NOT NULL))
);
@@ -18426,6 +18526,18 @@ CREATE TABLE namespace_details (
next_over_limit_check_at timestamp with time zone
);
+CREATE TABLE namespace_ldap_settings (
+ namespace_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ sync_last_start_at timestamp with time zone,
+ sync_last_update_at timestamp with time zone,
+ sync_last_successful_at timestamp with time zone,
+ sync_status smallint DEFAULT 0 NOT NULL,
+ sync_error text,
+ CONSTRAINT check_51a03d26b6 CHECK ((char_length(sync_error) <= 255))
+);
+
CREATE TABLE namespace_limits (
additional_purchased_storage_size bigint DEFAULT 0 NOT NULL,
additional_purchased_storage_ends_on date,
@@ -18463,7 +18575,8 @@ CREATE TABLE namespace_root_storage_statistics (
uploads_size bigint DEFAULT 0 NOT NULL,
dependency_proxy_size bigint DEFAULT 0 NOT NULL,
notification_level smallint DEFAULT 100 NOT NULL,
- container_registry_size bigint DEFAULT 0 NOT NULL
+ container_registry_size bigint DEFAULT 0 NOT NULL,
+ registry_size_estimated boolean DEFAULT false NOT NULL
);
CREATE TABLE namespace_settings (
@@ -18753,7 +18866,8 @@ CREATE TABLE oauth_access_tokens (
expires_in integer DEFAULT 7200,
revoked_at timestamp without time zone,
created_at timestamp without time zone NOT NULL,
- scopes character varying
+ scopes character varying,
+ CONSTRAINT check_70f294ef54 CHECK ((expires_in IS NOT NULL))
);
CREATE SEQUENCE oauth_access_tokens_id_seq
@@ -19992,6 +20106,7 @@ CREATE TABLE postgres_async_foreign_key_validations (
table_name text NOT NULL,
last_error text,
attempts integer DEFAULT 0 NOT NULL,
+ constraint_type smallint DEFAULT 0 NOT NULL,
CONSTRAINT check_536a40afbf CHECK ((char_length(last_error) <= 10000)),
CONSTRAINT check_74fb7c8e57 CHECK ((char_length(name) <= 63)),
CONSTRAINT check_cd435d6301 CHECK ((char_length(table_name) <= 63))
@@ -22076,6 +22191,18 @@ CREATE TABLE serverless_domain_cluster (
certificate text
);
+CREATE TABLE service_desk_custom_email_verifications (
+ project_id bigint NOT NULL,
+ triggerer_id bigint,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ triggered_at timestamp with time zone,
+ state smallint DEFAULT 0 NOT NULL,
+ error smallint,
+ encrypted_token bytea,
+ encrypted_token_iv bytea
+);
+
CREATE TABLE service_desk_settings (
project_id bigint NOT NULL,
issue_template_key character varying(255),
@@ -22639,10 +22766,10 @@ CREATE TABLE timelogs (
issue_id integer,
merge_request_id integer,
spent_at timestamp without time zone DEFAULT now(),
- note_id integer,
+ note_id_convert_to_bigint integer,
project_id integer,
summary text,
- note_id_convert_to_bigint bigint,
+ note_id bigint,
CONSTRAINT check_271d321699 CHECK ((char_length(summary) <= 255))
);
@@ -22944,6 +23071,7 @@ CREATE TABLE user_details (
password_last_changed_at timestamp with time zone DEFAULT now() NOT NULL,
onboarding_step_url text,
discord text DEFAULT ''::text NOT NULL,
+ provisioned_by_group_at timestamp with time zone,
CONSTRAINT check_245664af82 CHECK ((char_length(webauthn_xid) <= 100)),
CONSTRAINT check_444573ee52 CHECK ((char_length(skype) <= 500)),
CONSTRAINT check_466a25be35 CHECK ((char_length(twitter) <= 500)),
@@ -23799,6 +23927,7 @@ CREATE TABLE vulnerability_state_transitions (
author_id bigint,
comment text,
dismissal_reason smallint,
+ state_changed_at_pipeline_id bigint,
CONSTRAINT check_d1ca8ec043 CHECK ((from_state <> to_state)),
CONSTRAINT check_fe2eb6a0f3 CHECK ((char_length(comment) <= 50000))
);
@@ -24223,8 +24352,6 @@ ALTER TABLE ONLY agent_group_authorizations ALTER COLUMN id SET DEFAULT nextval(
ALTER TABLE ONLY agent_project_authorizations ALTER COLUMN id SET DEFAULT nextval('agent_project_authorizations_id_seq'::regclass);
-ALTER TABLE ONLY airflow_dags ALTER COLUMN id SET DEFAULT nextval('airflow_dags_id_seq'::regclass);
-
ALTER TABLE ONLY alert_management_alert_assignees ALTER COLUMN id SET DEFAULT nextval('alert_management_alert_assignees_id_seq'::regclass);
ALTER TABLE ONLY alert_management_alert_metric_images ALTER COLUMN id SET DEFAULT nextval('alert_management_alert_metric_images_id_seq'::regclass);
@@ -24337,10 +24464,14 @@ ALTER TABLE ONLY boards_epic_user_preferences ALTER COLUMN id SET DEFAULT nextva
ALTER TABLE ONLY broadcast_messages ALTER COLUMN id SET DEFAULT nextval('broadcast_messages_id_seq'::regclass);
+ALTER TABLE ONLY bulk_import_batch_trackers ALTER COLUMN id SET DEFAULT nextval('bulk_import_batch_trackers_id_seq'::regclass);
+
ALTER TABLE ONLY bulk_import_configurations ALTER COLUMN id SET DEFAULT nextval('bulk_import_configurations_id_seq'::regclass);
ALTER TABLE ONLY bulk_import_entities ALTER COLUMN id SET DEFAULT nextval('bulk_import_entities_id_seq'::regclass);
+ALTER TABLE ONLY bulk_import_export_batches ALTER COLUMN id SET DEFAULT nextval('bulk_import_export_batches_id_seq'::regclass);
+
ALTER TABLE ONLY bulk_import_export_uploads ALTER COLUMN id SET DEFAULT nextval('bulk_import_export_uploads_id_seq'::regclass);
ALTER TABLE ONLY bulk_import_exports ALTER COLUMN id SET DEFAULT nextval('bulk_import_exports_id_seq'::regclass);
@@ -24351,6 +24482,8 @@ ALTER TABLE ONLY bulk_import_trackers ALTER COLUMN id SET DEFAULT nextval('bulk_
ALTER TABLE ONLY bulk_imports ALTER COLUMN id SET DEFAULT nextval('bulk_imports_id_seq'::regclass);
+ALTER TABLE ONLY catalog_resources ALTER COLUMN id SET DEFAULT nextval('catalog_resources_id_seq'::regclass);
+
ALTER TABLE ONLY chat_names ALTER COLUMN id SET DEFAULT nextval('chat_names_id_seq'::regclass);
ALTER TABLE ONLY chat_teams ALTER COLUMN id SET DEFAULT nextval('chat_teams_id_seq'::regclass);
@@ -25904,9 +26037,6 @@ ALTER TABLE ONLY agent_group_authorizations
ALTER TABLE ONLY agent_project_authorizations
ADD CONSTRAINT agent_project_authorizations_pkey PRIMARY KEY (id);
-ALTER TABLE ONLY airflow_dags
- ADD CONSTRAINT airflow_dags_pkey PRIMARY KEY (id);
-
ALTER TABLE ONLY alert_management_alert_assignees
ADD CONSTRAINT alert_management_alert_assignees_pkey PRIMARY KEY (id);
@@ -26093,12 +26223,18 @@ ALTER TABLE ONLY boards
ALTER TABLE ONLY broadcast_messages
ADD CONSTRAINT broadcast_messages_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY bulk_import_batch_trackers
+ ADD CONSTRAINT bulk_import_batch_trackers_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY bulk_import_configurations
ADD CONSTRAINT bulk_import_configurations_pkey PRIMARY KEY (id);
ALTER TABLE ONLY bulk_import_entities
ADD CONSTRAINT bulk_import_entities_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY bulk_import_export_batches
+ ADD CONSTRAINT bulk_import_export_batches_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY bulk_import_export_uploads
ADD CONSTRAINT bulk_import_export_uploads_pkey PRIMARY KEY (id);
@@ -26114,6 +26250,9 @@ ALTER TABLE ONLY bulk_import_trackers
ALTER TABLE ONLY bulk_imports
ADD CONSTRAINT bulk_imports_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY catalog_resources
+ ADD CONSTRAINT catalog_resources_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY chat_names
ADD CONSTRAINT chat_names_pkey PRIMARY KEY (id);
@@ -26123,9 +26262,6 @@ ALTER TABLE ONLY chat_teams
ALTER TABLE vulnerability_scanners
ADD CONSTRAINT check_37608c9db5 CHECK ((char_length(vendor) <= 255)) NOT VALID;
-ALTER TABLE oauth_access_tokens
- ADD CONSTRAINT check_70f294ef54 CHECK ((expires_in IS NOT NULL)) NOT VALID;
-
ALTER TABLE sprints
ADD CONSTRAINT check_ccd8a1eae0 CHECK ((start_date IS NOT NULL)) NOT VALID;
@@ -26163,11 +26299,14 @@ ALTER TABLE ONLY ci_builds_metadata
ADD CONSTRAINT ci_builds_metadata_pkey PRIMARY KEY (id, partition_id);
ALTER TABLE ONLY ci_builds
- ADD CONSTRAINT ci_builds_pkey PRIMARY KEY (id);
+ ADD CONSTRAINT ci_builds_pkey PRIMARY KEY (id, partition_id);
ALTER TABLE ONLY ci_builds_runner_session
ADD CONSTRAINT ci_builds_runner_session_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY ci_cost_settings
+ ADD CONSTRAINT ci_cost_settings_pkey PRIMARY KEY (runner_id);
+
ALTER TABLE ONLY ci_daily_build_group_report_results
ADD CONSTRAINT ci_daily_build_group_report_results_pkey PRIMARY KEY (id);
@@ -26375,9 +26514,15 @@ ALTER TABLE ONLY compliance_management_frameworks
ALTER TABLE ONLY container_expiration_policies
ADD CONSTRAINT container_expiration_policies_pkey PRIMARY KEY (project_id);
+ALTER TABLE ONLY container_registry_data_repair_details
+ ADD CONSTRAINT container_registry_data_repair_details_pkey PRIMARY KEY (project_id);
+
ALTER TABLE ONLY container_repositories
ADD CONSTRAINT container_repositories_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY container_repository_states
+ ADD CONSTRAINT container_repository_states_pkey PRIMARY KEY (container_repository_id);
+
ALTER TABLE ONLY content_blocked_states
ADD CONSTRAINT content_blocked_states_pkey PRIMARY KEY (id);
@@ -26981,6 +27126,9 @@ ALTER TABLE ONLY namespace_commit_emails
ALTER TABLE ONLY namespace_details
ADD CONSTRAINT namespace_details_pkey PRIMARY KEY (namespace_id);
+ALTER TABLE ONLY namespace_ldap_settings
+ ADD CONSTRAINT namespace_ldap_settings_pkey PRIMARY KEY (namespace_id);
+
ALTER TABLE ONLY namespace_limits
ADD CONSTRAINT namespace_limits_pkey PRIMARY KEY (namespace_id);
@@ -27053,6 +27201,9 @@ ALTER TABLE ONLY operations_strategies_user_lists
ALTER TABLE ONLY operations_user_lists
ADD CONSTRAINT operations_user_lists_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY p_ci_runner_machine_builds
+ ADD CONSTRAINT p_ci_runner_machine_builds_pkey PRIMARY KEY (partition_id, build_id);
+
ALTER TABLE ONLY packages_build_infos
ADD CONSTRAINT packages_build_infos_pkey PRIMARY KEY (id);
@@ -27485,6 +27636,9 @@ ALTER TABLE ONLY sprints
ALTER TABLE ONLY serverless_domain_cluster
ADD CONSTRAINT serverless_domain_cluster_pkey PRIMARY KEY (uuid);
+ALTER TABLE ONLY service_desk_custom_email_verifications
+ ADD CONSTRAINT service_desk_custom_email_verifications_pkey PRIMARY KEY (project_id);
+
ALTER TABLE ONLY service_desk_settings
ADD CONSTRAINT service_desk_settings_pkey PRIMARY KEY (project_id);
@@ -28721,6 +28875,8 @@ CREATE UNIQUE INDEX any_approver_project_rule_type_unique_index ON approval_proj
CREATE INDEX approval_mr_rule_index_merge_request_id ON approval_merge_request_rules USING btree (merge_request_id);
+CREATE INDEX bulk_import_export_uploads_batch_id ON bulk_import_export_uploads USING btree (batch_id);
+
CREATE UNIQUE INDEX bulk_import_trackers_uniq_relation_by_entity ON bulk_import_trackers USING btree (bulk_import_entity_id, relation);
CREATE INDEX ca_aggregations_last_consistency_check_updated_at ON analytics_cycle_analytics_aggregations USING btree (last_consistency_check_updated_at NULLS FIRST) WHERE (enabled IS TRUE);
@@ -28765,6 +28921,10 @@ CREATE INDEX finding_links_on_vulnerability_occurrence_id ON vulnerability_findi
CREATE INDEX i_batched_background_migration_job_transition_logs_on_job_id ON ONLY batched_background_migration_job_transition_logs USING btree (batched_background_migration_job_id);
+CREATE UNIQUE INDEX i_bulk_import_export_batches_id_batch_number ON bulk_import_export_batches USING btree (export_id, batch_number);
+
+CREATE UNIQUE INDEX i_bulk_import_trackers_id_batch_number ON bulk_import_batch_trackers USING btree (tracker_id, batch_number);
+
CREATE INDEX i_compliance_frameworks_on_id_and_created_at ON compliance_management_frameworks USING btree (id, created_at, pipeline_configuration_full_path);
CREATE INDEX i_dast_pre_scan_verification_steps_on_pre_scan_verification_id ON dast_pre_scan_verification_steps USING btree (dast_pre_scan_verification_id);
@@ -28781,12 +28941,18 @@ 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 i_users_on_last_activity_for_active_human_service_migration ON users USING btree (id, last_activity_on) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = 0) OR (user_type = 4)));
+
CREATE INDEX idx_analytics_devops_adoption_segments_on_namespace_id ON analytics_devops_adoption_segments USING btree (namespace_id);
CREATE INDEX idx_analytics_devops_adoption_snapshots_finalized ON analytics_devops_adoption_snapshots USING btree (namespace_id, end_time) WHERE (recorded_at >= end_time);
+CREATE INDEX idx_approval_merge_request_rules_on_scan_result_policy_id ON approval_merge_request_rules USING btree (scan_result_policy_id);
+
CREATE INDEX idx_approval_merge_request_rules_on_sec_orchestration_config_id ON approval_merge_request_rules USING btree (security_orchestration_policy_configuration_id);
+CREATE INDEX idx_approval_project_rules_on_scan_result_policy_id ON approval_project_rules USING btree (scan_result_policy_id);
+
CREATE INDEX idx_approval_project_rules_on_sec_orchestration_config_id ON approval_project_rules USING btree (security_orchestration_policy_configuration_id);
CREATE INDEX idx_audit_events_part_on_entity_id_desc_author_id_created_at ON ONLY audit_events USING btree (entity_id, entity_type, id DESC, author_id, created_at);
@@ -28977,8 +29143,20 @@ CREATE UNIQUE INDEX idx_vulnerability_issue_links_on_vulnerability_id_and_issue_
CREATE UNIQUE INDEX idx_vulnerability_issue_links_on_vulnerability_id_and_link_type ON vulnerability_issue_links USING btree (vulnerability_id, link_type) WHERE (link_type = 2);
+CREATE INDEX idx_vulnerability_reads_project_id_scanner_id_vulnerability_id ON vulnerability_reads USING btree (project_id, scanner_id, vulnerability_id);
+
CREATE UNIQUE INDEX idx_work_item_types_on_namespace_id_and_name_null_namespace ON work_item_types USING btree (btrim(lower(name)), ((namespace_id IS NULL))) WHERE (namespace_id IS NULL);
+CREATE INDEX index_abuse_reports_on_status_and_created_at ON abuse_reports USING btree (status, created_at);
+
+CREATE INDEX index_abuse_reports_on_status_and_id ON abuse_reports USING btree (status, id);
+
+CREATE INDEX index_abuse_reports_on_status_and_updated_at ON abuse_reports USING btree (status, updated_at);
+
+CREATE INDEX index_abuse_reports_on_status_category_and_id ON abuse_reports USING btree (status, category, id);
+
+CREATE INDEX index_abuse_reports_on_status_reporter_id_and_id ON abuse_reports USING btree (status, reporter_id, id);
+
CREATE INDEX index_abuse_reports_on_user_id ON abuse_reports USING btree (user_id);
CREATE UNIQUE INDEX "index_achievements_on_namespace_id_LOWER_name" ON achievements USING btree (namespace_id, lower(name));
@@ -29001,8 +29179,6 @@ CREATE UNIQUE INDEX index_agent_project_authorizations_on_agent_id_and_project_i
CREATE INDEX index_agent_project_authorizations_on_project_id ON agent_project_authorizations USING btree (project_id);
-CREATE INDEX index_airflow_dags_on_project_id ON airflow_dags USING btree (project_id);
-
CREATE INDEX index_alert_assignees_on_alert_id ON alert_management_alert_assignees USING btree (alert_id);
CREATE UNIQUE INDEX index_alert_assignees_on_user_id_and_alert_id ON alert_management_alert_assignees USING btree (user_id, alert_id);
@@ -29253,6 +29429,8 @@ CREATE INDEX index_broadcast_messages_on_namespace_id ON broadcast_messages USIN
CREATE INDEX index_btree_namespaces_traversal_ids ON namespaces USING btree (traversal_ids);
+CREATE INDEX index_bulk_import_batch_trackers_on_tracker_id ON bulk_import_batch_trackers USING btree (tracker_id);
+
CREATE INDEX index_bulk_import_configurations_on_bulk_import_id ON bulk_import_configurations USING btree (bulk_import_id);
CREATE INDEX index_bulk_import_entities_on_bulk_import_id_and_status ON bulk_import_entities USING btree (bulk_import_id, status);
@@ -29263,6 +29441,8 @@ CREATE INDEX index_bulk_import_entities_on_parent_id ON bulk_import_entities USI
CREATE INDEX index_bulk_import_entities_on_project_id ON bulk_import_entities USING btree (project_id);
+CREATE INDEX index_bulk_import_export_batches_on_export_id ON bulk_import_export_batches USING btree (export_id);
+
CREATE INDEX index_bulk_import_export_uploads_on_export_id ON bulk_import_export_uploads USING btree (export_id);
CREATE INDEX index_bulk_import_failures_on_bulk_import_entity_id ON bulk_import_failures USING btree (bulk_import_entity_id);
@@ -29271,6 +29451,8 @@ CREATE INDEX index_bulk_import_failures_on_correlation_id_value ON bulk_import_f
CREATE INDEX index_bulk_imports_on_user_id ON bulk_imports USING btree (user_id);
+CREATE UNIQUE INDEX index_catalog_resources_on_project_id ON catalog_resources USING btree (project_id);
+
CREATE INDEX index_chat_names_on_team_id_and_chat_id ON chat_names USING btree (team_id, chat_id);
CREATE INDEX index_chat_names_on_user_id ON chat_names USING btree (user_id);
@@ -29307,10 +29489,6 @@ CREATE UNIQUE INDEX p_ci_builds_metadata_build_id_partition_id_idx ON ONLY p_ci_
CREATE UNIQUE INDEX index_ci_builds_metadata_on_build_id_partition_id_unique ON ci_builds_metadata USING btree (build_id, partition_id);
-CREATE UNIQUE INDEX p_ci_builds_metadata_id_partition_id_idx ON ONLY p_ci_builds_metadata USING btree (id, partition_id);
-
-CREATE UNIQUE INDEX index_ci_builds_metadata_on_id_partition_id_unique ON ci_builds_metadata USING btree (id, partition_id);
-
CREATE INDEX p_ci_builds_metadata_project_id_idx ON ONLY p_ci_builds_metadata USING btree (project_id);
CREATE INDEX index_ci_builds_metadata_on_project_id ON ci_builds_metadata USING btree (project_id);
@@ -29327,8 +29505,6 @@ CREATE INDEX index_ci_builds_on_commit_id_and_type_and_ref ON ci_builds USING bt
CREATE INDEX index_ci_builds_on_commit_id_artifacts_expired_at_and_id ON ci_builds USING btree (commit_id, artifacts_expire_at, id) WHERE (((type)::text = 'Ci::Build'::text) AND ((retried = false) OR (retried IS NULL)) AND ((name)::text = ANY (ARRAY[('sast'::character varying)::text, ('secret_detection'::character varying)::text, ('dependency_scanning'::character varying)::text, ('container_scanning'::character varying)::text, ('dast'::character varying)::text])));
-CREATE UNIQUE INDEX index_ci_builds_on_id_partition_id_unique ON ci_builds USING btree (id, partition_id);
-
CREATE INDEX index_ci_builds_on_project_id_and_id ON ci_builds USING btree (project_id, id);
CREATE INDEX index_ci_builds_on_project_id_and_name_and_ref ON ci_builds USING btree (project_id, name, ref) WHERE (((type)::text = 'Ci::Build'::text) AND ((status)::text = 'success'::text) AND ((retried = false) OR (retried IS NULL)));
@@ -29341,8 +29517,6 @@ CREATE INDEX index_ci_builds_on_stage_id ON ci_builds USING btree (stage_id);
CREATE INDEX index_ci_builds_on_status_and_type_and_runner_id ON ci_builds USING btree (status, type, runner_id);
-CREATE UNIQUE INDEX index_ci_builds_on_token_encrypted ON ci_builds USING btree (token_encrypted) WHERE (token_encrypted IS NOT NULL);
-
CREATE INDEX index_ci_builds_on_updated_at ON ci_builds USING btree (updated_at);
CREATE INDEX index_ci_builds_on_upstream_pipeline_id ON ci_builds USING btree (upstream_pipeline_id) WHERE (upstream_pipeline_id IS NOT NULL);
@@ -29375,6 +29549,8 @@ CREATE UNIQUE INDEX index_ci_instance_variables_on_key ON ci_instance_variables
CREATE INDEX index_ci_job_artifact_states_on_job_artifact_id ON ci_job_artifact_states USING btree (job_artifact_id);
+CREATE INDEX index_ci_job_artifacts_expire_at_unlocked_non_trace ON ci_job_artifacts USING btree (expire_at) WHERE ((locked = 0) AND (file_type <> 3) AND (expire_at IS NOT NULL));
+
CREATE INDEX index_ci_job_artifacts_for_terraform_reports ON ci_job_artifacts USING btree (project_id, id) WHERE (file_type = 18);
CREATE INDEX index_ci_job_artifacts_id_for_terraform_reports ON ci_job_artifacts USING btree (id) WHERE (file_type = 18);
@@ -29529,6 +29705,8 @@ CREATE INDEX index_ci_resources_on_partition_id_build_id ON ci_resources USING b
CREATE UNIQUE INDEX index_ci_resources_on_resource_group_id_and_build_id ON ci_resources USING btree (resource_group_id, build_id);
+CREATE INDEX index_ci_runner_machine_builds_on_runner_machine_id ON ONLY p_ci_runner_machine_builds USING btree (runner_machine_id);
+
CREATE INDEX index_ci_runner_machines_on_contacted_at_desc_and_id_desc ON ci_runner_machines USING btree (contacted_at DESC, id DESC);
CREATE INDEX index_ci_runner_machines_on_created_at_and_id_desc ON ci_runner_machines USING btree (created_at, id DESC);
@@ -29739,6 +29917,14 @@ CREATE INDEX index_container_repositories_on_status_and_id ON container_reposito
CREATE INDEX index_container_repository_on_name_trigram ON container_repositories USING gin (name gin_trgm_ops);
+CREATE INDEX index_container_repository_states_failed_verification ON container_repository_states USING btree (verification_retry_at NULLS FIRST) WHERE (verification_state = 3);
+
+CREATE INDEX index_container_repository_states_needs_verification ON container_repository_states USING btree (verification_state) WHERE ((verification_state = 0) OR (verification_state = 3));
+
+CREATE INDEX index_container_repository_states_on_verification_state ON container_repository_states USING btree (verification_state);
+
+CREATE INDEX index_container_repository_states_pending_verification ON container_repository_states USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0);
+
CREATE UNIQUE INDEX index_content_blocked_states_on_container_id_commit_sha_path ON content_blocked_states USING btree (container_identifier, commit_sha, path);
CREATE UNIQUE INDEX index_coverage_fuzzing_corpuses_on_package_id ON coverage_fuzzing_corpuses USING btree (package_id);
@@ -30537,6 +30723,8 @@ CREATE INDEX index_lfs_object_states_on_verification_state ON lfs_object_states
CREATE INDEX index_lfs_object_states_pending_verification ON lfs_object_states USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0);
+CREATE INDEX index_lfs_objects_on_file ON lfs_objects USING btree (file);
+
CREATE INDEX index_lfs_objects_on_file_store ON lfs_objects USING btree (file_store);
CREATE UNIQUE INDEX index_lfs_objects_on_oid ON lfs_objects USING btree (oid);
@@ -30635,6 +30823,8 @@ CREATE INDEX index_merge_request_diff_details_pending_verification ON merge_requ
CREATE INDEX index_merge_request_diffs_by_id_partial ON merge_request_diffs USING btree (id) WHERE ((files_count > 0) AND ((NOT stored_externally) OR (stored_externally IS NULL)));
+CREATE INDEX index_merge_request_diffs_on_external_diff ON merge_request_diffs USING btree (external_diff);
+
CREATE INDEX index_merge_request_diffs_on_external_diff_store ON merge_request_diffs USING btree (external_diff_store);
CREATE INDEX index_merge_request_diffs_on_merge_request_id_and_id ON merge_request_diffs USING btree (merge_request_id, id);
@@ -30661,6 +30851,8 @@ CREATE UNIQUE INDEX index_merge_request_reviewers_on_merge_request_id_and_user_i
CREATE INDEX index_merge_request_reviewers_on_user_id ON merge_request_reviewers USING btree (user_id);
+CREATE UNIQUE INDEX index_merge_request_user_mentions_note_id_convert_to_bigint ON merge_request_user_mentions USING btree (note_id_convert_to_bigint) WHERE (note_id_convert_to_bigint IS NOT NULL);
+
CREATE UNIQUE INDEX index_merge_request_user_mentions_on_note_id ON merge_request_user_mentions USING btree (note_id) WHERE (note_id IS NOT NULL);
CREATE INDEX index_merge_requests_closing_issues_on_issue_id ON merge_requests_closing_issues USING btree (issue_id);
@@ -30853,12 +31045,16 @@ CREATE INDEX index_namespaces_on_type_and_id ON namespaces USING btree (type, id
CREATE INDEX index_namespaces_on_type_and_visibility_and_parent_id ON namespaces USING btree (id) WHERE (((type)::text = 'Group'::text) AND (parent_id IS NULL) AND (visibility_level <> 20));
+CREATE INDEX index_namespaces_on_updated_at ON namespaces USING btree (updated_at);
+
CREATE INDEX index_namespaces_public_groups_name_id ON namespaces USING btree (name, id) WHERE (((type)::text = 'Group'::text) AND (visibility_level = 20));
CREATE INDEX index_namespaces_storage_limit_exclusions_on_namespace_id ON namespaces_storage_limit_exclusions USING btree (namespace_id);
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);
@@ -30891,8 +31087,12 @@ CREATE INDEX index_notification_settings_on_source_and_level_and_user ON notific
CREATE UNIQUE INDEX index_notifications_on_user_id_and_source_id_and_source_type ON notification_settings USING btree (user_id, source_id, source_type);
+CREATE INDEX index_ns_root_stor_stats_on_registry_size_estimated ON namespace_root_storage_statistics USING btree (registry_size_estimated);
+
CREATE UNIQUE INDEX index_ns_user_callouts_feature ON user_namespace_callouts USING btree (user_id, feature_name, namespace_id);
+CREATE INDEX index_oauth_access_grants_on_application_id ON oauth_access_grants USING btree (application_id);
+
CREATE INDEX index_oauth_access_grants_on_resource_owner_id ON oauth_access_grants USING btree (resource_owner_id, application_id, created_at);
CREATE UNIQUE INDEX index_oauth_access_grants_on_token ON oauth_access_grants USING btree (token);
@@ -30995,6 +31195,8 @@ CREATE UNIQUE INDEX index_ops_strategies_user_lists_on_strategy_id_and_user_list
CREATE UNIQUE INDEX index_organizations_on_unique_name_per_group ON customer_relations_organizations USING btree (group_id, lower(name), id);
+CREATE INDEX index_p_ci_runner_machine_builds_on_runner_machine_id ON ONLY p_ci_runner_machine_builds USING btree (runner_machine_id);
+
CREATE INDEX index_packages_build_infos_on_pipeline_id ON packages_build_infos USING btree (pipeline_id);
CREATE INDEX index_packages_build_infos_package_id_pipeline_id_id ON packages_build_infos USING btree (package_id, pipeline_id, id);
@@ -31045,6 +31247,8 @@ CREATE INDEX index_packages_package_file_build_infos_on_package_file_id ON packa
CREATE INDEX index_packages_package_file_build_infos_on_pipeline_id ON packages_package_file_build_infos USING btree (pipeline_id);
+CREATE INDEX index_packages_package_files_on_file_name ON packages_package_files USING gin (file_name gin_trgm_ops);
+
CREATE INDEX index_packages_package_files_on_file_store ON packages_package_files USING btree (file_store);
CREATE INDEX index_packages_package_files_on_id_for_cleanup ON packages_package_files USING btree (id) WHERE (status = 1);
@@ -31165,8 +31369,6 @@ CREATE INDEX index_pool_repositories_on_shard_id ON pool_repositories USING btre
CREATE UNIQUE INDEX index_pool_repositories_on_source_project_id_and_shard_id ON pool_repositories USING btree (source_project_id, shard_id);
-CREATE UNIQUE INDEX index_postgres_async_foreign_key_validations_on_name ON postgres_async_foreign_key_validations USING btree (name);
-
CREATE UNIQUE INDEX index_postgres_async_indexes_on_name ON postgres_async_indexes USING btree (name);
CREATE INDEX index_postgres_reindex_actions_on_index_identifier ON postgres_reindex_actions USING btree (index_identifier);
@@ -31611,6 +31813,8 @@ CREATE INDEX index_sbom_occurrences_on_pipeline_id ON sbom_occurrences USING btr
CREATE INDEX index_sbom_occurrences_on_project_id ON sbom_occurrences USING btree (project_id);
+CREATE INDEX index_sbom_occurrences_on_project_id_and_id ON sbom_occurrences USING btree (project_id, id);
+
CREATE INDEX index_sbom_occurrences_on_source_id ON sbom_occurrences USING btree (source_id);
CREATE UNIQUE INDEX index_sbom_occurrences_on_uuid ON sbom_occurrences USING btree (uuid);
@@ -31667,6 +31871,8 @@ CREATE INDEX index_serverless_domain_cluster_on_creator_id ON serverless_domain_
CREATE INDEX index_serverless_domain_cluster_on_pages_domain_id ON serverless_domain_cluster USING btree (pages_domain_id);
+CREATE INDEX index_service_desk_custom_email_verifications_on_triggerer_id ON service_desk_custom_email_verifications USING btree (triggerer_id);
+
CREATE INDEX index_service_desk_enabled_projects_on_id_creator_id_created_at ON projects USING btree (id, creator_id, created_at) WHERE (service_desk_enabled = true);
CREATE INDEX index_service_desk_settings_on_file_template_project_id ON service_desk_settings USING btree (file_template_project_id);
@@ -31955,6 +32161,10 @@ COMMENT ON INDEX index_user_details_on_phone IS 'JiHu-specific index';
CREATE UNIQUE INDEX index_user_details_on_user_id ON user_details USING btree (user_id);
+CREATE INDEX index_user_details_on_user_id_for_enterprise_users_with_date ON user_details USING btree (user_id) WHERE ((provisioned_by_group_id IS NOT NULL) AND (provisioned_by_group_at IS NOT NULL));
+
+CREATE INDEX index_user_details_on_user_id_for_enterprise_users_without_date ON user_details USING btree (user_id) WHERE ((provisioned_by_group_id IS NOT NULL) AND (provisioned_by_group_at IS NULL));
+
CREATE INDEX index_user_group_callouts_on_group_id ON user_group_callouts USING btree (group_id);
CREATE INDEX index_user_highest_roles_on_user_id_and_highest_access_level ON user_highest_roles USING btree (user_id, highest_access_level);
@@ -31979,7 +32189,7 @@ CREATE INDEX index_user_statuses_on_user_id ON user_statuses USING btree (user_i
CREATE UNIQUE INDEX index_user_synced_attributes_metadata_on_user_id ON user_synced_attributes_metadata USING btree (user_id);
-CREATE INDEX index_users_for_billable_users ON users USING btree (id) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = ANY (ARRAY[6, 4]))) AND ((user_type IS NULL) OR (user_type = ANY (ARRAY[4, 5]))));
+CREATE INDEX index_users_for_active_billable_users ON users USING btree (id) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = ANY (ARRAY[6, 4, 13]))) AND ((user_type IS NULL) OR (user_type = ANY (ARRAY[4, 5]))));
CREATE INDEX index_users_on_accepted_term_id ON users USING btree (accepted_term_id);
@@ -32023,6 +32233,8 @@ CREATE INDEX index_users_on_unconfirmed_email ON users USING btree (unconfirmed_
CREATE UNIQUE INDEX index_users_on_unlock_token ON users USING btree (unlock_token);
+CREATE INDEX index_users_on_updated_at ON users USING btree (updated_at);
+
CREATE INDEX index_users_on_user_type_and_id ON users USING btree (user_type, id);
CREATE INDEX index_users_on_username ON users USING btree (username);
@@ -32187,6 +32399,8 @@ CREATE INDEX index_vulnerability_state_transitions_id_and_vulnerability_id ON vu
CREATE INDEX index_vulnerability_state_transitions_on_author_id ON vulnerability_state_transitions USING btree (author_id);
+CREATE INDEX index_vulnerability_state_transitions_on_pipeline_id ON vulnerability_state_transitions USING btree (state_changed_at_pipeline_id);
+
CREATE INDEX index_vulnerability_statistics_on_latest_pipeline_id ON vulnerability_statistics USING btree (latest_pipeline_id);
CREATE INDEX index_vulnerability_statistics_on_letter_grade ON vulnerability_statistics USING btree (letter_grade);
@@ -32203,6 +32417,8 @@ CREATE UNIQUE INDEX index_vulns_user_mentions_on_vulnerability_id ON vulnerabili
CREATE UNIQUE INDEX index_vulns_user_mentions_on_vulnerability_id_and_note_id ON vulnerability_user_mentions USING btree (vulnerability_id, note_id);
+CREATE INDEX index_web_hook_logs_on_web_hook_id_and_created_at ON ONLY web_hook_logs USING btree (web_hook_id, created_at);
+
CREATE INDEX index_web_hook_logs_part_on_created_at_and_web_hook_id ON ONLY web_hook_logs USING btree (created_at, web_hook_id);
CREATE INDEX index_web_hook_logs_part_on_web_hook_id ON ONLY web_hook_logs USING btree (web_hook_id);
@@ -32303,6 +32519,8 @@ CREATE UNIQUE INDEX merge_request_user_mentions_on_mr_id_index ON merge_request_
CREATE INDEX merge_requests_state_id_temp_index ON merge_requests USING btree (id) WHERE (state_id = ANY (ARRAY[2, 3]));
+CREATE INDEX migrate_index_users_for_active_billable_users ON users USING btree (id) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = 0) OR (user_type = ANY (ARRAY[0, 6, 4, 13]))) AND ((user_type IS NULL) OR (user_type = 0) OR (user_type = ANY (ARRAY[0, 4, 5]))));
+
CREATE INDEX note_mentions_temp_index ON notes USING btree (id, noteable_type) WHERE (note ~~ '%@%'::text);
CREATE UNIQUE INDEX one_canonical_wiki_page_slug_per_metadata ON wiki_page_slugs USING btree (wiki_page_meta_id) WHERE (canonical = true);
@@ -32385,6 +32603,8 @@ CREATE INDEX tmp_index_for_null_member_namespace_id ON members USING btree (memb
CREATE INDEX tmp_index_for_project_namespace_id_migration_on_routes ON routes USING btree (id) WHERE ((namespace_id IS NULL) AND ((source_type)::text = 'Project'::text));
+CREATE INDEX tmp_index_for_software_licenses_spdx_identifier_cleanup ON software_licenses USING btree (spdx_identifier) WHERE (spdx_identifier IS NULL);
+
CREATE INDEX tmp_index_members_on_state ON members USING btree (state) WHERE (state = 2);
CREATE INDEX tmp_index_migrated_container_registries ON container_repositories USING btree (project_id) WHERE ((migration_state = 'import_done'::text) OR (created_at >= '2022-01-23 00:00:00'::timestamp without time zone));
@@ -32421,6 +32641,8 @@ CREATE UNIQUE INDEX unique_index_for_project_pages_unique_domain ON project_sett
CREATE UNIQUE INDEX unique_merge_request_metrics_by_merge_request_id ON merge_request_metrics USING btree (merge_request_id);
+CREATE UNIQUE INDEX unique_postgres_async_fk_validations_name_and_table_name ON postgres_async_foreign_key_validations USING btree (name, table_name);
+
CREATE UNIQUE INDEX unique_projects_on_name_namespace_id ON projects USING btree (name, namespace_id);
CREATE UNIQUE INDEX unique_streaming_event_type_filters_destination_id ON audit_events_streaming_event_type_filters USING btree (external_audit_event_destination_id, audit_event_type);
@@ -33725,8 +33947,6 @@ ALTER INDEX p_ci_builds_metadata_build_id_id_idx ATTACH PARTITION index_ci_build
ALTER INDEX p_ci_builds_metadata_build_id_partition_id_idx ATTACH PARTITION index_ci_builds_metadata_on_build_id_partition_id_unique;
-ALTER INDEX p_ci_builds_metadata_id_partition_id_idx ATTACH PARTITION index_ci_builds_metadata_on_id_partition_id_unique;
-
ALTER INDEX p_ci_builds_metadata_project_id_idx ATTACH PARTITION index_ci_builds_metadata_on_project_id;
CREATE TRIGGER chat_names_loose_fk_trigger AFTER DELETE ON chat_names REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
@@ -33735,6 +33955,8 @@ CREATE TRIGGER ci_builds_loose_fk_trigger AFTER DELETE ON ci_builds REFERENCING
CREATE TRIGGER ci_pipelines_loose_fk_trigger AFTER DELETE ON ci_pipelines REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
+CREATE TRIGGER ci_runner_machines_loose_fk_trigger AFTER DELETE ON ci_runner_machines REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
+
CREATE TRIGGER ci_runners_loose_fk_trigger AFTER DELETE ON ci_runners REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
CREATE TRIGGER clusters_loose_fk_trigger AFTER DELETE ON clusters REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
@@ -33843,6 +34065,9 @@ ALTER TABLE ONLY service_desk_settings
ALTER TABLE ONLY design_management_designs_versions
ADD CONSTRAINT fk_03c671965c FOREIGN KEY (design_id) REFERENCES design_management_designs(id) ON DELETE CASCADE;
+ALTER TABLE ONLY projects
+ ADD CONSTRAINT fk_03ec10b0d3 FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE SET NULL NOT VALID;
+
ALTER TABLE ONLY analytics_dashboards_pointers
ADD CONSTRAINT fk_05d96922bd FOREIGN KEY (target_project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -34062,6 +34287,9 @@ ALTER TABLE ONLY zoekt_indexed_namespaces
ALTER TABLE ONLY epics
ADD CONSTRAINT fk_3c1fd1cccc FOREIGN KEY (due_date_sourcing_milestone_id) REFERENCES milestones(id) ON DELETE SET NULL;
+ALTER TABLE ONLY bulk_import_export_uploads
+ ADD CONSTRAINT fk_3cbf0b9a2e FOREIGN KEY (batch_id) REFERENCES bulk_import_export_batches(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY ci_pipelines
ADD CONSTRAINT fk_3d34ab2e06 FOREIGN KEY (pipeline_schedule_id) REFERENCES ci_pipeline_schedules(id) ON DELETE SET NULL;
@@ -34503,6 +34731,9 @@ ALTER TABLE ONLY deployments
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 ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
+
ALTER TABLE ONLY namespace_bans
ADD CONSTRAINT fk_bcc024eef2 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -34519,10 +34750,7 @@ ALTER TABLE ONLY snippets
ADD CONSTRAINT fk_be41fd4bb7 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_sources_pipelines
- ADD CONSTRAINT fk_be5624bf37 FOREIGN KEY (source_job_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
-
-ALTER TABLE ONLY ci_sources_pipelines
- ADD CONSTRAINT fk_be5624bf37_p FOREIGN KEY (source_partition_id, source_job_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
+ ADD CONSTRAINT fk_be5624bf37_p FOREIGN KEY (source_partition_id, source_job_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY packages_maven_metadata
ADD CONSTRAINT fk_be88aed360 FOREIGN KEY (package_id) REFERENCES packages_packages(id) ON DELETE CASCADE;
@@ -34678,7 +34906,7 @@ ALTER TABLE ONLY ci_sources_pipelines
ADD CONSTRAINT fk_e1bad85861 FOREIGN KEY (pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
ALTER TABLE p_ci_builds_metadata
- ADD CONSTRAINT fk_e20479742e FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
+ ADD CONSTRAINT fk_e20479742e_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY gitlab_subscriptions
ADD CONSTRAINT fk_e2595d00a1 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -34788,6 +35016,9 @@ ALTER TABLE ONLY issues
ALTER TABLE ONLY geo_event_log
ADD CONSTRAINT fk_geo_event_log_on_geo_event_id FOREIGN KEY (geo_event_id) REFERENCES geo_events(id) ON DELETE CASCADE;
+ALTER TABLE ONLY merge_request_user_mentions
+ ADD CONSTRAINT fk_merge_request_user_mentions_note_id_convert_to_bigint FOREIGN KEY (note_id_convert_to_bigint) REFERENCES notes(id) ON DELETE CASCADE NOT VALID;
+
ALTER TABLE ONLY path_locks
ADD CONSTRAINT fk_path_locks_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
@@ -34920,6 +35151,9 @@ ALTER TABLE ONLY diff_note_positions
ALTER TABLE ONLY analytics_cycle_analytics_aggregations
ADD CONSTRAINT fk_rails_13c8374c7a FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+ALTER TABLE ONLY service_desk_custom_email_verifications
+ ADD CONSTRAINT fk_rails_14dcaf4c92 FOREIGN KEY (triggerer_id) REFERENCES users(id) ON DELETE SET NULL;
+
ALTER TABLE ONLY namespaces_storage_limit_exclusions
ADD CONSTRAINT fk_rails_14e8f7b0e0 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -34927,10 +35161,10 @@ ALTER TABLE ONLY users_security_dashboard_projects
ADD CONSTRAINT fk_rails_150cd5682c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_build_report_results
- ADD CONSTRAINT fk_rails_16cb1ff064 FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
+ ADD CONSTRAINT fk_rails_16cb1ff064_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
-ALTER TABLE ONLY ci_build_report_results
- ADD CONSTRAINT fk_rails_16cb1ff064_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
+ALTER TABLE ONLY catalog_resources
+ ADD CONSTRAINT fk_rails_16f09e5c44 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY project_deploy_tokens
ADD CONSTRAINT fk_rails_170e03cbaf FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -35115,6 +35349,9 @@ ALTER TABLE ONLY issuable_severities
ALTER TABLE ONLY saml_providers
ADD CONSTRAINT fk_rails_306d459be7 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_import_batch_trackers
+ ADD CONSTRAINT fk_rails_307efb9f32 FOREIGN KEY (tracker_id) REFERENCES bulk_import_trackers(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY pm_package_version_licenses
ADD CONSTRAINT fk_rails_30ddb7f837 FOREIGN KEY (pm_package_version_id) REFERENCES pm_package_versions(id) ON DELETE CASCADE;
@@ -35194,10 +35431,7 @@ ALTER TABLE ONLY chat_teams
ADD CONSTRAINT fk_rails_3b543909cb FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_build_needs
- ADD CONSTRAINT fk_rails_3cf221d4ed FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
-
-ALTER TABLE ONLY ci_build_needs
- ADD CONSTRAINT fk_rails_3cf221d4ed_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
+ ADD CONSTRAINT fk_rails_3cf221d4ed_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY cluster_groups
ADD CONSTRAINT fk_rails_3d28377556 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -35454,6 +35688,9 @@ ALTER TABLE ONLY sbom_component_versions
ALTER TABLE ONLY status_page_published_incidents
ADD CONSTRAINT fk_rails_61e5493940 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
+ALTER TABLE ONLY container_repository_states
+ ADD CONSTRAINT fk_rails_63436c99ce FOREIGN KEY (container_repository_id) REFERENCES container_repositories(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY deployment_clusters
ADD CONSTRAINT fk_rails_6359a164df FOREIGN KEY (deployment_id) REFERENCES deployments(id) ON DELETE CASCADE;
@@ -35523,6 +35760,9 @@ ALTER TABLE ONLY geo_hashed_storage_migrated_events
ALTER TABLE ONLY plan_limits
ADD CONSTRAINT fk_rails_69f8b6184f FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE;
+ALTER TABLE ONLY ci_cost_settings
+ ADD CONSTRAINT fk_rails_6a70651f75 FOREIGN KEY (runner_id) REFERENCES ci_runners(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY operations_feature_flags_issues
ADD CONSTRAINT fk_rails_6a8856ca4f FOREIGN KEY (feature_flag_id) REFERENCES operations_feature_flags(id) ON DELETE CASCADE;
@@ -35560,9 +35800,6 @@ ALTER TABLE ONLY project_custom_attributes
ADD CONSTRAINT fk_rails_719c3dccc5 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_pending_builds
- ADD CONSTRAINT fk_rails_725a2644a3 FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
-
-ALTER TABLE ONLY ci_pending_builds
ADD CONSTRAINT fk_rails_725a2644a3_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE security_findings
@@ -35661,6 +35898,9 @@ ALTER TABLE ONLY approval_merge_request_rules_users
ALTER TABLE ONLY required_code_owners_sections
ADD CONSTRAINT fk_rails_817708cf2d FOREIGN KEY (protected_branch_id) REFERENCES protected_branches(id) ON DELETE CASCADE;
+ALTER TABLE ONLY namespace_ldap_settings
+ ADD CONSTRAINT fk_rails_82cd0ad4bb FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY cluster_enabled_grants
ADD CONSTRAINT fk_rails_8336ce35af FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -35965,10 +36205,7 @@ ALTER TABLE ONLY metrics_dashboard_annotations
ADD CONSTRAINT fk_rails_aeb11a7643 FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_build_trace_metadata
- ADD CONSTRAINT fk_rails_aebc78111f FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
-
-ALTER TABLE ONLY ci_build_trace_metadata
- ADD CONSTRAINT fk_rails_aebc78111f_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
+ ADD CONSTRAINT fk_rails_aebc78111f_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY bulk_import_trackers
ADD CONSTRAINT fk_rails_aed566d3f3 FOREIGN KEY (bulk_import_entity_id) REFERENCES bulk_import_entities(id) ON DELETE CASCADE;
@@ -36015,6 +36252,9 @@ ALTER TABLE ONLY packages_debian_project_component_files
ALTER TABLE ONLY namespace_aggregation_schedules
ADD CONSTRAINT fk_rails_b565c8d16c FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+ALTER TABLE ONLY container_registry_data_repair_details
+ ADD CONSTRAINT fk_rails_b70d8111d9 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE batched_background_migration_job_transition_logs
ADD CONSTRAINT fk_rails_b7523a175b FOREIGN KEY (batched_background_migration_job_id) REFERENCES batched_background_migration_jobs(id) ON DELETE CASCADE;
@@ -36057,6 +36297,9 @@ ALTER TABLE ONLY elasticsearch_indexed_namespaces
ALTER TABLE ONLY vulnerability_occurrence_identifiers
ADD CONSTRAINT fk_rails_be2e49e1d0 FOREIGN KEY (identifier_id) REFERENCES vulnerability_identifiers(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_import_export_batches
+ ADD CONSTRAINT fk_rails_be479792f6 FOREIGN KEY (export_id) REFERENCES bulk_import_exports(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY alert_management_http_integrations
ADD CONSTRAINT fk_rails_bec49f52cc FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -36118,10 +36361,7 @@ ALTER TABLE ONLY boards_epic_board_recent_visits
ADD CONSTRAINT fk_rails_c4dcba4a3e FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_job_artifacts
- ADD CONSTRAINT fk_rails_c5137cb2c1 FOREIGN KEY (job_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
-
-ALTER TABLE ONLY ci_job_artifacts
- ADD CONSTRAINT fk_rails_c5137cb2c1_p FOREIGN KEY (partition_id, job_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
+ ADD CONSTRAINT fk_rails_c5137cb2c1_p FOREIGN KEY (partition_id, job_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY packages_events
ADD CONSTRAINT fk_rails_c6c20d0094 FOREIGN KEY (package_id) REFERENCES packages_packages(id) ON DELETE SET NULL;
@@ -36156,9 +36396,6 @@ ALTER TABLE ONLY gpg_signatures
ALTER TABLE ONLY board_group_recent_visits
ADD CONSTRAINT fk_rails_ca04c38720 FOREIGN KEY (board_id) REFERENCES boards(id) ON DELETE CASCADE;
-ALTER TABLE ONLY airflow_dags
- ADD CONSTRAINT fk_rails_ca3ac0d68c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY boards_epic_board_positions
ADD CONSTRAINT fk_rails_cb4563dd6e FOREIGN KEY (epic_board_id) REFERENCES boards_epic_boards(id) ON DELETE CASCADE;
@@ -36235,9 +36472,6 @@ ALTER TABLE ONLY merge_request_reviewers
ADD CONSTRAINT fk_rails_d9fec24b9d FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_running_builds
- ADD CONSTRAINT fk_rails_da45cfa165 FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
-
-ALTER TABLE ONLY ci_running_builds
ADD CONSTRAINT fk_rails_da45cfa165_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY jira_imports
@@ -36276,6 +36510,9 @@ ALTER TABLE ONLY dast_scanner_profiles_tags
ALTER TABLE ONLY vulnerability_feedback
ADD CONSTRAINT fk_rails_debd54e456 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY service_desk_custom_email_verifications
+ ADD CONSTRAINT fk_rails_debe4c4acc FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY packages_debian_project_distributions
ADD CONSTRAINT fk_rails_df44271a30 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE RESTRICT;
@@ -36474,9 +36711,6 @@ ALTER TABLE ONLY merge_requests_closing_issues
ALTER TABLE ONLY banned_users
ADD CONSTRAINT fk_rails_fa5bb598e5 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
-ALTER TABLE p_ci_builds_metadata
- ADD CONSTRAINT fk_rails_fae01b2700 FOREIGN KEY (runner_machine_id) REFERENCES ci_runner_machines(id) ON DELETE SET NULL;
-
ALTER TABLE ONLY operations_feature_flags_issues
ADD CONSTRAINT fk_rails_fb4d2a7cb1 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
@@ -36487,10 +36721,7 @@ ALTER TABLE ONLY serverless_domain_cluster
ADD CONSTRAINT fk_rails_fbdba67eb1 FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE ONLY ci_job_variables
- ADD CONSTRAINT fk_rails_fbf3b34792 FOREIGN KEY (job_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
-
-ALTER TABLE ONLY ci_job_variables
- ADD CONSTRAINT fk_rails_fbf3b34792_p FOREIGN KEY (partition_id, job_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID;
+ ADD CONSTRAINT fk_rails_fbf3b34792_p FOREIGN KEY (partition_id, job_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE ONLY packages_nuget_metadata
ADD CONSTRAINT fk_rails_fc0c19f5b4 FOREIGN KEY (package_id) REFERENCES packages_packages(id) ON DELETE CASCADE;
diff --git a/doc/.vale/gitlab/CodeblockFences.yml b/doc/.vale/gitlab/CodeblockFences.yml
index 9d5efe7f60a..27159f7e72e 100644
--- a/doc/.vale/gitlab/CodeblockFences.yml
+++ b/doc/.vale/gitlab/CodeblockFences.yml
@@ -5,9 +5,9 @@
#
# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: "Instead of '%s' for the code block, use yaml, ruby, plaintext, markdown, javascript, shell, golang, python, dockerfile, or typescript."
+message: "Instead of '%s' for the code block, use yaml, ruby, plaintext, markdown, javascript, shell, go, python, dockerfile, or typescript."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#code-blocks
level: error
scope: raw
raw:
- - '\`\`\`(yml|rb|text|md|bash|sh\n|js\n|go\n|py\n|docker\n|ts)'
+ - '\`\`\`(yml|rb|text|md|bash|sh\n|js\n|golang\n|py\n|docker\n|ts)'
diff --git a/doc/.vale/gitlab/HeadingDepth.yml b/doc/.vale/gitlab/HeadingDepth.yml
index 5bbe667481c..f29ec0e4ac7 100644
--- a/doc/.vale/gitlab/HeadingDepth.yml
+++ b/doc/.vale/gitlab/HeadingDepth.yml
@@ -6,7 +6,7 @@
# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
message: "Refactor the section or page to avoid headings greater than H5."
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#headings-in-markdown
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#heading-levels-in-markdown
level: suggestion
scope: raw
raw:
diff --git a/doc/.vale/gitlab/Substitutions.yml b/doc/.vale/gitlab/Substitutions.yml
index 675abc6ef6d..225e4e74880 100644
--- a/doc/.vale/gitlab/Substitutions.yml
+++ b/doc/.vale/gitlab/Substitutions.yml
@@ -23,6 +23,7 @@ swap:
params: parameters
pg: PostgreSQL
'postgres$': PostgreSQL
+ golang: Go
raketask: Rake task
raketasks: Rake tasks
rspec: RSpec
diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt
index a2a23c03aa3..83e187fe1b5 100644
--- a/doc/.vale/gitlab/spelling-exceptions.txt
+++ b/doc/.vale/gitlab/spelling-exceptions.txt
@@ -223,6 +223,8 @@ cybersecurity
CycloneDX
Dangerfile
DAST
+Database Lab Engine
+Database Lab
Databricks
Datadog
datasource
@@ -495,6 +497,7 @@ Kibana
Kinesis
Klar
Knative
+KPIs
Kramdown
Kroki
kubeconfig
@@ -615,6 +618,7 @@ Nurtch
NVMe
nyc
OAuth
+OCP
Octokit
offboarded
offboarding
@@ -623,6 +627,7 @@ OIDs
OKRs
OKRs
Okta
+OLM
OmniAuth
onboarding
OpenID
@@ -666,6 +671,7 @@ Pipfile
Pipfiles
Piwik
plaintext
+podman
Poedit
polyfill
polyfills
@@ -833,8 +839,8 @@ sanitization
SBOMs
sbt
SBT
-scalers
scalar's
+scalers
scatterplot
scatterplots
schedulable
@@ -1182,7 +1188,7 @@ ZAProxy
Zeitwerk
Zendesk
ZenTao
+Zoekt
zsh
Zstandard
Zuora
-Zoekt
diff --git a/doc/administration/audit_event_streaming.md b/doc/administration/audit_event_streaming.md
index 92ccbe8b1a6..bbf4c0699ca 100644
--- a/doc/administration/audit_event_streaming.md
+++ b/doc/administration/audit_event_streaming.md
@@ -41,7 +41,7 @@ Streaming destinations receive **all** audit event data, which could include sen
Users with the Owner role for a group can add streaming destinations for it:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Security & Compliance > Audit events**.
+1. On the left sidebar, select **Security and Compliance > Audit events**.
1. On the main area, select **Streams** tab.
1. Select **Add streaming destination** to show the section for adding destinations.
1. Enter the destination URL to add.
@@ -119,7 +119,7 @@ Users with the Owner role for a group can list streaming destinations.
To list the streaming destinations:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Security & Compliance > Audit events**.
+1. On the left sidebar, select **Security and Compliance > Audit events**.
1. On the main area, select **Streams** tab.
1. To the right of the item, select **Edit** (**{pencil}**) to see all the custom HTTP headers.
@@ -164,7 +164,7 @@ Users with the Owner role for a group can update streaming destinations.
To update a streaming destinations custom HTTP headers:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Security & Compliance > Audit events**.
+1. On the left sidebar, select **Security and Compliance > Audit events**.
1. On the main area, select **Streams** tab.
1. To the right of the item, select **Edit** (**{pencil}**).
1. Locate the **Custom HTTP headers** table.
@@ -218,14 +218,14 @@ When the last destination is successfully deleted, streaming is disabled for the
To delete a streaming destination:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Security & Compliance > Audit events**.
+1. On the left sidebar, select **Security and Compliance > Audit events**.
1. On the main area, select the **Streams** tab.
1. To the right of the item, select **Delete** (**{remove}**).
To delete only the custom HTTP headers for a streaming destination:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Security & Compliance > Audit events**.
+1. On the left sidebar, select **Security and Compliance > Audit events**.
1. On the main area, select the **Streams** tab.
1. To the right of the item, **Edit** (**{pencil}**).
1. Locate the **Custom HTTP headers** table.
@@ -282,7 +282,7 @@ the destination's value when [listing streaming destinations](#list-streaming-de
Users with the Owner role for a group can list streaming destinations and see the verification tokens:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Security & Compliance > Audit events**.
+1. On the left sidebar, select **Security and Compliance > Audit events**.
1. On the main area, select the **Streams**.
1. View the verification token on the right side of each item.
@@ -365,6 +365,50 @@ Streamed audit events have a predictable schema in the body of the response.
| `target_id` | ID of the audit event's target | |
| `target_type` | String representation of the target's type | |
+### JSON payload schema
+
+```json
+{
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "author_id": {
+ "type": "integer"
+ },
+ "author_name": {
+ "type": "string"
+ },
+ "details": {},
+ "ip_address": {
+ "type": "string"
+ },
+ "entity_id": {
+ "type": "integer"
+ },
+ "entity_path": {
+ "type": "string"
+ },
+ "entity_type": {
+ "type": "string"
+ },
+ "event_type": {
+ "type": "string"
+ },
+ "target_id": {
+ "type": "integer"
+ },
+ "target_type": {
+ "type": "string"
+ },
+ "target_details": {
+ "type": "string"
+ },
+ },
+ "type": "object"
+}
+```
+
## Audit event streaming on Git operations
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332747) in GitLab 14.9 [with a flag](../administration/feature_flags.md) named `audit_event_streaming_git_operations`. Disabled by default.
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index c51b5fbb431..47833224c0a 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -49,7 +49,7 @@ You can view audit events scoped to a group or project.
To view a group's audit events:
1. Go to the group.
-1. On the left sidebar, select **Security & Compliance > Audit Events**.
+1. On the left sidebar, select **Security and Compliance > Audit Events**.
Group events do not include project audit events. Group events can also be accessed using the
[Group Audit Events API](../api/audit_events.md#group-audit-events). Group event queries are limited to a maximum of 30
@@ -120,7 +120,7 @@ Successful sign-in events are the only audit events available at all tiers. To s
1. Select your avatar.
1. Select **Edit profile > Authentication log**.
-After upgrading to a paid tier, you can see also see successful sign-in events on audit event pages.
+After upgrading to a paid tier, you can also see successful sign-in events on audit event pages.
## Filter audit events
@@ -314,6 +314,15 @@ The following actions on projects generate project audit events:
- An environment is protected or unprotected.
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216164) in GitLab 15.8.
+### GitLab agent for Kubernetes events
+
+The following actions on projects generate agent audit events:
+
+- A cluster agent token is created.
+ Introduced in GitLab 15.9
+- A cluster agent token is revoked.
+ Introduced in GitLab 15.9
+
### Instance events **(PREMIUM SELF)**
The following user actions on a GitLab instance generate instance audit events:
diff --git a/doc/administration/auth/authentiq.md b/doc/administration/auth/authentiq.md
deleted file mode 100644
index a32d2a2cf94..00000000000
--- a/doc/administration/auth/authentiq.md
+++ /dev/null
@@ -1,12 +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-02-22'
-redirect_to: '../../integration/omniauth.md'
----
-
-# Authentiq OmniAuth Provider (removed) **(FREE SELF)**
-
-This feature was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/389452) in 15.9.
-Use another [OmniAuth provider](../../integration/omniauth.md) instead.
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index 0c7bd33c2c1..1f7f096eb2f 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -270,7 +270,7 @@ These LDAP sync configuration settings are available:
| Setting | Description | Required | Examples |
|-------------------|-------------|----------|----------|
-| `group_base` | Base used to search for groups. | **{dotted-circle}** No | `'ou=groups,dc=gitlab,dc=example'` |
+| `group_base` | Base used to search for groups. | **{dotted-circle}** No (required when `external_groups` is configured) | `'ou=groups,dc=gitlab,dc=example'` |
| `admin_group` | The CN of a group containing GitLab administrators. Not `cn=administrators` or the full DN. | **{dotted-circle}** No | `'administrators'` |
| `external_groups` | An array of CNs of groups containing users that should be considered external. Not `cn=interns` or the full DN. | **{dotted-circle}** No | `['interns', 'contractors']` |
| `sync_ssh_keys` | The LDAP attribute containing a user's public SSH key. | **{dotted-circle}** No | `'sshPublicKey'` or false if not set |
diff --git a/doc/administration/auth/ldap/ldap-troubleshooting.md b/doc/administration/auth/ldap/ldap-troubleshooting.md
index 7e21d3c6655..9c925e0a40e 100644
--- a/doc/administration/auth/ldap/ldap-troubleshooting.md
+++ b/doc/administration/auth/ldap/ldap-troubleshooting.md
@@ -170,10 +170,10 @@ We have a workaround, based on toggling the access level of affected users:
1. As an administrator, on the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Overview > Users**.
1. Select the name of the affected user.
-1. In the upper right, select **Edit**.
+1. In the upper-right corner, select **Edit**.
1. Change the user's access level from `Regular` to `Administrator` (or vice versa).
1. At the bottom of the page, select **Save changes**.
-1. In the upper right, select **Edit** again.
+1. In the upper-right corner, select **Edit** again.
1. Restore the user's original access level (`Regular` or `Administrator`)
and select **Save changes** again.
diff --git a/doc/administration/auth/ldap/ldap_synchronization.md b/doc/administration/auth/ldap/ldap_synchronization.md
index cc300941470..59ed3a4153d 100644
--- a/doc/administration/auth/ldap/ldap_synchronization.md
+++ b/doc/administration/auth/ldap/ldap_synchronization.md
@@ -33,9 +33,6 @@ For more information, see [Bitmask Searches in LDAP](https://ctovswild.com/2009/
<!-- vale gitlab.Spelling = YES -->
-The user is set to an `ldap_blocked` state in GitLab if the previous conditions
-fail. This means the user cannot sign in or push or pull code.
-
The process also updates the following user information:
- Name. Because of a [sync issue](https://gitlab.com/gitlab-org/gitlab/-/issues/342598), `name` is not synchronized if
@@ -44,6 +41,26 @@ The process also updates the following user information:
- SSH public keys if `sync_ssh_keys` is set.
- Kerberos identity if Kerberos is enabled.
+### Blocked users
+
+A user is blocked if either the:
+
+- [Access check fails](#user-sync) and that user is set to an `ldap_blocked` state in GitLab.
+- LDAP server is not available when that user signs in.
+
+If a user is blocked, that user cannot sign in or push or pull code.
+
+A blocked user is unblocked when they sign in with LDAP if all of the following are true:
+
+- All the access check conditions are true.
+- The LDAP server is available when the user signs in.
+
+**All users** are blocked if the LDAP server is unavailable when an LDAP user synchronization is run.
+
+NOTE:
+If all users are blocked due to the LDAP server not being available when an LDAP user synchronization is run,
+a subsequent LDAP user synchronization does not automatically unblock those users.
+
### Adjust LDAP user sync schedule
By default, GitLab runs a worker once per day at 01:30 a.m. server time to
@@ -387,6 +404,23 @@ To enable global group memberships lock:
1. Expand the **Visibility and access controls** section.
1. Ensure the **Lock memberships to LDAP synchronization** checkbox is selected.
+### Change LDAP group synchronization settings management
+
+By default, group members with the Owner role can manage [LDAP group synchronization settings](../../../user/group/access_and_permissions.md#manage-group-memberships-via-ldap).
+
+GitLab administrators can remove this permission from group Owners:
+
+1. [Configure LDAP](index.md#configure-ldap).
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Visibility and access controls**.
+1. Ensure the **Allow group owners to manage LDAP-related settings** checkbox is not checked.
+
+When **Allow group owners to manage LDAP-related settings** is disabled:
+
+- Group Owners cannot change LDAP synchronization settings for either top-level groups and subgroups.
+- Instance administrators can manage LDAP group synchronization settings on all groups on an instance.
+
### Adjust LDAP group sync schedule
By default, GitLab runs a group sync process every hour, on the hour.
@@ -411,7 +445,7 @@ sync to run once every two hours at the top of the hour.
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
- gitlab_rails['ldap_group_sync_worker_cron'] = "0 */2 * * * *"
+ gitlab_rails['ldap_group_sync_worker_cron'] = "0 */2 * * *"
```
1. Save the file and reconfigure GitLab:
@@ -454,7 +488,7 @@ sync to run once every two hours at the top of the hour.
gitlab:
environment:
GITLAB_OMNIBUS_CONFIG: |
- gitlab_rails['ldap_group_sync_worker_cron'] = "0 */2 * * * *"
+ gitlab_rails['ldap_group_sync_worker_cron'] = "0 */2 * * *"
```
1. Save the file and restart GitLab:
diff --git a/doc/administration/auth/oidc.md b/doc/administration/auth/oidc.md
index ea6922629d8..4edc00b0d62 100644
--- a/doc/administration/auth/oidc.md
+++ b/doc/administration/auth/oidc.md
@@ -561,6 +561,254 @@ Example installations from source configuration (file path: `config/gitlab.yml`)
}
```
+## Configure users based on OIDC group membership **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/209898) in GitLab 15.10.
+
+You can configure OIDC group membership to:
+
+- Require users to be members of a certain group.
+- Assign users [external roles](../../user/admin_area/external_users.md), or as
+ administrators based on group membership.
+
+GitLab checks these groups on each sign in and updates user attributes as necessary.
+This feature **does not** allow you to automatically add users to GitLab
+[groups](../../user/group/index.md).
+
+### Required groups
+
+Your identity provider (IdP) must pass group information to GitLab in the OIDC response. To use this
+response to require users to be members of a certain group, configure GitLab to identify:
+
+- Where to look for the groups in the OIDC response, using the `groups_attribute` setting.
+- Which group membership is required to sign in, using the `required_groups` setting.
+
+If you do not set `required_groups` or leave the setting empty, any user authenticated by the IdP through OIDC can use GitLab.
+
+For Omnibus GitLab:
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ name: "openid_connect",
+ label: "Provider name",
+ args: {
+ name: "openid_connect",
+ scope: ["openid","profile","email"],
+ response_type: "code",
+ issuer: "<your_oidc_url>",
+ discovery: true,
+ client_auth_method: "query",
+ uid_field: "<uid_field>",
+ client_options: {
+ identifier: "<your_oidc_client_id>",
+ secret: "<your_oidc_client_secret>",
+ redirect_uri: "<your_gitlab_url>/users/auth/openid_connect/callback",
+ gitlab: {
+ groups_attribute: "groups",
+ required_groups: ["Developer"]
+ }
+ }
+ }
+ }
+ ]
+ ```
+
+1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect.
+
+For installation from source:
+
+1. Edit `/home/git/gitlab/config/gitlab.yml`:
+
+ ```yaml
+ production: &base
+ omniauth:
+ providers:
+ - { name: 'openid_connect',
+ label: 'Provider name',
+ args: {
+ name: 'openid_connect',
+ scope: ['openid','profile','email'],
+ response_type: 'code',
+ issuer: '<your_oidc_url>',
+ discovery: true,
+ client_auth_method: 'query',
+ uid_field: '<uid_field>',
+ client_options: {
+ identifier: '<your_oidc_client_id>',
+ secret: '<your_oidc_client_secret>',
+ redirect_uri: '<your_gitlab_url>/users/auth/openid_connect/callback',
+ gitlab: {
+ groups_attribute: "groups",
+ required_groups: ["Developer"]
+ }
+ }
+ }
+ }
+ ```
+
+1. Save the file and [reconfigure GitLab](../restart_gitlab.md#installations-from-source)
+ for the changes to take effect.
+
+### External groups
+
+Your IdP must pass group information to GitLab in the OIDC response. To use this
+response to identify users as [external users](../../user/admin_area/external_users.md)
+based on group membership, configure GitLab to identify:
+
+- Where to look for the groups in the OIDC response, using the `groups_attribute` setting.
+- Which group memberships should identify a user as an
+ [external user](../../user/admin_area/external_users.md), using the
+ `external_groups` setting.
+
+For Omnibus GitLab:
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ name: "openid_connect",
+ label: "Provider name",
+ args: {
+ name: "openid_connect",
+ scope: ["openid","profile","email"],
+ response_type: "code",
+ issuer: "<your_oidc_url>",
+ discovery: true,
+ client_auth_method: "query",
+ uid_field: "<uid_field>",
+ client_options: {
+ identifier: "<your_oidc_client_id>",
+ secret: "<your_oidc_client_secret>",
+ redirect_uri: "<your_gitlab_url>/users/auth/openid_connect/callback",
+ gitlab: {
+ groups_attribute: "groups",
+ external_groups: ["Freelancer"]
+ }
+ }
+ }
+ }
+ ]
+ ```
+
+1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect.
+
+For installation from source:
+
+1. Edit `/home/git/gitlab/config/gitlab.yml`:
+
+ ```yaml
+ production: &base
+ omniauth:
+ providers:
+ - { name: 'openid_connect',
+ label: 'Provider name',
+ args: {
+ name: 'openid_connect',
+ scope: ['openid','profile','email'],
+ response_type: 'code',
+ issuer: '<your_oidc_url>',
+ discovery: true,
+ client_auth_method: 'query',
+ uid_field: '<uid_field>',
+ client_options: {
+ identifier: '<your_oidc_client_id>',
+ secret: '<your_oidc_client_secret>',
+ redirect_uri: '<your_gitlab_url>/users/auth/openid_connect/callback',
+ gitlab: {
+ groups_attribute: "groups",
+ external_groups: ["Freelancer"]
+ }
+ }
+ }
+ }
+ ```
+
+1. Save the file and [reconfigure GitLab](../restart_gitlab.md#installations-from-source)
+ for the changes to take effect.
+
+### Administrator groups
+
+Your IdP must pass group information to GitLab in the OIDC response. To use this
+response to assign users as administrator based on group membership, configure GitLab to identify:
+
+- Where to look for the groups in the OIDC response, using the `groups_attribute` setting.
+- Which group memberships grant the user administrator access, using the
+ `admin_groups` setting.
+
+For Omnibus GitLab:
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ name: "openid_connect",
+ label: "Provider name",
+ args: {
+ name: "openid_connect",
+ scope: ["openid","profile","email"],
+ response_type: "code",
+ issuer: "<your_oidc_url>",
+ discovery: true,
+ client_auth_method: "query",
+ uid_field: "<uid_field>",
+ client_options: {
+ identifier: "<your_oidc_client_id>",
+ secret: "<your_oidc_client_secret>",
+ redirect_uri: "<your_gitlab_url>/users/auth/openid_connect/callback",
+ gitlab: {
+ groups_attribute: "groups",
+ admin_groups: ["Admin"]
+ }
+ }
+ }
+ }
+ ]
+ ```
+
+1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect.
+
+For installation from source:
+
+1. Edit `/home/git/gitlab/config/gitlab.yml`:
+
+ ```yaml
+ production: &base
+ omniauth:
+ providers:
+ - { name: 'openid_connect',
+ label: 'Provider name',
+ args: {
+ name: 'openid_connect',
+ scope: ['openid','profile','email'],
+ response_type: 'code',
+ issuer: '<your_oidc_url>',
+ discovery: true,
+ client_auth_method: 'query',
+ uid_field: '<uid_field>',
+ client_options: {
+ identifier: '<your_oidc_client_id>',
+ secret: '<your_oidc_client_secret>',
+ redirect_uri: '<your_gitlab_url>/users/auth/openid_connect/callback',
+ gitlab: {
+ groups_attribute: "groups",
+ admin_groups: ["Admin"]
+ }
+ }
+ }
+ }
+ ```
+
+1. Save the file and [reconfigure GitLab](../restart_gitlab.md#installations-from-source)
+ for the changes to take effect.
+
## Troubleshooting
1. Ensure `discovery` is set to `true`. If you set it to `false`, you must
diff --git a/doc/administration/clusters/kas.md b/doc/administration/clusters/kas.md
index a7f8f8e712b..7a289b6a500 100644
--- a/doc/administration/clusters/kas.md
+++ b/doc/administration/clusters/kas.md
@@ -50,6 +50,8 @@ To enable the agent server on multiple nodes:
1. For each agent server node, edit `/etc/gitlab/gitlab.rb`:
```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>'
@@ -65,17 +67,23 @@ To enable the agent server on multiple nodes:
gitlab_rails['gitlab_kas_external_k8s_proxy_url'] = 'https://gitlab.example.com/-/kubernetes-agent/k8s-proxy/'
```
- In this configuration:
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
- - `gitlab_kas['private_api_listen_address']` is the address the agent server listens on. You can set it to `0.0.0.0` or an IP address reachable by other nodes in the cluster.
- - `OWN_PRIVATE_API_URL` is the environment variable used by the KAS process for service discovery. You can set it to a hostname or IP address of the node you're configuring. The node must be reachable by other nodes in the cluster.
- - `gitlab_kas['api_secret_key']` is the shared secret used for authentication between KAS and GitLab. This value must be Base64-encoded and exactly 32 bytes long.
- - `gitlab_kas['private_api_secret_key']` is the shared secret used for authentication between different KAS instances. This value must be Base64-encoded and exactly 32 bytes long.
- - `gitlab_rails['gitlab_kas_external_url']` is the user-facing URL for the in-cluster `agentk`.
- - `gitlab_rails['gitlab_kas_internal_url']` is the internal URL the GitLab backend uses to communicate with KAS.
- - `gitlab_rails['gitlab_kas_external_k8s_proxy_url']` is the user-facing URL for Kubernetes API proxying.
+##### Agent server node settings
-1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+| Setting | Description |
+|---------|-------------|
+| `gitlab_kas['private_api_listen_address']` | The address the agent server listens on. Set to `0.0.0.0` or to an IP address reachable by other nodes in the cluster. |
+| `gitlab_kas['api_secret_key']` | The shared secret used for authentication between KAS and GitLab. The value must be Base64-encoded and exactly 32 bytes long. |
+| `gitlab_kas['private_api_secret_key']` | The shared secret used for authentication between different KAS instances. The value must be Base64-encoded and exactly 32 bytes long. |
+| `OWN_PRIVATE_API_URL` | The environment variable used by KAS for service discovery. Set to the hostname or IP address of the node you're configuring. The node must be reachable by other nodes in the cluster. |
+| `gitlab_kas_external_url` | The user-facing URL for the in-cluster `agentk`. Can be a fully qualified domain or subdomain, <sup>**1**</sup> or a GitLab external URL. <sup>**2**</sup> If blank, defaults to a GitLab external URL. |
+| `gitlab_rails['gitlab_kas_external_url']` | The user-facing URL for the in-cluster `agentk`. If blank, defaults to the `gitlab_kas_external_url`. |
+| `gitlab_rails['gitlab_kas_external_k8s_proxy_url']` | The user-facing URL for Kubernetes API proxying. If blank, defaults to a URL based on `gitlab_kas_external_url`. |
+| `gitlab_rails['gitlab_kas_internal_url']` | The internal URL the GitLab backend uses to communicate with KAS. |
+
+1. For example, `wss://kas.gitlab.example.com/`.
+1. For example, `wss://gitlab.example.com/-/kubernetes-agent/`.
### For GitLab Helm Chart
@@ -105,6 +113,24 @@ For GitLab [Helm Chart](https://docs.gitlab.com/charts/) installations:
For details, see [how to use the GitLab-KAS chart](https://docs.gitlab.com/charts/charts/gitlab/kas/).
+## Kubernetes API proxy cookie
+
+> Introduced in GitLab 15.10 [with feature flags](../feature_flags.md) named `kas_user_access` and `kas_user_access_project`. 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 flags](../feature_flags.md) named `kas_user_access` and `kas_user_access_project`.
+
+KAS proxies Kubernetes API requests to the GitLab agent with either:
+
+- A [CI/CD job](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_ci_access.md).
+- [GitLab user credentials](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_user_access.md).
+
+To authenticate with user credentials, Rails sets a cookie for the GitLab frontend.
+This cookie is called `_gitlab_kas` and it contains an encrypted
+session ID, like the [`_gitlab_session` cookie](../../user/profile/index.md#cookies-used-for-sign-in).
+The `_gitlab_kas` cookie must be sent to the KAS proxy endpoint with every request
+to authenticate and authorize the user.
+
## Troubleshooting
If you have issues while using the agent server for Kubernetes, view the
diff --git a/doc/administration/dedicated/index.md b/doc/administration/dedicated/index.md
index 22b8cc13637..1991d0b64cc 100644
--- a/doc/administration/dedicated/index.md
+++ b/doc/administration/dedicated/index.md
@@ -27,6 +27,7 @@ To request the creation of a new GitLab Dedicated environment for your organizat
- 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`).
- Initial storage: Initial storage size for your repositories in GB.
- Availability Zone IDs for PrivateLink: If you plan to later add a PrivateLink connection (either [inbound](#inbound-private-link) or [outbound](#outbound-private-link)) to your environment, and you require the connections to be available in specific Availability Zones, you must provide up to two [Availability Zone IDs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#az-ids) during onboarding. If not specified, GitLab will select two random Availability Zone IDs in which the connections will be available.
+- [KMS keys](https://docs.aws.amazon.com/kms/latest/developerguide/overview.html) for encrypted AWS services (if you are using that functionality).
### Maintenance window
@@ -45,6 +46,111 @@ To change or update the configuration for your GitLab Dedicated instance, open a
The turnaround time for processing configuration change requests is [documented in the GitLab handbook](https://about.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/#handling-configuration-changes-for-tenant-environments).
+### 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:
+
+1. Per-service KMS keys (Backup, EBS, RDS, S3), or
+1. One KMS key for all services.
+
+If you use a key per service, all services must be encrypted at rest. Selective enablement of this feature is not supported.
+
+The keys provided have to reside in the same primary and secondary region specified during [onboarding](#onboarding).
+
+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.
+
+To create a KMS key using the AWS Console:
+
+1. In `Configure key`, select:
+ 1. Key type: **Symmetrical**
+ 1. Key usage: **Encrypt and decrypt**
+ 1. `Advanced options`:
+ 1. Key material origin: **KMS**
+ 1. Regionality: **Multi-Region key**
+1. Enter your values for key alias, description, and tags.
+1. Select Key administrators (optionally allow or deny key administrators to delete the key).
+1. For Key usage permissions, add the GitLab AWS account using the **Other AWS accounts** dialog.
+
+The last page asks you to confirm the KMS key policy. It should look similar to the following example, populated with your account IDs and usernames:
+
+```json
+{
+ "Version": "2012-10-17",
+ "Id": "byok-key-policy",
+ "Statement": [
+ {
+ "Sid": "Enable IAM User Permissions",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::<CUSTOMER-ACCOUNT-ID>:root"
+ },
+ "Action": "kms:*",
+ "Resource": "*"
+ },
+ {
+ "Sid": "Allow access for Key Administrators",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": [
+ "arn:aws:iam::<CUSTOMER-ACCOUNT-ID>:user/<CUSTOMER-USER>"
+ ]
+ },
+ "Action": [
+ "kms:Create*",
+ "kms:Describe*",
+ "kms:Enable*",
+ "kms:List*",
+ "kms:Put*",
+ "kms:Update*",
+ "kms:Revoke*",
+ "kms:Disable*",
+ "kms:Get*",
+ "kms:Delete*",
+ "kms:TagResource",
+ "kms:UntagResource",
+ "kms:ScheduleKeyDeletion",
+ "kms:CancelKeyDeletion",
+ "kms:ReplicateKey",
+ "kms:UpdatePrimaryRegion"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "Allow use of the key",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": [
+ "arn:aws:iam::<GITLAB-ACCOUNT-ID>:root"
+ ]
+ },
+ "Action": [
+ "kms:Encrypt",
+ "kms:Decrypt",
+ "kms:ReEncrypt*",
+ "kms:GenerateDataKey*",
+ "kms:DescribeKey"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "Allow attachment of persistent resources",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": [
+ "arn:aws:iam::<GITLAB-ACCOUNT-ID>:root"
+ ]
+ },
+ "Action": [
+ "kms:CreateGrant",
+ "kms:ListGrants",
+ "kms:RevokeGrant"
+ ],
+ "Resource": "*"
+ }
+ ]
+}
+```
+
### Inbound Private Link
[AWS Private Link](https://docs.aws.amazon.com/vpc/latest/privatelink/what-is-privatelink.html) allows users and applications in your VPC on AWS to securely connect to the GitLab Dedicated endpoint without network traffic going over the public internet.
@@ -97,7 +203,7 @@ Prerequisites:
To activate SAML for your GitLab Dedicated instance:
-1. Read the [GitLab documentation about SAML](../../integration/saml.md#https://docs.gitlab.com/ee/integration/saml.html#configure-saml-on-your-idp) to gather all data your identity provider requires for configuration. You can also find some providers and their requirements in the [group SAML documentation](../../user/group/saml_sso/index.md#providers).
+1. Read the [GitLab documentation about SAML](../../integration/saml.md#https://docs.gitlab.com/ee/integration/saml.html#configure-saml-on-your-idp) to gather all data your identity provider requires for configuration. You can also find some providers and their requirements in the [group SAML documentation](../../user/group/saml_sso/index.md#set-up-identity-provider).
1. To make the necessary changes, include in your [support ticket](#configuration-changes) the desired [SAML configuration block](../../integration/saml.md#configure-saml-support-in-gitlab) that will be set on the GitLab application. At a minimum, GitLab needs the following information to enable SAML for your instance:
- Assertion consumer service URL
- Certificate fingerprint or certificate
diff --git a/doc/administration/docs_self_host.md b/doc/administration/docs_self_host.md
index 97eff35da91..932ffb87288 100644
--- a/doc/administration/docs_self_host.md
+++ b/doc/administration/docs_self_host.md
@@ -22,7 +22,7 @@ To host the GitLab product documentation, you can use:
- GitLab Pages
- Your own web server
-After you create a website by using one of these methods, you redirect the UI links
+After you create a website by using one of these methods, redirect the UI links
in the product to point to your website.
NOTE:
@@ -41,7 +41,7 @@ In the following example, we expose this on the host under the same port.
Make sure you either:
- Allow port `4000` in your firewall.
-- Use a different port. In following examples, replace the leftmost `4000` with the port different port.
+- Use a different port. In following examples, replace the leftmost `4000` with a different port number.
To run the GitLab product documentation website in a Docker container:
@@ -74,7 +74,7 @@ To run the GitLab product documentation website in a Docker container:
docker-compose up -d
```
-1. Visit `http://0.0.0.0:4000` to view the documentation website and verify
+1. Visit `http://0.0.0.0:4000` to view the documentation website and verify that
it works.
1. [Redirect the help links to the new Docs site](#redirect-the-help-links-to-the-new-docs-site).
@@ -84,7 +84,7 @@ You can use GitLab Pages to host the GitLab product documentation.
Prerequisite:
-- Ensure the Pages site URL does not use a subfolder. Because of how the docs
+- Ensure the Pages site URL does not use a subfolder. Because of the way the docs
site is pre-compiled, the CSS and JavaScript files are relative to the
main domain or subdomain. For example, URLs like `https://example.com/docs/`
are not supported.
@@ -177,7 +177,11 @@ documentation URL requests as needed. For example, if your GitLab version is
- When you select the link, you are redirected to
`http://0.0.0.0:4000/14.5/ee/user/admin_area/settings/help_page/#destination-requirements`.
-To test the setting, select a **Learn more** link in the GitLab application.
+To test the setting, in GitLab, select a **Learn more** link. For example:
+
+1. On the top bar, in the upper-right corner, select your avatar.
+1. Select **Preferences**.
+1. In the **Syntax highlighting theme** section, select **Learn more**.
## Upgrade the product documentation to a later version
@@ -187,7 +191,7 @@ Upgrading the Docs site to a later version requires downloading the newer Docker
To upgrade to a later version [using Docker](#self-host-the-product-documentation-with-docker):
-- If you use plain Docker:
+- If you use Docker:
1. Stop the running container:
@@ -207,7 +211,7 @@ To upgrade to a later version [using Docker](#self-host-the-product-documentatio
docker run --detach --name gitlab_docs -it --rm -p 4000:4000 registry.gitlab.com/gitlab-org/gitlab-docs:14.6
```
-- If you use Docker compose:
+- If you use Docker Compose:
1. Change the version in `docker-compose.yaml`, for example 14.6:
@@ -231,7 +235,7 @@ To upgrade to a later version [using Docker](#self-host-the-product-documentatio
To upgrade to a later version [using GitLab Pages](#self-host-the-product-documentation-with-gitlab-pages):
-1. Edit your existing `.gitlab-ci.yml` file, and replace the `image`'s version number:
+1. Edit your existing `.gitlab-ci.yml` file, and replace the `image` version number:
```yaml
image: registry.gitlab.com/gitlab-org/gitlab-docs:14.5
diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md
index d2edc3085f1..b6a3a563ae1 100644
--- a/doc/administration/environment_variables.md
+++ b/doc/administration/environment_variables.md
@@ -35,7 +35,7 @@ You can use the following environment variables to override certain values:
| `GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation. |
| `GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN` | string | Sets the initial registration token used for runners. |
| `RAILS_ENV` | string | The Rails environment; can be one of `production`, `development`, `staging`, or `test`. |
-| `UNSTRUCTURED_RAILS_LOG` | string | Enables the unstructured log in addition to JSON logs (defaults to `true`). |
+| `UNSTRUCTURED_RAILS_LOG` | string | Enables the unstructured log in addition to JSON logs (defaults to `false`). |
| `GITLAB_RAILS_CACHE_DEFAULT_TTL_SECONDS` | integer | The default TTL used for entries stored in the Rails-cache. Default is `28800`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95042) in 15.3. |
## Adding more variables
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index 3f98f1e12fe..731f16822fd 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -123,7 +123,8 @@ The following are required to run Geo:
- Note,[PostgreSQL 12 is deprecated](../../update/deprecations.md#postgresql-12-deprecated) and is removed in GitLab 16.0.
- Git 2.9 or later
- Git-lfs 2.4.2 or later on the user side when using LFS
-- All sites must run [the same GitLab and PostgreSQL versions](setup/database.md#postgresql-replication).
+- All sites must run the same GitLab version.
+- All sites must run [the same PostgreSQL versions](setup/database.md#postgresql-replication).
- If using different operating system versions between Geo sites,
[check OS locale data compatibility](replication/troubleshooting.md#check-os-locale-data-compatibility)
across Geo sites to avoid silent corruption of database indexes.
diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md
index 912de360e43..feae2d49e8d 100644
--- a/doc/administration/geo/replication/configuration.md
+++ b/doc/administration/geo/replication/configuration.md
@@ -205,15 +205,16 @@ keys must be manually replicated to the **secondary** site.
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Geo > Sites**.
1. Select **Add site**.
- ![Add secondary site](img/adding_a_secondary_v13_3.png)
- 1. Fill in **Name** with the `gitlab_rails['geo_node_name']` in
- `/etc/gitlab/gitlab.rb`. These values must always match *exactly*, character
+ ![Add secondary site](img/adding_a_secondary_v15_8.png)
+ 1. In **Name**, enter the value for `gitlab_rails['geo_node_name']` in
+ `/etc/gitlab/gitlab.rb`. These values must always match **exactly**, character
for character.
- 1. Fill in **URL** with the `external_url` in `/etc/gitlab/gitlab.rb`. These
+ 1. In **External URL**, enter the value for `external_url` in `/etc/gitlab/gitlab.rb`. These
values must always match, but it doesn't matter if one ends with a `/` and
the other doesn't.
- 1. (Optional) Choose which groups or storage shards should be replicated by the
- **secondary** site. Leave blank to replicate all. Read more in
+ 1. Optional. In **Internal URL (optional)**, enter an internal URL for the primary site.
+ 1. Optional. Select which groups or storage shards should be replicated by the
+ **secondary** site. Leave blank to replicate all. For more information, see
[selective synchronization](#selective-synchronization).
1. Select **Save changes** to add the **secondary** site.
1. SSH into **each Rails, and Sidekiq node on your secondary** site and restart the services:
@@ -366,6 +367,9 @@ former is ideal for replicating data belonging to a subset of users, while the
latter is more suited to progressively rolling out Geo to a large GitLab
instance.
+NOTE:
+Geo's synchronization logic is outlined in the [documentation](../index.md). Both the solution and the documentation is subject to change from time to time. You must independently determine your legal obligations in regard to privacy and cybersecurity laws, and applicable trade control law on an ongoing basis.
+
Selective synchronization:
1. Does not restrict permissions from **secondary** sites.
diff --git a/doc/administration/geo/replication/container_registry.md b/doc/administration/geo/replication/container_registry.md
index 88ca8781dc3..66c67f29c1c 100644
--- a/doc/administration/geo/replication/container_registry.md
+++ b/doc/administration/geo/replication/container_registry.md
@@ -7,7 +7,7 @@ type: howto
# Container Registry for a secondary site **(PREMIUM SELF)**
-You can set up a Container Registry on your **secondary** Geo site that mirrors the one on the **primary** Geo site.
+You can set up a Container Registry on your **secondary** Geo site that mirrors the one on the **primary** Geo site.
NOTE:
The Container Registry replication is used only for disaster recovery purposes. We do not recommend
@@ -76,7 +76,9 @@ the **primary** site before following the next steps.
We need to make Container Registry send notification events to the
**primary** site.
-1. SSH into your GitLab **primary** server and login as root:
+For each application and Sidekiq node on the **primary** site:
+
+1. SSH into the node and login as the `root` user:
```shell
sudo -i
@@ -105,17 +107,15 @@ We need to make Container Registry send notification events to the
that starts with a letter. You can generate one with `< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c 32 | sed "s/^[0-9]*//"; echo`
NOTE:
- If you use an external Registry (not the one integrated with GitLab), you must add
- these settings to its configuration yourself. In this case, you also have to specify
- notification secret in `registry.notification_secret` section of
+ If you use an external Registry (not the one integrated with GitLab), you also have to specify
+ the notification secret (`registry['notification_secret']`) in the
`/etc/gitlab/gitlab.rb` file.
NOTE:
- If you use GitLab HA, you also have to specify
- the notification secret in `registry.notification_secret` section of
+ If you use GitLab HA, you also have to specify the notification secret (`registry['notification_secret']`) in
`/etc/gitlab/gitlab.rb` file for every web node.
-1. Reconfigure the **primary** node for the change to take effect:
+1. Reconfigure each node:
```shell
gitlab-ctl reconfigure
diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md
index 27e1b990b2b..95faafd073c 100644
--- a/doc/administration/geo/replication/datatypes.md
+++ b/doc/administration/geo/replication/datatypes.md
@@ -43,8 +43,8 @@ verification methods:
| Blobs | CI job artifacts _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
| 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 | Container registry _(file system)_ | Geo with API/Docker API | _Not implemented_ |
-| Blobs | Container registry _(object storage)_ | Geo with API/Managed/Docker API (*2*) | _Not implemented_ |
+| 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 | Package registry _(file system)_ | Geo with API | SHA256 checksum |
| Blobs | Package registry _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
| Blobs | Infrastructure registry _(file system)_ | Geo with API | SHA256 checksum |
@@ -139,7 +139,7 @@ We use PostgreSQL's own replication functionality to replicate data from the **p
We use Redis both as a cache store and to hold persistent data for our background jobs system. Because both
use-cases have data that are exclusive to the same Geo site, we don't replicate it between sites.
-Elasticsearch is an optional database that for advanced searching capabilities. It can improve search
+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.
Elasticsearch is not supported in Geo.
@@ -201,7 +201,7 @@ successfully, you must replicate their data using some other means.
|[CI job artifacts](../../../ci/pipelines/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. |
-|[Container Registry](../../packages/container_registry.md) | **Yes** (12.3)* | No | No | No | See [instructions](container_registry.md) to set up the Container Registry replication. |
+|[Container Registry](../../packages/container_registry.md) | **Yes** (12.3)* | **Yes** (15.10) | **Yes** (12.3)* | **Yes** (15.10) | See [instructions](container_registry.md) to set up the Container Registry replication. |
|[Infrastructure Registry](../../../user/packages/infrastructure_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) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/32467) | N/A | N/A | 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) | [No](object_storage.md#verification-of-files-in-object-storage) | Behind feature flag `geo_package_file_replication`, enabled by default. |
diff --git a/doc/administration/geo/replication/geo_validation_tests.md b/doc/administration/geo/replication/geo_validation_tests.md
index a12dd8d9d68..cad3a396bfc 100644
--- a/doc/administration/geo/replication/geo_validation_tests.md
+++ b/doc/administration/geo/replication/geo_validation_tests.md
@@ -127,8 +127,7 @@ The following are PostgreSQL upgrade validation tests we performed.
- Description: With PostgreSQL 12 available as an opt-in version in GitLab 13.3, we tested upgrading
existing Geo installations from PostgreSQL 11 to 12. We also re-tested fresh installations of GitLab
with Geo after fixes were made to support PostgreSQL 12. These tests were done using a
- [nightly build](https://packages.gitlab.com/gitlab/nightly-builds/packages/ubuntu/bionic/gitlab-ee_13.3.6+rnightly.169516.d5209202-0_amd64.deb)
- of GitLab 13.4.
+ nightly build of GitLab 13.4.
- Outcome: Tests were successful for Geo deployments with a single database node on the primary and secondary.
We encountered known issues with repmgr and Patroni managed PostgreSQL clusters on the Geo primary. Using
PostgreSQL 12 with a database cluster on the primary is not recommended until the issues are resolved.
diff --git a/doc/administration/geo/replication/img/adding_a_secondary_v15_8.png b/doc/administration/geo/replication/img/adding_a_secondary_v15_8.png
new file mode 100644
index 00000000000..d7c99e6551e
--- /dev/null
+++ b/doc/administration/geo/replication/img/adding_a_secondary_v15_8.png
Binary files differ
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index 59a67fecfcd..c18bb5b6351 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -42,7 +42,7 @@ to help identify if something is wrong:
![Geo health check](img/geo_site_health_v14_0.png)
-A site shows as "Unhealthy" if the site's status is more than 10 minutes old. In that case, try running the following in the [Rails console](../../operations/rails_console.md) on the affected site:
+A site shows as "Unhealthy" if the site's status is more than 10 minutes old. In that case, try running the following in the [Rails console](../../operations/rails_console.md) on the affected secondary site:
```ruby
Geo::MetricsUpdateWorker.new.perform
@@ -52,7 +52,7 @@ If it raises an error, then the error is probably also preventing the jobs from
If it successfully updates the status, then something may be wrong with Sidekiq. Is it running? Do the logs show errors? This job is supposed to be enqueued every minute. It takes an exclusive lease in Redis to ensure that only one of these jobs can run at a time. The primary site updates its status directly in the PostgreSQL database. Secondary sites send an HTTP Post request to the primary site with their status data.
-A site also shows as "Unhealthy" if certain health checks fail. You can reveal the failure by running the following in the [Rails console](../../operations/rails_console.md) on the affected site:
+A site also shows as "Unhealthy" if certain health checks fail. You can reveal the failure by running the following in the [Rails console](../../operations/rails_console.md) on the affected secondary site:
```ruby
Gitlab::Geo::HealthCheck.new.perform_checks
@@ -1373,6 +1373,23 @@ 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 top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Admin > Geo > Sites**.
+1. Change the URL and save the change.
+
## 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:
diff --git a/doc/administration/geo/replication/upgrading_the_geo_sites.md b/doc/administration/geo/replication/upgrading_the_geo_sites.md
index 55395a55857..644232a2c9e 100644
--- a/doc/administration/geo/replication/upgrading_the_geo_sites.md
+++ b/doc/administration/geo/replication/upgrading_the_geo_sites.md
@@ -33,6 +33,7 @@ and all **secondary** sites:
1. SSH into each node of the **primary** site.
1. [Upgrade GitLab on the **primary** site](../../../update/package/index.md#upgrade-using-the-official-repositories).
1. Perform testing on the **primary** site, particularly if you paused replication in step 1 to protect DR. [There are some suggestions for post-upgrade testing](../../../update/plan_your_upgrade.md#pre-upgrade-and-post-upgrade-checks) in the upgrade documentation.
+1. Ensure that the secrets in the `/etc/gitlab/gitlab-secrets.json` file of both the primary site and the secondary site are the same. The file must be the same on all of a site’s nodes.
1. SSH into each node of **secondary** sites.
1. [Upgrade GitLab on each **secondary** site](../../../update/package/index.md#upgrade-using-the-official-repositories).
1. If you paused replication in step 1, [resume replication on each **secondary**](../index.md#pausing-and-resuming-replication).
diff --git a/doc/administration/geo/secondary_proxy/index.md b/doc/administration/geo/secondary_proxy/index.md
index addf894f0a5..35ab1d8252c 100644
--- a/doc/administration/geo/secondary_proxy/index.md
+++ b/doc/administration/geo/secondary_proxy/index.md
@@ -165,6 +165,7 @@ It does not cover all data types.
| LFS objects (using Git) | **{check-circle}** Yes |
| Pages | **{dotted-circle}** No <sup>2</sup> |
| Advanced search (using the web UI) | **{dotted-circle}** No |
+| Container registry | **{dotted-circle}** No |
1. Git reads are served from the local secondary while pushes get proxied to the primary.
Selective sync or cases where repositories don't exist locally on the Geo secondary throw a "not found" error.
diff --git a/doc/administration/geo/setup/database.md b/doc/administration/geo/setup/database.md
index 99f7b32be59..5f04326d49f 100644
--- a/doc/administration/geo/setup/database.md
+++ b/doc/administration/geo/setup/database.md
@@ -151,6 +151,13 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
ALTER USER gitlab_replicator WITH REPLICATION ENCRYPTED PASSWORD '<replication_password>';
```
+1. Edit `/etc/gitlab/gitlab.rb` and set the role to `geo_primary_role` (for more information, see [Geo roles](https://docs.gitlab.com/omnibus/roles/#gitlab-geo-roles)):
+
+ ```ruby
+ ## Geo Primary role
+ roles(['geo_primary_role'])
+ ```
+
1. Configure PostgreSQL to listen on network interfaces:
For security reasons, PostgreSQL does not listen on any network interfaces
@@ -211,17 +218,6 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
```ruby
##
- ## Geo Primary role
- ## - Configures Postgres settings for replication
- ## - Prevents automatic upgrade of Postgres since it requires downtime of
- ## streaming replication to Geo secondary sites
- ## - Enables standard single-node GitLab services like NGINX, Puma, Redis,
- ## or Sidekiq. If you are segregating services, then you will need to
- ## explicitly disable unwanted services.
- ##
- roles(['geo_primary_role'])
-
- ##
## Primary address
## - replace '<primary_node_ip>' with the public or VPC address of your Geo primary node
##
@@ -239,11 +235,13 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
# postgresql['max_replication_slots'] = 1 # Set this to be the number of Geo secondary nodes if you have more than one
# postgresql['max_wal_senders'] = 10
# postgresql['wal_keep_segments'] = 10
+ ```
- ##
- ## Disable automatic database migrations temporarily
- ## (until PostgreSQL is restarted and listening on the private address).
- ##
+1. Disable automatic database migrations temporarily until PostgreSQL is restarted and listening on the private address.
+ Edit `/etc/gitlab/gitlab.rb` and change the configuration to false:
+
+ ```ruby
+ ## Disable automatic database migrations
gitlab_rails['auto_migrate'] = false
```
@@ -402,6 +400,16 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
Ensure that the contents of `~gitlab-psql/data/server.crt` on the **primary** site
match the contents of `~gitlab-psql/.postgresql/root.crt` on the **secondary** site.
+1. Edit `/etc/gitlab/gitlab.rb` and set the role to `geo_secondary_role` (for more information, see [Geo roles](https://docs.gitlab.com/omnibus/roles/#gitlab-geo-roles)):
+
+ ```ruby
+ ##
+ ## Geo Secondary role
+ ## - configure dependent flags automatically to enable Geo
+ ##
+ roles(['geo_secondary_role'])
+ ```
+
1. Configure PostgreSQL:
This step is similar to how you configured the **primary** instance.
@@ -412,12 +420,6 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
```ruby
##
- ## Geo Secondary role
- ## - configure dependent flags automatically to enable Geo
- ##
- roles(['geo_secondary_role'])
-
- ##
## Secondary address
## - replace '<secondary_site_ip>' with the public or VPC address of your Geo secondary site
##
diff --git a/doc/administration/geo/setup/external_database.md b/doc/administration/geo/setup/external_database.md
index 0fefc11f078..f93ef5f5d5e 100644
--- a/doc/administration/geo/setup/external_database.md
+++ b/doc/administration/geo/setup/external_database.md
@@ -217,14 +217,14 @@ the tracking database on port 5432.
`pg_hba.conf` that is associated with your tracking database.
Remember to restart PostgreSQL afterwards for the changes to take effect:
- ```plaintext
- ##
- ## Geo Tracking Database Role
- ## - pg_hba.conf
- ##
- host all all <trusted tracking IP>/32 md5
- host all all <trusted secondary IP>/32 md5
- ```
+ ```plaintext
+ ##
+ ## Geo Tracking Database Role
+ ## - pg_hba.conf
+ ##
+ host all all <trusted tracking IP>/32 md5
+ host all all <trusted secondary IP>/32 md5
+ ```
1. SSH into a GitLab **secondary** server and login as root:
diff --git a/doc/administration/geo/setup/index.md b/doc/administration/geo/setup/index.md
index c794b8ef219..022d9c00772 100644
--- a/doc/administration/geo/setup/index.md
+++ b/doc/administration/geo/setup/index.md
@@ -7,25 +7,22 @@ type: howto
# Setting up Geo **(PREMIUM SELF)**
-These instructions assume you have a working instance of GitLab. They guide you through:
+## Prerequisites
-1. Making your existing instance the **primary** site.
-1. Adding **secondary** sites.
+- Two (or more) independently working GitLab sites:
+ - One GitLab site serves as the Geo **primary** site. Use the [GitLab reference architectures documentation](../../reference_architectures/index.md) to set this up. You can use different reference architecture sizes for each Geo site. If you already have a working GitLab instance that is in-use, it can be used as a **primary** site.
+ - The second GitLab site serves as the Geo **secondary** site. Use the [GitLab reference architectures documentation](../../reference_architectures/index.md) to set this up. It's a good idea to sign in and test it. However, be aware that **all of the data on the secondary are lost** as part of the process of replicating from the **primary** site.
-You must use a [GitLab Premium](https://about.gitlab.com/pricing/) license or higher,
-but you only need one license for all the sites.
+ NOTE:
+ Geo supports multiple secondaries. You can follow the same steps and make any changes accordingly.
-WARNING:
-The steps below should be followed in the order they appear. **Make sure the GitLab version is the same on all sites. Do not create an account or sign in to the new secondary.**
+- Ensure the **primary** site has a [GitLab Premium](https://about.gitlab.com/pricing/) license or higher to unlock Geo. You only need one license for all the sites.
+- Confirm the [requirements for running Geo](../index.md#requirements-for-running-geo) are met by all sites. For example, sites must use the same GitLab version, and sites must be able to communicate with each other over certain ports.
## Using Omnibus GitLab
If you installed GitLab using the Omnibus packages (highly recommended):
-1. Confirm the [requirements for running Geo](../index.md#requirements-for-running-geo) are met.
-1. [Install GitLab Enterprise Edition](https://about.gitlab.com/install/) on the nodes that serve as the **secondary** site. **Do not create an account or sign in** to the new **secondary** site. The **GitLab version must match** across primary and secondary sites.
-1. [Add the GitLab License](../../../user/admin_area/license.md) on the **primary** site to unlock Geo. The license must be for [GitLab Premium](https://about.gitlab.com/pricing/) or higher.
-1. [Confirm network connectivity](../index.md#firewall-rules) between the **primary** and **secondary** site.
1. [Set up the database replication](database.md) (`primary (read-write) <-> secondary (read-only)` topology).
1. [Configure fast lookup of authorized SSH keys in the database](../../operations/fast_ssh_key_lookup.md). This step is required and needs to be done on **both** the **primary** and **secondary** sites.
1. [Configure GitLab](../replication/configuration.md) to set the **primary** and **secondary** sites.
@@ -34,6 +31,10 @@ If you installed GitLab using the Omnibus packages (highly recommended):
1. Optional: [Configure Geo secondary proxying](../secondary_proxy/index.md) to use a single, unified URL for all Geo sites. This step is recommended to accelerate most read requests while transparently proxying writes to the primary Geo site.
1. Follow the [Using a Geo Site](../replication/usage.md) guide.
+## Using GitLab Charts
+
+[Configure the GitLab chart with GitLab Geo](https://docs.gitlab.com/charts/advanced/geo/).
+
## Post-installation documentation
After installing GitLab on the **secondary** sites and performing the initial configuration, see the [following documentation for post-installation information](../index.md#post-installation-documentation).
diff --git a/doc/administration/get_started.md b/doc/administration/get_started.md
index d9191440a24..b11524083b1 100644
--- a/doc/administration/get_started.md
+++ b/doc/administration/get_started.md
@@ -1,7 +1,7 @@
---
-info: For assistance with this CSM Onboarding page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
+info: For assistance with this tutorial, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
stage: none
-group: unassigned
+group: Tutorials
---
# Get started administering GitLab **(FREE)**
@@ -151,7 +151,8 @@ Backups of GitLab databases and file systems are taken every 24 hours, and are k
- You can use the project export option in:
- [The UI](../user/project/settings/import_export.md#export-a-project-and-its-data).
- [The API](../api/project_import_export.md#schedule-an-export).
-- [Group export](../user/group/settings/import_export.md) does *not* export the projects in it, but does export:
+- [Group export by uploading a file export](../user/group/import/index.md#migrate-groups-by-uploading-an-export-file-deprecated)
+ does **not** export the projects in it, but does export:
- Epics
- Milestones
- Boards
diff --git a/doc/administration/git_protocol.md b/doc/administration/git_protocol.md
index 349a92de51e..df9bdb0ee8d 100644
--- a/doc/administration/git_protocol.md
+++ b/doc/administration/git_protocol.md
@@ -111,4 +111,4 @@ URL to use SSH.
### Observe Git protocol version of connections
For information on observing the Git protocol versions are being used in a production environment,
-see the [relevant documentation](gitaly/monitoring.md#useful-queries).
+see the [relevant documentation](gitaly/monitoring.md#queries).
diff --git a/doc/administration/gitaly/configure_gitaly.md b/doc/administration/gitaly/configure_gitaly.md
index 143f7dca7d3..543f5b3c119 100644
--- a/doc/administration/gitaly/configure_gitaly.md
+++ b/doc/administration/gitaly/configure_gitaly.md
@@ -143,10 +143,16 @@ Gitaly and GitLab use two shared secrets for authentication:
To configure the _Gitaly token_, edit `/etc/gitlab/gitlab.rb`:
```ruby
- gitaly['auth_token'] = 'abc123secret'
+ gitaly['configuration'] = {
+ # ...
+ auth: {
+ # ...
+ token: 'abc123secret',
+ },
+ }
```
-There are two ways to configure the _GitLab Shell token_.
+Configure the _GitLab Shell token_ in one of two ways.
Method 1 (recommended):
@@ -230,14 +236,21 @@ Updates to example must be made at:
# Don't forget to copy `/etc/gitlab/gitlab-secrets.json` from Gitaly client to Gitaly server.
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
- # Make Gitaly accept connections on all network interfaces. You must use
- # firewalls to restrict access to this address/port.
- # Comment out following line if you only want to support TLS connections
- gitaly['listen_addr'] = "0.0.0.0:8075"
-
- # Authentication token to ensure only authorized servers can communicate with
- # Gitaly server
- gitaly['auth_token'] = 'AUTH_TOKEN'
+ gitaly['configuration'] = {
+ # ...
+ #
+ # Make Gitaly accept connections on all network interfaces. You must use
+ # firewalls to restrict access to this address/port.
+ # Comment out following line if you only want to support TLS connections
+ listen_addr: '0.0.0.0:8075',
+ auth: {
+ # ...
+ #
+ # Authentication token to ensure only authorized servers can communicate with
+ # Gitaly server
+ token: 'AUTH_TOKEN',
+ },
+ }
```
1. Append the following to `/etc/gitlab/gitlab.rb` for each respective Gitaly server:
@@ -247,24 +260,33 @@ Updates to example must be made at:
On `gitaly1.internal`:
```ruby
- git_data_dirs({
- 'default' => {
- 'path' => '/var/opt/gitlab/git-data'
- },
- 'storage1' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'default',
+ path: '/var/opt/gitlab/git-data',
+ },
+ {
+ name: 'storage1',
+ path: '/mnt/gitlab/git-data',
+ },
+ ],
+ }
```
On `gitaly2.internal`:
```ruby
- git_data_dirs({
- 'storage2' => {
- 'path' => '/srv/gitlab/git-data'
- },
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'storage2',
+ path: '/srv/gitlab/git-data',
+ },
+ ],
+ }
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -461,17 +483,28 @@ example:
git_data_dirs({
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
# Address of the GitLab server that also has Gitaly running on it
- 'storage1' => { 'gitaly_address' => 'tcp://gitlab.internal:8075', 'path' => '/mnt/gitlab/git-data' },
+ 'storage1' => { 'gitaly_address' => 'tcp://gitlab.internal:8075' },
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
})
-# Make Gitaly accept connections on all network interfaces
-gitaly['listen_addr'] = "0.0.0.0:8075"
-
-# Or for TLS
-gitaly['tls_listen_addr'] = "0.0.0.0:9999"
-gitaly['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
-gitaly['key_path'] = "/etc/gitlab/ssl/key.pem"
+gitaly['configuration'] = {
+ # ...
+ #
+ # Make Gitaly accept connections on all network interfaces
+ listen_addr: '0.0.0.0:8075',
+ # Or for TLS
+ tls_listen_addr: '0.0.0.0:9999',
+ tls: {
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ storage: [
+ {
+ name: 'storage1',
+ path: '/mnt/gitlab/git-data',
+ },
+ ],
+}
```
`path` can be included only for storage shards on the local Gitaly server.
@@ -523,9 +556,6 @@ To disable Gitaly on a GitLab server:
## Enable TLS support
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22602) in GitLab 11.8.
-> - [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/3160) in GitLab 13.6, outgoing TLS connections to GitLab provide client certificates if configured.
-
Gitaly supports TLS encryption. To communicate with a Gitaly instance that listens for secure
connections, use the `tls://` URL scheme in the `gitaly_address` of the corresponding
storage entry in the GitLab configuration.
@@ -543,6 +573,8 @@ Additionally, the certificate (or its certificate authority) must be installed o
- Gitaly servers.
- Gitaly clients that communicate with it.
+If you use a load balancer, it must be able to negotiate HTTP/2 using the ALPN TLS extension.
+
### Certificate requirements
- The certificate must specify the address you use to access the Gitaly server. You must add the hostname or IP address as a Subject Alternative Name to the certificate.
@@ -600,16 +632,21 @@ To configure Gitaly with TLS:
<!-- Updates to following example must also be made at https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab -->
```ruby
- gitaly['tls_listen_addr'] = "0.0.0.0:9999"
- gitaly['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
- gitaly['key_path'] = "/etc/gitlab/ssl/key.pem"
+ gitaly['configuration'] = {
+ # ...
+ tls_listen_addr: '0.0.0.0:9999',
+ tls: {
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ }
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Verify Gitaly traffic is being served over TLS by
[observing the types of Gitaly connections](#observe-type-of-gitaly-connections).
1. Optional. Improve security by:
- 1. Disabling non-TLS connections by commenting out or deleting `gitaly['listen_addr']` in
+ 1. Disabling non-TLS connections by commenting out or deleting `gitaly['configuration'][:listen_addr]` in
`/etc/gitlab/gitlab.rb`.
1. Saving the file.
1. [Reconfiguring GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -693,7 +730,7 @@ To configure Gitaly with TLS:
### Observe type of Gitaly connections
For information on observing the type of Gitaly connections being served, see the
-[relevant documentation](monitoring.md#useful-queries).
+[relevant documentation](monitoring.md#queries).
## `gitaly-ruby`
@@ -708,14 +745,13 @@ Gitaly Go process. Some examples of things that are implemented in `gitaly-ruby`
- RPCs that deal with wikis.
- RPCs that create commits on behalf of a user, such as merge commits.
-We recommend:
+Recommended settings:
- At least 300 MB memory per worker.
- No more than one worker per core.
NOTE:
-`gitaly-ruby` is planned to be eventually removed. To track progress, see the
-[Remove the Gitaly-Ruby sidecar](https://gitlab.com/groups/gitlab-org/-/epics/2862) epic.
+[Epic 2862](https://gitlab.com/groups/gitlab-org/-/epics/2862) proposes to remove `gitaly-ruby`.
### Configure number of `gitaly-ruby` workers
@@ -733,9 +769,16 @@ settings:
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
- # Default is 2 workers. The minimum is 2; 1 worker is always reserved as
- # a passive stand-by.
- gitaly['ruby_num_workers'] = 4
+ gitaly['configuration'] = {
+ # ...
+ 'gitaly-ruby': {
+ # ...
+ #
+ # Default is 2 workers. The minimum is 2; 1 worker is always reserved as
+ # a passive stand-by.
+ num_workers: 4
+ },
+ }
```
1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -775,21 +818,23 @@ example:
```ruby
# in /etc/gitlab/gitlab.rb
-
-gitaly['concurrency'] = [
- {
- 'rpc' => "/gitaly.SmartHTTPService/PostUploadPackWithSidechannel",
- 'max_per_repo' => 20,
- 'max_queue_time' => "1s",
- 'max_queue_size' => 10
- },
- {
- 'rpc' => "/gitaly.SSHService/SSHUploadPackWithSidechannel",
- 'max_per_repo' => 20
- 'max_queue_time' => "1s",
- 'max_queue_size' => 10
- }
-]
+gitaly['configuration'] = {
+ # ...
+ concurrency: [
+ {
+ rpc: '/gitaly.SmartHTTPService/PostUploadPackWithSidechannel',
+ max_per_repo: 20,
+ max_queue_time: '1s',
+ max_queue_size: 10,
+ },
+ {
+ rpc: '/gitaly.SSHService/SSHUploadPackWithSidechannel',
+ max_per_repo: 20,
+ max_queue_time: '1s',
+ max_queue_size: 10,
+ },
+ ],
+}
```
- `rpc` is the name of the RPC to set a concurrency limit for per repository.
@@ -834,7 +879,7 @@ performance.
You can use control groups (cgroups) in Linux to impose limits on how much memory and CPU can be consumed by Gitaly processes.
See the [`cgroups` Linux man page](https://man7.org/linux/man-pages/man7/cgroups.7.html) for more information.
-cgroups can be useful for protecting the system against unexpected resource exhaustion because of over consumption of memory and CPU.
+cgroups can help protect the system against unexpected resource exhaustion because of over consumption of memory and CPU.
Some Git operations can consume notable resources up to the point of exhaustion in situations such as:
@@ -861,43 +906,60 @@ When these limits are reached, performance may be reduced and users may be disco
### Configure repository cgroups (new method)
-> This method of configuring repository cgroups was introduced in GitLab 15.1.
+> - This method of configuring repository cgroups was introduced in GitLab 15.1.
+> - `cpu_quota_us`[introduced](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5422) in GitLab 15.10.
To configure repository cgroups in Gitaly using the new method, use the following settings for the new configuration method
-to `gitaly['cgroups']` in `/etc/gitlab/gitlab.rb`:
+to `gitaly['configuration'][:cgroups]` in `/etc/gitlab/gitlab.rb`:
-- `cgroups_mountpoint` is where the parent cgroup directory is mounted. Defaults to `/sys/fs/cgroup`.
-- `cgroups_hierarchy_root` is the parent cgroup under which Gitaly creates groups, and
+- `mountpoint` is where the parent cgroup directory is mounted. Defaults to `/sys/fs/cgroup`.
+- `hierarchy_root` is the parent cgroup under which Gitaly creates groups, and
is expected to be owned by the user and group Gitaly runs as. Omnibus GitLab
creates the set of directories `mountpoint/<cpu|memory>/hierarchy_root`
when Gitaly starts.
-- `cgroups_memory_bytes` is the total memory limit that is imposed collectively on all
+- `memory_bytes` is the total memory limit that is imposed collectively on all
Git processes that Gitaly spawns. 0 implies no limit.
-- `cgroups_cpu_shares` is the CPU limit that is imposed collectively on all Git
+- `cpu_shares` is the CPU limit that is imposed collectively on all Git
processes that Gitaly spawns. 0 implies no limit. The maximum is 1024 shares,
which represents 100% of CPU.
-- `cgroups_repositories_count` is the number of cgroups in the cgroups pool. Each time a new Git
+- `cpu_quota_us` is the [`cfs_quota_us`](https://docs.kernel.org/scheduler/sched-bwc.html#management)
+ to throttle the cgroups' processes if they exceed this quota value. We set
+ `cfs_period_us` to `100ms` so 1 core is `100000`. 0 implies no limit.
+- `repositories.count` is the number of cgroups in the cgroups pool. Each time a new Git
command is spawned, Gitaly assigns it to one of these cgroups based
on the repository the command is for. A circular hashing algorithm assigns
Git commands to these cgroups, so a Git command for a repository is
always assigned to the same cgroup.
-- `cgroups_repositories_memory_bytes` is the total memory limit imposed on all Git processes contained in a repository cgroup.
- 0 implies no limit. This value cannot exceed that of the top level `cgroups_memory_bytes`.
-- `cgroups_repositories_cpu_shares` is the CPU limit that is imposed on all Git processes contained in a repository cgroup.
+- `repositories.memory_bytes` is the total memory limit imposed on all Git processes contained in a repository cgroup.
+ 0 implies no limit. This value cannot exceed that of the top level `memory_bytes`.
+- `repositories.cpu_shares` is the CPU limit that is imposed on all Git processes contained in a repository cgroup.
0 implies no limit. The maximum is 1024 shares, which represents 100% of CPU.
- This value cannot exceed that of the top level`cgroups_cpu_shares`.
+ This value cannot exceed that of the top level`cpu_shares`.
+- `repositories.cpu_quota_us` is the [`cfs_quota_us`](https://docs.kernel.org/scheduler/sched-bwc.html#management)
+ that is imposed on all Git processes contained in a repository cgroup. A Git
+ process can't use more then the given quota. We set
+ `cfs_period_us` to `100ms` so 1 core is `100000`. 0 implies no limit.
For example:
```ruby
# in /etc/gitlab/gitlab.rb
-gitaly['cgroups_mountpoint'] = "/sys/fs/cgroup"
-gitaly['cgroups_hierarchy_root'] => "gitaly"
-gitaly['cgroups_memory_bytes'] = 64424509440, # 60gb
-gitaly['cgroups_cpu_shares'] = 1024
-gitaly['cgroups_repositories_count'] => 1000,
-gitaly['cgroups_repositories_memory_bytes'] => 32212254720 # 20gb
-gitaly['cgroups_repositories_cpu_shares'] => 512
+gitaly['configuration'] = {
+ # ...
+ cgroups: {
+ mountpoint: '/sys/fs/cgroup',
+ hierarchy_root: 'gitaly',
+ memory_bytes: 64424509440, # 60gb
+ cpu_shares: 1024,
+ cpu_quota_us: 400000 # 4 cores
+ repositories: {
+ count: 1000,
+ memory_bytes: 32212254720, # 20gb
+ cpu_shares: 512,
+ cpu_quota_us: 200000 # 2 cores
+ },
+ },
+}
```
### Configure repository cgroups (legacy method)
@@ -953,14 +1015,14 @@ This strategy has two main benefits:
to 3 child cgroups can concurrently burst up to their max. In general, all
1000 cgroups would use much less than the 20 GB.
-## Background Repository Optimization
+## Background repository optimization
Empty directories and unneeded configuration settings may accumulate in a repository and
slow down Git operations. Gitaly can schedule a daily background task with a maximum duration
to clean up these items and improve performance.
WARNING:
-This is an experimental feature and may place significant load on the host while running.
+Background repository optimization is an experimental feature and may place significant load on the host while running.
Make sure to schedule this during off-peak hours and keep the duration short (for example, 30-60 minutes).
**For Omnibus GitLab**
@@ -968,10 +1030,16 @@ Make sure to schedule this during off-peak hours and keep the duration short (fo
Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
-gitaly['daily_maintenance_start_hour'] = 4
-gitaly['daily_maintenance_start_minute'] = 30
-gitaly['daily_maintenance_duration'] = '30m'
-gitaly['daily_maintenance_storages'] = ["default"]
+gitaly['configuration'] = {
+ # ...
+ daily_maintenance: {
+ # ...
+ start_hour: 4,
+ start_minute: 30,
+ duration: '30m',
+ storages: ['default'],
+ },
+}
```
**For installations from source**
@@ -1006,7 +1074,7 @@ server" and "Gitaly client" refers to the same machine.
### Verify authentication monitoring
Before rotating a Gitaly authentication token, verify that you can
-[monitor the authentication behavior](monitoring.md#useful-queries) of your GitLab installation using
+[monitor the authentication behavior](monitoring.md#queries) of your GitLab installation using
Prometheus.
You can then continue the rest of the procedure.
@@ -1018,7 +1086,13 @@ transitioning" mode as follows:
```ruby
# in /etc/gitlab/gitlab.rb
-gitaly['auth_transitioning'] = true
+gitaly['configuration'] = {
+ # ...
+ auth: {
+ # ...
+ transitioning: true,
+ },
+}
```
After you have made this change, your [Prometheus query](#verify-authentication-monitoring)
@@ -1038,8 +1112,13 @@ To update to a new Gitaly authentication token, on each Gitaly client **and** Gi
```ruby
# in /etc/gitlab/gitlab.rb
-
- gitaly['auth_token'] = '<new secret token>'
+ gitaly['configuration'] = {
+ # ...
+ auth: {
+ # ...
+ token: '<new secret token>',
+ },
+ }
```
1. Restart Gitaly:
@@ -1069,7 +1148,13 @@ your Gitaly servers as follows:
```ruby
# in /etc/gitlab/gitlab.rb
-gitaly['auth_transitioning'] = false
+gitaly['configuration'] = {
+ # ...
+ auth: {
+ # ...
+ transitioning: false,
+ },
+}
```
WARNING:
@@ -1088,17 +1173,11 @@ result as you did at the start. For example:
## Pack-objects cache **(FREE SELF)**
-> - [Introduced](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/372) in GitLab 13.11.
-> - It's enabled on GitLab.com.
-> - It's recommended for production use.
-
[Gitaly](index.md), the service that provides storage for Git
repositories, can be configured to cache a short rolling window of Git
fetch responses. This can reduce server load when your server receives
lots of CI fetch traffic.
-### Overview
-
The pack-objects cache wraps `git pack-objects`, an internal part of
Git that gets invoked indirectly via the PostUploadPack and
SSHUploadPack Gitaly RPCs. Gitaly runs PostUploadPack when a
@@ -1135,27 +1214,33 @@ disk write IO, it is off by default.
### Configure the cache
-These are the configuration settings for the pack-objects cache. Each
-setting is discussed in greater detail below.
+These configuration settings are available for the pack-objects cache. Each setting is discussed in greater detail
+below.
-|Setting|Default|Description|
-|:---|:---|:---|
-|`enabled`|`false`|Turns on the cache. When off, Gitaly runs a dedicated `git pack-objects` process for each request. |
-|`dir`|`<PATH TO FIRST STORAGE>/+gitaly/PackObjectsCache`|Local directory where cache files get stored.|
-|`max_age`|`5m` (5 minutes)|Cache entries older than this get evicted and removed from disk.|
+| Setting | Default | Description |
+|:----------|:---------------------------------------------------|:---------------------------------------------------------------------------------------------------|
+| `enabled` | `false` | Turns on the cache. When off, Gitaly runs a dedicated `git pack-objects` process for each request. |
+| `dir` | `<PATH TO FIRST STORAGE>/+gitaly/PackObjectsCache` | Local directory where cache files get stored. |
+| `max_age` | `5m` (5 minutes) | Cache entries older than this get evicted and removed from disk. |
In `/etc/gitlab/gitlab.rb`, set:
```ruby
-gitaly['pack_objects_cache_enabled'] = true
-## gitaly['pack_objects_cache_dir'] = '/var/opt/gitlab/git-data/repositories/+gitaly/PackObjectsCache'
-## gitaly['pack_objects_cache_max_age'] = '5m'
+gitaly['configuration'] = {
+ # ...
+ pack_objects_cache: {
+ # ...
+ enabled: true,
+ # dir: '/var/opt/gitlab/git-data/repositories/+gitaly/PackObjectsCache',
+ # max_age: '5m',
+ },
+}
```
#### `enabled` defaults to `false`
-The cache is disabled by default. This is because in some cases, it
-can create an [extreme increase](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/4010#note_534564684)
+The cache is disabled by default because in some cases, it can create an
+[extreme increase](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/4010#note_534564684)
in the number of bytes written to disk. On GitLab.com, we have verified
that our repository storage disks can handle this extra workload, but
we felt we cannot assume this is true everywhere.
@@ -1198,7 +1283,7 @@ The amount of space required depends on:
- The size of the `max_age` cache eviction window.
If your users pull 100 MB/s and you use a 5 minute window, then on average you have
-`5*60*100MB = 30GB` of data in your cache directory. This is an expected average, not
+`5*60*100MB = 30GB` of data in your cache directory. This average is an expected average, not
a guarantee. Peak size may exceed this average.
#### Cache eviction window `max_age`
@@ -1208,11 +1293,9 @@ cache hit and the average amount of storage used by cache files.
Entries older than `max_age` get evicted from the in-memory metadata
store, and deleted from disk.
-Eviction does not interfere with ongoing requests, so it is OK
-for `max_age` to be less than the time it takes to do a fetch over a
-slow connection. This is because Unix filesystems do not truly delete
-a file until all processes that are reading the deleted file have
-closed it.
+Eviction does not interfere with ongoing requests. It is OK for `max_age` to be less than the time it takes to do a
+fetch over a slow connection because Unix filesystems do not truly delete a file until all processes that are reading
+the deleted file have closed it.
### Observe the cache
@@ -1315,7 +1398,32 @@ process repositories that do not pass consistency checks.
For Omnibus GitLab installations, edit `/etc/gitlab/gitlab.rb` and set the
following keys (in this example, to disable the `hasDotgit` consistency check):
-- In [GitLab 15.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6800) and later:
+- In [GitLab 15.10](https://gitlab.com/gitlab-org/gitaly/-/issues/4754) and later:
+
+ ```ruby
+ ignored_blobs = "/etc/gitlab/instance_wide_ignored_git_blobs.txt"
+
+ gitaly['configuration'] = {
+ # ...
+ git: {
+ # ...
+ config: [
+ # Populate a file with one unabbreviated SHA-1 per line.
+ # See https://git-scm.com/docs/git-config#Documentation/git-config.txt-fsckskipList
+ { key: "fsck.skipList", value: ignored_blobs },
+ { key: "fetch.fsck.skipList", value: ignored_blobs },
+ { key: "receive.fsck.skipList", value: ignored_blobs },
+
+ { key: "fsck.hasDotgit", value: "ignore" },
+ { key: "fetch.fsck.hasDotgit", value: "ignore" },
+ { key: "receive.fsck.hasDotgit", value: "ignore" },
+ { key: "fsck.missingSpaceBeforeEmail", value: "ignore" },
+ ],
+ },
+ }
+ ```
+
+- In [GitLab 15.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6800) to GitLab 15.9:
```ruby
ignored_blobs = "/etc/gitlab/instance_wide_ignored_git_blobs.txt"
@@ -1423,7 +1531,13 @@ proposed in issue [19185](https://gitlab.com/gitlab-org/gitlab/-/issues/19185).
1. Edit `/etc/gitlab/gitlab.rb` and configure `gitaly['gpg_signing_key_path']`:
```ruby
- gitaly['gpg_signing_key_path'] = "/etc/gitlab/gitaly/signing_key.gpg"
+ gitaly['configuration'] = {
+ # ...
+ git: {
+ # ...
+ signing_key: '/etc/gitlab/gitaly/signing_key.gpg',
+ },
+ }
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index 405c56284cf..34e72f3eb5a 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -78,7 +78,7 @@ the current status of these issues, refer to the referenced issues and epics.
Gitaly Cluster does not support snapshot backups. Snapshot backups can cause issues where the Praefect database becomes
out of sync with the disk storage. Because of how Praefect rebuilds the replication metadata of Gitaly disk information
-during a restore, we recommend using the [official backup and restore Rake tasks](../../raketasks/backup_restore.md).
+during a restore, you should use the [official backup and restore Rake tasks](../../raketasks/backup_restore.md).
The [incremental backup method](../../raketasks/backup_gitlab.md#incremental-repository-backups)
can be used to speed up Gitaly Cluster backups.
@@ -100,7 +100,7 @@ These SSDs should have a throughput of at least:
- 2,000 IOPS for write operations.
These IOPS values are initial recommendations, and may be adjusted to greater or lesser values
-depending on the scale of your environment's workload. If you’re running the environment on a
+depending on the scale of your environment's workload. If you're running the environment on a
cloud provider, refer to their documentation about how to configure IOPS correctly.
For repository data, only local storage is supported for Gitaly and Gitaly Cluster for performance and consistency reasons.
@@ -363,10 +363,10 @@ For example, `@cluster/repositories/6f/96/54771`.
The last component of the replica path, `54771`, is the repository ID. This can be used to identify the repository on the disk.
-`<xx>/<xx>` are the first four hex digits of the SHA256 hash of the string representation of the repository ID. This is used to balance
-the repositories evenly into subdirectories to avoid overly large directories that might cause problems on some file
-systems. In this case, `54771` hashes to `6f960ab01689464e768366d3315b3d3b2c28f38761a58a70110554eb04d582f7` so the
-first four digits are `6f` and `96`.
+`<xx>/<xx>` are the first four hex digits of the SHA256 hash of the string representation of the repository ID. These
+digits are used to balance the repositories evenly into subdirectories to avoid overly large directories that might
+cause problems on some file systems. In this case, `54771` hashes to
+`6f960ab01689464e768366d3315b3d3b2c28f38761a58a70110554eb04d582f7` so the first four digits are `6f` and `96`.
#### Identify repositories on disk
@@ -387,8 +387,9 @@ Follow the [instructions in hashed storage's documentation](../repository_storag
Gitaly Cluster uses the PostgreSQL metadata store with the storage layout to ensure atomicity of repository creation,
deletion, and move operations. The disk operations can't be atomically applied across multiple storages. However, PostgreSQL guarantees
the atomicity of the metadata operations. Gitaly Cluster models the operations in a manner that the failing operations always leave
-the metadata consistent. The disks may contain stale state even after successful operations. This is expected and the leftover state
-does not interfere with future operations but may use up disk space unnecessarily until a clean up is performed.
+the metadata consistent. The disks may contain stale state even after successful operations. This situation is expected and
+the leftover state does not interfere with future operations but may use up disk space unnecessarily until a clean up is
+performed.
There is on-going work on a [background crawler](https://gitlab.com/gitlab-org/gitaly/-/issues/3719) that cleans up the leftover
repositories from the storages.
@@ -397,7 +398,7 @@ repositories from the storages.
When creating repositories, Praefect:
-1. Reserves a repository ID from PostgreSQL. This is atomic and no two creations receive the same ID.
+1. Reserves a repository ID from PostgreSQL, which is atomic and no two creations receive the same ID.
1. Creates replicas on the Gitaly storages in the replica path derived from the repository ID.
1. Creates metadata records after the repository is successfully created on disk.
@@ -470,7 +471,7 @@ _Up to date_ in this context means that:
The primary node is chosen to serve the request if:
-- There are no up to date nodes.
+- No up-to-date nodes exist.
- Any other error occurs during node selection.
You can [monitor distribution of reads](monitoring.md#monitor-gitaly-cluster) using Prometheus.
@@ -677,7 +678,7 @@ Direct Git access is:
For the sake of removing complexity, we must remove direct Git access in GitLab. However, we can't
remove it as long some GitLab installations require Git repositories on NFS.
-There are two facets to our efforts to remove direct Git access in GitLab:
+Two facets of our efforts to remove direct Git access in GitLab are:
- Reduce the number of inefficient Gitaly queries made by GitLab.
- Persuade administrators of fault-tolerant or horizontally-scaled GitLab instances to migrate off
diff --git a/doc/administration/gitaly/monitoring.md b/doc/administration/gitaly/monitoring.md
index 0fd34d5c89f..d4f3d931b03 100644
--- a/doc/administration/gitaly/monitoring.md
+++ b/doc/administration/gitaly/monitoring.md
@@ -54,6 +54,9 @@ You can observe the status of [control groups (cgroups)](configure_gitaly.md#con
- `gitaly_cgroups_cpu_usage`, a gauge that measures CPU usage per cgroup.
- `gitaly_cgroup_procs_total`, a gauge that measures the total number of
processes Gitaly has spawned under the control of cgroups.
+- `gitaly_cgroup_cpu_cfs_periods_total`, a counter that for the value of [`nr_periods`](https://docs.kernel.org/scheduler/sched-bwc.html#statistics).
+- `gitaly_cgroup_cpu_cfs_throttled_periods_total`, a counter for the value of [`nr_throttled`](https://docs.kernel.org/scheduler/sched-bwc.html#statistics).
+- `gitaly_cgroup_cpu_cfs_throttled_seconds_total`, a counter for the value of [`throttled_time`](https://docs.kernel.org/scheduler/sched-bwc.html#statistics) in seconds.
## `pack-objects` cache
@@ -86,9 +89,9 @@ gitaly_streamcache_filestore_removed_total{dir="/var/opt/gitlab/git-data/reposit
gitaly_streamcache_index_entries{dir="/var/opt/gitlab/git-data/repositories/+gitaly/PackObjectsCache"} 1
```
-## Useful queries
+## Queries
-The following are useful queries for monitoring Gitaly:
+The following are some queries for monitoring Gitaly:
- Use the following Prometheus query to observe the
[type of connections](configure_gitaly.md#enable-tls-support) Gitaly is serving a production
@@ -130,8 +133,8 @@ The following are useful queries for monitoring Gitaly:
## Monitor Gitaly Cluster
-To monitor Gitaly Cluster (Praefect), you can use these Prometheus metrics. There are two separate metrics
-endpoints from which metrics can be scraped:
+To monitor Gitaly Cluster (Praefect), you can use these Prometheus metrics. Two separate metrics endpoints are
+available from which metrics can be scraped:
- The default `/metrics` endpoint.
- `/db_metrics`, which contains metrics that require database queries.
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index 440bd7427ae..efaa8c1ee18 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -142,7 +142,7 @@ with secure tokens as you complete the setup process.
1. `PRAEFECT_EXTERNAL_TOKEN`: repositories hosted on your Praefect cluster can
only be accessed by Gitaly clients that carry this token.
1. `PRAEFECT_INTERNAL_TOKEN`: this token is used for replication traffic inside
- your Praefect cluster. This is distinct from `PRAEFECT_EXTERNAL_TOKEN`
+ your Praefect cluster. This token is distinct from `PRAEFECT_EXTERNAL_TOKEN`
because Gitaly clients must not be able to access internal nodes of the
Praefect cluster directly; that could lead to data loss.
1. `PRAEFECT_SQL_PASSWORD`: this password is used by Praefect to connect to
@@ -269,11 +269,16 @@ The database used by Praefect is now configured.
You can now configure Praefect to use the database:
```ruby
-praefect['database_host'] = POSTGRESQL_HOST
-praefect['database_port'] = 5432
-praefect['database_user'] = 'praefect'
-praefect['database_password'] = PRAEFECT_SQL_PASSWORD
-praefect['database_dbname'] = 'praefect_production'
+praefect['configuration'] = {
+ # ...
+ database: {
+ # ...
+ host: POSTGRESQL_HOST,
+ port: 5432,
+ password: PRAEFECT_SQL_PASSWORD,
+ dbname: 'praefect_production',
+ }
+}
```
If you see Praefect database errors after configuring PostgreSQL, see
@@ -285,19 +290,27 @@ Praefect performance can be improved by additionally configuring the `database_d
settings:
```ruby
-praefect['database_direct_host'] = POSTGRESQL_HOST
-praefect['database_direct_port'] = 5432
-
-# Use the following to override parameters of direct database connection.
-# Comment out where the parameters are the same for both connections.
-
-praefect['database_direct_user'] = 'praefect'
-praefect['database_direct_password'] = PRAEFECT_SQL_PASSWORD
-praefect['database_direct_dbname'] = 'praefect_production'
-#praefect['database_direct_sslmode'] = '...'
-#praefect['database_direct_sslcert'] = '...'
-#praefect['database_direct_sslkey'] = '...'
-#praefect['database_direct_sslrootcert'] = '...'
+praefect['configuration'] = {
+ # ...
+ database: {
+ # ...
+ session_pooled: {
+ # ...
+ host: POSTGRESQL_HOST,
+ port: 5432
+
+ # Use the following to override parameters of direct database connection.
+ # Comment out where the parameters are the same for both connections.
+ user: 'praefect',
+ password: PRAEFECT_SQL_PASSWORD,
+ dbname: 'praefect_production',
+ # sslmode: '...',
+ # sslcert: '...',
+ # sslkey: '...',
+ # sslrootcert: '...',
+ }
+ }
+}
```
When configured, this connection is automatically used for the
@@ -313,8 +326,8 @@ reads distribution caching is enabled by configuration
#### Use PgBouncer
-To reduce PostgreSQL resource consumption, we recommend setting up and configuring
-[PgBouncer](https://www.pgbouncer.org/) in front of the PostgreSQL instance. However, PgBouncer isn't required because
+To reduce PostgreSQL resource consumption, you should set up and configure [PgBouncer](https://www.pgbouncer.org/) in
+front of the PostgreSQL instance. However, PgBouncer isn't required because
Praefect makes a low number of connections. If you choose to use PgBouncer, you can use the same PgBouncer instance for
both the GitLab application database and the Praefect database.
@@ -322,15 +335,21 @@ To configure PgBouncer in front of the PostgreSQL instance, you must point Praef
parameters on Praefect configuration:
```ruby
-praefect['database_host'] = PGBOUNCER_HOST
-praefect['database_port'] = 6432
-praefect['database_user'] = 'praefect'
-praefect['database_password'] = PRAEFECT_SQL_PASSWORD
-praefect['database_dbname'] = 'praefect_production'
-#praefect['database_sslmode'] = '...'
-#praefect['database_sslcert'] = '...'
-#praefect['database_sslkey'] = '...'
-#praefect['database_sslrootcert'] = '...'
+praefect['configuration'] = {
+ # ...
+ database: {
+ # ...
+ host: PGBOUNCER_HOST,
+ port: 6432,
+ user: 'praefect',
+ password: PRAEFECT_SQL_PASSWORD,
+ dbname: 'praefect_production',
+ # sslmode: '...',
+ # sslcert: '...',
+ # sslkey: '...',
+ # sslrootcert: '...',
+ }
+}
```
Praefect requires an additional connection to the PostgreSQL that supports the
@@ -341,12 +360,12 @@ It is not supported in `transaction` pool mode (`pool_mode = transaction`).
To configure the additional connection, you must either:
- Configure a new PgBouncer database that uses to the same PostgreSQL database endpoint,
- but with different pool mode. That is, `pool_mode = session`.
+ but with different pool mode (`pool_mode = session`).
- Connect Praefect directly to PostgreSQL and bypass PgBouncer.
#### Configure a new PgBouncer database with `pool_mode = session`
-We recommend using PgBouncer with `session` pool mode. You can use the
+You should use PgBouncer with `session` pool mode. You can use the
[bundled PgBouncer](../postgresql/pgbouncer.md) or use an external PgBouncer and
[configure it manually](https://www.pgbouncer.org/config.html).
@@ -399,23 +418,30 @@ praefect_production_direct = host=POSTGRESQL_HOST auth_user=pgbouncer dbname=pra
Now you can configure Praefect to use PgBouncer for both connections:
```ruby
-praefect['database_host'] = PGBOUNCER_HOST
-praefect['database_port'] = 6432
-praefect['database_user'] = 'praefect'
-# `PRAEFECT_SQL_PASSWORD` is the plain-text password of
-# Praefect user. Not to be confused with `PRAEFECT_SQL_PASSWORD_HASH`.
-praefect['database_password'] = PRAEFECT_SQL_PASSWORD
-
-praefect['database_dbname'] = 'praefect_production'
-praefect['database_direct_dbname'] = 'praefect_production_direct'
-
-# There is no need to repeat the following. Parameters of direct
-# database connection will fall back to the values above.
-
-#praefect['database_direct_host'] = PGBOUNCER_HOST
-#praefect['database_direct_port'] = 6432
-#praefect['database_direct_user'] = 'praefect'
-#praefect['database_direct_password'] = PRAEFECT_SQL_PASSWORD
+praefect['configuration'] = {
+ # ...
+ database: {
+ # ...
+ host: PGBOUNCER_HOST,
+ port: 6432,
+ user: 'praefect',
+ # `PRAEFECT_SQL_PASSWORD` is the plain-text password of
+ # Praefect user. Not to be confused with `PRAEFECT_SQL_PASSWORD_HASH`.
+ password: PRAEFECT_SQL_PASSWORD,
+ dbname: 'praefect_production',
+ session_pooled: {
+ # ...
+ dbname: 'praefect_production_direct',
+ # There is no need to repeat the following. Parameters of direct
+ # database connection will fall back to the values above.
+ #
+ # host: PGBOUNCER_HOST,
+ # port: 6432,
+ # user: 'praefect',
+ # password: PRAEFECT_SQL_PASSWORD,
+ },
+ },
+}
```
With this configuration, Praefect uses PgBouncer for both connection types.
@@ -428,25 +454,34 @@ configuration option is set. For more details, consult the PgBouncer documentati
#### Configure Praefect to connect directly to PostgreSQL
-As an alternative to configuring PgBouncer with `session` pool mode, Praefect can be configured to use different connection parameters for direct access
-to PostgreSQL. This is the connection that supports the `LISTEN` feature.
+As an alternative to configuring PgBouncer with `session` pool mode, Praefect can be configured to use different
+connection parameters for direct access to PostgreSQL. This connection supports the `LISTEN` feature.
An example of Praefect configuration that bypasses PgBouncer and directly connects to PostgreSQL:
```ruby
-praefect['database_direct_host'] = POSTGRESQL_HOST
-praefect['database_direct_port'] = 5432
-
-# Use the following to override parameters of direct database connection.
-# Comment out where the parameters are the same for both connections.
-
-praefect['database_direct_user'] = 'praefect'
-praefect['database_direct_password'] = PRAEFECT_SQL_PASSWORD
-praefect['database_direct_dbname'] = 'praefect_production'
-#praefect['database_direct_sslmode'] = '...'
-#praefect['database_direct_sslcert'] = '...'
-#praefect['database_direct_sslkey'] = '...'
-#praefect['database_direct_sslrootcert'] = '...'
+praefect['configuration'] = {
+ # ...
+ database: {
+ # ...
+ session_pooled: {
+ # ...
+ host: POSTGRESQL_HOST,
+ port: 5432,
+
+ # Use the following to override parameters of direct database connection.
+ # Comment out where the parameters are the same for both connections.
+ #
+ user: 'praefect',
+ password: PRAEFECT_SQL_PASSWORD,
+ dbname: 'praefect_production',
+ # sslmode: '...',
+ # sslcert: '...',
+ # sslkey: '...',
+ # sslrootcert: '...',
+ },
+ },
+}
```
### Praefect
@@ -501,30 +536,42 @@ Updates to example must be made at:
`/etc/gitlab/gitlab.rb`:
```ruby
- praefect['listen_addr'] = '0.0.0.0:2305'
+ praefect['configuration'] = {
+ # ...
+ listen_addr: '0.0.0.0:2305',
+ }
```
1. Configure Prometheus metrics by editing
`/etc/gitlab/gitlab.rb`:
```ruby
- # Enable Prometheus metrics access to Praefect. You must use firewalls
- # to restrict access to this address/port.
- # The default metrics endpoint is /metrics
- praefect['prometheus_listen_addr'] = '0.0.0.0:9652'
-
- # Some metrics run queries against the database. Enabling separate database metrics allows
- # these metrics to be collected when the metrics are
- # scraped on a separate /db_metrics endpoint.
- praefect['separate_database_metrics'] = true
+ praefect['configuration'] = {
+ # ...
+ #
+ # Enable Prometheus metrics access to Praefect. You must use firewalls
+ # to restrict access to this address/port.
+ # The default metrics endpoint is /metrics
+ prometheus_listen_addr: '0.0.0.0:9652',
+ # Some metrics run queries against the database. Enabling separate database metrics allows
+ # these metrics to be collected when the metrics are
+ # scraped on a separate /db_metrics endpoint.
+ prometheus_exclude_database_from_default_metrics: true,
+ }
```
-1. Configure a strong `auth_token` for **Praefect** by editing
- `/etc/gitlab/gitlab.rb`. This is needed by clients outside the cluster
+1. Configure a strong authentication token for **Praefect** by editing
+ `/etc/gitlab/gitlab.rb`, which is needed by clients outside the cluster
(like GitLab Shell) to communicate with the Praefect cluster:
```ruby
- praefect['auth_token'] = 'PRAEFECT_EXTERNAL_TOKEN'
+ praefect['configuration'] = {
+ # ...
+ auth: {
+ # ...
+ token: 'PRAEFECT_EXTERNAL_TOKEN',
+ },
+ }
```
1. Configure **Praefect** to [connect to the PostgreSQL database](#postgresql). We
@@ -533,19 +580,32 @@ Updates to example must be made at:
If you want to use a TLS client certificate, the options below can be used:
```ruby
- # Connect to PostgreSQL using a TLS client certificate
- # praefect['database_sslcert'] = '/path/to/client-cert'
- # praefect['database_sslkey'] = '/path/to/client-key'
-
- # Trust a custom certificate authority
- # praefect['database_sslrootcert'] = '/path/to/rootcert'
+ praefect['configuration'] = {
+ # ...
+ database: {
+ # ...
+ #
+ # Connect to PostgreSQL using a TLS client certificate
+ # sslcert: '/path/to/client-cert',
+ # sslkey: '/path/to/client-key',
+ #
+ # Trust a custom certificate authority
+ # sslrootcert: '/path/to/rootcert',
+ },
+ }
```
By default, Praefect refuses to make an unencrypted connection to
PostgreSQL. You can override this by uncommenting the following line:
```ruby
- # praefect['database_sslmode'] = 'disable'
+ praefect['configuration'] = {
+ # ...
+ database: {
+ # ...
+ # sslmode: 'disable',
+ },
+ }
```
1. Configure the **Praefect** cluster to connect to each Gitaly node in the
@@ -573,29 +633,37 @@ Updates to example must be made at:
NOTE:
When adding additional Gitaly nodes to a virtual storage, all storage names
- within that virtual storage must be unique. Additionally, all Gitaly node
+ in that virtual storage must be unique. Additionally, all Gitaly node
addresses referenced in the Praefect configuration must be unique.
```ruby
# Name of storage hash must match storage name in git_data_dirs on GitLab
- # server ('default') and in git_data_dirs on Gitaly nodes ('gitaly-1')
- praefect['virtual_storages'] = {
- 'default' => {
- 'nodes' => {
- 'gitaly-1' => {
- 'address' => 'tcp://GITALY_HOST_1:8075',
- 'token' => 'PRAEFECT_INTERNAL_TOKEN',
- },
- 'gitaly-2' => {
- 'address' => 'tcp://GITALY_HOST_2:8075',
- 'token' => 'PRAEFECT_INTERNAL_TOKEN'
+ # server ('default') and in gitaly['configuration'][:storage][INDEX][:name] on Gitaly nodes ('gitaly-1')
+ praefect['configuration'] = {
+ # ...
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ node: [
+ {
+ storage: 'gitaly-1',
+ address: 'tcp://GITALY_HOST_1:8075',
+ token: 'PRAEFECT_INTERNAL_TOKEN'
+ },
+ {
+ storage: 'gitaly-2',
+ address: 'tcp://GITALY_HOST_2:8075',
+ token: 'PRAEFECT_INTERNAL_TOKEN'
+ },
+ {
+ storage: 'gitaly-3',
+ address: 'tcp://GITALY_HOST_3:8075',
+ token: 'PRAEFECT_INTERNAL_TOKEN'
+ },
+ ],
},
- 'gitaly-3' => {
- 'address' => 'tcp://GITALY_HOST_3:8075',
- 'token' => 'PRAEFECT_INTERNAL_TOKEN'
- }
- }
- }
+ ],
}
```
@@ -681,7 +749,14 @@ Note the following:
This allows you to do a gradual transition from unencrypted to encrypted traffic, if
necessary.
- To disable the unencrypted listener, set `praefect['listen_addr'] = nil`.
+ To disable the unencrypted listener, set:
+
+ ```ruby
+ praefect['configuration'] = {
+ # ...
+ listen_addr: nil,
+ }
+ ```
To configure Praefect with TLS:
@@ -702,9 +777,15 @@ To configure Praefect with TLS:
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
- praefect['tls_listen_addr'] = "0.0.0.0:3305"
- praefect['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
- praefect['key_path'] = "/etc/gitlab/ssl/key.pem"
+ praefect['configuration'] = {
+ # ...
+ tls_listen_addr: '0.0.0.0:3305',
+ tls: {
+ # ...
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ }
```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -790,6 +871,125 @@ To configure Praefect with TLS:
1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source).
+#### Service discovery
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8971) in GitLab 15.10.
+
+Prerequisites:
+
+- A DNS server.
+
+GitLab uses service discovery to retrieve a list of Praefect hosts. Service
+discovery involves periodic checks of a DNS A or AAAA record, with the IPs
+retrieved from the record serving as the addresses of the target nodes.
+Praefect does not support service discovery by SRV record.
+
+By default, the minimum time between checks is 5 minutes, regardless of the
+records' TTLs. Praefect does not support customizing this interval. When clients
+receive an update, they:
+
+- Establish new connections to the new IP addresses.
+- Keep existing connections to intact IP addresses.
+- Drop connections to removed IP addresses.
+
+In-flight requests on to-be-removed connections are still handled until they
+finish. Workhorse has a 10-minute timeout, while other clients do not specify a
+graceful timeout.
+
+The DNS server should return all IP addresses instead of load-balancing itself.
+Clients can distribute requests to IP addresses in a round-robin fashion.
+
+Before updating client configuration, ensure that DNS service discovery works
+correctly. It should return the list of IP addresses correctly. `dig` is a good
+tool to use to verify.
+
+```console
+⯠dig A praefect.service.consul @127.0.0.1
+
+; <<>> DiG 9.10.6 <<>> A praefect.service.consul @127.0.0.1
+;; global options: +cmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29210
+;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
+
+;; OPT PSEUDOSECTION:
+; EDNS: version: 0, flags:; udp: 4096
+;; QUESTION SECTION:
+;praefect.service.consul. IN A
+
+;; ANSWER SECTION:
+praefect.service.consul. 0 IN A 10.0.0.3
+praefect.service.consul. 0 IN A 10.0.0.2
+praefect.service.consul. 0 IN A 10.0.0.1
+
+;; Query time: 0 msec
+;; SERVER: ::1#53(::1)
+;; WHEN: Wed Dec 14 12:53:58 +07 2022
+;; MSG SIZE rcvd: 86
+```
+
+##### Configure service discovery
+
+By default, Praefect delegates DNS resolution to the operating system. In such
+cases, the Gitaly address can be set in either of these formats:
+
+- `dns:[host]:[port]`
+- `dns:///[host]:[port]` (note the three slashes)
+
+You can also appoint an authoritative name server by setting it in this format:
+
+- `dns://[authority_host]:[authority_port]/[host]:[port]`
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+1. Edit `/etc/gitlab/gitlab.rb` and add:
+
+ ```ruby
+ praefect['consul_service_name'] = 'praefect'
+ ```
+
+1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+1. On the Praefect clients (except Gitaly servers), edit `git_data_dirs` in
+`/etc/gitlab/gitlab.rb` as follows. Replace `PRAEFECT_SERVICE_DISCOVERY_ADDRESS`
+with Praefect service discovery address, such as `praefect.service.consul`.
+
+ ```ruby
+ git_data_dirs({
+ "default" => {
+ "gitaly_address" => 'dns:PRAEFECT_SERVICE_DISCOVERY_ADDRESS:2305',
+ "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
+ }
+ })
+ ```
+
+1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+
+:::TabTitle Self-compiled (source)
+
+1. Install a DNS service discovery service. Register all Praefect nodes with the service.
+1. On the Praefect clients (except Gitaly servers), edit `storages` in
+ `/home/git/gitlab/config/gitlab.yml` as follows:
+
+ ```yaml
+ gitlab:
+ repositories:
+ storages:
+ default:
+ gitaly_address: dns:PRAEFECT_SERVICE_DISCOVERY_ADDRESS:2305
+ path: /some/local/path
+ ```
+
+ NOTE:
+ `/some/local/path` should be set to a local folder that exists, however no
+ data is stored in this folder. [Issue 375254](https://gitlab.com/gitlab-org/gitlab/-/issues/375254)
+ proposes to remove this requirement.
+
+1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source).
+
+::EndTabs
+
### Gitaly
NOTE:
@@ -813,12 +1013,11 @@ because we rely on Praefect to route operations correctly.
Particular attention should be shown to:
-- The `gitaly['auth_token']` configured in this section must match the `token`
- value under `praefect['virtual_storages']['nodes']` on the Praefect node. This was set
- in the [previous section](#praefect). This document uses the placeholder
- `PRAEFECT_INTERNAL_TOKEN` throughout.
-- The storage names in `git_data_dirs` configured in this section must match the
- storage names under `praefect['virtual_storages']` on the Praefect node. This
+- The `gitaly['configuration'][:auth][:token]` configured in this section must match the `token`
+ value under `praefect['configuration'][:virtual_storage][<index>][:node][<index>][:token]` on the Praefect node. This value was
+ set in the [previous section](#praefect). This document uses the placeholder `PRAEFECT_INTERNAL_TOKEN` throughout.
+- The storage names in `gitaly['configuration'][:storage]` configured in this section must match the
+ storage names under `praefect['configuration'][:virtual_storage]` on the Praefect node. This
was set in the [previous section](#praefect). This document uses `gitaly-1`,
`gitaly-2`, and `gitaly-3` as Gitaly storage names.
@@ -859,22 +1058,31 @@ For more information on Gitaly server configuration, see our
`/etc/gitlab/gitlab.rb`:
```ruby
- # Make Gitaly accept connections on all network interfaces.
- # Use firewalls to restrict access to this address/port.
- gitaly['listen_addr'] = '0.0.0.0:8075'
-
- # Enable Prometheus metrics access to Gitaly. You must use firewalls
- # to restrict access to this address/port.
- gitaly['prometheus_listen_addr'] = '0.0.0.0:9236'
+ gitaly['configuration'] = {
+ # ...
+ #
+ # Make Gitaly accept connections on all network interfaces.
+ # Use firewalls to restrict access to this address/port.
+ listen_addr: '0.0.0.0:8075',
+ # Enable Prometheus metrics access to Gitaly. You must use firewalls
+ # to restrict access to this address/port.
+ prometheus_listen_addr: '0.0.0.0:9236',
+ }
```
1. Configure a strong `auth_token` for **Gitaly** by editing
- `/etc/gitlab/gitlab.rb`. This is needed by clients to communicate with
+ `/etc/gitlab/gitlab.rb`, which is needed by clients to communicate with
this Gitaly nodes. Typically, this token is the same for all Gitaly
nodes.
```ruby
- gitaly['auth_token'] = 'PRAEFECT_INTERNAL_TOKEN'
+ gitaly['configuration'] = {
+ # ...
+ auth: {
+ # ...
+ token: 'PRAEFECT_INTERNAL_TOKEN',
+ },
+ }
```
1. Configure the GitLab Shell secret token, which is needed for `git push` operations. Either:
@@ -903,13 +1111,13 @@ For more information on Gitaly server configuration, see our
gitlab_rails['internal_api_url'] = 'http://GITLAB_HOST'
```
-1. Configure the storage location for Git data by setting `git_data_dirs` in
+1. Configure the storage location for Git data by setting `gitaly['configuration'][:storage]` in
`/etc/gitlab/gitlab.rb`. Each Gitaly node should have a unique storage name
(such as `gitaly-1`).
- Instead of configuring `git_data_dirs` uniquely for each Gitaly node, it is
+ Instead of configuring `gitaly['configuration'][:storage]` uniquely for each Gitaly node, it is
often easier to have include the configuration for all Gitaly nodes on every
- Gitaly node. This is supported because the Praefect `virtual_storages`
+ Gitaly node. You can do this because the Praefect `virtual_storage`
configuration maps each storage name (such as `gitaly-1`) to a specific node, and
requests are routed accordingly. This means every Gitaly node in your fleet
can share the same configuration.
@@ -918,17 +1126,23 @@ For more information on Gitaly server configuration, see our
# You can include the data dirs for all nodes in the same config, because
# Praefect will only route requests according to the addresses provided in the
# prior step.
- git_data_dirs({
- "gitaly-1" => {
- "path" => "/var/opt/gitlab/git-data"
- },
- "gitaly-2" => {
- "path" => "/var/opt/gitlab/git-data"
- },
- "gitaly-3" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-1',
+ path: '/var/opt/gitlab/git-data',
+ },
+ {
+ name: 'gitaly-2',
+ path: '/var/opt/gitlab/git-data',
+ },
+ {
+ name: 'gitaly-3',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
1. Save the changes to `/etc/gitlab/gitlab.rb` and
@@ -980,8 +1194,8 @@ Big-IP LTM, and Citrix Net Scaler. This documentation outlines what ports
and protocols you need configure.
NOTE:
-We recommend the equivalent of HAProxy `leastconn` load-balancing strategy because long-running operations (for example,
-clones) keep some connections open for extended periods.
+You should use the equivalent of HAProxy `leastconn` load-balancing strategy because long-running operations (for
+example, clones) keep some connections open for extended periods.
| LB Port | Backend Port | Protocol |
|:--------|:-------------|:---------|
@@ -995,12 +1209,12 @@ To complete this section you need:
- [Configured Gitaly nodes](#gitaly)
The Praefect cluster needs to be exposed as a storage location to the GitLab
-application. This is done by updating the `git_data_dirs`.
+application, which is done by updating the `git_data_dirs`.
Particular attention should be shown to:
- the storage name added to `git_data_dirs` in this section must match the
- storage name under `praefect['virtual_storages']` on the Praefect nodes. This
+ storage name under `praefect['configuration'][:virtual_storage]` on the Praefect nodes. This
was set in the [Praefect](#praefect) section of this guide. This document uses
`default` as the Praefect storage name.
@@ -1219,12 +1433,16 @@ You can configure:
The configuration is added to the `/etc/gitlab/gitlab.rb` file:
```ruby
- praefect['virtual_storages'] = {
- 'default' => {
- 'default_replication_factor' => 1,
+ praefect['configuration'] = {
# ...
- }
- }
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ default_replication_factor: 1,
+ },
+ ],
+ }
```
- A replication factor for an existing repository using the `set-replication-factor` sub-command.
@@ -1313,29 +1531,50 @@ interval is configurable with any valid [Go duration string](https://pkg.go.dev/
To verify the metadata every three days:
```ruby
-praefect['background_verification_verification_interval'] = '72h'
+praefect['configuration'] = {
+ # ...
+ background_verification: {
+ # ...
+ verification_interval: '72h',
+ },
+}
```
Values of 0 and below disable the background verifier.
```ruby
-praefect['background_verification_verification_interval'] = '0'
+praefect['configuration'] = {
+ # ...
+ background_verification: {
+ # ...
+ verification_interval: '0',
+ },
+}
```
#### Enable deletions
+> - [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4080) and disabled by default in GitLab 15.0
+> - [Default enabled](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5321) in GitLab 15.9.
+
WARNING:
-Deletions are disabled by default due to a race condition with repository renames that can cause incorrect
-deletions. This is especially prominent in Geo instances as Geo performs more renames than instances without Geo.
-You should enable deletions only if the [`gitaly_praefect_generated_replica_paths` feature flag](index.md#praefect-generated-replica-paths-gitlab-150-and-later) is enabled.
+Deletions were disabled by default prior to GitLab 15.9 due to a race condition with repository renames
+that can cause incorrect deletions, which is especially prominent in Geo instances as Geo performs more renames
+than instances without Geo. In GitLab 15.0 to 15.5, you should enable deletions only if the [`gitaly_praefect_generated_replica_paths` feature flag](index.md#praefect-generated-replica-paths-gitlab-150-and-later) is enabled. The feature flag was removed in GitLab 15.6 making deletions always safe to enable.
-By default, the worker does not delete invalid metadata records but logs them and outputs Prometheus
-metrics for them.
+By default, the worker deletes invalid metadata records. It also logs the deleted records and outputs Prometheus
+metrics.
-You can enable deleting invalid metadata records with:
+You can disable deleting invalid metadata records with:
```ruby
-praefect['background_verification_delete_invalid_records'] = true
+praefect['configuration'] = {
+ # ...
+ background_verification: {
+ # ...
+ delete_invalid_records: false,
+ },
+}
```
### Prioritize verification manually
@@ -1370,10 +1609,10 @@ The output includes the number of replicas that were marked unverified.
## Automatic failover and primary election strategies
-Praefect regularly checks the health of each Gitaly node. This is used to automatically fail over
+Praefect regularly checks the health of each Gitaly node, which is used to automatically fail over
to a newly-elected primary Gitaly node if the current primary node is found to be unhealthy.
-We recommend using [repository-specific primary nodes](#repository-specific-primary-nodes). This is
+You should use [repository-specific primary nodes](#repository-specific-primary-nodes). This is
[the only available election strategy](https://gitlab.com/gitlab-org/gitaly/-/issues/3574) from GitLab 14.0.
### Repository-specific primary nodes
diff --git a/doc/administration/gitaly/recovery.md b/doc/administration/gitaly/recovery.md
index 1207d7af3e7..331f9b5a956 100644
--- a/doc/administration/gitaly/recovery.md
+++ b/doc/administration/gitaly/recovery.md
@@ -74,7 +74,7 @@ Cluster:
### Unavailable repositories
> - From GitLab 13.0 through 14.0, repositories became read-only if they were outdated on the primary but fully up to date on a healthy secondary. `dataloss` sub-command displays read-only repositories by default through these versions.
-> - Since GitLab 14.1, Praefect contains more responsive failover logic which immediately fails over to one of the fully up to date secondaries rather than placing the repository in read-only mode. Since GitLab 14.1, the `dataloss` sub-command displays repositories which are unavailable due to having no fully up to date copies on healthy Gitaly nodes.
+> - From GitLab 14.1, Praefect contains more responsive failover logic which immediately fails over to one of the fully up to date secondaries rather than placing the repository in read-only mode. From GitLab 14.1, the `dataloss` sub-command displays repositories which are unavailable due to having no fully up to date copies on healthy Gitaly nodes.
A repository is unavailable if all of its up to date replicas are unavailable. Unavailable repositories are
not accessible through Praefect to prevent serving stale data that may break automated tooling.
@@ -277,15 +277,33 @@ The reconciliation frequency can be changed via the configuration. The value can
Examples:
```ruby
-praefect['reconciliation_scheduling_interval'] = '5m' # the default value
+praefect['configuration'] = {
+ # ...
+ reconciliation: {
+ # ...
+ scheduling_interval: '5m', # the default value
+ },
+}
```
```ruby
-praefect['reconciliation_scheduling_interval'] = '30s' # reconcile every 30 seconds
+praefect['configuration'] = {
+ # ...
+ reconciliation: {
+ # ...
+ scheduling_interval: '30s', # reconcile every 30 seconds
+ },
+}
```
```ruby
-praefect['reconciliation_scheduling_interval'] = '0' # disable the feature
+praefect['configuration'] = {
+ # ...
+ reconciliation: {
+ # ...
+ scheduling_interval: '0', # disable the feature
+ },
+}
```
### Manual reconciliation
@@ -334,16 +352,21 @@ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.t
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml remove-repository -virtual-storage <virtual-storage> -repository <repository> -apply
```
-- `-virtual-storage` is the virtual storage the repository is located in. Virtual storages are configured in `/etc/gitlab/gitlab.rb` under `praefect['virtual_storages]` and looks like the following:
+- `-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:
```ruby
- praefect['virtual_storages'] = {
- 'default' => {
- ...
- },
- 'storage-1' => {
- ...
- }
+ praefect['configuration'] = {
+ # ...
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ },
+ {
+ # ...
+ name: 'storage-1',
+ },
+ ],
}
```
@@ -415,16 +438,21 @@ The `track-repository` Praefect sub-command adds repositories on disk to the Pra
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
```
-- `-virtual-storage` is the virtual storage the repository is located in. Virtual storages are configured in `/etc/gitlab/gitlab.rb` under `praefect['virtual_storages]` and looks like the following:
+- `-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:
```ruby
- praefect['virtual_storages'] = {
- 'default' => {
- ...
- },
- 'storage-1' => {
- ...
- }
+ praefect['configuration'] = {
+ # ...
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ },
+ {
+ # ...
+ name: 'storage-1',
+ },
+ ],
}
```
@@ -473,7 +501,7 @@ The command validates that all entries:
- Are formatted correctly and contain required fields.
- Correspond to a valid Git repository on disk.
-- Are not currently tracked in the Praefect tracking database.
+- Are not tracked in the Praefect tracking database.
If any entry fails these checks, the command aborts prior to attempting to track a repository.
diff --git a/doc/administration/gitaly/reference.md b/doc/administration/gitaly/reference.md
index 1516b82a906..8b4fc51bcdf 100644
--- a/doc/administration/gitaly/reference.md
+++ b/doc/administration/gitaly/reference.md
@@ -10,9 +10,8 @@ Gitaly is configured via a [TOML](https://github.com/toml-lang/toml)
configuration file. Unlike installations from source, in Omnibus GitLab, you
would not edit this file directly.
-The configuration file is passed as an argument to the `gitaly`
-executable. This is usually done by either Omnibus GitLab or your
-[init](https://en.wikipedia.org/wiki/Init) script.
+The configuration file is passed as an argument to the `gitaly` executable, which is usually done by either Omnibus
+GitLab or your [init](https://en.wikipedia.org/wiki/Init) script.
An [example configuration file](https://gitlab.com/gitlab-org/gitaly/blob/master/config.toml.example)
can be found in the Gitaly project.
@@ -42,7 +41,7 @@ prometheus_listen_addr = "localhost:9236"
### Authentication
Gitaly can be configured to reject requests that do not contain a
-specific bearer token in their headers. This is a security measure to
+specific bearer token in their headers, which is a security measure to
be used when serving requests over TCP:
```toml
@@ -70,7 +69,7 @@ Remember to disable `transitioning` when you are done
changing your token settings.
All authentication attempts are counted in Prometheus under
-the [`gitaly_authentications_total` metric](monitoring.md#useful-queries).
+the [`gitaly_authentications_total` metric](monitoring.md#queries).
### TLS
diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md
index 5f05b6322b0..a3db28b0d7b 100644
--- a/doc/administration/gitaly/troubleshooting.md
+++ b/doc/administration/gitaly/troubleshooting.md
@@ -66,7 +66,7 @@ for details.
### Client side gRPC logs
Gitaly uses the [gRPC](https://grpc.io/) RPC framework. The Ruby gRPC
-client has its own log file which may contain useful information when
+client has its own log file which may contain helpful information when
you are seeing Gitaly errors. You can control the log level of the
gRPC client with the `GRPC_LOG_LEVEL` environment variable. The
default level is `WARN`.
@@ -345,7 +345,7 @@ You might see the following in Gitaly and Praefect logs:
}
```
-This is a gRPC call
+This information in the logs is a gRPC call
[error response code](https://grpc.github.io/grpc/core/md_doc_statuscodes.html).
If this error occurs, even though
@@ -358,7 +358,7 @@ server to keep them synchronized.
### Gitaly not listening on new address after reconfiguring
-When updating the `gitaly['listen_addr']` or `gitaly['prometheus_listen_addr']` values, Gitaly may
+When updating the `gitaly['configuration'][:listen_addr]` or `gitaly['configuration'][:prometheus_listen_addr]` values, Gitaly may
continue to listen on the old address after a `sudo gitlab-ctl reconfigure`.
When this occurs, run `sudo gitlab-ctl restart` to resolve the issue. This should no longer be
@@ -514,9 +514,9 @@ Here are common errors and potential causes:
- 500 response code
- `ActionView::Template::Error (7:permission denied)`
- - `praefect['auth_token']` and `gitlab_rails['gitaly_token']` do not match on the GitLab server.
+ - `praefect['configuration'][:auth][:token]` and `gitlab_rails['gitaly_token']` do not match on the GitLab server.
- `Unable to save project. Error: 7:permission denied`
- - Secret token in `praefect['storage_nodes']` on GitLab server does not match the
+ - Secret token in `praefect['configuration'][:virtual_storage]` on GitLab server does not match the
value in `gitaly['auth_token']` on one or more Gitaly servers.
- 503 response code
- `GRPC::Unavailable (14:failed to connect to all addresses)`
@@ -530,7 +530,7 @@ Here are common errors and potential causes:
Some common reasons for the Praefect database to experience elevated CPU usage include:
- Prometheus metrics scrapes [running an expensive query](https://gitlab.com/gitlab-org/gitaly/-/issues/3796). If you have GitLab 14.2
- or above, set `praefect['separate_database_metrics'] = true` in `gitlab.rb`.
+ or above, set `praefect['configuration'][:prometheus_exclude_database_from_default_metrics] = true` in `gitlab.rb`.
- [Read distribution caching](praefect.md#reads-distribution-caching) is disabled, increasing the number of queries made to the
database when user traffic is high. Ensure read distribution caching is enabled.
@@ -544,9 +544,8 @@ To determine the primary node of a repository:
- With legacy election strategies in GitLab 13.12 and earlier, the primary was the same for all repositories in a virtual storage.
To determine the current primary Gitaly node for a specific virtual storage:
- - Use the `Shard Primary Election` [Grafana chart](praefect.md#grafana) on the
+ - (Recommended) Use the `Shard Primary Election` [Grafana chart](praefect.md#grafana) on the
[`Gitlab Omnibus - Praefect` dashboard](https://gitlab.com/gitlab-org/grafana-dashboards/-/blob/master/omnibus/praefect.json).
- This is recommended.
- If you do not have Grafana set up, use the following command on each host of each
Praefect node:
@@ -650,7 +649,7 @@ If the supplied value for `-virtual-storage` is incorrect, the command returns t
get metadata: rpc error: code = NotFound desc = repository not found
```
-The documented examples specify `-virtual-storage default`. Check the Praefect server setting `praefect['virtual_storages']` in `/etc/gitlab/gitlab.rb`.
+The documented examples specify `-virtual-storage default`. Check the Praefect server setting `praefect['configuration'][:virtual_storage]` in `/etc/gitlab/gitlab.rb`.
### Check that repositories are in sync
@@ -669,7 +668,7 @@ However, the Praefect database tables are not created on initial reconfigure and
errors that relations do not exist if either:
- The `gitlab-ctl reconfigure` command isn't executed.
-- There are errors during the execution.
+- Errors occur during the execution.
For example:
@@ -693,7 +692,7 @@ praefect sql-migrate: OK (applied 21 migrations)
This indicates that the virtual storage name used in the
[Praefect configuration](praefect.md#praefect) does not match the storage name used in
-[`git_data_dirs` setting](praefect.md#gitaly) for GitLab.
+[`gitaly['configuration'][:storage][<index>][:name]` setting](praefect.md#gitaly) for GitLab.
Resolve this by matching the virtual storage names used in Praefect and GitLab configuration.
@@ -715,9 +714,13 @@ Possible solutions:
- Provision larger VMs to gain access to larger network traffic allowances.
- Use your cloud service's monitoring and logging to check that the Praefect nodes are not exhausting their traffic allowances.
+### `gitlab-ctl reconfigure` fails with error: `STDOUT: praefect: configuration error: error reading config file: toml: cannot store TOML string into a Go int`
+
+This error occurs when `praefect['database_port']` or `praefect['database_direct_port']` are configured as a string instead of an integer.
+
## Profiling Gitaly
-Gitaly exposes several of the Golang built-in performance profiling tools on the Prometheus listen port. For example, if Prometheus is listening
+Gitaly exposes several of the Go built-in performance profiling tools on the Prometheus listen port. For example, if Prometheus is listening
on port `9236` of the GitLab server:
- Get a list of running `goroutines` and their backtraces:
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 9f4477bcbf7..68e16b56624 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -66,7 +66,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Broadcast Messages](../user/admin_area/broadcast_messages.md): Send messages
to GitLab users through the UI.
- [Elasticsearch](../integration/advanced_search/elasticsearch.md): Enable Elasticsearch to
- empower Advanced Search. Use when you deal with a huge amount of data.
+ empower advanced search. Use when you deal with a huge amount of data.
- [External Classification Policy Authorization](../user/admin_area/settings/external_authorization.md)
- [Add a license](../user/admin_area/license.md): Add a license to unlock
features that are in paid tiers of GitLab.
diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md
index b1d97fd16a9..2b2eefdb17c 100644
--- a/doc/administration/instance_limits.md
+++ b/doc/administration/instance_limits.md
@@ -290,7 +290,7 @@ Plan.default.actual_limits.update!(group_hooks: 100)
Set the limit to `0` to disable it.
-The default maximum number of webhooks is `100` per project, `50` per group.
+The default maximum number of webhooks is `100` per project and `50` per group. Webhooks in a child group do not count towards the webhook limit of their parent group.
For GitLab.com, see the [webhook limits for GitLab.com](../user/gitlab_com/index.md#webhooks).
@@ -723,22 +723,23 @@ GitLab checks these limits against runners that have been active in the last 3 m
A runner's registration fails if it exceeds the limit for the scope determined by the runner registration token.
If the limit value is set to zero, the limit is disabled.
-- GitLab SaaS subscribers have different limits defined per plan, affecting all projects using that plan.
-- Self-managed GitLab Premium and Ultimate limits are defined by a default plan that affects all projects:
+GitLab SaaS subscribers have different limits defined per plan, affecting all projects using that plan.
- | Runner scope | Default value |
- |---------------------------------------------|---------------|
- | `ci_registered_group_runners` | 1000 |
- | `ci_registered_project_runners` | 1000 |
+Self-managed GitLab Premium and Ultimate limits are defined by a default plan that affects all projects:
- To update these limits, run the following in the
- [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
+| Runner scope | Default value |
+|---------------------------------------------|---------------|
+| `ci_registered_group_runners` | 1000 |
+| `ci_registered_project_runners` | 1000 |
+
+To update these limits, run the following in the
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
- ```ruby
- # Use ci_registered_group_runners or ci_registered_project_runners
- # depending on desired scope
- Plan.default.actual_limits.update!(ci_registered_project_runners: 100)
- ```
+```ruby
+# Use ci_registered_group_runners or ci_registered_project_runners
+# depending on desired scope
+Plan.default.actual_limits.update!(ci_registered_project_runners: 100)
+```
### Maximum file size for job logs
@@ -922,7 +923,7 @@ Reports that go over the 20 MB limit aren't loaded. Affected reports:
- [CI/CD parameter `artifacts:expose_as`](../ci/yaml/index.md#artifactsexpose_as)
- [Unit test reports](../ci/testing/unit_test_reports.md)
-## Advanced Search limits
+## Advanced search limits
### Maximum file size indexed
@@ -945,7 +946,7 @@ is pre-allocated during indexing.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201826) in GitLab 12.8.
-You can set a limit on the content of text fields indexed for Advanced Search.
+You can set a limit on the content of text fields indexed for advanced search.
Setting a maximum helps to reduce the load of the indexing processes. If any
text field exceeds this limit, then the text is truncated to this number of
characters. The rest of the text is not indexed, and not searchable.
diff --git a/doc/administration/integration/kroki.md b/doc/administration/integration/kroki.md
index 081c4d8a08c..f90458200b3 100644
--- a/doc/administration/integration/kroki.md
+++ b/doc/administration/integration/kroki.md
@@ -9,12 +9,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241744) in GitLab 13.7.
> - Support for reStructuredText and Textile documents [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/324766) in GitLab 13.12.
-When [Kroki](https://kroki.io) integration is enabled and configured in
-GitLab, you can use it to create diagrams in AsciiDoc, Markdown, reStructuredText, and Textile documents.
+With the [Kroki](https://kroki.io) integration,
+you can create diagrams in AsciiDoc, Markdown, reStructuredText, and Textile.
-## Kroki Server
+## Kroki server
-When Kroki is enabled, GitLab sends diagrams to an instance of Kroki to display them as images.
+When you enable Kroki, GitLab sends diagrams to an instance of Kroki to display them as images.
You can use the free public cloud instance `https://kroki.io` or you can [install Kroki](https://docs.kroki.io/kroki/setup/install/)
on your own infrastructure.
After you've installed Kroki, make sure to update the server URL to point to your instance.
@@ -29,11 +29,16 @@ docker run -d --name kroki -p 8080:8000 yuzutech/kroki
The **Kroki URL** is the hostname of the server running the container.
-The [`yuzutech/kroki`](https://hub.docker.com/r/yuzutech/kroki) image contains the following diagrams libraries out-of-the-box:
+The [`yuzutech/kroki`](https://hub.docker.com/r/yuzutech/kroki) Docker image contains several diagram
+libraries out of the box. For a complete list, see the
+[`asciidoctor-kroki` README](https://github.com/ggrossetie/asciidoctor-kroki/blob/master/README.md#supported-diagram-types).
+Supported libraries include:
<!-- vale gitlab.Spelling = NO -->
- [Bytefield](https://bytefield-svg.deepsymmetry.org/)
+- [D2](https://d2lang.com/tour/intro/)
+- [DBML](https://www.dbml.org/home/)
- [Ditaa](https://ditaa.sourceforge.net)
- [Erd](https://github.com/BurntSushi/erd)
- [GraphViz](https://www.graphviz.org/)
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 33434e15c4e..042bca1f6c9 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -7,9 +7,8 @@ type: reference, howto
# PlantUML **(FREE)**
-When the [PlantUML](https://plantuml.com) integration is enabled and configured in
-GitLab, you can create diagrams in snippets, wikis, and repositories. This integration
-is enabled on GitLab.com for all SaaS users and does not require any additional configuration.
+With the [PlantUML](https://plantuml.com) integration, you can create diagrams in snippets, wikis, and repositories.
+This integration is enabled on GitLab.com for all SaaS users and does not require any additional configuration.
To set up the integration on a self-managed instance, you must:
@@ -117,7 +116,7 @@ services:
image: 'gitlab/gitlab-ee:12.2.5-ee.0'
environment:
GITLAB_OMNIBUS_CONFIG: |
- nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n proxy_cache off; \n proxy_pass http://plantuml:8080/; \n}\n"
+ nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n rewrite ^/-/plantuml/(.*) /$1 break;\n proxy_cache off; \n proxy_pass http://plantuml:8080/; \n}\n"
plantuml:
image: 'plantuml/plantuml-server:tomcat'
@@ -148,7 +147,7 @@ using Tomcat:
```
The Tomcat service should restart. After the restart is complete, the
-PlantUML service is ready and listening for requests on port 8080:
+PlantUML integration is ready and listening for requests on port 8080:
`http://localhost:8080/plantuml`
To change these defaults, edit the `/etc/tomcat8/server.xml` file.
@@ -180,10 +179,10 @@ To enable this redirection:
```ruby
# Docker deployment
- nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n proxy_cache off; \n proxy_pass http://plantuml:8080/; \n}\n"
+ nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n rewrite ^/-/plantuml/(.*) /$1 break;\n proxy_cache off; \n proxy_pass http://plantuml:8080/; \n}\n"
# Built from source
- nginx['custom_gitlab_server_config'] = "location /-/plantuml { \n rewrite ^/-/(plantuml.*) /$1 break;\n proxy_cache off; \n proxy_pass http://localhost:8080/plantuml; \n}\n"
+ nginx['custom_gitlab_server_config'] = "location /-/plantuml { \n rewrite ^/-/plantuml/(.*) /$1 break;\n proxy_cache off; \n proxy_pass http://localhost:8080/plantuml; \n}\n"
```
1. To activate the changes, run the following command:
diff --git a/doc/administration/integration/terminal.md b/doc/administration/integration/terminal.md
index a1522ccac31..0ffb83886ed 100644
--- a/doc/administration/integration/terminal.md
+++ b/doc/administration/integration/terminal.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Web terminals (DEPRECATED) **(FREE)**
+# Web terminals (deprecated) **(FREE)**
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
> - [Disabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/353410) in GitLab 15.0.
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index 4f2eb20877e..0a4213b7e2d 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
@@ -276,7 +276,7 @@ to clean up orphaned artifacts.
### Migrating from object storage to local storage
To migrate back to local storage, you must
-[selectively disable the artifacts storage](object_storage.md#selectively-disabling-object-storage).
+[selectively disable the artifacts storage](object_storage.md#disable-object-storage-for-specific-features).
## Expiring artifacts
diff --git a/doc/administration/lfs/index.md b/doc/administration/lfs/index.md
index 3638729a6b6..adfba28520e 100644
--- a/doc/administration/lfs/index.md
+++ b/doc/administration/lfs/index.md
@@ -272,7 +272,7 @@ To migrate back to local storage:
```
1. Edit `/etc/gitlab/gitlab.rb` and
- [disable object storage](../object_storage.md#selectively-disabling-object-storage)
+ [disable object storage](../object_storage.md#disable-object-storage-for-specific-features)
for LFS objects:
```ruby
@@ -421,6 +421,18 @@ To check an installed Git LFS client's version, run this command:
git lfs version
```
+### `Connection refused` errors
+
+If you push or mirror LFS objects and receive errors like the following:
+
+- `dial tcp <IP>:443: connect: connection refused`
+- `Connection refused - connect(2) for \"<target-or-proxy-IP>\" port 443`
+
+a firewall or proxy rule may be terminating the connection.
+
+If connection checks with standard Unix tools or manual Git pushes are successful,
+the rule may be related to the size of the request.
+
## Error viewing a PDF file
When LFS has been configured with object storage and `proxy_download` set to
diff --git a/doc/administration/load_balancer.md b/doc/administration/load_balancer.md
index 298d22f1da5..a077558c7d2 100644
--- a/doc/administration/load_balancer.md
+++ b/doc/administration/load_balancer.md
@@ -37,7 +37,7 @@ for details on managing SSL certificates and configuring NGINX.
### Load Balancers terminate SSL without backend SSL
Configure your load balancers to use the `HTTP(S)` protocol rather than `TCP`.
-The load balancers is be responsible for managing SSL certificates and
+The load balancers are responsible for managing SSL certificates and
terminating SSL.
Because communication between the load balancers and GitLab isn't secure,
diff --git a/doc/administration/logs/index.md b/doc/administration/logs/index.md
index eab4c9b7d83..1104412020a 100644
--- a/doc/administration/logs/index.md
+++ b/doc/administration/logs/index.md
@@ -180,7 +180,7 @@ In addition, the log contains the originating IP address,
(`remote_ip`), the user's ID (`user_id`), and username (`username`).
Some endpoints (such as `/search`) may make requests to Elasticsearch if using
-[Advanced Search](../../user/search/advanced_search.md). These
+[advanced search](../../user/search/advanced_search.md). These
additionally log `elasticsearch_calls` and `elasticsearch_call_duration_s`,
which correspond to:
@@ -426,7 +426,7 @@ like this example:
}
```
-## `kubernetes.log` (DEPRECATED)
+## `kubernetes.log` (deprecated)
> [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
@@ -771,6 +771,24 @@ are recorded in this file. For example:
{"severity":"INFO","time":"2020-11-24T02:31:29.329Z","correlation_id":null,"key":"cd_auto_rollback","action":"remove"}
```
+## `ci_resource_groups_json.log`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384180) in GitLab 15.9.
+
+Depending on your installation method, this file is located at:
+
+- Omnibus GitLab: `/var/log/gitlab/gitlab-rails/ci_resource_group_json.log`
+- Installations from source: `/home/git/gitlab/log/ci_resource_group_json.log`
+
+It contains information about [resource group](../../ci/resource_groups/index.md) acquisition. For example:
+
+```json
+{"severity":"INFO","time":"2023-02-10T23:02:06.095Z","correlation_id":"01GRYS10C2DZQ9J1G12ZVAD4YD","resource_group_id":1,"processable_id":288,"message":"attempted to assign resource to processable","success":true}
+{"severity":"INFO","time":"2023-02-10T23:02:08.945Z","correlation_id":"01GRYS138MYEG32C0QEWMC4BDM","resource_group_id":1,"processable_id":288,"message":"attempted to release resource from processable","success":true}
+```
+
+The examples show the `resource_group_id`, `processable_id`, `message`, and `success` fields for each entry.
+
## `auth.log`
> Introduced in GitLab 12.0.
diff --git a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
index 566bc070347..53b578eb2f3 100644
--- a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
+++ b/doc/administration/monitoring/gitlab_self_monitoring_project/index.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
---
-# Self-monitoring project (DEPRECATED) **(FREE SELF)**
+# Self-monitoring project (deprecated) **(FREE SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32351) in GitLab 12.7 [with a flag](../../feature_flags.md) named `self_monitoring_project`. Disabled by default.
> - Generally available in GitLab 12.8. [Feature flag `self_monitoring_project`](https://gitlab.com/gitlab-org/gitlab/-/issues/198511) removed.
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index ed55e7d7ff3..c21c92a3d63 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -37,8 +37,8 @@ The following metrics are available:
| `gitlab_banzai_cached_render_real_duration_seconds` | Histogram | 9.4 | Duration of rendering Markdown into HTML when cached output exists | `controller`, `action` |
| `gitlab_banzai_cacheless_render_real_duration_seconds` | Histogram | 9.4 | Duration of rendering Markdown into HTML when cached output does not exist | `controller`, `action` |
| `gitlab_cache_misses_total` | Counter | 10.2 | Cache read miss | `controller`, `action` |
-| `gitlab_cache_operation_duration_seconds` | Histogram | 10.2 | Cache access time | |
-| `gitlab_cache_operations_total` | Counter | 12.2 | Cache operations by controller or action | `controller`, `action`, `operation` |
+| `gitlab_cache_operation_duration_seconds` | Histogram | 10.2 | Cache access time | `operation`, `store` |
+| `gitlab_cache_operations_total` | Counter | 12.2 | Cache operations by controller or action | `controller`, `action`, `operation`, `store` |
| `gitlab_cache_read_multikey_count` | Histogram | 15.7 | Count of keys in multi-key cache read operations | `controller`, `action` |
| `gitlab_ci_pipeline_builder_scoped_variables_duration` | Histogram | 14.5 | Time in seconds it takes to create the scoped variables for a CI/CD job
| `gitlab_ci_pipeline_creation_duration_seconds` | Histogram | 13.0 | Time in seconds it takes to create a CI/CD pipeline | `gitlab` |
@@ -163,6 +163,9 @@ The following metrics are available:
| `gitlab_diffs_render_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on serializing and rendering diffs on diffs batch request | `controller`, `action` |
| `gitlab_memwd_violations_total` | Counter | 15.9 | Total number of times a Ruby process violated a memory threshold | |
| `gitlab_memwd_violations_handled_total` | Counter | 15.9 | Total number of times Ruby process memory violations were handled | |
+| `gitlab_sli_rails_request_apdex_total` | Counter | 14.4 | Total number of request Apdex measurements. For more information, see [Rails request SLIs](../../../development/application_slis/rails_request.md) | `endpoint_id`, `feature_category`, `request_urgency` |
+| `gitlab_sli_rails_request_apdex_success_total` | Counter | 14.4 | Total number of successful requests that met the target duration for their urgency. Divide by `gitlab_sli_rails_requests_apdex_total` to get a success ratio | `endpoint_id`, `feature_category`, `request_urgency` |
+| `gitlab_sli_rails_request_error_total` | Counter | 15.7 | Total number of request error measurements. For more information, see [Rails request SLIs](../../../development/application_slis/rails_request.md) | `endpoint_id`, `feature_category`, `request_urgency`, `error` |
## Metrics controlled by a feature flag
@@ -206,16 +209,16 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_repositories` | Gauge | 10.2 | Total number of repositories available on primary | `url` |
| `geo_repositories_synced` | Gauge | 10.2 | Number of repositories synced on secondary | `url` |
| `geo_repositories_failed` | Gauge | 10.2 | Number of repositories failed to sync on secondary | `url` |
-| `geo_lfs_objects` | Gauge | 10.2 | Number of LFS objects on primary | `url` |
+| `geo_lfs_objects` | Gauge | 10.2 | Number of LFS objects on primary | `url` |
| `geo_lfs_objects_checksummed` | Gauge | 14.6 | Number of LFS objects checksummed successfully on primary | `url` |
| `geo_lfs_objects_checksum_failed` | Gauge | 14.6 | Number of LFS objects failed to calculate the checksum on primary | `url` |
-| `geo_lfs_objects_checksum_total` | Gauge | 14.6 | Number of LFS objects tried to checksum on primary | `url` |
+| `geo_lfs_objects_checksum_total` | Gauge | 14.6 | Number of LFS objects that need to be checksummed on primary | `url` |
| `geo_lfs_objects_synced` | Gauge | 10.2 | Number of syncable LFS objects synced on secondary | `url` |
| `geo_lfs_objects_failed` | Gauge | 10.2 | Number of syncable LFS objects failed to sync on secondary | `url` |
| `geo_lfs_objects_registry` | Gauge | 14.6 | Number of LFS objects in the registry | `url` |
-| `geo_lfs_objects_verified` | Gauge | 14.6 | Number of LFS objects verified on secondary | `url` |
-| `geo_lfs_objects_verification_failed` | Gauge | 14.6 | Number of LFS objects' verifications failed on secondary | `url` |
-| `geo_lfs_objects_verification_total` | Gauge | 14.6 | Number of LFS objects' verifications tried on secondary | `url` |LFS objects failed to sync on secondary | `url` |
+| `geo_lfs_objects_verified` | Gauge | 14.6 | Number of LFS objects successfully verified on secondary | `url` |
+| `geo_lfs_objects_verification_failed` | Gauge | 14.6 | Number of LFS objects that failed verifications on secondary | `url` |
+| `geo_lfs_objects_verification_total` | Gauge | 14.6 | Number of LFS objects to attempt to verify on secondary | `url` |
| `geo_attachments` | Gauge | 10.2 | Total number of file attachments available on primary | `url` |
| `geo_attachments_synced` | Gauge | 10.2 | Number of attachments synced on secondary | `url` |
| `geo_attachments_failed` | Gauge | 10.2 | Number of attachments failed to sync on secondary | `url` |
@@ -230,11 +233,11 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `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 verified on secondary | `url` |
-| `geo_repositories_verification_failed` | Gauge | 10.7 | Number of repositories failed to verify on secondary | `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 verified on secondary | `url` |
-| `geo_wikis_verification_failed` | Gauge | 10.7 | Number of wikis failed to verify 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` |
@@ -249,25 +252,25 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_terraform_state_versions` | Gauge | 13.5 | Number of terraform state versions on primary | `url` |
| `geo_terraform_state_versions_checksummed` | Gauge | 13.5 | Number of terraform state versions checksummed successfully on primary | `url` |
| `geo_terraform_state_versions_checksum_failed` | Gauge | 13.5 | Number of terraform state versions failed to calculate the checksum on primary | `url` |
-| `geo_terraform_state_versions_checksum_total` | Gauge | 13.12 | Number of terraform state versions tried to checksum on primary | `url` |
+| `geo_terraform_state_versions_checksum_total` | Gauge | 13.12 | Number of terraform state versions that need to be checksummed on primary | `url` |
| `geo_terraform_state_versions_synced` | Gauge | 13.5 | Number of syncable terraform state versions synced on secondary | `url` |
| `geo_terraform_state_versions_failed` | Gauge | 13.5 | Number of syncable terraform state versions failed to sync on secondary | `url` |
| `geo_terraform_state_versions_registry` | Gauge | 13.5 | Number of terraform state versions in the registry | `url` |
-| `geo_terraform_state_versions_verified` | Gauge | 13.12 | Number of terraform state versions verified on secondary | `url` |
-| `geo_terraform_state_versions_verification_failed` | Gauge | 13.12 | Number of terraform state versions verifications failed on secondary | `url` |
-| `geo_terraform_state_versions_verification_total` | Gauge | 13.12 | Number of terraform state versions verifications tried on secondary | `url` |
+| `geo_terraform_state_versions_verified` | Gauge | 13.12 | Number of terraform state versions successfully verified on secondary | `url` |
+| `geo_terraform_state_versions_verification_failed` | Gauge | 13.12 | Number of terraform state versions that failed verification on secondary | `url` |
+| `geo_terraform_state_versions_verification_total` | Gauge | 13.12 | Number of terraform state versions to attempt to verify on secondary | `url` |
| `global_search_bulk_cron_queue_size` | Gauge | 12.10 | Number of database records waiting to be synchronized to Elasticsearch | |
| `global_search_awaiting_indexing_queue_size` | Gauge | 13.2 | Number of database updates waiting to be synchronized to Elasticsearch while indexing is paused | |
| `geo_merge_request_diffs` | Gauge | 13.4 | Number of merge request diffs on primary | `url` |
-| `geo_merge_request_diffs_checksum_total` | Gauge | 13.12 | Number of merge request diffs tried to checksum on primary | `url` |
-| `geo_merge_request_diffs_checksummed` | Gauge | 13.4 | Number of merge request diffs successfully checksummed on primary | `url` |
+| `geo_merge_request_diffs_checksum_total` | Gauge | 13.12 | Number of merge request diffs to checksum on primary | `url` |
+| `geo_merge_request_diffs_checksummed` | Gauge | 13.4 | Number of merge request diffs that successfully calculated the checksum on primary | `url` |
| `geo_merge_request_diffs_checksum_failed` | Gauge | 13.4 | Number of merge request diffs failed to calculate the checksum on primary | `url` |
| `geo_merge_request_diffs_synced` | Gauge | 13.4 | Number of syncable merge request diffs synced on secondary | `url` |
| `geo_merge_request_diffs_failed` | Gauge | 13.4 | Number of syncable merge request diffs failed to sync on secondary | `url` |
| `geo_merge_request_diffs_registry` | Gauge | 13.4 | Number of merge request diffs in the registry | `url` |
-| `geo_merge_request_diffs_verification_total` | Gauge | 13.12 | Number of merge request diffs verifications tried on secondary | `url` |
-| `geo_merge_request_diffs_verified` | Gauge | 13.12 | Number of merge request diffs verified on secondary | `url` |
-| `geo_merge_request_diffs_verification_failed` | Gauge | 13.12 | Number of merge request diffs verifications failed on secondary | `url` |
+| `geo_merge_request_diffs_verification_total` | Gauge | 13.12 | Number of merge request diffs to attempt to verify on secondary | `url` |
+| `geo_merge_request_diffs_verified` | Gauge | 13.12 | Number of merge request diffs successfully verified on secondary | `url` |
+| `geo_merge_request_diffs_verification_failed` | Gauge | 13.12 | Number of merge request diffs that failed verification on secondary | `url` |
| `geo_snippet_repositories` | Gauge | 13.4 | Number of snippets on primary | `url` |
| `geo_snippet_repositories_checksummed` | Gauge | 13.4 | Number of snippets checksummed on primary | `url` |
| `geo_snippet_repositories_checksum_failed` | Gauge | 13.4 | Number of snippets failed to calculate the checksum on primary | `url` |
@@ -281,25 +284,25 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_group_wiki_repositories_failed` | Gauge | 13.10 | Number of syncable group wikis failed on secondary | `url` |
| `geo_group_wiki_repositories_registry` | Gauge | 13.10 | Number of syncable group wikis in the registry | `url` |
| `geo_pages_deployments` | Gauge | 14.3 | Number of pages deployments on primary | `url` |
-| `geo_pages_deployments_checksum_total` | Gauge | 14.6 | Number of pages deployments tried to checksum on primary | `url` |
-| `geo_pages_deployments_checksummed` | Gauge | 14.6 | Number of pages deployments successfully checksummed on primary | `url` |
+| `geo_pages_deployments_checksum_total` | Gauge | 14.6 | Number of pages deployments to checksum on primary | `url` |
+| `geo_pages_deployments_checksummed` | Gauge | 14.6 | Number of pages deployments that successfully calculated the checksum on primary | `url` |
| `geo_pages_deployments_checksum_failed` | Gauge | 14.6 | Number of pages deployments failed to calculate the checksum on primary | `url` |
| `geo_pages_deployments_synced` | Gauge | 14.3 | Number of syncable pages deployments synced on secondary | `url` |
| `geo_pages_deployments_failed` | Gauge | 14.3 | Number of syncable pages deployments failed to sync on secondary | `url` |
| `geo_pages_deployments_registry` | Gauge | 14.3 | Number of pages deployments in the registry | `url` |
-| `geo_pages_deployments_verification_total` | Gauge | 14.6 | Number of pages deployments verifications tried on secondary | `url` |
-| `geo_pages_deployments_verified` | Gauge | 14.6 | Number of pages deployments verified on secondary | `url` |
+| `geo_pages_deployments_verification_total` | Gauge | 14.6 | Number of pages deployments to attempt to verify on secondary | `url` |
+| `geo_pages_deployments_verified` | Gauge | 14.6 | Number of pages deployments successfully verified on secondary | `url` |
| `geo_pages_deployments_verification_failed` | Gauge | 14.6 | Number of pages deployments verifications failed on secondary | `url` |
| `geo_job_artifacts` | Gauge | 14.8 | Number of job artifacts on primary | `url` |
-| `geo_job_artifacts_checksum_total` | Gauge | 14.8 | Number of job artifacts tried to checksum on primary | `url` |
-| `geo_job_artifacts_checksummed` | Gauge | 14.8 | Number of job artifacts successfully checksummed on primary | `url` |
+| `geo_job_artifacts_checksum_total` | Gauge | 14.8 | Number of job artifacts to checksum on primary | `url` |
+| `geo_job_artifacts_checksummed` | Gauge | 14.8 | Number of job artifacts that successfully calculated the checksum on primary | `url` |
| `geo_job_artifacts_checksum_failed` | Gauge | 14.8 | Number of job artifacts failed to calculate the checksum on primary | `url` |
| `geo_job_artifacts_synced` | Gauge | 14.8 | Number of syncable job artifacts synced on secondary | `url` |
| `geo_job_artifacts_failed` | Gauge | 14.8 | Number of syncable job artifacts failed to sync on secondary | `url` |
| `geo_job_artifacts_registry` | Gauge | 14.8 | Number of job artifacts in the registry | `url` |
-| `geo_job_artifacts_verification_total` | Gauge | 14.8 | Number of job artifacts verifications tried on secondary | `url` |
-| `geo_job_artifacts_verified` | Gauge | 14.8 | Number of job artifacts verified on secondary | `url` |
-| `geo_job_artifacts_verification_failed` | Gauge | 14.8 | Number of job artifacts verifications failed on secondary | `url` |
+| `geo_job_artifacts_verification_total` | Gauge | 14.8 | Number of job artifacts to attempt to verify on secondary | `url` |
+| `geo_job_artifacts_verified` | Gauge | 14.8 | Number of job artifacts successfully verified on secondary | `url` |
+| `geo_job_artifacts_verification_failed` | Gauge | 14.8 | Number of job artifacts that failed verification on secondary | `url` |
| `limited_capacity_worker_running_jobs` | Gauge | 13.5 | Number of running jobs | `worker` |
| `limited_capacity_worker_max_running_jobs` | Gauge | 13.5 | Maximum number of running jobs | `worker` |
| `limited_capacity_worker_remaining_work_count` | Gauge | 13.5 | Number of jobs waiting to be enqueued | `worker` |
@@ -310,48 +313,52 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_uploads_synced` | Gauge | 14.1 | Number of uploads synced on secondary | `url` |
| `geo_uploads_failed` | Gauge | 14.1 | Number of syncable uploads failed to sync on secondary | `url` |
| `geo_uploads_registry` | Gauge | 14.1 | Number of uploads in the registry | `url` |
-| `geo_uploads_checksum_total` | Gauge | 14.6 | Number of uploads tried to checksum on primary | `url` |
-| `geo_uploads_checksummed` | Gauge | 14.6 | Number of uploads successfully checksummed on primary | `url` |
+| `geo_uploads_checksum_total` | Gauge | 14.6 | Number of uploads to checksum on primary | `url` |
+| `geo_uploads_checksummed` | Gauge | 14.6 | Number of uploads that successfully calculated the checksum on primary | `url` |
| `geo_uploads_checksum_failed` | Gauge | 14.6 | Number of uploads failed to calculate the checksum on primary | `url` |
-| `geo_uploads_verification_total` | Gauge | 14.6 | Number of uploads verifications tried on secondary | `url` |
-| `geo_uploads_verified` | Gauge | 14.6 | Number of uploads verified on secondary | `url` |
-| `geo_uploads_verification_failed` | Gauge | 14.6 | Number of uploads verifications failed on secondary | `url` |
+| `geo_uploads_verification_total` | Gauge | 14.6 | Number of uploads to attempt to verify on secondary | `url` |
+| `geo_uploads_verified` | Gauge | 14.6 | Number of uploads successfully verified on secondary | `url` |
+| `geo_uploads_verification_failed` | Gauge | 14.6 | Number of uploads that failed verification on secondary | `url` |
| `geo_container_repositories` | Gauge | 15.4 | Number of container repositories on primary | `url` |
| `geo_container_repositories_synced` | Gauge | 15.4 | Number of container repositories synced on secondary | `url` |
| `geo_container_repositories_failed` | Gauge | 15.4 | Number of syncable container repositories failed to sync on secondary | `url` |
| `geo_container_repositories_registry` | Gauge | 15.4 | Number of container repositories in the registry | `url` |
-| `gitlab_sli:rails_request_apdex:total` | Counter | 14.4 | The number of request-apdex measurements, [more information the development documentation](../../../development/application_slis/rails_request_apdex.md) | `endpoint_id`, `feature_category`, `request_urgency` |
-| `gitlab_sli:rails_request_apdex:success_total` | Counter | 14.4 | The number of successful requests that met the target duration for their urgency. Divide by `gitlab_sli:rails_requests_apdex:total` to get a success ratio | `endpoint_id`, `feature_category`, `request_urgency` |
+| `geo_container_repositories_checksum_total` | Gauge | 15.10 | Number of container repositories checksummed successfully on primary | `url` |
+| `geo_container_repositories_checksummed` | Gauge | 15.10 | Number of container repositories tried to checksum on primary | `url` |
+| `geo_container_repositories_checksum_failed` | Gauge | 15.10 | Number of container repositories failed to calculate the checksum on primary | `url` |
+| `geo_container_repositories_verification_total` | Gauge | 15.10 | Number of container repositories' verifications tried on secondary | `url` |
+| `geo_container_repositories_verified` | Gauge | 15.10 | Number of container repositories verified on secondary | `url` |
+| `geo_container_repositories_verification_failed` | Gauge | 15.10 | Number of container repositories' failed verifications on secondary | `url` |
| `geo_ci_secure_files` | Gauge | 15.3 | Number of secure files on primary | `url` |
-| `geo_ci_secure_files_checksum_total` | Gauge | 15.3 | Number of secure files tried to checksum on primary | `url` |
-| `geo_ci_secure_files_checksummed` | Gauge | 15.3 | Number of secure files successfully checksummed on primary | `url` |
+| `geo_ci_secure_files_checksum_total` | Gauge | 15.3 | Number of secure files to checksum on primary | `url` |
+| `geo_ci_secure_files_checksummed` | Gauge | 15.3 | Number of secure files that successfully calculated the checksum on primary | `url` |
| `geo_ci_secure_files_checksum_failed` | Gauge | 15.3 | Number of secure files failed to calculate the checksum on primary | `url` |
| `geo_ci_secure_files_synced` | Gauge | 15.3 | Number of syncable secure files synced on secondary | `url` |
| `geo_ci_secure_files_failed` | Gauge | 15.3 | Number of syncable secure files failed to sync on secondary | `url` |
| `geo_ci_secure_files_registry` | Gauge | 15.3 | Number of secure files in the registry | `url` |
-| `geo_ci_secure_files_verification_total` | Gauge | 15.3 | Number of secure files verifications tried on secondary | `url` |
-| `geo_ci_secure_files_verified` | Gauge | 15.3 | Number of secure files verified on secondary | `url` |
-| `geo_ci_secure_files_verification_failed` | Gauge | 15.3 | Number of secure files verifications failed on secondary | `url` |
+| `geo_ci_secure_files_verification_total` | Gauge | 15.3 | Number of secure files to attempt to verify on secondary | `url` |
+| `geo_ci_secure_files_verified` | Gauge | 15.3 | Number of secure files successfully verified on secondary | `url` |
+| `geo_ci_secure_files_verification_failed` | Gauge | 15.3 | Number of secure files that failed verification on secondary | `url` |
| `geo_dependency_proxy_blob` | Gauge | 15.6 | Number of dependency proxy blobs on primary | |
-| `geo_dependency_proxy_blob_checksum_total` | Gauge | 15.6 | Number of dependency proxy blobs tried to checksum on primary | |
-| `geo_dependency_proxy_blob_checksummed` | Gauge | 15.6 | Number of dependency proxy blobs successfully checksummed on primary | |
+| `geo_dependency_proxy_blob_checksum_total` | Gauge | 15.6 | Number of dependency proxy blobs to checksum on primary | |
+| `geo_dependency_proxy_blob_checksummed` | Gauge | 15.6 | Number of dependency proxy blobs that successfully calculated the checksum on primary | |
| `geo_dependency_proxy_blob_checksum_failed` | Gauge | 15.6 | Number of dependency proxy blobs failed to calculate the checksum on primary | |
| `geo_dependency_proxy_blob_synced` | Gauge | 15.6 | Number of dependency proxy blobs synced on secondary | |
| `geo_dependency_proxy_blob_failed` | Gauge | 15.6 | Number of dependency proxy blobs failed to sync on secondary | |
| `geo_dependency_proxy_blob_registry` | Gauge | 15.6 | Number of dependency proxy blobs in the registry | |
-| `geo_dependency_proxy_blob_verification_total` | Gauge | 15.6 | Number of dependency proxy blobs verifications tried on secondary | |
-| `geo_dependency_proxy_blob_verified` | Gauge | 15.6 | Number of dependency proxy blobs verified on secondary | |
-| `geo_dependency_proxy_blob_verification_failed` | Gauge | 15.6 | Number of dependency proxy blobs verifications failed on secondary | |
+| `geo_dependency_proxy_blob_verification_total` | Gauge | 15.6 | Number of dependency proxy blobs to attempt to verify on secondary | |
+| `geo_dependency_proxy_blob_verified` | Gauge | 15.6 | Number of dependency proxy blobs successfully verified on secondary | |
+| `geo_dependency_proxy_blob_verification_failed` | Gauge | 15.6 | Number of dependency proxy blobs that failed verification on secondary | |
| `geo_dependency_proxy_manifests` | Gauge | 15.6 | Number of dependency proxy manifests on primary | `url` |
-| `geo_dependency_proxy_manifests_checksum_total` | Gauge | 15.6 | Number of dependency proxy manifests tried to checksum on primary | `url` |
-| `geo_dependency_proxy_manifests_checksummed` | Gauge | 15.6 | Number of dependency proxy manifests successfully checksummed on primary | `url` |
+| `geo_dependency_proxy_manifests_checksum_total` | Gauge | 15.6 | Number of dependency proxy manifests to checksum on primary | `url` |
+| `geo_dependency_proxy_manifests_checksummed` | Gauge | 15.6 | Number of dependency proxy manifests that successfully calculated the checksum on primary | `url` |
| `geo_dependency_proxy_manifests_checksum_failed` | Gauge | 15.6 | Number of dependency proxy manifests failed to calculate the checksum on primary | `url` |
| `geo_dependency_proxy_manifests_synced` | Gauge | 15.6 | Number of syncable dependency proxy manifests synced on secondary | `url` |
| `geo_dependency_proxy_manifests_failed` | Gauge | 15.6 | Number of syncable dependency proxy manifests failed to sync on secondary | `url` |
| `geo_dependency_proxy_manifests_registry` | Gauge | 15.6 | Number of dependency proxy manifests in the registry | `url` |
-| `geo_dependency_proxy_manifests_verification_total` | Gauge | 15.6 | Number of dependency proxy manifests verifications tried on secondary | `url` |
-| `geo_dependency_proxy_manifests_verified` | Gauge | 15.6 | Number of dependency proxy manifests verified on secondary | `url` |
-| `geo_dependency_proxy_manifests_verification_failed` | Gauge | 15.6 | Number of dependency proxy manifests verifications failed on secondary | `url` |
+| `geo_dependency_proxy_manifests_verification_total` | Gauge | 15.6 | Number of dependency proxy manifests to attempt to verify on secondary | `url` |
+| `geo_dependency_proxy_manifests_verified` | Gauge | 15.6 | Number of dependency proxy manifests successfully verified on secondary | `url` |
+| `geo_dependency_proxy_manifests_verification_failed` | Gauge | 15.6 | Number of dependency proxy manifests that failed verification on secondary | `url` |
| `gitlab_memwd_violations_total` | Counter | 15.9 | Total number of times a Sidekiq process violated a memory threshold | |
| `gitlab_memwd_violations_handled_total` | Counter | 15.9 | Total number of times Sidekiq process memory violations were handled | |
| `sidekiq_watchdog_running_jobs_total` | Counter | 15.9 | Current running jobs when RSS limit was reached | `worker_class` |
@@ -445,6 +452,7 @@ instance. For example, `cache` or `shared_state`.
| `gitlab_redis_client_exceptions_total` | Counter | 13.2 | Number of Redis client exceptions, broken down by exception class |
| `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 |
## Metrics shared directory
diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md
index 56583deca89..37a7445c290 100644
--- a/doc/administration/monitoring/prometheus/index.md
+++ b/doc/administration/monitoring/prometheus/index.md
@@ -201,7 +201,10 @@ To use an external Prometheus server:
postgres_exporter['listen_address'] = '0.0.0.0:9187'
# Gitaly nodes
- gitaly['prometheus_listen_addr'] = "0.0.0.0:9236"
+ gitaly['configuration'] = {
+ # ...
+ prometheus_listen_addr: '0.0.0.0:9236',
+ }
```
1. Install and set up a dedicated Prometheus instance, if necessary, using the [official installation instructions](https://prometheus.io/docs/prometheus/latest/installation/).
diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md
index 4b3e251d407..587da749766 100644
--- a/doc/administration/object_storage.md
+++ b/doc/administration/object_storage.md
@@ -11,7 +11,7 @@ It's recommended over NFS and
in general it's better in larger setups as object storage is
typically much more performant, reliable, and scalable.
-## Options
+## Supported object storage providers
GitLab is tightly integrated with `Fog`, so you can refer to its
[documentation](https://fog.io/about/provider_documentation.html) to check
@@ -19,7 +19,9 @@ which storage services can be integrated with GitLab.
Specifically, GitLab has been tested by vendors and customers on a number of object storage providers:
-- [Amazon S3](https://aws.amazon.com/s3/)
+- [Amazon S3](https://aws.amazon.com/s3/) ([Object Lock](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html)
+ is not supported, see [issue #335775](https://gitlab.com/gitlab-org/gitlab/-/issues/335775)
+ for more information)
- [Google Cloud Storage](https://cloud.google.com/storage)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces)
- [Oracle Cloud Infrastructure](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
@@ -28,19 +30,7 @@ Specifically, GitLab has been tested by vendors and customers on a number of obj
- On-premises hardware and appliances from various storage vendors, whose list is not officially established.
- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
-### Known compatibility issues
-
-- Dell EMC ECS: Prior to GitLab 13.3, there is a
- [known bug in GitLab Workhorse that prevents HTTP Range Requests from working with CI job artifacts](https://gitlab.com/gitlab-org/gitlab/-/issues/223806).
- Be sure to upgrade to GitLab 13.3.0 or above if you use S3 storage with this hardware.
-
-- Ceph S3 prior to [Kraken 11.0.2](https://ceph.com/releases/kraken-11-0-2-released/) does not support the [Upload Copy Part API](https://gitlab.com/gitlab-org/gitlab/-/issues/300604). You may need to [disable multi-threaded copying](#multi-threaded-copying).
-
-- Amazon S3 [Object Lock](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html)
- is not supported. Follow [issue #335775](https://gitlab.com/gitlab-org/gitlab/-/issues/335775)
- for progress on enabling this option.
-
-## Configuration guides
+## Configure the object storage
There are two ways of specifying object storage configuration in GitLab:
@@ -69,7 +59,7 @@ Using the consolidated object storage configuration has a number of advantages:
Because [direct upload mode](../development/uploads/index.md#direct-upload)
must be enabled, only the following providers can be used:
-- [Amazon S3-compatible providers](#s3-compatible-connection-settings)
+- [Amazon S3-compatible providers](#amazon-s3)
- [Google Cloud Storage](#google-cloud-storage-gcs)
- [Azure Blob storage](#azure-blob-storage)
@@ -90,7 +80,7 @@ Object storage for <object type> must have a bucket specified
```
If you want to use local storage for specific object types, you can
-[selectively disable object storages](#selectively-disabling-object-storage).
+[disable object storage for specific features](#disable-object-storage-for-specific-features).
Most types of objects, such as CI artifacts, LFS files, and upload
attachments can be saved in object storage by specifying a single
@@ -105,7 +95,7 @@ When the consolidated form is:
See the section on [ETag mismatch errors](#etag-mismatch) for more details.
-#### Use AWS S3
+#### Full example using Amazon S3
The following example uses AWS S3 to enable object storage for all supported services:
@@ -116,42 +106,42 @@ The following example uses AWS S3 to enable object storage for all supported ser
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines, substituting
the values you want:
- ```ruby
- # Consolidated object storage configuration
- gitlab_rails['object_store']['enabled'] = true
- gitlab_rails['object_store']['proxy_download'] = true
- gitlab_rails['object_store']['connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'aws_access_key_id' => '<AWS_ACCESS_KEY_ID>',
- 'aws_secret_access_key' => '<AWS_SECRET_ACCESS_KEY>'
- }
- # OPTIONAL: The following lines are only needed if server side encryption is required
- gitlab_rails['object_store']['storage_options'] = {
- 'server_side_encryption' => '<AES256 or aws:kms>',
- 'server_side_encryption_kms_key_id' => '<arn:aws:kms:xxx>'
- }
- gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts'
- gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs'
- gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs'
- gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads'
- gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages'
- gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy'
- gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state'
- gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files'
- gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'
- ```
-
- If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit
- the AWS access key and secret access key/value pairs. For example:
-
- ```ruby
- gitlab_rails['object_store']['connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'use_iam_profile' => true
- }
- ```
+ ```ruby
+ # Consolidated object storage configuration
+ gitlab_rails['object_store']['enabled'] = true
+ gitlab_rails['object_store']['proxy_download'] = true
+ gitlab_rails['object_store']['connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'aws_access_key_id' => '<AWS_ACCESS_KEY_ID>',
+ 'aws_secret_access_key' => '<AWS_SECRET_ACCESS_KEY>'
+ }
+ # OPTIONAL: The following lines are only needed if server side encryption is required
+ gitlab_rails['object_store']['storage_options'] = {
+ 'server_side_encryption' => '<AES256 or aws:kms>',
+ 'server_side_encryption_kms_key_id' => '<arn:aws:kms:xxx>'
+ }
+ gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts'
+ gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs'
+ gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs'
+ gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads'
+ gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages'
+ gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy'
+ gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state'
+ gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files'
+ gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'
+ ```
+
+ If you're using [AWS IAM profiles](#use-amazon-instance-profiles), omit
+ the AWS access key and secret access key/value pairs. For example:
+
+ ```ruby
+ gitlab_rails['object_store']['connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'use_iam_profile' => true
+ }
+ ```
1. Save the file and reconfigure GitLab:
@@ -171,7 +161,7 @@ The following example uses AWS S3 to enable object storage for all supported ser
aws_secret_access_key: <AWS_SECRET_ACCESS_KEY>
```
- If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit
+ If you're using [AWS IAM profiles](#use-amazon-instance-profiles), omit
the AWS access key and secret access key/value pairs. For example:
```yaml
@@ -293,7 +283,7 @@ The following example uses AWS S3 to enable object storage for all supported ser
gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'
```
- If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit
+ If you're using [AWS IAM profiles](#use-amazon-instance-profiles), omit
the AWS access key and secret access key/value pairs. For example:
```ruby
@@ -348,7 +338,7 @@ The following example uses AWS S3 to enable object storage for all supported ser
bucket: gitlab-pages
```
- If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit
+ If you're using [AWS IAM profiles](#use-amazon-instance-profiles), omit
the AWS access key and secret access key/value pairs. For example:
```yaml
@@ -369,7 +359,7 @@ The following example uses AWS S3 to enable object storage for all supported ser
aws_secret_access_key = "<AWS_SECRET_ACCESS_KEY>"
```
- If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit
+ If you're using [AWS IAM profiles](#use-amazon-instance-profiles), omit
the AWS access key and secret access key/value pairs. For example:
```yaml
@@ -432,7 +422,7 @@ gitlab_rails['object_store']['connection'] = {
Both consolidated configuration form and storage-specific configuration form must configure a connection. The following sections describe parameters that can be used
in the `connection` setting.
-#### S3-compatible connection settings
+#### Amazon S3
The connection settings match those provided by [fog-aws](https://github.com/fog/fog-aws):
@@ -450,7 +440,7 @@ The connection settings match those provided by [fog-aws](https://github.com/fog
| `use_iam_profile` | Set to `true` to use IAM profile instead of access keys. | `false` |
| `aws_credentials_refresh_threshold_seconds` | Sets the [automatic refresh threshold](https://github.com/fog/fog-aws#controlling-credential-refresh-time-with-iam-authentication) when using temporary credentials in IAM. | `15` |
-#### Oracle Cloud S3 connection settings
+#### Oracle Cloud S3
Oracle Cloud S3 must be sure to use the following settings:
@@ -487,9 +477,10 @@ see the [Cloud Storage authentication documentation](https://cloud.google.com/st
NOTE:
Bucket encryption with the [Cloud Key Management Service (KMS)](https://cloud.google.com/kms/docs) is not supported and results in [ETag mismatch errors](#etag-mismatch).
-##### Google example (consolidated form)
+##### GCS example
-For Omnibus installations, this is an example of the `connection` setting:
+For Omnibus installations, this is an example of the `connection` setting
+in the consolidated form:
```ruby
gitlab_rails['object_store']['connection'] = {
@@ -499,13 +490,13 @@ gitlab_rails['object_store']['connection'] = {
}
```
-##### Google example with ADC (consolidated form)
+##### GCS example with ADC
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/275979) in GitLab 13.6.
Google Cloud Application Default Credentials (ADC) are typically
used with GitLab to use the default service account. This eliminates the
-need to supply credentials for the instance. For example:
+need to supply credentials for the instance. For example, in the consolidated form:
```ruby
gitlab_rails['object_store']['connection'] = {
@@ -549,42 +540,39 @@ The following are the valid connection parameters for Azure. For more informatio
| `azure_storage_access_key` | Storage account access key used to access the container. This is typically a secret, 512-bit encryption key encoded in base64. | `czV2OHkvQj9FKEgrTWJRZVRoV21ZcTN0Nnc5eiRDJkYpSkBOY1JmVWpYbjJy\nNHU3eCFBJUQqRy1LYVBkU2dWaw==\n` |
| `azure_storage_domain` | Domain name used to contact the Azure Blob Storage API (optional). Defaults to `blob.core.windows.net`. Set this if you are using Azure China, Azure Germany, Azure US Government, or some other custom Azure domain. | `blob.core.windows.net` |
-##### Azure example (consolidated form)
-
-For Omnibus installations, this is an example of the `connection` setting:
-
-```ruby
-gitlab_rails['object_store']['connection'] = {
- 'provider' => 'AzureRM',
- 'azure_storage_account_name' => '<AZURE STORAGE ACCOUNT NAME>',
- 'azure_storage_access_key' => '<AZURE STORAGE ACCESS KEY>',
- 'azure_storage_domain' => '<AZURE STORAGE DOMAIN>'
-}
-```
+- For Omnibus installations, this is an example of the `connection` setting
+ in the consolidated form:
-###### Azure Workhorse settings (source installs only)
+ ```ruby
+ gitlab_rails['object_store']['connection'] = {
+ 'provider' => 'AzureRM',
+ 'azure_storage_account_name' => '<AZURE STORAGE ACCOUNT NAME>',
+ 'azure_storage_access_key' => '<AZURE STORAGE ACCESS KEY>',
+ 'azure_storage_domain' => '<AZURE STORAGE DOMAIN>'
+ }
+ ```
-For source installations, Workhorse also needs to be configured with Azure
-credentials. This isn't needed in Omnibus installs, because the Workhorse
-settings are populated from the previous settings.
+- For source installations, Workhorse also needs to be configured with Azure
+ credentials. This isn't needed in Omnibus installs, because the Workhorse
+ settings are populated from the previous settings.
-1. Edit `/home/git/gitlab-workhorse/config.toml` and add or amend the following lines:
+ 1. Edit `/home/git/gitlab-workhorse/config.toml` and add or amend the following lines:
- ```toml
- [object_storage]
- provider = "AzureRM"
+ ```toml
+ [object_storage]
+ provider = "AzureRM"
- [object_storage.azurerm]
- azure_storage_account_name = "<AZURE STORAGE ACCOUNT NAME>"
- azure_storage_access_key = "<AZURE STORAGE ACCESS KEY>"
- ```
+ [object_storage.azurerm]
+ azure_storage_account_name = "<AZURE STORAGE ACCOUNT NAME>"
+ azure_storage_access_key = "<AZURE STORAGE ACCESS KEY>"
+ ```
-If you are using a custom Azure storage domain,
-`azure_storage_domain` does **not** have to be set in the Workhorse
-configuration. This information is exchanged in an API call between
-GitLab Rails and Workhorse.
+ If you are using a custom Azure storage domain,
+ `azure_storage_domain` does **not** have to be set in the Workhorse
+ configuration. This information is exchanged in an API call between
+ GitLab Rails and Workhorse.
-#### Storj Gateway Configuration (SJ)
+#### Storj Gateway (SJ)
NOTE:
The Storj Gateway [does not support](https://github.com/storj/gateway-st/blob/4b74c3b92c63b5de7409378b0d1ebd029db9337d/docs/s3-compatibility.md) multi-threaded copying (see `UploadPartCopy` in the table).
@@ -676,7 +664,7 @@ Within each object type, three parameters can be defined:
| `enabled` | **{dotted-circle}** No | Overrides the common parameter. |
| `proxy_download` | **{dotted-circle}** No | Overrides the common parameter. |
-#### Selectively disabling object storage
+#### Disable object storage for specific features
As seen above, object storage can be disabled for specific types by
setting the `enabled` flag to `false`. For example, to disable object
@@ -779,11 +767,133 @@ See the following additional guides:
1. [Prevent local disk usage for job logs](job_logs.md#prevent-local-disk-usage).
1. [Disable Pages local storage](pages/index.md#disable-pages-local-storage).
-## Warnings, limitations, and known issues
+## Use Amazon instance profiles
+
+Instead of supplying AWS access and secret keys in object storage
+configuration, GitLab can be configured to use IAM roles to set up an
+[Amazon instance profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html).
+When this is used, GitLab fetches temporary credentials each time an
+S3 bucket is accessed, so no hard-coded values are needed in the
+configuration.
+
+To use an Amazon instance profile, GitLab must be able to connect to the
+[instance metadata endpoint](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html).
+If GitLab is [configured to use an Internet proxy](https://docs.gitlab.com/omnibus/settings/environment-variables.html), the endpoint IP
+address must be added to the `no_proxy` list.
+
+### Encrypted S3 buckets
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-workhorse/-/merge_requests/466) in GitLab 13.1 for instance profiles only and [S3 default encryption](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html).
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34460) in GitLab 13.2 for static credentials when [consolidated object storage configuration](#consolidated-object-storage-configuration) and [S3 default encryption](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html) are used.
+
+When configured either with an instance profile or with the consolidated
+object configuration, GitLab Workhorse properly uploads files to S3
+buckets that have [SSE-S3 or SSE-KMS encryption enabled by default](https://docs.aws.amazon.com/kms/latest/developerguide/services-s3.html).
+Customer master keys (CMKs) and SSE-C encryption are
+[not supported since this requires sending the encryption keys in every request](https://gitlab.com/gitlab-org/gitlab/-/issues/226006).
+
+#### Server-side encryption headers
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38240) in GitLab 13.3.
+
+Setting a default encryption on an S3 bucket is the easiest way to
+enable encryption, but you may want to
+[set a bucket policy to ensure only encrypted objects are uploaded](https://repost.aws/knowledge-center/s3-bucket-store-kms-encrypted-objects).
+To do this, you must configure GitLab to send the proper encryption headers
+in the `storage_options` configuration section:
+
+| Setting | Description |
+|-------------------------------------|------------------------------------------|
+| `server_side_encryption` | Encryption mode (`AES256` or `aws:kms`). |
+| `server_side_encryption_kms_key_id` | Amazon Resource Name. Only needed when `aws:kms` is used in `server_side_encryption`. See the [Amazon documentation on using KMS encryption](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html). |
+
+As with the case for default encryption, these options only work when
+the Workhorse S3 client is enabled. One of the following two conditions
+must be fulfilled:
+
+- `use_iam_profile` is `true` in the connection settings.
+- Consolidated object storage settings are in use.
+
+[ETag mismatch errors](#etag-mismatch) occur if server side
+encryption headers are used without enabling the Workhorse S3 client.
+
+#### IAM Permissions
+
+To set up an instance profile:
+
+1. Create an Amazon Identity Access and Management (IAM) role with the necessary permissions. The
+ following example is a role for an S3 bucket named `test-bucket`:
+
+ ```json
+ {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "VisualEditor0",
+ "Effect": "Allow",
+ "Action": [
+ "s3:PutObject",
+ "s3:GetObject",
+ "s3:DeleteObject"
+ ],
+ "Resource": "arn:aws:s3:::test-bucket/*"
+ }
+ ]
+ }
+ ```
+
+1. [Attach this role](https://aws.amazon.com/premiumsupport/knowledge-center/attach-replace-ec2-instance-profile/)
+ to the EC2 instance hosting your GitLab instance.
+1. Configure GitLab to use it via the `use_iam_profile` configuration option.
+
+## Migrate objects to a different object storage provider
+
+You may need to migrate GitLab data in object storage to a different object storage provider. The following steps show you how do this using [Rclone](https://rclone.org/).
+
+The steps assume you are moving the `uploads` bucket, but the same process works for other buckets.
+
+Prerequisites:
+
+- Choose the computer to run Rclone on. Depending on how much data you are migrating, Rclone may have to run for a long time so you should avoid using a laptop or desktop computer that can go into power saving. You can use your GitLab server to run Rclone.
+
+1. [Install](https://rclone.org/downloads/) Rclone.
+1. Configure Rclone by running the following:
+
+ ```shell
+ rclone config
+ ```
+
+ The configuration process is interactive. Add at least two "remotes": one for the object storage provider your data is currently on (`old`), and one for the provider you are moving to (`new`).
+
+1. Verify that you can read the old data. The following example refers to the `uploads` bucket , but your bucket may have a different name:
+
+ ```shell
+ rclone ls old:uploads | head
+ ```
+
+ This should print a partial list of the objects currently stored in your `uploads` bucket. If you get an error, or if
+ the list is empty, go back and update your Rclone configuration using `rclone config`.
+
+1. Perform an initial copy. You do not need to take your GitLab server offline for this step.
+
+ ```shell
+ rclone sync -P old:uploads new:uploads
+ ```
+
+1. After the first sync completes, use the web UI or command-line interface of your new object storage provider to
+ verify that there are objects in the new bucket. If there are none, or if you encounter an error while running `rclone
+ sync`, check your Rclone configuration and try again.
+
+After you have done at least one successful Rclone copy from the old location to the new location, schedule maintenance and take your GitLab server offline. During your maintenance window you must do two things:
+
+1. Perform a final `rclone sync` run, knowing that your users cannot add new objects so you do not leave any behind in the old bucket.
+1. Update the object storage configuration of your GitLab server to use the new provider for `uploads`.
+
+## Troubleshooting
### Objects are not included in GitLab backups
-As noted in [our backup documentation](../raketasks/backup_restore.md),
+As noted in [the backup documentation](../raketasks/backup_restore.md),
objects are not included in GitLab backups. You can enable backups with
your object storage provider instead.
@@ -883,7 +993,7 @@ it's likely this is due to [encryption settings on your bucket](https://docs.aws
To fix this issue, you have two options:
- [Use the consolidated object configuration](#consolidated-object-storage-configuration).
-- [Use Amazon instance profiles](#using-amazon-instance-profiles).
+- [Use Amazon instance profiles](#use-amazon-instance-profiles).
The first option is recommended for MinIO. Otherwise, the
[workaround for MinIO](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/1564#note_244497658)
@@ -903,85 +1013,6 @@ eliminates the need to compare ETag headers returned from the S3 server.
Encrypting buckets with the GCS [Cloud Key Management Service (KMS)](https://cloud.google.com/kms/docs) is not supported and results in ETag mismatch errors.
-### Using Amazon instance profiles
-
-Instead of supplying AWS access and secret keys in object storage
-configuration, GitLab can be configured to use IAM roles to set up an
-[Amazon instance profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html).
-When this is used, GitLab fetches temporary credentials each time an
-S3 bucket is accessed, so no hard-coded values are needed in the
-configuration.
-
-To use an Amazon instance profile, GitLab must be able to connect to the
-[instance metadata endpoint](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html).
-If GitLab is [configured to use an Internet proxy](https://docs.gitlab.com/omnibus/settings/environment-variables.html), the endpoint IP
-address must be added to the `no_proxy` list.
-
-#### Encrypted S3 buckets
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab-workhorse/-/merge_requests/466) in GitLab 13.1 for instance profiles only and [S3 default encryption](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html).
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34460) in GitLab 13.2 for static credentials when [consolidated object storage configuration](#consolidated-object-storage-configuration) and [S3 default encryption](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html) are used.
-
-When configured either with an instance profile or with the consolidated
-object configuration, GitLab Workhorse properly uploads files to S3
-buckets that have [SSE-S3 or SSE-KMS encryption enabled by default](https://docs.aws.amazon.com/kms/latest/developerguide/services-s3.html).
-Customer master keys (CMKs) and SSE-C encryption are
-[not supported since this requires sending the encryption keys in every request](https://gitlab.com/gitlab-org/gitlab/-/issues/226006).
-
-##### Server-side encryption headers
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38240) in GitLab 13.3.
-
-Setting a default encryption on an S3 bucket is the easiest way to
-enable encryption, but you may want to
-[set a bucket policy to ensure only encrypted objects are uploaded](https://repost.aws/knowledge-center/s3-bucket-store-kms-encrypted-objects).
-To do this, you must configure GitLab to send the proper encryption headers
-in the `storage_options` configuration section:
-
-| Setting | Description |
-|-------------------------------------|------------------------------------------|
-| `server_side_encryption` | Encryption mode (`AES256` or `aws:kms`). |
-| `server_side_encryption_kms_key_id` | Amazon Resource Name. Only needed when `aws:kms` is used in `server_side_encryption`. See the [Amazon documentation on using KMS encryption](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html). |
-
-As with the case for default encryption, these options only work when
-the Workhorse S3 client is enabled. One of the following two conditions
-must be fulfilled:
-
-- `use_iam_profile` is `true` in the connection settings.
-- Consolidated object storage settings are in use.
-
-[ETag mismatch errors](#etag-mismatch) occur if server side
-encryption headers are used without enabling the Workhorse S3 client.
-
-#### IAM Permissions
-
-To set up an instance profile:
-
-1. Create an Amazon Identity Access and Management (IAM) role with the necessary permissions. The
- following example is a role for an S3 bucket named `test-bucket`:
-
- ```json
- {
- "Version": "2012-10-17",
- "Statement": [
- {
- "Sid": "VisualEditor0",
- "Effect": "Allow",
- "Action": [
- "s3:PutObject",
- "s3:GetObject",
- "s3:DeleteObject"
- ],
- "Resource": "arn:aws:s3:::test-bucket/*"
- }
- ]
- }
- ```
-
-1. [Attach this role](https://aws.amazon.com/premiumsupport/knowledge-center/attach-replace-ec2-instance-profile/)
- to the EC2 instance hosting your GitLab instance.
-1. Configure GitLab to use it via the `use_iam_profile` configuration option.
-
### Multi-threaded copying
GitLab uses the [S3 Upload Part Copy API](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html)
@@ -996,46 +1027,3 @@ to run the following command:
```ruby
Feature.disable(:s3_multithreaded_uploads)
```
-
-## Migrate objects to a different object storage provider
-
-You may need to migrate GitLab data in object storage to a different object storage provider. The following steps show you how do this using [Rclone](https://rclone.org/).
-
-The steps assume you are moving the `uploads` bucket, but the same process works for other buckets.
-
-Prerequisites:
-
-- Choose the computer to run Rclone on. Depending on how much data you are migrating, Rclone may have to run for a long time so you should avoid using a laptop or desktop computer that can go into power saving. You can use your GitLab server to run Rclone.
-
-1. [Install](https://rclone.org/downloads/) Rclone.
-1. Configure Rclone by running the following:
-
- ```shell
- rclone config
- ```
-
- The configuration process is interactive. Add at least two "remotes": one for the object storage provider your data is currently on (`old`), and one for the provider you are moving to (`new`).
-
-1. Verify that you can read the old data. The following example refers to the `uploads` bucket , but your bucket may have a different name:
-
- ```shell
- rclone ls old:uploads | head
- ```
-
- This should print a partial list of the objects currently stored in your `uploads` bucket. If you get an error, or if
- the list is empty, go back and update your Rclone configuration using `rclone config`.
-
-1. Perform an initial copy. You do not need to take your GitLab server offline for this step.
-
- ```shell
- rclone sync -P old:uploads new:uploads
- ```
-
-1. After the first sync completes, use the web UI or command-line interface of your new object storage provider to
- verify that there are objects in the new bucket. If there are none, or if you encounter an error while running `rclone
- sync`, check your Rclone configuration and try again.
-
-After you have done at least one successful Rclone copy from the old location to the new location, schedule maintenance and take your GitLab server offline. During your maintenance window you must do two things:
-
-1. Perform a final `rclone sync` run, knowing that your users cannot add new objects so you do not leave any behind in the old bucket.
-1. Update the object storage configuration of your GitLab server to use the new provider for `uploads`.
diff --git a/doc/administration/operations/gitlab_sshd.md b/doc/administration/operations/gitlab_sshd.md
index 7b61631fe3a..1153321267d 100644
--- a/doc/administration/operations/gitlab_sshd.md
+++ b/doc/administration/operations/gitlab_sshd.md
@@ -110,11 +110,11 @@ To enable the PROXY protocol:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_sshd['proxy_protocol'] = true
- # # Proxy protocol policy ("use", "require", "reject", "ignore"), "use" is the default value
- gitlab_sshd['proxy_policy'] = "use"
- ```
+ ```ruby
+ gitlab_sshd['proxy_protocol'] = true
+ # # Proxy protocol policy ("use", "require", "reject", "ignore"), "use" is the default value
+ gitlab_sshd['proxy_policy'] = "use"
+ ```
1. Save the file and reconfigure GitLab:
diff --git a/doc/administration/operations/index.md b/doc/administration/operations/index.md
index f6ab46b9fbf..b02aab738ea 100644
--- a/doc/administration/operations/index.md
+++ b/doc/administration/operations/index.md
@@ -8,6 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Keep your GitLab instance up and running smoothly.
+- [Upgrading GitLab](../../update/index.md).
- [Rake tasks](../../raketasks/index.md): Tasks for common administration and operational processes such as
[cleaning up unneeded items from GitLab instance](../../raketasks/cleanup.md), integrity checks,
and more.
diff --git a/doc/administration/operations/moving_repositories.md b/doc/administration/operations/moving_repositories.md
index aa0477be788..e9d829f3f08 100644
--- a/doc/administration/operations/moving_repositories.md
+++ b/doc/administration/operations/moving_repositories.md
@@ -139,14 +139,14 @@ To move all snippets by using the API:
To move all groups by using the API:
1. [Schedule repository storage moves for all groups on a storage shard](../../api/group_repository_storage_moves.md#schedule-repository-storage-moves-for-all-groups-on-a-storage-shard).
- For example:
-
- ```shell
- curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
- --header "Content-Type: application/json" \
- --data '{"source_storage_name":"<original_storage_name>","destination_storage_name":"<cluster_storage_name>"}' \
- "https://gitlab.example.com/api/v4/group_repository_storage_moves"
- ```
+ For example:
+
+ ```shell
+ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
+ --header "Content-Type: application/json" \
+ --data '{"source_storage_name":"<original_storage_name>","destination_storage_name":"<cluster_storage_name>"}' \
+ "https://gitlab.example.com/api/v4/group_repository_storage_moves"
+ ```
1. [Query the most recent repository moves](../../api/group_repository_storage_moves.md#retrieve-all-group-repository-storage-moves).
The response indicates either:
diff --git a/doc/administration/operations/rails_console.md b/doc/administration/operations/rails_console.md
index 652a4fa5497..ac550d30566 100644
--- a/doc/administration/operations/rails_console.md
+++ b/doc/administration/operations/rails_console.md
@@ -569,7 +569,7 @@ def disable_two_factor!
end
def two_factor_enabled?
- two_factor_otp_enabled? || two_factor_u2f_enabled?
+ two_factor_otp_enabled? || two_factor_webauthn_enabled?
end
```
diff --git a/doc/administration/package_information/supported_os.md b/doc/administration/package_information/supported_os.md
index 9d1c8dcde5a..f92d57c0035 100644
--- a/doc/administration/package_information/supported_os.md
+++ b/doc/administration/package_information/supported_os.md
@@ -32,6 +32,7 @@ The following lists the currently supported OSs and their possible EOL dates.
| 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 2023 | <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/) |
| 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/) |
@@ -55,6 +56,14 @@ although [new versions have been released](https://about.gitlab.com/releases/cat
of the [Linux package install guide](https://about.gitlab.com/install/#content).
Future GitLab upgrades are fetched according to your upgraded OS.
+## Update both GitLab and the operating system
+
+To upgrade both the operating system (OS) and GitLab:
+
+1. Upgrade the OS.
+1. Check if it's necessary to [update the GitLab package sources](#update-gitlab-package-sources-after-upgrading-the-os).
+1. [Upgrade GitLab](../../update/index.md).
+
## Packages for ARM64
> [Introduced](https://gitlab.com/gitlab-org/gitlab-omnibus-builder/-/issues/27) in GitLab 13.4.
diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md
index 34acf57ce70..619ec2490a7 100644
--- a/doc/administration/packages/container_registry.md
+++ b/doc/administration/packages/container_registry.md
@@ -607,10 +607,10 @@ Without this configuration, the Azure storage driver uses `//` instead of `/` as
registry['storage'] = {
'azure' => {
'accountname' => 'accountname',
- 'accesskey' => 'base64encodedaccountkey',
+ 'accountkey' => 'base64encodedaccountkey',
'container' => 'containername',
'rootdirectory' => '/azure/virtual/container',
- 'trimlegacyrootprefix' => 'true'
+ 'trimlegacyrootprefix' => true
}
}
```
@@ -627,6 +627,8 @@ storage:
trimlegacyrootprefix: true
```
+By default, Azure Storage Driver uses the `core.windows.net` realm. You can set another value for `realm` in the `azure` section (for example, `core.usgovcloudapi.net` for Azure Government Cloud). For more information, see the [Docker documentation](https://docs.docker.com/registry/storage-drivers/azure/).
+
### Disable redirect for storage driver
By default, users accessing a registry configured with a remote backend are redirected to the default backend for the storage driver. For example, registries can be configured using the `s3` storage driver, which redirects requests to a remote S3 bucket to alleviate load on the GitLab server.
@@ -637,20 +639,20 @@ However, this behavior is undesirable for registries used by internal hosts that
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- registry['storage'] = {
- 's3' => {
- 'accesskey' => 's3-access-key',
- 'secretkey' => 's3-secret-key-for-access-key',
- 'bucket' => 'your-s3-bucket',
- 'region' => 'your-s3-region',
- 'regionendpoint' => 'your-s3-regionendpoint'
- },
- 'redirect' => {
- 'disable' => true
- }
- }
- ```
+ ```ruby
+ registry['storage'] = {
+ 's3' => {
+ 'accesskey' => 's3-access-key',
+ 'secretkey' => 's3-secret-key-for-access-key',
+ 'bucket' => 'your-s3-bucket',
+ 'region' => 'your-s3-region',
+ 'regionendpoint' => 'your-s3-regionendpoint'
+ },
+ 'redirect' => {
+ 'disable' => true
+ }
+ }
+ ```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
@@ -658,21 +660,21 @@ However, this behavior is undesirable for registries used by internal hosts that
1. Add the `redirect` flag to your registry configuration YAML file:
- ```yaml
- storage:
- s3:
- accesskey: 'AKIAKIAKI'
- secretkey: 'secret123'
- bucket: 'gitlab-registry-bucket-AKIAKIAKI'
- region: 'your-s3-region'
- regionendpoint: 'your-s3-regionendpoint'
- redirect:
- disable: true
- cache:
- blobdescriptor: inmemory
- delete:
- enabled: true
- ```
+ ```yaml
+ storage:
+ s3:
+ accesskey: 'AKIAKIAKI'
+ secretkey: 'secret123'
+ bucket: 'gitlab-registry-bucket-AKIAKIAKI'
+ region: 'your-s3-region'
+ regionendpoint: 'your-s3-regionendpoint'
+ redirect:
+ disable: true
+ cache:
+ blobdescriptor: inmemory
+ delete:
+ enabled: true
+ ```
1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
@@ -690,18 +692,18 @@ For Omnibus GitLab installations:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- registry['storage'] = {
- 's3' => {
- 'accesskey' => 's3-access-key',
- 'secretkey' => 's3-secret-key-for-access-key',
- 'bucket' => 'your-s3-bucket',
- 'region' => 'your-s3-region',
- 'regionendpoint' => 'your-s3-regionendpoint',
- 'encrypt' => true
- }
- }
- ```
+ ```ruby
+ registry['storage'] = {
+ 's3' => {
+ 'accesskey' => 's3-access-key',
+ 'secretkey' => 's3-secret-key-for-access-key',
+ 'bucket' => 'your-s3-bucket',
+ 'region' => 'your-s3-region',
+ 'regionendpoint' => 'your-s3-regionendpoint',
+ 'encrypt' => true
+ }
+ }
+ ```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
for the changes to take effect.
@@ -710,16 +712,16 @@ For installations from source:
1. Edit your registry configuration YAML file:
- ```yaml
- storage:
- s3:
- accesskey: 'AKIAKIAKI'
- secretkey: 'secret123'
- bucket: 'gitlab-registry-bucket-AKIAKIAKI'
- region: 'your-s3-region'
- regionendpoint: 'your-s3-regionendpoint'
- encrypt: true
- ```
+ ```yaml
+ storage:
+ s3:
+ accesskey: 'AKIAKIAKI'
+ secretkey: 'secret123'
+ bucket: 'gitlab-registry-bucket-AKIAKIAKI'
+ region: 'your-s3-region'
+ regionendpoint: 'your-s3-regionendpoint'
+ encrypt: true
+ ```
1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source)
for the changes to take effect.
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index ed08b10fe97..efeb19a8d5e 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -631,34 +631,6 @@ are stored.
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-Alternatively, if you have existing Pages deployed you can follow
-the below steps to do a no downtime transfer to a new storage location.
-
-1. Pause Pages deployments by setting the following in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- sidekiq['queue_selector'] = true
- sidekiq['queue_groups'] = [
- "feature_category!=pages"
- ]
- ```
-
-1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-1. `rsync` contents from the current storage location to the new storage location: `sudo rsync -avzh --progress /var/opt/gitlab/gitlab-rails/shared/pages/ /mnt/storage/pages`
-1. Set the new storage location in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- gitlab_rails['pages_path'] = "/mnt/storage/pages"
- ```
-
-1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-1. Verify Pages are still being served up as expected.
-1. Resume Pages deployments by removing from `/etc/gitlab/gitlab.rb` the `sidekiq` setting set above.
-1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-1. Trigger a new Pages deployment and verify it's working as expected.
-1. Remove the old Pages storage location: `sudo rm -rf /var/opt/gitlab/gitlab-rails/shared/pages`
-1. Verify Pages are still being served up as expected.
-
## Configure listener for reverse proxy requests
Follow the steps below to configure the proxy listener of GitLab Pages.
@@ -683,23 +655,23 @@ Follow the steps below to configure the proxy listener of GitLab Pages.
## Set global maximum size of each GitLab Pages site **(FREE SELF)**
-Prerequisites:
+Prerequisite:
-- Only GitLab administrators can edit this setting.
+- You must have administrator access to the instance.
To set the global maximum pages size for a project:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > Preferences**.
1. Expand **Pages**.
-1. Enter a value under **Maximum size of pages**.
+1. In **Maximum size of pages**, enter a value. The default is `100`.
1. Select **Save changes**.
## Set maximum size of each GitLab Pages site in a group **(PREMIUM SELF)**
-Prerequisites:
+Prerequisite:
-- You must have at least the Maintainer role for the group.
+- You must have administrator access to the instance.
To set the maximum size of each GitLab Pages site in a group, overriding the inherited setting:
@@ -711,9 +683,9 @@ To set the maximum size of each GitLab Pages site in a group, overriding the inh
## Set maximum size of GitLab Pages site in a project **(PREMIUM SELF)**
-Prerequisites:
+Prerequisite:
-- You must have at least the Maintainer role for the project.
+- You must have administrator access to the instance.
To set the maximum size of GitLab Pages site in a project, overriding the inherited setting:
@@ -729,7 +701,7 @@ To set the maximum size of GitLab Pages site in a project, overriding the inheri
Prerequisite:
-- You must be an administrator of a self-managed GitLab instance.
+- You must have administrator access to the instance.
To set the maximum number of GitLab Pages custom domains for a project:
@@ -891,7 +863,7 @@ Incorrect configuration of these values may result in intermittent
or persistent errors, or the Pages Daemon serving old content.
NOTE:
-Expiry, interval and timeout flags use [Golang's duration formatting](https://pkg.go.dev/time#ParseDuration).
+Expiry, interval and timeout flags use [Go duration formatting](https://pkg.go.dev/time#ParseDuration).
A duration string is a possibly signed sequence of decimal numbers,
each with optional fraction and a unit suffix, such as `300ms`, `1.5h` or `2h45m`.
Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`.
diff --git a/doc/administration/postgresql/external.md b/doc/administration/postgresql/external.md
index 8605ee94255..24548f690ff 100644
--- a/doc/administration/postgresql/external.md
+++ b/doc/administration/postgresql/external.md
@@ -30,18 +30,18 @@ If you use a cloud-managed service, or provide your own PostgreSQL instance:
1. Configure the GitLab application servers with the appropriate connection details
for your external PostgreSQL service in your `/etc/gitlab/gitlab.rb` file:
- ```ruby
- # Disable the bundled Omnibus provided PostgreSQL
- postgresql['enable'] = false
-
- # PostgreSQL connection details
- gitlab_rails['db_adapter'] = 'postgresql'
- gitlab_rails['db_encoding'] = 'unicode'
- gitlab_rails['db_host'] = '10.1.0.5' # IP/hostname of database server
- gitlab_rails['db_password'] = 'DB password'
- ```
-
- For more information on GitLab multi-node setups, refer to the [reference architectures](../reference_architectures/index.md).
+ ```ruby
+ # Disable the bundled Omnibus provided PostgreSQL
+ postgresql['enable'] = false
+
+ # PostgreSQL connection details
+ gitlab_rails['db_adapter'] = 'postgresql'
+ gitlab_rails['db_encoding'] = 'unicode'
+ gitlab_rails['db_host'] = '10.1.0.5' # IP/hostname of database server
+ gitlab_rails['db_password'] = 'DB password'
+ ```
+
+ For more information on GitLab multi-node setups, refer to the [reference architectures](../reference_architectures/index.md).
1. Reconfigure for the changes to take effect:
diff --git a/doc/administration/postgresql/multiple_databases.md b/doc/administration/postgresql/multiple_databases.md
index 836736fb73f..188578a739c 100644
--- a/doc/administration/postgresql/multiple_databases.md
+++ b/doc/administration/postgresql/multiple_databases.md
@@ -1,6 +1,6 @@
---
stage: Data Stores
-group: Pods
+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
---
@@ -17,21 +17,81 @@ To scale GitLab, you can configure GitLab to use multiple application databases.
Due to [known issues](#known-issues), configuring GitLab with multiple databases is in [**Alpha**](../../policy/alpha-beta-support.md#alpha-features).
+After you have set up multiple databases, GitLab uses a second application database for
+[CI/CD features](../../ci/index.md), referred to as the `ci` database.
+
+All tables have exactly the same structure in both the `main`, and `ci`
+databases. Some examples:
+
+- When multiple databases are configured, the `ci_pipelines` table exists in
+ both the `main` and `ci` databases, but GitLab reads and writes only to the
+ `ci_pipelines` table in the `ci` database.
+- Similarly, the `projects` table exists in
+ both the `main` and `ci` databases, but GitLab reads and writes only to the
+ `projects` table in the `main` database.
+- For some tables (such as `loose_foreign_keys_deleted_records`) GitLab reads and writes to both the `main` and `ci` databases. See the
+ [development documentation](../../development/database/multiple_databases.md#gitlab-schema)
+
## Known issues
-- Migrating data from the `main` database to the `ci` database is not supported or documented yet.
- Once data is migrated to the `ci` database, you cannot migrate it back.
-## Set up multiple databases
+## Migrate existing installations
-Use the following content to set up multiple databases with a new GitLab installation.
+To migrate existing data from the `main` database to the `ci` database, you can
+copy the database across.
-There is no documentation for existing GitLab installations yet.
+### Existing source installation
-After you have set up multiple databases, GitLab uses a second application database for
-[CI/CD features](../../ci/index.md), referred to as the `ci` database. For
-example, GitLab reads and writes to the `ci_pipelines` table in the `ci`
-database.
+1. Stop GitLab, except for PostgreSQL:
+
+ ```shell
+ sudo service gitlab stop
+ sudo service postgresql start
+ ```
+
+1. Dump the `main` database:
+
+ ```shell
+ sudo -u git pg_dump -f gitlabhq_production.sql gitlabhq_production
+ ```
+
+1. Create the `ci` database, and copy the data from the previous dump:
+
+ ```shell
+ sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production_ci OWNER git;"
+ sudo -u git psql -f gitlabhq_production.sql gitlabhq_production_ci
+ ```
+
+1. Configure GitLab to [use multiple databases](#set-up-multiple-databases).
+
+### Existing Omnibus installation
+
+1. Stop GitLab, except for PostgreSQL:
+
+ ```shell
+ sudo gitlab-ctl stop
+ sudo gitlab-ctl start postgresql
+ ```
+
+1. Dump the `main` database:
+
+ ```shell
+ sudo -u gitlab-psql /opt/gitlab/embedded/bin/pg_dump -h /var/opt/gitlab/postgresql -f gitlabhq_production.sql gitlabhq_production
+ ```
+
+1. Create the `ci` database, and copy the data from the previous dump:
+
+ ```shell
+ sudo -u gitlab-psql /opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -d template1 -c "CREATE DATABASE gitlabhq_production_ci OWNER gitlab;"
+ sudo -u gitlab-psql /opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -f gitlabhq_production.sql gitlabhq_production_ci
+ ```
+
+1. Configure GitLab to [use multiple databases](#set-up-multiple-databases).
+
+## Set up multiple databases
+
+To configure GitLab to use multiple application databases, follow the instructions below for your installation type.
WARNING:
You must stop GitLab before setting up multiple databases. This prevents
@@ -40,6 +100,9 @@ the other way around.
### Installations from source
+1. For existing installations,
+ [migrate the data](#migrate-existing-installations) first.
+
1. [Back up GitLab](../../raketasks/backup_restore.md)
in case of unforeseen issues.
@@ -70,7 +133,7 @@ the other way around.
1. Update the service files to set the `GITLAB_ALLOW_SEPARATE_CI_DATABASE`
environment variable to `true`.
-1. Create the `gitlabhq_production_ci` database:
+1. For new installations only. Create the `gitlabhq_production_ci` database:
```shell
sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production OWNER git;"
@@ -91,6 +154,9 @@ the other way around.
### Omnibus GitLab installations
+1. For existing installations,
+ [migrate the data](#migrate-existing-installations) first.
+
1. [Back up GitLab](../../raketasks/backup_restore.md)
in case of unforeseen issues.
@@ -116,7 +182,8 @@ the other way around.
sudo gitlab-ctl reconfigure
```
-1. Optional. Reconfiguring GitLab should create the `gitlabhq_production_ci`. If it did not, manually create the `gitlabhq_production_ci`:
+1. Optional, for new installations only. Reconfiguring GitLab should create the
+ `gitlabhq_production_ci` database if it does not exist. If the database is not created automatically, create it manually:
```shell
sudo gitlab-ctl start postgresql
diff --git a/doc/administration/postgresql/pgbouncer.md b/doc/administration/postgresql/pgbouncer.md
index 5dd0aad7162..59aac9141a4 100644
--- a/doc/administration/postgresql/pgbouncer.md
+++ b/doc/administration/postgresql/pgbouncer.md
@@ -174,10 +174,12 @@ ote_pid | tls
## Procedure for bypassing PgBouncer
+### Omnibus installations
+
Some database changes have to be done directly, and not through PgBouncer.
-Read more about the affected tasks: [database restores](../../raketasks/backup_restore.md#back-up-and-restore-for-installations-using-pgbouncer)
-and [GitLab upgrades](../../update/zero_downtime.md#postgresql).
+The main affected tasks are [database restores](../../raketasks/backup_restore.md#back-up-and-restore-for-installations-using-pgbouncer)
+and [GitLab upgrades with database migrations](../../update/zero_downtime.md#postgresql).
1. To find the primary node, run the following on a database node:
@@ -195,7 +197,7 @@ and [GitLab upgrades](../../update/zero_downtime.md#postgresql).
sudo gitlab-ctl reconfigure
```
-Once you've performed the tasks or procedure, switch back to using PgBouncer:
+After you've performed the tasks or procedure, switch back to using PgBouncer:
1. Change back `/etc/gitlab/gitlab.rb` to point to PgBouncer.
1. Run reconfigure:
@@ -204,6 +206,19 @@ Once you've performed the tasks or procedure, switch back to using PgBouncer:
sudo gitlab-ctl reconfigure
```
+### Helm chart installations
+
+High-availability deployments also need to bypass PgBouncer for the same reasons as Omnibus-based ones.
+For this type of installation:
+
+- Database backup and restore tasks are performed by the toolbox container.
+- Migration tasks are performed by the migrations container.
+
+You should override the PostgreSQL port on each subchart, so these tasks can execute and connect to PostgreSQL directly:
+
+- [Toolbox](https://gitlab.com/gitlab-org/charts/gitlab/-/blob/master/charts/gitlab/charts/toolbox/values.yaml#L40)
+- [Migrations](https://gitlab.com/gitlab-org/charts/gitlab/-/blob/master/charts/gitlab/charts/migrations/values.yaml#L46)
+
## Fine tuning
PgBouncer's default settings suit the majority of installations.
diff --git a/doc/administration/raketasks/github_import.md b/doc/administration/raketasks/github_import.md
index d089682f78e..5e96813103f 100644
--- a/doc/administration/raketasks/github_import.md
+++ b/doc/administration/raketasks/github_import.md
@@ -22,7 +22,7 @@ Prerequisite:
- At least the Maintainer role on the destination group to import to. Using the Developer role for this purpose was
[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387891) in GitLab 15.8 and will be removed in GitLab 16.0.
-## Caveats
+## Rate limit
If the GitHub [rate limit](https://docs.github.com/en/rest/rate-limit) is reached while
importing, the importing process waits (`sleep()`) until it can continue importing.
diff --git a/doc/administration/raketasks/project_import_export.md b/doc/administration/raketasks/project_import_export.md
index 4694af18af2..17a0eb46a30 100644
--- a/doc/administration/raketasks/project_import_export.md
+++ b/doc/administration/raketasks/project_import_export.md
@@ -4,61 +4,42 @@ 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
---
-# Project import/export administration **(FREE SELF)**
+# Project import and export Rake tasks **(FREE SELF)**
-GitLab provides Rake tasks relating to project import and export. For more information, see:
+GitLab provides Rake tasks for [project import and export](../../user/project/settings/import_export.md).
-- [Project import/export documentation](../../user/project/settings/import_export.md).
-- [Project import/export API](../../api/project_import_export.md).
-- [Developer documentation: project import/export](../../development/import_export.md)
+You can only import from a [compatible](../../user/project/settings/import_export.md#compatibility) GitLab instance.
-## Project import status
+## Import large projects
-You can query an import through the [Project import/export API](../../api/project_import_export.md#import-status).
-As described in the API documentation, the query may return an import error or exceptions.
+> The [Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/tasks/gitlab/import_export/import.rake) was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20724) in GitLab 12.6, replacing a GitLab.com Ruby script.
-## Import/export Rake tasks
+This script was introduced in GitLab 12.6 for importing large GitLab project exports.
-The GitLab import/export version can be checked by using the following command:
+As part of this script, we also disable direct upload. This avoids uploading a huge archive to GCS, which can cause idle transaction timeouts.
-```shell
-# Omnibus installations
-sudo gitlab-rake gitlab:import_export:version
+We can run this script from the terminal:
-# Installations from source
-bundle exec rake gitlab:import_export:version RAILS_ENV=production
-```
+Parameters:
-The current list of DB tables to export can be listed by using the following command:
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `username` | string | yes | User name |
+| `namespace_path` | string | yes | Namespace path |
+| `project_path` | string | yes | Project path |
+| `archive_path` | string | yes | Path to the exported project tarball you want to import |
```shell
-# Omnibus installations
-sudo gitlab-rake gitlab:import_export:data
-
-# Installations from source
-bundle exec rake gitlab:import_export:data RAILS_ENV=production
+bundle exec rake "gitlab:import_export:import[root, group/subgroup, testingprojectimport, /path/to/file.tar.gz]"
```
-Note the following:
-
-- Importing is only possible if the version of the import and export GitLab instances are
- [compatible](../../user/project/settings/import_export.md#compatibility).
-- The project import option must be enabled:
-
- 1. On the top bar, select **Main menu > Admin**.
- 1. On the left sidebar, select **Settings > General**.
- 1. Expand **Visibility and access controls**.
- 1. Under **Import sources**, check the "Project export enabled" option.
- 1. Select **Save changes**.
-
-- The exports are stored in a temporary directory and are deleted every
- 24 hours by a specific worker.
-
-### Import large projects using a Rake task
+If you're running Omnibus, run the following Rake task:
-If you have a larger project, consider using a Rake task as described in our [developer documentation](../../development/import_project.md#importing-via-a-rake-task).
+```shell
+gitlab-rake "gitlab:import_export:import[root, group/subgroup, testingprojectimport, /path/to/file.tar.gz]"
+```
-### Export using a Rake task
+## Export large projects
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25598) in GitLab 12.9.
@@ -88,3 +69,86 @@ IMPORT_DEBUG=true gitlab-rake "gitlab:import_export:import[root, group/subgroup,
# Export
EXPORT_DEBUG=true gitlab-rake "gitlab:import_export:export[root, group/subgroup, projectnametoexport, /tmp/export_file.tar.gz]"
```
+
+Check the common errors listed below, what they mean, and how to fix them.
+
+### `Exception: undefined method 'name' for nil:NilClass`
+
+The `username` is not valid.
+
+### `Exception: undefined method 'full_path' for nil:NilClass`
+
+The `namespace_path` does not exist.
+For example, one of the groups or subgroups is mistyped or missing,
+or you've specified the project name in the path.
+
+The task only creates the project.
+If you want to import it to a new group or subgroup, create it first.
+
+### `Exception: No such file or directory @ rb_sysopen - (filename)`
+
+The specified project export file in `archive_path` is missing.
+
+### `Exception: Permission denied @ rb_sysopen - (filename)`
+
+The specified project export file cannot be accessed by the `git` user.
+
+To fix the issue:
+
+1. Set the file owner to `git:git`.
+1. Change the file permissions to `0400`.
+1. Move the file to a public folder (for example `/tmp/`).
+
+### `Name can contain only letters, digits, emojis ...`
+
+```plaintext
+Name can contain only letters, digits, emojis, '_', '.', '+', dashes, or spaces. It must start with a letter,
+digit, emoji, or '_', and Path can contain only letters, digits, '_', '-', or '.'. It cannot start
+with '-', end in '.git', or end in '.atom'.
+```
+
+The project name specified in `project_path` is not valid for one of the specified reasons.
+
+Only put the project name in `project_path`. For example, if you provide a path of subgroups
+it fails with this error as `/` is not a valid character in a project name.
+
+### `Name has already been taken and Path has already been taken`
+
+A project with that name already exists.
+
+### `Exception: Error importing repository into (namespace) - No space left on device`
+
+The disk has insufficient space to complete the import.
+
+During import, the tarball is cached in your configured `shared_path` directory. Verify the
+disk has enough free space to accommodate both the cached tarball and the unpacked
+project files on disk.
+
+### Import is successful, but with a `Total number of not imported relations: XX` message, and issues are not created during the import
+
+If you receive a `Total number of not imported relations: XX` message, and issues
+aren't created during the import, check [exceptions_json.log](../logs/index.md#exceptions_jsonlog).
+You might see an error like `N is out of range for ActiveModel::Type::Integer with limit 4 bytes`,
+where `N` is the integer exceeding the 4-byte integer limit. If that's the case, you
+are likely hitting the issue with rebalancing of `relative_position` field of the issues.
+
+```ruby
+# Check the current maximum value of relative_position
+Issue.where(project_id: Project.find(ID).root_namespace.all_projects).maximum(:relative_position)
+
+# Run the rebalancing process and check if the maximum value of relative_position has changed
+Issues::RelativePositionRebalancingService.new(Project.find(ID).root_namespace.all_projects).execute
+Issue.where(project_id: Project.find(ID).root_namespace.all_projects).maximum(:relative_position)
+```
+
+Repeat the import attempt and check if the issues are imported successfully.
+
+### Gitaly calls error when importing
+
+If you're attempting to import a large project into a development environment, Gitaly might throw an error about too many calls or invocations. For example:
+
+```plaintext
+Error importing repository into qa-perf-testing/gitlabhq - GitalyClient#call called 31 times from single request. Potential n+1?
+```
+
+This error is due to a [n+1 calls limit for development setups](../../development/gitaly.md#toomanyinvocationserror-errors). To resolve this error, set `GITALY_DISABLE_REQUEST_LIMITS=1` as an environment variable. Then restart your development environment and import again.
diff --git a/doc/administration/read_only_gitlab.md b/doc/administration/read_only_gitlab.md
index 3718741e2e9..3842cf0846b 100644
--- a/doc/administration/read_only_gitlab.md
+++ b/doc/administration/read_only_gitlab.md
@@ -70,28 +70,28 @@ the database is read-only:
in case things don't go as expected.
1. Enter PostgreSQL on the console as an administrator user:
- ```shell
- sudo \
- -u gitlab-psql /opt/gitlab/embedded/bin/psql \
- -h /var/opt/gitlab/postgresql gitlabhq_production
- ```
+ ```shell
+ sudo \
+ -u gitlab-psql /opt/gitlab/embedded/bin/psql \
+ -h /var/opt/gitlab/postgresql gitlabhq_production
+ ```
1. Create the `gitlab_read_only` user. The password is set to `mypassword`,
change that to your liking:
- ```sql
- -- NOTE: Use the password defined earlier
- CREATE USER gitlab_read_only WITH password 'mypassword';
- GRANT CONNECT ON DATABASE gitlabhq_production to gitlab_read_only;
- GRANT USAGE ON SCHEMA public TO gitlab_read_only;
- GRANT SELECT ON ALL TABLES IN SCHEMA public TO gitlab_read_only;
- GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO gitlab_read_only;
-
- -- Tables created by "gitlab" should be made read-only for "gitlab_read_only"
- -- automatically.
- ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON TABLES TO gitlab_read_only;
- ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON SEQUENCES TO gitlab_read_only;
- ```
+ ```sql
+ -- NOTE: Use the password defined earlier
+ CREATE USER gitlab_read_only WITH password 'mypassword';
+ GRANT CONNECT ON DATABASE gitlabhq_production to gitlab_read_only;
+ GRANT USAGE ON SCHEMA public TO gitlab_read_only;
+ GRANT SELECT ON ALL TABLES IN SCHEMA public TO gitlab_read_only;
+ GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO gitlab_read_only;
+
+ -- Tables created by "gitlab" should be made read-only for "gitlab_read_only"
+ -- automatically.
+ ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON TABLES TO gitlab_read_only;
+ ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON SEQUENCES TO gitlab_read_only;
+ ```
1. Get the hashed password of the `gitlab_read_only` user and copy the result:
@@ -101,10 +101,10 @@ the database is read-only:
1. Edit `/etc/gitlab/gitlab.rb` and add the password from the previous step:
- ```ruby
- postgresql['sql_user_password'] = 'a2e20f823772650f039284619ab6f239'
- postgresql['sql_user'] = "gitlab_read_only"
- ```
+ ```ruby
+ postgresql['sql_user_password'] = 'a2e20f823772650f039284619ab6f239'
+ postgresql['sql_user'] = "gitlab_read_only"
+ ```
1. Reconfigure GitLab and restart PostgreSQL:
diff --git a/doc/administration/redis/replication_and_failover.md b/doc/administration/redis/replication_and_failover.md
index 2e56884e309..a37794ec44b 100644
--- a/doc/administration/redis/replication_and_failover.md
+++ b/doc/administration/redis/replication_and_failover.md
@@ -766,6 +766,49 @@ redis['master'] = false
You can find the relevant attributes defined in [`gitlab_rails.rb`](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-cookbooks/gitlab/libraries/gitlab_rails.rb).
+### Control startup behavior
+
+> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/6646) in GitLab 15.10.
+
+To prevent the bundled Redis service from starting at boot or restarting after changing its configuration:
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ redis['start_down'] = true
+ ```
+
+1. Reconfigure GitLab:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+If you need to test a new replica node, you may set `start_down` to
+`true` and manually start the node. After the new replica node is confirmed
+working in the Redis cluster, set `start_down` to `false` and reconfigure GitLab
+to ensure the node starts and restarts as expected during operation.
+
+### Control replica configuration
+
+> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/6646) in GitLab 15.10.
+
+To prevent the `replicaof` line from rendering in the Redis configuration file:
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ redis['set_replicaof'] = false
+ ```
+
+1. Reconfigure GitLab:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+This setting can be used to prevent replication of a Redis node independently of other Redis settings.
+
## Troubleshooting
See the [Redis troubleshooting guide](troubleshooting.md).
diff --git a/doc/administration/redis/replication_and_failover_external.md b/doc/administration/redis/replication_and_failover_external.md
index 23c9ce33c2d..16383db6c2a 100644
--- a/doc/administration/redis/replication_and_failover_external.md
+++ b/doc/administration/redis/replication_and_failover_external.md
@@ -32,15 +32,15 @@ Note the Redis node's IP address or hostname, port, and password (if required).
1. Configure the GitLab application servers with the appropriate connection details
for your external Redis service in your `/etc/gitlab/gitlab.rb` file:
- ```ruby
- redis['enable'] = false
+ ```ruby
+ redis['enable'] = false
- gitlab_rails['redis_host'] = 'redis.example.com'
- gitlab_rails['redis_port'] = 6379
+ gitlab_rails['redis_host'] = 'redis.example.com'
+ gitlab_rails['redis_port'] = 6379
- # Required if Redis authentication is configured on the Redis node
- gitlab_rails['redis_password'] = 'Redis Password'
- ```
+ # Required if Redis authentication is configured on the Redis node
+ gitlab_rails['redis_password'] = 'Redis Password'
+ ```
1. Reconfigure for the changes to take effect:
diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md
index 529621813aa..1934ca6bff0 100644
--- a/doc/administration/reference_architectures/10k_users.md
+++ b/doc/administration/reference_architectures/10k_users.md
@@ -170,7 +170,7 @@ To set up GitLab and its components to accommodate up to 10,000 users:
environment.
1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+1. [Configure advanced search](#configure-advanced-search) (optional) for faster,
more advanced code search across your entire GitLab instance.
The servers start on the same 10.6.0.0/24 private network range, and can
@@ -1389,7 +1389,6 @@ Updates to example must be made at:
# Praefect Configuration
praefect['enable'] = true
- praefect['listen_addr'] = '0.0.0.0:2305'
# Prevent database migrations from running on upgrade automatically
praefect['auto_migrate'] = false
@@ -1404,45 +1403,63 @@ Updates to example must be made at:
# Please set the real values as explained in Required Information section
#
- # Praefect External Token
- # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
- praefect['auth_token'] = '<praefect_external_token>'
-
- # Praefect Database Settings
- praefect['database_host'] = '10.6.0.141'
- praefect['database_port'] = 5432
- # `no_proxy` settings must always be a direct connection for caching
- praefect['database_direct_host'] = '10.6.0.141'
- praefect['database_direct_port'] = 5432
- praefect['database_dbname'] = 'praefect_production'
- praefect['database_user'] = 'praefect'
- praefect['database_password'] = '<praefect_postgresql_password>'
-
- # Praefect Virtual Storage config
- # Name of storage hash must match storage name in git_data_dirs on GitLab
- # server ('praefect') and in git_data_dirs on Gitaly nodes ('gitaly-1')
- praefect['virtual_storages'] = {
- 'default' => {
- 'nodes' => {
- 'gitaly-1' => {
- 'address' => 'tcp://10.6.0.91:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-2' => {
- 'address' => 'tcp://10.6.0.92:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-3' => {
- 'address' => 'tcp://10.6.0.93:8075',
- 'token' => '<praefect_internal_token>'
+ praefect['configuration'] = {
+ # ...
+ listen_addr: '0.0.0.0:2305',
+ auth: {
+ # ...
+ #
+ # Praefect External Token
+ # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
+ token: '<praefect_external_token>',
+ },
+ # Praefect Database Settings
+ database: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ # `no_proxy` settings must always be a direct connection for caching
+ session_pooled: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ dbname: 'praefect_production',
+ user: 'praefect',
+ password: '<praefect_postgresql_password>',
+ },
+ },
+ # Praefect Virtual Storage config
+ # Name of storage hash must match storage name in git_data_dirs on GitLab
+ # server ('praefect') and in gitaly['configuration'][:storage] on Gitaly nodes ('gitaly-1')
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ node: [
+ {
+ storage: 'gitaly-1',
+ address: 'tcp://10.6.0.91:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-2',
+ address: 'tcp://10.6.0.92:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-3',
+ address: 'tcp://10.6.0.93:8075',
+ token: '<praefect_internal_token>'
+ },
+ ],
},
- }
- }
+ ],
+ # Set the network address Praefect will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9652',
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- praefect['prometheus_listen_addr'] = '0.0.0.0:9652'
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
@@ -1505,7 +1522,7 @@ to restrict access to the Gitaly server. Another option is to
For configuring Gitaly you should note the following:
-- `git_data_dirs` should be configured to reflect the storage path for the specific Gitaly node
+- `gitaly['configuration'][:storage]` should be configured to reflect the storage path for the specific Gitaly node
- `auth_token` should be the same as `praefect_internal_token`
The following IPs will be used as an example:
@@ -1554,20 +1571,6 @@ Updates to example must be made at:
# Gitaly
gitaly['enable'] = true
- # Make Gitaly accept connections on all network interfaces. You must use
- # firewalls to restrict access to this address/port.
- # Comment out following line if you only want to support TLS connections
- gitaly['listen_addr'] = "0.0.0.0:8075"
-
- # Gitaly Auth Token
- # Should be the same as praefect_internal_token
- gitaly['auth_token'] = '<praefect_internal_token>'
-
- # Gitaly Pack-objects cache
- # Recommended to be enabled for improved performance but can notably increase disk I/O
- # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
- gitaly['pack_objects_cache_enabled'] = true
-
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
@@ -1582,9 +1585,29 @@ Updates to example must be made at:
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address that the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- gitaly['prometheus_listen_addr'] = '0.0.0.0:9236'
+
+ gitaly['configuration'] = {
+ # Make Gitaly accept connections on all network interfaces. You must use
+ # firewalls to restrict access to this address/port.
+ # Comment out following line if you only want to support TLS connections
+ listen_addr: '0.0.0.0:8075',
+ # Set the network address that Gitaly will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9236',
+ auth: {
+ # Gitaly Auth Token
+ # Should be the same as praefect_internal_token
+ token: '<praefect_internal_token>',
+ },
+ pack_objects_cache: {
+ # Gitaly Pack-objects cache
+ # Recommended to be enabled for improved performance but can notably increase disk I/O
+ # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
+ enabled: true,
+ },
+ }
+
#
# END user configuration
```
@@ -1593,31 +1616,43 @@ Updates to example must be made at:
- On Gitaly node 1:
```ruby
- git_data_dirs({
- "gitaly-1" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-1',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 2:
```ruby
- git_data_dirs({
- "gitaly-2" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-2',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 3:
```ruby
- git_data_dirs({
- "gitaly-3" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-3',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Omnibus node you configured and add or replace
@@ -1646,7 +1681,7 @@ Note the following:
- You can configure Praefect servers with both an unencrypted listening address
`listen_addr` and an encrypted listening address `tls_listen_addr` at the same time.
This allows you to do a gradual transition from unencrypted to encrypted traffic, if
- necessary. To disable the unencrypted listener, set `praefect['listen_addr'] = nil`.
+ necessary. To disable the unencrypted listener, set `praefect['configuration'][:listen_addr] = nil`.
- The Internal Load Balancer will also access to the certificates and need to be configured
to allow for TLS pass-through.
Refer to the load balancers documentation on how to configure this.
@@ -1668,9 +1703,15 @@ To configure Praefect with TLS:
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
- praefect['tls_listen_addr'] = "0.0.0.0:3305"
- praefect['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
- praefect['key_path'] = "/etc/gitlab/ssl/key.pem"
+ praefect['configuration'] = {
+ # ...
+ tls_listen_addr: '0.0.0.0:3305',
+ tls: {
+ # ...
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ }
```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -1751,7 +1792,7 @@ Updates to example must be made at:
# Redis
## Redis connection details
- ## First cluster that will host the cache
+ ## First cluster that will host the cache data
gitlab_rails['redis_cache_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER>@gitlab-redis-cache'
gitlab_rails['redis_cache_sentinels'] = [
@@ -1760,22 +1801,11 @@ Updates to example must be made at:
{host: '10.6.0.53', port: 26379},
]
- ## Second cluster that will host the persistent queues, shared state, and actioncable
- gitlab_rails['redis_queues_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_shared_state_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_actioncable_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
+ ## Second cluster that hosts all other persistent data
+ redis['master_name'] = 'gitlab-redis-persistent'
+ redis['master_password'] = '<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>'
- gitlab_rails['redis_queues_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_shared_state_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_actioncable_sentinels'] = [
+ gitlab_rails['redis_sentinels'] = [
{host: '10.6.0.61', port: 26379},
{host: '10.6.0.62', port: 26379},
{host: '10.6.0.63', port: 26379},
@@ -1936,7 +1966,7 @@ On each node perform the following:
gitlab_rails['auto_migrate'] = false
## Redis connection details
- ## First cluster that will host the cache
+ ## First cluster that will host the cache data
gitlab_rails['redis_cache_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER>@gitlab-redis-cache'
gitlab_rails['redis_cache_sentinels'] = [
@@ -1945,22 +1975,11 @@ On each node perform the following:
{host: '10.6.0.53', port: 26379},
]
- ## Second cluster that will host the persistent queues, shared state, and actioncable
- gitlab_rails['redis_queues_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_shared_state_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_actioncable_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
+ ## Second cluster that hosts all other persistent data
+ redis['master_name'] = 'gitlab-redis-persistent'
+ redis['master_password'] = '<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>'
- gitlab_rails['redis_queues_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_shared_state_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_actioncable_sentinels'] = [
+ gitlab_rails['redis_sentinels'] = [
{host: '10.6.0.61', port: 26379},
{host: '10.6.0.62', port: 26379},
{host: '10.6.0.63', port: 26379},
@@ -2200,9 +2219,9 @@ GitLab Runner returns job logs in chunks which Omnibus GitLab caches temporarily
While sharing the job logs through NFS is supported, it's recommended to avoid the need to use NFS by enabling [incremental logging](../job_logs.md#incremental-logging-architecture) (required when no NFS node has been deployed). Incremental logging uses Redis instead of disk space for temporary caching of job logs.
-## Configure Advanced Search
+## Configure advanced search
-You can leverage Elasticsearch and [enable Advanced Search](../../integration/advanced_search/elasticsearch.md)
+You can leverage Elasticsearch and [enable advanced search](../../integration/advanced_search/elasticsearch.md)
for faster, more advanced code search across your entire GitLab instance.
Elasticsearch cluster design and requirements are dependent on your specific
diff --git a/doc/administration/reference_architectures/1k_users.md b/doc/administration/reference_architectures/1k_users.md
index d3aa6fef51e..adcf8eeb4c6 100644
--- a/doc/administration/reference_architectures/1k_users.md
+++ b/doc/administration/reference_architectures/1k_users.md
@@ -78,9 +78,9 @@ You can also optionally configure GitLab to use an [external PostgreSQL service]
or an [external object storage service](../object_storage.md) for added
performance and reliability at an increased complexity cost.
-## Configure Advanced Search **(PREMIUM SELF)**
+## Configure advanced search **(PREMIUM SELF)**
-You can leverage Elasticsearch and [enable Advanced Search](../../integration/advanced_search/elasticsearch.md)
+You can leverage Elasticsearch and [enable advanced search](../../integration/advanced_search/elasticsearch.md)
for faster, more advanced code search across your entire GitLab instance.
Elasticsearch cluster design and requirements are dependent on your specific
diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md
index 71fe8b301e2..08cb6e2cdff 100644
--- a/doc/administration/reference_architectures/25k_users.md
+++ b/doc/administration/reference_architectures/25k_users.md
@@ -170,7 +170,7 @@ To set up GitLab and its components to accommodate up to 25,000 users:
environment.
1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+1. [Configure advanced search](#configure-advanced-search) (optional) for faster,
more advanced code search across your entire GitLab instance.
The servers start on the same 10.6.0.0/24 private network range, and can
@@ -1406,7 +1406,6 @@ Updates to example must be made at:
# Praefect Configuration
praefect['enable'] = true
- praefect['listen_addr'] = '0.0.0.0:2305'
# Prevent database migrations from running on upgrade automatically
praefect['auto_migrate'] = false
@@ -1415,51 +1414,69 @@ Updates to example must be made at:
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
- consul['monitoring_service_discovery'] = true
+ consul['monitoring_service_discovery'] = true
# START user configuration
# Please set the real values as explained in Required Information section
#
- # Praefect External Token
- # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
- praefect['auth_token'] = '<praefect_external_token>'
-
- # Praefect Database Settings
- praefect['database_host'] = '10.6.0.141'
- praefect['database_port'] = 5432
- # `no_proxy` settings must always be a direct connection for caching
- praefect['database_direct_host'] = '10.6.0.141'
- praefect['database_direct_port'] = 5432
- praefect['database_dbname'] = 'praefect_production'
- praefect['database_user'] = 'praefect'
- praefect['database_password'] = '<praefect_postgresql_password>'
-
- # Praefect Virtual Storage config
- # Name of storage hash must match storage name in git_data_dirs on GitLab
- # server ('praefect') and in git_data_dirs on Gitaly nodes ('gitaly-1')
- praefect['virtual_storages'] = {
- 'default' => {
- 'nodes' => {
- 'gitaly-1' => {
- 'address' => 'tcp://10.6.0.91:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-2' => {
- 'address' => 'tcp://10.6.0.92:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-3' => {
- 'address' => 'tcp://10.6.0.93:8075',
- 'token' => '<praefect_internal_token>'
+ praefect['configuration'] = {
+ # ...
+ listen_addr: '0.0.0.0:2305',
+ auth: {
+ # ...
+ #
+ # Praefect External Token
+ # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
+ token: '<praefect_external_token>',
+ },
+ # Praefect Database Settings
+ database: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ # `no_proxy` settings must always be a direct connection for caching
+ session_pooled: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ dbname: 'praefect_production',
+ user: 'praefect',
+ password: '<praefect_postgresql_password>',
+ },
+ },
+ # Praefect Virtual Storage config
+ # Name of storage hash must match storage name in git_data_dirs on GitLab
+ # server ('praefect') and in gitaly['configuration'][:storage] on Gitaly nodes ('gitaly-1')
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ node: [
+ {
+ storage: 'gitaly-1',
+ address: 'tcp://10.6.0.91:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-2',
+ address: 'tcp://10.6.0.92:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-3',
+ address: 'tcp://10.6.0.93:8075',
+ token: '<praefect_internal_token>'
+ },
+ ],
},
- }
- }
+ ],
+ # Set the network address Praefect will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9652',
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- praefect['prometheus_listen_addr'] = '0.0.0.0:9652'
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
@@ -1522,7 +1539,7 @@ to restrict access to the Gitaly server. Another option is to
For configuring Gitaly you should note the following:
-- `git_data_dirs` should be configured to reflect the storage path for the specific Gitaly node
+- `gitaly['configuration'][:storage]` should be configured to reflect the storage path for the specific Gitaly node
- `auth_token` should be the same as `praefect_internal_token`
The following IPs will be used as an example:
@@ -1571,20 +1588,6 @@ Updates to example must be made at:
# Gitaly
gitaly['enable'] = true
- # Make Gitaly accept connections on all network interfaces. You must use
- # firewalls to restrict access to this address/port.
- # Comment out following line if you only want to support TLS connections
- gitaly['listen_addr'] = "0.0.0.0:8075"
-
- # Gitaly Auth Token
- # Should be the same as praefect_internal_token
- gitaly['auth_token'] = '<praefect_internal_token>'
-
- # Gitaly Pack-objects cache
- # Recommended to be enabled for improved performance but can notably increase disk I/O
- # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
- gitaly['pack_objects_cache_enabled'] = true
-
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
@@ -1599,9 +1602,29 @@ Updates to example must be made at:
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address that the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- gitaly['prometheus_listen_addr'] = '0.0.0.0:9236'
+
+ gitaly['configuration'] = {
+ # Make Gitaly accept connections on all network interfaces. You must use
+ # firewalls to restrict access to this address/port.
+ # Comment out following line if you only want to support TLS connections
+ listen_addr: '0.0.0.0:8075',
+ # Set the network address that Gitaly will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9236',
+ auth: {
+ # Gitaly Auth Token
+ # Should be the same as praefect_internal_token
+ token: '<praefect_internal_token>',
+ },
+ pack_objects_cache: {
+ # Gitaly Pack-objects cache
+ # Recommended to be enabled for improved performance but can notably increase disk I/O
+ # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
+ enabled: true,
+ },
+ }
+
#
# END user configuration
```
@@ -1610,31 +1633,43 @@ Updates to example must be made at:
- On Gitaly node 1:
```ruby
- git_data_dirs({
- "gitaly-1" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-1',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 2:
```ruby
- git_data_dirs({
- "gitaly-2" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-2',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 3:
```ruby
- git_data_dirs({
- "gitaly-3" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-3',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Omnibus node you configured and add or replace
@@ -1663,7 +1698,7 @@ Note the following:
- You can configure Praefect servers with both an unencrypted listening address
`listen_addr` and an encrypted listening address `tls_listen_addr` at the same time.
This allows you to do a gradual transition from unencrypted to encrypted traffic, if
- necessary. To disable the unencrypted listener, set `praefect['listen_addr'] = nil`.
+ necessary. To disable the unencrypted listener, set `praefect['configuration'][:listen_addr] = nil`.
- The Internal Load Balancer will also access to the certificates and need to be configured
to allow for TLS passthrough.
Refer to the load balancers documentation on how to configure this.
@@ -1685,9 +1720,15 @@ To configure Praefect with TLS:
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
- praefect['tls_listen_addr'] = "0.0.0.0:3305"
- praefect['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
- praefect['key_path'] = "/etc/gitlab/ssl/key.pem"
+ praefect['configuration'] = {
+ # ...
+ tls_listen_addr: '0.0.0.0:3305',
+ tls: {
+ # ...
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ }
```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -1768,7 +1809,7 @@ Updates to example must be made at:
# Redis
## Redis connection details
- ## First cluster that will host the cache
+ ## First cluster that will host the cache data
gitlab_rails['redis_cache_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER>@gitlab-redis-cache'
gitlab_rails['redis_cache_sentinels'] = [
@@ -1777,22 +1818,11 @@ Updates to example must be made at:
{host: '10.6.0.53', port: 26379},
]
- ## Second cluster that will host the persistent queues, shared state, and actioncable
- gitlab_rails['redis_queues_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_shared_state_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_actioncable_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
+ ## Second cluster that hosts all other persistent data
+ redis['master_name'] = 'gitlab-redis-persistent'
+ redis['master_password'] = '<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>'
- gitlab_rails['redis_queues_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_shared_state_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_actioncable_sentinels'] = [
+ gitlab_rails['redis_sentinels'] = [
{host: '10.6.0.61', port: 26379},
{host: '10.6.0.62', port: 26379},
{host: '10.6.0.63', port: 26379},
@@ -1955,7 +1985,7 @@ On each node perform the following:
gitlab_rails['auto_migrate'] = false
## Redis connection details
- ## First cluster that will host the cache
+ ## First cluster that will host the cache data
gitlab_rails['redis_cache_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER>@gitlab-redis-cache'
gitlab_rails['redis_cache_sentinels'] = [
@@ -1964,22 +1994,11 @@ On each node perform the following:
{host: '10.6.0.53', port: 26379},
]
- ## Second cluster that will host the queues, shared state, and actionable
- gitlab_rails['redis_queues_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_shared_state_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_actioncable_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
+ ## Second cluster that hosts all other persistent data
+ redis['master_name'] = 'gitlab-redis-persistent'
+ redis['master_password'] = '<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>'
- gitlab_rails['redis_queues_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_shared_state_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_actioncable_sentinels'] = [
+ gitlab_rails['redis_sentinels'] = [
{host: '10.6.0.61', port: 26379},
{host: '10.6.0.62', port: 26379},
{host: '10.6.0.63', port: 26379},
@@ -2218,9 +2237,9 @@ GitLab Runner returns job logs in chunks which Omnibus GitLab caches temporarily
While sharing the job logs through NFS is supported, it's recommended to avoid the need to use NFS by enabling [incremental logging](../job_logs.md#incremental-logging-architecture) (required when no NFS node has been deployed). Incremental logging uses Redis instead of disk space for temporary caching of job logs.
-## Configure Advanced Search
+## Configure advanced search
-You can leverage Elasticsearch and [enable Advanced Search](../../integration/advanced_search/elasticsearch.md)
+You can leverage Elasticsearch and [enable advanced search](../../integration/advanced_search/elasticsearch.md)
for faster, more advanced code search across your entire GitLab instance.
Elasticsearch cluster design and requirements are dependent on your specific
diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md
index ee26504902c..d87e8270dcb 100644
--- a/doc/administration/reference_architectures/2k_users.md
+++ b/doc/administration/reference_architectures/2k_users.md
@@ -101,7 +101,7 @@ To set up GitLab and its components to accommodate up to 2,000 users:
environment.
1. [Configure the object storage](#configure-the-object-storage) used for
shared data objects.
-1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+1. [Configure advanced search](#configure-advanced-search) (optional) for faster,
more advanced code search across your entire GitLab instance.
## Configure the external load balancer
@@ -459,7 +459,7 @@ To configure the Gitaly server, on the server node you want to use for Gitaly:
storage paths, enable the network listener, and to configure the token:
NOTE:
- You can't remove the `default` entry from `git_data_dirs` because [GitLab requires it](../gitaly/configure_gitaly.md#gitlab-requires-a-default-repository-storage).
+ You can't remove the `default` entry from `gitaly['configuration'][:storage]` because [GitLab requires it](../gitaly/configure_gitaly.md#gitlab-requires-a-default-repository-storage).
<!--
Updates to example must be made at:
@@ -493,30 +493,48 @@ Updates to example must be made at:
# Gitaly
gitaly['enable'] = true
- # Make Gitaly accept connections on all network interfaces. You must use
- # firewalls to restrict access to this address/port.
- # Comment out following line if you only want to support TLS connections
- gitaly['listen_addr'] = "0.0.0.0:8075"
- gitaly['prometheus_listen_addr'] = "0.0.0.0:9236"
-
- # Gitaly and GitLab use two shared secrets for authentication, one to authenticate gRPC requests
- # to Gitaly, and a second for authentication callbacks from GitLab-Shell to the GitLab internal API.
- # The following two values must be the same as their respective values
- # of the GitLab Rails application setup
- gitaly['auth_token'] = 'gitalysecret'
+ # The secret token is used for authentication callbacks from Gitaly to the GitLab internal API.
+ # This must match the respective value in GitLab Rails application setup.
gitlab_shell['secret_token'] = 'shellsecret'
# Set the network addresses that the exporters used for monitoring will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
- git_data_dirs({
- 'default' => {
- 'path' => '/var/opt/gitlab/git-data'
- },
- 'storage1' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
+ gitaly['configuration'] = {
+ # ...
+ #
+ # Make Gitaly accept connections on all network interfaces. You must use
+ # firewalls to restrict access to this address/port.
+ # Comment out following line if you only want to support TLS connections
+ listen_addr: '0.0.0.0:8075',
+ prometheus_listen_addr: '0.0.0.0:9236',
+ # Gitaly Auth Token
+ # Should be the same as praefect_internal_token
+ auth: {
+ # ...
+ #
+ # Gitaly's authentication token is used to authenticate gRPC requests to Gitaly. This must match
+ # the respective value in GitLab Rails application setup.
+ token: 'gitalysecret',
+ },
+ # Gitaly Pack-objects cache
+ # Recommended to be enabled for improved performance but can notably increase disk I/O
+ # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
+ pack_objects_cache: {
+ # ...
+ enabled: true,
+ },
+ storage: [
+ {
+ name: 'default',
+ path: '/var/opt/gitlab/git-data',
+ },
+ {
+ name: 'storage1',
+ path: '/mnt/gitlab/git-data',
+ },
+ ],
+ }
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Omnibus node you configured and add or replace
@@ -574,9 +592,14 @@ To configure Gitaly with TLS:
<!-- Updates to following example must also be made at https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab -->
```ruby
- gitaly['tls_listen_addr'] = "0.0.0.0:9999"
- gitaly['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
- gitaly['key_path'] = "/etc/gitlab/ssl/key.pem"
+ gitaly['configuration'] = {
+ # ...
+ tls_listen_addr: '0.0.0.0:9999',
+ tls: {
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ }
```
1. Delete `gitaly['listen_addr']` to allow only encrypted connections.
@@ -911,9 +934,9 @@ GitLab Runner returns job logs in chunks which Omnibus GitLab caches temporarily
While sharing the job logs through NFS is supported, it's recommended to avoid the need to use NFS by enabling [incremental logging](../job_logs.md#incremental-logging-architecture) (required when no NFS node has been deployed). Incremental logging uses Redis instead of disk space for temporary caching of job logs.
-## Configure Advanced Search **(PREMIUM SELF)**
+## Configure advanced search **(PREMIUM SELF)**
-You can leverage Elasticsearch and [enable Advanced Search](../../integration/advanced_search/elasticsearch.md)
+You can leverage Elasticsearch and [enable advanced search](../../integration/advanced_search/elasticsearch.md)
for faster, more advanced code search across your entire GitLab instance.
Elasticsearch cluster design and requirements are dependent on your specific
diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md
index 1d5dad02b18..c28799ed459 100644
--- a/doc/administration/reference_architectures/3k_users.md
+++ b/doc/administration/reference_architectures/3k_users.md
@@ -176,7 +176,7 @@ To set up GitLab and its components to accommodate up to 3,000 users:
environment.
1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+1. [Configure advanced search](#configure-advanced-search) (optional) for faster,
more advanced code search across your entire GitLab instance.
The servers start on the same 10.6.0.0/24 private network range, and can
@@ -1341,7 +1341,6 @@ Updates to example must be made at:
# Praefect Configuration
praefect['enable'] = true
- praefect['listen_addr'] = '0.0.0.0:2305'
# Prevent database migrations from running on upgrade automatically
praefect['auto_migrate'] = false
@@ -1350,51 +1349,69 @@ Updates to example must be made at:
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
- consul['monitoring_service_discovery'] = true
+ consul['monitoring_service_discovery'] = true
# START user configuration
# Please set the real values as explained in Required Information section
#
- # Praefect External Token
- # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
- praefect['auth_token'] = '<praefect_external_token>'
-
- # Praefect Database Settings
- praefect['database_host'] = '10.6.0.141'
- praefect['database_port'] = 5432
- # `no_proxy` settings must always be a direct connection for caching
- praefect['database_direct_host'] = '10.6.0.141'
- praefect['database_direct_port'] = 5432
- praefect['database_dbname'] = 'praefect_production'
- praefect['database_user'] = 'praefect'
- praefect['database_password'] = '<praefect_postgresql_password>'
-
- # Praefect Virtual Storage config
- # Name of storage hash must match storage name in git_data_dirs on GitLab
- # server ('praefect') and in git_data_dirs on Gitaly nodes ('gitaly-1')
- praefect['virtual_storages'] = {
- 'default' => {
- 'nodes' => {
- 'gitaly-1' => {
- 'address' => 'tcp://10.6.0.91:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-2' => {
- 'address' => 'tcp://10.6.0.92:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-3' => {
- 'address' => 'tcp://10.6.0.93:8075',
- 'token' => '<praefect_internal_token>'
+ praefect['configuration'] = {
+ # ...
+ listen_addr: '0.0.0.0:2305',
+ auth: {
+ # ...
+ #
+ # Praefect External Token
+ # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
+ token: '<praefect_external_token>',
+ },
+ # Praefect Database Settings
+ database: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ # `no_proxy` settings must always be a direct connection for caching
+ session_pooled: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ dbname: 'praefect_production',
+ user: 'praefect',
+ password: '<praefect_postgresql_password>',
+ },
+ },
+ # Praefect Virtual Storage config
+ # Name of storage hash must match storage name in git_data_dirs on GitLab
+ # server ('praefect') and in gitaly['configuration'][:storage] on Gitaly nodes ('gitaly-1')
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ node: [
+ {
+ storage: 'gitaly-1',
+ address: 'tcp://10.6.0.91:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-2',
+ address: 'tcp://10.6.0.92:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-3',
+ address: 'tcp://10.6.0.93:8075',
+ token: '<praefect_internal_token>'
+ },
+ ],
},
- }
- }
+ ],
+ # Set the network address Praefect will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9652',
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- praefect['prometheus_listen_addr'] = '0.0.0.0:9652'
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
@@ -1457,7 +1474,7 @@ to restrict access to the Gitaly server. Another option is to
For configuring Gitaly you should note the following:
-- `git_data_dirs` should be configured to reflect the storage path for the specific Gitaly node
+- `gitaly['configuration'][:storage]` should be configured to reflect the storage path for the specific Gitaly node
- `auth_token` should be the same as `praefect_internal_token`
The following IPs will be used as an example:
@@ -1506,20 +1523,6 @@ Updates to example must be made at:
# balancer.
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
- # Make Gitaly accept connections on all network interfaces. You must use
- # firewalls to restrict access to this address/port.
- # Comment out following line if you only want to support TLS connections
- gitaly['listen_addr'] = "0.0.0.0:8075"
-
- # Gitaly Auth Token
- # Should be the same as praefect_internal_token
- gitaly['auth_token'] = '<praefect_internal_token>'
-
- # Gitaly Pack-objects cache
- # Recommended to be enabled for improved performance but can notably increase disk I/O
- # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
- gitaly['pack_objects_cache_enabled'] = true
-
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
@@ -1534,9 +1537,33 @@ Updates to example must be made at:
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address that the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- gitaly['prometheus_listen_addr'] = '0.0.0.0:9236'
+
+ gitaly['configuration'] = {
+ # ...
+ #
+ # Make Gitaly accept connections on all network interfaces. You must use
+ # firewalls to restrict access to this address/port.
+ # Comment out following line if you only want to support TLS connections
+ listen_addr: '0.0.0.0:8075',
+ # Set the network address that Gitaly will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9236',
+ # Gitaly Auth Token
+ # Should be the same as praefect_internal_token
+ auth: {
+ # ...
+ token: '<praefect_internal_token>',
+ },
+ # Gitaly Pack-objects cache
+ # Recommended to be enabled for improved performance but can notably increase disk I/O
+ # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
+ pack_objects_cache: {
+ # ...
+ enabled: true,
+ },
+ }
+
#
# END user configuration
```
@@ -1545,31 +1572,43 @@ Updates to example must be made at:
- On Gitaly node 1:
```ruby
- git_data_dirs({
- "gitaly-1" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-1',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 2:
```ruby
- git_data_dirs({
- "gitaly-2" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-2',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 3:
```ruby
- git_data_dirs({
- "gitaly-3" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-3',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Omnibus node you configured and add or replace
@@ -1598,7 +1637,7 @@ Note the following:
- You can configure Praefect servers with both an unencrypted listening address
`listen_addr` and an encrypted listening address `tls_listen_addr` at the same time.
This allows you to do a gradual transition from unencrypted to encrypted traffic, if
- necessary. To disable the unencrypted listener, set `praefect['listen_addr'] = nil`.
+ necessary. To disable the unencrypted listener, set `praefect['configuration'][:listen_addr] = nil`.
- The Internal Load Balancer will also access to the certificates and need to be configured
to allow for TLS passthrough.
Refer to the load balancers documentation on how to configure this.
@@ -1620,9 +1659,15 @@ To configure Praefect with TLS:
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
- praefect['tls_listen_addr'] = "0.0.0.0:3305"
- praefect['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
- praefect['key_path'] = "/etc/gitlab/ssl/key.pem"
+ praefect['configuration'] = {
+ # ...
+ tls_listen_addr: '0.0.0.0:3305',
+ tls: {
+ # ...
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ }
```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -2165,9 +2210,9 @@ GitLab Runner returns job logs in chunks which Omnibus GitLab caches temporarily
While sharing the job logs through NFS is supported, it's recommended to avoid the need to use NFS by enabling [incremental logging](../job_logs.md#incremental-logging-architecture) (required when no NFS node has been deployed). Incremental logging uses Redis instead of disk space for temporary caching of job logs.
-## Configure Advanced Search
+## Configure advanced search
-You can leverage Elasticsearch and [enable Advanced Search](../../integration/advanced_search/elasticsearch.md)
+You can leverage Elasticsearch and [enable advanced search](../../integration/advanced_search/elasticsearch.md)
for faster, more advanced code search across your entire GitLab instance.
Elasticsearch cluster design and requirements are dependent on your specific
diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md
index 3bcffa8f606..3f2771dda29 100644
--- a/doc/administration/reference_architectures/50k_users.md
+++ b/doc/administration/reference_architectures/50k_users.md
@@ -170,7 +170,7 @@ To set up GitLab and its components to accommodate up to 50,000 users:
environment.
1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+1. [Configure advanced search](#configure-advanced-search) (optional) for faster,
more advanced code search across your entire GitLab instance.
The servers start on the same 10.6.0.0/24 private network range, and can
@@ -1402,7 +1402,6 @@ Updates to example must be made at:
# Praefect Configuration
praefect['enable'] = true
- praefect['listen_addr'] = '0.0.0.0:2305'
# Prevent database migrations from running on upgrade automatically
praefect['auto_migrate'] = false
@@ -1411,51 +1410,69 @@ Updates to example must be made at:
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
- consul['monitoring_service_discovery'] = true
+ consul['monitoring_service_discovery'] = true
# START user configuration
# Please set the real values as explained in Required Information section
#
- # Praefect External Token
- # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
- praefect['auth_token'] = '<praefect_external_token>'
-
- # Praefect Database Settings
- praefect['database_host'] = '10.6.0.141'
- praefect['database_port'] = 5432
- # `no_proxy` settings must always be a direct connection for caching
- praefect['database_direct_host'] = '10.6.0.141'
- praefect['database_direct_port'] = 5432
- praefect['database_dbname'] = 'praefect_production'
- praefect['database_user'] = 'praefect'
- praefect['database_password'] = '<praefect_postgresql_password>'
-
- # Praefect Virtual Storage config
- # Name of storage hash must match storage name in git_data_dirs on GitLab
- # server ('praefect') and in git_data_dirs on Gitaly nodes ('gitaly-1')
- praefect['virtual_storages'] = {
- 'default' => {
- 'nodes' => {
- 'gitaly-1' => {
- 'address' => 'tcp://10.6.0.91:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-2' => {
- 'address' => 'tcp://10.6.0.92:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-3' => {
- 'address' => 'tcp://10.6.0.93:8075',
- 'token' => '<praefect_internal_token>'
+ praefect['configuration'] = {
+ # ...
+ listen_addr: '0.0.0.0:2305',
+ auth: {
+ # ...
+ #
+ # Praefect External Token
+ # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
+ token: '<praefect_external_token>',
+ },
+ # Praefect Database Settings
+ database: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ # `no_proxy` settings must always be a direct connection for caching
+ session_pooled: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ dbname: 'praefect_production',
+ user: 'praefect',
+ password: '<praefect_postgresql_password>',
+ },
+ },
+ # Praefect Virtual Storage config
+ # Name of storage hash must match storage name in git_data_dirs on GitLab
+ # server ('praefect') and in gitaly['configuration'][:storage] on Gitaly nodes ('gitaly-1')
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ node: [
+ {
+ storage: 'gitaly-1',
+ address: 'tcp://10.6.0.91:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-2',
+ address: 'tcp://10.6.0.92:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-3',
+ address: 'tcp://10.6.0.93:8075',
+ token: '<praefect_internal_token>'
+ },
+ ],
},
- }
- }
+ ],
+ # Set the network address Praefect will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9652',
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- praefect['prometheus_listen_addr'] = '0.0.0.0:9652'
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
@@ -1518,7 +1535,7 @@ to restrict access to the Gitaly server. Another option is to
For configuring Gitaly you should note the following:
-- `git_data_dirs` should be configured to reflect the storage path for the specific Gitaly node
+- `gitaly['configuration'][:storage]` should be configured to reflect the storage path for the specific Gitaly node
- `auth_token` should be the same as `praefect_internal_token`
The following IPs will be used as an example:
@@ -1567,20 +1584,6 @@ Updates to example must be made at:
# Gitaly
gitaly['enable'] = true
- # Make Gitaly accept connections on all network interfaces. You must use
- # firewalls to restrict access to this address/port.
- # Comment out following line if you only want to support TLS connections
- gitaly['listen_addr'] = "0.0.0.0:8075"
-
- # Gitaly Auth Token
- # Should be the same as praefect_internal_token
- gitaly['auth_token'] = '<praefect_internal_token>'
-
- # Gitaly Pack-objects cache
- # Recommended to be enabled for improved performance but can notably increase disk I/O
- # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
- gitaly['pack_objects_cache_enabled'] = true
-
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
@@ -1595,9 +1598,29 @@ Updates to example must be made at:
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address that the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- gitaly['prometheus_listen_addr'] = '0.0.0.0:9236'
+
+ gitaly['configuration'] = {
+ # Make Gitaly accept connections on all network interfaces. You must use
+ # firewalls to restrict access to this address/port.
+ # Comment out following line if you only want to support TLS connections
+ listen_addr: '0.0.0.0:8075',
+ # Set the network address that Gitaly will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9236',
+ auth: {
+ # Gitaly Auth Token
+ # Should be the same as praefect_internal_token
+ token: '<praefect_internal_token>',
+ },
+ pack_objects_cache: {
+ # Gitaly Pack-objects cache
+ # Recommended to be enabled for improved performance but can notably increase disk I/O
+ # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
+ enabled: true,
+ },
+ }
+
#
# END user configuration
```
@@ -1606,31 +1629,43 @@ Updates to example must be made at:
- On Gitaly node 1:
```ruby
- git_data_dirs({
- "gitaly-1" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-1',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 2:
```ruby
- git_data_dirs({
- "gitaly-2" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-2',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 3:
```ruby
- git_data_dirs({
- "gitaly-3" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-3',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Omnibus node you configured and add or replace
@@ -1659,7 +1694,7 @@ Note the following:
- You can configure Praefect servers with both an unencrypted listening address
`listen_addr` and an encrypted listening address `tls_listen_addr` at the same time.
This allows you to do a gradual transition from unencrypted to encrypted traffic, if
- necessary. To disable the unencrypted listener, set `praefect['listen_addr'] = nil`.
+ necessary. To disable the unencrypted listener, set `praefect['configuration'][:listen_addr] = nil`.
- The Internal Load Balancer will also access to the certificates and need to be configured
to allow for TLS passthrough.
Refer to the load balancers documentation on how to configure this.
@@ -1681,9 +1716,15 @@ To configure Praefect with TLS:
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
- praefect['tls_listen_addr'] = "0.0.0.0:3305"
- praefect['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
- praefect['key_path'] = "/etc/gitlab/ssl/key.pem"
+ praefect['configuration'] = {
+ # ...
+ tls_listen_addr: '0.0.0.0:3305',
+ tls: {
+ # ...
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ }
```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -1764,7 +1805,7 @@ Updates to example must be made at:
# Redis
## Redis connection details
- ## First cluster that will host the cache
+ ## First cluster that will host the cache data
gitlab_rails['redis_cache_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER>@gitlab-redis-cache'
gitlab_rails['redis_cache_sentinels'] = [
@@ -1773,22 +1814,11 @@ Updates to example must be made at:
{host: '10.6.0.53', port: 26379},
]
- ## Second cluster that will host the persistent queues, shared state, and actioncable
- gitlab_rails['redis_queues_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_shared_state_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_actioncable_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
+ ## Second cluster that hosts all other persistent data
+ redis['master_name'] = 'gitlab-redis-persistent'
+ redis['master_password'] = '<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>'
- gitlab_rails['redis_queues_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_shared_state_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_actioncable_sentinels'] = [
+ gitlab_rails['redis_sentinels'] = [
{host: '10.6.0.61', port: 26379},
{host: '10.6.0.62', port: 26379},
{host: '10.6.0.63', port: 26379},
@@ -1958,7 +1988,7 @@ On each node perform the following:
gitlab_rails['auto_migrate'] = false
## Redis connection details
- ## First cluster that will host the cache
+ ## First cluster that will host the cache data
gitlab_rails['redis_cache_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER>@gitlab-redis-cache'
gitlab_rails['redis_cache_sentinels'] = [
@@ -1967,22 +1997,11 @@ On each node perform the following:
{host: '10.6.0.53', port: 26379},
]
- ## Second cluster that will host the persistent queues, shared state, and actionable
- gitlab_rails['redis_queues_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_shared_state_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
- gitlab_rails['redis_actioncable_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>@gitlab-redis-persistent'
+ ## Second cluster that hosts all other persistent data
+ redis['master_name'] = 'gitlab-redis-persistent'
+ redis['master_password'] = '<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>'
- gitlab_rails['redis_queues_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_shared_state_sentinels'] = [
- {host: '10.6.0.61', port: 26379},
- {host: '10.6.0.62', port: 26379},
- {host: '10.6.0.63', port: 26379},
- ]
- gitlab_rails['redis_actioncable_sentinels'] = [
+ gitlab_rails['redis_sentinels'] = [
{host: '10.6.0.61', port: 26379},
{host: '10.6.0.62', port: 26379},
{host: '10.6.0.63', port: 26379},
@@ -2217,9 +2236,9 @@ GitLab Runner returns job logs in chunks which Omnibus GitLab caches temporarily
While sharing the job logs through NFS is supported, it's recommended to avoid the need to use NFS by enabling [incremental logging](../job_logs.md#incremental-logging-architecture) (required when no NFS node has been deployed). Incremental logging uses Redis instead of disk space for temporary caching of job logs.
-## Configure Advanced Search
+## Configure advanced search
-You can leverage Elasticsearch and [enable Advanced Search](../../integration/advanced_search/elasticsearch.md)
+You can leverage Elasticsearch and [enable advanced search](../../integration/advanced_search/elasticsearch.md)
for faster, more advanced code search across your entire GitLab instance.
Elasticsearch cluster design and requirements are dependent on your specific
diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md
index 691f71289c3..43d63d4f08e 100644
--- a/doc/administration/reference_architectures/5k_users.md
+++ b/doc/administration/reference_architectures/5k_users.md
@@ -173,7 +173,7 @@ To set up GitLab and its components to accommodate up to 5,000 users:
environment.
1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+1. [Configure advanced search](#configure-advanced-search) (optional) for faster,
more advanced code search across your entire GitLab instance.
The servers start on the same 10.6.0.0/24 private network range, and can
@@ -1338,7 +1338,6 @@ Updates to example must be made at:
# Praefect Configuration
praefect['enable'] = true
- praefect['listen_addr'] = '0.0.0.0:2305'
# Prevent database migrations from running on upgrade automatically
praefect['auto_migrate'] = false
@@ -1347,51 +1346,69 @@ Updates to example must be made at:
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
- consul['monitoring_service_discovery'] = true
+ consul['monitoring_service_discovery'] = true
# START user configuration
# Please set the real values as explained in Required Information section
#
- # Praefect External Token
- # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
- praefect['auth_token'] = '<praefect_external_token>'
-
- # Praefect Database Settings
- praefect['database_host'] = '10.6.0.141'
- praefect['database_port'] = 5432
- # `no_proxy` settings must always be a direct connection for caching
- praefect['database_direct_host'] = '10.6.0.141'
- praefect['database_direct_port'] = 5432
- praefect['database_dbname'] = 'praefect_production'
- praefect['database_user'] = 'praefect'
- praefect['database_password'] = '<praefect_postgresql_password>'
-
- # Praefect Virtual Storage config
- # Name of storage hash must match storage name in git_data_dirs on GitLab
- # server ('praefect') and in git_data_dirs on Gitaly nodes ('gitaly-1')
- praefect['virtual_storages'] = {
- 'default' => {
- 'nodes' => {
- 'gitaly-1' => {
- 'address' => 'tcp://10.6.0.91:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-2' => {
- 'address' => 'tcp://10.6.0.92:8075',
- 'token' => '<praefect_internal_token>'
- },
- 'gitaly-3' => {
- 'address' => 'tcp://10.6.0.93:8075',
- 'token' => '<praefect_internal_token>'
+ praefect['configuration'] = {
+ # ...
+ listen_addr: '0.0.0.0:2305',
+ auth: {
+ # ...
+ #
+ # Praefect External Token
+ # This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
+ token: '<praefect_external_token>',
+ },
+ # Praefect Database Settings
+ database: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ # `no_proxy` settings must always be a direct connection for caching
+ session_pooled: {
+ # ...
+ host: '10.6.0.141',
+ port: 5432,
+ dbname: 'praefect_production',
+ user: 'praefect',
+ password: '<praefect_postgresql_password>',
+ },
+ },
+ # Praefect Virtual Storage config
+ # Name of storage hash must match storage name in git_data_dirs on GitLab
+ # server ('praefect') and in gitaly['configuration'][:storage] on Gitaly nodes ('gitaly-1')
+ virtual_storage: [
+ {
+ # ...
+ name: 'default',
+ node: [
+ {
+ storage: 'gitaly-1',
+ address: 'tcp://10.6.0.91:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-2',
+ address: 'tcp://10.6.0.92:8075',
+ token: '<praefect_internal_token>'
+ },
+ {
+ storage: 'gitaly-3',
+ address: 'tcp://10.6.0.93:8075',
+ token: '<praefect_internal_token>'
+ },
+ ],
},
- }
- }
+ ],
+ # Set the network address Praefect will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9652',
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- praefect['prometheus_listen_addr'] = '0.0.0.0:9652'
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
@@ -1454,7 +1471,7 @@ to restrict access to the Gitaly server. Another option is to
For configuring Gitaly you should note the following:
-- `git_data_dirs` should be configured to reflect the storage path for the specific Gitaly node
+- `gitaly['configuration'][:storage]` should be configured to reflect the storage path for the specific Gitaly node
- `auth_token` should be the same as `praefect_internal_token`
The following IPs are used as an example:
@@ -1503,20 +1520,6 @@ Updates to example must be made at:
# Gitaly
gitaly['enable'] = true
- # Make Gitaly accept connections on all network interfaces. You must use
- # firewalls to restrict access to this address/port.
- # Comment out following line if you only want to support TLS connections
- gitaly['listen_addr'] = "0.0.0.0:8075"
-
- # Gitaly Auth Token
- # Should be the same as praefect_internal_token
- gitaly['auth_token'] = '<praefect_internal_token>'
-
- # Gitaly Pack-objects cache
- # Recommended to be enabled for improved performance but can notably increase disk I/O
- # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
- gitaly['pack_objects_cache_enabled'] = true
-
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
@@ -1531,9 +1534,29 @@ Updates to example must be made at:
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
- # Set the network addresses that the exporters will listen on for monitoring
+ # Set the network address that the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
- gitaly['prometheus_listen_addr'] = '0.0.0.0:9236'
+
+ gitaly['configuration'] = {
+ # Make Gitaly accept connections on all network interfaces. You must use
+ # firewalls to restrict access to this address/port.
+ # Comment out following line if you only want to support TLS connections
+ listen_addr: '0.0.0.0:8075',
+ # Set the network address that Gitaly will listen on for monitoring
+ prometheus_listen_addr: '0.0.0.0:9236',
+ auth: {
+ # Gitaly Auth Token
+ # Should be the same as praefect_internal_token
+ token: '<praefect_internal_token>',
+ },
+ pack_objects_cache: {
+ # Gitaly Pack-objects cache
+ # Recommended to be enabled for improved performance but can notably increase disk I/O
+ # Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
+ enabled: true,
+ },
+ }
+
#
# END user configuration
```
@@ -1542,31 +1565,43 @@ Updates to example must be made at:
- On Gitaly node 1:
```ruby
- git_data_dirs({
- "gitaly-1" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-1',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 2:
```ruby
- git_data_dirs({
- "gitaly-2" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-2',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
- On Gitaly node 3:
```ruby
- git_data_dirs({
- "gitaly-3" => {
- "path" => "/var/opt/gitlab/git-data"
- }
- })
+ gitaly['configuration'] = {
+ # ...
+ storage: [
+ {
+ name: 'gitaly-3',
+ path: '/var/opt/gitlab/git-data',
+ },
+ ],
+ }
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Omnibus node you configured and add or replace
@@ -1595,7 +1630,7 @@ Note the following:
- You can configure Praefect servers with both an unencrypted listening address
`listen_addr` and an encrypted listening address `tls_listen_addr` at the same time.
This allows you to do a gradual transition from unencrypted to encrypted traffic, if
- necessary. To disable the unencrypted listener, set `praefect['listen_addr'] = nil`.
+ necessary. To disable the unencrypted listener, set `praefect['configuration'][:listen_addr] = nil`.
- The Internal Load Balancer will also access to the certificates and need to be configured
to allow for TLS passthrough.
Refer to the load balancers documentation on how to configure this.
@@ -1617,9 +1652,15 @@ To configure Praefect with TLS:
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
- praefect['tls_listen_addr'] = "0.0.0.0:3305"
- praefect['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
- praefect['key_path'] = "/etc/gitlab/ssl/key.pem"
+ praefect['configuration'] = {
+ # ...
+ tls_listen_addr: '0.0.0.0:3305',
+ tls: {
+ # ...
+ certificate_path: '/etc/gitlab/ssl/cert.pem',
+ key_path: '/etc/gitlab/ssl/key.pem',
+ },
+ }
```
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
@@ -2164,9 +2205,9 @@ GitLab Runner returns job logs in chunks which Omnibus GitLab caches temporarily
While sharing the job logs through NFS is supported, it's recommended to avoid the need to use NFS by enabling [incremental logging](../job_logs.md#incremental-logging-architecture) (required when no NFS node has been deployed). Incremental logging uses Redis instead of disk space for temporary caching of job logs.
-## Configure Advanced Search
+## Configure advanced search
-You can leverage Elasticsearch and [enable Advanced Search](../../integration/advanced_search/elasticsearch.md)
+You can leverage Elasticsearch and [enable advanced search](../../integration/advanced_search/elasticsearch.md)
for faster, more advanced code search across your entire GitLab instance.
Elasticsearch cluster design and requirements are dependent on your specific
diff --git a/doc/administration/reference_architectures/index.md b/doc/administration/reference_architectures/index.md
index 7b01efa183b..e4d07558306 100644
--- a/doc/administration/reference_architectures/index.md
+++ b/doc/administration/reference_architectures/index.md
@@ -513,51 +513,51 @@ The following table details the cost to run the different reference architecture
</tr>
<tr>
<th scope="row">2k</th>
- <td><a href="https://cloud.google.com/products/calculator#id=84d11491-d72a-493c-a16e-650931faa658">Calculated cost</a></td>
+ <td><a href="https://cloud.google.com/products/calculator#id=0d3aff1f-ea3d-43f9-aa59-df49d27c35ca">Calculated cost</a></td>
<td></td>
- <td><a href="https://calculator.aws/#/estimate?id=dce36b5cb6ab25211f74e47233d77f58fefb54e2">Calculated cost</a></td>
+ <td><a href="https://calculator.aws/#/estimate?id=3b3e3b81953737132789591d3a5179521943f1c0">Calculated cost</a></td>
<td></td>
- <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=72764902f3854f798407fb03c3de4b6f">Calculated cost</a></td>
+ <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=25f66c35ba454bb98fb4034a8a50bb8c">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">3k</th>
- <td><a href="https://cloud.google.com/products/calculator/#id=ac4838e6-9c40-4a36-ac43-6d1bc1843e08">Calculated cost</a></td>
+ <td><a href="https://cloud.google.com/products/calculator/#id=15fc2bd9-5b1c-479d-bc46-d5ce096b8107">Calculated cost</a></td>
<td></td>
- <td><a href="https://calculator.aws/#/estimate?id=b1c5b4e32e990eaeb035a148255132bd28988760">Calculated cost</a></td>
+ <td><a href="https://calculator.aws/#/estimate?id=7e94eb8712f6845fdeb05e61f459598a91dac3cb">Calculated cost</a></td>
<td></td>
- <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=0dbfc575051943b9970e5d8ace03680d">Calculated cost</a></td>
+ <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=24ac11fd947a4985ae9c9a5142649ad3">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">5k</th>
- <td><a href="https://cloud.google.com/products/calculator/#id=8742e8ea-c08f-4e0a-b058-02f3a1c38a2f">Calculated cost</a></td>
+ <td><a href="https://cloud.google.com/products/calculator/#id=9a798136-53f2-4c35-be43-8e1e975a6663">Calculated cost</a></td>
<td></td>
- <td><a href="https://calculator.aws/#/estimate?id=2bf1af883096e6f4c6efddb4f3c35febead7fec2">Calculated cost</a></td>
+ <td><a href="https://calculator.aws/#/estimate?id=ad4c9db623a214c92d780cd9dff33f444d62cf02">Calculated cost</a></td>
<td></td>
- <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=8f618711ffec4b039f1581871ca6a7c9">Calculated cost</a></td>
+ <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=bcf23017ddfd40649fdc885cacd08d0c">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">10k</th>
- <td><a href="https://cloud.google.com/products/calculator#id=e77713f6-dc0b-4bb3-bcef-cea904ac8efd">Calculated cost</a></td>
+ <td><a href="https://cloud.google.com/products/calculator#id=cbe61840-31a1-487f-88fa-631251c2fde5">Calculated cost</a></td>
<td></td>
- <td><a href="https://calculator.aws/#/estimate?id=1d374df13c0f2088d332ab0134f5b1d0f717259e">Calculated cost</a></td>
+ <td><a href="https://calculator.aws/#/estimate?id=3e2970f919915a6337acea76a9f07655a1ecda4a">Calculated cost</a></td>
<td></td>
- <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=de3da8286dda4d4db1362932bc75410b">Calculated cost</a></td>
+ <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=5748068be4864af6a34efb1cde685fa1">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">25k</th>
- <td><a href="https://cloud.google.com/products/calculator#id=925386e1-c01c-4c0a-8d7d-ebde1824b7b0">Calculated cost</a></td>
+ <td><a href="https://cloud.google.com/products/calculator#id=b4b8b587-508a-4433-adc8-dc506bbe924f">Calculated cost</a></td>
<td></td>
- <td><a href="https://calculator.aws/#/estimate?id=46fe6a6e9256d9b7779fae59fbbfa7e836942b7d">Calculated cost</a></td>
+ <td><a href="https://calculator.aws/#/estimate?id=32acaeaa93366110cd5fbf98a66a8a141db7adcb">Calculated cost</a></td>
<td></td>
- <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=69724ebd82914a60857da6a3ace05a64">Calculate cost</a></td>
+ <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=24f878f20ee64b5cb64de459d34c8128">Calculate cost</a></td>
</tr>
<tr>
<th scope="row">50k</th>
- <td><a href="https://cloud.google.com/products/calculator/#id=8006396b-88ee-40cd-a1c8-77cdefa4d3c8">Calculated cost</a></td>
+ <td><a href="https://cloud.google.com/products/calculator/#id=48b4d817-d6cd-44b8-b069-0ba9a5d123ea">Calculated cost</a></td>
<td></td>
- <td><a href="https://calculator.aws/#/estimate?id=e15926b1a3c7139e4faf390a3875ff807d2ab91c">Calculated cost</a></td>
+ <td><a href="https://calculator.aws/#/estimate?id=5a0bba1338e3577d627ec97833dbc80ac9615562">Calculated cost</a></td>
<td></td>
- <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=3f973040ebc14023933d35f576c89846">Calculated cost</a></td>
+ <td><a href="https://azure.microsoft.com/en-us/pricing/calculator/?shared-estimate=4dd065eea2194d70b44d6d897e81f460">Calculated cost</a></td>
</tr>
</table>
diff --git a/doc/administration/reply_by_email.md b/doc/administration/reply_by_email.md
index 6e97ffc3b47..5172a9613ee 100644
--- a/doc/administration/reply_by_email.md
+++ b/doc/administration/reply_by_email.md
@@ -1,6 +1,6 @@
---
-stage: Plan
-group: Certify
+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
---
diff --git a/doc/administration/repository_checks.md b/doc/administration/repository_checks.md
index 08c1df3d5eb..3f715e451a8 100644
--- a/doc/administration/repository_checks.md
+++ b/doc/administration/repository_checks.md
@@ -9,9 +9,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
You can use [`git fsck`](https://git-scm.com/docs/git-fsck) to verify the integrity of all data
committed to a repository. GitLab administrators can:
-- Manually trigger this check for a project, using the GitLab UI.
-- Schedule this check to run automatically for all projects.
-- Run this check from the command line.
+- [Manually trigger this check for a project](#check-a-projects-repository-using-gitlab-ui).
+- [Schedule this check](#enable-repository-checks-for-all-projects) to run automatically for all projects.
+- [Run this check from the command line](#run-a-check-using-the-command-line).
- Run a [Rake task](raketasks/check.md#repository-integrity) for checking Git repositories, which can be used to run
`git fsck` against all repositories and generate repository checksums, as a way to compare repositories on different
servers.
@@ -68,9 +68,13 @@ You can run [`git fsck`](https://git-scm.com/docs/git-fsck) using the command li
1. Run the check. For example:
```shell
- sudo -u git /opt/gitlab/embedded/bin/git -C /var/opt/gitlab/git-data/repositories/@hashed/0b/91/0b91...f9.git fsck
+ sudo -u git /opt/gitlab/embedded/bin/git \
+ -C /var/opt/gitlab/git-data/repositories/@hashed/0b/91/0b91...f9.git fsck --no-dangling
```
+ The error `fatal: detected dubious ownership in repository` means you're running the command
+ using the wrong account. For example, `root`.
+
## What to do if a check failed
If a repository check fails, locate the error in the [`repocheck.log` file](logs/index.md#repochecklog) on disk at:
@@ -93,3 +97,26 @@ of date. The `commit-graph` cache is an auxiliary cache and is not required for
While the message can be safely ignored, see the issue [error: Could not read from object database for commit-graph](https://gitlab.com/gitlab-org/gitaly/-/issues/2359)
for more details.
+
+### Dangling commit, tag, or blob messages
+
+Repository check output often includes tags, blobs, and commits that must be pruned:
+
+```plaintext
+dangling tag 5c6886c774b713a43158aae35c4effdb03a3ceca
+dangling blob 3e268c23fcd736db92e89b31d9f267dd4a50ac4b
+dangling commit 919ff61d8d78c2e3ea9a32701dff70ecbefdd1d7
+```
+
+This is common in Git repositories. They're generated by operations like
+force pushing to branches, because this generates a commit in the repository
+that is not longer referred to by a ref or by another commit.
+
+If a repository check fails, the output is likely to include these warnings.
+
+Ignore these messages, and identify the root cause of the repository check failure
+from the other output.
+
+[GitLab 15.8 and later](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5230) no
+longer includes these messages in the check output. Use the `--no-dangling` option
+to suppress then when run from the command line.
diff --git a/doc/administration/server_hooks.md b/doc/administration/server_hooks.md
index 3d4f39b5ff0..87ae6fdb003 100644
--- a/doc/administration/server_hooks.md
+++ b/doc/administration/server_hooks.md
@@ -84,7 +84,7 @@ To create a Git hook that applies to all repositories, set a global server hook.
Before creating a global server hook, you must choose a directory for it.
-For Omnibus GitLab installations, the directory is set in `gitlab.rb` under `gitaly['custom_hooks_dir']`. You can either:
+For Omnibus GitLab installations, the directory is set in `gitlab.rb` under `gitaly['configuration'][:hooks][:custom_hooks_dir]`. You can either:
- Use the default suggestion of the `/var/opt/gitlab/gitaly/custom_hooks` directory by uncommenting it.
- Add your own setting.
diff --git a/doc/administration/sidekiq/extra_sidekiq_routing.md b/doc/administration/sidekiq/extra_sidekiq_routing.md
deleted file mode 100644
index d1d65498fcc..00000000000
--- a/doc/administration/sidekiq/extra_sidekiq_routing.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'processing_specific_job_classes.md#routing-rules'
-remove_date: '2023-02-01'
----
-
-This document was moved to [another location](processing_specific_job_classes.md#routing-rules).
-
-<!-- This redirect file can be deleted after <2023-02-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 (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/sidekiq/index.md b/doc/administration/sidekiq/index.md
index bf858476c0c..8645df55a62 100644
--- a/doc/administration/sidekiq/index.md
+++ b/doc/administration/sidekiq/index.md
@@ -32,12 +32,20 @@ By default, GitLab uses UNIX sockets and is not set up to communicate via TCP. T
## Gitaly
- # Make Gitaly accept connections on all network interfaces
- gitaly['listen_addr'] = "0.0.0.0:8075"
- ## Set up the Gitaly token as a form of authentication since you are accessing Gitaly over the network
- ## https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#about-the-gitaly-token
- gitaly['auth_token'] = 'abc123secret'
- praefect['auth_token'] = 'abc123secret'
+ gitaly['configuration'] = {
+ # ...
+ #
+ # Make Gitaly accept connections on all network interfaces
+ listen_addr: '0.0.0.0:8075',
+ auth: {
+ ## Set up the Gitaly token as a form of authentication since you are accessing Gitaly over the network
+ ## https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#about-the-gitaly-token
+ token: 'abc123secret',
+ },
+ }
+
+ gitaly['auth_token'] = ''
+ praefect['configuration'][:auth][:token] = 'abc123secret'
gitlab_rails['gitaly_token'] = 'abc123secret'
## Redis configuration
@@ -170,7 +178,7 @@ Updates to example must be made at:
# Replace <database_host> and <database_password>
gitlab_rails['db_host'] = '<database_host>'
- gitlab_rails['db_port'] = '5432'
+ gitlab_rails['db_port'] = 5432
gitlab_rails['db_password'] = '<database_password>'
## Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
@@ -257,7 +265,7 @@ To configure the metrics server:
```ruby
sidekiq['metrics_enabled'] = true
sidekiq['listen_address'] = "localhost"
- sidekiq['listen_port'] = "8082"
+ sidekiq['listen_port'] = 8082
# Optionally log all the metrics server logs to log/sidekiq_exporter.log
sidekiq['exporter_log_enabled'] = true
@@ -299,7 +307,7 @@ To make health checks available from `localhost:8092`:
```ruby
sidekiq['health_checks_enabled'] = true
sidekiq['health_checks_listen_address'] = "localhost"
- sidekiq['health_checks_listen_port'] = "8092"
+ sidekiq['health_checks_listen_port'] = 8092
```
1. Reconfigure GitLab:
@@ -325,7 +333,7 @@ To enable LDAP with the synchronization worker for Sidekiq:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
+ ```ruby
gitlab_rails['ldap_enabled'] = true
gitlab_rails['prevent_ldap_sign_in'] = false
gitlab_rails['ldap_servers'] = {
diff --git a/doc/administration/sidekiq/processing_specific_job_classes.md b/doc/administration/sidekiq/processing_specific_job_classes.md
index 61a154c8db2..0e4a0662277 100644
--- a/doc/administration/sidekiq/processing_specific_job_classes.md
+++ b/doc/administration/sidekiq/processing_specific_job_classes.md
@@ -17,7 +17,7 @@ job classes:
1. [Routing rules](#routing-rules) are used on GitLab.com. They direct jobs
inside the application to queue names configured by administrators. This
lowers the load on Redis, which is important on very large-scale deployments.
-1. [Queue selectors](#queue-selectors) perform the job selection outside the
+1. [Queue selectors](#queue-selectors-deprecated) perform the job selection outside the
application, when starting the Sidekiq process. This was used on GitLab.com
until September 2021, and is retained for compatibility reasons.
@@ -106,11 +106,19 @@ not a recommendation.
sudo gitlab-ctl reconfigure
```
-## Queue selectors
+<!--- start_remove The following content will be removed on remove_date: '2024-08-22' -->
+
+## Queue selectors (deprecated)
> - [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/45) in GitLab 12.8.
> - [Sidekiq cluster, including queue selector, moved](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/181) to GitLab Free in 12.10.
> - [Renamed from `experimental_queue_selector` to `queue_selector`](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/147) in GitLab 13.6.
+> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390787) in GitLab 15.9.
+
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390787) in GitLab 15.9
+and is planned for removal in 17.0. Most instances should have [all processes to listen to all queues](extra_sidekiq_processes.md#start-multiple-processes).
+Another alternative is to use [routing rules](#routing-rules) (be warned this is an advanced setting). This change is a breaking change.
The `queue_selector` option allows queue groups to be selected in a more general
way using a [worker matching query](#worker-matching-query). After
@@ -141,7 +149,12 @@ syntax.
sudo gitlab-ctl reconfigure
```
-### Negate settings
+### Negate settings (deprecated)
+
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390787) in GitLab 15.9
+and is planned for removal in 17.0. Most instances should have [all processes to listen to all queues](extra_sidekiq_processes.md#start-multiple-processes).
+Another alternative is to use [routing rules](#routing-rules) (be warned this is an advanced setting). This change is a breaking change.
This allows you to have the Sidekiq process work on every queue **except** the
ones you list. This is generally only used when there are multiple Sidekiq
@@ -168,7 +181,7 @@ nodes. In this example, we exclude all import-related jobs from a Sidekiq node.
We recommend GitLab deployments add more Sidekiq processes listening to all queues, as in the
[Reference Architectures](../reference_architectures/index.md). For very large-scale deployments, we recommend
-[routing rules](#routing-rules) instead of [queue selectors](#queue-selectors). We use routing rules on GitLab.com as
+[routing rules](#routing-rules) instead of [queue selectors](#queue-selectors-deprecated). We use routing rules on GitLab.com as
it helps to lower the load on Redis.
To migrate from queue selectors to routing rules:
@@ -255,11 +268,13 @@ in a queue group entry is 1, while `min_concurrency` is set to `0`, and `max_con
concurrency is set to `2` instead. A concurrency of `2` might be too low in most cases, except for very highly-CPU
bound tasks.
+<!--- end_remove -->
+
## Worker matching query
GitLab provides a query syntax to match a worker based on its attributes. This
query syntax is employed by both [routing rules](#routing-rules) and
-[queue selectors](#queue-selectors). A query includes two components:
+[queue selectors](#queue-selectors-deprecated). A query includes two components:
- Attributes that can be selected.
- Operators used to construct a query.
diff --git a/doc/administration/terraform_state.md b/doc/administration/terraform_state.md
index d3b941bd129..12d88c7c74a 100644
--- a/doc/administration/terraform_state.md
+++ b/doc/administration/terraform_state.md
@@ -22,9 +22,23 @@ Use [external object storage](https://docs.gitlab.com/charts/advanced/external-o
## Disabling Terraform state
-To disable terraform state site-wide, follow the steps below.
-A GitLab administrator may want to disable Terraform state to reduce disk space or if Terraform is not used in your instance.
-To do so, follow the steps below according to your installation's type.
+You can disable Terraform state across the entire instance. You might want to disable Terraform to reduce disk space,
+or because your instance doesn't use Terraform.
+
+When Terraform state administration is disabled:
+
+- On the left sidebar, you cannot select **Infrastructure > Terraform**.
+- Any CI/CD jobs that access the Terraform state fail with this error:
+
+ ```shell
+ Error refreshing state: HTTP remote state endpoint invalid auth
+ ```
+
+To disable Terraform administration, follow the steps below according to your installation.
+
+Prerequisite:
+
+- You must be an administrator.
**In Omnibus installations:**
@@ -79,7 +93,7 @@ Terraform state files are stored locally, follow the steps below.
## Using object storage **(FREE SELF)**
Instead of storing Terraform state files on disk, we recommend the use of
-[one of the supported object storage options](object_storage.md#options).
+[one of the supported object storage options](object_storage.md#supported-object-storage-providers).
This configuration relies on valid credentials to be configured already.
[Read more about using object storage with GitLab](object_storage.md).
diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md
index ff0b8ecf178..c4e2c352e9b 100644
--- a/doc/administration/uploads.md
+++ b/doc/administration/uploads.md
@@ -8,6 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Uploads represent all user data that may be sent to GitLab as a single file. For example, avatars and note attachments are uploads. Uploads are integral to GitLab functionality and therefore cannot be disabled.
+NOTE:
+Attachments added to comments or descriptions are deleted **only** when the parent project or group
+is deleted. Attachments remain in file storage even when the comment or resource (like issue, merge
+request, epic) where they were uploaded is deleted.
+
## Using local storage
This is the default configuration. To change the location where the uploads are
diff --git a/doc/api/audit_events.md b/doc/api/audit_events.md
index fec719b189c..f42ace8c1de 100644
--- a/doc/api/audit_events.md
+++ b/doc/api/audit_events.md
@@ -253,13 +253,16 @@ Example response:
## Project Audit Events
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/219238) in GitLab 13.1.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/219238) in GitLab 13.1.
+> - [Support for keyset pagination added](https://gitlab.com/gitlab-org/gitlab/-/issues/367528) in GitLab 15.10.
The Project Audit Events API allows you to retrieve [project audit events](../administration/audit_events.md#project-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.
+When requesting consecutive pages of results, you should use [keyset pagination](rest/index.md#keyset-based-pagination).
+
### Retrieve all project audit events
```plaintext
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 5a3481ee086..7c4d15e5d80 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -20,6 +20,8 @@ information:
## List repository commits
+> Commits by author [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114417) in GitLab 15.10.
+
Get a list of repository commits in a project.
```plaintext
@@ -33,6 +35,7 @@ GET /projects/:id/repository/commits
| `since` | string | no | Only commits after or on this date are returned in ISO 8601 format `YYYY-MM-DDTHH:MM:SSZ` |
| `until` | string | no | Only commits before or on this date are returned in ISO 8601 format `YYYY-MM-DDTHH:MM:SSZ` |
| `path` | string | no | The file path |
+| `author` | string | no | Search commits by commit author.|
| `all` | boolean | no | Retrieve every commit from the repository |
| `with_stats` | boolean | no | Stats about each commit are added to the response |
| `first_parent` | boolean | no | Follow only the first parent commit upon seeing a merge commit |
@@ -525,6 +528,11 @@ cases below is valid:
In any of the above cases, the response of `line`, `line_type` and `path` is
set to `null`.
+For other approaches to commenting on a merge request, see
+[Create new merge request note](notes.md#create-new-merge-request-note) in the Notes API,
+and [Create a new thread in the merge request diff](discussions.md#create-a-new-thread-in-the-merge-request-diff)
+in the Discussions API.
+
```plaintext
POST /projects/:id/repository/commits/:sha/comments
```
diff --git a/doc/api/deploy_keys.md b/doc/api/deploy_keys.md
index 684df9fdfdc..9b02f30b7ee 100644
--- a/doc/api/deploy_keys.md
+++ b/doc/api/deploy_keys.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/deploy_tokens.md b/doc/api/deploy_tokens.md
index 2cfb58c25e1..0b7ea13c341 100644
--- a/doc/api/deploy_tokens.md
+++ b/doc/api/deploy_tokens.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/deployments.md b/doc/api/deployments.md
index c6537493eab..eb718d80b78 100644
--- a/doc/api/deployments.md
+++ b/doc/api/deployments.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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, howto
---
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index ccef57dab7f..925d3ae6c9b 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -65,6 +65,7 @@ GET /projects/:id/issues/:issue_iid/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Issue",
+ "project_id": 5,
"noteable_iid": null
},
{
@@ -85,6 +86,7 @@ GET /projects/:id/issues/:issue_iid/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Issue",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
}
@@ -112,6 +114,7 @@ GET /projects/:id/issues/:issue_iid/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Issue",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
}
@@ -279,6 +282,7 @@ GET /projects/:id/snippets/:snippet_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Snippet",
+ "project_id": 5,
"noteable_iid": null
},
{
@@ -299,6 +303,7 @@ GET /projects/:id/snippets/:snippet_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Snippet",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
}
@@ -326,6 +331,7 @@ GET /projects/:id/snippets/:snippet_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Snippet",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
}
@@ -491,6 +497,7 @@ GET /groups/:id/epics/:epic_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Epic",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
},
@@ -512,6 +519,7 @@ GET /groups/:id/epics/:epic_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Epic",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
}
@@ -539,6 +547,7 @@ GET /groups/:id/epics/:epic_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Epic",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
}
@@ -705,6 +714,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Merge request",
+ "project_id": 5,
"noteable_iid": null,
"resolved": false,
"resolvable": true,
@@ -729,6 +739,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Merge request",
+ "project_id": 5,
"noteable_iid": null,
"resolved": false,
"resolvable": true,
@@ -758,6 +769,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Merge request",
+ "project_id": 5,
"noteable_iid": null,
"resolved": false,
"resolvable": true,
@@ -794,6 +806,7 @@ Diff comments also contain position:
"system": false,
"noteable_id": 3,
"noteable_type": "Merge request",
+ "project_id": 5,
"noteable_iid": null,
"commit_id": "4803c71e6b1833ca72b8b26ef2ecd5adc8a38031",
"position": {
@@ -856,7 +869,9 @@ curl --header "PRIVATE-TOKEN: <your_access_token>"\
> The `commit id` entry was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47130) in GitLab 13.7.
Creates a new thread to a single project merge request. This is similar to creating
-a note but other comments (replies) can be added to it later.
+a note but other comments (replies) can be added to it later. For other approaches,
+see [Post comment to commit](commits.md#post-comment-to-commit) in the Commits API,
+and [Create new merge request note](notes.md#create-new-merge-request-note) in the Notes API.
```plaintext
POST /projects/:id/merge_requests/:merge_request_iid/discussions
@@ -1135,6 +1150,7 @@ GET /projects/:id/repository/commits/:commit_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Commit",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
},
@@ -1156,6 +1172,7 @@ GET /projects/:id/repository/commits/:commit_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Commit",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
}
@@ -1183,6 +1200,7 @@ GET /projects/:id/repository/commits/:commit_id/discussions
"system": false,
"noteable_id": 3,
"noteable_type": "Commit",
+ "project_id": 5,
"noteable_iid": null,
"resolvable": false
}
@@ -1217,6 +1235,7 @@ Diff comments contain also position:
"system": false,
"noteable_id": 3,
"noteable_type": "Commit",
+ "project_id": 5,
"noteable_iid": null,
"position": {
"base_sha": "b5d6e7b1613fca24d250fa8e5bc7bcc3dd6002ef",
diff --git a/doc/api/dora/metrics.md b/doc/api/dora/metrics.md
index f0e90234ff4..a3865213714 100644
--- a/doc/api/dora/metrics.md
+++ b/doc/api/dora/metrics.md
@@ -101,8 +101,8 @@ parameter:
| `metric` query parameter | Description of `value` in response |
|:---------------------------|:-----------------------------------|
+| `deployment_frequency` | The API returns the total number of successful deployments during the time period. [Issue 371271](https://gitlab.com/gitlab-org/gitlab/-/issues/371271) proposes to update the API to return the daily average instead of the total number. |
| `change_failure_rate` | The number of incidents divided by the number of deployments during the time period. Available only for production environment. |
-| `deployment_frequency` | The number of successful deployments during the time period. |
| `lead_time_for_changes` | The median number of seconds between the merge of the merge request (MR) and the deployment of the MR commits for all MRs deployed during the time period. |
| `time_to_restore_service` | The median number of seconds an incident was open during the time period. Available only for production environment. |
diff --git a/doc/api/draft_notes.md b/doc/api/draft_notes.md
index a168c41092c..079b08781ae 100644
--- a/doc/api/draft_notes.md
+++ b/doc/api/draft_notes.md
@@ -94,6 +94,46 @@ GET /projects/:id/merge_requests/:merge_request_iid/draft_notes/:draft_note_id
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/14/merge_requests/11/draft_notes/5"
```
+## Create a draft note
+
+Create a draft note for a given merge request.
+
+```plaintext
+POST /projects/:id/merge_requests/:merge_request_iid/draft_notes
+```
+
+| Attribute | Type | Required | Description |
+| --------------------------- | ----------------- | ----------- | --------------------- |
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding).
+| `merge_request_iid` | integer | yes | The IID of a project merge request.
+| `note` | string | yes | The content of a note.
+| `commit_id` | string | no | The SHA of a commit to associate the draft note to.
+| `in_reply_to_discussion_id` | integer | no | The ID of a discussion the draft note replies to.
+| `resolve_discussion` | boolean | no | The associated discussion should be resolved.
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/14/merge_requests/11/draft_notes?note=note
+```
+
+## Modify existing draft note
+
+Modify a draft note for a given merge request.
+
+```plaintext
+PUT /projects/:id/merge_requests/:merge_request_iid/draft_notes/:draft_note_id
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ----------------- | ----------- | --------------------- |
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding).
+| `draft_note_id` | integer | yes | The ID of a draft note.
+| `merge_request_iid` | integer | yes | The IID of a project merge request.
+| `note` | string | no | The content of a note.
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/14/merge_requests/11/draft_notes/5"
+```
+
## Delete a draft note
Deletes an existing draft note for a given merge request.
diff --git a/doc/api/environments.md b/doc/api/environments.md
index bbf6c5fee99..2bd7b28d0d0 100644
--- a/doc/api/environments.md
+++ b/doc/api/environments.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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, howto
---
diff --git a/doc/api/error_tracking.md b/doc/api/error_tracking.md
index 36bcbb30d4b..3515b080b12 100644
--- a/doc/api/error_tracking.md
+++ b/doc/api/error_tracking.md
@@ -39,6 +39,45 @@ Example response:
}
```
+### Create Error Tracking settings
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393035/) in GitLab 15.10.
+The API allows you to create Error Tracking settings for a project. Only for users with Maintainer role for
+the project.
+
+NOTE:
+This API is only available when used with [integrated error tracking](../operations/error_tracking.md#integrated-error-tracking).
+
+```plaintext
+PUT /projects/:id/error_tracking/settings
+```
+
+Supported attributes:
+
+| Attribute | Type | Required | Description |
+| ------------ | ------- |----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `id` | integer | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `active` | boolean | yes | Pass `true` to enable the error tracking setting configuration or `false` to disable it. |
+| `integrated` | boolean | yes | Pass `true` to enable the integrated error tracking backend. [Available in](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68260) GitLab 14.2 and later. |
+
+Example request:
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/error_tracking/settings?active=true&integrated=true"
+```
+
+Example response:
+
+```json
+{
+ "active": true,
+ "project_name": null,
+ "sentry_external_url": null,
+ "api_url": null,
+ "integrated": true
+}
+```
+
### Enable or disable the Error Tracking project settings
The API allows you to enable or disable the Error Tracking settings for a project. Only for users with the
@@ -55,7 +94,7 @@ PATCH /projects/:id/error_tracking/settings
| `integrated` | boolean | no | Pass `true` to enable the integrated error tracking backend. [Available in](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68260) GitLab 14.2 and later. |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/error_tracking/settings?active=true"
+curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/error_tracking/settings?active=true"
```
Example response:
diff --git a/doc/api/feature_flag_specs.md b/doc/api/feature_flag_specs.md
deleted file mode 100644
index 960d00278d6..00000000000
--- a/doc/api/feature_flag_specs.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-stage: Release
-group: Release
-info: To 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-02-14'
-redirect_to: 'feature_flags.md'
----
-
-# Feature Flag Specs API (removed) **(PREMIUM)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in GitLab 12.5.
-
-This API was removed in [GitLab 14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/213369).
-Use [the new API](feature_flags.md) instead.
diff --git a/doc/api/feature_flag_user_lists.md b/doc/api/feature_flag_user_lists.md
index 27e2e925506..0d48f8daf40 100644
--- a/doc/api/feature_flag_user_lists.md
+++ b/doc/api/feature_flag_user_lists.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/feature_flags.md b/doc/api/feature_flags.md
index cd9907c8032..f62d51ea427 100644
--- a/doc/api/feature_flags.md
+++ b/doc/api/feature_flags.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/features.md b/doc/api/features.md
index c3db1e53f68..2b0bf656664 100644
--- a/doc/api/features.md
+++ b/doc/api/features.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/freeze_periods.md b/doc/api/freeze_periods.md
index ce7377e1e35..cb9bf81e961 100644
--- a/doc/api/freeze_periods.md
+++ b/doc/api/freeze_periods.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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, howto
---
diff --git a/doc/api/geo_nodes.md b/doc/api/geo_nodes.md
index 0b0dd543503..ed413c358de 100644
--- a/doc/api/geo_nodes.md
+++ b/doc/api/geo_nodes.md
@@ -520,6 +520,13 @@ Example response:
"container_repositories_registry_count": 5,
"container_repositories_synced_in_percentage": "100.00%",
"container_repositories_synced_missing_on_primary_count": 0,
+ "container_repositories_checksum_total_count": 0,
+ "container_repositories_checksummed_count": 0,
+ "container_repositories_checksum_failed_count": 0,
+ "container_repositories_verification_total_count": 0,
+ "container_repositories_verified_count": 0,
+ "container_repositories_verification_failed_count": 0,
+ "container_repositories_verified_in_percentage": "100.00%",
"dependency_proxy_manifests_count": 5,
"dependency_proxy_manifests_checksum_total_count": 5,
"dependency_proxy_manifests_checksummed_count": 5,
@@ -716,6 +723,13 @@ Example response:
"container_repositories_registry_count": 5,
"container_repositories_synced_in_percentage": "100.00%",
"container_repositories_synced_missing_on_primary_count": 0,
+ "container_repositories_checksum_total_count": 0,
+ "container_repositories_checksummed_count": 0,
+ "container_repositories_checksum_failed_count": 0,
+ "container_repositories_verification_total_count": 0,
+ "container_repositories_verified_count": 0,
+ "container_repositories_verification_failed_count": 0,
+ "container_repositories_verified_in_percentage": "100.00%",
"dependency_proxy_manifests_count": 5,
"dependency_proxy_manifests_checksum_total_count": 5,
"dependency_proxy_manifests_checksummed_count": 5,
@@ -922,6 +936,13 @@ Example response:
"container_repositories_registry_count": 5,
"container_repositories_synced_in_percentage": "100.00%",
"container_repositories_synced_missing_on_primary_count": 0,
+ "container_repositories_checksum_total_count": 0,
+ "container_repositories_checksummed_count": 0,
+ "container_repositories_checksum_failed_count": 0,
+ "container_repositories_verification_total_count": 0,
+ "container_repositories_verified_count": 0,
+ "container_repositories_verification_failed_count": 0,
+ "container_repositories_verified_in_percentage": "100.00%",
"dependency_proxy_manifests_count": 5,
"dependency_proxy_manifests_checksum_total_count": 5,
"dependency_proxy_manifests_checksummed_count": 5,
diff --git a/doc/api/graphql/getting_started.md b/doc/api/graphql/getting_started.md
index 57d7880988b..df1b1cdca7c 100644
--- a/doc/api/graphql/getting_started.md
+++ b/doc/api/graphql/getting_started.md
@@ -16,9 +16,9 @@ the API itself.
The examples documented here can be run using:
-- The command line.
-- GraphiQL.
-- Rails console.
+- [Command line](#command-line).
+- [GraphiQL](#graphiql).
+- [Rails console](#rails-console).
### Command line
@@ -79,6 +79,7 @@ If you are running GitLab 12.0, enable the `graphql`
GraphQL queries can be run in a [Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session). For example, to search projects:
```ruby
+current_user = User.find_by_id(1)
query = <<~EOQ
query securityGetProjects($search: String!) {
projects(search: $search) {
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 7dc5b557d33..27da9f2b653 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -745,8 +745,36 @@ mutation($id: NoteableID!, $body: String!) {
}
```
+### `Mutation.achievementsAward`
+
+WARNING:
+**Introduced** in 15.10.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Input type: `AchievementsAwardInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationachievementsawardachievementid"></a>`achievementId` | [`AchievementsAchievementID!`](#achievementsachievementid) | Global ID of the achievement being awarded. |
+| <a id="mutationachievementsawardclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationachievementsawarduserid"></a>`userId` | [`UserID!`](#userid) | Global ID of the user being awarded the achievement. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationachievementsawardclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationachievementsawarderrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationachievementsawarduserachievement"></a>`userAchievement` | [`UserAchievement`](#userachievement) | Achievement award. |
+
### `Mutation.achievementsCreate`
+WARNING:
+**Introduced** in 15.8.
+This feature is in Alpha. It can be changed or removed at any time.
+
Input type: `AchievementsCreateInput`
#### Arguments
@@ -767,6 +795,29 @@ Input type: `AchievementsCreateInput`
| <a id="mutationachievementscreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationachievementscreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+### `Mutation.achievementsRevoke`
+
+WARNING:
+**Introduced** in 15.10.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Input type: `AchievementsRevokeInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationachievementsrevokeclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationachievementsrevokeuserachievementid"></a>`userAchievementId` | [`AchievementsUserAchievementID!`](#achievementsuserachievementid) | Global ID of the user achievement being revoked. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationachievementsrevokeclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationachievementsrevokeerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationachievementsrevokeuserachievement"></a>`userAchievement` | [`UserAchievement`](#userachievement) | Achievement award. |
+
### `Mutation.addProjectToSecurityDashboard`
Input type: `AddProjectToSecurityDashboardInput`
@@ -1168,6 +1219,31 @@ Input type: `BoardListUpdateLimitMetricsInput`
| <a id="mutationboardlistupdatelimitmetricserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationboardlistupdatelimitmetricslist"></a>`list` | [`BoardList`](#boardlist) | Updated list. |
+### `Mutation.bulkDestroyJobArtifacts`
+
+WARNING:
+**Introduced** in 15.10.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Input type: `BulkDestroyJobArtifactsInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationbulkdestroyjobartifactsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationbulkdestroyjobartifactsids"></a>`ids` | [`[CiJobArtifactID!]!`](#cijobartifactid) | Global IDs of the job artifacts to destroy. |
+| <a id="mutationbulkdestroyjobartifactsprojectid"></a>`projectId` | [`ProjectID!`](#projectid) | Global Project ID of the job artifacts to destroy. Incompatible with projectPath. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationbulkdestroyjobartifactsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationbulkdestroyjobartifactsdestroyedcount"></a>`destroyedCount` | [`Int`](#int) | Number of job artifacts deleted. |
+| <a id="mutationbulkdestroyjobartifactsdestroyedids"></a>`destroyedIds` | [`[CiJobArtifactID!]`](#cijobartifactid) | IDs of job artifacts that were deleted. |
+| <a id="mutationbulkdestroyjobartifactserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.bulkEnableDevopsAdoptionNamespaces`
**BETA** This endpoint is subject to change without notice.
@@ -2401,6 +2477,26 @@ Input type: `DesignManagementMoveInput`
| <a id="mutationdesignmanagementmovedesigncollection"></a>`designCollection` | [`DesignCollection`](#designcollection) | Current state of the collection. |
| <a id="mutationdesignmanagementmoveerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+### `Mutation.designManagementUpdate`
+
+Input type: `DesignManagementUpdateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationdesignmanagementupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationdesignmanagementupdatedescription"></a>`description` | [`String`](#string) | Description of the design. |
+| <a id="mutationdesignmanagementupdateid"></a>`id` | [`DesignManagementDesignID!`](#designmanagementdesignid) | ID of the design to update. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationdesignmanagementupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationdesignmanagementupdatedesign"></a>`design` | [`Design!`](#design) | Updated design. |
+| <a id="mutationdesignmanagementupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.designManagementUpload`
Input type: `DesignManagementUploadInput`
@@ -3136,7 +3232,7 @@ Input type: `GroupMemberBulkUpdateInput`
| <a id="mutationgroupmemberbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationgroupmemberbulkupdateexpiresat"></a>`expiresAt` | [`Time`](#time) | Date and time the membership expires. |
| <a id="mutationgroupmemberbulkupdategroupid"></a>`groupId` | [`GroupID!`](#groupid) | Global ID of the group. |
-| <a id="mutationgroupmemberbulkupdateuserids"></a>`userIds` | [`[UserID!]!`](#userid) | Global IDs of the group members. |
+| <a id="mutationgroupmemberbulkupdateuserids"></a>`userIds` | [`[UserID!]!`](#userid) | Global IDs of the members. |
#### Fields
@@ -3649,12 +3745,18 @@ Input type: `IssuesBulkUpdateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="mutationissuesbulkupdateaddlabelids"></a>`addLabelIds` | [`[LabelID!]`](#labelid) | Global ID array of the labels that will be added to the issues. |
| <a id="mutationissuesbulkupdateassigneeids"></a>`assigneeIds` | [`[UserID!]`](#userid) | Global ID array of the users that will be assigned to the given issues. Existing assignees will be replaced with the ones on this list. |
| <a id="mutationissuesbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationissuesbulkupdateepicid"></a>`epicId` | [`EpicID`](#epicid) | Global ID of the epic that will be assigned to the issues. |
+| <a id="mutationissuesbulkupdatehealthstatus"></a>`healthStatus` | [`HealthStatus`](#healthstatus) | Health status that will be assigned to the issues. |
| <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 that the bulk update will be scoped to . 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)** or a group **(PREMIUM)**. 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. |
#### Fields
@@ -4215,6 +4317,32 @@ Input type: `MergeRequestUpdateInput`
| <a id="mutationmergerequestupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationmergerequestupdatemergerequest"></a>`mergeRequest` | [`MergeRequest`](#mergerequest) | Merge request after mutation. |
+### `Mutation.mergeRequestUpdateApprovalRule`
+
+Input type: `MergeRequestUpdateApprovalRuleInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationmergerequestupdateapprovalruleapprovalruleid"></a>`approvalRuleId` | [`Int!`](#int) | ID of an approval rule. |
+| <a id="mutationmergerequestupdateapprovalruleapprovalsrequired"></a>`approvalsRequired` | [`Int!`](#int) | Number of required approvals for a given rule. |
+| <a id="mutationmergerequestupdateapprovalruleclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationmergerequestupdateapprovalrulegroupids"></a>`groupIds` | [`[String!]`](#string) | IDs of groups as approvers. |
+| <a id="mutationmergerequestupdateapprovalruleiid"></a>`iid` | [`String!`](#string) | IID of the merge request to mutate. |
+| <a id="mutationmergerequestupdateapprovalrulename"></a>`name` | [`String!`](#string) | Name of the approval rule. |
+| <a id="mutationmergerequestupdateapprovalruleprojectpath"></a>`projectPath` | [`ID!`](#id) | Project the merge request to mutate is in. |
+| <a id="mutationmergerequestupdateapprovalruleremovehiddengroups"></a>`removeHiddenGroups` | [`[Boolean!]`](#boolean) | Whether hidden groups should be removed. |
+| <a id="mutationmergerequestupdateapprovalruleuserids"></a>`userIds` | [`[String!]`](#string) | IDs of users as approvers. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationmergerequestupdateapprovalruleclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationmergerequestupdateapprovalruleerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationmergerequestupdateapprovalrulemergerequest"></a>`mergeRequest` | [`MergeRequest`](#mergerequest) | Merge request after mutation. |
+
### `Mutation.namespaceBanDestroy`
Input type: `NamespaceBanDestroyInput`
@@ -4634,6 +4762,28 @@ Input type: `ProjectInitializeProductAnalyticsInput`
| <a id="mutationprojectinitializeproductanalyticserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationprojectinitializeproductanalyticsproject"></a>`project` | [`Project`](#project) | Project on which the initialization took place. |
+### `Mutation.projectMemberBulkUpdate`
+
+Input type: `ProjectMemberBulkUpdateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationprojectmemberbulkupdateaccesslevel"></a>`accessLevel` | [`MemberAccessLevel!`](#memberaccesslevel) | Access level to update the members to. |
+| <a id="mutationprojectmemberbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationprojectmemberbulkupdateexpiresat"></a>`expiresAt` | [`Time`](#time) | Date and time the membership expires. |
+| <a id="mutationprojectmemberbulkupdateprojectid"></a>`projectId` | [`ProjectID!`](#projectid) | Global ID of the project. |
+| <a id="mutationprojectmemberbulkupdateuserids"></a>`userIds` | [`[UserID!]!`](#userid) | Global IDs of the members. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationprojectmemberbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationprojectmemberbulkupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationprojectmemberbulkupdateprojectmembers"></a>`projectMembers` | [`[ProjectMember!]`](#projectmember) | Project members after mutation. |
+
### `Mutation.projectSetComplianceFramework`
Assign (or unset) a compliance framework to a project.
@@ -4677,6 +4827,30 @@ Input type: `ProjectSetLockedInput`
| <a id="mutationprojectsetlockederrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationprojectsetlockedproject"></a>`project` | [`Project`](#project) | Project after mutation. |
+### `Mutation.projectSyncFork`
+
+WARNING:
+**Introduced** in 15.9.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Input type: `ProjectSyncForkInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationprojectsyncforkclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationprojectsyncforkprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project to initialize. |
+| <a id="mutationprojectsyncforktargetbranch"></a>`targetBranch` | [`String!`](#string) | Ref of the fork to fetch into. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationprojectsyncforkclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationprojectsyncforkdetails"></a>`details` | [`ForkDetails`](#forkdetails) | Updated fork details. |
+| <a id="mutationprojectsyncforkerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.prometheusIntegrationCreate`
Input type: `PrometheusIntegrationCreateInput`
@@ -4937,6 +5111,37 @@ Input type: `RepositionImageDiffNoteInput`
| <a id="mutationrepositionimagediffnoteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationrepositionimagediffnotenote"></a>`note` | [`Note`](#note) | Note after mutation. |
+### `Mutation.runnerCreate`
+
+WARNING:
+**Introduced** in 15.10.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Input type: `RunnerCreateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationrunnercreateaccesslevel"></a>`accessLevel` | [`CiRunnerAccessLevel`](#cirunneraccesslevel) | Access level of the runner. |
+| <a id="mutationrunnercreateassociatedprojects"></a>`associatedProjects` | [`[ProjectID!]`](#projectid) | Projects associated with the runner. Available only for project runners. |
+| <a id="mutationrunnercreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationrunnercreatedescription"></a>`description` | [`String`](#string) | Description of the runner. |
+| <a id="mutationrunnercreatelocked"></a>`locked` | [`Boolean`](#boolean) | Indicates the runner is locked. |
+| <a id="mutationrunnercreatemaintenancenote"></a>`maintenanceNote` | [`String`](#string) | Runner's maintenance notes. |
+| <a id="mutationrunnercreatemaximumtimeout"></a>`maximumTimeout` | [`Int`](#int) | Maximum timeout (in seconds) for jobs processed by the runner. |
+| <a id="mutationrunnercreatepaused"></a>`paused` | [`Boolean`](#boolean) | Indicates the runner is not allowed to receive jobs. |
+| <a id="mutationrunnercreaterununtagged"></a>`runUntagged` | [`Boolean`](#boolean) | Indicates the runner is able to run untagged jobs. |
+| <a id="mutationrunnercreatetaglist"></a>`tagList` | [`[String!]`](#string) | Tags associated with the runner. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationrunnercreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationrunnercreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationrunnercreaterunner"></a>`runner` | [`CiRunner`](#cirunner) | Runner after mutation. |
+
### `Mutation.runnerDelete`
Input type: `RunnerDeleteInput`
@@ -5130,6 +5335,7 @@ Input type: `SecurityFindingDismissInput`
| ---- | ---- | ----------- |
| <a id="mutationsecurityfindingdismissclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationsecurityfindingdismisserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationsecurityfindingdismisssecurityfinding"></a>`securityFinding` | [`PipelineSecurityReportFinding`](#pipelinesecurityreportfinding) | Dismissed finding. |
| <a id="mutationsecurityfindingdismissuuid"></a>`uuid` | [`String`](#string) | UUID of dismissed finding. |
### `Mutation.securityFindingRevertToDetected`
@@ -6049,6 +6255,7 @@ Input type: `VulnerabilityConfirmInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationvulnerabilityconfirmclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationvulnerabilityconfirmcomment"></a>`comment` | [`String`](#string) | Comment why vulnerability was marked as confirmed (max. 50 000 characters). |
| <a id="mutationvulnerabilityconfirmid"></a>`id` | [`VulnerabilityID!`](#vulnerabilityid) | ID of the vulnerability to be confirmed. |
#### Fields
@@ -6186,6 +6393,7 @@ Input type: `VulnerabilityResolveInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationvulnerabilityresolveclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationvulnerabilityresolvecomment"></a>`comment` | [`String`](#string) | Comment why vulnerability was reverted to detected (max. 50 000 characters). |
| <a id="mutationvulnerabilityresolveid"></a>`id` | [`VulnerabilityID!`](#vulnerabilityid) | ID of the vulnerability to be resolved. |
#### Fields
@@ -6205,6 +6413,7 @@ Input type: `VulnerabilityRevertToDetectedInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationvulnerabilityreverttodetectedclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationvulnerabilityreverttodetectedcomment"></a>`comment` | [`String`](#string) | Comment why vulnerability was reverted to detected (max. 50 000 characters). |
| <a id="mutationvulnerabilityreverttodetectedid"></a>`id` | [`VulnerabilityID!`](#vulnerabilityid) | ID of the vulnerability to be reverted. |
#### Fields
@@ -6326,6 +6535,35 @@ Input type: `WorkItemDeleteTaskInput`
| <a id="mutationworkitemdeletetaskerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationworkitemdeletetaskworkitem"></a>`workItem` | [`WorkItem`](#workitem) | Updated work item. |
+### `Mutation.workItemExport`
+
+WARNING:
+**Introduced** in 15.10.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Input type: `WorkItemExportInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationworkitemexportauthorusername"></a>`authorUsername` **{warning-solid}** | [`String`](#string) | **Deprecated:** This feature is in Alpha. It can be changed or removed at any time. Introduced in 15.9. |
+| <a id="mutationworkitemexportclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationworkitemexportiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of work items. For example, `["1", "2"]`. |
+| <a id="mutationworkitemexportin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
+| <a id="mutationworkitemexportprojectpath"></a>`projectPath` | [`ID!`](#id) | Full project path. |
+| <a id="mutationworkitemexportsearch"></a>`search` | [`String`](#string) | Search query for title or description. |
+| <a id="mutationworkitemexportselectedfields"></a>`selectedFields` | [`[AvailableExportFields!]`](#availableexportfields) | List of selected fields to be exported. Omit to export all available fields. |
+| <a id="mutationworkitemexportstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of the work item. |
+| <a id="mutationworkitemexporttypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationworkitemexportclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationworkitemexporterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.workItemUpdate`
Updates a work item by Global ID.
@@ -6350,6 +6588,7 @@ Input type: `WorkItemUpdateInput`
| <a id="mutationworkitemupdateiterationwidget"></a>`iterationWidget` | [`WorkItemWidgetIterationInput`](#workitemwidgetiterationinput) | Input for iteration widget. |
| <a id="mutationworkitemupdatelabelswidget"></a>`labelsWidget` | [`WorkItemWidgetLabelsUpdateInput`](#workitemwidgetlabelsupdateinput) | Input for labels widget. |
| <a id="mutationworkitemupdatemilestonewidget"></a>`milestoneWidget` | [`WorkItemWidgetMilestoneInput`](#workitemwidgetmilestoneinput) | Input for milestone widget. |
+| <a id="mutationworkitemupdatenotificationswidget"></a>`notificationsWidget` | [`WorkItemWidgetNotificationsUpdateInput`](#workitemwidgetnotificationsupdateinput) | Input for notifications widget. |
| <a id="mutationworkitemupdateprogresswidget"></a>`progressWidget` | [`WorkItemWidgetProgressInput`](#workitemwidgetprogressinput) | Input for progress widget. |
| <a id="mutationworkitemupdatestartandduedatewidget"></a>`startAndDueDateWidget` | [`WorkItemWidgetStartAndDueDateUpdateInput`](#workitemwidgetstartandduedateupdateinput) | Input for start and due date widget. |
| <a id="mutationworkitemupdatestateevent"></a>`stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. |
@@ -7096,6 +7335,30 @@ The edge type for [`CiRunner`](#cirunner).
| <a id="cirunneredgenode"></a>`node` | [`CiRunner`](#cirunner) | The item at the end of the edge. |
| <a id="cirunneredgeweburl"></a>`webUrl` | [`String`](#string) | Web URL of the runner. The value depends on where you put this field in the query. You can use it for projects or groups. |
+#### `CiRunnerMachineConnection`
+
+The connection type for [`CiRunnerMachine`](#cirunnermachine).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cirunnermachineconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. |
+| <a id="cirunnermachineconnectionedges"></a>`edges` | [`[CiRunnerMachineEdge]`](#cirunnermachineedge) | A list of edges. |
+| <a id="cirunnermachineconnectionnodes"></a>`nodes` | [`[CiRunnerMachine]`](#cirunnermachine) | A list of nodes. |
+| <a id="cirunnermachineconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `CiRunnerMachineEdge`
+
+The edge type for [`CiRunnerMachine`](#cirunnermachine).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cirunnermachineedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="cirunnermachineedgenode"></a>`node` | [`CiRunnerMachine`](#cirunnermachine) | The item at the end of the edge. |
+
#### `CiSecureFileRegistryConnection`
The connection type for [`CiSecureFileRegistry`](#cisecurefileregistry).
@@ -7630,6 +7893,29 @@ The edge type for [`DastSiteValidation`](#dastsitevalidation).
| <a id="dastsitevalidationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="dastsitevalidationedgenode"></a>`node` | [`DastSiteValidation`](#dastsitevalidation) | The item at the end of the edge. |
+#### `DependencyConnection`
+
+The connection type for [`Dependency`](#dependency).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="dependencyconnectionedges"></a>`edges` | [`[DependencyEdge]`](#dependencyedge) | A list of edges. |
+| <a id="dependencyconnectionnodes"></a>`nodes` | [`[Dependency]`](#dependency) | A list of nodes. |
+| <a id="dependencyconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `DependencyEdge`
+
+The edge type for [`Dependency`](#dependency).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="dependencyedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="dependencyedgenode"></a>`node` | [`Dependency`](#dependency) | The item at the end of the edge. |
+
#### `DependencyProxyBlobConnection`
The connection type for [`DependencyProxyBlob`](#dependencyproxyblob).
@@ -10273,6 +10559,29 @@ The edge type for [`UsageTrendsMeasurement`](#usagetrendsmeasurement).
| <a id="usagetrendsmeasurementedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="usagetrendsmeasurementedgenode"></a>`node` | [`UsageTrendsMeasurement`](#usagetrendsmeasurement) | The item at the end of the edge. |
+#### `UserAchievementConnection`
+
+The connection type for [`UserAchievement`](#userachievement).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="userachievementconnectionedges"></a>`edges` | [`[UserAchievementEdge]`](#userachievementedge) | A list of edges. |
+| <a id="userachievementconnectionnodes"></a>`nodes` | [`[UserAchievement]`](#userachievement) | A list of nodes. |
+| <a id="userachievementconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `UserAchievementEdge`
+
+The edge type for [`UserAchievement`](#userachievement).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <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. |
+
#### `UserCalloutConnection`
The connection type for [`UserCallout`](#usercallout).
@@ -10457,6 +10766,29 @@ The edge type for [`VulnerabilityScanner`](#vulnerabilityscanner).
| <a id="vulnerabilityscanneredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="vulnerabilityscanneredgenode"></a>`node` | [`VulnerabilityScanner`](#vulnerabilityscanner) | The item at the end of the edge. |
+#### `VulnerabilityStateTransitionTypeConnection`
+
+The connection type for [`VulnerabilityStateTransitionType`](#vulnerabilitystatetransitiontype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="vulnerabilitystatetransitiontypeconnectionedges"></a>`edges` | [`[VulnerabilityStateTransitionTypeEdge]`](#vulnerabilitystatetransitiontypeedge) | A list of edges. |
+| <a id="vulnerabilitystatetransitiontypeconnectionnodes"></a>`nodes` | [`[VulnerabilityStateTransitionType]`](#vulnerabilitystatetransitiontype) | A list of nodes. |
+| <a id="vulnerabilitystatetransitiontypeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `VulnerabilityStateTransitionTypeEdge`
+
+The edge type for [`VulnerabilityStateTransitionType`](#vulnerabilitystatetransitiontype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="vulnerabilitystatetransitiontypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="vulnerabilitystatetransitiontypeedgenode"></a>`node` | [`VulnerabilityStateTransitionType`](#vulnerabilitystatetransitiontype) | The item at the end of the edge. |
+
#### `WorkItemConnection`
The connection type for [`WorkItem`](#workitem).
@@ -10570,6 +10902,7 @@ Representation of a GitLab user.
| <a id="achievementname"></a>`name` | [`String!`](#string) | Name of the achievement. |
| <a id="achievementnamespace"></a>`namespace` | [`Namespace!`](#namespace) | Namespace of the achievement. |
| <a id="achievementupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp the achievement was last updated. |
+| <a id="achievementuserachievements"></a>`userAchievements` **{warning-solid}** | [`UserAchievementConnection`](#userachievementconnection) | **Introduced** in 15.10. This feature is in Alpha. It can be changed or removed at any time. Recipients for the achievement. |
### `AgentConfiguration`
@@ -11390,6 +11723,7 @@ CI/CD variables for a GitLab instance.
| <a id="cijoballowfailure"></a>`allowFailure` | [`Boolean!`](#boolean) | Whether the job is allowed to fail. |
| <a id="cijobartifacts"></a>`artifacts` | [`CiJobArtifactConnection`](#cijobartifactconnection) | Artifacts generated by the job. (see [Connections](#connections)) |
| <a id="cijobbrowseartifactspath"></a>`browseArtifactsPath` | [`String`](#string) | URL for browsing the artifact's archive. |
+| <a id="cijobcanplayjob"></a>`canPlayJob` | [`Boolean!`](#boolean) | Indicates whether the current user can play the job. |
| <a id="cijobcancelable"></a>`cancelable` | [`Boolean!`](#boolean) | Indicates the job can be canceled. |
| <a id="cijobcommitpath"></a>`commitPath` | [`String`](#string) | Path to the commit that triggered the job. |
| <a id="cijobcoverage"></a>`coverage` | [`Float`](#float) | Coverage level of the job. |
@@ -11407,6 +11741,7 @@ CI/CD variables for a GitLab instance.
| <a id="cijobname"></a>`name` | [`String`](#string) | Name of the job. |
| <a id="cijobneeds"></a>`needs` | [`CiBuildNeedConnection`](#cibuildneedconnection) | References to builds that must complete before the jobs run. (see [Connections](#connections)) |
| <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="cijobproject"></a>`project` | [`Project`](#project) | Project that the job belongs to. |
@@ -11416,6 +11751,8 @@ CI/CD variables for a GitLab instance.
| <a id="cijobrefpath"></a>`refPath` | [`String`](#string) | Path to the ref. |
| <a id="cijobretried"></a>`retried` | [`Boolean`](#boolean) | Indicates that the job has been retried. |
| <a id="cijobretryable"></a>`retryable` | [`Boolean!`](#boolean) | Indicates the job can be retried. |
+| <a id="cijobrunnermachine"></a>`runnerMachine` **{warning-solid}** | [`CiRunnerMachine`](#cirunnermachine) | **Introduced** in 15.11. This feature is in Alpha. It can be changed or removed at any time. Runner machine assigned to the job. |
+| <a id="cijobscheduled"></a>`scheduled` | [`Boolean!`](#boolean) | Indicates the job is scheduled. |
| <a id="cijobscheduledat"></a>`scheduledAt` | [`Time`](#time) | Schedule for the build. |
| <a id="cijobschedulingtype"></a>`schedulingType` | [`String`](#string) | Type of job scheduling. Value is `dag` if the job uses the `needs` keyword, and `stage` otherwise. |
| <a id="cijobshortsha"></a>`shortSha` | [`String!`](#string) | Short SHA1 ID of the commit. |
@@ -11542,9 +11879,10 @@ CI/CD variables for a project.
| <a id="cirunnerarchitecturename"></a>`architectureName` | [`String`](#string) | Architecture provided by the the runner. |
| <a id="cirunnercontactedat"></a>`contactedAt` | [`Time`](#time) | Timestamp of last contact from this runner. |
| <a id="cirunnercreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of creation of this runner. |
+| <a id="cirunnercreatedby"></a>`createdBy` | [`UserCore`](#usercore) | User that created this runner. |
| <a id="cirunnerdescription"></a>`description` | [`String`](#string) | Description of the runner. |
| <a id="cirunnereditadminurl"></a>`editAdminUrl` | [`String`](#string) | Admin form URL of the runner. Only available for administrators. |
-| <a id="cirunnerephemeralauthenticationtoken"></a>`ephemeralAuthenticationToken` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is in Alpha. It can be changed or removed at any time. Ephemeral authentication token used for runner machine registration. |
+| <a id="cirunnerephemeralauthenticationtoken"></a>`ephemeralAuthenticationToken` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is in Alpha. It can be changed or removed at any time. Ephemeral authentication token used for runner machine registration. Only available for the creator of the runner for a limited time during registration. |
| <a id="cirunnerexecutorname"></a>`executorName` | [`String`](#string) | Executor last advertised by the runner. |
| <a id="cirunnergroups"></a>`groups` | [`GroupConnection`](#groupconnection) | Groups the runner is associated with. For group runners only. (see [Connections](#connections)) |
| <a id="cirunnerid"></a>`id` | [`CiRunnerID!`](#cirunnerid) | ID of the runner. |
@@ -11552,6 +11890,7 @@ CI/CD variables for a project.
| <a id="cirunnerjobcount"></a>`jobCount` | [`Int`](#int) | Number of jobs processed by the runner (limited to 1000, plus one to indicate that more items exist). |
| <a id="cirunnerjobexecutionstatus"></a>`jobExecutionStatus` **{warning-solid}** | [`CiRunnerJobExecutionStatus`](#cirunnerjobexecutionstatus) | **Introduced** in 15.7. This feature is in Alpha. It can be changed or removed at any time. Job execution status of the runner. |
| <a id="cirunnerlocked"></a>`locked` | [`Boolean`](#boolean) | Indicates the runner is locked. |
+| <a id="cirunnermachines"></a>`machines` **{warning-solid}** | [`CiRunnerMachineConnection`](#cirunnermachineconnection) | **Introduced** in 15.10. This feature is in Alpha. It can be changed or removed at any time. Machines associated with the runner configuration. |
| <a id="cirunnermaintenancenote"></a>`maintenanceNote` | [`String`](#string) | Runner's maintenance notes. |
| <a id="cirunnermaintenancenotehtml"></a>`maintenanceNoteHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `maintenance_note`. |
| <a id="cirunnermaximumtimeout"></a>`maximumTimeout` | [`Int`](#int) | Maximum timeout (in seconds) for jobs processed by the runner. |
@@ -11561,6 +11900,7 @@ CI/CD variables for a project.
| <a id="cirunnerprivateprojectsminutescostfactor"></a>`privateProjectsMinutesCostFactor` | [`Float`](#float) | Private projects' "minutes cost factor" associated with the runner (GitLab.com only). |
| <a id="cirunnerprojectcount"></a>`projectCount` | [`Int`](#int) | Number of projects that the runner is associated with. |
| <a id="cirunnerpublicprojectsminutescostfactor"></a>`publicProjectsMinutesCostFactor` | [`Float`](#float) | Public projects' "minutes cost factor" associated with the runner (GitLab.com only). |
+| <a id="cirunnerregisteradminurl"></a>`registerAdminUrl` | [`String`](#string) | URL of the temporary registration page of the runner. Only available before the runner is registered. Only available for administrators. |
| <a id="cirunnerrevision"></a>`revision` | [`String`](#string) | Revision of the runner. |
| <a id="cirunnerrununtagged"></a>`runUntagged` | [`Boolean!`](#boolean) | Indicates the runner is able to run untagged jobs. |
| <a id="cirunnerrunnertype"></a>`runnerType` | [`CiRunnerType!`](#cirunnertype) | Type of the runner. |
@@ -11621,6 +11961,25 @@ Returns [`CiRunnerStatus!`](#cirunnerstatus).
| ---- | ---- | ----------- |
| <a id="cirunnerstatuslegacymode"></a>`legacyMode` **{warning-solid}** | [`String`](#string) | **Deprecated** in 15.0. Will be removed in 17.0. In GitLab 16.0 and later, the field will act as if `legacyMode` is null. |
+### `CiRunnerMachine`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cirunnermachinearchitecturename"></a>`architectureName` | [`String`](#string) | Architecture provided by the runner machine. |
+| <a id="cirunnermachinecontactedat"></a>`contactedAt` | [`Time`](#time) | Timestamp of last contact from the runner machine. |
+| <a id="cirunnermachinecreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of creation of the runner machine. |
+| <a id="cirunnermachineexecutorname"></a>`executorName` | [`String`](#string) | Executor last advertised by the runner. |
+| <a id="cirunnermachineid"></a>`id` | [`CiRunnerMachineID!`](#cirunnermachineid) | ID of the runner machine. |
+| <a id="cirunnermachineipaddress"></a>`ipAddress` | [`String`](#string) | IP address of the runner machine. |
+| <a id="cirunnermachineplatformname"></a>`platformName` | [`String`](#string) | Platform provided by the runner machine. |
+| <a id="cirunnermachinerevision"></a>`revision` | [`String`](#string) | Revision of the runner. |
+| <a id="cirunnermachinerunner"></a>`runner` | [`CiRunner`](#cirunner) | Runner configuration for the runner machine. |
+| <a id="cirunnermachinestatus"></a>`status` | [`CiRunnerStatus!`](#cirunnerstatus) | Status of the runner machine. |
+| <a id="cirunnermachinesystemid"></a>`systemId` | [`String!`](#string) | System ID associated with the runner machine. |
+| <a id="cirunnermachineversion"></a>`version` | [`String`](#string) | Version of the runner. |
+
### `CiSecureFileRegistry`
Represents the Geo replication and verification state of a ci_secure_file.
@@ -12169,8 +12528,9 @@ Represents a DAST Pre Scan Verification Step.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="dastprescanverificationstepchecktype"></a>`checkType` | [`DastPreScanVerificationCheckType`](#dastprescanverificationchecktype) | Type of the pre scan verification check. |
| <a id="dastprescanverificationsteperrors"></a>`errors` | [`[String!]`](#string) | Errors that occurred in the pre scan verification step. |
-| <a id="dastprescanverificationstepname"></a>`name` | [`String`](#string) | Name of the pre scan verification step. |
+| <a id="dastprescanverificationstepname"></a>`name` **{warning-solid}** | [`String`](#string) | **Deprecated** in 15.10. This was renamed. Use: [`DastPreScanVerificationStep.checkType`](#dastprescanverificationstepchecktype). |
| <a id="dastprescanverificationstepsuccess"></a>`success` | [`Boolean!`](#boolean) | Whether or not the pre scan verification step has errors. |
### `DastProfile`
@@ -12334,6 +12694,20 @@ The response from the AdminSidekiqQueuesDeleteJobs mutation.
| <a id="deletednoteid"></a>`id` | [`NoteID!`](#noteid) | ID of the deleted note. |
| <a id="deletednotelastdiscussionnote"></a>`lastDiscussionNote` | [`Boolean`](#boolean) | Whether deleted note is the last note in the discussion. |
+### `Dependency`
+
+A software dependency used by a project.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="dependencyid"></a>`id` | [`GlobalID!`](#globalid) | ID of 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` | [`String`](#string) | Description of the tool used to manage the dependency. |
+| <a id="dependencyversion"></a>`version` | [`String`](#string) | Version of the dependency. |
+
### `DependencyProxyBlob`
Dependency proxy blob.
@@ -12533,6 +12907,8 @@ A single design.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="designcommenters"></a>`commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) |
+| <a id="designdescription"></a>`description` | [`String`](#string) | Description of the design. |
+| <a id="designdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. |
| <a id="designdiffrefs"></a>`diffRefs` | [`DiffRefs!`](#diffrefs) | Diff refs for this design. |
| <a id="designdiscussions"></a>`discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) |
| <a id="designevent"></a>`event` | [`DesignVersionEvent!`](#designversionevent) | How this design was changed in the current version. |
@@ -12925,10 +13301,10 @@ Returns [`[DoraMetric!]`](#dorametric).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="dorametricsenddate"></a>`endDate` | [`Date`](#date) | Date range to end at. Default is the current date. |
-| <a id="dorametricsenvironmenttier"></a>`environmentTier` | [`DeploymentTier`](#deploymenttier) | Deployment tier of the environments to return. Deprecated, please update to `environment_tiers` param. |
+| <a id="dorametricsenvironmenttier"></a>`environmentTier` **{warning-solid}** | [`DeploymentTier`](#deploymenttier) | **Deprecated** in 15.2. Superseded by `environment_tiers` param. |
| <a id="dorametricsenvironmenttiers"></a>`environmentTiers` | [`[DeploymentTier!]`](#deploymenttier) | Deployment tiers of the environments to return. Defaults to `[PRODUCTION]`. |
-| <a id="dorametricsinterval"></a>`interval` | [`DoraMetricBucketingInterval`](#dorametricbucketinginterval) | How the metric should be aggregrated. Defaults to `DAILY`. In the case of `ALL`, the `date` field in the response will be `null`. |
-| <a id="dorametricsmetric"></a>`metric` | [`DoraMetricType!`](#dorametrictype) | Type of metric to return. |
+| <a id="dorametricsinterval"></a>`interval` | [`DoraMetricBucketingInterval`](#dorametricbucketinginterval) | How the metric should be aggregated. Defaults to `DAILY`. In the case of `ALL`, the `date` field in the response will be `null`. |
+| <a id="dorametricsmetric"></a>`metric` **{warning-solid}** | [`DoraMetricType`](#dorametrictype) | **Deprecated** in 15.10. Superseded by metrics fields. See `DoraMetric` type. |
| <a id="dorametricsstartdate"></a>`startDate` | [`Date`](#date) | Date range to start from. Default is 3 months ago. |
### `DoraMetric`
@@ -12937,8 +13313,12 @@ Returns [`[DoraMetric!]`](#dorametric).
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="dorametricchangefailurerate"></a>`changeFailureRate` | [`Float`](#float) | Percentage of deployments that caused incidents in production. |
| <a id="dorametricdate"></a>`date` | [`String`](#string) | Date of the data point. |
-| <a id="dorametricvalue"></a>`value` | [`Float`](#float) | Value of the data point. |
+| <a id="dorametricdeploymentfrequency"></a>`deploymentFrequency` | [`Float`](#float) | Number of deployments per day. |
+| <a id="dorametricleadtimeforchanges"></a>`leadTimeForChanges` | [`Float`](#float) | Median time to deploy a merged merge request. |
+| <a id="dorametrictimetorestoreservice"></a>`timeToRestoreService` | [`Float`](#float) | Median time to close an incident. |
+| <a id="dorametricvalue"></a>`value` **{warning-solid}** | [`Float`](#float) | **Deprecated** in 15.10. Moved to corresponding metric field. |
### `EgressNode`
@@ -13597,6 +13977,8 @@ Details of the fork project compared to its upstream project.
| ---- | ---- | ----------- |
| <a id="forkdetailsahead"></a>`ahead` | [`Int`](#int) | Number of commits ahead of upstream. |
| <a id="forkdetailsbehind"></a>`behind` | [`Int`](#int) | Number of commits behind upstream. |
+| <a id="forkdetailshasconflicts"></a>`hasConflicts` | [`Boolean`](#boolean) | Indicates if the fork conflicts with its upstream project. |
+| <a id="forkdetailsissyncing"></a>`isSyncing` | [`Boolean`](#boolean) | Indicates if there is a synchronization in progress. |
### `GeoNode`
@@ -13952,6 +14334,7 @@ GPG signature for a signed commit.
| <a id="groupepicboards"></a>`epicBoards` | [`EpicBoardConnection`](#epicboardconnection) | Find epic boards. (see [Connections](#connections)) |
| <a id="groupepicsenabled"></a>`epicsEnabled` | [`Boolean`](#boolean) | Indicates if Epics are enabled for namespace. |
| <a id="groupexternalauditeventdestinations"></a>`externalAuditEventDestinations` | [`ExternalAuditEventDestinationConnection`](#externalauditeventdestinationconnection) | External locations that receive audit events belonging to the group. (see [Connections](#connections)) |
+| <a id="groupflowmetrics"></a>`flowMetrics` **{warning-solid}** | [`GroupValueStreamAnalyticsFlowMetrics`](#groupvaluestreamanalyticsflowmetrics) | **Introduced** in 15.10. This feature is in Alpha. It can be changed or removed at any time. Flow metrics for value stream analytics. |
| <a id="groupfullname"></a>`fullName` | [`String!`](#string) | Full name of the namespace. |
| <a id="groupfullpath"></a>`fullPath` | [`ID!`](#id) | Full path of the namespace. |
| <a id="groupid"></a>`id` | [`ID!`](#id) | ID of the namespace. |
@@ -14153,7 +14536,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <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 31 days after the start date. |
+| <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.dataTransfer`
@@ -14578,6 +14961,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="groupprojectscomplianceframeworkfilters"></a>`complianceFrameworkFilters` | [`ComplianceFrameworkFilters`](#complianceframeworkfilters) | Filters applied when selecting a compliance framework. |
| <a id="groupprojectshascodecoverage"></a>`hasCodeCoverage` | [`Boolean`](#boolean) | Returns only the projects which have code coverage. |
| <a id="groupprojectshasvulnerabilities"></a>`hasVulnerabilities` | [`Boolean`](#boolean) | Returns only the projects which have vulnerabilities. |
| <a id="groupprojectsids"></a>`ids` | [`[ID!]`](#id) | Filter projects by IDs. |
@@ -14641,7 +15025,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="groupscanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`, `dependency_scanning`. |
+| <a id="groupscanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`, `sast_iac`, `dependency_scanning`. |
| <a id="groupscanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
##### `Group.scanResultPolicies`
@@ -14859,6 +15243,80 @@ Contains statistics about a group.
| ---- | ---- | ----------- |
| <a id="groupstatsreleasestats"></a>`releaseStats` | [`GroupReleaseStats`](#groupreleasestats) | Statistics related to releases within the group. |
+### `GroupValueStreamAnalyticsFlowMetrics`
+
+Exposes aggregated value stream flow metrics.
+
+#### Fields with arguments
+
+##### `GroupValueStreamAnalyticsFlowMetrics.cycleTime`
+
+Median time from first commit to issue closed.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupvaluestreamanalyticsflowmetricscycletimeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricscycletimeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricscycletimefrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
+| <a id="groupvaluestreamanalyticsflowmetricscycletimelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricscycletimemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricscycletimeprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
+| <a id="groupvaluestreamanalyticsflowmetricscycletimeto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
+
+##### `GroupValueStreamAnalyticsFlowMetrics.deploymentCount`
+
+Number of production deployments in the given period.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupvaluestreamanalyticsflowmetricsdeploymentcountfrom"></a>`from` | [`Time!`](#time) | Deployments finished after the date. |
+| <a id="groupvaluestreamanalyticsflowmetricsdeploymentcountprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
+| <a id="groupvaluestreamanalyticsflowmetricsdeploymentcountto"></a>`to` | [`Time!`](#time) | Deployments finished before the date. |
+
+##### `GroupValueStreamAnalyticsFlowMetrics.issueCount`
+
+Number of issues opened in the given period.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupvaluestreamanalyticsflowmetricsissuecountassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricsissuecountauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricsissuecountfrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
+| <a id="groupvaluestreamanalyticsflowmetricsissuecountlabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricsissuecountmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricsissuecountprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
+| <a id="groupvaluestreamanalyticsflowmetricsissuecountto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
+
+##### `GroupValueStreamAnalyticsFlowMetrics.leadTime`
+
+Median time from when the issue was created to when it was closed.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupvaluestreamanalyticsflowmetricsleadtimeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricsleadtimeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricsleadtimefrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
+| <a id="groupvaluestreamanalyticsflowmetricsleadtimelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricsleadtimemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
+| <a id="groupvaluestreamanalyticsflowmetricsleadtimeprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
+| <a id="groupvaluestreamanalyticsflowmetricsleadtimeto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
+
### `GroupWikiRepositoryRegistry`
Represents the Geo sync and verification state of a group wiki repository.
@@ -15456,6 +15914,15 @@ Represents an entry from the Cloud License history.
| <a id="licensehistoryentrytype"></a>`type` | [`String!`](#string) | Type of the license. |
| <a id="licensehistoryentryusersinlicensecount"></a>`usersInLicenseCount` | [`Int`](#int) | Number of paid users in the license. |
+### `Location`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="locationblobpath"></a>`blobPath` | [`String`](#string) | HTTP URI path to view the input file in GitLab. |
+| <a id="locationpath"></a>`path` | [`String`](#string) | Path, relative to the root of the repository, of the filewhich was analyzed to detect the dependency. |
+
### `MavenMetadata`
Maven metadata.
@@ -15690,6 +16157,7 @@ A user assigned to a merge request.
| <a id="mergerequestassigneesavedreplies"></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="mergerequestassigneestate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="mergerequestassigneestatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
+| <a id="mergerequestassigneeuserachievements"></a>`userAchievements` **{warning-solid}** | [`UserAchievementConnection`](#userachievementconnection) | **Introduced** in 15.10. This feature is in Alpha. 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="mergerequestassigneeuserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
| <a id="mergerequestassigneeusername"></a>`username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. |
| <a id="mergerequestassigneewebpath"></a>`webPath` | [`String!`](#string) | Web path of the user. |
@@ -15936,6 +16404,7 @@ The author of the merge request.
| <a id="mergerequestauthorsavedreplies"></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="mergerequestauthorstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="mergerequestauthorstatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
+| <a id="mergerequestauthoruserachievements"></a>`userAchievements` **{warning-solid}** | [`UserAchievementConnection`](#userachievementconnection) | **Introduced** in 15.10. This feature is in Alpha. 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="mergerequestauthoruserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
| <a id="mergerequestauthorusername"></a>`username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. |
| <a id="mergerequestauthorwebpath"></a>`webPath` | [`String!`](#string) | Web path of the user. |
@@ -16201,6 +16670,7 @@ A user participating in a merge request.
| <a id="mergerequestparticipantsavedreplies"></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="mergerequestparticipantstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="mergerequestparticipantstatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
+| <a id="mergerequestparticipantuserachievements"></a>`userAchievements` **{warning-solid}** | [`UserAchievementConnection`](#userachievementconnection) | **Introduced** in 15.10. This feature is in Alpha. 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="mergerequestparticipantuserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
| <a id="mergerequestparticipantusername"></a>`username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. |
| <a id="mergerequestparticipantwebpath"></a>`webPath` | [`String!`](#string) | Web path of the user. |
@@ -16466,6 +16936,7 @@ A user assigned to a merge request as a reviewer.
| <a id="mergerequestreviewersavedreplies"></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="mergerequestreviewerstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="mergerequestreviewerstatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
+| <a id="mergerequestrevieweruserachievements"></a>`userAchievements` **{warning-solid}** | [`UserAchievementConnection`](#userachievementconnection) | **Introduced** in 15.10. This feature is in Alpha. 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="mergerequestrevieweruserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
| <a id="mergerequestreviewerusername"></a>`username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. |
| <a id="mergerequestreviewerwebpath"></a>`webPath` | [`String!`](#string) | Web path of the user. |
@@ -16861,6 +17332,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="namespaceprojectscomplianceframeworkfilters"></a>`complianceFrameworkFilters` | [`ComplianceFrameworkFilters`](#complianceframeworkfilters) | Filters applied when selecting a compliance framework. |
| <a id="namespaceprojectshascodecoverage"></a>`hasCodeCoverage` | [`Boolean`](#boolean) | Returns only the projects which have code coverage. |
| <a id="namespaceprojectshasvulnerabilities"></a>`hasVulnerabilities` | [`Boolean`](#boolean) | Returns only the projects which have vulnerabilities. |
| <a id="namespaceprojectsids"></a>`ids` | [`[ID!]`](#id) | Filter projects by IDs. |
@@ -16884,7 +17356,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="namespacescanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`, `dependency_scanning`. |
+| <a id="namespacescanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`, `sast_iac`, `dependency_scanning`. |
| <a id="namespacescanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
##### `Namespace.scanResultPolicies`
@@ -17615,7 +18087,7 @@ Represents a pipeline schedule.
| ---- | ---- | ----------- |
| <a id="pipelineschedulepermissionsadminpipelineschedule"></a>`adminPipelineSchedule` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_pipeline_schedule` on this resource. |
| <a id="pipelineschedulepermissionsplaypipelineschedule"></a>`playPipelineSchedule` | [`Boolean!`](#boolean) | Indicates the user can perform `play_pipeline_schedule` on this resource. |
-| <a id="pipelineschedulepermissionstakeownershippipelineschedule"></a>`takeOwnershipPipelineSchedule` | [`Boolean!`](#boolean) | Indicates the user can perform `take_ownership_pipeline_schedule` on this resource. |
+| <a id="pipelineschedulepermissionstakeownershippipelineschedule"></a>`takeOwnershipPipelineSchedule` **{warning-solid}** | [`Boolean!`](#boolean) | **Deprecated** in 15.9. Use admin_pipeline_schedule permission to determine if the user can take ownership of a pipeline schedule. |
| <a id="pipelineschedulepermissionsupdatepipelineschedule"></a>`updatePipelineSchedule` | [`Boolean!`](#boolean) | Indicates the user can perform `update_pipeline_schedule` on this resource. |
### `PipelineScheduleVariable`
@@ -17739,9 +18211,11 @@ Represents a product analytics dashboard visualization.
| <a id="projectcreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of the project creation. |
| <a id="projectdastscannerprofiles"></a>`dastScannerProfiles` | [`DastScannerProfileConnection`](#dastscannerprofileconnection) | DAST scanner profiles associated with the project. (see [Connections](#connections)) |
| <a id="projectdastsiteprofiles"></a>`dastSiteProfiles` | [`DastSiteProfileConnection`](#dastsiteprofileconnection) | DAST Site Profiles associated with the project. (see [Connections](#connections)) |
+| <a id="projectdependencies"></a>`dependencies` **{warning-solid}** | [`DependencyConnection`](#dependencyconnection) | **Introduced** in 15.9. This feature is in Alpha. It can be changed or removed at any time. Software dependencies used by the project. |
| <a id="projectdescription"></a>`description` | [`String`](#string) | Short description of the project. |
| <a id="projectdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. |
| <a id="projectdora"></a>`dora` | [`Dora`](#dora) | Project's DORA metrics. |
+| <a id="projectflowmetrics"></a>`flowMetrics` **{warning-solid}** | [`ProjectValueStreamAnalyticsFlowMetrics`](#projectvaluestreamanalyticsflowmetrics) | **Introduced** in 15.10. This feature is in Alpha. It can be changed or removed at any time. Flow metrics for value stream analytics. |
| <a id="projectforkscount"></a>`forksCount` | [`Int!`](#int) | Number of times the project has been forked. |
| <a id="projectfullpath"></a>`fullPath` | [`ID!`](#id) | Full path of the project. |
| <a id="projectgrafanaintegration"></a>`grafanaIntegration` | [`GrafanaIntegration`](#grafanaintegration) | Grafana integration details for the project. |
@@ -17759,6 +18233,7 @@ Represents a product analytics dashboard visualization.
| <a id="projectlastactivityat"></a>`lastActivityAt` | [`Time`](#time) | Timestamp of the project last activity. |
| <a id="projectlfsenabled"></a>`lfsEnabled` | [`Boolean`](#boolean) | Indicates if the project has Large File Storage (LFS) enabled. |
| <a id="projectmergecommittemplate"></a>`mergeCommitTemplate` | [`String`](#string) | Template used to create merge commit message in merge requests. |
+| <a id="projectmergerequestsdisablecommittersapproval"></a>`mergeRequestsDisableCommittersApproval` | [`Boolean!`](#boolean) | Indicates that committers of the given merge request cannot approve. |
| <a id="projectmergerequestsenabled"></a>`mergeRequestsEnabled` | [`Boolean`](#boolean) | Indicates if Merge Requests are enabled for the current user. |
| <a id="projectmergerequestsffonlyenabled"></a>`mergeRequestsFfOnlyEnabled` | [`Boolean`](#boolean) | Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. |
| <a id="projectname"></a>`name` | [`String!`](#string) | Name of the project (without namespace). |
@@ -17773,6 +18248,7 @@ Represents a product analytics dashboard visualization.
| <a id="projectpathlocks"></a>`pathLocks` | [`PathLockConnection`](#pathlockconnection) | The project's path locks. (see [Connections](#connections)) |
| <a id="projectpipelineanalytics"></a>`pipelineAnalytics` | [`PipelineAnalytics`](#pipelineanalytics) | Pipeline analytics. |
| <a id="projectprintingmergerequestlinkenabled"></a>`printingMergeRequestLinkEnabled` | [`Boolean`](#boolean) | Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line. |
+| <a id="projectproductanalyticsstate"></a>`productAnalyticsState` **{warning-solid}** | [`ProductAnalyticsState`](#productanalyticsstate) | **Introduced** in 15.10. This feature is in Alpha. It can be changed or removed at any time. Current state of the product analytics stack for this project.Can only be called for one project in a single request. |
| <a id="projectpublicjobs"></a>`publicJobs` | [`Boolean`](#boolean) | Indicates if there is public access to pipelines and job details of the project, including output logs and artifacts. |
| <a id="projectpushrules"></a>`pushRules` | [`PushRules`](#pushrules) | Project's push rules settings. |
| <a id="projectrecentissueboards"></a>`recentIssueBoards` | [`BoardConnection`](#boardconnection) | List of recently visited boards of the project. Maximum size is 4. (see [Connections](#connections)) |
@@ -18847,7 +19323,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="projectscanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`, `dependency_scanning`. |
+| <a id="projectscanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`, `sast_iac`, `dependency_scanning`. |
| <a id="projectscanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
##### `Project.scanResultPolicies`
@@ -19096,13 +19572,13 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectworkitemsauthorusername"></a>`authorUsername` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is in Alpha. It can be changed or removed at any time. Filter work items by author username. |
-| <a id="projectworkitemsiid"></a>`iid` | [`String`](#string) | IID of the issue. For example, "1". |
+| <a id="projectworkitemsiid"></a>`iid` | [`String`](#string) | IID of the work item. For example, "1". |
| <a id="projectworkitemsiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of work items. For example, `["1", "2"]`. |
| <a id="projectworkitemsin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
| <a id="projectworkitemsrequirementlegacywidget"></a>`requirementLegacyWidget` **{warning-solid}** | [`RequirementLegacyFilterInput`](#requirementlegacyfilterinput) | **Deprecated** in 15.9. Use work item IID filter instead. |
| <a id="projectworkitemssearch"></a>`search` | [`String`](#string) | Search query for title or description. |
-| <a id="projectworkitemssort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort work items by this criteria. |
-| <a id="projectworkitemsstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of this work item. |
+| <a id="projectworkitemssort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort work items by criteria. |
+| <a id="projectworkitemsstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of the work item. |
| <a id="projectworkitemsstatuswidget"></a>`statusWidget` | [`StatusFilterInput`](#statusfilterinput) | Input for status widget filter. Ignored if `work_items_mvc_2` is disabled. |
| <a id="projectworkitemstypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. |
@@ -19254,6 +19730,76 @@ Represents the source of a security policy belonging to a project.
| <a id="projectstatisticsuploadssize"></a>`uploadsSize` | [`Float`](#float) | Uploads size of the project in bytes. |
| <a id="projectstatisticswikisize"></a>`wikiSize` | [`Float`](#float) | Wiki size of the project in bytes. |
+### `ProjectValueStreamAnalyticsFlowMetrics`
+
+Exposes aggregated value stream flow metrics.
+
+#### Fields with arguments
+
+##### `ProjectValueStreamAnalyticsFlowMetrics.cycleTime`
+
+Median time from first commit to issue closed.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectvaluestreamanalyticsflowmetricscycletimeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricscycletimeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricscycletimefrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
+| <a id="projectvaluestreamanalyticsflowmetricscycletimelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricscycletimemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricscycletimeto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
+
+##### `ProjectValueStreamAnalyticsFlowMetrics.deploymentCount`
+
+Number of production deployments in the given period.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectvaluestreamanalyticsflowmetricsdeploymentcountfrom"></a>`from` | [`Time!`](#time) | Deployments finished after the date. |
+| <a id="projectvaluestreamanalyticsflowmetricsdeploymentcountto"></a>`to` | [`Time!`](#time) | Deployments finished before the date. |
+
+##### `ProjectValueStreamAnalyticsFlowMetrics.issueCount`
+
+Number of issues opened in the given period.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectvaluestreamanalyticsflowmetricsissuecountassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricsissuecountauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricsissuecountfrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
+| <a id="projectvaluestreamanalyticsflowmetricsissuecountlabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricsissuecountmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricsissuecountto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
+
+##### `ProjectValueStreamAnalyticsFlowMetrics.leadTime`
+
+Median time from when the issue was created to when it was closed.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectvaluestreamanalyticsflowmetricsleadtimeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricsleadtimeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricsleadtimefrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
+| <a id="projectvaluestreamanalyticsflowmetricsleadtimelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricsleadtimemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
+| <a id="projectvaluestreamanalyticsflowmetricsleadtimeto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
+
### `PrometheusAlert`
The alert condition for Prometheus.
@@ -19278,6 +19824,7 @@ Protected Environments of the environment.
| <a id="protectedenvironmentgroup"></a>`group` | [`Group`](#group) | Group details. Present if it's group-level protected environment. |
| <a id="protectedenvironmentname"></a>`name` | [`String`](#string) | Name of the environment if it's a project-level protected environment. Tier of the environment if it's a group-level protected environment. |
| <a id="protectedenvironmentproject"></a>`project` | [`Project`](#project) | Project details. Present if it's project-level protected environment. |
+| <a id="protectedenvironmentrequiredapprovalcount"></a>`requiredApprovalCount` | [`Int`](#int) | Required approval count for Unified Approval Setting. |
### `ProtectedEnvironmentApprovalRule`
@@ -19678,6 +20225,7 @@ Counts of requirements by their state.
| <a id="rootstoragestatisticslfsobjectssize"></a>`lfsObjectsSize` | [`Float!`](#float) | LFS objects size in bytes. |
| <a id="rootstoragestatisticspackagessize"></a>`packagesSize` | [`Float!`](#float) | Packages size in bytes. |
| <a id="rootstoragestatisticspipelineartifactssize"></a>`pipelineArtifactsSize` | [`Float!`](#float) | CI pipeline artifacts size in bytes. |
+| <a id="rootstoragestatisticsregistrysizeestimated"></a>`registrySizeEstimated` | [`Boolean!`](#boolean) | Indicates whether the deduplicated Container Registry size for the namespace is an estimated value or not. |
| <a id="rootstoragestatisticsrepositorysize"></a>`repositorySize` | [`Float!`](#float) | Git repository size in bytes. |
| <a id="rootstoragestatisticssnippetssize"></a>`snippetsSize` | [`Float!`](#float) | Snippets size in bytes. |
| <a id="rootstoragestatisticsstoragesize"></a>`storageSize` | [`Float!`](#float) | Total storage in bytes. |
@@ -20199,6 +20747,7 @@ SSH signature for a signed commit.
| ---- | ---- | ----------- |
| <a id="sshsignaturecommitsha"></a>`commitSha` | [`String`](#string) | SHA of the associated commit. |
| <a id="sshsignaturekey"></a>`key` | [`Key`](#key) | SSH key used for the signature. |
+| <a id="sshsignaturekeyfingerprintsha256"></a>`keyFingerprintSha256` | [`String`](#string) | Fingerprint of the key. |
| <a id="sshsignatureproject"></a>`project` | [`Project`](#project) | Project of the associated commit. |
| <a id="sshsignatureuser"></a>`user` | [`UserCore`](#usercore) | User associated with the key. |
| <a id="sshsignatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. |
@@ -20648,6 +21197,21 @@ Represents a recorded measurement (object count) for the Admins.
| <a id="usagetrendsmeasurementidentifier"></a>`identifier` | [`MeasurementIdentifier!`](#measurementidentifier) | Type of objects being measured. |
| <a id="usagetrendsmeasurementrecordedat"></a>`recordedAt` | [`Time`](#time) | Time the measurement was recorded. |
+### `UserAchievement`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="userachievementachievement"></a>`achievement` | [`Achievement!`](#achievement) | Achievement awarded. |
+| <a id="userachievementawardedbyuser"></a>`awardedByUser` | [`UserCore!`](#usercore) | Awarded by. |
+| <a id="userachievementcreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp the achievement was created. |
+| <a id="userachievementid"></a>`id` | [`AchievementsUserAchievementID!`](#achievementsuserachievementid) | ID of the user achievement. |
+| <a id="userachievementrevokedat"></a>`revokedAt` | [`Time`](#time) | Timestamp the achievement was revoked. |
+| <a id="userachievementrevokedbyuser"></a>`revokedByUser` | [`UserCore`](#usercore) | Revoked by. |
+| <a id="userachievementupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp the achievement was last updated. |
+| <a id="userachievementuser"></a>`user` | [`UserCore!`](#usercore) | Achievement recipient. |
+
### `UserCallout`
#### Fields
@@ -20686,6 +21250,7 @@ Core represention of a GitLab user.
| <a id="usercoresavedreplies"></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="usercorestate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="usercorestatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
+| <a id="usercoreuserachievements"></a>`userAchievements` **{warning-solid}** | [`UserAchievementConnection`](#userachievementconnection) | **Introduced** in 15.10. This feature is in Alpha. 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="usercoreuserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
| <a id="usercoreusername"></a>`username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. |
| <a id="usercorewebpath"></a>`webPath` | [`String!`](#string) | Web path of the user. |
@@ -20947,6 +21512,29 @@ fields relate to interactions between the two entities.
| <a id="userstatusmessage"></a>`message` | [`String`](#string) | User status message. |
| <a id="userstatusmessagehtml"></a>`messageHtml` | [`String`](#string) | HTML of the user status message. |
+### `ValueStreamAnalyticsMetric`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="valuestreamanalyticsmetricidentifier"></a>`identifier` | [`String!`](#string) | Identifier for the metric. |
+| <a id="valuestreamanalyticsmetriclinks"></a>`links` | [`[ValueStreamMetricLinkType!]!`](#valuestreammetriclinktype) | Optional links for drilling down. |
+| <a id="valuestreamanalyticsmetrictitle"></a>`title` | [`String!`](#string) | Title for the metric. |
+| <a id="valuestreamanalyticsmetricunit"></a>`unit` | [`String`](#string) | Unit of measurement. |
+| <a id="valuestreamanalyticsmetricvalue"></a>`value` | [`Float`](#float) | Value for the metric. |
+
+### `ValueStreamMetricLinkType`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="valuestreammetriclinktypedocslink"></a>`docsLink` | [`Boolean`](#boolean) | Link to the metric documentation. |
+| <a id="valuestreammetriclinktypelabel"></a>`label` | [`String!`](#string) | Label for the link. |
+| <a id="valuestreammetriclinktypename"></a>`name` | [`String!`](#string) | Name of the link group. |
+| <a id="valuestreammetriclinktypeurl"></a>`url` | [`String!`](#string) | Drill-down URL. |
+
### `VulnerabilitiesCountByDay`
Represents the count of vulnerabilities by severity on a particular day. This data is retained for 365 days.
@@ -21002,6 +21590,7 @@ Represents a vulnerability.
| <a id="vulnerabilityseverity"></a>`severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL). |
| <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)) |
| <a id="vulnerabilitytitle"></a>`title` | [`String`](#string) | Title of the 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. |
@@ -21171,6 +21760,19 @@ Represents the vulnerability details location within a file in the project.
| <a id="vulnerabilitydetailmodulelocationname"></a>`name` | [`String`](#string) | Name of the field. |
| <a id="vulnerabilitydetailmodulelocationoffset"></a>`offset` | [`Int!`](#int) | Offset of the module location. |
+### `VulnerabilityDetailRow`
+
+Represents an individual row in a table.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="vulnerabilitydetailrowdescription"></a>`description` | [`String`](#string) | Description of the field. |
+| <a id="vulnerabilitydetailrowfieldname"></a>`fieldName` | [`String`](#string) | Name of the field. |
+| <a id="vulnerabilitydetailrowname"></a>`name` | [`String`](#string) | Name of the field. |
+| <a id="vulnerabilitydetailrowrow"></a>`row` | [`[VulnerabilityDetail!]!`](#vulnerabilitydetail) | Value of the field. |
+
### `VulnerabilityDetailTable`
Represents the vulnerability details table value.
@@ -21183,7 +21785,7 @@ Represents the vulnerability details table value.
| <a id="vulnerabilitydetailtablefieldname"></a>`fieldName` | [`String`](#string) | Name of the field. |
| <a id="vulnerabilitydetailtableheaders"></a>`headers` | [`[VulnerabilityDetail!]!`](#vulnerabilitydetail) | Table headers. |
| <a id="vulnerabilitydetailtablename"></a>`name` | [`String`](#string) | Name of the field. |
-| <a id="vulnerabilitydetailtablerows"></a>`rows` | [`[VulnerabilityDetail!]!`](#vulnerabilitydetail) | Table rows. |
+| <a id="vulnerabilitydetailtablerows"></a>`rows` | [`[VulnerabilityDetailRow!]!`](#vulnerabilitydetailrow) | Table rows. |
### `VulnerabilityDetailText`
@@ -21502,6 +22104,21 @@ Represents vulnerability counts by severity.
| <a id="vulnerabilityseveritiescountmedium"></a>`medium` | [`Int`](#int) | Number of vulnerabilities of MEDIUM severity of the project. |
| <a id="vulnerabilityseveritiescountunknown"></a>`unknown` | [`Int`](#int) | Number of vulnerabilities of UNKNOWN severity of the project. |
+### `VulnerabilityStateTransitionType`
+
+Represents a state transition of a vulnerability.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="vulnerabilitystatetransitiontypeauthor"></a>`author` | [`UserCore!`](#usercore) | User who changed the state of the vulnerability. |
+| <a id="vulnerabilitystatetransitiontypecomment"></a>`comment` | [`String`](#string) | Comment for the state change. |
+| <a id="vulnerabilitystatetransitiontypecreatedat"></a>`createdAt` | [`Time!`](#time) | Time of the state change of the vulnerability. |
+| <a id="vulnerabilitystatetransitiontypedismissalreason"></a>`dismissalReason` | [`VulnerabilityDismissalReason`](#vulnerabilitydismissalreason) | Reason for the dismissal. |
+| <a id="vulnerabilitystatetransitiontypefromstate"></a>`fromState` | [`VulnerabilityState!`](#vulnerabilitystate) | State of the vulnerability before transition. |
+| <a id="vulnerabilitystatetransitiontypetostate"></a>`toState` | [`VulnerabilityState!`](#vulnerabilitystate) | State of the vulnerability after transition. |
+
### `VulnerableDependency`
Represents a vulnerable dependency. Used in vulnerability location data.
@@ -21712,6 +22329,17 @@ four standard [pagination arguments](#connection-pagination-arguments):
| ---- | ---- | ----------- |
| <a id="workitemwidgetnotesdiscussionsfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
+### `WorkItemWidgetNotifications`
+
+Represents the notifications widget.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetnotificationssubscribed"></a>`subscribed` | [`Boolean!`](#boolean) | Whether the current user is subscribed to notifications on the work item. |
+| <a id="workitemwidgetnotificationstype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
+
### `WorkItemWidgetProgress`
Represents a progress widget.
@@ -21996,6 +22624,19 @@ User availability status.
| <a id="availabilityenumbusy"></a>`BUSY` | Busy. |
| <a id="availabilityenumnot_set"></a>`NOT_SET` | Not Set. |
+### `AvailableExportFields`
+
+Available fields to be exported as CSV.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="availableexportfieldsauthor"></a>`AUTHOR` | Author name. |
+| <a id="availableexportfieldsauthor_username"></a>`AUTHOR_USERNAME` | Author username. |
+| <a id="availableexportfieldscreated_at"></a>`CREATED_AT` | Date of creation. |
+| <a id="availableexportfieldsid"></a>`ID` | Unique identifier. |
+| <a id="availableexportfieldstitle"></a>`TITLE` | Title. |
+| <a id="availableexportfieldstype"></a>`TYPE` | Type of the work item. |
+
### `BlobViewersType`
Types of blob viewers.
@@ -22178,6 +22819,15 @@ Mode of a commit action.
| <a id="commitencodingbase64"></a>`BASE64` | Base64 encoding. |
| <a id="commitencodingtext"></a>`TEXT` | Text encoding. |
+### `ComplianceFrameworkPresenceFilter`
+
+ComplianceFramework of a project for filtering.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="complianceframeworkpresencefilterany"></a>`ANY` | Any compliance framework is assigned. |
+| <a id="complianceframeworkpresencefilternone"></a>`NONE` | No compliance framework is assigned. |
+
### `ComplianceViolationReason`
Reason for the compliance violation.
@@ -22345,6 +22995,16 @@ Values for sorting tags.
| <a id="customerrelationsorganizationstateall"></a>`all` | All available organizations. |
| <a id="customerrelationsorganizationstateinactive"></a>`inactive` | Inactive organizations. |
+### `DastPreScanVerificationCheckType`
+
+Check type of the pre scan verification step.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="dastprescanverificationchecktypeauthentication"></a>`AUTHENTICATION` | Authentication check. |
+| <a id="dastprescanverificationchecktypeconnection"></a>`CONNECTION` | Connection check. |
+| <a id="dastprescanverificationchecktypecrawling"></a>`CRAWLING` | Crawling check. |
+
### `DastPreScanVerificationStatus`
Status of DAST pre scan verification.
@@ -22767,6 +23427,15 @@ State of a GitLab issue or merge request.
| <a id="issuablestatelocked"></a>`locked` | Discussion has been locked. |
| <a id="issuablestateopened"></a>`opened` | In open state. |
+### `IssuableSubscriptionEvent`
+
+Values for subscribing and unsubscribing from issuables.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="issuablesubscriptioneventsubscribe"></a>`SUBSCRIBE` | Subscribe to an issuable. |
+| <a id="issuablesubscriptioneventunsubscribe"></a>`UNSUBSCRIBE` | Unsubscribe from an issuable. |
+
### `IssueCreationIterationWildcardId`
Iteration ID wildcard values for issue creation.
@@ -23139,9 +23808,11 @@ Values for sorting projects.
| Value | Description |
| ----- | ----------- |
-| <a id="namespaceprojectsortactivity_desc"></a>`ACTIVITY_DESC` | Sort by latest activity, in descending order. |
+| <a id="namespaceprojectsortactivity_desc"></a>`ACTIVITY_DESC` | Sort by latest activity, descending order. |
| <a id="namespaceprojectsortsimilarity"></a>`SIMILARITY` | Most similar to the search query. |
-| <a id="namespaceprojectsortstorage"></a>`STORAGE` | Sort by storage size. |
+| <a id="namespaceprojectsortstorage"></a>`STORAGE` | Sort by excess repository storage size, descending order. |
+| <a id="namespaceprojectsortstorage_size_asc"></a>`STORAGE_SIZE_ASC` | Sort by total storage size, ascending order. |
+| <a id="namespaceprojectsortstorage_size_desc"></a>`STORAGE_SIZE_DESC` | Sort by total storage size, descending order. |
### `NegatedIterationWildcardId`
@@ -23348,6 +24019,17 @@ Event type of the pipeline associated with a merge request.
| <a id="pipelinestatusenumsuccess"></a>`SUCCESS` | Pipeline completed successfully. |
| <a id="pipelinestatusenumwaiting_for_resource"></a>`WAITING_FOR_RESOURCE` | A resource (for example, a runner) that the pipeline requires to run is unavailable. |
+### `ProductAnalyticsState`
+
+Current state of the product analytics stack.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="productanalyticsstatecomplete"></a>`COMPLETE` | Stack has been initialized and has data. |
+| <a id="productanalyticsstatecreate_instance"></a>`CREATE_INSTANCE` | Stack has not been created yet. |
+| <a id="productanalyticsstateloading_instance"></a>`LOADING_INSTANCE` | Stack is currently initializing. |
+| <a id="productanalyticsstatewaiting_for_events"></a>`WAITING_FOR_EVENTS` | Stack is waiting for events from users. |
+
### `ProjectMemberRelation`
Project member relation.
@@ -23523,6 +24205,7 @@ State of a Sentry error.
| <a id="servicetypeexternal_wiki_service"></a>`EXTERNAL_WIKI_SERVICE` | ExternalWikiService type. |
| <a id="servicetypegithub_service"></a>`GITHUB_SERVICE` | GithubService type. |
| <a id="servicetypegitlab_slack_application_service"></a>`GITLAB_SLACK_APPLICATION_SERVICE` | GitlabSlackApplicationService type (Gitlab.com only). |
+| <a id="servicetypegoogle_play_service"></a>`GOOGLE_PLAY_SERVICE` | GooglePlayService type. |
| <a id="servicetypehangouts_chat_service"></a>`HANGOUTS_CHAT_SERVICE` | HangoutsChatService type. |
| <a id="servicetypeharbor_service"></a>`HARBOR_SERVICE` | HarborService type. |
| <a id="servicetypeirker_service"></a>`IRKER_SERVICE` | IrkerService type. |
@@ -23541,6 +24224,7 @@ State of a Sentry error.
| <a id="servicetypeshimo_service"></a>`SHIMO_SERVICE` | ShimoService type. |
| <a id="servicetypeslack_service"></a>`SLACK_SERVICE` | SlackService type. |
| <a id="servicetypeslack_slash_commands_service"></a>`SLACK_SLASH_COMMANDS_SERVICE` | SlackSlashCommandsService type. |
+| <a id="servicetypesquash_tm_service"></a>`SQUASH_TM_SERVICE` | SquashTmService type. |
| <a id="servicetypeteamcity_service"></a>`TEAMCITY_SERVICE` | TeamcityService type. |
| <a id="servicetypeunify_circuit_service"></a>`UNIFY_CIRCUIT_SERVICE` | UnifyCircuitService type. |
| <a id="servicetypewebex_teams_service"></a>`WEBEX_TEAMS_SERVICE` | WebexTeamsService type. |
@@ -23719,6 +24403,7 @@ Name of the feature that the callout is for.
| ----- | ----------- |
| <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. |
@@ -23996,6 +24681,7 @@ Type of a work item widget.
| <a id="workitemwidgettypelabels"></a>`LABELS` | Labels widget. |
| <a id="workitemwidgettypemilestone"></a>`MILESTONE` | Milestone widget. |
| <a id="workitemwidgettypenotes"></a>`NOTES` | Notes widget. |
+| <a id="workitemwidgettypenotifications"></a>`NOTIFICATIONS` | Notifications widget. |
| <a id="workitemwidgettypeprogress"></a>`PROGRESS` | Progress widget. |
| <a id="workitemwidgettyperequirement_legacy"></a>`REQUIREMENT_LEGACY` | Requirement Legacy widget. |
| <a id="workitemwidgettypestart_and_due_date"></a>`START_AND_DUE_DATE` | Start And Due Date widget. |
@@ -24020,6 +24706,12 @@ A `AchievementsAchievementID` is a global ID. It is encoded as a string.
An example `AchievementsAchievementID` is: `"gid://gitlab/Achievements::Achievement/1"`.
+### `AchievementsUserAchievementID`
+
+A `AchievementsUserAchievementID` is a global ID. It is encoded as a string.
+
+An example `AchievementsUserAchievementID` is: `"gid://gitlab/Achievements::UserAchievement/1"`.
+
### `AlertManagementAlertID`
A `AlertManagementAlertID` is a global ID. It is encoded as a string.
@@ -24118,6 +24810,12 @@ A `CiRunnerID` is a global ID. It is encoded as a string.
An example `CiRunnerID` is: `"gid://gitlab/Ci::Runner/1"`.
+### `CiRunnerMachineID`
+
+A `CiRunnerMachineID` is a global ID. It is encoded as a string.
+
+An example `CiRunnerMachineID` is: `"gid://gitlab/Ci::RunnerMachine/1"`.
+
### `ClustersAgentID`
A `ClustersAgentID` is a global ID. It is encoded as a string.
@@ -25122,6 +25820,7 @@ Implementations:
| <a id="usersavedreplies"></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="userstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="userstatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
+| <a id="useruserachievements"></a>`userAchievements` **{warning-solid}** | [`UserAchievementConnection`](#userachievementconnection) | **Introduced** in 15.10. This feature is in Alpha. 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="useruserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
| <a id="userusername"></a>`username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. |
| <a id="userwebpath"></a>`webPath` | [`String!`](#string) | Web path of the user. |
@@ -25350,6 +26049,7 @@ Implementations:
- [`WorkItemWidgetLabels`](#workitemwidgetlabels)
- [`WorkItemWidgetMilestone`](#workitemwidgetmilestone)
- [`WorkItemWidgetNotes`](#workitemwidgetnotes)
+- [`WorkItemWidgetNotifications`](#workitemwidgetnotifications)
- [`WorkItemWidgetProgress`](#workitemwidgetprogress)
- [`WorkItemWidgetRequirementLegacy`](#workitemwidgetrequirementlegacy)
- [`WorkItemWidgetStartAndDueDate`](#workitemwidgetstartandduedate)
@@ -25439,6 +26139,16 @@ Attributes for defining a CI/CD variable.
| <a id="commitactionlastcommitid"></a>`lastCommitId` | [`String`](#string) | Last known file commit ID. |
| <a id="commitactionpreviouspath"></a>`previousPath` | [`String`](#string) | Original full path to the file being moved. |
+### `ComplianceFrameworkFilters`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="complianceframeworkfiltersid"></a>`id` | [`ComplianceManagementFrameworkID`](#compliancemanagementframeworkid) | ID of the compliance framework. |
+| <a id="complianceframeworkfiltersnot"></a>`not` | [`NegatedComplianceFrameworkFilters`](#negatedcomplianceframeworkfilters) | Negated compliance framework filter input. |
+| <a id="complianceframeworkfilterspresencefilter"></a>`presenceFilter` | [`ComplianceFrameworkPresenceFilter`](#complianceframeworkpresencefilter) | Checks presence of compliance framework of the project, "none" and "any" values are supported. |
+
### `ComplianceFrameworkInput`
#### Arguments
@@ -25629,6 +26339,14 @@ Represents an escalation rule.
| <a id="negatedboardissueinputtypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter by the given issue types. |
| <a id="negatedboardissueinputweight"></a>`weight` | [`String`](#string) | Filter by weight. |
+### `NegatedComplianceFrameworkFilters`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="negatedcomplianceframeworkfiltersid"></a>`id` | [`ComplianceManagementFrameworkID`](#compliancemanagementframeworkid) | ID of the compliance framework. |
+
### `NegatedEpicBoardIssueInput`
#### Arguments
@@ -25931,6 +26649,7 @@ A time-frame defined as a closed inclusive range of two dates.
| <a id="workitemupdatedtaskinputid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
| <a id="workitemupdatedtaskinputlabelswidget"></a>`labelsWidget` | [`WorkItemWidgetLabelsUpdateInput`](#workitemwidgetlabelsupdateinput) | Input for labels widget. |
| <a id="workitemupdatedtaskinputmilestonewidget"></a>`milestoneWidget` | [`WorkItemWidgetMilestoneInput`](#workitemwidgetmilestoneinput) | Input for milestone widget. |
+| <a id="workitemupdatedtaskinputnotificationswidget"></a>`notificationsWidget` | [`WorkItemWidgetNotificationsUpdateInput`](#workitemwidgetnotificationsupdateinput) | Input for notifications widget. |
| <a id="workitemupdatedtaskinputstartandduedatewidget"></a>`startAndDueDateWidget` | [`WorkItemWidgetStartAndDueDateUpdateInput`](#workitemwidgetstartandduedateupdateinput) | Input for start and due date widget. |
| <a id="workitemupdatedtaskinputstateevent"></a>`stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. |
| <a id="workitemupdatedtaskinputtitle"></a>`title` | [`String`](#string) | Title of the work item. |
@@ -26001,6 +26720,14 @@ A time-frame defined as a closed inclusive range of two dates.
| ---- | ---- | ----------- |
| <a id="workitemwidgetmilestoneinputmilestoneid"></a>`milestoneId` | [`MilestoneID`](#milestoneid) | Milestone to assign to the work item. |
+### `WorkItemWidgetNotificationsUpdateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetnotificationsupdateinputsubscribed"></a>`subscribed` | [`Boolean!`](#boolean) | Desired state of the subscription. |
+
### `WorkItemWidgetProgressInput`
#### Arguments
diff --git a/doc/api/group_badges.md b/doc/api/group_badges.md
index ede7591c6d1..4c225e8aacb 100644
--- a/doc/api/group_badges.md
+++ b/doc/api/group_badges.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
@@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## Placeholder tokens
-Badges support placeholders that are replaced in real time in both the link and image URL. The allowed placeholders are:
+[Badges](../user/project/badges.md) support placeholders that are replaced in real time in both the link and image URL. The allowed placeholders are:
<!-- vale gitlab.Spelling = NO -->
diff --git a/doc/api/group_clusters.md b/doc/api/group_clusters.md
index daffda8340c..a180c7a1f92 100644
--- a/doc/api/group_clusters.md
+++ b/doc/api/group_clusters.md
@@ -4,7 +4,7 @@ group: Configure
info: To 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 clusters API (certificate-based) (DEPRECATED) **(FREE)**
+# Group clusters API (certificate-based) (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30213) in GitLab 12.1.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/api/group_import_export.md b/doc/api/group_import_export.md
index c648b6bad37..5dd0e4e3d52 100644
--- a/doc/api/group_import_export.md
+++ b/doc/api/group_import_export.md
@@ -4,12 +4,12 @@ group: Import
info: To 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 import/export API **(FREE)**
+# Group import and export API **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20353) in GitLab 12.8.
-Group Import/Export allows you to export group structure and import it to a new location.
-When used with [Project Import/Export](project_import_export.md), you can preserve connections with
+Use the group import and export API to export a group structure and import it to a new location.
+When you use the group import and export API with the [project import and export API](project_import_export.md), you can preserve connections with
group-level relationships, such as connections between project issues and group epics.
Group exports include the following:
@@ -22,6 +22,13 @@ Group exports include the following:
- Subgroups. Each subgroup includes all data above
- Group wikis **(PREMIUM SELF)**
+To preserve group-level relationships from imported projects, you should run group import and export first. This way, you can import project exports into the desired group structure.
+
+Imported groups have a `private` visibility level unless you import them into a parent group.
+If you import groups into a parent group, the subgroups inherit by default a similar level of visibility.
+
+To preserve the member list and their respective permissions on imported groups, review the users in these groups. Make sure these users exist before importing the desired groups.
+
## Schedule new export
Start a new group export.
@@ -103,14 +110,3 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
NOTE:
The maximum import file size can be set by the Administrator, default is `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](../user/admin_area/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.
-
-## Important notes
-
-Note the following:
-
-- To preserve group-level relationships from imported projects, run Group Import/Export first,
- to allow project imports into the desired group structure.
-- Imported groups are given a `private` visibility level, unless imported into a parent group.
-- If imported into a parent group, subgroups inherit a similar level of visibility, unless otherwise restricted.
-- To preserve the member list and their respective permissions on imported groups,
- review the users in these groups. Make sure these users exist before importing the desired groups.
diff --git a/doc/api/group_iterations.md b/doc/api/group_iterations.md
index 3c445ee09dd..b2439861c2f 100644
--- a/doc/api/group_iterations.md
+++ b/doc/api/group_iterations.md
@@ -22,6 +22,8 @@ GET /groups/:id/iterations?state=opened
GET /groups/:id/iterations?state=closed
GET /groups/:id/iterations?search=version
GET /groups/:id/iterations?include_ancestors=false
+GET /groups/:id/iterations?updated_before=2013-10-02T09%3A24%3A18Z
+GET /groups/:id/iterations?updated_after=2013-10-02T09%3A24%3A18Z
```
| Attribute | Type | Required | Description |
@@ -29,6 +31,8 @@ GET /groups/:id/iterations?include_ancestors=false
| `state` | string | no | 'Return `opened`, `upcoming`, `current (previously started)`, `closed`, or `all` iterations. Filtering by `started` state is deprecated starting with 14.1, use `current` instead.' |
| `search` | string | no | Return only iterations with a title matching the provided string. |
| `include_ancestors` | boolean | no | Include iterations from parent group and its ancestors. Defaults to `true`. |
+| `updated_before` | datetime | no | Return only iterations updated before the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378662) in GitLab 15.10. |
+| `updated_after` | datetime | no | Return only iterations updated after the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378662) in GitLab 15.10. |
Example request:
diff --git a/doc/api/group_level_variables.md b/doc/api/group_level_variables.md
index 4037a778d7f..921a9922c9b 100644
--- a/doc/api/group_level_variables.md
+++ b/doc/api/group_level_variables.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
---
diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md
index fc95230cbba..52bce54119a 100644
--- a/doc/api/group_milestones.md
+++ b/doc/api/group_milestones.md
@@ -21,6 +21,8 @@ GET /groups/:id/milestones?state=active
GET /groups/:id/milestones?state=closed
GET /groups/:id/milestones?title=1.0
GET /groups/:id/milestones?search=version
+GET /groups/:id/milestones?updated_before=2013-10-02T09%3A24%3A18Z
+GET /groups/:id/milestones?updated_after=2013-10-02T09%3A24%3A18Z
```
Parameters:
@@ -32,7 +34,9 @@ Parameters:
| `state` | string | no | Return only `active` or `closed` milestones |
| `title` | string | no | Return only the milestones having the given `title` |
| `search` | string | no | Return only milestones with a title or description matching the provided string |
-| `include_parent_milestones` | boolean | optional | Include milestones from parent group and its ancestors. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196066) in GitLab 13.4 |
+| `include_parent_milestones` | boolean | no | Include milestones from parent group and its ancestors. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196066) in GitLab 13.4 |
+| `updated_before` | datetime | no | Return only milestones updated before the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). Introduced in GitLab 15.10 |
+| `updated_after` | datetime | no | Return only milestones updated after the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). Introduced in GitLab 15.10 |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/milestones"
diff --git a/doc/api/group_protected_branches.md b/doc/api/group_protected_branches.md
new file mode 100644
index 00000000000..db648f6870e
--- /dev/null
+++ b/doc/api/group_protected_branches.md
@@ -0,0 +1,469 @@
+---
+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-level protected branches API **(PREMIUM SELF)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110603) in GitLab 15.9 [with a flag](../administration/feature_flags.md) named `group_protected_branches`. 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 `group_protected_branches`.
+On GitLab.com, this feature is not available.
+
+## Valid access levels
+
+The access levels are defined in the `ProtectedRefAccess.allowed_access_levels` method.
+These levels are recognized:
+
+```plaintext
+0 => No access
+30 => Developer access
+40 => Maintainer access
+60 => Admin access
+```
+
+## List protected branches
+
+Gets a list of protected branches from a group. If a wildcard is set, it is returned instead
+of the exact name of the branches that match that wildcard.
+
+```plaintext
+GET /groups/:id/protected_branches
+```
+
+| 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. |
+| `search` | string | no | Name or part of the name of protected branches to be searched for. |
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/groups/5/protected_branches"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "user_id": null,
+ "group_id": 1234,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "user_id": null,
+ "group_id": 1234,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "allow_force_push":false,
+ "code_owner_approval_required": false
+ },
+ {
+ "id": 1,
+ "name": "release/*",
+ "push_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "user_id": null,
+ "group_id": 1234,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "allow_force_push":false,
+ "code_owner_approval_required": false
+ },
+ ...
+]
+```
+
+## Get a single protected branch or wildcard protected branch
+
+Gets a single protected branch or wildcard protected branch.
+
+```plaintext
+GET /groups/:id/protected_branches/:name
+```
+
+| 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. |
+| `name` | string | yes | The name of the branch or wildcard. |
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/groups/5/protected_branches/master"
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 1,
+ "access_level": null,
+ "user_id": null,
+ "group_id": 1234,
+ "access_level_description": "Example Merge Group"
+ }
+ ],
+ "allow_force_push":false,
+ "code_owner_approval_required": false
+}
+```
+
+## Protect repository branches
+
+Protects a single repository branch using a wildcard protected branch.
+
+```plaintext
+POST /groups/:id/protected_branches
+```
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/groups/5/protected_branches?name=*-stable&push_access_level=30&merge_access_level=30&unprotect_access_level=40"
+```
+
+| 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. |
+| `name` | string | yes | The name of the branch or wildcard. |
+| `allow_force_push` | boolean | no | Allow all users with push access to force push. Default: `false`. |
+| `allowed_to_merge` | array | no | Array of access levels allowed to merge, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`. |
+| `allowed_to_push` | array | no | Array of access levels allowed to push, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`. |
+| `allowed_to_unprotect` | array | no | Array of access levels allowed to unprotect, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`. |
+| `code_owner_approval_required` | boolean | no | Prevent pushes to this branch if it matches an item in the [`CODEOWNERS` file](../user/project/code_owners.md). Default: `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. |
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "name": "*-stable",
+ "push_access_levels": [
+ {
+ "id": 1,
+ "access_level": 30,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 1,
+ "access_level": 30,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "unprotect_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "allow_force_push":false,
+ "code_owner_approval_required": false
+}
+```
+
+### Example with user / group level access
+
+Elements in the `allowed_to_push` / `allowed_to_merge` / `allowed_to_unprotect` array should take the
+form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`. Each user must have
+access to the project and each group must
+[have this project shared](../user/project/members/share_project_with_groups.md). These access levels
+allow [more granular control over protected branch access](../user/project/protected_branches.md).
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/groups/5/protected_branches?name=*-stable&allowed_to_push%5B%5D%5Buser_id%5D=1"
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "name": "*-stable",
+ "push_access_levels": [
+ {
+ "id": 1,
+ "access_level": null,
+ "user_id": 1,
+ "group_id": null,
+ "access_level_description": "Administrator"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "unprotect_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "allow_force_push":false,
+ "code_owner_approval_required": false
+}
+```
+
+### Example with allow to push and allow to merge access
+
+Example request:
+
+```shell
+curl --request POST \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --header "Content-Type: application/json" \
+ --data '{
+ "name": "master",
+ "allowed_to_push": [{"access_level": 30}],
+ "allowed_to_merge": [{
+ "access_level": 30
+ },{
+ "access_level": 40
+ }
+ ]}'
+ "https://gitlab.example.com/api/v4/groups/5/protected_branches"
+```
+
+Example response:
+
+```json
+{
+ "id": 5,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 1,
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ "user_id": null,
+ "group_id": null
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 1,
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ "user_id": null,
+ "group_id": null
+ },
+ {
+ "id": 2,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": null,
+ "group_id": null
+ }
+ ],
+ "unprotect_access_levels": [
+ {
+ "id": 1,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": null,
+ "group_id": null
+ }
+ ],
+ "allow_force_push":false,
+ "code_owner_approval_required": false
+}
+```
+
+## Unprotect repository branches
+
+Unprotects the given protected branch or wildcard protected branch.
+
+```plaintext
+DELETE /groups/:id/protected_branches/:name
+```
+
+```shell
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/groups/5/protected_branches/*-stable"
+```
+
+| 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. |
+| `name` | string | yes | The name of the branch. |
+
+Example response:
+
+```json
+{
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 12,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": null,
+ "group_id": null
+ }
+ ]
+}
+```
+
+## Update a protected branch
+
+Updates a protected branch.
+
+```plaintext
+PATCH /groups/:id/protected_branches/:name
+```
+
+```shell
+curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/groups/5/protected_branches/feature-branch?allow_force_push=true&code_owner_approval_required=true"
+```
+
+| 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. |
+| `name` | string | yes | The name of the branch. |
+| `allow_force_push` | boolean | no | When enabled, members who can push to this branch can also force push. |
+| `allowed_to_push` | array | no | Array of push access levels, with each described by a hash. |
+| `allowed_to_merge` | array | no | Array of merge access levels, with each described by a hash. |
+| `allowed_to_unprotect` | array | no | Array of unprotect access levels, with each described by a hash. |
+| `code_owner_approval_required` | boolean | no | Prevent pushes to this branch if it matches an item in the [`CODEOWNERS` file](../user/project/code_owners.md). Default: `false`. |
+
+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`.
+- Take the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
+
+To update:
+
+- `user_id`: Ensure the updated user has access to the project. You must also pass the
+ `id` of the `access_level` in the respective hash.
+- `group_id`: Ensure the updated group [has this project shared](../user/project/members/share_project_with_groups.md).
+ You must also pass the `id` of the `access_level` in the respective hash.
+
+To delete:
+
+- You must pass `_destroy` set to `true`. See the following examples.
+
+### Example: create a `push_access_level` record
+
+```shell
+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"
+```
+
+Example response:
+
+```json
+{
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 12,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": null,
+ "group_id": null
+ }
+ ]
+}
+```
+
+### Example: update a `push_access_level` record
+
+```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"
+```
+
+Example response:
+
+```json
+{
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 12,
+ "access_level": 0,
+ "access_level_description": "No One",
+ "user_id": null,
+ "group_id": null
+ }
+ ]
+}
+```
+
+### Example: delete a `push_access_level` record
+
+```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"
+```
+
+Example response:
+
+```json
+{
+ "name": "master",
+ "push_access_levels": []
+}
+```
diff --git a/doc/api/group_protected_environments.md b/doc/api/group_protected_environments.md
index 3003b6b840f..bddfd774d43 100644
--- a/doc/api/group_protected_environments.md
+++ b/doc/api/group_protected_environments.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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, howto
---
diff --git a/doc/api/group_releases.md b/doc/api/group_releases.md
index 9c395adbe04..978218041f2 100644
--- a/doc/api/group_releases.md
+++ b/doc/api/group_releases.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/groups.md b/doc/api/groups.md
index 8b4850fa6de..8c0e94ece28 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
@@ -110,11 +110,14 @@ GET /groups?statistics=true
"packages_size": 0,
"snippets_size": 50,
"uploads_size": 0
- }
+ },
+ "wiki_access_level": "private"
}
]
```
+Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see the `wiki_access_level` attribute.
+
You can search for groups by name or path, see below.
You can filter by [custom attributes](custom_attributes.md) with:
@@ -184,6 +187,8 @@ GET /groups/:id/subgroups
]
```
+Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see the `wiki_access_level` attribute.
+
## List a group's descendant groups
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217115) in GitLab 13.5
@@ -267,6 +272,8 @@ GET /groups/:id/descendant_groups
]
```
+Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see the `wiki_access_level` attribute.
+
## List a group's projects
Get a list of projects in this group. When accessed without authentication, only public projects are returned.
@@ -695,10 +702,15 @@ Example response:
The `prevent_sharing_groups_outside_hierarchy` attribute is present only on top-level groups.
-Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see
-the `shared_runners_minutes_limit` and `extra_shared_runners_minutes_limit` parameters:
+Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see the attributes:
+
+- `shared_runners_minutes_limit`
+- `extra_shared_runners_minutes_limit`
+- `marked_for_deletion_on`
+- `membership_lock`
+- `wiki_access_level`
-Additional response parameters:
+Additional response attributes:
```json
{
@@ -706,30 +718,9 @@ Additional response parameters:
"description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
"shared_runners_minutes_limit": 133,
"extra_shared_runners_minutes_limit": 133,
- ...
-}
-```
-
-Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see
-the `marked_for_deletion_on` attribute:
-
-```json
-{
- "id": 4,
- "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
"marked_for_deletion_on": "2020-04-03",
- ...
-}
-```
-
-Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see
-the `membership_lock` attribute:
-
-```json
-{
- "id": 4,
- "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
"membership_lock": false,
+ "wiki_access_level": "disabled",
...
}
```
@@ -832,6 +823,7 @@ Parameters:
| `membership_lock` **(PREMIUM)** | 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 CI/CD minutes for this group. |
| `shared_runners_minutes_limit` **(PREMIUM SELF)** | integer | no | Can be set by administrators only. Maximum number of monthly CI/CD 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`. |
### Options for `default_branch_protection`
@@ -996,6 +988,7 @@ PUT /groups/:id
| `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`. |
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).
@@ -1078,6 +1071,8 @@ Example response:
The `prevent_sharing_groups_outside_hierarchy` attribute is present in the response only for top-level groups.
+Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see the `wiki_access_level` attribute.
+
### Disable the results limit **(FREE SELF)**
The 100 results limit can break integrations developed using GitLab 12.4 and earlier.
diff --git a/doc/api/import.md b/doc/api/import.md
index 5e9fbf30226..87bbb56869d 100644
--- a/doc/api/import.md
+++ b/doc/api/import.md
@@ -6,6 +6,21 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Import API **(FREE)**
+Use the Import API to import repositories from GitHub or Bitbucket Server.
+
+Related APIs include:
+
+- [Group migration by direct transfer API](bulk_imports.md)
+- [Group import and export API](group_import_export.md)
+- [Project import and export API](project_import_export.md)
+
+## Prerequisites
+
+For information on prerequisites for using the Import API, see:
+
+- [Prerequisites for GitHub importer](../user/project/import/github.md#prerequisites)
+- [Prerequisites for Bitbucket Server importer](../user/project/import/bitbucket_server.md#import-your-bitbucket-repositories)
+
## Import repository from GitHub
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/381902) in GitLab 15.8, GitLab no longer automatically creates namespaces or groups if the namespace or group name specified in `target_namespace` doesn't exist. GitLab also no longer falls back to using the user's personal namespace if the namespace or group name is taken or `target_namespace` is blank.
@@ -77,7 +92,7 @@ token:
- The GitLab project inherits the original project's visibility settings. As a result, the project is publicly accessible if the original project is public.
- If the `path` or `target_namespace` does not exist, the project import fails.
-## Cancel GitHub project import
+### Cancel GitHub project import
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/364783) in GitLab 15.5.
@@ -122,13 +137,14 @@ Returns the following status codes:
- `400 Bad Request`: the project import cannot be canceled.
- `404 Not Found`: the project associated with `project_id` does not exist.
-## Import GitHub gists into GitLab snippets
+### Import GitHub gists into GitLab snippets
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371099) in GitLab 15.8 [with a flag](../administration/feature_flags.md) named `github_import_gists`. Disabled by default. Enabled on GitLab.com.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371099) in GitLab 15.8 [with a flag](../administration/feature_flags.md) named `github_import_gists`. Disabled by default. Enabled on GitLab.com.
+> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/386579) in GitLab 15.10.
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 `github_import_gists`.
+On self-managed GitLab, this feature is available by default. To hide the feature,
+ask an administrator to [disable the feature flag](../administration/feature_flags.md) named `github_import_gists`.
On GitLab.com, this feature is available.
You can use the GitLab API to import personal GitHub gists (with up to 10 files) into personal GitLab snippets.
diff --git a/doc/api/instance_clusters.md b/doc/api/instance_clusters.md
index 45243003004..51296c2e96e 100644
--- a/doc/api/instance_clusters.md
+++ b/doc/api/instance_clusters.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Instance clusters API (certificate-based) (DEPRECATED) **(FREE SELF)**
+# Instance clusters API (certificate-based) (deprecated) **(FREE SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36001) in GitLab 13.2.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/api/instance_level_ci_variables.md b/doc/api/instance_level_ci_variables.md
index e71cf777b2c..840744bcae1 100644
--- a/doc/api/instance_level_ci_variables.md
+++ b/doc/api/instance_level_ci_variables.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
---
diff --git a/doc/api/integrations.md b/doc/api/integrations.md
index 24e0f189aad..e25753b892e 100644
--- a/doc/api/integrations.md
+++ b/doc/api/integrations.md
@@ -96,7 +96,7 @@ Parameters:
### Disable Apple App Store integration
-Disable the Apple App Store integration for a project. Integration settings are preserved.
+Disable the Apple App Store integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/apple_app_store
@@ -133,7 +133,7 @@ Parameters:
### Disable Asana integration
-Disable the Asana integration for a project. Integration settings are preserved.
+Disable the Asana integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/asana
@@ -168,7 +168,7 @@ Parameters:
### Disable Assembla integration
-Disable the Assembla integration for a project. Integration settings are preserved.
+Disable the Assembla integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/assembla
@@ -208,7 +208,7 @@ Parameters:
### Disable Atlassian Bamboo CI integration
-Disable the Atlassian Bamboo CI integration for a project. Integration settings are preserved.
+Disable the Atlassian Bamboo CI integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/bamboo
@@ -244,7 +244,7 @@ Parameters:
### Disable Bugzilla integration
-Disable the Bugzilla integration for a project. Integration settings are preserved.
+Disable the Bugzilla integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/bugzilla
@@ -283,7 +283,7 @@ Parameters:
### Disable Buildkite integration
-Disable the Buildkite integration for a project. Integration settings are preserved.
+Disable the Buildkite integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/buildkite
@@ -320,7 +320,7 @@ Parameters:
### Disable Campfire integration
-Disable the Campfire integration for a project. Integration settings are preserved.
+Disable the Campfire integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/campfire
@@ -360,7 +360,7 @@ Parameters:
### Disable Datadog integration
-Disable the Datadog integration for a project. Integration settings are preserved.
+Disable the Datadog integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/datadog
@@ -405,7 +405,7 @@ Parameters:
### Disable Unify Circuit integration
-Disable the Unify Circuit integration for a project. Integration settings are preserved.
+Disable the Unify Circuit integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/unify-circuit
@@ -450,7 +450,7 @@ Parameters:
### Disable Pumble integration
-Disable the Pumble integration for a project. Integration settings are preserved.
+Disable the Pumble integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/pumble
@@ -495,7 +495,7 @@ Parameters:
### Disable Webex Teams integration
-Disable the Webex Teams integration for a project. Integration settings are preserved.
+Disable the Webex Teams integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/webex-teams
@@ -531,7 +531,7 @@ Parameters:
### Disable Custom Issue Tracker integration
-Disable the Custom Issue Tracker integration for a project. Integration settings are preserved.
+Disable the Custom Issue Tracker integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/custom-issue-tracker
@@ -565,7 +565,7 @@ Parameters:
### Disable Discord integration
-Disable the Discord integration for a project. Integration settings are preserved.
+Disable the Discord integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/discord
@@ -604,7 +604,7 @@ Parameters:
### Disable Drone CI integration
-Disable the Drone CI integration for a project. Integration settings are preserved.
+Disable the Drone CI integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/drone-ci
@@ -643,7 +643,7 @@ Parameters:
### Disable Emails on Push integration
-Disable the Emails on Push integration for a project. Integration settings are preserved.
+Disable the Emails on Push integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/emails-on-push
@@ -679,7 +679,7 @@ Parameters:
### Disable EWM integration
-Disable the EWM integration for a project. Integration settings are preserved.
+Disable the EWM integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/ewm
@@ -715,7 +715,7 @@ Parameters:
### Disable Confluence integration
-Disable the Confluence integration for a project. Integration settings are preserved.
+Disable the Confluence integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/confluence
@@ -753,7 +753,7 @@ Parameters:
### Disable Shimo integration
-Disable the Shimo integration for a project. Integration settings are preserved.
+Disable the Shimo integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/shimo
@@ -779,7 +779,7 @@ Parameters:
### Disable External wiki integration
-Disable the External wiki integration for a project. Integration settings are preserved.
+Disable the External wiki integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/external-wiki
@@ -815,7 +815,7 @@ Parameters:
### Disable GitHub integration
-Disable the GitHub integration for a project. Integration settings are preserved.
+Disable the GitHub integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/github
@@ -861,7 +861,7 @@ Parameters:
### Disable Hangouts Chat integration
-Disable the Hangouts Chat integration for a project. Integration settings are preserved.
+Disable the Hangouts Chat integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/hangouts-chat
@@ -901,7 +901,7 @@ Parameters:
### Disable Irker (IRC gateway) integration
-Disable the Irker (IRC gateway) integration for a project. Integration settings are preserved.
+Disable the Irker (IRC gateway) integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/irker
@@ -952,7 +952,7 @@ Parameters:
### Disable Jira integration
-Disable the Jira integration for a project. Integration settings are preserved.
+Disable the Jira integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/jira
@@ -1011,7 +1011,7 @@ Parameters:
### Disable Slack Slash Command integration
-Disable the Slack Slash Command integration for a project. Integration settings are preserved.
+Disable the Slack Slash Command integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/slack-slash-commands
@@ -1045,7 +1045,7 @@ Parameters:
### Disable Mattermost Slash Command integration
-Disable the Mattermost Slash Command integration for a project. Integration settings are preserved.
+Disable the Mattermost Slash Command integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/mattermost-slash-commands
@@ -1076,7 +1076,7 @@ Parameters:
### Disable Packagist integration
-Disable the Packagist integration for a project. Integration settings are preserved.
+Disable the Packagist integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/packagist
@@ -1114,7 +1114,7 @@ Parameters:
### Disable Pipeline-Emails integration
-Disable the Pipeline-Emails integration for a project. Integration settings are preserved.
+Disable the Pipeline-Emails integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/pipelines-email
@@ -1151,7 +1151,7 @@ Parameters:
### Disable Pivotal Tracker integration
-Disable the Pivotal Tracker integration for a project. Integration settings are preserved.
+Disable the Pivotal Tracker integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/pivotaltracker
@@ -1187,7 +1187,7 @@ Parameters:
### Disable Prometheus integration
-Disable the Prometheus integration for a project. Integration settings are preserved.
+Disable the Prometheus integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/prometheus
@@ -1225,7 +1225,7 @@ Parameters:
### Disable Pushover integration
-Disable the Pushover integration for a project. Integration settings are preserved.
+Disable the Pushover integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/pushover
@@ -1261,7 +1261,7 @@ Parameters:
### Disable Redmine integration
-Disable the Redmine integration for a project. Integration settings are preserved.
+Disable the Redmine integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/redmine
@@ -1322,7 +1322,7 @@ Parameters:
### Disable Slack integration
-Disable the Slack integration for a project. Integration settings are preserved.
+Disable the Slack integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/slack
@@ -1368,7 +1368,7 @@ Parameters:
### Disable Microsoft Teams integration
-Disable the Microsoft Teams integration for a project. Integration settings are preserved.
+Disable the Microsoft Teams integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/microsoft-teams
@@ -1425,7 +1425,7 @@ Parameters:
### Disable Mattermost notifications integration
-Disable the Mattermost notifications integration for a project. Integration settings are preserved.
+Disable the Mattermost notifications integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/mattermost
@@ -1467,7 +1467,7 @@ Parameters:
### Disable JetBrains TeamCity CI integration
-Disable the JetBrains TeamCity CI integration for a project. Integration settings are preserved.
+Disable the JetBrains TeamCity CI integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/teamcity
@@ -1508,7 +1508,7 @@ Parameters:
### Disable Jenkins CI integration
-Disable the Jenkins CI integration for a project. Integration settings are preserved.
+Disable the Jenkins CI integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/jenkins
@@ -1545,7 +1545,7 @@ Parameters:
### Disable Jenkins CI (Deprecated) integration
-Disable the Jenkins CI (Deprecated) integration for a project. Integration settings are preserved.
+Disable the Jenkins CI (Deprecated) integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/jenkins-deprecated
@@ -1582,7 +1582,7 @@ Parameters:
### Disable MockCI integration
-Disable the MockCI integration for a project. Integration settings are preserved.
+Disable the MockCI integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/mock-ci
@@ -1596,6 +1596,43 @@ Get MockCI integration settings for a project.
GET /projects/:id/integrations/mock-ci
```
+## Squash TM
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337855) in GitLab 15.10.
+
+Update [Squash TM](https://www.squashtest.com/product-squash-tm?lang=en) requirements when GitLab issues are modified.
+
+### Create/Edit Squash TM integration
+
+Set Squash TM integration settings for a project.
+
+```plaintext
+PUT /projects/:id/integrations/squash-tm
+```
+
+Parameters:
+
+| Parameter | Type | Required | Description |
+|-------------------------|--------|----------|-------------------------------|
+| `url` | string | yes | URL of the Squash TM webhook. |
+| `token` | string | no | Optional token |
+
+### Disable Squash TM integration
+
+Disable the Squash TM integration for a project. Integration settings are preserved.
+
+```plaintext
+DELETE /projects/:id/integrations/squash-tm
+```
+
+### Get Squash TM integration settings
+
+Get Squash TM integration settings for a project.
+
+```plaintext
+GET /projects/:id/integrations/squash-tm
+```
+
## YouTrack
YouTrack issue tracker
@@ -1617,7 +1654,7 @@ Parameters:
### Disable YouTrack integration
-Disable the YouTrack integration for a project. Integration settings are preserved.
+Disable the YouTrack integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/youtrack
diff --git a/doc/api/iterations.md b/doc/api/iterations.md
index 4997a917a5a..ca280437eaf 100644
--- a/doc/api/iterations.md
+++ b/doc/api/iterations.md
@@ -24,6 +24,8 @@ GET /projects/:id/iterations?state=opened
GET /projects/:id/iterations?state=closed
GET /projects/:id/iterations?search=version
GET /projects/:id/iterations?include_ancestors=false
+GET /projects/:id/iterations?updated_before=2013-10-02T09%3A24%3A18Z
+GET /projects/:id/iterations?updated_after=2013-10-02T09%3A24%3A18Z
```
| Attribute | Type | Required | Description |
@@ -31,6 +33,8 @@ GET /projects/:id/iterations?include_ancestors=false
| `state` | string | no | 'Return `opened`, `upcoming`, `current (previously started)`, `closed`, or `all` iterations. Filtering by `started` state is deprecated starting with 14.1, please use `current` instead.' |
| `search` | string | no | Return only iterations with a title matching the provided string. |
| `include_ancestors` | boolean | no | Include iterations from parent group and its ancestors. Defaults to `true`. |
+| `updated_before` | datetime | no | Return only iterations updated before the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378662) in GitLab 15.10. |
+| `updated_after` | datetime | no | Return only iterations updated after the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378662) in GitLab 15.10. |
Example request:
diff --git a/doc/api/job_artifacts.md b/doc/api/job_artifacts.md
index b73eafea3c4..715b0614cc4 100644
--- a/doc/api/job_artifacts.md
+++ b/doc/api/job_artifacts.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/api/keys.md b/doc/api/keys.md
index e7bdc70017c..90144310238 100644
--- a/doc/api/keys.md
+++ b/doc/api/keys.md
@@ -7,6 +7,8 @@ type: reference, api
# Keys API **(FREE)**
+If using a SHA256 fingerprint in an API call, you should URL-encode the fingerprint.
+
## Get SSH key with user by ID of an SSH key
Get SSH key with user by ID of an SSH key. Note only administrators can lookup SSH key with user by ID of an SSH key.
@@ -22,7 +24,8 @@ GET /keys/:id
Example request:
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/keys/1"
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/keys/1"
```
```json
@@ -82,15 +85,8 @@ GET /keys
Example request:
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/keys?fingerprint=ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1"
-```
-
-If using sha256 fingerprint API calls, make sure that the fingerprint is URL-encoded.
-
-For example, `/` is represented by `%2F` and `:` is represented by`%3A`:
-
-```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/keys?fingerprint=SHA256%3AnUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo%2FlCg"
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/keys?fingerprint=ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1"
```
Example response:
@@ -142,15 +138,21 @@ Example response:
## Get user by deploy key fingerprint
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/119209) in GitLab 12.7.
+Deploy keys are bound to the creating user. If you query with a deploy key
+fingerprint, you get additional information about the projects using that key.
-Deploy keys are bound to the creating user, so if you query with a deploy key
-fingerprint you get additional information about the projects using that key.
+Example request with an MD5 fingerprint:
-Example request:
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/keys?fingerprint=ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1"
+```
+
+In this SHA256 example, `/` is represented by `%2F` and `:` is represented by`%3A`:
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/keys?fingerprint=SHA256%3AnUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo%2FlCg"
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/keys?fingerprint=SHA256%3AnUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo%2FlCg"
```
Example response:
diff --git a/doc/api/license.md b/doc/api/license.md
index ca9d9cf386d..39da6af30d4 100644
--- a/doc/api/license.md
+++ b/doc/api/license.md
@@ -233,3 +233,35 @@ Returns:
- `204 No Content` if the license is successfully deleted.
- `403 Forbidden` if the current user in not permitted to delete the license.
- `404 Not Found` if the license to delete could not be found.
+
+## Trigger recalculation of billable users
+
+```plaintext
+PUT /license/:id/refresh_billable_users
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | ID of the GitLab license. |
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/license/:id/refresh_billable_users"
+```
+
+Example response:
+
+```json
+{
+ "success": true
+}
+```
+
+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.
+
+| Attribute | Type | Description |
+|:-----------------------------|:--------------|:------------------------------------------|
+| `success` | boolean | Whether the request succeeded or not. |
diff --git a/doc/api/lint.md b/doc/api/lint.md
index e50832a9528..9de9aa23560 100644
--- a/doc/api/lint.md
+++ b/doc/api/lint.md
@@ -6,7 +6,113 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# CI Lint API **(FREE)**
-## Validate the CI YAML configuration
+## Validate a CI YAML configuration with a namespace
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231352) in GitLab 13.6.
+
+Checks if CI/CD YAML configuration is valid. This endpoint has namespace
+specific context.
+
+```plaintext
+POST /projects/:id/ci/lint
+```
+
+| Attribute | Type | Required | Description |
+| ---------- | ------- | -------- | -------- |
+| `content` | string | yes | The CI/CD configuration content. |
+| `dry_run` | boolean | no | Run [pipeline creation simulation](../ci/lint.md#simulate-a-pipeline), or only do static check. This is false by default. |
+| `include_jobs` | boolean | no | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. This is false by default. |
+| `ref` | string | no | When `dry_run` is `true`, sets the branch or tag to use. Defaults to the project's default branch when not set. |
+
+Example request:
+
+```shell
+curl --header "Content-Type: application/json" "https://gitlab.example.com/api/v4/projects/:id/ci/lint" --data '{"content": "{ \"image\": \"ruby:2.6\", \"services\": [\"postgres\"], \"before_script\": [\"bundle install\", \"bundle exec rake db:create\"], \"variables\": {\"DB_NAME\": \"postgres\"}, \"types\": [\"test\", \"deploy\", \"notify\"], \"rspec\": { \"script\": \"rake spec\", \"tags\": [\"ruby\", \"postgres\"], \"only\": [\"branches\"]}}"}'
+```
+
+Example responses:
+
+- Valid configuration:
+
+ ```json
+ {
+ "valid": true,
+ "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
+ "errors": [],
+ "warnings": []
+ }
+ ```
+
+- Invalid configuration:
+
+ ```json
+ {
+ "valid": false,
+ "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
+ "errors": [
+ "jobs config should contain at least one visible job"
+ ],
+ "warnings": []
+ }
+ ```
+
+## Validate a project's CI configuration
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231352) in GitLab 13.5.
+
+Checks if a project's latest (`HEAD` of the project's default branch)
+`.gitlab-ci.yml` configuration is valid. This endpoint uses all namespace
+specific data available, including variables and local includes.
+
+```plaintext
+GET /projects/:id/ci/lint
+```
+
+| Attribute | Type | Required | Description |
+| ---------- | ------- | -------- | -------- |
+| `dry_run` | boolean | no | Run pipeline creation simulation, or only do static check. |
+| `include_jobs` | boolean | no | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. This is false by default. |
+| `ref` | string | no | When `dry_run` is `true`, sets the branch or tag to use. Defaults to the project's default branch when not set. |
+
+Example request:
+
+```shell
+curl "https://gitlab.example.com/api/v4/projects/:id/ci/lint"
+```
+
+Example responses:
+
+- Valid configuration:
+
+```json
+{
+ "valid": true,
+ "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
+ "errors": [],
+ "warnings": []
+}
+```
+
+- Invalid configuration:
+
+```json
+{
+ "valid": false,
+ "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
+ "errors": [
+ "jobs config should contain at least one visible job"
+ ],
+ "warnings": []
+}
+```
+
+<!--- start_remove The following content will be removed on remove_date: '2023-08-22' -->
+
+## Validate the CI YAML configuration (deprecated)
+
+WARNING:
+This endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/381669) in GitLab 15.7
+and is planned for removal in 16.0. Use [`POST /projects/:id/ci/lint`](#validate-a-ci-yaml-configuration-with-a-namespace) instead.
Checks if CI/CD YAML configuration is valid. This endpoint validates basic CI/CD
configuration syntax. It doesn't have any namespace-specific context.
@@ -154,105 +260,7 @@ Example response:
}
```
-## Validate a CI YAML configuration with a namespace
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231352) in GitLab 13.6.
-
-Checks if CI/CD YAML configuration is valid. This endpoint has namespace
-specific context.
-
-```plaintext
-POST /projects/:id/ci/lint
-```
-
-| Attribute | Type | Required | Description |
-| ---------- | ------- | -------- | -------- |
-| `content` | string | yes | The CI/CD configuration content. |
-| `dry_run` | boolean | no | Run [pipeline creation simulation](../ci/lint.md#simulate-a-pipeline), or only do static check. This is false by default. |
-| `include_jobs` | boolean | no | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. This is false by default. |
-| `ref` | string | no | When `dry_run` is `true`, sets the branch or tag to use. Defaults to the project's default branch when not set. |
-
-Example request:
-
-```shell
-curl --header "Content-Type: application/json" "https://gitlab.example.com/api/v4/projects/:id/ci/lint" --data '{"content": "{ \"image\": \"ruby:2.6\", \"services\": [\"postgres\"], \"before_script\": [\"bundle install\", \"bundle exec rake db:create\"], \"variables\": {\"DB_NAME\": \"postgres\"}, \"types\": [\"test\", \"deploy\", \"notify\"], \"rspec\": { \"script\": \"rake spec\", \"tags\": [\"ruby\", \"postgres\"], \"only\": [\"branches\"]}}"}'
-```
-
-Example responses:
-
-- Valid configuration:
-
- ```json
- {
- "valid": true,
- "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
- "errors": [],
- "warnings": []
- }
- ```
-
-- Invalid configuration:
-
- ```json
- {
- "valid": false,
- "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
- "errors": [
- "jobs config should contain at least one visible job"
- ],
- "warnings": []
- }
- ```
-
-## Validate a project's CI configuration
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231352) in GitLab 13.5.
-
-Checks if a project's latest (`HEAD` of the project's default branch)
-`.gitlab-ci.yml` configuration is valid. This endpoint uses all namespace
-specific data available, including variables and local includes.
-
-```plaintext
-GET /projects/:id/ci/lint
-```
-
-| Attribute | Type | Required | Description |
-| ---------- | ------- | -------- | -------- |
-| `dry_run` | boolean | no | Run pipeline creation simulation, or only do static check. |
-| `include_jobs` | boolean | no | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. This is false by default. |
-| `ref` | string | no | When `dry_run` is `true`, sets the branch or tag to use. Defaults to the project's default branch when not set. |
-
-Example request:
-
-```shell
-curl "https://gitlab.example.com/api/v4/projects/:id/ci/lint"
-```
-
-Example responses:
-
-- Valid configuration:
-
-```json
-{
- "valid": true,
- "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
- "errors": [],
- "warnings": []
-}
-```
-
-- Invalid configuration:
-
-```json
-{
- "valid": false,
- "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
- "errors": [
- "jobs config should contain at least one visible job"
- ],
- "warnings": []
-}
-```
+<!--- end_remove -->
## Use jq to create and process YAML & JSON payloads
diff --git a/doc/api/managed_licenses.md b/doc/api/managed_licenses.md
index 6aee60c57e0..b98be629e90 100644
--- a/doc/api/managed_licenses.md
+++ b/doc/api/managed_licenses.md
@@ -4,7 +4,10 @@ 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
---
-# Managed Licenses API **(ULTIMATE)**
+# Managed Licenses API (deprecated) **(ULTIMATE)**
+
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390417) in GitLab 15.9.
WARNING:
"approval" and "blacklisted" approval statuses are changed to "allowed" and "denied" in GitLab 15.0.
diff --git a/doc/api/member_roles.md b/doc/api/member_roles.md
index a7fc93e0df5..3ef6e287418 100644
--- a/doc/api/member_roles.md
+++ b/doc/api/member_roles.md
@@ -63,6 +63,8 @@ Adds a member role to a group.
POST /groups/:id/member_roles
```
+To add a member role to a group, the group must be at root-level (have no parent group).
+
| 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. |
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index 0df2b90e64d..79a70bddfee 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -312,7 +312,7 @@ Supported attributes:
| `applies_to_all_protected_branches` | boolean | **{dotted-circle}** No | Whether the rule is applied to all protected branches. If set to `true`, the value of `protected_branch_ids` is ignored. Default is `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335316) in GitLab 15.3. |
| `group_ids` | Array | **{dotted-circle}** No | The IDs of groups as approvers. |
| `protected_branch_ids` | Array | **{dotted-circle}** No | The IDs of protected branches to scope the rule by. To identify the ID, [use the API](protected_branches.md#list-protected-branches). |
-| `report_type` | string | **{dotted-circle}** No | The report type required when the rule type is `report_approver`. The supported report types are `license_scanning` and `code_coverage`. |
+| `report_type` | string | **{dotted-circle}** No | The report type required when the rule type is `report_approver`. The supported report types are `license_scanning` [(Deprecated in GitLab 15.9)](../update/deprecations.md#license-check-and-the-policies-tab-on-the-license-compliance-page) and `code_coverage`. |
| `rule_type` | string | **{dotted-circle}** No | The type of rule. `any_approver` is a pre-configured default rule with `approvals_required` at `0`. Other rules are `regular`. |
| `user_ids` | Array | **{dotted-circle}** No | The IDs of users as approvers. |
| `usernames` | string array | **{dotted-circle}** No | The usernames for this rule. |
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 024593b2c6b..3e5982faee8 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -1174,7 +1174,8 @@ Example response:
## List merge request pipelines
-Get a list of merge request pipelines.
+Get a list of merge request pipelines. The pagination parameters `page` and
+`per_page` can be used to restrict the list of merge request pipelines.
```plaintext
GET /projects/:id/merge_requests/:merge_request_iid/pipelines
diff --git a/doc/api/merge_trains.md b/doc/api/merge_trains.md
index 6d5d12a618c..afa5b38b9c3 100644
--- a/doc/api/merge_trains.md
+++ b/doc/api/merge_trains.md
@@ -220,3 +220,74 @@ Example response:
"duration":null
}
```
+
+## Add a merge request to a merge train
+
+Add a merge request to the merge train targeting the merge request's target branch.
+
+```plaintext
+POST /projects/:id/merge_trains/merge_requests/:merge_request_iid
+```
+
+Supported attributes:
+
+| Attribute | Type | Required | Description |
+| ------------------------------ | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `merge_request_iid` | integer | yes | The internal ID of the merge request. |
+| `when_pipeline_succeeds` | boolean | no | If true, the merge request is added to the merge train when the pipeline succeeds. When false or unspecified, the merge request is added directly to the merge train. |
+| `sha` | string | no | If present, the SHA must match the `HEAD` of the source branch, otherwise the merge fails. |
+| `squash` | boolean | no | If true, the commits are squashed into a single commit on merge. |
+
+Example request:
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/597/merge_trains/merge_requests/1"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 267,
+ "merge_request": {
+ "id": 273,
+ "iid": 1,
+ "project_id": 597,
+ "title": "My title 9",
+ "description": null,
+ "state": "opened",
+ "created_at": "2022-10-31T19:06:05.725Z",
+ "updated_at": "2022-10-31T19:06:05.725Z",
+ "web_url": "http://localhost/namespace18/project21/-/merge_requests/1"
+ },
+ "user": {
+ "id": 933,
+ "username": "user12",
+ "name": "Sidney Jones31",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/6c8365de387cb3db10ecc7b1880203c4?s=80\u0026d=identicon",
+ "web_url": "http://localhost/user12"
+ },
+ "pipeline": {
+ "id": 273,
+ "iid": 1,
+ "project_id": 598,
+ "sha": "b83d6e391c22777fca1ed3012fce84f633d7fed0",
+ "ref": "main",
+ "status": "pending",
+ "source": "push",
+ "created_at": "2022-10-31T19:06:06.231Z",
+ "updated_at": "2022-10-31T19:06:06.231Z",
+ "web_url": "http://localhost/namespace19/project22/-/pipelines/273"
+ },
+ "created_at": "2022-10-31T19:06:06.237Z",
+ "updated_at":"2022-10-31T19:06:06.237Z",
+ "target_branch":"main",
+ "status":"idle",
+ "merged_at":null,
+ "duration":null
+ }
+]
+```
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
index 998beeb9b3b..e1acf4c14bb 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -21,6 +21,8 @@ GET /projects/:id/milestones?state=active
GET /projects/:id/milestones?state=closed
GET /projects/:id/milestones?title=1.0
GET /projects/:id/milestones?search=version
+GET /projects/:id/milestones?updated_before=2013-10-02T09%3A24%3A18Z
+GET /projects/:id/milestones?updated_after=2013-10-02T09%3A24%3A18Z
```
Parameters:
@@ -28,11 +30,13 @@ 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 |
-| `iids[]` | integer array | optional | Return only the milestones having the given `iid` (Note: ignored if `include_parent_milestones` is set as `true`) |
-| `state` | string | optional | Return only `active` or `closed` milestones |
-| `title` | string | optional | Return only the milestones having the given `title` |
-| `search` | string | optional | Return only milestones with a title or description matching the provided string |
-| `include_parent_milestones` | boolean | optional | Include group milestones from parent group and its ancestors. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196066) in GitLab 13.4 |
+| `iids[]` | integer array | no | Return only the milestones having the given `iid` (Note: ignored if `include_parent_milestones` is set as `true`) |
+| `state` | string | no | Return only `active` or `closed` milestones |
+| `title` | string | no | Return only the milestones having the given `title` |
+| `search` | string | no | Return only milestones with a title or description matching the provided string |
+| `include_parent_milestones` | boolean | no | Include group milestones from parent group and its ancestors. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196066) in GitLab 13.4 |
+| `updated_before` | datetime | no | Return only milestones updated before the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). Introduced in GitLab 15.10 |
+| `updated_after` | datetime | no | Return only milestones updated after the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). Introduced in GitLab 15.10 |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/milestones"
diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md
index cbf7ea079bc..25c26ee9339 100644
--- a/doc/api/namespaces.md
+++ b/doc/api/namespaces.md
@@ -100,9 +100,9 @@ Owners also see the `plan` property associated with a namespace:
]
```
-Users on GitLab.com also see `max_seats_used` and `seats_in_use` parameters.
+Users on GitLab.com also see `max_seats_used`, `seats_in_use` and `max_seats_used_changed_at` parameters.
`max_seats_used` is the highest number of users the group had. `seats_in_use` is
-the number of license seats currently being used. Both values are updated
+the number of license seats currently being used. `max_seats_used_changed_at` shows the date when the `max_seats_used` value changed. All the values are updated
once a day.
`max_seats_used` and `seats_in_use` are non-zero only for namespaces on paid plans.
@@ -114,6 +114,7 @@ once a day.
"name": "user1",
"billable_members_count": 2,
"max_seats_used": 3,
+ "max_seats_used_changed_at":"2023-02-13T12:00:02.000Z",
"seats_in_use": 2,
...
}
diff --git a/doc/api/notes.md b/doc/api/notes.md
index 9c453c6390f..305bdd294c5 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -78,6 +78,7 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
"system": true,
"noteable_id": 377,
"noteable_type": "Issue",
+ "project_id": 5,
"noteable_iid": 377,
"resolvable": false,
"confidential": false,
@@ -100,6 +101,7 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
"system": true,
"noteable_id": 121,
"noteable_type": "Issue",
+ "project_id": 5,
"noteable_iid": 121,
"resolvable": false,
"confidential": true,
@@ -239,9 +241,9 @@ Parameters:
```json
{
- "id": 52,
- "title": "Snippet",
- "file_name": "snippet.rb",
+ "id": 302,
+ "body": "closed",
+ "attachment": null,
"author": {
"id": 1,
"username": "pipin",
@@ -250,9 +252,16 @@ Parameters:
"state": "active",
"created_at": "2013-09-30T13:46:01Z"
},
- "expires_at": null,
- "updated_at": "2013-10-02T07:34:20Z",
- "created_at": "2013-10-02T07:34:20Z"
+ "created_at": "2013-10-02T09:22:45Z",
+ "updated_at": "2013-10-02T10:22:45Z",
+ "system": true,
+ "noteable_id": 377,
+ "noteable_type": "Issue",
+ "project_id": 5,
+ "noteable_iid": 377,
+ "resolvable": false,
+ "confidential": false,
+ "internal": false
}
```
@@ -379,6 +388,7 @@ Parameters:
"system": false,
"noteable_id": 2,
"noteable_type": "MergeRequest",
+ "project_id": 5,
"noteable_iid": 2,
"resolvable": false,
"confidential": false,
@@ -392,8 +402,13 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
### Create new merge request note
-Creates a new note for a single merge request.
-If you create a note where the body only contains an Award Emoji, GitLab returns this object.
+Creates a new note for a single merge request. Notes are not attached to specific
+lines in a merge request. For other approaches with more granular control, see
+[Post comment to commit](commits.md#post-comment-to-commit) in the Commits API,
+and [Create a new thread in the merge request diff](discussions.md#create-a-new-thread-in-the-merge-request-diff)
+in the Discussions API.
+
+If you create a note where the body only contains an award emoji, GitLab returns this object.
```plaintext
POST /projects/:id/merge_requests/:merge_request_iid/notes
@@ -496,9 +511,9 @@ Parameters:
```json
{
- "id": 52,
- "title": "Epic",
- "file_name": "epic.rb",
+ "id": 302,
+ "body": "Epic note",
+ "attachment": null,
"author": {
"id": 1,
"username": "pipin",
@@ -507,9 +522,14 @@ Parameters:
"state": "active",
"created_at": "2013-09-30T13:46:01Z"
},
- "expires_at": null,
- "updated_at": "2013-10-02T07:34:20Z",
- "created_at": "2013-10-02T07:34:20Z",
+ "created_at": "2013-10-02T09:22:45Z",
+ "updated_at": "2013-10-02T10:22:45Z",
+ "system": true,
+ "noteable_id": 11,
+ "noteable_type": "Epic",
+ "project_id": 5,
+ "noteable_iid": 11,
+ "resolvable": false,
"confidential": false,
"internal": false
}
diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md
index 3e470c5cb91..eb9d1d3bc8a 100644
--- a/doc/api/oauth2.md
+++ b/doc/api/oauth2.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# OAuth 2.0 identity provider API **(FREE)**
GitLab provides an API to allow third-party services to access GitLab resources on a user's behalf
-with the [OAuth2](https://oauth.net/2/) protocol.
+with the [OAuth 2.0](https://oauth.net/2/) protocol.
To configure GitLab for this, see
[Configure GitLab as an OAuth 2.0 authentication identity provider](../integration/oauth_provider.md).
@@ -45,6 +45,8 @@ GitLab supports the following authorization flows:
- **Resource owner password credentials:** To be used **only** for securely
hosted, first-party services. GitLab recommends against use of this flow.
+Device Authorization Grant is not supported. [Issue 332682](https://gitlab.com/gitlab-org/gitlab/-/issues/332682) proposes to add support.
+
The draft specification for [OAuth 2.1](https://oauth.net/2.1/) specifically omits both the
Implicit grant and Resource Owner Password Credentials flows.
diff --git a/doc/api/openapi/openapi.yaml b/doc/api/openapi/openapi.yaml
index 9ee2b8119be..e090eab1e5d 100644
--- a/doc/api/openapi/openapi.yaml
+++ b/doc/api/openapi/openapi.yaml
@@ -20,7 +20,7 @@ info:
The feature uses the current [GitLab session cookie](https://docs.gitlab.com/ee/api/index.html#session-cookie),
so each request is made using your account.
- Instructions for using this tool can be found in [Interactive API Documentation](openapi_interactive.md).
+ Instructions for using this tool can be found in [Interactive API Documentation](https://docs.gitlab.com/ee/api/openapi/openapi_interactive.html).
version: v4
title: GitLab API
diff --git a/doc/api/packages.md b/doc/api/packages.md
index 32b21ce354d..86eaf3028cf 100644
--- a/doc/api/packages.md
+++ b/doc/api/packages.md
@@ -352,6 +352,9 @@ Can return the following status codes:
- `204 No Content`, if the package was deleted successfully.
- `404 Not Found`, if the package was not found.
+If [request forwarding](../user/packages/package_registry/supported_functionality.md#forwarding-requests) is enabled,
+deleting a package can introduce a [dependency confusion risk](../user/packages/package_registry/supported_functionality.md#deleting-packages).
+
## Delete a package file
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32107) in GitLab 13.12.
diff --git a/doc/api/pages.md b/doc/api/pages.md
index dbe7416b939..ed63090b9be 100644
--- a/doc/api/pages.md
+++ b/doc/api/pages.md
@@ -10,9 +10,13 @@ Endpoints for managing [GitLab Pages](https://about.gitlab.com/stages-devops-lif
The GitLab Pages feature must be enabled to use these endpoints. Find out more about [administering](../administration/pages/index.md) and [using](../user/project/pages/index.md) the feature.
-## Unpublish pages
+## Unpublish Pages
-Remove pages. The user must have administrator access.
+Prerequisite:
+
+- You must have administrator access to the instance.
+
+Remove Pages.
```plaintext
DELETE /projects/:id/pages
diff --git a/doc/api/pages_domains.md b/doc/api/pages_domains.md
index 815cea7cc63..e83811d0415 100644
--- a/doc/api/pages_domains.md
+++ b/doc/api/pages_domains.md
@@ -12,7 +12,11 @@ The GitLab Pages feature must be enabled to use these endpoints. Find out more a
## List all Pages domains
-Get a list of all Pages domains. The user must have administrator access.
+Prerequisite:
+
+- You must have administrator access to the instance.
+
+Get a list of all Pages domains.
```plaintext
GET /pages/domains
diff --git a/doc/api/pipeline_triggers.md b/doc/api/pipeline_triggers.md
index 1ffda1c0d79..50acac6bc2a 100644
--- a/doc/api/pipeline_triggers.md
+++ b/doc/api/pipeline_triggers.md
@@ -155,7 +155,7 @@ or a [CI/CD job token](../ci/jobs/ci_job_token.md) for authentication.
With a CI/CD job token, the [triggered pipeline is a multi-project pipeline](../ci/pipelines/downstream_pipelines.md#trigger-a-multi-project-pipeline-by-using-the-api).
The job that authenticates the request becomes associated with the upstream pipeline,
-which is visible on the [pipeline graph](../ci/pipelines/downstream_pipelines.md#view-multi-project-pipelines-in-pipeline-graphs).
+which is visible on the pipeline graph.
If you use a trigger token in a job, the job is not associated with the upstream pipeline.
diff --git a/doc/api/product_analytics.md b/doc/api/product_analytics.md
index c687acdb5db..8eda24d1c65 100644
--- a/doc/api/product_analytics.md
+++ b/doc/api/product_analytics.md
@@ -6,7 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Product analytics API **(ULTIMATE)**
-> Introduced in GitLab 15.4 [with a flag](../administration/feature_flags.md) named `cube_api_proxy`. Disabled by default.
+> - Introduced in GitLab 15.4 [with a flag](../administration/feature_flags.md) named `cube_api_proxy`. Disabled by default.
+> - `cube_api_proxy` removed and replaced with `product_analytics_internal_preview` in GitLab 15.10.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../administration/feature_flags.md) named `cube_api_proxy`.
diff --git a/doc/api/project_badges.md b/doc/api/project_badges.md
index 3dad40a3f96..a8940a7875c 100644
--- a/doc/api/project_badges.md
+++ b/doc/api/project_badges.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## Placeholder tokens
-Badges support placeholders that are replaced in real-time in both the link and image URL. The allowed placeholders are:
+[Badges](../user/project/badges.md) support placeholders that are replaced in real-time in both the link and image URL. The allowed placeholders are:
<!-- vale gitlab.Spelling = NO -->
diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md
index 01081bdd6d9..f6d572f9a7d 100644
--- a/doc/api/project_clusters.md
+++ b/doc/api/project_clusters.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Project clusters API (certificate-based) (DEPRECATED) **(FREE)**
+# Project clusters API (certificate-based) (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/23922) in GitLab 11.7.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md
index 00e73d41b46..758c91dd3e7 100644
--- a/doc/api/project_import_export.md
+++ b/doc/api/project_import_export.md
@@ -4,12 +4,17 @@ 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
---
-# Project import/export API **(FREE)**
+# Project import and export API **(FREE)**
-See also:
+Use the project import and export API to import and export projects using file transfers.
-- [Project import/export documentation](../user/project/settings/import_export.md).
-- [Project import/export administration Rake tasks](../administration/raketasks/project_import_export.md). **(FREE SELF)**
+For more information, see:
+
+- [Migrating projects using file exports](../user/project/settings/import_export.md)
+- [Project import and export Rake tasks](../administration/raketasks/project_import_export.md)
+
+Before using the project import and export API, you might want to use the
+[group import and export API](group_import_export.md).
## Schedule an export
@@ -135,6 +140,7 @@ POST /projects/import
| Attribute | Type | Required | Description |
| --------- | -------------- | -------- | ---------------------------------------- |
+<!-- markdownlint-disable-next-line gitlab.SentenceSpacing -->
| `namespace` | integer/string | no | The ID or path of the namespace to import the project to. Defaults to the current user's namespace.<br/><br/>Requires at least the Maintainer role on the destination group to import to. Using the Developer role for this purpose was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387891) in GitLab 15.8 and will be removed in GitLab 16.0. |
| `name` | string | no | The name of the project to be imported. Defaults to the path of the project if not provided |
| `file` | string | yes | The file to be uploaded |
diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md
index 92ca2849e8e..fa699c34a8a 100644
--- a/doc/api/project_level_variables.md
+++ b/doc/api/project_level_variables.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: reference, api
---
diff --git a/doc/api/project_vulnerabilities.md b/doc/api/project_vulnerabilities.md
index 9effe54b8e2..446c629c3bf 100644
--- a/doc/api/project_vulnerabilities.md
+++ b/doc/api/project_vulnerabilities.md
@@ -1,6 +1,6 @@
---
-stage: Create
-group: Source Code
+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"
type: reference, api
---
diff --git a/doc/api/projects.md b/doc/api/projects.md
index b502d547ddc..3cd7cdd811d 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
@@ -1433,6 +1433,7 @@ Supported attributes:
|-------------------------------------------------------------|----------------|------------------------|-------------|
| `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 request by default. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). |
@@ -2244,9 +2245,12 @@ POST /projects/:id/restore
## Upload a file
+> - Maximum attachment size enforcement [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57250) in GitLab 13.11 [with a flag](../administration/feature_flags.md) named `enforce_max_attachment_size_upload_api`. Disabled by default.
+> - Maximum attachment size [enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62542) in GitLab 13.11.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112450) in GitLab 15.10. Feature flag `enforce_max_attachment_size_upload_api` removed.
+
Uploads a file to the specified project to be used in an issue or merge request
-description, or a comment. GitLab versions 14.0 and later
-[enforce](#max-attachment-size-enforcement) this limit.
+description, or a comment.
```plaintext
POST /projects/:id/uploads
@@ -2282,42 +2286,6 @@ The returned `url` is relative to the project path. The returned `full_path` is
the absolute path to the file. In Markdown contexts, the link is expanded when
the format in `markdown` is used.
-### Max attachment size enforcement
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57250) in GitLab 13.11.
-
-GitLab 13.11 added enforcement of the [maximum attachment size limit](../user/admin_area/settings/account_and_limit_settings.md#max-attachment-size) behind the `enforce_max_attachment_size_upload_api` feature flag. GitLab 14.0 enables this by default.
-To disable this enforcement:
-
-**In Omnibus installations:**
-
-1. Enter the Rails console:
-
- ```shell
- sudo gitlab-rails console
- ```
-
-1. Disable the feature flag:
-
- ```ruby
- Feature.disable(:enforce_max_attachment_size_upload_api)
- ```
-
-**In installations from source:**
-
-1. Enter the Rails console:
-
- ```shell
- cd /home/git/gitlab
- sudo -u git -H bundle exec rails console -e production
- ```
-
-1. Disable the feature flag:
-
- ```ruby
- Feature.disable(:enforce_max_attachment_size_upload_api)
- ```
-
## Upload a project avatar
Uploads an avatar to the specified project.
diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md
index 5f6e03fde4d..6c3bd63bbad 100644
--- a/doc/api/protected_branches.md
+++ b/doc/api/protected_branches.md
@@ -208,16 +208,16 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
| 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 |
-| `name` | string | yes | The name of the branch or wildcard |
-| `push_access_level` | integer | no | Access levels allowed to push (defaults: `40`, Maintainer role) |
-| `merge_access_level` | integer | no | Access levels allowed to merge (defaults: `40`, Maintainer role) |
-| `unprotect_access_level` | integer | no | Access levels allowed to unprotect (defaults: `40`, Maintainer role) |
-| `allow_force_push` | boolean | no | Allow all users with push access to force push. (default: `false`) |
-| `allowed_to_push` **(PREMIUM)** | array | no | Array of access levels allowed to push, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}` |
-| `allowed_to_merge` **(PREMIUM)** | array | no | Array of access levels allowed to merge, 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 access levels allowed to unprotect, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}` |
-| `code_owner_approval_required` **(PREMIUM)** | boolean | no | Prevent pushes to this branch if it matches an item in the [`CODEOWNERS` file](../user/project/code_owners.md). (defaults: false) |
+| `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 | Allow all users with push access to force push. (default: `false`)
+| `allowed_to_merge` **(PREMIUM)** | array | no | Array of access levels allowed to merge, 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 access levels allowed to push, 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 access levels allowed to unprotect, 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/code_owners.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)
Example response:
@@ -369,7 +369,7 @@ Example response:
"name": "master",
"push_access_levels": [
{
- "id": 1,
+ "id": 1,
"access_level": 30,
"access_level_description": "Developers + Maintainers",
"user_id": null,
@@ -378,14 +378,14 @@ Example response:
],
"merge_access_levels": [
{
- "id": 1,
+ "id": 1,
"access_level": 30,
"access_level_description": "Developers + Maintainers",
"user_id": null,
"group_id": null
},
{
- "id": 2,
+ "id": 2,
"access_level": 40,
"access_level_description": "Maintainers",
"user_id": null,
@@ -394,7 +394,7 @@ Example response:
],
"unprotect_access_levels": [
{
- "id": 1,
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers",
"user_id": null,
@@ -437,15 +437,15 @@ PATCH /projects/:id/protected_branches/:name
curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_branches/feature-branch?allow_force_push=true&code_owner_approval_required=true"
```
-| Attribute | Type | Required | Description |
+| 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 |
-| `name` | string | yes | The name of the branch |
-| `allow_force_push` | boolean | no | When enabled, members who can push to this branch can also force push. |
+| `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.
+| `allow_force_push` | boolean | no | When enabled, members who can push to this branch can also force push.
+| `allowed_to_push` **(PREMIUM)** | array | no | Array of push access levels, with each described by a hash.
+| `allowed_to_merge` **(PREMIUM)** | array | no | Array of merge access levels, with each described by a hash.
+| `allowed_to_unprotect` **(PREMIUM)** | array | no | Array of unprotect access levels, with each described by a hash. 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/code_owners.md). Defaults to `false`. |
-| `allowed_to_push` **(PREMIUM)** | array | no | Array of push access levels, with each described by a hash. |
-| `allowed_to_merge` **(PREMIUM)** | array | no | Array of merge access levels, with each described by a hash. |
-| `allowed_to_unprotect` **(PREMIUM)** | array | no | Array of unprotect access levels, with each described by a hash. |
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
diff --git a/doc/api/protected_environments.md b/doc/api/protected_environments.md
index 1ea3fc5adda..877add32fed 100644
--- a/doc/api/protected_environments.md
+++ b/doc/api/protected_environments.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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, howto
---
diff --git a/doc/api/protected_tags.md b/doc/api/protected_tags.md
index 633ca441fad..d6928d7293c 100644
--- a/doc/api/protected_tags.md
+++ b/doc/api/protected_tags.md
@@ -8,17 +8,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
**Valid access levels**
-Currently, these levels are recognized:
+These access levels are recognized:
-```plaintext
-0 => No access
-30 => Developer access
-40 => Maintainer access
-```
+- `0`: No access
+- `30`: Developer role
+- `40`: Maintainer role
## List protected tags
-Gets a list of protected tags from a project.
+Gets a list of [protected tags](../user/project/protected_tags.md) from a project.
This function takes pagination parameters `page` and `per_page` to restrict the list of protected tags.
```plaintext
@@ -27,10 +25,11 @@ GET /projects/:id/protected_tags
| 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 |
+| `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. |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_tags"
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/projects/5/protected_tags"
```
Example response:
@@ -62,11 +61,12 @@ GET /projects/:id/protected_tags/:name
| 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 |
-| `name` | string | yes | The name of the tag or wildcard |
+| `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. |
+| `name` | string | yes | The name of the tag or wildcard. |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_tags/release-1-0"
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/projects/5/protected_tags/release-1-0"
```
Example response:
@@ -86,23 +86,35 @@ Example response:
## Protect repository tags
-Protects a single repository tag or several project repository
-tags using a wildcard protected tag.
+Protects a single repository tag, or several project repository
+tags, using a wildcard protected tag.
```plaintext
POST /projects/:id/protected_tags
```
```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_tags?name=*-stable&create_access_level=30"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/projects/5/protected_tags" -d '{
+ "allowed_to_create" : [
+ {
+ "user_id" : 1
+ },
+ {
+ "access_level" : 30
+ }
+ ],
+ "create_access_level" : 30,
+ "name" : "*-stable"
+}'
```
| 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 |
-| `name` | string | yes | The name of the tag or wildcard |
-| `create_access_level` | string | no | Access levels allowed to create (defaults: `40`, Maintainer role) |
-| `allowed_to_create` | array | no | Array of access levels allowed to create tags, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}` |
+| `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. |
+| `name` | string | yes | The name of the tag or wildcard. |
+| `allowed_to_create` | array | no | Array of access levels allowed to create tags, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`. |
+| `create_access_level` | string | no | Access levels allowed to create. Default: `40`, for Maintainer role. |
Example response:
@@ -128,10 +140,17 @@ DELETE /projects/:id/protected_tags/:name
```
```shell
-curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_tags/*-stable"
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/projects/5/protected_tags/*-stable"
```
| 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 |
-| `name` | string | yes | The name of the tag |
+| `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. |
+| `name` | string | yes | The name of the tag. |
+
+## Related topics
+
+- [Tags API](tags.md) for all tags
+- [Tags](../user/project/repository/tags/index.md) user documentation
+- [Protected tags](../user/project/protected_tags.md) user documentation
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index f23f2b36ed0..0d8e335b620 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/releases/links.md b/doc/api/releases/links.md
index 74f6b1c9efa..2294f161759 100644
--- a/doc/api/releases/links.md
+++ b/doc/api/releases/links.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/resource_groups.md b/doc/api/resource_groups.md
index cdba0c01f4f..552c2a3ecfb 100644
--- a/doc/api/resource_groups.md
+++ b/doc/api/resource_groups.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/rest/deprecations.md b/doc/api/rest/deprecations.md
new file mode 100644
index 00000000000..7bfc9e1f59e
--- /dev/null
+++ b/doc/api/rest/deprecations.md
@@ -0,0 +1,86 @@
+---
+stage: Manage
+group: Integrations
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# REST API deprecations and removals
+
+The following API changes will occur when the v4 API is removed.
+
+The date of this change is unknown.
+For details, see [issue 216456](https://gitlab.com/gitlab-org/gitlab/-/issues/216456)
+and [issue 387485](https://gitlab.com/gitlab-org/gitlab/-/issues/387485).
+
+## `merged_by` API field
+
+Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/350534).
+
+The `merged_by` field in the [merge request API](../merge_requests.md#list-merge-requests)
+has been deprecated in favor of the `merge_user` field which more correctly identifies who merged a merge request when
+performing actions (merge when pipeline succeeds, add to merge train) other than a simple merge.
+
+API users are encouraged to use the new `merge_user` field instead. The `merged_by` field will be removed in v5 of the GitLab REST API.
+
+## `merge_status` API field
+
+Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/382032).
+
+The `merge_status` field in the [merge request API](../merge_requests.md#merge-status)
+has been deprecated in favor of the `detailed_merge_status` field which more correctly identifies
+all of the potential statuses that a merge request can be in. API users are encouraged to use the
+new `detailed_merge_status` field instead. The `merge_status` field will be removed in v5 of the GitLab REST API.
+
+## Single merge request changes API endpoint
+
+Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/322117).
+
+The endpoint to get
+[changes from a single merge request](../merge_requests.md#get-single-merge-request-changes)
+has been deprecated in favor the
+[list merge request diffs](../merge_requests.md#list-merge-request-diffs) endpoint.
+API users are encouraged to switch to the new diffs endpoint instead.
+
+The `changes from a single merge request` endpoint will be removed in v5 of the GitLab REST API.
+
+## Approvers and Approver Group fields in Merge Request Approval API
+
+Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/353097).
+
+The endpoint to get the configuration of approvals for a project returns
+empty arrays for `approvers` and `approval_groups`.
+These fields were deprecated in favor of the endpoint to
+[get project-level rules](../merge_request_approvals.md#get-project-level-rules)
+for a merge request. API users are encouraged to switch to this endpoint instead.
+
+These fields will be removed from the `get configuration` endpoint in v5 of the GitLab REST API.
+
+## Runner usage of `active` replaced by `paused`
+
+Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/351109).
+
+Occurrences of the `active` identifier in the GitLab Runner GraphQL API endpoints will be
+renamed to `paused` in GitLab 16.0.
+
+- In v4 of the REST API, starting in GitLab 14.8, you can use the `paused` property in place of `active`
+- In v5 of the REST API, this change will affect endpoints taking or returning `active` property, such as:
+ - `GET /runners`
+ - `GET /runners/all`
+ - `GET /runners/:id` / `PUT /runners/:id`
+ - `PUT --form "active=false" /runners/:runner_id`
+ - `GET /projects/:id/runners` / `POST /projects/:id/runners`
+ - `GET /groups/:id/runners`
+
+The 16.0 release of GitLab Runner will start using the `paused` property when registering runners.
+
+## Runner status will not return `paused`
+
+Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/344648).
+
+In a future v5 of the REST API, the endpoints for GitLab Runner will not return `paused` or `active`.
+
+A runner's status will only relate to runner contact status, such as:
+`online`, `offline`, or `not_connected`. Status `paused` or `active` will no longer appear.
+
+When checking if a runner is `paused`, API users are advised to check the boolean attribute
+`paused` to be `true` instead. When checking if a runner is `active`, check if `paused` is `false`.
diff --git a/doc/api/rest/index.md b/doc/api/rest/index.md
index 57d13f2a54f..91a70c3f2a9 100644
--- a/doc/api/rest/index.md
+++ b/doc/api/rest/index.md
@@ -311,17 +311,17 @@ The following table shows the possible return codes for API requests.
| Return values | Description |
|--------------------------|-------------|
| `200 OK` | The `GET`, `PUT` or `DELETE` request was successful, and the resource itself is returned as JSON. |
+| `201 Created` | The `POST` request was successful, and the resource is returned as JSON. |
| `202 Accepted` | The `GET`, `PUT` or `DELETE` request was successful, and the resource is scheduled for processing. |
| `204 No Content` | The server has successfully fulfilled the request, and there is no additional content to send in the response payload body. |
-| `201 Created` | The `POST` request was successful, and the resource is returned as JSON. |
| `304 Not Modified` | The resource hasn't been modified since the last request. |
| `400 Bad Request` | A required attribute of the API request is missing. For example, the title of an issue is not given. |
| `401 Unauthorized` | The user isn't authenticated. A valid [user token](#authentication) is necessary. |
| `403 Forbidden` | The request isn't allowed. For example, the user isn't allowed to delete a project. |
-| `404 Not Found` | A resource couldn't be accessed. For example, an ID for a resource couldn't be found. |
+| `404 Not Found` | A resource couldn't be accessed. For example, an ID for a resource couldn't be found, or the user isn't authorized to access the resource. |
| `405 Method Not Allowed` | The request isn't supported. |
| `409 Conflict` | A conflicting resource already exists. For example, creating a project with a name that already exists. |
-| `412` | The request was denied. This can happen if the `If-Unmodified-Since` header is provided when trying to delete a resource, which was modified in between. |
+| `412 Precondition Failed`| The request was denied. This can happen if the `If-Unmodified-Since` header is provided when trying to delete a resource, which was modified in between. |
| `422 Unprocessable` | The entity couldn't be processed. |
| `429 Too Many Requests` | The user exceeded the [application rate limits](../../administration/instance_limits.md#rate-limits). |
| `500 Server Error` | While handling the request, something went wrong on the server. |
@@ -483,12 +483,13 @@ pagination headers.
Keyset-based pagination is supported only for selected resources and ordering
options:
-| Resource | Options | Availability |
-|:---------------------------------------------------------|:---------------------------------|:-------------------------------------------------------------------------------------------------------------|
-| [Projects](../projects.md) | `order_by=id` only | Authenticated and unauthenticated users |
-| [Groups](../groups.md) | `order_by=name`, `sort=asc` only | Unauthenticated users only |
-| [Group audit events](../audit_events.md#group-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333968) in GitLab 15.2) |
-| [Jobs](../jobs.md) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/362172) in GitLab 15.9) |
+| Resource | Options | Availability |
+|:----------------------------------------------------------------|:---------------------------------|:--------------------------------------------------------------------------------------------------------------|
+| [Projects](../projects.md) | `order_by=id` only | Authenticated and unauthenticated users |
+| [Groups](../groups.md) | `order_by=name`, `sort=asc` only | Unauthenticated users only |
+| [Group audit events](../audit_events.md#group-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333968) in GitLab 15.2) |
+| [Project audit events](../audit_events.md#project-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367528) in GitLab 15.10) |
+| [Jobs](../jobs.md) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/362172) in GitLab 15.9) |
### Pagination response headers
diff --git a/doc/api/search.md b/doc/api/search.md
index 3c3ad3f6ab9..f7fa7babe71 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -31,8 +31,8 @@ GET /search
| `scope` | string | Yes | The scope to search in. Values include `projects`, `issues`, `merge_requests`, `milestones`, `snippet_titles`, `users`. [Additional scopes](#additional-scopes): `blobs`, `commits`, `notes`, `wiki_blobs`. |
| `search` | string | Yes | The search query. |
| `confidential` | boolean | No | Filter by confidentiality. Supports `issues` scope; other scopes are ignored. |
-| `order_by` | string | No | Allowed values are `created_at` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for Advanced Search.|
-| `sort` | string | No | Allowed values are `asc` or `desc` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for Advanced Search.|
+| `order_by` | string | No | Allowed values are `created_at` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for advanced search.|
+| `sort` | string | No | Allowed values are `asc` or `desc` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for advanced search.|
| `state` | string | No | Filter by state. Supports `issues` and `merge_requests` scopes; other scopes are ignored. |
### Scope: `projects`
@@ -407,6 +407,7 @@ Example response:
"system": false,
"noteable_id": 22,
"noteable_type": "Issue",
+ "project_id": 6,
"noteable_iid": 2
}
]
@@ -449,8 +450,8 @@ GET /groups/:id/search
| `scope` | string | Yes | The scope to search in. Values include `issues`, `merge_requests`, `milestones`, `projects`, `users`. [Additional scopes](#additional-scopes): `blobs`, `commits`, `notes`, `wiki_blobs`. |
| `search` | string | Yes | The search query. |
| `confidential` | boolean | No | Filter by confidentiality. Supports only `issues` scope; other scopes are ignored. |
-| `order_by` | string | No | Allowed values are `created_at` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for Advanced Search.|
-| `sort` | string | No | Allowed values are `asc` or `desc` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for Advanced Search.|
+| `order_by` | string | No | Allowed values are `created_at` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for advanced search.|
+| `sort` | string | No | Allowed values are `asc` or `desc` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for advanced search.|
| `state` | string | No | Filter by state. Supports `issues` and `merge_requests` only; other scopes are ignored. |
The response depends on the requested scope.
@@ -796,6 +797,7 @@ Example response:
"system": false,
"noteable_id": 22,
"noteable_type": "Issue",
+ "project_id": 6,
"noteable_iid": 2
}
]
@@ -839,8 +841,8 @@ GET /projects/:id/search
| `search` | string | Yes | The search query. |
| `confidential` | boolean | No | Filter by confidentiality. Supports `issues` scope; other scopes are ignored. |
| `ref` | string | No | The name of a repository branch or tag to search on. The project's default branch is used by default. Applicable only for scopes `blobs`, `commits`, and `wiki_blobs`. |
-| `order_by` | string | No | Allowed values are `created_at` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for Advanced Search.|
-| `sort` | string | No | Allowed values are `asc` or `desc` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for Advanced Search.|
+| `order_by` | string | No | Allowed values are `created_at` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for advanced search.|
+| `sort` | string | No | Allowed values are `asc` or `desc` only. If not set, results are sorted by `created_at` in descending order for basic search, or by the most relevant documents for advanced search.|
| `state` | string | No | Filter by state. Supports the `issues` and `merge_requests` scopes; other scopes are ignored. |
The response depends on the requested scope.
@@ -1046,6 +1048,7 @@ Example response:
"system": false,
"noteable_id": 22,
"noteable_type": "Issue",
+ "project_id": 6,
"noteable_iid": 2
}
]
diff --git a/doc/api/secure_files.md b/doc/api/secure_files.md
index 11c718dde01..0fb12cf3ad2 100644
--- a/doc/api/secure_files.md
+++ b/doc/api/secure_files.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: reference, api
---
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 94ed2b2e3db..c3c48fba339 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -227,7 +227,8 @@ Example response:
"can_create_group": false,
"jira_connect_application_key": "123",
"jira_connect_proxy_url": "http://gitlab.example.com",
- "user_defaults_to_private_profile": true
+ "user_defaults_to_private_profile": true,
+ "projects_api_rate_limit_unauthenticated": 400
}
```
@@ -268,9 +269,9 @@ listed in the descriptions of the relevant settings.
| `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_group_owners_to_manage_ldap` **(PREMIUM)** | 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 hooks and services. |
+| `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 web hooks and services. |
+| `allow_local_requests_from_web_hooks_and_services` | boolean | no | Allow requests to the local network from webhooks and integrations. |
| `allow_runner_registration_token` | boolean | no | Allow using a registration token to create a runner. Defaults to `true`. |
| `archive_builds_in_human_readable` | string | no | Set the duration for which the jobs are considered as old and expired. After that time passes, the jobs are archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>. |
| `asset_proxy_enabled` | boolean | no | (**If enabled, requires:** `asset_proxy_url`) Enable proxying of assets. GitLab restart is required to apply changes. |
@@ -282,7 +283,7 @@ 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. |
-| `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. Requires [`bulk_import_projects` feature flag](../user/group/import/index.md#migrate-groups-by-direct-transfer-recommended) to also migrate projects. Setting also [available](../user/admin_area/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](../user/admin_area/settings/visibility_and_access_controls.md#enable-migration-of-groups-and-projects-by-direct-transfer) in the Admin Area. |
| `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. |
| `commit_email_hostname` | string | no | Custom hostname (for private commit emails). |
@@ -305,6 +306,7 @@ listed in the descriptions of the relevant settings.
| `default_project_visibility` | string | no | What visibility level new projects receive. Can take `private`, `internal` and `public` as a parameter. Default is `private`. |
| `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. |
| `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`. |
| `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`. |
@@ -315,7 +317,7 @@ listed in the descriptions of the relevant settings.
| `disable_feed_token` | boolean | no | Disable display of RSS/Atom and calendar feed tokens. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231493) in GitLab 13.7. |
| `disable_personal_access_token` **(PREMIUM SELF)** | boolean | no | Disable personal access tokens. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384201) in GitLab 15.7. |
| `disabled_oauth_sign_in_sources` | array of strings | no | Disabled OAuth sign-in sources. |
-| `dns_rebinding_protection_enabled` | boolean | no | Enforce DNS rebinding attack protection. |
+| `dns_rebinding_protection_enabled` | boolean | no | Enforce DNS-rebinding attack protection. |
| `domain_denylist_enabled` | boolean | no | (**If enabled, requires:** `domain_denylist`) Allows blocking sign-ups from emails from specific domains. |
| `domain_denylist` | array of strings | no | Users with email addresses that match these domains **cannot** sign up. Wildcards allowed. Use separate lines for multiple entries. For example: `domain.com`, `*.domain.com`. |
| `domain_allowlist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is `null`, meaning there is no restriction. |
@@ -368,6 +370,7 @@ listed in the descriptions of the relevant settings.
| `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. |
+| `gitlab_dedicated_instance` | boolean | no | Indicates whether the instance was provisioned for GitLab Dedicated. |
| `grafana_enabled` | boolean | no | Enable Grafana. |
| `grafana_url` | string | no | Grafana URL. |
| `gravatar_enabled` | boolean | no | Enable Gravatar. |
@@ -417,7 +420,7 @@ listed in the descriptions of the relevant settings.
| `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. |
-| `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 hooks and services are disabled.
+| `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.
| `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`. |
@@ -434,6 +437,7 @@ listed in the descriptions of the relevant settings.
| `plantuml_url` | string | required by: `plantuml_enabled` | The PlantUML instance URL for integration. |
| `polling_interval_multiplier` | decimal | no | Interval multiplier used by endpoints that perform polling. Set to `0` to disable polling. |
| `project_export_enabled` | boolean | no | Enable project export. |
+| `projects_api_rate_limit_unauthenticated` | integer | no | [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112283) in GitLab 15.10. Max number of requests per 10 minutes per IP address for unauthenticated requests to the [list all projects API](projects.md#list-all-projects). Default: 400. To disable throttling set to 0.|
| `prometheus_metrics_enabled` | boolean | no | Enable Prometheus metrics. |
| `protected_ci_variables` | boolean | no | CI/CD variables are protected by default. |
| `push_event_activities_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether individual push events or bulk push events are created. [Bulk push events are created](../user/admin_area/settings/push_event_activities_limit.md) if it surpasses that value. |
diff --git a/doc/api/suggestions.md b/doc/api/suggestions.md
index 1e1f226481c..bb1f3968cf3 100644
--- a/doc/api/suggestions.md
+++ b/doc/api/suggestions.md
@@ -11,7 +11,19 @@ This page describes the API for [suggesting changes](../user/project/merge_reque
Every API call to suggestions must be authenticated.
-## Applying a suggestion
+## Create a suggestion
+
+To create a suggestion through the API, use the Discussions API to
+[create a new thread in the merge request diff](discussions.md#create-new-merge-request-thread).
+The format for suggestions is:
+
+````markdown
+```suggestion:-3+0
+example text
+```
+````
+
+## Apply a suggestion
Applies a suggested patch in a merge request. Users must have
at least the Developer role to perform such action.
@@ -43,7 +55,7 @@ Example response:
}
```
-## Applying multiple suggestions
+## Apply multiple suggestions
```plaintext
PUT /suggestions/batch_apply
diff --git a/doc/api/topics.md b/doc/api/topics.md
index 8acf6bd645d..8f2aae9e070 100644
--- a/doc/api/topics.md
+++ b/doc/api/topics.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
diff --git a/doc/api/users.md b/doc/api/users.md
index 4ecb3d48c0f..f877aa29b9c 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -41,7 +41,7 @@ GET /users
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.
+- 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`.
- Name or username, you do not have to get an exact match because this is a fuzzy search.
In addition, you can lookup users by username:
diff --git a/doc/api/visual_review_discussions.md b/doc/api/visual_review_discussions.md
index f966af82b10..561dc1a26a5 100644
--- a/doc/api/visual_review_discussions.md
+++ b/doc/api/visual_review_discussions.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/architecture/blueprints/_template.md b/doc/architecture/blueprints/_template.md
index f7dea60e9b7..64b79f996e0 100644
--- a/doc/architecture/blueprints/_template.md
+++ b/doc/architecture/blueprints/_template.md
@@ -50,6 +50,7 @@ Blueprint statuses you can use:
- "accepted"
- "ongoing"
- "implemented"
+- "postponed"
- "rejected"
-->
@@ -125,6 +126,9 @@ 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.
-->
## Design and implementation details
@@ -153,3 +157,12 @@ 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.
-->
+
+## 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.
+-->
diff --git a/doc/architecture/blueprints/cells/cells-feature-admin-area.md b/doc/architecture/blueprints/cells/cells-feature-admin-area.md
new file mode 100644
index 00000000000..abcf4a5e263
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-admin-area.md
@@ -0,0 +1,58 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Admin Area'
+---
+
+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 simpler management of all Cells in one interface and reduces
+the risk of settings diverging in different Cells. This introduces challenges
+with admin pages that allow you to manage data that will be spread across all
+Cells.
+
+## 1. Definition
+
+There are consequences for admin pages that contain data that spans "the whole
+instance" as the Admin pages may be served by any Cell or possibly just 1 cell.
+There are already many parts of the Admin interface that will have data that
+spans many cells. For example lists of all Groups, Projects, Topics, Jobs,
+Analytics, Applications and more. There are also administrative monitoring
+capabilities in the Admin page 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 this data per Cell. These pages will be distinct from
+ other Admin 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 the Cells are
+ designed to be totally independent, and it does also enforce more strict
+ requirements on compatibility between Cells.
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md b/doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md
new file mode 100644
index 00000000000..5f0c8c2823d
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md
@@ -0,0 +1,29 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Agent for Kubernetes'
+---
+
+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/cells-feature-backups.md b/doc/architecture/blueprints/cells/cells-feature-backups.md
new file mode 100644
index 00000000000..80cac8764e6
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-backups.md
@@ -0,0 +1,61 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Backups'
+---
+
+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 cells 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 (e.g. `main`, and `ci`).
+
+Additionally, there may be cluster-wide metadata tables (e.g. `users` table)
+which is directly accesible 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 metdata 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/cells-feature-ci-runners.md b/doc/architecture/blueprints/cells/cells-feature-ci-runners.md
new file mode 100644
index 00000000000..619c78d19ec
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-ci-runners.md
@@ -0,0 +1,169 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: CI Runners'
+---
+
+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 in order to execute CI jobs [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/),
+very often managed by customer in their infrastructure.
+
+All CI jobs created as part of CI pipeline are run in a context of project
+it 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 subprojects of that group
+- project runners: runners that execute jobs from projects or many projects: some runners might
+ have projects assigned from projects in different top-level groups.
+
+This alongside with existing data structure where `ci_runners` is a table describing
+all types of runners poses a challenge how the `ci_runners` should be managed in a Cells environment.
+
+## 2. Data flow
+
+GitLab Runners use a set of globally scoped endpoints to:
+
+- registration of a new runner via registration token `https://gitlab.com/api/v4/runners`
+ ([subject for removal](../runner_tokens/index.md)) (`registration token`)
+- requests 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 an registered runner in a system with specific configuration (`tags`, `locked`, etc.)
+- build token representing an ephemeral token giving a limited access to updating a specific
+ job, uploading artifacts, downloading dependent artifacts, downloading and uploading
+ container registry images
+
+Each of those endpoints do 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 a 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 correct Cell for a first time
+- be made to be two phase: request build from global pool, claim build on a specific Cell using a Cell specific URL
+
+## 3. Proposal
+
+This section describes various proposals. Reader should consider that those
+proposals do describe solutions for different problems. Many or some aspects
+of those proposals might be the solution to the stated problem.
+
+### 3.1. Authentication tokens
+
+Even though the paths for CI Runners are not routable they can be made routable with
+those 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). Runner when first
+ starts 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 `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 sole owner of the token that Runner later
+ uses for specific job. There were prior discussions about not storing `build token`
+ but rather using `JWT` token with defined scopes. Such token could encode the `cell`
+ to which router could easily route all requests.
+
+### 3.2. Request body
+
+- The most of used endpoints pass authentication token in 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 it's own set of instance-wide runners that are updated at it's 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 made routable. It might be via prefixing them, adding additional Cell parameter,
+ or providing much more robust way to decode runner token and match it to Cell.
+- If routable token is used, we could move away from cryptographic random stored in
+ database to rather prefer to use JWT tokens that would encode
+- The Admin Area showing registered Runners would have to be scoped to a Cell
+
+This model might be desired since it provides strong isolation guarantees.
+This model does significantly increase maintenance overhead since each Cell is managed
+separately.
+
+This model may require adjustments to runner tags feature so that projects have consistent runner experience across cells.
+
+### 3.4. Instance-wide are cluster-wide
+
+Contrary to 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 system and to change the following aspects:
+
+- `ci_runners` table would likely have to be split decomposed into `ci_instance_runners`, ...
+- all interfaces would have to be adopted to use correct table
+- build queuing would have to be reworked to be two phase 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
+- likely `ci_pending_builds` and `ci_running_builds` would have to be made `cluster-wide` tables
+ increasing likelihood of creating hotspots in a system related to CI queueing
+
+This model makes it complex to implement from engineering side. Does make some data being shared
+between Cells. Creates hotspots / scalability issues in a system (ex. during abuse) that
+might impact experience of organizations on other Cells.
+
+### 3.5. GitLab CI Daemon
+
+Another potential solution to explore is to have a dedicated service responsible for builds queueing
+owning it's database and working in a model of either sharded or celled service. There were prior
+discussions about [CI/CD Daemon](https://gitlab.com/gitlab-org/gitlab/-/issues/19435).
+
+If the service would be sharded:
+
+- depending on a model if runners are cluster-wide or cell-local this service would have to fetch
+ data from all Cells
+- if the sharded service would be used we could adapt a model of either sharing database containing
+ `ci_pending_builds/ci_running_builds` with the service
+- if the sharded service would be 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 designated Cell
+
+If the service would be celled:
+
+- 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 solutions it appears that solution giving the most promise is:
+
+- use "instance-wide are Cell local"
+- refine endpoints to have routable identities (either via specific paths, or better tokens)
+
+Other potential upsides is to get rid of `ci_builds.token` and rather use a `JWT token`
+that can much better and easier encode wider set of scopes allowed by CI runner.
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/cells-feature-container-registry.md b/doc/architecture/blueprints/cells/cells-feature-container-registry.md
new file mode 100644
index 00000000000..b266de56205
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-container-registry.md
@@ -0,0 +1,131 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Container Registry'
+---
+
+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 is a feature allowing to store Docker Container Images
+in GitLab. You can read about GitLab integration [here](../../../user/packages/container_registry/index.md).
+
+## 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 it's 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 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 be have many authorized scopes. This allows container registry and client
+to mount existing blobs from another 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 project. Each project can have many
+container registry images attached.
+
+Currently in case of 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 external service and uses it's own data store
+- the 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 it's architecture it extensive architecture 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 any theoretical problems with running GitLab Container Registry in a Cell.
+Service seems that can be easily made routable to work well.
+
+The practical complexities are around managing complex service from infrastructure side.
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/cells-feature-contributions-forks.md b/doc/architecture/blueprints/cells/cells-feature-contributions-forks.md
new file mode 100644
index 00000000000..cc6feb1c08a
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-contributions-forks.md
@@ -0,0 +1,120 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Contributions: Forks'
+---
+
+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
+
+[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
+
+[Forking workflow](../../../user/project/repository/forking_workflow.md) is common workflow
+with various usage patterns:
+
+- allows users to contribute back to upstream project
+- persist repositories into their personal namespace
+- copy to make changes and release as modified project
+
+Forks allow users not having write access to parent project to make changes. The forking workflow
+is especially important for the Open Source community which is able to contribute back
+to public projects. However, it is equally important in some companies which prefer the strong split
+of responsibilites and tighter access control. The access to project is restricted
+to designated list of developers.
+
+Forks enable:
+
+- tigther control of who can modify the upstream project
+- split of the responsibilites: parent project might use CI configuration connecting to production systems
+- run CI pipelines in context of fork in much more restrictive environment
+- consider all forks to be unveted which reduces risks of leaking secrets, or any other information
+ tied with the project
+
+The forking model is problematic in Cells architecture for following reasons:
+
+- Forks are clones of existing repositories, forks could be created across different organizations, Cells and Gitaly shards.
+- User can create merge request and contribute back to upstream project, this upstream project might in a different organization and Cell.
+- The merge request CI pipeline is to executed in a context of source project, but presented in a context of target project.
+
+## 2. Data flow
+
+## 3. Proposals
+
+### 3.1. Intra-Cluster forks
+
+This proposal makes us to implement forks as a intra-ClusterCell forks where communication is done via API
+between all trusted Cells of a cluster:
+
+- Forks when created, they are created always in context of user choice of group.
+- Forks are isolated from Organization.
+- Organization or group owner could disable forking across organizations or forking in general.
+- When a Merge Request is created it is created in context of target project, referencing
+ external project on another Cell.
+- To target project the merge reference is transfered that is used for presenting information
+ in context of target project.
+- CI pipeline is fetched in context of source project as it-is today, the result is fetched into
+ Merge Request of target project.
+- The Cell holding target project internally uses GraphQL to fetch status of source project
+ and include in context of the information for merge request.
+
+Upsides:
+
+- All existing forks continue to work as-is, 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 ability of users today to clone repository to local computer
+ and push it to any repository of choice.
+- Access control of source project can be lower than those of target project. System today
+ 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, the forks are created in a user personal namespace
+tied with the organization. Example:
+
+- Each user that is part of 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 it's own personal namespace of the organization.
+- The user has that many personal namespaces as many organizations it belongs to.
+- The personal namespace behaves similar to 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 personal namespace of user in Organization.
+- All forks are part of to the organization.
+- The forks are not federated features.
+- The personal namespace and forked project do not share configuration with parent project.
+
+### 3.3. Forks are created as internal projects under current project
+
+Instead of creating projects across organizations, the 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 a context of 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).
+- The forks are not federated features.
+
+Downsides:
+
+- Does not answer how to handle and migrate all exisiting forks.
+- Might share current group / project settings - breaking some security boundaries.
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/cells-feature-dashboard.md b/doc/architecture/blueprints/cells/cells-feature-dashboard.md
new file mode 100644
index 00000000000..37ed13ad9f9
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-dashboard.md
@@ -0,0 +1,29 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Dashboard'
+---
+
+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: Dashboard
+
+> TL;DR
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/cells-feature-data-migration.md b/doc/architecture/blueprints/cells/cells-feature-data-migration.md
new file mode 100644
index 00000000000..e24cd0323f4
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-data-migration.md
@@ -0,0 +1,130 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Data migration'
+---
+
+DISCLAIMER:
+This page may contain information related to upcoming products, features and
+functionality. It is important to note that the information presented is for
+informational purposes only, so please do not rely on the information for
+purchasing or planning purposes. Just like with all projects, the items
+mentioned on the page are subject to change or delay, and the development,
+release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
+
+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 Cells architecture to provide a way to migrate data out of big Cells
+into smaller ones. This describes various approaches to provide this type of split.
+
+We also need to handle for cases where data is already violating the expected
+isolation constraints of Cells (ie. 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 changed and modelled slightly differently before we can
+properly split or migrate the 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 principle
+that it is easier to create 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 organization.
+1. It requires either downtime for 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/cells-feature-database-sequences.md b/doc/architecture/blueprints/cells/cells-feature-database-sequences.md
new file mode 100644
index 00000000000..7966ac4bfdf
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-database-sequences.md
@@ -0,0 +1,94 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Database Sequences'
+---
+
+DISCLAIMER:
+This page may contain information related to upcoming products, features and
+functionality. It is important to note that the information presented is for
+informational purposes only, so please do not rely on the information for
+purchasing or planning purposes. Just like with all projects, the items
+mentioned on the page are subject to change or delay, and the development,
+release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
+
+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 unique ID, allowing
+to access 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 IDs for most of entities.
+
+It might 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
+
+This 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 database.
+
+- This might break existing IDs and requires adding 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
+
+Since significant number of tables already use 64 bit ID numbers we could use MSB to encode
+Cell ID effectively enabling
+
+- This might limit amount of Cells that can be enabled in system, as we might decide to only
+ allocate 1024 possible Cell numbers.
+- This might make IDs to be migratable between Cells, since even if 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 Cell number and we would need
+ 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 the sequences as they are consumed from a centrally managed place.
+Once 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 to be migratable between Cells, since even if 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 Cell number and we would need
+ 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 this 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 Cell-local ID,
+but when referenced outside it would rather use IID (an ID that is monotonic in context of a given resource, like project).
+
+- This makes the ID 10000 for `merge_requests` be present on all Cells, which might be sometimes confusing
+ as for uniqueness of the resource.
+- This might make random access by ID (if ever needed) be impossible without using 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/cells-feature-git-access.md b/doc/architecture/blueprints/cells/cells-feature-git-access.md
new file mode 100644
index 00000000000..3582c99c7dd
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-git-access.md
@@ -0,0 +1,163 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Git Access'
+---
+
+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 through out the application. It can be an operation performed by the system
+(read Git repository) or by 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 done 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 a context of a Cell.
+
+## 2. Data flow
+
+The are various operations performed today by the 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 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 to be routable. It means that at least the following paths will have to be updated
+do 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 user's personal namespaces.
+
+## 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. The across-Cells forks are likely impossible to be supported (discover: how this work today across different Gitaly node).
diff --git a/doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md b/doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md
new file mode 100644
index 00000000000..9d501918a21
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md
@@ -0,0 +1,29 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: GitLab Pages'
+---
+
+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/cells-feature-global-search.md b/doc/architecture/blueprints/cells/cells-feature-global-search.md
new file mode 100644
index 00000000000..fdd56d7258d
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-global-search.md
@@ -0,0 +1,47 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Global search'
+---
+
+DISCLAIMER:
+This page may contain information related to upcoming products, features and
+functionality. It is important to note that the information presented is for
+informational purposes only, so please do not rely on the information for
+purchasing or planning purposes. Just like with all projects, the items
+mentioned on the page are subject to change or delay, and the development,
+release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
+
+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 first versions of Cells will simply not support global searches and then
+we may later 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/cells-feature-graphql.md b/doc/architecture/blueprints/cells/cells-feature-graphql.md
new file mode 100644
index 00000000000..8430d23c7f4
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-graphql.md
@@ -0,0 +1,94 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: GraphQL'
+---
+
+DISCLAIMER:
+This page may contain information related to upcoming products, features and
+functionality. It is important to note that the information presented is for
+informational purposes only, so please do not rely on the information for
+purchasing or planning purposes. Just like with all projects, the items
+mentioned on the page are subject to change or delay, and the development,
+release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
+
+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 how GitLab uses
+it calls the `/api/graphql` endpoint, and only query or mutation of 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 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
+ since 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/cells-feature-organizations.md b/doc/architecture/blueprints/cells/cells-feature-organizations.md
new file mode 100644
index 00000000000..9c2e33719ab
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-organizations.md
@@ -0,0 +1,58 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Organizations'
+---
+
+DISCLAIMER:
+This page may contain information related to upcoming products, features and
+functionality. It is important to note that the information presented is for
+informational purposes only, so please do not rely on the information for
+purchasing or planning purposes. Just like with all projects, the items
+mentioned on the page are subject to change or delay, and the development,
+release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
+
+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 Cells architecture is strong isolation between Groups.
+Organizations as described by this blueprint provides a way to have plausible UX
+for joining together many Groups that are isolated from the rest of systems.
+
+## 1. Definition
+
+Cells do require that all groups and projects of a single organization can
+only be stored on a single Cell since 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 such 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. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md b/doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md
new file mode 100644
index 00000000000..467683ffadd
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md
@@ -0,0 +1,29 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Personal Namespaces'
+---
+
+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
diff --git a/doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md b/doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md
new file mode 100644
index 00000000000..c961857e4fa
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md
@@ -0,0 +1,46 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Router Endpoints Classification'
+---
+
+DISCLAIMER:
+This page may contain information related to upcoming products, features and
+functionality. It is important to note that the information presented is for
+informational purposes only, so please do not rely on the information for
+purchasing or planning purposes. Just like with all projects, the items
+mentioned on the page are subject to change or delay, and the development,
+release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
+
+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 request
+hitting load balancer of a GitLab installation to a Cell that can serve it.
+
+Each Cell should be able to decode each request and classify for 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/cells-feature-schema-changes.md b/doc/architecture/blueprints/cells/cells-feature-schema-changes.md
new file mode 100644
index 00000000000..c43fc6f302e
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-schema-changes.md
@@ -0,0 +1,55 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Schema changes'
+---
+
+DISCLAIMER:
+This page may contain information related to upcoming products, features and
+functionality. It is important to note that the information presented is for
+informational purposes only, so please do not rely on the information for
+purchasing or planning purposes. Just like with all projects, the items
+mentioned on the page are subject to change or delay, and the development,
+release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
+
+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/cells-feature-secrets.md b/doc/architecture/blueprints/cells/cells-feature-secrets.md
new file mode 100644
index 00000000000..44b65c27683
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-secrets.md
@@ -0,0 +1,48 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Secrets'
+---
+
+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 needs
+to be configured.
+
+Some secrets are for inter-component communication, e.g. `GitLab Shell secret`,
+and used only within a cell.
+
+Some secrets are used for features, e.g. `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/cells-feature-snippets.md b/doc/architecture/blueprints/cells/cells-feature-snippets.md
new file mode 100644
index 00000000000..a40b44c7b74
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-snippets.md
@@ -0,0 +1,29 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Snippets'
+---
+
+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
+
+> TL;DR
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/cells-feature-template.md b/doc/architecture/blueprints/cells/cells-feature-template.md
new file mode 100644
index 00000000000..6951421023d
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-template.md
@@ -0,0 +1,29 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Problem A'
+---
+
+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/cells-feature-uploads.md b/doc/architecture/blueprints/cells/cells-feature-uploads.md
new file mode 100644
index 00000000000..9d3500b6c36
--- /dev/null
+++ b/doc/architecture/blueprints/cells/cells-feature-uploads.md
@@ -0,0 +1,29 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells: Uploads'
+---
+
+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/pods/images/iteration0-organizations-introduction.png b/doc/architecture/blueprints/cells/images/iteration0-organizations-introduction.png
index 5725b0fa71f..5725b0fa71f 100644
--- a/doc/architecture/blueprints/pods/images/iteration0-organizations-introduction.png
+++ b/doc/architecture/blueprints/cells/images/iteration0-organizations-introduction.png
Binary files differ
diff --git a/doc/architecture/blueprints/pods/images/pods-and-fulfillment.png b/doc/architecture/blueprints/cells/images/pods-and-fulfillment.png
index fea32d1800e..fea32d1800e 100644
--- a/doc/architecture/blueprints/pods/images/pods-and-fulfillment.png
+++ b/doc/architecture/blueprints/cells/images/pods-and-fulfillment.png
Binary files differ
diff --git a/doc/architecture/blueprints/cells/images/term-cell.png b/doc/architecture/blueprints/cells/images/term-cell.png
new file mode 100644
index 00000000000..40e4a3e29c3
--- /dev/null
+++ b/doc/architecture/blueprints/cells/images/term-cell.png
Binary files differ
diff --git a/doc/architecture/blueprints/cells/images/term-cluster.png b/doc/architecture/blueprints/cells/images/term-cluster.png
new file mode 100644
index 00000000000..d54a3569a08
--- /dev/null
+++ b/doc/architecture/blueprints/cells/images/term-cluster.png
Binary files differ
diff --git a/doc/architecture/blueprints/cells/images/term-organization.png b/doc/architecture/blueprints/cells/images/term-organization.png
new file mode 100644
index 00000000000..172ff7e415a
--- /dev/null
+++ b/doc/architecture/blueprints/cells/images/term-organization.png
Binary files differ
diff --git a/doc/architecture/blueprints/pods/images/term-top-level-namespace.png b/doc/architecture/blueprints/cells/images/term-top-level-namespace.png
index c1cd317d878..c1cd317d878 100644
--- a/doc/architecture/blueprints/pods/images/term-top-level-namespace.png
+++ b/doc/architecture/blueprints/cells/images/term-top-level-namespace.png
Binary files differ
diff --git a/doc/architecture/blueprints/cells/index.md b/doc/architecture/blueprints/cells/index.md
new file mode 100644
index 00000000000..54244265b30
--- /dev/null
+++ b/doc/architecture/blueprints/cells/index.md
@@ -0,0 +1,358 @@
+---
+status: accepted
+creation-date: "2022-09-07"
+authors: [ "@ayufan", "@fzimmer", "@DylanGriffith" ]
+coach: "@ayufan"
+approvers: [ "@fzimmer" ]
+owning-stage: "~devops::enablement"
+participating-stages: []
+---
+
+# Cells
+
+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.
+
+## Summary
+
+Cells is a new architecture for our Software as a Service platform that is horizontally-scalable, resilient, and provides a more consistent user experience. It may also provide additional features in the future, such as data residency control (regions) and federated features.
+
+## Terminology
+
+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 namespaces 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 namespaces but not shared with other Cells. This isolation of infrastructure components means that Cells are independent from each other.
+
+![Term Cell](images/term-cell.png)
+
+#### Cell properties
+
+- Each cell is independent from the others
+- Infrastructure components are shared by organizations and their top-level namespaces 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.
+
+![Term Cluster](images/term-cluster.png)
+
+#### 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](images/term-organization.png)
+
+#### Organization properties
+
+- Top-level namespaces belong to organizations
+- Users can be members of different organizations
+- Organizations are isolated from each other by default meaning that cross-namespace features will only work for namespaces that exist within a single organization
+- User namespaces must not belong to an organization
+
+Discouraged synonyms: Billable entities, customers
+
+### Top-Level namespace
+
+A top-level namespace is the logical object container in the code that represents all groups, subgroups and projects that belong to an organization.
+
+A top-level namespace is the root of nested collection namespaces and projects. The namespace and its related entities form a tree-like hierarchy: Namespaces are the nodes of the tree, projects are the leaves.
+
+Example:
+
+`https://gitlab.com/gitlab-org/gitlab/`:
+
+- `gitlab-org` is a `top-level namespace`; the root for all groups and projects of an organization
+- `gitlab` is a `project`; a project of the organization.
+
+Top-level namespaces may [be replaced by organizations](https://gitlab.com/gitlab-org/gitlab/-/issues/368237#high-level-goals). This proposal only uses the term top-level namespaces as the organization definition is ongoing.
+
+Discouraged synonyms: Root-level namespace
+
+![Term Top-level Namespace](images/term-top-level-namespace.png)
+
+#### Top-level namespace properties
+
+- Top-level namespaces belonging to an organization are located on the same Cell
+- Top-level namespaces can interact with other top-level namespaces that belong to the same organization
+
+### Users
+
+Users are available globally and not restricted to a single Cell. Users can be members of many different organizations with varying permissions. Inside organizations, users can create multiple top-level namespaces. 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 namespaces
+- Users can be a member of multiple top-level namespaces
+- Users can be a member of multiple organizations
+- Users can administer organizations
+- User activity is aggregated in an organization
+- Every user has one personal namespace
+
+## 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 (internal) that the current architecture has scalability limitations, 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
+
+A major challenge for shared-infrastructure architectures is a lack of isolation between top-level namespaces. This can lead to noisy neighbor effects. A organization's behavior inside a top-level namespace 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.
+
+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
+
+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.
+
+## Market segment
+
+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).
+
+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:
+
+1. How will existing `gitlab-org` contributors contribute to the namespace??
+1. How do we move existing top-level namespaces 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.
+
+### 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
+continue with just a single Cell while supporting the option of adding additional
+Cells. Organizations, and possible User decomposition will also be adopted for
+self-managed instances.
+
+## High-level architecture problems to solve
+
+A number of technical issues need to be resolved to implement Cells (in no particular order). This section will be expanded.
+
+1. How are users of an organization routed to the correct Cell?
+1. How do users authenticate?
+1. How are Cells rebalanced?
+1. How are Cells provisioned?
+1. How can Cells implement disaster recovery capabilities?
+
+## 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 namespaces. 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 namespace to a level above. This would mean that a license applies for an organization and all its top-level namespaces.
+- 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](images/pods-and-fulfillment.png)
+
+#### Potential conflicts with Cells
+
+- There are no known conflicts between Fulfillment's plans and Cells
+
+## Iteration plan
+
+We can't ship the entire Cells architecture in one go - it is too large. Instead, we are adopting an iteration plan that provides value along the way.
+
+1. Introduce organizations
+1. Migrate existing top-level namespaces to organizations
+1. Create new organizations on `cell`
+1. Migrate existing organizations from `cell` to `cell`
+1. Add additional Cell capabilities (DR, Regions)
+
+### Iteration 0: Introduce organizations
+
+In the first iteration, we introduce the concept of an organization
+as a way to group top-level namespaces together. Support for organizations **does not require any Cells work** but having them will make all subsequent iterations of Cells simpler. This is mainly because we can group top-level namespaces for a single organization onto a Cell. Within an organization all interactions work as normal but we eliminate any cross-organizational interactions except in well defined cases (e.g. forking).
+
+This means that we don't have a large number of cross-cell interactions.
+
+Introducing organizations allows GitLab to move towards a multi-tenant system that is similar to Discord's with a single user account but many different "servers" - our organizations - that allow users to switch context. This model harmonizes the UX across self-managed and our SaaS Platforms and is a good fit for Cells.
+
+Organizations solve the following problems:
+
+1. We can group top-level namespaces by organization. It is very similar to the initial concept of "instance groups". For example these two top-level namespaces would belong to the organization `GitLab`:
+ 1. `https://gitlab.com/gitlab-org/`
+ 1. `https://gitlab.com/gitlab-com/`
+1. We can isolate organizations from each other. Top-level namespaces of the same organization can interact within organizations but are not allowed to interact with other namespaces in other organizations. This is useful for customers because it means an organization provides clear boundaries - similar to a self-managed instance. This means we don't have to aggregate user dashboards across everything and can locally scope them to organizations.
+1. We don't need to define hierarchies inside an organization. It is a container that could be filled with whatever hierarchy / entity set makes sense (organization, top-level namespaces etc.)
+1. Self-managed instances would set a default organization.
+1. Organizations can control user-profiles in a central way. This could be achieved by having an organization specific user-profile. Such a profile makes it possible for the organization administrators to control the user role in a company, enforce user emails, or show a graphical indicator of a user being part of the organization. An example would be a "GitLab Employee stamp" on comments.
+
+![Move to Organizations](images/iteration0-organizations-introduction.png)
+
+#### Why would customers opt-in to Organizations?
+
+By introducing organizations and Cells we can improve the reliability, performance and availability of our SaaS Platforms.
+
+The first iteration of organizations would also have some benefits by providing more isolation. A simple example would be that `@` mentions could be scoped to an organization.
+
+Future iterations would create additional value but are beyond the scope of this blueprint.
+
+Organizations will likely be required in the future as well.
+
+#### Initial user experience
+
+1. We create a default `GitLab.com public` organization and assign all public top-level namespaces to it. This allows existing users to access all the data on GitLab.com, exactly as it does now.
+1. Any user wanting to opt-in to the benefits of organizations will need to set a single default organization. Any attempts for these users to load a global page like `/dashboard` will end up redirecting to `/-/organizations/<DEFAULT_ORGANIZATION>/dashboard`.
+1. New users that opted in to organizations will only ever see data that is related to a single organization. Upon login, data is shown for the default organization. It will be clear to the user how they can switch to a different organization. Users can still navigate to the `GitLab.com` organization but they won't see TODOs from their new organizations in any such views. Instead they'd need to navigate directly to `/organizations/my-company/-/dashboard`.
+
+### Migrating to Organizations
+
+Existing customers could also opt-in to migrate their existing top-level paid namespaces to become part of an organization. In most cases this will be a 1-to-1 mapping. But in some cases it may allow a customer to move multiple top-level namespaces into one organization (for example GitLab).
+
+Migrating to Organizations would be optional. We could even recruit a few beta testers early on to see if this works for them. GitLab itself could dogfood organizations and we'd surface a lot of issues restricting interactions with other namespaces.
+
+## Iteration 1 - Introduce Cell US 0
+
+### GitLab.com as Cell US0
+
+GitLab.com will be treated as the first cell `Cell US 0`. It will be unique and much larger compared to newly created cells. All existing top-level namespaces and organizations will remain on `Cell US 0` in the first iteration.
+
+### Users are globally available
+
+Users are globally available and the same for all cells. This means that user data needs to be handled separately, for example via decomposition, see [!95941](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95941).
+
+### Cell groundwork
+
+In this iteration, we'll lay all the groundwork to support a second Cell for new organizations. This will be transparent to customers.
+
+## Iteration 2 - Introduce Cell US 1
+
+### Add new organizations to Cell US 1
+
+After we are ready to support a second Cell, newly created organizations are located by default on `Cell US 1`. The user experience for organizations is already well established.
+
+### Migrate existing organizations from Cell US 0 to Cell US 1
+
+We know that we'll have to move organizations from `Cell US 0` to other cells to reduce its size and ultimately retire the existing GitLab.com architecture.
+
+By introducing organizations early, we should be able to draw strong "boundaries" across organizations and support migrating existing organizations to a new Cell.
+
+This is likely going to be GitLab itself - if we can dogfood this, we are likely going to be successful with other organizations as well.
+
+## Iteration 3 - Introduce Regions
+
+We can now leverage the Cells architecture to introduce Regions.
+
+## Iteration 4 - Introduce cross-organizational interactions as needed
+
+Based on user research, we may want to change certain features to work across organizations. Examples include:
+
+- Specific features allow for cross-organization interactions, for example forking, search.
+
+## Technical Proposals
+
+The Cells architecture do have long lasting implications to data processing, location, scalability and the GitLab architecture.
+This section links all different technical proposals that are being evaluated.
+
+- [Stateless Router That Uses a Cache to Pick Cell and Is Redirected When Wrong Cell Is Reached](proposal-stateless-router-with-buffering-requests.md)
+
+- [Stateless Router That Uses a Cache to Pick Cell and pre-flight `/api/v4/cells/learn`](proposal-stateless-router-with-routes-learning.md)
+
+## Impacted features
+
+The Cells architecture will impact many features requiring some of them to be rewritten, or changed significantly.
+This is the list of known affected features with the proposed solutions.
+
+- [Cells: Git Access](cells-feature-git-access.md)
+- [Cells: Data Migration](cells-feature-data-migration.md)
+- [Cells: Database Sequences](cells-feature-database-sequences.md)
+- [Cells: GraphQL](cells-feature-graphql.md)
+- [Cells: Organizations](cells-feature-organizations.md)
+- [Cells: Router Endpoints Classification](cells-feature-router-endpoints-classification.md)
+- [Cells: Schema changes (Postgres and Elasticsearch migrations)](cells-feature-schema-changes.md)
+- [Cells: Backups](cells-feature-backups.md)
+- [Cells: Global Search](cells-feature-global-search.md)
+- [Cells: CI Runners](cells-feature-ci-runners.md)
+- [Cells: Admin Area](cells-feature-admin-area.md)
+- [Cells: Secrets](cells-feature-secrets.md)
+- [Cells: Container Registry](cells-feature-container-registry.md)
+- [Cells: Contributions: Forks](cells-feature-contributions-forks.md)
+- [Cells: Personal Namespaces](cells-feature-personal-namespaces.md)
+- [Cells: Dashboard: Projects, Todos, Issues, Merge Requests, Activity, ...](cells-feature-dashboard.md)
+- [Cells: Snippets](cells-feature-snippets.md)
+- [Cells: Uploads](cells-feature-uploads.md)
+- [Cells: GitLab Pages](cells-feature-gitlab-pages.md)
+- [Cells: Agent for Kubernetes](cells-feature-agent-for-kubernetes.md)
+
+## Links
+
+- [Internal Pods presentation](https://docs.google.com/presentation/d/1x1uIiN8FR9fhL7pzFh9juHOVcSxEY7d2_q4uiKKGD44/edit#slide=id.ge7acbdc97a_0_155)
+- [Cells Epic](https://gitlab.com/groups/gitlab-org/-/epics/7582)
+- [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)
diff --git a/doc/architecture/blueprints/cells/pods-feature-admin-area.md b/doc/architecture/blueprints/cells/pods-feature-admin-area.md
new file mode 100644
index 00000000000..354a55cacac
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-admin-area.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-admin-area.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-admin-area.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-agent-for-kubernetes.md b/doc/architecture/blueprints/cells/pods-feature-agent-for-kubernetes.md
new file mode 100644
index 00000000000..c6a7e138508
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-agent-for-kubernetes.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-agent-for-kubernetes.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-agent-for-kubernetes.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-backups.md b/doc/architecture/blueprints/cells/pods-feature-backups.md
new file mode 100644
index 00000000000..6927142f993
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-backups.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-backups.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-backups.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-ci-runners.md b/doc/architecture/blueprints/cells/pods-feature-ci-runners.md
new file mode 100644
index 00000000000..fd9c0094b2f
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-ci-runners.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-ci-runners.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-ci-runners.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-container-registry.md b/doc/architecture/blueprints/cells/pods-feature-container-registry.md
new file mode 100644
index 00000000000..f6a1aa997c3
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-container-registry.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-container-registry.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-container-registry.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-contributions-forks.md b/doc/architecture/blueprints/cells/pods-feature-contributions-forks.md
new file mode 100644
index 00000000000..441a0da11b7
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-contributions-forks.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-contributions-forks.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-contributions-forks.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-dashboard.md b/doc/architecture/blueprints/cells/pods-feature-dashboard.md
new file mode 100644
index 00000000000..9404f3b647b
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-dashboard.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-dashboard.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-dashboard.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-data-migration.md b/doc/architecture/blueprints/cells/pods-feature-data-migration.md
new file mode 100644
index 00000000000..023b54ae5e4
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-data-migration.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-data-migration.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-data-migration.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-database-sequences.md b/doc/architecture/blueprints/cells/pods-feature-database-sequences.md
new file mode 100644
index 00000000000..785289081bb
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-database-sequences.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-database-sequences.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-database-sequences.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-git-access.md b/doc/architecture/blueprints/cells/pods-feature-git-access.md
new file mode 100644
index 00000000000..bc44137f8d8
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-git-access.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-git-access.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-git-access.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-gitlab-pages.md b/doc/architecture/blueprints/cells/pods-feature-gitlab-pages.md
new file mode 100644
index 00000000000..8043155b1a6
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-gitlab-pages.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-gitlab-pages.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-gitlab-pages.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-global-search.md b/doc/architecture/blueprints/cells/pods-feature-global-search.md
new file mode 100644
index 00000000000..d472b6a9ff6
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-global-search.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-global-search.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-global-search.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-graphql.md b/doc/architecture/blueprints/cells/pods-feature-graphql.md
new file mode 100644
index 00000000000..23d7b0bb856
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-graphql.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-graphql.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-graphql.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-organizations.md b/doc/architecture/blueprints/cells/pods-feature-organizations.md
new file mode 100644
index 00000000000..92ab37a21bf
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-organizations.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-organizations.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-organizations.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-personal-namespaces.md b/doc/architecture/blueprints/cells/pods-feature-personal-namespaces.md
new file mode 100644
index 00000000000..0f05c7d83cb
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-personal-namespaces.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-personal-namespaces.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-personal-namespaces.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-router-endpoints-classification.md b/doc/architecture/blueprints/cells/pods-feature-router-endpoints-classification.md
new file mode 100644
index 00000000000..91de121f694
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-router-endpoints-classification.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-router-endpoints-classification.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-router-endpoints-classification.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-schema-changes.md b/doc/architecture/blueprints/cells/pods-feature-schema-changes.md
new file mode 100644
index 00000000000..5f7de0eb486
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-schema-changes.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-schema-changes.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-schema-changes.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-secrets.md b/doc/architecture/blueprints/cells/pods-feature-secrets.md
new file mode 100644
index 00000000000..5c482e1c986
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-secrets.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-secrets.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-secrets.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-snippets.md b/doc/architecture/blueprints/cells/pods-feature-snippets.md
new file mode 100644
index 00000000000..867c9b49955
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-snippets.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-snippets.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-snippets.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-template.md b/doc/architecture/blueprints/cells/pods-feature-template.md
new file mode 100644
index 00000000000..e1150c3426f
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-template.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-template.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-template.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/pods-feature-uploads.md b/doc/architecture/blueprints/cells/pods-feature-uploads.md
new file mode 100644
index 00000000000..7280f70ebdb
--- /dev/null
+++ b/doc/architecture/blueprints/cells/pods-feature-uploads.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'cells-feature-uploads.md'
+remove_date: '2023-06-14'
+---
+
+This document was moved to [another location](cells-feature-uploads.md).
+
+<!-- This redirect file can be deleted after <2023-06-14>. -->
+<!-- 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/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md b/doc/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md
new file mode 100644
index 00000000000..12102429b03
--- /dev/null
+++ b/doc/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md
@@ -0,0 +1,648 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells Stateless Router Proposal'
+---
+
+This document is a work-in-progress and represents a very early state of the
+Pods design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Pods, 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.
+
+# Proposal: Stateless Router
+
+We will decompose `gitlab_users`, `gitlab_routes` and `gitlab_admin` related
+tables so that they can be shared between all cells and allow any cell to
+authenticate a user and route requests to the correct cell. Cells may receive
+requests for the resources they don't own, but they know how to redirect back
+to the correct cell.
+
+The router is stateless and does not read from the `routes` database which
+means that all interactions with the database still happen from the Rails
+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](index.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.
+
+## Differences
+
+The main difference between this proposal and the one [with learning routes](proposal-stateless-router-with-routes-learning.md)
+is that this proposal always sends requests to any of the Cells. If the requests cannot be processed,
+the requests will be bounced back with relevant headers. This requires that request to be buffered.
+It allows that request decoding can be either via URI or Body of request by Rails.
+This means that each request might be sent more than once and be processed more than once as result.
+
+The [with learning routes proposal](proposal-stateless-router-with-routes-learning.md) requires that
+routable information is always encoded in URI, and the router sends a pre-flight request.
+
+## Summary in diagrams
+
+This shows how a user request routes via DNS to the nearest router and the router chooses a cell to send the request to.
+
+```mermaid
+graph TD;
+ user((User));
+ dns[DNS];
+ router_us(Router);
+ router_eu(Router);
+ cell_us0{Cell US0};
+ cell_us1{Cell US1};
+ cell_eu0{Cell EU0};
+ cell_eu1{Cell EU1};
+ user-->dns;
+ dns-->router_us;
+ dns-->router_eu;
+ subgraph Europe
+ router_eu-->cell_eu0;
+ router_eu-->cell_eu1;
+ end
+ subgraph United States
+ router_us-->cell_us0;
+ router_us-->cell_us1;
+ end
+```
+
+<details><summary>More detail</summary>
+
+This shows that the router can actually send requests to any cell. The user will
+get the closest router to them geographically.
+
+```mermaid
+graph TD;
+ user((User));
+ dns[DNS];
+ router_us(Router);
+ router_eu(Router);
+ cell_us0{Cell US0};
+ cell_us1{Cell US1};
+ cell_eu0{Cell EU0};
+ cell_eu1{Cell EU1};
+ user-->dns;
+ dns-->router_us;
+ dns-->router_eu;
+ subgraph Europe
+ router_eu-->cell_eu0;
+ router_eu-->cell_eu1;
+ end
+ subgraph United States
+ router_us-->cell_us0;
+ router_us-->cell_us1;
+ end
+ router_eu-.->cell_us0;
+ router_eu-.->cell_us1;
+ router_us-.->cell_eu0;
+ router_us-.->cell_eu1;
+```
+
+</details>
+
+<details><summary>Even more detail</summary>
+
+This shows the databases. `gitlab_users` and `gitlab_routes` exist only in the
+US region but are replicated to other regions. Replication does not have an
+arrow because it's too hard to read the diagram.
+
+```mermaid
+graph TD;
+ user((User));
+ dns[DNS];
+ router_us(Router);
+ router_eu(Router);
+ cell_us0{Cell US0};
+ cell_us1{Cell US1};
+ cell_eu0{Cell EU0};
+ cell_eu1{Cell EU1};
+ db_gitlab_users[(gitlab_users Primary)];
+ db_gitlab_routes[(gitlab_routes Primary)];
+ db_gitlab_users_replica[(gitlab_users Replica)];
+ db_gitlab_routes_replica[(gitlab_routes Replica)];
+ db_cell_us0[(gitlab_main/gitlab_ci Cell US0)];
+ db_cell_us1[(gitlab_main/gitlab_ci Cell US1)];
+ db_cell_eu0[(gitlab_main/gitlab_ci Cell EU0)];
+ db_cell_eu1[(gitlab_main/gitlab_ci Cell EU1)];
+ user-->dns;
+ dns-->router_us;
+ dns-->router_eu;
+ subgraph Europe
+ router_eu-->cell_eu0;
+ router_eu-->cell_eu1;
+ cell_eu0-->db_cell_eu0;
+ cell_eu0-->db_gitlab_users_replica;
+ cell_eu0-->db_gitlab_routes_replica;
+ cell_eu1-->db_gitlab_users_replica;
+ cell_eu1-->db_gitlab_routes_replica;
+ cell_eu1-->db_cell_eu1;
+ end
+ subgraph United States
+ router_us-->cell_us0;
+ router_us-->cell_us1;
+ cell_us0-->db_cell_us0;
+ cell_us0-->db_gitlab_users;
+ cell_us0-->db_gitlab_routes;
+ cell_us1-->db_gitlab_users;
+ cell_us1-->db_gitlab_routes;
+ cell_us1-->db_cell_us1;
+ end
+ router_eu-.->cell_us0;
+ router_eu-.->cell_us1;
+ router_us-.->cell_eu0;
+ router_us-.->cell_eu1;
+```
+
+</details>
+
+## Summary of changes
+
+1. Tables related to User data (including profile settings, authentication credentials, personal access tokens) are decomposed into a `gitlab_users` schema
+1. The `routes` table is decomposed into `gitlab_routes` schema
+1. The `application_settings` (and probably a few other instance level tables) are decomposed into `gitlab_admin` schema
+1. A new column `routes.cell_id` is added to `routes` table
+1. A new Router service exists to choose which cell to route a request to.
+1. A new concept will be introduced in GitLab called an organization and a user can select a "default organization" and this will be a user level setting. The default organization is used to redirect users away from ambiguous routes like `/dashboard` to organization scoped routes like `/organizations/my-organization/-/dashboard`. Legacy users will have a special default organization that allows them to keep using global resources on `Cell US0`. All existing namespaces will initially move to this public organization.
+1. If a cell receives a request for a `routes.cell_id` that it does not own it returns a `302` with `X-Gitlab-Cell-Redirect` header so that the router can send the request to the correct cell. The correct cell can also set a header `X-Gitlab-Cell-Cache` which contains information about how this request should be cached to remember the cell. For example if the request was `/gitlab-org/gitlab` then the header would encode `/gitlab-org/* => Cell US0` (for example, any requests starting with `/gitlab-org/` can always be routed to `Cell US0`
+1. When the cell does not know (from the cache) which cell to send a request to it just picks a random cell within it's region
+1. Writes to `gitlab_users` and `gitlab_routes` are sent to a primary PostgreSQL server in our `US` region but reads can come from replicas in the same region. This will add latency for these writes but we expect they are infrequent relative to the rest of GitLab.
+
+## Detailed explanation of default organization in the first iteration
+
+All users will get a new column `users.default_organization` which they can
+control in user settings. We will introduce a concept of the
+`GitLab.com Public` organization. This will be set as the default organization for all existing
+users. This organization will allow the user to see data from all namespaces in
+`Cell US0` (for example, our original GitLab.com instance). This behavior can be invisible to
+existing users such that they don't even get told when they are viewing a
+global page like `/dashboard` that it's even scoped to an organization.
+
+Any new users with a default organization other than `GitLab.com Public` will have
+a distinct user experience and will be fully aware that every page they load is
+only ever scoped to a single organization. These users can never
+load any global pages like `/dashboard` and will end up being redirected to
+`/organizations/<DEFAULT_ORGANIZATION>/-/dashboard`. This may also be the case
+for legacy APIs and such users may only ever be able to use APIs scoped to a
+organization.
+
+## Detailed explanation of Admin Area settings
+
+We believe that maintaining and synchronizing Admin Area settings will be
+frustrating and painful so to avoid this we will decompose and share all Admin Area
+settings in the `gitlab_admin` schema. This should be safe (similar to other
+shared schemas) because these receive very little write traffic.
+
+In cases where different cells need different settings (for example, the
+Elasticsearch URL), we will either decide to use a templated
+format in the relevant `application_settings` row which allows it to be dynamic
+per cell. Alternatively if that proves difficult we'll introduce a new table
+called `per_cell_application_settings` and this will have 1 row per cell to allow
+setting different settings per cell. It will still be part of the `gitlab_admin`
+schema and shared which will allow us to centrally manage it and simplify
+keeping settings in sync for all cells.
+
+## Pros
+
+1. Router is stateless and can live in many regions. We use Anycast DNS to resolve to nearest region for the user.
+1. Cells can receive requests for namespaces in the wrong cell and the user
+ still gets the right response as well as caching at the router that
+ ensures the next request is sent to the correct cell so the next request
+ will go to the correct cell
+1. The majority of the code still lives in `gitlab` rails codebase. The Router doesn't actually need to understand how GitLab URLs are composed.
+1. Since the responsibility to read and write `gitlab_users`,
+ `gitlab_routes` and `gitlab_admin` still lives in Rails it means minimal
+ changes will be needed to the Rails application compared to extracting
+ services that need to isolate the domain models and build new interfaces.
+1. Compared to a separate routing service this allows the Rails application
+ to encode more complex rules around how to map URLs to the correct cell
+ and may work for some existing API endpoints.
+1. All the new infrastructure (just a router) is optional and a single-cell
+ self-managed installation does not even need to run the Router and there are
+ no other new services.
+
+## Cons
+
+1. `gitlab_users`, `gitlab_routes` and `gitlab_admin` databases may need to be
+ replicated across regions and writes need to go across regions. We need to
+ do an analysis on write TPS for the relevant tables to determine if this is
+ feasible.
+1. Sharing access to the database from many different Cells means that they are
+ all coupled at the Postgres schema level and this means changes to the
+ database schema need to be done carefully in sync with the deployment of all
+ Cells. This limits us to ensure that Cells are kept in closely similar
+ versions compared to an architecture with shared services that have an API
+ we control.
+1. Although most data is stored in the right region there can be requests
+ proxied from another region which may be an issue for certain types
+ of compliance.
+1. Data in `gitlab_users` and `gitlab_routes` databases must be replicated in
+ all regions which may be an issue for certain types of compliance.
+1. The router cache may need to be very large if we get a wide variety of URLs
+ (for example, long tail). In such a case we may need to implement a 2nd level of
+ caching in user cookies so their frequently accessed pages always go to the
+ right cell the first time.
+1. Having shared database access for `gitlab_users` and `gitlab_routes`
+ from multiple cells is an unusual architecture decision compared to
+ extracting services that are called from multiple cells.
+1. It is very likely we won't be able to find cacheable elements of a
+ GraphQL URL and often existing GraphQL endpoints are heavily dependent on
+ ids that won't be in the `routes` table so cells won't necessarily know
+ what cell has the data. As such we'll probably have to update our GraphQL
+ calls to include an organization context in the path like
+ `/api/organizations/<organization>/graphql`.
+1. This architecture implies that implemented endpoints can only access data
+ that are readily accessible on a given Cell, but are unlikely
+ to aggregate information from many Cells.
+1. All unknown routes are sent to the latest deployment which we assume to be `Cell US0`.
+ This is required as newly added endpoints will be only decodable by latest cell.
+ This Cell could later redirect to correct one that can serve the given request.
+ Since request processing might be heavy some Cells might receive significant amount
+ of traffic due to that.
+
+## Example database configuration
+
+Handling shared `gitlab_users`, `gitlab_routes` and `gitlab_admin` databases, while having dedicated `gitlab_main` and `gitlab_ci` databases should already be handled by the way we use `config/database.yml`. We should also, already be able to handle the dedicated EU replicas while having a single US primary for `gitlab_users` and `gitlab_routes`. Below is a snippet of part of the database configuration for the Cell architecture described above.
+
+<details><summary>Cell US0</summary>
+
+```yaml
+# config/database.yml
+production:
+ main:
+ host: postgres-main.cell-us0.primary.consul
+ load_balancing:
+ discovery: postgres-main.cell-us0.replicas.consul
+ ci:
+ host: postgres-ci.cell-us0.primary.consul
+ load_balancing:
+ discovery: postgres-ci.cell-us0.replicas.consul
+ users:
+ host: postgres-users-primary.consul
+ load_balancing:
+ discovery: postgres-users-replicas.us.consul
+ routes:
+ host: postgres-routes-primary.consul
+ load_balancing:
+ discovery: postgres-routes-replicas.us.consul
+ admin:
+ host: postgres-admin-primary.consul
+ load_balancing:
+ discovery: postgres-admin-replicas.us.consul
+```
+
+</details>
+
+<details><summary>Cell EU0</summary>
+
+```yaml
+# config/database.yml
+production:
+ main:
+ host: postgres-main.cell-eu0.primary.consul
+ load_balancing:
+ discovery: postgres-main.cell-eu0.replicas.consul
+ ci:
+ host: postgres-ci.cell-eu0.primary.consul
+ load_balancing:
+ discovery: postgres-ci.cell-eu0.replicas.consul
+ users:
+ host: postgres-users-primary.consul
+ load_balancing:
+ discovery: postgres-users-replicas.eu.consul
+ routes:
+ host: postgres-routes-primary.consul
+ load_balancing:
+ discovery: postgres-routes-replicas.eu.consul
+ admin:
+ host: postgres-admin-primary.consul
+ load_balancing:
+ discovery: postgres-admin-replicas.eu.consul
+```
+
+</details>
+
+## Request flows
+
+1. `gitlab-org` is a top level namespace and lives in `Cell US0` in the `GitLab.com Public` organization
+1. `my-company` is a top level namespace and lives in `Cell EU0` in the `my-organization` organization
+
+### Experience for paying user that is part of `my-organization`
+
+Such a user will have a default organization set to `/my-organization` and will be
+unable to load any global routes outside of this organization. They may load other
+projects/namespaces but their MR/Todo/Issue counts at the top of the page will
+not be correctly populated in the first iteration. The user will be aware of
+this limitation.
+
+#### Navigates to `/my-company/my-project` while logged in
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. They request `/my-company/my-project` without the router cache, so the router chooses randomly `Cell EU1`
+1. `Cell EU1` does not have `/my-company`, but it knows that it lives in `Cell EU0` so it redirects the router to `Cell EU0`
+1. `Cell EU0` returns the correct response as well as setting the cache headers for the router `/my-company/* => Cell EU0`
+1. The router now caches and remembers any request paths matching `/my-company/*` should go to `Cell EU0`
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ participant cell_eu1 as Cell EU1
+ user->>router_eu: GET /my-company/my-project
+ router_eu->>cell_eu1: GET /my-company/my-project
+ cell_eu1->>router_eu: 302 /my-company/my-project X-Gitlab-Cell-Redirect={cell:Cell EU0}
+ router_eu->>cell_eu0: GET /my-company/my-project
+ cell_eu0->>user: <h1>My Project... X-Gitlab-Cell-Cache={path_prefix:/my-company/}
+```
+
+#### Navigates to `/my-company/my-project` while not logged in
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. The router does not have `/my-company/*` cached yet so it chooses randomly `Cell EU1`
+1. `Cell EU1` redirects them through a login flow
+1. Still they request `/my-company/my-project` without the router cache, so the router chooses a random cell `Cell EU1`
+1. `Cell EU1` does not have `/my-company`, but it knows that it lives in `Cell EU0` so it redirects the router to `Cell EU0`
+1. `Cell EU0` returns the correct response as well as setting the cache headers for the router `/my-company/* => Cell EU0`
+1. The router now caches and remembers any request paths matching `/my-company/*` should go to `Cell EU0`
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ participant cell_eu1 as Cell EU1
+ user->>router_eu: GET /my-company/my-project
+ router_eu->>cell_eu1: GET /my-company/my-project
+ cell_eu1->>user: 302 /users/sign_in?redirect=/my-company/my-project
+ user->>router_eu: GET /users/sign_in?redirect=/my-company/my-project
+ router_eu->>cell_eu1: GET /users/sign_in?redirect=/my-company/my-project
+ cell_eu1->>user: <h1>Sign in...
+ user->>router_eu: POST /users/sign_in?redirect=/my-company/my-project
+ router_eu->>cell_eu1: POST /users/sign_in?redirect=/my-company/my-project
+ cell_eu1->>user: 302 /my-company/my-project
+ user->>router_eu: GET /my-company/my-project
+ router_eu->>cell_eu1: GET /my-company/my-project
+ cell_eu1->>router_eu: 302 /my-company/my-project X-Gitlab-Cell-Redirect={cell:Cell EU0}
+ router_eu->>cell_eu0: GET /my-company/my-project
+ cell_eu0->>user: <h1>My Project... X-Gitlab-Cell-Cache={path_prefix:/my-company/}
+```
+
+#### Navigates to `/my-company/my-other-project` after last step
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. The router cache now has `/my-company/* => Cell EU0`, so the router chooses `Cell EU0`
+1. `Cell EU0` returns the correct response as well as the cache header again
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ participant cell_eu1 as Cell EU1
+ user->>router_eu: GET /my-company/my-project
+ router_eu->>cell_eu0: GET /my-company/my-project
+ cell_eu0->>user: <h1>My Project... X-Gitlab-Cell-Cache={path_prefix:/my-company/}
+```
+
+#### Navigates to `/gitlab-org/gitlab` after last step
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. The router has no cached value for this URL so randomly chooses `Cell EU0`
+1. `Cell EU0` redirects the router to `Cell US0`
+1. `Cell US0` returns the correct response as well as the cache header again
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ participant cell_us0 as Cell US0
+ user->>router_eu: GET /gitlab-org/gitlab
+ router_eu->>cell_eu0: GET /gitlab-org/gitlab
+ cell_eu0->>router_eu: 302 /gitlab-org/gitlab X-Gitlab-Cell-Redirect={cell:Cell US0}
+ router_eu->>cell_us0: GET /gitlab-org/gitlab
+ cell_us0->>user: <h1>GitLab.org... X-Gitlab-Cell-Cache={path_prefix:/gitlab-org/}
+```
+
+In this case the user is not on their "default organization" so their TODO
+counter will not include their normal todos. We may choose to highlight this in
+the UI somewhere. A future iteration may be able to fetch that for them from
+their default organization.
+
+#### Navigates to `/`
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. Router does not have a cache for `/` route (specifically rails never tells it to cache this route)
+1. The Router choose `Cell EU0` randomly
+1. The Rails application knows the users default organization is `/my-organization`, so
+ it redirects the user to `/organizations/my-organization/-/dashboard`
+1. The Router has a cached value for `/organizations/my-organization/*` so it then sends the
+ request to `POD EU0`
+1. `Cell EU0` serves up a new page `/organizations/my-organization/-/dashboard` which is the same
+ dashboard view we have today but scoped to an organization clearly in the UI
+1. The user is (optionally) presented with a message saying that data on this page is only
+ from their default organization and that they can change their default
+ organization if it's not right.
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ user->>router_eu: GET /
+ router_eu->>cell_eu0: GET /
+ cell_eu0->>user: 302 /organizations/my-organization/-/dashboard
+ user->>router: GET /organizations/my-organization/-/dashboard
+ router->>cell_eu0: GET /organizations/my-organization/-/dashboard
+ cell_eu0->>user: <h1>My Company Dashboard... X-Gitlab-Cell-Cache={path_prefix:/organizations/my-organization/}
+```
+
+#### Navigates to `/dashboard`
+
+As above, they will end up on `/organizations/my-organization/-/dashboard` as
+the rails application will already redirect `/` to the dashboard page.
+
+### Navigates to `/not-my-company/not-my-project` while logged in (but they don't have access since this project/group is private)
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. The router knows that `/not-my-company` lives in `Cell US1` so sends the request to this
+1. The user does not have access so `Cell US1` returns 404
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_us1 as Cell US1
+ user->>router_eu: GET /not-my-company/not-my-project
+ router_eu->>cell_us1: GET /not-my-company/not-my-project
+ cell_us1->>user: 404
+```
+
+#### Creates a new top level namespace
+
+The user will be asked which organization they want the namespace to belong to.
+If they select `my-organization` then it will end up on the same cell as all
+other namespaces in `my-organization`. If they select nothing we default to
+`GitLab.com Public` and it is clear to the user that this is isolated from
+their existing organization such that they won't be able to see data from both
+on a single page.
+
+### Experience for GitLab team member that is part of `/gitlab-org`
+
+Such a user is considered a legacy user and has their default organization set to
+`GitLab.com Public`. This is a "meta" organization that does not really exist but
+the Rails application knows to interpret this organization to mean that they are
+allowed to use legacy global functionality like `/dashboard` to see data across
+namespaces located on `Cell US0`. The rails backend also knows that the default cell to render any ambiguous
+routes like `/dashboard` is `Cell US0`. Lastly the user will be allowed to
+navigate to organizations on another cell like `/my-organization` but when they do the
+user will see a message indicating that some data may be missing (for example, the
+MRs/Issues/Todos) counts.
+
+#### Navigates to `/gitlab-org/gitlab` while not logged in
+
+1. User is in the US so DNS resolves to the US router
+1. The router knows that `/gitlab-org` lives in `Cell US0` so sends the request
+ to this cell
+1. `Cell US0` serves up the response
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_us as Router US
+ participant cell_us0 as Cell US0
+ user->>router_us: GET /gitlab-org/gitlab
+ router_us->>cell_us0: GET /gitlab-org/gitlab
+ cell_us0->>user: <h1>GitLab.org... X-Gitlab-Cell-Cache={path_prefix:/gitlab-org/}
+```
+
+#### Navigates to `/`
+
+1. User is in US so DNS resolves to the router in US
+1. Router does not have a cache for `/` route (specifically rails never tells it to cache this route)
+1. The Router chooses `Cell US1` randomly
+1. The Rails application knows the users default organization is `GitLab.com Public`, so
+ it redirects the user to `/dashboards` (only legacy users can see
+ `/dashboard` global view)
+1. Router does not have a cache for `/dashboard` route (specifically rails never tells it to cache this route)
+1. The Router chooses `Cell US1` randomly
+1. The Rails application knows the users default organization is `GitLab.com Public`, so
+ it allows the user to load `/dashboards` (only legacy users can see
+ `/dashboard` global view) and redirects to router the legacy cell which is `Cell US0`
+1. `Cell US0` serves up the global view dashboard page `/dashboard` which is the same
+ dashboard view we have today
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_us as Router US
+ participant cell_us0 as Cell US0
+ participant cell_us1 as Cell US1
+ user->>router_us: GET /
+ router_us->>cell_us1: GET /
+ cell_us1->>user: 302 /dashboard
+ user->>router_us: GET /dashboard
+ router_us->>cell_us1: GET /dashboard
+ cell_us1->>router_us: 302 /dashboard X-Gitlab-Cell-Redirect={cell:Cell US0}
+ router_us->>cell_us0: GET /dashboard
+ cell_us0->>user: <h1>Dashboard...
+```
+
+#### Navigates to `/my-company/my-other-project` while logged in (but they don't have access since this project is private)
+
+They get a 404.
+
+### Experience for non-authenticated users
+
+Flow is similar to authenticated users except global routes like `/dashboard` will
+redirect to the login page as there is no default organization to choose from.
+
+### A new customers signs up
+
+They will be asked if they are already part of an organization or if they'd
+like to create one. If they choose neither they end up no the default
+`GitLab.com Public` organization.
+
+### An organization is moved from 1 cell to another
+
+TODO
+
+### GraphQL/API requests which don't include the namespace in the URL
+
+TODO
+
+### The autocomplete suggestion functionality in the search bar which remembers recent issues/MRs
+
+TODO
+
+### Global search
+
+TODO
+
+## Administrator
+
+### Loads `/admin` page
+
+1. Router picks a random cell `Cell US0`
+1. Cell US0 redirects user to `/admin/cells/cellus0`
+1. Cell US0 renders an Admin Area page and also returns a cache header to cache `/admin/cellss/cellus0/* => Cell US0`. The Admin Area page contains a dropdown list showing other cells they could select and it changes the query parameter.
+
+Admin Area settings in Postgres are all shared across all cells to avoid
+divergence but we still make it clear in the URL and UI which cell is serving
+the Admin Area page as there is dynamic data being generated from these pages and
+the operator may want to view a specific cell.
+
+## More Technical Problems To Solve
+
+### Replicating User Sessions Between All Cells
+
+Today user sessions live in Redis but each cell will have their own Redis instance. We already use a dedicated Redis instance for sessions so we could consider sharing this with all cells like we do with `gitlab_users` PostgreSQL database. But an important consideration will be latency as we would still want to mostly fetch sessions from the same region.
+
+An alternative might be that user sessions get moved to a JWT payload that encodes all the session data but this has downsides. For example, it is difficult to expire a user session, when their password changes or for other reasons, if the session lives in a JWT controlled by the user.
+
+### How do we migrate between Cells
+
+Migrating data between cells will need to factor all data stores:
+
+1. PostgreSQL
+1. Redis Shared State
+1. Gitaly
+1. Elasticsearch
+
+### Is it still possible to leak the existence of private groups via a timing attack?
+
+If you have router in EU, and you know that EU router by default redirects
+to EU located Cells, you know their latency (lets assume 10 ms). Now, if your
+request is bounced back and redirected to US which has different latency
+(lets assume that roundtrip will be around 60 ms) you can deduce that 404 was
+returned by US Cell and know that your 404 is in fact 403.
+
+We may defer this until we actually implement a cell in a different region. Such timing attacks are already theoretically possible with the way we do permission checks today but the timing difference is probably too small to be able to detect.
+
+One technique to mitigate this risk might be to have the router add a random
+delay to any request that returns 404 from a cell.
+
+## Should runners be shared across all cells?
+
+We have 2 options and we should decide which is easier:
+
+1. Decompose runner registration and queuing tables and share them across all
+ cells. This may have implications for scalability, and we'd need to consider
+ if this would include group/project runners as this may have scalability
+ concerns as these are high traffic tables that would need to be shared.
+1. Runners are registered per-cell and, we probably have a separate fleet of
+ runners for every cell or just register the same runners to many cells which
+ may have implications for queueing
+
+## How do we guarantee unique ids across all cells for things that cannot conflict?
+
+This project assumes at least namespaces and projects have unique ids across
+all cells as many requests need to be routed based on their ID. Since those
+tables are across different databases then guaranteeing a unique ID will
+require a new solution. There are likely other tables where unique IDs are
+necessary and depending on how we resolve routing for GraphQL and other APIs
+and other design goals it may be determined that we want the primary key to be
+unique for all tables.
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
new file mode 100644
index 00000000000..7f25441c75f
--- /dev/null
+++ b/doc/architecture/blueprints/cells/proposal-stateless-router-with-routes-learning.md
@@ -0,0 +1,672 @@
+---
+stage: enablement
+group: Tenant Scale
+comments: false
+description: 'Cells Stateless Router Proposal'
+---
+
+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.
+
+# Proposal: Stateless Router
+
+We will decompose `gitlab_users`, `gitlab_routes` and `gitlab_admin` related
+tables so that they can be shared between all cells and allow any cell to
+authenticate a user and route requests to the correct cell. Cells may receive
+requests for the resources they don't own, but they know how to redirect back
+to the correct cell.
+
+The router is stateless and does not read from the `routes` database which
+means that all interactions with the database still happen from the Rails
+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](index.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.
+
+## Differences
+
+The main difference between this proposal and one [with buffering requests](proposal-stateless-router-with-buffering-requests.md)
+is that this proposal uses a pre-flight API request (`/api/v4/cells/learn`) to redirect the request body to the correct Cell.
+This means that each request is sent exactly once to be processed, but the URI is used to decode which Cell it should be directed.
+
+## Summary in diagrams
+
+This shows how a user request routes via DNS to the nearest router and the router chooses a cell to send the request to.
+
+```mermaid
+graph TD;
+ user((User));
+ dns[DNS];
+ router_us(Router);
+ router_eu(Router);
+ cell_us0{Cell US0};
+ cell_us1{Cell US1};
+ cell_eu0{Cell EU0};
+ cell_eu1{Cell EU1};
+ user-->dns;
+ dns-->router_us;
+ dns-->router_eu;
+ subgraph Europe
+ router_eu-->cell_eu0;
+ router_eu-->cell_eu1;
+ end
+ subgraph United States
+ router_us-->cell_us0;
+ router_us-->cell_us1;
+ end
+```
+
+### More detail
+
+This shows that the router can actually send requests to any cell. The user will
+get the closest router to them geographically.
+
+```mermaid
+graph TD;
+ user((User));
+ dns[DNS];
+ router_us(Router);
+ router_eu(Router);
+ cell_us0{Cell US0};
+ cell_us1{Cell US1};
+ cell_eu0{Cell EU0};
+ cell_eu1{Cell EU1};
+ user-->dns;
+ dns-->router_us;
+ dns-->router_eu;
+ subgraph Europe
+ router_eu-->cell_eu0;
+ router_eu-->cell_eu1;
+ end
+ subgraph United States
+ router_us-->cell_us0;
+ router_us-->cell_us1;
+ end
+ router_eu-.->cell_us0;
+ router_eu-.->cell_us1;
+ router_us-.->cell_eu0;
+ router_us-.->cell_eu1;
+```
+
+### Even more detail
+
+This shows the databases. `gitlab_users` and `gitlab_routes` exist only in the
+US region but are replicated to other regions. Replication does not have an
+arrow because it's too hard to read the diagram.
+
+```mermaid
+graph TD;
+ user((User));
+ dns[DNS];
+ router_us(Router);
+ router_eu(Router);
+ cell_us0{Cell US0};
+ cell_us1{Cell US1};
+ cell_eu0{Cell EU0};
+ cell_eu1{Cell EU1};
+ db_gitlab_users[(gitlab_users Primary)];
+ db_gitlab_routes[(gitlab_routes Primary)];
+ db_gitlab_users_replica[(gitlab_users Replica)];
+ db_gitlab_routes_replica[(gitlab_routes Replica)];
+ db_cell_us0[(gitlab_main/gitlab_ci Cell US0)];
+ db_cell_us1[(gitlab_main/gitlab_ci Cell US1)];
+ db_cell_eu0[(gitlab_main/gitlab_ci Cell EU0)];
+ db_cell_eu1[(gitlab_main/gitlab_ci Cell EU1)];
+ user-->dns;
+ dns-->router_us;
+ dns-->router_eu;
+ subgraph Europe
+ router_eu-->cell_eu0;
+ router_eu-->cell_eu1;
+ cell_eu0-->db_cell_eu0;
+ cell_eu0-->db_gitlab_users_replica;
+ cell_eu0-->db_gitlab_routes_replica;
+ cell_eu1-->db_gitlab_users_replica;
+ cell_eu1-->db_gitlab_routes_replica;
+ cell_eu1-->db_cell_eu1;
+ end
+ subgraph United States
+ router_us-->cell_us0;
+ router_us-->cell_us1;
+ cell_us0-->db_cell_us0;
+ cell_us0-->db_gitlab_users;
+ cell_us0-->db_gitlab_routes;
+ cell_us1-->db_gitlab_users;
+ cell_us1-->db_gitlab_routes;
+ cell_us1-->db_cell_us1;
+ end
+ router_eu-.->cell_us0;
+ router_eu-.->cell_us1;
+ router_us-.->cell_eu0;
+ router_us-.->cell_eu1;
+```
+
+## Summary of changes
+
+1. Tables related to User data (including profile settings, authentication credentials, personal access tokens) are decomposed into a `gitlab_users` schema
+1. The `routes` table is decomposed into `gitlab_routes` schema
+1. The `application_settings` (and probably a few other instance level tables) are decomposed into `gitlab_admin` schema
+1. A new column `routes.cell_id` is added to `routes` table
+1. A new Router service exists to choose which cell to route a request to.
+1. If a router receives a new request it will send `/api/v4/cells/learn?method=GET&path_info=/group-org/project` to learn which Cell can process it
+1. A new concept will be introduced in GitLab called an organization
+1. We require all existing endpoints to be routable by URI, or be fixed to a specific Cell for processing. This requires changing ambiguous endpoints like `/dashboard` to be scoped like `/organizations/my-organization/-/dashboard`
+1. Endpoints like `/admin` would be routed always to the specific Cell, like `cell_0`
+1. Each Cell can respond to `/api/v4/cells/learn` and classify each endpoint
+1. Writes to `gitlab_users` and `gitlab_routes` are sent to a primary PostgreSQL server in our `US` region but reads can come from replicas in the same region. This will add latency for these writes but we expect they are infrequent relative to the rest of GitLab.
+
+## Pre-flight request learning
+
+While processing a request the URI will be decoded and a pre-flight request
+will be sent for each non-cached endpoint.
+
+When asking for the endpoint GitLab Rails will return information about
+the routable path. GitLab Rails will decode `path_info` and match it to
+an existing endpoint and find a routable entity (like project). The router will
+treat this as short-lived cache information.
+
+1. Prefix match: `/api/v4/cells/learn?method=GET&path_info=/gitlab-org/gitlab-test/-/issues`
+
+ ```json
+ {
+ "path": "/gitlab-org/gitlab-test",
+ "cell": "cell_0",
+ "source": "routable"
+ }
+ ```
+
+1. Some endpoints might require an exact match: `/api/v4/cells/learn?method=GET&path_info=/-/profile`
+
+ ```json
+ {
+ "path": "/-/profile",
+ "cell": "cell_0",
+ "source": "fixed",
+ "exact": true
+ }
+ ```
+
+## Detailed explanation of default organization in the first iteration
+
+All users will get a new column `users.default_organization` which they can
+control in user settings. We will introduce a concept of the
+`GitLab.com Public` organization. This will be set as the default organization for all existing
+users. This organization will allow the user to see data from all namespaces in
+`Cell US0` (ie. our original GitLab.com instance). This behavior can be invisible to
+existing users such that they don't even get told when they are viewing a
+global page like `/dashboard` that it's even scoped to an organization.
+
+Any new users with a default organization other than `GitLab.com Public` will have
+a distinct user experience and will be fully aware that every page they load is
+only ever scoped to a single organization. These users can never
+load any global pages like `/dashboard` and will end up being redirected to
+`/organizations/<DEFAULT_ORGANIZATION>/-/dashboard`. This may also be the case
+for legacy APIs and such users may only ever be able to use APIs scoped to a
+organization.
+
+## Detailed explanation of Admin Area settings
+
+We believe that maintaining and synchronizing Admin Area settings will be
+frustrating and painful so to avoid this we will decompose and share all Admin Area
+settings in the `gitlab_admin` schema. This should be safe (similar to other
+shared schemas) because these receive very little write traffic.
+
+In cases where different cells need different settings (eg. the
+Elasticsearch URL), we will either decide to use a templated
+format in the relevant `application_settings` row which allows it to be dynamic
+per cell. Alternatively if that proves difficult we'll introduce a new table
+called `per_cell_application_settings` and this will have 1 row per cell to allow
+setting different settings per cell. It will still be part of the `gitlab_admin`
+schema and shared which will allow us to centrally manage it and simplify
+keeping settings in sync for all cells.
+
+## Pros
+
+1. Router is stateless and can live in many regions. We use Anycast DNS to resolve to nearest region for the user.
+1. Cells can receive requests for namespaces in the wrong cell and the user
+ still gets the right response as well as caching at the router that
+ ensures the next request is sent to the correct cell so the next request
+ will go to the correct cell
+1. The majority of the code still lives in `gitlab` rails codebase. The Router doesn't actually need to understand how GitLab URLs are composed.
+1. Since the responsibility to read and write `gitlab_users`,
+ `gitlab_routes` and `gitlab_admin` still lives in Rails it means minimal
+ changes will be needed to the Rails application compared to extracting
+ services that need to isolate the domain models and build new interfaces.
+1. Compared to a separate routing service this allows the Rails application
+ to encode more complex rules around how to map URLs to the correct cell
+ and may work for some existing API endpoints.
+1. All the new infrastructure (just a router) is optional and a single-cell
+ self-managed installation does not even need to run the Router and there are
+ no other new services.
+
+## Cons
+
+1. `gitlab_users`, `gitlab_routes` and `gitlab_admin` databases may need to be
+ replicated across regions and writes need to go across regions. We need to
+ do an analysis on write TPS for the relevant tables to determine if this is
+ feasible.
+1. Sharing access to the database from many different Cells means that they are
+ all coupled at the Postgres schema level and this means changes to the
+ database schema need to be done carefully in sync with the deployment of all
+ Cells. This limits us to ensure that Cells are kept in closely similar
+ versions compared to an architecture with shared services that have an API
+ we control.
+1. Although most data is stored in the right region there can be requests
+ proxied from another region which may be an issue for certain types
+ of compliance.
+1. Data in `gitlab_users` and `gitlab_routes` databases must be replicated in
+ all regions which may be an issue for certain types of compliance.
+1. The router cache may need to be very large if we get a wide variety of URLs
+ (ie. long tail). In such a case we may need to implement a 2nd level of
+ caching in user cookies so their frequently accessed pages always go to the
+ right cell the first time.
+1. Having shared database access for `gitlab_users` and `gitlab_routes`
+ from multiple cells is an unusual architecture decision compared to
+ extracting services that are called from multiple cells.
+1. It is very likely we won't be able to find cacheable elements of a
+ GraphQL URL and often existing GraphQL endpoints are heavily dependent on
+ ids that won't be in the `routes` table so cells won't necessarily know
+ what cell has the data. As such we'll probably have to update our GraphQL
+ calls to include an organization context in the path like
+ `/api/organizations/<organization>/graphql`.
+1. This architecture implies that implemented endpoints can only access data
+ that are readily accessible on a given Cell, but are unlikely
+ to aggregate information from many Cells.
+1. All unknown routes are sent to the latest deployment which we assume to be `Cell US0`.
+ This is required as newly added endpoints will be only decodable by latest cell.
+ Likely this is not a problem for the `/cells/learn` is it is lightweight
+ to process and this should not cause a performance impact.
+
+## Example database configuration
+
+Handling shared `gitlab_users`, `gitlab_routes` and `gitlab_admin` databases, while having dedicated `gitlab_main` and `gitlab_ci` databases should already be handled by the way we use `config/database.yml`. We should also, already be able to handle the dedicated EU replicas while having a single US primary for `gitlab_users` and `gitlab_routes`. Below is a snippet of part of the database configuration for the Cell architecture described above.
+
+**Cell US0**:
+
+```yaml
+# config/database.yml
+production:
+ main:
+ host: postgres-main.cell-us0.primary.consul
+ load_balancing:
+ discovery: postgres-main.cell-us0.replicas.consul
+ ci:
+ host: postgres-ci.cell-us0.primary.consul
+ load_balancing:
+ discovery: postgres-ci.cell-us0.replicas.consul
+ users:
+ host: postgres-users-primary.consul
+ load_balancing:
+ discovery: postgres-users-replicas.us.consul
+ routes:
+ host: postgres-routes-primary.consul
+ load_balancing:
+ discovery: postgres-routes-replicas.us.consul
+ admin:
+ host: postgres-admin-primary.consul
+ load_balancing:
+ discovery: postgres-admin-replicas.us.consul
+```
+
+**Cell EU0**:
+
+```yaml
+# config/database.yml
+production:
+ main:
+ host: postgres-main.cell-eu0.primary.consul
+ load_balancing:
+ discovery: postgres-main.cell-eu0.replicas.consul
+ ci:
+ host: postgres-ci.cell-eu0.primary.consul
+ load_balancing:
+ discovery: postgres-ci.cell-eu0.replicas.consul
+ users:
+ host: postgres-users-primary.consul
+ load_balancing:
+ discovery: postgres-users-replicas.eu.consul
+ routes:
+ host: postgres-routes-primary.consul
+ load_balancing:
+ discovery: postgres-routes-replicas.eu.consul
+ admin:
+ host: postgres-admin-primary.consul
+ load_balancing:
+ discovery: postgres-admin-replicas.eu.consul
+```
+
+## Request flows
+
+1. `gitlab-org` is a top level namespace and lives in `Cell US0` in the `GitLab.com Public` organization
+1. `my-company` is a top level namespace and lives in `Cell EU0` in the `my-organization` organization
+
+### Experience for paying user that is part of `my-organization`
+
+Such a user will have a default organization set to `/my-organization` and will be
+unable to load any global routes outside of this organization. They may load other
+projects/namespaces but their MR/Todo/Issue counts at the top of the page will
+not be correctly populated in the first iteration. The user will be aware of
+this limitation.
+
+#### Navigates to `/my-company/my-project` while logged in
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. They request `/my-company/my-project` without the router cache, so the router chooses randomly `Cell EU1`
+1. The `/cells/learn` is sent to `Cell EU1`, which responds that resource lives on `Cell EU0`
+1. `Cell EU0` returns the correct response
+1. The router now caches and remembers any request paths matching `/my-company/*` should go to `Cell EU0`
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ participant cell_eu1 as Cell EU1
+ user->>router_eu: GET /my-company/my-project
+ router_eu->>cell_eu1: /api/v4/cells/learn?method=GET&path_info=/my-company/my-project
+ cell_eu1->>router_eu: {path: "/my-company", cell: "cell_eu0", source: "routable"}
+ router_eu->>cell_eu0: GET /my-company/my-project
+ cell_eu0->>user: <h1>My Project...
+```
+
+#### Navigates to `/my-company/my-project` while not logged in
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. The router does not have `/my-company/*` cached yet so it chooses randomly `Cell EU1`
+1. The `/cells/learn` is sent to `Cell EU1`, which responds that resource lives on `Cell EU0`
+1. `Cell EU0` redirects them through a login flow
+1. User requests `/users/sign_in`, uses random Cell to run `/cells/learn`
+1. The `Cell EU1` responds with `cell_0` as a fixed route
+1. User after login requests `/my-company/my-project` which is cached and stored in `Cell EU0`
+1. `Cell EU0` returns the correct response
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ participant cell_eu1 as Cell EU1
+ user->>router_eu: GET /my-company/my-project
+ router_eu->>cell_eu1: /api/v4/cells/learn?method=GET&path_info=/my-company/my-project
+ cell_eu1->>router_eu: {path: "/my-company", cell: "cell_eu0", source: "routable"}
+ router_eu->>cell_eu0: GET /my-company/my-project
+ cell_eu0->>user: 302 /users/sign_in?redirect=/my-company/my-project
+ user->>router_eu: GET /users/sign_in?redirect=/my-company/my-project
+ router_eu->>cell_eu1: /api/v4/cells/learn?method=GET&path_info=/users/sign_in
+ cell_eu1->>router_eu: {path: "/users", cell: "cell_eu0", source: "fixed"}
+ router_eu->>cell_eu0: GET /users/sign_in?redirect=/my-company/my-project
+ cell_eu0-->>user: <h1>Sign in...
+ user->>router_eu: POST /users/sign_in?redirect=/my-company/my-project
+ router_eu->>cell_eu0: POST /users/sign_in?redirect=/my-company/my-project
+ cell_eu0->>user: 302 /my-company/my-project
+ user->>router_eu: GET /my-company/my-project
+ router_eu->>cell_eu0: GET /my-company/my-project
+ router_eu->>cell_eu0: GET /my-company/my-project
+ cell_eu0->>user: <h1>My Project...
+```
+
+#### Navigates to `/my-company/my-other-project` after last step
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. The router cache now has `/my-company/* => Cell EU0`, so the router chooses `Cell EU0`
+1. `Cell EU0` returns the correct response as well as the cache header again
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ participant cell_eu1 as Cell EU1
+ user->>router_eu: GET /my-company/my-project
+ router_eu->>cell_eu0: GET /my-company/my-project
+ cell_eu0->>user: <h1>My Project...
+```
+
+#### Navigates to `/gitlab-org/gitlab` after last step
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. The router has no cached value for this URL so randomly chooses `Cell EU0`
+1. `Cell EU0` redirects the router to `Cell US0`
+1. `Cell US0` returns the correct response as well as the cache header again
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ participant cell_us0 as Cell US0
+ user->>router_eu: GET /gitlab-org/gitlab
+ router_eu->>cell_eu0: /api/v4/cells/learn?method=GET&path_info=/gitlab-org/gitlab
+ cell_eu0->>router_eu: {path: "/gitlab-org", cell: "cell_us0", source: "routable"}
+ router_eu->>cell_us0: GET /gitlab-org/gitlab
+ cell_us0->>user: <h1>GitLab.org...
+```
+
+In this case the user is not on their "default organization" so their TODO
+counter will not include their normal todos. We may choose to highlight this in
+the UI somewhere. A future iteration may be able to fetch that for them from
+their default organization.
+
+#### Navigates to `/`
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. Router does not have a cache for `/` route (specifically rails never tells it to cache this route)
+1. The Router choose `Cell EU0` randomly
+1. The Rails application knows the users default organization is `/my-organization`, so
+ it redirects the user to `/organizations/my-organization/-/dashboard`
+1. The Router has a cached value for `/organizations/my-organization/*` so it then sends the
+ request to `POD EU0`
+1. `Cell EU0` serves up a new page `/organizations/my-organization/-/dashboard` which is the same
+ dashboard view we have today but scoped to an organization clearly in the UI
+1. The user is (optionally) presented with a message saying that data on this page is only
+ from their default organization and that they can change their default
+ organization if it's not right.
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_eu0 as Cell EU0
+ user->>router_eu: GET /
+ router_eu->>cell_eu0: GET /
+ cell_eu0->>user: 302 /organizations/my-organization/-/dashboard
+ user->>router: GET /organizations/my-organization/-/dashboard
+ router->>cell_eu0: GET /organizations/my-organization/-/dashboard
+ cell_eu0->>user: <h1>My Company Dashboard... X-Gitlab-Cell-Cache={path_prefix:/organizations/my-organization/}
+```
+
+#### Navigates to `/dashboard`
+
+As above, they will end up on `/organizations/my-organization/-/dashboard` as
+the rails application will already redirect `/` to the dashboard page.
+
+### Navigates to `/not-my-company/not-my-project` while logged in (but they don't have access since this project/group is private)
+
+1. User is in Europe so DNS resolves to the router in Europe
+1. The router knows that `/not-my-company` lives in `Cell US1` so sends the request to this
+1. The user does not have access so `Cell US1` returns 404
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_eu as Router EU
+ participant cell_us1 as Cell US1
+ user->>router_eu: GET /not-my-company/not-my-project
+ router_eu->>cell_us1: GET /not-my-company/not-my-project
+ cell_us1->>user: 404
+```
+
+#### Creates a new top level namespace
+
+The user will be asked which organization they want the namespace to belong to.
+If they select `my-organization` then it will end up on the same cell as all
+other namespaces in `my-organization`. If they select nothing we default to
+`GitLab.com Public` and it is clear to the user that this is isolated from
+their existing organization such that they won't be able to see data from both
+on a single page.
+
+### Experience for GitLab team member that is part of `/gitlab-org`
+
+Such a user is considered a legacy user and has their default organization set to
+`GitLab.com Public`. This is a "meta" organization that does not really exist but
+the Rails application knows to interpret this organization to mean that they are
+allowed to use legacy global functionality like `/dashboard` to see data across
+namespaces located on `Cell US0`. The rails backend also knows that the default cell to render any ambiguous
+routes like `/dashboard` is `Cell US0`. Lastly the user will be allowed to
+navigate to organizations on another cell like `/my-organization` but when they do the
+user will see a message indicating that some data may be missing (eg. the
+MRs/Issues/Todos) counts.
+
+#### Navigates to `/gitlab-org/gitlab` while not logged in
+
+1. User is in the US so DNS resolves to the US router
+1. The router knows that `/gitlab-org` lives in `Cell US0` so sends the request
+ to this cell
+1. `Cell US0` serves up the response
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_us as Router US
+ participant cell_us0 as Cell US0
+ user->>router_us: GET /gitlab-org/gitlab
+ router_us->>cell_us0: GET /gitlab-org/gitlab
+ cell_us0->>user: <h1>GitLab.org...
+```
+
+#### Navigates to `/`
+
+1. User is in US so DNS resolves to the router in US
+1. Router does not have a cache for `/` route (specifically rails never tells it to cache this route)
+1. The Router chooses `Cell US1` randomly
+1. The Rails application knows the users default organization is `GitLab.com Public`, so
+ it redirects the user to `/dashboards` (only legacy users can see
+ `/dashboard` global view)
+1. Router does not have a cache for `/dashboard` route (specifically rails never tells it to cache this route)
+1. The Router chooses `Cell US1` randomly
+1. The Rails application knows the users default organization is `GitLab.com Public`, so
+ it allows the user to load `/dashboards` (only legacy users can see
+ `/dashboard` global view) and redirects to router the legacy cell which is `Cell US0`
+1. `Cell US0` serves up the global view dashboard page `/dashboard` which is the same
+ dashboard view we have today
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant router_us as Router US
+ participant cell_us0 as Cell US0
+ participant cell_us1 as Cell US1
+ user->>router_us: GET /
+ router_us->>cell_us1: GET /
+ cell_us1->>user: 302 /dashboard
+ user->>router_us: GET /dashboard
+ router_us->>cell_us1: /api/v4/cells/learn?method=GET&path_info=/dashboard
+ cell_us1->>router_us: {path: "/dashboard", cell: "cell_us0", source: "routable"}
+ router_us->>cell_us0: GET /dashboard
+ cell_us0->>user: <h1>Dashboard...
+```
+
+#### Navigates to `/my-company/my-other-project` while logged in (but they don't have access since this project is private)
+
+They get a 404.
+
+### Experience for non-authenticated users
+
+Flow is similar to logged in users except global routes like `/dashboard` will
+redirect to the login page as there is no default organization to choose from.
+
+### A new customers signs up
+
+They will be asked if they are already part of an organization or if they'd
+like to create one. If they choose neither they end up no the default
+`GitLab.com Public` organization.
+
+### An organization is moved from 1 cell to another
+
+TODO
+
+### GraphQL/API requests which don't include the namespace in the URL
+
+TODO
+
+### The autocomplete suggestion functionality in the search bar which remembers recent issues/MRs
+
+TODO
+
+### Global search
+
+TODO
+
+## Administrator
+
+### Loads `/admin` page
+
+1. The `/admin` is locked to `Cell US0`
+1. Some endpoints of `/admin`, like Projects in Admin are scoped to a Cell
+ and users needs to choose the correct one in a dropdown, which results in endpoint
+ like `/admin/cells/cell_0/projects`.
+
+Admin Area settings in Postgres are all shared across all cells to avoid
+divergence but we still make it clear in the URL and UI which cell is serving
+the Admin Area page as there is dynamic data being generated from these pages and
+the operator may want to view a specific cell.
+
+## More Technical Problems To Solve
+
+### Replicating User Sessions Between All Cells
+
+Today user sessions live in Redis but each cell will have their own Redis instance. We already use a dedicated Redis instance for sessions so we could consider sharing this with all cells like we do with `gitlab_users` PostgreSQL database. But an important consideration will be latency as we would still want to mostly fetch sessions from the same region.
+
+An alternative might be that user sessions get moved to a JWT payload that encodes all the session data but this has downsides. For example, it is difficult to expire a user session, when their password changes or for other reasons, if the session lives in a JWT controlled by the user.
+
+### How do we migrate between Cells
+
+Migrating data between cells will need to factor all data stores:
+
+1. PostgreSQL
+1. Redis Shared State
+1. Gitaly
+1. Elasticsearch
+
+### Is it still possible to leak the existence of private groups via a timing attack?
+
+If you have router in EU, and you know that EU router by default redirects
+to EU located Cells, you know their latency (lets assume 10 ms). Now, if your
+request is bounced back and redirected to US which has different latency
+(lets assume that roundtrip will be around 60 ms) you can deduce that 404 was
+returned by US Cell and know that your 404 is in fact 403.
+
+We may defer this until we actually implement a cell in a different region. Such timing attacks are already theoretically possible with the way we do permission checks today but the timing difference is probably too small to be able to detect.
+
+One technique to mitigate this risk might be to have the router add a random
+delay to any request that returns 404 from a cell.
+
+## Should runners be shared across all cells?
+
+We have 2 options and we should decide which is easier:
+
+1. Decompose runner registration and queuing tables and share them across all
+ cells. This may have implications for scalability, and we'd need to consider
+ if this would include group/project runners as this may have scalability
+ concerns as these are high traffic tables that would need to be shared.
+1. Runners are registered per-cell and, we probably have a separate fleet of
+ runners for every cell or just register the same runners to many cells which
+ may have implications for queueing
+
+## How do we guarantee unique ids across all cells for things that cannot conflict?
+
+This project assumes at least namespaces and projects have unique ids across
+all cells as many requests need to be routed based on their ID. Since those
+tables are across different databases then guaranteeing a unique ID will
+require a new solution. There are likely other tables where unique IDs are
+necessary and depending on how we resolve routing for GraphQL and other APIs
+and other design goals it may be determined that we want the primary key to be
+unique for all tables.
diff --git a/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md b/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md
index ebe3c72adfc..3e86d30df1d 100644
--- a/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md
+++ b/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md
@@ -1,7 +1,11 @@
---
-stage: none
-group: unassigned
comments: false
+status: ongoing
+creation-date: "2022-05-31"
+authors: [ "@grzesiek" ]
+coach: [ "@ayufan", "@grzesiek" ]
+approvers: [ "@jreporter", "@cheryl.li" ]
+owning-stage: "~devops::verify"
description: 'Pipeline data partitioning design'
---
@@ -803,9 +807,11 @@ DRIs:
| Role | Who |
|---------------------|------------------------------------------------|
| Author | Grzegorz Bizon, Principal Engineer |
-| Recommender | Kamil Trzciński, Senior Distingiushed Engineer |
-| Product Manager | James Heimbuck, Senior Product Manager |
-| Engineering Manager | Scott Hampton, Engineering Manager |
+| Recommender | Kamil Trzciński, Senior Distinguished Engineer |
+| Product Leadership | Jackie Porter, Director of Product Management |
+| Engineering Leadership | Caroline Simpson, Engineering Manager / Cheryl Li, Senior Engineering Manager |
| Lead Engineer | Marius Bobin, Senior Backend Engineer |
+| Senior Engineer | Maxime Orefice, Senior Backend Engineer |
+| Senior Engineer | Tianwen Chen, Senior Backend Engineer |
<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/ci_pipeline_components/dev_workflow.md b/doc/architecture/blueprints/ci_pipeline_components/dev_workflow.md
new file mode 100644
index 00000000000..266ea13c275
--- /dev/null
+++ b/doc/architecture/blueprints/ci_pipeline_components/dev_workflow.md
@@ -0,0 +1,155 @@
+---
+stage: verify
+group: pipeline authoring
+comments: false
+description: 'Development workflow for a components repository'
+---
+
+# Development workflow for a components repository
+
+## Summary
+
+This page describes the process of creating a components repository.
+It describes all the necessary steps, from the creation of the project to having new releases displayed in the
+catalog page.
+
+## 1. Create a new project
+
+First, create a new project and add a `README.md` file, which is a planned future
+requirement for a repository to become a catalog resource.
+
+## 2. Create a component inside the repository
+
+If you intend to have only one component in the repository, you can define it in the root directory.
+Otherwise, create a directory for the component.
+For more information, see the [directory structure of a components repository](index.md#structure-of-a-components-repository).
+
+This example defines a single component in the root directory.
+
+Create a `template.yml` file that contains the configuration we want to provide as a component:
+
+```yaml
+spec:
+ inputs:
+ stage:
+ default: test
+---
+.component-default-job:
+ image: busybox
+ stage: $[[ inputs.stage ]]
+
+component-job-1:
+ extends: .component-default-job
+ script: echo job 1
+
+component-job-2:
+ extends: .component-default-job
+ script: echo job 2
+```
+
+The example component configuration above adds two jobs, `component-job-1` and `component-job-2`, to a pipeline.
+
+## 3. Test changes in CI
+
+To test any changes pushed to our component, we create a `.gitlab-ci.yml` in the root directory:
+
+```yaml
+##
+# This configuration expects an access token with read-only access to the API
+# to be saved as in a masked CI/CD variable named 'API_TOKEN'
+
+include:
+ # Leverage predefined variables to refer to the current project and SHA
+ - component: gitlab.com/$CI_PROJECT_PATH@$CI_COMMIT_SHA
+
+stages: [test, release]
+
+# Expect all `component-job-*` jobs are added
+ensure-jobs-added:
+ 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" != "2" ]; then
+ exit 1
+ fi
+
+# Ensure that a project description exists, because it will be important to display
+# the resource in the catalog.
+check-description:
+ image: badouralix/curl-jq
+ script:
+ - |
+ route="https://gitlab.com/api/v4/projects/$CI_PROJECT_ID"
+ desc=`curl --silent --header "PRIVATE-TOKEN: $API_TOKEN" $route | jq '.description'`
+ if [ "$desc" = "null" ]; then
+ echo "Description not set. Please set a projet description"
+ exit 1
+ else
+ echo "Description set"
+ fi
+
+# Ensure that a `README.md` exists in the root directory as it represents the
+# documentation for the whole components repository.
+check-readme:
+ image: busybox
+ script: ls README.md || (echo "Please add a README.md file" && exit 1)
+
+# 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"
+```
+
+This pipeline contains examples of several tasks:
+
+- Use the component to ensure that the final configuration uses valid syntax.
+ This also ensures that the minimal requirements for the component to work are in place,
+ like inputs and secrets.
+- Test that the created pipeline has the expected characteristics.
+ For example, ensure the `component-job-*` jobs are added to the pipeline.
+ - We call the [pipeline API endpoint](../../../api/pipelines.md#get-a-single-pipeline) with `curl`
+ and parse the data via `jq`.
+ - With this technique users could check things like ensuring certain jobs were included,
+ the job has the right properties set, or the log contains the expected output.
+- Ensure that the project description is set.
+- Ensure that the repository contains a `README.md` file.
+- Create a [release automatically](../../../ci/yaml/index.md#release). When a tag is created and follows specific regex, create a release
+ after all previous checks pass.
+
+## 4. Run a pipeline
+
+Now run a new pipeline for the `main` branch, by pushing a change or manually running a pipeline:
+
+![Pipeline on main branch](img/pipeline_main.png)
+
+## 5. Create a tag
+
+As the pipeline for `main` is green, we can now [create our first tag](../../../user/project/repository/tags/index.md#create-a-tag): `v1.0`.
+
+As soon as the `v1.0` tag is created, we see a tag pipeline start.
+This time the pipeline also has a `create-release` job in the `release` stage:
+
+![Pipeline on tag](img/pipeline_tag.png)
+
+When the `create-release` job finishes we should see the new release available in the **Releases** menu:
+
+![New components repository release](img/new_release.png)
+
+## 6. Publish the repository to the catalog
+
+To ensure that both the components repository and the new release is visible in the CI Catalog,
+we need to publish it.
+
+Publishing a components repository makes it a catalog resource.
+
+The API endpoint for this action is under development.
+For more details read the [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/387065).
diff --git a/doc/architecture/blueprints/ci_pipeline_components/img/new_release.png b/doc/architecture/blueprints/ci_pipeline_components/img/new_release.png
new file mode 100644
index 00000000000..eed5c55d5e3
--- /dev/null
+++ b/doc/architecture/blueprints/ci_pipeline_components/img/new_release.png
Binary files differ
diff --git a/doc/architecture/blueprints/ci_pipeline_components/img/pipeline_main.png b/doc/architecture/blueprints/ci_pipeline_components/img/pipeline_main.png
new file mode 100644
index 00000000000..8b03b96ba7e
--- /dev/null
+++ b/doc/architecture/blueprints/ci_pipeline_components/img/pipeline_main.png
Binary files differ
diff --git a/doc/architecture/blueprints/ci_pipeline_components/img/pipeline_tag.png b/doc/architecture/blueprints/ci_pipeline_components/img/pipeline_tag.png
new file mode 100644
index 00000000000..d0814a479ae
--- /dev/null
+++ b/doc/architecture/blueprints/ci_pipeline_components/img/pipeline_tag.png
Binary files differ
diff --git a/doc/architecture/blueprints/ci_pipeline_components/index.md b/doc/architecture/blueprints/ci_pipeline_components/index.md
index b1aee7c4217..c1094bc4290 100644
--- a/doc/architecture/blueprints/ci_pipeline_components/index.md
+++ b/doc/architecture/blueprints/ci_pipeline_components/index.md
@@ -92,9 +92,12 @@ This section defines some terms that are used throughout this document. With the
identifying abstract concepts and are subject to changes as we refine the design by discovering new insights.
- **Component** Is the reusable unit of pipeline configuration.
-- **Project** Is the GitLab project attached to a repository. A project can contain multiple components.
-- **Catalog** is the collection of projects that are set to contain components.
-- **Version** is the release name of a tag in the project, which allows components to be pinned to a specific revision.
+- **Components repository** represents a collection of CI components stored in the same project.
+- **Project** is the GitLab project attached to a single components repository.
+- **Catalog** is a collection of resources like components repositories.
+- **Catalog resource** is the single item displayed in the catalog. A components repository is a catalog resource.
+- **Version** is a specific revision of catalog resource. It maps to the released tag in the project,
+ which allows components to be pinned to a specific revision.
## Definition of pipeline component
@@ -202,7 +205,6 @@ A component YAML file:
- Should be **validated statically** (for example: using JSON schema validators).
```yaml
----
spec:
inputs:
website:
@@ -217,18 +219,13 @@ spec:
# content of the component
```
-Components that are released in the catalog must have a `README.md` file at the root directory of the repository.
-The `README.md` represents the documentation for the specific component, hence it's recommended
-even when not releasing versions in the catalog.
-
### The component version
The version of the component can be (in order of highest priority first):
1. A commit SHA - For example: `gitlab.com/gitlab-org/dast@e3262fdd0914fa823210cdb79a8c421e2cef79d8`
-1. A released tag - For example: `gitlab.com/gitlab-org/dast@1.0`
+1. A tag - For example: `gitlab.com/gitlab-org/dast@1.0`
1. A special moving target version that points to the most recent released tag - For example: `gitlab.com/gitlab-org/dast@~latest`
-1. An unreleased tag - For example: `gitlab.com/gitlab-org/dast@rc-1.0`
1. A branch name - For example: `gitlab.com/gitlab-org/dast@master`
If a tag and branch exist with the same name, the tag takes precedence over the branch.
@@ -237,26 +234,31 @@ takes precedence over the tag.
As we want to be able to reference any revisions (even those not released), a component must be defined in a Git repository.
-NOTE:
When referencing a component by local path (for example `./path/to/component`), its version is implicit and matches
the commit SHA of the current pipeline context.
-## Components project
+## Components repository
+
+A components repository is a GitLab project/repository that exclusively hosts one or more pipeline components.
-A components project is a GitLab project/repository that exclusively hosts one or more pipeline components.
+A components repository can be a catalog resource. For a components repository it's highly recommended to set
+an appropriate avatar and project description to improve discoverability in the catalog.
-For components projects it's highly recommended to set an appropriate avatar and project description
-to improve discoverability in the catalog.
+Components repositories that are released in the catalog must have a `README.md` file at the root directory of the repository.
+The `README.md` represents the documentation of the components repository, hence it's recommended
+even when not listing the repository in the catalog.
-### Structure of a components project
+### Structure of a components repository
-A project can host one or more components depending on whether the author wants to define a single component
-per project or include multiple cohesive components under the same project.
+A components repository can host one or more components. The author can decide whether to define a single component
+per repository or include multiple cohesive components in the same repository.
-Let's imagine we are developing a component that runs RSpec tests for a Rails app. We create a component project
+A components repository is identified by the project full path.
+
+Let's imagine we are developing a component that runs RSpec tests for a Rails app. We create a project
called `myorg/rails-rspec`.
-The following directory structure would support 1 component per project:
+The following directory structure would support 1 component per repository:
```plaintext
.
@@ -267,10 +269,10 @@ The following directory structure would support 1 component per project:
The `.gitlab-ci.yml` is recommended for the project to ensure changes are verified accordingly.
-The component is now identified by the path `gitlab.com/myorg/rails-rspec` and we expect a `template.yml` file
-and `README.md` located in the root directory of the repository.
+The component is now identified by the path `gitlab.com/myorg/rails-rspec` which also maps to the
+project path. We expect a `template.yml` file and `README.md` to be located in the root directory of the repository.
-The following directory structure would support multiple components per project:
+The following directory structure would support multiple components per repository:
```plaintext
.
@@ -319,7 +321,6 @@ This limitation encourages cohesion at project level and keeps complexity low.
If the component takes any input parameters they must be specified according to the following schema:
```yaml
----
spec:
inputs:
website: # by default all declared inputs are mandatory.
@@ -363,7 +364,6 @@ Input parameters are validated as soon as possible:
1. Interpolate input parameters inside the component's content.
```yaml
----
spec:
inputs:
environment:
@@ -452,7 +452,6 @@ include:
Then the configuration being included must specify the inputs by defining a specification section in the YAML:
```yaml
----
spec:
inputs:
foo:
@@ -496,7 +495,6 @@ deploy-app:
To solve the problem of `Run Pipeline` UI form we could fully leverage the `inputs` specifications:
```yaml
----
spec:
inputs:
concurrency:
@@ -516,35 +514,114 @@ spec:
# rest of the pipeline config
```
-### Limits
+## CI Catalog
-Any MVC that exposes a feature should be added with limitations from the beginning.
-It's safer to add new features with restrictions than trying to limit a feature after it's being used.
-We can always soften the restrictions later depending on user demand.
+The CI Catalog is an index of resources that users can leverage in CI/CD. It initially
+contains a list of components repositories that users can discover and use in their pipelines.
-Some limits we could consider adding:
+In the future, the Catalog could contain also other types of resources (for example:
+integrations, project templates, etc.).
-- number of components that a single project can contain/export
-- number of imports that a `.gitlab-ci.yml` file can use
-- number of imports that a component can declare/use
-- max level of nested imports
-- max length of the exported component name
+To list a components repository in the Catalog we need to mark the project as being a
+catalog resource. We do that initially with an API endpoint, similar to changing a project setting.
+
+Once a project is marked as a "catalog resource" it can be displayed in the Catalog.
+
+We could create a database record when the API endpoint is used and remove the record when
+the same is disabled/removed.
+
+## Catalog resource
+
+Upon publishing, a catalog resource should have at least following attributes:
+
+- `path`: to be uniquely identified.
+- `name`: for components repository this could be the project name.
+- `documentation`: we would use the `README.md` file which would be mandatory.
+- `versions`: one or more releases of the resource.
+
+Other properties of a catalog resource:
+
+- `description`: for components repository this could be the project description.
+- `avatar image`: we could use the project avatar.
+- indicators of popularity (stars, forks).
+- categorization: user should select a category and or define search tags
+
+As soon as a components repository is marked as being a "catalog resource"
+we should be seeing the resource listed in the Catalog.
+
+Initially for the resource, the project may not have any released tags.
+Users would be able to use the components repository by specifying a branch name or
+commit SHA for the version. However, these types of version qualifiers should not
+be listed in the catalog resource's page for various reasons:
+
+- The list of branches and tags can get very large.
+- Branches and tags may not be meaningful for the end-user.
+- Branches and tags don't communicate versioning thoroughly.
+
+## Releasing new resource versions to the Catalog
-## Publishing components
+The versions that should be displayed for the resource should be the project [releases](../../../user/project/releases/index.md).
+Creating project releases is an official act of versioning a resource.
-Users will be able to publish CI Components into a CI Catalog. This can happen
-in a CI pipeline job, similarly to how software is being deployed following
-Continuous Delivery principles. This will allow us to guardrail the quality of
-components being deployed. To ensure that the CI Components meet quality
-standards users will be able to test them before publishing new versions in the
+A resource page would have:
+
+- The latest release in evidence (for example: the default version).
+- The ability to inspect and use past releases of the resource.
+- The documentation represented by the `README.md`.
+
+Users should be able to release new versions of the resource in a CI pipeline job,
+similar to how software is being deployed following Continuous Delivery principles.
+
+To ensure that the components repository and the including components
+meet quality standards, users can test them before releasing new versions in the
CI Catalog.
-Once a project containing components gets published we will index components'
+Some examples of checks we can run during the release of a new resource version:
+
+- Ensure the project contains a `README.md` in the root directory.
+- Ensure the project description exists.
+- If an index of available components is present for a components repository, ensure each
+ component has valid YAML.
+
+Once a new release for the project gets created we index the resource's
metadata. We want to initially index as much metadata as possible, to gain more
flexibility in how we design CI Catalog's main page. We don't want to be
-constrained by the lack of data available to properly visualize CI Components
-in CI Catalog. In order to do that, we may need to find all components that are
-being published, read their `spec` metadata and index what we find there.
+constrained by the lack of data available to properly visualize resources in
+the CI Catalog. To do that, we may need to find all resources that are
+being released and index their data and metadata.
+For example: index the content of `spec:` section for CI components.
+
+See an [example of development workflow](dev_workflow.md) for a components repository.
+
+## Note about future resource types
+
+In the future, to support multiple types of resources in the Catalog we could
+require a file `catalog-resource.yml` to be defined in the root directory of the project:
+
+```yaml
+name: DAST
+description: Scan a web endpoint to find vulnerabilities
+category: security
+tags: [dynamic analysis, security scanner]
+type: components_repository
+```
+
+This file could also be used for indexing metadata about the content of the resource.
+For example, users could list the components in the repository and we can index
+further data for search purpose:
+
+```yaml
+name: DAST
+description: Scan a web endpoint to find vulnerabilities
+category: security
+tags: [dynamic analysis, security scanner]
+type: components_repository
+metadata:
+ components:
+ - all-scans
+ - scan-x
+ - scan-y
+```
## Implementation guidelines
@@ -585,6 +662,20 @@ being published, read their `spec` metadata and index what we find there.
components from GitLab.com or from repository exports.
- Iterate on feedback.
+## Limits
+
+Any MVC that exposes a feature should be added with limitations from the beginning.
+It's safer to add new features with restrictions than trying to limit a feature after it's being used.
+We can always soften the restrictions later depending on user demand.
+
+Some limits we could consider adding:
+
+- number of components that a single project can contain/export
+- number of imports that a `.gitlab-ci.yml` file can use
+- number of imports that a component can declare/use
+- max level of nested imports
+- max length of the exported component name
+
## Who
Proposal:
diff --git a/doc/architecture/blueprints/clickhouse_usage/index.md b/doc/architecture/blueprints/clickhouse_usage/index.md
new file mode 100644
index 00000000000..2781ea15a55
--- /dev/null
+++ b/doc/architecture/blueprints/clickhouse_usage/index.md
@@ -0,0 +1,52 @@
+---
+status: proposed
+creation-date: "2023-02-02"
+authors: [ "@nhxnguyen" ]
+coach: "@grzesiek"
+approvers: [ "@dorrino", "@nhxnguyen" ]
+owning-stage: "~devops::data_stores"
+participating-stages: ["~section::ops", "~section::dev"]
+---
+
+# ClickHouse Usage at GitLab
+
+## Summary
+
+[ClickHouse](https://clickhouse.com/) is an open-source column-oriented database management system. It can efficiently filter, aggregate, and sum across large numbers of rows. In FY23, GitLab selected ClickHouse as its standard data store for features with big data and insert-heavy requirements such as Observability and Analytics. This blueprint is a product of the [ClickHouse working group](https://about.gitlab.com/company/team/structure/working-groups/clickhouse-datastore/). It serves as a high-level blueprint to ClickHouse adoption at GitLab and references other blueprints addressing specific ClickHouse-related technical challenges.
+
+## Motivation
+
+In FY23-Q2, the Monitor:Observability team developed and shipped a [ClickHouse data platform](https://gitlab.com/groups/gitlab-org/-/epics/7772) to store and query data for Error Tracking and other observability features. Other teams have also begun to incorporate ClickHouse into their current or planned architectures. Given the growing interest in ClickHouse across product development teams, it is important to have a cohesive strategy for developing features using ClickHouse. This will allow teams to more efficiently leverage ClickHouse and ensure that we can maintain and support this functionality effectively for SaaS and self-managed customers.
+
+### Goals
+
+As ClickHouse has already been selected for use at GitLab, our main goal now is to ensure successful adoption of ClickHouse across GitLab. It is helpful to break down this goal according to the different phases of the product development workflow.
+
+1. Plan: Make it easy for development teams to understand if ClickHouse is the right fit for their feature.
+1. Develop and Test: Give teams the best practices and frameworks to develop ClickHouse-backed features.
+1. Launch: Support ClickHouse-backed features for SaaS and self-managed.
+1. Improve: Successfully scale our usage of ClickHouse.
+
+### Non-Goals
+
+## Proposals
+
+The following are links to proposals in the form of blueprints that address technical challenges to using ClickHouse across a wide variety of features.
+
+1. Scalable data ingestion pipeline.
+ - How do we ingest large volumes of data from GitLab into ClickHouse either directly or by replicating existing data?
+1. Supporting ClickHouse for self-managed installations.
+ - For which use-cases and scales does it make sense to run ClickHouse for self-managed and what are the associated costs?
+ - How can we best support self-managed installation of ClickHouse for different types/sizes of environments?
+ - Consider using the [Opstrace ClickHouse operator](https://gitlab.com/gitlab-org/opstrace/opstrace/-/tree/main/clickhouse-operator) as the basis for a canonical distribution.
+ - Consider exposing Clickhouse backend as [GitLab Plus](https://gitlab.com/groups/gitlab-org/-/epics/308) to combine benefits of using self-managed instance and GitLab-managed database.
+ - Should we develop abstractions for querying and data ingestion to avoid requiring ClickHouse for small-scale installations?
+1. Abstraction layer for features to leverage both ClickHouse or PostreSQL.
+ - What are the benefits and tradeoffs? For example, how would this impact our automated migration and query testing?
+1. Security recommendations and secure defaults for ClickHouse usage.
+
+Note that we are still formulating proposals and will update the blueprint accordingly.
+
+## Best Practices
+
+Best practices and guidelines for developing performant and scalable features using ClickHouse are located in the [ClickHouse developer documentation](../../../development/database/clickhouse/index.md).
diff --git a/doc/architecture/blueprints/code_search_with_zoekt/index.md b/doc/architecture/blueprints/code_search_with_zoekt/index.md
new file mode 100644
index 00000000000..ca74460b98a
--- /dev/null
+++ b/doc/architecture/blueprints/code_search_with_zoekt/index.md
@@ -0,0 +1,305 @@
+---
+status: ongoing
+creation-date: "2022-12-28"
+authors: [ "@dgruzd", "@DylanGriffith" ]
+coach: "@DylanGriffith"
+approvers: [ "@joshlambert", "@changzhengliu" ]
+owning-stage: "~devops::enablement"
+participating-stages: []
+---
+
+# Use Zoekt For code search
+
+## Summary
+
+We will be implementing an additional code search functionality in GitLab that
+is backed by [Zoekt](https://github.com/sourcegraph/zoekt), an open source
+search engine that is specifically designed for code search. Zoekt will be used as
+an API by GitLab and remain an implementation detail while the user interface
+in GitLab will not change much except for some new features made available by
+Zoekt.
+
+This will be rolled out in phases to ensure that the system will actually meet
+our scaling and cost expectations and will run alongside code search backed by
+Elasticsearch until we can be sure it is a viable replacement. The first step
+will be making it available for `gitlab-org` for internal and expanding
+customer by customer based on customer interest.
+
+## Motivation
+
+GitLab code search functionality today is backed by Elasticsearch.
+Elasticsearch has proven useful for other types of search (issues, merge
+requests, comments and so-on) but is by design not a good choice for code
+search where users expect matches to be precise (ie. no false positives) and
+flexible (e.g. support
+[substring matching](https://gitlab.com/gitlab-org/gitlab/-/issues/325234)
+and
+[regexes](https://gitlab.com/gitlab-org/gitlab/-/issues/4175)). We have
+[investigated our options](https://gitlab.com/groups/gitlab-org/-/epics/7404)
+and [Zoekt](https://github.com/sourcegraph/zoekt) is pretty much the only well
+maintained open source technology that is suited to code search. Based on our
+research we believe it will be better to adopt a well maintained open source
+database than attempt to build our own. This is mostly due to the fact that our
+research indicates that the fundamental architecture of Zoekt is what we would
+implement again if we tried to implement something ourselves.
+
+Our
+[early benchmarking](https://gitlab.com/gitlab-org/gitlab/-/issues/370832#note_1183611955)
+suggests that Zoekt will be viable at our scale, but we feel strongly
+that investing in building a beta integration with Zoekt and rolling it out
+group by group on GitLab.com will provide better insights into scalability and
+cost than more accurate benchmarking efforts. It will also be relatively low
+risk as it will be rolled out internally first and later rolled out to
+customers that wish to participate in the trial.
+
+### Goals
+
+The main goals of this integration will be to implement the following highly
+requested improvements to code search:
+
+1. [Exact match (substring match) code searches in advanced search](https://gitlab.com/gitlab-org/gitlab/-/issues/325234)
+1. [Support regular expressions with Advanced Global Search](https://gitlab.com/gitlab-org/gitlab/-/issues/4175)
+1. [Support multiple line matches in the same file](https://gitlab.com/gitlab-org/gitlab/-/issues/668)
+
+The initial phases of the rollout will be designed to catch and resolve scaling
+or infrastructure cost issues as early as possible so that we can pivot early
+before investing too much in this technology if it is not suitable.
+
+### Non-Goals
+
+The following are not goals initially but could theoretically be built upon
+this solution:
+
+1. Improving security scanning features by having access to quickly perform
+ regex scans across many repositories
+1. Saving money on our search infrastructure - this may be possible with
+ further optimizations, but initial estimates suggest the cost is similar
+1. AI/ML features of search used to predict what users might be interested in
+ finding
+1. Code Intelligence and Navigation - likely code intelligence and navigation
+ features should be built on structured data rather than a trigram index but
+ regex based searches (using Zoekt) may be a suitable fallback for code which
+ does not have structured metadata enabled or dynamic languages where static
+ analysis is not very accurate. Zoekt in particular may not be well suited
+ initially, despite existing symbol extraction using ctags, because ctags
+ symbols may not contain enough data for accurate navigation and Zoekt
+ doesn't undersand dependencies which would be necessary for cross-project
+ navigation.
+
+## Proposal
+
+An
+[initial implementation of a Zoekt integration](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105049)
+was created to demonstrate the feasibility of using Zoekt as a drop-in
+replacement for Elasticsearch code searches. This blueprint will extend on all
+the details needed to provide a minimum viable change as well steps needed to
+scale this to a larger customer rollout on GitLab.com.
+
+## Design and implementation details
+
+### User Experience
+
+When a user performs an advanced search on a group or project that is part
+of the Zoekt rollout we will present a toggle somewhere in the UI to change
+to "precise search" (or some other UX TBD) which switches them from
+Elasticsearch to Zoekt. Early user feedback will help us assess the best way
+to present these choices to users and ultimately we will want to remove the
+Elasticsearch option if we find Zoekt is a suitable long term option.
+
+### Indexing
+
+Similar to our Elasticsearch integration, GitLab will notify Zoekt every time
+there are updates to a repository. Zoekt, unlike Elasticsearch, is designed to
+clone and index Git repositories so we will simply notify Zoekt of the URL of
+the repository that has changed and it will update its local copy of the Git
+repo and then update its local index files. The Zoekt side of this logic will
+be implemented in a new server-side indexing endpoint we add to Zoekt which is
+currently in
+[an open Pull request](https://github.com/sourcegraph/zoekt/pull/496).
+While the details of
+this pull request are still being debated, we may choose to deploy a fork with
+the functionality we need, but our strongest intention is not to maintain a
+fork of Zoekt and the maintainers have already expressed they are open to this
+new functionality.
+
+The rails side of the integration will be a Sidekiq worker that is scheduled
+every time there is an update to a repository and it will simply call this
+`/index` endpoint in Zoekt. This will also need to generate a one-time token
+that can allow Zoekt to clone a private repository.
+
+```mermaid
+sequenceDiagram
+ participant user as User
+ participant gitlab_git as GitLab Git
+ participant gitlab_sidekiq as GitLab Sidekiq
+ participant zoekt as Zoekt
+ user->>gitlab_git: git push git@gitlab.com:gitlab-org/gitlab.git
+ gitlab_git->>gitlab_sidekiq: ZoektIndexerWorker.perform_async(278964)
+ gitlab_sidekiq->>zoekt: POST /index {"RepoUrl":"https://zoekt:SECRET_TOKEN@gitlab.com/gitlab-org/gitlab.git","RepoId":278964}'
+ zoekt->>gitlab_git: git clone https://zoekt:SECRET_TOKEN@gitlab.com/gitlab-org/gitlab.git
+```
+
+The Sidekiq worker can leverage de-duplication based on the `project_id`.
+
+Zoekt supports indexing multiple projects we'll likely need to, eventually,
+allow a way for users to configure additional branches (beyond the default
+branch) and this will need to be sent to Zoekt. We will need to decide if these
+branch lists are sent every time we index the project or only when they change
+configuration.
+
+There may be race conditions with multiple Zoekt processes indexing the same
+repo at the same time. For this reason we should implement a locking mechanism
+somewhere to ensure we are only indexing 1 project in 1 place at a time. We
+could make use of the same Redis locking we use for indexing projects in
+Elasticsearch.
+
+### Searching
+
+Searching will be implemented using the `/api/search` functionality in
+Zoekt. There is also
+[an open PR to fix this endpoint in Zoekt](https://github.com/sourcegraph/zoekt/pull/506),
+and again we may consider working from a fork until this is fixed. GitLab will
+prepend all searches with the appropriate filter for repositories based on the
+user's search context (group or project) in the same way we do for
+Elasticsearch. For Zoekt this will be implemented as a query string regex that
+matches all the searched repositories.
+
+### Zoekt infrastructure
+
+Each Zoekt node will need to run a
+[zoekt-dynamic-indexserver](https://github.com/sourcegraph/zoekt/pull/496) and
+a
+[zoekt-webserver](https://github.com/sourcegraph/zoekt/blob/main/cmd/zoekt-webserver/main.go).
+These are both webservers with different responsibilities. Considering that the
+Zoekt indexing process needs to keep a full clone of the bare repo
+([unless we come up with a better option](https://gitlab.com/gitlab-org/gitlab/-/issues/384722))
+these bare repos will be stored on spinning disks to save space. These are only
+used as an intermediate step to generate the actual `.zoekt` index files which
+will be stored on an SSD for fast searches. These web servers need to run on
+the same node as they access the same files. The `zoekt-dynamic-indexserver` is
+responsible for writing the `.zoekt` index files. The `zoekt-webserver` is
+responsible for responding to searches that it performs by reading these
+`.zoekt` index files.
+
+### Rollout strategy
+
+Initially Zoekt code search will only be available to `gitlab-org`. After that
+we'll start rolling it out to specific customers that have requested better
+code search experience. As we learn about scaling and make improvements we will
+gradually roll it out to all licensed groups on GitLab.com. We will use a
+similar approach to Elasticsearch for keeping track of which groups are indexed
+and which are not. This will be based on a new table `zoekt_indexed_namespaces`
+with a `namespace_id` reference. We will only allow rolling out to top level
+namespaces to simplify the logic of checking for all layers of group
+inheritance. Once we've rolled out to all licensed groups we'll enable logic to
+automatically enroll newly licensed groups. This table also may be a place to
+store per-namespace sharding and replication data as described below.
+
+### Sharding and replication strategy
+
+Zoekt does not have any inbuilt sharding, and we expect that we'll need
+multiple Zoekt servers to reach the scale to provide search functionality to
+all of GitLab licensed customers.
+
+There are 2 clear ways to implement sharding:
+
+1. Build it on top of, or in front of Zoekt, as an independent component. Building
+ all the complexities of a distributed database into Zoekt is not likely to
+ be a good direction for the project so most likely this would be an
+ independent piece of infrastructure that proxied requests to the correct
+ shard.
+1. Manage the shards inside GitLab. This would be an application layer in
+ GitLab which chooses the correct shard to send indexing and search requests
+ to.
+
+Likewise, there are a few ways to implement replication:
+
+1. Server-side where Zoekt replicas are aware of other Zoekt replicas and they
+ stream updates from some primary to remain in sync
+1. Client-side replication where clients send indexing requests to all replicas
+ and search requests to any replica
+
+We plan to implement sharding inside GitLab application but replication may be
+best served at the level of the filesystem of Zoekt servers rather than sending
+duplicated updates from GitLab to all replicas. This could be some process on
+Zoekt servers that monitors for changes to the `.zoekt` files in a specific
+directory and syncs those updates to the replicas. This will need to be
+slightly more sophisticated than `rsync` because the files are constantly
+changing and files may be getting deleted while the sync is happening so we
+would want to be syncing the updates in batches somehow without slowing down
+indexing.
+
+Implementing sharding in GitLab simplifies the additional infrastructure
+components that need to be deployed and allows more flexibility to control our
+rollout to many customers alongside our rollout of multiple shards.
+
+Implementing syncing from primary -> replica on Zoekt nodes at the filesystem
+level optimizes that overall resource usage. We only need to sync the index
+files to replicas as the bare repo is just a cache. This saves on:
+
+1. Disk space on replicas
+1. CPU usage on replicas as it does not need to rebuild the index
+1. Load on Gitaly to clone the repos
+
+We plan to defer the implementation of these high availability aspects until
+later, but a preliminary plan would be:
+
+1. GitLab is configured with a pool of Zoekt servers
+1. GitLab assigns groups randomly a Zoekt primary server
+1. There will also be Zoekt replica servers
+1. Periodically Zoekt primary servers will sync their `.zoekt` index files to
+ their respective replicas
+1. There will need to be some process by which to promote a replica to a
+ primary if the primary is having issues. We will be using Consul for
+ keeping track of which is the primary and which are the replicas.
+1. When indexing a project GitLab will queue a Sidekiq job to update the index
+ on the primary
+1. When searching we will randomly select one of the Zoekt primaries or replica
+ servers for the group being searched. We don't care which is "more up to
+ date" as code search will be "eventually consistent" and all reads may read
+ slightly out of date indexes. We will have a target of maximum latency of
+ index updates and may consider removing nodes from rotation if they are too
+ far out of date.
+1. We will shard everything by top level group as this ensures group search can
+ always search a single Zoekt server. Aggregation may be possible for global
+ searches at some point in future if this turns out to be important. Smaller
+ self-managed instances may use a single Zoekt server allowing global
+ searches to work without any aggregation being implemented. Depending on our
+ largest group sizes and scaling limitations of a single node Zoekt server we
+ may consider implementing an approach where a group can be assigned multiple
+ shards.
+
+The downside of the chosen path will be added complexity of managing all these
+Zoekt servers from GitLab when compared with a "proxy" layer outside of GitLab
+that is managing all of these shards. We will consider this decision a work in
+progress and reassess if it turns out to add too much complexity to GitLab.
+
+#### Sharding proposal using GitLab `::Zoekt::Shard` model
+
+This is already implemented as the `::Zoekt::IndexedNamespace`
+implements a many-to-many relationship between namespaces and shards.
+
+#### Replication and service discovery using Consul
+
+If we plan to replicate at the Zoekt node level as described above we need to
+change our data model to use a one-to-many relationship from `zoekt_shards ->
+namespaces`. This means making the `namespace_id` column unique in
+`zoekt_indexed_namespaces`. Then we need to implement a service discovery
+approach where the `index_url` always points at a primary Zoekt node and the
+`search_url` is a DNS record with N replicas and the primary. We then choose
+randomly from `search_url` records when searching.
+
+### Iterations
+
+1. Make available for `gitlab-org`
+1. Improve monitoring
+1. Improve performance
+1. Make available for select customers
+1. Implement sharding
+1. Implement replication
+1. Make available to many more licensed groups
+1. Implement automatic (re)balancing of shards
+1. Estimate costs for rolling out to all licensed groups and decide if it's worth it or if we need to optimize further or adjust our plan
+1. Rollout to all licensed groups
+1. Improve performance
+1. Assess costs and decide whether we should roll out to all free customers
diff --git a/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md b/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md
index 7fecbd1de71..12254fa7920 100644
--- a/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md
+++ b/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md
@@ -340,7 +340,7 @@ What was done?
spec.add_dependency 'graphql-docs'
spec.add_dependency 'grape'
end
- ```
+ ```
1. Move routes to the `engines/web_engine/config/routes.rb` file
@@ -380,59 +380,59 @@ What was done?
1. Configure GitLab when to load the engine.
- In GitLab `config/engines.rb`, we can configure when do we want to load our engines by relying on our `Gitlab::Runtime`
+ In GitLab `config/engines.rb`, we can configure when do we want to load our engines by relying on our `Gitlab::Runtime`
- ```ruby
- # config/engines.rb
- # Load only in case we are running web_server or rails console
- if Gitlab::Runtime.puma? || Gitlab::Runtime.console?
- require 'web_engine'
- end
- ```
+ ```ruby
+ # config/engines.rb
+ # Load only in case we are running web_server or rails console
+ if Gitlab::Runtime.puma? || Gitlab::Runtime.console?
+ require 'web_engine'
+ end
+ ```
1. Configure Engine
- Our Engine inherits from the `Rails::Engine` class. This way this gem notifies Rails that
- there's an engine at the specified path so it will correctly mount the engine inside
- the application, performing tasks such as adding the app directory of the engine to
- the load path for models, mailers, controllers, and views.
- A file at `lib/web_engine/engine.rb`, is identical in function to a standard Rails
- application's `config/application.rb` file. This way engines can access a configuration
- object which contains configuration shared by all railties and the application.
- Additionally, each engine can access `autoload_paths`, `eager_load_paths`, and `autoload_once_paths`
- settings which are scoped to that engine.
-
- ```ruby
- module WebEngine
- class Engine < ::Rails::Engine
- config.eager_load_paths.push(*%W[#{config.root}/lib
- #{config.root}/app/graphql/resolvers/concerns
- #{config.root}/app/graphql/mutations/concerns
- #{config.root}/app/graphql/types/concerns])
-
- if Gitlab.ee?
- ee_paths = config.eager_load_paths.each_with_object([]) do |path, memo|
- ee_path = config.root
- .join('ee', Pathname.new(path).relative_path_from(config.root))
- memo << ee_path.to_s
- end
- # Eager load should load CE first
- config.eager_load_paths.push(*ee_paths)
- end
- end
- end
- ```
+ Our Engine inherits from the `Rails::Engine` class. This way this gem notifies Rails that
+ there's an engine at the specified path so it will correctly mount the engine inside
+ the application, performing tasks such as adding the app directory of the engine to
+ the load path for models, mailers, controllers, and views.
+ A file at `lib/web_engine/engine.rb`, is identical in function to a standard Rails
+ application's `config/application.rb` file. This way engines can access a configuration
+ object which contains configuration shared by all railties and the application.
+ Additionally, each engine can access `autoload_paths`, `eager_load_paths`, and `autoload_once_paths`
+ settings which are scoped to that engine.
+
+ ```ruby
+ module WebEngine
+ class Engine < ::Rails::Engine
+ config.eager_load_paths.push(*%W[#{config.root}/lib
+ #{config.root}/app/graphql/resolvers/concerns
+ #{config.root}/app/graphql/mutations/concerns
+ #{config.root}/app/graphql/types/concerns])
+
+ if Gitlab.ee?
+ ee_paths = config.eager_load_paths.each_with_object([]) do |path, memo|
+ ee_path = config.root
+ .join('ee', Pathname.new(path).relative_path_from(config.root))
+ memo << ee_path.to_s
+ end
+ # Eager load should load CE first
+ config.eager_load_paths.push(*ee_paths)
+ end
+ end
+ end
+ ```
1. Testing
- We adapted CI to test `engines/web_engine/` as a self-sufficient component of stack.
+ We adapted CI to test `engines/web_engine/` as a self-sufficient component of stack.
- - We moved `spec` as-is files to the `engines/web_engine/spec` folder
- - We moved `ee/spec` as-is files to the `engines/web_engine/ee/spec` folder
- - We control specs from main application using environment variable `TEST_WEB_ENGINE`
- - We added new CI job that will run `engines/web_engine/spec` tests separately using `TEST_WEB_ENGINE` environment variable.
- - We added new CI job that will run `engines/web_engine/ee/spec` tests separately using `TEST_WEB_ENGINE` environment variable.
- - We are running all white box frontend tests with `TEST_WEB_ENGINE=true`
+ - We moved `spec` as-is files to the `engines/web_engine/spec` folder
+ - We moved `ee/spec` as-is files to the `engines/web_engine/ee/spec` folder
+ - We control specs from main application using environment variable `TEST_WEB_ENGINE`
+ - We added new CI job that will run `engines/web_engine/spec` tests separately using `TEST_WEB_ENGINE` environment variable.
+ - We added new CI job that will run `engines/web_engine/ee/spec` tests separately using `TEST_WEB_ENGINE` environment variable.
+ - We are running all white box frontend tests with `TEST_WEB_ENGINE=true`
#### Results
diff --git a/doc/architecture/blueprints/consolidating_groups_and_projects/index.md b/doc/architecture/blueprints/consolidating_groups_and_projects/index.md
index 97853075607..88034f60caf 100644
--- a/doc/architecture/blueprints/consolidating_groups_and_projects/index.md
+++ b/doc/architecture/blueprints/consolidating_groups_and_projects/index.md
@@ -4,7 +4,8 @@ creation-date: "2021-02-07"
authors: [ "@alexpooley", "@ifarkas" ]
coach: "@grzesiek"
approvers: [ "@m_gill", "@mushakov" ]
-owning-stage: "~devops::plan"
+author-stage: "~devops::plan"
+owning-stage: "~devops::data_stores"
participating-stages: []
---
@@ -147,4 +148,4 @@ The initial iteration will provide a framework to house features under `Namespac
## Related topics
-- [Workspace developer documentation](../../../development/workspace/index.md)
+- [Organization developer documentation](../../../development/organization/index.md)
diff --git a/doc/architecture/blueprints/gitlab_agent_deployments/index.md b/doc/architecture/blueprints/gitlab_agent_deployments/index.md
index 96e361d7531..0e5b5f0b248 100644
--- a/doc/architecture/blueprints/gitlab_agent_deployments/index.md
+++ b/doc/architecture/blueprints/gitlab_agent_deployments/index.md
@@ -374,6 +374,8 @@ Here is an example of GraphQL query:
lastDeployment(status: SUCCESS) {
agent {
id
+ name
+ project
kubernetesNamespace
}
}
diff --git a/doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md b/doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md
index c5bd2440b0c..82d1596bc90 100644
--- a/doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md
+++ b/doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md
@@ -93,9 +93,9 @@ Additionally, since we intend to ingest data via Prometheus `remote_write` API,
We also need to make sure to avoid writing a lot of small writes into Clickhouse, therefore it’d be prudent to batch data before writing it into Clickhouse.
-We must also make sure ingestion remains decoupled with `Storage` so as to reduce undue dependence on a given storage implementation. While we do intend to use Clickhouse as our backing storage for any foreseeable future, this ensures we do not tie ourselves in into Clickhouse too much should future business requirements warrant the usage of a different backend/technology. A good way to implement this in Golang would be our implementations adhering to a standard interface, the following for example:
+We must also make sure ingestion remains decoupled with `Storage` so as to reduce undue dependence on a given storage implementation. While we do intend to use Clickhouse as our backing storage for any foreseeable future, this ensures we do not tie ourselves in into Clickhouse too much should future business requirements warrant the usage of a different backend/technology. A good way to implement this in Go would be our implementations adhering to a standard interface, the following for example:
-```golang
+```go
type Storage interface {
Read(
ctx context.Context,
diff --git a/doc/architecture/blueprints/object_storage/index.md b/doc/architecture/blueprints/object_storage/index.md
index 4a8eeaf86a9..6718705a7c8 100644
--- a/doc/architecture/blueprints/object_storage/index.md
+++ b/doc/architecture/blueprints/object_storage/index.md
@@ -53,7 +53,7 @@ This has led to increased complexity across the board, from development
[we no longer recommend](../../../administration/nfs.md) to our
users and is no longer in use on GitLab.com.
- Understanding all the moving parts and the flow is extremely
- complicated: we have CarrierWave, Fog, Golang S3/Azure SDKs, all
+ complicated: we have CarrierWave, Fog, Go S3/Azure SDKs, all
being used, and that complicates testing as well.
- Fog and CarrierWave are not maintained to the level of the native
SDKs (for example, AWS S3 SDK), so we have to maintain or monkey
diff --git a/doc/architecture/blueprints/pods/images/term-cluster.png b/doc/architecture/blueprints/pods/images/term-cluster.png
deleted file mode 100644
index 87e4d631551..00000000000
--- a/doc/architecture/blueprints/pods/images/term-cluster.png
+++ /dev/null
Binary files differ
diff --git a/doc/architecture/blueprints/pods/images/term-organization.png b/doc/architecture/blueprints/pods/images/term-organization.png
deleted file mode 100644
index 4c82c62b8f4..00000000000
--- a/doc/architecture/blueprints/pods/images/term-organization.png
+++ /dev/null
Binary files differ
diff --git a/doc/architecture/blueprints/pods/images/term-pod.png b/doc/architecture/blueprints/pods/images/term-pod.png
deleted file mode 100644
index d8f79df2f29..00000000000
--- a/doc/architecture/blueprints/pods/images/term-pod.png
+++ /dev/null
Binary files differ
diff --git a/doc/architecture/blueprints/pods/index.md b/doc/architecture/blueprints/pods/index.md
index 077303be30f..5c15f880a54 100644
--- a/doc/architecture/blueprints/pods/index.md
+++ b/doc/architecture/blueprints/pods/index.md
@@ -1,356 +1,11 @@
---
-status: accepted
-creation-date: "2022-09-07"
-authors: [ "@ayufan", "@fzimmer", "@DylanGriffith" ]
-coach: "@ayufan"
-approvers: [ "@fzimmer" ]
-owning-stage: "~devops::enablement"
-participating-stages: []
+redirect_to: '../cells/index.md'
+remove_date: '2023-06-13'
---
-# Pods
+This document was moved to [another location](../cells/index.md).
-This document is a work-in-progress and represents a very early state of the Pods design. Significant aspects are not documented, though we expect to add them in the future.
-
-## Summary
-
-Pods is a new architecture for our Software as a Service platform that is horizontally-scalable, resilient, and provides a more consistent user experience. It may also provide additional features in the future, such as data residency control (regions) and federated features.
-
-## Terminology
-
-We use the following terms to describe components and properties of the Pods architecture.
-
-### Pod
-
-A Pod is a set of infrastructure components that contains multiple top-level namespaces that belong to different organizations. The components include both datastores (PostgreSQL, Redis etc.) and stateless services (web etc.). The infrastructure components provided within a Pod are shared among organizations and their top-level namespaces but not shared with other Pods. This isolation of infrastructure components means that Pods are independent from each other.
-
-![Term Pod](images/term-pod.png)
-
-#### Pod properties
-
-- Each pod is independent from the others
-- Infrastructure components are shared by organizations and their top-level namespaces within a Pod
-- More Pods can be provisioned to provide horizontal scalability
-- A failing Pod does not lead to failure of other Pods
-- Noisy neighbor effects are limited to within a Pod
-- Pods are not visible to organizations; it is an implementation detail
-- Pods 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 Pods.
-
-![Term Cluster](images/term-cluster.png)
-
-#### 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 Pods, 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 pod.
-
-![Term Organization](images/term-organization.png)
-
-#### Organization properties
-
-- Top-level namespaces belong to organizations
-- Users can be members of different organizations
-- Organizations are isolated from each other by default meaning that cross-namespace features will only work for namespaces that exist within a single organization
-- User namespaces must not belong to an organization
-
-Discouraged synonyms: Billable entities, customers
-
-### Top-Level namespace
-
-A top-level namespace is the logical object container in the code that represents all groups, subgroups and projects that belong to an organization.
-
-A top-level namespace is the root of nested collection namespaces and projects. The namespace and its related entities form a tree-like hierarchy: Namespaces are the nodes of the tree, projects are the leaves.
-
-Example:
-
-`https://gitlab.com/gitlab-org/gitlab/`:
-
-- `gitlab-org` is a `top-level namespace`; the root for all groups and projects of an organization
-- `gitlab` is a `project`; a project of the organization.
-
-Top-level namespaces may [be replaced by workspaces](https://gitlab.com/gitlab-org/gitlab/-/issues/368237#high-level-goals). This proposal only uses the term top-level namespaces as the workspace definition is ongoing.
-
-Discouraged synonyms: Root-level namespace
-
-![Term Top-level Namespace](images/term-top-level-namespace.png)
-
-#### Top-level namespace properties
-
-- Top-level namespaces belonging to an organization are located on the same Pod
-- Top-level namespaces can interact with other top-level namespaces that belong to the same organization
-
-### Users
-
-Users are available globally and not restricted to a single Pod. Users can be members of many different organizations with varying permissions. Inside organizations, users can create multiple top-level namespaces. 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 pods.
-
-#### User properties
-
-- Users are shared globally across all Pods
-- Users can create multiple top-level namespaces
-- Users can be a member of multiple top-level namespaces
-- Users can be a member of multiple organizations
-- Users can administer organizations
-- User activity is aggregated in an organization
-- Every user has one personal namespace
-
-## 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 (internal) that the current architecture has scalability limitations, even when database partitioning and decomposition are taken into account.
-
-Pods provide a horizontally scalable solution because additional Pods can be created based on demand. Pods can be provisioned and tuned as needed for optimal scalability.
-
-### Increased availability
-
-A major challenge for shared-infrastructure architectures is a lack of isolation between top-level namespaces. This can lead to noisy neighbor effects. A organization's behavior inside a top-level namespace can impact all other organizations. This is highly undesirable. Pods provide isolation at the pod level. A group of organizations is fully isolated from other organizations located on a different Pod. This minimizes noisy neighbor effects while still benefiting from the cost-efficiency of shared infrastructure.
-
-Additionally, Pods provide a way to implement disaster recovery capabilities. Entire Pods may be replicated to read-only standbys with automatic failover capabilities.
-
-### 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. Pods provide a path towards [GitLab Regions](https://gitlab.com/groups/gitlab-org/-/epics/6037) because Pods may be deployed within different geographies. Depending on which of the organization's data is located outside a Pod, this may solve data residency and compliance problems.
-
-## Market segment
-
-Pods 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).
-
-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:
-
-1. How will existing `gitlab-org` contributors contribute to the namespace??
-1. How do we move existing top-level namespaces 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.
-
-### Self-managed
-
-For reasons of consistency, it is expected that self-managed instances will
-adopt the pods architecture as well. To expand, self-managed instances can
-continue with just a single Pod while supporting the option of adding additional
-Pods. Organizations, and possible User decomposition will also be adopted for
-self-managed instances.
-
-## High-level architecture problems to solve
-
-A number of technical issues need to be resolved to implement Pods (in no particular order). This section will be expanded.
-
-1. How are users of an organization routed to the correct Pod?
-1. How do users authenticate?
-1. How are Pods rebalanced?
-1. How are Pods provisioned?
-1. How can Pods implement disaster recovery capabilities?
-
-## Cross-section impact
-
-Pods 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 Pods 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 Pods 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. Pods 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 Workspace and influence their decision on [how to approach introducing a workspace](https://gitlab.com/gitlab-org/gitlab/-/issues/376285#approach-2-workspace-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 Manage Workspace
-
-We synced with the Workspace PM and Designer ([recording](https://youtu.be/b5Opn9cFWFk)) and discussed the similarities and differences between the Pods and Workspace proposal ([presentation](https://docs.google.com/presentation/d/1FsUi22Up15b_tu6p2m-yLML3hCZ3rgrZrmzJAxUsNmU/edit?usp=sharing)).
-
-#### Goals of Group Manage Workspace
-
-As defined in the [workspace documentation](../../../user/workspace/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 [workspace roadmap outlines](https://gitlab.com/gitlab-org/gitlab/-/issues/368237#high-level-goals) the current goals in detail.
-
-#### Potential conflicts with Pods
-
-- Workspace and Organization are different terms for the same entity. Both define a new entity as the primary organizational object for groups and projects. This is mainly a semantic difference and **we need to decide on a name** following [user research to decide if workspace](https://gitlab.com/gitlab-org/ux-research/-/issues/2147). This is also driven by the fact that the Remote Development team is looking at better names and [are considering the term Workspace as well](https://gitlab.com/gitlab-com/Product/-/issues/4812).
-- We will only introduce one entity
-- Group workspace 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 Pods would impact them. Fulfillment is supportive of an entity above top-level namespaces. 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 namespace to a level above. This would mean that a license applies for an organization and all its top-level namespaces.
-- 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:
-
-![Pods and Fulfillment](images/pods-and-fulfillment.png)
-
-#### Potential conflicts with Pods
-
-- There are no known conflicts between Fulfillment's plans and Pods
-
-## Iteration plan
-
-We can't ship the entire Pods architecture in one go - it is too large. Instead, we are adopting an iteration plan that provides value along the way.
-
-1. Introduce organizations
-1. Migrate existing top-level namespaces to organizations
-1. Create new organizations on `pod_0`
-1. Migrate existing organizations from `pod_0` to `pod_n`
-1. Add additional Pod capabilities (DR, Regions)
-
-### Iteration 0: Introduce organizations
-
-In the first iteration, we introduce the concept of an organization
-as a way to group top-level namespaces together. Support for organizations **does not require any Pods work** but having them will make all subsequent iterations of Pods simpler. This is mainly because we can group top-level namespaces for a single organization onto a Pod. Within an organization all interactions work as normal but we eliminate any cross-organizational interactions except in well defined cases (e.g. forking).
-
-This means that we don't have a large number of cross-pod interactions.
-
-Introducing organizations allows GitLab to move towards a multi-tenant system that is similar to Discord's with a single user account but many different "servers" - our organizations - that allow users to switch context. This model harmonizes the UX across self-managed and our SaaS Platforms and is a good fit for Pods.
-
-Organizations solve the following problems:
-
-1. We can group top-level namespaces by organization. It is very similar to the initial concept of "instance groups". For example these two top-level namespaces would belong to the organization `GitLab`:
- 1. `https://gitlab.com/gitlab-org/`
- 1. `https://gitlab.com/gitlab-com/`
-1. We can isolate organizations from each other. Top-level namespaces of the same organization can interact within organizations but are not allowed to interact with other namespaces in other organizations. This is useful for customers because it means an organization provides clear boundaries - similar to a self-managed instance. This means we don't have to aggregate user dashboards across everything and can locally scope them to organizations.
-1. We don't need to define hierarchies inside an organization. It is a container that could be filled with whatever hierarchy / entity set makes sense (workspaces, top-level namespaces etc.)
-1. Self-managed instances would set a default organization.
-1. Organizations can control user-profiles in a central way. This could be achieved by having an organization specific user-profile. Such a profile makes it possible for the organization administrators to control the user role in a company, enforce user emails, or show a graphical indicator of a user being part of the organization. An example would be a "GitLab Employee stamp" on comments.
-
-![Move to Organizations](images/iteration0-organizations-introduction.png)
-
-#### Why would customers opt-in to Organizations?
-
-By introducing organizations and Pods we can improve the reliability, performance and availability of our SaaS Platforms.
-
-The first iteration of organizations would also have some benefits by providing more isolation. A simple example would be that `@` mentions could be scoped to an organization.
-
-Future iterations would create additional value but are beyond the scope of this blueprint.
-
-Organizations will likely be required in the future as well.
-
-#### Initial user experience
-
-1. We create a default `GitLab.com public` organization and assign all public top-level namespaces to it. This allows existing users to access all the data on GitLab.com, exactly as it does now.
-1. Any user wanting to opt-in to the benefits of organizations will need to set a single default organization. Any attempts for these users to load a global page like `/dashboard` will end up redirecting to `/-/organizations/<DEFAULT_ORGANIZATION>/dashboard`.
-1. New users that opted in to organizations will only ever see data that is related to a single organization. Upon login, data is shown for the default organization. It will be clear to the user how they can switch to a different organization. Users can still navigate to the `GitLab.com` organization but they won't see TODOs from their new organizations in any such views. Instead they'd need to navigate directly to `/organizations/my-company/-/dashboard`.
-
-### Migrating to Organizations
-
-Existing customers could also opt-in to migrate their existing top-level paid namespaces to become part of an organization. In most cases this will be a 1-to-1 mapping. But in some cases it may allow a customer to move multiple top-level namespaces into one organization (for example GitLab).
-
-Migrating to Organizations would be optional. We could even recruit a few beta testers early on to see if this works for them. GitLab itself could dogfood organizations and we'd surface a lot of issues restricting interactions with other namespaces.
-
-## Iteration 1 - Introduce Pod US 0
-
-### GitLab.com as Pod US0
-
-GitLab.com will be treated as the first pod `Pod US 0`. It will be unique and much larger compared to newly created pods. All existing top-level namespaces and organizations will remain on `Pod US 0` in the first iteration.
-
-### Users are globally available
-
-Users are globally available and the same for all pods. This means that user data needs to be handled separately, for example via decomposition, see [!95941](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95941).
-
-### Pod groundwork
-
-In this iteration, we'll lay all the groundwork to support a second Pod for new organizations. This will be transparent to customers.
-
-## Iteration 2 - Introduce Pod US 1
-
-### Add new organizations to Pod US 1
-
-After we are ready to support a second Pod, newly created organizations are located by default on `Pod US 1`. The user experience for organizations is already well established.
-
-### Migrate existing organizations from Pod US 0 to Pod US 1
-
-We know that we'll have to move organizations from `Pod US 0` to other pods to reduce its size and ultimately retire the existing GitLab.com architecture.
-
-By introducing organizations early, we should be able to draw strong "boundaries" across organizations and support migrating existing organizations to a new Pod.
-
-This is likely going to be GitLab itself - if we can dogfood this, we are likely going to be successful with other organizations as well.
-
-## Iteration 3 - Introduce Regions
-
-We can now leverage the Pods architecture to introduce Regions.
-
-## Iteration 4 - Introduce cross-organizational interactions as needed
-
-Based on user research, we may want to change certain features to work across organizations. Examples include:
-
-- Specific features allow for cross-organization interactions, for example forking, search.
-
-## Technical Proposals
-
-The Pods architecture do have long lasting implications to data processing, location, scalability and the GitLab architecture.
-This section links all different technical proposals that are being evaluated.
-
-- [Stateless Router That Uses a Cache to Pick Pod and Is Redirected When Wrong Pod Is Reached](proposal-stateless-router-with-buffering-requests.md)
-
-- [Stateless Router That Uses a Cache to Pick Pod and pre-flight `/api/v4/pods/learn`](proposal-stateless-router-with-routes-learning.md)
-
-## Impacted features
-
-The Pods architecture will impact many features requiring some of them to be rewritten, or changed significantly.
-This is the list of known affected features with the proposed solutions.
-
-- [Pods: Git Access](pods-feature-git-access.md)
-- [Pods: Data Migration](pods-feature-data-migration.md)
-- [Pods: Database Sequences](pods-feature-database-sequences.md)
-- [Pods: GraphQL](pods-feature-graphql.md)
-- [Pods: Organizations](pods-feature-organizations.md)
-- [Pods: Router Endpoints Classification](pods-feature-router-endpoints-classification.md)
-- [Pods: Schema changes (Postgres and Elasticsearch migrations)](pods-feature-schema-changes.md)
-- [Pods: Backups](pods-feature-backups.md)
-- [Pods: Global Search](pods-feature-global-search.md)
-- [Pods: CI Runners](pods-feature-ci-runners.md)
-- [Pods: Admin Area](pods-feature-admin-area.md)
-- [Pods: Secrets](pods-feature-secrets.md)
-- [Pods: Container Registry](pods-feature-container-registry.md)
-- [Pods: Contributions: Forks](pods-feature-contributions-forks.md)
-- [Pods: Personal Namespaces](pods-feature-personal-namespaces.md)
-- [Pods: Dashboard: Projects, Todos, Issues, Merge Requests, Activity, ...](pods-feature-dashboard.md)
-- [Pods: Snippets](pods-feature-snippets.md)
-- [Pods: Uploads](pods-feature-uploads.md)
-- [Pods: GitLab Pages](pods-feature-gitlab-pages.md)
-- [Pods: Agent for Kubernetes](pods-feature-agent-for-kubernetes.md)
-
-## Links
-
-- [Internal Pods presentation](https://docs.google.com/presentation/d/1x1uIiN8FR9fhL7pzFh9juHOVcSxEY7d2_q4uiKKGD44/edit#slide=id.ge7acbdc97a_0_155)
-- [Pods Epic](https://gitlab.com/groups/gitlab-org/-/epics/7582)
-- [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)
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-admin-area.md b/doc/architecture/blueprints/pods/pods-feature-admin-area.md
index 7efaa383510..0f02a4a88ba 100644
--- a/doc/architecture/blueprints/pods/pods-feature-admin-area.md
+++ b/doc/architecture/blueprints/pods/pods-feature-admin-area.md
@@ -1,58 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Admin Area'
+redirect_to: '../cells/cells-feature-admin-area.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-admin-area.md).
-# Pods: Admin Area
-
-In our Pods architecture proposal we plan to share all admin related tables in
-GitLab. This allows simpler management of all Pods in one interface and reduces
-the risk of settings diverging in different Pods. This introduces challenges
-with admin pages that allow you to manage data that will be spread across all
-Pods.
-
-## 1. Definition
-
-There are consequences for admin pages that contain data that spans "the whole
-instance" as the Admin pages may be served by any Pod or possibly just 1 pod.
-There are already many parts of the Admin interface that will have data that
-spans many pods. For example lists of all Groups, Projects, Topics, Jobs,
-Analytics, Applications and more. There are also administrative monitoring
-capabilities in the Admin page that will span many pods 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-pod Admin section. Probably
- the URL will need to be routable to a single Pod like `/pods/<pod_id>/admin`,
- then we can display this data per Pod. These pages will be distinct from
- other Admin pages which control settings that are shared across all Pods. We
- will also need to consider how this impacts self-managed customers and
- whether, or not, this should be visible for single-pod instances of GitLab.
-1. Build some aggregation interfaces for this data so that it can be fetched
- from all Pods 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 Pod the data is on. The downside, however, is
- that building this kind of aggregation is very tricky when all the Pods are
- designed to be totally independent, and it does also enforce more strict
- requirements on compatibility between Pods.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-agent-for-kubernetes.md b/doc/architecture/blueprints/pods/pods-feature-agent-for-kubernetes.md
index f390c751b8b..f28cc447e0a 100644
--- a/doc/architecture/blueprints/pods/pods-feature-agent-for-kubernetes.md
+++ b/doc/architecture/blueprints/pods/pods-feature-agent-for-kubernetes.md
@@ -1,29 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Agent for Kubernetes'
+redirect_to: '../cells/cells-feature-agent-for-kubernetes.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-agent-for-kubernetes.md).
-# Pods: Agent for Kubernetes
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-backups.md b/doc/architecture/blueprints/pods/pods-feature-backups.md
index 5e4de42f473..db22317cf75 100644
--- a/doc/architecture/blueprints/pods/pods-feature-backups.md
+++ b/doc/architecture/blueprints/pods/pods-feature-backups.md
@@ -1,61 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Backups'
+redirect_to: '../cells/cells-feature-backups.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-backups.md).
-# Pods: Backups
-
-Each pods 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 pod has a number of application databases to back up (e.g. `main`, and `ci`).
-
-Additionally, there may be cluster-wide metadata tables (e.g. `users` table)
-which is directly accesible 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 pod back up its copy of cluster-wide metdata tables.
-
-### 3.2 Consistency
-
-#### 3.2.1 Take backups independently
-
-As each pod will communicate with each other via API, and there will be no joins
-to the users table, it should be acceptable for each pod to take a backup
-independently of each other.
-
-#### 3.2.2 Enforce snapshots
-
-We can require that each pod 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 pods increases, it will likely not be feasible to take a
-snapshot at the same time for all pods. Hence taking backups independently is
-the better option.
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-ci-runners.md b/doc/architecture/blueprints/pods/pods-feature-ci-runners.md
index b75515a916f..1985bb21884 100644
--- a/doc/architecture/blueprints/pods/pods-feature-ci-runners.md
+++ b/doc/architecture/blueprints/pods/pods-feature-ci-runners.md
@@ -1,169 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: CI Runners'
+redirect_to: '../cells/cells-feature-ci-runners.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-ci-runners.md).
-# Pods: CI Runners
-
-GitLab in order to execute CI jobs [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/),
-very often managed by customer in their infrastructure.
-
-All CI jobs created as part of CI pipeline are run in a context of project
-it 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 subprojects of that group
-- project runners: runners that execute jobs from projects or many projects: some runners might
- have projects assigned from projects in different top-level groups.
-
-This alongside with existing data structure where `ci_runners` is a table describing
-all types of runners poses a challenge how the `ci_runners` should be managed in a Pods environment.
-
-## 2. Data flow
-
-GitLab Runners use a set of globally scoped endpoints to:
-
-- registration of a new runner via registration token `https://gitlab.com/api/v4/runners`
- ([subject for removal](../runner_tokens/index.md)) (`registration token`)
-- requests 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 an registered runner in a system with specific configuration (`tags`, `locked`, etc.)
-- build token representing an ephemeral token giving a limited access to updating a specific
- job, uploading artifacts, downloading dependent artifacts, downloading and uploading
- container registry images
-
-Each of those endpoints do 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 a context of a specific Pod it would be required
-that pick of a build would have to be processed by that particular Pod. This requires
-that build picking depending on a solution would have to be either:
-
-- routed to correct Pod for a first time
-- be made to be two phase: request build from global pool, claim build on a specific Pod using a Pod specific URL
-
-## 3. Proposal
-
-This section describes various proposals. Reader should consider that those
-proposals do describe solutions for different problems. Many or some aspects
-of those proposals might be the solution to the stated problem.
-
-### 3.1. Authentication tokens
-
-Even though the paths for CI Runners are not routable they can be made routable with
-those 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). Runner when first
- starts 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 `pod` 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 sole owner of the token that Runner later
- uses for specific job. There were prior discussions about not storing `build token`
- but rather using `JWT` token with defined scopes. Such token could encode the `pod`
- to which router could easily route all requests.
-
-### 3.2. Request body
-
-- The most of used endpoints pass authentication token in 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 Pod local
-
-We can pick a design where all runners are always registered and local to a given Pod:
-
-- Each Pod has it's own set of instance-wide runners that are updated at it's 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 Pod.
-- In this model we would require the above endpoints to be scoped to a Pod in some way
- or made routable. It might be via prefixing them, adding additional Pod parameter,
- or providing much more robust way to decode runner token and match it to Pod.
-- If routable token is used, we could move away from cryptographic random stored in
- database to rather prefer to use JWT tokens that would encode
-- The Admin Area showing registered Runners would have to be scoped to a Pod
-
-This model might be desired since it provides strong isolation guarantees.
-This model does significantly increase maintenance overhead since each Pod is managed
-separately.
-
-This model may require adjustments to runner tags feature so that projects have consistent runner experience across pods.
-
-### 3.4. Instance-wide are cluster-wide
-
-Contrary to proposal where all runners are Pod local, we can consider that runners
-are global, or just instance-wide runners are global.
-
-However, this requires significant overhaul of system and to change the following aspects:
-
-- `ci_runners` table would likely have to be split decomposed into `ci_instance_runners`, ...
-- all interfaces would have to be adopted to use correct table
-- build queuing would have to be reworked to be two phase where each Pod would know of all pending
- and running builds, but the actual claim of a build would happen against a Pod containing data
-- likely `ci_pending_builds` and `ci_running_builds` would have to be made `cluster-wide` tables
- increasing likelihood of creating hotspots in a system related to CI queueing
-
-This model makes it complex to implement from engineering side. Does make some data being shared
-between Pods. Creates hotspots / scalability issues in a system (ex. during abuse) that
-might impact experience of organizations on other Pods.
-
-### 3.5. GitLab CI Daemon
-
-Another potential solution to explore is to have a dedicated service responsible for builds queueing
-owning it's database and working in a model of either sharded or podded service. There were prior
-discussions about [CI/CD Daemon](https://gitlab.com/gitlab-org/gitlab/-/issues/19435).
-
-If the service would be sharded:
-
-- depending on a model if runners are cluster-wide or pod-local this service would have to fetch
- data from all Pods
-- if the sharded service would be used we could adapt a model of either sharing database containing
- `ci_pending_builds/ci_running_builds` with the service
-- if the sharded service would be used we could consider a push model where each Pod pushes to CI/CD Daemon
- builds that should be picked by Runner
-- the sharded service would be aware which Pod is responsible for processing the given build and could
- route processing requests to designated Pod
-
-If the service would be podded:
-
-- 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 solutions it appears that solution giving the most promise is:
-
-- use "instance-wide are Pod local"
-- refine endpoints to have routable identities (either via specific paths, or better tokens)
-
-Other potential upsides is to get rid of `ci_builds.token` and rather use a `JWT token`
-that can much better and easier encode wider set of scopes allowed by CI runner.
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-container-registry.md b/doc/architecture/blueprints/pods/pods-feature-container-registry.md
index d47913fbc2a..9d2bbb3febe 100644
--- a/doc/architecture/blueprints/pods/pods-feature-container-registry.md
+++ b/doc/architecture/blueprints/pods/pods-feature-container-registry.md
@@ -1,131 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Container Registry'
+redirect_to: '../cells/cells-feature-container-registry.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-container-registry.md).
-# Pods: Container Registry
-
-GitLab Container Registry is a feature allowing to store Docker Container Images
-in GitLab. You can read about GitLab integration [here](../../../user/packages/container_registry/index.md).
-
-## 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 it's 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 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 be have many authorized scopes. This allows container registry and client
-to mount existing blobs from another 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 project. Each project can have many
-container registry images attached.
-
-Currently in case of 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 external service and uses it's own data store
-- the data deduplication, the Pods architecture with registry run in a Pod 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 Pods architecture
-
-Due to it's architecture it extensive architecture and in general highly scalable
-horizontal architecture it should be evaluated if the GitLab Container Registry
-should be run not in Pod, 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 Pod
-
-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 Pod.
-
-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 Pod,
-but this might be desired approach.
-
-## 4. Evaluation
-
-There do not seem any theoretical problems with running GitLab Container Registry in a Pod.
-Service seems that can be easily made routable to work well.
-
-The practical complexities are around managing complex service from infrastructure side.
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-contributions-forks.md b/doc/architecture/blueprints/pods/pods-feature-contributions-forks.md
index 566ae50ec49..38bdef35329 100644
--- a/doc/architecture/blueprints/pods/pods-feature-contributions-forks.md
+++ b/doc/architecture/blueprints/pods/pods-feature-contributions-forks.md
@@ -1,120 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Contributions: Forks'
+redirect_to: '../cells/cells-feature-contributions-forks.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-contributions-forks.md).
-# Pods: Contributions: Forks
-
-[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
-
-[Forking workflow](../../../user/project/repository/forking_workflow.md) is common workflow
-with various usage patterns:
-
-- allows users to contribute back to upstream project
-- persist repositories into their personal namespace
-- copy to make changes and release as modified project
-
-Forks allow users not having write access to parent project to make changes. The forking workflow
-is especially important for the Open Source community which is able to contribute back
-to public projects. However, it is equally important in some companies which prefer the strong split
-of responsibilites and tighter access control. The access to project is restricted
-to designated list of developers.
-
-Forks enable:
-
-- tigther control of who can modify the upstream project
-- split of the responsibilites: parent project might use CI configuration connecting to production systems
-- run CI pipelines in context of fork in much more restrictive environment
-- consider all forks to be unveted which reduces risks of leaking secrets, or any other information
- tied with the project
-
-The forking model is problematic in Pods architecture for following reasons:
-
-- Forks are clones of existing repositories, forks could be created across different organizations, Pods and Gitaly shards.
-- User can create merge request and contribute back to upstream project, this upstream project might in a different organization and Pod.
-- The merge request CI pipeline is to executed in a context of source project, but presented in a context of target project.
-
-## 2. Data flow
-
-## 3. Proposals
-
-### 3.1. Intra-Cluster forks
-
-This proposal makes us to implement forks as a intra-ClusterPod forks where communication is done via API
-between all trusted Pods of a cluster:
-
-- Forks when created, they are created always in context of user choice of group.
-- Forks are isolated from Organization.
-- Organization or group owner could disable forking across organizations or forking in general.
-- When a Merge Request is created it is created in context of target project, referencing
- external project on another Pod.
-- To target project the merge reference is transfered that is used for presenting information
- in context of target project.
-- CI pipeline is fetched in context of source project as it-is today, the result is fetched into
- Merge Request of target project.
-- The Pod holding target project internally uses GraphQL to fetch status of source project
- and include in context of the information for merge request.
-
-Upsides:
-
-- All existing forks continue to work as-is, 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 ability of users today to clone repository to local computer
- and push it to any repository of choice.
-- Access control of source project can be lower than those of target project. System today
- 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, the forks are created in a user personal namespace
-tied with the organization. Example:
-
-- Each user that is part of 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 it's own personal namespace of the organization.
-- The user has that many personal namespaces as many organizations it belongs to.
-- The personal namespace behaves similar to 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 personal namespace of user in Organization.
-- All forks are part of to the organization.
-- The forks are not federated features.
-- The personal namespace and forked project do not share configuration with parent project.
-
-### 3.3. Forks are created as internal projects under current project
-
-Instead of creating projects across organizations, the 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 a context of 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).
-- The forks are not federated features.
-
-Downsides:
-
-- Does not answer how to handle and migrate all exisiting forks.
-- Might share current group / project settings - breaking some security boundaries.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-dashboard.md b/doc/architecture/blueprints/pods/pods-feature-dashboard.md
index e63d912b4c9..1d92b891aff 100644
--- a/doc/architecture/blueprints/pods/pods-feature-dashboard.md
+++ b/doc/architecture/blueprints/pods/pods-feature-dashboard.md
@@ -1,29 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Dashboard'
+redirect_to: '../cells/cells-feature-dashboard.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-dashboard.md).
-# Pods: Dashboard
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-data-migration.md b/doc/architecture/blueprints/pods/pods-feature-data-migration.md
index fbe97316dcc..c06006a86dc 100644
--- a/doc/architecture/blueprints/pods/pods-feature-data-migration.md
+++ b/doc/architecture/blueprints/pods/pods-feature-data-migration.md
@@ -1,130 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Data migration'
+redirect_to: '../cells/cells-feature-data-migration.md'
+remove_date: '2023-06-13'
---
-DISCLAIMER:
-This page may contain information related to upcoming products, features and
-functionality. It is important to note that the information presented is for
-informational purposes only, so please do not rely on the information for
-purchasing or planning purposes. Just like with all projects, the items
-mentioned on the page are subject to change or delay, and the development,
-release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+This document was moved to [another location](../cells/cells-feature-data-migration.md).
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
-
-# Pods: Data migration
-
-It is essential for Pods architecture to provide a way to migrate data out of big Pods
-into smaller ones. This describes various approaches to provide this type of split.
-
-We also need to handle for cases where data is already violating the expected
-isolation constraints of Pods (ie. 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 pods. This may mean some data needs to be
-deleted, or the feature changed and modelled slightly differently before we can
-properly split or migrate the organizations between pods.
-
-Having schema deviations across different Pods, which is a necessary
-consequence of different databases, will also impact our ability to migrate
-data between pods. Different schemas impact our ability to reliably replicate
-data across pods 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
-pods 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 Pods
-
-A single Pod can only be divided into many Pods. This is based on principle
-that it is easier to create exact clone of an existing Pod in many replicas
-out of which some will be made authoritative once migrated. Keeping those
-replicas up-to date with Pod 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 Pods.
-1. Split should be doable online.
-1. New Pods cannot contain pre-existing data.
-1. N Pods contain exact replica of Pod 0.
-1. The data of Pod 0 is live replicated to as many Pods it needs to be split.
-1. Once consensus is achieved between Pod 0 and N-Pods 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
- Pod holding the most recent data, like `gitlab-org` on `pod-100`.
-1. The data for `gitlab-org` on Pod 0, and on other non-authoritative N-Pods are dormant
- and will be removed in the future.
-1. All accesses to `gitlab-org` on a given Pod are validated about `pod_id` of `routes`
- to ensure that given Pod 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 pod 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 Pod
-
-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 Pod importing data into it. Ideally ensuring that we can
-perform logical replication live of all changed data, but change similarly to split
-which Pod is authoritative for this organization.
-
-1. It is hard to identify all resources belonging to organization.
-1. It requires either downtime for 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 redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-database-sequences.md b/doc/architecture/blueprints/pods/pods-feature-database-sequences.md
index 0a8bb4d250e..9c4d6c5e290 100644
--- a/doc/architecture/blueprints/pods/pods-feature-database-sequences.md
+++ b/doc/architecture/blueprints/pods/pods-feature-database-sequences.md
@@ -1,94 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Database Sequences'
+redirect_to: '../cells/cells-feature-database-sequences.md'
+remove_date: '2023-06-13'
---
-DISCLAIMER:
-This page may contain information related to upcoming products, features and
-functionality. It is important to note that the information presented is for
-informational purposes only, so please do not rely on the information for
-purchasing or planning purposes. Just like with all projects, the items
-mentioned on the page are subject to change or delay, and the development,
-release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+This document was moved to [another location](../cells/cells-feature-database-sequences.md).
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
-
-# Pods: Database Sequences
-
-GitLab today ensures that every database row create has unique ID, allowing
-to access Merge Request, CI Job or Project by a known global ID.
-
-Pods will use many distinct and not connected databases, each of them having
-a separate IDs for most of entities.
-
-It might be desirable to retain globally unique IDs for all database rows
-to allow migrating resources between Pods in the future.
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-This 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 database.
-
-- This might break existing IDs and requires adding 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 Pod index encoded in ID
-
-Since significant number of tables already use 64 bit ID numbers we could use MSB to encode
-Pod ID effectively enabling
-
-- This might limit amount of Pods that can be enabled in system, as we might decide to only
- allocate 1024 possible Pod numbers.
-- This might make IDs to be migratable between Pods, since even if entity from Pod 1 is migrated to Pod 100
- this ID would still be unique.
-- If resources are migrated the ID itself will not be enough to decode Pod number and we would need
- lookup table.
-- This requires updating all IDs to 32 bits.
-
-### 3.3. Allocate sequence ranges from central place
-
-Each Pod might receive its own range of the sequences as they are consumed from a centrally managed place.
-Once Pod 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 to be migratable between Pods, since even if entity from Pod 1 is migrated to Pod 100
- this ID would still be unique.
-- If resources are migrated the ID itself will not be enough to decode Pod number and we would need
- 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 this 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 Pod-local ID,
-but when referenced outside it would rather use IID (an ID that is monotonic in context of a given resource, like project).
-
-- This makes the ID 10000 for `merge_requests` be present on all Pods, which might be sometimes confusing
- as for uniqueness of the resource.
-- This might make random access by ID (if ever needed) be impossible without using 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 pod. 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 pods 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 redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-git-access.md b/doc/architecture/blueprints/pods/pods-feature-git-access.md
index 9bda2d1de9c..1a0df0f9569 100644
--- a/doc/architecture/blueprints/pods/pods-feature-git-access.md
+++ b/doc/architecture/blueprints/pods/pods-feature-git-access.md
@@ -1,163 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Git Access'
+redirect_to: '../cells/cells-feature-git-access.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-git-access.md).
-# Pods: Git Access
-
-This document describes impact of Pods architecture on all Git access (over HTTPS and SSH)
-patterns providing explanation of how potentially those features should be changed
-to work well with Pods.
-
-## 1. Definition
-
-Git access is done through out the application. It can be an operation performed by the system
-(read Git repository) or by user (create a new file via Web IDE, `git clone` or `git push` via command line).
-
-The Pods architecture defines that all Git repositories will be local to the Pod,
-so no repository could be shared with another Pod.
-
-The Pods architecture will require that any Git operation done can only be handled by a Pod holding
-the data. It means that any operation either via Web interface, API, or GraphQL needs to be routed
-to the correct Pod. It means that any `git clone` or `git push` operation can only be performed
-in a context of a Pod.
-
-## 2. Data flow
-
-The are various operations performed today by the 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 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 Pods stateless router proposal requires that any ambiguous path (that is not routable)
-will be made to be routable. It means that at least the following paths will have to be updated
-do 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 Pod 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 user's personal namespaces.
-
-## 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 Pod and Gitaly node.
-1. The across-Pods forks are likely impossible to be supported (discover: how this work today across different Gitaly node).
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-gitlab-pages.md b/doc/architecture/blueprints/pods/pods-feature-gitlab-pages.md
index 932f996d8ba..4c7f162434e 100644
--- a/doc/architecture/blueprints/pods/pods-feature-gitlab-pages.md
+++ b/doc/architecture/blueprints/pods/pods-feature-gitlab-pages.md
@@ -1,29 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: GitLab Pages'
+redirect_to: '../cells/cells-feature-gitlab-pages.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-gitlab-pages.md).
-# Pods: GitLab Pages
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-global-search.md b/doc/architecture/blueprints/pods/pods-feature-global-search.md
index 5ea863ac646..035e95219e4 100644
--- a/doc/architecture/blueprints/pods/pods-feature-global-search.md
+++ b/doc/architecture/blueprints/pods/pods-feature-global-search.md
@@ -1,47 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Global search'
+redirect_to: '../cells/cells-feature-global-search.md'
+remove_date: '2023-06-13'
---
-DISCLAIMER:
-This page may contain information related to upcoming products, features and
-functionality. It is important to note that the information presented is for
-informational purposes only, so please do not rely on the information for
-purchasing or planning purposes. Just like with all projects, the items
-mentioned on the page are subject to change or delay, and the development,
-release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+This document was moved to [another location](../cells/cells-feature-global-search.md).
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
-
-# Pods: Global search
-
-When we introduce multiple Pods we intend to isolate all services related to
-those Pods. This will include Elasticsearch which means our current global
-search functionality will not work. It may be possible to implement aggregated
-search across all pods, but it is unlikely to be performant to do fan-out
-searches across all pods 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 first versions of Pods will simply not support global searches and then
-we may later consider if building global searches to support popular use cases
-is worthwhile.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-graphql.md b/doc/architecture/blueprints/pods/pods-feature-graphql.md
index 87c8391fbb3..f0f01a2b120 100644
--- a/doc/architecture/blueprints/pods/pods-feature-graphql.md
+++ b/doc/architecture/blueprints/pods/pods-feature-graphql.md
@@ -1,94 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: GraphQL'
+redirect_to: '../cells/cells-feature-graphql.md'
+remove_date: '2023-06-13'
---
-DISCLAIMER:
-This page may contain information related to upcoming products, features and
-functionality. It is important to note that the information presented is for
-informational purposes only, so please do not rely on the information for
-purchasing or planning purposes. Just like with all projects, the items
-mentioned on the page are subject to change or delay, and the development,
-release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+This document was moved to [another location](../cells/cells-feature-graphql.md).
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
-
-# Pods: GraphQL
-
-GitLab extensively uses GraphQL to perform efficient data query operations.
-GraphQL due to it's nature is not directly routable. The way how GitLab uses
-it calls the `/api/graphql` endpoint, and only query or mutation of 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 Pods architecture.
-
-### 3.1. GraphQL routable by endpoint
-
-Change `/api/graphql` to `/api/organization/<organization>/graphql`.
-
-- This breaks all existing usages of `/api/graphql` endpoint
- since 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 Pod
- 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 Pods.
-
-- This might make pagination hard to achieve, or we might assume that
- we execute many queries of which results are merged across all Pods.
-
-```json
-{
- project(fullPath:"gitlab-org/gitlab"){
- id, description
- }
- group(fullPath:"gitlab-com") {
- id, description
- }
-}
-```
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-organizations.md b/doc/architecture/blueprints/pods/pods-feature-organizations.md
index a0a87458767..f801f739374 100644
--- a/doc/architecture/blueprints/pods/pods-feature-organizations.md
+++ b/doc/architecture/blueprints/pods/pods-feature-organizations.md
@@ -1,58 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Organizations'
+redirect_to: '../cells/cells-feature-organizations.md'
+remove_date: '2023-06-13'
---
-DISCLAIMER:
-This page may contain information related to upcoming products, features and
-functionality. It is important to note that the information presented is for
-informational purposes only, so please do not rely on the information for
-purchasing or planning purposes. Just like with all projects, the items
-mentioned on the page are subject to change or delay, and the development,
-release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+This document was moved to [another location](../cells/cells-feature-organizations.md).
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
-
-# Pods: Organizations
-
-One of the major designs of Pods architecture is strong isolation between Groups.
-Organizations as described by this blueprint provides a way to have plausible UX
-for joining together many Groups that are isolated from the rest of systems.
-
-## 1. Definition
-
-Pods do require that all groups and projects of a single organization can
-only be stored on a single Pod since a Pod can only access data that it holds locally
-and has very limited capabilities to read information from other Pods.
-
-Pods 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 such 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 Pod.
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-personal-namespaces.md b/doc/architecture/blueprints/pods/pods-feature-personal-namespaces.md
index f78044bb551..237eb5f9d64 100644
--- a/doc/architecture/blueprints/pods/pods-feature-personal-namespaces.md
+++ b/doc/architecture/blueprints/pods/pods-feature-personal-namespaces.md
@@ -1,29 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Personal Namespaces'
+redirect_to: '../cells/cells-feature-personal-namespaces.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-personal-namespaces.md).
-# Pods: Personal Namespaces
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md b/doc/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md
index bf0969fcb38..b9e85c29481 100644
--- a/doc/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md
+++ b/doc/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md
@@ -1,46 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Router Endpoints Classification'
+redirect_to: '../cells/cells-feature-router-endpoints-classification.md'
+remove_date: '2023-06-13'
---
-DISCLAIMER:
-This page may contain information related to upcoming products, features and
-functionality. It is important to note that the information presented is for
-informational purposes only, so please do not rely on the information for
-purchasing or planning purposes. Just like with all projects, the items
-mentioned on the page are subject to change or delay, and the development,
-release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+This document was moved to [another location](../cells/cells-feature-router-endpoints-classification.md).
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
-
-# Pods: Router Endpoints Classification
-
-Classification of all endpoints is essential to properly route request
-hitting load balancer of a GitLab installation to a Pod that can serve it.
-
-Each Pod should be able to decode each request and classify for which Pod
-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 redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-schema-changes.md b/doc/architecture/blueprints/pods/pods-feature-schema-changes.md
index ae7c288028d..a57f76ad9d4 100644
--- a/doc/architecture/blueprints/pods/pods-feature-schema-changes.md
+++ b/doc/architecture/blueprints/pods/pods-feature-schema-changes.md
@@ -1,55 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Schema changes'
+redirect_to: '../cells/cells-feature-schema-changes.md'
+remove_date: '2023-06-13'
---
-DISCLAIMER:
-This page may contain information related to upcoming products, features and
-functionality. It is important to note that the information presented is for
-informational purposes only, so please do not rely on the information for
-purchasing or planning purposes. Just like with all projects, the items
-mentioned on the page are subject to change or delay, and the development,
-release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+This document was moved to [another location](../cells/cells-feature-schema-changes.md).
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
-
-# Pods: Schema changes
-
-When we introduce multiple Pods 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 Pods.
-
-A key benefit of Pods may be that it allows us to run different
-customers on different versions of GitLab. We may choose to update our own pod
-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 redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-secrets.md b/doc/architecture/blueprints/pods/pods-feature-secrets.md
index f18a41dc0fb..f33b98add21 100644
--- a/doc/architecture/blueprints/pods/pods-feature-secrets.md
+++ b/doc/architecture/blueprints/pods/pods-feature-secrets.md
@@ -1,48 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Secrets'
+redirect_to: '../cells/cells-feature-secrets.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-secrets.md).
-# Pods: Secrets
-
-Where possible, each pod should have its own distinct set of secrets.
-However, there will be some secrets that will be required to be the same for all
-pods in the cluster
-
-## 1. Definition
-
-GitLab has a lot of
-[secrets](https://docs.gitlab.com/charts/installation/secrets.html) that needs
-to be configured.
-
-Some secrets are for inter-component communication, e.g. `GitLab Shell secret`,
-and used only within a pod.
-
-Some secrets are used for features, e.g. `ci_jwt_signing_key`.
-
-## 2. Data flow
-
-## 3. Proposal
-
-1. Secrets used for features will need to be consistent across all pods, 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 pod will continue to work. We do not want to have
- to re-encrypt such rows when we move projects/groups between pods.
-1. Secrets which are used for intra-pod communication only should be uniquely generated
- per-pod.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-snippets.md b/doc/architecture/blueprints/pods/pods-feature-snippets.md
index 1bb866ca958..42d3c401dba 100644
--- a/doc/architecture/blueprints/pods/pods-feature-snippets.md
+++ b/doc/architecture/blueprints/pods/pods-feature-snippets.md
@@ -1,29 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Snippets'
+redirect_to: '../cells/cells-feature-snippets.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-snippets.md).
-# Pods: Snippets
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-template.md b/doc/architecture/blueprints/pods/pods-feature-template.md
index dfae21b5406..acc8e329725 100644
--- a/doc/architecture/blueprints/pods/pods-feature-template.md
+++ b/doc/architecture/blueprints/pods/pods-feature-template.md
@@ -1,29 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Problem A'
+redirect_to: '../cells/cells-feature-template.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-template.md).
-# Pods: A
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/pods-feature-uploads.md b/doc/architecture/blueprints/pods/pods-feature-uploads.md
index 634f3ef9560..1de4c138843 100644
--- a/doc/architecture/blueprints/pods/pods-feature-uploads.md
+++ b/doc/architecture/blueprints/pods/pods-feature-uploads.md
@@ -1,29 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods: Uploads'
+redirect_to: '../cells/cells-feature-uploads.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/cells-feature-uploads.md).
-# Pods: Uploads
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/proposal-stateless-router-with-buffering-requests.md b/doc/architecture/blueprints/pods/proposal-stateless-router-with-buffering-requests.md
index adc523e90c2..4c135c5dbc3 100644
--- a/doc/architecture/blueprints/pods/proposal-stateless-router-with-buffering-requests.md
+++ b/doc/architecture/blueprints/pods/proposal-stateless-router-with-buffering-requests.md
@@ -1,648 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods Stateless Router Proposal'
+redirect_to: '../cells/proposal-stateless-router-with-buffering-requests.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/proposal-stateless-router-with-buffering-requests.md).
-# Proposal: Stateless Router
-
-We will decompose `gitlab_users`, `gitlab_routes` and `gitlab_admin` related
-tables so that they can be shared between all pods and allow any pod to
-authenticate a user and route requests to the correct pod. Pods may receive
-requests for the resources they don't own, but they know how to redirect back
-to the correct pod.
-
-The router is stateless and does not read from the `routes` database which
-means that all interactions with the database still happen from the Rails
-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 Pods but instead they see
-different data dependent on their chosen "organization".
-[Organizations](index.md#organizations) will be a new model introduced to enforce isolation in the
-application and allow us to decide which request route to which pod, since an
-organization can only be on a single pod.
-
-## Differences
-
-The main difference between this proposal and the one [with learning routes](proposal-stateless-router-with-routes-learning.md)
-is that this proposal always sends requests to any of the Pods. If the requests cannot be processed,
-the requests will be bounced back with relevant headers. This requires that request to be buffered.
-It allows that request decoding can be either via URI or Body of request by Rails.
-This means that each request might be sent more than once and be processed more than once as result.
-
-The [with learning routes proposal](proposal-stateless-router-with-routes-learning.md) requires that
-routable information is always encoded in URI, and the router sends a pre-flight request.
-
-## Summary in diagrams
-
-This shows how a user request routes via DNS to the nearest router and the router chooses a pod to send the request to.
-
-```mermaid
-graph TD;
- user((User));
- dns[DNS];
- router_us(Router);
- router_eu(Router);
- pod_us0{Pod US0};
- pod_us1{Pod US1};
- pod_eu0{Pod EU0};
- pod_eu1{Pod EU1};
- user-->dns;
- dns-->router_us;
- dns-->router_eu;
- subgraph Europe
- router_eu-->pod_eu0;
- router_eu-->pod_eu1;
- end
- subgraph United States
- router_us-->pod_us0;
- router_us-->pod_us1;
- end
-```
-
-<details><summary>More detail</summary>
-
-This shows that the router can actually send requests to any pod. The user will
-get the closest router to them geographically.
-
-```mermaid
-graph TD;
- user((User));
- dns[DNS];
- router_us(Router);
- router_eu(Router);
- pod_us0{Pod US0};
- pod_us1{Pod US1};
- pod_eu0{Pod EU0};
- pod_eu1{Pod EU1};
- user-->dns;
- dns-->router_us;
- dns-->router_eu;
- subgraph Europe
- router_eu-->pod_eu0;
- router_eu-->pod_eu1;
- end
- subgraph United States
- router_us-->pod_us0;
- router_us-->pod_us1;
- end
- router_eu-.->pod_us0;
- router_eu-.->pod_us1;
- router_us-.->pod_eu0;
- router_us-.->pod_eu1;
-```
-
-</details>
-
-<details><summary>Even more detail</summary>
-
-This shows the databases. `gitlab_users` and `gitlab_routes` exist only in the
-US region but are replicated to other regions. Replication does not have an
-arrow because it's too hard to read the diagram.
-
-```mermaid
-graph TD;
- user((User));
- dns[DNS];
- router_us(Router);
- router_eu(Router);
- pod_us0{Pod US0};
- pod_us1{Pod US1};
- pod_eu0{Pod EU0};
- pod_eu1{Pod EU1};
- db_gitlab_users[(gitlab_users Primary)];
- db_gitlab_routes[(gitlab_routes Primary)];
- db_gitlab_users_replica[(gitlab_users Replica)];
- db_gitlab_routes_replica[(gitlab_routes Replica)];
- db_pod_us0[(gitlab_main/gitlab_ci Pod US0)];
- db_pod_us1[(gitlab_main/gitlab_ci Pod US1)];
- db_pod_eu0[(gitlab_main/gitlab_ci Pod EU0)];
- db_pod_eu1[(gitlab_main/gitlab_ci Pod EU1)];
- user-->dns;
- dns-->router_us;
- dns-->router_eu;
- subgraph Europe
- router_eu-->pod_eu0;
- router_eu-->pod_eu1;
- pod_eu0-->db_pod_eu0;
- pod_eu0-->db_gitlab_users_replica;
- pod_eu0-->db_gitlab_routes_replica;
- pod_eu1-->db_gitlab_users_replica;
- pod_eu1-->db_gitlab_routes_replica;
- pod_eu1-->db_pod_eu1;
- end
- subgraph United States
- router_us-->pod_us0;
- router_us-->pod_us1;
- pod_us0-->db_pod_us0;
- pod_us0-->db_gitlab_users;
- pod_us0-->db_gitlab_routes;
- pod_us1-->db_gitlab_users;
- pod_us1-->db_gitlab_routes;
- pod_us1-->db_pod_us1;
- end
- router_eu-.->pod_us0;
- router_eu-.->pod_us1;
- router_us-.->pod_eu0;
- router_us-.->pod_eu1;
-```
-
-</details>
-
-## Summary of changes
-
-1. Tables related to User data (including profile settings, authentication credentials, personal access tokens) are decomposed into a `gitlab_users` schema
-1. The `routes` table is decomposed into `gitlab_routes` schema
-1. The `application_settings` (and probably a few other instance level tables) are decomposed into `gitlab_admin` schema
-1. A new column `routes.pod_id` is added to `routes` table
-1. A new Router service exists to choose which pod to route a request to.
-1. A new concept will be introduced in GitLab called an organization and a user can select a "default organization" and this will be a user level setting. The default organization is used to redirect users away from ambiguous routes like `/dashboard` to organization scoped routes like `/organizations/my-organization/-/dashboard`. Legacy users will have a special default organization that allows them to keep using global resources on `Pod US0`. All existing namespaces will initially move to this public organization.
-1. If a pod receives a request for a `routes.pod_id` that it does not own it returns a `302` with `X-Gitlab-Pod-Redirect` header so that the router can send the request to the correct pod. The correct pod can also set a header `X-Gitlab-Pod-Cache` which contains information about how this request should be cached to remember the pod. For example if the request was `/gitlab-org/gitlab` then the header would encode `/gitlab-org/* => Pod US0` (for example, any requests starting with `/gitlab-org/` can always be routed to `Pod US0`
-1. When the pod does not know (from the cache) which pod to send a request to it just picks a random pod within it's region
-1. Writes to `gitlab_users` and `gitlab_routes` are sent to a primary PostgreSQL server in our `US` region but reads can come from replicas in the same region. This will add latency for these writes but we expect they are infrequent relative to the rest of GitLab.
-
-## Detailed explanation of default organization in the first iteration
-
-All users will get a new column `users.default_organization` which they can
-control in user settings. We will introduce a concept of the
-`GitLab.com Public` organization. This will be set as the default organization for all existing
-users. This organization will allow the user to see data from all namespaces in
-`Pod US0` (for example, our original GitLab.com instance). This behavior can be invisible to
-existing users such that they don't even get told when they are viewing a
-global page like `/dashboard` that it's even scoped to an organization.
-
-Any new users with a default organization other than `GitLab.com Public` will have
-a distinct user experience and will be fully aware that every page they load is
-only ever scoped to a single organization. These users can never
-load any global pages like `/dashboard` and will end up being redirected to
-`/organizations/<DEFAULT_ORGANIZATION>/-/dashboard`. This may also be the case
-for legacy APIs and such users may only ever be able to use APIs scoped to a
-organization.
-
-## Detailed explanation of Admin Area settings
-
-We believe that maintaining and synchronizing Admin Area settings will be
-frustrating and painful so to avoid this we will decompose and share all Admin Area
-settings in the `gitlab_admin` schema. This should be safe (similar to other
-shared schemas) because these receive very little write traffic.
-
-In cases where different pods need different settings (for example, the
-Elasticsearch URL), we will either decide to use a templated
-format in the relevant `application_settings` row which allows it to be dynamic
-per pod. Alternatively if that proves difficult we'll introduce a new table
-called `per_pod_application_settings` and this will have 1 row per pod to allow
-setting different settings per pod. It will still be part of the `gitlab_admin`
-schema and shared which will allow us to centrally manage it and simplify
-keeping settings in sync for all pods.
-
-## Pros
-
-1. Router is stateless and can live in many regions. We use Anycast DNS to resolve to nearest region for the user.
-1. Pods can receive requests for namespaces in the wrong pod and the user
- still gets the right response as well as caching at the router that
- ensures the next request is sent to the correct pod so the next request
- will go to the correct pod
-1. The majority of the code still lives in `gitlab` rails codebase. The Router doesn't actually need to understand how GitLab URLs are composed.
-1. Since the responsibility to read and write `gitlab_users`,
- `gitlab_routes` and `gitlab_admin` still lives in Rails it means minimal
- changes will be needed to the Rails application compared to extracting
- services that need to isolate the domain models and build new interfaces.
-1. Compared to a separate routing service this allows the Rails application
- to encode more complex rules around how to map URLs to the correct pod
- and may work for some existing API endpoints.
-1. All the new infrastructure (just a router) is optional and a single-pod
- self-managed installation does not even need to run the Router and there are
- no other new services.
-
-## Cons
-
-1. `gitlab_users`, `gitlab_routes` and `gitlab_admin` databases may need to be
- replicated across regions and writes need to go across regions. We need to
- do an analysis on write TPS for the relevant tables to determine if this is
- feasible.
-1. Sharing access to the database from many different Pods means that they are
- all coupled at the Postgres schema level and this means changes to the
- database schema need to be done carefully in sync with the deployment of all
- Pods. This limits us to ensure that Pods are kept in closely similar
- versions compared to an architecture with shared services that have an API
- we control.
-1. Although most data is stored in the right region there can be requests
- proxied from another region which may be an issue for certain types
- of compliance.
-1. Data in `gitlab_users` and `gitlab_routes` databases must be replicated in
- all regions which may be an issue for certain types of compliance.
-1. The router cache may need to be very large if we get a wide variety of URLs
- (for example, long tail). In such a case we may need to implement a 2nd level of
- caching in user cookies so their frequently accessed pages always go to the
- right pod the first time.
-1. Having shared database access for `gitlab_users` and `gitlab_routes`
- from multiple pods is an unusual architecture decision compared to
- extracting services that are called from multiple pods.
-1. It is very likely we won't be able to find cacheable elements of a
- GraphQL URL and often existing GraphQL endpoints are heavily dependent on
- ids that won't be in the `routes` table so pods won't necessarily know
- what pod has the data. As such we'll probably have to update our GraphQL
- calls to include an organization context in the path like
- `/api/organizations/<organization>/graphql`.
-1. This architecture implies that implemented endpoints can only access data
- that are readily accessible on a given Pod, but are unlikely
- to aggregate information from many Pods.
-1. All unknown routes are sent to the latest deployment which we assume to be `Pod US0`.
- This is required as newly added endpoints will be only decodable by latest pod.
- This Pod could later redirect to correct one that can serve the given request.
- Since request processing might be heavy some Pods might receive significant amount
- of traffic due to that.
-
-## Example database configuration
-
-Handling shared `gitlab_users`, `gitlab_routes` and `gitlab_admin` databases, while having dedicated `gitlab_main` and `gitlab_ci` databases should already be handled by the way we use `config/database.yml`. We should also, already be able to handle the dedicated EU replicas while having a single US primary for `gitlab_users` and `gitlab_routes`. Below is a snippet of part of the database configuration for the Pod architecture described above.
-
-<details><summary>Pod US0</summary>
-
-```yaml
-# config/database.yml
-production:
- main:
- host: postgres-main.pod-us0.primary.consul
- load_balancing:
- discovery: postgres-main.pod-us0.replicas.consul
- ci:
- host: postgres-ci.pod-us0.primary.consul
- load_balancing:
- discovery: postgres-ci.pod-us0.replicas.consul
- users:
- host: postgres-users-primary.consul
- load_balancing:
- discovery: postgres-users-replicas.us.consul
- routes:
- host: postgres-routes-primary.consul
- load_balancing:
- discovery: postgres-routes-replicas.us.consul
- admin:
- host: postgres-admin-primary.consul
- load_balancing:
- discovery: postgres-admin-replicas.us.consul
-```
-
-</details>
-
-<details><summary>Pod EU0</summary>
-
-```yaml
-# config/database.yml
-production:
- main:
- host: postgres-main.pod-eu0.primary.consul
- load_balancing:
- discovery: postgres-main.pod-eu0.replicas.consul
- ci:
- host: postgres-ci.pod-eu0.primary.consul
- load_balancing:
- discovery: postgres-ci.pod-eu0.replicas.consul
- users:
- host: postgres-users-primary.consul
- load_balancing:
- discovery: postgres-users-replicas.eu.consul
- routes:
- host: postgres-routes-primary.consul
- load_balancing:
- discovery: postgres-routes-replicas.eu.consul
- admin:
- host: postgres-admin-primary.consul
- load_balancing:
- discovery: postgres-admin-replicas.eu.consul
-```
-
-</details>
-
-## Request flows
-
-1. `gitlab-org` is a top level namespace and lives in `Pod US0` in the `GitLab.com Public` organization
-1. `my-company` is a top level namespace and lives in `Pod EU0` in the `my-organization` organization
-
-### Experience for paying user that is part of `my-organization`
-
-Such a user will have a default organization set to `/my-organization` and will be
-unable to load any global routes outside of this organization. They may load other
-projects/namespaces but their MR/Todo/Issue counts at the top of the page will
-not be correctly populated in the first iteration. The user will be aware of
-this limitation.
-
-#### Navigates to `/my-company/my-project` while logged in
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. They request `/my-company/my-project` without the router cache, so the router chooses randomly `Pod EU1`
-1. `Pod EU1` does not have `/my-company`, but it knows that it lives in `Pod EU0` so it redirects the router to `Pod EU0`
-1. `Pod EU0` returns the correct response as well as setting the cache headers for the router `/my-company/* => Pod EU0`
-1. The router now caches and remembers any request paths matching `/my-company/*` should go to `Pod EU0`
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- participant pod_eu1 as Pod EU1
- user->>router_eu: GET /my-company/my-project
- router_eu->>pod_eu1: GET /my-company/my-project
- pod_eu1->>router_eu: 302 /my-company/my-project X-Gitlab-Pod-Redirect={pod:Pod EU0}
- router_eu->>pod_eu0: GET /my-company/my-project
- pod_eu0->>user: <h1>My Project... X-Gitlab-Pod-Cache={path_prefix:/my-company/}
-```
-
-#### Navigates to `/my-company/my-project` while not logged in
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. The router does not have `/my-company/*` cached yet so it chooses randomly `Pod EU1`
-1. `Pod EU1` redirects them through a login flow
-1. Still they request `/my-company/my-project` without the router cache, so the router chooses a random pod `Pod EU1`
-1. `Pod EU1` does not have `/my-company`, but it knows that it lives in `Pod EU0` so it redirects the router to `Pod EU0`
-1. `Pod EU0` returns the correct response as well as setting the cache headers for the router `/my-company/* => Pod EU0`
-1. The router now caches and remembers any request paths matching `/my-company/*` should go to `Pod EU0`
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- participant pod_eu1 as Pod EU1
- user->>router_eu: GET /my-company/my-project
- router_eu->>pod_eu1: GET /my-company/my-project
- pod_eu1->>user: 302 /users/sign_in?redirect=/my-company/my-project
- user->>router_eu: GET /users/sign_in?redirect=/my-company/my-project
- router_eu->>pod_eu1: GET /users/sign_in?redirect=/my-company/my-project
- pod_eu1->>user: <h1>Sign in...
- user->>router_eu: POST /users/sign_in?redirect=/my-company/my-project
- router_eu->>pod_eu1: POST /users/sign_in?redirect=/my-company/my-project
- pod_eu1->>user: 302 /my-company/my-project
- user->>router_eu: GET /my-company/my-project
- router_eu->>pod_eu1: GET /my-company/my-project
- pod_eu1->>router_eu: 302 /my-company/my-project X-Gitlab-Pod-Redirect={pod:Pod EU0}
- router_eu->>pod_eu0: GET /my-company/my-project
- pod_eu0->>user: <h1>My Project... X-Gitlab-Pod-Cache={path_prefix:/my-company/}
-```
-
-#### Navigates to `/my-company/my-other-project` after last step
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. The router cache now has `/my-company/* => Pod EU0`, so the router chooses `Pod EU0`
-1. `Pod EU0` returns the correct response as well as the cache header again
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- participant pod_eu1 as Pod EU1
- user->>router_eu: GET /my-company/my-project
- router_eu->>pod_eu0: GET /my-company/my-project
- pod_eu0->>user: <h1>My Project... X-Gitlab-Pod-Cache={path_prefix:/my-company/}
-```
-
-#### Navigates to `/gitlab-org/gitlab` after last step
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. The router has no cached value for this URL so randomly chooses `Pod EU0`
-1. `Pod EU0` redirects the router to `Pod US0`
-1. `Pod US0` returns the correct response as well as the cache header again
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- participant pod_us0 as Pod US0
- user->>router_eu: GET /gitlab-org/gitlab
- router_eu->>pod_eu0: GET /gitlab-org/gitlab
- pod_eu0->>router_eu: 302 /gitlab-org/gitlab X-Gitlab-Pod-Redirect={pod:Pod US0}
- router_eu->>pod_us0: GET /gitlab-org/gitlab
- pod_us0->>user: <h1>GitLab.org... X-Gitlab-Pod-Cache={path_prefix:/gitlab-org/}
-```
-
-In this case the user is not on their "default organization" so their TODO
-counter will not include their normal todos. We may choose to highlight this in
-the UI somewhere. A future iteration may be able to fetch that for them from
-their default organization.
-
-#### Navigates to `/`
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. Router does not have a cache for `/` route (specifically rails never tells it to cache this route)
-1. The Router choose `Pod EU0` randomly
-1. The Rails application knows the users default organization is `/my-organization`, so
- it redirects the user to `/organizations/my-organization/-/dashboard`
-1. The Router has a cached value for `/organizations/my-organization/*` so it then sends the
- request to `POD EU0`
-1. `Pod EU0` serves up a new page `/organizations/my-organization/-/dashboard` which is the same
- dashboard view we have today but scoped to an organization clearly in the UI
-1. The user is (optionally) presented with a message saying that data on this page is only
- from their default organization and that they can change their default
- organization if it's not right.
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- user->>router_eu: GET /
- router_eu->>pod_eu0: GET /
- pod_eu0->>user: 302 /organizations/my-organization/-/dashboard
- user->>router: GET /organizations/my-organization/-/dashboard
- router->>pod_eu0: GET /organizations/my-organization/-/dashboard
- pod_eu0->>user: <h1>My Company Dashboard... X-Gitlab-Pod-Cache={path_prefix:/organizations/my-organization/}
-```
-
-#### Navigates to `/dashboard`
-
-As above, they will end up on `/organizations/my-organization/-/dashboard` as
-the rails application will already redirect `/` to the dashboard page.
-
-### Navigates to `/not-my-company/not-my-project` while logged in (but they don't have access since this project/group is private)
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. The router knows that `/not-my-company` lives in `Pod US1` so sends the request to this
-1. The user does not have access so `Pod US1` returns 404
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_us1 as Pod US1
- user->>router_eu: GET /not-my-company/not-my-project
- router_eu->>pod_us1: GET /not-my-company/not-my-project
- pod_us1->>user: 404
-```
-
-#### Creates a new top level namespace
-
-The user will be asked which organization they want the namespace to belong to.
-If they select `my-organization` then it will end up on the same pod as all
-other namespaces in `my-organization`. If they select nothing we default to
-`GitLab.com Public` and it is clear to the user that this is isolated from
-their existing organization such that they won't be able to see data from both
-on a single page.
-
-### Experience for GitLab team member that is part of `/gitlab-org`
-
-Such a user is considered a legacy user and has their default organization set to
-`GitLab.com Public`. This is a "meta" organization that does not really exist but
-the Rails application knows to interpret this organization to mean that they are
-allowed to use legacy global functionality like `/dashboard` to see data across
-namespaces located on `Pod US0`. The rails backend also knows that the default pod to render any ambiguous
-routes like `/dashboard` is `Pod US0`. Lastly the user will be allowed to
-navigate to organizations on another pod like `/my-organization` but when they do the
-user will see a message indicating that some data may be missing (for example, the
-MRs/Issues/Todos) counts.
-
-#### Navigates to `/gitlab-org/gitlab` while not logged in
-
-1. User is in the US so DNS resolves to the US router
-1. The router knows that `/gitlab-org` lives in `Pod US0` so sends the request
- to this pod
-1. `Pod US0` serves up the response
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_us as Router US
- participant pod_us0 as Pod US0
- user->>router_us: GET /gitlab-org/gitlab
- router_us->>pod_us0: GET /gitlab-org/gitlab
- pod_us0->>user: <h1>GitLab.org... X-Gitlab-Pod-Cache={path_prefix:/gitlab-org/}
-```
-
-#### Navigates to `/`
-
-1. User is in US so DNS resolves to the router in US
-1. Router does not have a cache for `/` route (specifically rails never tells it to cache this route)
-1. The Router chooses `Pod US1` randomly
-1. The Rails application knows the users default organization is `GitLab.com Public`, so
- it redirects the user to `/dashboards` (only legacy users can see
- `/dashboard` global view)
-1. Router does not have a cache for `/dashboard` route (specifically rails never tells it to cache this route)
-1. The Router chooses `Pod US1` randomly
-1. The Rails application knows the users default organization is `GitLab.com Public`, so
- it allows the user to load `/dashboards` (only legacy users can see
- `/dashboard` global view) and redirects to router the legacy pod which is `Pod US0`
-1. `Pod US0` serves up the global view dashboard page `/dashboard` which is the same
- dashboard view we have today
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_us as Router US
- participant pod_us0 as Pod US0
- participant pod_us1 as Pod US1
- user->>router_us: GET /
- router_us->>pod_us1: GET /
- pod_us1->>user: 302 /dashboard
- user->>router_us: GET /dashboard
- router_us->>pod_us1: GET /dashboard
- pod_us1->>router_us: 302 /dashboard X-Gitlab-Pod-Redirect={pod:Pod US0}
- router_us->>pod_us0: GET /dashboard
- pod_us0->>user: <h1>Dashboard...
-```
-
-#### Navigates to `/my-company/my-other-project` while logged in (but they don't have access since this project is private)
-
-They get a 404.
-
-### Experience for non-authenticated users
-
-Flow is similar to authenticated users except global routes like `/dashboard` will
-redirect to the login page as there is no default organization to choose from.
-
-### A new customers signs up
-
-They will be asked if they are already part of an organization or if they'd
-like to create one. If they choose neither they end up no the default
-`GitLab.com Public` organization.
-
-### An organization is moved from 1 pod to another
-
-TODO
-
-### GraphQL/API requests which don't include the namespace in the URL
-
-TODO
-
-### The autocomplete suggestion functionality in the search bar which remembers recent issues/MRs
-
-TODO
-
-### Global search
-
-TODO
-
-## Administrator
-
-### Loads `/admin` page
-
-1. Router picks a random pod `Pod US0`
-1. Pod US0 redirects user to `/admin/pods/podus0`
-1. Pod US0 renders an Admin Area page and also returns a cache header to cache `/admin/podss/podus0/* => Pod US0`. The Admin Area page contains a dropdown list showing other pods they could select and it changes the query parameter.
-
-Admin Area settings in Postgres are all shared across all pods to avoid
-divergence but we still make it clear in the URL and UI which pod is serving
-the Admin Area page as there is dynamic data being generated from these pages and
-the operator may want to view a specific pod.
-
-## More Technical Problems To Solve
-
-### Replicating User Sessions Between All Pods
-
-Today user sessions live in Redis but each pod will have their own Redis instance. We already use a dedicated Redis instance for sessions so we could consider sharing this with all pods like we do with `gitlab_users` PostgreSQL database. But an important consideration will be latency as we would still want to mostly fetch sessions from the same region.
-
-An alternative might be that user sessions get moved to a JWT payload that encodes all the session data but this has downsides. For example, it is difficult to expire a user session, when their password changes or for other reasons, if the session lives in a JWT controlled by the user.
-
-### How do we migrate between Pods
-
-Migrating data between pods will need to factor all data stores:
-
-1. PostgreSQL
-1. Redis Shared State
-1. Gitaly
-1. Elasticsearch
-
-### Is it still possible to leak the existence of private groups via a timing attack?
-
-If you have router in EU, and you know that EU router by default redirects
-to EU located Pods, you know their latency (lets assume 10 ms). Now, if your
-request is bounced back and redirected to US which has different latency
-(lets assume that roundtrip will be around 60 ms) you can deduce that 404 was
-returned by US Pod and know that your 404 is in fact 403.
-
-We may defer this until we actually implement a pod in a different region. Such timing attacks are already theoretically possible with the way we do permission checks today but the timing difference is probably too small to be able to detect.
-
-One technique to mitigate this risk might be to have the router add a random
-delay to any request that returns 404 from a pod.
-
-## Should runners be shared across all pods?
-
-We have 2 options and we should decide which is easier:
-
-1. Decompose runner registration and queuing tables and share them across all
- pods. This may have implications for scalability, and we'd need to consider
- if this would include group/project runners as this may have scalability
- concerns as these are high traffic tables that would need to be shared.
-1. Runners are registered per-pod and, we probably have a separate fleet of
- runners for every pod or just register the same runners to many pods which
- may have implications for queueing
-
-## How do we guarantee unique ids across all pods for things that cannot conflict?
-
-This project assumes at least namespaces and projects have unique ids across
-all pods as many requests need to be routed based on their ID. Since those
-tables are across different databases then guaranteeing a unique ID will
-require a new solution. There are likely other tables where unique IDs are
-necessary and depending on how we resolve routing for GraphQL and other APIs
-and other design goals it may be determined that we want the primary key to be
-unique for all tables.
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/pods/proposal-stateless-router-with-routes-learning.md b/doc/architecture/blueprints/pods/proposal-stateless-router-with-routes-learning.md
index 1156e65f6aa..093d5d7acc6 100644
--- a/doc/architecture/blueprints/pods/proposal-stateless-router-with-routes-learning.md
+++ b/doc/architecture/blueprints/pods/proposal-stateless-router-with-routes-learning.md
@@ -1,672 +1,11 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods Stateless Router Proposal'
+redirect_to: '../cells/proposal-stateless-router-with-routes-learning.md'
+remove_date: '2023-06-13'
---
-This document is a work-in-progress and represents a very early state of the
-Pods design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Pods, 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.
+This document was moved to [another location](../cells/proposal-stateless-router-with-routes-learning.md).
-# Proposal: Stateless Router
-
-We will decompose `gitlab_users`, `gitlab_routes` and `gitlab_admin` related
-tables so that they can be shared between all pods and allow any pod to
-authenticate a user and route requests to the correct pod. Pods may receive
-requests for the resources they don't own, but they know how to redirect back
-to the correct pod.
-
-The router is stateless and does not read from the `routes` database which
-means that all interactions with the database still happen from the Rails
-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 Pods but instead they see
-different data dependent on their chosen "organization".
-[Organizations](index.md#organizations) will be a new model introduced to enforce isolation in the
-application and allow us to decide which request route to which pod, since an
-organization can only be on a single pod.
-
-## Differences
-
-The main difference between this proposal and one [with buffering requests](proposal-stateless-router-with-buffering-requests.md)
-is that this proposal uses a pre-flight API request (`/api/v4/pods/learn`) to redirect the request body to the correct Pod.
-This means that each request is sent exactly once to be processed, but the URI is used to decode which Pod it should be directed.
-
-## Summary in diagrams
-
-This shows how a user request routes via DNS to the nearest router and the router chooses a pod to send the request to.
-
-```mermaid
-graph TD;
- user((User));
- dns[DNS];
- router_us(Router);
- router_eu(Router);
- pod_us0{Pod US0};
- pod_us1{Pod US1};
- pod_eu0{Pod EU0};
- pod_eu1{Pod EU1};
- user-->dns;
- dns-->router_us;
- dns-->router_eu;
- subgraph Europe
- router_eu-->pod_eu0;
- router_eu-->pod_eu1;
- end
- subgraph United States
- router_us-->pod_us0;
- router_us-->pod_us1;
- end
-```
-
-### More detail
-
-This shows that the router can actually send requests to any pod. The user will
-get the closest router to them geographically.
-
-```mermaid
-graph TD;
- user((User));
- dns[DNS];
- router_us(Router);
- router_eu(Router);
- pod_us0{Pod US0};
- pod_us1{Pod US1};
- pod_eu0{Pod EU0};
- pod_eu1{Pod EU1};
- user-->dns;
- dns-->router_us;
- dns-->router_eu;
- subgraph Europe
- router_eu-->pod_eu0;
- router_eu-->pod_eu1;
- end
- subgraph United States
- router_us-->pod_us0;
- router_us-->pod_us1;
- end
- router_eu-.->pod_us0;
- router_eu-.->pod_us1;
- router_us-.->pod_eu0;
- router_us-.->pod_eu1;
-```
-
-### Even more detail
-
-This shows the databases. `gitlab_users` and `gitlab_routes` exist only in the
-US region but are replicated to other regions. Replication does not have an
-arrow because it's too hard to read the diagram.
-
-```mermaid
-graph TD;
- user((User));
- dns[DNS];
- router_us(Router);
- router_eu(Router);
- pod_us0{Pod US0};
- pod_us1{Pod US1};
- pod_eu0{Pod EU0};
- pod_eu1{Pod EU1};
- db_gitlab_users[(gitlab_users Primary)];
- db_gitlab_routes[(gitlab_routes Primary)];
- db_gitlab_users_replica[(gitlab_users Replica)];
- db_gitlab_routes_replica[(gitlab_routes Replica)];
- db_pod_us0[(gitlab_main/gitlab_ci Pod US0)];
- db_pod_us1[(gitlab_main/gitlab_ci Pod US1)];
- db_pod_eu0[(gitlab_main/gitlab_ci Pod EU0)];
- db_pod_eu1[(gitlab_main/gitlab_ci Pod EU1)];
- user-->dns;
- dns-->router_us;
- dns-->router_eu;
- subgraph Europe
- router_eu-->pod_eu0;
- router_eu-->pod_eu1;
- pod_eu0-->db_pod_eu0;
- pod_eu0-->db_gitlab_users_replica;
- pod_eu0-->db_gitlab_routes_replica;
- pod_eu1-->db_gitlab_users_replica;
- pod_eu1-->db_gitlab_routes_replica;
- pod_eu1-->db_pod_eu1;
- end
- subgraph United States
- router_us-->pod_us0;
- router_us-->pod_us1;
- pod_us0-->db_pod_us0;
- pod_us0-->db_gitlab_users;
- pod_us0-->db_gitlab_routes;
- pod_us1-->db_gitlab_users;
- pod_us1-->db_gitlab_routes;
- pod_us1-->db_pod_us1;
- end
- router_eu-.->pod_us0;
- router_eu-.->pod_us1;
- router_us-.->pod_eu0;
- router_us-.->pod_eu1;
-```
-
-## Summary of changes
-
-1. Tables related to User data (including profile settings, authentication credentials, personal access tokens) are decomposed into a `gitlab_users` schema
-1. The `routes` table is decomposed into `gitlab_routes` schema
-1. The `application_settings` (and probably a few other instance level tables) are decomposed into `gitlab_admin` schema
-1. A new column `routes.pod_id` is added to `routes` table
-1. A new Router service exists to choose which pod to route a request to.
-1. If a router receives a new request it will send `/api/v4/pods/learn?method=GET&path_info=/group-org/project` to learn which Pod can process it
-1. A new concept will be introduced in GitLab called an organization
-1. We require all existing endpoints to be routable by URI, or be fixed to a specific Pod for processing. This requires changing ambiguous endpoints like `/dashboard` to be scoped like `/organizations/my-organization/-/dashboard`
-1. Endpoints like `/admin` would be routed always to the specific Pod, like `pod_0`
-1. Each Pod can respond to `/api/v4/pods/learn` and classify each endpoint
-1. Writes to `gitlab_users` and `gitlab_routes` are sent to a primary PostgreSQL server in our `US` region but reads can come from replicas in the same region. This will add latency for these writes but we expect they are infrequent relative to the rest of GitLab.
-
-## Pre-flight request learning
-
-While processing a request the URI will be decoded and a pre-flight request
-will be sent for each non-cached endpoint.
-
-When asking for the endpoint GitLab Rails will return information about
-the routable path. GitLab Rails will decode `path_info` and match it to
-an existing endpoint and find a routable entity (like project). The router will
-treat this as short-lived cache information.
-
-1. Prefix match: `/api/v4/pods/learn?method=GET&path_info=/gitlab-org/gitlab-test/-/issues`
-
- ```json
- {
- "path": "/gitlab-org/gitlab-test",
- "pod": "pod_0",
- "source": "routable"
- }
- ```
-
-1. Some endpoints might require an exact match: `/api/v4/pods/learn?method=GET&path_info=/-/profile`
-
- ```json
- {
- "path": "/-/profile",
- "pod": "pod_0",
- "source": "fixed",
- "exact": true
- }
- ```
-
-## Detailed explanation of default organization in the first iteration
-
-All users will get a new column `users.default_organization` which they can
-control in user settings. We will introduce a concept of the
-`GitLab.com Public` organization. This will be set as the default organization for all existing
-users. This organization will allow the user to see data from all namespaces in
-`Pod US0` (ie. our original GitLab.com instance). This behavior can be invisible to
-existing users such that they don't even get told when they are viewing a
-global page like `/dashboard` that it's even scoped to an organization.
-
-Any new users with a default organization other than `GitLab.com Public` will have
-a distinct user experience and will be fully aware that every page they load is
-only ever scoped to a single organization. These users can never
-load any global pages like `/dashboard` and will end up being redirected to
-`/organizations/<DEFAULT_ORGANIZATION>/-/dashboard`. This may also be the case
-for legacy APIs and such users may only ever be able to use APIs scoped to a
-organization.
-
-## Detailed explanation of Admin Area settings
-
-We believe that maintaining and synchronizing Admin Area settings will be
-frustrating and painful so to avoid this we will decompose and share all Admin Area
-settings in the `gitlab_admin` schema. This should be safe (similar to other
-shared schemas) because these receive very little write traffic.
-
-In cases where different pods need different settings (eg. the
-Elasticsearch URL), we will either decide to use a templated
-format in the relevant `application_settings` row which allows it to be dynamic
-per pod. Alternatively if that proves difficult we'll introduce a new table
-called `per_pod_application_settings` and this will have 1 row per pod to allow
-setting different settings per pod. It will still be part of the `gitlab_admin`
-schema and shared which will allow us to centrally manage it and simplify
-keeping settings in sync for all pods.
-
-## Pros
-
-1. Router is stateless and can live in many regions. We use Anycast DNS to resolve to nearest region for the user.
-1. Pods can receive requests for namespaces in the wrong pod and the user
- still gets the right response as well as caching at the router that
- ensures the next request is sent to the correct pod so the next request
- will go to the correct pod
-1. The majority of the code still lives in `gitlab` rails codebase. The Router doesn't actually need to understand how GitLab URLs are composed.
-1. Since the responsibility to read and write `gitlab_users`,
- `gitlab_routes` and `gitlab_admin` still lives in Rails it means minimal
- changes will be needed to the Rails application compared to extracting
- services that need to isolate the domain models and build new interfaces.
-1. Compared to a separate routing service this allows the Rails application
- to encode more complex rules around how to map URLs to the correct pod
- and may work for some existing API endpoints.
-1. All the new infrastructure (just a router) is optional and a single-pod
- self-managed installation does not even need to run the Router and there are
- no other new services.
-
-## Cons
-
-1. `gitlab_users`, `gitlab_routes` and `gitlab_admin` databases may need to be
- replicated across regions and writes need to go across regions. We need to
- do an analysis on write TPS for the relevant tables to determine if this is
- feasible.
-1. Sharing access to the database from many different Pods means that they are
- all coupled at the Postgres schema level and this means changes to the
- database schema need to be done carefully in sync with the deployment of all
- Pods. This limits us to ensure that Pods are kept in closely similar
- versions compared to an architecture with shared services that have an API
- we control.
-1. Although most data is stored in the right region there can be requests
- proxied from another region which may be an issue for certain types
- of compliance.
-1. Data in `gitlab_users` and `gitlab_routes` databases must be replicated in
- all regions which may be an issue for certain types of compliance.
-1. The router cache may need to be very large if we get a wide variety of URLs
- (ie. long tail). In such a case we may need to implement a 2nd level of
- caching in user cookies so their frequently accessed pages always go to the
- right pod the first time.
-1. Having shared database access for `gitlab_users` and `gitlab_routes`
- from multiple pods is an unusual architecture decision compared to
- extracting services that are called from multiple pods.
-1. It is very likely we won't be able to find cacheable elements of a
- GraphQL URL and often existing GraphQL endpoints are heavily dependent on
- ids that won't be in the `routes` table so pods won't necessarily know
- what pod has the data. As such we'll probably have to update our GraphQL
- calls to include an organization context in the path like
- `/api/organizations/<organization>/graphql`.
-1. This architecture implies that implemented endpoints can only access data
- that are readily accessible on a given Pod, but are unlikely
- to aggregate information from many Pods.
-1. All unknown routes are sent to the latest deployment which we assume to be `Pod US0`.
- This is required as newly added endpoints will be only decodable by latest pod.
- Likely this is not a problem for the `/pods/learn` is it is lightweight
- to process and this should not cause a performance impact.
-
-## Example database configuration
-
-Handling shared `gitlab_users`, `gitlab_routes` and `gitlab_admin` databases, while having dedicated `gitlab_main` and `gitlab_ci` databases should already be handled by the way we use `config/database.yml`. We should also, already be able to handle the dedicated EU replicas while having a single US primary for `gitlab_users` and `gitlab_routes`. Below is a snippet of part of the database configuration for the Pod architecture described above.
-
-**Pod US0**:
-
-```yaml
-# config/database.yml
-production:
- main:
- host: postgres-main.pod-us0.primary.consul
- load_balancing:
- discovery: postgres-main.pod-us0.replicas.consul
- ci:
- host: postgres-ci.pod-us0.primary.consul
- load_balancing:
- discovery: postgres-ci.pod-us0.replicas.consul
- users:
- host: postgres-users-primary.consul
- load_balancing:
- discovery: postgres-users-replicas.us.consul
- routes:
- host: postgres-routes-primary.consul
- load_balancing:
- discovery: postgres-routes-replicas.us.consul
- admin:
- host: postgres-admin-primary.consul
- load_balancing:
- discovery: postgres-admin-replicas.us.consul
-```
-
-**Pod EU0**:
-
-```yaml
-# config/database.yml
-production:
- main:
- host: postgres-main.pod-eu0.primary.consul
- load_balancing:
- discovery: postgres-main.pod-eu0.replicas.consul
- ci:
- host: postgres-ci.pod-eu0.primary.consul
- load_balancing:
- discovery: postgres-ci.pod-eu0.replicas.consul
- users:
- host: postgres-users-primary.consul
- load_balancing:
- discovery: postgres-users-replicas.eu.consul
- routes:
- host: postgres-routes-primary.consul
- load_balancing:
- discovery: postgres-routes-replicas.eu.consul
- admin:
- host: postgres-admin-primary.consul
- load_balancing:
- discovery: postgres-admin-replicas.eu.consul
-```
-
-## Request flows
-
-1. `gitlab-org` is a top level namespace and lives in `Pod US0` in the `GitLab.com Public` organization
-1. `my-company` is a top level namespace and lives in `Pod EU0` in the `my-organization` organization
-
-### Experience for paying user that is part of `my-organization`
-
-Such a user will have a default organization set to `/my-organization` and will be
-unable to load any global routes outside of this organization. They may load other
-projects/namespaces but their MR/Todo/Issue counts at the top of the page will
-not be correctly populated in the first iteration. The user will be aware of
-this limitation.
-
-#### Navigates to `/my-company/my-project` while logged in
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. They request `/my-company/my-project` without the router cache, so the router chooses randomly `Pod EU1`
-1. The `/pods/learn` is sent to `Pod EU1`, which responds that resource lives on `Pod EU0`
-1. `Pod EU0` returns the correct response
-1. The router now caches and remembers any request paths matching `/my-company/*` should go to `Pod EU0`
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- participant pod_eu1 as Pod EU1
- user->>router_eu: GET /my-company/my-project
- router_eu->>pod_eu1: /api/v4/pods/learn?method=GET&path_info=/my-company/my-project
- pod_eu1->>router_eu: {path: "/my-company", pod: "pod_eu0", source: "routable"}
- router_eu->>pod_eu0: GET /my-company/my-project
- pod_eu0->>user: <h1>My Project...
-```
-
-#### Navigates to `/my-company/my-project` while not logged in
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. The router does not have `/my-company/*` cached yet so it chooses randomly `Pod EU1`
-1. The `/pods/learn` is sent to `Pod EU1`, which responds that resource lives on `Pod EU0`
-1. `Pod EU0` redirects them through a login flow
-1. User requests `/users/sign_in`, uses random Pod to run `/pods/learn`
-1. The `Pod EU1` responds with `pod_0` as a fixed route
-1. User after login requests `/my-company/my-project` which is cached and stored in `Pod EU0`
-1. `Pod EU0` returns the correct response
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- participant pod_eu1 as Pod EU1
- user->>router_eu: GET /my-company/my-project
- router_eu->>pod_eu1: /api/v4/pods/learn?method=GET&path_info=/my-company/my-project
- pod_eu1->>router_eu: {path: "/my-company", pod: "pod_eu0", source: "routable"}
- router_eu->>pod_eu0: GET /my-company/my-project
- pod_eu0->>user: 302 /users/sign_in?redirect=/my-company/my-project
- user->>router_eu: GET /users/sign_in?redirect=/my-company/my-project
- router_eu->>pod_eu1: /api/v4/pods/learn?method=GET&path_info=/users/sign_in
- pod_eu1->>router_eu: {path: "/users", pod: "pod_eu0", source: "fixed"}
- router_eu->>pod_eu0: GET /users/sign_in?redirect=/my-company/my-project
- pod_eu0-->>user: <h1>Sign in...
- user->>router_eu: POST /users/sign_in?redirect=/my-company/my-project
- router_eu->>pod_eu0: POST /users/sign_in?redirect=/my-company/my-project
- pod_eu0->>user: 302 /my-company/my-project
- user->>router_eu: GET /my-company/my-project
- router_eu->>pod_eu0: GET /my-company/my-project
- router_eu->>pod_eu0: GET /my-company/my-project
- pod_eu0->>user: <h1>My Project...
-```
-
-#### Navigates to `/my-company/my-other-project` after last step
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. The router cache now has `/my-company/* => Pod EU0`, so the router chooses `Pod EU0`
-1. `Pod EU0` returns the correct response as well as the cache header again
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- participant pod_eu1 as Pod EU1
- user->>router_eu: GET /my-company/my-project
- router_eu->>pod_eu0: GET /my-company/my-project
- pod_eu0->>user: <h1>My Project...
-```
-
-#### Navigates to `/gitlab-org/gitlab` after last step
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. The router has no cached value for this URL so randomly chooses `Pod EU0`
-1. `Pod EU0` redirects the router to `Pod US0`
-1. `Pod US0` returns the correct response as well as the cache header again
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- participant pod_us0 as Pod US0
- user->>router_eu: GET /gitlab-org/gitlab
- router_eu->>pod_eu0: /api/v4/pods/learn?method=GET&path_info=/gitlab-org/gitlab
- pod_eu0->>router_eu: {path: "/gitlab-org", pod: "pod_us0", source: "routable"}
- router_eu->>pod_us0: GET /gitlab-org/gitlab
- pod_us0->>user: <h1>GitLab.org...
-```
-
-In this case the user is not on their "default organization" so their TODO
-counter will not include their normal todos. We may choose to highlight this in
-the UI somewhere. A future iteration may be able to fetch that for them from
-their default organization.
-
-#### Navigates to `/`
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. Router does not have a cache for `/` route (specifically rails never tells it to cache this route)
-1. The Router choose `Pod EU0` randomly
-1. The Rails application knows the users default organization is `/my-organization`, so
- it redirects the user to `/organizations/my-organization/-/dashboard`
-1. The Router has a cached value for `/organizations/my-organization/*` so it then sends the
- request to `POD EU0`
-1. `Pod EU0` serves up a new page `/organizations/my-organization/-/dashboard` which is the same
- dashboard view we have today but scoped to an organization clearly in the UI
-1. The user is (optionally) presented with a message saying that data on this page is only
- from their default organization and that they can change their default
- organization if it's not right.
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_eu0 as Pod EU0
- user->>router_eu: GET /
- router_eu->>pod_eu0: GET /
- pod_eu0->>user: 302 /organizations/my-organization/-/dashboard
- user->>router: GET /organizations/my-organization/-/dashboard
- router->>pod_eu0: GET /organizations/my-organization/-/dashboard
- pod_eu0->>user: <h1>My Company Dashboard... X-Gitlab-Pod-Cache={path_prefix:/organizations/my-organization/}
-```
-
-#### Navigates to `/dashboard`
-
-As above, they will end up on `/organizations/my-organization/-/dashboard` as
-the rails application will already redirect `/` to the dashboard page.
-
-### Navigates to `/not-my-company/not-my-project` while logged in (but they don't have access since this project/group is private)
-
-1. User is in Europe so DNS resolves to the router in Europe
-1. The router knows that `/not-my-company` lives in `Pod US1` so sends the request to this
-1. The user does not have access so `Pod US1` returns 404
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_eu as Router EU
- participant pod_us1 as Pod US1
- user->>router_eu: GET /not-my-company/not-my-project
- router_eu->>pod_us1: GET /not-my-company/not-my-project
- pod_us1->>user: 404
-```
-
-#### Creates a new top level namespace
-
-The user will be asked which organization they want the namespace to belong to.
-If they select `my-organization` then it will end up on the same pod as all
-other namespaces in `my-organization`. If they select nothing we default to
-`GitLab.com Public` and it is clear to the user that this is isolated from
-their existing organization such that they won't be able to see data from both
-on a single page.
-
-### Experience for GitLab team member that is part of `/gitlab-org`
-
-Such a user is considered a legacy user and has their default organization set to
-`GitLab.com Public`. This is a "meta" organization that does not really exist but
-the Rails application knows to interpret this organization to mean that they are
-allowed to use legacy global functionality like `/dashboard` to see data across
-namespaces located on `Pod US0`. The rails backend also knows that the default pod to render any ambiguous
-routes like `/dashboard` is `Pod US0`. Lastly the user will be allowed to
-navigate to organizations on another pod like `/my-organization` but when they do the
-user will see a message indicating that some data may be missing (eg. the
-MRs/Issues/Todos) counts.
-
-#### Navigates to `/gitlab-org/gitlab` while not logged in
-
-1. User is in the US so DNS resolves to the US router
-1. The router knows that `/gitlab-org` lives in `Pod US0` so sends the request
- to this pod
-1. `Pod US0` serves up the response
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_us as Router US
- participant pod_us0 as Pod US0
- user->>router_us: GET /gitlab-org/gitlab
- router_us->>pod_us0: GET /gitlab-org/gitlab
- pod_us0->>user: <h1>GitLab.org...
-```
-
-#### Navigates to `/`
-
-1. User is in US so DNS resolves to the router in US
-1. Router does not have a cache for `/` route (specifically rails never tells it to cache this route)
-1. The Router chooses `Pod US1` randomly
-1. The Rails application knows the users default organization is `GitLab.com Public`, so
- it redirects the user to `/dashboards` (only legacy users can see
- `/dashboard` global view)
-1. Router does not have a cache for `/dashboard` route (specifically rails never tells it to cache this route)
-1. The Router chooses `Pod US1` randomly
-1. The Rails application knows the users default organization is `GitLab.com Public`, so
- it allows the user to load `/dashboards` (only legacy users can see
- `/dashboard` global view) and redirects to router the legacy pod which is `Pod US0`
-1. `Pod US0` serves up the global view dashboard page `/dashboard` which is the same
- dashboard view we have today
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant router_us as Router US
- participant pod_us0 as Pod US0
- participant pod_us1 as Pod US1
- user->>router_us: GET /
- router_us->>pod_us1: GET /
- pod_us1->>user: 302 /dashboard
- user->>router_us: GET /dashboard
- router_us->>pod_us1: /api/v4/pods/learn?method=GET&path_info=/dashboard
- pod_us1->>router_us: {path: "/dashboard", pod: "pod_us0", source: "routable"}
- router_us->>pod_us0: GET /dashboard
- pod_us0->>user: <h1>Dashboard...
-```
-
-#### Navigates to `/my-company/my-other-project` while logged in (but they don't have access since this project is private)
-
-They get a 404.
-
-### Experience for non-authenticated users
-
-Flow is similar to logged in users except global routes like `/dashboard` will
-redirect to the login page as there is no default organization to choose from.
-
-### A new customers signs up
-
-They will be asked if they are already part of an organization or if they'd
-like to create one. If they choose neither they end up no the default
-`GitLab.com Public` organization.
-
-### An organization is moved from 1 pod to another
-
-TODO
-
-### GraphQL/API requests which don't include the namespace in the URL
-
-TODO
-
-### The autocomplete suggestion functionality in the search bar which remembers recent issues/MRs
-
-TODO
-
-### Global search
-
-TODO
-
-## Administrator
-
-### Loads `/admin` page
-
-1. The `/admin` is locked to `Pod US0`
-1. Some endpoints of `/admin`, like Projects in Admin are scoped to a Pod
- and users needs to choose the correct one in a dropdown, which results in endpoint
- like `/admin/pods/pod_0/projects`.
-
-Admin Area settings in Postgres are all shared across all pods to avoid
-divergence but we still make it clear in the URL and UI which pod is serving
-the Admin Area page as there is dynamic data being generated from these pages and
-the operator may want to view a specific pod.
-
-## More Technical Problems To Solve
-
-### Replicating User Sessions Between All Pods
-
-Today user sessions live in Redis but each pod will have their own Redis instance. We already use a dedicated Redis instance for sessions so we could consider sharing this with all pods like we do with `gitlab_users` PostgreSQL database. But an important consideration will be latency as we would still want to mostly fetch sessions from the same region.
-
-An alternative might be that user sessions get moved to a JWT payload that encodes all the session data but this has downsides. For example, it is difficult to expire a user session, when their password changes or for other reasons, if the session lives in a JWT controlled by the user.
-
-### How do we migrate between Pods
-
-Migrating data between pods will need to factor all data stores:
-
-1. PostgreSQL
-1. Redis Shared State
-1. Gitaly
-1. Elasticsearch
-
-### Is it still possible to leak the existence of private groups via a timing attack?
-
-If you have router in EU, and you know that EU router by default redirects
-to EU located Pods, you know their latency (lets assume 10 ms). Now, if your
-request is bounced back and redirected to US which has different latency
-(lets assume that roundtrip will be around 60 ms) you can deduce that 404 was
-returned by US Pod and know that your 404 is in fact 403.
-
-We may defer this until we actually implement a pod in a different region. Such timing attacks are already theoretically possible with the way we do permission checks today but the timing difference is probably too small to be able to detect.
-
-One technique to mitigate this risk might be to have the router add a random
-delay to any request that returns 404 from a pod.
-
-## Should runners be shared across all pods?
-
-We have 2 options and we should decide which is easier:
-
-1. Decompose runner registration and queuing tables and share them across all
- pods. This may have implications for scalability, and we'd need to consider
- if this would include group/project runners as this may have scalability
- concerns as these are high traffic tables that would need to be shared.
-1. Runners are registered per-pod and, we probably have a separate fleet of
- runners for every pod or just register the same runners to many pods which
- may have implications for queueing
-
-## How do we guarantee unique ids across all pods for things that cannot conflict?
-
-This project assumes at least namespaces and projects have unique ids across
-all pods as many requests need to be routed based on their ID. Since those
-tables are across different databases then guaranteeing a unique ID will
-require a new solution. There are likely other tables where unique IDs are
-necessary and depending on how we resolve routing for GraphQL and other APIs
-and other design goals it may be determined that we want the primary key to be
-unique for all tables.
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/architecture/blueprints/rate_limiting/index.md b/doc/architecture/blueprints/rate_limiting/index.md
index b466a54e922..92364040962 100644
--- a/doc/architecture/blueprints/rate_limiting/index.md
+++ b/doc/architecture/blueprints/rate_limiting/index.md
@@ -375,7 +375,7 @@ hierarchy. Choosing a proper solution will require a thoughtful research.
- Implementing a separate Go library which uses the same backend (for example, Redis) for rate limiting.
1. **SDK for Satellite Services (Owning Team)**
- - Build Golang SDK.
+ - Build Go SDK.
- Create examples showcasing usage of the new rate limits SDK.
1. **Team fan out for Satellite Services (Stage Groups)**
diff --git a/doc/architecture/blueprints/runner_tokens/index.md b/doc/architecture/blueprints/runner_tokens/index.md
index 69a10674d7d..359eadb18c5 100644
--- a/doc/architecture/blueprints/runner_tokens/index.md
+++ b/doc/architecture/blueprints/runner_tokens/index.md
@@ -183,14 +183,17 @@ CREATE TABLE ci_runners (
)
```
-The `ci_builds_metadata` table shall reference `ci_runner_machines`.
+A new `p_ci_runner_machine_builds` table joins the `ci_runner_machines` and `ci_builds` tables, to avoid
+adding more pressure to those tables.
We might consider a more efficient way to store `contacted_at` than updating the existing record.
```sql
-CREATE TABLE ci_builds_metadata (
- ...
+CREATE TABLE p_ci_runner_machine_builds (
+ partition_id bigint DEFAULT 100 NOT NULL,
+ build_id bigint NOT NULL,
runner_machine_id bigint NOT NULL
-);
+)
+PARTITION BY LIST (partition_id);
CREATE TABLE ci_runner_machines (
id bigint NOT NULL,
@@ -370,44 +373,53 @@ scope.
| GitLab Rails app | `%15.8` | Create database migration to add `config` column to `ci_runner_machines` table. |
| GitLab Runner | `%15.9` | Start sending `system_id` value in `POST /jobs/request` request and other follow-up requests that require identifying the unique system. |
| GitLab Rails app | `%15.9` | Create service similar to `StaleGroupRunnersPruneCronWorker` service to clean up `ci_runner_machines` records instead of `ci_runners` records.<br/>Existing service continues to exist but focuses only on legacy runners. |
-| GitLab Rails app | `%15.9` | [Feature flag] Rollout of `create_runner_machine`. |
+| GitLab Rails app | `%15.9` | Implement the `create_runner_machine` [feature flag](../../../administration/feature_flags.md). |
| GitLab Rails app | `%15.9` | Create `ci_runner_machines` record in `POST /runners/verify` request if the runner token is prefixed with `glrt-`. |
| GitLab Rails app | `%15.9` | Use runner token + `system_id` JSON parameters in `POST /jobs/request` request in the [heartbeat request](https://gitlab.com/gitlab-org/gitlab/blob/c73c96a8ffd515295842d72a3635a8ae873d688c/lib/api/ci/helpers/runner.rb#L14-20) to update the `ci_runner_machines` cache/table. |
-| GitLab Rails app | `%15.9` | [Feature flag] Enable runner creation workflow (`create_runner_workflow`). |
+| GitLab Rails app | `%15.9` | Implement the `create_runner_workflow_for_admin` [feature flag](../../../administration/feature_flags.md). |
| GitLab Rails app | `%15.9` | Implement `create_{instance|group|project}_runner` permissions. |
| GitLab Rails app | `%15.9` | Rename `ci_runner_machines.machine_xid` column to `system_xid` to be consistent with `system_id` passed in APIs. |
-| GitLab Rails app | `%15.10` | Drop `ci_runner_machines.machine_xid` column. |
-| GitLab Rails app | `%15.11` | Remove the ignore rule for `ci_runner_machines.machine_xid` column. |
+| GitLab Rails app | `%15.10` | Remove the ignore rule for `ci_runner_machines.machine_xid` column. |
+| GitLab Rails app | `%15.10` | Replace `ci_builds_metadata.runner_machine_id` with a new join table. |
+| GitLab Rails app | `%15.11` | Drop `ci_builds_metadata.runner_machine_id` column. |
+| GitLab Rails app | `%16.0` | Remove the ignore rule for `ci_builds_metadata.runner_machine_id` column. |
### Stage 4 - Create runners from the UI
| Component | Milestone | Changes |
|------------------|----------:|---------|
-| GitLab Rails app | `%15.9` | Implement new GraphQL user-authenticated API to create a new runner. |
| GitLab Rails app | `%15.9` | [Add prefix to newly generated runner authentication tokens](https://gitlab.com/gitlab-org/gitlab/-/issues/383198). |
+| GitLab Rails app | `%15.9` | Add new runner field for with token that is used in registration |
+| GitLab Rails app | `%15.9` | Implement new GraphQL user-authenticated API to create a new runner. |
| GitLab Rails app | `%15.10` | Return token and runner ID information from `/runners/verify` REST endpoint. |
| GitLab Runner | `%15.10` | [Modify register command to allow new flow with glrt- prefixed authentication tokens](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/29613). |
-| GitLab Rails app | `%15.10` | Implement UI to create new runner. |
-| GitLab Rails app | `%15.10` | GraphQL changes to `CiRunner` type. |
-| GitLab Rails app | `%15.10` | UI changes to runner details view (listing of platform, architecture, IP address, etc.) (?) |
+| GitLab Runner | `%15.10` | Make the `gitlab-runner register` command happen in a single operation. |
+| GitLab Rails app | `%15.10` | Define feature flag and policies for "New Runner creation workflow" for groups and projects. |
+| GitLab Rails app | `%15.10` | Only update runner `contacted_at` and `status` when polled for jobs. |
+| GitLab Rails app | `%15.10` | Add GraphQL type to represent runner machines under `CiRunner`. |
+| GitLab Rails app | `%15.10` | Implement UI to create new instance runner. |
+| GitLab Rails app | `%15.11` | Update service and mutation to accept groups and projects. |
+| GitLab Rails app | `%15.11` | Implement UI to create new group/project runners. |
+| GitLab Rails app | `%15.11` | GraphQL changes to `CiRunner` type. (?) |
+| GitLab Rails app | `%15.11` | UI changes to runner details view (listing of platform, architecture, IP address, etc.) (?) |
| GitLab Rails app | `%15.11` | Adapt `POST /api/v4/runners` REST endpoint to accept a request from an authorized user with a scope instead of a registration token. |
+| GitLab Runner | `%15.11` | Handle glrt- runner tokens in `unregister` command. |
### Stage 5 - Optional disabling of registration token
| Component | Milestone | Changes |
|------------------|----------:|---------|
-| GitLab Rails app | `%15.11` | Adapt `register_{group|project}_runner` permissions to take [application setting](https://gitlab.com/gitlab-org/gitlab/-/issues/386712) in consideration. |
-| GitLab Rails app | `%15.11` | Add UI to allow disabling use of registration tokens at project or group level. |
-| GitLab Rails app | `%15.11` | Introduce `:enforce_create_runner_workflow` feature flag (disabled by default) to control whether use of registration tokens is allowed. |
-| GitLab Rails app | `%15.11` | Make [`POST /api/v4/runners` endpoint](../../../api/runners.md#register-a-new-runner) permanently return `HTTP 410 Gone` if either `allow_runner_registration_token` setting or `:enforce_create_runner_workflow` feature flag disables registration tokens.<br/>A future v5 version of the API should return `HTTP 404 Not Found`. |
-| GitLab Rails app | `%15.11` | Start refusing job requests that don't include a unique ID, if either `allow_runner_registration_token` setting or `:enforce_create_runner_workflow` feature flag disables registration tokens. |
-| GitLab Rails app | `%15.11` | Hide legacy UI showing registration with a registration token, if `:enforce_create_runner_workflow` feature flag disables registration tokens. |
+| GitLab Rails app | | Adapt `register_{group|project}_runner` permissions to take [application setting](https://gitlab.com/gitlab-org/gitlab/-/issues/386712) in consideration. |
+| GitLab Rails app | | Add UI to allow disabling use of registration tokens at project or group level. |
+| GitLab Rails app | | Introduce `:enforce_create_runner_workflow` feature flag (disabled by default) to control whether use of registration tokens is allowed. |
+| GitLab Rails app | | Make [`POST /api/v4/runners` endpoint](../../../api/runners.md#register-a-new-runner) permanently return `HTTP 410 Gone` if either `allow_runner_registration_token` setting or `:enforce_create_runner_workflow` feature flag disables registration tokens.<br/>A future v5 version of the API should return `HTTP 404 Not Found`. |
+| GitLab Rails app | | Start refusing job requests that don't include a unique ID, if either `allow_runner_registration_token` setting or `:enforce_create_runner_workflow` feature flag disables registration tokens. |
+| GitLab Rails app | | Hide legacy UI showing registration with a registration token, if `:enforce_create_runner_workflow` feature flag disables registration tokens. |
### Stage 6 - Enforcement
| Component | Milestone | Changes |
|------------------|----------:|---------|
-| GitLab Runner | `%16.0` | Do not allow runner to start if `.runner_system_id` file cannot be written. |
| GitLab Rails app | `%16.6` | Enable `:enforce_create_runner_workflow` feature flag by default. |
| GitLab Rails app | `%16.6` | Start reject job requests that don't include `system_id` value. |
@@ -495,7 +507,7 @@ gitlab-runner register
--executor "shell" \
--url "https://gitlab.com/" \
--non-interactive \
- --registration-token="grlt-2CR8_eVxiioB1QmzPZwa"
+ --registration-token="glrt-2CR8_eVxiioB1QmzPZwa"
```
### How does this change impact auto-scaling scenarios?
diff --git a/doc/architecture/blueprints/search/code_search_with_zoekt.md b/doc/architecture/blueprints/search/code_search_with_zoekt.md
deleted file mode 100644
index d0d347f1ff4..00000000000
--- a/doc/architecture/blueprints/search/code_search_with_zoekt.md
+++ /dev/null
@@ -1,305 +0,0 @@
----
-status: ongoing
-creation-date: "2022-12-28"
-authors: [ "@dgruzd", "@DylanGriffith" ]
-coach: "@DylanGriffith"
-approvers: [ "@joshlambert", "@changzhengliu" ]
-owning-stage: "~devops::enablement"
-participating-stages: []
----
-
-# Use Zoekt For code search
-
-## Summary
-
-We will be implementing an additional code search functionality in GitLab that
-is backed by [Zoekt](https://github.com/sourcegraph/zoekt), an open source
-search engine that is specifically designed for code search. Zoekt will be used as
-an API by GitLab and remain an implementation detail while the user interface
-in GitLab will not change much except for some new features made available by
-Zoekt.
-
-This will be rolled out in phases to ensure that the system will actually meet
-our scaling and cost expectations and will run alongside code search backed by
-Elasticsearch until we can be sure it is a viable replacement. The first step
-will be making it available for `gitlab-org` for internal and expanding
-customer by customer based on customer interest.
-
-## Motivation
-
-GitLab code search functionality today is backed by Elasticsearch.
-Elasticsearch has proven useful for other types of search (issues, merge
-requests, comments and so-on) but is by design not a good choice for code
-search where users expect matches to be precise (ie. no false positives) and
-flexible (e.g. support
-[substring matching](https://gitlab.com/gitlab-org/gitlab/-/issues/325234)
-and
-[regexes](https://gitlab.com/gitlab-org/gitlab/-/issues/4175)). We have
-[investigated our options](https://gitlab.com/groups/gitlab-org/-/epics/7404)
-and [Zoekt](https://github.com/sourcegraph/zoekt) is pretty much the only well
-maintained open source technology that is suited to code search. Based on our
-research we believe it will be better to adopt a well maintained open source
-database than attempt to build our own. This is mostly due to the fact that our
-research indicates that the fundamental architecture of Zoekt is what we would
-implement again if we tried to implement something ourselves.
-
-Our
-[early benchmarking](https://gitlab.com/gitlab-org/gitlab/-/issues/370832#note_1183611955)
-suggests that Zoekt will be viable at our scale, but we feel strongly
-that investing in building a beta integration with Zoekt and rolling it out
-group by group on GitLab.com will provide better insights into scalability and
-cost than more accurate benchmarking efforts. It will also be relatively low
-risk as it will be rolled out internally first and later rolled out to
-customers that wish to participate in the trial.
-
-### Goals
-
-The main goals of this integration will be to implement the following highly
-requested improvements to code search:
-
-1. [Exact match (substring match) code searches in Advanced Search](https://gitlab.com/gitlab-org/gitlab/-/issues/325234)
-1. [Support regular expressions with Advanced Global Search](https://gitlab.com/gitlab-org/gitlab/-/issues/4175)
-1. [Support multiple line matches in the same file](https://gitlab.com/gitlab-org/gitlab/-/issues/668)
-
-The initial phases of the rollout will be designed to catch and resolve scaling
-or infrastructure cost issues as early as possible so that we can pivot early
-before investing too much in this technology if it is not suitable.
-
-### Non-Goals
-
-The following are not goals initially but could theoretically be built upon
-this solution:
-
-1. Improving security scanning features by having access to quickly perform
- regex scans across many repositories
-1. Saving money on our search infrastructure - this may be possible with
- further optimizations, but initial estimates suggest the cost is similar
-1. AI/ML features of search used to predict what users might be interested in
- finding
-1. Code Intelligence and Navigation - likely code intelligence and navigation
- features should be built on structured data rather than a trigram index but
- regex based searches (using Zoekt) may be a suitable fallback for code which
- does not have structured metadata enabled or dynamic languages where static
- analysis is not very accurate. Zoekt in particular may not be well suited
- initially, despite existing symbol extraction using ctags, because ctags
- symbols may not contain enough data for accurate navigation and Zoekt
- doesn't undersand dependencies which would be necessary for cross-project
- navigation.
-
-## Proposal
-
-An
-[initial implementation of a Zoekt integration](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105049)
-was created to demonstrate the feasibility of using Zoekt as a drop-in
-replacement for Elasticsearch code searches. This blueprint will extend on all
-the details needed to provide a minimum viable change as well steps needed to
-scale this to a larger customer rollout on GitLab.com.
-
-## Design and implementation details
-
-### User Experience
-
-When a user performs an advanced search on a group or project that is part
-of the Zoekt rollout we will present a toggle somewhere in the UI to change
-to "precise search" (or some other UX TBD) which switches them from
-Elasticsearch to Zoekt. Early user feedback will help us assess the best way
-to present these choices to users and ultimately we will want to remove the
-Elasticsearch option if we find Zoekt is a suitable long term option.
-
-### Indexing
-
-Similar to our Elasticsearch integration, GitLab will notify Zoekt every time
-there are updates to a repository. Zoekt, unlike Elasticsearch, is designed to
-clone and index Git repositories so we will simply notify Zoekt of the URL of
-the repository that has changed and it will update its local copy of the Git
-repo and then update its local index files. The Zoekt side of this logic will
-be implemented in a new server-side indexing endpoint we add to Zoekt which is
-currently in
-[an open Pull request](https://github.com/sourcegraph/zoekt/pull/496).
-While the details of
-this pull request are still being debated, we may choose to deploy a fork with
-the functionality we need, but our strongest intention is not to maintain a
-fork of Zoekt and the maintainers have already expressed they are open to this
-new functionality.
-
-The rails side of the integration will be a Sidekiq worker that is scheduled
-every time there is an update to a repository and it will simply call this
-`/index` endpoint in Zoekt. This will also need to generate a one-time token
-that can allow Zoekt to clone a private repository.
-
-```mermaid
-sequenceDiagram
- participant user as User
- participant gitlab_git as GitLab Git
- participant gitlab_sidekiq as GitLab Sidekiq
- participant zoekt as Zoekt
- user->>gitlab_git: git push git@gitlab.com:gitlab-org/gitlab.git
- gitlab_git->>gitlab_sidekiq: ZoektIndexerWorker.perform_async(278964)
- gitlab_sidekiq->>zoekt: POST /index {"RepoUrl":"https://zoekt:SECRET_TOKEN@gitlab.com/gitlab-org/gitlab.git","RepoId":278964}'
- zoekt->>gitlab_git: git clone https://zoekt:SECRET_TOKEN@gitlab.com/gitlab-org/gitlab.git
-```
-
-The Sidekiq worker can leverage de-duplication based on the `project_id`.
-
-Zoekt supports indexing multiple projects we'll likely need to, eventually,
-allow a way for users to configure additional branches (beyond the default
-branch) and this will need to be sent to Zoekt. We will need to decide if these
-branch lists are sent every time we index the project or only when they change
-configuration.
-
-There may be race conditions with multiple Zoekt processes indexing the same
-repo at the same time. For this reason we should implement a locking mechanism
-somewhere to ensure we are only indexing 1 project in 1 place at a time. We
-could make use of the same Redis locking we use for indexing projects in
-Elasticsearch.
-
-### Searching
-
-Searching will be implemented using the `/api/search` functionality in
-Zoekt. There is also
-[an open PR to fix this endpoint in Zoekt](https://github.com/sourcegraph/zoekt/pull/506),
-and again we may consider working from a fork until this is fixed. GitLab will
-prepend all searches with the appropriate filter for repositories based on the
-user's search context (group or project) in the same way we do for
-Elasticsearch. For Zoekt this will be implemented as a query string regex that
-matches all the searched repositories.
-
-### Zoekt infrastructure
-
-Each Zoekt node will need to run a
-[zoekt-dynamic-indexserver](https://github.com/sourcegraph/zoekt/pull/496) and
-a
-[zoekt-webserver](https://github.com/sourcegraph/zoekt/blob/main/cmd/zoekt-webserver/main.go).
-These are both webservers with different responsibilities. Considering that the
-Zoekt indexing process needs to keep a full clone of the bare repo
-([unless we come up with a better option](https://gitlab.com/gitlab-org/gitlab/-/issues/384722))
-these bare repos will be stored on spinning disks to save space. These are only
-used as an intermediate step to generate the actual `.zoekt` index files which
-will be stored on an SSD for fast searches. These web servers need to run on
-the same node as they access the same files. The `zoekt-dynamic-indexserver` is
-responsible for writing the `.zoekt` index files. The `zoekt-webserver` is
-responsible for responding to searches that it performs by reading these
-`.zoekt` index files.
-
-### Rollout strategy
-
-Initially Zoekt code search will only be available to `gitlab-org`. After that
-we'll start rolling it out to specific customers that have requested better
-code search experience. As we learn about scaling and make improvements we will
-gradually roll it out to all licensed groups on GitLab.com. We will use a
-similar approach to Elasticsearch for keeping track of which groups are indexed
-and which are not. This will be based on a new table `zoekt_indexed_namespaces`
-with a `namespace_id` reference. We will only allow rolling out to top level
-namespaces to simplify the logic of checking for all layers of group
-inheritance. Once we've rolled out to all licensed groups we'll enable logic to
-automatically enroll newly licensed groups. This table also may be a place to
-store per-namespace sharding and replication data as described below.
-
-### Sharding and replication strategy
-
-Zoekt does not have any inbuilt sharding, and we expect that we'll need
-multiple Zoekt servers to reach the scale to provide search functionality to
-all of GitLab licensed customers.
-
-There are 2 clear ways to implement sharding:
-
-1. Build it on top of, or in front of Zoekt, as an independent component. Building
- all the complexities of a distributed database into Zoekt is not likely to
- be a good direction for the project so most likely this would be an
- independent piece of infrastructure that proxied requests to the correct
- shard.
-1. Manage the shards inside GitLab. This would be an application layer in
- GitLab which chooses the correct shard to send indexing and search requests
- to.
-
-Likewise, there are a few ways to implement replication:
-
-1. Server-side where Zoekt replicas are aware of other Zoekt replicas and they
- stream updates from some primary to remain in sync
-1. Client-side replication where clients send indexing requests to all replicas
- and search requests to any replica
-
-We plan to implement sharding inside GitLab application but replication may be
-best served at the level of the filesystem of Zoekt servers rather than sending
-duplicated updates from GitLab to all replicas. This could be some process on
-Zoekt servers that monitors for changes to the `.zoekt` files in a specific
-directory and syncs those updates to the replicas. This will need to be
-slightly more sophisticated than `rsync` because the files are constantly
-changing and files may be getting deleted while the sync is happening so we
-would want to be syncing the updates in batches somehow without slowing down
-indexing.
-
-Implementing sharding in GitLab simplifies the additional infrastructure
-components that need to be deployed and allows more flexibility to control our
-rollout to many customers alongside our rollout of multiple shards.
-
-Implementing syncing from primary -> replica on Zoekt nodes at the filesystem
-level optimizes that overall resource usage. We only need to sync the index
-files to replicas as the bare repo is just a cache. This saves on:
-
-1. Disk space on replicas
-1. CPU usage on replicas as it does not need to rebuild the index
-1. Load on Gitaly to clone the repos
-
-We plan to defer the implementation of these high availability aspects until
-later, but a preliminary plan would be:
-
-1. GitLab is configured with a pool of Zoekt servers
-1. GitLab assigns groups randomly a Zoekt primary server
-1. There will also be Zoekt replica servers
-1. Periodically Zoekt primary servers will sync their `.zoekt` index files to
- their respective replicas
-1. There will need to be some process by which to promote a replica to a
- primary if the primary is having issues. We will be using Consul for
- keeping track of which is the primary and which are the replicas.
-1. When indexing a project GitLab will queue a Sidekiq job to update the index
- on the primary
-1. When searching we will randomly select one of the Zoekt primaries or replica
- servers for the group being searched. We don't care which is "more up to
- date" as code search will be "eventually consistent" and all reads may read
- slightly out of date indexes. We will have a target of maximum latency of
- index updates and may consider removing nodes from rotation if they are too
- far out of date.
-1. We will shard everything by top level group as this ensures group search can
- always search a single Zoekt server. Aggregation may be possible for global
- searches at some point in future if this turns out to be important. Smaller
- self-managed instances may use a single Zoekt server allowing global
- searches to work without any aggregation being implemented. Depending on our
- largest group sizes and scaling limitations of a single node Zoekt server we
- may consider implementing an approach where a group can be assigned multiple
- shards.
-
-The downside of the chosen path will be added complexity of managing all these
-Zoekt servers from GitLab when compared with a "proxy" layer outside of GitLab
-that is managing all of these shards. We will consider this decision a work in
-progress and reassess if it turns out to add too much complexity to GitLab.
-
-#### Sharding proposal using GitLab `::Zoekt::Shard` model
-
-This is already implemented as the `::Zoekt::IndexedNamespace`
-implements a many-to-many relationship between namespaces and shards.
-
-#### Replication and service discovery using Consul
-
-If we plan to replicate at the Zoekt node level as described above we need to
-change our data model to use a one-to-many relationship from `zoekt_shards ->
-namespaces`. This means making the `namespace_id` column unique in
-`zoekt_indexed_namespaces`. Then we need to implement a service discovery
-approach where the `index_url` always points at a primary Zoekt node and the
-`search_url` is a DNS record with N replicas and the primary. We then choose
-randomly from `search_url` records when searching.
-
-### Iterations
-
-1. Make available for `gitlab-org`
-1. Improve monitoring
-1. Improve performance
-1. Make available for select customers
-1. Implement sharding
-1. Implement replication
-1. Make available to many more licensed groups
-1. Implement automatic (re)balancing of shards
-1. Estimate costs for rolling out to all licensed groups and decide if it's worth it or if we need to optimize further or adjust our plan
-1. Rollout to all licensed groups
-1. Improve performance
-1. Assess costs and decide whether we should roll out to all free customers
diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md
index 1aa579b842a..d7c5b089116 100644
--- a/doc/ci/caching/index.md
+++ b/doc/ci/caching/index.md
@@ -139,13 +139,14 @@ You can override cache settings without overwriting the global cache by using
`policy` for one job:
```yaml
-cache: &global_cache
- key: $CI_COMMIT_REF_SLUG
- paths:
- - node_modules/
- - public/
- - vendor/
- policy: pull-push
+default:
+ cache: &global_cache
+ key: $CI_COMMIT_REF_SLUG
+ paths:
+ - node_modules/
+ - public/
+ - vendor/
+ policy: pull-push
job:
cache:
@@ -570,7 +571,7 @@ You can clear the cache in the GitLab UI:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **CI/CD > Pipelines**.
-1. In the upper right, select **Clear runner caches**.
+1. In the upper-right corner, select **Clear runner caches**.
On the next commit, your CI/CD jobs use a new cache.
diff --git a/doc/ci/chatops/img/gitlab-chatops-icon-small.png b/doc/ci/chatops/img/gitlab-chatops-icon-small.png
deleted file mode 100644
index 71cc5dba5cf..00000000000
--- a/doc/ci/chatops/img/gitlab-chatops-icon-small.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/chatops/index.md b/doc/ci/chatops/index.md
index f0efb5fc884..bb3c8d537f3 100644
--- a/doc/ci/chatops/index.md
+++ b/doc/ci/chatops/index.md
@@ -9,62 +9,70 @@ type: index, concepts, howto
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4466) in GitLab Ultimate 10.6.
> - [Moved](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24780) to GitLab Free in 11.9.
-> - `CHAT_USER_ID` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/341798) in GitLab 14.4.
+> - `CHAT_USER_ID` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/341798) in GitLab 14.4.
-GitLab ChatOps provides a method to interact with CI/CD jobs through chat services
-like Slack. Many organizations' discussion, collaboration, and troubleshooting takes
-place in chat services. Having a method to run CI/CD jobs with output
-posted back to the channel can significantly augment your team's workflow.
+Use GitLab ChatOps to interact with CI/CD jobs through chat services
+like Slack.
-## How GitLab ChatOps works
+Many organizations use chat services to collaborate, troubleshoot, and plan work. With ChatOps,
+you can discuss work with your team, run CI/CD jobs, and view job output, all from the same
+application.
-GitLab ChatOps is built upon [GitLab CI/CD](../index.md) and
-[Slack Slash Commands](../../user/project/integrations/slack_slash_commands.md).
-ChatOps provides a `run` action for [slash commands](../../integration/slash_commands.md)
-with the following arguments:
+## ChatOps workflow and CI/CD configuration
-- A `<job name>` to execute.
-- The `<job arguments>`.
+ChatOps looks for the specified job in the
+[`.gitlab-ci.yml`](../yaml/index.md) on the project's default
+branch. If the job is found, ChatOps creates a pipeline that contains
+only the specified job. If you set `when: manual`, ChatOps creates the
+pipeline, but the job doesn't start automatically.
+
+A job run with ChatOps has the same functionality as a job run from
+GitLab. The job can use existing [CI/CD variables](../variables/index.md#predefined-cicd-variables) like
+`GITLAB_USER_ID` to perform additional rights validation, but these
+variables can be [overridden](../variables/index.md#cicd-variable-precedence).
+
+You should set [`rules`](../yaml/index.md#rules) so the job does not
+run as part of the standard CI/CD pipeline.
ChatOps passes the following [CI/CD variables](../variables/index.md#predefined-cicd-variables)
to the job:
-- `CHAT_INPUT` contains any additional arguments.
-- `CHAT_CHANNEL` is set to the name of channel the action was triggered in.
-- `CHAT_USER_ID` is set to the chat service's user ID of the user who triggered the slash command.
+- `CHAT_INPUT` - The arguments passed to `/project-name run`.
+- `CHAT_CHANNEL` - The name of the chat channel the job is run from.
+- `CHAT_USER_ID` - The chat service ID of the user who runs the job.
-When executed, ChatOps looks up the specified job name and attempts to match it
-to a corresponding job in [`.gitlab-ci.yml`](../yaml/index.md). If a matching job
-is found on the default branch, a pipeline containing only that job is scheduled. After the
-job completes:
+When the job runs:
-- If the job completes in *less than 30 minutes*, the ChatOps sends the job's output to Slack.
-- If the job completes in *more than 30 minutes*, the job must use the
+- If the job completes in less than 30 minutes, ChatOps sends the job output to the chat channel.
+- If the job completes in more than 30 minutes, you must use a method like the
[Slack API](https://api.slack.com/) to send data to the channel.
-To use the `run` command, you must have at least the
-Developer role.
-If a job shouldn't be able to be triggered from chat, you can set the job to `except: [chat]`.
+## Run a CI/CD job
+
+You can run a CI/CD job from chat with the `/project-name run`
+[slash command](../../integration/slash_commands.md).
+
+Prerequisites:
+
+- You must have at least the Developer role for the project.
+
+To run a CI/CD job:
+
+- In the chat client, enter `/project-name run <job name> <arguments>`.
-## Best practices for ChatOps CI jobs
+ChatOps schedules a pipeline that contains only the specified job.
-Since ChatOps is built upon GitLab CI/CD, the job has all the same features and
-functions available. Consider these best practices when creating ChatOps jobs:
+### Exclude a job from ChatOps
-- GitLab strongly recommends you set [`rules`](../yaml/index.md#rules) so the job does not run as part
- of the standard CI pipeline.
-- If the job is set to `when: manual`, ChatOps creates the pipeline, but the job waits to be started.
-- ChatOps provides limited support for access control. If the user triggering the
- slash command has at least the Developer role
- in the project, the job runs. The job itself can use existing
- [CI/CD variables](../variables/index.md#predefined-cicd-variables) like
- `GITLAB_USER_ID` to perform additional rights validation, but
- these variables can be [overridden](../variables/index.md#cicd-variable-precedence).
+To prevent a job from being run from chat:
-### Controlling the ChatOps reply
+- In `.gitlab-ci.yml`, set the job to `except: [chat]`.
-The output for jobs with a single command is sent to the channel as a reply. For
-example, the chat reply of the following job is `Hello World` in the channel:
+## Customize the ChatOps reply
+
+ChatOps sends the output for a job with a single command to the
+channel as a reply. For example, when the following job runs,
+the chat reply is `Hello world`:
```yaml
stages:
@@ -78,13 +86,12 @@ hello-world:
- echo "Hello World"
```
-Jobs that contain multiple commands (or `before_script`) return additional
-content in the chat reply. In these cases, both the commands and their output are
-included, with the commands wrapped in ANSI color codes.
+If the job contains multiple commands, or if `before_script` is set, ChatOps sends the commands
+and their output to the channel. The commands are wrapped in ANSI color codes.
-To selectively reply with the output of one command, its output must be bounded by
-the `chat_reply` section. For example, the following job lists the files in the
-current directory:
+To selectively reply with the output of one command, place the output
+in a `chat_reply` section. For example, the following job lists the
+files in the current directory:
```yaml
stages:
@@ -99,28 +106,8 @@ ls:
- echo -e "section_start:$( date +%s ):chat_reply\r\033[0K\n$( ls -la )\nsection_end:$( date +%s ):chat_reply\r\033[0K"
```
-## GitLab ChatOps examples
-
-The GitLab.com team created a repository of [common ChatOps scripts](https://gitlab.com/gitlab-com/chatops)
-they use to interact with our Production instance of GitLab. Administrators of
-other GitLab instances may find them useful. They can serve as inspiration for ChatOps
-scripts you can write to interact with your own applications.
-
-## GitLab ChatOps icon
-
-The [official GitLab ChatOps icon](img/gitlab-chatops-icon.png) is available for download.
-You can find and download the official GitLab ChatOps icon here.
-
-![GitLab ChatOps bot icon](img/gitlab-chatops-icon-small.png)
-
-<!-- ## Troubleshooting
-
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
+## Related topics
-Each scenario can be a third-level heading, for example `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+- Download the [official GitLab ChatOps icon](img/gitlab-chatops-icon.png).
+- The GitLab team maintains a [repository of common ChatOps scripts](https://gitlab.com/gitlab-com/chatops)
+ they use to interact with GitLab.com.
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 920e7cca2cb..71210467018 100644
--- a/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md
+++ b/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/ci/cloud_deployment/heroku.md b/doc/ci/cloud_deployment/heroku.md
index 541ba89dca8..7c15bf5b8cd 100644
--- a/doc/ci/cloud_deployment/heroku.md
+++ b/doc/ci/cloud_deployment/heroku.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/ci/cloud_deployment/index.md b/doc/ci/cloud_deployment/index.md
index a8826a6fdb5..79684d9d627 100644
--- a/doc/ci/cloud_deployment/index.md
+++ b/doc/ci/cloud_deployment/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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
---
diff --git a/doc/ci/cloud_services/aws/index.md b/doc/ci/cloud_services/aws/index.md
index 484a159cd2b..733105e9ddf 100644
--- a/doc/ci/cloud_services/aws/index.md
+++ b/doc/ci/cloud_services/aws/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
---
diff --git a/doc/ci/cloud_services/azure/index.md b/doc/ci/cloud_services/azure/index.md
index 321f9849632..c99e30e8bac 100644
--- a/doc/ci/cloud_services/azure/index.md
+++ b/doc/ci/cloud_services/azure/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
---
diff --git a/doc/ci/cloud_services/google_cloud/index.md b/doc/ci/cloud_services/google_cloud/index.md
index 516a2d05cd1..bcb2681403a 100644
--- a/doc/ci/cloud_services/google_cloud/index.md
+++ b/doc/ci/cloud_services/google_cloud/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
---
diff --git a/doc/ci/cloud_services/index.md b/doc/ci/cloud_services/index.md
index 9304e3562d9..88e7d88e22a 100644
--- a/doc/ci/cloud_services/index.md
+++ b/doc/ci/cloud_services/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
---
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index a8c192dc944..674f9b6035a 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -9,12 +9,12 @@ type: concepts, howto
You can use GitLab CI/CD with Docker to create Docker images.
For example, you can create a Docker image of your application,
-test it, and publish it to a container registry.
+test it, and push it to a container registry.
To run Docker commands in your CI/CD jobs, you must configure
-GitLab Runner to support `docker` commands.
+GitLab Runner to support `docker` commands. This method requires `privileged` mode.
-If you want to build Docker images without enabling privileged mode on the runner,
+If you want to build Docker images without enabling `privileged` mode on the runner,
you can use a [Docker alternative](#docker-alternatives).
## Enable Docker commands in your CI/CD jobs
@@ -58,7 +58,7 @@ the Docker commands, but needs permission to do so.
sudo -u gitlab-runner -H docker info
```
-1. In GitLab, to verify that everything works, add `docker info` to `.gitlab-ci.yml`:
+1. In GitLab, add `docker info` to `.gitlab-ci.yml` to verify that Docker is working:
```yaml
before_script:
@@ -70,10 +70,10 @@ the Docker commands, but needs permission to do so.
- docker run my-docker-image /script/to/run/tests
```
-You can now use `docker` commands (and install `docker-compose` if needed).
+You can now use `docker` commands (and install Docker Compose if needed).
-When you add `gitlab-runner` to the `docker` group, you are effectively granting `gitlab-runner` full root permissions.
-For more information, see the [security of the `docker` group](https://blog.zopyx.com/on-docker-security-docker-group-considered-harmful/).
+When you add `gitlab-runner` to the `docker` group, you effectively grant `gitlab-runner` full root permissions.
+For more information, see [security of the `docker` group](https://blog.zopyx.com/on-docker-security-docker-group-considered-harmful/).
### Use Docker-in-Docker
@@ -83,15 +83,15 @@ For more information, see the [security of the `docker` group](https://blog.zopy
- The executor uses a [container image of Docker](https://hub.docker.com/_/docker/), provided
by Docker, to run your CI/CD jobs.
-The Docker image has all of the `docker` tools installed and can run
+The Docker image includes all of the `docker` tools and can run
the job script in context of the image in privileged mode.
-We recommend you use Docker-in-Docker with TLS enabled,
+You should use Docker-in-Docker with TLS enabled,
which is supported by [GitLab.com shared runners](../runners/index.md).
-You should always specify a specific version of the image, like `docker:20.10.16`.
+You should always pin a specific version of the image, like `docker:20.10.16`.
If you use a tag like `docker:stable`, you have no control over which version is used.
-Unpredictable behavior can result, especially when new versions are released.
+This can cause incompatibility problems when new versions are released.
#### Use the Docker executor with Docker-in-Docker
@@ -101,14 +101,11 @@ You can use the Docker executor to run jobs in a Docker container.
> Introduced in GitLab Runner 11.11.
-The Docker daemon supports connections over TLS. In Docker 19.03.12 and later,
-TLS is the default.
+The Docker daemon supports connections over TLS. TLS is the default in Docker 19.03.12 and later.
WARNING:
-This task enables `--docker-privileged`. When you do this, you are effectively disabling all of
-the security mechanisms of containers and exposing your host to privilege
-escalation. Doing this can lead to container breakout. For more information,
-see the official Docker documentation about
+This task enables `--docker-privileged`, which effectively disables the container's security mechanisms and exposes your host to privilege
+escalation. This action can cause container breakout. For more information, see
[runtime privilege and Linux capabilities](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities).
To use Docker-in-Docker with TLS enabled:
@@ -134,10 +131,9 @@ To use Docker-in-Docker with TLS enabled:
you must always use `privileged = true` in your Docker containers.
- This command mounts `/certs/client` for the service and build
container, which is needed for the Docker client to use the
- certificates in that directory. For more information on how
- Docker with TLS works, see <https://hub.docker.com/_/docker/#tls>.
+ certificates in that directory. For more information, see [the Docker image documentation](https://hub.docker.com/_/docker/).
- The previous command creates a `config.toml` entry similar to this:
+ The previous command creates a `config.toml` entry similar to the following example:
```toml
[[runners]]
@@ -155,7 +151,7 @@ To use Docker-in-Docker with TLS enabled:
[runners.cache.gcs]
```
-1. You can now use `docker` in the job script. Note the inclusion of the
+1. You can now use `docker` in the job script. You should include the
`docker:20.10.16-dind` service:
```yaml
@@ -193,7 +189,7 @@ To use Docker-in-Docker with TLS enabled:
##### Docker-in-Docker with TLS disabled in the Docker executor
-Sometimes you might have legitimate reasons to disable TLS.
+Sometimes there are legitimate reasons to disable TLS.
For example, you have no control over the GitLab Runner configuration
that you are using.
@@ -215,7 +211,7 @@ Assuming that the runner's `config.toml` is similar to:
[runners.cache.gcs]
```
-You can now use `docker` in the job script. Note the inclusion of the
+You can now use `docker` in the job script. You should include the
`docker:20.10.16-dind` service:
```yaml
@@ -254,7 +250,7 @@ build:
#### Use the Kubernetes executor with Docker-in-Docker
-You can use the Kubernetes executor to run jobs in a Docker container.
+You can use the [Kubernetes executor](https://docs.gitlab.com/runner/executors/kubernetes.html) to run jobs in a Docker container.
##### Docker-in-Docker with TLS enabled in Kubernetes
@@ -280,7 +276,7 @@ To use Docker-in-Docker with TLS enabled in Kubernetes:
medium = "Memory"
```
-1. You can now use `docker` in the job script. Note the inclusion of the
+1. You can now use `docker` in the job script. You should include the
`docker:20.10.16-dind` service:
```yaml
@@ -324,25 +320,23 @@ To use Docker-in-Docker with TLS enabled in Kubernetes:
- docker run my-docker-image /script/to/run/tests
```
-#### Limitations of Docker-in-Docker
+#### Known issues with Docker-in-Docker
-Docker-in-Docker is the recommended configuration, but is
-not without its own challenges:
+Docker-in-Docker is the recommended configuration, but you should be aware of the following issues:
- **The `docker-compose` command**: This command is not available in this configuration by default.
- To use `docker-compose` in your job scripts, follow the `docker-compose`
+ To use `docker-compose` in your job scripts, follow the Docker Compose
[installation instructions](https://docs.docker.com/compose/install/).
-- **Cache**: Each job runs in a new environment. Concurrent jobs work fine,
- because every build gets its own instance of Docker engine and they don't conflict with each other.
- However, jobs can be slower because there's no caching of layers.
+- **Cache**: Each job runs in a new environment. Because every build gets its own instance of the Docker engine, concurrent jobs do not cause conflicts.
+ However, jobs can be slower because there's no caching of layers. See [Docker layer caching](#make-docker-in-docker-builds-faster-with-docker-layer-caching).
- **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 don't share their
+- **Root file system**: Because the `docker:20.10.16-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 might create a subdirectory under `/builds/$CI_PROJECT_PATH`
- and use it as your mount point. For a more detailed explanation, view
+ child container, you could create a subdirectory under `/builds/$CI_PROJECT_PATH`
+ and use it as your mount point. For a more detailed explanation, see
[issue #41227](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41227).
```yaml
@@ -362,16 +356,16 @@ NOTE:
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
-are done to the services as well, making these incompatible.
+also affect services, making them incompatible.
#### Use the Docker executor with Docker socket binding
To make Docker available in the context of the image, you need to mount
`/var/run/docker.sock` into the launched containers. To do this with the Docker
-executor, you need to add `"/var/run/docker.sock:/var/run/docker.sock"` to the
+executor, add `"/var/run/docker.sock:/var/run/docker.sock"` to the
[Volumes in the `[runners.docker]` section](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#volumes-in-the-runnersdocker-section).
-Your configuration should look something like this:
+Your configuration should look similar to this example:
```toml
[[runners]]
@@ -388,7 +382,7 @@ Your configuration should look something like this:
Insecure = false
```
-You can also do this while registering your runner by providing the following options:
+To mount `/var/run/docker.sock` while registering your runner, include the following options:
```shell
sudo gitlab-runner register -n \
@@ -402,10 +396,10 @@ sudo gitlab-runner register -n \
##### Enable registry mirror for `docker:dind` service
-When the Docker daemon starts inside of the service container, it uses
-the default configuration. You may want to configure a
+When the Docker daemon starts inside the service container, it uses
+the default configuration. You might want to configure a
[registry mirror](https://docs.docker.com/registry/recipes/mirror/) for
-performance improvements and to ensure you don't reach Docker Hub rate limits.
+performance improvements and to ensure you do not exceed Docker Hub rate limits.
###### The service in the `.gitlab-ci.yml` file
@@ -474,9 +468,9 @@ content:
```
Update the `config.toml` file to mount the file to
-`/etc/docker/daemon.json`. This would mount the file for **every**
-container that is created by GitLab Runner. The configuration is
-picked up by the `dind` service.
+`/etc/docker/daemon.json`. This mounts the file for **every**
+container created by GitLab Runner. The configuration is
+detected by the `dind` service.
```toml
[[runners]]
@@ -516,13 +510,12 @@ kubectl create configmap docker-daemon --namespace gitlab-runner --from-file /tm
```
NOTE:
-Make sure to use the namespace that the Kubernetes executor for GitLab Runner uses
-to create job pods in.
+You must use the namespace that the Kubernetes executor for GitLab Runner uses to create job pods.
After the ConfigMap is created, you can update the `config.toml`
file to mount the file to `/etc/docker/daemon.json`. This update
-mounts the file for **every** container that is created by GitLab Runner.
-The configuration is picked up by the `dind` service.
+mounts the file for **every** container created by GitLab Runner.
+The `dind` service detects this configuration.
```toml
[[runners]]
@@ -537,22 +530,21 @@ The configuration is picked up by the `dind` service.
sub_path = "daemon.json"
```
-##### Limitations of Docker socket binding
+##### Known issues with Docker socket binding
When you use Docker socket binding, you avoid running Docker in privileged mode. However,
the implications of this method are:
-- By sharing the Docker daemon, you are effectively disabling all
- the security mechanisms of containers and exposing your host to privilege
- escalation, which can lead to container breakout. For example, if a project
- ran `docker rm -f $(docker ps -a -q)` it would remove the GitLab Runner
+- By sharing the Docker daemon, you effectively disable all
+ the container's security mechanisms and expose your host to privilege
+ escalation. This can cause container breakout. For example, if a project
+ ran `docker rm -f $(docker ps -a -q)`, it would remove the GitLab Runner
containers.
-- Concurrent jobs may not work; if your tests
- create containers with specific names, they may conflict with each other.
-- Any containers spawned by Docker commands are siblings of the runner rather
- than children of the runner. This may have complications and limitations that
- are unsuitable for your workflow.
-- Sharing files and directories from the source repository into containers may not
+- Concurrent jobs might not work. If your tests
+ create containers with specific names, they might conflict with each other.
+- Any containers created by Docker commands are siblings of the runner, rather
+ than children of the runner. This might cause complications for your workflow.
+- Sharing files and directories from the source repository into containers might not
work as expected. Volume mounting is done in the context of the host
machine, not the build container. For example:
@@ -560,8 +552,8 @@ the implications of this method are:
docker run --rm -t -i -v $(pwd)/src:/home/app/src test-image:latest run_app_tests
```
-You don't need to include the `docker:20.10.16-dind` service, like you do when
-you're using the Docker-in-Docker executor:
+You do not need to include the `docker:20.10.16-dind` service, like you do when
+you use the Docker-in-Docker executor:
```yaml
image: docker:20.10.16
@@ -580,7 +572,7 @@ build:
When you use Docker-in-Docker, the
[standard authentication methods](using_docker_images.md#access-an-image-from-a-private-container-registry)
-don't work because a fresh Docker daemon is started with the service.
+do not work, because a fresh Docker daemon is started with the service.
### Option 1: Run `docker login`
@@ -612,14 +604,14 @@ 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 authenticated already. If you
+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
under `/root`.
If you mount the configuration file, any `docker` command
that modifies the `~/.docker/config.json` fails. For example, `docker login`
fails, because the file is mounted as read-only. Do not change it from
-read-only, because problems occur.
+read-only, because this causes problems.
Here is an example of `/opt/.docker/config.json` that follows the
[`DOCKER_AUTH_CONFIG`](using_docker_images.md#determine-your-docker_auth_config-data)
@@ -685,7 +677,7 @@ If you already have
defined, you can use the variable and save it in
`~/.docker/config.json`.
-There are multiple ways to define this authentication:
+You can define this authentication in several ways:
- In [`pre_build_script`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)
in the runner configuration file.
@@ -718,24 +710,23 @@ build:
When using Docker-in-Docker, Docker downloads all layers of your image every
time you create a build. Recent versions of Docker (Docker 1.13 and later) can
-use a pre-existing image as a cache during the `docker build` step. This considerably
-speeds up the build process.
+use a pre-existing image as a cache during the `docker build` step. This significantly
+accelerates the build process.
### How Docker caching works
-When running `docker build`, each command in `Dockerfile` results in a layer.
-These layers are kept around as a cache and can be reused if there haven't been
-any changes. Change in one layer causes all subsequent layers to be recreated.
+When running `docker build`, each command in `Dockerfile` creates a layer.
+These layers are retained as a cache and can be reused if there have been no changes. Change in one layer causes the recreation of all subsequent layers.
-You can specify a tagged image to be used as a cache source for the `docker build`
-command by using the `--cache-from` argument. Multiple images can be specified
+To specify a tagged image to be used as a cache source for the `docker build`
+command, use the `--cache-from` argument. Multiple images can be specified
as a cache source by using multiple `--cache-from` arguments. Any image that's used
-with the `--cache-from` argument must first be pulled
+with the `--cache-from` argument must be pulled
(using `docker pull`) before it can be used as a cache source.
### Docker caching example
-Here's a `.gitlab-ci.yml` file that shows how to use Docker caching:
+This example `.gitlab-ci.yml` file shows how to use Docker caching:
```yaml
image: docker:20.10.16
@@ -768,35 +759,33 @@ In the `script` section for the `build` stage:
cache (see the `--cache-from $CI_REGISTRY_IMAGE:latest` argument) if
available, and tags it.
1. The last two commands push the tagged Docker images to the container registry
- so that they may also be used as cache for subsequent builds.
+ so that they can also be used as cache for subsequent builds.
## Use the OverlayFS driver
NOTE:
The shared runners on GitLab.com use the `overlay2` driver by default.
-By default, when using `docker:dind`, Docker uses the `vfs` storage driver which
-copies the file system on every run. This is a disk-intensive operation
-which can be avoided if a different driver is used, for example `overlay2`.
+By default, when using `docker:dind`, Docker uses the `vfs` storage driver, which
+copies the file system on every run. You can avoid this disk-intensive operation by using a different driver, for example `overlay2`.
### Requirements
-1. Make sure a recent kernel is used, preferably `>= 4.2`.
+1. Ensure a recent kernel is used, preferably `>= 4.2`.
1. Check whether the `overlay` module is loaded:
```shell
sudo lsmod | grep overlay
```
- If you see no result, then it isn't loaded. To load it use:
+ If you see no result, then the module is not loaded. To load the module, use:
```shell
sudo modprobe overlay
```
- If everything went fine, you need to make sure module is loaded on reboot.
- On Ubuntu systems, this is done by editing `/etc/modules`. Just add the
- following line into it:
+ If the module loaded, you must make sure the module loads on reboot.
+ On Ubuntu systems, do this by adding the following line to `/etc/modules`:
```plaintext
overlay
@@ -823,7 +812,7 @@ environment variable in the
environment = ["DOCKER_DRIVER=overlay2"]
```
-If you're running multiple runners, you have to modify all configuration files.
+If you're running multiple runners, you must modify all configuration files.
Read more about the [runner configuration](https://docs.gitlab.com/runner/configuration/)
and [using the OverlayFS storage driver](https://docs.docker.com/storage/storagedriver/overlayfs-driver/).
@@ -833,8 +822,8 @@ and [using the OverlayFS storage driver](https://docs.docker.com/storage/storage
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).
+- [`kaniko`](using_kaniko.md)
+- [`buildah`](https://github.com/containers/buildah)
For example, with `buildah`:
@@ -868,7 +857,7 @@ build:
## Use the GitLab Container Registry
-After you've built a Docker image, you can push it up to the built-in
+After you've built a Docker image, you can push it to the
[GitLab Container Registry](../../user/packages/container_registry/build_and_push_images.md#use-gitlab-cicd).
## Troubleshooting
@@ -879,18 +868,18 @@ This is a common error when you are using
[Docker-in-Docker](#use-docker-in-docker)
v19.03 or later.
-This issue occurs because Docker starts on TLS automatically.
+This error occurs because Docker starts on TLS automatically.
-- If this is your first time setting it up, read
+- If this is your first time setting it up, see
[use the Docker executor with the Docker image](#use-docker-in-docker).
-- If you are upgrading from v18.09 or earlier, read our
+- If you are upgrading from v18.09 or earlier, see the
[upgrade guide](https://about.gitlab.com/blog/2019/07/31/docker-in-docker-with-docker-19-dot-03/).
-This error can also occur with the [Kubernetes executor](https://docs.gitlab.com/runner/executors/kubernetes.html#using-dockerdind) when attempts are made to access the Docker-in-Docker service before it has had time to fully start up. For a more detailed explanation, see [this issue](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27215).
+This error can also occur with the [Kubernetes executor](https://docs.gitlab.com/runner/executors/kubernetes.html#using-dockerdind) when attempts are made to access the Docker-in-Docker service before it has fully started up. For a more detailed explanation, see [issue 27215](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27215).
### Docker `no such host` error
-You may get an error that says
+You might get an error that says
`docker: error during connect: Post https://docker:2376/v1.40/containers/create: dial tcp: lookup docker on x.x.x.x:53: no such host`.
This issue can occur when the service's image name
diff --git a/doc/ci/environments/deployment_approvals.md b/doc/ci/environments/deployment_approvals.md
index 089ecefb373..c4f685b18ec 100644
--- a/doc/ci/environments/deployment_approvals.md
+++ b/doc/ci/environments/deployment_approvals.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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: Require approvals prior to deploying to a Protected Environment
---
diff --git a/doc/ci/environments/deployment_safety.md b/doc/ci/environments/deployment_safety.md
index cf82238564e..327118c8a86 100644
--- a/doc/ci/environments/deployment_safety.md
+++ b/doc/ci/environments/deployment_safety.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/ci/environments/environments_dashboard.md b/doc/ci/environments/environments_dashboard.md
index 479b783202d..2ee0dc2ee11 100644
--- a/doc/ci/environments/environments_dashboard.md
+++ b/doc/ci/environments/environments_dashboard.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/ci/environments/external_deployment_tools.md b/doc/ci/environments/external_deployment_tools.md
index ff3172f0e02..89a1f8565a9 100644
--- a/doc/ci/environments/external_deployment_tools.md
+++ b/doc/ci/environments/external_deployment_tools.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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
---
@@ -42,45 +42,45 @@ Here is an example setup that creates a `success` deployment record in GitLab wh
1. Create a new webhook. You can save the following manifest file and apply it by `kubectl apply -n argocd -f <manifiest-file-path>`:
- ```yaml
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: argocd-notifications-cm
- data:
- trigger.on-deployed: |
- - description: Application is synced and healthy. Triggered once per commit.
- oncePer: app.status.sync.revision
- send:
- - gitlab-deployment-status
- when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
- template.gitlab-deployment-status: |
- webhook:
- gitlab:
- method: POST
- path: /projects/<your-project-id>/deployments
- body: |
- {
- "status": "success",
- "environment": "production",
- "sha": "{{.app.status.operationState.operation.sync.revision}}",
- "ref": "main",
- "tag": "false"
- }
- service.webhook.gitlab: |
- url: https://gitlab.com/api/v4
- headers:
- - name: PRIVATE-TOKEN
- value: <your-access-token>
- - name: Content-type
- value: application/json
- ```
+ ```yaml
+ apiVersion: v1
+ kind: ConfigMap
+ metadata:
+ name: argocd-notifications-cm
+ data:
+ trigger.on-deployed: |
+ - description: Application is synced and healthy. Triggered once per commit.
+ oncePer: app.status.sync.revision
+ send:
+ - gitlab-deployment-status
+ when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
+ template.gitlab-deployment-status: |
+ webhook:
+ gitlab:
+ method: POST
+ path: /projects/<your-project-id>/deployments
+ body: |
+ {
+ "status": "success",
+ "environment": "production",
+ "sha": "{{.app.status.operationState.operation.sync.revision}}",
+ "ref": "main",
+ "tag": "false"
+ }
+ service.webhook.gitlab: |
+ url: https://gitlab.com/api/v4
+ headers:
+ - name: PRIVATE-TOKEN
+ value: <your-access-token>
+ - name: Content-type
+ value: application/json
+ ```
1. Create a new subscription in your application:
- ```shell
- kubectl patch app <your-app-name> -n argocd -p '{"metadata": {"annotations": {"notifications.argoproj.io/subscribe.on-deployed.gitlab":""}}}' --type merge
- ```
+ ```shell
+ kubectl patch app <your-app-name> -n argocd -p '{"metadata": {"annotations": {"notifications.argoproj.io/subscribe.on-deployed.gitlab":""}}}' --type merge
+ ```
NOTE:
If a deployment wasn't created as expected, you can troubleshoot with [`argocd-notifications` tool](https://argocd-notifications.readthedocs.io/en/stable/troubleshooting/).
diff --git a/doc/ci/environments/img/environments_project_home.png b/doc/ci/environments/img/environments_project_home.png
index 36b33e260f0..10d9de4f415 100644
--- a/doc/ci/environments/img/environments_project_home.png
+++ b/doc/ci/environments/img/environments_project_home.png
Binary files differ
diff --git a/doc/ci/environments/incremental_rollouts.md b/doc/ci/environments/incremental_rollouts.md
index 10cda68c4b5..8df2d8ead6c 100644
--- a/doc/ci/environments/incremental_rollouts.md
+++ b/doc/ci/environments/incremental_rollouts.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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, howto
---
diff --git a/doc/ci/environments/index.md b/doc/ci/environments/index.md
index 60450692794..c9b212c2915 100644
--- a/doc/ci/environments/index.md
+++ b/doc/ci/environments/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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
disqus_identifier: 'https://docs.gitlab.com/ee/ci/environments.html'
@@ -159,6 +159,19 @@ deploy_review_app:
- main
```
+### Rename an environment
+
+> - Renaming an environment by using the UI was [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68550) in GitLab 14.3.
+> - Renaming an environment by using the API was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/338897) in GitLab 15.9 and is planned for removal in GitLab 16.0.
+
+You cannot rename an environment by using the UI, and the API method was deprecated in GitLab 15.9.
+
+To achieve the same result as renaming an environment:
+
+1. [Stop the existing environment](#stop-an-environment-through-the-ui).
+1. [Delete the existing environment](#delete-an-environment).
+1. [Create a new environment](#create-a-static-environment) with the desired name.
+
## Deployment tier of environments
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/300741) in GitLab 13.10.
@@ -207,7 +220,7 @@ The `when: manual` action:
You can find the play button in the pipelines, environments, deployments, and jobs views.
-## Configure Kubernetes deployments (DEPRECATED)
+## Configure Kubernetes deployments (deprecated)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27630) in GitLab 12.6.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
@@ -708,7 +721,7 @@ You can view a deployment's expiration date in the GitLab UI.
1. On the left sidebar, select **Deployments > Environments**.
1. Select the name of the deployment.
-In the upper left, next to the environment name, the expiration date is displayed.
+In the upper-left corner, next to the environment name, the expiration date is displayed.
#### Override a deployment's scheduled stop time
@@ -717,7 +730,7 @@ You can manually override a deployment's expiration date.
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Deployments > Environments**.
1. Select the deployment name.
-1. in the upper right, select the thumbtack (**{thumbtack}**).
+1. in the upper-right corner, select the thumbtack (**{thumbtack}**).
![Environment auto stop](img/environment_auto_stop_v13_10.png)
@@ -866,7 +879,7 @@ It may take a minute or two for data to appear after initial deployment.
Metric charts can be embedded in GitLab Flavored Markdown. See [Embedding Metrics in GitLab Flavored Markdown](../../operations/metrics/embed.md) for more details.
-### Web terminals (DEPRECATED)
+### Web terminals (deprecated)
> [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
@@ -991,19 +1004,6 @@ like [Review Apps](../review_apps/index.md) (`review/*`).
The most specific spec takes precedence over the other wildcard matching. In this case,
the `review/feature-1` spec takes precedence over `review/*` and `*` specs.
-### Rename an environment
-
-> Renaming environments through the UI was [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68550) in GitLab 14.3. Renaming environments through the API was deprecated and [is planned to be removed](https://gitlab.com/gitlab-org/gitlab/-/issues/338897) in GitLab 15.0.
-
-Renaming an environment through the UI is not possible.
-Instead, you need to delete the old environment and create a new one:
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Deployments > Environments**.
-1. Find the environment and stop it.
-1. Delete the environment.
-1. Create a new environment with your preferred name.
-
## Related topics
- [Use GitLab CI to deploy to multiple environments (blog post)](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/)
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
index fc49be798ec..c81a5ab1378 100644
--- a/doc/ci/environments/protected_environments.md
+++ b/doc/ci/environments/protected_environments.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
index 7bb14c4c900..6295c131fb9 100644
--- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
+++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: tutorial
---
diff --git a/doc/ci/examples/deployment/composer-npm-deploy.md b/doc/ci/examples/deployment/composer-npm-deploy.md
index 533b6519d9a..81e70e5cf82 100644
--- a/doc/ci/examples/deployment/composer-npm-deploy.md
+++ b/doc/ci/examples/deployment/composer-npm-deploy.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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: tutorial
---
diff --git a/doc/ci/examples/deployment/index.md b/doc/ci/examples/deployment/index.md
index 67b4ec6b279..74b4581af99 100644
--- a/doc/ci/examples/deployment/index.md
+++ b/doc/ci/examples/deployment/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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: tutorial
---
diff --git a/doc/ci/examples/end_to_end_testing_webdriverio/index.md b/doc/ci/examples/end_to_end_testing_webdriverio/index.md
index 7b5690e2d3d..3385aca1ef2 100644
--- a/doc/ci/examples/end_to_end_testing_webdriverio/index.md
+++ b/doc/ci/examples/end_to_end_testing_webdriverio/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
author: Vincent Tunru
author_gitlab: Vinnl
diff --git a/doc/ci/examples/index.md b/doc/ci/examples/index.md
index 6738c55b6fa..b05c872d624 100644
--- a/doc/ci/examples/index.md
+++ b/doc/ci/examples/index.md
@@ -76,7 +76,7 @@ choose one of these templates:
- [dotNET Core (`dotNET-Core.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/dotNET-Core.gitlab-ci.yml)
- [Elixir (`Elixir.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml)
- [Flutter (`Flutter.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Flutter.gitlab-ci.yml)
-- [Golang (`Go.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Go.gitlab-ci.yml)
+- [Go (`Go.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Go.gitlab-ci.yml)
- [Gradle (`Gradle.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Gradle.gitlab-ci.yml)
- [Grails (`Grails.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Grails.gitlab-ci.yml)
- [iOS with fastlane (`iOS-Fastlane.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/iOS-Fastlane.gitlab-ci.yml)
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
index 062bd602c29..d56f14617db 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
@@ -126,7 +126,7 @@ We'll use this variable in the `.gitlab-ci.yml` later, to easily connect to our
![variables page](img/variables_page.png)
-We also need to add the public key to **Project** > **Settings** > **Repository** as a [Deploy Key](../../../user/project/deploy_keys/index.md), which gives us the ability to access our repository from the server through [SSH protocol](../../../gitlab-basics/command-line-commands.md#start-working-on-your-project).
+We also need to add the public key to **Project** > **Settings** > **Repository** as a [Deploy Key](../../../user/project/deploy_keys/index.md), which gives us the ability to access our repository from the server through the SSH protocol.
```shell
# As the deployer user on the server
diff --git a/doc/ci/examples/semantic-release.md b/doc/ci/examples/semantic-release.md
index 9f299448d52..0b4b2054610 100644
--- a/doc/ci/examples/semantic-release.md
+++ b/doc/ci/examples/semantic-release.md
@@ -90,7 +90,7 @@ As part of publishing a package, semantic-release increases the version number i
<!-- markdownlint-disable MD044 -->
-1. On the top bar, in the upper right, select your avatar.
+1. On the top bar, in the upper-right corner, select your avatar.
1. On the left sidebar, select **Access Tokens**.
1. In the **Token name** box, enter a token name.
1. Under **select scopes**, select the **api** checkbox.
diff --git a/doc/ci/introduction/index.md b/doc/ci/introduction/index.md
index e62c38fc1ec..bf07af5e761 100644
--- a/doc/ci/introduction/index.md
+++ b/doc/ci/introduction/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Execution
+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
diff --git a/doc/ci/jobs/ci_job_token.md b/doc/ci/jobs/ci_job_token.md
index d9cfbdf124e..db916d8d125 100644
--- a/doc/ci/jobs/ci_job_token.md
+++ b/doc/ci/jobs/ci_job_token.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Execution
+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
---
@@ -65,7 +65,9 @@ tries to steal tokens from other jobs.
You can control what projects a CI/CD job token can access to increase the
job token's security. A job token might give extra permissions that aren't necessary
-to access specific private resources.
+to access specific private resources. The job token scope only controls access
+to private projects. If an accessed project is public or internal, token scoping does
+not apply.
If a job token is leaked, it could potentially be used to access private data
to the job token's user. By limiting the job token access scope, private data cannot
@@ -78,14 +80,15 @@ see [epic 3559](https://gitlab.com/groups/gitlab-org/-/epics/3559).
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346298/) in GitLab 15.9. [Deployed behind the `:inbound_ci_scoped_job_token` feature flag](../../user/feature_flags.md), enabled by default.
-Control your project's job token scope by creating an **inbound** allowlist of projects which can
-access your project through its `CI_JOB_TOKEN`.
+Create an **inbound** allowlist of projects which can access your project through
+their `CI_JOB_TOKEN`.
-For example, you can add project `B` to the inbound allowlist for project `A`. Jobs
-in the pipeline for "allowed project" `B` can now use the CI/CD job token to authenticate
-API calls to access project `A`.
+For example, project `A` can add project `B` to the inbound allowlist. CI/CD jobs
+in project `B` (the "allowed project") can now use their CI/CD job token to
+authenticate API calls to access project `A`. If project `A` is public or internal,
+the project can be accessed by project `B` without adding it to the inbound allowlist.
-By default the allowlist includes your current project.
+By default the inbound allowlist of any project only includes itself.
It is a security risk to disable this feature, so project maintainers or owners should
keep this setting enabled at all times. Add projects to the allowlist only when cross-project
@@ -113,6 +116,8 @@ To disable the inbound job token scope allowlist:
1. Toggle **Allow access to this project with a CI_JOB_TOKEN** to disabled.
Enabled by default in new projects.
+You can also disable the allowlist [with the API](../../api/graphql/reference/index.md#mutationprojectcicdsettingsupdate).
+
### Add a project to the inbound job token scope allowlist
You can add projects to the inbound allowlist for a project. Projects added to the allowlist
@@ -133,6 +138,8 @@ To add a project:
1. Under **Allow CI job tokens from the following projects to access this project**,
add projects to the allowlist.
+You can also add a target project to the allowlist [with the API](../../api/graphql/reference/index.md#mutationcijobtokenscopeaddproject).
+
### Limit your project's job token access
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328553) in GitLab 14.1. [Deployed behind the `:ci_scoped_job_token` feature flag](../../user/feature_flags.md), disabled by default.
@@ -155,8 +162,8 @@ limited only by the user's access permissions.
For example, when the setting is enabled, jobs in a pipeline in project `A` have
a `CI_JOB_TOKEN` scope limited to project `A`. If the job needs to use the token
to make an API request to a private project `B`, then `B` must be added to the allowlist for `A`.
-If project `B` is public or internal, it's not required to be added to the allowlist.
-The job token scope is only for controlling access to private projects.
+If project `B` is public or internal, you do not need to add
+`B` to the allowlist to grant access.
### Configure the outbound job token scope
diff --git a/doc/ci/jobs/index.md b/doc/ci/jobs/index.md
index 5e69ecff7b8..b9c2ee409b8 100644
--- a/doc/ci/jobs/index.md
+++ b/doc/ci/jobs/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Execution
+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
---
@@ -339,8 +339,8 @@ In the example above:
- `date +%s`: The Unix timestamp (for example `1560896352`).
- `my_first_section`: The name given to the section.
- `\r\e[0K`: Prevents the section markers from displaying in the rendered (colored)
- job log, but they are displayed in the raw job log. To see them, in the upper right
- of the job log, select **{doc-text}** (**Show complete raw**).
+ job log, but they are displayed in the raw job log. To see them, in the upper-right corner
+ of the job log, select **Show complete raw** (**{doc-text}**).
- `\r`: carriage return.
- `\e[0K`: clear line ANSI escape code.
diff --git a/doc/ci/large_repositories/index.md b/doc/ci/large_repositories/index.md
index 5a553228ba1..f728e9b9e17 100644
--- a/doc/ci/large_repositories/index.md
+++ b/doc/ci/large_repositories/index.md
@@ -255,7 +255,7 @@ For very active repositories with a large number of references and files, you ca
enabled on all Gitaly servers, we found that we no longer need a pre-clone step for `gitlab-org/gitlab` development.
- Optimize your CI/CD jobs by seeding repository data in a pre-clone step with the
[`pre_clone_script`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) of GitLab Runner. See
- [SaaS runners on Linux](../runners/saas/linux_saas_runner.md#pre-clone-script) for details.
+ [SaaS runners on Linux](../runners/saas/linux_saas_runner.md#pre-clone-script-deprecated) for details.
Besides speeding up pipelines in large and active projects,
seeding the repository data also helps avoid
`429 Too many requests` errors from Cloudflare.
diff --git a/doc/ci/lint.md b/doc/ci/lint.md
index 74e0f0cd5ef..119a0e5853e 100644
--- a/doc/ci/lint.md
+++ b/doc/ci/lint.md
@@ -26,7 +26,7 @@ To check CI/CD configuration with the CI lint tool:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **CI/CD > Pipelines**.
-1. In the upper right, select **CI lint**.
+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.
1. Select **Validate**.
@@ -47,7 +47,7 @@ To simulate a pipeline:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **CI/CD > Pipelines**.
-1. In the upper right, select **CI lint**.
+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.
1. Select **Simulate pipeline creation for the default branch**.
1. Select **Validate**.
diff --git a/doc/ci/pipeline_editor/index.md b/doc/ci/pipeline_editor/index.md
index 727977b3bc8..1a7155c8195 100644
--- a/doc/ci/pipeline_editor/index.md
+++ b/doc/ci/pipeline_editor/index.md
@@ -70,7 +70,7 @@ simulations in the [CI Lint tool](../lint.md#simulate-a-pipeline).
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/357219) in GitLab 15.1.
You can review configuration added with the [`include`](../yaml/index.md#include)
-keyword in the pipeline editor. In the upper right, select the file tree (**{file-tree}**)
+keyword in the pipeline editor. In the upper-right corner, select the file tree (**{file-tree}**)
to see a list of all included configuration files. Selected files open in a new tab
for review.
diff --git a/doc/ci/pipelines/cicd_minutes.md b/doc/ci/pipelines/cicd_minutes.md
index 4cbaa77b029..e1eb2f53910 100644
--- a/doc/ci/pipelines/cicd_minutes.md
+++ b/doc/ci/pipelines/cicd_minutes.md
@@ -19,7 +19,7 @@ end-to-end duration of a pipeline.
On GitLab.com:
-- CI/CD minutes quotas are enabled for both public and private projects, but public
+- CI/CD minutes quotas are enabled for all projects, but certain
projects [consume CI/CD minutes at a slower rate](#cost-factor).
- The base monthly CI/CD minutes quota for a GitLab.com [namespace](../../user/namespace/index.md)
is determined by its [license tier](https://about.gitlab.com/pricing/).
@@ -201,13 +201,12 @@ can be higher than the end-to-end duration of a pipeline.
The cost factors for jobs running on shared runners on GitLab.com are:
-- `1` for internal and private projects.
-- `0.5` for public projects in the [GitLab for Open Source program](../../subscriptions/index.md#gitlab-for-open-source).
-- `0.008` for public forks of public projects in the [GitLab for Open Source program](../../subscriptions/index.md#gitlab-for-open-source). For every 125 minutes of job execution time,
+- `1` for internal, public, and private projects.
+- Exceptions for public projects:
+ - `0.5` for projects in the [GitLab for Open Source program](../../subscriptions/index.md#gitlab-for-open-source).
+ - `0.008` for forks of projects in the [GitLab for Open Source program](../../subscriptions/index.md#gitlab-for-open-source). For every 125 minutes of job execution time,
you use 1 CI/CD minute.
-- `1` for other public projects, after October 1, 2022 (previously `0.04`).
- For every 1 minute of job execution time, you use 1 CI/CD minute.
-- Calculated differently for [community contributions to GitLab projects](#cost-factor-for-community-contributions-to-gitlab-projects).
+- Discounted dynamically for [community contributions to GitLab projects](#cost-factor-for-community-contributions-to-gitlab-projects).
The cost factors on self-managed instances are:
diff --git a/doc/ci/pipelines/downstream_pipelines.md b/doc/ci/pipelines/downstream_pipelines.md
index e4560cd882d..1e4654e69fe 100644
--- a/doc/ci/pipelines/downstream_pipelines.md
+++ b/doc/ci/pipelines/downstream_pipelines.md
@@ -231,37 +231,43 @@ configuration for jobs that use the Windows runner, like scripts, use <code>&#92
### Run child pipelines with merge request pipelines
-To trigger a child pipeline as a [merge request pipeline](merge_request_pipelines.md):
+Pipelines, including child pipelines, run as branch pipelines by default when not using
+[`rules`](../yaml/index.md#rules) or [`workflow:rules`](../yaml/index.md#workflowrules).
+To configure child pipelines to run when triggered from a [merge request (parent) pipeline](merge_request_pipelines.md), use `rules` or `workflow:rules`.
+For example, using `rules`:
-1. Set the trigger job to run on merge requests in the parent pipeline's configuration file:
+1. Set the parent pipeline's trigger job to run on merge requests:
```yaml
- microservice_a:
+ trigger-child-pipeline-job:
trigger:
- include: path/to/microservice_a.yml
+ include: path/to/child-pipeline-configuration.yml
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
```
-1. Configure the child pipeline jobs to run in merge request pipelines with [`rules`](../yaml/index.md#rules)
- or [`workflow:rules`](../yaml/index.md#workflowrules).
- For example, with `rules` in a child pipeline's configuration file:
+1. Use `rules` to configure the child pipeline jobs to run when triggered by the parent pipeline:
```yaml
job1:
- script: echo "Child pipeline job 1"
+ script: echo "This child pipeline job runs any time the parent pipeline triggers it."
rules:
- - if: $CI_MERGE_REQUEST_ID
+ - if: $CI_PIPELINE_SOURCE == "parent_pipeline"
job2:
- script: echo "Child pipeline job 2"
+ script: echo "This child pipeline job runs only when the parent pipeline is a merge request pipeline"
rules:
- if: $CI_MERGE_REQUEST_ID
```
- In child pipelines, `$CI_PIPELINE_SOURCE` always has a value of `parent_pipeline`
- and cannot be used to identify merge request pipelines. Use `$CI_MERGE_REQUEST_ID`
- instead, which is always present in merge request pipelines.
+In child pipelines, `$CI_PIPELINE_SOURCE` always has a value of `parent_pipeline`, so:
+
+- You can use `if: $CI_PIPELINE_SOURCE == "parent_pipeline"` to ensure child pipeline jobs always run.
+- You _can't_ use `if: $CI_PIPELINE_SOURCE == "merge_request_event"` to configure child pipeline
+ jobs to run for merge request pipelines. Instead, use `if: $CI_MERGE_REQUEST_ID`
+ to set child pipeline jobs to run only when the parent pipeline is a merge request pipeline. The parent pipeline's
+ [`CI_MERGE_REQUEST_*` predefined variables](../variables/predefined_variables.md#predefined-variables-for-merge-request-pipelines)
+ are passed to the child pipeline jobs.
### Specify a branch for multi-project pipelines
@@ -281,7 +287,7 @@ Use:
- The `project` keyword to specify the full path to the downstream project.
In [GitLab 15.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/367660),
you can use [variable expansion](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
-- The `branch` keyword to specify the name of a branch or [tag](../../topics/git/tags.md)
+- The `branch` keyword to specify the name of a branch or [tag](../../user/project/repository/tags/index.md)
in the project specified by `project`. You can use variable expansion.
## Trigger a multi-project pipeline by using the API
@@ -309,18 +315,32 @@ trigger_pipeline:
> Hover behavior for pipeline cards [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/197140/) in GitLab 13.2.
In the [pipeline graph view](index.md#view-full-pipeline-graph), downstream pipelines display
-as a list of cards on the right of the graph. Hover over the pipeline's card to view
-which job triggered the downstream pipeline.
+as a list of cards on the right of the graph. From this view, you can:
-### Retry a downstream pipeline
+- Select a trigger job to see the triggered downstream pipeline's jobs.
+- Select **Expand jobs** **{chevron-lg-right}** on a pipeline card to expand the view
+ with the downstream pipeline's jobs. You can view one downstream pipeline at a time.
+- Hover over a pipeline card to have the job that triggered the downstream pipeline highlighted.
+
+### Retry failed and canceled jobs in a downstream pipeline
> - Retry from graph view [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354974) in GitLab 15.0 [with a flag](../../administration/feature_flags.md) named `downstream_retry_action`. Disabled by default.
> - Retry from graph view [generally available and feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/357406) in GitLab 15.1.
-To retry a completed downstream pipeline, select **Retry** (**{retry}**):
+To retry failed and canceled jobs, select **Retry** (**{retry}**):
- From the downstream pipeline's details page.
-- On the pipeline's card in the [pipeline graph view](index.md#view-full-pipeline-graph).
+- On the pipeline's card in the pipeline graph view.
+
+### Recreate a downstream pipeline
+
+> Retry trigger job from graph view [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367547) in GitLab 15.10 [with a flag](../../administration/feature_flags.md) named `ci_recreate_downstream_pipeline`. Disabled by default.
+
+You can recreate a downstream pipeline by retrying its corresponding trigger job. The newly created downstream pipeline replaces the current downstream pipeline in the pipeline graph.
+
+To recreate a downstream pipeline:
+
+- Select **Run again** (**{retry}**) on the trigger job's card in the pipeline graph view.
### Cancel a downstream pipeline
@@ -330,7 +350,7 @@ To retry a completed downstream pipeline, select **Retry** (**{retry}**):
To cancel a downstream pipeline that is still running, select **Cancel** (**{cancel}**):
- From the downstream pipeline's details page.
-- On the pipeline's card in the [pipeline graph view](index.md#view-full-pipeline-graph).
+- On the pipeline's card in the pipeline graph view.
### Mirror the status of a downstream pipeline in the trigger job
@@ -365,13 +385,9 @@ trigger_job:
After you trigger a multi-project pipeline, the downstream pipeline displays
to the right of the [pipeline graph](index.md#visualize-pipelines).
-![Multi-project pipeline graph](img/multi_project_pipeline_graph_v14_3.png)
-
In [pipeline mini graphs](index.md#pipeline-mini-graphs), the downstream pipeline
displays to the right of the mini graph.
-![Multi-project pipeline mini graph](img/pipeline_mini_graph_v15_0.png)
-
## Fetch artifacts from an upstream pipeline
Use [`needs:project`](../yaml/index.md#needsproject) to fetch artifacts from an
@@ -604,8 +620,9 @@ the ones defined in the upstream project take precedence.
### Pass dotenv variables created in a job **(PREMIUM)**
-You can pass variables to a downstream pipeline with [`dotenv` variable inheritance](../variables/index.md#pass-an-environment-variable-to-another-job)
-and [`needs:project`](../yaml/index.md#needsproject).
+You can pass variables to a downstream job with [`dotenv` variable inheritance](../variables/index.md#pass-an-environment-variable-to-another-job)
+and [`needs:project`](../yaml/index.md#needsproject). These variables are only available in
+the script of the job and can't be used to configure it, for example with `rules` or `artifact:paths`.
For example, in a [multi-project pipeline](#multi-project-pipelines):
@@ -656,6 +673,16 @@ With multi-project pipelines, the trigger job fails and does not create the down
to run pipelines against the protected branch. See [pipeline security for protected branches](index.md#pipeline-security-on-protected-branches)
for more information.
+### Job in child pipeline is not created when the pipeline runs
+
+If the parent pipeline is a [merge request pipeline](merge_request_pipelines.md),
+the child pipeline must [use `workflow:rules` or `rules` to ensure the jobs run](#run-child-pipelines-with-merge-request-pipelines).
+
+If no jobs in the child pipeline can run due to missing or incorrect `rules` configuration:
+
+- The child pipeline fails to start.
+- The parent pipeline's trigger job fails with: `downstream pipeline can not be created, Pipeline will not run for the selected trigger. The rules configuration prevented any jobs from being added to the pipeline.`
+
### `Ref is ambiguous`
You cannot trigger a multi-project pipeline with a tag when a branch exists with the same
diff --git a/doc/ci/pipelines/img/multi_project_pipeline_graph_v14_3.png b/doc/ci/pipelines/img/multi_project_pipeline_graph_v14_3.png
deleted file mode 100644
index aadf8bb0979..00000000000
--- a/doc/ci/pipelines/img/multi_project_pipeline_graph_v14_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/pipelines/img/pipeline_mini_graph_v15_0.png b/doc/ci/pipelines/img/pipeline_mini_graph_v15_0.png
deleted file mode 100644
index 48a0ca9d84f..00000000000
--- a/doc/ci/pipelines/img/pipeline_mini_graph_v15_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/pipelines/index.md b/doc/ci/pipelines/index.md
index fa04cb6cb92..d2038dbcb62 100644
--- a/doc/ci/pipelines/index.md
+++ b/doc/ci/pipelines/index.md
@@ -423,8 +423,7 @@ You can group the jobs by:
- [Job dependencies](#view-job-dependencies-in-the-pipeline-graph), which arranges
jobs based on their [`needs`](../yaml/index.md#needs) dependencies.
-[Multi-project pipeline graphs](downstream_pipelines.md#view-multi-project-pipelines-in-pipeline-graphs) help
-you visualize the entire pipeline, including all cross-project inter-dependencies.
+Multi-project pipeline graphs help you visualize the entire pipeline, including all cross-project inter-dependencies.
If a stage contains more than 100 jobs, only the first 100 jobs are listed in the
pipeline graph. The remaining jobs still run as usual. To see the jobs:
diff --git a/doc/ci/pipelines/job_artifacts.md b/doc/ci/pipelines/job_artifacts.md
index 75c9852d3d0..7db4596bb1d 100644
--- a/doc/ci/pipelines/job_artifacts.md
+++ b/doc/ci/pipelines/job_artifacts.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
disqus_identifier: 'https://docs.gitlab.com/ee/user/project/pipelines/job_artifacts.html'
---
@@ -264,7 +264,7 @@ artifacts and log. You must be:
To delete a job:
1. Go to a job's detail page.
-1. In the upper right of the job's log, select **Erase job log** (**{remove}**).
+1. In the upper-right corner of the job's log, select **Erase job log** (**{remove}**).
1. On the confirmation dialog, select **OK**.
## Expose job artifacts in the merge request UI
diff --git a/doc/ci/pipelines/merge_request_pipelines.md b/doc/ci/pipelines/merge_request_pipelines.md
index 7e18c11f234..881e94a6559 100644
--- a/doc/ci/pipelines/merge_request_pipelines.md
+++ b/doc/ci/pipelines/merge_request_pipelines.md
@@ -140,14 +140,7 @@ the parent project. Additionally, if you do not trust the fork project's runner,
running the pipeline in the parent project uses the parent project's trusted runners.
WARNING:
-Fork merge requests can contain malicious code that tries to steal secrets in the
-parent project when the pipeline runs, even before merge. As a reviewer, carefully
-check the changes in the merge request before triggering the pipeline. If you trigger
-the pipeline by selecting **Run pipeline** or applying a suggestion, GitLab shows
-a warning that you must accept before the pipeline runs. If you trigger the pipeline
-by using any other method, including the API, [`/rebase` quick action](../../user/project/quick_actions.md#issues-merge-requests-and-epics),
-or [**Rebase** option](../../user/project/merge_requests/methods/index.md#rebasing-in-semi-linear-merge-methods),
-**no warning displays**.
+Fork merge requests can contain malicious code that tries to steal secrets in the parent project when the pipeline runs, even before merge. As a reviewer, carefully check the changes in the merge request before triggering the pipeline. Unless you trigger the pipeline through the API or the [`/rebase` quick action](../../user/project/quick_actions.md#issues-merge-requests-and-epics), GitLab shows a warning that you must accept before the pipeline runs. Otherwise, **no warning displays**.
Prerequisites:
diff --git a/doc/ci/pipelines/pipeline_architectures.md b/doc/ci/pipelines/pipeline_architectures.md
index e4a3416f60b..dadf631e2bb 100644
--- a/doc/ci/pipelines/pipeline_architectures.md
+++ b/doc/ci/pipelines/pipeline_architectures.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Execution
+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
---
diff --git a/doc/ci/pipelines/pipeline_artifacts.md b/doc/ci/pipelines/pipeline_artifacts.md
index aacaa110041..31c848d5274 100644
--- a/doc/ci/pipelines/pipeline_artifacts.md
+++ b/doc/ci/pipelines/pipeline_artifacts.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/pipelines/settings.md b/doc/ci/pipelines/settings.md
index 3633863915c..98dc02c1041 100644
--- a/doc/ci/pipelines/settings.md
+++ b/doc/ci/pipelines/settings.md
@@ -71,7 +71,7 @@ is selected.
## Auto-cancel redundant pipelines
-You can set pending or running pipelines to cancel automatically when a new pipeline runs on the same branch. You can enable this in the project settings:
+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 top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > CI/CD**.
diff --git a/doc/ci/resource_groups/index.md b/doc/ci/resource_groups/index.md
index 7cf71f2a3ea..3835b5f2df2 100644
--- a/doc/ci/resource_groups/index.md
+++ b/doc/ci/resource_groups/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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: Control the job concurrency in GitLab CI/CD
---
diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md
index 7a0f43f9ec5..9e69ab1ccb8 100644
--- a/doc/ci/review_apps/index.md
+++ b/doc/ci/review_apps/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/runners/configure_runners.md b/doc/ci/runners/configure_runners.md
index 0fd4bff1bff..41dda5da0b2 100644
--- a/doc/ci/runners/configure_runners.md
+++ b/doc/ci/runners/configure_runners.md
@@ -155,8 +155,11 @@ different places.
### Determine the IP address of a shared runner
-To view the IP address of a shared runner you must have administrator access to
-the GitLab instance. To determine this:
+Prerequisite:
+
+- You must have administrator access to the instance.
+
+To determine the IP address of a shared runner:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **CI/CD > Runners**.
diff --git a/doc/ci/runners/index.md b/doc/ci/runners/index.md
index 41cde709143..d3bbd7d8816 100644
--- a/doc/ci/runners/index.md
+++ b/doc/ci/runners/index.md
@@ -20,7 +20,7 @@ in your [subscription plan](https://about.gitlab.com/pricing/).
## Security for GitLab SaaS runners
-GitLab SaaS runners on Linux and Windows run on Google Compute Platform. The [Google Infrastructure Security Design Overview whitepaper](https://cloud.google.com/docs/security/infrastructure/design/resources/google_infrastructure_whitepaper_fa.pdf) provides an overview of how Google designs security into its technical infrastructure. The GitLab [Trust Center](https://about.gitlab.com/security/) and [GitLab Security Compliance Controls](https://about.staging.gitlab.com/handbook/engineering/security/security-assurance/security-compliance/sec-controls.html) pages provide an overview of the Security and Compliance controls that govern the GitLab SaaS runners.
+GitLab SaaS runners on Linux and Windows run on Google Compute Platform. The [Google Infrastructure Security Design Overview whitepaper](https://cloud.google.com/docs/security/infrastructure/design/resources/google_infrastructure_whitepaper_fa.pdf) provides an overview of how Google designs security into its technical infrastructure. The GitLab [Trust Center](https://about.gitlab.com/security/) and [GitLab Security Compliance Controls](https://about.staging.gitlab.com/handbook/engineering/security/security-assurance/security-compliance/sec-controls.html) pages provide an overview of the security and compliance controls that govern the GitLab SaaS runners.
The runner that serves as a Runner Manager automatically initiates the creation and deletion of the virtual machines (VMs) used for CI jobs. When the Runner Manager picks up a GitLab SaaS CI job, it automatically executes that job on a new VM. There is no human or manual intervention in this process. The following section provides an overview of the additional built-in layers that harden the security of the GitLab Runner SaaS CI build environment.
diff --git a/doc/ci/runners/register_runner.md b/doc/ci/runners/register_runner.md
new file mode 100644
index 00000000000..ec10a1299dc
--- /dev/null
+++ b/doc/ci/runners/register_runner.md
@@ -0,0 +1,33 @@
+---
+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
+---
+
+# Register a shared runner **(FREE)**
+
+> [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), disabled by default.
+
+FLAG:
+On self-managed GitLab, this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `create_runner_workflow_for_admin`.
+On GitLab.com, this feature is available but can be configured by GitLab.com administrators only.
+
+Prerequisites:
+
+- You must be an administrator to register a shared runner.
+
+To register a [shared runner](../runners/runners_scope.md#shared-runners):
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **CI/CD > Runners**.
+1. Select **New instance runner**.
+1. Select a platform.
+1. Optional. Enter a description.
+1. Optional. Enter a maintenance note.
+1. Optional. Enter configurations for the runner.
+1. Select **Submit**.
+1. Follow the instructions to register the runner from the command line.
+
+NOTE:
+The token only displays in the UI for a short period of time during registration,
+and is then saved in `config.toml`.
diff --git a/doc/ci/runners/saas/linux_saas_runner.md b/doc/ci/runners/saas/linux_saas_runner.md
index 58c8a6d0815..e9ac91409af 100644
--- a/doc/ci/runners/saas/linux_saas_runner.md
+++ b/doc/ci/runners/saas/linux_saas_runner.md
@@ -88,12 +88,15 @@ Below are the settings for SaaS runners on Linux.
and [#4070](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/4070).
NOTE:
-The final disk space your jobs can use is less than 25 GB. Some disk space
-allocated to the instance is occupied by the operating system, the Docker image,
-and a copy of your cloned repository.
+SaaS runner instances are provisioned with a 25 GB storage volume. The underlying disk space of the storage volume
+is shared by the operating system, the Docker image, and a copy of your cloned repository.
+This means that the available free disk space that your jobs can use is **less than 25 GB**.
-## Pre-clone script
+## Pre-clone script (deprecated)
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/391896) in GitLab 15.9
+and is planned for removal in 16.0. Use [`pre_get_sources_script`](../../../ci/yaml/index.md#hookspre_get_sources_script) instead. This change is a breaking change.
With SaaS runners on Linux, you can run commands in a CI/CD
job before the runner attempts to run `git init` and `git fetch` to
download a GitLab repository. The
diff --git a/doc/ci/runners/saas/macos/environment.md b/doc/ci/runners/saas/macos/environment.md
index 1fc7afea7e6..7aa0f33fc59 100644
--- a/doc/ci/runners/saas/macos/environment.md
+++ b/doc/ci/runners/saas/macos/environment.md
@@ -20,11 +20,11 @@ Each time you run a job that requires tooling or dependencies not available in t
GitLab SaaS provides macOS build machines on Apple servers with Intel x86-64 processors.
The expectation is that virtual machines running on the Apple M1 chip will be available in the second half of 2022.
-At this time there is only one available machine type offered, `gbc-macos-large`.
+At this time there is only one available machine type offered, `shared-macos-amd64`.
| Instance type | vCPUS | Memory (GB) |
| --------- | --- | ------- |
-| `gbc-macos-large` | 4 | 10 |
+| `shared-macos-amd64` | 4 | 10 |
## VM images
diff --git a/doc/ci/runners/saas/macos_saas_runner.md b/doc/ci/runners/saas/macos_saas_runner.md
index 96e294ff828..21120732fbe 100644
--- a/doc/ci/runners/saas/macos_saas_runner.md
+++ b/doc/ci/runners/saas/macos_saas_runner.md
@@ -84,4 +84,4 @@ In SaaS runners on macOS, the objective is to make 90% of CI jobs start executin
- If the VM image does not include the specific software version you need for your job, then the job execution time will increase as the required software needs to be fetched and installed.
- At this time, it is not possible to bring your own OS image.
-- The keychain for user `gitlab` is not publicly available. You must create a keychain instead.
+- The keychain for user `gitlab` is not publicly available. You must create a keychain instead.
diff --git a/doc/ci/secrets/id_token_authentication.md b/doc/ci/secrets/id_token_authentication.md
index f622bc2a7b1..b10763b40d6 100644
--- a/doc/ci/secrets/id_token_authentication.md
+++ b/doc/ci/secrets/id_token_authentication.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: tutorial
---
@@ -45,7 +45,7 @@ The following fields are included in each ID token:
| [`iss`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.1) | Always | Issuer of the token, which is the domain of the GitLab instance ("issuer" claim). |
| [`jti`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.7) | Always | Unique identifier for the token ("JWT ID" claim). |
| [`nbf`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5) | Always | The time after which the token becomes valid ("not before" claim). |
-| [`sub`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.2) | Always | The job ID ("subject" claim). |
+| [`sub`](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.2) | Always | `project_path:{group}/{project}:ref_type:{type}:ref:{branch_name}` ("subject" claim). |
| `deployment_tier` | Job specifies an environment | [Deployment tier](../environments/index.md#deployment-tier-of-environments) of the environment the job specifies. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363590) in GitLab 15.2. |
| `environment_protected` | Job specifies an environment | `true` if specified environment is protected, `false` otherwise. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9. |
| `environment` | Job specifies an environment | Environment the job specifies. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9. |
diff --git a/doc/ci/secrets/index.md b/doc/ci/secrets/index.md
index 14f771431e5..fa8fe2a36a8 100644
--- a/doc/ci/secrets/index.md
+++ b/doc/ci/secrets/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: concepts, howto
---
diff --git a/doc/ci/secure_files/index.md b/doc/ci/secure_files/index.md
index 10baa57cabb..d432db351bb 100644
--- a/doc/ci/secure_files/index.md
+++ b/doc/ci/secure_files/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: reference
---
diff --git a/doc/ci/services/index.md b/doc/ci/services/index.md
index f26751c56e7..eca4c62deb2 100644
--- a/doc/ci/services/index.md
+++ b/doc/ci/services/index.md
@@ -269,7 +269,7 @@ test:
| `entrypoint` | no | 9.4 |Command or script to execute as the container's entrypoint. It's translated to the Docker `--entrypoint` option while creating the container. The syntax is similar to [`Dockerfile`'s `ENTRYPOINT`](https://docs.docker.com/engine/reference/builder/#entrypoint) directive, where each shell token is a separate string in the array. |
| `command` | no | 9.4 |Command or script that should be used as the container's command. It's translated to arguments passed to Docker after the image's name. The syntax is similar to [`Dockerfile`'s `CMD`](https://docs.docker.com/engine/reference/builder/#cmd) directive, where each shell token is a separate string in the array. |
| `alias` (1) | no | 9.4 | Additional alias that can be used to access the service from the job's container. Read [Accessing the services](#accessing-the-services) for more information. |
-| `variables` (2) | no | 14.5 | Additional environment variables that are passed exclusively to the service. The syntax is the same as [Job Variables](../variables/index.md). |
+| `variables` (2) | no | 14.5 | Additional environment variables that are passed exclusively to the service. The syntax is the same as [Job Variables](../variables/index.md). Service variables cannot reference themselves. |
(1) Alias support for the Kubernetes executor was [introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2229) in GitLab Runner 12.8, and is only available for Kubernetes version 1.7 or later.
diff --git a/doc/ci/ssh_keys/index.md b/doc/ci/ssh_keys/index.md
index c1154485018..ab767697cbc 100644
--- a/doc/ci/ssh_keys/index.md
+++ b/doc/ci/ssh_keys/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Execution
+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
type: tutorial
---
diff --git a/doc/ci/test_cases/index.md b/doc/ci/test_cases/index.md
index 4088e5e82c6..8ad9e27de8b 100644
--- a/doc/ci/test_cases/index.md
+++ b/doc/ci/test_cases/index.md
@@ -1,12 +1,12 @@
---
stage: Plan
-group: Certify
+group: Product Planning
info: To 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: Test cases in GitLab can help your teams create testing scenarios in their existing development platform.
type: reference
---
-# Test Cases **(ULTIMATE)**
+# Test cases **(ULTIMATE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233479) in GitLab 13.6.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/241983) in GitLab 13.7.
@@ -24,14 +24,14 @@ Prerequisite:
To create a test case in a GitLab project:
-1. Go to **CI/CD > Test Cases**.
+1. Go to **CI/CD > 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).
1. Select **Submit test case**. You are taken to view the new test case.
## View a test case
-You can view all test cases in the project in the Test Cases list. Filter the
+You can view all test cases in the project in the test cases list. Filter the
issue list with a search query, including labels or the test case's title.
Prerequisite:
@@ -43,7 +43,7 @@ Whether you can view an test case depends on the [project visibility level](../.
To view a test case:
-1. In a project, go to **CI/CD > Test Cases**.
+1. In a project, go to **CI/CD > Test cases**.
1. Select the title of the test case you want to view. You are taken to the test case page.
![An example test case page](img/test_case_show_v13_10.png)
@@ -77,7 +77,7 @@ To archive a test case, on the test case's page, select **Archive test case**.
To view archived test cases:
-1. Go to **CI/CD > Test Cases**.
+1. Go to **CI/CD > Test cases**.
1. Select **Archived**.
## Reopen an archived test case
diff --git a/doc/ci/testing/accessibility_testing.md b/doc/ci/testing/accessibility_testing.md
index fa57371a7d5..58bb4308095 100644
--- a/doc/ci/testing/accessibility_testing.md
+++ b/doc/ci/testing/accessibility_testing.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/testing/browser_performance_testing.md b/doc/ci/testing/browser_performance_testing.md
index ff013f0037e..175ecef7f09 100644
--- a/doc/ci/testing/browser_performance_testing.md
+++ b/doc/ci/testing/browser_performance_testing.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/testing/code_quality.md b/doc/ci/testing/code_quality.md
index 4b826991bb5..ff7e11e9c71 100644
--- a/doc/ci/testing/code_quality.md
+++ b/doc/ci/testing/code_quality.md
@@ -44,6 +44,7 @@ Code Quality results are shown in the:
- Merge request widget
- Merge request changes view
- Pipeline details view
+- Project quality view
### Merge request widget
@@ -73,6 +74,12 @@ tab of the pipeline's details page.
![Code Quality Report](img/code_quality_report_13_11.png)
+### Project quality view
+
+The project quality view displays an overview of the code quality findings.
+
+![Code Quality Summary](img/code_quality_summary_15_9.png)
+
## Enable Code Quality
Prerequisites:
diff --git a/doc/ci/testing/fail_fast_testing.md b/doc/ci/testing/fail_fast_testing.md
index 4ad1656c8d6..57e21beef06 100644
--- a/doc/ci/testing/fail_fast_testing.md
+++ b/doc/ci/testing/fail_fast_testing.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/testing/img/code_quality_summary_15_9.png b/doc/ci/testing/img/code_quality_summary_15_9.png
new file mode 100644
index 00000000000..60077123488
--- /dev/null
+++ b/doc/ci/testing/img/code_quality_summary_15_9.png
Binary files differ
diff --git a/doc/ci/testing/index.md b/doc/ci/testing/index.md
index 41d474f0e60..5fd86561b9e 100644
--- a/doc/ci/testing/index.md
+++ b/doc/ci/testing/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/testing/load_performance_testing.md b/doc/ci/testing/load_performance_testing.md
index 7e527fae562..cf870bcec55 100644
--- a/doc/ci/testing/load_performance_testing.md
+++ b/doc/ci/testing/load_performance_testing.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/testing/metrics_reports.md b/doc/ci/testing/metrics_reports.md
index e084e4d3bc7..9257ba8990e 100644
--- a/doc/ci/testing/metrics_reports.md
+++ b/doc/ci/testing/metrics_reports.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/testing/test_coverage_visualization.md b/doc/ci/testing/test_coverage_visualization.md
index e2a1a4a2c5e..1b29304d1af 100644
--- a/doc/ci/testing/test_coverage_visualization.md
+++ b/doc/ci/testing/test_coverage_visualization.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
@@ -33,7 +33,7 @@ This format was originally developed for Java, but most coverage analysis framew
for other languages have plugins to add support for it, like:
- [simplecov-cobertura](https://rubygems.org/gems/simplecov-cobertura) (Ruby)
-- [gocover-cobertura](https://github.com/boumenot/gocover-cobertura) (Golang)
+- [gocover-cobertura](https://github.com/boumenot/gocover-cobertura) (Go)
Other coverage analysis frameworks support the format out of the box, for example:
diff --git a/doc/ci/testing/unit_test_report_examples.md b/doc/ci/testing/unit_test_report_examples.md
index 87426fc8496..c63e225a2a7 100644
--- a/doc/ci/testing/unit_test_report_examples.md
+++ b/doc/ci/testing/unit_test_report_examples.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
@@ -274,3 +274,24 @@ phpunit:
reports:
junit: report.xml
```
+
+## Rust
+
+This example uses [cargo2junit](https://crates.io/crates/cargo2junit),
+which is installed in the current directory.
+To retrieve JSON output from `cargo test`, you must enable the nightly compiler.
+
+```yaml
+run unittests:
+ image: rust:latest
+ stage: test
+ before_script:
+ - cargo install --root . cargo2junit
+ script:
+ - cargo test -- -Z unstable-options --format json --report-time | bin/cargo2junit > report.xml
+ artifacts:
+ when: always
+ reports:
+ junit:
+ - report.xml
+```
diff --git a/doc/ci/testing/unit_test_reports.md b/doc/ci/testing/unit_test_reports.md
index 0fe9b2b6d64..88a5d90d30e 100644
--- a/doc/ci/testing/unit_test_reports.md
+++ b/doc/ci/testing/unit_test_reports.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/ci/triggers/index.md b/doc/ci/triggers/index.md
index 16530ea20b6..393b128c658 100644
--- a/doc/ci/triggers/index.md
+++ b/doc/ci/triggers/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Execution
+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: tutorial
---
@@ -201,3 +201,13 @@ doesn't exist, GitLab returns `The requested URL returned error: 400`.
For example, you might accidentally use `main` for the branch name in a project that
uses a different branch name for its default branch.
+
+Another possible cause for this error is a rule that prevents creation of the pipelines when `CI_PIPELINE_SOURCE` value is `trigger`, such as:
+
+```yaml
+rules:
+ - if: $CI_PIPELINE_SOURCE == "trigger"
+ when: never
+```
+
+Review your [`workflow:rules`](../yaml/index.md#workflowrules) to ensure a pipeline can be created when `CI_PIPELINE_SOURCE` value is `trigger`.
diff --git a/doc/ci/troubleshooting.md b/doc/ci/troubleshooting.md
index 17ce184ee28..30c067db36a 100644
--- a/doc/ci/troubleshooting.md
+++ b/doc/ci/troubleshooting.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Execution
+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
---
@@ -37,7 +37,7 @@ If you need to link to the schema directly, it
is at:
```plaintext
-https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/editor/schema/ci.json.
+https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/editor/schema/ci.json
```
To see the full list of custom tags covered by the CI/CD schema, check the
diff --git a/doc/ci/variables/index.md b/doc/ci/variables/index.md
index ec5c6c240a6..24eee4253a8 100644
--- a/doc/ci/variables/index.md
+++ b/doc/ci/variables/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: reference
---
@@ -19,6 +19,12 @@ or have them [prefilled in manual pipelines](../pipelines/index.md#prefill-varia
Variable names are limited by the [shell the runner uses](https://docs.gitlab.com/runner/shells/index.html)
to execute scripts. Each shell has its own set of reserved variable names.
+To ensure consistent behavior, you should always put variable values in single or double quotes.
+Variables are internally parsed by the [Psych YAML parser](https://docs.ruby-lang.org/en/master/Psych.html),
+so quoted and unquoted variables might be parsed differently. For example, `VAR1: 012345`
+is interpreted as an octal value, so the value becomes `5349`, but `VAR1: "012345"` is parsed
+as a string with a value of `012345`.
+
> For more information about advanced use of GitLab CI/CD:
>
> - <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>&nbsp;Get to productivity faster with these [7 advanced GitLab CI workflow hacks](https://about.gitlab.com/webcast/7cicd-hacks/)
@@ -189,7 +195,7 @@ You can make a CI/CD variable available to all projects and groups in a GitLab i
Prerequisite:
-- You must have administrator access.
+- You must have administrator access to the instance.
To add an instance variable:
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index b9557b98066..45dc1a7fe37 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: reference
---
diff --git a/doc/ci/variables/where_variables_can_be_used.md b/doc/ci/variables/where_variables_can_be_used.md
index 6ea1f454467..c20d9be51e7 100644
--- a/doc/ci/variables/where_variables_can_be_used.md
+++ b/doc/ci/variables/where_variables_can_be_used.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Authoring
+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
type: reference
---
diff --git a/doc/ci/yaml/artifacts_reports.md b/doc/ci/yaml/artifacts_reports.md
index 151a043da5e..8740cf100ac 100644
--- a/doc/ci/yaml/artifacts_reports.md
+++ b/doc/ci/yaml/artifacts_reports.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
@@ -22,7 +22,7 @@ date for the artifacts.
Some `artifacts:reports` types can be generated by multiple jobs in the same pipeline, and used by merge request or
pipeline features from each job.
-To be able to browse the report output files, include the [`artifacts:paths`](index.md#artifactspaths) keyword.
+To browse the report output files, ensure you include the [`artifacts:paths`](index.md#artifactspaths) keyword in your job definition.
NOTE:
Combined reports in parent pipelines using [artifacts from child pipelines](index.md#needspipelinejob) is
diff --git a/doc/ci/yaml/includes.md b/doc/ci/yaml/includes.md
index bf0b7444e78..6d34a3034f7 100644
--- a/doc/ci/yaml/includes.md
+++ b/doc/ci/yaml/includes.md
@@ -20,13 +20,6 @@ To include a single configuration file, use either of these syntax options:
include: '/templates/.after-script-template.yml'
```
-- `include` with a single file, and you specify the `include` type:
-
- ```yaml
- include:
- remote: 'https://gitlab.com/awesome-project/raw/main/.before-script-template.yml'
- ```
-
## Include an array of configuration files
You can include an array of configuration files:
@@ -159,12 +152,18 @@ do not change. This method is called *merging*.
### Merge method for `include`
-For a file containing `include` directives, the included files are read in order (possibly
-recursively), and the configuration in these files is likewise merged in order. If the parameters overlap, the last included file takes precedence. Finally, the directives in the
-file itself are merged with the configuration from the included files.
+The `include` configuration merges with the main configuration file with this process:
+
+- Included files are read in the order defined in the configuration file, and
+ the included configuration is merged together in the same order.
+- If an included file also uses `include`, that nested `include` configuration is merged first (recursively).
+- If parameters overlap, the last included file takes precedence when merging the configuration
+ from the included files.
+- After all configuration added with `include` is merged together, the main configuration
+ is merged with the included configuration.
This merge method is a _deep merge_, where hash maps are merged at any depth in the
-configuration. To merge hash map A (containing the configuration merged so far) and B (the next piece
+configuration. To merge hash map "A" (that contains the configuration merged so far) and "B" (the next piece
of configuration), the keys and values are processed as follows:
- When the key only exists in A, use the key and value from A.
@@ -172,9 +171,7 @@ of configuration), the keys and values are processed as follows:
- When the key exists in both A and B, and one of the values is not a hash map, use the value from B.
- Otherwise, use the key and value from B.
-For example:
-
-We have a configuration consisting of two files.
+For example, with a configuration that consists of two files:
- The `.gitlab-ci.yml` file:
@@ -211,7 +208,7 @@ We have a configuration consisting of two files.
dotenv: deploy.env
```
-The merged result:
+The merged result is:
```yaml
variables:
@@ -374,7 +371,7 @@ In `include` sections in your `.gitlab-ci.yml` file, you can use:
- [Project variables](../variables/index.md#for-a-project).
- [Group variables](../variables/index.md#for-a-group).
- [Instance variables](../variables/index.md#for-an-instance).
-- Project [predefined variables](../variables/predefined_variables.md).
+- Project [predefined variables](../variables/predefined_variables.md) (`CI_PROJECT_*`).
- In GitLab 14.2 and later, the `$CI_COMMIT_REF_NAME` [predefined variable](../variables/predefined_variables.md).
When used in `include`, the `CI_COMMIT_REF_NAME` variable returns the full
@@ -386,15 +383,7 @@ In GitLab 14.5 and later, you can also use:
- [Trigger variables](../triggers/index.md#pass-cicd-variables-in-the-api-call).
- [Scheduled pipeline variables](../pipelines/schedules.md#add-a-pipeline-schedule).
- [Manual pipeline run variables](../pipelines/index.md#run-a-pipeline-manually).
-- Pipeline [predefined variables](../variables/predefined_variables.md).
-
- YAML files are parsed before the pipeline is created, so the following pipeline predefined variables
- are **not** available:
-
- - `CI_PIPELINE_ID`
- - `CI_PIPELINE_URL`
- - `CI_PIPELINE_IID`
- - `CI_PIPELINE_CREATED_AT`
+- The `CI_PIPELINE_SOURCE` and `CI_PIPELINE_TRIGGERED` [predefined variables](../variables/predefined_variables.md).
For example:
@@ -517,3 +506,20 @@ When the pipeline runs, GitLab:
# This matches all `.yml` files only in subfolders of `configs`.
include: 'configs/**/*.yml'
```
+
+## Troubleshooting
+
+### `Maximum of 150 nested includes are allowed!` error
+
+The maximum number of [nested included files](#use-nested-includes) for a pipeline is 150.
+If you receive the `Maximum 150 includes are allowed` error message in your pipeline,
+it's likely that either:
+
+- Some of the nested configuration includes an overly large number of additional nested `include` configuration.
+- There is an accidental loop in the nested includes. For example, `include1.yml` includes
+ `include2.yml` which includes `include1.yml`, creating a recursive loop.
+
+To help reduce the risk of this happening, edit the pipeline configuration file
+with the [pipeline editor](../pipeline_editor/index.md), which validates if the
+limit is reached. You can remove one included file at a time to try to narrow down
+which configuration file is the source of the loop or excessive included files.
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index d5c0fe1d41d..6ba9d455278 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -136,11 +136,17 @@ The `include` files are:
- Always evaluated first and then merged with the content of the `.gitlab-ci.yml` file,
regardless of the position of the `include` keyword.
-You can [nest](includes.md#use-nested-includes) up to 100 includes. In [GitLab 14.9 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/28987),
-the same file can be included multiple times in nested includes, but duplicates are ignored.
+You can have up to 150 includes per pipeline, including [nested](includes.md#use-nested-includes) includes:
-In [GitLab 12.4 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/28212),
-the time limit to resolve all files is 30 seconds.
+- In [GitLab 15.10 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/367150) you can have up to 150 includes.
+ In nested includes, the same file can be included multiple times, but duplicated includes
+ count towards the limit.
+- From [GitLab 14.9 to GitLab 15.9](https://gitlab.com/gitlab-org/gitlab/-/issues/28987), you can have up to 100 includes.
+ The same file can be included multiple times in nested includes, but duplicates are ignored.
+- In GitLab 14.9 and earlier you can have up to 100 includes, but the same file can not
+ be included multiple times.
+
+The time limit to resolve all files is 30 seconds.
**Keyword type**: Global keyword.
@@ -153,6 +159,8 @@ the time limit to resolve all files is 30 seconds.
**Additional details**:
+- Only [certain CI/CD variables](includes.md#use-variables-with-include) can be used
+ with `include` keywords.
- Use merging to customize and override included CI/CD configurations with local
- You can override included configuration by having the same job name or global keyword
in the `.gitlab-ci.yml` file. The two configurations are merged together, and the
@@ -171,7 +179,7 @@ the time limit to resolve all files is 30 seconds.
#### `include:local`
-Use `include:local` to include a file that is in the same repository as the project running the pipeline.
+Use `include:local` to include a file that is in the same repository as the configuration file containing the `include` keyword.
Use `include:local` instead of symbolic links.
**Keyword type**: Global keyword.
@@ -201,8 +209,8 @@ include: '.gitlab-ci-production.yml'
- The `.gitlab-ci.yml` file and the local file must be on the same branch.
- You can't include local files through Git submodules paths.
-- All [nested includes](includes.md#use-nested-includes) are executed in the scope of the same project,
- so you can use local, project, remote, or template includes.
+- All [nested includes](includes.md#use-nested-includes) are executed in the scope of the project containing the configuration file with the `include` keyword, not the project running the pipeline.
+ You can use local, project, remote, or template includes.
#### `include:project`
@@ -220,8 +228,7 @@ use `include:project` and `include:file`.
The YAML files must have the `.yml` or `.yaml` extension.
- `include:ref`: Optional. The ref to retrieve the file from. Defaults to the `HEAD` of the project
when not specified.
-
-You can use [certain CI/CD variables](includes.md#use-variables-with-include).
+- You can use [certain CI/CD variables](includes.md#use-variables-with-include).
**Example of `include:project`**:
@@ -252,8 +259,8 @@ include:
**Additional details**:
-- All [nested includes](includes.md#use-nested-includes) are executed in the scope of the target project.
- You can use `local` (relative to the target project), `project`, `remote`, or `template` includes.
+- All [nested includes](includes.md#use-nested-includes) are executed in the scope of the project containing the configuration file with the nested `include` keyword.
+ You can use `local` (relative to the project containing the configuration file with the `include` keyword), `project`, `remote`, or `template` includes.
- When the pipeline starts, the `.gitlab-ci.yml` file configuration included by all methods is evaluated.
The configuration is a snapshot in time and persists in the database. GitLab does not reflect any changes to
the referenced `.gitlab-ci.yml` file configuration until the next pipeline starts.
@@ -422,23 +429,30 @@ A configuration with different pipeline names depending on the pipeline conditio
```yaml
variables:
- PIPELINE_NAME: 'Default pipeline name' # A default is not required.
+ PROJECT1_PIPELINE_NAME: 'Default pipeline name' # A default is not required.
workflow:
- name: '$PIPELINE_NAME'
+ name: '$PROJECT1_PIPELINE_NAME'
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
variables:
- PIPELINE_NAME: 'MR pipeline: $CI_COMMIT_BRANCH'
+ PROJECT1_PIPELINE_NAME: 'MR pipeline: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME'
- if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-in-ruby3/'
variables:
- PIPELINE_NAME: 'Ruby 3 pipeline'
+ PROJECT1_PIPELINE_NAME: 'Ruby 3 pipeline'
```
**Additional details**:
- If the name is an empty string, the pipeline is not assigned a name. A name consisting
of only CI/CD variables could evaluate to an empty string if all the variables are also empty.
+- `workflow:rules:variables` become [global variables](#variables) available in all jobs,
+ including [`trigger`](#trigger) jobs which forward variables to downstream pipelines by default.
+ If the downstream pipeline uses the same variable, the [variable is overwritten](../variables/index.md#cicd-variable-precedence)
+ by the upstream variable value. Be sure to either:
+ - Use a unique variable name in every project's pipeline configuration, like `PROJECT1_PIPELINE_NAME`.
+ - Use [`inherit:variables`](#inheritvariables) in the trigger job and list the
+ exact variables you want to forward to the downstream pipeline.
#### `workflow:rules`
@@ -552,6 +566,16 @@ When the branch is something else:
- job1's `DEPLOY_VARIABLE` is `job1-default-deploy`.
- job2's `DEPLOY_VARIABLE` is `default-deploy`.
+**Additional details**:
+
+- `workflow:rules:variables` become [global variables](#variables) available in all jobs,
+ including [`trigger`](#trigger) jobs which forward variables to downstream pipelines by default.
+ If the downstream pipeline uses the same variable, the [variable is overwritten](../variables/index.md#cicd-variable-precedence)
+ by the upstream variable value. Be sure to either:
+ - Use unique variable names in every project's pipeline configuration, like `PROJECT1_VARIABLE_NAME`.
+ - Use [`inherit:variables`](#inheritvariables) in the trigger job and list the
+ exact variables you want to forward to the downstream pipeline.
+
## Job keywords
The following topics explain how to use keywords to configure CI/CD pipelines.
@@ -938,10 +962,8 @@ job:
#### `artifacts:public`
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49775) in GitLab 13.8
-> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
-> - It's disabled on GitLab.com.
-> - It's recommended for production use.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223273) in GitLab 13.8 [with a flag](../../user/feature_flags.md) named `non_public_artifacts`, disabled by default.
+> - [Updated](https://gitlab.com/gitlab-org/gitlab/-/issues/322454) in GitLab 15.10. Artifacts created with `artifacts:public` before 15.10 are not guaranteed to remain private after this update.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available,
@@ -1924,12 +1946,8 @@ rspec:
### `hooks`
-> Introduced in GitLab 15.6 [with a flag](../../administration/feature_flags.md) named `ci_hooks_pre_get_sources_script`. 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 `ci_hooks_pre_get_sources_script`.
-The feature is not ready for production use.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356850) in GitLab 15.6 [with a flag](../../administration/feature_flags.md) named `ci_hooks_pre_get_sources_script`. Disabled by default.
+> - [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` to specify lists of commands to execute on the runner
at certain stages of job execution, like before retrieving the Git repository.
@@ -1943,7 +1961,8 @@ at certain stages of job execution, like before retrieving the Git repository.
#### `hooks:pre_get_sources_script`
-> Introduced in GitLab 15.6 [with a flag](../../administration/feature_flags.md) named `ci_hooks_pre_get_sources_script`. Disabled by default.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356850) in GitLab 15.6 [with a flag](../../administration/feature_flags.md) named `ci_hooks_pre_get_sources_script`. Disabled by default.
+> - [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
@@ -4348,18 +4367,19 @@ child3:
### `variables`
-Use `variables` to define [CI/CD variables](../variables/index.md#define-a-cicd-variable-in-the-gitlab-ciyml-file),
-which are configurable values that are passed to jobs.
-
-Variables are always available in `script`, `before_script`, and `after_script` commands.
-You can also use variables as inputs in some job keywords.
+Use `variables` to define [CI/CD variables](../variables/index.md#define-a-cicd-variable-in-the-gitlab-ciyml-file) for jobs.
**Keyword type**: Global and job keyword. You can use it at the global level,
and also at the job level.
-If you define `variables` at the global level, each variable is copied to
-every job configuration when the pipeline is created. If the job already has that
-variable defined, the [job-level variable takes precedence](../variables/index.md#cicd-variable-precedence).
+If you define `variables` as a [global keyword](#keywords), it behaves like default variables
+for all jobs. Each variable is copied to every job configuration when the pipeline is created.
+If the job already has that variable defined, the [job-level variable takes precedence](../variables/index.md#cicd-variable-precedence).
+
+Variables defined at the global-level cannot be used as inputs for other global keywords
+like [`include`](includes.md#use-variables-with-include). These variables can only
+be used at the job-level, in `script`, `before_script`, and `after_script` sections,
+as well as inputs in some job keywords like [`rules`](../jobs/job_control.md#cicd-variable-expressions).
**Possible inputs**: Variable name and value pairs:
diff --git a/doc/cloud_seed/index.md b/doc/cloud_seed/index.md
index 1021c7f7700..9ce18950506 100644
--- a/doc/cloud_seed/index.md
+++ b/doc/cloud_seed/index.md
@@ -1,5 +1,5 @@
---
-stage: Release
+stage: Configure
group: Incubation
info: Cloud Seed (formerly 5mp) is a GitLab Incubation Engineering program. No technical writer assigned to this group.
---
diff --git a/doc/development/advanced_search.md b/doc/development/advanced_search.md
new file mode 100644
index 00000000000..73a8191b789
--- /dev/null
+++ b/doc/development/advanced_search.md
@@ -0,0 +1,336 @@
+---
+stage: Data Stores
+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
+---
+
+# Advanced search development guidelines
+
+This page includes information about developing and working with Elasticsearch.
+
+Information on how to enable Elasticsearch and perform the initial indexing is in
+the [Elasticsearch integration documentation](../integration/advanced_search/elasticsearch.md#enable-advanced-search).
+
+## Deep Dive
+
+In June 2019, Mario de la Ossa hosted a Deep Dive (GitLab team members only: `https://gitlab.com/gitlab-org/create-stage/-/issues/1`) on the GitLab [Elasticsearch integration](../integration/advanced_search/elasticsearch.md) to share his domain specific knowledge with anyone who may work in this part of the codebase in the future. You can find the <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [recording on YouTube](https://www.youtube.com/watch?v=vrvl-tN2EaA), and the slides on [Google Slides](https://docs.google.com/presentation/d/1H-pCzI_LNrgrL5pJAIQgvLX8Ji0-jIKOg1QeJQzChug/edit) and in [PDF](https://gitlab.com/gitlab-org/create-stage/uploads/c5aa32b6b07476fa8b597004899ec538/Elasticsearch_Deep_Dive.pdf). Everything covered in this deep dive was accurate as of GitLab 12.0, and while specific details might have changed, it should still serve as a good introduction.
+
+In August 2020, a second Deep Dive was hosted, focusing on [GitLab-specific architecture for multi-indices support](#zero-downtime-reindexing-with-multiple-indices). The <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [recording on YouTube](https://www.youtube.com/watch?v=0WdPR9oB2fg) and the [slides](https://lulalala.gitlab.io/gitlab-elasticsearch-deepdive/) are available. Everything covered in this deep dive was accurate as of GitLab 13.3.
+
+## Supported Versions
+
+See [Version Requirements](../integration/advanced_search/elasticsearch.md#version-requirements).
+
+Developers making significant changes to Elasticsearch queries should test their features against all our supported versions.
+
+## Setting up development environment
+
+See the [Elasticsearch GDK setup instructions](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/howto/elasticsearch.md)
+
+## Helpful Rake tasks
+
+- `gitlab:elastic:test:index_size`: Tells you how much space the current index is using, as well as how many documents are in the index.
+- `gitlab:elastic:test:index_size_change`: Outputs index size, reindexes, and outputs index size again. Useful when testing improvements to indexing size.
+
+Additionally, if you need large repositories or multiple forks for testing, please consider [following these instructions](rake_tasks.md#extra-project-seed-options)
+
+## How does it work?
+
+The Elasticsearch integration depends on an external indexer. We ship an [indexer written in Go](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer). The user must trigger the initial indexing via a Rake task but, after this is done, GitLab itself will trigger reindexing when required via `after_` callbacks on create, update, and destroy that are inherited from [`/ee/app/models/concerns/elastic/application_versioned_search.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/concerns/elastic/application_versioned_search.rb).
+
+After initial indexing is complete, create, update, and delete operations for all models except projects (see [#207494](https://gitlab.com/gitlab-org/gitlab/-/issues/207494)) are tracked in a Redis [`ZSET`](https://redis.io/docs/manual/data-types/#sorted-sets). A regular `sidekiq-cron` `ElasticIndexBulkCronWorker` processes this queue, updating many Elasticsearch documents at a time with the [Bulk Request API](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html).
+
+Search queries are generated by the concerns found in [`ee/app/models/concerns/elastic`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/app/models/concerns/elastic). These concerns are also in charge of access control, and have been a historic source of security bugs so please pay close attention to them!
+
+### Custom routing
+
+[Custom routing](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html#_searching_with_custom_routing)
+is used in Elasticsearch for document types that are associated with a project. The routing format is `project_<project_id>`. Routing is set
+during indexing and searching operations. Some of the benefits and tradeoffs to using custom routing are:
+
+- Project scoped searches are much faster.
+- Routing is not used if too many shards would be hit for global and group scoped searches.
+- Shard size imbalance might occur.
+
+## Existing Analyzers/Tokenizers/Filters
+
+These are all defined in [`ee/lib/elastic/latest/config.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/elastic/latest/config.rb)
+
+### Analyzers
+
+#### `path_analyzer`
+
+Used when indexing blobs' paths. Uses the `path_tokenizer` and the `lowercase` and `asciifolding` filters.
+
+Please see the `path_tokenizer` explanation below for an example.
+
+#### `sha_analyzer`
+
+Used in blobs and commits. Uses the `sha_tokenizer` and the `lowercase` and `asciifolding` filters.
+
+Please see the `sha_tokenizer` explanation later below for an example.
+
+#### `code_analyzer`
+
+Used when indexing a blob's filename and content. Uses the `whitespace` tokenizer and the filters: [`code`](#code), `lowercase`, and `asciifolding`
+
+The `whitespace` tokenizer was selected to have more control over how tokens are split. For example the string `Foo::bar(4)` needs to generate tokens like `Foo` and `bar(4)` to be properly searched.
+
+Please see the `code` filter for an explanation on how tokens are split.
+
+NOTE:
+The [Elasticsearch `code_analyzer` doesn't account for all code cases](../integration/advanced_search/elasticsearch_troubleshooting.md#elasticsearch-code_analyzer-doesnt-account-for-all-code-cases).
+
+#### `code_search_analyzer`
+
+Not directly used for indexing, but rather used to transform a search input. Uses the `whitespace` tokenizer and the `lowercase` and `asciifolding` filters.
+
+### Tokenizers
+
+#### `sha_tokenizer`
+
+This is a custom tokenizer that uses the [`edgeNGram` tokenizer](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-edgengram-tokenizer.html) to allow SHAs to be searchable by any sub-set of it (minimum of 5 chars).
+
+Example:
+
+`240c29dc7e` becomes:
+
+- `240c2`
+- `240c29`
+- `240c29d`
+- `240c29dc`
+- `240c29dc7`
+- `240c29dc7e`
+
+#### `path_tokenizer`
+
+This is a custom tokenizer that uses the [`path_hierarchy` tokenizer](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-pathhierarchy-tokenizer.html) with `reverse: true` to allow searches to find paths no matter how much or how little of the path is given as input.
+
+Example:
+
+`'/some/path/application.js'` becomes:
+
+- `'/some/path/application.js'`
+- `'some/path/application.js'`
+- `'path/application.js'`
+- `'application.js'`
+
+### Filters
+
+#### `code`
+
+Uses a [Pattern Capture token filter](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-pattern-capture-tokenfilter.html) to split tokens into more easily searched versions of themselves.
+
+Patterns:
+
+- `"(\\p{Ll}+|\\p{Lu}\\p{Ll}+|\\p{Lu}+)"`: captures CamelCase and lowerCamelCase strings as separate tokens
+- `"(\\d+)"`: extracts digits
+- `"(?=([\\p{Lu}]+[\\p{L}]+))"`: captures CamelCase strings recursively. For example: `ThisIsATest` => `[ThisIsATest, IsATest, ATest, Test]`
+- `'"((?:\\"|[^"]|\\")*)"'`: captures terms inside quotes, removing the quotes
+- `"'((?:\\'|[^']|\\')*)'"`: same as above, for single-quotes
+- `'\.([^.]+)(?=\.|\s|\Z)'`: separate terms with periods in-between
+- `'([\p{L}_.-]+)'`: some common chars in file names to keep the whole filename intact (for example `my_file-ñame.txt`)
+- `'([\p{L}\d_]+)'`: letters, numbers and underscores are the most common tokens in programming. Always capture them greedily regardless of context.
+
+## Gotchas
+
+- Searches can have their own analyzers. Remember to check when editing analyzers
+- `Character` filters (as opposed to token filters) always replace the original character, so they're not a good choice as they can hinder exact searches
+
+## Zero downtime reindexing with multiple indices
+
+NOTE:
+This is not applicable yet as multiple indices functionality is not fully implemented.
+
+Currently GitLab can only handle a single version of setting. Any setting/schema changes would require reindexing everything from scratch. Since reindexing can take a long time, this can cause search functionality downtime.
+
+To avoid downtime, GitLab is working to support multiple indices that
+can function at the same time. Whenever the schema changes, the administrator
+will be able to create a new index and reindex to it, while searches
+continue to go to the older, stable index. Any data updates will be
+forwarded to both indices. Once the new index is ready, an administrator can
+mark it active, which will direct all searches to it, and remove the old
+index.
+
+This is also helpful for migrating to new servers, for example, moving to/from AWS.
+
+Currently we are on the process of migrating to this new design. Everything is hardwired to work with one single version for now.
+
+### Architecture
+
+The traditional setup, provided by `elasticsearch-rails`, is to communicate through its internal proxy classes. Developers would write model-specific logic in a module for the model to include in (for example, `SnippetsSearch`). The `__elasticsearch__` methods would return a proxy object, for example:
+
+- `Issue.__elasticsearch__` returns an instance of `Elasticsearch::Model::Proxy::ClassMethodsProxy`
+- `Issue.first.__elasticsearch__` returns an instance of `Elasticsearch::Model::Proxy::InstanceMethodsProxy`.
+
+These proxy objects would talk to Elasticsearch server directly (see top half of the diagram).
+
+![Elasticsearch Architecture](img/elasticsearch_architecture.svg)
+
+In the planned new design, each model would have a pair of corresponding sub-classed proxy objects, in which model-specific logic is located. For example, `Snippet` would have `SnippetClassProxy` and `SnippetInstanceProxy` (being subclass of `Elasticsearch::Model::Proxy::ClassMethodsProxy` and `Elasticsearch::Model::Proxy::InstanceMethodsProxy`, respectively).
+
+`__elasticsearch__` would represent another layer of proxy object, keeping track of multiple actual proxy objects. It would forward method calls to the appropriate index. For example:
+
+- `model.__elasticsearch__.search` would be forwarded to the one stable index, since it is a read operation.
+- `model.__elasticsearch__.update_document` would be forwarded to all indices, to keep all indices up-to-date.
+
+The global configurations per version are now in the `Elastic::(Version)::Config` class. You can change mappings there.
+
+### Creating new version of schema
+
+NOTE:
+This is not applicable yet as multiple indices functionality is not fully implemented.
+
+Folders like `ee/lib/elastic/v12p1` contain snapshots of search logic from different versions. To keep a continuous Git history, the latest version lives under `ee/lib/elastic/latest`, but its classes are aliased under an actual version (for example, `ee/lib/elastic/v12p3`). When referencing these classes, never use the `Latest` namespace directly, but use the actual version (for example, `V12p3`).
+
+The version name basically follows the GitLab release version. If setting is changed in 12.3, we will create a new namespace called `V12p3` (p stands for "point"). Raise an issue if there is a need to name a version differently.
+
+If the current version is `v12p1`, and we need to create a new version for `v12p3`, the steps are as follows:
+
+1. Copy the entire folder of `v12p1` as `v12p3`
+1. Change the namespace for files under `v12p3` folder from `V12p1` to `V12p3` (which are still aliased to `Latest`)
+1. Delete `v12p1` folder
+1. Copy the entire folder of `latest` as `v12p1`
+1. Change the namespace for files under `v12p1` folder from `Latest` to `V12p1`
+1. Make changes to files under the `latest` folder as needed
+
+## Performance Monitoring
+
+### Prometheus
+
+GitLab exports [Prometheus metrics](../administration/monitoring/prometheus/gitlab_metrics.md)
+relating to the number of requests and timing for all web/API requests and Sidekiq jobs,
+which can help diagnose performance trends and compare how Elasticsearch timing
+is impacting overall performance relative to the time spent doing other things.
+
+#### Indexing queues
+
+GitLab also exports [Prometheus metrics](../administration/monitoring/prometheus/gitlab_metrics.md)
+for indexing queues, which can help diagnose performance bottlenecks and determine
+whether or not your GitLab instance or Elasticsearch server can keep up with
+the volume of updates.
+
+### Logs
+
+All of the indexing happens in Sidekiq, so much of the relevant logs for the
+Elasticsearch integration can be found in
+[`sidekiq.log`](../administration/logs/index.md#sidekiqlog). In particular, all
+Sidekiq workers that make requests to Elasticsearch in any way will log the
+number of requests and time taken querying/writing to Elasticsearch. This can
+be useful to understand whether or not your cluster is keeping up with
+indexing.
+
+Searching Elasticsearch is done via ordinary web workers handling requests. Any
+requests to load a page or make an API request, which then make requests to
+Elasticsearch, will log the number of requests and the time taken to
+[`production_json.log`](../administration/logs/index.md#production_jsonlog). These
+logs will also include the time spent on Database and Gitaly requests, which
+may help to diagnose which part of the search is performing poorly.
+
+There are additional logs specific to Elasticsearch that are sent to
+[`elasticsearch.log`](../administration/logs/index.md#elasticsearchlog)
+that may contain information to help diagnose performance issues.
+
+### Performance Bar
+
+Elasticsearch requests will be displayed in the
+[`Performance Bar`](../administration/monitoring/performance/performance_bar.md), which can
+be used both locally in development and on any deployed GitLab instance to
+diagnose poor search performance. This will show the exact queries being made,
+which is useful to diagnose why a search might be slow.
+
+### Correlation ID and `X-Opaque-Id`
+
+Our [correlation ID](distributed_tracing.md#developer-guidelines-for-working-with-correlation-ids)
+is forwarded by all requests from Rails to Elasticsearch as the
+[`X-Opaque-Id`](https://www.elastic.co/guide/en/elasticsearch/reference/current/tasks.html#_identifying_running_tasks)
+header which allows us to track any
+[tasks](https://www.elastic.co/guide/en/elasticsearch/reference/current/tasks.html)
+in the cluster back the request in GitLab.
+
+## Troubleshooting
+
+### Getting `flood stage disk watermark [95%] exceeded`
+
+You might get an error such as
+
+```plaintext
+[2018-10-31T15:54:19,762][WARN ][o.e.c.r.a.DiskThresholdMonitor] [pval5Ct]
+ flood stage disk watermark [95%] exceeded on
+ [pval5Ct7SieH90t5MykM5w][pval5Ct][/usr/local/var/lib/elasticsearch/nodes/0] free: 56.2gb[3%],
+ all indices on this node will be marked read-only
+```
+
+This is because you've exceeded the disk space threshold - it thinks you don't have enough disk space left, based on the default 95% threshold.
+
+In addition, the `read_only_allow_delete` setting will be set to `true`. It will block indexing, `forcemerge`, etc
+
+```shell
+curl "http://localhost:9200/gitlab-development/_settings?pretty"
+```
+
+Add this to your `elasticsearch.yml` file:
+
+```yaml
+# turn off the disk allocator
+cluster.routing.allocation.disk.threshold_enabled: false
+```
+
+_or_
+
+```yaml
+# set your own limits
+cluster.routing.allocation.disk.threshold_enabled: true
+cluster.routing.allocation.disk.watermark.flood_stage: 5gb # ES 6.x only
+cluster.routing.allocation.disk.watermark.low: 15gb
+cluster.routing.allocation.disk.watermark.high: 10gb
+```
+
+Restart Elasticsearch, and the `read_only_allow_delete` will clear on its own.
+
+_from "Disk-based Shard Allocation | Elasticsearch Reference" [5.6](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/disk-allocator.html#disk-allocator) and [6.x](https://www.elastic.co/guide/en/elasticsearch/reference/6.7/disk-allocator.html)_
+
+### Disaster recovery/data loss/backups
+
+The use of Elasticsearch in GitLab is only ever as a secondary data store.
+This means that all of the data stored in Elasticsearch can always be derived
+again from other data sources, specifically PostgreSQL and Gitaly. Therefore if
+the Elasticsearch data store is ever corrupted for whatever reason you can reindex
+everything from scratch.
+
+If your Elasticsearch index is incredibly large it may be too time consuming or
+cause too much downtime to reindex from scratch. There aren't any built in
+mechanisms for automatically finding discrepancies and resyncing an
+Elasticsearch index if it gets out of sync but one tool that may be useful is
+looking at the logs for all the updates that occurred in a time range you
+believe may have been missed. This information is very low level and only
+useful for operators that are familiar with the GitLab codebase. It is
+documented here in case it is useful for others. The relevant logs that could
+theoretically be used to figure out what needs to be replayed are:
+
+1. All non-repository updates that were synced can be found in
+ [`elasticsearch.log`](../administration/logs/index.md#elasticsearchlog) by
+ searching for
+ [`track_items`](https://gitlab.com/gitlab-org/gitlab/-/blob/1e60ea99bd8110a97d8fc481e2f41cab14e63d31/ee/app/services/elastic/process_bookkeeping_service.rb#L25)
+ and these can be replayed by sending these items again through
+ `::Elastic::ProcessBookkeepingService.track!`
+1. All repository updates that occurred can be found in
+ [`elasticsearch.log`](../administration/logs/index.md#elasticsearchlog) by
+ searching for
+ [`indexing_commit_range`](https://gitlab.com/gitlab-org/gitlab/-/blob/6f9d75dd3898536b9ec2fb206e0bd677ab59bd6d/ee/lib/gitlab/elastic/indexer.rb#L41).
+ Replaying these requires resetting the
+ [`IndexStatus#last_commit/last_wiki_commit`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/index_status.rb)
+ to the oldest `from_sha` in the logs and then triggering another index of
+ the project using
+ [`ElasticCommitIndexerWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic_commit_indexer_worker.rb)
+1. All project deletes that occurred can be found in
+ [`sidekiq.log`](../administration/logs/index.md#sidekiqlog) by searching for
+ [`ElasticDeleteProjectWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic_delete_project_worker.rb).
+ These updates can be replayed by triggering another
+ `ElasticDeleteProjectWorker`.
+
+With the above methods and taking regular
+[Elasticsearch snapshots](https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-restore.html)
+we should be able to recover from different kinds of data loss issues in a
+relatively short period of time compared to indexing everything from
+scratch.
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 94abbda9671..d29d9b9651f 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -875,7 +875,7 @@ module Types
graphql_name 'IssuableSeverity'
description 'Incident severity'
- ::IssuableSeverity.severities.keys.each do |severity|
+ ::IssuableSeverity.severities.each_key do |severity|
value severity.upcase, value: severity, description: "#{severity.titleize} severity."
end
end
diff --git a/doc/development/api_styleguide.md b/doc/development/api_styleguide.md
index 006d0a01abb..828ef21ba9a 100644
--- a/doc/development/api_styleguide.md
+++ b/doc/development/api_styleguide.md
@@ -333,6 +333,17 @@ expect(response).to match_response_schema('merge_requests')
Also see [verifying N+1 performance](#verifying-with-tests) in tests.
+## Error handling
+
+When throwing an error with a message that is meant to be user-facing, you should
+use the error message utility function contained in `lib/gitlab/utils/error_message.rb`.
+It adds a prefix to the error message, making it distinguishable from non-user-facing error messages.
+Please make sure that the Frontend is aware of the prefix usage and is using the according utils.
+
+```ruby
+Gitlab::Utils::ErrorMessage.to_user_facing('Example user-facing error-message')
+```
+
## Include a changelog entry
All client-facing changes **must** include a [changelog entry](changelog.md).
diff --git a/doc/development/application_slis/index.md b/doc/development/application_slis/index.md
index bd4587333e0..f48088a6e08 100644
--- a/doc/development/application_slis/index.md
+++ b/doc/development/application_slis/index.md
@@ -24,7 +24,7 @@ to be emitted from the rails application:
## Existing SLIs
-1. [`rails_request_apdex`](rails_request_apdex.md)
+1. [`rails_request`](rails_request.md)
1. `global_search_apdex`
1. `global_search_error_rate`
1. `global_search_indexing_apdex`
diff --git a/doc/development/application_slis/rails_request.md b/doc/development/application_slis/rails_request.md
new file mode 100644
index 00000000000..b3ee326aa87
--- /dev/null
+++ b/doc/development/application_slis/rails_request.md
@@ -0,0 +1,282 @@
+---
+stage: Platforms
+group: Scalability
+info: To 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 request SLIs (service level indicators)
+
+> [Introduced](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/525) in GitLab 14.4
+
+NOTE:
+This SLI is used for service monitoring. But not for [error budgets for stage groups](../stage_group_observability/index.md#error-budget)
+by default. You can [opt in](#error-budget-attribution-and-ownership).
+
+The request Apdex SLI and the error rate SLI are [SLIs defined in the application](index.md).
+
+The request Apdex measures the duration of successful requests as an indicator for
+application performance. This includes the REST and GraphQL API, and the
+regular controller endpoints.
+
+The error rate measures unsuccessful requests as an indicator for
+server misbehavior. This includes the REST API, and the
+regular controller endpoints.
+
+1. `gitlab_sli_rails_request_apdex_total`: This counter gets
+ incremented for every request that did not result in a response
+ with a `5xx` status code. It ensures slow failures are not
+ counted twice, because the request is already counted in the error SLI.
+
+1. `gitlab_sli_rails_request_apdex_success_total`: This counter gets
+ incremented for every successful request that performed faster than
+ the [defined target duration depending on the endpoint's urgency](#adjusting-request-urgency).
+
+1. `gitlab_sli_rails_request_error_total`: This counter gets
+ incremented for every request that resulted in a response
+ with a `5xx` status code.
+
+1. `gitlab_sli_rails_request_total`: This counter gets
+ incremented for every request.
+
+These counters are labeled with:
+
+1. `endpoint_id`: The identification of the Rails Controller or the
+ Grape-API endpoint.
+
+1. `feature_category`: The feature category specified for that
+ controller or API endpoint.
+
+## Request Apdex SLO
+
+These counters can be combined into a success ratio. The objective for
+this ratio is defined in the service catalog per service. For this SLI to meet SLO,
+the ratio recorded must be higher than:
+
+- [Web: 0.998](https://gitlab.com/gitlab-com/runbooks/blob/master/metrics-catalog/services/web.jsonnet#L19)
+- [API: 0.995](https://gitlab.com/gitlab-com/runbooks/blob/master/metrics-catalog/services/api.jsonnet#L19)
+- [Git: 0.998](https://gitlab.com/gitlab-com/runbooks/blob/master/metrics-catalog/services/git.jsonnet#L22)
+
+For example: for the web-service, we want at least 99.8% of requests
+to be faster than their target duration.
+
+We use these targets for alerting and service monitoring. Set durations taking
+these targets into account, so we don't cause alerts. The goal, however, is to
+set the urgency to a target that satisfies our users.
+
+Both successful measurements and unsuccessful ones affect the
+error budget for stage groups.
+
+## Adjusting request urgency
+
+Not all endpoints perform the same type of work, so it is possible to
+define different urgency levels for different endpoints. An endpoint with a
+lower urgency can have a longer request duration than endpoints with high urgency.
+
+Long-running requests are more expensive for our infrastructure. While serving
+one request, the thread remains occupied for the duration of that request. The thread
+can handle nothing else. Due to Ruby's Global VM Lock, the thread might keep the
+lock and stall other requests handled by the same Puma worker
+process. The request is, in fact, a noisy neighbor for other requests
+handled by the worker. We cap the upper bound for a target duration at 5 seconds
+for this reason.
+
+## Decreasing the urgency (setting a higher target duration)
+
+You can decrease the urgency on an existing endpoint on
+a case-by-case basis. Take the following into account:
+
+1. Apdex is about perceived performance. If a user is actively waiting
+ for the result of a request, waiting 5 seconds might not be
+ acceptable. However, if the endpoint is used by an automation
+ requiring a lot of data, 5 seconds could be acceptable.
+
+ A product manager can help to identify how an endpoint is used.
+
+1. The workload for some endpoints can sometimes differ greatly
+ depending on the parameters specified by the caller. The urgency
+ needs to accommodate those differences. In some cases, you could
+ define a separate [application SLI](index.md#defining-a-new-sli)
+ for what the endpoint is doing.
+
+ When the endpoints in certain cases turn into no-ops, making them
+ very fast, we should ignore these fast requests when setting the
+ target. For example, if the `MergeRequests::DraftsController` is
+ hit for every merge request being viewed, but rarely renders
+ anything, then we should pick the target that
+ would still accommodate the endpoint performing work.
+
+1. Consider the dependent resources consumed by the endpoint. If the endpoint
+ loads a lot of data from Gitaly or the database, and this causes
+ unsatisfactory performance, consider optimizing the
+ way the data is loaded rather than increasing the target duration
+ by lowering the urgency.
+
+ In these cases, it might be appropriate to temporarily decrease
+ urgency to make the endpoint meet SLO, if this is bearable for the
+ infrastructure. In such cases, create a code comment linking to an issue.
+
+ If the endpoint consumes a lot of CPU time, we should also consider
+ this: these kinds of requests are the kind of noisy neighbors we
+ should try to keep as short as possible.
+
+1. Traffic characteristics should also be taken into account. If the
+ traffic to the endpoint sometimes bursts, like CI traffic spinning up a
+ big batch of jobs hitting the same endpoint, then having these
+ endpoints take five seconds is unacceptable from an infrastructure point of
+ view. We cannot scale up the fleet fast enough to accommodate for
+ the incoming slow requests alongside the regular traffic.
+
+When lowering the urgency for an existing endpoint, please involve a
+[Scalability team member](https://about.gitlab.com/handbook/engineering/infrastructure/team/scalability/#team-members)
+in the review. We can use request rates and durations available in the
+logs to come up with a recommendation. You can pick a threshold
+using the same process as for
+[increasing urgency](#increasing-urgency-setting-a-lower-target-duration),
+picking a duration that is higher than the SLO for the service.
+
+We shouldn't set the longest durations on endpoints in the merge
+requests that introduces them, because we don't yet have data to support
+the decision.
+
+## Increasing urgency (setting a lower target duration)
+
+When increasing the urgency, we must make sure the endpoint
+still meets SLO for the fleet that handles the request. You can use the
+information in the logs to check:
+
+1. Open [this table in Kibana](https://log.gprd.gitlab.net/goto/bbb6465c68eb83642269e64a467df3df)
+
+1. The table loads information for the busiest endpoints by
+ default. To speed the response, add both:
+
+ - A filter for `json.meta.caller_id.keyword`.
+ - The identifier you're interested in, for example:
+
+ ```ruby
+ Projects::RawController#show
+ ```
+
+ or:
+
+ ```plaintext
+ GET /api/:version/projects/:id/snippets/:snippet_id/raw
+ ```
+
+1. Check the [appropriate percentile duration](#request-apdex-slo) for
+ the service handling the endpoint. The overall duration should
+ be lower than your intended target.
+
+1. If the overall duration is below the intended target, check the peaks over time
+ in [this graph](https://log.gprd.gitlab.net/goto/9319c4a402461d204d13f3a4924a89fc)
+ in Kibana. Here, the percentile in question should not peak above
+ the target duration we want to set.
+
+As decreasing a threshold too much could result in alerts for the
+Apdex degradation, please also involve a Scalability team member in
+the merge request.
+
+## How to adjust the urgency
+
+You can specify urgency similar to how endpoints
+[get a feature category](../feature_categorization/index.md). Endpoints without a
+specific target use the default urgency: 1s duration. These configurations
+are available:
+
+| Urgency | Duration in seconds | Notes |
+|------------|---------------------|-----------------------------------------------|
+| `:high` | 0.25s | |
+| `:medium` | 0.5s | |
+| `:default` | 1s | The default when nothing is specified. |
+| `:low` | 5s | |
+
+### Rails controller
+
+An urgency can be specified for all actions in a controller:
+
+```ruby
+class Boards::ListsController < ApplicationController
+ urgency :high
+end
+```
+
+To also specify the urgency for certain actions in a controller:
+
+```ruby
+class Boards::ListsController < ApplicationController
+ urgency :high, [:index, :show]
+end
+```
+
+A custom RSpec matcher is available to check endpoint's request urgency in the controller specs:
+
+```ruby
+specify do
+ expect(get(:index, params: request_params)).to have_request_urgency(:medium)
+end
+```
+
+### Grape endpoints
+
+To specify the urgency for an entire API class:
+
+```ruby
+module API
+ class Issues < ::API::Base
+ urgency :low
+ end
+end
+```
+
+To specify the urgency also for certain actions in a API class:
+
+```ruby
+module API
+ class Issues < ::API::Base
+ urgency :medium, [
+ '/groups/:id/issues',
+ '/groups/:id/issues_statistics'
+ ]
+ end
+end
+```
+
+Or, we can specify the urgency per endpoint:
+
+```ruby
+get 'client/features', urgency: :low do
+ # endpoint logic
+end
+```
+
+A custom RSpec matcher is also compatible with grape endpoints' specs:
+
+```ruby
+
+specify do
+ expect(get(api('/avatar'), params: { email: 'public@example.com' })).to have_request_urgency(:medium)
+end
+```
+
+WARNING:
+We can't specify the urgency at the namespace level. The directive is ignored when doing so.
+
+### Error budget attribution and ownership
+
+This SLI is used for service level monitoring. It feeds into the
+[error budget for stage groups](../stage_group_observability/index.md#error-budget).
+
+For more information, read the epic for
+[defining custom SLIs and incorporating them into error budgets](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/525)).
+The endpoints for the SLI feed into a group's error budget based on the
+[feature category declared on it](../feature_categorization/index.md).
+
+To know which endpoints are included for your group, you can see the
+request rates on the
+[group dashboard for your group](https://dashboards.gitlab.net/dashboards/f/stage-groups/stage-groups).
+In the **Budget Attribution** row, the **Puma Apdex** log link shows you
+how many requests are not meeting a 1s or 5s target.
+
+For more information about the content of the dashboard, see
+[Dashboards for stage groups](../stage_group_observability/index.md). For more information
+about our exploration of the error budget itself, see
+[issue 1365](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1365).
diff --git a/doc/development/application_slis/rails_request_apdex.md b/doc/development/application_slis/rails_request_apdex.md
deleted file mode 100644
index dc9d67b0a2b..00000000000
--- a/doc/development/application_slis/rails_request_apdex.md
+++ /dev/null
@@ -1,253 +0,0 @@
----
-stage: Platforms
-group: Scalability
-info: To 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 request Apdex SLI
-
-> [Introduced](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/525) in GitLab 14.4
-
-NOTE:
-This SLI is used for service monitoring. But not for [error budgets for stage groups](../stage_group_observability/index.md#error-budget)
-by default. You can [opt in](#error-budget-attribution-and-ownership).
-
-The request Apdex SLI (Service Level Indicator) is [an SLI defined in the application](index.md).
-It measures the duration of successful requests as an indicator for
-application performance. This includes the REST and GraphQL API, and the
-regular controller endpoints. It consists of these counters:
-
-1. `gitlab_sli:rails_request_apdex:total`: This counter gets
- incremented for every request that did not result in a response
- with a `5xx` status code. It ensures slow failures are not
- counted twice, because the request is already counted in the error SLI.
-
-1. `gitlab_sli:rails_request_apdex:success_total`: This counter gets
- incremented for every successful request that performed faster than
- the [defined target duration depending on the endpoint's urgency](#adjusting-request-urgency).
-
-Both these counters are labeled with:
-
-1. `endpoint_id`: The identification of the Rails Controller or the
- Grape-API endpoint.
-
-1. `feature_category`: The feature category specified for that
- controller or API endpoint.
-
-## Request Apdex SLO
-
-These counters can be combined into a success ratio. The objective for
-this ratio is defined in the service catalog per service. For this SLI to meet SLO,
-the ratio recorded must be higher than:
-
-- [Web: 0.998](https://gitlab.com/gitlab-com/runbooks/blob/master/metrics-catalog/services/web.jsonnet#L19)
-- [API: 0.995](https://gitlab.com/gitlab-com/runbooks/blob/master/metrics-catalog/services/api.jsonnet#L19)
-- [Git: 0.998](https://gitlab.com/gitlab-com/runbooks/blob/master/metrics-catalog/services/git.jsonnet#L22)
-
-For example: for the web-service, we want at least 99.8% of requests
-to be faster than their target duration.
-
-We use these targets for alerting and service monitoring. Set durations taking
-these targets into account, so we don't cause alerts. The goal, however, is to
-set the urgency to a target that satisfies our users.
-
-Both successful measurements and unsuccessful ones affect the
-error budget for stage groups.
-
-## Adjusting request urgency
-
-Not all endpoints perform the same type of work, so it is possible to
-define different urgency levels for different endpoints. An endpoint with a
-lower urgency can have a longer request duration than endpoints with high urgency.
-
-Long-running requests are more expensive for our infrastructure. While serving
-one request, the thread remains occupied for the duration of that request. The thread
-can handle nothing else. Due to Ruby's Global VM Lock, the thread might keep the
-lock and stall other requests handled by the same Puma worker
-process. The request is, in fact, a noisy neighbor for other requests
-handled by the worker. We cap the upper bound for a target duration at 5 seconds
-for this reason.
-
-## Decreasing the urgency (setting a higher target duration)
-
-You can decrease the urgency on an existing endpoint on
-a case-by-case basis. Take the following into account:
-
-1. Apdex is about perceived performance. If a user is actively waiting
- for the result of a request, waiting 5 seconds might not be
- acceptable. However, if the endpoint is used by an automation
- requiring a lot of data, 5 seconds could be acceptable.
-
- A product manager can help to identify how an endpoint is used.
-
-1. The workload for some endpoints can sometimes differ greatly
- depending on the parameters specified by the caller. The urgency
- needs to accommodate those differences. In some cases, you could
- define a separate [application SLI](index.md#defining-a-new-sli)
- for what the endpoint is doing.
-
- When the endpoints in certain cases turn into no-ops, making them
- very fast, we should ignore these fast requests when setting the
- target. For example, if the `MergeRequests::DraftsController` is
- hit for every merge request being viewed, but rarely renders
- anything, then we should pick the target that
- would still accommodate the endpoint performing work.
-
-1. Consider the dependent resources consumed by the endpoint. If the endpoint
- loads a lot of data from Gitaly or the database, and this causes
- unsatisfactory performance, consider optimizing the
- way the data is loaded rather than increasing the target duration
- by lowering the urgency.
-
- In these cases, it might be appropriate to temporarily decrease
- urgency to make the endpoint meet SLO, if this is bearable for the
- infrastructure. In such cases, create a code comment linking to an issue.
-
- If the endpoint consumes a lot of CPU time, we should also consider
- this: these kinds of requests are the kind of noisy neighbors we
- should try to keep as short as possible.
-
-1. Traffic characteristics should also be taken into account. If the
- traffic to the endpoint sometimes bursts, like CI traffic spinning up a
- big batch of jobs hitting the same endpoint, then having these
- endpoints take five seconds is unacceptable from an infrastructure point of
- view. We cannot scale up the fleet fast enough to accommodate for
- the incoming slow requests alongside the regular traffic.
-
-When lowering the urgency for an existing endpoint, please involve a
-[Scalability team member](https://about.gitlab.com/handbook/engineering/infrastructure/team/scalability/#team-members)
-in the review. We can use request rates and durations available in the
-logs to come up with a recommendation. You can pick a threshold
-using the same process as for
-[increasing urgency](#increasing-urgency-setting-a-lower-target-duration),
-picking a duration that is higher than the SLO for the service.
-
-We shouldn't set the longest durations on endpoints in the merge
-requests that introduces them, because we don't yet have data to support
-the decision.
-
-## Increasing urgency (setting a lower target duration)
-
-When increasing the urgency, we must make sure the endpoint
-still meets SLO for the fleet that handles the request. You can use the
-information in the logs to check:
-
-1. Open [this table in Kibana](https://log.gprd.gitlab.net/goto/bbb6465c68eb83642269e64a467df3df)
-
-1. The table loads information for the busiest endpoints by
- default. To speed the response, add both:
-
- - A filter for `json.meta.caller_id.keyword`.
- - The identifier you're interested in, for example:
-
- ```ruby
- Projects::RawController#show
- ```
-
- or:
-
- ```plaintext
- GET /api/:version/projects/:id/snippets/:snippet_id/raw
- ```
-
-1. Check the [appropriate percentile duration](#request-apdex-slo) for
- the service handling the endpoint. The overall duration should
- be lower than your intended target.
-
-1. If the overall duration is below the intended target, check the peaks over time
- in [this graph](https://log.gprd.gitlab.net/goto/9319c4a402461d204d13f3a4924a89fc)
- in Kibana. Here, the percentile in question should not peak above
- the target duration we want to set.
-
-As decreasing a threshold too much could result in alerts for the
-Apdex degradation, please also involve a Scalability team member in
-the merge request.
-
-## How to adjust the urgency
-
-You can specify urgency similar to how endpoints
-[get a feature category](../feature_categorization/index.md). Endpoints without a
-specific target use the default urgency: 1s duration. These configurations
-are available:
-
-| Urgency | Duration in seconds | Notes |
-|------------|---------------------|-----------------------------------------------|
-| `:high` | 0.25s | |
-| `:medium` | 0.5s | |
-| `:default` | 1s | The default when nothing is specified. |
-| `:low` | 5s | |
-
-### Rails controller
-
-An urgency can be specified for all actions in a controller:
-
-```ruby
-class Boards::ListsController < ApplicationController
- urgency :high
-end
-```
-
-To also specify the urgency for certain actions in a controller:
-
-```ruby
-class Boards::ListsController < ApplicationController
- urgency :high, [:index, :show]
-end
-```
-
-### Grape endpoints
-
-To specify the urgency for an entire API class:
-
-```ruby
-module API
- class Issues < ::API::Base
- urgency :low
- end
-end
-```
-
-To specify the urgency also for certain actions in a API class:
-
-```ruby
-module API
- class Issues < ::API::Base
- urgency :medium, [
- '/groups/:id/issues',
- '/groups/:id/issues_statistics'
- ]
- end
-end
-```
-
-Or, we can specify the urgency per endpoint:
-
-```ruby
-get 'client/features', urgency: :low do
- # endpoint logic
-end
-```
-
-WARNING:
-We can't specify the urgency at the namespace level. The directive is ignored when doing so.
-
-### Error budget attribution and ownership
-
-This SLI is used for service level monitoring. It feeds into the
-[error budget for stage groups](../stage_group_observability/index.md#error-budget).
-
-For more information, read the epic for
-[defining custom SLIs and incorporating them into error budgets](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/525)).
-The endpoints for the SLI feed into a group's error budget based on the
-[feature category declared on it](../feature_categorization/index.md).
-
-To know which endpoints are included for your group, you can see the
-request rates on the
-[group dashboard for your group](https://dashboards.gitlab.net/dashboards/f/stage-groups/stage-groups).
-In the **Budget Attribution** row, the **Puma Apdex** log link shows you
-how many requests are not meeting a 1s or 5s target.
-
-For more information about the content of the dashboard, see
-[Dashboards for stage groups](../stage_group_observability/index.md). For more information
-about our exploration of the error budget itself, see
-[issue 1365](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1365).
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index 96b70e2fbd8..7a9c3572406 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -448,7 +448,7 @@ Consul is a tool for service discovery and configuration. Consul is distributed,
- [Source](../integration/advanced_search/elasticsearch.md)
- [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/howto/elasticsearch.md)
- Layer: Core Service (Data)
-- GitLab.com: [Get Advanced Search working on GitLab.com (Closed)](https://gitlab.com/groups/gitlab-org/-/epics/153) epic.
+- GitLab.com: [Get advanced search working on GitLab.com (Closed)](https://gitlab.com/groups/gitlab-org/-/epics/153) epic.
Elasticsearch is a distributed RESTful search engine built for the cloud.
@@ -695,7 +695,7 @@ Prometheus exporter for PgBouncer. Exports metrics at 9127/metrics.
- [Source](../install/installation.md#6-database)
- Layer: Core Service (Data)
- Process: `postgresql`
-- GitLab.com: [PostgreSQL](../user/gitlab_com/index.md#postgresql)
+- GitLab.com: [PostgreSQL](https://about.gitlab.com/handbook/engineering/infrastructure/database/)
GitLab packages the popular Database to provide storage for Application meta data and user information.
@@ -1101,12 +1101,29 @@ PostgreSQL:
GitLab has configuration files located in `/home/git/gitlab/config/*`. Commonly referenced
configuration files include:
-- `gitlab.yml`: GitLab configuration
+- `gitlab.yml`: GitLab Rails configuration
- `puma.rb`: Puma web server settings
- `database.yml`: Database connection settings
GitLab Shell has a configuration file at `/home/git/gitlab-shell/config.yml`.
+#### Adding a new setting in GitLab Rails
+
+Settings which belong in `gitlab.yml` include those related to:
+
+- How the application is wired together across multiple services. For example, Gitaly addresses, Redis addresses, Postgres addresses, and Consul addresses.
+- Distributed Tracing configuration, and some observability configurations. For example, histogram bucket boundaries.
+- Anything that needs to be configured during Rails initialization, possibly before the Postgres connection has been established.
+
+Many other settings are better placed in the app itself, in `ApplicationSetting`. Managing settings in UI is usually a better user experience compared to managing configuration files. With respect to development cost, modifying `gitlab.yml` often seems like a faster iteration, but when you consider all the deployment methods below, it may be a poor tradeoff.
+
+When adding a setting to `gitlab.yml`:
+
+1. Ensure that it is also
+ [added to Omnibus](https://docs.gitlab.com/omnibus/settings/gitlab.yml#adding-a-new-setting-to-gitlabyml).
+1. Ensure that it is also [added to Charts](https://docs.gitlab.com/charts/development/style_guide.html), if needed.
+1. Ensure that it is also [added to GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/support/templates/gitlab/config/gitlab.yml.erb).
+
### Maintenance tasks
[GitLab](https://gitlab.com/gitlab-org/gitlab/-/tree/master) provides Rake tasks with which you see version information and run a quick check on your configuration to ensure it is configured properly within the application. See [maintenance Rake tasks](../administration/raketasks/maintenance.md).
diff --git a/doc/development/audit_event_guide/index.md b/doc/development/audit_event_guide/index.md
index 8df5121a2f7..c7c723d1686 100644
--- a/doc/development/audit_event_guide/index.md
+++ b/doc/development/audit_event_guide/index.md
@@ -4,7 +4,7 @@ group: Compliance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Audit Event Guide
+# Audit event development guidelines
This guide provides an overview of how Audit Events work, and how to instrument
new audit events.
diff --git a/doc/development/auto_devops.md b/doc/development/auto_devops.md
index 53033cd19ff..b2281f9c032 100644
--- a/doc/development/auto_devops.md
+++ b/doc/development/auto_devops.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Auto DevOps development guide
+# Auto DevOps development guidelines
This document provides a development guide for contributors to
[Auto DevOps](../topics/autodevops/index.md).
diff --git a/doc/development/backend/create_source_code_be/gitaly_touch_points.md b/doc/development/backend/create_source_code_be/gitaly_touch_points.md
index 6ee2c7f0e51..c689af2f150 100644
--- a/doc/development/backend/create_source_code_be/gitaly_touch_points.md
+++ b/doc/development/backend/create_source_code_be/gitaly_touch_points.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## RPCs
-Gitaly is a wrapper around the `git` binary, running in a [Gitaly Cluster](../../../administration/gitaly/index.md). It provides managed access to the file system housing the `git` repositories, via Golang Remote Procedure Calls (RPCs). Other functions are access optimization, caching, and a form of pagination against the file system.
+Gitaly is a wrapper around the `git` binary, running in a [Gitaly Cluster](../../../administration/gitaly/index.md). It provides managed access to the file system housing the `git` repositories, using Go Remote Procedure Calls (RPCs). Other functions are access optimization, caching, and a form of pagination against the file system.
The comprehensive [Beginner's guide to Gitaly contributions](https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/beginners_guide.md) is focused on making updates to Gitaly, and offers many insights into how to understand the Gitaly code.
diff --git a/doc/development/backend/create_source_code_be/index.md b/doc/development/backend/create_source_code_be/index.md
index 77c98982210..d894a14b006 100644
--- a/doc/development/backend/create_source_code_be/index.md
+++ b/doc/development/backend/create_source_code_be/index.md
@@ -4,16 +4,16 @@ 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
---
-# Create: Source Code Backend
+# Create: Source Code backend
-The Create:Source Code BE team focuses on the GitLab suite of Source Code Management
+The Create: Source Code backend (BE) team focuses on the GitLab suite of Source Code Management
(SCM) tools. It is responsible for all backend aspects of the product categories
that fall under the [Source Code group](https://about.gitlab.com/handbook/product/categories/#source-code-group)
of the [Create stage](https://about.gitlab.com/handbook/product/categories/#create-stage)
of the [DevOps lifecycle](https://about.gitlab.com/handbook/product/categories/#devops-stages).
We interface with the Gitaly and Code Review teams, and work closely with the
-[Create:Source Code Frontend team](https://about.gitlab.com/handbook/engineering/development/dev/create/create-source-code-fe/). The features
+[Create: Source Code frontend team](https://about.gitlab.com/handbook/engineering/development/dev/create/create-source-code-fe/). The features
we work with are listed on the
[Features by Group Page](https://about.gitlab.com/handbook/product/categories/features/#createsource-code-group).
@@ -39,7 +39,7 @@ To learn about the reasoning behind our creation of `gitlab-sshd`, read the blog
### Gitaly touch points
-Gitaly is a Golang RPC service which handles all the `git` calls made by GitLab.
+Gitaly is a Go RPC service which handles all the `git` calls made by GitLab.
GitLab is not exposed directly, and all traffic comes through Create: Source Code.
For more information, read [Gitaly touch points](gitaly_touch_points.md).
diff --git a/doc/development/bulk_import.md b/doc/development/bulk_import.md
index 0d9c7348915..23976d09389 100644
--- a/doc/development/bulk_import.md
+++ b/doc/development/bulk_import.md
@@ -37,13 +37,14 @@ idea is to have one ETL pipeline for each relation to be imported.
### API
-The current [Project](../user/project/settings/import_export.md) and [Group](../user/group/settings/import_export.md) Import are file based, so they require an export
-step to generate the file to be imported.
+The current [project](../user/project/settings/import_export.md) and
+[group](../user/group/import/index.md#migrate-groups-by-uploading-an-export-file-deprecated) imports are file based, so
+they require an export step to generate the file to be imported.
-GitLab Group migration leverages on [GitLab API](../api/rest/index.md) to speed the migration.
+Group migration by direct transfer leverages the [GitLab API](../api/rest/index.md) to speed the migration.
And, because we're on the road to [GraphQL](../api/graphql/index.md),
-GitLab Group Migration will be contributing towards to expand the GraphQL API coverage, which benefits both GitLab
+Group migration by direct transfer can contribute to expanding GraphQL API coverage, which benefits both GitLab
and its users.
### Namespace
diff --git a/doc/development/caching.md b/doc/development/caching.md
index 9b3f9a4215e..dff94b68ca0 100644
--- a/doc/development/caching.md
+++ b/doc/development/caching.md
@@ -332,11 +332,11 @@ views/projects/_home_panel:462ad2485d7d6957e03ceba2c6717c29/projects/16-20210316
```
1. The view name and template tree digest
- `views/projects/_home_panel:462ad2485d7d6957e03ceba2c6717c29`
+ `views/projects/_home_panel:462ad2485d7d6957e03ceba2c6717c29`
1. The model name, ID, and `updated_at` values
- `projects/16-20210316142425469452`
+ `projects/16-20210316142425469452`
1. The symbol we passed in, converted to a string
- `tag_list`
+ `tag_list`
### Look for
diff --git a/doc/development/cascading_settings.md b/doc/development/cascading_settings.md
index 389623e68d8..42f4b5dd6f3 100644
--- a/doc/development/cascading_settings.md
+++ b/doc/development/cascading_settings.md
@@ -23,13 +23,13 @@ Settings are not cascading by default. To define a cascading setting, take the f
1. In the `NamespaceSetting` model, define the new attribute using the `cascading_attr`
helper method. You can use an array to define multiple attributes on a single line.
- ```ruby
- class NamespaceSetting
- include CascadingNamespaceSettingAttribute
+ ```ruby
+ class NamespaceSetting
+ include CascadingNamespaceSettingAttribute
- cascading_attr :delayed_project_removal
- end
- ```
+ cascading_attr :delayed_project_removal
+ end
+ ```
1. Create the database columns.
@@ -37,21 +37,21 @@ Settings are not cascading by default. To define a cascading setting, take the f
The helper creates four columns, two each in `namespace_settings` and
`application_settings`.
- ```ruby
- class AddDelayedProjectRemovalCascadingSetting < Gitlab::Database::Migration[2.1]
- include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings
+ ```ruby
+ class AddDelayedProjectRemovalCascadingSetting < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings
- enable_lock_retries!
+ enable_lock_retries!
- def up
- add_cascading_namespace_setting :delayed_project_removal, :boolean, default: false, null: false
- end
+ def up
+ add_cascading_namespace_setting :delayed_project_removal, :boolean, default: false, null: false
+ end
- def down
- remove_cascading_namespace_setting :delayed_project_removal
- end
- end
- ```
+ def down
+ remove_cascading_namespace_setting :delayed_project_removal
+ end
+ end
+ ```
Existing settings being converted to a cascading setting will require individual
migrations to add columns and change existing columns. Use the specifications
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index 27bcffe7560..56b5fa8c976 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -94,7 +94,7 @@ EE: true
uses system fonts for all text."
- Any client-facing change to our REST and GraphQL APIs **must** have a changelog entry.
See the [complete list what comprises a GraphQL breaking change](api_graphql_styleguide.md#breaking-changes).
-- Any change that introduces an [Advanced Search migration](elasticsearch.md#creating-a-new-advanced-search-migration)
+- Any change that introduces an [advanced search migration](search/advanced_search_migration_styleguide.md#creating-a-new-advanced-search-migration)
**must** have a changelog entry.
- A fix for a regression introduced and then fixed in the same release (such as
fixing a bug introduced during a monthly release candidate) **should not**
diff --git a/doc/development/cicd/cicd_tables.md b/doc/development/cicd/cicd_tables.md
new file mode 100644
index 00000000000..c86540c10f0
--- /dev/null
+++ b/doc/development/cicd/cicd_tables.md
@@ -0,0 +1,119 @@
+---
+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
+---
+
+# Add new tables to the CI database
+
+The [pipeline data partitioning](../../architecture/blueprints/ci_data_decay/pipeline_partitioning.md)
+design blueprint describes how to partition existing tables in the CI domain. However,
+you still need to add tables for new features. Sometimes these tables hold
+references to larger tables that need to be partitioned. To reduce future
+work, all tables that use a `belongs_to` association to partitionable tables
+should be partitioned from the start.
+
+## Create a new routing table
+
+The database helpers for creating tables do not accept partitioning options,
+so the best solution is to create the tables using raw SQL:
+
+```ruby
+ enable_lock_retries!
+
+ def up
+ execute(<<~SQL)
+ CREATE TABLE p_ci_examples (
+ id bigint NOT NULL,
+ partition_id bigint NOT NULL,
+ build_id bigint NOT NULL,
+ PRIMARY KEY (id, partition_id),
+ CONSTRAINT fk_bb490f12fe_p FOREIGN KEY (partition_id, build_id)
+ REFERENCES ci_builds(partition_id, id)
+ ON UPDATE CASCADE ON DELETE CASCADE
+ )
+ PARTITION BY LIST (partition_id);
+ SQL
+ end
+
+ def down
+ drop_table :p_ci_examples
+ end
+```
+
+This table is called a routing table and it does not hold any data. The
+data is stored in partitions.
+
+When creating the routing table:
+
+- The table name must start with the `p_` prefix. There are analyzers in place to ensure that all queries go
+ through the routing tables and do not access the partitions directly.
+- Each new table needs a `partition_id` column and its value must equal
+ the value from the related association. In this example, that is `ci_builds`. All resources
+ belonging to a pipeline share the same `partition_id` value.
+- The primary key must have the columns ordered this way to allow efficient
+ search only by `id`.
+- The foreign key constraint must include the `ON UPDATE CASCADE` option because
+ the `partition_id` value should be able to update it for re-balancing the
+ partitions.
+
+## Create the first partition
+
+Usually, you rely on the application to create the initial partition at boot time.
+However, due to the high traffic on the CI tables and the large number of nodes,
+it can be difficult to acquire a lock on the referenced table.
+Consequently, during deployment, a node may fail to start.
+To prevent this failure, you must ensure that the partition is already in place before
+the application runs:
+
+```ruby
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ connection.execute(<<~SQL)
+ LOCK TABLE ci_builds IN SHARE UPDATE EXCLUSIVE MODE;
+ LOCK TABLE ONLY p_ci_examples IN ACCESS EXCLUSIVE MODE;
+ SQL
+
+ connection.execute(<<~SQL)
+ CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_examples_100
+ PARTITION OF p_ci_examples
+ FOR VALUES IN (100);
+ SQL
+ end
+ end
+```
+
+Partitions are created in `gitlab_partitions_dynamic` schema.
+
+When creating a partition, remember:
+
+- Partition names do not use the `p_` prefix.
+- The default value for `partition_id` is `100`.
+
+## Cascade the partition value
+
+To cascade the partition value, the module should use the `Ci::Partitionable` module:
+
+```ruby
+class Ci::Example < Ci::ApplicationRecord
+ include Ci::Partitionable
+
+ self.table_name = :p_ci_examples
+ self.primary_key = :id
+
+ belongs_to :build, class_name: 'Ci::Build'
+ partitionable scope: :build, partitioned: true
+end
+```
+
+## Manage partitions
+
+The model must be included in the [`PARTITIONABLE_MODELS`](https://gitlab.com/gitlab-org/gitlab/-/blob/920147293ae304639915f66b260dc14e4f629850/app/models/concerns/ci/partitionable.rb#L25-44)
+list because it is used to test that the `partition_id` is
+propagated correctly.
+
+If it's missing, specifying `partitioned: true` creates the first partition. The model also needs to be registered in the
+[`postgres_partitioning.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/920147293ae304639915f66b260dc14e4f629850/config/initializers/postgres_partitioning.rb)
+initializer.
diff --git a/doc/development/cicd/index.md b/doc/development/cicd/index.md
index 641d0ea4f6f..2cc8fca02dd 100644
--- a/doc/development/cicd/index.md
+++ b/doc/development/cicd/index.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: index, concepts, howto
---
-# CI/CD development documentation
+# CI/CD development guidelines
Development guides that are specific to CI/CD are listed here:
@@ -147,6 +147,7 @@ This API endpoint runs [`Ci::RegisterJobService`](https://gitlab.com/gitlab-org/
There are 3 top level queries that this service uses to gather the majority of the jobs and they are selected based on the level where the runner is registered to:
- Select jobs for shared runner (instance level)
+ - Utilizes a fair scheduling algorithm which prioritizes projects with fewer running builds
- Select jobs for group runner
- Select jobs for project runner
diff --git a/doc/development/cicd/templates.md b/doc/development/cicd/templates.md
index 4f6799d12d8..1bf4a780e26 100644
--- a/doc/development/cicd/templates.md
+++ b/doc/development/cicd/templates.md
@@ -436,7 +436,6 @@ To add a metric definition for a new template:
```yaml
- name: p_ci_templates_my_template_name
category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
```
diff --git a/doc/development/code_intelligence/index.md b/doc/development/code_intelligence/index.md
index 107a1588e18..2034f57d995 100644
--- a/doc/development/code_intelligence/index.md
+++ b/doc/development/code_intelligence/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
---
-# Code Intelligence
+# Code intelligence development guidelines
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/1576) in GitLab 13.1.
diff --git a/doc/development/code_owners/index.md b/doc/development/code_owners/index.md
new file mode 100644
index 00000000000..fa0385777e8
--- /dev/null
+++ b/doc/development/code_owners/index.md
@@ -0,0 +1,132 @@
+---
+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
+---
+
+# Code Owners development guidelines
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/219916) in GitLab 15.10.
+
+This document was created to help contributors understand the code design of
+[Code Owners](../../user/project/code_owners.md). You should read this
+document before making changes to the code for this feature.
+
+This document is intentionally limited to an overview of how the code is
+designed, as code can change often. To understand how a specific part of the
+feature works, view the code and the specs. The details here explain how the
+major components of the Code Owners feature work.
+
+NOTE:
+This document should be updated when parts of the codebase referenced in this
+document are updated, removed, or new parts are added.
+
+## Business logic
+
+All of the business logic for code owners is located in the `Gitlab::CodeOwners`
+namespace. Code Owners is an EE-only feature, so the files only exist in the `./ee` directory.
+
+- `Gitlab::CodeOwners`: the main module used to interact with the code owner rules.
+ - Defined in `./ee/lib/gitlab/code_owners.rb`.
+- `Gitlab::CodeOwners::Loader`: finds the correct `CODEOWNER` file and loads the
+ content into a `Gitlab::CodeOwners::File` instance.
+ - Defined in `./ee/lib/gitlab/code_owners/loader.rb`.
+- `Gitlab::CodeOwners::ReferenceExtractor`: extracts `CODEOWNER` user, group,
+ and email references from texts.
+ - Defined in `./ee/lib/gitlab/code_owners/reference_extractor.rb`.
+- `Gitlab::CodeOwners::UsersLoader`: the correct `CODEOWNER` file and loads the
+ content into a `Gitlab::CodeOwners::File` instance.
+ - Defined in `./ee/lib/gitlab/code_owners/users_loader.rb`.
+- `Gitlab::CodeOwners::GroupsLoader`: finds the correct `CODEOWNER` file and loads
+ the content into a `Gitlab::CodeOwners::File` instance.
+ - Defined in `./ee/lib/gitlab/code_owners/groups_loader.rb`.
+- `Gitlab::CodeOwners::File`: wraps a `CODEOWNERS` file and exposes the data through
+ the class' public methods.
+ - Defined in `./ee/lib/gitlab/code_owners/file.rb`.
+- `Gitlab::CodeOwners::Entry`: wraps an entry (a pattern and owners line) in a
+ `CODEOWNERS` file and exposes the data through the class' public methods.
+ - Defined in `./ee/lib/gitlab/code_owners/entry.rb`.
+- `Gitlab::CodeOwners::Validator`: validates no files in the `CODEOWNERS` entries
+ have been changed when a user pushes to a protected branch with `require_code_owner_approval` enabled.
+ - Defined in `./ee/lib/gitlab/code_owners/validator.rb`.
+
+## Related models
+
+### `ProtectedBranch`
+
+The `ProtectedBranch` model is defined in `app/models/protected_branch.rb` and
+extended in `ee/app/ee/models/protected_branch.rb`. The EE version includes a column
+named `require_code_owner_approval` which prevents changes from being pushed directly
+to the branch being protected if the file is listed in `CODEOWNERS`.
+
+### `ApprovalMergeRequestRule`
+
+The `ApprovalMergeRequestRule` model is defined in `ee/app/models/approval_merge_request_rule.rb`.
+The model stores approval rules for a merge request. We use multiple rule types,
+including a `code_owner` type rule.
+
+## Controllers and Services
+
+The following controllers and services below are being used for the approval
+rules feature to work:
+
+### `Api::Internal::Base`
+
+This `/internal/allowed` endpoint is called when pushing to GitLab to ensure the
+user is allowed to push. The `/internal/allowed` endpoint performs a `Gitlab::Checks::DiffCheck`.
+In EE, this includes code owner checks.
+
+Defined in `lib/api/internal/base.rb`.
+
+### `Repositories::GitHttpController`
+
+When changes are pushed to GitLab over HTTP, the controller performs an access check
+to ensure the user is allowed to push. The checks perform a `Gitlab::Checks::DiffCheck`.
+In EE, this includes Code Owner checks.
+
+Defined in `app/controllers/repositories/git_http_controller.rb`.
+
+### `EE::Gitlab::Checks::DiffCheck`
+
+This module extends the CE `Gitlab::Checks::DiffChecks` class and adds code owner
+validation. It uses the `Gitlab::CodeOwner::Validator` class to verify users are
+not pushing files listed in `CODEOWNER` directly to a protected branch while the
+branch requires code owner approval.
+
+### `MergeRequests::SyncCodeOwnerApprovalRules`
+
+This service is defined in `services/merge_requests/sync_code_owner_approval_rules.rb` and used for:
+
+- Deleting outdated code owner approval rules when new changes are pushed to a merge request.
+- Creating code owner approval rules for each changed file in a merge request that is also listed in the `CODEOWNER` file.
+
+## Flow
+
+These flowcharts should help explain the flow from the controllers down to the
+models for different features.
+
+### Push changes to a protected branch with `require_code_owner_approval` enabled
+
+```mermaid
+graph TD
+ Api::Internal::Base --> Gitlab::GitAccess
+ Gitlab::GitAccess --> Gitlab::Checks::DiffCheck
+ Gitlab::Checks::DiffCheck --> Gitlab::CodeOwners::Validator
+ Gitlab::CodeOwners::Validator --> ProtectedBranch
+ Gitlab::CodeOwners::Validator --> Gitlab::CodeOwners::Loader
+ Gitlab::CodeOwners::Loader --> Gitlab::CodeOwners::Entry
+```
+
+### Sync code owner rules to merge request approval rules
+
+```mermaid
+graph TD
+ EE::ProtectedBranches::CreateService --> MergeRequest::SyncCodeOwnerApprovalRules
+ EE::MergeRequestRefreshService --> MergeRequest::SyncCodeOwnerApprovalRules
+ EE::MergeRequests::ReloadMergeHeadDiffService --> MergeRequest::SyncCodeOwnerApprovalRules
+ EE::MergeRequests::CreateService --> MergeRequests::SyncCodeOwnerApprovalRulesWorker
+ EE::MergeRequests::UpdateService --> MergeRequests::SyncCodeOwnerApprovalRulesWorker
+ MergeRequests::SyncCodeOwnerApprovalRulesWorker --> MergeRequest::SyncCodeOwnerApprovalRules
+ MergeRequest::SyncCodeOwnerApprovalRules --> id1{delete outdated code owner rules}
+ MergeRequest::SyncCodeOwnerApprovalRules --> id2{create rule for each code owner entry}
+```
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 245fb2152cd..ed9404187ae 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -68,6 +68,9 @@ When a suitable [domain expert](#domain-experts) isn't available, you can choose
To find a domain expert:
+- In the Merge Request approvals widget, select [View eligible approvers](../user/project/merge_requests/approvals/rules.md#eligible-approvers).
+ This widget shows recommended and required approvals per area of the codebase.
+ These rules are defined in [Code Owners](../user/project/merge_requests/approvals/rules.md#code-owners-as-eligible-approvers).
- View the list of team members who work in the [stage or group](https://about.gitlab.com/handbook/product/categories/#devops-stages) related to the merge request.
- View team members' domain expertise on the [engineering projects](https://about.gitlab.com/handbook/engineering/projects/) page or on the [GitLab team page](https://about.gitlab.com/company/team/). Domains are self-identified, so use your judgment to map the changes on your merge request to a domain.
- Look for team members who have contributed to the files in the merge request. View the logs by running `git log <file>`.
@@ -237,7 +240,7 @@ See the [test engineering process](https://about.gitlab.com/handbook/engineering
##### Compliance
-1. You have confirmed that the correct [MR type label](contributing/issue_workflow.md#type-labels) has been applied.
+1. You have confirmed that the correct [MR type label](labels/index.md) has been applied.
### The responsibility of the merge request author
@@ -532,7 +535,7 @@ WARNING:
Before taking the decision to merge:
- Set the milestone.
-- Confirm that the correct [MR type label](contributing/issue_workflow.md#type-labels) is applied.
+- Confirm that the correct [MR type label](labels/index.md#type-labels) is applied.
- Consider warnings and errors from danger bot, code quality, and other reports.
Unless a strong case can be made for the violation, these should be resolved
before merging. A comment must be posted if the MR is merged with any failed job.
@@ -718,12 +721,7 @@ Enterprise Edition instance. This has some implications:
cached value returns (say, from a string or nil to an array), change the
cache key at the same time.
1. **Settings** should be added as a
- [last resort](https://about.gitlab.com/handbook/product/product-principles/#convention-over-configuration).
- If you're adding a new setting in `gitlab.yml`:
- 1. Try to avoid that, and add to `ApplicationSetting` instead.
- 1. Ensure that it is also
- [added to Omnibus](https://docs.gitlab.com/omnibus/settings/gitlab.yml#adding-a-new-setting-to-gitlabyml).
- 1. Ensure that it is also [added to Charts](https://docs.gitlab.com/charts/development/style_guide.html), if needed.
+ [last resort](https://about.gitlab.com/handbook/product/product-principles/#convention-over-configuration). See [Adding a new setting to GitLab Rails](architecture.md#adding-a-new-setting-in-gitlab-rails).
1. **File system access** is not possible in a [cloud-native architecture](architecture.md#adapting-existing-and-introducing-new-components).
Ensure that we support object storage for any file storage we need to perform. For more
information, see the [uploads documentation](uploads/index.md).
diff --git a/doc/development/contributing/design.md b/doc/development/contributing/design.md
index aec487ed184..210370f9816 100644
--- a/doc/development/contributing/design.md
+++ b/doc/development/contributing/design.md
@@ -12,7 +12,7 @@ Follow these guidelines when contributing or reviewing design and user interface
advice and best practices for code review in general.
The basis for most of these guidelines is [Pajamas](https://design.gitlab.com/),
-GitLab design system. We encourage you to [contribute to Pajamas](https://design.gitlab.com/get-started/contribute/)
+GitLab design system. We encourage you to [contribute to Pajamas](https://design.gitlab.com/get-started/contributing/)
with additions and improvements.
## Merge request reviews
@@ -127,7 +127,7 @@ At any moment, but usually _during_ or _after_ the design's implementation:
- Contribute [issues to Pajamas](https://design.gitlab.com/get-started/contributing#contribute-an-issue)
for additions or enhancements to the design system.
-- Create issues with the [`~UX debt`](issue_workflow.md#technical-and-ux-debt)
+- Create issues with the [`~UX debt`](../labels/index.md#technical-and-ux-debt)
label for intentional deviations from the agreed-upon UX requirements due to
time or feasibility challenges, linking back to the corresponding issues or
merge requests.
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index 55827e00e43..6a9dd34e703 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -36,7 +36,7 @@ for audiences of all ages.
If you would like to contribute to GitLab:
- Issues with the
- [`~Seeking community contributions` label](issue_workflow.md#label-for-community-contributors)
+ [`~Seeking community contributions` label](../labels/index.md#label-for-community-contributors)
are a great place to start.
- Optimizing our tests is another great opportunity to contribute. You can use
[RSpec profiling statistics](https://gitlab-org.gitlab.io/rspec_profiling_stats/) to identify
@@ -49,11 +49,11 @@ If you would like to contribute to GitLab:
The general flow of contributing to GitLab is:
-1. [Create a fork](../../user/project/repository/forking_workflow.md#creating-a-fork)
- of GitLab. In some cases, you will want to set up the
+1. [Read about](https://gitlab.com/gitlab-community/meta) and [request access](https://gitlab.com/gitlab-community/meta#request-access-to-community-forks)
+ to the GitLab Community forks. In some cases, you will want to set up the
[GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit) to
- [develop against your fork](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/index.md#develop-in-your-own-gitlab-fork).
-1. Make your changes in your fork.
+ [develop against the GitLab community fork](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/index.md#develop-in-your-own-gitlab-fork).
+1. Create a feature branch and make changes in the [GitLab community fork](https://gitlab.com/gitlab-community/gitlab).
1. When you're ready, [create a new merge request](../../user/project/merge_requests/creating_merge_requests.md).
1. In the merge request's description:
- Ensure you provide complete and accurate information.
@@ -107,30 +107,16 @@ your code has multiple disciplines, you may mention multiple merge request coach
GitLab receives a lot of community contributions. If your code has not been reviewed within two
working days of its initial submission, you can ask for help with `@gitlab-bot help`.
-#### Addition of external libraries
-
-When submitting code to GitLab, you may feel that your contribution requires the aid of an external
-library. If your code includes an external library, please provide a link to the library, as well as
-reasons for including it.
-
-Mention a maintainer in merge requests that contain:
-
-- More than 500 changes.
-- Any major [breaking changes](../deprecation_guidelines/index.md).
-- External libraries.
-
-If you are not sure who to mention, the reviewer will do this for you early in the merge request process.
-
#### Issues workflow
This [documentation](issue_workflow.md) outlines the current issue workflow:
- [Issue triaging](issue_workflow.md#issue-triaging)
-- [Labels](issue_workflow.md#labels)
+- [Labels](../labels/index.md)
- [Feature proposals](issue_workflow.md#feature-proposals)
- [Issue weight](issue_workflow.md#issue-weight)
- [Regression issues](issue_workflow.md#regression-issues)
-- [Technical and UX debt](issue_workflow.md#technical-and-ux-debt)
+- [Technical and UX debt](../labels/index.md#technical-and-ux-debt)
- [Technical debt in follow-up issues](issue_workflow.md#technical-debt-in-follow-up-issues)
#### Merge requests workflow
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index b55fef25302..583b39ebe56 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -37,300 +37,7 @@ the affected files to find someone.
We also have triage automation in place, described [in our handbook](https://about.gitlab.com/handbook/engineering/quality/triage-operations/).
-## Labels
-
-To allow for asynchronous issue handling, we use [milestones](https://gitlab.com/groups/gitlab-org/-/milestones)
-and [labels](https://gitlab.com/gitlab-org/gitlab/-/labels). Leads and product managers handle most of the
-scheduling into milestones. Labeling is a task for everyone. (For some projects, labels can be set only by GitLab team members and not by community contributors).
-
-Most issues will have labels for at least one of the following:
-
-- Type. For example: `~"type::feature"`, `~"type::bug"`, or `~"type::maintenance"`.
-- Stage. For example: `~"devops::plan"` or `~"devops::create"`.
-- Group. For example: `~"group::source code"`, `~"group::knowledge"`, or `~"group::editor"`.
-- Category. For example: `~"Category:Code Analytics"`, `~"Category:DevOps Reports"`, or `~"Category:Templates"`.
-- Feature. For example: `~wiki`, `~ldap`, `~api`, `~issues`, or `~"merge requests"`.
-- Department: `~UX`, `~Quality`
-- Team: `~"Technical Writing"`, `~Delivery`
-- Specialization: `~frontend`, `~backend`, `~documentation`
-- Release Scoping: `~Deliverable`, `~Stretch`, `~"Next Patch Release"`
-- Priority: `~"priority::1"`, `~"priority::2"`, `~"priority::3"`, `~"priority::4"`
-- Severity: `~"severity::1"`, `~"severity::2"`, `~"severity::3"`, `~"severity::4"`
-
-Please add `~"breaking change"` label if the issue can be considered as a [breaking change](../deprecation_guidelines/index.md).
-
-Please add `~security` label if the issue is related to application security.
-
-All labels, their meaning and priority are defined on the
-[labels page](https://gitlab.com/gitlab-org/gitlab/-/labels).
-
-If you come across an issue that has none of these, and you're allowed to set
-labels, you can _always_ add the type, stage, group, and often the category/feature labels.
-
-### Type labels
-
-Type labels are very important. They define what kind of issue this is. Every
-issue should have one and only one.
-
-The SSOT for type and subtype labels is [available in the handbook](https://about.gitlab.com/handbook/engineering/metrics/#work-type-classification).
-
-A number of type labels have a priority assigned to them, which automatically
-makes them float to the top, depending on their importance.
-
-Type labels are always lowercase, and can have any color, besides blue (which is
-already reserved for category labels).
-
-The descriptions on the [labels page](https://gitlab.com/groups/gitlab-org/-/labels)
-explain what falls under each type label.
-
-The GitLab handbook documents [when something is a bug](https://about.gitlab.com/handbook/product/product-processes/#bug-issues) and [when it is a feature request](https://about.gitlab.com/handbook/product/product-processes/#feature-issues).
-
-### Stage labels
-
-Stage labels specify which [stage](https://about.gitlab.com/handbook/product/categories/#hierarchy) the issue belongs to.
-
-#### Naming and color convention
-
-Stage labels respects the `devops::<stage_key>` naming convention.
-`<stage_key>` is the stage key as it is in the single source of truth for stages at
-<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml>
-with `_` replaced with a space.
-
-For instance, the "Manage" stage is represented by the `~"devops::manage"` label in
-the `gitlab-org` group since its key under `stages` is `manage`.
-
-The current stage labels can be found by [searching the labels list for `devops::`](https://gitlab.com/groups/gitlab-org/-/labels?search=devops::).
-
-These labels are [scoped labels](../../user/project/labels.md#scoped-labels)
-and thus are mutually exclusive.
-
-The Stage labels are used to generate the [direction pages](https://about.gitlab.com/direction/) automatically.
-
-### Group labels
-
-Group labels specify which [groups](https://about.gitlab.com/company/team/structure/#product-groups) the issue belongs to.
-
-It's highly recommended to add a group label, as it's used by our triage
-automation to
-[infer the correct stage label](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues-and-merge-requests).
-
-#### Naming and color convention
-
-Group labels respects the `group::<group_key>` naming convention and
-their color is `#A8D695`.
-`<group_key>` is the group key as it is in the single source of truth for groups at
-<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml>,
-with `_` replaced with a space.
-
-For instance, the "Pipeline Execution" group is represented by the
-~"group::pipeline execution" label in the `gitlab-org` group since its key
-under `stages.manage.groups` is `pipeline_execution`.
-
-The current group labels can be found by [searching the labels list for `group::`](https://gitlab.com/groups/gitlab-org/-/labels?search=group::).
-
-These labels are [scoped labels](../../user/project/labels.md#scoped-labels)
-and thus are mutually exclusive.
-
-You can find the groups listed in the [Product Stages, Groups, and Categories](https://about.gitlab.com/handbook/product/categories/) page.
-
-We use the term group to map down product requirements from our product stages.
-As a team needs some way to collect the work their members are planning to be assigned to, we use the `~group::` labels to do so.
-
-### Category labels
-
-From the handbook's
-[Product stages, groups, and categories](https://about.gitlab.com/handbook/product/categories/#hierarchy)
-page:
-
-> Categories are high-level capabilities that may be a standalone product at
-another company, such as Portfolio Management, for example.
-
-It's highly recommended to add a category label, as it's used by our triage
-automation to
-[infer the correct group and stage labels](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues).
-
-If you are an expert in a particular area, it makes it easier to find issues to
-work on. You can also subscribe to those labels to receive an email each time an
-issue is labeled with a category label corresponding to your expertise.
-
-#### Naming and color convention
-
-Category labels respects the `Category:<Category Name>` naming convention and
-their color is `#428BCA`.
-`<Category Name>` is the category name as it is in the single source of truth for categories at
-<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml>.
-
-For instance, the "DevOps Reports" category is represented by the
-~"Category:DevOps Reports" label in the `gitlab-org` group since its
-`devops_reports.name` value is "DevOps Reports".
-
-If a category's label doesn't respect this naming convention, it should be specified
-with [the `label` attribute](https://about.gitlab.com/handbook/marketing/digital-experience/website/#category-attributes)
-in <https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml>.
-
-### Feature labels
-
-From the handbook's
-[Product stages, groups, and categories](https://about.gitlab.com/handbook/product/categories/#hierarchy)
-page:
-
-> Features: Small, discrete functionalities, for example Issue weights. Some common
-features are listed within parentheses to facilitate finding responsible PMs by keyword.
-
-It's highly recommended to add a feature label if no category label applies, as
-it's used by our triage automation to
-[infer the correct group and stage labels](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues).
-
-If you are an expert in a particular area, it makes it easier to find issues to
-work on. You can also subscribe to those labels to receive an email each time an
-issue is labeled with a feature label corresponding to your expertise.
-
-Examples of feature labels are `~wiki`, `~ldap`, `~api`, `~issues`, and `~"merge requests"`.
-
-#### Naming and color convention
-
-Feature labels are all-lowercase.
-
-### Facet labels
-
-To track additional information or context about created issues, developers may
-add _facet labels_. Facet labels are also sometimes used for issue prioritization
-or for measurements (such as time to close). An example of a facet label is the
-~customer label, which indicates customer interest.
-
-### Department labels
-
-The current department labels are:
-
-- ~UX
-- ~Quality
-
-### Team labels
-
-**Important**: Most of the historical team labels (like Manage or Plan) are
-now deprecated in favor of [Group labels](#group-labels) and [Stage labels](#stage-labels).
-
-Team labels specify what team is responsible for this issue.
-Assigning a team label makes sure issues get the attention of the appropriate
-people.
-
-The current team labels are:
-
-- ~Delivery
-- ~"Technical Writing"
-
-#### Naming and color convention
-
-Team labels are always capitalized so that they show up as the first label for
-any issue.
-
-### Specialization labels
-
-These labels narrow the [specialization](https://about.gitlab.com/company/team/structure/#specialist) on a unit of work.
-
-- ~frontend
-- ~backend
-- ~documentation
-
-### Release scoping labels
-
-Release Scoping labels help us clearly communicate expectations of the work for the
-release. There are three levels of Release Scoping labels:
-
-- ~Deliverable: Issues that are expected to be delivered in the current
- milestone.
-- ~Stretch: Issues that are a stretch goal for delivering in the current
- milestone. If these issues are not done in the current release, they will
- strongly be considered for the next release.
-- ~"Next Patch Release": Issues to put in the next patch release. Work on these
- first, and add the `~"Pick into X.Y"` label to the merge request, along with the
- appropriate milestone.
-
-Each issue scheduled for the current milestone should be labeled ~Deliverable
-or ~"Stretch". Any open issue for a previous milestone should be labeled
-~"Next Patch Release", or otherwise rescheduled to a different milestone.
-
-### Priority labels
-
-We have the following priority labels:
-
-- ~"priority::1"
-- ~"priority::2"
-- ~"priority::3"
-- ~"priority::4"
-
-Please refer to the issue triage [priority label](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#priority) section in our handbook to see how it's used.
-
-### Severity labels
-
-We have the following severity labels:
-
-- ~"severity::1"
-- ~"severity::2"
-- ~"severity::3"
-- ~"severity::4"
-
-Please refer to the issue triage [severity label](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#severity) section in our handbook to see how it's used.
-
-### Label for community contributors
-
-There are many issues that have a clear solution with uncontroversial benefit to GitLab users.
-However, GitLab might not have the capacity for all these proposals in the current roadmap.
-These issues are labeled ~"Seeking community contributions" because we welcome merge requests to resolve them.
-
-Community contributors can submit merge requests for any issue they want, but
-the ~"Seeking community contributions" label has a special meaning. It points to
-changes that:
-
-1. We already agreed on,
-1. Are well-defined,
-1. Are likely to get accepted by a maintainer.
-
-We want to avoid a situation when a contributor picks an
-~"Seeking community contributions" issue and then their merge request gets closed,
-because we realize that it does not fit our vision, or we want to solve it in a
-different way.
-
-We manually add the ~"Seeking community contributions" label to issues
-that fit the criteria described above.
-We do not automatically add this label, because it requires human evaluation.
-
-We recommend people that have never contributed to any open source project to
-look for issues labeled `~"Seeking community contributions"` with a
-[weight of 1](https://gitlab.com/groups/gitlab-org/-/issues?sort=created_date&state=opened&label_name[]=Seeking+community+contributions&assignee_id=None&weight=1) or the `~"good for new contributors"`
-[label](https://gitlab.com/gitlab-org/gitlab/-/issues?scope=all&state=opened&label_name[]=good%20for%20new%20contributors&assignee_id=None)
-attached to it.
-More experienced contributors are very welcome to tackle
-[any of them](https://gitlab.com/groups/gitlab-org/-/issues?sort=created_date&state=opened&label_name[]=Seeking+community+contributions&assignee_id=None).
-
-For more complex features that have a weight of 2 or more and clear scope, we recommend looking at issues
-with the [label `~"Community Challenge"`](https://gitlab.com/gitlab-org/gitlab/-/issues?sort=created_date&state=opened&label_name[]=Seeking+community+contributions&label_name[]=Community+challenge).
-If your MR for the `~"Community Challenge"` issue gets merged, you will also have a chance to win a custom
-GitLab merchandise.
-
-If you've decided that you would like to work on an issue, please @-mention
-the [appropriate product manager](https://about.gitlab.com/handbook/product/#who-to-talk-to-for-what)
-as soon as possible. The product manager will then pull in appropriate GitLab team
-members to further discuss scope, design, and technical considerations. This will
-ensure that your contribution is aligned with the GitLab product and minimize
-any rework and delay in getting it merged into main.
-
-GitLab team members who apply the ~"Seeking community contributions" label to an issue
-should update the issue description with a responsible product manager, inviting
-any potential community contributor to @-mention per above.
-
-### Stewardship label
-
-For issues related to the open source stewardship of GitLab,
-there is the ~"stewardship" label.
-
-This label is to be used for issues in which the stewardship of GitLab
-is a topic of discussion. For instance if GitLab Inc. is planning to add
-features from GitLab EE to GitLab CE, related issues would be labeled with
-~"stewardship".
-
-A recent example of this was the issue for
-[bringing the time tracking API to GitLab CE](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/25517#note_20019084).
+For information about which labels to apply to issues, see [Labels](../labels/index.md).
## Feature proposals
@@ -399,31 +106,6 @@ The release manager will
[update the notes](https://gitlab.com/gitlab-org/release-tools/blob/master/doc/pro-tips.md#update-the-regression-issue)
in the regression issue as fixes are addressed.
-## Technical and UX debt
-
-In order to track things that can be improved in the GitLab codebase,
-we use the ~"technical debt" label in the [GitLab issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues).
-We use the ~"UX debt" label when we choose to deviate from the MVC, in a way that harms the user experience.
-
-These labels should be added to issues that describe things that can be improved,
-shortcuts that have been taken, features that need additional attention, and all
-other things that have been left behind due to high velocity of development.
-For example, code that needs refactoring should use the ~"technical debt" label,
-something that didn't ship according to our Design System guidelines should
-use the ~"UX debt" label.
-
-Everyone can create an issue, though you may need to ask for adding a specific
-label, if you do not have permissions to do it by yourself. Additional labels
-can be combined with these labels, to make it easier to schedule
-the improvements for a release.
-
-Issues tagged with these labels have the same priority like issues
-that describe a new feature to be introduced in GitLab, and should be scheduled
-for a release by the appropriate person.
-
-Make sure to mention the merge request that the ~"technical debt" issue or
-~"UX debt" issue is associated with in the description of the issue.
-
## Technical debt in follow-up issues
It's common to discover technical debt during development of a new feature. In
@@ -459,6 +141,6 @@ and assignee.
The maintainer must always agree before an outstanding discussion is resolved in
this manner, and will be the one to create the issue. The title and description
should be of the same quality as those created
-[in the usual manner](#technical-and-ux-debt) - in particular, the issue title
+[in the usual manner](../labels/index.md#technical-and-ux-debt) - in particular, the issue title
**must not** begin with `Follow-up`! The creating maintainer should also expect
to be involved in some capacity when work begins on the follow-up issue.
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index 01bfdae5999..f39d93a39bc 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -9,11 +9,33 @@ info: To determine the technical writer assigned to the Stage/Group associated w
We welcome merge requests from everyone, with fixes and improvements
to GitLab code, tests, and documentation. The issues that are specifically suitable
-for community contributions have the [`Seeking community contributions`](issue_workflow.md#label-for-community-contributors)
+for community contributions have the
+[`Seeking community contributions`](../labels/index.md#label-for-community-contributors)
label, but you are free to contribute to any issue you want.
+## Working from issues
+
+If you find an issue, please submit a merge request with a fix or improvement,
+if you can, and include tests.
+
+If you want to add a new feature that is not labeled, it is best to first create
+an issue (if there isn't one already) and leave a comment asking for it
+to be labeled as `Seeking community contributions`. See the [feature proposals](issue_workflow.md#feature-proposals)
+section.
+
+If you don't know how to fix the issue but can write a test that exposes the
+issue, we will accept that as well. In general, bug fixes that include a
+regression test are merged quickly. New features without proper tests
+might be slower to receive feedback.
+
+If you are new to GitLab development (or web development in general), see the
+[how to contribute](index.md#how-to-contribute) section to get started with
+some potentially easy issues.
+
+## Merge request ownership
+
If an issue is marked for the current milestone at any time, even
-when you are working on it, a GitLab team member may take over the merge request to ensure the work is finished before the release date.
+when you are working on it, a GitLab team member may take over the merge request to ensure the work is finished before the release date.
If a contributor is no longer actively working on a submitted merge request,
we can:
@@ -31,28 +53,18 @@ we credit the original author by adding a changelog entry crediting the author
and optionally include the original author on at least one of the commits
within the MR.
-If you want to add a new feature that is not labeled, it is best to first create
-an issue (if there isn't one already) and leave a comment asking for it
-to be labeled as `Seeking community contributions`. See the [feature proposals](issue_workflow.md#feature-proposals)
-section.
+## Merge request guidelines for contributors
+
+### Getting started
Merge requests should be submitted to the appropriate project at GitLab.com, for example
[GitLab](https://gitlab.com/gitlab-org/gitlab/-/merge_requests),
[GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests), or
[Omnibus GitLab](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests).
-If you are new to GitLab development (or web development in general), see the
-[how to contribute](index.md#how-to-contribute) section to get started with
-some potentially easy issues.
-
-To start developing GitLab, download the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit)
+To start developing GitLab locally, download the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit)
and see the [Development section](../../index.md) for the required guidelines.
-## Merge request guidelines for contributors
-
-If you find an issue, please submit a merge request with a fix or improvement,
-if you can, and include tests.
-
NOTE:
Consider placing your code behind a feature flag if you think it might affect production availability.
Not sure? Read [When to use feature flags](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/#when-to-use-feature-flags).
@@ -64,20 +76,19 @@ this by tagging them in an MR before submitting the code for review. Talking
to team members can be helpful when making design decisions. Communicating the
intent behind your changes can also help expedite merge request reviews.
-If
-you don't know how to fix the issue but can write a test that exposes the
-issue, we will accept that as well. In general, bug fixes that include a
-regression test are merged quickly. New features without proper tests
-might be slower to receive feedback.
+### Creating a merge request
To create a merge request:
-1. [Fork](../../user/project/repository/forking_workflow.md) the project into
- your personal namespace (or group) on GitLab.com.
-1. Create a feature branch in your fork (don't work off your [default branch](../../user/project/repository/branches/default.md)).
+1. [Read about](https://gitlab.com/gitlab-community/meta) and [request access](https://gitlab.com/gitlab-community/meta#request-access-to-community-forks)
+ to the GitLab Community forks. In some cases, you will want to set up the
+ [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit) to
+ [develop against the GitLab community fork](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/index.md#develop-in-your-own-gitlab-fork).
+1. Create a feature branch in the [GitLab community fork](https://gitlab.com/gitlab-community/gitlab)
+ (don't work off the [default branch](../../user/project/repository/branches/default.md)).
1. Follow the [commit messages guidelines](#commit-messages-guidelines).
1. If you have multiple commits, combine them into a few logically organized commits.
-1. Push the commits to your working branch in your fork.
+1. Push the commits to your working branch in the fork.
1. Submit a merge request (MR) against the default branch of the upstream project.
1. The MR title should describe the change you want to make.
1. The MR description should give a reason for your change.
@@ -191,6 +202,10 @@ To make sure that your merge request can be approved, please ensure that it meet
the contribution acceptance criteria below:
1. The change is as small as possible.
+1. If the merge request contains more than 500 changes:
+ - Explain the reason
+ - Mention a maintainer
+1. Mention any major [breaking changes](../deprecation_guidelines/index.md).
1. Include proper tests and make all tests pass (unless it contains a test
exposing a bug in existing code). Every new class should have corresponding
unit tests, even if the class is exercised at a higher level, such as a feature test.
diff --git a/doc/development/contributing/style_guides.md b/doc/development/contributing/style_guides.md
index 28ce8e6ff4b..d24875e559a 100644
--- a/doc/development/contributing/style_guides.md
+++ b/doc/development/contributing/style_guides.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
---
-# Style guides
+# Development style guides
## Editor/IDE styling standardization
@@ -30,7 +30,9 @@ We were using Overcommit prior to Lefthook, so you may want to uninstall it firs
### Install Lefthook
-1. Install the `lefthook` Ruby gem:
+1. You can install lefthook in [different ways](https://github.com/evilmartians/lefthook/blob/master/docs/install.md#install-lefthook).
+ If you do not choose to install it globally (e.g. via Homebrew or package managers), and only want to use it for the GitLab project,
+ you can install the Ruby gem via:
```shell
bundle install
@@ -39,12 +41,18 @@ We were using Overcommit prior to Lefthook, so you may want to uninstall it firs
1. Install Lefthook managed Git hooks:
```shell
+ # If installed globally
+ lefthook install
+ # Or if installed via ruby gem
bundle exec lefthook install
```
1. Test Lefthook is working by running the Lefthook `pre-push` Git hook:
```shell
+ # If installed globally
+ lefthook run pre-push
+ # Or if installed via ruby gem
bundle exec lefthook run pre-push
```
@@ -57,6 +65,18 @@ Lefthook is configured with a combination of:
- Project configuration in [`lefthook.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lefthook.yml).
- Any [local configuration](https://github.com/evilmartians/lefthook/blob/master/README.md#local-config).
+### Lefthook auto-fixing files
+
+We have a custom lefthook target to run all the linters with auto-fix capabilities,
+but just on the files which changed in your branch.
+
+```shell
+# If installed globally
+lefthook run auto-fix
+# Or if installed via ruby gem
+bundle exec lefthook run auto-fix
+```
+
### Disable Lefthook temporarily
To disable Lefthook temporarily, you can set the `LEFTHOOK` environment variable to `0`. For instance:
diff --git a/doc/development/dangerbot.md b/doc/development/dangerbot.md
index b08eaed2afa..ef1e563b668 100644
--- a/doc/development/dangerbot.md
+++ b/doc/development/dangerbot.md
@@ -141,27 +141,27 @@ To enable the Dangerfile on another existing GitLab project, complete the follow
1. Add [`gitlab-dangerfiles`](https://rubygems.org/gems/gitlab-dangerfiles) to your `Gemfile`.
1. Create a `Dangerfile` with the following content:
- ```ruby
- require "gitlab-dangerfiles"
+ ```ruby
+ require "gitlab-dangerfiles"
- Gitlab::Dangerfiles.for_project(self, &:import_defaults)
- ```
+ Gitlab::Dangerfiles.for_project(self, &:import_defaults)
+ ```
1. Add the following to your CI/CD configuration:
- ```yaml
- include:
- - project: 'gitlab-org/quality/pipeline-common'
- file:
- - '/ci/danger-review.yml'
- rules:
- - if: $CI_SERVER_HOST == "gitlab.com"
- ```
+ ```yaml
+ include:
+ - project: 'gitlab-org/quality/pipeline-common'
+ file:
+ - '/ci/danger-review.yml'
+ rules:
+ - if: $CI_SERVER_HOST == "gitlab.com"
+ ```
1. If your project is in the `gitlab-org` group, you don't need to set up any token as the `DANGER_GITLAB_API_TOKEN`
variable is available at the group level. If not, follow these last steps:
- 1. Create a [Project access tokens](../user/project/settings/project_access_tokens.md).
- 1. Add the token as a CI/CD project variable named `DANGER_GITLAB_API_TOKEN`.
+ 1. Create a [Project access tokens](../user/project/settings/project_access_tokens.md).
+ 1. Add the token as a CI/CD project variable named `DANGER_GITLAB_API_TOKEN`.
You should add the ~"Danger bot" label to the merge request before sending it
for review.
diff --git a/doc/development/database/add_foreign_key_to_existing_column.md b/doc/development/database/add_foreign_key_to_existing_column.md
index 2c2999e69d6..823fb49a9ab 100644
--- a/doc/development/database/add_foreign_key_to_existing_column.md
+++ b/doc/development/database/add_foreign_key_to_existing_column.md
@@ -155,13 +155,13 @@ To limit impact on GitLab.com, a process exists to validate them asynchronously
during weekend hours. Due to generally lower traffic and fewer deployments,
FK validation can proceed at a lower level of risk.
-### Schedule foreign key validation for a low-impact time
+#### Schedule foreign key validation for a low-impact time
1. [Schedule the FK to be validated](#schedule-the-fk-to-be-validated).
1. [Verify the MR was deployed and the FK is valid in production](#verify-the-mr-was-deployed-and-the-fk-is-valid-in-production).
1. [Add a migration to validate the FK synchronously](#add-a-migration-to-validate-the-fk-synchronously).
-### Schedule the FK to be validated
+#### Schedule the FK to be validated
1. Create a merge request containing a post-deployment migration, which prepares
the foreign key for asynchronous validation.
@@ -198,7 +198,7 @@ def down
end
```
-### Verify the MR was deployed and the FK is valid in production
+#### Verify the MR was deployed and the FK is valid in production
1. Verify that the post-deploy migration was executed on GitLab.com using ChatOps with
`/chatops run auto_deploy status <merge_sha>`. If the output returns `db/gprd`,
@@ -208,7 +208,7 @@ end
1. Use [Database Lab](database_lab.md) to check if validation was successful.
Ensure the output does not indicate the foreign key is `NOT VALID`.
-### Add a migration to validate the FK synchronously
+#### Add a migration to validate the FK synchronously
After the foreign key is valid on the production database, create a second
merge request that validates the foreign key synchronously. The schema changes
@@ -240,19 +240,20 @@ end
```
-## Test database FK changes locally
+### Test database FK changes locally
You must test the database foreign key changes locally before creating a merge request.
-### Verify the foreign keys validated asynchronously
+#### Verify the foreign keys validated asynchronously
Use the asynchronous helpers on your local environment to test changes for
validating a foreign key:
-1. Enable the feature flags by running `Feature.enable(:database_async_foreign_key_validation)`
- and `Feature.enable(:database_reindexing)` in the Rails console.
+1. Enable the feature flag by running `Feature.enable(:database_async_foreign_key_validation)`
+ in the Rails console.
1. Run `bundle exec rails db:migrate` so that it creates an entry in the async validation table.
-1. Run `bundle exec rails gitlab:db:reindex` so that the FK is validated asynchronously.
+1. Run `bundle exec rails gitlab:db:validate_async_constraints:all` so that the FK is validated
+ asynchronously on all databases.
1. To verify the foreign key, open the PostgreSQL console using the
[GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/postgresql.md)
command `gdk psql` and run the command `\d+ table_name` to check that your
diff --git a/doc/development/database/batched_background_migrations.md b/doc/development/database/batched_background_migrations.md
index c6fe6d16faf..67dccd99a6c 100644
--- a/doc/development/database/batched_background_migrations.md
+++ b/doc/development/database/batched_background_migrations.md
@@ -34,10 +34,13 @@ Background migrations can help when:
- Populating one column based on JSON stored in another column.
- Migrating data that depends on the output of external services. (For example, an API.)
-NOTE:
-If the batched background migration is part of an important upgrade, it must be announced
-in the release post. Discuss with your Project Manager if you're unsure if the migration falls
-into this category.
+### Notes
+
+- If the batched background migration is part of an important upgrade, it must be announced
+ in the release post. Discuss with your Project Manager if you're unsure if the migration falls
+ into this category.
+- You should use the [generator](#generator) to create batched background migrations,
+ so that required files are created by default.
## Isolation
@@ -311,6 +314,22 @@ NOTE:
When applying additional filters, it is important to ensure they are properly covered by an index to optimize `EachBatch` performance.
In the example above we need an index on `(type, id)` to support the filters. See [the `EachBatch` documentation for more information](iterating_tables_in_batches.md).
+## Generator
+
+The custom generator `batched_background_migration` scaffolds necessary files and
+accepts `table_name`, `column_name`, and `feature_category` as arguments. Usage:
+
+```shell
+bundle exec rails g batched_background_migration my_batched_migration --table_name=<table-name> --column_name=<column-name> --feature_category=<feature-category>
+```
+
+This command creates these files:
+
+- `db/post_migrate/20230214231008_queue_my_batched_migration.rb`
+- `spec/migrations/20230214231008_queue_my_batched_migration_spec.rb`
+- `lib/gitlab/background_migration/my_batched_migration.rb`
+- `spec/lib/gitlab/background_migration/my_batched_migration_spec.rb`
+
## Example
The `routes` table has a `source_type` field that's used for a polymorphic relationship.
@@ -319,8 +338,13 @@ the work is migrating data from the `source_id` column into a new singular forei
Because we intend to delete old rows later, there's no need to update them as part of the
background migration.
-1. Start by defining our migration class, which should inherit
- from `Gitlab::BackgroundMigration::BatchedMigrationJob`:
+1. Start by using the generator to create batched background migration files:
+
+ ```shell
+ bundle exec rails g batched_background_migration BackfillRouteNamespaceId --table_name=routes --column_name=id --feature_category=source_code_management
+ ```
+
+1. Update the migration job (subclass of `BatchedMigrationJob`) to copy `source_id` values to `namespace_id`:
```ruby
class Gitlab::BackgroundMigration::BackfillRouteNamespaceId < BatchedMigrationJob
@@ -344,10 +368,10 @@ background migration.
```
NOTE:
- Job classes must be subclasses of `BatchedMigrationJob` to be
+ Job classes inherit from `BatchedMigrationJob` to ensure they are
correctly handled by the batched migration framework. Any subclass of
- `BatchedMigrationJob` is initialized with necessary arguments to
- execute the batch, as well as a connection to the tracking database.
+ `BatchedMigrationJob` is initialized with the necessary arguments to
+ execute the batch, and a connection to the tracking database.
1. Create a database migration that adds a new trigger to the database. Example:
@@ -380,12 +404,14 @@ background migration.
end
```
-1. Create a post-deployment migration that queues the migration for existing data:
+1. Update the created post-deployment migration with required delay and batch sizes:
```ruby
class QueueBackfillRoutesNamespaceId < Gitlab::Database::Migration[2.1]
MIGRATION = 'BackfillRouteNamespaceId'
DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
restrict_gitlab_migration gitlab_schema: :gitlab_main
@@ -394,7 +420,9 @@ background migration.
MIGRATION,
:routes,
:id,
- job_interval: DELAY_INTERVAL
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
)
end
@@ -719,6 +747,99 @@ You can view failures in two ways:
WHERE transition_logs.next_status = '2' AND migration.job_class_name = "CLASS_NAME";
```
+### Executing a particular batch on the database testing pipeline
+
+NOTE:
+Only [database maintainers](https://gitlab.com/groups/gitlab-org/maintainers/database/-/group_members?with_inherited_permissions=exclude) can view the database testing pipeline artifacts. Ask one for help if you need to use this method.
+
+Let's assume that a batched background migration failed on a particular batch on GitLab.com and you want to figure out which query failed and why. At the moment, we don't have a good way to retrieve query information (especially the query parameters) and rerunning the entire migration with more logging would be a long process.
+
+Fortunately you can leverage our [database migration pipeline](database_migration_pipeline.md) to rerun a particular batch with additional logging and/or fix to see if it solves the problem.
+
+<!-- vale gitlab.Substitutions = NO -->
+For an example see [Draft: Test PG::CardinalityViolation fix](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110910) but make sure to read the entire section.
+
+To do that, you need to:
+
+1. Find the batch `start_id` and `end_id`
+1. Create a regular migration
+1. Apply a workaround for our migration helpers (optional)
+1. Start the database migration pipeline
+
+#### 1. Find the batch `start_id` and `end_id`
+
+You should be able to find those in [Kibana][#viewing-failure-error-logs].
+
+#### 2. Create a regular migration
+
+Schedule the batch in the `up` block of a regular migration:
+
+```ruby
+def up
+ instance = Gitlab::BackgroundMigration::YourBackgroundMigrationClass.new(
+ start_id: <batch start_id>,
+ end_id: <batch end_id>,
+ batch_table: <table name>,
+ batch_column: <batching column>,
+ sub_batch_size: <sub batch size>,
+ pause_ms: <miliseconds between batches>,
+ job_arguments: <job arguments if any>,
+ connection: connection
+ )
+
+ instance.perform
+end
+
+
+def down
+ # no-op
+end
+```
+
+#### 3. Apply a workaround for our migration helpers (optional)
+
+If your batched background migration touches tables from a schema other than the one you specified by using `restrict_gitlab_migration` helper (example: the scheduling migration has `restrict_gitlab_migration gitlab_schema: :gitlab_main` but the background job uses tables from the `:gitlab_ci` schema) then the migration will fail. To prevent that from happening you'll have to monkey patch database helpers so they don't fail the testing pipeline job:
+
+1. Add the schema names to [`RestrictGitlabSchema`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/database/migration_helpers/restrict_gitlab_schema.rb#L57)
+
+```diff
+diff --git a/lib/gitlab/database/migration_helpers/restrict_gitlab_schema.rb b/lib/gitlab/database/migration_helpers/restrict_gitlab_schema.rb
+index b8d1d21a0d2d2a23d9e8c8a0a17db98ed1ed40b7..912e20659a6919f771045178c66828563cb5a4a1 100644
+--- a/lib/gitlab/database/migration_helpers/restrict_gitlab_schema.rb
++++ b/lib/gitlab/database/migration_helpers/restrict_gitlab_schema.rb
+@@ -55,7 +55,7 @@ def unmatched_schemas
+ end
+
+ def allowed_schemas_for_connection
+- Gitlab::Database.gitlab_schemas_for_connection(connection)
++ Gitlab::Database.gitlab_schemas_for_connection(connection) << :gitlab_ci
+ end
+ end
+ end
+```
+
+1. Add the schema names to [`RestrictAllowedSchemas`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/database/query_analyzers/restrict_allowed_schemas.rb#L82)
+
+```diff
+diff --git a/lib/gitlab/database/query_analyzers/restrict_allowed_schemas.rb b/lib/gitlab/database/query_analyzers/restrict_allowed_schemas.rb
+index 4ae3622479f0800c0553959e132143ec9051898e..d556ec7f55adae9d46a56665ce02de782cb09f2d 100644
+--- a/lib/gitlab/database/query_analyzers/restrict_allowed_schemas.rb
++++ b/lib/gitlab/database/query_analyzers/restrict_allowed_schemas.rb
+@@ -79,7 +79,7 @@ def restrict_to_dml_only(parsed)
+ tables = self.dml_tables(parsed)
+ schemas = self.dml_schemas(tables)
+
+- if (schemas - self.allowed_gitlab_schemas).any?
++ if (schemas - (self.allowed_gitlab_schemas << :gitlab_ci)).any?
+ raise DMLAccessDeniedError, \
+ "Select/DML queries (SELECT/UPDATE/DELETE) do access '#{tables}' (#{schemas.to_a}) " \
+ "which is outside of list of allowed schemas: '#{self.allowed_gitlab_schemas}'. " \
+```
+
+#### 4. Start the database migration pipeline
+
+Create a Draft merge request with your changes and trigger the manual `db:gitlabcom-database-testing` job.
+
### Adding indexes to support batched background migrations
Sometimes it is necessary to add a new or temporary index to support a batched background migration.
diff --git a/doc/development/database/clickhouse/merge_request_analytics.md b/doc/development/database/clickhouse/merge_request_analytics.md
new file mode 100644
index 00000000000..34da71d6c4c
--- /dev/null
+++ b/doc/development/database/clickhouse/merge_request_analytics.md
@@ -0,0 +1,355 @@
+---
+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
+---
+
+# Merge request analytics with ClickHouse
+
+The [merge request analytics feature](../../../user/analytics/merge_request_analytics.md)
+shows statistics about the merged merge requests in the project and also exposes record-level metadata.
+Aggregations include:
+
+- **Average time to merge**: The duration between the creation time and the merge time.
+- **Monthly aggregations**: A chart of 12 months of the merged merge requests.
+
+Under the chart, the user can see the paginated list of merge requests, 12 months per page.
+
+You can filter by:
+
+- Author
+- Assignee
+- Labels
+- Milestone
+- Source branch
+- Target branch
+
+## Current performance problems
+
+- The aggregation queries require specialized indexes, which cost additional
+ disk space (index-only scans).
+- Querying the whole 12 months is slow (statement timeout). Instead, the frontend
+ requests data per month (12 database queries).
+- Even with specialized indexes, making the feature available on the group level
+ would not be feasible due to the large volume of merge requests.
+
+## Example queries
+
+Get the number of merge requests merged in a given month:
+
+```sql
+SELECT COUNT(*)
+FROM "merge_requests"
+INNER JOIN "merge_request_metrics" ON "merge_request_metrics"."merge_request_id" = "merge_requests"."id"
+WHERE (NOT EXISTS
+ (SELECT 1
+ FROM "banned_users"
+ WHERE (merge_requests.author_id = banned_users.user_id)))
+ AND "merge_request_metrics"."target_project_id" = 278964
+ AND "merge_request_metrics"."merged_at" >= '2022-12-01 00:00:00'
+ AND "merge_request_metrics"."merged_at" <= '2023-01-01 00:00:00'
+```
+
+The `merge_request_metrics` table was de-normalized (by adding `target_project_id`)
+to improve the first-page load time. The query itself works well for smaller date ranges,
+however, it can time out as the date range increases.
+
+After an extra filter is added, the query becomes more complex because it must also
+filter the `merge_requests` table:
+
+```sql
+SELECT COUNT(*)
+FROM "merge_requests"
+INNER JOIN "merge_request_metrics" ON "merge_request_metrics"."merge_request_id" = "merge_requests"."id"
+WHERE (NOT EXISTS
+ (SELECT 1
+ FROM "banned_users"
+ WHERE (merge_requests.author_id = banned_users.user_id)))
+ AND "merge_requests"."author_id" IN
+ (SELECT "users"."id"
+ FROM "users"
+ WHERE (LOWER("users"."username") IN (LOWER('ahegyi'))))
+ AND "merge_request_metrics"."target_project_id" = 278964
+ AND "merge_request_metrics"."merged_at" >= '2022-12-01 00:00:00'
+ AND "merge_request_metrics"."merged_at" <= '2023-01-01 00:00:00'
+```
+
+To calculate mean time to merge, we also query the total time between the
+merge request creation time and merge time.
+
+```sql
+SELECT EXTRACT(epoch
+ FROM SUM(AGE(merge_request_metrics.merged_at, merge_request_metrics.created_at)))
+FROM "merge_requests"
+INNER JOIN "merge_request_metrics" ON "merge_request_metrics"."merge_request_id" = "merge_requests"."id"
+WHERE (NOT EXISTS
+ (SELECT 1
+ FROM "banned_users"
+ WHERE (merge_requests.author_id = banned_users.user_id)))
+ AND "merge_requests"."author_id" IN
+ (SELECT "users"."id"
+ FROM "users"
+ WHERE (LOWER("users"."username") IN (LOWER('ahegyi'))))
+ AND "merge_request_metrics"."target_project_id" = 278964
+ AND "merge_request_metrics"."merged_at" >= '2022-08-01 00:00:00'
+ AND "merge_request_metrics"."merged_at" <= '2022-09-01 00:00:00'
+ AND "merge_request_metrics"."merged_at" > "merge_request_metrics"."created_at"
+LIMIT 1
+```
+
+## Store merge request data in ClickHouse
+
+Several other use cases exist for storing and querying merge request data in
+ClickHouse. In this document, we focus on this particular feature.
+
+The core data exists in the `merge_request_metrics` and in the `merge_requests`
+database tables. Some filters require extra tables to be joined:
+
+- `banned_users`: Filter out merge requests created by banned users.
+- `labels`: A merge request can have one or more assigned labels.
+- `assignees`: A merge request can have one or more assignees.
+- `merged_at`: The `merged_at` column is located in the `merge_request_metrics` table.
+
+The `merge_requests` table contains data that can be filtered directly:
+
+- **Author**: via the `author_id` column.
+- **Milestone**: via the `milestone_id` column.
+- **Source branch**.
+- **Target branch**.
+- **Project**: via the `project_id` column.
+
+### Keep ClickHouse data up to date
+
+Replicating or syncing the `merge_requests` table is unfortunately not enough.
+Separate queries to associated tables are required to insert one de-normalized
+`merge_requests` row into the ClickHouse database.
+
+Change detection is non-trivial to implement. A few corners we could cut:
+
+- The feature is available for GitLab Premium and GitLab Ultimate customers.
+ We don't have to sync all the data, but instead sync only the `merge_requests` records
+ which are part of licensed groups.
+- Data changes (often) happen via the `MergeRequest` services, where bumping the
+ `updated_at` timestamp column is mostly consistent. Some sort of incremental
+ synchronization process could be implemented.
+- We only need to query the merged merge requests. After the merge, the record rarely changes.
+
+### Database table structure
+
+The database table structure uses de-normalization to make all required columns
+available in one database table. This eliminates the need for `JOINs`.
+
+```sql
+CREATE TABLE merge_requests
+(
+ `id` UInt64,
+ `project_id` UInt64 DEFAULT 0 NOT NULL,
+ `author_id` UInt64 DEFAULT 0 NOT NULL,
+ `milestone_id` UInt64 DEFAULT 0 NOT NULL,
+ `label_ids` Array(UInt64) DEFAULT [] NOT NULL,
+ `assignee_ids` Array(UInt64) DEFAULT [] NOT NULL,
+ `source_branch` String DEFAULT '' NOT NULL,
+ `target_branch` String DEFAULT '' NOT NULL,
+ `merged_at` DateTime64(6, 'UTC') NOT NULL,
+ `created_at` DateTime64(6, 'UTC') DEFAULT now() NOT NULL,
+ `updated_at` DateTime64(6, 'UTC') DEFAULT now() NOT NULL
+)
+ENGINE = ReplacingMergeTree(updated_at)
+ORDER BY (project_id, merged_at, id);
+```
+
+Similarly to the [activity data example](gitlab_activity_data.md), we use the
+`ReplacingMergeTree` engine. Several columns of the merge request record may change,
+so keeping the table up-to-date is important.
+
+The database table is ordered by the `project_id, merged_at, id` columns. This ordering
+optimizes the table data for our use case: querying the `merged_at` column in a project.
+
+## Rewrite the count query
+
+First, let's generate some data for the table.
+
+```sql
+INSERT INTO merge_requests (id, project_id, author_id, milestone_id, label_ids, merged_at, created_at)
+SELECT id, project_id, author_id, milestone_id, label_ids, merged_at, created_at
+FROM generateRandom('id UInt64, project_id UInt8, author_id UInt8, milestone_id UInt8, label_ids Array(UInt8), merged_at DateTime64(6, \'UTC\'), created_at DateTime64(6, \'UTC\')')
+LIMIT 1000000;
+```
+
+NOTE:
+Some integer data types were cast as `UInt8` so it is highly probable that they
+have same values across different rows.
+
+The original count query only aggregated data for one month. With ClickHouse, we can
+attempt aggregating the data for the whole year.
+
+PostgreSQL-based count query:
+
+```sql
+SELECT COUNT(*)
+FROM "merge_requests"
+INNER JOIN "merge_request_metrics" ON "merge_request_metrics"."merge_request_id" = "merge_requests"."id"
+WHERE (NOT EXISTS
+ (SELECT 1
+ FROM "banned_users"
+ WHERE (merge_requests.author_id = banned_users.user_id)))
+ AND "merge_request_metrics"."target_project_id" = 278964
+ AND "merge_request_metrics"."merged_at" >= '2022-12-01 00:00:00'
+ AND "merge_request_metrics"."merged_at" <= '2023-01-01 00:00:00'
+```
+
+ClickHouse query:
+
+```sql
+SELECT
+ toYear(merged_at) AS year,
+ toMonth(merged_at) AS month,
+ COUNT(*)
+FROM merge_requests
+WHERE
+ project_id = 200
+ AND merged_at BETWEEN '2022-01-01 00:00:00'
+ AND '2023-01-01 00:00:00'
+GROUP BY year, month
+```
+
+The query processed a significantly lower number of rows compared to the generated data.
+The `ORDER BY` clause (primary key) is helping the query execution:
+
+```plaintext
+11 rows in set. Elapsed: 0.010 sec.
+Processed 8.19 thousand rows, 131.07 KB (783.45 thousand rows/s., 12.54 MB/s.)
+```
+
+## Rewrite the Mean time to merge query
+
+The query calculates the mean time to merge as:
+`duration(created_at, merged_at) / merge_request_count`. The calculation is done in
+two separate steps:
+
+1. Request the monthly counts and the monthly duration values.
+1. Sum the counts to get the yearly count.
+1. Sum the durations to get the yearly duration.
+1. Divide the durations by the count.
+
+In ClickHouse, we can calculate the mean time to merge with one query:
+
+```sql
+SELECT
+ SUM(
+ dateDiff('second', merged_at, created_at) / 3600 / 24
+ ) / COUNT(*) AS mean_time_to_merge -- mean_time_to_merge is in days
+FROM merge_requests
+WHERE
+ project_id = 200
+ AND merged_at BETWEEN '2022-01-01 00:00:00'
+ AND '2023-01-01 00:00:00'
+```
+
+## Filtering
+
+The database queries above can be used as base queries. You can add more filters.
+For example, filtering for a label and a milestone:
+
+```sql
+SELECT
+ toYear(merged_at) AS year,
+ toMonth(merged_at) AS month,
+ COUNT(*)
+FROM merge_requests
+WHERE
+ project_id = 200
+ AND milestone_id = 15
+ AND has(label_ids, 118)
+ AND -- array includes 118
+ merged_at BETWEEN '2022-01-01 00:00:00'
+ AND '2023-01-01 00:00:00'
+GROUP BY year, month
+```
+
+Optimizing a particular filter is usually done with a database index. This particular
+query reads 8000 rows:
+
+```plaintext
+1 row in set. Elapsed: 0.016 sec.
+Processed 8.19 thousand rows, 589.99 KB (505.38 thousand rows/s., 36.40 MB/s.)
+```
+
+Adding an index on `milestone_id`:
+
+```sql
+ALTER TABLE merge_requests
+ADD
+ INDEX milestone_id_index milestone_id TYPE minmax GRANULARITY 10;
+ALTER TABLE
+ merge_requests MATERIALIZE INDEX milestone_id_index;
+```
+
+On the generated data, adding the index didn't improve the performance.
+
+### Banned users filter
+
+A recently added feature in GitLab filters out merge requests where the author is
+banned by the admins. The banned users are tracked on the instance level in the
+`banned_users` database table.
+
+#### Idea 1: Enumerate the banned user IDs
+
+This would require no structural changes to the ClickHouse database schema.
+We could query the banned users in the project and filter the values out in query time.
+
+Get the banned users (in PostgreSQL):
+
+```sql
+SELECT user_id FROM banned_users
+```
+
+In ClickHouse
+
+```sql
+SELECT
+ toYear(merged_at) AS year,
+ toMonth(merged_at) AS month,
+ COUNT(*)
+FROM merge_requests
+WHERE
+ author_id NOT IN (1, 2, 3, 4) AND -- banned users
+ project_id = 200
+ AND milestone_id = 15
+ AND has(label_ids, 118) AND -- array includes 118
+ merged_at BETWEEN '2022-01-01 00:00:00'
+ AND '2023-01-01 00:00:00'
+GROUP BY year, month
+```
+
+The problem with this approach is that the number of banned users could increase significantly which would make the query bigger and slower.
+
+#### Idea 2: replicate the `banned_users` table
+
+Assuming that the `banned_users table` doesn't grow to millions of rows, we could
+attempt to periodically sync the whole table to ClickHouse. With this approach,
+a mostly consistent `banned_users` table could be used in the ClickHouse database query:
+
+```sql
+SELECT
+ toYear(merged_at) AS year,
+ toMonth(merged_at) AS month,
+ COUNT(*)
+FROM merge_requests
+WHERE
+ author_id NOT IN (SELECT user_id FROM banned_users) AND
+ project_id = 200 AND
+ milestone_id = 15 AND
+ has(label_ids, 118) AND -- array includes 118
+ merged_at BETWEEN '2022-01-01 00:00:00' AND '2023-01-01 00:00:00'
+GROUP BY year, month
+```
+
+Alternatively, the `banned_users` table could be stored as a
+[dictionary](https://clickhouse.com/docs/en/sql-reference/dictionaries/external-dictionaries/external-dicts)
+to further improve the query performance.
+
+#### Idea 3: Alter the feature
+
+For analytical calculations, it might be acceptable to drop this particular filter.
+This approach assumes that including the merge requests of banned users doesn't skew the statistics significantly.
diff --git a/doc/development/database/clickhouse/tiered_storage.md b/doc/development/database/clickhouse/tiered_storage.md
new file mode 100644
index 00000000000..d9026f47e28
--- /dev/null
+++ b/doc/development/database/clickhouse/tiered_storage.md
@@ -0,0 +1,138 @@
+---
+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
+---
+
+# Tiered Storages in ClickHouse
+
+NOTE:
+The MergeTree table engine in ClickHouse supports tiered storage.
+See the documentation for [Using Multiple Block Devices for Data Storage](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-multiple-volumes)
+for details on setup and further explanation.
+
+Quoting from the [MergeTree documentation](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-multiple-volumes):
+
+<!-- vale gitlab.Simplicity = NO -->
+
+> MergeTree family table engines can store data on multiple block devices. For example,
+> it can be useful when the data of a certain table are implicitly split into "hot" and "cold".
+> The most recent data is regularly requested but requires only a small amount of space.
+> On the contrary, the fat-tailed historical data is requested rarely.
+
+<!-- vale gitlab.Simplicity = YES -->
+
+When used with remote storage backends such as
+[Amazon S3](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-s3),
+this makes a very efficient storage scheme. It allows for storage policies, which
+allows data to be on local disks for a period of time and then move it to object storage.
+
+An [example configuration](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-multiple-volumes_configure) can look like this:
+
+```xml
+<storage_configuration>
+ <disks>
+ <fast_ssd>
+ <path>/mnt/fast_ssd/clickhouse/</path>
+ </fast_ssd>
+ <gcs>
+ <support_batch_delete>false</support_batch_delete>
+ <type>s3</type>
+ <endpoint>https://storage.googleapis.com/${BUCKET_NAME}/${ROOT_FOLDER}/</endpoint>
+ <access_key_id>${SERVICE_ACCOUNT_HMAC_KEY}</access_key_id>
+ <secret_access_key>${SERVICE_ACCOUNT_HMAC_SECRET}</secret_access_key>
+ <metadata_path>/var/lib/clickhouse/disks/gcs/</metadata_path>
+ </gcs>
+ ...
+ </disks>
+ ...
+ <policies>
+
+ <move_from_local_disks_to_gcs> <!-- policy name -->
+ <volumes>
+ <hot> <!-- volume name -->
+ <disk>fast_ssd</disk> <!-- disk name -->
+ </hot>
+ <cold>
+ <disk>gcs</disk>
+ </cold>
+ </volumes>
+ <move_factor>0.2</move_factor>
+ <!-- The move factor determines when to move data from hot volume to cold.
+ See ClickHouse docs for more details. -->
+ </moving_from_ssd_to_hdd>
+ ....
+</storage_configuration>
+```
+
+In this storage policy, two volumes are defined `hot` and `cold`. After the `hot` volume is filled with occupancy of `disk_size * move_factor`, the data is being moved to Google Cloud Storage (GCS).
+
+If this storage policy is not the default, create tables by attaching the storage policies. For example:
+
+```sql
+CREATE TABLE key_value_table (
+ event_date Date,
+ key String,
+ value String,
+) ENGINE = MergeTree
+ORDER BY (key)
+PARTITION BY toYYYYMM(event_date)
+SETTINGS storage_policy = 'move_from_local_disks_to_gcs'
+```
+
+NOTE:
+In this storage policy, the move happens implicitly. It is also possible to keep
+_hot_ data on local disks for a fixed period of time and then move them as _cold_.
+
+This approach is possible with
+[Table TTLs](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree/#mergetree-table-ttl),
+which are also available with MergeTree table engine.
+
+The ClickHouse documentation shows this feature in detail, in the example of
+[implementing a hot - warm - cold architecture](https://clickhouse.com/docs/en/guides/developer/ttl/#implementing-a-hotwarmcold-architecture).
+
+You can take a similar approach for the example shown above. First, adjust the storage policy:
+
+```xml
+<storage_configuration>
+ ...
+ <policies>
+ <local_disk_and_gcs> <!-- policy name -->
+ <volumes>
+ <hot> <!-- volume name -->
+ <disk>fast_ssd</disk> <!-- disk name -->
+ </hot>
+ <cold>
+ <disk>gcs</disk>
+ </cold>
+ </volumes>
+ </local_disk_and_gcs>
+ ....
+</storage_configuration>
+```
+
+Then create the table as:
+
+```sql
+CREATE TABLE another_key_value_table (
+ event_date Date,
+ key String,
+ value String,
+) ENGINE = MergeTree
+ORDER BY (key)
+PARTITION BY toYYYYMM(event_date)
+TTL
+ event_date TO VOLUME 'hot',
+ event_date + INTERVAL 1 YEAR TO VOLUME 'cold'
+SETTINGS storage_policy = 'local_disk_and_gcs';
+```
+
+This creates the table so that data older than 1 year (evaluated against the
+`event_date` column) is moved to GCS. Such a storage policy can be helpful for append-only
+tables (like audit events) where only the most recent data is accessed frequently.
+You can drop the data altogether, which can be a regulatory requirement.
+
+We don't mention modifying TTLs in this guide, but that is possible as well.
+See ClickHouse documentation for
+[modifying TTL](https://clickhouse.com/docs/en/sql-reference/statements/alter/ttl/#modify-ttl)
+for details.
diff --git a/doc/development/database/database_dictionary.md b/doc/development/database/database_dictionary.md
index b7e6fa4b5b3..515bf00c6f0 100644
--- a/doc/development/database/database_dictionary.md
+++ b/doc/development/database/database_dictionary.md
@@ -26,6 +26,7 @@ feature_categories:
description: Represents a Terraform state backend
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26619
milestone: '13.0'
+gitlab_schema: gitlab_main
```
## Adding tables
diff --git a/doc/development/database/database_lab.md b/doc/development/database/database_lab.md
index 162fc597cc4..e428b9d4b0a 100644
--- a/doc/development/database/database_lab.md
+++ b/doc/development/database/database_lab.md
@@ -12,6 +12,17 @@ on replicated production data. Unlike a typical read-only production replica, in
also create, update, and delete rows. You can also test the performance of
schema changes, like additional indexes or columns, in an isolated copy of production data.
+## Database Lab quick start
+
+1. [Visit the console](https://console.postgres.ai/).
+1. Select **Sign in with Google**. (Not GitLab, as you need Google SSO to connect with our project.)
+1. After you sign in, select the GitLab organization and then visit "Ask Joe" in the sidebar.
+1. Select the database you're testing against:
+ - Most queries for the GitLab project run against `gitlab-production-tunnel-pg12`.
+ - If the query is for a CI table, select `gitlab-production-ci`.
+ - If the query is for the container registry, select `gitlab-production-registry`.
+1. Type `explain <Query Text>` in the chat box to get a plan.
+
## Access Database Lab Engine
Access to the DLE is helpful for:
@@ -21,7 +32,7 @@ Access to the DLE is helpful for:
To access the DLE's services, you can:
-- Perform query testing in the `#database_lab` Slack channel, or in the Postgres.ai web console.
+- Perform query testing in the Postgres.ai web console.
Employees access both services with their GitLab Google account. Query testing
provides `EXPLAIN` (analyze, buffers) plans for queries executed there.
- Migration testing by triggering a job as a part of a merge request.
@@ -40,8 +51,6 @@ This procedure is similar to [Rails console access with Teleport](https://gitlab
You can access Database Lab's query analysis features either:
-- In the `#database_lab` Slack channel. Shows everyone's commands and results, but
- your own commands are still isolated in their own clone.
- In [the Postgres.ai web console](https://console.postgres.ai/GitLab/joe-instances).
Shows only the commands you run.
diff --git a/doc/development/database/database_migration_pipeline.md b/doc/development/database/database_migration_pipeline.md
index 06e16b4c7f1..2344ee3f942 100644
--- a/doc/development/database/database_migration_pipeline.md
+++ b/doc/development/database/database_migration_pipeline.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/database-team/team-tasks/-/issues/171) in GitLab 14.2.
With the [automated migration testing pipeline](https://gitlab.com/gitlab-org/database-team/gitlab-com-database-testing)
-we can automatically test migrations in a production-like environment (similar to `#database-lab`).
+we can automatically test migrations in a production-like environment (using [Database Lab](database_lab.md)).
It is based on an [architecture blueprint](../../architecture/blueprints/database_testing/index.md).
Migration testing is enabled in the [GitLab project](https://gitlab.com/gitlab-org/gitlab)
diff --git a/doc/development/database/database_reviewer_guidelines.md b/doc/development/database/database_reviewer_guidelines.md
index aa92134018d..933bbe9c060 100644
--- a/doc/development/database/database_reviewer_guidelines.md
+++ b/doc/development/database/database_reviewer_guidelines.md
@@ -53,9 +53,8 @@ that require a more in-depth discussion between the database reviewers and maint
- [Database Office Hours Agenda](https://docs.google.com/document/d/1wgfmVL30F8SdMg-9yY6Y8djPSxWNvKmhR5XmsvYX1EI/edit).
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [YouTube playlist with past recordings](https://www.youtube.com/playlist?list=PL05JrBw4t0Kp-kqXeiF7fF7cFYaKtdqXM).
-You should also join the [#database-lab](understanding_explain_plans.md#database-lab-engine)
-Slack channel and get familiar with how to use Joe, the Slackbot that provides developers
-with their own clone of the production database.
+Get familiar with using [Database Lab from postgres.ai](database_lab.md), a bot that
+provides developers with their own clone of the production database.
Understanding and efficiently using `EXPLAIN` plans is at the core of the database review process.
The following guides provide a quick introduction and links to follow on more advanced topics:
diff --git a/doc/development/database/index.md b/doc/development/database/index.md
index 8f22eaac496..2cb8509e203 100644
--- a/doc/development/database/index.md
+++ b/doc/development/database/index.md
@@ -4,7 +4,7 @@ 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
---
-# Database guides
+# Database development guidelines
## Database Reviews
@@ -109,6 +109,8 @@ including the major methods:
- [Introduction](clickhouse/index.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)
+- [Tiered Storage in ClickHouse](clickhouse/tiered_storage.md)
## Miscellaneous
diff --git a/doc/development/database/multiple_databases.md b/doc/development/database/multiple_databases.md
index d22e3209096..c1b30a4cbbe 100644
--- a/doc/development/database/multiple_databases.md
+++ b/doc/development/database/multiple_databases.md
@@ -1,6 +1,6 @@
---
stage: Data Stores
-group: Pods
+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
---
diff --git a/doc/development/database/query_performance.md b/doc/development/database/query_performance.md
index 73a6a40f801..10ab726940a 100644
--- a/doc/development/database/query_performance.md
+++ b/doc/development/database/query_performance.md
@@ -44,7 +44,7 @@ automatically includes these options.
If you are making a warm cache query, you see only the `shared hits`.
-For example in #database-lab:
+For example, using [Database Lab](database_lab.md):
```plaintext
Shared buffers:
@@ -60,7 +60,7 @@ Buffers: shared hit=7323
If the cache is cold, you also see `reads`.
-In #database-lab:
+Using [Database Lab](database_lab.md):
```plaintext
Shared buffers:
diff --git a/doc/development/database/required_stops.md b/doc/development/database/required_stops.md
index 46fabb5c1b4..b706babbc5e 100644
--- a/doc/development/database/required_stops.md
+++ b/doc/development/database/required_stops.md
@@ -11,6 +11,36 @@ disruptive effect on customers. Before adding a required stop, consider if any
alternative approaches exist to avoid a required stop. Sometimes a required
stop is unavoidable. In those cases, follow the instructions below.
+## Common scenarios that require stops
+
+### Long running migrations being finalized
+
+If a migration takes a long time, it could cause a large number of customers to encounter timeouts
+during upgrades. The increased support volume may cause us to introduce a required stop. While any
+background migration may cause these issues with particularly large customers, we typically only
+introduce stops when the impact is widespread.
+
+- **Cause:** When an upgrade takes more than an hour, omnibus times out.
+- **Mitigation:** Schedule finalization for the first minor version after the next required stop.
+
+### Improperly finalized background migrations
+
+You may need to introduce a required stop for mitigation when:
+
+- A background migration is not finalized, and
+- A migration is written that depends on that background migration.
+
+- **Cause:** The dependent migration may fail if the background migration is incomplete.
+- **Mitigation:** Ensure that all background migrations are finalized before authoring dependent migrations.
+
+### Bugs in migration related tooling
+
+In a few circumstances, bugs in migration related tooling has required us to introduce stops. While we aim
+to prevent these in testing, sometimes they happen.
+
+- **Cause:** There have been a few different causes where we recognized these too late.
+- **Mitigation:** Typically we try to backport fixes for migrations, but in some cases this is not possible.
+
## Before the required stop is released
Before releasing a known required stop, complete these steps. If the required stop
diff --git a/doc/development/database/understanding_explain_plans.md b/doc/development/database/understanding_explain_plans.md
index 094bd6b346f..560744430f9 100644
--- a/doc/development/database/understanding_explain_plans.md
+++ b/doc/development/database/understanding_explain_plans.md
@@ -714,8 +714,7 @@ SQL optimization tool - [Joe Bot](https://gitlab.com/postgres-ai/joe).
Database Lab Engine provides developers with their own clone of the production database, while Joe Bot helps with exploring execution plans.
-Joe Bot is available in the [`#database-lab`](https://gitlab.slack.com/archives/CLJMDRD8C) channel on Slack,
-and through its [web interface](https://console.postgres.ai/gitlab/joe-instances).
+Joe Bot is available through its [web interface](https://console.postgres.ai/gitlab/joe-instances).
With Joe Bot you can execute DDL statements (like creating indexes, tables, and columns) and get query plans for `SELECT`, `UPDATE`, and `DELETE` statements.
@@ -792,34 +791,6 @@ Planning time: 0.411 ms
Execution time: 0.113 ms
```
-### ChatOps
-
-GitLab team members can also use our ChatOps solution, available in Slack
-using the [`/chatops` slash command](../chatops_on_gitlabcom.md).
-
-NOTE:
-While ChatOps is still available, the recommended way to generate execution plans is to use [Database Lab Engine](#database-lab-engine).
-
-You can use ChatOps to get a query plan by running the following:
-
-```sql
-/chatops run explain SELECT COUNT(*) FROM projects WHERE visibility_level IN (0, 20)
-```
-
-Visualising the plan using <https://explain.depesz.com/> is also supported:
-
-```sql
-/chatops run explain --visual SELECT COUNT(*) FROM projects WHERE visibility_level IN (0, 20)
-```
-
-Quoting the query is not necessary.
-
-For more information about the available options, run:
-
-```sql
-/chatops run explain --help
-```
-
## Further reading
A more extensive guide on understanding query plans can be found in
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index 048482960f4..1f653f8af94 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -68,7 +68,7 @@ Refer to [Preparation when adding or modifying queries](#preparation-when-adding
A merge request **author**'s role is to:
- Decide whether a database review is needed.
-- If database review is needed, add the ~database label.
+- If database review is needed, add the `~database` label.
- [Prepare the merge request for a database review](#how-to-prepare-the-merge-request-for-a-database-review).
- Provide the [required](#required) artifacts prior to submitting the MR.
@@ -99,7 +99,7 @@ The MR author should request a review from the suggested database
the suggested database **maintainer**.
If reviewer roulette didn't suggest a database reviewer & maintainer,
-make sure you have applied the ~database label and rerun the
+make sure you have applied the `~database` label and rerun the
`danger-review` CI job, or pick someone from the
[`@gl-database` team](https://gitlab.com/groups/gl-database/-/group_members).
@@ -122,14 +122,14 @@ the following preparations into account.
- When [high-traffic](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/rubocop-migrations.yml#L3) tables are involved in the migration, use the [`enable_lock_retries`](migration_style_guide.md#retry-mechanism-when-acquiring-database-locks) method to enable lock-retries. Review the relevant [examples in our documentation](migration_style_guide.md#usage-with-transactional-migrations) for use cases and solutions.
- Ensure RuboCop checks are not disabled unless there's a valid reason to.
- When adding an index to a [large table](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/rubocop-migrations.yml#L3),
-test its execution using `CREATE INDEX CONCURRENTLY` in the `#database-lab` Slack channel and add the execution time to the MR description:
- - Execution time largely varies between `#database-lab` and GitLab.com, but an elevated execution time from `#database-lab`
+ test its execution using `CREATE INDEX CONCURRENTLY` in [Database Lab](database/database_lab.md) and add the execution time to the MR description:
+ - Execution time largely varies between Database Lab and GitLab.com, but an elevated execution time from Database Lab
can give a hint that the execution on GitLab.com is also considerably high.
- - If the execution from `#database-lab` is longer than `1h`, the index should be moved to a [post-migration](database/post_deployment_migrations.md).
+ - If the execution from Database Lab is longer than `1h`, the index should be moved to a [post-migration](database/post_deployment_migrations.md).
Keep in mind that in this case you may need to split the migration and the application changes in separate releases to ensure the index
is in place when the code that needs it is deployed.
- Manually trigger the [database testing](database/database_migration_pipeline.md) job (`db:gitlabcom-database-testing`) in the `test` stage.
- - This job runs migrations in a production-like environment (similar to `#database_lab`) and posts to the MR its findings (queries, runtime, size change).
+ - This job runs migrations in a [Database Lab](database/database_lab.md) clone and posts to the MR its findings (queries, runtime, size change).
- Review migration runtimes and any warnings.
#### Preparation when adding data migrations
@@ -173,13 +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 public link to the plan from either:
- - [postgres.ai](https://postgres.ai/): Follow the link in `#database-lab` and generate a shareable, public link
- by selecting **Share** in the upper right corner.
- - [explain.depesz.com](https://explain.depesz.com) or [explain.dalibo.com](https://explain.dalibo.com): Paste both the plan and the query used in the form.
+- Provide a link to the plan from [postgres.ai](database/database_lab.md), provided by the 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.
- When providing query plans, make sure it hits enough data:
- - You can use a GitLab production replica to test your queries on a large scale,
- through the `#database-lab` Slack channel or through [ChatOps](database/understanding_explain_plans.md#chatops).
- 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.
- The `gitlab-org/gitlab-foss` (`project_id = 13083`) or the `gitlab-org/gitlab` (`project_id = 278964`) projects, for queries involving a project.
@@ -188,7 +186,7 @@ Include in the MR description:
- That means that no query plan should return 0 records or less records than the provided limit (if a limit is included). If a query is used in batching, a proper example batch with adequate included results should be identified and provided.
- If your queries belong to a new feature in GitLab.com and thus they don't return data in production:
- You may analyze the query and to provide the plan from a local environment.
- - `#database-lab` and [postgres.ai](https://postgres.ai/) both allow updates to data (`exec UPDATE issues SET ...`) and creation of new tables and columns (`exec ALTER TABLE issues ADD COLUMN ...`).
+ - [postgres.ai](https://postgres.ai/) allows updates to data (`exec UPDATE issues SET ...`) and creation of new tables and columns (`exec ALTER TABLE issues ADD COLUMN ...`).
- More information on how to find the number of actual returned records in [Understanding EXPLAIN plans](database/understanding_explain_plans.md)
- For query changes, it is best to provide both the SQL queries along with the
plan _before_ and _after_ the change. This helps spot differences quickly.
@@ -231,7 +229,7 @@ Include in the MR description:
- [Check indexes are present for foreign keys](migration_style_guide.md#adding-foreign-key-constraints)
- Ensure that migrations execute in a transaction or only contain
concurrent index/foreign key helpers (with transactions disabled)
- - If an index to a large table is added and its execution time was elevated (more than 1h) on `#database-lab`:
+ - If an index to a large table is added and its execution time was elevated (more than 1h) on [Database Lab](database/database_lab.md):
- Ensure it was added in a post-migration.
- Maintainer: After the merge request is merged, notify Release Managers about it on `#f_upcoming_release` Slack channel.
- Check consistency with `db/structure.sql` and that migrations are [reversible](migration_style_guide.md#reversibility)
@@ -269,8 +267,7 @@ Include in the MR description:
- Check for any overly complex queries and queries the author specifically
points out for review (if any)
- If not present, ask the author to provide SQL queries and query plans
- (for example, by using [ChatOps](database/understanding_explain_plans.md#chatops) or direct
- database access)
+ using [Database Lab](database/database_lab.md)
- For given queries, review parameters regarding data distribution
- [Check query plans](database/understanding_explain_plans.md) and suggest improvements
to queries (changing the query, schema or adding indexes and similar)
diff --git a/doc/development/deprecation_guidelines/index.md b/doc/development/deprecation_guidelines/index.md
index e532fa82011..bc14b0f127c 100644
--- a/doc/development/deprecation_guidelines/index.md
+++ b/doc/development/deprecation_guidelines/index.md
@@ -62,6 +62,8 @@ A breaking change can be considered major if it affects many users, or represent
Deprecations should be announced on the [Deprecated feature removal schedule](../../update/deprecations.md).
+Deprecations should be announced [no later than the third milestone preceding intended removal](https://about.gitlab.com/handbook/product/gitlab-the-product/#process-for-deprecating-and-removing-a-feature).
+
Do not include the deprecation announcement in the merge request that introduces a code change for the deprecation.
Use a separate MR to create a deprecation entry. For steps to create a deprecation entry, see
[Deprecations](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations).
@@ -77,7 +79,7 @@ However, at GitLab, we [give agency](https://about.gitlab.com/handbook/values/#g
Generally, feature or configuration can be removed/changed only on major release.
It also should be [deprecated in advance](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations).
-For API removals, see the [GraphQL](../../api/graphql/index.md#deprecation-and-removal-process) and [GitLab API](../../api/rest/index.md#compatibility-guidelines) guidelines.
+For API removals, see the [GraphQL](../../api/graphql/index.md#deprecation-and-removal-process) and [GitLab API](../documentation/restful_api_styleguide.md#deprecations) guidelines.
For configuration removals, see the [Omnibus deprecation policy](../../administration/package_information/deprecation_policy.md).
diff --git a/doc/development/directory_structure.md b/doc/development/directory_structure.md
deleted file mode 100644
index 34ee86d9ee5..00000000000
--- a/doc/development/directory_structure.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'software_design.md'
-remove_date: '2023-01-24'
----
-
-This document was moved to [another location](software_design.md)
-
-<!-- This redirect file can be deleted after <2023-01-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 (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/distributed_tracing.md b/doc/development/distributed_tracing.md
index 79d0ff84713..bd9e7035290 100644
--- a/doc/development/distributed_tracing.md
+++ b/doc/development/distributed_tracing.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
---
-# Distributed Tracing - development guidelines
+# Distributed tracing development guidelines
GitLab is instrumented for distributed tracing. Distributed Tracing in GitLab is currently considered **experimental**, as it has not yet been tested at scale on GitLab.com.
diff --git a/doc/development/distribution/index.md b/doc/development/distribution/index.md
new file mode 100644
index 00000000000..168e3854eca
--- /dev/null
+++ b/doc/development/distribution/index.md
@@ -0,0 +1,35 @@
+---
+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
+description: "GitLab's development guidelines for Distribution"
+---
+
+# Contribute to GitLab Distribution
+
+Learn how to add new components and services to the GitLab application.
+
+## Support all package methods
+
+Additions must support both Omnibus GitLab and Cloud Native GitLab. Changes
+to one must be made to the other to retain feature parity.
+
+## Contributing
+
+The primary projects handled by Distribution are listed below. For more
+information, visit the [Distribution team engineering handbook page](https://about.gitlab.com/handbook/engineering/development/enablement/systems/distribution/)
+or select one of the subsections in the navigation bar.
+
+### GitLab application
+
+- [Omnibus GitLab](https://gitlab.com/gitlab-org/omnibus-gitlab)
+- [Cloud Native GitLab (CNG)](https://gitlab.com/gitlab-org/build/CNG)
+- [GitLab Operator](https://gitlab.com/gitlab-org/cloud-native/gitlab-operator)
+- [GitLab Chart](https://gitlab.com/gitlab-org/charts/gitlab)
+
+### Components and tools
+
+- [Omnibus GitLab Builder](https://gitlab.com/gitlab-org/gitlab-omnibus-builder)
+- [Omnibus Fork](https://gitlab.com/gitlab-org/omnibus)
+- [GitLab Logger](https://gitlab.com/gitlab-org/cloud-native/gitlab-logger)
+- [Issue Bot](https://gitlab.com/gitlab-org/distribution/issue-bot)
diff --git a/doc/development/documentation/alpha_beta.md b/doc/development/documentation/alpha_beta.md
new file mode 100644
index 00000000000..4b5c24d512f
--- /dev/null
+++ b/doc/development/documentation/alpha_beta.md
@@ -0,0 +1,43 @@
+---
+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
+---
+
+# Document Alpha, Beta, LA features
+
+Some features are not generally available and are instead considered
+[Alpha, Beta, or Limited Availability](../../policy/alpha-beta-support.md).
+
+When you document a feature in one of these three statuses:
+
+- Add `(Alpha)`, `(Beta)`, or `(Limited Availability)` in parentheses after the page or topic title.
+- Do not include `(Alpha)`, `(Beta)`, or `(Limited Availability)` 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 (Alpha)
+
+FLAG:
+On self-managed GitLab, by default this feature is not available.
+To make it available, ask an administrator to 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 in Alpha. 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 released, remove:
+
+- The text in parentheses.
+- Any language about the feature not being ready for production.
+- The feature flag information.
+
+Ensure the version history is up-to-date.
diff --git a/doc/development/documentation/contribute.md b/doc/development/documentation/contribute.md
new file mode 100644
index 00000000000..8b08743c6e9
--- /dev/null
+++ b/doc/development/documentation/contribute.md
@@ -0,0 +1,83 @@
+---
+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
+---
+
+# Contribute to the GitLab documentation
+
+Everyone is welcome to update the GitLab documentation!
+
+## Work without an issue
+
+You don't need an issue to update the documentation.
+
+On [https://docs.gitlab.com](https://docs.gitlab.com), at the bottom of any page,
+you can select **View page source** or **Edit in Web IDE** and [get started with a merge request](#open-your-merge-request).
+
+You can alternately:
+
+- Choose a page [in the `/doc` directory](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc)
+ and edit it from there.
+- Try installing and running the [Vale linting tool](testing.md#vale)
+ and fixing the resulting issues.
+
+When you're developing code, the workflow for updating docs is slightly different.
+For details, see the [merge request workflow](../contributing/merge_request_workflow.md).
+
+## Search available issues
+
+If you're looking for an open issue, you can
+[review the list of documentation issues curated specifically for new contributors](https://gitlab.com/gitlab-org/gitlab/-/issues/?sort=created_date&state=opened&label_name%5B%5D=documentation&label_name%5B%5D=docs-only&label_name%5B%5D=Seeking%20community%20contributions&first_page_size=20).
+
+When you find an issue you'd like to work on:
+
+- If the issue is already assigned to someone, pick a different one.
+- If the issue is unassigned, add a comment and ask to work on the issue. For a Hackathon, use `@docs-hackathon`. Otherwise, use `@gl-docsteam`. For example:
+
+ ```plaintext
+ @docs-hackathon I would like to work on this issue
+ ```
+
+- Do not ask for more than three issues at a time.
+
+## Open your merge request
+
+When you are ready to update the documentation:
+
+1. Go to the [GitLab repository](https://gitlab.com/gitlab-org/gitlab).
+1. In the upper-right corner, select **Fork**. Forking makes a copy of the repository on GitLab.com.
+1. In your fork, find the documentation page in the `\doc` directory.
+1. If you know Git, make your changes and open a merge request.
+ If not, follow these steps:
+ 1. In the upper-right corner, select **Edit** if it is visible.
+ If it is not, select the down arrow (**{chevron-lg-down}**) next to
+ **Open in Web IDE** or **Gitpod**, and select **Edit**.
+ 1. In the **Commit message** text box, enter a commit message.
+ Use 3-5 words, start with a capital letter, and do not end with a period.
+ 1. Select **Commit changes**.
+ 1. On the left sidebar, select **Merge requests**.
+ 1. Select **New merge request**.
+ 1. For the source branch, select your fork and branch. If you did not create a branch, select `master`.
+ For the target branch, select the [GitLab repository](https://gitlab.com/gitlab-org/gitlab) `master` branch.
+ 1. Select **Compare branches and continue**. A new merge request opens.
+ 1. Select the **Documentation** template. In the description, write a brief summary of the changes and link to the related issue, if there is one.
+ 1. Select **Create merge request**.
+
+## Ask for help
+
+Ask for help from the Technical Writing team if you:
+
+- Need help to choose the correct place for documentation.
+- Want to discuss a documentation idea or outline.
+- Want to request any other help.
+
+To identify someone who can help you:
+
+1. Locate the Technical Writer for the relevant
+ [DevOps stage group](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments).
+1. Either:
+ - If urgent help is required, directly assign the Technical Writer in the issue or in the merge request.
+ - If non-urgent help is required, ping the Technical Writer in the issue or merge request.
+
+If you are a member of the GitLab Slack workspace, you can request help in the `#docs` channel.
diff --git a/doc/development/documentation/feature_flags.md b/doc/development/documentation/feature_flags.md
index 37be2178592..986252eedac 100644
--- a/doc/development/documentation/feature_flags.md
+++ b/doc/development/documentation/feature_flags.md
@@ -7,33 +7,32 @@ description: "GitLab development - how to document features deployed behind feat
# Document features deployed behind feature flags
-GitLab uses [feature flags](../feature_flags/index.md) to strategically roll
-out the deployment of its own features. The way we document a feature behind a
-feature flag depends on its state (enabled or disabled). When the state
-changes, the developer who made the change **must update the documentation**
-accordingly.
+GitLab uses [feature flags](../feature_flags/index.md) to roll
+out the deployment of its own features.
+
+When the state of a feature flag changes, the developer who made the change
+**must update the documentation**.
## When to document features behind a feature flag
Every feature introduced to the codebase, even if it's behind a disabled feature flag,
must be documented. For more information, see
-[the discussion that led to this decision](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47917#note_459984428).
+[the discussion that led to this decision](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47917#note_459984428). [Alpha, Beta, or Limited Availability](../../policy/alpha-beta-support.md) features are usually behind a feature flag, and must also be documented. For more information, see [Document Alpha, Beta, LA features](alpha_beta.md).
+
+When the feature is [implemented in multiple merge requests](../feature_flags/index.md#feature-flags-in-gitlab-development),
+discuss the plan with your technical writer.
-When the feature is [implemented over multiple merge requests](../feature_flags/index.md#feature-flags-in-gitlab-development),
-discuss the exact documentation plan with your technical writer. Consider
-creating a dedicated documentation issue if the feature:
+You can create a documentation issue and delay the documentation if the feature:
- Is far-reaching (makes changes across many areas of GitLab), like navigation changes.
- Includes many MRs.
- Affects more than a few documentation pages.
- Is not fully functional if the feature flag is enabled for testing.
-If you and the technical writer agree to delay the product documentation (for example, until after testing),
-collaborate with the TW to create a documentation issue detailing the plan for adding the content.
-The PM and EM should be included in the discussions to make sure the task of adding the documentation is assigned and scheduled.
-Despite any planned delays, every feature flag in the codebase is automatically listed at
-<https://docs.gitlab.com/ee/user/feature_flags.html#available-feature-flags>,
-even when the feature is not fully functional.
+The PM, EM, and writer should make sure the documentation work is assigned and scheduled.
+
+Every feature flag in the codebase is [in the documentation](../../user/feature_flags.md),
+even when the feature is not fully functional or otherwise documented.
## How to add feature flag documentation
@@ -57,13 +56,6 @@ Possible version history entries are:
> - [Generally available](issue-link) in GitLab X.Y. Feature flag `flag_name` removed.
```
-You can combine entries if they happened in the same release:
-
-```markdown
-> - Introduced in GitLab 14.2 [with a flag](../../administration/feature_flags.md) named `ci_include_rules`. Disabled by default.
-> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/337507) in GitLab 14.3.
-```
-
## Use a note to describe the state of the feature flag
Information about feature flags should be in a `FLAG` note at the start of the topic (just below the version history).
@@ -144,3 +136,41 @@ And, when the feature is done and fully available to all users:
> - [Enabled on GitLab.com](https://gitlab.com/issue/etc) in GitLab 13.9.
> - [Generally available](issue-link) in GitLab 14.0. Feature flag `forti_token_cloud` removed.
```
+
+## Simplify long version history
+
+The version history can get long, but you can sometimes simplify or remove entries.
+
+Combine entries if they happened in the same release:
+
+- Before:
+
+ ```markdown
+ > - [Introduced](issue-link) in GitLab 14.2 [with a flag](../../administration/feature_flags.md) named `ci_include_rules`. Disabled by default.
+ > - [Enabled on GitLab.com](issue-link) in GitLab 14.3.
+ > - [Enabled on self-managed](issue-link) in GitLab 14.3.
+ ```
+
+- After:
+
+ ```markdown
+ > - [Introduced](issue-link) in GitLab 14.2 [with a flag](../../administration/feature_flags.md) named `ci_include_rules`. Disabled by default.
+ > - [Enabled on GitLab.com and self-managed](issue-link) in GitLab 14.3.
+ ```
+
+Remove `Enabled on GitLab.com` entries when the feature is enabled by default for both GitLab.com and self-managed:
+
+- Before:
+
+ ```markdown
+ > - [Introduced](issue-link) in GitLab 15.6 [with a flag](../../administration/feature_flags.md) named `ci_hooks_pre_get_sources_script`. Disabled by default.
+ > - [Enabled on GitLab.com](issue-link) in GitLab 15.9.
+ > - [Generally available](issue-link) in GitLab 15.10. Feature flag `ci_hooks_pre_get_sources_script` removed.
+ ```
+
+- After:
+
+ ```markdown
+ > - [Introduced](issue-link) in GitLab 15.6 [with a flag](../../administration/feature_flags.md) named `ci_hooks_pre_get_sources_script`. Disabled by default.
+ > - [Generally available](issue-link) in GitLab 15.10. Feature flag `ci_hooks_pre_get_sources_script` removed.
+ ```
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index fd9e885e097..d1f5ee8f9f3 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -107,8 +107,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
---
```
-If you need help determining the correct stage, read [Ask for help](workflow.md#ask-for-help).
-
### Redirection metadata
The following metadata should be added when a page is moved to another location:
@@ -157,19 +155,15 @@ You can use a Rake task to update the `CODEOWNERS` file.
#### Update the `CODEOWNERS` file
-To update the `CODEOWNERS` file:
+When groups or [TW assignments](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments)
+change, you must update the `CODEOWNERS` file:
-1. Review the [TW team assignments](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments)
- in the [`codeowners.rake`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/tasks/gitlab/tw/codeowners.rake)
- file. If any assignments have changed:
- 1. Update the `codeowners.rake` file with the changes.
- 1. Assign the merge request to a technical writing manager for review and merge.
-1. After the changes to `codeowners.rake` are merged, go to the root of the `gitlab` repository.
+1. Update the [stage and group metadata](#stage-and-group-metadata) for any affected doc pages, if necessary. If there are many changes, you can do this step in a separate MR.
+1. Update the [`codeowners.rake`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/tasks/gitlab/tw/codeowners.rake) file with the changes.
+1. Go to the root of the `gitlab` repository.
1. Run the Rake task with this command: `bundle exec rake tw:codeowners`
-1. Review the command output for any pages that need attention to
- their metadata. Handle any needed changes in a separate merge request.
-1. Add the changes to the CODEOWNERS file to Git: `git add .gitlab/CODEOWNERS`
-1. Commit your changes to your branch, and push your branch up to `origin`.
+1. Review the changes in the `CODEOWNERS` file.
+1. Add and commit all your changes and push your branch up to `origin`.
1. Create a merge request and assign it to a technical writing manager for review.
## Move, rename, or delete a page
diff --git a/doc/development/documentation/restful_api_styleguide.md b/doc/development/documentation/restful_api_styleguide.md
index a92d58ead96..93afbf7e6dd 100644
--- a/doc/development/documentation/restful_api_styleguide.md
+++ b/doc/development/documentation/restful_api_styleguide.md
@@ -132,7 +132,7 @@ To deprecate an attribute:
```
To widely announce a deprecation, or if it's a breaking change,
-[update the deprecations and removals documentation pages](../deprecation_guidelines/index.md#update-the-deprecations-and-removals-documentation-pages).
+[update the REST API deprecations and removals page](../../api/rest/deprecations.md).
## Method description
diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md
index 74437ea46c9..7f69a1f0d54 100644
--- a/doc/development/documentation/styleguide/index.md
+++ b/doc/development/documentation/styleguide/index.md
@@ -779,14 +779,18 @@ As much as possible, use text that follows one of these patterns:
For example:
-- `For more information, see [merge requests](../../../user/project/merge_requests/index.md).`
-- `To create a review app, see [review apps](../../../ci/review_apps/index.md).`
+- `For more information, see [merge requests](LINK).`
+- `To create a review app, see [review apps](LINK).`
You can expand on this text by using phrases like
`For more information about this feature, see...`
-Do not to use alternate phrases, like `Learn more about...` or
-`To read more...`.
+Do not to use the following constructions:
+
+- `Learn more about...`
+- `To read more...`.
+- `For more information, see the [Merge requests](LINK) page.`
+- `For more information, see the [Merge requests](LINK) documentation.`
#### Descriptive text rather than `here`
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index e64fd4df7ff..1ea95367d01 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -82,6 +82,11 @@ If you can add the phrase "by zombies" to the phrase,
the construction is passive. For example, `The button is selected by zombies`
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**.
+This area of the UI says **Admin Area** at the top of the page and on the menu.
+
## administrator
Use **administrator access** instead of **admin** when talking about a user's access level.
@@ -99,10 +104,9 @@ Instead of:
- To do this thing, you must have the Admin role.
-## Admin Area
+## advanced search
-Use title case **Admin Area** to refer to the area of the UI that you access when you select **Main menu > Admin**.
-This area of the UI says **Admin Area** at the top of the page and on the menu.
+Use lowercase for **advanced search** to refer to the faster, more efficient search across the entire GitLab instance.
## agent
@@ -113,7 +117,7 @@ For example:
- Install the agent in your cluster.
- Select an agent from the list.
-Do not use title case **GitLab Agent** or **GitLab Agent for Kubernetes**.
+Do not use title case for **GitLab Agent** or **GitLab Agent for Kubernetes**.
## agent access token
@@ -530,9 +534,12 @@ Use title case for **Geo**.
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/).
-## GitLab.com
+## GitLab Flavored Markdown
-**GitLab.com** refers to the GitLab instance managed by GitLab itself.
+When possible, spell out [**GitLab Flavored Markdown**](../../../user/markdown.md).
+([Vale](../testing.md#vale) rule: [`GLFM.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SubstitutionSuggestions.yml))
+
+If you must abbreviate, do not use **GFM**. Use **GLFM** instead.
## GitLab Helm chart, GitLab chart
@@ -545,26 +552,30 @@ Do not use **the `gitlab` chart**, **the GitLab Chart**, or **the cloud-native c
You use the **GitLab Helm chart** to deploy **cloud-native GitLab** in a Kubernetes cluster.
-## GitLab Flavored Markdown
+## GitLab Pages
-When possible, spell out [**GitLab Flavored Markdown**](../../../user/markdown.md).
-([Vale](../testing.md#vale) rule: [`GLFM.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SubstitutionSuggestions.yml))
+For consistency and branding, use **GitLab Pages** rather than **Pages**.
-If you must abbreviate, do not use **GFM**. Use **GLFM** instead.
+However, if you use **GitLab Pages** for the first mention on a page or in the UI,
+you can use **Pages** thereafter.
+
+## GitLab Runner
+
+Use title case for **GitLab Runner**. This is the product you install. See also [runners](#runner-runners) and [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/233529).
## GitLab SaaS
**GitLab SaaS** refers to the product license that provides access to GitLab.com. It does not refer to the
GitLab instance managed by GitLab itself.
-## GitLab Runner
-
-Use title case for **GitLab Runner**. This is the product you install. See also [runners](#runner-runners) and [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/233529).
-
## GitLab self-managed
Use **GitLab self-managed** to refer to the product license for GitLab instances managed by customers themselves.
+## GitLab.com
+
+**GitLab.com** refers to the GitLab instance managed by GitLab itself.
+
## guide
We want to speak directly to users. On `docs.gitlab.com`, do not use **guide** as part of a page title.
@@ -730,7 +741,7 @@ Do not use **limitations**. Use **known issues** instead.
## log in, log on
-Do not use **log in** or **log on**. Use [sign in](#sign-in) instead. If the user interface has **Log in**, you can use it.
+Do not use **log in** or **log on**. Use [sign in](#sign-in-sign-in) instead. If the user interface has **Log in**, you can use it.
## logged-in user, logged in user
@@ -933,6 +944,17 @@ An Owner is the highest role a user can have.
Use title case for the GitLab Package Registry.
+## page
+
+If you write a phrase like, "On the **Issues** page," ensure steps for how to get to the page are nearby. Otherwise, people might not know what the **Issues** page is.
+
+The page name should be visible in the UI at the top of the page.
+If it is not, you should be able to get the name from the breadcrumb.
+
+The docs should match the case in the UI, and the page name should be bold. For example:
+
+- On the **Test cases** page, ...
+
## permissions
Do not use [**roles**](#roles) and **permissions** interchangeably. Each user is assigned a role. Each role includes a set of permissions.
@@ -947,6 +969,12 @@ Use lowercase for **personal access token**.
Do not use **please**. For details, see the [Microsoft style guide](https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/p/please).
+## prerequisites
+
+Use **prerequisites** when documenting the steps before a task. Do not use **requirements**.
+
+For more information, see [the task topic type](../topic_types/task.md).
+
## press
Use **press** when talking about keyboard keys. For example:
@@ -1009,6 +1037,12 @@ Do not use **Reporter permissions**. A user who is assigned the Reporter role ha
Use title case for **Repository Mirroring**.
+## requirements
+
+Use **prerequisites** when documenting the steps before a task. Do not use **requirements**.
+
+For more information, see [the task topic type](../topic_types/task.md).
+
## respectively
Avoid **respectively** and be more precise instead.
@@ -1120,14 +1154,17 @@ Use **setup** as a noun, and **set up** as a verb. For example:
- Your remote office setup is amazing.
- To set up your remote office correctly, consider the ergonomics of your work area.
-## sign in
+## sign in, sign-in
-Use **sign in** or **sign in to**.
+Use **sign in** or **sign in to** as a verb to describe the action of signing in.
Do not use **sign on** or **sign into**, or **log on**, **log in**, or **log into**.
If the user interface has different words, use those.
+You can use **sign-in** as a noun or adjective. For example, **sign-in page** or
+**sign-in restrictions**.
+
You can use **single sign-on**.
## sign up
@@ -1314,7 +1351,10 @@ See also [downgrade](#downgrade) and [roll back](#roll-back).
## upper left, upper right
-Use **upper left** and **upper right** instead of **top left** and **top right**. Hyphenate as adjectives (for example, **upper-left corner**).
+Use **upper-left corner** and **upper-right corner** to provide direction in the UI.
+If the UI element is not in a corner, use **upper left** and **upper right**.
+
+Do not use **top left** and **top right**.
For details, see the [Microsoft style guide](https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/u/upper-left-upper-right).
diff --git a/doc/development/documentation/topic_types/task.md b/doc/development/documentation/topic_types/task.md
index 8d23a5f322e..f596ffc9b8b 100644
--- a/doc/development/documentation/topic_types/task.md
+++ b/doc/development/documentation/topic_types/task.md
@@ -60,6 +60,22 @@ For example, `Create an issue`.
If several tasks on a page share prerequisites, you can create a separate
topic with the title `Prerequisites`.
+## When a task has only one step
+
+If you need to write a task that has only one step, make that step an unordered list item.
+This format helps the step stand out, while keeping it consistent with the rules
+for lists.
+
+For example:
+
+```markdown
+# Create a merge request
+
+To create a merge request:
+
+- In the upper-right corner, select **New merge request**.
+```
+
### When more than one way exists to perform a task
If more than one way exists to perform a task in the UI, you should
diff --git a/doc/development/documentation/versions.md b/doc/development/documentation/versions.md
index 30a0d4d4cf4..859e7265a2a 100644
--- a/doc/development/documentation/versions.md
+++ b/doc/development/documentation/versions.md
@@ -13,7 +13,7 @@ including when features were introduced and when they were updated or removed.
## View older documentation versions
Previous versions of the documentation are available on `docs.gitlab.com`.
-To view a previous version, select the **Versions** button in the upper right.
+To view a previous version, in the upper-right corner, select **Versions**.
To view versions that are not available on `docs.gitlab.com`:
@@ -89,8 +89,9 @@ voters to agree.
When features are deprecated and removed, update the related documentation.
-API documentation follows these guidelines, but the GraphQL docs use
-a [separate process](../api_graphql_styleguide.md#deprecating-schema-items).
+NOTE:
+A separate process exists for [GraphQL docs](../api_graphql_styleguide.md#deprecating-schema-items)
+and [REST API docs](restful_api_styleguide.md#deprecations).
### Deprecate a page or topic
diff --git a/doc/development/documentation/workflow.md b/doc/development/documentation/workflow.md
index fe5453a4a58..1a4194aebd9 100644
--- a/doc/development/documentation/workflow.md
+++ b/doc/development/documentation/workflow.md
@@ -4,148 +4,39 @@ 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
---
-# How to update GitLab documentation
+# Documentation workflow
-Anyone can contribute to the GitLab documentation! You can create a merge request for documentation when:
+Documentation at GitLab follows a workflow.
-- You find errors or other room for improvement in existing documentation.
-- You have an idea for all-new documentation that would help a GitLab user or administrator to
- accomplish their work with GitLab.
+## Before merging
-If you are working on a feature or enhancement, use the
-[feature workflow process described in the GitLab Handbook](https://about.gitlab.com/handbook/product/ux/technical-writing/workflow/#documentation-for-a-product-change).
+Ensure your documentation includes:
-## Do not use ChatGPT or AI-generated content for the docs
-
-GitLab documentation is distributed under the [CC BY-SA 4.0 license](https://creativecommons.org/licenses/by-sa/4.0/), which presupposes that GitLab owns the documentation.
-
-Under current law in the US and the EU, it’s possible that AI-generated works might either:
-
-- not be owned by anyone because they weren't created by a human, or
-- belong to the AI training data’s creator, if the AI verbatim reproduces content that it trained on
-
-If the documentation contains AI-generated content, GitLab probably wouldn't own this content, which would risk invalidating the CC BY-SA 4.0 license.
+- [Product badges](styleguide/index.md#product-tier-badges).
+- The GitLab [version](versions.md) that introduced the feature.
+- Accurate [links](styleguide/index.md#links).
+- Accurate [user permissions](../../user/permissions.md).
-Contributions to GitLab documentation are made under either our [DCO or our CLA terms](https://about.gitlab.com/community/contribute/dco-cla/). In both, contributors have to make certain certifications about the authorship of their work that they can't validly make for AI-generated text.
-
-For these reasons, do not add AI-generated content to the documentation.
-
-## How to update the docs
-
-If you are not a GitLab team member, or do not have the Developer role for the GitLab repository, to update GitLab documentation:
-
-1. Select an [issue](https://about.gitlab.com/handbook/product/ux/technical-writing/#community-contribution-opportunities) you'd like to work on.
- - For a Hackathon, mention `@docs-hackathon` in a comment and ask for the issue to be assigned to you.
- To be fair to other contributors, if you see someone has already asked to work on the issue, choose another issue.
- - If you're not taking part in a Hackathon, you don't need an issue to open a merge request.
- If you are looking for issues to work on and don't see any that suit you, you can always fix [Vale](testing.md#vale) issues.
-1. Go to the [GitLab repository](https://gitlab.com/gitlab-org/gitlab).
-1. In the upper right, select **Fork**. Forking makes a copy of the repository on GitLab.com.
-1. In your fork, find the documentation page in the `\doc` directory.
-1. If you know Git, make your changes and open a merge request.
- If not, follow these steps:
- 1. In the upper right, select **Edit** if it is visible. If it is not, select the down arrow (**{chevron-lg-down}**) next to **Open in Web IDE** or **Gitpod**, and select **Edit**.
- 1. In the **Commit message** text box, enter a commit message. Use 3-5 words, start with a capital letter, and do not end with a period.
- 1. Select **Commit changes**.
- 1. On the left sidebar, select **Merge requests**.
- 1. Select **New merge request**.
- 1. For the source branch, select your fork and branch. If you did not create a branch, select `master`.
- For the target branch, select the [GitLab repository](https://gitlab.com/gitlab-org/gitlab) `master` branch.
- 1. Select **Compare branches and continue**. A new merge request opens.
- 1. Select the **Documentation** template. In the description, write a brief summary of the changes and link to the related issue, if there is one.
- 1. Select **Create merge request**.
-
-If you need help while working on the page, view:
-
-- The [Style Guide](styleguide/index.md).
-- The [Word list](styleguide/word_list.md)
-- The [Markdown Guide](https://about.gitlab.com/handbook/markdown-guide/).
-
-### Ask for help
-
-Ask for help from the Technical Writing team if you:
-
-- Need help to choose the correct place for documentation.
-- Want to discuss a documentation idea or outline.
-- Want to request any other help.
-
-To identify someone who can help you:
-
-1. Locate the Technical Writer for the relevant
- [DevOps stage group](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments).
-1. Either:
- - If urgent help is required, directly assign the Technical Writer in the issue or in the merge request.
- - If non-urgent help is required, ping the Technical Writer in the issue or merge request.
-
-If you are a member of the GitLab Slack workspace, you can request help in `#docs`.
+Ensure you've followed the [style guide](styleguide/index.md) and [word list](styleguide/word_list.md).
## Documentation labels
-When you author an issue or merge request, you must add these labels:
+When you author an issue or merge request, choose the
+[Documentation template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/merge_request_templates/Documentation.md).
+It includes these labels, which are added to the merge request:
-- A [type label](../contributing/issue_workflow.md#type-labels), either `~"type::feature"` or `~"type::maintenance"`.
-- A [stage label](../contributing/issue_workflow.md#stage-labels) and [group label](../contributing/issue_workflow.md#group-labels).
+- A [type label](../labels/index.md#type-labels), either `~"type::feature"` or `~"type::maintenance"`.
+- A [stage label](../labels/index.md#stage-labels) and [group label](../labels/index.md#group-labels).
For example, `~devops::create` and `~group::source code`.
-- A `~documentation` [specialization label](../contributing/issue_workflow.md#specialization-labels).
+- A `~documentation` [specialization label](../labels/index.md#specialization-labels).
A member of the Technical Writing team adds these labels:
- A [documentation scoped label](../../user/project/labels.md#scoped-labels) with the
`docs::` prefix. For example, `~docs::improvement`.
-- The [`~Technical Writing` team label](../contributing/issue_workflow.md#team-labels).
-
-## Reviewing and merging
-
-Anyone with the Maintainer role to the relevant GitLab project can
-merge documentation changes. Maintainers must make a good-faith effort to ensure that the content:
-
-- Is clear and sufficiently easy for the intended audience to navigate and understand.
-- Meets the [Documentation Guidelines](index.md) and [Style Guide](styleguide/index.md).
+- The [`~Technical Writing` team label](../labels/index.md#team-labels).
-If the author or reviewer has any questions, they can mention the writer who is assigned to the relevant
-[DevOps stage group](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments).
-
-The process involves the following:
-
-- Primary Reviewer. Review by a [code reviewer](https://about.gitlab.com/handbook/engineering/projects/)
- or other appropriate colleague to confirm accuracy, clarity, and completeness. This can be skipped
- for minor fixes without substantive content changes.
-- Technical Writer (Optional). If not completed for a merge request before merging, must be scheduled
- post-merge. Schedule post-merge reviews only if an urgent merge is required. To request a:
- - Pre-merge review, assign the Technical Writer listed for the applicable
- [DevOps stage group](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments).
- - Post-merge review, see [Post-merge reviews](#post-merge-reviews).
-- Maintainer. For merge requests, Maintainers:
- - Can always request any of the above reviews.
- - Review before or after a Technical Writer review.
- - Ensure the given release milestone is set.
- - Ensure the appropriate labels are applied, including any required to pick a merge request into
- a release.
- - Ensure that, if there has not been a Technical Writer review completed or scheduled, they
- [create the required issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Doc%20Review), assign it to the Technical Writer of the given stage group,
- and link it from the merge request.
-
-The process is reflected in the **Documentation**
-[merge request template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/merge_request_templates/Documentation.md).
-
-### Before merging
-
-Ensure the following if skipping an initial Technical Writer review:
-
-- [Product badges](styleguide/index.md#product-tier-badges) are applied.
-- The GitLab [version](versions.md) that
- introduced the feature is included.
-- Changes to topic titles don't affect in-app hyperlinks.
-- Specific [user permissions](../../user/permissions.md) are documented.
-- New documents are linked from higher-level indexes, for discoverability.
-- The style guide is followed:
- - For [directories and files](site_architecture/folder_structure.md).
- - For [images](styleguide/index.md#images).
-
-Merge requests that change the location of documentation must always be reviewed by a Technical
-Writer before merging.
-
-### Post-merge reviews
+## Post-merge reviews
If not assigned to a Technical Writer for review prior to merging, a review must be scheduled
immediately after merge by the developer or maintainer. For this,
@@ -174,8 +65,25 @@ Remember:
- The Technical Writer can also help decide that documentation can be merged without Technical
writer review, with the review to occur soon after merge.
-## Other ways to help
+## Do not use ChatGPT or AI-generated content for the docs
+
+GitLab documentation is distributed under the [CC BY-SA 4.0 license](https://creativecommons.org/licenses/by-sa/4.0/), which presupposes that GitLab owns the documentation.
-If you have ideas for further documentation resources please
-[create an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Documentation)
-using the Documentation template.
+Under current law in the US and the EU, it’s possible that AI-generated works might either:
+
+- not be owned by anyone because they weren't created by a human, or
+- belong to the AI training data's creator, if the AI verbatim reproduces content that it trained on
+
+If the documentation contains AI-generated content, GitLab probably wouldn't own this content, which would risk invalidating the CC BY-SA 4.0 license.
+
+Contributions to GitLab documentation are made under either our [DCO or our CLA terms](https://about.gitlab.com/community/contribute/dco-cla/). In both, contributors have to make certain certifications about the authorship of their work that they can't validly make for AI-generated text.
+
+For these reasons, do not add AI-generated content to the documentation.
+
+## Related topics
+
+- [Reviews and levels of edit](https://about.gitlab.com/handbook/product/ux/technical-writing/#reviews)
+- [Technical writing assignments](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments)
+- The [Style Guide](styleguide/index.md)
+- The [Word list](styleguide/word_list.md)
+- The [Markdown Guide](https://about.gitlab.com/handbook/markdown-guide/)
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 4eb5bedef1c..bc997c37e66 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -18,6 +18,49 @@ info: To determine the technical writer assigned to the Stage/Group associated w
[EE features list](https://about.gitlab.com/features/).
<!-- markdownlint-enable MD044 -->
+## SaaS only feature
+
+Use the following guidelines when you develop a feature that is only applicable for SaaS (for example, a CustomersDot integration).
+
+1. It is recommended you use an application setting. This enables
+ granular settings so that each SaaS instance can switch things according to
+ their need.
+1. If application setting is not possible, helpers such as `Gitlab.com?` can be
+ used. However, this comes with drawbacks as listed in the epic to
+ [remove these helpers](https://gitlab.com/groups/gitlab-org/-/epics/7374).
+ 1. Consider performance and availability impact on other SaaS instances. For example,
+ [GitLab JH overrides](https://jihulab.com/gitlab-cn/gitlab/-/blob/main-jh/jh/lib/jh/gitlab/saas.rb)
+ SaaS helpers, so that it returns true for `Gitlab.com?`.
+
+### Simulate a SaaS instance
+
+If you're developing locally and need your instance to simulate the SaaS (GitLab.com)
+version of the product:
+
+1. Export this environment variable:
+
+ ```shell
+ export GITLAB_SIMULATE_SAAS=1
+ ```
+
+ There are many ways to pass an environment variable to your local GitLab instance.
+ For example, you can create an `env.runit` file in the root of your GDK with the above snippet.
+
+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. Visit **Admin > Settings > General**.
+ 1. Expand **Account and limit**.
+ 1. Select the **Allow use of licensed EE features** checkbox.
+ 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 top bar, select **Main menu > Admin**.
+ 1. On the left sidebar, select **Overview > Groups**.
+ 1. Identify the group you want to modify, and select **Edit**.
+ 1. Scroll to **Permissions and group features**. For **Plan**, select `Ultimate`.
+ 1. Select **Save changes**.
+
## Implement a new EE feature
If you're developing a GitLab Premium or GitLab Ultimate licensed feature, use these steps to
@@ -74,9 +117,9 @@ To guard your licensed feature:
1. Optional. If your global feature is also available to namespaces with a paid plan, combine two
feature identifiers to allow both administrators and group users. For example:
- ```ruby
- License.feature_available?(:my_feature_name) || group.licensed_feature_available?(:my_feature_name_for_namespace) # Both admins and group members can see this EE feature
- ```
+ ```ruby
+ License.feature_available?(:my_feature_name) || group.licensed_feature_available?(:my_feature_name_for_namespace) # Both admins and group members can see this EE feature
+ ```
### Simulate a CE instance when unlicensed
@@ -100,15 +143,15 @@ To simulate a CE instance without deleting the license in a GDK:
1. Create an `env.runit` file in the root of your GDK with the line:
- ```shell
- export FOSS_ONLY=1
- ```
+ ```shell
+ export FOSS_ONLY=1
+ ```
1. Then restart the GDK:
- ```shell
- gdk restart rails && gdk restart webpack
- ```
+ ```shell
+ gdk restart rails && gdk restart webpack
+ ```
Remove the line in `env.runit` if you want to revert back to an EE
installation, and repeat step 2.
@@ -137,35 +180,6 @@ To do so:
bin/rspec spec/features/<path_to_your_spec>
```
-### Simulate a SaaS instance
-
-If you're developing locally and need your instance to simulate the SaaS (GitLab.com)
-version of the product:
-
-1. Export this environment variable:
-
- ```shell
- export GITLAB_SIMULATE_SAAS=1
- ```
-
- There are many ways to pass an environment variable to your local GitLab instance.
- For example, you can create an `env.runit` file in the root of your GDK with the above snippet.
-
-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. Visit **Admin > Settings > General**.
- 1. Expand **Account and limit**.
- 1. Select the **Allow use of licensed EE features** checkbox.
- 1. Click **Save changes**.
-
-1. Ensure that the group for which you want to test the EE feature, is actually using an EE plan:
- 1. On the top bar, select **Main menu > Admin**.
- 1. On the left sidebar, select **Overview > Groups**.
- 1. Identify the group you want to modify, and select **Edit**.
- 1. Scroll to **Permissions and group features**. For **Plan**, select `Ultimate`.
- 1. Select **Save changes**.
-
### Run CI pipelines in a FOSS context
By default, merge request pipelines for development run in an EE-context only. If you are
@@ -580,11 +594,11 @@ Resolving an EE template path that is relative to the CE view path doesn't work.
For `render` and `render_if_exists`, they search for the EE partial first,
and then CE partial. They would only render a particular partial, not all
partials with the same name. We could take the advantage of this, so that
-the same partial path (for example, `shared/issuable/form/default_templates`) could
+the same partial path (for example, `projects/settings/archive`) could
be referring to the CE partial in CE (that is,
-`app/views/shared/issuable/form/_default_templates.html.haml`), while EE
+`app/views/projects/settings/_archive.html.haml`), while EE
partial in EE (that is,
-`ee/app/views/shared/issuable/form/_default_templates.html.haml`). This way,
+`ee/app/views/projects/settings/_archive.html.haml`). This way,
we could show different things between CE and EE.
However sometimes we would also want to reuse the CE partial in EE partial
@@ -594,21 +608,19 @@ would be tedious to do so.
In this case, we could as well just use `render_ce` which would ignore any EE
partials. One example would be
-`ee/app/views/shared/issuable/form/_default_templates.html.haml`:
+`ee/app/views/projects/settings/_archive.html.haml`:
```haml
-- if @project.feature_available?(:issuable_default_templates)
- = render_ce 'shared/issuable/form/default_templates'
-- elsif show_promotions?
- = render 'shared/promotions/promote_issue_templates'
+- return if @project.marked_for_deletion?
+= render_ce 'projects/settings/archive'
```
In the above example, we can't use
-`render 'shared/issuable/form/default_templates'` because it would find the
+`render 'projects/settings/archive'` because it would find the
same EE partial, causing infinite recursion. Instead, we could use `render_ce`
so it ignores any partials in `ee/` and then it would render the CE partial
-(that is, `app/views/shared/issuable/form/_default_templates.html.haml`)
-for the same path (that is, `shared/issuable/form/default_templates`). This way
+(that is, `app/views/projects/settings/_archive.html.haml`)
+for the same path (that is, `projects/settings/archive`). This way
we could easily wrap around the CE partial.
### Code in `lib/gitlab/background_migration/`
diff --git a/doc/development/elasticsearch.md b/doc/development/elasticsearch.md
deleted file mode 100644
index 935964a9a90..00000000000
--- a/doc/development/elasticsearch.md
+++ /dev/null
@@ -1,625 +0,0 @@
----
-stage: Data Stores
-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 knowledge
-
-This area is to maintain a compendium of useful information when working with Elasticsearch.
-
-Information on how to enable Elasticsearch and perform the initial indexing is in
-the [Elasticsearch integration documentation](../integration/advanced_search/elasticsearch.md#enable-advanced-search).
-
-## Deep Dive
-
-In June 2019, Mario de la Ossa hosted a Deep Dive (GitLab team members only: `https://gitlab.com/gitlab-org/create-stage/issues/1`) on the GitLab [Elasticsearch integration](../integration/advanced_search/elasticsearch.md) to share his domain specific knowledge with anyone who may work in this part of the codebase in the future. You can find the <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [recording on YouTube](https://www.youtube.com/watch?v=vrvl-tN2EaA), and the slides on [Google Slides](https://docs.google.com/presentation/d/1H-pCzI_LNrgrL5pJAIQgvLX8Ji0-jIKOg1QeJQzChug/edit) and in [PDF](https://gitlab.com/gitlab-org/create-stage/uploads/c5aa32b6b07476fa8b597004899ec538/Elasticsearch_Deep_Dive.pdf). Everything covered in this deep dive was accurate as of GitLab 12.0, and while specific details may have changed since then, it should still serve as a good introduction.
-
-In August 2020, a second Deep Dive was hosted, focusing on [GitLab-specific architecture for multi-indices support](#zero-downtime-reindexing-with-multiple-indices). The <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [recording on YouTube](https://www.youtube.com/watch?v=0WdPR9oB2fg) and the [slides](https://lulalala.gitlab.io/gitlab-elasticsearch-deepdive/) are available. Everything covered in this deep dive was accurate as of GitLab 13.3.
-
-## Supported Versions
-
-See [Version Requirements](../integration/advanced_search/elasticsearch.md#version-requirements).
-
-Developers making significant changes to Elasticsearch queries should test their features against all our supported versions.
-
-## Setting up development environment
-
-See the [Elasticsearch GDK setup instructions](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/howto/elasticsearch.md)
-
-## Helpful Rake tasks
-
-- `gitlab:elastic:test:index_size`: Tells you how much space the current index is using, as well as how many documents are in the index.
-- `gitlab:elastic:test:index_size_change`: Outputs index size, reindexes, and outputs index size again. Useful when testing improvements to indexing size.
-
-Additionally, if you need large repositories or multiple forks for testing, please consider [following these instructions](rake_tasks.md#extra-project-seed-options)
-
-## How does it work?
-
-The Elasticsearch integration depends on an external indexer. We ship an [indexer written in Go](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer). The user must trigger the initial indexing via a Rake task but, after this is done, GitLab itself will trigger reindexing when required via `after_` callbacks on create, update, and destroy that are inherited from [`/ee/app/models/concerns/elastic/application_versioned_search.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/concerns/elastic/application_versioned_search.rb).
-
-After initial indexing is complete, create, update, and delete operations for all models except projects (see [#207494](https://gitlab.com/gitlab-org/gitlab/-/issues/207494)) are tracked in a Redis [`ZSET`](https://redis.io/docs/manual/data-types/#sorted-sets). A regular `sidekiq-cron` `ElasticIndexBulkCronWorker` processes this queue, updating many Elasticsearch documents at a time with the [Bulk Request API](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html).
-
-Search queries are generated by the concerns found in [`ee/app/models/concerns/elastic`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/app/models/concerns/elastic). These concerns are also in charge of access control, and have been a historic source of security bugs so please pay close attention to them!
-
-## Existing Analyzers/Tokenizers/Filters
-
-These are all defined in [`ee/lib/elastic/latest/config.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/elastic/latest/config.rb)
-
-### Analyzers
-
-#### `path_analyzer`
-
-Used when indexing blobs' paths. Uses the `path_tokenizer` and the `lowercase` and `asciifolding` filters.
-
-Please see the `path_tokenizer` explanation below for an example.
-
-#### `sha_analyzer`
-
-Used in blobs and commits. Uses the `sha_tokenizer` and the `lowercase` and `asciifolding` filters.
-
-Please see the `sha_tokenizer` explanation later below for an example.
-
-#### `code_analyzer`
-
-Used when indexing a blob's filename and content. Uses the `whitespace` tokenizer and the filters: [`code`](#code), `lowercase`, and `asciifolding`
-
-The `whitespace` tokenizer was selected to have more control over how tokens are split. For example the string `Foo::bar(4)` needs to generate tokens like `Foo` and `bar(4)` to be properly searched.
-
-Please see the `code` filter for an explanation on how tokens are split.
-
-NOTE:
-The [Elasticsearch `code_analyzer` doesn't account for all code cases](../integration/advanced_search/elasticsearch_troubleshooting.md#elasticsearch-code_analyzer-doesnt-account-for-all-code-cases).
-
-#### `code_search_analyzer`
-
-Not directly used for indexing, but rather used to transform a search input. Uses the `whitespace` tokenizer and the `lowercase` and `asciifolding` filters.
-
-### Tokenizers
-
-#### `sha_tokenizer`
-
-This is a custom tokenizer that uses the [`edgeNGram` tokenizer](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-edgengram-tokenizer.html) to allow SHAs to be searchable by any sub-set of it (minimum of 5 chars).
-
-Example:
-
-`240c29dc7e` becomes:
-
-- `240c2`
-- `240c29`
-- `240c29d`
-- `240c29dc`
-- `240c29dc7`
-- `240c29dc7e`
-
-#### `path_tokenizer`
-
-This is a custom tokenizer that uses the [`path_hierarchy` tokenizer](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-pathhierarchy-tokenizer.html) with `reverse: true` to allow searches to find paths no matter how much or how little of the path is given as input.
-
-Example:
-
-`'/some/path/application.js'` becomes:
-
-- `'/some/path/application.js'`
-- `'some/path/application.js'`
-- `'path/application.js'`
-- `'application.js'`
-
-### Filters
-
-#### `code`
-
-Uses a [Pattern Capture token filter](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-pattern-capture-tokenfilter.html) to split tokens into more easily searched versions of themselves.
-
-Patterns:
-
-- `"(\\p{Ll}+|\\p{Lu}\\p{Ll}+|\\p{Lu}+)"`: captures CamelCase and lowerCamelCase strings as separate tokens
-- `"(\\d+)"`: extracts digits
-- `"(?=([\\p{Lu}]+[\\p{L}]+))"`: captures CamelCase strings recursively. For example: `ThisIsATest` => `[ThisIsATest, IsATest, ATest, Test]`
-- `'"((?:\\"|[^"]|\\")*)"'`: captures terms inside quotes, removing the quotes
-- `"'((?:\\'|[^']|\\')*)'"`: same as above, for single-quotes
-- `'\.([^.]+)(?=\.|\s|\Z)'`: separate terms with periods in-between
-- `'([\p{L}_.-]+)'`: some common chars in file names to keep the whole filename intact (for example `my_file-ñame.txt`)
-- `'([\p{L}\d_]+)'`: letters, numbers and underscores are the most common tokens in programming. Always capture them greedily regardless of context.
-
-## Gotchas
-
-- Searches can have their own analyzers. Remember to check when editing analyzers
-- `Character` filters (as opposed to token filters) always replace the original character, so they're not a good choice as they can hinder exact searches
-
-## Zero downtime reindexing with multiple indices
-
-NOTE:
-This is not applicable yet as multiple indices functionality is not fully implemented.
-
-Currently GitLab can only handle a single version of setting. Any setting/schema changes would require reindexing everything from scratch. Since reindexing can take a long time, this can cause search functionality downtime.
-
-To avoid downtime, GitLab is working to support multiple indices that
-can function at the same time. Whenever the schema changes, the administrator
-will be able to create a new index and reindex to it, while searches
-continue to go to the older, stable index. Any data updates will be
-forwarded to both indices. Once the new index is ready, an administrator can
-mark it active, which will direct all searches to it, and remove the old
-index.
-
-This is also helpful for migrating to new servers, for example, moving to/from AWS.
-
-Currently we are on the process of migrating to this new design. Everything is hardwired to work with one single version for now.
-
-### Architecture
-
-The traditional setup, provided by `elasticsearch-rails`, is to communicate through its internal proxy classes. Developers would write model-specific logic in a module for the model to include in (for example, `SnippetsSearch`). The `__elasticsearch__` methods would return a proxy object, for example:
-
-- `Issue.__elasticsearch__` returns an instance of `Elasticsearch::Model::Proxy::ClassMethodsProxy`
-- `Issue.first.__elasticsearch__` returns an instance of `Elasticsearch::Model::Proxy::InstanceMethodsProxy`.
-
-These proxy objects would talk to Elasticsearch server directly (see top half of the diagram).
-
-![Elasticsearch Architecture](img/elasticsearch_architecture.svg)
-
-In the planned new design, each model would have a pair of corresponding sub-classed proxy objects, in which model-specific logic is located. For example, `Snippet` would have `SnippetClassProxy` and `SnippetInstanceProxy` (being subclass of `Elasticsearch::Model::Proxy::ClassMethodsProxy` and `Elasticsearch::Model::Proxy::InstanceMethodsProxy`, respectively).
-
-`__elasticsearch__` would represent another layer of proxy object, keeping track of multiple actual proxy objects. It would forward method calls to the appropriate index. For example:
-
-- `model.__elasticsearch__.search` would be forwarded to the one stable index, since it is a read operation.
-- `model.__elasticsearch__.update_document` would be forwarded to all indices, to keep all indices up-to-date.
-
-The global configurations per version are now in the `Elastic::(Version)::Config` class. You can change mappings there.
-
-### Creating new version of schema
-
-NOTE:
-This is not applicable yet as multiple indices functionality is not fully implemented.
-
-Folders like `ee/lib/elastic/v12p1` contain snapshots of search logic from different versions. To keep a continuous Git history, the latest version lives under `ee/lib/elastic/latest`, but its classes are aliased under an actual version (for example, `ee/lib/elastic/v12p3`). When referencing these classes, never use the `Latest` namespace directly, but use the actual version (for example, `V12p3`).
-
-The version name basically follows the GitLab release version. If setting is changed in 12.3, we will create a new namespace called `V12p3` (p stands for "point"). Raise an issue if there is a need to name a version differently.
-
-If the current version is `v12p1`, and we need to create a new version for `v12p3`, the steps are as follows:
-
-1. Copy the entire folder of `v12p1` as `v12p3`
-1. Change the namespace for files under `v12p3` folder from `V12p1` to `V12p3` (which are still aliased to `Latest`)
-1. Delete `v12p1` folder
-1. Copy the entire folder of `latest` as `v12p1`
-1. Change the namespace for files under `v12p1` folder from `Latest` to `V12p1`
-1. Make changes to files under the `latest` folder as needed
-
-## Creating a new Advanced Search migration
-
-> This functionality was introduced by [#234046](https://gitlab.com/gitlab-org/gitlab/-/issues/234046).
-
-NOTE:
-This only supported for indices created with GitLab 13.0 or greater.
-
-In the [`ee/elastic/migrate/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/elastic/migrate) folder, create a new file with the filename format `YYYYMMDDHHMMSS_migration_name.rb`. This format is the same for Rails database migrations.
-
-```ruby
-# frozen_string_literal: true
-
-class MigrationName < Elastic::Migration
- # Important: Any updates to the Elastic index mappings must be replicated in the respective
- # configuration files:
- # - `Elastic::Latest::Config`, for the main index.
- # - `Elastic::Latest::<Type>Config`, for standalone indices.
-
- def migrate
- end
-
- # Check if the migration has completed
- # Return true if completed, otherwise return false
- def completed?
- end
-end
-```
-
-Applied migrations are stored in `gitlab-#{RAILS_ENV}-migrations` index. All migrations not executed
-are applied by the [`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb)
-cron worker sequentially.
-
-To update Elastic index mappings, apply the configuration to the respective files:
-
-- For the main index: [`Elastic::Latest::Config`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/elastic/latest/config.rb).
-- For standalone indices: `Elastic::Latest::<Type>Config`.
-
-Migrations can be built with a retry limit and have the ability to be [failed and marked as halted](https://gitlab.com/gitlab-org/gitlab/-/blob/66e899b6637372a4faf61cfd2f254cbdd2fb9f6d/ee/lib/elastic/migration.rb#L40).
-Any data or index cleanup needed to support migration retries should be handled within the migration.
-
-### Migration helpers
-
-The following migration helpers are available in `ee/app/workers/concerns/elastic/`:
-
-#### `Elastic::MigrationBackfillHelper`
-
-Backfills a specific field in an index. In most cases, the mapping for the field should already be added.
-
-Requires the `index_name` and `field_name` methods.
-
-```ruby
-class MigrationName < Elastic::Migration
- include Elastic::MigrationBackfillHelper
-
- private
-
- def index_name
- Issue.__elasticsearch__.index_name
- end
-
- def field_name
- :schema_version
- end
-end
-```
-
-#### `Elastic::MigrationUpdateMappingsHelper`
-
-Updates a mapping in an index by calling `put_mapping` with the mapping specified.
-
-Requires the `index_name` and `new_mappings` methods.
-
-```ruby
-class MigrationName < Elastic::Migration
- include Elastic::MigrationUpdateMappingsHelper
-
- private
-
- def index_name
- Issue.__elasticsearch__.index_name
- end
-
- def new_mappings
- {
- schema_version: {
- type: 'short'
- }
- }
- end
-end
-```
-
-#### `Elastic::MigrationRemoveFieldsHelper`
-
-Removes specified fields from an index.
-
-Requires the `index_name`, `document_type` methods. If there is one field to remove, add the `field_to_remove` method, otherwise add `fields_to_remove` with an array of fields.
-
-Checks in batches if any documents that match `document_type` have the fields specified in Elasticsearch. If documents exist, uses a Painless script to perform `update_by_query`.
-
-```ruby
-class MigrationName < Elastic::Migration
- include Elastic::MigrationRemoveFieldsHelper
-
- batched!
- throttle_delay 1.minute
-
- private
-
- def index_name
- User.__elasticsearch__.index_name
- end
-
- def document_type
- 'user'
- end
-
- def fields_to_remove
- %w[two_factor_enabled has_projects]
- end
-end
-```
-
-The default batch size is `10_000`. You can override this value by specifying `BATCH_SIZE`:
-
-```ruby
-class MigrationName < Elastic::Migration
- include Elastic::MigrationRemoveFieldsHelper
-
- batched!
- BATCH_SIZE = 100
-
- ...
-end
-```
-
-#### `Elastic::MigrationObsolete`
-
-Marks a migration as obsolete when it's no longer required.
-
-```ruby
-class MigrationName < Elastic::Migration
- include Elastic::MigrationObsolete
-end
-```
-
-#### `Elastic::MigrationHelper`
-
-Contains methods you can use when a migration doesn't fit the previous examples.
-
-```ruby
-class MigrationName < Elastic::Migration
- include Elastic::MigrationHelper
-
- def migrate
- ...
- end
-
- def completed?
- ...
- end
-end
-```
-
-### Migration options supported by the `Elastic::MigrationWorker`
-
-[`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb) supports the following migration options:
-
-- `batched!` - Allow the migration to run in batches. If set, the [`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb)
-will re-enqueue itself with a delay which is set using the `throttle_delay` option described below. The batching
-must be handled within the `migrate` method, this setting controls the re-enqueuing only.
-
-- `batch_size` - Sets the number of documents modified during a `batched!` migration run. This size should be set to a value which allows the updates
-enough time to finish. This can be tuned in combination with the `throttle_delay` option described below. The batching
-must be handled within a custom `migrate` method or by using the [`Elastic::MigrationBackfillHelper`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/concerns/elastic/migration_backfill_helper.rb)
-`migrate` method which uses this setting. Default value is 1000 documents.
-
-- `throttle_delay` - Sets the wait time in between batch runs. This time should be set high enough to allow each migration batch
-enough time to finish. Additionally, the time should be less than 30 minutes since that is how often the
-[`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb)
-cron worker runs. Default value is 5 minutes.
-
-- `pause_indexing!` - Pause indexing while the migration runs. This setting will record the indexing setting before
-the migration runs and set it back to that value when the migration is completed.
-
-- `space_requirements!` - Verify that enough free space is available in the cluster when the migration runs. This setting
- will halt the migration if the storage required is not available when the migration runs. The migration must provide
- the space required in bytes by defining a `space_required_bytes` method.
-
-- `retry_on_failure` - Enable the retry on failure feature. By default, it retries
- the migration 30 times. After it runs out of retries, the migration is marked as halted.
- To customize the number of retries, pass the `max_attempts` argument:
- `retry_on_failure max_attempts: 10`
-
-```ruby
-# frozen_string_literal: true
-
-class BatchedMigrationName < Elastic::Migration
- # Declares a migration should be run in batches
- batched!
- throttle_delay 10.minutes
- pause_indexing!
- space_requirements!
- retry_on_failure
-
- # ...
-end
-```
-
-### Multi-version compatibility
-
-These Advanced Search migrations, like any other GitLab changes, need to support the case where
-[multiple versions of the application are running at the same time](multi_version_compatibility.md).
-
-Depending on the order of deployment, it's possible that the migration
-has started or finished and there's still a server running the application code from before the
-migration. We need to take this into consideration until we can
-[ensure all Advanced Search migrations start after the deployment has finished](https://gitlab.com/gitlab-org/gitlab/-/issues/321619).
-
-### Reverting a migration
-
-Because Elasticsearch does not support transactions, we always need to design our
-migrations to accommodate a situation where the application
-code is reverted after the migration has started or after it is finished.
-
-For this reason we generally defer destructive actions (for example, deletions after
-some data is moved) to a later merge request after the migrations have
-completed successfully. To be safe, for self-managed customers we should also
-defer it to another release if there is risk of important data loss.
-
-### Best practices for Advanced Search migrations
-
-Follow these best practices for best results:
-
-- When working in batches, keep the batch size under 9,000 documents
- and `throttle_delay` for at least 3 minutes. The bulk indexer is set to run
- every 1 minute and process a batch of 10,000 documents. These limits
- allow the bulk indexer time to process records before another migration
- batch is attempted.
-- To ensure that document counts are up to date, it is recommended to refresh
- the index before checking if a migration is completed.
-- Add logging statements to each migration when the migration starts, when a
- completion check occurs, and when the migration is completed. These logs
- are helpful when debugging issues with migrations.
-- Pause indexing if you're using any Elasticsearch Reindex API operations.
-- Consider adding a retry limit if there is potential for the migration to fail.
- This ensures that migrations can be halted if an issue occurs.
-
-## Deleting Advanced Search migrations in a major version upgrade
-
-Since our Advanced Search migrations usually require us to support multiple
-code paths for a long period of time, it's important to clean those up when we
-safely can.
-
-We choose to use GitLab major version upgrades as a safe time to remove
-backwards compatibility for indices that have not been fully migrated. We
-[document this in our upgrade documentation](../update/index.md#upgrading-to-a-new-major-version).
-We also choose to replace the migration code with the halted migration
-and remove tests so that:
-
-- We don't need to maintain any code that is called from our Advanced Search
- migrations.
-- We don't waste CI time running tests for migrations that we don't support
- anymore.
-- Operators who have not run this migration and who upgrade directly to the
- target version will see a message prompting them to reindex from scratch.
-
-To be extra safe, we will not delete migrations that were created in the last
-minor version before the major upgrade. So, if we are upgrading to `%14.0`,
-we should not delete migrations that were only added in `%13.12`. This is an
-extra safety net as we expect there are migrations that get merged that may
-take multiple weeks to finish on GitLab.com. It would be bad if we upgraded
-GitLab.com to `%14.0` before the migrations in `%13.12` were finished. Since
-our deployments to GitLab.com are automated and we currently don't have
-automated checks to prevent this, the extra precaution is warranted.
-Additionally, even if we did have automated checks to prevent it, we wouldn't
-actually want to hold up GitLab.com deployments on Advanced Search migrations,
-as they may still have another week to go, and that's too long to block
-deployments.
-
-### Process for removing migrations
-
-For every migration that was created 2 minor versions before the major version
-being upgraded to, we do the following:
-
-1. Confirm the migration has actually completed successfully for GitLab.com.
-1. Replace the content of the migration with:
-
- ```ruby
- include Elastic::MigrationObsolete
- ```
-
-1. Delete any spec files to support this migration.
-1. Remove any logic handling backwards compatibility for this migration. You
- can find this by looking for
- `Elastic::DataMigrationService.migration_has_finished?(:migration_name_in_lowercase)`.
-1. Create a merge request with these changes. Noting that we should not
- accidentally merge this before the major release is started.
-
-## Performance Monitoring
-
-### Prometheus
-
-GitLab exports [Prometheus metrics](../administration/monitoring/prometheus/gitlab_metrics.md)
-relating to the number of requests and timing for all web/API requests and Sidekiq jobs,
-which can help diagnose performance trends and compare how Elasticsearch timing
-is impacting overall performance relative to the time spent doing other things.
-
-#### Indexing queues
-
-GitLab also exports [Prometheus metrics](../administration/monitoring/prometheus/gitlab_metrics.md)
-for indexing queues, which can help diagnose performance bottlenecks and determine
-whether or not your GitLab instance or Elasticsearch server can keep up with
-the volume of updates.
-
-### Logs
-
-All of the indexing happens in Sidekiq, so much of the relevant logs for the
-Elasticsearch integration can be found in
-[`sidekiq.log`](../administration/logs/index.md#sidekiqlog). In particular, all
-Sidekiq workers that make requests to Elasticsearch in any way will log the
-number of requests and time taken querying/writing to Elasticsearch. This can
-be useful to understand whether or not your cluster is keeping up with
-indexing.
-
-Searching Elasticsearch is done via ordinary web workers handling requests. Any
-requests to load a page or make an API request, which then make requests to
-Elasticsearch, will log the number of requests and the time taken to
-[`production_json.log`](../administration/logs/index.md#production_jsonlog). These
-logs will also include the time spent on Database and Gitaly requests, which
-may help to diagnose which part of the search is performing poorly.
-
-There are additional logs specific to Elasticsearch that are sent to
-[`elasticsearch.log`](../administration/logs/index.md#elasticsearchlog)
-that may contain information to help diagnose performance issues.
-
-### Performance Bar
-
-Elasticsearch requests will be displayed in the
-[`Performance Bar`](../administration/monitoring/performance/performance_bar.md), which can
-be used both locally in development and on any deployed GitLab instance to
-diagnose poor search performance. This will show the exact queries being made,
-which is useful to diagnose why a search might be slow.
-
-### Correlation ID and `X-Opaque-Id`
-
-Our [correlation ID](distributed_tracing.md#developer-guidelines-for-working-with-correlation-ids)
-is forwarded by all requests from Rails to Elasticsearch as the
-[`X-Opaque-Id`](https://www.elastic.co/guide/en/elasticsearch/reference/current/tasks.html#_identifying_running_tasks)
-header which allows us to track any
-[tasks](https://www.elastic.co/guide/en/elasticsearch/reference/current/tasks.html)
-in the cluster back the request in GitLab.
-
-## Troubleshooting
-
-### Getting `flood stage disk watermark [95%] exceeded`
-
-You might get an error such as
-
-```plaintext
-[2018-10-31T15:54:19,762][WARN ][o.e.c.r.a.DiskThresholdMonitor] [pval5Ct]
- flood stage disk watermark [95%] exceeded on
- [pval5Ct7SieH90t5MykM5w][pval5Ct][/usr/local/var/lib/elasticsearch/nodes/0] free: 56.2gb[3%],
- all indices on this node will be marked read-only
-```
-
-This is because you've exceeded the disk space threshold - it thinks you don't have enough disk space left, based on the default 95% threshold.
-
-In addition, the `read_only_allow_delete` setting will be set to `true`. It will block indexing, `forcemerge`, etc
-
-```shell
-curl "http://localhost:9200/gitlab-development/_settings?pretty"
-```
-
-Add this to your `elasticsearch.yml` file:
-
-```yaml
-# turn off the disk allocator
-cluster.routing.allocation.disk.threshold_enabled: false
-```
-
-_or_
-
-```yaml
-# set your own limits
-cluster.routing.allocation.disk.threshold_enabled: true
-cluster.routing.allocation.disk.watermark.flood_stage: 5gb # ES 6.x only
-cluster.routing.allocation.disk.watermark.low: 15gb
-cluster.routing.allocation.disk.watermark.high: 10gb
-```
-
-Restart Elasticsearch, and the `read_only_allow_delete` will clear on its own.
-
-_from "Disk-based Shard Allocation | Elasticsearch Reference" [5.6](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/disk-allocator.html#disk-allocator) and [6.x](https://www.elastic.co/guide/en/elasticsearch/reference/6.7/disk-allocator.html)_
-
-### Disaster recovery/data loss/backups
-
-The use of Elasticsearch in GitLab is only ever as a secondary data store.
-This means that all of the data stored in Elasticsearch can always be derived
-again from other data sources, specifically PostgreSQL and Gitaly. Therefore if
-the Elasticsearch data store is ever corrupted for whatever reason you can reindex
-everything from scratch.
-
-If your Elasticsearch index is incredibly large it may be too time consuming or
-cause too much downtime to reindex from scratch. There aren't any built in
-mechanisms for automatically finding discrepancies and resyncing an
-Elasticsearch index if it gets out of sync but one tool that may be useful is
-looking at the logs for all the updates that occurred in a time range you
-believe may have been missed. This information is very low level and only
-useful for operators that are familiar with the GitLab codebase. It is
-documented here in case it is useful for others. The relevant logs that could
-theoretically be used to figure out what needs to be replayed are:
-
-1. All non-repository updates that were synced can be found in
- [`elasticsearch.log`](../administration/logs/index.md#elasticsearchlog) by
- searching for
- [`track_items`](https://gitlab.com/gitlab-org/gitlab/-/blob/1e60ea99bd8110a97d8fc481e2f41cab14e63d31/ee/app/services/elastic/process_bookkeeping_service.rb#L25)
- and these can be replayed by sending these items again through
- `::Elastic::ProcessBookkeepingService.track!`
-1. All repository updates that occurred can be found in
- [`elasticsearch.log`](../administration/logs/index.md#elasticsearchlog) by
- searching for
- [`indexing_commit_range`](https://gitlab.com/gitlab-org/gitlab/-/blob/6f9d75dd3898536b9ec2fb206e0bd677ab59bd6d/ee/lib/gitlab/elastic/indexer.rb#L41).
- Replaying these requires resetting the
- [`IndexStatus#last_commit/last_wiki_commit`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/index_status.rb)
- to the oldest `from_sha` in the logs and then triggering another index of
- the project using
- [`ElasticCommitIndexerWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic_commit_indexer_worker.rb)
-1. All project deletes that occurred can be found in
- [`sidekiq.log`](../administration/logs/index.md#sidekiqlog) by searching for
- [`ElasticDeleteProjectWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic_delete_project_worker.rb).
- These updates can be replayed by triggering another
- `ElasticDeleteProjectWorker`.
-
-With the above methods and taking regular
-[Elasticsearch snapshots](https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-restore.html)
-we should be able to recover from different kinds of data loss issues in a
-relatively short period of time compared to indexing everything from
-scratch.
diff --git a/doc/development/fe_guide/accessibility.md b/doc/development/fe_guide/accessibility.md
index af45603782f..b00131b12f3 100644
--- a/doc/development/fe_guide/accessibility.md
+++ b/doc/development/fe_guide/accessibility.md
@@ -345,7 +345,7 @@ Keep in mind that:
- When you add `:hover` styles, in most cases you should add `:focus` styles too so that the styling is applied for both mouse **and** keyboard users.
- If you remove an interactive element's `outline`, make sure you maintain visual focus state in another way such as with `box-shadow`.
-See the [Pajamas Keyboard-only page](https://design.gitlab.com/accessibility-audits/keyboard-only/) for more detail.
+See the [Pajamas Keyboard-only page](https://design.gitlab.com/accessibility/keyboard-only) for more detail.
## `tabindex`
@@ -516,6 +516,55 @@ GitLab-specific examples are assignee and label dropdowns.
Building such widgets require ARIA to make them understandable to screen readers.
Proper research and testing should be done to ensure compliance with [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/).
+## Automated accessibility testing with axe
+
+You can use [axe-core](https://github.com/dequelabs/axe-core) [gems](https://github.com/dequelabs/axe-core-gems)
+to run automated accessibility tests in feature tests.
+
+Axe provides the custom matcher `be_axe_clean`, which can be used like the following:
+
+```ruby
+# spec/features/settings_spec.rb
+it 'passes axe automated accessibility testing', :js do
+ visit_settings_page
+
+ wait_for_requests # ensures page is fully loaded
+
+ expect(page).to be_axe_clean
+end
+```
+
+If needed, you can scope testing to a specific area of the page by using `within`.
+
+Axe also provides specific [clauses](https://github.com/dequelabs/axe-core-gems/blob/develop/packages/axe-core-rspec/README.md#clauses),
+for example:
+
+```ruby
+expect(page).to be_axe_clean.within '[data-testid="element"]'
+
+# run only WCAG 2.0 Level AA rules
+expect(page).to be_axe_clean.according_to :wcag2aa
+
+# specifies which rule to skip
+expect(page).to be_axe_clean.skipping :'link-in-text-block'
+
+# clauses can be chained
+expect(page).to be_axe_clean.within('[data-testid="element"]')
+ .according_to(:wcag2aa)
+```
+
+Axe does not test hidden regions, such as inactive menus or modal windows. To test
+hidden regions for accessibility, write tests that activate or render the regions visible
+and run the matcher again.
+
+### Known accessibility violations
+
+This section documents violations where a recommendation differs with the [design system](https://design.gitlab.com/):
+
+- `link-in-text-block`: For now, use the `skipping` clause to skip `:'link-in-text-block'`
+ rule to fix the violation. After this is fixed as part of [issue 1444](https://gitlab.com/gitlab-org/gitlab-services/design.gitlab.com/-/issues/1444)
+ and underline is added to the `GlLink` component, this clause can be removed.
+
## Resources
### Viewing the browser accessibility tree
diff --git a/doc/development/fe_guide/content_editor.md b/doc/development/fe_guide/content_editor.md
index 6d13f419430..5c7fe68fec5 100644
--- a/doc/development/fe_guide/content_editor.md
+++ b/doc/development/fe_guide/content_editor.md
@@ -64,7 +64,7 @@ Instead, you should obtain an instance of the `ContentEditor` class by listening
```html
<script>
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { __ } from '~/locale';
export default {
diff --git a/doc/development/fe_guide/frontend_faq.md b/doc/development/fe_guide/frontend_faq.md
index 3b349d880c0..995730796b4 100644
--- a/doc/development/fe_guide/frontend_faq.md
+++ b/doc/development/fe_guide/frontend_faq.md
@@ -69,7 +69,7 @@ banner on top of the component examples indicates that:
> component.
For example, at the time of writing, this type of warning can be observed for
-[all form components](https://design.gitlab.com/components/form/). It, however,
+all form components, such as the [checkbox](https://design.gitlab.com/components/checkbox). It, however,
doesn't imply that the component should not be used.
GitLab always asks to use `<gl-*>` components whenever a suitable component exists.
@@ -192,7 +192,7 @@ To see what polyfills are being used:
1. Select the [`compile-production-assets`](https://gitlab.com/gitlab-org/gitlab/-/jobs/641770154) job.
1. In the right-hand sidebar, scroll to **Job Artifacts**, and select **Browse**.
1. Select the **webpack-report** folder to open it, and select **index.html**.
-1. In the upper left corner of the page, select the right arrow **{chevron-lg-right}**
+1. In the upper-left corner of the page, select the right arrow (**{chevron-lg-right}**)
to display the explorer.
1. In the **Search modules** field, enter `gitlab/node_modules/core-js` to see
which polyfills are being loaded and where:
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index 8ae0458e47c..5f0855d8f91 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -63,17 +63,17 @@ the GraphQL extension, follow these steps:
1. Add an `apollo.config.js` file to the root of your `gitlab` local directory.
1. Populate the file with the following content:
- ```javascript
- module.exports = {
- client: {
- includes: ['./app/assets/javascripts/**/*.graphql', './ee/app/assets/javascripts/**/*.graphql'],
- service: {
- name: 'GitLab',
- localSchemaFile: './tmp/tests/graphql/gitlab_schema.graphql',
- },
- },
- };
- ```
+ ```javascript
+ module.exports = {
+ client: {
+ includes: ['./app/assets/javascripts/**/*.graphql', './ee/app/assets/javascripts/**/*.graphql'],
+ service: {
+ name: 'GitLab',
+ localSchemaFile: './tmp/tests/graphql/gitlab_schema.graphql',
+ },
+ },
+ };
+ ```
1. Restart VS Code.
@@ -84,10 +84,8 @@ Our GraphQL API can be explored via GraphiQL at your instance's
[GitLab GraphQL API Reference documentation](../../api/graphql/reference)
where needed.
-You can check all existing queries and mutations on the right side
-of GraphiQL in its **Documentation explorer**. You can also
-write queries and mutations directly on the left tab and check
-their execution by selecting **Execute query** in the upper left:
+To check all existing queries and mutations, on the right side of GraphiQL, select **Documentation explorer**.
+To check the execution of the queries and mutations you've written, in the upper-left corner, select **Execute query**.
![GraphiQL interface](img/graphiql_explorer_v12_4.png)
@@ -107,7 +105,9 @@ Default client accepts two parameters: `resolvers` and `config`.
### Multiple client queries for the same object
-If you are making multiple queries to the same Apollo client object you might encounter the following error: `Cache data may be lost when replacing the someProperty field of a Query object. To address this problem, either ensure all objects of SomeEntityhave an id or a custom merge function`. We are already checking `ID` presence for every GraphQL type that has an `ID`, so this shouldn't be the case. Most likely, the `SomeEntity` type doesn't have an `ID` property, and to fix this warning we need to define a custom merge function.
+If you are making multiple queries to the same Apollo client object you might encounter the following error: `Cache data may be lost when replacing the someProperty field of a Query object. To address this problem, either ensure all objects of SomeEntityhave an id or a custom merge function`. We are already checking `id` presence for every GraphQL type that has an `id`, so this shouldn't be the case (unless you see this warning when running unit tests; in this case please ensure your mocked responses contain an `id` whenever it's requested).
+
+When `SomeEntity` type doesn't have an `id` property in the GraphQL schema, to fix this warning we need to define a custom merge function.
We have some client-wide types with `merge: true` defined in the default client as [`typePolicies`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/lib/graphql.js) (this means that Apollo will merge existing and incoming responses in the case of subsequent queries). Consider adding `SomeEntity` there or defining a custom merge function for it.
@@ -264,9 +264,7 @@ Read more about [Vue Apollo](https://github.com/vuejs/vue-apollo) in the [Vue Ap
### Local state with Apollo
-It is possible to manage an application state with Apollo by using [client-site resolvers](#using-client-side-resolvers)
-or [type policies with reactive variables](#using-type-policies-with-reactive-variables) when creating your default
-client.
+It is possible to manage an application state with Apollo when creating your default client.
#### Using client-side resolvers
@@ -326,6 +324,32 @@ export default {
}
```
+Instead of using `writeQuery`, we can create a type policy that will return `user` on every attempt of reading the `userQuery` from the cache:
+
+```javascript
+const defaultClient = createDefaultClient({}, {
+ cacheConfig: {
+ typePolicies: {
+ Query: {
+ fields: {
+ user: {
+ read(data) {
+ return data || {
+ user: {
+ name: 'John',
+ surname: 'Doe',
+ age: 30
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+});
+```
+
Along with creating local data, we can also extend existing GraphQL types with `@client` fields. This is extremely helpful when we need to mock an API response for fields not yet added to our GraphQL API.
##### Mocking API response with local Apollo cache
@@ -390,122 +414,9 @@ For each attempt to fetch a version, our client fetches `id` and `sha` from the
Read more about local state management with Apollo in the [Vue Apollo documentation](https://vue-apollo.netlify.app/guide/local-state.html#local-state).
-#### Using type policies with reactive variables
-
-Apollo Client 3 offers an alternative to [client-side resolvers](#using-client-side-resolvers) by using
-[reactive variables to store client state](https://www.apollographql.com/docs/react/local-state/reactive-variables/).
-
-**NOTE:**
-We are still learning the best practices for both **type policies** and **reactive vars**.
-Take a moment to improve this guide or [leave a comment](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/100)
-if you use it!
-
-In the example below we define a `@client` query and its `typedefs`:
-
-```javascript
-// ./graphql/typedefs.graphql
-extend type Query {
- localData: String!
-}
-```
-
-```javascript
-// ./graphql/get_local_data.query.graphql
-query getLocalData {
- localData @client
-}
-```
-
-Similar to resolvers, your `typePolicies` execute when the `@client` query is used. However,
-using `makeVar` triggers every relevant active Apollo query to reactively update when the state
-mutates.
-
-```javascript
-// ./graphql/local_state.js
-
-import { makeVar } from '@apollo/client/core';
-import typeDefs from './typedefs.graphql';
-
-export const createLocalState = () => {
- // set an initial value
- const localDataVar = makeVar('');
-
- const cacheConfig = {
- typePolicies: {
- Query: {
- fields: {
- localData() {
- // obtain current value
- // triggers when `localDataVar` is updated
- return localDataVar();
- },
- },
- },
- },
- };
-
- // methods that update local state
- const localMutations = {
- setLocalData(newData) {
- localDataVar(newData);
- },
- clearData() {
- localDataVar('');
- },
- };
-
- return {
- cacheConfig,
- typeDefs,
- localMutations,
- };
-};
-```
-
-Pass the cache configuration to your Apollo Client:
-
-```javascript
-// index.js
-
-// ...
-import createDefaultClient from '~/lib/graphql';
-import { createLocalState } from './graphql/local_state';
-
-const { cacheConfig, typeDefs, localMutations } = createLocalState();
-
-const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient({}, { cacheConfig, typeDefs }),
-});
-
-return new Vue({
- el,
- apolloProvider,
- provide: {
- // inject local state mutations to your app
- localMutations,
- },
- render(h) {
- return h(MyApp);
- },
-});
-```
-
-Wherever used, the local query updates as the state updates thanks to the **reactive variable**.
-
### Using with Vuex
-When the Apollo Client is used in Vuex and fetched data is stored in the Vuex store, the Apollo Client cache does not need to be enabled. Otherwise we would have data from the API stored in two places - Vuex store and Apollo Client cache. With Apollo's default settings, a subsequent fetch from the GraphQL API could result in fetching data from Apollo cache (in the case where we have the same query and variables). To prevent this behavior, we need to disable Apollo Client cache by passing a valid `fetchPolicy` option to its constructor:
-
-```javascript
-import fetchPolicies from '~/graphql_shared/fetch_policy_constants';
-
-export const gqClient = createGqClient(
- {},
- {
- fetchPolicy: fetchPolicies.NO_CACHE,
- },
-);
-```
+We do not recommend creating new applications with Vuex and Apollo Client combined
### Working on GraphQL-based features when frontend and backend are not in sync
@@ -1314,73 +1225,6 @@ If you use the RubyMine IDE, and have marked the `tmp` directory as
`gitlab/tmp/tests/graphql`. This will allow the **JS GraphQL** plugin to
automatically find and index the schema.
-#### Testing Apollo components
-
-If we use `ApolloQuery` or `ApolloMutation` in our components, to test their functionality we need to add a stub first:
-
-```javascript
-import { ApolloMutation } from 'vue-apollo';
-
-function createComponent(props = {}) {
- wrapper = shallowMount(MyComponent, {
- sync: false,
- propsData: {
- ...props,
- },
- stubs: {
- ApolloMutation,
- },
- });
-}
-```
-
-`ApolloMutation` component exposes `mutate` method via scoped slot. If we want to test this method, we need to add it to mocks:
-
-```javascript
-const mutate = jest.fn().mockResolvedValue();
-const $apollo = {
- mutate,
-};
-
-function createComponent(props = {}) {
- wrapper = shallowMount(MyComponent, {
- sync: false,
- propsData: {
- ...props,
- },
- stubs: {
- ApolloMutation,
- },
- mocks: {
- $apollo,
- }
- });
-}
-```
-
-Then we can check if `mutate` is called with correct variables:
-
-```javascript
-const mutationVariables = {
- mutation: createNoteMutation,
- update: expect.anything(),
- variables: {
- input: {
- noteableId: 'noteable-id',
- body: 'test',
- discussionId: '0',
- },
- },
-};
-
-it('calls mutation on submitting form ', () => {
- createComponent()
- findReplyForm().vm.$emit('submitForm');
-
- expect(mutate).toHaveBeenCalledWith(mutationVariables);
-});
-```
-
#### Mocking Apollo Client
To test the components with Apollo operations, we need to mock an Apollo Client in our unit tests. We use [`mock-apollo-client`](https://www.npmjs.com/package/mock-apollo-client) library to mock Apollo client and [`createMockApollo` helper](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/frontend/__helpers__/mock_apollo_helper.js) we created on top of it.
@@ -1393,38 +1237,40 @@ import Vue from 'vue';
Vue.use(VueApollo);
-function createMockApolloProvider() {
- return createMockApollo(requestHandlers);
-}
+describe('Some component with Apollo mock', () => {
+ let wrapper;
-function createComponent(options = {}) {
- const { mockApollo } = options;
- ...
- return shallowMount(..., {
- apolloProvider: mockApollo,
- ...
- });
-}
+ function createComponent(options = {}) {
+ wrapper = shallowMount(...);
+ }
+})
```
-After this, you can control whether you need a variable for `mockApollo` and assign it in the appropriate `describe`-scope:
+After this, we need to create a mocked Apollo provider:
```javascript
-describe('Some component', () => {
+import createMockApollo from 'helpers/mock_apollo_helper';
+
+describe('Some component with Apollo mock', () => {
let wrapper;
+ let mockApollo;
- describe('with Apollo mock', () => {
- let mockApollo;
+ function createComponent(options = {}) {
+ mockApollo = createMockApollo(...)
- beforeEach(() => {
- mockApollo = createMockApolloProvider();
- wrapper = createComponent({ mockApollo });
+ wrapper = shallowMount(SomeComponent, {
+ apolloProvider: mockApollo
});
- });
-});
+ }
+
+ afterEach(() => {
+ // we need to ensure we don't have provider persisted between tests
+ mockApollo = null
+ })
+})
```
-In the `createMockApolloProvider`-factory, we need to define an array of _handlers_ for every query or mutation:
+Now, we need to define an array of _handlers_ for every query or mutation. Handlers should be mock functions that return either a correct query response, or an error:
```javascript
import getDesignListQuery from '~/design_management/graphql/queries/get_design_list.query.graphql';
@@ -1435,72 +1281,70 @@ describe('Some component with Apollo mock', () => {
let wrapper;
let mockApollo;
- function createMockApolloProvider() {
- Vue.use(VueApollo);
-
- const requestHandlers = [
- [getDesignListQuery, jest.fn().mockResolvedValue(designListQueryResponse)],
- [permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
- ];
- ...
+ function createComponent(options = {
+ designListHandler: jest.fn().mockResolvedValue(designListQueryResponse)
+ }) {
+ mockApollo = createMockApollo([
+ [getDesignListQuery, options.designListHandler],
+ [permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
+ [moveDesignMutation, jest.fn().mockResolvedValue(moveDesignMutationResponse)],
+ ])
+
+ wrapper = shallowMount(SomeComponent, {
+ apolloProvider: mockApollo
+ });
}
})
```
-After this, we need to create a mock Apollo Client instance using a helper:
+When mocking resolved values, ensure the structure of the response is the same
+as the actual API response. For example, root property should be `data`:
```javascript
-import createMockApollo from 'helpers/mock_apollo_helper';
-
-describe('Some component', () => {
- let wrapper;
-
- function createMockApolloProvider() {
- Vue.use(VueApollo);
-
- const requestHandlers = [
- [getDesignListQuery, jest.fn().mockResolvedValue(designListQueryResponse)],
- [permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
- ];
-
- return createMockApollo(requestHandlers);
- }
-
- function createComponent(options = {}) {
- const { mockApollo } = options;
-
- return shallowMount(Index, {
- apolloProvider: mockApollo,
- });
- }
-
- describe('with Apollo mock', () => {
- let mockApollo;
-
- beforeEach(() => {
- mockApollo = createMockApolloProvider();
- wrapper = createComponent({ mockApollo });
- });
- });
-});
+const designListQueryResponse = {
+ data: {
+ project: {
+ id: '1',
+ issue: {
+ id: 'issue-1',
+ designCollection: {
+ copyState: 'READY',
+ designs: {
+ nodes: [
+ {
+ id: '3',
+ event: 'NONE',
+ filename: 'fox_3.jpg',
+ notesCount: 1,
+ image: 'image-3',
+ imageV432x230: 'image-3',
+ currentUserTodos: {
+ nodes: [],
+ },
+ },
+ ],
+ },
+ versions: {
+ nodes: [],
+ },
+ },
+ },
+ },
+ },
+};
```
-When mocking resolved values, ensure the structure of the response is the same
-as the actual API response. For example, root property should be `data`.
-
When testing queries, keep in mind they are promises, so they need to be _resolved_ to render a result. Without resolving, we can check the `loading` state of the query:
```javascript
it('renders a loading state', () => {
- const mockApollo = createMockApolloProvider();
- const wrapper = createComponent({ mockApollo });
+ const wrapper = createComponent();
expect(wrapper.findComponent(LoadingSpinner).exists()).toBe(true)
});
it('renders designs list', async () => {
- const mockApollo = createMockApolloProvider();
- const wrapper = createComponent({ mockApollo });
+ const wrapper = createComponent();
await waitForPromises()
@@ -1511,17 +1355,10 @@ it('renders designs list', async () => {
If we need to test a query error, we need to mock a rejected value as request handler:
```javascript
-function createMockApolloProvider() {
- ...
- const requestHandlers = [
- [getDesignListQuery, jest.fn().mockRejectedValue(new Error('GraphQL error')],
- ];
- ...
-}
-...
-
it('renders error if query fails', async () => {
- const wrapper = createComponent();
+ const wrapper = createComponent({
+ designListHandler: jest.fn.mockRejectedValue('Houston, we have a problem!')
+ });
await waitForPromises()
@@ -1529,38 +1366,28 @@ it('renders error if query fails', async () => {
})
```
-Request handlers can also be passed to component factory as a parameter.
-
Mutations could be tested the same way:
```javascript
-function createMockApolloProvider({
- moveHandler = jest.fn().mockResolvedValue(moveDesignMutationResponse),
-}) {
- Vue.use(VueApollo);
-
- moveDesignHandler = moveHandler;
-
- const requestHandlers = [
- [getDesignListQuery, jest.fn().mockResolvedValue(designListQueryResponse)],
- [permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
- [moveDesignMutation, moveDesignHandler],
- ];
-
- return createMockApollo(requestHandlers);
-}
-
-function createComponent(options = {}) {
- const { mockApollo } = options;
+ const moveDesignHandlerSuccess = jest.fn().mockResolvedValue(moveDesignMutationResponse)
+
+ function createComponent(options = {
+ designListHandler: jest.fn().mockResolvedValue(designListQueryResponse),
+ moveDesignHandler: moveDesignHandlerSuccess
+ }) {
+ mockApollo = createMockApollo([
+ [getDesignListQuery, options.designListHandler],
+ [permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
+ [moveDesignMutation, moveDesignHandler],
+ ])
+
+ wrapper = shallowMount(SomeComponent, {
+ apolloProvider: mockApollo
+ });
+ }
- return shallowMount(Index, {
- apolloProvider: mockApollo,
- });
-}
-...
it('calls a mutation with correct parameters and reorders designs', async () => {
- const mockApollo = createMockApolloProvider({});
- const wrapper = createComponent({ mockApollo });
+ const wrapper = createComponent();
wrapper.find(VueDraggable).vm.$emit('change', {
moved: {
@@ -1569,7 +1396,7 @@ it('calls a mutation with correct parameters and reorders designs', async () =>
},
});
- expect(moveDesignHandler).toHaveBeenCalled();
+ expect(moveDesignHandlerSuccess).toHaveBeenCalled();
await waitForPromises();
@@ -1726,121 +1553,29 @@ query fetchLocalUser {
```javascript
import fetchLocalUserQuery from '~/design_management/graphql/queries/fetch_local_user.query.graphql';
-function createMockApolloProvider() {
- Vue.use(VueApollo);
-
- const requestHandlers = [
- [getDesignListQuery, jest.fn().mockResolvedValue(designListQueryResponse)],
- [permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
- ];
-
- const mockApollo = createMockApollo(requestHandlers, {});
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: fetchLocalUserQuery,
- data: {
- fetchLocalUser: {
- __typename: 'User',
- name: 'Test',
- },
- },
- });
-
- return mockApollo;
-}
-
-function createComponent(options = {}) {
- const { mockApollo } = options;
-
- return shallowMount(Index, {
- apolloProvider: mockApollo,
- });
-}
-```
-
-Sometimes it is necessary to control what the local resolver returns and inspect how it is called by the component. This can be done by mocking your local resolver:
-
-```javascript
-import fetchLocalUserQuery from '~/design_management/graphql/queries/fetch_local_user.query.graphql';
-
-function createMockApolloProvider(options = {}) {
- Vue.use(VueApollo);
- const { fetchLocalUserSpy } = options;
-
- const mockApollo = createMockApollo([], {
- Query: {
- fetchLocalUser: fetchLocalUserSpy,
- },
- });
-
- // Necessary for local resolvers to be activated
- mockApollo.clients.defaultClient.cache.writeQuery({
- query: fetchLocalUserQuery,
- data: {},
- });
-
- return mockApollo;
-}
-```
-
-In the test you can then control what the spy is supposed to do and inspect the component after the request have returned:
-
-```javascript
-describe('My Index test with `createMockApollo`', () => {
+describe('Some component with Apollo mock', () => {
let wrapper;
- let fetchLocalUserSpy;
-
- afterEach(() => {
- wrapper.destroy();
- fetchLocalUserSpy = null;
- });
-
- describe('when loading', () => {
- beforeEach(() => {
- const mockApollo = createMockApolloProvider();
- wrapper = createComponent({ mockApollo });
- });
-
- it('displays the loader', () => {
- // Assess that the loader is present
- });
- });
-
- describe('with data', () => {
- beforeEach(async () => {
- fetchLocalUserSpy = jest.fn().mockResolvedValue(localUserQueryResponse);
- const mockApollo = createMockApolloProvider(fetchLocalUserSpy);
- wrapper = createComponent({ mockApollo });
- await waitForPromises();
- });
-
- it('should fetch data once', () => {
- expect(fetchLocalUserSpy).toHaveBeenCalledTimes(1);
- });
-
- it('displays data', () => {
- // Assess that data is present
- });
- });
-
- describe('with error', () => {
- const error = 'Error!';
-
- beforeEach(async () => {
- fetchLocalUserSpy = jest.fn().mockRejectedValueOnce(error);
- const mockApollo = createMockApolloProvider(fetchLocalUserSpy);
- wrapper = createComponent({ mockApollo });
- await waitForPromises();
- });
+ let mockApollo;
- it('should fetch data once', () => {
- expect(fetchLocalUserSpy).toHaveBeenCalledTimes(1);
+ function createComponent(options = {
+ designListHandler: jest.fn().mockResolvedValue(designListQueryResponse)
+ }) {
+ mockApollo = createMockApollo([...])
+ mockApollo.clients.defaultClient.cache.writeQuery({
+ query: fetchLocalUserQuery,
+ data: {
+ fetchLocalUser: {
+ __typename: 'User',
+ name: 'Test',
+ },
+ },
});
- it('displays the error', () => {
- // Assess that the error is displayed
+ wrapper = shallowMount(SomeComponent, {
+ apolloProvider: mockApollo
});
- });
-});
+ }
+})
```
When you need to configure the mocked apollo client's caching behavior,
@@ -1854,21 +1589,15 @@ const defaultCacheOptions = {
```
```javascript
-function createMockApolloProvider({ props = {}, requestHandlers } = {}) {
- Vue.use(VueApollo);
-
- const mockApollo = createMockApollo(
- requestHandlers,
- {},
- {
- dataIdFromObject: (object) =>
- // eslint-disable-next-line no-underscore-dangle
- object.__typename === 'Requirement' ? object.iid : defaultDataIdFromObject(object),
- },
- );
-
- return mockApollo;
-}
+mockApollo = createMockApollo(
+ requestHandlers,
+ {},
+ {
+ dataIdFromObject: (object) =>
+ // eslint-disable-next-line no-underscore-dangle
+ object.__typename === 'Requirement' ? object.iid : defaultDataIdFromObject(object),
+ },
+);
```
## Handling errors
diff --git a/doc/development/fe_guide/merge_request_widget_extensions.md b/doc/development/fe_guide/merge_request_widget_extensions.md
index 5ad918d466b..4242dd837f8 100644
--- a/doc/development/fe_guide/merge_request_widget_extensions.md
+++ b/doc/development/fe_guide/merge_request_widget_extensions.md
@@ -352,7 +352,6 @@ To generate these known events for a single widget:
1. Repeat step 6, but change the `data_source` to `redis_hll`.
1. Add each of the HLL metrics to `lib/gitlab/usage_data_counters/known_events/code_review_events.yml`:
1. `name` = (the event)
- 1. `redis_slot` = `code_review`
1. `category` = `code_review`
1. `aggregation` = `weekly`
1. Add each event (those listed in the command in step 7, replacing `test_reports`
diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md
index 3aa901093f0..20609718217 100644
--- a/doc/development/fe_guide/performance.md
+++ b/doc/development/fe_guide/performance.md
@@ -142,21 +142,21 @@ To use the Vue performance plugin:
1. Import the plugin:
- ```javascript
- import PerformancePlugin from '~/performance/vue_performance_plugin';
- ```
+ ```javascript
+ import PerformancePlugin from '~/performance/vue_performance_plugin';
+ ```
1. Use it before initializing your Vue application:
- ```javascript
- Vue.use(PerformancePlugin, {
- components: [
- 'IdeTreeList',
- 'FileTree',
- 'RepoEditor',
- ]
- });
- ```
+ ```javascript
+ Vue.use(PerformancePlugin, {
+ components: [
+ 'IdeTreeList',
+ 'FileTree',
+ 'RepoEditor',
+ ]
+ });
+ ```
The plugin accepts the list of components, performance of which should be measured. The components
should be specified by their `name` option.
diff --git a/doc/development/fe_guide/source_editor.md b/doc/development/fe_guide/source_editor.md
index 5f2e8c1e029..9f52850041d 100644
--- a/doc/development/fe_guide/source_editor.md
+++ b/doc/development/fe_guide/source_editor.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+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
---
@@ -35,7 +35,7 @@ Vue component, but the integration of Source Editor is generally straightforward
const editor = new SourceEditor({
// Editor Options.
// The list of all accepted options can be found at
- // https://microsoft.github.io/monaco-editor/api/enums/monaco.editor.EditorOption.html
+ // https://microsoft.github.io/monaco-editor/docs.html
});
```
@@ -61,7 +61,7 @@ An instance of Source Editor accepts the following configuration options:
## API
The editor uses the same public API as
-[provided by Monaco editor](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneCodeEditor.html)
+[provided by Monaco editor](https://microsoft.github.io/monaco-editor/docs.html)
with additional functions on the instance level:
| Function | Arguments | Description
diff --git a/doc/development/fe_guide/storybook.md b/doc/development/fe_guide/storybook.md
index e57c117bc39..8e0814ad96b 100644
--- a/doc/development/fe_guide/storybook.md
+++ b/doc/development/fe_guide/storybook.md
@@ -16,15 +16,15 @@ To build and launch Storybook locally, in the root directory of the `gitlab` pro
1. Install Storybook dependencies:
- ```shell
- yarn storybook:install
- ```
+ ```shell
+ yarn storybook:install
+ ```
1. Build the Storybook site:
- ```shell
- yarn storybook:start
- ```
+ ```shell
+ yarn storybook:start
+ ```
## Adding components to Storybook
@@ -35,14 +35,14 @@ To add a story:
1. Create a new `.stories.js` file in the same directory as the Vue component.
The filename should have the same prefix as the Vue component.
- ```txt
- vue_shared/
- ├─ components/
- │ ├─ sidebar
- │ | ├─ todo_toggle
- │ | | ├─ todo_button.vue
- │ │ | ├─ todo_button.stories.js
- ```
+ ```txt
+ vue_shared/
+ ├─ components/
+ │ ├─ sidebar
+ │ | ├─ todo_toggle
+ │ | | ├─ todo_button.vue
+ │ │ | ├─ todo_button.stories.js
+ ```
1. Write the story as per the [official Storybook instructions](https://storybook.js.org/docs/vue/writing-stories/introduction/)
diff --git a/doc/development/fe_guide/style/html.md b/doc/development/fe_guide/style/html.md
index b1cce29bc61..c92f77e9033 100644
--- a/doc/development/fe_guide/style/html.md
+++ b/doc/development/fe_guide/style/html.md
@@ -58,7 +58,7 @@ Button tags requires a `type` attribute according to the [W3C HTML specification
### Blank target
-Arbitrarily opening links in a new tab is not recommended, so refer to the [Pajamas guidelines on links](https://design.gitlab.com/product-foundations/interaction/#links) when considering adding `target="_blank"` to links.
+Arbitrarily opening links in a new tab is not recommended, so refer to the [Pajamas guidelines on links](https://design.gitlab.com/components/link) when considering adding `target="_blank"` to links.
When using `target="_blank"` with `a` tags, you must also add the `rel="noopener noreferrer"` attribute. This prevents a security vulnerability [documented by JitBit](https://www.jitbit.com/alexblog/256-targetblank---the-most-underestimated-vulnerability-ever/).
diff --git a/doc/development/fe_guide/style/index.md b/doc/development/fe_guide/style/index.md
index 94ed9544cf5..552b769d6f6 100644
--- a/doc/development/fe_guide/style/index.md
+++ b/doc/development/fe_guide/style/index.md
@@ -4,7 +4,7 @@ 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
---
-# GitLab development style guides
+# Frontend style guides
See below for the relevant style guides, guidelines, linting, and other information for developing GitLab.
diff --git a/doc/development/fe_guide/style/javascript.md b/doc/development/fe_guide/style/javascript.md
index 3e3a79dd7bb..b35ffdd8669 100644
--- a/doc/development/fe_guide/style/javascript.md
+++ b/doc/development/fe_guide/style/javascript.md
@@ -329,3 +329,22 @@ Only export the constants as a collection (array, or object) when there is a nee
// good, if the constants need to be iterated over
export const VARIANTS = [VARIANT_WARNING, VARIANT_ERROR];
```
+
+## Error handling
+
+When catching a server-side error you should use the error message
+utility function contained in `app/assets/javascripts/lib/utils/error_message.js`.
+This utility parses the received error message and checks for a prefix that indicates
+whether the message is meant to be user-facing or not. The utility returns
+an object with the message, and a boolean indicating whether the message is meant to be user-facing or not. Please make sure that the Backend is aware of the utils usage and is adding the prefix
+to the error message accordingly.
+
+```javascript
+import { parseErrorMessage } from '~/lib/utils/error_message';
+
+onError(error) {
+ const { message, userFacing } = parseErrorMessage(error);
+
+ const errorMessage = userFacing ? message : genericErrorText;
+}
+```
diff --git a/doc/development/fe_guide/style/vue.md b/doc/development/fe_guide/style/vue.md
index a21d7c4577b..e9d2a724d9d 100644
--- a/doc/development/fe_guide/style/vue.md
+++ b/doc/development/fe_guide/style/vue.md
@@ -59,63 +59,66 @@ Check the [rules](https://github.com/vuejs/eslint-plugin-vue#bulb-rules) for mor
1. Explicitly define data being passed into the Vue app
- ```javascript
- // bad
- return new Vue({
- el: '#element',
- components: {
- componentName
- },
- provide: {
- ...someDataset
- },
- props: {
- ...anotherDataset
- },
- render: createElement => createElement('component-name'),
- }));
-
- // good
- const { foobar, barfoo } = someDataset;
- const { foo, bar } = anotherDataset;
-
- return new Vue({
- el: '#element',
- components: {
- componentName
- },
- provide: {
- foobar,
- barfoo
- },
- props: {
- foo,
- bar
- },
- render: createElement => createElement('component-name'),
- }));
- ```
-
- We discourage the use of the spread operator in this specific case in
- order to keep our codebase explicit, discoverable, and searchable.
- This applies in any place where we would benefit from the above, such as
- when [initializing Vuex state](../vuex.md#why-not-just-spread-the-initial-state).
- The pattern above also enables us to easily parse non scalar values during
- instantiation.
-
- ```javascript
- return new Vue({
- el: '#element',
- components: {
- componentName
- },
- props: {
- foo,
- bar: parseBoolean(bar)
- },
- render: createElement => createElement('component-name'),
- }));
- ```
+ ```javascript
+ // bad
+ return new Vue({
+ el: '#element',
+ name: 'ComponentNameRoot',
+ components: {
+ componentName
+ },
+ provide: {
+ ...someDataset
+ },
+ props: {
+ ...anotherDataset
+ },
+ render: createElement => createElement('component-name'),
+ }));
+
+ // good
+ const { foobar, barfoo } = someDataset;
+ const { foo, bar } = anotherDataset;
+
+ return new Vue({
+ el: '#element',
+ name: 'ComponentNameRoot',
+ components: {
+ componentName
+ },
+ provide: {
+ foobar,
+ barfoo
+ },
+ props: {
+ foo,
+ bar
+ },
+ render: createElement => createElement('component-name'),
+ }));
+ ```
+
+ We discourage the use of the spread operator in this specific case in
+ order to keep our codebase explicit, discoverable, and searchable.
+ This applies in any place where we would benefit from the above, such as
+ when [initializing Vuex state](../vuex.md#why-not-just-spread-the-initial-state).
+ The pattern above also enables us to easily parse non scalar values during
+ instantiation.
+
+ ```javascript
+ return new Vue({
+ el: '#element',
+ name: 'ComponentNameRoot',
+ components: {
+ componentName
+ },
+ props: {
+ foo,
+ bar: parseBoolean(bar)
+ },
+ render: createElement => createElement('component-name'),
+ }));
+ ```
## Naming
@@ -404,7 +407,7 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
```
1. When using `v-for` with `template` and there is more than one child element, the `:key` values
-must be unique. It's advised to use `kebab-case` namespaces.
+ must be unique. It's advised to use `kebab-case` namespaces.
```html
<template v-for="(item, index) in items">
@@ -467,8 +470,9 @@ Creating a global, mutable wrapper provides a number of advantages, including th
```
- Use a `beforeEach` block to mount the component (see
-[the `createComponent` factory](#the-createcomponent-factory) for more information).
-- Use an `afterEach` block to destroy the component, for example, `wrapper.destroy()`.
+ [the `createComponent` factory](#the-createcomponent-factory) for more information).
+- Automatically destroy the component after the test is run with [`enableAutoDestroy`](https://v1.test-utils.vuejs.org/api/#enableautodestroy-hook)
+ set in [`shared_test_setup.js`](https://gitlab.com/gitlab-org/gitlab/-/blob/d0bdc8370ef17891fd718a4578e41fef97cf065d/spec/frontend/__helpers__/shared_test_setup.js#L20).
#### The `createComponent` factory
@@ -538,42 +542,42 @@ describe('MyComponent', () => {
#### `createComponent` best practices
1. Consider using a single (or a limited number of) object arguments over many arguments.
- Defining single parameters for common data like `props` is okay,
- but keep in mind our [JavaScript style guide](javascript.md#limit-number-of-parameters) and
- stay within the parameter number limit:
+ Defining single parameters for common data like `props` is okay,
+ but keep in mind our [JavaScript style guide](javascript.md#limit-number-of-parameters) and
+ stay within the parameter number limit:
- ```javascript
- // bad
- function createComponent(data, props, methods, isLoading, mountFn) { }
+ ```javascript
+ // bad
+ function createComponent(data, props, methods, isLoading, mountFn) { }
- // good
- function createComponent({ data, props, methods, stubs, isLoading } = {}) { }
+ // good
+ function createComponent({ data, props, methods, stubs, isLoading } = {}) { }
- // good
- function createComponent(props = {}, { data, methods, stubs, isLoading } = {}) { }
- ```
+ // good
+ function createComponent(props = {}, { data, methods, stubs, isLoading } = {}) { }
+ ```
1. If you require both `mount` _and_ `shallowMount` within the same set of tests, it
-can be useful define a `mountFn` parameter for the `createComponent` factory that accepts
-the mounting function (`mount` or `shallowMount`) to be used to mount the component:
+ can be useful define a `mountFn` parameter for the `createComponent` factory that accepts
+ the mounting function (`mount` or `shallowMount`) to be used to mount the component:
- ```javascript
- import { shallowMount } from '@vue/test-utils';
+ ```javascript
+ import { shallowMount } from '@vue/test-utils';
- function createComponent({ mountFn = shallowMount } = {}) { }
- ```
+ function createComponent({ mountFn = shallowMount } = {}) { }
+ ```
1. Use the `mountExtended` and `shallowMountExtended` helpers to expose `wrapper.findByTestId()`:
- ```javascript
- import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
- import { SomeComponent } from 'components/some_component.vue';
+ ```javascript
+ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+ import { SomeComponent } from 'components/some_component.vue';
- let wrapper;
+ let wrapper;
- const createWrapper = () => { wrapper = shallowMountExtended(SomeComponent); };
- const someButton = () => wrapper.findByTestId('someButtonTestId');
- ```
+ const createWrapper = () => { wrapper = shallowMountExtended(SomeComponent); };
+ const someButton = () => wrapper.findByTestId('someButtonTestId');
+ ```
### Setting component state
@@ -581,70 +585,70 @@ the mounting function (`mount` or `shallowMount`) to be used to mount the compon
component state wherever possible. Instead, set the component's
[`propsData`](https://v1.test-utils.vuejs.org/api/options.html#propsdata) when mounting the component:
- ```javascript
- // bad
- wrapper = shallowMount(MyComponent);
- wrapper.setProps({
- myProp: 'my cool prop'
- });
+ ```javascript
+ // bad
+ wrapper = shallowMount(MyComponent);
+ wrapper.setProps({
+ myProp: 'my cool prop'
+ });
- // good
- wrapper = shallowMount({ propsData: { myProp: 'my cool prop' } });
- ```
+ // good
+ wrapper = shallowMount({ propsData: { myProp: 'my cool prop' } });
+ ```
- The exception here is when you wish to test component reactivity in some way.
- For example, you may want to test the output of a component when after a particular watcher has
- executed. Using `setProps` to test such behavior is okay.
+ The exception here is when you wish to test component reactivity in some way.
+ For example, you may want to test the output of a component when after a particular watcher has
+ executed. Using `setProps` to test such behavior is okay.
### Accessing component state
1. When accessing props or attributes, prefer the `wrapper.props('myProp')` syntax over
`wrapper.props().myProp` or `wrapper.vm.myProp`:
- ```javascript
- // good
- expect(wrapper.props().myProp).toBe(true);
- expect(wrapper.attributes().myAttr).toBe(true);
+ ```javascript
+ // good
+ expect(wrapper.props().myProp).toBe(true);
+ expect(wrapper.attributes().myAttr).toBe(true);
- // better
- expect(wrapper.props('myProp').toBe(true);
- expect(wrapper.attributes('myAttr')).toBe(true);
- ```
+ // better
+ expect(wrapper.props('myProp').toBe(true);
+ expect(wrapper.attributes('myAttr')).toBe(true);
+ ```
1. When asserting multiple props, check the deep equality of the `props()` object with
[`toEqual`](https://jestjs.io/docs/expect#toequalvalue):
- ```javascript
- // good
- expect(wrapper.props('propA')).toBe('valueA');
- expect(wrapper.props('propB')).toBe('valueB');
- expect(wrapper.props('propC')).toBe('valueC');
-
- // better
- expect(wrapper.props()).toEqual({
- propA: 'valueA',
- propB: 'valueB',
- propC: 'valueC',
- });
- ```
+ ```javascript
+ // good
+ expect(wrapper.props('propA')).toBe('valueA');
+ expect(wrapper.props('propB')).toBe('valueB');
+ expect(wrapper.props('propC')).toBe('valueC');
+
+ // better
+ expect(wrapper.props()).toEqual({
+ propA: 'valueA',
+ propB: 'valueB',
+ propC: 'valueC',
+ });
+ ```
1. If you are only interested in some of the props, you can use
[`toMatchObject`](https://jestjs.io/docs/expect#tomatchobjectobject). Prefer `toMatchObject`
over [`expect.objectContaining`](https://jestjs.io/docs/expect#expectobjectcontainingobject):
- ```javascript
- // good
- expect(wrapper.props()).toEqual(expect.objectContaining({
- propA: 'valueA',
- propB: 'valueB',
- }));
+ ```javascript
+ // good
+ expect(wrapper.props()).toEqual(expect.objectContaining({
+ propA: 'valueA',
+ propB: 'valueB',
+ }));
- // better
- expect(wrapper.props()).toMatchObject({
- propA: 'valueA',
- propB: 'valueB',
- });
- ```
+ // better
+ expect(wrapper.props()).toMatchObject({
+ propA: 'valueA',
+ propB: 'valueB',
+ });
+ ```
## The JavaScript/Vue Accord
@@ -659,16 +663,16 @@ The goal of this accord is to make sure we are all on the same page.
1. We avoid adding new jQuery events when they are not required. Instead of adding new jQuery
events take a look at [different methods to do the same task](https://v2.vuejs.org/v2/api/#vm-emit).
1. You may query the `window` object one time, while bootstrapping your application for application
-specific data (for example, `scrollTo` is ok to access anytime). Do this access during the
-bootstrapping of your application.
+ specific data (for example, `scrollTo` is ok to access anytime). Do this access during the
+ bootstrapping of your application.
1. You may have a temporary but immediate need to create technical debt by writing code that does
-not follow our standards, to be refactored later. Maintainers need to be ok with the tech debt in
-the first place. An issue should be created for that tech debt to evaluate it further and discuss.
-In the coming months you should fix that tech debt, with its priority to be determined by maintainers.
+ not follow our standards, to be refactored later. Maintainers need to be ok with the tech debt in
+ the first place. An issue should be created for that tech debt to evaluate it further and discuss.
+ In the coming months you should fix that tech debt, with its priority to be determined by maintainers.
1. When creating tech debt you must write the tests for that code before hand and those tests may
-not be rewritten. For example, jQuery tests rewritten to Vue tests.
+ not be rewritten. For example, jQuery tests rewritten to Vue tests.
1. You may choose to use VueX as a centralized state management. If you choose not to use VueX, you
-must use the *store pattern* which can be found in the
-[Vue.js documentation](https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch).
+ must use the *store pattern* which can be found in the
+ [Vue.js documentation](https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch).
1. Once you have chosen a centralized state-management solution you must use it for your entire
-application. Don't mix and match your state-management solutions.
+ application. Don't mix and match your state-management solutions.
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index cea47bc0e4c..119a91e33b5 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -76,7 +76,13 @@ component, is that you avoid creating a fixture or an HTML element in the unit t
`initSimpleApp` is a helper function that streamlines the process of mounting a component in Vue.js. It accepts two arguments: a selector string representing the mount point in the HTML, and a Vue component.
-To use `initSimpleApp`, include the HTML element in the page with the appropriate selector and add a data-view-model attribute containing a JSON object. Then, import the desired Vue component and pass it along with the selector to `initSimpleApp`. This mounts the component at the specified location.
+To use `initSimpleApp`:
+
+1. Include an HTML element in the page with an ID or unique class.
+1. Add a data-view-model attribute containing a JSON object.
+1. Import the desired Vue component, and pass it along with a valid CSS selector string
+ that selects the HTML element to `initSimpleApp`. This string mounts the component
+ at the specified location.
`initSimpleApp` automatically retrieves the content of the data-view-model attribute as a JSON object and passes it as props to the mounted Vue component. This can be used to pre-populate the component with data.
@@ -138,6 +144,7 @@ const { endpoint } = el.dataset;
return new Vue({
el,
+ name: 'MyComponentRoot',
render(createElement) {
return createElement('my-component', {
provide: {
@@ -198,6 +205,7 @@ const { endpoint } = el.dataset;
return new Vue({
el,
+ name: 'MyComponentRoot',
render(createElement) {
return createElement('my-component', {
props: {
@@ -252,6 +260,7 @@ export const initUserForm = () => {
return new Vue({
el,
+ name: 'UserFormRoot',
render(h) {
return h(UserForm, {
props: {
@@ -305,6 +314,7 @@ initializing our Vue instance, and the data should be provided as `props` to the
```javascript
return new Vue({
el: '.js-vue-app',
+ name: 'MyComponentRoot',
render(createElement) {
return createElement('my-component', {
props: {
@@ -443,6 +453,22 @@ Composition API allows you to place the logic in the `<script>` section of the c
</script>
```
+### `v-bind` limitations
+
+Avoid using `v-bind="$attrs"` unless absolutely necessary. You might need this when
+developing a native control wrapper. (This is a good candidate for a `gitlab-ui` component.)
+In any other cases, always prefer using `props` and explicit data flow.
+
+Using `v-bind="$attrs"` leads to:
+
+1. A loss in component's contract. The `props` were designed specifically
+ to address this problem.
+1. High maintenance cost for each component in the tree. `v-bind="$attrs"` is specifically
+ hard to debug because you must scan the whole hierarchy of components to understand
+ the data flow.
+1. Problems during migration to Vue 3. `$attrs` in Vue 3 include event listeners which
+ could cause unexpected side-effects after Vue 3 migration is completed.
+
### Aim to have one API style per component
When adding `setup()` property to Vue component, consider refactoring it to Composition API entirely. It's not always feasible, especially for large components, but we should aim to have one API style per component for readability and maintainability.
@@ -608,8 +634,7 @@ describe('~/todos/app.vue', () => {
});
afterEach(() => {
- // IMPORTANT: Clean up the component instance and axios mock adapter
- wrapper.destroy();
+ // IMPORTANT: Clean up the axios mock adapter
mock.restore();
});
diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md
index 01ee50fb6ca..52278c94e9f 100644
--- a/doc/development/fe_guide/vuex.md
+++ b/doc/development/fe_guide/vuex.md
@@ -6,14 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Vuex
-When there's a clear benefit to separating state management from components (for example, due to state complexity) we recommend using [Vuex](https://vuex.vuejs.org) over any other Flux pattern. Otherwise, feel free to manage state in the components.
-
-Vuex should be strongly considered when:
-
-- You expect multiple parts of the application to react to state changes.
-- There's a need to share data between multiple components.
-- There are complex interactions with Backend, for example, multiple API calls.
-- The app involves interacting with backend via both traditional REST API and GraphQL (especially when moving the REST API over to GraphQL is a pending backend task).
+[Vuex](https://vuex.vuejs.org) should no longer be considered a preferred path to store management and is currently in its legacy phase. This means it is acceptable to add upon existing `Vuex` stores, but we strongly recommend reducing store sizes over time and eventually migrating fully to [Apollo](https://www.apollographql.com/) whenever it's possible. Before adding any new `Vuex` store to an application, first ensure that the `Vue` application you plan to add it into **does not use** `Apollo`. `Vuex` and `Apollo` should not be combined unless absolutely necessary. Please consider reading through [our GraphQL documentation](../fe_guide/graphql.md) for more guidelines on how you can build `Apollo` based applications.
The information included in this page is explained in more detail in the
official [Vuex documentation](https://vuex.vuejs.org).
@@ -97,7 +90,7 @@ In this file, we write the actions that call mutations for handling a list of us
```javascript
import * as types from './mutation_types';
import axios from '~/lib/utils/axios_utils';
- import { createAlert } from '~/flash';
+ import { createAlert } from '~/alert';
export const fetchUsers = ({ state, dispatch }) => {
commit(types.REQUEST_USERS);
@@ -305,6 +298,7 @@ export default () => {
return new Vue({
el,
+ name: 'AwesomeVueRoot',
store: createStore(el.dataset),
render: h => h(AwesomeVueApp)
});
@@ -462,10 +456,6 @@ describe('component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should show a user', async () => {
const user = {
name: 'Foo',
diff --git a/doc/development/fe_guide/widgets.md b/doc/development/fe_guide/widgets.md
index edb8559da48..6cd8e6c091c 100644
--- a/doc/development/fe_guide/widgets.md
+++ b/doc/development/fe_guide/widgets.md
@@ -62,11 +62,11 @@ Because we need different GraphQL queries and mutations for different sidebars,
```javascript
export const assigneesQueries = {
- [IssuableType.Issue]: {
+ [TYPE_ISSUE]: {
query: getIssueParticipants,
mutation: updateAssigneesMutation,
},
- [IssuableType.MergeRequest]: {
+ [TYPE_MERGE_REQUEST]: {
query: getMergeRequestParticipants,
mutation: updateMergeRequestParticipantsMutation,
},
diff --git a/doc/development/feature_development.md b/doc/development/feature_development.md
index 141b24161b4..c3cee596d8a 100644
--- a/doc/development/feature_development.md
+++ b/doc/development/feature_development.md
@@ -79,7 +79,7 @@ Consult these topics for information on contributing to specific GitLab features
- [Adding a new Redis instance](redis/new_redis_instance.md)
- [Sidekiq guidelines](sidekiq/index.md) for working with Sidekiq workers
- [Working with Gitaly](gitaly.md)
-- [Elasticsearch integration docs](elasticsearch.md)
+- [Advanced search integration docs](advanced_search.md)
- [Working with merge request diffs](diffs.md)
- [Approval Rules](merge_request_concepts/approval_rules.md)
- [Repository mirroring](repository_mirroring.md)
@@ -127,7 +127,6 @@ See [database guidelines](database/index.md).
- [Security Scanners](integrations/secure.md)
- [Secure Partner Integration](integrations/secure_partner_integration.md)
- [How to run Jenkins in development environment](integrations/jenkins.md)
-- [How to run local CodeSandbox integration for Web IDE Live Preview](integrations/codesandbox.md)
The following integration guides are internal. Some integrations require access to administrative accounts of third-party services and are available only for GitLab team members to contribute to:
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
index 3adf5248b8d..f8a592f98f5 100644
--- a/doc/development/feature_flags/controls.md
+++ b/doc/development/feature_flags/controls.md
@@ -84,6 +84,8 @@ When a feature has successfully been
environment and verified as safe and working, you can roll out the
change to GitLab.com (production).
+If a feature is [deprecated](../../update/deprecations.md), do not enable the flag.
+
#### Communicate the change
Some feature flag changes on GitLab.com should be communicated with
diff --git a/doc/development/feature_flags/index.md b/doc/development/feature_flags/index.md
index 7370697b082..9b6876ac0bc 100644
--- a/doc/development/feature_flags/index.md
+++ b/doc/development/feature_flags/index.md
@@ -35,7 +35,7 @@ should be leveraged:
the status of a feature behind the feature flag in the documentation and with other stakeholders. The
issue description should be updated with the feature flag name and whether it is
defaulted on or off as soon it is evident that a feature flag is needed.
-- Merge requests that introduce a feature flag, update its state, or remove them
+- Merge requests that introduce a feature flag, update its state, or remove the
existing feature flag because a feature is deemed stable must have the
~"feature flag" label assigned.
diff --git a/doc/development/fips_compliance.md b/doc/development/fips_compliance.md
index 147ff5fa6e9..f0634107ba5 100644
--- a/doc/development/fips_compliance.md
+++ b/doc/development/fips_compliance.md
@@ -67,9 +67,8 @@ listed here that also do not work properly in FIPS mode:
- [Static Application Security Testing (SAST)](../user/application_security/sast/index.md)
supports a reduced set of [analyzers](../user/application_security/sast/index.md#fips-enabled-images)
when operating in FIPS-compliant mode.
-- Advanced Search is currently not included in FIPS mode. It must not be enabled to be FIPS-compliant.
+- Advanced search is currently not included in FIPS mode. It must not be enabled to be FIPS-compliant.
- [Gravatar or Libravatar-based profile images](../administration/libravatar.md) are not FIPS-compliant.
-- [Personal Access Tokens](../user/profile/personal_access_tokens.md) are not available for use or creation.
Additionally, these package repositories are disabled in FIPS mode:
@@ -275,104 +274,55 @@ all:
gitlab_charts_custom_config_file: '/path/to/gitlab-environment-toolkit/ansible/environments/gitlab-10k/inventory/charts.yml'
```
-Now create `charts.yml` in the location specified above and specify tags with a `-fips` suffix. For example:
+Now create `charts.yml` in the location specified above and specify tags with a `-fips` suffix.
-```yaml
-global:
- image:
- pullPolicy: Always
- certificates:
- image:
- tag: master-fips
- kubectl:
- image:
- tag: master-fips
-
-gitlab:
- gitaly:
- image:
- tag: master-fips
- gitlab-exporter:
- image:
- tag: master-fips
- gitlab-shell:
- image:
- tag: main-fips # The default branch is main, not master
- gitlab-mailroom:
- image:
- tag: master-fips
- gitlab-pages:
- image:
- tag: master-fips
- migrations:
- image:
- tag: master-fips
- sidekiq:
- image:
- tag: master-fips
- toolbox:
- image:
- tag: master-fips
- webservice:
- image:
- tag: master-fips
- workhorse:
- tag: master-fips
-
-nginx-ingress:
- controller:
- image:
- repository: registry.gitlab.com/gitlab-org/cloud-native/charts/gitlab-ingress-nginx/controller
- tag: v1.2.1-fips
- pullPolicy: Always
- digest: sha256:c4222b7ab3836b9be2a7649cff4b2e6ead34286dfdf3a7b04eb34fdd3abb0334
-```
-
-The above example shows a FIPS-enabled [`nginx-ingress`](https://github.com/kubernetes/ingress-nginx) image.
-See our [Charts documentation on FIPS](https://docs.gitlab.com/charts/advanced/fips/index.html) for more details.
+See our [Charts documentation on FIPS](https://docs.gitlab.com/charts/advanced/fips/index.html) for more details, including
+an [example values file](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/examples/fips/values.yaml) as a reference.
You can also use release tags, but the versioning is tricky because each
component may use its own versioning scheme. For example, for GitLab v15.2:
```yaml
global:
+ image:
+ tagSuffix: -fips
certificates:
image:
- tag: 20211220-r0-fips
+ tag: 20211220-r0
kubectl:
image:
- tag: 1.18.20-fips
+ tag: 1.18.20
gitlab:
gitaly:
image:
- tag: v15.2.0-fips
+ tag: v15.2.0
gitlab-exporter:
image:
- tag: 11.17.1-fips
+ tag: 11.17.1
gitlab-shell:
image:
- tag: v14.9.0-fips
+ tag: v14.9.0
gitlab-mailroom:
image:
- tag: v15.2.0-fips
+ tag: v15.2.0
gitlab-pages:
image:
- tag: v1.61.0-fips
+ tag: v1.61.0
migrations:
image:
- tag: v15.2.0-fips
+ tag: v15.2.0
sidekiq:
image:
- tag: v15.2.0-fips
+ tag: v15.2.0
toolbox:
image:
- tag: v15.2.0-fips
+ tag: v15.2.0
webservice:
image:
- tag: v15.2.0-fips
+ tag: v15.2.0
workhorse:
- tag: v15.2.0-fips
+ tag: v15.2.0
```
## FIPS Performance Benchmarking
@@ -496,7 +446,7 @@ irb(main):001:0> require 'openssl'; OpenSSL.fips_mode
### Go
-Google maintains a [`dev.boringcrypto` branch](https://github.com/golang/go/tree/dev.boringcrypto) in the Golang compiler
+Google maintains a [`dev.boringcrypto` branch](https://github.com/golang/go/tree/dev.boringcrypto) in the Go compiler
that makes it possible to statically link BoringSSL, a FIPS-validated module forked from OpenSSL.
However, BoringSSL is not intended for public use.
diff --git a/doc/development/gemfile.md b/doc/development/gemfile.md
index 36ef1bcd834..38c0d77bcae 100644
--- a/doc/development/gemfile.md
+++ b/doc/development/gemfile.md
@@ -4,7 +4,7 @@ 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
---
-# Gemfile guidelines
+# Gemfile development guidelines
When adding a new entry to `Gemfile`, or upgrading an existing dependency pay
attention to the following rules.
@@ -60,6 +60,8 @@ This means that new dependencies should, at a minimum, meet the following criter
- There are no issues open that we know may impact the availability or performance of GitLab.
- The project is tested using some form of test automation. The test suite must be passing
using the Ruby version currently used by GitLab.
+- CI builds for all supported platforms must succeed using the new dependency. For more information, see
+ how to [build a package for testing](build_test_package.md#building-a-package-for-testing).
- If the project uses a C extension, consider requesting an additional review from a C or MRI
domain expert. C extensions can greatly impact GitLab stability and performance.
@@ -95,6 +97,8 @@ does not contain any hidden dependencies on our application code.
In general, we want to think carefully before doing this as there are
also disadvantages:
+### Potential disadvantages
+
1. Gems - even those maintained by GitLab - do not necessarily go
through the same [code review process](code_review.md) as the main
Rails application.
@@ -106,9 +110,23 @@ also disadvantages:
community's needs. In general, if we are not using the latest version
of our own gem, that might be a warning sign.
+### Create and publish a Ruby gem
+
In the case where we do want to extract some library code we've written
to a gem, go through these steps:
+1. Determine a suitable name for the gem. If it's a GitLab-owned gem, prefix
+ the gem name with `gitlab-`. For example, `gitlab-sidekiq-fetcher`.
+1. Create the gem or fork as necessary.
+1. Ensure the `gitlab_rubygems` group is an owner of the new gem by running:
+
+ ```shell
+ gem owner <gem-name> --add gitlab_rubygems
+ ```
+
+1. [Publish the gem to rubygems.org](https://guides.rubygems.org/publishing/#publishing-to-rubygemsorg)
+1. Visit `https://rubygems.org/gems/<gem-name>` and verify that the gem published
+ successfully and `gitlab_rubygems` is also an owner.
1. Start with the code in the Rails application. Here it's fine to have
the code in `lib/` and loaded automatically. We can skip this step if
the step below makes more sense initially.
diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md
index b4f5501ccac..addab512f89 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -4,7 +4,7 @@ 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
---
-# Gitaly developers guide
+# Gitaly development guidelines
[Gitaly](https://gitlab.com/gitlab-org/gitaly) is a high-level Git RPC service used by GitLab Rails,
Workhorse and GitLab Shell.
@@ -14,7 +14,7 @@ Workhorse and GitLab Shell.
<!-- vale gitlab.Spelling = NO -->
In May 2019, Bob Van Landuyt
-hosted a Deep Dive (GitLab team members only: `https://gitlab.com/gitlab-org/create-stage/issues/1`)
+hosted a Deep Dive (GitLab team members only: `https://gitlab.com/gitlab-org/create-stage/-/issues/1`)
on the [Gitaly project](https://gitlab.com/gitlab-org/gitaly). It included how to contribute to it as a
Ruby developer, and shared domain-specific knowledge with anyone who may work in this part of the
codebase in the future.
@@ -257,13 +257,13 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
1. Create a package scoped flag name:
- ```golang
+ ```go
var findAllTagsFeatureFlag = "go-find-all-tags"
```
1. Create a switch in the code using the `featureflag` package:
- ```golang
+ ```go
if featureflag.IsEnabled(ctx, findAllTagsFeatureFlag) {
// go implementation
} else {
@@ -273,7 +273,7 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
1. Create Prometheus metrics:
- ```golang
+ ```go
var findAllTagsRequests = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "gitaly_find_all_tags_requests_total",
@@ -297,7 +297,7 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
1. Set headers in tests:
- ```golang
+ ```go
import (
"google.golang.org/grpc/metadata"
diff --git a/doc/development/github_importer.md b/doc/development/github_importer.md
index 17b4a28f57d..2d9ae768d33 100644
--- a/doc/development/github_importer.md
+++ b/doc/development/github_importer.md
@@ -12,10 +12,11 @@ necessary to import GitHub projects into a GitLab instance.
The GitHub importer offers two different types of importers: a sequential
importer and a parallel importer. The Rake task `import:github` uses the
-sequential importer, while everything else uses the parallel importer. The
-difference between these two importers is quite simple: the sequential importer
-does all work in a single thread, making it more useful for debugging purposes
-or Rake tasks. The parallel importer, on the other hand, uses Sidekiq.
+sequential importer, and everything else uses the parallel importer. The
+difference between these two importers is:
+
+- The sequential importer does all the work in a single thread, so it's more suited for debugging purposes or Rake tasks.
+- The parallel importer uses Sidekiq.
## Requirements
@@ -179,10 +180,10 @@ Advancing stages is done in one of two ways:
The first approach should only be used by workers that perform all their work in
a single thread, while `AdvanceStageWorker` should be used for everything else.
-The way `AdvanceStageWorker` works is fairly simple. When scheduling a job it
+When you schedule a job, `AdvanceStageWorker`
is given a project ID, a list of Redis keys, and the name of the next
stage. The Redis keys (produced by `Gitlab::JobWaiter`) are used to check if the
-currently running stage has been completed or not. If the stage has not yet been
+running stage has been completed or not. If the stage has not yet been
completed `AdvanceStageWorker` reschedules itself. After a stage finishes
`AdvanceStageworker` refreshes the import JID (more on this below) and
schedule the worker of the next stage.
@@ -324,14 +325,6 @@ The last log entry reports the number of objects fetched and imported:
}
```
-## Errors when importing large projects
-
-The GitHub importer may encounter errors when importing large projects. For help with this, see the
-documentation for the following use cases:
-
-- [Alternative way to import notes and diff notes](../user/project/import/github.md#alternative-way-to-import-notes-and-diff-notes)
-- [Reduce GitHub API request objects per page](../user/project/import/github.md#reduce-github-api-request-objects-per-page)
-
## Metrics dashboards
To assess the GitHub importer health, the [GitHub importer dashboard](https://dashboards.gitlab.net/d/importers-github-importer/importers-github-importer)
diff --git a/doc/development/gitlab_flavored_markdown/index.md b/doc/development/gitlab_flavored_markdown/index.md
index f115ae9a11c..064a7ecbfa9 100644
--- a/doc/development/gitlab_flavored_markdown/index.md
+++ b/doc/development/gitlab_flavored_markdown/index.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
<!-- vale gitlab.GitLabFlavoredMarkdown = NO -->
-# GitLab Flavored Markdown (GLFM) developer documentation
+# GitLab Flavored Markdown (GLFM) development guidelines
This page contains the MVC for the developer documentation for GitLab Flavored Markdown (GLFM).
For the user documentation about Markdown in GitLab, refer to
diff --git a/doc/development/gitlab_shell/index.md b/doc/development/gitlab_shell/index.md
index 7097fd48cea..3a1af0fc9e9 100644
--- a/doc/development/gitlab_shell/index.md
+++ b/doc/development/gitlab_shell/index.md
@@ -4,7 +4,7 @@ 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
---
-# GitLab Shell
+# GitLab Shell development guidelines
[![pipeline status](https://gitlab.com/gitlab-org/gitlab-shell/badges/main/pipeline.svg)](https://gitlab.com/gitlab-org/gitlab-shell/-/pipelines?ref=main) [![coverage report](https://gitlab.com/gitlab-org/gitlab-shell/badges/main/coverage.svg)](https://gitlab.com/gitlab-org/gitlab-shell/-/pipelines?ref=main) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlab-shell.svg)](https://codeclimate.com/github/gitlabhq/gitlab-shell)
@@ -21,8 +21,8 @@ Ruby to build and test, but not to run.
GitLab Shell runs on `port 22` on an Omnibus installation. To use a regular SSH
service, configure it on an alternative port.
-Download and install the current version of Go from [golang.org](https://go.dev/dl/).
-We follow the [Golang Release Policy](https://golang.org/doc/devel/release.html#policy)
+Download and install the [current version of Go](https://go.dev/dl/).
+We follow the [Go Release Policy](https://go.dev/doc/devel/release#policy)
and support:
- The current stable version.
diff --git a/doc/development/gitpod_internals.md b/doc/development/gitpod_internals.md
index a4674df758d..a4b340916dd 100644
--- a/doc/development/gitpod_internals.md
+++ b/doc/development/gitpod_internals.md
@@ -25,6 +25,6 @@ You can find this webhook in [Webhook Settings in `gitlab-org/gitlab`](https://g
If a webhook failed to connect for a long time, then it may have been disabled in the project.
-To re-enable a failing or failed webhook, send a test request in [Webhook Settings](https://gitlab.com/gitlab-org/gitlab/-/hooks). See [Re-enable disabled webhooks page](https://docs.gitlab.com/15.4/ee/user/project/integrations/webhooks.html#re-enable-disabled-webhooks) for more details.
+To re-enable a failing or failed webhook, send a test request in [Webhook Settings](https://gitlab.com/gitlab-org/gitlab/-/hooks). See [Re-enable disabled webhooks page](../user/project/integrations/webhooks.md#re-enable-disabled-webhooks) for more details.
After re-enabling, check the prebuilds' health in a [project's prebuilds](https://gitpod.io/t/gitlab-org/gitlab/prebuilds) and confirm that prebuilds start without any errors.
diff --git a/doc/development/go_guide/go_upgrade.md b/doc/development/go_guide/go_upgrade.md
index b3ec0a15c37..f71fe7b8dac 100644
--- a/doc/development/go_guide/go_upgrade.md
+++ b/doc/development/go_guide/go_upgrade.md
@@ -26,7 +26,7 @@ by Distribution:
## Supporting multiple Go versions
-Individual Golang projects need to support multiple Go versions because:
+Individual Go projects need to support multiple Go versions because:
- When a new version of Go is released, we should start integrating it into the CI pipelines to verify compatibility with the new compiler.
- We must support the [official Omnibus GitLab Go version](#updating-go-version), which may be behind the latest minor release.
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 508219cee43..6092a05afff 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -124,7 +124,7 @@ lint:
# Write the code coverage report to gl-code-quality-report.json
# and print linting issues to stdout in the format: path/to/file:line description
# remove `--issues-exit-code 0` or set to non-zero to fail the job if linting issues are detected
- - golangci-lint run --issues-exit-code 0 --out-format code-climate | tee gl-code-quality-report.json | jq -r '.[] | "\(.location.path):\(.location.lines.begin) \(.description)"'
+ - golangci-lint run --issues-exit-code 0 --print-issued-lines=false --out-format code-climate:gl-code-quality-report.json,line-number
artifacts:
reports:
codequality: gl-code-quality-report.json
@@ -216,7 +216,7 @@ When comparing expected and actual values in tests, use
and others to improve readability when comparing structs, errors,
large portions of text, or JSON documents:
-```golang
+```go
type TestData struct {
// ...
}
@@ -291,7 +291,7 @@ easier to debug.
For example:
-```golang
+```go
// Wrap the error
return nil, fmt.Errorf("get cache %s: %w", f.Name, err)
@@ -462,7 +462,7 @@ allocations.
**Don't:**
-```golang
+```go
var s2 []string
for _, val := range s1 {
s2 = append(s2, val)
@@ -471,8 +471,8 @@ for _, val := range s1 {
**Do:**
-```golang
-s2 := make([]string, 0, size)
+```go
+s2 := make([]string, 0, len(s1))
for _, val := range s1 {
s2 = append(s2, val)
}
@@ -494,7 +494,7 @@ If the scanner report is small, less than 35 lines, then feel free to [inline th
The [go-cmp](https://github.com/google/go-cmp) package should be used when comparing large structs in tests. It makes it possible to output a specific diff where the two structs differ, rather than seeing the whole of both structs printed out in the test logs. Here is a small example:
-```golang
+```go
package main
import (
diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md
index cc7232cd793..1957662317a 100644
--- a/doc/development/i18n/proofreader.md
+++ b/doc/development/i18n/proofreader.md
@@ -103,7 +103,7 @@ are very appreciative of the work done by translators and proofreaders!
- Portuguese
- Diogo Trindade - [GitLab](https://gitlab.com/luisdiogo2071317), [Crowdin](https://crowdin.com/profile/ldiogotrindade)
- Portuguese, Brazilian
- - Paulo George Gomes Bezerra - [GitLab](https://gitlab.com/paulobezerra), [Crowdin](https://crowdin.com/profile/paulogomes.rep)
+ - Paulo George Gomes Bezerra - [GitLab](https://gitlab.com/paulobezerra)
- André Gama - [GitLab](https://gitlab.com/andregamma), [Crowdin](https://crowdin.com/profile/ToeOficial)
- Eduardo Addad de Oliveira - [GitLab](https://gitlab.com/eduardoaddad), [Crowdin](https://crowdin.com/profile/eduardoaddad)
- Horberlan Brito - [GitLab](https://gitlab.com/horberlan), [Crowdin](https://crowdin.com/profile/horberlan)
diff --git a/doc/development/image_scaling.md b/doc/development/image_scaling.md
index d182bd8333e..48b780b50bf 100644
--- a/doc/development/image_scaling.md
+++ b/doc/development/image_scaling.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
diff --git a/doc/development/img/feature-flag-metrics.png b/doc/development/img/feature-flag-metrics.png
index ce8702d47eb..f94c0fc3e46 100644
--- a/doc/development/img/feature-flag-metrics.png
+++ b/doc/development/img/feature-flag-metrics.png
Binary files differ
diff --git a/doc/development/import_project.md b/doc/development/import_project.md
index 7f5a0faf8fb..ed5854f8833 100644
--- a/doc/development/import_project.md
+++ b/doc/development/import_project.md
@@ -4,28 +4,29 @@ 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
---
-# Test Import Project
+# Test import project
For testing, we can import our own [GitLab CE](https://gitlab.com/gitlab-org/gitlab-foss/) project (named `gitlabhq` in this case) under a group named `qa-perf-testing`. Project tarballs that can be used for testing can be found over on the [performance-data](https://gitlab.com/gitlab-org/quality/performance-data) project. A different project could be used if required.
-There are several options for importing the project into your GitLab environment. They are detailed as follows with the assumption that the recommended group `qa-perf-testing` and project `gitlabhq` are being set up.
+You can import the project into your GitLab environment in a number of ways. They are detailed as follows with the
+assumption that the recommended group `qa-perf-testing` and project `gitlabhq` are being set up.
## Importing the project
-There are several ways to import a project.
+Use one of these methods to import the test project.
-### Importing via UI
+### Import by using the UI
-The first option is to [import the Project tarball file via the GitLab UI](../user/project/settings/import_export.md#import-a-project-and-its-data):
+The first option is to [import the project tarball file by using the GitLab UI](../user/project/settings/import_export.md#import-a-project-and-its-data):
-1. Create the group `qa-perf-testing`
-1. Import the [GitLab FOSS project tarball](https://gitlab.com/gitlab-org/quality/performance-data/-/blob/master/projects_export/gitlabhq_export.tar.gz) into the Group.
+1. Create the group `qa-perf-testing`.
+1. Import the [GitLab FOSS project tarball](https://gitlab.com/gitlab-org/quality/performance-data/-/blob/master/projects_export/gitlabhq_export.tar.gz) into the group.
It should take up to 15 minutes for the project to fully import. You can head to the project's main page for the current status.
This method ignores all the errors silently (including the ones related to `GITALY_DISABLE_REQUEST_LIMITS`) and is used by GitLab users. For development and testing, check the other methods below.
-### Importing via the `import-project` script
+### Import by using the `import-project` script
A convenient script, [`bin/import-project`](https://gitlab.com/gitlab-org/quality/performance/blob/master/bin/import-project), is provided with [performance](https://gitlab.com/gitlab-org/quality/performance) project to import the Project tarball into a GitLab environment via API from the terminal.
@@ -42,7 +43,7 @@ bin/import-project --help
The process should take up to 15 minutes for the project to import fully. The script checks the status periodically and exits after the import has completed.
-### Importing via GitHub
+### Import by using GitHub
There is also an option to [import the project via GitHub](../user/project/import/github.md):
@@ -51,126 +52,12 @@ There is also an option to [import the project via GitHub](../user/project/impor
This method takes longer to import than the other methods and depends on several factors. It's recommended to use the other methods.
-### Importing via a Rake task
-
-> The [Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/tasks/gitlab/import_export/import.rake) was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20724) in GitLab 12.6, replacing a GitLab.com Ruby script.
-
-This script was introduced in GitLab 12.6 for importing large GitLab project exports.
-
-As part of this script we also disable direct upload to avoid situations where a huge archive is being uploaded to GCS (while being inside a transaction, which can cause idle transaction timeouts).
-
-We can run this script from the terminal:
-
-Parameters:
-
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `username` | string | yes | User name |
-| `namespace_path` | string | yes | Namespace path |
-| `project_path` | string | yes | Project name |
-| `archive_path` | string | yes | Path to the exported project tarball you want to import |
-
-```shell
-bundle exec rake "gitlab:import_export:import[root, group/subgroup, testingprojectimport, /path/to/file.tar.gz]"
-```
-
-If you're running Omnibus, run the following Rake task:
-
-```shell
-gitlab-rake "gitlab:import_export:import[root, group/subgroup, testingprojectimport, /path/to/file.tar.gz]"
-```
-
-#### Enable verbose output
-
-To make the import Rake task more verbose, use the `IMPORT_DEBUG` environment variable:
-
-```shell
-IMPORT_DEBUG=true gitlab-rake "gitlab:import_export:import[root, group/subgroup, testingprojectimport, /path/to/file.tar.gz]"
-```
-
-#### Troubleshooting
-
-Check the common errors listed below, what they mean, and how to fix them.
-
-##### `Exception: undefined method 'name' for nil:NilClass`
-
-The `username` is not valid.
-
-##### `Exception: undefined method 'full_path' for nil:NilClass`
-
-The `namespace_path` does not exist.
-For example, one of the groups or subgroups is mistyped or missing
-or you've specified the project name in the path.
-
-The task only creates the project.
-If you want to import it to a new group or subgroup then create it first.
-
-##### `Exception: No such file or directory @ rb_sysopen - (filename)`
-
-The specified project export file in `archive_path` is missing.
-
-##### `Exception: Permission denied @ rb_sysopen - (filename)`
-
-The specified project export file cannot be accessed by the `git` user.
-
-Setting the file owner to `git:git`, changing the file permissions to `0400`, and moving it to a
-public folder (for example `/tmp/`) fixes the issue.
-
-##### `Name can contain only letters, digits, emojis ...`
-
-```plaintext
-Name can contain only letters, digits, emojis, '_', '.', '+', dashes, or spaces. It must start with a letter,
-digit, emoji, or '_', and Path can contain only letters, digits, '_', '-', or '.'. It cannot start
-with '-', end in '.git', or end in '.atom'.
-```
-
-The project name specified in `project_path` is not valid for one of the specified reasons.
-
-Only put the project name in `project_path`. For example, if you provide a path of subgroups
-it fails with this error as `/` is not a valid character in a project name.
-
-##### `Name has already been taken and Path has already been taken`
-
-A project with that name already exists.
-
-##### `Exception: Error importing repository into (namespace) - No space left on device`
-
-The disk has insufficient space to complete the import.
-
-During import, the tarball is cached in your configured `shared_path` directory. Verify the
-disk has enough free space to accommodate both the cached tarball and the unpacked
-project files on disk.
-
-##### Import is successful, but with a `Total number of not imported relations: XX` message, and issues are not created during the import
-
-If you receive a `Total number of not imported relations: XX` message, and issues
-aren't created during the import, check [exceptions_json.log](../administration/logs/index.md#exceptions_jsonlog).
-You might see an error like `N is out of range for ActiveModel::Type::Integer with limit 4 bytes`,
-where `N` is the integer exceeding the 4-byte integer limit. If that's the case, you
-are likely hitting the issue with rebalancing of `relative_position` field of the issues.
-
-```ruby
-# Check the current maximum value of relative_position
-Issue.where(project_id: Project.find(ID).root_namespace.all_projects).maximum(:relative_position)
-
-# Run the rebalancing process and check if the maximum value of relative_position has changed
-Issues::RelativePositionRebalancingService.new(Project.find(ID).root_namespace.all_projects).execute
-Issue.where(project_id: Project.find(ID).root_namespace.all_projects).maximum(:relative_position)
-```
-
-Repeat the import attempt after that and check if the issues are imported successfully.
-
-##### Gitaly calls error when importing
-
-If you're attempting to import a large project into a development environment, you may see Gitaly throw an error about too many calls or invocations, for example:
-
-```plaintext
-Error importing repository into qa-perf-testing/gitlabhq - GitalyClient#call called 31 times from single request. Potential n+1?
-```
+### Import by using a Rake task
-This is due to a [n+1 calls limit being set for development setups](gitaly.md#toomanyinvocationserror-errors). You can work around this by setting `GITALY_DISABLE_REQUEST_LIMITS=1` as an environment variable, restarting your development environment and importing again.
+To import the test project by using a Rake task, see
+[Import large projects](../administration/raketasks/project_import_export.md#import-large-projects).
-### Importing via the Rails console
+### Import by using the Rails console
The last option is to import a project using a Rails console:
@@ -245,8 +132,9 @@ bundle exec rails r /path_to_script/script.rb project_name /path_to_extracted_p
## Access token setup
-Many of the tests also require a GitLab Personal Access Token. This is due to numerous endpoints themselves requiring authentication.
+Many of the tests also require a GitLab personal access token because numerous endpoints require authentication themselves.
-[The official GitLab docs detail how to create this token](../user/profile/personal_access_tokens.md#create-a-personal-access-token). The tests require that the token is generated by an administrator and that it has the `API` and `read_repository` permissions.
+[The GitLab documentation details how to create this token](../user/profile/personal_access_tokens.md#create-a-personal-access-token).
+The tests require that the token is generated by an administrator and that it has the `API` and `read_repository` permissions.
Details on how to use the Access Token with each type of test are found in their respective documentation.
diff --git a/doc/development/integrations/codesandbox.md b/doc/development/integrations/codesandbox.md
deleted file mode 100644
index 4553ed2966f..00000000000
--- a/doc/development/integrations/codesandbox.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-stage: none
-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
-remove_date: '2023-02-01'
----
-
-# Set up local CodeSandbox development environment (removed)
-
-WARNING:
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108627) in GitLab 15.8
-and is planned for removal in 15.9. This change is a breaking change.
-
-This guide walks through setting up a local [CodeSandbox repository](https://github.com/codesandbox/codesandbox-client) and integrating it with a local GitLab instance. CodeSandbox
-is used to power the Web IDE [Live Preview feature](../../user/project/web_ide/index.md#live-preview-removed). Having a local CodeSandbox setup is useful for debugging upstream issues or
-creating upstream contributions like [this one](https://github.com/codesandbox/codesandbox-client/pull/5137).
-
-## Initial setup
-
-Before using CodeSandbox with your local GitLab instance, you must:
-
-1. Enable HTTPS on your GDK. CodeSandbox uses Service Workers that require `https`.
- Follow the GDK [NGINX configuration instructions](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/nginx.md) to enable HTTPS for GDK.
-1. Clone the [`codesandbox-client` project](https://github.com/codesandbox/codesandbox-client)
- locally. If you plan on contributing upstream, you might want to fork and clone first.
-1. Optional. Use correct `python` and `nodejs` versions. Otherwise, `yarn` may fail to
- install or build some packages. If you're using `asdf` you can run the following commands:
-
- ```shell
- asdf local nodejs 10.14.2
- asdf local python 2.7.18
- ```
-
-1. Run the following commands in the `codesandbox-client` project checkout:
-
- ```shell
- # This might be necessary for the `prepublishOnly` job that is run later
- yarn global add lerna
-
- # Install packages
- yarn
- ```
-
- You can run `yarn build:clean` to clean up the build assets.
-
-## Use local GitLab instance with local CodeSandbox
-
-GitLab integrates with two parts of CodeSandbox:
-
-- An npm package called `smooshpack` (called `sandpack` in the `codesandbox-client` project).
- This exposes an entrypoint for us to kick off CodeSandbox's bundler.
-- A server that houses CodeSandbox assets for bundling and previewing. This is hosted
- on a separate server for security.
-
-Each time you want to run GitLab and CodeSandbox together, you need to perform the
-steps in the following sections.
-
-### Use local `smooshpack` for GitLab
-
-GitLab usually satisfies its `smooshpack` dependency with a remote module, but we want
-to use a locally-built module. To build and use a local `smooshpack` module:
-
-1. In the `codesandbox-client` project directory, run:
-
- ```shell
- cd standalone-packages/sandpack
- yarn link
-
- # (Optional) you might want to start a development build
- yarn run start
- ```
-
- Now, in the GitLab project, you can run `yarn link "smooshpack"`. `yarn` looks
- for `smooshpack` **on disk** as opposed to the one hosted remotely.
-
-1. In the `gitlab` project directory, run:
-
- ```shell
- # Remove and reinstall node_modules just to be safe
- rm -rf node_modules
- yarn install
-
- # Use the "smooshpack" package on disk
- yarn link "smooshpack"
- ```
-
-### Fix possible GDK webpack problem
-
-`webpack` in GDK can fail to find packages inside a linked package. This step can help
-you avoid `webpack` breaking with messages saying that it can't resolve packages from
-`smooshpack/dist/sandpack.es5.js`.
-
-In the `codesandbox-client` project directory, run:
-
-```shell
-cd standalone-packages
-
-mkdir node_modules
-ln -s $PATH_TO_LOCAL_GITLAB/node_modules/core-js ./node_modules/core-js
-```
-
-### Start building CodeSandbox app assets
-
-In the `codesandbox-client` project directory:
-
-```shell
-cd packages/app
-
-yarn start:sandpack-sandbox
-```
-
-### Create HTTPS proxy for CodeSandbox `sandpack` assets
-
-Because we need `https`, we need to create a proxy to the webpack server. We can use
-[`http-server`](https://www.npmjs.com/package/http-server), which can do this proxying
-out of the box:
-
-```shell
-npx http-server --proxy http://localhost:3000 -S -C $PATH_TO_CERT_PEM -K $PATH_TO_KEY_PEM -p 8044 -d false
-```
-
-### Update `bundler_url` setting in GitLab (removed)
-
-WARNING:
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108627) in GitLab 15.8
-and is planned for removal in 15.9. This change is a breaking change.
-
-We need to update our `application_setting_implementation.rb` to point to the server that hosts the
-CodeSandbox `sandpack` assets. For instance, if these assets are hosted by a server at `https://sandpack.local:8044`:
-
-```patch
-diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
-index 6eed627b502..1824669e881 100644
---- a/app/models/application_setting_implementation.rb
-+++ b/app/models/application_setting_implementation.rb
-@@ -391,7 +391,7 @@ def static_objects_external_storage_enabled?
- # This will eventually be configurable
- # https://gitlab.com/gitlab-org/gitlab/-/issues/208161
- def web_ide_clientside_preview_bundler_url
-- 'https://sandbox-prod.gitlab-static.net'
-+ 'https://sandpack.local:8044'
- end
-
- private
-
-```
-
-NOTE:
-You can apply this patch by copying it to your clipboard and running `pbpaste | git apply`.
-
-You may want to restart the GitLab Rails server after making this change:
-
-```shell
-gdk restart rails-web
-```
diff --git a/doc/development/integrations/index.md b/doc/development/integrations/index.md
index ceb64ba2bb7..6f42cb4d4fe 100644
--- a/doc/development/integrations/index.md
+++ b/doc/development/integrations/index.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
description: "GitLab's development guidelines for Integrations"
---
-# Integrations development guide
+# Integrations development guidelines
This page provides development guidelines for implementing [GitLab integrations](../../user/project/integrations/index.md),
which are part of our [main Rails project](https://gitlab.com/gitlab-org/gitlab).
@@ -315,7 +315,7 @@ When developing a new integration, we also recommend you gate the availability b
You can provide help text in the integration form, including links to off-site documentation,
as described above in [Customize the frontend form](#customize-the-frontend-form). Refer to
-our [usability guidelines](https://design.gitlab.com/usability/helping-users/) for help text.
+our [usability guidelines](https://design.gitlab.com/usability/contextual-help) for help text.
For more detailed documentation, provide a page in `doc/user/project/integrations`,
and link it from the [Integrations overview](../../user/project/integrations/index.md).
diff --git a/doc/development/integrations/jenkins.md b/doc/development/integrations/jenkins.md
index 6baccdca327..8b05cc3168e 100644
--- a/doc/development/integrations/jenkins.md
+++ b/doc/development/integrations/jenkins.md
@@ -26,9 +26,9 @@ GitLab does not allow requests to localhost or the local network by default. Whe
1. Log into your GitLab instance as an administrator.
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > Network**.
-1. Expand **Outbound requests** and check the following checkboxes:
+1. Expand **Outbound requests**, and select the following checkboxes:
- - **Allow requests to the local network from web hooks and services**
+ - **Allow requests to the local network from webhooks and integrations**
- **Allow requests to the local network from system hooks**
For more details about GitLab webhooks, see [Webhooks and insecure internal web services](../../security/webhooks.md).
diff --git a/doc/development/integrations/jira_connect.md b/doc/development/integrations/jira_connect.md
index eca4d9775c5..4789280c09d 100644
--- a/doc/development/integrations/jira_connect.md
+++ b/doc/development/integrations/jira_connect.md
@@ -4,7 +4,7 @@ group: Integrations
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Set up a development environment
+# Set up a Jira development environment
The following are required to install and test the app:
@@ -101,23 +101,23 @@ The following steps describe setting up an environment to test the GitLab OAuth
1. Start a Gitpod session and open the rails console.
- ```shell
- bundle exec rails console
- ```
+ ```shell
+ bundle exec rails console
+ ```
1. Enable the feature flag.
- ```shell
- Feature.enable(:jira_connect_oauth)
- ```
+ ```shell
+ Feature.enable(:jira_connect_oauth)
+ ```
1. On your GitLab instance, go to **Admin > Applications**.
1. Create a new application with the following settings:
- - Name: `Jira Connect`
- - Redirect URI: `YOUR_GITPOD_INSTANCE/-/jira_connect/oauth_callbacks`
- - Scopes: `api`
- - Trusted: **No**
- - Confidential: **No**
+ - Name: `Jira Connect`
+ - Redirect URI: `YOUR_GITPOD_INSTANCE/-/jira_connect/oauth_callbacks`
+ - Scopes: `api`
+ - Trusted: **No**
+ - Confidential: **No**
1. Copy the Application ID.
1. Go to **Admin > Settings > General**.
1. Scroll down and expand the GitLab for Jira App section.
diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md
index 002579d9b83..bc0a490f555 100644
--- a/doc/development/integrations/secure.md
+++ b/doc/development/integrations/secure.md
@@ -234,22 +234,13 @@ then `artifacts:reports:dependency_scanning` must be set to `depscan.json`.
### Exit code
-Following the POSIX exit code standard, the scanner exits with 0 for success and any number from 1 to 255 for anything else.
+Following the POSIX exit code standard, the scanner exits with either `0` for success or `1` for failure.
Success also includes the case when vulnerabilities are found.
When a CI job fails, security report results are not ingested by GitLab, even if the job
-[allows failure](../../ci/yaml/index.md#allow_failure). The report artifacts are still uploaded to GitLab and available
+[allows failure](../../ci/yaml/index.md#allow_failure). However, the report artifacts are still uploaded to GitLab and available
for [download in the pipeline security tab](../../user/application_security/vulnerability_report/pipeline.md#download-security-scan-outputs).
-When executing a scanning job using the [Docker-in-Docker privileged mode](../../user/application_security/sast/index.md#requirements),
-we reserve the following standard exit codes.
-
-| Orchestrator Exit Code | Description |
-|------------------------|----------------------------------|
-| 3 | No match, no compatible analyzer |
-| 4 | Project directory empty |
-| 5 | No compatible Docker image |
-
### Logging
The scanner should log error messages and warnings so that users can easily investigate
@@ -412,8 +403,6 @@ The `id` should not collide with any other analyzers or scanners another integra
##### Scan Primary Identifiers
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368284) in GitLab 15.4 [with a flag](../../administration/feature_flags.md) named `sec_mark_dropped_findings_as_resolved`. Disabled by default.
-
The `scan.primary_identifiers` field is an optional field containing an array of
[primary identifiers](../../user/application_security/terminology/index.md#primary-identifier)).
This is an exhaustive list of all rulesets for which the analyzer performed the scan.
@@ -422,7 +411,7 @@ Even when the [`Vulnerabilities`](#vulnerabilities) array for a given scan may b
should contain the complete list of potential identifiers to inform the Rails application of which
rules were executed.
-When populated, the Rails application automatically resolves previously detected vulnerabilities as no
+When populated, the Rails application [may automatically resolve previously detected vulnerabilities](../../user/application_security/iac_scanning/index.md#automatic-vulnerability-resolution) as no
longer relevant when their primary identifier is not included.
##### Name, message, and description
diff --git a/doc/development/internal_api/index.md b/doc/development/internal_api/index.md
index b19e431ebc6..aa10bbeda9c 100644
--- a/doc/development/internal_api/index.md
+++ b/doc/development/internal_api/index.md
@@ -37,13 +37,11 @@ is stored in a file at the path configured in `config/gitlab.yml` by
default this is in the root of the rails app named
`.gitlab_shell_secret`
-To authenticate using that token, clients read the contents of that
-file, and include the token Base64 encoded in a `secret_token` parameter
-or in the `Gitlab-Shared-Secret` header.
+To authenticate using that token, clients:
-NOTE:
-The internal API used by GitLab Pages, and GitLab agent server (`kas`) uses JSON Web Token (JWT)
-authentication, which is different from GitLab Shell.
+1. Read the contents of that file.
+1. Use the file contents to generate a JSON Web Token (`JWT`).
+1. Pass the JWT in the `Gitlab-Shell-Api-Request` header.
## Git Authentication
@@ -78,7 +76,7 @@ POST /internal/allowed
Example request:
```shell
-curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded token>" \
+curl --request POST --header "Gitlab-Shell-Api-Request: <JWT token>" \
--data "key_id=11&project=gnuwget/wget2&action=git-upload-pack&protocol=ssh" \
"http://localhost:3001/api/v4/internal/allowed"
```
@@ -128,7 +126,7 @@ information for LFS clients when the repository is accessed over SSH.
Example request:
```shell
-curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded token>" \
+curl --request POST --header "Gitlab-Shell-Api-Request: <JWT token>" \
--data "key_id=11&project=gnuwget/wget2" "http://localhost:3001/api/v4/internal/lfs_authenticate"
```
@@ -148,12 +146,12 @@ curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded token>" \
## Authorized Keys Check
This endpoint is called by the GitLab Shell authorized keys
-check. Which is called by OpenSSH for
+check. Which is called by OpenSSH or GitLab SSHD for
[fast SSH key lookup](../../administration/operations/fast_ssh_key_lookup.md).
| Attribute | Type | Required | Description |
|:----------|:-------|:---------|:------------|
-| `key` | string | yes | SSH key as passed by OpenSSH to GitLab Shell |
+| `key` | string | yes | An authorized key used for public key authentication. |
```plaintext
GET /internal/authorized_keys
@@ -162,7 +160,7 @@ GET /internal/authorized_keys
Example request:
```shell
-curl --request GET --header "Gitlab-Shared-Secret: <Base64 encoded secret>" "http://localhost:3001/api/v4/internal/authorized_keys?key=<key as passed by OpenSSH>"
+curl --request GET --header "Gitlab-Shell-Api-Request: <JWT token>" "http://localhost:3001/api/v4/internal/authorized_keys?key=<key>"
```
Example response:
@@ -197,7 +195,7 @@ GET /internal/discover
Example request:
```shell
-curl --request GET --header "Gitlab-Shared-Secret: <Base64 encoded secret>" "http://localhost:3001/api/v4/internal/discover?key_id=7"
+curl --request GET --header "Gitlab-Shell-Api-Request: <JWT token>" "http://localhost:3001/api/v4/internal/discover?key_id=7"
```
Example response:
@@ -226,7 +224,7 @@ GET /internal/check
Example request:
```shell
-curl --request GET --header "Gitlab-Shared-Secret: <Base64 encoded secret>" "http://localhost:3001/api/v4/internal/check"
+curl --request GET --header "Gitlab-Shell-Api-Request: <JWT token>" "http://localhost:3001/api/v4/internal/check"
```
Example response:
@@ -263,7 +261,7 @@ GET /internal/two_factor_recovery_codes
Example request:
```shell
-curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded secret>" \
+curl --request POST --header "Gitlab-Shell-Api-Request: <JWT token>" \
--data "key_id=7" "http://localhost:3001/api/v4/internal/two_factor_recovery_codes"
```
@@ -311,7 +309,7 @@ POST /internal/personal_access_token
Example request:
```shell
-curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded secret>" \
+curl --request POST --header "Gitlab-Shell-Api-Request: <JWT token>" \
--data "user_id=29&name=mytokenname&scopes[]=read_user&scopes[]=read_repository&expires_at=2020-07-24" \
"http://localhost:3001/api/v4/internal/personal_access_token"
```
@@ -348,7 +346,7 @@ POST /internal/error_tracking/allowed
Example request:
```shell
-curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded secret>" \
+curl --request POST --header "Gitlab-Shell-Api-Request: <JWT token>" \
--data "project_id=111&public_key=generated-error-tracking-key" \
"http://localhost:3001/api/v4/internal/error_tracking/allowed"
```
@@ -379,7 +377,7 @@ POST /internal/pre_receive
Example request:
```shell
-curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded secret>" \
+curl --request POST --header "Gitlab-Shell-Api-Request: <JWT token>" \
--data "gl_repository=project-7" "http://localhost:3001/api/v4/internal/pre_receive"
```
@@ -412,7 +410,7 @@ POST /internal/post_receive
Example Request:
```shell
-curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded secret>" \
+curl --request POST --header "Gitlab-Shell-Api-Request: <JWT token>" \
--data "gl_repository=project-7" --data "identifier=user-1" \
--data "changes=0000000000000000000000000000000000000000 fd9e76b9136bdd9fe217061b497745792fe5a5ee gh-pages\n" \
"http://localhost:3001/api/v4/internal/post_receive"
diff --git a/doc/development/issue_types.md b/doc/development/issue_types.md
index 465f539e026..d0d513af781 100644
--- a/doc/development/issue_types.md
+++ b/doc/development/issue_types.md
@@ -4,7 +4,7 @@ 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
---
-# Issue Types (DEPRECATED)
+# Issue Types (deprecated)
WARNING:
We are deprecating Issue Types as of GitLab 14.2 in favor of [Work Items and Work Item Types](work_items.md).
diff --git a/doc/development/json.md b/doc/development/json.md
index 8a2575401fb..bdb7f73ab62 100644
--- a/doc/development/json.md
+++ b/doc/development/json.md
@@ -4,7 +4,7 @@ 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
---
-# JSON Guidelines
+# JSON development guidelines
At GitLab we handle a lot of JSON data. To best ensure we remain performant
when handling large JSON encodes or decodes, we use our own JSON class
diff --git a/doc/development/kubernetes.md b/doc/development/kubernetes.md
index e44e2af4371..99737e71b22 100644
--- a/doc/development/kubernetes.md
+++ b/doc/development/kubernetes.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Kubernetes integration - development guidelines
+# Kubernetes integration development guidelines
This document provides various guidelines when developing for the GitLab
[Kubernetes integration](../user/infrastructure/clusters/index.md).
diff --git a/doc/development/labels/index.md b/doc/development/labels/index.md
new file mode 100644
index 00000000000..af4df4adee2
--- /dev/null
+++ b/doc/development/labels/index.md
@@ -0,0 +1,348 @@
+---
+stage: none
+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
+---
+
+# Labels
+
+To allow for asynchronous issue handling, we use [milestones](https://gitlab.com/groups/gitlab-org/-/milestones)
+and [labels](https://gitlab.com/gitlab-org/gitlab/-/labels). Leads and product managers handle most of the
+scheduling into milestones. Labeling is a task for everyone. (For some projects, labels can be set only by GitLab team members and not by community contributors).
+
+Most issues will have labels for at least one of the following:
+
+- Type. For example: `~"type::feature"`, `~"type::bug"`, or `~"type::maintenance"`.
+- Stage. For example: `~"devops::plan"` or `~"devops::create"`.
+- Group. For example: `~"group::source code"`, `~"group::knowledge"`, or `~"group::editor"`.
+- Category. For example: `~"Category:Code Analytics"`, `~"Category:DevOps Reports"`, or `~"Category:Templates"`.
+- Feature. For example: `~wiki`, `~ldap`, `~api`, `~issues`, or `~"merge requests"`.
+- Department: `~UX`, `~Quality`
+- Team: `~"Technical Writing"`, `~Delivery`
+- Specialization: `~frontend`, `~backend`, `~documentation`
+- Release Scoping: `~Deliverable`, `~Stretch`, `~"Next Patch Release"`
+- Priority: `~"priority::1"`, `~"priority::2"`, `~"priority::3"`, `~"priority::4"`
+- Severity: `~"severity::1"`, `~"severity::2"`, `~"severity::3"`, `~"severity::4"`
+
+Please add `~"breaking change"` label if the issue can be considered as a [breaking change](../deprecation_guidelines/index.md).
+
+Please add `~security` label if the issue is related to application security.
+
+All labels, their meaning and priority are defined on the
+[labels page](https://gitlab.com/gitlab-org/gitlab/-/labels).
+
+If you come across an issue that has none of these, and you're allowed to set
+labels, you can _always_ add the type, stage, group, and often the category/feature labels.
+
+## Type labels
+
+Type labels are very important. They define what kind of issue this is. Every
+issue should have one and only one.
+
+The SSOT for type and subtype labels is [available in the handbook](https://about.gitlab.com/handbook/engineering/metrics/#work-type-classification).
+
+A number of type labels have a priority assigned to them, which automatically
+makes them float to the top, depending on their importance.
+
+Type labels are always lowercase, and can have any color, besides blue (which is
+already reserved for category labels).
+
+The descriptions on the [labels page](https://gitlab.com/groups/gitlab-org/-/labels)
+explain what falls under each type label.
+
+The GitLab handbook documents [when something is a bug](https://about.gitlab.com/handbook/product/product-processes/#bug-issues) and [when it is a feature request](https://about.gitlab.com/handbook/product/product-processes/#feature-issues).
+
+## Stage labels
+
+Stage labels specify which [stage](https://about.gitlab.com/handbook/product/categories/#hierarchy) the issue belongs to.
+
+### Naming and color convention
+
+Stage labels respects the `devops::<stage_key>` naming convention.
+`<stage_key>` is the stage key as it is in the single source of truth for stages at
+<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml>
+with `_` replaced with a space.
+
+For instance, the "Manage" stage is represented by the `~"devops::manage"` label in
+the `gitlab-org` group since its key under `stages` is `manage`.
+
+The current stage labels can be found by [searching the labels list for `devops::`](https://gitlab.com/groups/gitlab-org/-/labels?search=devops::).
+
+These labels are [scoped labels](../../user/project/labels.md#scoped-labels)
+and thus are mutually exclusive.
+
+The Stage labels are used to generate the [direction pages](https://about.gitlab.com/direction/) automatically.
+
+## Group labels
+
+Group labels specify which [groups](https://about.gitlab.com/company/team/structure/#product-groups) the issue belongs to.
+
+It's highly recommended to add a group label, as it's used by our triage
+automation to
+[infer the correct stage label](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues-and-merge-requests).
+
+### Naming and color convention
+
+Group labels respects the `group::<group_key>` naming convention and
+their color is `#A8D695`.
+`<group_key>` is the group key as it is in the single source of truth for groups at
+<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml>,
+with `_` replaced with a space.
+
+For instance, the "Pipeline Execution" group is represented by the
+`~"group::pipeline execution"` label in the `gitlab-org` group since its key
+under `stages.manage.groups` is `pipeline_execution`.
+
+The current group labels can be found by [searching the labels list for `group::`](https://gitlab.com/groups/gitlab-org/-/labels?search=group::).
+
+These labels are [scoped labels](../../user/project/labels.md#scoped-labels)
+and thus are mutually exclusive.
+
+You can find the groups listed in the [Product Stages, Groups, and Categories](https://about.gitlab.com/handbook/product/categories/) page.
+
+We use the term group to map down product requirements from our product stages.
+As a team needs some way to collect the work their members are planning to be assigned to, we use the `~group::` labels to do so.
+
+## Category labels
+
+From the handbook's
+[Product stages, groups, and categories](https://about.gitlab.com/handbook/product/categories/#hierarchy)
+page:
+
+> Categories are high-level capabilities that may be a standalone product at
+another company, such as Portfolio Management, for example.
+
+It's highly recommended to add a category label, as it's used by our triage
+automation to
+[infer the correct group and stage labels](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues).
+
+If you are an expert in a particular area, it makes it easier to find issues to
+work on. You can also subscribe to those labels to receive an email each time an
+issue is labeled with a category label corresponding to your expertise.
+
+### Naming and color convention
+
+Category labels respects the `Category:<Category Name>` naming convention and
+their color is `#428BCA`.
+`<Category Name>` is the category name as it is in the single source of truth for categories at
+<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml>.
+
+For instance, the "DevOps Reports" category is represented by the
+`~"Category:DevOps Reports"` label in the `gitlab-org` group since its
+`devops_reports.name` value is "DevOps Reports".
+
+If a category's label doesn't respect this naming convention, it should be specified
+with [the `label` attribute](https://about.gitlab.com/handbook/marketing/digital-experience/website/#category-attributes)
+in <https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml>.
+
+## Feature labels
+
+From the handbook's
+[Product stages, groups, and categories](https://about.gitlab.com/handbook/product/categories/#hierarchy)
+page:
+
+> Features: Small, discrete functionalities, for example Issue weights. Some common
+features are listed within parentheses to facilitate finding responsible PMs by keyword.
+
+It's highly recommended to add a feature label if no category label applies, as
+it's used by our triage automation to
+[infer the correct group and stage labels](https://about.gitlab.com/handbook/engineering/quality/triage-operations/#auto-labelling-of-issues).
+
+If you are an expert in a particular area, it makes it easier to find issues to
+work on. You can also subscribe to those labels to receive an email each time an
+issue is labeled with a feature label corresponding to your expertise.
+
+Examples of feature labels are `~wiki`, `~ldap`, `~api`, `~issues`, and `~"merge requests"`.
+
+### Naming and color convention
+
+Feature labels are all-lowercase.
+
+## Workflow labels
+
+Issues use the following workflow labels to specify the current issue status:
+
+- `~"workflow::awaiting security release"`
+- `~"workflow::blocked"`
+- `~"workflow::complete"`
+- `~"workflow::design"`
+- `~"workflow::feature-flagged"`
+- `~"workflow::in dev"`
+- `~"workflow::in review"`
+- `~"workflow::planning breakdown"`
+- `~"workflow::problem validation"`
+- `~"workflow::production"`
+- `~"workflow::ready for design"`
+- `~"workflow::ready for development"`
+- `~"workflow::refinement"`
+- `~"workflow::scheduling"`
+- `~"workflow::solution validation"`
+- `~"workflow::start"`
+- `~"workflow::validation backlog"`
+- `~"workflow::verification"`
+
+## Facet labels
+
+To track additional information or context about created issues, developers may
+add _facet labels_. Facet labels are also sometimes used for issue prioritization
+or for measurements (such as time to close). An example of a facet label is the
+`~"customer"` label, which indicates customer interest.
+
+## Department labels
+
+The current department labels are:
+
+- `~"UX"`
+- `~"Quality"`
+
+## Team labels
+
+**Important**: Most of the historical team labels (like Manage or Plan) are
+now deprecated in favor of [Group labels](#group-labels) and [Stage labels](#stage-labels).
+
+Team labels specify what team is responsible for this issue.
+Assigning a team label makes sure issues get the attention of the appropriate
+people.
+
+The current team labels are:
+
+- `~"Delivery"~`
+- `~"Technical Writing"`
+
+### Naming and color convention
+
+Team labels are always capitalized so that they show up as the first label for
+any issue.
+
+## Specialization labels
+
+These labels narrow the [specialization](https://about.gitlab.com/company/team/structure/#specialist) on a unit of work.
+
+- `~"frontend"`
+- `~"backend"`
+- `~"documentation"`
+
+## Release scoping labels
+
+Release Scoping labels help us clearly communicate expectations of the work for the
+release. There are three levels of Release Scoping labels:
+
+- `~"Deliverable"`: Issues that are expected to be delivered in the current
+ milestone.
+- `~"Stretch"`: Issues that are a stretch goal for delivering in the current
+ milestone. If these issues are not done in the current release, they will
+ strongly be considered for the next release.
+- `~"Next Patch Release"`: Issues to put in the next patch release. Work on these
+ first, and add the `~"Pick into X.Y"` label to the merge request, along with the
+ appropriate milestone.
+
+Each issue scheduled for the current milestone should be labeled `~"Deliverable"~`
+or `~"Stretch"`. Any open issue for a previous milestone should be labeled
+`~"Next Patch Release"`, or otherwise rescheduled to a different milestone.
+
+## Priority labels
+
+We have the following priority labels:
+
+- `~"priority::1"`
+- `~"priority::2"`
+- `~"priority::3"`
+- `~"priority::4"`
+
+Please refer to the issue triage [priority label](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#priority) section in our handbook to see how it's used.
+
+## Severity labels
+
+We have the following severity labels:
+
+- `~"severity::1"`
+- `~"severity::2"`
+- `~"severity::3"`
+- `~"severity::4"`
+
+Please refer to the issue triage [severity label](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#severity) section in our handbook to see how it's used.
+
+## Label for community contributors
+
+There are many issues that have a clear solution with uncontroversial benefit to GitLab users.
+However, GitLab might not have the capacity for all these proposals in the current roadmap.
+These issues are labeled `~"Seeking community contributions"` because we welcome merge requests to resolve them.
+
+Community contributors can submit merge requests for any issue they want, but
+the `~"Seeking community contributions"` label has a special meaning. It points to
+changes that:
+
+1. We already agreed on,
+1. Are well-defined,
+1. Are likely to get accepted by a maintainer.
+
+We want to avoid a situation when a contributor picks an
+~"Seeking community contributions" issue and then their merge request gets closed,
+because we realize that it does not fit our vision, or we want to solve it in a
+different way.
+
+We manually add the `~"Seeking community contributions"` label to issues
+that fit the criteria described above.
+We do not automatically add this label, because it requires human evaluation.
+
+We recommend people that have never contributed to any open source project to
+look for issues labeled `~"Seeking community contributions"` with a
+[weight of 1](https://gitlab.com/groups/gitlab-org/-/issues?sort=created_date&state=opened&label_name[]=Seeking+community+contributions&assignee_id=None&weight=1) or the `~"quick win"`
+[label](https://gitlab.com/gitlab-org/gitlab/-/issues?scope=all&state=opened&label_name[]=quick%20win&assignee_id=None)
+attached to it.
+More experienced contributors are very welcome to tackle
+[any of them](https://gitlab.com/groups/gitlab-org/-/issues?sort=created_date&state=opened&label_name[]=Seeking+community+contributions&assignee_id=None).
+
+For more complex features that have a weight of 2 or more and clear scope, we recommend looking at issues
+with the [label `~"Community Challenge"`](https://gitlab.com/gitlab-org/gitlab/-/issues?sort=created_date&state=opened&label_name[]=Seeking+community+contributions&label_name[]=Community+challenge).
+If your MR for the `~"Community Challenge"` issue gets merged, you will also have a chance to win a custom
+GitLab merchandise.
+
+If you've decided that you would like to work on an issue, please @-mention
+the [appropriate product manager](https://about.gitlab.com/handbook/product/#who-to-talk-to-for-what)
+as soon as possible. The product manager will then pull in appropriate GitLab team
+members to further discuss scope, design, and technical considerations. This will
+ensure that your contribution is aligned with the GitLab product and minimize
+any rework and delay in getting it merged into main.
+
+GitLab team members who apply the `~"Seeking community contributions"` label to an issue
+should update the issue description with a responsible product manager, inviting
+any potential community contributor to @-mention per above.
+
+## Stewardship label
+
+For issues related to the open source stewardship of GitLab,
+there is the `~"stewardship"` label.
+
+This label is to be used for issues in which the stewardship of GitLab
+is a topic of discussion. For instance if GitLab Inc. is planning to add
+features from GitLab EE to GitLab CE, related issues would be labeled with
+`~"stewardship"`.
+
+A recent example of this was the issue for
+[bringing the time tracking API to GitLab CE](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/25517#note_20019084).
+
+## Technical and UX debt
+
+In order to track things that can be improved in the GitLab codebase,
+we use the `~"technical debt"` label in the [GitLab issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues).
+We use the `~"UX debt"` label when we choose to deviate from the MVC, in a way that harms the user experience.
+
+These labels should be added to issues that describe things that can be improved,
+shortcuts that have been taken, features that need additional attention, and all
+other things that have been left behind due to high velocity of development.
+For example, code that needs refactoring should use the `~"technical debt"` label,
+something that didn't ship according to our Design System guidelines should
+use the `~"UX debt"` label.
+
+Everyone can create an issue, though you may need to ask for adding a specific
+label, if you do not have permissions to do it by yourself. Additional labels
+can be combined with these labels, to make it easier to schedule
+the improvements for a release.
+
+Issues tagged with these labels have the same priority like issues
+that describe a new feature to be introduced in GitLab, and should be scheduled
+for a release by the appropriate person.
+
+Make sure to mention the merge request that the `~"technical debt"` issue or
+`~"UX debt"` issue is associated with in the description of the issue.
diff --git a/doc/development/lfs.md b/doc/development/lfs.md
index ec91f9f3c8b..8f6d54e08e3 100644
--- a/doc/development/lfs.md
+++ b/doc/development/lfs.md
@@ -4,14 +4,14 @@ 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
---
-# Git LFS developer information
+# Git LFS development guidelines
This page contains developer-centric information for GitLab team members. For the
user documentation, see [Git Large File Storage](../topics/git/lfs/index.md).
## Deep Dive
-In April 2019, Francisco Javier López hosted a Deep Dive (GitLab team members only: `https://gitlab.com/gitlab-org/create-stage/issues/1`)
+In April 2019, Francisco Javier López hosted a Deep Dive (GitLab team members only: `https://gitlab.com/gitlab-org/create-stage/-/issues/1`)
on the GitLab [Git LFS](../topics/git/lfs/index.md) implementation to share domain-specific
knowledge with anyone who may work in this part of the codebase in the future.
You can find the <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [recording on YouTube](https://www.youtube.com/watch?v=Yyxwcksr0Qc),
diff --git a/doc/development/logging.md b/doc/development/logging.md
index 538fc7ccfe1..6840445a0a5 100644
--- a/doc/development/logging.md
+++ b/doc/development/logging.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
---
-# GitLab Developers Guide to Logging
+# Logging development guidelines
[GitLab Logs](../administration/logs/index.md) play a critical role for both
administrators and GitLab team members to diagnose problems in the field.
@@ -169,6 +169,28 @@ Resources:
- [Elasticsearch mapping - avoiding type gotchas](https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping.html#_avoiding_type_gotchas)
- [Elasticsearch mapping types]( https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html)
+#### Include a class attribute
+
+Structured logs should always include a `class` attribute to make all entries logged from a particular place in the code findable.
+To automatically add the `class` attribute, you can include the
+[`Gitlab::Loggable` module](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/loggable.rb) and use the `build_structured_payload` method.
+
+```ruby
+class MyClass
+ include ::Gitlab::Loggable
+
+ def my_method
+ logger.info(build_structured_payload(message: 'log message', project_id: project_id))
+ end
+
+ private
+
+ def logger
+ @logger ||= Gitlab::AppJsonLogger.build
+ end
+end
+```
+
#### Logging durations
Similar to timezones, choosing the right time unit to log can impose avoidable overhead. So, whenever
diff --git a/doc/development/merge_request_concepts/approval_rules.md b/doc/development/merge_request_concepts/approval_rules.md
index d119644cd7c..d6000d48706 100644
--- a/doc/development/merge_request_concepts/approval_rules.md
+++ b/doc/development/merge_request_concepts/approval_rules.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
---
-# Approval Rules development guide
+# Approval rules development guidelines
This document explains the backend design and flow of all related functionality
about [merge request approval rules](../../user/project/merge_requests/approvals/index.md).
diff --git a/doc/development/merge_request_concepts/diffs/index.md b/doc/development/merge_request_concepts/diffs/index.md
index 8ef3f01aba9..c2dec5c4753 100644
--- a/doc/development/merge_request_concepts/diffs/index.md
+++ b/doc/development/merge_request_concepts/diffs/index.md
@@ -17,7 +17,7 @@ We rely on different sources to present diffs. These include:
<!-- vale gitlab.Spelling = NO -->
In January 2019, Oswaldo Ferreira hosted a Deep Dive (GitLab team members only:
-`https://gitlab.com/gitlab-org/create-stage/issues/1`) on GitLab Diffs and Commenting on Diffs
+`https://gitlab.com/gitlab-org/create-stage/-/issues/1`) on GitLab Diffs and Commenting on Diffs
functionality to share domain-specific knowledge with anyone who may work in this part of the
codebase in the future:
diff --git a/doc/development/merge_request_concepts/index.md b/doc/development/merge_request_concepts/index.md
index 14d9582ad84..8e9b586d5b0 100644
--- a/doc/development/merge_request_concepts/index.md
+++ b/doc/development/merge_request_concepts/index.md
@@ -34,7 +34,7 @@ This area of the merge request is where all of the options and commit messages a
Reports are widgets within the merge request that report information about changes within the merge request. These widgets provide information to better help the author understand the changes and further improvements to the proposed changes.
-[Design Documentation](https://design.gitlab.com/regions/merge-request-reports/)
+[Design Documentation](https://design.gitlab.com/patterns/merge-request-reports)
![merge request reports](../img/merge_request_reports_v14_7.png)
diff --git a/doc/development/merge_request_concepts/performance.md b/doc/development/merge_request_concepts/performance.md
index 740b8f1607b..3b2a097ea2d 100644
--- a/doc/development/merge_request_concepts/performance.md
+++ b/doc/development/merge_request_concepts/performance.md
@@ -260,7 +260,7 @@ It re-instantiates project object for each build, instead of using the same in-m
In this particular case the workaround is fairly easy:
```ruby
-ActiveRecord::Associations::Preloader.new.preload(pipeline, [builds: :project])
+ActiveRecord::Associations::Preloader.new(records: pipeline, associations: [builds: :project]).call
pipeline.builds.each do |build|
build.to_json(only: [:name], include: [project: { only: [:name]}])
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 4625489146e..9f2ad1f7769 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -1,6 +1,6 @@
---
-stage: none
-group: unassigned
+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
---
@@ -307,7 +307,7 @@ which is a "versioned" class. For new migrations, the latest version should be u
can be looked up in `Gitlab::Database::Migration::MIGRATION_CLASSES`) to use the latest version
of migration helpers.
-In this example, we use version 2.0 of the migration class:
+In this example, we use version 2.1 of the migration class:
```ruby
class TestMigration < Gitlab::Database::Migration[2.1]
@@ -323,7 +323,7 @@ version of migration helpers automatically.
Migration helpers and versioning were [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68986)
in GitLab 14.3.
For merge requests targeting previous stable branches, use the old format and still inherit from
-`ActiveRecord::Migration[6.1]` instead of `Gitlab::Database::Migration[2.0]`.
+`ActiveRecord::Migration[6.1]` instead of `Gitlab::Database::Migration[2.1]`.
## Retry mechanism when acquiring database locks
@@ -345,7 +345,7 @@ on the `users` table once it has been enqueued.
More information about PostgreSQL locks: [Explicit Locking](https://www.postgresql.org/docs/current/explicit-locking.html)
-For stability reasons, GitLab.com has a specific [`statement_timeout`](../user/gitlab_com/index.md#postgresql)
+For stability reasons, GitLab.com has a short `statement_timeout`
set. When the migration is invoked, any database query has
a fixed time to execute. In a worst-case scenario, the request sits in the
lock queue, blocking other queries for the duration of the configured statement timeout,
diff --git a/doc/development/navigation_sidebar.md b/doc/development/navigation_sidebar.md
new file mode 100644
index 00000000000..495f30a796c
--- /dev/null
+++ b/doc/development/navigation_sidebar.md
@@ -0,0 +1,38 @@
+---
+stage: Manage
+group: Foundations
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Navigation sidebar
+
+Follow these guidelines when contributing additions or changes to the
+[redesigned](https://gitlab.com/groups/gitlab-org/-/epics/9044) navigation
+sidebar.
+
+These guidelines reflect the current state of the navigation sidebar. However,
+the sidebar is a work in progress, and so is this documentation.
+
+## Enable the new navigation sidebar
+
+To enable the new navigation sidebar:
+
+- Enable the `super_sidebar_nav` feature flag.
+- Select your avatar, then turn on the **New navigation** toggle.
+
+## Adding page-specific Vue content
+
+Pages can render arbitrary content into the sidebar using the `SidebarPortal`
+component. Content passed to its default slot is rendered below that
+page's navigation items in the sidebar.
+
+NOTE:
+Only one instance of this component on a given page is supported. This is to
+avoid ordering issues and cluttering the sidebar.
+
+NOTE:
+Arbitrary content is allowed, but nav items should be implemented by
+subclassing `::Sidebars::Panel`.
+
+NOTE:
+Do not use the `SidebarPortalTarget` component. It is internal to the sidebar.
diff --git a/doc/development/organization/index.md b/doc/development/organization/index.md
new file mode 100644
index 00000000000..6a643603170
--- /dev/null
+++ b/doc/development/organization/index.md
@@ -0,0 +1,159 @@
+---
+comments: false
+type: index, dev
+stage: Data Stores
+group: Tenant Scale
+info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines"
+description: "Development Guidelines: learn about organization when developing GitLab."
+---
+
+# Organization
+
+The [Organization initiative](../../user/organization/index.md) focuses on reaching feature parity between
+SaaS and self-managed installations.
+
+## Consolidate groups and projects
+
+- [Architecture blueprint](../../architecture/blueprints/consolidating_groups_and_projects/index.md)
+
+One facet of the Organization initiative is to consolidate groups and projects,
+addressing the feature disparity between them. Some features, such as epics, are
+only available at the group level. Some features, such as issues, are only available
+at the project level. Other features, such as milestones, are available to both groups
+and projects.
+
+We receive many requests to add features either to the group or project level.
+Moving features around to different levels is problematic on multiple levels:
+
+- It requires engineering time to move the features.
+- It requires UX overhead to maintain mental models of feature availability.
+- It creates redundant code.
+
+When features are copied from one level (project, group, or instance) to another,
+the copies often have small, nuanced differences between them. These nuances cause
+extra engineering time when fixes are needed, because the fix must be copied to
+several locations. These nuances also create different user experiences when the
+feature is used in different places.
+
+A solution for this problem is to consolidate groups and projects into a single
+entity, `namespace`. The work on this solution is split into several phases and
+is tracked in [epic 6473](https://gitlab.com/groups/gitlab-org/-/epics/6473).
+
+### Phase 1
+
+- [Phase 1 epic](https://gitlab.com/groups/gitlab-org/-/epics/6697).
+- **Goals**:
+ 1. Ensure every project receives a corresponding record in the `namespaces`
+ table with `type='Project'`.
+ 1. For user namespaces, the type changes from `NULL` to `User`.
+
+We should make sure that projects, and the project namespace, are equivalent:
+
+- **Create project:** use Rails callbacks to ensure a new project namespace is
+ created for each project. Project namespace records should contain `created_at` and
+ `updated_at` attributes equal to the project's `created_at`/`updated_at` attributes.
+- **Update project:** use the `after_save` callback in Rails to ensure some
+ attributes are kept in sync between project and project namespaces.
+ Read [`project#after_save`](https://gitlab.com/gitlab-org/gitlab/blob/6d26634e864d7b748dda0e283eb2477362263bc3/app/models/project.rb#L101-L101)
+ for more information.
+- **Delete project:** use FKs cascade delete or Rails callbacks to ensure when a `Project`
+ or its `ProjectNamespace` is removed, its corresponding `ProjectNamespace` or `Project`
+ is also removed.
+- **Transfer project to a different group:** make sure that when a project is transferred,
+ its corresponding project namespace is transferred to the same group.
+- **Transfer group:** make sure when transferring a group that all of its sub-projects,
+ either direct or through descendant groups, have their corresponding project
+ namespaces transferred correctly as well.
+- **Export or import project**
+ - **Export project** continues to export only the project, and not its project namespace,
+ in this phase. The project namespace does not contain any specific information
+ to export at this point. Eventually we want the project namespace to be exported as well.
+ - **Import project** creates a new project, so the project namespace is created through
+ Rails `after_save` callback on the project model.
+- **Export or import group:** when importing or exporting a `Group`, projects are not
+ included in the operation. If that feature is changed to include `Project` when its group is
+ imported or exported, the logic must include their corresponding project namespaces
+ in the import or export.
+
+After ensuring these points, run a database migration to create a `ProjectNamespace`
+record for every `Project`. Project namespace records created during the migration
+should have `created_at` and `updated_at` attributes set to the migration runtime.
+The project namespaces' `created_at` and `updated_at` attributes would not match
+their corresponding project's `created_at` and `updated_at` attributes. We want
+the different dates to help audit any of the created project namespaces, in case we need it.
+After this work completes, we must migrate data as described in
+[Backfill `ProjectNamespace` for every Project](https://gitlab.com/gitlab-org/gitlab/-/issues/337100).
+
+### Phase 2
+
+- [Phase 2 epic](https://gitlab.com/groups/gitlab-org/-/epics/6768).
+- **Goal**: Link `ProjectNamespace` to other entities on the database level.
+
+In this phase:
+
+- Communicate the changes company-wide at the engineering level. We want to make
+ engineers aware of the upcoming changes, even though teams are not expected to
+ collaborate actively until phase 3.
+- Raise awareness to avoid regressions, and conflicting or duplicate work that
+ can be dealt with before phase 3.
+
+### Phase 3
+
+- [Phase 3 epic](https://gitlab.com/groups/gitlab-org/-/epics/6585).
+- **Goal**: Achieve feature parity between the namespace types.
+Problems to solve as part of this phase:
+
+- Routes handling through `ProjectNamespace` rather than `Project`.
+- Memberships handling.
+- Policies handling.
+- Import and export.
+- Other interactions between project namespace and project models.
+
+Phase 3 is when the active migration of features from `Project` to `ProjectNamespace`,
+or directly to `Namespace`, happens.
+
+### How to plan features that interact with Group and ProjectNamespace
+
+As of now, every Project in the system has a record in the `namespaces` table. This makes it possible to
+use common interface to create features that are shared between Groups and Projects. Shared behavior can be added using
+a concerns mechanism. Because the `Namespace` model is responsible for `UserNamespace` methods as well, it is discouraged
+to use the `Namespace` model for shared behavior for Projects and Groups.
+
+#### Resource-based features
+
+To migrate resource-based features, existing functionality will need to be supported. This can be achieved in two Phases.
+
+**Phase 1 - Setup**
+
+- Link into the namespaces table
+ - Add a column to the table
+ - For example, in issues a `project id` points to the projects table. We need to establish a link to the `namespaces` table.
+ - Modify code so that any new record already has the correct data in it
+ - Backfill
+
+**Phase 2 - Prerequisite work**
+
+- Investigate the permission model as well as any performance concerns related to that.
+ - Permissions need to be checked and kept in place.
+- Investigate what other models need to support namespaces for functionality dependent on features you migrate in Phase 1.
+- Adjust CRUD services and APIs (REST and GraphQL) to point to the new column you added in Phase 1.
+- Consider performance when fetching resources.
+
+Introducing new functionality is very much dependent on every single team and feature.
+
+#### Settings-related features
+
+Right now, cascading settings are available for `NamespaceSettings`. By creating `ProjectNamespace`,
+we can use this framework to make sure that some settings are applicable on the project level as well.
+
+When working on settings, we need to make sure that:
+
+- They are not used in `join` queries or modify those queries.
+- Updating settings is taken into consideration.
+- If we want to move from project to project namespace, we follow a similar database process to the one described in [Phase 1](#phase-1).
+
+## Related topics
+
+- [Consolidating groups and projects](../../architecture/blueprints/consolidating_groups_and_projects/index.md)
+ architecture documentation
+- [Organization user documentation](../../user/organization/index.md)
diff --git a/doc/development/packages/debian_repository.md b/doc/development/packages/debian_repository.md
index 26a33c548d8..1523d777e7b 100644
--- a/doc/development/packages/debian_repository.md
+++ b/doc/development/packages/debian_repository.md
@@ -116,7 +116,7 @@ sequenceDiagram
ProcessChangesService->>+ExtractChangesMetadataService: Extract changesmetadata
ExtractChangesMetadataService->>+ExtractMetadataService: Extract file metadata
ExtractMetadataService->>+ParseDebian822Service: run `dpkg --field` to get control file
- ExtractMetadataService->>+ExtractDebMetadataService: If .deb or .udeb
+ ExtractMetadataService->>+ExtractDebMetadataService: If .deb, .udeb or ddeb
ExtractDebMetadataService->>+ParseDebian822Service: run `dpkg --field` to get control file
ParseDebian822Service-->>-ExtractDebMetadataService: Parse String as Debian RFC822 control data format
ExtractDebMetadataService-->>-ExtractMetadataService: Return the parsed control file
@@ -127,7 +127,7 @@ sequenceDiagram
loop process files listed in .changes
ProcessChangesService->>+ExtractMetadataService: Process file
ExtractMetadataService->>+ParseDebian822Service: run `dpkg --field` to get control file
- ExtractMetadataService->>+ExtractDebMetadataService: If .deb or .udeb
+ ExtractMetadataService->>+ExtractDebMetadataService: If .deb, .udeb or ddeb
ExtractDebMetadataService->>+ParseDebian822Service: run `dpkg --field` to get control file
ParseDebian822Service-->>-ExtractDebMetadataService: Parse String as Debian RFC822 control data format
ExtractDebMetadataService-->>-ExtractMetadataService: Return the parsed control file
diff --git a/doc/development/packages/index.md b/doc/development/packages/index.md
index fa0e9f5d926..4f027825422 100644
--- a/doc/development/packages/index.md
+++ b/doc/development/packages/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
---
-# Package and container registry documentation
+# Package and container registry development guidelines
The documentation for package and container registry development is split into two groups.
diff --git a/doc/development/permissions.md b/doc/development/permissions.md
index bf7f99de1ab..3abadc98501 100644
--- a/doc/development/permissions.md
+++ b/doc/development/permissions.md
@@ -4,7 +4,7 @@ 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
---
-# Implementing permissions
+# Permission development guidelines
There are multiple types of permissions across GitLab, and when implementing
anything that deals with permissions, all of them should be considered.
@@ -60,7 +60,7 @@ Additionally, the following project features can have different visibility level
- Pipelines
- Analytics
- Requirements
-- Security & Compliance
+- Security and Compliance
- Wiki
- Snippets
- Pages
@@ -198,3 +198,124 @@ Say, for example, we extract the whole endpoint into a service. The `can?` check
- If the finder doesn't accept `current_user`, and therefore doesn't check permissions, then probably no.
- If the finder accepts `current_user`, and doesn't check permissions, then it would be a good idea to double check other usages of the finder, and we might consider adding authorization.
- If the finder accepts `current_user`, and already checks permissions, then either we need to add our case, or the existing checks are appropriate.
+
+### Refactoring permissions
+
+#### Finding existing permissions checks
+
+As mentioned [above](#where-should-permissions-be-checked), permissions are
+often checked in multiple locations for a single endpoint or web request. As a
+result, finding the list of authorization checks that are run for a given endpoint
+can be challenging.
+
+To assist with this, you can locally set `GITLAB_DEBUG_POLICIES=true`.
+
+This outputs information about which abilities are checked in the requests
+made in any specs that you run. The output also includes the line of code where the
+authorization check was made. Caller information is especially helpful in cases
+where there is metaprogramming used because those cases are difficult to find by
+grepping for ability name strings.
+
+Example:
+
+```shell
+# example spec run
+
+GITLAB_DEBUG_POLICIES=true bundle exec rspec spec/controllers/groups_controller_spec.rb:162
+
+# permissions debug output when spec is run; if multiple policy checks are run they will all be in the debug output.
+
+POLICY CHECK DEBUG -> policy: GlobalPolicy, ability: create_group, called_from: ["/gitlab/app/controllers/application_controller.rb:245:in `can?'", "/gitlab/app/controllers/groups_controller.rb:255:in `authorize_create_group!'"]
+```
+
+This flag is meant to help learn more about authorization checks while
+refactoring and should not remain enabled for any specs on the default branch.
+
+#### Understanding logic for individual abilities
+
+References to an ability may appear in a `DeclarativePolicy` class many times
+and depend on conditions and rules which reference other abilities. As a result,
+it can be challenging to know exactly which conditions apply to a particular
+ability.
+
+`DeclarativePolicy` provides a `ability_map` for each Policy class, which
+pulls all Rules for an ability into an array.
+
+Example:
+
+```ruby
+> GroupPolicy.ability_map.map.select { |k,v| k == :read_group_member }
+=> {:read_group_member=>[[:enable, #<Rule can?(:read_group)>], [:prevent, #<Rule ~can_read_group_member>]]}
+
+> GroupPolicy.ability_map.map.select { |k,v| k == :read_group }
+=> {:read_group=>
+ [[:enable, #<Rule public_group>],
+ [:enable, #<Rule logged_in_viewable>],
+ [:enable, #<Rule guest>],
+ [:enable, #<Rule admin>],
+ [:enable, #<Rule has_projects>],
+ [:enable, #<Rule read_package_registry_deploy_token>],
+ [:enable, #<Rule write_package_registry_deploy_token>],
+ [:prevent, #<Rule all?(~public_group, ~admin, user_banned_from_group)>],
+ [:enable, #<Rule auditor>],
+ [:prevent, #<Rule needs_new_sso_session>],
+ [:prevent, #<Rule all?(ip_enforcement_prevents_access, ~owner, ~auditor)>]]}
+```
+
+`DeclarativePolicy` also provides a `debug` method that can be used to
+understand the logic tree for a specific object and actor. The output is similar
+to the list of rules from `ability_map`. But, `DeclarativePolicy` stops
+evaluating rules once one `prevent`s an ability, so it is possible that
+not all conditions are called.
+
+Example:
+
+```ruby
+policy = GroupPolicy.new(User.last, Group.last)
+policy.debug(:read_group)
+
+- [0] enable when public_group ((@custom_guest_user1 : Group/139))
+- [0] enable when logged_in_viewable ((@custom_guest_user1 : Group/139))
+- [0] enable when admin ((@custom_guest_user1 : Group/139))
+- [0] enable when auditor ((@custom_guest_user1 : Group/139))
+- [14] prevent when all?(~public_group, ~admin, user_banned_from_group) ((@custom_guest_user1 : Group/139))
+- [14] prevent when needs_new_sso_session ((@custom_guest_user1 : Group/139))
+- [16] enable when guest ((@custom_guest_user1 : Group/139))
+- [16] enable when has_projects ((@custom_guest_user1 : Group/139))
+- [16] enable when read_package_registry_deploy_token ((@custom_guest_user1 : Group/139))
+- [16] enable when write_package_registry_deploy_token ((@custom_guest_user1 : Group/139))
+ [21] prevent when all?(ip_enforcement_prevents_access, ~owner, ~auditor) ((@custom_guest_user1 : Group/139))
+
+=> #<DeclarativePolicy::Runner::State:0x000000015c665050
+ @called_conditions=
+ #<Set: {
+ "/dp/condition/GroupPolicy/public_group/Group:139",
+ "/dp/condition/GroupPolicy/logged_in_viewable/User:83,Group:139",
+ "/dp/condition/BasePolicy/admin/User:83",
+ "/dp/condition/BasePolicy/auditor/User:83",
+ "/dp/condition/GroupPolicy/user_banned_from_group/User:83,Group:139",
+ "/dp/condition/GroupPolicy/needs_new_sso_session/User:83,Group:139",
+ "/dp/condition/GroupPolicy/guest/User:83,Group:139",
+ "/dp/condition/GroupPolicy/has_projects/User:83,Group:139",
+ "/dp/condition/GroupPolicy/read_package_registry_deploy_token/User:83,Group:139",
+ "/dp/condition/GroupPolicy/write_package_registry_deploy_token/User:83,Group:139"}>,
+ @enabled=false,
+ @prevented=true>
+```
+
+#### Testing that individual policies are equivalent
+
+You can use the `'equivalent project policy abilities'` shared example to ensure
+that 2 project policy abilities are equivalent for all project visibility levels
+and access levels.
+
+Example:
+
+```ruby
+ context 'when refactoring read_pipeline_schedule and read_pipeline' do
+ let(:old_policy) { :read_pipeline_schedule }
+ let(:new_policy) { :read_pipeline }
+
+ it_behaves_like 'equivalent policies'
+ end
+```
diff --git a/doc/development/pipelines/index.md b/doc/development/pipelines/index.md
index 240d98a855f..51cdd12a8c1 100644
--- a/doc/development/pipelines/index.md
+++ b/doc/development/pipelines/index.md
@@ -100,7 +100,7 @@ The `rules` definitions for full Jest tests are defined at `.frontend:rules:jest
We run only the predictive RSpec & Jest jobs for fork pipelines, unless the `pipeline:run-all-rspec`
label is set on the MR. The goal is to reduce the CI/CD minutes consumed by fork pipelines.
-See the [experiment issue](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1170).
+See the [experiment issue](https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/1170).
## Fail-fast job in merge request pipelines
@@ -392,6 +392,8 @@ to detect, and fail if any changes introduced in the merge request has zero cove
The `rspec:undercoverage` job obtains coverage data from the `rspec:coverage`
job.
+If the `rspec:undercoverage` job detects missing coverage due to a CE method being overridden in EE, add the `pipeline:run-as-if-foss` label to the merge request and start a new pipeline.
+
In the event of an emergency, or false positive from this job, add the
`pipeline:skip-undercoverage` label to the merge request to allow this job to
fail.
@@ -442,7 +444,7 @@ so that they're ultimately fixed by their respective group.
The automatic skipping of flaky tests can still be enabled by setting the `$SKIP_FLAKY_TESTS_AUTOMATICALLY` variable to `true`.
-See the [experiment issue](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1069).
+See the [experiment issue](https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/1069).
### Automatic retry of failing tests in a separate process
@@ -451,7 +453,7 @@ RSpec process. The goal is to get rid of most side-effects from previous tests t
We keep track of retried tests in the `$RETRIED_TESTS_REPORT_FILE` file saved as artifact by the `rspec:flaky-tests-report` job.
-See the [experiment issue](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1148).
+See the [experiment issue](https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/1148).
## Compatibility testing
@@ -484,19 +486,17 @@ This should let us:
Our test suite runs against PG12 as GitLab.com runs on PG12 and
[Omnibus defaults to PG12 for new installs and upgrades](../../administration/package_information/postgresql_versions.md).
-We do run our test suite against PG11 and PG13 on nightly scheduled pipelines.
-
-We also run our test suite against PG11 upon specific database library changes in MRs and `main` pipelines (with the `rspec db-library-code pg11` job).
+We do run our test suite against PG13 on nightly scheduled pipelines.
#### Current versions testing
-| Where? | PostgreSQL version | Ruby version |
-|------------------------------------------------------------------------------------------------|-------------------------------------------------|--------------|
-| Merge requests | 12 (default version), 11 for DB library changes | 3.0 (default version) |
-| `master` branch commits | 12 (default version), 11 for DB library changes | 3.0 (default version) |
-| `maintenance` scheduled pipelines for the `master` branch (every even-numbered hour) | 12 (default version), 11 for DB library changes | 3.0 (default version) |
-| `maintenance` scheduled pipelines for the `ruby2` branch (every odd-numbered hour), see below. | 12 (default version), 11 for DB library changes | 2.7 |
-| `nightly` scheduled pipelines for the `master` branch | 12 (default version), 11, 13 | 3.0 (default version) |
+| Where? | PostgreSQL version | Ruby version |
+|------------------------------------------------------------------------------------------------|--------------------------|-----------------------|
+| Merge requests | 12 (default version) | 3.0 (default version) |
+| `master` branch commits | 12 (default version) | 3.0 (default version) |
+| `maintenance` scheduled pipelines for the `master` branch (every even-numbered hour) | 12 (default version) | 3.0 (default version) |
+| `maintenance` scheduled pipelines for the `ruby2` branch (every odd-numbered hour), see below. | 12 (default version) | 2.7 |
+| `nightly` scheduled pipelines for the `master` branch | 12 (default version), 13 | 3.0 (default version) |
There are 2 pipeline schedules used for testing Ruby 2.7. One is triggering a
pipeline in `ruby2-sync` branch, which updates the `ruby2` branch with latest
@@ -518,7 +518,6 @@ We follow the [PostgreSQL versions shipped with Omnibus GitLab](../../administra
| PostgreSQL version | 14.1 (July 2021) | 14.2 (August 2021) | 14.3 (September 2021) | 14.4 (October 2021) | 14.5 (November 2021) | 14.6 (December 2021) |
| -------------------| ---------------------- | ---------------------- | ---------------------- | ---------------------- | ---------------------- | ---------------------- |
| PG12 | MRs/`2-hour`/`nightly` | MRs/`2-hour`/`nightly` | MRs/`2-hour`/`nightly` | MRs/`2-hour`/`nightly` | MRs/`2-hour`/`nightly` | MRs/`2-hour`/`nightly` |
-| PG11 | `nightly` | `nightly` | `nightly` | `nightly` | `nightly` | `nightly` |
| PG13 | `nightly` | `nightly` | `nightly` | `nightly` | `nightly` | `nightly` |
### Redis versions testing
diff --git a/doc/development/pipelines/internals.md b/doc/development/pipelines/internals.md
index 9ff4e5a35ec..bd96f2f2872 100644
--- a/doc/development/pipelines/internals.md
+++ b/doc/development/pipelines/internals.md
@@ -136,8 +136,6 @@ that are scoped to a single [configuration keyword](../../ci/yaml/index.md#job-k
| `.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. |
-| `.use-pg11` | Allows a job to run the `postgres` 11 and `redis` services (see [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml) for the specific versions of the services). |
-| `.use-pg11-ee` | Same as `.use-pg11` 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-pg12` | Allows a job to use the `postgres` 12 and `redis` services (see [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml) for the specific versions of the services). |
| `.use-pg12-ee` | Same as `.use-pg12` 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-pg13` | Allows a job to use the `postgres` 13 and `redis` services (see [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml) for the specific versions of the services). |
diff --git a/doc/development/pipelines/performance.md b/doc/development/pipelines/performance.md
index 5f2df91edf3..d0eef0c86bd 100644
--- a/doc/development/pipelines/performance.md
+++ b/doc/development/pipelines/performance.md
@@ -147,4 +147,4 @@ We no longer use this optimization for `gitlab-org/gitlab` because the [pack-obj
allows Gitaly to serve the full CI/CD fetch traffic now. See [Git fetch caching](#git-fetch-caching).
The pre-clone step works by using the `CI_PRE_CLONE_SCRIPT` variable
-[defined by GitLab.com shared runners](../../ci/runners/saas/linux_saas_runner.md#pre-clone-script).
+[defined by GitLab.com shared runners](../../ci/runners/saas/linux_saas_runner.md#pre-clone-script-deprecated).
diff --git a/doc/development/product_qualified_lead_guide/index.md b/doc/development/product_qualified_lead_guide/index.md
index c72110bc253..41237dcdff4 100644
--- a/doc/development/product_qualified_lead_guide/index.md
+++ b/doc/development/product_qualified_lead_guide/index.md
@@ -4,7 +4,7 @@ group: Acquisition
info: To 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 Qualified Lead (PQL) development guide
+# Product Qualified Lead (PQL) development guidelines
The Product Qualified Lead (PQL) funnel connects our users with our team members. Read more about [PQL product principles](https://about.gitlab.com/handbook/product/product-principles/#product-qualified-leads-pqls).
diff --git a/doc/development/project_templates.md b/doc/development/project_templates.md
index 3320f3134fb..31537b21527 100644
--- a/doc/development/project_templates.md
+++ b/doc/development/project_templates.md
@@ -35,7 +35,7 @@ installed:
1. In your selected namespace, create a public project.
1. Add the project content you want to use in the template. Do not include unnecessary assets or dependencies. For an example,
[see this project](https://gitlab.com/gitlab-org/project-templates/dotnetcore).
-1. When the project is ready for review, [create an issue](https://gitlab.com/gitlab-org/gitlab/issues) with a link to your project.
+1. When the project is ready for review, [create an issue](https://gitlab.com/gitlab-org/gitlab/-/issues) with a link to your project.
In your issue, mention the Create:Source Code [Backend Engineering Manager and Product Manager](https://about.gitlab.com/handbook/product/categories/#source-code-group)
for the Templates feature.
diff --git a/doc/development/prometheus_metrics.md b/doc/development/prometheus_metrics.md
index 834a20239fc..590ac547c2d 100644
--- a/doc/development/prometheus_metrics.md
+++ b/doc/development/prometheus_metrics.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
---
-# Working with Prometheus Metrics
+# Prometheus metrics development guidelines
## Adding to the library
diff --git a/doc/development/python_guide/index.md b/doc/development/python_guide/index.md
index 08d2f46c1cd..e9b52b81c0e 100644
--- a/doc/development/python_guide/index.md
+++ b/doc/development/python_guide/index.md
@@ -4,7 +4,7 @@ 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
---
-# Python Development Guidelines
+# Python development guidelines
GitLab requires Python as a dependency for [reStructuredText](https://docutils.sourceforge.io/rst.html)
markup rendering.
diff --git a/doc/development/rails_update.md b/doc/development/rails_update.md
index a541de020fb..32295cc0e43 100644
--- a/doc/development/rails_update.md
+++ b/doc/development/rails_update.md
@@ -61,49 +61,49 @@ To efficiently and quickly find which Rails change caused the spec failure you c
1. Clone the `rails` project in a folder of your choice. For example, it might be the GDK root dir:
- ```shell
- cd <GDK_FOLDER>
- git clone https://github.com/rails/rails.git
- ```
+ ```shell
+ cd <GDK_FOLDER>
+ git clone https://github.com/rails/rails.git
+ ```
1. Replace the `gem 'rails'` line in GitLab `Gemfile` with:
- ```ruby
- gem 'rails', ENV['RAILS_VERSION'], path: ENV['RAILS_FOLDER']
- ```
+ ```ruby
+ gem 'rails', ENV['RAILS_VERSION'], path: ENV['RAILS_FOLDER']
+ ```
1. Set the `RAILS_FOLDER` environment variable with the folder you cloned Rails into:
- ```shell
- export RAILS_FOLDER="<GDK_FOLDER>/rails"
- ```
+ ```shell
+ export RAILS_FOLDER="<GDK_FOLDER>/rails"
+ ```
1. Change the directory to `RAILS_FOLDER` and set the range for the `git bisect` command:
- ```shell
- cd $RAILS_FOLDER
- git bisect start <NEW_VERSION_TAG> <OLD_VERSION_TAG>
- ```
+ ```shell
+ cd $RAILS_FOLDER
+ git bisect start <NEW_VERSION_TAG> <OLD_VERSION_TAG>
+ ```
- Where `<NEW_VERSION_TAG>` is the tag where the spec is red and `<OLD_VERSION_TAG>` is the one with the green spec.
- For example, `git bisect start v6.1.4.1 v6.1.3.2` if we're upgrading from version 6.1.3.2 to 6.1.4.1.
- Replace `<NEW_VERSION_TAG>` with the tag where the spec is red and `<OLD_VERSION_TAG>` with the one with the green spec. For example, `git bisect start v6.1.4.1 v6.1.3.2` if we're upgrading from version 6.1.3.2 to 6.1.4.1.
- In the output, you can see how many steps approximately it takes to find the commit.
+ Where `<NEW_VERSION_TAG>` is the tag where the spec is red and `<OLD_VERSION_TAG>` is the one with the green spec.
+ For example, `git bisect start v6.1.4.1 v6.1.3.2` if we're upgrading from version 6.1.3.2 to 6.1.4.1.
+ Replace `<NEW_VERSION_TAG>` with the tag where the spec is red and `<OLD_VERSION_TAG>` with the one with the green spec. For example, `git bisect start v6.1.4.1 v6.1.3.2` if we're upgrading from version 6.1.3.2 to 6.1.4.1.
+ In the output, you can see how many steps approximately it takes to find the commit.
1. Start the `git bisect` process and pass spec's filenames to `scripts/rails-update-bisect` as arguments. It can be faster to pick only one example instead of an entire spec file.
- ```shell
- git bisect run <GDK_FOLDER>/gitlab/scripts/rails-update-bisect spec/models/ability_spec.rb
- # OR
- git bisect run <GDK_FOLDER>/gitlab/scripts/rails-update-bisect spec/models/ability_spec.rb:7
- ```
+ ```shell
+ git bisect run <GDK_FOLDER>/gitlab/scripts/rails-update-bisect spec/models/ability_spec.rb
+ # OR
+ git bisect run <GDK_FOLDER>/gitlab/scripts/rails-update-bisect spec/models/ability_spec.rb:7
+ ```
1. When the process is completed, `git bisect` prints the commit hash, which you can use to find the corresponding MR in the [`rails/rails`](https://github.com/rails/rails) repository.
1. Execute `git bisect reset` to exit the `bisect` mode.
1. Revert the changes to `Gemfile`:
- ```shell
- git checkout -- Gemfile
- ```
+ ```shell
+ git checkout -- Gemfile
+ ```
### Follow-up reading material
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index cd7f8cba39b..82e96befd11 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -258,7 +258,7 @@ One way to generate the initial list is to run the Rake task `rubocop:todo:gener
bundle exec rake rubocop:todo:generate
```
-To generate TODO list for specific RuboCop rules, pass them comma-separated as
+To generate TODO list for specific RuboCop rules, pass them comma-seperated as
argument to the Rake task:
```shell
diff --git a/doc/development/real_time.md b/doc/development/real_time.md
index 2aa48fed8eb..99d09170646 100644
--- a/doc/development/real_time.md
+++ b/doc/development/real_time.md
@@ -4,7 +4,7 @@ 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
---
-# Real-Time Features
+# Real-time features
This guide contains instructions on how to safely roll out new real-time
features.
diff --git a/doc/development/redis.md b/doc/development/redis.md
index 68cab9ac38d..a2dbf52822e 100644
--- a/doc/development/redis.md
+++ b/doc/development/redis.md
@@ -4,7 +4,7 @@ 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
---
-# Redis guidelines
+# Redis development guidelines
## Redis instances
@@ -188,6 +188,26 @@ it 'avoids N+1 Redis calls to forks_count key' do
end
```
+You also can use special matchers `exceed_redis_calls_limit` and
+`exceed_redis_command_calls_limit` to define an upper limit for
+a number of Redis calls:
+
+```ruby
+it 'avoids N+1 Redis calls' do
+ control = RedisCommands::Recorder.new { visit_page }
+
+ expect(control).not_to exceed_redis_calls_limit(1)
+end
+```
+
+```ruby
+it 'avoids N+1 sadd Redis calls' do
+ control = RedisCommands::Recorder.new { visit_page }
+
+ expect(control).not_to exceed_redis_command_calls_limit(:sadd, 1)
+end
+```
+
These tests can help to identify N+1 problems related to Redis calls,
and make sure that the fix for them works as expected.
diff --git a/doc/development/redis/new_redis_instance.md b/doc/development/redis/new_redis_instance.md
index 0a030a0877f..c1f69f4d103 100644
--- a/doc/development/redis/new_redis_instance.md
+++ b/doc/development/redis/new_redis_instance.md
@@ -177,19 +177,15 @@ bin/feature-flag use_primary_store_as_default_for_foo
```
By enabling `use_primary_and_secondary_stores_for_foo` feature flag, our `Gitlab::Redis::Foo` will use `MultiStore` to write to both new Redis instance
-and the [old (fallback-instance)](#fallback-instance).
-If we fail to fetch data from the new instance, we will fallback and read from the old Redis instance.
-We can monitor logs for `Gitlab::Redis::MultiStore::ReadFromPrimaryError`, and also the Prometheus counter `gitlab_redis_multi_store_read_fallback_total`.
+and the [old (fallback-instance)](#fallback-instance). All read commands are performed only on the default store which is controlled using the
+`use_primary_store_as_default_for_foo` feature flag. By enabling `use_primary_store_as_default_for_foo` feature flag,
+the `MultiStore` uses `primary_store` (new instance) as default Redis store.
For `pipelined` commands (`pipelined` and `multi`), we execute the entire operation in both stores and then compare the results. If they differ, we emit a
`Gitlab::Redis::MultiStore:PipelinedDiffError` error, and track it in the `gitlab_redis_multi_store_pipelined_diff_error_total` Prometheus counter.
-Once we stop seeing those errors, this means that we are no longer relying on the data stored on the old Redis store.
-At this point, we are probably safe to move the traffic to the new Redis store.
-
-By enabling `use_primary_store_as_default_for_foo` feature flag, the `MultiStore` will use `primary_store` (new instance) as default Redis store.
-
-Once this feature flag is enabled, we can disable `use_primary_and_secondary_stores_for_foo` feature flag.
+After a period of time for the new store to be populated, we can perform external validation to compare the state of both stores.
+Upon satisfactory validation results, we are probably safe to move the traffic to the new Redis store. We can disable `use_primary_and_secondary_stores_for_foo` feature flag.
This will allow the MultiStore to read and write only from the primary Redis store (new store), moving all the traffic to the new Redis store.
Once we have moved all our traffic to the primary store, our data migration is complete.
@@ -206,17 +202,44 @@ MultiStore implements read and write Redis commands separately.
- `smembers`
- `scard`
+- 'exists'
+- 'exists?'
+- 'get'
+- 'hexists'
+- 'hget'
+- 'hgetall'
+- 'hlen'
+- 'hmget'
+- 'hscan_each'
+- 'mapped_hmget'
+- 'mget'
+- 'scan_each'
+- 'scard'
+- 'sismember'
+- 'smembers'
+- 'sscan'
+- 'sscan_each'
+- 'ttl'
+- 'zscan_each'
+
##### Write commands
-- `set`
-- `setnx`
-- `setex`
-- `sadd`
-- `srem`
-- `del`
-- `pipelined`
-- `flushdb`
-- `rpush`
+- 'del'
+- 'eval'
+- 'expire'
+- 'flushdb'
+- 'hdel'
+- 'hset'
+- 'incr'
+- 'incrby'
+- 'mapped_hmset'
+- 'rpush'
+- 'sadd'
+- 'set'
+- 'setex'
+- 'setnx'
+- 'srem'
+- 'unlink'
##### `pipelined` commands
@@ -227,7 +250,8 @@ Thus, excluding the Redis operations performed, the block should be idempotent.
- `multi`
When a command outside of the supported list is used, `method_missing` will pass it to the old Redis instance and keep track of it.
-This ensures that anything unexpected behaves like it would before.
+This ensures that anything unexpected behaves like it would before. In development or test environment, an error would be raised for early
+detection.
NOTE:
By tracking `gitlab_redis_multi_store_method_missing_total` counter and `Gitlab::Redis::MultiStore::MethodMissingError`,
@@ -237,7 +261,6 @@ a developer will need to add an implementation for missing Redis commands before
| error | message |
|---------------------------------------------------|---------------------------------------------------------------------------------------------|
-| `Gitlab::Redis::MultiStore::ReadFromPrimaryError` | Value not found on the Redis primary store. Read from the Redis secondary store successful. |
| `Gitlab::Redis::MultiStore::PipelinedDiffError` | `pipelined` command executed on both stores successfully but results differ between them. |
| `Gitlab::Redis::MultiStore::MethodMissingError` | Method missing. Falling back to execute method on the Redis secondary store. |
@@ -245,7 +268,6 @@ a developer will need to add an implementation for missing Redis commands before
| Metrics name | Type | Labels | Description |
|-------------------------------------------------------|--------------------|----------------------------|----------------------------------------------------------|
-| `gitlab_redis_multi_store_read_fallback_total` | Prometheus Counter | `command`, `instance_name` | Client side Redis MultiStore reading fallback total |
| `gitlab_redis_multi_store_pipelined_diff_error_total` | Prometheus Counter | `command`, `instance_name` | Redis MultiStore `pipelined` command diff between stores |
| `gitlab_redis_multi_store_method_missing_total` | Prometheus Counter | `command`, `instance_name` | Client side Redis MultiStore method missing total |
diff --git a/doc/development/repository_mirroring.md b/doc/development/repository_mirroring.md
index a9164398afb..6d95dec823b 100644
--- a/doc/development/repository_mirroring.md
+++ b/doc/development/repository_mirroring.md
@@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
<!-- vale gitlab.Spelling = NO -->
-In December 2018, Tiago Botelho hosted a Deep Dive (GitLab team members only: `https://gitlab.com/gitlab-org/create-stage/issues/1`)
+In December 2018, Tiago Botelho hosted a Deep Dive (GitLab team members only: `https://gitlab.com/gitlab-org/create-stage/-/issues/1`)
on the GitLab [Pull Repository Mirroring functionality](../user/project/repository/mirror/pull.md)
to share his domain specific knowledge with anyone who may work in this part of the
codebase in the future. You can find the <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [recording on YouTube](https://www.youtube.com/watch?v=sSZq0fpdY-Y),
diff --git a/doc/development/rubocop_development_guide.md b/doc/development/rubocop_development_guide.md
index 2ff94f65232..1fdc0fbe78c 100644
--- a/doc/development/rubocop_development_guide.md
+++ b/doc/development/rubocop_development_guide.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
---
-# RuboCop rule development guide
+# RuboCop rule development guidelines
Our codebase style is defined and enforced by [RuboCop](https://github.com/rubocop-hq/rubocop).
@@ -43,7 +43,7 @@ Before adding a new cop to enforce a given style, make sure to discuss it with y
We maintain cops across several Ruby code bases, and not all of them are
specific to the GitLab application.
When creating a new cop that could be applied to multiple applications, we encourage you
-to add it to our [`gitlab-styles`](https://gitlab.com/gitlab-org/gitlab-styles) gem.
+to add it to our [`gitlab-styles`](https://gitlab.com/gitlab-org/ruby/gems/gitlab-styles) gem.
If the cop targets rules that only apply to the main GitLab application,
it should be added to [GitLab](https://gitlab.com/gitlab-org/gitlab) instead.
@@ -60,7 +60,7 @@ A grace period can safely be lifted as soon as there are no warnings for 2 weeks
1. Enable the new cop in `.rubocop.yml` (if not already done via [`gitlab-styles`](https://gitlab.com/gitlab-org/ruby/gems/gitlab-styles)).
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 ~"good for new contributors" and/or ~"Seeking community contributions"). [See some examples](https://gitlab.com/gitlab-org/gitlab/-/issues/?sort=created_date&state=opened&label_name%5B%5D=good%20for%20new%20contributors&label_name%5B%5D=static%20code%20analysis&first_page_size=20).
+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).
## Silenced offenses
diff --git a/doc/development/search/advanced_search_migration_styleguide.md b/doc/development/search/advanced_search_migration_styleguide.md
new file mode 100644
index 00000000000..2f8cd036dcf
--- /dev/null
+++ b/doc/development/search/advanced_search_migration_styleguide.md
@@ -0,0 +1,311 @@
+---
+stage: Data Stores
+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
+---
+
+# Advanced search migration style guide
+
+## Creating a new advanced search migration
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/234046) in GitLab 13.6.
+
+NOTE:
+This functionality is only supported for indices created in GitLab 13.0 and later.
+
+In the [`ee/elastic/migrate/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/ee/elastic/migrate) folder, create a new file with the filename format `YYYYMMDDHHMMSS_migration_name.rb`. This format is the same for Rails database migrations.
+
+```ruby
+# frozen_string_literal: true
+
+class MigrationName < Elastic::Migration
+ # Important: Any updates to the Elastic index mappings must be replicated in the respective
+ # configuration files:
+ # - `Elastic::Latest::Config`, for the main index.
+ # - `Elastic::Latest::<Type>Config`, for standalone indices.
+
+ def migrate
+ end
+
+ # Check if the migration has completed
+ # Return true if completed, otherwise return false
+ def completed?
+ end
+end
+```
+
+Applied migrations are stored in `gitlab-#{RAILS_ENV}-migrations` index. All migrations not executed
+are applied by the [`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb)
+cron worker sequentially.
+
+To update Elastic index mappings, apply the configuration to the respective files:
+
+- For the main index: [`Elastic::Latest::Config`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/elastic/latest/config.rb).
+- For standalone indices: `Elastic::Latest::<Type>Config`.
+
+Migrations can be built with a retry limit and have the ability to be [failed and marked as halted](https://gitlab.com/gitlab-org/gitlab/-/blob/66e899b6637372a4faf61cfd2f254cbdd2fb9f6d/ee/lib/elastic/migration.rb#L40).
+Any data or index cleanup needed to support migration retries should be handled in the migration.
+
+### Migration helpers
+
+The following migration helpers are available in `ee/app/workers/concerns/elastic/`:
+
+#### `Elastic::MigrationBackfillHelper`
+
+Backfills a specific field in an index. In most cases, the mapping for the field should already be added.
+
+Requires the `index_name` and `field_name` methods.
+
+```ruby
+class MigrationName < Elastic::Migration
+ include Elastic::MigrationBackfillHelper
+
+ private
+
+ def index_name
+ Issue.__elasticsearch__.index_name
+ end
+
+ def field_name
+ :schema_version
+ end
+end
+```
+
+#### `Elastic::MigrationUpdateMappingsHelper`
+
+Updates a mapping in an index by calling `put_mapping` with the mapping specified.
+
+Requires the `index_name` and `new_mappings` methods.
+
+```ruby
+class MigrationName < Elastic::Migration
+ include Elastic::MigrationUpdateMappingsHelper
+
+ private
+
+ def index_name
+ Issue.__elasticsearch__.index_name
+ end
+
+ def new_mappings
+ {
+ schema_version: {
+ type: 'short'
+ }
+ }
+ end
+end
+```
+
+#### `Elastic::MigrationRemoveFieldsHelper`
+
+Removes specified fields from an index.
+
+Requires the `index_name`, `document_type` methods. If there is one field to remove, add the `field_to_remove` method, otherwise add `fields_to_remove` with an array of fields.
+
+Checks in batches if any documents that match `document_type` have the fields specified in Elasticsearch. If documents exist, uses a Painless script to perform `update_by_query`.
+
+```ruby
+class MigrationName < Elastic::Migration
+ include Elastic::MigrationRemoveFieldsHelper
+
+ batched!
+ throttle_delay 1.minute
+
+ private
+
+ def index_name
+ User.__elasticsearch__.index_name
+ end
+
+ def document_type
+ 'user'
+ end
+
+ def fields_to_remove
+ %w[two_factor_enabled has_projects]
+ end
+end
+```
+
+The default batch size is `10_000`. You can override this value by specifying `BATCH_SIZE`:
+
+```ruby
+class MigrationName < Elastic::Migration
+ include Elastic::MigrationRemoveFieldsHelper
+
+ batched!
+ BATCH_SIZE = 100
+
+ ...
+end
+```
+
+#### `Elastic::MigrationObsolete`
+
+Marks a migration as obsolete when it's no longer required.
+
+```ruby
+class MigrationName < Elastic::Migration
+ include Elastic::MigrationObsolete
+end
+```
+
+#### `Elastic::MigrationHelper`
+
+Contains methods you can use when a migration doesn't fit the previous examples.
+
+```ruby
+class MigrationName < Elastic::Migration
+ include Elastic::MigrationHelper
+
+ def migrate
+ ...
+ end
+
+ def completed?
+ ...
+ end
+end
+```
+
+### Migration options supported by the `Elastic::MigrationWorker`
+
+[`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb) supports the following migration options:
+
+- `batched!` - Allow the migration to run in batches. If set, [`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb)
+ re-enqueues itself with a delay which is set using the `throttle_delay` option described below. The batching
+ must be handled in the `migrate` method. This setting controls the re-enqueuing only.
+
+- `batch_size` - Sets the number of documents modified during a `batched!` migration run. This size should be set to a value which allows the updates
+ enough time to finish. This can be tuned in combination with the `throttle_delay` option described below. The batching
+ must be handled in a custom `migrate` method or by using the [`Elastic::MigrationBackfillHelper`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/concerns/elastic/migration_backfill_helper.rb)
+ `migrate` method which uses this setting. Default value is 1000 documents.
+
+- `throttle_delay` - Sets the wait time in between batch runs. This time should be set high enough to allow each migration batch
+ enough time to finish. Additionally, the time should be less than 5 minutes because that is how often the
+ [`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb)
+ cron worker runs. The default value is 3 minutes.
+
+- `pause_indexing!` - Pause indexing while the migration runs. This setting records the indexing setting before
+ the migration runs and set it back to that value when the migration is completed.
+
+- `space_requirements!` - Verify that enough free space is available in the cluster when the migration runs. This setting
+ halts the migration if the storage required is not available when the migration runs. The migration must provide
+ the space required in bytes by defining a `space_required_bytes` method.
+
+- `retry_on_failure` - Enable the retry on failure feature. By default, it retries
+ the migration 30 times. After it runs out of retries, the migration is marked as halted.
+ To customize the number of retries, pass the `max_attempts` argument:
+ `retry_on_failure max_attempts: 10`
+
+```ruby
+# frozen_string_literal: true
+
+class BatchedMigrationName < Elastic::Migration
+ # Declares a migration should be run in batches
+ batched!
+ throttle_delay 10.minutes
+ pause_indexing!
+ space_requirements!
+ retry_on_failure
+
+ # ...
+end
+```
+
+### Multi-version compatibility
+
+These advanced search migrations, like any other GitLab changes, need to support the case where
+[multiple versions of the application are running at the same time](../multi_version_compatibility.md).
+
+Depending on the order of deployment, it's possible that the migration
+has started or finished and there's still a server running the application code from before the
+migration. We need to take this into consideration until we can
+[ensure all advanced search migrations start after the deployment has finished](https://gitlab.com/gitlab-org/gitlab/-/issues/321619).
+
+### Reverting a migration
+
+Because Elasticsearch does not support transactions, we always need to design our
+migrations to accommodate a situation where the application
+code is reverted after the migration has started or after it is finished.
+
+For this reason we generally defer destructive actions (for example, deletions after
+some data is moved) to a later merge request after the migrations have
+completed successfully. To be safe, for self-managed customers we should also
+defer it to another release if there is risk of important data loss.
+
+### Best practices for advanced search migrations
+
+Follow these best practices for best results:
+
+- Order all migrations for each document type so that any migrations that use
+ [`Elastic::MigrationUpdateMappingsHelper`](#elasticmigrationupdatemappingshelper)
+ are executed before migrations that use the
+ [`Elastic::MigrationBackfillHelper`](#elasticmigrationbackfillhelper). This avoids
+ reindexing the same documents multiple times if all of the migrations are unapplied
+ and reduces the backfill time.
+- When working in batches, keep the batch size under 9,000 documents.
+ The bulk indexer is set to run every minute and process a batch
+ of 10,000 documents. This way, the bulk indexer has time to
+ process records before another migration batch is attempted.
+- To ensure that document counts are up to date, you should refresh
+ the index before checking if a migration is completed.
+- Add logging statements to each migration when the migration starts, when a
+ completion check occurs, and when the migration is completed. These logs
+ are helpful when debugging issues with migrations.
+- Pause indexing if you're using any Elasticsearch Reindex API operations.
+- Consider adding a retry limit if there is potential for the migration to fail.
+ This ensures that migrations can be halted if an issue occurs.
+
+## Deleting advanced search migrations in a major version upgrade
+
+Because our advanced search migrations usually require us to support multiple
+code paths for a long period of time, it's important to clean those up when we
+safely can.
+
+We choose to use GitLab major version upgrades as a safe time to remove
+backwards compatibility for indices that have not been fully migrated. We
+[document this in our upgrade documentation](../../update/index.md#upgrading-to-a-new-major-version).
+We also choose to replace the migration code with the halted migration
+and remove tests so that:
+
+- We don't need to maintain any code that is called from our advanced search
+ migrations.
+- We don't waste CI time running tests for migrations that we don't support
+ anymore.
+- Operators who have not run this migration and who upgrade directly to the
+ target version see a message prompting them to reindex from scratch.
+
+To be extra safe, we do not delete migrations that were created in the last
+minor version before the major upgrade. So, if we are upgrading to `%14.0`,
+we should not delete migrations that were only added in `%13.12`. This
+extra safety net allows for migrations that might
+take multiple weeks to finish on GitLab.com. It would be bad if we upgraded
+GitLab.com to `%14.0` before the migrations in `%13.12` were finished. Because
+our deployments to GitLab.com are automated and we don't have
+automated checks to prevent this, the extra precaution is warranted.
+Additionally, even if we did have automated checks to prevent it, we wouldn't
+actually want to hold up GitLab.com deployments on advanced search migrations,
+as they may still have another week to go, and that's too long to block
+deployments.
+
+### Process for removing migrations
+
+For every migration that was created 2 minor versions before the major version
+being upgraded to, we do the following:
+
+1. Confirm the migration has actually completed successfully for GitLab.com.
+1. Replace the content of the migration with:
+
+ ```ruby
+ include Elastic::MigrationObsolete
+ ```
+
+1. Delete any spec files to support this migration.
+1. Remove any logic handling backwards compatibility for this migration. You
+ can find this by looking for
+ `Elastic::DataMigrationService.migration_has_finished?(:migration_name_in_lowercase)`.
+1. Create a merge request with these changes. Noting that we should not
+ accidentally merge this before the major release is started.
diff --git a/doc/development/sec/index.md b/doc/development/sec/index.md
index 5ac5118aae8..f74d31a1fb3 100644
--- a/doc/development/sec/index.md
+++ b/doc/development/sec/index.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: index, concepts, howto
---
-# Sec section development
+# Sec section development guidelines
The Sec section is responsible for GitLab application security features, the "Sec" part of
DevSecOps. Development guides that are specific to the Sec section are listed here.
@@ -88,7 +88,7 @@ In most other cases, the `identifiers` collection is unordered, where the remain
Any time the primary identifier changes and a project pipeline is re-run, ingestion of the new report will "orphan" the previous DB record.
Because our processing logic relies on generating a delta of two different vulnerabilities, it can end up looking rather confusing. For example:
-[!Screenshot of primary identifier mismatch in MR widget](img/primary_identifier_changed_v15_6.png)
+![Screenshot of primary identifier mismatch in MR widget](img/primary_identifier_changed_v15_6.png)
After being [merged](../integrations/secure.md#tracking-and-merging-vulnerabilities), the previous vulnerability is listed as "remediated" and the introduced as ["detected"](../../user/application_security/vulnerabilities/index.md#vulnerability-status-values).
diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md
index 6c64e3b2acc..4f644dd018e 100644
--- a/doc/development/secure_coding_guidelines.md
+++ b/doc/development/secure_coding_guidelines.md
@@ -5,7 +5,7 @@ group: Development
info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines"
---
-# Secure Coding Guidelines
+# Secure coding development guidelines
This document contains descriptions and guidelines for addressing security
vulnerabilities commonly identified in the GitLab codebase. They are intended
@@ -432,7 +432,7 @@ References:
### Select examples of past XSS issues affecting GitLab
-- [Stored XSS in user status](https://gitlab.com/gitlab-org/gitlab-foss/issues/55320)
+- [Stored XSS in user status](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55320)
- [XSS vulnerability on custom project templates form](https://gitlab.com/gitlab-org/gitlab/-/issues/197302)
- [Stored XSS in branch names](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55320)
- [Stored XSS in merge request pages](https://gitlab.com/gitlab-org/gitlab/-/issues/35096)
@@ -542,11 +542,11 @@ print(p.join('log', '/etc/passwd', ''))
# renders the path to "/etc/passwd", which is not what we expect!
```
-#### Golang
+#### Go
-Golang has similar behavior with [`path.Clean`](https://pkg.go.dev/path#example-Clean). Remember that with many file systems, using `../../../../` traverses up to the root directory. Any remaining `../` are ignored. This example may give an attacker access to `/etc/passwd`:
+Go has similar behavior with [`path.Clean`](https://pkg.go.dev/path#example-Clean). Remember that with many file systems, using `../../../../` traverses up to the root directory. Any remaining `../` are ignored. This example may give an attacker access to `/etc/passwd`:
-```golang
+```go
path.Clean("/../../etc/passwd")
// renders the path to "etc/passwd"; the file path is relative to whatever the current directory is
path.Clean("../../etc/passwd")
@@ -601,7 +601,7 @@ Go has built-in protections that usually prevent an attacker from successfully i
Consider the following example:
-```golang
+```go
package main
import (
@@ -620,7 +620,7 @@ This echoes `"1; cat /etc/passwd"`.
**Do not** use `sh`, as it bypasses internal protections:
-```golang
+```go
out, _ = exec.Command("sh", "-c", "echo 1 | cat /etc/passwd").Output()
```
@@ -646,15 +646,15 @@ And the following cipher suites (according to the [RFC 8446](https://datatracker
- `TLS_AES_128_GCM_SHA256`
- `TLS_AES_256_GCM_SHA384`
-*Note*: **Golang** does [not support](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676) all cipher suites with TLS 1.3.
+*Note*: **Go** does [not support](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676) all cipher suites with TLS 1.3.
##### Implementation examples
##### TLS 1.3
-For TLS 1.3, **Golang** only supports [3 cipher suites](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676), as such we only need to set the TLS version:
+For TLS 1.3, **Go** only supports [3 cipher suites](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676), as such we only need to set the TLS version:
-```golang
+```go
cfg := &tls.Config{
MinVersion: tls.VersionTLS13,
}
@@ -678,9 +678,9 @@ response = GitLab::HTTP.perform_request(Net::HTTP::Get, 'https://gitlab.com', ss
##### TLS 1.2
-**Golang** does support multiple cipher suites that we do not want to use with TLS 1.2. We need to explicitly list authorized ciphers:
+**Go** does support multiple cipher suites that we do not want to use with TLS 1.2. We need to explicitly list authorized ciphers:
-```golang
+```go
func secureCipherSuites() []uint16 {
return []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
@@ -692,7 +692,7 @@ func secureCipherSuites() []uint16 {
And then use `secureCipherSuites()` in `tls.Config`:
-```golang
+```go
tls.Config{
(...),
CipherSuites: secureCipherSuites(),
@@ -852,6 +852,31 @@ In the example above, the `is_admin?` method is overwritten when passing it to t
Working with archive files like `zip`, `tar`, `jar`, `war`, `cpio`, `apk`, `rar` and `7z` presents an area where potentially critical security vulnerabilities can sneak into an application.
+### Utilities for safely working with archive files
+
+There are common utilities that can be used to securely work with archive files.
+
+#### Ruby
+
+| Archive type | Utility |
+|--------------|-------------|
+| `zip` | `SafeZip` |
+
+#### `SafeZip`
+
+SafeZip provides a safe interface to extract specific directories or files within a `zip` archive through the `SafeZip::Extract` class.
+
+Example:
+
+```ruby
+Dir.mktmpdir do |tmp_dir|
+ SafeZip::Extract.new(zip_file_path).extract(files: ['index.html', 'app/index.js'], to: tmp_dir)
+ SafeZip::Extract.new(zip_file_path).extract(directories: ['src/', 'test/'], to: tmp_dir)
+rescue SafeZip::Extract::EntrySizeError
+ raise Error, "Path `#{file_path}` has invalid size in the zip!"
+end
+```
+
### Zip Slip
In 2018, the security company Snyk [released a blog post](https://security.snyk.io/research/zip-slip-vulnerability) describing research into a widespread and critical vulnerability present in many libraries and applications which allows an attacker to overwrite arbitrary files on the server file system which, in many cases, can be leveraged to achieve remote code execution. The vulnerability was dubbed Zip Slip.
@@ -895,7 +920,7 @@ end
#### Go
-```golang
+```go
// unzip INSECURELY extracts source zip file to destination.
func unzip(src, dest string) error {
r, err := zip.OpenReader(src)
@@ -991,7 +1016,7 @@ end
You are encouraged to use the secure archive utilities provided by [LabSec](https://gitlab.com/gitlab-com/gl-security/appsec/labsec) which will handle Zip Slip and other types of vulnerabilities for you. The LabSec utilities are also context aware which makes it possible to cancel or timeout extractions:
-```golang
+```go
package main
import "gitlab-com/gl-security/appsec/labsec/archive/zip"
@@ -1016,7 +1041,7 @@ func main() {
In case the LabSec utilities do not fit your needs, here is an example for extracting a zip file with protection against Zip Slip attacks:
-```golang
+```go
// unzip extracts source zip file to destination with protection against Zip Slip attacks.
func unzip(src, dest string) error {
r, err := zip.OpenReader(src)
@@ -1093,7 +1118,7 @@ end
#### Go
-```golang
+```go
// printZipContents INSECURELY prints contents of files in a zip file.
func printZipContents(src string) error {
r, err := zip.OpenReader(src)
@@ -1161,7 +1186,7 @@ You are encouraged to use the secure archive utilities provided by [LabSec](http
In case the LabSec utilities do not fit your needs, here is an example for extracting a zip file with protection against symlink attacks:
-```golang
+```go
// printZipContents prints contents of files in a zip file with protection against symlink attacks.
func printZipContents(src string) error {
r, err := zip.OpenReader(src)
diff --git a/doc/development/service_ping/implement.md b/doc/development/service_ping/implement.md
index ef2e7e6edf5..5bfb81c1d00 100644
--- a/doc/development/service_ping/implement.md
+++ b/doc/development/service_ping/implement.md
@@ -19,7 +19,7 @@ To implement a new metric in Service Ping, follow these steps:
1. [Name and place the metric](metrics_dictionary.md#metric-key_path)
1. [Test counters manually using your Rails console](#test-counters-manually-using-your-rails-console)
1. [Generate the SQL query](#generate-the-sql-query)
-1. [Optimize queries with `#database-lab`](#optimize-queries-with-database-lab)
+1. [Optimize queries with Database Lab](#optimize-queries-with-database-lab)
1. [Add the metric definition to the Metrics Dictionary](#add-the-metric-definition)
1. [Add the metric to the Versions Application](#add-the-metric-to-the-versions-application)
1. [Create a merge request](#create-a-merge-request)
@@ -174,7 +174,7 @@ Errors return a value of `-1`.
WARNING:
This functionality estimates a distinct count of a specific ActiveRecord_Relation in a given column,
-which uses the [HyperLogLog](http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf) algorithm.
+which uses the [HyperLogLog](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/40671.pdf) algorithm.
As the HyperLogLog algorithm is probabilistic, the **results always include error**.
The highest encountered error rate is 4.9%.
@@ -330,48 +330,36 @@ Implemented using Redis methods [PFADD](https://redis.io/commands/pfadd/) and [P
```yaml
- name: users_creating_epics
- category: epics_usage
- redis_slot: users
aggregation: weekly
- feature_flag: track_epics_activity
```
Keys:
- `name`: unique event name.
- Name format for Redis HLL events `<name>_<redis_slot>`.
+ Name format for Redis HLL events `{hll_counters}_<name>`
[See Metric name](metrics_dictionary.md#metric-name) for a complete guide on metric naming suggestion.
- Consider including in the event's name the Redis slot to be able to count totals for a specific category.
-
Example names: `users_creating_epics`, `users_triggering_security_scans`.
- - `category`: event category. Used for getting total counts for events in a category, for easier
- access to a group of events.
- - `redis_slot`: optional Redis slot. Default value: event name. Only event data that is stored in the same slot
- can be aggregated. Ensure keys are in the same slot. For example:
- `users_creating_epics` with `redis_slot: 'users'` builds Redis key
- `{users}_creating_epics-2020-34`. If `redis_slot` is not defined the Redis key will
- be `{users_creating_epics}-2020-34`.
- Recommended slots to use are: `users`, `projects`. This is the value we count.
- `aggregation`: may be set to a `:daily` or `:weekly` key. Defines how counting data is stored in Redis.
Aggregation on a `daily` basis does not pull more fine grained data.
- - `feature_flag`: if no feature flag is set then the tracking is enabled. One feature flag can be used for multiple events. For details, see our [GitLab internal Feature flags](../feature_flags/index.md) documentation. The feature flags are owned by the group adding the event tracking.
1. Use one of the following methods to track the event:
- - In the controller using the `RedisTracking` module and the following format:
+ - In the controller using the `ProductAnalyticsTracking` module and the following format:
```ruby
- track_event(*controller_actions, name:, conditions: nil, destinations: [:redis_hll], &block)
+ track_event(*controller_actions, name:, action:, label:, conditions: nil, destinations: [:redis_hll], &block)
```
Arguments:
- `controller_actions`: the controller actions to track.
- `name`: the event name.
+ - `action`: required if destination is `:snowplow. Action name for the triggered event. See [event schema](../snowplow/index.md#event-schema) for more details.
+ - `label`: required if destination is `:snowplow. Label for the triggered event. See [event schema](../snowplow/index.md#event-schema) for more details.
- `conditions`: optional custom conditions. Uses the same format as Rails callbacks.
- `destinations`: optional list of destinations. Currently supports `:redis_hll` and `:snowplow`. Default: `:redis_hll`.
- `&block`: optional block that computes and returns the `custom_id` that we want to track. This overrides the `visitor_id`.
@@ -381,10 +369,14 @@ Implemented using Redis methods [PFADD](https://redis.io/commands/pfadd/) and [P
```ruby
# controller
class ProjectsController < Projects::ApplicationController
- include RedisTracking
+ include ProductAnalyticsTracking
skip_before_action :authenticate_user!, only: :show
- track_event :index, :show, name: 'users_visiting_projects'
+ track_event :index, :show,
+ name: 'users_visiting_projects',
+ action: 'user_perform_visit',
+ label: 'redis_hll_counters.users_visiting_project_monthly',
+ destinations: %i[redis_hll snowplow]
def index
render html: 'index'
@@ -497,24 +489,12 @@ We have the following recommendations for [adding new events](#add-new-events):
- Event aggregation: weekly.
- When adding new metrics, use a [feature flag](../../operations/feature_flags.md) to control the impact.
-- For feature flags triggered by another service, set `default_enabled: false`,
- - Events can be triggered using the `UsageData` API, which helps when there are > 10 events per change
+It's recommended to disable the new feature flag by default (set `default_enabled: false`).
+- Events can be triggered using the `UsageData` API, which helps when there are > 10 events per change
##### Enable or disable Redis HLL tracking
-Events are tracked behind optional [feature flags](../feature_flags/index.md) due to concerns for Redis performance and scalability.
-
-For a full list of events and corresponding feature flags, see the [`known_events/`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events/) files.
-
-To enable or disable tracking for specific event in <https://gitlab.com> or <https://about.staging.gitlab.com>, run commands such as the following to
-[enable or disable the corresponding feature](../feature_flags/index.md).
-
-```shell
-/chatops run feature set <feature_name> true
-/chatops run feature set <feature_name> false
-```
-
-We can also disable tracking completely by using the global flag:
+We can disable tracking completely by using the global flag:
```shell
/chatops run feature set redis_hll_tracking true
@@ -529,16 +509,6 @@ For each event we add metrics for the weekly and monthly time frames, and totals
- `#{event_name}_weekly`: Data for 7 days for daily [aggregation](#add-new-events) events and data for the last complete week for weekly [aggregation](#add-new-events) events.
- `#{event_name}_monthly`: Data for 28 days for daily [aggregation](#add-new-events) events and data for the last 4 complete weeks for weekly [aggregation](#add-new-events) events.
-Redis HLL implementation calculates total metrics when both of these conditions are met:
-
-- The category is manually included in [CATEGORIES_FOR_TOTALS](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/hll_redis_counter.rb#L21).
-- There is more than one metric for the same category, aggregation, and Redis slot.
-
-We add total unique counts for the weekly and monthly time frames where applicable:
-
-- `#{category}_total_unique_counts_weekly`: Total unique counts for events in the same category for the last 7 days or the last complete week, if events are in the same Redis slot and we have more than one metric.
-- `#{category}_total_unique_counts_monthly`: Total unique counts for events in same category for the last 28 days or the last 4 complete weeks, if events are in the same Redis slot and we have more than one metric.
-
Example of `redis_hll_counters` data:
```ruby
@@ -563,6 +533,7 @@ Example of `redis_hll_counters` data:
"ide_edit_total_unique_counts_weekly"=>0,
"ide_edit_total_unique_counts_monthly"=>0}
}
+}
```
Example:
@@ -674,10 +645,9 @@ pry(main)> Gitlab::UsageData.count(User.active)
(1.9ms) SELECT COUNT("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4)) AND "users"."id" BETWEEN 1 AND 100000
```
-## Optimize queries with `#database-lab`
+## Optimize queries with Database Lab
-`#database-lab` is a Slack channel that uses a production-sized environment to test your queries.
-Paste the SQL query into `#database-lab` to see how the query performs at scale.
+[Database Lab](../database/database_lab.md) is a service that uses a production clone to test queries.
- GitLab.com's production database has a 15 second timeout.
- Any single query must stay below the [1 second execution time](../database/query_performance.md#timing-guidelines-for-queries) with cold caches.
@@ -693,7 +663,7 @@ to a merge request description:
- Query generated for the index and time.
- Migration output for up and down execution.
-We also use `#database-lab` and [explain.depesz.com](https://explain.depesz.com/). For more details, see the [database review guide](../database_review.md#preparation-when-adding-or-modifying-queries).
+For more details, see the [database review guide](../database_review.md#preparation-when-adding-or-modifying-queries).
### Optimization recommendations and examples
@@ -751,7 +721,7 @@ To set up Service Ping locally, you must:
Make sure you run `docker-compose up` to start a PostgreSQL and Redis instance.
1. Point GitLab to the Versions Application endpoint instead of the default endpoint:
1. Open [service_ping/submit_service.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/service_ping/submit_service.rb#L5) locally and modify `STAGING_BASE_URL`.
- 1. Set it to the local Versions Application URL: `http://localhost:3000/usage_data`.
+ 1. Set it to the local Versions Application URL: `http://localhost:3000`.
### Test local setup
@@ -846,7 +816,6 @@ you must fulfill the following requirements:
1. All events listed at `events` attribute must come from
[`known_events/*.yml`](#known-events-are-added-automatically-in-service-data-payload) files.
-1. All events listed at `events` attribute must have the same `redis_slot` attribute.
1. All events listed at `events` attribute must have the same `aggregation` attribute.
1. `time_frame` does not include `all` value, which is unavailable for Redis sourced aggregated metrics.
diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md
index 14c9cb33446..e938de9e253 100644
--- a/doc/development/service_ping/index.md
+++ b/doc/development/service_ping/index.md
@@ -4,7 +4,7 @@ group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Service Ping Guide
+# Service Ping development guidelines
> - Introduced in GitLab Ultimate 11.2, more statistics.
> - In GitLab 14.1, [renamed from Usage Ping to Service Ping](https://gitlab.com/groups/gitlab-org/-/epics/5990). In 14.0 and earlier, use the Usage Ping documentation for the Rails commands appropriate to your version.
@@ -91,23 +91,23 @@ sequenceDiagram
the required URL is <https://version.gitlab.com/>.
1. In case of an error, it will be reported to the Version application along with following pieces of information:
- - `uuid` - GitLab instance unique identifier
- - `hostname` - GitLab instance hostname
- - `version` - GitLab instance current versions
- - `elapsed` - Amount of time which passed since Service Ping report process started and moment of error occurrence
- - `message` - Error message
-
- <pre>
- <code>
- {
- "uuid"=>"02333324-1cd7-4c3b-a45b-a4993f05fb1d",
- "hostname"=>"127.0.0.1",
- "version"=>"14.7.0-pre",
- "elapsed"=>0.006946,
- "message"=>'PG::UndefinedColumn: ERROR: column \"non_existent_attribute\" does not exist\nLINE 1: SELECT COUNT(non_existent_attribute) FROM \"issues\" /*applica...'
- }
- </code>
- </pre>
+ - `uuid` - GitLab instance unique identifier
+ - `hostname` - GitLab instance hostname
+ - `version` - GitLab instance current versions
+ - `elapsed` - Amount of time which passed since Service Ping report process started and moment of error occurrence
+ - `message` - Error message
+
+ <pre>
+ <code>
+ {
+ "uuid"=>"02333324-1cd7-4c3b-a45b-a4993f05fb1d",
+ "hostname"=>"127.0.0.1",
+ "version"=>"14.7.0-pre",
+ "elapsed"=>0.006946,
+ "message"=>'PG::UndefinedColumn: ERROR: column \"non_existent_attribute\" does not exist\nLINE 1: SELECT COUNT(non_existent_attribute) FROM \"issues\" /*applica...'
+ }
+ </code>
+ </pre>
1. Finally, the timing metadata information that is used for diagnostic purposes is submitted to the Versions application. It consists of a list of metric identifiers and the time it took to calculate the metrics:
@@ -135,7 +135,7 @@ sequenceDiagram
]
}
}
- ```
+```
### On a Geo secondary site
@@ -177,7 +177,7 @@ The following is example content of the Service Ping payload.
"recorded_at": "2020-04-17T07:43:54.162+00:00",
"edition": "EEU",
"license_md5": "00000000000000000000000000000000",
- "license_sha256: "0000000000000000000000000000000000000000000000000000000000000000",
+ "license_sha256": "0000000000000000000000000000000000000000000000000000000000000000",
"license_id": null,
"historical_max_users": 999,
"licensee": {
diff --git a/doc/development/service_ping/metrics_dictionary.md b/doc/development/service_ping/metrics_dictionary.md
index 28581f81f94..90ce776af19 100644
--- a/doc/development/service_ping/metrics_dictionary.md
+++ b/doc/development/service_ping/metrics_dictionary.md
@@ -44,9 +44,9 @@ Each metric is defined in a separate YAML file consisting of a number of fields:
| `data_source` | yes | `string`; may be set to a value like `database`, `redis`, `redis_hll`, `prometheus`, `system`, `license`. |
| `data_category` | yes | `string`; [categories](#data-category) of the metric, may be set to `operational`, `optional`, `subscription`, `standard`. The default value is `optional`.|
| `instrumentation_class` | yes | `string`; [the class that implements the metric](metrics_instrumentation.md). |
-| `distribution` | yes | `array`; may be set to one of `ce, ee` or `ee`. The [distribution](https://about.gitlab.com/handbook/marketing/strategic-marketing/tiers/#definitions) where the tracked feature is available. |
+| `distribution` | yes | `array`; may be set to one of `ce, ee` or `ee`. The [distribution](https://about.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/#definitions) where the tracked feature is available. |
| `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/strategic-marketing/tiers/) where the tracked feature is available. This should be verbose and contain all tiers where a metric is available. |
+| `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. |
| `introduced_by_url` | no | The URL to the merge request that introduced the metric to be available for self-managed instances. |
diff --git a/doc/development/service_ping/metrics_instrumentation.md b/doc/development/service_ping/metrics_instrumentation.md
index 80500ccc723..14ec4b8c9a6 100644
--- a/doc/development/service_ping/metrics_instrumentation.md
+++ b/doc/development/service_ping/metrics_instrumentation.md
@@ -154,17 +154,17 @@ end
You can use Redis metrics to track events not kept in the database, for example, a count of how many times the search bar has been used.
-[Example of a merge request that adds a `Redis` metric](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97009).
+[Example of a merge request that adds `Redis` metrics](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103455).
The `RedisMetric` class can only be used as the `instrumentation_class` for Redis metrics with simple counters classes (classes that only inherit `BaseCounter` and set `PREFIX` and `KNOWN_EVENTS` constants). In case the counter class has additional logic included in it, a new `instrumentation_class`, inheriting from `RedisMetric`, needs to be created. This new class needs to include the additional logic from the counter class.
-Count unique values for `source_code_pushes` event.
-
Required options:
- `event`: the event name.
- `prefix`: the value of the `PREFIX` constant used in the counter classes from the `Gitlab::UsageDataCounters` namespace.
+Count unique values for `source_code_pushes` event.
+
```yaml
time_frame: all
data_source: redis
diff --git a/doc/development/service_ping/metrics_lifecycle.md b/doc/development/service_ping/metrics_lifecycle.md
index 8a8ceae1f4c..7fcbafe50f7 100644
--- a/doc/development/service_ping/metrics_lifecycle.md
+++ b/doc/development/service_ping/metrics_lifecycle.md
@@ -82,10 +82,6 @@ To remove a metric:
1. Create an issue for removing the metric if none exists yet. The issue needs to outline why the metric should be deleted. You can use this issue to document the removal process.
-1. Check the following YAML files and verify the metric is not used in an aggregate:
- - [`config/metrics/aggregates/*.yaml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/aggregates/)
- - [`ee/config/metrics/aggregates/*.yaml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/aggregates/)
-
1. Verify the metric is not used to calculate the conversational index. The
conversational index is a measure that reports back to self-managed instances
to inform administrators of the progress of DevOps adoption for the instance.
@@ -115,7 +111,7 @@ To remove a metric:
can be safely removed from Service Ping. Use this
[example issue](https://gitlab.com/gitlab-data/analytics/-/issues/15266) for guidance.
-1. Notify the Customer Success Ops team (`@csops-team`), Analytics Engineers (`@gitlab-data/analytics-engineers`), and Product Analysts (`@gitlab-data/product-analysts`) by `@` mentioning those groups in a comment in the issue regarding the deletion of the metric.
+1. Notify the Customer Success Ops team (`@csops-team`), Analytics Engineers (`@gitlab-data/analytics-engineers`), and Product Analysts (`@gitlab-data/product-analysts`) by `@` mentioning those groups in a comment in the issue from step 1 regarding the deletion of the metric.
Many Service Ping metrics are relied upon for health score and XMAU reporting and unexpected changes to those metrics could break reporting.
1. After you verify the metric can be safely removed,
diff --git a/doc/development/shell_commands.md b/doc/development/shell_commands.md
index d78a005d76b..25f62fbcc98 100644
--- a/doc/development/shell_commands.md
+++ b/doc/development/shell_commands.md
@@ -4,7 +4,7 @@ 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
---
-# Guidelines for shell commands in the GitLab codebase
+# Shell command development guidelines
This document contains guidelines for working with processes and files in the GitLab codebase.
These guidelines are meant to make your code more reliable _and_ secure.
diff --git a/doc/development/sidekiq/compatibility_across_updates.md b/doc/development/sidekiq/compatibility_across_updates.md
index b417a099228..97663b0b41c 100644
--- a/doc/development/sidekiq/compatibility_across_updates.md
+++ b/doc/development/sidekiq/compatibility_across_updates.md
@@ -46,30 +46,30 @@ following example deprecates and then removes `arg2` from the `perform_async` me
1. Provide a default value (usually `nil`) and use a comment to mark the
argument as deprecated in the coming minor release. (Release M)
- ```ruby
- class ExampleWorker
- # Keep arg2 parameter for backwards compatibility.
- def perform(object_id, arg1, arg2 = nil)
- # ...
- end
- end
- ```
+ ```ruby
+ class ExampleWorker
+ # Keep arg2 parameter for backwards compatibility.
+ def perform(object_id, arg1, arg2 = nil)
+ # ...
+ end
+ end
+ ```
1. One minor release later, stop using the argument in `perform_async`. (Release M+1)
- ```ruby
- ExampleWorker.perform_async(object_id, arg1)
- ```
+ ```ruby
+ ExampleWorker.perform_async(object_id, arg1)
+ ```
1. At the next major release, remove the value from the worker class. (Next major release)
- ```ruby
- class ExampleWorker
- def perform(object_id, arg1)
- # ...
- end
- end
- ```
+ ```ruby
+ class ExampleWorker
+ def perform(object_id, arg1)
+ # ...
+ end
+ end
+ ```
### Add an argument
@@ -84,29 +84,29 @@ This approach requires multiple releases.
1. Add the argument to the worker with a default value (Release M).
- ```ruby
- class ExampleWorker
- def perform(object_id, new_arg = nil)
- # ...
- end
- end
- ```
+ ```ruby
+ class ExampleWorker
+ def perform(object_id, new_arg = nil)
+ # ...
+ end
+ end
+ ```
1. Add the new argument to all the invocations of the worker (Release M+1).
- ```ruby
- ExampleWorker.perform_async(object_id, new_arg)
- ```
+ ```ruby
+ ExampleWorker.perform_async(object_id, new_arg)
+ ```
1. Remove the default value (Release M+2).
- ```ruby
- class ExampleWorker
- def perform(object_id, new_arg)
- # ...
- end
- end
- ```
+ ```ruby
+ class ExampleWorker
+ def perform(object_id, new_arg)
+ # ...
+ end
+ end
+ ```
#### Parameter hash
@@ -115,13 +115,13 @@ uses a parameter hash.
1. Use a parameter hash in the worker to allow future flexibility.
- ```ruby
- class ExampleWorker
- def perform(object_id, params = {})
- # ...
- end
- end
- ```
+ ```ruby
+ class ExampleWorker
+ def perform(object_id, params = {})
+ # ...
+ end
+ end
+ ```
## Removing worker classes
@@ -131,54 +131,54 @@ To remove a worker class, follow these steps over two minor releases:
1. Remove any code that enqueues the jobs.
- For example, if there is a UI component or an API endpoint that a user can interact with that results in the worker instance getting enqueued, make sure those surface areas are either removed or updated in a way that the worker instance is no longer enqueued.
+ For example, if there is a UI component or an API endpoint that a user can interact with that results in the worker instance getting enqueued, make sure those surface areas are either removed or updated in a way that the worker instance is no longer enqueued.
- This ensures that instances related to the worker class are no longer being enqueued.
+ This ensures that instances related to the worker class are no longer being enqueued.
1. Ensure both the frontend and backend code no longer relies on any of the work that used to be done by the worker.
1. In the relevant worker classes, replace the contents of the `perform` method with a no-op, while keeping any arguments in tact.
- For example, if you're working with the following `ExampleWorker`:
+ For example, if you're working with the following `ExampleWorker`:
- ```ruby
- class ExampleWorker
- def perform(object_id)
- SomeService.run!(object_id)
- end
- end
- ```
+ ```ruby
+ class ExampleWorker
+ def perform(object_id)
+ SomeService.run!(object_id)
+ end
+ end
+ ```
- Implementing the no-op might look like this:
+ Implementing the no-op might look like this:
- ```ruby
- class ExampleWorker
- def perform(object_id); end
- end
- ```
+ ```ruby
+ class ExampleWorker
+ def perform(object_id); end
+ end
+ ```
- By implementing this no-op, you can avoid unnecessary cycles once any deprecated jobs that are still enqueued eventually get processed.
+ By implementing this no-op, you can avoid unnecessary cycles once any deprecated jobs that are still enqueued eventually get processed.
### In a subsequent, separate minor release
1. Delete the worker class file and follow the guidance in our [Sidekiq queues documentation](../sidekiq/index.md#sidekiq-queues) around running Rake tasks to regenerate/update related files.
1. Add a migration (not a post-deployment migration) that uses `sidekiq_remove_jobs`:
- ```ruby
- class RemoveMyDeprecatedWorkersJobInstances < Gitlab::Database::Migration[2.0]
- DEPRECATED_JOB_CLASSES = %w[
- MyDeprecatedWorkerOne
- MyDeprecatedWorkerTwo
- ]
-
- 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
- ```
+ ```ruby
+ class RemoveMyDeprecatedWorkersJobInstances < Gitlab::Database::Migration[2.0]
+ DEPRECATED_JOB_CLASSES = %w[
+ MyDeprecatedWorkerOne
+ MyDeprecatedWorkerTwo
+ ]
+
+ 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
+ ```
## Renaming queues
diff --git a/doc/development/sidekiq/index.md b/doc/development/sidekiq/index.md
index 355f5a3b753..2010a21130d 100644
--- a/doc/development/sidekiq/index.md
+++ b/doc/development/sidekiq/index.md
@@ -4,7 +4,7 @@ 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
---
-# Sidekiq guides
+# Sidekiq development guidelines
We use [Sidekiq](https://github.com/mperham/sidekiq) as our background
job processor. These guides are for writing jobs that works well on
diff --git a/doc/development/snowplow/event_dictionary_guide.md b/doc/development/snowplow/event_dictionary_guide.md
index 794a9a0160c..dc2214a40ed 100644
--- a/doc/development/snowplow/event_dictionary_guide.md
+++ b/doc/development/snowplow/event_dictionary_guide.md
@@ -39,8 +39,8 @@ Each event is defined in a separate YAML file consisting of the following fields
| `product_category` | no | The [product category](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml) for the event. |
| `milestone` | no | The milestone when the event is introduced. |
| `introduced_by_url` | no | The URL to the merge request that introduced the event. |
-| `distributions` | yes | The [distributions](https://about.gitlab.com/handbook/marketing/strategic-marketing/tiers/#definitions) where the tracked feature is available. Can be set to one or more of `ce` or `ee`. |
-| `tiers` | yes | The [tiers]( https://about.gitlab.com/handbook/marketing/strategic-marketing/tiers/) where the tracked feature is available. Can be set to one or more of `free`, `premium`, or `ultimate`. |
+| `distributions` | yes | The [distributions](https://about.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/#definitions) where the tracked feature is available. Can be set to one or more of `ce` or `ee`. |
+| `tiers` | yes | The [tiers](https://about.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/) where the tracked feature is available. Can be set to one or more of `free`, `premium`, or `ultimate`. |
### Example event definition
@@ -79,14 +79,13 @@ tiers:
Use the dedicated [event definition generator](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/generators/gitlab/snowplow_event_definition_generator.rb)
to create new event definitions.
-The `category` and `action` of each event are included in the filename to enforce uniqueness.
+The `category` and `action` of each event are included in the filename to standardize file naming.
The generator takes three options:
- `--ee`: Indicates if the event is for EE.
- `--category=CATEGORY`: Indicates the `category` of the event.
- `--action=ACTION`: Indicates the `action` of the event.
-- `--force`: Overwrites the existing event definition, if one already exists.
```shell
bundle exec rails generate gitlab:snowplow_event_definition --category Groups::EmailCampaignsController --action click
diff --git a/doc/development/snowplow/implementation.md b/doc/development/snowplow/implementation.md
index 40b8b7b3da8..ae90b45b1f0 100644
--- a/doc/development/snowplow/implementation.md
+++ b/doc/development/snowplow/implementation.md
@@ -150,89 +150,89 @@ To implement Vue component tracking:
1. Import the `Tracking` library and call the `mixin` method:
- ```javascript
- import Tracking from '~/tracking';
+ ```javascript
+ import Tracking from '~/tracking';
- const trackingMixin = Tracking.mixin();
+ const trackingMixin = Tracking.mixin();
- // Optionally provide default properties
- // const trackingMixin = Tracking.mixin({ label: 'right_sidebar' });
- ```
+ // Optionally provide default properties
+ // const trackingMixin = Tracking.mixin({ label: 'right_sidebar' });
+ ```
1. Use the mixin in the component:
- ```javascript
- export default {
- mixins: [trackingMixin],
- // Or
- // mixins: [Tracking.mixin()],
- // mixins: [Tracking.mixin({ label: 'right_sidebar' })],
-
- data() {
- return {
- expanded: false,
- };
- },
- };
- ```
+ ```javascript
+ export default {
+ mixins: [trackingMixin],
+ // Or
+ // mixins: [Tracking.mixin()],
+ // mixins: [Tracking.mixin({ label: 'right_sidebar' })],
+
+ data() {
+ return {
+ expanded: false,
+ };
+ },
+ };
+ ```
1. You can specify tracking options in by creating a `tracking` data object
or computed property:
- ```javascript
- export default {
- name: 'RightSidebar',
-
- mixins: [Tracking.mixin()],
-
- data() {
- return {
- expanded: false,
- variant: '',
- tracking: {
- label: 'right_sidebar',
- // property: '',
- // value: '',
- // experiment: '',
- // extra: {},
- },
- };
- },
-
- // Or
- // computed: {
- // tracking() {
- // return {
- // property: this.variant,
- // extra: { expanded: this.expanded },
- // };
- // },
- // },
- };
- ```
+ ```javascript
+ export default {
+ name: 'RightSidebar',
+
+ mixins: [Tracking.mixin()],
+
+ data() {
+ return {
+ expanded: false,
+ variant: '',
+ tracking: {
+ label: 'right_sidebar',
+ // property: '',
+ // value: '',
+ // experiment: '',
+ // extra: {},
+ },
+ };
+ },
+
+ // Or
+ // computed: {
+ // tracking() {
+ // return {
+ // property: this.variant,
+ // extra: { expanded: this.expanded },
+ // };
+ // },
+ // },
+ };
+ ```
1. Call the `track` method. Tracking options can be passed as the second parameter:
- ```javascript
- this.track('click_button', {
- label: 'right_sidebar',
- });
- ```
+ ```javascript
+ this.track('click_button', {
+ label: 'right_sidebar',
+ });
+ ```
- Or use the `track` method in the template:
+ Or use the `track` method in the template:
- ```html
- <template>
- <div>
- <button data-testid="toggle" @click="toggle">Toggle</button>
+ ```html
+ <template>
+ <div>
+ <button data-testid="toggle" @click="toggle">Toggle</button>
- <div v-if="expanded">
- <p>Hello world!</p>
- <button @click="track('click_button')">Track another event</button>
- </div>
- </div>
- </template>
- ```
+ <div v-if="expanded">
+ <p>Hello world!</p>
+ <button @click="track('click_button')">Track another event</button>
+ </div>
+ </div>
+ </template>
+ ```
#### Testing example
@@ -473,9 +473,7 @@ For a video tutorial, see the [Snowplow plugin walk through](https://www.youtube
1. To open the extension, select the Snowplow Inspector icon beside the address bar.
1. Click around on a webpage with Snowplow to see JavaScript events firing in the inspector window.
-### Test backend events
-
-#### Snowplow Micro
+### Test backend events with Snowplow Micro
[Snowplow Micro](https://snowplow.io/blog/introducing-snowplow-micro/) is a
Docker-based solution for testing backend and frontend in a local development environment. Snowplow Micro
@@ -484,50 +482,10 @@ records the same events as the full Snowplow pipeline. To query events, use the
It can be set up automatically using [GitLab Development Kit (GDK)](https://gitlab.com/gitlab-org/gitlab-development-kit).
See the [how-to docs](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/snowplow_micro.md) for more details.
-Optionally, you can set it up manually, using the following instructions.
-
-#### Set up Snowplow Micro manually
-
-To install and run Snowplow Micro, complete these steps to modify the
-[GitLab Development Kit (GDK)](https://gitlab.com/gitlab-org/gitlab-development-kit):
-
-1. Ensure [Docker is installed](https://docs.docker.com/get-docker/) and running.
-
-1. To install Snowplow Micro, clone the settings in
-[this project](https://gitlab.com/gitlab-org/snowplow-micro-configuration).
-
-1. Navigate to the directory with the cloned project,
- and start the appropriate Docker container:
-
- ```shell
- ./snowplow-micro.sh
- ```
-
1. Set the environment variable to tell the GDK to use Snowplow Micro in development. This overrides two `application_settings` options:
- `snowplow_enabled` setting will instead return `true` from `Gitlab::Tracking.enabled?`
- `snowplow_collector_hostname` setting will instead always return `localhost:9090` (or whatever port is set for `snowplow_micro.port` GDK setting) from `Gitlab::Tracking.collector_hostname`.
-
- ```shell
- gdk config set snowplow_micro.enabled true
- ```
-
- Optionally, you can set the port for you Snowplow Micro instance as well (the default value is `9090`):
-
- ```shell
- gdk config set snowplow_micro.port 8080
- ```
-
-1. Regenerate the project YAML config:
-
- ```shell
- gdk reconfigure
- ```
-
-1. Restart GDK:
-
- ```shell
- gdk restart
- ```
+With Snowplow Micro set up you can now manually test backend Snowplow events:
1. Send a test Snowplow event from the Rails console:
diff --git a/doc/development/snowplow/index.md b/doc/development/snowplow/index.md
index 6acbd72175e..276b5913890 100644
--- a/doc/development/snowplow/index.md
+++ b/doc/development/snowplow/index.md
@@ -4,7 +4,7 @@ group: Product Intelligence
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Snowplow
+# Snowplow development guidelines
Snowplow is an enterprise-grade marketing and Product Intelligence platform that tracks how users engage with our website and application.
diff --git a/doc/development/snowplow/review_guidelines.md b/doc/development/snowplow/review_guidelines.md
index ee2c1eb95df..da7f2bc2781 100644
--- a/doc/development/snowplow/review_guidelines.md
+++ b/doc/development/snowplow/review_guidelines.md
@@ -28,7 +28,7 @@ events or touches Snowplow related files.
- For frontend events, when relevant, add a screenshot of the event in
the [testing tool](implementation.md#develop-and-test-snowplow) used.
- For backend events, when relevant, add the output of the
- [Snowplow Micro](implementation.md#snowplow-micro) good events
+ [Snowplow Micro](implementation.md#test-backend-events-with-snowplow-micro) good events
`GET http://localhost:9090/micro/good` (it might be a good idea
to reset with `GET http://localhost:9090/micro/reset` first).
- Update the [Event Dictionary](event_dictionary_guide.md).
@@ -41,3 +41,4 @@ events or touches Snowplow related files.
- If needed, check that the events are firing locally using one of the
[testing tools](implementation.md#develop-and-test-snowplow) available.
- Approve the MR, and relabel the MR with `~"product intelligence::approved"`.
+- If the snowplow event mirrors a RedisHLL event, then tag @mdrussell to review if the payload is usable for this purpose.
diff --git a/doc/development/spam_protection_and_captcha/exploratory_testing.md b/doc/development/spam_protection_and_captcha/exploratory_testing.md
index b2d780b1563..f2812cd6de9 100644
--- a/doc/development/spam_protection_and_captcha/exploratory_testing.md
+++ b/doc/development/spam_protection_and_captcha/exploratory_testing.md
@@ -32,6 +32,7 @@ Enable any relevant feature flag, if the spam/CAPTCHA support is behind a featur
1. For **Site key**, use: `6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI`
1. For **Secret key**, use: `6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe`
1. Go to **Admin -> Settings -> Reporting** settings: `http://gdk.test:3000/admin/application_settings/reporting#js-spam-settings`
+ 1. Expand the **Spam and Anti-bot Protection** section.
1. Select **Enable reCAPTCHA**. Enabling for login is not required unless you are testing that feature.
1. Enter the **Site key** and **Secret key**.
1. To set up Akismet:
diff --git a/doc/development/spam_protection_and_captcha/model_and_services.md b/doc/development/spam_protection_and_captcha/model_and_services.md
index 9c5d389a2f5..2c7ec8c3f50 100644
--- a/doc/development/spam_protection_and_captcha/model_and_services.md
+++ b/doc/development/spam_protection_and_captcha/model_and_services.md
@@ -35,9 +35,9 @@ To do this:
designate which fields to consider the "`title`" or "`description`". For example,
this line designates the `content` field as the `description`:
- ```ruby
- attr_spammable :content, spam_description: true
- ```
+ ```ruby
+ attr_spammable :content, spam_description: true
+ ```
1. Add a `#check_for_spam?` method implementation:
diff --git a/doc/development/stage_group_observability/img/error_budgets_kibana_dashboard_v15_10.png b/doc/development/stage_group_observability/img/error_budgets_kibana_dashboard_v15_10.png
new file mode 100644
index 00000000000..e4f54b579c1
--- /dev/null
+++ b/doc/development/stage_group_observability/img/error_budgets_kibana_dashboard_v15_10.png
Binary files differ
diff --git a/doc/development/stage_group_observability/index.md b/doc/development/stage_group_observability/index.md
index b275b0bfec2..ba17b4cc73a 100644
--- a/doc/development/stage_group_observability/index.md
+++ b/doc/development/stage_group_observability/index.md
@@ -68,11 +68,11 @@ component can have two indicators:
and
[Web](https://gitlab.com/gitlab-com/runbooks/-/blob/f22f40b2c2eab37d85e23ccac45e658b2c914445/metrics-catalog/services/web.jsonnet#L154)
services, that threshold is **5 seconds** when not opted in to the
- [`rails_requests` SLI](../application_slis/rails_request_apdex.md).
+ [`rails_request` SLI](../application_slis/rails_request.md).
We've made this target configurable in [this project](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/525).
- To learn how to customize the request Apdex, see
- [Rails request Apdex SLI](../application_slis/rails_request_apdex.md).
+ To customize the request Apdex, see
+ [Rails request SLIs](../application_slis/rails_request.md).
This new Apdex measurement is not part of the error budget until you
[opt in](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1451).
@@ -136,3 +136,39 @@ For example, see the `server` component of the `web-pages` service:
![web-pages-server-component SLI](img/stage_group_dashboards_service_sli_detail.png)
To add more SLIs tailored to specific features, you can use an [Application SLI](../application_slis/index.md).
+
+## Kibana dashboard for error budgets
+
+For a detailed analysis you can use [a specialized Kibana dashboard](https://log.gprd.gitlab.net/goto/771b5c10-c0ec-11ed-85ed-e7557b0a598c), like this:
+
+![Kibana dashboard](img/error_budgets_kibana_dashboard_v15_10.png)
+
+Description:
+
+- **Apdex requests over limit (graph)** - Displays only requests that exceeded their
+ target duration.
+- **Apdex operations over-limit duration (graph)** - Displays the distribution of duration
+ components (database, Redis, Gitaly, and Rails app).
+- **Apdex requests** (pie chart) - Displays the percentage of `2xx`, `3xx`, `4xx` and
+ `5xx` requests.
+- **Slow request component distribution** - Highlights the component responsible
+ for Apdex violation.
+- **Apdex operations over limit** (table) - Displays a number of operations over
+ limit for each endpoint.
+- **Apdex requests over limit** - Displays a list of individual requests responsible
+ for Apdex violation.
+
+### Use the dashboard
+
+1. Select the feature category you want to investigate.
+ 1. Scroll to the **Feature Category** section. Enter the feature name.
+ 1. Select **Apply changes**. Selected results contain only requests related to this feature category.
+1. Select the time frame for the investigation.
+1. Review dashboard and pay attention to the type of failures.
+
+Questions to answer:
+
+1. Does the failure pattern look like a spike? Or does it persist?
+1. Does the failure look related to a particular component? (database, Redis, ...)
+1. Does the failure affect a specific endpoint? Or is it system-wide?
+1. Does the failure appear caused by infrastructure incidents?
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 54d3f368bbd..a9d17472a9f 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -507,6 +507,8 @@ If needed, you can scope interactions within a specific area of the page by usin
As you will likely be scoping to an element such as a `div`, which typically does not have a label,
you may use a `data-testid` selector in this case.
+You can use the `be_axe_clean` matcher to run [axe automated accessibility testing](../fe_guide/accessibility.md#automated-accessibility-testing-with-axe) in feature tests.
+
##### Externalized contents
Test expectations against externalized contents should call the same
diff --git a/doc/development/testing_guide/contract/index.md b/doc/development/testing_guide/contract/index.md
index 31d68bb9f4f..cf23792e239 100644
--- a/doc/development/testing_guide/contract/index.md
+++ b/doc/development/testing_guide/contract/index.md
@@ -42,11 +42,11 @@ rake contracts:merge_requests:test:merge_requests[contract_merge_requests]
#### Verify the contracts in Pact Broker
-By default, the Rake tasks will verify the locally stored contracts. In order to verify the contracts published in the Pact Broker, we need to set the `PACT_BROKER` environment variable to `true`. It is important to point out here that the file path and file name of the provider test is what is used to find the contract in the Pact Broker which is why it is important to make sure the [provider test naming conventions](#provider-naming) are followed.
+By default, the Rake tasks will verify the locally stored contracts. In order to verify the contracts published in the Pact Broker, we need to set the `PACT_BROKER` environment variable to `true` and the `QA_PACT_BROKER_HOST` to the URL of the Pact Broker. It is important to point out here that the file path and file name of the provider test is what is used to find the contract in the Pact Broker which is why it is important to make sure the [provider test naming conventions](#provider-naming) are followed.
## Publish contracts to Pact Broker
-The contracts generated by the consumer test can be published to a hosted Pact Broker by going to `spec/contracts` and running the `publish-contracts.sh` script.
+The contracts generated by the consumer test can be published to a hosted Pact Broker by setting the `QA_PACT_BROKER_HOST` environment variable and running the [`publish-contracts.sh`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/spec/contracts/publish-contracts.sh) script.
## Test suite folder structure and naming conventions
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 b81379d89b2..07a9bcb2f5c 100644
--- a/doc/development/testing_guide/end_to_end/beginners_guide.md
+++ b/doc/development/testing_guide/end_to_end/beginners_guide.md
@@ -87,7 +87,7 @@ file `basic_login_spec.rb`.
See the [`RSpec.describe` outer block](#the-outer-rspecdescribe-block)
WARNING:
-The outer `context` [was deprecated](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/550) in `13.2`
+The outer `context` [was deprecated](https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/550) in `13.2`
in adherence to RSpec 4.0 specifications. Use `RSpec.describe` instead.
### The outer `RSpec.describe` block
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 777a9f47339..fd184c13e5e 100644
--- a/doc/development/testing_guide/end_to_end/best_practices.md
+++ b/doc/development/testing_guide/end_to_end/best_practices.md
@@ -16,9 +16,9 @@ In case custom inflection logic is needed, custom inflectors are added in the [q
## Link a test to its test case
-Every test should have a corresponding test case in the [GitLab project Test Cases](https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases) as well as a results issue in the [Quality Test Cases project](https://gitlab.com/gitlab-org/quality/testcases/-/issues).
+Every test should have a corresponding test case in the [GitLab project test cases](https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases) as well as a results issue in the [Quality Test Cases project](https://gitlab.com/gitlab-org/quality/testcases/-/issues).
If a test case issue does not yet exist, any GitLab team member can create a new test case in
-the [Test Cases](https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases) GitLab project
+the **[CI/CD > Test cases](https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases)** page of the GitLab project
with a placeholder title. After the test case URL is linked to a test in the code, when the test is
run in a pipeline that has reporting enabled, the `report-results` script automatically updates the
test case and the results issue.
diff --git a/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md b/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
index c1389b3ac0e..c9e60c06732 100644
--- a/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
+++ b/doc/development/testing_guide/end_to_end/rspec_metadata_tests.md
@@ -52,5 +52,5 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
| `:skip_signup_disabled` | The test uses UI to sign up a new user and is skipped in any environment that does not allow new user registration via the UI. |
| `:smoke` | The test belongs to the test suite which verifies basic functionality of a GitLab instance. |
| `:smtp` | The test requires a GitLab instance to be configured to use an SMTP server. Tests SMTP notification email delivery from GitLab by using MailHog. |
-| `:testcase` | The link to the test case issue in the [GitLab Project Test Cases](https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases). |
+| `:testcase` | The link to the test case issue in the [GitLab Project test cases](https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases). |
| `:transient` | The test tests transient bugs. It is excluded by default. |
diff --git a/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md b/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
index 4a947e59d5f..0d6d7a161c7 100644
--- a/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
+++ b/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
@@ -219,7 +219,7 @@ Geo requires an EE license. To visit the Geo sites in your browser, you need a r
# Using a full image address
GITLAB_QA_ACCESS_TOKEN=your-token-here gitlab-qa Test::Integration::Geo registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:examplesha123456789 --no-teardown
- ```
+ ```
You can use the `--no-tests` option to build the containers only, and then run the [`EE::Scenario::Test::Geo` scenario](https://gitlab.com/gitlab-org/gitlab/-/blob/f7272b77e80215c39d1ffeaed27794c220dbe03f/qa/qa/ee/scenario/test/geo.rb) from your GDK to complete setup and run tests. However, there might be configuration issues if your GDK and the containers are based on different GitLab versions. With the `--no-teardown` option, GitLab-QA uses the same GitLab version for the GitLab containers and the GitLab QA container used to configure the Geo setup.
@@ -369,15 +369,15 @@ To run the LDAP tests on your local with TLS disabled, follow these steps:
1. Run the GitLab container:
- ```shell
- sudo docker run \
- --hostname localhost \
- --net test \
- --publish 443:443 --publish 80:80 --publish 22:22 \
- --name gitlab \
- --env GITLAB_OMNIBUS_CONFIG="gitlab_rails['ldap_enabled'] = true; gitlab_rails['ldap_servers'] = {\"main\"=>{\"label\"=>\"LDAP\", \"host\"=>\"ldap-server.test\", \"port\"=>389, \"uid\"=>\"uid\", \"bind_dn\"=>\"cn=admin,dc=example,dc=org\", \"password\"=>\"admin\", \"encryption\"=>\"plain\", \"verify_certificates\"=>false, \"base\"=>\"dc=example,dc=org\", \"user_filter\"=>\"\", \"group_base\"=>\"ou=Global Groups,dc=example,dc=org\", \"admin_group\"=>\"AdminGroup\", \"external_groups\"=>\"\", \"sync_ssh_keys\"=>false}}; gitlab_rails['ldap_sync_worker_cron'] = '* * * * *'; gitlab_rails['ldap_group_sync_worker_cron'] = '* * * * *'; " \
- gitlab/gitlab-ee:latest
- ```
+ ```shell
+ sudo docker run \
+ --hostname localhost \
+ --net test \
+ --publish 443:443 --publish 80:80 --publish 22:22 \
+ --name gitlab \
+ --env GITLAB_OMNIBUS_CONFIG="gitlab_rails['ldap_enabled'] = true; gitlab_rails['ldap_servers'] = {\"main\"=>{\"label\"=>\"LDAP\", \"host\"=>\"ldap-server.test\", \"port\"=>389, \"uid\"=>\"uid\", \"bind_dn\"=>\"cn=admin,dc=example,dc=org\", \"password\"=>\"admin\", \"encryption\"=>\"plain\", \"verify_certificates\"=>false, \"base\"=>\"dc=example,dc=org\", \"user_filter\"=>\"\", \"group_base\"=>\"ou=Global Groups,dc=example,dc=org\", \"admin_group\"=>\"AdminGroup\", \"external_groups\"=>\"\", \"sync_ssh_keys\"=>false}}; gitlab_rails['ldap_sync_worker_cron'] = '* * * * *'; gitlab_rails['ldap_group_sync_worker_cron'] = '* * * * *'; " \
+ gitlab/gitlab-ee:latest
+ ```
1. Run an LDAP test from [`gitlab/qa`](https://gitlab.com/gitlab-org/gitlab/-/tree/d5447ebb5f99d4c72780681ddf4dc25b0738acba/qa) directory:
diff --git a/doc/development/testing_guide/flaky_tests.md b/doc/development/testing_guide/flaky_tests.md
index f476815bf32..c626a4fa81c 100644
--- a/doc/development/testing_guide/flaky_tests.md
+++ b/doc/development/testing_guide/flaky_tests.md
@@ -251,9 +251,9 @@ which would give us the minimal test combination to reproduce the failure:
for the list under `Knapsack node specs:` in the CI job output log.
1. Save the list of specs as a file, and run:
- ```shell
- cat knapsack_specs.txt | xargs scripts/rspec_bisect_flaky
- ```
+ ```shell
+ cat knapsack_specs.txt | xargs scripts/rspec_bisect_flaky
+ ```
If there is an order-dependency issue, the script above will print the minimal
reproduction.
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 85d807eceb1..6134e0f9959 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -520,6 +520,25 @@ it('waits for an event', () => {
});
```
+### Manipulate `gon` object
+
+`gon` (or `window.gon`) is a global object used to pass data from the backend. If your test depends
+on its value you can directly modify it:
+
+```javascript
+describe('when logged in', () => {
+ beforeEach(() => {
+ gon.current_user_id = 1;
+ });
+
+ it('shows message', () => {
+ expect(wrapper.text()).toBe('Logged in!');
+ });
+})
+```
+
+`gon` is reset in every test to ensure tests are isolated.
+
### Ensuring that tests are isolated
Tests are normally architected in a pattern which requires a recurring setup of the component under test. This is often achieved by making use of the `beforeEach` hook.
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index b074a9e34f3..7958d6db706 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -276,7 +276,7 @@ find a way to limit it to only us.**
## Other resources
- [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/team-tasks/-/issues/212)
+- [Stability issues](https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/212)
### Helpful command line tools
diff --git a/doc/development/testing_guide/testing_levels.md b/doc/development/testing_guide/testing_levels.md
index c93a5fd539b..187d30c12be 100644
--- a/doc/development/testing_guide/testing_levels.md
+++ b/doc/development/testing_guide/testing_levels.md
@@ -300,7 +300,7 @@ graph RL
- **DOM**:
Testing on the real DOM ensures your components work in the intended environment.
- Part of DOM testing is delegated to [cross-browser testing](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/45).
+ Part of DOM testing is delegated to [cross-browser testing](https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/45).
- **Properties or state of components**:
On this level, all tests can only perform actions a user would do.
For example: to change the state of a component, a click event would be fired.
diff --git a/doc/development/uploads/index.md b/doc/development/uploads/index.md
index b5509f5934e..a62e8ea2d58 100644
--- a/doc/development/uploads/index.md
+++ b/doc/development/uploads/index.md
@@ -4,7 +4,7 @@ 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
---
-# Uploads development guide
+# Uploads development guidelines
Uploads are an integral part of many GitLab features. To understand how GitLab handles uploads, this page
provides an overview of the key mechanisms for transferring files to a storage destination.
diff --git a/doc/development/uploads/working_with_uploads.md b/doc/development/uploads/working_with_uploads.md
index 6955f9c31cd..5575297ad6b 100644
--- a/doc/development/uploads/working_with_uploads.md
+++ b/doc/development/uploads/working_with_uploads.md
@@ -95,7 +95,7 @@ They consist of:
Example:
-```golang
+```go
u.route("PUT", apiProjectPattern+`packages/nuget/`, mimeMultipartUploader),
```
diff --git a/doc/development/ux/index.md b/doc/development/ux/index.md
new file mode 100644
index 00000000000..784a59a3a4a
--- /dev/null
+++ b/doc/development/ux/index.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
+---
+
+# Contribute to UX design
+
+## UX Design
+
+These instructions are specifically for those wanting to make UX design contributions to GitLab.
+
+The UX department at GitLab uses [Figma](https://www.figma.com/) for all of its designs, and you can see our [Design Repository documentation](https://gitlab.com/gitlab-org/gitlab-design/blob/master/README.md#getting-started) for details on working with our files.
+
+You may leverage the [Pajamas UI Kit](https://www.figma.com/community/file/781156790581391771) in Figma to create mockups for your proposals. However, we will also gladly accept handmade drawings and sketches, wireframes, manipulated DOM screenshots, or prototypes. You can find design resources documentation in our [Design System](https://design.gitlab.com/). Use it to understand where and when to use common design solutions.
+
+## Contributing to Pajamas
+
+To contribute to [Pajamas design system](https://design.gitlab.com/) and the [UI kit](https://www.figma.com/community/file/781156790581391771), follow the [contribution guidelines](https://design.gitlab.com/get-started/contribute) documented in the handbook. While the instructions are code-focused, they will help you understand the overall process of contributing.
+
+## Contributing to other issues
+
+1. Review the list of available issues that are currently [accepting UX contribution](https://gitlab.com/groups/gitlab-org/-/issues/?sort=weight&state=opened&label_name%5B%5D=UX&label_name%5B%5D=workflow%3A%3Aready%20for%20design&label_name%5B%5D=Accepting%20UX%20contributions&first_page_size=20).
+1. Find an issue that does not have an Assignee to ensure someone else is not working on a solution. Add the `~"workflow::design"` and `~"Community contribution"` labels and mention `@gitlab-com/gitlab-ux/reviewers` to request they assign the issue to you.
+1. Add your design proposal to the issue description/[design management](../../user/project/issues/design_management.md) section. Remember to keep the scope of the proposal/change small following our [MVCs guidelines](https://about.gitlab.com/handbook/values/#minimal-viable-change-mvc).
+1. If you have any questions or are ready for a review of your proposal, mention `@gitlab-com/gitlab-ux/reviewers` in a comment to make your request.
diff --git a/doc/development/value_stream_analytics.md b/doc/development/value_stream_analytics.md
index 77a32b62e32..634c337793f 100644
--- a/doc/development/value_stream_analytics.md
+++ b/doc/development/value_stream_analytics.md
@@ -4,7 +4,7 @@ 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
---
-# Value stream analytics development guide
+# Value stream analytics development guidelines
For information on how to configure value stream analytics (VSA) in GitLab, see our [analytics documentation](../user/analytics/value_stream_analytics.md).
@@ -65,7 +65,7 @@ of the stage. Stages are configurable by the user within the pairing rules defin
IDs are identical.
- The stage event hash ID is later used to store the aggregated data in partitioned database tables.
-Historically, value stream analytics defined [7 stages](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/analytics/cycle_analytics/default_stages.rb)
+Historically, value stream analytics defined [six stages](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/analytics/cycle_analytics/default_stages.rb)
which are always available to the end-users regardless of the subscription.
### Value streams
diff --git a/doc/development/wikis.md b/doc/development/wikis.md
index acb7ed335d3..2f97931f924 100644
--- a/doc/development/wikis.md
+++ b/doc/development/wikis.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
description: "GitLab's development guidelines for Wikis"
---
-# Wikis development guide
+# Wikis development guidelines
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227027) in GitLab 13.5.
diff --git a/doc/development/windows.md b/doc/development/windows.md
index bf56e16344a..99085b4b5f8 100644
--- a/doc/development/windows.md
+++ b/doc/development/windows.md
@@ -13,7 +13,7 @@ This is a guide for how to get a Windows development virtual machine on Google C
## Why Windows in Google Cloud?
-Use of Microsoft Windows operating systems on company laptops is banned under the GitLab [Approved Operating Systems policy](https://about.gitlab.com/handbook/security/approved_os.html#windows).
+Use of Microsoft Windows operating systems on company laptops is banned under the GitLab [Approved Operating Systems policy](https://about.gitlab.com/handbook/it/operating-systems/#windows).
This can make it difficult to develop features for the Windows platforms. Using GCP allows us to have a temporary Windows machine that can be removed once we're done with it.
diff --git a/doc/development/workspace/index.md b/doc/development/workspace/index.md
index 0e0b6943a0b..ca404702d72 100644
--- a/doc/development/workspace/index.md
+++ b/doc/development/workspace/index.md
@@ -1,159 +1,11 @@
---
-comments: false
-type: index, dev
-stage: none
-group: Development
-info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines"
-description: "Development Guidelines: learn about organization when developing GitLab."
+redirect_to: '../organization/index.md'
+remove_date: '2023-06-13'
---
-# Organization
+This document was moved to [another location](../organization/index.md).
-The [Organization initiative](../../user/workspace/index.md) focuses on reaching feature parity between
-SaaS and self-managed installations.
-
-## Consolidate groups and projects
-
-- [Architecture blueprint](../../architecture/blueprints/consolidating_groups_and_projects/index.md)
-
-One facet of the Organization initiative is to consolidate groups and projects,
-addressing the feature disparity between them. Some features, such as epics, are
-only available at the group level. Some features, such as issues, are only available
-at the project level. Other features, such as milestones, are available to both groups
-and projects.
-
-We receive many requests to add features either to the group or project level.
-Moving features around to different levels is problematic on multiple levels:
-
-- It requires engineering time to move the features.
-- It requires UX overhead to maintain mental models of feature availability.
-- It creates redundant code.
-
-When features are copied from one level (project, group, or instance) to another,
-the copies often have small, nuanced differences between them. These nuances cause
-extra engineering time when fixes are needed, because the fix must be copied to
-several locations. These nuances also create different user experiences when the
-feature is used in different places.
-
-A solution for this problem is to consolidate groups and projects into a single
-entity, `namespace`. The work on this solution is split into several phases and
-is tracked in [epic 6473](https://gitlab.com/groups/gitlab-org/-/epics/6473).
-
-### Phase 1
-
-- [Phase 1 epic](https://gitlab.com/groups/gitlab-org/-/epics/6697).
-- **Goals**:
- 1. Ensure every project receives a corresponding record in the `namespaces`
- table with `type='Project'`.
- 1. For user namespaces, the type changes from `NULL` to `User`.
-
-We should make sure that projects, and the project namespace, are equivalent:
-
-- **Create project:** use Rails callbacks to ensure a new project namespace is
- created for each project. Project namespace records should contain `created_at` and
- `updated_at` attributes equal to the project's `created_at`/`updated_at` attributes.
-- **Update project:** use the `after_save` callback in Rails to ensure some
- attributes are kept in sync between project and project namespaces.
- Read [`project#after_save`](https://gitlab.com/gitlab-org/gitlab/blob/6d26634e864d7b748dda0e283eb2477362263bc3/app/models/project.rb#L101-L101)
- for more information.
-- **Delete project:** use FKs cascade delete or Rails callbacks to ensure when a `Project`
- or its `ProjectNamespace` is removed, its corresponding `ProjectNamespace` or `Project`
- is also removed.
-- **Transfer project to a different group:** make sure that when a project is transferred,
- its corresponding project namespace is transferred to the same group.
-- **Transfer group:** make sure when transferring a group that all of its sub-projects,
- either direct or through descendant groups, have their corresponding project
- namespaces transferred correctly as well.
-- **Export or import project**
- - **Export project** continues to export only the project, and not its project namespace,
- in this phase. The project namespace does not contain any specific information
- to export at this point. Eventually we want the project namespace to be exported as well.
- - **Import project** creates a new project, so the project namespace is created through
- Rails `after_save` callback on the project model.
-- **Export or import group:** when importing or exporting a `Group`, projects are not
- included in the operation. If that feature is changed to include `Project` when its group is
- imported or exported, the logic must include their corresponding project namespaces
- in the import or export.
-
-After ensuring these points, run a database migration to create a `ProjectNamespace`
-record for every `Project`. Project namespace records created during the migration
-should have `created_at` and `updated_at` attributes set to the migration runtime.
-The project namespaces' `created_at` and `updated_at` attributes would not match
-their corresponding project's `created_at` and `updated_at` attributes. We want
-the different dates to help audit any of the created project namespaces, in case we need it.
-After this work completes, we must migrate data as described in
-[Backfill `ProjectNamespace` for every Project](https://gitlab.com/gitlab-org/gitlab/-/issues/337100).
-
-### Phase 2
-
-- [Phase 2 epic](https://gitlab.com/groups/gitlab-org/-/epics/6768).
-- **Goal**: Link `ProjectNamespace` to other entities on the database level.
-
-In this phase:
-
-- Communicate the changes company-wide at the engineering level. We want to make
- engineers aware of the upcoming changes, even though teams are not expected to
- collaborate actively until phase 3.
-- Raise awareness to avoid regressions, and conflicting or duplicate work that
- can be dealt with before phase 3.
-
-### Phase 3
-
-- [Phase 3 epic](https://gitlab.com/groups/gitlab-org/-/epics/6585).
-- **Goal**: Achieve feature parity between the namespace types.
-Problems to solve as part of this phase:
-
-- Routes handling through `ProjectNamespace` rather than `Project`.
-- Memberships handling.
-- Policies handling.
-- Import and export.
-- Other interactions between project namespace and project models.
-
-Phase 3 is when the active migration of features from `Project` to `ProjectNamespace`,
-or directly to `Namespace`, happens.
-
-### How to plan features that interact with Group and ProjectNamespace
-
-As of now, every Project in the system has a record in the `namespaces` table. This makes it possible to
-use common interface to create features that are shared between Groups and Projects. Shared behavior can be added using
-a concerns mechanism. Because the `Namespace` model is responsible for `UserNamespace` methods as well, it is discouraged
-to use the `Namespace` model for shared behavior for Projects and Groups.
-
-#### Resource-based features
-
-To migrate resource-based features, existing functionality will need to be supported. This can be achieved in two Phases.
-
-**Phase 1 - Setup**
-
-- Link into the namespaces table
- - Add a column to the table
- - For example, in issues a `project id` points to the projects table. We need to establish a link to the `namespaces` table.
- - Modify code so that any new record already has the correct data in it
- - Backfill
-
-**Phase 2 - Prerequisite work**
-
-- Investigate the permission model as well as any performance concerns related to that.
- - Permissions need to be checked and kept in place.
-- Investigate what other models need to support namespaces for functionality dependent on features you migrate in Phase 1.
-- Adjust CRUD services and APIs (REST and GraphQL) to point to the new column you added in Phase 1.
-- Consider performance when fetching resources.
-
-Introducing new functionality is very much dependent on every single team and feature.
-
-#### Settings-related features
-
-Right now, cascading settings are available for `NamespaceSettings`. By creating `ProjectNamespace`,
-we can use this framework to make sure that some settings are applicable on the project level as well.
-
-When working on settings, we need to make sure that:
-
-- They are not used in `join` queries or modify those queries.
-- Updating settings is taken into consideration.
-- If we want to move from project to project namespace, we follow a similar database process to the one described in [Phase 1](#phase-1).
-
-## Related topics
-
-- [Consolidating groups and projects](../../architecture/blueprints/consolidating_groups_and_projects/index.md)
- architecture documentation
-- [Organization user documentation](../../user/workspace/index.md)
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/drawers/advanced_search_syntax.md b/doc/drawers/advanced_search_syntax.md
index 7556c8bdfaf..6e732bd3175 100644
--- a/doc/drawers/advanced_search_syntax.md
+++ b/doc/drawers/advanced_search_syntax.md
@@ -13,6 +13,7 @@ source: /doc/user/search/advanced_search.md
| Syntax | Description | Example |
|--------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `"` | Exact search | [`"gem sidekiq"`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=%22gem+sidekiq%22) |
+| `~` | Fuzzy search | [`J~ Doe`](https://gitlab.com/search?scope=users&search=j%7E+doe) |
| <code>&#124;</code> | Or | [<code>display &#124; banner</code>](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=display+%7C+banner) |
| `+` | And | [`display +banner`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=display+%2Bbanner&snippets=) |
| `-` | Exclude | [`display -banner`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=display+-banner) |
diff --git a/doc/gitlab-basics/add-file.md b/doc/gitlab-basics/add-file.md
index 05731f93605..0915b9b8e21 100644
--- a/doc/gitlab-basics/add-file.md
+++ b/doc/gitlab-basics/add-file.md
@@ -7,89 +7,95 @@ type: howto
# Add a file to a repository **(FREE)**
-Adding files to a repository is a small, but key task. Bringing files in to a repository,
-such as code, images, or documents, allows them to be tracked by Git, even though they
-may have been created elsewhere.
-
-You can add a file to a repository in your [terminal](#add-a-file-using-the-command-line), and
-then push to GitLab. You can also use the [web interface](../user/project/repository/web_editor.md#upload-a-file),
-which may be a simpler solution.
-
-If you need to create a file first, for example a `README.md` text file, that can
-also be done from the [terminal](command-line-commands.md#create-a-text-file-in-the-current-directory) or
-[web interface](../user/project/repository/web_editor.md#create-a-file).
-
-## Add a file using the command line
-
-Open a [terminal/shell](command-line-commands.md), and change into the folder of your
-GitLab project. This usually means running the following command until you get
-to the desired destination:
-
-```shell
-cd <destination folder>
-```
-
-[Create a new branch](../tutorials/make_your_first_git_commit.md#create-a-branch-and-make-changes) to add your file into. Submitting changes directly
-to the default branch should be avoided unless your project is very small and you're the
-only person working on it.
-
-You can also [switch to an existing branch](start-using-git.md#switch-to-a-branch)
-if you have one already.
-
-Using your standard tool for copying files (for example, Finder in macOS, or File Explorer
-on Windows), put the file into a directory in the GitLab project.
-
-Check if your file is actually present in the directory (if you're on Windows,
-use `dir` instead):
-
-```shell
-ls
-```
-
-You should see the name of the file in the list shown.
-
-Check the status:
-
-```shell
-git status
-```
-
-Your file's name should appear in red, so `git` took notice of it! Now add it
-to the repository:
-
-```shell
-git add <name of file>
-```
-
-Check the status again, your file's name should have turned green:
-
-```shell
-git status
-```
-
-Commit (save) your file to the repository:
-
-```shell
-git commit -m "DESCRIBE COMMIT IN A FEW WORDS"
-```
-
-Now you can push (send) your changes (in the branch `<branch-name>`) to GitLab
-(the Git remote named 'origin'):
-
-```shell
-git push origin <branch-name>
-```
-
-Your image is added to your branch in your repository in GitLab.
-
-<!-- ## Troubleshooting
-
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
-
-Each scenario can be a third-level heading, for example `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+Adding files to a repository is a small, but key, task. No matter where the code,
+images, or documents were created, Git tracks them after you add them to your repository.
+
+## Add an existing file
+
+To add an existing file to your repository, either:
+
+- Upload the file from the GitLab UI.
+- Add a file to your repository from the command line, then push the file up to GitLab.
+
+### From the UI
+
+If you are unfamiliar with the command line, use the
+[Web Editor](../user/project/repository/web_editor.md) to upload a file from the GitLab UI:
+
+<!-- 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 top bar, select **Main menu > Projects** 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.
+1. Select **Upload file**.
+
+### From the command line
+
+To add a new file from the command line:
+
+1. Open a terminal (or shell) window.
+1. Use the "change directory" (`cd`) command to go to your GitLab project's folder.
+ Run the `cd DESTINATION` command, changing `DESTINATION` to the location of your folder.
+1. Choose a Git branch to work in. You can either:
+ - [Create a new branch](../tutorials/make_your_first_git_commit.md#create-a-branch-and-make-changes)
+ to add your file into. Don't submit changes directly to the default branch of your
+ repository unless your project is very small and you're the only person working on it.
+ - [Switch to an existing branch](start-using-git.md#switch-to-a-branch).
+1. Copy the file into the appropriate directory in your project. Use your standard tool
+ for copying files, such as Finder in macOS, or File Explorer in Windows.
+1. In your terminal window, confirm that your file is present in the directory:
+ - Windows: Use the `dir` command.
+ - All other operating systems: Use the `ls` command.
+ You should see the name of the file in the list shown.
+1. Check the status of your file with the `git status` command. Your file's name
+ should be red. Files listed in red are in your file system, but Git isn't tracking them yet.
+1. Tell Git to track this file with the `git add FILENAME` command, replacing `FILENAME`
+ with the name of your file.
+1. Check the status of your file again with the `git status` command. Your file's name
+ should be green. Files listed in green are tracked locally by Git, but still
+ need to be committed and pushed.
+1. Commit (save) your file to your local copy of your project's Git repository:
+
+ ```shell
+ git commit -m "DESCRIBE COMMIT IN A FEW WORDS"
+ ```
+
+1. Push (send) your changes from your copy of the repository, up to GitLab.
+ In this command, `origin` refers to the copy of the repository stored at GitLab.
+ Replace `BRANCHNAME` with the name of your branch:
+
+ ```shell
+ git push origin BRANCHNAME
+ ```
+
+1. Git prepares, compresses, and sends the data. Lines from the remote repository
+ (here, GitLab) are prefixed with `remote:` like this:
+
+ ```plaintext
+ Enumerating objects: 9, done.
+ Counting objects: 100% (9/9), done.
+ Delta compression using up to 10 threads
+ Compressing objects: 100% (5/5), done.
+ Writing objects: 100% (5/5), 1.84 KiB | 1.84 MiB/s, done.
+ Total 5 (delta 3), reused 0 (delta 0), pack-reused 0
+ remote:
+ remote: To create a merge request for BRANCHNAME, visit:
+ remote: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/new?merge_request%5Bsource_branch%5D=BRANCHNAME
+ remote:
+ To https://gitlab.com/gitlab-org/gitlab.git
+ * [new branch] BRANCHNAME -> BRANCHNAME
+ branch 'BRANCHNAME' set up to track 'origin/BRANCHNAME'.
+ ```
+
+Your file is now copied from your local copy of the repository, up to the remote
+repository at GitLab. To create a merge request, copy the link sent back from the remote
+repository and paste it into a browser window.
+
+## Add a new file
+
+To create a new file (like a `README.md` text file) in your repository, either:
+
+- [Create the file](../user/project/repository/web_editor.md#create-a-file) from the GitLab UI.
+- Create the file from the terminal.
diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md
index 07ab9365693..2850669ce57 100644
--- a/doc/gitlab-basics/command-line-commands.md
+++ b/doc/gitlab-basics/command-line-commands.md
@@ -1,123 +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: '../user/index.md'
+remove_date: '2023-06-09'
---
-# Edit files through the command line **(FREE)**
+This document was moved to [another location](../user/index.md).
-When [working with Git from the command line](start-using-git.md), you need to
-use more than just the Git commands. There are several basic commands that you should
-learn to make full use of the command line.
-
-## Start working on your project
-
-To work on a Git project locally (from your own computer), with the command line,
-first you need to [clone (copy) it](start-using-git.md#clone-a-repository) to
-your computer.
-
-## Working with files on the command line
-
-This section has examples of some basic shell commands that you might find useful.
-For more information, search the web for _bash commands_.
-
-Alternatively, you can edit files using your choice of editor (IDE), or the GitLab user
-interface (not locally).
-
-### Common commands
-
-The list below is not exhaustive, but contains many of the most commonly used commands.
-
-| Command | Description |
-|--------------------------------|---------------------------------------------|
-| `cd NAME-OF-DIRECTORY` | Go into a directory to work in it |
-| `cd ..` | Go back one directory |
-| `ls` | List what's in the current directory |
-| `ls a*` | List what's in the current directory that starts with `a` |
-| `ls *.md` | List what's in the current directory that ends with `.md` |
-| `mkdir NAME-OF-YOUR-DIRECTORY` | Create a new directory |
-| `cat README.md` | Display the contents of a [text file you created previously](#create-a-text-file-in-the-current-directory) |
-| `pwd` | Show the current directory |
-| `clear` | Clear the shell window |
-
-### Create a text file in the current directory
-
-To create a text file from the command line, for example `README.md`, follow these
-steps:
-
-```shell
-touch README.md
-nano README.md
-#### ADD YOUR INFORMATION
-#### Press: control + X
-#### Type: Y
-#### Press: enter
-```
-
-### Remove a file or directory
-
-It's easy to delete (remove) a file or directory, but be careful:
-
-WARNING:
-This will **permanently** delete a file.
-
-```shell
-rm NAME-OF-FILE
-```
-
-WARNING:
-This will **permanently** delete a directory and **all** of its contents.
-
-```shell
-rm -r NAME-OF-DIRECTORY
-```
-
-### View and Execute commands from history
-
-You can view the history of all the commands you executed from the command line,
-and then execute any of them again, if needed.
-
-First, list the commands you executed previously:
-
-```shell
-history
-```
-
-Then, choose a command from the list and check the number next to the command (`123`,
-for example) . Execute the same full command with:
-
-```shell
-!123
-```
-
-### Carry out commands for which the account you are using lacks authority
-
-Not all commands can be executed from a basic user account on a computer, you may
-need administrator's rights to execute commands that affect the system, or try to access
-protected data, for example. You can use `sudo` to execute these commands, but you
-might be asked for an administrator password.
-
-```shell
-sudo RESTRICTED-COMMAND
-```
-
-WARNING:
-Be careful of the commands you run with `sudo`. Certain commands may cause
-damage to your data or system.
-
-## Sample Git task flow
-
-If you're completely new to Git, looking through some [sample task flows](https://rogerdudler.github.io/git-guide/)
-may help you understand the best practices for using these commands as you work.
-
-<!-- ## Troubleshooting
-
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
-
-Each scenario can be a third-level heading, for example `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+<!-- This redirect file can be deleted after <2023-06-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 -->
diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md
index 224d1fabb14..194647259b8 100644
--- a/doc/gitlab-basics/start-using-git.md
+++ b/doc/gitlab-basics/start-using-git.md
@@ -98,7 +98,7 @@ access on GitLab.com or any other GitLab instance.
To use the repository in the examples on this page:
1. Go to [https://gitlab.com/gitlab-tests/sample-project/](https://gitlab.com/gitlab-tests/sample-project/).
-1. In the upper right, select **Fork**.
+1. In the upper-right corner, select **Fork**.
1. Choose a namespace for your fork.
The project becomes available at `https://gitlab.com/<your-namespace>/sample-project/`.
diff --git a/doc/index.md b/doc/index.md
index 492320d93aa..49684705686 100644
--- a/doc/index.md
+++ b/doc/index.md
@@ -28,7 +28,7 @@ Welcome to the GitLab documentation!
| [**New to Git and GitLab?**](tutorials/index.md)<br/>Start learning about Git and GitLab. | [**Contribute to GitLab development**](#contributing-to-gitlab)<br/>Create new GitLab functionality and documentation. |
| [**Coming to GitLab from another platform?**](#coming-to-gitlab-from-another-platform)<br/>Learn how to move to GitLab. | [**Build an integration with GitLab**](#build-an-integration-with-gitlab)<br/>Integrate with Jira and other common applications. |
| [**Choose a subscription**](subscriptions/index.md)<br/>Determine which subscription tier makes sense for you. | [**Install GitLab**](https://about.gitlab.com/install/)<br/>Install GitLab on different platforms. |
-| [**Reference architectures**](administration/reference_architectures/index.md)<br/>View recommended deployments at scale. | [**Update GitLab**](update/index.md)<br/>Update your GitLab self-managed instance to the latest version. |
+| [**Reference architectures**](administration/reference_architectures/index.md)<br/>View recommended deployments at scale. | [**Upgrade GitLab**](update/index.md)<br/>Upgrade your GitLab self-managed instance to the latest version. |
| [**GitLab releases**](https://about.gitlab.com/releases/)<br/>See what's new in GitLab. | |
## Popular topics
@@ -43,7 +43,7 @@ Have a look at some of our most popular topics:
| [Activate GitLab EE with a license](user/admin_area/license.md) | Activate GitLab Enterprise Edition functionality with a license. |
| [Back up and restore GitLab](raketasks/backup_restore.md) | Rake tasks for backing up and restoring GitLab self-managed instances. |
| [GitLab release and maintenance policy](policy/maintenance.md) | Policies for version naming and cadence, and also upgrade recommendations. |
-| [Elasticsearch integration](integration/advanced_search/elasticsearch.md) | Integrate Elasticsearch with GitLab to enable advanced searching. |
+| [Elasticsearch integration](integration/advanced_search/elasticsearch.md) | Integrate Elasticsearch with GitLab to enable advanced search. |
| [Omnibus GitLab database settings](https://docs.gitlab.com/omnibus/settings/database.html) | Database settings for Omnibus GitLab self-managed instances. |
| [Omnibus GitLab NGINX settings](https://docs.gitlab.com/omnibus/settings/nginx.html) | NGINX settings for Omnibus GitLab self-managed instances. |
| [Omnibus GitLab SSL configuration](https://docs.gitlab.com/omnibus/settings/ssl.html) | SSL settings for Omnibus GitLab self-managed instances. |
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index 99ba05925a5..8f540691a45 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -87,7 +87,7 @@ Because any given GitLab upgrade might involve data disk updates or database sch
- [GitLab Community Edition](https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#Images:visibility=public-images;ownerAlias=782774275127;search=GitLab%20CE;sort=desc:name): The open source version of GitLab.
- [GitLab Premium or Ultimate Marketplace (pre-licensed)](https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#Images:visibility=public-images;source=Marketplace;search=GitLab%20EE;sort=desc:name): 5 user license built into per-minute billing.
-1. AMI IDs are unique per region, so after you've loaded one of the above, select the desired target region in the upper right of the console to see the appropriate AMIs.
+1. AMI IDs are unique per region. After you've loaded any of these editions, in the upper-right corner, select the desired target region of the console to see the appropriate AMIs.
1. After the console is loaded, you can add additional search criteria to narrow further. For instance, type `13.` to find only 13.x versions.
1. To launch an EC2 Machine with one of the listed AMIs, check the box at the start of the relevant row, and select **Launch** near the top of left of the page.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index eda9c503e28..1cd6a4fc5d2 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -11,8 +11,7 @@ using the source files. To set up a **development installation** or for many
other installation options, see the [main installation page](index.md).
It was created for and tested on **Debian/Ubuntu** operating systems.
Read [requirements.md](requirements.md) for hardware and operating system requirements.
-If you want to install on RHEL/CentOS, we recommend using the
-[Omnibus packages](https://about.gitlab.com/install/).
+If you want to install on RHEL/CentOS, you should use the [Omnibus packages](https://about.gitlab.com/install/).
This guide is long because it covers many cases and includes all commands you
need, this is [one of the few installation scripts that actually work out of the box](https://twitter.com/robinvdvleuten/status/424163226532986880).
@@ -46,17 +45,16 @@ If the highest number stable branch is unclear, check the [GitLab blog](https://
## Software requirements
-| Software | Minimum version | Notes |
-| ------------------ | --------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Ruby](#2-ruby) | `2.7` | From GitLab 13.6, Ruby 2.7 is required. Ruby 3.0 is not supported yet (see [the relevant epic](https://gitlab.com/groups/gitlab-org/-/epics/5149) for the current status). You must use the standard MRI implementation of Ruby. We love [JRuby](https://www.jruby.org/) and [Rubinius](https://github.com/rubinius/rubinius#the-rubinius-language-platform), but GitLab needs several Gems that have native extensions. |
-| [Go](#3-go) | `1.18` | From GitLab 15.6, Go 1.18 or later is required. |
-| [Git](#git) | `2.38.x` | From GitLab 15.8, Git 2.38.x and later is required. It's highly recommended that you use the [Git version provided by Gitaly](#git). |
-| [Node.js](#4-node) | `16.15.0` | From GitLab 15.7, Node.js 16.15.0 or later is required. |
+| Software | Minimum version | Notes |
+|:-------------------|:----------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [Ruby](#2-ruby) | `3.0.x` | From GitLab 15.10, Ruby 3.0 is required. You must use the standard MRI implementation of Ruby. We love [JRuby](https://www.jruby.org/) and [Rubinius](https://github.com/rubinius/rubinius#the-rubinius-language-platform), but GitLab needs several Gems that have native extensions. |
+| [Go](#3-go) | `1.18.x` | From GitLab 15.6, Go 1.18 or later is required. |
+| [Git](#git) | `2.38.x` | From GitLab 15.8, Git 2.38.x and later is required. It's highly recommended that you use the [Git version provided by Gitaly](#git). |
+| [Node.js](#4-node) | `16.15.0` | From GitLab 15.7, Node.js 16.15.0 or later is required. |
## GitLab directory structure
-This is the main directory structure you end up with following the instructions
-of this page:
+When following the instructions on this page, you create this directory structure:
```plaintext
|-- home
@@ -224,8 +222,8 @@ Download Ruby and compile it:
```shell
mkdir /tmp/ruby && cd /tmp/ruby
-curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.6.tar.gz"
-echo 'e7203b0cc09442ed2c08936d483f8ac140ec1c72e37bb5c401646b7866cb5d10 ruby-2.7.6.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.6.tar.gz
+curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.5.tar.gz"
+echo '9afc6380a027a4fe1ae1a3e2eccb6b497b9c5ac0631c12ca56f9b7beb4848776 ruby-3.0.5.tar.gz' | sha256sum -c - && tar xzf ruby-3.0.5.tar.gz
cd ruby-2.7.6
./configure --disable-install-rdoc --enable-shared
diff --git a/doc/install/next_steps.md b/doc/install/next_steps.md
index c718d895c8a..70b6101b1eb 100644
--- a/doc/install/next_steps.md
+++ b/doc/install/next_steps.md
@@ -56,7 +56,7 @@ installation.
## Cross-repository Code Search
-- [Advanced Search](../integration/advanced_search/elasticsearch.md): Leverage [Elasticsearch](https://www.elastic.co/) or [OpenSearch](https://opensearch.org/) for
+- [Advanced search](../integration/advanced_search/elasticsearch.md): Leverage [Elasticsearch](https://www.elastic.co/) or [OpenSearch](https://opensearch.org/) for
faster, more advanced code search across your entire GitLab instance.
## Scaling and replication
diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md
index 6a2c562377f..389c79a281c 100644
--- a/doc/integration/advanced_search/elasticsearch.md
+++ b/doc/integration/advanced_search/elasticsearch.md
@@ -7,8 +7,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Elasticsearch **(PREMIUM SELF)**
-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).
+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).
## Version requirements
@@ -16,7 +16,7 @@ Advanced Search provides faster search response times and [improved search featu
> Support for Elasticsearch 6.8 was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/350275) in GitLab 15.0.
-Advanced Search works with the following versions of Elasticsearch.
+Advanced search works with the following versions of Elasticsearch.
| GitLab version | Elasticsearch version |
|-----------------------|--------------------------|
@@ -25,13 +25,13 @@ Advanced Search works with the following versions of Elasticsearch.
| GitLab 13.3 - 13.8 | Elasticsearch 6.4 - 7.x |
| GitLab 12.7 - 13.2 | Elasticsearch 6.x - 7.x |
-Advanced Search follows the [Elasticsearch end-of-life policy](https://www.elastic.co/support/eol).
+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
before we remove them.
### OpenSearch version requirements
-| GitLab version | Elasticsearch version |
+| GitLab version | OpenSearch version |
|-----------------------|--------------------------|
| GitLab 15.0 or later | OpenSearch 1.x or later |
@@ -46,7 +46,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 ([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.
## Install Elasticsearch
@@ -163,20 +163,22 @@ Errors from the [GitLab Elasticsearch Indexer](https://gitlab.com/gitlab-org/git
the [`elasticsearch.log`](../../administration/logs/index.md#elasticsearchlog) file and the [`sidekiq.log`](../../administration/logs/index.md#sidekiqlog) file with a `json.exception.class` of `Gitlab::Elastic::Indexer::Error`.
These errors may occur when indexing Git repository data.
-## Enable Advanced Search
+## Enable advanced search
+
+Prerequisite:
-For GitLab instances with more than 50 GB repository data you can follow the instructions for [how to index large instances efficiently](#how-to-index-large-instances-efficiently) below.
+- You must have administrator access to the instance.
-To enable Advanced Search, you must have administrator access to GitLab:
+To enable advanced search:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > Advanced Search**.
NOTE:
- To see the Advanced Search section, you need an active GitLab Premium
+ To see the **Advanced Search** section, you need an active GitLab Premium
[license](../../user/admin_area/license.md).
-1. Configure the [Advanced Search settings](#advanced-search-configuration) for
+1. Configure the [advanced search settings](#advanced-search-configuration) for
your Elasticsearch cluster. Do not enable **Search with Elasticsearch enabled**
yet.
1. Enable **Elasticsearch indexing** and select **Save changes**. This creates
@@ -202,7 +204,9 @@ you might have problems updating documents such as issues because your
instance queues a job to index the change, but cannot find a valid
Elasticsearch cluster.
-### Advanced Search configuration
+For GitLab instances with more than 50 GB of repository data, see [How to index large instances efficiently](#how-to-index-large-instances-efficiently).
+
+### Advanced search configuration
The following Elasticsearch settings are available:
@@ -223,8 +227,8 @@ The following Elasticsearch settings are available:
| `AWS Secret Access Key` | The AWS secret access key. |
| `Maximum file size indexed` | See [the explanation in instance limits.](../../administration/instance_limits.md#maximum-file-size-indexed). |
| `Maximum field length` | See [the explanation in instance limits.](../../administration/instance_limits.md#maximum-field-length). |
-| `Maximum bulk request size (MiB)` | Used by the GitLab Ruby and Golang-based indexer processes. This setting indicates how much data must be collected (and stored in memory) in a given indexing process before submitting the payload to the Elasticsearch Bulk API. For the GitLab Golang-based indexer, you should use this setting with `Bulk request concurrency`. `Maximum bulk request size (MiB)` must accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer from either the `gitlab-rake` command or the Sidekiq tasks. |
-| `Bulk request concurrency` | The Bulk request concurrency indicates how many of the GitLab Golang-based indexer processes (or threads) can run in parallel to collect data to subsequently submit to the Elasticsearch Bulk API. This increases indexing performance, but fills the Elasticsearch bulk requests queue faster. This setting should be used together with the Maximum bulk request size setting (see above) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. |
+| `Maximum bulk request size (MiB)` | Used by the GitLab Ruby and Go-based indexer processes. This setting indicates how much data must be collected (and stored in memory) in a given indexing process before submitting the payload to the Elasticsearch Bulk API. For the GitLab Go-based indexer, you should use this setting with `Bulk request concurrency`. `Maximum bulk request size (MiB)` must accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Go-based indexer from either the `gitlab-rake` command or the Sidekiq tasks. |
+| `Bulk request concurrency` | The Bulk request concurrency indicates how many of the GitLab Go-based indexer processes (or threads) can run in parallel to collect data to subsequently submit to the Elasticsearch Bulk API. This increases indexing performance, but fills the Elasticsearch bulk requests queue faster. This setting should be used together with the Maximum bulk request size setting (see above) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Go-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. |
| `Client request timeout` | Elasticsearch HTTP client request timeout value in seconds. `0` means using the system default timeout value, which depends on the libraries that GitLab application is built upon. |
WARNING:
@@ -294,16 +298,16 @@ For more information, see [Identity and Access Management in Amazon OpenSearch S
When using fine-grained access control with a user in the internal database, you should use HTTP basic
authentication to connect to OpenSearch. You can provide the master username and password as part of the
-OpenSearch URL or in the **Username** and **Password** text boxes in the Advanced Search settings. See
+OpenSearch URL or in the **Username** and **Password** text boxes in the advanced search settings. See
[Tutorial: Internal user database and HTTP basic authentication](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac-walkthrough-basic.html) for details.
##### Connecting with an IAM user
-When using fine-grained access control with IAM credentials, you can provide the credentials in the **AWS OpenSearch IAM credentials** section in the Advanced Search settings.
+When using fine-grained access control with IAM credentials, you can provide the credentials in the **AWS OpenSearch IAM credentials** section in the advanced search settings.
##### Permissions for fine-grained access control
-The following permissions are required for Advanced Search. See [Creating roles](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html#fgac-roles) for details.
+The following permissions are required for advanced search. See [Creating roles](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html#fgac-roles) for details.
```json
{
@@ -338,7 +342,7 @@ The following permissions are required for Advanced Search. See [Creating roles]
}
```
-The index pattern `*` requires a few permissions for Advanced Search to work.
+The index pattern `*` requires a few permissions for advanced search to work.
### Limit the number of namespaces and projects that can be indexed
@@ -350,14 +354,14 @@ under **Elasticsearch indexing restrictions** more options become available.
You can select namespaces and projects to index exclusively. If the namespace is a group, it includes
any subgroups and projects belonging to those subgroups to be indexed as well.
-Advanced Search only provides cross-group code/commit search (global) if all name-spaces are indexed. In this particular scenario where only a subset of namespaces are indexed, a global search does not provide a code or commit scope. This is possible only in the scope of an indexed namespace. There is no way to code/commit search in multiple indexed namespaces (when only a subset of namespaces has been indexed). For example if two groups are indexed, there is no way to run a single code search on both. You can only run a code search on the first group and then on the second.
+Advanced search only provides cross-group code/commit search (global) if all name-spaces are indexed. In this particular scenario where only a subset of namespaces are indexed, a global search does not provide a code or commit scope. This is possible only in the scope of an indexed namespace. There is no way to code/commit search in multiple indexed namespaces (when only a subset of namespaces has been indexed). For example if two groups are indexed, there is no way to run a single code search on both. You can only run a code search on the first group and then on the second.
You can filter the selection dropdown list by writing part of the namespace or project name you're interested in.
![limit namespace filter](img/limit_namespace_filter.png)
NOTE:
-If no namespaces or projects are selected, no Advanced Search indexing takes place.
+If no namespaces or projects are selected, no advanced search indexing takes place.
WARNING:
If you have already indexed your instance, you must regenerate the index to delete all existing data
@@ -385,11 +389,11 @@ For guidance on what to install, see the following Elasticsearch language plugin
| Parameter | Description |
|-------------------------------------------------------|-------------|
| `Enable Chinese (smartcn) custom analyzer: Indexing` | Enables or disables Chinese language support using [`smartcn`](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-smartcn.html) custom analyzer for newly created indices.|
-| `Enable Chinese (smartcn) custom analyzer: Search` | Enables or disables using [`smartcn`](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-smartcn.html) fields for Advanced Search. Only enable this after [installing the plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-smartcn.html), enabling custom analyzer indexing and recreating the index.|
+| `Enable Chinese (smartcn) custom analyzer: Search` | Enables or disables using [`smartcn`](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-smartcn.html) fields for advanced search. Only enable this after [installing the plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-smartcn.html), enabling custom analyzer indexing and recreating the index.|
| `Enable Japanese (kuromoji) custom analyzer: Indexing` | Enables or disables Japanese language support using [`kuromoji`](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji.html) custom analyzer for newly created indices.|
-| `Enable Japanese (kuromoji) custom analyzer: Search` | Enables or disables using [`kuromoji`](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji.html) fields for Advanced Search. Only enable this after [installing the plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji.html), enabling custom analyzer indexing and recreating the index.|
+| `Enable Japanese (kuromoji) custom analyzer: Search` | Enables or disables using [`kuromoji`](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji.html) fields for advanced search. Only enable this after [installing the plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji.html), enabling custom analyzer indexing and recreating the index.|
-## Disable Advanced Search
+## Disable advanced search
To disable the Elasticsearch integration:
@@ -423,7 +427,7 @@ the writes to the `primary` index. Then, we create another index and invoke the
index data onto the new index. After the reindexing job is complete, we switch to the new index by connecting the
index alias to it which becomes the new `primary` index. At the end, we resume the writes and typical operation resumes.
-### Trigger the reindex via the Advanced Search administration
+### 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.
@@ -502,15 +506,15 @@ Sometimes, you might want to abandon the unfinished reindex job and resume the i
1. Expand **Advanced Search**.
1. Clear the **Pause Elasticsearch indexing** checkbox.
-## Advanced Search migrations
+## 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.
+advanced search, which means adding or changing the way content is indexed.
-To confirm that the Advanced Search migrations ran, you can check with:
+To confirm that the advanced search migrations ran, you can check with:
```shell
curl "$CLUSTER_URL/gitlab-production-migrations/_search?q=*" | jq .
@@ -554,7 +558,7 @@ To debug issues with the migrations you can check the [`elasticsearch.log` file]
### Retry a halted migration
Some migrations are built with a retry limit. If the migration cannot finish within the retry limit,
-it is halted and a notification is displayed in the Advanced Search integration settings.
+it is halted and a notification is displayed in the advanced search integration settings.
It is recommended to check the [`elasticsearch.log` file](../../administration/logs/index.md#elasticsearchlog) to
debug why the migration was halted and make any changes before retrying the migration. Once you believe you've
fixed the cause of the failure, select "Retry migration", and the migration is scheduled to be retried
@@ -575,7 +579,7 @@ version. If you have halted migrations, these need to be resolved and
[retried](#retry-a-halted-migration) before proceeding with a major version
upgrade. Read more about [upgrading to a new major version](../../update/index.md#upgrading-to-a-new-major-version).
-## GitLab Advanced Search Rake tasks
+## GitLab advanced search Rake tasks
Rake tasks are available to:
@@ -587,7 +591,7 @@ The following are some available Rake tasks:
| Task | Description |
|:--------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [`sudo gitlab-rake gitlab:elastic:info`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Outputs debugging information for the Advanced Search integration. |
+| [`sudo gitlab-rake gitlab:elastic:info`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Outputs debugging information for the advanced search integration. |
| [`sudo gitlab-rake gitlab:elastic:index`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Enables Elasticsearch indexing and run `gitlab:elastic:create_empty_index`, `gitlab:elastic:clear_index_status`, `gitlab:elastic:index_projects`, `gitlab:elastic:index_snippets`, and `gitlab:elastic:index_users`. |
| [`sudo gitlab-rake gitlab:elastic:pause_indexing`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Pauses Elasticsearch indexing. Changes are still tracked. Useful for cluster/index migrations. |
| [`sudo gitlab-rake gitlab:elastic:resume_indexing`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Resumes Elasticsearch indexing. |
@@ -604,7 +608,7 @@ The following are some available Rake tasks:
| [`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. |
-| [`sudo gitlab-rake gitlab:elastic:enable_search_with_elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Enable advanced search with Elasticsearch. |
+| [`sudo gitlab-rake gitlab:elastic:enable_search_with_elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Enables advanced search with Elasticsearch. |
| [`sudo gitlab-rake gitlab:elastic:disable_search_with_elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Disables advanced search with Elasticsearch. |
### Environment variables
@@ -633,7 +637,7 @@ Indexing project repositories...I, [2019-03-04T21:27:03.083410 #3384] INFO -- :
I, [2019-03-04T21:27:05.215266 #3384] INFO -- : Indexing GitLab User / test (ID=33) is done!
```
-## Advanced Search index scopes
+## Advanced search index scopes
When performing a search, the GitLab index uses the following scopes:
@@ -658,6 +662,7 @@ For basic guidance on choosing a cluster configuration you may refer to [Elastic
- Generally, you want to use at least a 2-node cluster configuration with one replica, which allows you to have resilience. If your storage usage is growing quickly, you may want to plan horizontal scaling (adding more nodes) beforehand.
- It's not recommended to use HDD storage with the search cluster, because it takes a hit on performance. It's better to use SSD storage (NVMe or SATA SSD drives for example).
+- You should not use [coordinating-only nodes](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#coordinating-only-node) with large instances. Coordinating-only nodes are smaller than [data nodes](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#data-node), which can impact performance and advanced search migrations.
- You can use the [GitLab Performance Tool](https://gitlab.com/gitlab-org/quality/performance) to benchmark search performance with different search cluster sizes and configurations.
- `Heap size` should be set to no more than 50% of your physical RAM. Additionally, it shouldn't be set to more than the threshold for zero-based compressed oops. The exact threshold varies, but 26 GB is safe on most systems, but can also be as large as 30 GB on some systems. See [Heap size settings](https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html#heap-size-settings) and [Setting JVM options](https://www.elastic.co/guide/en/elasticsearch/reference/current/jvm-options.html) for more details.
- Number of CPUs (CPU cores) per node usually corresponds to the `Number of Elasticsearch shards` setting described below.
@@ -671,7 +676,7 @@ For basic guidance on choosing a cluster configuration you may refer to [Elastic
- `refresh_interval` is a per index setting. You may want to adjust that from default `1s` to a bigger value if you don't need data in real-time. This changes how soon you see fresh results. If that's important for you, you should leave it as close as possible to the default value.
- You might want to raise [`indices.memory.index_buffer_size`](https://www.elastic.co/guide/en/elasticsearch/reference/current/indexing-buffer.html) to 30% or 40% if you have a lot of heavy indexing operations.
-### Advanced Search integration settings guidance
+### Advanced search integration settings guidance
- The `Number of Elasticsearch shards` setting usually corresponds with the number of CPUs available in your cluster. For example, if you have a 3-node cluster with 4 cores each, this means you benefit from having at least 3*4=12 shards in the cluster. It's only possible to change the shards number by using [Split index API](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-split-index.html) or by reindexing to a different index with a changed number of shards.
- The `Number of Elasticsearch replicas` setting should most of the time be equal to `1` (each shard has 1 replica). Using `0` is not recommended, because losing one node corrupts the index.
@@ -862,6 +867,10 @@ However, some larger installations may wish to tune the merge policy settings:
## Index large instances with dedicated Sidekiq nodes or processes
+WARNING:
+Most instances should not need to configure this. The steps below use an advanced setting of Sidekiq called [routing rules](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules).
+Be sure to fully understand about the implication of using routing rules to avoid losing jobs entirely.
+
Indexing a large instance can be a lengthy and resource-intensive process that has the potential
of overwhelming Sidekiq nodes and processes. This negatively affects the GitLab performance and
availability.
@@ -871,18 +880,20 @@ additional process dedicated to indexing a set of queues (or queue group). This
ensure that indexing queues always have a dedicated worker, while the rest of the queues have
another dedicated worker to avoid contention.
-For this purpose, use the [queue selectors](../../administration/sidekiq/processing_specific_job_classes.md#queue-selectors)
-option that allows a more general selection of queue groups using a [worker matching query](../../administration/sidekiq/processing_specific_job_classes.md#worker-matching-query).
+For this purpose, use the [routing rules](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules)
+option that allows Sidekiq to route jobs to a specific queue based on [worker matching query](../../administration/sidekiq/processing_specific_job_classes.md#worker-matching-query).
-To handle these two queue groups, we generally recommend one of the following two options. You can either:
+To handle this, we generally recommend one of the following two options. You can either:
- [Use two queue groups on one single node](#single-node-two-processes).
- [Use two queue groups, one on each node](#two-nodes-one-process-for-each).
-For the steps below, consider:
+For the steps below, consider the entry of `sidekiq['routing_rules']`:
+
+- `["feature_category=global_search", "global_search"]` as all indexing jobs are routed to the `global_search` queue.
+- `["*", "default"]` as all other non-indexing jobs are routed to the `default` queue.
-- `feature_category=global_search` as an indexing queue group with its own Sidekiq process.
-- `feature_category!=global_search` as a non-indexing queue group that has its own Sidekiq process.
+Note that at least one process in `sidekiq['queue_groups']` has to include the `mailers` queue, otherwise mailers jobs are not processed at all.
### Single node, two processes
@@ -892,11 +903,20 @@ To create both an indexing and a non-indexing Sidekiq process in one node:
```ruby
sidekiq['enable'] = true
- sidekiq['queue_selector'] = true
+ sidekiq['queue_selector'] = false
+
+ sidekiq['routing_rules'] = [
+ ["feature_category=global_search", "global_search"],
+ ["*", "default"],
+ ]
+
sidekiq['queue_groups'] = [
- "feature_category=global_search",
- "feature_category!=global_search"
- ]
+ "global_search", # process that listens to global_search queue
+ "default,mailers" # process that listens to default and mailers queue
+ ]
+
+ sidekiq['min_concurrency'] = 20
+ sidekiq['max_concurrency'] = 20
```
1. Save the file and [reconfigure GitLab](../../administration/restart_gitlab.md)
@@ -914,26 +934,42 @@ To handle these queue groups on two nodes:
1. To set up the indexing Sidekiq process, on your indexing Sidekiq node, change the `/etc/gitlab/gitlab.rb` file to:
- ```ruby
- sidekiq['enable'] = true
- sidekiq['queue_selector'] = true
- sidekiq['queue_groups'] = [
- "feature_category=global_search"
- ]
- ```
+ ```ruby
+ sidekiq['enable'] = true
+ sidekiq['queue_selector'] = false
+
+ sidekiq['routing_rules'] = [
+ ["feature_category=global_search", "global_search"],
+ ["*", "default"],
+ ]
+
+ sidekiq['queue_groups'] = [
+ "global_search", # process that listens to global_search queue
+ ]
+
+ sidekiq['min_concurrency'] = 20
+ sidekiq['max_concurrency'] = 20
+ ```
1. Save the file and [reconfigure GitLab](../../administration/restart_gitlab.md)
for the changes to take effect.
1. To set up the non-indexing Sidekiq process, on your non-indexing Sidekiq node, change the `/etc/gitlab/gitlab.rb` file to:
- ```ruby
- sidekiq['enable'] = true
- sidekiq['queue_selector'] = true
- sidekiq['queue_groups'] = [
- "feature_category!=global_search"
- ]
- ```
+ ```ruby
+ sidekiq['enable'] = true
+ sidekiq['routing_rules'] = [
+ ["feature_category=global_search", "global_search"],
+ ["*", "default"],
+ ]
+
+ sidekiq['queue_groups'] = [
+ "default,mailers" # process that listens to default and mailers queue
+ ]
+
+ sidekiq['min_concurrency'] = 20
+ sidekiq['max_concurrency'] = 20
+ ```
to set up a non-indexing Sidekiq process.
@@ -945,7 +981,7 @@ for the changes to take effect.
Sometimes there may be issues with your Elasticsearch index data and as such
GitLab allows you to revert to "basic search" when there are no search
results and assuming that basic search is supported in that scope. This "basic
-search" behaves as though you don't have Advanced Search enabled at all for
+search" behaves as though you don't have advanced search enabled at all for
your instance and search using other data sources (such as PostgreSQL data and Git
data).
diff --git a/doc/integration/advanced_search/elasticsearch_troubleshooting.md b/doc/integration/advanced_search/elasticsearch_troubleshooting.md
index c8d11286a3c..0c4895f34fa 100644
--- a/doc/integration/advanced_search/elasticsearch_troubleshooting.md
+++ b/doc/integration/advanced_search/elasticsearch_troubleshooting.md
@@ -101,12 +101,12 @@ Here are some common pitfalls and how to overcome them.
There are a couple of ways to achieve that:
- When you perform a search, in the upper-right corner of the search results page,
- **Advanced search functionality is enabled** is displayed.
+ **Advanced search is enabled** is displayed.
This is always correctly identifying whether the current project/namespace
being searched is using Elasticsearch.
- From the Admin Area under **Settings > Advanced Search** check that the
- Advanced Search settings are checked.
+ advanced search settings are checked.
Those same settings there can be obtained from the Rails console if necessary:
@@ -212,7 +212,7 @@ More [complex Elasticsearch API calls](https://www.elastic.co/guide/en/elasticse
If the results:
-- Sync up, check that you are using [supported syntax](../../user/search/advanced_search.md#syntax). Advanced Search does not support [exact substring matching](https://gitlab.com/gitlab-org/gitlab/-/issues/325234).
+- Sync up, check that you are using [supported syntax](../../user/search/advanced_search.md#syntax). Advanced search does not support [exact substring matching](https://gitlab.com/gitlab-org/gitlab/-/issues/325234).
- Do not match up, this indicates a problem with the documents generated from the project. It is best to [re-index that project](../advanced_search/elasticsearch.md#indexing-a-range-of-projects-or-a-specific-project).
NOTE:
@@ -247,8 +247,8 @@ sudo gitlab-rake gitlab:elastic:clear_locked_projects
If `ElasticCommitIndexerWorker` Sidekiq workers are failing with this error during indexing, it usually means that Elasticsearch is unable to keep up with the concurrency of indexing request. To address change the following settings:
-- To decrease the indexing throughput you can decrease `Bulk request concurrency` (see [Advanced Search settings](elasticsearch.md#advanced-search-configuration)). This is set to `10` by default, but you change it to as low as 1 to reduce the number of concurrent indexing operations.
-- If changing `Bulk request concurrency` didn't help, you can use the [queue selector](../../administration/sidekiq/processing_specific_job_classes.md#queue-selectors) option to [limit indexing jobs only to specific Sidekiq nodes](elasticsearch.md#index-large-instances-with-dedicated-sidekiq-nodes-or-processes), which should reduce the number of indexing requests.
+- To decrease the indexing throughput you can decrease `Bulk request concurrency` (see [Advanced search settings](elasticsearch.md#advanced-search-configuration)). This is set to `10` by default, but you change it to as low as 1 to reduce the number of concurrent indexing operations.
+- If changing `Bulk request concurrency` didn't help, you can use the [routing rules](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules) option to [limit indexing jobs only to specific Sidekiq nodes](elasticsearch.md#index-large-instances-with-dedicated-sidekiq-nodes-or-processes), which should reduce the number of indexing requests.
### Indexing is very slow or fails with `rejected execution of coordinating operation` messages
@@ -437,11 +437,11 @@ Improvements to the `code_analyzer` pattern and filters are being discussed in [
In GitLab 13.9, a change was made where [binary file names are being indexed](https://gitlab.com/gitlab-org/gitlab/-/issues/301083). However, without indexing all projects' data from scratch, only binary files that are added or updated after the GitLab 13.9 release are searchable.
-## How does Advanced Search handle private projects?
+## How does advanced search handle private projects?
-Advanced Search stores all the projects in the same Elasticsearch indices,
+Advanced search stores all the projects in the same Elasticsearch indices,
however, searches only surface results that can be viewed by the user.
-Advanced Search honors all permission checks in the application by
+Advanced search honors all permission checks in the application by
filtering out projects that a user does not have access to at search time.
### Role mapping when using fine-grained access control with AWS Elasticsearch or OpenSearch
diff --git a/doc/integration/datadog.md b/doc/integration/datadog.md
index 8b64e3898f9..2c86b7a8ed3 100644
--- a/doc/integration/datadog.md
+++ b/doc/integration/datadog.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/270123) in GitLab 14.1
-This integration enables you to send CI/CD pipeline and job information to
+The Datadog integration enables you to send CI/CD pipeline and job information to
[Datadog](https://www.datadoghq.com/). The [Datadog CI Visibility](https://app.datadoghq.com/ci)
product helps you monitor for job failures and performance issues, then troubleshoot them.
It's based on [Webhooks](../user/project/integrations/webhooks.md),
diff --git a/doc/integration/ding_talk.md b/doc/integration/ding_talk.md
index ca939dc9f9a..cb7ba6849b9 100644
--- a/doc/integration/ding_talk.md
+++ b/doc/integration/ding_talk.md
@@ -6,7 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# DingTalk OAuth 2.0 OmniAuth provider **(FREE SELF)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/341898) in GitLab 14.5.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/341898) in GitLab 14.5.
+> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390855) in GitLab 15.10.
You can sign in to GitLab using your DingTalk account.
Sign in to DingTalk Open Platform and create an application on it. DingTalk generates a client ID and secret key for you to use.
diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md
index a3c206176b9..355be006fe8 100644
--- a/doc/integration/external-issue-tracker.md
+++ b/doc/integration/external-issue-tracker.md
@@ -4,7 +4,7 @@ group: Integrations
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# External issue tracker **(FREE)**
+# External issue trackers **(FREE)**
GitLab has an [issue tracker](../user/project/issues/index.md), but you can
configure an external issue tracker per GitLab project.
diff --git a/doc/integration/facebook.md b/doc/integration/facebook.md
index 8b7bdeaa177..b35e3c585e0 100644
--- a/doc/integration/facebook.md
+++ b/doc/integration/facebook.md
@@ -31,7 +31,7 @@ Facebook. Facebook generates an app ID and secret key for you to use.
1. Choose "Next"
-1. Choose "Skip Quick Start" in the upper right corner
+1. In the upper-right corner, select **Skip Quick Start**.
1. Choose "Settings" in the menu on the left
diff --git a/doc/integration/gitpod.md b/doc/integration/gitpod.md
index ee8f46e73df..6df36cff638 100644
--- a/doc/integration/gitpod.md
+++ b/doc/integration/gitpod.md
@@ -69,6 +69,6 @@ You can launch Gitpod directly from GitLab in one of these ways:
1. Select **Open in Gitpod**.
- *From a merge request:*
1. Go to your merge request.
- 1. In the upper right corner, select **Code**, then select **Open in Gitpod**.
+ 1. In the upper-right corner, select **Code**, then select **Open in Gitpod**.
Gitpod builds your development environment for your branch.
diff --git a/doc/integration/glab/index.md b/doc/integration/glab/index.md
index 621472a2083..427751a0297 100644
--- a/doc/integration/glab/index.md
+++ b/doc/integration/glab/index.md
@@ -43,19 +43,24 @@ glab mr merge
## Core commands
-- `glab alias`
-- `glab api`
-- `glab auth`
-- `glab ci`
-- `glab issue`
-- `glab label`
-- `glab mr`
-- `glab project`
-- `glab release`
-- `glab snippet`
-- `glab ssh-key`
-- `glab user`
-- `glab variable`
+- [`glab alias`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/alias)
+- [`glab api`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/api)
+- [`glab auth`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/auth)
+- [`glab check-update`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/check-update)
+- [`glab ci`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/ci)
+- [`glab completion`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/completion)
+- [`glab config`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/config)
+- [`glab incident`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/incident)
+- [`glab issue`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/ci)
+- [`glab label`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/label)
+- [`glab mr`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/mr)
+- [`glab release`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/release)
+- [`glab repo`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/repo)
+- [`glab schedule`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/schedule)
+- [`glab snippet`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/snippet)
+- [`glab ssh-key`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/ssh-key)
+- [`glab user`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/user)
+- [`glab variable`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/variable)
## Install the CLI
@@ -69,7 +74,7 @@ To authenticate with your GitLab account, run `glab auth login`.
## Report issues
-Open an issue in the [`gitlab-org/cli` repository](https://gitlab.com/gitlab-org/cli/issues/new)
+Open an issue in the [`gitlab-org/cli` repository](https://gitlab.com/gitlab-org/cli/-/issues/new)
to send us feedback.
## Related topics
diff --git a/doc/integration/gmail_action_buttons_for_gitlab.md b/doc/integration/gmail_action_buttons_for_gitlab.md
index 4a233df3899..6de7e7ab17c 100644
--- a/doc/integration/gmail_action_buttons_for_gitlab.md
+++ b/doc/integration/gmail_action_buttons_for_gitlab.md
@@ -7,8 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Gmail actions **(FREE)**
GitLab supports [Google actions in email](https://developers.google.com/gmail/markup/actions/actions-overview).
-
-If correctly set up, emails that require an action are marked in Gmail.
+When you configure this integration, emails that require an action are marked in Gmail.
![Gmail actions button](img/gmail_action_buttons_for_gitlab.png)
diff --git a/doc/integration/google.md b/doc/integration/google.md
index 5eac639f119..bb76d7c8ff1 100644
--- a/doc/integration/google.md
+++ b/doc/integration/google.md
@@ -22,7 +22,7 @@ In Google's side:
the randomly generated ID or choose a new one.
1. Refresh the page and you should see your new project in the list
1. Go to the [Google API Console](https://console.developers.google.com/apis/dashboard)
-1. Select the previously created project in the upper left corner
+1. In the upper-left corner, select the previously created project
1. Select **Credentials** from the sidebar
1. Select **OAuth consent screen** and fill the form with the required information
1. In the **Credentials** tab, select **Create credentials > OAuth client ID**
diff --git a/doc/integration/index.md b/doc/integration/index.md
index 195890ea4d8..02860339b6f 100644
--- a/doc/integration/index.md
+++ b/doc/integration/index.md
@@ -73,7 +73,7 @@ You can integrate GitLab with the following feature enhancements:
or [Kroki](../administration/integration/kroki.md) to use diagrams in AsciiDoc and Markdown documents.
- Attach merge requests to [Trello](trello_power_up.md) cards.
- Enable integrated code intelligence powered by [Sourcegraph](sourcegraph.md).
-- Add [Elasticsearch](advanced_search/elasticsearch.md) for [Advanced Search](../user/search/advanced_search.md).
+- Add [Elasticsearch](advanced_search/elasticsearch.md) for [advanced search](../user/search/advanced_search.md).
## Troubleshooting
diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md
index 983ff3c54bc..668038ef386 100644
--- a/doc/integration/jenkins.md
+++ b/doc/integration/jenkins.md
@@ -166,7 +166,7 @@ If you get this error message while configuring GitLab, the following are possib
- 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#create-an-allowlist-for-local-requests).
+ [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).
diff --git a/doc/integration/jira/configure.md b/doc/integration/jira/configure.md
index 03d742703a1..3ef4dfac3f4 100644
--- a/doc/integration/jira/configure.md
+++ b/doc/integration/jira/configure.md
@@ -4,7 +4,7 @@ group: Integrations
info: To 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 the Jira integration **(FREE)**
+# Configure Jira **(FREE)**
You can set up the [Jira integration](index.md#jira-integration)
by configuring your project settings in GitLab.
@@ -13,10 +13,10 @@ and for self-managed GitLab, at an [instance level](../../user/admin_area/settin
Prerequisites:
-- Ensure your GitLab installation does not use a [relative URL](development_panel.md#limitations).
+- Ensure your GitLab installation does not use a [relative URL](https://docs.gitlab.com/omnibus/settings/configuration.html#configure-a-relative-url-for-gitlab).
- For **Jira Server**, ensure you have a Jira username and password.
See [authentication in Jira](index.md#authentication-in-jira).
-- For **Jira on Atlassian cloud**, ensure you have an API token
+- For **Jira Cloud**, ensure you have an API token
and the email address you used to create the token.
See [authentication in Jira](index.md#authentication-in-jira).
diff --git a/doc/integration/jira/connect-app.md b/doc/integration/jira/connect-app.md
index 402efc409cb..8bbac021849 100644
--- a/doc/integration/jira/connect-app.md
+++ b/doc/integration/jira/connect-app.md
@@ -27,8 +27,8 @@ at least the Maintainer role in the GitLab.com namespace.
This integration method supports [Smart Commits](dvcs/index.md#smart-commits).
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For a walkthrough of the integration with GitLab for Jira Cloud app, watch
-[Configure GitLab.com Jira Could Integration using Marketplace App](https://youtu.be/SwR-g1s1zTo) on YouTube.
+For an overview, see
+[Configure the GitLab for Jira Cloud app from the Atlassian Marketplace](https://youtu.be/SwR-g1s1zTo).
To install the GitLab for Jira Cloud app:
@@ -117,7 +117,7 @@ Jira apps can only link to one URL per marketplace listing. The official listing
If your instance doesn't meet the prerequisites or you don't want to use the official marketplace listing, you can
[install the app manually](#install-the-gitlab-for-jira-cloud-app-manually).
-It's not possible to create branches from Jira for self-managed instances.
+It's not possible to create branches from Jira for self-managed instances. For more information, see [issue 391432](https://gitlab.com/gitlab-org/gitlab/-/issues/391432).
### Set up your instance
@@ -285,3 +285,29 @@ To resolve this issue on GitLab self-managed, follow one of the solutions below,
- Contact the [Jira Software Cloud support](https://support.atlassian.com/jira-software-cloud/) and ask to trigger a new installed lifecycle event for the GitLab for Jira Cloud app in your namespace.
- In all GitLab versions:
- Re-install the GitLab for Jira Cloud app. This might remove all already synced development panel data.
+
+## Security considerations
+
+The GitLab for Jira Cloud app connects GitLab and Jira, as data must be shared between the two applications and access must be granted in both directions.
+
+## Access to GitLab through OAuth
+
+GitLab does not share an access token with Jira. However, users must authenticate via OAuth to configure the app.
+
+An access token is retrieved via [PKCE](https://www.rfc-editor.org/rfc/rfc7636) OAuth flow, and stored only on the client side.
+The app-frontend that initializes the OAuth flow is a JavaScript application, which is loaded from GitLab through an iframe on Jira.
+
+The OAuth application requires the `api` scope that grants complete read/write access to the API, including to all groups and projects, the container registry, and the package registry.
+However, the GitLab for Jira Cloud app only uses this access to:
+
+- Display namespaces to be linked.
+- Link namespaces.
+
+Access through OAuth is only needed for the time a user configures the GitLab for Jira Cloud app. For more information, see [Access token expiration](../oauth_provider.md#access-token-expiration).
+
+## Access to Jira through access token
+
+Jira shares an access token with GitLab to authenticate and authorize data pushes to Jira.
+As part of the app installation process, Jira sends a handshake request to GitLab containing the access token.
+The handshake is signed with an [asymmetric JWT](https://developer.atlassian.com/cloud/jira/platform/understanding-jwt-for-connect-apps/)
+and the access token is stored encrypted with `AES256-GCM` on GitLab.
diff --git a/doc/integration/jira/development_panel.md b/doc/integration/jira/development_panel.md
index f36b9f2c4c1..57308c9a19e 100644
--- a/doc/integration/jira/development_panel.md
+++ b/doc/integration/jira/development_panel.md
@@ -4,99 +4,94 @@ group: Integrations
info: To 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 Jira development panel integration **(FREE)**
+# Jira development panel **(FREE)**
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/233149) from GitLab Premium to GitLab Free in 13.4.
-With the Jira development panel integration, you can reference Jira issues in GitLab.
-When configured, activity (such as pipeline, deployment, and feature flags) displays in the Jira issue's
-[development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/).
-From the development panel, you can open a detailed view and
-[take various actions](#use-the-integration), including creating a new merge request from a branch:
+You can view GitLab activity from the Jira development panel.
-![Branch, Commit and Pull Requests links on Jira issue](img/jira_dev_panel_jira_setup_3.png)
+When you're in GitLab, you can refer to a Jira issue by ID.
+The [activity for that issue](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/)
+is displayed in the Jira development panel.
-The information displayed in the Jira development panel depends on where you mention the Jira issue ID:
+In the Jira development panel, you can create a GitLab merge request from a branch.
+You can also create a GitLab branch from a Jira issue in the GitLab for Jira Cloud app
+([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66032) in GitLab 14.2).
-| Your mention of Jira issue ID in GitLab context | Automated effect in Jira issue |
-|---------------------------------------------------|--------------------------------------------------------------------------------------------------------|
-| In a merge request title or description | Link to the MR is displayed in the development panel. |
-| In a branch name | Link to the branch is displayed in the development panel. |
-| In a commit message | Link to the commit is displayed in the development panel. |
-| In a commit message with Jira [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html) | Displays your custom comment or logged time spent and/or performs specified issue transition on merge. |
+## Connected projects in GitLab
-This integration connects all GitLab projects to projects in the Jira instance in either:
+The Jira development panel connects to the entire Jira instance all GitLab projects in:
-- A top-level GitLab group: Connects the projects in a group with no parent group,
- including the projects in its subgroups.
-- A personal namespace: Connects the projects in that personal namespace to Jira.
+- A top-level group, including all projects in its subgroups.
+- A personal namespace.
-## Use the integration
+These GitLab projects can interact with all Jira projects in that instance.
-After the integration is [set up on GitLab and Jira](#configure-the-integration), you can:
+## Information displayed in the panel
-- Refer to any Jira issue by its ID (in uppercase) in GitLab branch names,
- commit messages, and merge request titles.
-- See the linked branches, commits, and merge requests in Jira issues.
-- Create GitLab branches from Jira Cloud issues ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66032) in GitLab 14.2 for the GitLab for Jira app).
+The information displayed in the Jira development panel depends on where you mention the Jira issue ID in GitLab.
-At this time, merge requests are called "pull requests" in Jira issues.
-This name may change in a future Jira release.
+| GitLab: where you mention the Jira issue ID | Jira development panel: what information is displayed |
+|------------------------------------------------|-------------------------------------------------------|
+| Merge request title or description | Link to the merge request |
+| Branch name | Link to the branch |
+| Commit message | Link to the commit |
+| [Jira Smart Commit](#jira-smart-commits) | Custom comment, logged time, or workflow transition |
-Select the links to see your GitLab repository data.
+## Jira Smart Commits
-![GitLab commits details on a Jira issue](img/jira_dev_panel_jira_setup_4.png)
+Jira Smart Commits are special commands to process a Jira issue. With these commands, you can use GitLab to:
-![GitLab merge requests details on a Jira issue](img/jira_dev_panel_jira_setup_5.png)
+- Add a custom comment to a Jira issue.
+- Log time against a Jira issue.
+- Transition a Jira issue to any status defined in the project workflow.
-### Use Jira Smart Commits
+For more information, see the
+[Atlassian documentation](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html).
-With Jira [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html),
-you can use GitLab to add Jira comments, log time spent on the issue, or apply any issue transition.
-
-For more information about using Jira Smart Commits to track time against an issue, specify
-an issue transition, or add a custom comment, read the Atlassian page
-[Using Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html).
-
-## Configure the integration
+## Configure the panel
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For an overview of how to configure the Jira development panel integration, see
-[Agile Management - GitLab Jira development panel integration](https://www.youtube.com/watch?v=VjVTOmMl85M).
+For an overview, see [Jira development panel integration](https://www.youtube.com/watch?v=VjVTOmMl85M).
+
+### For GitLab.com
-To simplify administration, we recommend that a GitLab group maintainer or group owner
-(or, if possible, instance administrator in the case of self-managed GitLab) set up the integration.
+Prerequisite:
-| Jira usage | GitLab.com customers need | GitLab self-managed customers need |
-|------------|---------------------------|------------------------------------|
-| [Atlassian cloud](https://www.atlassian.com/migration/assess/why-cloud) | The [GitLab for Jira Cloud app](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?hosting=cloud&tab=overview) from the [Atlassian Marketplace](https://marketplace.atlassian.com). This method offers real-time sync between GitLab.com and Jira. The method requires inbound connections for the setup and then pushes data to Jira through outbound connections. For more information, see [GitLab for Jira Cloud app](connect-app.md). | The GitLab for Jira Cloud app [installed manually](connect-app.md#install-the-gitlab-for-jira-cloud-app-manually). By default, you can install the app from the [Atlassian Marketplace](https://marketplace.atlassian.com/). The method requires inbound connections for the setup and then pushes data to Jira through outbound connections. For more information, see [Connect the GitLab for Jira Cloud app for self-managed instances](connect-app.md#connect-the-gitlab-for-jira-cloud-app-for-self-managed-instances). |
-| Your own server | The [Jira DVCS connector](dvcs/index.md). This method syncs data every hour and works only with inbound connections. The method tries to set up webhooks in GitLab to implement real-time data sync, which does not work without outbound connections. | The [Jira DVCS connector](dvcs/index.md). This method syncs data every hour and works only with inbound connections. The method tries to set up webhooks in GitLab to implement real-time data sync, which does not work without outbound connections. |
+- You must have at least the Maintainer role for the group.
-Each GitLab project can be configured to connect to an entire Jira instance. That means after
-configuration, one GitLab project can interact with all Jira projects in that instance. For:
+To configure the Jira development panel on GitLab.com:
-- The [view Jira issues](issues.md#view-jira-issues) feature, you must associate a GitLab project with a
- specific Jira project.
-- Other features, you do not have to explicitly associate a GitLab project with any single Jira
- project.
+- **For [Jira Cloud](https://www.atlassian.com/migration/assess/why-cloud)**:
+ - [From the Atlassian Marketplace, install the GitLab for Jira Cloud app](https://marketplace.atlassian.com/apps/1221011/gitlab-for-jira-cloud?hosting=cloud&tab=overview).
+ - This method syncs data between GitLab.com and Jira in real time.
+ - This method requires inbound connections for the setup and outbound connections to push data to Jira.
+ - For more information, see [GitLab for Jira Cloud app](connect-app.md).
+- **For Jira Server**:
+ - Use the [Jira DVCS connector](dvcs/index.md).
+ - This method syncs data every hour and works only with inbound connections.
+ - This method attempts to set up webhooks in GitLab to sync data in real time, which requires outbound connections.
-If you have a single Jira instance, you can pre-fill the settings. For more information, read the
-documentation for [central administration of project integrations](../../user/admin_area/settings/project_integration_management.md).
+### For self-managed GitLab
-## Limitations
+Prerequisites:
-- This integration is not supported on GitLab instances under a
-[relative URL](https://docs.gitlab.com/omnibus/settings/configuration.html#configure-a-relative-url-for-gitlab)
-(for example, `http://example.com/gitlab`).
-- [Creating a branch](https://gitlab.com/gitlab-org/gitlab/-/issues/2647) is only supported by the GitLab for Jira app and is not available within the DVCS integration. See [officially supported DVCS features](https://confluence.atlassian.com/adminjiraserver/integrating-with-development-tools-938846890.html) for more information.
+- You must have administrator access to the instance.
+- Your GitLab installation must not use a [relative URL](https://docs.gitlab.com/omnibus/settings/configuration.html#configure-a-relative-url-for-gitlab)
+ (for example, `https://example.com/gitlab`).
-## Troubleshoot the development panel
+To configure the Jira development panel on self-managed GitLab:
-If you use Jira on your own server, go to the [Atlassian documentation](https://confluence.atlassian.com/jirakb/troubleshoot-the-development-panel-in-jira-server-574685212.html)
-for general troubleshooting information.
+- **For [Jira Cloud](https://www.atlassian.com/migration/assess/why-cloud)**:
+ - [Install the GitLab for Jira Cloud app manually](connect-app.md#install-the-gitlab-for-jira-cloud-app-manually).
+ - This method requires inbound connections for the setup and outbound connection to push data to Jira.
+ - For more information, see [Connect the GitLab for Jira Cloud app for self-managed instances](connect-app.md#connect-the-gitlab-for-jira-cloud-app-for-self-managed-instances).
+- **For Jira Server**:
+ - Use the [Jira DVCS connector](dvcs/index.md).
+ - This method syncs data every hour and works only with inbound connections.
+ - This method attempts to set up webhooks in GitLab to sync data in real time, which requires outbound connections.
-### Cookies for Oracle's Access Manager
+## Troubleshooting
-To support Oracle's Access Manager, GitLab sends additional cookies
-to enable Basic Auth. The cookie being added to each request is `OBBasicAuth` with
-a value of `fromDialog`.
+To troubleshoot the Jira development panel on your own server, see the
+[Atlassian documentation](https://confluence.atlassian.com/jirakb/troubleshoot-the-development-panel-in-jira-server-574685212.html).
diff --git a/doc/integration/jira/img/jira_dev_panel_jira_setup_3.png b/doc/integration/jira/img/jira_dev_panel_jira_setup_3.png
deleted file mode 100644
index c58f1d5cecc..00000000000
--- a/doc/integration/jira/img/jira_dev_panel_jira_setup_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/jira/img/jira_dev_panel_jira_setup_4.png b/doc/integration/jira/img/jira_dev_panel_jira_setup_4.png
deleted file mode 100644
index 81d84cb173d..00000000000
--- a/doc/integration/jira/img/jira_dev_panel_jira_setup_4.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/jira/img/jira_dev_panel_jira_setup_5.png b/doc/integration/jira/img/jira_dev_panel_jira_setup_5.png
deleted file mode 100644
index b143fc24355..00000000000
--- a/doc/integration/jira/img/jira_dev_panel_jira_setup_5.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/jira/index.md b/doc/integration/jira/index.md
index 2ad71a19cf7..3ec4c7aee87 100644
--- a/doc/integration/jira/index.md
+++ b/doc/integration/jira/index.md
@@ -4,7 +4,7 @@ group: Integrations
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Jira integrations **(FREE)**
+# Jira **(FREE)**
If your organization uses [Jira](https://www.atlassian.com/software/jira) issues,
you can [migrate your issues from Jira](../../user/project/import/jira.md) and work
@@ -37,7 +37,7 @@ displays in the [development panel](https://support.atlassian.com/jira-software-
To set up the Jira development panel integration, use the GitLab for Jira Cloud app
or the Jira DVCS (distributed version control system) connector,
-[depending on your installation](development_panel.md#configure-the-integration).
+[depending on your installation](development_panel.md#configure-the-panel).
### Direct feature comparison
@@ -63,8 +63,8 @@ The authentication method in Jira depends on whether you host Jira on your own s
required. Connecting to Jira Server using the Central Authentication Service (CAS) is not possible. For more information, read
how to [set up a user in Jira Server](jira_server_configuration.md).
- **Jira on Atlassian cloud** supports authentication through an API token. When connecting to Jira on
- Atlassian cloud, an email and API token are required. For more information, read
- [create an API token for Jira in Atlassian cloud](jira_cloud_configuration.md).
+ Atlassian cloud, an email and API token are required. For more information, see
+ [Create a Jira Cloud API token](jira_cloud_configuration.md).
## Privacy considerations
diff --git a/doc/integration/jira/issues.md b/doc/integration/jira/issues.md
index 3a5d8e66b2d..58da871926b 100644
--- a/doc/integration/jira/issues.md
+++ b/doc/integration/jira/issues.md
@@ -4,10 +4,10 @@ group: Integrations
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Jira integration issue management **(FREE)**
+# Jira issue management **(FREE)**
-Integrating issue management with Jira requires you to [configure Jira](index.md#jira-integration)
-and [enable the Jira integration](configure.md) in GitLab.
+To integrate issue management with Jira, [configure Jira](index.md#jira-integration)
+and [enable the integration](configure.md) in GitLab.
After you configure and enable the integration, you can reference and close Jira
issues by mentioning the Jira ID in GitLab commits and merge requests.
@@ -47,12 +47,11 @@ You can [disable comments](#disable-comments-on-jira-issues) on issues.
### Require associated Jira issue for merge requests to be merged **(ULTIMATE)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/280766) in GitLab 13.12, disabled behind `jira_issue_association_on_merge_request` [feature flag](../../administration/feature_flags.md).
-> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61722) in GitLab 14.1.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/335280) in GitLab 14.2.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/280766) in GitLab 13.12 [with a flag](../../administration/feature_flags.md) named `jira_issue_association_on_merge_request`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/335280) in GitLab 14.2. Feature flag `jira_issue_association_on_merge_request` removed.
-You can prevent merge requests from being merged if they do not refer to a Jira issue.
-To enforce this:
+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 top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Merge requests**.
diff --git a/doc/integration/jira/jira_server_configuration.md b/doc/integration/jira/jira_server_configuration.md
index 7dee99b024e..5bac108b457 100644
--- a/doc/integration/jira/jira_server_configuration.md
+++ b/doc/integration/jira/jira_server_configuration.md
@@ -20,7 +20,7 @@ credentials, you must:
This process creates a user named `gitlab`:
1. Sign in to your Jira instance as a Jira administrator.
-1. In the upper right corner of the top menu, go to the gear icon and
+1. On the top bar, in the upper-right corner, select the gear icon, then
select **User Management**.
1. Create a new user account (`gitlab`) with write access to
projects in Jira.
@@ -43,9 +43,9 @@ group to assign permissions to the user.
This process adds the `gitlab` user you created to a new group named `gitlab-developers`:
1. Sign in to your Jira instance as a Jira administrator.
-1. In the upper right corner of the top menu, go to the gear icon and
+1. On the top bar, in the upper-right corner, select the gear icon, then
select **User Management**.
-1. On the sidebar, select **Groups**.
+1. On the left sidebar, select **Groups**.
![Jira create new user](img/jira_create_new_group.png)
@@ -70,9 +70,9 @@ Next, create a permission scheme for your group.
After creating the group in Jira, grant permissions to the group by creating a permission scheme:
1. Sign in to your Jira instance as a Jira administrator.
-1. In the upper right corner of the top menu, go to the gear icon and
+1. On the top bar, in the upper-right corner, select the gear icon, then
select **Issues**.
-1. On the sidebar, select **Permission Schemes**.
+1. On the left sidebar, select **Permission Schemes**.
1. Select **Add Permission Scheme**, enter a **Name** and (optionally) a
**Description**, and then select **Add**.
1. In the permissions scheme list, locate your new permissions scheme, and
diff --git a/doc/integration/jira/troubleshooting.md b/doc/integration/jira/troubleshooting.md
index 0e679693614..bf347c4698d 100644
--- a/doc/integration/jira/troubleshooting.md
+++ b/doc/integration/jira/troubleshooting.md
@@ -91,16 +91,16 @@ To reset the Jira user's password for all projects with active Jira integrations
run the following in a [Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session):
```ruby
-p = Project.find_by_sql("SELECT p.id FROM projects p LEFT JOIN services s ON p.id = s.project_id WHERE s.type = 'JiraService' AND s.active = true")
+p = Project.find_by_sql("SELECT p.id FROM projects p LEFT JOIN integrations i ON p.id = i.project_id WHERE i.type_new = 'Integrations::Jira' AND i.active = true")
p.each do |project|
project.jira_integration.update_attribute(:password, '<your-new-password>')
end
```
-## `500 Whoops` when accessing a Jira issue in GitLab
+## `500 We're sorry` when accessing a Jira issue in GitLab
-When accessing a Jira issue in GitLab, you might get a `500 Whoops, something went wrong on our end` error.
+When accessing a Jira issue in GitLab, you might get a `500 We're sorry. Something went wrong on our end` error.
Check [`production.log`](../../administration/logs/index.md#productionlog) to see if it contains the following exception:
```plaintext
diff --git a/doc/integration/mattermost/index.md b/doc/integration/mattermost/index.md
index 42592a0dff2..e1183f62225 100644
--- a/doc/integration/mattermost/index.md
+++ b/doc/integration/mattermost/index.md
@@ -10,7 +10,7 @@ NOTE:
This document applies to GitLab 11.0 and later.
You can run a [GitLab Mattermost](https://gitlab.com/gitlab-org/gitlab-mattermost)
-service on your GitLab server. Mattermost is not part of the single application that GitLab is. There is a good integration between with GitLab, and our Omnibus installer allows you to easily install it. But it is a separate application from a separate company.
+service on your GitLab server. Mattermost is not part of the single application that GitLab is. There is a good integration between [Mattermost and GitLab](https://mattermost.com/solutions/mattermost-gitlab/), and our Omnibus installer allows you to easily install it. But it is a separate application from a separate company.
## Prerequisites
@@ -245,7 +245,7 @@ For local connections, the `mmctl` binary and Mattermost must be run from the sa
"LocalModeSocketLocation": "/var/tmp/mattermost_local.socket",
...
}
- }
+ }
```
1. Restart Mattermost:
@@ -280,7 +280,7 @@ $ /opt/gitlab/embedded/bin/mmctl auth login http://mattermost.example.com
Connection name: test
Username: local-user
-Password:
+Password:
credentials for "test": "local-user@http://mattermost.example.com" stored
```
@@ -378,6 +378,10 @@ 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 15.10
+
+GitLab 15.10 ships with Mattermost 7.8. Before upgrading, [connect to the bundled PostgreSQL database](#connecting-to-the-bundled-postgresql-database) to perform the PostgreSQL maintenance described in the [Important Upgrade Notes](https://docs.mattermost.com/administration/important-upgrade-notes.html) provided by Mattermost.
+
## 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).
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 61019915c52..66d4ccb871f 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -379,8 +379,12 @@ but we'd like to at least help those with specific needs.
## Keep OmniAuth user profiles up to date
-You can enable profile syncing from selected OmniAuth providers. You can sync
-all or specific user information.
+You can enable profile syncing from selected OmniAuth providers.
+You can sync any combination of the following user attributes:
+
+- `name`
+- `email`
+- `location`
When authenticating using LDAP, the user's name and email are always synced.
diff --git a/doc/integration/partner_marketplace.md b/doc/integration/partner_marketplace.md
index a15457b5b0c..5ed131145f4 100644
--- a/doc/integration/partner_marketplace.md
+++ b/doc/integration/partner_marketplace.md
@@ -1,13 +1,13 @@
---
stage: Fulfillment
-group: Commerce Integrations
+group: Provision
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Marketplace partner integration guide
+# Marketplace partners
GitLab supports automation for selected distribution marketplaces to process sales of GitLab products to authorized
-channel partners. Marketplace partners can use the GitLab Marketplace APIs to integrate their systems with GitLab to
+channel partners. Marketplace partners can use the GitLab Marketplace APIs to integrate their systems with GitLab to
sell GitLab subscriptions on their site.
This document's target audience is third-party developers for Marketplace partners.
@@ -48,17 +48,113 @@ sequenceDiagram
Customers Portal ->> Marketplace partner system: Success response with order status
```
-## Prerequisites
+## Marketplace API Specification
+
+OpenAPI specs for the Marketplace APIs are available at [Marketplace interactive API documentation](https://customers.staging.gitlab.com/openapi_docs/marketplace).
+
+## Access the Marketplace API
+
+To access the Marketplace API you need to:
+
+- Request access from GitLab.
+- Retrieve an OAuth access token.
+
+Marketplace API endpoints are secured with [OAuth 2.0](https://oauth.net/2/). OAuth is an authorization framework
+that grants 3rd party or client applications, like a GitLab Partner application, limited access to resources on an
+HTTP service, like the Customers Portal.
+
+OAuth 2.0 uses _grant types_ (or _flows_) that describe how a client application gets authorization in
+the form of an _access token_. An access token is a string that the client application uses to make authorized requests to
+the resource server.
+
+The Marketplace API uses the `client_credentials` grant type. The client application uses the access token to access its
+own resources, instead of accessing resources on behalf of a user.
+
+### Step 1: Request access
-Before a marketplace partner client can use the Marketplace API, GitLab must set up the following configurations for the client:
+Before you can use the Marketplace API, you must contact your GitLab Partner Manager or email [`partnerorderops`](mailto:partnerorderops@gitlab.com)
+to request access. After you request access, GitLab configures the following accounts and credentials for you:
-1. Client credential. Marketplace APIs are secured with OAuth 2.0. A client credential is required to get the OAuth token.
+1. Client credentials. Marketplace APIs are secured with OAuth 2.0. The client credentials include the client ID and client secret
+ that you need to retrieve the OAuth access token.
1. Invoice owner account in Zuora system. Required for invoice processing.
1. Distributor account in Salesforce system.
1. Trading partner account in Salesforce system.
-Interested GitLab Partners should contact their GitLab Partner Manager or email [`partnerorderops`](mailto:partnerorderops@gitlab.com).
+### Step 2: Retrieve an access token
-## Marketplace API Specification
+To retrieve an access token,
+
+- Make a POST request to the [`/oauth/token`](https://customers.staging.gitlab.com/openapi_docs/marketplace#/marketplace/post_oauth_token) endpoint with the following required parameters:
+
+| Parameter | Type | Required |Description |
+|-----------------|--------|----------|------------------------------------------------------------------------------------------------------------------------------------|
+| `client_id` | string | yes |ID of your client application record on the Customers Portal. Received from GitLab. |
+| `client_secret` | string | yes |Secret of your client application record on the Customers Portal. Received from GitLab. |
+| `grant_type` | string | yes |Specifies the type of credential flow. Use `client_credentials`. |
+| `scope` | string | yes |Specifies the level of access. Use `marketplace.order:read` for read-only access. Use `marketplace.order:create` for create access. |
+
+If the request is successful, the response body includes the access token that you can use in subsequent requests. For an example of a successful
+response, see the [Marketplace interactive API documentation](https://customers.staging.gitlab.com/openapi_docs/marketplace)
+
+If the request is unsuccessful, the response body includes an error and error description. The errors can be:
+
+| Status | Description |
+|--------|----------------------------------------------------------------------------------------------------------------------------------------------|
+| 400 | Invalid scope. Ensure the `scope` is `marketplace.order:read` or `marketplace.order:create`. |
+| 401 | Invalid client. Ensure that there are no typos or extra spaces on the client specific credentials. Incorrect `client_id` or `client_secret` |
+
+### Step 3: Use the access token
+
+To use the access token from a client application:
+
+1. Set the `Authorization` header of the request to `Bearer <your_access_token>`.
+1. Set parameters or data needed for the endpoint and send the request.
+
+Example request:
+
+```shell
+curl \
+ --url "https://customers.staging.gitlab.com/api/v1/marketplace/subscriptions/:external_subscription_id" \
+ --header "Authorization: Bearer NHb_VhZhPOnBTSNfBSzmCmt28lLDWb2xtwr_c3DL148"
+```
+
+## Create a new customer subscription
+
+To create a new customer subscription from a GitLab Partner client application,
+
+- Make an authorized POST request to the
+[`/api/v1/marketplace/subscriptions`](https://customers.staging.gitlab.com/openapi_docs/marketplace#/marketplace/post_api_v1_marketplace_subscriptions)
+endpoint in the Customers Portal with the following parameters in JSON format:
+
+| Parameter | Type | Required | Description |
+|--------------------------|--------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `externalSubscriptionId` | string | yes | ID of the subscription on the GitLab Partner system. |
+| `tradingPartnerId` | string | yes | ID of the GitLab Partner account on the Customers Portal. |
+| `customer` | object | yes | Information about the customer. Must include company name. Contact must include `firstName`, `lastName` and `email`. Address must include `country`. |
+| `orderLines` | array | yes | Specifies the product purchased. Must include `quantity` and `productId`. |
+
+If the request is successful, the response body includes the newly created subscription number. For an example of a full request body,
+see the [Marketplace interactive API documentation](https://customers.staging.gitlab.com/openapi_docs/marketplace).
+
+If the subscription creation is unsuccessful, the response body includes an error message with details about the cause of the error.
+
+## Check the status of a subscription
+
+To get the status of a given subscription,
+
+- Make an authorized GET request to the
+[`/api/v1/marketplace/subscriptions/{external_subscription_id}`](https://customers.staging.gitlab.com/openapi_docs/marketplace#/marketplace/get_api_v1_marketplace_subscriptions__external_subscription_id_)
+endpoint in the Customers Portal.
+
+The request must include the GitLab partner system ID of the subscription to fetch the status for.
+
+If the request is successful, the response body contains the status of the subscription provision. The status can be:
+
+- Creating
+- Created
+- Failed
+- Provisioned
-OpenAPI specs for the Marketplace APIs are available upon request. The specs will be made public before the end of Q1 2023.
+If the subscription cannot be found using the passed `external_subscription_id`, the response has
+a 404 Not Found status.
diff --git a/doc/integration/saml.md b/doc/integration/saml.md
index 24b5e6152a5..888dd47a968 100644
--- a/doc/integration/saml.md
+++ b/doc/integration/saml.md
@@ -734,6 +734,10 @@ For a full list of supported assertions, see the [OmniAuth SAML gem](https://git
## Configure users based on SAML group membership
+NOTE:
+SAML Group Sync is only supported for the [SAML provider named `saml`](#configure-gitlab-to-use-multiple-saml-idps).
+As a result, SAML Group Sync only supports a single SAML provider. For more information, see [issue 366450](https://gitlab.com/gitlab-org/gitlab/-/issues/366450).
+
You can:
- Require users to be members of a certain group.
@@ -749,7 +753,7 @@ Support for these groups depends on:
- Whether you've installed [GitLab Enterprise Edition (EE)](https://about.gitlab.com/install/).
- The [name of the SAML provider](#configure-saml-support-in-gitlab). Group
memberships are only supported by a single SAML provider named
- `saml`. For more information, see [issue 386605](https://gitlab.com/gitlab-org/gitlab/-/issues/386605).
+ `saml`.
| Group | Tier | GitLab Enterprise Edition (EE) Only? |
|------------------------------|--------------------|--------------------------------------|
diff --git a/doc/integration/trello_power_up.md b/doc/integration/trello_power_up.md
index 9cca8e5485d..908fc623d0e 100644
--- a/doc/integration/trello_power_up.md
+++ b/doc/integration/trello_power_up.md
@@ -6,14 +6,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Trello Power-Ups **(FREE)**
-You can use the Trello Power-Up for GitLab to attach
+You can use Trello Power-Ups for GitLab to attach
GitLab merge requests to Trello cards.
-![GitLab Trello PowerUp - Trello card](img/trello_card_with_gitlab_powerup.png)
+![GitLab Trello Power-Ups - Trello card](img/trello_card_with_gitlab_powerup.png)
-## Configure the Power-Up
+## Configure Power-Ups
-To configure a Power-Up for a Trello board:
+To configure Power-Ups for a Trello board:
1. Go to your Trello board.
1. Select **Power-Ups** and find the **GitLab** row.
diff --git a/doc/operations/error_tracking.md b/doc/operations/error_tracking.md
index 0be2f087c62..8931f3ef833 100644
--- a/doc/operations/error_tracking.md
+++ b/doc/operations/error_tracking.md
@@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
WARNING:
This feature is in its end-of-life process. It is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/389991)
-for use in GitLab 15.9, and is planned for removal in GitLab 16.0. We are replacing this feature with functionality in the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui). Please also reference our direction for [Observability](https://about.gitlab.com/direction/monitor/observability/) and [data visualization](https://about.gitlab.com/direction/monitor/observability/data-visualization/).
+for use in GitLab 15.9, and is planned for removal in GitLab 16.0. We are replacing this feature with functionality in the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui). Please also reference our direction for [Observability](https://about.gitlab.com/direction/monitor/observability/) and [data visualization](https://about.gitlab.com/direction/monitor/observability/data-visualization/).
Error Tracking allows developers to discover and view errors generated by their application. Because error information is surfaced where the code is being developed, efficiency and awareness are increased.
@@ -34,15 +34,15 @@ For error tracking to work, you need two pieces:
## Sentry error tracking
-[Sentry](https://sentry.io/) is an open source error tracking system. GitLab allows administrators to connect Sentry to GitLab, to allow users to view a list of Sentry errors in GitLab.
+[Sentry](https://sentry.io/) is an open source error tracking system. GitLab allows administrators to connect Sentry to GitLab so users can view a list of Sentry errors in GitLab.
### Deploying Sentry
-You can sign up to the cloud hosted [Sentry](https://sentry.io) or deploy your own [on-premise instance](https://github.com/getsentry/onpremise/).
+You can sign up to the cloud-hosted [Sentry](https://sentry.io) or deploy your own [on-premise instance](https://github.com/getsentry/onpremise/).
### Enabling Sentry
-GitLab provides an easy way to connect Sentry to your project. You need at
+GitLab provides a way to connect Sentry to your project. You need at
least Maintainer [permissions](../user/permissions.md) to enable the Sentry integration.
1. Sign up to Sentry.io or [deploy your own](#deploying-sentry) Sentry instance.
@@ -84,7 +84,7 @@ DSN in **Sentry.io > Project Settings > Client Keys (DSN) > Show deprecated DSN*
ERROR: Sentry failure builds=0 error=raven: dsn missing private key
```
-## Error Tracking List
+## Error Tracking list
Users with at least Reporter [permissions](../user/permissions.md)
can find the Error Tracking list at **Monitor > Error Tracking** in your project's sidebar.
@@ -92,11 +92,11 @@ Here, you can filter errors by title or by status (one of Ignored , Resolved, or
![Error Tracking list](img/error_tracking_list_v12_6.png)
-## Error Details
+## Error details
-From error list, users can navigate to the error details page by selecting the title of any error.
+From error list, users can go to the error details page by selecting the title of any error.
-This page has:
+This page includes:
- A link to the Sentry issue.
- A link to the GitLab commit if the Sentry [release ID/version](https://docs.sentry.io/product/releases/?platform=javascript#configure-sdk) on the Sentry Issue's first release matches a commit SHA in your GitLab hosted project.
@@ -108,26 +108,26 @@ By default, a **Create issue** button is displayed:
![Error Details without Issue Link](img/error_details_v12_7.png)
If you create a GitLab issue from the error, the **Create issue** button changes to a **View issue**
-button and a link to the GitLab issue displays within the error detail section.
+button and a link to the GitLab issue displays in the error detail section.
-## Taking Action on errors
+## Taking action on errors
-You can take action on Sentry Errors from within the GitLab UI. Marking errors ignored or resolved require at least Developer role.
+You can take action on Sentry Errors in the GitLab UI. Marking errors as ignored or resolved requires at least Developer role.
### Ignoring errors
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/39665) in GitLab 12.7.
-From within the [Error Details](#error-details) page you can ignore a Sentry error by selecting the **Ignore** button near the top of the page.
+In the [Error Details](#error-details) page you can ignore a Sentry error by selecting **Ignore** near the top of the page.
-Ignoring an error prevents it from appearing in the [Error Tracking List](#error-tracking-list), and silences notifications that were set up within Sentry.
+Ignoring an error prevents it from appearing in the [Error Tracking List](#error-tracking-list), and silences notifications that were set up in Sentry.
### Resolving errors
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/39825) in GitLab 12.7.
-From within the [Error Details](#error-details) page you can resolve a Sentry error by
-selecting the **Resolve** button near the top of the page.
+In the [Error Details](#error-details) page you can resolve a Sentry error by
+selecting **Resolve** near the top of the page.
Marking an error as resolved indicates that the error has stopped firing events. If a GitLab issue is linked to the error, then the issue closes.
@@ -140,53 +140,225 @@ If another event occurs, the error reverts to unresolved.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/7586) in GitLab 15.6.
NOTE:
-Available only on GitLab.com. This feature is currently in [Open Beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#open-beta).
+Available only on GitLab.com. This feature is in [Open Beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#open-beta).
-Integrated error tracking is a lightweight alternative to Sentry backend.
-You still use Sentry SDK with your application. But you don't need to deploy Sentry
-or set up for cloud-hosted Sentry. Instead, you use GitLab as a backend for it.
+### Known limitations
-Sentry backend automatically assigns a Data Source Name (DSN) for every project you create.
-GitLab does the same. You should be able to find a DSN for your project in the GitLab error tracking
-settings. By using a GitLab-provided DSN, your application connects to GitLab to report an error.
-Those errors are stored in the GitLab database and rendered by the GitLab UI, in the same way as
-Sentry integration.
+Only basic support is provided with `capture_exception` as the holding method.
+Additional features requests (see this [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/340178)) are added on a case-by-case basis.
-In GitLab 15.6 and later, the integrated error tracking
-uses a new backend based on the ClickHouse database that enables better scalability.
-Integrated error tracking remains limited in comparison to the Sentry backend, as only a small subset of the
-Sentry API is implemented.
+### Debugging issues
-Changing the GitLab error UI to use the GitLab Observability UI is tracked in epic [19](https://gitlab.com/groups/gitlab-org/opstrace/-/epics/32).
+The majority of languages are supported by Sentry expose `debug` option as part of initialization.
+It is also possible to output JSON before it is sent to the API.
+See the [Go example](#go) below for a suggested solution.
-### Project settings
+### Enabling error tracking
-You can find the feature configuration at **Settings > Monitor > Error Tracking**.
+Regardless of the programming language, you need to enable error tracking for your project. This doc assumes you already have a project for which you want to enable error tracking.
+This example uses the `gitlab.com` instance.
-#### How to enable
+To enable error tracking, follow these steps:
-1. Select **GitLab** as the error tracking backend for your project:
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Monitor**.
+1. Expand the **Error Tracking** tab.
+1. Under **Enable error tracking**, select the **Active** checkbox.
+1. Under **Error tracking backend**, select **GitLab**.
+1. Select **Save changes**.
+1. Copy the DSN string to use later.
+
+### Listing captured errors
+
+Once your application has emitted errors to the Error Tracking API through the Sentry SDK, they should be available under **Monitor > Error Tracking** tab/section.
+
+For more details, refer to the [GitLab error tracking documentation](https://gitlab.com/help/operations/error_tracking#error-tracking-list).
+
+This process assumes the GDK feature flag `integrated_error_tracking` is enabled. If you are running GDK locally and you do not see the option for error tracking, you can enable it by running the following commands:
+
+```linux
+cd <PATH_TO_GDK>
+gdk rails console
+Feature.enable(:integrated_error_tracking)
+```
+
+### Emitting errors
+
+#### Supported Sentry types
+
+According to the [data model](https://develop.sentry.dev/sdk/envelopes/#data-model), the available item types are:
+
+- [Event](https://develop.sentry.dev/sdk/event-payloads/)
+- [Transactions](https://develop.sentry.dev/sdk/event-payloads/transaction/)
+- Attachment
+- [Session](https://develop.sentry.dev/sdk/sessions/)
+- [Sessions](https://develop.sentry.dev/sdk/sessions/)
+- [User feedback](https://develop.sentry.dev/sdk/envelopes/#user-feedback) (also known as user report)
+- [Client report](https://develop.sentry.dev/sdk/client-reports/)
+
+Items of various types can be sent to the error tracking app, using either the Store endpoint, the envelope endpoint, or both. The following table lists all event types available through Sentry SDK. It also explains which endpoint can be used for ingestion and whether it is supported by GitLab Observability Backend.
+
+Event item types can contain various interfaces, such as exception, message, stack trace, and template. You can read more about the core data interfaces in [Sentry documentation](https://develop.sentry.dev/sdk/event-payloads/#core-interfaces).
+
+| Item type | Interface | Can be sent through the Store endpoint | Can be sent through the Envelope endpoint | Supported |
+| --------------- | ----------- | -------------------------------------- | ----------------------------------------- | ---------------------- |
+| `event` | exception | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| `event` | message | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| `event` | stack trace | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| `event` | template | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
+| `transaction` | N/A | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
+| `attachment` | N/A | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
+| `session` | N/A | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
+| `sessions` | N/A | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
+| `user_report` | N/A | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
+| `client_report` | N/A | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
+
+#### Supported languages
+
+Each language shows a basic example of how to capture exceptions with the respective SDK.
+For more in-depth documentation, see [documentation for Sentry SDK](https://docs.sentry.io/). You can also find information for additional programming languages.
+
+Only a subset of languages is supported.
+
+The following table lists them:
+
+| Sentry SDK | Supported? |
+| ----------- | ----------- |
+| Ruby | Yes |
+| Go | Yes |
+| JavaScript | Yes |
+| Java | Yes |
+| Python | Yes |
+| PHP | Yes |
+| .NET | Not tested |
+| Android | Not tested |
+| Apple | Not tested |
+| Perl | Not tested |
+
+A more up-to-date version of [this matrix can be found in this doc](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/1737).
+
+#### Go
+
+1. `chdir` into folder `docs/guides/user/error_tracking_examples/go/`
+1. Install the dependencies with the following command:
+
+ ```shell
+ go mod tidy
+ ```
+
+1. Run the following command:
+
+ ```shell
+ export SENTRY_DSN="<DSN string>"
+ go run main.go <DSN string>
+ ```
+
+After you've run this program, there should be an error visible in the Error tracking tab from `Listing captured errors` section of this document.
+
+#### Ruby
+
+1. `chdir` into folder `docs/guides/user/error_tracking_examples/ruby/`
+1. Install the dependencies with the following command:
+
+ ```shell
+ gem install bundler
+ bundle install
+ ```
+
+1. Execute the example with the following command:
+
+ ```shell
+ export SENTRY_DSN="<DSN string>"
+ ruby app.rb
+ ```
+
+After you've run this program, there should be an error visible in the Error tracking tab from `Listing captured errors` section of this document.
+
+#### PHP
+
+1. `chdir` into folder `docs/guides/user/error_tracking_examples/php/`
+
+1. Build and run the Docker container with the following commands:
+
+```shell
+export SENTRY_DSN="<DSN string>"
+docker build -t sentry-php .
+docker run -e SENTRY_DSN --rm sentry-php
+```
+
+After you've run this program, there should be an error visible in the Error tracking tab from `Listing captured errors` section of this document.
+
+#### Python
+
+1. `chdir` into folder `docs/guides/user/error_tracking_examples/python/`
+
+1. Install the dependencies with the following commands:
+
+ ```shell
+ virtualenv env
+ source env/bin/activate
+ pip install -r requirements.txt
+ ```
+
+1. Run the following commands:
+
+```shell
+export SENTRY_DSN="<DSN string>"
+python send_exception.py
+```
+
+After you've run this program, there should be an error visible in the Error tracking tab from `Listing captured errors` section of this document.
+
+#### Java
+
+1. `chdir` into folder `docs/guides/user/error_tracking_examples/python/`
+
+1. Run the following command:
+
+```shell
+export SENTRY_DSN="<DSN string>"
+./gradlew run
+```
+
+#### Node.js
+
+1. `chdir` into folder `docs/guides/user/error_tracking_examples/nodejs/`
+
+1. Install the dependencies with the following command:
+
+ ```shell
+ npm install --save @sentry/node @sentry/tracing
+ ```
+
+1. Run the following command:
+
+ ```shell
+ export SENTRY_DSN="<DSN string>"
+ node ./test.js
+ ```
- ![Error Tracking Settings](img/error_tracking_setting_v14_3.png)
+After you've run this program, there should be an error visible in the Error tracking tab from `Listing captured errors` section of this document.
-1. Select **Save changes**. After page reload you should see a text field with the DSN string. Copy it.
+### Rotating Sentry DSN
- ![Error Tracking Settings DSN](img/error_tracking_setting_dsn_v14_4.png)
+The Sentry DSN (client key) is a secret and it should not be exposed to the public. If it's leaked, you can rotate the Sentry DSN with the following steps:
-1. Take the DSN from the previous step and configure your Sentry SDK with it. Errors are now
- reported to the GitLab collector and are visible in the [GitLab UI](#error-tracking-list).
+1. [Create an access token](../user/profile/personal_access_tokens.md#create-a-personal-access-token) by clicking your profile picture in GitLab.com. Then choose Preferences,then Access Token. Make sure you add the API scope.
+1. Using the [error tracking API](../api/error_tracking.md), create a new Sentry DSN with the following command:
-#### Managing DSN
+ ```shell
+ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" \
+ "https://gitlab.example.com/api/v4/projects/<your_project_number>/error_tracking/client_keys"
+ ```
-When you enable the feature you receive a DSN. It includes a hash used for authentication. This hash
-is a client key. GitLab uses client keys to authenticate error tracking requests from your
-application to the GitLab backend.
+1. Get the available client keys (Sentry DSNs). Ensure that the newly created Sentry DSN is in place. Then note down the key ID of the old client key:
-In some situations, you may want to create a new client key and remove an existing one.
-You can do so by managing client keys with the [error tracking API](../api/error_tracking.md).
+ ```shell
+ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<your_project_number>/error_tracking/client_keys"
+ ```
-#### Limitations
+1. Delete the old client key with the following command:
-The Integrated Error Tracking feature was built and tested with Sentry SDK for Ruby on Rails.
-Support for other languages and frameworks is not guaranteed. For up-to-date information, see the
-[compatibility issue](https://gitlab.com/gitlab-org/gitlab/-/issues/340178).
+ ```shell
+ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<your_project_number>/error_tracking/client_keys/<key_id>"
+ ```
diff --git a/doc/operations/feature_flags.md b/doc/operations/feature_flags.md
index 68fc0fb9499..968649e94b2 100644
--- a/doc/operations/feature_flags.md
+++ b/doc/operations/feature_flags.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -151,7 +151,7 @@ Enables the feature for a list of target users. It is implemented
using the Unleash UserIDs (`userWithId`) activation [strategy](https://docs.getunleash.io/reference/activation-strategies#userids).
Enter user IDs as a comma-separated list of values (for example,
-`user@example.com, user2@example.com`, or `username1,username2,username3`, and so on).
+`user@example.com, user2@example.com`, or `username1,username2,username3`, and so on).
User IDs are identifiers for your application users. They do not need to be GitLab users.
WARNING:
@@ -295,14 +295,13 @@ Unleash currently [offers many SDKs for various languages and frameworks](https:
For API content, see:
- [Feature flags API](../api/feature_flags.md)
-- [Feature flag specs API](../api/feature_flag_specs.md) (Deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/213369) in GitLab 14.0.)
- [Feature flag user lists API](../api/feature_flag_user_lists.md)
-### Golang application example
+### Go application example
-Here's an example of how to integrate feature flags in a Golang application:
+Here's an example of how to integrate feature flags in a Go application:
-```golang
+```go
package main
import (
diff --git a/doc/operations/img/copy-group-id.png b/doc/operations/img/copy-group-id.png
deleted file mode 100644
index 7837f49c3e3..00000000000
--- a/doc/operations/img/copy-group-id.png
+++ /dev/null
Binary files differ
diff --git a/doc/operations/img/create-gitlab-application.png b/doc/operations/img/create-gitlab-application.png
deleted file mode 100644
index 430b830cdb2..00000000000
--- a/doc/operations/img/create-gitlab-application.png
+++ /dev/null
Binary files differ
diff --git a/doc/operations/img/error_tracking_setting_dsn_v14_4.png b/doc/operations/img/error_tracking_setting_dsn_v14_4.png
deleted file mode 100644
index b7ecaa047b2..00000000000
--- a/doc/operations/img/error_tracking_setting_dsn_v14_4.png
+++ /dev/null
Binary files differ
diff --git a/doc/operations/img/error_tracking_setting_v14_3.png b/doc/operations/img/error_tracking_setting_v14_3.png
deleted file mode 100644
index 14306130c97..00000000000
--- a/doc/operations/img/error_tracking_setting_v14_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/operations/img/listing_groups.png b/doc/operations/img/listing_groups.png
deleted file mode 100644
index 1094bf4ff28..00000000000
--- a/doc/operations/img/listing_groups.png
+++ /dev/null
Binary files differ
diff --git a/doc/operations/incident_management/incident_timeline_events.md b/doc/operations/incident_management/incident_timeline_events.md
index e79f36884cb..7913e4668eb 100644
--- a/doc/operations/incident_management/incident_timeline_events.md
+++ b/doc/operations/incident_management/incident_timeline_events.md
@@ -110,12 +110,13 @@ Alternatively:
## Incident tags
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8741) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `incident_event_tags`. Disabled by default.
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8741) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `incident_event_tags`. Disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/387647) in GitLab 15.9.
+> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/387647) in GitLab 15.10.
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 `incident_event_tags`.
-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, ask an administrator to [disable the feature flag](../../administration/feature_flags.md) named `incident_event_tags`.
+On GitLab.com, this feature is available.
[When creating an event using the form](#using-the-form) or editing it,
you can specify incident tags to capture relevant incident timestamps.
diff --git a/doc/operations/incident_management/manage_incidents.md b/doc/operations/incident_management/manage_incidents.md
index ad4de8641e5..338dacda166 100644
--- a/doc/operations/incident_management/manage_incidents.md
+++ b/doc/operations/incident_management/manage_incidents.md
@@ -220,7 +220,7 @@ Prerequisites:
- You must have at least the Reporter role for the project.
-To close an incident, in the upper right, select **Close incident**.
+To close an incident, in the upper-right corner, select **Close incident**.
When you close an incident that is linked to an [alert](alerts.md),
the linked alert's status changes to **Resolved**.
diff --git a/doc/operations/index.md b/doc/operations/index.md
index ff13c617ea7..d4a5f895947 100644
--- a/doc/operations/index.md
+++ b/doc/operations/index.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
GitLab provides a variety of tools to help operate and maintain
your applications.
-## Measure reliability and stability with metrics (DEPRECATED)
+## Measure reliability and stability with metrics (deprecated)
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
@@ -35,14 +35,14 @@ performance degrades, and manage those alerts - all within GitLab.
GitLab helps reduce alert fatigue for IT responders by providing tools to identify
issues across multiple systems and aggregate alerts in a centralized place. Your
-team needs a single, central interface where they can easily investigate alerts
+team needs a single, central interface where they can investigate alerts
and promote the critical alerts to incidents.
Are your alerts too noisy? Alerts configured on GitLab metrics can configured
and fine-tuned in GitLab immediately following a fire-fight.
- [Manage alerts and incidents](incident_management/index.md) in GitLab.
-- [Configure alerts for metrics](metrics/alerts.md) in GitLab. (DEPRECATED)
+- [Configure alerts for metrics](metrics/alerts.md) in GitLab. (deprecated)
- Create a [status page](incident_management/status_page.md)
to communicate efficiently to your users during an incident.
diff --git a/doc/operations/metrics/dashboards/default.md b/doc/operations/metrics/dashboards/default.md
index e22b1096023..96c1238fd34 100644
--- a/doc/operations/metrics/dashboards/default.md
+++ b/doc/operations/metrics/dashboards/default.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
---
-# GitLab-defined metrics dashboards (DEPRECATED) **(FREE)**
+# GitLab-defined metrics dashboards (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/operations/metrics/dashboards/develop.md b/doc/operations/metrics/dashboards/develop.md
index fe14ec1dc3d..af76c09ca80 100644
--- a/doc/operations/metrics/dashboards/develop.md
+++ b/doc/operations/metrics/dashboards/develop.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
---
-# Developing templates for custom dashboards (DEPRECATED) **(FREE)**
+# Developing templates for custom dashboards (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/operations/metrics/dashboards/index.md b/doc/operations/metrics/dashboards/index.md
index 09bb8cedbf6..b2fc7397d17 100644
--- a/doc/operations/metrics/dashboards/index.md
+++ b/doc/operations/metrics/dashboards/index.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
---
-# Custom dashboards (DEPRECATED) **(FREE)**
+# Custom dashboards (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/59974) in GitLab 12.1.
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
@@ -124,9 +124,9 @@ can manage [the settings](settings.md) for your metrics dashboard.
## Chart Context Menu
-You can take action related to a chart's data by selecting the
-**{ellipsis_v}** **More actions** dropdown list above the upper right corner of
-any chart on a dashboard:
+To take action related to a chart's data:
+
+- In the upper-right corner of the chart, select **More actions** (**{ellipsis_v}**).
![Context Menu](img/panel_context_menu_v14_0.png)
diff --git a/doc/operations/metrics/dashboards/panel_types.md b/doc/operations/metrics/dashboards/panel_types.md
index 177a55fb85b..39893f279ff 100644
--- a/doc/operations/metrics/dashboards/panel_types.md
+++ b/doc/operations/metrics/dashboards/panel_types.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
---
-# Panel types for dashboards (DEPRECATED) **(FREE)**
+# Panel types for dashboards (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/operations/metrics/dashboards/settings.md b/doc/operations/metrics/dashboards/settings.md
index 5fb0476e164..6ddedd98fcb 100644
--- a/doc/operations/metrics/dashboards/settings.md
+++ b/doc/operations/metrics/dashboards/settings.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
---
-# Dashboard settings (DEPRECATED) **(FREE)**
+# Dashboard settings (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/operations/metrics/dashboards/templating_variables.md b/doc/operations/metrics/dashboards/templating_variables.md
index a1c2ce063bc..a27e75aacef 100644
--- a/doc/operations/metrics/dashboards/templating_variables.md
+++ b/doc/operations/metrics/dashboards/templating_variables.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
---
-# Templating variables for metrics dashboards (DEPRECATED) **(FREE)**
+# Templating variables for metrics dashboards (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214539) in GitLab 13.0.
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/operations/metrics/dashboards/variables.md b/doc/operations/metrics/dashboards/variables.md
index 2881c084115..152f7522c4e 100644
--- a/doc/operations/metrics/dashboards/variables.md
+++ b/doc/operations/metrics/dashboards/variables.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
---
-# Using variables (DEPRECATED) **(FREE)**
+# Using variables (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/operations/metrics/dashboards/yaml.md b/doc/operations/metrics/dashboards/yaml.md
index 7b0a91dd18a..e8bba4b6e42 100644
--- a/doc/operations/metrics/dashboards/yaml.md
+++ b/doc/operations/metrics/dashboards/yaml.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
---
-# Dashboard YAML properties (DEPRECATED) **(FREE)**
+# Dashboard YAML properties (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/operations/metrics/embed.md b/doc/operations/metrics/embed.md
index f622780530a..987f1dc019d 100644
--- a/doc/operations/metrics/embed.md
+++ b/doc/operations/metrics/embed.md
@@ -48,9 +48,8 @@ GitLab unfurls the link as an embedded metrics panel:
![Embedded Metrics Rendered](img/embedded_metrics_rendered_v13_4.png)
-You can also embed a single chart. To get a link to a chart, select
-**{ellipsis_v}** **More actions** in the upper right corner of the chart,
-and select **Copy link to chart**, as shown in this example:
+You can also embed a single chart. To get a link to a chart, in the upper-right corner of the chart,
+select **More actions** (**{ellipsis_v}**), then select **Copy link to chart** as shown in this example.
![Copy Link To Chart](img/copy_link_to_chart_v12_10.png)
diff --git a/doc/operations/metrics/index.md b/doc/operations/metrics/index.md
index 11350d65237..e67e7b0f97e 100644
--- a/doc/operations/metrics/index.md
+++ b/doc/operations/metrics/index.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
---
-# Monitor your environment's metrics **(FREE)**
+# Monitor your environment's metrics (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
@@ -124,7 +124,7 @@ After saving them, they display on the environment metrics dashboard provided th
- A [connected Kubernetes cluster](../../user/clusters/agent/index.md)
with the matching [environment scope](../../ci/environments/index.md#limit-the-environment-scope-of-a-cicd-variable) is used and
- [Prometheus installed on the cluster](../../user/project/integrations/prometheus.md#enabling-prometheus-integration).
+ [Prometheus installed on the cluster](../../user/project/integrations/prometheus.md#enabling-the-prometheus-integration).
- Prometheus is [manually configured](../../user/project/integrations/prometheus.md#manual-configuration-of-prometheus).
![Add New Metric](img/prometheus_add_metric.png)
diff --git a/doc/operations/quickstart-guide.md b/doc/operations/quickstart-guide.md
deleted file mode 100644
index 91c5f25405c..00000000000
--- a/doc/operations/quickstart-guide.md
+++ /dev/null
@@ -1,229 +0,0 @@
----
-stage: Monitor
-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
----
-
-# GitLab Observability Quickstart
-
-You can try GitLab Observability by [cloning or forking the project](https://gitlab.com/gitlab-org/opstrace/opstrace.git) and creating a local installation.
-
-## Prerequisites and dependencies
-
-To install GitLab Observability Platform (GOP), install and configure the following third-party dependencies. You can do this manually, or [automatically by using asdf](#install-dependencies-using-asdf):
-
-- [kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) for creating a local Kubernetes cluster.
-- [Docker](https://docs.docker.com/install)
- - [Docker Compose](https://docs.docker.com/compose/compose-v2/) is now part of the `docker` distribution.
-- [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) for interacting with GitLab Observability.
-- [Telepresence](https://www.telepresence.io/) allows you to code and test microservices locally against a remote Kubernetes cluster.
-- [jq](https://stedolan.github.io/jq/download/) for some Makefile utilities.
-- [Go 1.19](https://go.dev/doc/install).
-
-The current versions of these dependencies are pinned in the `.tool-versions` file in the project.
-
-You can run the following commands to check the availability and versions of these dependencies on your machine:
-
-```shell
-kind --version
-docker --version
-kubectl version
-telepresence version
-jq --version
-go version
-```
-
-### Run GOP on macOS
-
-If you're running GOP on macOS, ensure you have enough resources dedicated to Docker Desktop. The recommended minimum is:
-
-- CPUs: 4+
-- Memory: 8 GB+
-- Swap: 1 GB+
-
-It's possible to run GOP with fewer resources, but this specification works.
-
-### Install dependencies using asdf
-
-If you install dependencies using [`asdf`](https://asdf-vm.com/#/core-manage-asdf), GOP manages them for you automatically.
-
-1. If you have not already done so, clone the `opstrace` repository into your preferred location:
-
- ```shell
- git clone https://gitlab.com/gitlab-org/opstrace/opstrace.git
- ```
-
-1. Change into the project directory:
-
- ```shell
- cd opstrace
- ```
-
-1. Optional. If you need to install `asdf`, run:
-
- ```shell
- make install-asdf
- ```
-
-1. Install dependencies using `asdf`:
-
- ```shell
- make bootstrap
- ```
-
-## Step 1: Create a local Kubernetes cluster with kind
-
-Make sure Docker Desktop is running. In the `opstrace` project you cloned, run the following command:
-
-```shell
-make kind
-```
-
-Wait a few minutes while kind creates your Kubernetes cluster. When it's finished, you should see the following message:
-
-```plaintext
-Traffic Manager installed successfully
-```
-
-Now deploy the scheduler by running the following command in the `opstrace` project:
-
-```shell
-make deploy
-```
-
-This takes around 1 minute.
-
-## Step 2: Create a GitLab application for authentication
-
-You must create a GitLab application to use for authentication.
-
-In the GitLab instance you'd like to connect with GOP, [create an OAuth application](../integration/oauth_provider.md).
-This application can be a user-owned, group-owned or instance-wide application.
-In production, you would create a trusted instance-wide application so that users are explicitly authorized without the consent screen.
-The following example shows how to configure the application.
-
-1. Select the API scope and enter `http://localhost/v1/auth/callback` as the redirect URI.
-
-1. Run the following command to create the secret that holds the authentication data:
-
- ```shell
- kubectl create secret generic \
- --from-literal=gitlab_oauth_client_id=<gitlab_application_client_id> \
- --from-literal=gitlab_oauth_client_secret=<gitlab_application_client_secret> \
- --from-literal=internal_endpoint_token=<error_tracking_internal_endpoint_token> \
- dev-secret
- ```
-
-1. Replace `<gitlab_application_client_id>` and `<gitlab_application_client_secret>` with the values from the GitLab application you just created.
-Replace `<error_tracking_internal_endpoint_token>` with any string if you do not plan to use error tracking.
-
-You can also view [this MR on how to get the token to test error tracking](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91928).
-You must specify all the parameters when creating the secret.
-
-## Step 3: Create the cluster definition
-
-1. In your `opstrace` project, run the following command to create a `Cluster.yaml` manifest file:
-
- ```shell
- cat <<EOF > Cluster.yaml
- apiVersion: opstrace.com/v1alpha1
- kind: Cluster
- metadata:
- name: dev-cluster
- spec:
- target: kind
- goui:
- image: "registry.gitlab.com/gitlab-org/opstrace/opstrace-ui/ gitlab-observability-ui:c9fb6e70"
- dns:
- acmeEmail: ""
- dns01Challenge: {}
- externalDNSProvider: {}
- gitlab:
- groupAllowedAccess: '*'
- groupAllowedSystemAccess: "6543"
- instanceUrl: https://gitlab.com
- authSecret:
- name: dev-secret
- EOF
- ```
-
-1. Apply the file you just created with the following command:
-
- ```shell
- kubectl apply -f Cluster.yaml
- ```
-
-1. Run the following command to wait for the cluster to be ready:
-
- ```shell
- kubectl wait --for=condition=ready cluster/dev-cluster --timeout=600s
- ```
-
-After the previous command exits, the cluster is ready.
-
-## Step 4: Enable Observability on a GitLab namespace you own
-
-Go to a namespace you own in the connected GitLab instance and copy the Group ID below the group name.
-
-GOP can only be enabled for groups you own.
-To list all the groups that your user owns, go to the menu in upper left corner and select `Groups`->`View all Groups`. You then see the **Your groups** tab.
-
-In your browser, go to `http://localhost/-/{GroupID}`. For example, `http://localhost/-/14485840`.
-
-Follow the on-screen instructions to enable observability for the namespace.
-This can take a couple of minutes if it's the first time observability has been enabled for the root level namespace (GitLab.org in the previous example.)
-
-Once your namespace has been enabled and is ready, the page automatically redirects you to the GitLab Observability UI.
-
-## Step 5: Send traces to GOP
-
-[Follow this guide to send traces to your namespace and monitor them in the UI](https://gitlab.com/gitlab-org/opstrace/opstrace/-/blob/main/docs/guides/user/sending-traces-locally.md).
-
-## Step 6: Clean up your local GOP
-
-To tear down your locally running GOP instance, run the following command:
-
-```shell
-make destroy
-```
-
-## Known issues
-
-### Incorrect architecture for `kind/node` image
-
-If your machine has an Apple silicon (M1/M2) chip, you might encounter an architecture problem with the `kind/node` image when running the `make kind` command. For more details, see [issue 1802](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/1802).
-
-To fix this problem, you first need to create a Dockerfile. Then build and deploy the image:
-
-1. Create a new Dockerfile (without a file extension) and paste the following commands:
-
- ```Dockerfile
- FROM --platform=arm64 kindest/node:v1.23.13
- RUN arch
- ```
-
-1. Save your Dockerfile, then build the image with the following command:
-
- ```shell
- docker build -t tempkind .
- ```
-
- Do not forget the period at the end.
-
-1. Create a cluster using your new image with the following command:
-
- ```shell
- kind create cluster --image tempkind
- ```
-
-### scheduler-controller-manager pod cannot start due to ImagePullBackOff
-
-If while executing `make deploy` in step 1, the `scheduler-controller-manager` pod cannot start due to `ImagePullBackOff`, you must set the `CI_COMMIT_TAG` to a non-dirty state. By setting the commit tag to the latest commit, you ensure the Docker image can be pulled from the container registry.
-
-Run the following command to set the commit tag:
-
-```shell
-make kind
-export CI_COMMIT_TAG=0.2.0-e1206acf
-make deploy
-```
diff --git a/doc/policy/alpha-beta-support.md b/doc/policy/alpha-beta-support.md
index 1c7e9e77751..98910f9a3bb 100644
--- a/doc/policy/alpha-beta-support.md
+++ b/doc/policy/alpha-beta-support.md
@@ -12,7 +12,7 @@ All other features are considered to be Generally Available (GA).
## Alpha features
-Support is **not** provided for Alpha features and issues with them should be opened in the [GitLab issue tracker](https://gitlab.com/gitlab-org/gitlab/issues).
+Support is **not** provided for Alpha features and issues with them should be opened in the [GitLab issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues).
Characteristics of Alpha features:
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index fcb6e5c1b20..eed9f006bfa 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -110,9 +110,9 @@ The decision on whether backporting a change is performed is done at the discret
[current release managers](https://about.gitlab.com/community/release-managers/),
based on *all* of the following:
-1. Estimated [severity](../development/contributing/issue_workflow.md#severity-labels) of the bug:
+1. Estimated [severity](../development/labels/index.md#severity-labels) of the bug:
Highest possible impact to users based on the current definition of severity.
-1. Estimated [priority](../development/contributing/issue_workflow.md#priority-labels) of the bug:
+1. Estimated [priority](../development/labels/index.md#priority-labels) of the bug:
Immediate impact on all impacted users based on the above estimated severity.
1. Potentially incurring data loss and/or security breach.
1. Potentially affecting one or more strategic accounts due to a proven inability by the user to upgrade to the current stable version.
@@ -122,7 +122,7 @@ the current stable release, and two previous monthly releases. In rare cases a r
For instance, if we release `13.2.1` with a fix for a severe bug introduced in
`13.0.0`, we could backport the fix to a new `13.0.x`, and `13.1.x` patch release.
-Note that [severity](../development/contributing/issue_workflow.md#severity-labels) 3 and lower
+Note that [severity](../development/labels/index.md#severity-labels) 3 and lower
requests are automatically turned down.
To request backporting to more than one stable release for consideration, raise an issue in the
diff --git a/doc/raketasks/backup_gitlab.md b/doc/raketasks/backup_gitlab.md
index d63ef61a99f..5b4df8752f4 100644
--- a/doc/raketasks/backup_gitlab.md
+++ b/doc/raketasks/backup_gitlab.md
@@ -4,7 +4,7 @@ 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
---
-# Back up GitLab
+# Back up GitLab **(FREE SELF)**
GitLab provides a command line interface to back up your entire instance,
including:
@@ -262,6 +262,11 @@ For installations from source:
sudo -u git -H bundle exec rake gitlab:backup:create SKIP=db,uploads RAILS_ENV=production
```
+`SKIP=` is also used to:
+
+- [Skip creation of the tar file](#skipping-tar-creation) (`SKIP=tar`).
+- [Skip uploading the backup to remote storage](#skip-uploading-backups-to-remote-storage) (`SKIP=remote`).
+
### Skipping tar creation
NOTE:
@@ -411,12 +416,9 @@ You can let the backup script upload (using the [Fog library](https://fog.io/))
the `.tar` file it creates. In the following example, we use Amazon S3 for
storage, but Fog also lets you use [other storage providers](https://fog.io/storage/).
GitLab also [imports cloud drivers](https://gitlab.com/gitlab-org/gitlab/-/blob/da46c9655962df7d49caef0e2b9f6bbe88462a02/Gemfile#L113)
-for AWS, Google, OpenStack Swift, Rackspace, and Aliyun. A local driver is
+for AWS, Google, and Aliyun. A local driver is
[also available](#upload-to-locally-mounted-shares).
-NOTE:
-Support for Openstack Swift and Rackspace APIs will be removed in GitLab 15.10. See [issue #387976](https://gitlab.com/gitlab-org/gitlab/-/issues/387976) for more information.
-
[Read more about using object storage with GitLab](../administration/object_storage.md).
#### Using Amazon S3
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index a13d38a199d..9d82bbafe88 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -788,7 +788,7 @@ Truncating filenames to resolve the error involves:
#### Clean up remote uploaded files
-A [known issue](https://gitlab.com/gitlab-org/gitlab-foss/issues/45425) caused object store uploads to remain after a parent resource was deleted. This issue was [resolved](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18698).
+A [known issue](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/45425) caused object store uploads to remain after a parent resource was deleted. This issue was [resolved](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18698).
To fix these files, you must clean up all remote uploaded files that are in the storage but not tracked in the `uploads` database table.
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 073a0351ec5..3f716900d17 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -154,7 +154,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 [pipeline artifacts](../ci/pipelines/pipeline_artifacts.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
index 7445065c77e..73c49bd2599 100644
--- a/doc/raketasks/generate_sample_prometheus_data.md
+++ b/doc/raketasks/generate_sample_prometheus_data.md
@@ -4,9 +4,9 @@ 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
---
-# Generate sample Prometheus data Rake task **(FREE SELF)**
+# Sample Prometheus data Rake task **(FREE SELF)**
-This command runs Prometheus queries for each of the metrics of a specific environment
+The Rake task runs Prometheus queries for each of the metrics of a specific environment
for a series of time intervals to now:
- 30 minutes
@@ -16,12 +16,12 @@ for a series of time intervals to now:
- 72 hours
- 7 days
-The results of each of query are stored under a `sample_metrics` directory as a YAML
+The results of each query are stored under a `sample_metrics` directory as a YAML
file named by the metric's `identifier`. When the environmental variable `USE_SAMPLE_METRICS`
-is set, the Prometheus API query is re-routed to `Projects::Environments::SampleMetricsController`
-which loads the appropriate data set if it is present within the `sample_metrics` directory.
+is set, the Prometheus API query is re-routed to `Projects::Environments::SampleMetricsController`,
+which loads the appropriate data set if it's present in the `sample_metrics` directory.
-This command requires an ID from an environment with an available Prometheus installation.
+The Rake task requires an ID from an environment with an available Prometheus installation.
## Example
diff --git a/doc/raketasks/index.md b/doc/raketasks/index.md
index b5a778d6b74..e559605d147 100644
--- a/doc/raketasks/index.md
+++ b/doc/raketasks/index.md
@@ -12,7 +12,7 @@ processes.
You can perform GitLab Rake tasks by using:
-- `gitlab-rake <raketask>` for [Omnibus GitLab](https://docs.gitlab.com/omnibus/index.html) installations.
+- `gitlab-rake <raketask>` for [Omnibus GitLab](https://docs.gitlab.com/omnibus/index.html) and [GitLab Helm chart](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html#gitlab-specific-kubernetes-information) installations.
- `bundle exec rake <raketask>` for [source](../install/installation.md) installations.
## Available Rake tasks
@@ -28,7 +28,7 @@ The following Rake tasks are available for use with GitLab:
| [General maintenance](../administration/raketasks/maintenance.md) | General maintenance and self-check tasks. |
| [Geo maintenance](../administration/raketasks/geo.md) | [Geo](../administration/geo/index.md)-related maintenance. |
| [GitHub import](../administration/raketasks/github_import.md) | Retrieve and import repositories from GitHub. |
-| [Import large project exports](../development/import_project.md#importing-via-a-rake-task) | Import large GitLab [project exports](../user/project/settings/import_export.md). |
+| [Import large project exports](../administration/raketasks/project_import_export.md#import-large-projects) | Import large GitLab [project exports](../user/project/settings/import_export.md). |
| [Incoming email](../administration/raketasks/incoming_email.md) | Incoming email-related tasks. |
| [Integrity checks](../administration/raketasks/check.md) | Check the integrity of repositories, files, LDAP, and more. |
| [LDAP maintenance](../administration/raketasks/ldap.md) | [LDAP](../administration/auth/ldap/index.md)-related tasks. |
@@ -56,6 +56,9 @@ To list all available Rake tasks:
# Omnibus GitLab
sudo gitlab-rake -vT
+# GitLab Helm chart
+gitlab-rake -vT
+
# Installations from source
cd /home/git/gitlab
sudo -u git -H bundle exec rake -vT RAILS_ENV=production
diff --git a/doc/raketasks/restore_gitlab.md b/doc/raketasks/restore_gitlab.md
index c5bbb38cc37..13422817503 100644
--- a/doc/raketasks/restore_gitlab.md
+++ b/doc/raketasks/restore_gitlab.md
@@ -4,7 +4,7 @@ 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
---
-# Restore GitLab
+# Restore GitLab **(FREE SELF)**
GitLab provides a command line interface to restore your entire installation,
and is flexible enough to fit your needs.
@@ -273,9 +273,7 @@ project or group from there:
the backed-up instance from which you want to restore.
1. [Restore the backup](#restore-gitlab) into this new instance, then
export your [project](../user/project/settings/import_export.md)
- or [group](../user/group/settings/import_export.md). Be sure to read the
- **Important Notes** on either export feature's documentation to understand
- what is and isn't exported.
+ or [group](../user/group/import/index.md#migrate-groups-by-uploading-an-export-file-deprecated). For more information about what is and isn't exported, see the export feature's documentation.
1. After the export is complete, go to the old instance and then import it.
1. After importing the projects or groups that you wanted is complete, you may
delete the new, temporary GitLab instance.
diff --git a/doc/security/index.md b/doc/security/index.md
index 38eb5337f5a..e447b8ffe64 100644
--- a/doc/security/index.md
+++ b/doc/security/index.md
@@ -13,7 +13,7 @@ type: index
- [Generated passwords for users created through integrated authentication](passwords_for_integrated_authentication_methods.md)
- [Restrict SSH key technologies and minimum length](ssh_keys_restrictions.md)
- [Rate limits](rate_limits.md)
-- [Webhooks and insecure internal web services](webhooks.md)
+- [Filtering outbound requests](webhooks.md)
- [Information exclusivity](information_exclusivity.md)
- [Reset user password](reset_user_password.md)
- [Unlock a locked user](unlock_user.md)
diff --git a/doc/security/reset_user_password.md b/doc/security/reset_user_password.md
index 38c52912d5c..f8ba3953379 100644
--- a/doc/security/reset_user_password.md
+++ b/doc/security/reset_user_password.md
@@ -96,7 +96,7 @@ If you know the username, user ID, or email address, you can use the Rails conso
user.password = new_password
user.password_confirmation = new_password
```
-
+
To set a specific value for the new password:
```ruby
@@ -113,9 +113,9 @@ If you know the username, user ID, or email address, you can use the Rails conso
1. Save the changes:
- ```ruby
- user.save!
- ```
+ ```ruby
+ user.save!
+ ```
1. Exit the console:
@@ -145,10 +145,10 @@ attempt to fix this issue in a Rails console. For example, if a new `root` passw
1. Start a [Rails console](../administration/operations/rails_console.md).
1. Find the user and skip reconfirmation:
- ```ruby
- user = User.find(1)
- user.skip_reconfirmation!
- ```
+ ```ruby
+ user = User.find(1)
+ user.skip_reconfirmation!
+ ```
1. Attempt to sign in again.
diff --git a/doc/security/token_overview.md b/doc/security/token_overview.md
index a36d72f128d..b349eee9837 100644
--- a/doc/security/token_overview.md
+++ b/doc/security/token_overview.md
@@ -77,7 +77,7 @@ Project maintainers and owners can add or enable a deploy key for a project repo
## Runner registration tokens (deprecated)
WARNING:
-The ability to pass a runner registration token was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in GitLab 15.6 and is
+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
diff --git a/doc/security/user_file_uploads.md b/doc/security/user_file_uploads.md
index db2948a8bd5..80f4b1a8a2a 100644
--- a/doc/security/user_file_uploads.md
+++ b/doc/security/user_file_uploads.md
@@ -45,6 +45,30 @@ To configure authentication settings for all media files:
1. Scroll to **Project visibility** and select **Require authentication to view media files**.
You cannot select this option for projects with **Public** visibility.
+## Delete uploaded files
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92791) in GitLab 15.3.
+
+You should delete an uploaded file when that file contains sensitive or confidential information. When you have deleted that file, users cannot access the file and the direct URL returns a 404 error.
+
+Project Owners and Maintainers can use the [interactive GraphiQL explorer](../api/graphql/index.md#graphiql) to access a [GraphQL endpoint](../api/graphql/reference/index.md#mutationuploaddelete) and delete an uploaded file.
+
+For example:
+
+```graphql
+mutation{
+ uploadDelete(input: { projectPath: "<path/to/project>", secret: "<32-character-id>" , filename: "<filename>" }) {
+ upload {
+ id
+ size
+ path
+ }
+ errors
+ }
+}
+```
+
+Project members that do not have the Owner or Maintainer role cannot access this GraphQL endpoint.
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/security/webhooks.md b/doc/security/webhooks.md
index eeb6720dfb7..6164fb794c2 100644
--- a/doc/security/webhooks.md
+++ b/doc/security/webhooks.md
@@ -5,10 +5,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: concepts, reference, howto
---
-# Webhooks and insecure internal web services **(FREE SELF)**
+# Filtering outbound requests **(FREE SELF)**
+
+To protect against the risk of data loss and exposure, GitLab administrators can now use outbound request filtering controls to restrict certain outbound requests made by the GitLab instance.
+
+## Secure webhooks and integrations
Users with at least the Maintainer role can set up [webhooks](../user/project/integrations/webhooks.md) that are
-triggered when specific changes occur in a project. When triggered, a `POST` HTTP request is sent to a URL. A webhook is
+triggered when specific changes occur in a project or group. When triggered, a `POST` HTTP request is sent to a URL. A webhook is
usually configured to send data to a specific external web service, which processes the data in an appropriate way.
However, a webhook can be configured with a URL for an internal web service instead of an external web service.
@@ -32,9 +36,13 @@ that hosts the webhook including:
Webhooks can be used to trigger destructive commands using web services that don't require authentication. These webhooks
can get the GitLab server to make `POST` HTTP requests to endpoints that delete resources.
-## Allow webhook and service requests to local network
+### Allow requests to the local network from webhooks and integrations
+
+Prerequisite:
-To prevent exploitation of insecure internal web services, all webhook requests to the following local network addresses are not allowed:
+- You must have administrator access to the instance.
+
+To prevent exploitation of insecure internal web services, all webhook and integration requests to the following local network addresses are not allowed:
- The current GitLab instance server address.
- Private network addresses, including `127.0.0.1`, `::1`, `0.0.0.0`, `10.0.0.0/8`, `172.16.0.0/12`,
@@ -45,28 +53,64 @@ To allow access to these addresses:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
-1. Select the **Allow requests to the local network from web hooks and services** checkbox.
+1. Select the **Allow requests to the local network from webhooks and integrations** checkbox.
+
+### Prevent requests to the local network from system hooks
-## Prevent system hook requests to local network
+Prerequisite:
-[System hooks](../administration/system_hooks.md) are permitted to make requests to local network by default because
-they are set up by administrators. To prevent system hook requests to the local network:
+- You must have administrator access to the instance.
+
+[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 top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
1. Clear the **Allow requests to the local network from system hooks** checkbox.
-## Create an allowlist for local requests
+## Filter requests
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/377371) in GitLab 15.10 [with a flag](../administration/feature_flags.md) named `deny_all_requests_except_allowed`. 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 `deny_all_requests_except_allowed`.
+On GitLab.com, this feature is not available.
+
+Prerequisite:
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/44496) in GitLab 12.2
+- You must have administrator access to the instance.
-You can allow certain domains and IP addresses to be accessible to both system hooks and webhooks, even when local
-requests are forbidden. To add these domains to the allowlist:
+To filter requests by blocking many requests:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > Network**.
-1. Expand **Outbound requests** and add entries.
+1. Expand **Outbound requests**.
+1. Select the **Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist** checkbox.
+
+When this checkbox is selected, requests to the following are still not blocked:
+
+- Core services like Geo, Git, GitLab Shell, Gitaly, PostgreSQL, and Redis.
+- Object storage.
+- IP addresses and domains in the [allowlist](#allow-outbound-requests-to-certain-ip-addresses-and-domains).
+
+This setting is respected by the main GitLab application only, so other services like Gitaly can still make requests that break the rule.
+Additionally, [some areas of GitLab](https://gitlab.com/groups/gitlab-org/-/epics/8029) do not respect outbound filtering
+rules.
+
+## Allow outbound requests to certain IP addresses and domains
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/44496) in GitLab 12.2.
+
+Prerequisite:
+
+- You must have administrator access to the instance.
+
+To allow outbound requests to certain IP addresses and domains:
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > Network**.
+1. Expand **Outbound requests**.
+1. In **Local IP addresses and domain names that hooks and integrations can access**, enter your IP addresses and domains.
The entries can:
@@ -91,14 +135,37 @@ example.com;gitlab.example.com
example.com:8080
```
-<!-- ## Troubleshooting
+## Troubleshooting
+
+When filtering outbound requests, you might encounter the following issues.
+
+### Configured URLs are blocked
+
+You can only select the **Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist** checkbox if no configured URLs would be blocked. Otherwise, you might get an error message that says the URL is blocked.
+
+If you can't enable this setting, do one of the following:
+
+- Disable the URL setting.
+- Configure another URL, or leave the URL setting empty.
+- Add the configured URL to the [allowlist](#allow-requests-to-the-local-network-from-webhooks-and-integrations).
+
+### Public runner releases URL is blocked
+
+Most GitLab instances have their `public_runner_releases_url` set to
+`https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab-runner/releases`.
+You can't change or disable this setting in the Admin Area, which can prevent you from [filtering requests](#filter-requests).
+
+To enable the setting, use the [Rails console](../administration/operations/rails_console.md) to set `public_runner_releases_url` to the instance host:
+
+```ruby
+current_settings = ApplicationSetting.find_or_create_without_cache;
+ApplicationSettings::UpdateService.new(current_settings, nil, public_runner_releases_url: Gitlab.config.gitlab.base_url).execute
+```
+
+### GitLab subscription management is blocked
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
+When you [filter requests](#filter-requests), [GitLab subscription management](../subscriptions/self_managed/index.md)
+is blocked.
-Each scenario can be a third-level heading, for example `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+To work around this problem, add `customers.gitlab.com:443` to the
+[allowlist](#allow-outbound-requests-to-certain-ip-addresses-and-domains).
diff --git a/doc/subscriptions/bronze_starter.md b/doc/subscriptions/bronze_starter.md
index 91da875a049..accc0627a41 100644
--- a/doc/subscriptions/bronze_starter.md
+++ b/doc/subscriptions/bronze_starter.md
@@ -106,7 +106,7 @@ the tiers are no longer mentioned in GitLab documentation:
- Search:
- [Filtering merge requests](../user/project/merge_requests/index.md#filter-the-list-of-merge-requests) by approvers
- [Filtering merge requests](../user/project/merge_requests/index.md#filter-the-list-of-merge-requests) by "approved by"
- - [Advanced Search (Elasticsearch)](../user/search/advanced_search.md)
+ - [Advanced search (Elasticsearch)](../user/search/advanced_search.md)
- [Service Desk](../user/project/service_desk.md)
- [Storage usage statistics](../user/usage_quotas.md#storage-usage-statistics)
@@ -128,7 +128,7 @@ Bronze-level subscribers:
- [Group iterations API](../api/group_iterations.md)
- Project milestones API: [Get all burndown chart events for a single milestone](../api/milestones.md#get-all-burndown-chart-events-for-a-single-milestone)
- [Project iterations API](../api/iterations.md)
- - Fields in the [Search API](../api/search.md) available only to [Advanced Search (Elasticsearch)](../integration/advanced_search/elasticsearch.md) users
+ - Fields in the [Search API](../api/search.md) available only to [advanced search (Elasticsearch)](../integration/advanced_search/elasticsearch.md) users
- Fields in the [Merge requests API](../api/merge_requests.md) for [merge request approvals](../user/project/merge_requests/approvals/index.md)
- Fields in the [Protected branches API](../api/protected_branches.md) that specify users or groups allowed to merge
- [Merge request approvals API](../api/merge_request_approvals.md)
diff --git a/doc/subscriptions/gitlab_com/index.md b/doc/subscriptions/gitlab_com/index.md
index 632581e66d3..cd36e426852 100644
--- a/doc/subscriptions/gitlab_com/index.md
+++ b/doc/subscriptions/gitlab_com/index.md
@@ -70,8 +70,9 @@ The following information is displayed:
A GitLab SaaS subscription uses a concurrent (_seat_) model. You pay for a
subscription according to the maximum number of users assigned to the top-level group or its children during the billing period. You can
-add and remove users during the subscription period, as long as the total users
-at any given time doesn't exceed the subscription count.
+add and remove users during the subscription period without incurring additional charges, as long as the total users
+at any given time doesn't exceed the subscription count. If the total users exceeds your subscription count, you will incur an overage
+which must be paid at your next [reconciliation](../quarterly_reconciliation.md).
A top-level group can be [changed](../../user/group/manage.md#change-a-groups-path) like any other group.
@@ -170,13 +171,13 @@ The user must not be assigned any other role, anywhere in the instance.
- If your project is public, all users, including those with the Guest role
can access your project.
-### Add users to your subscription
+### Add seats to your subscription
Your subscription cost is based on the maximum number of seats you use during the billing period.
Even if you reach the number of seats in your subscription, you can continue to add users.
GitLab [bills you for the overage](../quarterly_reconciliation.md).
-To add users to a subscription:
+To add seats to a subscription:
1. Log in to the [Customers Portal](https://customers.gitlab.com/).
1. Navigate to the **Manage Purchases** page.
@@ -236,7 +237,7 @@ 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
- [linked](../index.md#change-the-linked-account) GitLab.com account.
+ [linked](../index.md#link-a-gitlabcom-account) GitLab.com account.
1. Go to the **Manage Purchases** page.
1. Select **Change linked namespace**.
1. Select the desired group from the **This subscription is for** dropdown list. For a group to appear here, you must have the Owner role for that group.
diff --git a/doc/subscriptions/gitlab_dedicated/index.md b/doc/subscriptions/gitlab_dedicated/index.md
index 2d684edb992..0c2b6375d7a 100644
--- a/doc/subscriptions/gitlab_dedicated/index.md
+++ b/doc/subscriptions/gitlab_dedicated/index.md
@@ -20,19 +20,97 @@ It's the offering of choice for enterprises and organizations in highly regulate
## Available features
-- Authentication: Support for instance-level [SAML OmniAuth](../../integration/saml.md) functionality. GitLab Dedicated acts as the service provider, and you must provide the necessary [configuration](../../integration/saml.md#configure-saml-support-in-gitlab) in order for GitLab to communicate with your IdP. This is provided during onboarding.
- - SAML [request signing](../../integration/saml.md#sign-saml-authentication-requests-optional), [group sync](../../user/group/saml_sso/group_sync.md#configure-saml-group-sync), and [SAML groups](../../integration/saml.md#configure-users-based-on-saml-group-membership) are supported.
-- Networking:
- - Public connectivity with support for IP Allowlists. During onboarding, you can optionally specify a list of IP addresses that can access your GitLab Dedicated instance. Subsequently, when an IP not on the allowlist tries to access your instance the connection is refused.
- - Optional. Private connectivity via [AWS PrivateLink](https://aws.amazon.com/privatelink/).
- You can specify an AWS IAM Principal and preferred Availability Zones during onboarding to enable this functionality. Both Ingress and Egress PrivateLinks are supported. When connecting to an internal service running in your VPC over HTTPS via PrivateLink, GitLab Dedicated supports the ability to use a private SSL certificate, which can be provided during onboarding.
-- Upgrades:
- - Monthly upgrades tracking one release behind the latest (n-1), with the latest security release.
- - Out of band security patches provided for high severity releases.
-- Backups: Regular backups taken and tested.
-- Choice of cloud region: Upon onboarding, choose the cloud region where you want to deploy your 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 currently supported.
-- Security: Data encrypted at rest and in transit using latest encryption standards.
-- Application: Self-managed [Ultimate feature set](https://about.gitlab.com/pricing/feature-comparison/) with the exception of the unsupported features [listed below](#features-that-are-not-available).
+### 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.
+
+### Availability and scalability
+
+GitLab Dedicated leverages the GitLab [Cloud Native Hybrid reference architectures](../../administration/reference_architectures/index.md#cloud-native-hybrid) with high availability enabled. When [onboarding](../../administration/dedicated/index.md#onboarding), GitLab will match you to the closest reference architecture size based on your number of users. Learn about the [current Service Level Objective](https://about.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/slas/#current-service-level-objective).
+
+#### Disaster Recovery
+
+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.
+
+### Security
+
+#### Authentication and authorization
+
+GitLab Dedicated supports instance-level [SAML OmniAuth](../../integration/saml.md) functionality. Your GitLab Dedicated instance acts as the service provider, and you must provide the necessary [configuration](../../integration/saml.md#configure-saml-support-in-gitlab) in order for GitLab to communicate with your IdP. For more information, see how to [configure SAML](../../administration/dedicated/index.md#saml) for your instance.
+
+- SAML [request signing](../../integration/saml.md#sign-saml-authentication-requests-optional), [group sync](../../user/group/saml_sso/group_sync.md#configure-saml-group-sync), and [SAML groups](../../integration/saml.md#configure-users-based-on-saml-group-membership) are supported.
+
+#### Secure networking
+
+GitLab Dedicated offers public connectivity by default with support for IP allowlists. You can [optionally specify a list of IP addresses](../../administration/dedicated/index.md#ip-allowlist) that can access your GitLab Dedicated instance. Subsequently, when an IP not on the allowlist tries to access your instance the connection is refused.
+
+Private connectivity via [AWS PrivateLink](https://aws.amazon.com/privatelink/) is also offered as an option. Both [inbound](../../administration/dedicated/index.md#inbound-private-link) and [outbound](../../administration/dedicated/index.md#outbound-private-link) PrivateLinks are supported. When connecting to an internal service running in your VPC over HTTPS via PrivateLink, GitLab Dedicated supports the ability to use a private SSL certificate, which can be provided when [updating your instance configuration](../../administration/dedicated/index.md#custom-certificates).
+
+#### Encryption
+
+Data is encrypted at rest and in transit using the latest encryption standards.
+
+#### Bring your own key encryption
+
+During onboarding, you can specify an AWS KMS encryption key stored in your own AWS account that GitLab uses to encrypt the data for your Dedicated instance. This gives you full control over the data you store in GitLab.
+
+### Compliance
+
+#### Certifications
+
+GitLab Dedicated offers the following [compliance certifications](https://about.gitlab.com/security/):
+
+- SOC 2 Type 1 Report (Security and Confidentiality criteria)
+- ISO/IEC 27001:2013
+- ISO/IEC 27017:2015
+- ISO/IEC 27018:2019
+
+#### Isolation
+
+As a single-tenant SaaS service, GitLab Dedicated provides infrastructure-level isolation of your GitLab environment. Your environment is placed into a separate AWS account from other tenants. This AWS account contains all of the underlying infrastructure necessary to host the GitLab application and your data stays within the account boundary. You administer the application while GitLab manages the underlying infrastructure. Tenant environments are also completely isolated from GitLab.com.
+
+#### Access controls
+
+GitLab Dedicated adheres to the [principle of least privilege](https://about.gitlab.com/handbook/security/access-management-policy.html#principle-of-least-privilege) to control access to customer tenant environments. Tenant AWS accounts live under a top-level GitLab Dedicated AWS parent organization. Access to the AWS Organization is restricted to select GitLab team members. All user accounts within the AWS Organization follow the overall GitLab Access Management Policy [outlined here](https://about.gitlab.com/handbook/security/access-management-policy.html). Direct access to customer tenant environments is restricted to a single Hub account. The GitLab Dedicated Control Plane uses the Hub account to perform automated actions over tenant accounts when managing environments. Similarly, GitLab Dedicated engineers do not have direct access to customer tenant environments. In break glass situations, where access to resources in the tenant environment is required to address a high-severity issue, GitLab engineers must go through the Hub account to manage those resources. This is done via an approval process, and after permission is granted, the engineer will assume an IAM role on a temporary basis to access tenant resources through the Hub account. All actions within the hub account and tenant account are logged to CloudTrail.
+
+Inside tenant accounts, GitLab leverages Intrusion Detection and Malware Scanning capabilities from AWS GuardDuty. Infrastructure logs are monitored by the GitLab Security Incident Response Team to detect anomalous events.
+
+#### Audit and observability
+
+GitLab Dedicated provides access to [audit and system logs](../../administration/dedicated/index.md#access-to-application-logs) generated by the application.
+
+### Maintenance
+
+GitLab leverages [weekly maintenance windows](../../administration/dedicated/index.md#maintenance-window) to keep your instance up to date, fix security issues, and ensure the overall reliability and performance of your environment.
+
+#### Upgrades
+
+GitLab performs monthly upgrades to your instance with the latest security release during your preferred [maintenance window](../../administration/dedicated/index.md#maintenance-window) tracking one release behind the latest GitLab release. For example, if the latest version of GitLab available is 15.8, GitLab Dedicated runs on 15.7.
+
+#### Unscheduled maintenance
+
+GitLab may conduct unscheduled maintenance to address high-severity issues affecting the security, availability, or reliability of your instance.
+
+### Application
+
+GitLab Dedicated comes with the self-managed [Ultimate feature set](https://about.gitlab.com/pricing/feature-comparison/) with the exception of the unsupported features [listed below](#features-that-are-not-available).
+
+#### GitLab Runners
+
+With GitLab Dedicated, you must [install the GitLab Runner application](https://docs.gitlab.com/runner/install/index.html) on infrastructure that you own or manage. If hosting GitLab Runners on AWS, you can avoid having requests from the Runner fleet route through the public internet by setting up a secure connection from the Runner VPC to the GitLab Dedicated endpoint via AWS Private Link. Learn more about [networking options](#secure-networking).
+
+#### Migration
+
+To help you migrate your data to GitLab Dedicated, you can choose from the following options:
+
+1. When migrating from another GitLab instance, you can either:
+ - Use the UI, including [group import](../../user/group/import/index.md) and [project import](../../user/project/settings/import_export.md).
+ - Use APIs, including the [group import API](../../api/group_import_export.md) and [project import API](../../api/project_import_export.md).
+ - Note: Import functionality behind a feature flag (such as `bulk_import_project`) is not supported in GitLab Dedicated.
+1. When migrating from third-party services, you can use [the GitLab importers](../../user/project/import/index.md#available-project-importers).
+1. You can perform a fully-automated migration through the [Congregate Automation Tool](../../user/project/import/index.md#automate-group-and-project-import), which supports migrating from existing GitLab instances as well as third-party services.
## Features that are not available
@@ -42,7 +120,7 @@ The following GitLab application features are not available:
- LDAP, Smartcard, or Kerberos authentication
- Multiple login providers
-- Advanced Search
+- Advanced search
- GitLab Pages
- FortiAuthenticator, or FortiToken 2FA
- Reply-by email
@@ -53,14 +131,13 @@ The following GitLab application features are not available:
The following features will not be supported:
- Mattermost
-- Server-side Git hooks
+- Server-side Git hooks. Use [push rules](../../user/project/repository/push_rules.md) instead.
### GitLab Dedicated service features
The following operational features are not available:
- Custom domains
-- Bring Your Own Key (BYOK) encryption
- Multiple Geo secondaries (Geo replicas) beyond the secondary site included by default
- Self-serve purchasing and configuration
- Multiple login providers
diff --git a/doc/subscriptions/index.md b/doc/subscriptions/index.md
index 2c9f93886bf..f1a960a6aa9 100644
--- a/doc/subscriptions/index.md
+++ b/doc/subscriptions/index.md
@@ -73,6 +73,7 @@ With the [Customers Portal](https://customers.gitlab.com/) you can:
- [Change account owner information](#change-account-owner-information)
- [Change your company details](#change-your-company-details)
- [Change your payment method](#change-your-payment-method)
+- [Link a GitLab.com account](#link-a-gitlabcom-account)
- [Change the linked account](#change-the-linked-account)
- [Change the namespace the subscription is linked to](gitlab_com/index.md#change-the-linked-namespace)
- [Change customers portal account password](#change-customers-portal-account-password)
@@ -137,18 +138,26 @@ method as the default:
1. **Edit** the selected payment method and check the **Make default payment method** checkbox.
1. Select **Save Changes**.
+### Link a GitLab.com account
+
+Follow this guideline if you have a legacy Customers Portal account and use an email and password to log in.
+
+To link a GitLab.com account to your Customers Portal account:
+
+1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in?legacy=true) using email and password.
+1. On the Customers Portal page, select **My account > Account details**.
+1. Under **Your GitLab.com account**, select **Link account**.
+1. Log in to the [GitLab.com](https://gitlab.com/users/sign_in) account you want to link to the Customers Portal account.
+
### Change the linked account
To change the GitLab.com account linked to your Customers Portal account:
-1. Log in to the
- [Customers Portal](https://customers.gitlab.com/customers/sign_in).
-1. In a separate browser tab, go to [GitLab.com](https://gitlab.com/users/sign_in) and ensure you
- are not logged in.
+1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
+1. In a separate browser tab, go to [GitLab.com](https://gitlab.com/users/sign_in) and ensure you are not logged in.
1. On the Customers Portal page, select **My account > Account details**.
1. Under **Your GitLab.com account**, select **Change linked account**.
-1. Log in to the [GitLab.com](https://gitlab.com/users/sign_in) account you want to link to the Customers Portal
- account.
+1. Log in to the [GitLab.com](https://gitlab.com/users/sign_in) account you want to link to the Customers Portal account.
### Change Customers Portal account password
@@ -176,7 +185,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 top bar, select **Main menu > Projects** 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/alphabetical) into the `LICENSE` file. Note that GitLab defaults to **All rights reserved** if users do not perform this action.
+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. Note that GitLab defaults to **All rights reserved** if users do not perform this action.
![Add license](img/add-license.png)
diff --git a/doc/subscriptions/self_managed/index.md b/doc/subscriptions/self_managed/index.md
index b5436b6cb72..52a39fb3f49 100644
--- a/doc/subscriptions/self_managed/index.md
+++ b/doc/subscriptions/self_managed/index.md
@@ -280,7 +280,7 @@ If you are an administrator, you can export your license usage into a CSV:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Subscription**.
-1. In the upper right, select **Export license usage file**.
+1. In the upper-right corner, select **Export license usage file**.
This file contains the information GitLab uses to manually process quarterly reconciliations or renewals. If your instance is firewalled or an offline environment, you must provide GitLab with this information.
diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md
index c1d0a69e1f4..55a58377b76 100644
--- a/doc/topics/authentication/index.md
+++ b/doc/topics/authentication/index.md
@@ -12,7 +12,7 @@ This page gathers all the resources for the topic **Authentication** within GitL
- [SSH](../../user/ssh.md)
- [Two-factor authentication](../../user/profile/account/two_factor_authentication.md)
-- [Why do you keep getting signed out?](../../user/profile/index.md#why-do-you-keep-getting-signed-out)
+- [Stay signed in indefinitely](../../user/profile/index.md#stay-signed-in-indefinitely)
- **Articles:**
- [Support for Universal 2nd Factor Authentication - YubiKeys](https://about.gitlab.com/blog/2016/06/22/gitlab-adds-support-for-u2f/)
- [Security Webcast with Yubico](https://about.gitlab.com/blog/2016/08/31/gitlab-and-yubico-security-webcast/)
diff --git a/doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md b/doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md
new file mode 100644
index 00000000000..30cbe06ab95
--- /dev/null
+++ b/doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md
@@ -0,0 +1,301 @@
+---
+stage: Configure
+group: Configure
+info: To 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 Auto DevOps to deploy an application to Amazon Elastic Kubernetes Service (EKS)
+
+In this tutorial, we'll help you to get started with [Auto DevOps](../index.md)
+through an example of how to deploy an application to Amazon Elastic Kubernetes Service (EKS).
+
+The tutorial uses the GitLab native Kubernetes integration, so you don't need
+to create a Kubernetes cluster manually using the AWS console.
+
+You can also follow this tutorial on a self-managed instance.
+Ensure your own [runners are configured](../../../ci/runners/index.md).
+
+To deploy a project to EKS:
+
+1. [Configure your Amazon account](#configure-your-amazon-account)
+1. [Create a Kubernetes cluster and deploy the agent](#create-a-kubernetes-cluster)
+1. [Create a new project from a template](#create-an-application-project-from-a-template)
+1. [Configure the agent](#configure-the-agent)
+1. [Install Ingress](#install-ingress)
+1. [Configure Auto DevOps](#configure-auto-devops)
+1. [Enable Auto DevOps and run the pipeline](#enable-auto-devops-and-run-the-pipeline)
+1. [Deploy the application](#deploy-the-application)
+
+## Configure your Amazon account
+
+Before you create and connect your Kubernetes cluster to your GitLab project,
+you need an [Amazon Web Services account](https://https://aws.amazon.com/).
+Sign in with an existing Amazon account or create a new one.
+
+## Create a Kubernetes cluster
+
+To create an new cluster on Amazon EKS:
+
+- Follow the steps in [Create an Amazon EKS cluster](../../../user/infrastructure/clusters/connect/new_eks_cluster.md).
+
+If you prefer, you can also create a cluster manually using `eksctl`.
+
+## Create an application project from a template
+
+Use a GitLab project template to get started. As the name suggests,
+those projects provide a bare-bones application built on some well-known frameworks.
+
+WARNING:
+Create the application project in the group hierarchy at the same level or below the project for cluster management. Otherwise, it fails to [authorize the agent](../../../user/clusters/agent/ci_cd_workflow.md#authorize-the-agent).
+
+1. On the top bar in GitLab, select the plus icon (**{plus-square}**), and select
+ **New project/repository**.
+1. Select **Create from template**.
+1. Select the **Ruby on Rails** template.
+1. Give your project a name, optionally a description, and make it public so that
+ you can take advantage of the features available in the
+ [GitLab Ultimate plan](https://about.gitlab.com/pricing/).
+1. Select **Create project**.
+
+Now you have an application project you are going to deploy to the EKS cluster.
+
+## Configure the agent
+
+Next, we'll configure the GitLab agent for Kubernetes so we can use it to deploy the application project.
+
+1. Go to the project [we created to manage the cluster](#create-a-kubernetes-cluster).
+1. Navigate to the [agent configuration file](../../../user/clusters/agent/install/index.md#create-an-agent-configuration-file) (`.gitlab/agents/eks-agent/config.yaml`) and edit it.
+1. Configure `ci_access:projects` attribute. Use the application project path as `id`:
+
+```yaml
+ci_access:
+ projects:
+ - id: path/to/application-project
+```
+
+## Install Ingress
+
+After your cluster is running, you must install NGINX Ingress Controller as a
+load balancer to route traffic from the internet to your application.
+Install the NGINX Ingress Controller
+through the GitLab [Cluster management project template](../../../user/clusters/management_project_template.md),
+or manually via the command line:
+
+1. Ensure you have `kubectl` and Helm installed on your machine.
+1. Create an IAM role to access the cluster.
+1. Create an access token to access the cluster.
+1. Use `kubectl` to connect to your cluster:
+
+ ```shell
+ helm upgrade --install ingress-nginx ingress-nginx \
+ --repo https://kubernetes.github.io/ingress-nginx \
+ --namespace gitlab-managed-apps --create-namespace
+
+ # Check that the ingress controller is installed successfully
+ kubectl get service ingress-nginx-controller -n gitlab-managed-apps
+ ```
+
+## Configure Auto DevOps
+
+Follow these steps to configure the base domain and other settings required for Auto DevOps.
+
+1. A few minutes after you install NGINX, the load balancer obtains an IP address, and you can
+ get the external IP address with the following command:
+
+ ```shell
+ kubectl get all -n gitlab-managed-apps --selector app.kubernetes.io/instance=ingress-nginx
+ ```
+
+ Replace `gitlab-managed-apps` if you have overwritten your namespace.
+
+ Next, find the actual external IP address for your cluster with the following command:
+
+ ```shell
+ nslookup [External IP]
+ ```
+
+ Where the `[External IP]` is the hostname found with the previous command.
+
+ The IP address might be listed in the `Non-authoritative answer:` section of the response.
+
+ Copy this IP address, as you need it in the next step.
+
+1. Go back to the application project.
+1. On the left sidebar, select **Settings > CI/CD** and expand **Variables**.
+ - Add a key called `KUBE_INGRESS_BASE_DOMAIN` with the application deployment domain as the value. For this example, use the domain `<IP address>.nip.io`.
+ - Add a key called `KUBE_NAMESPACE` with a value of the Kubernetes namespace for your deployments to target. You can use different namespaces per environment. Configure the environment, use the environment scope.
+ - Add a key called `KUBE_CONTEXT` with a value like `path/to/agent/project:eks-agent`. Select the environment scope of your choice.
+ - Select **Save changes**.
+
+## Enable Auto DevOps and run the pipeline
+
+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 top bar, select **Main menu > Projects** and find the application project.
+1. On the left sidebar, select **Settings > CI/CD**.
+1. Expand **Auto DevOps**.
+1. Select **Default to Auto DevOps pipeline** to display more options.
+1. In **Deployment strategy**, select your desired [continuous deployment strategy](../requirements.md#auto-devops-deployment-strategy)
+ to deploy the application to production after the pipeline successfully runs on the default branch.
+1. Select **Save changes**.
+1. Edit `.gitlab-ci.yml` file to include the Auto DevOps template and commit the change to the default branch:
+
+ ```yaml
+ include:
+ - template: Auto-DevOps.gitlab-ci.yml
+ ```
+
+The commit should trigger a pipeline. In the next section, we explain what each job does in the pipeline.
+
+## Deploy the application
+
+When your pipeline runs, what is it doing?
+
+To view the jobs in the pipeline, select the pipeline's status badge. The
+**{status_running}** icon displays when pipeline jobs are running, and updates
+without refreshing the page to **{status_success}** (for success) or
+**{status_failed}** (for failure) when the jobs complete.
+
+The jobs are separated into stages:
+
+![Pipeline stages](img/guide_pipeline_stages_v13_0.png)
+
+- **Build** - The application builds a Docker image and uploads it to your project's
+ [Container Registry](../../../user/packages/container_registry/index.md) ([Auto Build](../stages.md#auto-build)).
+- **Test** - GitLab runs various checks on the application, but all jobs except `test`
+ are allowed to fail in the test stage:
+
+ - The `test` job runs unit and integration tests by detecting the language and
+ framework ([Auto Test](../stages.md#auto-test-deprecated))
+ - The `code_quality` job checks the code quality and is allowed to fail
+ ([Auto Code Quality](../stages.md#auto-code-quality))
+ - The `container_scanning` job checks the Docker container if it has any
+ vulnerabilities and is allowed to fail ([Auto Container Scanning](../stages.md#auto-container-scanning))
+ - The `dependency_scanning` job checks if the application has any dependencies
+ susceptible to vulnerabilities and is allowed to fail
+ ([Auto Dependency Scanning](../stages.md#auto-dependency-scanning))
+ - Jobs suffixed with `-sast` run static analysis on the current code to check for potential
+ security issues, and are allowed to fail ([Auto SAST](../stages.md#auto-sast))
+ - The `secret-detection` job checks for leaked secrets and is allowed to fail ([Auto Secret Detection](../stages.md#auto-secret-detection))
+ - The `license_scanning` job searches the application's dependencies to determine each of their
+ licenses and is allowed to fail
+ ([Auto License Compliance](../stages.md#auto-license-compliance))
+
+- **Review** - Pipelines on the default branch include this stage with a `dast_environment_deploy` job.
+ To learn more, see [Dynamic Application Security Testing (DAST)](../../../user/application_security/dast/index.md).
+
+- **Production** - After the tests and checks finish, the application deploys in
+ Kubernetes ([Auto Deploy](../stages.md#auto-deploy)).
+
+- **Performance** - Performance tests are run on the deployed application
+ ([Auto Browser Performance Testing](../stages.md#auto-browser-performance-testing)).
+
+- **Cleanup** - Pipelines on the default branch include this stage with a `stop_dast_environment` job.
+
+After running a pipeline, you should view your deployed website and learn how
+to monitor it.
+
+### Monitor your project
+
+After successfully deploying your application, you can view its website and check
+on its health on the **Environments** page by navigating to
+**Deployments > Environments**. This page displays details about
+the deployed applications, and the right-hand column displays icons that link
+you to common environment tasks:
+
+![Environments](img/guide_environments_v12_3.png)
+
+- **Open live environment** (**{external-link}**) - Opens the URL of the application deployed in production
+- **Monitoring** (**{chart}**) - Opens the metrics page where Prometheus collects data
+ about the Kubernetes cluster and how the application
+ affects it in terms of memory usage, CPU usage, and latency
+- **Deploy to** (**{play}** **{chevron-lg-down}**) - Displays a list of environments you can deploy to
+- **Terminal** (**{terminal}**) - Opens a [web terminal](../../../ci/environments/index.md#web-terminals-deprecated)
+ session inside the container where the application is running
+- **Re-deploy to environment** (**{repeat}**) - For more information, see
+ [Retrying and rolling back](../../../ci/environments/index.md#retry-or-roll-back-a-deployment)
+- **Stop environment** (**{stop}**) - For more information, see
+ [Stopping an environment](../../../ci/environments/index.md#stop-an-environment)
+
+GitLab displays the [deploy board](../../../user/project/deploy_boards.md) below the
+environment's information, with squares representing pods in your
+Kubernetes cluster, color-coded to show their status. Hovering over a square on
+the deploy board displays the state of the deployment, and selecting the square
+takes you to the pod's logs page.
+
+Although the example shows only one pod hosting the application at the moment, you can add
+more pods by defining the [`REPLICAS` CI/CD variable](../cicd_variables.md)
+in **Settings > CI/CD > Variables**.
+
+### Work with branches
+
+Following the [GitLab flow](../../gitlab_flow.md#working-with-feature-branches),
+you should next create a feature branch to add content to your application:
+
+1. In your project's repository, go to the following file: `app/views/welcome/index.html.erb`.
+ This file should only contain a paragraph: `<p>You're on Rails!</p>`.
+1. Open the GitLab [Web IDE](../../../user/project/web_ide/index.md) to make the change.
+1. Edit the file so it contains:
+
+ ```html
+ <p>You're on Rails! Powered by GitLab Auto DevOps.</p>
+ ```
+
+1. Stage the file. Add a commit message, then create a new branch and a merge request
+ by selecting **Commit**.
+
+ ![Web IDE commit](img/guide_ide_commit_v12_3.png)
+
+After submitting the merge request, GitLab runs your pipeline, and all the jobs
+in it, as [described previously](#deploy-the-application), in addition to
+a few more that run only on branches other than the default branch.
+
+After a few minutes a test fails, which means a test was
+'broken' by your change. Select the failed `test` job to see more information
+about it:
+
+```plaintext
+Failure:
+WelcomeControllerTest#test_should_get_index [/app/test/controllers/welcome_controller_test.rb:7]:
+<You're on Rails!> expected but was
+<You're on Rails! Powered by GitLab Auto DevOps.>..
+Expected 0 to be >= 1.
+
+bin/rails test test/controllers/welcome_controller_test.rb:4
+```
+
+To fix the broken test:
+
+1. Return to your merge request.
+1. In the upper right corner, select **Code**, then select **Open in Gitpod**.
+1. In the left-hand directory of files, find the `test/controllers/welcome_controller_test.rb`
+ file, and select it to open it.
+1. Change line 7 to say `You're on Rails! Powered by GitLab Auto DevOps.`
+1. Select **Commit**.
+1. In the left-hand column, under **Unstaged changes**, select the checkmark icon
+ (**{stage-all}**) to stage the changes.
+1. Write a commit message, and select **Commit**.
+
+Return to the **Overview** page of your merge request, and you should not only
+see the test passing, but also the application deployed as a
+[review application](../stages.md#auto-review-apps). You can visit it by selecting
+the **View app** **{external-link}** button to see your changes deployed.
+
+After merging the merge request, GitLab runs the pipeline on the default branch,
+and then deploys the application to production.
+
+## Conclusion
+
+After implementing this project, you should have a solid understanding of the basics of Auto DevOps.
+You started from building and testing, to deploying and monitoring an application
+all in GitLab. Despite its automatic nature, Auto DevOps can also be configured
+and customized to fit your workflow. Here are some helpful resources for further reading:
+
+1. [Auto DevOps](../index.md)
+1. [Multiple Kubernetes clusters](../multiple_clusters_auto_devops.md)
+1. [Incremental rollout to production](../cicd_variables.md#incremental-rollout-to-production)
+1. [Disable jobs you don't need with CI/CD variables](../cicd_variables.md)
+1. [Use your own buildpacks to build your application](../customize.md#custom-buildpacks)
+1. [Prometheus monitoring](../../../user/project/integrations/prometheus.md)
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 9bd1d30e1b1..06b772cc455 100644
--- a/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md
+++ b/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md
@@ -274,7 +274,7 @@ bin/rails test test/controllers/welcome_controller_test.rb:4
To fix the broken test:
1. Return to your merge request.
-1. In the upper right corner, select **Code**, then select **Open in Gitpod**.
+1. In the upper-right corner, select **Code**, then select **Open in Gitpod**.
1. In the left-hand directory of files, find the `test/controllers/welcome_controller_test.rb`
file, and select it to open it.
1. Change line 7 to say `You're on Rails! Powered by GitLab Auto DevOps.`
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 588be855659..2a0cc7f39b1 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -185,6 +185,7 @@ and clear the **Default to Auto DevOps pipeline** checkbox.
### Deploy your app to a cloud provider
- [Use Auto DevOps to deploy to a Kubernetes cluster on Google Kubernetes Engine (GKE)](cloud_deployments/auto_devops_with_gke.md)
+- [Use Auto DevOps to deploy to a Kubernetes cluster on Amazon Elastic Kubernetes Service (EKS)](cloud_deployments/auto_devops_with_eks.md)
- [Use Auto DevOps to deploy to EC2](cloud_deployments/auto_devops_with_ec2.md)
- [Use Auto DevOps to deploy to ECS](cloud_deployments/auto_devops_with_ecs.md)
diff --git a/doc/topics/autodevops/upgrading_postgresql.md b/doc/topics/autodevops/upgrading_postgresql.md
index f18d5c49be5..daf1d5341d3 100644
--- a/doc/topics/autodevops/upgrading_postgresql.md
+++ b/doc/topics/autodevops/upgrading_postgresql.md
@@ -49,12 +49,12 @@ being modified after the database dump is created.
1. Get the Kubernetes namespace for the environment. It typically looks like `<project-name>-<project-id>-<environment>`.
In our example, the namespace is called `minimal-ruby-app-4349298-production`.
- ```shell
- $ kubectl get ns
+ ```shell
+ $ kubectl get ns
- NAME STATUS AGE
- minimal-ruby-app-4349298-production Active 7d14h
- ```
+ NAME STATUS AGE
+ minimal-ruby-app-4349298-production Active 7d14h
+ ```
1. For ease of use, export the namespace name:
@@ -64,20 +64,20 @@ being modified after the database dump is created.
1. Get the deployment name for your application with the following command. In our example, the deployment name is `production`.
- ```shell
- $ kubectl get deployment --namespace "$APP_NAMESPACE"
- NAME READY UP-TO-DATE AVAILABLE AGE
- production 2/2 2 2 7d21h
- production-postgres 1/1 1 1 7d21h
- ```
+ ```shell
+ $ kubectl get deployment --namespace "$APP_NAMESPACE"
+ NAME READY UP-TO-DATE AVAILABLE AGE
+ production 2/2 2 2 7d21h
+ production-postgres 1/1 1 1 7d21h
+ ```
1. To prevent the database from being modified, set replicas to 0 for the deployment with the following command.
We use the deployment name from the previous step (`deployments/<DEPLOYMENT_NAME>`).
- ```shell
- $ kubectl scale --replicas=0 deployments/production --namespace "$APP_NAMESPACE"
- deployment.extensions/production scaled
- ```
+ ```shell
+ $ kubectl scale --replicas=0 deployments/production --namespace "$APP_NAMESPACE"
+ deployment.extensions/production scaled
+ ```
1. You must also set replicas to zero for workers if you have any.
@@ -85,26 +85,26 @@ being modified after the database dump is created.
1. Get the service name for PostgreSQL. The name of the service should end with `-postgres`. In our example the service name is `production-postgres`.
- ```shell
- $ kubectl get svc --namespace "$APP_NAMESPACE"
- NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- production-auto-deploy ClusterIP 10.30.13.90 <none> 5000/TCP 7d14h
- production-postgres ClusterIP 10.30.4.57 <none> 5432/TCP 7d14h
- ```
+ ```shell
+ $ kubectl get svc --namespace "$APP_NAMESPACE"
+ NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
+ production-auto-deploy ClusterIP 10.30.13.90 <none> 5000/TCP 7d14h
+ production-postgres ClusterIP 10.30.4.57 <none> 5432/TCP 7d14h
+ ```
1. Get the pod name for PostgreSQL with the following command. In our example, the pod name is `production-postgres-5db86568d7-qxlxv`.
- ```shell
- $ kubectl get pod --namespace "$APP_NAMESPACE" -l app=production-postgres
- NAME READY STATUS RESTARTS AGE
- production-postgres-5db86568d7-qxlxv 1/1 Running 0 7d14h
- ```
+ ```shell
+ $ kubectl get pod --namespace "$APP_NAMESPACE" -l app=production-postgres
+ NAME READY STATUS RESTARTS AGE
+ production-postgres-5db86568d7-qxlxv 1/1 Running 0 7d14h
+ ```
1. Connect to the pod with:
- ```shell
- kubectl exec -it production-postgres-5db86568d7-qxlxv --namespace "$APP_NAMESPACE" -- bash
- ```
+ ```shell
+ kubectl exec -it production-postgres-5db86568d7-qxlxv --namespace "$APP_NAMESPACE" -- bash
+ ```
1. Once, connected, create a dump file with the following command.
@@ -114,20 +114,20 @@ being modified after the database dump is created.
- When prompted for the database password, the default is `testing-password`.
- ```shell
- ## Format is:
- # pg_dump -h SERVICE_NAME -U USERNAME DATABASE_NAME > /tmp/backup.sql
+ ```shell
+ ## Format is:
+ # pg_dump -h SERVICE_NAME -U USERNAME DATABASE_NAME > /tmp/backup.sql
- pg_dump -h production-postgres -U user production > /tmp/backup.sql
- ```
+ pg_dump -h production-postgres -U user production > /tmp/backup.sql
+ ```
1. Once the backup dump is complete, exit the Kubernetes exec process with `Control-D` or `exit`.
1. Download the dump file with the following command:
- ```shell
- kubectl cp --namespace "$APP_NAMESPACE" production-postgres-5db86568d7-qxlxv:/tmp/backup.sql backup.sql
- ```
+ ```shell
+ kubectl cp --namespace "$APP_NAMESPACE" production-postgres-5db86568d7-qxlxv:/tmp/backup.sql backup.sql
+ ```
## Retain persistent volumes
@@ -184,8 +184,7 @@ You can also
1. Set `AUTO_DEVOPS_POSTGRES_DELETE_V1` to a non-empty value. This flag is a
safeguard to prevent accidental deletion of databases.
<!-- DO NOT REPLACE when upgrading GitLab's supported version. This is NOT related to GitLab's PostgreSQL version support, but the one deployed by Auto DevOps. -->
-1. If you have a `POSTGRES_VERSION` set, make sure it is set to `9.6.16` *or
-higher*. This is the
+1. If you have a `POSTGRES_VERSION` set, make sure it is set to `9.6.16` *or higher*. This is the
minimum PostgreSQL version supported by Auto DevOps. See also the list of
[tags available](https://hub.docker.com/r/bitnami/postgresql/tags).
1. Set `PRODUCTION_REPLICAS` to `0`. For other environments, use
@@ -205,11 +204,11 @@ higher*. This is the
1. Get the pod name for the new PostgreSQL, in our example, the pod name is
`production-postgresql-0`:
- ```shell
- $ kubectl get pod --namespace "$APP_NAMESPACE" -l app=postgresql
- NAME READY STATUS RESTARTS AGE
- production-postgresql-0 1/1 Running 0 19m
- ````
+ ```shell
+ $ kubectl get pod --namespace "$APP_NAMESPACE" -l app=postgresql
+ NAME READY STATUS RESTARTS AGE
+ production-postgresql-0 1/1 Running 0 19m
+ ````
1. Copy the dump file from the backup steps to the pod:
diff --git a/doc/topics/awesome_co.md b/doc/topics/awesome_co.md
index ff3c81a1b90..ffda564cd91 100644
--- a/doc/topics/awesome_co.md
+++ b/doc/topics/awesome_co.md
@@ -141,3 +141,73 @@ create(:project, name: 'Throws Error', namespace: create(:group, name: 'Some Gro
create(:project, name: 'No longer throws error', owner: @owner, namespace: create(:group, name: 'Some Group'))
create(:epic, group: create(:group), author: @owner)
```
+
+## YAML Factories
+
+### Generator to generate _n_ amount of records
+
+### [Group Labels](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/factories/labels.rb)
+
+```yaml
+group_labels:
+ # Group Label with Name and a Color
+ - name: Group Label 1
+ group_id: <%= @group.id %>
+ color: "#FF0000"
+```
+
+### [Group Milestones](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/factories/milestones.rb)
+
+```yaml
+group_milestones:
+ # Past Milestone
+ - name: Past Milestone
+ group_id: <%= @group.id %>
+ group:
+ start_date: <%= 1.month.ago %>
+ due_date: <%= 1.day.ago %>
+
+ # Ongoing Milestone
+ - name: Ongoing Milestone
+ group_id: <%= @group.id %>
+ group:
+ start_date: <%= 1.day.ago %>
+ due_date: <%= 1.month.from_now %>
+
+ # Future Milestone
+ - name: Ongoing Milestone
+ group_id: <%= @group.id %>
+ group:
+ start_date: <%= 1.month.from_now %>
+ due_date: <%= 2.months.from_now %>
+```
+
+#### Quirks
+
+- You _must_ specify `group:` and have it be empty. This is because the Milestones factory will manipulate the factory in an `after(:build)`. If this is not present, the Milestone will not be associated properly with the Group.
+
+### [Epics](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/spec/factories/epics.rb)
+
+```yaml
+epics:
+ # Simple Epic
+ - title: Simple Epic
+ group_id: <%= @group.id %>
+ author_id: <%= @owner.id %>
+
+ # Epic with detailed Markdown description
+ - title: Detailed Epic
+ group_id: <%= @group.id %>
+ author_id: <%= @owner.id %>
+ description: |
+ # Markdown
+
+ **Description**
+
+ # Epic with dates
+ - title: Epic with dates
+ group_id: <%= @group.id %>
+ author_id: <%= @owner.id %>
+ start_date: <%= 1.day.ago %>
+ due_date: <%= 1.month.from_now %>
+```
diff --git a/doc/topics/git/bisect.md b/doc/topics/git/bisect.md
index a7f8b2a846c..eaf619ce36f 100644
--- a/doc/topics/git/bisect.md
+++ b/doc/topics/git/bisect.md
@@ -1,76 +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
-comments: false
+redirect_to: 'index.md'
+remove_date: '2023-06-09'
---
-# Bisect **(FREE)**
+This document was moved to [another location](index.md).
-- Find a commit that introduced a bug
-- Works through a process of elimination
-- Specify a known good and bad revision to begin
-
-## Bisect sample workflow
-
-1. Start the bisect process
-1. Enter the bad revision (usually latest commit)
-1. Enter a known good revision (commit/branch)
-1. Run code to see if bug still exists
-1. Tell bisect the result
-1. Repeat the previous 2 items until you find the offending commit
-
-## Setup
-
-```shell
- mkdir bisect-ex
- cd bisect-ex
- touch index.html
- git add -A
- git commit -m "starting out"
- vi index.html
- # Add all good
- git add -A
- git commit -m "second commit"
- vi index.html
- # Add all good 2
- git add -A
- git commit -m "third commit"
- vi index.html
-```
-
-```shell
- # Add all good 3
- git add -A
- git commit -m "fourth commit"
- vi index.html
- # This looks bad
- git add -A
- git commit -m "fifth commit"
- vi index.html
- # Really bad
- git add -A
- git commit -m "sixth commit"
- vi index.html
- # again just bad
- git add -A
- git commit -m "seventh commit"
-```
-
-## Commands
-
-```shell
- git bisect start
- # Test your code
- git bisect bad
- git bisect next
- # Say yes to the warning
- # Test
- git bisect good
- # Test
- git bisect bad
- # Test
- git bisect good
- # done
- git bisect reset
-```
+<!-- This redirect file can be deleted after <2023-06-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 -->
diff --git a/doc/topics/git/feature_branching.md b/doc/topics/git/feature_branching.md
index 73de351fde2..eaf619ce36f 100644
--- a/doc/topics/git/feature_branching.md
+++ b/doc/topics/git/feature_branching.md
@@ -1,31 +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
-comments: false
+redirect_to: 'index.md'
+remove_date: '2023-06-09'
---
-# Feature branching **(FREE)**
+This document was moved to [another location](index.md).
-- Efficient parallel workflow for teams
-- Develop each feature in a branch
-- Keeps changes isolated
-- Consider a 1-to-1 link to issues
-- Push branches to the server frequently
- - Hint: Pushing branches is a cheap backup for your work-in-progress code.
-
-## Feature branching sample workflow
-
-1. Create a new feature branch called `squash_some_bugs`
-1. Edit '`bugs.rb`' and remove all the bugs.
-1. Commit
-1. Push
-
-```shell
-git checkout -b squash_some_bugs
-# Edit `bugs.rb`
-git status
-git add bugs.rb
-git commit -m 'Fix some buggy code'
-git push origin squash_some_bugs
-```
+<!-- This redirect file can be deleted after <2023-06-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 -->
diff --git a/doc/topics/git/git_log.md b/doc/topics/git/git_log.md
index e2e9c0e8804..eaf619ce36f 100644
--- a/doc/topics/git/git_log.md
+++ b/doc/topics/git/git_log.md
@@ -1,60 +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
-comments: false
+redirect_to: 'index.md'
+remove_date: '2023-06-09'
---
-# Git Log **(FREE)**
+This document was moved to [another location](index.md).
-Git log lists commit history. It allows searching and filtering.
-
-- Initiate log:
-
- ```shell
- git log
- ```
-
-- Retrieve set number of records:
-
- ```shell
- git log -n 2
- ```
-
-- Search commits by author. Allows user name or a regular expression.
-
- ```shell
- git log --author="user_name"
- ```
-
-- Search by comment message:
-
- ```shell
- git log --grep="<pattern>"
- ```
-
-- Search by date:
-
- ```shell
- git log --since=1.month.ago --until=3.weeks.ago
- ```
-
-## Git Log Workflow
-
-1. Change to workspace directory
-1. Clone the multi runner projects
-1. Change to project dir
-1. Search by author
-1. Search by date
-1. Combine
-
-## Commands
-
-```shell
-cd ~/workspace
-git clone git@gitlab.com:gitlab-org/gitlab-runner.git
-cd gitlab-runner
-git log --author="Travis"
-git log --since=1.month.ago --until=3.weeks.ago
-git log --since=1.month.ago --until=1.day.ago --author="Travis"
-```
+<!-- This redirect file can be deleted after <2023-06-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 -->
diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md
index b47a34fa7b2..fa802952b32 100644
--- a/doc/topics/git/index.md
+++ b/doc/topics/git/index.md
@@ -32,7 +32,6 @@ The following resources can help you get started with Git:
- [How to install Git](how_to_install_git/index.md)
- [Git terminology](terminology.md)
- [Start using Git on the command line](../../gitlab-basics/start-using-git.md)
-- [Edit files through the command line](../../gitlab-basics/command-line-commands.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)
@@ -43,7 +42,7 @@ The following resources can help you get started with Git:
- [Git stash](stash.md)
- [Git file blame](../../user/project/repository/git_blame.md)
- [Git file history](../../user/project/repository/git_history.md)
-- [Git tags](tags.md)
+- [Git tags](../../user/project/repository/tags/index.md)
### Concepts
@@ -58,16 +57,11 @@ The following are resources on version control concepts:
You can do many Git tasks from the command line:
-- [Bisect](bisect.md).
- [Cherry-pick](cherry_picking.md).
-- [Feature branching](feature_branching.md).
- [Getting started with Git](getting_started.md).
- [Git add](git_add.md).
-- [Git log](git_log.md).
- [Git stash](stash.md).
-- [Merge conflicts](merge_conflicts.md).
- [Rollback commits](rollback_commits.md).
-- [Subtree](subtree.md).
- [Unstage](unstage.md).
## Git tips
diff --git a/doc/topics/git/merge_conflicts.md b/doc/topics/git/merge_conflicts.md
deleted file mode 100644
index ea37afe1b31..00000000000
--- a/doc/topics/git/merge_conflicts.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../../user/project/merge_requests/conflicts.md#resolve-conflicts-from-the-command-line'
-remove_date: '2023-02-01'
----
-
-This document was moved to [another location](../../user/project/merge_requests/conflicts.md#resolve-conflicts-from-the-command-line).
-
-<!-- This redirect file can be deleted after <2023-02-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/topics/git/partial_clone.md b/doc/topics/git/partial_clone.md
index f5f11b17675..de0547ae49d 100644
--- a/doc/topics/git/partial_clone.md
+++ b/doc/topics/git/partial_clone.md
@@ -94,9 +94,7 @@ Updating files: 100% (28/28), done.
$ cd www-gitlab-com
-$ git sparse-checkout init --cone
-
-$ git sparse-checkout add data
+$ git sparse-checkout set data --cone
remote: Enumerating objects: 301, done.
remote: Counting objects: 100% (301/301), done.
remote: Compressing objects: 100% (292/292), done.
diff --git a/doc/topics/git/subtree.md b/doc/topics/git/subtree.md
index a8a665d4e13..eaf619ce36f 100644
--- a/doc/topics/git/subtree.md
+++ b/doc/topics/git/subtree.md
@@ -1,50 +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
-comments: false
+redirect_to: 'index.md'
+remove_date: '2023-06-09'
---
-# Subtree **(FREE)**
+This document was moved to [another location](index.md).
-- Used when there are nested repositories.
-- Not recommended when the amount of dependencies is too large.
-- For these cases we need a dependency control system.
-- Command are painfully long so aliases are necessary.
-
-## Subtree Aliases
-
-- Add: `git subtree add --prefix <target-folder> <url> <branch> --squash`
-- Pull: `git subtree pull --prefix <target-folder> <url> <branch> --squash`
-- Push: `git subtree push --prefix <target-folder> <url> <branch>`
-
-```shell
- # Add an alias
- # Add
- git config alias.sba 'subtree add --prefix st /
- git@gitlab.com:balameb/subtree-nested-example.git master --squash'
- # Pull
- git config alias.sbpl 'subtree pull --prefix st /
- git@gitlab.com:balameb/subtree-nested-example.git master --squash'
- # Push
- git config alias.sbph 'subtree push --prefix st /
- git@gitlab.com:balameb/subtree-nested-example.git master'
-
- # Adding this subtree adds a st dir with a readme
- git sba
- vi st/README.md
- # Edit file
- git status shows differences
-
-```
-
-```shell
- # Adding, or committing won't change the sub repo at remote
- # even if we push
- git add -A
- git commit -m "Adding to subtree readme"
-
- # Push to subtree repo
- git sbph
- # now we can check our remote sub repo
-```
+<!-- This redirect file can be deleted after <2023-06-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 -->
diff --git a/doc/topics/git/tags.md b/doc/topics/git/tags.md
index ab196f409f7..c66c97717f2 100644
--- a/doc/topics/git/tags.md
+++ b/doc/topics/git/tags.md
@@ -1,41 +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: '../../user/project/repository/tags/index.md'
+remove_date: '2023-05-27'
---
-# Tags **(FREE)**
+This document was moved to [another location](../../user/project/repository/tags/index.md).
-Tags help you mark certain deployments and releases for later
-reference. Git supports two types of tags:
-
-- Annotated tags: An unchangeable part of Git history.
-- Lightweight (soft) tags: Tags that can be set and removed as needed.
-
-Many projects combine an annotated release tag with a stable branch. Consider
-setting deployment or release tags automatically.
-
-## Tags sample workflow
-
-1. Create a lightweight tag.
-1. Create an annotated tag.
-1. Push the tags to the remote repository.
-
-```shell
-git checkout master
-
-# Lightweight tag
-git tag my_lightweight_tag
-
-# Annotated tag
-git tag -a v1.0 -m 'Version 1.0'
-
-# Show list of the existing tags
-git tag
-
-git push origin --tags
-```
-
-## Related topics
-
-- [Tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging) Git reference page
+<!-- This redirect file can be deleted after <2023-05-27>. -->
+<!-- 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/topics/git/troubleshooting_git.md b/doc/topics/git/troubleshooting_git.md
index a116f6cc978..37450319350 100644
--- a/doc/topics/git/troubleshooting_git.md
+++ b/doc/topics/git/troubleshooting_git.md
@@ -221,11 +221,17 @@ apply more than one:
1. Modify the GitLab instance's
[`gitlab.rb`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/13.5.1+ee.0/files/gitlab-config-template/gitlab.rb.template#L1435-1455) file:
- ```shell
- gitaly['gitconfig'] = [
- # Set the http.postBuffer size, in bytes
- {key: "http.postBuffer", value: "524288000"},
- ]
+ ```ruby
+ gitaly['configuration'] = {
+ # ...
+ git: {
+ # ...
+ config: [
+ # Set the http.postBuffer size, in bytes
+ {key: "http.postBuffer", value: "524288000"},
+ ],
+ },
+ }
```
1. After applying this change, apply the configuration change:
diff --git a/doc/topics/git/unstage.md b/doc/topics/git/unstage.md
index 142a80a9ad9..aad5d0f44f8 100644
--- a/doc/topics/git/unstage.md
+++ b/doc/topics/git/unstage.md
@@ -5,15 +5,20 @@ info: To determine the technical writer assigned to the Stage/Group associated w
comments: false
---
-# Unstage **(FREE)**
+# Unstage a file in Git **(FREE)**
-- To remove files from stage use reset HEAD where HEAD is the last commit of the current branch. This unstages the file but maintain the modifications.
+When you _stage_ a file in Git, you instruct Git to track changes to the file in
+preparation for a commit. To instruct Git to disregard changes to a file, and not
+include it in your next commit, _unstage_ the file.
+
+- To remove files from stage use `reset HEAD`, where HEAD is the last commit of
+ the current branch. This unstages the file but maintains the modifications.
```shell
git reset HEAD <file>
```
-- To revert the file back to the state it was in before the changes we can use:
+- To revert the file back to the state it was in before the changes:
```shell
git checkout -- <file>
@@ -26,7 +31,8 @@ comments: false
git rm -r <dirname>
```
-- If we want to remove a file from the repository but keep it on disk, say we forgot to add it to our `.gitignore` file then use `--cache`:
+- To keep a file on disk but remove it from the repository (such as a file you want
+ to add to `.gitignore`), use the `rm` command with the `--cache` flag:
```shell
git rm <filename> --cache
diff --git a/doc/topics/git/useful_git_commands.md b/doc/topics/git/useful_git_commands.md
index 235412f511a..22548be2e8b 100644
--- a/doc/topics/git/useful_git_commands.md
+++ b/doc/topics/git/useful_git_commands.md
@@ -130,12 +130,6 @@ Use this to check the Git history of the file:
git log -- <file>
```
-### Find the tags that contain a particular SHA
-
-```shell
-git tag --contains <sha>
-```
-
### Check the content of each change to a file
```shell
diff --git a/doc/topics/offline/quick_start_guide.md b/doc/topics/offline/quick_start_guide.md
index 80ce703f7db..b2767f2e5eb 100644
--- a/doc/topics/offline/quick_start_guide.md
+++ b/doc/topics/offline/quick_start_guide.md
@@ -214,3 +214,89 @@ and Praefect servers so they can use an accessible NTP server.
On offline instances, the [GitLab Geo check Rake task](../../administration/geo/replication/troubleshooting.md#can-geo-detect-the-current-site-correctly)
always fails because it uses `pool.ntp.org`. This error can be ignored but you can
[read more about how to work around it](../../administration/geo/replication/troubleshooting.md#message-machine-clock-is-synchronized--exception).
+
+## 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).
+This process will require usage of the GitLab License Database, which is licensed under the [EE License](https://storage.googleapis.com/prod-export-license-bucket-1a6c642fc4de57d4/v1/LICENSE).
+Please note the following in relation to use of the License Database:
+
+- We may change or discontinue all or any part of the License Database, at any time and without notice, at our sole discretion.
+- The License 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 License 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.
+
+### Using the gsutil tool to download the package metadata exports
+
+1. Install the [`gsutil`](https://cloud.google.com/storage/docs/gsutil_install) tool.
+1. Find the root of the GitLab Rails directory.
+
+ ```shell
+ export GITLAB_RAILS_ROOT_DIR="$(gitlab-rails runner 'puts Rails.root.to_s')"
+ echo $GITLAB_RAILS_ROOT_DIR
+ ```
+
+1. Download the package metadata exports.
+
+ ```shell
+ # To download the package metadata exports, an outbound connection to Google Cloud Storage bucket must be allowed.
+ mkdir $GITLAB_RAILS_ROOT_DIR/vendor/package_metadata_db/
+ gsutil -m rsync -r -d gs://prod-export-license-bucket-1a6c642fc4de57d4 $GITLAB_RAILS_ROOT_DIR/vendor/package_metadata_db/
+
+ # Alternatively, if the GitLab instance is not allowed to connect to the Google Cloud Storage bucket, the package metadata
+ # exports can be downloaded using a machine with the allowed access, and then copied to the root of the GitLab Rails directory.
+ rsync rsync://example_username@gitlab.example.com/package_metadata_db $GITLAB_RAILS_ROOT_DIR/vendor/package_metadata_db/
+ ```
+
+### Using the Google Cloud Storage REST API to download the package metadata exports
+
+The package metadata exports can also be downloaded using the Google Cloud Storage API. The contents are available at [https://storage.googleapis.com/storage/v1/b/prod-export-license-bucket-1a6c642fc4de57d4/o](https://storage.googleapis.com/storage/v1/b/prod-export-license-bucket-1a6c642fc4de57d4/o). The following is an example of how this can be downloaded using [cURL](https://curl.se/) and [jq](https://stedolan.github.io/jq/).
+
+```shell
+#!/bin/bash
+
+set -euo pipefail
+
+GITLAB_RAILS_ROOT_DIR="$(gitlab-rails runner 'puts Rails.root.to_s')"
+PKG_METADATA_DIR="$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata_db"
+PKG_METADATA_MANIFEST_OUTPUT_FILE="/tmp/license_db_export_manifest.json"
+PKG_METADATA_DOWNLOADS_OUTPUT_FILE="/tmp/license_db_object_links.tsv"
+
+# Download the contents of the bucket
+curl --silent --show-error --request GET "https://storage.googleapis.com/storage/v1/b/prod-export-license-bucket-1a6c642fc4de57d4/o" > "$PKG_METADATA_MANIFEST_OUTPUT_FILE"
+
+# Parse the links and names for the bucket objects and output them into a tsv file
+jq -r '.items[] | [.name, .mediaLink] | @tsv' "$PKG_METADATA_MANIFEST_OUTPUT_FILE" > "$PKG_METADATA_DOWNLOADS_OUTPUT_FILE"
+
+echo -e "Saving package metadata exports to $PKG_METADATA_DIR\n"
+
+# Track how many objects will be downloaded
+INDEX=1
+TOTAL_OBJECT_COUNT="$(wc -l $PKG_METADATA_DOWNLOADS_OUTPUT_FILE | awk '{print $1}')"
+
+# Download the objects
+while IFS= read -r line; do
+ FILE="$(echo -n $line | awk '{print $1}')"
+ URL="$(echo -n $line | awk '{print $2}')"
+ OUTPUT_DIR="$(dirname $PKG_METADATA_DIR/$FILE)"
+ OUTPUT_PATH="$PKG_METADATA_DIR/$FILE"
+
+ echo "Downloading $FILE"
+
+ curl --progress-bar --create-dirs --output "$OUTPUT_PATH" --request "GET" "$URL"
+
+ echo -e "$INDEX of $TOTAL_OBJECT_COUNT objects downloaded\n"
+
+ let INDEX=(INDEX+1)
+done < "$PKG_METADATA_DOWNLOADS_OUTPUT_FILE"
+
+echo "All objects saved to $PKG_METADATA_DIR"
+```
+
+### Automatic synchronization
+
+Your GitLab instance is synchronized [every hour](https://gitlab.com/gitlab-org/gitlab/-/blob/d4331343d26d6e2a81fadd8f7ecd72f7cb74d04d/config/initializers/1_settings.rb#L831-832) with the contents of the `package_metadata_db` directory.
+To automatically update your local copy with the upstream changes, a cron job can be added to periodically download new exports. For example, the following crontabs can be added to setup a cron job that runs every 30 minutes.
+
+```plaintext
+*/30 * * * * gsutil -m rsync -r -d gs://prod-export-license-bucket-1a6c642fc4de57d4 $GITLAB_RAILS_ROOT_DIR/vendor/package_metadata_db/
+```
diff --git a/doc/topics/set_up_organization.md b/doc/topics/set_up_organization.md
index 855b4962960..cf0a0ae4ab7 100644
--- a/doc/topics/set_up_organization.md
+++ b/doc/topics/set_up_organization.md
@@ -11,7 +11,7 @@ and give everyone access to the projects they need.
- [Namespaces](../user/namespace/index.md)
- [Members](../user/project/members/index.md)
-- [Organization](../user/workspace/index.md) _(In development)_
+- [Organization](../user/organization/index.md) _(In development)_
- [Groups](../user/group/index.md)
- [User account options](../user/profile/index.md)
- [SSH keys](../user/ssh.md)
diff --git a/doc/topics/your_work.md b/doc/topics/your_work.md
index 862f9ae8430..268a6c4df5b 100644
--- a/doc/topics/your_work.md
+++ b/doc/topics/your_work.md
@@ -16,3 +16,8 @@ The **Your work** left sidebar provides access to your:
- [Merge requests](../user/project/merge_requests/index.md)
- [To-do List](../user/todos.md)
- [Milestones](../user/project/milestones/index.md)
+- [Snippets](../user/snippets.md#snippets)
+- [Activity](../user/profile/index.md#view-your-activity)
+- [Environments dashboard](../ci/environments/environments_dashboard.md)
+- [Operations dashboard](../user/operations_dashboard/index.md)
+- [Security center](../user/application_security/security_dashboard/index.md#security-center)
diff --git a/doc/tutorials/convert_personal_namespace_into_group.md b/doc/tutorials/convert_personal_namespace_into_group.md
new file mode 100644
index 00000000000..e272d854a35
--- /dev/null
+++ b/doc/tutorials/convert_personal_namespace_into_group.md
@@ -0,0 +1,95 @@
+---
+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: Convert a personal namespace into a group **(FREE SAAS)**
+
+If you've started out on GitLab with a personal [namespace](../user/namespace/index.md), but now find
+that you've outgrown its capabilities and its limitations hinder the collaboration on your projects,
+you might want to switch to a group namespace instead.
+A group namespace allows you to create multiple subgroups, and manage their members and permissions.
+
+You don't have to start from scratch - you can create a new group
+and move your existing projects to the group to get the added benefits.
+To find out how, see [Tutorial: Move your personal project to a group](move_personal_project_to_a_group.md).
+
+But you can go one step further and convert your personal namespace into a group namespace,
+so you get to keep the existing username and URL. For example, if your username is `alex`,
+you can continue using the `https://gitlab.example.com/alex` URL for your group.
+
+This tutorial shows you how to convert your personal namespace into a group namespace
+using the following steps:
+
+1. [Create a group](#create-a-group).
+1. [Transfer projects from the personal namespace to the group](#transfer-projects-from-the-personal-namespace-to-the-group).
+1. [Rename the original username](#rename-the-original-username).
+1. [Rename the new group namespace to the original username](#rename-the-new-group-namespace-to-the-original-username).
+
+For example, if your username for a personal namespace is `alex`, first create a group namespace named `alex-group`.
+Then, move all projects from the `alex` to the `alex-group` namespace. Finally,
+rename the `alex` namespace to `alex-user`, and `alex-group` namespace to the now available `alex` username.
+
+## Create a group
+
+1. On the top bar, select **Main menu > Groups > View all groups**.
+1. On the right of the page, select **New group**.
+1. In **Group name**, enter a name for the group.
+1. In **Group URL**, enter a path for the group, which is used as the namespace.
+ Don't worry about the actual path, this is only temporary. You'll change this URL to the username of the personal namespace in the [final step](#rename-the-new-group-namespace-to-the-original-username).
+1. Choose the [visibility level](../user/public_access.md).
+1. Optional. Fill in information to personalize your experience.
+1. Select **Create group**.
+
+## Transfer projects from the personal namespace to the group
+
+Next, you must transfer your projects from the personal namespace to the new group.
+You can transfer only one project at a time, so if you want to transfer multiple projects,
+you must perform the steps below for each project.
+
+Before you start the transfer process, make sure you:
+
+- Have the Owner role for the project.
+- Remove [container images](../user/packages/container_registry/index.md#move-or-rename-container-registry-repositories).
+ You can't transfer a project that contains container images.
+- Remove npm packages. You can't update the root namespace of a project that contains npm packages.
+
+To transfer a project to a group:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Advanced**.
+1. Under **Transfer project**, choose the group to transfer the project to.
+1. Select **Transfer project**.
+1. Enter the project's name and select **Confirm**.
+
+## Rename the original username
+
+Next, rename the original username of the personal namespace, so that the username becomes available for the new group namespace.
+You can keep on using the personal namespace for other personal projects, or [delete that user account](../user/profile/account/delete_account.md)
+
+From the moment you rename the personal namespace, the username becomes available, so it's possible that someone else registers an account with it. To avoid this, you should [rename the new group](#rename-the-new-group-namespace-to-the-original-username) as soon as possible.
+
+To [change a user's username](../user/profile/index.md#change-your-username):
+
+1. On the top bar, in the top-right corner, select your avatar.
+1. Select **Edit profile**.
+1. On the left sidebar, select **Account**.
+1. In the **Change username** section, enter a new username as the path.
+1. Select **Update username**.
+
+## Rename the new group namespace to the original username
+
+Finally, rename the new group's URL to the username of the original personal namespace.
+
+To [change your group path](../user/group/manage.md#change-a-groups-path) (group URL):
+
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, select **Settings > General page**.
+1. Expand the **Advanced** section.
+1. Under **Change group URL**, enter the user's original username.
+1. Select **Change group URL**.
+
+That's it! You have now converted a personal namespace into a group, which opens up new possibilities of
+working on projects and collaborating with more members.
diff --git a/doc/tutorials/index.md b/doc/tutorials/index.md
index c1b538bafbe..7a94583ae69 100644
--- a/doc/tutorials/index.md
+++ b/doc/tutorials/index.md
@@ -20,6 +20,7 @@ and running quickly.
| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Use GitLab for DevOps](https://www.youtube.com/watch?v=7q9Y1Cv-ib0) (12m 34s) | Use GitLab through the entire DevOps lifecycle, from planning to monitoring. | **{star}** |
| [Use Markdown at GitLab](../user/markdown.md) | GitLab Flavored Markdown (GLFM) is used in many areas of GitLab, for example, in merge requests. | **{star}** |
| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Learn GitLab project walkthrough](https://www.youtube.com/watch?v=-oaI2WEKdI4&list=PL05JrBw4t0KofkHq4GZJ05FnNGa11PQ4d) (59m 2s) | Step through the tutorial-style issues in the **Learn GitLab** project. If you don't have this project, download [the export file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/vendor/project_templates/learn_gitlab_ultimate.tar.gz) and [import it to a new project](../user/project/settings/import_export.md#import-a-project-and-its-data). | |
+| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [GitLab Continuous Delivery overview](https://www.youtube.com/watch?v=g-gO93PMZvk&list=PLFGfElNsQthYDx0A_FaNNfUm9NHsK6zED&index=134) (17m 2s) | Learn how to use GitLab features to continuously build, test, and deploy iterative code changes. | |
| [Productivity tips](https://about.gitlab.com/blog/2021/02/18/improve-your-gitlab-productivity-with-these-10-tips/) | Get tips to help make you a productive GitLab user. | |
## Use Git
diff --git a/doc/update/background_migrations.md b/doc/update/background_migrations.md
index a55d2af8dd4..47b786f2894 100644
--- a/doc/update/background_migrations.md
+++ b/doc/update/background_migrations.md
@@ -124,8 +124,10 @@ If you get this error, [check the batched background migration options](#databas
### Pause batched background migrations in GitLab 14.x
-To pause an ongoing batched background migration, use the `disable` command above.
-This command causes the migration to complete the current batch, and then wait to start the next batch.
+To pause an ongoing batched background migration,
+[disable the batched background migrations feature](#enable-or-disable-background-migrations).
+Disabling the feature completes the current batch of migrations, then waits to start
+the next batch until after the feature is enabled again.
Use the following database queries to see the state of the current batched background migration:
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index ff2a018cd23..d7bbf254f2a 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -18,14 +18,14 @@ For deprecation authors (usually Product Managers and Engineering Managers):
- To add a deprecation, use the example.yml file in `/data/deprecations/templates` as a template.
- For more information about authoring deprecations, check the the deprecation item guidance:
- https://about.gitlab.com/handbook/marketing/blog/release-posts/#creating-a-deprecation-entry
+ https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-deprecations-and-removals-docs
For deprecation reviewers (Technical Writers only):
- To update the deprecation doc, run: `bin/rake gitlab:docs:compile_deprecations`
- To verify the deprecations doc is up to date, run: `bin/rake gitlab:docs:check_deprecations`
- For more information about updating the deprecation doc, see the deprecation doc update guidance:
- https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-deprecations-doc
+ https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-deprecations-and-removals-docs
-->
{::options parse_block_html="true" /}
@@ -37,17 +37,89 @@ Some features cause breaking changes when they are removed.
**{rss}** **To be notified of upcoming breaking changes**,
add this URL to your RSS feed reader: `https://about.gitlab.com/breaking-changes.xml`
-DISCLAIMER:
-This page contains information related to upcoming products, features, and functionality.
-It is important to note that the information presented is for informational purposes only.
-Please do not rely on this information for purchasing or planning purposes.
-As with all projects, the items mentioned on this page are subject to change or delay.
-The development, release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
+You can also view [REST API](https://docs.gitlab.com/ee/api/rest/deprecations.html)
+and [GraphQL](https://docs.gitlab.com/ee/api/graphql/removed_items.html) deprecations/removals.
<div class="js-deprecation-filters"></div>
<div class="announcement-milestone">
+## Announced in 15.10
+
+<div class="deprecation removal-160 breaking-change">
+
+### Deprecated Consul http metrics
+
+Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The Consul provided in the GitLab Omnibus package will no longer provide older deprecated Consul metrics starting in GitLab 16.0.
+
+In GitLab 14.0, [Consul was updated to 1.9.6](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5344),
+which deprecated some telemetry metrics from being at the `consul.http` path. In GitLab 16.0, the `consul.http` path will be removed.
+
+If you have monitoring that consumes Consul metrics, update them to use `consul.api.http` instead of `consul.http`.
+For more information, see [the deprecation notes for Consul 1.9.0](https://github.com/hashicorp/consul/releases/tag/v1.9.0).
+
+</div>
+
+<div class="deprecation removal-170 breaking-change">
+
+### DingTalk OmniAuth provider
+
+Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The `omniauth-dingtalk` gem that provides GitLab with the DingTalk OmniAuth provider will be removed in our next
+major release, GitLab 17.0. This gem sees very little use and is better suited for JiHu edition.
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
+### Environment search query requires at least three characters
+
+Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+From GitLab 16.0, when you search for environments with the API, you must use at least three characters. This change helps us ensure the scalability of the search operation.
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
+### Legacy Gitaly configuration method
+
+Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+Gitaly configuration within Omnibus GitLab has been updated such that all Gitaly related configuration keys are in a single
+configuration structure that matches the standard Gitaly configuration. As such, the previous configuration structure is deprecated.
+
+The single configuration structure is available from GitLab 15.10, though backwards compatibility is maintained. Once removed, Gitaly must be configured using the single
+configuration structure. You should update the configuration of Gitaly at your earliest convenience.
+
+The change improves consistency between Omnibus GitLab and source installs and enables us to provide better documentation and tooling for both.
+
+You should update to the new configuration structure as soon as possible using
+[the upgrade instructions](https://docs.gitlab.com/ee/update/#gitaly-omnibus-gitlab-configuration-structure-change).
+
+</div>
+</div>
+
+<div class="announcement-milestone">
+
## Announced in 15.9
<div class="deprecation removal-170 breaking-change">
@@ -112,6 +184,21 @@ In 16.0, this inbound scope limit will be the only option available for all proj
<div class="deprecation removal-160 breaking-change">
+### Deprecation and planned removal for `CI_PRE_CLONE_SCRIPT` variable on GitLab SaaS
+
+End of Support: GitLab <span class="removal-milestone">16.0</span> <span class="support-end-date"></span><br />
+Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The [`CI_PRE_CLONE_SCRIPT` variable](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html#pre-clone-script) supported by GitLab SaaS Runners is deprecated as of GitLab 15.9 and will be removed in 16.0. The `CI_PRE_CLONE_SCRIPT` variable enables you to run commands in your CI/CD job prior to the runner executing Git init and get fetch. For more information about how this feature works, see [Pre-clone script](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html#pre-clone-script). As an alternative, you can use the [`pre_get_sources_script`](https://docs.gitlab.com/ee/ci/yaml/#hookspre_get_sources_script).
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
### Development dependencies reported for PHP and Python
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
@@ -141,7 +228,7 @@ We intend to replace this feature with the ability to [embed charts](https://git
<div class="deprecation removal-160 breaking-change">
-### Error Tracking UI in GitLab Rails is deprecated
+### Enforced validation of CI/CD parameter character lengths
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
@@ -149,7 +236,29 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-The [Error Tracking UI](https://docs.gitlab.com/ee/operations/error_tracking.html) is deprecated in 15.9 and will be removed in 16.0. In future versions, you should use the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui/), which will gradually be made available on GitLab.com over the next few releases.
+While CI/CD [job names](https://docs.gitlab.com/ee/ci/jobs/index.html#job-name-limitations) have a strict 255 character limit, other CI/CD parameters do not yet have validations ensuring they also stay under the limit.
+
+In GitLab 16.0, validation will be added to strictly limit the following to 255 characters as well:
+
+- The `stage` keyword.
+- The `ref`, which is the Git branch or tag name for the pipeline.
+- The `description` and `target_url` parameter, used by external CI/CD integrations.
+
+Users on self-managed instances should update their pipelines to ensure they do not use parameters that exceed 255 characters. Users on GitLab.com do not need to make any changes, as these are already limited in that database.
+
+</div>
+
+<div class="deprecation removal-166 breaking-change">
+
+### Error Tracking UI in GitLab Rails is deprecated
+
+Planned removal: GitLab <span class="removal-milestone">16.6</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The [Error Tracking UI](https://docs.gitlab.com/ee/operations/error_tracking.html) is deprecated in 15.9 and will be removed in 16.6 (milestone might change) once GitLab Observability UI is made available. In future versions, you should use the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui/), which will gradually be made available on GitLab.com over the next few releases.
During the transition to the GitLab Observability UI, we will migrate the [GitLab Observability Backend](https://gitlab.com/gitlab-org/opstrace/opstrace) from a per-cluster deployment model to a per-tenant deployment model. Because [Integrated Error Tracking](https://docs.gitlab.com/ee/operations/error_tracking.html#integrated-error-tracking) is in Open Beta, we will not migrate any existing user data. For more details about the migration, see the direction pages for:
@@ -268,8 +377,8 @@ Previously, Praefect configuration keys were scattered throughout the configurat
Praefect configuration so the previous configuration method is deprecated.
The single configuration structure available from GitLab 15.9, though backwards compatibility is maintained. Once removed, Praefect must be configured using the single
-configuration structure. You should update the configuration of Praefect at your earliest convenience. See
-[GitLab 15.9 upgrade information](https://docs.gitlab.com/ee/update/#1590).
+configuration structure. You should update your Praefect configuration as soon as possible using
+[the upgrade instructions](https://docs.gitlab.com/ee/update/#praefect-omnibus-gitlab-configuration-structure-change).
This change brings Praefect configuration in Omnibus GitLab in line with the configuration structure of Praefect. Previously, the hierarchies and configuration keys
didn't match. The change improves consistency between Omnibus GitLab and source installs and enables us to provide better documentation and tooling for both.
@@ -346,6 +455,20 @@ Due to low customer usage, Load Performance Testing is deprecated and will be re
<div class="deprecation removal-160 breaking-change">
+### Managed Licenses API
+
+Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The [Managed Licenses API](https://docs.gitlab.com/ee/api/managed_licenses.html) is now deprecated and is scheduled for removal in GitLab 16.0.
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
### Old versions of JSON web tokens are deprecated
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
@@ -379,11 +502,11 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-The project deletion protection setting in the Admin Area had an option to delete projects immediately. Starting with 16.0, this option will no longer be available, and delayed project deletion will become the default behavior.
+The group and project deletion protection setting in the Admin Area had an option to delete groups and projects immediately. Starting with 16.0, this option will no longer be available, and delayed group and project deletion will become the default behavior.
-The option will no longer appear as a group setting. Self-managed users will still have the option to define the deletion delay period, and SaaS users have a non-adjustable default retention period of 7 days. Users can still delete the project immediately from the project settings.
+The option will no longer appear as a group setting. Self-managed users will still have the option to define the deletion delay period, and SaaS users have a non-adjustable default retention period of 7 days. Users can still immediately delete the project from the project settings, and the group from the group settings.
-The option to delete projects immediately by default was deprecated to prevent users from accidentally taking this action and permanently losing projects.
+The option to delete groups and projects immediately by default was deprecated to prevent users from accidentally taking this action and permanently losing groups and projects.
</div>
@@ -638,17 +761,17 @@ We will be transitioning to a new IID as a result of moving requirements to a [w
</div>
-<div class="deprecation removal-160 breaking-change">
+<div class="deprecation removal-170 breaking-change">
### Trigger jobs can mirror downstream pipeline status exactly
-Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
+Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-In some cases, like when a downstream pipeline had the `passed with warnings` status, trigger jobs that were using [`strategy: depend`](https://docs.gitlab.com/ee/ci/yaml/index.html#strategydepend) did not mirror the status of the downstream pipeline exactly. In GitLab 16.0 trigger jobs will show the exact same status as the the downstream pipeline. If your pipeline relied on this behavior, you should update your pipeline to handle the more accurate status.
+In some cases, like when a downstream pipeline had the `passed with warnings` status, trigger jobs that were using [`strategy: depend`](https://docs.gitlab.com/ee/ci/yaml/index.html#strategydepend) did not mirror the status of the downstream pipeline exactly. In GitLab 17.0 trigger jobs will show the exact same status as the the downstream pipeline. If your pipeline relied on this behavior, you should update your pipeline to handle the more accurate status.
</div>
</div>
@@ -659,20 +782,6 @@ In some cases, like when a downstream pipeline had the `passed with warnings` st
<div class="deprecation removal-160 breaking-change">
-### Approvers and Approver Group fields in Merge Request Approval API
-
-Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
-
-WARNING:
-This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-Review the details carefully before upgrading.
-
-The endpoint to get the configuration of approvals for a project returns empty arrays for `approvers` and `approval_groups`. These fields were deprecated in favor of the endpoint to [get project-level rules](https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-project-level-rules) for a merge request. API users are encouraged to switch to this endpoint instead. These fields will be removed from the `get configuration` endpoint in v5 of the GitLab REST API.
-
-</div>
-
-<div class="deprecation removal-160 breaking-change">
-
### Auto DevOps no longer provisions a PostgreSQL database by default
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
@@ -1253,25 +1362,11 @@ and will be moved to the JiHu GitLab codebase.
</div>
-<div class="deprecation removal-160 breaking-change">
-
-### Single merge request changes API endpoint
-
-Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
-
-WARNING:
-This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-Review the details carefully before upgrading.
-
-The endpoint to get [changes from a single merge request](https://docs.gitlab.com/ee/api/merge_requests.html#get-single-merge-request-changes) has been deprecated in favor the [list merge request diffs](https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-request-diffs) endpoint. API users are encouraged to switch to the new diffs endpoint instead. The `changes from a single merge request` endpoint will be removed in v5 of the GitLab REST API.
-
-</div>
-
<div class="deprecation removal-170 breaking-change">
### Support for REST API endpoints that reset runner registration tokens
-End of Support: GitLab <span class="removal-milestone">16.6</span> <span class="support-end-date"></span><br />
+End of Support: GitLab <span class="removal-milestone">17.0</span> <span class="support-end-date"></span><br />
Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
WARNING:
@@ -1286,8 +1381,9 @@ The deprecated endpoints are:
- `POST /projects/:id/runners/reset_registration_token`
- `POST /groups/:id/runners/reset_registration_token`
-In GitLab 15.8, we plan to implement a new method to bind runners to a GitLab instance,
+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.
@@ -1402,14 +1498,17 @@ From GitLab 13.6, users can [specify any runner configuration in the GitLab Runn
### GitLab Runner registration token in Runner Operator
-End of Support: GitLab <span class="removal-milestone">16.6</span> <span class="support-end-date"></span><br />
+End of Support: GitLab <span class="removal-milestone">17.0</span> <span class="support-end-date"></span><br />
Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-The [`runner-registration-token`](https://docs.gitlab.com/runner/install/operator.html#install-the-kubernetes-operator) parameter that uses the OpenShift and k8s Vanilla Operator to install a runner on Kubernetes is deprecated. GitLab plans to introduce a new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/) in GitLab 15.8, which introduces a new method for registering runners and eliminates the legacy runner registration token.
+The [`runner-registration-token`](https://docs.gitlab.com/runner/install/operator.html#install-the-kubernetes-operator) parameter that uses the OpenShift and k8s Vanilla Operator to install a runner on Kubernetes is deprecated.
+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).
</div>
@@ -1417,7 +1516,7 @@ The [`runner-registration-token`](https://docs.gitlab.com/runner/install/operato
### Registration tokens and server-side runner arguments in `POST /api/v4/runners` endpoint
-End of Support: GitLab <span class="removal-milestone">16.6</span> <span class="support-end-date"></span><br />
+End of Support: GitLab <span class="removal-milestone">17.0</span> <span class="support-end-date"></span><br />
Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
WARNING:
@@ -1429,8 +1528,9 @@ This endpoint [registers](https://docs.gitlab.com/ee/api/runners.html#register-a
with a GitLab instance at the instance, group, or project level through the API. We plan to remove the support for
registration tokens and certain configuration arguments in this endpoint in GitLab 17.0.
-In GitLab 15.10, we plan to implement a new method to bind runners to a GitLab instance,
+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.
@@ -1441,7 +1541,7 @@ From GitLab 17.0 and later, the runner registration methods implemented by the n
### Registration tokens and server-side runner arguments in `gitlab-runner register` command
-End of Support: GitLab <span class="removal-milestone">16.6</span> <span class="support-end-date"></span><br />
+End of Support: GitLab <span class="removal-milestone">17.0</span> <span class="support-end-date"></span><br />
Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
WARNING:
@@ -1449,9 +1549,9 @@ This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_g
Review the details carefully before upgrading.
The support for registration tokens and certain configuration arguments in the command to [register](https://docs.gitlab.com/runner/register/) a runner, `gitlab-runner register` is deprecated.
-GitLab plans to introduce a new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/) in GitLab 15.10,
-which introduces a new method for registering runners and eliminates the legacy
-[runner registration token](https://docs.gitlab.com/ee/security/token_overview.html#runner-registration-tokens).
+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).
The new method will involve creating the runner in the GitLab UI and passing the
[runner authentication token](https://docs.gitlab.com/ee/security/token_overview.html#runner-authentication-tokens-also-called-runner-tokens)
to the `gitlab-runner register` command.
@@ -1462,7 +1562,7 @@ to the `gitlab-runner register` command.
### `runnerRegistrationToken` parameter for GitLab Runner Helm Chart
-End of Support: GitLab <span class="removal-milestone">16.6</span> <span class="support-end-date"></span><br />
+End of Support: GitLab <span class="removal-milestone">17.0</span> <span class="support-end-date"></span><br />
Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
WARNING:
@@ -1471,28 +1571,13 @@ Review the details carefully before upgrading.
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.
-As part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/), in GitLab 15.8 we plan to introduce:
-
-- A new method to bind runners to a GitLab instance leveraging `runnerToken`.
-- A unique system ID saved to the `config.toml`, which will ensure traceability between jobs and runners.
+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 removal-160 breaking-change">
-
-### merge_status API field
-
-Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
-
-WARNING:
-This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-Review the details carefully before upgrading.
-
-The `merge_status` field in the [merge request API](https://docs.gitlab.com/ee/api/merge_requests.html#merge-status) has been deprecated in favor of the `detailed_merge_status` field which more correctly identifies all of the potential statuses that a merge request can be in. API users are encouraged to use the new `detailed_merge_status` field instead. The `merge_status` field will be removed in v5 of the GitLab REST API.
-
-</div>
</div>
<div class="announcement-milestone">
@@ -1819,21 +1904,6 @@ The [`project_fingerprint`](https://gitlab.com/groups/gitlab-org/-/epics/2791) a
</div>
-<div class="deprecation removal-160 breaking-change">
-
-### REST API Runner maintainer_note
-
-Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
-
-WARNING:
-This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-Review the details carefully before upgrading.
-
-The `maintainer_note` argument in the `POST /runners` REST endpoint was deprecated in GitLab 14.8 and replaced with the `maintenance_note` argument.
-The `maintainer_note` argument will be removed in GitLab 16.0.
-
-</div>
-
<div class="deprecation removal-153">
### Vulnerability Report sort by Tool
@@ -2310,29 +2380,6 @@ To align with this change, API calls to list external status checks will also re
</div>
-<div class="deprecation removal-160 breaking-change">
-
-### GraphQL API Runner will not accept `status` filter values of `active` or `paused`
-
-Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
-
-WARNING:
-This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-Review the details carefully before upgrading.
-
-The GitLab Runner GraphQL endpoints will stop accepting `paused` or `active` as a status value in GitLab 16.0.
-
-A runner's status will only relate to runner contact status, such as: `online`, `offline`.
-Status values `paused` or `active` will no longer be accepted and will be replaced by the `paused` query parameter.
-
-When checking for paused runners, API users are advised to specify `paused: true` as the query parameter.
-When checking for active runners, specify `paused: false`.
-
-The REST API endpoints will follow in the same direction in a future REST v5 API, however the new `paused`
-status value can be used in place of `active` since GitLab 14.8.
-
-</div>
-
<div class="deprecation removal-150 breaking-change">
### GraphQL ID and GlobalID compatibility
@@ -2490,37 +2537,6 @@ The `instanceStatisticsMeasurements` GraphQL node has been renamed to `usageTren
</div>
-<div class="deprecation removal-160 breaking-change">
-
-### REST and GraphQL API Runner usage of `active` replaced by `paused`
-
-Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
-
-WARNING:
-This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-Review the details carefully before upgrading.
-
-Occurrences of the `active` identifier in the GitLab Runner GraphQL API endpoints will be
-renamed to `paused` in GitLab 16.0.
-
-- For the GraphQL API, this change affects:
- - the `CiRunner` property
- - the `RunnerUpdateInput` input type for the `runnerUpdate` mutation
- - the `runners` and `Group.runners` queries
-- In v4 of the REST API, starting in GitLab 14.8, you can use the `paused` property in place of `active`
-- In v5 of the REST API, this change will affect:
- - endpoints taking or returning `active` property, such as:
- - `GET /runners`
- - `GET /runners/all`
- - `GET /runners/:id` / `PUT /runners/:id`
- - `PUT --form "active=false" /runners/:runner_id`
- - `GET /projects/:id/runners` / `POST /projects/:id/runners`
- - `GET /groups/:id/runners`
-
-The 16.0 release of GitLab Runner will start using the `paused` property when registering runners.
-
-</div>
-
<div class="deprecation removal-150 breaking-change">
### Request profiling
@@ -3160,20 +3176,6 @@ Currently, test coverage visualizations in GitLab only support Cobertura reports
only supported report file in 15.0, but this is the first step towards GitLab supporting other report types.
</div>
-
-<div class="deprecation removal-160 breaking-change">
-
-### merged_by API field
-
-Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
-
-WARNING:
-This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-Review the details carefully before upgrading.
-
-The `merged_by` field in the [merge request API](https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-requests) has been deprecated in favor of the `merge_user` field which more correctly identifies who merged a merge request when performing actions (merge when pipeline succeeds, add to merge train) other than a simple merge. API users are encouraged to use the new `merge_user` field instead. The `merged_by` field will be removed in v5 of the GitLab REST API.
-
-</div>
</div>
<div class="announcement-milestone">
@@ -3682,3 +3684,11 @@ The OAuth implicit grant authorization flow will be removed in our next major re
</div>
</div>
+
+DISCLAIMER:
+This page contains information related to upcoming products, features, and functionality.
+It is important to note that the information presented is for informational purposes only.
+Please do not rely on this information for purchasing or planning purposes.
+As with all projects, the items mentioned on this page are subject to change or delay.
+The development, release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
diff --git a/doc/update/index.md b/doc/update/index.md
index d08368663da..07bd153907a 100644
--- a/doc/update/index.md
+++ b/doc/update/index.md
@@ -107,11 +107,11 @@ To address the above two scenarios, it is advised to do the following prior to u
as your GitLab version. Both versions [should be the same](https://docs.gitlab.com/runner/#gitlab-runner-versions).
1. Unpause your runners and unblock new jobs from starting by reverting the previous `/etc/gitlab/gitlab.rb` change.
-## Checking for pending Advanced Search migrations **(PREMIUM SELF)**
+## Checking for pending advanced search migrations **(PREMIUM SELF)**
This section is only applicable if you have enabled the [Elasticsearch integration](../integration/advanced_search/elasticsearch.md) **(PREMIUM SELF)**.
-Major releases require all [Advanced Search migrations](../integration/advanced_search/elasticsearch.md#advanced-search-migrations)
+Major releases require all [advanced search migrations](../integration/advanced_search/elasticsearch.md#advanced-search-migrations)
to be finished from the most recent minor release in your current version
before the major version upgrade. You can find pending migrations by
running the following command:
@@ -129,16 +129,16 @@ cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:elastic:list_pending_migrations
```
-### What do you do if your Advanced Search migrations are stuck?
+### What do you do if your advanced search migrations are stuck?
-In GitLab 15.0, an Advanced Search migration named `DeleteOrphanedCommit` can be permanently stuck
+In GitLab 15.0, an advanced search migration named `DeleteOrphanedCommit` can be permanently stuck
in a pending state across upgrades. This issue
[is corrected in GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89539).
-If you are a self-managed customer who uses GitLab 15.0 with Advanced Search, you will experience performance degradation.
+If you are a self-managed customer who uses GitLab 15.0 with advanced search, you will experience performance degradation.
To clean up the migration, upgrade to 15.1 or later.
-For other Advanced Search migrations stuck in pending, see [how to retry a halted migration](../integration/advanced_search/elasticsearch.md#retry-a-halted-migration).
+For other advanced search migrations stuck in pending, see [how to retry a halted migration](../integration/advanced_search/elasticsearch.md#retry-a-halted-migration).
### What do you do for the error `Elasticsearch version not compatible`
@@ -166,7 +166,7 @@ It's also important to ensure that any [background migrations have been fully co
before upgrading to a new major version.
If you have enabled the [Elasticsearch integration](../integration/advanced_search/elasticsearch.md) **(PREMIUM SELF)**, then
-[ensure all Advanced Search migrations are completed](#checking-for-pending-advanced-search-migrations) in the last minor version in
+[ensure all advanced search migrations are completed](#checking-for-pending-advanced-search-migrations) in the last minor version in
your current version
before proceeding with the major version upgrade.
@@ -196,11 +196,11 @@ accordingly, while also consulting the
NOTE:
When not explicitly specified, upgrade GitLab to the latest available patch
-release rather than the first patch release, for example `13.8.8` instead of `13.8.0`.
-This includes versions you must stop at on the upgrade path as there may
+release of the `major`.`minor` release rather than the first patch release, for example `13.8.8` instead of `13.8.0`.
+This includes `major`.`minor` versions you must stop at on the upgrade path as there may
be fixes for issues relating to the upgrade process.
Specifically around a [major version](#upgrading-to-a-new-major-version),
-crucial database schema and migration patches are included in the latest patch releases.
+crucial database schema and migration patches may be included in the latest patch releases.
## Upgrading between editions
@@ -237,7 +237,7 @@ possible.
## Version-specific upgrading instructions
-Each month, major, minor, or patch releases of GitLab are published along with a
+Each month, major or minor as well as possibly patch releases of GitLab are published along with a
[release post](https://about.gitlab.com/releases/categories/releases/).
You should read the release posts for all versions you're passing over.
At the end of major and minor release posts, there are three sections to look for specifically:
@@ -264,10 +264,31 @@ NOTE:
Specific information that follow related to Ruby and Git versions do not apply to [Omnibus installations](https://docs.gitlab.com/omnibus/)
and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with appropriate Ruby and Git versions and are not using system binaries for Ruby and Git. There is no need to install Ruby or Git when utilizing these two approaches.
+### 15.10.0
+
+- 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).
+
### 15.9.0
-- This version removes `SanitizeConfidentialTodos` background migration [added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87908/diffs) in 15.6, which removed any user inaccessible to-do items. Make sure that this migration is finished before upgrading to 15.9.
-- 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. Make sure that this migration is finished before upgrading to 15.9.
+- **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).
### 15.8.2
@@ -364,6 +385,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
consistent in our documentation and product defaults.
For example, previously:
+
- Omnibus GitLab default (`sidekiq['max_concurrency']`): 50
- From source installation default: 50
- Helm chart default (`gitlab.sidekiq.concurrency`): 25
@@ -476,7 +498,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
### 15.5.3
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/extra_sidekiq_routing.md) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors), this will cause [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+- 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`:
@@ -488,7 +510,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
### 15.5.2
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/extra_sidekiq_routing.md) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors), this will cause [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+- 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`:
@@ -500,7 +522,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
### 15.5.1
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/extra_sidekiq_routing.md) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors), this will cause [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+- 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`:
@@ -512,7 +534,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
### 15.5.0
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/extra_sidekiq_routing.md) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors), this will cause [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+- 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`:
@@ -564,7 +586,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
- 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/extra_sidekiq_routing.md) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors), this will cause [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+- 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`:
@@ -705,6 +727,8 @@ A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706)
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.
@@ -804,13 +828,13 @@ A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706)
[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):
+ 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
- ```
+ ```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
@@ -883,11 +907,11 @@ or [init scripts](upgrading_from_source.md#configure-sysv-init-script) by [follo
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
- ```
+ ```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.
@@ -928,13 +952,13 @@ or [init scripts](upgrading_from_source.md#configure-sysv-init-script) by [follo
[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):
+ 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
- ```
+ ```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
@@ -1425,6 +1449,330 @@ After upgraded to 11.11.8 you can safely upgrade to 12.0.Z.
See our [documentation on upgrade paths](../policy/maintenance.md#upgrade-recommendations)
for more information.
+### 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 higher 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 source installs.
+
+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`
+- `log_directory`
+- `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.
+
+ ```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: ...,
+ },
+ ],
+ },
+ 'gitaly-ruby': {
+ # gitaly['ruby_max_rss']
+ max_rss: ...,
+ # gitaly['ruby_graceful_restart_timeout']
+ graceful_restart_timeout: ...,
+ # gitaly['ruby_restart_delay']
+ restart_delay: ...,
+ # gitaly['ruby_num_workers']
+ num_workers: ...,
+ },
+ # gitaly['storage']. 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'}.
+ storage: ...,
+ 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 source installs.
+
+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.
@@ -1438,19 +1786,26 @@ and pass the `@hashed` storage path to `-relative-path`.
With this information, you can correctly install [server hooks](../administration/server_hooks.md).
-### Maintenance mode issue in GitLab 13.9 to 14.4
+### Geo: LFS transfers redirect to primary from secondary site mid-session in GitLab 15.1.0 to 15.3.2
-When [Maintenance mode](../administration/maintenance_mode/index.md) is enabled, users cannot sign in with SSO, SAML, or LDAP.
+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.
-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 issue is resolved in GitLab 15.3.3, so customers with the following configuration should upgrade to 15.3.3 or later:
-[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.
+- LFS is enabled.
+- LFS objects are being replicated across Geo sites.
+- Repositories are being pulled by using a Geo secondary site.
-### LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2
+### Geo: Incorrect object storage LFS file deletion on secondary sites in GitLab 15.0.0 to 15.3.2
-When Geo is enabled, LFS objects fail to be saved for imported or mirrored projects.
+[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:
-[This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/352368) was fixed in GitLab 14.8.0 and backported into 14.7.3.
+- 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
@@ -1466,26 +1821,19 @@ by a database engine bug that causes a segmentation fault.
Read more [in the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/364763).
-### 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:
+### LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2
-- 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.
+When Geo is enabled, LFS objects fail to be saved for imported or mirrored projects.
-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.
+[This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/352368) was fixed in GitLab 14.8.0 and backported into 14.7.3.
-### Geo: LFS transfers redirect to primary from secondary site mid-session in GitLab 15.1.0 to 15.3.2
+### Maintenance mode issue in GitLab 13.9 to 14.4
-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.
+When [Maintenance mode](../administration/maintenance_mode/index.md) is enabled, users cannot sign in with SSO, SAML, or LDAP.
-This issue is resolved in GitLab 15.3.3, so customers with the following configuration should upgrade to 15.3.3 or later:
+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).
-- LFS is enabled.
-- LFS objects are being replicated across Geo sites.
-- Repositories are being pulled by using a Geo secondary site.
+[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.
## Miscellaneous
diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md
deleted file mode 100644
index ad36a9ff534..00000000000
--- a/doc/update/mysql_to_postgresql.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-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
-remove_date: '2023-02-28'
-redirect_to: 'index.md'
----
-
-# Migrating from MySQL to PostgreSQL (removed) **(FREE SELF)**
-
-Support for MySQL was removed in GitLab 12.1.
diff --git a/doc/update/package/convert_to_ee.md b/doc/update/package/convert_to_ee.md
index 7ebb860746b..0edb08b9268 100644
--- a/doc/update/package/convert_to_ee.md
+++ b/doc/update/package/convert_to_ee.md
@@ -116,7 +116,7 @@ The steps can be summed up to:
sudo rm /etc/yum.repos.d/gitlab_gitlab-ce.repo
```
-1. Optional. [Set up the Elasticsearch integration](../../integration/advanced_search/elasticsearch.md) to enable [Advanced Search](../../user/search/advanced_search.md).
+1. Optional. [Set up the Elasticsearch integration](../../integration/advanced_search/elasticsearch.md) to enable [advanced search](../../user/search/advanced_search.md).
That's it! You can now use GitLab Enterprise Edition! To update to a newer
version, follow [Update using the official repositories](index.md#upgrade-using-the-official-repositories).
diff --git a/doc/update/package/index.md b/doc/update/package/index.md
index 34c7c096a8d..d3bd89975d2 100644
--- a/doc/update/package/index.md
+++ b/doc/update/package/index.md
@@ -169,7 +169,7 @@ To download and install GitLab:
and architecture. Next to the filename is a label indicating the distribution,
as the filenames may be the same.
1. Find the package version you wish to install, and select the filename from the list.
-1. Select **Download** in the upper right corner to download the package.
+1. In the upper-right corner, select **Download**.
1. After the package is downloaded, install it by using one of the
following commands and replacing `<package_name>` with the package name
you downloaded:
diff --git a/doc/update/plan_your_upgrade.md b/doc/update/plan_your_upgrade.md
index 5b4ecb96747..0d0084cf530 100644
--- a/doc/update/plan_your_upgrade.md
+++ b/doc/update/plan_your_upgrade.md
@@ -172,7 +172,7 @@ If you have Kubernetes clusters connected with GitLab, [upgrade your GitLab agen
#### Elasticsearch
-Before updating GitLab, confirm Advanced Search migrations are complete by
+Before updating GitLab, confirm advanced search migrations are complete by
[checking for pending advanced search migrations](background_migrations.md).
After updating GitLab, you may have to upgrade
diff --git a/doc/update/removals.md b/doc/update/removals.md
index ae42ba53fd5..248d03cbbcb 100644
--- a/doc/update/removals.md
+++ b/doc/update/removals.md
@@ -34,6 +34,16 @@ For removal reviewers (Technical Writers only):
https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-removals-doc
-->
+## Removed in 15.9
+
+### Live Preview no longer available in the Web IDE
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The Live Preview feature of the Web IDE was intended to provide a client-side preview of static web applications. However, complex configuration steps and a narrow set of supported project types have limited its utility. With the introduction of the Web IDE Beta in GitLab 15.7, you can now connect to a full server-side runtime environment. With upcoming support for installing extensions in the Web IDE, we’ll also support more advanced workflows than those available with Live Preview. As of GitLab 15.9, Live Preview is no longer available in the Web IDE.
+
## Removed in 15.8
### CiliumNetworkPolicy within the auto deploy Helm chart is removed
@@ -45,6 +55,18 @@ If you want to preserve this functionality, you can follow one of these two path
1. Fork the [GitLab Auto Deploy Helm chart](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/tree/master/assets/auto-deploy-app) into the `chart/` path within your project
1. Set `AUTO_DEPLOY_IMAGE_VERSION` and `DAST_AUTO_DEPLOY_IMAGE_VERSION` to the most recent version of the image that included the CiliumNetworkPolicy
+### `artifacts:public` CI/CD keyword refactored
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The [`artifacts:public` CI/CD keyword](https://docs.gitlab.com/ee/ci/yaml/#artifactspublic) was discovered to be not working properly since GitLab 15.8 and needed to be refactored. This feature is disabled on GitLab.com, and disabled by default on self-managed instances. If an administrator for an instance running GitLab 15.8 or 15.9 enabled this feature via the `non_public_artifacts` feature flag, it is likely that artifacts created with the `public:false` setting are being treated as `public:true`.
+
+If you have projects that use this setting, you should delete artifacts that must not be public, or [change the visibility](https://docs.gitlab.com/ee/user/public_access.html#change-project-visibility) of affected projects to private, before updating to GitLab 15.8 or later.
+
+In GitLab 15.10, this feature's code was refactored. On instances with this feature enabled, new artifacts created with `public:false` are now working as expected, though still disabled by default. Avoid testing this feature with production data until it is enabled by default and made generally available.
+
## Removed in 15.7
### File Type variable expansion in `.gitlab-ci.yml`
diff --git a/doc/update/restore_after_failure.md b/doc/update/restore_after_failure.md
deleted file mode 100644
index 92b68410dca..00000000000
--- a/doc/update/restore_after_failure.md
+++ /dev/null
@@ -1,12 +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-02-28'
-redirect_to: '../raketasks/backup_restore.md'
----
-
-# Restoring from backup after a failed upgrade (removed) **(FREE SELF)**
-
-This content was removed in GitLab 15.7.
-Use the [backup and restore](../raketasks/backup_restore.md) documentation instead.
diff --git a/doc/update/upgrading_from_source.md b/doc/update/upgrading_from_source.md
index b5ce0e74100..b6efaa7ec25 100644
--- a/doc/update/upgrading_from_source.md
+++ b/doc/update/upgrading_from_source.md
@@ -59,18 +59,15 @@ sudo service gitlab stop
### 3. Update Ruby
-NOTE:
-Beginning in GitLab 13.6, we only support Ruby 2.7 or higher, and dropped
-support for Ruby 2.6. Be sure to upgrade if necessary.
-
+From GitLab 15.10, we only support Ruby 3.0 or higher and dropped support for Ruby 2.7. Be sure to upgrade if necessary.
You can check which version you are running with `ruby -v`.
Download Ruby and compile it:
```shell
mkdir /tmp/ruby && cd /tmp/ruby
-curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.6.tar.gz"
-echo 'e7203b0cc09442ed2c08936d483f8ac140ec1c72e37bb5c401646b7866cb5d10 ruby-2.7.6.tar.gz' | sha256sum -c - && tar xzf ruby-2.7.6.tar.gz
+curl --remote-name --location --progress-bar "https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.5.tar.gz"
+echo '9afc6380a027a4fe1ae1a3e2eccb6b497b9c5ac0631c12ca56f9b7beb4848776 ruby-3.0.5.tar.gz' | sha256sum -c - && tar xzf ruby-3.0.5.tar.gz
cd ruby-2.7.6
./configure --disable-install-rdoc --enable-shared
diff --git a/doc/update/upgrading_postgresql_using_slony.md b/doc/update/upgrading_postgresql_using_slony.md
deleted file mode 100644
index 6d2abee3fc6..00000000000
--- a/doc/update/upgrading_postgresql_using_slony.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-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
-remove_date: '2023-02-28'
-redirect_to: '../administration/postgresql/replication_and_failover.md'
----
-
-# Upgrading PostgreSQL Using Slony (removed) **(FREE SELF)**
-
-This content was removed in GitLab 15.7.
-Patroni has been used for database replication since GitLab 14.0. To perform upgrades, use the [Patroni replication documentation](../administration/postgresql/replication_and_failover.md) instead.
diff --git a/doc/update/zero_downtime.md b/doc/update/zero_downtime.md
index bb5cd195e5d..a85ae79a61c 100644
--- a/doc/update/zero_downtime.md
+++ b/doc/update/zero_downtime.md
@@ -465,6 +465,8 @@ Log in to your **primary** node, executing the following:
sudo SKIP_POST_DEPLOYMENT_MIGRATIONS=true gitlab-rake db:migrate
```
+1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the primary site to the secondary site if they're different. The file must be the same on all of a site’s nodes.
+
### Update the Geo secondary site
On each **secondary** node, executing the following:
@@ -665,6 +667,8 @@ sudo gitlab-ctl hup puma
sudo gitlab-ctl restart sidekiq
```
+1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the primary site to the secondary site if they're different. The file must be the same on all of a site’s nodes.
+
### Step 3: Update each Geo secondary multi-node deployment
Only proceed if you have successfully completed all steps on the Geo **primary** multi-node deployment.
diff --git a/doc/user/admin_area/analytics/index.md b/doc/user/admin_area/analytics/index.md
index 4304e612e4a..2ac8941b286 100644
--- a/doc/user/admin_area/analytics/index.md
+++ b/doc/user/admin_area/analytics/index.md
@@ -14,7 +14,7 @@ Instance-level analytics provide insights into the feature and data usage of you
Prerequisite:
-- You must have administrator access for your instance.
+- You must have administrator access to the instance.
To view instance-level analytics:
diff --git a/doc/user/admin_area/appearance.md b/doc/user/admin_area/appearance.md
index a1fae7e8712..b9850048e7d 100644
--- a/doc/user/admin_area/appearance.md
+++ b/doc/user/admin_area/appearance.md
@@ -71,6 +71,27 @@ to review the saved appearance settings:
NOTE:
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
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375708) in GitLab 15.9.
+
+GitLab can be installed as a [Progressive Web App](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) (PWA).
+Use the Progressive Web App settings to customize its appearance, including its name,
+description, and icon.
+
+### Configure the PWA settings
+
+To configure the PWA settings:
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > Appearance**.
+1. Scroll to the **Progressive Web App (PWA)** section.
+1. Complete the fields.
+ - **Icon**: If you use the standard GitLab icon, it is available in sizes 192x192 pixels,
+ 512x512 pixels, also as a maskable icon. If you use a custom icon, it must be in either size
+ 192x192 pixels, or 512x512 pixels.
+1. Select **Update appearance settings**.
+
## New project pages
You can add a new project guidelines message to the **New project page** in GitLab.
diff --git a/doc/user/admin_area/custom_project_templates.md b/doc/user/admin_area/custom_project_templates.md
index 847f687d051..78819def5de 100644
--- a/doc/user/admin_area/custom_project_templates.md
+++ b/doc/user/admin_area/custom_project_templates.md
@@ -18,7 +18,7 @@ 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](../project/settings/index.md#configure-project-visibility-features-and-permissions)
- except for **GitLab Pages** and **Security & Compliance** are set to **Everyone With Access**.
+ 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.
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index 0375232334f..7227da3ce0d 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -86,6 +86,16 @@ project, the following information is listed:
Projects can be edited or deleted.
+To edit a project's name or description:
+
+1. In the Projects overview, next to the project you want to edit, select **Edit**.
+1. Edit the **Project name** or **Project description**.
+1. Select **Save Changes**.
+
+To delete a project:
+
+1. In the Projects overview, next to the project you want to delete, select **Delete**.
+
The list of projects can be sorted by:
- Updated date
diff --git a/doc/user/admin_area/license.md b/doc/user/admin_area/license.md
index 5296a918f56..823f876539f 100644
--- a/doc/user/admin_area/license.md
+++ b/doc/user/admin_area/license.md
@@ -78,3 +78,5 @@ You may have connectivity issues due to the following reasons:
- If the curl command returns a failure, 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
diff --git a/doc/user/admin_area/license_file.md b/doc/user/admin_area/license_file.md
index 29e43476819..69edb4551da 100644
--- a/doc/user/admin_area/license_file.md
+++ b/doc/user/admin_area/license_file.md
@@ -185,6 +185,13 @@ License.current.license_id
License.current.data
```
+#### Interaction with licenses that start in the future
+
+```ruby
+# Future license data follows the same format as current license data it just uses a different modifier for the License prefix
+License.future_dated
+```
+
#### Check if a project feature is available on the instance
Features listed in [`features.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/gitlab_subscriptions/features.rb).
diff --git a/doc/user/admin_area/monitoring/background_migrations.md b/doc/user/admin_area/monitoring/background_migrations.md
deleted file mode 100644
index b4a6f7f66fb..00000000000
--- a/doc/user/admin_area/monitoring/background_migrations.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../../../update/background_migrations.md'
-remove_date: '2023-03-11'
----
-
-This document was moved to [another location](../../../update/background_migrations.md).
-
-<!-- This redirect file can be deleted after <2023-03-11>. -->
-<!-- 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/user/admin_area/reporting/git_abuse_rate_limit.md b/doc/user/admin_area/reporting/git_abuse_rate_limit.md
index 66d1173058e..1dd9497fed9 100644
--- a/doc/user/admin_area/reporting/git_abuse_rate_limit.md
+++ b/doc/user/admin_area/reporting/git_abuse_rate_limit.md
@@ -11,13 +11,19 @@ info: To determine the technical writer assigned to the Stage/Group associated w
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 `git_abuse_rate_limit_feature_flag`. On GitLab.com, this feature is available.
-Git abuse rate limiting is a feature to automatically [ban users](../moderate_users.md#ban-and-unban-users) who download or clone more than a specified number of repositories in any project in the instance within a given time frame. Banned users cannot sign in to the instance and cannot access any non-public group via HTTP or SSH.
+This is the administration documentation. For information about Git abuse rate limiting at the group level, see the [group-level documentation](../../group/reporting/git_abuse_rate_limit.md).
-If the `git_abuse_rate_limit_feature_flag` feature flag is enabled, all application administrators receive an email when a user is about to be banned.
+Git abuse rate limiting is a feature to automatically [ban users](../moderate_users.md#ban-and-unban-users) who download or clone more than a specified number of repositories in any project in the instance in a given time frame. Banned users cannot sign in to the instance and cannot access any non-public group via HTTP or SSH. The rate limit also applies to users who authenticate with a [personal](../../../user/profile/personal_access_tokens.md) or [group access token](../../../user/group/settings/group_access_tokens.md).
-If automatic banning is disabled, a user is not banned automatically when they exceed the limit. However, administrators are still notified. You can use this setup to determine the correct values of the rate limit settings before enabling automatic banning.
+Git abuse rate limiting does not apply to instance administrators, [deploy tokens](../../../user/project/deploy_tokens/index.md), or [deploy keys](../../../user/project/deploy_keys/index.md).
-If automatic banning is enabled, administrators receive an email when a user is about to be banned, and the user is automatically banned from the GitLab instance.
+## Automatic ban notifications
+
+If the `git_abuse_rate_limit_feature_flag` feature flag is enabled, selected users receive an email when a user is about to be banned.
+
+If automatic banning is disabled, a user is not banned automatically when they exceed the limit. However, notifications are still sent. You can use this setup to determine the correct values of the rate limit settings before enabling automatic banning.
+
+If automatic banning is enabled, an email notification is sent when a user is about to be banned, and the user is automatically banned from the GitLab instance.
## Configure Git abuse rate limiting
@@ -28,6 +34,7 @@ If automatic banning is enabled, administrators receive an email when a user is
1. Enter a number in the **Number of repositories** field, greater than or equal to `0` and less than or equal to `10,000`. This number specifies the maximum amount of unique repositories a user can download in the specified time period before they're banned. When set to `0`, Git abuse rate limiting is disabled.
1. Enter a number in the **Reporting time period (seconds)** field, greater than or equal to `0` and less than or equal to `86,400` (10 days). This number specifies the time in seconds a user can download the maximum amount of repositories before they're banned. When set to `0`, Git abuse rate limiting is disabled.
1. Optional. Exclude up to `100` users by adding them to the **Excluded users** field. Excluded users are not automatically banned.
+ 1. Add up to `100` users to the **Send notifications to** field. You must select at least one user. All application administrators are selected by default.
1. Optional. Turn on the **Automatically ban users from this namespace when they exceed the specified limits** toggle to enable automatic banning.
1. Select **Save changes**.
diff --git a/doc/user/admin_area/reporting/spamcheck.md b/doc/user/admin_area/reporting/spamcheck.md
index 5c305eff4fa..16c144d2469 100644
--- a/doc/user/admin_area/reporting/spamcheck.md
+++ b/doc/user/admin_area/reporting/spamcheck.md
@@ -21,15 +21,15 @@ Spamcheck is only available for package-based installations:
1. Edit `/etc/gitlab/gitlab.rb` and enable Spamcheck:
- ```ruby
- spamcheck['enable'] = true
- ```
+ ```ruby
+ spamcheck['enable'] = true
+ ```
1. Reconfigure GitLab:
- ```shell
- sudo gitlab-ctl reconfigure
- ```
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
1. Verify that the new services `spamcheck` and `spam-classifier` are
up and running:
diff --git a/doc/user/admin_area/settings/account_and_limit_settings.md b/doc/user/admin_area/settings/account_and_limit_settings.md
index 35a4c0aeea7..a23f500172e 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -174,6 +174,16 @@ wiki, packages, or snippets. The repository size limit applies to both private a
For details on manually purging files, see [reducing the repository size using Git](../../project/repository/reducing_the_repo_size_using_git.md).
+## Customize the default session duration
+
+You can change how long users can remain signed in.
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Account and limit**. The set duration is in **Session duration (minutes)**.
+
+For details, see [cookies used for sign-in](../../profile/index.md#cookies-used-for-sign-in).
+
## Customize session duration for Git Operations when 2FA is enabled **(PREMIUM SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/296669) in GitLab 13.9.
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index aa171fe4536..8f7081a909d 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -54,7 +54,7 @@ To enable a project runner for more than one project:
1. On the top bar, select **Main menu > Admin**.
1. From the left sidebar, select **CI/CD > Runners**.
1. Select the runner you want to edit.
-1. In the upper right, select **Edit** (**{pencil}**).
+1. In the upper-right corner, select **Edit** (**{pencil}**).
1. Under **Restrict projects for this runner**, search for a project.
1. To the left of the project, select **Enable**.
1. Repeat this process for each additional project.
@@ -344,7 +344,7 @@ To restrict all users in an instance from registering runners:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > CI/CD**.
-1. Expand **Runner registration**.
+1. Expand **Runners**.
1. Clear the checkbox if you don't want to display runner registration
information in the UI for group or project members.
1. Select **Save changes**.
diff --git a/doc/user/admin_area/settings/deprecated_api_rate_limits.md b/doc/user/admin_area/settings/deprecated_api_rate_limits.md
index 8bf0ffd21a5..13f8bc008e3 100644
--- a/doc/user/admin_area/settings/deprecated_api_rate_limits.md
+++ b/doc/user/admin_area/settings/deprecated_api_rate_limits.md
@@ -28,9 +28,9 @@ the general user and IP rate limits for requests to deprecated endpoints. You ca
and IP rate limits already in place, and increase or decrease the rate limits
for deprecated API endpoints. No other new features are provided by this override.
-Prerequisites:
+Prerequisite:
-- You must have administrator access for your instance.
+- You must have administrator access to the instance.
To override the general user and IP rate limits for requests to deprecated API endpoints:
diff --git a/doc/user/admin_area/settings/external_authorization.md b/doc/user/admin_area/settings/external_authorization.md
index 94d9ec73640..32a5b0a606f 100644
--- a/doc/user/admin_area/settings/external_authorization.md
+++ b/doc/user/admin_area/settings/external_authorization.md
@@ -43,9 +43,6 @@ using Omnibus, learn to install a custom CA in the
Alternatively, learn where to install custom certificates by using
`openssl version -d`.
-When external authorization is enabled, [deploy tokens](../../project/deploy_tokens/index.md)
- and [deploy keys](../../project/deploy_keys/index.md) can't be used for Git operations.
-
## Configuration
The external authorization service can be enabled by an administrator:
@@ -56,6 +53,26 @@ The external authorization service can be enabled by an administrator:
1. Complete the fields.
1. Select **Save changes**.
+### Allow external authorization with deploy tokens and deploy keys
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386656) in GitLab 15.9.
+
+You can set your instance to allow external authorization for Git operations with
+[deploy tokens](../../project/deploy_tokens/index.md) or [deploy keys](../../project/deploy_keys/index.md).
+
+Prerequisites:
+
+- You must be using classification labels without a service URL for external authorization.
+
+To allow authorization with deploy tokens and keys:
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **External authorization**, and:
+ - Leave the service URL field empty.
+ - Select **Allow deploy tokens and deploy keys to be used with external authorization**.
+1. Select **Save changes**.
+
## How it works
When GitLab requests access, it sends a JSON POST request to the external
@@ -106,7 +123,7 @@ You can use your own classification label in the project's
label" box. When no classification label is specified on a project, the default
label defined in the [global settings](#configuration) is used.
-The label is shown on all project pages in the upper right corner.
+On all project pages, in the upper-right corner, the label appears.
![classification label on project page](img/classification_label_on_project_page_v14_8.png)
diff --git a/doc/user/admin_area/settings/files_api_rate_limits.md b/doc/user/admin_area/settings/files_api_rate_limits.md
index ef9a3674c49..8677e3d86bf 100644
--- a/doc/user/admin_area/settings/files_api_rate_limits.md
+++ b/doc/user/admin_area/settings/files_api_rate_limits.md
@@ -26,7 +26,7 @@ for the Files API. No other new features are provided by this override.
Prerequisite:
-- You must have administrator access for your instance.
+- You must have administrator access to the instance.
To override the general user and IP rate limits for requests to the Repository files API:
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index 5a550f15a41..5c4d7ee4be0 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -130,7 +130,7 @@ The **Network** settings contain:
- [Search rate limits](../../../administration/instance_limits.md#search-rate-limit) - Configure global search request rate limits for authenticated and unauthenticated users.
- [Deprecated API Rate Limits](deprecated_api_rate_limits.md) - Configure specific limits
for deprecated API requests that supersede the user and IP rate limits.
-- [Outbound requests](../../../security/webhooks.md) - Allow requests to the local network from hooks and services.
+- [Outbound requests](../../../security/webhooks.md) - Allow requests to the local network from webhooks and integrations, or deny all outbound requests.
- [Protected Paths](protected_paths.md) - Configure paths to be protected by Rack Attack.
- [Incident Management Limits](../../../operations/incident_management/index.md) - Limit the
number of inbound alerts that can be sent to a project.
diff --git a/doc/user/admin_area/settings/rate_limit_on_projects_api.md b/doc/user/admin_area/settings/rate_limit_on_projects_api.md
new file mode 100644
index 00000000000..beed083c484
--- /dev/null
+++ b/doc/user/admin_area/settings/rate_limit_on_projects_api.md
@@ -0,0 +1,33 @@
+---
+type: reference
+stage: Data Stores
+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
+---
+
+# Rate limit on Projects API **(FREE SELF)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112283) in GitLab 15.10 behind a feature flag, disabled by default.
+
+You can configure the rate limit per IP address for unauthenticated requests to the [list all projects API](../../../api/projects.md#list-all-projects).
+
+To change the rate limit:
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > Network**.
+1. Expand **Projects API rate limit**.
+1. In the **Maximum requests per 10 minutes per IP address** text box, enter the new value.
+1. Select **Save changes**.
+
+The rate limit:
+
+- Applies per IP address.
+- Doesn't apply to authenticated requests.
+- Can be set to 0 to disable rate limiting.
+
+The default value of the rate limit is `400`.
+
+Requests over the rate limit are logged into the `auth.log` file.
+
+For example, if you set a limit of 400, unauthenticated requests to the `GET /projects` API endpoint that
+exceed a rate of 400 within 10 minutes are blocked. Access to the endpoint is restored after ten minutes have elapsed.
diff --git a/doc/user/admin_area/settings/sign_up_restrictions.md b/doc/user/admin_area/settings/sign_up_restrictions.md
index c44901b1ad7..3bf52bfe001 100644
--- a/doc/user/admin_area/settings/sign_up_restrictions.md
+++ b/doc/user/admin_area/settings/sign_up_restrictions.md
@@ -51,17 +51,26 @@ signing up using OmniAuth or LDAP, set `block_auto_created_users` to `true` in t
[OmniAuth configuration](../../../integration/omniauth.md#configure-common-settings) or
[LDAP configuration](../../../administration/auth/ldap/index.md#basic-configuration-settings).
-## Require email confirmation
+## Confirm user email
+
+> - Soft email confirmation [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47003) in GitLab 12.2 [with a flag](../../../operations/feature_flags.md) named `soft_email_confirmation`.
+> - Soft email confirmation [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107302/diffs) from a feature flag to an application setting in GitLab 15.9.
You can send confirmation emails during sign up and require that users confirm
their email address before they are allowed to sign in.
-To enforce confirmation of the email address used for new sign ups:
+For example, to enforce confirmation of the email address used for new sign ups:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
1. Under **Email confirmation settings**, select **Hard**.
+The following settings are available:
+
+- **Hard** - Send a confirmation email during sign up. New users must confirm their email address before they can log in.
+- **Soft** - Send a confirmation email during sign up. New users can log in immediately, but must confirm their email in three days. Unconfirmed accounts are deleted.
+- **Off** - New users can sign up without confirming their email address.
+
## User cap
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4315) in GitLab 13.7.
@@ -95,22 +104,6 @@ New user sign ups are subject to the user cap restriction.
New users sign ups are not subject to the user cap restriction. Users in pending approval state are
automatically approved in a background job.
-## Soft email confirmation
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47003) in GitLab 12.2.
-> - It's [deployed behind a feature flag](../../../user/feature_flags.md), disabled by default.
-> - It's enabled on GitLab.com.
-> - It's recommended for production use.
-> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-soft-email-confirmation).
-
-WARNING:
-This feature might not be available to you. Check the **version history** note above for details.
-
-The soft email confirmation improves the sign-up experience for new users by allowing
-them to sign in without an immediate confirmation when an email confirmation is required.
-GitLab shows the user a reminder to confirm their email address, and the user can't
-create or update pipelines until their email address is confirmed.
-
## Minimum password length limit
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20661) in GitLab 12.6
@@ -171,25 +164,6 @@ semicolon, comma, or a new line.
![Domain Denylist](img/domain_denylist_v14_1.png)
-### Enable or disable soft email confirmation
-
-Soft email confirmation is under development but ready for production use.
-It is deployed behind a feature flag that is **disabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
-can opt to disable it.
-
-To enable it:
-
-```ruby
-Feature.enable(:soft_email_confirmation)
-```
-
-To disable it:
-
-```ruby
-Feature.disable(:soft_email_confirmation)
-```
-
## Set up LDAP user filter
You can limit GitLab access to a subset of the LDAP users on your LDAP server.
diff --git a/doc/user/admin_area/settings/third_party_offers.md b/doc/user/admin_area/settings/third_party_offers.md
index 4f6e727f673..6037b24a294 100644
--- a/doc/user/admin_area/settings/third_party_offers.md
+++ b/doc/user/admin_area/settings/third_party_offers.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
type: reference
---
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index acff483e4f8..cd0b461c26b 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -207,9 +207,6 @@ To enable the export of
You can enable migration of groups by direct transfer using the UI.
-To also migrate projects with the groups, you must enable the
-[`bulk_import_projects` feature flag](../../group/import/index.md#migrate-groups-by-direct-transfer-recommended).
-
To enable migration of groups by direct transfer:
1. Sign in to GitLab as a user with Administrator access level.
diff --git a/doc/user/analytics/ci_cd_analytics.md b/doc/user/analytics/ci_cd_analytics.md
index ef2d3a76990..4130ff6e036 100644
--- a/doc/user/analytics/ci_cd_analytics.md
+++ b/doc/user/analytics/ci_cd_analytics.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/analytics/dora_metrics.md b/doc/user/analytics/dora_metrics.md
index 9ac949f05b4..b85ec60f00e 100644
--- a/doc/user/analytics/dora_metrics.md
+++ b/doc/user/analytics/dora_metrics.md
@@ -29,7 +29,7 @@ For software leaders, tracking velocity alongside quality metrics ensures they'r
## DORA Metrics dashboard in Value Stream Analytics
-The four DORA metrics are available out-of-the-box in the [Value Stream Analytics (VSA) overview dashboard](../group/value_stream_analytics/index.md#view-dora-metrics-and-key-metrics-for-a-group).
+The four DORA metrics are available out-of-the-box in the [Value Stream Analytics (VSA) overview dashboard](../group/value_stream_analytics/index.md#view-value-stream-analytics).
This helps you visualize the engineering work in the context of end-to-end value delivery.
The One DevOps Platform [Value Stream Management](https://gitlab.com/gitlab-org/gitlab/-/value_stream_analytics) provides end-to-end visibility to the entire software delivery lifecycle.
@@ -37,76 +37,119 @@ This enables teams and managers to understand all aspects of productivity, quali
## Deployment frequency
-Deployment frequency is the frequency of successful deployments to production (hourly, daily, weekly, monthly, or yearly).
-This measures how often you deliver value to end users. A higher deployment frequency means you can
-get feedback sooner and iterate faster to deliver improvements and features. GitLab measures this as the number of
-deployments to a production environment in the given time period.
+Deployment frequency is the frequency of successful deployments to production over the given date range (hourly, daily, weekly, monthly, or yearly).
-Deployment frequency displays in several charts:
+Software leaders can use the deployment frequency metric to understand how often the team successfully deploys software to production, and how quickly the teams can respond to customers' requests or new market opportunities.
+High deployment frequency means you can get feedback sooner and iterate faster to deliver improvements and features.
-- [Group-level value stream analytics](../group/value_stream_analytics/index.md)
-- [Project-level value stream analytics](value_stream_analytics.md)
-- [CI/CD analytics](ci_cd_analytics.md)
+### How deployment frequency is calculated
-To retrieve metrics for deployment frequency, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
+In GitLab, Deployment frequency is measured by the average number of deployments per day to a given environment, based on the deployment's end time (its `finished_at` property).
+GitLab calculates the deployment frequency from the number of finished deployments on the given day.
+
+The calculation takes into account the production `environment tier` or the environments named `production/prod`. The environment must be part of the production deployment tier for its deployment information to appear on the graphs.
+
+### How to improve deployment frequency
+
+The first step is to benchmark the cadence of code releases between groups and projects. Next, you should consider:
+
+- Add more automated testing.
+- Add more automated code validation.
+- Break the changes down into smaller iterations.
## Lead time for changes
-DORA Lead time for changes measures the time to successfully deliver a commit into production.
-This metric reflects the efficiency of CI/CD pipelines.
+Lead time for changes is the amount of time it takes a code change to get into production.
+
+"Lead time for changes" is not the same as "Lead time". In the value stream, "Lead time" measures the time it takes for work on an issue to move from the moment it's requested (Issue created) to the moment it's fulfilled and delivered (Issue closed).
-In GitLab, Lead time for changes calculates the median time it takes for a merge request to get merged into production.
-We measure **from** code committed **to** code successfully running in production, without adding the `coding_time` to the calculation.
+For software leaders, Lead time for changes reflects the efficiency of CI/CD pipelines and visualizes how quickly work is delivered to customers.
+Over time, the lead time for changes should decrease, while your team's performance should increase. Low lead time for changes means more efficient CI/CD pipelines.
+In GitLab, Lead time for changes is measure by the `Median time it takes for a merge request to get merged into production (from master)`.
-Over time, the lead time for changes should decrease, while your team's performance should increase.
+### How lead time for changes is calculated
-Lead time for changes displays in several charts:
+GitLab calculates Lead time for changes base on the number of seconds to successfully deliver a commit into production - **from** code committed **to** code successfully running in production, without adding the `coding_time` to the calculation.
-- [Group-level value stream analytics](../group/value_stream_analytics/index.md)
-- [Project-level value stream analytics](value_stream_analytics.md)
-- [CI/CD analytics](ci_cd_analytics.md)
+### How to improve lead time for changes
-To retrieve metrics for lead time for changes, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
+The first step is to benchmark the CI/CD pipelines' efficiency between groups and projects. Next, you should consider:
-- The definition of lead time for change can vary widely, which often creates confusion within the industry.
-- "Lead time for changes" is not the same as "Lead time". In the value stream, "Lead time" measures the time it takes for work on an issue to move from the moment it's requested (Issue created) to the moment it's fulfilled and delivered (Issue closed).
+- Using Value Stream Analytics to identify bottlenecks in the processes.
+- Breaking the changes down into smaller iterations.
+- Adding more automation.
## Time to restore service
-Time to restore service measures how long it takes an organization to recover from a failure in production.
-GitLab measures this as the average time required to close the incidents
-in the given time period. This assumes:
+Time to restore service is the amount of time it takes an organization to recover from a failure in production.
+For software leaders, Time to restore service reflects how long it takes an organization to recover from a failure in production.
+Low Time to restore service means the organization can take risks with new innovative features to drive competitive advantages and increase business results.
+
+### How time to restore service is calculated
+
+In GitLab, Time to restore service is measured as the median time an incident was open for on a production environment.
+GitLab calculates the number of seconds an incident was open on a production environment in the given time period. This assumes:
+
+- [GitLab incidents](../../operations/incident_management/incidents.md) are tracked.
- All incidents are related to a production environment.
-- Incidents and deployments have a strictly one-to-one relationship. An incident is related to only
-one production deployment, and any production deployment is related to no more than one incident).
+- Incidents and deployments have a strictly one-to-one relationship. An incident is related to only one production deployment, and any production deployment is related to no more than one incident.
-Time to restore service displays in several charts:
+### How to improve time to restore service
-- [Group-level value stream analytics](../group/value_stream_analytics/index.md)
-- [Project-level value stream analytics](value_stream_analytics.md)
-- [CI/CD analytics](ci_cd_analytics.md)
+The first step is to benchmark the team response and recover from service interruptions and outages, between groups and projects. Next, you should consider:
-To retrieve metrics for time to restore service, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
+- Improving the observability into the production environment.
+- Improving response workflows.
## Change failure rate
-Change failure rate measures the percentage of deployments that cause a failure in production. GitLab measures this as the number
-of incidents divided by the number of deployments to a
-production environment in the given time period. This assumes:
+Change failure rate is how often a change cause failure in production.
+
+Software leaders can use the change failure rate metric to gain insights into the quality of the code being shipped.
+High change failure rate may indicate an inefficient deployment process or insufficient automated testing coverage.
+### How change failure rate is calculated
+
+In GitLab, Change failure rate is measured as the percentage of deployments that cause an incident in production in the given time period.
+GitLab calculates this by the number of incidents divided by the number of deployments to a production environment. This assumes:
+
+- [GitLab incidents](../../operations/incident_management/incidents.md) are tracked.
- All incidents are related to a production environment.
-- Incidents and deployments have a strictly one-to-one relationship. An incident is related to only
-one production deployment, and any production deployment is related to no
+- Incidents and deployments have a strictly one-to-one relationship. An incident is related to only one production deployment, and any production deployment is related to no
more than one incident.
-To retrieve metrics for change failure rate, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
+### How to improve change failure rate
+
+The first step is to benchmark the quality and stability, between groups and projects.
+
+To improve this metric, you should consider:
+
+- Finding the right balance between stability and throughput (Deployment frequency and Lead time for changes), and not sacrificing quality for speed.
+- Improving the efficacy of code review processes.
+- Adding more automated testing.
+
+## DORA metrics in GitLab
+
+The DORA metrics are displayed on the following charts:
+
+- [Value Streams Dashboard](value_streams_dashboard.md), which helps you identify trends, patterns, and opportunities for improvement.
+- [CI/CD analytics charts](ci_cd_analytics.md), which show pipeline success rates and duration, and the history of DORA metrics over time.
+- Value stream analytics for [groups](../group/value_stream_analytics/index.md) and [projects](value_stream_analytics.md), which provide metrics about each stage of your software development process
+- Insights reports for [groups](../group/insights/index.md) and [projects](value_stream_analytics.md), where you can also use [DORA query parameters](../../user/project/insights/index.md#dora-query-parameters) to create custom charts.
+
+The table below provides an overview of the DORA metrics' data aggregation in different charts.
-### Insights: Custom DORA reporting
+| Metric name | Measured values | Data aggregation in the [Value Streams Dashboard](value_streams_dashboard.md) | Data aggregation in CI/CD analytics charts | Data aggregation in Value stream analytics | Data aggregation in Custom insights reporting |
+|---------------------------|-------------------|-----------------------------------------------------|------------------------|-----------------------|----------|
+| Deployment frequency | Number of successful deployments | daily average per month | daily average | daily average | `day` (default) or `month` |
+| Lead time for changes | Number of seconds to successfully deliver a commit into production | daily median per month | median time | median time | `day` (default) or `month` |
+| Time to restore service | Number of seconds an incident was open for | daily median per month | daily median | median time | `day` (default) or `month` |
+| Change failure rate | percentage of deployments that cause an incident in production | daily median per month | percentage of failed deployments | percentage of failed deployments | `day` (default) or `month` |
-Custom charts to visualize DORA data with [Insights YAML-based reports](../../user/project/insights/index.md#dora-query-parameters).
+## Retrieve DORA metrics data
-With this new visualization, software leaders can track metrics improvements, understand patterns in their metrics trends, and compare performance between groups and projects.
+To retrieve DORA data, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
### Measure DORA metrics without using GitLab CI/CD pipelines
diff --git a/doc/user/analytics/value_stream_analytics.md b/doc/user/analytics/value_stream_analytics.md
index 093266e8aee..f22a6a483b8 100644
--- a/doc/user/analytics/value_stream_analytics.md
+++ b/doc/user/analytics/value_stream_analytics.md
@@ -198,8 +198,8 @@ example, milestones have been created and CI for testing and setting environment
Value stream analytics records the following times for each stage:
- **Issue**: 09:00 to 11:00: 2 hrs
-- **Plan**: 11:00 to 12:00: 1 hr
-- **Code**: 12:00 to 14:00: 2 hrs
+- **Plan**: 11:00 to 12:30: 1.5 hr
+- **Code**: 12:30 to 14:00: 1.5 hrs
- **Test**: 5 minutes
- **Review**: 14:00 to 19:00: 5 hrs
- **Staging**: 19:00 to 19:30: 30 minutes
diff --git a/doc/user/analytics/value_streams_dashboard.md b/doc/user/analytics/value_streams_dashboard.md
index f8cfb1bf06b..fd4cdd0d65f 100644
--- a/doc/user/analytics/value_streams_dashboard.md
+++ b/doc/user/analytics/value_streams_dashboard.md
@@ -4,20 +4,22 @@ 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
---
-# Value Streams Dashboard **(PREMIUM)**
+# Value Streams Dashboard **(ULTIMATE)**
-> Introduced in GitLab 15.8 as a Closed [Beta](../../policy/alpha-beta-support.md#beta-features) feature.
+> Introduced in GitLab 15.8 as a Closed [Beta](../../policy/alpha-beta-support.md#beta-features) feature [with a flag](../../administration/feature_flags.md) named `group_analytics_dashboards_page`. Disabled by default.
-You can leave feedback on dashboard bugs or functionality in [issue 381787](https://gitlab.com/gitlab-org/gitlab/-/issues/381787).
+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 `group_analytics_dashboards_page`.
+On GitLab.com, this feature is not available. This feature is not ready for production use.
-This feature is not ready for production use.
+You can leave feedback on dashboard bugs or functionality in [issue 381787](https://gitlab.com/gitlab-org/gitlab/-/issues/381787).
-The Value Streams Dashboard is a customizable dashboard to enable decision-makers to identify trends, patterns, and opportunities for digital transformation improvements.
+The Value Streams Dashboard is a customizable dashboard that enables decision-makers to identify trends, patterns, and opportunities for digital transformation improvements.
This page is a work in progress, and we're updating the information as we add more features.
For more information, see the [Value Stream Management category direction page](https://about.gitlab.com/direction/plan/value_stream_management/).
-After the feature flag is enabled, to open the new page, append this path `/analytics/dashboards` to the group URL
-(for example, `https://gitlab.com/groups/gitlab-org/-/analytics/dashboards`).
+After the feature flag is enabled, 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`).
## Initial use case
@@ -27,7 +29,7 @@ This comparison can help decision-makers understand whether projects and groups
The beta version of the Value Streams Dashboard includes the following metrics:
- [DORA metrics](dora_metrics.md)
-- [Value Stream Analytics (VSA) - flow metrics](value_stream_analytics.md)
+- [Value Stream Analytics (VSA) - flow metrics](../group/value_stream_analytics/index.md)
The Value Streams Dashboard allows you to:
@@ -49,7 +51,7 @@ that are the largest value contributors, overperforming, or underperforming.
You can also drill down the metrics for further analysis.
When you hover over a metric, a tooltip displays an explanation of the metric and a link to the related documentation page.
-## Customize the dashboard widgets
+## Customize the dashboard panels
You can customize the Value Streams Dashboard and configure what subgroups and projects to include in the page.
@@ -57,7 +59,7 @@ A view can display maximum four subgroups or projects.
To display multiple subgroups and projects, specify their path as a URL parameter.
-For example, the parameter `query=gitlab-org/gitlab-foss,gitlab-org/gitlab,gitlab-org/gitlab-design,gitlab-org/gitlab-docs` displays three separate widgets, one each for the:
+For example, the parameter `query=gitlab-org/gitlab-foss,gitlab-org/gitlab,gitlab-org/gitlab-design,gitlab-org/gitlab-docs` displays three separate panels, one each for the:
- `gitlab-org` group
- `gitlab-ui` project
diff --git a/doc/user/application_security/api_fuzzing/index.md b/doc/user/application_security/api_fuzzing/index.md
index b55c5a1b299..8ae6d8ee675 100644
--- a/doc/user/application_security/api_fuzzing/index.md
+++ b/doc/user/application_security/api_fuzzing/index.md
@@ -50,6 +50,7 @@ Example projects using these methods are available:
- [Example Postman Collection project](https://gitlab.com/gitlab-org/security-products/demos/api-fuzzing/postman-api-fuzzing-example)
- [Example GraphQL project](https://gitlab.com/gitlab-org/security-products/demos/api-fuzzing/graphql-api-fuzzing-example)
- [Example SOAP project](https://gitlab.com/gitlab-org/security-products/demos/api-fuzzing/soap-api-fuzzing-example)
+- [Authentication Token using Selenium](https://gitlab.com/gitlab-org/security-products/demos/api-fuzzing/auth-token-selenium)
## Enable Web API fuzzing
@@ -98,7 +99,7 @@ a YAML snippet that you can paste in your GitLab CI/CD configuration.
To generate an API Fuzzing configuration snippet:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > 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).
1. Select **Generate code snippet**.
@@ -330,6 +331,8 @@ This example is a minimal configuration for API Fuzzing. From here you can:
#### API Fuzzing with a GraphQL Schema file
+API Fuzzing can use a GraphQL schema file to understand and test a GraphQL endpoint that has introspection disabled. To use a GraphQL schema file, it must be in the introspection JSON format. A GraphQL schema can be converted to a the introspection JSON format using an online 3rd party tool: [https://transform.tools/graphql-to-introspection-json](https://transform.tools/graphql-to-introspection-json).
+
To configure API Fuzzing to use a GraphQl schema file that provides information about the target API to test:
1. [Include](../../../ci/yaml/index.md#includetemplate)
@@ -1994,7 +1997,7 @@ When configured correctly, a CI/CD pipeline contains a `fuzz` stage and an `apif
typical operation, the job always succeeds even if faults are identified during fuzz testing.
Faults are displayed on the **Security** pipeline tab with the suite name. When testing against the
-repositories default branch, the fuzzing faults are also shown on the Security & Compliance's
+repositories default branch, the fuzzing faults are also shown on the Security and Compliance's
Vulnerability Report page.
To prevent an excessive number of reported faults, the API fuzzing scanner limits the number of
@@ -2026,7 +2029,7 @@ Follow these steps to view details of a fuzzing fault:
1. You can view faults in a project, or a merge request:
- - In a project, go to the project's **Security & Compliance > Vulnerability Report**
+ - In a project, go to the project's **Security and Compliance > Vulnerability Report**
page. This page shows all vulnerabilities from the default branch only.
- In a merge request, go the merge request's **Security** section and select the **Expand**
button. API Fuzzing faults are available in a section labeled
@@ -2702,7 +2705,7 @@ You can expedite the investigation with the [testssl.sh tool](https://testssl.sh
To get support for your particular problem use the [getting help channels](https://about.gitlab.com/get-help/).
The [GitLab issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues) is the right place for bugs and feature proposals about API Security and API Fuzzing.
-Use `~"Category:API Security"` [label](../../../development/contributing/issue_workflow.md#labels) when opening a new issue regarding API fuzzing to ensure it is quickly reviewed by the right people. Refer to our [review response SLO](https://about.gitlab.com/handbook/engineering/workflow/code-review/#review-response-slo) to understand when you should receive a response.
+Use `~"Category:API Security"` [label](../../../development/labels/index.md) when opening a new issue regarding API fuzzing to ensure it is quickly reviewed by the right people. Refer to our [review response SLO](https://about.gitlab.com/handbook/engineering/workflow/code-review/#review-response-slo) to understand when you should receive a response.
[Search the issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues) for similar entries before submitting your own, there's a good chance somebody else had the same issue or feature proposal. Show your support with an award emoji and or join the discussion.
diff --git a/doc/user/application_security/api_security/api_discovery/index.md b/doc/user/application_security/api_security/api_discovery/index.md
new file mode 100644
index 00000000000..b77bed74c70
--- /dev/null
+++ b/doc/user/application_security/api_security/api_discovery/index.md
@@ -0,0 +1,169 @@
+---
+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
+type: reference, howto
+---
+
+# API Discovery **(ULTIMATE)**
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/9302) in GitLab 15.9. The API Discovery feature is in [Beta](../../../../policy/alpha-beta-support.md).
+
+API Discovery analyzes your application and produces an OpenAPI document describing the web APIs it exposes. This schema document can then be used by [DAST API](../../dast_api/index.md) or [API Fuzzing](../../api_fuzzing/index.md) to perform security scans of the web API.
+
+## Supported frameworks
+
+- [Java Spring-Boot](#java-spring-boot)
+
+## When does API Discovery run?
+
+API Discovery runs as a standalone job in your pipeline. The resulting OpenAPI document is captured as a job artifact so it can be used by other jobs in later stages.
+
+API Discovery runs in the `test` stage by default. The `test` stage was chosen as it typically executes before the stages used by other API Security features such as DAST API and API Fuzzing.
+
+## Example API Discovery configurations
+
+The following projects demonstrate API Discovery:
+
+- [Example Java Spring Boot v2 Pet Store](https://gitlab.com/gitlab-org/security-products/demos/api-discovery/java-spring-boot-v2-petstore)
+
+## Java Spring-Boot
+
+[Spring Boot](https://spring.io/projects/spring-boot) is a popular framework for creating stand-alone, production-grade Spring-based applications.
+
+### Supported Applications
+
+- Spring Boot: v2.X (>= 2.1)
+- Java: 11, 17 (LTS versions)
+- Executable JARs
+
+API Discovery supports Spring Boot major version 2, minor versions 1 and higher. Versions 2.0.X are not supported due to known bugs which affect API Discovery and were fixed in 2.1.
+
+Major version 3 is planned to be supported in the future. Support for major version 1 is not planned.
+
+API Discovery is tested with and officially supports LTS versions of the Java runtime. Other versions may work also, and bug reports from non-LTS versions are welcome.
+
+Only applications that are built as Spring Boot [executable JARs](https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html#appendix.executable-jar.nested-jars.jar-structure) are supported.
+
+### Configure as pipeline job
+
+The easiest way to run API Discovery is through a pipeline job based on our CI template.
+When running in this method, you provide a container image that has the required dependencies installed (such as an appropriate Java runtime). See [Image Requirements](#image-requirements) for more information.
+
+1. A container image that meets the [image requirements](#image-requirements) is uploaded to a container registry. If the container registry requires authentication see [this help section](/ee/ci/docker/using_docker_images.md#access-an-image-from-a-private-container-registry).
+1. In a job in the `build` stage, build your application and configure the resulting Spring Boot executable JAR as a job artifact.
+1. Include the API Discovery template in your `.gitlab-ci.yml` file.
+
+ ```yaml
+ include:
+ - template: Security/API-Discovery.gitlab-ci.yml
+ ```
+
+ Only a single `include` statement is allowed per `.gitlab-ci.yml` file. If you are including other files, combine them into a single `include` statement.
+
+ ```yaml
+ include:
+ - template: Security/API-Discovery.gitlab-ci.yml
+ - template: Security/DAST-API.gitlab-ci.yml
+ ```
+
+1. Create a new job that extends from `.api_discovery_java_spring_boot`. The default stage is `test` which can be optionally changed to any value.
+
+ ```yaml
+ api_discovery:
+ extends: .api_discovery_java_spring_boot
+ ```
+
+1. Configure the `image` for the job.
+
+ ```yaml
+ api_discovery:
+ extends: .api_discovery_java_spring_boot
+ image: openjdk:11-jre-slim
+ ```
+
+1. Provide the Java classpath needed by your application. This includes your compatible build artifact from step 2, along with any additional dependencies. For this example, the build artifact is `build/libs/spring-boot-app-0.0.0.jar` and contains all needed dependencies. The variable `API_DISCOVERY_JAVA_CLASSPATH` is used to provide the classpath.
+
+ ```yaml
+ api_discovery:
+ extends: .api_discovery_java_spring_boot
+ image: openjdk:11-jre-slim
+ variables:
+ API_DISCOVERY_JAVA_CLASSPATH: build/libs/spring-boot-app-0.0.0.jar
+ ```
+
+1. [Optional] If the image provided is missing a dependency needed by API Discovery, it can be added using a `before_script`. In this example, the `openjdk:11-jre-slim` container doesn't include `curl` which is required by API Discovery. The dependency can be installed using the Debian package manager `apt` as shown below.
+
+ ```yaml
+ api_discovery:
+ extends: .api_discovery_java_spring_boot
+ image: openjdk:11-jre-slim
+ variables:
+ API_DISCOVERY_JAVA_CLASSPATH: build/libs/spring-boot-app-0.0.0.jar
+ before_script:
+ - apt-get update && apt-get install -y curl
+ ```
+
+1. [Optional] If the image provided doesn't automatically set the `JAVA_HOME` environment variable, or include `java` in the path, the `API_DISCOVERY_JAVA_HOME` variable can be used.
+
+ ```yaml
+ api_discovery:
+ extends: .api_discovery_java_spring_boot
+ image: openjdk:11-jre-slim
+ variables:
+ API_DISCOVERY_JAVA_CLASSPATH: build/libs/spring-boot-app-0.0.0.jar
+ API_DISCOVERY_JAVA_HOME: /opt/java
+ ```
+
+1. [Optional] If the package registry at `API_DISCOVERY_PACKAGES` is not public, provide a token that has read access to the GitLab API and registry using the `API_DISCOVERY_PACKAGE_TOKEN` variable. This is not required if you are using `gitlab.com` and have not customized the `API_DISCOVERY_PACKAGES` variable. This example uses a [custom CI/CD variable](../../../../ci/variables/index.md#define-a-cicd-variable-in-the-ui) named `GITLAB_READ_TOKEN` to store the token.
+
+ ```yaml
+ api_discovery:
+ extends: .api_discovery_java_spring_boot
+ image: openjdk:8-jre-alpine
+ variables:
+ API_DISCOVERY_JAVA_CLASSPATH: build/libs/spring-boot-app-0.0.0.jar
+ API_DISCOVERY_PACKAGE_TOKEN: $GITLAB_READ_TOKEN
+ ```
+
+After the API Discovery job has successfully run, the OpenAPI document is available as a job artifact called `gl-api-discovery-openapi.json`.
+
+#### Image requirements
+
+- Linux container image.
+- Java versions 11 or 17 are officially supported, but other versions are likely compatible as well.
+- The `curl` command.
+- A shell at `/bin/sh` (like busybox sh or bash).
+
+### Available CI/CD variables
+
+| CI/CD variable | Description |
+|---------------------------------------------|--------------------|
+| `API_DISCOVERY_DISABLED` | Disables the API Discovery job when using template job rules. |
+| `API_DISCOVERY_DISABLED_FOR_DEFAULT_BRANCH` | Disables the API Discovery job for default branch pipelines when using template job rules. |
+| `API_DISCOVERY_JAVA_CLASSPATH` | Java class-path that includes target Spring Boot application. (`build/libs/sample-0.0.0.jar`) |
+| `API_DISCOVERY_JAVA_HOME` | If provided is used to set `JAVA_HOME`. |
+| `API_DISCOVERY_PACKAGES` | GitLab Project Package API Prefix (defaults to `$CI_API_V4_URL/projects/42503323/packages`). |
+| `API_DISCOVERY_PACKAGE_TOKEN` | GitLab token for calling the GitLab package API. Only needed when `API_DISCOVERY_PACKAGES` is set to a non-public project. |
+| `API_DISCOVERY_VERSION` | API Discovery version to use (defaults to `1`). Can be used to pin a version by providing the full version number `1.1.0`. |
+
+## Get support or request an improvement
+
+To get support for your particular problem, use the [getting help channels](https://about.gitlab.com/get-help/).
+
+The [GitLab issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues) is the right place for bugs and feature proposals about API Discovery.
+Use `~"Category:API Security"` [label](../../../../development/labels/index.md) when opening a new issue regarding API Discovery to ensure it is quickly reviewed by the right people. Refer to our [review response SLO](https://about.gitlab.com/handbook/engineering/workflow/code-review/#review-response-slo) to understand when you should receive a response.
+
+[Search the issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues) for similar entries before submitting your own, there's a good chance somebody else had the same issue or feature proposal. Show your support with an award emoji and or join the discussion.
+
+When experiencing a behavior not working as expected, consider providing contextual information:
+
+- GitLab version if using a self-managed instance.
+- `.gitlab-ci.yml` job definition.
+- Full job console output.
+- Framework in use with version (for example Spring Boot v2.3.2).
+- Language runtime with version (for example OpenJDK v17.0.1).
+<!-- - Scanner log file is available as a job artifact named `gl-api-discovery.log`. -->
+
+WARNING:
+**Sanitize data attached to a support issue**. Remove sensitive information, including: credentials, passwords, tokens, keys, and secrets.
diff --git a/doc/user/application_security/api_security/index.md b/doc/user/application_security/api_security/index.md
new file mode 100644
index 00000000000..5c2e74bceae
--- /dev/null
+++ b/doc/user/application_security/api_security/index.md
@@ -0,0 +1,21 @@
+---
+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
+type: reference, howto
+---
+
+# API Security **(ULTIMATE)**
+
+API Security refers to the measures taken to secure and protect web Application Programming Interfaces (APIs) from unauthorized access, misuse, and attacks.
+APIs are a crucial component of modern application development as they allow applications to interact with each other and exchange data.
+However, this also makes them attractive to attackers and vulnerable to security threats if not properly secured.
+In this section, we discuss GitLab features that can be used to ensure the security of web APIs in your application.
+Some of the features discussed are specific to web APIs and others are more general solutions that are also used with web API applications.
+
+- [SAST](../sast) identified vulnerabilities by analyzing the application's codebase.
+- [Dependency Scanning](../dependency_scanning) reviews a project 3rd party dependencies for known vulnerabilities (for example CVEs).
+- [Container Scanning](../container_scanning) analyzes container images to identify known OS package vulnerabilities and installed language dependencies.
+- [API Discovery](api_discovery) examines an application containing a REST API and intuits an OpenAPI specification for that API. OpenAPI specification documents are used by other GitLab security tools.
+- [DAST API](../dast_api) performs dynamic analysis security testing of web APIs. It can identify various security vulnerabilities in your application, including the OWASP Top 10.
+- [API Fuzzing](../api_fuzzing) performs fuzz testing of a web API. Fuzz testing looks for issues in an application that are not previously known and don't map to classic vulnerability types such as SQL Injection.
diff --git a/doc/user/application_security/configuration/index.md b/doc/user/application_security/configuration/index.md
index ea422f0b33c..380624c91ce 100644
--- a/doc/user/application_security/configuration/index.md
+++ b/doc/user/application_security/configuration/index.md
@@ -5,7 +5,7 @@ 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
---
-# Security Configuration **(FREE)**
+# Security configuration **(FREE)**
> - [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.
@@ -13,7 +13,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - 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.
-The Security Configuration page lists the following for the security testing and compliance tools:
+The **Security configuration** page lists the following for the security testing and compliance tools:
- Name, description, and a documentation link.
- Whether or not it is available.
@@ -41,7 +41,7 @@ all security features are configured by default.
To view a project's security configuration:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > Security configuration**.
Select **Configuration history** to see the `.gitlab-ci.yml` file's history.
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index 0a586a14cc4..a38f7bcb77c 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -15,6 +15,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86092) the major analyzer version from `4` to `5` in GitLab 15.0.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86783) from GitLab Ultimate to GitLab Free in 15.0.
> - Container Scanning variables that reference Docker [renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/357264) in GitLab 15.4.
+> - Container Scanning template [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/381665) from `Security/Container-Scanning.gitlab-ci.yml` to `Jobs/Container-Scanning.gitlab-ci.yml` in GitLab 15.6.
Your application's Docker image may itself be based on Docker images that contain known
vulnerabilities. By including an extra Container Scanning job in your pipeline that scans for those
@@ -90,12 +91,12 @@ To enable container scanning in your pipeline, you need the following:
## Configuration
To enable container scanning, add the
-[`Container-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml)
+[`Container-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml)
to your `.gitlab-ci.yml` file:
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
```
The included template:
@@ -117,7 +118,7 @@ registry, and scans the image:
```yaml
include:
- template: Jobs/Build.gitlab-ci.yml
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
@@ -142,7 +143,7 @@ enables verbose output for the analyzer:
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
variables:
SECURE_LOG_LEVEL: 'debug'
@@ -154,7 +155,7 @@ To scan images located in a registry other than the project's, use the following
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
@@ -178,7 +179,9 @@ container_scanning:
- export AWS_ECR_PASSWORD=$(aws ecr get-login-password --region region)
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
+
+variables:
CS_IMAGE: <aws_account_id>.dkr.ecr.<region>.amazonaws.com/<image>:<tag>
CS_REGISTRY_USER: AWS
CS_REGISTRY_PASSWORD: "$AWS_ECR_PASSWORD"
@@ -199,7 +202,7 @@ For example:
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
@@ -223,7 +226,7 @@ By default, the report only includes packages managed by the Operating System (O
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
@@ -326,7 +329,7 @@ To enable Container Scanning in a project, create a merge request from the Secur
page:
1. In the project where you want to enable Container Scanning, go to
- **Security & Compliance > Configuration**.
+ **Security and Compliance > Security configuration**.
1. In the **Container Scanning** row, select **Configure with a merge request**.
This automatically creates a merge request with the changes necessary to enable Container Scanning.
@@ -346,7 +349,7 @@ This example sets `GIT_STRATEGY` to `fetch`:
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
@@ -392,7 +395,7 @@ duplicated:
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
@@ -578,7 +581,7 @@ For details on saving and transporting Docker images as a file, see the Docker d
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
image: $CI_REGISTRY/namespace/container-scanning
@@ -629,7 +632,7 @@ This example shows the configuration needed to scan images in a private [Google
```yaml
include:
- - template: Jobs/Container-Scanning.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
diff --git a/doc/user/application_security/coverage_fuzzing/index.md b/doc/user/application_security/coverage_fuzzing/index.md
index 5d2593a1bed..4731e09474c 100644
--- a/doc/user/application_security/coverage_fuzzing/index.md
+++ b/doc/user/application_security/coverage_fuzzing/index.md
@@ -40,7 +40,7 @@ You can use the following fuzzing engines to test the specified languages.
| Language | Fuzzing Engine | Example |
|---------------------------------------------|------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| C/C++ | [libFuzzer](https://llvm.org/docs/LibFuzzer.html) | [c-cpp-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/c-cpp-fuzzing-example) |
-| GoLang | [go-fuzz (libFuzzer support)](https://github.com/dvyukov/go-fuzz) | [go-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example) |
+| Go | [go-fuzz (libFuzzer support)](https://github.com/dvyukov/go-fuzz) | [go-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example) |
| Swift | [libFuzzer](https://github.com/apple/swift/blob/master/docs/libFuzzerIntegration.md) | [swift-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/swift-fuzzing-example) |
| Rust | [cargo-fuzz (libFuzzer support)](https://github.com/rust-fuzz/cargo-fuzz) | [rust-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/rust-fuzzing-example) |
| Java | [Javafuzz](https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/javafuzz) (recommended) | [javafuzz-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/javafuzz-fuzzing-example) |
@@ -54,7 +54,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 top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > Security configuration**.
1. In the **Coverage Fuzzing** section the status is:
- **Not configured**
- **Enabled**
@@ -168,7 +168,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 top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > Security configuration**.
1. In the **Coverage Fuzzing** section, select **Manage corpus**.
### Create a corpus in the corpus registry
@@ -196,7 +196,7 @@ provided by the `COVFUZZ_CORPUS_NAME` variable. The corpus is updated on every p
To upload an existing corpus file:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > Security configuration**.
1. In the **Coverage Fuzzing** section, select **Manage corpus**.
1. Select **New corpus**.
1. Complete the fields.
diff --git a/doc/user/application_security/dast/authentication.md b/doc/user/application_security/dast/authentication.md
index 77732ab532c..03a273ffff9 100644
--- a/doc/user/application_security/dast/authentication.md
+++ b/doc/user/application_security/dast/authentication.md
@@ -45,34 +45,44 @@ To run a DAST authenticated scan:
### Prerequisites
+- You have the username and password of the user you would like to authenticate as during the scan.
+- You have checked the [known limitations](#known-limitations) to ensure DAST can authenticate to your application.
+- You have satisfied the prerequisites depending on whether you're using [form authentication](#form-authentication) or [HTTP authentication]((#http-authentication).
+- You have thought about how you can [verify](#verifying-authentication-is-successful) whether or not authentication was successful.
+
+#### Form authentication
+
- You are using either the [DAST proxy-based analyzer](proxy-based.md) or the [DAST browser-based analyzer](browser_based.md).
- You know the URL of the login form of your application. Alternatively, you know how to navigate to the login form from the authentication URL (see [clicking to navigate to the login form](#clicking-to-navigate-to-the-login-form)).
-- You have the username and password of the user you would like to authenticate as during the scan.
- You know the [selectors](#finding-an-elements-selector) of the username and password HTML fields that DAST uses to input the respective values.
- You know the element's [selector](#finding-an-elements-selector) that submits the login form when selected.
-- You have thought about how you can [verify](#verifying-authentication-is-successful) whether or not authentication was successful.
-- You have checked the [known limitations](#known-limitations) to ensure DAST can authenticate to your application.
+
+#### HTTP authentication
+
+- You must be using the [DAST browser-based analyzer](browser_based.md).
### Available CI/CD variables
| CI/CD variable | Type | Description |
|:-----------------------------------------------|:------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `DAST_AUTH_COOKIES` | string | Set to a comma-separated list of cookie names to specify which cookies are used for authentication. |
-| `DAST_AUTH_REPORT` | boolean | Used in combination with exporting the `gl-dast-debug-auth-report.html` artifact to aid in debugging authentication issues. |
+| `DAST_AUTH_REPORT` | boolean | Set to `true` to generate a report detailing steps taken during the authentication process. You must also define `gl-dast-debug-auth-report.html` as a CI job artifact to be able to access the generated report. Useful for debugging when authentication fails. |
+| `DAST_AUTH_TYPE` <sup>2</sup> | string | The authentication type to use. Example: `basic-digest`. |
| `DAST_AUTH_URL` <sup>1</sup> | URL | The URL of the page containing the sign-in HTML form on the target website. `DAST_USERNAME` and `DAST_PASSWORD` are submitted with the login form to create an authenticated scan. Example: `https://login.example.com`. |
| `DAST_AUTH_VERIFICATION_LOGIN_FORM` | boolean | Verifies successful authentication by checking for the absence of a login form once the login form has been submitted. |
| `DAST_AUTH_VERIFICATION_SELECTOR` | [selector](#finding-an-elements-selector) | Verifies successful authentication by checking for presence of a selector once the login form has been submitted. Example: `css:.user-photo`. |
| `DAST_AUTH_VERIFICATION_URL` <sup>1</sup> | URL | Verifies successful authentication by checking the URL in the browser once the login form has been submitted. Example: `"https://example.com/loggedin_page"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207335) in GitLab 13.8. |
| `DAST_BROWSER_PATH_TO_LOGIN_FORM` <sup>1</sup> | [selector](#finding-an-elements-selector) | Comma-separated list of selectors that are selected prior to attempting to enter `DAST_USERNAME` and `DAST_PASSWORD` into the login form. Example: `"css:.navigation-menu,css:.login-menu-item"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326633) in GitLab 14.1. |
| `DAST_EXCLUDE_URLS` <sup>1</sup> | URLs | The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. |
-| `DAST_FIRST_SUBMIT_FIELD` | string | The `id` or `name` of the element that when selected submits the username form of a multi-page login process. For example, `css:button[type='user-submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
+| `DAST_FIRST_SUBMIT_FIELD` | string | The `id` or `name` of the element that when selected submits the username form of a multi-page login process. For example, `css:button[type='user-submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9894) in GitLab 12.4. |
| `DAST_PASSWORD` <sup>1</sup> | string | The password to authenticate to in the website. Example: `P@55w0rd!` |
| `DAST_PASSWORD_FIELD` | string | The selector of password field at the sign-in HTML form. Example: `id:password` |
-| `DAST_SUBMIT_FIELD` | string | The `id` or `name` of the element that when selected submits the login form or the password form of a multi-page login process. For example, `css:button[type='submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
+| `DAST_SUBMIT_FIELD` | string | The `id` or `name` of the element that when selected submits the login form or the password form of a multi-page login process. For example, `css:button[type='submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9894) in GitLab 12.4. |
| `DAST_USERNAME` <sup>1</sup> | string | The username to authenticate to in the website. Example: `admin` |
| `DAST_USERNAME_FIELD` <sup>1</sup> | string | The selector of username field at the sign-in HTML form. Example: `name:username` |
1. Available to an on-demand proxy-based DAST scan.
+1. Not available to proxy-based scans.
### Update the target website
@@ -93,6 +103,28 @@ dast:
DAST_AUTH_URL: "https://example.com/login"
```
+### Configuration for HTTP authentication
+
+To use an [HTTP authentication scheme](https://www.chromium.org/developers/design-documents/http-authentication/) such as Basic Authentication you can set the `DAST_AUTH_TYPE` value to `basic-digest`.
+Other schemes such as Negotiate or NTLM may work but aren't officially supported due to current lack of automated test coverage.
+
+Configuration requires the CI/CD variables `DAST_AUTH_TYPE`, `DAST_AUTH_URL`, `DAST_USERNAME`, `DAST_PASSWORD` to be defined for the DAST job. If you don't have a unique login URL, please set `DAST_AUTH_URL` to the same URL as `DAST_WEBSITE`.
+
+```yaml
+include:
+ - template: DAST.gitlab-ci.yml
+
+dast:
+ variables:
+ DAST_WEBSITE: "https://example.com"
+ DAST_AUTH_TYPE: "basic-digest"
+ DAST_AUTH_URL: "https://example.com"
+```
+
+Do **not** define `DAST_USERNAME` and `DAST_PASSWORD` in the YAML job definition file as this could present a security risk. Instead, create them as masked CI/CD variables using the GitLab UI.
+See [Custom CI/CD variables](../../../ci/variables/index.md#for-a-project) for more information.
+The proxy-based analyzer does not support basic authentication as an authentication mechanism. A workaround could be to set `DAST_REQUEST_HEADERS` as a masked CI/CD variable with a value containing the appropriate `Authorization` header, for example, `Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQK`.
+
### Configuration for a single-step login form
A single-step login form has all login form elements on a single page.
@@ -114,7 +146,7 @@ dast:
```
Do **not** define `DAST_USERNAME` and `DAST_PASSWORD` in the YAML job definition file as this could present a security risk. Instead, create them as masked CI/CD variables using the GitLab UI.
-See [Custom CI/CI variables](../../../ci/variables/index.md#for-a-project) for more information.
+See [Custom CI/CD variables](../../../ci/variables/index.md#for-a-project) for more information.
### Configuration for a multi-step login form
@@ -140,7 +172,7 @@ dast:
```
Do **not** define `DAST_USERNAME` and `DAST_PASSWORD` in the YAML job definition file as this could present a security risk. Instead, create them as masked CI/CD variables using the GitLab UI.
-See [Custom CI/CI variables](../../../ci/variables/index.md#for-a-project) for more information.
+See [Custom CI/CD variables](../../../ci/variables/index.md#for-a-project) for more information.
### Configuration for Single Sign-On (SSO)
diff --git a/doc/user/application_security/dast/browser_based.md b/doc/user/application_security/dast/browser_based.md
index bdc08988cc0..88be88ad00e 100644
--- a/doc/user/application_security/dast/browser_based.md
+++ b/doc/user/application_security/dast/browser_based.md
@@ -42,10 +42,10 @@ To crawl a navigation path, DAST opens a browser window and instructs it to perf
When the browser has finished loading the result of the final action, DAST inspects the page for actions a user might take,
creates a new navigation for each found, and adds them to the navigation path to form new navigation paths. For example:
-- DAST processes navigation path `LoadURL[https://example.com]`.
-- DAST finds two user actions, `LeftClick[class=menu]` and `LeftClick[id=users]`.
-- DAST creates two new navigation paths, `LoadURL[https://example.com] -> LeftClick[class=menu]` and `LoadURL[https://example.com] -> LeftClick[id=users]`.
-- Crawling begins on the two new navigation paths.
+1. DAST processes navigation path `LoadURL[https://example.com]`.
+1. DAST finds two user actions, `LeftClick[class=menu]` and `LeftClick[id=users]`.
+1. DAST creates two new navigation paths, `LoadURL[https://example.com] -> LeftClick[class=menu]` and `LoadURL[https://example.com] -> LeftClick[id=users]`.
+1. Crawling begins on the two new navigation paths.
It's common for an HTML element to exist in multiple places in an application, such as a menu visible on every page.
Duplicate elements can cause crawlers to crawl the same pages again or become stuck in a loop.
@@ -170,13 +170,13 @@ For authentication CI/CD variables, see [Authentication](authentication.md).
| `DAST_ADVERTISE_SCAN` | boolean | `true` | Set to `true` to add a `Via` header to every request sent, advertising that the request was sent as part of a GitLab DAST scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334947) in GitLab 14.1. |
| `DAST_BROWSER_ACTION_STABILITY_TIMEOUT` | [Duration string](https://pkg.go.dev/time#ParseDuration) | `800ms` | The maximum amount of time to wait for a browser to consider a page loaded and ready for analysis after completing an action. |
| `DAST_BROWSER_ACTION_TIMEOUT` | [Duration string](https://pkg.go.dev/time#ParseDuration) | `7s` | The maximum amount of time to wait for a browser to complete an action. |
-| `DAST_BROWSER_ALLOWED_HOSTS` | List of strings | `site.com,another.com` | Hostnames included in this variable are considered in scope when crawled. By default the `DAST_WEBSITE` hostname is included in the allowed hosts list. Headers set using `DAST_REQUEST_HEADERS` are added to every request made to these hostnames. |
+| `DAST_BROWSER_ALLOWED_HOSTS` | List of strings | `site.com,another.com` | Hostnames included in this variable are considered in scope when crawled. By default the `DAST_WEBSITE` hostname is included in the allowed hosts list. Headers set using `DAST_REQUEST_HEADERS` are added to every request made to these hostnames. |
| `DAST_BROWSER_COOKIES` | dictionary | `abtesting_group:3,region:locked` | A cookie name and value to be added to every request. |
-| `DAST_BROWSER_CRAWL_GRAPH` | boolean | `true` | Set to `true` to generate an SVG graph of navigation paths visited during crawl phase of the scan. |
+| `DAST_BROWSER_CRAWL_GRAPH` | boolean | `true` | Set to `true` to generate an SVG graph of navigation paths visited during crawl phase of the scan. You must also define `gl-dast-crawl-graph.svg` as a CI job artifact to be able to access the generated graph. |
| `DAST_BROWSER_DEVTOOLS_LOG` | string | `Default:messageAndBody,truncate:2000` | Set to log protocol messages between DAST and the Chromium browser. | |
| `DAST_BROWSER_ELEMENT_TIMEOUT` | [Duration string](https://pkg.go.dev/time#ParseDuration) | `600ms` | The maximum amount of time to wait for an element before determining it is ready for analysis. |
| `DAST_BROWSER_EXCLUDED_ELEMENTS` | selector | `a[href='2.html'],css:.no-follow` | Comma-separated list of selectors that are ignored when scanning. |
-| `DAST_BROWSER_EXCLUDED_HOSTS` | List of strings | `site.com,another.com` | Hostnames included in this variable are considered excluded and connections are forcibly dropped. |
+| `DAST_BROWSER_EXCLUDED_HOSTS` | List of strings | `site.com,another.com` | Hostnames included in this variable are considered excluded and connections are forcibly dropped. |
| `DAST_BROWSER_EXTRACT_ELEMENT_TIMEOUT` | [Duration string](https://pkg.go.dev/time#ParseDuration) | `5s` | The maximum amount of time to allow the browser to extract newly found elements or navigations. |
| `DAST_BROWSER_FILE_LOG` | List of strings | `brows:debug,auth:debug` | A list of modules and their intended logging level for use in the file log. |
| `DAST_BROWSER_FILE_LOG_PATH` | string | `/output/browserker.log` | Set to the path of the file log. |
@@ -190,8 +190,8 @@ For authentication CI/CD variables, see [Authentication](authentication.md).
| `DAST_BROWSER_NAVIGATION_STABILITY_TIMEOUT` | [Duration string](https://pkg.go.dev/time#ParseDuration) | `7s` | The maximum amount of time to wait for a browser to consider a page loaded and ready for analysis after a navigation completes. |
| `DAST_BROWSER_NAVIGATION_TIMEOUT` | [Duration string](https://pkg.go.dev/time#ParseDuration) | `15s` | The maximum amount of time to wait for a browser to navigate from one page to another. |
| `DAST_BROWSER_NUMBER_OF_BROWSERS` | number | `3` | The maximum number of concurrent browser instances to use. For shared runners on GitLab.com, we recommended a maximum of three. Private runners with more resources may benefit from a higher number, but are likely to produce little benefit after five to seven instances. |
-| `DAST_BROWSER_PAGE_LOADING_SELECTOR` | selector | `css:#page-is-loading` | Selector that when is no longer visible on the page, indicates to the analyzer that the page has finished loading and the scan can continue. Cannot be used with `DAST_BROWSER_PAGE_READY_SELECTOR` |
-| `DAST_BROWSER_PAGE_READY_SELECTOR` | selector | `css:#page-is-ready` | Selector that when detected as visible on the page, indicates to the analyzer that the page has finished loading and the scan can continue. Cannot be used with `DAST_BROWSER_PAGE_LOADING_SELECTOR` |
+| `DAST_BROWSER_PAGE_LOADING_SELECTOR` | selector | `css:#page-is-loading` | Selector that when is no longer visible on the page, indicates to the analyzer that the page has finished loading and the scan can continue. Cannot be used with `DAST_BROWSER_PAGE_READY_SELECTOR`. |
+| `DAST_BROWSER_PAGE_READY_SELECTOR` | selector | `css:#page-is-ready` | Selector that when detected as visible on the page, indicates to the analyzer that the page has finished loading and the scan can continue. Cannot be used with `DAST_BROWSER_PAGE_LOADING_SELECTOR`. |
| `DAST_BROWSER_SCAN` | boolean | `true` | Required to be `true` to run a browser-based scan. |
| `DAST_BROWSER_SEARCH_ELEMENT_TIMEOUT` | [Duration string](https://pkg.go.dev/time#ParseDuration) | `3s` | The maximum amount of time to allow the browser to search for new elements or user actions. |
| `DAST_BROWSER_STABILITY_TIMEOUT` | [Duration string](https://pkg.go.dev/time#ParseDuration) | `7s` | The maximum amount of time to wait for a browser to consider a page loaded and ready for analysis. |
@@ -201,8 +201,8 @@ For authentication CI/CD variables, see [Authentication](authentication.md).
| `DAST_PATHS` | string | `/page1.html,/category1/page3.html` | Set to a comma-separated list of URL paths relative to `DAST_WEBSITE` for DAST to scan. |
| `DAST_PATHS_FILE` | string | `/builds/project/urls.txt` | Set to a file path containing a list of URL paths relative to `DAST_WEBSITE` for DAST to scan. The file must be plain text with one path per line. |
| `DAST_PKCS12_CERTIFICATE_BASE64` | string | `ZGZkZ2p5NGd...` | The PKCS12 certificate used for sites that require Mutual TLS. Must be encoded as base64 text. |
-| `DAST_PKCS12_PASSWORD` | string | `password` | The password of the certificate used in `DAST_PKCS12_CERTIFICATE_BASE64`. Create sensitive [custom CI/CI variables](../../../ci/variables/index.md#define-a-cicd-variable-in-the-ui) using the GitLab UI. |
-| `DAST_REQUEST_HEADERS` | string | `Cache-control:no-cache` | Set to a comma-separated list of request header names and values. |
+| `DAST_PKCS12_PASSWORD` | string | `password` | The password of the certificate used in `DAST_PKCS12_CERTIFICATE_BASE64`. Create sensitive [custom CI/CI variables](../../../ci/variables/index.md#define-a-cicd-variable-in-the-ui) using the GitLab UI. |
+| `DAST_REQUEST_HEADERS` | string | `Cache-control:no-cache` | Set to a comma-separated list of request header names and values. |
| `DAST_SKIP_TARGET_CHECK` | boolean | `true` | Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`. |
| `DAST_TARGET_AVAILABILITY_TIMEOUT` | number | `60` | Time limit in seconds to wait for target availability. |
| `DAST_WEBSITE` | URL | `https://example.com` | The URL of the website to scan. |
@@ -275,16 +275,6 @@ dast:
NOTE:
Adjusting these values may impact scan time because they adjust how long each browser waits for various activities to complete.
-## Artifacts
-
-Using the latest version of the DAST [template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST.latest.gitlab-ci.yml) these artifacts are exposed for download by default.
-
-The list of artifacts includes the following files:
-
-- `gl-dast-debug-auth-report.html`
-- `gl-dast-debug-crawl-report.html`
-- `gl-dast-crawl-graph.svg`
-
## Troubleshooting
See [troubleshooting](browser_based_troubleshooting.md) for more information.
diff --git a/doc/user/application_security/dast/proxy-based.md b/doc/user/application_security/dast/proxy-based.md
index f70afac4c26..ae2d04ae4bb 100644
--- a/doc/user/application_security/dast/proxy-based.md
+++ b/doc/user/application_security/dast/proxy-based.md
@@ -80,10 +80,10 @@ To enable DAST to run automatically, either:
- Enable [Auto DAST](../../../topics/autodevops/stages.md#auto-dast) (provided
by [Auto DevOps](../../../topics/autodevops/index.md)).
-- [Edit the `.gitlab.ci.yml` file manually](#edit-the-gitlabciyml-file-manually).
-- [Use an automatically configured merge request](#configure-dast-using-the-ui).
+- [Edit the `.gitlab.ci.yml` file manually](#edit-the-gitlab-ciyml-file-manually).
+- [Configure DAST using the UI](#configure-dast-using-the-ui).
-#### Edit the `.gitlab.ci.yml` file manually
+#### Edit the `.gitlab-ci.yml` file manually
In this method you manually edit the existing `.gitlab-ci.yml` file. Use this method if your GitLab CI/CD configuration file is complex.
diff --git a/doc/user/application_security/dast_api/index.md b/doc/user/application_security/dast_api/index.md
index 0cdbb879cfc..49d5859be45 100644
--- a/doc/user/application_security/dast_api/index.md
+++ b/doc/user/application_security/dast_api/index.md
@@ -48,6 +48,7 @@ The following projects demonstrate DAST API scanning:
- [Example Postman Collection project](https://gitlab.com/gitlab-org/security-products/demos/api-dast/postman-example)
- [Example GraphQL project](https://gitlab.com/gitlab-org/security-products/demos/api-dast/graphql-example)
- [Example SOAP project](https://gitlab.com/gitlab-org/security-products/demos/api-dast/soap-example)
+- [Authentication Token using Selenium](https://gitlab.com/gitlab-org/security-products/demos/api-dast/auth-token-selenium)
## Targeting API for DAST scanning
@@ -97,8 +98,6 @@ The environment variables `DAST_API_OPENAPI_ALL_MEDIA_TYPES` and `DAST_API_OPENA
#### Configure DAST API with an OpenAPI Specification
-To configure DAST API scanning with an OpenAPI specification:
-
To configure DAST API scanning with an OpenAPI Specification:
1. [Include](../../../ci/yaml/index.md#includetemplate)
@@ -264,6 +263,8 @@ This example is a minimal configuration for DAST API. From here you can:
#### DAST API scanning with a GraphQL Schema file
+DAST API can use a GraphQL schema file to understand and test a GraphQL endpoint that has introspection disabled. To use a GraphQL schema file, it must be in the introspection JSON format. A GraphQL schema can be converted to a the introspection JSON format using an online 3rd party tool: [https://transform.tools/graphql-to-introspection-json](https://transform.tools/graphql-to-introspection-json).
+
To configure DAST API to use a GraphQL schema file that provides information about the target API to test:
1. [Include](../../../ci/yaml/index.md#includetemplate)
@@ -1924,7 +1925,7 @@ variables:
When configured correctly, a CI/CD pipeline contains a `dast` stage and an `dast_api` job. The job only fails when an invalid configuration is provided. During typical operation, the job always succeeds even if vulnerabilities are identified during testing.
-Vulnerabilities are displayed on the **Security** pipeline tab with the suite name. When testing against the repositories default branch, the DAST API vulnerabilities are also shown on the Security & Compliance's Vulnerability Report page.
+Vulnerabilities are displayed on the **Security** pipeline tab with the suite name. When testing against the repositories default branch, the DAST API vulnerabilities are also shown on the Security and Compliance's Vulnerability Report page.
To prevent an excessive number of reported vulnerabilities, the DAST API scanner limits the number of vulnerabilities it reports per operation.
@@ -1941,7 +1942,7 @@ Follow these steps to view details of a vulnerability:
1. You can view vulnerabilities in a project, or a merge request:
- - In a project, go to the project's **Security & Compliance > Vulnerability Report**
+ - In a project, go to the project's **Security and Compliance > Vulnerability Report**
page. This page shows all vulnerabilities from the default branch only.
- In a merge request, go the merge request's **Security** section and select the **Expand**
button. DAST API vulnerabilities are available in a section labeled
@@ -2558,7 +2559,7 @@ You can expedite the investigation with the [testssl.sh tool](https://testssl.sh
To get support for your particular problem, use the [getting help channels](https://about.gitlab.com/get-help/).
The [GitLab issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues) is the right place for bugs and feature proposals about API Security and DAST API.
-Use `~"Category:API Security"` [label](../../../development/contributing/issue_workflow.md#labels) when opening a new issue regarding DAST API to ensure it is quickly reviewed by the right people. Refer to our [review response SLO](https://about.gitlab.com/handbook/engineering/workflow/code-review/#review-response-slo) to understand when you should receive a response.
+Use `~"Category:API Security"` [label](../../../development/labels/index.md) when opening a new issue regarding DAST API to ensure it is quickly reviewed by the right people. Refer to our [review response SLO](https://about.gitlab.com/handbook/engineering/workflow/code-review/#review-response-slo) to understand when you should receive a response.
[Search the issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues) for similar entries before submitting your own, there's a good chance somebody else had the same issue or feature proposal. Show your support with an award emoji and or join the discussion.
diff --git a/doc/user/application_security/dependency_list/index.md b/doc/user/application_security/dependency_list/index.md
index b86d98471ac..f46c5e5e801 100644
--- a/doc/user/application_security/dependency_list/index.md
+++ b/doc/user/application_security/dependency_list/index.md
@@ -13,7 +13,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Use the dependency list to review your project'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.
-To see the dependency list, go to your project and select **Security & Compliance > Dependency list**.
+To see the dependency list, go to your project and select **Security and Compliance > Dependency list**.
This information is sometimes referred to as a Software Bill of Materials, SBOM, or BOM.
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 579dd4dfc4f..7641c39d6d6 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -187,17 +187,17 @@ table.supported-languages ul {
<td>Y</td>
</tr>
<tr>
- <td rowspan="2">Java</td>
+ <td rowspan="2">Java and Kotlin (not Android)<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-1">1</a></b></sup></td>
<td rowspan="2">
8 LTS,
11 LTS,
- 13<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-1">1</a></b></sup>,
- 14<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-1">1</a></b></sup>,
- 15<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-1">1</a></b></sup>,
- 16<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-1">1</a></b></sup>,
+ 13<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-2">2</a></b></sup>,
+ 14<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-2">2</a></b></sup>,
+ 15<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-2">2</a></b></sup>,
+ 16<sup><b><a href="#notes-regarding-supported-languages-and-package-managers-2">2</a></b></sup>,
or 17 LTS
</td>
- <td><a href="https://gradle.org/">Gradle</a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-2">2</a></b></sup></td>
+ <td><a href="https://gradle.org/">Gradle</a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-3">3</a></b></sup></td>
<td>
<ul>
<li><code>build.gradle</code></li>
@@ -295,15 +295,19 @@ table.supported-languages ul {
<li>
<a id="notes-regarding-supported-languages-and-package-managers-1"></a>
<p>
- Support for these versions of Java is deprecated and is planned to be removed in the GitLab 16.0 release. Additionally, these versions of Java are not supported by the FIPS-enabled image of <code>gemnasium-maven</code>. Official support is limited to LTS versions only. Although it may be possible to use Dependency Scanning with other versions by building a custom dependency scanning image, this approach is not officially supported by GitLab.
+ Support for Kotlin projects for Android is tracked in <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/336866">issue 336866</a>.
</p>
</li>
<li>
<a id="notes-regarding-supported-languages-and-package-managers-2"></a>
<p>
- Although Gradle with Java 8 is supported, there are other issues such that Android project builds are not supported at this time.
- See the backlog issue <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/336866">Android support for Dependency
- Scanning (gemnasium-maven)</a> for more details. Also, Gradle is not supported when <a href="https://docs.gitlab.com/ee/development/fips_compliance.html#enable-fips-mode">FIPS mode</a> is enabled.
+ Support for these versions of Java is deprecated and is planned to be removed in the GitLab 16.0 release. Additionally, these versions of Java are not supported by the FIPS-enabled image of <code>gemnasium-maven</code>. Official support is limited to LTS versions only. Although it may be possible to use Dependency Scanning with other versions by building a custom dependency scanning image, this approach is not officially supported by GitLab.
+ </p>
+ </li>
+ <li>
+ <a id="notes-regarding-supported-languages-and-package-managers-3"></a>
+ <p>
+ Gradle is not supported when <a href="https://docs.gitlab.com/ee/development/fips_compliance.html#enable-fips-mode">FIPS mode</a> is enabled.
</p>
</li>
<li>
@@ -553,7 +557,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 top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > 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.
@@ -626,6 +630,7 @@ The following variables allow configuration of global dependency scanning settin
| `DS_EXCLUDED_ANALYZERS` | Specify the analyzers (by name) to exclude from Dependency Scanning. For more information, see [Dependency Scanning Analyzers](analyzers.md). |
| `DS_EXCLUDED_PATHS` | Exclude files and directories from the scan based on the paths. A comma-separated list of patterns. Patterns can be globs (see [`doublestar.Match`](https://pkg.go.dev/github.com/bmatcuk/doublestar/v4@v4.0.2#Match) for supported patterns), or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"`. |
| `DS_IMAGE_SUFFIX` | Suffix added to the image name. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354796) in GitLab 14.10.) Automatically set to `"-fips"` when FIPS mode is enabled. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357922) in GitLab 15.0.) |
+| `DS_MAX_DEPTH` | Defines how many directory levels deep that the analyzer should search for supported files to scan. A value of `-1` scans all directories regardless of depth. Default: `2`. |
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `SECURE_LOG_LEVEL` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info`, `debug`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1. Default: `info`. |
@@ -926,10 +931,30 @@ include:
merge cyclonedx sboms:
stage: merge-cyclonedx-sboms
image:
- name: cyclonedx/cyclonedx-cli:0.24.0
+ name: cyclonedx/cyclonedx-cli:0.24.2
entrypoint: [""]
script:
- - find . -name "gl-sbom-*.cdx.json" -exec /cyclonedx merge --output-file gl-sbom-all.cdx.json --input-files "{}" +
+ - apt-get update && apt-get install -y jq
+ - find . -name "gl-sbom-*.cdx.json" -exec cyclonedx merge --output-file gl-sbom-all.cdx.json --input-files "{}" +
+ # remove duplicates from merged file. See https://github.com/CycloneDX/cyclonedx-cli/issues/188 for details.
+ - |
+ jq '. |
+ {
+ "bomFormat": .bomFormat,
+ "specVersion": .specVersion,
+ "serialNumber": .serialNumber,
+ "version": .version,
+ "metadata": {
+ "tools": [
+ (.metadata.tools | unique[])
+ ]
+ },
+ "components": [
+ (.components | unique[])
+ ]
+ }' "gl-sbom-all.cdx.json" > gl-sbom-all.cdx.json.tmp && mv gl-sbom-all.cdx.json.tmp gl-sbom-all.cdx.json
+ # optional: validate the merged sbom
+ - cyclonedx validate --input-version v1_4 --input-file gl-sbom-all.cdx.json
artifacts:
paths:
- gl-sbom-all.cdx.json
diff --git a/doc/user/application_security/iac_scanning/index.md b/doc/user/application_security/iac_scanning/index.md
index c2f1257f989..937aaf76280 100644
--- a/doc/user/application_security/iac_scanning/index.md
+++ b/doc/user/application_security/iac_scanning/index.md
@@ -119,7 +119,7 @@ that you can download and analyze.
To enable IaC Scanning in a project, you can create a merge request:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > 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.
@@ -243,7 +243,8 @@ kics-iac-sast:
## Automatic vulnerability resolution
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368284) in GitLab 15.9 [with a project-level flag](../../../administration/feature_flags.md) named `sec_mark_dropped_findings_as_resolved`. Enabled by default on GitLab.com; disabled by default in self-managed. On GitLab.com, [contact Support](https://about.gitlab.com/support/) if you need to disable the flag for your project.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368284) in GitLab 15.9 [with a project-level flag](../../../administration/feature_flags.md) named `sec_mark_dropped_findings_as_resolved`.
+> - Enabled by default in 15.10. On GitLab.com, [contact Support](https://about.gitlab.com/support/) if you need to disable the flag for your project.
To help you focus on the vulnerabilities that are still relevant, GitLab IaC Scanning automatically [resolves](../vulnerabilities/index.md#vulnerability-status-values) vulnerabilities when:
diff --git a/doc/user/application_security/policies/img/association_diagram.png b/doc/user/application_security/policies/img/association_diagram.png
index d082e297c68..3a56aeba91b 100644
--- a/doc/user/application_security/policies/img/association_diagram.png
+++ b/doc/user/application_security/policies/img/association_diagram.png
Binary files differ
diff --git a/doc/user/application_security/policies/img/policy_rule_mode_v14_9.png b/doc/user/application_security/policies/img/policy_rule_mode_v14_9.png
deleted file mode 100644
index 8ca7547a33c..00000000000
--- a/doc/user/application_security/policies/img/policy_rule_mode_v14_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/policies/img/policy_rule_mode_v15_9.png b/doc/user/application_security/policies/img/policy_rule_mode_v15_9.png
new file mode 100644
index 00000000000..8cb2e82ac05
--- /dev/null
+++ b/doc/user/application_security/policies/img/policy_rule_mode_v15_9.png
Binary files differ
diff --git a/doc/user/application_security/policies/img/policy_yaml_mode_v14_9.png b/doc/user/application_security/policies/img/policy_yaml_mode_v14_9.png
deleted file mode 100644
index 1d71e8684e9..00000000000
--- a/doc/user/application_security/policies/img/policy_yaml_mode_v14_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/policies/img/policy_yaml_mode_v15_9.png b/doc/user/application_security/policies/img/policy_yaml_mode_v15_9.png
new file mode 100644
index 00000000000..95b637efef3
--- /dev/null
+++ b/doc/user/application_security/policies/img/policy_yaml_mode_v15_9.png
Binary files differ
diff --git a/doc/user/application_security/policies/img/scan_execution_policy_rule_mode_v15_5.png b/doc/user/application_security/policies/img/scan_execution_policy_rule_mode_v15_5.png
deleted file mode 100644
index 5ae7c2e065a..00000000000
--- a/doc/user/application_security/policies/img/scan_execution_policy_rule_mode_v15_5.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/policies/img/scan_execution_policy_rule_mode_v15_9.png b/doc/user/application_security/policies/img/scan_execution_policy_rule_mode_v15_9.png
new file mode 100644
index 00000000000..57e729158da
--- /dev/null
+++ b/doc/user/application_security/policies/img/scan_execution_policy_rule_mode_v15_9.png
Binary files differ
diff --git a/doc/user/application_security/policies/img/scheduled_scan_execution_policies_diagram.png b/doc/user/application_security/policies/img/scheduled_scan_execution_policies_diagram.png
new file mode 100644
index 00000000000..fcf7a8352fd
--- /dev/null
+++ b/doc/user/application_security/policies/img/scheduled_scan_execution_policies_diagram.png
Binary files differ
diff --git a/doc/user/application_security/policies/index.md b/doc/user/application_security/policies/index.md
index a214d0d2cec..1f53b671ed1 100644
--- a/doc/user/application_security/policies/index.md
+++ b/doc/user/application_security/policies/index.md
@@ -13,7 +13,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Policies in GitLab provide security teams a way to require scans of their choice to be run
whenever a project pipeline runs according to the configuration specified. Security teams can
therefore be confident that the scans they set up have not been changed, altered, or disabled. You
-can access these by navigating to your project's **Security & Compliance > Policies** page.
+can access these by navigating to your project's **Security and Compliance > Policies** page.
GitLab supports the following security policies:
@@ -23,8 +23,8 @@ GitLab supports the following security policies:
## Security policy project
All security policies are stored as YAML in a separate security policy project that gets linked to
-the development project. This association can be a one-to-many relationship, allowing one security
-policy project to apply to multiple development projects. Linked projects are not required to be in
+the development project, group, or sub-group. This association can be a one-to-many relationship, allowing one security
+policy project to apply to multiple development projects, groups, or sub-groups. Linked projects are not required to be in
the same group as the development projects to which they are linked.
![Security Policy Project Linking Diagram](img/association_diagram.png)
@@ -59,7 +59,7 @@ As a project owner, take the following steps to create or edit an association be
project and a project that you would like to designate as the security policy project:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Policies**.
+1. On the left sidebar, select **Security and Compliance > Policies**.
1. Select **Edit Policy Project**, and search for and select the
project you would like to link from the dropdown list.
1. Select **Save**.
@@ -83,7 +83,7 @@ policy's information (for example, description or enforcement
status), and create and edit deployed policies:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Policies**.
+1. On the left sidebar, select **Security and Compliance > Policies**.
![Policies List Page](img/policies_list_v15_1.png)
@@ -94,7 +94,7 @@ status), and create and edit deployed policies:
You can use the policy editor to create, edit, and delete policies:
1. On the top bar, select **Main menu > Projects** and find your group.
-1. On the left sidebar, select **Security & Compliance > Policies**.
+1. On the left sidebar, select **Security and Compliance > 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.
- To edit an existing policy, select **Edit policy** in the selected policy drawer.
@@ -104,13 +104,13 @@ The policy editor has two modes:
- The visual _Rule_ mode allows you to construct and preview policy
rules using rule blocks and related controls.
- ![Policy Editor Rule Mode](img/policy_rule_mode_v14_9.png)
+ ![Policy Editor Rule Mode](img/policy_rule_mode_v15_9.png)
- YAML mode allows you to enter a policy definition in `.yaml` format
and is aimed at expert users and cases that the Rule mode doesn't
support.
- ![Policy Editor YAML Mode](img/policy_yaml_mode_v14_9.png)
+ ![Policy Editor YAML Mode](img/policy_yaml_mode_v15_9.png)
You can use both modes interchangeably and switch between them at any
time. If a YAML resource is incorrect or contains data not supported
@@ -129,19 +129,6 @@ time that the first policy merge request is created.
You can use the [Vulnerability-Check Migration](https://gitlab.com/gitlab-org/gitlab/-/snippets/2328089) script to bulk create policies or associate security policy projects with development projects. For instructions and a demonstration of how to use the Vulnerability-Check Migration script, see [this video](https://youtu.be/biU1N26DfBc).
-## Scan execution policies
-
-See [Scan execution policies](scan-execution-policies.md).
-
-## Scan result policy editor
-
-See [Scan result policies](scan-result-policies.md).
-
-## Roadmap
-
-See the [Category Direction page](https://about.gitlab.com/direction/govern/security_policies/security_policy_management/)
-for more information on the product direction of security policies within GitLab.
-
## Troubleshooting
### `Branch name 'update-policy-<timestamp>' does not follow the pattern '<branch_name_regex>'`
diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md
index 26c7e1d9c77..96048bb2308 100644
--- a/doc/user/application_security/policies/scan-execution-policies.md
+++ b/doc/user/application_security/policies/scan-execution-policies.md
@@ -33,7 +33,7 @@ NOTE:
Only group, subgroup, or project Owners have the [permissions](../../permissions.md#project-members-permissions)
to select Security Policy Project.
-Once your policy is complete, save it by selecting **Create via merge request**
+Once your policy is complete, save it by selecting **Configure with a merge request**
at the bottom of the editor. You are redirected to the merge request on the project's
configured security policy project. If one does not link to your project, a security
policy project is automatically created. Existing policies can also be
@@ -44,7 +44,7 @@ Most policy changes take effect as soon as the merge request is merged. Any chan
do not go through a merge request and are committed directly to the default branch may require up to 10 minutes
before the policy changes take effect.
-![Scan Execution Policy Editor Rule Mode](img/scan_execution_policy_rule_mode_v15_5.png)
+![Scan Execution Policy Editor Rule Mode](img/scan_execution_policy_rule_mode_v15_9.png)
## Scan execution policies schema
@@ -88,7 +88,7 @@ This rule enforces the defined actions and schedules a scan on the provided date
|------------|------|-----------------|-------------|
| `type` | `string` | `schedule` | The rule's type. |
| `branches` | `array` of `string` | `*` or the branch's name | The branch the given policy applies to (supports wildcard). This field is required if the `agents` field is not set. |
-| `cadence` | `string` | CRON expression (for example, `0 0 * * *`) | A whitespace-separated string containing five fields that represents the scheduled time. |
+| `cadence` | `string` | 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. |
| `agents` | `object` | | 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. This field is required if the `branches` field is not set. |
GitLab supports the following types of CRON syntax for the `cadence` field:
@@ -99,8 +99,18 @@ GitLab supports the following types of CRON syntax for the `cadence` field:
NOTE:
Other elements of the [CRON syntax](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm) may work in the cadence field if supported by the [cron](https://github.com/robfig/cron) we are using in our implementation, however, GitLab does not officially test or support them.
-NOTE:
-If using the `agents` field, required for `Operational Container Scanning`, the CRON expression is evaluated in [UTC](https://www.timeanddate.com/worldclock/timezone/utc) using the system-time of the Kubernetes-agent pod. If not using the `agents` field, the CRON expression is evaluated in standard [UTC](https://www.timeanddate.com/worldclock/timezone/utc) time from GitLab.com. If you have a self-managed GitLab instance and have [changed the server time zone](../../../administration/timezone.md), the CRON expression is evaluated with the new time zone.
+When using the `schedule` rule type in conjunction with the `agents` field, note the following:
+
+- The GitLab Agent for Kubernetes checks every 30 seconds to see if there is an applicable policy. When a policy is found, the scans are executed according to the `cadence` defined.
+- The CRON expression is evaluated using the system-time of the Kubernetes-agent pod.
+
+When using the `schedule` rule type in conjunction with the `branches` field, note the following:
+
+- The cron worker runs on 15 minute intervals and starts any pipelines that were scheduled to run during the previous 15 minutes.
+- Based on your rule, you might expect scheduled pipelines to run with an offset of up to 15 minutes.
+- The CRON expression is evaluated in standard [UTC](https://www.timeanddate.com/worldclock/timezone/utc) time from GitLab.com. If you have a self-managed GitLab instance and have [changed the server time zone](../../../administration/timezone.md), the CRON expression is evaluated with the new time zone.
+
+![CRON worker diagram](img/scheduled_scan_execution_policies_diagram.png)
### `agent` schema
@@ -140,7 +150,7 @@ rule in the defined policy are met.
| Field | Type | Possible values | Description |
|-------|------|-----------------|-------------|
-| `scan` | `string` | `dast`, `secret_detection`, `sast`, `container_scanning`, `dependency_scanning` | The action's type. |
+| `scan` | `string` | `sast`, `sast_iac`, `dast`, `secret_detection`, `container_scanning`, `dependency_scanning` | The action's type. |
| `site_profile` | `string` | Name of the selected [DAST site profile](../dast/proxy-based.md#site-profile). | The DAST site profile to execute the DAST scan. This field should only be set if `scan` type is `dast`. |
| `scanner_profile` | `string` or `null` | Name of the selected [DAST scanner profile](../dast/proxy-based.md#scanner-profile). | The DAST scanner profile to execute the DAST scan. This field should only be set if `scan` type is `dast`.|
| `variables` | `object` | | A set of CI variables, supplied as an array of `key: value` pairs, to apply and enforce for the selected scan. The `key` is the variable name, with its `value` provided as a string. This parameter supports any variable that the GitLab CI job supports for the specified scan. |
diff --git a/doc/user/application_security/policies/scan-result-policies.md b/doc/user/application_security/policies/scan-result-policies.md
index bc74b8bdfb1..104462529c1 100644
--- a/doc/user/application_security/policies/scan-result-policies.md
+++ b/doc/user/application_security/policies/scan-result-policies.md
@@ -10,8 +10,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
You can use scan result policies to take action based on scan results. For example, one type of scan
result policy is a security approval policy that allows approval to be required based on the
-findings of one or more security scan jobs. Scan result policies are evaluated after a CI scanning
-job is fully executed. The following video gives you an overview of GitLab scan result policies:
+findings of one or more security scan jobs. Scan result policies are evaluated after a CI scanning job is fully executed.
+
+NOTE:
+Scan result policies are applicable only to [protected](../../project/protected_branches.md) target branches.
+
+The following video gives you an overview of GitLab scan result policies:
<div class="video-fallback">
See the video: <a href="https://youtu.be/w5I9gcUgr9U">Overview of GitLab Scan Result Policies</a>.
@@ -29,7 +33,7 @@ NOTE:
Only project Owners have the [permissions](../../permissions.md#project-members-permissions)
to select Security Policy Project.
-Once your policy is complete, save it by selecting **Create merge request** at the bottom of the
+Once your policy is complete, save it by selecting **Configure with a merge request** at the bottom of the
editor. This redirects you to the merge request on the project's configured security policy project.
If a security policy project doesn't link to your project, GitLab creates such a project for you.
Existing policies can also be removed from the editor interface by selecting **Delete policy** at
@@ -76,14 +80,14 @@ This rule enforces the defined actions based on security scan findings.
|------------|------|-----------------|-------------|
| `type` | `string` | `scan_finding` | The rule's type. |
| `branches` | `array` of `string` | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. |
-| `scanners` | `array` of `string` | `sast`, `secret_detection`, `dependency_scanning`, `container_scanning`, `dast`, `coverage_fuzzing`, `api_fuzzing` | The security scanners for this rule to consider. |
+| `scanners` | `array` of `string` | `sast`, `secret_detection`, `dependency_scanning`, `container_scanning`, `dast`, `coverage_fuzzing`, `api_fuzzing` | The security scanners for this rule to consider. Note that `sast` includes results from both SAST and SAST IaC scanners. |
| `vulnerabilities_allowed` | `integer` | Greater than or equal to zero | Number of vulnerabilities allowed before this rule is considered. |
| `severity_levels` | `array` of `string` | `info`, `unknown`, `low`, `medium`, `high`, `critical`| The severity levels for this rule to consider. |
| `vulnerability_states` | `array` of `string` | `newly_detected`, `detected`, `confirmed`, `resolved`, `dismissed` | All vulnerabilities fall into two categories:<br><br>**Newly Detected Vulnerabilities** - the `newly_detected` policy option covers vulnerabilities identified in the merge request branch itself but that do not currently exist on the default branch. This policy option requires a pipeline to complete before the rule is evaluated so that it knows whether vulnerabilities are newly detected or not. Merge requests are blocked until the pipeline and necessary security scans are complete. The `newly_detected` option considers both of the following statuses:<br><br> • Detected<br> • Dismissed<br><br>**Pre-Existing Vulnerabilities** - these policy options are evaluated immediately and do not require a pipeline complete as they consider only vulnerabilities previously detected in the default branch.<br><br> • `Detected` - the policy looks for vulnerabilities in the detected state.<br> • `Confirmed` - the policy looks for vulnerabilities in the confirmed state.<br> • `Dismissed` - the policy looks for vulnerabilities in the dismissed state.<br> • `Resolved` - the policy looks for vulnerabilities in the resolved state. |
## `license_finding` rule type
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `license_scanning_policies`. Disabled by default.
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `license_scanning_policies`. Enabled by default in GitLab 15.10.
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 `license_scanning_policies`.
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index b0d84e4cff9..a0c5adc89f5 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -183,7 +183,8 @@ For more information, see the confidential project `https://gitlab.com/gitlab-or
## Automatic vulnerability resolution
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368284) in GitLab 15.9 [with a project-level flag](../../../administration/feature_flags.md) named `sec_mark_dropped_findings_as_resolved`. Enabled by default on GitLab.com; disabled by default in self-managed. On GitLab.com, [contact Support](https://about.gitlab.com/support/) if you need to disable the flag for your project.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368284) in GitLab 15.9 [with a project-level flag](../../../administration/feature_flags.md) named `sec_mark_dropped_findings_as_resolved`.
+> - Enabled by default in GitLab 15.10. On GitLab.com, [contact Support](https://about.gitlab.com/support/) if you need to disable the flag for your project.
To help you focus on the vulnerabilities that are still relevant, GitLab SAST automatically [resolves](../vulnerabilities/index.md#vulnerability-status-values) vulnerabilities when:
@@ -303,7 +304,7 @@ successfully, and an error may occur.
To enable and configure SAST with customizations:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > 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**.
1. Enter the custom SAST values.
@@ -330,7 +331,7 @@ successfully, and an error may occur.
To enable and configure SAST with default settings:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance** > **Configuration**.
+1. On the left sidebar, select **Security and Compliance** > **Configuration**.
1. In the SAST section, select **Configure with a merge request**.
1. Review and merge the merge request to enable SAST.
diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md
index d6aab71a2c6..6dd20ea094e 100644
--- a/doc/user/application_security/secret_detection/index.md
+++ b/doc/user/application_security/secret_detection/index.md
@@ -36,8 +36,8 @@ more information, see [Post-processing and revocation](post_processing.md).
All identified secrets are reported in the:
-- Merge request widget
-- Pipelines' **Security** tab
+- [Merge request widget](../index.md#view-security-scan-information-in-merge-requests)
+- [Pipeline security report](../vulnerability_report/pipeline.md)
- [Vulnerability Report](../vulnerability_report/index.md)
![Secret Detection in merge request widget](img/secret_detection_v13_2.png)
@@ -141,12 +141,12 @@ To enable Secret Detection, either:
- Enable [Auto DevOps](../../../topics/autodevops/index.md), which includes [Auto Secret Detection](../../../topics/autodevops/stages.md#auto-secret-detection).
-- [Edit the `.gitlab.ci.yml` file manually](#edit-the-gitlabciyml-file-manually). Use this method if
- your `.gitlab-ci.yml` file is complex.
+- [Edit the `.gitlab.ci.yml` file manually](#edit-the-gitlab-ciyml-file-manually). Use this method
+ if your `.gitlab-ci.yml` file is complex.
- [Use an automatically configured merge request](#use-an-automatically-configured-merge-request).
-### Edit the `.gitlab.ci.yml` file manually
+### Edit the `.gitlab-ci.yml` file manually
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.
@@ -180,12 +180,12 @@ the `.gitlab-ci.yml` file. You then merge the merge request to enable Secret Det
NOTE:
This method works best with no existing `.gitlab-ci.yml` file, or with a minimal configuration
file. If you have a complex GitLab configuration file it may not be parsed successfully, and an
-error may occur. In that case, use the [manual](#edit-the-gitlabciyml-file-manually) method instead.
+error may occur. In that case, use the [manual](#edit-the-gitlab-ciyml-file-manually) method instead.
-To enable Secret Detection automatically:
+To enable Secret Detection:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > Security configuration**.
1. In the **Secret Detection** row, select **Configure with a merge request**.
1. Optional. Complete the fields.
1. Select **Create merge request**.
@@ -195,12 +195,13 @@ Pipelines now include a Secret Detection job.
## Responding to a leaked secret
-Secrets detected by the analyzer should be immediately rotated.
-[Purging a file from the repository's history](../../project/repository/reducing_the_repo_size_using_git.md#purge-files-from-repository-history)
-may not be effective in removing all references to the file. Additionally, the secret will remain in any existing
-forks or clones of the repository.
+When a secret is detected, you should rotate it immediately. GitLab attempts to
+[automatically revoke](post_processing.md) some types of leaked secrets. For those that are not
+automatically revoked, you must do so manually.
-GitLab will attempt to [automatically revoke](post_processing.md) some types of leaked secrets.
+[Purging a secret from the repository's history](../../project/repository/reducing_the_repo_size_using_git.md#purge-files-from-repository-history)
+does not fully address the leak. The original secret remains in any existing forks or
+clones of the repository.
## Pinning to specific analyzer version
@@ -413,18 +414,16 @@ In the following example `secret-detection-ruleset.toml` file, rules are matched
### Synthesize a custom configuration
-To create a custom configuration, you can use passthrough chains. Passthroughs can also be chained
-to build more complex configurations. For more details, see
-[SAST Customize ruleset](../sast/customize_rulesets.md).
+You can use passthroughs to override the default Secret Detection ruleset. The
+following passthrough types are supported by the `secrets` analyzer:
-Only the following passthrough types are supported by the `secrets` analyzer:
-
-- `file`
- `raw`
+- `file`
-In the `secret-detection-ruleset.toml` file, do one of the following:
+To define a passthrough, add _one_ of the following to the
+`secret-detection-ruleset.toml` file:
-- Define a custom ruleset, for example:
+- Using an inline (`raw`) value:
```toml
[secrets]
@@ -442,7 +441,7 @@ In the `secret-detection-ruleset.toml` file, do one of the following:
"""
```
-- Provide the name of the file containing a custom ruleset, for example:
+- Using an external `file` committed to the current repository:
```toml
[secrets]
@@ -454,6 +453,10 @@ In the `secret-detection-ruleset.toml` file, do one of the following:
value = "config/gitleaks.toml"
```
+For more information on the syntax of passthroughs, see the
+[passthroughs section on the SAST customize rulesets](../sast/customize_rulesets.md#the-analyzerpassthrough-section)
+page.
+
## Running Secret Detection in an offline environment **(PREMIUM SELF)**
An offline environment has limited, restricted, or intermittent access to external resources through
diff --git a/doc/user/application_security/secure_your_application.md b/doc/user/application_security/secure_your_application.md
index fb10efff2c6..8dd1168a0d9 100644
--- a/doc/user/application_security/secure_your_application.md
+++ b/doc/user/application_security/secure_your_application.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
GitLab can check your applications for security vulnerabilities.
- [Get started](get-started-security.md)
-- [Security Configuration](configuration/index.md)
+- [Security configuration](configuration/index.md)
- [Container Scanning](container_scanning/index.md)
- [Dependency Scanning](dependency_scanning/index.md)
- [Static Application Security Testing](sast/index.md)
diff --git a/doc/user/application_security/security_dashboard/img/security_center_dashboard_v13_4.png b/doc/user/application_security/security_dashboard/img/security_center_dashboard_v13_4.png
deleted file mode 100644
index 5379b5c6e5d..00000000000
--- a/doc/user/application_security/security_dashboard/img/security_center_dashboard_v13_4.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/security_center_dashboard_v15_10.png b/doc/user/application_security/security_dashboard/img/security_center_dashboard_v15_10.png
new file mode 100644
index 00000000000..c2780fce787
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/security_center_dashboard_v15_10.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index 7388ef80e68..1a8b4dac10e 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -64,7 +64,7 @@ Project Security Dashboards show statistics for all vulnerabilities with a curre
To view total number of vulnerabilities over time:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Security Dashboard**.
+1. On the left sidebar, select **Security and Compliance > Security Dashboard**.
1. Filter and search for what you need.
- To filter the chart by severity, select the legend name.
- To view a specific time frame, use the time range handles (**{scroll-handle}**).
@@ -77,7 +77,7 @@ To view total number of vulnerabilities over time:
To download an SVG image of the vulnerabilities chart:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Security dashboard**.
+1. On the left sidebar, select **Security and Compliance > Security dashboard**.
1. Select **Save chart as an image** (**{download}**).
## View vulnerabilities over time for a group
@@ -133,7 +133,7 @@ The Security Center includes:
- A [vulnerability report](../vulnerability_report/index.md).
- A settings area to configure which projects to display.
-![Security Center Dashboard with projects](img/security_center_dashboard_v13_4.png)
+![Security Center Dashboard with projects](img/security_center_dashboard_v15_10.png)
### View the Security Center
@@ -151,6 +151,9 @@ To add projects to the Security Center:
After you add projects, the security dashboard and vulnerability report show the vulnerabilities
found in those projects' default branches.
+You can add a maximum of 1,000 projects, however the **Project** filter in the **Vulnerability
+Report** is limited to 100 projects.
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/application_security/vulnerabilities/index.md b/doc/user/application_security/vulnerabilities/index.md
index 67a1257799b..8107b9d8484 100644
--- a/doc/user/application_security/vulnerabilities/index.md
+++ b/doc/user/application_security/vulnerabilities/index.md
@@ -54,7 +54,7 @@ no longer detected, and change their status.
To change a vulnerability's status from its Vulnerability Page:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
+1. On the left sidebar, select **Security and Compliance > Vulnerability report**.
1. Select the vulnerability's description.
1. From the **Status** dropdown list select a status, then select **Change status**.
1. Optionally, at the bottom of the page, add a comment to the log entry.
@@ -80,7 +80,7 @@ that when Jira integration is enabled, the GitLab issue feature is not available
To create a GitLab issue for a vulnerability:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
+1. On the left sidebar, select **Security and Compliance > Vulnerability report**.
1. Select the vulnerability's description.
1. Select **Create issue**.
@@ -102,7 +102,7 @@ Prerequisites:
To create a Jira issue for a vulnerability:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
+1. On the left sidebar, select **Security and Compliance > Vulnerability report**.
1. Select the vulnerability's description.
1. Select **Create Jira issue**.
1. If you're not already logged in to Jira, sign in.
@@ -135,7 +135,7 @@ Be aware of the following conditions between a vulnerability and a linked issue:
To link a vulnerability to existing issues:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
+1. On the left sidebar, select **Security and Compliance > Vulnerability report**.
1. Select the vulnerability's description.
1. In the **Linked issues** section, select the plus icon (**{plus}**).
1. For each issue to be linked, either:
@@ -170,7 +170,7 @@ To resolve a vulnerability, you can either:
To resolve the vulnerability with a merge request:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
+1. On the left sidebar, select **Security and Compliance > Vulnerability report**.
1. Select the vulnerability's description.
1. From the **Resolve with merge request** dropdown list, select **Resolve with merge request**.
@@ -182,7 +182,7 @@ Process the merge request according to your standard workflow.
To manually apply the patch that GitLab generated for a vulnerability:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
+1. On the left sidebar, select **Security and Compliance > Vulnerability report**.
1. Select the vulnerability's description.
1. From the **Resolve with merge request** dropdown list, select **Download patch to resolve**.
1. Ensure your local project has the same commit checked out that was used to generate the patch.
@@ -195,17 +195,19 @@ To manually apply the patch that GitLab generated for a vulnerability:
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6176) in GitLab 14.9.
+NOTE:
+Security training is not available in an offline environment because it uses content from
+third-party vendors.
+
Security training helps your developers learn how to fix vulnerabilities. Developers can view security training from selected educational providers, relevant to the detected vulnerability.
To enable security training for vulnerabilities in your project:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. On the left sidebar, select **Security and Compliance > Security configuration**.
1. On the tab bar, select **Vulnerability Management**.
1. To enable a security training provider, turn on the toggle.
-Security training uses content from third-party vendors. You must have an internet connection to use this feature.
-
## View security training for a vulnerability
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6176) in GitLab 14.9.
@@ -220,6 +222,6 @@ Vulnerabilities with a CWE are most likely to return a training result.
To view the security training for a vulnerability:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
+1. On the left sidebar, select **Security and Compliance > 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 e6353264f39..3d7565f97bc 100644
--- a/doc/user/application_security/vulnerability_report/index.md
+++ b/doc/user/application_security/vulnerability_report/index.md
@@ -45,7 +45,7 @@ At the project level, the Vulnerability Report also contains:
To view the project-level vulnerability report:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability report**.
+1. On the left sidebar, select **Security and Compliance > Vulnerability report**.
## Vulnerability Report actions
@@ -242,7 +242,7 @@ Vulnerability records cannot be deleted, so a permanent record always remains.
You can dismiss a vulnerability in projects and groups:
1. Select the vulnerability in the Security Dashboard.
-1. In the upper right, from the **Status** selector menu, select **Dismissed**.
+1. In the upper-right corner, from the **Status** dropdown list, select **Dismissed**.
1. Optional. Add a reason for the dismissal and select **Save comment**.
To undo this action, select a different status from the same menu.
@@ -256,7 +256,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 top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Vulnerability Report**.
+1. On the left sidebar, select **Security and Compliance > Vulnerability Report**.
1. Select **Submit vulnerability**.
1. Complete the fields and submit the form.
diff --git a/doc/user/award_emojis.md b/doc/user/award_emojis.md
index e1459717241..919b76e930f 100644
--- a/doc/user/award_emojis.md
+++ b/doc/user/award_emojis.md
@@ -36,7 +36,7 @@ celebrate an accomplishment or agree with an opinion.
To add an award emoji:
-1. In the upper right of the comment, select the smile (**{slight-smile}**).
+1. In the upper-right corner of the comment, select the smile (**{slight-smile}**).
1. Select an emoji from the dropdown list.
To remove an award emoji, select the emoji again.
diff --git a/doc/user/clusters/agent/gitops.md b/doc/user/clusters/agent/gitops.md
index 787b0062017..1d71f6ac511 100644
--- a/doc/user/clusters/agent/gitops.md
+++ b/doc/user/clusters/agent/gitops.md
@@ -12,6 +12,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/346585) to make the `id` attribute optional in GitLab 15.7.
> - Specifying a branch, tag, or commit reference to fetch the Kubernetes manifest files [introduced](https://gitlab.com/groups/gitlab-org/-/epics/4516) in GitLab 15.7.
+NOTE:
+From GitLab 15.10, you should use [Flux](gitops/flux.md) for GitOps. For more information, see
+[this announcement blog post](https://about.gitlab.com/blog/2023/02/08/why-did-we-choose-to-integrate-fluxcd-with-gitlab/).
+
With GitOps, you can manage containerized clusters and applications from a Git repository that:
- Is the single source of truth of your system.
diff --git a/doc/user/clusters/agent/gitops/flux.md b/doc/user/clusters/agent/gitops/flux.md
new file mode 100644
index 00000000000..9a3537aacbf
--- /dev/null
+++ b/doc/user/clusters/agent/gitops/flux.md
@@ -0,0 +1,36 @@
+---
+stage: Configure
+group: Configure
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Flux (Beta) **(FREE)**
+
+Flux is a GitOps tool that helps you manage your Kubernetes clusters.
+You can use Flux to:
+
+- Keep your clusters in sync with your Git repositories.
+- Reconcile code changes with your deployments.
+- Manage your Flux installation itself with a bootstrap.
+
+To get started, see the [Flux installation documentation](https://fluxcd.io/flux/installation).
+
+Support for Flux is in [Open Beta](../../../../policy/alpha-beta-support.md#beta-features).
+
+## Bootstrap installation
+
+Use the Flux command [`bootstrap gitlab`](https://fluxcd.io/flux/installation/#gitlab-and-gitlab-enterprise)
+to configure a Kubernetes cluster to manage itself from a Git repository.
+
+You must authenticate your installation with either:
+
+- Recommended. [A project access token](../../../project/settings/project_access_tokens.md).
+- A [group access token](../../../group/settings/group_access_tokens.md).
+- A [personal access token](../../../profile/personal_access_tokens.md).
+
+Some Flux features like [automated image updates](https://fluxcd.io/flux/guides/image-update/) require
+write access to the source repositories.
+
+## GitOps repository structure
+
+You should organize your repositories to meet the needs of your team. For detailed recommendations, see the Flux [repository structure documentation](https://fluxcd.io/flux/guides/repository-structure/).
diff --git a/doc/user/clusters/agent/gitops/flux_tutorial.md b/doc/user/clusters/agent/gitops/flux_tutorial.md
new file mode 100644
index 00000000000..5f902002f83
--- /dev/null
+++ b/doc/user/clusters/agent/gitops/flux_tutorial.md
@@ -0,0 +1,184 @@
+---
+stage: Configure
+group: Configure
+info: A tutorial using Flux with Project Access Tokens
+---
+
+# Tutorial: Set up Flux for GitOps **(FREE)**
+
+This tutorial teaches you how to set up Flux for GitOps. You'll set up a sample project,
+complete a bootstrap Flux installation, and authenticate your installation with a
+[project access token](../../../project/settings/project_access_tokens.md).
+
+You can find the fully configured tutorial project [in this GitLab repository](https://gitlab.com/gitlab-org/configure/examples/flux/flux-config). It works in conjunction with [this repository](https://gitlab.com/gitlab-org/configure/examples/flux/web-app-manifests/-/tree/main), which contains the example Kubernetes manifests.
+
+To set up Flux with a project access token:
+
+1. [Create the Flux repository](#create-the-flux-repository)
+1. [Create the Kubernetes manifest repository](#create-the-kubernetes-manifest-repository)
+1. [Configure Flux to sync your manifests](#configure-flux-to-sync-your-manifests)
+1. [Verify your configuration](#verify-your-configuration)
+
+Prerequisites:
+
+- On GitLab SaaS, you must have the Premium or Ultimate tier to use a project access token.
+ On self-managed instances, you can have any tier.
+- Not recommended. You can authenticate with a [personal or group access token](flux.md#bootstrap-installation) in all tiers.
+- You must have a Kubernetes cluster running.
+
+## Create the Flux repository
+
+To start, create a Git repository, install Flux, and authenticate Flux with your repo:
+
+1. Make sure your `kubectl` is configured to access your cluster.
+1. [Install the Flux CLI](https://fluxcd.io/flux/installation/#install-the-flux-cli).
+1. In GitLab, create a new empty project called `flux-config`.
+1. In the `flux-config` project, create a [project access token](../../../project/settings/project_access_tokens.md#create-a-project-access-token) with the following settings:
+
+ - From the **Select a role** dropdown list, select **Maintainer**.
+ - Under **Select scopes**, select the **API** and **write_repository** checkboxes.
+
+ Name the project token `flux-project-access-token`.
+
+1. From your shell, export a `GITLAB_TOKEN` environment variable with the value of your project access token.
+ For example, `export GITLAB_TOKEN=<flux-project-access-token>`.
+1. Run the `bootstrap` command. The exact command depends on whether you are
+ creating the Flux repository under a GitLab user, group, or subgroup. For more information,
+ see the [Flux bootstrap documentation](https://fluxcd.io/flux/installation/#gitlab-and-gitlab-enterprise).
+
+ In this tutorial, you're working with a public project in a subgroup. The bootstrap command looks like this:
+
+ ```shell
+ flux bootstrap gitlab \
+ --owner=gitlab-org/configure/examples/flux \
+ --repository=flux-config \
+ --branch=main \
+ --path=clusters/my-cluster
+ ```
+
+ This command installs Flux on the Kubernetes cluster and configures it to manage itself from the repository `flux-config`.
+
+Great work! You now have a repository, a project access token, and a Flux bootstrap installation authenticated to your repo. Any updates to your repo are automatically synced to the cluster.
+
+## Create the Kubernetes manifest repository
+
+Next, create a repository for your Kubernetes manifests:
+
+1. In GitLab, create a new repository called `web-app-manifests`.
+1. Add a file to `web-app-manifests` named `nginx-deployment.yaml` with the following contents:
+
+ ```yaml
+ apiVersion: apps/v1
+
+ kind: Deployment
+
+ metadata:
+ name: nginx-deployment
+ labels:
+ app: nginx
+ spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ containers:
+ - name: nginx
+ image: nginx:1.14.2
+ ports:
+ - containerPort: 80
+ ```
+
+1. In the new repository, [create a deploy token](../../../project/deploy_tokens/index.md#create-a-deploy-token) with only the **read_repository** scope.
+1. Store your deploy token username and password somewhere safe.
+1. In Flux CLI, create a secret with your deploy token and point the secret to the new repository. For example:
+
+ ```shell
+ flux create secret git flux-deploy-authentication \
+ --url=https://gitlab.com/gitlab-org/configure/examples/flux/web-app-manifests \
+ --namespace=default \
+ --username=<token-user-name> \
+ --password=<token-password>
+ ```
+
+1. To check if your secret was generated successfully, run:
+
+ ```shell
+ kubectl -n default get secrets flux-deploy-authentication -o yaml
+ ```
+
+ Under `data`, you should see base64-encoded values associated with your token username and password.
+
+Congratulations! You now have a manifest repository, a deploy token, and a secret generated directly on your cluster.
+
+## Configure Flux to sync your manifests
+
+Next, tell `flux-config` to sync with the `web-app-manifests` repository.
+
+To do so, create a [`GitRepository`](https://fluxcd.io/flux/components/source/gitrepositories/) resource:
+
+1. Clone the `flux-config` repo to your machine.
+1. In your local clone of `flux-config`, add the `GitRepository` file `clusters/my-cluster/web-app-manifests-source.yaml`:
+
+ ```yaml
+ ---
+ apiVersion: source.toolkit.fluxcd.io/v1beta2
+ kind: GitRepository
+ metadata:
+ name: web-app-manifests
+ namespace: default
+ spec:
+ interval: 1m0s
+ ref:
+ branch: main
+ secretRef:
+ name: flux-deploy-authentication
+ url: https://gitlab.com/gitlab-org/configure/examples/flux/web-app-manifests
+ ```
+
+ This file uses `secretRef` to refer back to the deploy token secret you created in the last step.
+
+1. In your local clone of `flux-config`, add the `GitRepository` file `clusters/my-cluster/web-app-manifests-kustomization.yaml`:
+
+ ```yaml
+ ---
+ apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+ kind: Kustomization
+ metadata:
+ name: nginx-source-kustomization
+ namespace: default
+ spec:
+ interval: 1m0s
+ path: ./
+ prune: true
+ sourceRef:
+ kind: GitRepository
+ name: web-app-manifests
+ namespace: default
+ targetNamespace: default
+ ```
+
+ This file adds a [`Kustomization`](https://fluxcd.io/flux/components/kustomize/kustomization/) resource that tells Flux to sync the manifests from
+ `web-app-manifests` with `kustomize`.
+
+1. Commit the new files and push.
+
+## Verify your configuration
+
+You should see a newly created `nginx-deployment` pod in your cluster.
+
+To check whether the `nginx-deployment` pod is running in the default namespace, run the following:
+
+```shell
+kubectl -n default get pods -n default
+```
+
+If you want to see the deployment sync again, try updating the number of replicas in the
+`nginx-deployment.yaml` file and push to your `main` branch. If all is working well, it
+should sync to the cluster.
+
+Excellent work! You've successfully set up a complete Flux project.
diff --git a/doc/user/clusters/agent/gitops/secrets_management.md b/doc/user/clusters/agent/gitops/secrets_management.md
index dc1cbe3009d..8a47dcfaf72 100644
--- a/doc/user/clusters/agent/gitops/secrets_management.md
+++ b/doc/user/clusters/agent/gitops/secrets_management.md
@@ -50,9 +50,9 @@ To deploy containers from the GitLab Container Registry, you must configure the
1. Generate a GitLab token with at least `read-registry` rights. The token can be either a Personal or a Project Access Token.
1. Create a Kubernetes secret manifest YAML file. Update the values as needed:
- ```shell
- kubectl create secret docker-registry gitlab-credentials --docker-server=registry.gitlab.example.com --docker-username=<gitlab-username> --docker-password=<gitlab-token> --docker-email=<gitlab-user-email> -n <namespace> --dry-run=client -o yaml > gitlab-credentials.yaml
- ```
+ ```shell
+ kubectl create secret docker-registry gitlab-credentials --docker-server=registry.gitlab.example.com --docker-username=<gitlab-username> --docker-password=<gitlab-token> --docker-email=<gitlab-user-email> -n <namespace> --dry-run=client -o yaml > gitlab-credentials.yaml
+ ```
1. Encrypt the secret into a `SealedSecret` manifest:
diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md
index 8f4855a7f93..0d84a617808 100644
--- a/doc/user/clusters/agent/index.md
+++ b/doc/user/clusters/agent/index.md
@@ -12,6 +12,7 @@ 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.11, the GitLab agent became available on GitLab.com.
> - [Moved](https://gitlab.com/groups/gitlab-org/-/epics/6290) from GitLab Premium to GitLab Free in 14.5.
> - [Renamed](https://gitlab.com/groups/gitlab-org/-/epics/7167) from "GitLab Kubernetes Agent" to "GitLab agent for Kubernetes" in GitLab 14.6.
+> - Flux [recommended](https://gitlab.com/gitlab-org/gitlab/-/issues/357947#note_1253489000) as GitOps solution in GitLab 15.10.
You can connect your Kubernetes cluster with GitLab to deploy, manage,
and monitor your cloud-native solutions.
@@ -33,20 +34,7 @@ You can choose from two primary workflows. The GitOps workflow is recommended.
### GitOps workflow
-In a [**GitOps** workflow](gitops.md):
-
-- You keep your Kubernetes manifests in GitLab.
-- You install a GitLab agent in your cluster.
-- Any time you update your manifests, the agent updates the cluster.
-- The cluster automatically cleans up unexpected changes. It uses
- [server-side applies](https://kubernetes.io/docs/reference/using-api/server-side-apply/)
- to fix any configuration inconsistencies that third parties introduce.
-
-This workflow is fully driven with Git and is considered **pull-based**,
-because the cluster is pulling updates from your GitLab repository.
-
-GitLab recommends this workflow. We are actively investing in this workflow
-so we can provide a first-class experience.
+You should use Flux for GitOps. To get started, see the GitLab [Flux documentation](../../../user/clusters/agent/gitops/flux.md).
### GitLab CI/CD workflow
diff --git a/doc/user/clusters/agent/troubleshooting.md b/doc/user/clusters/agent/troubleshooting.md
index f5f235d2758..84cdbbcc096 100644
--- a/doc/user/clusters/agent/troubleshooting.md
+++ b/doc/user/clusters/agent/troubleshooting.md
@@ -107,71 +107,72 @@ This error occurs when your GitLab instance is using a certificate signed by an
certificate authority that is unknown to the agent.
To fix this issue, you can present the CA certificate file to the agent
-by using a Kubernetes `configmap` and mount the file in the agent `/etc/ssl/certs` directory from where it
-is picked up automatically.
+by [customizing the Helm installation](install/index.md#customize-the-helm-installation).
+Add `--set config.caCert="$(cat ~/path/to/ca.crt)"` to the `helm install` command. Make sure to replace `~/path/to/ca.crt`
+with the path to your internal CA's certificate file. The file should be a valid PEM or DER-encoded certificate.
-For example, if your internal CA certificate is `myCA.pem`:
+When you deploy `agentk` with a set `config.caCert` value, the certificate is added to `configmap` and the certificate file is mounted in `/etc/ssl/certs`.
-```plaintext
-kubectl -n gitlab-agent create configmap ca-pemstore --from-file=myCA.pem
+```yaml
+$ kubectl get configmap -lapp=gitlab-agent -o yaml
+apiVersion: v1
+items:
+- apiVersion: v1
+ data:
+ ca.crt: |-
+ -----BEGIN CERTIFICATE-----
+ MIIFmzCCA4OgAwIBAgIUE+FvXfDpJ869UgJitjRX7HHT84cwDQYJKoZIhvcNAQEL
+ ...truncated certificate...
+ GHZCTQkbQyUwBWJOUyOxW1lro4hWqtP4xLj8Dpq1jfopH72h0qTGkX0XhFGiSaM=
+ -----END CERTIFICATE-----
+ kind: ConfigMap
+ metadata:
+ annotations:
+ meta.helm.sh/release-name: self-signed
+ meta.helm.sh/release-namespace: gitlab-agent-self-signed
+ creationTimestamp: "2023-03-07T20:12:26Z"
+ labels:
+ app: gitlab-agent
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/name: gitlab-agent
+ app.kubernetes.io/version: v15.9.0
+ helm.sh/chart: gitlab-agent-1.11.0
+ name: self-signed-gitlab-agent
+ resourceVersion: "263184207"
+kind: List
```
-Then in `resources.yml`:
+You might see a similar error in the [agent server (KAS) logs](../../../administration/logs/index.md#gitlab-agent-server) of your GitLab application server:
-```yaml
- spec:
- serviceAccountName: gitlab-agent
- containers:
- - name: agent
- image: "registry.gitlab.com/gitlab-org/cluster-integration/gitlab-agent/agentk:<version>"
- args:
- - --token-file=/config/token
- - --kas-address
- - wss://kas.host.tld:443 # replace this line with the line below if using Omnibus GitLab or GitLab.com.
- # - wss://gitlab.host.tld:443/-/kubernetes-agent/
- # - wss://kas.gitlab.com # for GitLab.com users, use this KAS.
- # - grpc://host.docker.internal:8150 # use this attribute when connecting from Docker.
- volumeMounts:
- - name: token-volume
- mountPath: /config
- - name: ca-pemstore-volume
- mountPath: /etc/ssl/certs/myCA.pem
- subPath: myCA.pem
- volumes:
- - name: token-volume
- secret:
- secretName: gitlab-agent-token
- - name: ca-pemstore-volume
- configMap:
- name: ca-pemstore
- items:
- - key: myCA.pem
- path: myCA.pem
+```json
+{"level":"error","time":"2023-03-07T20:19:48.151Z","msg":"AgentInfo()","grpc_service":"gitlab.agent.agent_configuration.rpc.AgentConfiguration","grpc_method":"GetConfiguration","error":"Get \"https://gitlab.example.com/api/v4/internal/kubernetes/agent_info\": x509: certificate signed by unknown authority"}
```
-Alternatively, you can mount the certificate file at a different location and specify it for the
-`--ca-cert-file` agent parameter:
+To fix it, [install your internal CA's public certificate](https://docs.gitlab.com/omnibus/settings/ssl/#install-custom-public-certificates) in the `/etc/gitlab/trusted-certs` directory.
-```yaml
- containers:
- - name: agent
- image: "registry.gitlab.com/gitlab-org/cluster-integration/gitlab-agent/agentk:<version>"
- args:
- - --ca-cert-file=/tmp/myCA.pem
- - --token-file=/config/token
- - --kas-address
- - wss://kas.host.tld:443 # replace this line with the line below if using Omnibus GitLab or GitLab.com.
- # - wss://gitlab.host.tld:443/-/kubernetes-agent/
- # - wss://kas.gitlab.com # for GitLab.com users, use this KAS.
- # - grpc://host.docker.internal:8150 # use this attribute when connecting from Docker.
- volumeMounts:
- - name: token-volume
- mountPath: /config
- - name: ca-pemstore-volume
- mountPath: /tmp/myCA.pem
- subPath: myCA.pem
+Alternatively, you can configure the agent server (KAS) to read the certificate from a custom directory.
+Add the following configuration to `/etc/gitlab/gitlab.rb`:
+
+```ruby
+gitlab_kas['env'] = {
+ 'SSL_CERT_DIR' => "/opt/gitlab/embedded/ssl/certs/"
+ }
```
+To apply the changes:
+
+1. Reconfigure GitLab.
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+1. Restart `gitlab-kas`.
+
+ ```shell
+ gitlab-ctl restart gitlab-kas
+ ```
+
## Project not found
```json
diff --git a/doc/user/clusters/cost_management.md b/doc/user/clusters/cost_management.md
index 74bfab49c55..910092eb4e0 100644
--- a/doc/user/clusters/cost_management.md
+++ b/doc/user/clusters/cost_management.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Cluster cost management (DEPRECATED) **(ULTIMATE)**
+# Cluster cost management (deprecated) **(ULTIMATE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216737) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.5.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/clusters/environments.md b/doc/user/clusters/environments.md
index f4313656803..dc6898bd3d3 100644
--- a/doc/user/clusters/environments.md
+++ b/doc/user/clusters/environments.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Cluster Environments (DEPRECATED) **(PREMIUM)**
+# Cluster Environments (deprecated) **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13392) in GitLab 12.3 for group-level clusters.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14809) in GitLab 12.4 for instance-level clusters.
diff --git a/doc/user/clusters/integrations.md b/doc/user/clusters/integrations.md
index c5e56fcd3a7..b5600096856 100644
--- a/doc/user/clusters/integrations.md
+++ b/doc/user/clusters/integrations.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Cluster integrations (DEPRECATED) **(FREE)**
+# Cluster integrations (deprecated) **(FREE)**
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
> - [Disabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/353410) in GitLab 15.0.
diff --git a/doc/user/clusters/management_project.md b/doc/user/clusters/management_project.md
index 18317ae09ed..f2eb0cfbc39 100644
--- a/doc/user/clusters/management_project.md
+++ b/doc/user/clusters/management_project.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Cluster management project (DEPRECATED) **(FREE)**
+# Cluster management project (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32810) in GitLab 12.5.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/clusters/migrating_from_gma_to_project_template.md b/doc/user/clusters/migrating_from_gma_to_project_template.md
index e5d81091094..42510a93495 100644
--- a/doc/user/clusters/migrating_from_gma_to_project_template.md
+++ b/doc/user/clusters/migrating_from_gma_to_project_template.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Migrate from GitLab Managed Apps to Cluster Management Projects (DEPRECATED) **(FREE)**
+# Migrate from GitLab Managed Apps to Cluster Management Projects (deprecated) **(FREE)**
The GitLab Managed Apps were deprecated in GitLab 14.0
in favor of user-controlled Cluster Management projects.
diff --git a/doc/user/compliance/compliance_report/index.md b/doc/user/compliance/compliance_report/index.md
index 04609026793..d5af7edf515 100644
--- a/doc/user/compliance/compliance_report/index.md
+++ b/doc/user/compliance/compliance_report/index.md
@@ -5,38 +5,57 @@ group: Compliance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Compliance report **(ULTIMATE)**
+# Compliance reports **(ULTIMATE)**
+
+See reports about compliance violations and compliance frameworks for the group.
+
+## Compliance violations report
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36524) in GitLab 12.8 as Compliance Dashboard.
+> - Compliance violation drawer [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/299357) in GitLab 14.1.
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/299360) to compliance report in GitLab 14.2.
> - [Replaced](https://gitlab.com/groups/gitlab-org/-/epics/5237) by merge request violations in GitLab 14.6 [with a flag](../../../administration/feature_flags.md) named `compliance_violations_report`. Disabled by default.
> - 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.
-Compliance report gives you the ability to see a group's merge request activity. It provides a
-high-level view for all projects in the group. For example, code approved for merging into
-production.
+With compliance violations report, you can see a high-level view of merge request activity for all projects in the group.
-You can use the report to get:
+When you select a row in the compliance report, a drawer appears that provides:
-- A list of compliance violations from all merged merge requests within the group.
-- The reason and severity of each compliance violation.
-- A link to the merge request that caused each compliance violation.
+- The project name and [compliance framework label](../../project/settings/index.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]`.
+- A list of users that committed changes to the merge request.
+- A list of users that commented on the merge request.
+- A list of users that approved the merge request.
+- The user that merged the merge request.
-## View the compliance report for a group
+### View the compliance violations report for a group
Prerequisites:
- You must be an administrator or have the Owner role for the group.
-To view the compliance report:
+To view the compliance violations report:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Security & Compliance > Compliance report**.
+1. On the left sidebar, select **Security and Compliance > Compliance report**.
+
+You can sort the compliance report on:
-### Severity levels scale
+- Severity level.
+- Type of violation.
+- Merge request title.
-The following is a list of available violation severity levels, ranked from most to least severe:
+Select a row to see details of the compliance violation.
+
+#### Severity levels
+
+Each compliance violation has one of the following severities.
+
+<!-- vale gitlab.SubstitutionWarning = NO -->
| Icon | Severity level |
|:----------------------------------------------|:---------------|
@@ -46,75 +65,69 @@ The following is a list of available violation severity levels, ranked from most
| **{severity-low, 18, gl-fill-orange-300}** | Low |
| **{severity-info, 18, gl-fill-blue-400}** | Info |
-### Violation types
+<!-- vale gitlab.SubstitutionWarning = YES -->
-The following is a list of violations that are either:
+#### Violation types
-- Already available.
-- Aren't available, but which we are tracking in issues.
+From [GitLab 14.10](https://gitlab.com/groups/gitlab-org/-/epics/6870), these are the available compliance violations.
-| Violation | Severity level | Category | Description | Availability |
-|:-------------------------------------|:----------------|:---------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------|
-| Author approved merge request | High | [Separation of duties](#separation-of-duties) | The author of the merge request approved their own merge request. For more information, see [Prevent approval by author](../../project/merge_requests/approvals/settings.md#prevent-approval-by-author). | [Available in GitLab 14.10](https://gitlab.com/groups/gitlab-org/-/epics/6870) |
-| Committers approved merge request | High | [Separation of duties](#separation-of-duties) | The committers of the merge request approved the merge request they contributed to. For more information, see [Prevent approvals by users who add commits](../../project/merge_requests/approvals/settings.md#prevent-approvals-by-users-who-add-commits). | [Available in GitLab 14.10](https://gitlab.com/groups/gitlab-org/-/epics/6870) |
-| Fewer than two approvals | High | [Separation of duties](#separation-of-duties) | The merge request was merged with fewer than two approvals. For more information, see [Merge request approval rules](../../project/merge_requests/approvals/rules.md). | [Available in GitLab 14.10](https://gitlab.com/groups/gitlab-org/-/epics/6870) |
-| Pipeline failed | Medium | [Pipeline results](../../../ci/pipelines/index.md) | The merge requests pipeline failed and was merged. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
-| Pipeline passed with warnings | Info | [Pipeline results](../../../ci/pipelines/index.md) | The merge request pipeline passed with warnings and was merged. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
-| Code coverage down more than 10% | High | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | The code coverage report for the merge request indicates a reduction in coverage of more than 10%. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
-| Code coverage down between 5% to 10% | Medium | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | The code coverage report for the merge request indicates a reduction in coverage of between 5% to 10%. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
-| Code coverage down between 1% to 5% | Low | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | The code coverage report for the merge request indicates a reduction in coverage of between 1% to 5%. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
-| Code coverage down less than 1% | Info | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | The code coverage report for the merge request indicates a reduction in coverage of less than 1%. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
+| Violation | Severity level | Category | Description |
+|:----------------------------------|:---------------|:----------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| Author approved merge request | High | [Separation of duties](#separation-of-duties) | Author of the merge request approved their own merge request. For more information, see [Prevent approval by author](../../project/merge_requests/approvals/settings.md#prevent-approval-by-author). |
+| Committers approved merge request | High | [Separation of duties](#separation-of-duties) | Committers of the merge request approved the merge request they contributed to. For more information, see [Prevent approvals by users who add commits](../../project/merge_requests/approvals/settings.md#prevent-approvals-by-users-who-add-commits). |
+| Fewer than two approvals | High | [Separation of duties](#separation-of-duties) | Merge request was merged with fewer than two approvals. For more information, see [Merge request approval rules](../../project/merge_requests/approvals/rules.md). |
-## Merge request drawer
+The following are unavailable compliance violations that are tracked in [epic 5237](https://gitlab.com/groups/gitlab-org/-/epics/5237).
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/299357) in GitLab 14.1.
+<!-- vale gitlab.SubstitutionWarning = NO -->
-When you select a row, a drawer is shown that provides further details about the merge
-request:
+| Violation | Severity level | Category | Description |
+|:-------------------------------------|:---------------|:---------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------|
+| Pipeline failed | Medium | [Pipeline results](../../../ci/pipelines/index.md) | Merge requests pipeline failed and was merged. |
+| Pipeline passed with warnings | Info | [Pipeline results](../../../ci/pipelines/index.md) | Merge request pipeline passed with warnings and was merged. |
+| Code coverage down more than 10% | High | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | Code coverage report for the merge request indicates a reduction in coverage of more than 10%. |
+| Code coverage down between 5% to 10% | Medium | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | Code coverage report for the merge request indicates a reduction in coverage of between 5% to 10%. |
+| Code coverage down between 1% to 5% | Low | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | Code coverage report for the merge request indicates a reduction in coverage of between 1% to 5%. |
+| Code coverage down less than 1% | Info | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | Code coverage report for the merge request indicates a reduction in coverage of less than 1%. |
-- Project name and [compliance framework label](../../project/settings/index.md#add-a-compliance-framework-to-a-project),
- if the project has one assigned.
-- Link to the merge request.
-- The merge request's branch path in the format `[source] into [target]`.
-- A list of users that committed changes to the merge request.
-- A list of users that commented on the merge request.
-- A list of users that approved the merge request.
-- The user that merged the merge request.
+<!-- vale gitlab.SubstitutionWarning = YES -->
-## Separation of duties
+##### Separation of duties
-We support a separation of duties policy between users who create and approve merge requests.
-Our criteria for the separation of duties is as follows:
+GitLab supports a separation of duties policy between users who create and approve merge requests. Our criteria for the
+separation of duties is:
-- [A merge request author is **not** allowed to approve their merge request](../../project/merge_requests/approvals/settings.md#prevent-approval-by-author)
-- [A merge request committer is **not** allowed to approve a merge request they have added commits to](../../project/merge_requests/approvals/settings.md#prevent-approvals-by-users-who-add-commits)
-- [The minimum number of approvals required to merge a merge request is **at least** two](../../project/merge_requests/approvals/rules.md)
+- [A merge request author is **not** allowed to approve their merge request](../../project/merge_requests/approvals/settings.md#prevent-approval-by-author).
+- [A merge request committer is **not** allowed to approve a merge request they have added commits to](../../project/merge_requests/approvals/settings.md#prevent-approvals-by-users-who-add-commits).
+- [The minimum number of approvals required to merge a merge request is **at least** two](../../project/merge_requests/approvals/rules.md).
-## Chain of Custody report
+### Chain of Custody report
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213364) in GitLab 13.3.
> - Chain of Custody reports sent using email [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342594) in GitLab 15.3 with a flag named `async_chain_of_custody_report`. Disabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/370100) in GitLab 15.5. Feature flag `async_chain_of_custody_report` removed.
> - Chain of Custody report includes all commits (instead of just merge commits) [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267601) in GitLab 15.9 with a flag named `all_commits_compliance_report`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112092) in GitLab 15.9. Feature flag `all_commits_compliance_report` removed.
-FLAG:
-On self-managed GitLab, by default the Chain of Custody report only contains information on merge commits. To make the report contain information on all commits to projects within a group, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `all_commits_compliance_report`. On GitLab.com, this feature is not available.
-
-The Chain of Custody report allows customers to export a list of merge commits within the group.
-The data provides a comprehensive view with respect to merge commits. It includes the merge commit SHA,
-merge request author, merge request ID, merge user, date merged, pipeline ID, group name, project name, and merge request approvers.
-Depending on the merge strategy, the merge commit SHA can be a merge commit, squash commit, or a diff head commit.
-
-With the `all_commits_compliance_report` flag enabled, the Chain of Custody report provides a 1 month trailing window of any commit into a project under the group.
+The Chain of Custody report provides a 1 month trailing window of all commits to a project under the group.
To generate the report for all commits, GitLab:
1. Fetches all projects under the group.
-1. For each project, fetches the last 1 month of commits. Each project is capped at 1024 commits. If there are more than 1024 commits in the 1-month window, they
- are truncated.
-1. Writes the commits to a CSV file. The file is truncated at 15 MB because the report is emailed as an attachment.
+1. For each project, fetches the last 1 month of commits. Each project is capped at 1024 commits. If there are more than
+ 1024 commits in the 1-month window, they are truncated.
+1. Writes the commits to a CSV file. The file is truncated at 15 MB because the report is emailed as an attachment
+ (GitLab 15.5 and later).
+
+The report includes:
+
+- Commit SHA.
+- Commit author.
+- Committer.
+- Date committed.
+- Group.
+- Project.
-The expanded report includes the commit SHA, commit author, committer, date committed, the group, and the project.
If the commit has a related merge commit, then the following are also included:
- Merge commit SHA.
@@ -124,39 +137,57 @@ If the commit has a related merge commit, then the following are also included:
- Pipeline ID.
- Merge request approvers.
+#### Generate Chain of Custody report
+
To generate the Chain of Custody report:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Security & Compliance > Compliance report**.
+1. On the left sidebar, select **Security and Compliance > Compliance report**.
1. Select **List of all merge commits**.
-The Chain of Custody report is either:
+Depending on your version of GitLab, the Chain of Custody report is either sent through email or available for download.
+
+#### Generate commit-specific Chain of Custody report
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267629) in GitLab 13.6.
+> - Support for including all commits instead of only merge commits [added](https://gitlab.com/gitlab-org/gitlab/-/issues/393446) in GitLab 15.10.
+
+You can generate a commit-specific Chain of Custody report for a given commit SHA. This report provides only the
+details for the provided commit SHA.
-- Available for download.
-- Sent through email. Requires GitLab 15.5 and later.
+To generate a commit-specific Chain of Custody report:
-### Commit-specific Chain of Custody report
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, select **Security and Compliance > Compliance report**.
+1. At the top of the compliance report, to the right of **List of all commits**, select the down arrow
+ (**{chevron-lg-down}**).
+1. Enter the commit SHA, and then select **Export commit custody report**.
+
+Depending on your version of GitLab, the Chain of Custody report is either sent through email or available for download.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267629) in GitLab 13.6.
+Alternatively, use a direct link: `https://gitlab.com/groups/<group-name>/-/security/merge_commit_reports.csv?commit_sha={optional_commit_sha}`,
+passing in an optional value to the `commit_sha` query parameter.
-Authenticated group owners can generate a commit-specific Chain of Custody report for a given commit SHA, either:
+## Compliance frameworks report
-- Using the GitLab UI:
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387910) in GitLab 15.10.
- 1. On the top bar, select **Main menu > Groups** and find your group.
- 1. On the left sidebar, select **Security & Compliance > Compliance report**.
- 1. At the top of the compliance report, to the right of **List of all merge commits**, select the down arrow (**{chevron-lg-down}**).
- 1. Enter the merge commit SHA, and then select **Export commit custody report**.
- SHA and then select **Export commit custody report**.
+With compliance frameworks report, you can see the compliance frameworks that are applied to projects in a group. Each row of the report shows:
-The Chain of Custody report is either:
+- Project name.
+- Project path.
+- Compliance framework label if the project has one assigned.
-- Available for download.
-- Sent through email. Requires GitLab 15.5 and later.
+The default framework for the group has a **default** badge.
-- Using a direct link: `https://gitlab.com/groups/<group-name>/-/security/merge_commit_reports.csv?commit_sha={optional_commit_sha}`, passing in an optional value to the
- `commit_sha` query parameter.
+### View the compliance frameworks report for a group
-NOTE:
-The Chain of Custody report download is a CSV file, with a maximum size of 15 MB.
-The remaining records are truncated when this limit is reached.
+Prerequisites:
+
+- You must be an administrator or have the Owner role for the group.
+
+To view the compliance frameworks report:
+
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, select **Security & Compliance > Compliance report**.
+1. On the page, select the **Frameworks** tab.
diff --git a/doc/user/compliance/img/license_approval_policy_v15_9.png b/doc/user/compliance/img/license_approval_policy_v15_9.png
index 43b1f89a07c..208643b47ae 100644
--- a/doc/user/compliance/img/license_approval_policy_v15_9.png
+++ b/doc/user/compliance/img/license_approval_policy_v15_9.png
Binary files differ
diff --git a/doc/user/compliance/license_approval_policies.md b/doc/user/compliance/license_approval_policies.md
index 32c90a1d317..2769732c49a 100644
--- a/doc/user/compliance/license_approval_policies.md
+++ b/doc/user/compliance/license_approval_policies.md
@@ -11,6 +11,18 @@ info: To determine the technical writer assigned to the Stage/Group associated w
License Approval Policies allow you to specify multiple types of criteria that define when approval is required before a merge request can be merged in.
+NOTE:
+License Approval Policies are applicable only to [protected](../project/protected_branches.md) target branches.
+
+The following video provides an overview of these policies.
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=34qBQ9t8qO8">Overview of GitLab License Approval Policies</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/34qBQ9t8qO8" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
## Create a new license approval policy
Create a license approval policy to enforce license compliance.
diff --git a/doc/user/compliance/license_check_rules.md b/doc/user/compliance/license_check_rules.md
index 968cf49ffdf..4280cfa0f5b 100644
--- a/doc/user/compliance/license_check_rules.md
+++ b/doc/user/compliance/license_check_rules.md
@@ -5,7 +5,7 @@ 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
---
-# License Check Policies (DEPRECATED) **(ULTIMATE)**
+# License Check Policies (deprecated) **(ULTIMATE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390417) in GitLab 15.9.
diff --git a/doc/user/compliance/license_compliance/index.md b/doc/user/compliance/license_compliance/index.md
index 43e88e89c18..55aa5b2b653 100644
--- a/doc/user/compliance/license_compliance/index.md
+++ b/doc/user/compliance/license_compliance/index.md
@@ -5,7 +5,7 @@ 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
---
-# License compliance (DEPRECATED) **(ULTIMATE)**
+# License compliance (deprecated) **(ULTIMATE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5483) in GitLab 11.0.
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387561) in GitLab 15.9.
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 483c15d648c..0ad73f9939d 100644
--- a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md
+++ b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md
@@ -16,12 +16,12 @@ To detect the licenses in use, License Compliance relies on running the
[Dependency Scanning CI Jobs](../../application_security/dependency_scanning/index.md),
and analyzing the [CycloneDX](https://cyclonedx.org/) Software Bill of Materials (SBOM) generated by those jobs.
Other 3rd party scanners may also be used as long as they produce a CycloneDX file with a list of dependencies for [one of our supported languages](#supported-languages-and-package-managers).
-This method of scanning is also capable of parsing and identifying over 500 different types of licenses
-and can extract license information from packages that are dual-licensed or have multiple different licenses that apply.
+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.
To enable license detection using Dependency Scanning in a project,
-include the `Jobs/Dependency-Scanning.yml` template in its CI configuration,
-but do not include the `Jobs/License-Scanning.yml` template.
+include the `Jobs/Dependency-Scanning.gitlab-ci.yml` template in its CI configuration,
+but do not include the `Jobs/License-Scanning.gitlab-ci.yml` template.
## Requirements
@@ -121,3 +121,23 @@ in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/6571).
## Blocking merge requests based on detected licenses
Users can require approval for merge requests based on the licenses that are detected by configuring a [license approval policy](../license_approval_policies.md).
+
+## Running in an offline environment
+
+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 licenses. For more information, see the offline [quick start guide](../../../topics/offline/quick_start_guide.md#enabling-the-package-metadata-database).
+
+## Troubleshooting
+
+### A CycloneDX file is not being scanned and appears to provide no results
+
+Ensure that the CycloneDX file adheres to the [CycloneDX JSON specification](https://cyclonedx.org/docs/latest/json). This specification does [not permit duplicate entries](https://cyclonedx.org/docs/latest/json/#components). Projects that contain multiple SBOM files should either report each SBOM file up as individual CI report artifacts or they should ensure that duplicates are removed if the SBOMs are merged as part of the CI pipeline.
+
+You can validate CycloneDX SBOM files against the `CycloneDX JSON specification` as follows:
+
+```shell
+$ docker run -it --rm -v "$PWD:/my-cyclonedx-sboms" -w /my-cyclonedx-sboms cyclonedx/cyclonedx-cli:latest cyclonedx validate --input-version v1_4 --input-file gl-sbom-all.cdx.json
+
+Validating JSON BOM...
+BOM validated successfully.
+```
diff --git a/doc/user/crm/index.md b/doc/user/crm/index.md
index ebacda506b4..54e87118361 100644
--- a/doc/user/crm/index.md
+++ b/doc/user/crm/index.md
@@ -1,6 +1,6 @@
---
-stage: Plan
-group: Certify
+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
---
diff --git a/doc/user/discussions/img/index_notes_filters.png b/doc/user/discussions/img/index_notes_filters.png
deleted file mode 100644
index 977a3770c05..00000000000
--- a/doc/user/discussions/img/index_notes_filters.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 9c9b5301460..c71ea6576ef 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -36,6 +36,8 @@ You can create comments in places like:
- Issues
- Merge requests
- Snippets
+- Tasks
+- OKRs
Each object can have as many as 5,000 comments.
@@ -46,12 +48,12 @@ instance with `@username` or `@groupname`. All mentioned users are notified with
Users can change this setting for themselves in the [notification settings](../profile/notifications.md).
You can quickly see which comments involve you, because
-mentions for yourself (the user currently signed in) are highlighted
+mentions for yourself (the user who is signed in) are highlighted
in a different color.
Avoid mentioning `@all` in issues and merge requests. It sends an email notification
-to all members of that project's parent group, not only the participants of the project,
-and may be interpreted as spam.
+to all members of that project's parent group, not only the participants of the project.
+It might be interpreted as spam.
Notifications and mentions can be disabled in
[a group's settings](../group/manage.md#disable-email-notifications).
@@ -89,8 +91,8 @@ The comment is not displayed on your project's **Repository > Commits** page.
NOTE:
When your comment contains a reference to a commit included in the merge request,
-it's automatically converted to a link in the context of the current merge request.
-For example, `28719b171a056960dfdc0012b625d0b47b123196` becomes
+it's converted to a link in the context of the merge request.
+For example, `28719b171a056960dfdc0012b625d0b47b123196` becomes `28719b17` that links to
`https://gitlab.example.com/example-group/example-project/-/merge_requests/12345/diffs?commit_id=28719b171a056960dfdc0012b625d0b47b123196`.
## Add a comment to a commit
@@ -203,41 +205,35 @@ You can also mark an [issue as confidential](../project/issues/confidential_issu
## Show only comments
-For issues and merge requests with many comments, you can filter the page to show comments only.
+In discussions with many comments, filter the discussion to show only comments or history of
+changes (system notes). System notes include changes to the description, mentions in other GitLab
+objects, or changes to labels, assignees, and the milestone.
+GitLab saves your preference, and applies it to every issue, merge request, or epic you view.
1. Open the **Overview** tab in a merge request, issue, or epic.
-1. On the right side of the page, select from the filter:
+1. On the right side of the page, from the **Sort or filter** dropdown list, select a filter:
- **Show all activity**: Display all user comments and system notes.
- (issue updates, mentions from other issues, changes to the description, and so on).
- **Show comments only**: Display only user comments.
- **Show history only**: Display only activity notes.
-![Notes filters dropdown list options](img/index_notes_filters.png)
+## Change activity sort order
-GitLab saves your preference, so it persists when you visit the same page again
-from any device you're logged into.
+Reverse the default order and interact with the activity feed sorted by most recent items
+at the top. GitLab saves your preference in local storage and applies it to every issue,
+merge request, or epic you view.
-## View description change history **(PREMIUM)**
+To change the activity sort order:
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10103) in GitLab 12.6.
+1. Open the **Overview** tab in a merge request, issue, or epic.
+1. On the right side of the page, from the **Sort or filter** dropdown list, select the sort order
+ **Newest first** or **Oldest first** (default).
+
+## View description change history **(PREMIUM)**
You can see changes to the description listed in the history.
To compare the changes, select **Compare with previous version**.
-## Change activity sort order
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14588) in GitLab 12.10.
-
-You can reverse the default order and interact with the activity feed sorted by most recent items
-at the top. Your preference is saved in local storage and automatically applies to every issue,
-merge request, or epic you view.
-
-To change the activity sort order:
-
-1. Select the **Oldest first** (or **Newest first**) dropdown list.
-1. Select either oldest or newest items to be shown first.
-
## Assign an issue to the commenting user
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/191455) in GitLab 13.1.
@@ -260,7 +256,7 @@ Prerequisites:
To create a thread by replying to a comment:
-1. In the upper right of the comment, select **Reply to comment** (**{comment}**).
+1. In the upper-right corner of the comment, select **Reply to comment** (**{comment}**).
![Reply to comment button](img/reply_to_comment_button.png)
@@ -283,7 +279,7 @@ Prerequisites:
To create a thread:
1. Enter a comment.
-1. Below the comment, to the right of the **Comment** button, select the down arrow (**{chevron-down}**).
+1. Below the comment, to the right of **Comment**, select the down arrow (**{chevron-down}**).
1. From the list, select **Start thread**.
1. Select **Start thread** again.
@@ -308,7 +304,7 @@ To resolve a thread:
1. Go to the thread.
1. Do one of the following:
- - In the upper right of the original comment, select **Resolve thread** (**{check-circle}**).
+ - 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 3daee460956..b6a823c656f 100644
--- a/doc/user/enterprise_user/index.md
+++ b/doc/user/enterprise_user/index.md
@@ -31,6 +31,45 @@ Although a user can be a member of more than one group, each user account can be
provisioned by only one group. As a result, a user is considered an enterprise
user under one top-level group only.
+## Verified domains for groups
+
+The following automated processes use [verified domains](../project/pages/custom_domains_ssl_tls_certification/index.md) to run:
+
+- [Bypass email confirmation for provisioned users](#bypass-email-confirmation-for-provisioned-users).
+
+### Set up a verified domain
+
+Prerequisites:
+
+- A project with [GitLab Pages](../project/pages/index.md), served under the default Pages domain `*.gitlab.io`.
+- A custom domain name `example.com` or subdomain `subdomain.example.com`.
+- Access to your domain's server control panel to set up a DNS `TXT` record to verify your domain's ownership.
+
+Setting up a verified domain is similar to [setting up a custom domain on GitLab Pages](../project/pages/custom_domains_ssl_tls_certification/index.md). However, you must:
+
+- Only configure the DNS `TXT` record to verify the domain's ownership.
+- Ignore instructions for the `A`, `CNAME`, and `ALIAS` records.
+
+1. [Add a custom domain](../project/pages/custom_domains_ssl_tls_certification/index.md#1-add-a-custom-domain) for the matching email domain.
+ - The domain must match the email domain exactly. For example, if your email is `username@example.com`, verify the `example.com` domain.
+1. [Get a verification code](../project/pages/custom_domains_ssl_tls_certification/index.md#2-get-the-verification-code).
+1. [Set up the DNS `TXT`](../project/pages/custom_domains_ssl_tls_certification/index.md#3-set-up-dns-records) for your custom domain.
+1. [Verify the domain's ownership](../project/pages/custom_domains_ssl_tls_certification/index.md#4-verify-the-domains-ownership).
+1. Optional. [Add more domain aliases](../project/pages/custom_domains_ssl_tls_certification/index.md#add-more-domain-aliases).
+
+### View domains in group
+
+To view all configured domains in your group:
+
+1. On the top bar, select **Main menu > Groups** and find your top-level group.
+1. On the left sidebar, select **Settings > Domain Verification**.
+
+You then see:
+
+- A list of added domains.
+- The domains' status of **Verified** or **Unverified**.
+- The project where the domain has been configured.
+
## Manage enterprise users in a namespace
A top-level Owner of a namespace on a paid plan can retrieve information about and
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index fb32c64f06c..4fb16d6ea27 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -125,20 +125,21 @@ Host gitlab.com
## GitLab Pages
-Below are the settings for [GitLab Pages](https://about.gitlab.com/stages-devops-lifecycle/pages/).
-
-| Setting | GitLab.com | Default |
-|---------------------------|------------------------|------------------------|
-| Domain name | `gitlab.io` | - |
-| IP address | `35.185.44.232` | - |
-| Custom domains support | **{check-circle}** Yes | **{dotted-circle}** No |
-| TLS certificates support | **{check-circle}** Yes | **{dotted-circle}** No |
-| [Maximum size](../../administration/pages/index.md#set-global-maximum-size-of-each-gitlab-pages-site) (compressed) | 1 GB | 100 MB |
-
-The maximum size of your Pages site is also regulated by the artifacts maximum size,
+Some settings for [GitLab Pages](../project/pages/index.md) differ from the
+[defaults for self-managed instances](../../administration/pages/index.md):
+
+| Setting | GitLab.com |
+|------------------------------|------------------------|
+| Domain name | `gitlab.io` |
+| IP address | `35.185.44.232` |
+| Support for custom domains | **{check-circle}** Yes |
+| Support for TLS certificates | **{check-circle}** Yes |
+| Maximum site size | 1 GB |
+
+The maximum size of your Pages site depends on the maximum artifact size,
which is part of [GitLab CI/CD](#gitlab-cicd).
-There are also [rate limits set for GitLab Pages](#gitlabcom-specific-rate-limits).
+[Rate limits](#gitlabcom-specific-rate-limits) also exist for GitLab Pages.
## GitLab CI/CD
@@ -175,7 +176,7 @@ varies by format:
| Generic | 5 GB |
| Helm | 5 MB |
| Maven | 5 GB |
-| npm: | 5 GB |
+| npm | 5 GB |
| NuGet | 5 GB |
| PyPI | 5 GB |
| Terraform | 1 GB |
@@ -247,7 +248,7 @@ The limit varies depending on your plan and the number of seats in your subscrip
| Setting | Default for GitLab.com |
|----------------------|-------------------------|
-| Number of webhooks | `100` per project, `50` per group |
+| Number of webhooks | `100` per project, `50` per group (subgroup webhooks are not counted towards parent group limits ) |
| Maximum payload size | 25 MB |
| Timeout | 10 seconds |
@@ -263,73 +264,6 @@ Runner SaaS is the hosted, secure, and managed build environment you can use to
For more information, see [Runner SaaS](../../ci/runners/index.md).
-## Sidekiq
-
-GitLab.com runs [Sidekiq](https://sidekiq.org) with arguments `--timeout=4 --concurrency=4`
-and the following environment variables:
-
-| Setting | GitLab.com | Default |
-|----------------------------------------|------------|-----------|
-| `GITLAB_MEMORY_WATCHDOG_ENABLED` | - | `true` |
-| `SIDEKIQ_MEMORY_KILLER_MAX_RSS` | - | `2000000` |
-| `SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS` | - | - |
-| `SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL` | - | `3` |
-| `SIDEKIQ_MEMORY_KILLER_GRACE_TIME` | - | `900` |
-| `SIDEKIQ_MEMORY_KILLER_SHUTDOWN_WAIT` | - | `30` |
-| `SIDEKIQ_LOG_ARGUMENTS` | `1` | `1` |
-
-For more information, see how to
-[configure the environment variables](../../administration/sidekiq/sidekiq_memory_killer.md).
-
-NOTE:
-The `SIDEKIQ_MEMORY_KILLER_MAX_RSS` setting is `16000000` on Sidekiq import
-nodes and Sidekiq export nodes.
-
-## PostgreSQL
-
-GitLab.com being a fairly large installation of GitLab means we have changed
-various PostgreSQL settings to better suit our needs. For example, we use
-streaming replication and servers in hot-standby mode to balance queries across
-different database servers.
-
-The list of GitLab.com specific settings (and their defaults) is as follows:
-
-| Setting | GitLab.com | Default |
-|:--------------------------------------|:--------------------------------------------------------------------|:--------------------------------------|
-| `archive_command` | `/usr/bin/envdir /etc/wal-e.d/env /opt/wal-e/bin/wal-e wal-push %p` | empty |
-| `archive_mode` | on | off |
-| `autovacuum_analyze_scale_factor` | 0.01 | 0.01 |
-| `autovacuum_max_workers` | 6 | 3 |
-| `autovacuum_vacuum_cost_limit` | 1000 | -1 |
-| `autovacuum_vacuum_scale_factor` | 0.01 | 0.02 |
-| `checkpoint_completion_target` | 0.7 | 0.9 |
-| `checkpoint_segments` | 32 | 10 |
-| `effective_cache_size` | 338688 MB | Based on how much memory is available |
-| `hot_standby` | on | off |
-| `hot_standby_feedback` | on | off |
-| `log_autovacuum_min_duration` | 0 | -1 |
-| `log_checkpoints` | on | off |
-| `log_line_prefix` | `%t [%p]: [%l-1]` | empty |
-| `log_min_duration_statement` | 1000 | -1 |
-| `log_temp_files` | 0 | -1 |
-| `maintenance_work_mem` | 2048 MB | 16 MB |
-| `max_replication_slots` | 5 | 0 |
-| `max_wal_senders` | 32 | 0 |
-| `max_wal_size` | 5 GB | 1 GB |
-| `shared_buffers` | 112896 MB | Based on how much memory is available |
-| `shared_preload_libraries` | `pg_stat_statements` | empty |
-| `shmall` | 30146560 | Based on the server's capabilities |
-| `shmmax` | 123480309760 | Based on the server's capabilities |
-| `wal_buffers` | 16 MB | -1 |
-| `wal_keep_segments` | 512 | 10 |
-| `wal_level` | replica | minimal |
-| `statement_timeout` | 15 s | 60 s |
-| `idle_in_transaction_session_timeout` | 60 s | 60 s |
-
-Some of these settings are in the process being adjusted. For example, the value
-for `shared_buffers` is quite high, and we are
-[considering adjusting it](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/4985).
-
## Puma
GitLab.com uses the default of 60 seconds for [Puma request timeouts](../../administration/operations/puma.md#change-the-worker-timeout).
@@ -497,7 +431,8 @@ and can't be configured on GitLab.com to expire. You can erase job logs
In addition to the GitLab Enterprise Edition Omnibus install, GitLab.com uses
the following applications and settings to achieve scale. All settings are
-publicly available at [chef cookbooks](https://gitlab.com/gitlab-cookbooks).
+publicly available, as [Kubernetes configuration](https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com)
+or [Chef cookbooks](https://gitlab.com/gitlab-cookbooks).
### Elastic cluster
@@ -541,3 +476,10 @@ Service discovery:
High Performance TCP/HTTP Load Balancer:
- [`gitlab-cookbooks` / `gitlab-haproxy` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-haproxy)
+
+## Sidekiq
+
+GitLab.com runs [Sidekiq](https://sidekiq.org) as an [external process](../../administration/sidekiq/index.md)
+for Ruby job scheduling.
+
+The current settings are in the [GitLab.com Kubernetes pod configuration](https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com/-/blob/master/releases/gitlab/values/gprd.yaml.gotmpl).
diff --git a/doc/user/group/access_and_permissions.md b/doc/user/group/access_and_permissions.md
index 4aecf016e56..0299f5c1a74 100644
--- a/doc/user/group/access_and_permissions.md
+++ b/doc/user/group/access_and_permissions.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
@@ -90,8 +90,8 @@ To restrict group access by IP address:
Keep in mind that restricting group access by IP address has the following implications:
-- Administrators and group owners can access group settings from any IP address, regardless of IP restriction. However:
- - Group owners can access the subgroups, but not the projects belonging to the group or subgroups, when accessing from a disallowed IP address.
+- Administrators and group Owners can access group settings from any IP address, regardless of IP restriction. However:
+ - Group Owners can access the subgroups, but not the projects belonging to the group or subgroups, when accessing from a disallowed IP address.
- Administrators can access projects belonging to the group when accessing from a disallowed IP address.
Access to projects includes cloning code from them.
- Users can still see group and project names and hierarchies. Only the following are restricted:
@@ -181,12 +181,12 @@ prevent a project from being shared with other groups:
1. Select **Projects in `<group_name>` cannot be shared with other groups**.
1. Select **Save changes**.
-This setting applies to all subgroups unless overridden by a group owner. Groups already
+This setting applies to all subgroups unless overridden by a group Owner. Groups already
added to a project lose access when the setting is enabled.
## Prevent users from requesting access to a group
-As a group owner, you can prevent non-members from requesting access to
+As a group Owner, you can prevent non-members from requesting access to
your group.
1. On the top bar, **Main menu > Groups** and find your group.
@@ -221,13 +221,13 @@ Existing forks are not removed.
## Prevent members from being added to projects in a group **(PREMIUM)**
-As a group owner, you can prevent any new project membership for all
+As a group Owner, you can prevent any new project membership for all
projects in a group, allowing tighter control over project membership.
For example, if you want to lock the group for an [Audit Event](../../administration/audit_events.md),
you can guarantee that project membership cannot be modified during the audit.
-If group membership lock is enabled, the group owner can still:
+If group membership lock is enabled, the group Owner can still:
- Invite groups or add members to groups to give them access to projects in the **locked** group.
- Change the role of group members.
@@ -286,7 +286,15 @@ 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 top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, select **Group information > Members**.
+1. On the left sidebar, select **Group information > Members**. If LDAP synchronization
+ has granted a user a role with:
+ - More permissions than the parent group membership, that user is displayed as having
+ [direct membership](../project/members/index.md#display-direct-members) of the group.
+ - The same or fewer permissions than the parent group membership, that user is displayed as having
+ [inherited membership](../project/members/index.md#display-inherited-members) of the group.
+1. Optional. If the user you want to edit is displayed as having inherited membership,
+ [filter the subgroup to show direct members](manage.md#filter-a-group) before
+ overriding LDAP user permissions.
1. In the row for the user you are editing, select the pencil (**{pencil}**) icon.
1. Select **Edit permissions** in the modal.
@@ -302,3 +310,17 @@ If a user sees a 404 when they would usually expect access, and the problem is l
- `json.allowed`: `false`
In viewing the log entries, compare `remote.ip` with the list of [allowed IP addresses](#restrict-group-access-by-ip-address) for the group.
+
+### Cannot update permissions for a group member
+
+If a group Owner cannot update permissions for a group member, check which memberships
+are listed. Group Owners can only update direct memberships.
+
+If a parent group membership has the same or higher role than a subgroup, the
+[inherited membership](../project/members/index.md#inherited-membership) is
+listed on the subgroup members page, even if a [direct membership](../project/members/index.md#membership-types)
+on the group exists.
+
+To view and update direct memberships, [filter the group to show direct members](manage.md#filter-a-group).
+
+The need to filter members by type through a redesigned members page that lists both direct and inherited memberships is proposed in [issue 337539](https://gitlab.com/gitlab-org/gitlab/-/issues/337539#note_1277786161).
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index cb760217487..a6dba3afacd 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -5,7 +5,7 @@ group: Configure
info: To 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-level Kubernetes clusters (certificate-based) (DEPRECATED) **(FREE)**
+# Group-level Kubernetes clusters (certificate-based) (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/34758) in GitLab 11.6.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/group/compliance_frameworks.md b/doc/user/group/compliance_frameworks.md
index 84cca5800c2..4ea474069cd 100644
--- a/doc/user/group/compliance_frameworks.md
+++ b/doc/user/group/compliance_frameworks.md
@@ -34,6 +34,10 @@ default framework cannot be deleted.
A compliance framework that is set to default has a **default** label.
+NOTE:
+Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/394630), only group owners can apply the default compliance framework when creating
+new projects or importing projects.
+
### Set and remove as default
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375038) in GitLab 15.7.
@@ -94,7 +98,8 @@ mutation {
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/331231) in GitLab 14.2.
Group owners can configure a compliance pipeline in a project separate to other projects. By default, the compliance
-pipeline configuration (`.gitlab-ci.yml` file) is run instead of the pipeline configuration of labeled projects.
+pipeline configuration (for example, `.compliance-gitlab-ci.yml`) is run instead of the pipeline configuration (for example, `.gitlab-ci.yml`) of labeled
+projects.
However, the compliance pipeline configuration can reference the `.gitlab-ci.yml` file of the labeled projects so that:
@@ -208,16 +213,47 @@ audit trail:
- "# No after scripts."
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
- project: '$CI_PROJECT_PATH'
- file: '$CI_CONFIG_PATH'
- ref: '$CI_COMMIT_SHA' # Must be defined or MR pipelines always use the use default branch
- rules:
- - if: $CI_PROJECT_PATH != "my-group/project-1" # Must be the hardcoded path to the project that hosts this configuration.
+ - project: '$CI_PROJECT_PATH'
+ file: '$CI_CONFIG_PATH'
+ ref: '$CI_COMMIT_SHA' # Must be defined or MR pipelines always use the use default branch
+ rules:
+ - if: $CI_PROJECT_PATH != "my-group/project-1" # Must be the hardcoded path to the project that hosts this configuration.
```
The `rules` configuration in the `include` definition avoids circular inclusion in case the compliance pipeline must be able to run in the host project itself.
You can leave it out if your compliance pipeline only ever runs in labeled projects.
+#### Compliance pipelines and custom pipeline configuration hosted externally
+
+The example above assumes that all projects host their pipeline configuration in the same project.
+If any projects use [configuration hosted externally to the project](../../ci/pipelines/settings.md#specify-a-custom-cicd-configuration-file):
+
+- The `include` section in the example compliance pipeline configuration must be adjusted.
+ For example, using [`include:rules`](../../ci/yaml/includes.md#use-rules-with-include):
+
+ ```yaml
+ include:
+ # If the custom path variables are defined, include the project's external config file.
+ - project: '$PROTECTED_PIPELINE_CI_PROJECT_PATH'
+ file: '$PROTECTED_PIPELINE_CI_CONFIG_PATH'
+ ref: '$PROTECTED_PIPELINE_CI_REF'
+ rules:
+ - if: $PROTECTED_PIPELINE_CI_PROJECT_PATH && $PROTECTED_PIPELINE_CI_CONFIG_PATH && $PROTECTED_PIPELINE_CI_REF
+ # If any custom path variable is not defined, include the project's internal config file as normal.
+ - project: '$CI_PROJECT_PATH'
+ file: '$CI_CONFIG_PATH'
+ ref: '$CI_COMMIT_SHA'
+ rules:
+ - if: $PROTECTED_PIPELINE_CI_PROJECT_PATH == null || $PROTECTED_PIPELINE_CI_CONFIG_PATH == null || $PROTECTED_PIPELINE_CI_REF == null
+ ```
+
+- [CI/CD variables](../../ci/variables/index.md) must be added to projects with external
+ pipeline configuration. In this example:
+
+ - `PROTECTED_PIPELINE_CI_PROJECT_PATH`: The path to the project hosting the configuration file, for example `group/subgroup/project`.
+ - `PROTECTED_PIPELINE_CI_CONFIG_PATH`: The path to the configuration file in the project, for example `path/to/.gitlab-ci.yml`.
+ - `PROTECTED_PIPELINE_CI_REF`: The ref to use when retrieving the configuration file, for example `main`.
+
#### Compliance pipelines in merge requests originating in project forks
When a merge request originates in a fork, the branch to be merged usually only exists in the fork.
diff --git a/doc/user/group/contribution_analytics/img/group_stats_cal.png b/doc/user/group/contribution_analytics/img/group_stats_cal.png
deleted file mode 100644
index 0238c7bf088..00000000000
--- a/doc/user/group/contribution_analytics/img/group_stats_cal.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/group/contribution_analytics/img/group_stats_table.png b/doc/user/group/contribution_analytics/img/group_stats_table.png
deleted file mode 100644
index 1f58b9717d0..00000000000
--- a/doc/user/group/contribution_analytics/img/group_stats_table.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/group/custom_project_templates.md b/doc/user/group/custom_project_templates.md
index 2716db27037..d205e834e60 100644
--- a/doc/user/group/custom_project_templates.md
+++ b/doc/user/group/custom_project_templates.md
@@ -42,7 +42,7 @@ Projects in nested subgroups are not included in the template list.
- 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)
- except for **GitLab Pages** and **Security & Compliance** are set to **Everyone With Access**.
+ 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.
## Example structure
diff --git a/doc/user/group/epics/epic_boards.md b/doc/user/group/epics/epic_boards.md
index 64addd524ad..6ec56d0d510 100644
--- a/doc/user/group/epics/epic_boards.md
+++ b/doc/user/group/epics/epic_boards.md
@@ -18,7 +18,7 @@ To view an epic board:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Epics > Boards**.
-![GitLab epic board - Premium](img/epic_board_v14_1.png)
+![GitLab epic board - Premium](img/epic_board_v15_10.png)
## Create an epic board
@@ -30,7 +30,7 @@ To create a new epic board:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Epics > Boards**.
-1. In the upper left corner, select the dropdown list with the current board name.
+1. In the upper-left corner, select the dropdown list with the current board name.
1. Select **Create new board**.
1. Enter the new board's title.
1. Optional. To hide the Open or Closed lists, clear the **Show the Open list** and
@@ -54,7 +54,7 @@ Prerequisites:
To delete the active epic board:
-1. Select the dropdown list with the current board name in the upper left corner of the epic boards page.
+1. In the upper-left corner of the epic board page, select the dropdown list.
1. Select **Delete board**.
1. Select **Delete**.
@@ -115,7 +115,7 @@ To create an epic from a list in epic board:
1. Enter the new epic's title.
1. Select **Create epic**.
-![Create a GitLab epic from an epic board](img/epic_board_epic_create_v14_1.png)
+![Create a GitLab epic from an epic board](img/epic_board_epic_create_v15_10.png)
### Filter epics
@@ -216,3 +216,15 @@ To edit the scope of an epic board:
- Show or hide the Open and Closed columns.
- Select other labels as the board's scope.
1. Select **Save changes**.
+
+#### Display total weight on board lists
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/364503) in GitLab 15.1 [with a flag](../../../administration/feature_flags.md) named `fe_epic_board_total_weight`. Disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/364503) in GitLab 15.9.
+> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/364503) in GitLab 15.10.
+
+FLAG:
+On self-managed GitLab, by default this feature is available. To hide the feature, ask an administrator to [disable the feature flag](../../../administration/feature_flags.md) named `fe_epic_board_total_weight`.
+On GitLab.com, this feature is available.
+
+When enabled, this feature displays total weight of all epics at the top of each list.
diff --git a/doc/user/group/epics/img/epic_board_epic_create_v14_1.png b/doc/user/group/epics/img/epic_board_epic_create_v14_1.png
deleted file mode 100644
index 04017014885..00000000000
--- a/doc/user/group/epics/img/epic_board_epic_create_v14_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/group/epics/img/epic_board_epic_create_v15_10.png b/doc/user/group/epics/img/epic_board_epic_create_v15_10.png
new file mode 100644
index 00000000000..71d1fc0a9fc
--- /dev/null
+++ b/doc/user/group/epics/img/epic_board_epic_create_v15_10.png
Binary files differ
diff --git a/doc/user/group/epics/img/epic_board_v14_1.png b/doc/user/group/epics/img/epic_board_v14_1.png
deleted file mode 100644
index ccf1ef9559e..00000000000
--- a/doc/user/group/epics/img/epic_board_v14_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/group/epics/img/epic_board_v15_10.png b/doc/user/group/epics/img/epic_board_v15_10.png
new file mode 100644
index 00000000000..d836abdbb59
--- /dev/null
+++ b/doc/user/group/epics/img/epic_board_v15_10.png
Binary files differ
diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md
index 74cfa2bd6ed..3a0fc86e803 100644
--- a/doc/user/group/epics/manage_epics.md
+++ b/doc/user/group/epics/manage_epics.md
@@ -41,8 +41,6 @@ The newly created epic opens.
### Start and due date inheritance
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7332) in GitLab 12.5 to replace **From milestones**.
-
If you select **Inherited**:
- For the **start date**: GitLab scans all child epics and issues assigned to the epic,
@@ -52,7 +50,7 @@ If you select **Inherited**:
and sets the due date to match the latest due date found in the child epics or the milestone
assigned to the issues.
-These are dynamic dates and recalculated if any of the following occur:
+These dates are dynamic and recalculated if any of the following occur:
- A child epic's dates change.
- Milestones are reassigned to an issue.
@@ -123,8 +121,6 @@ To reorder list items, when viewing an epic:
## Bulk edit epics
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7250) in GitLab 12.2.
-
Users with at least the Reporter role can manage epics.
When bulk editing epics in a group, you can edit their labels.
@@ -233,7 +229,6 @@ than 1000. The cached value is rounded to thousands or millions and updated ever
## Filter the list of epics
-> - Filtering by epics was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/195704) in GitLab 12.9.
> - Filtering by child epics was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9029) in GitLab 13.0.
> - Filtering by the user's reaction emoji [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325630) in GitLab 13.11.
> - Sorting by epic titles [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/331625) in GitLab 14.1.
@@ -341,7 +336,7 @@ in relation to epics.
### View issues assigned to an epic
-On the **Epics and Issues** tab, you can see epics and issues assigned to this epic.
+On the **Child issues and epics** section, you can see epics and issues assigned to this epic.
Only epics and issues that you can access show on the list.
You can always view the issues assigned to the epic if they are in the group's child project.
@@ -350,7 +345,7 @@ of its parent group.
### View count of issues in an epic
-On the **Epics and Issues** tab, under each epic name, hover over the total counts.
+On the **Child issues and epics** section, under each epic name, hover over the total counts.
The number indicates all epics associated with the project, including issues
you might not have permission to.
@@ -365,7 +360,7 @@ automatically added to the epic.
> Minimum required role for the project [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/382506) from Reporter to Guest in GitLab 15.8.
You can add existing issues to an epic, including issues in a project from a [different group hierarchy](index.md#child-issues-from-different-group-hierarchies).
-Newly added issues appear at the top of the list of issues in the **Epics and Issues** tab.
+Newly added issues appear at the top of the list of issues in the **Child issues and epics** section.
An epic contains a list of issues and an issue can be associated with at most one epic.
When you add a new issue that's already linked to an epic, the issue is automatically unlinked from its
@@ -377,13 +372,13 @@ Prerequisites:
To add an existing issue to an epic:
-1. On the epic's page, under **Epics and Issues**, select **Add**.
+1. On the epic's page, under **Child issues and epics**, select **Add**.
1. Select **Add an existing issue**.
1. Identify the issue to be added, using either of the following methods:
- Paste the link of the issue.
- Search for the desired issue by entering part of the issue's title, then selecting the desired
- match ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9126) in GitLab 12.5). Issues
- from different group hierarchies do not appear in search results. To add such an issue, enter its full URL.
+ match. Issues from different group hierarchies do not appear in search results.
+ To add such an issue, enter its full URL.
If there are multiple issues to be added, press <kbd>Space</kbd> and repeat this step.
1. Select **Add**.
@@ -401,7 +396,7 @@ Prerequisites:
To create an issue from an epic:
-1. On the epic's page, under **Epics and Issues**, select **Add**.
+1. On the epic's page, under **Child issues and epics**, select **Add**.
1. Select **Add a new issue**.
1. Under **Title**, enter the title for the new issue.
1. From the **Project** dropdown list, select the project in which the issue should be created.
@@ -430,10 +425,9 @@ To remove an issue from an epic:
### Reorder issues assigned to an epic
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9367) in GitLab 12.5.
-> - Minimum required role for the project [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/382506) from Reporter to Guest in GitLab 15.8.
+> Minimum required role for the project [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/382506) from Reporter to Guest in GitLab 15.8.
-New issues appear at the top of the list in the **Epics and Issues** tab.
+New issues appear at the top of the list in the **Child issues and epics** section.
You can reorder the list of issues by dragging them.
Prerequisites:
@@ -442,7 +436,7 @@ Prerequisites:
To reorder issues assigned to an epic:
-1. Go to the **Epics and Issues** tab.
+1. Go to the **Child issues and epics** section.
1. Drag issues into the desired order.
### Move issues between epics **(ULTIMATE)**
@@ -450,7 +444,7 @@ To reorder issues assigned to an epic:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33039) in GitLab 13.0.
> - Minimum required role for the project [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/382506) from Reporter to Guest in GitLab 15.8.
-New issues appear at the top of the list in the **Epics and Issues**
+New issues appear at the top of the list in the **Child issues and epics**
tab. You can move issues from one epic to another.
Prerequisites:
@@ -459,13 +453,12 @@ Prerequisites:
To move an issue to another epic:
-1. Go to the **Epics and Issues** tab.
+1. Go to the **Child issues and epics** section.
1. Drag issues into the desired parent epic in the visible hierarchy.
### Promote an issue to an epic
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3777) in GitLab 11.6.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/37081) from GitLab Ultimate to GitLab Premium in 12.8.
+> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/37081) from GitLab Ultimate to GitLab Premium in 12.8.
Prerequisites:
@@ -504,12 +497,12 @@ You can create a spreadsheet template to manage a pattern of consistently repeat
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an introduction to epic templates, see [GitLab Epics and Epic Template Tip](https://www.youtube.com/watch?v=D74xKFNw8vg).
-For more on epic templates, see [Epic Templates - Repeatable sets of issues](https://about.gitlab.com/handbook/marketing/strategic-marketing/getting-started/104/).
+For more on epic templates, see [Epic Templates - Repeatable sets of issues](https://about.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/getting-started/104/).
## Multi-level child epics **(ULTIMATE)**
You can add any epic that belongs to a group or subgroup of the parent epic's group.
-New child epics appear at the top of the list of epics in the **Epics and Issues** tab.
+New child epics appear at the top of the list of epics in the **Child issues and epics** section.
When you add an epic that's already linked to a parent epic, the link to its current parent is removed.
@@ -522,11 +515,7 @@ The maximum number of direct child epics is 100.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8502) in GitLab 15.6 [with a flag](../../../administration/feature_flags.md) named `child_epics_from_different_hierarchies`. Disabled by default.
> - Minimum required role for the group [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/382503) from Reporter to Guest in GitLab 15.7.
> - Cross-group child epics [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/375622) in GitLab 15.9. Enabled by default.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To disable it,
-ask an administrator to [disable the feature flag](../../../administration/feature_flags.md) named `child_epics_from_different_hierarchies`.
-On GitLab.com, this feature is available.
+> - [Feature flag `child_epics_from_different_hierarchies`](https://gitlab.com/gitlab-org/gitlab/-/issues/382719) removed in GitLab 15.10.
You can add a child epic that belongs to a group that is different from the parent epic's group.
@@ -548,7 +537,7 @@ Prerequisites:
To add a new epic as child epic:
1. In an epic, in the **Child issues and epics** section, select **Add > Add a new epic**.
-1. Select a group from the dropdown. The epic's group is selected by default.
+1. Select a group from the dropdown list. The epic's group is selected by default.
1. Enter a title for the new epic.
1. Select **Create epic**.
@@ -557,7 +546,7 @@ To add an existing epic as child epic:
1. In an epic, in the **Child issues and epics** section, select **Add > Add an existing epic**.
1. Identify the epic to be added, using either of the following methods:
- Paste the link of the epic.
- - Search for the desired issue by entering part of the epic's title, then selecting the desired match. This search is only available for epics within the same group hierarchy.
+ - Search for the desired issue by entering part of the epic's title, then selecting the desired match. This search is only available for epics in the same group hierarchy.
If there are multiple epics to be added, press <kbd>Space</kbd> and repeat this step.
1. Select **Add**.
@@ -567,7 +556,7 @@ To add an existing epic as child epic:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33039) in GitLab 13.0.
> - Minimum required role for the group [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/382503) from Reporter to Guest in GitLab 15.7.
-New child epics appear at the top of the list in the **Epics and Issues** tab.
+New child epics appear at the top of the list in the **Child issues and epics** section.
You can move child epics from one epic to another.
When you add a new epic that's already linked to a parent epic, the link to its current parent is removed.
Issues and child epics cannot be intermingled.
@@ -578,15 +567,14 @@ Prerequisites:
To move child epics to another epic:
-1. Go to the **Epics and Issues** tab.
+1. Go to the **Child issues and epics** section.
1. Drag epics into the desired parent epic.
### Reorder child epics assigned to an epic
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9367) in GitLab 12.5.
-> - Minimum required role for the group [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/382503) from Reporter to Guest in GitLab 15.7.
+> Minimum required role for the group [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/382503) from Reporter to Guest in GitLab 15.7.
-New child epics appear at the top of the list in the **Epics and Issues** tab.
+New child epics appear at the top of the list in the **Child issues and epics** section.
You can reorder the list of child epics.
Prerequisites:
@@ -595,7 +583,7 @@ Prerequisites:
To reorder child epics assigned to an epic:
-1. Go to the **Epics and Issues** tab.
+1. Go to the **Child issues and epics** section.
1. Drag epics into the desired order.
### Remove a child epic from a parent epic
diff --git a/doc/user/group/import/index.md b/doc/user/group/import/index.md
index eb32856ff79..b0297076a43 100644
--- a/doc/user/group/import/index.md
+++ b/doc/user/group/import/index.md
@@ -27,42 +27,55 @@ If you migrate from GitLab.com to self-managed GitLab, an administrator can crea
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267945) in GitLab 14.4 for project resources [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.
> - New application setting `bulk_import_enabled` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383268) in GitLab 15.8. `bulk_import` feature flag removed.
+> - `bulk_import_projects` feature flag [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/339941) in GitLab 15.10.
-FLAG:
On self-managed GitLab, by default [migrating group items](#migrated-group-items) is not available. To show the
feature, ask an administrator to [enable it in application settings](../../admin_area/settings/visibility_and_access_controls.md#enable-migration-of-groups-and-projects-by-direct-transfer).
-Also on self-managed GitLab, by default [migrating project items](#migrated-project-items-beta) is not available. To show
-this feature, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named
-`bulk_import_projects`. The feature is not ready for production use. On GitLab.com, migration of both groups and projects is available.
Migrating groups by direct transfer copies the groups from one place to another. You can:
- Copy many groups at once.
-- Copy top-level groups to:
+- In the GitLab UI, copy top-level groups to:
- Another top-level group.
- The subgroup of any existing top-level group.
- Another GitLab instance, including GitLab.com.
+- In the [API](../../../api/bulk_imports.md), copy top-level groups and subgroups to these locations.
- Copy groups with projects (in [beta](../../../policy/alpha-beta-support.md#beta-features) and not ready for production
use) or without projects. Copying projects with groups is available:
- On GitLab.com by default.
- - On self-managed GitLab instances after an administrator first [enables the feature flag](../../../administration/feature_flags.md) named `bulk_import_projects`.
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).
+WARNING:
+Importing groups with projects is in [beta](../../../policy/alpha-beta-support.md#beta-features). This feature is not
+ready for production use.
+
We invite you to leave your feedback about migrating by direct transfer in
[the feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/284495).
If you want to move groups instead of copying groups, you can [transfer groups](../manage.md#transfer-a-group) if the
groups are in the same GitLab instance. Transferring groups is a faster and more complete option.
-### Rate limit
+### Known issues
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386452) in GitLab 15.9.
+See [epic 6629](https://gitlab.com/groups/gitlab-org/-/epics/6629) for a list of known issues for migrating by direct
+transfer.
-Each user can perform up to six migrations per minute.
+### Limits
+
+| Limit | Description |
+|:------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| 6 | Maximum number of migrations permitted by a destination GitLab instance per minute per user. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386452) in GitLab 15.9. |
+| 5 GB | Maximum relation size that can be downloaded from the source instance. |
+| 10 GB | Maximum size of a decompressed archive. |
+| 210 seconds | Maximum number of seconds to wait for decompressing an archive file. |
+| 50 MB | Maximum length an NDJSON row can have. |
+| 5 minutes | Maximum number of seconds until an empty export status on source instance is raised. |
+| 8 hours | Time until migration times out. |
+| 90 minutes | Time the destination is waiting for export to complete. |
### Visibility rules
@@ -100,16 +113,15 @@ To migrate groups by direct transfer:
To ensure GitLab maps users and their contributions correctly:
-1. Create the required users on the destination GitLab instance. When migrating to GitLab.com, you must create users
- manually unless [SCIM](../../group/saml_sso/scim_setup.md) is used. Creating users with the API is only available to
- self-managed instances because it requires administrator access.
-1. Check that users have a public email on the source GitLab instance that matches their primary email on the
- destination GitLab instance.
-1. Ensure that users confirm their primary email addresses on the destination GitLab instance. Most users receive an
- email asking them to confirm their email address.
-1. If using an OmniAuth provider like SAML, link GitLab and SAML accounts of users on GitLab. All users on the
- destination GitLab instance must sign in and verify their account on the destination GitLab instance. If using
- [SAML SSO for GitLab.com groups](../../group/saml_sso/index.md), users must
+1. Create the required users on the destination GitLab instance. You can create users with the API only on self-managed instances because it requires
+ administrator access. When migrating to GitLab.com or a self-managed GitLab instance you can:
+ - Create users manually.
+ - Set up or use your existing [SAML SSO provider](../saml_sso/index.md) and leverage user synchronization of SAML SSO groups supported through
+ [SCIM](../../group/saml_sso/scim_setup.md). You can
+ [bypass the GitLab user account verification with verified email domains](../saml_sso/index.md#bypass-user-email-confirmation-with-verified-domains).
+1. Ensure that users have a public email on the source GitLab instance that matches any confirmed email address on the destination GitLab instance. Most
+ users receive an email asking them to confirm their email address.
+1. If users already exist on the destination instance and you use [SAML SSO for GitLab.com groups](../../group/saml_sso/index.md), all users must
[link their SAML identity to their GitLab.com account](../../group/saml_sso/index.md#linking-saml-to-your-existing-gitlabcom-account).
### Connect the source GitLab instance
@@ -135,12 +147,15 @@ role.
1. By default, the proposed group namespaces match the names as they exist in source instance, but based on your permissions, you can choose to edit these names before you proceed to import any of them.
1. Next to the groups you want to import, select either:
- - **Import with projects**. Importing groups with projects is in [Beta](../../../policy/alpha-beta-support.md#beta-features). This feature is not ready for production use.
+ - **Import with projects**.
- **Import without projects**.
- - **Import** on self-managed GitLab, when the `bulk_import_projects` feature flag is disabled and the feature is not available.
1. The **Status** column shows the import status of each group. If you leave the page open, it updates in real-time.
1. After a group has been imported, select its GitLab path to open its GitLab URL.
+WARNING:
+Importing groups with projects is in [beta](../../../policy/alpha-beta-support.md#beta-features). This feature is not
+ready for production use.
+
### Group import history
You can view all groups migrated by you by direct transfer listed on the group import history page. This list includes:
@@ -157,108 +172,154 @@ To view group import history:
1. On the top bar, select **Create new…** (**{plus-square}**).
1. Select **New group**.
1. Select **Import group**.
-1. Select **History** in the upper right corner.
+1. In the upper-right corner, select **History**.
1. If there are any errors for a particular import, you can see them by selecting **Details**.
### Migrated group items
-The [`import_export.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/import_export/group/import_export.yml)
-file for groups lists many of the items imported when migrating groups by direct transfer. View this file in the branch
-for your version of GitLab to see the list of items relevant to you. For example,
-[`import_export.yml` on the `14-10-stable-ee` branch](https://gitlab.com/gitlab-org/gitlab/-/blob/14-10-stable-ee/lib/gitlab/import_export/group/import_export.yml).
+The group items that are migrated depend on the version of GitLab you use on the destination. To determine if a
+specific group item is migrated:
+
+1. Check the [`groups/stage.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/bulk_imports/groups/stage.rb)
+ file for all editions and the
+ [`groups/stage.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/ee/bulk_imports/groups/stage.rb) file
+ for Enterprise Edition for your version on the destination. For example, for version 15.9:
+ - <https://gitlab.com/gitlab-org/gitlab/-/blob/15-9-stable-ee/lib/bulk_imports/groups/stage.rb> (all editions).
+ - <https://gitlab.com/gitlab-org/gitlab/-/blob/15-9-stable-ee/ee/lib/ee/bulk_imports/groups/stage.rb> (Enterprise
+ Edition).
+1. Check the
+ [`group/import_export.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/import_export/group/import_export.yml)
+ file for groups for your version on the destination. For example, for version 15.9:
+ <https://gitlab.com/gitlab-org/gitlab/-/blob/15-9-stable-ee/lib/gitlab/import_export/group/import_export.yml>.
+
+Any other group items are **not** migrated.
Group items that are migrated to the destination GitLab instance include:
-- Badges ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292431) in 13.11)
-- Board Lists
-- Boards
-- Epics ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250281) in 13.7)
- - Epic resource state events ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) in GitLab 15.4)
-- Finisher
-- Group Labels ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292429) in 13.9)
-- Iterations ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292428) in 13.10)
-- Iterations cadences ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96570) in 15.4)
-- Members ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/299415) in 13.9)
- Group members are associated with the imported group if:
- - The user already exists in the destination GitLab instance and
- - The user has a public email in the source GitLab instance that matches a
- confirmed email in the destination GitLab instance
-- Milestones ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292427) in 13.10)
-- Namespace Settings
-- Releases
- - Milestones ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339422) in GitLab 15.0).
-- Subgroups
-- Uploads
-
-Any other items are **not** migrated.
+| Group item | Introduced in |
+|:---------------------|:----------------------------------------------------------------------------|
+| Badges | [GitLab 13.11](https://gitlab.com/gitlab-org/gitlab/-/issues/292431) |
+| Boards | [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18938) |
+| Board lists | [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24863) |
+| Epics <sup>1</sup> | [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/issues/250281) |
+| Group labels | [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/292429) |
+| Iterations | [GitLab 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/292428) |
+| Iteration cadences | [GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96570) |
+| Members <sup>2</sup> | [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/299415) |
+| Group milestones | [GitLab 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/292427) |
+| Namespace settings | [GitLab 14.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85128) |
+| Release milestones | [GitLab 15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/339422) |
+| Subgroups | [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18938) |
+| Uploads | [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18938) |
+
+1. Epic resource state events [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) in GitLab 15.4, label
+ associations [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62074) in GitLab 13.12, state and
+ state ID [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28203) in GitLab 13.7, and system note
+ metadata [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63551) in GitLab 14.0.
+1. Group members are associated with the imported group if the user:
+ - Already exists in the destination GitLab instance.
+ - Has a public email in the source GitLab instance that matches a confirmed email in the destination GitLab instance.
### 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.
+> - `bulk_import_projects` feature flag [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/339941) in GitLab 15.10.
-FLAG:
-On self-managed GitLab, migrating project resources when migrating groups is not available by default.
-To make it available ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named
-`bulk_import_projects`. On GitLab.com, groups are migrated with all their projects by default.
+The project items that are migrated depends on the version of GitLab you use on the destination. To determine if a
+specific project item is migrated:
-The [`import_export.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/import_export/project/import_export.yml)
-file for projects lists many of the items imported when migrating projects using group migration. View this file in the branch
-for your version of GitLab to see the list of items relevant to you. For example,
-[`import_export.yml` on the `14-10-stable-ee` branch](https://gitlab.com/gitlab-org/gitlab/-/blob/14-10-stable-ee/lib/gitlab/import_export/project/import_export.yml).
+1. Check the [`projects/stage.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/bulk_imports/projects/stage.rb)
+ file for all editions and the
+ [`projects/stage.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/ee/bulk_imports/projects/stage.rb)
+ file for Enterprise Edition for your version on the destination. For example, for version 15.9:
+ - <https://gitlab.com/gitlab-org/gitlab/-/blob/15-9-stable-ee/lib/bulk_imports/projects/stage.rb> (all editions).
+ - <https://gitlab.com/gitlab-org/gitlab/-/blob/15-9-stable-ee/ee/lib/ee/bulk_imports/projects/stage.rb> (Enterprise
+ Edition).
+1. Check the
+ [`project/import_export.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/import_export/project/import_export.yml)
+ file for projects for your version on the destination. For example, for version 15.9:
+ <https://gitlab.com/gitlab-org/gitlab/-/blob/15-9-stable-ee/lib/gitlab/import_export/project/import_export.yml>.
+
+Any other project items are **not** migrated.
WARNING:
-Migrating projects when migrating groups by direct transfer is in [Beta](../../../policy/alpha-beta-support.md#beta-features)
+Migrating projects when migrating groups by direct transfer is in [beta](../../../policy/alpha-beta-support.md#beta-features)
and is not ready for production use.
Project items that are migrated to the destination GitLab instance include:
-- Projects ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267945) in GitLab 14.4)
- - Auto DevOps ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339410) in GitLab 14.6)
- - Badges ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75029) in GitLab 14.6)
- - Branches (including protected branches) ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339414) in GitLab 14.7)
- - CI Pipelines ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339407) in GitLab 14.6)
- - Designs ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339421) in GitLab 15.1)
- - Issues ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267946) in GitLab 14.4)
- - Issue iteration ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96184) in 15.4)
- - Issue resource state events ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) in GitLab 15.4)
- - Issue resource milestone events ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) in GitLab 15.4)
- - Issue resource iteration events ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) in GitLab 15.4)
- - Merge request URL references ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267947) in GitLab 15.6)
- - Time Tracking ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267946) in GitLab 14.4)
- - Issue boards ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71661) in GitLab 14.4)
- - Labels ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339419) in GitLab 14.4)
- - LFS Objects ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339405) in GitLab 14.8)
- - Members ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/341886) in GitLab 14.8)
- - Merge Requests ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339403) in GitLab 14.5)
- - Multiple merge request assignees ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339520) in GitLab 15.3)
- - Merge request reviewers ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339520) in GitLab 15.3)
- - Merge request approvers ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339520) in GitLab 15.3)
- - Merge request resource state events ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) in GitLab 15.4)
- - Merge request resource milestone events ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) in GitLab 15.4)
- - Issue URL references ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267947) in GitLab 15.6)
- - Time Tracking ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339403) in GitLab 14.5)
- - Push Rules ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339403) in GitLab 14.6)
- - Milestones ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339417) in GitLab 14.5)
- - External Pull Requests ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339409) in GitLab 14.5)
- - Pipeline History ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339412) in GitLab 14.6)
- - Pipeline Schedules ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339408) in GitLab 14.8)
- - Project Features ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74722) in GitLab 14.6)
- - Releases ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339422) in GitLab 15.1)
- - Release Evidences ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/360567) in GitLab 15.1)
- - Repositories ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267945) in GitLab 14.4)
- - Snippets ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/343438) in GitLab 14.6)
- - Settings ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339416) in GitLab 14.6)
- - Avatar ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75249) in GitLab 14.6)
- - Container Expiration Policy ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75653) in GitLab 14.6)
- - Project Properties ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75898) in GitLab 14.6)
- - Service Desk ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75653) in GitLab 14.6)
- - Uploads ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339401) in GitLab 14.5)
- - Wikis ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345923) in GitLab 14.6)
-
-Items excluded from migration, because they contain sensitive information:
-
-- Pipeline Triggers.
+| Project item | Introduced in |
+|:----------------------------------------|:---------------------------------------------------------------------------|
+| Projects | [GitLab 14.4](https://gitlab.com/gitlab-org/gitlab/-/issues/267945) |
+| Auto DevOps | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/339410) |
+| Badges | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75029) |
+| Branches (including protected branches) | [GitLab 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/339414) |
+| CI Pipelines | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/339407) |
+| Designs | [GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/339421) |
+| Issues | [GitLab 14.4](https://gitlab.com/gitlab-org/gitlab/-/issues/267946) |
+| Issue boards | [GitLab 14.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71661) |
+| Labels | [GitLab 14.4](https://gitlab.com/gitlab-org/gitlab/-/issues/339419) |
+| LFS Objects | [GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/339405) |
+| Members | [GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/341886) |
+| Merge requests | [GitLab 14.5](https://gitlab.com/gitlab-org/gitlab/-/issues/339403) |
+| Push rules | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/339403) |
+| Milestones | [GitLab 14.5](https://gitlab.com/gitlab-org/gitlab/-/issues/339417) |
+| External pull requests | [GitLab 14.5](https://gitlab.com/gitlab-org/gitlab/-/issues/339409) |
+| Pipeline history | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/339412) |
+| Pipeline schedules | [GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/339408) |
+| Project features | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74722) |
+| Releases | [GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/339422) |
+| Release evidences | [GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/360567) |
+| Repositories | [GitLab 14.4](https://gitlab.com/gitlab-org/gitlab/-/issues/267945) |
+| Snippets | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/343438) |
+| Settings | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/339416) |
+| Uploads | [GitLab 14.5](https://gitlab.com/gitlab-org/gitlab/-/issues/339401) |
+| Wikis | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/345923) |
+
+#### Issue-related items
+
+Issue-related project items that are migrated to the destination GitLab instance include:
+
+| Issue-related project item | Introduced in |
+|:--------------------------------|:---------------------------------------------------------------------------|
+| Issue iterations | [GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96184) |
+| Issue resource state events | [GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) |
+| Issue resource milestone events | [GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) |
+| Issue resource iteration events | [GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) |
+| Merge request URL references | [GitLab 15.6](https://gitlab.com/gitlab-org/gitlab/-/issues/267947) |
+| Time tracking | [GitLab 14.4](https://gitlab.com/gitlab-org/gitlab/-/issues/267946) |
+
+#### Merge request-related items
+
+Merge request-related project items that are migrated to the destination GitLab instance include:
+
+| Merge request-related project item | Introduced in |
+|:----------------------------------------|:--------------------------------------------------------------------|
+| Multiple merge request assignees | [GitLab 15.3](https://gitlab.com/gitlab-org/gitlab/-/issues/339520) |
+| Merge request reviewers | [GitLab 15.3](https://gitlab.com/gitlab-org/gitlab/-/issues/339520) |
+| Merge request approvers | [GitLab 15.3](https://gitlab.com/gitlab-org/gitlab/-/issues/339520) |
+| Merge request resource state events | [GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) |
+| Merge request resource milestone events | [GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/291983) |
+| Issue URL references | [GitLab 15.6](https://gitlab.com/gitlab-org/gitlab/-/issues/267947) |
+| Time tracking | [GitLab 14.5](https://gitlab.com/gitlab-org/gitlab/-/issues/339403) |
+
+#### Setting-related items
+
+Setting-related project items that are migrated to the destination GitLab instance include:
+
+| Setting-related project item | Introduced in |
+|:-----------------------------|:---------------------------------------------------------------------------|
+| Avatar | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75249) |
+| Container expiration policy | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75653) |
+| Project properties | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75898) |
+| Service Desk | [GitLab 14.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75653) |
+
+#### Excluded items
+
+Project items excluded from migration because they contain sensitive information:
+
+- Pipeline triggers.
### Troubleshooting
@@ -316,6 +377,18 @@ To solve this, you must change the source group path to include a non-numerical
- The [Groups API](../../../api/groups.md#update-group).
+#### Other `404` errors
+
+You can receive other `404` errors when importing a group, for example:
+
+```json
+"exception_message": "Unsuccessful response 404 from [FILTERED] Bo...",
+"exception_class": "BulkImports::NetworkError",
+```
+
+This error indicates a problem transferring from the _source_ instance. To solve this, check that you have met the [prerequisites](#prerequisites) on the source
+instance.
+
## Migrate groups by uploading an export file (deprecated)
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2888) in GitLab 13.0 as an experimental feature. May change in future releases.
@@ -323,8 +396,8 @@ To solve this, you must change the source group path to include a non-numerical
WARNING:
This feature was [deprecated](https://gitlab.com/groups/gitlab-org/-/epics/4619) in GitLab 14.6 and replaced by
-[migrating groups by direct transfer](#migrate-groups-by-direct-transfer-recommended). To follow progress on a solution for
-[offline environments](../../application_security/offline_deployments/index.md), see
+[migrating groups by direct transfer](#migrate-groups-by-direct-transfer-recommended). However, this feature is still recommended for migrating groups between
+offline systems. To follow progress on an alternative solution for [offline environments](../../application_security/offline_deployments/index.md), see
[the relevant epic](https://gitlab.com/groups/gitlab-org/-/epics/8985).
Prerequisites:
@@ -377,7 +450,7 @@ For example:
The [`import_export.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/import_export/group/import_export.yml)
file for groups lists items exported and imported when migrating groups using file exports. View this file in the branch
-for your version of GitLab to see the list of items relevant to you. For example,
+for your version of GitLab to check which items can be imported to the destination GitLab instance. For example,
[`import_export.yml` on the `14-10-stable-ee` branch](https://gitlab.com/gitlab-org/gitlab/-/blob/14-10-stable-ee/lib/gitlab/import_export/group/import_export.yml).
Group items that are exported include:
@@ -404,7 +477,7 @@ Items that are **not** exported include:
- To preserve the member list and their respective permissions on imported groups, review the users in these groups. Make
sure these users exist before importing the desired groups.
-- Users must set a public email in the source GitLab instance that matches one of their verified emails in the target GitLab instance.
+- Users must set a public email in the source GitLab instance that matches their confirmed primary email in the destination GitLab instance. Most users receive an email asking them to confirm their email address.
### Enable export for a group
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index db01358d899..d35a0920cf2 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md
index d21dbe357da..622112d9735 100644
--- a/doc/user/group/manage.md
+++ b/doc/user/group/manage.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
@@ -155,7 +155,7 @@ You can sort members by **Account**, **Access granted**, **Max role**, or **Last
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Group information > Members**.
-1. Above the list of members, in the upper right, from the **Account** list, select
+1. Above the list of members, in the upper-right corner, from the **Account** list, select
the criteria to filter by.
1. To switch the sort between ascending and descending, to the right of the **Account** list, select the
arrow (**{sort-lowest}** or **{sort-highest}**).
@@ -348,7 +348,7 @@ If you need to copy a group to a different GitLab instance,
When transferring groups, note:
- Changing a group's parent can have unintended side effects. See [what happens when a repository path changes](../project/repository/index.md#what-happens-when-a-repository-path-changes).
-- You can only transfer groups to groups you manage.
+- You must have the Owner role in the source and target group.
- You must update your local repositories to point to the new location.
- If the immediate parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects change to match the new parent group's visibility.
- Only explicit group membership is transferred, not inherited membership. If the group's owners have only inherited membership, this leaves the group without an owner. In this case, the user transferring the group becomes the group's owner.
diff --git a/doc/user/group/reporting/git_abuse_rate_limit.md b/doc/user/group/reporting/git_abuse_rate_limit.md
index 14b188e1204..d96f950edcd 100644
--- a/doc/user/group/reporting/git_abuse_rate_limit.md
+++ b/doc/user/group/reporting/git_abuse_rate_limit.md
@@ -11,13 +11,19 @@ info: To determine the technical writer assigned to the Stage/Group associated w
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 `limit_unique_project_downloads_per_namespace_user`. On GitLab.com, this feature is available.
-Git abuse rate limiting is a feature to automatically ban users who download or clone more than a specified number of repositories in a group or any of its subgroups within a given time frame. Banned users cannot access the main group or any of its non-public subgroups via HTTP or SSH. Access to unrelated groups is unaffected.
+This is the group-level documentation. For self-managed instances, see the [administration documentation](../../admin_area/reporting/git_abuse_rate_limit.md).
-If the `limit_unique_project_downloads_per_namespace_user` feature flag is enabled, all users with the Owner role for the main group receive an email when a user is about to be banned.
+Git abuse rate limiting is a feature to automatically [ban users](#unban-a-user) who download or clone more than a specified number of repositories of a group in a given time frame. Banned users cannot access the top-level group or any of its non-public subgroups via HTTP or SSH. The rate limit also applies to users who authenticate with a [personal](../../../user/profile/personal_access_tokens.md) or [group access token](../../../user/group/settings/group_access_tokens.md). Access to unrelated groups is unaffected.
-If automatic banning is disabled, a user is not banned automatically when they exceed the limit. However, users with the Owner role for the main group are still notified. You can use this setup to determine the correct values of the rate limit settings before enabling automatic banning.
+Git abuse rate limiting does not apply to top-level group owners, [deploy tokens](../../../user/project/deploy_tokens/index.md), or [deploy keys](../../../user/project/deploy_keys/index.md).
-If automatic banning is enabled, users with the Owner role for the main group receive an email when a user is about to be banned, and the user is automatically banned from the group and its subgroups.
+## Automatic ban notifications
+
+If the `limit_unique_project_downloads_per_namespace_user` feature flag is enabled, selected users receive an email when a user is about to be banned.
+
+If automatic banning is disabled, a user is not banned automatically when they exceed the limit. However, notifications are still sent. You can use this setup to determine the correct values of the rate limit settings before enabling automatic banning.
+
+If automatic banning is enabled, an email notification is sent when a user is about to be banned, and the user is automatically banned from the group and its subgroups.
## Configure Git abuse rate limiting
@@ -26,6 +32,7 @@ If automatic banning is enabled, users with the Owner role for the main group re
1. Enter a number in the **Number of repositories** field, greater than or equal to `0` and less than or equal to `10,000`. This number specifies the maximum amount of unique repositories a user can download in the specified time period before they're banned. When set to `0`, Git abuse rate limiting is disabled.
1. Enter a number in the **Reporting time period (seconds)** field, greater than or equal to `0` and less than or equal to `86,400` (10 days). This number specifies the time in seconds a user can download the maximum amount of repositories before they're banned. When set to `0`, Git abuse rate limiting is disabled.
1. Optional. Exclude up to `100` users by adding them to the **Excluded users** field. Excluded users are not automatically banned.
+ 1. Add up to `100` users to the **Send notifications to** field. You must select at least one user. All users with the Owner role for the main group are selected by default.
1. Optional. Turn on the **Automatically ban users from this namespace when they exceed the specified limits** toggle to enable automatic banning.
1. Select **Save changes**.
diff --git a/doc/user/group/repositories_analytics/index.md b/doc/user/group/repositories_analytics/index.md
index 9971457f2ac..edb3e1b5079 100644
--- a/doc/user/group/repositories_analytics/index.md
+++ b/doc/user/group/repositories_analytics/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Pipeline Insights
+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
---
diff --git a/doc/user/group/saml_sso/group_sync.md b/doc/user/group/saml_sso/group_sync.md
index 27482893bd6..7c9b6effc43 100644
--- a/doc/user/group/saml_sso/group_sync.md
+++ b/doc/user/group/saml_sso/group_sync.md
@@ -22,10 +22,7 @@ For a demo of Group Sync using Azure, see [Demo: SAML Group Sync](https://youtu.
## Configure SAML Group Sync
NOTE:
-You must include the SAML configuration block on all Sidekiq nodes in addition to Rails application nodes if you:
-
-- Use SAML Group Sync.
-- Have multiple GitLab nodes, for example in a distributed or highly available architecture.
+You must include the SAML configuration block on all Sidekiq nodes in addition to Rails application nodes if you use SAML Group Sync and have multiple GitLab nodes, for example in a distributed or highly available architecture.
NOTE:
SAML Group Sync is only supported for the [SAML provider named `saml`](../../../integration/saml.md#configure-gitlab-to-use-multiple-saml-idps).
@@ -107,6 +104,32 @@ Users granted:
- A lower or the same role with Group Sync are displayed as having
[inherited membership](../../project/members/index.md#display-inherited-members) of the group.
+SAML group membership is evaluated each time a user signs in.
+
+### Global SAML group memberships lock **(PREMIUM SELF)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386390) in GitLab 15.10.
+
+GitLab administrators can use the global SAML group memberships lock to prevent group members from inviting new members to subgroups that have their membership synchronized with SAML Group Links.
+
+Global group memberships lock only applies to subgroups of a top-level group where SAML Group Links synchronization is configured. No user can modify the
+membership of a top-level group configured for SAML Group Links synchronization.
+
+When global group memberships lock is enabled:
+
+- Only an administrator can manage memberships of any group including access levels.
+- Users cannot:
+ - Share a project with other groups.
+ - Invite members to a project created in a group.
+
+To enable global group memberships lock:
+
+1. [Configure SAML](../../../integration/saml.md) for your self-managed GitLab instance.
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand the **Visibility and access controls** section.
+1. Ensure the **Lock memberships to SAML synchronization** checkbox is selected.
+
### Automatic member removal
After a group sync, users who are not members of a mapped SAML group are removed from the group.
diff --git a/doc/user/group/saml_sso/img/Azure-manage-group-claims.png b/doc/user/group/saml_sso/img/Azure-manage-group-claims.png
index 2ff24733282..b08b6ab4907 100644
--- a/doc/user/group/saml_sso/img/Azure-manage-group-claims.png
+++ b/doc/user/group/saml_sso/img/Azure-manage-group-claims.png
Binary files differ
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index e650b2dd130..04dfdbc6892 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -8,17 +8,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> Introduced in GitLab 11.0.
-This page describes SAML for groups. For instance-wide SAML on self-managed GitLab instances, see [SAML SSO for self-managed GitLab instances](../../../integration/saml.md).
-[View the differences between SaaS and Self-Managed Authentication and Authorization Options](../../../administration/auth/index.md#saas-vs-self-managed-comparison).
+Users can sign in to GitLab through their SAML identity provider.
-SAML on GitLab.com allows users to sign in through their SAML identity provider. If the user is not already a member, the sign-in process automatically adds the user to the appropriate group.
+[SCIM](scim_setup.md) synchronizes users with the group on GitLab.com.
-User synchronization of SAML SSO groups is supported through [SCIM](scim_setup.md). SCIM supports adding and removing users from the GitLab group automatically.
-For example, if you remove a user from the SCIM app, SCIM removes that same user from the GitLab group.
+- When you add or remove a user from the SCIM app, SCIM adds or removes the user
+ from the GitLab group.
+- If the user is not already a group member, the user is added to the group as part of the sign-in process.
-SAML SSO is only configurable at the top-level group.
-
-If required, you can find [a glossary of common terms](../../../integration/saml.md#glossary-of-common-terms).
+You can configure SAML SSO for the top-level group only.
## Configure your identity provider
@@ -27,8 +25,8 @@ If required, you can find [a glossary of common terms](../../../integration/saml
1. On the left sidebar, select **Settings > SAML SSO**.
1. Note the **Assertion consumer service URL**, **Identifier**, and **GitLab single sign-on URL**.
1. Configure your SAML identity provider app using the noted details.
- Alternatively, GitLab provides a [metadata XML configuration](#metadata-configuration).
- See [specific identity provider documentation](#providers) for more details.
+ Alternatively, GitLab provides a [metadata XML configuration](#set-up-identity-provider-using-metadata).
+ See [specific identity provider documentation](#set-up-identity-provider) for more details.
1. Configure the SAML response to include a [NameID](#nameid) that uniquely identifies each user.
1. Configure the required [user attributes](#user-attributes), ensuring you include the user's email address.
1. While the default is enabled for most SAML providers, ensure the app is set to have service provider
@@ -40,6 +38,137 @@ If required, you can find [a glossary of common terms](../../../integration/saml
If your account is the only owner in the group after SAML is set up, you can't unlink the account. To [unlink the account](#unlinking-accounts),
set up another user as a group owner.
+## Set up identity provider
+
+The SAML standard means that you can use a wide range of identity providers with GitLab. Your identity provider might have relevant documentation. It can be generic SAML documentation or specifically targeted for GitLab.
+
+When [configuring your identity provider](#configure-your-identity-provider), consider the notes below for specific providers to help avoid common issues and as a guide for terminology used.
+
+For providers not listed below, you can refer to the [instance SAML notes on configuring an identity provider](../../../integration/saml.md#configure-saml-on-your-idp)
+for additional guidance on information your identity provider may require.
+
+GitLab provides the following information for guidance only.
+If you have any questions on configuring the SAML app, contact your provider's support.
+
+### Set up Azure
+
+To set up SSO with Azure as your identification provider:
+
+1. In GitLab, on the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, 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.
+
+ | GitLab setting | Azure field |
+ | -----------------------------------------| ---------------------------------------------- |
+ | **Identifier** | **Identifier (Entity ID)** |
+ | **Assertion consumer service URL** | **Reply URL (Assertion Consumer Service URL)** |
+ | **GitLab single sign-on URL** | **Sign on URL** |
+ | **Identity provider single sign-on URL** | **Login URL** |
+ | **Certificate fingerprint** | **Thumbprint** |
+
+1. You should set the following attributes:
+ - **Unique User Identifier (Name identifier)** to `user.objectID`.
+ - **nameid-format** to `persistent`.
+ - **Additional claims** to [supported attributes](#user-attributes).
+
+1. Optional. If you use [Group Sync](#group-sync), customize the name of the
+ group claim to match the required attribute.
+
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+View a demo of [SCIM provisioning on Azure using SAML SSO for groups](https://youtu.be/24-ZxmTeEBU). The `objectID` mapping is outdated in this video. Follow the [SCIM documentation](scim_setup.md#configure-azure-active-directory) instead.
+
+View an [example configuration page](example_saml_config.md#azure-active-directory).
+
+### Set up Google Workspace
+
+1. [Set 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.
+
+ | GitLab setting | Google Workspace field |
+ |:-------------------------------------|:-----------------------|
+ | Identifier | **Entity ID** |
+ | Assertion consumer service URL | **ACS URL** |
+ | GitLab single sign-on URL | **Start URL** |
+ | Identity provider single sign-on URL | **SSO URL** |
+
+1. Google Workspace displays a SHA256 fingerprint. To retrieve the SHA1 fingerprint
+ required by GitLab to [configure SAML](#configure-gitlab):
+ 1. Download the certificate.
+ 1. Run this command:
+
+ ```shell
+ openssl x509 -noout -fingerprint -sha1 -inform pem -in "GoogleIDPCertificate-domain.com.pem"
+ ```
+
+1. Set these values:
+ - For **Primary email**: `email`
+ - For **First name**: `first_name`
+ - For **Last name**: `last_name`
+ - For **Name ID format**: `EMAIL`
+ - For **NameID**: `Basic Information > Primary email`
+
+On the GitLab SAML SSO page, when you select **Verify SAML Configuration**, disregard
+the warning that recommends setting the **NameID** format to `persistent`.
+
+For details, see the [example configuration page](example_saml_config.md#google-workspace).
+
+### Set up Okta
+
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For a demo of the Okta SAML setup including SCIM, see [Demo: Okta Group SAML & SCIM setup](https://youtu.be/0ES9HsZq0AQ).
+
+1. [Set up a SAML application in Okta](https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/).
+ The following GitLab settings correspond to the Okta fields.
+
+ | GitLab setting | Okta field |
+ | ------------------------------------ | ---------------------------------------------------------- |
+ | Identifier | **Audience URI** |
+ | Assertion consumer service URL | **Single sign-on URL** |
+ | GitLab single sign-on URL | **Login page URL** (under **Application Login Page** settings) |
+ | Identity provider single sign-on URL | **Identity Provider Single Sign-On URL** |
+
+1. Under the Okta **Single sign-on URL** field, select the **Use this for Recipient URL and Destination URL** checkbox.
+
+1. Set these values:
+ - For **Application username (NameID)**: **Custom** `user.getInternalProperty("id")`
+ - For **Name ID Format**: `Persistent`
+
+The Okta GitLab application available in the App Catalog only supports [SCIM](scim_setup.md). Support
+for SAML is proposed in [issue 216173](https://gitlab.com/gitlab-org/gitlab/-/issues/216173).
+
+### Set up OneLogin
+
+OneLogin supports its own [GitLab (SaaS) application](https://onelogin.service-now.com/support?id=kb_article&sys_id=92e4160adbf16cd0ca1c400e0b961923&kb_category=50984e84db738300d5505eea4b961913).
+
+1. If you use the OneLogin generic
+ [SAML Test Connector (Advanced)](https://onelogin.service-now.com/support?id=kb_article&sys_id=b2c19353dbde7b8024c780c74b9619fb&kb_category=93e869b0db185340d5505eea4b961934),
+ you should [use the OneLogin SAML Test Connector](https://onelogin.service-now.com/support?id=kb_article&sys_id=93f95543db109700d5505eea4b96198f). The following GitLab settings correspond
+ to the OneLogin fields:
+
+ | GitLab setting | OneLogin field |
+ | ------------------------------------------------ | -------------------------------- |
+ | Identifier | **Audience** |
+ | Assertion consumer service URL | **Recipient** |
+ | Assertion consumer service URL | **ACS (Consumer) URL** |
+ | Assertion consumer service URL (escaped version) | **ACS (Consumer) URL Validator** |
+ | GitLab single sign-on URL | **Login URL** |
+ | Identity provider single sign-on URL | **SAML 2.0 Endpoint** |
+
+1. For **NameID**, use `OneLogin ID`.
+
+### Set up identity provider using metadata
+
+To configure some identity providers, you need a GitLab metadata URL.
+To find this URL:
+
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, 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.
+
+Check your identity provider's documentation to see if it supports the GitLab metadata URL.
+
### NameID
GitLab.com uses the SAML NameID to identify users. The NameID element:
@@ -52,7 +181,7 @@ GitLab.com uses the SAML NameID to identify users. The NameID element:
guarantee it doesn't ever change, for example, when a person's name changes. Email addresses are
also case-insensitive, which can result in users being unable to sign in.
-The relevant field name and recommended value for supported providers are in the [provider specific notes](#providers).
+The relevant field name and recommended value for supported providers are in the [provider specific notes](#set-up-identity-provider).
WARNING:
Once users have signed into GitLab using the SSO SAML setup, changing the `NameID` breaks the configuration and potentially locks users out of the GitLab group.
@@ -73,15 +202,6 @@ You can configure the following attributes with GitLab.com Group SAML:
- `username` or `nickname`. We recommend you configure only one of these.
- The [attributes available](../../../integration/saml.md#configure-assertions) to self-managed GitLab instances.
-### Metadata configuration
-
-GitLab provides metadata XML that can be used to configure your identity provider.
-
-1. On the top bar, select **Main menu > Groups** and find your group.
-1. On the left sidebar, 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.
-
## Configure GitLab
After you set up your identity provider to work with GitLab, you must configure GitLab to use it for authentication:
@@ -122,38 +242,24 @@ It can also help to compare the XML response from your provider with our [exampl
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/339888) in GitLab 14.7 to not enforce SSO checks for Git activity originating from CI/CD jobs.
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/215155) in GitLab 15.5 [with a flag](../../../administration/feature_flags.md) named `transparent_sso_enforcement` to include transparent enforcement even when SSO enforcement is not enabled. Disabled on GitLab.com.
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/375788) in GitLab 15.8 by enabling transparent SSO by default on GitLab.com.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/389562) in GitLab 15.10. Feature flag `transparent_sso_enforcement` removed.
-FLAG:
-On self-managed GitLab, transparent SSO enforcement is unavailable. An
-[issue exists](https://gitlab.com/gitlab-org/gitlab/-/issues/382917) to add
-transparent SSO enforcement to self-managed GitLab.
-On GitLab.com, transparent SSO enforcement is available by default. To turn off
-transparent SSO, ask a support or production team to enable the
-`transparent_sso_enforcement_override` feature flag for a specific customer
-group.
-
-#### Transparent SSO enforcement
-
-By default, transparent SSO enforcement is enabled in GitLab.com. This means SSO is enforced:
-
-- When users access groups and projects in the organization's
- group hierarchy. Users can view other groups and projects without SSO sign in.
-- For each user with an existing SAML identity.
-
-When transparent SSO enforcement is enabled, users:
+On GitLab.com, SSO is enforced:
-- Are not prompted to sign in through SSO on each visit. GitLab checks
- whether a user has authenticated through SSO. If the user last signed in more
- than 24 hours ago, GitLab prompts the user to sign in again through SSO.
-- Without SAML identities are not required to use SSO unless **Enforce
- SSO-only authentication for web activity for this group** is enabled.
+- When SAML SSO is enabled.
+- For users with an existing SAML identity when accessing groups and projects in the organization's
+ group hierarchy. Users can view other groups and projects as well as their user settings without SSO sign in by using their GitLab.com credentials.
A user has a SAML identity if one or both of the following are true:
- They have signed in to GitLab by using their GitLab group's single sign-on URL.
- They were provisioned by SCIM.
-With transparent SSO enabled, SSO is enforced as follows:
+Users are not prompted to sign in through SSO on each visit. GitLab checks
+whether a user has authenticated through SSO. If the user last signed in more
+than 24 hours ago, GitLab prompts the user to sign in again through SSO.
+
+SSO is enforced as follows:
| Project/Group visibility | Enforce SSO setting | Member with identity | Member without identity | Non-member or not signed in |
|--------------------------|---------------------|--------------------| ------ |------------------------------|
@@ -181,9 +287,6 @@ SSO enforcement for web activity has the following effects when enabled:
- For groups, users cannot share a project in the group outside the top-level
group, even if the project is forked.
-- For Git activity over SSH and HTTPS, users must have at least one active
- session signed-in through SSO before they can push to or
- pull from a GitLab repository.
- Git activity originating from CI/CD jobs do not have the SSO check enforced.
- Credentials that are not tied to regular users (for example, project and group
access tokens, and deploy keys) do not have the SSO check enforced.
@@ -192,7 +295,9 @@ SSO enforcement for web activity has the following effects when enabled:
- When the **Enforce SSO-only authentication for Git and Dependency Proxy
activity for this group** option is enabled, any API endpoint that involves
Git activity is under SSO enforcement. For example, creating or deleting a
- branch, commit, or tag.
+ branch, commit, or tag. For Git activity over SSH and HTTPS, users must
+ have at least one active session signed-in through SSO before they can push to or
+ pull from a GitLab repository.
When SSO for web activity is enforced, non-SSO group members do not lose access
immediately. If the user:
@@ -202,149 +307,40 @@ immediately. If the user:
- Is signed out, they cannot access the group after being removed from the
identity provider.
-## Providers
-
-The SAML standard means that you can use a wide range of identity providers with GitLab. Your identity provider might have relevant documentation. It can be generic SAML documentation or specifically targeted for GitLab.
-
-When [configuring your identity provider](#configure-your-identity-provider), consider the notes below for specific providers to help avoid common issues and as a guide for terminology used.
-
-For providers not listed below, you can refer to the [instance SAML notes on configuring an identity provider](../../../integration/saml.md#configure-saml-on-your-idp)
-for additional guidance on information your identity provider may require.
-
-GitLab provides the following information for guidance only.
-If you have any questions on configuring the SAML app, contact your provider's support.
-
-### Set up Azure
-
-Follow the Azure documentation on [configuring single sign-on to applications](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/add-application-portal-setup-sso), and use the following notes when needed.
-
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For a demo of the Azure SAML setup including SCIM, see [SCIM Provisioning on Azure Using SAML SSO for Groups Demo](https://youtu.be/24-ZxmTeEBU).
-The video is outdated in regard to objectID mapping and you should follow the [SCIM documentation](scim_setup.md#configure-azure-active-directory).
-
-| GitLab Setting | Azure Field |
-| ------------------------------------ | ------------------------------------------ |
-| Identifier | Identifier (Entity ID) |
-| Assertion consumer service URL | Reply URL (Assertion Consumer Service URL) |
-| GitLab single sign-on URL | Sign on URL |
-| Identity provider single sign-on URL | Login URL |
-| Certificate fingerprint | Thumbprint |
-
-You should set the following attributes:
-
-- **Unique User Identifier (Name identifier)** to `user.objectID`.
-- **nameid-format** to persistent.
-- Additional claims to [supported attributes](#user-attributes).
-
-If using [Group Sync](#group-sync), customize the name of the group claim to match the required attribute.
-
-See our [example configuration page](example_saml_config.md#azure-active-directory).
-
-### Set up Google Workspace
-
-1. [Set 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.
-
- | GitLab setting | Google Workspace field |
- |:-------------------------------------|:-----------------------|
- | Identifier | **Entity ID** |
- | Assertion consumer service URL | **ACS URL** |
- | GitLab single sign-on URL | **Start URL** |
- | Identity provider single sign-on URL | **SSO URL** |
-
-1. Google Workspace displays a SHA256 fingerprint. To retrieve the SHA1 fingerprint
- required by GitLab to [configure SAML](#configure-gitlab):
- 1. Download the certificate.
- 1. Run this command:
-
- ```shell
- openssl x509 -noout -fingerprint -sha1 -inform pem -in "GoogleIDPCertificate-domain.com.pem"
- ```
-
-1. Set these values:
- - For **Primary email**: `email`
- - For **First name**: `first_name`
- - For **Last name**: `last_name`
- - For **Name ID format**: `EMAIL`
- - For **NameID**: `Basic Information > Primary email`
-
-On the GitLab SAML SSO page, when you select **Verify SAML Configuration**, disregard
-the warning that recommends setting the **NameID** format to `persistent`.
-
-For details, see the [example configuration page](example_saml_config.md#google-workspace).
-
-### Set up Okta
-
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For a demo of the Okta SAML setup including SCIM, see [Demo: Okta Group SAML & SCIM setup](https://youtu.be/0ES9HsZq0AQ).
-
-1. [Set up a SAML application in Okta](https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/).
- The following GitLab settings correspond to the Okta fields.
-
- | GitLab setting | Okta field |
- | ------------------------------------ | ---------------------------------------------------------- |
- | Identifier | **Audience URI** |
- | Assertion consumer service URL | **Single sign-on URL** |
- | GitLab single sign-on URL | **Login page URL** (under **Application Login Page** settings) |
- | Identity provider single sign-on URL | **Identity Provider Single Sign-On URL** |
-
-1. Under the Okta **Single sign-on URL** field, select the **Use this for Recipient URL and Destination URL** checkbox.
-
-1. Set these values:
- - For **Application username (NameID)**: **Custom** `user.getInternalProperty("id")`
- - For **Name ID Format**: `Persistent`
-
-The Okta GitLab application available in the App Catalog only supports [SCIM](scim_setup.md). Support
-for SAML is proposed in [issue 216173](https://gitlab.com/gitlab-org/gitlab/-/issues/216173).
-
-### Set up OneLogin
-
-OneLogin supports its own [GitLab (SaaS) application](https://onelogin.service-now.com/support?id=kb_article&sys_id=92e4160adbf16cd0ca1c400e0b961923&kb_category=50984e84db738300d5505eea4b961913).
-
-1. If you use the OneLogin generic
- [SAML Test Connector (Advanced)](https://onelogin.service-now.com/support?id=kb_article&sys_id=b2c19353dbde7b8024c780c74b9619fb&kb_category=93e869b0db185340d5505eea4b961934),
- you should [use the OneLogin SAML Test Connector](https://onelogin.service-now.com/support?id=kb_article&sys_id=93f95543db109700d5505eea4b96198f). The following GitLab settings correspond
- to the OneLogin fields:
+### Change the SAML app
- | GitLab setting | OneLogin field |
- | ------------------------------------------------ | -------------------------------- |
- | Identifier | **Audience** |
- | Assertion consumer service URL | **Recipient** |
- | Assertion consumer service URL | **ACS (Consumer) URL** |
- | Assertion consumer service URL (escaped version) | **ACS (Consumer) URL Validator** |
- | GitLab single sign-on URL | **Login URL** |
- | Identity provider single sign-on URL | **SAML 2.0 Endpoint** |
+After you have configured your identity provider, you can:
-1. For **NameID**, use `OneLogin ID`.
+- Change the identity provider users sign in with.
+- Migrate to a different identity provider.
+- Change email domains.
-### Change the SAML app
+### Change the identity provider
-To change the SAML app used for sign in:
+To change the identity provider:
-- If the NameID is not identical in both the existing and new SAML apps, users must:
- 1. [Unlink the current SAML identity](#unlinking-accounts).
- 1. [Link their identity](#user-access-and-management) to the new SAML app.
-- If the NameID is identical, no change is required.
+- If the `NameID` is not identical in the existing and new identity providers, [change the NameID for users](#change-nameid-for-one-or-more-users).
+- If the `NameID` is identical, users do not have to make any changes.
-### Migrate to a different SAML provider
+### Migrate to a different identity provider
-You can migrate to a different SAML provider. During the migration process users will not be able to access any of the SAML groups.
-To mitigate this, you can disable [SSO enforcement](#sso-enforcement).
+You can migrate to a different identity provider. During the migration process,
+users cannot access any of the SAML groups. To mitigate this, you can disable
+[SSO enforcement](#sso-enforcement).
-To migrate SAML providers:
+To migrate identity providers:
-1. [Configure](#configure-your-identity-provider) the group with the new identity provider SAML app.
-1. Ask users to [unlink their account from the group](#unlinking-accounts).
-1. Ask users to [link their account to the new SAML app](#linking-saml-to-your-existing-gitlabcom-account).
+1. [Configure](#configure-your-identity-provider) the group with the new identity provider.
+1. [Change the NameID for users](#change-nameid-for-one-or-more-users).
### Change email domains
-To migrate users to a new email domain, users must:
+To migrate users to a new email domain, tell users to:
1. Add their new email as the primary email to their accounts and verify it.
-1. [Unlink their account from the group](#unlinking-accounts).
-1. [Link their account to the group](#linking-saml-to-your-existing-gitlabcom-account).
-1. (Optional) Remove their old email from the account.
+1. Optional. Remove their old email from the account.
+
+If the NameID is configured with the email address, [change the NameID for users](#change-nameid-for-one-or-more-users).
## User access and management
@@ -388,7 +384,8 @@ On subsequent visits, you should be able to go [sign in to GitLab.com with SAML]
> Update of SAML identities using the SAML API [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227841) in GitLab 15.5.
-Group owners can update the SAML identities for their group members using the [SAML API](../../../api/saml.md).
+Group owners can update the SAML identities for their group members using the [SAML API](../../../api/saml.md#update-extern_uid-field-for-a-saml-identity).
+If [SCIM](scim_setup.md) is configured, group owners can update the SCIM identities using the [SCIM API](../../../api/scim.md#update-extern_uid-field-for-a-scim-identity).
Alternatively, ask the users to reconnect their SAML account.
@@ -446,7 +443,7 @@ convert the information to XML. An example SAML response is shown here.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238461) in GitLab 15.4.
By default, users provisioned with SAML or SCIM are sent a verification email to verify their identity. Instead, you can
-[configure GitLab with a custom domain](../../project/pages/custom_domains_ssl_tls_certification/index.md) and GitLab
+[configure GitLab with a custom domain](../../enterprise_user/index.md#set-up-a-verified-domain) and GitLab
automatically confirms user accounts. Users still receive an
[enterprise user](../../enterprise_user/index.md) welcome email. Confirmation is
bypassed for users:
@@ -473,7 +470,7 @@ To rescind a user's access to the group when only SAML SSO is configured, either
- Remove (in order) the user from:
1. The user data store on the identity provider or the list of users on the specific app.
1. The GitLab.com group.
-- Use Group Sync at the top-level of your group to [automatically remove the user](group_sync.md#automatic-member-removal).
+- Use [Group Sync](group_sync.md#automatic-member-removal) at the top-level of your group with the [default role](#role) set to [minimal access](../../permissions.md#users-with-minimal-access) to automatically block access to all resources within the group. Users may continue to [use a seat](../../permissions.md#minimal-access-users-take-license-seats).
To rescind a user's access to the group when also using SCIM, refer to [Remove access](scim_setup.md#remove-access).
@@ -507,6 +504,17 @@ For information on automatically managing GitLab group membership, see [SAML Gro
The [Generated passwords for users created through integrated authentication](../../../security/passwords_for_integrated_authentication_methods.md) guide provides an overview of how GitLab generates and sets passwords for users created via SAML SSO for Groups.
+## Related topics
+
+For more information on:
+
+- Setting up SAML on self-managed GitLab instances, see
+ [SAML SSO for self-managed GitLab instances](../../../integration/saml.md).
+- Commonly-used terms, see the
+ [glossary of common terms](../../../integration/saml.md#glossary-of-common-terms).
+- The differences between SaaS and self-managed authentication and authorization,
+ see the [SaaS vs. Self-Managed comparison](../../../administration/auth/index.md#saas-vs-self-managed-comparison).
+
## Troubleshooting
See our [troubleshooting SAML guide](troubleshooting.md).
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index c6ff5dc63c3..a61615104c1 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -139,7 +139,7 @@ Prerequisites:
To configure Okta for SCIM:
1. Sign in to Okta.
-1. Ensure you are in the Admin Area by selecting the **Admin** button located in the upper right. The button is not visible from the Admin Area.
+1. In the upper-right corner, select **Admin**. The button is not visible from the Admin Area.
1. In the **Application** tab, select **Browse App Catalog**.
1. Search for **GitLab**, find and select the **GitLab** application.
1. On the GitLab application overview page, select **Add**.
@@ -200,6 +200,10 @@ On subsequent visits, new and existing users can access groups either:
For role information, see the [Group SAML](index.md#user-access-and-management) page.
+### Passwords for users created through SCIM for GitLab groups
+
+GitLab requires passwords for all user accounts. For more information on how GitLab generates passwords for users created through SCIM for GitLab groups, see [generated passwords for users created through integrated authentication](../../../security/passwords_for_integrated_authentication_methods.md).
+
### Link SCIM and SAML identities
If [group SAML](index.md) is configured and you have an existing GitLab.com account, users can link their SCIM and SAML
@@ -222,6 +226,8 @@ Remove or deactivate a user on the identity provider to remove their access to:
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.
+
NOTE:
Deprovisioning does not delete the GitLab user account.
diff --git a/doc/user/group/saml_sso/troubleshooting_scim.md b/doc/user/group/saml_sso/troubleshooting_scim.md
index 939ed804a99..12144c7c080 100644
--- a/doc/user/group/saml_sso/troubleshooting_scim.md
+++ b/doc/user/group/saml_sso/troubleshooting_scim.md
@@ -79,7 +79,7 @@ You must not:
When the SCIM app changes:
-- Users can follow the instructions in the [Change the SAML app](index.md#change-the-saml-app) section.
+- Users can follow the instructions in the [Change the SAML app](index.md#change-the-identity-provider) section.
- Administrators of the identity provider can:
1. Remove users from the SCIM app, which unlinks all removed users.
1. Turn on sync for the new SCIM app to [link existing users](scim_setup.md#link-scim-and-saml-identities).
diff --git a/doc/user/group/settings/group_access_tokens.md b/doc/user/group/settings/group_access_tokens.md
index cd50c209b0d..07e0fb4b616 100644
--- a/doc/user/group/settings/group_access_tokens.md
+++ b/doc/user/group/settings/group_access_tokens.md
@@ -48,9 +48,6 @@ You cannot use group access tokens to create other group, project, or personal a
Group access tokens inherit the [default prefix setting](../../admin_area/settings/account_and_limit_settings.md#personal-access-token-prefix)
configured for personal access tokens.
-NOTE:
-Group access tokens are not FIPS compliant and creation and use are disabled when [FIPS mode](../../../development/fips_compliance.md) is enabled.
-
## Create a group access token using UI
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214045) in GitLab 14.7.
@@ -87,8 +84,9 @@ or API. However, administrators can use a workaround:
# Set the group group you want to create a token for. For example, group with ID 109.
group = Group.find(109)
- # Create the group bot user. For further group access tokens, the username should be group_#{group.id}_bot#{bot_count}. For example, group_109_bot2 and email address group_109_bot2@example.com.
- bot = Users::CreateService.new(admin, { name: 'group_token', username: "group_#{group.id}_bot", email: "group_#{group.id}_bot@example.com", user_type: :project_bot }).execute
+ # Create the group bot user. For further group access tokens, the username should be `group_{group_id}_bot_{random_string}` and email address `group_{group_id}_bot_{random_string}@noreply.{Gitlab.config.gitlab.host}`.
+ random_string = SecureRandom.hex(16)
+ bot = Users::CreateService.new(admin, { name: 'group_token', username: "group_#{group.id}_bot_#{random_string}", email: "group_#{group.id}_bot_#{random_string}@noreply.#{Gitlab.config.gitlab.host}", user_type: :project_bot }).execute
# Confirm the group bot.
bot.confirm
@@ -172,7 +170,11 @@ to groups instead of projects. Bot users for groups:
- Do not count as licensed seats.
- Can have a maximum role of Owner for a group. For more information, see
[Create a group access token](../../../api/group_access_tokens.md#create-a-group-access-token).
-- Have a username set to `group_{group_id}_bot` for the first access token. For example, `group_123_bot`.
-- Have an email set to `group{group_id}_bot@noreply.{Gitlab.config.gitlab.host}`. For example, `group123_bot@noreply.example.com`.
+- Have a username set to `group_{group_id}_bot_{random_string}`. For example, `group_123_bot_4ffca233d8298ea1`.
+- Have an email set to `group_{group_id}_bot_{random_string}@noreply.{Gitlab.config.gitlab.host}`. For example, `group_123_bot_4ffca233d8298ea1@noreply.example.com`.
All other properties are similar to [bot users for projects](../../project/settings/project_access_tokens.md#bot-users-for-projects).
+
+## Token availability
+
+Group access tokens are only available in paid subscriptions, and not available in trial subscriptions. For more information, see the ["What is included" section of the GitLab Trial FAQ](https://about.gitlab.com/free-trial/#what-is-included-in-my-free-trial-what-is-excluded).
diff --git a/doc/user/group/settings/import_export.md b/doc/user/group/settings/import_export.md
deleted file mode 100644
index ff64a7dcd54..00000000000
--- a/doc/user/group/settings/import_export.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../import/index.md'
-remove_date: '2023-03-08'
----
-
-This document was moved to [another location](../import/index.md).
-
-<!-- This redirect file can be deleted after <2023-03-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/user/group/subgroups/index.md b/doc/user/group/subgroups/index.md
index 6c7baa848e7..63ffbf62981 100644
--- a/doc/user/group/subgroups/index.md
+++ b/doc/user/group/subgroups/index.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
@@ -85,7 +85,7 @@ You cannot host a GitLab Pages subgroup website with a top-level domain name. Fo
To create a subgroup:
1. On the top bar, select **Main menu > Groups** and find and select the parent group to add a subgroup to.
-1. On the parent group's overview page, in the upper right, select **New 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.
1. Select **Create group**.
diff --git a/doc/user/group/value_stream_analytics/img/object_hierarchy_example_V14_10.png b/doc/user/group/value_stream_analytics/img/object_hierarchy_example_V14_10.png
new file mode 100644
index 00000000000..9c4d4ae7718
--- /dev/null
+++ b/doc/user/group/value_stream_analytics/img/object_hierarchy_example_V14_10.png
Binary files differ
diff --git a/doc/user/group/value_stream_analytics/index.md b/doc/user/group/value_stream_analytics/index.md
index c5a95779087..57d4fd513ff 100644
--- a/doc/user/group/value_stream_analytics/index.md
+++ b/doc/user/group/value_stream_analytics/index.md
@@ -7,7 +7,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Value stream analytics for groups **(PREMIUM)**
-Value stream analytics provides metrics about each stage of your software development process.
+Value stream analytics measures the time it takes to go from an idea to production. It also helps businesses:
+
+- Visualize their end-to-end DevSecOps workstreams.
+- Identify and solve inefficiencies.
+- Optimize their workstreams to deliver more value, faster.
A **value stream** is the entire work process that delivers value to customers. For example,
the [DevOps lifecycle](https://about.gitlab.com/stages-devops-lifecycle/) is a value stream that starts
@@ -23,6 +27,105 @@ Use value stream analytics to identify:
Value stream analytics is also available for [projects](../../analytics/value_stream_analytics.md).
+## How value stream analytics works
+
+### How value stream analytics aggregates data
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335391) in GitLab 14.5.
+> - Filter by stop date toggle [added](https://gitlab.com/gitlab-org/gitlab/-/issues/352428) in GitLab 14.9
+> - Data refresh badge [added](https://gitlab.com/gitlab-org/gitlab/-/issues/341739) in GitLab 14.9
+> - Filter by stop date toggle [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84356) in GitLab 14.9
+> - Enable filtering by stop date [added](https://gitlab.com/gitlab-org/gitlab/-/issues/355000) in GitLab 15.0
+
+Value stream analytics uses a backend process to collect and aggregate stage-level data, which
+ensures it can scale for large groups with a high number of issues and merge requests. Due to this process,
+there may be a slight delay between when an action is taken (for example, closing an issue) and when the data
+displays on the value stream analytics page.
+
+It may take up to 10 minutes to process the data and display results. Data collection may take
+longer than 10 minutes in the following cases:
+
+- If this is the first time you are viewing value stream analytics and have not yet [created a value stream](#create-a-value-stream-with-gitlab-default-stages).
+- If the group hierarchy has been re-arranged.
+- If there have been bulk updates on issues and merge requests.
+
+To view when the data was most recently updated, in the right corner next to **Edit**, hover over the **Last updated** badge.
+
+### How value stream analytics measures stages
+
+Value stream analytics measures each stage from its start event to its end event.
+
+For example, a stage might start when a user adds a label to an issue, and ends when they add another label.
+Items aren't included in the stage time calculation if they have not reached the end event.
+
+Value stream analytics allows you to customize your stages based on pre-defined events. To make the
+configuration easier, GitLab provides a pre-defined list of stages that can be used as a template
+
+Each pre-defined stages of value stream analytics is further described in the table below.
+
+| Stage | Measurement method |
+| ------- | -------------------- |
+| Issue | The median time between creating an issue and taking action to solve it, by either labeling it or adding it to a milestone, whichever comes first. The label is tracked only if it already has an [issue board list](../../project/issue_board.md) created for it. |
+| Plan | The median time between the action you took for the previous stage, and pushing the first commit to the branch. The first commit on the branch triggers the separation between **Plan** and **Code**. At least one of the commits in the branch must contain the related issue number (for example, `#42`). If none of the commits in the branch mention the related issue number, it is not considered in the measurement time of the stage. |
+| Code | The median time between pushing a first commit (previous stage) and creating a merge request (MR) related to that commit. The key to keep the process tracked is to include the [issue closing pattern](../../project/issues/managing_issues.md#default-closing-pattern) in the description of the merge request. For example, `Closes #xxx`, where `xxx` is the number of the issue related to this merge request. If the closing pattern is not present, then the calculation uses the creation time of the first commit in the merge request as the start time. |
+| Test | The median time to run the entire pipeline for that project. It's related to the time GitLab CI/CD takes to run every job for the commits pushed to that merge request. It is basically the start->finish time for all pipelines. |
+| Review | The median time taken to review a merge request that has a closing issue pattern, between its creation and until it's merged. |
+| Staging | The median time between merging a merge request that has a closing issue pattern until the very first deployment to a [production environment](#how-value-stream-analytics-identifies-the-production-environment). If there isn't a production environment, this is not tracked. |
+
+For information about how value stream analytics calculates each stage, see the [Value stream analytics development guide](../../../development/value_stream_analytics.md).
+
+#### Example workflow
+
+This example shows a workflow through all seven stages in one day.
+
+If a stage does not include a start and a stop time, its data is not included in the median time.
+In this example, milestones have been created and CI/CD for testing and setting environments is configured.
+
+- 09:00: Create issue. **Issue** stage starts.
+- 11:00: Add issue to a milestone, start work on the issue, and create a branch locally.
+ **Issue** stage stops and **Plan** stage starts.
+- 12:00: Make the first commit.
+- 12:30: Make the second commit to the branch that mentions the issue number.
+ **Plan** stage stops and **Code** stage starts.
+- 14:00: Push branch and create a merge request that contains the
+ [issue closing pattern](../../project/issues/managing_issues.md#closing-issues-automatically).
+ **Code** stage stops and **Test** and **Review** stages start.
+- GitLab CI/CD takes 5 minutes to run scripts defined in [`.gitlab-ci.yml`](../../../ci/yaml/index.md).
+- 19:00: Merge the merge request. **Review** stage stops and **Staging** stage starts.
+- 19:30: Deployment to the `production` environment finishes. **Staging** stops.
+
+Value stream analytics records the following times for each stage:
+
+- **Issue**: 09:00 to 11:00: 2 hrs
+- **Plan**: 11:00 to 12:00: 1 hr
+- **Code**: 12:00 to 14:00: 2 hrs
+- **Test**: 5 minutes
+- **Review**: 14:00 to 19:00: 5 hrs
+- **Staging**: 19:00 to 19:30: 30 minutes
+
+Keep in mind the following observations related to this example:
+
+- This example demonstrates that it doesn't matter if your first
+ commit doesn't mention the issue number, you can do this later in any commit
+ on the branch you are working on.
+- The **Test** stage is used in the calculation for the overall time of
+ the cycle. It is included in the **Review** process, as every MR should be
+ tested.
+- This example illustrates only **one cycle** of the seven stages. The value stream analytics dashboard
+ shows the median time for multiple cycles.
+
+### How value stream analytics identifies the production environment
+
+Value stream analytics identifies [production environments](../../../ci/environments/index.md#deployment-tier-of-environments) by looking for project
+[environments](../../../ci/yaml/index.md#environment) with a name matching any of these patterns:
+
+- `prod` or `prod/*`
+- `production` or `production/*`
+
+These patterns are not case-sensitive.
+
+You can change the name of a project environment in your GitLab CI/CD configuration.
+
## View value stream analytics
> - Filtering [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13216) in GitLab 13.3
@@ -55,23 +158,21 @@ completed during the selected stage.
The table shows a list of related workflow items for the selected stage. Based on the stage you select, this can be:
-- CI/CD jobs
- Issues
- Merge requests
-- Pipelines
-## View DORA metrics and key metrics for a group
+## Value stream analytics metrics
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/210315) in GitLab 13.0.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/323982) in GitLab 13.12.
-The **Overview** dashboard in value stream analytics shows key metrics and DORA metrics of group performance. Based on the filter you select,
+The **Overview** page in value stream analytics shows key metrics and DORA metrics of group performance. Based on the filter you select,
the dashboard automatically aggregates DORA metrics and displays the current status of the value stream. Select a DORA metric to view its chart.
Prerequisite:
- To view deployment metrics, you must have a
-[production environment configured](../../../ci/environments/index.md#deployment-tier-of-environments).
+[production environment configured](#how-value-stream-analytics-identifies-the-production-environment).
To view the DORA metrics and key metrics:
@@ -86,16 +187,16 @@ To view the DORA metrics and key metrics:
- In the **To** field, select an end date.
Key metrics and DORA metrics display below the **Filter results** text box.
-### Key metrics in the value stream
+### Key metrics
-The **Overview** dashboard shows the following key metrics that measure team performance:
+The **Overview** page shows the following key metrics that measure team performance:
-- Lead time: Median time from when the issue was created to when it was closed.
-- Cycle time: Median time from first commit to issue closed. GitLab measures cycle time from the earliest commit of a
+- **Lead time**: Median time from when the issue was created to when it was closed.
+- **Cycle time**: Median time from first commit to issue closed. GitLab measures cycle time from the earliest commit of a
[linked issue's merge request](../../project/issues/crosslinking_issues.md#from-commit-messages) to when that issue is closed.
The cycle time approach underestimates the lead time because merge request creation is always later than commit time.
-- New issues: Number of new issues created.
-- Deploys: Total number of deployments to production.
+- **New issues**: Number of new issues created.
+- **Deploys**: Total number of deployments to production.
### DORA metrics **(ULTIMATE)**
@@ -118,35 +219,6 @@ NOTE:
In GitLab 13.9 and later, deployment frequency metrics are calculated based on when the deployment was finished.
In GitLab 13.8 and earlier, deployment frequency metrics are calculated based on when the deployment was created.
-<div class="video-fallback">
- See the video: <a href="https://www.youtube.com/watch?v=wQU-mWvNSiI">DORA metrics and value stream analytics</a>.
-</div>
-<figure class="video-container">
- <iframe src="https://www.youtube-nocookie.com/embed/wQU-mWvNSiI" frameborder="0" allowfullscreen> </iframe>
-</figure>
-
-### How value stream analytics aggregates data
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335391) in GitLab 14.5.
-> - Filter by stop date toggle [added](https://gitlab.com/gitlab-org/gitlab/-/issues/352428) in GitLab 14.9
-> - Data refresh badge [added](https://gitlab.com/gitlab-org/gitlab/-/issues/341739) in GitLab 14.9
-> - Filter by stop date toggle [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84356) in GitLab 14.9
-> - Enable filtering by stop date [added](https://gitlab.com/gitlab-org/gitlab/-/issues/355000) in GitLab 15.0
-
-Value stream analytics uses a backend process to collect and aggregate stage-level data, which
-ensures it can scale for large groups with a high number of issues and merge requests. Due to this process,
-there may be a slight delay between when an action is taken (for example, closing an issue) and when the data
-displays on the value stream analytics page.
-
-It may take up to 10 minutes to process the data and display results. Data collection may take
-longer than 10 minutes in the following cases:
-
-- If this is the first time you are viewing value stream analytics and have not yet [created a value stream](#create-a-value-stream-with-gitlab-default-stages).
-- If the group hierarchy has been re-arranged.
-- If there have been bulk updates on issues and merge requests.
-
-To view when the data was most recently updated, in the right corner next to **Edit**, hover over the **Last updated** badge.
-
## View metrics for each development stage
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/210315) in GitLab 13.0.
@@ -171,82 +243,9 @@ NOTE:
The date range selector filters items by the event time. The event time is when the
selected stage finished for the given item.
-## How value stream analytics measures stages
-
-Value stream analytics measures each stage from its start event to its end event.
-
-For example, a stage might start when a user adds a label to an issue, and ends when they add another label.
-Items aren't included in the stage time calculation if they have not reached the end event.
-
-Value stream analytics allows you to customize your stages based on pre-defined events. To make the
-configuration easier, GitLab provides a pre-defined list of stages that can be used as a template
-
-Each pre-defined stages of value stream analytics is further described in the table below.
-
-| Stage | Measurement method |
-| ------- | -------------------- |
-| Issue | The median time between creating an issue and taking action to solve it, by either labeling it or adding it to a milestone, whichever comes first. The label is tracked only if it already has an [issue board list](../../project/issue_board.md) created for it. |
-| Plan | The median time between the action you took for the previous stage, and pushing the first commit to the branch. The first commit on the branch triggers the separation between **Plan** and **Code**. At least one of the commits in the branch must contain the related issue number (for example, `#42`). If none of the commits in the branch mention the related issue number, it is not considered in the measurement time of the stage. |
-| Code | The median time between pushing a first commit (previous stage) and creating a merge request (MR) related to that commit. The key to keep the process tracked is to include the [issue closing pattern](../../project/issues/managing_issues.md#default-closing-pattern) in the description of the merge request. For example, `Closes #xxx`, where `xxx` is the number of the issue related to this merge request. If the closing pattern is not present, then the calculation uses the creation time of the first commit in the merge request as the start time. |
-| Test | The median time to run the entire pipeline for that project. It's related to the time GitLab CI/CD takes to run every job for the commits pushed to that merge request. It is basically the start->finish time for all pipelines. |
-| Review | The median time taken to review a merge request that has a closing issue pattern, between its creation and until it's merged. |
-| Staging | The median time between merging a merge request that has a closing issue pattern until the very first deployment to a [production environment](#how-value-stream-analytics-identifies-the-production-environment). If there isn't a production environment, this is not tracked. |
-
-For information about how value stream analytics calculates each stage, see the [Value stream analytics development guide](../../../development/value_stream_analytics.md).
-
-### Example workflow
-
-This example shows a workflow through all seven stages in one day.
-
-If a stage does not include a start and a stop time, its data is not included in the median time.
-In this example, milestones have been created and CI/CD for testing and setting environments is configured.
-
-- 09:00: Create issue. **Issue** stage starts.
-- 11:00: Add issue to a milestone, start work on the issue, and create a branch locally.
- **Issue** stage stops and **Plan** stage starts.
-- 12:00: Make the first commit.
-- 12:30: Make the second commit to the branch that mentions the issue number.
- **Plan** stage stops and **Code** stage starts.
-- 14:00: Push branch and create a merge request that contains the
- [issue closing pattern](../../project/issues/managing_issues.md#closing-issues-automatically).
- **Code** stage stops and **Test** and **Review** stages start.
-- GitLab CI/CD takes 5 minutes to run scripts defined in [`.gitlab-ci.yml`](../../../ci/yaml/index.md).
-- 19:00: Merge the merge request. **Review** stage stops and **Staging** stage starts.
-- 19:30: Deployment to the `production` environment finishes. **Staging** stops.
-
-Value stream analytics records the following times for each stage:
-
-- **Issue**: 09:00 to 11:00: 2 hrs
-- **Plan**: 11:00 to 12:00: 1 hr
-- **Code**: 12:00 to 14:00: 2 hrs
-- **Test**: 5 minutes
-- **Review**: 14:00 to 19:00: 5 hrs
-- **Staging**: 19:00 to 19:30: 30 minutes
-
-Keep in mind the following observations related to this example:
-
-- This example demonstrates that it doesn't matter if your first
- commit doesn't mention the issue number, you can do this later in any commit
- on the branch you are working on.
-- The **Test** stage is used in the calculation for the overall time of
- the cycle. It is included in the **Review** process, as every MR should be
- tested.
-- This example illustrates only **one cycle** of the seven stages. The value stream analytics dashboard
- shows the median time for multiple cycles.
-
-## How value stream analytics identifies the production environment
-
-Value stream analytics identifies production environments by looking for project
-[environments](../../../ci/yaml/index.md#environment) with a name matching any of these patterns:
-
-- `prod` or `prod/*`
-- `production` or `production/*`
-
-These patterns are not case-sensitive.
+## Create a value stream
-You can change the name of a project environment in your GitLab CI/CD configuration.
-
-## Create a value stream with GitLab default stages
+### Create a value stream with GitLab default stages
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/221202) in GitLab 13.3
@@ -269,7 +268,7 @@ create custom stages in addition to those provided in the default template.
NOTE:
If you have recently upgraded to GitLab Premium, it can take up to 30 minutes for data to collect and display.
-## Create a value stream with custom stages
+### Create a value stream with custom stages
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50229) in GitLab 13.7.
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55572) in GitLab 13.10.
@@ -287,7 +286,7 @@ When you create a value stream, you can create and add custom stages that align
1. To re-order the stages, select the up or down arrows.
1. Select **Create value stream**.
-### Label-based stages for custom value streams
+#### Label-based stages for custom value streams
To measure complex workflows, you can use [scoped labels](../../project/labels.md#scoped-labels). For example, to measure deployment
time from a staging environment to production, you could use the following labels:
@@ -297,6 +296,14 @@ time from a staging environment to production, you could use the following label
![Label-based value stream analytics stage](img/vsa_label_based_stage_v14_0.png "Creating a label-based value stream analytics stage")
+#### Example for custom value stream configuration
+
+![Example configuration](img/object_hierarchy_example_V14_10.png "Example custom value stream configuration")
+
+In the example above, two independent value streams are set up for two teams that are using different development workflows in the **Test Group** (top-level namespace).
+
+The first value stream uses standard timestamp-based events for defining the stages. The second value stream uses label events.
+
## Edit a value stream
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267537) in GitLab 13.10.
@@ -305,7 +312,7 @@ After you create a value stream, you can customize it to suit your purposes. To
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Analytics > Value Stream**.
-1. In the upper right, select the dropdown list, and select a value stream.
+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**.
1. Optional:
- Rename the value stream.
@@ -324,7 +331,7 @@ To delete a custom value stream:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Analytics > Value Stream**.
-1. In the upper right, select the dropdown list and then select the value stream you would like to delete.
+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**.
diff --git a/doc/user/img/observability_copy_shortened_link.png b/doc/user/img/observability_copy_shortened_link.png
new file mode 100644
index 00000000000..217e56972cc
--- /dev/null
+++ b/doc/user/img/observability_copy_shortened_link.png
Binary files differ
diff --git a/doc/user/infrastructure/clusters/connect/index.md b/doc/user/infrastructure/clusters/connect/index.md
index 9325f11b0c7..655bc774477 100644
--- a/doc/user/infrastructure/clusters/connect/index.md
+++ b/doc/user/infrastructure/clusters/connect/index.md
@@ -10,7 +10,7 @@ The [certificate-based Kubernetes integration with GitLab](../index.md)
was [deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8)
in GitLab 14.5. To connect your clusters, use the [GitLab agent](../../../clusters/agent/index.md).
-## Cluster levels (DEPRECATED)
+## Cluster levels (deprecated)
> [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/infrastructure/clusters/connect/new_civo_cluster.md b/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
index df785cce406..569f876f36c 100644
--- a/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
@@ -117,18 +117,18 @@ To remove all resources:
1. Add the following to your `.gitlab-ci.yml` file:
- ```yaml
- stages:
- - init
- - validate
- - build
- - deploy
- - cleanup
-
- destroy:
- extends: .destroy
- needs: []
- ```
+ ```yaml
+ stages:
+ - init
+ - validate
+ - build
+ - deploy
+ - cleanup
+
+ destroy:
+ extends: .destroy
+ needs: []
+ ```
1. On the left sidebar, select **CI/CD > Pipelines** and select the most recent pipeline.
1. For the `destroy` job, select **Play** (**{play}**).
diff --git a/doc/user/infrastructure/clusters/connect/new_eks_cluster.md b/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
index cefa8885bfe..befd793c949 100644
--- a/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
@@ -67,42 +67,42 @@ Set up your AWS credentials when you want to authenticate AWS with GitLab.
1. Create an [IAM User](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html) or [IAM Role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html).
1. Make sure that your IAM user or role has the appropriate permissions for your project. For this example project, you must have the permissions shown below. You can expand this when you set up your own project.
- ```json
- // IAM custom Policy definition
- {
- "Version": "2012-10-17",
- "Statement": [
- {
- "Sid": "VisualEditor0",
- "Effect": "Allow",
- "Action": [
- "ec2:*",
- "eks:*",
- "elasticloadbalancing:*",
- "autoscaling:*",
- "cloudwatch:*",
- "logs:*",
- "kms:DescribeKey",
- "iam:AddRoleToInstanceProfile",
- "iam:AttachRolePolicy",
- "iam:CreateInstanceProfile",
- "iam:CreateRole",
- "iam:CreateServiceLinkedRole",
- "iam:GetRole",
- "iam:ListAttachedRolePolicies",
- "iam:ListRolePolicies",
- "iam:ListRoles",
- "iam:PassRole",
- // required for destroy step
- "iam:DetachRolePolicy",
- "iam:ListInstanceProfilesForRole",
- "iam:DeleteRole"
- ],
- "Resource": "*"
- }
- ]
- }
- ```
+ ```json
+ // IAM custom Policy definition
+ {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "VisualEditor0",
+ "Effect": "Allow",
+ "Action": [
+ "ec2:*",
+ "eks:*",
+ "elasticloadbalancing:*",
+ "autoscaling:*",
+ "cloudwatch:*",
+ "logs:*",
+ "kms:DescribeKey",
+ "iam:AddRoleToInstanceProfile",
+ "iam:AttachRolePolicy",
+ "iam:CreateInstanceProfile",
+ "iam:CreateRole",
+ "iam:CreateServiceLinkedRole",
+ "iam:GetRole",
+ "iam:ListAttachedRolePolicies",
+ "iam:ListRolePolicies",
+ "iam:ListRoles",
+ "iam:PassRole",
+ // required for destroy step
+ "iam:DetachRolePolicy",
+ "iam:ListInstanceProfilesForRole",
+ "iam:DeleteRole"
+ ],
+ "Resource": "*"
+ }
+ ]
+ }
+ ```
1. [Create an access key for the user or role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html).
1. Save your access key and secret. You need these to authenticate AWS with GitLab.
@@ -165,19 +165,19 @@ To remove all resources:
1. Add the following to your `.gitlab-ci.yml` file:
- ```yaml
- stages:
- - init
- - validate
- - test
- - build
- - deploy
- - cleanup
-
- destroy:
- extends: .terraform:destroy
- needs: []
- ```
+ ```yaml
+ stages:
+ - init
+ - validate
+ - test
+ - build
+ - deploy
+ - cleanup
+
+ destroy:
+ extends: .terraform:destroy
+ needs: []
+ ```
1. On the left sidebar, select **CI/CD > Pipelines** and select the most recent pipeline.
1. For the `destroy` job, select **Play** (**{play}**).
diff --git a/doc/user/infrastructure/clusters/connect/new_gke_cluster.md b/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
index 7e6a0495d90..ecfd086d254 100644
--- a/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
@@ -143,19 +143,19 @@ To remove all resources:
1. Add the following to your `.gitlab-ci.yml` file:
- ```yaml
- stages:
- - init
- - validate
- - build
- - test
- - deploy
- - cleanup
-
- destroy:
- extends: .terraform:destroy
- needs: []
- ```
+ ```yaml
+ stages:
+ - init
+ - validate
+ - build
+ - test
+ - deploy
+ - cleanup
+
+ destroy:
+ extends: .terraform:destroy
+ needs: []
+ ```
1. On the left sidebar, select **CI/CD > Pipelines** and select the most recent pipeline.
1. For the `destroy` job, select **Play** (**{play}**).
diff --git a/doc/user/infrastructure/clusters/index.md b/doc/user/infrastructure/clusters/index.md
index 14fd4917141..9f56b92dabc 100644
--- a/doc/user/infrastructure/clusters/index.md
+++ b/doc/user/infrastructure/clusters/index.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
To connect clusters to GitLab, use the [GitLab agent](../../clusters/agent/index.md).
-## Certificate-based Kubernetes integration (DEPRECATED)
+## Certificate-based Kubernetes integration (deprecated)
WARNING:
In GitLab 14.5, the certificate-based method to connect Kubernetes clusters
diff --git a/doc/user/infrastructure/clusters/manage/clusters_health.md b/doc/user/infrastructure/clusters/manage/clusters_health.md
index 4f63f3e4e2a..f522cb5bff6 100644
--- a/doc/user/infrastructure/clusters/manage/clusters_health.md
+++ b/doc/user/infrastructure/clusters/manage/clusters_health.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Clusters health (DEPRECATED) **(FREE)**
+# Clusters health (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4701) in GitLab 10.6.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/208224) from GitLab Ultimate to GitLab Free in 13.2.
diff --git a/doc/user/infrastructure/iac/terraform_state.md b/doc/user/infrastructure/iac/terraform_state.md
index 93a82023480..62772c5b379 100644
--- a/doc/user/infrastructure/iac/terraform_state.md
+++ b/doc/user/infrastructure/iac/terraform_state.md
@@ -42,7 +42,7 @@ For self-managed GitLab, before you can use GitLab for your Terraform state file
- An administrator must [set up Terraform state storage](../../../administration/terraform_state.md).
- You must enable the **Infrastructure** menu for your project. Go to **Settings > General**,
- expand **Visibility, project features, permissions**, and under **Operations**, turn on the toggle.
+ expand **Visibility, project features, permissions**, and under **Infrastructure**, turn on the toggle.
## Initialize a Terraform state as a backend by using GitLab CI/CD
@@ -58,7 +58,7 @@ WARNING:
Like any other job artifact, Terraform plan data is viewable by anyone with the Guest role on the repository.
Neither Terraform nor GitLab encrypts the plan file by default. If your Terraform plan
includes sensitive data, like passwords, access tokens, or certificates, you should
-encrypt plan output or modify the project visibility settings. We also strongly recommend that you **disable**
+encrypt plan output or modify the project visibility settings. We also strongly recommend that you **disable**
[public pipelines](../../../ci/pipelines/settings.md#change-pipeline-visibility-for-non-project-members-in-public-projects)
by setting the artifact's public flag to false (`public: false`). This setting ensures artifacts are
accessible only to GitLab Administrators and project members with the Reporter role and above.
diff --git a/doc/user/infrastructure/iac/terraform_template_recipes.md b/doc/user/infrastructure/iac/terraform_template_recipes.md
index 89a97f305e4..a79f2758441 100644
--- a/doc/user/infrastructure/iac/terraform_template_recipes.md
+++ b/doc/user/infrastructure/iac/terraform_template_recipes.md
@@ -36,7 +36,7 @@ include:
- template: Terraform.latest.gitlab-ci.yml
deploy:
- envrionment:
+ environment:
name: $TF_STATE_NAME
action: start
on_stop: destroy
@@ -65,7 +65,7 @@ build:
- when: on_success
deploy:
- envrionment:
+ environment:
name: $TF_STATE_NAME
action: start
on_stop: destroy
diff --git a/doc/user/instance/clusters/index.md b/doc/user/instance/clusters/index.md
index 88430df0d67..dc5d402d04b 100644
--- a/doc/user/instance/clusters/index.md
+++ b/doc/user/instance/clusters/index.md
@@ -4,7 +4,7 @@ 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
---
-# Instance-level Kubernetes clusters (certificate-based) (DEPRECATED) **(FREE SELF)**
+# Instance-level Kubernetes clusters (certificate-based) (deprecated) **(FREE SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39840) in GitLab 11.11.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index eaceeccc148..30432b8b492 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -124,8 +124,13 @@ to see the color chips next to the color code:
### Diagrams and flowcharts
-You can generate diagrams and flowcharts from text by using [Mermaid](https://mermaidjs.github.io/) or [PlantUML](https://plantuml.com).
-You can also use [Kroki](https://kroki.io) to create a wide variety of diagrams.
+You can generate diagrams from text by using:
+
+- [Mermaid](https://mermaidjs.github.io/)
+- [PlantUML](https://plantuml.com)
+- [Kroki](https://kroki.io) to create a wide variety of diagrams.
+
+In wikis, you can also add and edit diagrams created with the [diagrams.net editor](#diagramsnet-editor).
#### Mermaid
@@ -543,6 +548,58 @@ This example links to `<wiki_root>/miscellaneous.md`:
[Link to Related Page](/miscellaneous.md)
```
+#### diagrams.net editor
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/322174) in GitLab 15.10.
+
+NOTE:
+Use of the diagrams.net editor is not available on offline environments.
+
+In wikis, you can use the [diagrams.net](https://www.diagrams.net/) editor to create diagrams. You
+can also edit diagrams created with the diagrams.net editor. The diagram editor is available in both
+the Markdown editor and the content editor.
+
+##### Markdown editor
+
+To create a diagram in the Markdown editor:
+
+1. In the editor's toolbar, select **Insert or edit diagram** (**{diagram}**).
+1. Use the diagrams.net editor to create the diagram.
+1. Select **Save & exit**.
+
+A Markdown image reference to the diagram is inserted in the wiki content.
+
+To edit a diagram in the Markdown editor:
+
+1. Place the Markdown editor's text field cursor in a Markdown image reference
+that contains the diagram.
+1. Select **Insert or edit diagram** (**{diagram}**) in the Markdown editor.
+1. Use the diagrams.net editor to edit the diagram.
+1. Select **Save & exit**.
+
+A Markdown image reference to the diagram is inserted in the wiki content,
+replacing the previous diagram.
+
+##### Content editor
+
+To create a diagram in the content editor:
+
+1. In the editor's toolbar, select **More options** (**{plus}**).
+1. In the dropdown list, select **Create or edit diagram**.
+1. Use the diagrams.net editor to create the diagram.
+1. Select **Save & exit**.
+
+The diagram as visualized in the diagrams.net editor is inserted in the wiki content.
+
+To edit a diagram in the content editor:
+
+1. Select the diagram that you want to edit.
+1. In the floating toolbar, select **Edit diagram** (**{diagram}**).
+1. Use the diagrams.net editor to edit the diagram.
+1. Select **Save & exit**.
+
+The selected diagram is replaced with an updated version.
+
## GitLab-specific references
GitLab Flavored Markdown renders GitLab-specific references. For example, you can reference
@@ -605,11 +662,34 @@ at the end of the reference. For example, a reference like `#123+` is rendered a
URL references like `https://gitlab.com/gitlab-org/gitlab/-/issues/1234+` are also expanded.
-### Embedding metrics in GitLab Flavored Markdown
+### Show the issue or merge request summary in the reference
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386937) in GitLab 15.10.
+
+To include an extended summary in the rendered link of an issue or merge request, add a `+s`
+at the end of the reference. Summary includes information about **assignees**, **milestone**
+and **health status** of referenced item.
+
+For example, a reference like `#123+s` is rendered as
+`The issue title (#123) • First Assignee, Second Assignee+ • v15.10 • Needs attention`.
+
+URL references like `https://gitlab.com/gitlab-org/gitlab/-/issues/1234+s` are also expanded.
+
+### 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.
+
+To embed an Observability dashboard URL:
+
+1. In GitLab Observability UI, copy the URL in the address bar.
+
+1. Paste your link wherever you want to embed your dashboard. GitLab Flavored Markdown recognizes the URL and displays the source.
+
## Features extended from standard Markdown
All standard Markdown formatting should work as expected in GitLab. Some standard
diff --git a/doc/user/namespace/index.md b/doc/user/namespace/index.md
index 7463b8f1099..00eb63da3ff 100644
--- a/doc/user/namespace/index.md
+++ b/doc/user/namespace/index.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
diff --git a/doc/user/okrs.md b/doc/user/okrs.md
index 0d3be8474fe..7025dc916ac 100644
--- a/doc/user/okrs.md
+++ b/doc/user/okrs.md
@@ -17,12 +17,11 @@ On self-managed GitLab, by default this feature is not available. To make it ava
On GitLab.com, this feature is not available.
The feature is not ready for production use.
-Use objectives and key results to align your workforce towards common goals and track the progress.
-Set a big goal with an objective and use [child objectives and key results](#child-objectives-and-key-results)
-to measure the big goal's completion.
+[Objectives and key results](https:://en.wikipedia.org/wiki/OKR) (OKRs) are a framework for setting
+and tracking goals that are aligned with your organization's overall strategy and vision.
The objective and the key result in GitLab share many features. In the documentation, the term
-**OKR** refers to either an objective or a key result.
+**OKRs** refers to both objectives and key results.
OKRs are a type of work item, a step towards [default issue types](https://gitlab.com/gitlab-org/gitlab/-/issues/323404)
in GitLab.
@@ -31,6 +30,29 @@ to work items and adding custom work item types, see
[epic 6033](https://gitlab.com/groups/gitlab-org/-/epics/6033) or the
[Plan direction page](https://about.gitlab.com/direction/plan/).
+## Designing effective OKRs
+
+Use objectives and key results to align your workforce towards common goals and track the progress.
+Set a big goal with an objective and use [child objectives and key results](#child-objectives-and-key-results)
+to measure the big goal's completion.
+
+**Objectives** are aspirational goals to be achieved and define **what you're aiming to do**.
+They show how an individual's, team's, or department's work impacts overall direction of the
+organization by connecting their work to overall company strategy.
+
+**Key results** are measures of progress against aligned objectives. They express
+**how you know if you have reached your goal** (objective).
+By achieving a specific outcome (key result), you create progress for the linked objective.
+
+To know if your OKR makes sense, you can use this sentence:
+
+<!-- vale gitlab.FutureTense = NO -->
+> I/we will accomplish (objective) by (date) through attaining and achieving the following metrics (key results).
+<!-- vale gitlab.FutureTense = YES -->
+
+To learn how to create better OKRs and how we use them at GitLab, see the
+[Objectives and Key Results handbook page](https://about.gitlab.com/company/okrs/).
+
## Create an objective
Prerequisites:
@@ -93,6 +115,26 @@ To edit an OKR:
1. Optional. To edit the description, select the edit icon (**{pencil}**), make your changes, and
select **Save**.
+## View OKR system notes
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) in GitLab 15.7 [with a flag](../administration/feature_flags.md) named `work_items_mvc_2`. Disabled by default.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) to feature flag named `work_items_mvc` in GitLab 15.8. Disabled by default.
+> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/334812) in GitLab 15.10.
+> - Changing activity sort order [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) in GitLab 15.8.
+> - Filtering activity [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/389971) in GitLab 15.10.
+> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/334812) in GitLab 15.10.
+
+Prerequisites:
+
+- You must have at least the Reporter role for the project.
+
+You can view all the system notes related to the task. By default they are sorted by **Oldest first**.
+You can always change the sorting order to **Newest first**, which is remembered across sessions.
+
+## Comments and threads
+
+You can add [comments](discussions/index.md) and reply to threads in tasks.
+
## Assign users
To show who is responsible for an OKR, you can assign users to it.
diff --git a/doc/user/operations_dashboard/index.md b/doc/user/operations_dashboard/index.md
index 2911a700e14..493771fa30a 100644
--- a/doc/user/operations_dashboard/index.md
+++ b/doc/user/operations_dashboard/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/organization/index.md b/doc/user/organization/index.md
new file mode 100644
index 00000000000..f5af26250f6
--- /dev/null
+++ b/doc/user/organization/index.md
@@ -0,0 +1,42 @@
+---
+stage: Data Stores
+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
+---
+
+# Organization
+
+DISCLAIMER:
+This page contains information related to upcoming products, features, and functionality.
+It is important to note that the information presented is for informational purposes only.
+Please do not rely on this information for purchasing or planning purposes.
+As with all projects, the items mentioned on this page are subject to change or delay.
+The development, release, and timing of any products, features, or functionality remain at the
+sole discretion of GitLab Inc.
+
+NOTE:
+Organization is in development.
+
+Organization will be above the [top-level namespaces](../namespace/index.md) for you to manage
+everything you do as a GitLab administrator, including:
+
+- Defining and applying settings to all of your groups, subgroups, and projects.
+- Aggregating data from all your groups, subgroups, and projects.
+
+Our goal is to reach feature parity between SaaS and self-managed installations, with all
+[Admin Area settings](/ee/user/admin_area/settings/index.md) moving to either:
+
+- Groups. Available in the Organization, and subgroups.
+- Hardware Controls. For functionality that does not apply to groups, Hardware Controls are only
+ applicable to self-managed installations. There is one Hardware Controls section per installation.
+
+For more information about the state of organization development,
+see [epic 9265](https://gitlab.com/groups/gitlab-org/-/epics/9265).
+
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For a video introduction to the new hierarchy concept for groups and projects for epics, see
+[Consolidating groups and projects update (August 2021)](https://www.youtube.com/watch?v=fE74lsG_8yM).
+
+## Related topics
+
+- [Organization developer documentation](../../development/organization/index.md)
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 9229ea61821..9419451fd5d 100644
--- a/doc/user/packages/container_registry/reduce_container_registry_storage.md
+++ b/doc/user/packages/container_registry/reduce_container_registry_storage.md
@@ -281,7 +281,7 @@ Here are some other options you can use to reduce the Container Registry storage
If you see this error message, check the regex patterns to ensure they are valid.
-GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular expressions in the cleanup policy. You can test them with the [regex101 regex tester](https://regex101.com/).
+GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular expressions in the cleanup policy. You can test them with the [regex101 regex tester](https://regex101.com/) using the `Golang` flavor.
View some common [regex pattern examples](#regex-pattern-examples).
### The cleanup policy doesn't delete any tags
diff --git a/doc/user/packages/debian_repository/index.md b/doc/user/packages/debian_repository/index.md
index 7ec20e3d036..05574c54112 100644
--- a/doc/user/packages/debian_repository/index.md
+++ b/doc/user/packages/debian_repository/index.md
@@ -23,6 +23,12 @@ Project and Group packages are supported.
For documentation of the specific API endpoints that Debian package manager
clients use, see the [Debian API documentation](../../../api/packages/debian.md).
+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.
+
## Enable the Debian API **(FREE SELF)**
Debian repository support is still a work in progress. It's gated behind a feature flag that's
@@ -135,6 +141,7 @@ Once built, several files are created:
- `.deb` files: the binary packages
- `.udeb` files: lightened .deb files, used for Debian-Installer (if needed)
+- `.ddeb` files: Ubuntu debug .deb files (if needed)
- `.tar.{gz,bz2,xz,...}` files: Source files
- `.dsc` file: Source metadata, and list of source files (with hashes)
- `.buildinfo` file: Used for Reproducible builds (optional)
@@ -176,39 +183,39 @@ To install a package:
1. Configure the repository:
- If you are using a private project, add your [credentials](#authenticate-to-the-debian-package-repositories) to your apt configuration:
+ If you are using a private project, add your [credentials](#authenticate-to-the-debian-package-repositories) to your apt configuration:
- ```shell
- echo 'machine gitlab.example.com login <username> password <password>' \
- | sudo tee /etc/apt/auth.conf.d/gitlab_project.conf
- ```
+ ```shell
+ echo 'machine gitlab.example.com login <username> password <password>' \
+ | sudo tee /etc/apt/auth.conf.d/gitlab_project.conf
+ ```
- Download your distribution key using your [credentials](#authenticate-to-the-debian-distributions-apis):
+ Download your distribution key using your [credentials](#authenticate-to-the-debian-distributions-apis):
- ```shell
- sudo mkdir -p /usr/local/share/keyrings
- curl --header "PRIVATE-TOKEN: <your_access_token>" \
- "https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions/<codename>/key.asc" \
- | \
- gpg --dearmor \
- | \
- sudo tee /usr/local/share/keyrings/<codename>-archive-keyring.gpg \
- > /dev/null
- ```
+ ```shell
+ sudo mkdir -p /usr/local/share/keyrings
+ curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions/<codename>/key.asc" \
+ | \
+ gpg --dearmor \
+ | \
+ sudo tee /usr/local/share/keyrings/<codename>-archive-keyring.gpg \
+ > /dev/null
+ ```
- Add your project as a source:
+ Add your project as a source:
- ```shell
- echo 'deb [ signed-by=/usr/local/share/keyrings/<codename>-archive-keyring.gpg ] https://gitlab.example.com/api/v4/projects/<project_id>/packages/debian <codename> <component1> <component2>' \
- | sudo tee /etc/apt/sources.list.d/gitlab_project.list
- sudo apt-get update
- ```
+ ```shell
+ echo 'deb [ signed-by=/usr/local/share/keyrings/<codename>-archive-keyring.gpg ] https://gitlab.example.com/api/v4/projects/<project_id>/packages/debian <codename> <component1> <component2>' \
+ | sudo tee /etc/apt/sources.list.d/gitlab_project.list
+ sudo apt-get update
+ ```
1. Install the package:
- ```shell
- sudo apt-get -y install -t <codename> <package-name>
- ```
+ ```shell
+ sudo apt-get -y install -t <codename> <package-name>
+ ```
## Download a source package
@@ -216,36 +223,36 @@ To download a source package:
1. Configure the repository:
- If you are using a private project, add your [credentials](#authenticate-to-the-debian-package-repositories) to your apt configuration:
+ If you are using a private project, add your [credentials](#authenticate-to-the-debian-package-repositories) to your apt configuration:
- ```shell
- echo 'machine gitlab.example.com login <username> password <password>' \
- | sudo tee /etc/apt/auth.conf.d/gitlab_project.conf
- ```
+ ```shell
+ echo 'machine gitlab.example.com login <username> password <password>' \
+ | sudo tee /etc/apt/auth.conf.d/gitlab_project.conf
+ ```
- Download your distribution key using your [credentials](#authenticate-to-the-debian-distributions-apis):
+ Download your distribution key using your [credentials](#authenticate-to-the-debian-distributions-apis):
- ```shell
- sudo mkdir -p /usr/local/share/keyrings
- curl --header "PRIVATE-TOKEN: <your_access_token>" \
- "https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions/<codename>/key.asc" \
- | \
- gpg --dearmor \
- | \
- sudo tee /usr/local/share/keyrings/<codename>-archive-keyring.gpg \
- > /dev/null
- ```
+ ```shell
+ sudo mkdir -p /usr/local/share/keyrings
+ curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions/<codename>/key.asc" \
+ | \
+ gpg --dearmor \
+ | \
+ sudo tee /usr/local/share/keyrings/<codename>-archive-keyring.gpg \
+ > /dev/null
+ ```
- Add your project as a source:
+ Add your project as a source:
- ```shell
- echo 'deb-src [ signed-by=/usr/local/share/keyrings/<codename>-archive-keyring.gpg ] https://gitlab.example.com/api/v4/projects/<project_id>/packages/debian <codename> <component1> <component2>' \
- | sudo tee /etc/apt/sources.list.d/gitlab_project-sources.list
- sudo apt-get update
- ```
+ ```shell
+ echo 'deb-src [ signed-by=/usr/local/share/keyrings/<codename>-archive-keyring.gpg ] https://gitlab.example.com/api/v4/projects/<project_id>/packages/debian <codename> <component1> <component2>' \
+ | sudo tee /etc/apt/sources.list.d/gitlab_project-sources.list
+ sudo apt-get update
+ ```
1. Download the source package:
- ```shell
- sudo apt-get source -t <codename> <package-name>
- ```
+ ```shell
+ sudo apt-get source -t <codename> <package-name>
+ ```
diff --git a/doc/user/packages/go_proxy/index.md b/doc/user/packages/go_proxy/index.md
index 1a089cd82be..f0e10d73d08 100644
--- a/doc/user/packages/go_proxy/index.md
+++ b/doc/user/packages/go_proxy/index.md
@@ -74,7 +74,7 @@ go env -w GOPROXY='https://gitlab.example.com/api/v4/projects/1234/packages/go,h
With this configuration, Go fetches dependencies in this order:
1. Go attempts to fetch from the project-specific Go proxy.
-1. Go attempts to fetch from [proxy.golang.org](https://proxy.golang.org).
+1. Go attempts to fetch from [`proxy.golang.org`](https://proxy.golang.org).
1. Go fetches directly with version control system operations (like `git clone`,
`svn checkout`, and so on).
diff --git a/doc/user/packages/harbor_container_registry/index.md b/doc/user/packages/harbor_container_registry/index.md
index 1ad5e2c2f05..6cea541a55d 100644
--- a/doc/user/packages/harbor_container_registry/index.md
+++ b/doc/user/packages/harbor_container_registry/index.md
@@ -18,7 +18,7 @@ You can view the Harbor Registry for a project or group.
You can search, sort, and filter images on this page. You can share a filtered view by copying the URL from your browser.
-At the project level, you can see **CLI Commands** in the upper right corner, where you can copy
+At the project level, in the upper-right corner, you can see **CLI Commands** where you can copy
corresponding commands to sign in, build images, and push images. **CLI Commands** is not shown at
the group level.
diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md
index 11e3d0e5131..6ce4aab930e 100644
--- a/doc/user/packages/npm_registry/index.md
+++ b/doc/user/packages/npm_registry/index.md
@@ -244,8 +244,19 @@ npm dist-tag rm @scope/package@version my-tag # Delete a tag from the package
npm install @scope/package@my-tag # Install a specific tag
```
-You cannot use your `CI_JOB_TOKEN` or deploy token with the `npm dist-tag` commands.
-View [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/258835) for details.
+#### From CI/CD
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258835) in GitLab 15.10.
+
+You can use a [`CI_JOB_TOKEN`](../../../ci/jobs/ci_job_token.md) or [deploy token](../../project/deploy_tokens/index.md)
+to run `npm dist-tag` commands in a GitLab CI/CD job. For example:
+
+```yaml
+npm-deploy-job:
+ script:
+ - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}">.npmrc
+ - npm dist-tag add @scope/package@version my-tag
+```
Due to a bug in npm 6.9.0, deleting distribution tags fails. Make sure your npm version is 6.9.1 or later.
@@ -266,19 +277,28 @@ The GitLab npm repository supports the following commands for the npm CLI (`npm`
### `404 Not Found` errors are happening on `npm install` or `yarn`
-Using `CI_JOB_TOKEN` to install npm packages with dependencies in another project gives you 404 Not Found errors. A fix for this problem is proposed in [issue 352962](https://gitlab.com/gitlab-org/gitlab/-/issues/352962).
+Using `CI_JOB_TOKEN` to install npm packages with dependencies in another project gives you 404 Not Found errors. You need to authenticate with a token that has access to the package and all its dependencies.
-As a workaround, you can:
+If the package and its dependencies are in separate projects but in the same group, you can use a
+[group deploy token](../../project/deploy_tokens/index.md#create-a-deploy-token):
-1. Create a [personal access token](../../profile/personal_access_tokens.md).
-1. Authenticate at both the instance level and project level for each package:
+```ini
+//gitlab.example.com/api/v4/packages/npm/:_authToken=<group-token>
+@group-scope:registry=https://gitlab.example.com/api/v4/packages/npm/
+```
- ```ini
- @foo:registry=https://gitlab.example.com/api/v4/packages/npm/
- //gitlab.example.com/api/v4/packages/npm/:_authToken=${MY_TOKEN}
- //gitlab.example.com/api/v4/projects/<your_project_id_a>/packages/npm/:_authToken=${MY_TOKEN}
- //gitlab.example.com/api/v4/projects/<your_project_id_b>/packages/npm/:_authToken=${MY_TOKEN}
- ```
+If the package and its dependencies are spread across multiple groups, you can use a [personal access token](../../profile/personal_access_tokens.md)
+from a user that has access to all the groups or individual projects:
+
+```ini
+//gitlab.example.com/api/v4/packages/npm/:_authToken=<personal-access-token>
+@group-1:registry=https://gitlab.example.com/api/v4/packages/npm/
+@group-2:registry=https://gitlab.example.com/api/v4/packages/npm/
+```
+
+WARNING:
+Personal access tokens must be treated carefully. Read our [token security considerations](../../../security/token_overview.md#security-considerations)
+for guidance on managing personal access tokens (for example, setting a short expiry and using minimal scopes).
### `npm publish` targets default npm registry (`registry.npmjs.org`)
diff --git a/doc/user/packages/nuget_repository/index.md b/doc/user/packages/nuget_repository/index.md
index 6710c147c87..4595e0eebb9 100644
--- a/doc/user/packages/nuget_repository/index.md
+++ b/doc/user/packages/nuget_repository/index.md
@@ -472,4 +472,4 @@ nuget locals all -clear
### `Error publishing` or `Invalid Package: Failed metadata extraction error` messages when trying to publish NuGet packages in a Docker-based GitLab installation
-Webhook requests to local network addresses are blocked to prevent the exploitation of internal web services. If you get `Error publishing` or `Invalid Package` messages when you try to publish NuGet packages, change your network settings to [allow webhook and service requests to the local network](../../../security/webhooks.md#allow-webhook-and-service-requests-to-local-network).
+Webhook requests to local network addresses are blocked to prevent exploitation of internal web services. If you get `Error publishing` or `Invalid Package` messages when you try to publish NuGet packages, change your network settings to [allow webhook and integration requests to the local network](../../../security/webhooks.md#allow-requests-to-the-local-network-from-webhooks-and-integrations).
diff --git a/doc/user/packages/package_registry/reduce_package_registry_storage.md b/doc/user/packages/package_registry/reduce_package_registry_storage.md
index 673196ebad5..020cad5ac14 100644
--- a/doc/user/packages/package_registry/reduce_package_registry_storage.md
+++ b/doc/user/packages/package_registry/reduce_package_registry_storage.md
@@ -35,6 +35,9 @@ To delete a package in the UI, from your group or project:
The package is permanently deleted.
+If [request forwarding](supported_functionality.md#forwarding-requests) is enabled,
+deleting a package can introduce a [dependency confusion risk](supported_functionality.md#deleting-packages).
+
## Delete assets associated with a package
To delete package assets, you must have suitable [permissions](../../permissions.md).
diff --git a/doc/user/packages/package_registry/supported_functionality.md b/doc/user/packages/package_registry/supported_functionality.md
index e56ae88872a..0c7813beae0 100644
--- a/doc/user/packages/package_registry/supported_functionality.md
+++ b/doc/user/packages/package_registry/supported_functionality.md
@@ -53,10 +53,10 @@ Requests for packages not found in your GitLab project are forwarded to the publ
| Package type | Supports request forwarding |
|-----------------------------------------------------|-----------------------------|
-| [Maven](../maven_repository/index.md) | Y |
-| [npm](../npm_registry/index.md) | Y |
+| [Maven](../maven_repository/index.md) | [Yes (disabled by default)](../../admin_area/settings/continuous_integration.md#maven-forwarding) |
+| [npm](../npm_registry/index.md) | [Yes](../../admin_area/settings/continuous_integration.md#npm-forwarding) |
| [NuGet](../nuget_repository/index.md) | N |
-| [PyPI](../pypi_repository/index.md) | Y |
+| [PyPI](../pypi_repository/index.md) | [Yes](../../admin_area/settings/continuous_integration.md#pypi-forwarding) |
| [Generic packages](../generic_packages/index.md) | N |
| [Terraform](../terraform_module_registry/index.md) | N |
| [Composer](../composer_repository/index.md) | N |
@@ -66,6 +66,23 @@ 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
+
+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).
+
+If a system tries to pull a deleted package, the request is forwarded to the public
+registry. If a package with the same name and version is found in the public registry, that package
+is pulled instead. There is a risk that the package pulled from the registry might not be
+what is expected, and could even be malicious.
+
+To reduce the associated security risks, before deleting a package you can:
+
+- Verify the package is not being actively used.
+- Disable request forwarding:
+ - Instance administrators can disable forwarding in the [**Continuous Integration** section](../../admin_area/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.
+
## Allow or prevent duplicates **(FREE)**
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/yarn_repository/index.md b/doc/user/packages/yarn_repository/index.md
index 7e2f45019cd..e756a912928 100644
--- a/doc/user/packages/yarn_repository/index.md
+++ b/doc/user/packages/yarn_repository/index.md
@@ -6,220 +6,312 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Publish packages with Yarn
-Publish npm packages in your project's Package Registry using Yarn. Then install the
-packages whenever you need to use them as a dependency.
+You can publish packages with [Yarn 1 (Classic)](https://classic.yarnpkg.com) and [Yarn 2+](https://yarnpkg.com).
-Learn how to build a [yarn](../workflows/build_packages.md#yarn) package.
+To find the Yarn version used in the deployment container, run `yarn --version` in the `script` block of the CI
+script job block that is responsible for calling `yarn publish`**`. The Yarn version is shown in the pipeline output.
-You can get started with Yarn 2 by following the [Yarn documentation](https://yarnpkg.com/getting-started/install/).
+Learn how to build a [Yarn](../workflows/build_packages.md#yarn) package.
+
+You can use the Yarn documentation to get started with
+[Yarn Classic](https://classic.yarnpkg.com/en/docs/getting-started) and
+[Yarn 2+](https://yarnpkg.com/getting-started/).
## Publish to GitLab Package Registry
+You can use Yarn to publish to the GitLab Package Registry.
+
### Authentication to the Package Registry
You need a token to publish a package. Different tokens are available depending on what you're trying to
achieve. For more information, review the [guidance on tokens](../../../user/packages/package_registry/index.md#authenticate-with-the-registry).
-- If your organization uses two-factor authentication (2FA), you must use a personal access token with the scope set to `api`.
-- If you publish a package via CI/CD pipelines, you must use a CI job token.
+- If your organization uses two-factor authentication (2FA), you must use a
+ personal access token with the scope set to `api`.
+- If you publish a package via CI/CD pipelines, you can use a CI job token in
+ private runners or you can register a variable for shared runners.
-Create a token and save it to use later in the process.
+### Publish configuration
-### Naming convention
+To publish, set the following configuration in `.yarnrc.yml`. This file should be
+located in the root directory of your package project source where `package.json` is found.
-Depending on how you install the package, you may need to adhere to the naming convention.
+```yaml
+npmScopes:
+ <my-org>:
+ npmPublishRegistry: 'https://<your_domain>/api/v4/projects/<your_project_id>/packages/npm/'
+ npmAlwaysAuth: true
+ npmAuthToken: '<your_token>'
+```
-You can use one of two API endpoints to install packages:
+In this configuration:
-- **Instance-level**: Use when you have many npm packages in different GitLab groups or in their own namespace.
-- **Project-level**: Use when you have a few npm packages, and they are not in the same GitLab group.
+- Replace `<my-org>` with your organization scope, exclude the `@` symbol.
+- Replace `<your_domain>` with your domain name.
+- Replace `<your_project_id>` with your project's ID, which you can find on the project's home page.
+- Replace `<your_token>` with a deployment token, group access token, project access token, or personal access token.
-If you plan to install a package through the [project level](#install-from-the-project-level), you do not have to
-adhere to the naming convention.
+Scoped registry does not work in Yarn Classic in `package.json` file, based on
+this [issue](https://github.com/yarnpkg/yarn/pull/7829).
+Therefore, under `publishConfig` there should be `registry` and not `@scope:registry` for Yarn Classic.
+You can publish using your command line or a CI/CD pipeline to the GitLab Package Registry.
-If you plan to install a package through the [instance level](#install-from-the-instance-level), then you must name
-your package with a [scope](https://docs.npmjs.com/misc/scope/). Scoped packages begin with a `@` and have the
-`@owner/package-name` format. You can set up the scope for your package in the `.yarnrc.yml` file and by using the
-`publishConfig` option in the `package.json`.
+### Publishing via the command line - Manual Publish
-- The value used for the `@scope` is the root of the project that hosts the packages and not the root
- of the project with the package's source code. The scope should be lowercase.
-- The package name can be anything you want
+```shell
+# Yarn 1 (Classic)
+yarn publish
-| Project URL | Package Registry in | Scope | Full package name |
-| ------------------------------------------------------- | ------------------- | --------- | ---------------------- |
-| `https://gitlab.com/my-org/engineering-group/analytics` | Analytics | `@my-org` | `@my-org/package-name` |
+# Yarn 2+
+yarn npm publish
+```
-### Configuring `.yarnrc.yml` to publish from the project level
+Your package should now publish to the Package Registry.
-To publish with the project-level npm endpoint, set the following configuration in
-`.yarnrc.yml`:
+### Publishing via a CI/CD pipeline - Automated Publish
-```yaml
-npmScopes:
- foo:
- npmRegistryServer: 'https://<your_domain>/api/v4/projects/<your_project_id>/packages/npm/'
- npmPublishRegistry: 'https://<your_domain>/api/v4/projects/<your_project_id>/packages/npm/'
+You can use pipeline variables when you use this method.
-npmRegistries:
- //gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:
- npmAlwaysAuth: true
- npmAuthToken: '<your_token>'
-```
+You can use **Shared Runners** *(Default)* or **Private Runners** (Advanced).
-In this configuration:
+#### Shared runners
-- Replace `<your_domain>` with your domain name.
-- Replace `<your_project_id>` with your project's ID, which you can find on the project's home page.
-- Replace `<your_token>` with a deploy token, group access token, project access token, or personal access token.
+Third party images such as `node:latest` or `node:current` do not have direct access
+to the `CI_JOB_TOKEN` when operating in a shared runner. You must configure an
+authentication token or use a private runner.
+
+To create a authentication token:
-### Configuring `.yarnrc.yml` to publish from the instance level
+1. On the top bar, select **Main menu**, and:
+ - For a project, select **Projects** and find your project.
+ - For a group, select **Groups** and find your 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**.
+1. Select `Add variable` and use the following settings:
-For the instance-level npm endpoint, use this Yarn 2 configuration in `.yarnrc.yml`:
+| Field | Value |
+|--------------------|------------------------------|
+| key | `NPM_AUTH_TOKEN` |
+| value | `<DEPLOY-TOKEN-FROM-STEP-3>` |
+| type | Variable |
+| Protected variable | `CHECKED` |
+| Mask variable | `CHECKED` |
+| Expand variable | `CHECKED` |
+
+To use any **Protected variable**:
+
+ 1. Go to the repository that contains the Yarn package source code.
+ 1. On the left sidebar, select **Settings > Repository**.
+ - If you are building from branches with tags, select **Protected Tags** and add `v*` (wildcard) for semantic versioning.
+ - If you are building from branches without tags, select **Protected Branches**.
+
+Then add the `NPM_AUTH_TOKEN` created above, to the `.yarnrc.yml` configuration
+in your package project root directory where `package.json` is found:
```yaml
npmScopes:
- <scope>:
- npmRegistryServer: 'https://<your_domain>/api/v4/packages/npm/'
-
-npmRegistries:
- //gitlab.example.com/api/v4/packages/npm/:
+ esp-code:
+ npmPublishRegistry: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/npm/"
npmAlwaysAuth: true
- npmAuthToken: '<your_token>'
+ npmAuthToken: "${NPM_AUTH_TOKEN}"
```
-In this configuration:
+#### Private runners
-- Replace `<your_domain>` with your domain name.
-- Your scope is `<scope>`, without `@`.
-- Replace `<your_token>` with a deploy token, group access token, project access token, or personal access token.
+Add the `CI_JOB_TOKEN` to the `.yarnrc.yml` configuration in your package project
+root directory where `package.json` is found:
-### Publishing a package via the command line
+```yaml
+npmScopes:
+ esp-code:
+ npmPublishRegistry: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/npm/"
+ npmAlwaysAuth: true
+ npmAuthToken: "${CI_JOB_TOKEN}"
+```
-Publish a package:
+To publish the package using CI/CD pipeline, In the GitLab project that houses
+your `yarnrc.yml`, edit or create a `.gitlab-ci.yml` file. For example to trigger
+only on any tag push:
-```shell
-npm publish
-```
+```yaml
+# Yarn 1
+image: node:lts
-Your package should now publish to the Package Registry.
+stages:
+ - deploy
-### Publishing via a CI/CD pipeline
+rules:
+- if: $CI_COMMIT_TAG
-In the GitLab project that houses your `yarnrc.yml`, edit or create a `.gitlab-ci.yml` file. For example:
+deploy:
+ stage: deploy
+ script:
+ - yarn publish
+```
```yaml
-image: node:latest
+# Yarn 2+
+image: node:lts
stages:
- deploy
+rules:
+ - if: $CI_COMMIT_TAG
+
deploy:
stage: deploy
+ before_script:
+ - corepack enable
+ - yarn set version stable
script:
- - npm publish
+ - yarn npm publish
```
Your package should now publish to the Package Registry when the pipeline runs.
## Install a package
-If multiple packages have the same name and version, the most recently-published package is retrieved when you install a package.
+NOTE:
+If multiple packages have the same name and version, the most recently-published
+package is retrieved when you install a package.
-You can install a package from a GitLab project or instance:
+You can use one of two API endpoints to install packages:
-- **Instance-level**: Use when you have many npm packages in different GitLab groups or in their own namespace.
-- **Project-level**: Use when you have a few npm packages, and they are not in the same GitLab group.
+- **Instance-level**: Best used when working with many packages in an organization scope.
-### Install from the instance level
+- If you plan to install a package through the [instance level](#install-from-the-instance-level),
+ then you must name your package with a [scope](https://docs.npmjs.com/misc/scope/).
+ Scoped packages begin with a `@` and have the `@owner/package-name` format. You can set up
+ the scope for your package in the `.yarnrc.yml` file and by using the `publishConfig`
+ option in the `package.json`.
-WARNING:
-You must use packages published with the scoped [naming convention](#naming-convention) when you install a package from the instance level.
+- The value used for the `@scope` is the organization root (top-level project) `...com/my-org`
+ *(@my-org)* that hosts the packages, not the root of the project with the package's source code.
+- The scope is always lowercase.
+- The package name can be anything you want `@my-org/any-name`.
-1. Authenticate to the Package Registry
+- **Project-level**: For when you have a one-off package.
- If you install a package from a private project, you must authenticate to the Package Registry. Skip this step if the project is not private.
+If you plan to install a package through the [project level](#install-from-the-project-level),
+you do not have to adhere to the naming convention.
- ```shell
- npm config set -- //your_domain_name/api/v4/packages/npm/:_authToken=your_token
- ```
+| Project URL | Package Registry | Organization Scope | Full package name |
+|-------------------------------------------------------------------|----------------------|--------------------|-----------------------------|
+| `https://gitlab.com/<my-org>/<group-name>/<package-name-example>` | Package Name Example | `@my-org` | `@my-org/package-name` |
+| `https://gitlab.com/<example-org>/<group-name>/<project-name>` | Project Name | `@example-org` | `@example-org/project-name` |
- - Replace `your_domain_name` with your domain name, for example, `gitlab.com`.
- - Replace `your_token` with a deploy token, group access token, project access token, or personal access token.
+You can install from the instance level or from the project level.
-1. Set the registry
+The configurations for `.yarnrc.yml` can be added per package consuming project
+root where `package.json` is located, or you can use a global
+configuration located in your system user home directory.
- ```shell
- npm config set @scope:registry https://your_domain_name.com/api/v4/packages/npm/
- ```
+### Install from the instance level
- - Replace `@scope` with the [root level group](#naming-convention) of the project you're installing to the package from.
- - Replace `your_domain_name` with your domain name, for example, `gitlab.com`.
- - Replace `your_token` with a deploy token, group access token, project access token, or personal access token.
+Use these steps for global configuration in the `.yarnrc.yml` file:
-1. Install the package
+1. [Configure organization scope](#configure-organization-scope).
+1. [Set the registry](#set-the-registry).
- ```shell
- yarn add @scope/my-package
- ```
+#### Configure organization scope
+
+```yaml
+npmScopes:
+ <my-org>:
+ npmRegistryServer: "https://<your_domain_name>/api/v4/packages/npm"
+```
+
+- Replace `<my-org>` with the root level group of the project you're installing to the package from excluding the `@` symbol.
+- Replace `<your_domain_name>` with your domain name, for example, `gitlab.com`.
+
+#### Set the registry
+
+Skip this step if your package is public not private.
+
+```yaml
+ npmRegistries:
+ //<your_domain_name>/api/v4/packages/npm:
+ npmAlwaysAuth: true
+ npmAuthToken: "<your_token>"
+```
+
+- Replace `<your_domain_name>` with your domain name, for example, `gitlab.com`.
+- Replace `<your_token>` with a deployment token (recommended), group access token, project access token, or personal access token.
### Install from the project level
-1. Authenticate to the Package Registry
+Use these steps for each project in the `.yarnrc.yml` file:
+
+1. [Configure project scope](#configure-project-scope).
+1. [Set the registry](#set-the-registry-project-level).
- If you install a package from a private project, you must authenticate to the Package Registry. Skip this step if the project is not private.
+#### Configure project scope
- ```shell
- npm config set -- //your_domain_name/api/v4/projects/your_project_id/packages/npm/:_authToken=your_token
- ```
+ ```yaml
+ npmScopes:
+ <my-org>:
+ npmRegistryServer: "https://<your_domain_name>/api/v4/projects/<your_project_id>/packages/npm"
+```
- - Replace `your_domain_name` with your domain name, for example, `gitlab.com`.
- - Replace `your_project_id` is your project ID, found on the project's home page.
- - Replace `your_token` with a deploy token, group access token, project access token, or personal access token.
+- Replace `<my-org>` with the root level group of the project you're installing to the package from excluding the `@` symbol.
+- Replace `<your_domain_name>` with your domain name, for example, `gitlab.com`.
+- Replace `<your_project_id>` with your project ID, found on the project's home page.
-1. Set the registry
+#### Set the registry (project level)
- ```shell
- npm config set @scope:registry=https://your_domain_name/api/v4/projects/your_project_id/packages/npm/
- ```
+Skip this step if your package is public not private.
- - Replace `@scope` with the [root level group](#naming-convention) of the project you're installing to the package from.
- - Replace `your_domain_name` with your domain name, for example, `gitlab.com`.
- - Replace `your_project_id` is your project ID, found on the project's home page.
+```yaml
+npmRegistries:
+ //<your_domain_name>/api/v4/projects/<your_project_id>/packages/npm:
+ npmAlwaysAuth: true
+ npmAuthToken: "<your_token>"
+```
-1. Install the package
+- Replace `<your_domain_name>` with your domain name, for example, `gitlab.com`.
+- Replace `<your_token>` with a deployment token (recommended), group access token, project access token, or personal access token.
+- Replace `<your_project_id>` with your project ID, found on the project's home page.
- ```shell
- yarn add @scope/my-package
- ```
+### Install the package
-## Helpful hints
+For Yarn 2+, use `yarn add` either in the command line or in the CI/CD pipelines to install your packages:
-For full helpful hints information, refer to the [npm documentation](../npm_registry/index.md#helpful-hints).
+```shell
+yarn add @scope/my-package
+```
-### Supported CLI commands
+#### For Yarn Classic
-The GitLab npm repository supports the following commands for the npm CLI (`npm`) and yarn CLI
-(`yarn`):
+The Yarn Classic setup, requires both `.npmrc` and `.yarnrc` files as
+[mentioned in issue](https://github.com/yarnpkg/yarn/issues/4451#issuecomment-753670295):
-- `npm install`: Install npm packages.
-- `npm publish`: Publish an npm package to the registry.
-- `npm dist-tag add`: Add a dist-tag to an npm package.
-- `npm dist-tag ls`: List dist-tags for a package.
-- `npm dist-tag rm`: Delete a dist-tag.
-- `npm ci`: Install npm packages directly from your `package-lock.json` file.
-- `npm view`: Show package metadata.
-- `yarn add`: Install an npm package.
-- `yarn update`: Update your dependencies.
+- Place credentials in the `.npmrc` file.
+- Place the scoped registry in the `.yarnrc` file.
-## Troubleshooting
+```shell
+# .npmrc
+//<your_domain_name>/api/v4/projects/<your_project_id>/packages/npm/:_authToken="<your_token>"
+
+# .yarnrc
+"@scope:registry" "https://<your_domain_name>/api/v4/projects/<your_project_id>/packages/npm/"
+```
+
+Then you can use `yarn add` to install your packages.
+
+## Related topics
-For full troubleshooting information, refer to the [npm documentation](../npm_registry/index.md#troubleshooting).
+- For full helpful hints information, see the
+ [npm documentation](../npm_registry/index.md#helpful-hints).
+- For Yarn 1 to Yarn 2+ migration information see the
+ [Yarn Migration Guide](https://yarnpkg.com/getting-started/migration).
+
+## Troubleshooting
### Error running Yarn with the Package Registry for the npm registry
-If you are using [Yarn](https://classic.yarnpkg.com/en/) with the npm registry, you may get
-an error message like:
+If you are using [Yarn](https://classic.yarnpkg.com/en/) with the npm registry, you may get an error message like:
```shell
yarn install v1.15.2
@@ -233,14 +325,7 @@ info If you think this is a bug, please open a bug report with the information p
info Visit https://classic.yarnpkg.com/en/docs/cli/install for documentation about this command
```
-In this case, try adding this to your `.npmrc` file (and replace `<your_token>`
-with your personal access token or deploy token):
-
-```plaintext
-//gitlab.example.com/api/v4/projects/:_authToken=<your_token>
-```
-
-You can also use `yarn config` instead of `npm config` when setting your auth-token dynamically:
+In this case, the following commands creates a file called `.yarnrc` in the current directory. Make sure to be in either your user home directory for global configuration or your project root for per-project configuration:
```shell
yarn config set '//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' "<your_token>"
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 8e736b6d83e..43029e37047 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -69,8 +69,8 @@ The following table lists project permissions available for each role:
| [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) | | | | | ✓ |
-| [Clusters](infrastructure/clusters/index.md):<br>View clusters | | | ✓ | ✓ | ✓ |
-| [Clusters](infrastructure/clusters/index.md):<br>Manage clusters | | | | ✓ | ✓ |
+| [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) | | | | ✓ | ✓ |
| [Container Registry](packages/container_registry/index.md):<br>Push an image to the Container Registry | | | ✓ | ✓ | ✓ |
| [Container Registry](packages/container_registry/index.md):<br>Pull an image from the Container Registry | ✓ (19) | ✓ (19) | ✓ | ✓ | ✓ |
@@ -220,7 +220,7 @@ The following table lists project permissions available for each role:
<!-- markdownlint-disable MD029 -->
-1. On self-managed GitLab instances, users with the Guest role are able to perform this action only on public and internal projects (not on private projects). [External users](admin_area/external_users.md) must be given explicit access even if the project is internal. Users with the Guest role on GitLab.com are only able to perform this action on public projects because internal visibility is not available. In GitLab 15.9 and later, this restriction only applies to users with the non-custom Guest role on self-managed GitLab instances and GitLab.com.
+1. On self-managed GitLab instances, users with the Guest role are able to perform this action only on public and internal projects (not on private projects). [External users](admin_area/external_users.md) must be given explicit access even if the project is internal. Users with the Guest role on GitLab.com are only able to perform this action on public projects because internal visibility is not available.
2. Guest users can only view the [confidential issues](project/issues/confidential_issues.md) they created themselves or are assigned to.
3. Not allowed for Guest, Reporter, Developer, Maintainer, or Owner. See [protected branches](project/protected_branches.md).
4. If the [branch is protected](project/protected_branches.md), this depends on the access given to Developers and Maintainers.
@@ -271,8 +271,7 @@ More details about the permissions for some project-level features follow.
| View and download artifacts | ✓ (1) | ✓ (2) | ✓ | ✓ | ✓ | ✓ |
| View [environments](../ci/environments/index.md) | ✓ (3) | ✓ (3) | ✓ | ✓ | ✓ | ✓ |
| View job logs and job details page | ✓ (1) | ✓ (2) | ✓ | ✓ | ✓ | ✓ |
-| View pipeline details page | ✓ (1) | ✓ (2) | ✓ | ✓ | ✓ | ✓ |
-| View pipelines page | ✓ (1) | ✓ (2) | ✓ | ✓ | ✓ | ✓ |
+| View pipelines and pipeline details pages | ✓ (1) | ✓ (2) | ✓ | ✓ | ✓ | ✓ |
| View pipelines tab in MR | ✓ (3) | ✓ (3) | ✓ | ✓ | ✓ | ✓ |
| [View vulnerabilities in a pipeline](application_security/vulnerability_report/pipeline.md#view-vulnerabilities-in-a-pipeline) | | ✓ (2) | ✓ | ✓ | ✓ | ✓ |
| View and download project-level [Secure Files](../api/secure_files.md) | | | | ✓ | ✓ | ✓ |
@@ -467,9 +466,10 @@ subscriptions.
> - [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.
Custom roles allow group members who are assigned the Owner role to create roles
-specific to the needs of their organization.
+specific to the needs of their organization.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For a demo of the custom roles feature, see [[Demo] Ultimate Guest can view code on private repositories via custom role](https://www.youtube.com/watch?v=46cp_-Rtxps).
@@ -481,29 +481,36 @@ To enable custom roles for your group, a group member with the Owner 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 the Guest+1 role for the group.
+1. Uses [the API](../api/member_roles.md#add-a-member-role-to-a-group) to create the Guest+1 role for the root group.
### Associate a custom role with an existing group member
To associate a custom role with an existing group member, a group member with
the Owner role:
-1. Invites a test user account to the root group as a Guest.
- At this point, this Guest user cannot see any code on the projects in the group.
+1. Invites a user 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. Associates the group 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)
+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
- 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/$GROUP_PATH/members/$GUEST_USER_ID"
- ```
+ ```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"
+
+ # 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"
+ ```
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.
- Now the Guest+1 user can view code on all projects in the root group.
+ Now the Guest+1 user can view code on all projects associated with this membership.
### Remove a custom role from a group member
diff --git a/doc/user/product_analytics/index.md b/doc/user/product_analytics/index.md
index 6d6a609618b..1a6ad4edf02 100644
--- a/doc/user/product_analytics/index.md
+++ b/doc/user/product_analytics/index.md
@@ -8,9 +8,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Introduced in GitLab 15.4 as an [Alpha](../../policy/alpha-beta-support.md#alpha-features) 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.
FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `cube_api_proxy`.
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `product_analytics_internal_preview`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
@@ -50,6 +51,7 @@ Product Analytics uses several tools:
> - Introduced in GitLab 15.6 behind the [feature flag](../../administration/feature_flags.md) named `cube_api_proxy`. Disabled by default.
> - Moved to be behind the [feature flag](../../administration/feature_flags.md) named `product_analytics_admin_settings` in GitLab 15.7. Disabled by default.
+> - `cube_api_proxy` removed and replaced with `product_analytics_internal_preview` in GitLab 15.10.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `product_analytics_admin_settings`.
@@ -205,3 +207,47 @@ The `afterDate` filter is not supported. Please use `beforeDate` or `inDateRange
}
}
```
+
+## Raw data export
+
+Exporting the raw event data from the underlying storage engine can help you debug and create datasets for data analysis.
+
+### Export raw data with Cube queries
+
+You can [query the raw data with the REST API](../../api/product_analytics.md#send-query-request-to-cube) and convert the JSON output to any required format.
+
+You can export the raw data for a specific dimension by passing a list of dimensions to the `dimensions` key. For example, the following query outputs the raw data for the attributes listed:
+
+```json
+POST /api/v4/projects/PROJECT_ID/product_analytics/request/load?queryType=multi
+
+{
+ "dimensions": [
+ "TrackedEvents.docEncoding",
+ "TrackedEvents.docHost",
+ "TrackedEvents.docPath",
+ "TrackedEvents.docSearch",
+ "TrackedEvents.eventType",
+ "TrackedEvents.idsAjsAnonymousId",
+ "TrackedEvents.localTzOffset",
+ "TrackedEvents.pageTitle",
+ "TrackedEvents.src",
+ "TrackedEvents.utcTime",
+ "TrackedEvents.vpSize"
+ ],
+ "order": {
+ "TrackedEvents.apiKey": "asc"
+ }
+}
+```
+
+If the request is successful, the returned JSON includes an array of rows of results.
+
+### Caveats
+
+Because Cube acts as an abstraction layer between the raw data and the API, the exported raw data has some caveats:
+
+- Data is grouped by the selected dimensions. Therefore, the exported data might be incomplete, unless including both `utcTime` and `userAnonymousId`.
+- Data is by default limited to 10,000 rows, but you can increase the limit to maximum 50,000 rows. If your dataset has more than 50,000 rows, you need to paginate through the results by using the `limit` and `offset` parameters.
+- Data is always returned in JSON format. If you need it in a different format, you need to convert the JSON to the required format using a scripting language of your choice.
+- [Issue 391683](https://gitlab.com/gitlab-org/gitlab/-/issues/391683) tracks the implementation of a more scalable export solution.
diff --git a/doc/user/profile/account/create_accounts.md b/doc/user/profile/account/create_accounts.md
index 60b8fe8ab88..08d23902095 100644
--- a/doc/user/profile/account/create_accounts.md
+++ b/doc/user/profile/account/create_accounts.md
@@ -16,9 +16,9 @@ You can create users:
## Create users on sign-in page
-Prerequisites:
+Prerequisite:
-- [Sign-up enabled](../../admin_area/settings/sign_up_restrictions.md)
+- [Sign-up must be enabled](../../admin_area/settings/sign_up_restrictions.md).
Users can create their own accounts by either:
@@ -27,9 +27,9 @@ Users can create their own accounts by either:
## Create users in Admin Area
-Prerequisites:
+Prerequisite:
-- You must have administrator access for the instance.
+- You must have administrator access to the instance.
To create a user manually:
diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md
index a74fd8d5215..56aa545408f 100644
--- a/doc/user/profile/account/delete_account.md
+++ b/doc/user/profile/account/delete_account.md
@@ -48,6 +48,7 @@ When deleting users, you can either:
- Delete just the user. Not all associated records are deleted with the user. Instead of being deleted, these records
are moved to a system-wide user with the username Ghost User. The Ghost User's purpose is to act as a container for
such records. Any commits made by a deleted user still display the username of the original user.
+ The user's personal projects are deleted, not moved to the Ghost User.
- Delete the user and their contributions, including:
- Abuse reports.
- Award emojis.
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index b76b99b5242..fe2e2acaae3 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -14,7 +14,7 @@ GitLab supports as a second factor of authentication:
- Time-based one-time passwords ([TOTP](https://datatracker.ietf.org/doc/html/rfc6238)). When enabled, GitLab prompts
you for a code when you sign in. Codes are generated by your one-time password authenticator (for example, a password
manager on one of your devices).
-- U2F or WebAuthn devices. You're prompted to activate your U2F or WebAuthn device (usually by pressing a button on it) when
+- WebAuthn devices. You're prompted to activate your WebAuthn device (usually by pressing a button on it) when
you supply your username and password to sign in. This performs secure authentication on your behalf.
If you set up a device, also set up a TOTP so you can still access your account if you lose the device.
@@ -42,10 +42,10 @@ Git Credential Manager is developed primarily by GitHub, Inc. It is an open-sour
> - Account email confirmation requirement [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35102) in GitLab 14.3. [Deployed behind the `ensure_verified_primary_email_for_2fa` flag](../../../administration/feature_flags.md), enabled by default.
> - Account email confirmation requirement generally available and [feature flag `ensure_verified_primary_email_for_2fa` removed](https://gitlab.com/gitlab-org/gitlab/-/issues/340151) in GitLab 14.4.
-You can enable 2FA:
+You can enable 2FA using a:
-- Using a one-time password authenticator. After you enable 2FA, back up your [recovery codes](#recovery-codes).
-- Using a U2F or WebAuthn device.
+- One-time password authenticator. After you enable 2FA, back up your [recovery codes](#recovery-codes).
+- WebAuthn device.
In GitLab 14.3 and later, your account email must be confirmed to enable 2FA.
@@ -60,10 +60,11 @@ To enable 2FA with a one-time password:
1. **On your device (usually your phone):**
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/)
+ - [Authy](https://authy.com/).
+ - [Duo](https://duo.com/).
- Other:
- - [Google Authenticator](https://support.google.com/accounts/answer/1066447?hl=en)
- - [Microsoft Authenticator](https://www.microsoft.com/en-us/security/mobile-authenticator-app)
+ - [Google Authenticator](https://support.google.com/accounts/answer/1066447?hl=en).
+ - [Microsoft Authenticator](https://www.microsoft.com/en-us/security/mobile-authenticator-app).
1. In the application, add a new entry in one of two ways:
- Scan the code displayed by GitLab with your device's camera to add the entry automatically.
- Enter the details provided to add the entry manually.
@@ -72,9 +73,6 @@ To enable 2FA with a one-time password:
1. Enter your current password.
1. Select **Submit**.
-NOTE:
-DUO [cannot be used for 2FA](https://gitlab.com/gitlab-org/gitlab/-/issues/15760).
-
If you entered the correct pin, GitLab displays a list of [recovery codes](#recovery-codes). Download them and keep them
in a safe place.
@@ -141,6 +139,70 @@ Configure FortiAuthenticator in GitLab. On your GitLab server:
1. [Reconfigure](../../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) (Omnibus GitLab) or
[restart](../../../administration/restart_gitlab.md#installations-from-source) (GitLab installed from source).
+### Enable one-time password using 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.
+
+#### Prerequisites
+
+To use Duo as an OTP provider:
+
+- 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 [Duo API documentation](https://duo.com/docs/authapi).
+
+GitLab 15.10 has been tested with Duo version D261.14
+
+#### Configure Duo in GitLab
+
+On your GitLab server:
+
+1. Open the configuration file.
+
+ For Omnibus GitLab:
+
+ ```shell
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For installations from source:
+
+ ```shell
+ cd /home/git/gitlab
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+1. Add the provider configuration:
+
+ For Omnibus package:
+
+ ```ruby
+ gitlab_rails['duo_auth_enabled'] = false
+ gitlab_rails['duo_auth_integration_key'] = '<duo_integration_key_value>'
+ gitlab_rails['duo_auth_secret_key'] = '<duo_secret_key_value>'
+ gitlab_rails['duo_auth_hostname'] = '<duo_api_hostname>'
+ ```
+
+ For installations from source:
+
+ ```yaml
+ duo_auth:
+ enabled: true
+ hostname: <duo_api_hostname>
+ integration_key: <duo_integration_key_value>
+ secret_key: <duo_secret_key_value>
+ ```
+
+1. Save the configuration file.
+1. For Omnibus GitLab, [reconfigure GitLab](../../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure).
+ For installations from source, [restart GitLab](../../../administration/restart_gitlab.md#installations-from-source).
+
### Enable one-time password using FortiToken Cloud
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/212313) in GitLab 13.7 [with a flag](../../../administration/feature_flags.md) named `forti_token_cloud`. Disabled by default.
@@ -198,68 +260,61 @@ Configure FortiToken Cloud in GitLab. On your GitLab server:
1. [Reconfigure](../../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) (Omnibus GitLab) or
[restart](../../../administration/restart_gitlab.md#installations-from-source) (GitLab installed from source).
-### Set up a U2F device
-
-GitLab officially supports [YubiKey](https://www.yubico.com/products/) U2F devices, but users have successfully used
-[SoloKeys](https://solokeys.com/) and [Google Titan Security Key](https://cloud.google.com/titan-security-key).
-
-U2F is [supported by](https://caniuse.com/#search=U2F) the following desktop browsers:
-
-- Chrome
-- Edge
-- Opera
-- Firefox 67+. For Firefox 47-66:
-
- 1. Enable the FIDO U2F API in [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
- 1. Search for `security.webauth.u2f` and select it to toggle to `true`.
-
-To set up 2FA with a U2F device:
-
-1. Access your [**User settings**](../index.md#access-your-user-settings).
-1. Select **Account**.
-1. Select **Enable Two-Factor Authentication**.
-1. Connect your U2F device.
-1. Select **Set up New U2F Device**.
-1. A light begins blinking on your device. Activate it by pressing its button.
-
-A message displays indicating that your device was successfully set up. Select **Register U2F Device** to complete the
-process. Recovery codes are not generated for U2F devices.
-
### Set up a WebAuthn device
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22506) in GitLab 13.4 [with a flag](../../../administration/feature_flags.md) named `webauthn`. Disabled by default.
-> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/232671) in GitLab 14.6.
+> - WebAuthn devices [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22506) in GitLab 13.4 [with a flag](../../../administration/feature_flags.md) named `webauthn`. Disabled by default.
+> - WebAuthn devices [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/232671) in GitLab 14.6.
+> - Optional one-time password authentication for WebAuthn devices [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378844) in GitLab 15.10 [with a flag](../../../administration/feature_flags.md) named `webauthn_without_topt`. [Enabled on GitLab.com and self-managed by default](https://gitlab.com/gitlab-org/gitlab/-/issues/232671).
FLAG:
-On self-managed GitLab, by default this feature is available. To disable the feature, ask an administrator to
+On self-managed GitLab, by default, WebAuthn devices are available. To disable the feature, ask an administrator to
[disable the feature flag](../../../administration/feature_flags.md) named `webauthn`. If you disable the WebAuthn
feature flag after WebAuthn devices have been registered, these devices are not usable until you re-enable this feature.
+On GitLab.com, WebAuthn devices are available.
+
+FLAG:
+On self-managed GitLab, by default, optional one-time password authentication for WebAuthn devices is available. To hide the feature, ask an administrator to [disable the feature flag](../../../administration/feature_flags.md) named `webauthn_without_topt`.
On GitLab.com, this feature is available.
-WebAuthn [supported by](https://caniuse.com/#search=webauthn):
+WebAuthn is [supported by](https://caniuse.com/#search=webauthn) the following:
-- The following desktop browsers:
+- Desktop browsers:
- Chrome
- Edge
- Firefox
- Opera
- Safari
-- The following mobile browsers:
+- Mobile browsers:
- Chrome for Android
- Firefox for Android
- iOS Safari (since iOS 13.3)
To set up 2FA with a WebAuthn-compatible device:
+1. Optional. [Set up a one-time password](#enable-one-time-password).
1. Access your [**User settings**](../index.md#access-your-user-settings).
1. Select **Account**.
1. Select **Enable Two-Factor Authentication**.
1. Plug in your WebAuthn device.
+1. Enter a device name and in GitLab 15.10 and later, your GitLab account password.
+ You might not need to enter this password if you have signed in through your
+ identity provider.
1. Select **Set up New WebAuthn Device**.
1. Depending on your device, you might have to press a button or touch a sensor.
-A message displays indicating that your device was successfully set up. Recovery codes are not generated for WebAuthn
-devices.
+You should receive a message indicating that you successfully set up your device.
+
+When you set up 2FA with a WebAuthn-compatible device, that device is linked to
+a specific browser on a specific computer. Depending on the browser and WebAuthn
+device, you might be able to configure settings to use the WebAuthn device on a
+different browser or computer.
+
+If this is the first time you have set up 2FA, you
+must [download recovery codes](#recovery-codes) so you can recover access to your
+account if you lose access.
+
+WARNING:
+You can lose access to your account if you clear your browser data.
## Recovery codes
@@ -272,11 +327,11 @@ these recovery codes to sign in to your account.
WARNING:
Each code can be used only once to sign in to your account.
-We recommend copying and printing them, or downloading them using the **Download codes** button for storage in a safe
+You should copy and print the codes, or use **Download codes** to download them for storage in a safe
place. If you choose to download them, the file is called `gitlab-recovery-codes.txt`.
NOTE:
-Recovery codes are not generated for U2F or WebAuthn devices.
+Recovery codes are not generated for WebAuthn devices.
If you lose the recovery codes, or want to generate new ones, you can use either:
@@ -302,18 +357,7 @@ and you're presented with a second prompt, depending on which type of 2FA you've
### Sign in using a one-time password
-When asked, enter the pin from your one time password authenticator's application or a recovery code to sign in.
-
-### Sign in using a U2F device
-
-To sign in by using a U2F device:
-
-1. Select **Login via U2F Device**.
-1. A light begins blinking on your device. Activate it by touching/pressing
- its button.
-
-A message displays indicating that your device responded to the authentication request, and you're automatically signed
-in.
+When asked, enter the pin from your one-time password authenticator's application or a recovery code to sign in.
### Sign in using a WebAuthn device
@@ -333,7 +377,7 @@ To disable 2FA:
1. Under **Register Two-Factor Authenticator**, enter your current password and select **Disable two-factor
authentication**.
-This clears all your 2FA registrations, including mobile applications and U2F or WebAuthn devices.
+This clears all your 2FA registrations, including mobile applications and WebAuthn devices.
## Recovery options
@@ -412,18 +456,18 @@ a GitLab global administrator disable 2FA for your account:
## Information for GitLab administrators **(FREE SELF)**
- Take care that 2FA keeps working after [restoring a GitLab backup](../../../raketasks/backup_restore.md).
-- To ensure 2FA authorizes correctly with a time-based one time passwords (TOTP) server, synchronize your GitLab
+- To ensure 2FA authorizes correctly with a time-based one-time password (TOTP) server, synchronize your GitLab
server's time using a service like NTP. Otherwise, authorization can always fail because of time differences.
-- The GitLab U2F and WebAuthn implementation does _not_ work when the GitLab instance is accessed from multiple hostnames
- or FQDNs. Each U2F or WebAuthn registration is linked to the _current hostname_ at the time of registration, and
+- The GitLab WebAuthn implementation does _not_ work when the GitLab instance is accessed from multiple hostnames
+ or FQDNs. Each WebAuthn registration is linked to the _current hostname_ at the time of registration, and
cannot be used for other hostnames or FQDNs.
For example, if a user is trying to access a GitLab instance from `first.host.xyz` and `second.host.xyz`:
- - The user signs in by using `first.host.xyz` and registers their U2F key.
- - The user signs out and attempts to sign in by using `first.host.xyz` - U2F authentication succeeds.
- - The user signs out and attempts to sign in by using `second.host.xyz` - U2F authentication fails, because
- the U2F key has only been registered on `first.host.xyz`.
+ - The user signs in by using `first.host.xyz` and registers their WebAuthn key.
+ - The user signs out and attempts to sign in by using `first.host.xyz` - WebAuthn authentication succeeds.
+ - The user signs out and attempts to sign in by using `second.host.xyz` - WebAuthn authentication fails, because
+ the WebAuthn key has only been registered on `first.host.xyz`.
- To enforce 2FA at the system or group levels see, [Enforce two-factor authentication](../../../security/two_factor_authentication.md).
diff --git a/doc/user/profile/active_sessions.md b/doc/user/profile/active_sessions.md
index 1f7264d740e..f22accf2ff5 100644
--- a/doc/user/profile/active_sessions.md
+++ b/doc/user/profile/active_sessions.md
@@ -40,8 +40,8 @@ To revoke an active session:
NOTE:
When any session is revoked all **Remember me** tokens for all
-devices are revoked. See [Why do you keep getting signed out?](index.md#why-do-you-keep-getting-signed-out)
-for more information about the **Remember me** feature.
+devices are revoked. For details about **Remember me**, see
+[cookies used for sign-in](index.md#cookies-used-for-sign-in).
<!-- ## Troubleshooting
diff --git a/doc/user/profile/contributions_calendar.md b/doc/user/profile/contributions_calendar.md
index e9802cccef6..7b5691e1ee5 100644
--- a/doc/user/profile/contributions_calendar.md
+++ b/doc/user/profile/contributions_calendar.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
type: concepts, howto
---
@@ -83,7 +83,7 @@ GitLab provides RSS feeds of user activity. To subscribe to the
RSS feed of a user's activity:
1. Go to the [user's profile](index.md#access-your-user-profile).
-1. In the upper right, select the feed symbol **{rss}** to display the results as an RSS feed in Atom format.
+1. In the upper-right corner, select the feed symbol (**{rss}**) to display the results as an RSS feed in Atom format.
The URL of the result contains both a feed token, and
the user's activity that you're authorized to view.
diff --git a/doc/user/profile/img/saved_replies_dropdown_v15_10.png b/doc/user/profile/img/saved_replies_dropdown_v15_10.png
new file mode 100644
index 00000000000..50313f71f4a
--- /dev/null
+++ b/doc/user/profile/img/saved_replies_dropdown_v15_10.png
Binary files differ
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index a84d16e6d0c..d52f119ba09 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -34,9 +34,13 @@ If you do not want to update the namespace, you can create a new user or group a
Prerequisites:
-- Your namespace cannot contain a project with [Container Registry](../packages/container_registry/index.md) tags.
-- Your namespace cannot have a project that hosts [GitLab Pages](../project/pages/index.md). For more information,
- see [this procedure in the GitLab Team Handbook](https://about.gitlab.com/handbook/tools-and-tips/#change-your-username-at-gitlabcom).
+- Your namespace must not:
+ - Contain a project with [Container Registry](../packages/container_registry/index.md) tags.
+ - Have a project that hosts [GitLab Pages](../project/pages/index.md). For more information,
+ see [changing your username in the GitLab Team Handbook](https://about.gitlab.com/handbook/tools-and-tips/#change-your-username-at-gitlabcom).
+- Your username must be between 2 and 255 characters in length, and must not:
+ - Contain special characters or emojis.
+ - End with `.<reserved file extension>`, for example `jon.png`. However, `jonpng` is valid.
To change your username:
@@ -310,9 +314,9 @@ and configure it on your local machine by using the following command:
git config --global user.email <your email address>
```
-## User activity
+## Follow users
-GitLab tracks [user contribution activity](contributions_calendar.md). You can follow or unfollow other users from either:
+You can follow or unfollow users from either:
- Their [user profiles](#access-your-user-profile).
- The small popover that appears when you hover over a user's name ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76050)
@@ -321,66 +325,56 @@ GitLab tracks [user contribution activity](contributions_calendar.md). You can f
In [GitLab 15.5 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/360755),
the maximum number of users you can follow is 300.
-To view a user's activity in a top-level Activity view:
+## View your activity
+
+GitLab tracks [user contribution activity](contributions_calendar.md).
+To view a summary of your activity, or the activity of other users:
1. From a user's profile, select **Follow**.
1. In the GitLab menu, select **Activity**.
1. Select the **Followed users** tab.
-## Troubleshooting
-
-### Why do you keep getting signed out?
+## Stay signed in for two weeks
-When you sign in to the main GitLab application, a `_gitlab_session` cookie is
-set. When you close your browser, the cookie is cleared client-side
-and it expires after a set duration. GitLab administrators can determine the duration:
+By default, you are signed out of GitLab every seven days, or 10080 minutes.
+GitLab administrators can
+[change this default](../admin_area/settings/account_and_limit_settings.md#customize-the-default-session-duration).
-1. On the top bar, select **Main menu > Admin**.
-1. On the left sidebar, select **Settings > General**.
-1. Expand **Account and limit**. The set duration is in **Session duration (minutes)**.
+To extend the duration to two weeks:
-The default is `10080`, which equals 7 days.
+- On the GitLab sign-in page, select the **Remember me** checkbox.
-When you sign in to the main GitLab application, you can also check the
-**Remember me** option. This sets the `remember_user_token`
-cookie via [`devise`](https://github.com/heartcombo/devise).
-The `remember_user_token` cookie expires after
-`config/initializers/devise.rb` -> `config.remember_for`. The default is 2 weeks.
+## Stay signed in indefinitely
-When the `_gitlab_session` expires or isn't available, GitLab uses the `remember_user_token`
-to get you a new `_gitlab_session` and keep you signed in through browser restarts.
+To remain signed in indefinitely:
-After your `remember_user_token` expires and your `_gitlab_session` is cleared/expired,
-you are asked to sign in again to verify your identity for security reasons.
+1. On the GitLab sign-in page, select the **Remember me** checkbox.
+1. Access GitLab at least once every two weeks, and leave your browser open.
-NOTE:
-When any session is signed out, or when a session is revoked
-via [Active Sessions](active_sessions.md), all **Remember me** tokens are revoked.
-While other sessions remain active, the **Remember me** feature doesn't restore
-a session if the browser is closed or the existing session expires.
+You remain signed in because, although the server sets a time-to-live (TTL) of one week on your browser session,
+the server continues to reset the TTL, regardless of whether 2FA is installed.
-### Increased sign-in time
+### Cookies used for sign-in
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20340) in GitLab 13.1.
-The `remember_user_token` lifetime of a cookie can now extend beyond the deadline set by `config.remember_for`, as the `config.extend_remember_period` flag is now set to true.
+When you sign in, two cookies are set:
-GitLab uses both session and persistent cookies:
+- A session cookie called `_gitlab_session`.
+ This cookie has no set expiration date. However, it expires based on its `session_expire_delay`.
+- A persistent cookie called `remember_user_token`, which is set only if you selected **Remember me** on the sign-in page.
-- Session cookie: Session cookies are typically removed at the end of the browser session when
- the browser is closed. The `_gitlab_session` cookie has no fixed expiration date. However,
- it expires based on its [`session_expire_delay`](#why-do-you-keep-getting-signed-out).
-- Persistent cookie: The `remember_user_token` is a cookie with an expiration date of two weeks.
- GitLab activates this cookie if you select **Remember Me** when you sign in.
+When you close your browser, the `_gitlab_session` cookie is 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.
-By default, the server sets a time-to-live (TTL) of 1-week on any session that is used.
+When both cookies are gone or expired, you must sign in again.
-When you close a browser, the session cookie may still remain. For example, Chrome has the "Continue where you left off" option that restores session cookies.
-In other words, as long as you access GitLab at least once every 2 weeks, you could remain signed in with GitLab, as long as your browser tab is open.
-The server continues to reset the TTL for that session, independent of whether 2FA is installed,
-If you close your browser and open it up again, the `remember_user_token` cookie allows your user to reauthenticate itself.
-
-Without the `config.extend_remember_period` flag, you would be forced to sign in again after two weeks.
+NOTE:
+When any session is signed out, or when a session is revoked
+from the [active sessions list](active_sessions.md), all **Remember me** tokens are revoked.
+While other sessions remain active, the **Remember me** feature doesn't restore
+a session if the browser is closed or the existing session expires.
## Related topics
@@ -389,7 +383,7 @@ Without the `config.extend_remember_period` flag, you would be forced to sign in
- [Change your password](user_passwords.md)
- Receive emails for:
- [Sign-ins from unknown IP addresses or devices](notifications.md#notifications-for-unknown-sign-ins)
- - [Attempted sign-ins using wrong two-factor authentication codes](notifications.md#notifications-for-attempted-sign-in-using-wrong-two-factor-authentication-codes)
+ - [Attempted sign-ins using incorrect verification codes](notifications.md#notifications-for-attempted-sign-ins-using-incorrect-verification-codes)
- Manage applications that can [use GitLab as an OAuth provider](../../integration/oauth_provider.md)
- Manage [personal access tokens](personal_access_tokens.md) to access your account via API and authorized applications
- Manage [SSH keys](../ssh.md) to access your account via SSH
diff --git a/doc/user/profile/notifications.md b/doc/user/profile/notifications.md
index dcc78dac05b..e6675b4eff2 100644
--- a/doc/user/profile/notifications.md
+++ b/doc/user/profile/notifications.md
@@ -286,7 +286,8 @@ To always receive notifications on your own issues, merge requests, and so on, t
## Notifications for unknown sign-ins
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27211) in GitLab 13.0.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27211) in GitLab 13.0.
+> - Listing the full name and username of the signed-in user [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225183) in GitLab 15.10.
NOTE:
This feature is enabled by default for self-managed instances. Administrators may disable this feature
@@ -295,7 +296,12 @@ The feature is always enabled on GitLab.com.
When a user successfully signs in from a previously unknown IP address or device,
GitLab notifies the user by email. In this way, GitLab proactively alerts users of potentially
-malicious or unauthorized sign-ins.
+malicious or unauthorized sign-ins. This notification email includes the:
+
+- Hostname.
+- User's name and username.
+- IP address.
+- Date and time of sign-in.
GitLab uses several methods to identify a known sign-in. All methods must fail for a notification email to be sent.
@@ -306,7 +312,7 @@ GitLab uses several methods to identify a known sign-in. All methods must fail f
- Cookie: After successful sign in, an encrypted cookie is stored in the browser.
This cookie is set to expire 14 days after the last successful sign in.
-## Notifications for attempted sign-in using wrong two-factor authentication codes
+## Notifications for attempted sign-ins using incorrect verification codes
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/374740) in GitLab 15.5.
diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index 3826c602fb4..0c733b8de30 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -45,9 +45,6 @@ For examples of how you can use a personal access token to authenticate with the
Alternately, GitLab administrators can use the API to create [impersonation tokens](../../api/rest/index.md#impersonation-tokens).
Use impersonation tokens to automate authentication as a specific user.
-NOTE:
-Personal access tokens are not FIPS compliant and creation and use are disabled when [FIPS mode](../../development/fips_compliance.md) is enabled.
-
## Create a personal access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/348660) in GitLab 15.3, default expiration of 30 days is populated in the UI.
@@ -225,7 +222,7 @@ Remember this if you set up an automation pipeline that depends on authenticatio
### Unrevoke a personal access token **(FREE SELF)**
-If a personal access token is revoked accidentally by any method, administrators can unrevoke that token.
+If a personal access token is revoked accidentally by any method, administrators can unrevoke that token. By default, a daily job deletes revoked tokens at 1:00 AM system time.
WARNING:
Running the following commands changes data directly. This could be damaging if not done correctly, or under the right conditions. You should first run these commands in a test environment with a backup of the instance ready to be restored, just in case.
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index 7e581bb7419..0f46c3d6d25 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -63,6 +63,8 @@ Dark theme only works with the **Dark** syntax highlighting theme.
## Syntax highlighting theme
+> Changing the default syntax highlighting theme for new users and users who are not signed in [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25129) in GitLab 15.10.
+
GitLab uses the [rouge Ruby library](http://rouge.jneen.net/ "Rouge website")
for syntax highlighting outside of any Editor context. The WebIDE (like Snippets)
uses [Monaco Editor](https://microsoft.github.io/monaco-editor/) and it's provided
@@ -89,6 +91,10 @@ The default syntax theme is White, and you can choose among 5 different themes:
Introduced in GitLab 13.6, the themes [Solarized](https://gitlab.com/gitlab-org/gitlab/-/issues/221034) and [Monokai](https://gitlab.com/gitlab-org/gitlab/-/issues/221034) also apply to the [Web IDE](../project/web_ide/index.md) and [Snippets](../snippets.md).
+You can use an API call to change the default syntax highlighting theme for new users and users
+who are not signed in. For more information, see the `default_syntax_highlighting_theme`
+in the [list of settings that can be accessed through API calls](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
+
## Diff colors
A diff compares the old/removed content with the new/added content (for example, when
diff --git a/doc/user/profile/saved_replies.md b/doc/user/profile/saved_replies.md
new file mode 100644
index 00000000000..302daceb31d
--- /dev/null
+++ b/doc/user/profile/saved_replies.md
@@ -0,0 +1,61 @@
+---
+stage: Create
+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
+type: howto
+---
+
+# Saved replies **(FREE)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352956) in GitLab 14.9 [with a flag](../../administration/feature_flags.md) named `saved_replies`. Disabled by default.
+
+With saved replies, create and reuse text for any text area in:
+
+- Merge requests, including diffs.
+- Issues, including design management comments.
+- Epics.
+- Work items.
+
+Saved replies can be small, like approving a merge request and unassigning yourself from it,
+or large, like chunks of boilerplate text you use frequently:
+
+![Saved replies dropdown list](img/saved_replies_dropdown_v15_10.png)
+
+## Use saved replies in a text area
+
+To include the text of a saved reply in your comment:
+
+1. In the editor toolbar for your comment, select **Saved replies** (**{symlink}**).
+1. Select your desired saved reply.
+
+## Create saved replies
+
+To create a saved reply for future use:
+
+1. On the top bar, in the upper-right corner, select your avatar.
+1. From the dropdown list, select **Preferences**.
+1. On the left sidebar, select **Saved replies** (**{symlink}**).
+1. Provide a **Name** for your saved reply.
+1. Enter the **Content** of your reply. You can use any formatting you use in
+ other GitLab text areas.
+1. Select **Save**, and the page reloads with your saved reply shown.
+
+## View your saved replies
+
+To go to your saved replies:
+
+1. On the top bar, in the upper-right corner, select your avatar.
+1. From the dropdown list, select **Preferences**.
+1. On the left sidebar, select **Saved replies** (**{symlink}**).
+1. Scroll to **My saved replies**.
+
+## Edit or delete saved replies
+
+To edit or delete a previously saved reply:
+
+1. On the top bar, in the upper-right corner, select your avatar.
+1. From the dropdown list, select **Preferences**.
+1. On the left sidebar, select **Saved replies** (**{symlink}**).
+1. Scroll to **My saved replies**, and identify the saved reply you want to edit.
+1. To edit, select **Edit** (**{pencil}**).
+1. To delete, select **Delete** (**{remove}**), then select **Delete** again from the modal window.
diff --git a/doc/user/project/badges.md b/doc/user/project/badges.md
index 0ea1a80bc54..2d36a378b82 100644
--- a/doc/user/project/badges.md
+++ b/doc/user/project/badges.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
@@ -117,6 +117,10 @@ time with the `?order_by` query parameter.
https://gitlab.example.com/<namespace>/<project>/-/badges/release.svg?order_by=release_at
```
+You can change the width of the release name field by using the `value_width` parameter ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113615) in GitLab 15.10).
+The value must be between 1 and 200, and the default value is 54.
+If you set an out of range value, GitLab automatically adjusts it to the default value.
+
## Project badges
Badges can be added to a project by Maintainers or Owners, and are visible on the project's overview page.
diff --git a/doc/user/project/clusters/add_eks_clusters.md b/doc/user/project/clusters/add_eks_clusters.md
index 52288af101a..3ed8a4a67cf 100644
--- a/doc/user/project/clusters/add_eks_clusters.md
+++ b/doc/user/project/clusters/add_eks_clusters.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Connect EKS clusters through cluster certificates (DEPRECATED) **(FREE)**
+# Connect EKS clusters through cluster certificates (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22392) in GitLab 12.5.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
@@ -25,7 +25,7 @@ use the [GitLab agent](../../clusters/agent/index.md).
To create a new cluster from GitLab, use [Infrastructure as Code](../../infrastructure/iac/index.md).
-### How to create a new cluster on EKS through cluster certificates (DEPRECATED)
+### How to create a new cluster on EKS through cluster certificates (deprecated)
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/327908) in GitLab 14.0.
diff --git a/doc/user/project/clusters/add_existing_cluster.md b/doc/user/project/clusters/add_existing_cluster.md
index 0b0555806ce..a7fac2a1cea 100644
--- a/doc/user/project/clusters/add_existing_cluster.md
+++ b/doc/user/project/clusters/add_existing_cluster.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Connect existing clusters through cluster certificates (DEPRECATED) **(FREE)**
+# Connect existing clusters through cluster certificates (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/project/clusters/add_gke_clusters.md b/doc/user/project/clusters/add_gke_clusters.md
index b1c5bbfc4f7..e00c4370da9 100644
--- a/doc/user/project/clusters/add_gke_clusters.md
+++ b/doc/user/project/clusters/add_gke_clusters.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Connect GKE clusters through cluster certificates (DEPRECATED) **(FREE)**
+# Connect GKE clusters through cluster certificates (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/project/clusters/add_remove_clusters.md b/doc/user/project/clusters/add_remove_clusters.md
index d3048158958..bf2f6e28d9a 100644
--- a/doc/user/project/clusters/add_remove_clusters.md
+++ b/doc/user/project/clusters/add_remove_clusters.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Add a cluster using cluster certificates (DEPRECATED) **(FREE)**
+# Add a cluster using cluster certificates (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/327908) in GitLab 14.0.
diff --git a/doc/user/project/clusters/cluster_access.md b/doc/user/project/clusters/cluster_access.md
index 529e7a6da12..0eea3ebb8cd 100644
--- a/doc/user/project/clusters/cluster_access.md
+++ b/doc/user/project/clusters/cluster_access.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Access controls with cluster certificates (RBAC or ABAC) (DEPRECATED) **(FREE)**
+# Access controls with cluster certificates (RBAC or ABAC) (deprecated) **(FREE)**
> - Restricted service account for deployment was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/51716) in GitLab 11.5.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/project/clusters/deploy_to_cluster.md b/doc/user/project/clusters/deploy_to_cluster.md
index 173f1f39a66..e2d0a010293 100644
--- a/doc/user/project/clusters/deploy_to_cluster.md
+++ b/doc/user/project/clusters/deploy_to_cluster.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Deploy to a Kubernetes cluster with cluster certificates (DEPRECATED) **(FREE)**
+# Deploy to a Kubernetes cluster with cluster certificates (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/project/clusters/gitlab_managed_clusters.md b/doc/user/project/clusters/gitlab_managed_clusters.md
index b2a4bd85de4..46e74eb8460 100644
--- a/doc/user/project/clusters/gitlab_managed_clusters.md
+++ b/doc/user/project/clusters/gitlab_managed_clusters.md
@@ -4,7 +4,7 @@ group: Configure
info: To 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-managed clusters (DEPRECATED) **(FREE)**
+# GitLab-managed clusters (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22011) in GitLab 11.5.
> - Became [optional](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26565) in GitLab 11.11.
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 94513fc7124..490188b27b0 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Project-level Kubernetes clusters (certificate-based) (DEPRECATED) **(FREE)**
+# Project-level Kubernetes clusters (certificate-based) (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/35954) in GitLab 10.1.
> - [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
diff --git a/doc/user/project/clusters/multiple_kubernetes_clusters.md b/doc/user/project/clusters/multiple_kubernetes_clusters.md
index c79f250da7a..9167e6197d6 100644
--- a/doc/user/project/clusters/multiple_kubernetes_clusters.md
+++ b/doc/user/project/clusters/multiple_kubernetes_clusters.md
@@ -4,7 +4,7 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Multiple clusters per project with cluster certificates (DEPRECATED) **(FREE)**
+# Multiple clusters per project with cluster certificates (deprecated) **(FREE)**
> - Introduced in GitLab 10.3
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35094) from GitLab Premium to GitLab Free in 13.2.
diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md
index df0ffff8561..b1f2a9dbb79 100644
--- a/doc/user/project/clusters/runbooks/index.md
+++ b/doc/user/project/clusters/runbooks/index.md
@@ -107,7 +107,7 @@ the components outlined above and the pre-loaded demo runbook.
'''
We set user's id, login and access token on single user image to
enable repository integration for JupyterHub.
- See: https://gitlab.com/gitlab-org/gitlab-foss/issues/47138#note_154294790
+ See: https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47138#note_154294790
'''
auth_state = await spawner.user.get_auth_state()
diff --git a/doc/user/project/code_owners.md b/doc/user/project/code_owners.md
index 9de9d445965..0994bff4aa2 100644
--- a/doc/user/project/code_owners.md
+++ b/doc/user/project/code_owners.md
@@ -8,12 +8,32 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> Moved to GitLab Premium in 13.9.
-Code Owners define who develops and maintains a feature, and own the resulting
-files or directories in a repository.
+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:
-- The users you define as Code Owners are displayed in the UI when you browse directories.
-- You can set your merge requests so they must be approved by Code Owners before merge.
-- You can protect a branch and allow only Code Owners to approve changes to the branch.
+- **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
+[approval rules](merge_requests/approvals/rules.md) (either optional or required)
+to build a flexible approval workflow:
+
+- Use **Code Owners** to ensure quality. Define the users who have domain expertise
+ for specific paths in your repository.
+- Use **Approval rules** to define areas of expertise that don't correspond to specific
+ file paths in your repository. Approval rules help guide merge request creators to
+ the correct set of reviewers, such as frontend developers or a security team.
+
+For example:
+
+| Type | Name | Scope | Comment |
+|------|------|--------|------------|
+| Approval rule | UX | All files | A user experience (UX) team member reviews the user experience of all changes made in your project.
+| Approval rule | Security | All files | A security team member reviews all changes for vulnerabilities.
+| Code Owner approval rule | Frontend: Code Style | `*.css` files | A frontend engineer reviews CSS file changes for adherence to project style standards.
+| Code Owner approval rule | Backend: Code Review | `*.rb` files | A backend engineer reviews the logic and code style of Ruby files.
<div class="video-fallback">
Video introduction: <a href="https://www.youtube.com/watch?v=RoyBySTUSB0">Code Owners</a>.
@@ -24,45 +44,20 @@ files or directories in a repository.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-Use Code Owners and approvers together with
-[approval rules](merge_requests/approvals/rules.md) to build a flexible approval
-workflow:
-
-- Use **Code Owners** to define the users who have domain expertise for specific paths in your repository.
-- Use **Approvers** and **Approval rules** to define domains of expertise (such as a security team)
- that are not scoped to specific file paths in your repository.
- - **Approvers** define the users.
- - **Approval rules** define when these users can approve work, and whether or not their approval is required.
-
-For example:
-
-| Type | Name | Scope | Comment |
-|------|------|--------|------------|
-| Approval rule | UX | All files | A user experience (UX) team member reviews the user experience of all changes made in your project. |
-| Approval rule | Security | All files | A security team member reviews all changes for vulnerabilities. |
-| Code Owner approval rule | Frontend: Code Style | `*.css` files | A frontend engineer reviews CSS file changes for adherence to project style standards. |
-| Code Owner approval rule | Backend: Code Review | `*.rb` files | A backend engineer reviews the logic and code style of Ruby files. |
-
-## Code Owners file
+## View a file's Code Owner
-A `CODEOWNERS` file (with no extension) can specify users or [shared groups](members/share_project_with_groups.md)
-that are responsible for specific files and directories in a repository. Each repository
-can have a single `CODEOWNERS` file, and it must be found one of these three locations:
+To view the Code Owners for a file:
-- In the root directory of the repository.
-- In the `.gitlab/` directory.
-- In the `docs/` directory.
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Repository > Files**.
+1. Go to the file or directory you want to see the Code Owners for.
+1. Optional. Select your desired branch.
-A CODEOWNERS file in any other location is ignored.
+GitLab shows the Code Owners at the top of the page.
## Set up Code Owners
-1. Create a file named `CODEOWNERS` (with no extension) in one of these locations:
-
-- In the root directory of the repository
-- In the `.gitlab/` directory
-- In the `docs/` directory
-
+1. Create a `CODEOWNERS` file in your [preferred location](#code-owners-file).
1. In the file, enter text that follows one of these patterns:
```plaintext
@@ -79,17 +74,28 @@ A CODEOWNERS file in any other location is ignored.
directoryname/ @groupname
```
-The Code Owners are now displayed in the UI. They apply to the current branch only.
+### Code Owners file
+
+A `CODEOWNERS` file (with no extension) specifies the users or
+[shared groups](members/share_project_with_groups.md) responsible for
+specific files and directories in a repository.
+
+Each repository uses a single `CODEOWNERS` file. GitLab checks these locations
+in your repository in this order. The first `CODEOWNERS` file found is used, and
+all others are ignored:
-Next steps:
+1. In the root directory: `./CODEOWNERS`.
+1. In the `docs` directory: `./docs/CODEOWNERS`.
+1. In the `.gitlab` directory: `./.gitlab/CODEOWNERS`.
+
+### Make Code Owners eligible approvers or require their approval of MRs
- [Add Code Owners as merge request approvers](merge_requests/approvals/rules.md#code-owners-as-eligible-approvers).
- Set up [Code Owner approval on a protected branch](protected_branches.md#require-code-owner-approval-on-a-protected-branch).
-## Groups as Code Owners
+### Groups as Code Owners
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/53182) in GitLab 12.1.
-> - Group and subgroup hierarchy support was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32432) in GitLab 13.0.
+> Group and subgroup hierarchy support was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32432) in GitLab 13.0.
You can use members of groups and subgroups as Code Owners for projects:
@@ -137,7 +143,7 @@ For approval to be required, groups as Code Owners must have a direct membership
that inherit membership. Members in the Code Owners group also must be direct members,
and not inherit membership from any parent groups.
-### Add a group as a Code Owner
+#### Add a group as a Code Owner
To set a group as a Code Owner:
@@ -154,23 +160,26 @@ file.md @group-x/subgroup-y
file.md @group-x @group-x/subgroup-y
```
-## When a file matches multiple `CODEOWNERS` entries
+### Define more specific owners for more specifically defined files or directories
-When a file matches multiple entries in the `CODEOWNERS` file,
-the users from last pattern matching the file are used.
+When a file or directory matches multiple entries in the `CODEOWNERS` file,
+the users from last pattern matching the file or directory are used. This enables you
+to define more specific owners for more specifically defined files or directories, when
+you order the entries in a sensible way.
For example, in the following `CODEOWNERS` file:
```plaintext
-README.md @user1
+# This line would match the file terms.md
+*.md @doc-team
-# This line would also match the file README.md
-*.md @user2
+# This line would also match the file terms.md
+terms.md @legal-team
```
-The Code Owner for `README.md` would be `@user2`.
+The Code Owner for `terms.md` would be `@legal-team`.
-If you use sections, the last pattern matching the file for each section is used.
+If you use sections, the last pattern matching the file or directory for each section is used.
For example, in a `CODEOWNERS` file using sections:
```plaintext
@@ -183,9 +192,9 @@ README.md @user3
```
The Code Owners for the `README.md` in the root directory are `@user1`, `@user2`,
-and `@user3`. The Code Owners for `internal/README.md` are `@user4` and `@user3`.
+and `@user3`. The Code Owners for `internal/README.md` are `@user4` and `@user3`.
-Only one CODEOWNERS pattern can match per file path.
+Only one CODEOWNERS pattern per section is matched to a file path.
### Organize Code Owners by putting them into sections
@@ -211,7 +220,56 @@ The following image shows a **Groups** and **Documentation** section:
![MR widget - Sectional Code Owners](img/sectional_code_owners_v13.2.png)
-### Sections with duplicate names
+#### Set default owner for a section **(PREMIUM SELF)**
+
+> [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.
+
+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 `codeowners_default_owners`.
+The feature is not ready for production use.
+
+WARNING:
+To disable this feature flag after setting default owners per section, edit your
+CODEOWNERS file to [list Code Owners per line](#set-up-code-owners).
+
+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.
+
+Default owners are applied when specific owners are not specified for file paths.
+Specific owners defined beside the file path override default owners:
+
+```plaintext
+[Documentation] @docs-team
+docs/
+README.md
+
+[Database] @database-team
+model/db/
+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
+ `config/db/database-setup.md`, which has an override assigning it to `@docs-team`.
+
+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:
+
+```plaintext
+[Documentation][2] @docs-team
+docs/
+README.md
+
+^[Database] @database-team
+model/db/
+config/db/database-setup.md @docs-team
+```
+
+#### Sections with duplicate names
If multiple sections have the same name, they are combined.
Also, section headings are not case-sensitive. For example:
@@ -233,7 +291,7 @@ This code results in three entries under the **Documentation** section header, a
entries under **Database**. The entries defined under the sections **Documentation** and
**DOCUMENTATION** are combined, using the case of the first section.
-### Make a Code Owners section optional
+#### Make a Code Owners section optional
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/232995) in GitLab 13.8.
@@ -268,6 +326,35 @@ when changes are submitted by using merge requests. If a change is submitted dir
to the protected branch, approval from Code Owners is still required, even if the
section is marked as optional.
+### Require multiple approvals from Code Owners
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335451) in GitLab 15.9.
+
+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`.
+
+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.
+
+In this example, the `[Documentation]` section requires 2 approvals:
+
+```plaintext
+[Documentation][2]
+*.md @tech-writer-team
+
+[Ruby]
+*.rb @dev-team
+```
+
+The `Documentation` Code Owners section under the **Approval Rules** area displays 2 approvals are required:
+
+![MR widget - Multiple Approval Code Owners sections](img/multi_approvals_code_owners_sections_v15_9.png)
+
### Allowed to Push
The Code Owner approval and protected branch features do not apply to users who
@@ -338,15 +425,22 @@ path\ with\ spaces/ @space-owner
ee/docs @docs
docs @docs
-[Database]
-README.md @database
-model/db @database
+# Use of default owners for a section. In this case, all files (*) are owned by
+the dev team except the README.md and data-models which are owned by other teams.
+[Development] @dev-team
+*
+README.md @docs-team
+data-models/ @data-science-team
# This section is combined with the previously defined [Documentation] section:
[DOCUMENTATION]
README.md @docs
```
+## Technical Resources
+
+[Code Owners development guidelines](../../../ee/development/code_owners/index.md)
+
## Troubleshooting
### Approvals shown as optional
@@ -371,3 +465,9 @@ if any of these conditions are true:
Check the project [merge request approval](merge_requests/approvals/settings.md#edit-merge-request-approval-settings) settings.
- A Code Owner group has a visibility of **private**, and the current user is not a
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
+
+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.
diff --git a/doc/user/project/deploy_boards.md b/doc/user/project/deploy_boards.md
index a68f9550ebf..5adc678e942 100644
--- a/doc/user/project/deploy_boards.md
+++ b/doc/user/project/deploy_boards.md
@@ -1,11 +1,11 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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, reference
---
-# Deploy boards (DEPRECATED) **(FREE)**
+# Deploy boards (deprecated) **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1589) in GitLab 9.0.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212320) from GitLab Premium to GitLab Free in 13.8.
diff --git a/doc/user/project/deploy_keys/index.md b/doc/user/project/deploy_keys/index.md
index fc88535dc77..362d5826124 100644
--- a/doc/user/project/deploy_keys/index.md
+++ b/doc/user/project/deploy_keys/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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,8 +15,7 @@ Depending on your needs, you might want to use a [deploy token](../deploy_tokens
|------------------|-------------|--------------|
| Sharing | Shareable between multiple projects, even those in different groups. | Belong to a project or group. |
| Source | Public SSH key generated on an external host. | Generated on your GitLab instance, and is provided to users only at creation time. |
-| Validity | Valid as long as it's registered and enabled, and the user that created it exists. | Can be given an expiration date. |
-| Registry access | Cannot access a package registry. | Can read from and write to a package registry. |
+| Accessible resources | Git repository over SSH | Git repository over HTTP, package registry, and container registry. |
Deploy keys can't be used for Git operations if [external authorization](../../admin_area/settings/external_authorization.md) is enabled.
@@ -41,10 +40,8 @@ A deploy key is given a permission level when it is created:
You can change a deploy key's permission level after creating it. Changing a project deploy key's
permissions only applies for the current project.
-When a read-write deploy key is used to push a commit, GitLab checks if the creator of the
-deploy key has permission to access the resource.
-
-For example:
+Although a deploy key is a secret that isn't associated with a specific user,
+GitLab authorizes the creator of the deploy key if the Git-command triggers additional processes. For example:
- When a deploy key is used to push a commit to a [protected branch](../protected_branches.md),
the _creator_ of the deploy key must have access to the branch.
@@ -52,6 +49,15 @@ For example:
deploy key must have access to the CI/CD resources, including protected environments and secret
variables.
+## Security implications
+
+The intended use case for deploy keys is for non-human interaction with GitLab, for example: an automated script running on a server in your organization.
+As with all sensitive information, you should ensure only those who need access to the secret can read it.
+For human interactions, use credentials tied to users such as Personal Access Tokens.
+
+To help detect a potential secret leak, you can use the
+[Audit Event](../../../administration/audit_event_streaming.md#example-payloads-for-ssh-events-with-deploy-key) feature.
+
## View deploy keys
To view the deploy keys available to a project:
@@ -88,9 +94,9 @@ name and permissions.
Prerequisites:
-- You must have administrator access.
-- [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.
+- You must have administrator access to the instance.
+- You must [generate an SSH key pair](../../ssh.md#generate-an-ssh-key-pair).
+- You must put the private SSH key on the host that requires access to the repository.
To create a public deploy key:
diff --git a/doc/user/project/deploy_tokens/index.md b/doc/user/project/deploy_tokens/index.md
index cfb382d73e2..23cfa7cc500 100644
--- a/doc/user/project/deploy_tokens/index.md
+++ b/doc/user/project/deploy_tokens/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/description_templates.md b/doc/user/project/description_templates.md
index ffbe7447aa8..eeaf5d799d2 100644
--- a/doc/user/project/description_templates.md
+++ b/doc/user/project/description_templates.md
@@ -87,6 +87,10 @@ For example: `https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_templat
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89810) in GitLab 15.7.
+NOTE:
+This feature is available only for
+[the default template](#set-a-default-template-for-merge-requests-and-issues).
+
When you save a merge request for the first time, GitLab replaces these variables in
your merge request template with their values:
diff --git a/doc/user/project/file_lock.md b/doc/user/project/file_lock.md
index 8d3446994e8..b83feda0c96 100644
--- a/doc/user/project/file_lock.md
+++ b/doc/user/project/file_lock.md
@@ -209,7 +209,7 @@ requests that modify locked files. Unlock the file to allow changes.
To lock a file:
1. Open the file or directory in GitLab.
-1. In the upper right, above the file, select **Lock**.
+1. In the upper-right corner, above the file, select **Lock**.
1. On the confirmation dialog box, select **OK**.
If you do not have permission to lock the file, the button is not enabled.
@@ -221,7 +221,7 @@ To view the user who locked the file (if it was not you), hover over the button.
To view and remove file locks:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Repository > Locked Files**.
+1. On the left sidebar, select **Repository > Locked files**.
This list shows all the files locked either through LFS or GitLab UI.
diff --git a/doc/user/project/img/codeowners_in_UI_v15_10.png b/doc/user/project/img/codeowners_in_UI_v15_10.png
new file mode 100644
index 00000000000..c643d333791
--- /dev/null
+++ b/doc/user/project/img/codeowners_in_UI_v15_10.png
Binary files differ
diff --git a/doc/user/project/img/multi_approvals_code_owners_sections_v15_9.png b/doc/user/project/img/multi_approvals_code_owners_sections_v15_9.png
new file mode 100644
index 00000000000..a7fea76d5b1
--- /dev/null
+++ b/doc/user/project/img/multi_approvals_code_owners_sections_v15_9.png
Binary files differ
diff --git a/doc/user/project/import/bitbucket.md b/doc/user/project/import/bitbucket.md
index 7114974d8db..a5d5f93f9ad 100644
--- a/doc/user/project/import/bitbucket.md
+++ b/doc/user/project/import/bitbucket.md
@@ -35,6 +35,8 @@ 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](../../admin_area/settings/visibility_and_access_controls.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. Using the Developer role for this purpose was
[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387891) in GitLab 15.8 and will be removed in GitLab 16.0.
diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md
index e6d2e3e00b6..9937ea956c4 100644
--- a/doc/user/project/import/bitbucket_server.md
+++ b/doc/user/project/import/bitbucket_server.md
@@ -120,6 +120,16 @@ If the project import completes but LFS objects can't be downloaded or cloned, y
password or personal access token containing special characters. For more information, see
[this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/337769).
+### Pull requests are missing
+
+Importing large projects spawns a process that can consume a lot of memory. Sometimes you can see messages such as `Sidekiq worker RSS out of range` in the
+[Sidekiq logs](../../../administration/logs/index.md#sidekiq-logs). This can mean that MemoryKiller is interrupting the `RepositoryImportWorker` because it's using
+too much memory.
+
+To resolve this problem, temporarily increase the `SIDEKIQ_MEMORY_KILLER_MAX_RSS` environment variable using
+[custom environment variables](https://docs.gitlab.com/omnibus/settings/environment-variables.html) from the default `2000000` value to a larger value like `3000000`.
+Consider memory constraints on the system before deciding to increase `SIDEKIQ_MEMORY_KILLER_MAX_RSS`.
+
## Related topics
For information on automating user, group, and project import API calls, see
diff --git a/doc/user/project/import/gitea.md b/doc/user/project/import/gitea.md
index 404bb4c8600..29fe9db8887 100644
--- a/doc/user/project/import/gitea.md
+++ b/doc/user/project/import/gitea.md
@@ -75,10 +75,9 @@ From there, you can view the import statuses of your Gitea repositories:
You also can:
-- Import all of your Gitea projects in one go by selecting **Import all projects**
- in the upper left corner.
-- Filter projects by name. If filter is applied, selecting **Import all projects**
- imports only matched projects.
+- In the upper-left corner, select **Import all projects** to import all of your Gitea projects at once.
+- Filter projects by name. If a filter is applied, **Import all projects**
+ imports only selected projects.
![Gitea importer page](img/import_projects_from_gitea_importer_v12_3.png)
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index eeebb5a166c..a1d94d81e69 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -30,10 +30,8 @@ When importing projects:
imported with a naming scheme similar to `GH-SHA-username/pull-request-number/fork-name/branch`. This may lead to
a discrepancy in branches compared to those of the GitHub repository.
-For additional technical details, refer to the [GitHub Importer](../../../development/github_importer.md)
-developer documentation.
-
-For an overview of the import process, see the video [Migrating from GitHub to GitLab](https://youtu.be/VYOXuOg9tQI).
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview of the import process, see [Migrating from GitHub to GitLab](https://youtu.be/VYOXuOg9tQI).
## Prerequisites
@@ -62,7 +60,7 @@ prerequisites for those imports.
If you are importing from GitHub Enterprise to a self-managed GitLab instance:
- You must first enable the [GitHub integration](../../../integration/github.md).
-- If GitLab is behind a HTTP/HTTPS proxy, you must populate the [allowlist for local requests](../../../security/webhooks.md#create-an-allowlist-for-local-requests)
+- If GitLab is behind an HTTP/HTTPS proxy, you must populate the [allowlist for local requests](../../../security/webhooks.md#allow-outbound-requests-to-certain-ip-addresses-and-domains)
with `github.com` and `api.github.com` to solve the hostname. For more information, read the issue
[Importing a GitHub project requires DNS resolution even when behind a proxy](https://gitlab.com/gitlab-org/gitlab/-/issues/37941).
@@ -209,17 +207,18 @@ The following items of a project are imported:
- Repository description.
- Git repository data.
- Branch protection rules. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22650) in GitLab 15.4.
+- Collaborators (members). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388716) in GitLab 15.10.
- Issues.
- Pull requests.
- Wiki pages.
- Milestones.
- Labels.
-- Release note descriptions.
+- Release notes content.
- Attachments for:
- Release notes. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15620) in GitLab 15.4.
- - Comments and notes. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18052) in GitLab 15.5.
+ - Comments. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18052) in GitLab 15.5.
- Issue description. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18052) in GitLab 15.5.
- - Merge Request description. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18052) in GitLab 15.5.
+ - Pull Request description. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18052) in GitLab 15.5.
All attachment imports are disabled by default behind
`github_importer_attachments_import` [feature flag](../../../administration/feature_flags.md). From GitLab 15.5, can
@@ -232,7 +231,7 @@ The following items of a project are imported:
- Pull request "merged by" information.
- Pull request comments replies in discussions. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336596) in
GitLab 14.5.
-- Diff Notes suggestions. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340624) in GitLab 14.7.
+- Pull request review comments suggestions. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340624) in GitLab 14.7.
- Issue events and pull requests events. [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/7673) in GitLab 15.4
with `github_importer_issue_events_import` [feature flag](../../../administration/feature_flags.md) disabled by default.
From GitLab 15.5, can be imported [as an additional item](#select-additional-items-to-import). The feature flag was
@@ -267,39 +266,25 @@ Mapping GitHub rule **Require status checks to pass before merging** to
into GitLab due to technical difficulties. You can still create [external status checks](../merge_requests/status_checks.md)
manually.
-## Alternative way to import notes and diff notes
-
-When GitHub Importer runs on extremely large projects not all notes & diff notes can be imported due to GitHub API `issues_comments` & `pull_requests_comments` endpoints limitation.
-Not all pages can be fetched due to the following error coming from GitHub API: `In order to keep the API fast for everyone, pagination is limited for this resource. Check the rel=last link relation in the Link response header to see how far back you can traverse.`.
-
-An [alternative approach](#select-additional-items-to-import) for importing comments is available.
-
-Instead of using `issues_comments` and `pull_requests_comments`, use individual resources `issue_comments` and `pull_request_comments` instead to pull notes from one object at a time.
-This allows us to carry over any missing comments, however it increases the number of network requests required to perform the import, which means its execution takes a longer time.
+### Collaborators (members)
-## Reduce GitHub API request objects per page
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388716) in GitLab 15.10.
-Some GitHub API endpoints may return a 500 or 502 error for project imports from large repositories.
-To reduce the chance of such errors, you can enable the feature flag
-`github_importer_lower_per_page_limit` in the group project importing the data. This reduces the
-page size from 100 to 50.
+These GitHub collaborator roles are mapped to these GitLab [member roles](../../permissions.md#roles):
-To enable this feature flag, start a [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-and run the following `enable` command:
+| GitHub role | Mapped GitLab role |
+|:------------|:-------------------|
+| Read | Guest |
+| Triage | Reporter |
+| Write | Developer |
+| Maintain | Maintainer |
+| Admin | Owner |
-```ruby
-group = Group.find_by_full_path('my/group/fullpath')
-
-# Enable
-Feature.enable(:github_importer_lower_per_page_limit, group)
-```
+GitHub Enterprise Cloud has
+[custom repository roles](https://docs.github.com/en/enterprise-cloud@latest/organizations/managing-peoples-access-to-your-organization-with-roles/about-custom-repository-roles).
+These roles aren't supported and cause partial imports.
-To disable the feature, run this command:
-
-```ruby
-# Disable
-Feature.disable(:github_importer_lower_per_page_limit, group)
-```
+To import GitHub collaborators, you must have at least the Write role on the GitHub project. Otherwise collaborators import is skipped.
## Import from GitHub Enterprise on an internal network
@@ -443,3 +428,47 @@ repository to be imported manually. Administrators can manually import the repos
# Trigger import from second step
Gitlab::GithubImport::Stage::ImportRepositoryWorker.perform_async(project.id)
```
+
+### Errors when importing large projects
+
+The GitHub importer might encounter some errors when importing large projects.
+
+#### Alternative way to import notes and diff notes
+
+When the GitHub importer runs on extremely large projects, not all notes and diff notes can be imported due to the GitHub API `issues_comments` and `pull_requests_comments` endpoint limitations.
+
+If it's not possible to fetch all pages, the GitHub API might return the following error:
+
+```plaintext
+In order to keep the API fast for everyone, pagination is limited for this resource. Check the rel=last link relation in the Link response header to see how far back you can traverse.
+```
+
+An [alternative approach](#select-additional-items-to-import) for importing comments is available.
+
+Instead of using `issues_comments` and `pull_requests_comments`, use individual resources to pull notes from one object at a time. This way, you can carry over any missing comments. However, execution takes longer because this method increases the number of network requests required to perform the import.
+
+#### Reduce GitHub API request objects per page
+
+Some GitHub API endpoints might return a `500` or `502` error for project imports from large repositories.
+To reduce the chance of these errors, in the group project importing the data, enable the
+`github_importer_lower_per_page_limit` feature flag. When enabled, the flag reduces the
+page size from `100` to `50`.
+
+To enable this feature flag:
+
+1. Start a [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session).
+1. Run the following `enable` command:
+
+ ```ruby
+ group = Group.find_by_full_path('my/group/fullpath')
+
+ # Enable
+ Feature.enable(:github_importer_lower_per_page_limit, group)
+ ```
+
+To disable the feature flag, run this command:
+
+```ruby
+# Disable
+Feature.disable(:github_importer_lower_per_page_limit, group)
+```
diff --git a/doc/user/project/import/img/bitbucket_import_select_project_v12_3.png b/doc/user/project/import/img/bitbucket_import_select_project_v12_3.png
deleted file mode 100644
index bbc72a0b4b7..00000000000
--- a/doc/user/project/import/img/bitbucket_import_select_project_v12_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/import/img/fogbugz_import_finished.png b/doc/user/project/import/img/fogbugz_import_finished.png
deleted file mode 100644
index 62c5c86c9b3..00000000000
--- a/doc/user/project/import/img/fogbugz_import_finished.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/import/img/manifest_status_v13_3.png b/doc/user/project/import/img/manifest_status_v13_3.png
deleted file mode 100644
index c1a55ba1f50..00000000000
--- a/doc/user/project/import/img/manifest_status_v13_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index 24748b2e89c..8c95e68e1f2 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -109,7 +109,7 @@ To view project import history:
1. On the top bar, select **Create new...** (**{plus-square}**).
1. Select **New project/repository**.
1. Select **Import project**.
-1. Select **History** in the upper right corner.
+1. In the upper-right corner, select **History**.
1. If there are any errors for a particular import, you can see them by selecting **Details**.
The history also includes projects created from [built-in](../index.md#create-a-project-from-a-built-in-template)
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index decf3b071e7..da0546b85e6 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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"
---
@@ -139,9 +139,8 @@ Prerequisites:
- You must have permission to add new projects to a namespace. To check if you have permission:
1. On the top bar, select **Main menu > Groups** and find your group.
- 1. Confirm that **New project** is visible in the upper right
- corner. Contact your GitLab
- administrator if you require permission.
+ 1. In the upper-right corner, confirm that **New project** is visible.
+ Contact your GitLab administrator if you require permission.
To push your repository and create a project:
diff --git a/doc/user/project/integrations/apple_app_store.md b/doc/user/project/integrations/apple_app_store.md
index 1b41dd0b669..e326e7a222b 100644
--- a/doc/user/project/integrations/apple_app_store.md
+++ b/doc/user/project/integrations/apple_app_store.md
@@ -6,12 +6,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Apple App Store **(FREE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104888) in GitLab 15.8 [with a flag](../../../administration/feature_flags.md) named `apple_app_store_integration`. Disabled by default.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104888) in GitLab 15.8 [with a flag](../../../administration/feature_flags.md) named `apple_app_store_integration`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/385335) in GitLab 15.10. Feature flag `apple_app_store_integration` removed.
-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 `apple_app_store_integration`. On GitLab.com, this feature is not available.
-
-The Apple App Store integration makes it easy 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.
+With the Apple App Store integration, you can 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.
The integration is designed to be able to work out of the box with [fastlane](http://fastlane.tools/), but can be used with other build tools as well.
diff --git a/doc/user/project/integrations/asana.md b/doc/user/project/integrations/asana.md
index 8bc1a984e3d..fac09e7f071 100644
--- a/doc/user/project/integrations/asana.md
+++ b/doc/user/project/integrations/asana.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Asana **(FREE)**
-This integration adds commit messages as comments to Asana tasks.
+The Asana integration adds commit messages as comments to Asana tasks.
Once enabled, commit messages are checked for Asana task URLs (for example,
`https://app.asana.com/0/123456/987654`) or task IDs starting with `#`
(for example, `#987654`). Every task ID found gets the commit comment added to it.
diff --git a/doc/user/project/integrations/ewm.md b/doc/user/project/integrations/ewm.md
index c2371d32853..42f0ec6b0de 100644
--- a/doc/user/project/integrations/ewm.md
+++ b/doc/user/project/integrations/ewm.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Engineering Workflow Management (EWM) **(FREE)**
-This integration allows you to go from GitLab to EWM work items mentioned in merge request
+The EWM integration allows you to go from GitLab to EWM work items mentioned in merge request
descriptions and commit messages.
Each work item reference is automatically converted to a link to the work item.
diff --git a/doc/user/project/integrations/github.md b/doc/user/project/integrations/github.md
index 990d0839581..3b5e55b48a1 100644
--- a/doc/user/project/integrations/github.md
+++ b/doc/user/project/integrations/github.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitHub **(PREMIUM)**
You can update GitHub with pipeline status updates from GitLab.
-This integration can help you if you use GitLab for CI/CD.
+The GitHub integration can help you if you use GitLab for CI/CD.
![Pipeline status update on GitHub](img/github_status_check_pipeline_update.png)
diff --git a/doc/user/project/integrations/google_play.md b/doc/user/project/integrations/google_play.md
new file mode 100644
index 00000000000..553e82be382
--- /dev/null
+++ b/doc/user/project/integrations/google_play.md
@@ -0,0 +1,49 @@
+---
+stage: Manage
+group: Integrations
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Google Play **(FREE)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621) in GitLab 15.10 [with a flag](../../../administration/feature_flags.md) named `google_play_integration`. 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 `google_play_integration`. On GitLab.com, this feature is not available.
+
+With the Google Play integration, you can configure your CI/CD pipelines to connect to the [Google Play Console](https://play.google.com/console) to build and release apps for Android devices.
+
+The Google Play integration works out of the box with [fastlane](https://fastlane.tools/). You can also use this integration with other build tools.
+
+## Enable the integration in GitLab
+
+Prerequisites:
+
+- You must have a [Google Play Console](https://play.google.com/console/signup) developer account.
+- You must [generate a new service account key for your project](https://developers.google.com/android-publisher/getting_started) from the Google Cloud console.
+
+To enable the Google Play integration in GitLab:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Integrations**.
+1. Select **Google Play**.
+1. In **Enable Integration**, select the **Active** checkbox.
+1. In **Service account key (.JSON)**, drag or upload your key file.
+1. Select **Save changes**.
+
+After you enable the integration, the global variable `$SUPPLY_JSON_KEY_DATA` is created for CI/CD use.
+
+### CI/CD variable security
+
+Malicious code pushed to your `.gitlab-ci.yml` file could compromise your variables, including `$SUPPLY_JSON_KEY_DATA`, and send them to a third-party server. For more information, see [CI/CD variable security](../../../ci/variables/index.md#cicd-variable-security).
+
+## Enable the integration in fastlane
+
+To enable the integration in fastlane and upload the build to the given track in Google Play, you can add the following code to your app's `fastlane/Fastfile`:
+
+```ruby
+upload_to_play_store(
+ track: 'internal',
+ aab: '../build/app/outputs/bundle/release/app-release.aab'
+)
+```
diff --git a/doc/user/project/integrations/hangouts_chat.md b/doc/user/project/integrations/hangouts_chat.md
index 3537033902d..c9ba5b1b3aa 100644
--- a/doc/user/project/integrations/hangouts_chat.md
+++ b/doc/user/project/integrations/hangouts_chat.md
@@ -6,8 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Google Chat **(FREE)**
-Integrate your project to send notifications from GitLab to a
-room of your choice in [Google Chat](https://chat.google.com/) (former Google
+You can configure your project to send notifications from GitLab to a
+room of your choice in [Google Chat](https://chat.google.com/) (formerly Google
Hangouts).
## Integration workflow
@@ -28,7 +28,7 @@ notifications to Google Chat:
To enable the integration in Google Chat:
1. Enter the room where you want to receive notifications from GitLab.
-1. Open the room dropdown list in the upper left and select **Manage webhooks**.
+1. In the upper-left corner, from the room dropdown list, select **Manage webhooks**.
1. Enter the name for your webhook, for example "GitLab integration".
1. Optional. Add an avatar for your bot.
1. Select **Save**.
diff --git a/doc/user/project/integrations/harbor.md b/doc/user/project/integrations/harbor.md
index 596821ba12b..e316f6fbd9e 100644
--- a/doc/user/project/integrations/harbor.md
+++ b/doc/user/project/integrations/harbor.md
@@ -8,11 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80999) in GitLab 14.9.
-Use Harbor as the container registry for your GitLab project.
+You can use Harbor as the container registry for your GitLab project.
-[Harbor](https://goharbor.io/) is an open source registry that can help you manage artifacts across cloud-native compute platforms, like Kubernetes and Docker.
+[Harbor](https://goharbor.io/) is an open-source registry that can help you manage artifacts across cloud-native compute platforms like Kubernetes and Docker.
-This integration can help you if you need GitLab CI/CD and a container image repository.
+The Harbor integration can help you if you need GitLab CI/CD and a container image repository.
## Prerequisites
diff --git a/doc/user/project/integrations/index.md b/doc/user/project/integrations/index.md
index 57947e21736..9ff6ad2a237 100644
--- a/doc/user/project/integrations/index.md
+++ b/doc/user/project/integrations/index.md
@@ -72,13 +72,14 @@ You can configure the following integrations.
| [Pipelines emails](pipeline_status_emails.md) | Send the pipeline status to a list of recipients by email. | **{dotted-circle}** No |
| [Pivotal Tracker](pivotal_tracker.md) | Add commit messages as comments to Pivotal Tracker stories. | **{dotted-circle}** No |
| [Prometheus](prometheus.md) | Monitor application metrics. | **{dotted-circle}** No |
-| [Pumble](pumble.md) | Send event notifications to a Pumble channel. | **{dotted-circle}** No |
+| [Pumble](pumble.md) | Send event notifications to a Pumble channel. | **{dotted-circle}** No |
| Pushover | Get real-time notifications on your device. | **{dotted-circle}** No |
| [Redmine](redmine.md) | Use Redmine as the issue tracker. | **{dotted-circle}** No |
-| [Shimo Workspace](shimo.md) | Use Shimo instead of the GitLab Wiki. | **{dotted-circle}** No |
+| [Shimo Workspace](shimo.md) | Use Shimo instead of the GitLab Wiki. | **{dotted-circle}** No |
| [GitLab for Slack app](gitlab_slack_application.md) | Use Slack's official GitLab application. | **{dotted-circle}** No |
| [Slack notifications](slack.md) | Send notifications about project events to Slack. | **{dotted-circle}** No |
| [Slack slash commands](slack_slash_commands.md) | Enable slash commands in a workspace. | **{dotted-circle}** No |
+| [Squash TM](squash_tm.md) | Update Squash TM requirements when GitLab issues are modified. | **{check-circle}** Yes |
| [Unify Circuit](unify_circuit.md) | Send notifications about project events to Unify Circuit. | **{dotted-circle}** No |
| [Webex Teams](webex_teams.md) | Receive events notifications. | **{dotted-circle}** No |
| [YouTrack](youtrack.md) | Use YouTrack as the issue tracker. | **{dotted-circle}** No |
diff --git a/doc/user/project/integrations/irker.md b/doc/user/project/integrations/irker.md
index 23525c33e84..757d15e71b3 100644
--- a/doc/user/project/integrations/irker.md
+++ b/doc/user/project/integrations/irker.md
@@ -6,8 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# irker (IRC gateway) **(FREE)**
-GitLab provides a way to push update messages to an irker server. When
-configured, pushes to a project trigger the integration to send data directly
+GitLab provides a way to push update messages to an irker server. After you configure
+the integration, each push to a project triggers the integration to send data directly
to the irker server.
See also the [irker integration API documentation](../../../api/integrations.md).
diff --git a/doc/user/project/integrations/mock_ci.md b/doc/user/project/integrations/mock_ci.md
index ae1737f8d3f..cbe073485e0 100644
--- a/doc/user/project/integrations/mock_ci.md
+++ b/doc/user/project/integrations/mock_ci.md
@@ -9,12 +9,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
NOTE:
This integration only appears if you're in a [development environment](https://gitlab.com/gitlab-org/gitlab-mock-ci-service#setup-mockci-integration).
-To set up the mock CI service server, respond to the following endpoints
+To set up the mock CI service server, respond to the following endpoints:
- `commit_status`: `#{project.namespace.path}/#{project.path}/status/#{sha}.json`
- - Have your service return `200 { status: ['failed'|'canceled'|'running'|'pending'|'success'|'success-with-warnings'|'skipped'|'not_found'] }`
- - If the service returns a 404, it is interpreted as `pending`
+ - Have your service return `200 { status: ['failed'|'canceled'|'running'|'pending'|'success'|'success-with-warnings'|'skipped'|'not_found'] }`.
+ - If the service returns a 404, the service is interpreted as `pending`.
- `build_page`: `#{project.namespace.path}/#{project.path}/status/#{sha}`
- - Just where the build is linked to, doesn't matter if implemented
+ - Where the build is linked to (whether or not it's implemented).
-For an example of a mock CI server, see [`gitlab-org/gitlab-mock-ci-service`](https://gitlab.com/gitlab-org/gitlab-mock-ci-service)
+For an example of a mock CI server, see [`gitlab-org/gitlab-mock-ci-service`](https://gitlab.com/gitlab-org/gitlab-mock-ci-service).
diff --git a/doc/user/project/integrations/pivotal_tracker.md b/doc/user/project/integrations/pivotal_tracker.md
index 034be8ab3d8..c794001672b 100644
--- a/doc/user/project/integrations/pivotal_tracker.md
+++ b/doc/user/project/integrations/pivotal_tracker.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Pivotal Tracker **(FREE)**
-This integration adds commit messages as comments to Pivotal Tracker stories.
+The Pivotal Tracker integration adds commit messages as comments to Pivotal Tracker stories.
Once enabled, commit messages are checked for square brackets containing a hash mark followed by
the story ID (for example, `[#555]`). Every story ID found gets the commit comment added to it.
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index cd92e49cada..80c6337f934 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -23,7 +23,7 @@ Once enabled, GitLab detects metrics from known services in the
[add your own metrics](../../../operations/metrics/index.md#adding-custom-metrics) and create
[custom dashboards](../../../operations/metrics/dashboards/index.md).
-## Enabling Prometheus Integration
+## Enabling the Prometheus integration
### Prometheus cluster integration
diff --git a/doc/user/project/integrations/prometheus_library/cloudwatch.md b/doc/user/project/integrations/prometheus_library/cloudwatch.md
index 1e9319fa7c7..4f841b7ccb3 100644
--- a/doc/user/project/integrations/prometheus_library/cloudwatch.md
+++ b/doc/user/project/integrations/prometheus_library/cloudwatch.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
---
-# Monitoring AWS resources (DEPRECATED) **(FREE)**
+# Monitoring AWS resources (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/user/project/integrations/prometheus_library/haproxy.md b/doc/user/project/integrations/prometheus_library/haproxy.md
index b4533d83acd..8fec7f68ab1 100644
--- a/doc/user/project/integrations/prometheus_library/haproxy.md
+++ b/doc/user/project/integrations/prometheus_library/haproxy.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
---
-# Monitoring HAProxy (DEPRECATED) **(FREE)**
+# Monitoring HAProxy (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/user/project/integrations/prometheus_library/index.md b/doc/user/project/integrations/prometheus_library/index.md
index afefe80271e..fe9ce323b23 100644
--- a/doc/user/project/integrations/prometheus_library/index.md
+++ b/doc/user/project/integrations/prometheus_library/index.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
---
-# Prometheus Metrics library (DEPRECATED) **(FREE)**
+# Prometheus Metrics library (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md
index 34a6823f007..dc6aa41d691 100644
--- a/doc/user/project/integrations/prometheus_library/kubernetes.md
+++ b/doc/user/project/integrations/prometheus_library/kubernetes.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
---
-# Monitoring Kubernetes (DEPRECATED) **(FREE)**
+# Monitoring Kubernetes (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/user/project/integrations/prometheus_library/nginx.md b/doc/user/project/integrations/prometheus_library/nginx.md
index f0a3b25f11a..90fe3ab8f8e 100644
--- a/doc/user/project/integrations/prometheus_library/nginx.md
+++ b/doc/user/project/integrations/prometheus_library/nginx.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
---
-# Monitoring NGINX (DEPRECATED) **(FREE)**
+# Monitoring NGINX (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress.md b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
index 947210541f4..ba3f41e8201 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress.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
---
-# Monitoring NGINX Ingress Controller (DEPRECATED) **(FREE)**
+# Monitoring NGINX Ingress Controller (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
index f8057866592..89b8388b70c 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.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
---
-# Monitoring NGINX Ingress Controller with VTS metrics (DEPRECATED) **(FREE)**
+# Monitoring NGINX Ingress Controller with VTS metrics (deprecated) **(FREE)**
> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7.
diff --git a/doc/user/project/integrations/redmine.md b/doc/user/project/integrations/redmine.md
index 0a399d3481f..97c3e14dd9d 100644
--- a/doc/user/project/integrations/redmine.md
+++ b/doc/user/project/integrations/redmine.md
@@ -6,8 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Redmine **(FREE)**
-Use [Redmine](https://www.redmine.org/) as the issue tracker.
-
+You can use [Redmine](https://www.redmine.org/) as an external issue tracker.
To enable the Redmine integration in a project:
1. On the top bar, select **Main menu > Projects** and find your project.
diff --git a/doc/user/project/integrations/servicenow.md b/doc/user/project/integrations/servicenow.md
index a34655c8e35..149c9172896 100644
--- a/doc/user/project/integrations/servicenow.md
+++ b/doc/user/project/integrations/servicenow.md
@@ -9,6 +9,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
ServiceNow offers several integrations to help centralize and automate your
management of GitLab workflows.
+To simplify your stack and streamline your processes, you should use GitLab [deployment approvals](../../../ci/environments/deployment_approvals.md) whenever possible.
+
## GitLab spoke
With the GitLab spoke in ServiceNow, you can automate actions for GitLab
diff --git a/doc/user/project/integrations/slack_slash_commands.md b/doc/user/project/integrations/slack_slash_commands.md
index 2563cec2b05..f9b95a0dd0c 100644
--- a/doc/user/project/integrations/slack_slash_commands.md
+++ b/doc/user/project/integrations/slack_slash_commands.md
@@ -15,7 +15,7 @@ working in Slack, you can use Slack slash commands.
To use Slack slash commands, you must configure both Slack and GitLab.
GitLab can also send events (for example, `issue created`) to Slack as notifications.
-The [Slack notifications service](slack.md) is configured separately.
+The [Slack notifications integration](slack.md) is configured separately.
## Configure GitLab and Slack
diff --git a/doc/user/project/integrations/squash_tm.md b/doc/user/project/integrations/squash_tm.md
new file mode 100644
index 00000000000..0f63b4a48db
--- /dev/null
+++ b/doc/user/project/integrations/squash_tm.md
@@ -0,0 +1,37 @@
+---
+stage: Ecosystem
+group: Integrations
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Squash TM integration **(FREE SELF)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337855) in GitLab 15.10.
+
+When [Squash TM](https://www.squashtest.com/squash-gitlab-integration?lang=en) (Test Management)
+integration is enabled and configured in GitLab, issues (typically user stories) created in GitLab
+are synchronized as requirements in Squash TM and test progress is reported in GitLab issues.
+
+## Configure Squash TM
+
+1. Optional. Ask your system administrator to [configure a token in the properties file](https://tm-en.doc.squashtest.com/latest/redirect/gitlab-integration-token.html).
+1. Follow the [Squash TM documentation](https://tm-en.doc.squashtest.com/latest/redirect/gitlab-integration-configuration.html) to:
+ 1. Create a GitLab server.
+ 1. Enable the `Xsquash4GitLab` plugin
+ 1. Configure a synchronization.
+ 1. From the **Real-time synchronization** panel, copy the following fields to use later in GitLab:
+
+ - **Webhook URL**.
+ - **Secret token** if your Squash TM system administrator configured one at step 1.
+
+## Configure GitLab
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Integrations**.
+1. Select **Squash TM**.
+1. Ensure that the **Active** toggle is enabled.
+1. In the **Trigger** section, indicate which type of issue is concerned by the real-time synchronization.
+1. Complete the fields:
+
+ - Enter the **Squash TM webhook URL**,
+ - Enter the **secret token** if your Squash TM system administrator configured it earlier.
diff --git a/doc/user/project/integrations/unify_circuit.md b/doc/user/project/integrations/unify_circuit.md
index d465b4e50f0..9c38cec0a01 100644
--- a/doc/user/project/integrations/unify_circuit.md
+++ b/doc/user/project/integrations/unify_circuit.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
The Unify Circuit integration sends notifications from GitLab to a Circuit conversation.
-## Set up Unify Circuit service
+## Set up Unify Circuit
In Unify Circuit, [add a webhook](https://www.circuit.com/unifyportalfaqdetail?articleId=164448) and
copy its URL.
diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md
index 3d971af5c2a..1511e37e31e 100644
--- a/doc/user/project/integrations/webhooks.md
+++ b/doc/user/project/integrations/webhooks.md
@@ -118,11 +118,16 @@ Endpoints should follow these best practices:
- Never return `500` server error status responses if the event has been handled as this can cause the webhook to be [temporarily disabled](#failing-webhooks).
- Invalid HTTP responses are treated as failed requests.
-### Failing webhooks
+## Failing webhooks
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60837) in GitLab 13.12 [with a flag](../../../administration/feature_flags.md) named `web_hooks_disable_failed`. Disabled by default.
-> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/329849) in GitLab 15.7.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/329849) in GitLab 15.7. Feature flag `web_hooks_disable_failed` removed.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60837) for project webhooks in GitLab 13.12 [with a flag](../../../administration/feature_flags.md) named `web_hooks_disable_failed`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/329849) for project webhooks in GitLab 15.7. Feature flag `web_hooks_disable_failed` removed.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/385902) for group webhooks in GitLab 15.10.
+> - [Disabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/390157) in GitLab 15.10 [with a flag](../../../administration/feature_flags.md) named `auto_disabling_web_hooks`.
+
+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 `auto_disabling_web_hooks`.
+On GitLab.com, this feature is available.
If a webhook fails repeatedly, it may be disabled automatically.
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 234faa893eb..98017fb5542 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -74,7 +74,7 @@ Prerequisites:
To create a new issue board:
-1. Select the dropdown list with the current board name in the upper left corner of the issue boards page.
+1. In the upper-left corner of the issue board page, select the dropdown list with the current board name.
1. Select **Create new board**.
1. Enter the new board's name and select its scope: milestone, labels, assignee, or weight.
@@ -86,7 +86,7 @@ Prerequisites:
To delete the currently active issue board:
-1. Select the dropdown list with the current board name in the upper left corner of the issue boards page.
+1. In the upper-left corner of the issue board page, select the dropdown list with the current board name.
1. Select **Delete board**.
1. Select **Delete** to confirm.
@@ -394,11 +394,11 @@ You can also [drag issues](#move-issues-and-lists) to change their position and
![Drag issues between swimlanes](img/epics_swimlanes_drag_and_drop.png)
-## Work In Progress limits **(PREMIUM)**
+## Work in progress limits **(PREMIUM)**
> Moved to GitLab Premium in 13.9.
-You can set a Work In Progress (WIP) limit for each issue list on an issue board. When a limit is
+You can set a work in progress (WIP) limit for each issue list on an issue board. When a limit is
set, the list's header shows the number of issues in the list and the soft limit of issues.
You cannot set a WIP limit on the default lists (**Open** and **Closed**).
@@ -413,11 +413,11 @@ Prerequisites:
- You must have at least the Reporter role for the project.
-To set a WIP limit for a list:
+To set a WIP limit for a list, in an issue board:
-1. Navigate to a Project or Group board of which you're a member.
-1. Select the settings icon in a list's header.
-1. Next to **Work In Progress Limit**, select **Edit**.
+1. On the top of the list you want to edit, select **List actions** (**{ellipsis_v}**) **> Edit list settings**.
+ The list settings sidebar opens on the right.
+1. Next to **Work in progress limit**, select **Edit**.
1. Enter the maximum number of issues.
1. Press <kbd>Enter</kbd> to save.
@@ -475,7 +475,7 @@ Additionally, you can also see the time tracking value.
### Create a new list
-Create a new list by selecting the **Create** button in the upper right corner of the issue board.
+To create a new list, in the upper-right corner of the issue board, select **Create**.
![creating a new list in an issue board](img/issue_board_add_list_v14_1.png)
@@ -493,10 +493,10 @@ Prerequisites:
To remove a list from an issue board:
-1. On the top of the list you want to remove, select the **List settings** icon (**{settings}**).
+1. On the top of the list you want to remove, select **List actions** (**{ellipsis_v}**).
The list settings sidebar opens on the right.
1. Select **Remove list**. A confirmation dialog appears.
-1. Select **OK**.
+1. Select **Remove list** again.
### Add issues to a list
diff --git a/doc/user/project/issues/create_issues.md b/doc/user/project/issues/create_issues.md
index 5ebb2fc2e1c..b6931149ede 100644
--- a/doc/user/project/issues/create_issues.md
+++ b/doc/user/project/issues/create_issues.md
@@ -100,7 +100,7 @@ To create an issue from a project issue board:
1. On the top bar, select **Main menu > Projects** and find your project.
1. Select **Issues > Boards**.
-1. At the top of a board list, select **New issue** (**{plus-square}**).
+1. At the top of a board list, select **List actions** (**{ellipsis_v}**) **> Create new issue**.
1. Enter the issue's title.
1. Select **Create issue**.
@@ -108,7 +108,7 @@ To create an issue from a group issue board:
1. On the top bar, select **Main menu > Groups** and find your group.
1. Select **Issues > Boards**.
-1. At the top of a board list, select **New issue** (**{plus-square}**).
+1. At the top of a board list, select **List actions** (**{ellipsis_v}**) **> Create new issue**.
1. Enter the issue's title.
1. Under **Projects**, select the project in the group that the issue should belong to.
1. Select **Create issue**.
@@ -118,9 +118,6 @@ example, if the list is scoped to a label `Frontend`, the new issue also has thi
## By sending an email
-> - Generated email address format changed in GitLab 11.7.
-> - The older format is still supported, so existing aliases and contacts still work.
-
You can send an email to create an issue in a project on the project's
**Issues List** page.
diff --git a/doc/user/project/issues/crosslinking_issues.md b/doc/user/project/issues/crosslinking_issues.md
index 52da1acd32a..f1f41de7cb4 100644
--- a/doc/user/project/issues/crosslinking_issues.md
+++ b/doc/user/project/issues/crosslinking_issues.md
@@ -39,10 +39,10 @@ git commit -m "this is my commit message. Ref projectname#xxx"
```
If they are not in the same group, you can add the full URL to the issue
-(`https://gitlab.com/<username>/<projectname>/issues/<xxx>`).
+(`https://gitlab.com/<username>/<projectname>/-/issues/<xxx>`).
```shell
-git commit -m "this is my commit message. Related to https://gitlab.com/<username>/<projectname>/issues/<xxx>"
+git commit -m "this is my commit message. Related to https://gitlab.com/<username>/<projectname>/-/issues/<xxx>"
```
Of course, you can replace `gitlab.com` with the URL of your own GitLab instance.
diff --git a/doc/user/project/issues/csv_import.md b/doc/user/project/issues/csv_import.md
index 8a6683a55b5..ac7d8c99fa8 100644
--- a/doc/user/project/issues/csv_import.md
+++ b/doc/user/project/issues/csv_import.md
@@ -36,8 +36,8 @@ To import issues:
1. Go to your project's Issues list page.
1. Open the import feature, depending if the project has issues:
- - Existing issues are present: Select the import icon in the upper right, next to **Edit issues**.
- - Project has no issues: Select **Import CSV** in the middle of the page.
+ - The project has existing issues: in the upper-right corner, next to **Edit issues**, select the import icon (**{import}**).
+ - The project has no issues: in the middle of the page, select **Import CSV**.
1. Select the file you want to import, and then select **Import issues**.
The file is processed in the background, and a notification email is sent
diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md
index f43f87119a6..10b29feb072 100644
--- a/doc/user/project/issues/design_management.md
+++ b/doc/user/project/issues/design_management.md
@@ -227,6 +227,19 @@ New discussion threads get different pin numbers, which you can use to refer to
In GitLab 12.5 and later, new discussions are output to the issue activity,
so that everyone involved can participate in the discussion.
+## Delete a comment from a design
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/385100) in GitLab 15.9.
+
+Prerequisites:
+
+- You must have at least the Reporter role for the project.
+
+To delete a comment from a design:
+
+1. On the comment you want to delete, select **More actions** **{ellipsis_v}** **> Delete comment**.
+1. On the confirmation dialog box, select **Delete comment**.
+
## Resolve a discussion thread on a design
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13049) in GitLab 13.1.
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
index c16074ea1d8..e0966909b1e 100644
--- a/doc/user/project/issues/managing_issues.md
+++ b/doc/user/project/issues/managing_issues.md
@@ -400,7 +400,7 @@ To view all issues assigned to you:
Or:
- To use a [keyboard shortcut](../../shortcuts.md), press <kbd>Shift</kbd> + <kbd>i</kbd>.
-- On the top bar, in the upper right, select **{issues}** **Issues**.
+- On the top bar, in the upper-right corner, select **Issues** (**{issues}**).
## Filter the list of issues
diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md
index c7d45b0bd15..6e20492db05 100644
--- a/doc/user/project/members/index.md
+++ b/doc/user/project/members/index.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
diff --git a/doc/user/project/members/share_project_with_groups.md b/doc/user/project/members/share_project_with_groups.md
index 4dda68a6d08..356e4e1b194 100644
--- a/doc/user/project/members/share_project_with_groups.md
+++ b/doc/user/project/members/share_project_with_groups.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
@@ -70,17 +70,21 @@ are given access to the project. In addition:
## Maximum role
+When you invite a group to a project, the maximum role is the highest level of access the invited group members are allowed to have in the project.
+
When multiple groups contain the same members, and the groups
have access to the same project, the group members are
-given the most restrictive role for the project.
-
-This most restrictive role is called the *maximum role*, or **Max role**.
+given the highest access level of the two for the project.
The member's **Max role** is the more restrictive of:
- The role the user is assigned for the group.
- The role you chose when you invited the group to the project.
+NOTE:
+The Max role does not elevate the privileges of users.
+For example, if a group member has the role of Developer, and the group is invited to a project with a Max role of Maintainer, the member's role is not elevated to Maintainer.
+
### View the member's Max role
To view the maximum role assigned to a member:
diff --git a/doc/user/project/merge_requests/allow_collaboration.md b/doc/user/project/merge_requests/allow_collaboration.md
index 0729e024df4..4a22cc71349 100644
--- a/doc/user/project/merge_requests/allow_collaboration.md
+++ b/doc/user/project/merge_requests/allow_collaboration.md
@@ -61,7 +61,7 @@ In the following example:
To change or add a commit to the contributor's merge request:
1. Go to the merge request.
-1. In the upper right corner, select **Code**, then select **Check out branch**.
+1. In the upper-right corner, select **Code**, then select **Check out branch**.
1. In the modal window, select **Copy** (**{copy-to-clipboard}**).
1. In your terminal, go to your cloned version of the repository, and
paste the commands. For example:
diff --git a/doc/user/project/merge_requests/cherry_pick_changes.md b/doc/user/project/merge_requests/cherry_pick_changes.md
index 9fac872ac4b..d2676b1bdf0 100644
--- a/doc/user/project/merge_requests/cherry_pick_changes.md
+++ b/doc/user/project/merge_requests/cherry_pick_changes.md
@@ -55,7 +55,7 @@ by the merge request:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **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, select **Cherry-pick**:
+1. In the upper-right corner, select **Cherry-pick**:
![Cherry-pick merge request](img/cherry_pick_v15_4.png)
1. In the modal window, select the project and branch to cherry-pick into.
@@ -72,7 +72,8 @@ To cherry-pick a commit from the list of all commits for a project:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Repository > Commits**.
-1. Select the title of the commit you want to cherry-pick.
+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.
1. In the modal window, select the project and branch to cherry-pick into.
1. Optional. Select **Start a new merge request with these changes**.
1. Select **Cherry-pick**.
@@ -86,7 +87,7 @@ list of commits included in a merge request:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **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 of the commit you want to cherry-pick.
+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.
1. In the modal window, select the project and branch to cherry-pick into.
1. Optional. Select **Start a new merge request with these changes**.
@@ -100,7 +101,8 @@ when you view that file in your project's Git repository:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Repository > Files** and go to the file
changed by the commit.
-1. Select **History**, then select the title of the commit you want to cherry-pick.
+1. Select **History**, then 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.
1. In the modal window, select the project and branch to cherry-pick into.
1. Optional. Select **Start a new merge request with these changes**.
diff --git a/doc/user/project/merge_requests/commits.md b/doc/user/project/merge_requests/commits.md
deleted file mode 100644
index a9f67c39ae8..00000000000
--- a/doc/user/project/merge_requests/commits.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../merge_requests/index.md'
-remove_date: '2023-03-12'
----
-
-This document was removed.
-
-<!-- This redirect file can be deleted after <2023-03-12>. -->
-<!-- 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/merge_requests/creating_merge_requests.md b/doc/user/project/merge_requests/creating_merge_requests.md
index 875312bbb7c..4ea549e5986 100644
--- a/doc/user/project/merge_requests/creating_merge_requests.md
+++ b/doc/user/project/merge_requests/creating_merge_requests.md
@@ -11,7 +11,7 @@ disqus_identifier: 'https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.h
There are many different ways to create a merge request.
NOTE:
-Use [branch naming patterns](../repository/branches/index.md#naming) to streamline merge request creation.
+Use [branch naming patterns](../repository/branches/index.md#prefix-branch-names-with-issue-numbers) to streamline merge request creation.
## From the merge request list
@@ -19,7 +19,7 @@ You can create a merge request from the list of merge requests.
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left menu, select **Merge requests**.
-1. In the upper right, select **New merge request**.
+1. In the upper-right corner, select **New merge request**.
1. Select a source and target branch and then **Compare branches and continue**.
1. Fill out the fields and select **Create merge request**.
@@ -171,7 +171,7 @@ To create a merge request by sending an email:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left menu, select **Merge requests**.
-1. In the upper right, select **Email a new merge request to this project**.
+1. In the upper-right corner, select **Email a new merge request to this project**.
An email address is displayed. Copy this address.
Ensure you keep this address private.
1. Open an email and compose a message with the following information:
diff --git a/doc/user/project/merge_requests/img/remove_source_branch_status.png b/doc/user/project/merge_requests/img/remove_source_branch_status.png
deleted file mode 100644
index afd93207e02..00000000000
--- a/doc/user/project/merge_requests/img/remove_source_branch_status.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index a633366cc62..f760b1b730a 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -65,7 +65,7 @@ or:
or:
-1. On the top bar, in the upper right, select **{merge-request-open}** **Merge requests**.
+1. On the top bar, in the upper-right corner, select **Merge requests** (**{merge-request-open}**).
1. From the dropdown list, select **Assigned to you**.
## Filter the list of merge requests
@@ -257,8 +257,8 @@ FLAG:
On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `moved_mr_sidebar`.
On GitLab.com, this feature is enabled in the following projects: `gitlab-org/gitlab`, `gitlab-com/www-gitlab-com`, and `gitlab-org/customers-gitlab-com`.
-When this feature flag is enabled, you can find the following actions in
-**Merge request actions** (**{ellipsis_v}**) in the upper right:
+When this feature flag is enabled, in the upper-right corner,
+**Merge request actions** (**{ellipsis_v}**) contains the following actions:
- The [notifications](../../profile/notifications.md#edit-notification-settings-for-issues-merge-requests-and-epics) toggle
- Mark merge request as ready or [draft](../merge_requests/drafts.md)
@@ -304,7 +304,6 @@ For a web developer writing a webpage for your company's website:
- [GitLab keyboard shortcuts](../../shortcuts.md)
- [Comments and threads](../../discussions/index.md)
- [Suggest code changes](reviews/suggestions.md)
-- [Commits](commits.md)
- [CI/CD pipelines](../../../ci/index.md)
- [Push options](../push_options.md) for merge requests
diff --git a/doc/user/project/merge_requests/methods/index.md b/doc/user/project/merge_requests/methods/index.md
index 1f7e15ee982..02bd4ed0502 100644
--- a/doc/user/project/merge_requests/methods/index.md
+++ b/doc/user/project/merge_requests/methods/index.md
@@ -228,5 +228,4 @@ workflow that requires frequent rebases.
## Related topics
-- [Commits history](../commits.md)
- [Squash and merge](../squash_and_merge.md)
diff --git a/doc/user/project/merge_requests/reviews/img/apply_suggestion_v13_9.png b/doc/user/project/merge_requests/reviews/img/apply_suggestion_v13_9.png
deleted file mode 100644
index e27fa629672..00000000000
--- a/doc/user/project/merge_requests/reviews/img/apply_suggestion_v13_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/reviews/img/make_suggestion_v13_9.png b/doc/user/project/merge_requests/reviews/img/make_suggestion_v13_9.png
deleted file mode 100644
index 92d5ba5ddda..00000000000
--- a/doc/user/project/merge_requests/reviews/img/make_suggestion_v13_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/reviews/img/suggestion_button_v13_9.png b/doc/user/project/merge_requests/reviews/img/suggestion_button_v13_9.png
deleted file mode 100644
index 58e0508d8cf..00000000000
--- a/doc/user/project/merge_requests/reviews/img/suggestion_button_v13_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/reviews/img/suggestions_custom_commit_messages_v14_7.png b/doc/user/project/merge_requests/reviews/img/suggestions_custom_commit_messages_v14_7.png
deleted file mode 100644
index 2805ef19f2d..00000000000
--- a/doc/user/project/merge_requests/reviews/img/suggestions_custom_commit_messages_v14_7.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/reviews/index.md b/doc/user/project/merge_requests/reviews/index.md
index 5291a845437..4bd77c7ebdd 100644
--- a/doc/user/project/merge_requests/reviews/index.md
+++ b/doc/user/project/merge_requests/reviews/index.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: index, reference
---
-# Review a merge request **(FREE)**
+# Merge request reviews **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216054) in GitLab 13.5.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/245190) in GitLab 13.9.
@@ -84,7 +84,7 @@ To download the changes included in a merge request as a diff:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Merge requests**.
1. Select your merge request.
-1. In the upper right, select **Code > Plain diff**.
+1. In the upper-right corner, select **Code > Plain diff**.
If you know the URL of the merge request, you can also download the diff from
the command line by appending `.diff` to the URL. This example downloads the diff
@@ -107,7 +107,7 @@ To download the changes included in a merge request as a patch file:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Merge requests**.
1. Select your merge request.
-1. In the upper right, select **Code > Email patches**.
+1. In the upper-right corner, select **Code > Email patches**.
If you know the URL of the merge request, you can also download the patch from
the command line by appending `.patch` to the URL. This example downloads the patch
diff --git a/doc/user/project/merge_requests/reviews/suggestions.md b/doc/user/project/merge_requests/reviews/suggestions.md
index 668dece9fda..6976d4052e1 100644
--- a/doc/user/project/merge_requests/reviews/suggestions.md
+++ b/doc/user/project/merge_requests/reviews/suggestions.md
@@ -8,44 +8,40 @@ type: index, reference
# Suggest changes **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25381) custom commit messages for suggestions in GitLab 13.9 [with a flag](../../../../administration/feature_flags.md) named `suggestions_custom_commit`. Disabled by default.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/297404) in GitLab 13.10.
-
-As a reviewer, you're able to suggest code changes with a Markdown syntax in merge request
-diff threads. Then, the merge request author (or other users with appropriate
-[permission](../../../permissions.md)) can apply these suggestions.
-This action generates a commit in the merge request, authored by the user that suggested the changes.
-
-1. Choose a line of code to be changed, add a new comment, then select
- the **Insert suggestion** icon in the toolbar:
-
- ![Add a new comment](img/suggestion_button_v13_9.png)
-
-1. In the comment, add your suggestion to the pre-populated code block:
-
- ![Add a suggestion into a code block tagged properly](img/make_suggestion_v13_9.png)
-
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/297404) in GitLab 13.10. Feature flag `suggestions_custom_commit` removed.
+
+Reviewers can suggest code changes with a Markdown syntax in merge request diff threads.
+The merge request author (or other users with the appropriate role) can apply any or
+all of the suggestions from the GitLab UI. Applying suggestions adds a commit to the
+merge request, authored by the user who suggested the changes.
+
+## Create suggestions
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Merge requests** and find your merge request.
+1. On the secondary menu, select **Changes**.
+1. Find the lines of code you want to change.
+ - To select a single line:
+ - Hover over the line number, and
+ select **Add a comment to this line** (**{comment}**).
+ - To select multiple lines:
+ 1. Hover over the line number, and select **Add a comment to this line** (**{comment}**).
+ 1. Select and drag your selection until all desired lines are included. To
+ learn more, see [Multi-line suggestions](#multi-line-suggestions).
+1. In the comment toolbar, select **Insert suggestion** (**{doc-code}**). GitLab
+ inserts a pre-populated code block into your comment, like this:
+
+ ````markdown
+ ```suggestion:-0+0
+ The content of the line you selected is shown here.
+ ```
+ ````
+
+1. Edit the pre-populated code block to add your suggestion.
1. Select either **Start a review** or **Add to review** to add your comment to a
[review](index.md), or **Add comment now** to add the comment to the thread immediately.
- The suggestion in the comment can be applied by the merge request author
- directly from the merge request:
-
- ![Apply suggestions](img/apply_suggestion_v13_9.png)
-
-1. Optionally specify a custom commit message for individual suggestions (GitLab 13.9 and later) to
- describe your change. If you don't specify it, the default commit message is used.
-
- ![Custom commit](img/custom_commit_v13_9.png)
-
-After the author applies a suggestion:
-
-1. The suggestion is marked as **Applied**.
-1. The thread is resolved.
-1. GitLab creates a new commit with the changes.
-1. If the user has the Developer role, GitLab pushes
- the suggested change directly into the codebase in the merge request's branch.
-
-## Multi-line suggestions
+### Multi-line suggestions
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/232339) in GitLab 13.11: suggestions in multi-line comments also become multi-line.
@@ -68,65 +64,83 @@ Suggestions for multiple lines are limited to 100 lines _above_ and 100
lines _below_ the commented diff line. This allows for up to 200 changed lines per
suggestion.
-## Code block nested in suggestions
+## Apply suggestions
+
+The merge request author can apply suggested changes directly from the merge request:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **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**.
+ - To apply multiple suggestions in a single commit, select **Add suggestion to batch**.
+1. Optional. Provide a custom commit message to describe your change. If you don't provide a custom message, the default commit message is used.
+1. Select **Apply**.
+
+After a suggestion is applied:
+
+- The suggestion is marked as **Applied**.
+- The comment thread is resolved.
+- GitLab creates a new commit with the changes.
+- If the user has the Developer role, GitLab pushes
+ the suggested change directly into the codebase in the merge request's branch.
+
+## Nest code blocks in suggestions
To add a suggestion that includes a
[fenced code block](../../../markdown.md#code-spans-and-blocks), wrap your suggestion
in four backticks instead of three:
-~~~markdown
+`````markdown
````suggestion:-0+2
```shell
git config --global receive.advertisepushoptions true
```
````
-~~~
+`````
![Output of a comment with a suggestion with a fenced code block](img/suggestion_code_block_output_v12_8.png)
## Configure the commit message for applied suggestions
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13086) in GitLab 12.7.
+GitLab uses a default commit message when applying suggestions. This message
+supports placeholders, and can be changed. For example, the default message
+`Apply %{suggestions_count} suggestion(s) to %{files_count} file(s)` renders
+like this if you apply three suggestions to two different files:
-GitLab uses a default commit message
-when applying suggestions: `Apply %{suggestions_count} suggestion(s) to %{files_count} file(s)`
-
-<!-- vale gitlab.BadPlurals = NO -->
+```plaintext
+Apply 3 suggestion(s) to 2 file(s)
+```
-For example, consider that a user applied 3 suggestions to 2 different files, the
-default commit message is: **Apply 3 suggestion(s) to 2 file(s)**
+Merge requests created from forks use the template defined in the target project.
-<!-- vale gitlab.BadPlurals = YES -->
+To meet your project's needs, you can customize these messages and include other
+placeholder variables:
-These commit messages can be customized to follow any guidelines you might have.
-To do so, expand the **Merge requests** tab within your project's **General**
-settings and change the **Merge suggestions** text:
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, 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
+ you can use in this message.
-![Custom commit message for applied suggestions](img/suggestions_custom_commit_messages_v14_7.png)
+### Supported variables
-You can also use following variables besides static text:
+The template for commit messages for applied suggestions supports these variables:
| Variable | Description | Output example |
|------------------------|-------------|----------------|
| `%{branch_name}` | The name of the branch to which suggestions were applied. | `my-feature-branch` |
-| `%{files_count}` | The number of files to which suggestions were applied.| **2** |
+| `%{files_count}` | The number of files to which suggestions were applied.| `2` |
| `%{file_paths}` | The paths of the file to which suggestions were applied. Paths are separated by commas.| `docs/index.md, docs/about.md` |
| `%{project_path}` | The project path. | `my-group/my-project` |
-| `%{project_name}` | The human-readable name of the project. | **My Project** |
-| `%{suggestions_count}` | The number of suggestions applied.| **3** |
+| `%{project_name}` | The human-readable name of the project. | `My Project` |
+| `%{suggestions_count}` | The number of suggestions applied.| `3` |
| `%{username}` | The username of the user applying suggestions. | `user_1` |
-| `%{user_full_name}` | The full name of the user applying suggestions. | **User 1** |
+| `%{user_full_name}` | The full name of the user applying suggestions. | `User 1` |
For example, to customize the commit message to output
-**Addresses user_1's review**, set the custom text to
+`Addresses user_1's review`, set the custom text to
`Addresses %{username}'s review`.
-For merge requests created from forks, GitLab uses the template defined in target project.
-
-NOTE:
-Custom commit messages for each applied suggestion is
-introduced by [#25381](https://gitlab.com/gitlab-org/gitlab/-/issues/25381).
-
## Batch suggestions
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25486) in GitLab 13.1 as an [alpha feature](../../../../policy/alpha-beta-support.md#alpha-features) with a flag named `batch_suggestions`, disabled by default.
diff --git a/doc/user/project/merge_requests/status_checks.md b/doc/user/project/merge_requests/status_checks.md
index 62a2baa049b..6a791a17057 100644
--- a/doc/user/project/merge_requests/status_checks.md
+++ b/doc/user/project/merge_requests/status_checks.md
@@ -151,12 +151,15 @@ the status check and it **is not** recoverable.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327634) in GitLab 14.1.
> - UI [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91504) in GitLab 15.2.
> - Ability to retry failed external status checks [added](https://gitlab.com/gitlab-org/gitlab/-/issues/383200) in GitLab 15.8.
+> - Widget [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111763) to poll for updates when there are pending status checks in GitLab 15.11.
The status checks widget displays in merge requests and displays the following statuses:
- **pending** (**{status-neutral}**), while GitLab waits for a response from an external status check.
- **success** (**{status-success}**) or **failed** (**{status-failed}**), when GitLab receives a response from an external status check.
+When there are pending status checks, the widget polls for updates every few seconds until it receives a **success** or **failed** response.
+
To retry a failed status check:
1. Expand the merge request widget to show the list of external status checks.
diff --git a/doc/user/project/milestones/burndown_and_burnup_charts.md b/doc/user/project/milestones/burndown_and_burnup_charts.md
index 81b334c0a02..c7ed6069cb6 100644
--- a/doc/user/project/milestones/burndown_and_burnup_charts.md
+++ b/doc/user/project/milestones/burndown_and_burnup_charts.md
@@ -137,14 +137,16 @@ To switch between the two settings, select either **Issues** or **Issue weight**
When sorting by weight, make sure all your issues
have weight assigned, because issues with no weight don't show on the chart.
-<!-- ## Troubleshooting
+## Troubleshooting
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
+### Burndown and burnup charts do not show the correct issue status
-Each scenario can be a third-level heading, for example `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+A limitation of these charts is that [the days are in the UTC time zone](https://gitlab.com/gitlab-org/gitlab/-/issues/267967).
+
+This can cause the graphs to be inaccurate in other timezones. For example:
+
+- All the issues in a milestone are recorded as being closed on or before the last day.
+- One issue was closed on the last day at 6 PM PST (Pacific time), which is UTC-7.
+- The issue activity log displays the closure time at 6 PM on the last day of the milestone.
+- The charts plot the time in UTC, so for this issue, the close time is 1 AM the following day.
+- The charts show the milestone as incomplete and missing one closed issue.
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index 5f9a2961df5..e9de780655a 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -65,7 +65,10 @@ Improving this experience is tracked in issue [339009](https://gitlab.com/gitlab
You can view all the milestones you have access to in the entire GitLab namespace.
You might not see some milestones because they're in projects or groups you're not a member of.
-To do so, on the top bar select **Main menu > Milestones**.
+To do so:
+
+1. On the top bar select **Main menu > Your work**.
+1. On the left sidebar, select **Milestones**.
### View milestone details
diff --git a/doc/user/project/organize_work_with_projects.md b/doc/user/project/organize_work_with_projects.md
index 2b4ce6d2fd0..85a1dfda679 100644
--- a/doc/user/project/organize_work_with_projects.md
+++ b/doc/user/project/organize_work_with_projects.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md
index e55cf337d16..a92f65b064e 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md
@@ -5,10 +5,7 @@ group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# DNS records overview **(FREE)**
-
-_Read this document for a brief overview of DNS records in the scope
-of GitLab Pages, for beginners in web development._
+# GitLab Pages DNS records **(FREE)**
A Domain Name System (DNS) web service routes visitors to websites
by translating domain names (such as `www.example.com`) into the
@@ -74,7 +71,7 @@ Example:
This way, visitors visiting `www.example.com` are redirected to
`example.com`.
-## MX record
+## `MX` record
MX records are used to define the mail exchanges that are used for the domain.
This helps email messages arrive at your mail server correctly.
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 24e9e6e15a4..3bb62921979 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
@@ -5,7 +5,7 @@ group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Custom domains and SSL/TLS certificates **(FREE)**
+# GitLab Pages custom domains **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238461) in GitLab 15.4, you can use verified domains to [bypass user email confirmation for SAML- or SCIM-provisioned users](../../../group/saml_sso/index.md#bypass-user-email-confirmation-with-verified-domains).
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 95ac2e50f29..34a2f221327 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
@@ -6,7 +6,7 @@ group: Editor
info: To 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 Pages integration with Let's Encrypt **(FREE)**
+# GitLab Pages Let's Encrypt certificates **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/28996) in GitLab 12.1.
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md
index 398d8dc6e1e..0ba00177659 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/ssl_tls_concepts.md
@@ -5,10 +5,7 @@ group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# SSL/TLS certificates **(FREE)**
-
-_Read this document for a brief overview of SSL/TLS certificates in
-the scope of GitLab Pages, for beginners in web development._
+# GitLab Pages SSL/TLS certificates **(FREE)**
Every GitLab Pages project on GitLab.com is available under
HTTPS for the default Pages domain (`*.gitlab.io`). Once you set
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 f596e418b02..37f74d18d4c 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
@@ -5,7 +5,7 @@ group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Create a Pages website by using a CI/CD template **(FREE)**
+# Create a GitLab Pages website from a CI/CD template **(FREE)**
GitLab provides `.gitlab-ci.yml` templates for the most popular Static Site Generators (SSGs).
You can create your own `.gitlab-ci.yml` file from one of these templates, and run
diff --git a/doc/user/project/pages/getting_started/pages_forked_sample_project.md b/doc/user/project/pages/getting_started/pages_forked_sample_project.md
index 509609e9b89..a864c114b3e 100644
--- a/doc/user/project/pages/getting_started/pages_forked_sample_project.md
+++ b/doc/user/project/pages/getting_started/pages_forked_sample_project.md
@@ -5,7 +5,7 @@ group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Create a Pages website from a forked sample **(FREE)**
+# Create a GitLab Pages website from a forked sample project **(FREE)**
GitLab provides [sample projects for the most popular Static Site Generators (SSG)](https://gitlab.com/pages).
You can fork one of the sample projects and run the CI/CD pipeline to generate a Pages website.
@@ -19,7 +19,7 @@ To fork a sample project and create a Pages website:
1. View the sample projects by navigating to the [GitLab Pages examples](https://gitlab.com/pages) group.
1. Select the name of the project you want to [fork](../../repository/forking_workflow.md#creating-a-fork).
-1. In the upper right, select **Fork** and then choose a namespace to fork to.
+1. In the upper-right corner, select **Fork**, then choose a namespace to fork to.
1. For your project, on the left sidebar, select **CI/CD > Pipelines** and then **Run pipeline**.
GitLab CI/CD builds and deploys your site.
diff --git a/doc/user/project/pages/getting_started/pages_new_project_template.md b/doc/user/project/pages/getting_started/pages_new_project_template.md
index a301d2b64be..7b6efaa7af4 100644
--- a/doc/user/project/pages/getting_started/pages_new_project_template.md
+++ b/doc/user/project/pages/getting_started/pages_new_project_template.md
@@ -4,7 +4,7 @@ group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Create a Pages website from a template **(FREE)**
+# Create a GitLab Pages website from a project template **(FREE)**
GitLab provides templates for the most popular Static Site Generators (SSGs).
You can create a new project from a template and run the CI/CD pipeline to generate a Pages website.
diff --git a/doc/user/project/pages/getting_started/pages_ui.md b/doc/user/project/pages/getting_started/pages_ui.md
index 91c2c532a9a..00635fe6db2 100644
--- a/doc/user/project/pages/getting_started/pages_ui.md
+++ b/doc/user/project/pages/getting_started/pages_ui.md
@@ -4,7 +4,7 @@ group: Incubation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Create a Pages deployment for your static site **(FREE)**
+# Create a GitLab Pages deployment for a static site **(FREE)**
If you already have a GitLab project that contains your static site or framework,
you can generate a GitLab Pages website from it.
diff --git a/doc/user/project/pages/getting_started_part_one.md b/doc/user/project/pages/getting_started_part_one.md
index a0c8073d6eb..b286c59916a 100644
--- a/doc/user/project/pages/getting_started_part_one.md
+++ b/doc/user/project/pages/getting_started_part_one.md
@@ -4,7 +4,7 @@ group: Editor
info: To 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 Pages domain names, URLs, and base URLs **(FREE)**
+# GitLab Pages default domain names and URLs **(FREE)**
On this document, learn how to name your project for GitLab Pages
according to your intended website's URL.
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index 51c42eeecb8..0a8348f468e 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -4,7 +4,7 @@ group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Exploring GitLab Pages **(FREE)**
+# GitLab Pages settings **(FREE)**
This document is a user guide to explore the options and settings
GitLab Pages offers.
diff --git a/doc/user/project/pages/public_folder.md b/doc/user/project/pages/public_folder.md
index 751db136e34..3007d1a10d1 100644
--- a/doc/user/project/pages/public_folder.md
+++ b/doc/user/project/pages/public_folder.md
@@ -6,7 +6,7 @@ group: Editor
info: To 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 the public files folder **(FREE)**
+# GitLab Pages public folder **(FREE)**
All the files that should be accessible by the browser must be in a root-level folder called `public`.
@@ -98,7 +98,7 @@ example:
next export -o public
```
-### Nuxt.js
+## Nuxt.js
NOTE:
GitLab Pages supports only static sites.
diff --git a/doc/user/project/pages/redirects.md b/doc/user/project/pages/redirects.md
index f5447fd67ca..75cb1474dc2 100644
--- a/doc/user/project/pages/redirects.md
+++ b/doc/user/project/pages/redirects.md
@@ -4,7 +4,7 @@ group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Create redirects for GitLab Pages **(FREE)**
+# GitLab Pages redirects **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/24) in GitLab Pages 1.25.0 and GitLab 13.4 behind a feature flag, disabled by default.
> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab-pages/-/merge_requests/367) in GitLab 13.5.
diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md
index da53fe2f5e9..725818a7d25 100644
--- a/doc/user/project/protected_branches.md
+++ b/doc/user/project/protected_branches.md
@@ -36,6 +36,40 @@ When a branch is protected, the default behavior enforces these restrictions on
1. No one can delete a protected branch using Git commands, however, users with at least Maintainer
role can [delete a protected branch from the UI or API](#delete-a-protected-branch).
+### When a branch matches multiple rules
+
+When a branch matches multiple rules, the **most permissive rule** determines the
+level of protection for the branch. For example, consider these rules, which include
+[wildcards](#configure-multiple-protected-branches-by-using-a-wildcard):
+
+| Branch name pattern | Allowed to merge | Allowed to push |
+|---------------------|------------------------|-----------------|
+| `v1.x` | Maintainer | Maintainer |
+| `v1.*` | Maintainer + Developer | Maintainer |
+| `v*` | No one | No one |
+
+A branch named `v1.x` matches all three branch name patterns: `v1.x`, `v1.*`, and `v*`.
+As the most permissive option determines the behavior, the resulting permissions for branch `v1.x` are:
+
+- **Allowed to merge:** Of the three settings, `Maintainer + Developer` is most permissive,
+ and controls branch behavior as a result. Even though the branch also matched `v1.x` and `v*`
+ (which each have stricter permissions), users with the Developer role can merge into the branch.
+- **Allowed to push:** Of the three settings, `Maintainer` is the most permissive, and controls
+ branch behavior as a result. Even though branches matching `v*` are set to `No one`, branches
+ that _also_ match `v1.x` or `v1.*` receive the more permissive `Maintainer` permission.
+
+To be certain that a rule controls the behavior of a branch,
+_all_ other patterns that match must apply less or equally permissive rules.
+
+If you want to ensure that `No one` is allowed to push to branch `v1.x`, every pattern
+that matches `v1.x` must set `Allowed to push` to `No one`, like this:
+
+| Branch name pattern | Allowed to merge | Allowed to push |
+|---------------------|------------------------|-----------------|
+| `v1.x` | Maintainer | No one |
+| `v1.*` | Maintainer + Developer | No one |
+| `v*` | No one | No one |
+
### Set the default branch protection level
Administrators can set a default branch protection level in the
@@ -43,6 +77,37 @@ Administrators can set a default branch protection level in the
## Configure a protected branch
+Configure protected branches for all projects in a group, or just for a project.
+
+### For all projects in a group
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106532) in GitLab 15.9 behind a feature flag, disabled by default.
+
+Group owners can create protected branches for a group. These settings are inherited by all projects in the group and can't be overridden by project settings.
+
+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 `group_protected_branches`. On GitLab.com, this feature is not available.
+
+Prerequisite:
+
+- You must have the Owner role in the group.
+
+To protect a branch for all the projects in a group:
+
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, select **Settings > Repository**.
+1. Expand **Protected branches**.
+1. In the **Branch** text box, type the branch name or a wildcard.
+1. From the **Allowed to merge** list, select a role, group, or user that can merge into this branch.
+1. From the **Allowed to push** list, select a role, group, or user that can push to this branch.
+1. Select **Protect**.
+
+The protected branch is added to the list of protected branches.
+
+### For a project
+
Prerequisite:
- You must have at least the Maintainer role.
@@ -203,8 +268,7 @@ Members who can push to this branch can now also force push.
## Require Code Owner approval on a protected branch **(PREMIUM)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13251) in GitLab 12.4.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35097) in GitLab 13.5, users and groups who can push to protected branches do not have to use a merge request to merge their feature branches. This means they can skip merge request approval rules.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35097) in GitLab 13.5, users and groups who can push to protected branches do not have to use a merge request to merge their feature branches. This means they can skip merge request approval rules.
For a protected branch, you can require at least one approval by a [Code Owner](code_owners.md).
diff --git a/doc/user/project/protected_tags.md b/doc/user/project/protected_tags.md
index 152a55d24b7..1256599c521 100644
--- a/doc/user/project/protected_tags.md
+++ b/doc/user/project/protected_tags.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Protected tags **(FREE)**
-Protected tags:
+Protected [tags](repository/tags/index.md):
- Allow control over who has permission to create tags.
- Prevent accidental update or deletion once created.
@@ -86,6 +86,32 @@ To prevent this problem:
Users can still create branches, but not tags, with the protected names.
+## Allow deploy keys to create protected tags
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325415) in GitLab 15.11.
+
+You can permit the owner of a [deploy key](deploy_keys/index.md) to create protected tags.
+The deploy key works, even if the user isn't a member of the related project. However, the owner of the deploy
+key must have at least read access to the project.
+
+Prerequisites:
+
+- The deploy key must be enabled for your project. A project deploy key is enabled by default when
+ it is created. However, a public deploy key must be
+ [granted](deploy_keys/index.md#grant-project-access-to-a-public-deploy-key) access to the
+ project.
+- The deploy key must have [write access](deploy_keys/index.md#permissions) to your project
+ repository.
+
+To allow a deploy key to create a protected tag:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Repository**.
+1. Expand **Protected tags**.
+1. From the **Tag** dropdown list, select the tag you want to protect.
+1. From the **Allowed to create** list, select the deploy key.
+1. Select **Protect**.
+
## Delete a protected tag
You can manually delete protected tags with the GitLab API, or the
@@ -106,6 +132,11 @@ Protected tags can only be deleted by using GitLab either from the UI or API.
These protections prevent you from accidentally deleting a tag through local
Git commands or third-party Git clients.
+## Related topics
+
+- [Protected Tags API](../../api/protected_tags.md)
+- [Tags API](../../api/tags.md)
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index 90da47f7995..3a00260770e 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -69,7 +69,7 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/copy_metadata <!merge_request>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Copy labels and milestone from another merge request in the project. |
| `/copy_metadata <#issue>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Copy labels and milestone from another issue in the project. |
| `/create_merge_request <branch name>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Create a new merge request starting from the current issue. |
-| `/done` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mark to do as done. |
+| `/done` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mark to-do item as done. |
| `/draft` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Set the [draft status](merge_requests/drafts.md). Use for toggling the draft status ([deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92654) in GitLab 15.4.) |
| `/due <date>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set due date. Examples of valid `<date>` include `in 2 days`, `this Friday` and `December 31st`. See [Chronic](https://gitlab.com/gitlab-org/ruby/gems/gitlab-chronic#examples) for more examples. |
| `/duplicate <#issue>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Close this issue. Mark as a duplicate of, and related to, issue `<#issue>`. |
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
index dca34af41b4..be2c923adcc 100644
--- a/doc/user/project/releases/index.md
+++ b/doc/user/project/releases/index.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -88,7 +88,7 @@ To create a release in the Releases page:
- [Title](release_fields.md#title).
- [Milestones](#associate-milestones-with-a-release).
- [Release notes](release_fields.md#release-notes-description).
- - Whether or not to include the [Tag message](../../../topics/git/tags.md).
+ - Whether or not to include the [Tag message](../repository/tags/index.md).
- [Asset links](release_fields.md#links).
1. Select **Create release**.
diff --git a/doc/user/project/releases/release_cicd_examples.md b/doc/user/project/releases/release_cicd_examples.md
index 1ec82d6702e..36e36412cf1 100644
--- a/doc/user/project/releases/release_cicd_examples.md
+++ b/doc/user/project/releases/release_cicd_examples.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/releases/release_cli.md b/doc/user/project/releases/release_cli.md
index 5af19c7cced..953e1d4b082 100644
--- a/doc/user/project/releases/release_cli.md
+++ b/doc/user/project/releases/release_cli.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/releases/release_fields.md b/doc/user/project/releases/release_fields.md
index 120bbe32a63..93822be89b6 100644
--- a/doc/user/project/releases/release_fields.md
+++ b/doc/user/project/releases/release_fields.md
@@ -1,6 +1,6 @@
---
-stage: Release
-group: Release
+stage: Configure
+group: Configure
info: To 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/remote_development/index.md b/doc/user/project/remote_development/index.md
index 1abcca547db..58d43f64812 100644
--- a/doc/user/project/remote_development/index.md
+++ b/doc/user/project/remote_development/index.md
@@ -97,7 +97,7 @@ docker run -d \
-v "${CERTS_DIR}/fullchain.pem:/gitlab-rd-web-ide/certs/fullchain.pem" \
-v "${CERTS_DIR}/privkey.pem:/gitlab-rd-web-ide/certs/privkey.pem" \
-v "${PROJECTS_DIR}:/projects" \
- registry.gitlab.com/gitlab-com/create-stage/editor-poc/remote-development/gitlab-rd-web-ide-docker:0.1-alpha \
+ registry.gitlab.com/gitlab-org/remote-development/gitlab-rd-web-ide-docker:0.2-alpha \
--log-level warn --domain "${DOMAIN}" --ignore-version-mismatch
```
diff --git a/doc/user/project/repository/branches/img/branch_filter_search_box_v13_12.png b/doc/user/project/repository/branches/img/branch_filter_search_box_v13_12.png
deleted file mode 100644
index a1cf9f10122..00000000000
--- a/doc/user/project/repository/branches/img/branch_filter_search_box_v13_12.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/repository/branches/img/compare_branches_v13_12.png b/doc/user/project/repository/branches/img/compare_branches_v13_12.png
deleted file mode 100644
index 29627406729..00000000000
--- a/doc/user/project/repository/branches/img/compare_branches_v13_12.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/repository/branches/img/repository_filter_search_box_v13_12.png b/doc/user/project/repository/branches/img/repository_filter_search_box_v13_12.png
deleted file mode 100644
index 230abf0d875..00000000000
--- a/doc/user/project/repository/branches/img/repository_filter_search_box_v13_12.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/repository/branches/img/swap_revisions_after_v13_12.png b/doc/user/project/repository/branches/img/swap_revisions_after_v13_12.png
deleted file mode 100644
index 7eb10d10938..00000000000
--- a/doc/user/project/repository/branches/img/swap_revisions_after_v13_12.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/repository/branches/img/swap_revisions_before_v13_12.png b/doc/user/project/repository/branches/img/swap_revisions_before_v13_12.png
deleted file mode 100644
index f92c4279871..00000000000
--- a/doc/user/project/repository/branches/img/swap_revisions_before_v13_12.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/repository/branches/img/view_branch_protections_v15_10.png b/doc/user/project/repository/branches/img/view_branch_protections_v15_10.png
new file mode 100644
index 00000000000..09b30af91d0
--- /dev/null
+++ b/doc/user/project/repository/branches/img/view_branch_protections_v15_10.png
Binary files differ
diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md
index 60504b94502..ef625739956 100644
--- a/doc/user/project/repository/branches/index.md
+++ b/doc/user/project/repository/branches/index.md
@@ -6,142 +6,148 @@ info: "To determine the technical writer assigned to the Stage/Group associated
# Branches **(FREE)**
-A branch is a version of a project's working tree. You create a branch for each
-set of related changes you make. This keeps each set of changes separate from
-each other, allowing changes to be made in parallel, without affecting each
-other.
+Branches are versions of a project's working tree. When you create a new
+[project](../../index.md), GitLab creates a [default branch](default.md) (which
+cannot be deleted) for your repository. Default branch settings can be configured
+at the project, subgroup, group, or instance level.
-After pushing your changes to a new branch, you can:
+As your project grows, your team [creates](../web_editor.md#create-a-branch) 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.
-- Create a [merge request](../../merge_requests/index.md). You can streamline this process
- by following [branch naming patterns](#naming).
-- Perform inline code review.
-- [Discuss](../../../discussions/index.md) your implementation with your team.
-- Preview changes submitted to a new branch with [Review Apps](../../../../ci/review_apps/index.md).
+Branches are the foundation of development in a project:
-You can also request [approval](../../merge_requests/approvals/index.md)
-from your managers.
+1. To get started, create a branch and add commits to it.
+1. When the work is ready for review, create a [merge request](../../merge_requests/index.md) to propose
+ merging the changes in your branch. To streamline this process, you should follow
+ [branch naming patterns](#prefix-branch-names-with-issue-numbers).
+1. Preview changes in a branch with a [review app](../../../../ci/review_apps/index.md).
+1. After the contents of your branch are merged, [delete the merged branch](#delete-merged-branches).
-For more information on managing branches using the GitLab UI, see:
+## Manage and protect branches
-- [Default branches](default.md): When you create a new [project](../../index.md), GitLab creates a
- default branch for the repository. You can change this setting at the project,
- subgroup, group, or instance level.
-- [Create a branch](../web_editor.md#create-a-branch)
-- [Protected branches](../../protected_branches.md#protected-branches)
-- [Delete merged branches](#delete-merged-branches)
-- [Branch filter search box](#branch-filter-search-box)
+GitLab provides you multiple methods to protect individual branches. These methods
+ensure your branches receive oversight and quality checks from their creation to their deletion:
-You can also manage branches using the
-[command line](../../../../gitlab-basics/start-using-git.md#create-a-branch).
+- The [default branch](default.md) in your project receives extra protection.
+- Configure [protected branches](../../protected_branches.md#protected-branches)
+ to restrict who can commit to a branch, merge other branches into it, or merge
+ the branch itself into another branch.
+- Configure [approval rules](../../merge_requests/approvals/rules.md) to set review
+ requirements, including [security-related approvals](../../merge_requests/approvals/rules.md#security-approvals), before a branch can merge.
+- Integrate with third-party [status checks](../../merge_requests/status_checks.md)
+ to ensure your branch contents meet your standards of quality.
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>Watch the video [GitLab Flow](https://www.youtube.com/watch?v=InKNIvky2KE).
+You can manage your branches:
-See also:
+- With the GitLab user interface.
+- With the [command line](../../../../gitlab-basics/start-using-git.md#create-a-branch).
+- With the [Branches API](../../../../api/branches.md).
-- [Branches API](../../../../api/branches.md), for information on operating on repository branches using the GitLab API.
-- [GitLab Flow](../../../../topics/gitlab_flow.md) documentation.
-- [Getting started with Git](../../../../topics/git/index.md) and GitLab.
-
-## Naming
-
-Prefix a branch name with an issue number to streamline merge request creation.
-When you create a merge request for a branch with a name beginning with an issue
-number, GitLab:
-
-- Marks the issue as related. If your project is configured with a
- [default closing pattern](../../issues/managing_issues.md#default-closing-pattern),
- merging this merge request [also closes](../../issues/managing_issues.md#closing-issues-automatically)
- the related issue.
-- Copies label and milestone metadata from the issue.
-
-## Compare
-
-To compare branches in a repository:
-
-1. Navigate to your project's repository.
-1. Select **Repository > Compare** in the sidebar.
-1. Select the target repository to compare with the [repository filter search box](#repository-filter-search-box).
-1. Select branches to compare using the [branch filter search box](#branch-filter-search-box).
-1. Select **Compare** to view the changes inline:
-
- ![compare branches](img/compare_branches_v13_12.png)
-
-## Delete merged branches
-
-![Delete merged branches](img/delete_merged_branches.png)
+### View all branches
-This feature allows merged branches to be deleted in bulk. Only branches that
-have been merged into the project's default branch and
-[are not protected](../../protected_branches.md) are deleted as part of
-this operation.
+To view and manage your branches in the GitLab user interface:
-It's particularly useful to clean up old branches that were not deleted
-automatically when a merge request was merged.
-
-## Repository filter search box
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Repository > Branches**.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52967) in GitLab 13.10.
+On this page, you can:
-This feature allows you to search and select a repository quickly when [comparing branches](#compare).
+- See all branches, active branches, or stale branches.
+- Create new branches.
+- [Compare branches](#compare-branches).
+- Delete merged branches.
-![Repository filter search box](img/repository_filter_search_box_v13_12.png)
+### View branches with configured protections
-Search results appear in the following order:
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88279) in GitLab 15.1 with a flag named `branch_rules`. Disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/363170) in GitLab 15.10.
-- Repositories with names exactly matching the search terms.
-- Other repositories with names that include search terms, sorted alphabetically.
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../feature_flags.md) named `branch_rules`.
+On GitLab.com, this feature is available.
-## Branch filter search box
+Branches in your repository can be [protected](../../protected_branches.md) in multiple ways. You can:
-![Branch filter search box](img/branch_filter_search_box_v13_12.png)
+- Limit who can push to the branch.
+- Limit who can merge the branch.
+- Require approval of all changes.
+- Require external tests to pass.
-This feature allows you to search and select branches quickly. Search results appear in the following order:
+The **Branch rules overview** page shows all branches with any configured protections,
+and their protection methods:
-- Branches with names that matched search terms exactly.
-- Other branches with names that include search terms, sorted alphabetically.
+![Example of a branch with configured protections](img/view_branch_protections_v15_10.png)
-Sometimes when you have hundreds of branches you may want a more flexible matching pattern. In such cases you can use the following operators:
+Prerequisites:
-- `^` matches beginning of branch name, for example `^feat` would match `feat/user-authentication`
-- `$` matches end of branch name, for example `widget$` would match `feat/search-box-widget`
-- `*` wildcard matcher, for example `branch*cache*` would match `fix/branch-search-cache-expiration`
+- You must have at least the Developer role in the project.
-These operators can be mixed, for example `^chore/*migration$` would match `chore/user-data-migration`
+To view the **Branch rules overview** list:
-## Swap revisions
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Repository**.
+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:
+ - [Branch protections](../../protected_branches.md).
+ - [Approval rules](../../merge_requests/approvals/rules.md).
+ - [Status checks](../../merge_requests/status_checks.md).
+
+## 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:
+
+- The issue is marked as related. The issue and merge request display links to each other.
+- If your project is configured with a
+ [default closing pattern](../../issues/managing_issues.md#default-closing-pattern),
+ merging the merge request [also closes](../../issues/managing_issues.md#closing-issues-automatically)
+ the related issue.
+- The issue milestone and labels are copied to the merge request.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60491) in GitLab 13.12.
+## Compare branches
-![Before swap revisions](img/swap_revisions_before_v13_12.png)
+> - 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 Swap revisions feature allows you to swap the Source and Target revisions. When the Swap revisions button is selected, the selected revisions for Source and Target is swapped.
+To compare branches in a repository:
-![After swap revisions](img/swap_revisions_after_v13_12.png)
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Repository > 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:
+ - `^` matches the beginning of the branch name: `^feat` matches `feat/user-authentication`.
+ - `$` matches the end of the branch name: `widget$` matches `feat/search-box-widget`.
+ - `*` 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**.
-## View branches with configured protections **(FREE SELF)**
+## Delete merged branches
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88279) in GitLab 15.1 with a flag named `branch_rules`. Disabled by default.
+![Delete merged branches](img/delete_merged_branches.png)
-FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../feature_flags.md) named `branch_rules`.
-On GitLab.com, this feature is not available.
-This feature is not ready for production use.
+This feature allows merged branches to be deleted in bulk. Only branches that
+have been merged into the project's default branch and
+[are not protected](../../protected_branches.md) are deleted as part of
+this operation.
-Branches in your repository can be [protected](../../protected_branches.md) by limiting
-who can push to a branch, require approval for those pushed changes, or merge those changes.
-To help you track the protections for all branches, the **Branch rules overview**
-page shows your branches with their configured rules.
+It's particularly useful to clean up old branches that were not deleted
+automatically when a merge request was merged.
-To view the **Branch rules overview** list:
+## Related topics
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Settings > Repository**.
-1. Expand **Branch Rules** to view all branches with protections.
-1. Select **Details** next to your desired branch to show information about its:
- - [Branch protections](../../protected_branches.md).
- - [Approval rules](../../merge_requests/approvals/rules.md).
- - [Status checks](../../merge_requests/status_checks.md).
+- [Protected branches](../../protected_branches.md) user documentation.
+- [Branches API](../../../../api/branches.md), for information on operating on repository branches using the GitLab API.
+- [Protected Branches API](../../../../api/protected_branches.md).
+- [Getting started with Git](../../../../topics/git/index.md) and GitLab.
## Troubleshooting
diff --git a/doc/user/project/repository/file_finder.md b/doc/user/project/repository/file_finder.md
index f9a5d4e3aa7..3fcc19db344 100644
--- a/doc/user/project/repository/file_finder.md
+++ b/doc/user/project/repository/file_finder.md
@@ -11,7 +11,7 @@ The file finder feature allows you to search for a file in a repository using th
GitLab UI. To use it:
1. Go to your project's **Repository > Files**.
-1. In the upper right corner, select **Find File**.
+1. In the upper-right corner, select **Find File**.
If you prefer to keep your fingers on the keyboard, use the
[shortcut button](../../shortcuts.md), which you can invoke from anywhere
diff --git a/doc/user/project/repository/forking_workflow.md b/doc/user/project/repository/forking_workflow.md
index 929751b7247..8c7c94613a7 100644
--- a/doc/user/project/repository/forking_workflow.md
+++ b/doc/user/project/repository/forking_workflow.md
@@ -23,7 +23,7 @@ submit them through a merge request to the repository you don't have access to.
To fork an existing project in GitLab:
-1. On the project's home page, in the upper right, select **{fork}** **Fork**:
+1. On the project's homepage, in the upper-right corner, select **Fork** (**{fork}**):
![Fork this project](img/forking_workflow_fork_button_v13_10.png)
1. Optional. Edit the **Project name**.
1. For **Project URL**, select the [namespace](../../namespace/index.md)
@@ -137,3 +137,11 @@ You can unlink your fork from its upstream project in the [advanced settings](..
- GitLab blog post: [How to keep your fork up to date with its origin](https://about.gitlab.com/blog/2016/12/01/how-to-keep-your-fork-up-to-date-with-its-origin/).
- GitLab community forum: [Refreshing a fork](https://forum.gitlab.com/t/refreshing-a-fork/).
+
+## Troubleshooting
+
+### An error occurred while forking the project. Please try again
+
+This error can be due to a mismatch in shared runner settings between the forked project
+and the new namespace. See [Forks](../../../ci/runners/configure_runners.md#forks)
+in the Runner documentation for more information.
diff --git a/doc/user/project/repository/git_blame.md b/doc/user/project/repository/git_blame.md
index 78fcdec2a0b..fbf29bddd46 100644
--- a/doc/user/project/repository/git_blame.md
+++ b/doc/user/project/repository/git_blame.md
@@ -14,7 +14,7 @@ commit hash. To view it for a file:
1. Go to your project's **Repository > Files**.
1. Select the file you want to review.
-1. In the upper right corner, select **Blame**.
+1. In the upper-right corner, select **Blame**.
When you select **Blame**, this information is displayed:
diff --git a/doc/user/project/repository/git_history.md b/doc/user/project/repository/git_history.md
index 321b9a5eb53..a9228b8cabd 100644
--- a/doc/user/project/repository/git_history.md
+++ b/doc/user/project/repository/git_history.md
@@ -12,7 +12,7 @@ Git file History provides information about the commit history associated
with a file. To use it:
1. Go to your project's **Repository > Files**.
-1. In the upper right corner, select **History**.
+1. In the upper-right corner, select **History**.
When you select **History**, this information is displayed:
diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md
index 64f19d1a92c..a2dd2488961 100644
--- a/doc/user/project/repository/gpg_signed_commits/index.md
+++ b/doc/user/project/repository/gpg_signed_commits/index.md
@@ -43,7 +43,7 @@ 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
+- 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
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index 5b4e1b14489..1c64a47985b 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -25,7 +25,7 @@ You can add files to a repository:
- When you create a project.
- After you create a project:
- By using [the web editor](web_editor.md).
- - [From the command line](../../../gitlab-basics/command-line-commands.md).
+ - From the command line.
## Commit changes to a repository
@@ -235,9 +235,9 @@ The size can differ slightly from one instance to another due to compression, ho
Administrators can set a [repository size limit](../../admin_area/settings/account_and_limit_settings.md).
[GitLab sets the size limits for GitLab.com](../../gitlab_com/index.md#account-and-limit-settings).
-## Repository contributor graph
+## Repository contributor statistics
-All code contributors are displayed under your project's **Repository > Contributors**.
+All code contributors are displayed under your project's **Repository > Contributor statistics**.
The graph shows the contributor with the most commits to the fewest.
diff --git a/doc/user/project/repository/mirror/push.md b/doc/user/project/repository/mirror/push.md
index f06dd747897..ea58c472f4a 100644
--- a/doc/user/project/repository/mirror/push.md
+++ b/doc/user/project/repository/mirror/push.md
@@ -26,8 +26,10 @@ When you push a change to the upstream repository, the push mirror receives it:
- Within five minutes.
- Within one minute, if you enabled **Only mirror protected branches**.
-In the case of a diverged branch, an error displays in the **Mirroring repositories**
-section.
+When a branch is merged into the default branch and deleted in the source project,
+it is deleted from the remote mirror on the next push. Branches with unmerged
+changes are kept. If a branch diverges, the **Mirroring repositories** section
+displays an error.
## Configure push mirroring
diff --git a/doc/user/project/repository/tags/img/tag-display_v15_9.png b/doc/user/project/repository/tags/img/tag-display_v15_9.png
new file mode 100644
index 00000000000..015df07d025
--- /dev/null
+++ b/doc/user/project/repository/tags/img/tag-display_v15_9.png
Binary files differ
diff --git a/doc/user/project/repository/tags/img/tags_commits_view_v15_10.png b/doc/user/project/repository/tags/img/tags_commits_view_v15_10.png
new file mode 100644
index 00000000000..247d2f368d5
--- /dev/null
+++ b/doc/user/project/repository/tags/img/tags_commits_view_v15_10.png
Binary files differ
diff --git a/doc/user/project/repository/tags/index.md b/doc/user/project/repository/tags/index.md
new file mode 100644
index 00000000000..706b50a916d
--- /dev/null
+++ b/doc/user/project/repository/tags/index.md
@@ -0,0 +1,108 @@
+---
+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
+---
+
+# Tags **(FREE)**
+
+In Git, a tag marks an important point in a repository's history.
+Git supports two types of tags:
+
+- **Lightweight tags** point to specific commits, and contain no other information.
+ Also known as soft tags. Create or remove them as needed.
+- **Annotated tags** contain metadata, can be signed for verification purposes,
+ and can't be changed.
+
+The creation or deletion of a tag can be used as a trigger for automation, including:
+
+- Using a [webhook](../../integrations/webhook_events.md#tag-events) to automate actions
+ like Slack notifications.
+- Signaling a [repository mirror](../mirror/index.md) to update.
+- Running a CI/CD pipeline with [`if: $CI_COMMIT_TAG`](../../../../ci/jobs/job_control.md#common-if-clauses-for-rules).
+
+When you [create a release](../../releases/index.md),
+GitLab also creates a tag to mark the release point.
+Many projects combine an annotated release tag with a stable branch. Consider
+setting deployment or release tags automatically.
+
+In the GitLab UI, each tag displays:
+
+![Example of a single tag](img/tag-display_v15_9.png)
+
+- The tag name. (**{tag}**)
+- Optional. If the tag is [protected](../../protected_tags.md), a **protected** badge.
+- The commit SHA (**{commit}**), linked to the commit's contents.
+- The commit's title and creation date.
+- Optional. A link to the release (**{rocket}**).
+- Optional. If a pipeline has been run, the current pipeline status.
+- Download links to the source code and artifacts linked to the tag.
+- A [**Create release**](../../releases/index.md#create-a-release) (**{pencil}**) link.
+- A link to delete the tag.
+
+## View tags for a project
+
+To view all existing tags for a project:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Repository > Tags**.
+
+## View tagged commits in the commits list
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18795) in GitLab 15.10.
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Repository > 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`:
+
+ ![A tagged commit in the Commits view](img/tags_commits_view_v15_10.png)
+
+To view the list of commits in this tag, select the tag name.
+
+## Create a tag
+
+Tags can be created from the command line, or the GitLab UI.
+
+### From the command line
+
+To create either a lightweight or annotated tag from the command line, and push it upstream:
+
+1. To create a lightweight tag, run the command `git tag TAG_NAME`, changing
+ `TAG_NAME` to your desired tag name.
+1. To create an annotated tag, run one of the versions of `git tag` from the command line:
+
+ ```shell
+ # In this short version, the annotated tag's name is "v1.0",
+ # and the message is "Version 1.0".
+ git tag -a v1.0 -m "Version 1.0"
+
+ # Use this version to write a longer tag message
+ # for annotated tag "v1.0" in your text editor.
+ git tag -a v1.0
+ ```
+
+1. Push your tags upstream with `git push origin --tags`.
+
+### From the UI
+
+To create a tag from the GitLab UI:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Repository > Tags**.
+1. Select **New tag**.
+1. Provide a **Tag name**.
+1. For **Create from**, select an existing branch name, tag, or commit SHA.
+1. Optional. Add a **Message** to create an annotated tag, or leave blank to
+ create a lightweight tag.
+1. Select **Create tag**.
+
+## Prevent tag deletion **(PREMIUM)**
+
+To prevent users from removing a tag with `git push`, create a [push rule](../push_rules.md).
+
+## Related topics
+
+- [Tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging) Git reference page.
+- [Protected tags](../../protected_tags.md).
+- [Tags API](../../../../api/tags.md).
diff --git a/doc/user/project/repository/web_editor.md b/doc/user/project/repository/web_editor.md
index 80b0ada6f7b..ace7e119469 100644
--- a/doc/user/project/repository/web_editor.md
+++ b/doc/user/project/repository/web_editor.md
@@ -26,11 +26,32 @@ for any change you commit through the Web Editor.
To create a text file in the Web Editor:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. From the project dashboard or repository, next to the branch name, select the plus icon (**{plus}**).
+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**.
-1. Complete the fields. To create a merge request with the new file, ensure the **Start a new merge request with these changes** checkbox is selected.
+1. Complete the fields.
+1. To create a merge request with the new file, ensure the **Start a new merge request with these changes** checkbox is selected, if you had chosen a **Target branch** other than the [default branch (such as `main`)](../../../user/project/repository/branches/default.md).
1. Select **Commit changes**.
+### Create a file from a template
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Repository > Files**.
+1. Next to the project name, select the plus icon (**{plus}**) to display a
+ dropdown list, then select **New file** from the list.
+1. For **Filename**, provide one of the filenames that GitLab provides a template for:
+ - `.gitignore`
+ - `.gitlab-ci.yml`
+ - `LICENSE`
+ - `Dockerfile`
+1. Select **Apply a template**, then select the template you want to apply.
+1. Make your changes to the file.
+1. Provide a **Commit message**.
+1. Enter a **Target branch** to merge into. To create a new merge request with
+ your changes, enter a branch name that is not your repository's
+ [default branch](../../../user/project/repository/branches/default.md),
+1. Select **Commit changes** to add the commit to your branch.
+
## Edit a file
To edit a text file in the Web Editor:
@@ -87,6 +108,9 @@ To link to a single line, you can also:
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 top bar, select **Main menu > Projects** 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**.
@@ -115,7 +139,7 @@ To create a [branch](branches/index.md) in the Web Editor:
## Create a tag
-You can create [tags](../../../topics/git/tags.md) to mark milestones such as
+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 top bar, select **Main menu > Projects** and find your project.
diff --git a/doc/user/project/requirements/index.md b/doc/user/project/requirements/index.md
index b04905e6b34..d385daa4fa1 100644
--- a/doc/user/project/requirements/index.md
+++ b/doc/user/project/requirements/index.md
@@ -1,7 +1,7 @@
---
type: reference, howto
stage: Plan
-group: Certify
+group: Product Planning
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -235,9 +235,9 @@ Before you import your file:
To import requirements:
1. In a project, go to **Issues > Requirements**.
- - If the project already has existing requirements, select the import icon (**{import}**) in the
- upper right.
- - For a project without any requirements, select **Import CSV** in the middle of the page.
+ - For a project with requirements, in the
+ upper-right corner, select the import icon (**{import}**).
+ - For a project without requirements, in the middle of the page, select **Import CSV**.
1. Select the file and select **Import requirements**.
The file is processed in the background and a notification email is sent
@@ -296,7 +296,7 @@ Prerequisite:
To export requirements:
1. In a project, go to **Issues > Requirements**.
-1. In the upper right, select the **Export as CSV** icon (**{export}**).
+1. In the upper-right corner, select **Export as CSV** (**{export}**).
A confirmation modal appears.
diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md
index 22297149561..c4fcdc5733e 100644
--- a/doc/user/project/service_desk.md
+++ b/doc/user/project/service_desk.md
@@ -8,29 +8,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> Moved to GitLab Free in 13.2.
-Service Desk is a module that allows your team to connect
-with any external party through email, without any external tools.
-An ongoing conversation in the same place as where your software
-is built ensures user feedback ends up where it's needed.
+With Service Desk, your customers
+can email you bug reports, feature requests, or general feedback.
+Service Desk provides a unique email address, so they don't need their own GitLab accounts.
-With Service Desk, you can provide efficient email support to your customers. They can
-email you bug reports, feature requests, or general feedback. They all end up in your
-GitLab project as new issues. In turn, your team can respond directly from the project.
+Service Desk emails are created in your GitLab project as new issues.
+Your team can respond directly from the project, while customers interact with the thread only
+through email.
-As Service Desk is built right into GitLab itself, the complexity and inefficiencies
-of multiple tools and external integrations are eliminated. This significantly shortens
-the cycle time from feedback to software update.
-
-For an overview, check the video demonstration on [GitLab Service Desk](https://about.gitlab.com/blog/2017/05/09/demo-service-desk/).
-
-## How it works
-
-GitLab Service Desk enables people to create issues in your
-GitLab instance without needing their own user account.
-
-It provides a unique email address for end users to create issues in a project.
-Follow-up notes can be sent either through the GitLab interface or by email. End
-users only see the thread through email.
+## Service Desk workflow
For example, let's assume you develop a game for iOS or Android.
The codebase is hosted in your GitLab instance, built and deployed
@@ -43,23 +29,24 @@ Here's how Service Desk works for you:
1. Each email they send creates an issue in the appropriate project.
1. Your team members go to the Service Desk issue tracker, where they can see new support
requests and respond inside associated issues.
-1. Your team communicates back and forth with the customer to understand the request.
+1. Your team communicates with the customer to understand the request.
1. Your team starts working on implementing code to solve your customer's problem.
-1. When your team finishes the implementation, whereupon the merge request is merged and the issue
+1. When your team finishes the implementation, the merge request is merged and the issue
is closed automatically.
-1. The customer's requests are handled through email, without ever having access to your
- GitLab instance.
-1. Your team saved time by not having to leave GitLab (or setup any integrations) to follow up with
- your customer.
+
+Meanwhile:
+
+- The customer interacts with your team entirely through email, without needing access to your
+ GitLab instance.
+- Your team saves time by not having to leave GitLab (or set up integrations) to follow up with
+ your customer.
## Configuring Service Desk
Users with Maintainer and higher access in a project can configure Service Desk.
Service Desk issues are [confidential](issues/confidential_issues.md), so they are
-only visible to project members. In GitLab 11.7 we updated the generated email
-address format. The older format is still supported, so existing aliases or
-contacts still work.
+only visible to project members.
If you have [templates](description_templates.md) in your repository, you can optionally select
one from the selector menu to append it to all Service Desk issues.
@@ -93,7 +80,6 @@ displayed in the information note.
### Using customized email templates
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2460) in GitLab 12.7.
> - 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.
@@ -174,8 +160,6 @@ To use a custom description template with Service Desk:
### Using a custom email display name
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7529) in GitLab 12.8.
-
You can customize the email display name. Emails sent from Service Desk have
this name in the `From` header. The default display name is `GitLab Support Bot`.
@@ -207,15 +191,12 @@ you can customize the mailbox used by Service Desk. This allows you to have
a separate email address for Service Desk by also configuring a [custom suffix](#configuring-a-custom-email-address-suffix)
in project settings.
-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.
+Prerequisites:
-NOTE:
-When configuring a custom mailbox, the `service_desk_email` and `incoming_email`
-configurations must always use separate mailboxes. It's important, because
-emails picked from `service_desk_email` mailbox are processed by a different
-worker and it would not recognize `incoming_email` emails.
+- 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:
@@ -504,15 +485,18 @@ You can read and write comments as you usually do in GitLab:
#### Receiving files attached to comments as email attachments
-> [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.
+> - [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 not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `service_desk_new_note_email_native_attachments`.
-On GitLab.com, this feature is not available.
+On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, ask an administrator to [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.
+
#### Special HTML formatting in HTML emails
<!-- When the feature flag is removed, delete this topic and add as a line in version history under one of the topics above this one.-->
@@ -567,8 +551,3 @@ in both issues. They continue to receive any notifications in the old issue and
Your emails might be ignored because they contain one of the
[email headers that GitLab ignores](../../administration/incoming_email.md#rejected-headers).
-
-### Responses to a Service Desk issue do not generate emails
-
-Your issue might have been moved to a different project.
-Moved Service Desk issues do not retain email participants.
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 3715eef08e0..230795222a0 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -9,8 +9,8 @@ info: "To determine the technical writer assigned to the Stage/Group associated
Existing projects on any self-managed GitLab instance or GitLab.com can be exported to a file and
then imported into a new GitLab instance. You can also:
-- [Migrate groups](../../group/import/index.md) using the preferred method.
-- [Migrate groups using file exports](../../group/settings/import_export.md).
+- Migrate projects when you [migrate groups by direct transfer](../../group/import/index.md#migrate-groups-by-direct-transfer-recommended).
+- [Migrate groups by using file exports](../../group/import/index.md#migrate-groups-by-uploading-an-export-file-deprecated).
GitLab maps user contributions correctly when an admin access token is used to perform the import.
@@ -155,7 +155,8 @@ Items that are **not** exported include:
- Repository size limits
- Deploy keys allowed to push to protected branches
- Secure Files
-- [Activity logs for Git-related events](https://gitlab.com/gitlab-org/gitlab/-/issues/214700). For example, pushing and creating tags
+- [Activity logs for Git-related events](https://gitlab.com/gitlab-org/gitlab/-/issues/214700) (for example, pushing and creating tags)
+- Security policies associated with your project
## Import a project and its data
@@ -200,7 +201,7 @@ Deploy keys aren't imported. To use deploy keys, you must enable them in your im
### Import large projects **(FREE SELF)**
-If you have a larger project, consider using a Rake task as described in the [developer documentation](../../../development/import_project.md#importing-via-a-rake-task).
+If you have a larger project, consider [using a Rake task](../../../administration/raketasks/project_import_export.md#import-large-projects).
## Automate group and project import **(PREMIUM)**
diff --git a/doc/user/project/settings/import_export_troubleshooting.md b/doc/user/project/settings/import_export_troubleshooting.md
index 00edeef5cfa..82412a1dcbf 100644
--- a/doc/user/project/settings/import_export_troubleshooting.md
+++ b/doc/user/project/settings/import_export_troubleshooting.md
@@ -48,41 +48,41 @@ reduce the repository size for another import attempt:
1. Create a temporary working directory from the export:
- ```shell
- EXPORT=<filename-without-extension>
+ ```shell
+ EXPORT=<filename-without-extension>
- mkdir "$EXPORT"
- tar -xf "$EXPORT".tar.gz --directory="$EXPORT"/
- cd "$EXPORT"/
- git clone project.bundle
+ mkdir "$EXPORT"
+ tar -xf "$EXPORT".tar.gz --directory="$EXPORT"/
+ cd "$EXPORT"/
+ git clone project.bundle
- # Prevent interference with recreating an importable file later
- mv project.bundle ../"$EXPORT"-original.bundle
- mv ../"$EXPORT".tar.gz ../"$EXPORT"-original.tar.gz
+ # Prevent interference with recreating an importable file later
+ mv project.bundle ../"$EXPORT"-original.bundle
+ mv ../"$EXPORT".tar.gz ../"$EXPORT"-original.tar.gz
- git switch --create smaller-tmp-main
- ```
+ git switch --create smaller-tmp-main
+ ```
1. To reduce the repository size, work on this `smaller-tmp-main` branch:
[identify and remove large files](../repository/reducing_the_repo_size_using_git.md)
or [interactively rebase and fixup](../../../topics/git/git_rebase.md#interactive-rebase)
to reduce the number of commits.
- ```shell
- # Reduce the .git/objects/pack/ file size
- cd project
- git reflog expire --expire=now --all
- git gc --prune=now --aggressive
-
- # Prepare recreating an importable file
- git bundle create ../project.bundle <default-branch-name>
- cd ..
- mv project/ ../"$EXPORT"-project
- cd ..
-
- # Recreate an importable file
- tar -czf "$EXPORT"-smaller.tar.gz --directory="$EXPORT"/ .
- ```
+ ```shell
+ # Reduce the .git/objects/pack/ file size
+ cd project
+ git reflog expire --expire=now --all
+ git gc --prune=now --aggressive
+
+ # Prepare recreating an importable file
+ git bundle create ../project.bundle <default-branch-name>
+ cd ..
+ mv project/ ../"$EXPORT"-project
+ cd ..
+
+ # Recreate an importable file
+ tar -czf "$EXPORT"-smaller.tar.gz --directory="$EXPORT"/ .
+ ```
1. Import this new, smaller file into GitLab.
1. In a full clone of the original repository,
@@ -265,12 +265,12 @@ Marked stuck import jobs as failed. JIDs: xyz
| Problem | Possible solutions |
| -------- | -------- |
| [Slow JSON](https://gitlab.com/gitlab-org/gitlab/-/issues/25251) loading/dumping models from the database | [split the worker](https://gitlab.com/gitlab-org/gitlab/-/issues/25252) |
-| | Batch export
-| | Optimize SQL
-| | Move away from `ActiveRecord` callbacks (difficult)
-| High memory usage (see also some [analysis](https://gitlab.com/gitlab-org/gitlab/-/issues/18857) | DB Commit sweet spot that uses less memory |
+| | Batch export |
+| | Optimize SQL |
+| | Move away from `ActiveRecord` callbacks (difficult) |
+| High memory usage (see also some [analysis](https://gitlab.com/gitlab-org/gitlab/-/issues/18857)) | DB Commit sweet spot that uses less memory |
| | [Netflix Fast JSON API](https://github.com/Netflix/fast_jsonapi) may help |
-| | Batch reading/writing to disk and any SQL
+| | Batch reading/writing to disk and any SQL |
### Temporary solutions
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index ed4eea56514..7250406144f 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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'
type: reference, index, howto
---
@@ -87,7 +87,7 @@ Use the toggles to enable or disable features in the project.
| **Container Registry** | | Activates a [registry](../../packages/container_registry/index.md) for your Docker images. |
| **Analytics** | ✓ | Enables [analytics](../../analytics/index.md). |
| **Requirements** | ✓ | Control access to [Requirements Management](../requirements/index.md). |
-| **Security & Compliance** | ✓ | Control access to [security features](../../application_security/index.md). |
+| **Security and Compliance** | ✓ | Control access to [security features](../../application_security/index.md). |
| **Wiki** | ✓ | Enables a separate system for [documentation](../wiki/index.md). |
| **Snippets** | ✓ | Enables [sharing of code and text](../../snippets.md). |
| **Pages** | ✓ | Allows you to [publish static websites](../pages/index.md). |
diff --git a/doc/user/project/settings/project_access_tokens.md b/doc/user/project/settings/project_access_tokens.md
index f9218a228ca..b4d48e52e46 100644
--- a/doc/user/project/settings/project_access_tokens.md
+++ b/doc/user/project/settings/project_access_tokens.md
@@ -48,9 +48,6 @@ You cannot use project access tokens to create other group, project, or personal
Project access tokens inherit the [default prefix setting](../../admin_area/settings/account_and_limit_settings.md#personal-access-token-prefix)
configured for personal access tokens.
-NOTE:
-Project access tokens are not FIPS compliant and creation and use are disabled when [FIPS mode](../../../development/fips_compliance.md) is enabled.
-
## Create a project access token
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89114) in GitLab 15.1, Owners can select Owner role for project access tokens.
@@ -121,12 +118,8 @@ The bot users for projects have [permissions](../../permissions.md#project-membe
selected role and [scope](#scopes-for-a-project-access-token) of the project access token.
- The name is set to the name of the token.
-- The username is set to `project_{project_id}_bot` for the first access token. For example, `project_123_bot`.
-- The email is set to `project{project_id}_bot@noreply.{Gitlab.config.gitlab.host}`. For example, `project123_bot@noreply.example.com`.
-- For additional access tokens in the same project, the username is set to `project_{project_id}_bot{bot_count}`. For
- example, `project_123_bot1`.
-- For additional access tokens in the same project, the email is set to `project{project_id}_bot{bot_count}@noreply.{Gitlab.config.gitlab.host}`.
- For example, `project123_bot1@noreply.example.com`.
+- The username is set to `project_{project_id}_bot_{random_string}`. For example, `project_123_bot_4ffca233d8298ea1`.
+- The email is set to `project_{project_id}_bot_{random_string}@noreply.{Gitlab.config.gitlab.host}`. For example, `project_123_bot_4ffca233d8298ea1@noreply.example.com`.
API calls made with a project access token are associated with the corresponding bot user.
@@ -143,3 +136,7 @@ When the project access token is [revoked](#revoke-a-project-access-token):
- All records are moved to a system-wide user with the username [Ghost User](../../profile/account/delete_account.md#associated-records).
See also [Bot users for groups](../../group/settings/group_access_tokens.md#bot-users-for-groups).
+
+## Token availability
+
+Project access tokens are only available in paid subscriptions, and not available in trial subscriptions. For more information, see the ["What is included" section of the GitLab Trial FAQ](https://about.gitlab.com/free-trial/#what-is-included-in-my-free-trial-what-is-excluded).
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index 5e9f648daba..e2a74f02008 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -22,7 +22,7 @@ and from merge requests:
### When viewing a file or the repository file list
- 1. In the upper right corner of the page, select **Open in Web IDE** if it is visible.
+ 1. In the upper-right corner of the page, select **Open in Web IDE** if it is visible.
1. If **Open in Web IDE** is not visible:
1. Select the (**{chevron-lg-down}**) next to **Edit** or **Gitpod**, depending on your configuration.
1. Select **Open in Web IDE** from the list to display it as the editing option.
@@ -31,7 +31,7 @@ and from merge requests:
### When viewing a merge request
1. Go to your merge request.
- 1. In the upper right corner, select **Code > Open in Web IDE**.
+ 1. In the upper-right corner, select **Code > Open in Web IDE**.
## File finder
diff --git a/doc/user/project/web_ide_beta/index.md b/doc/user/project/web_ide_beta/index.md
index fe110baf578..635b5e12575 100644
--- a/doc/user/project/web_ide_beta/index.md
+++ b/doc/user/project/web_ide_beta/index.md
@@ -40,7 +40,7 @@ or a merge request.
To open the Web IDE Beta from a file or the repository file list:
-- In the upper right of the page, select **Open in Web IDE**.
+- In the upper-right corner of the page, select **Open in Web IDE**.
If **Open in Web IDE** is not visible:
@@ -53,7 +53,7 @@ If **Open in Web IDE** is not visible:
To open the Web IDE Beta from a merge request:
1. Go to your merge request.
-1. In the upper right corner, select **Code > Open in Web IDE**.
+1. In the upper-right corner, select **Code > Open in Web IDE**.
## Open a file in the Web IDE Beta
@@ -64,6 +64,26 @@ To open any file by its name:
![fuzzy_finder_v15_7](img/fuzzy_finder_v15_7.png)
+## Switch branches
+
+The Web IDE Beta uses the currently selected branch by default.
+To switch branches in the Web IDE Beta:
+
+1. On the status bar, in the lower-left corner, select the current branch name.
+1. In the search box, start typing the branch name.
+1. From the dropdown list, select the branch.
+
+## Create a branch
+
+To create a branch from the current branch in the Web IDE Beta:
+
+1. On the status bar, in the lower-left corner, select the current branch name.
+1. From the dropdown list, select **Create new branch...**.
+1. Enter the branch name.
+1. Press <kbd>Enter</kbd>.
+
+If you don't have write access to the repository, **Create new branch...** is not visible.
+
## Search across files
You can use VS Code to quickly search all files in the opened folder.
@@ -84,6 +104,15 @@ Your `CHANGES`, `STAGED CHANGES`, and `MERGE CHANGES` are displayed.
For details, see the [VS Code documentation](https://code.visualstudio.com/docs/sourcecontrol/overview#_commit).
+## Open the command palette
+
+In the Web IDE Beta, you can access many commands through the command palette.
+To open the command palette and run a command in the Web IDE Beta:
+
+1. Press <kbd>F1</kbd> or <kbd>Shift</kbd>+<kbd>Command</kbd>+<kbd>P</kbd>.
+1. In the search box, start typing the command name.
+1. From the dropdown list, select the command.
+
## Stop using the Web IDE Beta
If you do not want to use the Web IDE Beta, you can change your personal preferences.
diff --git a/doc/user/project/wiki/group.md b/doc/user/project/wiki/group.md
index 53aaa41319b..1513ea18ed2 100644
--- a/doc/user/project/wiki/group.md
+++ b/doc/user/project/wiki/group.md
@@ -38,8 +38,8 @@ To access a group wiki:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53247) in GitLab 13.9.
Users with the Owner role in a group can
-[import and export group wikis](../../group/settings/import_export.md) when importing
-or exporting a group.
+[import or export a group wiki](../../group/import/index.md#migrate-groups-by-uploading-an-export-file-deprecated) when they
+import or export a group.
Content created in a group wiki is not deleted when an account is downgraded or a
GitLab trial ends. The group wiki data is exported whenever the group owner of
@@ -48,8 +48,8 @@ the wiki is exported.
To access the group wiki data from the export file if the feature is no longer
available, you have to:
-1. Extract the [export file tarball](../../group/settings/import_export.md) with
- this command, replacing `FILENAME` with your file's name:
+1. Extract the [export file tarball](../../group/import/index.md#migrate-groups-by-uploading-an-export-file-deprecated)
+ with this command, replacing `FILENAME` with your file's name:
`tar -xvzf FILENAME.tar.gz`
1. Browse to the `repositories` directory. This directory contains a
[Git bundle](https://git-scm.com/docs/git-bundle) with the extension `.wiki.bundle`.
diff --git a/doc/user/project/working_with_projects.md b/doc/user/project/working_with_projects.md
index a0e6a78dfe2..24ca86fc93b 100644
--- a/doc/user/project/working_with_projects.md
+++ b/doc/user/project/working_with_projects.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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"
---
@@ -11,12 +11,9 @@ code are saved in projects, and most features are in the scope of projects.
## View projects
-To view projects, on the top bar, select **Main menu > Projects > View all projects**.
+To view all your projects, on the top bar, select **Main menu > Projects > View all projects**.
-NOTE:
-The **Explore projects** tab is visible to unauthenticated users unless the
-[**Public** visibility level](../admin_area/settings/visibility_and_access_controls.md#restrict-visibility-levels)
-is restricted. Then the tab is visible only to authenticated users.
+To browse all public projects, select **Main menu > Explore > Projects**.
### Who can view the Projects page
@@ -63,7 +60,7 @@ 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 top bar, select **Main menu > Projects** and find your project.
-1. In the upper right corner of the page, select **Star**.
+1. In the upper-right corner of the page, select **Star**.
## View starred projects
@@ -241,15 +238,15 @@ Configure Git to either:
- Embed credentials in the request URL:
- ```shell
- git config --global url."https://${user}:${personal_access_token}@gitlab.example.com".insteadOf "https://gitlab.example.com"
- ```
+ ```shell
+ git config --global url."https://${user}:${personal_access_token}@gitlab.example.com".insteadOf "https://gitlab.example.com"
+ ```
- Use SSH instead of HTTPS:
- ```shell
- git config --global url."git@gitlab.example.com:".insteadOf "https://gitlab.example.com/"
- ```
+ ```shell
+ git config --global url."git@gitlab.example.com:".insteadOf "https://gitlab.example.com/"
+ ```
### Disable Go module fetching for private projects
@@ -263,8 +260,8 @@ the [environment variables](../../development/go_guide/dependencies.md#proxies):
To disable fetching:
1. Disable `GOPRIVATE`:
- - To disable queries for one project, disable `GOPRIVATE=gitlab.example.com/my/private/project`.
- - To disable queries for all projects on GitLab.com, disable `GOPRIVATE=gitlab.example.com`.
+ - To disable queries for one project, disable `GOPRIVATE=gitlab.example.com/my/private/project`.
+ - To disable queries for all projects on GitLab.com, disable `GOPRIVATE=gitlab.example.com`.
1. Disable proxy queries in `GONOPROXY`.
1. Disable checksum queries in `GONOSUMDB`.
@@ -291,8 +288,8 @@ To access the Geo secondary server with SSH:
git config --global url."git@gitlab-secondary.example.com".insteadOf "http://gitlab.example.com"
```
- - For `gitlab.example.com`, use the primary site domain name.
- - For `gitlab-secondary.example.com`, use the secondary site domain name.
+ - For `gitlab.example.com`, use the primary site domain name.
+ - For `gitlab-secondary.example.com`, use the secondary site domain name.
1. Ensure the client is set up for SSH access to GitLab repositories. You can test this on the primary,
and GitLab replicates the public key to the secondary.
diff --git a/doc/user/public_access.md b/doc/user/public_access.md
index 2a9a9fb84fe..87380ec324e 100644
--- a/doc/user/public_access.md
+++ b/doc/user/public_access.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
type: reference
---
diff --git a/doc/user/report_abuse.md b/doc/user/report_abuse.md
index aabc9c5dff1..a20a699e550 100644
--- a/doc/user/report_abuse.md
+++ b/doc/user/report_abuse.md
@@ -34,6 +34,8 @@ To report abuse from a user's profile page:
## Report abuse from a user's comment
+> Reporting abuse from comments in epics [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/389992) in GitLab 15.10.
+
To report abuse from a user's comment:
1. In the comment, in the upper-right corner, select **More actions** (**{ellipsis_v}**).
diff --git a/doc/user/reserved_names.md b/doc/user/reserved_names.md
index 372ec141112..6e8a7e7c1cf 100644
--- a/doc/user/reserved_names.md
+++ b/doc/user/reserved_names.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Data Stores
+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
---
diff --git a/doc/user/search/advanced_search.md b/doc/user/search/advanced_search.md
index ed1d3b1d290..1444e5385f9 100644
--- a/doc/user/search/advanced_search.md
+++ b/doc/user/search/advanced_search.md
@@ -5,18 +5,18 @@ info: "To determine the technical writer assigned to the Stage/Group associated
type: reference
---
-# Advanced Search **(PREMIUM)**
+# Advanced search **(PREMIUM)**
> Moved to GitLab Premium in 13.9.
-You can use Advanced Search for faster, more efficient search across the entire GitLab
-instance. Advanced Search is based on Elasticsearch, a purpose-built full-text search
+You can use advanced search for faster, more efficient search across the entire GitLab
+instance. Advanced search is based on Elasticsearch, a purpose-built full-text search
engine you can horizontally scale to get results in up to a second in most cases.
You can find code you want to update in all projects at once to save
maintenance time and promote innersourcing.
-You can use Advanced Search in:
+You can use advanced search in:
- Projects
- Issues
@@ -29,37 +29,22 @@ You can use Advanced Search in:
- Commits
- Project wikis (not [group wikis](../project/wiki/group.md))
-For Advanced Search:
+## Enable advanced search
-- You can only search files smaller than 1 MB.
- For self-managed GitLab instances, an administrator can
- [change this limit](../../integration/advanced_search/elasticsearch.md#advanced-search-configuration).
-- You can't use any of the following characters in the search query:
-
- ```plaintext
- . , : ; / ` ' = ? $ & ^ | ~ < > ( ) { } [ ] @
- ```
-
-- Only the default branch of a project is indexed for code search.
- In a non-default branch, basic search is used.
-- Search results show only the first match in a file,
- but there might be more results in that file.
-
-## Enable Advanced Search
-
-- On GitLab.com, Advanced Search is enabled for groups with paid subscriptions.
+- On GitLab.com, advanced search is enabled for groups with paid subscriptions.
- For self-managed GitLab instances, an administrator must
- [enable Advanced Search](../../integration/advanced_search/elasticsearch.md#enable-advanced-search).
+ [enable advanced search](../../integration/advanced_search/elasticsearch.md#enable-advanced-search).
## Syntax
-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.
+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) |
+| `~` | Fuzzy search | [`J~ Doe`](https://gitlab.com/search?scope=users&search=j%7E+doe) |
| <code>&#124;</code> | Or | [<code>display &#124; banner</code>](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=display+%7C+banner) |
| `+` | And | [`display +banner`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=display+%2Bbanner&snippets=) |
| `-` | Exclude | [`display -banner`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=display+-banner) |
@@ -68,16 +53,23 @@ 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
+
+> [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).
+
### Code search
| Syntax | Description | Example |
|--------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `filename:` | Filename | [`filename:*spec.rb`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=filename%3A*spec.rb&group_id=9970&project_id=278964) |
-| `path:` | Repository location | [`path:spec/workers/`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=path%3Aspec%2Fworkers&snippets=) |
-| `extension:` | File extension without `.` | [`extension:js`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=extension%3Ajs&snippets=) |
-| `blob:` | Git object ID | [`blob:998707*`](https://gitlab.com/search?snippets=false&scope=blobs&repository_ref=&search=blob%3A998707*&group_id=9970) |
+| `path:` | Repository location <sup>1</sup> | [`path:spec/workers/`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=path%3Aspec%2Fworkers&snippets=) |
+| `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) |
-`extension:` and `blob:` return exact matches only.
+1. `path:` returns matches for full paths or subpaths.
+1. `extension:` and `blob:` return exact matches only.
### Examples
@@ -87,5 +79,21 @@ Advanced Search uses [Elasticsearch syntax](https://www.elastic.co/guide/en/elas
| [`RSpec.describe Resolvers -*builder`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=RSpec.describe+Resolvers+-*builder) | Returns `RSpec.describe Resolvers` that does not start with `builder`. |
| [<code>bug &#124; (display +banner)</code>](https://gitlab.com/search?snippets=&scope=issues&repository_ref=&search=bug+%7C+%28display+%2Bbanner%29&group_id=9970&project_id=278964) | Returns `bug` or both `display` and `banner`. |
| [<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
+
+- You can only search files smaller than 1 MB.
+ 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.
+- The search query must not contain any of the following characters:
+
+ ```plaintext
+ . , : ; / ` ' = ? $ & ^ | < > ( ) { } [ ] @
+ ```
+
+- Search results show only the first match in a file.
diff --git a/doc/user/search/exact_code_search.md b/doc/user/search/exact_code_search.md
index 14dca6d4a12..76a298a2cee 100644
--- a/doc/user/search/exact_code_search.md
+++ b/doc/user/search/exact_code_search.md
@@ -20,9 +20,12 @@ When performing any Code search in GitLab it will choose to use "Exact Code
Search" powered by [Zoekt](https://github.com/sourcegraph/zoekt) if the project
is part of an enabled Group.
-The main differences between Zoekt and [Advanced Search](advanced_search.md)
+The main differences between Zoekt and [advanced search](advanced_search.md)
are that Zoekt provides exact substring matching as well as allows you to
search for regular expressions. Since it allows searching for regular
expressions, certain special characters will require escaping. Backslash can
escape special characters and wrapping in double quotes can be used for phrase
searches.
+
+To understand the possible filtering options, see the
+[Zoekt query syntax](https://github.com/sourcegraph/zoekt/blob/main/doc/query_syntax.md).
diff --git a/doc/user/search/global_search/advanced_search_syntax.md b/doc/user/search/global_search/advanced_search_syntax.md
deleted file mode 100644
index c34c5c0c8fc..00000000000
--- a/doc/user/search/global_search/advanced_search_syntax.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../advanced_search.md'
-remove_date: '2023-02-02'
----
-
-This document was moved to [another location](../advanced_search.md).
-
-<!-- This redirect file can be deleted after <2023-02-02>. -->
-<!-- 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/search/index.md b/doc/user/search/index.md
index dc07b4c9215..310d733800a 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -50,7 +50,7 @@ Global search only flags with an error any search that includes more than:
## Perform a search
-To start a search, type your search query in the search bar in the upper right of the screen.
+To start a search, in the upper-right corner of the screen, in the search bar, type your search query.
You must type at least two characters.
![search navbar](img/search_navbar_v15_7.png)
@@ -82,7 +82,16 @@ where the results were found.
1. From the code search result, hover over the line number.
1. On the left, select **View blame**.
- ![code search results](img/code_search_git_blame_v15_1.png)
+![code search results](img/code_search_git_blame_v15_1.png)
+
+### Filter code search results by language
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342651) in GitLab 15.10.
+
+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**.
## Search for projects by full path
diff --git a/doc/user/shortcuts.md b/doc/user/shortcuts.md
index d67c595512a..9c2925ec647 100644
--- a/doc/user/shortcuts.md
+++ b/doc/user/shortcuts.md
@@ -15,7 +15,7 @@ To display a window in GitLab that lists its keyboard shortcuts, use one of the
following methods:
- Press <kbd>?</kbd>.
-- In the Help menu in the upper right of the application, select **Keyboard shortcuts**.
+- In the Help menu, in the upper-right corner of the application, select **Keyboard shortcuts**.
Although [global shortcuts](#global-shortcuts) work from any area of GitLab,
you must be in specific pages for the other shortcuts to be available, as
diff --git a/doc/user/snippets.md b/doc/user/snippets.md
index 0532ed27010..7ca897288e1 100644
--- a/doc/user/snippets.md
+++ b/doc/user/snippets.md
@@ -67,10 +67,10 @@ 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 all snippets visible to you**: On the top bar of your GitLab
- instance, select **Main menu > Snippets** to view your snippets dashboard.
+ instance, select **Main menu > Your work** and then **Snippets** to view your snippets dashboard.
- **Visit [GitLab snippets](https://gitlab.com/dashboard/snippets)** for your snippets on GitLab.com.
- **Explore all public snippets**: On the top bar of your GitLab
- instance, select **Main menu > Snippets** and select **Explore snippets** to view
+ instance, select **Main menu > Explore** and select **Snippets** to view
[all public snippets](https://gitlab.com/explore/snippets).
- **View a project's snippets**: In your project,
go to **Snippets**.
diff --git a/doc/user/ssh.md b/doc/user/ssh.md
index d44e6a0e071..7b6fa66b1d7 100644
--- a/doc/user/ssh.md
+++ b/doc/user/ssh.md
@@ -208,7 +208,7 @@ the following command:
ssh-keygen -o -t rsa -b 4096 -C "<comment>"
```
-## Generate an SSH key pair for a FIDO/U2F hardware security key
+## Generate an SSH key pair for a FIDO2 hardware security key
To generate ED25519_SK or ECDSA_SK SSH keys, you must use OpenSSH 8.2 or later:
@@ -548,7 +548,7 @@ If you receive this error, restart your terminal and try the command again.
### `Key enrollment failed: invalid format` error
-You may receive the following error when [generating an SSH key pair for a FIDO/U2F hardware security key](#generate-an-ssh-key-pair-for-a-fidou2f-hardware-security-key):
+You may receive the following error when [generating an SSH key pair for a FIDO2 hardware security key](#generate-an-ssh-key-pair-for-a-fido2-hardware-security-key):
```shell
Key enrollment failed: invalid format
@@ -557,7 +557,7 @@ Key enrollment failed: invalid format
You can troubleshoot this by trying the following:
- Run the `ssh-keygen` command using `sudo`.
-- Verify your IDO/U2F hardware security key supports
+- Verify your FIDO2 hardware security key supports
the key type provided.
- Verify the version of OpenSSH is 8.2 or greater by
running `ssh -V`.
diff --git a/doc/user/tasks.md b/doc/user/tasks.md
index 0fc4c7571ab..eb0184da929 100644
--- a/doc/user/tasks.md
+++ b/doc/user/tasks.md
@@ -289,3 +289,23 @@ To add a task to an iteration:
The task window opens.
1. Next to **Iteration**, select **Add to iteration**.
1. From the dropdown list, select the iteration to be associated with the task.
+
+## View task system notes
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) in GitLab 15.7 [with a flag](../administration/feature_flags.md) named `work_items_mvc_2`. Disabled by default.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) to feature flag named `work_items_mvc` in GitLab 15.8. Disabled by default.
+> - Changing activity sort order [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) in GitLab 15.8.
+> - Filtering activity [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/389971) in GitLab 15.10.
+> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/334812) in GitLab 15.10.
+
+Prerequisites:
+
+- You must have at least the Reporter role for the project.
+
+You can view all the system notes related to the task. By default they are sorted by **Oldest first**.
+You can always change the sorting order to **Newest first**, which is remembered across sessions.
+You can also filter activity by **Comments only** and **History only** in addition to the default **All activity** which is remembered across sessions.
+
+## Comments and threads
+
+You can add [comments](discussions/index.md) and reply to threads in tasks.
diff --git a/doc/user/todos.md b/doc/user/todos.md
index 50b60dc5b4b..4951ba024af 100644
--- a/doc/user/todos.md
+++ b/doc/user/todos.md
@@ -21,7 +21,7 @@ You can use the To-Do List to track [actions](#actions-that-create-to-do-items)
To access your To-Do List:
-On the top bar, in the upper right, select To-Do List (**{task-done}**).
+On the top bar, in the upper-right corner, select the To-Do List (**{task-done}**).
## Search the To-Do List
@@ -158,7 +158,7 @@ There are two ways to do this:
You can mark all your to-do items as done at the same time.
-In the To-Do List, in the upper right, select **Mark all as done**.
+In the To-Do List, in the upper-right corner, select **Mark all as done**.
## How a user's To-Do List is affected when their access changes
diff --git a/doc/user/workspace/index.md b/doc/user/workspace/index.md
index e4e1edd6346..ca404702d72 100644
--- a/doc/user/workspace/index.md
+++ b/doc/user/workspace/index.md
@@ -1,42 +1,11 @@
---
-stage: Manage
-group: Organization
-info: To 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: '../organization/index.md'
+remove_date: '2023-06-13'
---
-# Organization
+This document was moved to [another location](../organization/index.md).
-DISCLAIMER:
-This page contains information related to upcoming products, features, and functionality.
-It is important to note that the information presented is for informational purposes only.
-Please do not rely on this information for purchasing or planning purposes.
-As with all projects, the items mentioned on this page are subject to change or delay.
-The development, release, and timing of any products, features, or functionality remain at the
-sole discretion of GitLab Inc.
-
-NOTE:
-Organization is in development.
-
-Organization will be above the [top-level namespaces](../namespace/index.md) for you to manage
-everything you do as a GitLab administrator, including:
-
-- Defining and applying settings to all of your groups, subgroups, and projects.
-- Aggregating data from all your groups, subgroups, and projects.
-
-Our goal is to reach feature parity between SaaS and self-managed installations, with all
-[Admin Area settings](/ee/user/admin_area/settings/index.md) moving to either:
-
-- Groups. Available in the Organization, and subgroups.
-- Hardware Controls. For functionality that does not apply to groups, Hardware Controls are only
- applicable to self-managed installations. There is one Hardware Controls section per installation.
-
-For more information about the state of organization development,
-see [epic 9265](https://gitlab.com/groups/gitlab-org/-/epics/9265).
-
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For a video introduction to the new hierarchy concept for groups and projects for epics, see
-[Consolidating groups and projects update (August 2021)](https://www.youtube.com/watch?v=fE74lsG_8yM).
-
-## Related topics
-
-- [Organization developer documentation](../../development/workspace/index.md)
+<!-- This redirect file can be deleted after <2023-06-13>. -->
+<!-- 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/glfm_specification/output_example_snapshots/html.yml b/glfm_specification/output_example_snapshots/html.yml
index cd134f1965c..0b87caf19a9 100644
--- a/glfm_specification/output_example_snapshots/html.yml
+++ b/glfm_specification/output_example_snapshots/html.yml
@@ -8060,7 +8060,7 @@
TODO: Write canonical HTML for this example
static: |-
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" lang="javascript" class="code highlight js-syntax-highlight language-javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>
+ <pre data-sourcepos="1:1-3:3" lang="javascript" class="code highlight js-syntax-highlight language-javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>
<copy-code></copy-code>
</div>
wysiwyg: |-
diff --git a/jest.config.base.js b/jest.config.base.js
index 26e7c8e8d18..0897bc66b30 100644
--- a/jest.config.base.js
+++ b/jest.config.base.js
@@ -1,6 +1,15 @@
const IS_EE = require('./config/helpers/is_ee_env');
const isESLint = require('./config/helpers/is_eslint');
const IS_JH = require('./config/helpers/is_jh_env');
+
+const { VUE_VERSION: EXPLICIT_VUE_VERSION } = process.env;
+if (![undefined, '2', '3'].includes(EXPLICIT_VUE_VERSION)) {
+ throw new Error(
+ `Invalid VUE_VERSION value: ${EXPLICIT_VUE_VERSION}. Only '2' and '3' are supported`,
+ );
+}
+const USE_VUE_3 = EXPLICIT_VUE_VERSION === '3';
+
const { TEST_HOST } = require('./spec/frontend/__helpers__/test_constants');
module.exports = (path, options = {}) => {
@@ -11,6 +20,39 @@ module.exports = (path, options = {}) => {
} = options;
const reporters = ['default'];
+ const VUE_JEST_TRANSFORMER = USE_VUE_3 ? '@vue/vue3-jest' : '@vue/vue2-jest';
+ const setupFilesAfterEnv = [`<rootDir>/${path}/test_setup.js`, 'jest-canvas-mock'];
+ const vueModuleNameMappers = {};
+ const globals = {};
+
+ if (EXPLICIT_VUE_VERSION) {
+ Object.assign(vueModuleNameMappers, {
+ '^@gitlab/ui/dist/([^.]*)$': [
+ '<rootDir>/node_modules/@gitlab/ui/src/$1.vue',
+ '<rootDir>/node_modules/@gitlab/ui/src/$1.js',
+ ],
+ '^@gitlab/ui$': '<rootDir>/node_modules/@gitlab/ui/src/index.js',
+ });
+ }
+
+ if (USE_VUE_3) {
+ setupFilesAfterEnv.unshift(`<rootDir>/${path}/vue_compat_test_setup.js`);
+ Object.assign(vueModuleNameMappers, {
+ '^vue$': '@vue/compat',
+ '^@vue/test-utils$': '@vue/test-utils-vue3',
+ });
+ Object.assign(globals, {
+ 'vue-jest': {
+ experimentalCSSCompile: false,
+ compiler: require.resolve('./config/vue3migration/compiler'),
+ compilerOptions: {
+ compatConfig: {
+ MODE: 2,
+ },
+ },
+ },
+ });
+ }
// To have consistent date time parsing both in local and CI environments we set
// the timezone of the Node process. https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/27738
@@ -69,6 +111,7 @@ module.exports = (path, options = {}) => {
'^jquery$': '<rootDir>/node_modules/jquery/dist/jquery.slim.js',
'^@sentry/browser$': '<rootDir>/app/assets/javascripts/sentry/sentry_browser_wrapper.js',
...extModuleNameMapper,
+ ...vueModuleNameMappers,
};
const collectCoverageFrom = ['<rootDir>/app/assets/javascripts/**/*.{js,vue}'];
@@ -143,6 +186,7 @@ module.exports = (path, options = {}) => {
];
const transformIgnoreNodeModules = [
+ 'vue-test-utils-compat',
'@gitlab/ui',
'@gitlab/favicon-overlay',
'bootstrap-vue',
@@ -163,6 +207,7 @@ module.exports = (path, options = {}) => {
];
return {
+ globals,
clearMocks: true,
testMatch,
moduleFileExtensions: ['js', 'json', 'vue', 'gql', 'graphql', 'yaml', 'yml'],
@@ -176,17 +221,17 @@ module.exports = (path, options = {}) => {
modulePathIgnorePatterns: ['<rootDir>/.yarn-cache/'],
reporters,
resolver: './jest_resolver.js',
- setupFilesAfterEnv: [`<rootDir>/${path}/test_setup.js`, 'jest-canvas-mock'],
+ setupFilesAfterEnv,
restoreMocks: true,
slowTestThreshold: process.env.CI ? 6000 : 500,
transform: {
'^.+\\.(gql|graphql)$': './spec/frontend/__helpers__/graphql_transformer.js',
'^.+_worker\\.js$': './spec/frontend/__helpers__/web_worker_transformer.js',
'^.+\\.js$': 'babel-jest',
- '^.+\\.vue$': '@vue/vue2-jest',
+ '^.+\\.vue$': VUE_JEST_TRANSFORMER,
'spec/frontend/editor/schema/ci/yaml_tests/.+\\.(yml|yaml)$':
'./spec/frontend/__helpers__/yaml_transformer.js',
- '^.+\\.(md|zip|png|yml|yaml)$': './spec/frontend/__helpers__/raw_transformer.js',
+ '^.+\\.(md|zip|png|yml|yaml|sh|ps1)$': './spec/frontend/__helpers__/raw_transformer.js',
},
transformIgnorePatterns: [`node_modules/(?!(${transformIgnoreNodeModules.join('|')}))`],
fakeTimers: {
diff --git a/lefthook.yml b/lefthook.yml
index 39496e0d241..d5c0230f12b 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -86,10 +86,17 @@ pre-push:
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
glob: 'data/removals/*.yml'
run: echo "Changes to removals files detected. Checking removals..\n"; bundle exec rake gitlab:docs:check_removals
+ db-schema-changes:
+ tags: database
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
+ glob: 'db/structure.sql'
+ run: scripts/validate_schema_changes
+
scripts:
"merge_conflicts":
skip: true # This is disabled by default. You can enable this check by adding skip: false in lefhook-local.yml https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md#skip
runner: bash
+
pre-commit:
parallel: true
commands:
@@ -97,3 +104,27 @@ pre-commit:
tags: secrets
files: git diff --name-only --diff-filter=d --staged
run: 'if command -v gitleaks > /dev/null 2>&1; then gitleaks protect --no-banner --staged --redact --verbose; else echo "WARNING: gitleaks is not installed. Please install it. See https://github.com/zricethezav/gitleaks#installing."; fi'
+
+auto-fix:
+ parallel: true
+ commands:
+ frontend:
+ tags: frontend style
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
+ 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
+ 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
+ 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
+ glob: '*.{rb,rake}'
+ run: REVEAL_RUBOCOP_TODO=0 bundle exec rubocop --parallel --autocorrect --force-exclusion {files}
diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index 38a9856ca58..249301f308c 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -8,7 +8,7 @@ module API
helpers ::API::Helpers::MembersHelpers
- feature_category :authentication_and_authorization
+ feature_category :system_access
%w[group project].each do |source_type|
params do
diff --git a/lib/api/admin/ci/variables.rb b/lib/api/admin/ci/variables.rb
index bc351e27f99..58b9a0f9ed9 100644
--- a/lib/api/admin/ci/variables.rb
+++ b/lib/api/admin/ci/variables.rb
@@ -8,7 +8,7 @@ module API
before { authenticated_as_admin! }
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
namespace 'admin' do
namespace 'ci' do
diff --git a/lib/api/applications.rb b/lib/api/applications.rb
index 6fc9408a570..39f1638301b 100644
--- a/lib/api/applications.rb
+++ b/lib/api/applications.rb
@@ -5,7 +5,7 @@ module API
class Applications < ::API::Base
before { authenticated_as_admin! }
- feature_category :authentication_and_authorization
+ feature_category :system_access
resource :applications do
desc 'Create a new application' do
diff --git a/lib/api/ci/helpers/runner.rb b/lib/api/ci/helpers/runner.rb
index 96f5265ce23..738c5bb3789 100644
--- a/lib/api/ci/helpers/runner.rb
+++ b/lib/api/ci/helpers/runner.rb
@@ -12,13 +12,13 @@ module API
JOB_TOKEN_PARAM = :token
LEGACY_SYSTEM_XID = '<legacy>'
- def authenticate_runner!
+ def authenticate_runner!(update_contacted_at: true)
track_runner_authentication
forbidden! unless current_runner
runner_details = get_runner_details_from_request
- current_runner.heartbeat(runner_details)
- current_runner_machine&.heartbeat(runner_details)
+ current_runner.heartbeat(runner_details, update_contacted_at: update_contacted_at)
+ current_runner_machine&.heartbeat(runner_details, update_contacted_at: update_contacted_at)
end
def get_runner_details_from_request
@@ -96,7 +96,7 @@ module API
# the heartbeat should be triggered.
if heartbeat_runner
job.runner&.heartbeat(get_runner_ip)
- job.runner_machine&.heartbeat(get_runner_ip)
+ job.runner_machine&.heartbeat(get_runner_ip) if Feature.enabled?(:runner_machine_heartbeat)
end
job
diff --git a/lib/api/ci/pipeline_schedules.rb b/lib/api/ci/pipeline_schedules.rb
index afb3754f2ae..e27ec24fb44 100644
--- a/lib/api/ci/pipeline_schedules.rb
+++ b/lib/api/ci/pipeline_schedules.rb
@@ -141,9 +141,12 @@ module API
requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
end
post ':id/pipeline_schedules/:pipeline_schedule_id/take_ownership' do
- authorize! :take_ownership_pipeline_schedule, pipeline_schedule
+ authorize! :admin_pipeline_schedule, pipeline_schedule
- if pipeline_schedule.own!(current_user)
+ if pipeline_schedule.owned_by?(current_user)
+ status(:ok) # Set response code to 200 if schedule is already owned by current user
+ present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails
+ elsif pipeline_schedule.own!(current_user)
present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails
else
render_validation_error!(pipeline_schedule)
diff --git a/lib/api/ci/pipelines.rb b/lib/api/ci/pipelines.rb
index c055512e54e..419d7afd3ca 100644
--- a/lib/api/ci/pipelines.rb
+++ b/lib/api/ci/pipelines.rb
@@ -199,7 +199,7 @@ module API
use :pagination
end
- get ':id/pipelines/:pipeline_id/bridges', urgency: :low, feature_category: :pipeline_authoring do
+ get ':id/pipelines/:pipeline_id/bridges', urgency: :low, feature_category: :pipeline_composition do
authorize!(:read_build, user_project)
pipeline = user_project.all_pipelines.find(params[:pipeline_id])
@@ -225,7 +225,7 @@ module API
params do
requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
- get ':id/pipelines/:pipeline_id/variables', feature_category: :pipeline_authoring, urgency: :low do
+ get ':id/pipelines/:pipeline_id/variables', feature_category: :pipeline_composition, urgency: :low do
authorize! :read_pipeline_variable, pipeline
present pipeline.variables, with: Entities::Ci::Variable
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index 1c81db39bb1..0e67fb762a9 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -85,7 +85,11 @@ module API
optional :system_id, type: String, desc: %q(The runner's system identifier)
end
post '/verify', urgency: :low, feature_category: :runner do
- authenticate_runner!
+ # For runners that were created in the UI, we want to update the contacted_at value
+ # only when it starts polling for jobs
+ registering_created_runner = params[:token].start_with?(::Ci::Runner::CREATED_RUNNER_TOKEN_PREFIX)
+
+ authenticate_runner!(update_contacted_at: !registering_created_runner)
status 200
present current_runner, with: Entities::Ci::RunnerRegistrationDetails
diff --git a/lib/api/ci/variables.rb b/lib/api/ci/variables.rb
index 5a6b5987228..2184fc873c1 100644
--- a/lib/api/ci/variables.rb
+++ b/lib/api/ci/variables.rb
@@ -8,7 +8,7 @@ module API
before { authenticate! }
before { authorize! :admin_build, user_project }
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
helpers ::API::Helpers::VariablesHelpers
diff --git a/lib/api/clusters/agent_tokens.rb b/lib/api/clusters/agent_tokens.rb
index 68eef21903d..f0eb7ce2cd6 100644
--- a/lib/api/clusters/agent_tokens.rb
+++ b/lib/api/clusters/agent_tokens.rb
@@ -65,7 +65,9 @@ module API
agent = ::Clusters::AgentsFinder.new(user_project, current_user).find(params[:agent_id])
result = ::Clusters::AgentTokens::CreateService.new(
- container: agent.project, current_user: current_user, params: token_params.merge(agent_id: agent.id)
+ agent: agent,
+ current_user: current_user,
+ params: token_params
).execute
bad_request!(result[:message]) if result[:status] == :error
@@ -86,8 +88,9 @@ module API
agent = ::Clusters::AgentsFinder.new(user_project, current_user).find(params[:agent_id])
token = ::Clusters::AgentTokensFinder.new(agent, current_user).find(params[:token_id])
- # Skipping explicit error handling and relying on exceptions
- token.revoked!
+ result = ::Clusters::AgentTokens::RevokeService.new(token: token, current_user: current_user).execute
+
+ bad_request!(result[:message]) if result[:status] == :error
status :no_content
end
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index fa99a1a2bc8..f884dde3552 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -20,6 +20,8 @@ module API
end
def authorize_push_to_branch!(branch)
+ authenticate!
+
unless user_access.can_push_to_branch?(branch)
forbidden!("You are not allowed to push into this branch")
end
@@ -76,6 +78,10 @@ module API
type: String,
desc: 'The file path',
documentation: { example: 'README.md' }
+ optional :author,
+ type: String,
+ desc: 'Search commits by commit author',
+ documentation: { example: 'John Smith' }
optional :all, type: Boolean, desc: 'Every commit will be returned'
optional :with_stats, type: Boolean, desc: 'Stats about each commit will be added to the response'
optional :first_parent, type: Boolean, desc: 'Only include the first parent of merges'
@@ -99,6 +105,7 @@ module API
with_stats = params[:with_stats]
first_parent = params[:first_parent]
order = params[:order]
+ author = params[:author]
commits = user_project.repository.commits(ref,
path: path,
@@ -109,6 +116,7 @@ module API
all: all,
first_parent: first_parent,
order: order,
+ author: author,
trailers: params[:trailers])
serializer = with_stats ? Entities::CommitWithStats : Entities::Commit
@@ -127,6 +135,8 @@ module API
tags %w[commits]
failure [
{ code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
detail 'This feature was introduced in GitLab 8.13'
diff --git a/lib/api/composer_packages.rb b/lib/api/composer_packages.rb
index 3819e6d236d..56fa10dd7d4 100644
--- a/lib/api/composer_packages.rb
+++ b/lib/api/composer_packages.rb
@@ -179,7 +179,7 @@ module API
.new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job))
.execute
- track_package_event('push_package', :composer, project: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace)
+ track_package_event('push_package', :composer, project: authorized_user_project, namespace: authorized_user_project.namespace)
created!
end
diff --git a/lib/api/concerns/packages/conan_endpoints.rb b/lib/api/concerns/packages/conan_endpoints.rb
index e65e8f8710c..82c97474b30 100644
--- a/lib/api/concerns/packages/conan_endpoints.rb
+++ b/lib/api/concerns/packages/conan_endpoints.rb
@@ -350,7 +350,7 @@ module API
delete urgency: :low do
authorize!(:destroy_package, project)
- track_package_event('delete_package', :conan, category: 'API::ConanPackages', user: current_user, project: project, namespace: project.namespace)
+ track_package_event('delete_package', :conan, category: 'API::ConanPackages', project: project, namespace: project.namespace)
package.destroy
end
diff --git a/lib/api/concerns/packages/debian_package_endpoints.rb b/lib/api/concerns/packages/debian_package_endpoints.rb
index db31f2e35f1..7969a49909a 100644
--- a/lib/api/concerns/packages/debian_package_endpoints.rb
+++ b/lib/api/concerns/packages/debian_package_endpoints.rb
@@ -58,9 +58,19 @@ module API
.with_compression_type(nil)
.order_created_asc
+ # Empty component files are not persisted in DB
+ no_content! if params[:file_sha256] == ::Packages::Debian::EMPTY_FILE_SHA256
+
relation = relation.with_file_sha256(params[:file_sha256]) if params[:file_sha256]
- present_carrierwave_file!(relation.last!.file)
+ component_file = relation.last
+
+ if component_file.nil? || component_file.empty?
+ not_found! if params[:file_sha256] # asking for a non existing component file.
+ no_content! # empty component files are not always persisted in DB
+ end
+
+ present_carrierwave_file!(component_file.file)
end
end
@@ -156,7 +166,10 @@ module API
# https://wiki.debian.org/DebianRepository/Format#A.22Packages.22_Indices
desc 'The installer (udeb) binary files index' do
detail 'This feature was introduced in GitLab 15.4'
- success code: 200
+ success [
+ { code: 200 },
+ { code: 202 }
+ ]
failure [
{ code: 400, message: 'Bad Request' },
{ code: 401, message: 'Unauthorized' },
@@ -175,7 +188,10 @@ module API
# https://wiki.debian.org/DebianRepository/Format?action=show&redirect=RepositoryFormat#indices_acquisition_via_hashsums_.28by-hash.29
desc 'The installer (udeb) binary files index by hash' do
detail 'This feature was introduced in GitLab 15.4'
- success code: 200
+ success [
+ { code: 200 },
+ { code: 202 }
+ ]
failure [
{ code: 400, message: 'Bad Request' },
{ code: 401, message: 'Unauthorized' },
@@ -196,7 +212,10 @@ module API
# https://wiki.debian.org/DebianRepository/Format#A.22Sources.22_Indices
desc 'The source files index' do
detail 'This feature was introduced in GitLab 15.4'
- success code: 200
+ success [
+ { code: 200 },
+ { code: 202 }
+ ]
failure [
{ code: 400, message: 'Bad Request' },
{ code: 401, message: 'Unauthorized' },
@@ -215,7 +234,10 @@ module API
# https://wiki.debian.org/DebianRepository/Format?action=show&redirect=RepositoryFormat#indices_acquisition_via_hashsums_.28by-hash.29
desc 'The source files index by hash' do
detail 'This feature was introduced in GitLab 15.4'
- success code: 200
+ success [
+ { code: 200 },
+ { code: 202 }
+ ]
failure [
{ code: 400, message: 'Bad Request' },
{ code: 401, message: 'Unauthorized' },
@@ -240,7 +262,10 @@ module API
# https://wiki.debian.org/DebianRepository/Format#A.22Packages.22_Indices
desc 'The binary files index' do
detail 'This feature was introduced in GitLab 13.5'
- success code: 200
+ success [
+ { code: 200 },
+ { code: 202 }
+ ]
failure [
{ code: 400, message: 'Bad Request' },
{ code: 401, message: 'Unauthorized' },
@@ -259,7 +284,10 @@ module API
# https://wiki.debian.org/DebianRepository/Format?action=show&redirect=RepositoryFormat#indices_acquisition_via_hashsums_.28by-hash.29
desc 'The binary files index by hash' do
detail 'This feature was introduced in GitLab 15.4'
- success code: 200
+ success [
+ { code: 200 },
+ { code: 202 }
+ ]
failure [
{ code: 400, message: 'Bad Request' },
{ code: 401, message: 'Unauthorized' },
diff --git a/lib/api/concerns/packages/npm_endpoints.rb b/lib/api/concerns/packages/npm_endpoints.rb
index f26b3a1d8c2..703a655ddce 100644
--- a/lib/api/concerns/packages/npm_endpoints.rb
+++ b/lib/api/concerns/packages/npm_endpoints.rb
@@ -60,6 +60,7 @@ module API
]
tags %w[npm_packages]
end
+ route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
get 'dist-tags', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do
package_name = params[:package_name]
@@ -91,6 +92,7 @@ module API
]
tags %w[npm_packages]
end
+ route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
put format: false do
package_name = params[:package_name]
version = env['api.request.body']
@@ -122,6 +124,7 @@ module API
]
tags %w[npm_packages]
end
+ route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
delete format: false do
package_name = params[:package_name]
tag = params[:tag]
@@ -163,8 +166,13 @@ 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 = ::Packages::Npm::PackageFinder.new(package_name, project: project_or_nil)
- .execute
+ packages =
+ if Feature.enabled?(:npm_allow_packages_in_multiple_projects)
+ finder_for_endpoint_scope(package_name).execute
+ else
+ ::Packages::Npm::PackageFinder.new(package_name, project: project_or_nil)
+ .execute
+ end
redirect_request = project_or_nil.blank? || packages.empty?
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index 21c0c219046..5324e4158bf 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -82,7 +82,7 @@ module API
optional :distribution, type: String, desc: 'The Debian Codename or Suite', regexp: Gitlab::Regex.debian_distribution_regex
given :distribution do
requires :component, type: String, desc: 'The Debian Component', regexp: Gitlab::Regex.debian_component_regex
- requires :file_name, type: String, desc: 'The filename', regexp: { value: Gitlab::Regex.debian_direct_upload_filename_regex, message: 'Only debs and udebs can be directly added to a distribution' }
+ requires :file_name, type: String, desc: 'The filename', regexp: { value: Gitlab::Regex.debian_direct_upload_filename_regex, message: 'Only debs, udebs and ddebs can be directly added to a distribution' }
end
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
@@ -132,7 +132,7 @@ module API
optional :distribution, type: String, desc: 'The Debian Codename or Suite', regexp: Gitlab::Regex.debian_distribution_regex
given :distribution do
requires :component, type: String, desc: 'The Debian Component', regexp: Gitlab::Regex.debian_component_regex
- requires :file_name, type: String, desc: 'The filename', regexp: { value: Gitlab::Regex.debian_direct_upload_filename_regex, message: 'Only debs and udebs can be directly added to a distribution' }
+ requires :file_name, type: String, desc: 'The filename', regexp: { value: Gitlab::Regex.debian_direct_upload_filename_regex, message: 'Only debs, udebs and ddebs can be directly added to a distribution' }
end
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
diff --git a/lib/api/draft_notes.rb b/lib/api/draft_notes.rb
index 842180652c4..217cd4ae325 100644
--- a/lib/api/draft_notes.rb
+++ b/lib/api/draft_notes.rb
@@ -30,6 +30,22 @@ module API
.new(merge_request(params: params), current_user)
.execute(get_draft_note(params: params))
end
+
+ def authorize_create_note!(params:)
+ access_denied! unless can?(current_user, :create_note, merge_request(params: params))
+ end
+
+ def authorize_admin_draft!(draft_note)
+ access_denied! unless can?(current_user, :admin_note, draft_note)
+ end
+
+ def draft_note_params
+ {
+ note: params[:note],
+ commit_id: params[:commit_id] == 'undefined' ? nil : params[:commit_id],
+ resolve_discussion: params[:resolve_discussion] || false
+ }
+ end
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -71,6 +87,64 @@ module API
end
end
+ desc "Create a new draft note" do
+ success Entities::DraftNote
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ end
+ params do
+ requires :id, type: String, desc: "The ID of a project."
+ requires :merge_request_iid, type: Integer, desc: "The ID of a merge request."
+ requires :note, type: String, desc: 'The content of a note.'
+ optional :in_reply_to_discussion_id, type: Integer, desc: 'The ID of a discussion the draft note replies to.'
+ optional :commit_id, type: String, desc: 'The sha of a commit to associate the draft note to.'
+ optional :resolve_discussion, type: Boolean, desc: 'The associated discussion should be resolved.'
+ end
+ post ":id/merge_requests/:merge_request_iid/draft_notes", feature_category: :code_review_workflow do
+ authorize_create_note!(params: params)
+
+ create_params = draft_note_params.merge(in_reply_to_discussion_id: params[:in_reply_to_discussion_id])
+ create_service = ::DraftNotes::CreateService.new(merge_request(params: params), current_user, create_params)
+
+ draft_note = create_service.execute
+
+ if draft_note.persisted?
+ present draft_note, with: Entities::DraftNote
+ else
+ render_validation_error!(draft_note)
+ end
+ end
+
+ desc "Modify an existing draft note" do
+ success Entities::DraftNote
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ end
+ params do
+ requires :id, type: String, desc: "The ID of a project."
+ requires :merge_request_iid, type: Integer, desc: "The ID of a merge request."
+ requires :draft_note_id, type: Integer, desc: "The ID of a draft note"
+ optional :note, type: String, allow_blank: false, desc: 'The content of a note.'
+ end
+ put ":id/merge_requests/:merge_request_iid/draft_notes/:draft_note_id", feature_category: :code_review_workflow do
+ bad_request!('Missing params to modify') unless params[:note].present?
+
+ draft_note = get_draft_note(params: params)
+
+ if draft_note
+ authorize_admin_draft!(draft_note)
+
+ draft_note.update!(note: params[:note])
+ present draft_note, with: Entities::DraftNote
+ else
+ not_found!("Draft Note")
+ end
+ end
+
desc "Delete a draft note" do
success Entities::DraftNote
failure [
diff --git a/lib/api/entities/application_with_secret.rb b/lib/api/entities/application_with_secret.rb
index 1d0acee8624..5679ab4253d 100644
--- a/lib/api/entities/application_with_secret.rb
+++ b/lib/api/entities/application_with_secret.rb
@@ -4,8 +4,12 @@ module API
module Entities
# Use with care, this exposes the secret
class ApplicationWithSecret < Entities::Application
- expose :secret, documentation: { type: 'string',
- example: 'ee1dd64b6adc89cf7e2c23099301ccc2c61b441064e9324d963c46902a85ec34' }
+ expose :secret, documentation: {
+ type: 'string',
+ example: 'ee1dd64b6adc89cf7e2c23099301ccc2c61b441064e9324d963c46902a85ec34'
+ } do |application, _options|
+ application.plaintext_secret
+ end
end
end
end
diff --git a/lib/api/entities/ci/job_request/response.rb b/lib/api/entities/ci/job_request/response.rb
index cfdbeed79b6..e07bba1e850 100644
--- a/lib/api/entities/ci/job_request/response.rb
+++ b/lib/api/entities/ci/job_request/response.rb
@@ -23,9 +23,7 @@ module API
expose :runner_variables, as: :variables
expose :steps, using: Entities::Ci::JobRequest::Step
- expose :runtime_hooks, as: :hooks,
- using: Entities::Ci::JobRequest::Hook,
- if: ->(job) { ::Feature.enabled?(:ci_hooks_pre_get_sources_script, job.project) }
+ expose :runtime_hooks, as: :hooks, using: Entities::Ci::JobRequest::Hook
expose :image, using: Entities::Ci::JobRequest::Image
expose :services, using: Entities::Ci::JobRequest::Service
expose :artifacts, using: Entities::Ci::JobRequest::Artifacts
diff --git a/lib/api/entities/internal/pages/lookup_path.rb b/lib/api/entities/internal/pages/lookup_path.rb
index 1bf94f74fb4..1ea41e129b2 100644
--- a/lib/api/entities/internal/pages/lookup_path.rb
+++ b/lib/api/entities/internal/pages/lookup_path.rb
@@ -5,8 +5,12 @@ module API
module Internal
module Pages
class LookupPath < Grape::Entity
- expose :project_id, :access_control,
- :source, :https_only, :prefix
+ expose :access_control,
+ :https_only,
+ :prefix,
+ :project_id,
+ :source,
+ :unique_domain
end
end
end
diff --git a/lib/api/entities/note.rb b/lib/api/entities/note.rb
index a92f534bbdc..cac4a8280e3 100644
--- a/lib/api/entities/note.rb
+++ b/lib/api/entities/note.rb
@@ -14,6 +14,7 @@ module API
expose :created_at, :updated_at
expose :system?, as: :system
expose :noteable_id, :noteable_type
+ expose :project_id
expose :commit_id, if: ->(note, options) { note.noteable_type == "MergeRequest" && note.is_a?(DiffNote) }
expose :position, if: ->(note, options) { note.is_a?(DiffNote) } do |note|
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index fcb7ddb9567..7f4a0359e03 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -155,7 +155,7 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def self.preload_resource(project)
- ActiveRecord::Associations::Preloader.new.preload(project, project_group_links: { group: :route })
+ ActiveRecord::Associations::Preloader.new(records: [project], associations: { project_group_links: { group: :route } }).call
end
def self.preload_relation(projects_relation, options = {})
diff --git a/lib/api/error_tracking/project_settings.rb b/lib/api/error_tracking/project_settings.rb
index ec1d6a8b87f..99af8494723 100644
--- a/lib/api/error_tracking/project_settings.rb
+++ b/lib/api/error_tracking/project_settings.rb
@@ -23,8 +23,6 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
authorize! :admin_operations, user_project
-
- not_found!('Error Tracking Setting') unless project_setting
end
desc 'Get Error Tracking settings' do
@@ -34,6 +32,7 @@ module API
end
get ':id/error_tracking/settings' do
+ not_found!('Error Tracking Setting') unless project_setting
present project_setting, with: Entities::ErrorTracking::ProjectSetting
end
@@ -59,6 +58,7 @@ module API
end
patch ':id/error_tracking/settings/' do
+ not_found!('Error Tracking Setting') unless project_setting
update_params = {
error_tracking_setting_attributes: { enabled: params[:active] }
}
@@ -75,6 +75,42 @@ module API
result
end
end
+
+ desc 'Update Error Tracking project settings. Available in GitLab 15.10 and later.' do
+ detail 'Update Error Tracking settings for a project. ' \
+ 'Only for users with Maintainer role for the project.'
+ success Entities::ErrorTracking::ProjectSetting
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ERROR_TRACKING_PROJECT_SETTINGS_TAGS
+ end
+ params do
+ requires :active, type: Boolean,
+ desc: 'Pass true to enable the configured Error Tracking settings or false to disable it.',
+ allow_blank: false
+ requires :integrated,
+ type: Boolean,
+ desc: 'Pass true to enable the integrated Error Tracking backend.'
+ end
+
+ put ':id/error_tracking/settings' do
+ not_found! unless Feature.enabled?(:integrated_error_tracking, user_project)
+ update_params = {
+ error_tracking_setting_attributes: { enabled: params[:active] }
+ }
+
+ update_params[:error_tracking_setting_attributes][:integrated] = params[:integrated]
+
+ result = ::Projects::Operations::UpdateService.new(user_project, current_user, update_params).execute
+ if result[:status] == :success
+ present project_setting, with: Entities::ErrorTracking::ProjectSetting
+ else
+ result
+ end
+ end
end
end
end
diff --git a/lib/api/files.rb b/lib/api/files.rb
index 18638abd184..1850413caa6 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -49,13 +49,21 @@ module API
end
def content_sha
- Rails.cache.fetch("blob_content_sha256:#{user_project.full_path}:#{@blob.id}") do
+ cache_client.fetch("blob_content_sha256:#{user_project.full_path}:#{@blob.id}") do
@blob.load_all_data!
Digest::SHA256.hexdigest(@blob.data)
end
end
+ def cache_client
+ Gitlab::Cache::Client.build_with_metadata(
+ cache_identifier: 'API::Files#content_sha',
+ feature_category: :source_code_management,
+ backing_resource: :gitaly
+ )
+ end
+
def fetch_blame_range(blame_params)
return if blame_params[:range].blank?
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index da5b0930543..95852848f3a 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -84,7 +84,7 @@ module API
authorize_upload!(project)
bad_request!('File is too large') if max_file_size_exceeded?
- track_package_event('push_package', :generic, project: project, user: current_user, namespace: project.namespace)
+ track_package_event('push_package', :generic, project: project, namespace: project.namespace)
create_package_file_params = declared_params.merge(build: current_authenticated_job)
package_file = ::Packages::Generic::CreatePackageFileService
@@ -131,7 +131,7 @@ module API
package = ::Packages::Generic::PackageFinder.new(project).execute!(params[:package_name], params[:package_version])
package_file = ::Packages::PackageFileFinder.new(package, params[:file_name]).execute!
- track_package_event('pull_package', :generic, project: project, user: current_user, namespace: project.namespace)
+ track_package_event('pull_package', :generic, project: project, namespace: project.namespace)
present_package_file!(package_file)
end
diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb
index 753f0db10c1..5173a55308d 100644
--- a/lib/api/group_container_repositories.rb
+++ b/lib/api/group_container_repositories.rb
@@ -38,7 +38,7 @@ module API
user: current_user, subject: user_group
).execute
- track_package_event('list_repositories', :container, user: current_user, namespace: user_group)
+ track_package_event('list_repositories', :container, namespace: user_group)
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: false, tags_count: false
end
diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb
index a42f9045b9d..1fe4f8dc7c0 100644
--- a/lib/api/group_variables.rb
+++ b/lib/api/group_variables.rb
@@ -6,7 +6,7 @@ module API
before { authenticate! }
before { authorize! :admin_group, user_group }
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
helpers ::API::Helpers::VariablesHelpers
diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb
index 31328facd69..c85871d4b8c 100644
--- a/lib/api/helpers/integrations_helpers.rb
+++ b/lib/api/helpers/integrations_helpers.rb
@@ -191,6 +191,12 @@ module API
name: :app_store_private_key,
type: String,
desc: 'The Apple App Store Connect Private Key'
+ },
+ {
+ required: true,
+ name: :app_store_private_key_file_name,
+ type: String,
+ desc: 'The Apple App Store Connect Private Key File Name'
}
],
'asana' => [
@@ -447,6 +453,20 @@ module API
desc: 'The URL of the external wiki'
}
],
+ 'google-play' => [
+ {
+ required: true,
+ name: :service_account_key,
+ type: String,
+ desc: 'The Google Play Service Account Key'
+ },
+ {
+ required: true,
+ name: :service_account_key_file_name,
+ type: String,
+ desc: 'The Google Play Service Account Key File Name'
+ }
+ ],
'hangouts-chat' => [
{
required: true,
@@ -897,6 +917,20 @@ module API
type: String,
desc: 'The product ID of ZenTao project'
}
+ ],
+ 'squash-tm' => [
+ {
+ required: true,
+ name: :url,
+ type: String,
+ desc: 'The Squash TM webhook URL'
+ },
+ {
+ required: false,
+ name: :token,
+ type: String,
+ desc: 'The secret token'
+ }
]
}
end
@@ -918,6 +952,7 @@ module API
::Integrations::EmailsOnPush,
::Integrations::Ewm,
::Integrations::ExternalWiki,
+ ::Integrations::GooglePlay,
::Integrations::HangoutsChat,
::Integrations::Harbor,
::Integrations::Irker,
@@ -934,6 +969,7 @@ module API
::Integrations::Redmine,
::Integrations::Slack,
::Integrations::SlackSlashCommands,
+ ::Integrations::SquashTm,
::Integrations::Teamcity,
::Integrations::Youtrack,
::Integrations::Zentao
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index 816b8deb461..0a6b288e3f8 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -57,6 +57,7 @@ module API
def log_user_activity(actor)
commands = Gitlab::GitAccess::DOWNLOAD_COMMANDS
+ commands += Gitlab::GitAccess::PUSH_COMMANDS if Feature.enabled?(:log_user_git_push_activity)
return unless commands.include?(params[:action])
diff --git a/lib/api/helpers/packages/conan/api_helpers.rb b/lib/api/helpers/packages/conan/api_helpers.rb
index 3ea558f3569..b47bfbfb5aa 100644
--- a/lib/api/helpers/packages/conan/api_helpers.rb
+++ b/lib/api/helpers/packages/conan/api_helpers.rb
@@ -171,7 +171,7 @@ module API
conan_package_reference: params[:conan_package_reference]
).execute!
- track_package_event('pull_package', :conan, category: 'API::ConanPackages', user: current_user, project: project, namespace: project.namespace) if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY
+ track_package_event('pull_package', :conan, category: 'API::ConanPackages', project: project, namespace: project.namespace) if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY
present_package_file!(package_file)
end
@@ -186,7 +186,7 @@ module API
def track_push_package_event
if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY && params[:file].size > 0 # rubocop: disable Style/ZeroLengthPredicate
- track_package_event('push_package', :conan, category: 'API::ConanPackages', user: current_user, project: project, namespace: project.namespace)
+ track_package_event('push_package', :conan, category: 'API::ConanPackages', project: project, namespace: project.namespace)
end
end
diff --git a/lib/api/helpers/packages/dependency_proxy_helpers.rb b/lib/api/helpers/packages/dependency_proxy_helpers.rb
index 4b0e63c8f3b..a8e5560e106 100644
--- a/lib/api/helpers/packages/dependency_proxy_helpers.rb
+++ b/lib/api/helpers/packages/dependency_proxy_helpers.rb
@@ -28,7 +28,7 @@ module API
end
def registry_url(package_type, options)
- base_url = REGISTRY_BASE_URLS[package_type]
+ base_url = registry_base_url(package_type)
raise ArgumentError, "Can't build registry_url for package_type #{package_type}" unless base_url
@@ -66,7 +66,14 @@ module API
Feature.enabled?(:maven_central_request_forwarding, target.root_ancestor)
end
+
+ # Override in JiHu repo
+ def registry_base_url(package_type)
+ REGISTRY_BASE_URLS[package_type]
+ end
end
end
end
end
+
+API::Helpers::Packages::DependencyProxyHelpers.prepend_mod
diff --git a/lib/api/helpers/packages/npm.rb b/lib/api/helpers/packages/npm.rb
index 352d77f472c..4eb6c39b7dc 100644
--- a/lib/api/helpers/packages/npm.rb
+++ b/lib/api/helpers/packages/npm.rb
@@ -33,6 +33,15 @@ module API
end
end
+ def finder_for_endpoint_scope(package_name)
+ case endpoint_scope
+ when :project
+ ::Packages::Npm::PackageFinder.new(package_name, project: project_or_nil)
+ when :instance
+ ::Packages::Npm::PackageFinder.new(package_name, namespace: top_namespace_from(package_name))
+ end
+ end
+
def project_or_nil
# mainly used by the metadata endpoint where we need to get a project
# and return nil if not found (no errors should be raised)
@@ -50,11 +59,17 @@ module API
params[:id]
when :instance
package_name = params[:package_name]
- namespace_path = ::Packages::Npm.scope_of(package_name)
- next unless namespace_path
- namespace = Namespace.top_most
- .by_path(namespace_path)
+ namespace =
+ if Feature.enabled?(:npm_allow_packages_in_multiple_projects)
+ top_namespace_from(package_name)
+ else
+ namespace_path = ::Packages::Npm.scope_of(package_name)
+ next unless namespace_path
+
+ Namespace.top_most.by_path(namespace_path)
+ end
+
next unless namespace
finder = ::Packages::Npm::PackageFinder.new(
@@ -67,6 +82,15 @@ module API
end
end
end
+
+ private
+
+ def top_namespace_from(package_name)
+ namespace_path = ::Packages::Npm.scope_of(package_name)
+ return unless namespace_path
+
+ Namespace.top_most.by_path(namespace_path)
+ end
end
end
end
diff --git a/lib/api/helpers/packages_helpers.rb b/lib/api/helpers/packages_helpers.rb
index 0fb3a19b8fd..23b1849c4fc 100644
--- a/lib/api/helpers/packages_helpers.rb
+++ b/lib/api/helpers/packages_helpers.rb
@@ -90,6 +90,7 @@ module API
service.execute
category = args.delete(:category) || self.options[:for].name
+ args[:user] = current_user if current_user
event_name = "i_package_#{scope}_user"
::Gitlab::Tracking.event(
category,
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
index 3f6e052f7b6..2a5ff257718 100644
--- a/lib/api/internal/base.rb
+++ b/lib/api/internal/base.rb
@@ -195,7 +195,7 @@ module API
#
# Discover user by ssh key, user id or username
#
- get '/discover', feature_category: :authentication_and_authorization do
+ get '/discover', feature_category: :system_access do
present actor.user, with: Entities::UserSafe
end
@@ -208,7 +208,7 @@ module API
}
end
- post '/two_factor_recovery_codes', feature_category: :authentication_and_authorization do
+ post '/two_factor_recovery_codes', feature_category: :system_access do
status 200
actor.update_last_used_at!
@@ -237,7 +237,7 @@ module API
{ success: true, recovery_codes: codes }
end
- post '/personal_access_token', feature_category: :authentication_and_authorization do
+ post '/personal_access_token', feature_category: :system_access do
status 200
actor.update_last_used_at!
@@ -308,7 +308,7 @@ module API
# decided to pursue a different approach, so it's currently not used.
# We might revive the PAM module though as it provides better user
# flow.
- post '/two_factor_config', feature_category: :authentication_and_authorization do
+ post '/two_factor_config', feature_category: :system_access do
status 200
break { success: false } unless Feature.enabled?(:two_factor_for_cli)
@@ -330,13 +330,13 @@ module API
end
end
- post '/two_factor_push_otp_check', feature_category: :authentication_and_authorization do
+ post '/two_factor_push_otp_check', feature_category: :system_access do
status 200
two_factor_push_otp_check
end
- post '/two_factor_manual_otp_check', feature_category: :authentication_and_authorization do
+ post '/two_factor_manual_otp_check', feature_category: :system_access do
status 200
two_factor_manual_otp_check
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index 5f12275b7a0..bf9612db6bf 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -47,7 +47,7 @@ module API
end
def check_feature_enabled
- not_found! unless Feature.enabled?(:kubernetes_agent_internal_api, type: :ops)
+ not_found!('Internal API not found') unless Feature.enabled?(:kubernetes_agent_internal_api, type: :ops)
end
def check_agent_token
@@ -135,6 +135,49 @@ module API
end
end
+ namespace 'kubernetes/authorize_proxy_user' do
+ 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_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: :kubernetes_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
+
+ # Load agent
+ agent = ::Clusters::Agent.find(params[:agent_id])
+ unauthorized!('Feature disabled for agent') unless ::Gitlab::Kas::UserAccess.enabled_for?(agent)
+
+ service_response = ::Clusters::Agents::AuthorizeProxyUserService.new(user, agent).execute
+ render_api_error!(service_response[:message], service_response[:reason]) unless service_response.success?
+
+ service_response.payload
+ end
+ end
+
namespace 'kubernetes/usage_metrics' do
desc 'POST usage metrics' do
detail 'Updates usage metrics for agent'
diff --git a/lib/api/internal/pages.rb b/lib/api/internal/pages.rb
index 771059053ac..5664a3df589 100644
--- a/lib/api/internal/pages.rb
+++ b/lib/api/internal/pages.rb
@@ -33,26 +33,7 @@ module API
requires :host, type: String, desc: 'The host to query for'
end
get "/" do
- ##
- # Serverless domain proxy has been deprecated and disabled as per
- # https://gitlab.com/gitlab-org/gitlab-pages/-/issues/467
- #
- # serverless_domain_finder = ServerlessDomainFinder.new(params[:host])
- # if serverless_domain_finder.serverless?
- # # Handle Serverless domains
- # serverless_domain = serverless_domain_finder.execute
- # no_content! unless serverless_domain
- #
- # virtual_domain = Serverless::VirtualDomain.new(serverless_domain)
- # no_content! unless virtual_domain
- #
- # present virtual_domain, with: Entities::Internal::Serverless::VirtualDomain
- # end
-
- host = Namespace.find_by_pages_host(params[:host]) || PagesDomain.find_by_domain_case_insensitive(params[:host])
- no_content! unless host
-
- virtual_domain = host.pages_virtual_domain
+ virtual_domain = ::Gitlab::Pages::VirtualHostFinder.new(params[:host]).execute
no_content! unless virtual_domain
if virtual_domain.cache_key.present?
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 88e99b29587..d033913aa71 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -99,7 +99,7 @@ module API
optional :add_labels, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names'
optional :remove_labels, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names'
optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY'
- optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential'
+ optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential', allow_blank: false
optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked"
optional :issue_type, type: String, values: WorkItems::Type.allowed_types_for_issues, desc: "The type of the issue. Accepts: #{WorkItems::Type.allowed_types_for_issues.join(', ')}"
diff --git a/lib/api/keys.rb b/lib/api/keys.rb
index 77952bac01a..c711b3d9c19 100644
--- a/lib/api/keys.rb
+++ b/lib/api/keys.rb
@@ -5,7 +5,7 @@ module API
class Keys < ::API::Base
before { authenticate! }
- feature_category :authentication_and_authorization
+ feature_category :system_access
resource :keys do
desc 'Get single ssh key by id. Only available to admin users' do
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index 89787ba00c2..0dd06d27aeb 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -2,7 +2,7 @@
module API
class Lint < ::API::Base
- feature_category :pipeline_authoring
+ feature_category :pipeline_composition
helpers do
def can_lint_ci?
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index 411a53a481b..bd1ebbaf899 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -191,6 +191,7 @@ module API
package_file.file_sha1
else
track_package_event('pull_package', :maven, project: project, namespace: project.namespace) if jar_file?(format)
+
present_carrierwave_file_with_head_support!(package_file)
end
end
@@ -353,7 +354,7 @@ module API
}
::Packages::CreatePackageFileService.new(package, file_params.merge(build: current_authenticated_job)).execute
- track_package_event('push_package', :maven, user: current_user, project: user_project, namespace: user_project.namespace) if jar_file?(format)
+ track_package_event('push_package', :maven, project: user_project, namespace: user_project.namespace) if jar_file?(format)
end
end
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index cd46b442b68..e99e8f5421c 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -8,6 +8,10 @@ module API
before { authenticate_non_get! }
+ rescue_from ActiveRecord::QueryCanceled do |_e|
+ render_api_error!({ error: 'Request timed out' }, 408)
+ end
+
helpers Helpers::MergeRequestsHelpers
# These endpoints are defined in `TimeTrackingEndpoints` and is shared by
diff --git a/lib/api/metrics/dashboard/annotations.rb b/lib/api/metrics/dashboard/annotations.rb
index 6ba154191be..db667b0291b 100644
--- a/lib/api/metrics/dashboard/annotations.rb
+++ b/lib/api/metrics/dashboard/annotations.rb
@@ -42,7 +42,7 @@ module API
post ':id/metrics_dashboard/annotations' do
annotations_source_object = annotations_source[:class].find(params[:id])
- forbidden! unless can?(current_user, :create_metrics_dashboard_annotation, annotations_source_object)
+ forbidden! unless can?(current_user, :admin_metrics_dashboard_annotation, annotations_source_object)
create_service_params = declared(params).merge(
annotations_source[:create_service_param_key] => annotations_source_object
diff --git a/lib/api/milestone_responses.rb b/lib/api/milestone_responses.rb
index 2fd3239b44a..fb71cb0e791 100644
--- a/lib/api/milestone_responses.rb
+++ b/lib/api/milestone_responses.rb
@@ -20,6 +20,8 @@ module API
optional :search, type: String, desc: 'The search criteria for the title or description of the milestone'
optional :include_parent_milestones, type: Grape::API::Boolean, default: false,
desc: 'Include group milestones from parent and its ancestors'
+ optional :updated_before, type: DateTime, desc: 'Return milestones updated before the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ'
+ optional :updated_after, type: DateTime, desc: 'Return milestones updated after the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ'
use :pagination
end
@@ -33,14 +35,9 @@ module API
end
def list_milestones_for(parent)
- milestones = init_milestones_collection(parent)
- milestones = Milestone.filter_by_state(milestones, params[:state])
- if params[:iids].present? && !params[:include_parent_milestones]
- milestones = filter_by_iid(milestones, params[:iids])
- end
-
- milestones = filter_by_title(milestones, params[:title]) if params[:title]
- milestones = filter_by_search(milestones, params[:search]) if params[:search]
+ milestones = MilestonesFinder.new(
+ params.merge(parent_finder_params(parent))
+ ).execute
present paginate(milestones), with: Entities::Milestone
end
@@ -84,6 +81,16 @@ module API
present paginate(issuables), with: entity, current_user: current_user
end
+ def parent_finder_params(parent)
+ include_parent = params[:include_parent_milestones].present?
+
+ if parent.is_a?(Project)
+ { project_ids: parent.id, group_ids: (include_parent ? project_group_ids(parent) : nil) }
+ else
+ { group_ids: (include_parent ? group_and_ancestor_ids(parent) : parent.id) }
+ end
+ end
+
def build_finder_params(milestone, parent)
finder_params = { milestone_title: milestone.title, sort: 'label_priority' }
@@ -102,26 +109,6 @@ module API
end
end
- def init_milestones_collection(parent)
- milestones = if params[:include_parent_milestones].present?
- parent_and_ancestors_milestones(parent)
- else
- parent.milestones
- end
-
- milestones.order_id_desc
- end
-
- def parent_and_ancestors_milestones(parent)
- project_id, group_ids = if parent.is_a?(Project)
- [parent.id, project_group_ids(parent)]
- else
- [nil, parent_group_ids(parent)]
- end
-
- Milestone.for_projects_and_groups(project_id, group_ids)
- end
-
def project_group_ids(parent)
group = parent.group
return unless group.present?
@@ -129,7 +116,7 @@ module API
group.self_and_ancestors.select(:id)
end
- def parent_group_ids(group)
+ def group_and_ancestor_ids(group)
return unless group.present?
group.self_and_ancestors
diff --git a/lib/api/npm_project_packages.rb b/lib/api/npm_project_packages.rb
index f42ded5ac09..07cbb3bf582 100644
--- a/lib/api/npm_project_packages.rb
+++ b/lib/api/npm_project_packages.rb
@@ -69,7 +69,7 @@ module API
if created_package[:status] == :error
render_api_error!(created_package[:message], created_package[:http_status])
else
- track_package_event('push_package', :npm, category: 'API::NpmPackages', project: project, user: current_user, namespace: project.namespace)
+ track_package_event('push_package', :npm, category: 'API::NpmPackages', project: project, namespace: project.namespace)
created_package
end
end
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index 8e974cb9cbe..cd16aaf6b5f 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -125,7 +125,6 @@ module API
'push_package',
:nuget,
category: 'API::NugetPackages',
- user: current_user,
project: package.project,
namespace: package.project.namespace
)
@@ -171,7 +170,6 @@ module API
'push_symbol_package',
:nuget,
category: 'API::NugetPackages',
- user: current_user,
project: package.project,
namespace: package.project.namespace
)
diff --git a/lib/api/personal_access_tokens.rb b/lib/api/personal_access_tokens.rb
index 66930ecd797..e588eb17720 100644
--- a/lib/api/personal_access_tokens.rb
+++ b/lib/api/personal_access_tokens.rb
@@ -4,7 +4,7 @@ module API
class PersonalAccessTokens < ::API::Base
include ::API::PaginationParams
- feature_category :authentication_and_authorization
+ feature_category :system_access
before do
authenticate!
diff --git a/lib/api/personal_access_tokens/self_information.rb b/lib/api/personal_access_tokens/self_information.rb
index 5735fe49f33..4f17ca955ac 100644
--- a/lib/api/personal_access_tokens/self_information.rb
+++ b/lib/api/personal_access_tokens/self_information.rb
@@ -5,7 +5,7 @@ module API
class SelfInformation < ::API::Base
include APIGuard
- feature_category :authentication_and_authorization
+ feature_category :system_access
helpers ::API::Helpers::PersonalAccessTokensHelpers
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 0f4f1dc7fa6..3e7e95c2c0d 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -40,7 +40,7 @@ module API
user: current_user, subject: user_project
).execute
- track_package_event('list_repositories', :container, user: current_user, project: user_project, namespace: user_project.namespace)
+ track_package_event('list_repositories', :container, project: user_project, namespace: user_project.namespace)
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
end
@@ -62,7 +62,7 @@ module API
authorize_admin_container_image!
repository.delete_scheduled!
- track_package_event('delete_repository', :container, user: current_user, project: user_project, namespace: user_project.namespace)
+ track_package_event('delete_repository', :container, project: user_project, namespace: user_project.namespace)
status :accepted
end
@@ -85,7 +85,7 @@ module API
authorize_read_container_image!
tags = Kaminari.paginate_array(repository.tags)
- track_package_event('list_tags', :container, user: current_user, project: user_project, namespace: user_project.namespace)
+ track_package_event('list_tags', :container, project: user_project, namespace: user_project.namespace)
present paginate(tags), with: Entities::ContainerRegistry::Tag
end
@@ -121,7 +121,7 @@ module API
declared_params.except(:repository_id))
# rubocop:enable CodeReuse/Worker
- track_package_event('delete_tag_bulk', :container, user: current_user, project: user_project, namespace: user_project.namespace)
+ track_package_event('delete_tag_bulk', :container, project: user_project, namespace: user_project.namespace)
status :accepted
end
@@ -169,7 +169,7 @@ module API
.execute(repository)
if result[:status] == :success
- track_package_event('delete_tag', :container, user: current_user, project: user_project, namespace: user_project.namespace)
+ track_package_event('delete_tag', :container, project: user_project, namespace: user_project.namespace)
status :ok
else
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 6eea56ea117..c32f61c6704 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -80,9 +80,8 @@ module API
# Temporarily introduced for upload API: https://gitlab.com/gitlab-org/gitlab/-/issues/325788
def project_attachment_size(user_project)
return PROJECT_ATTACHMENT_SIZE_EXEMPT if exempt_from_global_attachment_size?(user_project)
- return user_project.max_attachment_size if Feature.enabled?(:enforce_max_attachment_size_upload_api, user_project)
- PROJECT_ATTACHMENT_SIZE_EXEMPT
+ user_project.max_attachment_size
end
# This is to help determine which projects to use in https://gitlab.com/gitlab-org/gitlab/-/issues/325788
@@ -94,6 +93,12 @@ module API
Gitlab::AppLogger.info({ message: "File exceeds maximum size", file_bytes: file.size, project_id: user_project.id, project_path: user_project.full_path, upload_allowed: allowed })
end
end
+
+ def validate_projects_api_rate_limit_for_unauthenticated_users!
+ return unless Feature.enabled?(:rate_limit_for_unauthenticated_projects_api_access)
+
+ check_rate_limit!(:projects_api_rate_limit_unauthenticated, scope: [ip_address]) if current_user.blank?
+ end
end
helpers do
@@ -266,6 +271,8 @@ module API
end
# TODO: Set higher urgency https://gitlab.com/gitlab-org/gitlab/-/issues/211495
get feature_category: :projects, urgency: :low do
+ validate_projects_api_rate_limit_for_unauthenticated_users!
+
present_projects load_projects
end
@@ -701,7 +708,7 @@ module API
requires :group_access, type: Integer, values: Gitlab::Access.values, as: :link_group_access, desc: 'The group access level'
optional :expires_at, type: Date, desc: 'Share expiration date'
end
- post ":id/share", feature_category: :authentication_and_authorization do
+ post ":id/share", feature_category: :system_access do
authorize! :admin_project, user_project
shared_with_group = Group.find_by_id(params[:group_id])
@@ -731,7 +738,7 @@ module API
requires :group_id, type: Integer, desc: 'The ID of the group'
end
# rubocop: disable CodeReuse/ActiveRecord
- delete ":id/share/:group_id", feature_category: :authentication_and_authorization do
+ delete ":id/share/:group_id", feature_category: :system_access do
authorize! :admin_project, user_project
link = user_project.project_group_links.find_by(group_id: params[:group_id])
@@ -822,7 +829,7 @@ module API
optional :skip_users, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Filter out users with the specified IDs'
use :pagination
end
- get ':id/users', urgency: :low, feature_category: :authentication_and_authorization do
+ get ':id/users', urgency: :low, feature_category: :system_access do
users = DeclarativePolicy.subject_scope { user_project.team.users }
users = users.search(params[:search]) if params[:search].present?
users = users.where_not_in(params[:skip_users]) if params[:skip_users].present?
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index 786045684b8..a50208d78d7 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -109,13 +109,15 @@ module API
failure [
{ code: 422, message: 'Push access levels access level has already been taken' },
{ code: 404, message: '404 Project Not Found' },
- { code: 401, message: '401 Unauthorized' }
+ { code: 401, message: '401 Unauthorized' },
+ { code: 400, message: '400 Bad request' }
]
end
params do
requires :name, type: String, desc: 'The name of the branch', documentation: { example: 'main' }
optional :allow_force_push, type: Boolean,
- desc: 'Allow force push for all users with push access.'
+ desc: 'Allow force push for all users with push access.',
+ allow_blank: false
use :optional_params_ee
end
diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb
index 8c4203d8819..027a11738d3 100644
--- a/lib/api/pypi_packages.rb
+++ b/lib/api/pypi_packages.rb
@@ -288,7 +288,7 @@ module API
authorize_upload!(project)
bad_request!('File is too large') if project.actual_limits.exceeded?(:pypi_max_file_size, params[:content].size)
- track_package_event('push_package', :pypi, project: project, user: current_user, namespace: project.namespace)
+ track_package_event('push_package', :pypi, project: project, namespace: project.namespace)
validate_fips! if Gitlab::FIPS.enabled?
diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb
index b21bcb4a903..311fcf9aba1 100644
--- a/lib/api/release/links.rb
+++ b/lib/api/release/links.rb
@@ -65,14 +65,16 @@ module API
end
route_setting :authentication, job_token_allowed: true
post 'links' do
- authorize! :create_release, release
-
- new_link = release.links.create(declared_params(include_missing: false))
-
- if new_link.persisted?
- present new_link, with: Entities::Releases::Link
+ result = ::Releases::Links::CreateService
+ .new(release, current_user, declared_params(include_missing: false))
+ .execute
+
+ if result.success?
+ present result.payload[:link], with: Entities::Releases::Link
+ elsif result.reason == ::Releases::Links::REASON_FORBIDDEN
+ forbidden!
else
- render_api_error!(new_link.errors.messages, 400)
+ render_api_error!(result.message, 400)
end
end
@@ -119,12 +121,16 @@ module API
end
route_setting :authentication, job_token_allowed: true
put do
- authorize! :update_release, release
-
- if link.update(declared_params(include_missing: false))
- present link, with: Entities::Releases::Link
+ result = ::Releases::Links::UpdateService
+ .new(release, current_user, declared_params(include_missing: false))
+ .execute(link)
+
+ if result.success?
+ present result.payload[:link], with: Entities::Releases::Link
+ elsif result.reason == ::Releases::Links::REASON_FORBIDDEN
+ forbidden!
else
- render_api_error!(link.errors.messages, 400)
+ render_api_error!(result.message, 400)
end
end
@@ -139,12 +145,16 @@ module API
end
route_setting :authentication, job_token_allowed: true
delete do
- authorize! :destroy_release, release
-
- if link.destroy
- present link, with: Entities::Releases::Link
+ result = ::Releases::Links::DestroyService
+ .new(release, current_user)
+ .execute(link)
+
+ if result.success?
+ present result.payload[:link], with: Entities::Releases::Link
+ elsif result.reason == ::Releases::Links::REASON_FORBIDDEN
+ forbidden!
else
- render_api_error!(link.errors.messages, 400)
+ render_api_error!(result.message, 400)
end
end
end
diff --git a/lib/api/resource_access_tokens.rb b/lib/api/resource_access_tokens.rb
index 754dfadb5fc..2726e05cd44 100644
--- a/lib/api/resource_access_tokens.rb
+++ b/lib/api/resource_access_tokens.rb
@@ -8,7 +8,7 @@ module API
before { authenticate! }
- feature_category :authentication_and_authorization
+ feature_category :system_access
%w[project group].each do |source_type|
resource source_type.pluralize, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/rpm_project_packages.rb b/lib/api/rpm_project_packages.rb
index f02d288982a..7db2815bb98 100644
--- a/lib/api/rpm_project_packages.rb
+++ b/lib/api/rpm_project_packages.rb
@@ -97,7 +97,6 @@ module API
track_package_event(
'push_package',
:rpm,
- user: current_user,
category: self.class.name,
project: authorized_user_project,
namespace: authorized_user_project.namespace
diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb
index 896d8fcc727..b7bc065eee8 100644
--- a/lib/api/rubygem_packages.rb
+++ b/lib/api/rubygem_packages.rb
@@ -138,7 +138,7 @@ module API
authorize_upload!(project)
bad_request!('File is too large') if project.actual_limits.exceeded?(:rubygems_max_file_size, params[:file].size)
- track_package_event('push_package', :rubygems, user: current_user, project: project, namespace: project.namespace)
+ track_package_event('push_package', :rubygems, project: project, namespace: project.namespace)
package_file = nil
diff --git a/lib/api/search.rb b/lib/api/search.rb
index 2204437f2ec..954c3cd9f9e 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -68,6 +68,9 @@ module API
@results = search_service.search_objects(preload_method)
end
+ search_results = search_service.search_results
+ bad_request!(search_results.error) if search_results.respond_to?(:failed?) && search_results.failed?
+
set_global_search_log_information(additional_params)
Gitlab::Metrics::GlobalSearchSlis.record_apdex(
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index a80ef514943..583b6e1fed4 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -12,7 +12,7 @@ module API
},
gitlab_ci_ymls: {
gitlab_version: 8.9,
- feature_category: :pipeline_authoring,
+ feature_category: :pipeline_composition,
file_type: 'GitLab CI/CD YAML'
},
dockerfiles: {
diff --git a/lib/api/terraform/modules/v1/packages.rb b/lib/api/terraform/modules/v1/packages.rb
index 5624784228e..8f264097867 100644
--- a/lib/api/terraform/modules/v1/packages.rb
+++ b/lib/api/terraform/modules/v1/packages.rb
@@ -200,7 +200,7 @@ module API
tags %w[terraform_registry]
end
get do
- track_package_event('pull_package', :terraform_module, project: package.project, namespace: module_namespace, user: current_user)
+ track_package_event('pull_package', :terraform_module, project: package.project, namespace: module_namespace)
present_carrierwave_file!(package_file.file)
end
@@ -292,7 +292,7 @@ module API
render_api_error!(result[:message], result[:http_status]) if result[:status] == :error
- track_package_event('push_package', :terraform_module, project: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace)
+ track_package_event('push_package', :terraform_module, project: authorized_user_project, namespace: authorized_user_project.namespace)
created!
rescue ObjectStorage::RemoteStoreError => e
diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb
index bdc9f975970..184690f9979 100644
--- a/lib/api/terraform/state.rb
+++ b/lib/api/terraform/state.rb
@@ -28,18 +28,16 @@ module API
increment_unique_values('p_terraform_state_api_unique_users', current_user.id)
- if Feature.enabled?(:route_hll_to_snowplow_phase2, user_project&.namespace)
- Gitlab::Tracking.event(
- 'API::Terraform::State',
- 'terraform_state_api_request',
- namespace: user_project&.namespace,
- user: current_user,
- project: user_project,
- label: 'redis_hll_counters.terraform.p_terraform_state_api_unique_users_monthly',
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
- event: 'p_terraform_state_api_unique_users').to_context]
- )
- end
+ Gitlab::Tracking.event(
+ 'API::Terraform::State',
+ 'terraform_state_api_request',
+ namespace: user_project&.namespace,
+ user: current_user,
+ project: user_project,
+ label: 'redis_hll_counters.terraform.p_terraform_state_api_unique_users_monthly',
+ context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
+ event: 'p_terraform_state_api_unique_users').to_context]
+ )
end
params do
diff --git a/lib/api/unleash.rb b/lib/api/unleash.rb
index b2133dc743a..ae84c6c7010 100644
--- a/lib/api/unleash.rb
+++ b/lib/api/unleash.rb
@@ -33,13 +33,11 @@ module API
present_feature_flags
end
- # We decrease the urgency of this endpoint until the maxmemory issue of redis-cache has been resolved.
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/365575#note_1033611872 for more information.
desc 'Get a list of features' do
is_array true
tags unleash_tags
end
- get 'client/features', urgency: :low do
+ get 'client/features', urgency: :medium do
present_feature_flags
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index cc7eb63798a..63f838c8962 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -156,7 +156,7 @@ module API
entity = current_user&.can_read_all_resources? ? Entities::UserWithAdmin : Entities::UserBasic
if entity == Entities::UserWithAdmin
- users = users.preload(:identities, :u2f_registrations, :webauthn_registrations, :namespace, :followers, :followees, :user_preference)
+ users = users.preload(:identities, :webauthn_registrations, :namespace, :followers, :followees, :user_preference)
end
users, options = with_custom_attributes(users, { with: entity, current_user: current_user })
@@ -381,7 +381,7 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
- patch ":id/disable_two_factor", feature_category: :authentication_and_authorization do
+ patch ":id/disable_two_factor", feature_category: :system_access do
authenticated_as_admin!
user = User.find_by_id(params[:id])
@@ -407,7 +407,7 @@ module API
requires :provider, type: String, desc: 'The external provider'
end
# rubocop: disable CodeReuse/ActiveRecord
- delete ":id/identities/:provider", feature_category: :authentication_and_authorization do
+ delete ":id/identities/:provider", feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params[:id])
@@ -456,7 +456,7 @@ module API
desc: 'Scope of usage for the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ":user_id/keys", feature_category: :authentication_and_authorization do
+ post ":user_id/keys", feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params.delete(:user_id))
@@ -479,7 +479,7 @@ module API
requires :user_id, type: String, desc: 'The ID or username of the user'
use :pagination
end
- get ':user_id/keys', requirements: API::USER_REQUIREMENTS, feature_category: :authentication_and_authorization do
+ get ':user_id/keys', requirements: API::USER_REQUIREMENTS, feature_category: :system_access do
user = find_user(params[:user_id])
not_found!('User') unless user && can?(current_user, :read_user, user)
@@ -494,7 +494,7 @@ module API
requires :id, type: Integer, desc: 'The ID of the user'
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
- get ':id/keys/:key_id', requirements: API::USER_REQUIREMENTS, feature_category: :authentication_and_authorization do
+ get ':id/keys/:key_id', requirements: API::USER_REQUIREMENTS, feature_category: :system_access do
user = find_user(params[:id])
not_found!('User') unless user && can?(current_user, :read_user, user)
@@ -512,7 +512,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
- delete ':id/keys/:key_id', feature_category: :authentication_and_authorization do
+ delete ':id/keys/:key_id', feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params[:id])
@@ -537,7 +537,7 @@ module API
requires :key, type: String, desc: 'The new GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ':id/gpg_keys', feature_category: :authentication_and_authorization do
+ post ':id/gpg_keys', feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params.delete(:id))
@@ -562,7 +562,7 @@ module API
use :pagination
end
# rubocop: disable CodeReuse/ActiveRecord
- get ':id/gpg_keys', feature_category: :authentication_and_authorization do
+ get ':id/gpg_keys', feature_category: :system_access do
user = User.find_by(id: params[:id])
not_found!('User') unless user
@@ -579,7 +579,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
- get ':id/gpg_keys/:key_id', feature_category: :authentication_and_authorization do
+ get ':id/gpg_keys/:key_id', feature_category: :system_access do
user = User.find_by(id: params[:id])
not_found!('User') unless user
@@ -598,7 +598,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
- delete ':id/gpg_keys/:key_id', feature_category: :authentication_and_authorization do
+ delete ':id/gpg_keys/:key_id', feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params[:id])
@@ -622,7 +622,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ':id/gpg_keys/:key_id/revoke', feature_category: :authentication_and_authorization do
+ post ':id/gpg_keys/:key_id/revoke', feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params[:id])
@@ -726,7 +726,7 @@ module API
requires :id, type: Integer, desc: 'The ID of the user'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ':id/activate', feature_category: :authentication_and_authorization do
+ post ':id/activate', feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params[:id])
@@ -740,7 +740,7 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
- post ':id/approve', feature_category: :authentication_and_authorization do
+ post ':id/approve', feature_category: :system_access do
user = User.find_by(id: params[:id])
not_found!('User') unless can?(current_user, :read_user, user)
@@ -757,7 +757,7 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
- post ':id/reject', feature_category: :authentication_and_authorization do
+ post ':id/reject', feature_category: :system_access do
user = find_user_by_id(params)
result = ::Users::RejectService.new(current_user).execute(user)
@@ -775,7 +775,7 @@ module API
requires :id, type: Integer, desc: 'The ID of the user'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ':id/deactivate', feature_category: :authentication_and_authorization do
+ post ':id/deactivate', feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
@@ -801,7 +801,7 @@ module API
requires :id, type: Integer, desc: 'The ID of the user'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ':id/block', feature_category: :authentication_and_authorization do
+ post ':id/block', feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
@@ -828,7 +828,7 @@ module API
requires :id, type: Integer, desc: 'The ID of the user'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ':id/unblock', feature_category: :authentication_and_authorization do
+ post ':id/unblock', feature_category: :system_access do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
@@ -848,7 +848,7 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
- post ':id/ban', feature_category: :authentication_and_authorization do
+ post ':id/ban', feature_category: :system_access do
authenticated_as_admin!
user = find_user_by_id(params)
@@ -864,7 +864,7 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
- post ':id/unban', feature_category: :authentication_and_authorization do
+ post ':id/unban', feature_category: :system_access do
authenticated_as_admin!
user = find_user_by_id(params)
@@ -928,7 +928,7 @@ module API
use :pagination
optional :state, type: String, default: 'all', values: %w[all active inactive], desc: 'Filters (all|active|inactive) impersonation_tokens'
end
- get feature_category: :authentication_and_authorization do
+ get feature_category: :system_access do
present paginate(finder(declared_params(include_missing: false)).execute), with: Entities::ImpersonationToken
end
@@ -941,7 +941,7 @@ module API
optional :expires_at, type: Date, desc: 'The expiration date in the format YEAR-MONTH-DAY of the impersonation token'
optional :scopes, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The array of scopes of the impersonation token'
end
- post feature_category: :authentication_and_authorization do
+ post feature_category: :system_access do
impersonation_token = finder.build(declared_params(include_missing: false))
if impersonation_token.save
@@ -958,7 +958,7 @@ module API
params do
requires :impersonation_token_id, type: Integer, desc: 'The ID of the impersonation token'
end
- get ':impersonation_token_id', feature_category: :authentication_and_authorization do
+ get ':impersonation_token_id', feature_category: :system_access do
present find_impersonation_token, with: Entities::ImpersonationToken
end
@@ -968,7 +968,7 @@ module API
params do
requires :impersonation_token_id, type: Integer, desc: 'The ID of the impersonation token'
end
- delete ':impersonation_token_id', feature_category: :authentication_and_authorization do
+ delete ':impersonation_token_id', feature_category: :system_access do
token = find_impersonation_token
destroy_conditionally!(token) do
@@ -996,7 +996,7 @@ module API
desc: 'The array of scopes of the personal access token'
optional :expires_at, type: Date, desc: 'The expiration date in the format YEAR-MONTH-DAY of the personal access token'
end
- post feature_category: :authentication_and_authorization do
+ post feature_category: :system_access do
response = ::PersonalAccessTokens::CreateService.new(
current_user: current_user, target_user: target_user, params: declared_params(include_missing: false)
).execute
@@ -1060,7 +1060,7 @@ module API
params do
use :pagination
end
- get "keys", feature_category: :authentication_and_authorization do
+ get "keys", feature_category: :system_access do
keys = current_user.keys.preload_users
present paginate(keys), with: Entities::SSHKey
@@ -1073,7 +1073,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
- get "keys/:key_id", feature_category: :authentication_and_authorization do
+ get "keys/:key_id", feature_category: :system_access do
key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
@@ -1091,7 +1091,7 @@ module API
optional :usage_type, type: String, values: Key.usage_types.keys, default: 'auth_and_signing',
desc: 'Scope of usage for the SSH key'
end
- post "keys", feature_category: :authentication_and_authorization do
+ post "keys", feature_category: :system_access do
key = ::Keys::CreateService.new(current_user, declared_params(include_missing: false)).execute
if key.persisted?
@@ -1108,7 +1108,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
- delete "keys/:key_id", feature_category: :authentication_and_authorization do
+ delete "keys/:key_id", feature_category: :system_access do
key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
@@ -1126,7 +1126,7 @@ module API
params do
use :pagination
end
- get 'gpg_keys', feature_category: :authentication_and_authorization do
+ get 'gpg_keys', feature_category: :system_access do
present paginate(current_user.gpg_keys), with: Entities::GpgKey
end
@@ -1138,7 +1138,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
- get 'gpg_keys/:key_id', feature_category: :authentication_and_authorization do
+ get 'gpg_keys/:key_id', feature_category: :system_access do
key = current_user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
@@ -1153,7 +1153,7 @@ module API
params do
requires :key, type: String, desc: 'The new GPG key'
end
- post 'gpg_keys', feature_category: :authentication_and_authorization do
+ post 'gpg_keys', feature_category: :system_access do
key = ::GpgKeys::CreateService.new(current_user, declared_params(include_missing: false)).execute
if key.persisted?
@@ -1170,7 +1170,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
- post 'gpg_keys/:key_id/revoke', feature_category: :authentication_and_authorization do
+ post 'gpg_keys/:key_id/revoke', feature_category: :system_access do
key = current_user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
@@ -1186,7 +1186,7 @@ module API
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
- delete 'gpg_keys/:key_id', feature_category: :authentication_and_authorization do
+ delete 'gpg_keys/:key_id', feature_category: :system_access do
key = current_user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
diff --git a/lib/atlassian/jira_connect/serializers/build_entity.rb b/lib/atlassian/jira_connect/serializers/build_entity.rb
index aa864cb268f..b595d0c2a92 100644
--- a/lib/atlassian/jira_connect/serializers/build_entity.rb
+++ b/lib/atlassian/jira_connect/serializers/build_entity.rb
@@ -22,9 +22,10 @@ module Atlassian
expose :references
def issue_keys
- # extract Jira issue keys from either the source branch/ref or the
- # merge request title.
- @issue_keys ||= pipeline.all_merge_requests.flat_map do |mr|
+ commit_message_issue_keys = JiraIssueKeyExtractor.new(pipeline.git_commit_message).issue_keys
+
+ # extract Jira issue keys from either the source branch/ref or the merge request title.
+ @issue_keys ||= commit_message_issue_keys + pipeline.all_merge_requests.flat_map do |mr|
src = "#{mr.source_branch} #{mr.title} #{mr.description}"
JiraIssueKeyExtractor.new(src).issue_keys
end.uniq
diff --git a/lib/backup/gitaly_backup.rb b/lib/backup/gitaly_backup.rb
index 57dd74c7950..354025ffb85 100644
--- a/lib/backup/gitaly_backup.rb
+++ b/lib/backup/gitaly_backup.rb
@@ -77,11 +77,7 @@ module Backup
#
# @see https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/gitaly-backup.md
def schedule_backup_job(repository, always_create:)
- connection_params = Gitlab::GitalyClient.connection_data(repository.storage)
-
json_job = {
- address: connection_params['address'],
- token: connection_params['token'],
storage_name: repository.storage,
relative_path: repository.relative_path,
gl_project_path: repository.gl_project_path,
@@ -91,10 +87,21 @@ module Backup
@input_stream.puts(json_job)
end
+ def gitaly_servers
+ Gitlab.config.repositories.storages.keys.index_with do |storage_name|
+ Gitlab::GitalyClient.connection_data(storage_name)
+ end
+ end
+
+ def gitaly_servers_encoded
+ Base64.strict_encode64(Gitlab::Json.dump(gitaly_servers))
+ end
+
def build_env
{
'SSL_CERT_FILE' => Gitlab::X509::Certificate.default_cert_file,
- 'SSL_CERT_DIR' => Gitlab::X509::Certificate.default_cert_dir
+ 'SSL_CERT_DIR' => Gitlab::X509::Certificate.default_cert_dir,
+ 'GITALY_SERVERS' => gitaly_servers_encoded
}.merge(ENV)
end
diff --git a/lib/banzai/filter/inline_observability_filter.rb b/lib/banzai/filter/inline_observability_filter.rb
index 334c04f2b59..a47b57d94dd 100644
--- a/lib/banzai/filter/inline_observability_filter.rb
+++ b/lib/banzai/filter/inline_observability_filter.rb
@@ -3,8 +3,10 @@
module Banzai
module Filter
class InlineObservabilityFilter < ::Banzai::Filter::InlineEmbedsFilter
+ include Gitlab::Utils::StrongMemoize
+
def call
- return doc unless can_view_observability?
+ return doc unless Gitlab::Observability.enabled?(group)
super
end
@@ -21,7 +23,7 @@ module Banzai
# Search params for selecting observability links.
def xpath_search
- "descendant-or-self::a[starts-with(@href, '#{Gitlab::Observability.observability_url}')]"
+ "descendant-or-self::a[starts-with(@href, '#{gitlab_domain}/groups/') and contains(@href,'/-/observability/')]"
end
# Creates a new element based on the parameters
@@ -29,13 +31,16 @@ module Banzai
def element_to_embed(node)
url = node['href']
- create_element(url)
+ embeddable_url = extract_embeddable_url(url)
+ create_element(embeddable_url) if embeddable_url
end
private
- def can_view_observability?
- Feature.enabled?(:observability_group_tab, group)
+ def extract_embeddable_url(url)
+ strong_memoize_with(:embeddable_url, url) do
+ Gitlab::Observability.embeddable_url(url)
+ end
end
def group
diff --git a/lib/banzai/filter/issuable_reference_expansion_filter.rb b/lib/banzai/filter/issuable_reference_expansion_filter.rb
index 6822e36c9be..8fe1c90b314 100644
--- a/lib/banzai/filter/issuable_reference_expansion_filter.rb
+++ b/lib/banzai/filter/issuable_reference_expansion_filter.rb
@@ -10,13 +10,17 @@ module Banzai
class IssuableReferenceExpansionFilter < HTML::Pipeline::Filter
include Gitlab::Utils::StrongMemoize
+ NUMBER_OF_SUMMARY_ASSIGNEES = 2
VISIBLE_STATES = %w(closed merged).freeze
+ EXTENDED_FORMAT_XPATH = Gitlab::Utils::Nokogiri.css_to_xpath('a[data-reference-format="+s"]')
def call
return doc unless context[:issuable_reference_expansion_enabled]
- context = RenderContext.new(project, current_user)
- extractor = Banzai::IssuableExtractor.new(context)
+ options = { extended_preload: doc.xpath(EXTENDED_FORMAT_XPATH).present? }
+ extractor_context = RenderContext.new(project, current_user, options: options)
+
+ extractor = Banzai::IssuableExtractor.new(extractor_context)
issuables = extractor.extract([doc])
issuables.each do |node, issuable|
@@ -26,6 +30,9 @@ module Banzai
case node.attr('data-reference-format')
when '+'
expand_reference_with_title_and_state(node, issuable)
+ when '+s'
+ expand_reference_with_title_and_state(node, issuable)
+ expand_reference_with_summary(node, issuable)
else
expand_reference_with_state(node, issuable)
end
@@ -43,11 +50,41 @@ module Banzai
node.content += ')'
end
+ # rubocop:disable Style/AsciiComments
+ # Example: Issue Title (#123 - closed) assignee name 1, assignee name 2+ • v15.9 • On track
+ def expand_reference_with_summary(node, issuable)
+ summary = []
+
+ summary << assignees_text(issuable) if issuable.supports_assignee?
+ summary << milestone_text(issuable.milestone) if issuable.supports_milestone?
+ summary << health_status_text(issuable.health_status) if issuable.supports_health_status?
+
+ node.content = [node.content, *summary].compact_blank.join(' • ')
+ end
+ # rubocop:enable Style/AsciiComments
+
# Example: #123 (closed)
def expand_reference_with_state(node, issuable)
node.content += " (#{issuable_state_text(issuable)})"
end
+ def assignees_text(issuable)
+ assignee_names = issuable.assignees.first(NUMBER_OF_SUMMARY_ASSIGNEES + 1).map(&:sanitize_name)
+
+ return _('Unassigned') if assignee_names.empty?
+
+ "#{assignee_names.first(NUMBER_OF_SUMMARY_ASSIGNEES).to_sentence(two_words_connector: ', ')}" \
+ "#{assignee_names.size > NUMBER_OF_SUMMARY_ASSIGNEES ? '+' : ''}"
+ end
+
+ def milestone_text(milestone)
+ milestone&.title
+ end
+
+ def health_status_text(health_status)
+ health_status&.humanize
+ end
+
def issuable_state_text(issuable)
moved_issue?(issuable) ? s_("IssuableStatus|moved") : issuable.state
end
diff --git a/lib/banzai/filter/reference_redactor_filter.rb b/lib/banzai/filter/reference_redactor_filter.rb
index 485d3fd5fc7..9fae46a24a9 100644
--- a/lib/banzai/filter/reference_redactor_filter.rb
+++ b/lib/banzai/filter/reference_redactor_filter.rb
@@ -10,9 +10,9 @@ module Banzai
class ReferenceRedactorFilter < HTML::Pipeline::Filter
def call
unless context[:skip_redaction]
- context = RenderContext.new(project, current_user)
+ redactor_context = RenderContext.new(project, current_user)
- ReferenceRedactor.new(context).redact([doc])
+ ReferenceRedactor.new(redactor_context).redact([doc])
end
doc
diff --git a/lib/banzai/filter/references/design_reference_filter.rb b/lib/banzai/filter/references/design_reference_filter.rb
index 01e1036dcec..16a2a2835e9 100644
--- a/lib/banzai/filter/references/design_reference_filter.rb
+++ b/lib/banzai/filter/references/design_reference_filter.rb
@@ -43,7 +43,7 @@ module Banzai
return [] unless project.design_management_enabled?
iids = identifiers.map(&:issue_iid).to_set
- issues = project.issues.where(iid: iids)
+ issues = project.issues.where(iid: iids).includes(:project, :namespace)
id_for_iid = issues.index_by(&:iid).transform_values(&:id)
issue_by_id = issues.index_by(&:id)
diff --git a/lib/banzai/filter/references/issue_reference_filter.rb b/lib/banzai/filter/references/issue_reference_filter.rb
index b536d900a02..e186c8b1f73 100644
--- a/lib/banzai/filter/references/issue_reference_filter.rb
+++ b/lib/banzai/filter/references/issue_reference_filter.rb
@@ -22,7 +22,7 @@ module Banzai
end
def parent_records(parent, ids)
- parent.issues.where(iid: ids.to_a)
+ parent.issues.where(iid: ids.to_a).includes(:project, :namespace)
end
def object_link_text_extras(issue, matches)
diff --git a/lib/banzai/reference_parser/commit_parser.rb b/lib/banzai/reference_parser/commit_parser.rb
index c51f4976c28..88896970bc6 100644
--- a/lib/banzai/reference_parser/commit_parser.rb
+++ b/lib/banzai/reference_parser/commit_parser.rb
@@ -32,13 +32,6 @@ module Banzai
commits
end
- def nodes_visible_to_user(user, nodes)
- projects = lazy { projects_for_nodes(nodes) }
- user.preloaded_member_roles_for_projects(projects.values) if user
-
- super
- end
-
private
def can_read_reference?(user, ref_project, node)
diff --git a/lib/banzai/reference_parser/commit_range_parser.rb b/lib/banzai/reference_parser/commit_range_parser.rb
index 3d09bc83151..fb4a392105f 100644
--- a/lib/banzai/reference_parser/commit_range_parser.rb
+++ b/lib/banzai/reference_parser/commit_range_parser.rb
@@ -38,13 +38,6 @@ module Banzai
range.valid_commits? ? range : nil
end
- def nodes_visible_to_user(user, nodes)
- projects = lazy { projects_for_nodes(nodes) }
- user.preloaded_member_roles_for_projects(projects.values) if user
-
- super
- end
-
private
def can_read_reference?(user, ref_project, node)
diff --git a/lib/banzai/reference_parser/issue_parser.rb b/lib/banzai/reference_parser/issue_parser.rb
index 6b1491cc56b..a5862fbaac4 100644
--- a/lib/banzai/reference_parser/issue_parser.rb
+++ b/lib/banzai/reference_parser/issue_parser.rb
@@ -57,18 +57,22 @@ module Banzai
end
def records_for_nodes(nodes)
+ node_includes = [
+ :namespace,
+ :author,
+ :assignees,
+ {
+ # These associations are primarily used for checking permissions.
+ # Eager loading these ensures we don't end up running dozens of
+ # queries in this process.
+ project: [:namespace, :project_feature, :route]
+ }
+ ]
+ node_includes << :milestone if context.options[:extended_preload]
+
@issues_for_nodes ||= grouped_objects_for_nodes(
nodes,
- Issue.all.includes(
- :author,
- :assignees,
- {
- # These associations are primarily used for checking permissions.
- # Eager loading these ensures we don't end up running dozens of
- # queries in this process.
- project: [:namespace, :project_feature, :route]
- }
- ),
+ Issue.all.includes(node_includes),
self.class.data_attribute
)
end
diff --git a/lib/banzai/reference_parser/merge_request_parser.rb b/lib/banzai/reference_parser/merge_request_parser.rb
index 3e28f06b783..2bd06e79e96 100644
--- a/lib/banzai/reference_parser/merge_request_parser.rb
+++ b/lib/banzai/reference_parser/merge_request_parser.rb
@@ -19,17 +19,21 @@ module Banzai
end
def records_for_nodes(nodes)
+ node_includes = [
+ :author,
+ :assignees,
+ {
+ # These associations are primarily used for checking permissions.
+ # Eager loading these ensures we don't end up running dozens of
+ # queries in this process.
+ target_project: [{ namespace: :route }, :project_feature, :route]
+ }
+ ]
+ node_includes << :milestone if context.options[:extended_preload]
+
@merge_requests_for_nodes ||= grouped_objects_for_nodes(
nodes,
- MergeRequest.includes(
- :author,
- :assignees,
- {
- # These associations are primarily used for checking permissions.
- # Eager loading these ensures we don't end up running dozens of
- # queries in this process.
- target_project: [{ namespace: :route }, :project_feature, :route]
- }),
+ MergeRequest.includes(node_includes),
self.class.data_attribute
)
end
diff --git a/lib/banzai/render_context.rb b/lib/banzai/render_context.rb
index e30fc9f469b..a69732a26e2 100644
--- a/lib/banzai/render_context.rb
+++ b/lib/banzai/render_context.rb
@@ -4,13 +4,14 @@ module Banzai
# Object storing the current user, project, and other details used when
# parsing Markdown references.
class RenderContext
- attr_reader :current_user
+ attr_reader :current_user, :options
# default_project - The default project to use for all documents, if any.
# current_user - The user viewing the document, if any.
- def initialize(default_project = nil, current_user = nil)
+ def initialize(default_project = nil, current_user = nil, options: {})
@current_user = current_user
@projects = Hash.new(default_project)
+ @options = options
end
# Associates an HTML document with a Project.
diff --git a/lib/bulk_imports/clients/http.rb b/lib/bulk_imports/clients/http.rb
index 6c36875111b..6efee83a0dd 100644
--- a/lib/bulk_imports/clients/http.rb
+++ b/lib/bulk_imports/clients/http.rb
@@ -9,6 +9,7 @@ module BulkImports
DEFAULT_PAGE = 1
DEFAULT_PER_PAGE = 30
PAT_ENDPOINT_MIN_VERSION = '15.5.0'
+ SIDEKIQ_REQUEST_TIMEOUT = 60
def initialize(url:, token:, page: DEFAULT_PAGE, per_page: DEFAULT_PER_PAGE, api_version: API_VERSION)
@url = url
@@ -84,6 +85,8 @@ module BulkImports
end
def validate_instance_version!
+ raise ::BulkImports::Error.invalid_url unless instance_version.valid?
+
return true unless instance_version.major < BulkImport::MIN_MAJOR_VERSION
raise ::BulkImports::Error.unsupported_gitlab_version
@@ -140,7 +143,7 @@ module BulkImports
follow_redirects: true,
resend_on_redirect: false,
limit: 2
- }
+ }.merge(request_timeout.to_h)
end
def request_query
@@ -151,6 +154,10 @@ module BulkImports
}
end
+ def request_timeout
+ { timeout: SIDEKIQ_REQUEST_TIMEOUT } if Gitlab::Runtime.sidekiq?
+ end
+
def with_error_handling
response = yield
diff --git a/lib/bulk_imports/error.rb b/lib/bulk_imports/error.rb
index 4699d5eab5f..009fa02a72a 100644
--- a/lib/bulk_imports/error.rb
+++ b/lib/bulk_imports/error.rb
@@ -13,7 +13,7 @@ module BulkImports
end
def self.invalid_url
- self.new("Import aborted as it was not possible to connect to the provided GitLab instance URL.")
+ self.new("Invalid source URL. Enter only the base URL of the source GitLab instance.")
end
def self.destination_full_path_validation_failure(full_path)
diff --git a/lib/bulk_imports/features.rb b/lib/bulk_imports/features.rb
deleted file mode 100644
index 9fdceb03655..00000000000
--- a/lib/bulk_imports/features.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-module BulkImports
- module Features
- def self.project_migration_enabled?(destination_namespace = nil)
- if destination_namespace.present?
- root_ancestor = Namespace.find_by_full_path(destination_namespace)&.root_ancestor
-
- ::Feature.enabled?(:bulk_import_projects, root_ancestor)
- else
- ::Feature.enabled?(:bulk_import_projects)
- end
- end
- end
-end
diff --git a/lib/bulk_imports/groups/stage.rb b/lib/bulk_imports/groups/stage.rb
index 7a777f1c8e1..1cdd3bb1d65 100644
--- a/lib/bulk_imports/groups/stage.rb
+++ b/lib/bulk_imports/groups/stage.rb
@@ -71,7 +71,7 @@ module BulkImports
end
def project_entities_pipeline
- if migrate_projects? && project_pipeline_available? && feature_flag_enabled?
+ if migrate_projects? && project_pipeline_available?
{
project_entities: {
pipeline: BulkImports::Groups::Pipelines::ProjectEntitiesPipeline,
@@ -90,12 +90,6 @@ module BulkImports
def project_pipeline_available?
@bulk_import.source_version_info >= BulkImport.min_gl_version_for_project_migration
end
-
- def feature_flag_enabled?
- destination_namespace = @bulk_import_entity.destination_namespace
-
- BulkImports::Features.project_migration_enabled?(destination_namespace)
- end
end
end
end
diff --git a/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb b/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb
index 19993629ff5..18ef460385c 100644
--- a/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb
+++ b/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb
@@ -65,9 +65,10 @@ module BulkImports
namespace_children_names = namespace.children.pluck(:name) # rubocop: disable CodeReuse/ActiveRecord
if namespace_children_names.include?(data['name'])
- data['name'] = Uniquify.new(1).string(-> (counter) { "#{data['name']}(#{counter})" }) do |base|
- namespace_children_names.include?(base)
- end
+ data['name'] =
+ Gitlab::Utils::Uniquify.new(1).string(-> (counter) { "#{data['name']}(#{counter})" }) do |base|
+ namespace_children_names.include?(base)
+ end
end
end
diff --git a/lib/bulk_imports/ndjson_pipeline.rb b/lib/bulk_imports/ndjson_pipeline.rb
index 05d724a5e42..3c392910c1f 100644
--- a/lib/bulk_imports/ndjson_pipeline.rb
+++ b/lib/bulk_imports/ndjson_pipeline.rb
@@ -16,8 +16,6 @@ module BulkImports
return unless relation_hash
- relation_definition = import_export_config.top_relation_tree(relation)
-
relation_object = deep_transform_relation!(relation_hash, relation, relation_definition) do |key, hash|
relation_factory.create(
relation_index: relation_index,
@@ -35,8 +33,29 @@ module BulkImports
relation_object
end
- def load(_, object)
- object&.save!
+ def load(_context, object)
+ return unless object
+
+ if object.new_record?
+ saver = Gitlab::ImportExport::Base::RelationObjectSaver.new(
+ relation_object: object,
+ relation_key: relation,
+ relation_definition: relation_definition,
+ importable: portable
+ )
+
+ saver.execute
+
+ capture_invalid_subrelations(saver.invalid_subrelations)
+ else
+ if object.invalid?
+ Gitlab::Import::Errors.merge_nested_errors(object)
+
+ raise(ActiveRecord::RecordInvalid, object)
+ end
+
+ object.save!
+ end
end
def deep_transform_relation!(relation_hash, relation_key, relation_definition, &block)
@@ -104,6 +123,22 @@ module BulkImports
def portable_class_sym
portable.class.to_s.downcase.to_sym
end
+
+ def relation_definition
+ import_export_config.top_relation_tree(relation)
+ end
+
+ def capture_invalid_subrelations(invalid_subrelations)
+ invalid_subrelations.each do |record|
+ BulkImports::Failure.create(
+ bulk_import_entity_id: tracker.entity.id,
+ pipeline_class: tracker.pipeline_name,
+ exception_class: 'RecordInvalid',
+ exception_message: record.errors.full_messages.to_sentence.truncate(255),
+ correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id
+ )
+ end
+ end
end
end
end
diff --git a/lib/bulk_imports/projects/pipelines/commit_notes_pipeline.rb b/lib/bulk_imports/projects/pipelines/commit_notes_pipeline.rb
new file mode 100644
index 00000000000..092b03cb7b7
--- /dev/null
+++ b/lib/bulk_imports/projects/pipelines/commit_notes_pipeline.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module BulkImports
+ module Projects
+ module Pipelines
+ class CommitNotesPipeline
+ include NdjsonPipeline
+
+ relation_name 'commit_notes'
+
+ extractor ::BulkImports::Common::Extractors::NdjsonExtractor, relation: relation
+ end
+ end
+ end
+end
diff --git a/lib/bulk_imports/projects/stage.rb b/lib/bulk_imports/projects/stage.rb
index 73e102696fa..eecd567f54f 100644
--- a/lib/bulk_imports/projects/stage.rb
+++ b/lib/bulk_imports/projects/stage.rb
@@ -104,6 +104,11 @@ module BulkImports
pipeline: BulkImports::Projects::Pipelines::CiPipelinesPipeline,
stage: 5
},
+ commit_notes: {
+ pipeline: BulkImports::Projects::Pipelines::CommitNotesPipeline,
+ minimum_source_version: '15.10.0',
+ stage: 5
+ },
wiki: {
pipeline: BulkImports::Common::Pipelines::WikiPipeline,
stage: 5
diff --git a/lib/container_registry/gitlab_api_client.rb b/lib/container_registry/gitlab_api_client.rb
index 5dddd421223..d3c0ec03983 100644
--- a/lib/container_registry/gitlab_api_client.rb
+++ b/lib/container_registry/gitlab_api_client.rb
@@ -22,6 +22,8 @@ module ContainerRegistry
REGISTRY_GITLAB_V1_API_FEATURE = 'gitlab_v1_api'
MAX_TAGS_PAGE_SIZE = 1000
+ MAX_REPOSITORIES_PAGE_SIZE = 1000
+ PAGE_SIZE = 1
UnsuccessfulResponseError = Class.new(StandardError)
@@ -37,6 +39,21 @@ module ContainerRegistry
end
end
+ def self.one_project_with_container_registry_tag(path)
+ with_dummy_client(token_config: { type: :nested_repositories_token, path: path&.downcase }) do |client|
+ page = client.sub_repositories_with_tag(path&.downcase, page_size: PAGE_SIZE)
+ details = page[:response_body]&.first
+
+ break unless details
+
+ path = ContainerRegistry::Path.new(details["path"])
+
+ break unless path.valid?
+
+ ContainerRepository.find_by_path(path)&.project
+ end
+ end
+
# https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/api.md#compliance-check
def supports_gitlab_api?
strong_memoize(:supports_gitlab_api) do
@@ -133,6 +150,37 @@ module ContainerRegistry
end
end
+ # https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/api.md#list-sub-repositories
+ def sub_repositories_with_tag(path, page_size: 100, last: nil)
+ limited_page_size = [page_size, MAX_REPOSITORIES_PAGE_SIZE].min
+
+ with_token_faraday do |faraday_client|
+ url = "/gitlab/v1/repository-paths/#{path}/repositories/list/"
+ response = faraday_client.get(url) do |req|
+ req.params['n'] = limited_page_size
+ req.params['last'] = last if last
+ end
+
+ unless response.success?
+ Gitlab::ErrorTracking.log_exception(
+ UnsuccessfulResponseError.new,
+ class: self.class.name,
+ url: url,
+ status_code: response.status
+ )
+
+ break {}
+ end
+
+ link_parser = Gitlab::Utils::LinkHeaderParser.new(response.headers['link'])
+
+ {
+ pagination: link_parser.parse,
+ response_body: response_body(response)
+ }
+ end
+ end
+
private
def start_import_for(path, pre:)
diff --git a/lib/generators/batched_background_migration/USAGE b/lib/generators/batched_background_migration/USAGE
new file mode 100644
index 00000000000..2fc2b2f7b96
--- /dev/null
+++ b/lib/generators/batched_background_migration/USAGE
@@ -0,0 +1,12 @@
+Description:
+ Generates files required for batched background migration.
+
+Example:
+ rails g batched_background_migration my_batched_migration --table_name=users --column_name=id --feature_category=gitaly
+
+ This will create:
+ db/post_migrate/20230213215230_queue_my_batched_migration.rb
+ spec/migrations/20230213215230_queue_my_batched_migration_spec.rb
+ lib/gitlab/background_migration/my_batched_migration.rb
+ spec/lib/gitlab/background_migration/my_batched_migration_spec.rb
+ db/docs/batched_background_migrations/my_batched_migration.yml
diff --git a/lib/generators/batched_background_migration/batched_background_migration_generator.rb b/lib/generators/batched_background_migration/batched_background_migration_generator.rb
new file mode 100644
index 00000000000..c68ed52c1a0
--- /dev/null
+++ b/lib/generators/batched_background_migration/batched_background_migration_generator.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'rails/generators/active_record'
+
+module BatchedBackgroundMigration
+ class BatchedBackgroundMigrationGenerator < ActiveRecord::Generators::Base
+ source_root File.expand_path('templates', __dir__)
+
+ class_option :table_name
+ class_option :column_name
+ class_option :feature_category
+
+ def validate!
+ raise ArgumentError, "table_name is required" unless table_name.present?
+ raise ArgumentError, "column_name is required" unless column_name.present?
+ raise ArgumentError, "feature_category is required" unless feature_category.present?
+ end
+
+ def create_post_migration_and_specs
+ migration_template(
+ "queue_batched_background_migration.template",
+ File.join(db_migrate_path, "queue_#{file_name}.rb")
+ )
+
+ template(
+ "queue_batched_background_migration_spec.template",
+ File.join("spec/migrations/#{migration_number}_queue_#{file_name}_spec.rb")
+ )
+ end
+
+ def create_batched_background_migration_class_and_specs
+ template(
+ "batched_background_migration_job.template",
+ File.join("lib/gitlab/background_migration/#{file_name}.rb")
+ )
+
+ template(
+ "batched_background_migration_job_spec.template",
+ File.join("spec/lib/gitlab/background_migration/#{file_name}_spec.rb")
+ )
+ end
+
+ def create_dictionary_file
+ template(
+ "batched_background_migration_dictionary.template",
+ File.join("db/docs/batched_background_migrations/#{file_name}.yml")
+ )
+ end
+
+ def db_migrate_path
+ super.sub("migrate", "post_migrate")
+ end
+
+ private
+
+ def table_name
+ options[:table_name]
+ end
+
+ def column_name
+ options[:column_name]
+ end
+
+ def feature_category
+ options[:feature_category]
+ end
+
+ def current_milestone
+ version = Gem::Version.new(File.read('VERSION'))
+ version.release.segments.first(2).join('.')
+ end
+ end
+end
diff --git a/lib/generators/batched_background_migration/templates/batched_background_migration_dictionary.template b/lib/generators/batched_background_migration/templates/batched_background_migration_dictionary.template
new file mode 100644
index 00000000000..8aa08e15f48
--- /dev/null
+++ b/lib/generators/batched_background_migration/templates/batched_background_migration_dictionary.template
@@ -0,0 +1,6 @@
+---
+migration_job_name: <%= class_name %>
+description: # Please capture what <%= class_name %> does
+feature_category: <%= feature_category %>
+introduced_by_url: # URL of the MR (or issue/commit) that introduced the migration
+milestone: <%= current_milestone %>
diff --git a/lib/generators/batched_background_migration/templates/batched_background_migration_job.template b/lib/generators/batched_background_migration/templates/batched_background_migration_job.template
new file mode 100644
index 00000000000..c57ac637cb8
--- /dev/null
+++ b/lib/generators/batched_background_migration/templates/batched_background_migration_job.template
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/database/batched_background_migrations.html
+# for more information on how to use batched background migrations
+
+# Update below commented lines with appropriate values.
+
+module Gitlab
+ module BackgroundMigration
+ class <%= class_name %> < BatchedMigrationJob
+ # operation_name :my_operation
+ # scope_to ->(relation) { relation.where(column: "value") }
+ feature_category :<%= feature_category %>
+
+ def perform
+ each_sub_batch do |sub_batch|
+ # Your action on each sub_batch
+ end
+ end
+ end
+ end
+end
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
new file mode 100644
index 00000000000..c41b8107c95
--- /dev/null
+++ b/lib/generators/batched_background_migration/templates/batched_background_migration_job_spec.template
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::<%= class_name %>, schema: <%= migration_number %>, feature_category: :<%= feature_category %> do # rubocop:disable Layout/LineLength
+ # Tests go here
+end
diff --git a/lib/generators/batched_background_migration/templates/queue_batched_background_migration.template b/lib/generators/batched_background_migration/templates/queue_batched_background_migration.template
new file mode 100644
index 00000000000..502edf2c1d7
--- /dev/null
+++ b/lib/generators/batched_background_migration/templates/queue_batched_background_migration.template
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/database/batched_background_migrations.html
+# for more information on when/how to queue batched background migrations
+
+# Update below commented lines with appropriate values.
+
+class <%= migration_class_name %> < Gitlab::Database::Migration[<%= Gitlab::Database::Migration.current_version %>]
+ MIGRATION = "<%= class_name %>"
+ # DELAY_INTERVAL = 2.minutes
+ # BATCH_SIZE = <%= Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers::BATCH_SIZE %>
+ # SUB_BATCH_SIZE = <%= Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers::SUB_BATCH_SIZE %>
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :<%= table_name %>,
+ :<%= column_name %>,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :<%= table_name.to_sym %>, :<%= column_name.to_sym %>, [])
+ end
+end
diff --git a/lib/generators/batched_background_migration/templates/queue_batched_background_migration_spec.template b/lib/generators/batched_background_migration/templates/queue_batched_background_migration_spec.template
new file mode 100644
index 00000000000..e0a3078114e
--- /dev/null
+++ b/lib/generators/batched_background_migration/templates/queue_batched_background_migration_spec.template
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe <%= migration_class_name %>, feature_category: :<%= feature_category.to_sym %> 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: :<%= table_name %>,
+ # column_name: :<%= column_name %>,
+ # 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/lib/generators/gitlab/snowplow_event_definition_generator.rb b/lib/generators/gitlab/snowplow_event_definition_generator.rb
index 827e87dc313..b1a31541350 100644
--- a/lib/generators/gitlab/snowplow_event_definition_generator.rb
+++ b/lib/generators/gitlab/snowplow_event_definition_generator.rb
@@ -14,12 +14,11 @@ module Gitlab
class_option :ee, type: :boolean, optional: true, default: false, desc: 'Indicates if event is for ee'
class_option :category, type: :string, optional: false, desc: 'Category of the event'
class_option :action, type: :string, optional: false, desc: 'Action of the event'
- class_option :force, type: :boolean, optional: true, default: false, desc: 'Overwrite existing definition'
def create_event_file
- raise "Event definition already exists at #{file_path}" if definition_exists? && !force_definition_override?
+ raise "Event definition already exists at #{file_path}" if definition_exists?
- template "event_definition.yml", file_path, force: force_definition_override?
+ template "event_definition.yml", file_path, force: false
end
def distributions
@@ -42,10 +41,6 @@ module Gitlab
options[:ee]
end
- def force_definition_override?
- options[:force]
- end
-
private
def definition_exists?
@@ -64,8 +59,10 @@ module Gitlab
File.join(EE_DIR, file_name)
end
+ # Example of file name
+ # 20230227000018_project_management_issue_title_changed.yml
def file_name
- name = remove_special_chars("#{Time.current.to_i}_#{event_category}_#{event_action}")
+ name = remove_special_chars("#{Time.now.utc.strftime('%Y%m%d%H%M%S')}_#{event_category}_#{event_action}")
"#{name[0..95]}.yml" # max 100 chars, see https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/2030#note_679501200
end
diff --git a/lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher.rb b/lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher.rb
index 07dc4c02ba8..2143497f084 100644
--- a/lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher.rb
+++ b/lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher.rb
@@ -94,10 +94,10 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def preload_associations(records)
- ActiveRecord::Associations::Preloader.new.preload(
- records,
- MAPPINGS.fetch(subject_class).fetch(:includes_for_query)
- )
+ ActiveRecord::Associations::Preloader.new(
+ records: records,
+ associations: MAPPINGS.fetch(subject_class).fetch(:includes_for_query)
+ ).call
records
end
diff --git a/lib/gitlab/analytics/cycle_analytics/records_fetcher.rb b/lib/gitlab/analytics/cycle_analytics/records_fetcher.rb
index 140c4a300ca..9deb5072112 100644
--- a/lib/gitlab/analytics/cycle_analytics/records_fetcher.rb
+++ b/lib/gitlab/analytics/cycle_analytics/records_fetcher.rb
@@ -67,10 +67,10 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def preload_associations(records)
# using preloader instead of includes to avoid AR generating a large column list
- ActiveRecord::Associations::Preloader.new.preload(
- records,
- MAPPINGS.fetch(subject_class).fetch(:includes_for_query)
- )
+ ActiveRecord::Associations::Preloader.new(
+ records: records,
+ associations: MAPPINGS.fetch(subject_class).fetch(:includes_for_query)
+ ).call
records
end
diff --git a/lib/gitlab/analytics/cycle_analytics/request_params.rb b/lib/gitlab/analytics/cycle_analytics/request_params.rb
index 2df3680db5f..3e70d64fea6 100644
--- a/lib/gitlab/analytics/cycle_analytics/request_params.rb
+++ b/lib/gitlab/analytics/cycle_analytics/request_params.rb
@@ -38,13 +38,12 @@ module Gitlab
attribute :created_after, :datetime
attribute :created_before, :datetime
- attribute :group
+ attribute :namespace
attribute :current_user
attribute :value_stream
attribute :sort
attribute :direction
attribute :page
- attribute :project
attribute :stage_id
attribute :end_event_filter
@@ -66,10 +65,6 @@ module Gitlab
self.end_event_filter ||= Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder::DEFAULT_END_EVENT_FILTER
end
- def project_ids
- Array(@project_ids)
- end
-
def to_data_collector_params
{
current_user: current_user,
@@ -86,12 +81,9 @@ module Gitlab
def to_data_attributes
{}.tap do |attrs|
- attrs[:aggregation] = aggregation_attributes if group
- attrs[:group] = group_data_attributes if group
attrs[:value_stream] = value_stream_data_attributes.to_json if value_stream
attrs[:created_after] = created_after.to_date.iso8601
attrs[:created_before] = created_before.to_date.iso8601
- attrs[:projects] = group_projects(project_ids) if group && project_ids.present?
attrs[:labels] = label_name.to_json if label_name.present?
attrs[:assignees] = assignee_username.to_json if assignee_username.present?
attrs[:author] = author_username if author_username.present?
@@ -99,35 +91,61 @@ module Gitlab
attrs[:sort] = sort if sort.present?
attrs[:direction] = direction if direction.present?
attrs[:stage] = stage_data_attributes.to_json if stage_id.present?
+ attrs[:namespace] = namespace_attributes
+ attrs[:enable_tasks_by_type_chart] = 'false'
+ attrs[:default_stages] = Gitlab::Analytics::CycleAnalytics::DefaultStages.all.map do |stage_params|
+ ::Analytics::CycleAnalytics::StagePresenter.new(stage_params)
+ end.to_json
+
+ attrs.merge!(foss_project_level_params, resource_paths)
end
end
+ def project_ids
+ Array(@project_ids)
+ end
+
private
- def use_aggregated_backend?
- # for now it's only available on the group-level
- group.present?
- end
+ delegate :url_helpers, to: Gitlab::Routing
+
+ def foss_project_level_params
+ return {} unless project
- def aggregation_attributes
{
- enabled: aggregation.enabled.to_s,
- last_run_at: aggregation.last_incremental_run_at&.iso8601,
- next_run_at: aggregation.estimated_next_run_at&.iso8601
+ project_id: project.id,
+ group_path: project.group&.path,
+ request_path: url_helpers.project_cycle_analytics_path(project),
+ full_path: project.full_path
}
end
- def aggregation
- @aggregation ||= ::Analytics::CycleAnalytics::Aggregation.safe_create_for_namespace(group)
+ def resource_paths
+ helpers = ActionController::Base.helpers
+
+ {}.tap do |paths|
+ paths[:empty_state_svg_path] = helpers.image_path("illustrations/analytics/cycle-analytics-empty-chart.svg")
+ paths[:no_data_svg_path] = helpers.image_path("illustrations/analytics/cycle-analytics-empty-chart.svg")
+ paths[:no_access_svg_path] = helpers.image_path("illustrations/analytics/no-access.svg")
+
+ if project
+ paths[:milestones_path] = url_helpers.project_milestones_path(project, format: :json)
+ paths[:labels_path] = url_helpers.project_labels_path(project, format: :json)
+ end
+ end
+ end
+
+ # FOSS version doesn't use the aggregated VSA backend
+ def use_aggregated_backend?
+ false
end
- def group_data_attributes
+ def namespace_attributes
+ return {} unless project
+
{
- id: group.id,
- namespace_id: group.id,
- name: group.name,
- full_path: group.full_path,
- avatar_url: group.avatar_url
+ name: project.name,
+ full_path: project.full_path
}
end
@@ -139,28 +157,6 @@ module Gitlab
}
end
- def group_projects(project_ids)
- GroupProjectsFinder.new(
- group: group,
- current_user: current_user,
- options: { include_subgroups: true },
- project_ids_relation: project_ids
- )
- .execute
- .with_route
- .map { |project| project_data_attributes(project) }
- .to_json
- end
-
- def project_data_attributes(project)
- {
- id: project.to_gid.to_s,
- name: project.name,
- path_with_namespace: project.path_with_namespace,
- avatar_url: project.avatar_url
- }
- end
-
def stage_data_attributes
return unless stage
@@ -196,10 +192,18 @@ module Gitlab
return unless value_stream
strong_memoize(:stage) do
- ::Analytics::CycleAnalytics::StageFinder.new(parent: project&.project_namespace || group, stage_id: stage_id).execute if stage_id
+ ::Analytics::CycleAnalytics::StageFinder.new(parent: namespace, stage_id: stage_id).execute if stage_id
+ end
+ end
+
+ def project
+ strong_memoize(:project) do
+ namespace.project if namespace.is_a?(Namespaces::ProjectNamespace)
end
end
end
end
end
end
+
+Gitlab::Analytics::CycleAnalytics::RequestParams.prepend_mod_with('Gitlab::Analytics::CycleAnalytics::RequestParams')
diff --git a/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb b/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb
index 9b4cbc9090c..85dcc773e2b 100644
--- a/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb
+++ b/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start.rb
@@ -6,7 +6,7 @@ module Gitlab
module StageEvents
class PlanStageStart < MetricsBasedStageEvent
def self.name
- s_("CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board")
+ s_("CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board")
end
def self.identifier
diff --git a/lib/gitlab/app_logger.rb b/lib/gitlab/app_logger.rb
index a39e7f31886..40bdc538594 100644
--- a/lib/gitlab/app_logger.rb
+++ b/lib/gitlab/app_logger.rb
@@ -5,7 +5,7 @@ module Gitlab
LOGGERS = [Gitlab::AppTextLogger, Gitlab::AppJsonLogger].freeze
def self.loggers
- if Gitlab::Utils.to_boolean(ENV.fetch('UNSTRUCTURED_RAILS_LOG', 'true'))
+ if Gitlab::Utils.to_boolean(ENV.fetch('UNSTRUCTURED_RAILS_LOG', 'false'))
LOGGERS
else
[Gitlab::AppJsonLogger]
diff --git a/lib/gitlab/application_rate_limiter.rb b/lib/gitlab/application_rate_limiter.rb
index 466538df56e..71629eb701c 100644
--- a/lib/gitlab/application_rate_limiter.rb
+++ b/lib/gitlab/application_rate_limiter.rb
@@ -55,8 +55,12 @@ module Gitlab
phone_verification_verify_code: { threshold: 10, interval: 10.minutes },
namespace_exists: { threshold: 20, interval: 1.minute },
fetch_google_ip_list: { threshold: 10, interval: 1.minute },
+ project_fork_sync: { threshold: 10, interval: 30.minutes },
jobs_index: { threshold: 600, interval: 1.minute },
- bulk_import: { threshold: 6, interval: 1.minute }
+ bulk_import: { threshold: 6, interval: 1.minute },
+ projects_api_rate_limit_unauthenticated: {
+ threshold: -> { application_settings.projects_api_rate_limit_unauthenticated }, interval: 10.minutes
+ }
}.freeze
end
diff --git a/lib/gitlab/audit/auditor.rb b/lib/gitlab/audit/auditor.rb
index fddc1f830aa..e3d2b394404 100644
--- a/lib/gitlab/audit/auditor.rb
+++ b/lib/gitlab/audit/auditor.rb
@@ -5,6 +5,10 @@ module Gitlab
class Auditor
attr_reader :scope, :name
+ PERMITTED_TARGET_CLASSES = [
+ ::Operations::FeatureFlag
+ ].freeze
+
# Record audit events
#
# @param [Hash] context
@@ -113,7 +117,11 @@ module Gitlab
end
def audit_enabled?
- authentication_event?
+ authentication_event? || permitted_target?
+ end
+
+ def permitted_target?
+ @target.class.in? PERMITTED_TARGET_CLASSES
end
def authentication_event?
diff --git a/lib/gitlab/auth/o_auth/user.rb b/lib/gitlab/auth/o_auth/user.rb
index 01e126ec2f5..bb47b4236fb 100644
--- a/lib/gitlab/auth/o_auth/user.rb
+++ b/lib/gitlab/auth/o_auth/user.rb
@@ -233,7 +233,7 @@ module Gitlab
email ||= auth_hash.email
valid_username = ::Namespace.clean_path(username)
- valid_username = Uniquify.new.string(valid_username) { |s| !NamespacePathValidator.valid_path?(s) }
+ valid_username = Gitlab::Utils::Uniquify.new.string(valid_username) { |s| !NamespacePathValidator.valid_path?(s) }
{
name: name.strip.presence || valid_username,
diff --git a/lib/gitlab/auth/otp/duo_auth.rb b/lib/gitlab/auth/otp/duo_auth.rb
new file mode 100644
index 00000000000..eeae04bc08b
--- /dev/null
+++ b/lib/gitlab/auth/otp/duo_auth.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Otp
+ module DuoAuth
+ def duo_auth_enabled?(_user)
+ ::Gitlab.config.duo_auth.enabled
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/otp/strategies/duo_auth/manual_otp.rb b/lib/gitlab/auth/otp/strategies/duo_auth/manual_otp.rb
new file mode 100644
index 00000000000..57bc88de175
--- /dev/null
+++ b/lib/gitlab/auth/otp/strategies/duo_auth/manual_otp.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Otp
+ module Strategies
+ module DuoAuth
+ class ManualOtp < Base
+ include Gitlab::Utils::StrongMemoize
+
+ def validate(otp_code)
+ params = { username: user.username, factor: "passcode", passcode: otp_code.to_i }
+ response = duo_client.request('POST', "/auth/v2/auth", params)
+ approve_or_deny(parse_response(response))
+ rescue StandardError => e
+ Gitlab::AppLogger.error(e)
+ error(e.message)
+ end
+
+ private
+
+ def duo_client
+ DuoApi.new(::Gitlab.config.duo_auth.integration_key,
+ ::Gitlab.config.duo_auth.secret_key,
+ ::Gitlab.config.duo_auth.hostname)
+ end
+ strong_memoize_attr :duo_client
+
+ def parse_response(response)
+ Gitlab::Json.parse(response.body)
+ end
+
+ def approve_or_deny(parsed_response)
+ result_key = parsed_response.dig('response', 'result')
+ if result_key.to_s == "allow"
+ success
+ else
+ error(message: parsed_response.dig('response', 'status_msg').to_s)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/user_access_denied_reason.rb b/lib/gitlab/auth/user_access_denied_reason.rb
index 322dfa74d09..3025960a8ab 100644
--- a/lib/gitlab/auth/user_access_denied_reason.rb
+++ b/lib/gitlab/auth/user_access_denied_reason.rb
@@ -29,7 +29,8 @@ module Gitlab
"Your password expired. "\
"Please access GitLab from a web browser to update your password."
else
- "Your account has been blocked."
+ "Your request has been rejected for an unknown reason."\
+ "Please contact your GitLab administrator and/or GitLab Support."
end
end
diff --git a/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens.rb b/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens.rb
index 82e607ac7a7..6f5ddec628d 100644
--- a/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens.rb
+++ b/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens.rb
@@ -12,7 +12,7 @@ module Gitlab
end
operation_name :update_all
- feature_category :authentication_and_authorization
+ feature_category :system_access
ADMIN_MODE_SCOPE = ['admin_mode'].freeze
diff --git a/lib/gitlab/background_migration/backfill_compliance_violations.rb b/lib/gitlab/background_migration/backfill_compliance_violations.rb
new file mode 100644
index 00000000000..131b4a05e41
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_compliance_violations.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # rubocop: disable Style/Documentation
+ class BackfillComplianceViolations < Gitlab::BackgroundMigration::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::BackfillComplianceViolations.prepend_mod
diff --git a/lib/gitlab/background_migration/backfill_namespace_ldap_settings.rb b/lib/gitlab/background_migration/backfill_namespace_ldap_settings.rb
new file mode 100644
index 00000000000..1a5ad1c14a6
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_namespace_ldap_settings.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Back-fill container_registry_size for project_statistics
+ class BackfillNamespaceLdapSettings < Gitlab::BackgroundMigration::BatchedMigrationJob
+ operation_name :backfill_namespace_ldap_settings
+ feature_category :system_access
+
+ def perform
+ # no-op in FOSS
+ end
+ end
+ end
+end
+
+Gitlab::BackgroundMigration::BackfillNamespaceLdapSettings.prepend_mod
diff --git a/lib/gitlab/background_migration/backfill_prepared_at_merge_requests.rb b/lib/gitlab/background_migration/backfill_prepared_at_merge_requests.rb
new file mode 100644
index 00000000000..9bf503bd6e7
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_prepared_at_merge_requests.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Backfill prepared_at for an array of merge requests
+ class BackfillPreparedAtMergeRequests < ::Gitlab::BackgroundMigration::BatchedMigrationJob
+ scope_to ->(relation) { relation }
+ operation_name :update_all
+ feature_category :code_review_workflow
+
+ def perform
+ each_sub_batch do |sub_batch|
+ sub_batch.where(prepared_at: nil).where.not(merge_status: 'preparing').update_all('prepared_at = created_at')
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_project_wiki_repositories.rb b/lib/gitlab/background_migration/backfill_project_wiki_repositories.rb
new file mode 100644
index 00000000000..8d6df905f15
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_project_wiki_repositories.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Backfill project_wiki_repositories table for a range of projects
+ class BackfillProjectWikiRepositories < BatchedMigrationJob
+ operation_name :backfill_project_wiki_repositories
+ feature_category :geo_replication
+
+ scope_to ->(relation) do
+ relation
+ .joins('LEFT OUTER JOIN project_wiki_repositories ON project_wiki_repositories.project_id = projects.id')
+ .where(project_wiki_repositories: { project_id: nil })
+ end
+
+ def perform
+ each_sub_batch do |sub_batch|
+ backfill_project_wiki_repositories(sub_batch)
+ end
+ end
+
+ def backfill_project_wiki_repositories(relation)
+ connection.execute(
+ <<~SQL
+ INSERT INTO project_wiki_repositories (project_id, created_at, updated_at)
+ SELECT projects.id, now(), now()
+ FROM projects
+ WHERE projects.id IN(#{relation.select(:id).to_sql})
+ ON CONFLICT (project_id) DO NOTHING;
+ SQL
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/batched_migration_job.rb b/lib/gitlab/background_migration/batched_migration_job.rb
index 4039a79cfa7..952e6d01f1a 100644
--- a/lib/gitlab/background_migration/batched_migration_job.rb
+++ b/lib/gitlab/background_migration/batched_migration_job.rb
@@ -7,6 +7,8 @@ module Gitlab
#
# Job arguments needed must be defined explicitly,
# see https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#job-arguments.
+ # rubocop:disable Metrics/ClassLength
+ # rubocop:disable Metrics/ParameterLists
class BatchedMigrationJob
include Gitlab::Database::DynamicModelHelpers
include Gitlab::ClassAttributes
@@ -60,7 +62,8 @@ module Gitlab
end
def initialize(
- start_id:, end_id:, batch_table:, batch_column:, sub_batch_size:, pause_ms:, job_arguments: [], connection:
+ start_id:, end_id:, batch_table:, batch_column:, sub_batch_size:, pause_ms:, job_arguments: [], connection:,
+ sub_batch_exception: nil
)
@start_id = start_id
@@ -71,6 +74,7 @@ module Gitlab
@pause_ms = pause_ms
@job_arguments = job_arguments
@connection = connection
+ @sub_batch_exception = sub_batch_exception
end
def filter_batch(relation)
@@ -87,7 +91,8 @@ module Gitlab
private
- attr_reader :start_id, :end_id, :batch_table, :batch_column, :sub_batch_size, :pause_ms, :connection
+ attr_reader :start_id, :end_id, :batch_table, :batch_column, :sub_batch_size,
+ :pause_ms, :connection, :sub_batch_exception
def each_sub_batch(batching_arguments: {}, batching_scope: nil)
all_batching_arguments = { column: batch_column, of: sub_batch_size }.merge(batching_arguments)
@@ -98,6 +103,10 @@ module Gitlab
sub_batch_relation.each_batch(**all_batching_arguments) do |relation|
batch_metrics.instrument_operation(operation_name) do
yield relation
+ rescue *Gitlab::Database::BackgroundMigration::BatchedJob::TIMEOUT_EXCEPTIONS => exception
+ exception_class = sub_batch_exception || exception.class
+
+ raise exception_class, exception
end
sleep([pause_ms, 0].max * 0.001)
@@ -137,3 +146,5 @@ module Gitlab
end
end
end
+# rubocop:enable Metrics/ClassLength
+# rubocop:enable Metrics/ParameterLists
diff --git a/lib/gitlab/background_migration/create_vulnerability_links.rb b/lib/gitlab/background_migration/create_vulnerability_links.rb
new file mode 100644
index 00000000000..bbc71dfb392
--- /dev/null
+++ b/lib/gitlab/background_migration/create_vulnerability_links.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+# rubocop:disable Style/Documentation
+module Gitlab
+ module BackgroundMigration
+ class CreateVulnerabilityLinks < BatchedMigrationJob
+ feature_category :vulnerability_management
+ def perform; end
+ end
+ end
+end
+
+Gitlab::BackgroundMigration::CreateVulnerabilityLinks.prepend_mod
+# rubocop:enable Style/Documentation
diff --git a/lib/gitlab/background_migration/delete_orphaned_packages_dependencies.rb b/lib/gitlab/background_migration/delete_orphaned_packages_dependencies.rb
new file mode 100644
index 00000000000..a795300fa9d
--- /dev/null
+++ b/lib/gitlab/background_migration/delete_orphaned_packages_dependencies.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Deletes orphaned packages_dependencies records that have no packages_dependency_links
+ class DeleteOrphanedPackagesDependencies < BatchedMigrationJob
+ operation_name :delete_all
+ feature_category :package_registry
+
+ scope_to ->(relation) {
+ relation.where(
+ <<~SQL.squish
+ NOT EXISTS (
+ SELECT 1
+ FROM packages_dependency_links
+ WHERE packages_dependency_links.dependency_id = packages_dependencies.id
+ )
+ SQL
+ )
+ }
+
+ def perform
+ each_sub_batch(&:delete_all)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/fix_vulnerability_reads_has_issues.rb b/lib/gitlab/background_migration/fix_vulnerability_reads_has_issues.rb
new file mode 100644
index 00000000000..5b3b5642ba8
--- /dev/null
+++ b/lib/gitlab/background_migration/fix_vulnerability_reads_has_issues.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # This migration fixes existing `vulnerability_reads` records which did not have `has_issues`
+ # correctly set at the time of creation.
+ class FixVulnerabilityReadsHasIssues < BatchedMigrationJob
+ operation_name :fix_has_issues
+ feature_category :vulnerability_management
+
+ # rubocop:disable Style/Documentation
+ class VulnerabilityRead < ::ApplicationRecord
+ self.table_name = 'vulnerability_reads'
+
+ scope :with_vulnerability_ids, ->(ids) { where(vulnerability_id: ids) }
+ scope :without_issues, -> { where(has_issues: false) }
+ end
+ # rubocop:enable Style/Documentation
+
+ def perform
+ each_sub_batch do |sub_batch|
+ vulnerability_reads_with_issue_links(sub_batch).update_all('has_issues = true')
+ end
+ end
+
+ private
+
+ def vulnerability_reads_with_issue_links(sub_batch)
+ VulnerabilityRead.with_vulnerability_ids(sub_batch.select(:vulnerability_id)).without_issues
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/issues_internal_id_scope_updater.rb b/lib/gitlab/background_migration/issues_internal_id_scope_updater.rb
new file mode 100644
index 00000000000..21ca4392003
--- /dev/null
+++ b/lib/gitlab/background_migration/issues_internal_id_scope_updater.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Migrates internal_ids records for `usage: issues` from project to namespace scope.
+ # For project issues it will be project namespace, for group issues it will be group namespace.
+ class IssuesInternalIdScopeUpdater < ::Gitlab::BackgroundMigration::BatchedMigrationJob
+ operation_name :issues_internal_id_scope_updater
+ feature_category :database
+
+ ISSUES_USAGE = 0 # see Enums::InternalId#usage_resources[:issues]
+
+ scope_to ->(relation) do
+ relation.where(usage: ISSUES_USAGE).where.not(project_id: nil)
+ end
+
+ def perform
+ each_sub_batch do |sub_batch|
+ create_namespace_scoped_records(sub_batch)
+ delete_project_scoped_records(sub_batch)
+ end
+ end
+
+ private
+
+ def delete_project_scoped_records(sub_batch)
+ # There is no need to keep the project scoped issues usage as we move to scoping issues to namespace.
+ # Also in case we do decide to move back to scoping issues usage to project, we are better off if the
+ # project record is not present as that would result in overlapping IIDs because project scoped issues
+ # usage will have outdated IIDs left in the DB
+ log_info("Deleted internal_ids records", ids: sub_batch.pluck(:id))
+
+ connection.execute(
+ <<~SQL
+ DELETE FROM internal_ids WHERE id IN (#{sub_batch.select(:id).to_sql})
+ SQL
+ )
+ end
+
+ def create_namespace_scoped_records(sub_batch)
+ # Creates a corresponding namespace scoped record for every `issues` usage scoped to a project.
+ # On conflict it means the record was already created when a new issue is created with the
+ # newly namespace scoped Issue model, see Issue#has_internal_id definition. In which case to
+ # make sure we have the namespace_id scoped record set to the greatest of the two last_values.
+ created_records_ids = connection.execute(
+ <<~SQL
+ INSERT INTO internal_ids (usage, last_value, namespace_id)
+ SELECT #{ISSUES_USAGE}, last_value, project_namespace_id
+ FROM internal_ids
+ INNER JOIN projects ON projects.id = internal_ids.project_id
+ WHERE internal_ids.id IN(#{sub_batch.select(:id).to_sql})
+ ON CONFLICT (usage, namespace_id) WHERE namespace_id IS NOT NULL
+ DO UPDATE SET last_value = GREATEST(EXCLUDED.last_value, internal_ids.last_value)
+ RETURNING id;
+ SQL
+ )
+
+ log_info("Created/updated internal_ids records", ids: created_records_ids.field_values('id'))
+ end
+
+ def log_info(message, **extra)
+ ::Gitlab::BackgroundMigration::Logger.info(migrator: self.class.to_s, message: message, **extra)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings.rb b/lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings.rb
new file mode 100644
index 00000000000..78a93b49c49
--- /dev/null
+++ b/lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # The class to migrate the evidence data into their own records from the json attribute
+ class MigrateEvidencesForVulnerabilityFindings < BatchedMigrationJob
+ feature_category :vulnerability_management
+ operation_name :migrate_evidences_for_vulnerability_findings
+
+ # The class is mimicking Vulnerabilites::Finding
+ class Finding < ApplicationRecord
+ self.table_name = 'vulnerability_occurrences'
+
+ validates :details, json_schema: { filename: 'vulnerability_finding_details', draft: 7 }, if: false
+ end
+
+ # The class is mimicking Vulnerabilites::Finding::Evidence
+ class Evidence < ApplicationRecord
+ self.table_name = 'vulnerability_finding_evidences'
+
+ # This data has been already validated when parsed into vulnerability_occurrences.raw_metadata
+ # Having this validation is a requerment from:
+ # https://gitlab.com/gitlab-org/gitlab/-/blob/dc3262f850cbd0ac14171d3c389b1258b4749cda/spec/db/schema_spec.rb#L253-265
+ validates :data, json_schema: { filename: "filename" }, if: false
+ end
+
+ def perform
+ each_sub_batch do |sub_batch|
+ migrate_evidences(sub_batch)
+ end
+ end
+
+ private
+
+ def migrate_evidences(sub_batch)
+ attrs = sub_batch.filter_map do |finding|
+ evidence = extract_evidence(finding.raw_metadata)
+
+ next unless evidence
+
+ build_evidence(finding, evidence)
+ end.compact
+
+ begin
+ create_evidences(attrs) if attrs.present?
+ rescue StandardError => e
+ logger.error(
+ message: e.message,
+ class: self.class.name
+ )
+ end
+ end
+
+ def build_evidence(finding, evidence)
+ current_time = Time.current
+ {
+ vulnerability_occurrence_id: finding.id,
+ data: evidence,
+ created_at: current_time,
+ updated_at: current_time
+ }
+ end
+
+ def create_evidences(evidences)
+ Evidence.upsert_all(evidences, returning: false, unique_by: %i[vulnerability_occurrence_id])
+ end
+
+ def extract_evidence(metadata)
+ parsed_metadata = Gitlab::Json.parse(metadata)
+
+ parsed_metadata['evidence']
+ rescue JSON::ParserError
+ nil
+ end
+
+ def logger
+ @logger ||= ::Gitlab::AppLogger
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/migrate_links_for_vulnerability_findings.rb b/lib/gitlab/background_migration/migrate_links_for_vulnerability_findings.rb
new file mode 100644
index 00000000000..222ee4e524e
--- /dev/null
+++ b/lib/gitlab/background_migration/migrate_links_for_vulnerability_findings.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # The class to migrate the link data into their own records from the json attribute
+ class MigrateLinksForVulnerabilityFindings < BatchedMigrationJob
+ feature_category :vulnerability_management
+ operation_name :migrate_links_for_vulnerability_findings
+
+ # The class is mimicking Vulnerabilites::Finding
+ class Finding < ApplicationRecord
+ self.table_name = 'vulnerability_occurrences'
+
+ validates :details, json_schema: { filename: 'vulnerability_finding_details', draft: 7 }, if: false
+ end
+
+ # The class is mimicking Vulnerabilites::FindingLink
+ class Link < ApplicationRecord
+ self.table_name = 'vulnerability_finding_links'
+ end
+
+ def perform
+ each_sub_batch do |sub_batch|
+ migrate_remediations(sub_batch)
+ end
+ end
+
+ private
+
+ def migrate_remediations(sub_batch)
+ sub_batch.each do |finding|
+ links = extract_links(finding.raw_metadata)
+
+ list_of_attrs = links.map do |link|
+ build_link(finding, link)
+ end
+
+ next unless list_of_attrs.present?
+
+ create_links(list_of_attrs)
+ rescue ActiveRecord::RecordNotUnique
+ rescue StandardError => e
+ logger.error(
+ message: e.message,
+ class: self.class.name,
+ model_id: finding.id
+ )
+ end
+ end
+
+ def build_link(finding, link)
+ current_time = Time.current
+ {
+ vulnerability_occurrence_id: finding.id,
+ name: link['name'],
+ url: link['url'],
+ created_at: current_time,
+ updated_at: current_time
+ }
+ end
+
+ def create_links(attributes)
+ Link.upsert_all(attributes, returning: false)
+ end
+
+ def extract_links(metadata)
+ parsed_metadata = Gitlab::Json.parse(metadata)
+
+ return [] unless parsed_metadata['links']
+
+ parsed_metadata['links'].compact.uniq
+ end
+
+ def logger
+ @logger ||= ::Gitlab::AppLogger
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings.rb b/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings.rb
new file mode 100644
index 00000000000..9eadef96db6
--- /dev/null
+++ b/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings.rb
@@ -0,0 +1,164 @@
+# frozen_string_literal: true
+
+module Vulnerabilities
+ # The class is mimicking Vulnerabilites::Remediation
+ class Remediation < ApplicationRecord
+ include FileStoreMounter
+ include ShaAttribute
+
+ self.table_name = 'vulnerability_remediations'
+
+ sha_attribute :checksum
+
+ mount_file_store_uploader AttachmentUploader
+
+ def retrieve_upload(_identifier, paths)
+ Upload.find_by(model: self, path: paths)
+ end
+ end
+end
+
+module Gitlab
+ module BackgroundMigration
+ # The class to migrate the remediation data into their own records from the json attribute
+ class MigrateRemediationsForVulnerabilityFindings < BatchedMigrationJob
+ feature_category :vulnerability_management
+ operation_name :migrate_remediations_for_vulnerability_findings
+
+ # The class to encapsulate checksum and file for uploading
+ class DiffFile < StringIO
+ # This method is used by the `carrierwave` gem
+ def original_filename
+ @original_filename ||= self.class.original_filename(checksum)
+ end
+
+ def checksum
+ @checksum ||= self.class.checksum(string)
+ end
+
+ def self.checksum(value)
+ Digest::SHA256.hexdigest(value)
+ end
+
+ def self.original_filename(checksum)
+ "#{checksum}.diff"
+ end
+ end
+
+ # The class is mimicking Vulnerabilites::Finding
+ class Finding < ApplicationRecord
+ self.table_name = 'vulnerability_occurrences'
+
+ validates :details, json_schema: { filename: 'vulnerability_finding_details', draft: 7 }, if: false
+ end
+
+ # The class is mimicking Vulnerabilites::FindingRemediation
+ class FindingRemediation < ApplicationRecord
+ self.table_name = 'vulnerability_findings_remediations'
+ end
+
+ def perform
+ each_sub_batch do |sub_batch|
+ migrate_remediations(sub_batch)
+ end
+ end
+
+ private
+
+ def migrate_remediations(sub_batch)
+ sub_batch.each do |finding|
+ FindingRemediation.transaction do
+ remediations = append_remediations_diff_checksum(finding.raw_metadata)
+
+ result_ids = create_remediations(finding, remediations)
+
+ create_finding_remediations(finding.id, result_ids)
+ end
+ rescue StandardError => e
+ logger.error(
+ message: e.message,
+ class: self.class.name,
+ model_id: finding.id
+ )
+ end
+ end
+
+ def create_finding_remediations(finding_id, result_ids)
+ attrs = result_ids.map do |result_id|
+ build_finding_remediation_attrs(finding_id, result_id)
+ end
+
+ return unless attrs.present?
+
+ FindingRemediation.upsert_all(
+ attrs,
+ returning: false,
+ unique_by: [:vulnerability_occurrence_id, :vulnerability_remediation_id]
+ )
+ end
+
+ def create_remediations(finding, remediations)
+ attrs = remediations.map do |remediation|
+ build_remediation_attrs(finding, remediation)
+ end
+
+ return [] unless attrs.present?
+
+ ids_checksums = ::Vulnerabilities::Remediation.upsert_all(
+ attrs,
+ returning: %w[id checksum],
+ unique_by: [:project_id, :checksum]
+ )
+
+ ids_checksums.each do |id_checksum|
+ upload_file(id_checksum['id'], id_checksum['checksum'], remediations)
+ end
+
+ ids_checksums.pluck('id')
+ end
+
+ def upload_file(id, checksum, remediations)
+ deserialized_checksum = Gitlab::Database::ShaAttribute.new.deserialize(checksum)
+ diff = remediations.find { |rem| rem['checksum'] == deserialized_checksum }["diff"]
+ file = DiffFile.new(diff)
+ ::Vulnerabilities::Remediation.find_by(id: id).update!(file: file)
+ end
+
+ def build_remediation_attrs(finding, remediation)
+ {
+ project_id: finding.project_id,
+ summary: remediation['summary'],
+ file: DiffFile.original_filename(remediation['checksum']),
+ checksum: remediation['checksum'],
+ created_at: Time.current,
+ updated_at: Time.current
+ }
+ end
+
+ def build_finding_remediation_attrs(finding_id, remediation_id)
+ {
+ vulnerability_occurrence_id: finding_id,
+ vulnerability_remediation_id: remediation_id,
+ created_at: Time.current,
+ updated_at: Time.current
+ }
+ end
+
+ def append_remediations_diff_checksum(metadata)
+ parsed_metadata = Gitlab::Json.parse(metadata)
+
+ return [] unless parsed_metadata['remediations']
+
+ parsed_metadata['remediations'].filter_map do |remediation|
+ next unless remediation && remediation['diff'].present?
+
+ remediation.merge('checksum' => DiffFile.checksum(remediation['diff']))
+ end.compact.uniq
+ end
+
+ def logger
+ @logger ||= ::Gitlab::AppLogger
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index 3dafe7c8962..592e75b1430 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -72,7 +72,7 @@ module Gitlab
return unless last_bitbucket_issue
- Issue.track_project_iid!(project, last_bitbucket_issue.iid)
+ Issue.track_namespace_iid!(project.project_namespace, last_bitbucket_issue.iid)
end
def repo
diff --git a/lib/gitlab/cache/client.rb b/lib/gitlab/cache/client.rb
new file mode 100644
index 00000000000..ac710ee0adf
--- /dev/null
+++ b/lib/gitlab/cache/client.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Cache
+ # It replaces Rails.cache with metrics support
+ class Client
+ DEFAULT_BACKING_RESOURCE = :unknown
+
+ # Build Cache client with the metadata support
+ #
+ # @param cache_identifier [String] defines the location of the cache definition
+ # Example: "ProtectedBranches::CacheService#fetch"
+ # @param feature_category [Symbol] name of the feature category (from config/feature_categories.yml)
+ # @param caller_id [String] caller id from labkit context
+ # @param backing_resource [Symbol] most affected resource by cache generation (full list: VALID_BACKING_RESOURCES)
+ # @return [Gitlab::Cache::Client]
+ def self.build_with_metadata(
+ cache_identifier:,
+ feature_category:,
+ caller_id: Gitlab::ApplicationContext.current_context_attribute(:caller_id),
+ backing_resource: DEFAULT_BACKING_RESOURCE
+ )
+ new(Metadata.new(
+ caller_id: caller_id,
+ cache_identifier: cache_identifier,
+ feature_category: feature_category,
+ backing_resource: backing_resource
+ ))
+ end
+
+ def initialize(metadata, backend: Rails.cache)
+ @metadata = metadata
+ @metrics = Metrics.new(metadata)
+ @backend = backend
+ end
+
+ def read(name)
+ read_result = backend.read(name)
+
+ if read_result.nil?
+ metrics.increment_cache_miss
+ else
+ metrics.increment_cache_hit
+ end
+
+ read_result
+ end
+
+ def fetch(name, options = nil, &block)
+ read_result = read(name)
+
+ return read_result unless block || read_result
+
+ backend.fetch(name, options) do
+ metrics.observe_cache_generation(&block)
+ end
+ end
+
+ delegate :write, :exist?, :delete, to: :backend
+
+ attr_reader :metadata, :metrics
+
+ private
+
+ attr_reader :backend
+ end
+ end
+end
diff --git a/lib/gitlab/cache/metadata.rb b/lib/gitlab/cache/metadata.rb
index d6c89b5b2c3..224f215ef82 100644
--- a/lib/gitlab/cache/metadata.rb
+++ b/lib/gitlab/cache/metadata.rb
@@ -5,13 +5,18 @@ module Gitlab
# Value object for cache metadata
class Metadata
VALID_BACKING_RESOURCES = [:cpu, :database, :gitaly, :memory, :unknown].freeze
- DEFAULT_BACKING_RESOURCE = :unknown
+ # @param cache_identifier [String] defines the location of the cache definition
+ # Example: "ProtectedBranches::CacheService#fetch"
+ # @param feature_category [Symbol] name of the feature category (from config/feature_categories.yml)
+ # @param caller_id [String] caller id from labkit context
+ # @param backing_resource [Symbol] most affected resource by cache generation (full list: VALID_BACKING_RESOURCES)
+ # @return [Gitlab::Cache::Metadata]
def initialize(
cache_identifier:,
feature_category:,
caller_id: Gitlab::ApplicationContext.current_context_attribute(:caller_id),
- backing_resource: DEFAULT_BACKING_RESOURCE
+ backing_resource: Client::DEFAULT_BACKING_RESOURCE
)
@cache_identifier = cache_identifier
@feature_category = Gitlab::FeatureCategories.default.get!(feature_category)
@@ -28,7 +33,7 @@ module Gitlab
raise "Unknown backing resource: #{resource}" if Gitlab.dev_or_test_env?
- DEFAULT_BACKING_RESOURCE
+ Client::DEFAULT_BACKING_RESOURCE
end
end
end
diff --git a/lib/gitlab/changes_list.rb b/lib/gitlab/changes_list.rb
index 999d2ee4356..ca55692ca2f 100644
--- a/lib/gitlab/changes_list.rb
+++ b/lib/gitlab/changes_list.rb
@@ -15,12 +15,12 @@ module Gitlab
end
def changes
- @changes ||= @raw_changes.map do |change|
+ @changes ||= @raw_changes.filter_map do |change|
next if change.blank?
oldrev, newrev, ref = change.strip.split(' ')
{ oldrev: oldrev, newrev: newrev, ref: ref }
- end.compact
+ end
end
end
end
diff --git a/lib/gitlab/chat/responder.rb b/lib/gitlab/chat/responder.rb
index 478be5bd350..7ec64b7cfbf 100644
--- a/lib/gitlab/chat/responder.rb
+++ b/lib/gitlab/chat/responder.rb
@@ -11,21 +11,13 @@ module Gitlab
#
# build - A `Ci::Build` that executed a chat command.
def self.responder_for(build)
- if Feature.enabled?(:use_response_url_for_chat_responder)
- response_url = build.pipeline.chat_data&.response_url
- return unless response_url
+ response_url = build.pipeline.chat_data&.response_url
+ return unless response_url
- if response_url.start_with?('https://hooks.slack.com/')
- Gitlab::Chat::Responder::Slack.new(build)
- else
- Gitlab::Chat::Responder::Mattermost.new(build)
- end
+ if response_url.start_with?('https://hooks.slack.com/')
+ Gitlab::Chat::Responder::Slack.new(build)
else
- integration = build.pipeline.chat_data&.chat_name&.integration
-
- if (responder = integration.try(:chat_responder))
- responder.new(build)
- end
+ Gitlab::Chat::Responder::Mattermost.new(build)
end
end
end
diff --git a/lib/gitlab/checks/base_single_checker.rb b/lib/gitlab/checks/base_single_checker.rb
index 435f4ccf5ba..755778efa60 100644
--- a/lib/gitlab/checks/base_single_checker.rb
+++ b/lib/gitlab/checks/base_single_checker.rb
@@ -5,7 +5,7 @@ module Gitlab
class BaseSingleChecker < BaseChecker
attr_reader :change_access
- delegate(*SingleChangeAccess::ATTRIBUTES, to: :change_access)
+ delegate(*SingleChangeAccess::ATTRIBUTES, :branch_ref?, :tag_ref?, to: :change_access)
def initialize(change_access)
@change_access = change_access
diff --git a/lib/gitlab/checks/changes_access.rb b/lib/gitlab/checks/changes_access.rb
index 99752dc6a01..194e3f6e938 100644
--- a/lib/gitlab/checks/changes_access.rb
+++ b/lib/gitlab/checks/changes_access.rb
@@ -36,13 +36,13 @@ module Gitlab
# any of the new revisions.
def commits
strong_memoize(:commits) do
- newrevs = @changes.map do |change|
+ newrevs = @changes.filter_map do |change|
newrev = change[:newrev]
next if blank_rev?(newrev)
newrev
- end.compact
+ end
next [] if newrevs.empty?
@@ -89,7 +89,7 @@ module Gitlab
@single_changes_accesses ||=
changes.map do |change|
commits =
- if blank_rev?(change[:newrev])
+ if !commitish_ref?(change[:ref]) || blank_rev?(change[:newrev])
[]
else
Gitlab::Lazy.new { commits_for(change[:oldrev], change[:newrev]) }
@@ -122,6 +122,14 @@ module Gitlab
def blank_rev?(rev)
rev.blank? || Gitlab::Git.blank_ref?(rev)
end
+
+ # refs/notes/commits contains commits added via `git-notes`. We currently
+ # have no features that check notes so we can skip them. To future-proof
+ # we are skipping anything that isn't a branch or tag ref as those are
+ # the only refs that can contain commits.
+ def commitish_ref?(ref)
+ Gitlab::Git.branch_ref?(ref) || Gitlab::Git.tag_ref?(ref)
+ end
end
end
end
diff --git a/lib/gitlab/checks/diff_check.rb b/lib/gitlab/checks/diff_check.rb
index d8f5cec8a4a..083c2448a0a 100644
--- a/lib/gitlab/checks/diff_check.rb
+++ b/lib/gitlab/checks/diff_check.rb
@@ -10,6 +10,10 @@ module Gitlab
}.freeze
def validate!
+ # git-notes stores notes history as commits in refs/notes/commits (by
+ # default but is configurable) so we restrict the diff checks to tag
+ # and branch refs
+ return unless tag_ref? || branch_ref?
return if deletion?
return unless should_run_validations?
return if commits.empty?
diff --git a/lib/gitlab/checks/single_change_access.rb b/lib/gitlab/checks/single_change_access.rb
index 2fd48dfbfe2..9f427e98e55 100644
--- a/lib/gitlab/checks/single_change_access.rb
+++ b/lib/gitlab/checks/single_change_access.rb
@@ -14,7 +14,9 @@ module Gitlab
protocol:, logger:, commits: nil
)
@oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref)
+ @branch_ref = Gitlab::Git.branch_ref?(@ref)
@branch_name = Gitlab::Git.branch_name(@ref)
+ @tag_ref = Gitlab::Git.tag_ref?(@ref)
@tag_name = Gitlab::Git.tag_name(@ref)
@user_access = user_access
@project = project
@@ -38,6 +40,14 @@ module Gitlab
@commits ||= project.repository.new_commits(newrev)
end
+ def branch_ref?
+ @branch_ref
+ end
+
+ def tag_ref?
+ @tag_ref
+ end
+
protected
def ref_level_checks
diff --git a/lib/gitlab/ci/badge/release/latest_release.rb b/lib/gitlab/ci/badge/release/latest_release.rb
index e73bb2a912a..8d84a54787b 100644
--- a/lib/gitlab/ci/badge/release/latest_release.rb
+++ b/lib/gitlab/ci/badge/release/latest_release.rb
@@ -10,7 +10,8 @@ module Gitlab::Ci
@project = project
@customization = {
key_width: opts[:key_width] ? opts[:key_width].to_i : nil,
- key_text: opts[:key_text]
+ key_text: opts[:key_text],
+ value_width: opts[:value_width] ? opts[:value_width].to_i : nil
}
# In the future, we should support `order_by=semver` for showing the
diff --git a/lib/gitlab/ci/badge/release/template.rb b/lib/gitlab/ci/badge/release/template.rb
index 354be6276fa..549742226a1 100644
--- a/lib/gitlab/ci/badge/release/template.rb
+++ b/lib/gitlab/ci/badge/release/template.rb
@@ -11,9 +11,11 @@ module Gitlab::Ci
}.freeze
KEY_WIDTH_DEFAULT = 90
VALUE_WIDTH_DEFAULT = 54
+ VALUE_WIDTH_MAXIMUM = 200
def initialize(badge)
@tag = badge.tag || "none"
+ @value_width = badge.customization[:value_width]
super
end
@@ -30,7 +32,11 @@ module Gitlab::Ci
end
def value_width
- VALUE_WIDTH_DEFAULT
+ if @value_width && @value_width.between?(1, VALUE_WIDTH_MAXIMUM)
+ @value_width
+ else
+ VALUE_WIDTH_DEFAULT
+ end
end
def value_color
diff --git a/lib/gitlab/ci/components/header.rb b/lib/gitlab/ci/components/header.rb
new file mode 100644
index 00000000000..732874d7a88
--- /dev/null
+++ b/lib/gitlab/ci/components/header.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Components
+ ##
+ # Components::Header class represents full component specification that is being prepended as first YAML document
+ # in the CI Component file.
+ #
+ class Header
+ attr_reader :errors
+
+ def initialize(header)
+ @header = header
+ @errors = []
+ end
+
+ def empty?
+ inputs_spec.to_h.empty?
+ end
+
+ def inputs(args)
+ @input ||= Ci::Input::Inputs.new(inputs_spec, args)
+ end
+
+ def context(args)
+ inputs(args).then do |input|
+ raise ArgumentError unless input.valid?
+
+ Ci::Interpolation::Context.new({ inputs: input.to_hash })
+ end
+ end
+
+ private
+
+ def inputs_spec
+ @header.dig(:spec, :inputs)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 585e671ce42..534b84afc23 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -21,14 +21,15 @@ module Gitlab
attr_reader :root, :context, :source_ref_path, :source, :logger
- def initialize(config, project: nil, pipeline: nil, sha: nil, user: nil, parent_pipeline: nil, source: nil, logger: nil)
+ # rubocop: disable Metrics/ParameterLists
+ def initialize(config, project: nil, pipeline: nil, sha: nil, user: nil, parent_pipeline: nil, source: nil, pipeline_config: nil, logger: nil)
@logger = logger || ::Gitlab::Ci::Pipeline::Logger.new(project: project)
@source_ref_path = pipeline&.source_ref_path
@project = project
@context = self.logger.instrument(:config_build_context, once: true) do
pipeline ||= ::Ci::Pipeline.new(project: project, sha: sha, user: user, source: source)
- build_context(project: project, pipeline: pipeline, sha: sha, user: user, parent_pipeline: parent_pipeline)
+ build_context(project: project, pipeline: pipeline, sha: sha, user: user, parent_pipeline: parent_pipeline, pipeline_config: pipeline_config)
end
@context.set_deadline(TIMEOUT_SECONDS)
@@ -49,6 +50,7 @@ module Gitlab
rescue *rescue_errors => e
raise Config::ConfigError, e.message
end
+ # rubocop: enable Metrics/ParameterLists
def valid?
@root.valid?
@@ -117,8 +119,7 @@ module Gitlab
def expand_config(config)
build_config(config)
- rescue Gitlab::Config::Loader::Yaml::DataTooLargeError,
- Gitlab::Config::Loader::MultiDocYaml::DataTooLargeError => e
+ rescue Gitlab::Config::Loader::Yaml::DataTooLargeError => e
track_and_raise_for_dev_exception(e)
raise Config::ConfigError, e.message
@@ -157,13 +158,14 @@ module Gitlab
end
end
- def build_context(project:, pipeline:, sha:, user:, parent_pipeline:)
+ def build_context(project:, pipeline:, sha:, user:, parent_pipeline:, pipeline_config:)
Config::External::Context.new(
project: project,
sha: sha || find_sha(project),
user: user,
parent_pipeline: parent_pipeline,
variables: build_variables(pipeline: pipeline),
+ pipeline_config: pipeline_config,
logger: logger)
end
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index 7c49b59a7f0..2390ba05916 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -164,7 +164,7 @@ module Gitlab
artifacts: artifacts_value,
release: release_value,
after_script: after_script_value,
- hooks: hooks_pre_get_sources_script_enabled? ? hooks_value : nil,
+ hooks: hooks_value,
ignore: ignored?,
allow_failure_criteria: allow_failure_criteria,
needs: needs_defined? ? needs_value : nil,
@@ -194,10 +194,6 @@ module Gitlab
allow_failure_value
end
-
- def hooks_pre_get_sources_script_enabled?
- YamlProcessor::FeatureFlags.enabled?(:ci_hooks_pre_get_sources_script)
- end
end
end
end
diff --git a/lib/gitlab/ci/config/external/context.rb b/lib/gitlab/ci/config/external/context.rb
index 6eef279d3de..156109a084d 100644
--- a/lib/gitlab/ci/config/external/context.rb
+++ b/lib/gitlab/ci/config/external/context.rb
@@ -9,29 +9,30 @@ module Gitlab
TimeoutError = Class.new(StandardError)
- MAX_INCLUDES = 100
- NEW_MAX_INCLUDES = 150 # Update to MAX_INCLUDES when FF ci_includes_count_duplicates is removed
+ MAX_INCLUDES = 150
+ TEMP_MAX_INCLUDES = 100 # For logging; to be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/367150
include ::Gitlab::Utils::StrongMemoize
- attr_reader :project, :sha, :user, :parent_pipeline, :variables
+ attr_reader :project, :sha, :user, :parent_pipeline, :variables, :pipeline_config
attr_reader :expandset, :execution_deadline, :logger, :max_includes
delegate :instrument, to: :logger
def initialize(
project: nil, sha: nil, user: nil, parent_pipeline: nil, variables: nil,
- logger: nil
+ pipeline_config: nil, logger: nil
)
@project = project
@sha = sha
@user = user
@parent_pipeline = parent_pipeline
@variables = variables || Ci::Variables::Collection.new
- @expandset = Feature.enabled?(:ci_includes_count_duplicates, project) ? [] : Set.new
+ @pipeline_config = pipeline_config
+ @expandset = []
@execution_deadline = 0
@logger = logger || Gitlab::Ci::Pipeline::Logger.new(project: project)
- @max_includes = Feature.enabled?(:ci_includes_count_duplicates, project) ? NEW_MAX_INCLUDES : MAX_INCLUDES
+ @max_includes = MAX_INCLUDES
yield self if block_given?
end
@@ -91,6 +92,13 @@ module Gitlab
expandset.map(&:metadata)
end
+ # Some Ci::ProjectConfig sources prepend the config content with an "internal" `include`, which becomes
+ # the first included file. When running a pipeline, we pass pipeline_config into the context of the first
+ # included file, which we use in this method to determine if the file is an "internal" one.
+ def internal_include?
+ !!pipeline_config&.internal_include_prepended?
+ end
+
protected
attr_writer :expandset, :execution_deadline, :logger, :max_includes
diff --git a/lib/gitlab/ci/config/external/file/base.rb b/lib/gitlab/ci/config/external/file/base.rb
index 84f34f2584b..7060754a670 100644
--- a/lib/gitlab/ci/config/external/file/base.rb
+++ b/lib/gitlab/ci/config/external/file/base.rb
@@ -73,6 +73,18 @@ module Gitlab
validate_hash!
end
+ # This method is overridden to load context into the memoized result
+ # or to lazily load context via BatchLoader
+ def preload_context
+ # no-op
+ end
+
+ def preload_content
+ # calling the `content` method either loads content into the memoized result
+ # or lazily loads it via BatchLoader
+ content
+ end
+
def validate_location!
if invalid_location_type?
errors.push("Included file `#{masked_location}` needs to be a string")
@@ -93,6 +105,19 @@ module Gitlab
protected
+ def content_result
+ strong_memoize(:content_hash) do
+ ::Gitlab::Ci::Config::Yaml
+ .load_result!(content, project: context.project)
+ end
+ end
+
+ def content_hash
+ return unless content_result.valid?
+
+ content_result.content
+ end
+
def expanded_content_hash
return unless content_hash
@@ -101,14 +126,6 @@ module Gitlab
end
end
- def content_hash
- strong_memoize(:content_hash) do
- ::Gitlab::Ci::Config::Yaml.load!(content)
- end
- rescue Gitlab::Config::Loader::FormatError
- nil
- end
-
def validate_hash!
if to_hash.blank?
errors.push("Included file `#{masked_location}` does not have valid YAML syntax!")
diff --git a/lib/gitlab/ci/config/external/file/component.rb b/lib/gitlab/ci/config/external/file/component.rb
index 33e7724bf9b..7ab7dc3d64e 100644
--- a/lib/gitlab/ci/config/external/file/component.rb
+++ b/lib/gitlab/ci/config/external/file/component.rb
@@ -15,7 +15,7 @@ module Gitlab
end
def matching?
- super && ::Feature.enabled?(:ci_include_components, context.project)
+ super && ::Feature.enabled?(:ci_include_components, context.project&.root_namespace)
end
def content
diff --git a/lib/gitlab/ci/config/external/file/project.rb b/lib/gitlab/ci/config/external/file/project.rb
index f8d4cb27710..5efefeeaf9d 100644
--- a/lib/gitlab/ci/config/external/file/project.rb
+++ b/lib/gitlab/ci/config/external/file/project.rb
@@ -15,7 +15,8 @@ module Gitlab
# `Repository#blobs_at` does not support files with the `/` prefix.
@location = Gitlab::Utils.remove_leading_slashes(params[:file])
- @project_name = get_project_name(params[:project])
+ # We are using the same downcase in the `project` method.
+ @project_name = get_project_name(params[:project]).to_s.downcase
@ref_name = params[:ref] || 'HEAD'
super
@@ -39,6 +40,15 @@ module Gitlab
)
end
+ def preload_context
+ #
+ # calling these methods lazily loads them via BatchLoader
+ #
+ project
+ can_access_local_content?
+ sha
+ end
+
def validate_context!
if !can_access_local_content?
errors.push("Project `#{masked_project_name}` not found or access denied! Make sure any includes in the pipeline configuration are correctly defined.")
@@ -58,21 +68,48 @@ module Gitlab
private
def project
- strong_memoize(:project) do
- ::Project.find_by_full_path(project_name)
+ return legacy_project if ::Feature.disabled?(:ci_batch_project_includes_context, context.project)
+
+ # Although we use `where_full_path_in`, this BatchLoader does not reduce the number of queries to 1.
+ # That's because we use it in the `can_access_local_content?` and `sha` BatchLoaders
+ # as the `for` parameter. And this loads the project immediately.
+ BatchLoader.for(project_name)
+ .batch do |project_names, loader|
+ ::Project.where_full_path_in(project_names.uniq).each do |project|
+ # We are using the same downcase in the `initialize` method.
+ loader.call(project.full_path.downcase, project)
+ end
end
end
def can_access_local_content?
- strong_memoize(:can_access_local_content) do
- context.logger.instrument(:config_file_project_validate_access) do
- Ability.allowed?(context.user, :download_code, project)
+ if ::Feature.disabled?(:ci_batch_project_includes_context, context.project)
+ return legacy_can_access_local_content?
+ end
+
+ BatchLoader.for(project)
+ .batch(key: context.user) do |projects, loader, args|
+ projects.uniq.each do |project|
+ context.logger.instrument(:config_file_project_validate_access) do
+ loader.call(project, Ability.allowed?(args[:key], :download_code, project))
+ end
+ end
+ end
+ end
+
+ def sha
+ return legacy_sha if ::Feature.disabled?(:ci_batch_project_includes_context, context.project)
+
+ BatchLoader.for([project, ref_name])
+ .batch do |project_ref_pairs, loader|
+ project_ref_pairs.uniq.each do |project, ref_name|
+ loader.call([project, ref_name], project.commit(ref_name).try(:sha))
end
end
end
def fetch_local_content
- BatchLoader.for([sha, location])
+ BatchLoader.for([sha.to_s, location])
.batch(key: project) do |locations, loader, args|
context.logger.instrument(:config_file_fetch_project_content) do
args[:key].repository.blobs_at(locations).each do |blob|
@@ -84,8 +121,22 @@ module Gitlab
end
end
- def sha
- strong_memoize(:sha) do
+ def legacy_project
+ strong_memoize(:legacy_project) do
+ ::Project.find_by_full_path(project_name)
+ end
+ end
+
+ def legacy_can_access_local_content?
+ strong_memoize(:legacy_can_access_local_content) do
+ context.logger.instrument(:config_file_project_validate_access) do
+ Ability.allowed?(context.user, :download_code, project)
+ end
+ end
+ end
+
+ def legacy_sha
+ strong_memoize(:legacy_sha) do
project.commit(ref_name).try(:sha)
end
end
@@ -94,7 +145,7 @@ module Gitlab
def expand_context_attrs
{
project: project,
- sha: sha,
+ sha: sha.to_s, # we need to use `.to_s` to load the value from the BatchLoader
user: context.user,
parent_pipeline: context.parent_pipeline,
variables: context.variables
diff --git a/lib/gitlab/ci/config/external/mapper/verifier.rb b/lib/gitlab/ci/config/external/mapper/verifier.rb
index 2982b0efb6c..7284d2a7e01 100644
--- a/lib/gitlab/ci/config/external/mapper/verifier.rb
+++ b/lib/gitlab/ci/config/external/mapper/verifier.rb
@@ -9,8 +9,56 @@ module Gitlab
class Verifier < Base
private
+ # rubocop: disable Metrics/CyclomaticComplexity
def process_without_instrumentation(files)
+ if ::Feature.disabled?(:ci_batch_project_includes_context, context.project)
+ return legacy_process_without_instrumentation(files)
+ end
+
files.each do |file|
+ if YamlProcessor::FeatureFlags.enabled?(:ci_fix_max_includes)
+ # When running a pipeline, some Ci::ProjectConfig sources prepend the config content with an
+ # "internal" `include`. We use this condition to exclude that `include` from the included file set.
+ context.expandset << file unless context.internal_include?
+ verify_max_includes!
+ end
+
+ verify_execution_time!
+
+ file.validate_location!
+ file.preload_context if file.valid?
+ end
+
+ # We do not combine the loops because we need to load the context of all files via `BatchLoader`.
+ files.each do |file| # rubocop:disable Style/CombinableLoops
+ verify_execution_time!
+
+ file.validate_context! if file.valid?
+ file.preload_content if file.valid?
+ end
+
+ # We do not combine the loops because we need to load the content of all files via `BatchLoader`.
+ files.each do |file| # rubocop:disable Style/CombinableLoops
+ verify_max_includes! unless YamlProcessor::FeatureFlags.enabled?(:ci_fix_max_includes)
+ verify_execution_time!
+
+ file.validate_content! if file.valid?
+ file.load_and_validate_expanded_hash! if file.valid?
+
+ context.expandset << file unless YamlProcessor::FeatureFlags.enabled?(:ci_fix_max_includes)
+ end
+ end
+ # rubocop: enable Metrics/CyclomaticComplexity
+
+ def legacy_process_without_instrumentation(files)
+ files.each do |file|
+ if YamlProcessor::FeatureFlags.enabled?(:ci_fix_max_includes)
+ # When running a pipeline, some Ci::ProjectConfig sources prepend the config content with an
+ # "internal" `include`. We use this condition to exclude that `include` from the included file set.
+ context.expandset << file unless context.internal_include?
+ verify_max_includes!
+ end
+
verify_execution_time!
file.validate_location!
@@ -21,23 +69,22 @@ module Gitlab
# We do not combine the loops because we need to load the content of all files before continuing
# to call `BatchLoader` for all locations.
files.each do |file| # rubocop:disable Style/CombinableLoops
- # Checking the max includes will be changed with https://gitlab.com/gitlab-org/gitlab/-/issues/367150
- verify_max_includes!
+ verify_max_includes! unless YamlProcessor::FeatureFlags.enabled?(:ci_fix_max_includes)
verify_execution_time!
file.validate_content! if file.valid?
file.load_and_validate_expanded_hash! if file.valid?
- if context.expandset.is_a?(Array) # To be removed when FF 'ci_includes_count_duplicates' is removed
- context.expandset << file
- else
- context.expandset.add(file)
- end
+ context.expandset << file unless YamlProcessor::FeatureFlags.enabled?(:ci_fix_max_includes)
end
end
def verify_max_includes!
- return if context.expandset.count < context.max_includes
+ if YamlProcessor::FeatureFlags.enabled?(:ci_fix_max_includes)
+ return if context.expandset.count <= context.max_includes
+ else
+ return if context.expandset.count < context.max_includes # rubocop:disable Style/IfInsideElse
+ end
raise Mapper::TooManyIncludesError, "Maximum of #{context.max_includes} nested includes are allowed!"
end
diff --git a/lib/gitlab/ci/config/header/input.rb b/lib/gitlab/ci/config/header/input.rb
new file mode 100644
index 00000000000..525b009afe3
--- /dev/null
+++ b/lib/gitlab/ci/config/header/input.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Header
+ ##
+ # Input parameter used for interpolation with the CI configuration.
+ class Input < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+ include ::Gitlab::Config::Entry::Attributable
+
+ attributes :default, prefix: :input
+
+ validations do
+ validates :config, type: Hash, allowed_keys: [:default]
+ validates :key, alphanumeric: true
+ validates :input_default, alphanumeric: true, allow_nil: true
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/header/root.rb b/lib/gitlab/ci/config/header/root.rb
new file mode 100644
index 00000000000..251682d13b4
--- /dev/null
+++ b/lib/gitlab/ci/config/header/root.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Header
+ ##
+ # This class represents the root entry of the GitLab CI configuration header.
+ #
+ # A header is the first document in a multi-doc YAML that contains metadata
+ # and specifications about the GitLab CI configuration (the second document).
+ #
+ # The header is optional. A CI configuration can also be represented with a
+ # YAML containing a single document.
+ class Root < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Configurable
+
+ ALLOWED_KEYS = %i[spec].freeze
+
+ validations do
+ validates :config, type: Hash, allowed_keys: ALLOWED_KEYS
+ end
+
+ entry :spec, Header::Spec,
+ description: 'Specifications of the CI configuration.',
+ inherit: false,
+ default: {}
+
+ def inputs_value
+ spec_entry.inputs_value
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/header/spec.rb b/lib/gitlab/ci/config/header/spec.rb
new file mode 100644
index 00000000000..98d6d0d5783
--- /dev/null
+++ b/lib/gitlab/ci/config/header/spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Header
+ class Spec < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Configurable
+
+ ALLOWED_KEYS = %i[inputs].freeze
+
+ validations do
+ validates :config, type: Hash, allowed_keys: ALLOWED_KEYS
+ end
+
+ entry :inputs, ::Gitlab::Config::Entry::ComposableHash,
+ description: 'Allowed input parameters used for interpolation.',
+ inherit: false,
+ metadata: { composable_class: ::Gitlab::Ci::Config::Header::Input }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/yaml.rb b/lib/gitlab/ci/config/yaml.rb
index 94ef0afe7f9..d1b1b8caa5c 100644
--- a/lib/gitlab/ci/config/yaml.rb
+++ b/lib/gitlab/ci/config/yaml.rb
@@ -7,23 +7,38 @@ module Gitlab
AVAILABLE_TAGS = [Config::Yaml::Tags::Reference].freeze
MAX_DOCUMENTS = 2
- class << self
- def load!(content)
+ class Loader
+ def initialize(content, project: nil)
+ @content = content
+ @project = project
+ end
+
+ def load!
ensure_custom_tags
- if ::Feature.enabled?(:ci_multi_doc_yaml)
- Gitlab::Config::Loader::MultiDocYaml.new(
+ if project.present? && ::Feature.enabled?(:ci_multi_doc_yaml, project)
+ ::Gitlab::Config::Loader::MultiDocYaml.new(
content,
max_documents: MAX_DOCUMENTS,
additional_permitted_classes: AVAILABLE_TAGS
- ).load!.first
+ ).load!
else
- Gitlab::Config::Loader::Yaml.new(content, additional_permitted_classes: AVAILABLE_TAGS).load!
+ ::Gitlab::Config::Loader::Yaml
+ .new(content, additional_permitted_classes: AVAILABLE_TAGS)
+ .load!
end
end
+ def to_result
+ Yaml::Result.new(config: load!, error: nil)
+ rescue ::Gitlab::Config::Loader::FormatError => e
+ Yaml::Result.new(error: e)
+ end
+
private
+ attr_reader :content, :project
+
def ensure_custom_tags
@ensure_custom_tags ||= begin
AVAILABLE_TAGS.each { |klass| Psych.add_tag(klass.tag, klass) }
@@ -32,6 +47,23 @@ module Gitlab
end
end
end
+
+ class << self
+ def load!(content, project: nil)
+ Loader.new(content, project: project).to_result.then do |result|
+ ##
+ # raise an error for backwards compatibility
+ #
+ raise result.error unless result.valid?
+
+ result.content
+ end
+ end
+
+ def load_result!(content, project: nil)
+ Loader.new(content, project: project).to_result
+ end
+ end
end
end
end
diff --git a/lib/gitlab/ci/config/yaml/result.rb b/lib/gitlab/ci/config/yaml/result.rb
new file mode 100644
index 00000000000..1a3ca53c161
--- /dev/null
+++ b/lib/gitlab/ci/config/yaml/result.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Yaml
+ class Result
+ attr_reader :error
+
+ def initialize(config: nil, error: nil)
+ @config = Array.wrap(config)
+ @error = error
+ end
+
+ def valid?
+ error.nil?
+ end
+
+ def has_header?
+ @config.size > 1
+ end
+
+ def header
+ raise ArgumentError unless has_header?
+
+ @config.first
+ end
+
+ def content
+ @config.last
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/input/arguments/base.rb b/lib/gitlab/ci/input/arguments/base.rb
new file mode 100644
index 00000000000..a46037c40ce
--- /dev/null
+++ b/lib/gitlab/ci/input/arguments/base.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Input
+ module Arguments
+ ##
+ # Input::Arguments::Base is a common abstraction for input arguments:
+ # - required
+ # - optional
+ # - with a default value
+ #
+ class Base
+ attr_reader :key, :value, :spec, :errors
+
+ ArgumentNotValidError = Class.new(StandardError)
+
+ def initialize(key, spec, value)
+ @key = key # hash key / argument name
+ @value = value # user-provided value
+ @spec = spec # configured specification
+ @errors = []
+
+ unless value.is_a?(String) || value.nil? # rubocop:disable Style/IfUnlessModifier
+ @errors.push("unsupported value in input argument `#{key}`")
+ end
+
+ validate!
+ end
+
+ def valid?
+ @errors.none?
+ end
+
+ def validate!
+ raise NotImplementedError
+ end
+
+ def to_value
+ raise NotImplementedError
+ end
+
+ def to_hash
+ raise ArgumentNotValidError unless valid?
+
+ @output ||= { key => to_value }
+ end
+
+ def self.matches?(spec)
+ raise NotImplementedError
+ end
+
+ private
+
+ def error(message)
+ @errors.push("`#{@key}` input: #{message}")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/input/arguments/default.rb b/lib/gitlab/ci/input/arguments/default.rb
new file mode 100644
index 00000000000..fd61c1ab786
--- /dev/null
+++ b/lib/gitlab/ci/input/arguments/default.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Input
+ module Arguments
+ ##
+ # Input::Arguments::Default class represents user-provided input argument that has a default value.
+ #
+ class Default < Input::Arguments::Base
+ def validate!
+ error('invalid specification') unless default.present?
+ end
+
+ ##
+ # User-provided value needs to be specified, but it may be an empty string:
+ #
+ # ```yaml
+ # inputs:
+ # env:
+ # default: development
+ #
+ # with:
+ # env: ""
+ # ```
+ #
+ # The configuration above will result in `env` being an empty string.
+ #
+ def to_value
+ value.nil? ? default : value
+ end
+
+ def default
+ spec[:default]
+ end
+
+ def self.matches?(spec)
+ spec.count == 1 && spec.each_key.first == :default
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/input/arguments/options.rb b/lib/gitlab/ci/input/arguments/options.rb
new file mode 100644
index 00000000000..debc89b10bd
--- /dev/null
+++ b/lib/gitlab/ci/input/arguments/options.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Input
+ module Arguments
+ ##
+ # Input::Arguments::Options class represents user-provided input argument that is an enum, and is only valid
+ # when the value provided is listed as an acceptable one.
+ #
+ class Options < Input::Arguments::Base
+ ##
+ # An empty value is valid if it is allowlisted:
+ #
+ # ```yaml
+ # inputs:
+ # run:
+ # - ""
+ # - tests
+ #
+ # with:
+ # run: ""
+ # ```
+ #
+ # The configuration above will return an empty value.
+ #
+ def validate!
+ return error('argument specification invalid') if options.to_a.empty?
+
+ if !value.nil?
+ error("argument value #{value} not allowlisted") unless options.include?(value)
+ else
+ error('argument not provided')
+ end
+ end
+
+ def to_value
+ value
+ end
+
+ def options
+ spec[:options]
+ end
+
+ def self.matches?(spec)
+ spec.count == 1 && spec.each_key.first == :options
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/input/arguments/required.rb b/lib/gitlab/ci/input/arguments/required.rb
new file mode 100644
index 00000000000..b4e218ed29e
--- /dev/null
+++ b/lib/gitlab/ci/input/arguments/required.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Input
+ module Arguments
+ ##
+ # Input::Arguments::Required class represents user-provided required input argument.
+ #
+ class Required < Input::Arguments::Base
+ ##
+ # The value has to be defined, but it may be empty.
+ #
+ def validate!
+ error('required value has not been provided') if value.nil?
+ end
+
+ def to_value
+ value
+ end
+
+ ##
+ # Required arguments do not have nested configuration. It has to be defined a null value.
+ #
+ # ```yaml
+ # spec:
+ # inputs:
+ # website:
+ # ```
+ #
+ # An empty value, that has no specification is also considered as a "required" input, however we should
+ # never see that being used, because it will be rejected by Ci::Config::Header validation.
+ #
+ # ```yaml
+ # spec:
+ # inputs:
+ # website: ""
+ # ```
+ def self.matches?(spec)
+ spec.to_s.empty?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/input/arguments/unknown.rb b/lib/gitlab/ci/input/arguments/unknown.rb
new file mode 100644
index 00000000000..5873e6e66a6
--- /dev/null
+++ b/lib/gitlab/ci/input/arguments/unknown.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Input
+ module Arguments
+ ##
+ # Input::Arguments::Unknown object gets fabricated when we can't match an input argument entry with any known
+ # specification. It is matched as the last one, and always returns an error.
+ #
+ class Unknown < Input::Arguments::Base
+ def validate!
+ if spec.is_a?(Hash) && spec.count == 1
+ error("unrecognized input argument specification: `#{spec.each_key.first}`")
+ else
+ error('unrecognized input argument definition')
+ end
+ end
+
+ def to_value
+ raise ArgumentError, 'unknown argument value'
+ end
+
+ def self.matches?(*)
+ true
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/input/inputs.rb b/lib/gitlab/ci/input/inputs.rb
new file mode 100644
index 00000000000..743ae2ecf1e
--- /dev/null
+++ b/lib/gitlab/ci/input/inputs.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Input
+ ##
+ # Inputs::Input class represents user-provided inputs, configured using `with:` keyword.
+ #
+ # Input arguments are only valid with an associated component's inputs specification from component's header.
+ #
+ class Inputs
+ UnknownSpecArgumentError = Class.new(StandardError)
+
+ ARGUMENTS = [
+ Input::Arguments::Required, # Input argument is required
+ Input::Arguments::Default, # Input argument has a default value
+ Input::Arguments::Options, # Input argument that needs to be allowlisted
+ Input::Arguments::Unknown # Input argument has not been recognized
+ ].freeze
+
+ def initialize(spec, args)
+ @spec = spec
+ @args = args
+ @inputs = []
+ @errors = []
+
+ validate!
+ fabricate!
+ end
+
+ def errors
+ @errors + @inputs.flat_map(&:errors)
+ end
+
+ def valid?
+ errors.none?
+ end
+
+ def unknown
+ @args.keys - @spec.keys
+ end
+
+ def count
+ @inputs.count
+ end
+
+ def to_hash
+ @inputs.inject({}) do |hash, argument|
+ raise ArgumentError unless argument.valid?
+
+ hash.merge(argument.to_hash)
+ end
+ end
+
+ private
+
+ def validate!
+ @errors.push("unknown input arguments: #{unknown.inspect}") if unknown.any?
+ end
+
+ def fabricate!
+ @spec.each do |key, spec|
+ argument = ARGUMENTS.find { |klass| klass.matches?(spec) }
+
+ raise UnknownSpecArgumentError if argument.nil?
+
+ @inputs.push(argument.new(key, spec, @args[key]))
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/parsers/security/common.rb b/lib/gitlab/ci/parsers/security/common.rb
index 1b9afc92d6b..447136df81f 100644
--- a/lib/gitlab/ci/parsers/security/common.rb
+++ b/lib/gitlab/ci/parsers/security/common.rb
@@ -139,6 +139,7 @@ module Gitlab
details: data['details'] || {},
signatures: signatures,
project_id: @project.id,
+ found_by_pipeline: report.pipeline,
vulnerability_finding_signatures_enabled: @signatures_enabled))
end
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index d2dc712e366..4bc2f6c7be7 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -13,7 +13,8 @@ module Gitlab
:seeds_block, :variables_attributes, :push_options,
:chat_data, :allow_mirror_update, :bridge, :content, :dry_run, :logger,
# These attributes are set by Chains during processing:
- :config_content, :yaml_processor_result, :workflow_rules_result, :pipeline_seed
+ :config_content, :yaml_processor_result, :workflow_rules_result, :pipeline_seed,
+ :pipeline_config
) do
include Gitlab::Utils::StrongMemoize
diff --git a/lib/gitlab/ci/pipeline/chain/config/content.rb b/lib/gitlab/ci/pipeline/chain/config/content.rb
index d41213ef6dd..779aac7d520 100644
--- a/lib/gitlab/ci/pipeline/chain/config/content.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/content.rb
@@ -14,6 +14,7 @@ module Gitlab
@pipeline.build_pipeline_config(content: pipeline_config.content)
@command.config_content = pipeline_config.content
@pipeline.config_source = pipeline_config.source
+ @command.pipeline_config = pipeline_config
else
error('Missing CI config file')
end
diff --git a/lib/gitlab/ci/pipeline/chain/config/process.rb b/lib/gitlab/ci/pipeline/chain/config/process.rb
index ad6b2fd3411..4976e075727 100644
--- a/lib/gitlab/ci/pipeline/chain/config/process.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/process.rb
@@ -20,6 +20,7 @@ module Gitlab
source: @pipeline.source,
user: current_user,
parent_pipeline: parent_pipeline,
+ pipeline_config: @command.pipeline_config,
logger: logger
}
)
diff --git a/lib/gitlab/ci/pipeline/duration.rb b/lib/gitlab/ci/pipeline/duration.rb
index e8a991026b5..573d4c25b91 100644
--- a/lib/gitlab/ci/pipeline/duration.rb
+++ b/lib/gitlab/ci/pipeline/duration.rb
@@ -82,6 +82,8 @@ module Gitlab
module Duration
extend self
+ STATUSES = %w[success failed running canceled].freeze
+
Period = Struct.new(:first, :last) do
def duration
last - first
@@ -90,14 +92,15 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def from_pipeline(pipeline)
- status = %w[success failed running canceled]
- builds = pipeline.processables.latest
- .where(status: status).where.not(started_at: nil).order(:started_at)
+ builds =
+ self_and_downstreams_builds_of_pipeline(pipeline)
from_builds(builds)
end
# rubocop: enable CodeReuse/ActiveRecord
+ private
+
def from_builds(builds)
now = Time.now
@@ -113,8 +116,6 @@ module Gitlab
process_duration(process_periods(periods))
end
- private
-
def process_periods(periods)
return periods if periods.empty?
@@ -139,6 +140,20 @@ module Gitlab
end
# rubocop: disable CodeReuse/ActiveRecord
+ def self_and_downstreams_builds_of_pipeline(pipeline)
+ ::Ci::Build
+ .select(:id, :type, :started_at, :finished_at)
+ .in_pipelines(
+ pipeline.self_and_downstreams.select(:id)
+ )
+ .with_status(STATUSES)
+ .latest
+ .where.not(started_at: nil)
+ .order(:started_at)
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
def process_duration(periods)
periods.sum(&:duration)
end
diff --git a/lib/gitlab/ci/project_config.rb b/lib/gitlab/ci/project_config.rb
index ded6877ef29..00b2ad58428 100644
--- a/lib/gitlab/ci/project_config.rb
+++ b/lib/gitlab/ci/project_config.rb
@@ -26,6 +26,7 @@ module Gitlab
end
delegate :content, :source, to: :@config, allow_nil: true
+ delegate :internal_include_prepended?, to: :@config
def exists?
!!@config&.exists?
diff --git a/lib/gitlab/ci/project_config/auto_devops.rb b/lib/gitlab/ci/project_config/auto_devops.rb
index c6905f480a2..c5f010ebaea 100644
--- a/lib/gitlab/ci/project_config/auto_devops.rb
+++ b/lib/gitlab/ci/project_config/auto_devops.rb
@@ -13,6 +13,10 @@ module Gitlab
end
end
+ def internal_include_prepended?
+ true
+ end
+
def source
:auto_devops_source
end
diff --git a/lib/gitlab/ci/project_config/external_project.rb b/lib/gitlab/ci/project_config/external_project.rb
index 0ed5d6fa226..0afdab23886 100644
--- a/lib/gitlab/ci/project_config/external_project.rb
+++ b/lib/gitlab/ci/project_config/external_project.rb
@@ -17,6 +17,10 @@ module Gitlab
end
end
+ def internal_include_prepended?
+ true
+ end
+
def source
:external_project_source
end
diff --git a/lib/gitlab/ci/project_config/remote.rb b/lib/gitlab/ci/project_config/remote.rb
index cf1292706d2..19cbf8e9c1e 100644
--- a/lib/gitlab/ci/project_config/remote.rb
+++ b/lib/gitlab/ci/project_config/remote.rb
@@ -12,6 +12,10 @@ module Gitlab
end
end
+ def internal_include_prepended?
+ true
+ end
+
def source
:remote_source
end
diff --git a/lib/gitlab/ci/project_config/repository.rb b/lib/gitlab/ci/project_config/repository.rb
index 435ad4d42fe..272425fd546 100644
--- a/lib/gitlab/ci/project_config/repository.rb
+++ b/lib/gitlab/ci/project_config/repository.rb
@@ -12,6 +12,10 @@ module Gitlab
end
end
+ def internal_include_prepended?
+ true
+ end
+
def source
:repository_source
end
diff --git a/lib/gitlab/ci/project_config/source.rb b/lib/gitlab/ci/project_config/source.rb
index ebe5728163b..9a4a6394fa1 100644
--- a/lib/gitlab/ci/project_config/source.rb
+++ b/lib/gitlab/ci/project_config/source.rb
@@ -24,6 +24,11 @@ module Gitlab
raise NotImplementedError
end
+ # Indicates if we are prepending the content with an "internal" `include`
+ def internal_include_prepended?
+ false
+ end
+
def source
raise NotImplementedError
end
diff --git a/lib/gitlab/ci/reports/security/finding.rb b/lib/gitlab/ci/reports/security/finding.rb
index 92a91854358..45e67528f12 100644
--- a/lib/gitlab/ci/reports/security/finding.rb
+++ b/lib/gitlab/ci/reports/security/finding.rb
@@ -29,12 +29,13 @@ module Gitlab
attr_reader :signatures
attr_reader :project_id
attr_reader :original_data
+ attr_reader :found_by_pipeline
delegate :file_path, :start_line, :end_line, to: :location
alias_method :cve, :compare_key
- def initialize(compare_key:, identifiers:, flags: [], links: [], remediations: [], location:, evidence:, metadata_version:, name:, original_data:, report_type:, scanner:, scan:, uuid:, confidence: nil, severity: nil, details: {}, signatures: [], project_id: nil, vulnerability_finding_signatures_enabled: false) # rubocop:disable Metrics/ParameterLists
+ def initialize(compare_key:, identifiers:, flags: [], links: [], remediations: [], location:, evidence:, metadata_version:, name:, original_data:, report_type:, scanner:, scan:, uuid:, confidence: nil, severity: nil, details: {}, signatures: [], project_id: nil, vulnerability_finding_signatures_enabled: false, found_by_pipeline: nil) # rubocop:disable Metrics/ParameterLists
@compare_key = compare_key
@confidence = confidence
@identifiers = identifiers
@@ -55,6 +56,7 @@ module Gitlab
@signatures = signatures
@project_id = project_id
@vulnerability_finding_signatures_enabled = vulnerability_finding_signatures_enabled
+ @found_by_pipeline = found_by_pipeline
@project_fingerprint = generate_project_fingerprint
end
diff --git a/lib/gitlab/ci/reports/security/report.rb b/lib/gitlab/ci/reports/security/report.rb
index 54b21da5436..2287c397c2b 100644
--- a/lib/gitlab/ci/reports/security/report.rb
+++ b/lib/gitlab/ci/reports/security/report.rb
@@ -5,8 +5,9 @@ module Gitlab
module Reports
module Security
class Report
- attr_reader :created_at, :type, :pipeline, :findings, :scanners, :identifiers
- attr_accessor :scan, :scanned_resources, :errors, :analyzer, :version, :schema_validation_status, :warnings
+ attr_reader :created_at, :type, :findings, :scanners, :identifiers
+ attr_accessor :scan, :pipeline, :scanned_resources, :errors,
+ :analyzer, :version, :schema_validation_status, :warnings
delegate :project_id, to: :pipeline
delegate :project, to: :pipeline
diff --git a/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb b/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb
deleted file mode 100644
index 4be4cf62e7b..00000000000
--- a/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Ci
- module Reports
- module Security
- class VulnerabilityReportsComparer
- include Gitlab::Utils::StrongMemoize
-
- attr_reader :base_report, :head_report
-
- ACCEPTABLE_REPORT_AGE = 1.week
-
- def initialize(project, base_report, head_report)
- @base_report = base_report
- @head_report = head_report
-
- @signatures_enabled = project.licensed_feature_available?(:vulnerability_finding_signatures)
-
- if @signatures_enabled
- @added_findings = []
- @fixed_findings = []
- calculate_changes
- end
- end
-
- def base_report_created_at
- @base_report.created_at
- end
-
- def head_report_created_at
- @head_report.created_at
- end
-
- def base_report_out_of_date
- return false unless @base_report.created_at
-
- ACCEPTABLE_REPORT_AGE.ago > @base_report.created_at
- end
-
- def added
- strong_memoize(:added) do
- if @signatures_enabled
- @added_findings
- else
- head_report.findings - base_report.findings
- end
- end
- end
-
- def fixed
- strong_memoize(:fixed) do
- if @signatures_enabled
- @fixed_findings
- else
- base_report.findings - head_report.findings
- end
- end
- end
-
- private
-
- def calculate_changes
- # This is a deconstructed version of the eql? method on
- # Ci::Reports::Security::Finding. It:
- #
- # * precomputes for the head_findings (using FindingMatcher):
- # * sets of signature shas grouped by priority
- # * mappings of signature shas to the head finding object
- #
- # These are then used when iterating the base findings to perform
- # fast(er) prioritized, signature-based comparisons between each base finding
- # and the head findings.
- #
- # Both the head_findings and base_findings arrays are iterated once
-
- base_findings = base_report.findings
- head_findings = head_report.findings
-
- matcher = FindingMatcher.new(head_findings)
-
- base_findings.each do |base_finding|
- next if base_finding.requires_manual_resolution?
-
- matched_head_finding = matcher.find_and_remove_match!(base_finding)
-
- @fixed_findings << base_finding if matched_head_finding.nil?
- end
-
- @added_findings = matcher.unmatched_head_findings.values
- end
- end
-
- class FindingMatcher
- attr_reader :unmatched_head_findings, :head_findings
-
- include Gitlab::Utils::StrongMemoize
-
- def initialize(head_findings)
- @head_findings = head_findings
- @unmatched_head_findings = @head_findings.index_by(&:object_id)
- end
-
- def find_and_remove_match!(base_finding)
- matched_head_finding = find_matched_head_finding_for(base_finding)
-
- # no signatures matched, so check the normal uuids of the base and head findings
- # for a match
- matched_head_finding = head_signatures_shas[base_finding.uuid] if matched_head_finding.nil?
-
- @unmatched_head_findings.delete(matched_head_finding.object_id) unless matched_head_finding.nil?
-
- matched_head_finding
- end
-
- private
-
- def find_matched_head_finding_for(base_finding)
- base_signature = sorted_signatures_for(base_finding).find do |signature|
- # at this point a head_finding exists that has a signature with a
- # matching priority, and a matching sha --> lookup the actual finding
- # object from head_signatures_shas
- head_signatures_shas[signature.signature_sha].eql?(base_finding)
- end
-
- base_signature.present? ? head_signatures_shas[base_signature.signature_sha] : nil
- end
-
- def sorted_signatures_for(base_finding)
- base_finding.signatures.select { |signature| head_finding_signature?(signature) }
- .sort_by { |sig| -sig.priority }
- end
-
- def head_finding_signature?(signature)
- head_signatures_priorities[signature.priority].include?(signature.signature_sha)
- end
-
- def head_signatures_priorities
- strong_memoize(:head_signatures_priorities) do
- signatures_priorities = Hash.new { |hash, key| hash[key] = Set.new }
-
- head_findings.each_with_object(signatures_priorities) do |head_finding, memo|
- head_finding.signatures.each do |signature|
- memo[signature.priority].add(signature.signature_sha)
- end
- end
- end
- end
-
- def head_signatures_shas
- strong_memoize(:head_signatures_shas) do
- head_findings.each_with_object({}) do |head_finding, memo|
- head_finding.signatures.each do |signature|
- memo[signature.signature_sha] = head_finding
- end
- # for the final uuid check when no signatures have matched
- memo[head_finding.uuid] = head_finding
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/ci/resource_groups/logger.rb b/lib/gitlab/ci/resource_groups/logger.rb
new file mode 100644
index 00000000000..9c93ee95bc7
--- /dev/null
+++ b/lib/gitlab/ci/resource_groups/logger.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module ResourceGroups
+ class Logger < ::Gitlab::JsonLogger
+ def self.file_name_noext
+ 'ci_resource_groups_json'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/runner_releases.rb b/lib/gitlab/ci/runner_releases.rb
index dab24bfd501..a27dd3896e1 100644
--- a/lib/gitlab/ci/runner_releases.rb
+++ b/lib/gitlab/ci/runner_releases.rb
@@ -15,9 +15,14 @@ module Gitlab
reset_backoff!
end
+ def enabled?
+ ::Gitlab::CurrentSettings.current_application_settings.update_runner_versions_enabled?
+ end
+
# Returns a sorted list of the publicly available GitLab Runner releases
#
def releases
+ return unless enabled?
return if backoff_active?
Rails.cache.fetch(
diff --git a/lib/gitlab/ci/status/composite.rb b/lib/gitlab/ci/status/composite.rb
index e854164d377..002bd846ab1 100644
--- a/lib/gitlab/ci/status/composite.rb
+++ b/lib/gitlab/ci/status/composite.rb
@@ -7,6 +7,7 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
# This class accepts an array of arrays/hashes/or objects
+ # `with_allow_failure` will be removed when deleting ci_remove_ensure_stage_service
def initialize(all_statuses, with_allow_failure: true, dag: false)
unless all_statuses.respond_to?(:pluck)
raise ArgumentError, "all_statuses needs to respond to `.pluck`"
@@ -26,6 +27,12 @@ module Gitlab
# 2. In other cases we assume that status is of that type
# based on what statuses are no longer valid based on the
# data set that we have
+ #
+ # This method is used for two cases:
+ # 1. When it is called for a stage or a pipeline (with `all_statuses` from all jobs in a stage or a pipeline),
+ # then, the returned status is assigned to the stage or pipeline.
+ # 2. When it is called for a job (with `all_statuses` from all previous jobs or all needed jobs),
+ # then, the returned status is used to determine if the job is processed or not.
# rubocop: disable Metrics/CyclomaticComplexity
# rubocop: disable Metrics/PerceivedComplexity
def status
@@ -101,23 +108,22 @@ module Gitlab
all_statuses
.pluck(*columns) # rubocop: disable CodeReuse/ActiveRecord
- .each(&method(:consume_status))
+ .each do |status_attrs|
+ consume_status(Array.wrap(status_attrs))
+ end
end
- def consume_status(description)
- # convert `"status"` into `["status"]`
- description = Array(description)
-
- status =
- if success_with_warnings?(description)
+ def consume_status(status_attrs)
+ status_result =
+ if success_with_warnings?(status_attrs)
:success_with_warnings
- elsif ignored_status?(description)
+ elsif ignored_status?(status_attrs)
:ignored
else
- description[@status_key].to_sym
+ status_attrs[@status_key].to_sym
end
- @status_set.add(status)
+ @status_set.add(status_result)
end
def success_with_warnings?(status)
@@ -129,7 +135,7 @@ module Gitlab
def ignored_status?(status)
@allow_failure_key &&
status[@allow_failure_key] &&
- ::Ci::HasStatus::EXCLUDE_IGNORED_STATUSES.include?(status[@status_key])
+ ::Ci::HasStatus::IGNORED_STATUSES.include?(status[@status_key])
end
end
end
diff --git a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
index 40f5109851b..2f7c16f0904 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.28.0'
+ AUTO_BUILD_IMAGE_VERSION: 'v1.30.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 40f5109851b..2f7c16f0904 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.28.0'
+ AUTO_BUILD_IMAGE_VERSION: 'v1.30.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 fa609afc5a8..7f8e2150c71 100644
--- a/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml
@@ -23,6 +23,7 @@
variables:
CS_ANALYZER_IMAGE: "$CI_TEMPLATE_REGISTRY_HOST/security-products/container-scanning:5"
+ CS_SCHEMA_MODEL: 15
container_scanning:
image: "$CS_ANALYZER_IMAGE$CS_IMAGE_SUFFIX"
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 f750bda2a3f..15688da71ab 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
@@ -23,6 +23,7 @@
variables:
CS_ANALYZER_IMAGE: "$CI_TEMPLATE_REGISTRY_HOST/security-products/container-scanning:5"
+ CS_SCHEMA_MODEL: 15
container_scanning:
image: "$CS_ANALYZER_IMAGE$CS_IMAGE_SUFFIX"
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 aa2356f6a34..61c2b468899 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.46.0'
+ DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.47.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/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
index eb8e5de5b56..31d19779434 100644
--- a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
@@ -56,15 +56,15 @@ dependency_scanning:
.gemnasium-shared-rule:
exists:
- - '{Gemfile.lock,*/Gemfile.lock,*/*/Gemfile.lock}'
- - '{composer.lock,*/composer.lock,*/*/composer.lock}'
- - '{gems.locked,*/gems.locked,*/*/gems.locked}'
- - '{go.sum,*/go.sum,*/*/go.sum}'
- - '{npm-shrinkwrap.json,*/npm-shrinkwrap.json,*/*/npm-shrinkwrap.json}'
- - '{package-lock.json,*/package-lock.json,*/*/package-lock.json}'
- - '{yarn.lock,*/yarn.lock,*/*/yarn.lock}'
- - '{packages.lock.json,*/packages.lock.json,*/*/packages.lock.json}'
- - '{conan.lock,*/conan.lock,*/*/conan.lock}'
+ - '**/Gemfile.lock'
+ - '**/composer.lock'
+ - '**/gems.locked'
+ - '**/go.sum'
+ - '**/npm-shrinkwrap.json'
+ - '**/package-lock.json'
+ - '**/yarn.lock'
+ - '**/packages.lock.json'
+ - '**/conan.lock'
gemnasium-dependency_scanning:
extends:
@@ -91,10 +91,10 @@ gemnasium-dependency_scanning:
.gemnasium-maven-shared-rule:
exists:
- - '{build.gradle,*/build.gradle,*/*/build.gradle}'
- - '{build.gradle.kts,*/build.gradle.kts,*/*/build.gradle.kts}'
- - '{build.sbt,*/build.sbt,*/*/build.sbt}'
- - '{pom.xml,*/pom.xml,*/*/pom.xml}'
+ - '**/build.gradle'
+ - '**/build.gradle.kts'
+ - '**/build.sbt'
+ - '**/pom.xml'
gemnasium-maven-dependency_scanning:
extends:
@@ -119,12 +119,12 @@ gemnasium-maven-dependency_scanning:
.gemnasium-python-shared-rule:
exists:
- - '{requirements.txt,*/requirements.txt,*/*/requirements.txt}'
- - '{requirements.pip,*/requirements.pip,*/*/requirements.pip}'
- - '{Pipfile,*/Pipfile,*/*/Pipfile}'
- - '{requires.txt,*/requires.txt,*/*/requires.txt}'
- - '{setup.py,*/setup.py,*/*/setup.py}'
- - '{poetry.lock,*/poetry.lock,*/*/poetry.lock}'
+ - '**/requirements.txt'
+ - '**/requirements.pip'
+ - '**/Pipfile'
+ - '**/requires.txt'
+ - '**/setup.py'
+ - '**/poetry.lock'
gemnasium-python-dependency_scanning:
extends:
diff --git a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml
index 655ac6ee712..9ab17997c27 100644
--- a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml
@@ -56,15 +56,15 @@ dependency_scanning:
.gemnasium-shared-rule:
exists:
- - '{Gemfile.lock,*/Gemfile.lock,*/*/Gemfile.lock}'
- - '{composer.lock,*/composer.lock,*/*/composer.lock}'
- - '{gems.locked,*/gems.locked,*/*/gems.locked}'
- - '{go.sum,*/go.sum,*/*/go.sum}'
- - '{npm-shrinkwrap.json,*/npm-shrinkwrap.json,*/*/npm-shrinkwrap.json}'
- - '{package-lock.json,*/package-lock.json,*/*/package-lock.json}'
- - '{yarn.lock,*/yarn.lock,*/*/yarn.lock}'
- - '{packages.lock.json,*/packages.lock.json,*/*/packages.lock.json}'
- - '{conan.lock,*/conan.lock,*/*/conan.lock}'
+ - '**/Gemfile.lock'
+ - '**/composer.lock'
+ - '**/gems.locked'
+ - '**/go.sum'
+ - '**/npm-shrinkwrap.json'
+ - '**/package-lock.json'
+ - '**/yarn.lock'
+ - '**/packages.lock.json'
+ - '**/conan.lock'
gemnasium-dependency_scanning:
extends:
@@ -109,10 +109,10 @@ gemnasium-dependency_scanning:
.gemnasium-maven-shared-rule:
exists:
- - '{build.gradle,*/build.gradle,*/*/build.gradle}'
- - '{build.gradle.kts,*/build.gradle.kts,*/*/build.gradle.kts}'
- - '{build.sbt,*/build.sbt,*/*/build.sbt}'
- - '{pom.xml,*/pom.xml,*/*/pom.xml}'
+ - '**/build.gradle'
+ - '**/build.gradle.kts'
+ - '**/build.sbt'
+ - '**/pom.xml'
gemnasium-maven-dependency_scanning:
extends:
@@ -155,12 +155,12 @@ gemnasium-maven-dependency_scanning:
.gemnasium-python-shared-rule:
exists:
- - '{requirements.txt,*/requirements.txt,*/*/requirements.txt}'
- - '{requirements.pip,*/requirements.pip,*/*/requirements.pip}'
- - '{Pipfile,*/Pipfile,*/*/Pipfile}'
- - '{requires.txt,*/requires.txt,*/*/requires.txt}'
- - '{setup.py,*/setup.py,*/*/setup.py}'
- - '{poetry.lock,*/poetry.lock,*/*/poetry.lock}'
+ - '**/requirements.txt'
+ - '**/requirements.pip'
+ - '**/Pipfile'
+ - '**/requires.txt'
+ - '**/setup.py'
+ - '**/poetry.lock'
gemnasium-python-dependency_scanning:
extends:
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index 372b782c0a0..9bac82b660f 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.46.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.47.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 feba2efcf22..ec43217792f 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.46.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.47.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/SAST-IaC.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/SAST-IaC.latest.gitlab-ci.yml
index 77048037915..b4bff9d9667 100644
--- a/lib/gitlab/ci/templates/Jobs/SAST-IaC.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/SAST-IaC.latest.gitlab-ci.yml
@@ -34,7 +34,7 @@ kics-iac-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/kics:$SAST_ANALYZER_IMAGE_TAG$SAST_IMAGE_SUFFIX"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /kics/
when: never
diff --git a/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml
index 1c4dbe6cd0f..e7c8356662b 100644
--- a/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml
@@ -51,7 +51,7 @@ brakeman-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/brakeman:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /brakeman/
when: never
@@ -83,7 +83,7 @@ flawfinder-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/flawfinder:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /flawfinder/
when: never
@@ -123,7 +123,7 @@ kubesec-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/kubesec:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /kubesec/
when: never
@@ -147,7 +147,7 @@ kubesec-sast:
mobsf-android-sast:
extends: .mobsf-sast
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /mobsf/
when: never
@@ -169,7 +169,7 @@ mobsf-android-sast:
mobsf-ios-sast:
extends: .mobsf-sast
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /mobsf/
when: never
@@ -196,7 +196,7 @@ nodejs-scan-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/nodejs-scan:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /nodejs-scan/
when: never
@@ -217,7 +217,7 @@ phpcs-security-audit-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/phpcs-security-audit:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /phpcs-security-audit/
when: never
@@ -238,7 +238,7 @@ pmd-apex-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/pmd-apex:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /pmd-apex/
when: never
@@ -259,7 +259,7 @@ security-code-scan-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/security-code-scan:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /security-code-scan/
when: never
@@ -283,7 +283,7 @@ semgrep-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/semgrep:$SAST_ANALYZER_IMAGE_TAG$SAST_IMAGE_SUFFIX"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /semgrep/
when: never
@@ -326,7 +326,7 @@ sobelow-sast:
SAST_ANALYZER_IMAGE_TAG: 3
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/sobelow:$SAST_ANALYZER_IMAGE_TAG"
rules:
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /sobelow/
when: never
@@ -353,7 +353,7 @@ spotbugs-sast:
exists:
- '**/AndroidManifest.xml'
when: never
- - if: $SAST_DISABLED
+ - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
exists:
diff --git a/lib/gitlab/ci/templates/Jobs/Secret-Detection.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Secret-Detection.latest.gitlab-ci.yml
index 6603ee4268e..f343dfaa28f 100644
--- a/lib/gitlab/ci/templates/Jobs/Secret-Detection.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Secret-Detection.latest.gitlab-ci.yml
@@ -27,7 +27,7 @@ variables:
secret_detection:
extends: .secret-analyzer
rules:
- - if: $SECRET_DETECTION_DISABLED
+ - if: $SECRET_DETECTION_DISABLED == 'true' || $SECRET_DETECTION_DISABLED == '1'
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
- if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
diff --git a/lib/gitlab/ci/templates/Security/API-Discovery.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/API-Discovery.gitlab-ci.yml
new file mode 100644
index 00000000000..d9bc76dad1e
--- /dev/null
+++ b/lib/gitlab/ci/templates/Security/API-Discovery.gitlab-ci.yml
@@ -0,0 +1,66 @@
+# 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/Security/API-Discovery.gitlab-ci.yml
+
+# Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/api_discovery/
+#
+# Configure API Discovery with CI/CD variables (https://docs.gitlab.com/ee/ci/variables/index.html).
+# List of available variables: https://docs.gitlab.com/ee/user/application_security/api_discovery/#available-cicd-variables
+
+variables:
+ API_DISCOVERY_PACKAGES: "$CI_API_V4_URL/projects/42503323/packages"
+ API_DISCOVERY_VERSION: "1"
+
+.api_discovery_java_spring_boot:
+ stage: test
+ allow_failure: true
+ script:
+ #
+ # Check configuration
+ - if [[ -z "$API_DISCOVERY_VERSION" ]]; then echo "Error, API_DISCOVERY_VERSION not provided. Please set this variable and re-run the pipeline."; exit 1; fi
+ #
+ # Check for required commands
+ - requires() { command -v "$1" >/dev/null 2>&1 || { echo "'$1' is required but it's not installed. Add the needed command to the job image and retry." >&2; exit 1; } }
+ - requires 'curl'
+ - requires 'java'
+ #
+ # Set JAVA_HOME if API_DISCOVERY_JAVA_HOME provided
+ - if [[ -n "$API_DISCOVERY_JAVA_HOME" ]]; then export JAVA_HOME="$API_DISCOVERY_JAVA_HOME"; export PATH="$JAVA_HOME/bin:$PATH"; fi
+ #
+ # Download jar file
+ - if [[ -n "$API_DISCOVERY_PACKAGE_TOKEN" ]]; then echo "Using API_DISCOVERY_PACKAGE_TOKEN"; export CURL_AUTH="-H PRIVATE-TOKEN:$API_DISCOVERY_PACKAGE_TOKEN"; else export CURL_AUTH=""; fi
+ - DL_URL="$API_DISCOVERY_PACKAGES/maven/com/gitlab/analyzers/api-discovery/api-discovery_spring-boot/$API_DISCOVERY_VERSION/api-discovery_spring-boot-$API_DISCOVERY_VERSION.jar"
+ - echo "Downloading Discovery jar from '${DL_URL}'"
+ - CURL_CMD="curl -L ${CURL_AUTH} --write-out "%{http_code}" --output api_discovery_java_spring_boot_${API_DISCOVERY_VERSION}.jar ${DL_URL}"
+ - STATUS_CODE=$(${CURL_CMD})
+ - RC=$?
+ - if [[ $RC -ne 0 ]]; then echo "Error connecting to GitLab API, curl exit code was $RC."; echo "To diagnose, see the curl documentation- https://everything.curl.dev/usingcurl/returns"; exit 1; fi
+ - if [[ "$STATUS_CODE" != "200" ]]; then echo "Error, Unable to download api_discovery_java_spring_boot_${API_DISCOVERY_VERSION}.jar"; echo "Error, Status Code was $STATUS_CODE, but wanted 200"; exit 1; fi
+ #
+ # Run API Discovery
+ - java -jar "api_discovery_java_spring_boot_${API_DISCOVERY_VERSION}.jar"
+ #
+ # Check for expected output file
+ - if [[ ! -e "gl-api-discovery-openapi.json" ]]; then echo "Error, Unable to find gl-api-discovery-openapi.json"; exit 1; fi
+ #
+ artifacts:
+ when: always
+ paths:
+ - gl-api-discovery-openapi.json
+ - gl-*.log
+ rules:
+ - if: $API_DISCOVERY_DISABLED
+ when: never
+ - if: $API_DISCOVERY_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ # Add the job to merge request pipelines if there's an open merge request.
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+
+ # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ - if: $CI_OPEN_MERGE_REQUESTS
+ when: never
+
+ # Add the job to branch pipelines.
+ - if: $CI_COMMIT_BRANCH
diff --git a/lib/gitlab/color_schemes.rb b/lib/gitlab/color_schemes.rb
index 3884f5f0428..1ba99e23d65 100644
--- a/lib/gitlab/color_schemes.rb
+++ b/lib/gitlab/color_schemes.rb
@@ -46,7 +46,7 @@ module Gitlab
#
# Returns a Scheme
def self.default
- by_id(1)
+ by_id(Gitlab::CurrentSettings.default_syntax_highlighting_theme)
end
# Iterate through each Scheme
diff --git a/lib/gitlab/config/entry/validators.rb b/lib/gitlab/config/entry/validators.rb
index fad2260d818..28cfb6d8fee 100644
--- a/lib/gitlab/config/entry/validators.rb
+++ b/lib/gitlab/config/entry/validators.rb
@@ -356,7 +356,7 @@ module Gitlab
ports_size = value.count
return if ports_size <= 1
- named_ports = value.select { |e| e.is_a?(Hash) }.map { |e| e[:name] }.compact.map(&:downcase)
+ named_ports = value.select { |e| e.is_a?(Hash) }.filter_map { |e| e[:name] }.map(&:downcase)
if ports_size != named_ports.size
record.errors.add(attribute, 'when there is more than one port, a unique name should be added')
diff --git a/lib/gitlab/config/loader/multi_doc_yaml.rb b/lib/gitlab/config/loader/multi_doc_yaml.rb
index 346adc79896..34080d26b7c 100644
--- a/lib/gitlab/config/loader/multi_doc_yaml.rb
+++ b/lib/gitlab/config/loader/multi_doc_yaml.rb
@@ -4,59 +4,48 @@ module Gitlab
module Config
module Loader
class MultiDocYaml
- TooManyDocumentsError = Class.new(Loader::FormatError)
- DataTooLargeError = Class.new(Loader::FormatError)
- NotHashError = Class.new(Loader::FormatError)
+ include Gitlab::Utils::StrongMemoize
- MULTI_DOC_DIVIDER = /^---$/.freeze
+ MULTI_DOC_DIVIDER = /^---\s+/.freeze
def initialize(config, max_documents:, additional_permitted_classes: [])
+ @config = config
@max_documents = max_documents
- @safe_config = load_config(config, additional_permitted_classes)
+ @additional_permitted_classes = additional_permitted_classes
end
- def load!
- raise TooManyDocumentsError, 'The parsed YAML has too many documents' if too_many_documents?
- raise DataTooLargeError, 'The parsed YAML is too big' if too_big?
- raise NotHashError, 'Invalid configuration format' unless all_hashes?
-
- safe_config.map(&:deep_symbolize_keys)
+ def valid?
+ documents.all?(&:valid?)
end
- private
-
- attr_reader :safe_config, :max_documents
-
- def load_config(config, additional_permitted_classes)
- config.split(MULTI_DOC_DIVIDER).filter_map do |document|
- YAML.safe_load(document,
- permitted_classes: [Symbol, *additional_permitted_classes],
- permitted_symbols: [],
- aliases: true
- )
- end
- rescue Psych::Exception => e
- raise Loader::FormatError, e.message
+ def load_raw!
+ documents.map(&:load_raw!)
end
- def all_hashes?
- safe_config.all?(Hash)
+ def load!
+ documents.map(&:load!)
end
- def too_many_documents?
- safe_config.count > max_documents
- end
+ private
+
+ attr_reader :config, :max_documents, :additional_permitted_classes
+
+ # Valid YAML files can start with either a leading delimiter or no delimiter.
+ # To avoid counting a leading delimiter towards the document limit,
+ # this method splits the file by one more than the maximum number of permitted documents.
+ # It then discards the first document if it is blank.
+ def documents
+ docs = config
+ .split(MULTI_DOC_DIVIDER, max_documents_including_leading_delimiter)
+ .map { |d| Yaml.new(d, additional_permitted_classes: additional_permitted_classes) }
- def too_big?
- !deep_sizes.all?(&:valid?)
+ docs.shift if docs.first.blank?
+ docs
end
+ strong_memoize_attr :documents
- def deep_sizes
- safe_config.map do |config|
- Gitlab::Utils::DeepSize.new(config,
- max_size: Gitlab::CurrentSettings.current_application_settings.max_yaml_size_bytes,
- max_depth: Gitlab::CurrentSettings.current_application_settings.max_yaml_depth)
- end
+ def max_documents_including_leading_delimiter
+ max_documents + 1
end
end
end
diff --git a/lib/gitlab/config/loader/yaml.rb b/lib/gitlab/config/loader/yaml.rb
index 7b87b5b8f97..38f8eca3c3c 100644
--- a/lib/gitlab/config/loader/yaml.rb
+++ b/lib/gitlab/config/loader/yaml.rb
@@ -34,6 +34,10 @@ module Gitlab
@symbolized_config ||= load_raw!.deep_symbolize_keys
end
+ def blank?
+ @config.blank?
+ end
+
private
def hash?
diff --git a/lib/gitlab/content_security_policy/config_loader.rb b/lib/gitlab/content_security_policy/config_loader.rb
index ceca206b084..477877e6a7c 100644
--- a/lib/gitlab/content_security_policy/config_loader.rb
+++ b/lib/gitlab/content_security_policy/config_loader.rb
@@ -50,6 +50,7 @@ module Gitlab
allow_sentry(directives) if Gitlab::CurrentSettings.try(:sentry_enabled) && Gitlab::CurrentSettings.try(:sentry_clientside_dsn)
allow_framed_gitlab_paths(directives)
allow_customersdot(directives) if ENV['CUSTOMER_PORTAL_URL'].present?
+ allow_kas(directives)
allow_review_apps(directives) if ENV['REVIEW_APPS_ENABLED']
# The follow section contains workarounds to patch Safari's lack of support for CSP Level 3
@@ -147,6 +148,17 @@ module Gitlab
append_to_directive(directives, 'frame_src', customersdot_host)
end
+ def self.allow_kas(directives)
+ return unless ::Gitlab::Kas::UserAccess.enabled?
+
+ kas_url = ::Gitlab::Kas.tunnel_url
+ return if URI(kas_url).host == ::Gitlab.config.gitlab.host # already allowed, no need for exception
+
+ kas_url += '/' unless kas_url.end_with?('/')
+
+ append_to_directive(directives, 'connect_src', kas_url)
+ end
+
def self.allow_legacy_sentry(directives)
# Support for Sentry setup via configuration files will be removed in 16.0
# in favor of Gitlab::CurrentSettings.
diff --git a/lib/gitlab/data_builder/pipeline.rb b/lib/gitlab/data_builder/pipeline.rb
index 939eaa377aa..ecb0cc20a64 100644
--- a/lib/gitlab/data_builder/pipeline.rb
+++ b/lib/gitlab/data_builder/pipeline.rb
@@ -45,8 +45,9 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def preload_builds(pipeline, association)
- ActiveRecord::Associations::Preloader.new.preload(pipeline,
- {
+ ActiveRecord::Associations::Preloader.new(
+ records: [pipeline],
+ associations: {
association => {
**::Ci::Pipeline::PROJECT_ROUTE_AND_NAMESPACE_ROUTE,
runner: :tags,
@@ -56,7 +57,7 @@ module Gitlab
ci_stage: []
}
}
- )
+ ).call
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/lib/gitlab/database/async_constraints.rb b/lib/gitlab/database/async_constraints.rb
new file mode 100644
index 00000000000..026197c7e40
--- /dev/null
+++ b/lib/gitlab/database/async_constraints.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module AsyncConstraints
+ DEFAULT_ENTRIES_PER_INVOCATION = 2
+
+ def self.validate_pending_entries!(how_many: DEFAULT_ENTRIES_PER_INVOCATION)
+ PostgresAsyncConstraintValidation.ordered.limit(how_many).each do |record|
+ AsyncConstraints::Validators.for(record).perform
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/async_constraints/migration_helpers.rb b/lib/gitlab/database/async_constraints/migration_helpers.rb
new file mode 100644
index 00000000000..8b4d4ecea04
--- /dev/null
+++ b/lib/gitlab/database/async_constraints/migration_helpers.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module AsyncConstraints
+ module MigrationHelpers
+ # Prepares a foreign key for asynchronous validation.
+ #
+ # Stores the FK information in the postgres_async_foreign_key_validations
+ # table to be executed later.
+ #
+ def prepare_async_foreign_key_validation(table_name, column_name = nil, name: nil)
+ Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
+
+ return unless async_constraint_validation_available?
+
+ fk_name = name || concurrent_foreign_key_name(table_name, column_name)
+
+ unless foreign_key_exists?(table_name, name: fk_name)
+ raise missing_schema_object_message(table_name, "foreign key", fk_name)
+ end
+
+ async_validation = PostgresAsyncConstraintValidation
+ .foreign_key_type
+ .find_or_create_by!(name: fk_name, table_name: table_name)
+
+ Gitlab::AppLogger.info(
+ message: 'Prepared FK for async validation',
+ table_name: async_validation.table_name,
+ fk_name: async_validation.name)
+
+ async_validation
+ end
+
+ def unprepare_async_foreign_key_validation(table_name, column_name = nil, name: nil)
+ Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
+
+ return unless async_constraint_validation_available?
+
+ fk_name = name || concurrent_foreign_key_name(table_name, column_name)
+
+ PostgresAsyncConstraintValidation
+ .foreign_key_type
+ .find_by(name: fk_name, table_name: table_name)
+ .try(&:destroy!)
+ end
+
+ def prepare_partitioned_async_foreign_key_validation(table_name, column_name = nil, name: nil)
+ Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
+
+ return unless async_constraint_validation_available?
+
+ Gitlab::Database::PostgresPartitionedTable.each_partition(table_name) do |partition|
+ prepare_async_foreign_key_validation(partition.identifier, column_name, name: name)
+ end
+ end
+
+ def unprepare_partitioned_async_foreign_key_validation(table_name, column_name = nil, name: nil)
+ Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
+
+ return unless async_constraint_validation_available?
+
+ Gitlab::Database::PostgresPartitionedTable.each_partition(table_name) do |partition|
+ unprepare_async_foreign_key_validation(partition.identifier, column_name, name: name)
+ end
+ end
+
+ # Prepares a check constraint for asynchronous validation.
+ #
+ # Stores the constraint information in the postgres_async_foreign_key_validations
+ # table to be executed later.
+ #
+ def prepare_async_check_constraint_validation(table_name, name:)
+ Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
+
+ return unless async_constraint_validation_available?
+
+ unless check_constraint_exists?(table_name, name)
+ raise missing_schema_object_message(table_name, "check constraint", name)
+ end
+
+ async_validation = PostgresAsyncConstraintValidation
+ .check_constraint_type
+ .find_or_create_by!(name: name, table_name: table_name)
+
+ Gitlab::AppLogger.info(
+ message: 'Prepared check constraint for async validation',
+ table_name: async_validation.table_name,
+ constraint_name: async_validation.name)
+
+ async_validation
+ end
+
+ def unprepare_async_check_constraint_validation(table_name, name:)
+ Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
+
+ return unless async_constraint_validation_available?
+
+ PostgresAsyncConstraintValidation
+ .check_constraint_type
+ .find_by(name: name, table_name: table_name)
+ .try(&:destroy!)
+ end
+
+ private
+
+ def async_constraint_validation_available?
+ PostgresAsyncConstraintValidation.table_available?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/async_constraints/postgres_async_constraint_validation.rb b/lib/gitlab/database/async_constraints/postgres_async_constraint_validation.rb
new file mode 100644
index 00000000000..7fb62948119
--- /dev/null
+++ b/lib/gitlab/database/async_constraints/postgres_async_constraint_validation.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module AsyncConstraints
+ class PostgresAsyncConstraintValidation < SharedModel
+ include QueueErrorHandlingConcern
+
+ self.table_name = 'postgres_async_foreign_key_validations'
+
+ MAX_IDENTIFIER_LENGTH = Gitlab::Database::MigrationHelpers::MAX_IDENTIFIER_NAME_LENGTH
+ MAX_LAST_ERROR_LENGTH = 10_000
+
+ validates :name, presence: true, uniqueness: { scope: :table_name }, length: { maximum: MAX_IDENTIFIER_LENGTH }
+ validates :table_name, presence: true, length: { maximum: MAX_IDENTIFIER_LENGTH }
+
+ enum constraint_type: { foreign_key: 0, check_constraint: 1 }
+
+ scope :ordered, -> { order(attempts: :asc, id: :asc) }
+ scope :foreign_key_type, -> { constraint_type_exists? ? foreign_key : all }
+ scope :check_constraint_type, -> { check_constraint }
+
+ class << self
+ def table_available?
+ connection.table_exists?(table_name)
+ end
+
+ def constraint_type_exists?
+ connection.column_exists?(table_name, :constraint_type)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/async_constraints/validators.rb b/lib/gitlab/database/async_constraints/validators.rb
new file mode 100644
index 00000000000..39792a5ee8e
--- /dev/null
+++ b/lib/gitlab/database/async_constraints/validators.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module AsyncConstraints
+ module Validators
+ MAPPING = {
+ foreign_key: Validators::ForeignKey,
+ check_constraint: Validators::CheckConstraint
+ }.freeze
+
+ def self.for(record)
+ MAPPING
+ .fetch(record.constraint_type.to_sym)
+ .new(record)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/async_constraints/validators/base.rb b/lib/gitlab/database/async_constraints/validators/base.rb
new file mode 100644
index 00000000000..39a72955d63
--- /dev/null
+++ b/lib/gitlab/database/async_constraints/validators/base.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module AsyncConstraints
+ module Validators
+ class Base
+ include AsyncDdlExclusiveLeaseGuard
+ extend ::Gitlab::Utils::Override
+
+ TIMEOUT_PER_ACTION = 1.day
+ STATEMENT_TIMEOUT = 12.hours
+
+ def initialize(record)
+ @record = record
+ end
+
+ def perform
+ try_obtain_lease do
+ if constraint_exists?
+ log_info('Starting to validate constraint')
+ validate_constraint_with_error_handling
+ log_info('Finished validating constraint')
+ else
+ log_info(skip_log_message)
+ record.destroy!
+ end
+ end
+ end
+
+ private
+
+ attr_reader :record
+
+ delegate :connection, :name, :table_name, :connection_db_config, to: :record
+
+ def constraint_exists?; end
+
+ def validate_constraint_with_error_handling
+ validate_constraint
+ record.destroy!
+ rescue StandardError => error
+ record.handle_exception!(error)
+
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error)
+ Gitlab::AppLogger.error(message: error.message, **logging_options)
+ end
+
+ def validate_constraint
+ set_statement_timeout do
+ connection.execute(<<~SQL.squish)
+ ALTER TABLE #{connection.quote_table_name(table_name)}
+ VALIDATE CONSTRAINT #{connection.quote_column_name(name)};
+ SQL
+ end
+ end
+
+ def set_statement_timeout
+ connection.execute(format("SET statement_timeout TO '%ds'", STATEMENT_TIMEOUT))
+ yield
+ ensure
+ connection.execute('RESET statement_timeout')
+ end
+
+ def lease_timeout
+ TIMEOUT_PER_ACTION
+ end
+
+ def log_info(message)
+ Gitlab::AppLogger.info(message: message, **logging_options)
+ end
+
+ def skip_log_message
+ "Skipping #{name} validation since it does not exist. " \
+ "The queuing entry will be deleted"
+ end
+
+ def logging_options
+ {
+ class: self.class.name.to_s,
+ connection_name: database_config_name,
+ constraint_name: name,
+ constraint_type: record.constraint_type,
+ table_name: table_name
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/async_constraints/validators/check_constraint.rb b/lib/gitlab/database/async_constraints/validators/check_constraint.rb
new file mode 100644
index 00000000000..695ecdebc9f
--- /dev/null
+++ b/lib/gitlab/database/async_constraints/validators/check_constraint.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module AsyncConstraints
+ module Validators
+ class CheckConstraint < Base
+ private
+
+ override :constraint_exists?
+ def constraint_exists?
+ Gitlab::Database::Migrations::ConstraintsHelpers
+ .check_constraint_exists?(table_name, name, connection: connection)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/async_constraints/validators/foreign_key.rb b/lib/gitlab/database/async_constraints/validators/foreign_key.rb
new file mode 100644
index 00000000000..ff6b807c982
--- /dev/null
+++ b/lib/gitlab/database/async_constraints/validators/foreign_key.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module AsyncConstraints
+ module Validators
+ class ForeignKey < Base
+ private
+
+ override :constraint_exists?
+ def constraint_exists?
+ Gitlab::Database::PostgresForeignKey
+ .by_constrained_table_name_or_identifier(table_name)
+ .by_name(name)
+ .exists?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/async_foreign_keys.rb b/lib/gitlab/database/async_foreign_keys.rb
deleted file mode 100644
index 115ae9ba2e8..00000000000
--- a/lib/gitlab/database/async_foreign_keys.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- module AsyncForeignKeys
- DEFAULT_ENTRIES_PER_INVOCATION = 2
-
- def self.validate_pending_entries!(how_many: DEFAULT_ENTRIES_PER_INVOCATION)
- PostgresAsyncForeignKeyValidation.ordered.limit(how_many).each do |record|
- ForeignKeyValidator.new(record).perform
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/database/async_foreign_keys/foreign_key_validator.rb b/lib/gitlab/database/async_foreign_keys/foreign_key_validator.rb
deleted file mode 100644
index 5958c56a45a..00000000000
--- a/lib/gitlab/database/async_foreign_keys/foreign_key_validator.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- module AsyncForeignKeys
- class ForeignKeyValidator
- include AsyncDdlExclusiveLeaseGuard
-
- TIMEOUT_PER_ACTION = 1.day
- STATEMENT_TIMEOUT = 12.hours
-
- def initialize(async_validation)
- @async_validation = async_validation
- end
-
- def perform
- try_obtain_lease do
- if foreign_key_exists?
- log_index_info("Starting to validate foreign key")
- validate_foreign_with_error_handling
- log_index_info("Finished validating foreign key")
- else
- log_index_info(skip_log_message)
- async_validation.destroy!
- end
- end
- end
-
- private
-
- attr_reader :async_validation
-
- delegate :connection, :name, :table_name, :connection_db_config, to: :async_validation
-
- def foreign_key_exists?
- relation = if table_name =~ Gitlab::Database::FULLY_QUALIFIED_IDENTIFIER
- Gitlab::Database::PostgresForeignKey.by_constrained_table_identifier(table_name)
- else
- Gitlab::Database::PostgresForeignKey.by_constrained_table_name(table_name)
- end
-
- relation.by_name(name).exists?
- end
-
- def validate_foreign_with_error_handling
- validate_foreign_key
- async_validation.destroy!
- rescue StandardError => error
- async_validation.handle_exception!(error)
-
- Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error)
- Gitlab::AppLogger.error(message: error.message, **logging_options)
- end
-
- def validate_foreign_key
- set_statement_timeout do
- connection.execute(<<~SQL.squish)
- ALTER TABLE #{connection.quote_table_name(table_name)}
- VALIDATE CONSTRAINT #{connection.quote_column_name(name)};
- SQL
- end
- end
-
- def set_statement_timeout
- connection.execute(format("SET statement_timeout TO '%ds'", STATEMENT_TIMEOUT))
- yield
- ensure
- connection.execute('RESET statement_timeout')
- end
-
- def lease_timeout
- TIMEOUT_PER_ACTION
- end
-
- def log_index_info(message)
- Gitlab::AppLogger.info(message: message, **logging_options)
- end
-
- def skip_log_message
- "Skipping #{name} validation since it does not exist. " \
- "The queuing entry will be deleted"
- end
-
- def logging_options
- {
- fk_name: name,
- table_name: table_name,
- class: self.class.name.to_s
- }
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/database/async_foreign_keys/migration_helpers.rb b/lib/gitlab/database/async_foreign_keys/migration_helpers.rb
deleted file mode 100644
index b8b9fc6d156..00000000000
--- a/lib/gitlab/database/async_foreign_keys/migration_helpers.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- module AsyncForeignKeys
- module MigrationHelpers
- # Prepares a foreign key for asynchronous validation.
- #
- # Stores the FK information in the postgres_async_foreign_key_validations
- # table to be executed later.
- #
- def prepare_async_foreign_key_validation(table_name, column_name = nil, name: nil)
- Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
-
- return unless async_fk_validation_available?
-
- fk_name = name || concurrent_foreign_key_name(table_name, column_name)
-
- unless foreign_key_exists?(table_name, name: fk_name)
- raise missing_schema_object_message(table_name, "foreign key", fk_name)
- end
-
- async_validation = PostgresAsyncForeignKeyValidation
- .find_or_create_by!(name: fk_name, table_name: table_name)
-
- Gitlab::AppLogger.info(
- message: 'Prepared FK for async validation',
- table_name: async_validation.table_name,
- fk_name: async_validation.name)
-
- async_validation
- end
-
- def unprepare_async_foreign_key_validation(table_name, column_name = nil, name: nil)
- Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
-
- return unless async_fk_validation_available?
-
- fk_name = name || concurrent_foreign_key_name(table_name, column_name)
-
- PostgresAsyncForeignKeyValidation.find_by(name: fk_name).try(&:destroy)
- end
-
- def prepare_partitioned_async_foreign_key_validation(table_name, column_name = nil, name: nil)
- Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
-
- return unless async_fk_validation_available?
-
- Gitlab::Database::PostgresPartitionedTable.each_partition(table_name) do |partition|
- prepare_async_foreign_key_validation(partition.identifier, column_name, name: name)
- end
- end
-
- def unprepare_partitioned_async_foreign_key_validation(table_name, column_name = nil, name: nil)
- Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
-
- return unless async_fk_validation_available?
-
- Gitlab::Database::PostgresPartitionedTable.each_partition(table_name) do |partition|
- unprepare_async_foreign_key_validation(partition.identifier, column_name, name: name)
- end
- end
-
- private
-
- def async_fk_validation_available?
- connection.table_exists?(:postgres_async_foreign_key_validations)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb b/lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb
deleted file mode 100644
index de69a3d496f..00000000000
--- a/lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- module AsyncForeignKeys
- class PostgresAsyncForeignKeyValidation < SharedModel
- include QueueErrorHandlingConcern
-
- self.table_name = 'postgres_async_foreign_key_validations'
-
- MAX_IDENTIFIER_LENGTH = Gitlab::Database::MigrationHelpers::MAX_IDENTIFIER_NAME_LENGTH
- MAX_LAST_ERROR_LENGTH = 10_000
-
- validates :name, presence: true, uniqueness: true, length: { maximum: MAX_IDENTIFIER_LENGTH }
- validates :table_name, presence: true, length: { maximum: MAX_IDENTIFIER_LENGTH }
-
- scope :ordered, -> { order(attempts: :asc, id: :asc) }
- end
- end
- end
-end
diff --git a/lib/gitlab/database/background_migration/batch_optimizer.rb b/lib/gitlab/database/background_migration/batch_optimizer.rb
index c8fdf8281cd..9eb456f6e2e 100644
--- a/lib/gitlab/database/background_migration/batch_optimizer.rb
+++ b/lib/gitlab/database/background_migration/batch_optimizer.rb
@@ -43,11 +43,14 @@ module Gitlab
def optimize!
return unless Feature.enabled?(:optimize_batched_migrations, type: :ops)
- if multiplier = batch_size_multiplier
- max_batch = migration.max_batch_size || MAX_BATCH_SIZE
- migration.batch_size = (migration.batch_size * multiplier).to_i.clamp(MIN_BATCH_SIZE, max_batch)
- migration.save!
- end
+ multiplier = batch_size_multiplier
+ return if multiplier.nil?
+
+ max_batch = migration.max_batch_size || MAX_BATCH_SIZE
+ min_batch = [max_batch, MIN_BATCH_SIZE].min
+
+ migration.batch_size = (migration.batch_size * multiplier).to_i.clamp(min_batch, max_batch)
+ migration.save!
end
private
diff --git a/lib/gitlab/database/background_migration/batched_job.rb b/lib/gitlab/database/background_migration/batched_job.rb
index 6b7ff308c7e..5147ea92291 100644
--- a/lib/gitlab/database/background_migration/batched_job.rb
+++ b/lib/gitlab/database/background_migration/batched_job.rb
@@ -4,6 +4,7 @@ module Gitlab
module Database
module BackgroundMigration
SplitAndRetryError = Class.new(StandardError)
+ ReduceSubBatchSizeError = Class.new(StandardError)
class BatchedJob < SharedModel
include EachBatch
@@ -12,6 +13,9 @@ module Gitlab
self.table_name = :batched_background_migration_jobs
MAX_ATTEMPTS = 3
+ MIN_BATCH_SIZE = 1
+ SUB_BATCH_SIZE_REDUCE_FACTOR = 0.75
+ SUB_BATCH_SIZE_THRESHOLD = 65
STUCK_JOBS_TIMEOUT = 1.hour.freeze
TIMEOUT_EXCEPTIONS = [ActiveRecord::StatementTimeout, ActiveRecord::ConnectionTimeoutError,
ActiveRecord::AdapterTimeout, ActiveRecord::LockWaitTimeout,
@@ -59,12 +63,12 @@ module Gitlab
end
after_transition any => :failed do |job, transition|
- error_hash = transition.args.find { |arg| arg[:error].present? }
+ exception, from_sub_batch = job.class.extract_transition_options(transition.args)
- exception = error_hash&.fetch(:error)
+ job.reduce_sub_batch_size! if from_sub_batch && job.can_reduce_sub_batch_size?
job.split_and_retry! if job.can_split?(exception)
- rescue SplitAndRetryError => error
+ rescue SplitAndRetryError, ReduceSubBatchSizeError => error
Gitlab::AppLogger.error(
message: error.message,
batched_job_id: job.id,
@@ -75,9 +79,7 @@ module Gitlab
end
after_transition do |job, transition|
- error_hash = transition.args.find { |arg| arg[:error].present? }
-
- exception = error_hash&.fetch(:error)
+ exception, _ = job.class.extract_transition_options(transition.args)
job.batched_job_transition_logs.create(previous_status: transition.from, next_status: transition.to, exception_class: exception&.class, exception_message: exception&.message)
@@ -100,7 +102,16 @@ module Gitlab
delegate :job_class, :table_name, :column_name, :job_arguments, :job_class_name,
to: :batched_migration, prefix: :migration
- attribute :pause_ms, :integer, default: 100
+ def self.extract_transition_options(args)
+ error_hash = args.find { |arg| arg[:error].present? }
+
+ return [] unless error_hash
+
+ exception = error_hash.fetch(:error)
+ from_sub_batch = error_hash[:from_sub_batch]
+
+ [exception, from_sub_batch]
+ end
def time_efficiency
return unless succeeded?
@@ -113,10 +124,15 @@ module Gitlab
end
def can_split?(exception)
- attempts >= MAX_ATTEMPTS &&
- exception&.class&.in?(TIMEOUT_EXCEPTIONS) &&
- batch_size > sub_batch_size &&
- batch_size > 1
+ return if still_retryable?
+
+ exception.class.in?(TIMEOUT_EXCEPTIONS) && within_batch_size_boundaries?
+ end
+
+ def can_reduce_sub_batch_size?
+ return false unless Feature.enabled?(:reduce_sub_batch_size_on_timeouts)
+
+ still_retryable? && within_batch_size_boundaries?
end
def split_and_retry!
@@ -165,6 +181,51 @@ module Gitlab
end
end
end
+
+ # It reduces the size of +sub_batch_size+ by 25%
+ def reduce_sub_batch_size!
+ raise ReduceSubBatchSizeError, 'Only sub_batch_size of failed jobs can be reduced' unless failed?
+
+ return if sub_batch_exceeds_threshold?
+
+ with_lock do
+ actual_sub_batch_size = sub_batch_size
+ reduced_sub_batch_size = (sub_batch_size * SUB_BATCH_SIZE_REDUCE_FACTOR).to_i.clamp(1, batch_size)
+
+ update!(sub_batch_size: reduced_sub_batch_size)
+
+ Gitlab::AppLogger.warn(
+ message: 'Sub batch size reduced due to timeout',
+ batched_job_id: id,
+ sub_batch_size: actual_sub_batch_size,
+ reduced_sub_batch_size: reduced_sub_batch_size,
+ attempts: attempts,
+ batched_migration_id: batched_migration.id,
+ job_class_name: migration_job_class_name,
+ job_arguments: migration_job_arguments
+ )
+ end
+ end
+
+ def still_retryable?
+ attempts < MAX_ATTEMPTS
+ end
+
+ def within_batch_size_boundaries?
+ batch_size > MIN_BATCH_SIZE && batch_size > sub_batch_size
+ end
+
+ # It doesn't allow sub-batch size to be reduced lower than the threshold
+ #
+ # @info It will prevent the next iteration to reduce the +sub_batch_size+ lower
+ # than the +SUB_BATCH_SIZE_THRESHOLD+ or 65% of its original size.
+ def sub_batch_exceeds_threshold?
+ initial_sub_batch_size = batched_migration.sub_batch_size
+ reduced_sub_batch_size = (sub_batch_size * SUB_BATCH_SIZE_REDUCE_FACTOR).to_i
+ diff = initial_sub_batch_size - reduced_sub_batch_size
+
+ (1.0 * diff / initial_sub_batch_size * 100).round(2) > SUB_BATCH_SIZE_THRESHOLD
+ end
end
end
end
diff --git a/lib/gitlab/database/background_migration/batched_migration.rb b/lib/gitlab/database/background_migration/batched_migration.rb
index 61a660ad14c..429dc79e170 100644
--- a/lib/gitlab/database/background_migration/batched_migration.rb
+++ b/lib/gitlab/database/background_migration/batched_migration.rb
@@ -83,8 +83,6 @@ module Gitlab
end
end
- attribute :pause_ms, :integer, default: 100
-
def self.valid_status
state_machine.states.map(&:name)
end
diff --git a/lib/gitlab/database/background_migration/batched_migration_wrapper.rb b/lib/gitlab/database/background_migration/batched_migration_wrapper.rb
index f1fc3efae9e..8fdaa685ba9 100644
--- a/lib/gitlab/database/background_migration/batched_migration_wrapper.rb
+++ b/lib/gitlab/database/background_migration/batched_migration_wrapper.rb
@@ -15,13 +15,21 @@ module Gitlab
# when starting and finishing execution, and optionally saves batch_metrics
# the migration provides, if any are given.
#
- # The job's batch_metrics are serialized to JSON for storage.
+ # @info The job's batch_metrics are serialized to JSON for storage.
+ #
+ # @info Track exceptions that could happen when processing sub-batches
+ # through +Gitlab::BackgroundMigration::SubBatchTimeoutException+
def perform(batch_tracking_record)
start_tracking_execution(batch_tracking_record)
execute_batch(batch_tracking_record)
batch_tracking_record.succeed!
+ rescue SubBatchTimeoutError => exception
+ caused_by = exception.caused_by
+ batch_tracking_record.failure!(error: caused_by, from_sub_batch: true)
+
+ raise caused_by
rescue Exception => error # rubocop:disable Lint/RescueException
batch_tracking_record.failure!(error: error)
@@ -67,7 +75,8 @@ module Gitlab
sub_batch_size: tracking_record.sub_batch_size,
pause_ms: tracking_record.pause_ms,
job_arguments: tracking_record.migration_job_arguments,
- connection: connection)
+ connection: connection,
+ sub_batch_exception: ::Gitlab::Database::BackgroundMigration::SubBatchTimeoutError)
job_instance.perform
diff --git a/lib/gitlab/database/background_migration/sub_batch_timeout_error.rb b/lib/gitlab/database/background_migration/sub_batch_timeout_error.rb
new file mode 100644
index 00000000000..815dff11e1f
--- /dev/null
+++ b/lib/gitlab/database/background_migration/sub_batch_timeout_error.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module BackgroundMigration
+ class SubBatchTimeoutError < StandardError
+ def initialize(caused_by)
+ @caused_by = caused_by
+
+ super(caused_by)
+ end
+
+ attr_reader :caused_by
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/gitlab_schema.rb b/lib/gitlab/database/gitlab_schema.rb
index 38558512b6a..926a4aeedf1 100644
--- a/lib/gitlab/database/gitlab_schema.rb
+++ b/lib/gitlab/database/gitlab_schema.rb
@@ -45,6 +45,11 @@ module Gitlab
return gitlab_schema
end
+ # Partitions that belong to the CI domain
+ if table_name.start_with?('ci_') && gitlab_schema = views_and_tables_to_schema["p_#{table_name}"]
+ return gitlab_schema
+ end
+
# All tables from `information_schema.` are marked as `internal`
return :gitlab_internal if schema_name == 'information_schema'
@@ -121,6 +126,16 @@ module Gitlab
key_name = data['table_name'] || data['view_name']
+ # rubocop:disable Gitlab/DocUrl
+ if data['gitlab_schema'].nil?
+ raise(
+ UnknownSchemaError,
+ "#{file_path} must specify a valid gitlab_schema for #{key_name}." \
+ "See https://docs.gitlab.com/ee/development/database/database_dictionary.html"
+ )
+ end
+ # rubocop:enable Gitlab/DocUrl
+
dic[key_name] = data['gitlab_schema'].to_sym
end
end
diff --git a/lib/gitlab/database/lock_writes_manager.rb b/lib/gitlab/database/lock_writes_manager.rb
index 83884e89d6e..e8f7b51955d 100644
--- a/lib/gitlab/database/lock_writes_manager.rb
+++ b/lib/gitlab/database/lock_writes_manager.rb
@@ -10,6 +10,8 @@ module Gitlab
# See https://www.postgresql.org/message-id/16934.1568989957%40sss.pgh.pa.us
EXPECTED_TRIGGER_RECORD_COUNT = 3
+ # table_name can include schema name as a prefix. For example: 'gitlab_partitions_static.events_03',
+ # otherwise, it will default to current used schema, for example 'public'.
def initialize(table_name:, connection:, database_name:, with_retries: true, logger: nil, dry_run: false)
@table_name = table_name
@connection = connection
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 9b041c18da4..3a342abe65d 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -14,7 +14,7 @@ module Gitlab
include DynamicModelHelpers
include RenameTableHelpers
include AsyncIndexes::MigrationHelpers
- include AsyncForeignKeys::MigrationHelpers
+ include AsyncConstraints::MigrationHelpers
def define_batchable_model(table_name, connection: self.connection)
super(table_name, connection: connection)
@@ -292,23 +292,34 @@ module Gitlab
# order of the ALTER TABLE. This can be useful in situations where the foreign
# key creation could deadlock with another process.
#
- # rubocop: disable Metrics/ParameterLists
- def add_concurrent_foreign_key(source, target, column:, on_delete: :cascade, on_update: nil, target_column: :id, name: nil, validate: true, reverse_lock_order: false)
+ def add_concurrent_foreign_key(source, target, column:, **options)
+ options.reverse_merge!({
+ on_delete: :cascade,
+ on_update: nil,
+ target_column: :id,
+ validate: true,
+ reverse_lock_order: false,
+ allow_partitioned: false,
+ column: column
+ })
+
# Transactions would result in ALTER TABLE locks being held for the
# duration of the transaction, defeating the purpose of this method.
if transaction_open?
raise 'add_concurrent_foreign_key can not be run inside a transaction'
end
- options = {
- column: column,
- on_delete: on_delete,
- on_update: on_update,
- name: name.presence || concurrent_foreign_key_name(source, column),
- primary_key: target_column
- }
+ if !options.delete(:allow_partitioned) && table_partitioned?(source)
+ raise ArgumentError, 'add_concurrent_foreign_key can not be used on a partitioned ' \
+ 'table. Please use add_concurrent_partitioned_foreign_key on the partitioned table ' \
+ 'as we need to create foreign keys on each partition and a FK on the parent table'
+ end
+
+ options[:name] ||= concurrent_foreign_key_name(source, column)
+ options[:primary_key] = options[:target_column]
+ check_options = options.slice(:column, :on_delete, :on_update, :name, :primary_key)
- if foreign_key_exists?(source, target, **options)
+ if foreign_key_exists?(source, target, **check_options)
warning_message = "Foreign key not created because it exists already " \
"(this may be due to an aborted migration or similar): " \
"source: #{source}, target: #{target}, column: #{options[:column]}, "\
@@ -317,23 +328,7 @@ module Gitlab
Gitlab::AppLogger.warn warning_message
else
- # Using NOT VALID allows us to create a key without immediately
- # validating it. This means we keep the ALTER TABLE lock only for a
- # short period of time. The key _is_ enforced for any newly created
- # data.
-
- with_lock_retries do
- execute("LOCK TABLE #{target}, #{source} IN SHARE ROW EXCLUSIVE MODE") if reverse_lock_order
- execute <<-EOF.strip_heredoc
- ALTER TABLE #{source}
- ADD CONSTRAINT #{options[:name]}
- FOREIGN KEY (#{multiple_columns(options[:column])})
- REFERENCES #{target} (#{multiple_columns(target_column)})
- #{on_update_statement(options[:on_update])}
- #{on_delete_statement(options[:on_delete])}
- NOT VALID;
- EOF
- end
+ execute_add_concurrent_foreign_key(source, target, options)
end
# Validate the existing constraint. This can potentially take a very
@@ -345,13 +340,12 @@ module Gitlab
#
# Note this is a no-op in case the constraint is VALID already
- if validate
+ if options[:validate]
disable_statement_timeout do
execute("ALTER TABLE #{source} VALIDATE CONSTRAINT #{options[:name]};")
end
end
end
- # rubocop: enable Metrics/ParameterLists
def validate_foreign_key(source, column, name: nil)
fk_name = name || concurrent_foreign_key_name(source, column)
@@ -379,7 +373,7 @@ module Gitlab
end
end
- fks = Gitlab::Database::PostgresForeignKey.by_constrained_table_name(source)
+ fks = Gitlab::Database::PostgresForeignKey.by_constrained_table_name_or_identifier(source)
fks = fks.by_referenced_table_name(target) if target
fks = fks.by_name(options[:name]) if options[:name]
@@ -1239,6 +1233,12 @@ into similar problems in the future (e.g. when new tables are created).
end
end
+ def table_partitioned?(table_name)
+ Gitlab::Database::PostgresPartitionedTable
+ .find_by_name_in_current_schema(table_name)
+ .present?
+ end
+
private
def multiple_columns(columns, separator: ', ')
@@ -1354,6 +1354,33 @@ into similar problems in the future (e.g. when new tables are created).
Must end with `_at`}
MESSAGE
end
+
+ def execute_add_concurrent_foreign_key(source, target, options)
+ # Using NOT VALID allows us to create a key without immediately
+ # validating it. This means we keep the ALTER TABLE lock only for a
+ # short period of time. The key _is_ enforced for any newly created
+ # data.
+ not_valid = 'NOT VALID'
+ lock_mode = 'SHARE ROW EXCLUSIVE'
+
+ if table_partitioned?(source)
+ not_valid = ''
+ lock_mode = 'ACCESS EXCLUSIVE'
+ end
+
+ with_lock_retries do
+ execute("LOCK TABLE #{target}, #{source} IN #{lock_mode} MODE") if options[:reverse_lock_order]
+ execute(<<~SQL.squish)
+ ALTER TABLE #{source}
+ ADD CONSTRAINT #{options[:name]}
+ FOREIGN KEY (#{multiple_columns(options[:column])})
+ REFERENCES #{target} (#{multiple_columns(options[:target_column])})
+ #{on_update_statement(options[:on_update])}
+ #{on_delete_statement(options[:on_delete])}
+ #{not_valid};
+ SQL
+ end
+ end
end
end
end
diff --git a/lib/gitlab/database/migration_helpers/convert_to_bigint.rb b/lib/gitlab/database/migration_helpers/convert_to_bigint.rb
new file mode 100644
index 00000000000..cf5640deb3d
--- /dev/null
+++ b/lib/gitlab/database/migration_helpers/convert_to_bigint.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module MigrationHelpers
+ module ConvertToBigint
+ # This helper is extracted for the purpose of
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/392815
+ # so that we can test all combinations just once,
+ # and simplify migration tests.
+ #
+ # Once we are done with the PK conversions we can remove this.
+ def com_or_dev_or_test_but_not_jh?
+ !Gitlab.jh? && (Gitlab.com? || Gitlab.dev_or_test_env?)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/migrations/batched_background_migration_helpers.rb b/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
index e958ce2aba4..cb2a98b553f 100644
--- a/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
+++ b/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
@@ -12,6 +12,7 @@ module Gitlab
# For now, these migrations are not considered ready for general use, for more information see the tracking epic:
# https://gitlab.com/groups/gitlab-org/-/epics/6751
module BatchedBackgroundMigrationHelpers
+ NonExistentMigrationError = Class.new(StandardError)
BATCH_SIZE = 1_000 # Number of rows to process per job
SUB_BATCH_SIZE = 100 # Number of rows to process per sub-batch
BATCH_CLASS_NAME = 'PrimaryKeyBatchingStrategy' # Default batch class for batched migrations
@@ -200,6 +201,12 @@ module Gitlab
def ensure_batched_background_migration_is_finished(job_class_name:, table_name:, column_name:, job_arguments:, finalize: true)
Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_dml_mode!
+ if transaction_open?
+ raise 'The `ensure_batched_background_migration_is_finished` cannot be run inside a transaction. ' \
+ 'You can disable transactions by calling `disable_ddl_transaction!` in the body of ' \
+ 'your migration class.'
+ end
+
Gitlab::Database::BackgroundMigration::BatchedMigration.reset_column_information
migration = Gitlab::Database::BackgroundMigration::BatchedMigration.find_for_configuration(
Gitlab::Database.gitlab_schemas_for_connection(connection),
@@ -213,6 +220,10 @@ module Gitlab
job_arguments: job_arguments
}
+ if ENV['DBLAB_ENVIRONMENT'] && migration.nil?
+ raise NonExistentMigrationError, 'called ensure_batched_background_migration_is_finished with non-existent migration name'
+ end
+
return Gitlab::AppLogger.warn "Could not find batched background migration for the given configuration: #{configuration}" if migration.nil?
return if migration.finished?
diff --git a/lib/gitlab/database/migrations/constraints_helpers.rb b/lib/gitlab/database/migrations/constraints_helpers.rb
index 7b849e3137a..5aafc9f1444 100644
--- a/lib/gitlab/database/migrations/constraints_helpers.rb
+++ b/lib/gitlab/database/migrations/constraints_helpers.rb
@@ -10,6 +10,27 @@ module Gitlab
# https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
MAX_IDENTIFIER_NAME_LENGTH = 63
+ def self.check_constraint_exists?(table, constraint_name, connection:)
+ # Constraint names are unique per table in Postgres, not per schema
+ # Two tables can have constraints with the same name, so we filter by
+ # the table name in addition to using the constraint_name
+
+ check_sql = <<~SQL
+ SELECT COUNT(*)
+ FROM pg_catalog.pg_constraint con
+ INNER JOIN pg_catalog.pg_class rel
+ ON rel.oid = con.conrelid
+ INNER JOIN pg_catalog.pg_namespace nsp
+ ON nsp.oid = con.connamespace
+ WHERE con.contype = 'c'
+ AND con.conname = #{connection.quote(constraint_name)}
+ AND nsp.nspname = #{connection.quote(connection.current_schema)}
+ AND rel.relname = #{connection.quote(table)}
+ SQL
+
+ connection.select_value(check_sql.squish) > 0
+ end
+
# Returns the name for a check constraint
#
# type:
@@ -29,24 +50,7 @@ module Gitlab
end
def check_constraint_exists?(table, constraint_name)
- # Constraint names are unique per table in Postgres, not per schema
- # Two tables can have constraints with the same name, so we filter by
- # the table name in addition to using the constraint_name
-
- check_sql = <<~SQL
- SELECT COUNT(*)
- FROM pg_catalog.pg_constraint con
- INNER JOIN pg_catalog.pg_class rel
- ON rel.oid = con.conrelid
- INNER JOIN pg_catalog.pg_namespace nsp
- ON nsp.oid = con.connamespace
- WHERE con.contype = 'c'
- AND con.conname = #{connection.quote(constraint_name)}
- AND nsp.nspname = #{connection.quote(current_schema)}
- AND rel.relname = #{connection.quote(table)}
- SQL
-
- connection.select_value(check_sql) > 0
+ ConstraintsHelpers.check_constraint_exists?(table, constraint_name, connection: connection)
end
# Adds a check constraint to a table
diff --git a/lib/gitlab/database/migrations/test_batched_background_runner.rb b/lib/gitlab/database/migrations/test_batched_background_runner.rb
index 01fdba22c19..af853c933ba 100644
--- a/lib/gitlab/database/migrations/test_batched_background_runner.rb
+++ b/lib/gitlab/database/migrations/test_batched_background_runner.rb
@@ -27,7 +27,7 @@ module Gitlab
table_max_value = define_batchable_model(migration.table_name, connection: connection)
.maximum(migration.column_name)
- largest_batch_start = table_max_value - migration.batch_size
+ largest_batch_start = [table_max_value - migration.batch_size, smallest_batch_start].max
# variance is the portion of the batch range that we shrink between variance * 0 and variance * 1
# to pick actual batches to sample.
diff --git a/lib/gitlab/database/partitioning.rb b/lib/gitlab/database/partitioning.rb
index 6314aff9914..4a9e002a1a2 100644
--- a/lib/gitlab/database/partitioning.rb
+++ b/lib/gitlab/database/partitioning.rb
@@ -37,8 +37,9 @@ module Gitlab
models_to_sync.each do |model|
next if model < ::Gitlab::Database::SharedModel && !(model < TableWithoutModel)
+ model_connection_name = model.connection_db_config.name
Gitlab::Database::EachDatabase.each_database_connection do |connection, connection_name|
- if connection_name != model.connection_db_config.name
+ if connection_name != model_connection_name
PartitionManager.new(model, connection: connection).sync_partitions
end
end
diff --git a/lib/gitlab/database/partitioning/ci_sliding_list_strategy.rb b/lib/gitlab/database/partitioning/ci_sliding_list_strategy.rb
new file mode 100644
index 00000000000..69a69091b5c
--- /dev/null
+++ b/lib/gitlab/database/partitioning/ci_sliding_list_strategy.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Partitioning
+ class CiSlidingListStrategy < SlidingListStrategy
+ def initial_partition
+ partition_for(100)
+ end
+
+ def next_partition
+ partition_for(active_partition.value + 1)
+ end
+
+ def validate_and_fix; end
+
+ def after_adding_partitions; end
+
+ def extra_partitions
+ []
+ end
+
+ private
+
+ def ensure_partitioning_column_ignored_or_readonly!; end
+
+ def partition_for(value)
+ SingleNumericListPartition.new(table_name, value, partition_name: partition_name(value))
+ end
+
+ def partition_name(value)
+ [
+ table_name.to_s.delete_prefix('p_'),
+ value
+ ].join('_')
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/partitioning/partition_manager.rb b/lib/gitlab/database/partitioning/partition_manager.rb
index 55ca9ff8645..124fae582d3 100644
--- a/lib/gitlab/database/partitioning/partition_manager.rb
+++ b/lib/gitlab/database/partitioning/partition_manager.rb
@@ -34,6 +34,8 @@ module Gitlab
create(partitions_to_create) unless partitions_to_create.empty?
detach(partitions_to_detach) unless partitions_to_detach.empty?
end
+ rescue ArgumentError => e
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
rescue StandardError => e
Gitlab::AppLogger.error(
message: "Failed to create / detach partition(s)",
diff --git a/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers.rb b/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers.rb
index 8849191f356..7d9c12d776e 100644
--- a/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers.rb
+++ b/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers.rb
@@ -32,46 +32,75 @@ module Gitlab
# column - The name of the column to create the foreign key on.
# on_delete - The action to perform when associated data is removed,
# defaults to "CASCADE".
+ # on_update - The action to perform when associated data is updated,
+ # no default value is set.
# name - The name of the foreign key.
+ # validate - Flag that controls whether the new foreign key will be
+ # validated after creation and if it will be added on the parent table.
+ # If the flag is not set, the constraint will only be enforced for new data
+ # in the existing partitions. The helper will need to be called again
+ # with the flag set to `true` to add the foreign key on the parent table
+ # after validating it on all partitions.
+ # `validate: false` should be paired with `prepare_partitioned_async_foreign_key_validation`
+ # reverse_lock_order - Flag that controls whether we should attempt to acquire locks in the reverse
+ # order of the ALTER TABLE. This can be useful in situations where the foreign
+ # key creation could deadlock with another process.
#
- def add_concurrent_partitioned_foreign_key(source, target, column:, on_delete: :cascade, name: nil)
+ def add_concurrent_partitioned_foreign_key(source, target, column:, **options)
assert_not_in_transaction_block(scope: ERROR_SCOPE)
- partition_options = {
- column: column,
- on_delete: on_delete,
+ options.reverse_merge!({
+ target_column: :id,
+ on_delete: :cascade,
+ on_update: nil,
+ name: nil,
+ validate: true,
+ reverse_lock_order: false,
+ column: column
+ })
- # We'll use the same FK name for all partitions and match it to
- # the name used for the partitioned table to follow the convention
- # used by PostgreSQL when adding FKs to new partitions
- name: name.presence || concurrent_partitioned_foreign_key_name(source, column),
+ # We'll use the same FK name for all partitions and match it to
+ # the name used for the partitioned table to follow the convention
+ # used by PostgreSQL when adding FKs to new partitions
+ options[:name] ||= concurrent_partitioned_foreign_key_name(source, column)
+ check_options = options.slice(:column, :on_delete, :on_update, :name)
+ check_options[:primary_key] = options[:target_column]
- # Force the FK validation to true for partitions (and the partitioned table)
- validate: true
- }
-
- if foreign_key_exists?(source, target, **partition_options)
+ if foreign_key_exists?(source, target, **check_options)
warning_message = "Foreign key not created because it exists already " \
"(this may be due to an aborted migration or similar): " \
- "source: #{source}, target: #{target}, column: #{partition_options[:column]}, "\
- "name: #{partition_options[:name]}, on_delete: #{partition_options[:on_delete]}"
+ "source: #{source}, target: #{target}, column: #{options[:column]}, "\
+ "name: #{options[:name]}, on_delete: #{options[:on_delete]}, "\
+ "on_update: #{options[:on_update]}"
Gitlab::AppLogger.warn warning_message
return
end
- partitioned_table = find_partitioned_table(source)
-
- partitioned_table.postgres_partitions.order(:name).each do |partition|
- add_concurrent_foreign_key(partition.identifier, target, **partition_options)
+ Gitlab::Database::PostgresPartitionedTable.each_partition(source) do |partition|
+ add_concurrent_foreign_key(partition.identifier, target, **options)
end
- with_lock_retries do
- add_foreign_key(source, target, **partition_options)
+ # If we are to add the FK on the parent table now, it will trigger
+ # the validation on all partitions. The helper must be called one
+ # more time with `validate: true` after the FK is valid on all partitions.
+ return unless options[:validate]
+
+ options[:allow_partitioned] = true
+ add_concurrent_foreign_key(source, target, **options)
+ end
+
+ def validate_partitioned_foreign_key(source, column, name: nil)
+ assert_not_in_transaction_block(scope: ERROR_SCOPE)
+
+ Gitlab::Database::PostgresPartitionedTable.each_partition(source) do |partition|
+ validate_foreign_key(partition.identifier, column, name: name)
end
end
+ private
+
# Returns the name for a concurrent partitioned foreign key.
#
# Similar to concurrent_foreign_key_name (Gitlab::Database::MigrationHelpers)
diff --git a/lib/gitlab/database/postgres_foreign_key.rb b/lib/gitlab/database/postgres_foreign_key.rb
index 04ef574a451..28044b42f44 100644
--- a/lib/gitlab/database/postgres_foreign_key.rb
+++ b/lib/gitlab/database/postgres_foreign_key.rb
@@ -38,6 +38,14 @@ module Gitlab
scope :by_constrained_table_name, ->(name) { where(constrained_table_name: name) }
+ scope :by_constrained_table_name_or_identifier, ->(name) do
+ if name =~ Database::FULLY_QUALIFIED_IDENTIFIER
+ by_constrained_table_identifier(name)
+ else
+ by_constrained_table_name(name)
+ end
+ end
+
scope :not_inherited, -> { where(is_inherited: false) }
scope :by_name, ->(name) { where(name: name) }
diff --git a/lib/gitlab/database/postgres_partition.rb b/lib/gitlab/database/postgres_partition.rb
index 36dc6818157..e63c6fc86ea 100644
--- a/lib/gitlab/database/postgres_partition.rb
+++ b/lib/gitlab/database/postgres_partition.rb
@@ -7,6 +7,8 @@ module Gitlab
belongs_to :postgres_partitioned_table, foreign_key: 'parent_identifier', primary_key: 'identifier'
+ # identifier includes the partition schema.
+ # For example 'gitlab_partitions_static.events_03', or 'gitlab_partitions_dynamic.logs_03'
scope :for_identifier, ->(identifier) do
unless identifier =~ Gitlab::Database::FULLY_QUALIFIED_IDENTIFIER
raise ArgumentError, "Partition name is not fully qualified with a schema: #{identifier}"
@@ -19,8 +21,12 @@ module Gitlab
for_identifier(identifier).first!
end
- scope :for_parent_table, ->(name) do
- where("parent_identifier = concat(current_schema(), '.', ?)", name).order(:name)
+ scope :for_parent_table, ->(parent_table) do
+ if parent_table =~ Database::FULLY_QUALIFIED_IDENTIFIER
+ where(parent_identifier: parent_table).order(:name)
+ else
+ where("parent_identifier = concat(current_schema(), '.', ?)", parent_table).order(:name)
+ end
end
def self.partition_exists?(table_name)
diff --git a/lib/gitlab/database/reindexing.rb b/lib/gitlab/database/reindexing.rb
index 78de7161a0f..739e573b6c4 100644
--- a/lib/gitlab/database/reindexing.rb
+++ b/lib/gitlab/database/reindexing.rb
@@ -28,7 +28,7 @@ module Gitlab
# 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)
Gitlab::Database::AsyncIndexes.drop_pending_indexes!
- Gitlab::Database::AsyncForeignKeys.validate_pending_entries! if Feature.enabled?(:database_async_foreign_key_validation, type: :ops)
+ Gitlab::Database::AsyncConstraints.validate_pending_entries! if Feature.enabled?(:database_async_foreign_key_validation, type: :ops)
automatic_reindexing
end
diff --git a/lib/gitlab/database/schema_validation/database.rb b/lib/gitlab/database/schema_validation/database.rb
index dfc845f0b44..07bd02e58e1 100644
--- a/lib/gitlab/database/schema_validation/database.rb
+++ b/lib/gitlab/database/schema_validation/database.rb
@@ -4,6 +4,8 @@ module Gitlab
module Database
module SchemaValidation
class Database
+ STATIC_PARTITIONS_SCHEMA = 'gitlab_partitions_static'
+
def initialize(connection)
@connection = connection
end
@@ -12,29 +14,69 @@ module Gitlab
index_map[index_name]
end
+ def fetch_trigger_by_name(trigger_name)
+ trigger_map[trigger_name]
+ end
+
+ def index_exists?(index_name)
+ index_map[index_name].present?
+ end
+
+ def trigger_exists?(trigger_name)
+ trigger_map[trigger_name].present?
+ end
+
def indexes
index_map.values
end
+ def triggers
+ trigger_map.values
+ end
+
private
+ attr_reader :connection
+
+ def schemas
+ @schemas ||= [STATIC_PARTITIONS_SCHEMA, connection.current_schema]
+ end
+
def index_map
@index_map ||=
fetch_indexes.transform_values! do |index_stmt|
- Index.new(PgQuery.parse(index_stmt).tree.stmts.first.stmt.index_stmt)
+ SchemaObjects::Index.new(PgQuery.parse(index_stmt).tree.stmts.first.stmt.index_stmt)
end
end
- attr_reader :connection
+ def trigger_map
+ @trigger_map ||=
+ fetch_triggers.transform_values! do |trigger_stmt|
+ SchemaObjects::Trigger.new(PgQuery.parse(trigger_stmt).tree.stmts.first.stmt.create_trig_stmt)
+ end
+ end
def fetch_indexes
sql = <<~SQL
SELECT indexname, indexdef
FROM pg_indexes
- WHERE indexname NOT LIKE '%_pkey' AND schemaname IN ('public', 'gitlab_partitions_static');
+ WHERE indexname NOT LIKE '%_pkey' AND schemaname IN ($1, $2);
+ SQL
+
+ connection.select_rows(sql, nil, schemas).to_h
+ end
+
+ def fetch_triggers
+ sql = <<~SQL
+ SELECT triggers.tgname, pg_get_triggerdef(triggers.oid)
+ FROM pg_catalog.pg_trigger triggers
+ INNER JOIN pg_catalog.pg_class rel ON triggers.tgrelid = rel.oid
+ INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = rel.relnamespace
+ WHERE triggers.tgisinternal IS FALSE
+ AND nsp.nspname IN ($1, $2)
SQL
- @fetch_indexes ||= connection.exec_query(sql).rows.to_h
+ connection.select_rows(sql, nil, schemas).to_h
end
end
end
diff --git a/lib/gitlab/database/schema_validation/index.rb b/lib/gitlab/database/schema_validation/index.rb
deleted file mode 100644
index af0d5f31f4e..00000000000
--- a/lib/gitlab/database/schema_validation/index.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- module SchemaValidation
- class Index
- def initialize(parsed_stmt)
- @parsed_stmt = parsed_stmt
- end
-
- def name
- parsed_stmt.idxname
- end
-
- def statement
- @statement ||= PgQuery.deparse_stmt(parsed_stmt)
- end
-
- private
-
- attr_reader :parsed_stmt
- end
- end
- end
-end
diff --git a/lib/gitlab/database/schema_validation/indexes.rb b/lib/gitlab/database/schema_validation/indexes.rb
deleted file mode 100644
index b7c3705bde9..00000000000
--- a/lib/gitlab/database/schema_validation/indexes.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- module SchemaValidation
- class Indexes
- def initialize(structure_sql, database)
- @structure_sql = structure_sql
- @database = database
- end
-
- def missing_indexes
- structure_sql.indexes.map(&:name) - database.indexes.map(&:name)
- end
-
- def extra_indexes
- database.indexes.map(&:name) - structure_sql.indexes.map(&:name)
- end
-
- def wrong_indexes
- structure_sql.indexes.filter_map do |structure_sql_index|
- database_index = database.fetch_index_by_name(structure_sql_index.name)
-
- next if database_index.nil?
- next if database_index.statement == structure_sql_index.statement
-
- structure_sql_index.name
- end
- end
-
- private
-
- attr_reader :structure_sql, :database
- end
- end
- end
-end
diff --git a/lib/gitlab/database/schema_validation/runner.rb b/lib/gitlab/database/schema_validation/runner.rb
new file mode 100644
index 00000000000..7a02c8a16d6
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/runner.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ class Runner
+ def initialize(structure_sql, database, validators: Validators::BaseValidator.all_validators)
+ @structure_sql = structure_sql
+ @database = database
+ @validators = validators
+ end
+
+ def execute
+ validators.flat_map { |c| c.new(structure_sql, database).execute }
+ end
+
+ private
+
+ attr_reader :structure_sql, :database, :validators
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/schema_objects/base.rb b/lib/gitlab/database/schema_validation/schema_objects/base.rb
new file mode 100644
index 00000000000..b0c8eb087dd
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/schema_objects/base.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module SchemaObjects
+ class Base
+ def initialize(parsed_stmt)
+ @parsed_stmt = parsed_stmt
+ end
+
+ def name
+ raise NoMethodError, "subclasses of #{self.class.name} must implement #{__method__}"
+ end
+
+ def statement
+ @statement ||= PgQuery.deparse_stmt(parsed_stmt)
+ end
+
+ private
+
+ attr_reader :parsed_stmt
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/schema_objects/index.rb b/lib/gitlab/database/schema_validation/schema_objects/index.rb
new file mode 100644
index 00000000000..28d61b18266
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/schema_objects/index.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module SchemaObjects
+ class Index < Base
+ def name
+ parsed_stmt.idxname
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/schema_objects/trigger.rb b/lib/gitlab/database/schema_validation/schema_objects/trigger.rb
new file mode 100644
index 00000000000..508e6b27ed3
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/schema_objects/trigger.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module SchemaObjects
+ class Trigger < Base
+ def name
+ parsed_stmt.trigname
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/structure_sql.rb b/lib/gitlab/database/schema_validation/structure_sql.rb
index 32c69a0e5e7..cb62af8d8b8 100644
--- a/lib/gitlab/database/schema_validation/structure_sql.rb
+++ b/lib/gitlab/database/schema_validation/structure_sql.rb
@@ -4,29 +4,56 @@ module Gitlab
module Database
module SchemaValidation
class StructureSql
- def initialize(structure_file_path)
+ DEFAULT_SCHEMA = 'public'
+
+ def initialize(structure_file_path, schema_name = DEFAULT_SCHEMA)
@structure_file_path = structure_file_path
+ @schema_name = schema_name
+ end
+
+ def index_exists?(index_name)
+ indexes.find { |index| index.name == index_name }.present?
+ end
+
+ def trigger_exists?(trigger_name)
+ triggers.find { |trigger| trigger.name == trigger_name }.present?
end
def indexes
- @indexes ||= index_statements.map do |index_statement|
- index_statement.relation.schemaname = "public" if index_statement.relation.schemaname == ''
+ @indexes ||= map_with_default_schema(index_statements, SchemaObjects::Index)
+ end
- Index.new(index_statement)
- end
+ def triggers
+ @triggers ||= map_with_default_schema(trigger_statements, SchemaObjects::Trigger)
end
private
- attr_reader :structure_file_path
+ attr_reader :structure_file_path, :schema_name
def index_statements
- parsed_structure_file.tree.stmts.filter_map { |s| s.stmt.index_stmt }
+ statements.filter_map { |s| s.stmt.index_stmt }
+ end
+
+ def trigger_statements
+ statements.filter_map { |s| s.stmt.create_trig_stmt }
+ end
+
+ def statements
+ @statements ||= parsed_structure_file.tree.stmts
end
def parsed_structure_file
PgQuery.parse(File.read(structure_file_path))
end
+
+ def map_with_default_schema(statements, validation_class)
+ statements.map do |statement|
+ statement.relation.schemaname = schema_name if statement.relation.schemaname == ''
+
+ validation_class.new(statement)
+ end
+ end
end
end
end
diff --git a/lib/gitlab/database/schema_validation/validators/base_validator.rb b/lib/gitlab/database/schema_validation/validators/base_validator.rb
new file mode 100644
index 00000000000..14995b5f378
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/base_validator.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class BaseValidator
+ Inconsistency = Struct.new(:type, :object_name, :statement)
+
+ def initialize(structure_sql, database)
+ @structure_sql = structure_sql
+ @database = database
+ end
+
+ def self.all_validators
+ [
+ ExtraIndexes,
+ ExtraTriggers,
+ MissingIndexes,
+ MissingTriggers,
+ DifferentDefinitionIndexes,
+ DifferentDefinitionTriggers
+ ]
+ end
+
+ def execute
+ raise NoMethodError, "subclasses of #{self.class.name} must implement #{__method__}"
+ end
+
+ private
+
+ attr_reader :structure_sql, :database
+
+ def build_inconsistency(validator_class, schema_object)
+ inconsistency_type = validator_class.name.demodulize.underscore
+
+ Inconsistency.new(inconsistency_type, schema_object.name, schema_object.statement)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/different_definition_indexes.rb b/lib/gitlab/database/schema_validation/validators/different_definition_indexes.rb
new file mode 100644
index 00000000000..d54b62ac1e7
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/different_definition_indexes.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class DifferentDefinitionIndexes < BaseValidator
+ def execute
+ structure_sql.indexes.filter_map do |structure_sql_index|
+ database_index = database.fetch_index_by_name(structure_sql_index.name)
+
+ next if database_index.nil?
+ next if database_index.statement == structure_sql_index.statement
+
+ build_inconsistency(self.class, structure_sql_index)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/different_definition_triggers.rb b/lib/gitlab/database/schema_validation/validators/different_definition_triggers.rb
new file mode 100644
index 00000000000..efb87a70ca8
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/different_definition_triggers.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class DifferentDefinitionTriggers < BaseValidator
+ def execute
+ structure_sql.triggers.filter_map do |structure_sql_trigger|
+ database_trigger = database.fetch_trigger_by_name(structure_sql_trigger.name)
+
+ next if database_trigger.nil?
+ next if database_trigger.statement == structure_sql_trigger.statement
+
+ build_inconsistency(self.class, structure_sql_trigger)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/extra_indexes.rb b/lib/gitlab/database/schema_validation/validators/extra_indexes.rb
new file mode 100644
index 00000000000..28384dd7cee
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/extra_indexes.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class ExtraIndexes < BaseValidator
+ def execute
+ database.indexes.filter_map do |index|
+ next if structure_sql.index_exists?(index.name)
+
+ build_inconsistency(self.class, index)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/extra_triggers.rb b/lib/gitlab/database/schema_validation/validators/extra_triggers.rb
new file mode 100644
index 00000000000..f03bb49526c
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/extra_triggers.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class ExtraTriggers < BaseValidator
+ def execute
+ database.triggers.filter_map do |trigger|
+ next if structure_sql.trigger_exists?(trigger.name)
+
+ build_inconsistency(self.class, trigger)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/missing_indexes.rb b/lib/gitlab/database/schema_validation/validators/missing_indexes.rb
new file mode 100644
index 00000000000..ac0ea0152ba
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/missing_indexes.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class MissingIndexes < BaseValidator
+ def execute
+ structure_sql.indexes.filter_map do |index|
+ next if database.index_exists?(index.name)
+
+ build_inconsistency(self.class, index)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/missing_triggers.rb b/lib/gitlab/database/schema_validation/validators/missing_triggers.rb
new file mode 100644
index 00000000000..c7137c68c1c
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/missing_triggers.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class MissingTriggers < BaseValidator
+ def execute
+ structure_sql.triggers.filter_map do |index|
+ next if database.trigger_exists?(index.name)
+
+ build_inconsistency(self.class, index)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/tables_locker.rb b/lib/gitlab/database/tables_locker.rb
index c417ce716e8..42a2c5c02f7 100644
--- a/lib/gitlab/database/tables_locker.rb
+++ b/lib/gitlab/database/tables_locker.rb
@@ -16,11 +16,13 @@ module Gitlab
# TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/366834
next if schema_name.in? GITLAB_SCHEMAS_TO_IGNORE
- lock_writes_manager(table_name, connection, database_name).unlock_writes
+ unlock_writes_on_table(table_name, connection, database_name)
end
end
end
+ # It locks the tables on the database where they don't belong. Also it unlocks the tables
+ # on the database where they belong
def lock_writes
Gitlab::Database::EachDatabase.each_database_connection(include_shared: false) do |connection, database_name|
schemas_for_connection = Gitlab::Database.gitlab_schemas_for_connection(connection)
@@ -30,9 +32,9 @@ module Gitlab
next if schema_name.in? GITLAB_SCHEMAS_TO_IGNORE
if schemas_for_connection.include?(schema_name)
- lock_writes_manager(table_name, connection, database_name).unlock_writes
+ unlock_writes_on_table(table_name, connection, database_name)
else
- lock_writes_manager(table_name, connection, database_name).lock_writes
+ lock_writes_on_table(table_name, connection, database_name)
end
end
end
@@ -40,6 +42,24 @@ module Gitlab
private
+ # Unlocks the writes on the table and its partitions
+ def unlock_writes_on_table(table_name, connection, database_name)
+ lock_writes_manager(table_name, connection, database_name).unlock_writes
+
+ table_attached_partitions(table_name, connection) do |postgres_partition|
+ lock_writes_manager(postgres_partition.identifier, connection, database_name).unlock_writes
+ end
+ end
+
+ # It locks the writes on the table and its partitions
+ def lock_writes_on_table(table_name, connection, database_name)
+ lock_writes_manager(table_name, connection, database_name).lock_writes
+
+ table_attached_partitions(table_name, connection) do |postgres_partition|
+ lock_writes_manager(postgres_partition.identifier, connection, database_name).lock_writes
+ end
+ end
+
def tables_to_lock(connection, &block)
Gitlab::Database::GitlabSchema.tables_to_schema.each(&block)
@@ -50,6 +70,14 @@ module Gitlab
end
end
+ def table_attached_partitions(table_name, connection, &block)
+ Gitlab::Database::SharedModel.using_connection(connection) do
+ break unless Gitlab::Database::PostgresPartitionedTable.find_by_name_in_current_schema(table_name)
+
+ Gitlab::Database::PostgresPartitionedTable.each_partition(table_name, &block)
+ end
+ end
+
def lock_writes_manager(table_name, connection, database_name)
Gitlab::Database::LockWritesManager.new(
table_name: table_name,
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 9796a5905e3..85ac816f712 100644
--- a/lib/gitlab/database_importers/work_items/base_type_importer.rb
+++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb
@@ -18,7 +18,8 @@ module Gitlab
progress: 'Progress',
status: 'Status',
requirement_legacy: 'Requirement legacy',
- test_reports: 'Test reports'
+ test_reports: 'Test reports',
+ notifications: 'Notifications'
}.freeze
WIDGETS_FOR_TYPE = {
@@ -32,23 +33,27 @@ module Gitlab
:notes,
:iteration,
:weight,
- :health_status
+ :health_status,
+ :notifications
],
incident: [
:description,
:hierarchy,
- :notes
+ :notes,
+ :notifications
],
test_case: [
:description,
- :notes
+ :notes,
+ :notifications
],
requirement: [
:description,
:notes,
:status,
:requirement_legacy,
- :test_reports
+ :test_reports,
+ :notifications
],
task: [
:assignees,
@@ -59,7 +64,8 @@ module Gitlab
:milestone,
:notes,
:iteration,
- :weight
+ :weight,
+ :notifications
],
objective: [
:assignees,
@@ -69,7 +75,8 @@ module Gitlab
:milestone,
:notes,
:health_status,
- :progress
+ :progress,
+ :notifications
],
key_result: [
:assignees,
@@ -79,7 +86,8 @@ module Gitlab
:start_and_due_date,
:notes,
:health_status,
- :progress
+ :progress,
+ :notifications
]
}.freeze
diff --git a/lib/gitlab/design_management/copy_design_collection_model_attributes.yml b/lib/gitlab/design_management/copy_design_collection_model_attributes.yml
index 95f15bd6dee..fe1baeb7b67 100644
--- a/lib/gitlab/design_management/copy_design_collection_model_attributes.yml
+++ b/lib/gitlab/design_management/copy_design_collection_model_attributes.yml
@@ -16,6 +16,7 @@
design_attributes:
- filename
- relative_position
+ - description
version_attributes:
- author_id
@@ -30,6 +31,8 @@ ignore_design_attributes:
- issue_id
- project_id
- iid
+ - description_html
+ - cached_markdown_version
ignore_version_attributes:
- id
diff --git a/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512.rb b/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512.rb
index e0884557496..0624fe934f9 100644
--- a/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512.rb
+++ b/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512.rb
@@ -10,9 +10,7 @@ module Gitlab
# additional security.
SALT = ''
- def self.transform_secret(plain_secret, stored_as_hash = false)
- return plain_secret if Feature.disabled?(:hash_oauth_secrets) && !stored_as_hash
-
+ def self.transform_secret(plain_secret)
Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.digest(plain_secret, STRETCHES, SALT)
end
@@ -28,8 +26,7 @@ module Gitlab
# Securely compare the given +input+ value with a +stored+ value
# processed by +transform_secret+.
def self.secret_matches?(input, stored)
- stored_as_hash = stored.starts_with?('$pbkdf2-')
- transformed_input = transform_secret(input, stored_as_hash)
+ transformed_input = transform_secret(input)
ActiveSupport::SecurityUtils.secure_compare transformed_input, stored
end
end
diff --git a/lib/gitlab/email/html_to_markdown_parser.rb b/lib/gitlab/email/html_to_markdown_parser.rb
index 42dd012308b..5dd3725cc3e 100644
--- a/lib/gitlab/email/html_to_markdown_parser.rb
+++ b/lib/gitlab/email/html_to_markdown_parser.rb
@@ -5,25 +5,46 @@ require 'nokogiri'
module Gitlab
module Email
class HtmlToMarkdownParser < Html2Text
- ADDITIONAL_TAGS = %w[em strong img details].freeze
- IMG_ATTRS = %w[alt src].freeze
+ extend Gitlab::Utils::Override
+ # List of tags to be converted by Markdown.
+ #
+ # All attributes are removed except for the defined ones.
+ #
+ # <tag> => [<attribute to keep>, ...]
+ ALLOWED_TAG_ATTRIBUTES = {
+ 'em' => [],
+ 'strong' => [],
+ 'details' => [],
+ 'img' => %w[alt src]
+ }.freeze
+ private_constant :ALLOWED_TAG_ATTRIBUTES
+
+ # This redefinition can be removed once https://github.com/soundasleep/html2text_ruby/pull/30
+ # is merged and released.
def self.convert(html)
html = fix_newlines(replace_entities(html))
doc = Nokogiri::HTML(html)
- HtmlToMarkdownParser.new(doc).convert
+ new(doc).convert
end
+ private
+
+ override :iterate_over
def iterate_over(node)
- return super unless ADDITIONAL_TAGS.include?(node.name)
+ allowed_attributes = ALLOWED_TAG_ATTRIBUTES[node.name]
+ return super unless allowed_attributes
- if node.name == 'img'
- node.keys.each { |key| node.remove_attribute(key) unless IMG_ATTRS.include?(key) } # rubocop:disable Style/HashEachMethods
- end
+ remove_attributes(node, allowed_attributes)
Kramdown::Document.new(node.to_html, input: 'html').to_commonmark
end
+
+ def remove_attributes(node, allowed_attributes)
+ to_remove = (node.keys - allowed_attributes)
+ to_remove.each { |key| node.remove_attribute(key) }
+ end
end
end
end
diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb
index 32794a6c99d..664f0a1bb4a 100644
--- a/lib/gitlab/email/receiver.rb
+++ b/lib/gitlab/email/receiver.rb
@@ -177,7 +177,7 @@ module Gitlab
def recipients_from_received_headers
strong_memoize :emails_from_received_headers do
- received.map { |header| header.value[RECEIVED_HEADER_REGEX, 1] }.compact
+ received.filter_map { |header| header.value[RECEIVED_HEADER_REGEX, 1] }
end
end
diff --git a/lib/gitlab/etag_caching/router/graphql.rb b/lib/gitlab/etag_caching/router/graphql.rb
index 7a0fb2ac269..b53164ac94c 100644
--- a/lib/gitlab/etag_caching/router/graphql.rb
+++ b/lib/gitlab/etag_caching/router/graphql.rb
@@ -16,7 +16,7 @@ module Gitlab
[
%r(\Apipelines/sha/\w{7,40}\z),
'ci_editor',
- 'pipeline_authoring'
+ 'pipeline_composition'
],
[
%r(\Aon_demand_scan/counts/),
diff --git a/lib/gitlab/exception_log_formatter.rb b/lib/gitlab/exception_log_formatter.rb
index ce802b562f0..52ad67d6f8b 100644
--- a/lib/gitlab/exception_log_formatter.rb
+++ b/lib/gitlab/exception_log_formatter.rb
@@ -17,6 +17,10 @@ module Gitlab
payload['exception.backtrace'] = Rails.backtrace_cleaner.clean(exception.backtrace)
end
+ if exception.cause
+ payload['exception.cause_class'] = exception.cause.class.name
+ end
+
if sql = find_sql(exception)
payload['exception.sql'] = sql
end
diff --git a/lib/gitlab/file_finder.rb b/lib/gitlab/file_finder.rb
index 95f896a74e9..8a894901ca1 100644
--- a/lib/gitlab/file_finder.rb
+++ b/lib/gitlab/file_finder.rb
@@ -44,15 +44,11 @@ module Gitlab
# Overridden in Gitlab::WikiFileFinder
def search_paths(query)
- if Feature.enabled?(:code_basic_search_files_by_regexp, project)
- return [] if query.blank? || ref.blank?
-
- escaped_query = RE2::Regexp.escape(query)
- query_regexp = Gitlab::EncodingHelper.encode_utf8_no_detect("(?i)#{escaped_query}")
- repository.search_files_by_regexp(query_regexp, ref)
- else
- repository.search_files_by_name(query, ref)
- end
+ return [] if query.blank? || ref.blank?
+
+ escaped_query = RE2::Regexp.escape(query)
+ query_regexp = Gitlab::EncodingHelper.encode_utf8_no_detect("(?i)#{escaped_query}")
+ repository.search_files_by_regexp(query_regexp, ref)
end
end
end
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 8e1b51fcec5..eb204a7dd8e 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require_dependency 'gitlab/encoding_helper'
+require_relative 'encoding_helper'
module Gitlab
module Git
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index 267107e04e6..3a65c7c334d 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -16,7 +16,7 @@ module Gitlab
SERIALIZE_KEYS = [
:id, :message, :parent_ids,
:authored_date, :author_name, :author_email,
- :committed_date, :committer_name, :committer_email, :trailers
+ :committed_date, :committer_name, :committer_email, :trailers, :referenced_by
].freeze
attr_accessor(*SERIALIZE_KEYS)
@@ -414,6 +414,7 @@ module Gitlab
@committer_email = commit.committer.email.dup
@parent_ids = Array(commit.parent_ids)
@trailers = commit.trailers.to_h { |t| [t.key, t.value] }
+ @referenced_by = Array(commit.referenced_by)
end
# Gitaly provides a UNIX timestamp in author.date.seconds, and a timezone
diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb
index 0ffe8bee953..b4dd880ceb7 100644
--- a/lib/gitlab/git/diff_collection.rb
+++ b/lib/gitlab/git/diff_collection.rb
@@ -24,6 +24,8 @@ module Gitlab
limits[:safe_max_lines] = [limits[:max_lines], defaults[:max_lines]].min
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
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index e054b6df98f..95633400aee 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -803,27 +803,17 @@ module Gitlab
end
end
- def license(from_gitaly)
+ def license
wrapped_gitaly_errors do
response = gitaly_repository_client.find_license
break nil if response.license_short_name.empty?
- if from_gitaly
- break ::Gitlab::Git::DeclaredLicense.new(key: response.license_short_name,
- name: response.license_name,
- nickname: response.license_nickname.presence,
- url: response.license_url.presence,
- path: response.license_path)
- end
-
- licensee_object = Licensee::License.new(response.license_short_name)
-
- break nil if licensee_object.name.blank?
-
- licensee_object.meta.nickname = "LICENSE" if licensee_object.key == "other"
-
- licensee_object
+ ::Gitlab::Git::DeclaredLicense.new(key: response.license_short_name,
+ name: response.license_name,
+ nickname: response.license_nickname.presence,
+ url: response.license_url.presence,
+ path: response.license_path)
end
rescue Licensee::InvalidLicense => e
Gitlab::ErrorTracking.track_exception(e)
diff --git a/lib/gitlab/git/rugged_impl/tree.rb b/lib/gitlab/git/rugged_impl/tree.rb
index 66cfc02130b..c7a981c7dd4 100644
--- a/lib/gitlab/git/rugged_impl/tree.rb
+++ b/lib/gitlab/git/rugged_impl/tree.rb
@@ -130,7 +130,6 @@ module Gitlab
new(
id: entry[:oid],
- root_id: root_tree.oid,
name: entry[:name],
type: entry[:type],
mode: entry[:filemode].to_s(8),
diff --git a/lib/gitlab/git/tree.rb b/lib/gitlab/git/tree.rb
index f0eef619e13..e437f99dab3 100644
--- a/lib/gitlab/git/tree.rb
+++ b/lib/gitlab/git/tree.rb
@@ -6,7 +6,7 @@ module Gitlab
include Gitlab::EncodingHelper
extend Gitlab::Git::WrapsGitalyErrors
- attr_accessor :id, :root_id, :type, :mode, :commit_id, :submodule_url
+ attr_accessor :id, :type, :mode, :commit_id, :submodule_url
attr_writer :name, :path, :flat_path
class << self
@@ -61,7 +61,7 @@ module Gitlab
end
def initialize(options)
- %w(id root_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/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 4df9d800ea6..b7f2d7d3e11 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -146,7 +146,6 @@ module Gitlab
message.entries.map do |gitaly_tree_entry|
Gitlab::Git::Tree.new(
id: gitaly_tree_entry.oid,
- root_id: gitaly_tree_entry.root_oid,
type: gitaly_tree_entry.type.downcase,
mode: gitaly_tree_entry.mode.to_s(8),
name: File.basename(gitaly_tree_entry.path),
@@ -423,7 +422,8 @@ module Gitlab
first_parent: !!options[:first_parent],
global_options: parse_global_options!(options),
disable_walk: true, # This option is deprecated. The 'walk' implementation is being removed.
- trailers: options[:trailers]
+ trailers: options[:trailers],
+ include_referenced_by: options[:include_referenced_by]
)
request.after = GitalyClient.timestamp(options[:after]) if options[:after]
request.before = GitalyClient.timestamp(options[:before]) if options[:before]
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index ac6491e8770..525d7064dae 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -239,7 +239,7 @@ module Gitlab
sort_by = 'name' if sort_by == 'name_asc'
enum_value = Gitaly::FindLocalBranchesRequest::SortBy.resolve(sort_by.upcase.to_sym)
- raise ArgumentError, "Invalid sort_by key `#{sort_by}`" unless enum_value
+ return Gitaly::FindLocalBranchesRequest::SortBy::NAME unless enum_value
enum_value
end
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index bcc03ca08c9..93d58710b0c 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -109,7 +109,7 @@ module Gitlab
# rubocop: enable Metrics/ParameterLists
def create_repository(default_branch = nil)
- request = Gitaly::CreateRepositoryRequest.new(repository: @gitaly_repo, default_branch: default_branch)
+ request = Gitaly::CreateRepositoryRequest.new(repository: @gitaly_repo, default_branch: encode_binary(default_branch))
gitaly_client_call(@storage, :repository_service, :create_repository, request, timeout: GitalyClient.fast_timeout)
end
@@ -306,18 +306,18 @@ module Gitlab
end
def search_files_by_name(ref, query, limit: 0, offset: 0)
- request = Gitaly::SearchFilesByNameRequest.new(repository: @gitaly_repo, ref: ref, query: query, limit: limit, offset: offset)
+ request = Gitaly::SearchFilesByNameRequest.new(repository: @gitaly_repo, ref: encode_binary(ref), query: query, limit: limit, offset: offset)
gitaly_client_call(@storage, :repository_service, :search_files_by_name, request, timeout: GitalyClient.fast_timeout).flat_map(&:files)
end
def search_files_by_content(ref, query, options = {})
- request = Gitaly::SearchFilesByContentRequest.new(repository: @gitaly_repo, ref: ref, query: query)
+ request = Gitaly::SearchFilesByContentRequest.new(repository: @gitaly_repo, ref: encode_binary(ref), query: query)
response = gitaly_client_call(@storage, :repository_service, :search_files_by_content, request, timeout: GitalyClient.default_timeout)
search_results_from_response(response, options)
end
def search_files_by_regexp(ref, filter, limit: 0, offset: 0)
- request = Gitaly::SearchFilesByNameRequest.new(repository: @gitaly_repo, ref: ref, query: '.', filter: filter, limit: limit, offset: offset)
+ request = Gitaly::SearchFilesByNameRequest.new(repository: @gitaly_repo, ref: encode_binary(ref), query: '.', filter: filter, limit: limit, offset: offset)
gitaly_client_call(@storage, :repository_service, :search_files_by_name, request, timeout: GitalyClient.fast_timeout).flat_map(&:files)
end
diff --git a/lib/gitlab/github_import/clients/proxy.rb b/lib/gitlab/github_import/clients/proxy.rb
index b12df404640..27030f5382a 100644
--- a/lib/gitlab/github_import/clients/proxy.rb
+++ b/lib/gitlab/github_import/clients/proxy.rb
@@ -6,6 +6,10 @@ module Gitlab
class Proxy
attr_reader :client
+ delegate :each_object, :user, :octokit, to: :client
+
+ REPOS_COUNT_CACHE_KEY = 'github-importer/provider-repo-count/%{type}/%{user_id}'
+
def initialize(access_token, client_options)
@client = pick_client(access_token, client_options)
end
@@ -13,24 +17,26 @@ module Gitlab
def repos(search_text, options)
return { repos: filtered(client.repos, search_text) } if use_legacy?
- if use_graphql?
- fetch_repos_via_graphql(search_text, options)
- else
- fetch_repos_via_rest(search_text, options)
- end
+ fetch_repos_via_graphql(search_text, options)
end
- private
+ def count_repos_by(relation_type, user_id)
+ return if use_legacy?
+
+ key = format(REPOS_COUNT_CACHE_KEY, type: relation_type, user_id: user_id)
- def fetch_repos_via_rest(search_text, options)
- { repos: client.search_repos_by_name(search_text, options)[:items] }
+ ::Gitlab::Cache::Import::Caching.read_integer(key, timeout: 5.minutes) ||
+ fetch_and_cache_repos_count_via_graphql(relation_type, key)
end
+ private
+
def fetch_repos_via_graphql(search_text, options)
response = client.search_repos_by_name_graphql(search_text, options)
{
repos: response.dig(:data, :search, :nodes),
- page_info: response.dig(:data, :search, :pageInfo)
+ page_info: response.dig(:data, :search, :pageInfo),
+ count: response.dig(:data, :search, :repositoryCount)
}
end
@@ -50,8 +56,11 @@ module Gitlab
Feature.disabled?(:remove_legacy_github_client)
end
- def use_graphql?
- Feature.enabled?(:github_client_fetch_repos_via_graphql)
+ def fetch_and_cache_repos_count_via_graphql(relation_type, key)
+ response = client.count_repos_by_relation_type_graphql(relation_type: relation_type)
+ count = response.dig(:data, :search, :repositoryCount)
+
+ ::Gitlab::Cache::Import::Caching.write(key, count, timeout: 5.minutes)
end
end
end
diff --git a/lib/gitlab/github_import/clients/search_repos.rb b/lib/gitlab/github_import/clients/search_repos.rb
index b72e5ac7751..5e058fc0933 100644
--- a/lib/gitlab/github_import/clients/search_repos.rb
+++ b/lib/gitlab/github_import/clients/search_repos.rb
@@ -5,24 +5,24 @@ module Gitlab
module Clients
module SearchRepos
def search_repos_by_name_graphql(name, options = {})
- with_retry do
- octokit.post(
- '/graphql',
- { query: graphql_search_repos_body(name, options) }.to_json
- ).to_h
- end
+ graphql_request(graphql_search_repos_body(name, options))
+ end
+
+ def count_repos_by_relation_type_graphql(options)
+ graphql_request(count_by_relation_type_query(options))
end
- def search_repos_by_name(name, options = {})
- search_query = search_repos_query(name, options)
+ private
+ def graphql_request(query)
with_retry do
- octokit.search_repositories(search_query, options).to_h
+ octokit.post(
+ '/graphql',
+ { query: query }.to_json
+ ).to_h
end
end
- private
-
def graphql_search_repos_body(name, options)
query = search_repos_query(name, options)
query = "query: \"#{query}\""
@@ -45,7 +45,8 @@ module Gitlab
endCursor
hasNextPage
hasPreviousPage
- }
+ },
+ repositoryCount
}
}
TEXT
@@ -64,7 +65,11 @@ module Gitlab
end
def organization_repos_query(search_string, options)
- "#{search_string} org:#{options[:organization_login]}"
+ if options[:organization_login].present?
+ "#{search_string} org:#{options[:organization_login]}"
+ else
+ organizations_subquery
+ end
end
def collaborated_repos_query(search_string)
@@ -95,6 +100,18 @@ module Gitlab
.map { |org| "org:#{org[:login]}" }
.join(' ')
end
+
+ def count_by_relation_type_query(options)
+ query = search_repos_query(nil, options)
+ query = "query: \"#{query}\""
+ <<-TEXT
+ {
+ search(type: REPOSITORY, #{query}) {
+ repositoryCount
+ }
+ }
+ TEXT
+ end
end
end
end
diff --git a/lib/gitlab/github_import/importer/collaborator_importer.rb b/lib/gitlab/github_import/importer/collaborator_importer.rb
new file mode 100644
index 00000000000..9a90ea5a4ed
--- /dev/null
+++ b/lib/gitlab/github_import/importer/collaborator_importer.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module Importer
+ class CollaboratorImporter
+ attr_reader :collaborator, :project, :client, :members_finder
+
+ # collaborator - An instance of `Gitlab::GithubImport::Representation::Collaborator`
+ # project - An instance of `Project`
+ # client - An instance of `Gitlab::GithubImport::Client`
+ def initialize(collaborator, project, client)
+ @collaborator = collaborator
+ @project = project
+ @client = client
+ @members_finder = ::MembersFinder.new(project, project.creator)
+ end
+
+ def execute
+ user_finder = GithubImport::UserFinder.new(project, client)
+ user_id = user_finder.user_id_for(collaborator)
+ return if user_id.nil?
+
+ membership = existing_user_membership(user_id)
+ access_level = map_access_level
+ return if membership && membership[:access_level] >= map_access_level
+
+ create_membership!(user_id, access_level)
+ end
+
+ private
+
+ def existing_user_membership(user_id)
+ members_finder.execute.find_by_user_id(user_id)
+ end
+
+ def map_access_level
+ access_level =
+ case collaborator[:role_name]
+ when 'read' then Gitlab::Access::GUEST
+ when 'triage' then Gitlab::Access::REPORTER
+ when 'write' then Gitlab::Access::DEVELOPER
+ when 'maintain' then Gitlab::Access::MAINTAINER
+ when 'admin' then Gitlab::Access::OWNER
+ end
+ return access_level if access_level
+
+ raise(
+ ::Gitlab::GithubImport::ObjectImporter::NotRetriableError,
+ "Unknown GitHub role: #{collaborator[:role_name]}"
+ )
+ end
+
+ def create_membership!(user_id, access_level)
+ ::ProjectMember.create!(
+ source: project,
+ access_level: access_level,
+ user_id: user_id,
+ member_namespace_id: project.project_namespace_id,
+ created_by_id: project.creator_id
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/importer/collaborators_importer.rb b/lib/gitlab/github_import/importer/collaborators_importer.rb
new file mode 100644
index 00000000000..dd947632d01
--- /dev/null
+++ b/lib/gitlab/github_import/importer/collaborators_importer.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module Importer
+ class CollaboratorsImporter
+ include ParallelScheduling
+
+ def importer_class
+ CollaboratorImporter
+ end
+
+ def representation_class
+ Representation::Collaborator
+ end
+
+ def sidekiq_worker_class
+ ImportCollaboratorWorker
+ end
+
+ def object_type
+ :collaborator
+ end
+
+ def collection_method
+ :collaborators
+ end
+
+ def id_for_already_imported_cache(collaborator)
+ collaborator[:id]
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/importer/events/cross_referenced.rb b/lib/gitlab/github_import/importer/events/cross_referenced.rb
index b56ae186d3c..4fe371e5900 100644
--- a/lib/gitlab/github_import/importer/events/cross_referenced.rb
+++ b/lib/gitlab/github_import/importer/events/cross_referenced.rb
@@ -55,6 +55,7 @@ module Gitlab
record = record_class.new(id: db_id, iid: iid)
record.project = project
+ record.namespace = project.project_namespace if record.respond_to?(:namespace)
record.readonly!
record
end
diff --git a/lib/gitlab/github_import/importer/label_links_importer.rb b/lib/gitlab/github_import/importer/label_links_importer.rb
index 52c87dda347..a20fec4b2ba 100644
--- a/lib/gitlab/github_import/importer/label_links_importer.rb
+++ b/lib/gitlab/github_import/importer/label_links_importer.rb
@@ -25,6 +25,8 @@ module Gitlab
items = []
target_id = find_target_id
+ return if target_id.blank?
+
issue.label_names.each do |label_name|
# Although unlikely it's technically possible for an issue to be
# given a label that was created and assigned after we imported all
diff --git a/lib/gitlab/github_import/importer/note_attachments_importer.rb b/lib/gitlab/github_import/importer/note_attachments_importer.rb
index 9901c9e76f5..a84fcd253ef 100644
--- a/lib/gitlab/github_import/importer/note_attachments_importer.rb
+++ b/lib/gitlab/github_import/importer/note_attachments_importer.rb
@@ -19,7 +19,7 @@ module Gitlab
return if attachments.blank?
new_text = attachments.reduce(note_text.text) do |text, attachment|
- new_url = download_attachment(attachment)
+ new_url = gitlab_attachment_link(attachment)
text.gsub(attachment.url, new_url)
end
@@ -28,6 +28,28 @@ module Gitlab
private
+ def gitlab_attachment_link(attachment)
+ project_import_source = project.import_source
+
+ 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)
+ download_attachment(attachment)
+ else # url to other GitHub project
+ attachment.url
+ end
+ end
+
+ # From: https://github.com/login/test-import-attachments-source/blob/main/example.md
+ # To: https://gitlab.com/login/test-import-attachments-target/-/blob/main/example.md
+ def convert_project_content_link(attachment_url, import_source)
+ path_without_domain = attachment_url.gsub(::Gitlab::GithubImport::MarkdownText.github_url, '')
+ path_without_import_source = path_without_domain.gsub(import_source, '').delete_prefix('/')
+ path_with_blob_prefix = "/-#{path_without_import_source}"
+
+ ::Gitlab::Routing.url_helpers.project_url(project) + path_with_blob_prefix
+ end
+
# in: an instance of Gitlab::GithubImport::Markdown::Attachment
# out: gitlab attachment markdown url
def download_attachment(attachment)
diff --git a/lib/gitlab/github_import/importer/pull_requests/review_request_importer.rb b/lib/gitlab/github_import/importer/pull_requests/review_request_importer.rb
index bb51d856d9b..1da99942cf6 100644
--- a/lib/gitlab/github_import/importer/pull_requests/review_request_importer.rb
+++ b/lib/gitlab/github_import/importer/pull_requests/review_request_importer.rb
@@ -20,7 +20,7 @@ module Gitlab
attr_reader :review_request, :user_finder
def build_reviewers
- reviewer_ids = review_request.users.map { |user| user_finder.user_id_for(user) }.compact
+ reviewer_ids = review_request.users.filter_map { |user| user_finder.user_id_for(user) }
reviewer_ids.map do |reviewer_id|
MergeRequestReviewer.new(
diff --git a/lib/gitlab/github_import/importer/repository_importer.rb b/lib/gitlab/github_import/importer/repository_importer.rb
index d7fe01e90f8..2654812b64a 100644
--- a/lib/gitlab/github_import/importer/repository_importer.rb
+++ b/lib/gitlab/github_import/importer/repository_importer.rb
@@ -66,13 +66,10 @@ module Gitlab
true
rescue ::Gitlab::Git::CommandError => e
- if e.message !~ /repository not exported/
- project.create_wiki
+ return true if e.message.include?('repository not exported')
- raise e
- else
- true
- end
+ project.create_wiki
+ raise e
end
def wiki_url
@@ -89,10 +86,8 @@ module Gitlab
client_repository[:default_branch]
end
- def client_repository
- strong_memoize(:client_repository) do
- client.repository(project.import_source)
- end
+ strong_memoize_attr def client_repository
+ client.repository(project.import_source)
end
end
end
diff --git a/lib/gitlab/github_import/markdown/attachment.rb b/lib/gitlab/github_import/markdown/attachment.rb
index 1c814e34a39..e270cfba619 100644
--- a/lib/gitlab/github_import/markdown/attachment.rb
+++ b/lib/gitlab/github_import/markdown/attachment.rb
@@ -79,6 +79,22 @@ module Gitlab
@url = url
end
+ def part_of_project_blob?(import_source)
+ url.start_with?(
+ "#{::Gitlab::GithubImport::MarkdownText.github_url}/#{import_source}/blob"
+ )
+ end
+
+ def doc_belongs_to_project?(import_source)
+ url.start_with?(
+ "#{::Gitlab::GithubImport::MarkdownText.github_url}/#{import_source}/files"
+ )
+ end
+
+ def media?
+ url.start_with?(::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN)
+ end
+
def inspect
"<#{self.class.name}: { name: #{name}, url: #{url} }>"
end
diff --git a/lib/gitlab/github_import/parallel_scheduling.rb b/lib/gitlab/github_import/parallel_scheduling.rb
index 4b54a77983d..f8d8e4c1e8d 100644
--- a/lib/gitlab/github_import/parallel_scheduling.rb
+++ b/lib/gitlab/github_import/parallel_scheduling.rb
@@ -85,14 +85,10 @@ module Gitlab
def parallel_import
raise 'Batch settings must be defined for parallel import' if parallel_import_batch.blank?
- if Feature.enabled?(:improved_spread_parallel_import)
- improved_spread_parallel_import
- else
- spread_parallel_import
- end
+ spread_parallel_import
end
- def improved_spread_parallel_import
+ def spread_parallel_import
enqueued_job_counter = 0
each_object_to_import do |object|
@@ -108,33 +104,6 @@ module Gitlab
job_waiter
end
- def spread_parallel_import
- waiter = JobWaiter.new
-
- import_arguments = []
-
- each_object_to_import do |object|
- repr = object_representation(object)
-
- import_arguments << [project.id, repr.to_hash, waiter.key]
-
- waiter.jobs_remaining += 1
- end
-
- # rubocop:disable Scalability/BulkPerformWithContext
- Gitlab::ApplicationContext.with_context(project: project) do
- sidekiq_worker_class.bulk_perform_in(
- 1.second,
- import_arguments,
- batch_size: parallel_import_batch[:size],
- batch_delay: parallel_import_batch[:delay]
- )
- end
- # rubocop:enable Scalability/BulkPerformWithContext
-
- waiter
- end
-
# The method that will be called for traversing through all the objects to
# import, yielding them to the supplied block.
def each_object_to_import
diff --git a/lib/gitlab/github_import/project_relation_type.rb b/lib/gitlab/github_import/project_relation_type.rb
new file mode 100644
index 00000000000..a6e598172ee
--- /dev/null
+++ b/lib/gitlab/github_import/project_relation_type.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ class ProjectRelationType
+ CACHE_ORGS_EXPIRES_IN = 5.minutes
+ CACHE_USER_EXPIRES_IN = 1.hour
+
+ def initialize(client)
+ @client = client
+ end
+
+ def for(import_source)
+ namespace = import_source.split('/')[0]
+ if user?(namespace)
+ 'owned'
+ elsif organization?(namespace)
+ 'organization'
+ else
+ 'collaborated'
+ end
+ end
+
+ private
+
+ attr_reader :client
+
+ def user?(namespace)
+ github_user_login == namespace
+ end
+
+ def organization?(namespace)
+ github_org_logins.include? namespace
+ end
+
+ def github_user_login
+ ::Rails.cache.fetch(cache_key('user_login'), expire_in: CACHE_USER_EXPIRES_IN) do
+ client.user(nil)[:login]
+ end
+ end
+
+ def github_org_logins
+ ::Rails.cache.fetch(cache_key('organization_logins'), expires_in: CACHE_ORGS_EXPIRES_IN) do
+ logins = []
+ client.each_object(:organizations) { |org| logins.push(org[:login]) }
+ logins
+ end
+ end
+
+ def cache_key(subject)
+ ['github_import', Gitlab::CryptoHelper.sha256(client.octokit.access_token), subject].join('/')
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/representation/collaborator.rb b/lib/gitlab/github_import/representation/collaborator.rb
new file mode 100644
index 00000000000..55f13593f4f
--- /dev/null
+++ b/lib/gitlab/github_import/representation/collaborator.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module Representation
+ class Collaborator
+ include ToHash
+ include ExposeAttribute
+
+ attr_reader :attributes
+
+ expose_attribute :id, :login, :role_name
+
+ # Builds a user from a GitHub API response.
+ #
+ # collaborator - An instance of `Hash` containing the user & role details.
+ def self.from_api_response(collaborator, _additional_data = {})
+ new(
+ id: collaborator[:id],
+ login: collaborator[:login],
+ role_name: collaborator[:role_name]
+ )
+ end
+
+ # Builds a user using a Hash that was built from a JSON payload.
+ def self.from_json_hash(raw_hash)
+ new(Representation.symbolize_hash(raw_hash))
+ end
+
+ # attributes - A Hash containing the user details. The keys of this
+ # Hash (and any nested hashes) must be symbols.
+ def initialize(attributes)
+ @attributes = attributes
+ end
+
+ def github_identifiers
+ { id: id }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/settings.rb b/lib/gitlab/github_import/settings.rb
index 77288b9fb98..22ab99df107 100644
--- a/lib/gitlab/github_import/settings.rb
+++ b/lib/gitlab/github_import/settings.rb
@@ -18,9 +18,9 @@ module Gitlab
TEXT
},
attachments_import: {
- label: 'Import Markdown attachments',
+ label: 'Import Markdown attachments (links)',
details: <<-TEXT.split("\n").map(&:strip).join(' ')
- Import Markdown attachments from repository comments, release posts, issue descriptions,
+ Import Markdown attachments (links) from repository comments, release posts, issue descriptions,
and pull request descriptions. These can include images, text, or binary attachments.
If not imported, links in Markdown to attachments break after you remove the attachments from GitHub.
TEXT
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index c9766ee095a..d7d06aa5271 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -66,7 +66,6 @@ module Gitlab
push_frontend_feature_flag(:new_header_search)
push_frontend_feature_flag(:source_editor_toolbar)
push_frontend_feature_flag(:vscode_web_ide, current_user)
- push_frontend_feature_flag(:integration_slack_app_notifications)
push_frontend_feature_flag(:full_path_project_search, current_user)
end
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index 8fe5868ca57..a1b6e937396 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -44,28 +44,28 @@ module Gitlab
TRANSLATION_LEVELS = {
'bg' => 0,
'cs_CZ' => 0,
- 'da_DK' => 34,
- 'de' => 16,
+ 'da_DK' => 33,
+ 'de' => 15,
'en' => 100,
'eo' => 0,
- 'es' => 33,
+ 'es' => 32,
'fil_PH' => 0,
'fr' => 99,
'gl_ES' => 0,
'id_ID' => 0,
'it' => 1,
'ja' => 31,
- 'ko' => 20,
- 'nb_NO' => 23,
+ 'ko' => 19,
+ 'nb_NO' => 22,
'nl_NL' => 0,
'pl_PL' => 3,
- 'pt_BR' => 57,
- 'ro_RO' => 91,
- 'ru' => 26,
- 'si_LK' => 11,
+ 'pt_BR' => 56,
+ 'ro_RO' => 89,
+ 'ru' => 25,
+ 'si_LK' => 10,
'tr_TR' => 10,
- 'uk' => 55,
- 'zh_CN' => 98,
+ 'uk' => 53,
+ 'zh_CN' => 96,
'zh_HK' => 1,
'zh_TW' => 98
}.freeze
@@ -118,12 +118,17 @@ module Gitlab
end
def setup(domain:, default_locale:)
+ custom_pluralization
setup_repositories(domain)
setup_default_locale(default_locale)
end
private
+ def custom_pluralization
+ Gitlab::I18n::Pluralization.install_on(FastGettext)
+ end
+
def setup_repositories(domain)
translation_repositories = [
(po_repository(domain, 'jh/locale') if Gitlab.jh?),
diff --git a/lib/gitlab/i18n/pluralization.rb b/lib/gitlab/i18n/pluralization.rb
new file mode 100644
index 00000000000..5d4a05f1fd1
--- /dev/null
+++ b/lib/gitlab/i18n/pluralization.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module I18n
+ # Pluralization formulas per locale used by FastGettext via:
+ # `FastGettext.pluralisation_rule.call(count)`.
+ module Pluralization
+ # rubocop:disable all
+ MAP = {
+ "bg" => ->(n) { (n != 1) },
+ "cs_CZ" => ->(n) { (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3 },
+ "da_DK" => ->(n) { (n != 1) },
+ "de" => ->(n) { (n != 1) },
+ "en" => ->(n) { (n != 1) },
+ "eo" => ->(n) { (n != 1) },
+ "es" => ->(n) { (n != 1) },
+ "fil_PH" => ->(n) { (n > 1) },
+ "fr" => ->(n) { (n > 1) },
+ "gl_ES" => ->(n) { (n != 1) },
+ "id_ID" => ->(n) { 0 },
+ "it" => ->(n) { (n != 1) },
+ "ja" => ->(n) { 0 },
+ "ko" => ->(n) { 0 },
+ "nb_NO" => ->(n) { (n != 1) },
+ "nl_NL" => ->(n) { (n != 1) },
+ "pl_PL" => ->(n) { (n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3) },
+ "pt_BR" => ->(n) { (n != 1) },
+ "ro_RO" => ->(n) { (n==1 ? 0 : (n==0 || (n%100>0 && n%100<20)) ? 1 : 2) },
+ "ru" => ->(n) { ((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3)) },
+ "si_LK" => ->(n) { (n != 1) },
+ "tr_TR" => ->(n) { (n != 1) },
+ "uk" => ->(n) { ((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3)) },
+ "zh_CN" => ->(n) { 0 },
+ "zh_HK" => ->(n) { 0 },
+ "zh_TW" => ->(n) { 0 }
+ }.freeze
+ # rubocop:enable
+
+ NOT_FOUND_ERROR = lambda do |locale|
+ po = File.expand_path("../../../locale/#{locale}/gitlab.po", __dir__)
+
+ forms = File.read(po)[/Plural-Forms:.*; plural=(.*?);\\n/, 1] if File.exist?(po)
+ suggestion = <<~TEXT if forms
+ Add the following line to #{__FILE__}:
+
+ MAP = {
+ ...
+ "#{locale}" => ->(n) { #{forms} },
+ ...
+ }.freeze
+
+ This rule was extracted from #{po}.
+ TEXT
+
+ raise ArgumentError, <<~MESSAGE
+ Missing pluralization rule for locale #{locale.inspect}.
+
+ #{suggestion}
+ MESSAGE
+ end
+
+ def self.call(count)
+ locale = FastGettext.locale
+
+ MAP.fetch(locale, &NOT_FOUND_ERROR).call(count)
+ end
+
+ def self.install_on(klass)
+ klass.extend(FastGettextClassMethods)
+ end
+
+ module FastGettextClassMethods
+ # FastGettext allows to set the rule via
+ # `FastGettext.pluralisation_rule=` which is on thread-level.
+ #
+ # Because we are patching FastGettext at boot time per thread values
+ # won't work so we have to override the method implementation.
+ #
+ # `FastGettext.pluralisation_rule=` has now no effect.
+ def pluralisation_rule
+ Gitlab::I18n::Pluralization
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import/errors.rb b/lib/gitlab/import/errors.rb
new file mode 100644
index 00000000000..b9e8c9135fd
--- /dev/null
+++ b/lib/gitlab/import/errors.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Import
+ module Errors
+ # Merges all nested subrelation errors into base errors object.
+ #
+ # @example
+ # issue = Project.last.issues.new(
+ # title: 'test',
+ # author: User.first,
+ # notes: [Note.new(
+ # award_emoji: [AwardEmoji.new(name: 'test')]
+ # )])
+ #
+ # issue.validate
+ # issue.errors.full_messages
+ # => ["Notes is invalid"]
+ #
+ # Gitlab::Import::Errors.merge_nested_errors(issue)
+ # issue.errors.full_messages
+ # => ["Notes is invalid",
+ # "Award emoji is invalid",
+ # "Awardable can't be blank",
+ # "Name is not a valid emoji name",
+ # ...
+ # ]
+ def self.merge_nested_errors(object)
+ object.errors.each do |error|
+ association = object.class.reflect_on_association(error.attribute)
+
+ next unless association&.collection?
+
+ records = object.public_send(error.attribute).select(&:invalid?) # rubocop: disable GitlabSecurity/PublicSend
+
+ records.each do |record|
+ merge_nested_errors(record)
+
+ object.errors.merge!(record.errors)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import/import_failure_service.rb b/lib/gitlab/import/import_failure_service.rb
index bebd64b29a9..714d9b3edd9 100644
--- a/lib/gitlab/import/import_failure_service.rb
+++ b/lib/gitlab/import/import_failure_service.rb
@@ -50,10 +50,10 @@ module Gitlab
def execute
track_exception
- persist_failure
-
- track_metrics if metrics
- import_state.mark_as_failed(exception.message) if fail_import
+ persist_failure.tap do
+ import_state.mark_as_failed(exception.message) if fail_import
+ track_metrics if metrics
+ end
end
private
diff --git a/lib/gitlab/import/metrics.rb b/lib/gitlab/import/metrics.rb
index 7a0cf1682a6..e457d9ec57c 100644
--- a/lib/gitlab/import/metrics.rb
+++ b/lib/gitlab/import/metrics.rb
@@ -32,6 +32,14 @@ module Gitlab
return unless project.github_import?
track_usage_event(:github_import_project_failure, project.id)
+ track_import_state('github')
+ end
+
+ def track_canceled_import
+ return unless project.github_import?
+
+ track_usage_event(:github_import_project_cancelled, project.id)
+ track_import_state('github')
end
def issues_counter
@@ -75,7 +83,24 @@ module Gitlab
def track_finish_metric
return unless project.github_import?
- track_usage_event(:github_import_project_success, project.id)
+ track_import_state('github')
+
+ case project.beautified_import_status_name
+ when 'partially completed'
+ track_usage_event(:github_import_project_partially_completed, project.id)
+ when 'completed'
+ track_usage_event(:github_import_project_success, project.id)
+ end
+ end
+
+ def track_import_state(type)
+ Gitlab::Tracking.event(
+ importer,
+ 'create',
+ label: "#{type}_import_project_state",
+ project: project,
+ extra: { import_type: type, state: project.beautified_import_status_name }
+ )
end
end
end
diff --git a/lib/gitlab/import_export/attributes_finder.rb b/lib/gitlab/import_export/attributes_finder.rb
index 8843b4f5755..dea989931c7 100644
--- a/lib/gitlab/import_export/attributes_finder.rb
+++ b/lib/gitlab/import_export/attributes_finder.rb
@@ -3,7 +3,8 @@
module Gitlab
module ImportExport
class AttributesFinder
- attr_reader :tree, :included_attributes, :excluded_attributes, :methods, :preloads, :export_reorders
+ attr_reader :tree, :included_attributes, :excluded_attributes, :methods, :preloads, :export_reorders,
+ :import_only_tree
def initialize(config:)
@tree = config[:tree] || {}
@@ -13,13 +14,16 @@ module Gitlab
@preloads = config[:preloads] || {}
@export_reorders = config[:export_reorders] || {}
@include_if_exportable = config[:include_if_exportable] || {}
+ @import_only_tree = config[:import_only_tree] || {}
end
def find_root(model_key)
find(model_key, @tree[model_key])
end
- def find_relations_tree(model_key)
+ def find_relations_tree(model_key, include_import_only_tree: false)
+ return @tree[model_key].deep_merge(@import_only_tree[model_key] || {}) if include_import_only_tree
+
@tree[model_key]
end
diff --git a/lib/gitlab/import_export/attributes_permitter.rb b/lib/gitlab/import_export/attributes_permitter.rb
index 8c7a6c13246..889cab88de4 100644
--- a/lib/gitlab/import_export/attributes_permitter.rb
+++ b/lib/gitlab/import_export/attributes_permitter.rb
@@ -80,7 +80,7 @@ module Gitlab
# Deep traverse relations tree to build a list of allowed model relations
def build_associations
- stack = @attributes_finder.tree.to_a
+ stack = @attributes_finder.tree.deep_merge(@attributes_finder.import_only_tree).to_a
while stack.any?
model_name, relations = stack.pop
diff --git a/lib/gitlab/import_export/base/relation_object_saver.rb b/lib/gitlab/import_export/base/relation_object_saver.rb
index 77b85fc9f15..986191bdb6b 100644
--- a/lib/gitlab/import_export/base/relation_object_saver.rb
+++ b/lib/gitlab/import_export/base/relation_object_saver.rb
@@ -17,6 +17,8 @@ module Gitlab
BATCH_SIZE = 100
MIN_RECORDS_SIZE = 1
+ attr_reader :invalid_subrelations
+
# @param relation_object [Object] Object of a project/group, e.g. an issue
# @param relation_key [String] Name of the object association to group/project, e.g. :issues
# @param relation_definition [Hash] Object subrelations as defined in import_export.yml
@@ -43,14 +45,11 @@ module Gitlab
relation_object.save!
save_subrelations
- ensure
- log_invalid_subrelations
end
private
- attr_reader :relation_object, :relation_key, :relation_definition,
- :importable, :collection_subrelations, :invalid_subrelations
+ attr_reader :relation_object, :relation_key, :relation_definition, :importable, :collection_subrelations
# rubocop:disable GitlabSecurity/PublicSend
def save_subrelations
@@ -92,30 +91,6 @@ module Gitlab
end
end
# rubocop:enable GitlabSecurity/PublicSend
-
- def log_invalid_subrelations
- invalid_subrelations.flatten.each do |record|
- Gitlab::Import::Logger.info(
- message: '[Project/Group Import] Invalid subrelation',
- importable_column_name => importable.id,
- relation_key: relation_key,
- error_messages: record.errors.full_messages.to_sentence
- )
-
- ImportFailure.create(
- source: 'RelationObjectSaver#save!',
- relation_key: relation_key,
- exception_class: 'RecordInvalid',
- exception_message: record.errors.full_messages.to_sentence,
- correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id,
- importable_column_name => importable.id
- )
- end
- end
-
- def importable_column_name
- @column_name ||= importable.class.reflect_on_association(:import_failures).foreign_key.to_sym
- end
end
end
end
diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb
index 64ef3dd4830..d681f39f00b 100644
--- a/lib/gitlab/import_export/command_line_util.rb
+++ b/lib/gitlab/import_export/command_line_util.rb
@@ -90,6 +90,7 @@ module Gitlab
def untar_with_options(archive:, dir:, options:)
execute_cmd(%W(tar -#{options} #{archive} -C #{dir}))
execute_cmd(%W(chmod -R #{UNTAR_MASK} #{dir}))
+ remove_symlinks(dir)
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
@@ -120,6 +121,19 @@ module Gitlab
FileUtils.copy_entry(source, destination)
true
end
+
+ def remove_symlinks(dir)
+ ignore_file_names = %w[. ..]
+
+ # Using File::FNM_DOTMATCH to also delete symlinks starting with "."
+ Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH)
+ .reject { |f| ignore_file_names.include?(File.basename(f)) }
+ .each do |filepath|
+ FileUtils.rm(filepath) if File.lstat(filepath).symlink?
+ end
+
+ true
+ end
end
end
end
diff --git a/lib/gitlab/import_export/config.rb b/lib/gitlab/import_export/config.rb
index 83c4bc47349..423e0933605 100644
--- a/lib/gitlab/import_export/config.rb
+++ b/lib/gitlab/import_export/config.rb
@@ -10,6 +10,7 @@ module Gitlab
@ee_hash = @hash.delete(:ee) || {}
@hash[:tree] = normalize_tree(@hash[:tree])
+ @hash[:import_only_tree] = normalize_tree(@hash[:import_only_tree] || {})
@ee_hash[:tree] = normalize_tree(@ee_hash[:tree] || {})
end
diff --git a/lib/gitlab/import_export/file_importer.rb b/lib/gitlab/import_export/file_importer.rb
index 1878b5b1a30..d2593289c23 100644
--- a/lib/gitlab/import_export/file_importer.rb
+++ b/lib/gitlab/import_export/file_importer.rb
@@ -8,7 +8,6 @@ module Gitlab
ImporterError = Class.new(StandardError)
MAX_RETRIES = 8
- IGNORED_FILENAMES = %w(. ..).freeze
def self.import(*args, **kwargs)
new(*args, **kwargs).import
@@ -24,7 +23,7 @@ module Gitlab
mkdir_p(@shared.export_path)
mkdir_p(@shared.archive_path)
- remove_symlinks
+ remove_symlinks(@shared.export_path)
copy_archive
wait_for_archived_file do
@@ -36,7 +35,7 @@ module Gitlab
false
ensure
remove_import_file
- remove_symlinks
+ remove_symlinks(@shared.export_path)
end
private
@@ -86,22 +85,10 @@ module Gitlab
end
end
- def remove_symlinks
- extracted_files.each do |path|
- FileUtils.rm(path) if File.lstat(path).symlink?
- end
-
- true
- end
-
def remove_import_file
FileUtils.rm_rf(@archive_file)
end
- def extracted_files
- Dir.glob("#{@shared.export_path}/**/*", File::FNM_DOTMATCH).reject { |f| IGNORED_FILENAMES.include?(File.basename(f)) }
- end
-
def validate_decompressed_archive_size
raise ImporterError, _('Decompressed archive size validation failed.') unless size_validator.valid?
end
diff --git a/lib/gitlab/import_export/group/relation_tree_restorer.rb b/lib/gitlab/import_export/group/relation_tree_restorer.rb
index 5a78f2fb531..624acd3bb2a 100644
--- a/lib/gitlab/import_export/group/relation_tree_restorer.rb
+++ b/lib/gitlab/import_export/group/relation_tree_restorer.rb
@@ -90,13 +90,23 @@ module Gitlab
def save_relation_object(relation_object, relation_key, relation_definition, relation_index)
if relation_object.new_record?
- Gitlab::ImportExport::Base::RelationObjectSaver.new(
+ saver = Gitlab::ImportExport::Base::RelationObjectSaver.new(
relation_object: relation_object,
relation_key: relation_key,
relation_definition: relation_definition,
importable: @importable
- ).execute
+ )
+
+ saver.execute
+
+ log_invalid_subrelations(saver.invalid_subrelations, relation_key)
else
+ if relation_object.invalid?
+ Gitlab::Import::Errors.merge_nested_errors(relation_object)
+
+ raise(ActiveRecord::RecordInvalid, relation_object)
+ end
+
import_failure_service.with_retry(action: 'relation_object.save!', relation_key: relation_key, relation_index: relation_index) do
relation_object.save!
end
@@ -113,7 +123,7 @@ module Gitlab
@relations ||=
@reader
.attributes_finder
- .find_relations_tree(importable_class_sym)
+ .find_relations_tree(importable_class_sym, include_import_only_tree: true)
.deep_stringify_keys
end
@@ -290,6 +300,32 @@ module Gitlab
message: '[Project/Group Import] Created new object relation'
)
end
+
+ def log_invalid_subrelations(invalid_subrelations, relation_key)
+ invalid_subrelations.flatten.each do |record|
+ Gitlab::Import::Errors.merge_nested_errors(record)
+
+ @shared.logger.info(
+ message: '[Project/Group Import] Invalid subrelation',
+ importable_column_name => @importable.id,
+ relation_key: relation_key,
+ error_messages: record.errors.full_messages.to_sentence
+ )
+
+ ::ImportFailure.create(
+ source: 'RelationTreeRestorer#save_relation_object',
+ relation_key: relation_key,
+ exception_class: 'ActiveRecord::RecordInvalid',
+ exception_message: record.errors.full_messages.to_sentence,
+ correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id,
+ importable_column_name => @importable.id
+ )
+ end
+ end
+
+ def importable_column_name
+ @column_name ||= @importable.class.reflect_on_association(:import_failures).foreign_key.to_sym
+ end
end
end
end
diff --git a/lib/gitlab/import_export/project/import_export.yml b/lib/gitlab/import_export/project/import_export.yml
index d97ffee8698..335096faed6 100644
--- a/lib/gitlab/import_export/project/import_export.yml
+++ b/lib/gitlab/import_export/project/import_export.yml
@@ -89,13 +89,15 @@ tree:
- :milestone
- :resource_state_events
- :external_pull_requests
+ - commit_notes:
+ - :author
+ - events:
+ - :push_event_payload
- ci_pipelines:
- - notes:
- - :author
- - events:
- - :push_event_payload
- stages:
- - :statuses
+ - :builds
+ - :generic_commit_statuses
+ - :bridges
- :external_pull_request
- :merge_request
- :pipeline_metadata
@@ -122,6 +124,21 @@ tree:
group_members:
- :user
+# Used to support old exports that were exported before the removal/rename of the associations
+#
+# For example, statuses of ci_pipelines are no longer exported, and instead, statuses are
+# exported as builds, generic_commit_statuses, and bridges. So in order to allow statuses
+# to be still imported, it is added to the list below.
+import_only_tree:
+ project:
+ - ci_pipelines:
+ - notes:
+ - :author
+ - events:
+ - :push_event_payload
+ - stages:
+ - :statuses
+
# Only include the following attributes for the models specified.
included_attributes:
user:
@@ -529,7 +546,7 @@ included_attributes:
- :source_sha
- :target_sha
external_pull_requests: *external_pull_request_definition
- statuses:
+ statuses: &statuses_definition
- :project_id
- :status
- :finished_at
@@ -562,6 +579,9 @@ included_attributes:
- :scheduled_at
- :scheduling_type
- :ci_stage
+ builds: *statuses_definition
+ generic_commit_statuses: *statuses_definition
+ bridges: *statuses_definition
ci_pipelines:
- :ref
- :sha
@@ -596,6 +616,7 @@ included_attributes:
- :project_id
- :created_at
- :updated_at
+ # - :statuses # old exports use statuses instead of builds, generic_commit_statuses and bridges
actions:
- :event
design: &design_definition
@@ -896,7 +917,7 @@ excluded_attributes:
merge_requests: *merge_request_excluded_definition
award_emoji:
- :awardable_id
- statuses:
+ statuses: &statuses_excluded_definition
- :trace
- :token
- :token_encrypted
@@ -918,6 +939,9 @@ excluded_attributes:
- :processed
- :id_convert_to_bigint
- :stage_id_convert_to_bigint
+ builds: *statuses_excluded_definition
+ generic_commit_statuses: *statuses_excluded_definition
+ bridges: *statuses_excluded_definition
sentry_issue:
- :issue_id
push_event_payload:
@@ -955,6 +979,9 @@ excluded_attributes:
notes:
- :noteable_id
- :review_id
+ commit_notes:
+ - :noteable_id
+ - :review_id
label_links:
- :label_id
- :target_id
@@ -1079,6 +1106,8 @@ methods:
- :squash_option
notes:
- :type
+ commit_notes:
+ - :type
labels:
- :type
label:
@@ -1100,8 +1129,6 @@ methods:
- :type
lists:
- :list_type
- ci_pipelines:
- - :notes
issues:
- :state
@@ -1111,10 +1138,11 @@ methods:
preloads:
issues:
project: :route
- statuses:
- # TODO: We cannot preload tags, as they are not part of `GenericCommitStatus`
- # tags: # needed by tag_list
- project: # deprecated: needed by coverage_regex of Ci::Build
+ builds:
+ metadata:
+ project:
+ bridges:
+ metadata:
merge_requests:
source_project: :route # needed by source_branch_sha and diff_head_sha
target_project: :route # needed by target_branch_sha
diff --git a/lib/gitlab/import_export/project/object_builder.rb b/lib/gitlab/import_export/project/object_builder.rb
index 50a67a746f8..0962ad9f028 100644
--- a/lib/gitlab/import_export/project/object_builder.rb
+++ b/lib/gitlab/import_export/project/object_builder.rb
@@ -64,6 +64,7 @@ module Gitlab
if label?
atts['type'] = 'ProjectLabel' # Always create project labels
+ atts.delete('group_id')
elsif milestone?
if atts['group_id'] # Transform new group milestones into project ones
atts['iid'] = nil
diff --git a/lib/gitlab/import_export/project/relation_factory.rb b/lib/gitlab/import_export/project/relation_factory.rb
index 4134c428500..ab95e306abf 100644
--- a/lib/gitlab/import_export/project/relation_factory.rb
+++ b/lib/gitlab/import_export/project/relation_factory.rb
@@ -5,6 +5,7 @@ module Gitlab
module Project
class RelationFactory < Base::RelationFactory
OVERRIDES = { snippets: :project_snippets,
+ commit_notes: 'Note',
ci_pipelines: 'Ci::Pipeline',
pipelines: 'Ci::Pipeline',
stages: 'Ci::Stage',
@@ -12,6 +13,7 @@ module Gitlab
triggers: 'Ci::Trigger',
pipeline_schedules: 'Ci::PipelineSchedule',
builds: 'Ci::Build',
+ bridges: 'Ci::Bridge',
runners: 'Ci::Runner',
pipeline_metadata: 'Ci::PipelineMetadata',
hooks: 'ProjectHook',
@@ -37,7 +39,7 @@ module Gitlab
committer: 'MergeRequest::DiffCommitUser',
merge_request_diff_commits: 'MergeRequestDiffCommit' }.freeze
- BUILD_MODELS = %i[Ci::Build commit_status].freeze
+ BUILD_MODELS = %i[Ci::Build Ci::Bridge commit_status generic_commit_status].freeze
GROUP_REFERENCES = %w[group_id].freeze
@@ -83,7 +85,7 @@ module Gitlab
def setup_models
case @relation_name
when :merge_request_diff_files then setup_diff
- when :notes then setup_note
+ when :notes, :Note then setup_note
when :'Ci::Pipeline' then setup_pipeline
when *BUILD_MODELS then setup_build
when :issues then setup_issue
@@ -142,9 +144,22 @@ module Gitlab
def setup_pipeline
@relation_hash.fetch('stages', []).each do |stage|
+ # old export files have statuses
stage.statuses.each do |status|
status.pipeline = imported_object
end
+
+ stage.builds.each do |status|
+ status.pipeline = imported_object
+ end
+
+ stage.bridges.each do |status|
+ status.pipeline = imported_object
+ end
+
+ stage.generic_commit_statuses.each do |status|
+ status.pipeline = imported_object
+ end
end
end
diff --git a/lib/gitlab/instrumentation/redis_base.rb b/lib/gitlab/instrumentation/redis_base.rb
index de24132a28e..00a7387afe2 100644
--- a/lib/gitlab/instrumentation/redis_base.rb
+++ b/lib/gitlab/instrumentation/redis_base.rb
@@ -118,6 +118,14 @@ module Gitlab
@exception_counter.increment({ storage: storage_key, exception: ex.class.to_s })
end
+ def instance_count_cluster_redirection(ex)
+ # This metric is meant to give a client side view of how often are commands
+ # redirected to the right node, especially during resharding..
+ # This metric can be used for Redis alerting and service health monitoring.
+ @redirection_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_redirections_total, 'Client side Redis Cluster redirection count, per Redis node, per slot')
+ @redirection_counter.increment(decompose_redirection_message(ex.message).merge({ storage: storage_key }))
+ end
+
def instance_observe_duration(duration)
@request_latency_histogram ||= Gitlab::Metrics.histogram(
:gitlab_redis_client_requests_duration_seconds,
@@ -129,6 +137,10 @@ module Gitlab
@request_latency_histogram.observe({ storage: storage_key }, duration)
end
+ def log_exception(ex)
+ ::Gitlab::ErrorTracking.log_exception(ex, storage: storage_key)
+ end
+
private
def request_count_key
@@ -162,6 +174,11 @@ module Gitlab
def build_key(namespace)
"#{storage_key}_#{namespace}"
end
+
+ def decompose_redirection_message(err_msg)
+ redirection_type, _, target_node_key = err_msg.split
+ { redirection_type: redirection_type, target_node_key: target_node_key }
+ end
end
end
end
diff --git a/lib/gitlab/instrumentation/redis_interceptor.rb b/lib/gitlab/instrumentation/redis_interceptor.rb
index 35dd7cbfeb8..2a86b9e4202 100644
--- a/lib/gitlab/instrumentation/redis_interceptor.rb
+++ b/lib/gitlab/instrumentation/redis_interceptor.rb
@@ -40,7 +40,13 @@ module Gitlab
yield
rescue ::Redis::BaseError => ex
- instrumentation_class.instance_count_exception(ex)
+ if ex.message.start_with?('MOVED', 'ASK')
+ instrumentation_class.instance_count_cluster_redirection(ex)
+ else
+ instrumentation_class.instance_count_exception(ex)
+ end
+
+ instrumentation_class.log_exception(ex)
raise ex
ensure
duration = Gitlab::Metrics::System.monotonic_time - start
diff --git a/lib/gitlab/instrumentation/zoekt.rb b/lib/gitlab/instrumentation/zoekt.rb
new file mode 100644
index 00000000000..cd9b15bcee8
--- /dev/null
+++ b/lib/gitlab/instrumentation/zoekt.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Instrumentation
+ class Zoekt
+ ZOEKT_REQUEST_COUNT = :zoekt_request_count
+ ZOEKT_CALL_DURATION = :zoekt_call_duration
+ ZOEKT_CALL_DETAILS = :zoekt_call_details
+
+ class << self
+ def get_request_count
+ ::Gitlab::SafeRequestStore[ZOEKT_REQUEST_COUNT] || 0
+ end
+
+ def increment_request_count
+ ::Gitlab::SafeRequestStore[ZOEKT_REQUEST_COUNT] ||= 0
+ ::Gitlab::SafeRequestStore[ZOEKT_REQUEST_COUNT] += 1
+ end
+
+ def detail_store
+ ::Gitlab::SafeRequestStore[ZOEKT_CALL_DETAILS] ||= []
+ end
+
+ def query_time
+ query_time = ::Gitlab::SafeRequestStore[ZOEKT_CALL_DURATION] || 0
+ query_time.round(::Gitlab::InstrumentationHelper::DURATION_PRECISION)
+ end
+
+ def add_duration(duration)
+ ::Gitlab::SafeRequestStore[ZOEKT_CALL_DURATION] ||= 0
+ ::Gitlab::SafeRequestStore[ZOEKT_CALL_DURATION] += duration
+ end
+
+ def add_call_details(duration:, method:, path:, params: nil, body: nil)
+ return unless Gitlab::PerformanceBar.enabled_for_request?
+
+ detail_store << {
+ method: method,
+ path: path,
+ params: params,
+ body: body,
+ duration: duration,
+ backtrace: ::Gitlab::BacktraceCleaner.clean_backtrace(caller)
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/instrumentation_helper.rb b/lib/gitlab/instrumentation_helper.rb
index 15a760fada0..1b81ec012d1 100644
--- a/lib/gitlab/instrumentation_helper.rb
+++ b/lib/gitlab/instrumentation_helper.rb
@@ -23,6 +23,7 @@ module Gitlab
instrument_rugged(payload)
instrument_redis(payload)
instrument_elasticsearch(payload)
+ instrument_zoekt(payload)
instrument_throttle(payload)
instrument_active_record(payload)
instrument_external_http(payload)
@@ -72,6 +73,17 @@ module Gitlab
payload[:elasticsearch_timed_out_count] = Gitlab::Instrumentation::ElasticsearchTransport.get_timed_out_count
end
+ def instrument_zoekt(payload)
+ # Zoekt integration is only available in EE but instrumentation
+ # only depends on the Gem which is also available in FOSS.
+ zoekt_calls = Gitlab::Instrumentation::Zoekt.get_request_count
+
+ return if zoekt_calls == 0
+
+ payload[:zoekt_calls] = zoekt_calls
+ payload[:zoekt_duration_s] = Gitlab::Instrumentation::Zoekt.query_time
+ end
+
def instrument_external_http(payload)
external_http_count = Gitlab::Metrics::Subscribers::ExternalHttp.request_count
diff --git a/lib/gitlab/issuable/clone/copy_resource_events_service.rb b/lib/gitlab/issuable/clone/copy_resource_events_service.rb
index 448ac4c2ae0..22b0d5c4fb2 100644
--- a/lib/gitlab/issuable/clone/copy_resource_events_service.rb
+++ b/lib/gitlab/issuable/clone/copy_resource_events_service.rb
@@ -69,9 +69,9 @@ module Gitlab
def copy_events(table_name, events_to_copy)
events_to_copy.find_in_batches do |batch|
- events = batch.map do |event|
+ events = batch.filter_map do |event|
yield(event)
- end.compact
+ end
ApplicationRecord.legacy_bulk_insert(table_name, events) # rubocop:disable Gitlab/BulkInsert
end
diff --git a/lib/gitlab/issues/rebalancing/state.rb b/lib/gitlab/issues/rebalancing/state.rb
index 36346564b39..f1f6cc55a2b 100644
--- a/lib/gitlab/issues/rebalancing/state.rb
+++ b/lib/gitlab/issues/rebalancing/state.rb
@@ -38,10 +38,10 @@ module Gitlab
def rebalance_in_progress?
is_running = case rebalanced_container_type
when NAMESPACE
- namespace_ids = self.class.current_rebalancing_containers.map { |string| string.split("#{NAMESPACE}/").second.to_i }.compact
+ namespace_ids = self.class.current_rebalancing_containers.filter_map { |string| string.split("#{NAMESPACE}/").second.to_i }
namespace_ids.include?(root_namespace.id)
when PROJECT
- project_ids = self.class.current_rebalancing_containers.map { |string| string.split("#{PROJECT}/").second.to_i }.compact
+ project_ids = self.class.current_rebalancing_containers.filter_map { |string| string.split("#{PROJECT}/").second.to_i }
project_ids.include?(projects.take.id) # rubocop:disable CodeReuse/ActiveRecord
else
false
diff --git a/lib/gitlab/jira_import/issues_importer.rb b/lib/gitlab/jira_import/issues_importer.rb
index 7b031c26b72..458f7c3f470 100644
--- a/lib/gitlab/jira_import/issues_importer.rb
+++ b/lib/gitlab/jira_import/issues_importer.rb
@@ -48,7 +48,7 @@ module Gitlab
end
def schedule_issue_import_workers(issues)
- next_iid = Issue.with_project_iid_supply(project, &:next_value)
+ next_iid = Issue.with_namespace_iid_supply(project.project_namespace, &:next_value)
issues.each do |jira_issue|
# Technically it's possible that the same work is performed multiple
@@ -71,7 +71,7 @@ module Gitlab
job_waiter.jobs_remaining += 1
- next_iid = Issue.with_project_iid_supply(project, &:next_value)
+ next_iid = Issue.with_namespace_iid_supply(project.project_namespace, &:next_value)
# Mark the issue as imported immediately so we don't end up
# importing it multiple times within same import.
diff --git a/lib/gitlab/jira_import/metadata_collector.rb b/lib/gitlab/jira_import/metadata_collector.rb
index 4551f38ba98..090b95ac14a 100644
--- a/lib/gitlab/jira_import/metadata_collector.rb
+++ b/lib/gitlab/jira_import/metadata_collector.rb
@@ -45,7 +45,7 @@ module Gitlab
def add_versions
return if fields['fixVersions'].blank? || !fields['fixVersions'].is_a?(Array)
- versions = fields['fixVersions'].map { |version| version['name'] }.compact.join(', ')
+ versions = fields['fixVersions'].filter_map { |version| version['name'] }.join(', ')
metadata << "- Fix versions: #{versions}"
end
diff --git a/lib/gitlab/json_cache.rb b/lib/gitlab/json_cache.rb
index d2916a01809..0087c2accc3 100644
--- a/lib/gitlab/json_cache.rb
+++ b/lib/gitlab/json_cache.rb
@@ -112,7 +112,7 @@ module Gitlab
end
def parse_entries(values, klass)
- values.map { |value| parse_entry(value, klass) }.compact
+ values.filter_map { |value| parse_entry(value, klass) }
end
end
end
diff --git a/lib/gitlab/kas/user_access.rb b/lib/gitlab/kas/user_access.rb
new file mode 100644
index 00000000000..65ae399d826
--- /dev/null
+++ b/lib/gitlab/kas/user_access.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Kas
+ # The name of the cookie that will be used for the KAS cookie
+ COOKIE_KEY = '_gitlab_kas'
+ DEFAULT_ENCRYPTED_COOKIE_CIPHER = 'aes-256-gcm'
+
+ class UserAccess
+ class << self
+ def enabled?
+ ::Gitlab::Kas.enabled? && ::Feature.enabled?(:kas_user_access)
+ end
+
+ def enabled_for?(agent)
+ enabled? && ::Feature.enabled?(:kas_user_access_project, agent.project)
+ end
+
+ def encrypt_public_session_id(data)
+ encryptor.encrypt_and_sign(data.to_json, purpose: public_session_id_purpose)
+ end
+
+ def decrypt_public_session_id(data)
+ decrypted = encryptor.decrypt_and_verify(data, purpose: public_session_id_purpose)
+ ::Gitlab::Json.parse(decrypted)
+ end
+
+ def valid_authenticity_token?(session, masked_authenticity_token)
+ # rubocop:disable GitlabSecurity/PublicSend
+ ActionController::Base.new.send(:valid_authenticity_token?, session, masked_authenticity_token)
+ # rubocop:enable GitlabSecurity/PublicSend
+ end
+
+ def cookie_data(public_session_id)
+ uri = URI(::Gitlab::Kas.tunnel_url)
+
+ cookie = {
+ value: encrypt_public_session_id(public_session_id),
+ expires: 1.day,
+ httponly: true,
+ path: uri.path.presence || '/',
+ secure: Gitlab.config.gitlab.https
+ }
+ # Only set domain attribute if KAS is on a subdomain.
+ # When on the same domain, we can omit the attribute.
+ gitlab_host = Gitlab.config.gitlab.host
+ cookie[:domain] = gitlab_host if uri.host.end_with?(".#{gitlab_host}")
+
+ cookie
+ end
+
+ private
+
+ def encryptor
+ action_dispatch_config = Gitlab::Application.config.action_dispatch
+ serializer = ActiveSupport::MessageEncryptor::NullSerializer
+ key_generator = ::Gitlab::Application.key_generator
+
+ cipher = action_dispatch_config.encrypted_cookie_cipher || DEFAULT_ENCRYPTED_COOKIE_CIPHER
+ salt = action_dispatch_config.authenticated_encrypted_cookie_salt
+ key_len = ActiveSupport::MessageEncryptor.key_len(cipher)
+ secret = key_generator.generate_key(salt, key_len)
+
+ ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: serializer)
+ end
+
+ def public_session_id_purpose
+ "kas.user_public_session_id"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/language_detection.rb b/lib/gitlab/language_detection.rb
index b259f58350b..68deafc68b2 100644
--- a/lib/gitlab/language_detection.rb
+++ b/lib/gitlab/language_detection.rb
@@ -45,11 +45,11 @@ module Gitlab
# Returns the ids of the programming languages that do not occur in the detection
# as current repository languages
def deletions
- @repository_languages.map do |repo_lang|
+ @repository_languages.filter_map do |repo_lang|
next if detection.key?(repo_lang.name)
repo_lang.programming_language_id
- end.compact
+ end
end
private
diff --git a/lib/gitlab/legacy_github_import/client.rb b/lib/gitlab/legacy_github_import/client.rb
index dd1502bbbcd..16c3bc09c4d 100644
--- a/lib/gitlab/legacy_github_import/client.rb
+++ b/lib/gitlab/legacy_github_import/client.rb
@@ -34,6 +34,7 @@ module Gitlab
}
)
end
+ alias_method :octokit, :api
def client
unless config
diff --git a/lib/gitlab/legacy_github_import/importer.rb b/lib/gitlab/legacy_github_import/importer.rb
index 331eab7b62a..5eeea8f9548 100644
--- a/lib/gitlab/legacy_github_import/importer.rb
+++ b/lib/gitlab/legacy_github_import/importer.rb
@@ -22,7 +22,7 @@ module Gitlab
unless credentials
raise Projects::ImportService::Error,
- "Unable to find project import data credentials for project ID: #{@project.id}"
+ "Unable to find project import data credentials for project ID: #{@project.id}"
end
opts = {}
@@ -55,9 +55,7 @@ module Gitlab
import_comments(:issues)
# Gitea doesn't have an API endpoint for pull requests comments
- unless project.gitea_import?
- import_comments(:pull_requests)
- end
+ import_comments(:pull_requests) unless project.gitea_import?
import_wiki
@@ -67,9 +65,7 @@ module Gitlab
# See:
# 1) https://gitlab.com/gitlab-org/gitlab/-/issues/343448#note_985979730
# 2) https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89694/diffs#dfc4a8141aa296465ea3c50b095a30292fb6ebc4_180_182
- unless project.gitea_import?
- import_releases
- end
+ import_releases unless project.gitea_import?
handle_errors
@@ -142,8 +138,8 @@ module Gitlab
# rubocop: enable CodeReuse/ActiveRecord
def import_pull_requests
- fetch_resources(:pull_requests, repo, state: :all, sort: :created, direction: :asc, per_page: 100) do |pull_requests|
- pull_requests.each do |raw|
+ fetch_resources(:pull_requests, repo, state: :all, sort: :created, direction: :asc, per_page: 100) do |prs|
+ prs.each do |raw|
raw = raw.to_h
gh_pull_request = PullRequestFormatter.new(project, raw, client)
@@ -156,11 +152,13 @@ module Gitlab
merge_request = gh_pull_request.create!
# Gitea doesn't return PR in the Issue API endpoint, so labels must be assigned at this stage
- if project.gitea_import?
- apply_labels(merge_request, raw)
- end
+ apply_labels(merge_request, raw) if project.gitea_import?
rescue StandardError => e
- errors << { type: :pull_request, url: Gitlab::UrlSanitizer.sanitize(gh_pull_request.url), errors: e.message }
+ errors << {
+ type: :pull_request,
+ url: Gitlab::UrlSanitizer.sanitize(gh_pull_request.url),
+ errors: e.message
+ }
ensure
clean_up_restored_branches(gh_pull_request)
end
@@ -196,9 +194,7 @@ module Gitlab
return unless raw[:labels].count > 0
- label_ids = raw[:labels]
- .map { |attrs| @labels[attrs[:name]] }
- .compact
+ label_ids = raw[:labels].filter_map { |attrs| @labels[attrs[:name]] }
issuable.update_attribute(:label_ids, label_ids)
end
@@ -208,10 +204,14 @@ module Gitlab
resource_type = "#{issuable_type}_comments".to_sym
# Two notes here:
- # 1. We don't have a distinctive attribute for comments (unlike issues iid), so we fetch the last inserted note,
- # compare it against every comment in the current imported page until we find match, and that's where start importing
- # 2. GH returns comments for _both_ issues and PRs through issues_comments API, while pull_requests_comments returns
- # only comments on diffs, so select last note not based on noteable_type but on line_code
+ # 1. We don't have a distinctive attribute for comments (unlike issues
+ # iid), so we fetch the last inserted note, compare it against every
+ # comment in the current imported page until we find match, and that's
+ # where start importing
+ # 2. GH returns comments for _both_ issues and PRs through
+ # issues_comments API, while pull_requests_comments returns only
+ # comments on diffs, so select last note not based on noteable_type but
+ # on line_code
line_code_is = issuable_type == :pull_requests ? 'NOT NULL' : 'NULL'
last_note = project.notes.where("line_code IS #{line_code_is}").last
@@ -264,7 +264,8 @@ module Gitlab
comment_attrs.with_indifferent_access == last_note_attrs
end
- # No matching resource in the collection, which means we got halted right on the end of the last page, so all good
+ # No matching resource in the collection, which means we got halted
+ # right on the end of the last page, so all good
return unless cut_off_index
# Otherwise, remove the resources we've already inserted
@@ -280,9 +281,7 @@ module Gitlab
# GitHub error message when the wiki repo has not been created,
# this means that repo has wiki enabled, but have no pages. So,
# we can skip the import.
- if e.message !~ /repository not exported/
- errors << { type: :wiki, errors: e.message }
- end
+ errors << { type: :wiki, errors: e.message } if e.message.exclude?('repository not exported')
end
def import_releases
diff --git a/lib/gitlab/loggable.rb b/lib/gitlab/loggable.rb
new file mode 100644
index 00000000000..393e3eb37b6
--- /dev/null
+++ b/lib/gitlab/loggable.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Loggable
+ ANONYMOUS = '<Anonymous>'
+
+ def build_structured_payload(**params)
+ { class: self.class.name || ANONYMOUS }.merge(params).stringify_keys
+ end
+ end
+end
diff --git a/lib/gitlab/metrics/requests_rack_middleware.rb b/lib/gitlab/metrics/requests_rack_middleware.rb
index f635deabf76..b4baeba72e8 100644
--- a/lib/gitlab/metrics/requests_rack_middleware.rb
+++ b/lib/gitlab/metrics/requests_rack_middleware.rb
@@ -22,7 +22,7 @@ module Gitlab
# reasonable default. If we initialize every category we'll end up
# with an explosion in unused metric combinations, but we want the
# most common ones to be always present.
- FEATURE_CATEGORIES_TO_INITIALIZE = ['authentication_and_authorization',
+ FEATURE_CATEGORIES_TO_INITIALIZE = ['system_access',
'code_review_workflow', 'continuous_integration',
'not_owned', 'source_code_management',
FEATURE_CATEGORY_DEFAULT].freeze
diff --git a/lib/gitlab/metrics/subscribers/rack_attack.rb b/lib/gitlab/metrics/subscribers/rack_attack.rb
index e6cf14a6c8c..2196122df01 100644
--- a/lib/gitlab/metrics/subscribers/rack_attack.rb
+++ b/lib/gitlab/metrics/subscribers/rack_attack.rb
@@ -22,11 +22,6 @@ module Gitlab
}
end
- def redis(event)
- self.class.payload[:rack_attack_redis_count] += 1
- self.class.payload[:rack_attack_redis_duration_s] += event.duration.to_f / 1000
- end
-
def safelist(event)
req = event.payload[:request]
Gitlab::Instrumentation::Throttle.safelist = req.env['rack.attack.matched']
diff --git a/lib/gitlab/metrics/subscribers/rails_cache.rb b/lib/gitlab/metrics/subscribers/rails_cache.rb
index b12db9df66d..d2b6d0e3c14 100644
--- a/lib/gitlab/metrics/subscribers/rails_cache.rb
+++ b/lib/gitlab/metrics/subscribers/rails_cache.rb
@@ -9,7 +9,7 @@ module Gitlab
attach_to :active_support
def cache_read_multi(event)
- observe(:read_multi, event.duration)
+ observe(:read_multi, event)
return unless current_transaction
@@ -20,7 +20,7 @@ module Gitlab
end
def cache_read(event)
- observe(:read, event.duration)
+ observe(:read, event)
return unless current_transaction
return if event.payload[:super_operation] == :fetch
@@ -33,15 +33,15 @@ module Gitlab
end
def cache_write(event)
- observe(:write, event.duration)
+ observe(:write, event)
end
def cache_delete(event)
- observe(:delete, event.duration)
+ observe(:delete, event)
end
def cache_exist?(event)
- observe(:exists, event.duration)
+ observe(:exists, event)
end
def cache_fetch_hit(event)
@@ -60,17 +60,17 @@ module Gitlab
current_transaction.increment(:gitlab_transaction_cache_read_miss_count_total, 1)
end
- def observe(key, duration)
+ def observe(key, event)
return unless current_transaction
- labels = { operation: key }
+ labels = { operation: key, store: event.payload[:store].split('::').last }
current_transaction.increment(:gitlab_cache_operations_total, 1, labels) do
docstring 'Cache operations'
label_keys labels.keys
end
- metric_cache_operation_duration_seconds.observe(labels, duration / 1000.0)
+ metric_cache_operation_duration_seconds.observe(labels, event.duration / 1000.0)
end
private
diff --git a/lib/gitlab/multi_collection_paginator.rb b/lib/gitlab/multi_collection_paginator.rb
index 87cc0a0d3d2..e122f0b9317 100644
--- a/lib/gitlab/multi_collection_paginator.rb
+++ b/lib/gitlab/multi_collection_paginator.rb
@@ -9,6 +9,8 @@ module Gitlab
@per_page = (per_page || Kaminari.config.default_per_page).to_i
@first_collection, @second_collection = collections
+
+ raise ArgumentError, 'Page size must be at least 1' if @per_page < 1
end
def paginate(page)
diff --git a/lib/gitlab/nav/top_nav_menu_item.rb b/lib/gitlab/nav/top_nav_menu_item.rb
index 75eb0e8a264..a83cdbe15df 100644
--- a/lib/gitlab/nav/top_nav_menu_item.rb
+++ b/lib/gitlab/nav/top_nav_menu_item.rb
@@ -8,7 +8,10 @@ module Gitlab
# this is already :/. We could also take a hash and manually check every
# entry, but it's much more maintainable to do rely on native Ruby.
# rubocop: disable Metrics/ParameterLists
- def self.build(id:, title:, active: false, icon: '', href: '', view: '', css_class: nil, data: nil, emoji: nil)
+ def self.build(
+ id:, title:, active: false, icon: '', href: '', view: '',
+ css_class: nil, data: nil, partial: nil, component: nil
+ )
{
id: id,
type: :item,
@@ -19,7 +22,8 @@ module Gitlab
view: view.to_s,
css_class: css_class,
data: data || { qa_selector: 'menu_item_link', qa_title: title },
- emoji: emoji
+ partial: partial,
+ component: component
}
end
# rubocop: enable Metrics/ParameterLists
diff --git a/lib/gitlab/no_cache_headers.rb b/lib/gitlab/no_cache_headers.rb
index 2d03741480d..6afb108dcfd 100644
--- a/lib/gitlab/no_cache_headers.rb
+++ b/lib/gitlab/no_cache_headers.rb
@@ -4,7 +4,6 @@ module Gitlab
module NoCacheHeaders
DEFAULT_GITLAB_NO_CACHE_HEADERS = {
'Cache-Control' => "#{ActionDispatch::Http::Cache::Response::DEFAULT_CACHE_CONTROL}, no-store, no-cache",
- 'Pragma' => 'no-cache', # HTTP 1.0 compatibility
'Expires' => 'Fri, 01 Jan 1990 00:00:00 GMT'
}.freeze
diff --git a/lib/gitlab/observability.rb b/lib/gitlab/observability.rb
index 8dbd2f41ccb..f7f65c91339 100644
--- a/lib/gitlab/observability.rb
+++ b/lib/gitlab/observability.rb
@@ -2,8 +2,19 @@
module Gitlab
module Observability
- module_function
+ extend self
+ ACTION_TO_PERMISSION = {
+ explore: :read_observability,
+ datasources: :admin_observability,
+ manage: :admin_observability,
+ dashboards: :read_observability
+ }.freeze
+
+ EMBEDDABLE_PATHS = %w[explore goto].freeze
+
+ # Returns the GitLab Observability URL
+ #
def observability_url
return ENV['OVERRIDE_OBSERVABILITY_URL'] if ENV['OVERRIDE_OBSERVABILITY_URL']
# TODO Make observability URL configurable https://gitlab.com/gitlab-org/opstrace/opstrace-ui/-/issues/80
@@ -12,8 +23,123 @@ module Gitlab
'https://observe.gitlab.com'
end
- def observability_enabled?(user, group)
- Gitlab::Observability.observability_url.present? && Ability.allowed?(user, :read_observability, group)
+ # Returns true if the Observability feature flag is enabled
+ #
+ def enabled?(group = nil)
+ return Feature.enabled?(:observability_group_tab, group) if group
+
+ Feature.enabled?(:observability_group_tab)
+ end
+
+ # Returns the embeddable Observability URL of a given URL
+ #
+ # - Validates the URL
+ # - Checks that the path is embeddable
+ # - Converts the gitlab.com URL to observe.gitlab.com URL
+ #
+ # e.g.
+ #
+ # from: gitlab.com/groups/GROUP_PATH/-/observability/explore?observability_path=/explore
+ # to observe.gitlab.com/-/GROUP_ID/explore
+ #
+ # Returns nil if the URL is not a valid Observability URL or the path is not embeddable
+ #
+ def embeddable_url(url)
+ uri = validate_url(url, Gitlab.config.gitlab.url)
+ return unless uri
+
+ group = group_from_observability_url(url)
+ return unless group
+
+ parsed_query = CGI.parse(uri.query.to_s).transform_values(&:first).symbolize_keys
+ observability_path = parsed_query[:observability_path]
+
+ return build_full_url(group, observability_path, '/') if observability_path_embeddable?(observability_path)
+ end
+
+ # Returns true if the user is allowed to perform an action within a group
+ #
+ def allowed_for_action?(user, group, action)
+ return false if action.nil?
+
+ permission = ACTION_TO_PERMISSION.fetch(action.to_sym, :admin_observability)
+ allowed?(user, group, permission)
+ end
+
+ # Returns true if the user has the specified permission within the group
+ def allowed?(user, group, permission = :admin_observability)
+ return false unless group && user
+
+ observability_url.present? && Ability.allowed?(user, permission, group)
+ end
+
+ # Builds the full Observability URL given a certan group and path
+ #
+ # If unsanitized_observability_path is not valid or missing, fallbacks to fallback_path
+ #
+ def build_full_url(group, unsanitized_observability_path, fallback_path)
+ return unless group
+
+ # When running Observability UI in standalone mode (i.e. not backed by Observability Backend)
+ # the group-id is not required. !!This is only used for local dev!!
+ base_url = ENV['STANDALONE_OBSERVABILITY_UI'] == 'true' ? observability_url : "#{observability_url}/-/#{group.id}"
+
+ sanitized_path = if unsanitized_observability_path && sanitize(unsanitized_observability_path) != ''
+ CGI.unescapeHTML(sanitize(unsanitized_observability_path))
+ else
+ fallback_path || '/'
+ end
+
+ sanitized_path.prepend('/') if sanitized_path[0] != '/'
+
+ "#{base_url}#{sanitized_path}"
+ end
+
+ private
+
+ def validate_url(url, reference_url)
+ uri = URI.parse(url)
+ reference_uri = URI.parse(reference_url)
+
+ return uri if uri.scheme == reference_uri.scheme &&
+ uri.port == reference_uri.port &&
+ uri.host.casecmp?(reference_uri.host)
+ rescue URI::InvalidURIError
+ nil
+ end
+
+ def link_sanitizer
+ @link_sanitizer ||= Rails::Html::Sanitizer.safe_list_sanitizer.new
+ end
+
+ def sanitize(input)
+ link_sanitizer.sanitize(input, {})&.html_safe
+ end
+
+ def group_from_observability_url(url)
+ match = Rails.application.routes.recognize_path(url)
+
+ return if match[:unmatched_route].present?
+ return if match[:group_id].blank? || match[:action].blank? || match[:controller] != "groups/observability"
+
+ group_path = match[:group_id]
+ Group.find_by_full_path(group_path)
+ rescue ActionController::RoutingError
+ nil
+ end
+
+ def observability_path_embeddable?(observability_path)
+ return false unless observability_path
+
+ observability_path = observability_path[1..] if observability_path[0] == '/'
+
+ parsed_observability_path = URI.parse(observability_path).path.split('/')
+
+ base_path = parsed_observability_path[0]
+
+ EMBEDDABLE_PATHS.include?(base_path)
+ rescue URI::InvalidURIError
+ false
end
end
end
diff --git a/lib/gitlab/optimistic_locking.rb b/lib/gitlab/optimistic_locking.rb
index 9f39b5f122f..3c8ac55f70b 100644
--- a/lib/gitlab/optimistic_locking.rb
+++ b/lib/gitlab/optimistic_locking.rb
@@ -10,8 +10,11 @@ module Gitlab
start_time = Gitlab::Metrics::System.monotonic_time
retry_attempts = 0
+ # prevent scope override, see https://gitlab.com/gitlab-org/gitlab/-/issues/391186
+ klass = subject.is_a?(ActiveRecord::Relation) ? subject.klass : subject.class
+
begin
- subject.transaction do
+ klass.transaction do
yield(subject)
end
rescue ActiveRecord::StaleObjectError
diff --git a/lib/gitlab/pages/random_domain.rb b/lib/gitlab/pages/random_domain.rb
new file mode 100644
index 00000000000..8aa7611c910
--- /dev/null
+++ b/lib/gitlab/pages/random_domain.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Pages
+ class RandomDomain
+ PROJECT_PATH_LIMIT = 48
+ SUBDOMAIN_LABEL_LIMIT = 63
+
+ def self.generate(project_path:, namespace_path:)
+ new(project_path: project_path, namespace_path: namespace_path).generate
+ end
+
+ def initialize(project_path:, namespace_path:)
+ @project_path = project_path
+ @namespace_path = namespace_path
+ end
+
+ # Subdomains have a limit of 63 bytes (https://www.freesoft.org/CIE/RFC/1035/9.htm)
+ # For this reason we're limiting each part of the unique subdomain
+ #
+ # The domain is made up of 3 parts, like: projectpath-namespacepath-randomstring
+ # - project path: between 1 and 48 chars
+ # - namespace path: when the project path has less than 48 chars,
+ # the namespace full path will be used to fill the value up to 48 chars
+ # - random hexadecimal: to ensure a random value, the domain is then filled
+ # with a random hexadecimal value to complete 63 chars
+ def generate
+ domain = project_path.byteslice(0, PROJECT_PATH_LIMIT)
+
+ # if the project_path has less than PROJECT_PATH_LIMIT chars,
+ # fill the domain with the parent full_path up to 48 chars like:
+ # projectpath-namespacepath
+ if domain.length < PROJECT_PATH_LIMIT
+ namespace_size = PROJECT_PATH_LIMIT - domain.length - 1
+ domain.concat('-', namespace_path.byteslice(0, namespace_size))
+ end
+
+ # Complete the domain with random hexadecimal values util it is 63 chars long
+ # PS.: SecureRandom.hex return an string twice the size passed as argument.
+ domain.concat('-', SecureRandom.hex(SUBDOMAIN_LABEL_LIMIT - domain.length - 1))
+
+ # Slugify ensures the format and size (63 chars) of the given string
+ Gitlab::Utils.slugify(domain)
+ end
+
+ private
+
+ attr_reader :project_path, :namespace_path
+ end
+ end
+end
diff --git a/lib/gitlab/pages/virtual_host_finder.rb b/lib/gitlab/pages/virtual_host_finder.rb
new file mode 100644
index 00000000000..87fbf547770
--- /dev/null
+++ b/lib/gitlab/pages/virtual_host_finder.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Pages
+ class VirtualHostFinder
+ def initialize(host)
+ @host = host&.downcase
+ end
+
+ def execute
+ return if host.blank?
+
+ gitlab_host = ::Settings.pages.host.downcase.prepend(".")
+
+ if host.ends_with?(gitlab_host)
+ name = host.delete_suffix(gitlab_host)
+
+ by_namespace_domain(name) ||
+ by_unique_domain(name)
+ else
+ by_custom_domain(host)
+ end
+ end
+
+ private
+
+ attr_reader :host
+
+ def by_unique_domain(name)
+ return unless Feature.enabled?(:pages_unique_domain)
+
+ project = Project.by_pages_enabled_unique_domain(name)
+
+ return unless project&.pages_deployed?
+
+ ::Pages::VirtualDomain.new(projects: [project])
+ end
+
+ def by_namespace_domain(name)
+ namespace = Namespace.top_most.by_path(name)
+
+ 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
+ )
+ end
+
+ def by_custom_domain(host)
+ domain = PagesDomain.find_by_domain_case_insensitive(host)
+
+ 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
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/patch/node_loader.rb b/lib/gitlab/patch/node_loader.rb
new file mode 100644
index 00000000000..79f4b17dd93
--- /dev/null
+++ b/lib/gitlab/patch/node_loader.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+# Patch to address https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/2212#note_1287996694
+# It uses hostname instead of IP address if the former is present in `CLUSTER NODES` output.
+if Gem::Version.new(Redis::VERSION) > Gem::Version.new('4.8.1')
+ raise 'New version of redis detected, please remove or update this patch'
+end
+
+module Gitlab
+ module Patch
+ module NodeLoader
+ def self.prepended(base)
+ base.class_eval do
+ # monkey-patches https://github.com/redis/redis-rb/blob/v4.8.0/lib/redis/cluster/node_loader.rb#L23
+ def self.fetch_node_info(node)
+ node.call(%i[cluster nodes]).split("\n").map(&:split).to_h do |arr|
+ [
+ extract_host_identifier(arr[1]),
+ (arr[2].split(',') & %w[master slave]).first # rubocop:disable Naming/InclusiveLanguage
+ ]
+ end
+ end
+
+ # Since `CLUSTER SLOT` uses the preferred endpoint determined by
+ # the `cluster-preferred-endpoint-type` config value, we will prefer hostname over IP address.
+ # See https://redis.io/commands/cluster-nodes/ for details on the output format.
+ #
+ # @param [String] Address info matching fhe format: <ip:port@cport[,hostname[,auxiliary_field=value]*]>
+ def self.extract_host_identifier(node_address)
+ ip_chunk, hostname, _auxiliaries = node_address.split(',')
+ return ip_chunk.split('@').first if hostname.blank?
+
+ port = ip_chunk.split('@').first.split(':')[1]
+ "#{hostname}:#{port}"
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/private_commit_email.rb b/lib/gitlab/private_commit_email.rb
index 886c2c32d36..176402cadfe 100644
--- a/lib/gitlab/private_commit_email.rb
+++ b/lib/gitlab/private_commit_email.rb
@@ -19,7 +19,7 @@ module Gitlab
end
def user_ids_for_emails(emails)
- emails.map { |email| user_id_for_email(email) }.compact.uniq
+ emails.filter_map { |email| user_id_for_email(email) }.uniq
end
def for_user(user)
diff --git a/lib/gitlab/prometheus/queries/knative_invocation_query.rb b/lib/gitlab/prometheus/queries/knative_invocation_query.rb
deleted file mode 100644
index 6438995b576..00000000000
--- a/lib/gitlab/prometheus/queries/knative_invocation_query.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Prometheus
- module Queries
- class KnativeInvocationQuery < BaseQuery
- include QueryAdditionalMetrics
-
- def query(serverless_function_id)
- PrometheusMetricsFinder
- .new(identifier: :system_metrics_knative_function_invocation_count, common: true)
- .execute
- .first
- .to_query_metric
- .tap do |q|
- q.queries[0][:result] = run_query(q.queries[0][:query_range], context(serverless_function_id))
- end
- end
-
- protected
-
- def context(function_id)
- function = ::Serverless::Function.find_by_id(function_id)
- {
- function_name: function.name,
- kube_namespace: function.namespace
- }
- end
-
- def run_query(query, context)
- query %= context
- client_query_range(query, start_time: 8.hours.ago.to_f, end_time: Time.now.to_f)
- end
-
- def self.transform_reactive_result(result)
- result[:metrics] = result.delete :data
- result
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/rack_attack.rb b/lib/gitlab/rack_attack.rb
index bedbe9c0bff..d999b706d6c 100644
--- a/lib/gitlab/rack_attack.rb
+++ b/lib/gitlab/rack_attack.rb
@@ -19,7 +19,7 @@ module Gitlab
[429, { 'Content-Type' => 'text/plain' }.merge(throttled_headers), [Gitlab::Throttle.rate_limiting_response_text]]
end
- rack_attack.cache.store = Gitlab::RackAttack::InstrumentedCacheStore.new
+ rack_attack.cache.store = Gitlab::RackAttack::Store.new
# Configure the throttles
configure_throttles(rack_attack)
diff --git a/lib/gitlab/rack_attack/instrumented_cache_store.rb b/lib/gitlab/rack_attack/instrumented_cache_store.rb
deleted file mode 100644
index d8beb259fba..00000000000
--- a/lib/gitlab/rack_attack/instrumented_cache_store.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module RackAttack
- # This class is a proxy for all Redis calls made by RackAttack. All
- # the calls are instrumented, then redirected to the underlying
- # store (in `.store). This class instruments the standard interfaces
- # of ActiveRecord::Cache defined in
- # https://github.com/rails/rails/blob/v6.0.3.1/activesupport/lib/active_support/cache.rb#L315
- #
- # For more information, please see
- # https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/751
- class InstrumentedCacheStore
- NOTIFICATION_CHANNEL = 'redis.rack_attack'
-
- delegate :silence!, :mute, to: :@upstream_store
-
- def initialize(upstream_store: ::Gitlab::Redis::RateLimiting.cache_store, notifier: ActiveSupport::Notifications)
- @upstream_store = upstream_store
- @notifier = notifier
- end
-
- [:fetch, :read, :read_multi, :write_multi, :fetch_multi, :write, :delete,
- :exist?, :delete_matched, :increment, :decrement, :cleanup, :clear].each do |interface|
- define_method interface do |*args, **k_args, &block|
- @notifier.instrument(NOTIFICATION_CHANNEL, operation: interface) do
- @upstream_store.public_send(interface, *args, **k_args, &block) # rubocop:disable GitlabSecurity/PublicSend
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/rack_attack/store.rb b/lib/gitlab/rack_attack/store.rb
new file mode 100644
index 00000000000..e4a1b022c32
--- /dev/null
+++ b/lib/gitlab/rack_attack/store.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module RackAttack
+ class Store
+ InvalidAmount = Class.new(StandardError)
+
+ # The increment method gets called very often. The implementation below
+ # aims to minimize the number of Redis calls we make.
+ def increment(key, amount = 1, options = {})
+ # Our code below that prevents calling EXPIRE after every INCR assumes
+ # we always increment by 1. This is true in Rack::Attack as of v6.6.1.
+ # This guard should alert us if Rack::Attack changes its behavior in a
+ # future version.
+ raise InvalidAmount unless amount == 1
+
+ with do |redis|
+ key = namespace(key)
+ new_value = redis.incr(key)
+ expires_in = options[:expires_in]
+ redis.expire(key, expires_in) if new_value == 1 && expires_in
+ new_value
+ end
+ end
+
+ def read(key, _options = {})
+ with { |redis| redis.get(namespace(key)) }
+ end
+
+ def write(key, value, options = {})
+ with { |redis| redis.set(namespace(key), value, ex: options[:expires_in]) }
+ end
+
+ def delete(key, _options = {})
+ with { |redis| redis.del(namespace(key)) }
+ end
+
+ private
+
+ def with(&block)
+ # rubocop: disable CodeReuse/ActiveRecord
+ Gitlab::Redis::RateLimiting.with(&block)
+ # rubocop: enable CodeReuse/ActiveRecord
+ rescue ::Redis::BaseConnectionError
+ # Following the example of
+ # https://github.com/rack/rack-attack/blob/v6.6.1/lib/rack/attack/store_proxy/redis_proxy.rb#L61-L65,
+ # do not raise an error if we cannot connect to Redis. If
+ # Redis::RateLimiting is unavailable it should not take the site down.
+ nil
+ end
+
+ def namespace(key)
+ "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:#{key}"
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/redis/cache.rb b/lib/gitlab/redis/cache.rb
index 647573e59fe..ba3af3e7a6f 100644
--- a/lib/gitlab/redis/cache.rb
+++ b/lib/gitlab/redis/cache.rb
@@ -2,16 +2,6 @@
module Gitlab
module Redis
- # Match signature in
- # https://github.com/rails/rails/blob/v6.1.7.2/activesupport/lib/active_support/cache/redis_cache_store.rb#L59
- ERROR_HANDLER = ->(method:, returning:, exception:) do
- Gitlab::ErrorTracking.log_exception(
- exception,
- method: method,
- returning: returning.inspect
- )
- end
-
class Cache < ::Gitlab::Redis::Wrapper
CACHE_NAMESPACE = 'cache:gitlab'
@@ -22,8 +12,7 @@ module Gitlab
redis: pool,
compress: Gitlab::Utils.to_boolean(ENV.fetch('ENABLE_REDIS_CACHE_COMPRESSION', '1')),
namespace: CACHE_NAMESPACE,
- expires_in: default_ttl_seconds,
- error_handler: ::Gitlab::Redis::ERROR_HANDLER
+ expires_in: default_ttl_seconds
}
end
diff --git a/lib/gitlab/redis/multi_store.rb b/lib/gitlab/redis/multi_store.rb
index a102267d52b..9571e2f92e6 100644
--- a/lib/gitlab/redis/multi_store.rb
+++ b/lib/gitlab/redis/multi_store.rb
@@ -5,12 +5,6 @@ module Gitlab
class MultiStore
include Gitlab::Utils::StrongMemoize
- class ReadFromPrimaryError < StandardError
- def message
- 'Value not found on the redis primary store. Read from the redis secondary store successful.'
- end
- end
-
class PipelinedDiffError < StandardError
def initialize(result_primary, result_secondary)
@result_primary = result_primary
@@ -32,41 +26,33 @@ module Gitlab
attr_reader :primary_store, :secondary_store, :instance_name
- FAILED_TO_READ_ERROR_MESSAGE = 'Failed to read from the redis primary_store.'
+ FAILED_TO_READ_ERROR_MESSAGE = 'Failed to read from the redis default_store.'
FAILED_TO_WRITE_ERROR_MESSAGE = 'Failed to write to the redis primary_store.'
FAILED_TO_RUN_PIPELINE = 'Failed to execute pipeline on the redis primary_store.'
SKIP_LOG_METHOD_MISSING_FOR_COMMANDS = %i[info].freeze
- # For ENUMERATOR_CACHE_HIT_VALIDATOR and READ_CACHE_HIT_VALIDATOR,
- # we define procs to validate cache hit. The only other acceptable value is nil,
- # in the case of errors being raised.
- #
- # If a command has no empty response, set ->(val) { true }
- #
- # Ref: https://www.rubydoc.info/github/redis/redis-rb/Redis/Commands
- #
- READ_CACHE_HIT_VALIDATOR = {
- exists: ->(val) { val != 0 },
- exists?: ->(val) { val },
- get: ->(val) { !val.nil? },
- hexists: ->(val) { val },
- hget: ->(val) { !val.nil? },
- hgetall: ->(val) { val.is_a?(Hash) && !val.empty? },
- hlen: ->(val) { val != 0 },
- hmget: ->(val) { val.is_a?(Array) && !val.compact.empty? },
- hscan_each: ->(val) { val.is_a?(Enumerator) && !val.first.nil? },
- mapped_hmget: ->(val) { val.is_a?(Hash) && !val.compact.empty? },
- mget: ->(val) { val.is_a?(Array) && !val.compact.empty? },
- scan_each: ->(val) { val.is_a?(Enumerator) && !val.first.nil? },
- scard: ->(val) { val != 0 },
- sismember: ->(val) { val },
- smembers: ->(val) { val.is_a?(Array) && !val.empty? },
- sscan: ->(val) { val != ['0', []] },
- sscan_each: ->(val) { val.is_a?(Enumerator) && !val.first.nil? },
- ttl: ->(val) { val != 0 && val != -2 }, # ttl returns -2 if the key does not exist. See https://redis.io/commands/ttl/
- zscan_each: ->(val) { val.is_a?(Enumerator) && !val.first.nil? }
- }.freeze
+ READ_COMMANDS = %i[
+ exists
+ exists?
+ get
+ hexists
+ hget
+ hgetall
+ hlen
+ hmget
+ hscan_each
+ mapped_hmget
+ mget
+ scan_each
+ scard
+ sismember
+ smembers
+ sscan
+ sscan_each
+ ttl
+ zscan_each
+ ].freeze
WRITE_COMMANDS = %i[
del
@@ -111,7 +97,7 @@ module Gitlab
end
# rubocop:disable GitlabSecurity/PublicSend
- READ_CACHE_HIT_VALIDATOR.each_key do |name|
+ READ_COMMANDS.each do |name|
define_method(name) do |*args, **kwargs, &block|
if use_primary_and_secondary_stores?
read_command(name, *args, **kwargs, &block)
@@ -186,12 +172,6 @@ module Gitlab
@pipelined_command_error.increment(command: command_name, instance_name: instance_name)
end
- def increment_read_fallback_count(command_name)
- @read_fallback_counter ||= Gitlab::Metrics.counter(:gitlab_redis_multi_store_read_fallback_total,
- 'Client side Redis MultiStore reading fallback')
- @read_fallback_counter.increment(command: command_name, instance_name: instance_name)
- end
-
def increment_method_missing_count(command_name)
@method_missing_counter ||= Gitlab::Metrics.counter(:gitlab_redis_multi_store_method_missing_total,
'Client side Redis MultiStore method missing')
@@ -247,7 +227,7 @@ module Gitlab
if @instance
send_command(@instance, command_name, *args, **kwargs, &block)
else
- read_one_with_fallback(command_name, *args, **kwargs, &block)
+ read_from_default(command_name, *args, **kwargs, &block)
end
end
@@ -259,35 +239,12 @@ module Gitlab
end
end
- def read_one_with_fallback(command_name, *args, **kwargs, &block)
- begin
- value = send_command(default_store, command_name, *args, **kwargs, &block)
- rescue StandardError => e
- log_error(e, command_name,
- multi_store_error_message: FAILED_TO_READ_ERROR_MESSAGE)
- end
-
- return value if block.nil? && cache_hit?(command_name, value)
-
- fallback_read(command_name, *args, **kwargs, &block)
- end
-
- def cache_hit?(command, value)
- validator = READ_CACHE_HIT_VALIDATOR[command]
- return false unless validator
-
- !value.nil? && validator.call(value)
- end
-
- def fallback_read(command_name, *args, **kwargs, &block)
- value = send_command(fallback_store, command_name, *args, **kwargs, &block)
-
- if value
- log_error(ReadFromPrimaryError.new, command_name)
- increment_read_fallback_count(command_name)
- end
-
- value
+ def read_from_default(command_name, *args, **kwargs, &block)
+ send_command(default_store, command_name, *args, **kwargs, &block)
+ rescue StandardError => e
+ log_error(e, command_name,
+ multi_store_error_message: FAILED_TO_READ_ERROR_MESSAGE)
+ raise
end
def write_both(command_name, *args, **kwargs, &block)
diff --git a/lib/gitlab/redis/rate_limiting.rb b/lib/gitlab/redis/rate_limiting.rb
index 12710bafbea..62ab00c2408 100644
--- a/lib/gitlab/redis/rate_limiting.rb
+++ b/lib/gitlab/redis/rate_limiting.rb
@@ -3,6 +3,9 @@
module Gitlab
module Redis
class RateLimiting < ::Gitlab::Redis::Wrapper
+ # We create a subclass only for the purpose of differentiating between different stores in cache metrics
+ RateLimitingStore = Class.new(ActiveSupport::Cache::RedisCacheStore)
+
class << self
# The data we store on RateLimiting used to be stored on Cache.
def config_fallback
@@ -10,11 +13,7 @@ module Gitlab
end
def cache_store
- @cache_store ||= ActiveSupport::Cache::RedisCacheStore.new(
- redis: pool,
- namespace: Cache::CACHE_NAMESPACE,
- error_handler: ::Gitlab::Redis::ERROR_HANDLER
- )
+ @cache_store ||= RateLimitingStore.new(redis: pool, namespace: Cache::CACHE_NAMESPACE)
end
private
diff --git a/lib/gitlab/redis/repository_cache.rb b/lib/gitlab/redis/repository_cache.rb
index 6c7bc8c41d5..966c6584aa5 100644
--- a/lib/gitlab/redis/repository_cache.rb
+++ b/lib/gitlab/redis/repository_cache.rb
@@ -3,6 +3,9 @@
module Gitlab
module Redis
class RepositoryCache < ::Gitlab::Redis::Wrapper
+ # We create a subclass only for the purpose of differentiating between different stores in cache metrics
+ RepositoryCacheStore = Class.new(ActiveSupport::Cache::RedisCacheStore)
+
class << self
# The data we store on RepositoryCache used to be stored on Cache.
def config_fallback
@@ -10,12 +13,11 @@ module Gitlab
end
def cache_store
- @cache_store ||= ActiveSupport::Cache::RedisCacheStore.new(
+ @cache_store ||= RepositoryCacheStore.new(
redis: pool,
compress: Gitlab::Utils.to_boolean(ENV.fetch('ENABLE_REDIS_CACHE_COMPRESSION', '1')),
namespace: Cache::CACHE_NAMESPACE,
- expires_in: Cache.default_ttl_seconds,
- error_handler: ::Gitlab::Redis::ERROR_HANDLER
+ expires_in: Cache.default_ttl_seconds
)
end
end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 93d23add5eb..5b235639ae8 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -5,7 +5,12 @@ module Gitlab
module Packages
CONAN_RECIPE_FILES = %w[conanfile.py conanmanifest.txt conan_sources.tgz conan_export.tgz].freeze
CONAN_PACKAGE_FILES = %w[conaninfo.txt conanmanifest.txt conan_package.tgz].freeze
+
PYPI_NORMALIZED_NAME_REGEX_STRING = '[-_.]+'
+
+ # see https://github.com/apache/maven/blob/c1dfb947b509e195c75d4275a113598cf3063c3e/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java#L46
+ MAVEN_SNAPSHOT_DYNAMIC_PARTS = /\A.{0,1000}(-\d{8}\.\d{6}-\d+).{0,1000}\z/.freeze
+
API_PATH_REGEX = %r{^/api/v\d+/(projects/[^/]+/|groups?/[^/]+/-/)?packages/[A-Za-z]+}.freeze
def conan_package_reference_regex
@@ -141,7 +146,7 @@ module Gitlab
end
def debian_direct_upload_filename_regex
- @debian_direct_upload_filename_regex ||= %r{\A.*\.(deb|udeb)\z}o.freeze
+ @debian_direct_upload_filename_regex ||= %r{\A.*\.(deb|udeb|ddeb)\z}o.freeze
end
def helm_channel_regex
@@ -265,7 +270,7 @@ module Gitlab
# eg 'source/full/path' or 'destination_namespace' not 'https://example.com/destination/namespace/path'
# the regex also allows for an empty string ('') to be accepted as this is allowed in
# a bulk_import POST request
- @bulk_import_destination_namespace_path_regex ||= %r/((\A\z)|\A([.]?)[^\W](\/?[.]?[0-9a-z][-_]*)+\z)/i
+ @bulk_import_destination_namespace_path_regex ||= %r/((\A\z)|\A([.]?)\w*([0-9a-z][-_]*)(\/?[.]?[0-9a-z][-_]*)+\z)/i
end
def bulk_import_source_full_path_regex
@@ -548,11 +553,11 @@ module Gitlab
end
def issue
- @issue ||= /(?<issue>\d+)(?<format>\+)?(?=\W|\z)/
+ @issue ||= /(?<issue>\d+)(?<format>\+s{,1})?(?=\W|\z)/
end
def merge_request
- @merge_request ||= /(?<merge_request>\d+)(?<format>\+)?/
+ @merge_request ||= /(?<merge_request>\d+)(?<format>\+s{,1})?/
end
def base64_regex
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index 37414f9e2b1..93befc2df57 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -120,6 +120,14 @@ module Gitlab
[]
end
+ def failed?
+ false
+ end
+
+ def error
+ nil
+ end
+
private
def collection_for(scope)
diff --git a/lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb b/lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb
index 082d267442c..9340f67f73e 100644
--- a/lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb
+++ b/lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb
@@ -66,14 +66,18 @@ module Gitlab
plan_limits = Plan.default.actual_limits
if plan_limits.ci_registered_group_runners < @runner_count
- logger.error('The plan limits for group runners is set to ' \
+ warn 'The plan limits for group runners is set to ' \
"#{plan_limits.ci_registered_group_runners} runners. " \
- 'You should raise the plan limits to avoid errors during runner creation')
+ "You should raise the plan limits to avoid errors during runner creation by running " \
+ "the following command in the Rails console:\n" \
+ "Plan.default.actual_limits.update!(ci_registered_group_runners: #{@runner_count})"
return false
elsif plan_limits.ci_registered_project_runners < @runner_count
- logger.error('The plan limits for project runners is set to ' \
+ warn 'The plan limits for project runners is set to ' \
"#{plan_limits.ci_registered_project_runners} runners. " \
- 'You should raise the plan limits to avoid errors during runner creation')
+ "You should raise the plan limits to avoid errors during runner creation by running " \
+ "the following command in the Rails console:\n" \
+ "Plan.default.actual_limits.update!(ci_registered_project_runners: #{@runner_count})"
return false
end
diff --git a/lib/gitlab/serializer/ci/variables.rb b/lib/gitlab/serializer/ci/variables.rb
index 9abf3a54f37..a12bda0e5a7 100644
--- a/lib/gitlab/serializer/ci/variables.rb
+++ b/lib/gitlab/serializer/ci/variables.rb
@@ -12,7 +12,7 @@ module Gitlab
def load(string)
return unless string
- object = YAML.safe_load(string, [Symbol])
+ object = YAML.safe_load(string, permitted_classes: [Symbol])
object.map do |variable|
variable.symbolize_keys.tap do |variable|
diff --git a/lib/gitlab/serverless/service.rb b/lib/gitlab/serverless/service.rb
deleted file mode 100644
index c3ab2e9ddeb..00000000000
--- a/lib/gitlab/serverless/service.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-# frozen_string_literal: true
-
-class Gitlab::Serverless::Service
- include Gitlab::Utils::StrongMemoize
-
- def initialize(attributes)
- @attributes = attributes
- end
-
- def name
- @attributes.dig('metadata', 'name')
- end
-
- def namespace
- @attributes.dig('metadata', 'namespace')
- end
-
- def environment_scope
- @attributes.dig('environment_scope')
- end
-
- def environment
- @attributes.dig('environment')
- end
-
- def podcount
- @attributes.dig('podcount')
- end
-
- def created_at
- strong_memoize(:created_at) do
- timestamp = @attributes.dig('metadata', 'creationTimestamp')
- DateTime.parse(timestamp) if timestamp
- end
- end
-
- def image
- @attributes.dig(
- 'spec',
- 'runLatest',
- 'configuration',
- 'build',
- 'template',
- 'name')
- end
-
- def description
- knative_07_description || knative_05_06_description
- end
-
- def cluster
- @attributes.dig('cluster')
- end
-
- def url
- proxy_url || knative_06_07_url || knative_05_url
- end
-
- private
-
- def proxy_url
- if cluster&.serverless_domain
- ::Serverless::Domain.new(
- function_name: name,
- serverless_domain_cluster: cluster.serverless_domain,
- environment: environment
- ).uri.to_s
- end
- end
-
- def knative_07_description
- @attributes.dig(
- 'spec',
- 'template',
- 'metadata',
- 'annotations',
- 'Description'
- )
- end
-
- def knative_05_06_description
- @attributes.dig(
- 'spec',
- 'runLatest',
- 'configuration',
- 'revisionTemplate',
- 'metadata',
- 'annotations',
- 'Description')
- end
-
- def knative_05_url
- domain = @attributes.dig('status', 'domain')
- return unless domain
-
- "http://#{domain}"
- end
-
- def knative_06_07_url
- @attributes.dig('status', 'url')
- end
-end
diff --git a/lib/gitlab/slash_commands/incident_management/incident_new.rb b/lib/gitlab/slash_commands/incident_management/incident_new.rb
index 722fcff151d..ce91edfd51a 100644
--- a/lib/gitlab/slash_commands/incident_management/incident_new.rb
+++ b/lib/gitlab/slash_commands/incident_management/incident_new.rb
@@ -8,8 +8,8 @@ module Gitlab
'incident declare'
end
- def self.allowed?(project, user)
- Feature.enabled?(:incident_declare_slash_command, user) && can?(user, :create_incident, project)
+ def self.allowed?(_project, _user)
+ Feature.enabled?(:incident_declare_slash_command)
end
def self.match(text)
diff --git a/lib/gitlab/task_helpers.rb b/lib/gitlab/task_helpers.rb
index 9dba8c99b99..b9800a4db73 100644
--- a/lib/gitlab/task_helpers.rb
+++ b/lib/gitlab/task_helpers.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'rainbow/ext/string'
-require_dependency 'gitlab/utils/strong_memoize'
+require_relative 'utils/strong_memoize'
# rubocop:disable Rails/Output
module Gitlab
diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb
index 00e609511f2..1be9190e5f8 100644
--- a/lib/gitlab/url_blocker.rb
+++ b/lib/gitlab/url_blocker.rb
@@ -7,6 +7,8 @@ module Gitlab
class UrlBlocker
BlockedUrlError = Class.new(StandardError)
+ DENY_ALL_REQUESTS_EXCEPT_ALLOWED_DEFAULT = proc { deny_all_requests_except_allowed_app_setting }.freeze
+
class << self
# Validates the given url according to the constraints specified by arguments.
#
@@ -17,6 +19,7 @@ module Gitlab
# 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.
#
# Returns an array with [<uri>, <original-hostname>].
# rubocop:disable Metrics/ParameterLists
@@ -30,6 +33,7 @@ module Gitlab
ascii_only: false,
enforce_user: false,
enforce_sanitization: false,
+ deny_all_requests_except_allowed: DENY_ALL_REQUESTS_EXCEPT_ALLOWED_DEFAULT,
dns_rebind_protection: true)
# rubocop:enable Metrics/ParameterLists
@@ -49,21 +53,28 @@ module Gitlab
ascii_only: ascii_only
)
- address_info = get_address_info(uri, dns_rebind_protection)
- return [uri, nil] unless address_info
+ begin
+ address_info = get_address_info(uri)
+ rescue SocketError
+ return [uri, nil] unless enforce_address_info_retrievable?(uri, dns_rebind_protection, deny_all_requests_except_allowed)
+
+ raise BlockedUrlError, 'Host cannot be resolved or invalid'
+ end
ip_address = ip_address(address_info)
- return [uri, nil] if domain_allowed?(uri)
+ return [uri, nil] if domain_in_allow_list?(uri)
protected_uri_with_hostname = enforce_uri_hostname(ip_address, uri, dns_rebind_protection)
- return protected_uri_with_hostname if ip_allowed?(ip_address, port: get_port(uri))
+ return protected_uri_with_hostname if ip_in_allow_list?(ip_address, port: get_port(uri))
# Allow url from the GitLab instance itself but only for the configured hostname and ports
return protected_uri_with_hostname if internal?(uri)
return protected_uri_with_hostname if allow_object_storage && object_storage_endpoint?(uri)
+ validate_deny_all_requests_except_allowed!(deny_all_requests_except_allowed)
+
validate_local_request(
address_info: address_info,
allow_localhost: allow_localhost,
@@ -115,29 +126,41 @@ module Gitlab
validate_unicode_restriction(uri) if ascii_only
end
- def get_address_info(uri, dns_rebind_protection)
+ # 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 SocketError
- # If the dns rebinding protection is not enabled or the domain
- # is allowed we avoid the dns rebinding checks
- return if domain_allowed?(uri) || !dns_rebind_protection
+ rescue ArgumentError => error
+ # Addrinfo.getaddrinfo errors if the domain exceeds 1024 characters.
+ raise unless error.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)
+ # Do not enforce if URI is in the allow list
+ return false if domain_in_allow_list?(uri)
+
+ # Enforce if the instance should block requests
+ return true if deny_all_requests_except_allowed?(deny_all_requests_except_allowed)
+
+ # Do not enforce unless DNS rebinding protection is enabled
+ return false unless dns_rebind_protection
# 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 if Rails.env.test? && ENV['RSPEC_ALLOW_INVALID_URLS'] == 'true'
-
- # If the addr can't be resolved or the url is invalid (i.e http://1.1.1.1.1)
- # we block the url
- raise BlockedUrlError, "Host cannot be resolved or invalid"
- rescue ArgumentError => error
- # Addrinfo.getaddrinfo errors if the domain exceeds 1024 characters.
- raise unless error.message.include?('hostname too long')
+ return false if Rails.env.test? && ENV['RSPEC_ALLOW_INVALID_URLS'] == 'true'
- raise BlockedUrlError, "Host is too long (maximum is 1024 characters)"
+ true
end
def validate_local_request(
@@ -260,6 +283,15 @@ module Gitlab
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
@@ -302,6 +334,15 @@ module Gitlab
end.compact.uniq
end
+ def deny_all_requests_except_allowed?(should_deny)
+ should_deny.is_a?(Proc) ? should_deny.call : should_deny
+ end
+
+ def deny_all_requests_except_allowed_app_setting
+ Gitlab::CurrentSettings.current_application_settings? &&
+ Gitlab::CurrentSettings.deny_all_requests_except_allowed?
+ end
+
def object_storage_endpoint?(uri)
enabled_object_storage_endpoints.any? do |endpoint|
endpoint_uri = URI(endpoint)
@@ -312,11 +353,11 @@ module Gitlab
end
end
- def domain_allowed?(uri)
+ def domain_in_allow_list?(uri)
Gitlab::UrlBlockers::UrlAllowlist.domain_allowed?(uri.normalized_host, port: get_port(uri))
end
- def ip_allowed?(ip_address, port: nil)
+ def ip_in_allow_list?(ip_address, port: nil)
Gitlab::UrlBlockers::UrlAllowlist.ip_allowed?(ip_address, port: port)
end
diff --git a/lib/gitlab/usage/metrics/aggregates/aggregate.rb b/lib/gitlab/usage/metrics/aggregates/aggregate.rb
index b68e1ace658..a0a58534661 100644
--- a/lib/gitlab/usage/metrics/aggregates/aggregate.rb
+++ b/lib/gitlab/usage/metrics/aggregates/aggregate.rb
@@ -7,11 +7,6 @@ module Gitlab
class Aggregate
include Gitlab::Usage::TimeFrame
- # TODO: define this missing event https://gitlab.com/gitlab-org/gitlab/-/issues/385080
- EVENTS_NOT_DEFINED_YET = %w[
- i_code_review_merge_request_widget_license_compliance_warning
- ].freeze
-
def initialize(recorded_at)
@recorded_at = recorded_at
end
@@ -84,7 +79,7 @@ module Gitlab
return events if source != ::Gitlab::Usage::Metrics::Aggregates::REDIS_SOURCE
events.select do |event|
- ::Gitlab::UsageDataCounters::HLLRedisCounter.known_event?(event) || EVENTS_NOT_DEFINED_YET.include?(event)
+ ::Gitlab::UsageDataCounters::HLLRedisCounter.known_event?(event)
end
end
end
diff --git a/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric.rb b/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric.rb
index 642b67a3b02..ca122ccf6f3 100644
--- a/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric.rb
@@ -23,6 +23,7 @@ module Gitlab
scope = super
scope = scope.where(source_type: source_type) if source_type.present?
scope = scope.where(status: status) if status.present?
+ scope = scope.where(has_failures: failures) if failures.present?
scope
end
@@ -34,6 +35,10 @@ module Gitlab
options[:status]
end
+ def failures
+ options[:has_failures].to_s
+ end
+
def allowed_source_types
BulkImports::Entity.source_types.keys.map(&:to_s)
end
diff --git a/lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric.rb b/lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric.rb
new file mode 100644
index 00000000000..b7ca5fadd5b
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class GitlabDedicatedMetric < GenericMetric
+ value do
+ Gitlab::CurrentSettings.gitlab_dedicated_instance
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric.rb b/lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric.rb
new file mode 100644
index 00000000000..409027925d1
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class IndexInconsistenciesMetric < GenericMetric
+ value do
+ runner = Gitlab::Database::SchemaValidation::Runner.new(structure_sql, database, validators: validators)
+
+ inconsistencies = runner.execute
+
+ inconsistencies.map do |inconsistency|
+ {
+ object_name: inconsistency.object_name,
+ inconsistency_type: inconsistency.type
+ }
+ end
+ end
+
+ class << self
+ private
+
+ def database
+ database_model = Gitlab::Database.database_base_models[Gitlab::Database::MAIN_DATABASE_NAME]
+ Gitlab::Database::SchemaValidation::Database.new(database_model.connection)
+ end
+
+ def structure_sql
+ stucture_sql_path = Rails.root.join('db/structure.sql')
+ Gitlab::Database::SchemaValidation::StructureSql.new(stucture_sql_path)
+ end
+
+ def validators
+ [
+ Gitlab::Database::SchemaValidation::Validators::MissingIndexes,
+ Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionIndexes,
+ Gitlab::Database::SchemaValidation::Validators::ExtraIndexes
+ ]
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric.rb b/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric.rb
new file mode 100644
index 00000000000..c2ca62f9eba
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class InstallationCreationDateMetric < GenericMetric
+ value do
+ User.where(id: 1).pick(:created_at)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 53794854bd0..52b8d70c113 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -333,24 +333,10 @@ module Gitlab
end
def jira_usage
- # Jira Cloud does not support custom domains as per https://jira.atlassian.com/browse/CLOUD-6999
- # so we can just check for subdomains of atlassian.net
- jira_integration_data_hash = jira_integration_data
- if jira_integration_data_hash.nil?
- return { projects_jira_server_active: FALLBACK, projects_jira_cloud_active: FALLBACK }
- end
-
- results = {
- projects_jira_server_active: 0,
- projects_jira_cloud_active: 0,
+ {
projects_jira_dvcs_cloud_active: count(ProjectFeatureUsage.with_jira_dvcs_integration_enabled),
projects_jira_dvcs_server_active: count(ProjectFeatureUsage.with_jira_dvcs_integration_enabled(cloud: false))
}
-
- results[:projects_jira_server_active] = jira_integration_data_hash[:projects_jira_server_active]
- results[:projects_jira_cloud_active] = jira_integration_data_hash[:projects_jira_cloud_active]
-
- results
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -385,13 +371,11 @@ module Gitlab
end
def merge_requests_users(time_period)
- counter = Gitlab::UsageDataCounters::TrackUniqueEvents
-
redis_usage_data do
- counter.count_unique_events(
- event_action: Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION,
- date_from: time_period[:created_at].first,
- date_to: time_period[:created_at].last
+ Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
+ event_names: :merge_request_action,
+ start_date: time_period[:created_at].first,
+ end_date: time_period[:created_at].last
)
end
end
@@ -410,7 +394,7 @@ module Gitlab
end.data
platform = ohai_data['platform']
- platform = 'raspbian' if ohai_data['platform'] == 'debian' && /armv/.match?(ohai_data['kernel']['machine'])
+ platform = 'raspbian' if ohai_data['platform'] == 'debian' && ohai_data['kernel']['machine']&.include?('armv')
"#{platform}-#{ohai_data['platform_version']}"
end
@@ -464,10 +448,7 @@ module Gitlab
remote_mirrors: distinct_count(::Project.with_remote_mirrors.where(time_period), :creator_id),
snippets: distinct_count(::Snippet.where(time_period), :author_id)
}.tap do |h|
- if time_period.present?
- h[:merge_requests_users] = merge_requests_users(time_period)
- h.merge!(action_monthly_active_users(time_period))
- end
+ h[:merge_requests_users] = merge_requests_users(time_period) if time_period.present?
end
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -527,7 +508,6 @@ module Gitlab
# Omitted because no user, creator or author associated: `boards`, `labels`, `milestones`, `uploads`
# Omitted because too expensive: `epics_deepest_relationship_level`
- # Omitted because of encrypted properties: `projects_jira_cloud_active`, `projects_jira_server_active`
# rubocop: disable CodeReuse/ActiveRecord
def usage_activity_by_stage_plan(time_period)
time_frame = metric_time_period(time_period)
@@ -582,17 +562,6 @@ module Gitlab
{}
end
- def action_monthly_active_users(time_period)
- counter = Gitlab::UsageDataCounters::EditorUniqueCounter
- date_range = { date_from: time_period[:created_at].first, date_to: time_period[:created_at].last }
-
- {
- action_monthly_active_users_web_ide_edit: redis_usage_data { counter.count_web_ide_edit_actions(**date_range) },
- action_monthly_active_users_sfe_edit: redis_usage_data { counter.count_sfe_edit_actions(**date_range) },
- action_monthly_active_users_snippet_editor_edit: redis_usage_data { counter.count_snippet_editor_edit_actions(**date_range) }
- }
- end
-
def with_metadata
result = nil
error = nil
diff --git a/lib/gitlab/usage_data_counters/container_registry_event_counter.rb b/lib/gitlab/usage_data_counters/container_registry_event_counter.rb
new file mode 100644
index 00000000000..5d54bb18443
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/container_registry_event_counter.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module UsageDataCounters
+ class ContainerRegistryEventCounter < BaseCounter
+ KNOWN_EVENTS = %w[i_container_registry_delete_manifest].freeze
+ PREFIX = 'container_registry_events'
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data_counters/editor_unique_counter.rb b/lib/gitlab/usage_data_counters/editor_unique_counter.rb
index 2aebc1b8813..4e4a01ed301 100644
--- a/lib/gitlab/usage_data_counters/editor_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/editor_unique_counter.rb
@@ -38,18 +38,16 @@ module Gitlab
def track_unique_action(event_name, author, time, project = nil)
return unless author
- if Feature.enabled?(:route_hll_to_snowplow_phase2)
- Gitlab::Tracking.event(
- name,
- 'ide_edit',
- property: event_name.to_s,
- project: project,
- namespace: project&.namespace,
- user: author,
- label: 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit',
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context]
- )
- end
+ Gitlab::Tracking.event(
+ name,
+ 'ide_edit',
+ property: event_name.to_s,
+ project: project,
+ namespace: project&.namespace,
+ user: author,
+ label: 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit',
+ context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context]
+ )
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: author.id, time: time)
end
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 8a57a0331b8..b30c4b675f9 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
@@ -4,7 +4,9 @@ module Gitlab
module UsageDataCounters
module GitLabCliActivityUniqueCounter
GITLAB_CLI_API_REQUEST_ACTION = 'i_code_review_user_gitlab_cli_api_request'
- GITLAB_CLI_USER_AGENT_REGEX = /GitLab\sCLI$/.freeze
+
+ # 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
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 b809e6c4e42..4b7ec45bcca 100644
--- a/lib/gitlab/usage_data_counters/hll_redis_counter.rb
+++ b/lib/gitlab/usage_data_counters/hll_redis_counter.rb
@@ -5,26 +5,17 @@ module Gitlab
module HLLRedisCounter
DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH = 6.weeks
DEFAULT_DAILY_KEY_EXPIRY_LENGTH = 29.days
- DEFAULT_REDIS_SLOT = ''
+ REDIS_SLOT = 'hll_counters'
EventError = Class.new(StandardError)
UnknownEvent = Class.new(EventError)
UnknownAggregation = Class.new(EventError)
AggregationMismatch = Class.new(EventError)
- SlotMismatch = Class.new(EventError)
- CategoryMismatch = Class.new(EventError)
InvalidContext = Class.new(EventError)
KNOWN_EVENTS_PATH = File.expand_path('known_events/*.yml', __dir__)
ALLOWED_AGGREGATIONS = %i(daily weekly).freeze
- CATEGORIES_FOR_TOTALS = %w[
- compliance
- error_tracking
- ide_edit
- pipeline_authoring
- ].freeze
-
# Track event on entity_id
# Increment a Redis HLL counter for unique event_name and entity_id
#
@@ -33,10 +24,7 @@ module Gitlab
# Event example:
#
# - name: g_compliance_dashboard # Unique event name
- # redis_slot: compliance # Optional slot name, if not defined it will use name as a slot, used for totals
- # category: compliance # Group events in categories
# aggregation: daily # Aggregation level, keys are stored daily or weekly
- # feature_flag: # The event feature flag
#
# Usage:
#
@@ -76,23 +64,11 @@ module Gitlab
# context - Event context, plan level tracking. Available if set when tracking.
def unique_events(event_names:, start_date:, end_date:, context: '')
count_unique_events(event_names: event_names, start_date: start_date, end_date: end_date, context: context) do |events|
- raise SlotMismatch, events unless events_in_same_slot?(events)
- raise CategoryMismatch, events unless events_in_same_category?(events)
raise AggregationMismatch, events unless events_same_aggregation?(events)
raise InvalidContext if context.present? && !context.in?(valid_context_list)
end
end
- def categories
- @categories ||= known_events.map { |event| event[:category] }.uniq
- end
-
- # @param category [String] the category name
- # @return [Array<String>] list of event names for given category
- def events_for_category(category)
- known_events.select { |event| event[:category] == category.to_s }.map { |event| event[:name] }
- end
-
def known_event?(event_name)
event_for(event_name).present?
end
@@ -103,7 +79,6 @@ module Gitlab
def calculate_events_union(event_names:, start_date:, end_date:)
count_unique_events(event_names: event_names, start_date: start_date, end_date: end_date) do |events|
- raise SlotMismatch, events unless events_in_same_slot?(events)
raise AggregationMismatch, events unless events_same_aggregation?(events)
end
end
@@ -117,7 +92,7 @@ module Gitlab
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(UnknownEvent.new("Unknown event #{event_name}")) unless event.present?
return if event.blank?
- return unless feature_enabled?(event)
+ return unless Feature.enabled?(:redis_hll_tracking, type: :ops)
Gitlab::Redis::HLL.add(key: redis_key(event, time, context), value: values, expiry: expiry(event))
rescue StandardError => e
@@ -145,21 +120,6 @@ module Gitlab
redis_usage_data { Gitlab::Redis::HLL.count(keys: keys) }
end
- def feature_enabled?(event)
- return true if event[:feature_flag].blank?
-
- Feature.enabled?(event[:feature_flag]) && Feature.enabled?(:redis_hll_tracking, type: :ops)
- end
-
- # Allow to add totals for events that are in the same redis slot, category and have the same aggregation level
- # and if there are more than 1 event
- def eligible_for_totals?(events_names)
- return false if events_names.size <= 1
-
- events = events_for(events_names)
- events_in_same_slot?(events) && events_in_same_category?(events) && events_same_aggregation?(events)
- end
-
def keys_for_aggregation(aggregation, events:, start_date:, end_date:, context: '')
if aggregation.to_sym == :daily
daily_redis_keys(events: events, start_date: start_date, end_date: end_date, context: context)
@@ -182,20 +142,6 @@ module Gitlab
known_events.map { |event| event[:name] }
end
- def events_in_same_slot?(events)
- # if we check one event then redis_slot is only one to check
- return false if events.empty?
- return true if events.size == 1
-
- slot = events.first[:redis_slot]
- events.all? { |event| event[:redis_slot].present? && event[:redis_slot] == slot }
- end
-
- def events_in_same_category?(events)
- category = events.first[:category]
- events.all? { |event| event[:category] == category }
- end
-
def events_same_aggregation?(events)
aggregation = events.first[:aggregation]
events.all? { |event| event[:aggregation] == aggregation }
@@ -213,30 +159,17 @@ module Gitlab
known_events.select { |event| event_names.include?(event[:name]) }
end
- def redis_slot(event)
- event[:redis_slot] || DEFAULT_REDIS_SLOT
- end
-
# Compose the key in order to store events daily or weekly
def redis_key(event, time, context = '')
raise UnknownEvent, "Unknown event #{event[:name]}" unless known_events_names.include?(event[:name].to_s)
raise UnknownAggregation, "Use :daily or :weekly aggregation" unless ALLOWED_AGGREGATIONS.include?(event[:aggregation].to_sym)
- key = apply_slot(event)
+ key = "{#{REDIS_SLOT}}_#{event[:name]}"
key = apply_time_aggregation(key, time, event)
key = "#{context}_#{key}" if context.present?
key
end
- def apply_slot(event)
- slot = redis_slot(event)
- if slot.present?
- event[:name].to_s.gsub(slot, "{#{slot}}")
- else
- "{#{event[:name]}}"
- end
- end
-
def apply_time_aggregation(key, time, event)
if event[:aggregation].to_sym == :daily
year_day = time.strftime('%G-%j')
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 a59ea36961d..c0d1af8a43a 100644
--- a/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
@@ -180,7 +180,6 @@ module Gitlab
private
def track_snowplow_action(event_name, author, project)
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, project.namespace)
return unless author
Gitlab::Tracking.event(
diff --git a/lib/gitlab/usage_data_counters/known_events/analytics.yml b/lib/gitlab/usage_data_counters/known_events/analytics.yml
index 85524c766ca..0b30308b552 100644
--- a/lib/gitlab/usage_data_counters/known_events/analytics.yml
+++ b/lib/gitlab/usage_data_counters/known_events/analytics.yml
@@ -1,52 +1,26 @@
- name: users_viewing_analytics_group_devops_adoption
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: i_analytics_dev_ops_adoption
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: i_analytics_dev_ops_score
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: i_analytics_instance_statistics
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: p_analytics_pipelines
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: p_analytics_valuestream
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: p_analytics_repo
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: i_analytics_cohorts
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_pipelines
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_deployment_frequency
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_lead_time
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_time_to_restore_service
- category: analytics
- redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_change_failure_rate
- category: analytics
- redis_slot: analytics
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/ci_templates.yml b/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
index b13e3d631c7..82c023e6e38 100644
--- a/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
+++ b/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
@@ -4,602 +4,304 @@
# Do not edit it manually!
---
- name: p_ci_templates_terraform_base_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform_base
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_dotnet
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_nodejs
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_openshift
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_auto_devops
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_bash
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_rust
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_elixir
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_clojure
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_crystal
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_getting_started
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_code_quality
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_load_performance_testing
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_accessibility
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_failfast
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_browser_performance
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_browser_performance_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_grails
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_sast
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_runner_validation
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_on_demand_scan
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_secret_detection
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_license_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_coverage_fuzzing_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_on_demand_api_scan
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_coverage_fuzzing
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_api_fuzzing_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_secure_binaries
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_api
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_container_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_sast_iac
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dependency_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_api_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_container_scanning_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_api_fuzzing
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast
- category: ci_templates
- redis_slot: ci_templates
+ aggregation: weekly
+- name: p_ci_templates_security_api_discovery
aggregation: weekly
- name: p_ci_templates_security_fortify_fod_sast
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_sast_iac_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_qualys_iac_security
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_ios_fastlane
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_composer
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_c
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_python
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_android_fastlane
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_android_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_django
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_maven
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_liquibase
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_flutter
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_workflows_branch_pipelines
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_workflows_mergerequest_pipelines
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_laravel
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_kaniko
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_php
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_packer
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_themekit
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_katalon
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_mono
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_go
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_scala
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_latex
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_android
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_indeni_cloudrail
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_matlab
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_deploy_ecs
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_aws_cf_provision_and_deploy_ec2
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_aws_deploy_ecs
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_gradle
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_chef
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_dast_default_branch_deploy
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_load_performance_testing
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_helm_2to3
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_secret_detection
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_license_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_code_intelligence
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_code_quality
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_deploy_ecs
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_deploy_ec2
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_license_scanning_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_deploy
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_build
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_browser_performance_testing
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_container_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_container_scanning_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_dependency_scanning_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_test
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast_iac
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_secret_detection_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_dependency_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_deploy_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_browser_performance_testing_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_cf_provision
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_build_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast_iac_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform_latest
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_swift
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_jekyll
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_harp
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_octopress
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_brunch
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_doxygen
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_hyde
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_lektor
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_jbake
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_hexo
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_middleman
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_hugo
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_pelican
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_nanoc
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_swaggerui
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_jigsaw
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_metalsmith
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_gatsby
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_html
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_dart
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_docker
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_julia
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_npm
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_dotnet_core
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_5_minute_production_app
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_ruby
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_auto_devops
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_browser_performance_testing
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_build
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_code_intelligence
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_code_quality
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_container_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_dast_default_branch_deploy
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_dependency_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_deploy
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_deploy_ec2
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_deploy_ecs
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_helm_2to3
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_license_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_sast
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_secret_detection
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_test
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_container_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_dast
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_dependency_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_license_scanning
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_sast
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_secret_detection
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform_module_base
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform_module
- category: ci_templates
- redis_slot: ci_templates
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/ci_users.yml b/lib/gitlab/usage_data_counters/known_events/ci_users.yml
index b012d61eef5..49757c6e672 100644
--- a/lib/gitlab/usage_data_counters/known_events/ci_users.yml
+++ b/lib/gitlab/usage_data_counters/known_events/ci_users.yml
@@ -1,10 +1,4 @@
- name: ci_users_executing_deployment_job
- category: ci_users
- redis_slot: ci_users
aggregation: weekly
- feature_flag:
- name: ci_users_executing_verify_environment_job
- category: ci_users
- redis_slot: ci_users
aggregation: weekly
- feature_flag:
diff --git a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
index 3bb6655d762..db0c0653f63 100644
--- a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
@@ -1,457 +1,233 @@
---
- name: i_code_review_create_note_in_ipynb_diff
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_create_note_in_ipynb_diff_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_create_note_in_ipynb_diff_commit
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_create_note_in_ipynb_diff
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_create_note_in_ipynb_diff_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_create_note_in_ipynb_diff_commit
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_mr_diffs
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_single_file_diffs
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_mr_single_file_diffs
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_toggled_task_item_status
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_create_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_create_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_close_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_reopen_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_approve_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_unapprove_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_resolve_thread
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_unresolve_thread
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_edit_mr_title
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_edit_mr_desc
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_merge_mr
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_create_mr_comment
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_edit_mr_comment
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_remove_mr_comment
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_create_review_note
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_publish_review
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_create_multiline_mr_comment
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_edit_multiline_mr_comment
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_remove_multiline_mr_comment
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_add_suggestion
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_apply_suggestion
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_assigned
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_marked_as_draft
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_unmarked_as_draft
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_review_requested
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_approval_rule_added
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_approval_rule_deleted
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_approval_rule_edited
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_vs_code_api_request
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_jetbrains_api_request
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_gitlab_cli_api_request
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_create_mr_from_issue
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_mr_discussion_locked
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_mr_discussion_unlocked
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_time_estimate_changed
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_time_spent_changed
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_assignees_changed
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_reviewers_changed
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_milestone_changed
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_labels_changed
- redis_slot: code_review
- category: code_review
aggregation: weekly
# Diff settings events
- name: i_code_review_click_diff_view_setting
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_click_single_file_mode_setting
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_click_file_browser_setting
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_click_whitespace_setting
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_diff_view_inline
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_diff_view_parallel
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_file_browser_tree_view
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_file_browser_list_view
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_diff_show_whitespace
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_diff_hide_whitespace
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_diff_single_file
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_diff_multiple_files
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_load_conflict_ui
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_resolve_conflict
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_searches_diff
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_total_suggestions_applied
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_total_suggestions_added
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_user_resolve_thread_in_issue
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_widget_nothing_merge_click_new_file
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_post_merge_delete_branch
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_post_merge_click_revert
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_post_merge_click_cherry_pick
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_post_merge_submit_revert_modal
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_post_merge_submit_cherry_pick_modal
- redis_slot: code_review
- category: code_review
aggregation: weekly
# MR Widget Extensions
## Test Summary
- name: i_code_review_merge_request_widget_test_summary_view
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_full_report_clicked
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_expand
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_expand_success
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_expand_warning
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_expand_failed
- redis_slot: code_review
- category: code_review
aggregation: weekly
## Accessibility
- name: i_code_review_merge_request_widget_accessibility_view
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_full_report_clicked
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_expand
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_expand_success
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_expand_warning
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_expand_failed
- redis_slot: code_review
- category: code_review
aggregation: weekly
## Code Quality
- name: i_code_review_merge_request_widget_code_quality_view
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_full_report_clicked
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_expand
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_expand_success
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_expand_warning
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_expand_failed
- redis_slot: code_review
- category: code_review
aggregation: weekly
## Terraform
- name: i_code_review_merge_request_widget_terraform_view
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_full_report_clicked
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_expand
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_expand_success
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_expand_warning
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_expand_failed
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_submit_review_approve
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_submit_review_comment
- redis_slot: code_review
- category: code_review
aggregation: weekly
## License Compliance
- name: i_code_review_merge_request_widget_license_compliance_view
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_full_report_clicked
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_expand
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_expand_success
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_expand_warning
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_expand_failed
- redis_slot: code_review
- category: code_review
aggregation: weekly
## Security Reports
- name: i_code_review_merge_request_widget_security_reports_view
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_full_report_clicked
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_expand
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_expand_success
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_expand_warning
- redis_slot: code_review
- category: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_expand_failed
- redis_slot: code_review
- category: code_review
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/common.yml b/lib/gitlab/usage_data_counters/known_events/common.yml
index ae15530f0d0..f5973587ebb 100644
--- a/lib/gitlab/usage_data_counters/known_events/common.yml
+++ b/lib/gitlab/usage_data_counters/known_events/common.yml
@@ -1,313 +1,167 @@
---
# Compliance category
- name: g_edit_by_web_ide
- category: ide_edit
- redis_slot: edit
aggregation: daily
- name: g_edit_by_sfe
- category: ide_edit
- redis_slot: edit
aggregation: daily
- name: g_edit_by_snippet_ide
- category: ide_edit
- redis_slot: edit
aggregation: daily
- name: g_edit_by_live_preview
- category: ide_edit
- redis_slot: edit
aggregation: daily
- name: i_search_total
- category: search
- redis_slot: search
aggregation: weekly
- name: wiki_action
- category: source_code
aggregation: daily
- name: design_action
- category: source_code
aggregation: daily
- name: project_action
- category: source_code
aggregation: daily
- name: git_write_action
- category: source_code
aggregation: daily
- name: merge_request_action
- category: source_code
aggregation: daily
- name: i_source_code_code_intelligence
- redis_slot: source_code
- category: source_code
aggregation: daily
# Incident management
- name: incident_management_alert_status_changed
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_alert_assigned
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_alert_todo
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_created
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_reopened
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_closed
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_assigned
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_todo
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_comment
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_zoom_meeting
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_relate
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_unrelate
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_incident_change_confidential
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
# Incident management timeline events
- name: incident_management_timeline_event_created
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_timeline_event_edited
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
- name: incident_management_timeline_event_deleted
- redis_slot: incident_management
- category: incident_management
aggregation: weekly
# Incident management alerts
- name: incident_management_alert_create_incident
- redis_slot: incident_management
- category: incident_management_alerts
aggregation: weekly
# Testing category
- name: i_testing_test_case_parsed
- category: testing
- redis_slot: testing
aggregation: weekly
- name: i_testing_summary_widget_total
- category: testing
- redis_slot: testing
aggregation: weekly
- name: i_testing_test_report_uploaded
- category: testing
- redis_slot: testing
aggregation: weekly
- name: i_testing_coverage_report_uploaded
- category: testing
- redis_slot: testing
aggregation: weekly
# Project Management group
- name: g_project_management_issue_title_changed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_description_changed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_assignee_changed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_made_confidential
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_made_visible
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_created
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_closed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_reopened
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_label_changed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_milestone_changed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_cross_referenced
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_moved
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_related
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_unrelated
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_marked_as_duplicate
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_locked
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_unlocked
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_designs_added
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_designs_modified
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_designs_removed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_due_date_changed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_design_comments_removed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_time_estimate_changed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_time_spent_changed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_comment_added
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_comment_edited
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_comment_removed
- category: issues_edit
- redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_cloned
- category: issues_edit
- redis_slot: project_management
aggregation: daily
# Runner group
- name: g_runner_fleet_read_jobs_statistics
- category: runner
- redis_slot: runner
aggregation: weekly
# Secrets Management
- name: i_snippets_show
- category: snippets
- redis_slot: snippets
aggregation: weekly
# Terraform
- name: p_terraform_state_api_unique_users
- category: terraform
- redis_slot: terraform
aggregation: weekly
# Pipeline Authoring group
- name: o_pipeline_authoring_unique_users_committing_ciconfigfile
- category: pipeline_authoring
- redis_slot: pipeline_authoring
aggregation: weekly
- name: o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile
- category: pipeline_authoring
- redis_slot: pipeline_authoring
aggregation: weekly
- name: i_ci_secrets_management_id_tokens_build_created
- category: ci_secrets_management
- redis_slot: ci_secrets_management
aggregation: weekly
# Merge request widgets
- name: users_expanding_secure_security_report
- redis_slot: secure
- category: secure
aggregation: weekly
- name: users_expanding_testing_code_quality_report
- redis_slot: testing
- category: testing
aggregation: weekly
- name: users_expanding_testing_accessibility_report
- redis_slot: testing
- category: testing
aggregation: weekly
- name: users_expanding_testing_license_compliance_report
- redis_slot: testing
- category: testing
aggregation: weekly
- name: users_visiting_testing_license_compliance_full_report
- redis_slot: testing
- category: testing
aggregation: weekly
- name: users_visiting_testing_manage_license_compliance
- redis_slot: testing
- category: testing
aggregation: weekly
- name: users_clicking_license_testing_visiting_external_website
- redis_slot: testing
- category: testing
aggregation: weekly
# Geo group
- name: g_geo_proxied_requests
- category: geo
- redis_slot: geo
aggregation: daily
# Manage
- name: unique_active_user
- category: manage
aggregation: weekly
# Environments page
- name: users_visiting_environments_pages
- category: environments
- redis_slot: users
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/container_registry_events.yml b/lib/gitlab/usage_data_counters/known_events/container_registry_events.yml
index e8b14de1769..aa0f9965fa7 100644
--- a/lib/gitlab/usage_data_counters/known_events/container_registry_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/container_registry_events.yml
@@ -1,22 +1,11 @@
---
- name: i_container_registry_push_tag_user
- category: user_container_registry
aggregation: weekly
- redis_slot: container_registry
- name: i_container_registry_delete_tag_user
- category: user_container_registry
aggregation: weekly
- redis_slot: container_registry
- name: i_container_registry_push_repository_user
- category: user_container_registry
aggregation: weekly
- redis_slot: container_registry
- name: i_container_registry_delete_repository_user
- category: user_container_registry
aggregation: weekly
- redis_slot: container_registry
- name: i_container_registry_create_repository_user
- category: user_container_registry
aggregation: weekly
- redis_slot: container_registry
- \ No newline at end of file
diff --git a/lib/gitlab/usage_data_counters/known_events/ecosystem.yml b/lib/gitlab/usage_data_counters/known_events/ecosystem.yml
index 7f7c9166086..6e4a893d19a 100644
--- a/lib/gitlab/usage_data_counters/known_events/ecosystem.yml
+++ b/lib/gitlab/usage_data_counters/known_events/ecosystem.yml
@@ -1,46 +1,24 @@
---
# Ecosystem category
- name: i_ecosystem_jira_service_close_issue
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_jira_service_cross_reference
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_issue_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_push_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_deployment_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_wiki_page_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_merge_request_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_note_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_tag_push_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_confidential_note_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_confidential_issue_notification
- category: ecosystem
- redis_slot: ecosystem
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/error_tracking.yml b/lib/gitlab/usage_data_counters/known_events/error_tracking.yml
index d80b711f8eb..ebfd1b274f9 100644
--- a/lib/gitlab/usage_data_counters/known_events/error_tracking.yml
+++ b/lib/gitlab/usage_data_counters/known_events/error_tracking.yml
@@ -1,9 +1,5 @@
---
- name: error_tracking_view_details
- category: error_tracking
- redis_slot: error_tracking
aggregation: weekly
- name: error_tracking_view_list
- category: error_tracking
- redis_slot: error_tracking
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/importer_events.yml b/lib/gitlab/usage_data_counters/known_events/importer_events.yml
index c84d756a013..3346c0556d6 100644
--- a/lib/gitlab/usage_data_counters/known_events/importer_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/importer_events.yml
@@ -1,14 +1,14 @@
---
# Importer events
- name: github_import_project_start
- category: importer
- redis_slot: import
aggregation: weekly
- name: github_import_project_success
- category: importer
- redis_slot: import
aggregation: weekly
- name: github_import_project_failure
- category: importer
+ aggregation: weekly
+- name: github_import_project_cancelled
+ redis_slot: import
+ aggregation: weekly
+- name: github_import_project_partially_completed
redis_slot: import
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml b/lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml
index 966e6c584c7..b3d1c51c0e7 100644
--- a/lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml
+++ b/lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml
@@ -1,4 +1,2 @@
- name: agent_users_using_ci_tunnel
- category: kubernetes_agent
- redis_slot: agent
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/package_events.yml b/lib/gitlab/usage_data_counters/known_events/package_events.yml
index ef8d02fa365..47cc7f98838 100644
--- a/lib/gitlab/usage_data_counters/known_events/package_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/package_events.yml
@@ -1,89 +1,45 @@
---
- name: i_package_composer_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_composer_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_conan_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_conan_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_generic_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_generic_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_helm_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_helm_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_maven_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_maven_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_npm_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_npm_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_nuget_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_nuget_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_pypi_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_pypi_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_rubygems_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_rubygems_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_terraform_module_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
- name: i_package_terraform_module_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_rpm_user
- category: user_packages
aggregation: weekly
- redis_slot: package
- name: i_package_rpm_deploy_token
- category: deploy_token_packages
aggregation: weekly
- redis_slot: package
diff --git a/lib/gitlab/usage_data_counters/known_events/quickactions.yml b/lib/gitlab/usage_data_counters/known_events/quickactions.yml
index 69b348b9a22..7006173cc59 100644
--- a/lib/gitlab/usage_data_counters/known_events/quickactions.yml
+++ b/lib/gitlab/usage_data_counters/known_events/quickactions.yml
@@ -1,253 +1,127 @@
---
- name: i_quickactions_assign_multiple
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_approve
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unapprove
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_assign_single
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_assign_self
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_assign_reviewer
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_award
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_board_move
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_clone
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_close
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_confidential
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_copy_metadata_merge_request
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_copy_metadata_issue
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_create_merge_request
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_done
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_draft
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_due
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_duplicate
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_estimate
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_label
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_lock
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_merge
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_milestone
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_move
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_promote_to_incident
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_timeline
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_ready
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_reassign
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_reassign_reviewer
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_rebase
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_relabel
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_relate
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_due_date
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_estimate
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_milestone
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_time_spent
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_zoom
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_reopen
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_severity
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_shrug
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_spend_subtract
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_spend_add
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_submit_review
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_subscribe
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_tableflip
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_tag
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_target_branch
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_title
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_todo
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unassign_specific
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unassign_all
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unassign_reviewer
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unlabel_specific
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unlabel_all
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unlock
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unsubscribe
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_wip
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_zoom
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_link
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_invite_email_single
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_invite_email_multiple
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_add_contacts
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_contacts
- category: quickactions
- redis_slot: quickactions
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/work_items.yml b/lib/gitlab/usage_data_counters/known_events/work_items.yml
index d088b6d7e5a..a6e5b9e1af5 100644
--- a/lib/gitlab/usage_data_counters/known_events/work_items.yml
+++ b/lib/gitlab/usage_data_counters/known_events/work_items.yml
@@ -1,42 +1,21 @@
---
- name: users_updating_work_item_title
- category: work_items
- redis_slot: users
aggregation: weekly
- feature_flag: track_work_items_activity
- name: users_creating_work_items
- category: work_items
- redis_slot: users
aggregation: weekly
- feature_flag: track_work_items_activity
- name: users_updating_work_item_dates
- category: work_items
- redis_slot: users
aggregation: weekly
- feature_flag: track_work_items_activity
- name: users_updating_work_item_labels
- category: work_items
- redis_slot: users
aggregation: weekly
- feature_flag: track_work_items_activity
- name: users_updating_work_item_milestone
- category: work_items
- redis_slot: users
aggregation: weekly
- feature_flag: track_work_items_activity
- name: users_updating_work_item_iteration
# The event tracks an EE feature.
# It's added here so it can be aggregated into the CE/EE 'OR' aggregate metrics.
# It will report 0 for CE instances and should not be used with 'AND' aggregators.
- category: work_items
- redis_slot: users
aggregation: weekly
- feature_flag: track_work_items_activity
- name: users_updating_weight_estimate
# The event tracks an EE feature.
# It's added here so it can be aggregated into the CE/EE 'OR' aggregate metrics.
# It will report 0 for CE instances and should not be used with 'AND' aggregators.
- category: work_items
- redis_slot: users
aggregation: weekly
- feature_flag: track_work_items_activity
diff --git a/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
index c8768164710..fceeacb60ca 100644
--- a/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
@@ -68,8 +68,6 @@ module Gitlab
track_unique_action_by_merge_request(MR_CREATE_ACTION, merge_request)
project = merge_request.target_project
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, project.namespace)
-
Gitlab::Tracking.event(
name,
:create,
@@ -99,8 +97,6 @@ module Gitlab
track_unique_action_by_user(MR_APPROVE_ACTION, user)
project = merge_request.target_project
- return unless Feature.enabled?(:route_hll_to_snowplow_phase2, project.namespace)
-
Gitlab::Tracking.event(
name,
:approve,
diff --git a/lib/gitlab/usage_data_counters/track_unique_events.rb b/lib/gitlab/usage_data_counters/track_unique_events.rb
deleted file mode 100644
index 20da9665876..00000000000
--- a/lib/gitlab/usage_data_counters/track_unique_events.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module UsageDataCounters
- module TrackUniqueEvents
- WIKI_ACTION = :wiki_action
- DESIGN_ACTION = :design_action
- PUSH_ACTION = :project_action
- MERGE_REQUEST_ACTION = :merge_request_action
-
- GIT_WRITE_ACTIONS = [WIKI_ACTION, DESIGN_ACTION, PUSH_ACTION].freeze
- GIT_WRITE_ACTION = :git_write_action
-
- ACTION_TRANSFORMATIONS = HashWithIndifferentAccess.new({
- wiki: {
- created: WIKI_ACTION,
- updated: WIKI_ACTION,
- destroyed: WIKI_ACTION
- },
- design: {
- created: DESIGN_ACTION,
- updated: DESIGN_ACTION,
- destroyed: DESIGN_ACTION
- },
- project: {
- pushed: PUSH_ACTION
- },
- merge_request: {
- closed: MERGE_REQUEST_ACTION,
- merged: MERGE_REQUEST_ACTION,
- created: MERGE_REQUEST_ACTION,
- commented: MERGE_REQUEST_ACTION
- }
- }).freeze
-
- class << self
- def track_event(event_action:, event_target:, author_id:, time: Time.zone.now)
- return unless valid_target?(event_target)
- return unless valid_action?(event_action)
-
- transformed_target = transform_target(event_target)
- transformed_action = transform_action(event_action, transformed_target)
-
- return unless Gitlab::UsageDataCounters::HLLRedisCounter.known_event?(transformed_action.to_s)
-
- Gitlab::UsageDataCounters::HLLRedisCounter.track_event(transformed_action.to_s, values: author_id, time: time)
-
- track_git_write_action(author_id, transformed_action, time)
- end
-
- def count_unique_events(event_action:, date_from:, date_to:)
- Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: event_action.to_s, start_date: date_from, end_date: date_to)
- end
-
- private
-
- def transform_action(event_action, event_target)
- ACTION_TRANSFORMATIONS.dig(event_target, event_action) || event_action
- end
-
- def transform_target(event_target)
- Event::TARGET_TYPES.key(event_target)
- end
-
- def valid_target?(target)
- Event::TARGET_TYPES.value?(target)
- end
-
- def valid_action?(action)
- Event.actions.key?(action)
- end
-
- def track_git_write_action(author_id, transformed_action, time)
- return unless GIT_WRITE_ACTIONS.include?(transformed_action)
-
- Gitlab::UsageDataCounters::HLLRedisCounter.track_event(GIT_WRITE_ACTION, values: author_id, time: time)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/usage_data_counters/work_item_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/work_item_activity_unique_counter.rb
index b99c9ebb24f..9de575d8567 100644
--- a/lib/gitlab/usage_data_counters/work_item_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/work_item_activity_unique_counter.rb
@@ -33,7 +33,7 @@ module Gitlab
private
def track_unique_action(action, author)
- return unless author
+ return unless author && Feature.enabled?(:track_work_items_activity)
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(action, values: author.id)
end
diff --git a/lib/gitlab/usage_data_non_sql_metrics.rb b/lib/gitlab/usage_data_non_sql_metrics.rb
index 79d4b45a1ce..71386a58ba7 100644
--- a/lib/gitlab/usage_data_non_sql_metrics.rb
+++ b/lib/gitlab/usage_data_non_sql_metrics.rb
@@ -40,13 +40,6 @@ module Gitlab
def minimum_id(model, column = nil)
end
-
- def jira_integration_data
- {
- projects_jira_server_active: 0,
- projects_jira_cloud_active: 0
- }
- end
end
end
end
diff --git a/lib/gitlab/usage_data_queries.rb b/lib/gitlab/usage_data_queries.rb
index 3a163e5dde9..534a08cad9a 100644
--- a/lib/gitlab/usage_data_queries.rb
+++ b/lib/gitlab/usage_data_queries.rb
@@ -68,13 +68,6 @@ module Gitlab
end
end
- def jira_integration_data
- {
- projects_jira_server_active: 0,
- projects_jira_cloud_active: 0
- }
- end
-
def topology_usage_data
{
duration_s: 0,
diff --git a/lib/gitlab/utils/error_message.rb b/lib/gitlab/utils/error_message.rb
new file mode 100644
index 00000000000..e9c6f8a5847
--- /dev/null
+++ b/lib/gitlab/utils/error_message.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Utils
+ module ErrorMessage
+ extend self
+
+ def to_user_facing(message)
+ "UF: #{message}"
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/utils/override.rb b/lib/gitlab/utils/override.rb
index 7f43e25e50d..1d02bcbb2d2 100644
--- a/lib/gitlab/utils/override.rb
+++ b/lib/gitlab/utils/override.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
-require_dependency 'gitlab/utils'
-require_dependency 'gitlab/environment'
+require_relative '../utils'
+require_relative '../environment'
module Gitlab
module Utils
diff --git a/lib/gitlab/utils/uniquify.rb b/lib/gitlab/utils/uniquify.rb
new file mode 100644
index 00000000000..b5908d18103
--- /dev/null
+++ b/lib/gitlab/utils/uniquify.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+# Uniquify
+#
+# Return a version of the given 'base' string that is unique
+# by appending a counter to it. Uniqueness is determined by
+# repeated calls to the passed block.
+#
+# You can pass an initial value for the counter, if not given
+# counting starts from 1.
+#
+# If `base` is a function/proc, we expect that calling it with a
+# candidate counter returns a string to test/return.
+
+module Gitlab
+ module Utils
+ class Uniquify
+ def initialize(counter = nil)
+ @counter = counter
+ end
+
+ def string(base)
+ @base = base
+
+ increment_counter! while yield(base_string)
+ base_string
+ end
+
+ private
+
+ def base_string
+ if @base.respond_to?(:call)
+ @base.call(@counter)
+ else
+ "#{@base}#{@counter}"
+ end
+ end
+
+ def increment_counter!
+ @counter ||= 0
+ @counter += 1
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/utils/usage_data.rb b/lib/gitlab/utils/usage_data.rb
index fab8617bcda..4106084b301 100644
--- a/lib/gitlab/utils/usage_data.rb
+++ b/lib/gitlab/utils/usage_data.rb
@@ -255,33 +255,6 @@ module Gitlab
end
end
- # rubocop: disable UsageData/LargeTable:
- def jira_integration_data
- with_metadata do
- data = {
- projects_jira_server_active: 0,
- projects_jira_cloud_active: 0
- }
-
- # rubocop: disable CodeReuse/ActiveRecord
- ::Integrations::Jira.active.includes(:jira_tracker_data).find_in_batches(batch_size: 100) do |services|
- counts = services.group_by do |service|
- # TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
- service_url = service.data_fields&.url || (service.properties && service.properties['url'])
- service_url&.include?('.atlassian.net') ? :cloud : :server
- end
-
- data[:projects_jira_server_active] += counts[:server].size if counts[:server]
- data[:projects_jira_cloud_active] += counts[:cloud].size if counts[:cloud]
- end
-
- data
- end
- end
-
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: enable UsageData/LargeTable:
-
def minimum_id(model, column = nil)
key = :"#{model.name.downcase.gsub('::', '_')}_minimum_id"
column_to_read = column || :id
diff --git a/lib/gitlab/utils/username_and_email_generator.rb b/lib/gitlab/utils/username_and_email_generator.rb
new file mode 100644
index 00000000000..38c9bb7050d
--- /dev/null
+++ b/lib/gitlab/utils/username_and_email_generator.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'securerandom'
+
+module Gitlab
+ module Utils
+ class UsernameAndEmailGenerator
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(username_prefix:, email_domain: Gitlab.config.gitlab.host)
+ @username_prefix = username_prefix
+ @email_domain = email_domain
+ end
+
+ def username
+ uniquify.string(->(counter) { Kernel.sprintf(username_pattern, counter) }) do |suggested_username|
+ ::Namespace.by_path(suggested_username) || ::User.find_by_any_email(email_for(suggested_username))
+ end
+ end
+ strong_memoize_attr :username
+
+ def email
+ email_for(username)
+ end
+ strong_memoize_attr :email
+
+ private
+
+ def username_pattern
+ "#{@username_prefix}_#{SecureRandom.hex(16)}%s"
+ end
+
+ def email_for(name)
+ "#{name}@#{@email_domain}"
+ end
+
+ def uniquify
+ Gitlab::Utils::Uniquify.new
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/verify/batch_verifier.rb b/lib/gitlab/verify/batch_verifier.rb
index 71d106db742..bff95743dbd 100644
--- a/lib/gitlab/verify/batch_verifier.rb
+++ b/lib/gitlab/verify/batch_verifier.rb
@@ -34,7 +34,7 @@ module Gitlab
private
def run_batch_for(batch)
- batch.map { |upload| verify(upload) }.compact.to_h
+ batch.filter_map { |upload| verify(upload) }.to_h
end
def verify(object)
diff --git a/lib/object_storage/config.rb b/lib/object_storage/config.rb
index 056e22278dd..8a2044a8cba 100644
--- a/lib/object_storage/config.rb
+++ b/lib/object_storage/config.rb
@@ -6,6 +6,18 @@ module ObjectStorage
AZURE_PROVIDER = 'AzureRM'
GOOGLE_PROVIDER = 'Google'
+ LOCATIONS = {
+ artifacts: Gitlab.config.artifacts,
+ ci_secure_files: Gitlab.config.ci_secure_files,
+ dependency_proxy: Gitlab.config.dependency_proxy,
+ external_diffs: Gitlab.config.external_diffs,
+ lfs: Gitlab.config.lfs,
+ packages: Gitlab.config.packages,
+ pages: Gitlab.config.pages,
+ terraform_state: Gitlab.config.terraform_state,
+ uploads: Gitlab.config.uploads
+ }.freeze
+
attr_reader :options
def initialize(options)
@@ -13,7 +25,7 @@ module ObjectStorage
end
def credentials
- @credentials ||= options[:connection] || {}
+ @credentials ||= connection_params
end
def storage_options
@@ -86,6 +98,16 @@ module ObjectStorage
private
+ def connection_params
+ base_params = options[:connection] || {}
+
+ return base_params unless base_params[:provider].to_s == AWS_PROVIDER
+ return base_params unless ::Gitlab::FIPS.enabled?
+
+ # In fog-aws, this disables the use of Content-Md5: https://github.com/fog/fog-aws/pull/668
+ base_params.merge({ disable_content_md5_validation: true })
+ end
+
# This returns a Hash of HTTP encryption headers to send along to S3.
#
# They can also be passed in as Fog::AWS::Storage::File attributes, since there
diff --git a/lib/safe_zip/extract.rb b/lib/safe_zip/extract.rb
index b86941e6bea..3403e3e429e 100644
--- a/lib/safe_zip/extract.rb
+++ b/lib/safe_zip/extract.rb
@@ -1,6 +1,13 @@
# frozen_string_literal: true
module SafeZip
+ # SafeZip::Extract provides a safe interface
+ # to extract specific directories or files within a `zip` archive.
+ #
+ # @example Extract directories to destination
+ # SafeZip::Extract.new(archive_file).extract(directories: ['app/', 'test/'], to: destination_path)
+ # @example Extract files to destination
+ # SafeZip::Extract.new(archive_file).extract(files: ['index.html', 'app/index.js'], to: destination_path)
class Extract
Error = Class.new(StandardError)
PermissionDeniedError = Class.new(Error)
@@ -17,6 +24,20 @@ module SafeZip
@archive_path = archive_file
end
+ # extract given files or directories from the archive into the destination path
+ #
+ # @param [Hash] opts the options for extraction.
+ # @option opts [Array<String] :files list of files to be extracted
+ # @option opts [Array<String] :directories list of directories to be extracted
+ # @option opts [String] :to destination path
+ #
+ # @raise [PermissionDeniedError]
+ # @raise [SymlinkSourceDoesNotExistError]
+ # @raise [UnsupportedEntryError]
+ # @raise [EntrySizeError]
+ # @raise [AlreadyExistsError]
+ # @raise [NoMatchingError]
+ # @raise [ExtractError]
def extract(opts = {})
params = SafeZip::ExtractParams.new(**opts)
diff --git a/lib/sidebars/concerns/render_if_logged_in.rb b/lib/sidebars/concerns/render_if_logged_in.rb
new file mode 100644
index 00000000000..221af7df23b
--- /dev/null
+++ b/lib/sidebars/concerns/render_if_logged_in.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Concerns
+ module RenderIfLoggedIn
+ def render?
+ !!context.current_user
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/concerns/super_sidebar_panel.rb b/lib/sidebars/concerns/super_sidebar_panel.rb
new file mode 100644
index 00000000000..5f3607debbc
--- /dev/null
+++ b/lib/sidebars/concerns/super_sidebar_panel.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Concerns
+ # Contains helper methods aid conversion of a "normal" panel
+ # into a Super Sidebar Panel
+ module SuperSidebarPanel
+ # Picks menus from a list and adds them to the current menu list
+ # if they should be picked into the super sidebar
+ def pick_from_old_menus(old_menus)
+ old_menus.select! do |menu|
+ next true unless menu.pick_into_super_sidebar?
+
+ add_menu(menu)
+ false
+ end
+ end
+
+ def transform_old_menus(current_menus, *old_menus)
+ old_menus.each do |menu|
+ next unless menu.render?
+
+ menu.renderable_items.each { |item| add_menu_item_to_super_sidebar_parent(current_menus, item) }
+
+ menu_item_args = menu.serialize_as_menu_item_args
+
+ next if menu_item_args.nil?
+
+ add_menu_item_to_super_sidebar_parent(
+ current_menus, ::Sidebars::MenuItem.new(**menu_item_args)
+ )
+ end
+ end
+
+ private
+
+ # Finds a menu_items super sidebar parent and adds the item to that menu
+ # Handles:
+ # - menu_item.super_sidebar_before, adding before a certain item
+ # - parent == nil, or parent not being part of the panel:
+ # we assume that the menu item hasn't been categorized yet
+ # - parent == ::Sidebars::NilMenuItem, the item explicitly is supposed to be removed
+ def add_menu_item_to_super_sidebar_parent(menus, menu_item)
+ parent = menu_item.super_sidebar_parent || ::Sidebars::UncategorizedMenu
+ return if parent == ::Sidebars::NilMenuItem
+
+ idx = index_of(menus, parent) || index_of(menus, ::Sidebars::UncategorizedMenu)
+ return unless idx
+
+ if menu_item.super_sidebar_before
+ menus[idx].insert_item_before(menu_item.super_sidebar_before, menu_item)
+ else
+ menus[idx].add_item(menu_item)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/context.rb b/lib/sidebars/context.rb
index d9ac2705aaf..b49776bed10 100644
--- a/lib/sidebars/context.rb
+++ b/lib/sidebars/context.rb
@@ -6,16 +6,19 @@
# values where the logic is in helpers.
module Sidebars
class Context
- attr_reader :current_user, :container
+ attr_reader :current_user, :container, :route_is_active, :is_super_sidebar
def initialize(current_user:, container:, **args)
@current_user = current_user
@container = container
+ @is_super_sidebar = false
args.each do |key, value|
singleton_class.public_send(:attr_reader, key) # rubocop:disable GitlabSecurity/PublicSend
instance_variable_set("@#{key}", value)
end
+
+ @route_is_active ||= ->(_) { false }
end
end
end
diff --git a/lib/sidebars/explore/menus/groups_menu.rb b/lib/sidebars/explore/menus/groups_menu.rb
new file mode 100644
index 00000000000..542da0ad7fd
--- /dev/null
+++ b/lib/sidebars/explore/menus/groups_menu.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Explore
+ module Menus
+ class GroupsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ explore_groups_path
+ end
+
+ override :title
+ def title
+ _('Groups')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'group'
+ end
+
+ override :render?
+ def render?
+ true
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: ['explore/groups'] }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/explore/menus/projects_menu.rb b/lib/sidebars/explore/menus/projects_menu.rb
new file mode 100644
index 00000000000..29c35d23b7b
--- /dev/null
+++ b/lib/sidebars/explore/menus/projects_menu.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Explore
+ module Menus
+ class ProjectsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ explore_projects_path
+ end
+
+ override :title
+ def title
+ _('Projects')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'project'
+ end
+
+ override :render?
+ def render?
+ true
+ end
+
+ override :active_routes
+ def active_routes
+ { page: [link, explore_root_path] }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/explore/menus/snippets_menu.rb b/lib/sidebars/explore/menus/snippets_menu.rb
new file mode 100644
index 00000000000..67b852258a7
--- /dev/null
+++ b/lib/sidebars/explore/menus/snippets_menu.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Explore
+ module Menus
+ class SnippetsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ explore_snippets_path
+ end
+
+ override :title
+ def title
+ _('Snippets')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'snippet'
+ end
+
+ override :render?
+ def render?
+ true
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: ['explore/snippets'] }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/explore/menus/topics_menu.rb b/lib/sidebars/explore/menus/topics_menu.rb
new file mode 100644
index 00000000000..5e0a7897873
--- /dev/null
+++ b/lib/sidebars/explore/menus/topics_menu.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Explore
+ module Menus
+ class TopicsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ topics_explore_projects_path
+ end
+
+ override :title
+ def title
+ _('Topics')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'labels'
+ end
+
+ override :render?
+ def render?
+ true
+ end
+
+ override :active_routes
+ def active_routes
+ { page: link, path: 'projects#topic' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/explore/panel.rb b/lib/sidebars/explore/panel.rb
new file mode 100644
index 00000000000..9a585a99705
--- /dev/null
+++ b/lib/sidebars/explore/panel.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Explore
+ class Panel < ::Sidebars::Panel
+ override :configure_menus
+ def configure_menus
+ add_menus
+ end
+
+ override :aria_label
+ def aria_label
+ _('Explore')
+ end
+
+ override :render_raw_scope_menu_partial
+ def render_raw_scope_menu_partial
+ "shared/nav/explore_scope_header"
+ end
+
+ override :super_sidebar_context_header
+ def super_sidebar_context_header
+ {
+ title: aria_label,
+ icon: 'compass'
+ }
+ end
+
+ private
+
+ def add_menus
+ add_menu(Sidebars::Explore::Menus::ProjectsMenu.new(context))
+ add_menu(Sidebars::Explore::Menus::GroupsMenu.new(context))
+ add_menu(Sidebars::Explore::Menus::TopicsMenu.new(context))
+ add_menu(Sidebars::Explore::Menus::SnippetsMenu.new(context))
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/groups/menus/ci_cd_menu.rb b/lib/sidebars/groups/menus/ci_cd_menu.rb
index 0c2995f95e6..f32bc49673f 100644
--- a/lib/sidebars/groups/menus/ci_cd_menu.rb
+++ b/lib/sidebars/groups/menus/ci_cd_menu.rb
@@ -21,6 +21,11 @@ module Sidebars
'rocket'
end
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
+ end
+
private
def runners_menu_item
diff --git a/lib/sidebars/groups/menus/group_information_menu.rb b/lib/sidebars/groups/menus/group_information_menu.rb
index 3ce99e14a04..2364ad85cb5 100644
--- a/lib/sidebars/groups/menus/group_information_menu.rb
+++ b/lib/sidebars/groups/menus/group_information_menu.rb
@@ -28,6 +28,11 @@ module Sidebars
{ path: 'groups#subgroups' }
end
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ nil
+ end
+
private
def activity_menu_item
@@ -38,6 +43,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Activity'),
link: activity_group_path(context.group),
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::PlanMenu,
active_routes: { path: 'groups#activity' },
item_id: :activity
)
@@ -51,6 +57,8 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Labels'),
link: group_labels_path(context.group),
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::PlanMenu,
+ super_sidebar_before: :activity,
active_routes: { controller: :labels },
item_id: :labels
)
@@ -64,6 +72,8 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Members'),
link: group_group_members_path(context.group),
+ sprite_icon: context.is_super_sidebar ? 'users' : nil,
+ super_sidebar_parent: ::Sidebars::StaticMenu,
active_routes: { path: 'group_members#index' },
item_id: :members
)
diff --git a/lib/sidebars/groups/menus/invite_team_members_menu.rb b/lib/sidebars/groups/menus/invite_team_members_menu.rb
deleted file mode 100644
index 0779b696061..00000000000
--- a/lib/sidebars/groups/menus/invite_team_members_menu.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-module Sidebars
- module Groups
- module Menus
- class InviteTeamMembersMenu < ::Sidebars::Menu
- override :title
- def title
- s_('InviteMember|Invite members')
- end
-
- override :render?
- def render?
- can?(context.current_user, :admin_group_member, context.group) && all_valid_members.size <= 1
- end
-
- override :menu_partial
- def menu_partial
- 'groups/invite_members_side_nav_link'
- end
-
- override :menu_partial_options
- def menu_partial_options
- {
- group: context.group,
- title: title,
- sidebar_menu: self
- }
- end
-
- override :extra_nav_link_html_options
- def extra_nav_link_html_options
- {
- 'data-test-id': 'side-nav-invite-members'
- }
- end
-
- private
-
- def all_valid_members
- GroupMembersFinder.new(context.group, context.current_user).execute
- end
- end
- end
- end
-end
diff --git a/lib/sidebars/groups/menus/issues_menu.rb b/lib/sidebars/groups/menus/issues_menu.rb
index 4044cb1c716..75bdb617b1a 100644
--- a/lib/sidebars/groups/menus/issues_menu.rb
+++ b/lib/sidebars/groups/menus/issues_menu.rb
@@ -49,12 +49,25 @@ module Sidebars
}
end
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.merge({
+ active_routes: list_menu_item.active_routes,
+ sprite_icon: sprite_icon,
+ pill_count: pill_count,
+ has_pill: has_pill?,
+ super_sidebar_parent: ::Sidebars::StaticMenu,
+ item_id: :group_issue_list
+ })
+ end
+
private
def list_menu_item
::Sidebars::MenuItem.new(
title: _('List'),
link: issues_group_path(context.group),
+ super_sidebar_parent: ::Sidebars::NilMenuItem,
active_routes: { path: 'groups#issues' },
container_html_options: { aria: { label: _('Issues') } },
item_id: :issue_list
@@ -66,11 +79,16 @@ module Sidebars
return ::Sidebars::NilMenuItem.new(item_id: :boards)
end
- title = context.group.multiple_issue_boards_available? ? s_('IssueBoards|Boards') : s_('IssueBoards|Board')
+ title = if context.is_super_sidebar
+ context.group.multiple_issue_boards_available? ? s_('Issue boards') : s_('Issue board')
+ else
+ context.group.multiple_issue_boards_available? ? s_('IssueBoards|Boards') : s_('IssueBoards|Board')
+ end
::Sidebars::MenuItem.new(
title: title,
link: group_boards_path(context.group),
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::PlanMenu,
active_routes: { path: %w[boards#index boards#show] },
item_id: :boards
)
@@ -84,6 +102,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Milestones'),
link: group_milestones_path(context.group),
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::PlanMenu,
active_routes: { path: 'milestones#index' },
item_id: :milestones
)
diff --git a/lib/sidebars/groups/menus/kubernetes_menu.rb b/lib/sidebars/groups/menus/kubernetes_menu.rb
index 0d845978a93..a7c14148230 100644
--- a/lib/sidebars/groups/menus/kubernetes_menu.rb
+++ b/lib/sidebars/groups/menus/kubernetes_menu.rb
@@ -38,6 +38,14 @@ module Sidebars
def active_routes
{ controller: :clusters }
end
+
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.merge({
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::OperationsMenu,
+ item_id: :group_kubernetes_clusters
+ })
+ end
end
end
end
diff --git a/lib/sidebars/groups/menus/merge_requests_menu.rb b/lib/sidebars/groups/menus/merge_requests_menu.rb
index 050cba07641..5e25c33167c 100644
--- a/lib/sidebars/groups/menus/merge_requests_menu.rb
+++ b/lib/sidebars/groups/menus/merge_requests_menu.rb
@@ -52,6 +52,17 @@ module Sidebars
def active_routes
{ path: 'groups#merge_requests' }
end
+
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.merge({
+ sprite_icon: sprite_icon,
+ pill_count: pill_count,
+ has_pill: has_pill?,
+ super_sidebar_parent: ::Sidebars::StaticMenu,
+ item_id: :group_merge_request_list
+ })
+ end
end
end
end
diff --git a/lib/sidebars/groups/menus/observability_menu.rb b/lib/sidebars/groups/menus/observability_menu.rb
index d85efb1a002..570a59f7e55 100644
--- a/lib/sidebars/groups/menus/observability_menu.rb
+++ b/lib/sidebars/groups/menus/observability_menu.rb
@@ -6,8 +6,11 @@ module Sidebars
class ObservabilityMenu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
- add_item(explore_menu_item)
- add_item(datasources_menu_item)
+ add_item(explore_menu_item) if Gitlab::Observability.allowed_for_action?(context.current_user, context.group,
+ :explore)
+
+ add_item(datasources_menu_item) if Gitlab::Observability.allowed_for_action?(context.current_user,
+ context.group, :datasources)
end
override :title
@@ -22,7 +25,12 @@ module Sidebars
override :render?
def render?
- Gitlab::Observability.observability_enabled?(context.current_user, context.group)
+ Gitlab::Observability.allowed_for_action?(context.current_user, context.group, :explore)
+ end
+
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
end
private
diff --git a/lib/sidebars/groups/menus/packages_registries_menu.rb b/lib/sidebars/groups/menus/packages_registries_menu.rb
index e115ca669d4..73a67bf1142 100644
--- a/lib/sidebars/groups/menus/packages_registries_menu.rb
+++ b/lib/sidebars/groups/menus/packages_registries_menu.rb
@@ -23,6 +23,11 @@ module Sidebars
'package'
end
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ nil
+ end
+
private
def packages_registry_menu_item
@@ -31,6 +36,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Package Registry'),
link: group_packages_path(context.group),
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: 'groups/packages' },
item_id: :packages_registry
)
@@ -44,6 +50,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Container Registry'),
link: group_container_registries_path(context.group),
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: 'groups/registry/repositories' },
item_id: :container_registry
)
@@ -59,6 +66,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Harbor Registry'),
link: group_harbor_repositories_path(context.group),
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: 'groups/harbor/repositories' },
item_id: :harbor_registry
)
@@ -74,6 +82,8 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Dependency Proxy'),
link: group_dependency_proxy_path(context.group),
+ super_sidebar_parent: ::Sidebars::Groups::SuperSidebarMenus::OperationsMenu,
+ super_sidebar_before: :packages_registry,
active_routes: { controller: 'groups/dependency_proxies' },
item_id: :dependency_proxy
)
diff --git a/lib/sidebars/groups/menus/scope_menu.rb b/lib/sidebars/groups/menus/scope_menu.rb
index 6ce43491343..5505f56a6d3 100644
--- a/lib/sidebars/groups/menus/scope_menu.rb
+++ b/lib/sidebars/groups/menus/scope_menu.rb
@@ -16,7 +16,7 @@ module Sidebars
override :active_routes
def active_routes
- { path: %w[groups#show groups#details] }
+ { path: %w[groups#show groups#details groups#new projects#new] }
end
override :extra_nav_link_html_options
@@ -32,6 +32,16 @@ module Sidebars
def render?
true
end
+
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.merge({
+ title: _('Group overview'),
+ sprite_icon: 'group',
+ super_sidebar_parent: ::Sidebars::StaticMenu,
+ item_id: :group_overview
+ })
+ end
end
end
end
diff --git a/lib/sidebars/groups/menus/settings_menu.rb b/lib/sidebars/groups/menus/settings_menu.rb
index 5b81f22c796..76c5f9c16a5 100644
--- a/lib/sidebars/groups/menus/settings_menu.rb
+++ b/lib/sidebars/groups/menus/settings_menu.rb
@@ -47,6 +47,11 @@ module Sidebars
}
end
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
+ end
+
private
def general_menu_item
diff --git a/lib/sidebars/groups/panel.rb b/lib/sidebars/groups/panel.rb
index e8b815bdce7..77ca51ddf92 100644
--- a/lib/sidebars/groups/panel.rb
+++ b/lib/sidebars/groups/panel.rb
@@ -16,22 +16,12 @@ module Sidebars
add_menu(Sidebars::Groups::Menus::PackagesRegistriesMenu.new(context))
add_menu(Sidebars::Groups::Menus::CustomerRelationsMenu.new(context))
add_menu(Sidebars::Groups::Menus::SettingsMenu.new(context))
- add_invite_members_menu
end
override :aria_label
def aria_label
context.group.subgroup? ? _('Subgroup navigation') : _('Group navigation')
end
-
- private
-
- def add_invite_members_menu
- experiment(:invite_members_in_side_nav, group: context.group) do |e|
- e.control {}
- e.candidate { add_menu(Sidebars::Groups::Menus::InviteTeamMembersMenu.new(context)) }
- end
- end
end
end
end
diff --git a/lib/sidebars/groups/super_sidebar_menus/operations_menu.rb b/lib/sidebars/groups/super_sidebar_menus/operations_menu.rb
new file mode 100644
index 00000000000..195718e0681
--- /dev/null
+++ b/lib/sidebars/groups/super_sidebar_menus/operations_menu.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Groups
+ module SuperSidebarMenus
+ class OperationsMenu < ::Sidebars::Menu
+ override :title
+ def title
+ _('Operations')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'deployments'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/groups/super_sidebar_menus/plan_menu.rb b/lib/sidebars/groups/super_sidebar_menus/plan_menu.rb
new file mode 100644
index 00000000000..8a90974c0d4
--- /dev/null
+++ b/lib/sidebars/groups/super_sidebar_menus/plan_menu.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Groups
+ module SuperSidebarMenus
+ class PlanMenu < ::Sidebars::Menu
+ override :title
+ def title
+ _('Plan')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'planning'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/groups/super_sidebar_panel.rb b/lib/sidebars/groups/super_sidebar_panel.rb
new file mode 100644
index 00000000000..620f6e78eda
--- /dev/null
+++ b/lib/sidebars/groups/super_sidebar_panel.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Groups
+ class SuperSidebarPanel < ::Sidebars::Groups::Panel
+ include ::Sidebars::Concerns::SuperSidebarPanel
+ extend ::Gitlab::Utils::Override
+
+ override :configure_menus
+ def configure_menus
+ super
+ old_menus = @menus
+ @menus = []
+
+ add_menu(Sidebars::StaticMenu.new(context))
+ add_menu(Sidebars::Groups::SuperSidebarMenus::PlanMenu.new(context))
+
+ pick_from_old_menus(old_menus)
+
+ insert_menu_before(
+ Sidebars::Groups::Menus::ObservabilityMenu,
+ Sidebars::Groups::SuperSidebarMenus::OperationsMenu.new(context)
+ )
+
+ insert_menu_before(
+ Sidebars::Groups::Menus::SettingsMenu,
+ Sidebars::UncategorizedMenu.new(context)
+ )
+
+ transform_old_menus(@menus, @scope_menu, *old_menus)
+ end
+
+ override :super_sidebar_context_header
+ def super_sidebar_context_header
+ {
+ title: context.group.name,
+ avatar: context.group.avatar_url,
+ id: context.group.id
+ }
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/menu.rb b/lib/sidebars/menu.rb
index dfd88c99a0c..03995362ff0 100644
--- a/lib/sidebars/menu.rb
+++ b/lib/sidebars/menu.rb
@@ -66,6 +66,40 @@ module Sidebars
@renderable_items ||= @items.select(&:render?)
end
+ # Returns a tree-like representation of itself and all
+ # renderable menu entries, with additional information
+ # on whether the item(s) have an active route
+ def serialize_for_super_sidebar
+ items = serialize_items_for_super_sidebar
+ is_active = @context.route_is_active.call(active_routes) || items.any? { |item| item[:is_active] }
+
+ {
+ title: title,
+ icon: sprite_icon,
+ link: link,
+ is_active: is_active,
+ pill_count: has_pill? ? pill_count : nil,
+ items: items
+ }
+ end
+
+ # Returns an array of renderable menu entries,
+ # with additional information on whether the item
+ # has an active route
+ def serialize_items_for_super_sidebar
+ # All renderable menu entries
+ renderable_items.map do |entry|
+ entry.serialize_for_super_sidebar.tap do |item|
+ active_routes = item.delete(:active_routes)
+ item[:is_active] = active_routes ? @context.route_is_active.call(active_routes) : false
+ end
+ end
+ end
+
+ def pick_into_super_sidebar?
+ false
+ end
+
# Returns whether the menu has any renderable menu item
def has_renderable_items?
renderable_items.any?
@@ -93,6 +127,17 @@ module Sidebars
end
end
+ # Sometimes we want to convert a top-level Menu (e.g. Wiki/Snippets)
+ # to a MenuItem. This serializer is used in order to enable that conversion
+ def serialize_as_menu_item_args
+ {
+ title: title,
+ link: link,
+ active_routes: active_routes,
+ container_html_options: container_html_options
+ }
+ end
+
private
override :index_of
diff --git a/lib/sidebars/menu_item.rb b/lib/sidebars/menu_item.rb
index efdedf6c3bd..becff240034 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
+ 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, :super_sidebar_before
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)
+ 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, super_sidebar_before: nil)
@title = title
@link = link
@active_routes = active_routes
@@ -19,6 +19,8 @@ module Sidebars
@hint_html_options = hint_html_options
@has_pill = has_pill
@pill_count = pill_count
+ @super_sidebar_before = super_sidebar_before
+ @super_sidebar_parent = super_sidebar_parent
end
# rubocop: enable Metrics/ParameterLists
@@ -30,6 +32,25 @@ module Sidebars
true
end
+ def serialize_for_super_sidebar
+ {
+ title: title,
+ icon: sprite_icon,
+ link: link,
+ active_routes: active_routes,
+ pill_count: has_pill ? pill_count : nil
+ # Check whether support is needed for the following properties,
+ # in order to get feature parity with the HAML renderer
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/391864
+ #
+ # container_html_options
+ # hint_html_options
+ # nav_link_html_options
+ #
+ # item_id
+ }
+ end
+
def nav_link_html_options
{
data: {
diff --git a/lib/sidebars/panel.rb b/lib/sidebars/panel.rb
index 2a172cfffe3..4c0d4caf81e 100644
--- a/lib/sidebars/panel.rb
+++ b/lib/sidebars/panel.rb
@@ -4,7 +4,6 @@ module Sidebars
class Panel
extend ::Gitlab::Utils::Override
include ::Sidebars::Concerns::PositionableList
- include Gitlab::Experiment::Dsl
attr_reader :context, :scope_menu, :hidden_menu
@@ -61,6 +60,16 @@ module Sidebars
@renderable_menus ||= @menus.select(&:render?)
end
+ # Serializes every renderable menu and returns a flattened result
+ def super_sidebar_menu_items
+ @super_sidebar_menu_items ||= renderable_menus
+ .flat_map(&:serialize_for_super_sidebar)
+ end
+
+ def super_sidebar_context_header
+ raise NotImplementedError
+ end
+
def container
context.container
end
diff --git a/lib/sidebars/projects/menus/analytics_menu.rb b/lib/sidebars/projects/menus/analytics_menu.rb
index 643b7ebcd5a..fae2efd91de 100644
--- a/lib/sidebars/projects/menus/analytics_menu.rb
+++ b/lib/sidebars/projects/menus/analytics_menu.rb
@@ -41,6 +41,11 @@ module Sidebars
'chart'
end
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
+ end
+
private
def ci_cd_analytics_menu_item
diff --git a/lib/sidebars/projects/menus/ci_cd_menu.rb b/lib/sidebars/projects/menus/ci_cd_menu.rb
index 5df99bb9d84..3d11dba1089 100644
--- a/lib/sidebars/projects/menus/ci_cd_menu.rb
+++ b/lib/sidebars/projects/menus/ci_cd_menu.rb
@@ -39,6 +39,11 @@ module Sidebars
'rocket'
end
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
+ end
+
private
def pipelines_menu_item
diff --git a/lib/sidebars/projects/menus/deployments_menu.rb b/lib/sidebars/projects/menus/deployments_menu.rb
index 4d4e65e9795..fa6c70cfd3d 100644
--- a/lib/sidebars/projects/menus/deployments_menu.rb
+++ b/lib/sidebars/projects/menus/deployments_menu.rb
@@ -34,6 +34,11 @@ module Sidebars
'deployments'
end
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ nil
+ end
+
private
def feature_flags_menu_item
@@ -44,6 +49,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Feature Flags'),
link: project_feature_flags_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: :feature_flags },
container_html_options: { class: 'shortcuts-feature-flags' },
item_id: :feature_flags
@@ -58,6 +64,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Environments'),
link: project_environments_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: :environments },
container_html_options: { class: 'shortcuts-environments' },
item_id: :environments
@@ -73,6 +80,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Releases'),
link: project_releases_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
item_id: :releases,
active_routes: { controller: :releases },
container_html_options: { class: 'shortcuts-deployments-releases' }
@@ -87,6 +95,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Pages'),
link: project_pages_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { path: 'pages#show' },
item_id: :pages
)
diff --git a/lib/sidebars/projects/menus/infrastructure_menu.rb b/lib/sidebars/projects/menus/infrastructure_menu.rb
index 04c9ab77729..a7cd920a74c 100644
--- a/lib/sidebars/projects/menus/infrastructure_menu.rb
+++ b/lib/sidebars/projects/menus/infrastructure_menu.rb
@@ -11,6 +11,7 @@ module Sidebars
add_item(kubernetes_menu_item)
add_item(terraform_menu_item)
add_item(google_cloud_menu_item)
+ add_item(aws_menu_item)
true
end
@@ -32,6 +33,11 @@ module Sidebars
'cloud-gear'
end
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ nil
+ end
+
private
def feature_enabled?
@@ -46,6 +52,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Kubernetes clusters'),
link: project_clusters_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: [:cluster_agents, :clusters] },
container_html_options: { class: 'shortcuts-kubernetes' },
hint_html_options: kubernetes_hint_html_options,
@@ -74,11 +81,30 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Terraform'),
link: project_terraform_index_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: :terraform },
item_id: :terraform
)
end
+ def aws_menu_item
+ enabled_for_user = Feature.enabled?(:cloudseed_aws, context.current_user)
+ enabled_for_group = Feature.enabled?(:cloudseed_aws, context.project.group)
+ enabled_for_project = Feature.enabled?(:cloudseed_aws, context.project)
+ feature_is_enabled = enabled_for_user || enabled_for_group || enabled_for_project
+ user_has_permissions = can?(context.current_user, :admin_project_aws, context.project)
+
+ return ::Sidebars::NilMenuItem.new(item_id: :cloudseed_aws) unless feature_is_enabled && user_has_permissions
+
+ ::Sidebars::MenuItem.new(
+ title: _('AWS'),
+ link: '#',
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
+ item_id: :aws,
+ active_routes: { controller: '' }
+ )
+ end
+
def google_cloud_menu_item
enabled_for_user = Feature.enabled?(:incubation_5mp_google_cloud, context.current_user)
enabled_for_group = Feature.enabled?(:incubation_5mp_google_cloud, context.project.group)
@@ -86,13 +112,16 @@ module Sidebars
feature_is_enabled = enabled_for_user || enabled_for_group || enabled_for_project
user_has_permissions = can?(context.current_user, :admin_project_google_cloud, context.project)
- unless feature_is_enabled && user_has_permissions
+ google_oauth2_configured = google_oauth2_configured?
+
+ unless feature_is_enabled && user_has_permissions && google_oauth2_configured
return ::Sidebars::NilMenuItem.new(item_id: :incubation_5mp_google_cloud)
end
::Sidebars::MenuItem.new(
title: _('Google Cloud'),
link: project_google_cloud_configuration_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: %w[
projects/google_cloud/configuration
projects/google_cloud/service_accounts
@@ -103,6 +132,11 @@ module Sidebars
item_id: :google_cloud
)
end
+
+ def google_oauth2_configured?
+ config = Gitlab::Auth::OAuth::Provider.config_for('google_oauth2')
+ config&.present? && config.app_id.present? && config.app_secret.present?
+ end
end
end
end
diff --git a/lib/sidebars/projects/menus/invite_team_members_menu.rb b/lib/sidebars/projects/menus/invite_team_members_menu.rb
deleted file mode 100644
index 0db49f1e12a..00000000000
--- a/lib/sidebars/projects/menus/invite_team_members_menu.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module Sidebars
- module Projects
- module Menus
- class InviteTeamMembersMenu < ::Sidebars::Menu
- override :title
- def title
- s_('InviteMember|Invite members')
- end
-
- override :render?
- def render?
- can?(context.current_user, :admin_project_member, context.project) && all_valid_members.size <= 1
- end
-
- override :menu_partial
- def menu_partial
- 'projects/invite_members_side_nav_link'
- end
-
- override :menu_partial_options
- def menu_partial_options
- {
- project: context.project,
- title: title,
- sidebar_menu: self
- }
- end
-
- override :extra_nav_link_html_options
- def extra_nav_link_html_options
- {
- 'data-test-id': 'side-nav-invite-members'
- }
- end
-
- private
-
- def all_valid_members
- MembersFinder.new(context.project, context.current_user)
- .execute(include_relations: [:inherited, :direct, :invited_groups])
- end
- end
- end
- end
-end
diff --git a/lib/sidebars/projects/menus/issues_menu.rb b/lib/sidebars/projects/menus/issues_menu.rb
index 51eea3d850d..6904dc129b7 100644
--- a/lib/sidebars/projects/menus/issues_menu.rb
+++ b/lib/sidebars/projects/menus/issues_menu.rb
@@ -68,6 +68,17 @@ module Sidebars
}
end
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.merge({
+ sprite_icon: sprite_icon,
+ pill_count: pill_count,
+ has_pill: has_pill?,
+ super_sidebar_parent: ::Sidebars::StaticMenu,
+ item_id: :project_issue_list
+ })
+ end
+
private
def show_issues_menu_items?
@@ -78,6 +89,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('List'),
link: project_issues_path(context.project),
+ super_sidebar_parent: ::Sidebars::NilMenuItem,
active_routes: { path: 'projects/issues#index' },
container_html_options: { aria: { label: _('Issues') } },
item_id: :issue_list
@@ -90,6 +102,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: title,
link: project_boards_path(context.project),
+ super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu,
active_routes: { controller: :boards },
item_id: :boards
)
@@ -99,6 +112,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Service Desk'),
link: service_desk_project_issues_path(context.project),
+ super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu,
active_routes: { path: 'issues#service_desk' },
item_id: :service_desk
)
@@ -108,6 +122,8 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Milestones'),
link: project_milestones_path(context.project),
+ super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu,
+ super_sidebar_before: :service_desk,
active_routes: { controller: :milestones },
item_id: :milestones
)
diff --git a/lib/sidebars/projects/menus/merge_requests_menu.rb b/lib/sidebars/projects/menus/merge_requests_menu.rb
index 3e543872d36..cc7fda0c920 100644
--- a/lib/sidebars/projects/menus/merge_requests_menu.rb
+++ b/lib/sidebars/projects/menus/merge_requests_menu.rb
@@ -64,6 +64,17 @@ module Sidebars
{ controller: ['projects/merge_requests', :milestones] }
end
end
+
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.merge({
+ sprite_icon: sprite_icon,
+ pill_count: pill_count,
+ has_pill: has_pill?,
+ super_sidebar_parent: ::Sidebars::StaticMenu,
+ item_id: :project_merge_request_list
+ })
+ end
end
end
end
diff --git a/lib/sidebars/projects/menus/monitor_menu.rb b/lib/sidebars/projects/menus/monitor_menu.rb
index 7d1fa8b8fa7..333112e13b6 100644
--- a/lib/sidebars/projects/menus/monitor_menu.rb
+++ b/lib/sidebars/projects/menus/monitor_menu.rb
@@ -12,7 +12,6 @@ module Sidebars
add_item(error_tracking_menu_item)
add_item(alert_management_menu_item)
add_item(incidents_menu_item)
- add_item(airflow_dashboard_menu_item)
true
end
@@ -39,6 +38,11 @@ module Sidebars
{ controller: [:user, :gcp] }
end
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
+ end
+
private
def feature_enabled?
@@ -97,20 +101,6 @@ module Sidebars
item_id: :incidents
)
end
-
- def airflow_dashboard_menu_item
- unless can?(context.current_user, :read_airflow_dags, context.project) &&
- Feature.enabled?(:airflow_dags, context.project)
- return ::Sidebars::NilMenuItem.new(item_id: :airflow)
- end
-
- ::Sidebars::MenuItem.new(
- title: _('Airflow'),
- link: project_airflow_dags_path(context.project),
- active_routes: { path: 'airflow/dags#show' },
- item_id: :airflow_dags
- )
- end
end
end
end
diff --git a/lib/sidebars/projects/menus/packages_registries_menu.rb b/lib/sidebars/projects/menus/packages_registries_menu.rb
index fc7c564574a..d5b590a03aa 100644
--- a/lib/sidebars/projects/menus/packages_registries_menu.rb
+++ b/lib/sidebars/projects/menus/packages_registries_menu.rb
@@ -23,6 +23,11 @@ module Sidebars
'package'
end
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ nil
+ end
+
private
def packages_registry_menu_item
@@ -33,6 +38,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Package Registry'),
link: project_packages_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: :packages },
item_id: :packages_registry,
container_html_options: { class: 'shortcuts-container-registry' }
@@ -47,6 +53,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Container Registry'),
link: project_container_registry_index_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: 'projects/registry/repositories' },
item_id: :container_registry
)
@@ -60,6 +67,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Infrastructure Registry'),
link: project_infrastructure_registry_index_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: :infrastructure_registry },
item_id: :infrastructure_registry
)
@@ -75,6 +83,7 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Harbor Registry'),
link: project_harbor_repositories_path(context.project),
+ super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
active_routes: { controller: :harbor_registry },
item_id: :harbor_registry
)
diff --git a/lib/sidebars/projects/menus/project_information_menu.rb b/lib/sidebars/projects/menus/project_information_menu.rb
index 44b94ee3522..020de2ff65f 100644
--- a/lib/sidebars/projects/menus/project_information_menu.rb
+++ b/lib/sidebars/projects/menus/project_information_menu.rb
@@ -33,12 +33,18 @@ module Sidebars
'project'
end
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ nil
+ end
+
private
def activity_menu_item
::Sidebars::MenuItem.new(
title: _('Activity'),
link: activity_project_path(context.project),
+ super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu,
active_routes: { path: 'projects#activity' },
item_id: :activity,
container_html_options: { class: 'shortcuts-project-activity' }
@@ -53,6 +59,8 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Labels'),
link: project_labels_path(context.project),
+ super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu,
+ super_sidebar_before: :activity,
active_routes: { controller: :labels },
item_id: :labels
)
@@ -66,6 +74,8 @@ module Sidebars
::Sidebars::MenuItem.new(
title: _('Members'),
link: project_project_members_path(context.project),
+ super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu,
+ super_sidebar_before: :labels,
active_routes: { controller: :project_members },
item_id: :members,
container_html_options: {
diff --git a/lib/sidebars/projects/menus/repository_menu.rb b/lib/sidebars/projects/menus/repository_menu.rb
index ec91ae741fe..158a29f0b31 100644
--- a/lib/sidebars/projects/menus/repository_menu.rb
+++ b/lib/sidebars/projects/menus/repository_menu.rb
@@ -44,6 +44,11 @@ module Sidebars
'doc-text'
end
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
+ end
+
private
def files_menu_item
@@ -92,7 +97,7 @@ module Sidebars
link = project_graph_path(context.project, context.current_ref, ref_type: ref_type_from_context(context))
::Sidebars::MenuItem.new(
- title: _('Contributors'),
+ title: _('Contributor statistics'),
link: link,
active_routes: { path: 'graphs#show' },
item_id: :contributors
@@ -112,7 +117,7 @@ module Sidebars
def compare_menu_item
::Sidebars::MenuItem.new(
- title: _('Compare'),
+ title: _('Compare revisions'),
link: project_compare_index_path(context.project, from: context.project.repository.root_ref, to: context.current_ref),
active_routes: { controller: :compare },
item_id: :compare
diff --git a/lib/sidebars/projects/menus/scope_menu.rb b/lib/sidebars/projects/menus/scope_menu.rb
index 35502c7ea09..7e2286633e5 100644
--- a/lib/sidebars/projects/menus/scope_menu.rb
+++ b/lib/sidebars/projects/menus/scope_menu.rb
@@ -39,6 +39,16 @@ module Sidebars
def render?
true
end
+
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.merge({
+ title: _('Project overview'),
+ sprite_icon: 'project',
+ super_sidebar_parent: ::Sidebars::StaticMenu,
+ item_id: :project_overview
+ })
+ end
end
end
end
diff --git a/lib/sidebars/projects/menus/security_compliance_menu.rb b/lib/sidebars/projects/menus/security_compliance_menu.rb
index 9367514cdca..eb713244a7c 100644
--- a/lib/sidebars/projects/menus/security_compliance_menu.rb
+++ b/lib/sidebars/projects/menus/security_compliance_menu.rb
@@ -17,7 +17,7 @@ module Sidebars
override :title
def title
- _('Security & Compliance')
+ _('Security and Compliance')
end
override :sprite_icon
@@ -25,6 +25,11 @@ module Sidebars
'shield'
end
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
+ end
+
private
def configuration_menu_item
@@ -33,7 +38,7 @@ module Sidebars
end
::Sidebars::MenuItem.new(
- title: _('Configuration'),
+ title: _('Security configuration'),
link: project_security_configuration_path(context.project),
active_routes: { path: configuration_menu_item_paths },
item_id: :configuration
diff --git a/lib/sidebars/projects/menus/settings_menu.rb b/lib/sidebars/projects/menus/settings_menu.rb
index eea32d8b626..8b6d85e718d 100644
--- a/lib/sidebars/projects/menus/settings_menu.rb
+++ b/lib/sidebars/projects/menus/settings_menu.rb
@@ -44,6 +44,11 @@ module Sidebars
'settings'
end
+ override :pick_into_super_sidebar?
+ def pick_into_super_sidebar?
+ true
+ end
+
private
def general_menu_item
diff --git a/lib/sidebars/projects/menus/snippets_menu.rb b/lib/sidebars/projects/menus/snippets_menu.rb
index 060341b3c51..535f12963b1 100644
--- a/lib/sidebars/projects/menus/snippets_menu.rb
+++ b/lib/sidebars/projects/menus/snippets_menu.rb
@@ -35,6 +35,15 @@ module Sidebars
def active_routes
{ controller: :snippets }
end
+
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.deep_merge({
+ super_sidebar_parent: ::Sidebars::Projects::Menus::RepositoryMenu,
+ super_sidebar_before: :contributors,
+ item_id: :project_snippets
+ })
+ end
end
end
end
diff --git a/lib/sidebars/projects/menus/wiki_menu.rb b/lib/sidebars/projects/menus/wiki_menu.rb
index 3980b193fd1..d800dae8be3 100644
--- a/lib/sidebars/projects/menus/wiki_menu.rb
+++ b/lib/sidebars/projects/menus/wiki_menu.rb
@@ -35,6 +35,14 @@ module Sidebars
def active_routes
{ controller: :wikis }
end
+
+ override :serialize_as_menu_item_args
+ def serialize_as_menu_item_args
+ super.merge({
+ super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu,
+ item_id: :project_wiki
+ })
+ end
end
end
end
diff --git a/lib/sidebars/projects/panel.rb b/lib/sidebars/projects/panel.rb
index 9d0f5eb87bd..5d8bc18ac88 100644
--- a/lib/sidebars/projects/panel.rb
+++ b/lib/sidebars/projects/panel.rb
@@ -34,14 +34,6 @@ module Sidebars
add_wiki_menus
add_menu(Sidebars::Projects::Menus::SnippetsMenu.new(context))
add_menu(Sidebars::Projects::Menus::SettingsMenu.new(context))
- add_invite_members_menu
- end
-
- def add_invite_members_menu
- experiment(:invite_members_in_side_nav, group: context.project.group) do |e|
- e.control {}
- e.candidate { add_menu(Sidebars::Projects::Menus::InviteTeamMembersMenu.new(context)) }
- end
end
def add_wiki_menus
diff --git a/lib/sidebars/projects/super_sidebar_menus/operations_menu.rb b/lib/sidebars/projects/super_sidebar_menus/operations_menu.rb
new file mode 100644
index 00000000000..5490aac5a65
--- /dev/null
+++ b/lib/sidebars/projects/super_sidebar_menus/operations_menu.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module SuperSidebarMenus
+ class OperationsMenu < ::Sidebars::Menu
+ override :title
+ def title
+ _('Operations')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'deployments'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/super_sidebar_menus/plan_menu.rb b/lib/sidebars/projects/super_sidebar_menus/plan_menu.rb
new file mode 100644
index 00000000000..ae9b2d826b7
--- /dev/null
+++ b/lib/sidebars/projects/super_sidebar_menus/plan_menu.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module SuperSidebarMenus
+ class PlanMenu < ::Sidebars::Menu
+ override :title
+ def title
+ _('Plan')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'planning'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/super_sidebar_panel.rb b/lib/sidebars/projects/super_sidebar_panel.rb
new file mode 100644
index 00000000000..f76f28eb642
--- /dev/null
+++ b/lib/sidebars/projects/super_sidebar_panel.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ class SuperSidebarPanel < ::Sidebars::Projects::Panel
+ include ::Sidebars::Concerns::SuperSidebarPanel
+ extend ::Gitlab::Utils::Override
+
+ override :configure_menus
+ def configure_menus
+ super
+ old_menus = @menus
+ @menus = []
+
+ add_menu(Sidebars::StaticMenu.new(context))
+ add_menu(Sidebars::Projects::SuperSidebarMenus::PlanMenu.new(context))
+
+ pick_from_old_menus(old_menus)
+
+ insert_menu_before(
+ Sidebars::Projects::Menus::MonitorMenu,
+ Sidebars::Projects::SuperSidebarMenus::OperationsMenu.new(context)
+ )
+
+ insert_menu_before(
+ Sidebars::Projects::Menus::SettingsMenu,
+ Sidebars::UncategorizedMenu.new(context)
+ )
+
+ transform_old_menus(@menus, @scope_menu, *old_menus)
+ end
+
+ override :super_sidebar_context_header
+ def super_sidebar_context_header
+ {
+ title: context.project.name,
+ avatar: context.project.avatar_url,
+ id: context.project.id
+ }
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/static_menu.rb b/lib/sidebars/static_menu.rb
new file mode 100644
index 00000000000..b7ba69b1717
--- /dev/null
+++ b/lib/sidebars/static_menu.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Sidebars
+ # This is a special menu which does not serialize as
+ # a section and instead hoists all of menu items
+ # to be top-level items
+ class StaticMenu < ::Sidebars::Menu
+ override :serialize_for_super_sidebar
+ def serialize_for_super_sidebar
+ serialize_items_for_super_sidebar
+ end
+ end
+end
diff --git a/lib/sidebars/uncategorized_menu.rb b/lib/sidebars/uncategorized_menu.rb
new file mode 100644
index 00000000000..dc9ed8308fa
--- /dev/null
+++ b/lib/sidebars/uncategorized_menu.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Sidebars
+ # This Menu is a temporary help while we implement the new menu
+ # categories for everything. Once every Menu Item is categorized,
+ # we can remove this. This should be done before the Super Sidebar
+ # moves out of Alpha.
+ class UncategorizedMenu < ::Sidebars::Menu
+ override :title
+ def title
+ _('Uncategorized')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'question'
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/base_menu.rb b/lib/sidebars/user_profile/base_menu.rb
new file mode 100644
index 00000000000..5594d7c3c65
--- /dev/null
+++ b/lib/sidebars/user_profile/base_menu.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ class BaseMenu < ::Sidebars::Menu
+ override :render?
+ def render?
+ can?(context.current_user, :read_user_profile, context.container)
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/activity_menu.rb b/lib/sidebars/user_profile/menus/activity_menu.rb
new file mode 100644
index 00000000000..95e99a3dcbc
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/activity_menu.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class ActivityMenu < ::Sidebars::UserProfile::BaseMenu
+ override :link
+ def link
+ user_activity_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Activity')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#activity' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/contributed_projects_menu.rb b/lib/sidebars/user_profile/menus/contributed_projects_menu.rb
new file mode 100644
index 00000000000..0644982a143
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/contributed_projects_menu.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class ContributedProjectsMenu < ::Sidebars::UserProfile::BaseMenu
+ override :link
+ def link
+ user_contributed_projects_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Contributed projects')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#contributed' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/followers_menu.rb b/lib/sidebars/user_profile/menus/followers_menu.rb
new file mode 100644
index 00000000000..53411c21a86
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/followers_menu.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class FollowersMenu < ::Sidebars::UserProfile::BaseMenu
+ include Gitlab::Utils::StrongMemoize
+
+ override :link
+ def link
+ user_followers_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Followers')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#followers' }
+ end
+
+ override :has_pill?
+ def has_pill?
+ context.container.followers.any?
+ end
+ strong_memoize_attr :has_pill?
+
+ override :pill_count
+ def pill_count
+ context.container.followers.count
+ end
+ strong_memoize_attr :pill_count
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/following_menu.rb b/lib/sidebars/user_profile/menus/following_menu.rb
new file mode 100644
index 00000000000..5da76a0100a
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/following_menu.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class FollowingMenu < ::Sidebars::UserProfile::BaseMenu
+ include Gitlab::Utils::StrongMemoize
+
+ override :link
+ def link
+ user_following_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Following')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#following' }
+ end
+
+ override :has_pill?
+ def has_pill?
+ context.container.followees.any?
+ end
+ strong_memoize_attr :has_pill?
+
+ override :pill_count
+ def pill_count
+ context.container.followees.count
+ end
+ strong_memoize_attr :pill_count
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/groups_menu.rb b/lib/sidebars/user_profile/menus/groups_menu.rb
new file mode 100644
index 00000000000..38c2c3f042d
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/groups_menu.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class GroupsMenu < ::Sidebars::UserProfile::BaseMenu
+ override :link
+ def link
+ user_groups_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Groups')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#groups' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/overview_menu.rb b/lib/sidebars/user_profile/menus/overview_menu.rb
new file mode 100644
index 00000000000..ebf184e7e4e
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/overview_menu.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class OverviewMenu < ::Sidebars::UserProfile::BaseMenu
+ override :link
+ def link
+ user_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Overview')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#show' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/personal_projects_menu.rb b/lib/sidebars/user_profile/menus/personal_projects_menu.rb
new file mode 100644
index 00000000000..14fcddf2cc2
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/personal_projects_menu.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class PersonalProjectsMenu < ::Sidebars::UserProfile::BaseMenu
+ override :link
+ def link
+ user_projects_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Personal projects')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#projects' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/snippets_menu.rb b/lib/sidebars/user_profile/menus/snippets_menu.rb
new file mode 100644
index 00000000000..a8e5077098c
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/snippets_menu.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class SnippetsMenu < ::Sidebars::UserProfile::BaseMenu
+ override :link
+ def link
+ user_snippets_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Snippets')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#snippets' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/menus/starred_projects_menu.rb b/lib/sidebars/user_profile/menus/starred_projects_menu.rb
new file mode 100644
index 00000000000..762b451f4a1
--- /dev/null
+++ b/lib/sidebars/user_profile/menus/starred_projects_menu.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ module Menus
+ class StarredProjectsMenu < ::Sidebars::UserProfile::BaseMenu
+ override :link
+ def link
+ user_starred_projects_path(context.container)
+ end
+
+ override :title
+ def title
+ s_('UserProfile|Starred projects')
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'users#starred' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_profile/panel.rb b/lib/sidebars/user_profile/panel.rb
new file mode 100644
index 00000000000..9a595fdf64c
--- /dev/null
+++ b/lib/sidebars/user_profile/panel.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserProfile
+ class Panel < ::Sidebars::Panel
+ include UsersHelper
+
+ override :configure_menus
+ def configure_menus
+ add_menus
+ end
+
+ override :aria_label
+ def aria_label
+ s_('UserProfile|User profile navigation')
+ end
+
+ 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'
+ }
+ 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))
+ add_menu(Sidebars::UserProfile::Menus::GroupsMenu.new(context))
+ add_menu(Sidebars::UserProfile::Menus::ContributedProjectsMenu.new(context))
+ add_menu(Sidebars::UserProfile::Menus::PersonalProjectsMenu.new(context))
+ add_menu(Sidebars::UserProfile::Menus::StarredProjectsMenu.new(context))
+ add_menu(Sidebars::UserProfile::Menus::SnippetsMenu.new(context))
+ add_menu(Sidebars::UserProfile::Menus::FollowersMenu.new(context))
+ add_menu(Sidebars::UserProfile::Menus::FollowingMenu.new(context))
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/access_tokens_menu.rb b/lib/sidebars/user_settings/menus/access_tokens_menu.rb
new file mode 100644
index 00000000000..f52be22e044
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/access_tokens_menu.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class AccessTokensMenu < ::Sidebars::Menu
+ override :link
+ def link
+ profile_personal_access_tokens_path
+ end
+
+ override :title
+ def title
+ _('Access Tokens')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'token'
+ end
+
+ override :render?
+ def render?
+ !!context.current_user && !Gitlab::CurrentSettings.personal_access_tokens_disabled?
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :personal_access_tokens }
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ { 'data-qa-selector': 'access_token_link' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/account_menu.rb b/lib/sidebars/user_settings/menus/account_menu.rb
new file mode 100644
index 00000000000..a26dee83da3
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/account_menu.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class AccountMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_account_path
+ end
+
+ override :title
+ def title
+ _('Account')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'account'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: [:accounts, :two_factor_auths] }
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ { 'data-qa-selector': 'profile_account_link' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/active_sessions_menu.rb b/lib/sidebars/user_settings/menus/active_sessions_menu.rb
new file mode 100644
index 00000000000..f806c04e77c
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/active_sessions_menu.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class ActiveSessionsMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_active_sessions_path
+ end
+
+ override :title
+ def title
+ _('Active Sessions')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'monitor-lines'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :active_sessions }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/applications_menu.rb b/lib/sidebars/user_settings/menus/applications_menu.rb
new file mode 100644
index 00000000000..c71f9a9660b
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/applications_menu.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class ApplicationsMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ applications_profile_path
+ end
+
+ override :title
+ def title
+ _('Applications')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'applications'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: 'oauth/applications' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/authentication_log_menu.rb b/lib/sidebars/user_settings/menus/authentication_log_menu.rb
new file mode 100644
index 00000000000..c5a27acf1fd
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/authentication_log_menu.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class AuthenticationLogMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ audit_log_profile_path
+ end
+
+ override :title
+ def title
+ _('Authentication Log')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'log'
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'profiles#audit_log' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/chat_menu.rb b/lib/sidebars/user_settings/menus/chat_menu.rb
new file mode 100644
index 00000000000..54795c29b3f
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/chat_menu.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class ChatMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_chat_names_path
+ end
+
+ override :title
+ def title
+ _('Chat')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'comment'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :chat_names }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/emails_menu.rb b/lib/sidebars/user_settings/menus/emails_menu.rb
new file mode 100644
index 00000000000..3b6b4ae1daf
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/emails_menu.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class EmailsMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_emails_path
+ end
+
+ override :title
+ def title
+ _('Emails')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'mail'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :emails }
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ { 'data-qa-selector': 'profile_emails_link' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/gpg_keys_menu.rb b/lib/sidebars/user_settings/menus/gpg_keys_menu.rb
new file mode 100644
index 00000000000..89e447aa277
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/gpg_keys_menu.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class GpgKeysMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_gpg_keys_path
+ end
+
+ override :title
+ def title
+ _('GPG Keys')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'key'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :gpg_keys }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/notifications_menu.rb b/lib/sidebars/user_settings/menus/notifications_menu.rb
new file mode 100644
index 00000000000..f7ea0de0cc9
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/notifications_menu.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class NotificationsMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_notifications_path
+ end
+
+ override :title
+ def title
+ _('Notifications')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'notifications'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :notifications }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/password_menu.rb b/lib/sidebars/user_settings/menus/password_menu.rb
new file mode 100644
index 00000000000..9a53e0c727e
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/password_menu.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class PasswordMenu < ::Sidebars::Menu
+ override :link
+ def link
+ edit_profile_password_path
+ end
+
+ override :title
+ def title
+ _('Password')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'lock'
+ end
+
+ override :render?
+ def render?
+ !!context.current_user&.allow_password_authentication?
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :passwords }
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ { 'data-qa-selector': 'profile_password_link' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/preferences_menu.rb b/lib/sidebars/user_settings/menus/preferences_menu.rb
new file mode 100644
index 00000000000..b6b94ec1ad9
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/preferences_menu.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class PreferencesMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_preferences_path
+ end
+
+ override :title
+ def title
+ _('Preferences')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'preferences'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :preferences }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/profile_menu.rb b/lib/sidebars/user_settings/menus/profile_menu.rb
new file mode 100644
index 00000000000..73119070586
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/profile_menu.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class ProfileMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_path
+ end
+
+ override :title
+ def title
+ _('Profile')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'profile'
+ end
+
+ override :active_routes
+ def active_routes
+ { path: 'profiles#show' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/saved_replies_menu.rb b/lib/sidebars/user_settings/menus/saved_replies_menu.rb
new file mode 100644
index 00000000000..25c8b2f8eb2
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/saved_replies_menu.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class SavedRepliesMenu < ::Sidebars::Menu
+ include UsersHelper
+
+ override :link
+ def link
+ profile_saved_replies_path
+ end
+
+ override :title
+ def title
+ _('Saved Replies')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'symlink'
+ end
+
+ override :render?
+ def render?
+ !!context.current_user && saved_replies_enabled?
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :saved_replies }
+ end
+
+ private
+
+ def current_user
+ context.current_user
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/menus/ssh_keys_menu.rb b/lib/sidebars/user_settings/menus/ssh_keys_menu.rb
new file mode 100644
index 00000000000..8d92db0147a
--- /dev/null
+++ b/lib/sidebars/user_settings/menus/ssh_keys_menu.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ module Menus
+ class SshKeysMenu < ::Sidebars::Menu
+ include ::Sidebars::Concerns::RenderIfLoggedIn
+
+ override :link
+ def link
+ profile_keys_path
+ end
+
+ override :title
+ def title
+ _('SSH Keys')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'key'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :keys }
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ { 'data-qa-selector': 'ssh_keys_link' }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/user_settings/panel.rb b/lib/sidebars/user_settings/panel.rb
new file mode 100644
index 00000000000..14a52a8fb23
--- /dev/null
+++ b/lib/sidebars/user_settings/panel.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module UserSettings
+ class Panel < ::Sidebars::Panel
+ override :configure_menus
+ def configure_menus
+ add_menus
+ end
+
+ override :aria_label
+ def aria_label
+ _('User settings')
+ end
+
+ override :render_raw_scope_menu_partial
+ def render_raw_scope_menu_partial
+ "shared/nav/user_settings_scope_header"
+ end
+
+ override :super_sidebar_context_header
+ def super_sidebar_context_header
+ @super_sidebar_context_header ||= {
+ title: aria_label,
+ avatar: context.current_user.avatar_url
+ }
+ end
+
+ private
+
+ def add_menus
+ add_menu(Sidebars::UserSettings::Menus::ProfileMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::AccountMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::ApplicationsMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::ChatMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::AccessTokensMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::EmailsMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::PasswordMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::NotificationsMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::SshKeysMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::GpgKeysMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::PreferencesMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::SavedRepliesMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::ActiveSessionsMenu.new(context))
+ add_menu(Sidebars::UserSettings::Menus::AuthenticationLogMenu.new(context))
+ end
+ end
+ end
+end
+
+Sidebars::UserSettings::Panel.prepend_mod_with('Sidebars::UserSettings::Panel')
diff --git a/lib/sidebars/your_work/panel.rb b/lib/sidebars/your_work/panel.rb
index 215a2a2da09..5f917976872 100644
--- a/lib/sidebars/your_work/panel.rb
+++ b/lib/sidebars/your_work/panel.rb
@@ -18,6 +18,14 @@ module Sidebars
"shared/nav/your_work_scope_header"
end
+ override :super_sidebar_context_header
+ def super_sidebar_context_header
+ @super_sidebar_context_header ||= {
+ title: aria_label,
+ icon: 'work'
+ }
+ end
+
private
def add_menus
@@ -33,3 +41,4 @@ module Sidebars
end
end
end
+Sidebars::YourWork::Panel.prepend_mod_with('Sidebars::YourWork::Panel')
diff --git a/lib/support/nginx/gitlab-pages-ssl b/lib/support/nginx/gitlab-pages-ssl
index 900d91e0575..a883d151a96 100644
--- a/lib/support/nginx/gitlab-pages-ssl
+++ b/lib/support/nginx/gitlab-pages-ssl
@@ -38,8 +38,10 @@ server {
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
- ssl_protocols TLSv1.2 TLSv1.3;
- 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;
+ # These settings are in line with the modern settings from https://ssl-config.mozilla.org/
+ # and are supported by all still-supported browsers since 2019. If you have specific needs
+ # for older settings, please consult the intermediate settings there.
+ ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
## See app/controllers/application_controller.rb for headers set
@@ -53,11 +55,6 @@ server {
# ssl_stapling_verify on;
# ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt;
- ## [Optional] Generate a stronger DHE parameter:
- ## sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
- ##
- # ssl_dhparam /etc/ssl/certs/dhparam.pem;
-
## [Optional] Enable HTTP Strict Transport Security
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 435b9055929..23d504736e6 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -97,8 +97,10 @@ server {
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
- ssl_protocols TLSv1.2 TLSv1.3;
- 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;
+ # These settings are in line with the modern settings from https://ssl-config.mozilla.org/
+ # and are supported by all still-supported browsers since 2019. If you have specific needs
+ # for older settings, please consult the intermediate settings there.
+ ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
## See app/controllers/application_controller.rb for headers set
@@ -114,11 +116,6 @@ server {
# resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired
# resolver_timeout 5s;
- ## [Optional] Generate a stronger DHE parameter:
- ## sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
- ##
- # ssl_dhparam /etc/ssl/certs/dhparam.pem;
-
## [Optional] Enable HTTP Strict Transport Security
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
diff --git a/lib/support/nginx/registry-ssl b/lib/support/nginx/registry-ssl
index be16037629b..50ecb855e24 100644
--- a/lib/support/nginx/registry-ssl
+++ b/lib/support/nginx/registry-ssl
@@ -34,15 +34,12 @@ server {
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
- ssl_protocols TLSv1.2 TLSv1.3;
- 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;
+ # These settings are in line with the modern settings from https://ssl-config.mozilla.org/
+ # and are supported by all still-supported browsers since 2019. If you have specific needs
+ # for older settings, please consult the intermediate settings there.
+ ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
- ## [Optional] Generate a stronger DHE parameter:
- ## sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
- ##
- # ssl_dhparam /etc/ssl/certs/dhparam.pem;
-
## [Optional] Enable HTTP Strict Transport Security
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
diff --git a/lib/tasks/contracts/merge_requests.rake b/lib/tasks/contracts/merge_requests.rake
index 5a6186d393d..049e4e41092 100644
--- a/lib/tasks/contracts/merge_requests.rake
+++ b/lib/tasks/contracts/merge_requests.rake
@@ -38,7 +38,7 @@ namespace :contracts do
end
desc 'Run all merge request contract tests'
- task 'test:merge_requests', :contract_merge_requests do |_t, arg|
+ task 'test:merge_requests', :contract_merge_requests do |_t|
errors = %w[get_diffs_batch get_diffs_metadata get_discussions].each_with_object([]) do |task, err|
Rake::Task["contracts:merge_requests:pact:verify:#{task}"].execute
rescue StandardError, SystemExit
diff --git a/lib/tasks/contracts/pipeline_schedules.rake b/lib/tasks/contracts/pipeline_schedules.rake
index f3e65b94940..2733ad41de6 100644
--- a/lib/tasks/contracts/pipeline_schedules.rake
+++ b/lib/tasks/contracts/pipeline_schedules.rake
@@ -20,7 +20,7 @@ namespace :contracts do
end
desc 'Run all pipeline schedule contract tests'
- task 'test:pipeline_schedules', :contract_pipeline_schedules do |_t, arg|
+ task 'test:pipeline_schedules', :contract_pipeline_schedules do |_t|
errors = %w[
update_pipeline_schedule
].each_with_object([]) do |task, err|
diff --git a/lib/tasks/contracts/pipelines.rake b/lib/tasks/contracts/pipelines.rake
index 13c973f1358..08e0a8b0319 100644
--- a/lib/tasks/contracts/pipelines.rake
+++ b/lib/tasks/contracts/pipelines.rake
@@ -47,7 +47,7 @@ namespace :contracts do
end
desc 'Run all pipeline contract tests'
- task 'test:pipelines', :contract_pipelines do |_t, arg|
+ task 'test:pipelines', :contract_pipelines do |_t|
errors = %w[
create_a_new_pipeline
get_list_project_pipelines
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
index d8c0b1007e6..8eae36008fd 100644
--- a/lib/tasks/gitlab/assets.rake
+++ b/lib/tasks/gitlab/assets.rake
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require 'fileutils'
-
module Tasks
module Gitlab
module Assets
@@ -78,6 +76,8 @@ namespace :gitlab do
desc 'GitLab | Assets | Compile all frontend assets'
task :compile do
+ require 'fileutils'
+
require_dependency 'gitlab/task_helpers'
puts "Assets SHA256 for `master`: #{Tasks::Gitlab::Assets.master_assets_sha256.inspect}"
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index c4dc7b938cc..72fe190bc8f 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -131,7 +131,7 @@ namespace :gitlab do
end
end
- desc 'This adjusts and cleans db/structure.sql - it runs after db:structure:dump'
+ desc 'This adjusts and cleans db/structure.sql - it runs after db:schema:dump'
task :clean_structure_sql do |task_name|
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
structure_file = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.name)
@@ -147,26 +147,13 @@ namespace :gitlab do
Rake::Task[task_name].reenable
end
- # Inform Rake that custom tasks should be run every time rake db:structure:dump is run
- #
- # Rails 6.1 deprecates db:structure:dump in favor of db:schema:dump
- Rake::Task['db:structure:dump'].enhance do
- Rake::Task['gitlab:db:clean_structure_sql'].invoke
- end
-
# Inform Rake that custom tasks should be run every time rake db:schema:dump is run
Rake::Task['db:schema:dump'].enhance do
Rake::Task['gitlab:db:clean_structure_sql'].invoke
end
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
- # Inform Rake that custom tasks should be run every time rake db:structure:dump is run
- #
- # Rails 6.1 deprecates db:structure:dump in favor of db:schema:dump
- Rake::Task["db:structure:dump:#{name}"].enhance do
- Rake::Task['gitlab:db:clean_structure_sql'].invoke
- end
-
+ # Inform Rake that custom tasks should be run every time rake db:schema:dump is run
Rake::Task["db:schema:dump:#{name}"].enhance do
Rake::Task['gitlab:db:clean_structure_sql'].invoke
end
@@ -313,6 +300,36 @@ namespace :gitlab do
end
end
+ namespace :validate_async_constraints do
+ each_database(databases) do |database_name|
+ task database_name, [:pick] => :environment do |_, args|
+ args.with_defaults(pick: 2)
+
+ if Feature.disabled?(:database_async_foreign_key_validation, type: :ops)
+ puts <<~NOTE.color(:yellow)
+ Note: database async foreign key validation feature is currently disabled.
+
+ Enable with: Feature.enable(:database_async_foreign_key_validation)
+ NOTE
+ exit
+ end
+
+ Gitlab::Database::EachDatabase.each_database_connection(only: database_name) do
+ Gitlab::Database::AsyncConstraints.validate_pending_entries!(how_many: args[:pick].to_i)
+ end
+ end
+ end
+
+ task :all, [:pick] => :environment do |_, args|
+ default_pick = Gitlab.dev_or_test_env? ? 1000 : 2
+ args.with_defaults(pick: default_pick)
+
+ each_database(databases) do |database_name|
+ Rake::Task["gitlab:db:validate_async_constraints:#{database_name}"].invoke(args[:pick])
+ end
+ end
+ end
+
desc 'Check if there have been user additions to the database'
task active: :environment do
if ActiveRecord::Base.connection.migration_context.needs_migration?
@@ -433,13 +450,15 @@ namespace :gitlab do
desc 'Generate database docs yaml'
task generate: :environment do
+ next if Gitlab.jh?
+
FileUtils.mkdir_p(DB_DOCS_PATH)
FileUtils.mkdir_p(EE_DICTIONARY_PATH) if Gitlab.ee?
Rails.application.eager_load!
version = Gem::Version.new(File.read('VERSION'))
- milestone = version.release.segments[0..1].join('.')
+ milestone = version.release.segments.first(2).join('.')
classes = {}
@@ -459,6 +478,7 @@ namespace :gitlab do
.reject(&:abstract_class)
.reject { |c| c.name =~ /^(?:EE::)?Gitlab::(?:BackgroundMigration|DatabaseImporters)::/ }
.reject { |c| c.name =~ /^HABTM_/ }
+ .reject { |c| c < Gitlab::Database::Migration[1.0]::MigrationRecord }
.each { |c| classes[c.table_name] << c.name if classes.has_key?(c.table_name) }
sources.each do |source_name|
@@ -488,7 +508,7 @@ namespace :gitlab do
end
if existing_metadata['classes'] && existing_metadata['classes'].sort != table_metadata['classes'].sort
- existing_metadata['classes'] = table_metadata['classes']
+ existing_metadata['classes'] = (existing_metadata['classes'] + table_metadata['classes']).uniq.sort
outdated = true
end
diff --git a/lib/tasks/gitlab/db/decomposition/connection_status.rake b/lib/tasks/gitlab/db/decomposition/connection_status.rake
new file mode 100644
index 00000000000..a7230126158
--- /dev/null
+++ b/lib/tasks/gitlab/db/decomposition/connection_status.rake
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+namespace :gitlab do
+ namespace :db do
+ namespace :decomposition do
+ desc 'Check if PostgreSQL max_connections needs to be increased'
+ task connection_status: :environment do
+ if Gitlab::Database.database_base_models.has_key?(:ci)
+ puts "GitLab database already running on two connections"
+ next
+ end
+
+ sql = <<~SQL
+ select q1.active, q2.max from
+ (select count(*) as active from pg_stat_activity) q1,
+ (select setting::int as max from pg_settings where name='max_connections') q2
+ SQL
+
+ active, max = ApplicationRecord.connection.select_one(sql).values
+
+ puts "Currently using #{active} connections out of #{max} max_connections,"
+
+ if active / max.to_f > 0.5
+ puts <<~ADVISE_INCREASE
+ which may run out when you switch to two database connections.
+
+ Consider increasing PostgreSQL 'max_connections' setting.
+ Depending on the installation method, there are different ways to
+ increase that setting. Please consult the GitLab documentation.
+ ADVISE_INCREASE
+ else
+ puts "which is enough for running GitLab using two database connections."
+ end
+ end
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/docs/redirect.rake b/lib/tasks/gitlab/docs/redirect.rake
index 2d234fcdb36..35e0d083210 100644
--- a/lib/tasks/gitlab/docs/redirect.rake
+++ b/lib/tasks/gitlab/docs/redirect.rake
@@ -1,12 +1,13 @@
# frozen_string_literal: true
-require 'date'
-require 'pathname'
-require "yaml"
#
# https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page
#
namespace :gitlab do
+ require 'date'
+ require 'pathname'
+ require 'yaml'
+
namespace :docs do
desc 'GitLab | Docs | Create a doc redirect'
task :redirect, [:old_path, :new_path] do |_, args|
diff --git a/lib/tasks/gitlab/graphql.rake b/lib/tasks/gitlab/graphql.rake
index a05b749a60e..ed12b93d311 100644
--- a/lib/tasks/gitlab/graphql.rake
+++ b/lib/tasks/gitlab/graphql.rake
@@ -2,10 +2,10 @@
return if Rails.env.production?
-require 'graphql/rake_task'
-require_relative '../../../tooling/graphql/docs/renderer'
-
namespace :gitlab do
+ require 'graphql/rake_task'
+ require_relative '../../../tooling/graphql/docs/renderer'
+
OUTPUT_DIR = Rails.root.join("doc/api/graphql/reference")
TEMP_SCHEMA_DIR = Rails.root.join('tmp/tests/graphql')
TEMPLATES_DIR = 'tooling/graphql/docs/templates/'
@@ -86,8 +86,10 @@ namespace :gitlab do
else
warn("#{'OK'.color(:green)} #{defn.file}") if errs.empty?
errs.each do |err|
+ path_info = "(at #{err.path.join('.')})" if err.path
+
warn(<<~MSG)
- #{'ERROR'.color(:red)} #{defn.file}: #{err.message} (at #{err.path.join('.')})
+ #{'ERROR'.color(:red)} #{defn.file}: #{err.message} #{path_info}
MSG
end
end
diff --git a/lib/tasks/gitlab/import_export/import.rake b/lib/tasks/gitlab/import_export/import.rake
index fc727eda380..2c219717535 100644
--- a/lib/tasks/gitlab/import_export/import.rake
+++ b/lib/tasks/gitlab/import_export/import.rake
@@ -30,10 +30,12 @@ namespace :gitlab do
end
task = Gitlab::ImportExport::Project::ImportTask.new(
- namespace_path: args.namespace_path,
- project_path: args.project_path,
- username: args.username,
- file_path: args.archive_path,
+ {
+ namespace_path: args.namespace_path,
+ project_path: args.project_path,
+ username: args.username,
+ file_path: args.archive_path
+ },
logger: logger
)
diff --git a/lib/tasks/gitlab/lfs/migrate.rake b/lib/tasks/gitlab/lfs/migrate.rake
index 47f9e1dfb32..19de45dca17 100644
--- a/lib/tasks/gitlab/lfs/migrate.rake
+++ b/lib/tasks/gitlab/lfs/migrate.rake
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-require 'logger'
-
desc "GitLab | LFS | Migrate LFS objects to remote storage"
namespace :gitlab do
+ require 'logger'
+
namespace :lfs do
task migrate: :environment do
logger = Logger.new($stdout)
diff --git a/lib/tasks/gitlab/metrics_exporter.rake b/lib/tasks/gitlab/metrics_exporter.rake
index d9dd80b8eeb..70719648fc5 100644
--- a/lib/tasks/gitlab/metrics_exporter.rake
+++ b/lib/tasks/gitlab/metrics_exporter.rake
@@ -1,8 +1,9 @@
# frozen_string_literal: true
-require_relative Rails.root.join('metrics_server', 'dependencies')
-require_relative Rails.root.join('metrics_server', 'metrics_server')
namespace :gitlab do
+ require_relative Rails.root.join('metrics_server', 'dependencies')
+ require_relative Rails.root.join('metrics_server', 'metrics_server')
+
namespace :metrics_exporter do
REPO = 'https://gitlab.com/gitlab-org/gitlab-metrics-exporter.git'
diff --git a/lib/tasks/gitlab/openapi.rake b/lib/tasks/gitlab/openapi.rake
index dee365de11c..c9aec6a112a 100644
--- a/lib/tasks/gitlab/openapi.rake
+++ b/lib/tasks/gitlab/openapi.rake
@@ -1,13 +1,13 @@
# frozen_string_literal: true
-require 'logger'
-
if Rails.env.development?
require 'grape-swagger/rake/oapi_tasks'
GrapeSwagger::Rake::OapiTasks.new('::API::API')
end
namespace :gitlab do
+ require 'logger'
+
namespace :openapi do
task :validate do
raise 'This task can only be run in the development environment' unless Rails.env.development?
diff --git a/lib/tasks/gitlab/packages/events.rake b/lib/tasks/gitlab/packages/events.rake
index a5b801ff62d..9a9eeb6977d 100644
--- a/lib/tasks/gitlab/packages/events.rake
+++ b/lib/tasks/gitlab/packages/events.rake
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require 'logger'
-
desc "GitLab | Packages | Events | Generate hll counter events file for packages"
namespace :gitlab do
namespace :packages do
@@ -49,9 +47,7 @@ namespace :gitlab do
events_definition = Packages::Event.unique_counters_for(event_scope, event_type, originator_type).map do |event_name|
{
"name" => event_name,
- "category" => "#{originator_type}_packages",
- "aggregation" => "weekly",
- "redis_slot" => "package"
+ "aggregation" => "weekly"
}
end
diff --git a/lib/tasks/gitlab/packages/migrate.rake b/lib/tasks/gitlab/packages/migrate.rake
index 1c28f4308a2..737788583ae 100644
--- a/lib/tasks/gitlab/packages/migrate.rake
+++ b/lib/tasks/gitlab/packages/migrate.rake
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require 'logger'
-
desc "GitLab | Packages | Migrate packages files to remote storage"
namespace :gitlab do
namespace :packages do
task migrate: :environment do
+ require 'logger'
+
logger = Logger.new($stdout)
logger.info('Starting transfer of package files to object storage')
diff --git a/lib/tasks/gitlab/pages.rake b/lib/tasks/gitlab/pages.rake
index e6fde28e38f..ecfb163f284 100644
--- a/lib/tasks/gitlab/pages.rake
+++ b/lib/tasks/gitlab/pages.rake
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require 'logger'
-
namespace :gitlab do
namespace :pages do
namespace :deployments do
task migrate_to_object_storage: :gitlab_environment do
+ require 'logger'
+
logger = Logger.new($stdout)
helper = Gitlab::LocalAndRemoteStorageMigration::PagesDeploymentMigrater.new(logger)
diff --git a/lib/tasks/gitlab/refresh_project_statistics_build_artifacts_size.rake b/lib/tasks/gitlab/refresh_project_statistics_build_artifacts_size.rake
index 203d500b616..ca23bd31961 100644
--- a/lib/tasks/gitlab/refresh_project_statistics_build_artifacts_size.rake
+++ b/lib/tasks/gitlab/refresh_project_statistics_build_artifacts_size.rake
@@ -1,14 +1,14 @@
# frozen_string_literal: true
-require 'httparty'
-require 'csv'
-
namespace :gitlab do
desc "GitLab | Refresh build artifacts size project statistics for given list of Project IDs from remote CSV"
BUILD_ARTIFACTS_SIZE_REFRESH_ENQUEUE_BATCH_SIZE = 500
task :refresh_project_statistics_build_artifacts_size, [:csv_url] => :environment do |_t, args|
+ require 'httparty'
+ require 'csv'
+
csv_url = args.csv_url
# rubocop: disable Gitlab/HTTParty
diff --git a/lib/tasks/gitlab/seed/runner_fleet.rake b/lib/tasks/gitlab/seed/runner_fleet.rake
index c0b79269c75..784451226b7 100644
--- a/lib/tasks/gitlab/seed/runner_fleet.rake
+++ b/lib/tasks/gitlab/seed/runner_fleet.rake
@@ -28,10 +28,12 @@ namespace :gitlab do
runner_count: args.runner_count&.to_i
).seed
- Gitlab::Seeders::Ci::Runner::RunnerFleetPipelineSeeder.new(
- projects_to_runners: projects_to_runners,
- job_count: args.job_count&.to_i
- ).seed
+ if projects_to_runners
+ Gitlab::Seeders::Ci::Runner::RunnerFleetPipelineSeeder.new(
+ projects_to_runners: projects_to_runners,
+ job_count: args.job_count&.to_i
+ ).seed
+ end
end
puts "Seed finished. Timings: #{timings}"
diff --git a/lib/tasks/gitlab/terraform/migrate.rake b/lib/tasks/gitlab/terraform/migrate.rake
index 99e33011cf5..3347b823376 100644
--- a/lib/tasks/gitlab/terraform/migrate.rake
+++ b/lib/tasks/gitlab/terraform/migrate.rake
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require 'logger'
-
desc "GitLab | Terraform | Migrate Terraform states to remote storage"
namespace :gitlab do
namespace :terraform_states do
task migrate: :environment do
+ require 'logger'
+
logger = Logger.new($stdout)
logger.info('Starting transfer of Terraform states to object storage')
diff --git a/lib/tasks/gitlab/tw/codeowners.rake b/lib/tasks/gitlab/tw/codeowners.rake
index 77f5eb87725..2ff3dd668b7 100644
--- a/lib/tasks/gitlab/tw/codeowners.rake
+++ b/lib/tasks/gitlab/tw/codeowners.rake
@@ -1,10 +1,10 @@
# frozen_string_literal: true
-require 'yaml'
-
namespace :tw do
desc 'Generates a list of codeowners for documentation pages.'
task :codeowners do
+ require 'yaml'
+
CodeOwnerRule = Struct.new(:category, :writer)
DocumentOwnerMapping = Struct.new(:path, :writer) do
def writer_owns_directory?(mappings)
@@ -19,20 +19,22 @@ namespace :tw do
end
CODE_OWNER_RULES = [
- CodeOwnerRule.new('Activation', '@phillipwells'),
- CodeOwnerRule.new('Acquisition', '@phillipwells'),
+ # CodeOwnerRule.new('Activation', ''),
+ # CodeOwnerRule.new('Acquisition', ''),
+ # CodeOwnerRule.new('AI Assisted', ''),
CodeOwnerRule.new('Anti-Abuse', '@phillipwells'),
+ CodeOwnerRule.new('Application Performance', '@jglassman1'),
CodeOwnerRule.new('Authentication and Authorization', '@jglassman1'),
- CodeOwnerRule.new('Certify', '@msedlakjakubowski'),
+ # CodeOwnerRule.new('Billing and Subscription Management', ''),
CodeOwnerRule.new('Code Review', '@aqualls'),
CodeOwnerRule.new('Compliance', '@eread'),
- CodeOwnerRule.new('Commerce Integrations', '@drcatherinepope'),
CodeOwnerRule.new('Composition Analysis', '@rdickenson'),
CodeOwnerRule.new('Configure', '@phillipwells'),
- CodeOwnerRule.new('Container Registry', '@dianalogan'),
+ CodeOwnerRule.new('Container Registry', '@marcel.amirault'),
CodeOwnerRule.new('Contributor Experience', '@eread'),
- CodeOwnerRule.new('Conversion', '@kpaizee'),
CodeOwnerRule.new('Database', '@aqualls'),
+ # CodeOwnerRule.new('DataOps', ''),
+ # CodeOwnerRule.new('Delivery', ''),
CodeOwnerRule.new('Development', '@sselhorn'),
CodeOwnerRule.new('Distribution', '@axil'),
CodeOwnerRule.new('Distribution (Charts)', '@axil'),
@@ -40,46 +42,46 @@ namespace :tw do
CodeOwnerRule.new('Documentation Guidelines', '@sselhorn'),
CodeOwnerRule.new('Dynamic Analysis', '@rdickenson'),
CodeOwnerRule.new('Editor', '@ashrafkhamis'),
- CodeOwnerRule.new('Foundations', '@rdickenson'),
+ CodeOwnerRule.new('Foundations', '@sselhorn'),
+ # CodeOwnerRule.new('Fulfillment Platform', ''),
CodeOwnerRule.new('Fuzz Testing', '@rdickenson'),
CodeOwnerRule.new('Geo', '@axil'),
CodeOwnerRule.new('Gitaly', '@eread'),
+ CodeOwnerRule.new('GitLab Dedicated', '@drcatherinepope'),
CodeOwnerRule.new('Global Search', '@ashrafkhamis'),
CodeOwnerRule.new('Import', '@eread'),
CodeOwnerRule.new('Infrastructure', '@sselhorn'),
CodeOwnerRule.new('Integrations', '@ashrafkhamis'),
- CodeOwnerRule.new('Knowledge', '@aqualls'),
- CodeOwnerRule.new('Application Performance', '@jglassman1'),
- CodeOwnerRule.new('Monitor', '@msedlakjakubowski'),
+ # CodeOwnerRule.new('Knowledge', ''),
+ # CodeOwnerRule.new('MLOps', '')
CodeOwnerRule.new('Observability', '@drcatherinepope'),
CodeOwnerRule.new('Optimize', '@lciutacu'),
- CodeOwnerRule.new('Package Registry', '@dianalogan'),
+ CodeOwnerRule.new('Organization', '@lciutacu'),
+ CodeOwnerRule.new('Package Registry', '@marcel.amirault'),
CodeOwnerRule.new('Pipeline Authoring', '@marcel.amirault'),
CodeOwnerRule.new('Pipeline Execution', '@drcatherinepope'),
- CodeOwnerRule.new('Pipeline Insights', '@marcel.amirault'),
- CodeOwnerRule.new('Portfolio Management', '@msedlakjakubowski'),
+ CodeOwnerRule.new('Pipeline Security', '@marcel.amirault'),
CodeOwnerRule.new('Product Analytics', '@lciutacu'),
- CodeOwnerRule.new('Product Intelligence', '@dianalogan'),
+ CodeOwnerRule.new('Product Intelligence', '@lciutacu'),
CodeOwnerRule.new('Product Planning', '@msedlakjakubowski'),
CodeOwnerRule.new('Project Management', '@msedlakjakubowski'),
CodeOwnerRule.new('Provision', '@fneill'),
CodeOwnerRule.new('Purchase', '@fneill'),
CodeOwnerRule.new('Redirect', 'Redirect'),
- CodeOwnerRule.new('Release', '@rdickenson'),
CodeOwnerRule.new('Respond', '@msedlakjakubowski'),
CodeOwnerRule.new('Runner', '@fneill'),
CodeOwnerRule.new('Runner SaaS', '@fneill'),
- CodeOwnerRule.new('Pods', '@jglassman1'),
CodeOwnerRule.new('Security Policies', '@dianalogan'),
CodeOwnerRule.new('Source Code', '@aqualls'),
CodeOwnerRule.new('Static Analysis', '@rdickenson'),
CodeOwnerRule.new('Style Guide', '@sselhorn'),
+ CodeOwnerRule.new('Tenant Scale', '@lciutacu'),
CodeOwnerRule.new('Testing', '@eread'),
- CodeOwnerRule.new('Threat Insights', '@dianalogan'),
+ CodeOwnerRule.new('Threat Insights', '@rdickenson'),
CodeOwnerRule.new('Tutorials', '@kpaizee'),
- CodeOwnerRule.new('Utilization', '@fneill'),
- CodeOwnerRule.new('Vulnerability Research', '@dianalogan'),
- CodeOwnerRule.new('Organization', '@lciutacu')
+ # CodeOwnerRule.new('US Public Sector Services', ''),
+ CodeOwnerRule.new('Utilization', '@fneill')
+ # CodeOwnerRule.new('Vulnerability Research', '')
].freeze
ERRORS_EXCLUDED_FILES = [
diff --git a/lib/tasks/gitlab/usage_data.rake b/lib/tasks/gitlab/usage_data.rake
index 32db5e2dff6..fcbec4b0dba 100644
--- a/lib/tasks/gitlab/usage_data.rake
+++ b/lib/tasks/gitlab/usage_data.rake
@@ -88,8 +88,6 @@ namespace :gitlab do
def ci_template_event(event_name)
{
'name' => event_name,
- 'category' => 'ci_templates',
- 'redis_slot' => Gitlab::UsageDataCounters::CiTemplateUniqueCounter::REDIS_SLOT,
'aggregation' => 'weekly'
}
end
diff --git a/lib/tasks/gitlab/x509/update.rake b/lib/tasks/gitlab/x509/update.rake
index 7b7d15479bf..dc868ede05d 100644
--- a/lib/tasks/gitlab/x509/update.rake
+++ b/lib/tasks/gitlab/x509/update.rake
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require 'logger'
-
desc "GitLab | X509 | Update signatures when certificate store has changed"
namespace :gitlab do
namespace :x509 do
task update_signatures: :environment do
+ require 'logger'
+
update_certificates
end
diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake
index d2056338350..54aee5ff9f5 100644
--- a/lib/tasks/import.rake
+++ b/lib/tasks/import.rake
@@ -1,8 +1,5 @@
# frozen_string_literal: true
-require 'benchmark'
-require 'rainbow/ext/string'
-
class GithubImport
def self.run!(...)
new(...).run!
@@ -124,6 +121,9 @@ class GithubRepos
end
namespace :import do
+ require 'benchmark'
+ require 'rainbow/ext/string'
+
desc 'GitLab | Import | Import a GitHub project - Example: import:github[ToKeN,root,root/blah,my/github_repo] (optional my/github_repo)'
task :github, [:token, :gitlab_username, :project_path] => :environment do |_t, args|
abort 'Project path must be: namespace(s)/project_name'.color(:red) unless args.project_path.include?('/')
diff --git a/locale/am_ET/gitlab.po b/locale/am_ET/gitlab.po
index eb667f2698e..d3f5b4c1de1 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 "%{actionText} እና %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr "%{count} ተዛማጅ %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr "የá•áˆ®áŒ€áŠ­á‰± fork áˆáŠ•áŒ­ á‹á‰…ተኛ እይታ ስላለዠ%{
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} merge ማድረጠይቻላáˆ"
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po
index 01bca599814..499fdad3af4 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-02-11 04:19\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -706,6 +706,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -769,6 +778,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
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] ""
@@ -778,6 +796,12 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -994,6 +1018,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1195,6 +1222,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1210,9 +1240,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1354,6 +1381,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1666,6 +1696,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1996,15 +2029,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -2365,9 +2389,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2782,9 +2803,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2806,6 +2824,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2815,6 +2836,9 @@ 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 ""
@@ -2929,6 +2953,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -3067,6 +3094,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -4246,40 +4276,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4651,6 +4651,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -5287,6 +5290,9 @@ 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 ""
@@ -5296,6 +5302,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5374,13 +5497,28 @@ 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|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."
+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."
@@ -5533,12 +5671,18 @@ 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 ""
@@ -5803,6 +5947,15 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5815,6 +5968,24 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5890,9 +6061,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5905,6 +6073,9 @@ 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 ""
@@ -6268,7 +6439,7 @@ msgstr[5] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6526,9 +6697,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6541,9 +6709,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6553,9 +6718,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6937,6 +7111,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6964,9 +7141,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -7036,6 +7210,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -7051,9 +7228,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -7189,27 +7363,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -7219,9 +7375,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7366,6 +7519,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7600,15 +7756,27 @@ msgstr[5] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7621,9 +7789,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7741,9 +7906,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7762,6 +7924,15 @@ 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 ""
@@ -7792,10 +7963,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7837,6 +8011,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8608,6 +8785,15 @@ 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 ""
@@ -8725,6 +8911,9 @@ 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 ""
@@ -9115,6 +9304,9 @@ 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 ""
@@ -9157,6 +9349,9 @@ 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 ""
@@ -9166,16 +9361,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -9202,6 +9394,9 @@ 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 ""
@@ -9220,6 +9415,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -9238,6 +9436,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9358,12 +9559,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9442,10 +9649,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9475,6 +9682,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -10264,6 +10474,9 @@ 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 ""
@@ -10555,7 +10768,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10951,9 +11164,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10966,6 +11176,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -11035,12 +11248,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11149,9 +11371,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -11170,9 +11407,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11806,6 +12040,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11848,12 +12085,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11869,6 +12115,9 @@ 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 ""
@@ -11914,7 +12163,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11935,7 +12187,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -12007,6 +12259,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -12253,7 +12508,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12442,6 +12697,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12691,9 +12949,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12901,6 +13156,9 @@ 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 ""
@@ -13000,7 +13258,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -13171,9 +13429,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -14089,6 +14344,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -14131,6 +14389,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14914,6 +15175,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -15019,10 +15283,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -15127,6 +15394,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -15322,6 +15592,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15487,9 +15760,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15931,6 +16201,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15955,6 +16228,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15973,9 +16249,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16432,6 +16714,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16477,7 +16762,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16495,6 +16780,9 @@ 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 ""
@@ -16789,6 +17077,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16900,6 +17191,9 @@ 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 ""
@@ -17188,6 +17482,9 @@ 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 ""
@@ -17470,6 +17767,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17494,6 +17794,9 @@ 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 ""
@@ -17695,6 +17998,9 @@ 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 ""
@@ -17713,6 +18019,9 @@ 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 ""
@@ -18295,9 +18604,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18421,6 +18727,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18577,9 +18886,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18721,9 +19027,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19546,13 +19849,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19603,6 +19915,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19627,6 +19942,12 @@ 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 ""
@@ -19642,9 +19963,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19693,15 +20011,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19795,12 +20104,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19840,6 +20155,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19852,13 +20170,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19876,7 +20194,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19930,6 +20248,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -20002,6 +20323,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -20056,15 +20380,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -20281,6 +20599,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20470,6 +20812,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20821,6 +21166,9 @@ 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 ""
@@ -21079,6 +21427,9 @@ 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 ""
@@ -21094,6 +21445,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21478,6 +21835,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21829,6 +22189,9 @@ 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 ""
@@ -21928,6 +22291,9 @@ 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 ""
@@ -21970,15 +22336,24 @@ 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 ""
@@ -22039,7 +22414,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -22273,6 +22648,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22681,7 +23059,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -23344,12 +23722,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23527,10 +23911,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23548,6 +23935,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23836,7 +24226,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23965,9 +24355,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -24241,6 +24628,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24466,6 +24859,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -25003,9 +25399,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25702,6 +26113,15 @@ 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 ""
@@ -25783,6 +26203,9 @@ 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 ""
@@ -25792,6 +26215,9 @@ 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 ""
@@ -25807,9 +26233,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25825,6 +26248,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -26098,6 +26524,15 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Line changes"
msgstr ""
@@ -26125,6 +26560,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -26218,9 +26656,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -26263,6 +26698,9 @@ 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 ""
@@ -26302,6 +26740,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -26320,9 +26761,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -26392,9 +26830,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26431,10 +26866,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26926,6 +27358,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -27007,12 +27442,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -27241,18 +27685,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -27325,9 +27760,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -27340,6 +27772,27 @@ 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 ""
@@ -27958,6 +28411,9 @@ msgstr[5] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -28138,6 +28594,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -28150,6 +28612,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -28210,31 +28675,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28582,6 +29062,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28630,10 +29113,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28750,9 +29239,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28840,9 +29326,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -29197,6 +29680,15 @@ 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 ""
@@ -29284,13 +29776,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29608,12 +30103,24 @@ 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|%{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 ""
@@ -29662,9 +30169,18 @@ 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 ""
@@ -29692,9 +30208,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29731,6 +30244,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29740,6 +30256,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29752,6 +30271,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -30232,6 +30754,9 @@ 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 ""
@@ -30301,9 +30826,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30601,28 +31123,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -31435,6 +31963,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31624,9 +32155,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31825,6 +32353,9 @@ 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 ""
@@ -32050,6 +32581,9 @@ 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 ""
@@ -32101,9 +32635,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -32149,6 +32680,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -32200,7 +32737,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -32209,6 +32746,9 @@ 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|Revoke trigger"
msgstr ""
@@ -32245,13 +32785,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -32281,6 +32821,12 @@ 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 ""
@@ -32302,6 +32848,9 @@ 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 ""
@@ -32311,6 +32860,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32626,6 +33178,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32647,6 +33202,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32707,7 +33265,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -33061,6 +33619,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -33130,88 +33691,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -33220,34 +33724,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -33256,24 +33763,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -33286,22 +33787,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -33310,70 +33820,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User activity"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33541,6 +34054,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33790,7 +34309,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33964,6 +34483,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33976,6 +34498,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -34003,6 +34528,9 @@ 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 ""
@@ -34099,9 +34627,21 @@ 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 ""
@@ -34114,6 +34654,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -34156,7 +34699,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -34171,9 +34717,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -34303,9 +34846,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34456,9 +34996,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34501,9 +35038,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34540,9 +35074,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34585,10 +35116,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34612,9 +35143,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34849,6 +35377,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34975,6 +35506,9 @@ 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 ""
@@ -34990,6 +35524,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -35170,9 +35707,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -35281,12 +35815,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35458,9 +35986,33 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35470,10 +36022,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35482,15 +36046,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35500,6 +36073,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35956,24 +36532,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -36049,6 +36616,9 @@ 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] ""
@@ -36088,13 +36658,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -36187,6 +36757,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -37150,15 +37723,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -37345,9 +37924,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37525,9 +38101,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37618,6 +38191,9 @@ 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|Administrator"
msgstr ""
@@ -37681,6 +38257,9 @@ 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 ""
@@ -37699,6 +38278,9 @@ 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 ""
@@ -37759,9 +38341,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37774,6 +38362,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37792,6 +38386,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37819,6 +38416,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37828,6 +38431,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37840,6 +38446,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37882,6 +38491,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37918,6 +38530,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37933,6 +38551,9 @@ 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 ""
@@ -37957,6 +38578,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37972,6 +38596,12 @@ 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 ""
@@ -38044,9 +38674,15 @@ 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 ""
@@ -38080,6 +38716,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -38089,6 +38731,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -38110,6 +38755,9 @@ msgstr[5] ""
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 runner has not run any jobs."
msgstr ""
@@ -38158,6 +38806,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -38212,15 +38863,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -38242,6 +38884,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -38266,9 +38911,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -38398,16 +39040,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -38449,9 +39094,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38944,22 +39595,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
msgstr ""
-msgid "Security dashboard"
+msgid "Security configuration"
msgstr ""
-msgid "Security navigation"
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -39088,7 +39742,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -39202,6 +39856,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -39307,9 +39964,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -39400,6 +40066,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -39421,6 +40090,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -39430,6 +40102,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -39496,7 +40171,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39574,6 +40249,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -40051,6 +40729,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -40153,6 +40834,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -40165,6 +40849,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -40177,6 +40864,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -40279,6 +40969,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -40414,6 +41110,9 @@ 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 ""
@@ -40441,7 +41140,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40696,6 +41395,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40864,9 +41566,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -41020,15 +41719,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -41038,6 +41755,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -41047,6 +41767,9 @@ 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 ""
@@ -41080,9 +41803,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -41266,12 +41995,18 @@ 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 ""
@@ -41683,9 +42418,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41749,6 +42481,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41998,6 +42733,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42643,16 +43381,22 @@ 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|Sync subscription request."
+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}."
@@ -42661,7 +43405,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42694,9 +43438,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42739,9 +43480,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42892,9 +43630,27 @@ 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 ""
@@ -43309,10 +44065,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -43342,9 +44098,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -43471,6 +44224,9 @@ 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 ""
@@ -43534,6 +44290,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43576,9 +44335,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -43636,6 +44392,9 @@ 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 ""
@@ -43957,7 +44716,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -44302,6 +45070,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -44491,13 +45262,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44998,6 +45763,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -45052,10 +45820,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -45514,6 +46279,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -46009,6 +46777,9 @@ 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 ""
@@ -46102,9 +46873,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -46207,9 +46975,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -46255,12 +47020,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -46366,6 +47125,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -46465,6 +47227,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -46522,6 +47287,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46609,6 +47383,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46678,6 +47455,9 @@ 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 ""
@@ -46804,6 +47584,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46975,6 +47758,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -47179,6 +47965,9 @@ 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 ""
@@ -47191,6 +47980,9 @@ 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 ""
@@ -47269,6 +48061,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47695,6 +48490,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47806,6 +48604,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47950,6 +48751,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47983,9 +48787,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -48196,6 +48997,69 @@ 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|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 ""
@@ -48586,12 +49450,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48643,9 +49501,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48787,6 +49642,9 @@ 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 ""
@@ -49054,6 +49912,15 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
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] ""
@@ -49096,6 +49963,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -49315,7 +50185,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -49363,6 +50233,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -49390,6 +50263,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -49414,9 +50296,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -49537,6 +50425,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49573,6 +50464,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49603,6 +50497,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -50008,9 +50905,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -50185,12 +51079,18 @@ 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 ""
@@ -50365,6 +51265,9 @@ 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 ""
@@ -50374,7 +51277,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -50404,6 +51307,9 @@ 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 ""
@@ -50428,6 +51334,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -50473,6 +51382,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -50482,9 +51394,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -50515,6 +51424,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50680,6 +51592,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50929,6 +51844,9 @@ 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 ""
@@ -51283,9 +52201,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -51355,6 +52270,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -51385,6 +52303,9 @@ 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 ""
@@ -51682,9 +52603,6 @@ msgstr[5] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -52006,10 +52924,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -52075,6 +52999,84 @@ 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|%{mergeError}."
msgstr ""
@@ -52090,6 +53092,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -52117,12 +53125,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -52138,6 +53140,9 @@ 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 ""
@@ -52225,82 +53230,28 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -52363,9 +53314,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -52390,6 +53338,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/as_IN/gitlab.po b/locale/as_IN/gitlab.po
index 65fd8ac7b0c..31ddc20cf3d 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/az_AZ/gitlab.po b/locale/az_AZ/gitlab.po
index a92f874997d..36165dcff3c 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ba_RU/gitlab.po b/locale/ba_RU/gitlab.po
index 7c0a3066fb2..26ea4f17732 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -539,6 +553,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -740,6 +757,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -755,9 +775,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -889,6 +906,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1675,9 +1694,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2092,9 +2108,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2116,6 +2129,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2125,6 +2141,9 @@ 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 ""
@@ -2239,6 +2258,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2377,6 +2399,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3556,40 +3581,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3961,6 +3956,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4587,6 +4585,9 @@ 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 ""
@@ -4596,6 +4597,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4674,13 +4792,28 @@ 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|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."
+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."
@@ -4823,12 +4956,18 @@ 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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5080,6 +5223,14 @@ msgstr ""
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ 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 ""
@@ -5518,7 +5669,7 @@ msgstr[0] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5771,9 +5922,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5786,9 +5934,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5798,9 +5943,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6606,6 +6739,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -6846,9 +6994,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -6987,6 +7129,15 @@ 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 ""
@@ -7017,10 +7168,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7062,6 +7216,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7945,6 +8111,9 @@ 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 ""
@@ -8325,6 +8494,9 @@ 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 ""
@@ -8367,6 +8539,9 @@ 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 ""
@@ -8376,16 +8551,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8412,6 +8584,9 @@ 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 ""
@@ -8430,6 +8605,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8568,12 +8749,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,10 +8839,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10161,6 +10351,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10365,9 +10582,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ 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 ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11115,7 +11347,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11187,6 +11419,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11433,7 +11668,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,7 +12418,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13301,6 +13539,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,10 +14388,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15060,6 +15313,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15582,7 +15847,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 ""
@@ -16795,6 +17078,9 @@ 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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17662,9 +17951,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ 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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19121,15 +19430,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19535,6 +19862,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -19886,6 +20216,9 @@ 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 ""
@@ -20144,6 +20477,9 @@ 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 ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -20874,6 +21219,9 @@ 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 ""
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ 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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21308,6 +21668,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22374,12 +22737,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23261,6 +23633,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23486,6 +23864,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ 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 ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ 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 ""
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25372,9 +25790,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 ""
@@ -26918,6 +27351,9 @@ msgstr[0] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27098,6 +27534,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27110,6 +27552,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28533,12 +29008,24 @@ 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|%{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 ""
@@ -28587,9 +29074,18 @@ 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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29152,6 +29654,9 @@ 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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30330,6 +30838,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30720,6 +31228,9 @@ 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 ""
@@ -30945,6 +31456,9 @@ 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 ""
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 ""
@@ -31197,6 +31723,9 @@ 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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,7 +32140,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -32898,6 +33403,9 @@ 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 ""
@@ -32994,9 +33502,21 @@ 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 ""
@@ -33009,6 +33529,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,7 +33574,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33435,9 +33949,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -33870,6 +34381,9 @@ 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 ""
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34176,12 +34690,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34395,6 +34938,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] ""
@@ -34978,13 +35518,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36005,15 +36548,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr ""
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ 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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ 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 ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37042,6 +37654,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37689,22 +38310,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -37833,7 +38457,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -38796,6 +39444,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ 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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 ""
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41622,9 +42330,27 @@ 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 ""
@@ -42029,10 +42755,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42341,6 +43067,9 @@ 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 ""
@@ -42652,7 +43381,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -43747,10 +44485,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44199,6 +44934,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44684,6 +45422,9 @@ 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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -44877,9 +45615,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -44925,12 +45660,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ 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 ""
@@ -45474,6 +46224,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46360,6 +47125,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46643,9 +47417,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -46846,6 +47617,69 @@ 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|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 ""
@@ -47236,12 +48070,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -47955,7 +48790,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ 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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,7 +49862,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49024,6 +49892,9 @@ 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 ""
@@ -49048,6 +49919,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49102,9 +49979,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -49915,6 +50795,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50521,10 +51404,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,82 +51690,28 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index 391b8a27b4d..41befe3b71c 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-02-11 04:19\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s подаване беше пропуÑнато, за да не Ñе натоварва ÑиÑтемата."
msgstr[1] "%s Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð±Ñха пропуÑнати, за да не Ñе натоварва ÑиÑтемата."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr "ДобавÑне на нова папка"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr "протича в момента"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
-msgstr "Сътрудници"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr ""
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "ÐапуÑкане на групата"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr "Схема"
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/bn_BD/gitlab.po b/locale/bn_BD/gitlab.po
index 7e14cd41203..0556ca778e1 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/bn_IN/gitlab.po b/locale/bn_IN/gitlab.po
index d07dff413d9..64c797cbad3 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/br_FR/gitlab.po b/locale/br_FR/gitlab.po
index 9d1ec5bc095..df8f4fbcb51 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -636,6 +636,14 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -692,6 +700,14 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
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] ""
@@ -700,6 +716,12 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -903,6 +925,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1104,6 +1129,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1119,9 +1147,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1261,6 +1286,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1556,6 +1584,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1873,14 +1904,6 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -2227,9 +2250,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2644,9 +2664,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2668,6 +2685,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2677,6 +2697,9 @@ 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 ""
@@ -2791,6 +2814,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2929,6 +2955,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -4108,40 +4137,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4513,6 +4512,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -5147,6 +5149,9 @@ 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 ""
@@ -5156,6 +5161,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5234,13 +5356,28 @@ 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|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."
+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."
@@ -5391,12 +5528,18 @@ 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 ""
@@ -5656,6 +5799,14 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5668,6 +5819,22 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5743,9 +5910,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5758,6 +5922,9 @@ 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 ""
@@ -6118,7 +6285,7 @@ msgstr[4] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6375,9 +6542,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6390,9 +6554,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6402,9 +6563,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6786,6 +6956,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6813,9 +6986,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6885,6 +7055,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6900,9 +7073,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -7038,27 +7208,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -7068,9 +7220,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7214,6 +7363,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7445,15 +7597,27 @@ msgstr[4] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7466,9 +7630,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7586,9 +7747,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7607,6 +7765,15 @@ 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 ""
@@ -7637,10 +7804,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7682,6 +7852,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8452,6 +8625,15 @@ 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 ""
@@ -8569,6 +8751,9 @@ 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 ""
@@ -8957,6 +9142,9 @@ 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 ""
@@ -8999,6 +9187,9 @@ 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 ""
@@ -9008,16 +9199,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -9044,6 +9232,9 @@ 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 ""
@@ -9062,6 +9253,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -9080,6 +9274,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9200,12 +9397,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9284,10 +9487,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9317,6 +9520,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -10104,6 +10310,9 @@ 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 ""
@@ -10395,7 +10604,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10790,9 +10999,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10805,6 +11011,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10874,12 +11083,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10988,9 +11206,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -11009,9 +11242,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11642,6 +11872,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11684,12 +11917,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11705,6 +11947,9 @@ 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 ""
@@ -11750,7 +11995,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11771,7 +12019,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11843,6 +12091,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -12089,7 +12340,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12278,6 +12529,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12527,9 +12781,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12737,6 +12988,9 @@ 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 ""
@@ -12836,7 +13090,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -13006,9 +13260,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13923,6 +14174,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13965,6 +14219,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14740,6 +14997,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14844,10 +15104,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14952,6 +15215,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -15147,6 +15413,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15309,9 +15578,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15752,6 +16018,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15776,6 +16045,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15794,9 +16066,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16253,6 +16531,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16298,7 +16579,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16316,6 +16597,9 @@ 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 ""
@@ -16610,6 +16894,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16721,6 +17008,9 @@ 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 ""
@@ -17009,6 +17299,9 @@ 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 ""
@@ -17290,6 +17583,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17314,6 +17610,9 @@ 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 ""
@@ -17515,6 +17814,9 @@ 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 ""
@@ -17533,6 +17835,9 @@ 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 ""
@@ -18112,9 +18417,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18238,6 +18540,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18394,9 +18699,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18538,9 +18840,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19360,13 +19659,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19417,6 +19725,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19441,6 +19752,12 @@ 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 ""
@@ -19456,9 +19773,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19507,14 +19821,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19608,12 +19914,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19653,6 +19965,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19665,13 +19980,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19689,7 +20004,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19743,6 +20058,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19815,6 +20133,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19869,15 +20190,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -20094,6 +20409,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20283,6 +20622,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20634,6 +20976,9 @@ 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 ""
@@ -20892,6 +21237,9 @@ 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 ""
@@ -20907,6 +21255,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21289,6 +21643,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21638,6 +21995,9 @@ 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 ""
@@ -21737,6 +22097,9 @@ 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 ""
@@ -21779,15 +22142,24 @@ 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 ""
@@ -21848,7 +22220,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -22080,6 +22452,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22487,7 +22862,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -23150,12 +23525,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23332,10 +23713,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23353,6 +23737,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23641,7 +24028,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23770,9 +24157,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -24045,6 +24429,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24270,6 +24660,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24807,9 +25200,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25504,6 +25912,15 @@ 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 ""
@@ -25585,6 +26002,9 @@ 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 ""
@@ -25594,6 +26014,9 @@ 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 ""
@@ -25609,9 +26032,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25627,6 +26047,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25894,6 +26317,14 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "Line changes"
msgstr ""
@@ -25921,6 +26352,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -26014,9 +26448,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -26059,6 +26490,9 @@ 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 ""
@@ -26098,6 +26532,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -26116,9 +26553,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -26188,9 +26622,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26227,10 +26658,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26722,6 +27150,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26803,12 +27234,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -27035,18 +27475,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -27119,9 +27550,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -27134,6 +27562,27 @@ 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 ""
@@ -27750,6 +28199,9 @@ msgstr[4] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27930,6 +28382,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27942,6 +28400,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -28002,31 +28463,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
+msgstr ""
+
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28373,6 +28849,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28421,10 +28900,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28540,9 +29025,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28630,9 +29112,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28987,6 +29466,15 @@ 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 ""
@@ -29073,13 +29561,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29393,12 +29884,24 @@ 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|%{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 ""
@@ -29447,9 +29950,18 @@ 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 ""
@@ -29477,9 +29989,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29516,6 +30025,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29525,6 +30037,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29537,6 +30052,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -30016,6 +30534,9 @@ 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 ""
@@ -30085,9 +30606,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30384,28 +30902,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -31214,6 +31738,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31403,9 +31930,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31604,6 +32128,9 @@ 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 ""
@@ -31829,6 +32356,9 @@ 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 ""
@@ -31880,9 +32410,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31928,6 +32455,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31979,7 +32512,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31988,6 +32521,9 @@ 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|Revoke trigger"
msgstr ""
@@ -32024,13 +32560,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -32060,6 +32596,12 @@ 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 ""
@@ -32081,6 +32623,9 @@ 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 ""
@@ -32090,6 +32635,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32405,6 +32953,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32426,6 +32977,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32486,7 +33040,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32840,6 +33394,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32909,88 +33466,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32999,34 +33499,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -33035,24 +33538,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -33065,22 +33562,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -33089,70 +33595,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33320,6 +33829,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33569,7 +34084,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33743,6 +34258,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33755,6 +34273,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33782,6 +34303,9 @@ 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 ""
@@ -33878,9 +34402,21 @@ 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 ""
@@ -33893,6 +34429,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33935,7 +34474,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33950,9 +34492,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -34082,9 +34621,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34235,9 +34771,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34280,9 +34813,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34319,9 +34849,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34364,10 +34891,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34391,9 +34918,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34628,6 +35152,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34754,6 +35281,9 @@ 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 ""
@@ -34769,6 +35299,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34949,9 +35482,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -35060,12 +35590,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35237,9 +35761,31 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35249,10 +35795,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35261,15 +35819,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35279,6 +35846,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35735,24 +36305,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35828,6 +36389,9 @@ 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] ""
@@ -35866,13 +36430,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35965,6 +36529,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36921,15 +37488,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -37114,9 +37687,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37292,9 +37862,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37381,6 +37948,9 @@ 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|Administrator"
msgstr ""
@@ -37444,6 +38014,9 @@ 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 ""
@@ -37462,6 +38035,9 @@ 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 ""
@@ -37521,9 +38097,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37536,6 +38118,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37554,6 +38142,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37581,6 +38172,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37590,6 +38187,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37602,6 +38202,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37644,6 +38247,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37679,6 +38285,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37694,6 +38306,9 @@ 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 ""
@@ -37718,6 +38333,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37733,6 +38351,12 @@ 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 ""
@@ -37805,9 +38429,15 @@ 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 ""
@@ -37841,6 +38471,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37850,6 +38486,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37870,6 +38509,9 @@ msgstr[4] ""
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 runner has not run any jobs."
msgstr ""
@@ -37918,6 +38560,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37972,15 +38617,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -38002,6 +38638,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -38026,9 +38665,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -38158,16 +38794,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -38209,9 +38848,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38693,22 +39338,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38837,7 +39485,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38951,6 +39599,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -39056,9 +39707,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -39149,6 +39809,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -39170,6 +39833,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -39179,6 +39845,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -39245,7 +39914,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39323,6 +39992,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39800,6 +40472,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39902,6 +40577,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39914,6 +40592,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39926,6 +40607,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -40028,6 +40712,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -40163,6 +40853,9 @@ 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 ""
@@ -40190,7 +40883,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40444,6 +41137,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40611,9 +41307,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40767,15 +41460,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40785,6 +41496,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40794,6 +41508,9 @@ 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 ""
@@ -40827,9 +41544,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -41013,12 +41736,18 @@ 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 ""
@@ -41430,9 +42159,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41496,6 +42222,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41745,6 +42474,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42390,16 +43122,22 @@ 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|Sync subscription request."
+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}."
@@ -42408,7 +43146,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42440,9 +43178,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42485,9 +43220,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42638,9 +43370,27 @@ 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 ""
@@ -43053,10 +43803,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -43084,9 +43834,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -43213,6 +43960,9 @@ 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 ""
@@ -43275,6 +44025,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43317,9 +44070,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -43377,6 +44127,9 @@ 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 ""
@@ -43696,7 +44449,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -44041,6 +44803,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -44230,13 +44995,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44737,6 +45496,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44791,10 +45553,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -45251,6 +46010,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45744,6 +46506,9 @@ 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 ""
@@ -45836,9 +46601,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45941,9 +46703,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45989,12 +46748,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -46100,6 +46853,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -46199,6 +46955,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -46256,6 +47015,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46343,6 +47111,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46412,6 +47183,9 @@ 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 ""
@@ -46538,6 +47312,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46709,6 +47486,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46913,6 +47693,9 @@ 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 ""
@@ -46925,6 +47708,9 @@ 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 ""
@@ -47002,6 +47788,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47428,6 +48217,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47539,6 +48331,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47683,6 +48478,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47715,9 +48513,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47926,6 +48721,69 @@ 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|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 ""
@@ -48316,12 +49174,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48373,9 +49225,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48517,6 +49366,9 @@ 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 ""
@@ -48783,6 +49635,14 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
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] ""
@@ -48824,6 +49684,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -49043,7 +49906,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -49091,6 +49954,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -49117,6 +49983,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -49141,9 +50016,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -49264,6 +50145,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49300,6 +50184,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49330,6 +50217,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49734,9 +50624,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49910,12 +50797,18 @@ 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 ""
@@ -50089,6 +50982,9 @@ 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 ""
@@ -50098,7 +50994,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -50128,6 +51024,9 @@ 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 ""
@@ -50152,6 +51051,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -50197,6 +51099,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -50206,9 +51111,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -50239,6 +51141,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50402,6 +51307,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50648,6 +51556,9 @@ 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 ""
@@ -50996,9 +51907,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -51067,6 +51975,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -51097,6 +52008,9 @@ 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 ""
@@ -51389,9 +52303,6 @@ msgstr[4] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51709,10 +52620,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51776,6 +52693,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51791,6 +52786,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51818,12 +52819,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51839,6 +52834,9 @@ 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 ""
@@ -51924,82 +52922,28 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -52062,9 +53006,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -52089,6 +53030,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/bs_BA/gitlab.po b/locale/bs_BA/gitlab.po
index f42a91fa4f1..6dc3cc76188 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -496,6 +496,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -538,12 +544,24 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
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] ""
msgstr[2] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -721,6 +739,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -922,6 +943,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -937,9 +961,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1075,6 +1096,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1336,6 +1360,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1627,12 +1654,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1951,9 +1972,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2368,9 +2386,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2392,6 +2407,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2401,6 +2419,9 @@ 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 ""
@@ -2515,6 +2536,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2653,6 +2677,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3832,40 +3859,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4237,6 +4234,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4867,6 +4867,9 @@ 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 ""
@@ -4876,6 +4879,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4954,13 +5074,28 @@ 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|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."
+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."
@@ -5107,12 +5242,18 @@ 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 ""
@@ -5362,6 +5503,12 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5374,6 +5521,18 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+
+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] ""
+msgstr[2] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5449,9 +5608,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5464,6 +5620,9 @@ 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 ""
@@ -5818,7 +5977,7 @@ msgstr[2] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6073,9 +6232,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6088,9 +6244,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6100,9 +6253,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6484,6 +6646,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6511,9 +6676,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6583,6 +6745,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6598,9 +6763,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6736,27 +6898,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6766,9 +6910,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6910,6 +7051,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7135,15 +7279,27 @@ msgstr[2] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7156,9 +7312,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7276,9 +7429,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7297,6 +7447,15 @@ 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 ""
@@ -7327,10 +7486,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7372,6 +7534,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8140,6 +8305,15 @@ 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 ""
@@ -8257,6 +8431,9 @@ 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 ""
@@ -8641,6 +8818,9 @@ 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 ""
@@ -8683,6 +8863,9 @@ 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 ""
@@ -8692,16 +8875,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8728,6 +8908,9 @@ 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 ""
@@ -8746,6 +8929,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8764,6 +8950,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8884,12 +9073,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8968,10 +9163,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9001,6 +9196,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9784,6 +9982,9 @@ 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 ""
@@ -10075,7 +10276,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10468,9 +10669,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10483,6 +10681,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10552,12 +10753,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10666,9 +10876,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10687,9 +10912,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11314,6 +11536,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11356,12 +11581,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11377,6 +11611,9 @@ 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 ""
@@ -11422,7 +11659,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11443,7 +11683,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11515,6 +11755,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11761,7 +12004,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11950,6 +12193,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12199,9 +12445,6 @@ msgstr "Kreirano:"
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12409,6 +12652,9 @@ 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 ""
@@ -12508,7 +12754,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12676,9 +12922,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13591,6 +13834,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13633,6 +13879,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14392,6 +14641,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14494,10 +14746,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14602,6 +14857,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14797,6 +15055,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14953,9 +15214,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15394,6 +15652,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15418,6 +15679,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15436,9 +15700,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15895,6 +16165,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15940,7 +16213,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15958,6 +16231,9 @@ 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 ""
@@ -16252,6 +16528,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16363,6 +16642,9 @@ 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 ""
@@ -16651,6 +16933,9 @@ 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 ""
@@ -16930,6 +17215,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16954,6 +17242,9 @@ 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 ""
@@ -17155,6 +17446,9 @@ 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 ""
@@ -17173,6 +17467,9 @@ 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 ""
@@ -17746,9 +18043,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17872,6 +18166,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18028,9 +18325,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18172,9 +18466,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18988,13 +19279,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19045,6 +19345,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19069,6 +19372,12 @@ 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 ""
@@ -19084,9 +19393,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19135,12 +19441,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19234,12 +19534,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19279,6 +19585,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19291,13 +19600,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19315,7 +19624,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19369,6 +19678,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19441,6 +19753,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19495,15 +19810,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19720,6 +20029,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19909,6 +20242,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20260,6 +20596,9 @@ 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 ""
@@ -20518,6 +20857,9 @@ 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 ""
@@ -20533,6 +20875,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20911,6 +21259,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21256,6 +21607,9 @@ 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 ""
@@ -21355,6 +21709,9 @@ 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 ""
@@ -21397,15 +21754,24 @@ 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 ""
@@ -21466,7 +21832,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21694,6 +22060,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22099,7 +22468,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22762,12 +23131,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22942,10 +23317,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22963,6 +23341,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23251,7 +23632,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23380,9 +23761,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23653,6 +24031,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr "Zadatak je već promoviran u epik."
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr "Zadatak nije pronađen."
@@ -23878,6 +24262,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24415,9 +24802,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25108,6 +25510,15 @@ 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 ""
@@ -25189,6 +25600,9 @@ 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 ""
@@ -25198,6 +25612,9 @@ 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 ""
@@ -25213,9 +25630,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25231,6 +25645,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25486,6 +25903,12 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Line changes"
msgstr ""
@@ -25513,6 +25936,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25606,9 +26032,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25651,6 +26074,9 @@ 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 ""
@@ -25690,6 +26116,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25708,9 +26137,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25780,9 +26206,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25819,10 +26242,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26314,6 +26734,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26395,12 +26818,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26623,18 +27055,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26707,9 +27130,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26722,6 +27142,27 @@ 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 ""
@@ -27334,6 +27775,9 @@ msgstr[2] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27514,6 +27958,12 @@ msgstr ""
msgid "Minutes"
msgstr "Minute"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27526,6 +27976,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27586,31 +28039,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27955,6 +28423,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28003,10 +28474,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28120,9 +28597,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28210,9 +28684,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28567,6 +29038,15 @@ 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 ""
@@ -28651,13 +29131,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28963,12 +29446,24 @@ 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|%{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 ""
@@ -29017,9 +29512,18 @@ 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 ""
@@ -29047,9 +29551,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29086,6 +29587,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29095,6 +29599,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29107,6 +29614,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29584,6 +30094,9 @@ 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 ""
@@ -29653,9 +30166,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29950,28 +30460,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30772,6 +31288,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30961,9 +31480,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31162,6 +31678,9 @@ 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 ""
@@ -31387,6 +31906,9 @@ 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 ""
@@ -31438,9 +31960,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31486,6 +32005,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31537,7 +32062,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31546,6 +32071,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31582,13 +32110,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31618,6 +32146,12 @@ 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 ""
@@ -31639,6 +32173,9 @@ 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 ""
@@ -31648,6 +32185,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31963,6 +32503,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31984,6 +32527,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32044,7 +32590,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32398,6 +32944,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32467,88 +33016,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32557,34 +33049,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32593,24 +33088,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32623,22 +33112,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Instrument your application"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32647,70 +33145,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32878,6 +33379,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33127,7 +33634,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33301,6 +33808,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33313,6 +33823,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33340,6 +33853,9 @@ 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 ""
@@ -33436,9 +33952,21 @@ 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 ""
@@ -33451,6 +33979,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33493,7 +34024,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33508,9 +34042,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33640,9 +34171,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33793,9 +34321,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33838,9 +34363,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33877,9 +34399,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33922,10 +34441,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33949,9 +34468,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34186,6 +34702,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34312,6 +34831,9 @@ 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 ""
@@ -34327,6 +34849,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34507,9 +35032,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34618,12 +35140,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34795,9 +35311,27 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34807,10 +35341,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34819,15 +35365,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34837,6 +35392,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35293,24 +35851,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35386,6 +35935,9 @@ 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] ""
@@ -35422,13 +35974,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35521,6 +36073,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36463,15 +37018,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36652,9 +37213,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36826,9 +37384,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36907,6 +37462,9 @@ 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|Administrator"
msgstr ""
@@ -36970,6 +37528,9 @@ 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 ""
@@ -36988,6 +37549,9 @@ 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 ""
@@ -37045,9 +37609,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37060,6 +37630,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37078,6 +37654,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37105,6 +37684,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37114,6 +37699,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37126,6 +37714,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37168,6 +37759,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37201,6 +37795,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37216,6 +37816,9 @@ 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 ""
@@ -37240,6 +37843,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37255,6 +37861,12 @@ 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 ""
@@ -37327,9 +37939,15 @@ 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 ""
@@ -37363,6 +37981,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37372,6 +37996,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37390,6 +38017,9 @@ msgstr[2] ""
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 runner has not run any jobs."
msgstr ""
@@ -37438,6 +38068,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37492,15 +38125,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37522,6 +38146,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37546,9 +38173,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37678,16 +38302,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37729,9 +38356,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38191,22 +38824,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38335,7 +38971,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38449,6 +39085,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38554,9 +39193,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38647,6 +39295,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38668,6 +39319,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38677,6 +39331,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38743,7 +39400,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38821,6 +39478,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39298,6 +39958,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39400,6 +40063,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39412,6 +40078,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39424,6 +40093,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39526,6 +40198,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39661,6 +40339,9 @@ 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 ""
@@ -39688,7 +40369,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39940,6 +40621,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40105,9 +40789,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40261,15 +40942,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40279,6 +40978,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40288,6 +40990,9 @@ 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 ""
@@ -40321,9 +41026,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40507,12 +41218,18 @@ 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 ""
@@ -40924,9 +41641,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40990,6 +41704,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41239,6 +41956,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41884,16 +42604,22 @@ 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|Sync subscription request."
+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}."
@@ -41902,7 +42628,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41932,9 +42658,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41977,9 +42700,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42130,9 +42850,27 @@ 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 ""
@@ -42541,10 +43279,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42568,9 +43306,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42697,6 +43432,9 @@ 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 ""
@@ -42757,6 +43495,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42799,9 +43540,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42859,6 +43597,9 @@ 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 ""
@@ -43174,7 +43915,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43519,6 +44269,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43708,13 +44461,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44215,6 +44962,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44269,10 +45019,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44725,6 +45472,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45214,6 +45964,9 @@ 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 ""
@@ -45304,9 +46057,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45409,9 +46159,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45457,12 +46204,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr "URL"
@@ -45568,6 +46309,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45667,6 +46411,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45724,6 +46471,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45811,6 +46567,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45880,6 +46639,9 @@ 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 ""
@@ -46006,6 +46768,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46177,6 +46942,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46381,6 +47149,9 @@ 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 ""
@@ -46393,6 +47164,9 @@ 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 ""
@@ -46468,6 +47242,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46894,6 +47671,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47005,6 +47785,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47149,6 +47932,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47179,9 +47965,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47386,6 +48169,69 @@ 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|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 ""
@@ -47776,12 +48622,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47833,9 +48673,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47977,6 +48814,9 @@ 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 ""
@@ -48241,6 +49081,12 @@ 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] ""
+msgstr[2] ""
+
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] ""
@@ -48280,6 +49126,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48499,7 +49348,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48547,6 +49396,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48571,6 +49423,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48595,9 +49456,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48718,6 +49585,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48754,6 +49624,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48784,6 +49657,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49186,9 +50062,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49360,12 +50233,18 @@ 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 ""
@@ -49537,6 +50416,9 @@ 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 ""
@@ -49546,7 +50428,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49576,6 +50458,9 @@ 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 ""
@@ -49600,6 +50485,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49645,6 +50533,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49654,9 +50545,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49687,6 +50575,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49846,6 +50737,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50086,6 +50980,9 @@ 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 ""
@@ -50422,9 +51319,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50491,6 +51385,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50521,6 +51418,9 @@ 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 ""
@@ -50803,9 +51703,6 @@ msgstr[2] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51115,10 +52012,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51178,6 +52081,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51193,6 +52174,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51220,12 +52207,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51241,6 +52222,9 @@ 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 ""
@@ -51322,82 +52306,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51460,9 +52390,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51487,6 +52414,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po
index 0c614d8c3bd..6b49694e57a 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-02-11 04:19\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr " Des de %{start} fins %{end}"
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grup"
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr "Afegeix una aplicació nova"
msgid "Add new directory"
msgstr "Afegeix un directori nou"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr "Text addicional"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr "Analítiques"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "Confidencialitat"
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr "feb."
msgid "February"
msgstr "febrer"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po
index df1a0179b7e..af35ab16b4b 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-02-11 04:19\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -566,6 +566,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -615,6 +622,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
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 další commit byl vynechán, aby se předešlo problémům s výkonem."
@@ -622,6 +636,12 @@ msgstr[1] "%s další commity byly vynechány, aby se předešlo problémům s v
msgstr[2] "%s dalších commitů bylo vynecháno, aby se předešlo problémům s výkonem."
msgstr[3] "%s dalších commitů bylo vynecháno, aby se předešlo problémům s výkonem."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -812,6 +832,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1013,6 +1036,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1028,9 +1054,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1168,6 +1191,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1446,6 +1472,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1750,13 +1779,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -2089,9 +2111,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2506,9 +2525,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2530,6 +2546,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2539,6 +2558,9 @@ 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 ""
@@ -2653,6 +2675,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2791,6 +2816,9 @@ msgstr ""
msgid "Additional text"
msgstr "DodateÄný text"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3970,40 +3998,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4375,6 +4373,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -5007,6 +5008,9 @@ 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 ""
@@ -5016,6 +5020,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5094,13 +5215,28 @@ 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|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."
+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."
@@ -5249,12 +5385,18 @@ 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 ""
@@ -5509,6 +5651,13 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5521,6 +5670,20 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5596,9 +5759,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5611,6 +5771,9 @@ 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 ""
@@ -5968,7 +6131,7 @@ msgstr[3] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6224,9 +6387,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6239,9 +6399,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6251,9 +6408,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6635,6 +6801,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6662,9 +6831,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6734,6 +6900,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6749,9 +6918,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6887,27 +7053,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6917,9 +7065,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7062,6 +7207,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7290,15 +7438,27 @@ msgstr[3] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7311,9 +7471,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7431,9 +7588,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7452,6 +7606,15 @@ 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 ""
@@ -7482,10 +7645,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7527,6 +7693,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8296,6 +8465,15 @@ 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 ""
@@ -8413,6 +8591,9 @@ 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 ""
@@ -8799,6 +8980,9 @@ 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 ""
@@ -8841,6 +9025,9 @@ 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 ""
@@ -8850,16 +9037,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8886,6 +9070,9 @@ 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 ""
@@ -8904,6 +9091,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8922,6 +9112,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9042,12 +9235,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9126,10 +9325,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9159,6 +9358,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9944,6 +10146,9 @@ 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 ""
@@ -10235,7 +10440,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10629,9 +10834,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10644,6 +10846,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10713,12 +10918,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10827,9 +11041,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10848,9 +11077,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11478,6 +11704,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11520,12 +11749,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11541,6 +11779,9 @@ 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 ""
@@ -11586,7 +11827,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11607,7 +11851,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11679,6 +11923,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11925,7 +12172,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12114,6 +12361,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12363,9 +12613,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12573,6 +12820,9 @@ 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 ""
@@ -12672,7 +12922,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12841,9 +13091,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13757,6 +14004,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13799,6 +14049,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14566,6 +14819,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14669,10 +14925,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14777,6 +15036,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14972,6 +15234,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15131,9 +15396,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15573,6 +15835,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15597,6 +15862,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15615,9 +15883,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16074,6 +16348,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16119,7 +16396,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16137,6 +16414,9 @@ 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 ""
@@ -16431,6 +16711,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16542,6 +16825,9 @@ 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 ""
@@ -16830,6 +17116,9 @@ 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 ""
@@ -17110,6 +17399,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17134,6 +17426,9 @@ 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 ""
@@ -17335,6 +17630,9 @@ 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 ""
@@ -17353,6 +17651,9 @@ 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 ""
@@ -17929,9 +18230,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18055,6 +18353,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18211,9 +18512,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18355,9 +18653,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19174,13 +19469,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19231,6 +19535,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19255,6 +19562,12 @@ 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 ""
@@ -19270,9 +19583,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19321,13 +19631,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19421,12 +19724,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19466,6 +19775,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19478,13 +19790,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19502,7 +19814,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19556,6 +19868,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19628,6 +19943,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19682,15 +20000,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19907,6 +20219,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20096,6 +20432,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20447,6 +20786,9 @@ 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 ""
@@ -20705,6 +21047,9 @@ 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 ""
@@ -20720,6 +21065,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21100,6 +21451,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21447,6 +21801,9 @@ 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 ""
@@ -21546,6 +21903,9 @@ 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 ""
@@ -21588,15 +21948,24 @@ 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 ""
@@ -21657,7 +22026,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21887,6 +22256,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22293,7 +22665,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22956,12 +23328,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23137,10 +23515,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23158,6 +23539,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23446,7 +23830,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23575,9 +23959,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23849,6 +24230,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24074,6 +24461,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24611,9 +25001,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25306,6 +25711,15 @@ 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 ""
@@ -25387,6 +25801,9 @@ 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 ""
@@ -25396,6 +25813,9 @@ 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 ""
@@ -25411,9 +25831,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25429,6 +25846,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25690,6 +26110,13 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Line changes"
msgstr ""
@@ -25717,6 +26144,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25810,9 +26240,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25855,6 +26282,9 @@ 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 ""
@@ -25894,6 +26324,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25912,9 +26345,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25984,9 +26414,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26023,10 +26450,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26518,6 +26942,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26599,12 +27026,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26829,18 +27265,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26913,9 +27340,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26928,6 +27352,27 @@ 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 ""
@@ -27542,6 +27987,9 @@ msgstr[3] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27722,6 +28170,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27734,6 +28188,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27794,31 +28251,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28164,6 +28636,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28212,10 +28687,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28330,9 +28811,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28420,9 +28898,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28777,6 +29252,15 @@ 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 ""
@@ -28862,13 +29346,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29178,12 +29665,24 @@ 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|%{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 ""
@@ -29232,9 +29731,18 @@ 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 ""
@@ -29262,9 +29770,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29301,6 +29806,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29310,6 +29818,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29322,6 +29833,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29800,6 +30314,9 @@ 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 ""
@@ -29869,9 +30386,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30167,28 +30681,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30993,6 +31513,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31182,9 +31705,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31383,6 +31903,9 @@ 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 ""
@@ -31608,6 +32131,9 @@ 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 ""
@@ -31659,9 +32185,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31707,6 +32230,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31758,7 +32287,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31767,6 +32296,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31803,13 +32335,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31839,6 +32371,12 @@ 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 ""
@@ -31860,6 +32398,9 @@ 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 ""
@@ -31869,6 +32410,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32184,6 +32728,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32205,6 +32752,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32265,7 +32815,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32619,6 +33169,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32688,88 +33241,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32778,34 +33274,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32814,24 +33313,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32844,22 +33337,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32868,70 +33370,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33099,6 +33604,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33348,7 +33859,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33522,6 +34033,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33534,6 +34048,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33561,6 +34078,9 @@ 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 ""
@@ -33657,9 +34177,21 @@ 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 ""
@@ -33672,6 +34204,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33714,7 +34249,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33729,9 +34267,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33861,9 +34396,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34014,9 +34546,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34059,9 +34588,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34098,9 +34624,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34143,10 +34666,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34170,9 +34693,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34407,6 +34927,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34533,6 +35056,9 @@ 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 ""
@@ -34548,6 +35074,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34728,9 +35257,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34839,12 +35365,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35016,9 +35536,29 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35028,10 +35568,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35040,15 +35592,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35058,6 +35619,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35514,24 +36078,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35607,6 +36162,9 @@ 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] ""
@@ -35644,13 +36202,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35743,6 +36301,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36692,15 +37253,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36883,9 +37450,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37059,9 +37623,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37144,6 +37705,9 @@ 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|Administrator"
msgstr ""
@@ -37207,6 +37771,9 @@ 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 ""
@@ -37225,6 +37792,9 @@ 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 ""
@@ -37283,9 +37853,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37298,6 +37874,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37316,6 +37898,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37343,6 +37928,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37352,6 +37943,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37364,6 +37958,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37406,6 +38003,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37440,6 +38040,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37455,6 +38061,9 @@ 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 ""
@@ -37479,6 +38088,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37494,6 +38106,12 @@ 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 ""
@@ -37566,9 +38184,15 @@ 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 ""
@@ -37602,6 +38226,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37611,6 +38241,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37630,6 +38263,9 @@ msgstr[3] ""
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 runner has not run any jobs."
msgstr ""
@@ -37678,6 +38314,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37732,15 +38371,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37762,6 +38392,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37786,9 +38419,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37918,16 +38548,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37969,9 +38602,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38442,22 +39081,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
msgstr ""
-msgid "Security dashboard"
+msgid "Security configuration"
msgstr ""
-msgid "Security navigation"
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38586,7 +39228,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38700,6 +39342,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38805,9 +39450,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38898,6 +39552,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38919,6 +39576,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38928,6 +39588,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38994,7 +39657,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39072,6 +39735,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39549,6 +40215,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39651,6 +40320,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39663,6 +40335,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39675,6 +40350,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39777,6 +40455,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39912,6 +40596,9 @@ 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 ""
@@ -39939,7 +40626,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40192,6 +40879,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40358,9 +41048,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40514,15 +41201,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40532,6 +41237,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40541,6 +41249,9 @@ 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 ""
@@ -40574,9 +41285,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40760,12 +41477,18 @@ 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 ""
@@ -41177,9 +41900,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41243,6 +41963,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41492,6 +42215,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42137,16 +42863,22 @@ 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|Sync subscription request."
+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}."
@@ -42155,7 +42887,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42186,9 +42918,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42231,9 +42960,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42384,9 +43110,27 @@ 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 ""
@@ -42797,10 +43541,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42826,9 +43570,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42955,6 +43696,9 @@ 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 ""
@@ -43016,6 +43760,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43058,9 +43805,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -43118,6 +43862,9 @@ 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 ""
@@ -43435,7 +44182,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43780,6 +44536,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43969,13 +44728,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44476,6 +45229,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44530,10 +45286,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44988,6 +45741,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45479,6 +46235,9 @@ 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 ""
@@ -45570,9 +46329,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45675,9 +46431,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45723,12 +46476,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45834,6 +46581,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45933,6 +46683,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45990,6 +46743,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46077,6 +46839,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46146,6 +46911,9 @@ 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 ""
@@ -46272,6 +47040,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46443,6 +47214,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46647,6 +47421,9 @@ 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 ""
@@ -46659,6 +47436,9 @@ 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 ""
@@ -46735,6 +47515,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47161,6 +47944,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47272,6 +48058,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47416,6 +48205,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47447,9 +48239,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47656,6 +48445,69 @@ 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|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 ""
@@ -48046,12 +48898,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48103,9 +48949,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48247,6 +49090,9 @@ 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 ""
@@ -48512,6 +49358,13 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -48552,6 +49405,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48771,7 +49627,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48819,6 +49675,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48844,6 +49703,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48868,9 +49736,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48991,6 +49865,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49027,6 +49904,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49057,6 +49937,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49460,9 +50343,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49635,12 +50515,18 @@ 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 ""
@@ -49813,6 +50699,9 @@ 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 ""
@@ -49822,7 +50711,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49852,6 +50741,9 @@ 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 ""
@@ -49876,6 +50768,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49921,6 +50816,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49930,9 +50828,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49963,6 +50858,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50124,6 +51022,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50367,6 +51268,9 @@ 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 ""
@@ -50709,9 +51613,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50779,6 +51680,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50809,6 +51713,9 @@ 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 ""
@@ -51096,9 +52003,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51412,10 +52316,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51477,6 +52387,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51492,6 +52480,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51519,12 +52513,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51540,6 +52528,9 @@ 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 ""
@@ -51623,82 +52614,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51761,9 +52698,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51788,6 +52722,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/cy_GB/gitlab.po b/locale/cy_GB/gitlab.po
index 6ad64668ee1..10e0bc62319 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr " %{start} i %{end}"
@@ -706,6 +706,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -769,6 +778,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
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] ""
@@ -778,6 +796,12 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -994,6 +1018,9 @@ msgstr "%{count} %{pluralized_subject} cysylltiedig: %{links}"
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1195,6 +1222,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1210,9 +1240,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1354,6 +1381,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1666,6 +1696,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1996,15 +2029,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -2365,9 +2389,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2782,9 +2803,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2806,6 +2824,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2815,6 +2836,9 @@ 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 ""
@@ -2929,6 +2953,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -3067,6 +3094,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -4246,40 +4276,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4651,6 +4651,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -5287,6 +5290,9 @@ 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 ""
@@ -5296,6 +5302,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5374,13 +5497,28 @@ 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|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."
+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."
@@ -5533,12 +5671,18 @@ 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 ""
@@ -5803,6 +5947,15 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5815,6 +5968,24 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5890,9 +6061,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5905,6 +6073,9 @@ 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 ""
@@ -6268,7 +6439,7 @@ msgstr[5] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6526,9 +6697,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6541,9 +6709,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6553,9 +6718,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6937,6 +7111,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6964,9 +7141,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -7036,6 +7210,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -7051,9 +7228,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -7189,27 +7363,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -7219,9 +7375,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7366,6 +7519,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7600,15 +7756,27 @@ msgstr[5] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7621,9 +7789,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7741,9 +7906,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7762,6 +7924,15 @@ 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 ""
@@ -7792,10 +7963,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7837,6 +8011,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8608,6 +8785,15 @@ 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 ""
@@ -8725,6 +8911,9 @@ 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 ""
@@ -9115,6 +9304,9 @@ 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 ""
@@ -9157,6 +9349,9 @@ 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 ""
@@ -9166,16 +9361,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -9202,6 +9394,9 @@ 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 ""
@@ -9220,6 +9415,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -9238,6 +9436,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9358,12 +9559,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9442,10 +9649,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9475,6 +9682,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -10264,6 +10474,9 @@ 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 ""
@@ -10555,7 +10768,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10951,9 +11164,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10966,6 +11176,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -11035,12 +11248,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11149,9 +11371,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -11170,9 +11407,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11806,6 +12040,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11848,12 +12085,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11869,6 +12115,9 @@ 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 ""
@@ -11914,7 +12163,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11935,7 +12187,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -12007,6 +12259,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -12253,7 +12508,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12442,6 +12697,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12691,9 +12949,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12901,6 +13156,9 @@ 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 ""
@@ -13000,7 +13258,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -13171,9 +13429,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -14089,6 +14344,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -14131,6 +14389,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14914,6 +15175,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -15019,10 +15283,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -15127,6 +15394,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -15322,6 +15592,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15487,9 +15760,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15931,6 +16201,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15955,6 +16228,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15973,9 +16249,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16432,6 +16714,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16477,7 +16762,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16495,6 +16780,9 @@ 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 ""
@@ -16789,6 +17077,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16900,6 +17191,9 @@ 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 ""
@@ -17188,6 +17482,9 @@ 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 ""
@@ -17470,6 +17767,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17494,6 +17794,9 @@ 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 ""
@@ -17695,6 +17998,9 @@ 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 ""
@@ -17713,6 +18019,9 @@ 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 ""
@@ -18295,9 +18604,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18421,6 +18727,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18577,9 +18886,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18721,9 +19027,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19546,13 +19849,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19603,6 +19915,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19627,6 +19942,12 @@ 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 ""
@@ -19642,9 +19963,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19693,15 +20011,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19795,12 +20104,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19840,6 +20155,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19852,13 +20170,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19876,7 +20194,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19930,6 +20248,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -20002,6 +20323,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -20056,15 +20380,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -20281,6 +20599,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20470,6 +20812,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20821,6 +21166,9 @@ 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 ""
@@ -21079,6 +21427,9 @@ 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 ""
@@ -21094,6 +21445,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21478,6 +21835,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21829,6 +22189,9 @@ 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 ""
@@ -21928,6 +22291,9 @@ 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 ""
@@ -21970,15 +22336,24 @@ 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 ""
@@ -22039,7 +22414,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -22273,6 +22648,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22681,7 +23059,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -23344,12 +23722,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23527,10 +23911,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23548,6 +23935,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23836,7 +24226,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23965,9 +24355,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -24241,6 +24628,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24466,6 +24859,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -25003,9 +25399,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25702,6 +26113,15 @@ 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 ""
@@ -25783,6 +26203,9 @@ 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 ""
@@ -25792,6 +26215,9 @@ 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 ""
@@ -25807,9 +26233,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25825,6 +26248,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -26098,6 +26524,15 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Line changes"
msgstr ""
@@ -26125,6 +26560,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -26218,9 +26656,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -26263,6 +26698,9 @@ 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 ""
@@ -26302,6 +26740,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -26320,9 +26761,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -26392,9 +26830,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26431,10 +26866,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26926,6 +27358,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -27007,12 +27442,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -27241,18 +27685,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -27325,9 +27760,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -27340,6 +27772,27 @@ 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 ""
@@ -27958,6 +28411,9 @@ msgstr[5] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -28138,6 +28594,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -28150,6 +28612,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -28210,31 +28675,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28582,6 +29062,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28630,10 +29113,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28750,9 +29239,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28840,9 +29326,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -29197,6 +29680,15 @@ 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 ""
@@ -29284,13 +29776,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29608,12 +30103,24 @@ 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|%{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 ""
@@ -29662,9 +30169,18 @@ 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 ""
@@ -29692,9 +30208,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29731,6 +30244,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29740,6 +30256,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29752,6 +30271,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -30232,6 +30754,9 @@ 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 ""
@@ -30301,9 +30826,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30601,28 +31123,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -31435,6 +31963,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31624,9 +32155,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31825,6 +32353,9 @@ 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 ""
@@ -32050,6 +32581,9 @@ 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 ""
@@ -32101,9 +32635,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -32149,6 +32680,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -32200,7 +32737,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -32209,6 +32746,9 @@ 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|Revoke trigger"
msgstr ""
@@ -32245,13 +32785,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -32281,6 +32821,12 @@ 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 ""
@@ -32302,6 +32848,9 @@ 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 ""
@@ -32311,6 +32860,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32626,6 +33178,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32647,6 +33202,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32707,7 +33265,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -33061,6 +33619,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -33130,88 +33691,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -33220,34 +33724,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -33256,24 +33763,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -33286,22 +33787,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -33310,70 +33820,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User activity"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33541,6 +34054,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33790,7 +34309,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33964,6 +34483,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33976,6 +34498,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -34003,6 +34528,9 @@ 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 ""
@@ -34099,9 +34627,21 @@ 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 ""
@@ -34114,6 +34654,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -34156,7 +34699,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -34171,9 +34717,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -34303,9 +34846,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34456,9 +34996,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34501,9 +35038,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34540,9 +35074,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34585,10 +35116,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34612,9 +35143,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34849,6 +35377,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34975,6 +35506,9 @@ 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 ""
@@ -34990,6 +35524,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -35170,9 +35707,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -35281,12 +35815,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35458,9 +35986,33 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35470,10 +36022,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35482,15 +36046,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35500,6 +36073,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35956,24 +36532,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -36049,6 +36616,9 @@ 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] ""
@@ -36088,13 +36658,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -36187,6 +36757,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -37150,15 +37723,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -37345,9 +37924,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37525,9 +38101,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37618,6 +38191,9 @@ 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|Administrator"
msgstr ""
@@ -37681,6 +38257,9 @@ 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 ""
@@ -37699,6 +38278,9 @@ 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 ""
@@ -37759,9 +38341,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37774,6 +38362,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37792,6 +38386,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37819,6 +38416,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37828,6 +38431,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37840,6 +38446,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37882,6 +38491,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37918,6 +38530,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37933,6 +38551,9 @@ 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 ""
@@ -37957,6 +38578,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37972,6 +38596,12 @@ 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 ""
@@ -38044,9 +38674,15 @@ 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 ""
@@ -38080,6 +38716,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -38089,6 +38731,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -38110,6 +38755,9 @@ msgstr[5] ""
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 runner has not run any jobs."
msgstr ""
@@ -38158,6 +38806,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -38212,15 +38863,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -38242,6 +38884,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -38266,9 +38911,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -38398,16 +39040,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -38449,9 +39094,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38944,22 +39595,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
msgstr ""
-msgid "Security dashboard"
+msgid "Security configuration"
msgstr ""
-msgid "Security navigation"
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -39088,7 +39742,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -39202,6 +39856,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -39307,9 +39964,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -39400,6 +40066,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -39421,6 +40090,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -39430,6 +40102,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -39496,7 +40171,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39574,6 +40249,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -40051,6 +40729,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -40153,6 +40834,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -40165,6 +40849,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -40177,6 +40864,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -40279,6 +40969,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -40414,6 +41110,9 @@ 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 ""
@@ -40441,7 +41140,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40696,6 +41395,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40864,9 +41566,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -41020,15 +41719,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -41038,6 +41755,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -41047,6 +41767,9 @@ 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 ""
@@ -41080,9 +41803,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -41266,12 +41995,18 @@ 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 ""
@@ -41683,9 +42418,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41749,6 +42481,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41998,6 +42733,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42643,16 +43381,22 @@ 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|Sync subscription request."
+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}."
@@ -42661,7 +43405,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42694,9 +43438,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42739,9 +43480,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42892,9 +43630,27 @@ 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 ""
@@ -43309,10 +44065,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -43342,9 +44098,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -43471,6 +44224,9 @@ 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 ""
@@ -43534,6 +44290,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43576,9 +44335,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -43636,6 +44392,9 @@ 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 ""
@@ -43957,7 +44716,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -44302,6 +45070,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -44491,13 +45262,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44998,6 +45763,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -45052,10 +45820,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -45514,6 +46279,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -46009,6 +46777,9 @@ 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 ""
@@ -46102,9 +46873,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -46207,9 +46975,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -46255,12 +47020,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -46366,6 +47125,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -46465,6 +47227,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -46522,6 +47287,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46609,6 +47383,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46678,6 +47455,9 @@ 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 ""
@@ -46804,6 +47584,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46975,6 +47758,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -47179,6 +47965,9 @@ 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 ""
@@ -47191,6 +47980,9 @@ 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 ""
@@ -47269,6 +48061,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47695,6 +48490,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47806,6 +48604,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47950,6 +48751,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47983,9 +48787,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -48196,6 +48997,69 @@ 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|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 ""
@@ -48586,12 +49450,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48643,9 +49501,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48787,6 +49642,9 @@ 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 ""
@@ -49054,6 +49912,15 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
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] ""
@@ -49096,6 +49963,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -49315,7 +50185,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -49363,6 +50233,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -49390,6 +50263,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -49414,9 +50296,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -49537,6 +50425,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49573,6 +50464,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49603,6 +50497,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -50008,9 +50905,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -50185,12 +51079,18 @@ 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 ""
@@ -50365,6 +51265,9 @@ 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 ""
@@ -50374,7 +51277,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -50404,6 +51307,9 @@ 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 ""
@@ -50428,6 +51334,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -50473,6 +51382,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -50482,9 +51394,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -50515,6 +51424,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50680,6 +51592,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50929,6 +51844,9 @@ 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 ""
@@ -51283,9 +52201,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -51355,6 +52270,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -51385,6 +52303,9 @@ 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 ""
@@ -51682,9 +52603,6 @@ msgstr[5] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -52006,10 +52924,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -52075,6 +52999,84 @@ 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|%{mergeError}."
msgstr ""
@@ -52090,6 +53092,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -52117,12 +53125,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -52138,6 +53140,9 @@ 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 ""
@@ -52225,82 +53230,28 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -52363,9 +53314,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -52390,6 +53338,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po
index 11e027c425e..c36919c5fd4 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-02-11 04:19\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr " %{start} til %{end}"
@@ -426,6 +426,11 @@ msgid_plural "%d unresolved threads"
msgstr[0] "%d uløst tråd"
msgstr[1] "%d uløste tråde"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d sårbarhed"
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "%d advarsel fundet:"
msgstr[1] "%d advarsler fundet:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s yderligere commit er udeladt for at forhindre ydelsesproblemer."
msgstr[1] "%s yderligere commits er udeladt for at forhindre ydelsesproblemer."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} og %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr "%{count} relaterede %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "%{count} valgt"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} vægt i alt"
@@ -831,6 +850,9 @@ msgstr "%{level_name} er ikke tilladt eftersom forgreningskildeprojektet har lav
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow} og %{awardsListLength} mere"
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} kan sammenlægge"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} viser første %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (udløbet)"
@@ -982,6 +1001,9 @@ msgstr "%{reportType} registrerede %{totalStart}%{total}%{totalEnd} potentielle
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr "%{user} oprettede en epic: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} oprettede en problemstilling: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} er ikke med på listen"
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] "1 udsendelsesnøgle"
msgstr[1] "%d udsendelsesnøgler"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "1 følger"
-msgstr[1] "%{count} følgere"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 gruppe"
@@ -1813,9 +1833,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "API-fuzzing"
-msgid "API Fuzzing Configuration"
-msgstr "Konfiguration af API-fuzzing"
-
msgid "API Help"
msgstr "Hjælp for API"
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr "Tilføj et afsnit som kan foldes sammen"
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr "Tilføj en kommentar til linjen"
@@ -2254,6 +2268,9 @@ msgstr "Tilføj en startside til din wiki med information om dit projekt, så vi
msgid "Add a new issue"
msgstr "Tilføj en ny problemstilling"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Tilføj en nummereret liste"
@@ -2263,6 +2280,9 @@ msgstr ""
msgid "Add a related issue"
msgstr "Tilføj en relateret problemstilling"
+msgid "Add a reply"
+msgstr ""
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -2377,6 +2397,9 @@ msgstr "Tilføj nyt program"
msgid "Add new directory"
msgstr "Tilføj ny mappe"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr "Yderligere minutter:"
msgid "Additional text"
msgstr "Yderligere tekst"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr "Yderligere tekst til indlognings- og hjælpesiden."
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr "Hele GitLab"
msgid "All Members"
msgstr "Alle medlemmer"
+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 "Alle grene"
@@ -4727,6 +4726,9 @@ msgstr "Der opstod en uventet fejl under start af webterminal."
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Der opstod en uventet fejl under stop af webterminal."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr "Der opstod en ukendt fejl under indlæsning af grafen."
@@ -4736,6 +4738,123 @@ msgstr "Der opstod en ukendt fejl."
msgid "Analytics"
msgstr "Analyse"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analyser dine afhængigheder for kendte sårbarheder."
@@ -4814,13 +4933,28 @@ msgstr "Tilføj %{shrug} til slutningen af kommentaren"
msgid "Append the comment with %{tableflip}"
msgstr "Tilføj %{tableflip} til slutningen af kommentaren"
+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|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."
+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."
@@ -4965,12 +5099,18 @@ msgstr "Gem ændringer"
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 "Tilmelding aktiveret"
+msgid "ApplicationSettings|Soft"
+msgstr ""
+
msgid "ApplicationSettings|Text shown after a user signs up. Markdown enabled."
msgstr ""
@@ -5215,6 +5355,11 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Godkend en sammenlægningsanmodning"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5227,6 +5372,16 @@ msgstr "Godkendt"
msgid "Approved MRs"
msgstr "Godkendte sammenlægningsanmodninger"
+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 "Godkendte den nuværende sammenlægningsanmodning."
@@ -5302,9 +5457,6 @@ msgstr "Er du sikker på, at du vil %{action} %{name}?"
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr "Er du sikker på, at du forsøge at sammenlægge?"
@@ -5317,6 +5469,9 @@ msgstr "Er du sikker på, at du vil lukke den blokerede problemstilling?"
msgid "Are you sure you want to delete %{name}?"
msgstr "Er du sikker på, at du vil slette %{name}?"
+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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] "Vedhæfter %d filer"
msgid "Attaching the file failed."
msgstr "Kunne ikke vedhæfte filen."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr "Forfattet %{timeago} af %{author}"
msgid "Authorization code:"
msgstr "Godkendelseskode:"
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr "Godkend"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "Giv %{link_to_client} tilladelse til at bruge din konto?"
-msgid "Authorize %{user} to use your account?"
-msgstr "Giv %{user} tilladelse til at bruge din konto?"
-
msgid "Authorized %{new_chat_name}"
msgstr "Giv %{new_chat_name} tilladelse"
@@ -5949,9 +6098,18 @@ msgstr "Tilladelse givet kl."
msgid "Authorized applications (%{size})"
msgstr "Godkendte programmer (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Vær forsigtig. Omdøbning af et projekts depot kan have utilsigtede bivirkninger."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr "Nedenunder finder du alle de grupper, som er offentlige."
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr "Hvis du vil nedgradere din plan, så kontakt venligst %{support_link_sta
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 "Lær mere om hver plan ved at læse vores %{faq_link} eller start en gratis 30-dages prøveperiode af GitLab.com Ultimate."
@@ -6585,27 +6743,9 @@ msgstr "Opgrader"
msgid "BillingPlan|Upgrade for free"
msgstr "Opgrader gratis"
-msgid "Billings|%{planName} plan"
-msgstr "%{planName}-plan"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr "Der opstod en fejl under forlængelse af din prøveperiode."
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr "Der opstod en fejl under genaktivering af din prøveperiode."
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr "Ved at forlænge din prøveperiode vil du modtage yderligere 30 dage med %{planName}. Din prøveperiode kan kun forlænges én gang."
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr "Ved at genaktivere din prøveperiode vil du modtage yderligere 30 dage med %{planName}. Din prøveperiode kan kun aktiveres én gang."
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr "Forlæng plan"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr "Genaktivér prøveperiode"
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr "Bitbucket-import"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ msgstr[1] ""
msgid "Boards|Collapse"
msgstr "Sammenfold"
+msgid "Boards|Create new epic"
+msgstr ""
+
+msgid "Boards|Create new issue"
+msgstr ""
+
msgid "Boards|Edit board"
msgstr "Rediger tavle"
+msgid "Boards|Edit list settings"
+msgstr ""
+
msgid "Boards|Expand"
msgstr "Udfold"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr "Kunne ikke hente blokerende %{issuableType}s"
+msgid "Boards|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr "Ny epic"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr "Henter blokerende %{issuableType}s"
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ msgstr "Kan ikke anvende forslaget."
msgid "Can't be empty"
msgstr "Må ikke være tomt"
+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 "Kan ikke oprette udklip: %{err}"
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+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 ""
@@ -8525,6 +8701,9 @@ msgstr "Land"
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 "Opret en ny gruppe"
@@ -8534,18 +8713,15 @@ msgstr "Kreditkortformular kunne ikke indlæses. Prøv venligst igen."
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "Rediger"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "Kunne ikke bekræfte din bestilling! Prøv venligst igen."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "Kunne ikke bekræfte din bestilling: %{message}. Prøv venligst igen."
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "Kunne ikke indlæse lande. Prøv venligst igen."
@@ -8570,6 +8746,9 @@ msgstr "GitLab-plan"
msgid "Checkout|Group"
msgstr "Gruppe"
+msgid "Checkout|Invalid coupon code. Enter a valid coupon code."
+msgstr ""
+
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
msgstr ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "Brug for flere brugere? Køb GitLab til din %{company}."
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "Antal brugere"
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "Tilstand"
@@ -8726,12 +8911,18 @@ msgstr "Vælg hvilket indhold du vil se på en gruppes oversigtsside."
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 "Vælg dit framework"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,12 +9001,12 @@ msgstr "venter"
msgid "CiStatus|running"
msgstr "kører"
+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|Clear inputs"
-msgstr ""
-
msgid "CiVariables|Environments"
msgstr "Miljøer"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr "Beskyttede"
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr "Fjern variabel"
@@ -9624,6 +9818,9 @@ 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 "Du har ikke tilstrækkelige tilladelser til at oprette en klyngeagent for projektet"
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr "Sammenlign GitLab-udgaver"
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "Sammenlign revisioner"
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr "Sammenlign ændringer med den sidste commit"
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr "Fuldført"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr "Overholdelsesframework"
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Tilføj framework"
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "Komponent"
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "Fortrolighed"
-msgid "Configuration"
-msgstr "Konfiguration"
-
msgid "Configuration help"
msgstr "Konfigurationshjælp"
@@ -11150,6 +11368,9 @@ msgstr "Du er ved at fjerne depotet %{title}. Når du bekræfter, så vil depote
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "Du kan tilføje et aftryk til registeret med følgende kommandoer:"
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr "Bidrag"
msgid "Contribution Analytics"
msgstr "Bidragsanalyse"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr "Bidrag pr. gruppemedlem"
msgid "Contributor"
msgstr "Bidragsyder"
-msgid "Contributors"
-msgstr "Bidragsydere"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "Styr e-mails som er linket til din konto"
@@ -11351,6 +11587,9 @@ msgstr "Kopiér kommandoer"
msgid "Copy commit SHA"
msgstr "Kopiér commit-SHA"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr "Kopiér miljø"
@@ -11597,8 +11836,8 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
-msgstr "Land"
+msgid "Country / Region"
+msgstr ""
msgid "Counts"
msgstr ""
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr "Opret eller importér dit første projekt"
@@ -12035,9 +12277,6 @@ msgstr "Oprettet"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "Opret en gren og en sammenlægningsanmodning for at løse problemstillingen."
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "Oprettede grenen '%{branch_name}' og en sammenlægningsanmodning for at løse problemstillingen."
@@ -12245,6 +12484,9 @@ msgstr "Præferencer"
msgid "CurrentUser|Start an Ultimate trial"
msgstr "Start en Ultimate-prøveperiode"
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr ""
+
msgid "Currently unable to fetch data for this pipeline."
msgstr ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr "DAST-konfiguration"
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr "Slet korpus"
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr "Slet række"
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr "lykkedes"
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,12 +14567,15 @@ msgstr "Kunne ikke tilføje en ny kommentar. Prøv venligst igen."
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "Kunne ikke oprette ny debat. Prøv venligst igen."
+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 discussion. Please try again."
msgstr "Kunne ikke opdatere debat. Prøv venligst igen."
-msgid "DesignManagement|Could not update note. Please try again."
-msgstr "Kunne ikke opdatere note. Prøv venligst igen."
-
msgid "DesignManagement|Deselect all"
msgstr "Fravælg alle"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr "Enheder (valgfrit)"
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr "Discord-underretninger"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr "Send underretninger om projektbegivenheder til en Discord-kanal."
-msgid "Discover"
-msgstr "Opdag"
-
msgid "Discover GitLab Geo"
msgstr "Opdag GitLab Geo"
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr "Rediger beskrivelse"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "Rediger miljø"
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr "Rediger sammenlægningsanmodninger"
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "Rediger offentlig udsendelsesnøgle"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr "Rediger sidebjælke"
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr "GÃ¥ i administratortilstand"
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "Indtast et tal"
@@ -15761,7 +16030,7 @@ msgstr "Indtast beskrivelsen for %{name}"
msgid "Enter the %{name} title"
msgstr "Indtast titlen for %{name}"
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 "Indtast din Packagist-server. Er som standard https://packagist.org."
@@ -16073,6 +16345,9 @@ msgstr "Epictavler"
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "Kan ikke finde epic."
@@ -16184,6 +16459,9 @@ msgstr ""
msgid "Error creating new iteration"
msgstr "Fejl ved oprettelse af nyt gennemløb"
+msgid "Error creating or updating PreScanVerificationStep: %{errors}"
+msgstr ""
+
msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr "Fejl ved oprettelse af depot for udklip med id'et %{snippet_id}"
@@ -16472,6 +16750,9 @@ msgstr "Er du sikker på, at du vil slette eskaleringsregelsættet \"%{escalatio
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 "Opret et eskaleringsregelsæt i GitLab"
@@ -16750,6 +17031,9 @@ msgstr "Bevissamling"
msgid "Exactly one of %{attributes} is required"
msgstr "Præcist én af %{attributes} kræves"
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ msgstr ""
msgid "Exceptions"
msgstr "Undtagelser"
+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 "Uden sammenlægningscommits. Begrænset til %{limit} commits."
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr "Feb."
msgid "February"
msgstr "Februar"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr "Filtrér pipelines"
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "Filtrér resultater"
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr "Format: %{dateFormat}"
msgid "Framework successfully deleted"
msgstr "Framework slettet"
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Gratis prøveperiode af GitLab.com Ultimate"
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr "GitLab Pages"
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr "GitLab-gruppe: %{source_link}"
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr "GitLab-version"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr "Ubekræftet"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use unique domain"
+msgstr ""
+
msgid "GitLabPages|Verified"
msgstr "Verificeret"
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 ""
@@ -19092,6 +19395,9 @@ msgstr "URL for Gitea-vært"
msgid "Gitea Import"
msgstr "Gitea-import"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr "Fik adgang %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 "OK"
@@ -19722,6 +20052,9 @@ msgstr "Gruppenavn (din organisation)"
msgid "Group navigation"
msgstr "Gruppenavigation"
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr "Indhold for gruppeoversigt"
@@ -20073,6 +20406,9 @@ 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 "Overholdelsesframeworks"
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "Hej %{username}!"
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ msgstr ""
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "Hvis den er tilvalgt, så kan nye gruppemedlemskaber og -tilladelser kun tilføjes via LDAP-synkronisering"
+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 ""
@@ -21275,7 +21638,7 @@ msgstr ""
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "Hvis du for nyligt har logget ind og genkender IP-adressen, så kan du se bort fra e-mailen."
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr "Import af projektet mislykkedes"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr "Import af projektet mislykkedes: %{reason}"
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr "Indsæt billede"
msgid "Insert link"
msgstr "Indsæt link"
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr "Indsæt række efter"
msgid "Insert row before"
msgstr "Indsæt række før"
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "Indsæt forslag"
@@ -22747,11 +23119,14 @@ msgstr "Standardindstillinger nedarves fra gruppeniveauet."
msgid "Integrations|Default settings are inherited from the instance level."
msgstr "Standardindstillinger nedarves fra instansniveauet."
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
-msgstr "Aktivér GitLab.com-skråstregskommandoer i et Slack-arbejdsområde."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
+msgstr ""
msgid "Integrations|Enable SSL verification"
msgstr ""
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr "Kunne ikke linke navnerum. Prøv venligst igen."
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr "Ugyldig depotsti"
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr "Problemstillingstype"
msgid "Issue already promoted to epic."
msgstr "Problemstilling allerede forfremmet til epic."
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr "Kan ikke finde problemstilling."
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr "Titel"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "Job"
@@ -24910,6 +25309,15 @@ msgstr "Lær mere."
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
msgstr "%{percentage} %{percentSymbol} fuldført"
+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 "Tilføj kodeejere"
@@ -24991,6 +25399,9 @@ msgstr "Opsæt dit arbejdsområde"
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 ""
@@ -25000,6 +25411,9 @@ msgstr "Prøv GitLab Ultimate, gratis"
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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr "Forlad administratortilstand"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "Forlad redigeringstilstand? Alle ændringer som ikke er blevet gemt vil gå tabt."
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Forlad gruppe"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr "Linjeændringer"
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr "Link kopieret"
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr "Linktekst"
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr "Liste over alle sammenlægningscommits"
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 "Indlæser mere"
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr "Lås til nuværende projekter"
msgid "Locked"
msgstr "LÃ¥st"
-msgid "Locked Files"
-msgstr "LÃ¥ste filer"
-
msgid "Locked by %{fileLockUserName}"
msgstr "LÃ¥st af %{fileLockUserName}"
@@ -25576,9 +25998,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "SAMMENLAGT"
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr "Vis kun ændringer"
msgid "MRDiff|Show full file"
msgstr "Vis hele filen"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr "Maksimale størrelse på push"
msgid "Maximum push size (MB)"
msgstr "Maksimale størrelse på push (MB)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ 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 "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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr "Sammenlæg automatisk (%{strategy})"
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr "Sammenlægning blokeret: nye ændringer blev netop tilføjet."
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr "Sammenlægning blokeret: kildegrenen skal rebases på målgrenen."
-
msgid "Merge commit SHA"
msgstr "Sammenlægningscommit-SHA"
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ msgstr "Sammenlæg når pipeline lykkes"
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 "Commit til kildegren"
@@ -27126,6 +27563,9 @@ msgstr[1] "Milepæle"
msgid "Milestone due date"
msgstr "Forfaldsdato for milepæl"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "Milepælslister er ikke tilgængelige med din nuværende licens"
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr "Minutter"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
+msgstr ""
+
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr "Navnerum"
msgid "Namespaces to index"
msgstr "Navnerum som skal indekseres"
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "Navngivning, emner, avatar"
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr "Nyt krav"
msgid "New Snippet"
msgstr "Nyt udklip"
-msgid "New Test Case"
-msgstr "Ny testsag"
-
msgid "New User"
msgstr "Ny bruger"
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr "Ny adgangskode"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "Nyt projekt"
@@ -28357,6 +28824,15 @@ 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 "Ingen kilde valgt"
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ msgstr "Vores team er blevet underrettet. Prøv venligst igen."
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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr "Afventende kommentarer"
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr "Vælg et navn"
-msgid "Pin code"
-msgstr "Pinkode"
-
msgid "Pipeline"
msgstr "Pipeline"
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ msgstr "Pipelines"
msgid "Pipelines charts"
msgstr "Pipelinediagrammer"
+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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr "Ryd runnermellemlagre"
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr "Ejer"
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ msgstr "Projektmellemlager nulstillet."
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|Revoke trigger"
msgstr ""
@@ -31361,14 +31885,14 @@ msgstr ""
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
msgstr "Der opstod en fejl under hentning af pipelinesne. Prøv igen om lidt eller kontakt dit supportteam."
-msgid "Pipelines|This GitLab CI configuration is invalid."
+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}."
-msgstr "GitLab CI-konfigurationen er ugyldig: %{reason}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
msgstr ""
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ msgstr "Vis sammenlagt YAML"
msgid "Pipelines|Visualize"
msgstr "Visualiser"
+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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr "Slet venligst din nuværende licens hvis du vil nedgradere til den grati
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,8 +32365,8 @@ msgstr "Vælg venligst"
msgid "Please select a Jira project"
msgstr "Vælg venligst et Jira-projekt"
-msgid "Please select a country"
-msgstr "Vælg venligst et land"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr ""
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "Tidligere artefakter"
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr "Fortsæt"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr "Vis ikke i profil"
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr "Projektmedlemmer"
msgid "Project milestone"
msgstr "Projektmilepæl"
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Projektnavn"
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr "Projektsti"
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ msgstr "Projekt-id: %{project_id}"
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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,8 +33799,11 @@ 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 "ProjectSelect| or group"
-msgstr " eller gruppe"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
msgid "ProjectSelect|No matching results"
msgstr "Ingen matchende resultater"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr "Vælg et projekt"
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr "Yderligere indstillinger der påvirker hvordan og hvornår sammenlægnin
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr "Tillad"
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr "Internt"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr "Problemstillinger"
@@ -33617,9 +34138,6 @@ msgstr "Sammenlægningsanmodninger"
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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,11 +34216,11 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
-msgstr "Sikkerhed og overholdelse"
+msgid "ProjectSettings|Security and Compliance"
+msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
-msgstr "Sikkerhed og overholdelse for projektet"
+msgid "ProjectSettings|Security and compliance for this project."
+msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
msgstr ""
@@ -33728,9 +34243,6 @@ msgstr "Vis standardbelønningsemojier"
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr "Udklip"
@@ -33965,6 +34477,9 @@ msgstr "Projekter (%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr "Projektkonfiguration"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "Projektbeskrivelse %{tag_start}(valgfrit)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr "Kontakt ejeren %{link_start}%{owner_name}%{link_end} for at opgradere pl
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr "Kontakt din administrator for at opgradere din licens."
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr "Når du har mange problemstillinger, så kan det være svært at få et
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr "beskrivelsesskabeloner"
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr "til at hjælpe dine bidragsydere med at kommunikere effektivt!"
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+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?"
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "MÃ¥ udsende"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr "Klar til at sammenlægge!"
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr "Rebase"
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr "Rebase i gang"
-
msgid "Rebase source branch"
msgstr "Rebase kildegren"
msgid "Rebase source branch on the target branch."
msgstr "Rebase kildegren på målgrenen."
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr "Recaptcha verificeret?"
@@ -35165,6 +35708,9 @@ msgstr ""
msgid "Refresh the page and try again."
msgstr "Opdater siden og prøv igen."
+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] "Opdaterer om et sekund for at vise den opdateret status ..."
@@ -35200,14 +35746,14 @@ msgstr "Tilmeld"
msgid "Register / Sign In"
msgstr "Tilmeld/log ind"
-msgid "Register Two-Factor Authenticator"
-msgstr "Tilmeld totrinsgodkendelse"
+msgid "Register a WebAuthn device"
+msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "Tilmeld U2F-enhed (Universal Two-Factor)"
+msgid "Register a one-time password authenticator"
+msgstr ""
-msgid "Register WebAuthn Device"
-msgstr "Tilmeld WebAuthn-enhed"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
+msgstr ""
msgid "Register device"
msgstr ""
@@ -35299,6 +35845,9 @@ msgstr "Afvist (lukket)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr "Relaterede funktionsflag"
@@ -36234,15 +36783,21 @@ msgstr "Kravet %{reference} er blevet genåbnet"
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr ""
-
msgid "Requirements"
msgstr "Krav"
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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr "Genoptag"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr "Prøv igen"
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr "Kør manuelle eller forsinkede job"
@@ -36670,6 +37219,9 @@ msgstr "Aktiv"
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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr "Installer en runner"
@@ -36867,6 +37440,12 @@ msgstr "LÃ¥st til projektet"
msgid "Runners|Maintenance note"
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 "Maksimum timeout for job"
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr "Navn"
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr "Beskyttet"
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr "Runner #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr "Stop runneren i at acceptere nye job."
@@ -37133,6 +37751,9 @@ msgstr "Mærkater"
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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr "delt"
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "Kører"
@@ -37282,6 +37900,9 @@ msgstr "SAML-opdagelsestokens"
msgid "SAML for %{group_name}"
msgstr "SAML for %{group_name}"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr "SAST-konfiguration"
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,24 +38567,27 @@ msgstr ""
msgid "Security"
msgstr "Sikkerhed"
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr "Sikkerhedsbetjeningspanel"
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
-msgstr "Sikkerhedsbetjeningspanel"
+msgid "Security and Compliance"
+msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
+msgstr ""
+
+msgid "Security configuration"
msgstr ""
msgid "Security dashboard"
msgstr "Sikkerhedsbetjeningspanel"
-msgid "Security navigation"
-msgstr "Sikkerhedsnavigation"
-
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr "Sikkerhedsrapporten er forældet. Opdater venligst din gren med de seneste ændringer fra målgrenen (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr "Vælg sikkerhedsprojekt"
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr "%{firstProject}, %{secondProject} og %{rest}"
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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."
@@ -39047,6 +39701,9 @@ msgstr "Vælg etiket"
msgid "Select labels"
msgstr "Vælg etiketter"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "Vælg sammenlægningsøjeblik"
@@ -39149,6 +39806,9 @@ msgstr "Selvovervågningsprojekt er blevet slettet"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "Selvovervågningsprojekt blev ikke slettet. Tjek venligst loggene for fejlmeddelelser"
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr "Send"
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr "Aktivér serviceskranke"
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr "Opsæt Jira-integrering"
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr "Log ind"
-msgid "Sign in / Register"
-msgstr "Log ind/tilmeld"
-
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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 "Noget gik galt ved omorganisering af designs. Prøv venligst igen"
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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr "Beskyttelse for spam og anti-bot"
msgid "Spam log successfully submitted as ham."
msgstr "Spamlog indsendt som ham."
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr "Fjern statustjek?"
msgid "StatusCheck|Service name"
msgstr "Tjenestenavn"
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr "Statustjek"
@@ -41631,16 +42345,22 @@ msgstr ""
msgid "SuperSonics|Start free trial"
msgstr "Start gratis prøveperiode"
+msgid "SuperSonics|Subscription detail synchronization has started and will complete soon."
+msgstr ""
+
msgid "SuperSonics|Subscription details"
msgstr "Abonnementsdetaljer"
+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|Sync subscription request."
+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}."
@@ -41649,8 +42369,8 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
-msgstr "Der er problemer med forbindelsen."
+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 ""
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr "Dit abonnement"
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ msgstr "Mærkatliste:"
msgid "Tag name"
msgstr "Mærkatnavn"
+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 ""
@@ -42285,12 +43017,12 @@ msgstr ""
msgid "Test"
msgstr "Test"
-msgid "Test Cases"
-msgstr "Testsager"
-
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] ""
@@ -42310,9 +43042,6 @@ msgstr "Flyt testsag"
msgid "TestCases|Moving test case"
msgstr "Flytter testsag"
-msgid "TestCases|New Test Case"
-msgstr "Ny testsag"
-
msgid "TestCases|New test case"
msgstr "Ny testsag"
@@ -42439,6 +43168,9 @@ 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 "Tekststil"
@@ -42498,6 +43230,9 @@ msgstr "Problemstillingsporingen er stedet hvor ting tilføjes som har brug for
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ msgstr "Sammenligningsvisningen kan være upræcis pga. sammenlægningskonflikte
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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 "Mappen er blevet oprettet."
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr "Der opstod en fejl ved hentning af jobbene for dit projekt."
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr "Der var en fejl ved hentning af topetiketterne for den valgte gruppe"
@@ -43447,14 +44194,8 @@ 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 "Vedhæftningen er blevet afkortet for ikke at overstige den maksimale tilladte vedhæftningsstørrelse på %{size_limit}. %{written_count} af %{count} %{issuables} er blevet medtaget. Overvej at eksportere igen med et mindre udvalg af %{issuables}."
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr "Vedhæftningen er blevet afkortet for ikke at overstige den maksimale tilladte vedhæftningsstørrelse på %{size_limit}. %{written_count} af %{issues_count} problemstillinger er blevet medtaget. Overvej at eksportere igen med et mindre udvalg af problemstillinger."
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr "Vedhæftningen er blevet afkortet for ikke at overstige den maksimale tilladte vedhæftningsstørrelse på %{size_limit}. %{written_count} af %{merge_requests_count} sammenlægningsanmodninger er blevet medtaget. Overvej at eksportere igen med et mindre udvalg af sammenlægningsanmodninger."
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
-msgstr "Vedhæftningen er blevet afkortet for ikke at overstige den maksimale tilladte vedhæftningsstørrelse på %{size_limit}. %{written_count} af %{requirements_count} krav er blevet medtaget. Overvej at eksportere igen med et mindre udvalg af krav."
+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 ""
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "Runneren vil kun køre på pipelines som er udløst på beskyttede grene"
@@ -44008,10 +44752,7 @@ msgstr "Variablen kan ikke maskeres."
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ msgstr ""
msgid "To get started, use the link below to confirm your account."
msgstr "Kom i gang ved at bruge linket nedenunder for at bekræfte din konto."
+msgid "To go to GitLab Pages, on the left sidebar, select %{pages_link}."
+msgstr ""
+
msgid "To help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ msgstr "Gruppen er allerede en rodmappe."
msgid "TransferGroup|Group is already associated to the parent group."
msgstr "Gruppe er allerede tilknyttet til forældergruppen."
+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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr "Twitter:"
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr "Type"
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr "U2F-enheder (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "U2F virker kun med HTTPS-aktiverede websteder. Kontakt din administrator for flere detaljer."
-
msgid "URL"
msgstr "URL"
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr "Ubegrænset"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr "Aflink"
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr "Ubrugt"
@@ -45614,6 +46367,9 @@ msgstr "Opdater dine bogmærkede URL'er når URL for filtrerede/sorterede grene
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 ""
@@ -45740,6 +46496,9 @@ msgstr "Forbrugstrends"
msgid "Usage statistics"
msgstr "Forbrugsstatistik"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 "Brug linket nedenunder for at bekræfte din e-mailadresse (%{email})"
@@ -46127,6 +46892,9 @@ msgstr ""
msgid "Use the search bar on the top of this page"
msgstr "Brug søgelinjen øverst på siden"
+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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr "Brugeridentiteten blev oprettet."
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr "Elementer i stadie"
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr "Vis dokumentation"
msgid "View eligible approvers"
msgstr "Vis kvalificerede godkendere"
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 "%{statusStart}Bekræftet%{statusEnd} %{timeago} af %{user}"
@@ -47506,12 +48346,6 @@ msgstr "Vi kunne ikke finde nogle %{scope} som matcher %{term} i projektet %{pro
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "Vi registererede potentiel spam i %{humanized_resource_name}. Løs venligst reCAPTCHA'en for at fortsætte."
@@ -47563,9 +48397,6 @@ msgstr "Vi vil underrette %{inviter} om at du afviste deres invitation til at de
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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "Vi bruger det til at hjælpe med at fremfinde de rette funktioner og information til dig."
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ msgstr "NÃ¥r protokollerne %{code_open}http://%{code_close} eller %{code_open}ht
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] ""
@@ -48008,6 +48847,9 @@ msgstr "Hvem vil komme til at bruge gruppen?"
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr "Igangværende arbejde (åbne og tildelte)"
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr "Vil du oprette en ny gren?"
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "Skriv dine udgivelsesnoter eller træk dine filer hertil …"
@@ -48912,9 +49781,6 @@ msgstr "Du har ikke tilladelse til at opdatere miljøet."
msgid "You do not have permissions to run the import."
msgstr "Du har ikke tilladelser til at køre importen."
-msgid "You don't have any U2F devices registered yet."
-msgstr "Du har endnu ikke tilmeldt nogle U2F-enheder."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr "Du har endnu ikke tilmeldt nogle WebAuthn-enheder."
@@ -49085,12 +49951,18 @@ msgstr ""
msgid "You must provide a valid current password"
msgstr "Du skal angive en gyldig nuværende adgangskode"
+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 "Du skal angive din nuværende adgangskode for at ændre den."
+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 "Du skal logge ind for at søge efter bestemte projekter."
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,8 +50145,8 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
-msgstr "Din CSV-eksport af %{written_count} fra projektet %{project_name} (%{project_url}) er blevet tilføjet til e-mailen som en vedhæftning."
+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 import for project"
msgstr ""
@@ -49300,6 +50175,9 @@ msgstr "Din GitLab-gruppe"
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 "Dine grupper"
@@ -49324,6 +50202,9 @@ msgstr "Din SSH-nøgle blev slettet"
msgid "Your SSH keys (%{count})"
msgstr "Dine SSH-nøgler (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "Din gøremålsliste"
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr "Din handling lykkedes."
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "Dine programmer (%{size})"
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr "Din browser understøtter ikke iFrames"
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "Din browser understøtter ikke U2F. Brug venligst Google Chrome desktop (version 41 eller nyere)."
-
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+)."
@@ -49411,6 +50292,9 @@ msgstr "Din kommentar kasseres."
msgid "Your commit email is used for web based operations, such as edits and merges."
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 "Din nuværende adgangskode kræves for at tilmelde et totrinsgodkendelsesprogram."
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ msgstr "kan kun ændres af en gruppeadministrator."
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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Løsning"
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST)"
msgstr ""
@@ -50510,9 +51403,6 @@ msgstr[1] "filer"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr "følger"
-
msgid "for"
msgstr ""
@@ -50818,11 +51708,17 @@ msgstr "låst af %{path_lock_user_name} %{created_at}"
msgid "manual"
msgstr "manuelt"
-msgid "math|Displaying this math block may cause performance issues on this page"
-msgstr "Visning af math-blokken kan forårsage ydelsesproblemer på siden"
+msgid "math|Displaying this math block may cause performance issues on this page."
+msgstr ""
-msgid "math|There was an error rendering this math block"
-msgstr "Der opstod en fejl ved gengivelse af math-blokken"
+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"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr "%{mergeError}."
@@ -50894,6 +51868,12 @@ msgstr "%{metricsLinkStart} Hukommelsesforbrug %{metricsLinkEnd} %{emphasisStart
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart} Hukommelsesforbrug %{metricsLinkEnd} er %{emphasisStart} uændret %{emphasisEnd} på %{memoryFrom} MB"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr "Godkendelse er valgfrit"
msgid "mrWidget|Approval password is invalid."
msgstr "Godkendelsesadgangskode er ugyldig."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr "Godkend"
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,84 +51998,30 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] "Nævner problemstilling"
msgstr[1] "Nævner problemstillinger"
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "Sammenlægning blokeret: alle tråde skal være løst."
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr "Sammenlægning blokeret: pipeline skal lykkes. Den venter på en manuel handling for at fortsætte."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "Sammenlægning mislykkedes."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr "Sammenlagt af"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr "Sammenlægger! Ændringer er ved at blive sendt afsted …"
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr "Sammenlægger! Ændringerne kommer snart …"
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr "Sammenlægger! Trommehvirvel, tak …"
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr "Sammenlægger! Det ser altsammen godt ud …"
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
+msgid "mrWidget|More information"
+msgstr "Mere information"
-msgid "mrWidget|Merging! Take a deep breath and relax…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Merging! The changes are leaving the station…"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr "Sammenlægger! Det skal nok blive godt …"
-
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "Sammenlægger! Vi er der næsten …"
-
-msgid "mrWidget|More information"
-msgstr "Mere information"
-
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "Klar til at blive sammenlagt automatisk. Spørg nogen med skriveadgang til depotet om at sammenlægge anmodningen"
-
msgid "mrWidget|Refresh"
msgstr "Opdater"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr "skal være en gyldig IPv4- eller IPv6-adresse"
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr "skal være efter start"
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index 1cf3798db41..90457532ce9 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr " %{start} bis %{end}"
@@ -426,6 +426,11 @@ msgid_plural "%d unresolved threads"
msgstr[0] "%d ungelöster Thread"
msgstr[1] "%d ungelöste Threads"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d Sicherheitslücke"
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "%d Warnung gefunden:"
msgstr[1] "%d Warnungen gefunden:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s zusätzlicher Commit wurde ausgelassen um Leistungsprobleme zu verhindern."
msgstr[1] "%s zusätzliche Commits wurden ausgelassen um Leistungsprobleme zu verhindern."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr "%{count} verwandte %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "%{count} ausgewählt"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} Gesamtgewichtung"
@@ -831,6 +850,9 @@ msgstr "%{level_name} ist nicht zulässig, da das Fork-Quellprojekt eine geringe
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow} und %{awardsListLength} weitere"
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} können zusammenführen"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} zeigt zuerst %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (vergangen)"
@@ -982,6 +1001,9 @@ msgstr "%{reportType} erkannte %{totalStart}%{total}%{totalEnd} potentielle %{vu
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} hat ein Ticket erstellt: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} ist nicht in der Liste enthalten"
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "Eine Gruppe"
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr "Einen zusammenklappbaren Abschnitt hinzufügen"
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr "Füge zu deinem Wiki eine Startseite mit Informationen zu deinem GitLab-
msgid "Add a new issue"
msgstr "Neues Ticket hinzufügen"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Eine nummerierte Liste hinzufügen"
@@ -2263,6 +2280,9 @@ msgstr "Verwandtes Epic hinzufügen"
msgid "Add a related issue"
msgstr "Verwandtes Problem hinzufügen"
+msgid "Add a reply"
+msgstr ""
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -2377,6 +2397,9 @@ msgstr "Neue Anwendung hinzufügen"
msgid "Add new directory"
msgstr "Erstelle eine neues Verzeichnis"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr "Zusätzlicher Text"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
msgstr "Alle Mitglieder"
+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 "Alle Branches"
@@ -4727,6 +4726,9 @@ msgstr "Beim Starten des Web-Terminals ist ein unerwarteter Fehler aufgetreten."
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Beim Beenden des Web-Terminals ist ein unerwarteter Fehler aufgetreten."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr "Analysen"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ msgstr "Beende den Kommentar mit %{shrug}"
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|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."
+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."
@@ -4965,12 +5099,18 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "Siehe %{linkStart}Passwortrichtlinien%{linkEnd}."
+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 ""
@@ -5215,6 +5355,11 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Einen Merge-Request genehmigen"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 "Der aktuelle Merge-Request wurde genehmigt."
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,8 +5823,8 @@ msgstr[1] "%d Dateien anhängen"
msgid "Attaching the file failed."
msgstr "Die Datei konnte nicht angehängt werden."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
-msgstr "Es wurde versucht, sich mit einem falschen Zwei-Faktor-Authentifizierungscode bei %{host} anzumelden"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
+msgstr ""
msgid "Audit Events"
msgstr "Audit-Ereignisse"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr "Autorisierungscode:"
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr "Autorisieren"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "Autorisierst du %{link_to_client} dein Konto zu verwenden?"
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr "%{new_chat_name} autorisiert"
@@ -5949,9 +6098,18 @@ msgstr "Autorisiert bei"
msgid "Authorized applications (%{size})"
msgstr "Autorisierte Anwendungen (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr "Vorsicht. Änderungen am Projektnamensraum können unbeabsichtigte Neben
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Vorsicht. Das Umbenennen des Projekt-Repositorys kann unbeabsichtigte Nebenwirkungen haben."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr "Unten findest du alle Gruppen, die öffentlich sind."
-msgid "Beta"
-msgstr "Beta"
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr "Bitbucket-Import"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ msgstr[1] ""
msgid "Boards|Collapse"
msgstr "Einklappen"
+msgid "Boards|Create new epic"
+msgstr ""
+
+msgid "Boards|Create new issue"
+msgstr ""
+
msgid "Boards|Edit board"
msgstr "Board bearbeiten"
+msgid "Boards|Edit list settings"
+msgstr ""
+
msgid "Boards|Expand"
msgstr ""
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr ""
+msgid "Boards|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr "Karte verschieben"
@@ -7001,9 +7153,6 @@ msgstr "An den Anfang der Liste verschieben"
msgid "Boards|New board"
msgstr "Neues Board"
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr "Rollen"
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ msgstr "(x%{numberOfUsers})"
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 ""
@@ -8525,6 +8701,9 @@ 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 "Neue Gruppe erstellen"
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "Benötigst du weitere Benutzer? Kaufe GitLab für deine %{company}."
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "Status"
@@ -8726,12 +8911,18 @@ msgstr "Inhalte auswählen, die du auf Gruppenübersichtsseiten sehen willst."
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 "Wähle welche Repositories du verbinden und die CI/CD-Pipelines ausführen möchtest."
msgid "Choose your framework"
msgstr "Wähle dein Framework"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr "warte"
msgid "CiStatus|running"
msgstr "laufend"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "Vergleiche Revisionen"
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr "Vergleiche Änderungen mit dem letzten Commit"
msgid "Compare changes with the merge request target branch"
msgstr "Vergleiche die Änderungen mit dem Zielbranch des Merge-Requests"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "Vertraulichkeit"
-msgid "Configuration"
-msgstr "Konfiguration"
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr "Du bist dabei, das Repository %{title} zu entfernen. Sobald du bestätig
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr "Beitrag"
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr "Beiträge pro Gruppenmitglied"
msgid "Contributor"
msgstr "Mitwirkender"
-msgid "Contributors"
-msgstr "Mitwirkende"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "Lege mit deinem Konto verknüpfte E-Mails fest"
@@ -11351,6 +11587,9 @@ msgstr "Befehle kopieren"
msgid "Copy commit SHA"
msgstr "Commit-SHA kopieren"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr "Erstellt am"
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ msgstr "Einstellungen"
msgid "CurrentUser|Start an Ultimate trial"
msgstr ""
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr ""
+
msgid "Currently unable to fetch data for this pipeline."
msgstr ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr "DAST-Konfiguration nicht gefunden"
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr "Release %{release} löschen?"
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr "Für Informationen zu einem möglichen Ersatz %{epicStart} erfahre mehr über Opstrace %{epicEnd}."
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr "Entwickler"
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr "Discord-Benachrichtigungen"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr "Entdecke GitLab Geo"
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr "Beschreibung bearbeiten"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "Umgebung bearbeiten"
@@ -15239,6 +15496,9 @@ msgstr "Identität für %{user_name} bearbeiten"
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "Öffentlichen Bereitstellungsschlüssel bearbeiten"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "Epic wurde nicht gefunden."
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr "Beweissammlung"
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ msgstr "Wenn kein Klassifizierungslabel gesetzt ist, wird das Standardlabel `%{d
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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr "Feb"
msgid "February"
msgstr "Februar"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "Ergebnisse filtern"
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,14 +19089,23 @@ msgstr "Berichtszeitraum muss eine Zahl sein."
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "Berichtszeitraum sollte zwischen %{minTimePeriod}-%{maxTimePeriod} Sekunden liegen."
+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 "Die maximale Anzahl eindeutiger Repositories, die ein Benutzer in einem bestimmten Zeitraum herunterladen kann, bevor er gesperrt wird."
+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 "Benutzer, die von der Begrenzung der Git-Missbrauchsrate ausgeschlossen sind."
-msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
-msgstr "Du kannst nicht mehr als %{maxExcludedUsers} ausgeschlossene Benutzer angeben."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr ""
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab erstellt einen Branch in deinem Fork und startet ein Merge Request."
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Deine Pages-Konfiguration wird aktualisiert..."
+msgid "GitLabPages|Use unique domain"
+msgstr ""
+
msgid "GitLabPages|Verified"
msgstr ""
msgid "GitLabPages|Waiting for the Pages Pipeline to complete..."
msgstr "Warten, bis die Pages-Pipeline abgeschlossen ist..."
+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 ""
@@ -19092,6 +19395,9 @@ msgstr "Gitea-Host-URL"
msgid "Gitea Import"
msgstr "Gitea-Import"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr "Inhalt der Gruppenübersicht"
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,8 +21638,8 @@ msgstr ""
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "Wenn du dich kürzlich angemeldet hast und die IP-Adresse erkennst, kannst du diese E-Mail ignorieren."
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email."
-msgstr "Wenn Du vor kurzem versucht hast, Dich anzumelden, aber versehentlich einen falschen Code für die Zwei-Faktor-Authentifizierung eingegeben hast, kannst Du diese E-Mail ignorieren."
+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 ""
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr "Titel"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "Jobs"
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Verlasse die Gruppe"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr "Verfügbare Repositories auflisten"
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ msgstr "Beitragsstatistiken für Gruppenmitglieder laden"
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr ""
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr "Auf aktuelle Projekte beschränken"
msgid "Locked"
msgstr "Gesperrt"
-msgid "Locked Files"
-msgstr "Gesperrte Dateien"
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "ZUSAMMENGEFÃœHRT"
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr "Merge-Requests dienen dazu, deine Änderungsvorschläge für ein Projekt
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] "Meilensteine"
msgid "Milestone due date"
msgstr "Fälligkeitsdatum des Meilensteins"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "Meilensteinlisten ist mit deiner momentanen Lizenz nicht verfügbar"
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr "Minuten"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr "Richtung der Spiegelung"
@@ -27318,6 +27764,9 @@ msgstr "Repository spiegeln"
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr "Benutzer(in) spiegeln"
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr "Neue Anforderung"
msgid "New Snippet"
msgstr "Neuer Codeausschnitt"
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr "Neues Passwort"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "Neues Projekt"
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ msgstr "%{paragraph_start}Hallo %{name}!%{paragraph_end} %{paragraph_start}Ein n
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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 "Projekt %{old_path_with_namespace} wurde an einen anderen Ort verschoben."
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr "Ausstehende Löschung"
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "Ausstehende Löschung"
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr "Pipeline"
@@ -30941,6 +31453,9 @@ msgstr "Warten auf Laden von CI-Inhalten..."
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 ""
@@ -31166,6 +31681,9 @@ msgstr "Pipelines"
msgid "Pipelines charts"
msgstr "Pipelinediagramme"
+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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,8 +31837,8 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
-msgstr "Die Pipeline-Syntax ist korrekt."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr "Der Projekt-Cache wurde erfolgreich zurückgesetzt."
@@ -31325,6 +31846,9 @@ msgstr "Der Projekt-Cache wurde erfolgreich zurückgesetzt."
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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ msgstr ""
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
msgstr "Beim Abrufen der Pipelines ist ein Fehler aufgetreten. Versuche es in einigen Augenblicken noch einmal oder wende dich an dein Support-Team."
-msgid "Pipelines|This GitLab CI configuration is invalid."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr "Diagrammvorschau"
msgid "Preview payload"
msgstr "Vorschau der Nutzdaten"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "Vorherige Artefakte"
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ msgstr "Verbindung trennen"
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|Do not show on profile"
msgstr "Nicht im Profil zeigen"
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Du musst die Eigentumsrechte dieser Gruppen übertragen oder die Gruppen löschen, bevor du dein Konto löschen kannst."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Projektname"
@@ -33092,6 +33598,9 @@ msgstr "Projekt oder Gruppe"
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ msgstr "Die Sichtbarkeitsebene des Projekts ist weniger restriktiv als die Grupp
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 ""
@@ -33215,9 +33727,21 @@ msgstr "Projekt ID: %{project_id}"
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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ msgstr "Deine Daten von einer externen Quelle wie GitHub, Bitbucket oder einer a
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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr "Du kannst den Zugriff auf geschützte Branches einschränken, indem du eine Rolle (Betreuer, Entwickler) sowie bestimmte Benutzer auswählst."
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} wird für Entwickler änderbar sein. Bist du sicher?"
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "Für Bereitstellung zugelassen"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] "In einer Sekunde aktualisieren, um den aktualisierten Status anzuzeigen..."
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr "Bezug zu %{issuable_type} %{add_related_issue_link}"
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr ""
-
msgid "Requirements"
msgstr "Anforderungen"
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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr "Fortsetzen"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr "Wiederholen"
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr "Administrator"
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr "Leerlauf"
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr "Eigentümer(in)"
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr "Empfohlen"
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr "Runner Registrierung"
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "Laufend"
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr "SAML Single Sign-On"
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr "Sicherheit"
-msgid "Security & Compliance"
-msgstr "Sicherheit & Compliance"
-
-msgid "Security Configuration"
-msgstr ""
-
msgid "Security Dashboard"
msgstr "Sicherheits-Dashboard"
msgid "Security Finding not found"
msgstr "Sicherheitsergebnis nicht gefunden"
-msgid "Security dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security navigation"
+msgid "Security and Compliance"
+msgstr ""
+
+msgid "Security capabilities"
+msgstr ""
+
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr "Anmelden"
-msgid "Sign in / Register"
-msgstr "Anmelden / Registrieren"
-
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 ""
@@ -40008,15 +40683,33 @@ msgstr "Die Slack-Integration ermöglicht es dir, mit GitLab über Slash-Befehle
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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr "Spam- und Anti-Bot-Schutz"
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr "Test"
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr "Das Ticketsystem ist der Ort, um Dinge hinzuzufügen, die in einem Proje
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Die Verbindung wird nach %{timeout} beendet. Verwende eine Clone/Push-Kombination für Repositorys, die länger brauchen."
@@ -42600,6 +43332,9 @@ msgstr ""
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "Die Bereitstellung dieses Jobs auf %{environmentLink} war nicht erfolgreich."
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "Dieser Runner wird nur Pipelines von geschützen Branches ausführen"
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ msgstr "Gib zunächst deine Gitea-Host-URL und einen %{link_to_personal_token} e
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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr "Pipelines für Mirror-Updates auslösen"
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr "Zwei-Faktor-Authentifizierung"
-msgid "Two-Factor Authentication code"
-msgstr "Zwei-Faktor-Authentifizierungscode"
-
msgid "Two-factor Authentication"
msgstr "Zwei-Faktor-Authentifizierung"
@@ -45191,12 +45932,6 @@ msgstr "Typ"
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr "Entsperren"
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ msgstr ""
msgid "Update your group name, description, avatar, and visibility."
msgstr "Deine Gruppenbezeichnung, Beschreibung, Avatar und Sichtbarkeit anpassen."
+msgid "Update your project name and description."
+msgstr ""
+
msgid "Update your project name, topics, description, and avatar."
msgstr ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr "Nutzungsstatistiken"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ msgstr ""
msgid "Use the search bar on the top of this page"
msgstr "Verwende die Suchleiste oben auf dieser Seite"
+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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr "Geeignete Genehmigungsberechtigte anzeigen"
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "Wir haben potenziellen Spam in %{humanized_resource_name} gefunden. Bitte löse den reCAPTCHA um fortzufahren."
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "Wir verwenden dies, um dir die richtigen Funktionen und Informationen anzuzeigen."
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr "Wer wird diese Gruppe verwenden?"
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr "Aufgabe gelöscht"
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr "Eine interne Notiz schreiben oder Dateien hierher ziehen…"
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ msgstr "Du musst Betreuerzugriff besitzen, um das Entfernen einer Sperre zu erzw
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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,8 +50145,8 @@ msgstr "Dein CSV-Export hat begonnen. Es wird nach Abschluss per E-Mail an %{ema
msgid "Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment."
msgstr "Der CSV-Export von %{count} aus dem Projekt %{project_link} wurde dieser E-Mail als Anhang hinzugefügt."
-msgid "Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
-msgstr "Der CSV-Export von %{written_count} aus dem Projekt %{project_name} (%{project_url}) wurde dieser E-Mail als Anhang hinzugefügt."
+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 import for project"
msgstr ""
@@ -49300,6 +50175,9 @@ 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 "Deine Gruppen"
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr "Deine SSH-Schlüssel (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "Deine Anwendungen (%{size})"
@@ -49378,9 +50262,6 @@ msgstr "Deine autorisierten Anwendungen"
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr "Vollständiger Bericht"
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Lösung"
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST)"
msgstr ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr "gesperrt durch %{path_lock_user_name} %{created_at}"
msgid "manual"
msgstr "manuell"
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr "%{metricsLinkStart} Speicherauslastung %{metricsLinkEnd} %{emphasisStart
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart} Speicherauslastung %{metricsLinkEnd} ist %{emphasisStart} unverändert %{emphasisEnd} bei %{memoryFrom} MB"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr "Genehmigung ist optional"
msgid "mrWidget|Approval password is invalid."
msgstr "Falsches Zustimmungspasswort."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr "Genehmigen"
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,84 +51998,30 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "Merge fehlgeschlagen."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr "Merged von"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
+msgid "mrWidget|More information"
+msgstr "Weitere Informationen"
-msgid "mrWidget|Merging! Take a deep breath and relax…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Merging! The changes are leaving the station…"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Merging! This is going to be great…"
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
-msgid "mrWidget|More information"
-msgstr "Weitere Informationen"
-
-msgid "mrWidget|No users match the rule's criteria."
-msgstr ""
-
-msgid "mrWidget|Please restore it or use a different %{type} branch."
-msgstr ""
-
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "Bereit zum automatischen Mergen. Bitte jemanden mit Schreibrechten zu diesem Repository diesen Merge-Request zu mergen"
-
msgid "mrWidget|Refresh"
msgstr "Aktualisieren"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/el_GR/gitlab.po b/locale/el_GR/gitlab.po
index a1a9f05f749..72be2826f4d 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/en_GB/gitlab.po b/locale/en_GB/gitlab.po
index 5482d5837a0..ff632c7a52d 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-02-11 04:46\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr " %{start} to %{end}"
@@ -426,6 +426,11 @@ msgid_plural "%d unresolved threads"
msgstr[0] "%d unresolved thread"
msgstr[1] "%d unresolved threads"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d vulnerability"
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "%d warning found:"
msgstr[1] "%d warnings found:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s additional commit has been omitted to prevent performance issues."
msgstr[1] "%s additional commits have been omitted to prevent performance issues."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr "%{count} related %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "%{count} selected"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} total weight"
@@ -831,6 +850,9 @@ msgstr "%{level_name} is not allowed since the fork source project has lower vis
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 "Must be %{minimumNumberOfUsers} (your seats in use) or more."
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr "Diagram (%{language})"
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,14 +19089,23 @@ msgstr "Reporting time period must be a number."
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
+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 "The maximum number of unique repositories a user can download in the specified time period before they're banned."
+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 "Users who are excluded from the Git abuse rate limit."
-msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
-msgstr "You cannot specify more than %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr ""
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Updating your Pages configuration..."
+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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr "all GitLab"
-msgid "GlobalSearch|group"
-msgstr "group"
-
msgid "GlobalSearch|in %{scope}"
msgstr "in %{scope}"
-msgid "GlobalSearch|project"
-msgstr "project"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 "For added security, you'll need to verify your identity. We've sent a verification code to %{email}"
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,8 +23434,8 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
-msgstr "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr ""
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ msgstr ""
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "Start a free trial of GitLab Ultimate"
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr ""
+
msgid "LearnGitLab|Submit a merge request (MR)"
msgstr ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr "Pipeline %{pipeline_link} triggered by"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr "Preview diagram"
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Instrument your application"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr "Something went wrong while fetching projects"
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr "Dismiss Service Desk promotion"
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr "Rebase completed"
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ msgstr ""
msgid "Runners|Get started with runners"
msgstr "Get started with runners"
+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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr "If both settings are disabled, new runners cannot be registered."
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ msgstr "Upgrade recommended"
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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ 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 "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "Are you sure you want to cancel editing?"
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr "Closed"
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr "Task deleted"
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ msgstr "Your %{spammable_entity_type} has been recognised as spam. Please, chang
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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 "can't be enabled when delayed group deletion is disabled"
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr "for"
@@ -50818,11 +51708,17 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
-msgstr "Displaying this maths block may cause performance issues on this page"
+msgid "math|Displaying this math block may cause performance issues on this page."
+msgstr ""
-msgid "math|There was an error rendering this math block"
-msgstr "There was an error rendering this maths block"
+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"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr "Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr "Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr "Merge blocked: All required approvals must be given."
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr "Merge blocked: denied licences must be removed."
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "No users match the rule's criteria."
-
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index 163e8a6022d..2a517810e17 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s enmetado estis transsaltita, por ne troÅarÄi la sistemon."
msgstr[1] "%s enmetadoj estis transsaltitaj, por ne troÅarÄi la sistemon."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr "Aldoni novan dosierujon"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr "plenumiÄanta"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
-msgstr "Kontribuantoj"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr ""
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Forlasi la grupon"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr "Ĉenstablo"
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ msgstr "Ĉenstabloj"
msgid "Pipelines charts"
msgstr "Ĉenstablaj diagramoj"
+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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index 4af3e7d19c3..b8e6cebe2cd 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-02-11 04:19\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr " %{start} hasta %{end}"
@@ -426,6 +426,11 @@ msgid_plural "%d unresolved threads"
msgstr[0] "%d hilo sin resolver"
msgstr[1] "%d hilos sin resolver"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d vulnerabilidad"
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "%d advertencia encontrada:"
msgstr[1] "%d advertencias encontradas:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "se ha omitido %s cambio adicional para evitar problemas de rendimiento."
msgstr[1] "se han omitido %s cambios adicionales para evitar problemas de rendimiento."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr "%{count} %{pluralized_subject} relacionados: %{links}"
msgid "%{count} selected"
msgstr "%{count} seleccionados"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} peso total"
@@ -831,6 +850,9 @@ msgstr "%{level_name} no está permitido debido a que el fork del proyecto orige
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}, y %{awardsListLength} más"
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} puede hacer merge"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} mostrando el primer %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (expirado)"
@@ -982,6 +1001,9 @@ msgstr "%{reportType} detectó %{totalStart}%{total}%{totalEnd} potencial %{vuln
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr "%{user} creó una tarea épica: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} creó una incidencia: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} no está incluido en la lista"
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] "1 clave de despliegue"
msgstr[1] "%d claves de despliegue"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "1 seguidor"
-msgstr[1] "%{count} seguidores"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grupo"
@@ -1813,9 +1833,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "API Fuzzing"
-msgid "API Fuzzing Configuration"
-msgstr "Configuración de API Fuzzing"
-
msgid "API Help"
msgstr "Ayuda de la API"
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr "Añadir una sección colapsable"
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr "Añadir un comentario a esta línea"
@@ -2254,6 +2268,9 @@ msgstr "Añada una página de inicio a su wiki que contenga información sobre s
msgid "Add a new issue"
msgstr "Añadir una nueva incidencia"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Añadir una lista numerada"
@@ -2263,6 +2280,9 @@ msgstr ""
msgid "Add a related issue"
msgstr "Añadir una incidencia relacionada"
+msgid "Add a reply"
+msgstr ""
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -2377,6 +2397,9 @@ msgstr "Añadir una nueva aplicación"
msgid "Add new directory"
msgstr "Añadir nuevo directorio"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr "Minutos adicionales:"
msgid "Additional text"
msgstr "Texto adicional"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr "Texto adicional para mostrar en la página de inicio de sesión y ayuda."
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr "Todo GitLab"
msgid "All Members"
msgstr "Todos los miembros"
+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 "Todas las ramas"
@@ -4727,6 +4726,9 @@ msgstr "Se ha producido un error inesperado al iniciar el Terminal Web."
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Se ha producido un error inesperado al detener el Terminal Web."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr "Se ha producido un error desconocido mientras se cargaba este gráfico."
@@ -4736,6 +4738,123 @@ msgstr "Se ha producido un error desconocido."
msgid "Analytics"
msgstr "Analíticas"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analizar sus dependencias en busca de vulnerabilidades conocidas."
@@ -4814,13 +4933,28 @@ msgstr "Añadir el comentario con %{shrug}"
msgid "Append the comment with %{tableflip}"
msgstr "Añadir el comentario con %{tableflip}"
+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|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."
+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."
@@ -4965,12 +5099,18 @@ msgstr "Guardar cambios"
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 ""
@@ -5215,6 +5355,11 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Aprobar el merge request"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5227,6 +5372,16 @@ msgstr "Aprobado"
msgid "Approved MRs"
msgstr "MRs aprobados"
+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 "Aprobado el merge request actual."
@@ -5302,9 +5457,6 @@ msgstr "¿Está seguro que desea %{action} %{name}?"
msgid "Are you sure you want to approve %{user}?"
msgstr "¿Está seguro de que desea aprobar a %{user}?"
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ msgstr "¿Está seguro de que desea cerrar esta incidencia bloqueada?"
msgid "Are you sure you want to delete %{name}?"
msgstr "¿Estás seguro de que deseas eliminar %{name}?"
+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 "¿Está seguro que quiere eliminar este %{commentType}?"
@@ -5668,7 +5823,7 @@ msgstr[1] "Adjuntar %d archivos"
msgid "Attaching the file failed."
msgstr "Se ha producido un error al adjuntar el archivo."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr "Creado %{timeago} por %{author}"
msgid "Authorization code:"
msgstr "Código de autorización:"
-msgid "Authorization required"
-msgstr "Autorización requerida"
-
msgid "Authorization token duration (minutes)"
msgstr "Duración del token de autorización (minutos)"
@@ -5937,9 +6089,6 @@ msgstr "Autorizar"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "¿Autorizar %{link_to_client} para utilizar su cuenta?"
-msgid "Authorize %{user} to use your account?"
-msgstr "¿Autorizar a %{user} para utilizar su cuenta?"
-
msgid "Authorized %{new_chat_name}"
msgstr "Autorizado %{new_chat_name}"
@@ -5949,9 +6098,18 @@ msgstr "Autorizado en"
msgid "Authorized applications (%{size})"
msgstr "Aplicaciones autorizadas (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr "Tenga cuidado. Cambiar el espacio de nombres del proyecto puede tener ef
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Tenga cuidado. Cambiar el nombre del repositorio de un proyecto puede tener efectos secundarios no deseados."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr "A continuación se muestran los ajustes relativos a %{link_to_gitlab_pag
msgid "Below you will find all the groups that are public."
msgstr "A continuación encontrará todos los grupos públicos."
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr "Cobertura de código quincenal"
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr "Si deseas cambiar su plan, por favor, póngase en contacto con %{support
msgid "BillingPlans|Includes free static websites"
msgstr "Incluye sitios web estáticos gratuitos"
-msgid "BillingPlans|Learn more"
-msgstr "Más información"
-
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}, or start a free 30-day trial of GitLab.com Ultimate."
msgstr ""
@@ -6585,27 +6743,9 @@ msgstr "Actualizar"
msgid "BillingPlan|Upgrade for free"
msgstr "Actualizar gratuitamente"
-msgid "Billings|%{planName} plan"
-msgstr "Plan %{planName}"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr "Se ha producido un error al extender su periodo de prueba."
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr "Se ha producido un error al reactivar su periodo de prueba."
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr "Extender el periodo de prueba"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr "Reactivar el periodo de prueba"
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr "Importar desde Bitbucket"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ msgstr[1] ""
msgid "Boards|Collapse"
msgstr "Contraer"
+msgid "Boards|Create new epic"
+msgstr ""
+
+msgid "Boards|Create new issue"
+msgstr ""
+
msgid "Boards|Edit board"
msgstr "Editar tablero"
+msgid "Boards|Edit list settings"
+msgstr ""
+
msgid "Boards|Expand"
msgstr "Expandir"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr ""
+msgid "Boards|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr "Nuevo tablero"
-msgid "Boards|New epic"
-msgstr "Nueva épica"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ msgstr "No se puede aplicar esta sugerencia."
msgid "Can't be empty"
msgstr "No puede estar vacío"
+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 "No se puede crear el fragmento de código: %{err}"
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+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 ""
@@ -8525,6 +8701,9 @@ msgstr "País"
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 "Crear un nuevo grupo"
@@ -8534,18 +8713,15 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "Editar"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr ""
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr ""
@@ -8570,6 +8746,9 @@ msgstr "Plan de GitLab"
msgid "Checkout|Group"
msgstr "Grupo"
+msgid "Checkout|Invalid coupon code. Enter a valid coupon code."
+msgstr ""
+
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
msgstr ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "¿Necesita más usuarios? Compre GitLab para su %{company}."
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "Número de usuarios"
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "Estado"
@@ -8726,12 +8911,18 @@ 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 "Elija que repositorios quiere conectar y ejecutar los CI/CD pipelines."
msgid "Choose your framework"
msgstr "Seleccione su marco de trabajo"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr "Rango de fechas: %{range}"
@@ -8810,12 +9001,12 @@ msgstr "Esperando"
msgid "CiStatus|running"
msgstr "en ejecución"
+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|Clear inputs"
-msgstr ""
-
msgid "CiVariables|Environments"
msgstr "Entornos"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr "Protegido"
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ msgstr ""
msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
msgstr "El usuario no tiene permisos suficientes para crear un token para este proyecto"
+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 "No tiene permisos suficientes para crear un agente de clúster para este proyecto"
@@ -9915,7 +10112,7 @@ msgstr "El certificado Kubernetes utilizado para autenticarse en el clúster."
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "La URL utilizada para acceder a la API de Kubernetes."
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr "Compare las ediciones de GitLab"
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "Comparar revisiones"
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr "Comparar los cambios con el último commit"
msgid "Compare changes with the merge request target branch"
msgstr "Comparar los cambios con la rama de destino del merge request"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr "Completado"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr "Framework de cumplimiento"
msgid "Compliance report"
msgstr "Informe de cumplimiento"
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Añadir framework"
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "Componente"
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "Confidencialidad"
-msgid "Configuration"
-msgstr "Configuración"
-
msgid "Configuration help"
msgstr "Ayuda de configuración"
@@ -11150,6 +11368,9 @@ msgstr "Está a punto de eliminar el repositorio %{title}. Una vez que confirme
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "Puede añadir una imagen a este registro utilizando los siguientes comandos:"
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr "Colaboración"
msgid "Contribution Analytics"
msgstr "Análisis de colaboración"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr "Contribuciones por cada miembro de un grupo"
msgid "Contributor"
msgstr "Colaborador"
-msgid "Contributors"
-msgstr "Contribuidores"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "Controle los correos electrónicos vinculados a su cuenta"
@@ -11351,6 +11587,9 @@ msgstr "Copiar los comandos"
msgid "Copy commit SHA"
msgstr "Copiar el SHA del commit"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr "Copiar entorno"
@@ -11597,8 +11836,8 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
-msgstr "País"
+msgid "Country / Region"
+msgstr ""
msgid "Counts"
msgstr ""
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr "Cree o importe su primer proyecto"
@@ -12035,9 +12277,6 @@ msgstr "Creado el"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "Creada una rama y un merge request para resolver esta incidencia."
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "Creada una rama '%{branch_name}' y un merge request para resolver esta incidencia."
@@ -12245,6 +12484,9 @@ msgstr "Preferencias"
msgid "CurrentUser|Start an Ultimate trial"
msgstr ""
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr ""
+
msgid "Currently unable to fetch data for this pipeline."
msgstr ""
@@ -12344,7 +12586,7 @@ msgstr "CycleAnalyticsEvent|Incidencia añadida por primera vez a un tablero"
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "Incidencia asociada por primera con un hito"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr "Configuración DAST"
-
msgid "DAST configuration not found"
msgstr "Configuración de DAST no encontrada"
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr "¿Eliminar la versión %{release}?"
msgid "Delete row"
msgstr "Eliminar fila"
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr "exitoso"
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,11 +14567,14 @@ msgstr "Se ha producido un error al crear el comentario. Por favor, inténtelo d
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "Se ha producido un error al crear una nueva discusión. Por favor, inténtelo de nuevo."
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
-msgstr "Se ha producido un error al actualizar la nota. Por favor, inténtelo de nuevo."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
+msgstr ""
msgid "DesignManagement|Deselect all"
msgstr "Deseleccionar todo"
@@ -14427,6 +14678,9 @@ msgstr "Adopción DevOps"
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr "Dispositivos (opcional)"
@@ -14622,6 +14876,9 @@ msgstr "Su uso"
msgid "Diagram (%{language})"
msgstr "Diagrama (%{language})"
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr "Notificaciones de Discord"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr "Descubrir"
-
msgid "Discover GitLab Geo"
msgstr "Descubra GitLab Geo"
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr "Editar descripción"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "Editar el entorno"
@@ -15239,6 +15496,9 @@ msgstr "Editar la identidad para %{user_name}"
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "Editar clave pública de despliegue"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr "Editar barra lateral"
@@ -15716,6 +15982,9 @@ msgstr "Introduzca el 2FA para el modo de administración"
msgid "Enter Admin Mode"
msgstr "Entrar en el modo de administración"
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "Introduzca un número"
@@ -15761,7 +16030,7 @@ msgstr "Introduzca la descripción de %{name}"
msgid "Enter the %{name} title"
msgstr "Introduzca el título de %{name}"
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "No es posible encontrar la tarea épica."
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 "Crear una política de escalado en GitLab"
@@ -16750,6 +17031,9 @@ msgstr "Recopilación de evidencias"
msgid "Exactly one of %{attributes} is required"
msgstr "Exactamente uno de los %{attributes} es necesario"
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ msgstr "Extracto de la política:"
msgid "Exceptions"
msgstr "Excepciones"
+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 ""
@@ -16975,6 +17262,9 @@ msgstr "Cuando no existe ninguna etiqueta de clasificación se utilizará la eti
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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr "Feb"
msgid "February"
msgstr "Febrero"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr "Filtrar pipelines"
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "Filtrar resultados"
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr "Formato: %{dateFormat}"
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ msgstr "El período de tiempo del informe debe ser un número."
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "El período de tiempo del informe debe estar entre %{minTimePeriod}y%{maxTimePeriod} segundos."
+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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr "GitLab Pages"
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr "GitLab Shell"
@@ -18883,6 +19182,12 @@ msgstr "Solicitud de cuenta de GitLab rechazada"
msgid "GitLab commit"
msgstr "GitLab commit"
+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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr "Sin verificar"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Actualizando su configuración de Pages..."
+msgid "GitLabPages|Use unique domain"
+msgstr ""
+
msgid "GitLabPages|Verified"
msgstr "Verificado"
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 ""
@@ -19092,6 +19395,9 @@ msgstr "URL del host de Gitea"
msgid "Gitea Import"
msgstr "Importar desde Gitea"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,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 "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr "todo GitLab"
-msgid "GlobalSearch|group"
-msgstr "grupo"
-
msgid "GlobalSearch|in %{scope}"
msgstr "en %{scope}"
-msgid "GlobalSearch|project"
-msgstr "proyecto"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 "¡Lo tengo!"
@@ -19722,6 +20052,9 @@ 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"
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "Hola %{username}!"
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ msgstr "Verifique su identidad"
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 ""
@@ -21206,15 +21560,24 @@ msgstr "Si está marcado, los propietarios de grupos pueden administrar enlaces
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "Si se marca, las nuevas miembros del grupo y los permisos sólo se pueden añadir a través de la sincronización vía LDAP"
+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 ""
@@ -21275,7 +21638,7 @@ msgstr "Si pierde los códigos de recuperación, puede generar otros nuevos, inv
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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr "Se ha producido un error al importar el proyecto"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,8 +22271,8 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr "InProductMarketing|Desarrollo rápido, simplificado"
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
-msgstr "InProductMarketing|Reduzca el riesgo de seguridad y cumplimiento"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
+msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
msgstr ""
@@ -22568,12 +22934,18 @@ msgstr "Insertar imagen"
msgid "Insert link"
msgstr "Insertar un enlace"
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr "Insertar fila después"
msgid "Insert row before"
msgstr "Insertar fila antes"
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "Insertar sugerencia"
@@ -22747,12 +23119,15 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
-msgstr "Editar el alias del proyecto"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
+msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
msgstr ""
+msgid "Integrations|Edit project alias"
+msgstr "Editar el alias del proyecto"
+
msgid "Integrations|Enable SSL verification"
msgstr ""
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr "Introduzca su alias"
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,8 +23434,8 @@ msgstr ""
msgid "Invalid repository path"
msgstr "Ruta del repositorio no válida"
-msgid "Invalid rule"
-msgstr "Regla inválida"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr "Respuesta del servidor no válida"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr "Incidencia no encontrada."
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr "Título"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr "Se reintentó el trabajo"
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "Trabajos"
@@ -24910,6 +25309,15 @@ msgstr "Obtener mas información."
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 ""
@@ -24991,6 +25399,9 @@ msgstr ""
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "Comience una prueba gratuita de GitLab Ultimate"
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr ""
+
msgid "LearnGitLab|Submit a merge request (MR)"
msgstr ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr "Salir del modo administrador"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "¿Desea salir del modo de edición? Se perderán todos los cambios no guardados."
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Abandonar grupo"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr "Cambios de línea"
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr "Enlace copiado"
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr "Lista de repositorios disponibles"
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ msgstr "Cargando las estadísticas de las colaboraciones de los miembros del gru
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr "Cargando archivos, directorios y submódulos en la ruta %{path} para la referencia del commit %{ref}"
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr "Cargar más"
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr "Bloquear membresías a la sincronización LDAP"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr "Bloquear al proyecto actual"
msgid "Locked"
msgstr "Bloqueado"
-msgid "Locked Files"
-msgstr "Archivos bloqueados"
-
msgid "Locked by %{fileLockUserName}"
msgstr "Bloqueado por %{fileLockUserName}"
@@ -25576,9 +25998,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr "Mostrar sólo los cambios"
msgid "MRDiff|Show full file"
msgstr "Mostrar el archivo completo"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr "Tamaño máximo para los archivos a subir al ejecutar un comando push (MB)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr "Los merge request son un lugar para proponer los cambios que ha realizad
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ msgstr "Ejecutar merge cuando el pipeline se ejecute con éxito"
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 "Commit a la rama origen"
@@ -27126,6 +27563,9 @@ msgstr[1] "Hitos"
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "Las listas de hitos no están disponibles con tu licencia actual"
@@ -27306,6 +27746,12 @@ msgstr "Capacidad mínima que debe estar disponible antes de que programemos má
msgid "Minutes"
msgstr "Minutos"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr "Dirección de la réplica"
@@ -27318,6 +27764,9 @@ msgstr "Replicar repositorio"
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr "Replicar usuario"
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr "Espacios de nombres"
msgid "Namespaces to index"
msgstr "Espacios de nombres a indexar"
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "Nombres, temas, avatar"
@@ -27794,10 +28261,16 @@ msgstr "Rojo"
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr "Nuevo requisito"
msgid "New Snippet"
msgstr "Nuevo fragmento de código"
-msgid "New Test Case"
-msgstr "Nuevo caso de prueba"
-
msgid "New User"
msgstr "Nuevo usuario"
@@ -28000,9 +28470,6 @@ msgstr "Nuevo nombre"
msgid "New password"
msgstr "Nueva contraseña"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "Nuevo proyecto"
@@ -28357,6 +28824,15 @@ msgstr "Sin cuentas de servicio"
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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr "Pipeline %{pipeline_link} activado por"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 "Repetir"
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ msgstr "Nuestro equipo ha sido notificado. Por favor, inténtalo de nuevo."
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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr "Escoja un nombre"
-msgid "Pin code"
-msgstr "Código pin"
-
msgid "Pipeline"
msgstr "Pipeline"
@@ -30941,6 +31453,9 @@ msgstr "Esperando que se cargue el contenido de CI..."
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 ""
@@ -31166,6 +31681,9 @@ msgstr "Pipelines"
msgid "Pipelines charts"
msgstr "Gráficos de los pipelines"
+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 "La configuración de los pipelines para '%{project_name}' se actualizó correctamente."
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,8 +31837,8 @@ msgstr "Propietario"
msgid "Pipelines|Pipeline Editor"
msgstr "Editor de pipeline"
-msgid "Pipelines|Pipeline syntax is correct."
-msgstr "La sintaxis del pipeline es correcta."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr "Caché del proyecto restablecida correctamente."
@@ -31325,6 +31846,9 @@ msgstr "Caché del proyecto restablecida correctamente."
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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ msgstr ""
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
msgstr "Se ha producido un error al obtener los pipelines. Por favor, inténtelo de nuevo en unos momentos o contacte con su equipo de soporte."
-msgid "Pipelines|This GitLab CI configuration is invalid."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ msgstr ""
msgid "Pipelines|Visualize"
msgstr "Visualizar"
+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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "Por favor, habilite y migre todos los proyectos existentes al almacenamiento de tipo hash para evitar problemas de seguridad y asegurar la integridad de los datos. %{migrate_link}"
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "Por favor, introduzca un número no negativo"
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,8 +32365,8 @@ msgstr "Por favor, seleccione"
msgid "Please select a Jira project"
msgstr "Por favor, seleccione un proyecto Jira"
-msgid "Please select a country"
-msgstr "Por favor, seleccione un país"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr "Por favor, seleccione un grupo"
@@ -32177,6 +32719,9 @@ msgstr "Vista previa del Diagrama"
msgid "Preview payload"
msgstr "Vista previa del payload"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "Artefactos anteriores"
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr "Continuar"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ msgstr "Desconectar"
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|Do not show on profile"
msgstr "No mostrar en el perfil"
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Debes transferir o eliminar estos grupos antes de que puedas eliminar tu cuenta."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr "Miembros del proyecto"
msgid "Project milestone"
msgstr "Hito del proyecto"
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Nombre del proyecto"
@@ -33092,6 +33598,9 @@ 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"
@@ -33119,6 +33628,9 @@ msgstr "El nivel de visibilidad del proyecto es menos restrictivo que la configu
msgid "Project visibility level will be changed to match namespace rules when transferring to a group."
msgstr "Se modificará el nivel de visibilidad del proyecto para hacerlo coincidir con las reglas del espacio de nombres al transferirlo a un grupo."
+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 ""
@@ -33215,9 +33727,21 @@ msgstr "ID de proyecto: %{project_id}"
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 "Cobertura"
+msgid "ProjectQualitySummary|Critical"
+msgstr ""
+
msgid "ProjectQualitySummary|Failure"
msgstr "Error"
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,8 +33799,11 @@ 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 "ProjectSelect| or group"
-msgstr "o grupo"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
msgid "ProjectSelect|No matching results"
msgstr ""
@@ -33287,9 +33817,6 @@ msgstr "Buscar proyectos"
msgid "ProjectSelect|Select a project"
msgstr "Seleccione un proyecto"
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr "Permitir"
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr "Interno"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr "Incidencias"
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr "Páginas"
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "La ejecución debe finalizar correctamente"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr "Fragmentos de código"
@@ -33965,6 +34477,9 @@ msgstr "Proyectos (%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr "Proyectos recuperados con éxito"
@@ -34091,6 +34606,9 @@ 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 "No hay opciones de importación disponibles"
@@ -34106,6 +34624,9 @@ msgstr "Configuración del proyecto"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "Descripción del proyecto %{tag_start}(opcional)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr "Descartar promoción de Service Desk"
@@ -34397,12 +34915,6 @@ msgstr "Cuando tienes muchas incidencias, puede ser difícil obtener una visión
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr "Solicitar a los usuarios que carguen claves SSH"
@@ -34574,9 +35086,25 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr "Por defecto"
+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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+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?"
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "Permitido desplegar"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr "Rebase"
-
msgid "Rebase completed"
msgstr "Reiniciar completado"
-msgid "Rebase in progress"
-msgstr "Rebase en progreso"
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] "Actualizar en un segundo para mostrar el estado actualizado..."
@@ -35200,13 +35746,13 @@ msgstr "Registro"
msgid "Register / Sign In"
msgstr "Registrarse / Iniciar sesión"
-msgid "Register Two-Factor Authenticator"
-msgstr "Registrar un dispositivo de autenticación de dos factores"
+msgid "Register a WebAuthn device"
+msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "Registrar un dispositivo universal de autenticación de dos factores (U2F)"
+msgid "Register a one-time password authenticator"
+msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr "Rechazado (cerrado)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr "Se ha reabierto el requisito %{reference}"
msgid "Requirement %{reference} has been updated"
msgstr "Se ha actualizado el requisito %{reference}"
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr "El título del requisito no puede tener más de %{limit} caracteres."
-
msgid "Requirements"
msgstr "Requisitos"
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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr "Reanudar"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr "Reintentar"
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ msgstr ""
msgid "Runners|Get started with runners"
msgstr "Runners|Empezar con los ejecutores"
+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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr "Recomendado"
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 "Token de registro"
@@ -37001,6 +37598,9 @@ msgstr "Ejecutor #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ msgstr "Runners|Actualización recomendada"
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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr "Propietario"
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "En ejecución"
@@ -37282,6 +37900,9 @@ msgstr "Tokens de descubrimiento SAML"
msgid "SAML for %{group_name}"
msgstr "SAML para %{group_name}"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,24 +38567,27 @@ msgstr ""
msgid "Security"
msgstr "Seguridad"
-msgid "Security & Compliance"
-msgstr "Seguridad y cumplimiento"
-
-msgid "Security Configuration"
-msgstr "Configuración de seguridad"
-
msgid "Security Dashboard"
msgstr "Tablero de seguridad"
msgid "Security Finding not found"
msgstr ""
-msgid "Security dashboard"
-msgstr "Tablero de seguridad"
+msgid "Security Policy project already exists."
+msgstr ""
-msgid "Security navigation"
+msgid "Security and Compliance"
msgstr ""
+msgid "Security capabilities"
+msgstr ""
+
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
+msgstr "Tablero de seguridad"
+
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr "Seleccione un proyecto"
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr "%{firstProject}, %{secondProject} y %{rest}"
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr "Seleccionar etiqueta"
msgid "Select labels"
msgstr "Seleccione las etiquetas"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "Seleccionar el momento de fusión"
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr "Enviar"
@@ -39275,6 +39941,12 @@ msgstr "Cuentas de servicio"
msgid "Service usage data"
msgstr "Datos de uso del servicio"
+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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ msgstr "Establecer el tiempo máximo de sesión para un terminal web."
msgid "Set the milestone to %{milestone_reference}."
msgstr "Establecer el hito a %{milestone_reference}."
+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 ""
@@ -39437,7 +40112,7 @@ msgstr "Configurar la integración con Jira"
msgid "Set up a %{type} runner for a project"
msgstr "Configurar un %{type} ejecutor para un proyecto"
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr "Mostrar el contenido del archivo"
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr "Mostrar los hitos del grupo"
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr "Iniciar sesión"
-msgid "Sign in / Register"
-msgstr "Iniciar sesión / Registro"
-
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 ""
@@ -40008,15 +40683,33 @@ msgstr "La integración con Slack le permite interactuar con GitLab mediante com
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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr "Secreto del cliente"
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr "Alias del proyecto"
@@ -40035,6 +40731,9 @@ msgstr ""
msgid "SlackIntegration|Remove project"
msgstr "Eliminar proyecto"
+msgid "SlackIntegration|Run ChatOps jobs."
+msgstr ""
+
msgid "SlackIntegration|See the list of available commands in Slack after setting up this integration by entering"
msgstr ""
@@ -40068,9 +40767,15 @@ msgstr "Token de verificación"
msgid "SlackIntegration|You can now close this window and go to your Slack workspace."
msgstr "Ahora puede cerrar esta ventana e ir a su espacio de trabajo de Slack."
+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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ msgstr "Se ha producido un error al intentar cargar los contactos de la incidenc
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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr "Protección Anti-Spam y Anti-Bot"
msgid "Spam log successfully submitted as ham."
msgstr "Se ha enviado el registro de spam correctamente."
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr "No se puede usar la URL especificada: \"%{reason}\""
@@ -40986,6 +41697,9 @@ msgstr "¿Eliminar la verificación de estado?"
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ msgstr ""
msgid "SuperSonics|Start free trial"
msgstr "Iniciar prueba gratuita"
+msgid "SuperSonics|Subscription detail synchronization has started and will complete soon."
+msgstr ""
+
msgid "SuperSonics|Subscription details"
msgstr "Detalles de la suscripción"
+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 "Suscripción no disponible"
msgid "SuperSonics|Sync subscription details"
msgstr ""
-msgid "SuperSonics|Sync subscription request."
+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}."
@@ -41649,8 +42369,8 @@ msgstr "El código de activación no es válido. Por favor, asegúrese de copiar
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr "El código de activación debe ser una cadena alfanumérica de 24 caracteres"
-msgid "SuperSonics|There is a connectivity issue."
-msgstr "Hay un problema de conectividad."
+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 ""
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr "Su suscripción"
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr "Los detalles de su suscripción se sincronizarán en breve."
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ msgstr "Listas de etiquetas:"
msgid "Tag name"
msgstr "Nombre de la etiqueta"
+msgid "Tag name cannot be one of the following: %{names}"
+msgstr ""
+
msgid "Tag name is required."
msgstr "El nombre de la etiqueta es obligatorio."
+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 ""
@@ -42285,12 +43017,12 @@ msgstr ""
msgid "Test"
msgstr "Probar"
-msgid "Test Cases"
-msgstr "Casos de prueba"
-
msgid "Test case"
msgstr "Caso de prueba"
+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] ""
@@ -42310,9 +43042,6 @@ msgstr "Mover caso de prueba"
msgid "TestCases|Moving test case"
msgstr "Moviendo caso de prueba"
-msgid "TestCases|New Test Case"
-msgstr "Nuevo caso de prueba"
-
msgid "TestCases|New test case"
msgstr "Nuevo caso de prueba"
@@ -42439,6 +43168,9 @@ msgstr "Texto (opcional)"
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 "Estilo del texto"
@@ -42498,6 +43230,9 @@ msgstr "El gestor de incidencias es el lugar para añadir cosas que necesitan se
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "La conexión terminará después de %{timeout}. Para los repositorios que tarden más tiempo, utilice una combinación de git clone y git push."
@@ -42600,6 +43332,9 @@ msgstr "La lista de dependencias detalla la información sobre los componentes u
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "El despliegue de este trabajo en %{environmentLink} no tuvo éxito."
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr "El directorio se ha creado correctamente."
@@ -42913,7 +43648,16 @@ msgstr "El recurso al que está intentando acceder no existe o no tiene permiso
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "Este ejecutor solo se ejecutará en pipelines disparados sobre ramas protegidas"
@@ -44008,10 +44752,7 @@ msgstr "Esta variable no se puede enmascarar."
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ msgstr "Para comenzar, introduzca la URL de su servidor de Gitea y un %{link_to_
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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ msgstr "El grupo ya es un grupo raíz."
msgid "TransferGroup|Group is already associated to the parent group."
msgstr "El grupo ya está asociado al grupo principal."
+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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr "Ejecutar pipelines para la actualización de las replicas"
@@ -45143,9 +45887,6 @@ msgstr "Twitter:"
msgid "Two-Factor Authentication"
msgstr "Autenticación de doble factor"
-msgid "Two-Factor Authentication code"
-msgstr "Código de autenticación de dos factores"
-
msgid "Two-factor Authentication"
msgstr "Autenticación de doble factor"
@@ -45191,12 +45932,6 @@ msgstr "Tipo"
msgid "Type to search"
msgstr "Teclee para buscar"
-msgid "U2F Devices (%{length})"
-msgstr "Dispositivos U2F (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "U2F sólo funciona con sitios web habilitados con HTTPS. Contacte con su administrador para más detalles."
-
msgid "URL"
msgstr "URL"
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr "No se puede encontrar el proyecto Jira para importar datos."
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr "Ilimitado"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr "Tipo de tarea no soportada. Los tipos de tareas soportadas son: %{todo_types}"
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ msgstr ""
msgid "Update your group name, description, avatar, and visibility."
msgstr "Actualice el nombre de su grupo, su descripción, su avatar y su visibilidad."
+msgid "Update your project name and description."
+msgstr ""
+
msgid "Update your project name, topics, description, and avatar."
msgstr ""
@@ -45740,6 +46496,9 @@ msgstr "Tendencias de uso"
msgid "Usage statistics"
msgstr "Estadísticas de uso"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr "Subidas"
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ msgstr "Usuario creado el"
msgid "User does not have a pending request"
msgstr "El usuario no tiene una solicitudes pendientes"
+msgid "User does not have permission to create a Security Policy project."
+msgstr ""
+
msgid "User identity was successfully created."
msgstr "La identidad de usuario se ha creado correctamente."
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr "Ver documentación"
msgid "View eligible approvers"
msgstr "Ver aprobadores elegibles"
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "Ver artefacto expuesto"
@@ -47116,6 +47893,69 @@ msgstr "%{formattedStartDate} hasta hoy"
msgid "VulnerabilityChart|Severity"
msgstr "Gravedad"
+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|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 ""
@@ -47506,12 +48346,6 @@ msgstr "No hemos podido encontrar ningún %{scope} que coincida con %{term} en e
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "No ha sido posible conectar al servidor de Prometheus. O el servidor ya no existe o debe actualizar los detalles de configuración."
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "Hemos detectado spam potencial en %{humanized_resource_name}. Por favor resuelva el reCAPTCHA para poder continuar."
@@ -47563,9 +48397,6 @@ msgstr "Notificaremos a %{inviter} que ha rechazado su invitación para unirse a
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 "Nos gustaría informarle de que su suscripción a GitLab Enterprise Edition %{plan_name} se está acercando a su límite de usuarios. Tiene %{active_user_count} usuarios activos, lo que casi alcanza el límite de usuarios de %{maximum_user_count}."
-msgid "We'll continuously validate your pipeline configuration. The validation results will appear here."
-msgstr "Validaremos continuamente la configuración de su pipeline. Los resultados de la validación aparecerán aquí."
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -48227,8 +49069,8 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr "Trabajo en curso (abierto y sin asignar)"
-msgid "Work in progress Limit"
-msgstr "Límite de trabajo en progreso"
+msgid "Work in progress limit"
+msgstr ""
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "¿Está seguro que desea cancelar la edición?"
@@ -48298,6 +49143,15 @@ msgstr "Elemento hijo eliminado"
msgid "WorkItem|Closed"
msgstr "Cerrado"
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr "Tarea eliminada"
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr "Escriba una nota interna o arrastre sus archivos aquí…"
msgid "Write milestone description..."
msgstr "Escriba la descripción del hito..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "Escribe sus notas de la versión o arrastrar sus archivos aquí…"
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr "No tiene permisos para ejecutar la importación."
-msgid "You don't have any U2F devices registered yet."
-msgstr "No tiene ningún dispositivo U2F registrado."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ msgstr "Debe tener permiso como mantenedor para forzar la eliminación de un blo
msgid "You must provide a valid current password"
msgstr "Debe proporcionar una contraseña válida"
+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 "Debe introducir su contraseña actual para poder cambiarla."
+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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ msgstr "Su grupo de GitLab"
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 "Sus grupos"
@@ -49324,6 +50202,9 @@ msgstr "Su clave SSH fue eliminada"
msgid "Your SSH keys (%{count})"
msgstr "Sus Claves SSH (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "Su lista de tareas pendientes"
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "Sus aplicaciones (%{size})"
@@ -49378,9 +50262,6 @@ msgstr "Sus aplicaciones autorizadas"
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "Su navegador no soporta U2F. Por favor, utilice la versión de escritorio de Google Chrome (versión 41 o posterior)."
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr "Su comentario será descartado."
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "Investigue esta vulnerabilidad creando una incidencia"
@@ -50203,6 +51090,9 @@ msgstr "Resolver con un merge request"
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "Detección de secretos"
@@ -50233,6 +51123,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Solución"
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST)"
msgstr ""
@@ -50510,9 +51403,6 @@ msgstr[1] "archivos"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr "para"
@@ -50818,10 +51708,16 @@ msgstr "bloqueado por %{path_lock_user_name} %{created_at}"
msgid "manual"
msgstr "manual"
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr "Uso de %{metricsLinkStart} memoria %{metricsLinkEnd} %{emphasisStart} in
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart} El uso de la memoria %{metricsLinkEnd} es %{emphasisStart} sin cambios %{emphasisEnd} en %{memoryFrom}MB"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr "La contraseña de aprobación no es correcta."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr "Aprobar"
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,84 +51998,30 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "Merge fallido."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr "Merge realizado por"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
+msgid "mrWidget|More information"
+msgstr "Más información"
-msgid "mrWidget|Merging! The changes are leaving the station…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Merging! This is going to be great…"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|More information"
-msgstr "Más información"
-
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "Ningún usuario coincide con los criterios de la regla."
-
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "listo para fusionarse automáticamente. Pídale a alguien que tenga acceso de escritura a este repositorio que fusione esta solicitud"
-
msgid "mrWidget|Refresh"
msgstr "Actualizar"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po
index 90ddd5e585c..0df2f9422ba 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/fa_IR/gitlab.po b/locale/fa_IR/gitlab.po
index 4d813f3ce56..2fac4726df9 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/fi_FI/gitlab.po b/locale/fi_FI/gitlab.po
index 692da34ce1e..f000f03acc7 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po
index bb0049ebefb..41cd4caee86 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index f1026634e0d..c1375cd33ab 100644
--- a/locale/fr/gitlab.po
+++ b/locale/fr/gitlab.po
@@ -14,10 +14,10 @@ msgstr ""
"X-Crowdin-Language: fr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-02-11 15:23\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
-msgstr " %{start} à %{end}"
+msgstr " %{start} au %{end}"
msgid " (from %{timeoutSource})"
msgstr " (depuis %{timeoutSource})"
@@ -426,6 +426,11 @@ msgid_plural "%d unresolved threads"
msgstr[0] "%d fil de conversation non résolu"
msgstr[1] "%d fils de conversation non résolus"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] "%d version"
+msgstr[1] "%d versions"
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d vulnérabilité"
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "%d avertissement trouvé :"
msgstr[1] "%d avertissements trouvés :"
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] "%d élément de travail"
+msgstr[1] "%d éléments de travail"
+
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 commit supplémentaire a été ignoré afin d’éviter de causer des problèmes de performance."
msgstr[1] "%s commits supplémentaires ont été ignorés afin d’éviter de causer des problèmes de performance."
+msgid "%{actionText} %{actionDetail}"
+msgstr "%{actionText} %{actionDetail}"
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr "%{actionText} %{actionDetail} %{timeago} par %{author}"
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} et %{openOrClose} %{noteable}"
@@ -625,11 +641,14 @@ msgstr[0] "%{count} projet"
msgstr[1] "%{count} projets"
msgid "%{count} related %{pluralized_subject}: %{links}"
-msgstr "%{count} lié à %{pluralized_subject}: %{links}"
+msgstr "%{count} %{pluralized_subject} associée(s) : %{links}"
msgid "%{count} selected"
msgstr "%{count} sélectionnés"
+msgid "%{count} tags"
+msgstr "%{count} étiquettes"
+
msgid "%{count} total weight"
msgstr "%{count} poids total"
@@ -831,6 +850,9 @@ msgstr "%{level_name} n'est pas autorisé car le projet divergent a une visibili
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr "%{linkStart} En savoir plus%{linkEnd}."
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}, et %{awardsListLength} de plus"
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} peuvent fusionner"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} %{warnings_displayed} premiers affichés"
-msgid "%{message}. Your attention request was removed."
-msgstr "%{message}. Votre demande d’attention a été supprimée."
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (expirée)"
@@ -982,6 +1001,9 @@ msgstr "%{reportType} a détecté %{totalStart}%{total}%{totalEnd} %{vulnMessage
msgid "%{reportType} detected no new vulnerabilities."
msgstr "%{reportType} n'a détecté aucune nouvelle vulnérabilité."
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] "%{requireStart}Nécessite%{requireEnd} %{approvalsRequired} %{approvalStart}approbation%{approvalEnd} de :"
@@ -1226,6 +1248,9 @@ msgstr "%{user} a créé une épopée : %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} a créé un ticket : %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr "Menu utilisateur de %{user}"
+
msgid "%{value} is not included in the list"
msgstr "%{value} ne fait pas partie de la liste"
@@ -1291,11 +1316,11 @@ msgstr "« %{value} » jours d'inactivité doit être supérieur ou égal à 90"
msgid "(%d closed)"
msgid_plural "(%d closed)"
-msgstr[0] "(%d fermé)"
-msgstr[1] "(%d fermés)"
+msgstr[0] "(%d fermée)"
+msgstr[1] "(%d fermées)"
msgid "(%{mrCount} merged)"
-msgstr "(%{mrCount} fusionnés)"
+msgstr "(%{mrCount} fusionnées)"
msgid "(%{value}) has already been taken"
msgstr "(%{value}) a déjà été pris"
@@ -1457,7 +1482,7 @@ msgid "/day"
msgstr "/jour"
msgid "0 bytes"
-msgstr "0 octets"
+msgstr "0 octet"
msgid "1 Code quality finding"
msgid_plural "%d Code quality findings"
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] "1 clé de déploiement"
msgstr[1] "%d clés de déploiement"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "1 suiveur"
-msgstr[1] "%{count} suiveurs"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "Un groupe"
@@ -1813,9 +1833,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "API Fuzzing"
-msgid "API Fuzzing Configuration"
-msgstr "Configuration de l'API Fuzzing"
-
msgid "API Help"
msgstr "Aide sur l’API"
@@ -2230,9 +2247,6 @@ msgstr "Ajouter une liste de contrôle"
msgid "Add a collapsible section"
msgstr "Ajouter une section rétractable"
-msgid "Add a comment"
-msgstr "Ajouter un commentaire"
-
msgid "Add a comment to this line"
msgstr "Ajouter un commentaire à cette ligne"
@@ -2254,6 +2268,9 @@ msgstr "Ajoutez une page d’accueil à votre wiki contenant des informations su
msgid "Add a new issue"
msgstr "Ajouter un nouveau ticket"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Ajouter une liste numérotée"
@@ -2263,6 +2280,9 @@ msgstr "Ajouter une épopée associée"
msgid "Add a related issue"
msgstr "Ajouter un ticket lié"
+msgid "Add a reply"
+msgstr ""
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr "Ajouter un suffixe à l'adresse de courriel du Service d'Assistance. %{linkStart}En savoir plus.%{linkEnd}"
@@ -2377,6 +2397,9 @@ msgstr "Ajouter une nouvelle application"
msgid "Add new directory"
msgstr "Ajouter un nouveau dossier"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr "Ajouter ou supprimer un utilisateur."
@@ -2515,6 +2538,9 @@ msgstr "Minutes supplémentaires :"
msgid "Additional text"
msgstr "Texte supplémentaire"
+msgid "Additional text for deactivation email"
+msgstr "Texte supplémentaire pour le courriel de désactivation"
+
msgid "Additional text for the sign-in and Help page."
msgstr "Texte supplémentaire pour les pages d'aide et de connexion."
@@ -3143,13 +3169,13 @@ msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr "Utiliser AWS OpenSearch Service avec les identifiants IAM"
msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
-msgstr "Utilisé pour connecter Jitsu à l'instance Clickhouse."
+msgstr "Utilisée pour connecter Jitsu à l'instance Clickhouse."
msgid "AdminSettings|Used to generate short-lived API access tokens."
msgstr "Utilisé pour générer des jetons d'accès d'API de courte durée."
msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
-msgstr "Utilisé pour récupérer les données du tableau de bord à partir de l'instance de Cube."
+msgstr "Utilisée pour récupérer les données du tableau de bord à partir de l'instance de Cube."
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr "Les utilisateurs et les groupes doivent accepter l’invitation avant de pouvoir être ajoutés à un groupe ou à un projet."
@@ -3694,42 +3720,12 @@ msgstr "Une fois l'intégration Apple App Store Connect activée, les variables
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 "Une fois l'exportation terminée, téléchargez le fichier de données depuis le courriel de notification ou depuis cette page. Vous pourrez ensuite l'importer sur la page %{strong_text_start}Créer un nouveau groupe%{strong_text_end} d'une autre instance GitLab."
+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 "Après avoir pris connaissance de ces consignes de contribution, vous serez prêt à"
-msgid "Airflow"
-msgstr "Airflow"
-
-msgid "Airflow|Airflow DAGs"
-msgstr "DAGs Airflow"
-
-msgid "Airflow|DAG"
-msgstr "DAG"
-
-msgid "Airflow|DAG file location"
-msgstr "Emplacement du fichier du DAG"
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr "Soit l'instance Airflow ne contient aucun DAG, soit elle n'a pas encore été configurée"
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr "Intégration Airflow de GitLab"
-
-msgid "Airflow|Is active"
-msgstr "Est active"
-
-msgid "Airflow|Is paused"
-msgstr "Est en pause"
-
-msgid "Airflow|Next run"
-msgstr "Prochaine exécution"
-
-msgid "Airflow|Schedule"
-msgstr "Programmation"
-
-msgid "Airflow|There are no DAGs to show"
-msgstr "Il n'y a aucun DAG à afficher"
-
msgid "Akismet"
msgstr "Akismet"
@@ -4099,6 +4095,9 @@ msgstr "Tout GitLab"
msgid "All Members"
msgstr "Tous les membres"
+msgid "All branch names must match %{link_start}this regular expression%{link_end}. If empty, any branch name is allowed."
+msgstr "Tous les noms de branche doivent correspondre à %{link_start}cette expression rationnelle%{link_end}. Si vide, tout nom de branche est autorisé."
+
msgid "All branches"
msgstr "Toutes les branches"
@@ -4672,7 +4671,7 @@ msgid "An error occurred. Please sign in again."
msgstr "Une erreur s'est produite. Veuillez vous reconnecter."
msgid "An error occurred. Please try again."
-msgstr "Une erreur est survenue. Merci de réessayer."
+msgstr "Une erreur s’est produite. Veuillez réessayer."
msgid "An error occurred. Unable to reopen this merge request."
msgstr "Une erreur s'est produite. Impossible de rouvrir cette demande de fusion."
@@ -4727,6 +4726,9 @@ msgstr "Une erreur inattendue s'est produite lors du démarrage du Terminal Web.
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Une erreur inattendue s'est produite lors de l'arrêt du Terminal Web."
+msgid "An unexpected error occurred. Please try again."
+msgstr "Une erreur inattendue s'est produite. Veuillez réessayer."
+
msgid "An unknown error occurred while loading this graph."
msgstr "Une erreur inconnue s'est produite lors du chargement de ce graphe."
@@ -4736,6 +4738,123 @@ msgstr "Une erreur inconnue s'est produite."
msgid "Analytics"
msgstr "Analytique"
+msgid "Analytics|Add to Dashboard"
+msgstr "Ajouter au tableau de bord"
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr "Une erreur s'est produite lors du chargement de la visualisation %{visualizationTitle}."
+
+msgid "Analytics|Analytics dashboards"
+msgstr "Tableaux de bord analytiques"
+
+msgid "Analytics|Browser"
+msgstr "Navigateur"
+
+msgid "Analytics|Browser Family"
+msgstr "Famille de navigateurs"
+
+msgid "Analytics|Choose a chart type on the right"
+msgstr "Choisissez un type de graphique sur la droite"
+
+msgid "Analytics|Choose a measurement to start"
+msgstr ""
+
+msgid "Analytics|Code"
+msgstr "Code"
+
+msgid "Analytics|Configure Dashboard Project"
+msgstr "Configurer le projet de tableaux de bord"
+
+msgid "Analytics|Custom dashboards"
+msgstr "Tableaux de bord personnalisés"
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr "Les tableaux de bord sont créés en modifiant les fichiers de tableau de bord des projets."
+
+msgid "Analytics|Data"
+msgstr "Données"
+
+msgid "Analytics|Data Table"
+msgstr "Tableau de données"
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr "Hôte"
+
+msgid "Analytics|Language"
+msgstr "Langue"
+
+msgid "Analytics|Line Chart"
+msgstr "Graphique linéaire"
+
+msgid "Analytics|New Analytics Visualization Title"
+msgstr "Titre de la nouvelle visualisation analytique"
+
+msgid "Analytics|OS"
+msgstr "OS"
+
+msgid "Analytics|OS Version"
+msgstr "Version de l'OS"
+
+msgid "Analytics|Page Language"
+msgstr "Langue de la page"
+
+msgid "Analytics|Page Path"
+msgstr ""
+
+msgid "Analytics|Page Title"
+msgstr ""
+
+msgid "Analytics|Pages"
+msgstr "Pages"
+
+msgid "Analytics|Referer"
+msgstr "Référent"
+
+msgid "Analytics|Resulting Data"
+msgstr "Données résultantes"
+
+msgid "Analytics|Save"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr "Statistique unique"
+
+msgid "Analytics|URL"
+msgstr "URL"
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr "Utilisateurs"
+
+msgid "Analytics|Viewport"
+msgstr "Zone d'affichage"
+
+msgid "Analytics|Visualization"
+msgstr "Visualisation"
+
+msgid "Analytics|Visualization Designer"
+msgstr "Concepteur de visualisation"
+
+msgid "Analytics|Visualization Type"
+msgstr "Type de visualisation"
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analyser vos dépendances à la recherche de vulnérabilités connues."
@@ -4814,14 +4933,29 @@ msgstr "Ajouter %{shrug} dans le commentaire"
msgid "Append the comment with %{tableflip}"
msgstr "Ajouter %{tableflip} dans le commentaire"
+msgid "AppleAppStore|Drag your Private Key file here or %{linkStart}click to upload%{linkEnd}."
+msgstr "Faites glisser votre fichier de clé privée ici ou %{linkStart}cliquez pour le téléverser%{linkEnd}."
+
+msgid "AppleAppStore|Drop your Private Key file to start the upload."
+msgstr "Déposez votre fichier de clé privée pour lancer le téléversement."
+
+msgid "AppleAppStore|Error: You are trying to upload something other than a Private Key file."
+msgstr "Erreur : Vous essayez de téléverser autre chose qu’un fichier de clé privée."
+
+msgid "AppleAppStore|Leave empty to use your current Private Key."
+msgstr "Laissez vide pour utiliser votre clé privée actuelle."
+
msgid "AppleAppStore|The Apple App Store Connect Issuer ID."
msgstr "L'ID d'émetteur Apple App Store Connect."
msgid "AppleAppStore|The Apple App Store Connect Key ID."
msgstr "L'ID de clé Apple App Store Connect."
-msgid "AppleAppStore|The Apple App Store Connect Private Key."
-msgstr "La clé privée Apple App Store Connect."
+msgid "AppleAppStore|The Apple App Store Connect Private Key (.p8)"
+msgstr "La clé privée Apple App Store Connect (.p8)"
+
+msgid "AppleAppStore|Upload a new Apple App Store Connect Private Key (replace %{currentFileName})"
+msgstr "Téléversez une nouvelle clé privée Apple App Store Connect (remplace %{currentFileName})"
msgid "AppleAppStore|Use GitLab to build and release an app in the Apple App Store."
msgstr "Utiliser GitLab pour construire et publier une app dans l'App Store d'Apple."
@@ -4965,12 +5099,18 @@ msgstr "Enregistrer les modifications"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "Voir la %{linkStart}stratégie des mots de passe%{linkEnd}."
+msgid "ApplicationSettings|Send a confirmation email during sign up. New users can log in immediately, but must confirm their email within three days."
+msgstr "Envoyer un courriel de confirmation lors de l'inscription. Les nouveaux utilisateurs peuvent se connecter immédiatement mais doivent confirmer leur adresse de courriel dans les trois jours."
+
msgid "ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in."
msgstr "Envoyer un courriel de confirmation lors de l'inscription. Les nouveaux utilisateurs doivent confirmer leur adresse de courriel avant de pouvoir se connecter."
msgid "ApplicationSettings|Sign-up enabled"
msgstr "Inscription activée"
+msgid "ApplicationSettings|Soft"
+msgstr "Souple"
+
msgid "ApplicationSettings|Text shown after a user signs up. Markdown enabled."
msgstr "Texte affiché après l’inscription d’un utilisateur. Markdown activé."
@@ -5215,6 +5355,11 @@ msgstr "Tout approuver"
msgid "Approve a merge request"
msgstr "Approuver une demande de fusion"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] "Approuver un membre en attente"
+msgstr[1] "Approuver %d membres en attente"
+
msgid "Approve merge request"
msgstr "Approuver la demande de fusion"
@@ -5227,6 +5372,16 @@ msgstr "Approuvée"
msgid "Approved MRs"
msgstr "Demandes de fusion approuvées"
+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] "Les membres approuvés utiliseront un siège supplémentaire dans votre abonnement, ce qui peut entraîner un dépassement du plafond d'utilisateurs."
+msgstr[1] "Les membres approuvés utiliseront %d sièges supplémentaires dans votre abonnement, ce qui peut entraîner un dépassement du plafond d'utilisateurs."
+
+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] "Les membres approuvés utiliseront un siège supplémentaire dans votre abonnement."
+msgstr[1] "Les membres approuvés utiliseront %d sièges supplémentaires dans votre abonnement."
+
msgid "Approved the current merge request."
msgstr "Demande de fusion actuelle approuvée."
@@ -5285,7 +5440,7 @@ msgid "Are you ABSOLUTELY SURE you wish to remove this group?"
msgstr "Voulez-vous VRAIMENT supprimer ce groupe ?"
msgid "Are you absolutely sure?"
-msgstr "Êtes-vous absolument sûr(e) ?"
+msgstr "Voulez-vous vraiment continuer ?"
msgid "Are you sure that you want to archive this project?"
msgstr "Voulez-vous vraiment archiver ce projet ?"
@@ -5302,9 +5457,6 @@ msgstr "Voulez-vous vraiment %{action} %{name} ?"
msgid "Are you sure you want to approve %{user}?"
msgstr "Voulez-vous vraiment approuver %{user} ?"
-msgid "Are you sure you want to approve all users?"
-msgstr "Voulez-vous vraiment approuver tous les utilisateurs ?"
-
msgid "Are you sure you want to attempt to merge?"
msgstr "Voulez-vous vraiment tenter la fusion ?"
@@ -5317,6 +5469,9 @@ msgstr "Voulez-vous vraiment fermer ce ticket bloqué ?"
msgid "Are you sure you want to delete %{name}?"
msgstr "Voulez-vous vraiment supprimer %{name} ?"
+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 "Voulez-vous vraiment supprimer ce %{commentType} ?"
@@ -5668,8 +5823,8 @@ msgstr[1] "Joindre %d fichiers"
msgid "Attaching the file failed."
msgstr "L'ajout du fichier en pièce-jointe a échoué."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
-msgstr "Tentative de connexion à %{host} en utilisant un code d'authentification à deux facteurs erroné"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
+msgstr "Tentative de connexion à %{host} à l'aide d'un code de vérification erroné"
msgid "Audit Events"
msgstr "Événements d’audit"
@@ -5922,9 +6077,6 @@ msgstr "Rédigé %{timeago} par %{author}"
msgid "Authorization code:"
msgstr "Code d’autorisation :"
-msgid "Authorization required"
-msgstr "Autorisation requise"
-
msgid "Authorization token duration (minutes)"
msgstr "Durée d'un jeton d'autorisation (minutes)"
@@ -5937,9 +6089,6 @@ msgstr "Autoriser"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "Autoriser %{link_to_client} à utiliser votre compte ?"
-msgid "Authorize %{user} to use your account?"
-msgstr "Autoriser %{user} à utiliser votre compte ?"
-
msgid "Authorized %{new_chat_name}"
msgstr "%{new_chat_name} autorisé"
@@ -5949,9 +6098,18 @@ msgstr "Autorisé à"
msgid "Authorized applications (%{size})"
msgstr "Applications autorisées (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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 "Voulez-vous vraiment révoquer cette application ?"
+msgid "AuthorizedApplication|Renew secret"
+msgstr ""
+
msgid "AuthorizedApplication|Revoke application"
msgstr "Révoquer l'application"
@@ -6082,7 +6240,7 @@ msgid "Avatar for %{assigneeName}"
msgstr "Avatar pour %{assigneeName}"
msgid "Avatar will be removed. Are you sure?"
-msgstr "L’avatar sera supprimé. Êtesâ€vous sûr(e) ?"
+msgstr "Voulez-vous vraiment supprimer l'avatar ?"
msgid "Average per day: %{average}"
msgstr "Moyenne par jour : %{average}"
@@ -6333,6 +6491,9 @@ msgstr "Faites attention. Modifier l'espace de noms du projet peut avoir des eff
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Faites attention. Renommer le dépôt d'un projet peut avoir des effets secondaires imprévus."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 "Parce que vous avez activé le bannissement automatique, cet utilisateur se trouve avoir été banni automatiquement du %{scope}. S'il s'agit d'une erreur, vous pouvez %{link_start}le gracier%{link_end}."
@@ -6360,9 +6521,6 @@ msgstr "Les paramètres de %{link_to_gitlab_pages} figurent ci-après."
msgid "Below you will find all the groups that are public."
msgstr "Vous trouverez ciâ€dessous tous les groupes publics."
-msgid "Beta"
-msgstr "Bêta"
-
msgid "Bi-weekly code coverage"
msgstr "Couverture de code bihebdomadaire"
@@ -6432,6 +6590,9 @@ msgstr "Planification agile d'entreprise"
msgid "BillingPlans|Faster code reviews"
msgstr "Revues de code plus rapides"
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr "Fonctionnalités gratuites pour toujours pour les utilisateurs individuels"
@@ -6447,9 +6608,6 @@ msgstr "Si vous souhaitez passer à un forfait inférieur, veuillez contacter le
msgid "BillingPlans|Includes free static websites"
msgstr "Inclut les sites Web statiques gratuits"
-msgid "BillingPlans|Learn more"
-msgstr "En savoir plus"
-
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}, or start a free 30-day trial of GitLab.com Ultimate."
msgstr "Renseignez-vous sur nos forfaits en lisant notre %{faq_link} ou essayez gratuitement l’édition Ultimate sur GitLab.com pendant 30 jours."
@@ -6585,27 +6743,9 @@ msgstr "Mettre à niveau"
msgid "BillingPlan|Upgrade for free"
msgstr "Mettre à niveau gratuitement"
-msgid "Billings|%{planName} plan"
-msgstr "Forfait %{planName}"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr "Une erreur s’est produite lors de l’extension de votre essai."
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr "Une erreur est survenue lors de la réactivation de votre essai."
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr "En prolongeant votre essai, vous bénéficierez de 30 jours supplémentaires sur %{planName}. Votre essai ne peut être prolongé qu'une seule fois."
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr "En réactivant votre essai, vous bénéficierez de 30 jours supplémentaires sur %{planName}. Votre essai ne peut être réactivé qu'une seule fois."
-
msgid "Billings|Error validating card details"
msgstr "Erreur lors de la validation des détails de la carte"
-msgid "Billings|Extend trial"
-msgstr "Prolonger l'essai"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr "Les groupes gratuits sont limités à %{number} sièges."
@@ -6615,9 +6755,6 @@ msgstr "Les groupes dans les éditions Gratuite ou d'essai peuvent inviter au ma
msgid "Billings|In a seat"
msgstr "Dans un siège"
-msgid "Billings|Reactivate trial"
-msgstr "Réactiver l'essai"
-
msgid "Billings|Seats in use / Seats available"
msgstr "Sièges utilisés / Sièges disponibles"
@@ -6758,6 +6895,9 @@ msgstr "Importation de Bitbucket"
msgid "Blame"
msgstr "Inspecter"
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr "Voir sur %{environmentName}"
@@ -6791,7 +6931,7 @@ msgid "Blog"
msgstr "Blog"
msgid "Board scope affects which epics are displayed for anyone who visits this board"
-msgstr "La portée du tableau indique quelles épopées sont affichées pour toute les personnes visitant ce tableau"
+msgstr "La portée du tableau indique quelles épopées sont affichées pour toutes les personnes visitant ce tableau"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "La portée du tableau définit quels tickets sont affichés pour toute personne qui le consulte"
@@ -6980,15 +7120,27 @@ msgstr[1] "Blocage par %{blockedByCount} %{issuableType}s"
msgid "Boards|Collapse"
msgstr "Réduire"
+msgid "Boards|Create new epic"
+msgstr "Créer une nouvelle épopée"
+
+msgid "Boards|Create new issue"
+msgstr "Créer un nouveau ticket"
+
msgid "Boards|Edit board"
msgstr "Modifier le tableau"
+msgid "Boards|Edit list settings"
+msgstr "Modifier les paramètres de la liste"
+
msgid "Boards|Expand"
msgstr "Étendre"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr "Échec de la récupération des %{issuableType}s bloquant(e)s"
+msgid "Boards|List actions"
+msgstr "Actions de liste"
+
msgid "Boards|Move card"
msgstr "Déplacer la carte"
@@ -7001,9 +7153,6 @@ msgstr "Déplacer en début de liste"
msgid "Boards|New board"
msgstr "Nouveau tableau"
-msgid "Boards|New epic"
-msgstr "Nouvelle épopée"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr "Récupération des %{issuableType}s bloquant(e)s"
@@ -7121,9 +7270,6 @@ msgstr "Après la création d’une branche protégée, elle apparaîtra dans la
msgid "BranchRules|All branches"
msgstr "Toutes les branches"
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr "Tous les utilisateurs ayant un accès pour pousser sont autorisés à forcer les poussées."
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "Autoriser tous les utilisateurs ayant un accès pour pousser à %{linkStart}forcer les poussées%{linkEnd}."
@@ -7142,6 +7288,15 @@ msgstr "Autorisés à pousser et fusionner"
msgid "BranchRules|Allowed to push and merge (%{total})"
msgstr "Autorisés à pousser et fusionner (%{total})"
+msgid "BranchRules|Allows force push"
+msgstr "Autorise à forcer les poussées"
+
+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 "Une erreur s'est produite lors de la récupération des branches."
@@ -7172,11 +7327,14 @@ msgstr "Créer un joker : %{searchTerm}"
msgid "BranchRules|Details"
msgstr "Détails"
-msgid "BranchRules|Force push"
-msgstr "Forcer la poussée"
+msgid "BranchRules|Does not allow force push"
+msgstr "N'autorise pas à forcer les poussées"
-msgid "BranchRules|Force push is not allowed."
-msgstr "Forcer les poussées n'est pas autorisé."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr "Ne nécessite pas l'approbation des propriétaires du code"
+
+msgid "BranchRules|From users with push access."
+msgstr ""
msgid "BranchRules|Groups"
msgstr "Groupes"
@@ -7217,6 +7375,9 @@ msgstr "Approbations requises (%{total})"
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr "Nécessite les approbations de CODEOWNERS"
+msgid "BranchRules|Requires approval from code owners"
+msgstr "Nécessite l'approbation des propriétaires du code"
+
msgid "BranchRules|Roles"
msgstr "Rôles"
@@ -7984,6 +8145,15 @@ msgstr "Impossible d'appliquer cette suggestion."
msgid "Can't be empty"
msgstr "Ne peut pas être vide"
+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 "Impossible de créer l'extrait de code : %{err}"
@@ -8101,6 +8271,9 @@ msgstr "Impossible d'avoir plusieurs alertes non résolues"
msgid "Cannot import because issues are not available in this project."
msgstr "Impossible d'importer car les tickets ne sont pas disponibles dans ce projet."
+msgid "Cannot load the diagram into the diagrams.net editor"
+msgstr "Impossible de charger le diagramme dans l'éditeur diagrams.net"
+
msgid "Cannot make the epic confidential if it contains non-confidential child epics"
msgstr "Impossible de rendre l'épopée confidentielle si elle contient des épopées enfants non confidentielles"
@@ -8483,6 +8656,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+msgid "Checkout|Add active users before adding a coupon."
+msgstr "Ajoutez des utilisateurs actifs avant d'ajouter un coupon."
+
msgid "Checkout|An unknown error has occurred. Please try again by refreshing this page."
msgstr "Une erreur inconnue s'est produite. Veuillez réessayer en actualisant cette page."
@@ -8525,6 +8701,9 @@ msgstr "Pays"
msgid "Checkout|Coupon code (optional)"
msgstr "Code du coupon (facultatif)"
+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 "Créer un nouveau groupe"
@@ -8534,18 +8713,15 @@ msgstr "Le chargement du formulaire de carte de crédit a échoué. Veuillez ré
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "Le chargement du formulaire de carte de crédit a échoué : %{message}"
+msgid "Checkout|Discount"
+msgstr "Réduction"
+
msgid "Checkout|Edit"
msgstr "Modifier"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr "Exp %{expirationMonth}/%{expirationYear}"
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "Échec de la confirmation de votre commande ! Veuillez réessayer."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "Échec de la confirmation de votre commande : %{message}. Veuillez réessayer."
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "Impossible de charger les pays. Veuillez réessayer."
@@ -8570,6 +8746,9 @@ msgstr "forfait GitLab"
msgid "Checkout|Group"
msgstr "Groupe"
+msgid "Checkout|Invalid coupon code. Enter a valid coupon code."
+msgstr "Code de coupon non valide. Entrez un code de coupon valide."
+
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
msgstr "Doit valoir %{minimumNumberOfUsers} (votre nombre de sièges en cours d'utilisation) ou plus."
@@ -8588,6 +8767,9 @@ msgstr "Nom : %{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "Besoin de plus d'utilisateurs ? Achetez GitLab pour votre %{company}."
+msgid "Checkout|Network Error: %{message}"
+msgstr "Erreur réseau : %{message}"
+
msgid "Checkout|Number of users"
msgstr "Nombre d'utilisateurs"
@@ -8604,7 +8786,10 @@ msgid "Checkout|Select a country"
msgstr "Sélectionnez un pays"
msgid "Checkout|Select a state"
-msgstr ""
+msgstr "Sélectionnez un département"
+
+msgid "Checkout|Something went wrong while loading price details."
+msgstr "Une erreur s'est produite lors du chargement des détails du tarif."
msgid "Checkout|State"
msgstr "Département"
@@ -8721,17 +8906,23 @@ msgid "Choose visibility level, enable/disable project features and their permis
msgstr "Choisissez le niveau de visibilité, activez/désactivez les fonctionnalités du projet ainsi que ses permissions, désactivez les notifications par courriel et affichez les émojis de récompense par défaut."
msgid "Choose what content you want to see on a group’s overview page."
-msgstr "Choisissez le contenu que vous souhaitez voir sur la page d'aperçu de groupe."
+msgstr "Choisissez le contenu que vous souhaitez voir sur la vue d'ensemble d'un groupe."
msgid "Choose which Git strategy to use when fetching the project."
msgstr "Choisissez la stratégie Git à utiliser lors de la récupération du projet."
+msgid "Choose which branches should be mirrored"
+msgstr "Choisissez les branches à mettre en miroir"
+
msgid "Choose which repositories you want to connect and run CI/CD pipelines."
msgstr "Choisissez quels dépôts vous voulez connecter pour exécuter des pipelines d’intégration et de livraison continues (CI/CD)."
msgid "Choose your framework"
msgstr "Choisissez votre cadre"
+msgid "Ci config already present"
+msgstr "Configuration CI déjà présente"
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr "Plage de dates : %{range}"
@@ -8810,12 +9001,12 @@ msgstr "en attente"
msgid "CiStatus|running"
msgstr "en cours"
+msgid "CiVariables|Cancel"
+msgstr ""
+
msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr "Impossible d'utiliser une Variable Masquée avec la valeur actuelle"
-msgid "CiVariables|Clear inputs"
-msgstr "Effacer les entrées"
-
msgid "CiVariables|Environments"
msgstr "Environnements"
@@ -8843,6 +9034,9 @@ msgstr "Options"
msgid "CiVariables|Protected"
msgstr "Protégée"
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr "Supprimer la variable"
@@ -8859,7 +9053,7 @@ msgid "CiVariables|Scope"
msgstr "Portée"
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 "Spécifiez les valeurs de variables à utiliser lors de cette exécution. Les variables spécifiées dans le fichier de configuration et les %{linkStart}paramètres CI/CD%{linkEnd} sont utilisées par défaut."
+msgstr "Spécifiez les valeurs de variables à utiliser lors de cette exécution. Les variables spécifiées dans le fichier de configuration et les %{linkStart}paramètres CI/CD%{linkEnd} sont utilisés par défaut."
msgid "CiVariables|State"
msgstr "État"
@@ -9624,6 +9818,9 @@ msgstr "Le %{linkStart}Serveur d'Agent GitLab (KAS)%{linkEnd} n'est pas mis en Å
msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
msgstr "L’utilisateur n’a pas les permissions suffisantes pour créer un jeton pour ce projet"
+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 "Vous n'avez pas les permissions suffisantes pour créer un agent de grappe de serveurs pour ce projet"
@@ -9915,14 +10112,14 @@ msgstr "Le certificat Kubernetes utilisé pour s'authentifier auprès de la grap
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "L'URL utilisée pour accéder à l'API Kubernetes."
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr "L'intégration Kubernetes basée sur un certificat est désormais obsolète et sera désactivée à la fin du mois de février 2023. Veuillez %{linkStart}migrer vers l'agent GitLab pour Kubernetes%{linkEnd} ou contacter le support GitLab."
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
msgstr "L’intégration Kubernetes basée sur un certificat est désormais obsolète et sera désactivée à la fin du mois de février 2023. Veuillez %{linkStart}migrer vers l'agent GitLab pour Kubernetes%{linkEnd}."
msgid "ClusterIntegration|The certificate-based method to connect clusters to GitLab was %{linkStart}deprecated%{linkEnd} in GitLab 14.5."
-msgstr "La méthode à base de certificat pour connecter les grappes de serveurs à GitLab a été %{linkStart} dépréciée%{linkEnd} dans GitLab 14.5."
+msgstr "La méthode à base de certificat pour connecter les grappes de serveurs à GitLab a été %{linkStart}dépréciée%{linkEnd} dans GitLab 14.5."
msgid "ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, and Web terminals."
msgstr "L’espace de noms associé à votre projet. Il sera utilisé pour déployer les tableaux de bord et les terminaux Web."
@@ -10307,9 +10504,6 @@ msgstr "Comparer les éditions de GitLab"
msgid "Compare GitLab plans"
msgstr "Comparer les forfaits GitLab"
-msgid "Compare Revisions"
-msgstr "Comparer les révisions"
-
msgid "Compare branches and continue"
msgstr "Comparer les branches et continuer"
@@ -10322,6 +10516,9 @@ msgstr "Comparer les changements avec le dernier commit"
msgid "Compare changes with the merge request target branch"
msgstr "Comparer les modifications avec la branche cible de la demande de fusion"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr "Comparer les révisions des commits de sous-modules"
@@ -10391,12 +10588,21 @@ msgstr "Terminés"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr "Terminé en %{duration_seconds} secondes (%{relative_time})"
+msgid "Compliance Report|Frameworks"
+msgstr "Cadres"
+
+msgid "Compliance Report|Violations"
+msgstr "Violations"
+
msgid "Compliance framework"
msgstr "Cadre de conformité"
msgid "Compliance report"
msgstr "Rapport de conformité"
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Ajouter un cadre"
@@ -10505,9 +10711,24 @@ msgstr "Approuvée par le contributeur"
msgid "ComplianceReport|Less than 2 approvers"
msgstr "Moins de 2 approbateurs"
+msgid "ComplianceReport|No framework"
+msgstr "Aucun cadre"
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr "Aucune violation trouvée"
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+msgstr ""
+
+msgid "ComplianceReport|Unable to load the compliance framework report. Refresh the page and try again."
+msgstr "Impossible de charger le rapport du cadre de conformité. Actualisez la page et réessayez."
+
+msgid "ComplianceReport|Unable to load the compliance violations report. Refresh the page and try again."
+msgstr ""
+
msgid "Component"
msgstr "Composant"
@@ -10526,9 +10747,6 @@ msgstr "Note confidentielle"
msgid "Confidentiality"
msgstr "Confidentialité"
-msgid "Configuration"
-msgstr "Configuration"
-
msgid "Configuration help"
msgstr "Aide à la configuration"
@@ -11150,6 +11368,9 @@ msgstr "Vous êtes sur le point de supprimer le dépôt %{title}. Une fois confi
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "Vous pouvez ajouter une image à ce registre avec les commandes suivantes :"
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr "Contenu analysé avec %{link}."
@@ -11192,12 +11413,21 @@ msgstr "Contribution"
msgid "Contribution Analytics"
msgstr "Analytique des contributions"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr "%{createdCount} créés, %{closedCount} fermés."
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr "%{createdCount} créées, %{mergedCount} fusionnées, %{closedCount} fermées."
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr "%{created} créés, %{closed} fermés."
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr "%{created} créées, %{merged} fusionnées, %{closed} fermées."
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr "%{pushCount} de %{authorCount}."
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr "%{pushes}, plus de %{commits} par %{contributors}."
@@ -11213,6 +11443,9 @@ msgstr "Tickets fermés"
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr "Données analytiques des contributions pour les tickets, demandes de fusion et événements de poussée depuis %{start_date}"
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr "Contributions par membre du groupe"
+
msgid "ContributionAnalytics|Failed to load the contribution stats"
msgstr "Échec du chargement des statistiques des contributions"
@@ -11258,8 +11491,11 @@ msgstr "Tickets ouverts"
msgid "ContributionAnalytics|Pushed"
msgstr "Poussées"
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
-msgstr "La plage de dates fournie est supérieure à 31 jours"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr "La plage de dates donnée est supérieure à %{number_of_days} jours"
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
+msgstr "La plage de dates donnée est supérieure à 93 jours"
msgid "ContributionAnalytics|The to date is earlier than the given from date"
msgstr "La date de fin est antérieure à la date de début indiquée"
@@ -11279,8 +11515,8 @@ msgstr "Contributions par membre du groupe"
msgid "Contributor"
msgstr "Contributeur"
-msgid "Contributors"
-msgstr "Contributeurs"
+msgid "Contributor statistics"
+msgstr "Statistiques sur les contributeurs"
msgid "Control emails linked to your account"
msgstr "Contrôler les courriels liés à votre compte"
@@ -11351,6 +11587,9 @@ msgstr "Copier les commandes"
msgid "Copy commit SHA"
msgstr "Copier le SHA du commit"
+msgid "Copy diagram URL"
+msgstr "Copier l'URL du diagramme"
+
msgid "Copy environment"
msgstr "Copier l'environnement"
@@ -11597,8 +11836,8 @@ msgstr "Impossible d'assigner la stratégie au projet ou au groupe"
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr "Impossible de trouver les filtres de type d'événement que le ou les événements d'audit écrivent : %{missing_filters}"
-msgid "Country"
-msgstr "Pays"
+msgid "Country / Region"
+msgstr "Pays / Région"
msgid "Counts"
msgstr "Nombre"
@@ -11786,6 +12025,9 @@ msgstr "Créez-en un"
msgid "Create or close an issue."
msgstr "Créer ou fermer un ticket."
+msgid "Create or edit diagram"
+msgstr "Créer ou modifier un diagramme"
+
msgid "Create or import your first project"
msgstr "Créez ou importez votre premier projet"
@@ -12035,9 +12277,6 @@ msgstr "Créé le"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "A créé une branche et une demande de fusion pour résoudre ce ticket."
-msgid "Created at"
-msgstr "Créé le"
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "A créé la branche « %{branch_name} » et une demande de fusion pour résoudre ce ticket."
@@ -12245,6 +12484,9 @@ msgstr "Préférences"
msgid "CurrentUser|Start an Ultimate trial"
msgstr "Commencer un essai Ultimate"
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr ""
+
msgid "Currently unable to fetch data for this pipeline."
msgstr "Impossible actuellement de récupérer les données pour ce pipeline."
@@ -12344,8 +12586,8 @@ msgstr "Un ticket est ajouté pour la première fois dans un tableau"
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "Un ticket est associé pour la première fois à un jalon"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
-msgstr "Un ticket est associé pour la première fois à un jalon ou ajouté dans un tableau"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
+msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
msgstr "Un ticket est mentionné pour la première fois dans une validation"
@@ -12511,9 +12753,6 @@ msgstr "l’objet assigné n’est pas pris en charge"
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr "La visualisation des DAG nécessite au minimum 3 tâches dépendantes."
-msgid "DAST Configuration"
-msgstr "Configuration DAST"
-
msgid "DAST configuration not found"
msgstr "Configuration DAST introuvable"
@@ -13174,7 +13413,7 @@ msgid "DatadogIntegration|Trace your GitLab pipelines with Datadog."
msgstr "Tracer vos pipelines GitLab avec Datadog."
msgid "DatadogIntegration|have an invalid format"
-msgstr "a un format non valide"
+msgstr "ont un format non valide"
msgid "Datasource name not found"
msgstr "Nom de la source de données introuvable"
@@ -13425,6 +13664,9 @@ msgstr "Supprimer le corpus"
msgid "Delete deploy key"
msgstr "Supprimer la clé de déploiement"
+msgid "Delete diagram"
+msgstr "Supprimer le diagramme"
+
msgid "Delete epic"
msgstr "Supprimer l'épopée"
@@ -13467,6 +13709,9 @@ msgstr "Supprimer la version %{release} ?"
msgid "Delete row"
msgstr "Supprimer la ligne"
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr "Supprimer la sélection"
@@ -14218,6 +14463,9 @@ msgstr "réussi"
msgid "Deprecated API rate limits"
msgstr "Limitations de fréquence des API dépréciées"
+msgid "Deprecation notice"
+msgstr "Annonce d'obsolescence"
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr "Pour plus d'informations sur un possible remplacement, %{epicStart} en savoir plus sur Opstrace %{epicEnd}."
@@ -14319,12 +14567,15 @@ msgstr "Impossible d'ajouter un nouveau commentaire. Veuillez réessayer."
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "Impossible de créer une nouvelle discussion. Veuillez réessayer."
+msgid "DesignManagement|Could not delete comment. Please try again."
+msgstr "Impossible de supprimer le commentaire. Veuillez réessayer."
+
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr "Impossible de mettre à jour le commentaire. Veuillez réessayer."
+
msgid "DesignManagement|Could not update discussion. Please try again."
msgstr "Impossible de mettre à jour la discussion. Veuillez réessayer."
-msgid "DesignManagement|Could not update note. Please try again."
-msgstr "Impossible de mettre à jour la note. Veuillez réessayer."
-
msgid "DesignManagement|Deselect all"
msgstr "Tout désélectionner"
@@ -14427,6 +14678,9 @@ msgstr "Adoption de DevOps"
msgid "Developer"
msgstr "Développeur"
+msgid "Device name"
+msgstr "Nom de l'appareil"
+
msgid "Devices (optional)"
msgstr "Appareils (facultatif)"
@@ -14622,6 +14876,9 @@ msgstr "Votre usage"
msgid "Diagram (%{language})"
msgstr "Diagramme (%{language})"
+msgid "Diagram saved successfully."
+msgstr "Diagramme enregistré avec succès."
+
msgid "Did not delete the source branch."
msgstr "N'a pas supprimé la branche source."
@@ -14775,9 +15032,6 @@ msgstr "Notifications Discord"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr "Envoie des notifications sur les événements du projet vers un canal Discord."
-msgid "Discover"
-msgstr "Découvrir"
-
msgid "Discover GitLab Geo"
msgstr "Découvrir GitLab Geo"
@@ -15215,6 +15469,9 @@ msgstr "Modifier la clé de déploiement"
msgid "Edit description"
msgstr "Modifier la description"
+msgid "Edit diagram description"
+msgstr "Modifier la description du diagramme"
+
msgid "Edit environment"
msgstr "Modifier l'environnement"
@@ -15239,6 +15496,9 @@ msgstr "Modifier l’identité de %{user_name}"
msgid "Edit image description"
msgstr "Modifier la description de l'image"
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr "Modifier dans l'éditeur de pipeline"
@@ -15257,9 +15517,15 @@ msgstr "Modifier le lien"
msgid "Edit merge requests"
msgstr "Modifier les demandes de fusion"
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "Modifier la clé de déploiement publique"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr "Modifier la barre latérale"
@@ -15716,6 +15982,9 @@ msgstr "Entrez le code A2F pour le mode admin"
msgid "Enter Admin Mode"
msgstr "Entrer en Mode Admin"
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "Entrez un nombre"
@@ -15761,8 +16030,8 @@ msgstr "Entrez la description de %{name}"
msgid "Enter the %{name} title"
msgstr "Entrez le titre de %{name}"
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
-msgstr "Entrez le code de l'application d'authentification à deux facteurs sur votre appareil mobile. Si vous avez perdu votre appareil, vous pouvez saisir un de vos codes de récupération."
+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 "Entrez le code fourni par votre application d'authentification à deux facteurs. Si vous avez perdu votre appareil, vous pouvez saisir un de vos codes de récupération."
msgid "Enter the following to confirm:"
msgstr "Entrez ce qui suit pour confirmer :"
@@ -15779,6 +16048,9 @@ msgstr "Entrez le mot de passe pour les serveurs Elasticsearch protégés par mo
msgid "Enter the username for password-protected Elasticsearch servers."
msgstr "Entrez le nom d'utilisateur pour les serveurs Elasticsearch protégés par mot de passe."
+msgid "Enter verification code"
+msgstr "Entrez le code de vérification"
+
msgid "Enter your Packagist server. Defaults to https://packagist.org."
msgstr "Entrez votre serveur Packagist. https://packagist.org par défaut."
@@ -16073,6 +16345,9 @@ msgstr "Tableaux des Épopées"
msgid "Epic actions"
msgstr "Actions des épopées"
+msgid "Epic boards"
+msgstr "Tableaux d'épopées"
+
msgid "Epic cannot be found."
msgstr "L'épopée est introuvable."
@@ -16184,6 +16459,9 @@ msgstr "Erreur lors de la création du nouveau répertoire. Veuillez réessayer.
msgid "Error creating new iteration"
msgstr "Erreur lors de la création d'une nouvelle itération"
+msgid "Error creating or updating PreScanVerificationStep: %{errors}"
+msgstr ""
+
msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr "Erreur lors de la création du dépôt pour l'extrait de code dont l'id est %{snippet_id}"
@@ -16472,6 +16750,9 @@ msgstr "Voulez-vous vraiment supprimer la politique d'escalade « %{escalationPo
msgid "EscalationPolicies|Choose who to email if those contacted first about an alert don't respond."
msgstr "Choisissez à qui envoyer un courriel si ceux contactés en premier à propos d'une alerte ne répondent pas."
+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 "Choisissez à qui envoyer un courriel si les personnes contactées en premier à propos d'une alerte ne répondent pas. Pour accéder à cette fonctionnalité, demandez à %{linkStart}un propriétaire du projet%{linkEnd} de vous accorder au moins le rôle de mainteneur."
+
msgid "EscalationPolicies|Create an escalation policy in GitLab"
msgstr "Créer une politique d'escalade dans GitLab"
@@ -16750,6 +17031,9 @@ msgstr "Collecte de preuves"
msgid "Exactly one of %{attributes} is required"
msgstr "Exactement un des %{attributes} est requis"
+msgid "Example"
+msgstr "Exemple"
+
msgid "Example: (feature|hotfix)\\/*"
msgstr "Exemple : (feature|hotfix)\\/*"
@@ -16774,6 +17058,9 @@ msgstr "Politique « except » :"
msgid "Exceptions"
msgstr "Exceptions"
+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 "Commits de fusion exclus. Limités à %{limit} commits."
@@ -16975,6 +17262,9 @@ msgstr "Lorsqu’aucune étiquette de classification n’est définie, l’étiq
msgid "ExternalAuthorization|Access to projects is validated on an external service using their classification label."
msgstr "L’accès aux projets est validé sur un service externe en utilisant leur étiquette de classification."
+msgid "ExternalAuthorization|Allow deploy tokens and deploy keys to be used with external authorization"
+msgstr "Autoriser les jetons et clés de déploiement à être utilisés avec une autorisation externe"
+
msgid "ExternalAuthorization|Certificate used to authenticate with the external authorization service. If blank, the server certificate is validated when accessing over HTTPS."
msgstr "Certificat utilisé pour l'authentification avec le service d'autorisation externe. Si vide, le certificat du serveur est validé lors de l'accès via HTTPS."
@@ -16993,6 +17283,9 @@ msgstr "Mot de passe de la clé d'autorisation du client (facultatif)"
msgid "ExternalAuthorization|Default classification label"
msgstr "Étiquette de classification par défaut"
+msgid "ExternalAuthorization|Does not apply if service URL is specified."
+msgstr "Ne s'applique pas si l'URL du service est spécifiée."
+
msgid "ExternalAuthorization|Enable classification control using an external service"
msgstr "Activer le contrôle de classification en utilisant un service externe"
@@ -17563,9 +17856,6 @@ msgstr "févr."
msgid "February"
msgstr "février"
-msgid "Feedback and Updates"
-msgstr "Commentaires et mises à jour"
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr "Récupérez et basculez sur la branche de fonctionnalité de cette demande de fusion :"
@@ -17689,6 +17979,9 @@ msgstr "Les paramètres du filtre ne sont pas valides. Assurez-vous que la date
msgid "Filter pipelines"
msgstr "Filtrer les pipelines"
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "Filtrer les résultats"
@@ -17845,9 +18138,6 @@ msgstr "Pour chaque tâche, réutiliser l'espace de travail du projet. S'il n'en
msgid "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 "Par exemple, l'application utilisant le jeton ou le but du jeton. Ne donnez pas d'informations sensibles pour le nom du jeton, car elles seront visibles pour tous les membres du %{resource_type}."
-msgid "For faster browsing, not all history is shown."
-msgstr "Pour une navigation plus rapide, l'historique n'est pas entièrement affiché."
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr "Pour les fichiers de taille supérieure à cette limite, n'indexer que le nom. Le contenu du fichier ne sera ni indexé ni accessible aux recherches."
@@ -17989,9 +18279,6 @@ msgstr "Format : %{dateFormat}"
msgid "Framework successfully deleted"
msgstr "Framework supprimé avec succès"
-msgid "Free"
-msgstr "Gratuit"
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Essai Gratuit de GitLab.com Ultimate"
@@ -18802,14 +19089,23 @@ msgstr "La durée considérée doit être un nombre."
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "La durée considérée doit être comprise entre %{minTimePeriod} et %{maxTimePeriod} secondes."
+msgid "GitAbuse|Select between %{minAlertedUsers} and %{maxAlertedUsers} users to notify."
+msgstr "Sélectionnez entre %{minAlertedUsers} et %{maxAlertedUsers} utilisateurs à notifier."
+
+msgid "GitAbuse|Send notifications to"
+msgstr "Envoyer des notifications à"
+
msgid "GitAbuse|The maximum number of unique repositories a user can download in the specified time period before they're banned."
msgstr "Le nombre maximum de dépôts uniques qu'un utilisateur peut télécharger au cours de la période spécifiée avant d'être banni."
+msgid "GitAbuse|Users who are emailed when Git abuse rate limit is exceeded."
+msgstr "Utilisateurs auxquels des courriels sont envoyés lorsque le taux limite avant abus de Git est dépassé."
+
msgid "GitAbuse|Users who are excluded from the Git abuse rate limit."
msgstr "Utilisateurs exclus du taux limite d’abus de Git."
-msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
-msgstr "Vous ne pouvez pas spécifier plus de %{maxExcludedUsers} utilisateurs exclus."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr "Vous ne pouvez pas spécifier plus de %{maxAllowedUsers} utilisateurs exclus."
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr "La limite de fréquence d'appel à l'API de GitHub a été dépassée. Réessayez après %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr "GitLab KAS"
msgid "GitLab Pages"
msgstr "GitLab Pages"
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr "GitLab Shell"
@@ -18883,6 +19182,12 @@ msgstr "Demande de compte GitLab rejetée"
msgid "GitLab commit"
msgstr "Validation GitLab"
+msgid "GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code"
+msgstr "GitLab a détecté une tentative de connexion à votre compte %{host} à l'aide d'un code de vérification erroné"
+
+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 "GitLab a détecté une tentative de connexion à votre compte %{host} à l'aide d'un code de vérification erroné, à partir de l'adresse IP suivante : %{ip}, à %{time}"
+
msgid "GitLab documentation"
msgstr "Documentation de GitLab"
@@ -18898,9 +19203,6 @@ msgstr "GitLab pour Jira Cloud"
msgid "GitLab group: %{source_link}"
msgstr "Groupe GitLab : %{source_link}"
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr "GitLab sert d'incubateur pour des fonctionnalités dont le but est d'explorer des nouveaux cas d'usage. Ces fonctionnalités sont mises à jour régulièrement et le support est limité"
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr "GitLab vous informe si une nouvelle version est disponible. %{link_start}Quelles sont les informations collectées par GitLab Inc. ?%{link_end}"
@@ -18949,11 +19251,6 @@ msgstr "Version de GitLab"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab va créer une branche dans votre projet divergent et lancer une demande de fusion."
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] "GitLab va imposer cette limite dans le futur. Si vous avez plus de %{free_user_limit} utilisateur au moment de la mise en application, votre groupe de premier niveau, y compris ses sous-groupes et ses projets, sera placé dans un état de %{link_start}lecture seule%{link_end}. Pour éviter cette situation, réduisez votre groupe de premier niveau à %{free_user_limit} utilisateur ou moins, ou achetez une édition payante."
-msgstr[1] "GitLab va imposer cette limite dans le futur. Si vous avez plus de %{free_user_limit} utilisateurs au moment de la mise en application, votre groupe de premier niveau, y compris ses sous-groupes et ses projets, sera placé dans un état de %{link_start}lecture seule%{link_end}. Pour éviter cette situation, réduisez votre groupe de premier niveau à %{free_user_limit} utilisateurs ou moins, ou achetez une édition payante."
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -19047,12 +19344,18 @@ msgstr "Non vérifié"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Mise à jour de la configuration de vos Pages..."
+msgid "GitLabPages|Use unique domain"
+msgstr "Utiliser un domaine unique"
+
msgid "GitLabPages|Verified"
msgstr "Vérifié"
msgid "GitLabPages|Waiting for the Pages Pipeline to complete..."
msgstr "En attente de la fin du Pipeline Pages..."
+msgid "GitLabPages|When enabled, a unique domain is generated to access pages."
+msgstr "Lorsque cette option est activée, un domaine unique est généré pour accéder aux pages."
+
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. Nécessite un certificat valide pour tous les domaines. %{docs_link_start}En savoir plus.%{link_end}"
@@ -19092,6 +19395,9 @@ msgstr "URL de l’hôte Gitea"
msgid "Gitea Import"
msgstr "Importation depuis Gitea"
+msgid "GithubImporter|Collaborators"
+msgstr "Collaborateurs"
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr "Le gist avec l'id %{gist_id} a échoué à cause de l'erreur : %{error}."
@@ -19104,14 +19410,14 @@ msgstr "Gists GitHub qui n'ont pas été importés :"
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr "Les gists GitHub avec plus de 10 fichiers doivent être migrés manuellement."
-msgid "GithubImporter|Issue attachments"
-msgstr "Pièces jointes des tickets"
+msgid "GithubImporter|Issue links"
+msgstr ""
-msgid "GithubImporter|Merge request attachments"
-msgstr "Pièces jointes des demandes de fusion"
+msgid "GithubImporter|Merge request links"
+msgstr ""
-msgid "GithubImporter|Note attachments"
-msgstr "Pièces jointes des notes"
+msgid "GithubImporter|Note links"
+msgstr ""
msgid "GithubImporter|PR mergers"
msgstr "Valideurs de PR"
@@ -19128,8 +19434,8 @@ msgstr "Veuillez suivre %{import_snippets_url} pour plus de détails."
msgid "GithubImporter|Pull requests"
msgstr "Demandes de tirage"
-msgid "GithubImporter|Release attachments"
-msgstr "Pièces jointes des versions"
+msgid "GithubImporter|Release links"
+msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
msgstr "L'importation de vos gists GitHub vers les extraits GitLab est terminée."
@@ -19182,6 +19488,9 @@ msgstr "Accès donné %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr "L'épopée donnée est déjà liée à cette épopée."
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr "La Recherche Globale est désactivée pour cette portée"
@@ -19254,6 +19563,9 @@ msgstr "Tickets récents"
msgid "GlobalSearch|Recent merge requests"
msgstr "Demandes de fusion récentes"
+msgid "GlobalSearch|Reset filters"
+msgstr "Réinitialiser les filtres"
+
msgid "GlobalSearch|Result count is over limit."
msgstr "Le nombre de résultats est supérieur à la limite."
@@ -19279,7 +19591,7 @@ msgid "GlobalSearch|Show more"
msgstr "Afficher plus"
msgid "GlobalSearch|Showing top %{maxItems}"
-msgstr ""
+msgstr "Affichage des %{maxItems} premiers"
msgid "GlobalSearch|Syntax options"
msgstr "Options de syntaxe"
@@ -19308,15 +19620,9 @@ msgstr "Que recherchez-vous ?"
msgid "GlobalSearch|all GitLab"
msgstr "tout GitLab"
-msgid "GlobalSearch|group"
-msgstr "groupe"
-
msgid "GlobalSearch|in %{scope}"
msgstr "dans %{scope}"
-msgid "GlobalSearch|project"
-msgstr "projet"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr "Nom de la branche source copié dans le presse-papiers."
@@ -19533,6 +19839,30 @@ 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 "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}."
+
+msgid "GooglePlay|Drag your key file to start the upload."
+msgstr "Faites glisser votre fichier de clé pour lancer le téléversement."
+
+msgid "GooglePlay|Error: The file you're trying to upload is not a service account key."
+msgstr "Erreur : Le fichier que vous essayez de téléverser n'est pas une clé de compte de service."
+
+msgid "GooglePlay|Google Play"
+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é du 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 (remplace %{currentFileName})"
+
+msgid "GooglePlay|Use GitLab to build and release an app in Google Play."
+msgstr "Utiliser GitLab pour construire et publier une application sur Google Play."
+
msgid "Got it"
msgstr "Compris"
@@ -19722,6 +20052,9 @@ msgstr "Nom du groupe (votre entreprise)"
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"
@@ -20073,6 +20406,9 @@ msgstr "La modification de l’URL d'un groupe peut avoir des effets secondaires
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 "Choisissez un chemin de groupe qui ne commence pas par un tiret ni se termine par un point. Il peut également contenir des caractères alphanumériques et des traits de soulignement."
+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 "Choisissez les vérifications des demandes de fusion pour les projets de ce groupe. Ce paramètre prend le dessus sur le même paramètre configuré au niveau de chaque projet de ce groupe."
+
msgid "GroupSettings|Compliance frameworks"
msgstr "Cadres de conformité"
@@ -20331,6 +20667,9 @@ msgstr "Entrez l’URL de l’instance source."
msgid "GroupsNew|GitLab source instance URL"
msgstr "URL de l’instance GitLab source"
+msgid "GroupsNew|Groups"
+msgstr "Groupes"
+
msgid "GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}."
msgstr "Les groupes peuvent également être imbriqués en créant des %{linkStart}sous-groupes%{linkEnd}."
@@ -20346,6 +20685,12 @@ msgstr "Importer des groupes par transfert direct"
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr "L'importation de groupes par transfert direct est actuellement désactivée."
+msgid "GroupsNew|New group"
+msgstr "Nouveau groupe"
+
+msgid "GroupsNew|New subgroup"
+msgstr "Nouveau sous-groupe"
+
msgid "GroupsNew|No import options available"
msgstr "Aucune option d'importation n'est disponible"
@@ -20651,7 +20996,7 @@ msgid "Health Check"
msgstr "État des services"
msgid "Health information can be retrieved from the following endpoints. More information is available"
-msgstr "L’état des services peut être récupéré depuis les emplacements suivants. Plus d’information disponible."
+msgstr "L’état des services peut être récupéré depuis les emplacements suivants. Plus d’information disponible"
msgid "Health status"
msgstr "État de santé"
@@ -20722,6 +21067,9 @@ msgstr "Contribue à réduire le volume de requêtes (celles de robots d'explora
msgid "Helps reduce request volume for protected paths."
msgstr "Aide à réduire le volume de demandes pour les chemins d'accès protégés."
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr "Bonjour %{user_name} (%{user_username}) !"
+
msgid "Hi %{username}!"
msgstr "Bonjour %{username}!"
@@ -21065,6 +21413,9 @@ msgstr "Entrez un code valide."
msgid "IdentityVerification|For added security, you'll need to verify your identity in a few quick steps."
msgstr "Pour une sécurité accrue, vous devez vérifier votre identité en quelques étapes rapides."
+msgid "IdentityVerification|For added security, you'll need to verify your identity."
+msgstr "Pour plus de sécurité, votre identité doit être vérifiée."
+
msgid "IdentityVerification|For added security, you'll need to verify your identity. We've sent a verification code to %{email}"
msgstr "Pour plus de sécurité, vous devrez vérifier votre identité. Nous avons envoyé un code de vérification à %{email}"
@@ -21164,6 +21515,9 @@ msgstr "Vérifiez votre identité"
msgid "IdentityVerification|We sent a new code to +%{phoneNumber}"
msgstr "Nous avons envoyé un nouveau code au +%{phoneNumber}"
+msgid "IdentityVerification|We've sent a verification code to %{email}"
+msgstr "Un code de vérification vous a été envoyé sur %{email}"
+
msgid "IdentityVerification|We've sent a verification code to +%{phoneNumber}"
msgstr "Nous avons envoyé un code de vérification au +%{phoneNumber}"
@@ -21206,15 +21560,24 @@ msgstr "Si cette case est cochée, les propriétaires de groupe peuvent gérer l
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "Si cette case est cochée, les nouvelles adhésions aux groupes et les nouvelles permissions ne peuvent être ajoutées que via la synchronisation LDAP"
+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 "Si la case est décochée, une branche locale divergente ne sera pas mise à jour automatiquement avec les commits provenant de son homologue distant, ceci afin d'empêcher toute perte de données en local. Si la branche par défaut (%{default_branch}) a divergé et ne peut pas être mise à jour, alors la mise en miroir échouera. Les autres branches divergentes sont ignorées silencieusement. %{link_start}En savoir plus.%{link_end}"
msgid "If disabled, only administrators can configure repository mirroring."
msgstr "Si cette option est désactivée, seuls les administrateurs peuvent configurer la mise en miroir du dépôt."
+msgid "If enabled, all branches will be mirrored."
+msgstr "Si activé, toutes les branches seront mises en miroir."
+
msgid "If enabled, only protected branches will be mirrored."
msgstr "Si activé, seules les branches protégées seront mises en miroir."
+msgid "If the email address is incorrect, you can %{registration_link_start}register again with a different email%{registration_link_end}."
+msgstr "Si l'adresse de courriel est incorrecte, vous pouvez %{registration_link_start}vous réinscrire avec une adresse différente%{registration_link_end}."
+
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 "Si le nombre d'utilisateurs actifs dépasse la limite définie, une quantité de %{users_over_license_link} vous sera facturée lors du prochain rapprochement de votre licence."
@@ -21275,8 +21638,8 @@ msgstr "Si vous perdez vos codes de récupération, vous pouvez en générer de
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "Si vous vous êtes connecté récemment et que vous reconnaissez l'adresse IP, vous pouvez ignorer ce courriel."
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email."
-msgstr "Si vous avez récemment essayé de vous connecter, mais que vous avez entré un code d'authentification à deux facteurs incorrect, vous pouvez ignorer ce courriel."
+msgid "If you recently tried to sign in, but mistakenly entered an incorrect verification code, you can ignore this email."
+msgstr "Si vous avez récemment essayé de vous connecter, mais que vous avez entré un code de vérification incorrect, vous pouvez ignorer ce courriel."
msgid "If you want to re-enable two-factor authentication, visit %{two_factor_link}"
msgstr "Si vous souhaitez réactiver l'authentification à deux facteurs, consultez %{two_factor_link}"
@@ -21501,6 +21864,9 @@ msgstr "L'importation du projet a échoué"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr "L'importation du projet a échoué : %{reason}"
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr "La réimportation crée un nouveau projet. Il n'est pas synchronisé avec le projet existant."
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr "L'interrogation des espaces de noms a échoué"
@@ -21905,8 +22271,8 @@ msgstr "Protégez votre application Web en utilisant DAST pour rechercher les vu
msgid "InProductMarketing|Rapid development, simplified"
msgstr "Développement rapide, simplifié"
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
-msgstr "Réduire les Risques de Sécurité et de Conformité"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
+msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
msgstr "Exigez plusieurs approbateurs sur une demande de fusion, vous saurez ainsi que tout est pour le mieux avant qu'elle ne soit fusionnée."
@@ -22568,12 +22934,18 @@ msgstr "Insérer une image"
msgid "Insert link"
msgstr "Insérer un lien"
+msgid "Insert or edit diagram"
+msgstr "Insérer ou modifier un diagramme"
+
msgid "Insert row after"
msgstr "Insérer une ligne après"
msgid "Insert row before"
msgstr "Insérer une ligne avant"
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "Insérer une suggestion"
@@ -22747,12 +23119,15 @@ msgstr "Les paramètres par défaut sont hérités de ceux au niveau du groupe."
msgid "Integrations|Default settings are inherited from the instance level."
msgstr "Les paramètres par défaut sont hérités de ceux au niveau de l'instance."
+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 "Modifier l'alias du projet"
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
-msgstr "Activer les commandes de barre oblique GitLab.com dans un espace de travail Slack."
-
msgid "Integrations|Enable SSL verification"
msgstr "Activer la vérification SSL"
@@ -22768,6 +23143,9 @@ msgstr "Assurez-vous que l'URL de votre instance est correcte et que votre insta
msgid "Integrations|Enter your alias"
msgstr "Entrez votre alias"
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr "Échec de la liaison de l'espace de noms. Veuillez réessayer."
@@ -23056,8 +23434,8 @@ msgstr "Bundle de dépôt non valide pour l'extrait d'id %{snippet_id}"
msgid "Invalid repository path"
msgstr "Chemin de dépôt non valide"
-msgid "Invalid rule"
-msgstr "Règle non valide"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr "Réponse du serveur non valide"
@@ -23185,9 +23563,6 @@ msgstr "Créer des tickets pour que le nouveau membre de votre équipe travaille
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 "Pendant votre essai, vous pouvez inviter autant de membres que vous voulez sur %{groupName}. Une fois l'essai terminé, vous aurez un maximum de %{dashboardLimit} membres sur l'édition Gratuite. Pour obtenir un plus grand nombre de membres, %{linkStart}faites une mise à niveau vers une édition payante%{linkEnd}."
-msgid "InviteMembersModal|Explore paid plans"
-msgstr "Découvrir les forfaits payants"
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr "GitLab, c'est mieux avec des collègues !"
@@ -23457,6 +23832,12 @@ msgstr "Type de Ticket"
msgid "Issue already promoted to epic."
msgstr "Le ticket a déjà été promu en épopée."
+msgid "Issue board"
+msgstr "Tableau de tickets"
+
+msgid "Issue boards"
+msgstr "Tableaux de tickets"
+
msgid "Issue cannot be found."
msgstr "Le ticket est introuvable."
@@ -23682,6 +24063,9 @@ msgstr "Une erreur s'est produite lors du déplacement des tickets."
msgid "Issue|Title"
msgstr "Titre"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr "Il semble que vous essayez d'activer votre abonnement. Utilisez %{a_start}la page d'abonnement%{a_end} à la place."
@@ -24219,9 +24603,24 @@ msgstr "La tâche a été retentée"
msgid "JobAssistant|Add job"
msgstr "Ajouter une tâche"
+msgid "JobAssistant|Job Setup"
+msgstr "Configuration de la tâche"
+
msgid "JobAssistant|Job assistant"
msgstr "Assistant de tâche"
+msgid "JobAssistant|Job name"
+msgstr "Nom de la tâche"
+
+msgid "JobAssistant|Script"
+msgstr "Script"
+
+msgid "JobAssistant|Stage (optional)"
+msgstr "Étape (facultative)"
+
+msgid "JobAssistant|Tags (optional)"
+msgstr "Étiquettes (facultatives)"
+
msgid "Jobs"
msgstr "Tâches"
@@ -24910,6 +25309,15 @@ msgstr "En savoir plus."
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
msgstr "Terminé à %{percentage}%{percentSymbol}"
+msgid "LearnGitLab|1. Add code to your project"
+msgstr "1. Ajouter du code à votre projet"
+
+msgid "LearnGitLab|2. Build"
+msgstr "2. Construire"
+
+msgid "LearnGitLab|Add code"
+msgstr "Ajouter du code"
+
msgid "LearnGitLab|Add code owners"
msgstr "Ajoutez des propriétaires de code"
@@ -24991,6 +25399,9 @@ msgstr "Configurer votre espace de travail"
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "Commencez un essai gratuit de GitLab Ultimate"
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr "Commencer avec l'IDE Web"
+
msgid "LearnGitLab|Submit a merge request (MR)"
msgstr "Soumettre une demande de fusion (MR)"
@@ -25000,6 +25411,9 @@ msgstr "Essayez GitLab Ultimate gratuitement"
msgid "LearnGitLab|Try all GitLab features for 30 days, no credit card required."
msgstr "Essayez toutes les fonctionnalités de GitLab pendant 30 jours, aucune carte de crédit n’est requise."
+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 "Utilisez votre nouveau flux de travail GitLab pour déployer votre application, surveiller son état de santé et assurer sa sécurité :"
@@ -25015,9 +25429,6 @@ msgstr "Contactez votre administrateur pour activer cette action."
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr "Contactez votre administrateur pour démarrer un essai gratuit d'Ultimate."
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr "Création de votre expérience d'intégration..."
-
msgid "LearnGitlab|Ok, let's go"
msgstr "D'accord, allons-y"
@@ -25033,6 +25444,9 @@ msgstr "Quitter le Mode Admin"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "Quitter le mode édition ? Toutes les modifications non enregistrées seront perdues."
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Quitter le groupe"
@@ -25282,6 +25696,11 @@ msgstr "Limiter la taille des tâches Sidekiq stockées dans Redis."
msgid "Limiting mode"
msgstr "Mode de limitation"
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] "Ligne"
+msgstr[1] "Lignes"
+
msgid "Line changes"
msgstr "Lignes changées"
@@ -25309,6 +25728,9 @@ msgstr "Lier un wiki externe à la barre latérale du projet. %{docs_link}"
msgid "Link copied"
msgstr "Lien copié"
+msgid "Link does not exist"
+msgstr "Le lien n'existe pas"
+
msgid "Link text"
msgstr "Texte de lien"
@@ -25402,9 +25824,6 @@ msgstr "Lister les dépôts disponibles"
msgid "List of all commits"
msgstr "Liste de tous les commits"
-msgid "List of all merge commits"
-msgstr "Liste de tous les commits de fusion"
-
msgid "List of suitable GCP locations"
msgstr "Liste des emplacements GCP appropriés"
@@ -25447,6 +25866,9 @@ msgstr "Chargement des statistiques de contribution des membres du groupe"
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr "Chargement des fichiers, répertoires et sous-modules dans le chemin %{path} pour la référence de commit %{ref}"
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr "Suite en cours de chargement"
@@ -25486,6 +25908,9 @@ msgstr "Verrouiller le fichier ?"
msgid "Lock memberships to LDAP synchronization"
msgstr "Verrouiller les adhésions à la synchronisation LDAP"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr "Verrouiller la demande de fusion"
@@ -25504,9 +25929,6 @@ msgstr "Verrouiller aux projets en cours"
msgid "Locked"
msgstr "Verrouillé"
-msgid "Locked Files"
-msgstr "Fichiers verrouillés"
-
msgid "Locked by %{fileLockUserName}"
msgstr "Verrouillé par %{fileLockUserName}"
@@ -25576,9 +25998,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "FUSIONNÉE"
-msgid "ML Experiments"
-msgstr "Expériences d'AA"
-
msgid "MR widget|Back to the merge request"
msgstr "Revenir à la demande de fusion"
@@ -25615,11 +26034,8 @@ msgstr "Afficher uniquement les modifications"
msgid "MRDiff|Show full file"
msgstr "Afficher le fichier complet"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr "Le Suivi d'Expérience d'Apprentissage Automatique est à l'Étape de l'Incubation"
-
-msgid "Machine Learning Experiments"
-msgstr "Expériences d'Apprentissage Automatique"
+msgid "Macbook Touch ID on Edge"
+msgstr ""
msgid "Made this %{type} confidential."
msgstr "Ce(tte) %{type} a été rendu(e) confidentiel(le)."
@@ -26110,6 +26526,9 @@ msgstr "Taille maximale de poussée"
msgid "Maximum push size (MB)"
msgstr "Taille maximale de poussée (Mo)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr "Nombre maximum de requêtes par période de 10 minutes et par adresse IP"
+
msgid "Maximum requests per 10 minutes per user"
msgstr "Nombre maximum de requêtes par période de 10 minutes et par utilisateur"
@@ -26191,12 +26610,21 @@ msgstr "%{member_name} vous a invité à 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 "MemberRole|%{role} - custom"
+msgstr "%{role} - personnalisé"
+
msgid "MemberRole|can't be changed"
msgstr "ne peut pas être modifié"
msgid "MemberRole|cannot be changed because it is already assigned to a user. Please create a new Member Role instead"
msgstr "ne peut pas être modifié car il est déjà assigné à un utilisateur. Veuillez plutôt créer un nouveau Rôle de Membre"
+msgid "MemberRole|cannot be deleted because it is already assigned to a user. Please disassociate the member role from all users before deletion."
+msgstr "ne peut pas être supprimé car il est déjà attribué à un utilisateur. Veuillez dissocier le rôle de membre de tous les utilisateurs avant de le supprimer."
+
+msgid "MemberRole|maximum number of Member Roles are already in use by the group hierarchy. Please delete an existing Member Role."
+msgstr ""
+
msgid "MemberRole|must be top-level namespace"
msgstr "doit être un espace de noms de premier niveau"
@@ -26417,18 +26845,9 @@ msgstr "Fusionner automatiquement (%{strategy})"
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr "Fusion bloquée : toutes les dépendances de demande de fusion doivent être fusionnées."
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr "Fusion bloquée : la demande de fusion doit être marquée comme prête. Elle est toujours marquée comme brouillon."
-
-msgid "Merge blocked: new changes were just added."
-msgstr "Fusion bloquée : de nouvelles modifications viennent d'être apportées."
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr "Fusion bloquée : le pipeline doit réussir. Il est en attente d'une tâche manuelle pour continuer."
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr "Fusion bloquée : la branche source doit être rebasée sur la branche cible."
-
msgid "Merge commit SHA"
msgstr "SHA du commit de fusion"
@@ -26501,9 +26920,6 @@ msgstr "Les demandes de fusion permettent de proposer les modifications que vous
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr "Les demandes de fusion ne peuvent pas être fusionnées si les vérifications d'état ont échoué ou sont toujours en cours d'exécution."
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr "Fusion indisponible : les demandes de fusion dans un nœud Geo secondaire sont en lecture seule."
-
msgid "Merge unverified changes"
msgstr "Fusionner les modifications non vérifiées"
@@ -26516,6 +26932,27 @@ msgstr "Fusionner lorsque le pipeline réussit"
msgid "Merge..."
msgstr "Fusionner..."
+msgid "MergeChecks|All threads must be resolved"
+msgstr "Tous les fils de conversation doivent être résolus"
+
+msgid "MergeChecks|Enable \"Pipelines must succeed\" first."
+msgstr "Activez d'abord « Les pipelines doivent réussir »."
+
+msgid "MergeChecks|Introduces the risk of merging changes that do not pass the pipeline."
+msgstr "Présente le risque de fusionner des modifications qui ne passent pas le pipeline."
+
+msgid "MergeChecks|Merge requests can't be merged if the latest pipeline did not succeed or is still running."
+msgstr "Les demandes de fusion ne peuvent pas être fusionnées si le dernier pipeline a échoué ou est toujours en cours d'exécution."
+
+msgid "MergeChecks|Pipelines must succeed"
+msgstr "Les pipelines doivent réussir"
+
+msgid "MergeChecks|Skipped pipelines are considered successful"
+msgstr "Les pipelines ignorés sont considérés réussis"
+
+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 "Ce paramètre est configuré dans le groupe %{groupName} et ne peut être modifié que dans les paramètres du groupe par un administrateur ou par un propriétaire du groupe."
+
msgid "MergeConflict|Commit to source branch"
msgstr "Valider sur la branche source"
@@ -27126,6 +27563,9 @@ msgstr[1] "Jalons"
msgid "Milestone due date"
msgstr "Date d'échéance du jalon"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr "Id(s) de jalon introuvable(s) : %{milestones}"
+
msgid "Milestone lists not available with your current license"
msgstr "La liste des jalons n’est pas disponible avec votre licence actuelle"
@@ -27306,6 +27746,12 @@ msgstr "La capacité minimale qui doit être disponible avant de programmer plus
msgid "Minutes"
msgstr "Minutes"
+msgid "Mirror all branches"
+msgstr "Mettre en miroir toutes les branches"
+
+msgid "Mirror branches"
+msgstr "Mettre des branches en miroir"
+
msgid "Mirror direction"
msgstr "Sens du miroir"
@@ -27318,6 +27764,9 @@ msgstr "Dépôt miroir"
msgid "Mirror settings are only available to GitLab administrators."
msgstr "Les paramètres de miroir ne sont disponibles que pour les administrateurs GitLab."
+msgid "Mirror specific branches"
+msgstr "Mettre en miroir des branches spécifiques"
+
msgid "Mirror user"
msgstr "Utilisateur accédant au miroir"
@@ -27378,33 +27827,48 @@ msgstr "-"
msgid "MlExperimentTracking|Artifacts"
msgstr "Artéfacts"
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr "Créer une nouvelle expérience"
+
msgid "MlExperimentTracking|Created at"
msgstr "Créé"
msgid "MlExperimentTracking|Details"
msgstr "Détails"
+msgid "MlExperimentTracking|Experiment"
+msgstr "Expérience"
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr "Candidats de l'expérience"
msgid "MlExperimentTracking|Filter candidates"
msgstr "Filtrer les candidats"
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr "Candidats consignés pour l'expérience"
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr "Suivi des expériences d'apprentissage automatique"
+msgid "MlExperimentTracking|Model experiments"
+msgstr "Expériences du modèle"
+
msgid "MlExperimentTracking|Name"
msgstr "Nom"
msgid "MlExperimentTracking|No candidates to display"
msgstr "Aucun candidat à afficher"
+msgid "MlExperimentTracking|No experiments"
+msgstr "Aucune expérience"
+
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr "Aucune expérience n'a été consignée pour ce projet. Créez une nouvelle expérience à l'aide du client MLflow."
+
msgid "MlExperimentTracking|User"
msgstr "Utilisateur"
-msgid "MlExperimentsEmptyState|No Experiments to Show"
-msgstr "Aucune Expérience à afficher"
-
msgid "Modal updated"
msgstr "Fenêtre modale mise à jour"
@@ -27746,6 +28210,9 @@ msgstr "Espaces de noms"
msgid "Namespaces to index"
msgstr "Espaces de noms à indexer"
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "Nommage, sujets, avatar"
@@ -27794,11 +28261,17 @@ msgstr "Rouge"
msgid "Navigation|Context navigation"
msgstr "Navigation contextuelle"
-msgid "Navigation|Recent groups"
-msgstr "Groupes récents"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
-msgid "Navigation|Recent projects"
-msgstr "Projets récents"
+msgid "Navigation|Projects you visit often will appear here."
+msgstr ""
msgid "Navigation|Switch to..."
msgstr "Basculer vers..."
@@ -27910,9 +28383,6 @@ msgstr "Nouvelle Exigence"
msgid "New Snippet"
msgstr "Nouvel extrait de code"
-msgid "New Test Case"
-msgstr "Nouveau Cas de Test"
-
msgid "New User"
msgstr "Nouvel utilisateur"
@@ -28000,9 +28470,6 @@ msgstr "Nouveau Nom"
msgid "New password"
msgstr "Nouveau mot de passe"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr "Les nouveaux pipelines entraînent l'annulation de ceux plus anciens qui sont en attente ou en cours d'exécution sur la même branche."
-
msgid "New project"
msgstr "Nouveau projet"
@@ -28357,6 +28824,15 @@ msgstr "Aucun compte de service"
msgid "No severity matches the provided parameter"
msgstr "Aucune gravité ne correspond au paramètre fourni"
+msgid "No slash-separated component can begin with %{sequencePrefixes}"
+msgstr "Aucun des composants séparés par des barres obliques ne peut commencer par %{sequencePrefixes}"
+
+msgid "No slash-separated component can end with %{sequencePostfixes}"
+msgstr "Aucun des composants séparés par des barres obliques ne peut se terminer par %{sequencePostfixes}"
+
+msgid "No slash-separated tag name component can be empty"
+msgstr "Aucun des composants séparés par des barres obliques ne peut être vide"
+
msgid "No source selected"
msgstr "Aucune source sélectionnée"
@@ -28364,7 +28840,7 @@ msgid "No stack trace for this error"
msgstr "Pas de trace de pile pour cette erreur"
msgid "No starrers matched your search"
-msgstr ""
+msgstr "Aucun supporteur ne correspond à votre recherche"
msgid "No suggestions found"
msgstr "Aucune suggestion trouvée"
@@ -28440,14 +28916,17 @@ msgstr "Refonte de la navigation"
msgid "NorthstarNavigation|New navigation"
msgstr "Nouvelle navigation"
+msgid "NorthstarNavigation|Provide feedback"
+msgstr "Donner un avis"
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr "Activer/désactiver la nouvelle navigation"
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
-msgstr "Tous les navigateurs ne gèrent pas les appareils U2F. Par conséquent, il vous faut d'abord configurer une application d'authentification à deux facteurs. De cette façon, vous serez toujours en mesure de vous connecter - même si vous utilisez un navigateur non pris en charge."
+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 "Tous les navigateurs ne gèrent pas WebAuthn. Par conséquent, il vous faut d'abord configurer une application d'authentification à deux facteurs. De cette façon, vous serez toujours en mesure de vous connecter, même si vous utilisez un navigateur non pris en charge."
-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 "Tous les navigateurs ne gèrent pas WebAuthn. Par conséquent, il vous faut d'abord configurer une application d'authentification à deux facteurs. De cette façon, vous serez toujours en mesure de vous connecter - même si vous utilisez un navigateur non pris en charge."
+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 "Tous les navigateurs ne prennent pas en charge WebAuthn. Vous devez sauvegarder vos codes de récupération juste après avoir enregistré un authentificateur à deux facteurs pour pouvoir vous connecter, même à partir d'un navigateur non pris en charge."
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr "Toutes les données n'ont pas encore été traitées, la précision du graphique pour la période sélectionnée est limitée."
@@ -28748,12 +29227,24 @@ msgstr "%{paragraph_start}Bonjour %{name}!%{paragraph_end} %{paragraph_start}Une
msgid "Notify|%{project_link_start}Download%{project_link_end} the project export."
msgstr "%{project_link_start}Téléchargez%{project_link_end} l'exportation du projet."
+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|%{update_at_start} Last update at %{update_at_mid} %{last_update_at} %{update_at_end}"
msgstr "%{update_at_start} Dernière mise à jour le %{update_at_mid} %{last_update_at} %{update_at_end}"
msgid "Notify|%{updated_by_user_name} pushed new commits to merge request %{mr_link}"
msgstr "%{updated_by_user_name} a poussé de nouveaux commits sur la demande de fusion %{mr_link}"
+msgid "Notify|%{work_items} successfully imported."
+msgstr ""
+
msgid "Notify|A new GPG key was added to your account:"
msgstr "Une nouvelle clé GPG a été ajoutée sur votre compte :"
@@ -28802,9 +29293,18 @@ msgstr "Erreur lors de l'analyse du fichier CSV. Veuillez vous assurer qu'il a l
msgid "Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check if these lines have an issue title."
msgstr "Erreurs trouvées sur %{singular_or_plural_line} : %{error_lines}. Veuillez vérifier si ces lignes ont un titre de ticket."
+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 "Empreinte : %{fingerprint}"
+msgid "Notify|Here are the results for your CSV import for %{project_link}."
+msgstr "Voici les résultats de votre importation CSV pour %{project_link}."
+
+msgid "Notify|Here are the results for your CSV import for %{project_name} (%{project_link})."
+msgstr "Voici les résultats de votre importation CSV pour %{project_name} (%{project_link})."
+
msgid "Notify|Hi %{username}!"
msgstr "Bonjour %{username} !"
@@ -28832,9 +29332,6 @@ msgstr "Les journaux peuvent contenir des données sensibles. Veuillez en tenir
msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict."
msgstr "La demande de fusion %{merge_request} ne peut plus être fusionnée en raison d'un conflit."
-msgid "Notify|Merge request %{merge_request} was %{mr_status}"
-msgstr "La demande de fusion %{merge_request} a été %{mr_status}"
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr "La demande de fusion %{merge_request} a été %{mr_status} par %{updated_by}"
@@ -28871,6 +29368,9 @@ msgstr "Nouveau ticket : %{project_issue_url}"
msgid "Notify|No preview for this file type"
msgstr "Aucun aperçu pour ce type de fichier"
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr "Le pipeline #%{pipeline_id} a échoué !"
@@ -28880,6 +29380,9 @@ msgstr "Pipeline %{pipeline_link} déclenché par"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
msgstr "Le pipeline a été corrigé et #%{pipeline_id} est passé !"
+msgid "Notify|Please fix the lines with errors and try the CSV import again."
+msgstr "Veuillez corriger les lignes contenant des erreurs et réessayez l’importation CSV."
+
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr "Le projet %{old_path_with_namespace} a été déplacé vers un autre emplacement."
@@ -28892,6 +29395,9 @@ msgstr "Le projet %{project_name} a été exporté avec succès."
msgid "Notify|Remote mirror"
msgstr "Miroir distant"
+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 "L'Administrateur vous a créé un compte. Vous êtes à présent membre de l'application GitLab de l'entreprise."
@@ -29126,7 +29632,7 @@ msgid "OnCallSchedules|Create on-call schedules in GitLab"
msgstr "Créer des calendriers d'astreintes dans GitLab"
msgid "OnCallSchedules|Currently no rotation."
-msgstr ""
+msgstr "Actuellement aucune rotation."
msgid "OnCallSchedules|Delete rotation"
msgstr "Supprimer le cycle"
@@ -29165,7 +29671,7 @@ msgid "OnCallSchedules|On-call schedules"
msgstr "Calendriers d'astreintes"
msgid "OnCallSchedules|Please note, rotations with shifts that are less than four hours are currently not supported in the weekly view."
-msgstr ""
+msgstr "Veuillez noter que les rotations avec des quarts de travail inférieurs à quatre heures ne sont actuellement pas prises en charge dans la vue hebdomadaire."
msgid "OnCallSchedules|Removing this user may put their on-call team at risk of missing a notification."
msgstr "La suppression de cet utilisateur peut exposer son équipe d'astreinte au risque de manquer une notification."
@@ -29183,7 +29689,7 @@ msgid "OnCallSchedules|Rotation length"
msgstr "Durée de cycle"
msgid "OnCallSchedules|Rotation length must be a positive number"
-msgstr ""
+msgstr "La durée de la rotation doit être un nombre positif"
msgid "OnCallSchedules|Rotation name cannot be empty"
msgstr "Le nom du cycle ne peut pas être vide"
@@ -29368,6 +29874,9 @@ msgstr "Les analyses à la demande s'exécutent en dehors du cycle DevOps et tro
msgid "OnDemandScans|Only project owners and maintainers can select runner tags."
msgstr "Seuls les propriétaires et les mainteneurs du projet peuvent sélectionner des tags d'exécuteur."
+msgid "OnDemandScans|Pre-scan verification for %{profile_name} completed with"
+msgstr ""
+
msgid "OnDemandScans|Repeats"
msgstr "Répétitions"
@@ -29437,9 +29946,6 @@ msgstr "Fuseau horaire"
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr "Impossible de récupérer les tags d’exécuteur. Essayez de recharger la page."
-msgid "OnDemandScans|Verify"
-msgstr "Vérifier"
-
msgid "OnDemandScans|Verify configuration"
msgstr "Vérifier la configuration"
@@ -29733,29 +30239,35 @@ msgstr "Notre équipe a été notifiée. Veuillez réessayer."
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr "Non conforme(s) aux stratégies de ce projet et à supprimer"
-msgid "OutboundRequests|Allow requests to the local network from hooks and services."
-msgstr "Autoriser les requêtes vers le réseau local depuis les crochets et les services."
+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 "Autoriser les requêtes vers le réseau local depuis les crochets du système"
-msgid "OutboundRequests|Allow requests to the local network from web hooks and services"
-msgstr "Autoriser les requêtes vers le réseau local depuis les crochets web et les services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
+msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
-msgstr "Imposer la protection contre les attaques par DNS rebinding"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
+msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
-msgstr "Adresses IP locales et noms de domaines auxquels les services et crochets peuvent accéder"
+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 "Requêtes sortantes"
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
-msgstr "Les requêtes vers ces domaines et adresses IP sont accessibles à la fois aux crochets du système et aux crochets Web même lorsque les requêtes locales ne sont pas autorisées. Les plages d'IP telles que 1:0:0:0:0:0:0/124 ou 127.0.0/28 sont prises en charge. Les domaines wildcard ne sont pas pris en charge. Pour séparer les entrées, utilisez des virgules, des points-virgules ou des nouvelles lignes. La liste d'autorisation peut contenir un maximum de 1000 entrées. Les domaines doivent utiliser l'encodage IDNA."
+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 once and uses them to submit requests."
-msgstr "Résoudre les adresses IP une seule fois et les utiliser pour soumettre des requêtes."
+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 "GitLab peut ne pas fonctionner correctement car vous utilisez un navigateur Web obsolète."
@@ -30551,6 +31063,9 @@ msgstr "Suppression en attente"
msgid "Pending comments"
msgstr "Commentaires en attente"
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "Suppression en attente"
@@ -30740,9 +31255,6 @@ msgstr "Vous avez atteint le nombre maximal d'essais. Patientez %{interval} et r
msgid "Pick a name"
msgstr "Choisir un nom"
-msgid "Pin code"
-msgstr "Code Pin"
-
msgid "Pipeline"
msgstr "Pipeline"
@@ -30941,6 +31453,9 @@ msgstr "En attente du chargement du contenu CI..."
msgid "PipelineGraph|Are you sure you want to retry %{jobName}?"
msgstr "Voulez-vous vraiment réessayer %{jobName} ?"
+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 "Réessayer une tâche de déclencheur créera un nouveau pipeline en aval."
@@ -31166,6 +31681,9 @@ msgstr "Pipelines"
msgid "Pipelines charts"
msgstr "Graphiques des pipelines"
+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 "Les paramètres des pipelines pour « %{project_name} » ont été mis à jour avec succès."
@@ -31217,9 +31735,6 @@ msgstr "Pipeline enfant (%{link_start}parent%{link_end})"
msgid "Pipelines|Clear runner caches"
msgstr "Vider les caches des exécuteurs"
-msgid "Pipelines|Configuration validation currently not available."
-msgstr "La validation de la configuration n'est pas disponible actuellement."
-
msgid "Pipelines|Configure pipeline"
msgstr "Configurer le pipeline"
@@ -31265,6 +31780,12 @@ msgstr "GitLab Runner est une application qui fonctionne avec GitLab CI/CD pour
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
msgstr "GitLab Runner est une application qui fonctionne avec GitLab CI/CD pour exécuter des tâches dans un pipeline. Il y a des exécuteurs actifs disponibles pour exécuter vos tâches dès à présent. Si vous préférez, vous pouvez %{settingsLinkStart}configurer vos exécuteurs%{settingsLinkEnd} ou %{docsLinkStart}en savoir plus%{docsLinkEnd} à leur propos."
+msgid "Pipelines|Go to the pipeline editor"
+msgstr "Aller à l'éditeur de pipeline"
+
+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 "En cas de doute, veuillez demander à un mainteneur du projet de l'examiner pour vous."
@@ -31316,8 +31837,8 @@ msgstr "Propriétaire"
msgid "Pipelines|Pipeline Editor"
msgstr "Éditeur de Pipeline"
-msgid "Pipelines|Pipeline syntax is correct."
-msgstr "La syntaxe du pipeline est correcte."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr "Réinitialisation du cache de projet réussie."
@@ -31325,6 +31846,9 @@ msgstr "Réinitialisation du cache de projet réussie."
msgid "Pipelines|Ready to set up CI/CD for your project?"
msgstr "Prêt pour la configuration CI/CD de votre projet ?"
+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|Revoke trigger"
msgstr "Révoquer le déclencheur"
@@ -31361,14 +31885,14 @@ msgstr "Une erreur s'est produite lors du chargement des données du pipeline."
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
msgstr "Une erreur est survenue lors de la récupération des pipelines. Réessayez dans quelques instants ou contactez votre équipe d’assistance."
-msgid "Pipelines|This GitLab CI configuration is invalid."
-msgstr "Cette configuration de GitLab CI n’est pas valide."
+msgid "Pipelines|This GitLab CI configuration is invalid. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is invalid:"
msgstr "Cette configuration de GitLab CI n’est pas valide :"
-msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}."
-msgstr "Cette configuration de GitLab CI n’est pas valide : %{reason}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
msgstr "Cette configuration de GitLab CI est valide."
@@ -31397,6 +31921,12 @@ msgstr "L’utilisateur du déclencheur n’a pas les permissions suffisantes po
msgid "Pipelines|Try test template"
msgstr "Essayer le modèle de test"
+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 "Utilisez un fichier modèle d'exemple %{codeStart}.gitlab-ci.yml%{codeEnd} pour découvrir le fonctionnement de CI/CD."
@@ -31418,6 +31948,9 @@ msgstr "Afficher le YAML à fusionner"
msgid "Pipelines|Visualize"
msgstr "Visualiser"
+msgid "Pipelines|We'll continuously validate your pipeline configuration. The validation results will appear here."
+msgstr "Votre configuration de pipeline sera validée en continu. Les résultats de validation apparaîtront ici."
+
msgid "Pipelines|We'll guide you through a simple pipeline set-up."
msgstr "Nous allons vous guider à travers la configuration d'un pipeline simple."
@@ -31427,6 +31960,9 @@ msgstr "Nous allons vous expliquer comment déployer sur iOS en deux étapes sim
msgid "Pipelines|You have runners available to run your job now. No need to do anything else."
msgstr "Vous avez des exécuteurs disponibles pour lancer votre tâche maintenant. Pas besoin de faire quoi que ce soit d'autre."
+msgid "Pipelines|You should review the code thoroughly before running this pipeline with the parent project's CI/CD resources."
+msgstr ""
+
msgid "Pipelines|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr "Vos modifications ont été validées avec succès. Redirection vers la page de nouvelle demande de fusion."
@@ -31742,6 +32278,9 @@ msgstr "Veuillez supprimer votre licence actuelle si vous souhaitez revenir au f
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "Veuillez activer et migrer vers un stockage haché pour éviter les problèmes de sécurité et assurer l'intégrité des données. %{migrate_link}"
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "Veuillez entrer un nombre non négatif"
@@ -31763,6 +32302,9 @@ msgstr "Veuillez entrer un intervalle de temps valide"
msgid "Please enter a value of 90 days or more"
msgstr "Veuillez entrer une valeur de 90 jours ou plus"
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr "Veuillez entrer votre mot de passe actuel."
@@ -31823,8 +32365,8 @@ msgstr "Veuillez sélectionner"
msgid "Please select a Jira project"
msgstr "Veuillez sélectionner un projet Jira"
-msgid "Please select a country"
-msgstr "Veuillez sélectionner un pays"
+msgid "Please select a country / region"
+msgstr "Veuillez sélectionner un pays / une région"
msgid "Please select a group"
msgstr "Veuillez sélectionner un groupe"
@@ -32177,6 +32719,9 @@ msgstr "Aperçu du diagramme"
msgid "Preview payload"
msgstr "Aperçu de la charge utile"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "Artéfacts précédents"
@@ -32246,150 +32791,90 @@ msgstr "Problème avec la commande %{name} : %{message}."
msgid "Proceed"
msgstr "Poursuivre"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr "Ajoutez le paquet NPM à votre package.json à l'aide de votre gestionnaire de paquets préféré :"
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr "Ajoutez le script dans la page et assignez le client SDK à la fenêtre :"
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr "Analysez votre produit avec l'Analytique des Produits"
-
-msgid "Product Analytics|Back to dashboards"
-msgstr "Retour aux tableaux de bord"
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr "Création de votre instance analytique de produits..."
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr "Détails sur la façon de configurer l'analytique des produits pour collecter des données."
-
-msgid "Product Analytics|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 de l'analytique des produits commence à vous montrer des données, vous devez ajouter le code de suivi analytique à votre projet."
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr "Identifie l'expéditeur des événements de suivi"
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr "Importez le nouveau paquet dans votre code JS :"
-
-msgid "Product Analytics|Instrument your application"
-msgstr "Instrumentez votre application"
-
-msgid "Product Analytics|Instrumentation details"
-msgstr "Détails de l’instrumentation"
-
-msgid "Product Analytics|SDK App ID"
-msgstr "ID de l'appli SDK"
-
-msgid "Product Analytics|SDK Host"
-msgstr "Hôte SDK"
-
-msgid "Product Analytics|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 "Mettez en œuvre l'Analytique des Produits pour suivre les performances de votre produit. Combinez-la avec vos données GitLab pour mieux comprendre où vous pouvez améliorer votre produit et vos processus de développement."
-
-msgid "Product Analytics|Set up product analytics"
-msgstr "Configurer l'analytique des produits"
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr "Étapes pour ajouter l'analytique des produits en tant que module CommonJS"
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr "Étapes pour ajouter l'analytique des produits en tant que balise de script HTML"
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr "Étapes pour ajouter l'analytique des produits en tant que module ESM"
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr "L'hôte auquel envoyer tous les événements de suivi"
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
-msgstr "Cela peut prendre un certain temps, n’hésitez pas à naviguer ailleurs que sur cette page et revenez plus tard."
-
-msgid "Product Analytics|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 "Pour instrumenter votre application, sélectionnez l'une des options ci-dessous. Après l'instrumentation et une fois les données en cours de collecte, cette page passera à l'étape suivante."
-
msgid "Product analytics"
msgstr "Analytique des produits"
msgid "ProductAnalytics|Add another dimension"
msgstr "Ajouter une autre dimension"
-msgid "ProductAnalytics|Add to Dashboard"
-msgstr "Ajouter au tableau de bord"
-
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Clicks Compared"
+msgstr "Comparaison de tous les clics"
+
+msgid "ProductAnalytics|All Events Compared"
+msgstr "Comparaison de tous les événements"
+
+msgid "ProductAnalytics|All Features"
msgstr "Toutes les fonctionnalités"
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Pages"
msgstr "Toutes les pages"
+msgid "ProductAnalytics|All Sessions Compared"
+msgstr "Comparaison de toutes les sessions"
+
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
msgstr "Une erreur s'est produite lors du chargement du panneau %{panelTitle}."
msgid "ProductAnalytics|An error occurred while fetching data. Refresh the page to try again."
msgstr "Une erreur s'est produite lors de la récupération des données. Actualisez la page pour réessayer."
+msgid "ProductAnalytics|Analyze your product with Product Analytics"
+msgstr ""
+
msgid "ProductAnalytics|Any Click on elements"
msgstr "Tout clic sur des éléments"
msgid "ProductAnalytics|Audience"
msgstr "Audience"
-msgid "ProductAnalytics|Browser"
-msgstr "Navigateur"
+msgid "ProductAnalytics|Average Per User"
+msgstr "Moyenne par utilisateur"
-msgid "ProductAnalytics|Browser Family"
-msgstr "Famille de navigateur"
+msgid "ProductAnalytics|Average Session Duration"
+msgstr "Durée moyenne de session"
-msgid "ProductAnalytics|Cancel Edit"
-msgstr "Annuler la modification"
+msgid "ProductAnalytics|Average duration in minutes"
+msgstr "Durée moyenne en minutes"
-msgid "ProductAnalytics|Choose a chart type on the right"
-msgstr "Choisissez un type de graphique sur la droite"
+msgid "ProductAnalytics|Back to dashboards"
+msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
-msgstr "Choisissez une mesure pour commencer"
+msgid "ProductAnalytics|Cancel Edit"
+msgstr "Annuler la modification"
msgid "ProductAnalytics|Click Events"
msgstr "Événements de clic"
-msgid "ProductAnalytics|Code"
-msgstr "Code"
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr "Compare tous les événements les uns aux autres"
+msgid "ProductAnalytics|Compares all user sessions against each other"
+msgstr "Compare toutes les sessions utilisateurs les unes aux autres"
+
msgid "ProductAnalytics|Compares click events against each other"
msgstr "Compare les événements de clic les uns aux autres"
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr "Compare l'utilisation des fonctionnalités les unes aux autres pour toutes les fonctionnalités"
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr "Compare les vues de pages les unes aux autres pour toutes les pages"
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
-msgstr "Les tableaux de bord sont créés en modifiant les fichiers de tableau de bord des projets."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
+msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr "Données"
+msgid "ProductAnalytics|Creating your product analytics instance..."
+msgstr ""
-msgid "ProductAnalytics|Data Table"
-msgstr "Tableau de données"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
+msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr "Dimensions"
-msgid "ProductAnalytics|Edit"
-msgstr "Modifier"
-
msgid "ProductAnalytics|Event Type"
msgstr "Type d’événement"
@@ -32402,23 +32887,32 @@ msgstr "Événements groupés par %{granularity}"
msgid "ProductAnalytics|Events over time"
msgstr "Événements au cours du temps"
-msgid "ProductAnalytics|Feature Usage"
-msgstr "Utilisation des fonctionnalités"
+msgid "ProductAnalytics|Feature Usages"
+msgstr ""
-msgid "ProductAnalytics|Feature usage"
-msgstr "Utilisation des fonctionnalités"
+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 "Retour"
-msgid "ProductAnalytics|Host"
-msgstr "Hôte"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr "Combien de sessions possède un utilisateur"
-msgid "ProductAnalytics|Language"
-msgstr "Langage"
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
-msgid "ProductAnalytics|Line Chart"
-msgstr "Graphique linéaire"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
+msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
msgstr "Mesurer tous les événements suivis"
@@ -32426,59 +32920,68 @@ msgstr "Mesurer tous les événements suivis"
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr "Mesurer toutes les vues de pages, ou des vues de pages spécifiques"
-msgid "ProductAnalytics|Measuring"
-msgstr "À mesurer"
-
-msgid "ProductAnalytics|New Analytics Panel Title"
-msgstr "Titre du nouveau panneau analytique"
+msgid "ProductAnalytics|Measure all sessions"
+msgstr "Mesurer toutes les sessions"
-msgid "ProductAnalytics|OS"
-msgstr "OS"
+msgid "ProductAnalytics|Measure by unique users"
+msgstr "Mesurer par utilisateurs uniques"
-msgid "ProductAnalytics|OS Version"
-msgstr "Version de l'OS"
+msgid "ProductAnalytics|Measuring"
+msgstr "À mesurer"
msgid "ProductAnalytics|On what do you want to get insights?"
msgstr "Sur quoi voulez-vous obtenir des statistiques ?"
-msgid "ProductAnalytics|Page Language"
-msgstr "Langage de page"
+msgid "ProductAnalytics|Page Views"
+msgstr "Vues de page"
-msgid "ProductAnalytics|Page Path"
-msgstr "Chemin de page"
+msgid "ProductAnalytics|Repeat Visit Percentage"
+msgstr ""
-msgid "ProductAnalytics|Page Title"
-msgstr "Titre de page"
+msgid "ProductAnalytics|SDK App ID"
+msgstr ""
-msgid "ProductAnalytics|Page Views"
-msgstr "Vues de page"
+msgid "ProductAnalytics|SDK Host"
+msgstr ""
-msgid "ProductAnalytics|Pages"
-msgstr "Pages"
+msgid "ProductAnalytics|Sessions"
+msgstr "Sessions"
+
+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|Panel"
-msgstr "Panneau"
+msgid "ProductAnalytics|Set up product analytics"
+msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
-msgstr "Tableaux de bord de l'analytique des produits"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
+msgstr ""
-msgid "ProductAnalytics|Referer"
-msgstr "Référent"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
+msgstr ""
-msgid "ProductAnalytics|Resulting Data"
-msgstr "Données résultantes"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
+msgstr ""
-msgid "ProductAnalytics|Single Statistic"
-msgstr "Statistique unique"
+msgid "ProductAnalytics|The host to send all tracking events to"
+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 "Il n’y a pas de données pour ce type de graphique actuellement. Veuillez consulter l’onglet Configuration si vous n’avez pas déjà configuré l’outil des données analytiques de produit."
+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 "Suivre des fonctionnalités spécifiques"
-msgid "ProductAnalytics|URL"
-msgstr "URL"
+msgid "ProductAnalytics|Unique Users"
+msgstr "Utilisateurs uniques"
+
+msgid "ProductAnalytics|User Sessions"
+msgstr "Sessions utilisateurs"
msgid "ProductAnalytics|User activity"
msgstr "Activité des utilisateurs"
@@ -32486,12 +32989,6 @@ msgstr "Activité des utilisateurs"
msgid "ProductAnalytics|Users"
msgstr "Utilisateurs"
-msgid "ProductAnalytics|Viewport"
-msgstr "Zone d'affichage"
-
-msgid "ProductAnalytics|Visualization Type"
-msgstr "Type de visualisation"
-
msgid "ProductAnalytics|What do you want to measure?"
msgstr "Que voulez-vous mesurer ?"
@@ -32657,6 +33154,12 @@ msgstr "Déconnecter"
msgid "Profiles|Disconnect %{provider}"
msgstr "Déconnecter %{provider}"
+msgid "Profiles|Discord ID is too long (maximum is %{max_length} characters)."
+msgstr "L'ID Discord est trop long (le maximum est de %{max_length} caractères)."
+
+msgid "Profiles|Discord ID is too short (minimum is %{min_length} characters)."
+msgstr "L'ID Discord est trop court (le minimum est de %{min_length} caractères)."
+
msgid "Profiles|Do not show on profile"
msgstr "Ne pas montrer sur le profil"
@@ -32906,8 +33409,8 @@ msgstr "Vous devez faire un transfert de propriété ou supprimer les groupes do
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Vous devez transférer la propriété ou supprimer ces groupes avant de pouvoir supprimer votre compte."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
-msgstr "Votre ID d'utilisateur Discord. Doit faire entre %{min} et %{max} chiffres de long. %{external_accounts_link_start}En savoir plus.%{external_accounts_link_end}"
+msgid "Profiles|Your Discord user ID. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+msgstr "Votre ID d'utilisateur Discord. %{external_accounts_link_start}En savoir plus.%{external_accounts_link_end}"
msgid "Profiles|Your LinkedIn profile name from linkedin.com/in/profilename"
msgstr "Votre nom de profil LinkedIn accessible à partir de linkedin.com/in/nom_profil"
@@ -33080,6 +33583,9 @@ msgstr "Membres du projet"
msgid "Project milestone"
msgstr "Jalon du projet"
+msgid "Project must have default branch"
+msgstr "Le projet doit avoir une branche par défaut"
+
msgid "Project name"
msgstr "Nom du projet"
@@ -33092,6 +33598,9 @@ 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 ""
+
msgid "Project path"
msgstr "Chemin du projet"
@@ -33119,6 +33628,9 @@ msgstr "Le niveau de visibilité du projet est moins restrictif que celui défin
msgid "Project visibility level will be changed to match namespace rules when transferring to a group."
msgstr "Le niveau de visibilité du projet sera modifié pour correspondre aux règles de l'espace de noms lors du transfert vers un groupe."
+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 "Le projet n'a pas été trouvé ou vous n'avez pas la permission de l'ajouter aux Tableaux de bord de Sécurité."
@@ -33189,10 +33701,10 @@ msgid "ProjectOverview|Star"
msgstr "Ajouter aux favoris"
msgid "ProjectOverview|Starrer"
-msgstr ""
+msgstr "Supporteur"
msgid "ProjectOverview|Starrers"
-msgstr ""
+msgstr "Supporteurs"
msgid "ProjectOverview|Unstar"
msgstr "Supprimer des favoris"
@@ -33215,9 +33727,21 @@ msgstr "Identifiant de projet : %{project_id}"
msgid "ProjectQualitySummary|An error occurred while trying to fetch project quality statistics"
msgstr "Une erreur s'est produite lors de la tentative de récupération des statistiques de qualité du projet"
+msgid "ProjectQualitySummary|Analysis of your source code's quality and complexity."
+msgstr "Analyse de la qualité et de la complexité de votre code source."
+
+msgid "ProjectQualitySummary|Blocker"
+msgstr "Bloquant"
+
+msgid "ProjectQualitySummary|Code quality"
+msgstr "Qualité du code"
+
msgid "ProjectQualitySummary|Coverage"
msgstr "Couverture"
+msgid "ProjectQualitySummary|Critical"
+msgstr "Critique"
+
msgid "ProjectQualitySummary|Failure"
msgstr "Échec"
@@ -33230,6 +33754,9 @@ msgstr "Aidez-nous à améliorer cette page"
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr "Derniers résultats du pipeline"
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr "En savoir plus sur la qualité du code"
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr "En savoir plus sur la couverture des tests"
@@ -33272,8 +33799,11 @@ msgstr "Le pourcentage des tests qui ont réussi, échoué ou été ignorés."
msgid "ProjectQualitySummary|This page helps you understand the code testing trends for your project. Let us know how we can improve it!"
msgstr "Cette page vous aide à comprendre les tendances des tests de code de votre projet. Faites-nous savoir comment nous pouvons l'améliorer !"
-msgid "ProjectSelect| or group"
-msgstr " ou un groupe"
+msgid "ProjectQualitySummary|Violations"
+msgstr "Violations"
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr "Violations trouvées"
msgid "ProjectSelect|No matching results"
msgstr "Aucun résultat correspondant"
@@ -33287,9 +33817,6 @@ msgstr "Rechercher des projets"
msgid "ProjectSelect|Select a project"
msgstr "Sélectionnez un projet"
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr "Une erreur s'est produite lors de la récupération des projets"
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr "Une erreur s'est produite lors de la récupération des projets. Veuillez réessayer."
@@ -33419,9 +33946,6 @@ msgstr "Paramètres supplémentaires qui agissent sur comment et quand les fusio
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr "Toutes les demandes de fusion et les validations sont faites sur cette branche, sauf si vous en spécifiez une autre."
-msgid "ProjectSettings|All threads must be resolved"
-msgstr "Tous les fils de conversation doivent être résolus"
-
msgid "ProjectSettings|Allow"
msgstr "Autoriser"
@@ -33572,9 +34096,6 @@ msgstr "Infrastructure"
msgid "ProjectSettings|Internal"
msgstr "Interne"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr "Présente le risque de fusionner des modifications qui ne passent pas le pipeline."
-
msgid "ProjectSettings|Issues"
msgstr "Tickets"
@@ -33617,9 +34138,6 @@ msgstr "Demandes de fusion"
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 "Les demandes de fusion approuvées pour être fusionnées sont mises en file d'attente, et les pipelines valident les résultats combinés des branches source et cible avant la fusion. %{link_start}Que sont les trains de fusion ?%{link_end}"
-msgid "ProjectSettings|Merge requests can't be merged if the latest pipeline did not succeed or is still running."
-msgstr "Les demandes de fusion ne peuvent pas être fusionnées si le dernier pipeline a échoué ou est toujours en cours d'exécution."
-
msgid "ProjectSettings|Merge suggestions"
msgstr "Suggestions de fusion"
@@ -33656,9 +34174,6 @@ msgstr "Pages"
msgid "ProjectSettings|Pages for project documentation."
msgstr "Pages pour la documentation du projet."
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "Les pipelines doivent réussir"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr "Empêche les liens directs vers des fichiers multimédia potentiellement sensibles"
@@ -33701,11 +34216,11 @@ msgstr "Intégrez de nouvelles fonctionnalités sans faire de nouveau déploieme
msgid "ProjectSettings|Search for topic"
msgstr "Rechercher un sujet"
-msgid "ProjectSettings|Security & Compliance"
-msgstr "Sécurité & Conformité"
+msgid "ProjectSettings|Security and Compliance"
+msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
-msgstr "Sécurité & Conformité de ce projet"
+msgid "ProjectSettings|Security and compliance for this project."
+msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
msgstr "Sélectionnez la branche par défaut pour ce projet et configurez le modèle pour les noms de branches."
@@ -33728,9 +34243,6 @@ msgstr "Afficher les émojis de récompense par défaut"
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr "Afficher un lien pour créer ou afficher une demande de fusion lors des poussées faites à partir de la ligne de commande"
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr "Les pipelines ignorés sont considérés comme réussis"
-
msgid "ProjectSettings|Snippets"
msgstr "Extraits"
@@ -33965,6 +34477,9 @@ msgstr "Projets (%{count})"
msgid "Projects API"
msgstr "API des projets"
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr "Projets Récupérés avec Succès"
@@ -34091,6 +34606,9 @@ msgstr "Migrez vos données depuis une source externe comme GitHub, Bitbucket ou
msgid "ProjectsNew|Must start with a lowercase or uppercase letter, digit, emoji, or underscore. Can also contain dots, pluses, dashes, or spaces."
msgstr "Doit commencer par une lettre minuscule ou majuscule, un chiffre, un émoji ou un trait de soulignement. Peut également contenir des points, des signes plus, des tirets ou des espaces."
+msgid "ProjectsNew|New project"
+msgstr "Nouveau projet"
+
msgid "ProjectsNew|No import options available"
msgstr "Aucune option d'importation n'est disponible"
@@ -34106,6 +34624,9 @@ msgstr "Configuration du Projet"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "Description du projet %{tag_start}(facultative)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr "Projets"
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr "Recommandé si vous êtes nouveau sur GitLab"
@@ -34286,9 +34807,6 @@ msgstr "Contactez le propriétaire %{link_start}%{owner_name}%{link_end} pour me
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr "Contactez votre administrateur pour mettre à niveau votre licence."
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "Les modèles de description vous permettent de définir des modèles spécifiques à un contexte pour les champs de description des tickets et des demandes de fusion de votre projet."
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr "Ignorer l'offre promotionnelle du Service d'assistance"
@@ -34397,12 +34915,6 @@ msgstr "Lorsque vous avez de nombreux tickets, il peut être difficile d'en avoi
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr "Vous pouvez restreindre l'accès aux branches protégées en sélectionnant un rôle (Mainteneurs, Développeurs) ou des utilisateurs spécifiques."
-msgid "Promotions|description templates"
-msgstr "modèles de description"
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr "pour aider vos contributeurs à communiquer efficacement !"
-
msgid "Prompt users to upload SSH keys"
msgstr "Inviter les utilisateurs à téléverser des clés SSH"
@@ -34574,9 +35086,25 @@ msgstr "Vous ne pouvez ajouter que des groupes qui ont ce projet en partage. %{l
msgid "ProtectedBranch|default"
msgstr "par défaut"
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] "%d règle d'approbation"
+msgstr[1] "%d règles d'approbation"
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] "%d règle de déploiement"
+msgstr[1] "%d règles de déploiement"
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr "Ajouter des règles d'approbation"
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr "Ajouter des règles de déploiement"
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr "Autorisés à approuver"
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr "Autorisés à déployer"
@@ -34586,11 +35114,23 @@ msgstr "Une erreur s'est produite lors de la récupération des informations sur
msgid "ProtectedEnvironments|Approval rules"
msgstr "Règles d'approbation"
+msgid "ProtectedEnvironments|Approvals required"
+msgstr "Approbations requises"
+
+msgid "ProtectedEnvironments|Create approval rule"
+msgstr "Créer une règle d'approbation"
+
msgid "ProtectedEnvironments|Create deployment rule"
msgstr "Créer une règle de déploiement"
-msgid "ProtectedEnvironments|Delete deployment rule"
-msgstr "Supprimer la règle de déploiement"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
+msgstr "Modifier"
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
msgstr "Liste des environnements protégés (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ 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|Save"
+msgstr "Enregistrer"
+
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."
msgid "ProtectedEnvironments|Set which groups, access levels or users that are allowed to deploy to this environment"
msgstr "Définir quels sont les groupes, niveaux d'accès ou utilisateurs autorisés à faire des déploiements dans cet environnement"
+msgid "ProtectedEnvironments|Unified approval rules have been removed from the settings UI"
+msgstr "Les règles d'approbation unifiées ont été supprimées de l'interface des paramètres"
+
msgid "ProtectedEnvironments|Users"
msgstr "Utilisateurs"
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr "Vous pouvez toujours utiliser l'%{apiLinkStart}API%{apiLinkEnd} pour configurer des règles d'approbation unifiées. Envisagez plutôt l'utilisation de %{docsLinkStart}règles d'approbations multiples%{docsLinkEnd} car elles offrent une plus grande flexibilité."
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} sera accessible en écriture aux développeurs. Êtesâ€vous sûr de vouloir cela ?"
@@ -34616,6 +35165,9 @@ msgstr "Tous les environnements spécifiés avec les niveaux de déploiement ci-
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "Autorisé à déployer"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr "Autorisés à déployer et approuver"
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr "Autorisés à déployer sur %{project} / %{environment}"
@@ -35072,24 +35624,15 @@ msgstr "Prêt pour la fusion !"
msgid "Reauthenticating with SAML provider."
msgstr "Réauthentification avec le fournisseur SAML."
-msgid "Rebase"
-msgstr "Rebaser"
-
msgid "Rebase completed"
msgstr "Rebasage terminé"
-msgid "Rebase in progress"
-msgstr "Rebasage en cours"
-
msgid "Rebase source branch"
msgstr "Rebaser la branche source"
msgid "Rebase source branch on the target branch."
msgstr "Rebaser la branche source sur la branche cible."
-msgid "Rebase without pipeline"
-msgstr "Rebaser sans pipeline"
-
msgid "Recaptcha verified?"
msgstr "Recaptcha vérifié ?"
@@ -35165,6 +35708,9 @@ msgstr "Affinez vos critères de recherche (sélectionnez un %{strong_open}group
msgid "Refresh the page and try again."
msgstr "Actualiser la page et réessayer."
+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] "L’affichage sera réactualisé dans une seconde avec le statut mis à jour..."
@@ -35200,14 +35746,14 @@ msgstr "S'inscrire"
msgid "Register / Sign In"
msgstr "Inscription / Connexion"
-msgid "Register Two-Factor Authenticator"
-msgstr "Enregistrer un Authentificateur A2F"
+msgid "Register a WebAuthn device"
+msgstr "Enregistrer un appareil WebAuthn"
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "Enregistrer un Appareil Universel à Deux Facteurs (U2F)"
+msgid "Register a one-time password authenticator"
+msgstr "Enregistrer un authentificateur de mot de passe à usage unique"
-msgid "Register WebAuthn Device"
-msgstr "Enregistrer un Appareil WebAuthn"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
+msgstr ""
msgid "Register device"
msgstr "Enregistrer un appareil"
@@ -35299,6 +35845,9 @@ msgstr "Rejetées (fermées)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr "Est lié au %{issuable_type} %{add_related_issue_link}"
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr "Indicateurs de fonctionnalité associés"
@@ -36234,15 +36783,21 @@ msgstr "L'exigence %{reference} a été rouverte"
msgid "Requirement %{reference} has been updated"
msgstr "L'exigence %{reference} a été mise à jour"
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr "Le titre de l'exigence ne peut pas avoir plus de %{limit} caractères."
-
msgid "Requirements"
msgstr "Exigences"
msgid "Requirements can be based on users, stakeholders, system, software, or anything else you find important to capture."
msgstr "Les exigences peuvent être basées sur les utilisateurs, les intervenants, le système, les logiciels ou tout autre élément dont la capture vous paraît importante."
+msgid "Requirement|Legacy requirement ID: %{legacyId}"
+msgstr "ID de l'exigence héritée : %{legacyId}"
+
+msgid "Requirement|Legacy requirement IDs are being deprecated. Update your links to reference this item's new ID %{id}. %{linkStart}Learn more%{linkEnd}."
+msgstr "Les IDs des exigences héritées vont devenir obsolètes. Mettez à jour vos liens pour référencer l'élément via son nouvel ID %{id}. %{linkStart}En savoir plus%{linkEnd}."
+
+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 "Les exigences sont devenues des éléments de travail et les IDs des exigences héritées vont devenir obsolètes. Mettez à jour vos liens pour référencer l'élément via son nouvel ID %{id}. %{linkStart}En savoir plus%{linkEnd}."
+
msgid "Requires %d approval from eligible users."
msgid_plural "Requires %d approvals from eligible users."
msgstr[0] "Nécessite %d approbation d'utilisateurs éligibles."
@@ -36413,7 +36968,7 @@ msgid "Restrict projects for this runner"
msgstr "Restreindre les projets de cet exécuteur"
msgid "Restricted shift times are not available for hourly shifts"
-msgstr ""
+msgstr "Les horaires de travail restreints ne sont pas disponibles pour les quarts horaires"
msgid "Results limit reached"
msgstr "Limite de résultats atteinte"
@@ -36421,9 +36976,6 @@ msgstr "Limite de résultats atteinte"
msgid "Resume"
msgstr "Reprendre"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr "La récupération du rapport de conformité a échoué. Actualisez la page et réessayez."
-
msgid "Retry"
msgstr "Réessayer"
@@ -36593,9 +37145,6 @@ msgstr "Exécuter des tâches de maintenance pour optimiser automatiquement les
msgid "Run job"
msgstr "Exécuter la tâche"
-msgid "Run manual job again"
-msgstr "Exécuter de nouveau la tâche manuelle"
-
msgid "Run manual or delayed jobs"
msgstr "Exécuter des tâches manuelles ou différées"
@@ -36670,6 +37219,9 @@ msgstr "Actif"
msgid "Runners|Add notes such as the runner owner or what it should be used for."
msgstr "Ajoutez des notes, comme à qui appartient l'exécuteur ou à quoi il doit servir."
+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 "Ajouter des tags pour les types de tâches que l'exécuteur traite pour s'assurer que celui-ci exécute uniquement les tâches que vous avez l'intention de lui faire exécuter. %{helpLinkStart}En savoir plus.%{helpLinkEnd}"
+
msgid "Runners|Administrator"
msgstr "Administrateur"
@@ -36733,6 +37285,9 @@ msgstr "La capacité de 1 active la haute disponibilité avec reprise semi-autom
msgid "Runners|Checkbox"
msgstr "Case à cocher de sélection"
+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 "Sélectionnez un exécutant lorsque cela vous est proposé en ligne de commande. Les exécutants lancent les compilations dans différents environnements. %{linkStart}Vous hésitez sur lequel choisir ?%{linkEnd}"
+
msgid "Runners|Choose your preferred GitLab Runner"
msgstr "Choisissez votre exécuteur GitLab préféré"
@@ -36751,6 +37306,9 @@ msgstr "Configuration"
msgid "Runners|Containers"
msgstr "Conteneurs"
+msgid "Runners|Copy and paste the following command into your command line to register the runner."
+msgstr "Copiez et collez la commande suivante dans votre interpréteur de commandes pour enregistrer l’exécuteur."
+
msgid "Runners|Copy instructions"
msgstr "Copier les instructions"
@@ -36807,9 +37365,15 @@ msgstr "Activer le nettoyage des exécuteurs périmés"
msgid "Runners|Enable stale runner cleanup?"
msgstr "Activer le nettoyage des exécuteurs périmés ?"
+msgid "Runners|Enter the number of seconds."
+msgstr "Entrez le nombre de secondes."
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr "Entrez le nombre de secondes. Ce délai d'expiration a la priorité sur les délais inférieurs définis pour le projet."
+msgid "Runners|Environment"
+msgstr "Environnement"
+
msgid "Runners|Executor"
msgstr "Exécuteur"
@@ -36822,6 +37386,12 @@ msgstr "Filtrer les projets"
msgid "Runners|Get started with runners"
msgstr "Démarrez avec les exécuteurs"
+msgid "Runners|GitLab Runner must be installed before you can register a runner. %{linkStart}How do I install GitLab Runner?%{linkEnd}"
+msgstr "GitLab Runner doit être installé avant de pouvoir enregistrer un exécuteur. %{linkStart}Comment puis-je installer GitLab Runner ?%{linkEnd}"
+
+msgid "Runners|Go to runners page"
+msgstr "Aller à la page des exécuteurs"
+
msgid "Runners|Group"
msgstr "Groupe"
@@ -36840,6 +37410,9 @@ msgstr "Au repos"
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr "Si les deux paramètres sont désactivés, les nouveaux exécuteurs ne pourront pas être enregistrés."
+msgid "Runners|Install GitLab Runner"
+msgstr "Installer GitLab Runner"
+
msgid "Runners|Install a runner"
msgstr "Installer un exécuteur"
@@ -36867,6 +37440,12 @@ msgstr "Verrouillé sur ce projet"
msgid "Runners|Maintenance note"
msgstr "Note de maintenance"
+msgid "Runners|Manually verify that the runner is available to pick up jobs."
+msgstr "Vérifiez manuellement que l'exécuteur est disponible pour aller chercher des tâches."
+
+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 "Durée maximale pendant laquelle l'exécuteur peut tourner avant de prendre fin. Si un projet a une durée plus courte pour le délai d'attente avant expiration des tâches, celle de l'exécuteur d'instance est utilisée à la place."
+
msgid "Runners|Maximum job timeout"
msgstr "Délai d'expiration maximal des tâches"
@@ -36876,6 +37455,9 @@ msgstr "Les membres du %{type} peuvent enregistrer des exécuteurs"
msgid "Runners|Minor version upgrades are available."
msgstr "Des mises à jour de version mineure sont disponibles."
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr "Une virgule doit séparer les tags s'il y en a plusieurs. Par exemple : %{example}."
+
msgid "Runners|Name"
msgstr "Nom"
@@ -36888,6 +37470,9 @@ msgstr "Jamais contacté :"
msgid "Runners|Never expires"
msgstr "N'expire jamais"
+msgid "Runners|New"
+msgstr "Nouveau"
+
msgid "Runners|New group runners can be registered"
msgstr "Les nouveaux exécuteurs de groupe peuvent être enregistrés"
@@ -36930,6 +37515,9 @@ msgstr "Seuls les administrateurs peuvent voir celle-ci."
msgid "Runners|Operating systems"
msgstr "Systèmes d'exploitation"
+msgid "Runners|Optional. Step 3"
+msgstr "Facultatif. Étape 3"
+
msgid "Runners|Owner"
msgstr "Propriétaire"
@@ -36962,6 +37550,12 @@ msgstr "Protégé"
msgid "Runners|Recommended"
msgstr "Recommandé"
+msgid "Runners|Register"
+msgstr "Inscription"
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr "Enregistrer l'exécuteur « %{runnerDescription} »"
+
msgid "Runners|Register a group runner"
msgstr "Enregistrer un exécuteur de groupe"
@@ -36977,6 +37571,9 @@ msgstr "Enregistrer un exécuteur d'instance"
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 "Enregistrez autant d'exécuteurs que vous le souhaitez. Vous pouvez les enregistrer en tant qu'utilisateurs séparés, sur des serveurs séparés et sur votre machine locale."
+msgid "Runners|Register runner"
+msgstr ""
+
msgid "Runners|Registration token"
msgstr "Jeton d'inscription"
@@ -37001,6 +37598,9 @@ msgstr "Exécuteur #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
msgstr "L'exécuteur %{name} a été supprimé"
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr "Échec de la suppression de l'exécuteur %{runnerName}"
+
msgid "Runners|Runner Registration"
msgstr "Enregistrement des exécuteurs"
@@ -37016,6 +37616,12 @@ msgstr "Expiration du jeton d'authentification de l'exécuteur"
msgid "Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired."
msgstr "Les jetons d'authentification des exécuteurs expireront selon un intervalle défini. Ils seront renouvelés automatiquement une fois expirés."
+msgid "Runners|Runner created."
+msgstr "Exécuteur créé."
+
+msgid "Runners|Runner description"
+msgstr "Description de l’exécuteur"
+
msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
msgstr "L'exécuteur a contacté GitLab au cours des dernières %{elapsedTime}"
@@ -37088,9 +37694,15 @@ msgstr "Exécute des tâches non marquées"
msgid "Runners|Security or compatibility upgrades are recommended."
msgstr "Les mises à jour de sécurité ou de compatibilité sont recommandées."
+msgid "Runners|See more %{linkStart}installation methods and architectures%{linkEnd}."
+msgstr ""
+
msgid "Runners|Select all"
msgstr "Tout sélectionner"
+msgid "Runners|Select platform specifications to install GitLab Runner."
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr "Sélectionnez les projets à attribuer à cet exécuteur"
@@ -37124,6 +37736,12 @@ msgstr "Périmé :"
msgid "Runners|Status"
msgstr "État"
+msgid "Runners|Step 1"
+msgstr "Étape 1"
+
+msgid "Runners|Step 2"
+msgstr "Étape 2"
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr "Ne plus accepter de nouvelles tâches pour l'exécuteur."
@@ -37133,6 +37751,9 @@ msgstr "Étiquettes"
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 "Les étiquettes contrôlent quels sont les types de tâches qu'un exécuteur peut gérer. En étiquetant un exécuteur, vous avez la garantie que les exécuteurs partagés ne gérerons que les tâches qu'ils sont capables d'exécuter."
+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 create the runner. It will not be visible once the runner is registered."
+msgstr "Le %{boldStart}jeton d'exécuteur%{boldEnd} %{token} s'affiche %{boldStart}seulement sur une courte durée%{boldEnd} et est stocké dans %{codeStart}config.oml%{codeEnd} après la création de l'exécuteur. Il ne sera pas visible une fois l'exécuteur enregistré."
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr "Le projet, le groupe ou l'instance où l'exécuteur a été enregistré. Les exécuteurs d'instance sont toujours détenus par l'Administrateur."
@@ -37150,6 +37771,9 @@ msgstr[1] "Ce groupe a actuellement %d exécuteurs périmés."
msgid "Runners|This group currently has no stale runners."
msgstr "Ce groupe n'a actuellement aucun exécuteur périmé."
+msgid "Runners|This may not be needed if you manage your runner as a %{linkStart}system or user service%{linkEnd}."
+msgstr "Cela peut ne pas être nécessaire si vous gérez votre exécuteur en tant que %{linkStart}service système ou utilisateur%{linkEnd}."
+
msgid "Runners|This runner has not run any jobs."
msgstr "Cet exécuteur n'a exécuté aucune tâche."
@@ -37198,6 +37822,9 @@ msgstr "Mise à jour recommandée"
msgid "Runners|Use Group runners when you want all projects in a group to have access to a set of runners."
msgstr "Utilisez les Exécuteurs de groupe quand vous souhaitez que tous les projets d'un groupe aient accès à un ensemble d'exécuteurs."
+msgid "Runners|Use the runner for jobs without tags in addition to tagged jobs."
+msgstr "Utilisez l’exécuteur pour les tâches sans tag en plus des tâches taguées."
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr "Utiliser l'exécuteur pour les tâches sans étiquette, en plus des tâches étiquetées."
@@ -37252,15 +37879,6 @@ msgstr "projet"
msgid "Runners|shared"
msgstr "partagé"
-msgid "Runner|New"
-msgstr "Nouveau"
-
-msgid "Runner|Owner"
-msgstr "Propriétaire"
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr "Échec de la suppression de l'exécuteur %{runnerName}"
-
msgid "Running"
msgstr "En cours d’exécution"
@@ -37282,6 +37900,9 @@ msgstr "Jetons de découverte SAML"
msgid "SAML for %{group_name}"
msgstr "SAML pour %{group_name}"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr "Authentification unique SAML"
@@ -37306,9 +37927,6 @@ 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 "SAST Configuration"
-msgstr "Configuration SAST"
-
msgid "SCIM|SCIM Token"
msgstr "Jeton SCIM"
@@ -37438,17 +38056,20 @@ msgstr "%{period} %{days} à %{time}"
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr "%{rules} actions pour la %{scopes} %{branches} %{agents} %{namespaces}"
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
-msgstr "%{thenLabelStart}Alors%{thenLabelEnd} Nécessite l'exécution d'une analyse %{scan} avec le profil de site %{siteProfile} et le profil de scanner %{scannerProfile} avec les étiquettes %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
+msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
-msgstr "%{thenLabelStart}Alors%{thenLabelEnd} Nécessite l'exécution d'une analyse %{scan} avec les étiquettes %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
+msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr "Un pipeline est exécuté"
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
-msgstr "Ex. nom-étiquette-1, nom-étiquette-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
+msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
msgstr "Si le champ est vide, l’exécuteur sera choisi automatiquement"
@@ -37489,9 +38110,15 @@ msgstr "agent"
msgid "ScanExecutionPolicy|branch"
msgstr "branche"
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr "dans les espaces de noms"
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr "%{count} licences"
@@ -37940,24 +38567,27 @@ msgstr "UUID"
msgid "Security"
msgstr "Sécurité"
-msgid "Security & Compliance"
-msgstr "Sécurité et Conformité"
-
-msgid "Security Configuration"
-msgstr "Configuration de la sécurité"
-
msgid "Security Dashboard"
msgstr "Tableau de bord de sécurité"
msgid "Security Finding not found"
msgstr "Découverte de Sécurité introuvable"
+msgid "Security Policy project already exists."
+msgstr ""
+
+msgid "Security and Compliance"
+msgstr "Sécurité et conformité"
+
+msgid "Security capabilities"
+msgstr ""
+
+msgid "Security configuration"
+msgstr ""
+
msgid "Security dashboard"
msgstr "Tableau de bord de sécurité"
-msgid "Security navigation"
-msgstr "Navigation dans la sécurité"
-
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr "Le rapport de sécurité n'est pas à jour. Veuillez mettre à jour votre branche avec les derniers changements de la branche cible (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr "Métriques de sécurité en cours d'exécution pour les environnements d
msgid "SecurityConfiguration|SAST Analyzers"
msgstr "Analyseurs SAST"
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr "Configuration SAST"
msgid "SecurityConfiguration|Secure your project"
@@ -38151,7 +38781,7 @@ msgid "SecurityOrchestration|, and %{count} more"
msgstr ", et %{count} de plus"
msgid "SecurityOrchestration|.yaml mode"
-msgstr "mode .yaml"
+msgstr "Mode .yaml"
msgid "SecurityOrchestration|.yaml preview"
msgstr "Aperçu .yaml"
@@ -38198,6 +38828,9 @@ msgstr "Choisir un projet"
msgid "SecurityOrchestration|Choose approver type"
msgstr "Choisir le type d'approbateur"
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr "Créez des règles de vulnérabilité plus robustes et appliquez-les à tous vos projets."
@@ -38303,9 +38936,18 @@ msgstr "Aucune action définie - la politique ne sera pas exécutée."
msgid "SecurityOrchestration|No description"
msgstr "Aucune description"
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr "Aucune règle définie - la politique ne sera pas exécutée."
+msgid "SecurityOrchestration|No tags available"
+msgstr "Aucune étiquette disponible"
+
+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 "Non activée"
@@ -38396,6 +39038,9 @@ msgstr "Analyse à faire effectuer par l'agent nommé %{agents} %{cadence}"
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr "Analyse à effectuer sur chaque pipeline des %{branches}"
+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 "Approbations de sécurité"
@@ -38417,6 +39062,9 @@ msgstr "Sélectionner des groupes"
msgid "SecurityOrchestration|Select policy"
msgstr "Sélectionner la politique"
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr "Sélectionnez le type d'analyse"
@@ -38426,6 +39074,9 @@ msgstr "Sélectionner un projet de sécurité"
msgid "SecurityOrchestration|Select users"
msgstr "Sélectionnez des utilisateurs"
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr "Une erreur s’est produite, impossible de récupérer les stratégies"
@@ -38492,8 +39143,8 @@ msgstr "Dissocier un projet de sécurité supprime toutes les politiques stocké
msgid "SecurityOrchestration|Update scan policies"
msgstr "Mettre à jour les politiques d'analyse"
-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, DAST, Secret detection, Container scanning, and Dependency scanning."
-msgstr "Utilisez une stratégie d'exécution d'analyse pour créer des règles qui forcent les analyses de sécurité sur des branches particulières à un moment donné. Les types pris en charge sont SAST, DAST, Détection de Secret, analyse de Conteneur et analyse de Dépendance."
+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 "Utilisez une stratégie de résultats d'analyse pour créer des règles qui vérifient les failles de sécurité et la conformité des licences avant de fusionner une demande de fusion."
@@ -38570,6 +39221,9 @@ msgstr "%{firstProject}, %{secondProject}, et %{rest}"
msgid "SecurityReports|Activity"
msgstr "Activité"
+msgid "SecurityReports|Add comment and dismiss"
+msgstr "Ajouter le 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 "Ajouter ou supprimer des projets à surveiller 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é."
@@ -39047,6 +39701,9 @@ msgstr "Sélectionnez une étiquette"
msgid "Select labels"
msgstr "Sélectionner des étiquettes"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "Sélectionnez le moment de fusion"
@@ -39149,6 +39806,9 @@ msgstr "Le projet d'auto-surveillance a été supprimé avec succès"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "Le projet d'auto-surveillance n'a pas été supprimé. Veuillez vérifier les messages d'erreur dans les journaux"
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr "L'auto-surveillance a été rendue %{deprecation}obsolète%{link_end} dans GitLab 14.9 et %{removal}sa suppression est prévue%{link_end} dans GitLab 16.0. Pour des informations sur une solution de remplacement possible, %{opstrace}renseignez-vous sur Opstrace%{link_end}."
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr "Activer ou désactiver l'autosurveillance de l'instance."
@@ -39161,6 +39821,9 @@ msgstr "Désactiver l'autosurveillance ?"
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr "La désactivation de l’autosurveillance supprime le projet d’autosurveillance. Voulez-vous vraiment désactiver l’autosurveillance et supprimer le projet ?"
+msgid "SelfMonitoring|Deprecation notice"
+msgstr "Annonce d'obsolescense"
+
msgid "SelfMonitoring|Self-monitoring"
msgstr "Autosurveillance"
@@ -39173,6 +39836,9 @@ msgstr "Le projet d’autosurveillance a été créé avec succès."
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr "Le projet d’autosurveillance a été supprimé avec succès."
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr "L'auto-surveillance a été rendue %{deprecation}obsolète%{link_end} dans GitLab 14.9 et %{removal}sa suppression est prévue%{link_end} dans GitLab 16.0. Pour des informations sur une solution de remplacement possible, %{opstrace}renseignez-vous sur Opstrace%{link_end}."
+
msgid "Send"
msgstr "Envoyer"
@@ -39275,6 +39941,12 @@ msgstr "Comptes de service"
msgid "Service usage data"
msgstr "Données d'utilisation du service"
+msgid "ServiceAccount|User does not have permission to create a service account in this namespace."
+msgstr "L’utilisateur n’a pas la permission de créer un compte de service dans cet espace de noms."
+
+msgid "ServiceAccount|User does not have permission to create a service account."
+msgstr "L’utilisateur n’a pas la permission de créer un compte de service."
+
msgid "ServiceDesk|Enable Service Desk"
msgstr "Activer le Service d'Assistance"
@@ -39410,6 +40082,9 @@ msgstr "Définir la durée maximale de session pour un terminal Web."
msgid "Set the milestone to %{milestone_reference}."
msgstr "Définir le jalon à %{milestone_reference}."
+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 "Définissez la limite de fréquence par utilisateur pour l'obtention d'un utilisateur par son ID via l'API."
@@ -39437,8 +40112,8 @@ msgstr "Configurer l'intégration de Jira"
msgid "Set up a %{type} runner for a project"
msgstr "Mettre en place un exécuteur %{type} pour un projet"
-msgid "Set up a hardware device as a second factor to sign in."
-msgstr "Configurer un appareil matériel comme deuxième facteur pour se connecter."
+msgid "Set up a hardware device to enable two-factor authentication (2FA)."
+msgstr "Configurez un périphérique matériel pour activer l'authentification à deux facteurs (A2F)."
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "Configure les assertions, attributs et revendications (courriel, prénom et nom), ainsi que le NameID, conformément à %{docsLinkStart}la documentation %{icon}%{docsLinkEnd}"
@@ -39688,6 +40363,9 @@ msgstr "Afficher le contenu du fichier"
msgid "Show filters"
msgstr "Afficher les filtres"
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr "Afficher les jalons de groupe"
@@ -39852,9 +40530,6 @@ msgstr "Limites de taille des tâches Sidekiq"
msgid "Sign in"
msgstr "Connexion"
-msgid "Sign in / Register"
-msgstr "Connexion / Inscription"
-
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 "Connectez-vous comme utilisateur avec l'adresse de courriel correspondante, ajoutez l'adresse à ce compte ou créez-un nouveau en utilisant l'adresse correspondante."
@@ -39991,7 +40666,7 @@ msgid "Size limit per repository (MB)"
msgstr "Limite de taille par dépôt (Mo)"
msgid "Skipped"
-msgstr "Ignoré"
+msgstr "Ignorées"
msgid "Skipped deployment to"
msgstr "Déploiement ignoré sur"
@@ -40008,15 +40683,33 @@ msgstr "L’intégration de Slack permet d’interagir avec GitLab via des comma
msgid "Slack logo"
msgstr "Logo Slack"
+msgid "Slack notifications integration is deprecated"
+msgstr "L'intégration des notifications Slack est obsolète"
+
+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 "Les notifications Slack seront obsolètes"
+
+msgid "SlackIntegration|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr "Une application appelée appli GitLab pour Slack demande l’accès à votre compte GitLab. Cette application a été créée par GitLab Inc."
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr "Voulez-vous vraiment supprimer ce projet de l'appli GitLab pour Slack ?"
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr "Autoriser l'appli GitLab pour Slack (%{user}) à utiliser votre compte ?"
+
msgid "SlackIntegration|Client ID"
msgstr "ID client"
msgid "SlackIntegration|Client secret"
msgstr "Secret client"
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr "Créer et lire les commentaires et données des tickets."
+
msgid "SlackIntegration|GitLab for Slack"
msgstr "GitLab pour Slack"
@@ -40026,6 +40719,9 @@ msgstr "GitLab pour Slack a été installé avec succès."
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr "Installer l'appli GitLab pour Slack"
+msgid "SlackIntegration|Perform deployments."
+msgstr "Effectuer des déploiements."
+
msgid "SlackIntegration|Project alias"
msgstr "Alias du projet"
@@ -40035,6 +40731,9 @@ msgstr "Réinstaller l'appli GitLab pour Slack"
msgid "SlackIntegration|Remove project"
msgstr "Supprimer le projet"
+msgid "SlackIntegration|Run ChatOps jobs."
+msgstr "Exécuter des tâches ChatOps."
+
msgid "SlackIntegration|See the list of available commands in Slack after setting up this integration by entering"
msgstr "Affichez la liste des commandes disponibles dans Slack après avoir configuré cette intégration en tapant"
@@ -40068,9 +40767,15 @@ msgstr "Jeton de vérification"
msgid "SlackIntegration|You can now close this window and go to your Slack workspace."
msgstr "Vous pouvez à présent fermer cette fenêtre et rejoindre votre espace de travail Slack."
+msgid "SlackIntegration|You don't have to reauthorize this application if the permission scope changes in future releases."
+msgstr "Vous n'avez pas à réautoriser cette application si la portée des permissions change dans les versions futures."
+
msgid "SlackIntegration|You may need to reinstall the GitLab for Slack app when we %{linkStart}make updates or change permissions%{linkEnd}."
msgstr "Vous aurez peut-être besoin de réinstaller l'appli GitLab pour Slack lorsque nous %{linkStart}effectuerons des mises à jour ou modifierons les permissions%{linkEnd}."
+msgid "SlackIntegration|cannot have more than %{limit} channels"
+msgstr "ne peut pas avoir plus de %{limit} canaux"
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr "Voulez-vous vraiment modifier le projet ?"
@@ -40246,7 +40951,7 @@ msgid "Something went wrong on our end. Please try again."
msgstr "Une erreur s'est produite de notre côté. Veuillez réessayer."
msgid "Something went wrong trying to change the locked state of this %{issuableDisplayName}"
-msgstr "Une erreur est survenue lors de la tentative de modification de l’état de verrouillage de ce·t·te %{issuableDisplayName}"
+msgstr "Une erreur s'est produite lors de la tentative de modification de l’état de verrouillage de ce(tte) %{issuableDisplayName}"
msgid "Something went wrong trying to load issue contacts."
msgstr "Une erreur s'est produite lors de la tentative de chargement des contacts du ticket."
@@ -40254,12 +40959,18 @@ msgstr "Une erreur s'est produite lors de la tentative de chargement des contact
msgid "Something went wrong when deleting a comment. Please try again"
msgstr "Une erreur s'est produite lors de la suppression d'un commentaire. Veuillez réessayer"
+msgid "Something went wrong when deleting a comment. Please try again."
+msgstr "Une erreur s'est produite lors de la suppression d'un commentaire. Veuillez réessayer."
+
msgid "Something went wrong when reordering designs. Please try again"
msgstr "Une erreur s'est produite lors de la réorganisation des esquisses. Veuillez réessayer"
msgid "Something went wrong when sending the incident link to Slack."
msgstr "Une erreur s'est produite lors de l'envoi du lien d'incident vers Slack."
+msgid "Something went wrong when updating a comment. Please try again"
+msgstr "Une erreur s'est produite lors de la mise à jour d'un commentaire. Veuillez réessayer"
+
msgid "Something went wrong while adding timeline event."
msgstr "Une erreur s'est produite lors de l'ajout d'un événement de chronologie."
@@ -40671,9 +41382,6 @@ msgstr "Conflit de nom pour la méthode « %{prop}() »."
msgid "SourceEditor|No extension for unuse has been specified."
msgstr "Aucune extension pour inutilisation n'a été spécifiée."
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr "Une instance de l'Éditeur de Source est requise pour mettre en place une extension."
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr "La propriété `definition` est attendue sur l'extension."
@@ -40737,6 +41445,9 @@ msgstr "Protection antiâ€pourriel et antiâ€robot"
msgid "Spam log successfully submitted as ham."
msgstr "Le journal d'indésirables a été soumis avec succès comme acceptable."
+msgid "Specific branches"
+msgstr "Branches spécifiques"
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr "L'URL spécifiée ne peut pas être utilisée : \"%{reason}\""
@@ -40804,7 +41515,7 @@ msgid "StarredProjectsEmptyState|You don't have starred projects yet."
msgstr "Vous n'avez pas encore de projets favoris."
msgid "Starrers"
-msgstr ""
+msgstr "Supporteurs"
msgid "Stars"
msgstr "Étoiles"
@@ -40986,6 +41697,9 @@ msgstr "Supprimer la vérification de l'état ?"
msgid "StatusCheck|Service name"
msgstr "Nom du service"
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr "Vérifications d'état"
@@ -41044,7 +41758,7 @@ msgid "StatusPage|To publish incidents to an external status page, GitLab stores
msgstr "Pour publier des incidents sur une page d'état externe, GitLab enregistre un fichier JSON sur votre compte Amazon S3 dans un emplacement accessible à votre service de page d'état externe. Assurez-vous également de configurer %{docsLink}"
msgid "StatusPage|configuration documentation"
-msgstr "documentation de configuration"
+msgstr "Documentation sur la configuration"
msgid "StatusPage|your status page frontend."
msgstr "votre page frontale d'état."
@@ -41631,17 +42345,23 @@ msgstr "Prêt à commencer ? Un forfait GitLab est parfait pour des entreprises
msgid "SuperSonics|Start free trial"
msgstr "Commencer un essai gratuit"
+msgid "SuperSonics|Subscription detail synchronization has started and will complete soon."
+msgstr ""
+
msgid "SuperSonics|Subscription details"
msgstr "Détails de l'abonnement"
+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 "Abonnement non disponible"
msgid "SuperSonics|Sync subscription details"
msgstr "Synchroniser les détails de l'abonnement"
-msgid "SuperSonics|Sync subscription request."
-msgstr "Demande de synchro d'abonnement."
+msgid "SuperSonics|Synchronization started"
+msgstr "Synchronisation démarrée"
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 "Le code d'activation n'est pas valide. Veuillez vous assurer de l'avoir copié de manière exacte depuis le Portail Clients ou depuis le courriel de confirmation. En savoir plus sur l'%{linkStart}activation de votre abonnement%{linkEnd}."
@@ -41649,8 +42369,8 @@ msgstr "Le code d'activation n'est pas valide. Veuillez vous assurer de l'avoir
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr "Le code d'activation doit être une chaîne alphanumérique de 24 caractères"
-msgid "SuperSonics|There is a connectivity issue."
-msgstr "Il y a un problème de connectivité."
+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 "Il s'agit du pic d'utilisateurs le plus élevé de votre installation depuis que la licence a démarré."
@@ -41678,9 +42398,6 @@ msgstr "Les utilisateurs ayant un rôle d'Invité et ceux qui ne font pas partie
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 "Vous pouvez %{purchaseSubscriptionLinkStart}souscrire un nouvel abonnement%{purchaseSubscriptionLinkEnd} et réessayer. Si vous avez besoin d’une assistance supplémentaire, %{supportLinkStart}contactez le Support GitLab%{supportLinkEnd}."
-msgid "SuperSonics|You can no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr "Vous ne pouvez plus synchroniser les détails de votre abonnement avec GitLab. Obtenez de l'aide sur les problèmes de connectivité les plus courants avec le %{connectivityHelpLinkStart}dépannage du code d'activation%{connectivityHelpLinkEnd}."
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr "Vous pouvez commencer un essai gratuit de GitLab Ultimate sans aucune obligation ou détails de paiement."
@@ -41723,9 +42440,6 @@ msgstr "Votre abonnement"
msgid "SuperSonics|Your subscription cannot be located"
msgstr "Votre abonnement est introuvable"
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr "Les détails de votre abonnement seront synchronisés sous peu."
-
msgid "SuperSonics|Your subscription is expired"
msgstr "Votre abonnement a expiré"
@@ -41876,9 +42590,27 @@ msgstr "Liste des étiquettes :"
msgid "Tag name"
msgstr "Nom de l'étiquette"
+msgid "Tag name cannot be one of the following: %{names}"
+msgstr "Le nom de l'étiquette ne peut pas être l'un des suivants : %{names}"
+
msgid "Tag name is required."
msgstr "Le nom de l'étiquette est requis."
+msgid "Tag name should not be empty"
+msgstr "Le nom de l'étiquette ne doit pas être vide"
+
+msgid "Tag name should not contain any control characters"
+msgstr "Le nom de l'étiquette ne doit contenir aucun caractère de contrôle"
+
+msgid "Tag name should not contain any of the following: %{substrings}"
+msgstr "Le nom de l'étiquette ne doit contenir aucun des éléments suivants : %{substrings}"
+
+msgid "Tag name should not end with %{postfixes}"
+msgstr ""
+
+msgid "Tag name should not start with %{prefixes}"
+msgstr ""
+
msgid "Tag push"
msgstr "Poussée d'étiquette"
@@ -42015,7 +42747,7 @@ msgid "TagsPage|You're about to permanently delete the tag %{strongStart}%{tagNa
msgstr "Vous êtes sur le point de supprimer définitivement l'étiquette %{strongStart}%{tagName}.%{strongEnd}"
msgid "TagsPage|protected"
-msgstr "protégé"
+msgstr "protégée"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr "Jetez un œil à la documentation pour découvrir toutes les fonctionnalités de GitLab."
@@ -42285,12 +43017,12 @@ msgstr "Votre projet n'a aucun fichier d'état Terraform"
msgid "Test"
msgstr "Test"
-msgid "Test Cases"
-msgstr "Cas de test"
-
msgid "Test case"
msgstr "Scénario de test"
+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] "La valeur de la couverture de test de ce pipeline a été calculée à partir de celle de %d tâche."
@@ -42310,9 +43042,6 @@ msgstr "Déplacer le cas de test"
msgid "TestCases|Moving test case"
msgstr "Déplacement du cas de test"
-msgid "TestCases|New Test Case"
-msgstr "Nouveau Cas de Test"
-
msgid "TestCases|New test case"
msgstr "Nouveau cas de test"
@@ -42439,6 +43168,9 @@ msgstr "Texte (facultatif)"
msgid "Text added to the body of all email messages. %{character_limit} character limit"
msgstr "Texte ajouté au corps de tous les courriels. Limite de %{character_limit} caractères"
+msgid "Text added to the body of user deactivation email messages. 1000 character limit."
+msgstr "Texte ajouté au corps du message des courriels de désactivation d'utilisateurs. Limité à 1000 caractères."
+
msgid "Text style"
msgstr "Style de texte"
@@ -42498,6 +43230,9 @@ msgstr "Le système de suivi est un endroit où l’on peut ouvrir un ticket pou
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr "Le serveur Prometheus a répondu par « mauvaise requête ». Veuillez vérifier que vos requêtes sont correctes et prises en charge par votre version de Prometheus. %{documentationLink}"
+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 "L'intégration des notifications Slack est obsolète et sera supprimée dans une prochaine version. Pour continuer à recevoir des notifications de Slack, utilisez l'application GitLab pour Slack à la place. %{learn_more_link_start}En savoir plus%{link_end}."
+
msgid "The Snowplow cookie domain."
msgstr "Le domaine des cookies de Snowplow."
@@ -42540,9 +43275,6 @@ msgstr "La vue comparative peut être inexacte en raison de conflits de fusion."
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 "La plateforme DevOps complète. Une application unique avec des possibilités infinies. Les entreprises s'appuient sur la gestion du code source, la CI/CD, la sécurité et d'autres fonctionnalités de GitLab pour livrer des logiciels rapidement."
-msgid "The compliance report shows the merge request violations merged in protected environments."
-msgstr "Le rapport de conformité montre les violations des demandes de fusion fusionnées dans les environnements protégés."
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "La connexion expirera après %{timeout}. Pour les dépôts qui nécessitent plus de temps, utilisez une combinaison de clone et push."
@@ -42600,6 +43332,9 @@ msgstr "La liste des dépendances détaille les informations sur les composants
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "Le déploiement de cette tâche sur %{environmentLink} a échoué."
+msgid "The diagrams.net editor could not be loaded."
+msgstr "L'éditeur diagrams.net n'a pas pu être chargé."
+
msgid "The directory has been successfully created."
msgstr "Le répertoire a été créé avec succès."
@@ -42913,8 +43648,17 @@ msgstr "La ressource à laquelle vous essayez d'accéder n'existe pas ou vous n'
msgid "The scan has been created."
msgstr "L'analyse a été créée."
-msgid "The secret is only available when you first create the application."
-msgstr "Le secret n'est disponible qu'au moment où vous créez l'application."
+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 "L'image sélectionnée n'est pas un diagramme SVG valide"
+
+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 "L'extrait de code peut être consulté sans aucune authentification."
@@ -43258,6 +44002,9 @@ msgstr "Une erreur s'est produite lors de la récupération de la tâche."
msgid "There was an error fetching the jobs for your project."
msgstr "Une erreur s'est produite lors de la récupération des tâches de votre projet."
+msgid "There was an error fetching the number of jobs for your project."
+msgstr "Une erreur s'est produite lors de la récupération du nombre de tâches de votre projet."
+
msgid "There was an error fetching the top labels for the selected group"
msgstr "Une erreur s'est produite lors de la récupération des étiquettes les mieux classées pour le groupe sélectionné"
@@ -43373,7 +44120,7 @@ msgid "Third Party Advisory Link"
msgstr "Liens des Annonces d'Offres Tierces"
msgid "This %{issuableDisplayName} is locked. Only project members can comment."
-msgstr "Ce %{issuableDisplayName} est verrouillé. Seuls les membres du projet peuvent commenter."
+msgstr "Ce(tte) %{issuableDisplayName} est verrouillé(e). Seuls les membres du projet peuvent commenter."
msgid "This %{issuable} is hidden because its author has been banned"
msgstr "Ce(tte) %{issuable} est caché(e) car son auteur a été banni"
@@ -43447,14 +44194,8 @@ msgstr "Cette archive a été demandée trop souvent. Réessayez plus tard."
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 "Cette pièce-jointe a été tronquée pour éviter de dépasser la taille maximale autorisée de %{size_limit}. %{written_count} des %{count} %{issuables} ont été inclus. Envisagez de réexporter avec une sélection plus restreinte de %{issuables}."
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr "Cette pièce-jointe a été tronquée pour éviter de dépasser la taille maximale autorisée de %{size_limit}. %{written_count} des %{issues_count} tickets ont été inclus. Envisagez de réexporter avec une sélection plus restreinte de tickets."
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr "Cette pièce-jointe a été tronquée pour éviter de dépasser la taille maximale autorisée de %{size_limit}. %{written_count} des %{merge_requests_count} demandes de fusion ont été incluses. Envisagez de réexporter avec une sélection plus restreinte de demandes de fusion."
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
-msgstr "Cette pièce-jointe a été tronquée pour éviter de dépasser la taille maximale autorisée de %{size_limit}. %{written_count} des %{requirements_count} exigences ont été incluses. Envisagez de réexporter avec une sélection plus restreinte d'exigences."
+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 "Ce bloc est autoréférentiel"
@@ -43954,6 +44695,9 @@ msgstr "Ce dépôt a été vérifié pour la dernière fois %{last_check_timesta
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr "Ce dépôt a été vérifié pour la dernière fois %{last_check_timestamp}. La vérification est passée."
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "Cet exécuteur ne fonctionnera que sur les pipelines déclenchés sur des branches protégées"
@@ -44008,11 +44752,8 @@ msgstr "Cette variable ne peut pas être masquée."
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 will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr "Cela va invalider vos applications enregistrées et vos appareils U2F/WebAuthn."
-
-msgid "This will invalidate your registered applications and U2F devices."
-msgstr "Cela va invalider vos applications enregistrées et vos appareils U2F."
+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 "Cela supprimera la relation de fork entre ce projet et %{fork_source}."
@@ -44462,6 +45203,9 @@ msgstr "Pour commencer, entrez l’URL de votre hôte Gitea et un %{link_to_pers
msgid "To get started, use the link below to confirm your account."
msgstr "Pour commencer, utilisez le lien ci-dessous pour confirmer votre compte."
+msgid "To go to GitLab Pages, on the left sidebar, select %{pages_link}."
+msgstr "Pour aller sur GitLab Pages, à partir de la barre latérale de gauche, sélectionnez %{pages_link}."
+
msgid "To help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr "Pour contribuer à améliorer GitLab, nous souhaiterions périodiquement %{docs_link}. Cela peut être modifié à tout moment dans %{settings_link}."
@@ -44949,6 +45693,9 @@ msgstr "Le groupe est déjà un groupe racine."
msgid "TransferGroup|Group is already associated to the parent group."
msgstr "Le groupe est déjà associé au groupe parent."
+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 "Le groupe parent possède déjà un sous-groupe ou un projet avec le même chemin."
@@ -45038,9 +45785,6 @@ msgstr "Déclencher une réindexation de la grappe de serveurs. N'utilisez cela
msgid "Trigger job"
msgstr "Tâche de déclenchement"
-msgid "Trigger manual job"
-msgstr "Déclencher une tâche manuelle"
-
msgid "Trigger pipelines for mirror updates"
msgstr "Déclencher des pipelines pour les mises à jour de miroirs"
@@ -45143,9 +45887,6 @@ msgstr "Twitter :"
msgid "Two-Factor Authentication"
msgstr "Authentification à Deux Facteurs"
-msgid "Two-Factor Authentication code"
-msgstr "Code d'authentification à deux facteurs"
-
msgid "Two-factor Authentication"
msgstr "Authentification à Deux Facteurs"
@@ -45191,12 +45932,6 @@ msgstr "Type"
msgid "Type to search"
msgstr "Tapez pour rechercher"
-msgid "U2F Devices (%{length})"
-msgstr "Appareils U2F (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "U2F ne fonctionne qu'avec les sites Web ayant activé HTTPS. Contactez votre administrateur pour plus de détails."
-
msgid "URL"
msgstr "URL"
@@ -45302,6 +46037,9 @@ msgstr "Impossible de récupérer les pipelines en amont ni ceux en aval."
msgid "Unable to find Jira project to import data from."
msgstr "Impossible de trouver le projet Jira à partir duquel importer les données."
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr "Impossible de charger entièrement le message de commit par défaut. Vous pouvez néanmoins appliquer cette suggestion et le message de commit sera corrigé."
@@ -45401,6 +46139,9 @@ msgstr "Non disponible"
msgid "Unban"
msgstr "Gracier"
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr "Les modifications non validées seront perdues si vous changez de branche. Voulez-vous continuer ?"
@@ -45458,6 +46199,15 @@ msgstr "Sauf accord contraire écrit avec GitLab, en cliquant sur « Téléverse
msgid "Unlimited"
msgstr "Illimité"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr "Dissocier"
@@ -45545,6 +46295,9 @@ msgstr "Valeur de tri non prise en charge."
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr "Type de pense-bête non pris en charge. Les types de pense-bêtes pris en charge sont : %{todo_types}"
+msgid "Untitled"
+msgstr "Sans titre"
+
msgid "Unused"
msgstr "Inutilisé"
@@ -45614,6 +46367,9 @@ msgstr "Mettez à jour vos marque-pages car les URLs des branches filtrées/triÃ
msgid "Update your group name, description, avatar, and visibility."
msgstr "Modifiez le nom du groupe, sa description, son avatar et sa visibilité."
+msgid "Update your project name and description."
+msgstr ""
+
msgid "Update your project name, topics, description, and avatar."
msgstr "Mettre à jour le nom, les sujets, la description et l'avatar de votre projet."
@@ -45740,6 +46496,9 @@ msgstr "Tendances d'Utilisation"
msgid "Usage statistics"
msgstr "Statistiques d’utilisation"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr "Les statistiques de stockage au niveau du projet pour le Registre de Conteneur sont uniquement à titre indicatif et n'incluent pas les économies réalisées par la déduplication à l'échelle de l'instance."
@@ -45911,6 +46670,9 @@ msgstr "Aucun projet de cet espace de noms n'a utilisé d'exécuteurs partagés
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr "Ce tableau omet les projets qui ont utilisé 0 minute CI/CD ou 0 durée des exécuteurs partagés"
+msgid "UsageQuota|Transfer"
+msgstr "Transferts"
+
msgid "UsageQuota|Uploads"
msgstr "Téléversements"
@@ -46115,6 +46877,9 @@ msgstr "Utiliser l'option %{strongStart}Test%{strongEnd} ci-dessus pour créer u
msgid "Use the Apple App Store Connect integration to easily connect to the Apple App Store with Fastlane in CI/CD pipelines."
msgstr "Utilisez l'intégration de Apple App Store Connect pour vous connecter facilement à l'App Store d'Apple avec Fastlane dans des pipelines CI/CD."
+msgid "Use the Google Play integration to connect to Google Play with fastlane in CI/CD pipelines."
+msgstr "Utilisez l'intégration de Google Play pour vous y connecter avec Fastlane dans des pipelines CI/CD."
+
msgid "Use the link below to confirm your email address (%{email})"
msgstr "Utilisez le lien ci-dessous pour confirmer votre adresse de courriel (%{email})"
@@ -46127,6 +46892,9 @@ msgstr "Utilisez l'URL de l'instance Cloud publique (%{kroki_public_url}) ou %{i
msgid "Use the search bar on the top of this page"
msgstr "Utilisez la barre de recherche en haut de cette page"
+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 "Utiliser ce jeton pour valider les charges utiles reçues."
@@ -46201,6 +46969,9 @@ msgstr "Utilisateur créé le"
msgid "User does not have a pending request"
msgstr "L'utilisateur n'a pas de requête en attente"
+msgid "User does not have permission to create a Security Policy project."
+msgstr ""
+
msgid "User identity was successfully created."
msgstr "L'identité de l'utilisateur a été créée avec succès."
@@ -46627,6 +47398,9 @@ msgstr "L'analyse des chaînes de valeur peut vous aider à déterminer la vélo
msgid "Value Streams Dashboard (Beta)"
msgstr "Tableau de bord de la chaîne de valeur (bêta)"
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr "La valeur peut contenir une référence de variable"
@@ -46738,6 +47512,9 @@ msgstr "Voir les détails"
msgid "ValueStreamEvent|Items in stage"
msgstr "Éléments dans l'étape"
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr "Seulement les éléments qui ont atteint leur événement d'arrêt."
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr "Durée de l'étape (médiane)"
@@ -46882,6 +47659,9 @@ msgstr "Affichez et modifiez le markdown, avec la possibilité de prévisualiser
msgid "View blame"
msgstr "Voir les annotations"
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr "Voir les annotations antérieures à cette modification"
@@ -46911,9 +47691,6 @@ msgstr "Voir la documentation"
msgid "View eligible approvers"
msgstr "Voir les approbateurs éligibles"
-msgid "View entire blame"
-msgstr "Voir toutes les annotations"
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "Voir l'artéfact exposé"
@@ -47116,6 +47893,69 @@ msgstr "%{formattedStartDate} à aujourd'hui"
msgid "VulnerabilityChart|Severity"
msgstr "Gravité"
+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 "Activité"
+
+msgid "VulnerabilityExport|Additional Info"
+msgstr "Infos supplémentaires"
+
+msgid "VulnerabilityExport|CVE"
+msgstr "CVE"
+
+msgid "VulnerabilityExport|CWE"
+msgstr "CWE"
+
+msgid "VulnerabilityExport|Comments"
+msgstr "Commentaires"
+
+msgid "VulnerabilityExport|Details"
+msgstr "Détails"
+
+msgid "VulnerabilityExport|Detected At"
+msgstr ""
+
+msgid "VulnerabilityExport|Group Name"
+msgstr "Nom du groupe"
+
+msgid "VulnerabilityExport|Location"
+msgstr ""
+
+msgid "VulnerabilityExport|Other Identifiers"
+msgstr "Autres identifiants"
+
+msgid "VulnerabilityExport|Project Name"
+msgstr "Nom du projet"
+
+msgid "VulnerabilityExport|Scanner Name"
+msgstr ""
+
+msgid "VulnerabilityExport|Severity"
+msgstr "Gravité"
+
+msgid "VulnerabilityExport|Status"
+msgstr "État"
+
+msgid "VulnerabilityExport|Tool"
+msgstr "Outil"
+
+msgid "VulnerabilityExport|Vulnerability"
+msgstr "Vulnérabilité"
+
msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr "%{statusStart}Confirmée%{statusEnd} %{timeago} par %{user}"
@@ -47506,12 +48346,6 @@ msgstr "Nous n'avons pas trouvé de %{scope} correspondant à %{term} dans le pr
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "Nous n'avons pas pu atteindre le serveur Prometheus. Soit le serveur n'existe plus, soit les détails de la configuration doivent être mis à jour."
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr "Nous avons détecté une tentative de connexion à votre compte %{host} à l'aide d'un code d'authentification à deux facteurs erroné"
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr "Nous avons détecté une tentative de connexion à votre compte %{host} à l'aide d'un code d'authentification à deux facteurs erroné, à partir de l'adresse IP suivante : %{ip}, à %{time}"
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "Nous avons détecté un potentiel indésirable dans %{humanized_resource_name}. Veuillez résoudre le reCAPTCHA pour continuer."
@@ -47563,9 +48397,6 @@ msgstr "Nous informerons %{inviter} que vous avez refusé leur invitation à rej
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 "Nous tenons à vous informer que votre abonnement GitLab Édition Entreprise %{plan_name} approche de la limite de son nombre d'utilisateurs. Vous avez %{active_user_count} utilisateurs actifs, ce qui est presque la limite qui est de %{maximum_user_count}."
-msgid "We'll continuously validate your pipeline configuration. The validation results will appear here."
-msgstr "Nous validerons votre configuration de pipeline en continu. Les résultats de validation apparaîtront ici."
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "Cela contribuera à nous permettre de vous présenter des fonctionnalités et informations personnalisées."
@@ -47707,6 +48538,9 @@ msgstr "Une version est créée ou mise à jour."
msgid "Webhooks|A subgroup is created or removed."
msgstr "Un sous-groupe est créé ou supprimé."
+msgid "Webhooks|A webhook in this group was automatically disabled after being retried multiple times."
+msgstr "Un crochet web de ce groupe a été désactivé automatiquement après avoir été retenté plusieurs fois."
+
msgid "Webhooks|A webhook in this project was automatically disabled after being retried multiple times."
msgstr "Un crochet web de ce projet a été désactivé automatiquement après avoir été retenté plusieurs fois."
@@ -47970,6 +48804,11 @@ msgstr "Lors de l'utilisation des protocoles %{code_open}http://%{code_close} ou
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 "Lorsque vous transférez votre projet vers un groupe, vous pouvez facilement gérer plusieurs projets, voir les quotas d'utilisation pour le stockage, les minutes de pipelines, les utilisateurs, et commencer un essai ou la mise à niveau vers une offre payante."
+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] "À la fin de votre période d'essai, vous basculerez sur l'édition Gratuite qui est limitée à %{free_user_limit} siège. %{free_user_limit} siège restera actif, et les membres qui n'occupent pas de siège passeront à l'%{link_start}état Hors limite%{link_end} et perdront l'accès à ce groupe."
@@ -48008,6 +48847,9 @@ msgstr "Qui utilisera ce groupe ?"
msgid "Why are you signing up? (optional)"
msgstr "Pourquoi vous inscrivez-vous ? (facultatif)"
+msgid "Why is this rule invalid?"
+msgstr "Pourquoi cette règle est-elle invalide ?"
+
msgid "Wiki"
msgstr "Wiki"
@@ -48227,8 +49069,8 @@ msgstr "Ne sera pas corrigé / Accepter le risque"
msgid "Work in progress (open and unassigned)"
msgstr "Travaux en cours (ouverts et non assignés)"
-msgid "Work in progress Limit"
-msgstr "Limite des travaux en cours"
+msgid "Work in progress limit"
+msgstr ""
msgid "WorkItem|%{count} more assignees"
msgstr "%{count} autres personnes assignées"
@@ -48275,6 +49117,9 @@ msgstr "Ajouter à l'itération"
msgid "WorkItem|Add to milestone"
msgstr "Ajouter au jalon"
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "Voulez-vous vraiment annuler la modification ?"
@@ -48298,6 +49143,15 @@ msgstr "Enfant supprimé"
msgid "WorkItem|Closed"
msgstr "Fermé"
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr "Convertir en tâche"
+
+msgid "WorkItem|Converted to task"
+msgstr "Converti en tâche"
+
msgid "WorkItem|Create %{workItemType}"
msgstr "Créer %{workItemType}"
@@ -48322,9 +49176,15 @@ msgstr "Date d'échéance"
msgid "WorkItem|Existing task"
msgstr "Tâche existante"
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr "État de santé"
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr "Incident"
@@ -48445,6 +49305,9 @@ msgstr "Actions des tâches"
msgid "WorkItem|Task deleted"
msgstr "Tâche supprimée"
+msgid "WorkItem|Task reverted"
+msgstr "Tâche enlevée"
+
msgid "WorkItem|Tasks"
msgstr "Tâches"
@@ -48481,6 +49344,9 @@ msgstr "Élément de travail"
msgid "WorkItem|Work item not found"
msgstr "Élément de travail introuvable"
+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 "Would you like to create a new branch?"
msgstr "Voulez-vous créer une nouvelle branche ?"
@@ -48511,6 +49377,9 @@ msgstr "Rédigez une note interne ou faites glisser vos fichiers ici…"
msgid "Write milestone description..."
msgstr "Ecrire une description du jalon ..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "Rédigez vos notes de version ou faites glisser vos fichiers ici…"
@@ -48694,7 +49563,7 @@ msgid "You can also press ⌘-Enter"
msgstr "Vous pouvez aussi appuyer sur ⌘-Entrée"
msgid "You can also star a label to make it a priority label."
-msgstr "Vous pouvez marquer un label comme important pour en faire un label prioritaire."
+msgstr "Vous pouvez marquer une étiquette avec une étoile pour la rendre prioritaire."
msgid "You can also upload existing files from your computer using the instructions below."
msgstr "Vous pouvez également téléverser des fichiers existants depuis votre ordinateur en suivant les instructions ci-dessous."
@@ -48912,9 +49781,6 @@ msgstr "Vous n'avez pas la permission pour mettre à jour l'environnement."
msgid "You do not have permissions to run the import."
msgstr "Vous n'avez pas la permission de lancer l'importation."
-msgid "You don't have any U2F devices registered yet."
-msgstr "Vous n'avez pas encore d'appareil U2F enregistré."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr "Vous n'avez pas encore d'appareil WebAuthn enregistré."
@@ -49085,12 +49951,18 @@ msgstr "Seul un responsable peut forcer la suppression d’un verrou"
msgid "You must provide a valid current password"
msgstr "Vous devez fournir le mot de passe actuel correct"
+msgid "You must provide a valid current password."
+msgstr "Vous devez fournir le mot de passe actuel correct."
+
msgid "You must provide at least one filter argument for this query"
msgstr "Vous devez fournir au moins un argument de filtre pour cette requête"
msgid "You must provide your current password in order to change it."
msgstr "Vous devez fournir votre mot de passe actuel pour le changer."
+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 "Vous devez vous connecter pour rechercher des projets spécifiques."
@@ -49261,6 +50133,9 @@ msgstr "Votre %{spammable_entity_type} a été reconnu comme du pourriel. Veuill
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
msgstr "Votre abonnement %{strong}%{plan_name}%{strong_close} pour %{strong}%{namespace_name}%{strong_close} expirera le %{strong}%{expires_on}%{strong_close}."
+msgid "Your Activity"
+msgstr "Votre activité"
+
msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details."
msgstr "La syntaxe de votre configuration CI/CD n'est pas valide. Sélectionnez l'onglet Valider pour plus de détails."
@@ -49270,8 +50145,8 @@ msgstr "Votre exportation CSV a commencé. Elle sera envoyée à %{email} une fo
msgid "Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment."
msgstr "Votre export CSV de %{count} depuis le projet %{project_link} a été ajouté à ce courriel en pièce-jointe."
-msgid "Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
-msgstr "Votre export CSV de %{written_count} du projet %{project_name} (%{project_url}) a été ajouté en pièce-jointe à ce courriel."
+msgid "Your CSV export of %{exported_objects} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+msgstr "Votre export CSV de %{exported_objects} du projet %{project_name} (%{project_url}) a été ajouté en pièce-jointe à ce courriel."
msgid "Your CSV import for project"
msgstr "Votre importation CSV pour le projet"
@@ -49300,6 +50175,9 @@ msgstr "Votre groupe GitLab"
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 "Votre instance GitLab permet à tout le monde de se créer un compte, ce qui représente un risque de sécurité pour les instances GitLab exposées publiquement. Vous devriez désactiver les nouvelles inscriptions si les utilisateurs publics ne sont pas censés s'enregistrer."
+msgid "Your GitLab version"
+msgstr "Votre version de GitLab"
+
msgid "Your Groups"
msgstr "Vos groupes"
@@ -49310,7 +50188,7 @@ msgid "Your Projects (default)"
msgstr "Vos projets (défaut)"
msgid "Your Projects' Activity"
-msgstr "Activité de vos projets favoris"
+msgstr "Activité de vos projets"
msgid "Your SSH key has expired"
msgstr "Votre clé SSH a expiré"
@@ -49324,6 +50202,9 @@ msgstr "Votre clé SSH a été supprimée"
msgid "Your SSH keys (%{count})"
msgstr "Vos clés SSH (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr "Votre appareil OTP basé sur le temps a été enregistré !"
+
msgid "Your To-Do List"
msgstr "Vos pense-bêtes"
@@ -49369,6 +50250,9 @@ msgstr "Votre action a été rejetée car la limite de stockage de l'espace de n
msgid "Your action succeeded."
msgstr "Votre action a réussi."
+msgid "Your activity"
+msgstr "Votre activité"
+
msgid "Your applications (%{size})"
msgstr "Vos applications (%{size})"
@@ -49378,9 +50262,6 @@ 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 U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "Votre navigateur ne prend pas en charge U2F. Veuillez utiliser Google Chrome pour ordinateur (version 41 ou plus récente)."
-
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 supporté, p. ex. Chrome (67+) ou Firefox (60+)."
@@ -49411,6 +50292,9 @@ msgstr "Votre commentaire sera abandonné."
msgid "Your commit email is used for web based operations, such as edits and merges."
msgstr "Votre adresse de courriel de commit est utilisée pour les opérations Web basiques, telles que les modifications et les fusions."
+msgid "Your current password is required to register a new device."
+msgstr "Votre mot de passe actuel est nécessaire pour l'enregistrement d'un nouvel appareil."
+
msgid "Your current password is required to register a two-factor authenticator app."
msgstr "Votre mot de passe actuel est requis pour enregistrer une application d'authentification à deux facteurs."
@@ -49568,6 +50452,9 @@ msgstr "Votre groupe de premier niveau %{namespace_name} dépasse la limite de %
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr "Votre groupe de premier niveau %{namespace_name} dépasse la limite de %{free_user_limit} utilisateur(s)"
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr "Votre groupe de premier niveau dépasse les limites d'utilisateurs et de stockage et a été placé en lecture seule."
@@ -49805,6 +50692,9 @@ msgstr "ne peut être modifié que par un administrateur de groupe."
msgid "can only have one escalation policy"
msgstr "ne peut avoir qu'une seule politique d'escalade"
+msgid "can't be blank"
+msgstr ""
+
msgid "can't be enabled when delayed group deletion is disabled"
msgstr "ne peut pas être activé quand la suppression de groupe différée est désactivée"
@@ -50135,9 +51025,6 @@ msgstr "Rapport complet"
msgid "ciReport|Generic Report"
msgstr "Rapport Générique"
-msgid "ciReport|IaC Scanning"
-msgstr "Analyse IaC"
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "Enquêter sur cette vulnérabilité en créant un ticket"
@@ -50203,6 +51090,9 @@ msgstr "Résoudre avec une demande de fusion"
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "Détection de secret"
@@ -50233,6 +51123,9 @@ msgstr "Affichage de %{fetchedItems} éléments sur %{totalItems}"
msgid "ciReport|Solution"
msgstr "Solution"
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr "Une erreur s’est produite lors de la récupération de la découverte. Veuillez réessayer plus tard."
+
msgid "ciReport|Static Application Security Testing (SAST)"
msgstr "Test statique de la sécurité des applications (SAST)"
@@ -50510,9 +51403,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 "following"
-msgstr "suivi(s)"
-
msgid "for"
msgstr "pendant"
@@ -50818,11 +51708,17 @@ msgstr "verrouillé par %{path_lock_user_name} %{created_at}"
msgid "manual"
msgstr "manuel"
-msgid "math|Displaying this math block may cause performance issues on this page"
-msgstr "L'affichage de cet élément mathématique peut entraîner des problèmes de performances sur cette page"
+msgid "math|Displaying this math block may cause performance issues on this page."
+msgstr "L'affichage de cet bloc mathématique peut entraîner des problèmes de performances sur cette page."
+
+msgid "math|There was an error rendering this math block. %{katexMessage}"
+msgstr "Une erreur s'est produite lors de l'affichage de ce bloc mathématique. %{katexMessage}"
+
+msgid "math|This math block exceeds %{maxMathChars} characters, and may cause performance issues on this page."
+msgstr "Ce bloc mathématique dépasse %{maxMathChars} caractères et peut entraîner des problèmes de performances sur cette page."
-msgid "math|There was an error rendering this math block"
-msgstr "Une erreur s'est produite lors de l'affichage de ce bloc mathématique"
+msgid "math|Too many expansions. Consider using multiple math blocks."
+msgstr "Trop de développements. Envisagez l'utilisation de plusieurs blocs mathématiques."
msgid "member"
msgid_plural "members"
@@ -50879,6 +51775,84 @@ msgstr "Utilisez les demandes de fusion pour proposer des modifications à votre
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr "%{boldHeaderStart}Il semble ne pas y avoir de pipeline ici.%{boldHeaderEnd}"
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Select %{boldStart}Mark as ready%{boldEnd} to remove it from Draft status."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} Sélectionnez %{boldStart}Marquer comme prêt%{boldEnd} pour lui supprimer l'état de brouillon."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Users who can write to the source or target branches can resolve the conflicts."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} Les utilisateurs qui peuvent écrire dans les branches source ou cible peuvent résoudre les conflits."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} a Jira issue key must be mentioned in the title or description."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} une clé de ticket Jira doit être mentionnée dans le titre ou dans la description."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all required approvals must be given."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} toutes les approbations requises doivent être données."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all status checks must pass."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} toutes les vérifications d'état doivent passer."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all threads must be resolved."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} tous les fils de conversation doivent être résolus."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} denied licenses must be removed."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} les licences refusées doivent être supprimées."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} fast-forward merge is not possible. To merge this request, first rebase locally."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} la fusion en avance rapide n’est pas possible. Pour fusionner cette demande, rebasez localement au préalable."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} merge conflicts must be resolved."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} les conflits de fusion doivent être résolus."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} new changes were just added."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} de nouvelles modifications viennent juste d'être apportées."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} pipeline must succeed. It's waiting for a manual action to continue."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} le pipeline doit réussir. Il est en attente d'une action manuelle pour continuer."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} pipeline must succeed. Push a commit that fixes the failure or %{linkStart}learn about other solutions.%{linkEnd}"
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} le pipeline doit réussir. Poussez un commit qui corrige l'échec ou %{linkStart}recherchez d'autres solutions.%{linkEnd}"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} the source branch must be rebased onto the target branch."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} la branche source doit être rebasée sur la branche cible."
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} you can only merge after the above items are resolved."
+msgstr "%{boldStart}Fusion bloquée :%{boldEnd} vous ne pouvez fusionner qu'après la résolution des éléments ci-dessus."
+
+msgid "mrWidget|%{boldStart}Merge unavailable:%{boldEnd} merge requests are read-only in a secondary Geo node."
+msgstr "%{boldStart}Fusion non disponible :%{boldEnd} les demandes de fusion sont en lecture seule sur un nœud Geo secondaire."
+
+msgid "mrWidget|%{boldStart}Merge unavailable:%{boldEnd} merge requests are read-only on archived projects."
+msgstr "%{boldStart}Fusion non disponible :%{boldEnd} les demandes de fusion sont en lecture seule sur les projets archivés."
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Changes are being shipped…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Les modifications sont en cours d'expédition…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Changes will land soon…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Les modifications vont bientôt débarquer…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Drum roll, please…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Roulement de tambour…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Everything's good…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Tout va bien…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Lift-off in 5… 4… 3…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Décollage dans 5… 4… 3…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Take a deep breath and relax…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Respirez profondément et détendez-vous…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} The changes are leaving the station…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Les modifications sont sur le départ…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} This is going to be great…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Ça s'annonce très bien…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} We're almost there…"
+msgstr "%{boldStart}Fusion en cours !%{boldEnd} Ça y est presque…"
+
+msgid "mrWidget|%{boldStart}Ready to be merged automatically.%{boldEnd} Ask someone with write access to this repository to merge this request."
+msgstr "%{boldStart}Prête à être fusionnée automatiquement.%{boldEnd} Demandez à quelqu'un ayant un accès en écriture sur ce dépôt de fusionner cette requête."
+
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}."
@@ -50894,6 +51868,12 @@ msgstr "%{metricsLinkStart}L’usage mémoire%{metricsLinkEnd} %{emphasisStart}a
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart}L’usage mémoire%{metricsLinkEnd} %{emphasisStart}est resté stable%{emphasisEnd} à %{memoryFrom}MO"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr "%{rules} règle non valide a été approuvée automatiquement car personne ne peut l'approuver."
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr "%{rules} règles non valides ont été approuvées automatiquement car personne ne peut les approuver."
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr "Un train de fusion est une file d'attente constituée de demandes de fusions attendant d'être fusionnées dans la branche cible. Les modifications de chaque demande de fusion sont combinées avec celles des demandes de fusion antérieures et testées avant la fusion."
@@ -50921,12 +51901,6 @@ msgstr "L'approbation est facultative"
msgid "mrWidget|Approval password is invalid."
msgstr "Le mot de passe d'approbation n'est pas valide."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr "La règle d’approbation %{rules} n'est pas valide. GitLab l'a approuvée automatiquement pour débloquer la demande de fusion. %{link}"
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr "Les règles d’approbation %{rules} ne sont pas valides. GitLab les a approuvées automatiquement pour débloquer la demande de fusion. %{link}"
-
msgid "mrWidget|Approve"
msgstr "Approuver"
@@ -50942,6 +51916,9 @@ msgstr "Approuvé par vous"
msgid "mrWidget|Approved by you and others"
msgstr "Approuvé par vous et d'autres personnes"
+msgid "mrWidget|Are you sure you want to rebase?"
+msgstr ""
+
msgid "mrWidget|Assign yourself to these issues"
msgstr "Assignez-vous sur ces tickets"
@@ -51021,83 +51998,29 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] "Mentionne le ticket"
msgstr[1] "Mentionne les tickets"
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr "Fusion bloquée : une clé de ticket Jira doit être citée dans le titre ou dans la description."
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr "Fusion bloquée : toutes les approbations requises doivent être données."
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr "Fusion bloquée : toutes les vérifications d'état doivent passer."
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "Fusion bloquée : tous les fils de conversation doivent être résolus."
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr "Fusion bloquée : les licences refusées doivent être supprimées."
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr "Fusion bloquée : la fusion en avance rapide n’est pas possible. Pour fusionner cette demande, rebasez localement au préalable."
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr "Fusion bloquée : des conflits de fusion doivent être résolus."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr "Fusion bloquée : le pipeline doit réussir. Il est en attente d'une action manuelle pour continuer."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr "Fusion bloquée : le pipeline doit réussir. Poussez une validation qui corrige l'erreur, ou %{linkStart}explorez d'autres solutions.%{linkEnd}"
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr "Fusion bloquée : vous ne pouvez fusionner qu'après résolution des éléments ci-dessus."
-
msgid "mrWidget|Merge failed."
msgstr "La fusion a échoué."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr "Fusion indisponible : les demandes de fusion sur les projets archivés sont en lecture seule."
-
msgid "mrWidget|Merged by"
msgstr "Fusionnée par"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr "Fusion en cours ! Les modifications sont en cours d'application…"
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr "Fusion en cours ! Les modifications seront bientôt faites…"
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr "Fusion en cours ! Roulement de tambour…"
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr "Fusion en cours ! Tout va bien…"
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr "Fusion ! Décollage dans 5… 4… 3…"
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr "Fusion ! Respirez profondément et détendez-vous…"
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr "Fusion ! Les modifications sont en route…"
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr "Fusion en cours ! Ça va bien se passer…"
-
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "Fusion en cours ! Nous y sommes presque…"
-
msgid "mrWidget|More information"
msgstr "Plus d'informations"
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "Aucun utilisateur ne correspond aux critères de la règle."
-
msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr "Veuillez le restaurer ou utiliser une branche %{type} différente."
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "Prête à être fusionnée automatiquement. Demandez à quelqu’un ayant un accès en écriture à ce dépôt d’effectuer cette fusion"
+msgid "mrWidget|Rebase"
+msgstr "Rebaser"
+
+msgid "mrWidget|Rebase in progress"
+msgstr "Rebasage en cours"
+
+msgid "mrWidget|Rebase without pipeline"
+msgstr "Rebaser sans pipeline"
msgid "mrWidget|Refresh"
msgstr "Actualiser"
@@ -51142,7 +52065,7 @@ msgid "mrWidget|The %{type} branch %{codeStart}%{name}%{codeEnd} does not exist.
msgstr "La branche %{type} %{codeStart}%{name}%{codeEnd} n'existe pas."
msgid "mrWidget|The source branch is %{link} the target branch"
-msgstr "La branche source est %{link} à la branche cible"
+msgstr "La branche source a %{link} sur la branche cible"
msgid "mrWidget|This merge request failed to be merged automatically"
msgstr "Cette demande de fusion n’a pas pu être fusionnée automatiquement"
@@ -51159,9 +52082,6 @@ msgstr "Pour modifier ce message par défaut, éditez le modèle des messages po
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr "Pour modifier ce message par défaut, éditez le modèle des messages pour les squash de validations. %{linkStart}En savoir plus.%{linkEnd}"
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr "Les utilisateurs qui peuvent écrire dans les branches source ou cible peuvent résoudre les conflits."
-
msgid "mrWidget|What is a merge train?"
msgstr "Qu'est-ce qu'un train de fusion ?"
@@ -51186,6 +52106,9 @@ msgstr "doit être une adresse IPv4 ou IPv6 valide"
msgid "must be a valid json schema"
msgstr "doit être un schéma json valide"
+msgid "must be a valid syntax highlighting theme ID"
+msgstr "doit être un ID de thème de coloration syntaxique valide"
+
msgid "must be after start"
msgstr "doit être après le début"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 88a17b7d697..97b4b0e614e 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -466,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -635,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -836,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -851,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -987,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1231,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1509,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1818,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -1932,6 +1944,9 @@ msgstr ""
msgid "APIFuzzing|folder/openapi.json"
msgstr ""
+msgid "AWS"
+msgstr ""
+
msgid "AWS Access Key"
msgstr ""
@@ -1971,6 +1986,9 @@ msgstr ""
msgid "Abuse reports notification email"
msgstr ""
+msgid "AbuseReports|No reports found"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2139,6 +2157,9 @@ 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|Awarded %{timeAgo} by %{namespace}"
+msgstr ""
+
msgid "Acknowledge"
msgstr ""
@@ -2235,9 +2256,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2259,6 +2277,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2268,6 +2289,9 @@ 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 ""
@@ -2382,6 +2406,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2409,6 +2436,9 @@ msgstr ""
msgid "Add request manually"
msgstr ""
+msgid "Add start and due date"
+msgstr ""
+
msgid "Add suggestion to batch"
msgstr ""
@@ -3609,9 +3639,6 @@ msgstr ""
msgid "AdminUsers|user cap"
msgstr ""
-msgid "Administration"
-msgstr ""
-
msgid "Administrators"
msgstr ""
@@ -3702,40 +3729,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4266,7 +4263,7 @@ msgstr ""
msgid "Already blocked"
msgstr ""
-msgid "Already have login and password?"
+msgid "Already have an account?"
msgstr ""
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
@@ -4738,6 +4735,9 @@ 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 ""
@@ -4747,6 +4747,135 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard not found"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+msgstr ""
+
+msgid "Analytics|No dashboard matches the specified URL path."
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+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 %{dashboardId}"
+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 "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4825,13 +4954,28 @@ 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|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."
+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."
@@ -4976,12 +5120,18 @@ 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 ""
@@ -5226,6 +5376,11 @@ 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 ""
@@ -5238,6 +5393,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5313,9 +5478,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5328,6 +5490,9 @@ 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 ""
@@ -5486,9 +5651,22 @@ 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 ""
@@ -5498,18 +5676,42 @@ 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|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 ""
@@ -5679,7 +5881,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5912,9 +6114,6 @@ msgstr ""
msgid "Authentication method updated"
msgstr ""
-msgid "Authentication via U2F device failed."
-msgstr ""
-
msgid "Authentication via WebAuthn device failed."
msgstr ""
@@ -5933,9 +6132,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5948,9 +6144,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5960,9 +6153,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6344,6 +6546,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6371,9 +6576,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6443,6 +6645,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6458,9 +6663,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6596,27 +6798,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6626,9 +6810,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6769,6 +6950,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6991,15 +7175,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7012,9 +7208,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7132,9 +7325,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7153,6 +7343,15 @@ 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 ""
@@ -7183,10 +7382,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7228,6 +7430,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7333,6 +7538,9 @@ 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 ""
@@ -7378,6 +7586,9 @@ msgstr ""
msgid "Branches|Unable to load branches"
msgstr ""
+msgid "Branches|View branch rules"
+msgstr ""
+
msgid "Branches|Yes, delete branch"
msgstr ""
@@ -7387,6 +7598,9 @@ 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 ""
@@ -7573,9 +7787,6 @@ msgstr ""
msgid "BulkImport|Import is finished. Pick another name for re-import"
msgstr ""
-msgid "BulkImport|Import selected"
-msgstr ""
-
msgid "BulkImport|Import with projects"
msgstr ""
@@ -7657,9 +7868,6 @@ msgstr ""
msgid "BulkImport|expected an associated Project but has an associated Group"
msgstr ""
-msgid "BulkImport|invalid entity source type"
-msgstr ""
-
msgid "BulkImport|must be a group"
msgstr ""
@@ -7995,6 +8203,15 @@ 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 ""
@@ -8112,6 +8329,9 @@ 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 ""
@@ -8181,6 +8401,9 @@ msgstr ""
msgid "CascadingSettings|cannot be nil when locking the attribute"
msgstr ""
+msgid "Category"
+msgstr ""
+
msgid "Cause identified"
msgstr ""
@@ -8494,6 +8717,9 @@ 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 ""
@@ -8536,6 +8762,9 @@ 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 ""
@@ -8545,16 +8774,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8581,6 +8807,9 @@ 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 ""
@@ -8833,10 +9062,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8866,6 +9095,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9360,6 +9592,9 @@ msgstr ""
msgid "ClusterAgents|Agent %{strongStart}disconnected%{strongEnd}"
msgstr ""
+msgid "ClusterAgents|Agent ID #%{agentId}"
+msgstr ""
+
msgid "ClusterAgents|Agent access token:"
msgstr ""
@@ -9647,6 +9882,9 @@ 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 ""
@@ -9938,10 +10176,10 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based method to connect clusters to GitLab was %{linkStart}deprecated%{linkEnd} in GitLab 14.5."
@@ -10330,9 +10568,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10345,6 +10580,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10426,6 +10664,9 @@ msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10492,7 +10733,7 @@ msgstr ""
msgid "ComplianceFrameworks|Remove default"
msgstr ""
-msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}What is a compliance pipeline configuration?%{linkEnd}"
+msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}See some examples%{linkEnd}."
msgstr ""
msgid "ComplianceFrameworks|Set default"
@@ -10534,9 +10775,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10555,9 +10811,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10842,8 +11095,8 @@ msgid_plural "ContainerRegistry|%{count} Image repositories"
msgstr[0] ""
msgstr[1] ""
-msgid "ContainerRegistry|%{count} Tag"
-msgid_plural "ContainerRegistry|%{count} Tags"
+msgid "ContainerRegistry|%{count} tag"
+msgid_plural "ContainerRegistry|%{count} tags"
msgstr[0] ""
msgstr[1] ""
@@ -11179,9 +11432,15 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
+msgid "ContentEditor|For %{quickActionsDocsLinkStart}quick actions%{quickActionsDocsLinkEnd}, type %{keyboardStart}/%{keyboardEnd}."
+msgstr ""
+
msgid "ContentEditor|You have to provide a renderMarkdown function or a custom serializer"
msgstr ""
@@ -11221,12 +11480,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11242,6 +11510,9 @@ 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 ""
@@ -11287,7 +11558,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11308,7 +11582,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11380,6 +11654,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11815,6 +12092,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12064,9 +12344,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12274,6 +12551,9 @@ 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 ""
@@ -12373,7 +12653,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12540,9 +12820,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13217,6 +13494,11 @@ 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 ""
@@ -13454,6 +13736,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13496,6 +13781,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -13930,6 +14218,9 @@ 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 ""
@@ -14247,6 +14538,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14348,10 +14642,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14456,6 +14753,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14651,6 +14951,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14735,6 +15038,9 @@ msgstr ""
msgid "Diffs|with %{additions} and %{deletions}"
msgstr ""
+msgid "Dimension"
+msgstr ""
+
msgid "Direct member"
msgstr ""
@@ -14804,9 +15110,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15244,6 +15547,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15268,6 +15574,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15286,9 +15595,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15745,6 +16060,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15790,7 +16108,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15808,6 +16126,9 @@ 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 ""
@@ -16093,6 +16414,9 @@ msgstr ""
msgid "Environment|Deployment tier"
msgstr ""
+msgid "Environment|Kubernetes overview"
+msgstr ""
+
msgid "Epic"
msgstr ""
@@ -16102,6 +16426,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16213,6 +16540,9 @@ 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 ""
@@ -16809,6 +17139,9 @@ 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 ""
@@ -16878,9 +17211,6 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
-msgid "Experiment"
-msgstr ""
-
msgid "Experiments"
msgstr ""
@@ -16923,9 +17253,6 @@ msgstr ""
msgid "Explore GitLab"
msgstr ""
-msgid "Explore Groups"
-msgstr ""
-
msgid "Explore groups"
msgstr ""
@@ -16935,15 +17262,15 @@ msgstr ""
msgid "Explore projects"
msgstr ""
-msgid "Explore public groups"
-msgstr ""
-
msgid "Explore public projects"
msgstr ""
msgid "Explore snippets"
msgstr ""
+msgid "Explore topics"
+msgstr ""
+
msgid "Export"
msgstr ""
@@ -17604,9 +17931,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17730,6 +18054,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17886,9 +18213,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18015,22 +18339,43 @@ msgstr ""
msgid "ForksDivergence|%{messages} the upstream repository."
msgstr ""
+msgid "ForksDivergence|Check out to a new 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 a merge request to your project's default branch."
+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|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 "Format: %{dateFormat}"
+msgid "ForksDivergence|Update fork"
msgstr ""
-msgid "Framework successfully deleted"
+msgid "Format: %{dateFormat}"
msgstr ""
-msgid "Free"
+msgid "Framework successfully deleted"
msgstr ""
msgid "Free Trial of GitLab.com Ultimate"
@@ -18321,7 +18666,7 @@ msgstr ""
msgid "Geo|Does not match the primary storage configuration"
msgstr ""
-msgid "Geo|Edit %{nodeType} site"
+msgid "Geo|Edit %{siteType} site"
msgstr ""
msgid "Geo|Edit Geo Site"
@@ -18504,7 +18849,7 @@ msgstr ""
msgid "Geo|Remove"
msgstr ""
-msgid "Geo|Remove %{nodeType} site"
+msgid "Geo|Remove %{siteType} site"
msgstr ""
msgid "Geo|Remove entry"
@@ -18843,13 +19188,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18900,6 +19254,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18924,6 +19281,12 @@ 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 ""
@@ -18939,9 +19302,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18990,11 +19350,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19088,12 +19443,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19133,6 +19494,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19145,13 +19509,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19169,7 +19533,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19223,6 +19587,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19295,6 +19662,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19349,15 +19719,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19574,6 +19938,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19763,6 +20151,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20249,7 +20640,7 @@ msgstr ""
msgid "GroupSettings|When the number of active users exceeds this number, additional users must be %{user_cap_docs_link_start}approved by an owner%{user_cap_docs_link_end}. Leave empty if you don't want to enforce approvals. Increasing the user cap will not automatically approve pending users."
msgstr ""
-msgid "GroupSettings|You can only transfer the group to a group you manage."
+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."
@@ -20375,6 +20766,9 @@ 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 ""
@@ -20390,10 +20784,16 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
-msgid "GroupsNew|Not all related objects are migrated. %{docs_link_start}More info%{docs_link_end}."
+msgid "GroupsNew|Not all group items are migrated. %{docs_link_start}What items are migrated%{docs_link_end}?"
msgstr ""
msgid "GroupsNew|Personal access token"
@@ -20414,7 +20814,7 @@ 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 %{docs_link_start}group migration%{docs_link_end}."
+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."
@@ -20766,6 +21166,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21256,6 +21659,9 @@ 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 ""
@@ -21268,6 +21674,9 @@ 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 ""
@@ -21328,7 +21737,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21961,7 +22370,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22531,9 +22940,6 @@ msgstr ""
msgid "Indicates whether this runner can pick jobs without tags"
msgstr ""
-msgid "Info"
-msgstr ""
-
msgid "Inform users without uploaded SSH keys that they can't push over SSH until one is added"
msgstr ""
@@ -22624,12 +23030,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22803,10 +23215,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22824,6 +23239,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23112,7 +23530,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23241,9 +23659,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23513,6 +23928,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23738,6 +24159,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24275,9 +24699,33 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Image"
+msgstr ""
+
+msgid "JobAssistant|Image entrypoint (optional)"
+msgstr ""
+
+msgid "JobAssistant|Image name (optional)"
+msgstr ""
+
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24966,6 +25414,15 @@ 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 ""
@@ -25047,6 +25504,9 @@ 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 ""
@@ -25056,6 +25516,9 @@ 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 ""
@@ -25071,9 +25534,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25089,6 +25549,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feedback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25338,6 +25801,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25365,6 +25833,12 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link copied to clipboard."
+msgstr ""
+
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25458,9 +25932,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25503,6 +25974,9 @@ 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 ""
@@ -25542,6 +26016,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25560,9 +26037,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25668,7 +26142,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26160,6 +26634,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26253,6 +26730,9 @@ 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|must be top-level namespace"
msgstr ""
@@ -26476,9 +26956,6 @@ msgstr ""
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge commit SHA"
-msgstr ""
-
msgid "Merge commit message"
msgstr ""
@@ -26644,6 +27121,15 @@ msgstr ""
msgid "MergeRequests|An error occurred while saving the draft comment."
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 ""
@@ -26653,6 +27139,12 @@ 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 ""
@@ -26791,9 +27283,6 @@ msgstr ""
msgid "Messages"
msgstr ""
-msgid "Metadata"
-msgstr ""
-
msgid "Method"
msgstr ""
@@ -27455,9 +27944,15 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Author"
+msgstr ""
+
msgid "MlExperimentTracking|Create a new experiment"
msgstr ""
+msgid "MlExperimentTracking|Create new candidates"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
@@ -27467,10 +27962,13 @@ msgstr ""
msgid "MlExperimentTracking|Experiment"
msgstr ""
-msgid "MlExperimentTracking|Experiment candidates"
+msgid "MlExperimentTracking|Filter candidates"
msgstr ""
-msgid "MlExperimentTracking|Filter candidates"
+msgid "MlExperimentTracking|ID"
+msgstr ""
+
+msgid "MlExperimentTracking|Info"
msgstr ""
msgid "MlExperimentTracking|Logged candidates for experiment"
@@ -27479,25 +27977,43 @@ 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|Name"
msgstr ""
-msgid "MlExperimentTracking|No candidates to display"
+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 experiments"
msgstr ""
-msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgid "MlExperimentTracking|No name"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|Parameters"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|Status"
+msgstr ""
+
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
msgstr ""
msgid "Modal updated"
@@ -27509,9 +28025,6 @@ msgstr ""
msgid "Modal|Close"
msgstr ""
-msgid "Model candidate details"
-msgstr ""
-
msgid "Modified"
msgstr ""
@@ -27593,7 +28106,7 @@ msgstr ""
msgid "Most relevant"
msgstr ""
-msgid "Most stars"
+msgid "Most starred"
msgstr ""
msgid "Move"
@@ -27841,6 +28354,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27889,10 +28405,34 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|Explore"
+msgstr ""
+
+msgid "Navigation|Frequent groups"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Frequent projects"
+msgstr ""
+
+msgid "Navigation|Groups"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|No group matches found"
+msgstr ""
+
+msgid "Navigation|No project matches found"
+msgstr ""
+
+msgid "Navigation|Projects"
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Search for projects or groups"
msgstr ""
msgid "Navigation|Switch to..."
@@ -28005,9 +28545,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28095,9 +28632,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28452,6 +28986,15 @@ 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 ""
@@ -28535,13 +29078,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28843,12 +29389,24 @@ 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|%{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 ""
@@ -28897,9 +29455,18 @@ 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 ""
@@ -28927,9 +29494,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28966,6 +29530,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28975,6 +29542,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28987,6 +29557,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29463,6 +30036,9 @@ 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 ""
@@ -29675,6 +30251,9 @@ msgstr ""
msgid "Open Selection"
msgstr ""
+msgid "Open color picker"
+msgstr ""
+
msgid "Open errors"
msgstr ""
@@ -29825,28 +30404,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30496,9 +31081,6 @@ msgstr ""
msgid "Parameter \"job_id\" cannot exceed length of %{job_id_max_size}"
msgstr ""
-msgid "Parameters"
-msgstr ""
-
msgid "Parent"
msgstr ""
@@ -30643,6 +31225,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30832,9 +31417,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31033,6 +31615,9 @@ 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 ""
@@ -31258,16 +31843,13 @@ msgstr ""
msgid "Pipelines charts"
msgstr ""
-msgid "Pipelines settings for '%{project_name}' were successfully updated."
+msgid "Pipelines for new changes cause older pending or running pipelines on the same branch to be cancelled."
msgstr ""
-msgid "Pipelines|\"Hello world\" with GitLab CI"
-msgstr ""
-
-msgid "Pipelines|%{jobs} %{ref_text} in %{duration}"
+msgid "Pipelines settings for '%{project_name}' were successfully updated."
msgstr ""
-msgid "Pipelines|(queued for %{queued_duration})"
+msgid "Pipelines|\"Hello world\" with GitLab CI"
msgstr ""
msgid "Pipelines|1. Set up a runner"
@@ -31303,13 +31885,13 @@ msgstr ""
msgid "Pipelines|CI lint"
msgstr ""
-msgid "Pipelines|Child pipeline (%{link_start}parent%{link_end})"
+msgid "Pipelines|CI/CD Catalog"
msgstr ""
-msgid "Pipelines|Clear runner caches"
+msgid "Pipelines|Child pipeline (%{link_start}parent%{link_end})"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
+msgid "Pipelines|Clear runner caches"
msgstr ""
msgid "Pipelines|Configure pipeline"
@@ -31357,6 +31939,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31408,7 +31996,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31417,6 +32005,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31453,13 +32044,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31489,6 +32080,12 @@ 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 ""
@@ -31510,6 +32107,9 @@ 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 ""
@@ -31519,6 +32119,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31834,6 +32437,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31855,6 +32461,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31996,6 +32605,9 @@ msgstr ""
msgid "PolicyRuleMultiSelect|All %{itemTypeName}"
msgstr ""
+msgid "PolicyRuleMultiSelect|Clear all"
+msgstr ""
+
msgid "PolicyRuleMultiSelect|Select %{itemTypeName}"
msgstr ""
@@ -32167,6 +32779,9 @@ 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|Opt out of the Web IDE Beta"
msgstr ""
@@ -32269,6 +32884,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32338,88 +32956,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32428,34 +32989,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32464,24 +33028,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32494,22 +33052,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Instrument your application"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32518,70 +33085,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32641,9 +33211,6 @@ msgstr ""
msgid "Profile"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
msgid "Profile failed to delete"
msgstr ""
@@ -32725,6 +33292,9 @@ msgstr ""
msgid "Profiles|Connected Accounts"
msgstr ""
+msgid "Profiles|Created %{time_ago}"
+msgstr ""
+
msgid "Profiles|Created%{time_ago}"
msgstr ""
@@ -32749,6 +33319,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32998,7 +33574,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33187,6 +33763,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33214,6 +33793,9 @@ 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 ""
@@ -33259,15 +33841,9 @@ msgstr ""
msgid "ProjectLastActivity|Never"
msgstr ""
-msgid "ProjectList|Explore"
-msgstr ""
-
msgid "ProjectList|Starred"
msgstr ""
-msgid "ProjectList|Topics"
-msgstr ""
-
msgid "ProjectList|Yours"
msgstr ""
@@ -33310,9 +33886,21 @@ 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 ""
@@ -33325,6 +33913,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33367,6 +33958,12 @@ 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 ""
@@ -33667,6 +34264,9 @@ 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 ""
@@ -33778,10 +34378,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33859,6 +34459,12 @@ 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|Transfer project"
msgstr ""
@@ -34039,6 +34645,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34165,6 +34774,9 @@ 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 ""
@@ -34180,6 +34792,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34360,9 +34975,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34471,12 +35083,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34648,9 +35254,25 @@ 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 ""
@@ -34660,10 +35282,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34672,6 +35306,9 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -34696,6 +35333,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34939,6 +35579,9 @@ 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 ""
@@ -35236,6 +35879,9 @@ 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] ""
@@ -35271,13 +35917,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35370,6 +36016,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36498,9 +37147,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36670,9 +37316,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36750,6 +37393,9 @@ 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|Admin area › Runners"
+msgstr ""
+
msgid "Runners|Administrator"
msgstr ""
@@ -36813,6 +37459,9 @@ 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 ""
@@ -36831,6 +37480,9 @@ 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 ""
@@ -36893,18 +37545,30 @@ msgstr ""
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
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|Fetch GitLab Runner release version data from GitLab.com"
+msgstr ""
+
msgid "Runners|Filter projects"
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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36923,6 +37587,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36950,6 +37617,9 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37004,6 +37674,9 @@ 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 ""
@@ -37054,6 +37727,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37069,6 +37748,9 @@ 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 ""
@@ -37111,6 +37793,9 @@ 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 ""
@@ -37162,6 +37847,9 @@ msgstr ""
msgid "Runners|Runner unassigned from project."
msgstr ""
+msgid "Runners|Runner version management"
+msgstr ""
+
msgid "Runners|Runners"
msgstr ""
@@ -37186,9 +37874,15 @@ 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 ""
@@ -37222,6 +37916,15 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
+msgid "Runners|Step 3 (optional)"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37231,6 +37934,12 @@ 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 ""
@@ -37248,6 +37957,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37269,6 +37981,9 @@ 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 ""
@@ -37338,6 +38053,9 @@ msgstr ""
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
+msgid "Runners|You've created a new runner!"
+msgstr ""
+
msgid "Runners|active"
msgstr ""
@@ -37374,6 +38092,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37398,9 +38119,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37530,16 +38248,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run %{dastProfiles} with tags %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37581,9 +38302,18 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|scanner profile %{scannerProfile} and site profile %{siteProfile}"
+msgstr ""
+
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37960,12 +38690,6 @@ msgstr ""
msgid "Seats owed"
msgstr ""
-msgid "Seats usage data as of %{last_enqueue_time} (Updated daily)"
-msgstr ""
-
-msgid "Seats usage data is updated every day at 12:00pm UTC"
-msgstr ""
-
msgid "Secondary email:"
msgstr ""
@@ -38032,22 +38756,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38176,7 +38903,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38188,6 +38915,9 @@ msgstr ""
msgid "SecurityConfiguration|Security training"
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 ""
@@ -38290,6 +39020,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38395,9 +39128,21 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+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 ""
@@ -38488,6 +39233,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38509,6 +39257,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38518,6 +39269,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38584,7 +39338,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39115,6 +39869,9 @@ msgstr ""
msgid "Select branches"
msgstr ""
+msgid "Select color"
+msgstr ""
+
msgid "Select default branch"
msgstr ""
@@ -39142,6 +39899,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39211,9 +39971,6 @@ msgstr ""
msgid "Select type"
msgstr ""
-msgid "Selected"
-msgstr ""
-
msgid "Selected commits"
msgstr ""
@@ -39244,6 +40001,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39256,6 +40016,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39268,6 +40031,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39370,6 +40136,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39505,6 +40277,9 @@ 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 ""
@@ -39532,7 +40307,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39783,6 +40558,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40082,6 +40860,9 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
+msgid "Skip to main content"
+msgstr ""
+
msgid "Skipped"
msgstr ""
@@ -40100,15 +40881,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40118,6 +40917,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40127,6 +40929,9 @@ 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 ""
@@ -40160,6 +40965,9 @@ 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 ""
@@ -40349,6 +41157,9 @@ 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 ""
@@ -40769,9 +41580,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40865,6 +41673,18 @@ 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 ""
@@ -41087,6 +41907,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41354,6 +42177,9 @@ msgstr ""
msgid "SubscriptionTable|Last invoice"
msgstr ""
+msgid "SubscriptionTable|Last updated at %{seatsLastUpdated} UTC"
+msgstr ""
+
msgid "SubscriptionTable|Loading subscriptions"
msgstr ""
@@ -41414,6 +42240,9 @@ msgstr ""
msgid "SubscriptionTable|Trial start date"
msgstr ""
+msgid "SubscriptionTable|Up to date"
+msgstr ""
+
msgid "SubscriptionTable|Usage"
msgstr ""
@@ -41486,9 +42315,6 @@ msgstr ""
msgid "Successfully deactivated"
msgstr ""
-msgid "Successfully deleted U2F device."
-msgstr ""
-
msgid "Successfully deleted WebAuthn device."
msgstr ""
@@ -41732,16 +42558,22 @@ 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|Sync subscription request."
+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}."
@@ -41750,7 +42582,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41779,9 +42611,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41824,9 +42653,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41977,9 +42803,27 @@ 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 ""
@@ -42386,10 +43230,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42411,9 +43255,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42602,6 +43443,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42644,9 +43488,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42704,6 +43545,9 @@ 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 ""
@@ -43017,7 +43861,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43362,6 +44215,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43551,13 +44407,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43674,9 +44524,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. It is already an ancestor of the parent epic."
msgstr ""
@@ -44058,6 +44905,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44112,10 +44962,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44566,6 +45413,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45145,9 +45995,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45250,9 +46097,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45298,12 +46142,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45409,6 +46247,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45508,6 +46349,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45565,6 +46409,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45706,9 +46559,6 @@ msgstr ""
msgid "Update it"
msgstr ""
-msgid "Update milestone"
-msgstr ""
-
msgid "Update now"
msgstr ""
@@ -45724,6 +46574,9 @@ 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 ""
@@ -45850,6 +46703,12 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
+msgid "UsageQuotas|Namespace transfer data used"
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46021,6 +46880,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46225,6 +47087,9 @@ 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 ""
@@ -46237,6 +47102,9 @@ 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 ""
@@ -46311,6 +47179,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46461,9 +47332,6 @@ msgstr ""
msgid "UserProfile|Activity"
msgstr ""
-msgid "UserProfile|An error occurred loading the profile. Please refresh the page to try again."
-msgstr ""
-
msgid "UserProfile|Blocked user"
msgstr ""
@@ -46557,6 +47425,9 @@ msgstr ""
msgid "UserProfile|User ID: %{id}"
msgstr ""
+msgid "UserProfile|User profile navigation"
+msgstr ""
+
msgid "UserProfile|View all"
msgstr ""
@@ -46737,6 +47608,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46848,6 +47722,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46992,6 +47869,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47021,9 +47901,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47083,9 +47960,6 @@ msgstr ""
msgid "View logs"
msgstr ""
-msgid "View markdown"
-msgstr ""
-
msgid "View milestones"
msgstr ""
@@ -47118,9 +47992,6 @@ msgstr[1] ""
msgid "View replaced file @ "
msgstr ""
-msgid "View rich text"
-msgstr ""
-
msgid "View seat usage"
msgstr ""
@@ -47154,9 +48025,15 @@ msgstr ""
msgid "Viewing commit"
msgstr ""
+msgid "Viewing markdown"
+msgstr ""
+
msgid "Viewing projects and designs data from a primary site is not possible when using a unified URL. Visit the secondary site directly. %{geo_help_url}"
msgstr ""
+msgid "Viewing rich text"
+msgstr ""
+
msgid "Violation"
msgstr ""
@@ -47226,6 +48103,69 @@ 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|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 ""
@@ -47586,9 +48526,6 @@ msgstr ""
msgid "Warning: Synchronizing LDAP removes direct members' access."
msgstr ""
-msgid "Watch how"
-msgstr ""
-
msgid "We also use email for avatar detection if no avatar is uploaded."
msgstr ""
@@ -47616,12 +48553,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47673,9 +48604,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47817,6 +48745,9 @@ 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 ""
@@ -48080,6 +49011,11 @@ 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] ""
@@ -48118,6 +49054,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48337,7 +49276,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48385,6 +49324,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48408,6 +49350,9 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
msgid "WorkItem|Convert to task"
msgstr ""
@@ -48438,9 +49383,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48600,6 +49551,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48630,6 +49584,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49031,9 +49988,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49213,6 +50167,9 @@ 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 ""
@@ -49395,7 +50352,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49461,9 +50418,6 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
-msgstr ""
-
msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
@@ -49512,9 +50466,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49545,6 +50496,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49577,9 +50531,6 @@ msgid_plural "Your free group is now limited to %d members"
msgstr[0] ""
msgstr[1] ""
-msgid "Your groups"
-msgstr ""
-
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 ""
@@ -49607,9 +50558,6 @@ msgstr ""
msgid "Your membership in %{group} no longer expires."
msgstr ""
-msgid "Your message here"
-msgstr ""
-
msgid "Your name"
msgstr ""
@@ -49682,9 +50630,6 @@ msgstr ""
msgid "Your sign-in page is %{url}."
msgstr ""
-msgid "Your snippets"
-msgstr ""
-
msgid "Your subscription expired!"
msgstr ""
@@ -49699,7 +50644,10 @@ 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 %{namespace_name} is over the %{free_user_limit} user limit"
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
+msgid "Your top-level group %{name} will move to a read-only state soon"
msgstr ""
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
@@ -49939,6 +50887,9 @@ 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 ""
@@ -50269,9 +51220,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50337,6 +51285,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50367,6 +51318,9 @@ 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 ""
@@ -50388,12 +51342,18 @@ 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 ""
@@ -50644,9 +51604,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50762,6 +51719,12 @@ msgstr ""
msgid "in"
msgstr ""
+msgid "in %{duration} and was queued for %{queued_duration}"
+msgstr ""
+
+msgid "in %{duration}, using %{compute_credits} compute credits, and was queued for %{queued_duration}"
+msgstr ""
+
msgid "in group %{link_to_group}"
msgstr ""
@@ -51112,6 +52075,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51139,12 +52108,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51160,6 +52123,9 @@ 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 ""
@@ -51251,9 +52217,6 @@ msgstr ""
msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
-msgstr ""
-
msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
@@ -51350,6 +52313,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po
index 96ab73d302c..8ea1de85ee4 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr " %{start} a %{end}"
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po
index 2dc20967943..daf6aff08a0 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -566,6 +566,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -615,6 +622,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -622,6 +636,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -812,6 +832,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1013,6 +1036,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1028,9 +1054,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1168,6 +1191,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1446,6 +1472,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1750,13 +1779,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -2089,9 +2111,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2506,9 +2525,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2530,6 +2546,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "הוספת רשימה ממוספרת"
@@ -2539,6 +2558,9 @@ 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 ""
@@ -2653,6 +2675,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2791,6 +2816,9 @@ msgstr ""
msgid "Additional text"
msgstr "טקסט נוסף"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3970,40 +3998,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4375,6 +4373,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -5007,6 +5008,9 @@ 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 ""
@@ -5016,6 +5020,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5094,13 +5215,28 @@ 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|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."
+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."
@@ -5249,12 +5385,18 @@ 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 ""
@@ -5509,6 +5651,13 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5521,6 +5670,20 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5596,9 +5759,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5611,6 +5771,9 @@ 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 ""
@@ -5968,7 +6131,7 @@ msgstr[3] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6224,9 +6387,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6239,9 +6399,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6251,9 +6408,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6635,6 +6801,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6662,9 +6831,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6734,6 +6900,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6749,9 +6918,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6887,27 +7053,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6917,9 +7065,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7062,6 +7207,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7290,15 +7438,27 @@ msgstr[3] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7311,9 +7471,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7431,9 +7588,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7452,6 +7606,15 @@ 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 ""
@@ -7482,10 +7645,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7527,6 +7693,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8296,6 +8465,15 @@ 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 ""
@@ -8413,6 +8591,9 @@ 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 ""
@@ -8799,6 +8980,9 @@ 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 ""
@@ -8841,6 +9025,9 @@ 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 ""
@@ -8850,16 +9037,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8886,6 +9070,9 @@ 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 ""
@@ -8904,6 +9091,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8922,6 +9112,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9042,12 +9235,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9126,10 +9325,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9159,6 +9358,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9944,6 +10146,9 @@ 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 ""
@@ -10235,7 +10440,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10629,9 +10834,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10644,6 +10846,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10713,12 +10918,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10827,9 +11041,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10848,9 +11077,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11478,6 +11704,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11520,12 +11749,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11541,6 +11779,9 @@ 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 ""
@@ -11586,7 +11827,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11607,7 +11851,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11679,6 +11923,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11925,7 +12172,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12114,6 +12361,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12363,9 +12613,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12573,6 +12820,9 @@ 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 ""
@@ -12672,7 +12922,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12841,9 +13091,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13757,6 +14004,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13799,6 +14049,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14566,6 +14819,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14669,10 +14925,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14777,6 +15036,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14972,6 +15234,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15131,9 +15396,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15573,6 +15835,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15597,6 +15862,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15615,9 +15883,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16074,6 +16348,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16119,7 +16396,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16137,6 +16414,9 @@ 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 ""
@@ -16431,6 +16711,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16542,6 +16825,9 @@ 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 ""
@@ -16830,6 +17116,9 @@ 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 ""
@@ -17110,6 +17399,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17134,6 +17426,9 @@ 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 ""
@@ -17335,6 +17630,9 @@ 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 ""
@@ -17353,6 +17651,9 @@ 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 ""
@@ -17929,9 +18230,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18055,6 +18353,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18211,9 +18512,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18355,9 +18653,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19174,13 +19469,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19231,6 +19535,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19255,6 +19562,12 @@ 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 ""
@@ -19270,9 +19583,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19321,13 +19631,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19421,12 +19724,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19466,6 +19775,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19478,13 +19790,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19502,7 +19814,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19556,6 +19868,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19628,6 +19943,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19682,15 +20000,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19907,6 +20219,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20096,6 +20432,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20447,6 +20786,9 @@ 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 ""
@@ -20705,6 +21047,9 @@ 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 ""
@@ -20720,6 +21065,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21100,6 +21451,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21447,6 +21801,9 @@ 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 ""
@@ -21546,6 +21903,9 @@ 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 ""
@@ -21588,15 +21948,24 @@ 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 ""
@@ -21657,7 +22026,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21887,6 +22256,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22293,7 +22665,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22956,12 +23328,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23137,10 +23515,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23158,6 +23539,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23446,7 +23830,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23575,9 +23959,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23849,6 +24230,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24074,6 +24461,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24611,9 +25001,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25306,6 +25711,15 @@ 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 ""
@@ -25387,6 +25801,9 @@ 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 ""
@@ -25396,6 +25813,9 @@ 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 ""
@@ -25411,9 +25831,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25429,6 +25846,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25690,6 +26110,13 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Line changes"
msgstr ""
@@ -25717,6 +26144,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25810,9 +26240,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25855,6 +26282,9 @@ 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 ""
@@ -25894,6 +26324,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25912,9 +26345,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25984,9 +26414,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26023,10 +26450,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26518,6 +26942,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26599,12 +27026,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26829,18 +27265,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26913,9 +27340,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26928,6 +27352,27 @@ 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 ""
@@ -27542,6 +27987,9 @@ msgstr[3] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27722,6 +28170,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27734,6 +28188,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27794,31 +28251,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28164,6 +28636,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28212,10 +28687,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28330,9 +28811,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28420,9 +28898,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28777,6 +29252,15 @@ 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 ""
@@ -28862,13 +29346,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29178,12 +29665,24 @@ 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|%{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 ""
@@ -29232,9 +29731,18 @@ 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 ""
@@ -29262,9 +29770,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29301,6 +29806,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29310,6 +29818,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29322,6 +29833,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29800,6 +30314,9 @@ 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 ""
@@ -29869,9 +30386,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30167,28 +30681,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30993,6 +31513,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31182,9 +31705,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31383,6 +31903,9 @@ 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 ""
@@ -31608,6 +32131,9 @@ 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 ""
@@ -31659,9 +32185,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31707,6 +32230,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31758,7 +32287,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31767,6 +32296,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31803,13 +32335,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31839,6 +32371,12 @@ 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 ""
@@ -31860,6 +32398,9 @@ 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 ""
@@ -31869,6 +32410,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32184,6 +32728,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32205,6 +32752,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32265,7 +32815,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32619,6 +33169,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32688,88 +33241,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32778,34 +33274,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32814,24 +33313,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32844,22 +33337,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32868,70 +33370,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33099,6 +33604,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33348,7 +33859,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33522,6 +34033,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33534,6 +34048,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33561,6 +34078,9 @@ 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 ""
@@ -33657,9 +34177,21 @@ 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 ""
@@ -33672,6 +34204,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33714,7 +34249,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33729,9 +34267,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33861,9 +34396,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34014,9 +34546,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34059,9 +34588,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34098,9 +34624,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34143,10 +34666,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34170,9 +34693,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34407,6 +34927,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34533,6 +35056,9 @@ 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 ""
@@ -34548,6 +35074,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34728,9 +35257,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34839,12 +35365,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35016,9 +35536,29 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35028,10 +35568,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35040,15 +35592,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35058,6 +35619,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35514,24 +36078,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35607,6 +36162,9 @@ 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] ""
@@ -35644,13 +36202,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35743,6 +36301,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36692,15 +37253,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36883,9 +37450,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37059,9 +37623,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37144,6 +37705,9 @@ 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|Administrator"
msgstr ""
@@ -37207,6 +37771,9 @@ 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 ""
@@ -37225,6 +37792,9 @@ 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 ""
@@ -37283,9 +37853,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37298,6 +37874,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37316,6 +37898,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37343,6 +37928,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37352,6 +37943,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37364,6 +37958,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37406,6 +38003,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37440,6 +38040,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37455,6 +38061,9 @@ 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 ""
@@ -37479,6 +38088,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37494,6 +38106,12 @@ 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 ""
@@ -37566,9 +38184,15 @@ 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 ""
@@ -37602,6 +38226,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37611,6 +38241,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37630,6 +38263,9 @@ msgstr[3] ""
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 runner has not run any jobs."
msgstr ""
@@ -37678,6 +38314,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37732,15 +38371,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37762,6 +38392,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37786,9 +38419,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37918,16 +38548,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37969,9 +38602,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38442,22 +39081,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
msgstr ""
-msgid "Security dashboard"
+msgid "Security configuration"
msgstr ""
-msgid "Security navigation"
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38586,7 +39228,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38700,6 +39342,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38805,9 +39450,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38898,6 +39552,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38919,6 +39576,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38928,6 +39588,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38994,7 +39657,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39072,6 +39735,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39549,6 +40215,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39651,6 +40320,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39663,6 +40335,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39675,6 +40350,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39777,6 +40455,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39912,6 +40596,9 @@ 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 ""
@@ -39939,7 +40626,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40192,6 +40879,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40358,9 +41048,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40514,15 +41201,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40532,6 +41237,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40541,6 +41249,9 @@ 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 ""
@@ -40574,9 +41285,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40760,12 +41477,18 @@ 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 ""
@@ -41177,9 +41900,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41243,6 +41963,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41492,6 +42215,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42137,16 +42863,22 @@ 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|Sync subscription request."
+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}."
@@ -42155,7 +42887,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42186,9 +42918,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42231,9 +42960,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42384,9 +43110,27 @@ 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 ""
@@ -42797,10 +43541,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42826,9 +43570,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42955,6 +43696,9 @@ 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 ""
@@ -43016,6 +43760,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43058,9 +43805,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -43118,6 +43862,9 @@ 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 ""
@@ -43435,7 +44182,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43780,6 +44536,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43969,13 +44728,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44476,6 +45229,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44530,10 +45286,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44988,6 +45741,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45479,6 +46235,9 @@ 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 ""
@@ -45570,9 +46329,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45675,9 +46431,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45723,12 +46476,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45834,6 +46581,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45933,6 +46683,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45990,6 +46743,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46077,6 +46839,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46146,6 +46911,9 @@ 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 ""
@@ -46272,6 +47040,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46443,6 +47214,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46647,6 +47421,9 @@ 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 ""
@@ -46659,6 +47436,9 @@ 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 ""
@@ -46735,6 +47515,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47161,6 +47944,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47272,6 +48058,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47416,6 +48205,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47447,9 +48239,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47656,6 +48445,69 @@ 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|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 ""
@@ -48046,12 +48898,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48103,9 +48949,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48247,6 +49090,9 @@ 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 ""
@@ -48512,6 +49358,13 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -48552,6 +49405,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48771,7 +49627,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48819,6 +49675,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48844,6 +49703,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48868,9 +49736,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48991,6 +49865,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49027,6 +49904,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49057,6 +49937,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49460,9 +50343,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49635,12 +50515,18 @@ 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 ""
@@ -49813,6 +50699,9 @@ 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 ""
@@ -49822,7 +50711,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49852,6 +50741,9 @@ 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 ""
@@ -49876,6 +50768,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49921,6 +50816,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49930,9 +50828,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49963,6 +50858,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50124,6 +51022,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50367,6 +51268,9 @@ 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 ""
@@ -50709,9 +51613,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50779,6 +51680,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50809,6 +51713,9 @@ 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 ""
@@ -51096,9 +52003,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51412,10 +52316,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51477,6 +52387,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51492,6 +52480,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51519,12 +52513,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51540,6 +52528,9 @@ 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 ""
@@ -51623,82 +52614,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51761,9 +52698,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51788,6 +52722,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/hi_IN/gitlab.po b/locale/hi_IN/gitlab.po
index a7c0dbed830..f5f39f0c195 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/hr_HR/gitlab.po b/locale/hr_HR/gitlab.po
index 62ae68a1a3b..2b7e9a6bcec 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -496,6 +496,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -538,12 +544,24 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
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] ""
msgstr[2] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -721,6 +739,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -922,6 +943,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -937,9 +961,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1075,6 +1096,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1336,6 +1360,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1627,12 +1654,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1951,9 +1972,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2368,9 +2386,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2392,6 +2407,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2401,6 +2419,9 @@ 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 ""
@@ -2515,6 +2536,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2653,6 +2677,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3832,40 +3859,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4237,6 +4234,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4867,6 +4867,9 @@ 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 ""
@@ -4876,6 +4879,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4954,13 +5074,28 @@ 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|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."
+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."
@@ -5107,12 +5242,18 @@ 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 ""
@@ -5362,6 +5503,12 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5374,6 +5521,18 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+
+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] ""
+msgstr[2] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5449,9 +5608,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5464,6 +5620,9 @@ 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 ""
@@ -5818,7 +5977,7 @@ msgstr[2] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6073,9 +6232,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6088,9 +6244,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6100,9 +6253,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6484,6 +6646,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6511,9 +6676,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6583,6 +6745,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6598,9 +6763,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6736,27 +6898,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6766,9 +6910,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6910,6 +7051,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7135,15 +7279,27 @@ msgstr[2] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7156,9 +7312,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7276,9 +7429,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7297,6 +7447,15 @@ 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 ""
@@ -7327,10 +7486,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7372,6 +7534,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8140,6 +8305,15 @@ 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 ""
@@ -8257,6 +8431,9 @@ 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 ""
@@ -8641,6 +8818,9 @@ 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 ""
@@ -8683,6 +8863,9 @@ 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 ""
@@ -8692,16 +8875,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8728,6 +8908,9 @@ 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 ""
@@ -8746,6 +8929,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8764,6 +8950,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8884,12 +9073,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8968,10 +9163,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9001,6 +9196,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9784,6 +9982,9 @@ 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 ""
@@ -10075,7 +10276,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10468,9 +10669,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10483,6 +10681,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10552,12 +10753,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10666,9 +10876,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10687,9 +10912,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11314,6 +11536,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11356,12 +11581,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11377,6 +11611,9 @@ 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 ""
@@ -11422,7 +11659,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11443,7 +11683,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11515,6 +11755,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11761,7 +12004,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11950,6 +12193,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12199,9 +12445,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12409,6 +12652,9 @@ 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 ""
@@ -12508,7 +12754,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12676,9 +12922,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13591,6 +13834,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13633,6 +13879,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14392,6 +14641,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14494,10 +14746,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14602,6 +14857,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14797,6 +15055,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14953,9 +15214,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15394,6 +15652,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15418,6 +15679,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15436,9 +15700,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15895,6 +16165,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15940,7 +16213,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15958,6 +16231,9 @@ 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 ""
@@ -16252,6 +16528,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16363,6 +16642,9 @@ 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 ""
@@ -16651,6 +16933,9 @@ 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 ""
@@ -16930,6 +17215,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16954,6 +17242,9 @@ 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 ""
@@ -17155,6 +17446,9 @@ 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 ""
@@ -17173,6 +17467,9 @@ 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 ""
@@ -17746,9 +18043,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17872,6 +18166,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18028,9 +18325,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18172,9 +18466,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18988,13 +19279,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19045,6 +19345,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19069,6 +19372,12 @@ 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 ""
@@ -19084,9 +19393,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19135,12 +19441,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19234,12 +19534,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19279,6 +19585,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19291,13 +19600,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19315,7 +19624,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19369,6 +19678,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19441,6 +19753,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19495,15 +19810,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19720,6 +20029,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19909,6 +20242,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20260,6 +20596,9 @@ 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 ""
@@ -20518,6 +20857,9 @@ 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 ""
@@ -20533,6 +20875,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20911,6 +21259,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21256,6 +21607,9 @@ 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 ""
@@ -21355,6 +21709,9 @@ 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 ""
@@ -21397,15 +21754,24 @@ 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 ""
@@ -21466,7 +21832,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21694,6 +22060,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22099,7 +22468,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22762,12 +23131,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22942,10 +23317,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22963,6 +23341,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23251,7 +23632,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23380,9 +23761,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23653,6 +24031,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23878,6 +24262,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24415,9 +24802,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25108,6 +25510,15 @@ 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 ""
@@ -25189,6 +25600,9 @@ 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 ""
@@ -25198,6 +25612,9 @@ 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 ""
@@ -25213,9 +25630,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25231,6 +25645,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25486,6 +25903,12 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Line changes"
msgstr ""
@@ -25513,6 +25936,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25606,9 +26032,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25651,6 +26074,9 @@ 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 ""
@@ -25690,6 +26116,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25708,9 +26137,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25780,9 +26206,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25819,10 +26242,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26314,6 +26734,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26395,12 +26818,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26623,18 +27055,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26707,9 +27130,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26722,6 +27142,27 @@ 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 ""
@@ -27334,6 +27775,9 @@ msgstr[2] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27514,6 +27958,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27526,6 +27976,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27586,31 +28039,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27955,6 +28423,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28003,10 +28474,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28120,9 +28597,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28210,9 +28684,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28567,6 +29038,15 @@ 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 ""
@@ -28651,13 +29131,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28963,12 +29446,24 @@ 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|%{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 ""
@@ -29017,9 +29512,18 @@ 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 ""
@@ -29047,9 +29551,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29086,6 +29587,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29095,6 +29599,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29107,6 +29614,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29584,6 +30094,9 @@ 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 ""
@@ -29653,9 +30166,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29950,28 +30460,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30772,6 +31288,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30961,9 +31480,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31162,6 +31678,9 @@ 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 ""
@@ -31387,6 +31906,9 @@ 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 ""
@@ -31438,9 +31960,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31486,6 +32005,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31537,7 +32062,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31546,6 +32071,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31582,13 +32110,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31618,6 +32146,12 @@ 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 ""
@@ -31639,6 +32173,9 @@ 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 ""
@@ -31648,6 +32185,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31963,6 +32503,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31984,6 +32527,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32044,7 +32590,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32398,6 +32944,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32467,88 +33016,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32557,34 +33049,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32593,24 +33088,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32623,22 +33112,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Instrument your application"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32647,70 +33145,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32878,6 +33379,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33127,7 +33634,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33301,6 +33808,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33313,6 +33823,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33340,6 +33853,9 @@ 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 ""
@@ -33436,9 +33952,21 @@ 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 ""
@@ -33451,6 +33979,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33493,7 +34024,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33508,9 +34042,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33640,9 +34171,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33793,9 +34321,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33838,9 +34363,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33877,9 +34399,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33922,10 +34441,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33949,9 +34468,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34186,6 +34702,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34312,6 +34831,9 @@ 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 ""
@@ -34327,6 +34849,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34507,9 +35032,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34618,12 +35140,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34795,9 +35311,27 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34807,10 +35341,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34819,15 +35365,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34837,6 +35392,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35293,24 +35851,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35386,6 +35935,9 @@ 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] ""
@@ -35422,13 +35974,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35521,6 +36073,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36463,15 +37018,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36652,9 +37213,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36826,9 +37384,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36907,6 +37462,9 @@ 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|Administrator"
msgstr ""
@@ -36970,6 +37528,9 @@ 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 ""
@@ -36988,6 +37549,9 @@ 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 ""
@@ -37045,9 +37609,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37060,6 +37630,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37078,6 +37654,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37105,6 +37684,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37114,6 +37699,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37126,6 +37714,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37168,6 +37759,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37201,6 +37795,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37216,6 +37816,9 @@ 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 ""
@@ -37240,6 +37843,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37255,6 +37861,12 @@ 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 ""
@@ -37327,9 +37939,15 @@ 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 ""
@@ -37363,6 +37981,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37372,6 +37996,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37390,6 +38017,9 @@ msgstr[2] ""
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 runner has not run any jobs."
msgstr ""
@@ -37438,6 +38068,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37492,15 +38125,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37522,6 +38146,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37546,9 +38173,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37678,16 +38302,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37729,9 +38356,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38191,22 +38824,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38335,7 +38971,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38449,6 +39085,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38554,9 +39193,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38647,6 +39295,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38668,6 +39319,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38677,6 +39331,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38743,7 +39400,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38821,6 +39478,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39298,6 +39958,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39400,6 +40063,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39412,6 +40078,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39424,6 +40093,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39526,6 +40198,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39661,6 +40339,9 @@ 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 ""
@@ -39688,7 +40369,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39940,6 +40621,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40105,9 +40789,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40261,15 +40942,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40279,6 +40978,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40288,6 +40990,9 @@ 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 ""
@@ -40321,9 +41026,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40507,12 +41218,18 @@ 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 ""
@@ -40924,9 +41641,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40990,6 +41704,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41239,6 +41956,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41884,16 +42604,22 @@ 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|Sync subscription request."
+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}."
@@ -41902,7 +42628,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41932,9 +42658,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41977,9 +42700,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42130,9 +42850,27 @@ 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 ""
@@ -42541,10 +43279,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42568,9 +43306,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42697,6 +43432,9 @@ 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 ""
@@ -42757,6 +43495,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42799,9 +43540,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42859,6 +43597,9 @@ 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 ""
@@ -43174,7 +43915,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43519,6 +44269,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43708,13 +44461,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44215,6 +44962,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44269,10 +45019,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44725,6 +45472,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45214,6 +45964,9 @@ 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 ""
@@ -45304,9 +46057,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45409,9 +46159,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45457,12 +46204,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45568,6 +46309,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45667,6 +46411,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45724,6 +46471,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45811,6 +46567,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45880,6 +46639,9 @@ 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 ""
@@ -46006,6 +46768,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46177,6 +46942,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46381,6 +47149,9 @@ 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 ""
@@ -46393,6 +47164,9 @@ 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 ""
@@ -46468,6 +47242,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46894,6 +47671,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47005,6 +47785,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47149,6 +47932,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47179,9 +47965,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47386,6 +48169,69 @@ 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|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 ""
@@ -47776,12 +48622,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47833,9 +48673,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47977,6 +48814,9 @@ 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 ""
@@ -48241,6 +49081,12 @@ 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] ""
+msgstr[2] ""
+
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] ""
@@ -48280,6 +49126,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48499,7 +49348,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48547,6 +49396,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48571,6 +49423,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48595,9 +49456,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48718,6 +49585,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48754,6 +49624,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48784,6 +49657,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49186,9 +50062,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49360,12 +50233,18 @@ 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 ""
@@ -49537,6 +50416,9 @@ 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 ""
@@ -49546,7 +50428,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49576,6 +50458,9 @@ 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 ""
@@ -49600,6 +50485,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49645,6 +50533,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49654,9 +50545,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49687,6 +50575,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49846,6 +50737,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50086,6 +50980,9 @@ 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 ""
@@ -50422,9 +51319,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50491,6 +51385,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50521,6 +51418,9 @@ 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 ""
@@ -50803,9 +51703,6 @@ msgstr[2] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51115,10 +52012,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51178,6 +52081,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51193,6 +52174,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51220,12 +52207,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51241,6 +52222,9 @@ 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 ""
@@ -51322,82 +52306,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51460,9 +52390,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51487,6 +52414,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/hu_HU/gitlab.po b/locale/hu_HU/gitlab.po
index 04a25af0a52..ef3f97e859b 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/hy_AM/gitlab.po b/locale/hy_AM/gitlab.po
index b8120a6f2ec..e1720294b08 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po
index 18079243acf..d5a52924236 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -539,6 +553,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -740,6 +757,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -755,9 +775,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -889,6 +906,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1675,9 +1694,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2092,9 +2108,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2116,6 +2129,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2125,6 +2141,9 @@ 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 ""
@@ -2239,6 +2258,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2377,6 +2399,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3556,40 +3581,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3961,6 +3956,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4587,6 +4585,9 @@ 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 ""
@@ -4596,6 +4597,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4674,13 +4792,28 @@ 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|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."
+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."
@@ -4823,12 +4956,18 @@ 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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5080,6 +5223,14 @@ msgstr ""
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ 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 ""
@@ -5518,7 +5669,7 @@ msgstr[0] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5771,9 +5922,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5786,9 +5934,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5798,9 +5943,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6606,6 +6739,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -6846,9 +6994,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -6987,6 +7129,15 @@ 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 ""
@@ -7017,10 +7168,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7062,6 +7216,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7945,6 +8111,9 @@ 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 ""
@@ -8325,6 +8494,9 @@ 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 ""
@@ -8367,6 +8539,9 @@ 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 ""
@@ -8376,16 +8551,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8412,6 +8584,9 @@ 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 ""
@@ -8430,6 +8605,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8568,12 +8749,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,10 +8839,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10161,6 +10351,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10365,9 +10582,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ 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 ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11115,7 +11347,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11187,6 +11419,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11433,7 +11668,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,7 +12418,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13301,6 +13539,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,10 +14388,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15060,6 +15313,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15582,7 +15847,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 ""
@@ -16795,6 +17078,9 @@ 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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17662,9 +17951,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ 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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19121,15 +19430,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19535,6 +19862,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -19886,6 +20216,9 @@ 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 ""
@@ -20144,6 +20477,9 @@ 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 ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -20874,6 +21219,9 @@ 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 ""
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ 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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21308,6 +21668,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22374,12 +22737,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23261,6 +23633,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23486,6 +23864,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ 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 ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ 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 ""
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25372,9 +25790,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 ""
@@ -26918,6 +27351,9 @@ msgstr[0] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27098,6 +27534,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27110,6 +27552,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28533,12 +29008,24 @@ 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|%{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 ""
@@ -28587,9 +29074,18 @@ 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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29152,6 +29654,9 @@ 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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30330,6 +30838,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30720,6 +31228,9 @@ 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 ""
@@ -30945,6 +31456,9 @@ 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 ""
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 ""
@@ -31197,6 +31723,9 @@ 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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,7 +32140,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -32898,6 +33403,9 @@ 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 ""
@@ -32994,9 +33502,21 @@ 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 ""
@@ -33009,6 +33529,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,7 +33574,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33435,9 +33949,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -33870,6 +34381,9 @@ 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 ""
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34176,12 +34690,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34395,6 +34938,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] ""
@@ -34978,13 +35518,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36005,15 +36548,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr ""
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ 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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ 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 ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37042,6 +37654,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37689,22 +38310,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -37833,7 +38457,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -38796,6 +39444,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ 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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 ""
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41622,9 +42330,27 @@ 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 ""
@@ -42029,10 +42755,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42341,6 +43067,9 @@ 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 ""
@@ -42652,7 +43381,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -43747,10 +44485,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44199,6 +44934,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44684,6 +45422,9 @@ 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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -44877,9 +45615,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -44925,12 +45660,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ 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 ""
@@ -45474,6 +46224,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46360,6 +47125,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46643,9 +47417,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -46846,6 +47617,69 @@ 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|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 ""
@@ -47236,12 +48070,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -47955,7 +48790,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ 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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,7 +49862,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49024,6 +49892,9 @@ 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 ""
@@ -49048,6 +49919,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49102,9 +49979,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -49915,6 +50795,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50521,10 +51404,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,82 +51690,28 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ig_NG/gitlab.po b/locale/ig_NG/gitlab.po
index fa241e5bdef..ca9e8b1cffa 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -539,6 +553,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -740,6 +757,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -755,9 +775,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -889,6 +906,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1675,9 +1694,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2092,9 +2108,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2116,6 +2129,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2125,6 +2141,9 @@ 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 ""
@@ -2239,6 +2258,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2377,6 +2399,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3556,40 +3581,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3961,6 +3956,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4587,6 +4585,9 @@ 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 ""
@@ -4596,6 +4597,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4674,13 +4792,28 @@ 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|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."
+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."
@@ -4823,12 +4956,18 @@ 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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5080,6 +5223,14 @@ msgstr ""
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ 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 ""
@@ -5518,7 +5669,7 @@ msgstr[0] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5771,9 +5922,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5786,9 +5934,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5798,9 +5943,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6606,6 +6739,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -6846,9 +6994,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -6987,6 +7129,15 @@ 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 ""
@@ -7017,10 +7168,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7062,6 +7216,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7945,6 +8111,9 @@ 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 ""
@@ -8325,6 +8494,9 @@ 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 ""
@@ -8367,6 +8539,9 @@ 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 ""
@@ -8376,16 +8551,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8412,6 +8584,9 @@ 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 ""
@@ -8430,6 +8605,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8568,12 +8749,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,10 +8839,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10161,6 +10351,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10365,9 +10582,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ 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 ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11115,7 +11347,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11187,6 +11419,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11433,7 +11668,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,7 +12418,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13301,6 +13539,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,10 +14388,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15060,6 +15313,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15582,7 +15847,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 ""
@@ -16795,6 +17078,9 @@ 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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17662,9 +17951,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ 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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19121,15 +19430,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19535,6 +19862,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -19886,6 +20216,9 @@ 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 ""
@@ -20144,6 +20477,9 @@ 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 ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -20874,6 +21219,9 @@ 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 ""
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ 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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21308,6 +21668,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22374,12 +22737,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23261,6 +23633,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23486,6 +23864,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ 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 ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ 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 ""
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25372,9 +25790,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 ""
@@ -26918,6 +27351,9 @@ msgstr[0] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27098,6 +27534,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27110,6 +27552,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28533,12 +29008,24 @@ 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|%{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 ""
@@ -28587,9 +29074,18 @@ 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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29152,6 +29654,9 @@ 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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30330,6 +30838,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30720,6 +31228,9 @@ 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 ""
@@ -30945,6 +31456,9 @@ 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 ""
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 ""
@@ -31197,6 +31723,9 @@ 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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,7 +32140,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -32898,6 +33403,9 @@ 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 ""
@@ -32994,9 +33502,21 @@ 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 ""
@@ -33009,6 +33529,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,7 +33574,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33435,9 +33949,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -33870,6 +34381,9 @@ 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 ""
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34176,12 +34690,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34395,6 +34938,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] ""
@@ -34978,13 +35518,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36005,15 +36548,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr ""
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ 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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ 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 ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37042,6 +37654,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37689,22 +38310,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -37833,7 +38457,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -38796,6 +39444,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ 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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 ""
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41622,9 +42330,27 @@ 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 ""
@@ -42029,10 +42755,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42341,6 +43067,9 @@ 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 ""
@@ -42652,7 +43381,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -43747,10 +44485,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44199,6 +44934,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44684,6 +45422,9 @@ 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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -44877,9 +45615,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -44925,12 +45660,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ 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 ""
@@ -45474,6 +46224,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46360,6 +47125,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46643,9 +47417,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -46846,6 +47617,69 @@ 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|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 ""
@@ -47236,12 +48070,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -47955,7 +48790,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ 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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,7 +49862,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49024,6 +49892,9 @@ 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 ""
@@ -49048,6 +49919,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49102,9 +49979,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -49915,6 +50795,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50521,10 +51404,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,82 +51690,28 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/is_IS/gitlab.po b/locale/is_IS/gitlab.po
index 55f5637fc82..7fc3029feed 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index ba5828bc224..816d62acb6a 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s commit aggiuntivo è stato omesso per evitare degradi di prestazioni negli issues."
msgstr[1] "%s commit aggiuntivi sono stati omessi per evitare degradi di prestazioni negli issues."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 gruppo"
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr "Aggiungi una directory (cartella)"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr "in corso"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
-msgstr "Collaboratori"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr ""
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr "Feb"
msgid "February"
msgstr "Febbraio"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Abbandona il gruppo"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr "Bloccato"
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "Nuovo progetto"
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr "Pipeline"
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ msgstr "Pipeline"
msgid "Pipelines charts"
msgstr "Grafici pipeline"
+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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Devi trasferire la proprietà o eliminare questi gruppi prima che tu possa eliminare l'account."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index f2345062db3..d9adb2ff0af 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr " %{start} ã‹ã‚‰ %{end} ã¾ã§"
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] "%d 件ã®æœªè§£æ±ºã‚¹ãƒ¬ãƒƒãƒ‰"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d 件ã®è„†å¼±æ€§"
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] "%d 件ã®è­¦å‘ŠãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸ:"
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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 ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} 㨠%{openOrClose} %{noteable}"
@@ -539,6 +553,9 @@ msgstr "%{count} 件ã®é–¢é€£ã—㟠%{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "%{count} 件é¸æŠžã—ã¾ã—ãŸ"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "åˆè¨ˆã‚¦ã‚§ã‚¤ãƒˆ %{count}"
@@ -615,7 +632,7 @@ msgid "%{global_id} is not a valid ID for %{expected_types}."
msgstr "%{global_id} 㯠%{expected_types} ã«ã¨ã£ã¦æœ‰åŠ¹ãªIDã§ã¯ã‚ã‚Šã¾ã›ã‚“。"
msgid "%{group_name} activity"
-msgstr "%{group_name} アクティビティー"
+msgstr "%{group_name} アクティビティ"
msgid "%{group_name} group members"
msgstr "%{group_name} グループã®ãƒ¡ãƒ³ãƒãƒ¼"
@@ -740,6 +757,9 @@ msgstr "%{level_name} ã¯è¨±å¯ã•ã‚Œã¾ã›ã‚“。フォークã—ãŸã‚½ãƒ¼ã‚¹ãƒ—ã
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}ã€ãã—ã¦ã•ã‚‰ã« %{awardsListLength} 個。"
@@ -755,9 +775,6 @@ msgstr "%{mergeLength}/%{usersLength} 人ãŒãƒžãƒ¼ã‚¸ã§ãã¾ã™"
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr "%{message}。ã‚ãªãŸã®æ³¨æ„リクエストã¯å‰Šé™¤ã•ã‚Œã¾ã—ãŸã€‚"
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (期é™åˆ‡ã‚Œ)"
@@ -889,6 +906,9 @@ msgstr "%{reportType} ã®æ½œåœ¨çš„㪠%{vulnMessage} ã‚’ %{totalStart}%{total}%{
msgid "%{reportType} detected no new vulnerabilities."
msgstr "種類㌠%{reportType} ã®æ–°ã—ã„脆弱性ã¯ã‚ã‚Šã¾ã›ã‚“。"
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr "%{user} ãŒã‚¨ãƒ”ックを作æˆã—ã¾ã—ãŸ: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} ãŒã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆã—ã¾ã—ãŸ: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} ã¯ãƒªã‚¹ãƒˆã«å«ã¾ã‚Œã¦ã„ã¾ã›ã‚“。"
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] "%d 個ã®ãƒ‡ãƒ—ロイキー"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "%{count} フォロワー"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%dグループ"
@@ -1604,7 +1623,7 @@ msgid "A new personal access token, named %{token_name}, has been created."
msgstr "%{token_name} ã¨ã„ã†åå‰ã®æ–°ã—ã„パーソナルアクセストークンãŒä½œæˆã•ã‚Œã¾ã—ãŸã€‚"
msgid "A non-confidential epic cannot be assigned to a confidential parent epic"
-msgstr "公開エピックã®è¦ªã‚¨ãƒ”ックã«éžå…¬é–‹ã‚¨ãƒ”ックã«å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+msgstr "コンフィデンシャルã§ã¯ãªã„エピックã®è¦ªã‚¨ãƒ”ックã«ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«ã‚¨ãƒ”ックã«å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
msgid "A non-confidential issue cannot have a confidential parent."
msgstr "公開ã•ã‚ŒãŸã‚¤ã‚·ãƒ¥ãƒ¼ã¯ã€éžå…¬é–‹ã®è¦ªã‚’æŒã¤ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
@@ -1675,9 +1694,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "APIファジング"
-msgid "API Fuzzing Configuration"
-msgstr "API Fuzzing ã®è¨­å®š"
-
msgid "API Help"
msgstr "API ヘルプ"
@@ -2027,7 +2043,7 @@ msgid "Active chat names (%{count})"
msgstr "アクティブãªãƒãƒ£ãƒƒãƒˆå (%{count})"
msgid "Activity"
-msgstr "アクティビティー"
+msgstr "アクティビティ"
msgid "Activity|An error occurred while retrieving activity. Reload the page to try again."
msgstr "アクティビティをå–å¾—ã™ã‚‹éš›ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ページをå†èª­ã¿è¾¼ã¿ã—ã¦ã€å†åº¦ãŠè©¦ã—ãã ã•ã„。"
@@ -2092,9 +2108,6 @@ msgstr "ãƒã‚§ãƒƒã‚¯ãƒªã‚¹ãƒˆã‚’追加"
msgid "Add a collapsible section"
msgstr "折りãŸãŸã¿å¯èƒ½ãªã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‚’追加"
-msgid "Add a comment"
-msgstr "コメントを追加"
-
msgid "Add a comment to this line"
msgstr "ã“ã®è¡Œã«ã‚³ãƒ¡ãƒ³ãƒˆã‚’追加"
@@ -2116,6 +2129,9 @@ msgstr "ã‚ãªãŸã® Wiki ã«ãƒ—ロジェクトã«é–¢ã™ã‚‹æƒ…報をå«ã‚€ãƒ›ãƒ¼
msgid "Add a new issue"
msgstr "æ–°ã—ã„イシューを作æˆã™ã‚‹"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "番å·ä»˜ãリストを追加"
@@ -2125,6 +2141,9 @@ 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 "サービスデスクã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã«ã‚µãƒ•ã‚£ãƒƒã‚¯ã‚¹ã‚’追加ã—ã¾ã™ã€‚ %{linkStart}詳細ã¯ã“ã¡ã‚‰ã€‚%{linkEnd}"
@@ -2204,7 +2223,7 @@ msgid "Add environment"
msgstr "環境ã®è¿½åŠ "
msgid "Add existing confidential %{issuableType}"
-msgstr "既存ã®éžå…¬é–‹ %{issuableType} を追加"
+msgstr "既存ã®ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ« %{issuableType} を追加"
msgid "Add existing issue"
msgstr "既存ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’追加"
@@ -2239,6 +2258,9 @@ msgstr "æ–°ã—ã„アプリケーションを追加"
msgid "Add new directory"
msgstr "æ–°è¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’追加"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr "ユーザーを追加ã¾ãŸã¯å‰Šé™¤ã—ã¾ã™ã€‚"
@@ -2377,6 +2399,9 @@ msgstr "追加時間(分):"
msgid "Additional text"
msgstr "追加テキスト"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr "サインインã¨ãƒ˜ãƒ«ãƒ—ページã®è¿½åŠ ãƒ†ã‚­ã‚¹ãƒˆã§ã™ã€‚"
@@ -3556,40 +3581,10 @@ 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 "エクスãƒãƒ¼ãƒˆãŒå®Œäº†ã—ãŸã‚‰ã€é€šçŸ¥ãƒ¡ãƒ¼ãƒ«ã¾ãŸã¯ã“ã®ãƒšãƒ¼ã‚¸ã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ダウンロードã—ã¾ã™ã€‚ ãã®å¾Œã€åˆ¥ã® GitLab インスタンス㮠%{strong_text_start}æ–°ã—ã„グループã®ä½œæˆ%{strong_text_end} ページã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ ファイルをインãƒãƒ¼ãƒˆã§ãã¾ã™ã€‚"
-msgid "After you've reviewed these contribution guidelines, you'll be all set to"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3608,7 +3603,7 @@ msgid "AlertManagement|Acknowledged"
msgstr "確èªæ¸ˆã¿"
msgid "AlertManagement|Activity feed"
-msgstr ""
+msgstr "アクティビティフィード"
msgid "AlertManagement|Alert"
msgstr "アラート"
@@ -3961,6 +3956,9 @@ msgstr ""
msgid "All Members"
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 "ã™ã¹ã¦ã®ãƒ–ランãƒ"
@@ -4460,7 +4458,7 @@ msgid "An error occurred while reordering issues."
msgstr "イシューã®ä¸¦ã¹æ›¿ãˆä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "An error occurred while retrieving calendar activity"
-msgstr "カレンダーアクティビティーå–å¾—ã®éš›ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+msgstr "カレンダーアクティビティå–å¾—ã®éš›ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
msgid "An error occurred while retrieving diff"
msgstr "差分をå–å¾—ã®éš›ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -4587,6 +4585,9 @@ msgstr "Web ターミナルã®èµ·å‹•ä¸­ã«äºˆæœŸã—ãªã„エラーãŒç™ºç”Ÿã—ã
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Web ターミナルã®åœæ­¢ä¸­ã«äºˆæœŸã—ãªã„エラーãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr ""
@@ -4596,6 +4597,123 @@ msgstr ""
msgid "Analytics"
msgstr "分æž"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "ä¾å­˜é–¢ä¿‚ã«å«ã¾ã‚Œã¦ã„る既知ã®è„†å¼±æ€§ã‚’分æžã—ã¾ã™ã€‚"
@@ -4674,13 +4792,28 @@ msgstr "コメントを %{shrug} ã«è¿½åŠ "
msgid "Append the comment with %{tableflip}"
msgstr "コメントを%{tableflip} ã«è¿½åŠ ã—ã¾ã—ãŸ"
+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|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."
+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."
@@ -4823,12 +4956,18 @@ 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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr "マージリクエストを承èªã™ã‚‹"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5080,6 +5223,14 @@ msgstr "承èªæ¸ˆã¿"
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr "ç¾åœ¨ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯æ‰¿èªæ¸ˆã§ã™ã€‚"
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ msgstr "ã“ã®ãƒ–ロックã•ã‚Œã¦ã„るイシューをクローズã—ã¦ã‚‚よ
msgid "Are you sure you want to delete %{name}?"
msgstr "%{name} を削除ã—ã¾ã™ã‹ï¼Ÿ"
+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 ""
@@ -5518,7 +5669,7 @@ msgstr[0] "%d 個ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’添付"
msgid "Attaching the file failed."
msgstr "ファイルã®æ·»ä»˜ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5619,7 +5770,7 @@ msgid "AuditStreams|An error occurred when updating external audit event stream
msgstr ""
msgid "AuditStreams|Cancel editing"
-msgstr ""
+msgstr "編集をキャンセル"
msgid "AuditStreams|Custom HTTP headers (optional)"
msgstr ""
@@ -5676,7 +5827,7 @@ msgid "AuditStreams|Streams"
msgstr ""
msgid "AuditStreams|This could include sensitive information. Make sure you trust the destination endpoint."
-msgstr ""
+msgstr "機密情報ãŒå«ã¾ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚宛先ã®ã‚¨ãƒ³ãƒ‰ãƒã‚¤ãƒ³ãƒˆã‚’ä¿¡é ¼ã—ã¦ãã ã•ã„。"
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
@@ -5771,9 +5922,6 @@ msgstr "%{author}ã«ã‚ˆã£ã¦ %{timeago} ã«ä½œæˆã•ã‚Œã¾ã—ãŸ"
msgid "Authorization code:"
msgstr "èªè¨¼ã‚³ãƒ¼ãƒ‰:"
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5786,9 +5934,6 @@ msgstr "承èªã™ã‚‹"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã« %{link_to_client} を承èªã—ã¾ã™ã‹ï¼Ÿ"
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr "%{new_chat_name} ãŒæ‰¿èªã•ã‚Œã¾ã—ãŸ"
@@ -5798,9 +5943,18 @@ msgstr "èªè¨¼æ—¥æ™‚"
msgid "Authorized applications (%{size})"
msgstr "承èªã•ã‚ŒãŸã‚¢ãƒ—リケーション(%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr "ã”注æ„ãã ã•ã„。プロジェクトã®åå‰ç©ºé–“を変更ã™ã‚‹
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "ã”注æ„ãã ã•ã„。プロジェクトã®ãƒªãƒã‚¸ãƒˆãƒªã®åå‰ã‚’変更ã™ã‚‹ã¨ã€æ„図ã—ãªã„副作用ãŒç™ºç”Ÿã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6198,7 +6355,7 @@ msgid "Before this can be merged, a Jira issue must be linked in the title or de
msgstr ""
msgid "Begin with the selected commit"
-msgstr "é¸æŠžã—ãŸã‚³ãƒŸãƒƒãƒˆã§ã¯ã˜ã‚ã‚‹"
+msgstr "é¸æŠžã—ãŸã‚³ãƒŸãƒƒãƒˆã‹ã‚‰é–‹å§‹"
msgid "Below are the fingerprints for the current instance SSH host keys."
msgstr "以下ã¯ç¾åœ¨ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®SSHホストキーã®ãƒ•ã‚£ãƒ³ã‚¬ãƒ¼ãƒ—リントã§ã™ã€‚"
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr "以下ã«å…¬é–‹ã•ã‚Œã¦ã„る全グループを表示ã—ã¾ã™ã€‚"
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr "プランをダウングレードを希望ã™ã‚‹å ´åˆã€ %{support_link
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr "アップグレード"
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6549,7 +6682,7 @@ msgid "Billing|Export list"
msgstr ""
msgid "Billing|Group invite"
-msgstr ""
+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"
@@ -6606,6 +6739,9 @@ msgstr "Bitbucket インãƒãƒ¼ãƒˆ"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -6846,9 +6994,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -6987,6 +7129,15 @@ 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 ""
@@ -7017,10 +7168,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7062,6 +7216,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7883,7 +8049,7 @@ msgid "Cancel"
msgstr "キャンセル"
msgid "Cancel and close"
-msgstr ""
+msgstr "キャンセルã—ã¦é–‰ã˜ã‚‹"
msgid "Cancel downstream pipeline"
msgstr ""
@@ -7901,7 +8067,7 @@ msgid "Cancel this job"
msgstr "ã“ã®ã‚¸ãƒ§ãƒ–をキャンセルã™ã‚‹"
msgid "Cancel your account"
-msgstr ""
+msgstr "アカウントをキャンセル"
msgid "Cancel, keep project"
msgstr ""
@@ -7916,7 +8082,7 @@ msgid "Cancelling Preview"
msgstr "プレビューをキャンセル"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
-msgstr ""
+msgstr "コンフィデンシャル扱ã„ã§ãªã„イシューã«ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«æ‰±ã„ã®ã‚¨ãƒ”ックを割り当ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。イシューをコンフィデンシャル扱ã„ã«ã—ã¦ã€ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
msgid "Cannot be merged automatically"
msgstr "自動的ã«ãƒžãƒ¼ã‚¸ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
@@ -7945,11 +8111,14 @@ 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 "公開ã•ã‚Œã¦ã„ã‚‹å­ã‚¨ãƒ”ックãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã€ã“ã®ã‚¨ãƒ”ックをéžå…¬é–‹ã«ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+msgstr "コンフィデンシャルã§ã¯ãªã„å­ã‚¨ãƒ”ックãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã€ã“ã®ã‚¨ãƒ”ックをコンフィデンシャルã«ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
msgid "Cannot make the epic confidential if it contains non-confidential issues"
-msgstr "公開ã•ã‚Œã¦ã„るイシューãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã€ã‚¨ãƒ”ックをéžå…¬é–‹ã«ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+msgstr "コンフィデンシャルã§ã¯ãªã„イシューãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã€ã‚¨ãƒ”ックをコンフィデンシャルã«ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
msgid "Cannot merge"
msgstr "マージã§ãã¾ã›ã‚“"
@@ -8325,6 +8494,9 @@ msgstr "(x%{numberOfUsers})"
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 ""
@@ -8367,6 +8539,9 @@ 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 "æ–°ã—ã„グループを作æˆ"
@@ -8376,18 +8551,15 @@ msgstr "クレジットカードã®ãƒ•ã‚©ãƒ¼ãƒ èª­ã¿è¾¼ã¿å¤±æ•—ã—ã¾ã—ãŸã€‚
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "クレジットカードã®ãƒ•ã‚©ãƒ¼ãƒ èª­ã¿è¾¼ã¿å¤±æ•—ã—ã¾ã—ãŸã€‚: %{message}"
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "編集"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr "有効期é™: %{expirationMonth}/%{expirationYear}"
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "注文ã®ç¢ºèªã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "注文ã®ç¢ºèªã«å¤±æ•—ã—ã¾ã—ãŸã€‚: %{message} ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "国情報ã®èª­ã¿è¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -8412,6 +8584,9 @@ msgstr "GitLabプラン"
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 ""
@@ -8430,6 +8605,9 @@ msgstr "åå‰: %{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "ã‚‚ã£ã¨å¤šãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒå¿…è¦ã§ã™ã‹ï¼Ÿ %{company} ã¯GitLabを購入ã—ã¾ã™ã‹?"
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "ユーザー数"
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "都é“府県ã¾ãŸã¯å·ž"
@@ -8568,12 +8749,18 @@ 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 "CI/CD パイプラインを実行ã—ãŸã„リãƒã‚¸ãƒˆãƒªã‚’é¸æŠžã—ã¦ãã ã•ã„。"
msgid "Choose your framework"
msgstr "フレームワークをé¸æŠž"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,12 +8839,12 @@ msgstr "å¾…ã¡"
msgid "CiStatus|running"
msgstr "実行中"
+msgid "CiVariables|Cancel"
+msgstr ""
+
msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr "ç¾åœ¨ã®å€¤ã§ã¯ãƒžã‚¹ã‚¯ã•ã‚ŒãŸå¤‰æ•°ã‚’使用ã§ãã¾ã›ã‚“"
-msgid "CiVariables|Clear inputs"
-msgstr ""
-
msgid "CiVariables|Environments"
msgstr ""
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9206,7 +9396,7 @@ 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 ""
+msgstr "クラスターエージェント|アクティビティã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ページをリロードã—ã¦å†è©¦è¡Œã—ã¦ãã ã•ã„。"
msgid "ClusterAgents|An unknown error occurred. Please try again."
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr "クラスターã®èªè¨¼ã«ä½¿ç”¨ã•ã‚Œã‚‹Kubernetes証明書。"
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "Kubernetes APIã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã«ä½¿ç”¨ã•ã‚Œã‚‹URL。"
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "リビジョンを比較"
-
msgid "Compare branches and continue"
msgstr ""
@@ -10161,6 +10351,9 @@ msgstr "最後ã®ã‚³ãƒŸãƒƒãƒˆã¨å¤‰æ›´ã‚’比較"
msgid "Compare changes with the merge request target branch"
msgstr "マージリクエストã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒ–ランãƒã¨ã®å¤‰æ›´ã‚’比較ã™ã‚‹"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr "コンプライアンスフレームワーク"
msgid "Compliance report"
msgstr "コンプライアンスレãƒãƒ¼ãƒˆ"
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "フレームワークを追加"
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10354,7 +10571,7 @@ msgid "Confidence"
msgstr ""
msgid "Confidential"
-msgstr "éžå…¬é–‹"
+msgstr "コンフィデンシャル"
msgid "Confidential issue"
msgstr "éžå…¬é–‹ã®ã‚¤ã‚·ãƒ¥ãƒ¼"
@@ -10363,10 +10580,7 @@ msgid "Confidential note"
msgstr ""
msgid "Confidentiality"
-msgstr "機密性"
-
-msgid "Configuration"
-msgstr "設定"
+msgstr "コンフィデンシャル"
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr "ã‚ãªãŸã¯ %{title} リãƒã‚¸ãƒˆãƒªã‚’削除ã—よã†ã¨ã—ã¦ã„ã¾ã
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "次ã®ã‚³ãƒžãƒ³ãƒ‰ã‚’使用ã—ã¦ã€ã“ã®ãƒ¬ã‚¸ã‚¹ãƒˆãƒªã«ã‚¤ãƒ¡ãƒ¼ã‚¸ã‚’追加ã§ãã¾ã™ï¼š"
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr "貢献度"
msgid "Contribution Analytics"
msgstr "貢献度分æž"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ msgstr ""
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr "%{start_date} 以é™ã®ã€ã‚¤ã‚·ãƒ¥ãƒ¼ã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã€ プッシュã«ã¤ã„ã¦ã®è²¢çŒ®åº¦åˆ†æž"
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr ""
+
msgid "ContributionAnalytics|Failed to load the contribution stats"
msgstr ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11113,10 +11345,10 @@ msgid "Contributions per group member"
msgstr "グループメンãƒãƒ¼ã®è²¢çŒ®åº¦"
msgid "Contributor"
-msgstr ""
+msgstr "コントリビュータ"
-msgid "Contributors"
-msgstr "貢献者"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "アカウントã«ç´ã¥ãメールã®ç®¡ç†"
@@ -11187,6 +11419,9 @@ msgstr "コピーコマンド"
msgid "Copy commit SHA"
msgstr "コミットã®SHAをコピー"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr "環境をコピー"
@@ -11433,7 +11668,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11461,7 +11696,7 @@ msgid "Create %{type}"
msgstr ""
msgid "Create %{workspace} label"
-msgstr ""
+msgstr "%{workspace} ラベルを作æˆ"
msgid "Create New Directory"
msgstr "æ–°è¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’作æˆ"
@@ -11533,10 +11768,10 @@ msgid "Create common files more quickly, and standardize their format."
msgstr ""
msgid "Create confidential merge request"
-msgstr "機密性ã®ã‚るマージリクエストを作æˆã™ã‚‹"
+msgstr "コンフィデンシャルマージリクエストを作æˆã™ã‚‹"
msgid "Create confidential merge request and branch"
-msgstr "機密性ã®ã‚るマージリクエストã¨ãƒ–ランãƒã‚’作æˆã™ã‚‹"
+msgstr "コンフィデンシャルマージリクエストã¨ãƒ–ランãƒã‚’作æˆã™ã‚‹"
msgid "Create custom type"
msgstr "カスタムタイプã®ä½œæˆ"
@@ -11554,7 +11789,7 @@ msgid "Create file"
msgstr "ファイルを作æˆ"
msgid "Create from"
-msgstr ""
+msgstr "作æˆå…ƒ"
msgid "Create group"
msgstr "グループを作æˆ"
@@ -11569,7 +11804,7 @@ msgid "Create issue to resolve all threads"
msgstr "ã™ã¹ã¦ã®ã‚¹ãƒ¬ãƒƒãƒ‰ã‚’解決ã™ã‚‹ãŸã‚ã«ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆ"
msgid "Create label"
-msgstr ""
+msgstr "ラベルを作æˆ"
msgid "Create list"
msgstr "リストを作æˆ"
@@ -11599,7 +11834,7 @@ msgid "Create new branch"
msgstr "æ–°ã—ã„ブランãƒã‚’作æˆ"
msgid "Create new confidential %{issuableType}"
-msgstr "æ–°è¦ã®éžå…¬é–‹ %{issuableType} を作æˆ"
+msgstr "æ–°è¦ã®ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«%{issuableType} を作æˆ"
msgid "Create new directory"
msgstr "æ–°ã—ã„ディレクトリを作æˆ"
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr "イシューを作æˆã¾ãŸã¯é–‰ã˜ã¾ã™ã€‚"
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr "作æˆæ—¥æ™‚"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "ブランãƒã‚’作æˆã—マージリクエストを作æˆã—ã¾ã—ãŸã€‚ã“ã‚Œã§ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’解決ã§ãã¾ã™ã€‚"
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "'%{branch_name}' ブランãƒã‚’作æˆã—マージリクエストを作æˆã—ã¾ã—ãŸã€‚ã“ã‚Œã§ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’解決ã§ãã¾ã™ã€‚"
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,8 +12418,8 @@ msgstr "ボードã«æœ€åˆã«åŠ ãˆã‚‰ã‚ŒãŸã‚¤ã‚·ãƒ¥ãƒ¼"
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "マイルストーンã«æœ€åˆã«é–¢é€£ä»˜ã‘られãŸã‚¤ã‚·ãƒ¥ãƒ¼"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
-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 "コミットã§æœ€åˆã«è¨€åŠã•ã‚ŒãŸã‚¤ã‚·ãƒ¥ãƒ¼"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr "DAGã®å¯è¦–化ã«ã¯ã€å°‘ãªãã¨ã‚‚3ã¤ã®ä¾å­˜æ€§ã®ã‚るジョブãŒå¿…è¦ã§ã™ã€‚"
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13301,6 +13539,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr "æˆåŠŸ"
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,12 +14388,15 @@ msgstr "æ–°ã—ã„コメントを追加ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "æ–°ã—ã„ディスカッションを作æˆã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-msgid "DesignManagement|Could not update discussion. Please try again."
-msgstr "ディスカッションを更新ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
+msgid "DesignManagement|Could not delete comment. Please try again."
+msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
msgstr ""
+msgid "DesignManagement|Could not update discussion. Please try again."
+msgstr "ディスカッションを更新ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
+
msgid "DesignManagement|Deselect all"
msgstr "å…¨ã¦é¸æŠžã‚’解除"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr "Discord 通知"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr "GitLab Geo ã«ã¤ã„ã¦"
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr "説明を編集"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "環境を編集"
@@ -15060,6 +15313,9 @@ msgstr "%{user_name} ã® ID を編集ã™ã‚‹"
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr "マージリクエストを編集"
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "公開デプロイキーã®ç·¨é›†"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15406,7 +15668,7 @@ 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 ""
+msgstr "クライアントシークレットを安全ã«ä¿å­˜ã§ãã‚‹ä¿¡é ¼ã§ãã‚‹ãƒãƒƒã‚¯ã‚¨ãƒ³ãƒ‰ã‚µãƒ¼ãƒã§ä½¿ç”¨ã•ã‚Œã‚‹æ©Ÿå¯†ã‚¢ãƒ—リケーションã®ã¿ã‚’有効ã«ã—ã¾ã™ã€‚ クライアントã®æ©Ÿå¯†æƒ…報を守るã“ã¨ãŒã§ããªã„ãŸã‚ã€ãƒã‚¤ãƒ†ã‚£ãƒ–モãƒã‚¤ãƒ«ã€ã‚·ãƒ³ã‚°ãƒ«ãƒšãƒ¼ã‚¸ã€ã¾ãŸã¯ãã®ä»–ã® JavaScript アプリケーションã§ã¯æœ‰åŠ¹ã«ã—ãªã„ã§ãã ã•ã„。"
msgid "Enable or disable version check and Service Ping."
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr "管ç†è€…モードã«ã—ã¾ã™"
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "数値ã®å…¥åŠ›"
@@ -15582,8 +15847,8 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
-msgstr "モãƒã‚¤ãƒ«ç«¯æœ«ã®2è¦ç´ èªè¨¼ã‚¢ãƒ—リã‹ã‚‰ã‚³ãƒ¼ãƒ‰ã‚’入力ã—ã¾ã™ã€‚デãƒã‚¤ã‚¹ã‚’紛失ã—ãŸå ´åˆã¯ã€ãƒªã‚«ãƒãƒªãƒ¼ã‚³ãƒ¼ãƒ‰ã®ã„ãšã‚Œã‹ã‚’入力ã—ã¦ãã ã•ã„。"
+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 ""
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "エピックãŒã‚ã‚Šã¾ã›ã‚“。"
@@ -15973,7 +16244,7 @@ msgid "Epics|The color for the epic when it's visualized, such as on roadmap tim
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 "ã“ã®ã‚¨ãƒ”ックã¨ã“ã‚Œå«ã¾ã‚Œã¦ã„ã‚‹å­ã‚¨ãƒ”ックã¯éžå…¬é–‹ã§ã‚ã‚Šã€å°‘ãªãã¨ã‚‚Reporterアクセス権é™ã®ã‚ã‚‹ãƒãƒ¼ãƒ ãƒ¡ãƒ³ãƒãƒ¼ã«ã®ã¿è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
+msgstr "ã“ã®ã‚¨ãƒ”ックã¨ã“ã‚Œå«ã¾ã‚Œã¦ã„ã‚‹å­ã‚¨ãƒ”ックã¯ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«ã§ã‚ã‚Šã€å°‘ãªãã¨ã‚‚Reporterアクセス権é™ã®ã‚ã‚‹ãƒãƒ¼ãƒ ãƒ¡ãƒ³ãƒãƒ¼ã«ã®ã¿è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
msgid "Epics|This will also remove any descendents of %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}. Are you sure?"
msgstr "%{bStart}%{parentEpicTitle}%{bEnd} ã‹ã‚‰ %{bStart}%{targetEpicTitle}%{bEnd} 以下ã®å…¨ã¦ã®èª²é¡Œã‚’削除ã—ã¾ã™ã€‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr "エビデンス一覧"
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 "マージコミットを除外ã—ã¦ã„ã¾ã™ã€‚%{limit} 件ã®ã‚³ãƒŸãƒƒãƒˆã«åˆ¶é™ã•ã‚Œã¦ã„ã¾ã™ã€‚"
@@ -16604,7 +16887,7 @@ msgid "Execution time"
msgstr ""
msgid "Existing branch name, tag, or commit SHA"
-msgstr ""
+msgstr "既存ã®ãƒ–ランãƒåã€ã‚¿ã‚°ã€ã¾ãŸã¯ã‚³ãƒŸãƒƒãƒˆSHA"
msgid "Existing projects may be moved into a group"
msgstr ""
@@ -16795,6 +17078,9 @@ msgstr "ラベルãŒåˆ†é¡žã•ã‚Œã¦ã„ãªã„ã¨ãã¯ã€`%{default_label}` ãŒæ—
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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr "2月"
msgid "February"
msgstr "2月"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr "マージリクエストã®ãƒ•ã‚£ãƒ¼ãƒãƒ£ãƒ¼ãƒ–ランãƒã‚’å–å¾—ã—ã¦ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆã—ã¦ãã ã•ã„:"
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17660,10 +17949,7 @@ msgid "For each job, re-use the project workspace. If the workspace doesn't exis
msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
+msgstr "ãŸã¨ãˆã°ã€ãƒˆãƒ¼ã‚¯ãƒ³ã‚„トークンã®ç›®çš„を使用ã™ã‚‹ã‚¢ãƒ—リケーションã§ã™ã€‚ ã™ã¹ã¦ã® %{resource_type} メンãƒãƒ¼ã«è¡¨ç¤ºã•ã‚Œã‚‹ãŸã‚ã€ãƒˆãƒ¼ã‚¯ãƒ³ã®åå‰ã«æ©Ÿå¯†æƒ…報を与ãˆãªã„ã§ãã ã•ã„。"
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17714,7 +18000,7 @@ msgid "ForkProject|An error occurred while forking the project. Please try again
msgstr ""
msgid "ForkProject|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "ForkProject|Create a group"
msgstr ""
@@ -17762,7 +18048,7 @@ msgid "ForkProject|Want to organize several dependent projects under the same na
msgstr ""
msgid "ForkSuggestion|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "ForkSuggestion|Fork"
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr "フォーマット:%{dateFormat}"
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ msgstr ""
msgid "GitLab commit"
msgstr "GitLab ã®ã‚³ãƒŸãƒƒãƒˆ"
+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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr "未確èª"
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr "Gitea ホスト㮠URL"
msgid "Gitea Import"
msgstr "Gitea インãƒãƒ¼ãƒˆ"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr "%{time_ago} ã«ã‚¢ã‚¯ã‚»ã‚¹è¨±å¯"
msgid "Given epic is already related to this epic."
msgstr "指定ã•ã‚ŒãŸã‚¨ãƒ”ックã¯ã™ã§ã«ã“ã®ã‚¨ãƒ”ックã¨é–¢é€£ã—ã¦ã„ã¾ã™ã€‚"
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr "最近ã®ã‚¤ã‚·ãƒ¥ãƒ¼"
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19121,15 +19430,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19257,7 +19560,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 ""
@@ -19311,7 +19614,7 @@ msgid "Google Cloud authorizations required"
msgstr ""
msgid "GoogleCloud|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "GoogleCloud|Configured region is linked to the selected branch or tag"
msgstr ""
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 "了解"
@@ -19535,6 +19862,9 @@ msgstr "グループå (ã‚ãªãŸã®çµ„ç¹”)"
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr "グループ概è¦ã‚³ãƒ³ãƒ†ãƒ³ãƒ„"
@@ -19587,7 +19917,7 @@ msgid "GroupActivityMetrics|Merge requests created"
msgstr ""
msgid "GroupActivityMetrics|Recent activity"
-msgstr "最近ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティー"
+msgstr "最近ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティ"
msgid "GroupImport|Failed to import group: %{error}"
msgstr ""
@@ -19886,6 +20216,9 @@ msgstr "グループã®URLを変更ã™ã‚‹ã¨ã€æ„図ã—ãªã„副作用ãŒç™ºç”Ÿ
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 "コンプライアンスフレームワーク"
@@ -20144,6 +20477,9 @@ 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 ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20435,7 +20777,7 @@ msgid "Header message"
msgstr "ヘッダーメッセージ"
msgid "HeaderAction|incident"
-msgstr ""
+msgstr "インシデント"
msgid "HeaderAction|issue"
msgstr "イシュー"
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "よã†ã“ã%{username}!"
@@ -20874,6 +21219,9 @@ 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 ""
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ msgstr "ãƒã‚§ãƒƒã‚¯ã™ã‚‹ã¨ã€ã‚°ãƒ«ãƒ¼ãƒ—オーナー㯠LDAP グループリ
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "ãƒã‚§ãƒƒã‚¯ã—ãŸå ´åˆã€æ–°ã—ã„グループメンãƒãƒ¼ã‚·ãƒƒãƒ—ã¨ãƒ‘ーミッションをLDAPåŒæœŸã‚’使用ã—ãŸå ´åˆã ã‘追加ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚"
+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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21255,22 +21615,22 @@ msgid "ImportAProjectModal|Import from a project"
msgstr "プロジェクトã‹ã‚‰ã‚¤ãƒ³ãƒãƒ¼ãƒˆ"
msgid "ImportAProjectModal|Import members from another project"
-msgstr ""
+msgstr "ä»–ã®ãƒ—ロジェクトã‹ã‚‰ãƒ¡ãƒ³ãƒãƒ¼ã‚’インãƒãƒ¼ãƒˆ"
msgid "ImportAProjectModal|Import project members"
-msgstr ""
+msgstr "プロジェクトメンãƒãƒ¼ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ"
msgid "ImportAProjectModal|Only project members (not group members) are imported, and they get the same permissions as the project you import from."
-msgstr ""
+msgstr "グループã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã¯ãªãã€ãƒ—ロジェクトã®ãƒ¡ãƒ³ãƒãƒ¼ã®ã¿ã‚’インãƒãƒ¼ãƒˆã—ã¾ã™ã€‚新メンãƒãƒ¼ã¯ã‚¤ãƒ³ãƒãƒ¼ãƒˆã—ãŸãƒ—ロジェクトã¨åŒã˜æ¨©é™ã‚’æŒã¡ã¾ã™ã€‚"
msgid "ImportAProjectModal|Successfully imported"
msgstr ""
msgid "ImportAProjectModal|Unable to import project members"
-msgstr ""
+msgstr "プロジェクトメンãƒãƒ¼ã‚’インãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“"
msgid "ImportAProjectModal|You're importing members to the %{strongStart}%{name}%{strongEnd} project."
-msgstr ""
+msgstr "%{strongStart}%{name}%{strongEnd} プロジェクトã«ãƒ¡ãƒ³ãƒãƒ¼ã‚’インãƒãƒ¼ãƒˆã—ã¾ã™ã€‚"
msgid "ImportButtons|Connect repositories from"
msgstr "リãƒã‚¸ãƒˆãƒªã¸æŽ¥ç¶š"
@@ -21308,6 +21668,9 @@ msgstr "プロジェクトã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã«å¤±æ•—ã—ã¾ã—ãŸ"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21358,7 +21721,7 @@ 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 ""
+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 ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -21994,10 +22357,10 @@ msgid "IncidentManagement|High - S2"
msgstr ""
msgid "IncidentManagement|Incident"
-msgstr ""
+msgstr "インシデント"
msgid "IncidentManagement|Incidents"
-msgstr ""
+msgstr "インシデント"
msgid "IncidentManagement|Learn more about incident statuses"
msgstr ""
@@ -22078,10 +22441,10 @@ msgid "IncidentSettings|Grafana integration"
msgstr ""
msgid "IncidentSettings|Incident settings"
-msgstr ""
+msgstr "インシデント設定"
msgid "IncidentSettings|Incidents"
-msgstr ""
+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 ""
@@ -22374,12 +22737,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "候補を挿入ã™ã‚‹"
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr "リãƒã‚¸ãƒˆãƒªãƒ‘スãŒç„¡åŠ¹ã§ã™"
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22901,7 +23276,7 @@ msgid "Invite \"%{email}\" by email"
msgstr "メール㧠\"%{email}\" を招待"
msgid "Invite Members"
-msgstr ""
+msgstr "メンãƒãƒ¼ã‚’招待"
msgid "Invite a group"
msgstr "グループを招待"
@@ -22922,7 +23297,7 @@ msgid "InviteEmail|Groups assemble related projects together and grant members a
msgstr ""
msgid "InviteEmail|Join now"
-msgstr ""
+msgstr "今ã™ãå‚加ã™ã‚‹"
msgid "InviteEmail|Join your team on GitLab! %{inviter} invited you to %{project_or_group_name}"
msgstr ""
@@ -22964,16 +23339,16 @@ msgid "InviteMembersModal| To get more members, the owner of this top-level grou
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
-msgstr ""
+msgstr "ロール権é™ã®è©³ç´°ã«ã¤ã„ã¦ã¯%{linkStart}ã“ã¡ã‚‰ã‚’ã”確èªãã ã•ã„%{linkEnd}"
msgid "InviteMembersModal|Access expiration date (optional)"
-msgstr ""
+msgstr "アクセスã®æœ‰åŠ¹æœŸé™ï¼ˆã‚ªãƒ—ション)"
msgid "InviteMembersModal|Add unlimited members with your trial"
msgstr ""
msgid "InviteMembersModal|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "InviteMembersModal|Choose a project for the issues"
msgstr "イシューã®ãƒ—ロジェクトをé¸æŠž"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23003,16 +23375,16 @@ msgid "InviteMembersModal|How about inviting a colleague or two to join you?"
msgstr ""
msgid "InviteMembersModal|Invite"
-msgstr ""
+msgstr "招待"
msgid "InviteMembersModal|Invite a group"
-msgstr ""
+msgstr "グループを招待"
msgid "InviteMembersModal|Invite members"
-msgstr ""
+msgstr "メンãƒãƒ¼ã‚’招待"
msgid "InviteMembersModal|Manage members"
-msgstr ""
+msgstr "メンãƒãƒ¼ã‚’管ç†"
msgid "InviteMembersModal|Members were successfully added"
msgstr "メンãƒãƒ¼ã®è¿½åŠ ã«æˆåŠŸã—ã¾ã—ãŸ"
@@ -23024,10 +23396,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 ""
@@ -23067,10 +23439,10 @@ msgid "InviteMembersModal|You're inviting a group to the %{strongStart}%{name}%{
msgstr "グループを %{strongStart}%{name}%{strongEnd} グループã«æ‹›å¾…ã—ã¦ã„ã¾ã™ã€‚"
msgid "InviteMembersModal|You're inviting a group to the %{strongStart}%{name}%{strongEnd} project."
-msgstr ""
+msgstr "グループを%{strongStart}%{name}%{strongEnd} プロジェクトã«æ‹›å¾…ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚"
msgid "InviteMembersModal|You're inviting members to the %{strongStart}%{name}%{strongEnd} group."
-msgstr ""
+msgstr "%{strongStart}%{name}%{strongEnd} グループã«ãƒ¡ãƒ³ãƒãƒ¼ã‚’招待ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚"
msgid "InviteMembersModal|You're inviting members to the %{strongStart}%{name}%{strongEnd} project."
msgstr ""
@@ -23082,7 +23454,7 @@ msgid "InviteMembersModal|Your top-level group %{namespaceName} is over the %{da
msgstr ""
msgid "InviteMembers|Invite a group"
-msgstr ""
+msgstr "グループを招待"
msgid "InviteMembers|Invite team members"
msgstr ""
@@ -23097,10 +23469,10 @@ msgid "InviteMember|Invite another member"
msgstr ""
msgid "InviteMember|Invite members"
-msgstr ""
+msgstr "メンãƒãƒ¼ã‚’招待"
msgid "InviteMember|Invite your team"
-msgstr ""
+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 ""
@@ -23118,13 +23490,13 @@ msgid "InviteReminderEmail|%{inviter}'s invitation to GitLab is pending"
msgstr ""
msgid "InviteReminderEmail|Accept invitation"
-msgstr ""
+msgstr "招待を承èªã™ã‚‹"
msgid "InviteReminderEmail|Accept invitation: %{invite_url}"
msgstr ""
msgid "InviteReminderEmail|Decline invitation"
-msgstr ""
+msgstr "招待を辞退ã™ã‚‹"
msgid "InviteReminderEmail|Decline invitation: %{decline_url}"
msgstr ""
@@ -23148,7 +23520,7 @@ msgid "InviteReminderEmail|This is a friendly reminder that %{inviter} invited y
msgstr ""
msgid "Invited"
-msgstr ""
+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 ""
@@ -23261,6 +23633,12 @@ msgstr "イシュータイプ"
msgid "Issue already promoted to epic."
msgstr "イシューã¯ã™ã§ã«ã‚¨ãƒ”ックã«æ˜‡æ ¼ã—ã¦ã„ã¾ã™ã€‚"
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr "イシューを見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“"
@@ -23486,6 +23864,9 @@ msgstr "イシューã®ç§»å‹•ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "Issue|Title"
msgstr "タイトル"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -23565,7 +23946,7 @@ msgid "Iterations|Cadence name"
msgstr ""
msgid "Iterations|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "Iterations|Couldn't find iteration cadence"
msgstr ""
@@ -23928,7 +24309,7 @@ msgid "JiraService|Project key is required to generate issue types"
msgstr ""
msgid "JiraService|Select issue type"
-msgstr ""
+msgstr "イシューã®ç¨®é¡žã‚’é¸æŠž"
msgid "JiraService|Set a custom final state by using transition IDs. %{linkStart}Learn about transition IDs%{linkEnd}"
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr "ジョブãŒå†è©¦è¡Œã•ã‚Œã¾ã—ãŸ"
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "ジョブ"
@@ -24096,7 +24492,7 @@ msgid "Job|Browse"
msgstr "ブラウズ"
msgid "Job|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "Job|Canceled"
msgstr ""
@@ -24491,7 +24887,7 @@ msgid "Last Accessed On"
msgstr "最終アクセス"
msgid "Last Activity"
-msgstr ""
+msgstr "å‰å›žã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティ"
msgid "Last Name"
msgstr ""
@@ -24605,7 +25001,7 @@ msgid "Latest pipeline for the most recent commit on this branch"
msgstr "ã“ã®ãƒ–ランãƒã§ã®ç›´è¿‘ã®ã‚³ãƒŸãƒƒãƒˆã®æœ€æ–°ã®ãƒ‘イプライン"
msgid "Launch a ready-to-code development environment for your project."
-msgstr ""
+msgstr "プロジェクトã®ãŸã‚ã®ã™ãã«ä½¿ãˆã‚‹é–‹ç™ºç’°å¢ƒã‚’èµ·å‹•ã—ã¾ã™ã€‚"
msgid "Layout|Fixed"
msgstr ""
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ 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 ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr "管ç†è€…モードを終ãˆã‚‹"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "編集モードを終了ã—ã¾ã™ã‹ï¼Ÿãã®å ´åˆã€ä¿å­˜ã—ã¦ã„ãªã„変更ã¯ã™ã¹ã¦å¤±ã‚ã‚Œã¾ã™ã€‚"
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "グループを離脱"
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr "リンクをコピーã—ã¾ã—ãŸ"
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr "利用å¯èƒ½ãªãƒªãƒã‚¸ãƒˆãƒªã®ä¸€è¦§"
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ msgstr "グループメンãƒãƒ¼ã®è²¢çŒ®åº¦æƒ…報を読ã¿è¾¼ã¿ä¸­"
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr "コミットå‚ç…§ %{ref} 㮠パス %{path} ã«ãŠã‘るファイルã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã€ãŠã‚ˆã³ã‚µãƒ–モジュールを読ã¿è¾¼ã‚“ã§ã„ã¾ã™"
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr ""
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr "メンãƒãƒ¼ã‚·ãƒƒãƒ—ã‚’LDAPåŒæœŸã«é™å®š"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr "ç¾åœ¨ã®ãƒ—ロジェクトをロックã™ã‚‹"
msgid "Locked"
msgstr "ロック中"
-msgid "Locked Files"
-msgstr "ロックã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«"
-
msgid "Locked by %{fileLockUserName}"
msgstr "%{fileLockUserName} ã«ã‚ˆã£ã¦ ã«ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚"
@@ -25372,9 +25790,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "マージ済ã¿"
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr "変更ã®ã¿è¡¨ç¤º"
msgid "MRDiff|Show full file"
msgstr "ã™ã¹ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’表示"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr "最大プッシュサイズ (MB)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr "マージãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™: ã™ã¹ã¦ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ä¾å­˜é–¢ä¿‚ã¯ãƒžãƒ¼ã‚¸æ¸ˆã¿ã§ã‚ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr "マージリクエストã¨ã¯ã€ãƒ—ロジェクトã«åŠ ãˆãŸå¤‰æ›´ã‚’
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 "ソースブランãƒã¸ã®ã‚³ãƒŸãƒƒãƒˆ"
@@ -26665,7 +27098,7 @@ msgid "Metrics|Back to dashboard"
msgstr ""
msgid "Metrics|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "Metrics|Check out the CI/CD documentation on deploying to an environment"
msgstr "環境ã¸ã®ãƒ‡ãƒ—ロイã«ã¤ã„ã¦ã¯ã€CI / CD ã®æ–‡æ›¸ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
@@ -26918,6 +27351,9 @@ msgstr[0] "マイルストーン"
msgid "Milestone due date"
msgstr "マイルストーンã®æœŸæ—¥"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "ç¾åœ¨ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã§ã¯ マイルストーンリストを利用ã§ãã¾ã›ã‚“"
@@ -27098,6 +27534,12 @@ msgstr "より多ãã®ãƒŸãƒ©ãƒ¼ã‚’優先的ã«ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã™ã‚‹å‰ã«ä½¿
msgid "Minutes"
msgstr "分"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr "ミラーã®æ–¹å‘"
@@ -27110,6 +27552,9 @@ msgstr "ミラーリãƒã‚¸ãƒˆãƒª"
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr "ミラーã®ãƒ¦ãƒ¼ã‚¶ãƒ¼"
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr "インデックス作æˆã™ã‚‹åå‰ç©ºé–“"
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "命åã€ãƒˆãƒ”ックã€ã‚¢ãƒã‚¿ãƒ¼"
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr "æ–°è¦ã‚¹ãƒ‹ãƒšãƒƒãƒˆ"
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr "æ–°è¦ãƒ¦ãƒ¼ã‚¶ãƒ¼"
@@ -27719,7 +28185,7 @@ msgid "New code quality findings"
msgstr ""
msgid "New confidential epic title "
-msgstr "æ–°ã—ã„éžå…¬é–‹ã®ã‚¨ãƒ”ックã®ã‚¿ã‚¤ãƒˆãƒ« "
+msgstr "æ–°ã—ã„コンフィデンシャルエピックã®ã‚¿ã‚¤ãƒˆãƒ« "
msgid "New confidential issue title"
msgstr "æ–°ã—ã„éžå…¬é–‹ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã®ã‚¿ã‚¤ãƒˆãƒ«"
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr "æ–°ã—ã„パスワード"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "æ–°è¦ãƒ—ロジェクト"
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28254,7 +28729,7 @@ msgid "Not available for protected branches"
msgstr "ä¿è­·ãƒ–ランãƒã§ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“"
msgid "Not confidential"
-msgstr "機密ã§ã¯ãªã„"
+msgstr "コンフィデンシャルã§ã¯ãªã„"
msgid "Not found"
msgstr ""
@@ -28347,7 +28822,7 @@ msgid "Notes|This comment has changed since you started editing, please review t
msgstr "ã“ã®ã‚³ãƒ¡ãƒ³ãƒˆã¯ç·¨é›†ã‚’始ã‚ã¦ã‹ã‚‰å¤‰æ›´ã•ã‚Œã¦ã„ã¾ã™ã€‚情報ãŒå¤±ã‚ã‚Œãªã„よã†ã«ã€%{open_link}æ›´æ–°ã•ã‚ŒãŸã‚³ãƒ¡ãƒ³ãƒˆ%{close_link}をレビューã—ã¦ãã ã•ã„。"
msgid "Notes|This internal note will always remain confidential"
-msgstr ""
+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 ""
@@ -28533,12 +29008,24 @@ 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|%{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 ""
@@ -28587,9 +29074,18 @@ 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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29051,7 +29553,7 @@ msgid "OnDemandScans|Are you sure you want to delete this scan?"
msgstr ""
msgid "OnDemandScans|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "OnDemandScans|Could not delete saved scan. Please refresh the page, or try again later."
msgstr ""
@@ -29152,6 +29654,9 @@ msgstr "オンデマンドスキャン㯠DevOps ã®ã‚µã‚¤ã‚¯ãƒ«å¤–ã§å®Ÿè¡Œã•ã
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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -29586,7 +30094,7 @@ msgid "PQL|By providing my contact information, I agree GitLab may contact me vi
msgstr ""
msgid "PQL|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "PQL|Contact our Sales team"
msgstr ""
@@ -30274,10 +30782,10 @@ msgid "Paste a public key here. %{link_start}How do I generate it?%{link_end}"
msgstr ""
msgid "Paste confidential epic link"
-msgstr "éžå…¬é–‹ã‚¨ãƒ”ックリンクを貼り付ã‘"
+msgstr "コンフィデンシャルエピックリンクを貼り付ã‘"
msgid "Paste confidential issue link"
-msgstr "éžå…¬é–‹ã‚¤ã‚·ãƒ¥ãƒ¼ã®ãƒªãƒ³ã‚¯ã‚’貼り付ã‘"
+msgstr "コンフィデンシャルイシューã®ãƒªãƒ³ã‚¯ã‚’貼り付ã‘"
msgid "Paste epic link"
msgstr "エピックリンクã®è²¼ã‚Šä»˜ã‘"
@@ -30330,6 +30838,9 @@ msgstr "削除ã®ä¿ç•™ä¸­"
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "削除ã®ä¿ç•™ä¸­"
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr "åå‰ã‚’é¸æŠž"
-msgid "Pin code"
-msgstr "PINコード"
-
msgid "Pipeline"
msgstr "パイプライン"
@@ -30720,6 +31228,9 @@ 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 ""
@@ -30945,6 +31456,9 @@ 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 "%{project_name} ã®ãƒ‘イプライン設定を正常ã«æ›´æ–°ã—ã¾ã—ãŸã€‚"
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr "パイプラインエディタ"
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 "サンプル㮠%{codeStart}.gitlab-ci.yml%{codeEnd} テンプレートファイルを使用ã—ã¦CI/CDã®å‹•ä½œã‚’確èªã—ã¦ãã ã•ã„。"
@@ -31197,6 +31723,9 @@ 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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "セキュリティ上ã®å•é¡Œå›žé¿ã¨ãƒ‡ãƒ¼ã‚¿æ•´åˆæ€§ã®ç¢ºä¿ã®ãŸã‚ã€ãƒãƒƒã‚·ãƒ¥åŒ–ã•ã‚ŒãŸã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã‚’有効化ã—ã€ç§»è¡Œã—ã¦ãã ã•ã„。 %{migrate_link}"
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "有効ãªã‚¼ãƒ­ä»¥ä¸Šã®æ•°å­—を入力ã—ã¦ãã ã•ã„"
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,8 +32140,8 @@ msgstr "é¸æŠžã—ã¦ãã ã•ã„"
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
-msgstr "国をé¸æŠžã—ã¦ãã ã•ã„"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr ""
@@ -31956,6 +32494,9 @@ msgstr ""
msgid "Preview payload"
msgstr "データ部ã®ãƒ—レビュー"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "å‰å›žã®ã‚¢ãƒ¼ãƒ†ã‚£ãƒ•ã‚¡ã‚¯ãƒˆ"
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr "続行"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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 "ç¾åœ¨ã€ã“ã®ã‚¿ã‚¤ãƒ—ã®ãƒãƒ£ãƒ¼ãƒˆã«ã¯ãƒ‡ãƒ¼ã‚¿ãŒã‚ã‚Šã¾ã›ã‚“。プロダクト分æžãƒ„ールを設定ã—ã¦ã„ãªã„å ´åˆã¯ã€Setup タブを開ã„ã¦ãã ã•ã„。"
-msgid "ProductAnalytics|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User activity"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ 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|Do not show on profile"
msgstr "プロフィールã«è¡¨ç¤ºã—ãªã„"
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "アカウントを削除ã™ã‚‹å‰ã«ã“れらã®ã‚°ãƒ«ãƒ¼ãƒ—を削除ã€ã¾ãŸã¯æ‰€æœ‰æ¨©ã‚’譲渡ã—ã¦ãã ã•ã„。"
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr "プロジェクトメンãƒãƒ¼"
msgid "Project milestone"
msgstr "プロジェクトマイルストーン"
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "プロジェクトå"
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr "ローカルストレージãŒåˆ©ç”¨ã§ããªã„ãŸã‚ã€ãƒ—ロジェクトã®é †åºã¯ä¿å­˜ã•ã‚Œã¾ã›ã‚“。"
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr "プロジェクトパス"
@@ -32898,6 +33403,9 @@ 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 "プロジェクトãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。ã¾ãŸã¯ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ã«ã“ã®ãƒ—ロジェクトを追加ã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。"
@@ -32994,9 +33502,21 @@ msgstr "プロジェクトID: %{project_id}"
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 ""
@@ -33009,6 +33529,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,8 +33574,11 @@ 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 "ProjectSelect| or group"
-msgstr "ã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
msgid "ProjectSelect|No matching results"
msgstr ""
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33139,7 +33662,7 @@ msgid "ProjectService|Token for the Drone project."
msgstr ""
msgid "ProjectService|Trigger event for new comments on confidential issues."
-msgstr ""
+msgstr "コンフィデンシャルイシューã«é–¢ã™ã‚‹æ–°ã—ã„コメントã®ãƒˆãƒªã‚¬ãƒ¼ã‚¤ãƒ™ãƒ³ãƒˆã€‚"
msgid "ProjectService|Trigger event for new comments."
msgstr ""
@@ -33154,7 +33677,7 @@ 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 "機密性ã®é«˜ã„イシューãŒä½œæˆã€æ›´æ–°ã¾ãŸã¯ã‚¯ãƒ­ãƒ¼ã‚ºã•ã‚ŒãŸã¨ãã®ãƒˆãƒªã‚¬ãƒ¼ã‚¤ãƒ™ãƒ³ãƒˆ"
+msgstr "コンフィデンシャルイシューãŒä½œæˆã€æ›´æ–°ã¾ãŸã¯ã‚¯ãƒ­ãƒ¼ã‚ºã•ã‚ŒãŸã¨ãã®ãƒˆãƒªã‚¬ãƒ¼ã‚¤ãƒ™ãƒ³ãƒˆ"
msgid "ProjectService|Trigger event when a deployment starts or finishes."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr "内部"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr "イシュー"
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr "マージæ案"
@@ -33435,11 +33949,8 @@ msgstr "ページ"
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "パイプラインã¯æˆåŠŸã—ãªã‘ã‚Œã°ãªã‚‰ãªã„"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
-msgstr ""
+msgstr "潜在的ã«æ©Ÿå¯†æ€§ã®ã‚るメディアファイルã¸ã®ç›´æŽ¥ãƒªãƒ³ã‚¯ã‚’防ãŽã¾ã™"
msgid "ProjectSettings|Private"
msgstr "éžå…¬é–‹"
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr "デフォルトã®çµµæ–‡å­—リアクションを表示"
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr "スニペット"
@@ -33727,7 +34235,7 @@ msgid "ProjectTransfer|An error occurred fetching the transfer locations, please
msgstr ""
msgid "ProjectView|Activity"
-msgstr ""
+msgstr "アクティビティ"
msgid "ProjectView|Files and Readme (default)"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr "プロジェクト(%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr "正常ã«å–å¾—ã—ãŸãƒ—ロジェクト"
@@ -33870,6 +34381,9 @@ 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 "利用å¯èƒ½ãªã‚¤ãƒ³ãƒãƒ¼ãƒˆã‚ªãƒ—ションã¯ã‚ã‚Šã¾ã›ã‚“"
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "プロジェクトã®èª¬æ˜Ž%{tag_start}(オプション)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34036,7 +34553,7 @@ msgid "Promotion is not supported."
msgstr "昇格ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。"
msgid "Promotions|Add %{link_start} description templates %{link_end} to help your contributors to communicate effectively!"
-msgstr ""
+msgstr "%{link_start} 説明テンプレート %{link_end} を追加ã—ã¦ã€ã‚³ãƒ³ãƒˆãƒªãƒ“ュータãŒåŠ¹æžœçš„ã«ã‚³ãƒŸãƒ¥ãƒ‹ã‚±ãƒ¼ã‚·ãƒ§ãƒ³ã§ãるよã†ã«ã—ã¾ã™ã€‚"
msgid "Promotions|Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34176,12 +34690,6 @@ msgstr "多ãã®ã‚¤ã‚·ãƒ¥ãƒ¼ãŒã‚ã‚‹å ´åˆã€å…¨ä½“を把æ¡ã™ã‚‹ã®ã¯å›°é›£
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr "SSH éµã‚’アップロードã™ã‚‹ã‚ˆã†ã«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ä¿ƒã™"
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} ã¯é–‹ç™ºè€…権é™ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒæ›¸ãè¾¼ã¿å¯èƒ½ã«ãªã‚Šã¾ã™ã€‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
@@ -34395,6 +34938,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "デプロイ許å¯"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr "Rebase"
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr "進行中㮠Rebase"
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34879,7 +35416,7 @@ msgid "Receive notification of abuse reports by email."
msgstr ""
msgid "Receive notifications about your own activity"
-msgstr "自身ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティーã«é–¢ã™ã‚‹é€šçŸ¥ã‚’å—ä¿¡ã™ã‚‹"
+msgstr "自身ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティã«é–¢ã™ã‚‹é€šçŸ¥ã‚’å—ä¿¡ã™ã‚‹"
msgid "Receive product marketing emails"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] "æ›´æ–°ã•ã‚ŒãŸã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã‚’表示ã™ã‚‹ãŸã‚ã«ã€ %d 秒間リフレッシュã—ã¦ã„ã¾ã™..."
@@ -34978,13 +35518,13 @@ msgstr "登録"
msgid "Register / Sign In"
msgstr "登録 / サインイン"
-msgid "Register Two-Factor Authenticator"
-msgstr "2è¦ç´ èªè¨¼ã®ç™»éŒ²"
+msgid "Register a WebAuthn device"
+msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "ユニãƒãƒ¼ã‚µãƒ«ãª2è¦ç´ èªè¨¼ãƒ‡ãƒã‚¤ã‚¹ã‚’登録ã™ã‚‹"
+msgid "Register a one-time password authenticator"
+msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -35654,7 +36197,7 @@ msgid "Reports|Actions"
msgstr "アクション"
msgid "Reports|Activity"
-msgstr ""
+msgstr "アクティビティ"
msgid "Reports|An error occurred while loading %{name} results"
msgstr "%{name} ã®çµæžœã‚’読ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -36005,15 +36548,21 @@ msgstr "è¦ä»¶ã® %{reference} ãŒå†ã‚ªãƒ¼ãƒ—ンã•ã‚Œã¾ã—ãŸ"
msgid "Requirement %{reference} has been updated"
msgstr "è¦ä»¶ã® %{reference} ãŒæ›´æ–°ã•ã‚Œã¾ã—ãŸ"
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr "å†é–‹"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr "å†è©¦è¡Œ"
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr "手動ジョブ実行ã¾ãŸã¯é…延ジョブを実行"
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr ""
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ msgstr ""
msgid "Runners|Get started with runners"
msgstr "Runners を始ã‚ã¾ã—ょã†"
+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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ msgstr "インスタンス runner を登録"
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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ 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 ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr "å¤ã„:"
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "稼åƒä¸­"
@@ -37042,6 +37654,9 @@ msgstr "SAML ディスカãƒãƒªãƒ¼ãƒˆãƒ¼ã‚¯ãƒ³"
msgid "SAML for %{group_name}"
msgstr "%{group_name} 用ã®SAML"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37424,7 +38045,7 @@ msgid "Search by commit title or SHA"
msgstr ""
msgid "Search by message"
-msgstr ""
+msgstr "メッセージã§æ¤œç´¢"
msgid "Search by name"
msgstr "åå‰ã§æ¤œç´¢"
@@ -37689,24 +38310,27 @@ msgstr ""
msgid "Security"
msgstr "セキュリティ"
-msgid "Security & Compliance"
-msgstr "セキュリティã¨ã‚³ãƒ³ãƒ—ライアンス"
-
-msgid "Security Configuration"
-msgstr "セキュリティ設定"
-
msgid "Security Dashboard"
msgstr "セキュリティダッシュボード"
msgid "Security Finding not found"
msgstr ""
-msgid "Security dashboard"
-msgstr "セキュリティダッシュボード"
+msgid "Security Policy project already exists."
+msgstr ""
-msgid "Security navigation"
+msgid "Security and Compliance"
msgstr ""
+msgid "Security capabilities"
+msgstr ""
+
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
+msgstr "セキュリティダッシュボード"
+
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -37833,8 +38457,8 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
-msgstr "SAST 設定"
+msgid "SecurityConfiguration|SAST configuration"
+msgstr ""
msgid "SecurityConfiguration|Secure your project"
msgstr ""
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr "%{firstProject}〠%{secondProject}ã€ãŠã‚ˆã³ %{rest}"
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 "セキュリティエリアã§ç›£è¦–ã™ã‚‹ãƒ—ロジェクトを追加ã¾ãŸã¯å‰Šé™¤ã—ã¾ã™ã€‚ ã“ã®ä¸€è¦§ã«å«ã¾ã‚Œã‚‹ãƒ—ロジェクトã§ã¯ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ã¨è„†å¼±æ€§ãƒ¬ãƒãƒ¼ãƒˆã«çµæžœãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
@@ -38326,7 +38974,7 @@ msgid "SecurityReports|Add projects"
msgstr "プロジェクトを追加"
msgid "SecurityReports|All activity"
-msgstr ""
+msgstr "ã™ã¹ã¦ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティ"
msgid "SecurityReports|All clusters"
msgstr ""
@@ -38476,7 +39124,7 @@ msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security
msgstr ""
msgid "SecurityReports|No activity"
-msgstr ""
+msgstr "アクティビティãªã—"
msgid "SecurityReports|No longer detected"
msgstr ""
@@ -38796,6 +39444,9 @@ msgstr ""
msgid "Select labels"
msgstr "ラベルをé¸æŠž"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "マージã™ã‚‹ã‚¿ã‚¤ãƒŸãƒ³ã‚°ã‚’é¸æŠž"
@@ -38863,7 +39514,7 @@ msgid "Select timezone"
msgstr "タイムゾーンをé¸æŠž"
msgid "Select type"
-msgstr ""
+msgstr "種類をé¸æŠž"
msgid "Selected"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr "自己監視プロジェクトãŒæ­£å¸¸ã«å‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "自己監視プロジェクトã¯å‰Šé™¤ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚ログを調ã¹ã‚¨ãƒ©ãƒ¼ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’確èªã—ã¦ãã ã•ã„"
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ msgstr ""
msgid "Set the milestone to %{milestone_reference}."
msgstr "マイルストーンを %{milestone_reference} ã«è¨­å®šã€‚"
+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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr "サインイン"
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ msgstr "Slackçµ±åˆã§ã¯ã€Slackã®ãƒãƒ£ãƒƒãƒˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰ slash コã
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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 ""
@@ -40122,7 +40827,7 @@ msgid "Something went wrong while setting %{issuableType} %{dateType} date."
msgstr ""
msgid "Something went wrong while setting %{issuableType} confidentiality."
-msgstr ""
+msgstr "%{issuableType} をコンフィデンシャルã«è¨­å®šã™ã‚‹éš›ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "Something went wrong while setting %{issuableType} health status."
msgstr ""
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr "スパムã¨ã‚¢ãƒ³ãƒãƒœãƒƒãƒˆä¿è­·"
msgid "Spam log successfully submitted as ham."
msgstr "スパムログã¯ãƒãƒ ã¨ã—ã¦é€ä¿¡ã•ã‚Œã¾ã—ãŸã€‚"
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr "指定ã®URLã¯ä½¿ç”¨ã§ãã¾ã›ã‚“: \"%{reason}\""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 "%{purchaseSubscriptionLinkStart}æ–°ã—ã„サブスクリプション%{purchaseSubscriptionLinkEnd}を購入ã—ã€å†åº¦ãŠè©¦ã—ãã ã•ã„。サãƒãƒ¼ãƒˆãŒå¿…è¦ãªå ´åˆã¯ã€%{supportLinkStart} GitLabサãƒãƒ¼ãƒˆ%{supportLinkEnd}ã«é€£çµ¡ã—ã¦ãã ã•ã„。"
-msgid "SuperSonics|You can no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr "サブスクリプション"
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41622,9 +42330,27 @@ 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 ""
@@ -41922,7 +42648,7 @@ msgid "Terraform|Are you sure you want to remove the Terraform State %{name}?"
msgstr ""
msgid "Terraform|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "Terraform|Cannot remove a locked state"
msgstr ""
@@ -42029,12 +42755,12 @@ msgstr ""
msgid "Test"
msgstr "テスト"
-msgid "Test Cases"
-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] ""
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr "イシュートラッカーã¯ã€ãƒ—ロジェクトを改善ã—ãŸã‚Šè§£
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr "Prometheusサーãƒãƒ¼ã¯ã€Œæ‚ªã„リクエストã€ã¨å¿œç­”ã—ã¾ã—ãŸã€‚クエリãŒæ­£ã—ãã‚ãªãŸã®Prometheusã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。 %{documentationLink}"
+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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "コãƒã‚¯ã‚·ãƒ§ãƒ³ã¯ %{timeout} ã§ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã™ã€‚タイムアウトã™ã‚‹ãƒªãƒã‚¸ãƒˆãƒªã§ã¯ã€clone/push を組ã¿åˆã‚ã›ã¦ä½¿ç”¨ã—ã¦ãã ã•ã„。"
@@ -42341,6 +43067,9 @@ msgstr "ä¾å­˜é–¢ä¿‚リストã«ã¯ãƒ—ロジェクト内ã§ä½¿ç”¨ã•ã‚Œã¦ã„ã‚‹
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "ã“ã®ã‚¸ãƒ§ãƒ–ã® %{environmentLink} ã¸ã®ãƒ‡ãƒ—ロイã¯æˆåŠŸã—ã¾ã›ã‚“ã§ã—ãŸã€‚"
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr "ディレクトリã®ä½œæˆã«æˆåŠŸã—ã¾ã—ãŸ"
@@ -42569,7 +43298,7 @@ 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 "親エピックã¯éžå…¬é–‹ã§ã€éžå…¬é–‹ã®ã‚¨ãƒ”ックã¨ã‚¤ã‚·ãƒ¥ãƒ¼ã ã‘ã‚’å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™"
+msgstr "親エピックã¯ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«ã§ã€ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«ã®ã‚¨ãƒ”ックã¨ã‚¤ã‚·ãƒ¥ãƒ¼ã ã‘ã‚’å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™"
msgid "The parsed YAML is too big"
msgstr ""
@@ -42652,7 +43381,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43433,13 +44168,13 @@ msgid "This is your current session"
msgstr "ã“ã‚Œã¯ã‚ãªãŸã®ç¾åœ¨ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã§ã™"
msgid "This issue cannot be assigned to a confidential epic because it is public."
-msgstr ""
+msgstr "ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã¯å…¬é–‹ã•ã‚Œã¦ã„ã‚‹ãŸã‚コンフィデンシャルエピックã«å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“."
msgid "This issue cannot be made public because it belongs to a confidential epic."
-msgstr ""
+msgstr "ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã¯ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«ã‚¨ãƒ”ックã«å±žã—ã¦ã„ã‚‹ãŸã‚公開ã§ãã¾ã›ã‚“."
msgid "This issue is confidential and should only be visible to team members with at least Reporter access."
-msgstr ""
+msgstr "ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã¯ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«ã§ã‚ã‚Šã€å°‘ãªãã¨ã‚‚Reporter以上ã®æ¨©é™ã®ã‚ã‚‹ãƒãƒ¼ãƒ ãƒ¡ãƒ³ãƒãƒ¼ã«ã®ã¿è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
msgid "This issue is currently blocked by the following issues:"
msgstr ""
@@ -43553,7 +44288,7 @@ 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 "é¸æŠžã—ãŸãƒ•ã‚©ãƒ¼ã‚¯ã¯ä»–ã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’æŒã¤ã“ã¨ãŒã§ãる別ã®åå‰ç©ºé–“ã«ã‚ã‚‹ãŸã‚ã€ã“ã‚Œã«ã‚ˆã‚Šæ©Ÿå¯†æƒ…å ±ãŒå…¬é–‹ã•ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚"
+msgstr "é¸æŠžã—ãŸãƒ•ã‚©ãƒ¼ã‚¯ã¯ä»–ã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’æŒã¤ã“ã¨ãŒã§ãる別ã®åå‰ç©ºé–“ã«ã‚ã‚‹ãŸã‚ã€ã“ã‚Œã«ã‚ˆã‚Šã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«æƒ…å ±ãŒå…¬é–‹ã•ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "空リãƒã‚¸ãƒˆãƒªã‚’作æˆã¾ãŸã¯æ—¢å­˜ãƒªãƒã‚¸ãƒˆãƒªã‚’インãƒãƒ¼ãƒˆã‚’ã—ãªã‘ã‚Œã°ã€ã‚³ãƒ¼ãƒ‰ã®ãƒ—ッシュã¯ã§ãã¾ã›ã‚“。"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "ã“ã® Runner ã¯ä¿è­·ãƒ–ランãƒä¸Šã§èµ·å‹•ã•ã‚ŒãŸãƒ‘イプラインã§ã®ã¿å®Ÿè¡Œã§ãã¾ã™ã€‚"
@@ -43747,10 +44485,7 @@ msgstr "ã“ã®å¤‰æ•°ã¯ãƒžã‚¹ã‚¯ã§ãã¾ã›ã‚“."
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44092,7 +44827,7 @@ msgid "Title"
msgstr "タイトル"
msgid "Title (required)"
-msgstr ""
+msgstr "タイトル (必須)"
msgid "Title:"
msgstr "タイトル:"
@@ -44199,6 +44934,9 @@ msgstr "開始ã™ã‚‹ã«ã¯ã€Gitea Host ã® URL 㨠%{link_to_personal_token} ã‚
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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44240,7 +44978,7 @@ msgid "To preserve performance only %{strong_open}%{display_size} of %{real_size
msgstr ""
msgid "To protect this issue's confidentiality, %{linkStart}fork this project%{linkEnd} and set the fork's visibility to private."
-msgstr ""
+msgstr "ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã®æ©Ÿå¯†æ€§ã‚’ä¿è­·ã™ã‚‹ãŸã‚ã«ã€%{linkStart}プロジェクトをフォーク%{linkEnd}ã—ã€ãƒ•ã‚©ãƒ¼ã‚¯ã®å¯è¦–性をプライベートã«è¨­å®šã—ã¦ãã ã•ã„。"
msgid "To protect this issue's confidentiality, a private fork of this project was selected."
msgstr "ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã®æ©Ÿå¯†æ€§ã‚’ä¿è­·ã™ã‚‹ãŸã‚ã«ã€ã“ã®ãƒ—ロジェクトã®ãƒ—ライベートフォークãŒé¸æŠžã•ã‚Œã¾ã—ãŸã€‚"
@@ -44273,7 +45011,7 @@ msgid "To see this project's operational details, contact an owner of group %{gr
msgstr "ã“ã®ãƒ—ロジェクトã®é‹ç”¨ä¸Šã®è©³ç´°ã‚’確èªã™ã‚‹ã«ã¯ã€ %{groupName} グループã®ã‚ªãƒ¼ãƒŠãƒ¼ã«é€£çµ¡ã‚’ã¨ã£ã¦ãƒ—ランをアップグレードã—ã¦ãã ã•ã„。ダッシュボードã‹ã‚‰ãƒ—ロジェクトを削除ã§ãã¾ã™ã€‚"
msgid "To see what's changed or create a merge request, choose a branch or tag (like %{branch}), or enter a commit (like %{sha})."
-msgstr ""
+msgstr "変更ã¾ãŸã¯ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ä½œæˆå†…容を確èªã™ã‚‹ã«ã¯ã€ãƒ–ランãƒã¾ãŸã¯ã‚¿ã‚° ( %{branch}ãªã©) ã‚’é¸æŠžã™ã‚‹ã‹ã€ã‚³ãƒŸãƒƒãƒˆ ( %{sha} ãªã©) を入力ã—ã¾ã™ã€‚"
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 "Azureã€Oktaã€Oneloginã€Ping Identyã€ã¾ãŸã¯ã‚«ã‚¹ã‚¿ãƒ  SAML 2.0 プロãƒã‚¤ãƒ€ãƒ¼ãªã©ã® ID プロãƒã‚¤ãƒ€ãƒ¼ã‚’利用ã—ã¦ã€ã‚ãªãŸã®ã‚°ãƒ«ãƒ¼ãƒ—ã® SAML èªè¨¼ã‚’設定ã™ã‚‹ã«ã¯:"
@@ -44684,6 +45422,9 @@ msgstr "グループã¯ã™ã§ã«ãƒ«ãƒ¼ãƒˆã‚°ãƒ«ãƒ¼ãƒ—ã§ã™ã€‚"
msgid "TransferGroup|Group is already associated to the parent group."
msgstr "Groupã¯ã™ã§ã«è¦ªã‚°ãƒ«ãƒ¼ãƒ—ã«é–¢é€£ä»˜ã‘ã§ãã¦ã„ã¾ã™ã€‚"
+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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr "マニュアルジョブをトリガーã™ã‚‹"
-
msgid "Trigger pipelines for mirror updates"
msgstr "ミラー更新ã®ãŸã‚ã®ã€ãƒ‘イプライントリガー"
@@ -44812,7 +45550,7 @@ 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 ""
+msgstr "ä¿¡é ¼ã•ã‚ŒãŸã‚¢ãƒ—リケーションã¯ã€GitLab OAuthフローã§è‡ªå‹•çš„ã«æ‰¿èªã•ã‚Œã¾ã™ã€‚ ä¿¡é ¼ã§ãるアプリケーションãŒæ©Ÿå¯†è¨­å®šã‚’ true ã«è¨­å®šã—ã¦ã„ã‚‹ã“ã¨ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã®ãŸã‚ã«å¼·ã推奨ã•ã‚Œã¾ã™ã€‚"
msgid "Try again"
msgstr "å†è©¦è¡Œ"
@@ -44877,9 +45615,6 @@ msgstr "Twitter:"
msgid "Two-Factor Authentication"
msgstr "2è¦ç´ èªè¨¼"
-msgid "Two-Factor Authentication code"
-msgstr "2è¦ç´ èªè¨¼ã‚³ãƒ¼ãƒ‰"
-
msgid "Two-factor Authentication"
msgstr "2è¦ç´ èªè¨¼"
@@ -44925,12 +45660,6 @@ msgstr "タイプ"
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr "2è¦ç´ èªè¨¼ãƒ‡ãƒã‚¤ã‚¹ (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "2è¦ç´ èªè¨¼ã¯HTTPSãŒæœ‰åŠ¹ãªWebサイトã§ã®ã¿å‹•ä½œã—ã¾ã™ã€‚詳細ã«ã¤ã„ã¦ã¯ç®¡ç†è€…ã«é€£çµ¡ã—ã¦ãã ã•ã„。"
-
msgid "URL"
msgstr "URL"
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr "無制é™"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ msgstr "ã‚ãªãŸã®ãƒ–ックマークã•ã‚ŒãŸURLã‚’æ›´æ–°ã—ã¦ãã ã•ã„。
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 ""
@@ -45474,6 +46224,9 @@ msgstr "使用状æ³ã®ãƒˆãƒ¬ãƒ³ãƒ‰"
msgid "Usage statistics"
msgstr "使用状æ³ã®çµ±è¨ˆ"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -45709,10 +46465,10 @@ msgid "UsageTrends|Groups"
msgstr ""
msgid "UsageTrends|Issues"
-msgstr ""
+msgstr "イシュー"
msgid "UsageTrends|Issues & merge requests"
-msgstr ""
+msgstr "イシューã¨ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
msgid "UsageTrends|Items"
msgstr ""
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr "ユーザーã®è­˜åˆ¥å­ãŒæ­£å¸¸ã«ä½œæˆã§ãã¾ã—ãŸã€‚"
@@ -46013,7 +46778,7 @@ msgid "UserLists|Add users"
msgstr ""
msgid "UserLists|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "UserLists|Create"
msgstr ""
@@ -46091,7 +46856,7 @@ msgid "UserProfile|Blocked user"
msgstr "ブロックã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼"
msgid "UserProfile|Bot activity"
-msgstr ""
+msgstr "ボットã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティ"
msgid "UserProfile|Contributed projects"
msgstr "貢献ã—ãŸãƒ—ロジェクト"
@@ -46360,6 +47125,9 @@ msgstr "ãƒãƒªãƒ¥ãƒ¼ã‚¹ãƒˆãƒªãƒ¼ãƒ åˆ†æžã¯ã€ã‚ãªãŸã®ãƒãƒ¼ãƒ ã®é–‹ç™ºé€Ÿ
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr "ã“ã®å¤‰æ›´å‰ã® blame を表示"
@@ -46643,9 +47417,6 @@ msgstr "ドキュメントã®è¡¨ç¤º"
msgid "View eligible approvers"
msgstr "資格ã®ã‚る承èªè€…を表示"
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "%d 件ã®å…¬é–‹ã•ã‚ŒãŸã‚¢ãƒ¼ãƒ†ã‚£ãƒ•ã‚¡ã‚¯ãƒˆã‚’表示"
@@ -46846,6 +47617,69 @@ msgstr "%{formattedStartDate} ã‹ã‚‰ä»Šæ—¥ã¾ã§"
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|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 ""
@@ -46997,7 +47831,7 @@ msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %{scannerVersion})"
msgid "Vulnerability|Activity"
-msgstr ""
+msgstr "アクティビティ"
msgid "Vulnerability|Actual Response"
msgstr ""
@@ -47236,12 +48070,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "Prometheusサーãƒãƒ¼ã«åˆ°é”ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚サーãƒãƒ¼ãŒå­˜åœ¨ã—ãªã„ã‹ã€è¨­å®šã®è©³ç´°ã‚’æ›´æ–°ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "%{humanized_resource_name} ã«ã‚¹ãƒ‘ムãŒã‚ã‚‹å¯èƒ½æ€§ã‚’検出ã—ã¾ã—ãŸã€‚続行ã™ã‚‹ã«ã¯ reCAPTCHA を実行ã—ã¦ãã ã•ã„。"
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47456,10 +48284,10 @@ msgid "Webhooks|Are you sure you want to delete this webhook?"
msgstr ""
msgid "Webhooks|Confidential comments"
-msgstr ""
+msgstr "コンフィデンシャルコメント"
msgid "Webhooks|Confidential issues events"
-msgstr ""
+msgstr "コンフィデンシャルイシューイベント"
msgid "Webhooks|Delete webhook"
msgstr ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -47848,7 +48683,7 @@ msgid "WikiPageConflictMessage|Someone edited the page the same time you did. Pl
msgstr ""
msgid "WikiPage|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "WikiPage|Commit message"
msgstr ""
@@ -47955,7 +48790,7 @@ msgstr "修正ã—ãªã„ / リスクをå—ã‘入れる"
msgid "Work in progress (open and unassigned)"
msgstr "作業中(オープンã‹ã¤æœªå‰²ã‚Šå½“ã¦ï¼‰"
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48014,7 +48852,7 @@ msgid_plural "WorkItem|Assignees"
msgstr[0] ""
msgid "WorkItem|Cancel"
-msgstr ""
+msgstr "キャンセル"
msgid "WorkItem|Child objectives and key results"
msgstr ""
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48224,13 +49083,13 @@ msgid "Write a comment…"
msgstr "コメントを書ã..."
msgid "Write a description or drag your files here…"
-msgstr ""
+msgstr "説明を記述ã™ã‚‹ã‹ã€ã“ã“ã«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ドラッグã—ã¦ãã ã•ã„"
msgid "Write a description..."
msgstr ""
msgid "Write a description…"
-msgstr ""
+msgstr "説明を記述ã—ã¦ãã ã•ã„"
msgid "Write an internal note or drag your files here…"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr "マイルストーンã®èª¬æ˜Žã‚’書ã..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "リリースノートを書ãã‹ã€ã“ã“ã«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ドラッグ"
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr "ã‚ãªãŸã¯ã¾ã 2è¦ç´ èªè¨¼ãƒ‡ãƒã‚¤ã‚¹ã‚’登録ã—ã¦ã„ã¾ã›ã‚“。"
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ msgstr "ロックを強制的ã«å‰Šé™¤ã™ã‚‹ã«ã¯ã€Maintainer ã®ã‚¢ã‚¯ã‚»ã‚¹æ
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 ""
@@ -48859,7 +49724,7 @@ 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 ""
+msgstr "ã‚ãªãŸã¯ã€æ–°ã—ã作æˆã•ã‚ŒãŸãƒ–ランãƒã‚„既存ã®ãƒ–ランãƒã¸ã®æ–°è¦ã‚³ãƒŸãƒƒãƒˆãªã©ã®ã‚ˆã†ã«ã€æ›´æ–°ã®çµæžœã§ã‚るアクティビティフィード内ã®ã™ã¹ã¦ã®ã‚¤ãƒ™ãƒ³ãƒˆã®ä½œæˆè€…ã«ãªã‚Šã¾ã™ã€‚"
msgid "You will first need to set up Jira Integration to use this feature."
msgstr "ã“ã®æ©Ÿèƒ½ã‚’使用ã™ã‚‹ã«ã¯ã€ã¾ãšJiraインテグレーションを設定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -48883,7 +49748,7 @@ msgid "You will only receive notifications for threads you have participated in"
msgstr "å‚加ã—ãŸã‚¹ãƒ¬ãƒƒãƒ‰ã®ã¿é€šçŸ¥ã—ã¾ã™"
msgid "You will receive notifications for any activity"
-msgstr "å…¨ã¦ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティーを通知ã—ã¾ã™"
+msgstr "å…¨ã¦ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティを通知ã—ã¾ã™"
msgid "You will receive notifications only for comments in which you were @mentioned"
msgstr "ã‚ãªãŸãŒ @mentioned ã§ã‚³ãƒ¡ãƒ³ãƒˆã•ã‚ŒãŸæ™‚ã®ã¿é€šçŸ¥ã—ã¾ã™"
@@ -48934,7 +49799,7 @@ msgid "You're receiving this email because of your account on %{host}. %{unsubsc
msgstr ""
msgid "You're receiving this email because of your activity on %{host}."
-msgstr "%{host} ã§ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティーã®ãŸã‚ã€ã“ã®ãƒ¡ãƒ¼ãƒ«ã‚’å—ä¿¡ã—ã¦ã„ã¾ã™ã€‚"
+msgstr "%{host} ã§ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティã®ãŸã‚ã€ã“ã®ãƒ¡ãƒ¼ãƒ«ã‚’å—ä¿¡ã—ã¦ã„ã¾ã™ã€‚"
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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,8 +49862,8 @@ msgstr "CSV エクスãƒãƒ¼ãƒˆã‚’開始ã—ã¾ã—ãŸã€‚完了後ã«ã€%{email} ã
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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
-msgstr "%{project_name} (%{project_url}) プロジェクトã‹ã‚‰ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—㟠%{written_count} ã® CSV ã‚’ã“ã®ãƒ¡ãƒ¼ãƒ«ã«æ·»ä»˜ã—ã¦ã„ã¾ã™ã€‚"
+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 import for project"
msgstr ""
@@ -49024,6 +49892,9 @@ msgstr "ã‚ãªãŸã® GitLab ã®ã‚°ãƒ«ãƒ¼ãƒ—"
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 "所属グループ"
@@ -49048,6 +49919,9 @@ msgstr "SSH キーãŒå‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
msgid "Your SSH keys (%{count})"
msgstr "SSH キー (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "ã‚ãªãŸã®To Doリスト"
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "アプリケーション(%{size})"
@@ -49102,9 +49979,6 @@ msgstr "承èªã•ã‚ŒãŸã‚¢ãƒ—リケーション"
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "ã‚ãªãŸã®ãƒ–ラウザã¯U2Fをサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。 Google Chromeデスクトップ (ãƒãƒ¼ã‚¸ãƒ§ãƒ³41以é™) を使用ã—ã¦ãã ã•ã„。"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr "コメントã¯ç ´æ£„ã•ã‚Œã¾ã™ã€‚"
msgid "Your commit email is used for web based operations, such as edits and merges."
msgstr "ã“ã®ã‚³ãƒŸãƒƒãƒˆãƒ¡ãƒ¼ãƒ«ã¯ã€ç·¨é›†ã‚„マージãªã©ã®Webベースã®æ“作ã«ä½¿ç”¨ã—ã¾ã™ã€‚"
+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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "イシューを作æˆã—ã¦ã€ã“ã®è„†å¼±æ€§ã‚’調査ã—ã¾ã™"
@@ -49915,6 +50795,9 @@ msgstr "マージリクエストã§è§£æ±º"
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] "ファイル"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "検出çµæžœãŒè¦‹ã¤ã‹ã‚‰ãªã„ã‹ã€ã™ã§ã«è„†å¼±æ€§ã«é–¢é€£ä»˜ã‘られã¦ã„ã¾ã™"
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50521,11 +51404,17 @@ msgstr "%{path_lock_user_name} ã«ã‚ˆã£ã¦ %{created_at} ã«ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã
msgid "manual"
msgstr "マニュアル"
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
-msgstr "ã“ã® math ブロックã®ãƒ¬ãƒ³ãƒ€ãƒªãƒ³ã‚°ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+msgid "math|Too many expansions. Consider using multiple math blocks."
+msgstr ""
msgid "member"
msgid_plural "members"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr "%{metricsLinkStart} メモリ %{metricsLinkEnd} 使用率㌠%{memoryFro
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart} メモリ %{metricsLinkEnd} 使用率㯠%{memoryFrom} MB㧠%{emphasisStart} 変化ãªã— %{emphasisEnd}"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr "承èªã¯ã‚ªãƒ—ションã§ã™"
msgid "mrWidget|Approval password is invalid."
msgstr "承èªãƒ‘スワードãŒç„¡åŠ¹ã§ã™ã€‚"
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr "承èª"
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,84 +51690,30 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "マージã¯ãƒ–ロックã•ã‚Œã¾ã—ãŸ: ã™ã¹ã¦ã®ã‚¹ãƒ¬ãƒƒãƒ‰ã‚’解決ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "マージã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr "マージ作業者"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
+msgid "mrWidget|More information"
+msgstr "詳ã—ã„情報"
-msgid "mrWidget|Merging! This is going to be great…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|More information"
-msgstr "詳ã—ã„情報"
-
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "自動マージã®æº–å‚™ãŒã§ãã¾ã—ãŸã€‚ã“ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’マージã™ã‚‹ã«ã¯ã€ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã¸ã®æ›¸ãè¾¼ã¿æ¨©é™ã‚’æŒã¤äººã«ä¾é ¼ã—ã¾ã™"
-
msgid "mrWidget|Refresh"
msgstr "æ›´æ–°"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
@@ -51123,7 +52039,7 @@ msgid "reached maximum depth"
msgstr ""
msgid "recent activity"
-msgstr "最新アクティビティー"
+msgstr "最新アクティビティ"
msgid "register"
msgstr "登録"
diff --git a/locale/ka_GE/gitlab.po b/locale/ka_GE/gitlab.po
index d48f03f413e..0edb0698c3b 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/kab/gitlab.po b/locale/kab/gitlab.po
index f8de4027e14..201d9202e68 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-02-11 04:24\n"
+"PO-Revision-Date: 2023-03-11 10:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index b44c1164c40..228c6cecf32 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr " %{start}부터 %{end}까지"
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] "%dê°œì˜ í•´ê²°ë˜ì§€ ì•Šì€ ìŠ¤ë ˆë“œ"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%dê°œì˜ ì·¨ì•½ì "
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] "%dê°œì˜ ê²½ê³  발견:"
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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 ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -539,6 +553,9 @@ msgstr "%{count} ê±´ê³¼ ê´€ë ¨ëœ %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "%{count}ê°œ ì„ íƒë¨"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -740,6 +757,9 @@ msgstr "Forkí•œ ì›ë³¸ 프로ì íŠ¸ê°€ ë” ë‚®ì€ ê³µê°œ 수준으로 설정ë˜ì
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -755,9 +775,6 @@ msgstr "%{mergeLength}/%{usersLength} 머지 가능"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} 첫 번째 %{warnings_displayed} 보기"
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (만료ë¨)"
@@ -889,6 +906,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} ì€(는) 목ë¡ì— í¬í•¨ë˜ì§€ 않습니다"
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] "%dê°œì˜ ë°°í¬ í‚¤"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "팔로워 %{count}명"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%d 그룹"
@@ -1675,9 +1694,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "API í¼ì§•"
-msgid "API Fuzzing Configuration"
-msgstr "API í¼ì§• 설정"
-
msgid "API Help"
msgstr "API ë„움ë§"
@@ -2092,9 +2108,6 @@ msgstr "ì²´í¬ë¦¬ìŠ¤íŠ¸ 추가"
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr "ì´ ë¼ì¸ì— 댓글 추가"
@@ -2116,6 +2129,9 @@ msgstr "프로ì íŠ¸ì— 관한 ì •ë³´ê°€ 담긴 홈페ì´ì§€ë¥¼ wikiì— ì¶”ê°€í•
msgid "Add a new issue"
msgstr "ì´ìŠˆ 추가"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "번호 매기기 ëª©ë¡ ì¶”ê°€"
@@ -2125,6 +2141,9 @@ 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 ""
@@ -2239,6 +2258,9 @@ msgstr "새 애플리케ì´ì…˜ 추가"
msgid "Add new directory"
msgstr "새 디렉토리 추가"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2377,6 +2399,9 @@ msgstr "추가 시간(분):"
msgid "Additional text"
msgstr "추가 í…스트"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr "ë¡œê·¸ì¸ ë° ë„ì›€ë§ íŽ˜ì´ì§€ì— 대한 추가 í…스트"
@@ -3556,40 +3581,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3961,6 +3956,9 @@ msgstr "모든 GitLab"
msgid "All Members"
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 "모든 브랜치"
@@ -4310,7 +4308,7 @@ msgid "An error occurred while fetching reference"
msgstr ""
msgid "An error occurred while fetching reviewers."
-msgstr "리뷰어를 가져오는 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+msgstr ""
msgid "An error occurred while fetching tags. Retry the search."
msgstr "태그를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 검색해 보세요."
@@ -4587,6 +4585,9 @@ 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 ""
@@ -4596,6 +4597,123 @@ msgstr "ì•Œ 수 없는 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "Analytics"
msgstr "분ì„"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4674,13 +4792,28 @@ 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|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."
+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."
@@ -4823,12 +4956,18 @@ msgstr "변경 사항 저장"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "%{linkStart}비밀번호 ì •ì±… ê°€ì´ë“œë¼ì¸%{linkEnd}ì„ í™•ì¸í•˜ì„¸ìš”."
+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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr "머지 리퀘스트 승ì¸"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr "머지 리퀘스트 승ì¸"
@@ -5080,6 +5223,14 @@ msgstr "승ì¸ë¨"
msgid "Approved MRs"
msgstr "승ì¸ëœ MR"
+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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr "ì´ ë¨¸ì§€ 리퀘스트를 승ì¸í–ˆìŠµë‹ˆë‹¤."
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ 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 "ì´ %{commentType}ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
@@ -5518,7 +5669,7 @@ msgstr[0] "íŒŒì¼ %d ê°œ 첨부"
msgid "Attaching the file failed."
msgstr "íŒŒì¼ ì²¨ë¶€ê°€ 실패했습니다."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5771,9 +5922,6 @@ msgstr "%{timeago} ì „ %{author}ì— ì˜í•´ 작성ë¨"
msgid "Authorization code:"
msgstr "ì¸ì¦ 코드:"
-msgid "Authorization required"
-msgstr "ì¸ì¦ í•„ìš”"
-
msgid "Authorization token duration (minutes)"
msgstr "ì¸ì¦ í† í° ìœ íš¨ 기간 (분)"
@@ -5786,9 +5934,6 @@ msgstr "권한 부여"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "%{link_to_client} ì„ ë‚´ 계정으로 ì¸ì¦í•˜ì‹œê² ì–´ìš”?"
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5798,9 +5943,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr "ì¸ì¦ëœ 애플리케ì´ì…˜ (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr "공개 ëœ ëª¨ë“  ê·¸ë£¹ì„ ì•„ëž˜ì—ì„œ ì°¾ì„ ìˆ˜ 있습니다."
-msgid "Beta"
-msgstr "베타"
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr "요금제를 다운그레ì´ë“œí•˜ë ¤ë©´ %{support_link_start}ê³ ê° ì§€
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr "업그레ì´ë“œ"
msgid "BillingPlan|Upgrade for free"
msgstr "무료 업그레ì´ë“œ"
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr "Billings|무료 요금제 ë° í‰ê°€íŒì—ì„œ ê·¸ë£¹ì€ í•˜ë£¨ì— ìµœëŒ€
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6606,6 +6739,9 @@ msgstr "Bitbucketì—ì„œ 가져오기"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr "ì¹´ë“œ ì´ë™"
@@ -6846,9 +6994,6 @@ msgstr "목ë¡ì˜ 처ìŒìœ¼ë¡œ ì´ë™"
msgid "Boards|New board"
msgstr "새 보드"
-msgid "Boards|New epic"
-msgstr "새 ì—픽"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr "모든 브랜치"
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr "푸시 액세스 ê¶Œí•œì´ ìžˆëŠ” 모든 사용ìžëŠ” 강제로 푸시할 수 있습니다."
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "푸시 액세스 ê¶Œí•œì´ ìžˆëŠ” 모든 사용ìžì—게 %{linkStart}ê°•ì œ 푸시%{linkEnd}를 허용합니다."
@@ -6987,6 +7129,15 @@ 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 "브랜치를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -7017,11 +7168,14 @@ msgstr "와ì¼ë“œì¹´ë“œ ìƒì„±: %{searchTerm}"
msgid "BranchRules|Details"
msgstr "세부정보"
-msgid "BranchRules|Force push"
-msgstr "강제 푸시"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
-msgid "BranchRules|Force push is not allowed."
-msgstr "ê°•ì œ 푸시는 허용ë˜ì§€ 않습니다."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
+msgstr ""
msgid "BranchRules|Groups"
msgstr ""
@@ -7062,6 +7216,9 @@ msgstr "ìŠ¹ì¸ í•„ìš” (%{total})"
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7945,6 +8111,9 @@ 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 "대외비가 ì•„ë‹Œ 하위 ì—í”½ì´ í¬í•¨ëœ ì—í”½ì„ ëŒ€ì™¸ë¹„ë¡œ 지정할 수 없습니다."
@@ -8325,6 +8494,9 @@ 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 ""
@@ -8367,6 +8539,9 @@ 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 ""
@@ -8376,16 +8551,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8412,6 +8584,9 @@ 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 "%{minimumNumberOfUsers} (사용 ì¤‘ì¸ ì¢Œì„) ì´ìƒì´ì–´ì•¼ 합니다."
@@ -8430,6 +8605,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8568,12 +8749,18 @@ 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 "Ci/CD 파ì´í”„ë¼ì¸ì´ ì—°ê²°ë˜ê³  실행할 저장소를 ì„ íƒí•´ 주세요."
msgid "Choose your framework"
msgstr "프레임워í¬ë¥¼ ì„ íƒí•˜ì„¸ìš”"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,10 +8839,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr "실행 중"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "리비전 비êµ"
-
msgid "Compare branches and continue"
msgstr "브랜치를 비êµí•˜ê³  계ì†"
@@ -10161,6 +10351,9 @@ msgstr "마지막 커밋과 ë³€ê²½ì  ë¹„êµ"
msgid "Compare changes with the merge request target branch"
msgstr "머지 리퀘스트(MR) ëŒ€ìƒ ë¸Œëžœì¹˜ì™€ 변경 사항 비êµ"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "ì»´í¬ë„ŒíŠ¸"
@@ -10365,9 +10582,6 @@ msgstr "비공개 메모"
msgid "Confidentiality"
msgstr "대외비"
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr "기여"
msgid "Contribution Analytics"
msgstr "ê¸°ì—¬ë„ ë¶„ì„"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ 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 ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11115,8 +11347,8 @@ msgstr "그룹 구성ì›ë³„ 기여"
msgid "Contributor"
msgstr "기여ìž"
-msgid "Contributors"
-msgstr "기여ìž"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr ""
@@ -11187,6 +11419,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr "커밋 SHA 복사"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11433,8 +11668,8 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
-msgstr "êµ­ê°€"
+msgid "Country / Region"
+msgstr ""
msgid "Counts"
msgstr ""
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,7 +12418,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr "DAST ì„¤ì •ì„ ì°¾ì„ ìˆ˜ 없습니다."
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr "ì—픽 ì‚­ì œ"
@@ -13301,6 +13539,9 @@ msgstr "릴리스 %{release}ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,10 +14388,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr "개발ìž"
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr "다ì´ì–´ê·¸ëž¨ (%{language})"
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr "GitLab Geo 알아보기"
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr "설명 편집"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "환경 편집"
@@ -15060,6 +15313,9 @@ msgstr "%{user_name}ì˜ ì‹ ì› íŽ¸ì§‘"
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr "머지 리퀘스트 수정"
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "공개 ë°°í¬ í‚¤ 편집"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15582,7 +15847,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr "ì—픽 ë³´ë“œ"
msgid "Epic actions"
msgstr "ì—픽 ë™ìž‘"
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 ""
@@ -16795,6 +17078,9 @@ 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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr "2ì›”"
msgid "February"
msgstr "2ì›”"
-msgid "Feedback and Updates"
-msgstr "피드백 ë° ì—…ë°ì´íŠ¸"
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17662,9 +17951,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr "ë” ë¹ ë¥¸ íƒìƒ‰ì„ 위해 모든 기ë¡ì´ 표시ë˜ì§€ëŠ” 않습니다."
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr "무료"
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ 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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr "Gitea 호스트 URL"
msgid "Gitea Import"
msgstr "Gitea 가져오기"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr "%{time_ago} ì „ 엑세스 권한 부여ë¨"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr "GlobalSearch|최근 ì´ìŠˆ"
msgid "GlobalSearch|Recent merge requests"
msgstr "GlobalSearch|최근 머지 리퀘스트"
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr "ê²°ê³¼ 수가 í•œë„를 초과했습니다."
@@ -19121,15 +19430,9 @@ msgstr "ë¬´ì—‡ì„ ì°¾ê³  있나요?"
msgid "GlobalSearch|all GitLab"
msgstr "GitLab ì „ì²´"
-msgid "GlobalSearch|group"
-msgstr "그룹"
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr "프로ì íŠ¸"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr "í´ë¦½ë³´ë“œì— 소스 브랜치 ì´ë¦„ì„ ë³µì‚¬í–ˆìŠµë‹ˆë‹¤."
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "GitLabì— ë¶€ì—¬ëœ ìŠ¹ì¸ì„ 취소합니다. ì´ê²ƒì´ 서비스 ê³„ì •ì„ ë¬´íš¨í™”í•˜ì§€ëŠ” 않습니다."
+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 ""
@@ -19535,6 +19862,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -19886,6 +20216,9 @@ 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 ""
@@ -20144,6 +20477,9 @@ msgstr "GroupsNew|소스 ì¸ìŠ¤í„´ìŠ¤ì˜ URLì„ ìž…ë ¥í•˜ì‹­ì‹œì˜¤."
msgid "GroupsNew|GitLab source instance URL"
msgstr "GroupsNew|GitLab 소스 ì¸ìŠ¤í„´ìŠ¤ URL"
+msgid "GroupsNew|Groups"
+msgstr ""
+
msgid "GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}."
msgstr ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -20874,6 +21219,9 @@ 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 "보안 강화를 위해 ê³„ì •ì„ í™•ì¸í•´ì•¼ 합니다. ì¸ì¦ 코드를 %{email}으로 보냈습니다."
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ 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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21308,6 +21668,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22374,12 +22737,18 @@ msgstr "ì´ë¯¸ì§€ 삽입"
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23261,6 +23633,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23486,6 +23864,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "Jobs"
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ msgstr ""
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "GitLab Ultimate 무료 í‰ê°€íŒ 시작"
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr ""
+
msgid "LearnGitLab|Submit a merge request (MR)"
msgstr ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "그룹 떠나기"
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr "사용 가능한 저장소 목ë¡"
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ 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 "ë” ë¶ˆëŸ¬ì˜¤ê¸°"
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr "현재 프로ì íŠ¸ 잠금"
msgid "Locked"
msgstr "ìž ê¹€"
-msgid "Locked Files"
-msgstr "잠긴 파ì¼"
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25372,9 +25790,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr "머지 리퀘스트(MR)는 프로ì íŠ¸ì˜ 변경 ì‚¬í•­ì„ ì œì•ˆí•˜ê³ 
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 ""
@@ -26918,6 +27351,9 @@ msgstr[0] "마ì¼ìŠ¤í†¤"
msgid "Milestone due date"
msgstr "마ì¼ìŠ¤í†¤ 마ê°ì¼"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "현재 ë¼ì´ì„¼ìŠ¤ì—서는 마ì¼ìŠ¤í†¤ 목ë¡ì„ 사용할 수 없습니다."
@@ -27098,6 +27534,12 @@ msgstr ""
msgid "Minutes"
msgstr "분"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr "미러 방향"
@@ -27110,6 +27552,9 @@ msgstr "미러 저장소"
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr "미러 사용ìž"
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr "Machine Learning 실험 추ì ."
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr "새 스니펫"
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr "새 비밀번호"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "새 프로ì íŠ¸"
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28533,12 +29008,24 @@ msgstr "Notify|%{paragraph_start}안녕하세요 %{name}!%{paragraph_end} %{para
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|%{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 "%{updated_by_user_name}ê°€ 머지 리퀘스트 %{mr_link}ì— ëŒ€í•œ 새 ì»¤ë°‹ì„ í‘¸ì‹œí–ˆìŠµë‹ˆë‹¤."
+msgid "Notify|%{work_items} successfully imported."
+msgstr ""
+
msgid "Notify|A new GPG key was added to your account:"
msgstr ""
@@ -28587,9 +29074,18 @@ msgstr "CSV 파ì¼ì„ 파싱하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 형ì‹ì
msgid "Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check if these lines have an issue title."
msgstr "%{singular_or_plural_line}: %{error_lines}ì— ì˜¤ë¥˜ê°€ 발견ë˜ì—ˆìŠµë‹ˆë‹¤. ì´ ë¼ì¸ì¤‘ì— ì´ìŠˆ ì œëª©ì´ ìžˆëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤."
+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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr "ì´ íŒŒì¼ í˜•ì‹ì— 대한 미리보기가 없습니다."
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr "다ìŒì— ì˜í•´ íŠ¸ë¦¬ê±°ëœ íŒŒì´í”„ë¼ì¸ %{pipeline_link}"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
msgstr "파ì´í”„ë¼ì¸ì´ 수정ë˜ì—ˆìœ¼ë©° #%{pipeline_id} ì´ í†µê³¼ë˜ì—ˆìŠµë‹ˆë‹¤!"
+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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29152,6 +29654,9 @@ 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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30330,6 +30838,9 @@ msgstr "삭제 대기 중"
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "삭제 대기 중"
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr "Pin 코드"
-
msgid "Pipeline"
msgstr "파ì´í”„ë¼ì¸"
@@ -30720,6 +31228,9 @@ msgstr "CI 콘í…츠가 로드ë˜ê¸°ë¥¼ 기다리는 중..."
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 ""
@@ -30945,6 +31456,9 @@ 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 ""
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 ""
@@ -31197,6 +31723,9 @@ msgstr "ë¨¸ì§€ëœ YAML 보기"
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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,7 +32140,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr "다ì´ì–´ê·¸ëž¨ 미리보기"
msgid "Preview payload"
msgstr "페ì´ë¡œë“œ 미리보기"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr "대시보드로 ëŒì•„가기"
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr "ë°ì´í„°ë¥¼ 수집하ë„ë¡ ì œí’ˆ 분ì„ì„ êµ¬ì„±í•˜ëŠ” ë°©ë²•ì— ëŒ€í•œ 세부 정보입니다."
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr "계측 세부 정보"
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User activity"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ msgstr "연결 해제"
msgid "Profiles|Disconnect %{provider}"
msgstr "%{provider} ì—°ê²° ëŠê¸°"
+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|Do not show on profile"
msgstr "í”„ë¡œí•„ì— í‘œì‹œí•˜ì§€ ì•ŠìŒ"
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "ê³„ì •ì„ ì‚­ì œí•˜ê¸° ì „ì— ê·¸ë£¹ì˜ ì†Œìœ ê¶Œì„ ì´ì „하거나 삭제해야 합니다."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr "프로ì íŠ¸ 구성ì›"
msgid "Project milestone"
msgstr "프로ì íŠ¸ 마ì¼ìŠ¤í†¤"
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "프로ì íŠ¸ ì´ë¦„"
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr "프로ì íŠ¸ 경로"
@@ -32898,6 +33403,9 @@ 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 "프로ì íŠ¸ë¥¼ ì°¾ì„ ìˆ˜ 없거나 ì´ í”„ë¡œì íŠ¸ë¥¼ 보안 ëŒ€ì‹œë³´ë“œì— ì¶”ê°€í•  수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
@@ -32994,9 +33502,21 @@ msgstr "프로ì íŠ¸ ID: %{project_id}"
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 ""
@@ -33009,6 +33529,9 @@ msgstr "ProjectQualitySummary|ì´ íŽ˜ì´ì§€ë¥¼ 개선하는 ë° ë„ì›€ì„ ì£¼ì„¸
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,7 +33574,10 @@ msgstr ""
msgid "ProjectQualitySummary|This page helps you understand the code testing trends for your project. Let us know how we can improve it!"
msgstr "ProjectQualitySummary|ì´ íŽ˜ì´ì§€ëŠ” 프로ì íŠ¸ì˜ 코드 테스트 추세를 ì´í•´í•˜ëŠ” ë° ë„ì›€ì´ ë©ë‹ˆë‹¤. 개선할 수 있는 ë°©ë²•ì„ ì•Œë ¤ì£¼ì„¸ìš”!"
-msgid "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr "프로ì íŠ¸ë¥¼ 가져오는 ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33435,9 +33949,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -33870,6 +34381,9 @@ 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 ""
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr "서비스 ë°ìŠ¤í¬ 프로모션 닫기"
@@ -34176,12 +34690,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34395,6 +34938,9 @@ msgstr "아래 ë°°í¬ ê³„ì¸µìœ¼ë¡œ ì§€ì •ëœ ëª¨ë“  í™˜ê²½ì€ ìƒìœ„ ê·¸ë£¹ì— ì
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr "ProtectedEnvironment|%{project} / %{environment}ì— ë°°í¬ í—ˆìš©"
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr "리베ì´ìŠ¤ 완료"
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] ""
@@ -34978,13 +35518,13 @@ msgstr "회ì›ê°€ìž…"
msgid "Register / Sign In"
msgstr "ë“±ë¡ / 로그ì¸"
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36005,15 +36548,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr "재개"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr "재시ë„"
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr "관리ìž"
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ msgstr "프로ì íŠ¸ í•„í„°"
msgid "Runners|Get started with runners"
msgstr "Runners|러너 시작하기"
+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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr "만료ë˜ì§€ ì•ŠìŒ"
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr "소유ìž"
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ 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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ msgstr "러너 ì¸ì¦ í† í° ë§Œë£Œ"
msgid "Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired."
msgstr "Runner ì¸ì¦ 토í°ì€ ì„¤ì •ëœ ì£¼ê¸°ë¡œ 만료ë©ë‹ˆë‹¤. 만료ë˜ë©´ ìžë™ìœ¼ë¡œ 전환ë©ë‹ˆë‹¤."
+msgid "Runners|Runner created."
+msgstr ""
+
+msgid "Runners|Runner description"
+msgstr ""
+
msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
msgstr ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr "러너가 등ë¡ëœ 프로ì íŠ¸, 그룹 ë˜ëŠ” ì¸ìŠ¤í„´ìŠ¤. ì¸ìŠ¤í„´ìŠ¤ 실행기는 í•­ìƒ ê´€ë¦¬ìžê°€ 소유합니다."
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr "Runner|소유ìž"
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "실행중"
@@ -37042,6 +37654,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "ì¡°ì§ì˜ SSOê°€ GitLab ê³„ì •ì— ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤."
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr "ScanExecutionPolicy| %{time}ì—ì„œ%{period} %{days}"
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr "%{scopes} %{branches} %{agents} %{namespaces}ì— ëŒ€í•œ %{rules} ìž‘ì—…"
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr "ì—ì´ì „트"
msgid "ScanExecutionPolicy|branch"
msgstr "ScanExecutionPolicy|브랜치"
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr "네임스페ì´ìŠ¤ ë‚´"
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37689,24 +38310,27 @@ msgstr ""
msgid "Security"
msgstr "보안"
-msgid "Security & Compliance"
-msgstr "보안 ë° ì¤€ìˆ˜ 사항"
-
-msgid "Security Configuration"
-msgstr ""
-
msgid "Security Dashboard"
msgstr "보안 대시보드"
msgid "Security Finding not found"
msgstr ""
-msgid "Security dashboard"
-msgstr "보안 대시보드"
+msgid "Security Policy project already exists."
+msgstr ""
+
+msgid "Security and Compliance"
+msgstr ""
+
+msgid "Security capabilities"
+msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
msgstr ""
+msgid "Security dashboard"
+msgstr "보안 대시보드"
+
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -37833,7 +38457,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 "보안 ì˜ì—­ì—ì„œ 모니터ë§í•  프로ì íŠ¸ë¥¼ 추가하거나 제거합니다. ì´ ëª©ë¡ì— í¬í•¨ëœ 프로ì íŠ¸ì˜ 결과는 보안 대시보드 ë° ì·¨ì•½ì  ë³´ê³ ì„œì— í‘œì‹œë©ë‹ˆë‹¤."
@@ -38796,6 +39444,9 @@ msgstr "ë¼ë²¨ ì„ íƒ"
msgid "Select labels"
msgstr "ë¼ë²¨ ì„ íƒ"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr "셀프 ëª¨ë‹ˆí„°ë§ í”„ë¡œì íŠ¸ê°€ 성공ì ìœ¼ë¡œ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "셀프 ëª¨ë‹ˆí„°ë§ í”„ë¡œì íŠ¸ê°€ ì‚­ì œë˜ì§€ 않았습니다. 오류 메시지가 있는지 로그를 확ì¸í•˜ì‹­ì‹œì˜¤."
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ 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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr "로그ì¸"
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 "타임ë¼ì¸ ì´ë²¤íŠ¸ë¥¼ 추가하는 ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr "스팸 ë° ì•ˆí‹°ë´‡ 보호"
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr "ê·€í•˜ì˜ êµ¬ë…ì„ ì°¾ì„ ìˆ˜ 없습니다"
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr "ê·€í•˜ì˜ êµ¬ë…ì´ ë§Œë£Œë˜ì—ˆìŠµë‹ˆë‹¤"
@@ -41622,9 +42330,27 @@ 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 ""
@@ -42029,12 +42755,12 @@ msgstr ""
msgid "Test"
msgstr "테스트"
-msgid "Test Cases"
-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] ""
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr "ì´ìŠˆ 트래커는 프로ì íŠ¸ì—ì„œ 개선해야하거나 í•´ê²°í•´ì•
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr "Prometheus 서버가 \"ìž˜ëª»ëœ ìš”ì²­\"으로 ì‘답했습니다. 쿼리가 정확한지, 그리고 해당 Prometheus 버전ì—ì„œ 지ì›ë˜ëŠ”지 확ì¸í•˜ì„¸ìš”. %{documentationLink}"
+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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42341,6 +43067,9 @@ 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 ""
@@ -42652,8 +43381,17 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
-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 ""
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr "ì„ íƒí•œ ê·¸ë£¹ì˜ ìƒìœ„ ë¼ë²¨ì„ 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -43747,10 +44485,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44199,6 +44934,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44684,6 +45422,9 @@ 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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -44877,9 +45615,6 @@ msgstr "트위터:"
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -44925,12 +45660,6 @@ msgstr ""
msgid "Type to search"
msgstr "입력하여 검색"
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr "URL"
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr "차단 해제"
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr "무제한"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ 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 "프로ì íŠ¸ ì´ë¦„, 주제, 설명 ë° ì•„ë°”íƒ€ë¥¼ ì—…ë°ì´íŠ¸í•©ë‹ˆë‹¤."
@@ -45474,6 +46224,9 @@ msgstr ""
msgid "Usage statistics"
msgstr "사용 통계"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr "Container Registryì— ëŒ€í•œ 프로ì íŠ¸ 수준 스토리지 통계는 방향성만 제공ë˜ë©° ì¸ìŠ¤í„´ìŠ¤ ì „ì²´ 중복 ì œê±°ì— ëŒ€í•œ ì ˆê° íš¨ê³¼ëŠ” í¬í•¨ë˜ì§€ 않습니다."
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr "업로드"
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46360,6 +47125,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46643,9 +47417,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr "전체 비난 보기"
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -46846,6 +47617,69 @@ 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|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 ""
@@ -47236,12 +48070,6 @@ msgstr "프로ì íŠ¸ %{project}ì—ì„œ %{term} ê³¼ ì¼ì¹˜í•˜ëŠ” %{scope}를 ì°¾ì
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "Prometheus ì„œë²„ì— ì—°ê²°í•  수 없습니다. 서버가 ë” ì´ìƒ 존재하지 않거나 설정 세부 정보를 ì—…ë°ì´íŠ¸í•´ì•¼ 합니다."
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "%{humanized_resource_name}ì—ì„œ 잠재ì ì¸ ìŠ¤íŒ¸ì„ íƒì§€í–ˆìŠµë‹ˆë‹¤. 계ì†í•˜ë ¤ë©´ reCAPTCHA를 진행하세요."
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "위키"
@@ -47955,7 +48790,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr "ë°˜ë³µì— ì¶”ê°€"
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "ì •ë§ íŽ¸ì§‘ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr "ì¸ì‹œë˜íŠ¸"
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr "태스í¬"
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "릴리스 노트를 작성하거나 여기로 파ì¼ì„ ëŒì–´ë‹¤ 놓으십시오…"
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ 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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,7 +49862,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49024,6 +49892,9 @@ 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 "ë‚˜ì˜ ê·¸ë£¹"
@@ -49048,6 +49919,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "ë‚˜ì˜ í•  ì¼ ëª©ë¡"
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "승ì¸ëœ 애플리케ì´ì…˜ (%{size})"
@@ -49102,9 +49979,6 @@ msgstr "승ì¸ëœ 애플리케ì´ì…˜"
msgid "Your browser does not support iFrames"
msgstr "브ë¼ìš°ì €ê°€ iFrames를 지ì›í•˜ì§€ 않습니다"
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr "ì¼ë°˜ ë³´ê³ "
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -49915,6 +50795,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] "파ì¼"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr "팔로잉"
-
msgid "for"
msgstr "for"
@@ -50521,10 +51404,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr "%{metricsLinkStart} 메모리 사용률 %{metricsLinkEnd} ì´ %{memoryFr
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart} 메모리 사용률 %{metricsLinkEnd} ì´ %{memoryFrom}MB ì—ì„œ %{emphasisStart} 변하지 않았습니다. %{emphasisEnd}"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr "mrWidget|ìŠ¹ì¸ ê·œì¹™ %{rules} ì´ ìœ íš¨í•˜ì§€ 않습니다. GitLabì€ ë¨¸ì§€ 리퀘스트 ì°¨ë‹¨ì„ í•´ì œí•˜ê¸° 위해 ì´ ê·œì¹™ì„ ìžë™ìœ¼ë¡œ 승ì¸í–ˆìŠµë‹ˆë‹¤. %{link}"
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr "ìŠ¹ì¸ ê·œì¹™ %{rules} ì´ ìœ íš¨í•˜ì§€ 않습니다. GitLabì€ ë¨¸ì§€ 리퀘스트를 차단 해제하기 위해 ì´ëŸ¬í•œ ê·œì¹™ì„ ìžë™ìœ¼ë¡œ 승ì¸í–ˆìŠµë‹ˆë‹¤. %{link}"
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,84 +51690,30 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr "머지 차단ë¨: 요구ë˜ëŠ” 모든 승ì¸ì´ 필요합니다."
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "머지 차단ë¨: 모든 스레드를 해결해야 합니다."
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr "머지 차단ë¨: 패스트-í¬ì›Œë“œ 머지가 불가능합니다. ì´ ìš”ì²­ì„ ë¨¸ì§€í•˜ë ¤ë©´ 먼저 로컬ì—ì„œ 리베ì´ìŠ¤í•˜ì‹­ì‹œì˜¤."
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr "머지 차단ë¨: 파ì´í”„ë¼ì¸ì´ 성공해야 합니다. ìˆ˜ë™ ìž‘ì—…ì´ ê³„ì†ë˜ê¸°ë¥¼ 기다리고 있습니다."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "머지 실패."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr "머지:"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr "머지 중! 변경 ì‚¬í•­ì´ ê³§ ì ìš©ë©ë‹ˆë‹¤â€¦"
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr "머지 중! ë‘구ë‘구ë‘구…"
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|Merging! The changes are leaving the station…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Merging! This is going to be great…"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "머지 중! ê±°ì˜ ë‹¤ ë습니다…"
-
-msgid "mrWidget|More information"
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "ê·œì¹™ì˜ ê¸°ì¤€ê³¼ ì¼ì¹˜í•˜ëŠ” 사용ìžê°€ 없습니다."
-
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "ìžë™ìœ¼ë¡œ 머지할 준비가 ë˜ì—ˆìŠµë‹ˆë‹¤. ì´ ì €ìž¥ì†Œì˜ ì“°ê¸° ê¶Œí•œì´ ìžˆëŠ” ì‚¬ëžŒì´ ë¨¸ì§€í•  수 있ë„ë¡ ìš”ì²­í•˜ì„¸ìš”."
-
msgid "mrWidget|Refresh"
msgstr "새로고침"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ku_TR/gitlab.po b/locale/ku_TR/gitlab.po
index 71313b02f23..ee76ab86871 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ky_KG/gitlab.po b/locale/ky_KG/gitlab.po
index dd603cbcce2..9fc77744ef1 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/lt_LT/gitlab.po b/locale/lt_LT/gitlab.po
index 1b6cabeaaab..24c1eca51b6 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -566,6 +566,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -615,6 +622,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -622,6 +636,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -812,6 +832,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1013,6 +1036,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1028,9 +1054,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1168,6 +1191,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1446,6 +1472,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1750,13 +1779,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -2089,9 +2111,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2506,9 +2525,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2530,6 +2546,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2539,6 +2558,9 @@ 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 ""
@@ -2653,6 +2675,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2791,6 +2816,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3970,40 +3998,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4375,6 +4373,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -5007,6 +5008,9 @@ 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 ""
@@ -5016,6 +5020,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5094,13 +5215,28 @@ 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|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."
+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."
@@ -5249,12 +5385,18 @@ 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 ""
@@ -5509,6 +5651,13 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5521,6 +5670,20 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5596,9 +5759,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5611,6 +5771,9 @@ 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 ""
@@ -5968,7 +6131,7 @@ msgstr[3] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6224,9 +6387,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6239,9 +6399,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6251,9 +6408,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6635,6 +6801,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6662,9 +6831,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6734,6 +6900,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6749,9 +6918,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6887,27 +7053,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6917,9 +7065,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7062,6 +7207,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7290,15 +7438,27 @@ msgstr[3] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7311,9 +7471,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7431,9 +7588,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7452,6 +7606,15 @@ 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 ""
@@ -7482,10 +7645,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7527,6 +7693,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8296,6 +8465,15 @@ 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 ""
@@ -8413,6 +8591,9 @@ 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 ""
@@ -8799,6 +8980,9 @@ 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 ""
@@ -8841,6 +9025,9 @@ 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 ""
@@ -8850,16 +9037,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8886,6 +9070,9 @@ 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 ""
@@ -8904,6 +9091,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8922,6 +9112,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9042,12 +9235,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9126,10 +9325,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9159,6 +9358,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9944,6 +10146,9 @@ 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 ""
@@ -10235,7 +10440,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10629,9 +10834,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10644,6 +10846,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10713,12 +10918,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10827,9 +11041,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10848,9 +11077,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11478,6 +11704,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11520,12 +11749,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11541,6 +11779,9 @@ 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 ""
@@ -11586,7 +11827,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11607,7 +11851,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11679,6 +11923,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11925,7 +12172,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12114,6 +12361,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12363,9 +12613,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12573,6 +12820,9 @@ 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 ""
@@ -12672,7 +12922,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12841,9 +13091,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13757,6 +14004,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13799,6 +14049,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14566,6 +14819,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14669,10 +14925,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14777,6 +15036,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14972,6 +15234,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15131,9 +15396,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15573,6 +15835,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15597,6 +15862,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15615,9 +15883,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16074,6 +16348,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16119,7 +16396,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16137,6 +16414,9 @@ 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 ""
@@ -16431,6 +16711,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16542,6 +16825,9 @@ 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 ""
@@ -16830,6 +17116,9 @@ 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 ""
@@ -17110,6 +17399,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17134,6 +17426,9 @@ 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 ""
@@ -17335,6 +17630,9 @@ 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 ""
@@ -17353,6 +17651,9 @@ 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 ""
@@ -17929,9 +18230,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18055,6 +18353,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18211,9 +18512,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18355,9 +18653,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19174,13 +19469,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19231,6 +19535,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19255,6 +19562,12 @@ 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 ""
@@ -19270,9 +19583,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19321,13 +19631,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19421,12 +19724,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19466,6 +19775,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19478,13 +19790,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19502,7 +19814,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19556,6 +19868,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19628,6 +19943,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19682,15 +20000,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19907,6 +20219,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20096,6 +20432,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20447,6 +20786,9 @@ 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 ""
@@ -20705,6 +21047,9 @@ 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 ""
@@ -20720,6 +21065,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21100,6 +21451,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21447,6 +21801,9 @@ 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 ""
@@ -21546,6 +21903,9 @@ 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 ""
@@ -21588,15 +21948,24 @@ 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 ""
@@ -21657,7 +22026,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21887,6 +22256,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22293,7 +22665,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22956,12 +23328,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23137,10 +23515,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23158,6 +23539,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23446,7 +23830,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23575,9 +23959,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23849,6 +24230,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24074,6 +24461,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24611,9 +25001,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25306,6 +25711,15 @@ 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 ""
@@ -25387,6 +25801,9 @@ 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 ""
@@ -25396,6 +25813,9 @@ 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 ""
@@ -25411,9 +25831,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25429,6 +25846,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25690,6 +26110,13 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Line changes"
msgstr ""
@@ -25717,6 +26144,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25810,9 +26240,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25855,6 +26282,9 @@ 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 ""
@@ -25894,6 +26324,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25912,9 +26345,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25984,9 +26414,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26023,10 +26450,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26518,6 +26942,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26599,12 +27026,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26829,18 +27265,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26913,9 +27340,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26928,6 +27352,27 @@ 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 ""
@@ -27542,6 +27987,9 @@ msgstr[3] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27722,6 +28170,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27734,6 +28188,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27794,31 +28251,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28164,6 +28636,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28212,10 +28687,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28330,9 +28811,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28420,9 +28898,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28777,6 +29252,15 @@ 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 ""
@@ -28862,13 +29346,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29178,12 +29665,24 @@ 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|%{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 ""
@@ -29232,9 +29731,18 @@ 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 ""
@@ -29262,9 +29770,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29301,6 +29806,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29310,6 +29818,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29322,6 +29833,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29800,6 +30314,9 @@ 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 ""
@@ -29869,9 +30386,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30167,28 +30681,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30993,6 +31513,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31182,9 +31705,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31383,6 +31903,9 @@ 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 ""
@@ -31608,6 +32131,9 @@ 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 ""
@@ -31659,9 +32185,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31707,6 +32230,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31758,7 +32287,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31767,6 +32296,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31803,13 +32335,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31839,6 +32371,12 @@ 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 ""
@@ -31860,6 +32398,9 @@ 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 ""
@@ -31869,6 +32410,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32184,6 +32728,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32205,6 +32752,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32265,7 +32815,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32619,6 +33169,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32688,88 +33241,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32778,34 +33274,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32814,24 +33313,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32844,22 +33337,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32868,70 +33370,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33099,6 +33604,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33348,7 +33859,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33522,6 +34033,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33534,6 +34048,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33561,6 +34078,9 @@ 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 ""
@@ -33657,9 +34177,21 @@ 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 ""
@@ -33672,6 +34204,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33714,7 +34249,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33729,9 +34267,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33861,9 +34396,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34014,9 +34546,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34059,9 +34588,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34098,9 +34624,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34143,10 +34666,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34170,9 +34693,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34407,6 +34927,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34533,6 +35056,9 @@ 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 ""
@@ -34548,6 +35074,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34728,9 +35257,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34839,12 +35365,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35016,9 +35536,29 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35028,10 +35568,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35040,15 +35592,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35058,6 +35619,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35514,24 +36078,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35607,6 +36162,9 @@ 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] ""
@@ -35644,13 +36202,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35743,6 +36301,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36692,15 +37253,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36883,9 +37450,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37059,9 +37623,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37144,6 +37705,9 @@ 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|Administrator"
msgstr ""
@@ -37207,6 +37771,9 @@ 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 ""
@@ -37225,6 +37792,9 @@ 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 ""
@@ -37283,9 +37853,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37298,6 +37874,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37316,6 +37898,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37343,6 +37928,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37352,6 +37943,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37364,6 +37958,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37406,6 +38003,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37440,6 +38040,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37455,6 +38061,9 @@ 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 ""
@@ -37479,6 +38088,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37494,6 +38106,12 @@ 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 ""
@@ -37566,9 +38184,15 @@ 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 ""
@@ -37602,6 +38226,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37611,6 +38241,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37630,6 +38263,9 @@ msgstr[3] ""
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 runner has not run any jobs."
msgstr ""
@@ -37678,6 +38314,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37732,15 +38371,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37762,6 +38392,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37786,9 +38419,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37918,16 +38548,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37969,9 +38602,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38442,22 +39081,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
msgstr ""
-msgid "Security dashboard"
+msgid "Security configuration"
msgstr ""
-msgid "Security navigation"
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38586,7 +39228,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38700,6 +39342,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38805,9 +39450,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38898,6 +39552,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38919,6 +39576,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38928,6 +39588,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38994,7 +39657,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39072,6 +39735,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39549,6 +40215,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39651,6 +40320,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39663,6 +40335,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39675,6 +40350,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39777,6 +40455,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39912,6 +40596,9 @@ 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 ""
@@ -39939,7 +40626,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40192,6 +40879,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40358,9 +41048,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40514,15 +41201,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40532,6 +41237,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40541,6 +41249,9 @@ 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 ""
@@ -40574,9 +41285,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40760,12 +41477,18 @@ 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 ""
@@ -41177,9 +41900,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41243,6 +41963,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41492,6 +42215,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42137,16 +42863,22 @@ 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|Sync subscription request."
+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}."
@@ -42155,7 +42887,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42186,9 +42918,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42231,9 +42960,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42384,9 +43110,27 @@ 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 ""
@@ -42797,10 +43541,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42826,9 +43570,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42955,6 +43696,9 @@ 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 ""
@@ -43016,6 +43760,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43058,9 +43805,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -43118,6 +43862,9 @@ 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 ""
@@ -43435,7 +44182,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43780,6 +44536,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43969,13 +44728,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44476,6 +45229,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44530,10 +45286,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44988,6 +45741,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45479,6 +46235,9 @@ 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 ""
@@ -45570,9 +46329,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45675,9 +46431,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45723,12 +46476,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45834,6 +46581,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45933,6 +46683,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45990,6 +46743,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46077,6 +46839,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46146,6 +46911,9 @@ 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 ""
@@ -46272,6 +47040,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46443,6 +47214,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46647,6 +47421,9 @@ 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 ""
@@ -46659,6 +47436,9 @@ 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 ""
@@ -46735,6 +47515,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47161,6 +47944,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47272,6 +48058,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47416,6 +48205,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47447,9 +48239,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47656,6 +48445,69 @@ 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|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 ""
@@ -48046,12 +48898,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48103,9 +48949,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48247,6 +49090,9 @@ 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 ""
@@ -48512,6 +49358,13 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -48552,6 +49405,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48771,7 +49627,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48819,6 +49675,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48844,6 +49703,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48868,9 +49736,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48991,6 +49865,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49027,6 +49904,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49057,6 +49937,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49460,9 +50343,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49635,12 +50515,18 @@ 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 ""
@@ -49813,6 +50699,9 @@ 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 ""
@@ -49822,7 +50711,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49852,6 +50741,9 @@ 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 ""
@@ -49876,6 +50768,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49921,6 +50816,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49930,9 +50828,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49963,6 +50858,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50124,6 +51022,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50367,6 +51268,9 @@ 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 ""
@@ -50709,9 +51613,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50779,6 +51680,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50809,6 +51713,9 @@ 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 ""
@@ -51096,9 +52003,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51412,10 +52316,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51477,6 +52387,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51492,6 +52480,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51519,12 +52513,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51540,6 +52528,9 @@ 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 ""
@@ -51623,82 +52614,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51761,9 +52698,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51788,6 +52722,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/mk_MK/gitlab.po b/locale/mk_MK/gitlab.po
index f2e46cf017a..8705c18b837 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ml_IN/gitlab.po b/locale/ml_IN/gitlab.po
index 9e4c2dfa85b..9377fd74234 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/mn_MN/gitlab.po b/locale/mn_MN/gitlab.po
index ae465c5bb9a..9fdb50f4cbd 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ms_MY/gitlab.po b/locale/ms_MY/gitlab.po
index 5c1ab335beb..1730bf58f6f 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -539,6 +553,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -740,6 +757,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -755,9 +775,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -889,6 +906,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1675,9 +1694,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2092,9 +2108,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2116,6 +2129,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2125,6 +2141,9 @@ 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 ""
@@ -2239,6 +2258,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2377,6 +2399,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3556,40 +3581,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3961,6 +3956,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4587,6 +4585,9 @@ 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 ""
@@ -4596,6 +4597,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4674,13 +4792,28 @@ 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|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."
+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."
@@ -4823,12 +4956,18 @@ 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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5080,6 +5223,14 @@ msgstr ""
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ 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 ""
@@ -5518,7 +5669,7 @@ msgstr[0] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5771,9 +5922,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5786,9 +5934,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5798,9 +5943,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6606,6 +6739,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -6846,9 +6994,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -6987,6 +7129,15 @@ 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 ""
@@ -7017,10 +7168,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7062,6 +7216,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7945,6 +8111,9 @@ 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 ""
@@ -8325,6 +8494,9 @@ 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 ""
@@ -8367,6 +8539,9 @@ 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 ""
@@ -8376,16 +8551,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8412,6 +8584,9 @@ 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 ""
@@ -8430,6 +8605,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8568,12 +8749,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,10 +8839,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10161,6 +10351,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10365,9 +10582,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ 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 ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11115,7 +11347,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11187,6 +11419,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11433,7 +11668,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,7 +12418,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13301,6 +13539,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,10 +14388,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15060,6 +15313,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15582,7 +15847,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 ""
@@ -16795,6 +17078,9 @@ 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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17662,9 +17951,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ 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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19121,15 +19430,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19535,6 +19862,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -19886,6 +20216,9 @@ 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 ""
@@ -20144,6 +20477,9 @@ 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 ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -20874,6 +21219,9 @@ 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 ""
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ 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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21308,6 +21668,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22374,12 +22737,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23261,6 +23633,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23486,6 +23864,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ 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 ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ 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 ""
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25372,9 +25790,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 ""
@@ -26918,6 +27351,9 @@ msgstr[0] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27098,6 +27534,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27110,6 +27552,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28533,12 +29008,24 @@ 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|%{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 ""
@@ -28587,9 +29074,18 @@ 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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29152,6 +29654,9 @@ 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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30330,6 +30838,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30720,6 +31228,9 @@ 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 ""
@@ -30945,6 +31456,9 @@ 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 ""
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 ""
@@ -31197,6 +31723,9 @@ 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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,7 +32140,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -32898,6 +33403,9 @@ 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 ""
@@ -32994,9 +33502,21 @@ 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 ""
@@ -33009,6 +33529,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,7 +33574,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33435,9 +33949,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -33870,6 +34381,9 @@ 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 ""
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34176,12 +34690,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34395,6 +34938,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] ""
@@ -34978,13 +35518,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36005,15 +36548,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr ""
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ 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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ 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 ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37042,6 +37654,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37689,22 +38310,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -37833,7 +38457,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -38796,6 +39444,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ 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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 ""
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41622,9 +42330,27 @@ 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 ""
@@ -42029,10 +42755,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42341,6 +43067,9 @@ 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 ""
@@ -42652,7 +43381,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -43747,10 +44485,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44199,6 +44934,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44684,6 +45422,9 @@ 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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -44877,9 +45615,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -44925,12 +45660,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ 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 ""
@@ -45474,6 +46224,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46360,6 +47125,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46643,9 +47417,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -46846,6 +47617,69 @@ 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|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 ""
@@ -47236,12 +48070,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -47955,7 +48790,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ 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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,7 +49862,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49024,6 +49892,9 @@ 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 ""
@@ -49048,6 +49919,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49102,9 +49979,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -49915,6 +50795,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50521,10 +51404,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,82 +51690,28 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/nb_NO/gitlab.po b/locale/nb_NO/gitlab.po
index 49aa90e1305..8bc2725f718 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr " %{start} til %{end}"
@@ -426,6 +426,11 @@ msgid_plural "%d unresolved threads"
msgstr[0] "%d uoppklart tråd"
msgstr[1] "%d uoppklarte tråder"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d sårbarhet"
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "%d advarsel funnet:"
msgstr[1] "%d advarsler funnet:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s ekstra commit er utelatt for å forhindre ytelsesproblemer."
msgstr[1] "%s ekstra commiter er utelatt for å forhindre ytelsesproblemer."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} og %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr "%{count} relatert(e) %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "%{count} valgt"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} totalvekt"
@@ -831,6 +850,9 @@ msgstr "%{level_name} er ikke tillatt siden utgreiningskildeprosjektet har laver
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}, og %{awardsListLength} til"
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} kan bli flettet"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} viser de første %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (utløpt)"
@@ -982,6 +1001,9 @@ msgstr "%{reportType} oppdaget %{totalStart}%{total}%{totalEnd} potensial %{vuln
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr "%{user} opprettet et epos: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} opprettet en sak: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} er ikke inkludert i listen"
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] "1 distribusjonsnøkkel"
msgstr[1] "%d distribusjonsnøkler"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "1 følger"
-msgstr[1] "%{count} følgere"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 gruppe"
@@ -1813,9 +1833,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr "API-hjelp"
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr "Legg til en sammenklappbar seksjon"
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr "Legg til en kommentar til denne linjen"
@@ -2254,6 +2268,9 @@ msgstr "Legg til en hjemmeside på din wiki som inneholder informasjon om prosje
msgid "Add a new issue"
msgstr "Legg til en ny sak"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Legg til en nummerert liste"
@@ -2263,6 +2280,9 @@ msgstr ""
msgid "Add a related issue"
msgstr "Legg til en related sak"
+msgid "Add a reply"
+msgstr ""
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -2377,6 +2397,9 @@ msgstr "Legg til ny applikasjon"
msgid "Add new directory"
msgstr "Legg til ny katalog"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr "Ytterligere minutter:"
msgid "Additional text"
msgstr "Ytterligere tekst"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr "Ytterligere tekst for påloggings- og hjelpesiden."
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
msgstr "Alle medlemmer"
+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 "Alle grener"
@@ -4727,6 +4726,9 @@ msgstr "En uventet feil oppstod under oppstart av netterminalen."
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "En uventet feil oppstod under stopping av netterminalen."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr "En ukjent feil oppstod under innlasting av denne grafen."
@@ -4736,6 +4738,123 @@ msgstr "En ukjent feil har oppstått."
msgid "Analytics"
msgstr "Analyser"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analyser avhengighetene dine for kjente sårbarheter."
@@ -4814,13 +4933,28 @@ msgstr "Tilføy til kommentaren med %{shrug}"
msgid "Append the comment with %{tableflip}"
msgstr "Tilføy kommentaren med %{tableflip}"
+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|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."
+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."
@@ -4965,12 +5099,18 @@ msgstr "Lagre endringer"
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 ""
@@ -5215,6 +5355,11 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Godkjenn en fletteforespørsel"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5227,6 +5372,16 @@ msgstr "Godkjent"
msgid "Approved MRs"
msgstr "Godkjente FF-er"
+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 "Godkjente den nåværende fletteforespørselen."
@@ -5302,9 +5457,6 @@ msgstr "Er du sikker på at du vil %{action} %{name}?"
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr "Er du sikker på at du vil slette %{name}?"
+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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] "Legger ved %d filer"
msgid "Attaching the file failed."
msgstr "Vedlegging av filen mislyktes."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr "Skapt %{timeago} av %{author}"
msgid "Authorization code:"
msgstr "Autorisasjonskode:"
-msgid "Authorization required"
-msgstr "Autorisasjon påkrevd"
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr "Autoriser"
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr "Vil du autorisere at %{user} kan bruke kontoen din?"
-
msgid "Authorized %{new_chat_name}"
msgstr "Autoriserte %{new_chat_name}"
@@ -5949,9 +6098,18 @@ msgstr "Autorisert den"
msgid "Authorized applications (%{size})"
msgstr "Autoriserte applikasjoner (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr "Nedenfor vil du finne alle de gruppene som er offentlige."
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr "Hvis du ønsker å nedgradere planen din, kan du kontakte %{support_link
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr "Oppgrader"
msgid "BillingPlan|Upgrade for free"
msgstr "Oppgrader gratis"
-msgid "Billings|%{planName} plan"
-msgstr "%{planName}-plan"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr "Forleng prøveperioden"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr "Bitbucket-import"
msgid "Blame"
msgstr "Ã…rsaksliste"
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ msgstr[1] ""
msgid "Boards|Collapse"
msgstr "Klapp sammen"
+msgid "Boards|Create new epic"
+msgstr ""
+
+msgid "Boards|Create new issue"
+msgstr ""
+
msgid "Boards|Edit board"
msgstr "Rediger bord"
+msgid "Boards|Edit list settings"
+msgstr ""
+
msgid "Boards|Expand"
msgstr "Utvid"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr ""
+msgid "Boards|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr "Nytt epos"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ msgstr "Kan ikke benytte dette forslaget."
msgid "Can't be empty"
msgstr "Kan ikke være tom"
+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 "Kan ikke opprette utdrag: %{err}"
@@ -8101,6 +8271,9 @@ msgstr ""
msgid "Cannot import because issues are not available in this project."
msgstr "Kan ikke importere fordi saker ikke er tilgjengelige i dette prosjektet."
+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 ""
@@ -8483,6 +8656,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+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 ""
@@ -8525,6 +8701,9 @@ msgstr "Land"
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 "Opprett en ny gruppe"
@@ -8534,18 +8713,15 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "Rediger"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "Mislyktes i å bekrefte din ordre! Vennligst prøv igjen."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "Mislyktes i å bekrefte din ordre: %{message}. Vennligst prøv igjen."
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "Mislyktes i å laste inn land. Vennligst prøv igjen."
@@ -8570,6 +8746,9 @@ msgstr "GitLab-plan"
msgid "Checkout|Group"
msgstr "Gruppe"
+msgid "Checkout|Invalid coupon code. Enter a valid coupon code."
+msgstr ""
+
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
msgstr ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "Trenger du flere brukere? Kjøp GitLab for ditt %{company}."
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "Antall brukere"
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "Delstat"
@@ -8726,12 +8911,18 @@ msgstr "Velg hvilket innhold du vil se på en gruppes oversiktsside."
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 "Velg ditt rammeverk"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr "Datoperiode: %{range}"
@@ -8810,10 +9001,10 @@ msgstr "venter"
msgid "CiStatus|running"
msgstr "kjørende"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr "Beskyttet"
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr "Fjern variabel"
@@ -9624,6 +9818,9 @@ msgstr ""
msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
msgstr "Brukeren har ikke tilstrekkelige tillatelser til å opprette en sjetong for dette prosjektet"
+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 "Du har ikke tilstrekkelige tillatelser til å opprette en klyngeagent for dette prosjektet"
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "URL-en som brukes til å få tilgang til Kubernetes-API-en."
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr "Sammenlign GitLab-utgaver"
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "Sammenlign revisjoner"
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr "Sammenlign endringer med den nyeste commiten"
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr "Fullført"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "Komponent"
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "Konfidensialitet"
-msgid "Configuration"
-msgstr "Konfigurasjon"
-
msgid "Configuration help"
msgstr "Oppsettshjelp"
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr "Bidrag"
msgid "Contribution Analytics"
msgstr "Bidragsanalyse"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr "Bidrag per gruppemedlem"
msgid "Contributor"
msgstr "Bidragsyter"
-msgid "Contributors"
-msgstr "Bidragsytere"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr ""
@@ -11351,6 +11587,9 @@ msgstr "Kopier kommandoer"
msgid "Copy commit SHA"
msgstr "Kopier commit-SHA-en"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr "Kopier miljø"
@@ -11597,8 +11836,8 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
-msgstr "Land"
+msgid "Country / Region"
+msgstr ""
msgid "Counts"
msgstr ""
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr "Opprettet den"
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ msgstr "Innstillinger"
msgid "CurrentUser|Start an Ultimate trial"
msgstr ""
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr ""
+
msgid "Currently unable to fetch data for this pipeline."
msgstr ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr "DAST-oppsett"
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr "Slett rad"
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr "suksess"
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,12 +14567,15 @@ msgstr "Klarte ikke å legge til en ny kommentar. Vennligst prøv igjen."
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "Klarte ikke å opprette en ny diskusjon. Vennligst prøv igjen."
+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 discussion. Please try again."
msgstr "Klarte ikke å oppdatere diskusjonen. Vennligst prøv igjen."
-msgid "DesignManagement|Could not update note. Please try again."
-msgstr "Klarte ikke å oppdatere notisen. Vennligst prøv igjen."
-
msgid "DesignManagement|Deselect all"
msgstr "Avvelg alle"
@@ -14427,6 +14678,9 @@ msgstr "DevOps-adopsjon"
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr "Enheter (valgfritt)"
@@ -14622,6 +14876,9 @@ msgstr "Din bruk"
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr "Discord-varsler"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr "Oppdag"
-
msgid "Discover GitLab Geo"
msgstr "Oppdag GitLab Geo"
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr "Rediger beskrivelse"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "Rediger miljø"
@@ -15239,6 +15496,9 @@ msgstr "Rediger identiteten til %{user_name}"
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr "Rediger sidepanel"
@@ -15716,6 +15982,9 @@ msgstr "Skriv inn 2FA for adminmodus"
msgid "Enter Admin Mode"
msgstr "GÃ¥ inn i adminmodus"
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "Skriv inn et nummer"
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr "Epose-bord"
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "Eposen ble ikke funnet."
@@ -16184,6 +16459,9 @@ msgstr ""
msgid "Error creating new iteration"
msgstr "Feil under opprettelse av ny iterasjon"
+msgid "Error creating or updating PreScanVerificationStep: %{errors}"
+msgstr ""
+
msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ msgstr ""
msgid "Exceptions"
msgstr "Unntak"
+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 "Ekskludert innflettings-commiter. Begrenset til %{limit} commiter."
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr "Feb"
msgid "February"
msgstr "Februar"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr "Filtrer rørledninger"
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "Filtrerresultater"
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr "Format: %{dateFormat}"
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr "GitLab-sider"
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ msgstr ""
msgid "GitLab commit"
msgstr "GitLab-commit"
+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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr "GitLab-gruppe: %{source_link}"
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr "GitLab-versjon"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr "Uverifisert"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use unique domain"
+msgstr ""
+
msgid "GitLabPages|Verified"
msgstr "Verifisert"
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr "Gitea-importering"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr "Gitt tilgang %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr "Hva søker du etter?"
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr "GlobalSearch|i %{scope}"
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 "Jeg forstår"
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr "Gruppenavigasjon"
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr "Gruppeoversikts-innhold"
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr "Ingen importalternativer er tilgjengelige"
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "Hei, %{username}!"
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr "Importering av prosjektet mislyktes"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr "Sett inn bilde"
msgid "Insert link"
msgstr "Sett inn lenke"
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr "Sett inn rad etter"
msgid "Insert row before"
msgstr "Sett inn rad før"
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "Sett inn forslag"
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr "Ugyldig kodelager-filbane"
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr "Saksrapporttype"
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr "Saken kunne ikke bli funnet."
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr "Tittel"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr "Jobben ble forsøkt på nytt"
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "Jobber"
@@ -24910,6 +25309,15 @@ msgstr "Lær mer."
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 "Legg til kodeeiere"
@@ -24991,6 +25399,9 @@ msgstr "Sett opp arbeidsområdet ditt"
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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr "OK, da setter vi i gang"
@@ -25033,6 +25444,9 @@ msgstr "Forlat adminmodus"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Forlat gruppen"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr "Linjeendringer"
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr "Lenken er kopiert"
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr "Lenketekst"
@@ -25402,9 +25824,6 @@ msgstr "List opp tilgjengelige kodelagre"
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr "Liste over alle innflettings-commits"
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 "Laster inn mer"
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr "Lås til nåværende prosjekter"
msgid "Locked"
msgstr "LÃ¥st"
-msgid "Locked Files"
-msgstr "LÃ¥ste filer"
-
msgid "Locked by %{fileLockUserName}"
msgstr "LÃ¥st av %{fileLockUserName}"
@@ -25576,9 +25998,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "INNFLETTET"
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr "Vis kun endringer"
msgid "MRDiff|Show full file"
msgstr "Vis hele filen"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr "Maks push-størrelse"
msgid "Maximum push size (MB)"
msgstr "Maksimal pushstørrelse (MB)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr "Innflettingen er forhindret: fletteforespørselen må merkes som klar. Den er fortsatt merket som et utkast."
-
-msgid "Merge blocked: new changes were just added."
-msgstr "Innflettingen er blokkert: nye endringer ble nettopp lagt til."
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr "Innflettingen er forhindret: rørledningen må lykkes. Den venter på at en manuell jobb skal fortsette."
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ msgstr ""
msgid "Merge..."
msgstr "Flett …"
+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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] "Milepæler"
msgid "Milestone due date"
msgstr "Milepælens forfallsdato"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr "Minutter"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr "Speilingsretning"
@@ -27318,6 +27764,9 @@ msgstr "Speil kodelager"
msgid "Mirror settings are only available to GitLab administrators."
msgstr "Speilingsinnstillinger er bare tilgjengelige for GitLab-administratorer."
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr "Speil bruker"
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr "Navnerom"
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr "Nytt krav"
msgid "New Snippet"
msgstr "Nytt utdrag"
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr "Ny bruker"
@@ -28000,9 +28470,6 @@ msgstr "Nytt navn"
msgid "New password"
msgstr "Nytt passord"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "Nytt prosjekt"
@@ -28357,6 +28824,15 @@ 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 "Ingen kilde er valgt"
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr "Avventende kommentarer"
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "Venter på sletting"
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr "Velg et navn"
-msgid "Pin code"
-msgstr "PIN-kode"
-
msgid "Pipeline"
msgstr "Rørledning"
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ msgstr "Rørledninger"
msgid "Pipelines charts"
msgstr "Rørledningsdiagrammer"
+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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr "Eier"
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "Vennligst skriv inn et nummer som ikke er negativt"
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,8 +32365,8 @@ msgstr "Vennligst velg"
msgid "Please select a Jira project"
msgstr "Vennligst velg et Jira-prosjekt"
-msgid "Please select a country"
-msgstr "Vennligst velg et land"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr ""
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "Tidligere artefakter"
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr "Fortsett"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User activity"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ msgstr "Koble fra"
msgid "Profiles|Disconnect %{provider}"
msgstr "Koble fra %{provider}"
+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|Do not show on profile"
msgstr "Vis ikke på profilen"
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Du må overføre eierskapet eller slette disse gruppene før du kan slette kontoen din."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr "Prosjektmedlemmer"
msgid "Project milestone"
msgstr "Prosjektmilepæl"
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Prosjektets navn"
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr "Prosjektfilbane"
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ msgstr "Prosjekt-ID: %{project_id}"
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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,8 +33799,11 @@ 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 "ProjectSelect| or group"
-msgstr "eller gruppe"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
msgid "ProjectSelect|No matching results"
msgstr ""
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr "Tillat"
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr "Internt"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr "Saker"
@@ -33617,9 +34138,6 @@ msgstr "Fletteforespørsler"
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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr "Fletteforslag"
@@ -33656,9 +34174,6 @@ msgstr "Sider"
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "Rørledningene må lykkes"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
-msgstr "Sikkerhet og standarder"
+msgid "ProjectSettings|Security and Compliance"
+msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr "Rørledninger som hoppes over blir ansett som vellykkede"
-
msgid "ProjectSettings|Snippets"
msgstr "Utdrag"
@@ -33965,6 +34477,9 @@ msgstr "Prosjekter (%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 "Ingen importalternativer er tilgjengelige"
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "Prosjektbeskrivelse %{tag_start}(valgfritt)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr "Når du har mange saker, kan det være vanskelig å få oversikt. Ved å
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} vil være skrivbar for utviklere. Er du sikker?"
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "Tillatt å distribuere"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr "Klar til å innflette!"
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr "Nullstill"
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr "Register"
msgid "Register / Sign In"
msgstr "Registrer / Logg inn"
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr "Avslått (lukket)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr "Kravet %{reference} har blitt gjenåpnet"
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr ""
-
msgid "Requirements"
msgstr "Krav"
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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr "Fortsett"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr "Forsøk igjen"
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ msgstr "Aktiv"
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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr "Navn"
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr "Beskyttet"
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ msgstr "Etiketter"
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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr "delt"
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "Kjører"
@@ -37282,6 +37900,9 @@ msgstr "SAML-oppdagelsessjetonger"
msgid "SAML for %{group_name}"
msgstr "SAML for %{group_name}"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr "SAST-oppsett"
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,24 +38567,27 @@ msgstr ""
msgid "Security"
msgstr "Sikkerhet"
-msgid "Security & Compliance"
-msgstr ""
-
-msgid "Security Configuration"
-msgstr "Sikkerhetsoppsett"
-
msgid "Security Dashboard"
msgstr "Sikkerhetskontrollpanel"
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 "Sikkerhetskontrollpanel"
-msgid "Security navigation"
-msgstr "Sikkerhetsnavigasjon"
-
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -38084,8 +38714,8 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr "SAST-analytikere"
-msgid "SecurityConfiguration|SAST Configuration"
-msgstr "SAST-oppsett"
+msgid "SecurityConfiguration|SAST configuration"
+msgstr ""
msgid "SecurityConfiguration|Secure your project"
msgstr ""
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr "%{firstProject}, %{secondProject}, og %{rest}"
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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."
@@ -39047,6 +39701,9 @@ msgstr "Velg stempel"
msgid "Select labels"
msgstr "Velg stempler"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr "Send"
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ msgstr ""
msgid "Set the milestone to %{milestone_reference}."
msgstr "Sett milepælen til %{milestone_reference}."
+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 ""
@@ -39437,7 +40112,7 @@ msgstr "Sett opp Jira-integrering"
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr "Vis filens innhold"
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr "Logg på"
-msgid "Sign in / Register"
-msgstr "Logg inn / Registrer"
-
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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr "Spam- og anti-bot-beskyttelse"
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr "Tjenestenavn"
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr "Status-sjekkinger"
@@ -41631,16 +42345,22 @@ msgstr ""
msgid "SuperSonics|Start free trial"
msgstr "Begynn gratis prøveperiode"
+msgid "SuperSonics|Subscription detail synchronization has started and will complete soon."
+msgstr ""
+
msgid "SuperSonics|Subscription details"
msgstr "Abonnementsdetaljer"
+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 "Synkroniser abonnementsdetaljer"
-msgid "SuperSonics|Sync subscription request."
+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}."
@@ -41649,8 +42369,8 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
-msgstr "Det er et tilkoblingsproblem."
+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 ""
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr "Abonnementet ditt"
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ msgstr "Etikettliste:"
msgid "Tag name"
msgstr "Navn på tag"
+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 ""
@@ -42285,12 +43017,12 @@ msgstr ""
msgid "Test"
msgstr "Test"
-msgid "Test Cases"
-msgstr "Testtilfeller"
-
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] ""
@@ -42310,9 +43042,6 @@ msgstr "Flytt testtilfelle"
msgid "TestCases|Moving test case"
msgstr "Flytter testtilfelle"
-msgid "TestCases|New Test Case"
-msgstr "Nytt testtilfelle"
-
msgid "TestCases|New test case"
msgstr "Nytt testtilfelle"
@@ -42439,6 +43168,9 @@ 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 "Tekststil"
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 "Snowplow-infokapseldomenet."
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 "Mappen har blitt vellykket opprettet."
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr "Denne variabelen kan ikke maskeres."
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ msgstr "For å komme i gang, skriv inn din Gitea-verts-URL og en %{link_to_perso
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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr "Twitter:"
msgid "Two-Factor Authentication"
msgstr "2-trinnautentisering"
-msgid "Two-Factor Authentication code"
-msgstr "2-trinnsautentiseringskode"
-
msgid "Two-factor Authentication"
msgstr "2-trinnautentisering"
@@ -45191,12 +45932,6 @@ msgstr "Type"
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr "U2F-enheter (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr "URL"
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr "Ubegrenset"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr "Ubrukte"
@@ -45614,6 +46367,9 @@ msgstr ""
msgid "Update your group name, description, avatar, and visibility."
msgstr "Oppdater ditt gruppenavn, beskrivelse, avatar og synlighet."
+msgid "Update your project name and description."
+msgstr ""
+
msgid "Update your project name, topics, description, and avatar."
msgstr ""
@@ -45740,6 +46496,9 @@ msgstr "Brukstrender"
msgid "Usage statistics"
msgstr "Bruksstatistikk"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr "Opplastinger"
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr "Brukeridentiteten ble vellykket opprettet."
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr "Vis dokumentasjon"
msgid "View eligible approvers"
msgstr "Vis kvalifiserte godkjennere"
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr "Alvorlighetsgrad"
+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|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 ""
@@ -47506,12 +48346,6 @@ msgstr "Vi fant ingen %{scope} som samsvarer med %{term} i prosjektet %{project}
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ msgstr "NÃ¥r du bruker %{code_open}http: //%{code_close} eller %{code_open}https
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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr "Skriv en milepælbeskrivelse …"
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr "Du har ikke registrert noen U2F-enheter enda."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ msgstr "Du må ha vedlikeholder-tilgang for å tvangsslette en lås"
msgid "You must provide a valid current password"
msgstr "Du må oppgi et gjeldende gyldig passord"
+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 "Du må oppgi ditt nåværende passord for å kunne endre den."
+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 ""
@@ -49261,6 +50133,9 @@ msgstr ""
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
msgstr "Ditt %{strong}%{plan_name}%{strong_close} abonnement på %{strong}%{namespace_name}%{strong_close} vil utløpe den %{strong}%{expires_on}%{strong_close}."
+msgid "Your Activity"
+msgstr ""
+
msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details."
msgstr ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ msgstr "Din GitLab-gruppe"
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 "Dine grupper"
@@ -49324,6 +50202,9 @@ msgstr "SSH-nøkkelen din ble slettet"
msgid "Your SSH keys (%{count})"
msgstr "SSH-nøklene dine (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "Din gjøremålsliste"
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr "Handlingen din lyktes."
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "Dine applikasjoner (%{size})"
@@ -49378,9 +50262,6 @@ msgstr "Dine autoriserte applikasjoner"
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr "Din kommentar vil bli forkastet."
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "Undersøk dette sikkerhetsproblemet ved å opprette en sak"
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "Hemmelig oppdaging"
@@ -50233,6 +51123,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Løsning"
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST)"
msgstr ""
@@ -50510,9 +51403,6 @@ msgstr[1] "filer"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr "følger"
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr "låst av %{path_lock_user_name} %{created_at}"
msgid "manual"
msgstr "manual"
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr "%{mergeError}."
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr "Godkjennelse er valgfritt"
msgid "mrWidget|Approval password is invalid."
msgstr "Godkjennelsespassordet er ugyldig."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr "Godkjenn"
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "mrWidget|Innflettingen er forhindret: alle tråder må oppklares."
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr "mrWidget|Innflettingen er forhindret: flettekonflikter må oppklares."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "Fletting mislyktes."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr "Flettet av"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
-msgstr ""
-
msgid "mrWidget|More information"
msgstr "Mer informasjon"
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase in progress"
+msgstr ""
+
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr "mrWidget|Brukere som kan skrive til kilde- eller målgrenene kan oppklare konfliktene."
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr "må være etter starten"
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index 7f2808901fc..550871c5e5d 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-02-11 04:20\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s andere commit is weggelaten om prestatieproblemen te voorkomen."
msgstr[1] "%s andere commits zijn weggelaten om prestatieproblemen te voorkomen."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 groep"
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr "Nieuwe map toevoegen"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/or_IN/gitlab.po b/locale/or_IN/gitlab.po
index 9644498f3ae..9bc704c692c 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/pa_IN/gitlab.po b/locale/pa_IN/gitlab.po
index 6ee64e9c26b..60f4f1fc4b2 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/pa_PK/gitlab.po b/locale/pa_PK/gitlab.po
index 274f5836331..bfc8277d0ee 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-02-11 04:24\n"
+"PO-Revision-Date: 2023-03-11 10:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index a984423ae94..15c2c02e83d 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr " %{start} do %{end}"
@@ -566,6 +566,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d podatność"
@@ -615,6 +622,13 @@ msgstr[1] "%d znalezione ostrzeżenia:"
msgstr[2] "%d znalezionych ostrzeżeń:"
msgstr[3] "%d znalezionego ostrzeżenia:"
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
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 dodatkowy commit został pominięty, aby zapobiec problemom z wydajnością."
@@ -622,6 +636,12 @@ msgstr[1] "%s dodatkowe commity zostały pominięte, aby zapobiec problemom z wy
msgstr[2] "%s dodatkowych commitów zostało pominiętych, aby zapobiec problemom z wydajnością."
msgstr[3] "%s dodatkowego commitu zostało pominięte, aby zapobiec problemom z wydajnością."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} i %{openOrClose} %{noteable}"
@@ -812,6 +832,9 @@ msgstr "%{count} powiÄ…zanych %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} całkowitej wagi"
@@ -1013,6 +1036,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1028,9 +1054,6 @@ msgstr "%{mergeLength}/%{usersLength} można zmergować"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} pokazuje pierwsze %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (wygasł)"
@@ -1168,6 +1191,9 @@ msgstr "%{reportType} wykryto %{totalStart}%{total}%{totalEnd} potencjalnych %{v
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1446,6 +1472,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} utworzył(a) zgłoszenie: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1750,13 +1779,6 @@ msgstr[1] "%d klucze wdrożeniowe"
msgstr[2] "%d kluczy wdrożeniowych"
msgstr[3] "%d klucza wdrożeniowego"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grupa"
@@ -2089,9 +2111,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "Fuzzing API"
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr "Pomoc API"
@@ -2506,9 +2525,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr "Dodaj komentarz do tej linii"
@@ -2530,6 +2546,9 @@ msgstr "Dodaj do swojej wiki stronę główną z informacjami o Twoim projekcie,
msgid "Add a new issue"
msgstr "Dodaj nowe zgłoszenie"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Dodaj listÄ™ numerowanÄ…"
@@ -2539,6 +2558,9 @@ msgstr ""
msgid "Add a related issue"
msgstr "Dodaj powiązane zgłoszenie"
+msgid "Add a reply"
+msgstr ""
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -2653,6 +2675,9 @@ msgstr "Dodaj nowÄ… aplikacjÄ™"
msgid "Add new directory"
msgstr "Dodaj nowy katalog"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2791,6 +2816,9 @@ msgstr "Dodatkowe minuty:"
msgid "Additional text"
msgstr "Dodatkowy tekst"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3970,40 +3998,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4375,6 +4373,9 @@ msgstr ""
msgid "All Members"
msgstr "Wszyscy członkowie"
+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 ""
@@ -5007,6 +5008,9 @@ 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 ""
@@ -5016,6 +5020,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5094,13 +5215,28 @@ msgstr ""
msgid "Append the comment with %{tableflip}"
msgstr "Dodaj %{tableflip} na końcu komentarza"
+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|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."
+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."
@@ -5249,12 +5385,18 @@ msgstr "Zapisz zmiany"
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 ""
@@ -5509,6 +5651,13 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5521,6 +5670,20 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5596,9 +5759,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5611,6 +5771,9 @@ 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 ""
@@ -5968,7 +6131,7 @@ msgstr[3] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6224,9 +6387,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6239,9 +6399,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6251,9 +6408,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6635,6 +6801,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6662,9 +6831,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6734,6 +6900,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6749,9 +6918,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6887,27 +7053,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6917,9 +7065,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7062,6 +7207,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7290,15 +7438,27 @@ msgstr[3] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7311,9 +7471,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7431,9 +7588,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7452,6 +7606,15 @@ 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 ""
@@ -7482,10 +7645,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7527,6 +7693,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8296,6 +8465,15 @@ 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 ""
@@ -8413,6 +8591,9 @@ 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 ""
@@ -8799,6 +8980,9 @@ 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 ""
@@ -8841,6 +9025,9 @@ 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 ""
@@ -8850,16 +9037,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8886,6 +9070,9 @@ 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 ""
@@ -8904,6 +9091,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8922,6 +9112,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9042,12 +9235,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9126,10 +9325,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9159,6 +9358,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9944,6 +10146,9 @@ 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 ""
@@ -10235,7 +10440,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10629,9 +10834,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10644,6 +10846,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10713,12 +10918,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10827,9 +11041,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10848,9 +11077,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11478,6 +11704,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11520,12 +11749,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11541,6 +11779,9 @@ 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 ""
@@ -11586,7 +11827,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11607,7 +11851,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11679,6 +11923,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11925,7 +12172,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12114,6 +12361,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12363,9 +12613,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12573,6 +12820,9 @@ 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 ""
@@ -12672,7 +12922,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12841,9 +13091,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13757,6 +14004,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13799,6 +14049,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14566,6 +14819,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14669,10 +14925,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14777,6 +15036,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14972,6 +15234,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15131,9 +15396,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15573,6 +15835,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15597,6 +15862,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15615,9 +15883,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16074,6 +16348,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16119,7 +16396,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16137,6 +16414,9 @@ 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 ""
@@ -16431,6 +16711,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16542,6 +16825,9 @@ 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 ""
@@ -16830,6 +17116,9 @@ 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 ""
@@ -17110,6 +17399,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17134,6 +17426,9 @@ 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 ""
@@ -17335,6 +17630,9 @@ 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 ""
@@ -17353,6 +17651,9 @@ 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 ""
@@ -17929,9 +18230,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18055,6 +18353,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18211,9 +18512,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18355,9 +18653,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19174,13 +19469,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19231,6 +19535,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19255,6 +19562,12 @@ 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 ""
@@ -19270,9 +19583,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19321,13 +19631,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19421,12 +19724,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19466,6 +19775,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19478,13 +19790,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19502,7 +19814,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19556,6 +19868,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19628,6 +19943,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19682,15 +20000,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19907,6 +20219,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20096,6 +20432,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20447,6 +20786,9 @@ 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 ""
@@ -20705,6 +21047,9 @@ 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 ""
@@ -20720,6 +21065,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21100,6 +21451,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21447,6 +21801,9 @@ 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 ""
@@ -21546,6 +21903,9 @@ 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 ""
@@ -21588,15 +21948,24 @@ 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 ""
@@ -21657,7 +22026,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21887,6 +22256,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22293,7 +22665,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22956,12 +23328,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23137,10 +23515,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23158,6 +23539,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23446,7 +23830,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23575,9 +23959,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23849,6 +24230,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24074,6 +24461,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24611,9 +25001,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25306,6 +25711,15 @@ 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 ""
@@ -25387,6 +25801,9 @@ 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 ""
@@ -25396,6 +25813,9 @@ 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 ""
@@ -25411,9 +25831,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25429,6 +25846,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25690,6 +26110,13 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Line changes"
msgstr ""
@@ -25717,6 +26144,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25810,9 +26240,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25855,6 +26282,9 @@ 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 ""
@@ -25894,6 +26324,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25912,9 +26345,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25984,9 +26414,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26023,10 +26450,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26518,6 +26942,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26599,12 +27026,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26829,18 +27265,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26913,9 +27340,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26928,6 +27352,27 @@ 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 ""
@@ -27542,6 +27987,9 @@ msgstr[3] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27722,6 +28170,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27734,6 +28188,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27794,31 +28251,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28164,6 +28636,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28212,10 +28687,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28330,9 +28811,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28420,9 +28898,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28777,6 +29252,15 @@ 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 ""
@@ -28862,13 +29346,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29178,12 +29665,24 @@ 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|%{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 ""
@@ -29232,9 +29731,18 @@ 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 ""
@@ -29262,9 +29770,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29301,6 +29806,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29310,6 +29818,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29322,6 +29833,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29800,6 +30314,9 @@ 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 ""
@@ -29869,9 +30386,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30167,28 +30681,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30993,6 +31513,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31182,9 +31705,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31383,6 +31903,9 @@ 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 ""
@@ -31608,6 +32131,9 @@ 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 ""
@@ -31659,9 +32185,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31707,6 +32230,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31758,7 +32287,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31767,6 +32296,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31803,13 +32335,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31839,6 +32371,12 @@ 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 ""
@@ -31860,6 +32398,9 @@ 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 ""
@@ -31869,6 +32410,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32184,6 +32728,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32205,6 +32752,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32265,7 +32815,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32619,6 +33169,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32688,88 +33241,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32778,34 +33274,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32814,24 +33313,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32844,22 +33337,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32868,70 +33370,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33099,6 +33604,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33348,7 +33859,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33522,6 +34033,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33534,6 +34048,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33561,6 +34078,9 @@ 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 ""
@@ -33657,9 +34177,21 @@ 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 ""
@@ -33672,6 +34204,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33714,7 +34249,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33729,9 +34267,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33861,9 +34396,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34014,9 +34546,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34059,9 +34588,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34098,9 +34624,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34143,10 +34666,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34170,9 +34693,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34407,6 +34927,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34533,6 +35056,9 @@ 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 ""
@@ -34548,6 +35074,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34728,9 +35257,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34839,12 +35365,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35016,9 +35536,29 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35028,10 +35568,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35040,15 +35592,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35058,6 +35619,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35514,24 +36078,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35607,6 +36162,9 @@ 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] ""
@@ -35644,13 +36202,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35743,6 +36301,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36692,15 +37253,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36883,9 +37450,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37059,9 +37623,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37144,6 +37705,9 @@ 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|Administrator"
msgstr ""
@@ -37207,6 +37771,9 @@ 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 ""
@@ -37225,6 +37792,9 @@ 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 ""
@@ -37283,9 +37853,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37298,6 +37874,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37316,6 +37898,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37343,6 +37928,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37352,6 +37943,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37364,6 +37958,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37406,6 +38003,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37440,6 +38040,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37455,6 +38061,9 @@ 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 ""
@@ -37479,6 +38088,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37494,6 +38106,12 @@ 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 ""
@@ -37566,9 +38184,15 @@ 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 ""
@@ -37602,6 +38226,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37611,6 +38241,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37630,6 +38263,9 @@ msgstr[3] ""
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 runner has not run any jobs."
msgstr ""
@@ -37678,6 +38314,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37732,15 +38371,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37762,6 +38392,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37786,9 +38419,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37918,16 +38548,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37969,9 +38602,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38442,22 +39081,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
msgstr ""
-msgid "Security dashboard"
+msgid "Security configuration"
msgstr ""
-msgid "Security navigation"
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38586,7 +39228,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38700,6 +39342,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38805,9 +39450,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38898,6 +39552,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38919,6 +39576,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38928,6 +39588,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38994,7 +39657,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39072,6 +39735,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39549,6 +40215,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39651,6 +40320,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39663,6 +40335,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39675,6 +40350,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39777,6 +40455,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39912,6 +40596,9 @@ 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 ""
@@ -39939,7 +40626,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40192,6 +40879,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40358,9 +41048,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40514,15 +41201,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40532,6 +41237,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40541,6 +41249,9 @@ 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 ""
@@ -40574,9 +41285,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40760,12 +41477,18 @@ 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 ""
@@ -41177,9 +41900,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41243,6 +41963,9 @@ msgstr "Ochrona przed spamem i przed botami"
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41492,6 +42215,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42137,16 +42863,22 @@ 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|Sync subscription request."
+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}."
@@ -42155,7 +42887,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42186,9 +42918,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42231,9 +42960,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42384,9 +43110,27 @@ 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 ""
@@ -42797,10 +43541,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42826,9 +43570,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42955,6 +43696,9 @@ 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 ""
@@ -43016,6 +43760,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43058,9 +43805,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Połączenie upłynie po %{timeout}. W przypadku repozytoriów, którym zajmuje to dłużej, użyj kombinacji klonuj/pchnij."
@@ -43118,6 +43862,9 @@ msgstr ""
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "Wdrożenie tego zadania do %{environmentLink} nie powiodło się."
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr ""
@@ -43435,7 +44182,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43780,6 +44536,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43969,13 +44728,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44476,6 +45229,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44530,10 +45286,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44988,6 +45741,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45479,6 +46235,9 @@ 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 ""
@@ -45570,9 +46329,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45675,9 +46431,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45723,12 +46476,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45834,6 +46581,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45933,6 +46683,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45990,6 +46743,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46077,6 +46839,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46146,6 +46911,9 @@ 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 ""
@@ -46272,6 +47040,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46443,6 +47214,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46647,6 +47421,9 @@ 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 ""
@@ -46659,6 +47436,9 @@ 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 ""
@@ -46735,6 +47515,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47161,6 +47944,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47272,6 +48058,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47416,6 +48205,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47447,9 +48239,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47656,6 +48445,69 @@ 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|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 ""
@@ -48046,12 +48898,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48103,9 +48949,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48247,6 +49090,9 @@ 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 ""
@@ -48512,6 +49358,13 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -48552,6 +49405,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48771,7 +49627,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48819,6 +49675,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48844,6 +49703,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48868,9 +49736,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48991,6 +49865,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49027,6 +49904,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49057,6 +49937,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49460,9 +50343,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49635,12 +50515,18 @@ 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 ""
@@ -49813,6 +50699,9 @@ 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 ""
@@ -49822,7 +50711,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49852,6 +50741,9 @@ 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 ""
@@ -49876,6 +50768,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49921,6 +50816,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49930,9 +50828,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49963,6 +50858,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50124,6 +51022,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50367,6 +51268,9 @@ 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 ""
@@ -50709,9 +51613,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50779,6 +51680,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50809,6 +51713,9 @@ 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 ""
@@ -51096,9 +52003,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51412,10 +52316,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51477,6 +52387,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51492,6 +52480,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51519,12 +52513,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51540,6 +52528,9 @@ 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 ""
@@ -51623,82 +52614,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51761,9 +52698,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51788,6 +52722,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 42b85b10853..b2b830db119 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr " %{start} até %{end}"
@@ -426,6 +426,11 @@ msgid_plural "%d unresolved threads"
msgstr[0] "%d tópico não resolvido"
msgstr[1] "%d tópicos não resolvidos"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d vulnerabilidade"
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "%d advertência encontrada:"
msgstr[1] "%d advertências encontradas:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s commit adicional foi omitido para prevenir problemas de performance."
msgstr[1] "%s commits adicionais foram omitidos para prevenir problemas de performance."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr "%{count} %{pluralized_subject} relacionados: %{links}"
msgid "%{count} selected"
msgstr "%{count} selecionado"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} peso total"
@@ -831,6 +850,9 @@ msgstr "%{level_name} não é permitido, pois o projeto de origem do fork possui
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}, e %{awardsListLength} mais"
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} podem mesclar"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} mostrando o primeiro %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr "%{message}. Seu pedido de atenção foi removido."
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (expirado)"
@@ -982,6 +1001,9 @@ msgstr "%{reportType} detectou %{totalStart}%{total}%{totalEnd} %{vulnMessage} p
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr "%{reported} relatado para %{category} por %{reporter}"
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] "%{requireStart}Requer%{requireEnd} %{approvalsRequired} %{approvalStart}aprovação%{approvalEnd} de:"
@@ -1226,6 +1248,9 @@ msgstr "%{user} criou um épico: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} criou uma issue: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} não está incluído na lista"
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] "1 chave de implantação"
msgstr[1] "%d chaves de implantação"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "1 seguidor"
-msgstr[1] "%{count} seguidores"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grupo"
@@ -1813,9 +1833,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "Fuzzing API"
-msgid "API Fuzzing Configuration"
-msgstr "Configuração de Fuzzing API"
-
msgid "API Help"
msgstr "Ajuda da API"
@@ -2156,7 +2173,7 @@ msgid "Active"
msgstr "Ativo"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
-msgstr "Ativo %{accessTokenTypePlural} (%{totalAccessTokens})"
+msgstr "%{accessTokenTypePlural} (%{totalAccessTokens}) ativo "
msgid "Active Sessions"
msgstr "Sessões ativas"
@@ -2230,9 +2247,6 @@ msgstr "Adicionar uma lista de verificação"
msgid "Add a collapsible section"
msgstr "Adicionar uma seção resolvível"
-msgid "Add a comment"
-msgstr "Adicionar um comentário"
-
msgid "Add a comment to this line"
msgstr "Adicionar um comentário a esta linha"
@@ -2254,6 +2268,9 @@ msgstr "Adicione uma homepage ao seu wiki que contenha informações sobre o seu
msgid "Add a new issue"
msgstr "Adicionar uma nova issue"
+msgid "Add a new saved reply"
+msgstr "Adicionar uma nova resposta salva"
+
msgid "Add a numbered list"
msgstr "Adicionar uma lista numerada"
@@ -2263,6 +2280,9 @@ msgstr "Adicionar um épico relacionado"
msgid "Add a related issue"
msgstr "Adicionar um issue relacionada"
+msgid "Add a reply"
+msgstr "Adicionar uma resposta"
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr "Adicione um sufixo ao endereço de e-mail da Central de serviços. %{linkStart}Saiba mais.%{linkEnd}"
@@ -2377,6 +2397,9 @@ msgstr "Adicionar novo aplicativo"
msgid "Add new directory"
msgstr "Adicionar novo diretório"
+msgid "Add new saved reply"
+msgstr "Adicionar nova resposta salva"
+
msgid "Add or remove a user."
msgstr "Adicionar ou remover um usuário."
@@ -2515,6 +2538,9 @@ msgstr "Minutos adicionais:"
msgid "Additional text"
msgstr "Texto adicional"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr "Texto adicional para a página de login e ajuda."
@@ -2558,7 +2584,7 @@ msgid "Adds email participant(s)."
msgstr ""
msgid "Adds this %{issuable_type} as related to the %{issuable_type} it was created from"
-msgstr ""
+msgstr "Adicone essa %{issuable_type} relacionada a %{issuable_type} que foi criada de"
msgid "Adjust how frequently the GitLab UI polls for updates."
msgstr "Ajuste a frequência com que a interface do usuário do GitLab para atualizações."
@@ -3694,40 +3720,10 @@ 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 "Depois que a exportação for concluída, baixe o arquivo de dados do e-mail de notificação ou desta página. Você pode então importar o arquivo de dados na página %{strong_text_start}Criar novo grupo%{strong_text_end} de outra instância do GitLab."
-msgid "After you've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr "Está ativo"
-
-msgid "Airflow|Is paused"
-msgstr "Está pausado"
-
-msgid "Airflow|Next run"
-msgstr "Próxima execução"
-
-msgid "Airflow|Schedule"
-msgstr "Agendamento"
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr "Todo o GitLab"
msgid "All Members"
msgstr "Todos os membros"
+msgid "All branch names must match %{link_start}this regular expression%{link_end}. If empty, any branch name is allowed."
+msgstr "Todos os nomes de ramificação devem corresponder a %{link_start}esta expressão regular%{link_end}. Se vazio, qualquer nome de ramificação é permitido."
+
msgid "All branches"
msgstr "Todas as ramificações"
@@ -4727,6 +4726,9 @@ msgstr "Ocorreu um erro inesperado ao iniciar o terminal da web."
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Ocorreu um erro inesperado ao parar o terminal da web."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr "Ocorreu um erro desconhecido ao carregar este gráfico."
@@ -4736,6 +4738,123 @@ msgstr "Ocorreu um erro desconhecido."
msgid "Analytics"
msgstr "Telemetria"
+msgid "Analytics|Add to Dashboard"
+msgstr "Adicionar ao Painel"
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+msgstr ""
+
+msgid "Analytics|Choose a chart type on the right"
+msgstr ""
+
+msgid "Analytics|Choose a measurement to start"
+msgstr "Escolha uma medição para começar"
+
+msgid "Analytics|Code"
+msgstr "Código"
+
+msgid "Analytics|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr "Painéis personalizados"
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr "Painéis são criados editando os arquivos do painel de projetos."
+
+msgid "Analytics|Data"
+msgstr "Dados"
+
+msgid "Analytics|Data Table"
+msgstr "Tabela de dados"
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr "Para poder criar seus próprios painéis, configure um projeto especial para armazenar seus painéis."
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr "Gráfico de linhas"
+
+msgid "Analytics|New Analytics Visualization Title"
+msgstr ""
+
+msgid "Analytics|OS"
+msgstr "SO"
+
+msgid "Analytics|OS Version"
+msgstr "Versão do SO"
+
+msgid "Analytics|Page Language"
+msgstr ""
+
+msgid "Analytics|Page Path"
+msgstr "Caminho da página"
+
+msgid "Analytics|Page Title"
+msgstr "Título da página"
+
+msgid "Analytics|Pages"
+msgstr ""
+
+msgid "Analytics|Referer"
+msgstr "Referenciador"
+
+msgid "Analytics|Resulting Data"
+msgstr "Dados resultantes"
+
+msgid "Analytics|Save"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr "Estatística única"
+
+msgid "Analytics|URL"
+msgstr "URL"
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr "Usuários"
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr "Visualização"
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr "Tipo de visualização"
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analise suas dependências em busca de vulnerabilidades conhecidas."
@@ -4814,13 +4933,28 @@ msgstr "Anexar o comentário com %{shrug}"
msgid "Append the comment with %{tableflip}"
msgstr "Anexar o comentário com %{tableflip}"
+msgid "AppleAppStore|Drag your Private Key file here or %{linkStart}click to upload%{linkEnd}."
+msgstr "Arraste seu arquivo de chave privada aqui ou %{linkStart}clique para carregar%{linkEnd}."
+
+msgid "AppleAppStore|Drop your Private Key file to start the upload."
+msgstr "Solte seu arquivo de chave privada para iniciar o carregamento."
+
+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|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."
+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."
@@ -4965,12 +5099,18 @@ msgstr "Salvar mudanças"
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 "Cadastro ativado"
+msgid "ApplicationSettings|Soft"
+msgstr ""
+
msgid "ApplicationSettings|Text shown after a user signs up. Markdown enabled."
msgstr "Texto mostrado após um usuário se cadastrar. Markdown ativado."
@@ -5215,6 +5355,11 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Aprovar uma solicitação de mesclagem"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Approve merge request"
msgstr "Aprovar solicitação de mesclagem"
@@ -5227,6 +5372,16 @@ msgstr "Aprovado"
msgid "Approved MRs"
msgstr "MRs Aprovados"
+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 "Aprovou o merge request atual."
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr "Você tem certeza de que quer aprovar %{user}?"
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr "Tem certeza de que deseja tentar mesclar?"
@@ -5317,6 +5469,9 @@ msgstr "Tem certeza de que deseja fechar esta issue bloqueada?"
msgid "Are you sure you want to delete %{name}?"
msgstr "Tem certeza de que deseja excluir %{name}?"
+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 ""
@@ -5668,8 +5823,8 @@ msgstr[1] "Anexando %d arquivos"
msgid "Attaching the file failed."
msgstr "Falha ao anexar o arquivo."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
-msgstr "Tentativa de entrada em %{host} usando um código de autenticação de dois fatores incorreto"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
+msgstr "Tentativa de entrada em %{host} usando um código de verificação incorreto"
msgid "Audit Events"
msgstr "Eventos de auditoria"
@@ -5922,9 +6077,6 @@ msgstr "Criado em %{timeago} por %{author}"
msgid "Authorization code:"
msgstr "Código de autorização:"
-msgid "Authorization required"
-msgstr "Autorização necessária"
-
msgid "Authorization token duration (minutes)"
msgstr "Duração do token de autorização (minutos)"
@@ -5937,9 +6089,6 @@ msgstr "Autorizar"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "Autorizar %{link_to_client} usar sua conta?"
-msgid "Authorize %{user} to use your account?"
-msgstr "Autorizar %{user} para usar sua conta?"
-
msgid "Authorized %{new_chat_name}"
msgstr "%{new_chat_name} autorizado"
@@ -5949,9 +6098,18 @@ msgstr "Autorizado em"
msgid "Authorized applications (%{size})"
msgstr "Aplicativos autorizados (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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 "Tem certeza de que deseja revogar este aplicativo?"
+msgid "AuthorizedApplication|Renew secret"
+msgstr "Renovar segredo"
+
msgid "AuthorizedApplication|Revoke application"
msgstr "Revogar aplicativo"
@@ -6031,10 +6189,10 @@ msgid "Autocomplete description"
msgstr "Autocompletar descrição"
msgid "Autocomplete hint"
-msgstr ""
+msgstr "Dica do autocompletar"
msgid "Autocomplete usage hint"
-msgstr ""
+msgstr "Dica de uso do autocompletar"
msgid "Automatic certificate management using %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}"
msgstr "Gerenciamento automático de certificado usando %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}"
@@ -6333,6 +6491,9 @@ msgstr "Cuidado. Alterar o espaço de nome do projeto pode ter efeitos colaterai
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Tenha cuidado. Renomear o repositório de um projeto pode ter efeitos colaterais indesejados."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr "Abaixo você encontrará todos os grupos que são públicos."
-msgid "Beta"
-msgstr "Beta"
-
msgid "Bi-weekly code coverage"
msgstr "Cobertura semestral de código"
@@ -6432,6 +6590,9 @@ msgstr "Planejamento ágil empresarial"
msgid "BillingPlans|Faster code reviews"
msgstr "Revisões de código mais rápidas"
+msgid "BillingPlans|Free"
+msgstr "Grátis"
+
msgid "BillingPlans|Free forever features for individual users"
msgstr "Recursos gratuitos para sempre para usuários individuais"
@@ -6447,9 +6608,6 @@ msgstr "Se você gostaria de diminuir o seu plano, por favor entre em contato co
msgid "BillingPlans|Includes free static websites"
msgstr "Inclui sites estáticos gratuitos"
-msgid "BillingPlans|Learn more"
-msgstr "Saiba mais"
-
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}, or start a free 30-day trial of GitLab.com Ultimate."
msgstr "Aprenda mais sobre cada plano lendo nossos %{faq_link}ou inicie uma avaliação gratuita de 30 dias do GitLab.com Ultimate."
@@ -6585,27 +6743,9 @@ msgstr "Atualizar"
msgid "BillingPlan|Upgrade for free"
msgstr "Atualizar gratuitamente"
-msgid "Billings|%{planName} plan"
-msgstr "Plano %{planName}"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr "Ocorreu um erro ao estender a sua avaliação."
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr "Ocorreu um erro ao reativar a sua avaliação."
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr "Ao estender a sua avaliação, você receberá 30 dias adicionais de %{planName}. Sua avaliação só pode ser estendida uma vez."
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr "Ao reativar a sua avaliação, você receberá 30 dias adicionais de %{planName}. Sua avaliação só pode ser reativada uma vez."
-
msgid "Billings|Error validating card details"
msgstr "Erro ao validar os dados do cartão"
-msgid "Billings|Extend trial"
-msgstr "Estender avaliação"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr "Grupos gratuitos são limitados a %{number} assentos."
@@ -6615,9 +6755,6 @@ msgstr "Grupos de nível gratuito e de avaliação podem convidar no máximo 20
msgid "Billings|In a seat"
msgstr "Em um assento"
-msgid "Billings|Reactivate trial"
-msgstr "Reativar avaliação"
-
msgid "Billings|Seats in use / Seats available"
msgstr "Assentos em uso / Assentos disponíveis"
@@ -6758,6 +6895,9 @@ msgstr "Importar do Bitbucket"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr "Ver em %{environmentName}"
@@ -6980,15 +7120,27 @@ msgstr[1] "Bloqueado por %{blockedByCount} %{issuableType}s"
msgid "Boards|Collapse"
msgstr "Recolher"
+msgid "Boards|Create new epic"
+msgstr "Criar novo épico"
+
+msgid "Boards|Create new issue"
+msgstr "Criar novoa issue"
+
msgid "Boards|Edit board"
msgstr "Editar painel"
+msgid "Boards|Edit list settings"
+msgstr "Editar configurações de lista"
+
msgid "Boards|Expand"
msgstr "Expandir"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr ""
+msgid "Boards|List actions"
+msgstr "Lista de ações"
+
msgid "Boards|Move card"
msgstr "Mover cartão"
@@ -7001,9 +7153,6 @@ msgstr "Mover para o início da lista"
msgid "Boards|New board"
msgstr "Novo painel"
-msgid "Boards|New epic"
-msgstr "Novo épico"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr "Depois que uma ramificação protegida é criada, aparecerá na lista co
msgid "BranchRules|All branches"
msgstr "Todas as ramificações"
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr "Todos os usuários com acesso push são permitidos de forçar o push."
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "Permitir que todos os usuários com acesso push a %{linkStart}force push%{linkEnd}."
@@ -7142,6 +7288,15 @@ msgstr "Permitido push e mesclar"
msgid "BranchRules|Allowed to push and merge (%{total})"
msgstr "Permitido push e mesclar (%{total})"
+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 ""
@@ -7172,11 +7327,14 @@ msgstr "Criar curinga: %{searchTerm}"
msgid "BranchRules|Details"
msgstr "Detalhes"
-msgid "BranchRules|Force push"
-msgstr "Forçar push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
-msgid "BranchRules|Force push is not allowed."
-msgstr "Forçar push não é permitido."
+msgid "BranchRules|From users with push access."
+msgstr ""
msgid "BranchRules|Groups"
msgstr "Grupos"
@@ -7217,6 +7375,9 @@ msgstr "Aprovações necessárias (%{total})"
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr "Requer aprovação de CODEOWNERS"
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr "Cargos"
@@ -7907,16 +8068,16 @@ 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 ""
+msgstr "Como mantenedor, solicitar um CVE para uma vulnerabilidade em seu projeto ajudará seus usuários a se manterem seguros e informados."
msgid "CVE|CVE ID Request"
-msgstr ""
+msgstr "Solicitação de CVE ID"
msgid "CVE|Common Vulnerability Enumeration (CVE) identifiers are used to track distinct vulnerabilities in specific versions of code."
-msgstr ""
+msgstr "Enumeração de vulnerabilidade comum (CVE) são usados para rastrear vulnerabilidades distintas em versões específicas do código."
msgid "CVE|Create CVE ID Request"
-msgstr ""
+msgstr "Criar solicitação de CVE ID"
msgid "CVE|Enable CVE ID requests in the issue sidebar"
msgstr "Ativar requisições de CVE ID na barra lateral de issue"
@@ -7925,7 +8086,7 @@ msgid "CVE|Request CVE ID"
msgstr "Solicitar ID de CVE"
msgid "CVE|Why Request a CVE ID?"
-msgstr ""
+msgstr "Por que solicitar um CVE ID?"
msgid "Cadence is not automated"
msgstr ""
@@ -7984,6 +8145,15 @@ msgstr ""
msgid "Can't be empty"
msgstr "Não pode estar vazio"
+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 "Não é possível criar snippet: %{err}"
@@ -8101,6 +8271,9 @@ 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 "Não é possível tornar o épico confidencial se ele contém épicos filhos não confidenciais"
@@ -8483,6 +8656,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+msgid "Checkout|Add active users before adding a coupon."
+msgstr "Adicione usuários ativos antes de adicionar um cupom."
+
msgid "Checkout|An unknown error has occurred. Please try again by refreshing this page."
msgstr "Ocorreu um erro desconhecido. Tente novamente atualizando esta página."
@@ -8525,6 +8701,9 @@ msgstr "País"
msgid "Checkout|Coupon code (optional)"
msgstr "Código do cupom (opcional)"
+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 "Criar um novo grupo"
@@ -8534,18 +8713,15 @@ msgstr "Falha ao carregar o formulário de cartão de crédito. Por favor, tente
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 ""
+
msgid "Checkout|Edit"
msgstr "Editar"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr "Expira em: %{expirationMonth}/%{expirationYear}"
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "Falha ao confirmar seu pedido! Por favor, tente novamente."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "Falha ao confirmar seu pedido: %{message}. Por favor, tente novamente."
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "Falha ao carregar países. Por favor, tente novamente."
@@ -8570,6 +8746,9 @@ msgstr "Plano no GitLab"
msgid "Checkout|Group"
msgstr "Grupo"
+msgid "Checkout|Invalid coupon code. Enter a valid coupon code."
+msgstr "Código de cupom inválido. Insira um código de cupom válido."
+
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
msgstr "Deve ser %{minimumNumberOfUsers} (seus assentos em uso) ou mais."
@@ -8588,6 +8767,9 @@ msgstr "Nome: %{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "Necessita de mais usuários? Compre o GitLab para a sua %{company}."
+msgid "Checkout|Network Error: %{message}"
+msgstr "Erro de rede: %{message}"
+
msgid "Checkout|Number of users"
msgstr "Número de usuários"
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "Estado"
@@ -8726,12 +8911,18 @@ msgstr "Escolha o conteúdo que você deseja ver na página de visão geral de u
msgid "Choose which Git strategy to use when fetching the project."
msgstr "Escolha qual estratégia de Git usar ao buscar o projeto."
+msgid "Choose which branches should be mirrored"
+msgstr "Escolha quais ramificações devem ser espelhadas"
+
msgid "Choose which repositories you want to connect and run CI/CD pipelines."
msgstr "Escolha quais repositórios você deseja se conectar e executar pipelines de CI/CD."
msgid "Choose your framework"
msgstr "Escolha seu framework"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr "Intervalo de datas: %{range}"
@@ -8810,12 +9001,12 @@ msgstr "aguardando"
msgid "CiStatus|running"
msgstr "executando"
+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|Clear inputs"
-msgstr ""
-
msgid "CiVariables|Environments"
msgstr "Ambientes"
@@ -8843,6 +9034,9 @@ msgstr "Opções"
msgid "CiVariables|Protected"
msgstr "Protegido"
+msgid "CiVariables|Remove inputs"
+msgstr "Remover entradas"
+
msgid "CiVariables|Remove variable"
msgstr "Remover variável"
@@ -9624,6 +9818,9 @@ msgstr "Sua instância não tem o %{linkStart}GitLab Agent Server (KAS)%{linkEnd
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 ""
@@ -9915,7 +10112,7 @@ msgstr "O certificado do Kubernetes usado para autenticar no cluster."
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "A URL usada para acessar a API do Kubernetes."
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr "Comparar as edições do GitLab"
msgid "Compare GitLab plans"
msgstr "Comparar planos do GitLab"
-msgid "Compare Revisions"
-msgstr "Comparar revisões"
-
msgid "Compare branches and continue"
msgstr "Comparar ramificações e continuar"
@@ -10322,6 +10516,9 @@ msgstr "Compare as mudanças do último commit"
msgid "Compare changes with the merge request target branch"
msgstr "Compare as mudanças da solicitação de mesclagem com a ramificação de destino"
+msgid "Compare revisions"
+msgstr "Comparar revisões"
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr "Completo"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr "Completado em %{duration_seconds} segundos (%{relative_time})"
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr "Violações"
+
msgid "Compliance framework"
msgstr "Framework de conformidade"
msgid "Compliance report"
msgstr "Relatório de conformidade"
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Adicionar framework"
@@ -10505,9 +10711,24 @@ msgstr "Aprovado pelo autor"
msgid "ComplianceReport|Less than 2 approvers"
msgstr "Menos de 2 aprovadores"
+msgid "ComplianceReport|No framework"
+msgstr "Sem framework"
+
+msgid "ComplianceReport|No projects found"
+msgstr "Nenhum projeto encontrado"
+
msgid "ComplianceReport|No violations found"
msgstr "Nenhuma violação encontrada"
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "Componente"
@@ -10526,9 +10747,6 @@ msgstr "nota confidencial"
msgid "Confidentiality"
msgstr "Confidencialidade"
-msgid "Configuration"
-msgstr "Configuração"
-
msgid "Configuration help"
msgstr "Ajuda na configuração"
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "Você pode adicionar uma imagem a este registro com os seguintes comandos:"
+msgid "Content"
+msgstr "Conteúdo"
+
msgid "Content parsed with %{link}."
msgstr "Conteúdo analisado com %{link}."
@@ -11192,12 +11413,21 @@ msgstr "Contribuições"
msgid "Contribution Analytics"
msgstr "Análise de contribuição"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr "%{created} criado, %{closed} fechado."
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr "%{created} criado, %{merged} mesclado, %{closed} fechado."
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ msgstr ""
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr "Análises de contribuição para issues, solicitações de mesclagem e eventos de push desde %{start_date}"
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr ""
+
msgid "ContributionAnalytics|Failed to load the contribution stats"
msgstr ""
@@ -11258,8 +11491,11 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
-msgstr "O intervalo de datas fornecido é maior que 31 dias"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
+msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
msgstr "A data final é anterior à data inicial fornecida"
@@ -11279,8 +11515,8 @@ msgstr "Contribuições por membro do grupo"
msgid "Contributor"
msgstr "Contribuidor"
-msgid "Contributors"
-msgstr "Contribuidores"
+msgid "Contributor statistics"
+msgstr "Estatísticas do colaborador"
msgid "Control emails linked to your account"
msgstr "Controle e-mails vinculados à sua conta"
@@ -11351,6 +11587,9 @@ msgstr "Copiar comandos"
msgid "Copy commit SHA"
msgstr "Copiar SHA do commit"
+msgid "Copy diagram URL"
+msgstr "Copiar URL do diagrama"
+
msgid "Copy environment"
msgstr "Copiar ambiente"
@@ -11597,8 +11836,8 @@ msgstr "Não foi possível atribuir política ao projeto ou grupo"
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
-msgstr "País"
+msgid "Country / Region"
+msgstr ""
msgid "Counts"
msgstr ""
@@ -11786,6 +12025,9 @@ msgstr "Criar um"
msgid "Create or close an issue."
msgstr "Criar ou fechar uma issue."
+msgid "Create or edit diagram"
+msgstr "Criar ou editar o diagrama"
+
msgid "Create or import your first project"
msgstr "Criar ou importar seu primeiro projeto"
@@ -12035,9 +12277,6 @@ msgstr "Criado em"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "Criado uma ramificação e uma solicitação de mesclagem para resolver esta issue."
-msgid "Created at"
-msgstr "Criado em"
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "Criado a ramificação '%{branch_name}' e uma solicitação de mesclagem para resolver esta issue."
@@ -12245,6 +12484,9 @@ msgstr "Preferências"
msgid "CurrentUser|Start an Ultimate trial"
msgstr "Iniciar uma avaliação do Ultimate"
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr "Mudar para o GitLab Next"
+
msgid "Currently unable to fetch data for this pipeline."
msgstr "Atualmente não é possível buscar dados para este pipeline."
@@ -12344,8 +12586,8 @@ msgstr "Issue adicionada pela primeira vez a um painel"
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "Issue associada pela primeira com um marcos"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
-msgstr "Issue associada primeiro a um marco ou issue adicionada primeiro a um painel"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
+msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
msgstr "Issue mencionada primeiro em um commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr "Cconfiguração de DAST"
-
msgid "DAST configuration not found"
msgstr "Configuração do DAST não encontrada"
@@ -13425,6 +13664,9 @@ msgstr "Excluir corpus"
msgid "Delete deploy key"
msgstr "Excluir chave de implantação"
+msgid "Delete diagram"
+msgstr "Excluir diagrama"
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr "Excluir linha"
+msgid "Delete saved reply"
+msgstr "Excluir resposta salva"
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr "sucesso"
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr "Aviso de descontinuação"
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr "Para informações sobre uma possível substituição %{epicStart} leia mais sobre Opstrace %{epicEnd}."
@@ -14319,12 +14567,15 @@ msgstr "Não foi possível adicionar um novo comentário. Por favor, tente novam
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "Não foi possível criar uma nova discussão. Por favor, tente novamente."
+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 discussion. Please try again."
msgstr "Não foi possível atualizar uma discussão. Por favor, tente novamente."
-msgid "DesignManagement|Could not update note. Please try again."
-msgstr "Não foi possível atualizar uma nota. Por favor, tente novamente."
-
msgid "DesignManagement|Deselect all"
msgstr "Desmarcar tudo"
@@ -14427,6 +14678,9 @@ msgstr "Adoção de DevOps"
msgid "Developer"
msgstr "Desenvolvedor"
+msgid "Device name"
+msgstr "Nome do dispositivo"
+
msgid "Devices (optional)"
msgstr "Dispositivos (opcional)"
@@ -14622,6 +14876,9 @@ msgstr "Seu uso"
msgid "Diagram (%{language})"
msgstr "Diagrama (%{language})"
+msgid "Diagram saved successfully."
+msgstr "Diagrama salvo com sucesso."
+
msgid "Did not delete the source branch."
msgstr "Não excluiu a ramificação de origem."
@@ -14775,9 +15032,6 @@ msgstr "Notificações do Discord"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr "Envie notificações sobre eventos de projeto para um canal Discord."
-msgid "Discover"
-msgstr "Descobrir"
-
msgid "Discover GitLab Geo"
msgstr "Descubra o GitLab Geo"
@@ -15215,6 +15469,9 @@ msgstr "Editar chave de implantação"
msgid "Edit description"
msgstr "Editar descrição"
+msgid "Edit diagram description"
+msgstr "Editar descrição do diagrama"
+
msgid "Edit environment"
msgstr "Editar ambiente"
@@ -15239,6 +15496,9 @@ msgstr "Editar identidade para %{user_name}"
msgid "Edit image description"
msgstr "Editar descrição da imagem"
+msgid "Edit image text or link"
+msgstr "Editar texto ou link da imagem"
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr "Editar link"
msgid "Edit merge requests"
msgstr "Editar solicitação de mesclagem"
+msgid "Edit project: %{project_name}"
+msgstr "Editar projeto: %{project_name}"
+
msgid "Edit public deploy key"
msgstr "Editar chave de implantação pública"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr "Editar barra lateral"
@@ -15716,6 +15982,9 @@ msgstr "Insira 2FA (chave de dois fatores) para o modo de administrador"
msgid "Enter Admin Mode"
msgstr "Entrar no modo administrativo"
+msgid "Enter a name for your saved reply"
+msgstr "Insira um titulo para sua resposta"
+
msgid "Enter a number"
msgstr "Digite um número"
@@ -15761,8 +16030,8 @@ msgstr "Digite a descrição de %{name}"
msgid "Enter the %{name} title"
msgstr "Digite o título para %{name}"
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
-msgstr "Insira o código do aplicativo em duas etapas no seu dispositivo móvel. Se perdeu o seu dispositivo, você pode inserir um dos seus códigos de recuperação."
+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 "Digite o código do seu aplicativo autenticador de dois fatores. Se você perdeu seu dispositivo, pode inserir um de seus códigos de recuperação."
msgid "Enter the following to confirm:"
msgstr "Digite o seguinte para confirmar:"
@@ -15779,6 +16048,9 @@ msgstr ""
msgid "Enter the username for password-protected Elasticsearch servers."
msgstr ""
+msgid "Enter verification code"
+msgstr "Inserir código de verificação"
+
msgid "Enter your Packagist server. Defaults to https://packagist.org."
msgstr ""
@@ -16073,6 +16345,9 @@ msgstr "Quadros épicos"
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "Épico não pode ser encontrado."
@@ -16184,6 +16459,9 @@ msgstr ""
msgid "Error creating new iteration"
msgstr "Erro ao criar uma nova iteração"
+msgid "Error creating or updating PreScanVerificationStep: %{errors}"
+msgstr ""
+
msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr ""
@@ -16472,6 +16750,9 @@ msgstr "Tem certeza de que deseja excluir a política de escalação \"%{escalat
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 "Crie uma política de escalação no GitLab"
@@ -16750,6 +17031,9 @@ msgstr "Coleção de provas"
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr "Exemplo"
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ msgstr "Exceto da política:"
msgid "Exceptions"
msgstr "Exceções"
+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 "Excluindo commits de mesclar. Limitado a %{limit} commits."
@@ -16880,7 +17167,7 @@ msgid "Expires:"
msgstr "Expira:"
msgid "Explain why you're reporting the user."
-msgstr ""
+msgstr "Explique por que você está reportando o usuário."
msgid "Explore"
msgstr "Explorar"
@@ -16975,6 +17262,9 @@ msgstr "Quando nenhum etiqueta de classificação está definida, a etiqueta pad
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 "Permite que os tokens de implementação e as chaves de implementação sejam usadas com autorização externa"
+
msgid "ExternalAuthorization|Certificate used to authenticate with the external authorization service. If blank, the server certificate is validated when accessing over HTTPS."
msgstr ""
@@ -16993,6 +17283,9 @@ msgstr "Senha da chave de autorização do cliente (opcional)"
msgid "ExternalAuthorization|Default classification label"
msgstr "Etiqueta de classificação padrão"
+msgid "ExternalAuthorization|Does not apply if service URL is specified."
+msgstr "Não se aplica se a URL do serviço for especificada."
+
msgid "ExternalAuthorization|Enable classification control using an external service"
msgstr "Ativar controle de classificação usando um serviço externo"
@@ -17563,9 +17856,6 @@ msgstr "Fev"
msgid "February"
msgstr "Fevereiro"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr "Filtrar pipelines"
+msgid "Filter reports"
+msgstr "Filtrar relatórios"
+
msgid "Filter results"
msgstr "Filtrar resultados"
@@ -17845,9 +18138,6 @@ msgstr "Para cada tarefa, reutilize o espaço de tarefa do projeto. Se o espaço
msgid "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 "O nome da aplicação que vai usar o token ou seu propósito, por exemplo. Não coloque informações sensíveis no nome do token. Ele vai estar visível a todos os membros de %{resource_type}."
-msgid "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr "Para arquivos maiores que este limite indexam apenas o nome do arquivo. O conteúdo do arquivo não é indexado nem pesquisável."
@@ -17989,9 +18279,6 @@ msgstr "Formato: %{dateFormat}"
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr "Grátis"
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Avaliação gratuita do GitLab.com Ultimate"
@@ -18115,7 +18402,7 @@ msgid "Generate new export"
msgstr "Gerar nova exportação"
msgid "Generate project access tokens scoped to this project for your applications that need access to the GitLab API."
-msgstr ""
+msgstr "Gere tokens de acesso do projeto com escopo para este projeto para seus aplicativos que precisam de acesso à API do GitLab."
msgid "Generate site and private keys at"
msgstr ""
@@ -18802,14 +19089,23 @@ 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 "Enviar notificações para"
+
msgid "GitAbuse|The maximum number of unique repositories a user can download in the specified time period before they're banned."
msgstr "O número máximo de repositórios únicos que um usuário pode baixar no período de tempo especificado antes de ser banido."
+msgid "GitAbuse|Users who are emailed when Git abuse rate limit is exceeded."
+msgstr "Usuários que recebem um e-mail quando o limite de taxa de abuso do Git é excedido."
+
msgid "GitAbuse|Users who are excluded from the Git abuse rate limit."
msgstr ""
-msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
-msgstr "Você não pode especificar mais de %{maxExcludedUsers} usuários excluídos."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr ""
@@ -18859,6 +19155,9 @@ msgstr "GitLab KAS"
msgid "GitLab Pages"
msgstr "GitLab Pages"
+msgid "GitLab Pages has moved"
+msgstr "As páginas do GitLab foram movidas"
+
msgid "GitLab Shell"
msgstr "GitLab Shell"
@@ -18883,6 +19182,12 @@ msgstr "Solicitação de conta do GitLab rejeitada"
msgid "GitLab commit"
msgstr ""
+msgid "GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code"
+msgstr "O GitLab detectou uma tentativa de entrada em sua conta %{host} usando um código de verificação incorreto"
+
+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 "O GitLab detectou uma tentativa de entrada na sua conta %{host} usando um código de verificação incorreto do seguinte endereço IP: %{ip}, em %{time}"
+
msgid "GitLab documentation"
msgstr "Documentação do GitLab"
@@ -18898,9 +19203,6 @@ msgstr "GitLab para Jira Cloud"
msgid "GitLab group: %{source_link}"
msgstr "Grupo do GitLab: %{source_link}"
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr "O GitLab informa se uma nova versão está disponível. %{link_start}Quais informações o GitLab Inc. coleta?%{link_end}"
@@ -18949,11 +19251,6 @@ msgstr "Versão do GitLab"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -19047,12 +19344,18 @@ msgstr "Não verificado"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Atualizando a configuração de suas páginas..."
+msgid "GitLabPages|Use unique domain"
+msgstr "Usar domínio único"
+
msgid "GitLabPages|Verified"
msgstr "Verificado"
msgid "GitLabPages|Waiting for the Pages Pipeline to complete..."
msgstr ""
+msgid "GitLabPages|When enabled, a unique domain is generated to access pages."
+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}"
@@ -19092,6 +19395,9 @@ msgstr "URL do host do Gitea"
msgid "Gitea Import"
msgstr "Importação do Gitea"
+msgid "GithubImporter|Collaborators"
+msgstr "Colaboradores"
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,14 +19410,14 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
-msgstr ""
+msgid "GithubImporter|Issue links"
+msgstr "Links de issue"
-msgid "GithubImporter|Merge request attachments"
-msgstr ""
+msgid "GithubImporter|Merge request links"
+msgstr "Mesclar links de solicitação"
-msgid "GithubImporter|Note attachments"
-msgstr ""
+msgid "GithubImporter|Note links"
+msgstr "Links de notas"
msgid "GithubImporter|PR mergers"
msgstr ""
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr "Acesso concedido %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr "A pesquisa global está desativada para este escopo"
@@ -19254,6 +19563,9 @@ msgstr "Edições recentes"
msgid "GlobalSearch|Recent merge requests"
msgstr "Solicitações de mesclagem recentes"
+msgid "GlobalSearch|Reset filters"
+msgstr "Redefinir filtros"
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr "O que você está procurando?"
msgid "GlobalSearch|all GitLab"
msgstr "todo GitLab"
-msgid "GlobalSearch|group"
-msgstr "grupo"
-
msgid "GlobalSearch|in %{scope}"
msgstr "em %{scope}"
-msgid "GlobalSearch|project"
-msgstr "projeto"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr "Revogar autorizações"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 "Google Play"
+
+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 "Entendi"
@@ -19722,6 +20052,9 @@ msgstr "Nome do grupo (sua organização)"
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr "Visão geral do grupo"
+
msgid "Group overview content"
msgstr "Conteúdo da visão geral do grupo"
@@ -20073,6 +20406,9 @@ msgstr "Alterar a URL do grupo pode ter efeitos colaterais indesejados."
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 "Escolha um caminho de grupo que não comece com um traço ou termine com um ponto. Também pode conter caracteres alfanuméricos e sublinhados."
+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 "Frameworks de conformidade"
@@ -20331,6 +20667,9 @@ msgstr "Insira a URL para a instância de origem."
msgid "GroupsNew|GitLab source instance URL"
msgstr "URL da instância de origem do GitLab"
+msgid "GroupsNew|Groups"
+msgstr "Grupos"
+
msgid "GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}."
msgstr "Grupos também podem ser aninhados criando %{linkStart}subgrupos%{linkEnd}."
@@ -20346,6 +20685,12 @@ msgstr "Importar grupos por transferência direta"
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr "A importação de grupos por transferência direta está desativada no momento."
+msgid "GroupsNew|New group"
+msgstr "Novo grupo"
+
+msgid "GroupsNew|New subgroup"
+msgstr "Novo subgrupo"
+
msgid "GroupsNew|No import options available"
msgstr "Nenhuma opção de importação disponível"
@@ -20449,7 +20794,7 @@ msgid "Groups|Learn more about subgroups"
msgstr "Saiba mais sobre subgrupos"
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 ""
+msgstr "Membros, projetos, avaliações e assinaturas pagas estão vinculados a um grupo específico de nível superior. Se você já for membro de um grupo de nível superior, poderá criar um subgrupo para que seu novo trabalho faça parte do grupo de nível superior existente. Você deseja criar um subgrupo em vez disso?"
msgid "Groups|Must start with letter, digit, emoji, or underscore. Can also contain periods, dashes, spaces, and parentheses."
msgstr "Deve começar com letra, dígito, emoji ou sublinhado. Também pode conter pontos, traços, espaços e parênteses."
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr "Olá %{user_name} (%{user_username})!"
+
msgid "Hi %{username}!"
msgstr "Olá %{username}!"
@@ -21065,6 +21413,9 @@ msgstr "Digitar um código válido."
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 "Para maior segurança, você precisará verificar sua identidade."
+
msgid "IdentityVerification|For added security, you'll need to verify your identity. We've sent a verification code to %{email}"
msgstr ""
@@ -21164,6 +21515,9 @@ msgstr "Verificar sua identidade"
msgid "IdentityVerification|We sent a new code to +%{phoneNumber}"
msgstr ""
+msgid "IdentityVerification|We've sent a verification code to %{email}"
+msgstr "Enviamos um código de verificação para %{email}"
+
msgid "IdentityVerification|We've sent a verification code to +%{phoneNumber}"
msgstr ""
@@ -21206,15 +21560,24 @@ msgstr "Se marcado, os proprietários de grupos podem gerenciar links de grupo L
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "Se marcado, novas inscrições de grupo e permissões só podem ser adicionadas através da sincronização LDAP"
+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 "Se desativada, uma ramificação local divergente não será atualizada automaticamente com confirmações de sua contraparte remota, para evitar a perda de dados locais. Se a ramificação padrão (%{default_branch}) tiver divergido e não puder ser atualizada, o espelhamento falhará. Outrss ramificações divergentes são ignoradas silenciosamente. %{link_start}Saiba mais.%{link_end}"
msgid "If disabled, only administrators can configure repository mirroring."
msgstr ""
+msgid "If enabled, all branches will be mirrored."
+msgstr "Se ativado, todas as ramificações serão espelhadas."
+
msgid "If enabled, only protected branches will be mirrored."
msgstr "Se ativado, apenas ramificações protegidas serão espelhados."
+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 ""
@@ -21275,8 +21638,8 @@ msgstr "Se você perder seus códigos de recuperação, você pode gerar novos,
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "Se você entrou recentemente e reconhece o endereço IP, pode desconsiderar este e-mail."
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email."
-msgstr "Se você tentou entrar recentemente, mas inseriu por engano um código de autenticação de dois fatores errado, ignore este e-mail."
+msgid "If you recently tried to sign in, but mistakenly entered an incorrect verification code, you can ignore this email."
+msgstr "Se você tentou entrar recentemente, mas inseriu por engano um código de verificação incorreto, você pode ignorar este e-mail."
msgid "If you want to re-enable two-factor authentication, visit %{two_factor_link}"
msgstr "Se você quiser reativar a autenticação de dois fatores, visite %{two_factor_link}"
@@ -21501,6 +21864,9 @@ msgstr "Falha ao importar o projeto"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr "Falha ao importar o projeto: %{reason}"
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21531,7 +21897,7 @@ msgstr[0] "Importando %d repositório"
msgstr[1] "Importando %d repositórios"
msgid "Importing GitLab projects? Migrating GitLab projects when migrating groups by direct transfer is in Beta. %{link_start}Learn more.%{link_end}"
-msgstr ""
+msgstr "Importando projetos do GitLab? A migração de projetos do GitLab ao migrar grupos por transferência direta está em Beta. %{link_start}Saiba mais.%{link_end}"
msgid "Importing..."
msgstr "Importando..."
@@ -21905,8 +22271,8 @@ msgstr "Proteja seu aplicativo da Web usando o DAST para examinar vulnerabilidad
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
-msgstr ""
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
+msgstr "Reduza o risco de segurança e conformidade"
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
msgstr "Exigir vários aprovadores em uma solicitação de mesclagem, para que você saiba que está em boas condições antes de ser mesclada."
@@ -22014,7 +22380,7 @@ msgid "InProductMarketing|Try it out"
msgstr ""
msgid "InProductMarketing|Try it yourself"
-msgstr ""
+msgstr "Experimente você mesmo"
msgid "InProductMarketing|Turn coworkers into collaborators"
msgstr ""
@@ -22568,12 +22934,18 @@ msgstr "Inserir imagem"
msgid "Insert link"
msgstr "Inserir link"
+msgid "Insert or edit diagram"
+msgstr "Inserir ou editar o diagrama"
+
msgid "Insert row after"
msgstr "Inserir linha acima"
msgid "Insert row before"
msgstr "Inserir linha abaixo"
+msgid "Insert saved reply"
+msgstr "Inserir resposta salva"
+
msgid "Insert suggestion"
msgstr "Inserir sugestão"
@@ -22640,22 +23012,22 @@ msgid "Integration Settings"
msgstr "Configurações de integração"
msgid "IntegrationEvents|A comment is added"
-msgstr ""
+msgstr "Um comentário é adicionado"
msgid "IntegrationEvents|A confidential issue is created, closed, or reopened"
-msgstr ""
+msgstr "Uma issue confidencial é criada, fechada ou reaberta"
msgid "IntegrationEvents|A deployment is started or finished"
-msgstr ""
+msgstr "Uma implantação é iniciada ou concluída"
msgid "IntegrationEvents|A merge request is created, merged, closed, or reopened"
-msgstr ""
+msgstr "Uma solicitação de mesclagem é criada, mesclada, fechada ou reaberta"
msgid "IntegrationEvents|A new, unique alert is recorded"
-msgstr ""
+msgstr "Um novo alerta exclusivo é registrado"
msgid "IntegrationEvents|A new, unique vulnerability is recorded (available only in GitLab Ultimate)"
-msgstr ""
+msgstr "Uma nova vulnerabilidade exclusiva é registrada (disponível apenas no GitLab Ultimate)"
msgid "IntegrationEvents|A pipeline status changes"
msgstr "Um status de pipeline muda"
@@ -22664,19 +23036,19 @@ msgid "IntegrationEvents|A push is made to the repository"
msgstr "Um push é feito para o repositório"
msgid "IntegrationEvents|A tag is pushed to the repository or removed"
-msgstr ""
+msgstr "Uma tag é enviada para o repositório ou removida"
msgid "IntegrationEvents|A wiki page is created or updated"
msgstr "Uma página de wiki é criada ou atualizada"
msgid "IntegrationEvents|An incident is created, closed, or reopened"
-msgstr ""
+msgstr "Um incidente é criado, fechado ou reaberto"
msgid "IntegrationEvents|An internal note or comment on a confidential issue is added"
-msgstr ""
+msgstr "Uma nota interna ou comentário sobre uma issue confidencial confidencial é adicionada"
msgid "IntegrationEvents|An issue is created, closed, or reopened"
-msgstr ""
+msgstr "Uma issue é criada, fechada ou reaberta"
msgid "Integrations"
msgstr "Integrações"
@@ -22747,12 +23119,15 @@ 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 "Arraste seu arquivo aqui ou %{linkStart}clique para enviar%{linkEnd}."
+
+msgid "Integrations|Drop your file to start the upload."
+msgstr "Solte seu arquivo para iniciar o envio."
+
msgid "Integrations|Edit project alias"
msgstr "Editar o alias do projeto"
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
-msgstr "Ative os comandos de barra do GitLab.com em um espaço de trabalho do Slack."
-
msgid "Integrations|Enable SSL verification"
msgstr "Ativar verificação de SSL"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr "Digite seu alias"
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22796,7 +23174,7 @@ msgid "Integrations|GitLab administrators can set up integrations that all proje
msgstr "Os administradores do GitLab podem configurar integrações que todos os projetos herdam e usam por padrão. Essas integrações se aplicam a todos os projetos que ainda não usam configurações personalizadas. Você pode substituir configurações personalizadas para um projeto, se as configurações forem necessárias nesse nível. Saiba mais sobre o %{integrations_link_start}gerenciamento de integração em nível em grupo%{link_end}."
msgid "Integrations|GitLab for Slack app"
-msgstr ""
+msgstr "GitLab para Slack"
msgid "Integrations|GitLab for Slack app must be reinstalled to enable notifications"
msgstr "O aplicativo GitLab para Slack deve ser reinstalado para ativar as notificações"
@@ -22907,7 +23285,7 @@ msgid "Integrations|To keep this project going, create a new issue."
msgstr "Para manter este projeto em andamento, crie uma nova issue."
msgid "Integrations|Trigger"
-msgstr ""
+msgstr "Gatilho"
msgid "Integrations|Unable to post to %{channel_list}, please add the GitLab Slack app to any private Slack channels"
msgstr ""
@@ -23056,8 +23434,8 @@ msgstr ""
msgid "Invalid repository path"
msgstr "Caminho de repositório inválido"
-msgid "Invalid rule"
-msgstr "Regra inválida"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr "Resposta do servidor inválida"
@@ -23185,9 +23563,6 @@ msgstr "Crie issues para o novo membro da equipe trabalhar (opcional)"
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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr "Tipo de issue"
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr "Painel de issues"
+
+msgid "Issue boards"
+msgstr "Painéis de issue"
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr "Título"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24157,7 +24541,7 @@ msgid "JiraService|Using Jira for issue tracking?"
msgstr "Usando Jira para rastreamento de issue?"
msgid "JiraService|Warning: All GitLab users with access to this GitLab project can view all issues from the Jira project you select."
-msgstr ""
+msgstr "Aviso: Todos os usuários do GitLab com acesso a esse projeto podem ver todos as issues do projeto do Jira que você selecionou."
msgid "JiraService|Web URL"
msgstr "URL da Web"
@@ -24219,9 +24603,24 @@ msgstr "A tarefa foi retentada"
msgid "JobAssistant|Add job"
msgstr "Adicionar tarefa"
+msgid "JobAssistant|Job Setup"
+msgstr "Configuração da tarefa"
+
msgid "JobAssistant|Job assistant"
msgstr "Assistente de tarefa"
+msgid "JobAssistant|Job name"
+msgstr "Nome da tarefa"
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr "Estágio (opcional)"
+
+msgid "JobAssistant|Tags (optional)"
+msgstr "Tags (opcional)"
+
msgid "Jobs"
msgstr "Tarefas"
@@ -24910,6 +25309,15 @@ msgstr "Saiba mais."
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
msgstr "%{percentage}%{percentSymbol} concluído"
+msgid "LearnGitLab|1. Add code to your project"
+msgstr "1. Adicionar código ao seu projeto"
+
+msgid "LearnGitLab|2. Build"
+msgstr "2. Construir"
+
+msgid "LearnGitLab|Add code"
+msgstr "Adicionar código"
+
msgid "LearnGitLab|Add code owners"
msgstr "Adicionar proprietários de códigos"
@@ -24991,6 +25399,9 @@ msgstr "Configure sua área de trabalho"
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "Comece uma avaliação gratuita do GitLab Ultimate"
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr "Comece com o WebIDE"
+
msgid "LearnGitLab|Submit a merge request (MR)"
msgstr "Enviar uma solicitação de mesclagem (MR)"
@@ -25000,6 +25411,9 @@ msgstr "Experimente o GitLab Ultimate gratuitamente"
msgid "LearnGitLab|Try all GitLab features for 30 days, no credit card required."
msgstr "Confira todos os recursos do GitLab por 30 dias, sem necessidade de cartão de crédito."
+msgid "LearnGitLab|Use the built-in editor to create or upload files."
+msgstr "Use o editor embutido para criar ou enviar arquivos."
+
msgid "LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:"
msgstr "Use o seu novo fluxo de trabalho do GitLab para publicar seu aplicativo, monitorar sua saúde e mantê-lo seguro:"
@@ -25015,9 +25429,6 @@ msgstr "Entre em contato com seu administrador para ativar esta ação."
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr "Entre em contato com seu administrador para iniciar uma avaliação gratuita do Ultimate."
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr "Criando sua experiência de integração..."
-
msgid "LearnGitlab|Ok, let's go"
msgstr "Ok, vamos lá"
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "Sair do modo de edição? Todas as alterações não salvas serão perdidas."
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Sair do grupo"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr "Modo de limitação"
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] "Linha"
+msgstr[1] "Linhas"
+
msgid "Line changes"
msgstr "Alterações de linha"
@@ -25309,6 +25728,9 @@ msgstr "Vincule um wiki externo da barra lateral do projeto. %{docs_link}"
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr "Texto do link"
@@ -25402,9 +25824,6 @@ msgstr "Listar repositórios disponíveis"
msgid "List of all commits"
msgstr "Lista de todos os commits"
-msgid "List of all merge commits"
-msgstr "Lista de todos commits de mesclagem"
-
msgid "List of suitable GCP locations"
msgstr "Lista de localizações adequadas do GCP"
@@ -25447,6 +25866,9 @@ msgstr "Carregando estados de contribuição para membros de grupo"
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr ""
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr "Carregando mais"
@@ -25486,6 +25908,9 @@ msgstr "Bloquear arquivo?"
msgid "Lock memberships to LDAP synchronization"
msgstr "Bloquear inscrições para sincronização LDAP"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr "Bloquear solicitação de mesclagem"
@@ -25504,9 +25929,6 @@ msgstr "Travar para projetos existentes"
msgid "Locked"
msgstr "Bloqueado"
-msgid "Locked Files"
-msgstr "Arquivos travados"
-
msgid "Locked by %{fileLockUserName}"
msgstr "Bloqueado por %{fileLockUserName}"
@@ -25576,9 +25998,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr "Mostrar apenas alterações"
msgid "MRDiff|Show full file"
msgstr "Mostrar arquivo completo"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr "Tamanho máximo de push"
msgid "Maximum push size (MB)"
msgstr "Tamanho máximo de push (MB)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr "Máximo de requisições por 10 minutos por usuário"
@@ -26191,12 +26610,21 @@ msgstr "%{member_name} convidou você para participar do GitLab"
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRole|%{role} - custom"
+msgstr ""
+
msgid "MemberRole|can't be changed"
msgstr "não pode ser alterado"
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|must be top-level namespace"
msgstr ""
@@ -26376,7 +26804,7 @@ msgid "Members|You cannot remove yourself from a personal project."
msgstr ""
msgid "Member|Deny access"
-msgstr ""
+msgstr "Negar acesso"
msgid "Member|Revoke invite"
msgstr "Revogar convite"
@@ -26417,18 +26845,9 @@ msgstr "Mesclar automaticamente (%{strategy})"
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr "Mesclagem bloqueada: a solicitação de mesclagem deve ser marcada como pronta. Ainda está marcado como rascunho."
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr "A tela de solicitação de mesclagem é um lugar para propor mudanças e
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr "As solicitações de mesclagem não podem ser mescladas se as verificações de status não forem bem-sucedidas ou ainda estiverem em execução."
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ msgstr "Realizar merge quando o pipeline for bem sucedido"
msgid "Merge..."
msgstr ""
+msgid "MergeChecks|All threads must be resolved"
+msgstr "Todos os tópicos devem ser resolvidos"
+
+msgid "MergeChecks|Enable \"Pipelines must succeed\" first."
+msgstr ""
+
+msgid "MergeChecks|Introduces the risk of merging changes that do not pass the pipeline."
+msgstr "Introduz o risco de mesclar alterações que não passam pelo pipeline."
+
+msgid "MergeChecks|Merge requests can't be merged if the latest pipeline did not succeed or is still running."
+msgstr "As solicitações de mesclagem não podem ser mescladas se o pipeline mais recente não tiver êxito ou ainda estiver em execução."
+
+msgid "MergeChecks|Pipelines must succeed"
+msgstr "Pipelines devem ser bem-sucedidos"
+
+msgid "MergeChecks|Skipped pipelines are considered successful"
+msgstr "Pipelines ignorados são considerados bem-sucedidos"
+
+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 "Commit para o branch de origem"
@@ -27126,6 +27563,9 @@ msgstr[1] "Marcos"
msgid "Milestone due date"
msgstr "Validade do marco"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "Listas de marcos não estão disponíveis para a sua licença atual"
@@ -27306,6 +27746,12 @@ msgstr "Capacidade mínima para estar disponível antes de agendar mais espelhos
msgid "Minutes"
msgstr "Minutos"
+msgid "Mirror all branches"
+msgstr "Espelhar todas as ramificações"
+
+msgid "Mirror branches"
+msgstr "Espelhar as ramificações"
+
msgid "Mirror direction"
msgstr "Direção do espelho"
@@ -27318,6 +27764,9 @@ msgstr "Espelhar repositório"
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr "Espelhar ramificações específicas"
+
msgid "Mirror user"
msgstr "Espelhar usuário"
@@ -27378,33 +27827,48 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr "Artefatos"
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr "Criado em"
msgid "MlExperimentTracking|Details"
msgstr "Detalhes"
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr "Acompanhamento de experimentos de aprendizado de máquina"
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr "Nome"
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
-msgstr "Usuário"
+msgid "MlExperimentTracking|No experiments"
+msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
msgstr ""
+msgid "MlExperimentTracking|User"
+msgstr "Usuário"
+
msgid "Modal updated"
msgstr "Modal atualizado"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr "Espaços de nome para indexar"
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "Nomes, tópicos, avatar"
@@ -27794,11 +28261,17 @@ msgstr "Vermelho"
msgid "Navigation|Context navigation"
msgstr "Navegação de contexto"
-msgid "Navigation|Recent groups"
-msgstr "Grupos recentes"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr "GRUPOS FREQUENTES"
-msgid "Navigation|Recent projects"
-msgstr "Projetos recentes"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr "PROJETOS FREQUENTES"
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr "Grupos que você visita frequentemente aparecerão aqui."
+
+msgid "Navigation|Projects you visit often will appear here."
+msgstr "Os projetos que você visita frequentemente aparecerão aqui."
msgid "Navigation|Switch to..."
msgstr "Alternar para..."
@@ -27910,9 +28383,6 @@ msgstr "Novo requisito"
msgid "New Snippet"
msgstr "Novo snippet"
-msgid "New Test Case"
-msgstr "Novo caso de teste"
-
msgid "New User"
msgstr "Novo usuário"
@@ -28000,9 +28470,6 @@ msgstr "Novo nome"
msgid "New password"
msgstr "Nova senha"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr "Novos pipelines fazem com que os pipelines mais antigos pendentes ou rodando na mesma ramificação sejam cancelados."
-
msgid "New project"
msgstr "Novo projeto"
@@ -28357,6 +28824,15 @@ 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 "Nenhuma fonte selecionada"
@@ -28440,14 +28916,17 @@ msgstr "Redesenho da navegação"
msgid "NorthstarNavigation|New navigation"
msgstr "Nova navegação"
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
-msgstr "Nem todos os navegadores suportam dispositivos U2F. Portanto, exigimos que você configure um aplicativo de autenticação de dois fatores primeiro. Dessa forma, você sempre será capaz de entrar - mesmo quando você estiver usando um navegador não suportado."
+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. 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 "Nem todos os navegadores são compatíveis com WebAuthn. Portanto, exigimos que você configure primeiro um aplicativo de autenticação de dois fatores. Dessa forma, você sempre poderá entrar - mesmo em um navegador não compatível."
+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 "Nem todos os dados foram processados ainda, a precisão do gráfico para o período selecionado é limitada."
@@ -28543,7 +29022,7 @@ msgid "Notes|Last reply by %{name}"
msgstr "Última resposta por %{name}"
msgid "Notes|Make this an internal note"
-msgstr "Tornar disso uma nota interna"
+msgstr "Tornar uma nota interna"
msgid "Notes|Show all activity"
msgstr "Exibir todas as atividades"
@@ -28748,12 +29227,24 @@ 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|%{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 "Uma nova chave GPG foi adicionada à sua conta:"
@@ -28802,9 +29293,18 @@ 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 "Impressão digital: %{fingerprint}"
+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 "Olá %{username}!"
@@ -28832,9 +29332,6 @@ msgstr ""
msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict."
msgstr "A solicitação de mesclagem %{merge_request} não pode mais ser mesclada devido a conflito."
-msgid "Notify|Merge request %{merge_request} was %{mr_status}"
-msgstr "A solicitação de mesclagem %{merge_request} foi %{mr_status}"
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr "A solicitação de mesclagem %{merge_request} foi %{mr_status} por %{updated_by}"
@@ -28871,6 +29368,9 @@ msgstr "Nova issue: %{project_issue_url}"
msgid "Notify|No preview for this file type"
msgstr "Nenhuma pré-visualização disponível para este tipo de arquivo"
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr "Pipeline %{pipeline_link} acionado por"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
msgstr "Pipeline foi corrigido e #%{pipeline_id} foi aprovado!"
+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 ""
@@ -28892,6 +29395,9 @@ msgstr "O projeto %{project_name} foi exportado com sucesso."
msgid "Notify|Remote mirror"
msgstr "Espelho remoto"
+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 ""
@@ -29368,6 +29874,9 @@ msgstr "Verificações sob demanda são executadas fora do ciclo DevOps e encont
msgid "OnDemandScans|Only project owners and maintainers can select runner tags."
msgstr "Apenas proprietários e mantenedores de projetos podem selecionar tags de execução."
+msgid "OnDemandScans|Pre-scan verification for %{profile_name} completed with"
+msgstr ""
+
msgid "OnDemandScans|Repeats"
msgstr "Repetições"
@@ -29437,9 +29946,6 @@ msgstr "Fuso horário"
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr "Verificar"
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,29 +30239,35 @@ 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 services."
-msgstr "Permitir solicitações para a rede local de ganchos e serviços."
+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 "Permitir requisições à rede local a partir de hooks de sistema"
-msgid "OutboundRequests|Allow requests to the local network from web hooks and services"
-msgstr "Permitir requisições à rede local de web hooks e serviços"
+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 "Reforçar proteção de ataque de redefinição de DNS"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
+msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
-msgstr "Endereços IP locais e nomes de domínio que ganchos e serviços podem acessar"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
+msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr "Requisições de saída"
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
-msgstr "Resolve endereços IP uma vez e os usa para enviar requisições."
+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 ""
@@ -30551,6 +31063,9 @@ msgstr "Exclusão pendente"
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "Exclusão pendente"
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr "Escolha um nome"
-msgid "Pin code"
-msgstr "Código PIN"
-
msgid "Pipeline"
msgstr "Pipeline"
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ msgstr "Pipelines"
msgid "Pipelines charts"
msgstr "Gráficos de pipelines"
+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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr "Limpar cache dos executores"
-msgid "Pipelines|Configuration validation currently not available."
-msgstr "Validação de configuração atualmente não disponível."
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr "GitLab Runner é um aplicativo que funciona com GitLab CI/CD para execut
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,8 +31837,8 @@ msgstr "Proprietário"
msgid "Pipelines|Pipeline Editor"
msgstr "Editor de pipeline"
-msgid "Pipelines|Pipeline syntax is correct."
-msgstr "Sintaxe do pipeline está correta."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr "Cache do projeto redefinido com sucesso."
@@ -31325,6 +31846,9 @@ msgstr "Cache do projeto redefinido com sucesso."
msgid "Pipelines|Ready to set up CI/CD for your project?"
msgstr "Pronto para configurar CI/CD para seu projeto?"
+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|Revoke trigger"
msgstr ""
@@ -31361,14 +31885,14 @@ msgstr ""
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
msgstr "Ocorreu um erro ao buscar os pipelines. Tente novamente daqui a pouco ou entre em contato com sua equipe de suporte."
-msgid "Pipelines|This GitLab CI configuration is invalid."
-msgstr "Essa configuração do GitLab CI é invalida."
+msgid "Pipelines|This GitLab CI configuration is invalid. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is invalid:"
msgstr "Essa configuração do GitLab CI é invalida:"
-msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}."
-msgstr "Essa configuração do GitLab CI é invalida: %{reason}"
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
msgstr "Essa configuração do GitLab CI é válida."
@@ -31397,6 +31921,12 @@ msgstr ""
msgid "Pipelines|Try test template"
msgstr "Tente um modelo de teste"
+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 "Usar um arquivo de modelo %{codeStart}.gitlab-ci.yml%{codeEnd} para explorar como funciona o CI/CD."
@@ -31418,6 +31948,9 @@ msgstr "Análise de YAML mesclado"
msgid "Pipelines|Visualize"
msgstr "Visualizar"
+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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "Por favor, ative e migre para o armazenamento com hash para evitar problemas de segurança e garantir a integridade dos dados. %{migrate_link}"
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "Digite um número não-negativo"
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr "Por favor digite sua senha atual."
@@ -31823,8 +32365,8 @@ msgstr "Por favor selecione"
msgid "Please select a Jira project"
msgstr "Selecione um projeto Jira"
-msgid "Please select a country"
-msgstr "Por favor selecione um país"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr "Por favor, selecione um grupo"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr "Pré-visualização de carga"
+msgid "Previous"
+msgstr "Anterior"
+
msgid "Previous Artifacts"
msgstr "Artefatos anteriores"
@@ -32246,89 +32791,32 @@ msgstr ""
msgid "Proceed"
msgstr "Prosseguir"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr "Voltar aos painéis"
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr "Criando sua instância de análise de produto..."
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr "Detalhes sobre como configurar a análise do produto para coletar dados."
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr "Detalhes da instrumentação"
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr "Configurar análise de produto"
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
-msgstr ""
-
-msgid "Product Analytics|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 "Product analytics"
msgstr "Análise de produtos"
msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All pages"
-msgstr ""
+msgid "ProductAnalytics|All Features"
+msgstr "Todos os recursos"
+
+msgid "ProductAnalytics|All Pages"
+msgstr "Todas as páginas"
+
+msgid "ProductAnalytics|All Sessions Compared"
+msgstr "Todas as sessões comparadas"
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
msgstr ""
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
+msgstr "Média por usuário"
+
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
+msgid "ProductAnalytics|Back to dashboards"
+msgstr "Voltar aos painéis"
+
msgid "ProductAnalytics|Cancel Edit"
msgstr "Cancelar edição"
-msgid "ProductAnalytics|Choose a chart type on the right"
-msgstr ""
-
-msgid "ProductAnalytics|Choose a measurement to start"
-msgstr ""
-
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr "Editar"
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
-msgstr "Painel"
+msgid "ProductAnalytics|Set up product analytics"
+msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
-msgstr "Estatística única"
+msgid "ProductAnalytics|The host to send all tracking events to"
+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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User activity"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ msgstr "Desconectar"
msgid "Profiles|Disconnect %{provider}"
msgstr "Desconectar %{provider}"
+msgid "Profiles|Discord ID is too long (maximum is %{max_length} characters)."
+msgstr "O ID do Discord está muito longo (máximo é %{max_length} caracteres)."
+
+msgid "Profiles|Discord ID is too short (minimum is %{min_length} characters)."
+msgstr "O ID do Discord está muito curto (mínimo é %{min_length} caracteres)."
+
msgid "Profiles|Do not show on profile"
msgstr "Não mostrar no perfil"
@@ -32906,8 +33409,8 @@ msgstr "Você deve transferir a propriedade ou excluir grupos dos quais você é
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Você precisa delegar outro usuário para ser dono ou apagar esses grupos antes de excluir sua conta."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
-msgstr ""
+msgid "Profiles|Your Discord user ID. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+msgstr "Seu ID de usuário do Discord. %{external_accounts_link_start}Saiba mais.%{external_accounts_link_end}"
msgid "Profiles|Your LinkedIn profile name from linkedin.com/in/profilename"
msgstr "Seu nome de perfil no LinkedIn em linkedin.com/in/nomedeperfil"
@@ -33080,6 +33583,9 @@ msgstr "Membros do projeto"
msgid "Project milestone"
msgstr "Marco de projeto"
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Nome do projeto"
@@ -33092,6 +33598,9 @@ 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"
@@ -33119,6 +33628,9 @@ msgstr ""
msgid "Project visibility level will be changed to match namespace rules when transferring to a group."
msgstr "O nível de visibilidade do projeto será alterado para coincidir com as regras do espaço de nome ao transferir para um grupo."
+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 ""
@@ -33168,13 +33680,13 @@ msgid "ProjectList|Explore"
msgstr "Explorar"
msgid "ProjectList|Starred"
-msgstr ""
+msgstr "Favoritos"
msgid "ProjectList|Topics"
msgstr "Tópicos"
msgid "ProjectList|Yours"
-msgstr ""
+msgstr "Seus"
msgid "ProjectOverview|Fork"
msgstr "Fork"
@@ -33215,9 +33727,21 @@ msgstr "ID do Projeto: %{project_id}"
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 "Qualidade do código"
+
msgid "ProjectQualitySummary|Coverage"
msgstr "Cobertura"
+msgid "ProjectQualitySummary|Critical"
+msgstr "Crítico"
+
msgid "ProjectQualitySummary|Failure"
msgstr "Falha"
@@ -33230,6 +33754,9 @@ msgstr "Ajude-nos a melhorar esta página"
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr "Últimos resultados do pipeline"
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr "Saiba mais sobre a cobertura de testes"
@@ -33272,8 +33799,11 @@ msgstr "A porcentagem de testes bem-sucedidos, reprovados ou ignorados."
msgid "ProjectQualitySummary|This page helps you understand the code testing trends for your project. Let us know how we can improve it!"
msgstr "Esta página ajuda você a entender as tendências de teste de código para seu projeto. Deixe-nos saber como podemos melhorá-lo!"
-msgid "ProjectSelect| or group"
-msgstr " ou grupo"
+msgid "ProjectQualitySummary|Violations"
+msgstr "Violações"
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr "Violações encontradas"
msgid "ProjectSelect|No matching results"
msgstr "Nenhum resultado correspondente"
@@ -33287,9 +33817,6 @@ msgstr "Pesquisar projetos"
msgid "ProjectSelect|Select a project"
msgstr "Selecionar um projeto"
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,14 +33946,11 @@ msgstr "Configurações adicionais que influenciam como e onde as mesclagem são
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr "Todas as solicitações de mesclagem e commits são feitas nessa ramificação, a menos que você especifique uma diferente."
-msgid "ProjectSettings|All threads must be resolved"
-msgstr "Todos os tópicos devem ser resolvidos"
-
msgid "ProjectSettings|Allow"
msgstr "Permitir"
msgid "ProjectSettings|Allow anyone to pull from Package Registry"
-msgstr ""
+msgstr "Permitir que qualquer pessoa extraia do Registro de Pacotes"
msgid "ProjectSettings|Always show thumbs-up and thumbs-down award emoji buttons on issues, merge requests, and snippets."
msgstr "Sempre mostrar os emojis de aprovação e desaprovação com polegar em issues, solicitações de mesclagem e snippets."
@@ -33438,7 +33962,7 @@ msgid "ProjectSettings|Analytics Dashboards"
msgstr "Painéis analíticos"
msgid "ProjectSettings|Anyone can pull packages with a package manager API."
-msgstr ""
+msgstr "Qualquer um pode extrair pacotes com uma API do gerenciador de pacotes."
msgid "ProjectSettings|Auto-close referenced issues on default branch"
msgstr "Fechar automaticamente as issues referenciadas na ramificação padrão"
@@ -33474,7 +33998,7 @@ msgid "ProjectSettings|Combine git tags with release notes, release evidence, an
msgstr ""
msgid "ProjectSettings|Configure your infrastructure."
-msgstr "Configure sua infraestrutura."
+msgstr "Configurar sua infraestrutura."
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr "Contate um administrador para alterar essa configuração."
@@ -33572,9 +34096,6 @@ msgstr "Infraestrutura"
msgid "ProjectSettings|Internal"
msgstr "Interno"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr "Introduz o risco de mesclar alterações que não passam pelo pipeline."
-
msgid "ProjectSettings|Issues"
msgstr "Issues"
@@ -33588,7 +34109,7 @@ msgid "ProjectSettings|Manage who can see the project in the public access direc
msgstr "Gerenciar quem pode ver o projeto no diretório de acesso público."
msgid "ProjectSettings|Manages large files such as audio, video, and graphics files."
-msgstr "Gerencia arquivos grandes, como arquivos de áudio, vídeo e gráficos."
+msgstr "Gerenciar arquivos grandes, como arquivos de áudio, vídeo e gráficos."
msgid "ProjectSettings|Maximum %{maxLength} characters."
msgstr "Máximo de %{maxLength} caracteres."
@@ -33617,9 +34138,6 @@ msgstr "Solicitações de mesclagem"
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 "As solicitações de mesclagem aprovadas para mesclagem são enfileiradas e os pipelines validam os resultados combinados das ramificações de origem e destino antes da mesclagem. %{link_start}O que são merge train?%{link_end}"
-msgid "ProjectSettings|Merge requests can't be merged if the latest pipeline did not succeed or is still running."
-msgstr "As solicitações de mesclagem não podem ser mescladas se o pipeline mais recente não tiver êxito ou ainda estiver em execução."
-
msgid "ProjectSettings|Merge suggestions"
msgstr "Sugestões de mesclagem"
@@ -33630,7 +34148,7 @@ msgid "ProjectSettings|Monitor"
msgstr "Monitor"
msgid "ProjectSettings|Monitor the health of your project and respond to incidents."
-msgstr ""
+msgstr "Monitorar a saúde do seu projeto e responda a incidentes."
msgid "ProjectSettings|No merge commits are created."
msgstr "Nenhum commit de mesclagem foi criado."
@@ -33656,9 +34174,6 @@ msgstr "Páginas"
msgid "ProjectSettings|Pages for project documentation."
msgstr "Páginas de documentação do projeto."
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "Pipelines devem ter êxito"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr "Evitar que links diretos para arquivos de mídia potencialmente confidenciais"
@@ -33672,7 +34187,7 @@ msgid "ProjectSettings|Public"
msgstr "Público"
msgid "ProjectSettings|Publish, store, and view packages in a project."
-msgstr ""
+msgstr "Publicar, armazenar e visualizar pacotes em um projeto."
msgid "ProjectSettings|Releases"
msgstr "Versões"
@@ -33701,11 +34216,11 @@ msgstr "Lançar novos recursos sem reimplantar com feature flag."
msgid "ProjectSettings|Search for topic"
msgstr "Pesquisar tópico"
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr "Segurança e conformidade"
-msgid "ProjectSettings|Security & Compliance for this project"
-msgstr "Segurança e conformidade para esse projeto"
+msgid "ProjectSettings|Security and compliance for this project."
+msgstr "Segurança e conformidade para esse 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."
@@ -33720,7 +34235,7 @@ msgid "ProjectSettings|Set the default behavior of this option in merge requests
msgstr "Defina o comportamento padrão desta opção em solicitações de mesclagem. As alterações também são aplicadas às solicitações de mesclagem existentes."
msgid "ProjectSettings|Share code with others outside the project."
-msgstr "Compartilhe o código com outras pessoas de fora do projeto."
+msgstr "Compartilhar o código com outras pessoas de fora do projeto."
msgid "ProjectSettings|Show default award emojis"
msgstr "Mostrar emojis de recopensa por padrão"
@@ -33728,9 +34243,6 @@ msgstr "Mostrar emojis de recopensa por padrão"
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr "Mostrar link para criar ou ver uma solicitação de mesclagem ao fazer push da linha de comando"
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr "Pipelines ignorados são considerados bem-sucedidos"
-
msgid "ProjectSettings|Snippets"
msgstr "Snippets"
@@ -33807,10 +34319,10 @@ msgid "ProjectSettings|Users can request access"
msgstr "Usuários podem solicitar acesso"
msgid "ProjectSettings|View and edit files in this project."
-msgstr "Visualize e edite arquivos neste projeto."
+msgstr "Ver e editar arquivos neste projeto."
msgid "ProjectSettings|View and edit files in this project. When set to **Everyone With Access** non-project members have only read access."
-msgstr ""
+msgstr "Visualizar e editar arquivos neste projeto. Quando definido como **Todos com acesso**, membros que não são do projeto têm apenas acesso de leitura."
msgid "ProjectSettings|View project analytics."
msgstr "Ver análise de projeto."
@@ -33819,7 +34331,7 @@ msgid "ProjectSettings|Visibility options for this fork are limited by the curre
msgstr "As opções de visibilidade para este fork são limitadas pela visibilidade atual do projeto fonte."
msgid "ProjectSettings|Visualize the project's performance metrics."
-msgstr "Visualize as métricas de desempenho do projeto."
+msgstr "Ver as métricas de desempenho do projeto."
msgid "ProjectSettings|Warn about Potentially Unwanted Characters"
msgstr "Avisar sobre caracteres potencialmente indesejados"
@@ -33965,6 +34477,9 @@ msgstr "Projetos (%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr "Projetos obtidos com sucesso"
@@ -34089,7 +34604,10 @@ msgid "ProjectsNew|Migrate your data from an external source like GitHub, Bitbuc
msgstr "Migre seus dados de uma fonte externa como GitHub, Bitbucket, ou outra instância do GitLab."
msgid "ProjectsNew|Must start with a lowercase or uppercase letter, digit, emoji, or underscore. Can also contain dots, pluses, dashes, or spaces."
-msgstr ""
+msgstr "Deve começar com uma letra minúscula ou maiúscula, dígito, emoji ou sublinhado. Também pode conter pontos, sinais de adição, traços ou espaços."
+
+msgid "ProjectsNew|New project"
+msgstr "Novo projeto"
msgid "ProjectsNew|No import options available"
msgstr "Nenhuma opção de importação disponível"
@@ -34106,6 +34624,9 @@ msgstr "Configuração do projeto"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "Descrição do projeto %{tag_start}(opcional)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr "Projetos"
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr "Recomendado se você é novo no GitLab"
@@ -34286,9 +34807,6 @@ msgstr "Entre em contato com o proprietário %{link_start}%{owner_name}%{link_en
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr "Entre em contato com seu administrador para aprimorar sua licença."
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "Modelos de descrição permitem que você defina modelos de contextos específicos para issue e descrição de merge requests para seu projeto."
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr "Dispensar promoção de central de serviços"
@@ -34397,12 +34915,6 @@ msgstr "Quando você tem muitas issues, pode ser difícil obter uma visão geral
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr "Você pode restringir o acesso a ramificações protegidas escolhendo um cargo (Mantenedores, Desenvolveres) e também determinados usuários."
-msgid "Promotions|description templates"
-msgstr "modelos de descrição"
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr "para ajudar seus contribuintes à se comunicar de maneira eficaz!"
-
msgid "Prompt users to upload SSH keys"
msgstr "Solicitar que os usuários adicionem chaves SSH"
@@ -34574,9 +35086,25 @@ msgstr "Você pode adicionar apenas grupos que tenham este projeto compartilhado
msgid "ProtectedBranch|default"
msgstr "padrão"
+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 "Adicionar regras de aprovação"
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr "Adicionar regras de implantação"
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr "Permitido para aprovar"
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr "Permitido para implantar"
@@ -34586,11 +35114,23 @@ msgstr ""
msgid "ProtectedEnvironments|Approval rules"
msgstr ""
+msgid "ProtectedEnvironments|Approvals required"
+msgstr "Aprovações necessárias"
+
+msgid "ProtectedEnvironments|Create approval rule"
+msgstr "Criar regra de aprovação"
+
msgid "ProtectedEnvironments|Create deployment rule"
msgstr "Criar regra de implantação"
-msgid "ProtectedEnvironments|Delete deployment rule"
-msgstr ""
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr "Excluir regra de aprovação"
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr "Excluir regra de implantação"
+
+msgid "ProtectedEnvironments|Edit"
+msgstr "Editar"
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
msgstr ""
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+msgstr "Salvar"
+
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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr "Usuários"
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} poderá ser editado por desenvolvedores. Tem certeza disso?"
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "Permitido para implantar"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr "Pronto para mesclar!"
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr "Rebase"
-
msgid "Rebase completed"
msgstr "Rebase concluído"
-msgid "Rebase in progress"
-msgstr "Rebase em andamento"
-
msgid "Rebase source branch"
msgstr "ramificação de origem de rebase"
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] "Atualizando em um segundo para mostrar o status atualizado..."
@@ -35200,14 +35746,14 @@ msgstr "Registrar"
msgid "Register / Sign In"
msgstr "Registrar/Entrar"
-msgid "Register Two-Factor Authenticator"
-msgstr "Registrar autenticador de dois fatores"
+msgid "Register a WebAuthn device"
+msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "Registrar dispositivo de dois fatores universal (U2F)"
+msgid "Register a one-time password authenticator"
+msgstr "Registrar um autenticador de senha de uso único"
-msgid "Register WebAuthn Device"
-msgstr "Registrar dispositivo WebAuthn"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
+msgstr ""
msgid "Register device"
msgstr "Registar dispositivo"
@@ -35299,6 +35845,9 @@ msgstr "Rejeitado (fechado)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr "Relacionar com %{issuable_type} %{add_related_issue_link}"
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr "Feature flags relacionados"
@@ -35710,7 +36259,7 @@ msgid "Reopen %{issueType}"
msgstr "Reabrir %{issueType}"
msgid "Reopen %{noteable}"
-msgstr ""
+msgstr "Reabrir %{noteable}"
msgid "Reopen epic"
msgstr "Reabrir epic"
@@ -35800,40 +36349,40 @@ msgid "ReportAbuse|Add another link"
msgstr "Adicionar outro link"
msgid "ReportAbuse|Link to spam"
-msgstr ""
+msgstr "Link do spam"
msgid "ReportAbuse|Report abuse to administrator"
msgstr "Reportar abuso ao administrador"
msgid "ReportAbuse|Something else."
-msgstr ""
+msgstr "Algo mais."
msgid "ReportAbuse|They're being offensive or abusive."
-msgstr ""
+msgstr "Eles estão sendo ofensivos ou abusivos."
msgid "ReportAbuse|They're crypto mining."
-msgstr ""
+msgstr "Eles estão minerando criptomoedas."
msgid "ReportAbuse|They're phishing."
-msgstr ""
+msgstr "Eles estão fazendo phishing."
msgid "ReportAbuse|They're posting malware."
-msgstr ""
+msgstr "Eles estão postando malware."
msgid "ReportAbuse|They're posting personal information or credentials."
-msgstr ""
+msgstr "Eles estão postando informações pessoais ou credenciais."
msgid "ReportAbuse|They're posting spam."
-msgstr ""
+msgstr "Eles estão postando spam."
msgid "ReportAbuse|They're violating a copyright or trademark."
-msgstr ""
+msgstr "Eles estão violando direitos autorais ou marca registrada."
msgid "ReportAbuse|URL of this user posting spam"
-msgstr ""
+msgstr "URL deste usuário postando spam"
msgid "ReportAbuse|Why are you reporting this user?"
-msgstr ""
+msgstr "Por que você está reportando este usuário?"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Denunciado em %{timeAgo} por %{reportedBy}"
@@ -36234,15 +36783,21 @@ msgstr "O requisito%{reference} foi adicionado"
msgid "Requirement %{reference} has been updated"
msgstr "O requisito%{reference} foi atualizado"
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr ""
-
msgid "Requirements"
msgstr "Requisitos"
msgid "Requirements can be based on users, stakeholders, system, software, or anything else you find important to capture."
msgstr "Os requisitos podem ser baseados em usuários, partes interessadas, sistema, software ou qualquer outra coisa que você considere importante capturar."
+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] "Requer %d aprovação de usuários qualificados."
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr "Continuar"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr "A recuperação do relatório de conformidade falhou. Atualize a página e tente novamente."
-
msgid "Retry"
msgstr "Tentar novamente"
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr "Executar tarefa"
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ msgstr "Ativo"
msgid "Runners|Add notes such as the runner owner or what it should be used for."
msgstr "Adicione notas como o proprietário do executor ou para que deve ser usado."
+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|Administrator"
msgstr "Administrador"
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ msgstr "Configuração"
msgid "Runners|Containers"
msgstr " Contêineres"
+msgid "Runners|Copy and paste the following command into your command line to register the runner."
+msgstr ""
+
msgid "Runners|Copy instructions"
msgstr "Copiar instruções"
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr "Ambiente"
+
msgid "Runners|Executor"
msgstr "Executor"
@@ -36822,6 +37386,12 @@ msgstr "Filtrar projetos"
msgid "Runners|Get started with runners"
msgstr "Comece com os executores"
+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 runners page"
+msgstr "Ir para a página de executores"
+
msgid "Runners|Group"
msgstr "Grupo"
@@ -36840,6 +37410,9 @@ msgstr "Ocioso"
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr "Instalar GitLab Runner"
+
msgid "Runners|Install a runner"
msgstr "Instalar um executor"
@@ -36867,6 +37440,12 @@ msgstr "Travado para este projeto"
msgid "Runners|Maintenance note"
msgstr "Nota de manutenção"
+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 "Tempo limite máximo da tarefa"
@@ -36876,6 +37455,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|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr "Nome"
@@ -36888,6 +37470,9 @@ msgstr "Nunca contatados:"
msgid "Runners|Never expires"
msgstr "Nunca expira"
+msgid "Runners|New"
+msgstr "Novo"
+
msgid "Runners|New group runners can be registered"
msgstr "Novos executores do grupo podem ser registrados"
@@ -36930,6 +37515,9 @@ msgstr "Apenas administradores podem ver isso."
msgid "Runners|Operating systems"
msgstr "Sistemas operacionais"
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr "Proprietário"
@@ -36962,6 +37550,12 @@ msgstr "Protegido"
msgid "Runners|Recommended"
msgstr "Recomendado"
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr "Registrar um executor de grupo"
@@ -36977,6 +37571,9 @@ 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 "Registre quantos executores quiser. Você pode registrar executores como usuários separados, em servidores separados e em sua máquina local."
+msgid "Runners|Register runner"
+msgstr "Registrar executor"
+
msgid "Runners|Registration token"
msgstr "Token de registro"
@@ -37001,6 +37598,9 @@ msgstr "Executor #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ msgstr "Expiração do token de autenticação do executor"
msgid "Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired."
msgstr ""
+msgid "Runners|Runner created."
+msgstr "Executor criado."
+
+msgid "Runners|Runner description"
+msgstr ""
+
msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
msgstr ""
@@ -37088,9 +37694,15 @@ msgstr ""
msgid "Runners|Security or compatibility upgrades are recommended."
msgstr "Atualizações de segurança ou compatibilidade são recomendadas."
+msgid "Runners|See more %{linkStart}installation methods and architectures%{linkEnd}."
+msgstr ""
+
msgid "Runners|Select all"
msgstr "Selecionar todos"
+msgid "Runners|Select platform specifications to install GitLab Runner."
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr "Selecione projetos para atribuir a este executor"
@@ -37124,6 +37736,12 @@ msgstr "Obsoleto:"
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr "Etapa 1"
+
+msgid "Runners|Step 2"
+msgstr "Etapa 2"
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ msgstr "Tags"
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 "Tags controlam que tipo de tarefas um executor pode manipular. Ao marcar um executor, você garante que os executores compartilhados lidem apenas com as tarefas para os quais estão equipados."
+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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr "O projeto, grupo ou instância onde o executor foi registrado. Os executores de instâncias são sempre de propriedade do Administrador."
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ msgstr "Atualização recomendada"
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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr "projeto"
msgid "Runners|shared"
msgstr "compartilhado"
-msgid "Runner|New"
-msgstr "Novo"
-
-msgid "Runner|Owner"
-msgstr "Proprietário"
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "Executando"
@@ -37282,6 +37900,9 @@ msgstr "Tokens de descoberta de SAML"
msgid "SAML for %{group_name}"
msgstr "SAML para %{group_name}"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr "Entrada única SAML"
@@ -37306,9 +37927,6 @@ 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 "SAST Configuration"
-msgstr "Configuração de SAST"
-
msgid "SCIM|SCIM Token"
msgstr "Token SCIM"
@@ -37438,17 +38056,20 @@ msgstr "%{period} %{days} a %{time}"
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
-msgstr ""
+msgid "ScanExecutionPolicy|Add condition"
+msgstr "Adicionar condição"
+
+msgid "ScanExecutionPolicy|Conditions"
+msgstr "Condições"
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
msgstr ""
@@ -37489,9 +38110,15 @@ msgstr "agente"
msgid "ScanExecutionPolicy|branch"
msgstr "ramificação"
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,24 +38567,27 @@ msgstr ""
msgid "Security"
msgstr "Segurança"
-msgid "Security & Compliance"
-msgstr "Segurança e conformidade"
-
-msgid "Security Configuration"
-msgstr "Configurações de segurança"
-
msgid "Security Dashboard"
msgstr "Painel de segurança"
msgid "Security Finding not found"
msgstr ""
-msgid "Security dashboard"
-msgstr "Painel de segurança"
+msgid "Security Policy project already exists."
+msgstr ""
-msgid "Security navigation"
+msgid "Security and Compliance"
+msgstr "Segurança e conformidade"
+
+msgid "Security capabilities"
msgstr ""
+msgid "Security configuration"
+msgstr "Configuração de segurança"
+
+msgid "Security dashboard"
+msgstr "Painel de segurança"
+
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -38084,8 +38714,8 @@ msgstr "Métricas de segurança de tempo de execução para ambientes de aplicaÃ
msgid "SecurityConfiguration|SAST Analyzers"
msgstr "Análises de SAST"
-msgid "SecurityConfiguration|SAST Configuration"
-msgstr "Configuração de SAST"
+msgid "SecurityConfiguration|SAST configuration"
+msgstr "Configuração SAST"
msgid "SecurityConfiguration|Secure your project"
msgstr "Proteja seu projeto"
@@ -38198,6 +38828,9 @@ msgstr "Escolha um projeto"
msgid "SecurityOrchestration|Choose approver type"
msgstr "Escolha o tipo de aprovador"
+msgid "SecurityOrchestration|Clear all"
+msgstr "Limpar tudo"
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr "Crie regras de vulnerabilidade mais robustas e aplique-as a todos os seus projetos."
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr "Nenhum resultado correspondente"
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 "Aprovações de segurança"
@@ -38417,6 +39062,9 @@ msgstr "Selecionar grupos"
msgid "SecurityOrchestration|Select policy"
msgstr "Selecionar política"
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr "Selecionar tipo de verificação"
@@ -38426,6 +39074,9 @@ msgstr "Selecionar projeto de segurança"
msgid "SecurityOrchestration|Select users"
msgstr "Selecionar usuários"
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr "%{firstProject}, %{secondProject} e %{rest}"
msgid "SecurityReports|Activity"
msgstr "Atividade"
+msgid "SecurityReports|Add comment and 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."
@@ -39047,6 +39701,9 @@ msgstr "Selecionar etiqueta"
msgid "Select labels"
msgstr "Selecionar etiquetas"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "Selecionar momento do merge"
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr "Enviar"
@@ -39275,6 +39941,12 @@ msgstr "Contas de serviço"
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|Enable Service Desk"
msgstr "Ativar central de Serviços"
@@ -39410,6 +40082,9 @@ msgstr "Defina o tempo máximo de sessão para um terminal web."
msgid "Set the milestone to %{milestone_reference}."
msgstr "Definir o marco como %{milestone_reference}."
+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 ""
@@ -39437,8 +40112,8 @@ msgstr "Configurar integração do Jira"
msgid "Set up a %{type} runner for a project"
msgstr "Configurar um executor %{type} para um projeto"
-msgid "Set up a hardware device as a second factor to sign in."
-msgstr "Definir um dispositivo de hardware como o segundo fator para entrar."
+msgid "Set up a hardware device to enable two-factor authentication (2FA)."
+msgstr "Configure um dispositivo de hardware para habilitar a autenticação de dois fatores (2FA)."
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "Configurar asserções/atributos/alegações (email, first_name, last_name) e NameID de acordo com %{docsLinkStart}a documentação %{icon}%{docsLinkEnd}"
@@ -39688,6 +40363,9 @@ msgstr "Mostrar conteúdo do arquivo"
msgid "Show filters"
msgstr "Mostrar filtros"
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr "Entrar"
-msgid "Sign in / Register"
-msgstr "Entrar / Criar conta"
-
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 "Entre como um usuário com um endereço de e-mail correspondente, adicione o e-mail a esta conta, ou cadastre uma nova conta utilizando o e-mail correspondente."
@@ -40008,7 +40683,22 @@ msgstr "A integração com o Slack permite que você interaja com o GitLab por m
msgid "Slack logo"
msgstr "Logotipo do Slack"
+msgid "Slack notifications integration is deprecated"
+msgstr "A integração de notificações do Slack está obsoleta"
+
+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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
+msgstr "Tem certeza de que deseja remover este projeto do GitLab para Slack?"
+
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
msgstr ""
msgid "SlackIntegration|Client ID"
@@ -40017,6 +40707,9 @@ msgstr "ID do cliente"
msgid "SlackIntegration|Client secret"
msgstr "Segredo do cliente"
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr "GitLab para Slack"
@@ -40024,17 +40717,23 @@ msgid "SlackIntegration|GitLab for Slack was successfully installed."
msgstr "GitLab for Slack foi instalado com sucesso."
msgid "SlackIntegration|Install GitLab for Slack app"
+msgstr "Instalar GitLab para Slack"
+
+msgid "SlackIntegration|Perform deployments."
msgstr ""
msgid "SlackIntegration|Project alias"
msgstr "Alias do projeto"
msgid "SlackIntegration|Reinstall GitLab for Slack app"
-msgstr ""
+msgstr "Reinstalar GitLab para Slack"
msgid "SlackIntegration|Remove project"
msgstr "Remover projeto"
+msgid "SlackIntegration|Run ChatOps jobs."
+msgstr ""
+
msgid "SlackIntegration|See the list of available commands in Slack after setting up this integration by entering"
msgstr "Veja a lista de comandos disponíveis no Slack após configurar esta integração digitando"
@@ -40057,7 +40756,7 @@ msgid "SlackIntegration|Update to the latest version"
msgstr "Atualizar para a última versão"
msgid "SlackIntegration|Update to the latest version of GitLab for Slack to get notifications"
-msgstr ""
+msgstr "Atualize para a versão mais recente do GitLab para Slack para receber notificações"
msgid "SlackIntegration|Update to the latest version to receive notifications from GitLab."
msgstr "Atualize para a versão mais recente para receber notificações do GitLab."
@@ -40068,7 +40767,13 @@ msgstr "Token de verificação"
msgid "SlackIntegration|You can now close this window and go to your Slack workspace."
msgstr "Agora você pode fechar esta janela e acessar seu workspace do Slack."
+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 "Talvez seja necessário reinstalar o GitLab para Slack quando fizer %{linkStart}atualizações ou alterar as permissões%{linkEnd}."
+
+msgid "SlackIntegration|cannot have more than %{limit} channels"
msgstr ""
msgid "SlackModal|Are you sure you want to change the project?"
@@ -40120,7 +40825,7 @@ msgid "Slack|GitLab for Slack now supports channel-based notifications. Let your
msgstr ""
msgid "Slack|To start using notifications, %{startMarkup}enable the GitLab for Slack app integration%{endMarkup} in your project settings."
-msgstr ""
+msgstr "Para começar a usar as notificações, %{startMarkup}a integração do GitLab para Slack%{endMarkup} nas configurações do seu projeto."
msgid "Slack|To start using slash commands, connect your GitLab account."
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr "Proteção contra spam e anti-bot"
msgid "Spam log successfully submitted as ham."
msgstr "Registro de spam foi enviado com sucesso como ham."
+msgid "Specific branches"
+msgstr "Ramificações específicas"
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40747,7 +41458,7 @@ msgid "Specify an email address regex pattern to identify default internal users
msgstr ""
msgid "Speed up your pipelines with Needs relationships"
-msgstr ""
+msgstr "Acelere seus pipelines com relacionamentos de necessidades"
msgid "Spent at"
msgstr "Gasto em"
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr "Nome do serviço"
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr "Verificações de status"
@@ -41631,16 +42345,22 @@ msgstr ""
msgid "SuperSonics|Start free trial"
msgstr "Iniciar a avaliação gratuita"
+msgid "SuperSonics|Subscription detail synchronization has started and will complete soon."
+msgstr ""
+
msgid "SuperSonics|Subscription details"
msgstr "Detalhes da assinatura"
+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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr "O código de ativação deve ser um texto alfanumérico de 24 caracteres"
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ msgstr "Os usuários com um cargo de convidado ou aqueles que não pertencem a u
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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr "Sua assinatura"
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ msgstr "Lista de tags:"
msgid "Tag name"
msgstr "Nome da tag"
+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 ""
@@ -42060,7 +42792,7 @@ msgid "TasksToBeDone|Set up CI/CD pipelines to build, test, deploy, and monitor
msgstr "Configure pipelines de CI/CD para construir, testar, implantar e monitorar código"
msgid "Tasks|%{complete_count} of %{total_count} %{checklist_item_noun} completed"
-msgstr ""
+msgstr "%{complete_count} de %{total_count} %{checklist_item_noun} concluído"
msgid "Tasks|%{complete_count}/%{total_count} %{checklist_item_noun}"
msgstr ""
@@ -42285,12 +43017,12 @@ msgstr "Seu projeto não possui nenhum arquivo do Terraform state"
msgid "Test"
msgstr "Teste"
-msgid "Test Cases"
-msgstr "Casos de teste"
-
msgid "Test case"
msgstr "Caso de teste"
+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] "O valor de cobertura de teste para este pipeline foi calculado pelo valor de cobertura de %d tarefa."
@@ -42310,9 +43042,6 @@ msgstr "Mover caso de teste"
msgid "TestCases|Moving test case"
msgstr "Movendo caso de teste"
-msgid "TestCases|New Test Case"
-msgstr "Novo caso de teste"
-
msgid "TestCases|New test case"
msgstr "Novo caso de teste"
@@ -42439,6 +43168,9 @@ msgstr "Texto (opcional)"
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 "Estilo do texto"
@@ -42498,6 +43230,9 @@ msgstr "O rastreador de issue é o lugar para adicionar coisas que precisam ser
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 "A integração de notificações do Slack está obsoleta e será removida em uma versão futura. Para continuar recebendo notificações do Slack, use o aplicativo GitLab para Slack. %{learn_more_link_start}Saiba mais%{link_end}."
+
msgid "The Snowplow cookie domain."
msgstr ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr "O relatório de conformidade mostra as violações de solicitação de mesclagem mescladas em ambientes protegidos."
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "A conexão expirará após %{timeout}. Para repositórios que demoram mais tempo, use a combinação clone/push."
@@ -42600,6 +43332,9 @@ msgstr "A lista de dependências detalha informações sobre os componentes usad
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "A implantação desta tarefa para o ambiente %{environmentLink} foi mal sucedida."
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr "O diretório foi criado com sucesso."
@@ -42913,7 +43648,16 @@ msgstr "O recurso que você está tentando acessar não existe ou você não tem
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43892,7 +44633,7 @@ msgid "This project does not have a wiki homepage yet"
msgstr "Este projeto ainda não tem uma página inicial na wiki"
msgid "This project has no active access tokens."
-msgstr ""
+msgstr "Este projeto não tem tokens de acesso ativos."
msgid "This project is %{strongStart}NOT%{strongEnd} a fork, and has the following:"
msgstr "Este projeto %{strongStart}NÃO%{strongEnd} tem um fork e tem o seguinte:"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "Este executor somente será executado em Pipelines acionados em ramificações protegidas"
@@ -44008,11 +44752,8 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr "Isso invalidará seus aplicativos registrados e dispositivos U2F / WebAuthn."
-
-msgid "This will invalidate your registered applications and U2F devices."
-msgstr "Isso invalidará seus aplicativos registrados e dispositivos U2F."
+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 "Isso removerá o relacionamento do fork entre esse projeto e %{fork_source}"
@@ -44462,6 +45203,9 @@ msgstr "Para começar, insira seu URL de Host do Gitea e um %{link_to_personal_t
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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr "Pipelines de disparo para atualizações de espelho"
@@ -45143,9 +45887,6 @@ msgstr "Twitter:"
msgid "Two-Factor Authentication"
msgstr "Autenticação de dois fatores"
-msgid "Two-Factor Authentication code"
-msgstr "Código da verificação de dois fatores"
-
msgid "Two-factor Authentication"
msgstr "Autenticação de dois fatores"
@@ -45191,12 +45932,6 @@ msgstr "Tipo"
msgid "Type to search"
msgstr "Digite para pesquisar"
-msgid "U2F Devices (%{length})"
-msgstr "Dispositivos U2F (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "O U2F só funciona com sites habilitados para HTTPS. Entre em contato com seu administrador para mais detalhes."
-
msgid "URL"
msgstr "URL"
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr "Indisponível"
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr "Ilimitado"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} to collaborate with you."
+msgstr "Durante sua avaliação, convide %{group} membros quiser para colaborar com você."
+
+msgid "UnlimitedMembersDuringTrialAlert|Explore paid plans"
+msgstr "Explore planos pagos"
+
+msgid "UnlimitedMembersDuringTrialAlert|Get the most out of your trial with space for more members"
+msgstr "Aproveite ao máximo sua avaliação com espaço para mais membros"
+
msgid "Unlink"
msgstr "Desvincular"
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr "Não usado"
@@ -45614,11 +46367,14 @@ msgstr ""
msgid "Update your group name, description, avatar, and visibility."
msgstr "Atualize o nome do seu grupo, descrição, avatar e visibilidade."
+msgid "Update your project name and description."
+msgstr ""
+
msgid "Update your project name, topics, description, and avatar."
msgstr "Atualize o nome do seu projeto, tópicos, a descrição e o avatar."
msgid "UpdateProject|Are you sure you want to prune unreachable objects?"
-msgstr ""
+msgstr "Tem certeza de que deseja eliminar objetos inacessíveis?"
msgid "UpdateProject|Are you sure you want to prune?"
msgstr "Tem certeza que deseja remover?"
@@ -45627,7 +46383,7 @@ msgid "UpdateProject|Cancel"
msgstr "Cancelar"
msgid "UpdateProject|Cannot rename project because it contains container registry tags!"
-msgstr ""
+msgstr "Não é possível renomear o projeto porque contém tags de registro de contêiner!"
msgid "UpdateProject|Could not set the default branch"
msgstr ""
@@ -45645,13 +46401,13 @@ msgid "UpdateProject|Project could not be updated!"
msgstr ""
msgid "UpdateProject|Prune"
-msgstr ""
+msgstr "Eliminar"
msgid "UpdateProject|Prune unreachable objects"
-msgstr ""
+msgstr "Eliminar objetos inacessíveis"
msgid "UpdateProject|Pruning unreachable objects can lead to repository corruption."
-msgstr ""
+msgstr "A eliminação de objetos inacessíveis pode levar à corrupção do repositório."
msgid "UpdateRepositoryStorage|Failed to verify %{type} repository checksum from %{old} to %{new}"
msgstr ""
@@ -45740,6 +46496,9 @@ msgstr "Tendências de uso"
msgid "Usage statistics"
msgstr "Estatísticas de uso"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr "Este espaço de nome não tem projetos que usaram executores compartilha
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr "Esta tabela omite projetos que usaram 0 minutos de CI/CD ou 0 duração de executores compartilhados"
+msgid "UsageQuota|Transfer"
+msgstr "Transferência"
+
msgid "UsageQuota|Uploads"
msgstr "Envios"
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ msgstr "Usuário criado em"
msgid "User does not have a pending request"
msgstr "Usuário não tem uma solicitação pendente"
+msgid "User does not have permission to create a Security Policy project."
+msgstr ""
+
msgid "User identity was successfully created."
msgstr "A identidade do usuário foi criada com sucesso."
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr "O valor pode conter uma referência de variável"
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr "Itens no estágio"
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr "Tempo do estágio (mediana)"
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr "Ver documentação"
msgid "View eligible approvers"
msgstr "Visualizar aprovadores elegíveis"
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "Ver artefato exposto"
@@ -47116,6 +47893,69 @@ msgstr "%{formattedStartDate} até hoje"
msgid "VulnerabilityChart|Severity"
msgstr "Severidade"
+msgid "VulnerabilityDismissalReasons|Acceptable risk"
+msgstr "Risco aceitável"
+
+msgid "VulnerabilityDismissalReasons|False positive"
+msgstr "Falso positivo"
+
+msgid "VulnerabilityDismissalReasons|Mitigating control"
+msgstr ""
+
+msgid "VulnerabilityDismissalReasons|Not applicable"
+msgstr "Não aplicável"
+
+msgid "VulnerabilityDismissalReasons|Used in tests"
+msgstr ""
+
+msgid "VulnerabilityExport|Activity"
+msgstr "Atividade"
+
+msgid "VulnerabilityExport|Additional Info"
+msgstr "Informações adicionais"
+
+msgid "VulnerabilityExport|CVE"
+msgstr "CVE"
+
+msgid "VulnerabilityExport|CWE"
+msgstr "CWE"
+
+msgid "VulnerabilityExport|Comments"
+msgstr "Comentários"
+
+msgid "VulnerabilityExport|Details"
+msgstr "Detalhes"
+
+msgid "VulnerabilityExport|Detected At"
+msgstr "Detectado em"
+
+msgid "VulnerabilityExport|Group Name"
+msgstr "Nome do grupo"
+
+msgid "VulnerabilityExport|Location"
+msgstr "Localização"
+
+msgid "VulnerabilityExport|Other Identifiers"
+msgstr "Outros identificadores"
+
+msgid "VulnerabilityExport|Project Name"
+msgstr "Nome do projeto"
+
+msgid "VulnerabilityExport|Scanner Name"
+msgstr ""
+
+msgid "VulnerabilityExport|Severity"
+msgstr "Severidade"
+
+msgid "VulnerabilityExport|Status"
+msgstr "Status"
+
+msgid "VulnerabilityExport|Tool"
+msgstr "Ferramenta"
+
+msgid "VulnerabilityExport|Vulnerability"
+msgstr "Vulnerabilidade"
+
msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr "%{statusStart}Confirmado%{statusEnd} %{timeago} por %{user}"
@@ -47159,10 +47999,10 @@ msgid "VulnerabilityManagement|Enter a name"
msgstr ""
msgid "VulnerabilityManagement|Enter the CVE or CWE code"
-msgstr ""
+msgstr "Digite o código CVE ou CWE"
msgid "VulnerabilityManagement|Enter the CVE or CWE identifier URL"
-msgstr ""
+msgstr "Insira a URL do identificador CVE ou CWE"
msgid "VulnerabilityManagement|Fetching linked Jira issues"
msgstr ""
@@ -47324,7 +48164,7 @@ msgid "Vulnerability|Download"
msgstr "Baixar"
msgid "Vulnerability|Enter the associated CVE or CWE entries for this vulnerability."
-msgstr ""
+msgstr "Insira as entradas CVE ou CWE associadas para esta vulnerabilidade."
msgid "Vulnerability|Evidence"
msgstr "Evidência"
@@ -47506,12 +48346,6 @@ msgstr "Não encontramos nenhum %{scope} correspondente a %{term} no projeto %{p
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr "Detectamos uma tentativa de entrada na sua conta %{host} usando um código de autenticação de dois fatores incorreto"
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr "Detectamos uma tentativa de entrada na sua conta %{host} usando um código de autenticação de dois fatores incorreto, do seguinte endereço IP: %{ip}, em %{time}"
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "Detectamos spam potencial no %{humanized_resource_name}. Por favor, resolva o reCAPTCHA para continuar."
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "Vamos usar isso para ajudar a supervisionar os recursos e informações certos para você."
@@ -47707,6 +48538,9 @@ msgstr "Uma versão é criada ou atualizada."
msgid "Webhooks|A subgroup is created or removed."
msgstr "Um subgrupo é criado ou removido."
+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 "Um webhook neste projeto foi desativado automaticamente após ser repetido várias vezes."
@@ -47970,6 +48804,11 @@ msgstr "Quando usar os protocolos %{code_open}http://%{code_close} ou %{code_ope
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 "Ao transferir seu projeto para um grupo, você pode gerenciar facilmente vários projetos, visualizar cotas de uso para armazenamento, minutos de pipeline e usuários e iniciar uma avaliação ou atualizar para um nível pago."
+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] ""
@@ -48008,6 +48847,9 @@ msgstr "Quem usará esse grupo?"
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr "Por que essa regra é inválida?"
+
msgid "Wiki"
msgstr "Wiki"
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr "Trabalho em andamento (aberto e não atribuído)"
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr "Adicionar ao marco"
+msgid "WorkItem|All activity"
+msgstr "Todas as atividades"
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr "Fechado"
+msgid "WorkItem|Comments only"
+msgstr "Somente comentários"
+
+msgid "WorkItem|Convert to task"
+msgstr "Converter em tarefa"
+
+msgid "WorkItem|Converted to task"
+msgstr "Convertido em tarefa"
+
msgid "WorkItem|Create %{workItemType}"
msgstr "Criar %{workItemType}"
@@ -48322,9 +49176,15 @@ msgstr "Data de vencimento"
msgid "WorkItem|Existing task"
msgstr "Tarefa existente"
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr "Somente histórico"
+
msgid "WorkItem|Incident"
msgstr "Incidente"
@@ -48383,7 +49243,7 @@ msgid "WorkItem|Save and overwrite"
msgstr "Salvar e sobrescrever"
msgid "WorkItem|Search existing %{workItemType}s"
-msgstr ""
+msgstr "Pesquisar %{workItemType}s existentes"
msgid "WorkItem|Select type"
msgstr "Selecione o tipo"
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr "Tarefa excluída"
+msgid "WorkItem|Task reverted"
+msgstr "Tarefa revertida"
+
msgid "WorkItem|Tasks"
msgstr "Tarefas"
@@ -48481,6 +49344,9 @@ msgstr "Item de trabalho"
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr "Escreva a descrição do marco..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "Escreva suas notas de lançamento ou arraste seus arquivos aqui…"
@@ -48703,7 +49572,7 @@ msgid "You can also use group access tokens with Git to authenticate over HTTP(S
msgstr ""
msgid "You can also use project access tokens with Git to authenticate over HTTP(S). %{link_start}Learn more.%{link_end}"
-msgstr ""
+msgstr "Você também pode usar tokens de acesso do projeto com o Git para autenticar por HTTP(S). %{link_start}Saiba mais.%{link_end}"
msgid "You can always change your URL later"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr "Você não possui permissão para atualizar esse ambiente."
msgid "You do not have permissions to run the import."
msgstr "Você não possui permissão para executar essa importação"
-msgid "You don't have any U2F devices registered yet."
-msgstr "Você ainda não tem nenhum dispositivo U2F registrado."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr "Você ainda não tem nenhum dispositivo WebAuthn registrado."
@@ -49085,12 +49951,18 @@ msgstr "Você deve ter o acesso de mantenedor para apagar um bloqueio"
msgid "You must provide a valid current password"
msgstr "Você deve fornecer uma senha atual válida"
+msgid "You must provide a valid current password."
+msgstr "Você deve fornecer uma senha atual válida."
+
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 "Você deve fornecer sua senha atual para alterá-la."
+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 ""
@@ -49261,6 +50133,9 @@ 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 "Sua atividade"
+
msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details."
msgstr ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 "Sua versão do GitLab"
+
msgid "Your Groups"
msgstr "Seus grupos"
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr "Suas chaves SSH (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "Sua lista de tarefas pendentes"
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr "Sua atividade"
+
msgid "Your applications (%{size})"
msgstr "Seus aplicativos (%{size})"
@@ -49378,9 +50262,6 @@ msgstr "Seus aplicativos autorizados"
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "Seu navegador não oferece suporte U2F. Por favor, use o Google Chrome desktop (versão de 41 ou mais recente)."
-
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+)."
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
msgstr "Seu e-mail de commit é usado para operações baseadas na web, como edições e merges."
+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 "Sua senha atual é necessária para registrar um aplicativo autenticador de dois fatores."
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49584,7 +50471,7 @@ msgid "Your username is %{username}."
msgstr "Seu nome de usuário é %{username}."
msgid "Your work"
-msgstr ""
+msgstr "Seu trabalho"
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 ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr "Relatório completo"
msgid "ciReport|Generic Report"
msgstr "Relatório genérico"
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr "Resolver com solicitação de mesclagem"
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "Detecção de secreto"
@@ -50233,6 +51123,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Solução"
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST)"
msgstr ""
@@ -50510,9 +51403,6 @@ msgstr[1] "arquivos"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr "Seguindo"
-
msgid "for"
msgstr "para"
@@ -50818,10 +51708,16 @@ msgstr "bloqueador por %{path_lock_user_name} %{created_at}"
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ msgstr "Use solicitações de mesclagem para propor alterações ao seu projeto
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 "%{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 ""
+
+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 "%{boldStart}Mesclagem bloqueada:%{boldEnd} todas as aprovações necessárias devem ser dadas."
+
+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|%{mergeError}."
msgstr "%{mergeError}."
@@ -50894,6 +51868,12 @@ msgstr "%{metricsLinkStart} Memória %{metricsLinkEnd} uso %{emphasisStart} aume
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart} Memória %{metricsLinkEnd} uso é %{emphasisStart} inalterado %{emphasisEnd} em %{memoryFrom}MB"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr "A aprovação é opcional"
msgid "mrWidget|Approval password is invalid."
msgstr "A senha de aprovação é inválida."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr "A regra de aprovação %{rules} é inválida. O GitLab aprovou esta regra automaticamente para desbloquear a solicitação de mesclagem. %{link}"
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr "As regras de aprovação %{rules} são inválidas. O GitLab aprovou essas regras automaticamente para desbloquear a solicitação de mesclagem. %{link}"
-
msgid "mrWidget|Approve"
msgstr "Aprovar"
@@ -50942,6 +51916,9 @@ msgstr "Aprovado por você"
msgid "mrWidget|Approved by you and others"
msgstr "Aprovado por você e outros"
+msgid "mrWidget|Are you sure you want to rebase?"
+msgstr ""
+
msgid "mrWidget|Assign yourself to these issues"
msgstr "mrWidget|Atribuir-se a essas issues"
@@ -51021,84 +51998,30 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] "Issue mencionada"
msgstr[1] "Issues mencionadas"
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr "Mesclagem bloqueada: todas as aprovações necessárias devem ser dadas."
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr "Mesclagem bloqueada:: todas as verificações de status devem passar."
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "Mesclagem bloqueada: todos os tópicos devem ser resolvidos."
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr "Mesclar bloqueado: as licenças negadas devem ser removidas."
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr "Mesclagem bloqueada: conflitos de mesclagem devem ser resolvidos."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr "Mesclagem bloqueada: o pipeline deve ser bem-sucedido. Envie um commit que corrige a falha ou %{linkStart}aprenda sobre outras soluções.%{linkEnd}"
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "Falha ao mesclar."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr "Mesclado por"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr "Mesclando! As alterações estão sendo enviadas…"
+msgid "mrWidget|More information"
+msgstr "Mais informações"
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr "Mesclando! As mudanças chegarão em breve…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgstr "Por favor, restaurar ou usar um branch %{type} diferente."
-msgid "mrWidget|Merging! Drum roll, please…"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Merging! Everything's good…"
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr "Mesclando! Decolagem em 5… 4… 3…"
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr "Mesclando! Respire fundo e relaxe…"
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr "Mesclando! As mudanças estão saindo da estação…"
-
-msgid "mrWidget|Merging! This is going to be great…"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "Mesclando! Estamos quase lá…"
-
-msgid "mrWidget|More information"
-msgstr "Mais informações"
-
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "Nenhum usuário corresponde aos critérios da regra."
-
-msgid "mrWidget|Please restore it or use a different %{type} branch."
-msgstr "Por favor, restaurar ou usar um branch %{type} diferente."
-
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "Pronto para ser mesclado automaticamente. Peça a alguém com acesso de gravação a este repositório para mesclar nessa requisição"
-
msgid "mrWidget|Refresh"
msgstr "Atualizar"
@@ -51159,9 +52082,6 @@ msgstr "Para alterar esta mensagem padrão, edite o modelo para mensagens de com
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr "deve ser um endereço IPv4 ou IPv6 válido"
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr "deve ser depois do início"
@@ -51388,10 +52311,10 @@ msgstr[0] "projeto"
msgstr[1] "projetos"
msgid "project access token"
-msgstr ""
+msgstr "token de acesso do projeto"
msgid "project access tokens"
-msgstr ""
+msgstr "tokens de acesso do projeto"
msgid "project bots cannot be added to other groups / projects"
msgstr ""
diff --git a/locale/pt_PT/gitlab.po b/locale/pt_PT/gitlab.po
index 1162b24be06..7a802e241a7 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s envio adicional foi omitido para prevenir problemas de desempenho."
msgstr[1] "%s envios adicionais foram omitidos para prevenir problemas de desempenho."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr "%{level_name} não é permitido uma vez que o projeto de origem do fork
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grupo"
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr "Adiciona uma página inicial à tua wiki que confoi informações sobre
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Adicionar uma lista numerada"
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr "Adicionar nova aplicação"
msgid "Add new directory"
msgstr "Adicionar novo diretório"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr "Texto adicional"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
msgstr "Todos os Membros"
+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 ""
@@ -4727,6 +4726,9 @@ msgstr "Ocorreu um erro inesperado ao iniciar o Terminal Web."
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Ocorreu um erro inesperado ao parar o Terminal Web."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr "Estatísticas"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ msgstr "Anexar o comentário com %{shrug}"
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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] "Anexar %d ficheiros"
msgid "Attaching the file failed."
msgstr "Falha ao anexar o ficheiro."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr "Código de autorização:"
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr "Autorizar"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "Autorizar %{link_to_client} a usar a tua conta?"
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr "Autorizado %{new_chat_name}"
@@ -5949,9 +6098,18 @@ msgstr "Autorizado em"
msgid "Authorized applications (%{size})"
msgstr "Aplicações autorizadas (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr "Tem cuidado. Alterar o espaço de nomes do projeto pode ter efeitos secu
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Tem cuidado. Renomear o repositório de um projeto pode ter efeitos secundários indesejados."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr "Abaixo vais encontrar todos os grupos que são públicos."
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr "Importar do Bitbucket"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ msgstr[1] ""
msgid "Boards|Collapse"
msgstr "Colapsar"
+msgid "Boards|Create new epic"
+msgstr ""
+
+msgid "Boards|Create new issue"
+msgstr ""
+
msgid "Boards|Edit board"
msgstr "Editar painel"
+msgid "Boards|Edit list settings"
+msgstr ""
+
msgid "Boards|Expand"
msgstr "Expandir"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr ""
+msgid "Boards|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "Escolhe quais repositórios desejas conectar e executar pipelines de CI/CD."
msgid "Choose your framework"
msgstr ""
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,12 +9001,12 @@ msgstr ""
msgid "CiStatus|running"
msgstr "em execução"
+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|Clear inputs"
-msgstr ""
-
msgid "CiVariables|Environments"
msgstr ""
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr "O certificado Kubernetes usado para autenticar no cluster."
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "A URL usada para acessar a API Kubernetes."
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "Não está disponível as listas de objetivos com a tua licença atual"
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ msgstr "Desconectar"
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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr "Projetos (%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr "Solicitar que os utilizadores enviem chaves SSH"
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr "Escreve a descrição do objetivo..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ msgstr "Deves ter acesso de responsável para forçar o apagamento de um bloquei
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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po
index 2f101f3b885..8b1b28bff8e 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-02-11 04:19\n"
+"PO-Revision-Date: 2023-03-11 10:30\n"
msgid " %{start} to %{end}"
msgstr " de la %{start} până la %{end}"
@@ -496,6 +496,12 @@ msgstr[0] "%d subiect nerezolvat"
msgstr[1] "%d subiecte nerezolvate"
msgstr[2] "%d de subiecte nerezolvate"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d vulnerabilitate"
@@ -538,12 +544,24 @@ msgstr[0] "%d avertisment găsit:"
msgstr[1] "%d avertismente găsite:"
msgstr[2] "%d de avertismente găsite:"
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
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 commit suplimentar a fost omis pentru a preveni problemele de performanță."
msgstr[1] "%s commit-uri suplimentare au fost omise pentru a preveni probleme de performanță."
msgstr[2] "%s de commit-uri suplimentare au fost omise pentru a preveni problemele de performanță."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -721,6 +739,9 @@ msgstr "%{count} de %{pluralized_subject} conexe: %{links}"
msgid "%{count} selected"
msgstr "%{count} selectat(e)"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} greutate totală"
@@ -922,6 +943,9 @@ msgstr "%{level_name} nu este permis, deoarece proiectul sursă al forkului are
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow} și %{awardsListLength} mai mult"
@@ -937,9 +961,6 @@ msgstr "%{mergeLength}/%{usersLength} poate îmbina"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} afișând primul %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr "%{message}. Solicitarea dvs. de atenție a fost înlăturată."
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (expirat)"
@@ -1075,6 +1096,9 @@ msgstr "%{reportType} a detectat %{totalStart}%{total}%{totalEnd} potențiale %{
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1336,6 +1360,9 @@ msgstr "%{user} a creat o epică: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} a creat o problemă: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} nu face parte din listă"
@@ -1627,12 +1654,6 @@ msgstr[0] "O cheie de implementare"
msgstr[1] "%d chei de implementare"
msgstr[2] "%d de chei de implementare"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "Un urmăritor"
-msgstr[1] "%{count} urmăritori"
-msgstr[2] "%{count} de urmăritori"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grup"
@@ -1951,9 +1972,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "Fuzzing de API"
-msgid "API Fuzzing Configuration"
-msgstr "Configurare de Fuzzing de API"
-
msgid "API Help"
msgstr "Ajutor API"
@@ -2368,9 +2386,6 @@ msgstr "Adăugați o listă de verificare"
msgid "Add a collapsible section"
msgstr "Adăugați o secțiune pliabilă"
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr "Adăugați un comentariu la această linie"
@@ -2392,6 +2407,9 @@ msgstr "Adăugați o pagină de pornire la propriul wiki care conține informaț
msgid "Add a new issue"
msgstr "Adăugați o nouă problemă"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Adăugați o listă numerotată"
@@ -2401,6 +2419,9 @@ msgstr "Adăugați o epică asociată"
msgid "Add a related issue"
msgstr "Adăugați o problemă asociată"
+msgid "Add a reply"
+msgstr ""
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr "Adăugați un sufix la adresa de e-mail Service Desk. %{linkStart}Aflați mai multe.%{linkEnd}"
@@ -2515,6 +2536,9 @@ msgstr "Adăugare aplicație nouă"
msgid "Add new directory"
msgstr "Adăugare director nou"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr "Adăugați sau înlăturați un utilizator."
@@ -2653,6 +2677,9 @@ msgstr "Minute suplimentare:"
msgid "Additional text"
msgstr "Text suplimentar"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr "Text suplimentar pentru pagina de autentificare și de Ajutor."
@@ -3832,41 +3859,11 @@ 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 "După ce exportul este finalizat, descărcați fișierul de date dintr-un e-mail de notificare sau de pe această pagină. Apoi puteți importa fișierul de date de pe pagina %{strong_text_start}Creați un grup nou%{strong_text_end} al unei alte instanțe GitLab."
-msgid "After you've reviewed these contribution guidelines, you'll be all set to"
-msgstr "După revizuirea acestor orientări privind contribuțiile, veți fi gata să"
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
-msgstr ""
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
+msgstr "După revizuirea acestor orientări privind contribuțiile, veți fi gata să"
msgid "Akismet"
msgstr "Akismet"
@@ -4237,6 +4234,9 @@ msgstr "Peste tot în GitLab"
msgid "All Members"
msgstr "Toți membrii"
+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 "Toate ramurile"
@@ -4867,6 +4867,9 @@ msgstr "A apărut o eroare neașteptată la pornirea Terminalului Web."
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "A apărut o eroare neașteptată în timpul opririi Terminalului Web."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr "A apărut o eroare necunoscută la încărcarea acestui grafic."
@@ -4876,6 +4879,123 @@ msgstr "A apărut o eroare necunoscută."
msgid "Analytics"
msgstr "Analize"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analizați-vă dependențele pentru vulnerabilități cunoscute."
@@ -4954,13 +5074,28 @@ msgstr "Anexați comentariul cu %{shrug}"
msgid "Append the comment with %{tableflip}"
msgstr "Anexați comentariul cu %{tableflip}"
+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|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."
+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."
@@ -5107,12 +5242,18 @@ msgstr "Salvați modificările"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "Consultați %{linkStart}instrucțiunile privind politica parolelor%{linkEnd}."
+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 "Trimiteți un e-mail de confirmare în timpul înscrierii. Noii utilizatori trebuie să-și confirme adresa de e-mail înainte de a se conecta."
msgid "ApplicationSettings|Sign-up enabled"
msgstr "Înregistrare activată"
+msgid "ApplicationSettings|Soft"
+msgstr ""
+
msgid "ApplicationSettings|Text shown after a user signs up. Markdown enabled."
msgstr "Text afișat după ce un utilizator se înregistrează. Markdown activat."
@@ -5362,6 +5503,12 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Aprobați un merge request"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Approve merge request"
msgstr "Aprobați merge request-ul"
@@ -5374,6 +5521,18 @@ msgstr "Aprobat"
msgid "Approved MRs"
msgstr "MR-uri aprobate"
+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] ""
+msgstr[2] ""
+
+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] ""
+msgstr[2] ""
+
msgid "Approved the current merge request."
msgstr "A fost aprobat merge request-ul actual."
@@ -5449,9 +5608,6 @@ msgstr "Sunteți sigur că doriți să %{action} %{name}?"
msgid "Are you sure you want to approve %{user}?"
msgstr "Sunteți sigur că vreți să aprobați pe %{user}?"
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr "Sunteți sigur că vreți să încercați să îmbinați?"
@@ -5464,6 +5620,9 @@ msgstr "Sunteți sigur că doriți să închideți această problemă blocată?"
msgid "Are you sure you want to delete %{name}?"
msgstr "Sunteți sigur că doriți să ștergeți %{name}?"
+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 "Sunteți sigur că doriți să ștergeți acest %{commentType}?"
@@ -5818,8 +5977,8 @@ msgstr[2] "Se atașează %d de fișiere"
msgid "Attaching the file failed."
msgstr "Atașarea fișierului a eșuat."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
-msgstr "S-a încercat conectarea la %{host} folosind un cod de autentificare cu doi factori greșit"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
+msgstr ""
msgid "Audit Events"
msgstr "Evenimente de audit"
@@ -6073,9 +6232,6 @@ msgstr "Redactat %{timeago} de %{author}"
msgid "Authorization code:"
msgstr "Codul de autorizare:"
-msgid "Authorization required"
-msgstr "Autorizație necesară"
-
msgid "Authorization token duration (minutes)"
msgstr "Durata tokenului de autorizare (minute)"
@@ -6088,9 +6244,6 @@ msgstr "Autorizați"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "Autorizați %{link_to_client} să vă utilizeze contul?"
-msgid "Authorize %{user} to use your account?"
-msgstr "Autorizați %{user} să vă utilizeze contul?"
-
msgid "Authorized %{new_chat_name}"
msgstr "S-a autorizat %{new_chat_name}"
@@ -6100,9 +6253,18 @@ msgstr "Autorizat la"
msgid "Authorized applications (%{size})"
msgstr "Aplicații autorizate (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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 "Sunteți sigur că doriți să revocați această aplicație?"
+msgid "AuthorizedApplication|Renew secret"
+msgstr ""
+
msgid "AuthorizedApplication|Revoke application"
msgstr "Revocați cererea"
@@ -6484,6 +6646,9 @@ msgstr "Aveți grijă. Schimbarea spațiului de nume al proiectului poate avea e
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Atenție. Redenumirea repozitoriului unui proiect poate avea efecte secundare neintenționate."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6511,9 +6676,6 @@ msgstr "Mai jos sunt setările pentru %{link_to_gitlab_pages}."
msgid "Below you will find all the groups that are public."
msgstr "Mai jos veți găsi toate grupurile care sunt publice."
-msgid "Beta"
-msgstr "Beta"
-
msgid "Bi-weekly code coverage"
msgstr "Coverage de cod bisăptămânal"
@@ -6583,6 +6745,9 @@ msgstr "Planificarea Enterprise Agile"
msgid "BillingPlans|Faster code reviews"
msgstr "Revizuiri mai rapide ale codului"
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr "Caracteristici gratuite pentru totdeauna pentru utilizatorii individuali"
@@ -6598,9 +6763,6 @@ msgstr "Dacă doriți să vă retrogradați planul, vă rugăm să contactați %
msgid "BillingPlans|Includes free static websites"
msgstr "Include site-uri web statice gratuite"
-msgid "BillingPlans|Learn more"
-msgstr "Aflați mai multe"
-
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}, or start a free 30-day trial of GitLab.com Ultimate."
msgstr "Aflați mai multe despre fiecare plan citind %{faq_link} nostru sau începeți o perioadă de încercare gratuită de 30 de zile GitLab.com Ultimate."
@@ -6736,27 +6898,9 @@ msgstr "Actualizați"
msgid "BillingPlan|Upgrade for free"
msgstr "Actualizați gratuit"
-msgid "Billings|%{planName} plan"
-msgstr "Planul %{planName}"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr "A apărut o eroare la prelungirea perioadei de încercare."
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr "A apărut o eroare în timpul reactivării perioadei dvs. de încercare."
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr "Prin prelungirea perioadei dvs. de încercare, veți primi 30 de zile suplimentare de %{planName}. Perioada dvs. de încercare poate fi prelungită doar o singură dată."
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr "Prin reactivarea perioadei dvs. de încercare, veți primi 30 de zile suplimentare de %{planName}. Încercarea dvs. poate fi reactivată doar o singură dată."
-
msgid "Billings|Error validating card details"
msgstr "Eroare la validarea detaliilor cardului"
-msgid "Billings|Extend trial"
-msgstr "Extindeți perioada de încercare"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr "Grupurile gratuite sunt limitate la %{number} seats."
@@ -6766,9 +6910,6 @@ msgstr "Grupurile de nivel gratuit și de probă pot invita maximum 20 de membri
msgid "Billings|In a seat"
msgstr "ÃŽntr-un seat"
-msgid "Billings|Reactivate trial"
-msgstr "Reactivați perioada de încercare"
-
msgid "Billings|Seats in use / Seats available"
msgstr "Seats în uz / Seats disponibile"
@@ -6910,6 +7051,9 @@ msgstr "Import din Bitbucket"
msgid "Blame"
msgstr "Blame"
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr "Vizualizare pe %{environmentName}"
@@ -7135,15 +7279,27 @@ msgstr[2] "Blocat de %{blockedByCount} de %{issuableType}s"
msgid "Boards|Collapse"
msgstr "Restrângeți"
+msgid "Boards|Create new epic"
+msgstr ""
+
+msgid "Boards|Create new issue"
+msgstr ""
+
msgid "Boards|Edit board"
msgstr "Editare bord"
+msgid "Boards|Edit list settings"
+msgstr ""
+
msgid "Boards|Expand"
msgstr "Extindeți"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr "Nu s-a reușit preluarea %{issuableType}s care blochează"
+msgid "Boards|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr "Mutați cardul"
@@ -7156,9 +7312,6 @@ msgstr "Mutați la începutul listei"
msgid "Boards|New board"
msgstr "Bord nou"
-msgid "Boards|New epic"
-msgstr "Epică nouă"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr "Recuperarea %{issuableType}s care blochează"
@@ -7276,9 +7429,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr "Toate ramurile"
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr "Toți utilizatorii care au acces push au voie să execute push forțat."
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "Permiteți tuturor utilizatorilor cu acces push să %{linkStart}forțeze push%{linkEnd}."
@@ -7297,6 +7447,15 @@ 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 "A apărut o eroare în timpul preluării ramurilor."
@@ -7327,11 +7486,14 @@ msgstr "Creați un wildcard: %{searchTerm}"
msgid "BranchRules|Details"
msgstr "Detalii"
-msgid "BranchRules|Force push"
-msgstr "Push forțat"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
-msgid "BranchRules|Force push is not allowed."
-msgstr "Nu este permis push forțat."
+msgid "BranchRules|From users with push access."
+msgstr ""
msgid "BranchRules|Groups"
msgstr "Grupuri"
@@ -7372,6 +7534,9 @@ msgstr "Aprobări necesare (%{total})"
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr "Este necesară aprobarea CODEOWNERS"
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr "Roluri"
@@ -8140,6 +8305,15 @@ msgstr "Nu pot aplica această sugestie."
msgid "Can't be empty"
msgstr "Nu poate fi gol"
+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 "Nu se poate crea un fragment de cod: %{err}"
@@ -8257,6 +8431,9 @@ msgstr "Nu pot exista mai multe alerte nerezolvate"
msgid "Cannot import because issues are not available in this project."
msgstr "Nu se poate importa deoarece problemele nu sunt disponibile în acest proiect."
+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 "Nu se poate face epica de tip confidențial dacă aceasta conține epice copil neconfidențiale"
@@ -8641,6 +8818,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+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 "A survenit o eroare necunoscută. Vă rugăm să încercați din nou prin reîmprospătarea acestei pagini."
@@ -8683,6 +8863,9 @@ msgstr "Èšara"
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 "Creați un grup nou"
@@ -8692,18 +8875,15 @@ msgstr "Formularul cardului de credit nu s-a încărcat. Vă rugăm să încerca
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "Formularul cardului de credit nu s-a încărcat: %{message}"
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "Editați"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr "Exp %{expirationMonth}/%{expirationYear}"
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "Nu s-a reușit confirmarea comenzii dumneavoastră! Vă rugăm să încercați din nou."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "Nu s-a reușit confirmarea comenzii dumneavoastră: %{message}. Vă rugăm să încercați din nou."
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "Nu s-a reușit încărcarea țărilor. Vă rugăm să încercați din nou."
@@ -8728,6 +8908,9 @@ msgstr "Planul GitLab"
msgid "Checkout|Group"
msgstr "Grupul"
+msgid "Checkout|Invalid coupon code. Enter a valid coupon code."
+msgstr ""
+
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
msgstr "Trebuie să fie de cel puțin %{minimumNumberOfUsers} (seat-urile dvs. în uz) sau mai mult."
@@ -8746,6 +8929,9 @@ msgstr "Nume: %{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "Aveți nevoie de mai mulți utilizatori? Achiziționați GitLab pentru %{company} dumneavoastră."
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "Numărul de utilizatori"
@@ -8764,6 +8950,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "JudeÈ›"
@@ -8884,12 +9073,18 @@ msgstr "Alegeți ce conținut doriți să vedeți pe pagina de prezentare genera
msgid "Choose which Git strategy to use when fetching the project."
msgstr "Alegeți ce strategie Git să utilizați la preluarea proiectului."
+msgid "Choose which branches should be mirrored"
+msgstr ""
+
msgid "Choose which repositories you want to connect and run CI/CD pipelines."
msgstr "Alegeți ce repozitorii doriți să conectați pentru a rula pipeline-uri CI/CD."
msgid "Choose your framework"
msgstr "Alegeți framework-ul d-voastră"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr "Interval de date: %{range}"
@@ -8968,12 +9163,12 @@ msgstr "în așteptare"
msgid "CiStatus|running"
msgstr "în execuție"
+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|Clear inputs"
-msgstr ""
-
msgid "CiVariables|Environments"
msgstr "Medii"
@@ -9001,6 +9196,9 @@ msgstr "Opțiuni"
msgid "CiVariables|Protected"
msgstr "Protejat"
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr "Înlăturați variabila"
@@ -9784,6 +9982,9 @@ msgstr "Instanța dvs. nu are configurat %{linkStart}Serverul agentului GitLab (
msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
msgstr "Utilizatorul are permisiuni insuficiente pentru a crea un token pentru acest proiect"
+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 "Nu aveți permisiuni suficiente pentru a crea un agent de cluster pentru acest proiect"
@@ -10075,7 +10276,7 @@ msgstr "Certificatul Kubernetes folosit pentru autentificarea în cluster."
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "URL-ul utilizat pentru a accesa API-ul Kubernetes."
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr "Integrarea Kubernetes bazată pe certificate a fost depreciată și va fi dezactivată la sfârșitul lunii februarie 2023. %{linkStart}Migrați la agentul GitLab pentru Kubernetes%{linkEnd} sau contactați asistența GitLab."
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10468,9 +10669,6 @@ msgstr "Comparați edițiile GitLab"
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "Comparați revizuirile"
-
msgid "Compare branches and continue"
msgstr "Comparați ramurile și continuați"
@@ -10483,6 +10681,9 @@ msgstr "Comparați modificările cu ultimul commit"
msgid "Compare changes with the merge request target branch"
msgstr "Comparați modificările cu ramura țintă a merge request-ului"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr "Comparați revizuirile commit-ului submodulului"
@@ -10552,12 +10753,21 @@ msgstr "Completat"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr "S-a completat în %{duration_seconds} (de) secunde (%{relative_time})"
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr "Framework de conformitate"
msgid "Compliance report"
msgstr "Raport de conformitate"
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Adăugare framework"
@@ -10666,9 +10876,24 @@ msgstr "Aprobat de comitent"
msgid "ComplianceReport|Less than 2 approvers"
msgstr "Mai puțin de 2 aprobatori"
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr "Nu s-au constatat încălcări"
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "Component"
@@ -10687,9 +10912,6 @@ msgstr "Notă confidențială"
msgid "Confidentiality"
msgstr "Confidențialitate"
-msgid "Configuration"
-msgstr "Configurație"
-
msgid "Configuration help"
msgstr "Ajutor pentru configurare"
@@ -11314,6 +11536,9 @@ msgstr "Sunteți pe cale să înlăturați repozitoriul %{title}. Odată ce conf
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "Puteți adăuga o imagine în acest registru cu ajutorul următoarelor comenzi:"
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr "Conținut analizat cu %{link}."
@@ -11356,12 +11581,21 @@ msgstr "Contribuție"
msgid "Contribution Analytics"
msgstr "Analize de contribuții"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr "%{created} create, %{closed} închise."
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr "%{created} create, %{merged} îmbinate, %{closed} închise."
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11377,6 +11611,9 @@ msgstr ""
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr "Analiza contribuțiilor pentru probleme, merge request-uri și evenimente push de la %{start_date}"
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr ""
+
msgid "ContributionAnalytics|Failed to load the contribution stats"
msgstr ""
@@ -11422,7 +11659,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11443,8 +11683,8 @@ msgstr "Contribuții pe membru de grup"
msgid "Contributor"
msgstr "Colaborator"
-msgid "Contributors"
-msgstr "Colaboratori"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "Controlați e-mailurile legate de contul d-voastră"
@@ -11515,6 +11755,9 @@ msgstr "Copiați comenzile"
msgid "Copy commit SHA"
msgstr "Copiați commit-ul SHA"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr "Copiați mediul"
@@ -11761,8 +12004,8 @@ msgstr "Nu s-a putut atribui politica unui proiect sau grup"
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
-msgstr "Å¢ara"
+msgid "Country / Region"
+msgstr ""
msgid "Counts"
msgstr ""
@@ -11950,6 +12193,9 @@ msgstr "Creați unul"
msgid "Create or close an issue."
msgstr "Creați sau închideți o problemă."
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr "Creați sau importați primul dvs. proiect"
@@ -12199,9 +12445,6 @@ msgstr "Creat pe"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "Am creat o ramură și un merge request pentru a rezolva această problemă."
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "S-a creat ramura „%{branch_name}†și un merge request pentru a rezolva această problemă."
@@ -12409,6 +12652,9 @@ msgstr "Preferințe"
msgid "CurrentUser|Start an Ultimate trial"
msgstr "Începeți o perioadă de încercare Ultimate"
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr ""
+
msgid "Currently unable to fetch data for this pipeline."
msgstr "ÃŽn prezent, nu putem prelua date pentru acest pipeline."
@@ -12508,8 +12754,8 @@ msgstr "Problema a fost adăugată pentru prima dată la un bord"
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "Problema a fost asociată pentru prima dată cu un obiectiv"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
-msgstr "Problema a fost asociată pentru prima dată cu un obiectiv sau problema a fost adăugată pentru prima dată la un bord"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
+msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
msgstr "Prima problemă menționată într-un commit"
@@ -12676,9 +12922,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr "Vizualizarea DAG necesită cel puțin 3 joburi dependente."
-msgid "DAST Configuration"
-msgstr "Configurația DAST"
-
msgid "DAST configuration not found"
msgstr "Configurația DAST nu a fost găsită"
@@ -13591,6 +13834,9 @@ msgstr "Ștergerea corpusului"
msgid "Delete deploy key"
msgstr "Ștergeți cheia de implementare"
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr "Ștergeți epica"
@@ -13633,6 +13879,9 @@ msgstr "Ștergeți versiunea %{release}?"
msgid "Delete row"
msgstr "Ștergeți rândul"
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14392,6 +14641,9 @@ msgstr "succes"
msgid "Deprecated API rate limits"
msgstr "Limite de rată API depreciate"
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr "Pentru informații cu privire la un posibil înlocuitor, %{epicStart}aflați mai multe despre Opstrace %{epicEnd}."
@@ -14494,12 +14746,15 @@ msgstr "Nu s-a putut adăuga un comentariu nou. Vă rugăm să încercați din n
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "Nu s-a putut crea o nouă discuție. Vă rugăm să încercați din nou."
+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 discussion. Please try again."
msgstr "Nu s-a putut actualiza discuția. Vă rugăm să încercați din nou."
-msgid "DesignManagement|Could not update note. Please try again."
-msgstr "Nu s-a putut actualiza nota. Vă rugăm să încercați din nou."
-
msgid "DesignManagement|Deselect all"
msgstr "Deselectați totul"
@@ -14602,6 +14857,9 @@ msgstr "Adoptarea DevOps"
msgid "Developer"
msgstr "Dezvoltator"
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr "Dispozitive (opțional)"
@@ -14797,6 +15055,9 @@ msgstr "Utilizarea dvs."
msgid "Diagram (%{language})"
msgstr "Diagramă (%{language})"
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr "Nu s-a șters ramura sursă."
@@ -14953,9 +15214,6 @@ msgstr "Notificări Discord"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr "Trimiteți notificări despre evenimentele proiectului pe un canal Discord."
-msgid "Discover"
-msgstr "Descoperiți"
-
msgid "Discover GitLab Geo"
msgstr "Descoperiți GitLab Geo"
@@ -15394,6 +15652,9 @@ msgstr "Editați cheia de implementare"
msgid "Edit description"
msgstr "Editați descrierea"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "Editați mediul"
@@ -15418,6 +15679,9 @@ msgstr "Editați identitatea pentru %{user_name}"
msgid "Edit image description"
msgstr "Editați descrierea imaginii"
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr "Editați în editorul de pipeline"
@@ -15436,9 +15700,15 @@ msgstr "Editare link"
msgid "Edit merge requests"
msgstr "Editați merge request-urile"
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "Modificați cheia de implementare publică"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr "Editați bara laterală"
@@ -15895,6 +16165,9 @@ msgstr "Introduceți 2FA pentru Modul Admin"
msgid "Enter Admin Mode"
msgstr "Intrați în Modul Admin"
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "Introduceți un număr"
@@ -15940,8 +16213,8 @@ msgstr "Introduceți descrierea %{name}"
msgid "Enter the %{name} title"
msgstr "Introduceți titlul %{name}"
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
-msgstr "Introduceți codul din aplicația cu doi factori de pe dispozitivul dvs. mobil. Dacă v-ați pierdut dispozitivul, puteți introduce unul dintre codurile de recuperare."
+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 "Introduceți următoarele pentru a confirma:"
@@ -15958,6 +16231,9 @@ msgstr "IntroduceÈ›i parola pentru serverele Elasticsearch protejate prin parolÄ
msgid "Enter the username for password-protected Elasticsearch servers."
msgstr "Introduceți numele de utilizator pentru serverele Elasticsearch protejate prin parolă."
+msgid "Enter verification code"
+msgstr ""
+
msgid "Enter your Packagist server. Defaults to https://packagist.org."
msgstr "Introduceți serverul dvs. Packagist. Valoarea implicită este https://packagist.org."
@@ -16252,6 +16528,9 @@ msgstr "Borduri de epice"
msgid "Epic actions"
msgstr "Acțiunile epicei"
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "Epica nu poate fi găsită."
@@ -16363,6 +16642,9 @@ msgstr "Eroare la crearea unui nou director. Vă rugăm să încercați din nou.
msgid "Error creating new iteration"
msgstr "Eroare la crearea noii iterații"
+msgid "Error creating or updating PreScanVerificationStep: %{errors}"
+msgstr ""
+
msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr "Eroare la crearea repozitoriului pentru fragmentul de cod cu ID-ul %{snippet_id}"
@@ -16651,6 +16933,9 @@ msgstr "Sunteți sigur că doriți să ștergeți politica de escaladare „%{es
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 "Creați o politică de escaladare în GitLab"
@@ -16930,6 +17215,9 @@ msgstr "Colectarea probelor"
msgid "Exactly one of %{attributes} is required"
msgstr "Exact unul dintre %{attributes} este necesar"
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16954,6 +17242,9 @@ msgstr "Cu excepția politicii:"
msgid "Exceptions"
msgstr "Excepții"
+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 "Se exclud commit-urile de îmbinare. Limitat la %{limit} de commit-uri."
@@ -17155,6 +17446,9 @@ msgstr "Dacă nu este setată nicio etichetă de clasificare, se va utiliza etic
msgid "ExternalAuthorization|Access to projects is validated on an external service using their classification label."
msgstr "Accesul la proiecte este validat pe un serviciu extern folosind eticheta de clasificare a acestora."
+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 "Certificat utilizat pentru autentificarea cu serviciul de autorizare extern. Dacă este gol, certificatul serverului este validat la accesarea prin HTTPS."
@@ -17173,6 +17467,9 @@ msgstr "Parola cheii de autorizare a clientului (opțional)"
msgid "ExternalAuthorization|Default classification label"
msgstr "Etichetă de clasificare implicită"
+msgid "ExternalAuthorization|Does not apply if service URL is specified."
+msgstr ""
+
msgid "ExternalAuthorization|Enable classification control using an external service"
msgstr "Activați controlul clasificării utilizând un serviciu extern"
@@ -17746,9 +18043,6 @@ msgstr "Feb"
msgid "February"
msgstr "Februarie"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr "Obțineți și verificați această ramură de caracteristică a merge request-ului:"
@@ -17872,6 +18166,9 @@ msgstr "Parametrii de filtrare nu sunt valabili. Asigurați-vă că data de sfâ
msgid "Filter pipelines"
msgstr "Filtrare de pipeline-uri"
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "Filtrați rezultatele"
@@ -18028,9 +18325,6 @@ msgstr "Pentru fiecare job, reutilizați spațiul de lucru al proiectului. Dacă
msgid "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 "De exemplu, aplicația care utilizează tokenul sau scopul său. Nu furnizați informații sensibile pentru numele tokenului, deoarece acesta va fi vizibil pentru toți membrii %{resource_type}."
-msgid "For faster browsing, not all history is shown."
-msgstr "Pentru o navigare mai rapidă, nu se afișează tot istoricul."
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr "Pentru fișiere mai mari decât această limită, indexați numai numele fișierului. Conținutul fișierului nu este nici indexat, nici nu poate fi căutat."
@@ -18172,9 +18466,6 @@ msgstr "Format: %{dateFormat}"
msgid "Framework successfully deleted"
msgstr "Framework-ul a fost eliminat cu succes"
-msgid "Free"
-msgstr "Gratuit"
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Versiune de încercare gratuită a GitLab.com Ultimate"
@@ -18988,14 +19279,23 @@ msgstr "Perioada de raportare trebuie să fie un număr."
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "Perioada de raportare trebuie să fie cuprinsă între %{minTimePeriod}-%{maxTimePeriod} (de) secunde."
+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 "Numărul maxim de repozitorii unice pe care un utilizator le poate descărca în perioada de timp specificată înainte de a fi interzis."
+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 "Utilizatorii care sunt excluși de la limita ratei de abuz Git."
-msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
-msgstr "Nu puteți specifica mai mult de %{maxExcludedUsers} (de) utilizatori excluși"
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr "Limita ratei API GitHub a fost depășită. Încercați din nou după %{reset_time}"
@@ -19045,6 +19345,9 @@ msgstr "GitLab KAS"
msgid "GitLab Pages"
msgstr "GitLab Pages"
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr "GitLab Shell"
@@ -19069,6 +19372,12 @@ msgstr "Solicitarea contului GitLab a fost respinsă"
msgid "GitLab commit"
msgstr "Commit GitLab"
+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 ""
@@ -19084,9 +19393,6 @@ msgstr "GitLab for Jira Cloud"
msgid "GitLab group: %{source_link}"
msgstr "Grup GitLab: %{source_link}"
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr "GitLab vă informează dacă este disponibilă o nouă versiune. %{link_start}Ce informații colectează GitLab Inc.?%{link_end}"
@@ -19135,12 +19441,6 @@ msgstr "Versiunea GitLab"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab va crea o ramură în forkul dvs. și va iniția un merge request."
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -19234,12 +19534,18 @@ msgstr "Neconfirmat"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Actualizarea configurației Pages..."
+msgid "GitLabPages|Use unique domain"
+msgstr ""
+
msgid "GitLabPages|Verified"
msgstr "Verificat"
msgid "GitLabPages|Waiting for the Pages Pipeline to complete..."
msgstr "Așteptând ca Pipeline-ul Pages să se finalizeze..."
+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 "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}"
@@ -19279,6 +19585,9 @@ msgstr "URL-ul gazdei Gitea"
msgid "Gitea Import"
msgstr "Import Gitea"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19291,13 +19600,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19315,7 +19624,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr "Solicitări pull"
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19369,6 +19678,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 "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr "Căutarea globală este dezactivată pentru acest scop"
@@ -19441,6 +19753,9 @@ msgstr "Probleme recente"
msgid "GlobalSearch|Recent merge requests"
msgstr "Merge request-uri recente"
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19495,15 +19810,9 @@ msgstr "Ce căutați?"
msgid "GlobalSearch|all GitLab"
msgstr "peste tot în GitLab"
-msgid "GlobalSearch|group"
-msgstr "grup"
-
msgid "GlobalSearch|in %{scope}"
msgstr "în %{scope}"
-msgid "GlobalSearch|project"
-msgstr "proiect"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr "Numele ramurii sursă a fost copiat în clipboard."
@@ -19720,6 +20029,30 @@ 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 "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 "Am înțeles"
@@ -19909,6 +20242,9 @@ 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"
@@ -20260,6 +20596,9 @@ msgstr "Schimbarea URL-ului unui grup poate avea efecte secundare neintenționat
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 "Alegeți o cale de grup care nu începe cu o liniuță și nu se termină cu un punct. De asemenea, poate conține caractere alfanumerice și caractere de subliniere."
+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 "Framework-uri de conformitate"
@@ -20518,6 +20857,9 @@ 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 "Grupurile pot fi, de asemenea, imbricate prin crearea de %{linkStart}subgrupuri%{linkEnd}."
@@ -20533,6 +20875,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr "Nu sunt disponibile opțiuni de import"
@@ -20911,6 +21259,9 @@ msgstr "Ajută la reducerea volumului de solicitări (de exemplu, de la crawlere
msgid "Helps reduce request volume for protected paths."
msgstr "Ajută la reducerea volumului de solicitări pentru căile protejate."
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "Bună %{username}!"
@@ -21256,6 +21607,9 @@ msgstr "Introduceți un cod valid."
msgid "IdentityVerification|For added security, you'll need to verify your identity in a few quick steps."
msgstr "Pentru mai multă siguranță, va fi necesar să vă verificați identitatea în câțiva pași rapizi."
+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 "Pentru mai multă siguranță, va trebui să vă verificați identitatea. V-am trimis un cod de verificare la %{email}."
@@ -21355,6 +21709,9 @@ msgstr "Verificați-vă identitatea"
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 ""
@@ -21397,15 +21754,24 @@ msgstr "Dacă este bifată, proprietarii de grupuri pot gestiona linkurile de gr
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "Dacă se bifează această opțiune, se pot adăuga noi membri și permisiuni de grup numai prin intermediul sincronizării LDAP."
+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 "Dacă este dezactivată, o ramură locală divergentă nu va fi actualizată automat cu commit-urile de la omologul său remote, pentru a preveni pierderea datelor locale. În cazul în care ramura implicită (%{default_branch}) a deviat și nu poate fi actualizată, replicarea va eșua. Alte ramuri divergente sunt ignorate în tăcere. %{link_start}Aflați mai multe.%{link_end}"
msgid "If disabled, only administrators can configure repository mirroring."
msgstr "Dacă este dezactivat, numai administratorii pot configura replicarea repozitoriului."
+msgid "If enabled, all branches will be mirrored."
+msgstr ""
+
msgid "If enabled, only protected branches will be mirrored."
msgstr "Dacă este activată, numai ramurile protejate vor fi replicate."
+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 "Dacă numărul de utilizatori activi depășește limita de utilizator, veți fi taxat pentru numărul de %{users_over_license_link} la următoarea reconciliere a licenței."
@@ -21466,8 +21832,8 @@ msgstr "Dacă vă pierdeți codurile de recuperare, puteți genera altele noi, i
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "Dacă v-ați conectat recent și recunoașteți adresa IP, puteți ignora acest e-mail."
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email."
-msgstr "Dacă dvs. ați încercat recent să vă conectați, dar ați introdus un cod de autentificare cu doi factori greșit, puteți ignora acest e-mail."
+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 "Dacă doriți să reactivați autentificarea cu doi factori, vizitați %{two_factor_link}"
@@ -21694,6 +22060,9 @@ msgstr "Importul proiectului a eșuat"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr "Importul proiectului a eșuat: %{reason}"
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr "Solicitarea spațiilor de nume a eșuat"
@@ -22099,8 +22468,8 @@ msgstr "Protejați-vă aplicația web folosind DAST pentru a scana mediile de de
msgid "InProductMarketing|Rapid development, simplified"
msgstr "Dezvoltare rapidă, simplificată"
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
-msgstr "Reduceți riscurile de securitate și conformitate"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
+msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
msgstr "Solicitați mai multe aprobări pentru un merge request, astfel încât să știți că este în formă bună înainte de a fi îmbinat."
@@ -22762,12 +23131,18 @@ msgstr "Inserați imaginea"
msgid "Insert link"
msgstr "Inserați un link"
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr "Inserați rândul după"
msgid "Insert row before"
msgstr "Inserați rândul înainte"
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "Inserați sugestia"
@@ -22942,12 +23317,15 @@ msgstr "Setările implicite sunt moștenite de la nivelul grupului."
msgid "Integrations|Default settings are inherited from the instance level."
msgstr "Setările implicite sunt moștenite de la nivelul instanței."
+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 "Editați aliasul proiectului"
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
-msgstr "Activați comenzile slash GitLab.com într-un spațiu de lucru Slack."
-
msgid "Integrations|Enable SSL verification"
msgstr "Activați verificarea SSL"
@@ -22963,6 +23341,9 @@ msgstr "Verificați dacă URL-ul instanței dvs. este corect și dacă instanța
msgid "Integrations|Enter your alias"
msgstr "Introduceți aliasul dvs."
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr "Spațiul de nume n-a putut fi conectat. Vă rugăm să încercați din nou."
@@ -23251,8 +23632,8 @@ msgstr "Pachet de repozitoriu nevalabil pentru fragmentul cu ID-ul %{snippet_id}
msgid "Invalid repository path"
msgstr "Cale de repozitoriu nevalidă"
-msgid "Invalid rule"
-msgstr "Regulă nevalidă"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr "Răspuns nevalid al serverului"
@@ -23380,9 +23761,6 @@ msgstr "Creați probleme la care să lucreze noul membru al echipei dumneavoastr
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|Explore paid plans"
-msgstr "Explorați planurile plătite"
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr "GitLab este mai bun împreună cu colegii!"
@@ -23653,6 +24031,12 @@ msgstr "Tip de problemă"
msgid "Issue already promoted to epic."
msgstr "Problema a fost deja promovată la epică."
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr "Problema nu poate fi găsită."
@@ -23878,6 +24262,9 @@ msgstr "S-a produs o eroare în timpul mutării problemelor."
msgid "Issue|Title"
msgstr "Titlu"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr "Se pare că încercați să vă activați abonamentul. Utilizați în schimb %{a_start}pagina Abonament%{a_end}."
@@ -24415,9 +24802,24 @@ msgstr "Jobul a fost reîncercat"
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "Joburi"
@@ -25108,6 +25510,15 @@ msgstr "Aflați mai multe."
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
msgstr "%{percentage}%{percentSymbol} completat"
+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 "Adăugare de proprietari de coduri"
@@ -25189,6 +25600,9 @@ msgstr "Configurați-vă spațiul de lucru"
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "Începeți o încercare gratuită a GitLab Ultimate"
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr ""
+
msgid "LearnGitLab|Submit a merge request (MR)"
msgstr "Trimiteți un merge request (MR)"
@@ -25198,6 +25612,9 @@ msgstr "Încercați GitLab Ultimate gratuit"
msgid "LearnGitLab|Try all GitLab features for 30 days, no credit card required."
msgstr "Încercați toate funcțiile GitLab timp de 30 de zile, fără a fi nevoie de un card de credit."
+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 "Folosiți-vă noul flux de lucru GitLab pentru a vă implementa aplicația, a-i monitoriza starea de sănătate și pentru a o menține în siguranță:"
@@ -25213,9 +25630,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr "Contactați-vă administratorul pentru a începe o perioadă de încercare gratuită Ultimate."
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr "Crearea experienței dvs. de onboarding..."
-
msgid "LearnGitlab|Ok, let's go"
msgstr "Bine, să mergem."
@@ -25231,6 +25645,9 @@ msgstr "Ieșiți din Modul Admin"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "Părăsiți modul de editare? Toate modificările nesalvate vor fi pierdute."
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Părăsiți grupul"
@@ -25486,6 +25903,12 @@ msgstr "Limitați mărimea joburilor Sidekiq stocate în Redis."
msgid "Limiting mode"
msgstr "Modul restricționat"
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Line changes"
msgstr "Modificări de linie"
@@ -25513,6 +25936,9 @@ msgstr "Conectați un wiki extern din bara laterală a proiectului. %{docs_link}
msgid "Link copied"
msgstr "Link copiat"
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr "Textul linkului"
@@ -25606,9 +26032,6 @@ msgstr "Listați repozitoriile disponibile"
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr "Lista tuturor commit-urilor de îmbinare"
-
msgid "List of suitable GCP locations"
msgstr "Lista de locații GCP adecvate"
@@ -25651,6 +26074,9 @@ msgstr "Se încarcă statisticile de contribuție pentru membrii grupului"
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr "Se încarcă fișierele, directoarele și submodulele din calea %{path} pentru referința commit-ului %{ref}"
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr "Se încarcă mai multe"
@@ -25690,6 +26116,9 @@ msgstr "Blocați fișierul?"
msgid "Lock memberships to LDAP synchronization"
msgstr "Blocați abonamentele la sincronizarea LDAP"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr "Blocați merge request-ul"
@@ -25708,9 +26137,6 @@ msgstr "Blocați la proiectele curente"
msgid "Locked"
msgstr "Blocat"
-msgid "Locked Files"
-msgstr "Fișiere blocate"
-
msgid "Locked by %{fileLockUserName}"
msgstr "Blocat de %{fileLockUserName}"
@@ -25780,9 +26206,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "ÃŽMBINAT"
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr "ÃŽnapoi la merge request"
@@ -25819,10 +26242,7 @@ msgstr "Afișați numai modificările"
msgid "MRDiff|Show full file"
msgstr "Afișați întregul fișier"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26314,6 +26734,9 @@ msgstr "Mărime maximă de push"
msgid "Maximum push size (MB)"
msgstr "Mărimea maximă de push (MB)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr "Maximum de solicitări pe 10 minute pe utilizator"
@@ -26395,12 +26818,21 @@ 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 "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|must be top-level namespace"
msgstr ""
@@ -26623,18 +27055,9 @@ msgstr "Îmbinare automată (%{strategy})"
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr "Îmbinare blocată: toate dependențele merge request-ului trebuie să fie îmbinate."
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr "Îmbinare blocată: merge request-ul trebuie să fie marcat ca gata. Este încă marcat ca draft."
-
-msgid "Merge blocked: new changes were just added."
-msgstr "Merge blocat: tocmai au fost adăugate noi modificări."
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr "Îmbinare blocată: pipeline-ul trebuie să reușească. Se așteaptă un job manual pentru a continua."
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr "Îmbinare blocată: trebuie făcut un rebase a ramurii sursă pe ramura țintă."
-
msgid "Merge commit SHA"
msgstr "Commit de îmbinare SHA"
@@ -26707,9 +27130,6 @@ msgstr "Merge request-urile sunt un loc în care puteți propune modificările p
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr "Îmbinare indisponibilă: merge request-urile sunt numai în citire într-un nod Geo secundar."
-
msgid "Merge unverified changes"
msgstr "Îmbinați modificările neverificate"
@@ -26722,6 +27142,27 @@ msgstr "Se îmbină atunci când pipeline-ul reușește"
msgid "Merge..."
msgstr "ÃŽmbinarea..."
+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 "Comiteți la ramura sursă"
@@ -27334,6 +27775,9 @@ msgstr[2] "Obiective"
msgid "Milestone due date"
msgstr "Data scadentă a obiectivului"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "Listele de obiective nu sunt disponibile cu licența dvs. actuală"
@@ -27514,6 +27958,12 @@ msgstr "Capacitatea minimă care trebuie să fie disponibilă înainte de a prog
msgid "Minutes"
msgstr "Minute"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr "Direcția replicării"
@@ -27526,6 +27976,9 @@ msgstr "Replicați repozitoriul"
msgid "Mirror settings are only available to GitLab administrators."
msgstr "Setările pentru replici sunt disponibile numai administratorilor GitLab."
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr "Utilizatorul replicii"
@@ -27586,31 +28039,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27955,6 +28423,9 @@ msgstr "Spații de nume"
msgid "Namespaces to index"
msgstr "Spațiu de nume pentru indexare"
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "Denumirea, subiecte, avatar"
@@ -28003,10 +28474,16 @@ msgstr "Roșu"
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28120,9 +28597,6 @@ msgstr "Cerință nouă"
msgid "New Snippet"
msgstr "Nou fragment de cod"
-msgid "New Test Case"
-msgstr "Caz de testare nou"
-
msgid "New User"
msgstr "Utilizator nou"
@@ -28210,9 +28684,6 @@ msgstr "Nume nou"
msgid "New password"
msgstr "Parolă nouă"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr "Noile pipeline-uri determină anularea pipeline-urilor mai vechi în așteptare sau în curs de execuție pe aceeași ramură."
-
msgid "New project"
msgstr "Proiect nou"
@@ -28567,6 +29038,15 @@ msgstr "Nu există conturi de servicii"
msgid "No severity matches the provided parameter"
msgstr "Nicio severitate nu corespunde parametrului furnizat"
+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 "Nicio sursă selectată"
@@ -28651,14 +29131,17 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
-msgstr "Nu toate browserele sunt compatibile cu dispozitivele U2F. Prin urmare, vă solicităm să configurați mai întâi o aplicație de autentificare cu doi factori. În acest fel, veți putea să vă conectați întotdeauna - chiar și atunci când utilizați un browser neacceptat."
+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. 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 "Nu toate browserele acceptă WebAuthn. Prin urmare, vă solicităm să configurați mai întâi o aplicație de autentificare cu doi factori. În acest fel, veți putea să vă conectați întotdeauna - chiar și de pe un browser neacceptat."
+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 "Nu au fost procesate încă toate datele, precizia graficului pentru intervalul de timp selectat este limitată."
@@ -28963,12 +29446,24 @@ msgstr "%{paragraph_start}Bună, %{name}!%{paragraph_end} %{paragraph_start}A fo
msgid "Notify|%{project_link_start}Download%{project_link_end} the project export."
msgstr "%{project_link_start}Descărcați%{project_link_end} exportul proiectului."
+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|%{update_at_start} Last update at %{update_at_mid} %{last_update_at} %{update_at_end}"
msgstr "%{update_at_start} Ultima actualizare la %{update_at_mid} %{last_update_at} %{update_at_end}"
msgid "Notify|%{updated_by_user_name} pushed new commits to merge request %{mr_link}"
msgstr "%{updated_by_user_name} a împins noi commit-uri în merge request-ul %{mr_link}"
+msgid "Notify|%{work_items} successfully imported."
+msgstr ""
+
msgid "Notify|A new GPG key was added to your account:"
msgstr "O nouă cheie GPG a fost adăugată în contul dvs.:"
@@ -29017,9 +29512,18 @@ msgstr "Eroare la analizarea fișierului CSV. Asigurați-vă că are formatul co
msgid "Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check if these lines have an issue title."
msgstr "S-au găsit erori pe %{singular_or_plural_line}: %{error_lines}. Verificați dacă aceste linii au un titlu de problemă."
+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 "Amprenta: %{fingerprint}"
+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 "Bună %{username}!"
@@ -29047,9 +29551,6 @@ msgstr "Jurnalele pot conține date sensibile. Vă rugăm să luați în conside
msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict."
msgstr "Merge request-ul %{merge_request} nu mai poate fi îmbinat din cauza unui conflict."
-msgid "Notify|Merge request %{merge_request} was %{mr_status}"
-msgstr "Merge request-ul %{merge_request} a fost %{mr_status}"
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr "Merge request-ul %{merge_request} a fost %{mr_status} de %{updated_by}"
@@ -29086,6 +29587,9 @@ msgstr "Problema nouă: %{project_issue_url}"
msgid "Notify|No preview for this file type"
msgstr "Acest tip de fișier nu poate fi previzualizat"
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29095,6 +29599,9 @@ msgstr "Pipeline-ul %{pipeline_link} declanșat de"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
msgstr "Pipeline-ul a fost reparat și #%{pipeline_id} a trecut!"
+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 "Proiectul %{old_path_with_namespace} a fost mutat în altă locație."
@@ -29107,6 +29614,9 @@ msgstr "Exportul proiectului %{project_name} s-a finalizat."
msgid "Notify|Remote mirror"
msgstr "Replicare remote"
+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 "Administratorul v-a creat un cont. Acum sunteți membru al aplicației GitLab a companiei GitLab."
@@ -29584,6 +30094,9 @@ msgstr "Scanările la cerere se execută în afara ciclului DevOps și identific
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 "Repetiții"
@@ -29653,9 +30166,6 @@ msgstr "Fusul orar"
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29950,29 +30460,35 @@ msgstr "Echipa noastră a fost notificată. Vă rugăm să încercați din nou."
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr "Neconform cu politicile acestui proiect și ar trebui să fie înlăturat."
-msgid "OutboundRequests|Allow requests to the local network from hooks and services."
-msgstr "Permiteți solicitări către rețeaua locală de la hook-uri și servicii."
+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 "Permiteți solicitările către rețeaua locală de la hook-urile de sistem"
-msgid "OutboundRequests|Allow requests to the local network from web hooks and services"
-msgstr "Permiteți solicitări către rețeaua locală de la hook-uri și servicii web"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
+msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
-msgstr "Impuneți protecția împotriva atacurilor de re-legare DNS"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
+msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
-msgstr "Adresele IP locale și numele de domenii pe care hook-urile și serviciile le pot accesa"
+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 "Solicitări de ieșire"
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
-msgstr "Solicitările către aceste domenii și adrese IP sunt accesibile atât hook-urilor de sistem, cât și celor web, chiar și atunci când nu sunt permise solicitările locale. Sunt acceptate intervale IP precum 1:0:0:0:0:0:0:0:0:0/124 și 127.0.0.0.0/28. Nu sunt acceptate caractere wildcard de domeniu. Pentru a separa intrările, utilizați virgule, punct și virgulă sau linii noi. Lista de permisiuni poate conține maximum 1000 de intrări. Domeniile trebuie să fie codificate IDNA."
+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|Resolve IP addresses once and uses them to submit requests."
-msgstr "Rezolvați adresele IP o dată și utilizați-le pentru a trimite solicitări."
+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 "S-ar putea ca GitLab să nu funcționeze corect, deoarece utilizați un browser web învechit."
@@ -30772,6 +31288,9 @@ msgstr "În așteptarea ștergerii"
msgid "Pending comments"
msgstr "Comentarii în așteptare"
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "În așteptarea ștergerii"
@@ -30961,9 +31480,6 @@ msgstr ""
msgid "Pick a name"
msgstr "Alegeți un nume"
-msgid "Pin code"
-msgstr "Codul PIN"
-
msgid "Pipeline"
msgstr "Pipeline"
@@ -31162,6 +31678,9 @@ msgstr "În așteptarea încărcării conținutului CI..."
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 ""
@@ -31387,6 +31906,9 @@ msgstr "Pipeline-uri"
msgid "Pipelines charts"
msgstr "Diagrame de pipeline-uri"
+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 "Setările pipeline-urilor pentru „%{project_name}†au fost actualizate cu succes."
@@ -31438,9 +31960,6 @@ msgstr "Pipeline copil (%{link_start}părinte%{link_end})"
msgid "Pipelines|Clear runner caches"
msgstr "Ștergeți cache-urile executorilor"
-msgid "Pipelines|Configuration validation currently not available."
-msgstr "Validarea configurației nu este disponibilă în prezent."
-
msgid "Pipelines|Configure pipeline"
msgstr "Configurați pipeline-ul"
@@ -31486,6 +32005,12 @@ msgstr "GitLab Runner este o aplicație care funcționează cu GitLab CI/CD pent
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
msgstr "GitLab Runner este o aplicație care funcționează cu GitLab CI/CD pentru a rula joburi într-un pipeline. Există executori activi disponibili pentru a vă rula joburile chiar acum. Dacă preferați, vă puteți %{settingsLinkStart}configura executorii%{settingsLinkEnd} sau puteți %{docsLinkStart}afla mai multe%{docsLinkEnd} despre executori."
+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 "Dacă nu sunteți sigur, vă rugăm să cereți unui responsabil de proiect să-l revizuiască pentru dumneavoastră."
@@ -31537,8 +32062,8 @@ msgstr "Proprietar"
msgid "Pipelines|Pipeline Editor"
msgstr "Editor de pipeline"
-msgid "Pipelines|Pipeline syntax is correct."
-msgstr "Sintaxa pipeline-ului este corectă."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr "Cache-ul proiectului a fost resetat cu succes."
@@ -31546,6 +32071,9 @@ msgstr "Cache-ul proiectului a fost resetat cu succes."
msgid "Pipelines|Ready to set up CI/CD for your project?"
msgstr "Sunteți gata să configurați CI/CD pentru proiectul dumneavoastră?"
+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|Revoke trigger"
msgstr "Revocare declanșator"
@@ -31582,14 +32110,14 @@ msgstr "A apărut o problemă în timpul încărcării datelor pipeline-ului."
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
msgstr "A apărut o eroare în timpul preluării pipeline-urilor. Încercați din nou în câteva momente sau contactați echipa de asistență."
-msgid "Pipelines|This GitLab CI configuration is invalid."
-msgstr "Această configurație GitLab CI nu este validă."
+msgid "Pipelines|This GitLab CI configuration is invalid. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is invalid:"
msgstr "Această configurație GitLab CI nu este validă:"
-msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}."
-msgstr "Această configurație GitLab CI nu este validă: %{reason}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
msgstr "Această configurație GitLab CI este validă."
@@ -31618,6 +32146,12 @@ msgstr "Utilizatorul declanșator nu are permisiuni suficiente pentru proiect"
msgid "Pipelines|Try test template"
msgstr "Încercați șablonul de testare"
+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 "Utilizați un exemplu de fișier șablon %{codeStart}.gitlab-ci.yml%{codeEnd} pentru a explora modul în care funcționează CI/CD."
@@ -31639,6 +32173,9 @@ msgstr "Vizualizați YAML-ul îmbinat"
msgid "Pipelines|Visualize"
msgstr "Vizualizare"
+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 "Vă vom ghida prin configurarea simplă a unui pipeline."
@@ -31648,6 +32185,9 @@ msgstr "Vă vom prezenta cum să implementați pe iOS în doi pași simpli."
msgid "Pipelines|You have runners available to run your job now. No need to do anything else."
msgstr "Acum aveți executori disponibili pentru a vă executa activitatea. Nu este nevoie să faceți nimic altceva."
+msgid "Pipelines|You should review the code thoroughly before running this pipeline with the parent project's CI/CD resources."
+msgstr ""
+
msgid "Pipelines|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr "Schimbările dvs. au fost comise cu succes. Acum se redirecționează către noua pagină a merge request-ului."
@@ -31963,6 +32503,9 @@ msgstr "Vă rugăm să ștergeți licența dvs. actuală dacă doriți să retro
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "Vă rugăm să activați și să migrați la stocarea hash pentru a evita problemele de securitate și a asigura integritatea datelor. %{migrate_link}"
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "Vă rugăm să introduceți un număr non-negativ"
@@ -31984,6 +32527,9 @@ msgstr "Vă rugăm să introduceți un interval de timp valid"
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr "Vă rugăm să introduceți parola dvs. actuală."
@@ -32044,8 +32590,8 @@ msgstr "Vă rugăm să selectați"
msgid "Please select a Jira project"
msgstr "Vă rugăm să selectați un proiect Jira"
-msgid "Please select a country"
-msgstr "Vă rugăm să selectați o țară"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr "Vă rugăm să selectați un grup"
@@ -32398,6 +32944,9 @@ msgstr "Previzualizare diagramă"
msgid "Preview payload"
msgstr "Vizualizare payload"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "Artefactele anterioare"
@@ -32467,88 +33016,31 @@ msgstr "Problemă cu comanda %{name}: %{message}."
msgid "Proceed"
msgstr "Continuați"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32557,34 +33049,37 @@ 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 "Audiență"
-msgid "ProductAnalytics|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32593,24 +33088,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32623,22 +33112,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32647,70 +33145,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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 "În prezent, nu există date pentru acest tip de grafic. Vă rugăm să consultați fila „Configurare†dacă nu ați configurat deja instrumentul de analiză a produsului."
-msgid "ProductAnalytics|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32878,6 +33379,12 @@ msgstr "Deconectare"
msgid "Profiles|Disconnect %{provider}"
msgstr "Deconectare de la %{provider}"
+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|Do not show on profile"
msgstr "Nu se afișează în profil"
@@ -33127,7 +33634,7 @@ msgstr "Trebuie să transferați proprietatea sau să ștergeți grupurile de ca
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Trebuie să transferați proprietatea sau să ștergeți aceste grupuri înainte de a vă putea șterge contul."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33301,6 +33808,9 @@ msgstr "Membrii proiectului"
msgid "Project milestone"
msgstr "Obiectiv de proiect"
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Numele proiectului"
@@ -33313,6 +33823,9 @@ 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"
@@ -33340,6 +33853,9 @@ msgstr "Nivelul de vizibilitate al proiectului este mai puțin restrictiv decât
msgid "Project visibility level will be changed to match namespace rules when transferring to a group."
msgstr "Nivelul de vizibilitate al proiectului va fi modificat pentru a se potrivi cu regulile spațiului de nume atunci când se transferă într-un grup."
+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 "Proiectul nu a fost găsit sau nu aveți permisiunea de a adăuga acest proiect în Tablourile de bord de securitate."
@@ -33436,9 +33952,21 @@ msgstr "ID-ul proiectului: %{project_id}"
msgid "ProjectQualitySummary|An error occurred while trying to fetch project quality statistics"
msgstr "A apărut o eroare în timpul încercării de a prelua statisticile privind calitatea proiectului"
+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 "Coverage"
+msgid "ProjectQualitySummary|Critical"
+msgstr ""
+
msgid "ProjectQualitySummary|Failure"
msgstr "Eșec"
@@ -33451,6 +33979,9 @@ msgstr "Ajutați-ne la îmbunătățirea acestei pagini"
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr "Rezultatele celui mai recent pipeline"
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr "Aflați mai multe despre coverage de testate"
@@ -33493,8 +34024,11 @@ msgstr "Procentul de teste care reușesc, eșuează sau sunt sărite."
msgid "ProjectQualitySummary|This page helps you understand the code testing trends for your project. Let us know how we can improve it!"
msgstr "Pagina aceasta vă ajută la înțelegerea trendurilor în testarea codului din proiectul dumneavoastră. Faceți-ne cunoscut în ce mod îl putem îmbunătăți!"
-msgid "ProjectSelect| or group"
-msgstr "sau grup"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
msgid "ProjectSelect|No matching results"
msgstr "Nu există rezultate potrivite"
@@ -33508,9 +34042,6 @@ msgstr "Căutați proiecte"
msgid "ProjectSelect|Select a project"
msgstr "Selectați un proiect"
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr "Ceva nu a mers bine la preluarea proiectelor"
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr "S-a produs o eroare la preluarea proiectelor. Vă rugăm să încercați din nou."
@@ -33640,9 +34171,6 @@ msgstr "Setări suplimentare care influențează modul și momentul în care se
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr "Toate merge-request-urile și commit-urile sunt făcute pe această ramură, cu excepția cazului în care specificați una diferită."
-msgid "ProjectSettings|All threads must be resolved"
-msgstr "Toate subiectele trebuie să fie rezolvate"
-
msgid "ProjectSettings|Allow"
msgstr "Permiteți"
@@ -33793,9 +34321,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr "Intern"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr "Introduce riscul de îmbinare a modificărilor care nu trec de pipeline."
-
msgid "ProjectSettings|Issues"
msgstr "Probleme"
@@ -33838,9 +34363,6 @@ msgstr "Merge request-uri"
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 "Merge request-urile aprobate pentru îmbinare sunt puse în coadă și pipeline-urile validează rezultatele combinate ale ramurilor sursă și țintă înainte de îmbinare. %{link_start}Ce sunt merge train-urile? %{link_end}"
-msgid "ProjectSettings|Merge requests can't be merged if the latest pipeline did not succeed or is still running."
-msgstr "Merge request-urile nu pot fi îmbinate dacă ultimul pipeline nu a avut succes sau este încă în curs de execuție."
-
msgid "ProjectSettings|Merge suggestions"
msgstr "Sugestii de îmbinare"
@@ -33877,9 +34399,6 @@ msgstr "Pages"
msgid "ProjectSettings|Pages for project documentation."
msgstr "Pages pentru documentația proiectului."
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "Pipeline-urile trebuie să reușească"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr "Împiedică crearea de legături directe către fișiere media potențial sensibile"
@@ -33922,11 +34441,11 @@ msgstr "Lansați noi caracteristici fără a redistribui cu feature flags."
msgid "ProjectSettings|Search for topic"
msgstr "Căutați un subiect"
-msgid "ProjectSettings|Security & Compliance"
-msgstr "Securitate & Conformitate"
+msgid "ProjectSettings|Security and Compliance"
+msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
-msgstr "Securitate și conformitate pentru acest proiect"
+msgid "ProjectSettings|Security and compliance for this project."
+msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
msgstr "Selectați ramura implicită a acestui proiect și configurați șablonul pentru numele ramurii."
@@ -33949,9 +34468,6 @@ msgstr "Afișați emojiurile de atribuire implicite"
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr "Afișați linkul pentru a crea sau a vizualiza un merge request atunci când se face push din linia de comandă"
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr "Pipeline-urile ignorate sunt considerate reușite"
-
msgid "ProjectSettings|Snippets"
msgstr "Fragmente de cod"
@@ -34186,6 +34702,9 @@ msgstr "Proiecte (%{count})"
msgid "Projects API"
msgstr "API de proiecte"
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr "Proiecte recuperate cu succes"
@@ -34312,6 +34831,9 @@ msgstr "Migrați datele dintr-o sursă externă, cum ar fi GitHub, Bitbucket sau
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 "Nu sunt disponibile opțiuni de import"
@@ -34327,6 +34849,9 @@ msgstr "Configurarea proiectului"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "Descrierea proiectului %{tag_start}(opțional)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr "Recomandat dacă sunteți nou în GitLab"
@@ -34507,9 +35032,6 @@ msgstr "Contactați proprietarul %{link_start}%{owner_name}%{link_end} pentru a
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr "Contactați administratorul dvs. pentru a vă actualiza licența."
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "Șabloanele de descriere vă permit să definiți șabloane specifice contextului pentru câmpurile de descriere a problemelor și a merge request-urilor pentru proiectul dumneavoastră."
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr "Respingeți promovarea Service Desk"
@@ -34618,12 +35140,6 @@ msgstr "Atunci când aveți o mulțime de probleme, poate fi dificil să obține
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr "Puteți restricționa accesul la ramurile protejate prin selectarea unui rol (Întreținători, Dezvoltatori), precum și a anumitor utilizatori."
-msgid "Promotions|description templates"
-msgstr "șabloane de descriere"
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr "pentru a vă ajuta colaboratorii să comunice eficient!"
-
msgid "Prompt users to upload SSH keys"
msgstr "Solicită utilizatorilor să încarce cheile SSH"
@@ -34795,9 +35311,27 @@ msgstr "Puteți adăuga numai grupurile care au acest proiect partajat. %{learn_
msgid "ProtectedBranch|default"
msgstr "implicit"
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34807,10 +35341,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34819,15 +35365,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+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?"
@@ -34837,6 +35392,9 @@ msgstr "Toate mediile specificate cu nivelurile de implementare de mai jos sunt
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "Autorizat să desfășoare"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr "Se permite implementarea în %{project} / %{environment}"
@@ -35293,24 +35851,15 @@ msgstr "Gata de îmbinare!"
msgid "Reauthenticating with SAML provider."
msgstr "Reautentificarea cu furnizorul SAML."
-msgid "Rebase"
-msgstr "Rebase"
-
msgid "Rebase completed"
msgstr "Rebase finalizat"
-msgid "Rebase in progress"
-msgstr "Rebase în curs"
-
msgid "Rebase source branch"
msgstr "Faceți un rebase al ramurii sursă"
msgid "Rebase source branch on the target branch."
msgstr "Faceți un rebase al ramurii sursă pe ramura țintă."
-msgid "Rebase without pipeline"
-msgstr "Rebase fără pipeline"
-
msgid "Recaptcha verified?"
msgstr "Recaptcha este verificată?"
@@ -35386,6 +35935,9 @@ msgstr "Rafinați-vă criteriile de căutare (selectați %{strong_open}un grup%{
msgid "Refresh the page and try again."
msgstr "Reîmprospătați pagina și încercați din nou."
+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] "Se reîmprospătează într-o secundă pentru a afișa starea actualizată..."
@@ -35422,14 +35974,14 @@ msgstr "Înregistrați-vă"
msgid "Register / Sign In"
msgstr "ÃŽnregistrare / Conectare"
-msgid "Register Two-Factor Authenticator"
-msgstr "Înregistrați Authenticatorul cu doi factori"
+msgid "Register a WebAuthn device"
+msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "Înregistrați dispozitivul universal cu doi factori (U2F)"
+msgid "Register a one-time password authenticator"
+msgstr ""
-msgid "Register WebAuthn Device"
-msgstr "Înregistrați dispozitivul WebAuthn"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
+msgstr ""
msgid "Register device"
msgstr "Înregistrați dispozitivul"
@@ -35521,6 +36073,9 @@ msgstr "Respins (închis)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr "Se referă la %{issuable_type} %{add_related_issue_link}"
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr "Feature Flags asociate"
@@ -36463,15 +37018,21 @@ msgstr "Cerința %{reference} a fost redeschisă"
msgid "Requirement %{reference} has been updated"
msgstr "Cerința %{reference} a fost actualizată"
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr "Titlul cerinței nu poate avea mai mult de %{limit} caractere."
-
msgid "Requirements"
msgstr "Cerințe"
msgid "Requirements can be based on users, stakeholders, system, software, or anything else you find important to capture."
msgstr "Cerințele se pot baza pe utilizatori, părți interesate, sistem, software sau orice altceva vi se pare important de captat."
+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] "Necesită %d aprobare din partea utilizatorilor eligibili."
@@ -36652,9 +37213,6 @@ msgstr ""
msgid "Resume"
msgstr "Reluare"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr "Recuperarea raportului de conformitate a eșuat. Reîmprospătați pagina și încercați din nou."
-
msgid "Retry"
msgstr "Reîncercați"
@@ -36826,9 +37384,6 @@ msgstr "Executați sarcini de menaj pentru a optimiza automat repozitoriile Git.
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr "Executați joburi manuale sau întârziate"
@@ -36907,6 +37462,9 @@ msgstr "Activ"
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|Administrator"
msgstr "Administrator"
@@ -36970,6 +37528,9 @@ msgstr "Capacitatea de 1 permite HA caldă prin regenerarea grupului cu Scalare
msgid "Runners|Checkbox"
msgstr "Caseta de selectare"
+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 "Alegeți-vă Executorul GitLab preferat"
@@ -36988,6 +37549,9 @@ msgstr "Configurare"
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 "Copiați instrucțiunile"
@@ -37045,9 +37609,15 @@ msgstr "Activați curățarea executorilor inactivi"
msgid "Runners|Enable stale runner cleanup?"
msgstr "Activați curățarea executorilor inactivi?"
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr "Introduceți numărul de secunde. Acest timp de expirare are prioritate față de timpii de expirare mai mici setați pentru proiect."
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr "Executor"
@@ -37060,6 +37630,12 @@ msgstr "Filtrare proiecte"
msgid "Runners|Get started with runners"
msgstr "Începeți cu executorii"
+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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr "Grup"
@@ -37078,6 +37654,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr "Instalați un executor"
@@ -37105,6 +37684,12 @@ msgstr "Blocat pentru acest proiect"
msgid "Runners|Maintenance note"
msgstr "Notă de întreținere"
+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 "Timpul maxim de expirare a jobului"
@@ -37114,6 +37699,9 @@ msgstr "Membrii cu rol de %{type} pot înregistra executori"
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr "Nume"
@@ -37126,6 +37714,9 @@ msgstr "Niciodată contactat:"
msgid "Runners|Never expires"
msgstr "Nu expiră niciodată"
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37168,6 +37759,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr "Proprietar"
@@ -37201,6 +37795,12 @@ msgstr "Protejat"
msgid "Runners|Recommended"
msgstr "Recomandat"
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr "Înregistrați un executor de grup"
@@ -37216,6 +37816,9 @@ msgstr "Înregistrați un executor de instanță"
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 "Înregistrați cât de mulți executori doriți. Puteți înregistra executori ca utilizatori separați, pe servere separate și pe computerul local."
+msgid "Runners|Register runner"
+msgstr ""
+
msgid "Runners|Registration token"
msgstr "Tokenul de înregistrare"
@@ -37240,6 +37843,9 @@ msgstr "Executor #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
msgstr "Executorul %{name} a fost șters"
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37255,6 +37861,12 @@ msgstr "Expirarea tokenului de autentificare a executorului"
msgid "Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired."
msgstr "Tokenurile de autentificare ale executorului vor expira după un interval stabilit. Odată expirate, acestea vor fi înlocuite automat."
+msgid "Runners|Runner created."
+msgstr ""
+
+msgid "Runners|Runner description"
+msgstr ""
+
msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
msgstr "Executorul a contactat GitLab în ultimele %{elapsedTime}"
@@ -37327,9 +37939,15 @@ msgstr "Rulează joburi neetichetate"
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 "Selectați-i pe toți"
+msgid "Runners|Select platform specifications to install GitLab Runner."
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr "Selectați proiectele pe care să le atribuiți acestui executor"
@@ -37363,6 +37981,12 @@ msgstr "Inactiv:"
msgid "Runners|Status"
msgstr "Statusul"
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr "Împiedicați executorul să mai accepte noi joburi."
@@ -37372,6 +37996,9 @@ msgstr "Etichete"
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 "Etichetele controlează tipul de joburi pe care le poate gestiona un executor. Prin etichetarea unui executor, asigurați ca executorii partajați să se ocupe numai de joburile pentru care sunt echipați."
+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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr "Proiectul, grupul sau instanța în care a fost înregistrat executorul. Executorii de instanță sunt întotdeauna deținuți de Administrator."
@@ -37390,6 +38017,9 @@ msgstr[2] "Acest grup are în prezent %d de executori inactivi."
msgid "Runners|This group currently has no stale runners."
msgstr "Acest grup nu are în prezent niciun executor inactiv."
+msgid "Runners|This may not be needed if you manage your runner as a %{linkStart}system or user service%{linkEnd}."
+msgstr ""
+
msgid "Runners|This runner has not run any jobs."
msgstr "Acest executor nu a executat niciun job."
@@ -37438,6 +38068,9 @@ msgstr "Upgrade recomandat"
msgid "Runners|Use Group runners when you want all projects in a group to have access to a set of runners."
msgstr "Folosiți Executorii de grup atunci când doriți ca toate proiectele dintr-un grup să aibă acces la un set de executori."
+msgid "Runners|Use the runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr "Folosiți executorul pentru joburi fără etichete, în plus față de joburile cu etichete."
@@ -37492,15 +38125,6 @@ msgstr ""
msgid "Runners|shared"
msgstr "partajat"
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr "Proprietar"
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "Rulează"
@@ -37522,6 +38146,9 @@ msgstr "Tokenuri de descoperire SAML"
msgid "SAML for %{group_name}"
msgstr "SAML pentru %{group_name}"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr "Autentificare unică SAML"
@@ -37546,9 +38173,6 @@ 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 "SAST Configuration"
-msgstr "Configurare SAST"
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37678,16 +38302,19 @@ msgstr "ScanExecutionPolicy|%{period} %{days} la %{time}"
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr "%{rules} acțiuni pentru %{scopes} %{branches} %{agents} %{namespaces}"
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr "Se execută un pipeline"
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37729,9 +38356,15 @@ msgstr "agent"
msgid "ScanExecutionPolicy|branch"
msgstr "ramura"
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr "în spațiile de nume"
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38191,24 +38824,27 @@ msgstr ""
msgid "Security"
msgstr "Securitate"
-msgid "Security & Compliance"
-msgstr "Securitate & Conformitate"
-
-msgid "Security Configuration"
-msgstr "Configurarea securității"
-
msgid "Security Dashboard"
msgstr "Tabloul de bord de securitate"
msgid "Security Finding not found"
msgstr "Detectarea de securitate nu a fost găsită"
+msgid "Security Policy project already exists."
+msgstr ""
+
+msgid "Security and Compliance"
+msgstr ""
+
+msgid "Security capabilities"
+msgstr ""
+
+msgid "Security configuration"
+msgstr ""
+
msgid "Security dashboard"
msgstr "Tabloul de bord de securitate"
-msgid "Security navigation"
-msgstr "Navigare de securitate"
-
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr "Raportul de securitate este expirat. Vă rugăm să vă actualizați ramura cu ultimele modificări din ramura țintă (%{targetBranchName})"
@@ -38335,8 +38971,8 @@ msgstr "Metricile de securitate runtime pentru mediile aplicațiilor"
msgid "SecurityConfiguration|SAST Analyzers"
msgstr "Analizatoare SAST"
-msgid "SecurityConfiguration|SAST Configuration"
-msgstr "Configurația SAST"
+msgid "SecurityConfiguration|SAST configuration"
+msgstr ""
msgid "SecurityConfiguration|Secure your project"
msgstr "Asigurați-vă securitatea proiectului"
@@ -38449,6 +39085,9 @@ msgstr "Alegeți un proiect"
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr "Creați reguli de vulnerabilitate mai solide și aplicați-le tuturor proiectelor dumneavoastră."
@@ -38554,9 +39193,18 @@ msgstr "Nu a fost definită nicio acțiune - politica nu se va executa."
msgid "SecurityOrchestration|No description"
msgstr "Fără descriere"
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr "Nu s-au definit reguli - politica nu se va executa."
+msgid "SecurityOrchestration|No tags available"
+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 "Neactivat"
@@ -38647,6 +39295,9 @@ msgstr "Scanare care urmează să fie efectuată de agentul numit %{agents} %{ca
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr "Scanare care trebuie efectuată pe fiecare pipeline de pe %{branches}"
+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 "Aprobări de securitate"
@@ -38668,6 +39319,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr "Selectați politica"
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38677,6 +39331,9 @@ msgstr "Selectați proiectul de securitate"
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr "Ceva nu a mers bine, nu se pot prelua politicile"
@@ -38743,7 +39400,7 @@ msgstr "Deconectarea unui proiect de securitate elimină toate politicile stocat
msgid "SecurityOrchestration|Update scan policies"
msgstr "Actualizați politicile de scanare"
-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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38821,6 +39478,9 @@ msgstr "%{firstProject}, %{secondProject}, și %{rest}"
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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."
@@ -39298,6 +39958,9 @@ msgstr "Selectați eticheta"
msgid "Select labels"
msgstr "Selectați etichetele"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "Selectați momentul îmbinării"
@@ -39400,6 +40063,9 @@ msgstr "Proiectul de automonitorizare a fost șters cu succes"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "Proiectul de automonitorizare nu a fost șters. Vă rugăm să verificați jurnalele pentru orice mesaj de eroare"
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr "Activați sau dezactivați automonitorizarea instanței."
@@ -39412,6 +40078,9 @@ msgstr "Dezactivați automonitorizarea?"
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr "Dezactivarea automonitorizării șterge proiectul de automonitorizare. Sunteți sigur că doriți să dezactivați automonitorizarea și să ștergeți proiectul?"
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr "Automonitorizare"
@@ -39424,6 +40093,9 @@ msgstr "Crearea proiectului de automonitorizare s-a finalizat."
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr "Ștergerea proiectului de automonitorizare s-a finalizat."
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr "Trimite"
@@ -39526,6 +40198,12 @@ msgstr "Conturi de servicii"
msgid "Service usage data"
msgstr "Date de utilizare a serviciilor"
+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|Enable Service Desk"
msgstr "Activați Service Desk"
@@ -39661,6 +40339,9 @@ msgstr "Setați durata maximă a sesiunii pentru un terminal web."
msgid "Set the milestone to %{milestone_reference}."
msgstr "Setați obiectivul la %{milestone_reference}"
+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 "Setați limita ratei pe utilizator pentru obținerea unui utilizator după ID prin intermediul API-ului."
@@ -39688,8 +40369,8 @@ msgstr "Configurați integrarea Jira"
msgid "Set up a %{type} runner for a project"
msgstr "Configurați un executor %{type} pentru un proiect"
-msgid "Set up a hardware device as a second factor to sign in."
-msgstr "Configurați un dispozitiv hardware ca al doilea factor de autentificare."
+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 "Configurați aserțiunile/atributele/reclamațiile (email, first_name, last_name) și NameID în conformitate cu %{docsLinkStart}documentația %{icon}%{docsLinkEnd}"
@@ -39940,6 +40621,9 @@ msgstr "Afișați conținutul fișierului"
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr "Afișați obiectivele grupului"
@@ -40105,9 +40789,6 @@ msgstr "Limitele mărimii jobului Sidekiq"
msgid "Sign in"
msgstr "Autentificare"
-msgid "Sign in / Register"
-msgstr "Conectare / ÃŽnregistrare"
-
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 "Conectați-vă ca utilizator cu adresa de e-mail potrivită, adăugați adresa de e-mail la acest cont sau înregistrați-vă pentru un cont nou utilizând adresa de e-mail potrivită."
@@ -40261,15 +40942,33 @@ msgstr "Integrarea Slack vă permite să interacționați cu GitLab prin comenzi
msgid "Slack logo"
msgstr "Logoul Slack"
+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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr "ID client"
msgid "SlackIntegration|Client secret"
msgstr "Secretul clientului"
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr "GitLab pentru Slack"
@@ -40279,6 +40978,9 @@ msgstr "GitLab pentru Slack a fost instalat cu succes."
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr "Aliasul proiectului"
@@ -40288,6 +40990,9 @@ msgstr ""
msgid "SlackIntegration|Remove project"
msgstr "Înlăturați proiectul"
+msgid "SlackIntegration|Run ChatOps jobs."
+msgstr ""
+
msgid "SlackIntegration|See the list of available commands in Slack after setting up this integration by entering"
msgstr "Consultați lista de comenzi disponibile în Slack după ce ați configurat această integrare, introducând"
@@ -40321,9 +41026,15 @@ msgstr "Token de verificare"
msgid "SlackIntegration|You can now close this window and go to your Slack workspace."
msgstr "Acum puteți închide această fereastră și puteți merge la spațiul de lucru Slack."
+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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40507,12 +41218,18 @@ msgstr "S-a produs o eroare în timpul încercării de încărcare a contactelor
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 "Ceva nu a mers bine atunci când am reordonat design-urile. Vă rugăm să încercați din nou"
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 "Ceva nu a mers bine la adăugarea evenimentului cronologic."
@@ -40924,9 +41641,6 @@ msgstr "Conflict de nume pentru metoda „%{prop}()â€."
msgid "SourceEditor|No extension for unuse has been specified."
msgstr "Nu a fost specificată nicio extensie pentru nefolosire."
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr "Instanța Editor de sursă este necesară pentru a configura o extensie."
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr "Proprietatea „definition†este așteptată pe extensie."
@@ -40990,6 +41704,9 @@ msgstr "Protecție anti-spam și anti-bot"
msgid "Spam log successfully submitted as ham."
msgstr "Jurnalul de spam a fost trimis cu succes ca ham."
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr "URL-ul specificat nu poate fi utilizat: „%{reason}â€"
@@ -41239,6 +41956,9 @@ msgstr "Înlăturați verificarea stării?"
msgid "StatusCheck|Service name"
msgstr "Numele serviciului"
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr "Verificări de stare"
@@ -41884,17 +42604,23 @@ msgstr "SunteÈ›i gata să începeÈ›i? Un plan GitLab este ideal pentru organizaÈ
msgid "SuperSonics|Start free trial"
msgstr "Începeți o perioadă de încercare gratuită"
+msgid "SuperSonics|Subscription detail synchronization has started and will complete soon."
+msgstr ""
+
msgid "SuperSonics|Subscription details"
msgstr "Detaliile abonamentului"
+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 "Abonament indisponibil"
msgid "SuperSonics|Sync subscription details"
msgstr "Sincronizați detaliile abonamentului"
-msgid "SuperSonics|Sync subscription request."
-msgstr "Solicitarea de sincronizare a abonamentului."
+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 "Codul de activare nu este valid. Asigurați-vă că îl copiați exact din Portalul Clienților sau din e-mailul de confirmare. Aflați mai multe despre %{linkStart}activarea abonamentului dumneavoastră%{linkEnd}."
@@ -41902,8 +42628,8 @@ msgstr "Codul de activare nu este valid. Asigurați-vă că îl copiați exact d
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr "Codul de activare trebuie să fie un șir alfanumeric de 24 de caractere."
-msgid "SuperSonics|There is a connectivity issue."
-msgstr "Există o problemă de conectivitate."
+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 "Acesta este punctul cu cel mai mare număr de utilizatori de pe instalația dvs. de când a început licența."
@@ -41932,9 +42658,6 @@ msgstr "Utilizatorii cu rol de Invitat sau cei care nu aparțin unui Proiect sau
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 "Puteți %{purchaseSubscriptionLinkStart}achiziționa un nou abonament%{purchaseSubscriptionLinkEnd} și să încercați din nou. Dacă aveți nevoie de asistență suplimentară, vă rugăm să %{supportLinkStart}contactați serviciul de asistență GitLab%{supportLinkEnd}."
-msgid "SuperSonics|You can no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr "Nu vă mai puteți sincroniza detaliile abonamentului cu GitLab. Obțineți ajutor pentru cele mai frecvente probleme de conectivitate prin %{connectivityHelpLinkStart}depanarea codului de activare%{connectivityHelpLinkEnd}."
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr "Puteți începe o perioadă de încercare gratuită a GitLab Ultimate fără nicio obligație sau detalii de plată."
@@ -41977,9 +42700,6 @@ msgstr "Abonamentul d-voastră"
msgid "SuperSonics|Your subscription cannot be located"
msgstr "Abonamentul dvs. nu poate fi localizat"
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr "Detaliile abonamentului dvs. se vor sincroniza în scurt timp."
-
msgid "SuperSonics|Your subscription is expired"
msgstr "Abonamentul dvs. a expirat"
@@ -42130,9 +42850,27 @@ msgstr "Lista de etichete:"
msgid "Tag name"
msgstr "Numele etichetei"
+msgid "Tag name cannot be one of the following: %{names}"
+msgstr ""
+
msgid "Tag name is required."
msgstr "Numele etichetei este necesar."
+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 "Push de etichetă"
@@ -42541,12 +43279,12 @@ msgstr "Proiectul dvs. nu are niciun fișier de stare Terraform"
msgid "Test"
msgstr "Test"
-msgid "Test Cases"
-msgstr "Cazuri de testare"
-
msgid "Test case"
msgstr "Caz de testare"
+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] "Valoarea de coverage de teste pentru acest pipeline a fost calculată prin valoarea de coverage pentru %d job"
@@ -42568,9 +43306,6 @@ msgstr "Mutați cazul de testare"
msgid "TestCases|Moving test case"
msgstr "Cazul de testare se mută"
-msgid "TestCases|New Test Case"
-msgstr "Caz de testare nou"
-
msgid "TestCases|New test case"
msgstr "Caz de testare nou"
@@ -42697,6 +43432,9 @@ msgstr "Text (opțional)"
msgid "Text added to the body of all email messages. %{character_limit} character limit"
msgstr "Text adăugat în corpul tuturor mesajelor de e-mail. Limita de %{character_limit} de caractere"
+msgid "Text added to the body of user deactivation email messages. 1000 character limit."
+msgstr ""
+
msgid "Text style"
msgstr "Stil de text"
@@ -42757,6 +43495,9 @@ msgstr "Trackerul de probleme este locul în care puteți adăuga lucruri care t
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr "Serverul Prometheus a răspuns cu „solicitare greÈ™ităâ€. Vă rugăm să verificaÈ›i dacă interogările dvs. sunt corecte È™i sunt acceptate în versiunea dvs. de Prometheus. %{documentationLink}"
+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 "Domeniul cookie-ului Snowplow."
@@ -42799,9 +43540,6 @@ msgstr "Vizualizarea comparativă poate fi inexactă din cauza conflictelor de Ã
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 "Platforma DevOps completă. O singură aplicație cu posibilități infinite. Organizațiile se bazează pe managementul codului sursă, CI/CD, securitate și multe altele de la GitLab pentru a livra rapid software."
-msgid "The compliance report shows the merge request violations merged in protected environments."
-msgstr "Raportul de conformitate arată încălcările merge request-urilor îmbinate în medii protejate."
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Conexiunea se va termina după %{timeout}. Pentru repozitoriile care necesită mai mult timp, utilizați o combinație clonă/push."
@@ -42859,6 +43597,9 @@ msgstr "Lista de dependențe conține informații detaliate despre componentele
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "Implementarea acestei sarcini în %{environmentLink} nu a reușit."
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr "Directorul a fost creat cu succes."
@@ -43174,8 +43915,17 @@ msgstr "Resursa pe care încercați să o accesați nu există sau nu aveți per
msgid "The scan has been created."
msgstr "Scanarea a fost creată."
-msgid "The secret is only available when you first create the application."
-msgstr "Secretul este accesibil numai atunci când creați prima dată aplicația."
+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 "Fragmentul de cod poate fi accesat fără nicio autentificare."
@@ -43519,6 +44269,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr "A apărut o eroare la preluarea joburilor pentru proiectul dvs."
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr "A apărut o eroare la preluarea etichetelor de top pentru grupul selectat"
@@ -43708,14 +44461,8 @@ msgstr "Această arhivă a fost solicitată de prea multe ori. Încercați din n
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 "Acest atașament a fost trunchiat pentru a evita depășirea mărimii maxime admise a atașamentului de %{size_limit}. Au fost incluse %{written_count} din %{count} %{issuables}. Luați în considerare reexportarea cu o selecție mai restrânsă de %{issuables}."
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr "Acest atașament a fost trunchiat pentru a evita depășirea mărimii maxime permise a atașamentului de %{size_limit}. Au fost incluse %{written_count} din %{issues_count} probleme. Luați în considerare reexportarea cu o selecție mai restrânsă de probleme."
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr "Acest atașament a fost trunchiat pentru a evita depășirea mărimii maxime permise a atașamentului de %{size_limit}. Au fost incluse %{written_count} din %{merge_requests_count} merge request-uri. Luați în considerare reexportarea cu o selecție mai restrânsă de merge request-uri."
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
-msgstr "Acest atașament a fost trunchiat pentru a evita depășirea mărimii maxime permise a atașamentului de %{size_limit}. Au fost incluse %{written_count} din %{requirements_count} cerințe. Luați în considerare reexportarea cu o selecție mai restrânsă de cerințe."
+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 "Acest bloc este autoreferențial"
@@ -44215,6 +44962,9 @@ msgstr "Acest repozitoriu a fost verificat ultima dată %{last_check_timestamp}.
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr "Acest depozit a fost verificat ultima dată la %{last_check_timestamp}. Verificarea a trecut."
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "Acest executor va rula numai pe pipeline-urile declanșate pe ramurile protejate"
@@ -44269,11 +45019,8 @@ msgstr "Această variabilă nu poate fi mascată."
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr "Aceasta va invalida aplicațiile înregistrate și dispozitivele U2F / WebAuthn."
-
-msgid "This will invalidate your registered applications and U2F devices."
-msgstr "Aceasta va invalida aplicațiile înregistrate și dispozitivele U2F."
+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 "Aceasta va elimina relația de fork dintre acest proiect și %{fork_source}."
@@ -44725,6 +45472,9 @@ msgstr "Pentru a începe, vă rugăm să introduceți URL-ul dvs. Gitea Host și
msgid "To get started, use the link below to confirm your account."
msgstr "Pentru a începe, utilizați linkul de mai jos pentru a vă confirma contul."
+msgid "To go to GitLab Pages, on the left sidebar, select %{pages_link}."
+msgstr ""
+
msgid "To help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr "Pentru a ajuta la îmbunătățirea GitLab, am dori ca periodic să %{docs_link}. Acest lucru poate fi schimbat în orice moment în %{settings_link}."
@@ -45214,6 +45964,9 @@ msgstr "Grupul este deja un grup rădăcină."
msgid "TransferGroup|Group is already associated to the parent group."
msgstr "Grupul este deja asociat grupului părinte."
+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 "Grupul părinte are deja un subgrup sau un proiect cu aceeași cale."
@@ -45304,9 +46057,6 @@ msgstr "Declanșați reindexarea clusterului. Folosiți această opțiune numai
msgid "Trigger job"
msgstr "Job declanșator"
-msgid "Trigger manual job"
-msgstr "Declanșează un job manual"
-
msgid "Trigger pipelines for mirror updates"
msgstr "Declanșați pipeline-uri pentru actualizările în replică"
@@ -45409,9 +46159,6 @@ msgstr "Twitter:"
msgid "Two-Factor Authentication"
msgstr "Autentificarea cu doi factori"
-msgid "Two-Factor Authentication code"
-msgstr "Codul de autentificare cu doi factori"
-
msgid "Two-factor Authentication"
msgstr "Autentificarea cu doi factori"
@@ -45457,12 +46204,6 @@ msgstr "Tipul"
msgid "Type to search"
msgstr "Introduceți textul de căutat"
-msgid "U2F Devices (%{length})"
-msgstr "Dispozitive U2F (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "U2F funcționează numai cu site-uri web compatibile cu HTTPS. Contactați administratorul pentru mai multe detalii."
-
msgid "URL"
msgstr "URL"
@@ -45568,6 +46309,9 @@ msgstr "Imposibil de preluat pipeline-urile din amonte și din aval."
msgid "Unable to find Jira project to import data from."
msgstr "Nu se poate găsi proiectul Jira din care să se importe date."
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr "Nu s-a putut încărca în totalitate mesajul implicit al commit-ului. Puteți aplica în continuare această sugestie iar mesajul commit-ului va fi corect"
@@ -45667,6 +46411,9 @@ msgstr ""
msgid "Unban"
msgstr "Deblocați"
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr "Modificările care nu au fost comise vor fi pierdute dacă schimbați ramurile. Doriți să continuați?"
@@ -45724,6 +46471,15 @@ msgstr "Dacă nu se convine altfel în scris cu GitLab, făcând clic pe „Înc
msgid "Unlimited"
msgstr "Nelimitat"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr "Dezlegare"
@@ -45811,6 +46567,9 @@ msgstr "Valoare de sortare neacceptată."
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr "Tip de sarcină de făcut neacceptat transmis. Tipurile de lucruri de făcut acceptate sunt: %{todo_types}"
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr "Nefolosit"
@@ -45880,6 +46639,9 @@ msgstr "Actualizați URL-urile marcate ca favorite, deoarece URL-urile ramurilor
msgid "Update your group name, description, avatar, and visibility."
msgstr "Actualizați numele, descrierea, avatarul și vizibilitatea grupului dumneavoastră."
+msgid "Update your project name and description."
+msgstr ""
+
msgid "Update your project name, topics, description, and avatar."
msgstr "Actualizați numele, subiectele, descrierea și avatarul proiectului dumneavoastră."
@@ -46006,6 +46768,9 @@ msgstr "Tendințe de utilizare"
msgid "Usage statistics"
msgstr "Statistici de utilizare"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr "Statisticile de stocare la nivel de proiect pentru registrul de containere sunt numai direcționale și nu includ economiile pentru deduplicarea la nivel de instanță."
@@ -46177,6 +46942,9 @@ msgstr "Acest spațiu de nume nu are proiecte care au folosit executorii partaja
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr "Acest tabel omite proiectele care au folosit 0 minute CI/CD sau 0 minute de funcționare partajată."
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr "Încărcări"
@@ -46381,6 +47149,9 @@ msgstr "Utilizați opțiunea %{strongStart}Test%{strongEnd} menționată anterio
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 "Utilizați linkul de mai jos pentru a vă confirma adresa de e-mail (%{email})"
@@ -46393,6 +47164,9 @@ msgstr "Folosiți URL-ul instanței cloud publice (%{kroki_public_url}) sau %{in
msgid "Use the search bar on the top of this page"
msgstr "Utilizați bara de căutare din partea de sus a acestei pagini"
+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 "Utilizați acest token pentru a valida payload-urile primite."
@@ -46468,6 +47242,9 @@ msgstr "Utilizator creat la"
msgid "User does not have a pending request"
msgstr "Utilizatorul nu are o solicitare în așteptare"
+msgid "User does not have permission to create a Security Policy project."
+msgstr ""
+
msgid "User identity was successfully created."
msgstr "Identitatea utilizatorului a fost creată cu succes."
@@ -46894,6 +47671,9 @@ msgstr "Analiza Fluxului de valori vă poate ajuta să determinați viteza echip
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr "Valoarea poate conține o referință la o variabilă"
@@ -47005,6 +47785,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr "Elemente în etapă"
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr "Durata etapei (medie)"
@@ -47149,6 +47932,9 @@ msgstr ""
msgid "View blame"
msgstr "Vizualizați blame"
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr "Consultați blame înainte de această modificare"
@@ -47179,9 +47965,6 @@ msgstr "Vizualizați documentația"
msgid "View eligible approvers"
msgstr "Vizualizați aprobatorii eligibili"
-msgid "View entire blame"
-msgstr "Vizualizați întregul blame"
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "Vizualizați artefactul expus"
@@ -47386,6 +48169,69 @@ msgstr "%{formattedStartDate} până astăzi"
msgid "VulnerabilityChart|Severity"
msgstr "Severitatea"
+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|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 "%{statusStart}Confirmat%{statusEnd} %{timeago} de %{user}"
@@ -47776,12 +48622,6 @@ msgstr "Nu s-au găsit %{scope} care să corespundă cu %{term} din proiectul %{
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "Nu am putut ajunge la serverul Prometheus. Fie serverul nu mai există, fie detaliile de configurare trebuie actualizate."
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr "Am detectat o tentativă de conectare la contul dvs. %{host} folosind un cod de autentificare cu doi factori greșit"
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr "Am detectat o tentativă de conectare la contul dvs. %{host} folosind un cod de autentificare cu doi factori greșit, de la următoarea adresă IP: %{ip}, la %{time}."
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "Am detectat un spam potențial în %{humanized_resource_name}. Vă rugăm să rezolvați reCAPTCHA pentru a continua."
@@ -47833,9 +48673,6 @@ msgstr "Vom notifica %{inviter} că ați refuzat invitația de a vă alătura Gi
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 "Dorim să vă informăm că abonamentul Ediția GitLab Enterprise %{plan_name} se apropie de limita de utilizatori. Aveți %{active_user_count} utilizatori activi, care este aproape de limita maximă de %{maximum_user_count} de utilizatori."
-msgid "We'll continuously validate your pipeline configuration. The validation results will appear here."
-msgstr "Vom valida în permanență configurația pipeline-ului dumneavoastră. Rezultatele validării vor apărea aici."
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "Vom folosi aceste date pentru a vă ajuta să evidențiați caracteristicile și informațiile potrivite pentru dumneavoastră."
@@ -47977,6 +48814,9 @@ msgstr "Se creează sau se actualizează o versiune."
msgid "Webhooks|A subgroup is created or removed."
msgstr "Se creează sau se înlătură un subgrup."
+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 "Un webhook din acest proiect, după ce a fost încercat de mai multe ori, a fost dezactivat automat."
@@ -48241,6 +49081,12 @@ msgstr "Atunci când utilizați protocoalele %{code_open}http://%{code_close} sa
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 "Când vă transferați proiectul într-un grup, puteți să gestionați cu ușurință mai multe proiecte, să vizualizați cotele de utilizare a stocării, a minutelor de pipeline și a utilizatorilor și să începeți o perioadă de încercare sau să treceți la un nivel plătit."
+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] ""
+msgstr[2] ""
+
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] "La sfârșitul perioadei de probă, veți trece la nivelul gratuit, care are o limită de %{free_user_limit} seat. %{free_user_limit} seat va rămâne activ, iar membrii care nu ocupă un seat vor avea %{link_start}statutul Peste limită%{link_end} și vor pierde accesul la acest grup."
@@ -48280,6 +49126,9 @@ msgstr "Cine va folosi acest grup?"
msgid "Why are you signing up? (optional)"
msgstr "De ce vă înscrieți? (opțional)"
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -48499,8 +49348,8 @@ msgstr "Nu se repară / Acceptați riscul"
msgid "Work in progress (open and unassigned)"
msgstr "Lucrări în curs (deschise și neatribuite)"
-msgid "Work in progress Limit"
-msgstr "Limita de lucrări în curs"
+msgid "Work in progress limit"
+msgstr ""
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -48547,6 +49396,9 @@ msgstr "Adăugați la iterație"
msgid "WorkItem|Add to milestone"
msgstr "Adăugați un obiectiv"
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "Sunteți sigur că doriți să anulați editarea?"
@@ -48571,6 +49423,15 @@ msgstr "Copilul a fost înlăturat"
msgid "WorkItem|Closed"
msgstr "ÃŽnchis"
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48595,9 +49456,15 @@ msgstr "Data scadenței"
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr "Incident"
@@ -48718,6 +49585,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr "Sarcină ștearsă"
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr "Sarcini"
@@ -48754,6 +49624,9 @@ msgstr "Element de lucru"
msgid "WorkItem|Work item not found"
msgstr "Elementul de lucru nu a fost găsit"
+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 "Would you like to create a new branch?"
msgstr "Doriți să creați o nouă ramură?"
@@ -48784,6 +49657,9 @@ msgstr "Scrieți o notă internă sau glisați fișierele aici..."
msgid "Write milestone description..."
msgstr "Scrieți descrierea obiectivului..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "Scrieți-vă notele de lansare sau trageți fișierele aici…"
@@ -49186,9 +50062,6 @@ msgstr "Nu aveți permisiunea de a actualiza mediul."
msgid "You do not have permissions to run the import."
msgstr "Nu aveți permisiuni pentru a executa importul."
-msgid "You don't have any U2F devices registered yet."
-msgstr "Nu aveți încă dispozitive U2F înregistrate."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr "Nu aveți încă niciun dispozitiv WebAuthn înregistrat."
@@ -49360,12 +50233,18 @@ msgstr "Trebuie să aveți acces de întreținător pentru a forța ștergerea u
msgid "You must provide a valid current password"
msgstr "Trebuie să furnizați o parolă actuală valabilă"
+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 "Trebuie să furnizați parola curentă pentru a o modifica."
+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 "Trebuie să vă conectați pentru a căuta proiecte specifice."
@@ -49537,6 +50416,9 @@ msgstr "%{spammable_entity_type} dvs. a fost recunoscut(ă) ca fiind spam. Vă r
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
msgstr "Abonamentul dvs. %{strong}%{plan_name}%{strong_close} pentru %{strong}%{namespace_name}%{strong_close} va expira pe %{strong}%{expires_on}%{strong_close}."
+msgid "Your Activity"
+msgstr ""
+
msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details."
msgstr ""
@@ -49546,8 +50428,8 @@ msgstr "Exportul dvs. CSV a început. Acesta va fi trimis prin e-mail la %{email
msgid "Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment."
msgstr "Exportul dvs. CSV de %{count} din proiectul %{project_link} a fost adăugat la acest e-mail ca atașament."
-msgid "Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
-msgstr "Exportul dvs. CSV de %{written_count} din proiectul %{project_name} (%{project_url}) a fost adăugat la acest e-mail ca atașament."
+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 import for project"
msgstr "Importul dvs. CSV pentru proiect"
@@ -49576,6 +50458,9 @@ msgstr "Grupul dvs. GitLab"
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 "Grupurile dvs."
@@ -49600,6 +50485,9 @@ msgstr "Cheia dvs. SSH a fost ștearsă"
msgid "Your SSH keys (%{count})"
msgstr "Cheile dvs. SSH (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "Lista dvs. De-Făcut"
@@ -49645,6 +50533,9 @@ msgstr "Acțiunea a fost respinsă deoarece ați atins limita de stocare a spaț
msgid "Your action succeeded."
msgstr "Acțiunea dvs. a reușit."
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "Aplicațiile dvs. (%{size})"
@@ -49654,9 +50545,6 @@ msgstr "Aplicațiile dvs. autorizate"
msgid "Your browser does not support iFrames"
msgstr "Browserul dvs. nu acceptă iFrames"
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "Browserul dvs. nu acceptă U2F. Va rugăm să folosiți Google Chrome desktop (versiunea 41 sau mai nouă)."
-
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+)."
@@ -49687,6 +50575,9 @@ msgstr "Comentariul dvs. va fi înlăturat."
msgid "Your commit email is used for web based operations, such as edits and merges."
msgstr "E-mailul dvs. de commit este utilizat pentru operațiunile bazate pe web, cum ar fi editările și fuziunile."
+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 "Parola dvs. actuală este necesară pentru a înregistra o aplicație de autentificare cu doi factori."
@@ -49846,6 +50737,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50086,6 +50980,9 @@ msgstr "se poate schimba doar de un administrator de grup."
msgid "can only have one escalation policy"
msgstr "poate avea doar o singură politică de escaladare"
+msgid "can't be blank"
+msgstr ""
+
msgid "can't be enabled when delayed group deletion is disabled"
msgstr "nu se poate activa atunci când ștergerea întârziată a grupului este dezactivată"
@@ -50422,9 +51319,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr "Raport generic"
-msgid "ciReport|IaC Scanning"
-msgstr "Scanarea IaC"
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "Investigați această vulnerabilitate prin crearea unei probleme"
@@ -50491,6 +51385,9 @@ msgstr "Rezolvați cu un merge request"
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "Detectarea secretelor"
@@ -50521,6 +51418,9 @@ msgstr "Se afișează %{fetchedItems} din %{totalItems} elemente"
msgid "ciReport|Solution"
msgstr "Soluție"
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST)"
msgstr ""
@@ -50803,9 +51703,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 "following"
-msgstr "urmăriți"
-
msgid "for"
msgstr "pentru"
@@ -51115,11 +52012,17 @@ msgstr "blocat(ă) de %{path_lock_user_name} la %{created_at}"
msgid "manual"
msgstr "manual"
-msgid "math|Displaying this math block may cause performance issues on this page"
-msgstr "Afișarea acestui bloc-math poate cauza probleme de performanță pe această pagină"
+msgid "math|Displaying this math block may cause performance issues on this page."
+msgstr ""
-msgid "math|There was an error rendering this math block"
-msgstr "A apărut o eroare la redarea acestui bloc-math"
+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"
@@ -51178,6 +52081,84 @@ msgstr "Folosiți merge request-uri pentru a propune modificări la propriul pro
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr "%{boldHeaderStart}Se pare că nu există niciun pipeline aici.%{boldHeaderEnd}"
+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|%{mergeError}."
msgstr "%{mergeError}."
@@ -51193,6 +52174,12 @@ msgstr "Utilizarea %{metricsLinkStart} memoriei %{metricsLinkEnd} %{emphasisStar
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "Utilizarea %{metricsLinkStart} memoriei %{metricsLinkEnd} este %{emphasisStart} neschimbată %{emphasisEnd} la %{memoryFrom}MB"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr "Un merge train este o listă de merge request-uri care așteaptă să fie îmbinate în ramura țintă. Modificările din fiecare merge request sunt combinate cu modificările din merge request-urile anterioare și sunt testate înainte de îmbinare."
@@ -51220,12 +52207,6 @@ msgstr "Aprobarea este opțională"
msgid "mrWidget|Approval password is invalid."
msgstr "Parola de aprobare nu este validă."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr "Regula de aprobare %{rules} este nevalidă. GitLab a aprobat automat această regulă pentru a debloca merge request-ul. %{link}"
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr "Regulile de aprobare %{rules} sunt nevalide. GitLab a aprobat automat aceste reguli pentru a debloca merge request-ul. %{link}"
-
msgid "mrWidget|Approve"
msgstr "Aprobați"
@@ -51241,6 +52222,9 @@ msgstr "Aprobat de dvs."
msgid "mrWidget|Approved by you and others"
msgstr "Aprobat de dvs. și de alții"
+msgid "mrWidget|Are you sure you want to rebase?"
+msgstr ""
+
msgid "mrWidget|Assign yourself to these issues"
msgstr "Atribuiți-vă aceste probleme"
@@ -51322,83 +52306,29 @@ msgstr[0] "Problemă menționată"
msgstr[1] "Probleme menționate"
msgstr[2] "Probleme menționate"
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr "Fuziune blocată: în titlu sau în descriere trebuie să se menționeze cheia unei probleme Jira."
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr "Îmbinare blocată: toate aprobările necesare trebuie să fie acordate."
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "Îmbinare blocată: toate subiectele trebuie să fie rezolvate."
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr "Îmbinare blocată: licențele refuzate trebuie să fie înlăturate."
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr "Îmbinare blocată: nu este posibilă o îmbinare fast-forward. Pentru a îmbina această solicitare, mai întâi faceți un rebase local."
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr "Îmbinare blocată: conflictele de îmbinare trebuie să fie rezolvate."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr "Îmbinare blocată: pipeline-ul trebuie să reușească. Se așteaptă o acțiune manuală pentru a continua."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr "Îmbinare blocată: pipeline-ul trebuie să reușească. Faceți push la un commit care corectează eșecul sau %{linkStart}aflați despre alte soluții.%{linkEnd}"
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr "Îmbinare blocată: puteți îmbina numai după ce elementele de mai sus sunt rezolvate."
-
msgid "mrWidget|Merge failed."
msgstr "Îmbinarea nu a reușit."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr "Îmbinare indisponibilă: merge request-urile sunt numai în citire pe proiectele arhivate."
-
msgid "mrWidget|Merged by"
msgstr "ÃŽmbinat de"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr "Îmbinare în curs! Modificările sunt în curs de expediere..."
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr "Îmbinare în curs! Modificările vor ateriza în curând..."
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr "Îmbinare în curs! Tobele, vă rugăm..."
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr "Îmbinare în curs! Totul e în regulă..."
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr "Îmbinare în curs! Decolarea în 5... 4... 3..."
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr "Îmbinare în curs! Respirați adânc și relaxați-vă..."
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr "Îmbinare în curs! Schimbările părăsesc gara..."
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr "Îmbinare în curs! Acest lucru va fi grozav..."
-
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "Îmbinare în curs! Suntem aproape acolo..."
-
msgid "mrWidget|More information"
msgstr "Mai multe informații"
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "Niciun utilizator nu corespunde criteriilor regulii."
-
msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr "Vă rugăm să o restaurați sau să folosiți o altă ramură %{type}."
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "Gata pentru îmbinarea automată. Cereți cuiva cu acces în scriere la acest repozitoriu să îmbine această solicitare"
+msgid "mrWidget|Rebase"
+msgstr ""
+
+msgid "mrWidget|Rebase in progress"
+msgstr ""
+
+msgid "mrWidget|Rebase without pipeline"
+msgstr ""
msgid "mrWidget|Refresh"
msgstr "Reîmprospătați"
@@ -51460,9 +52390,6 @@ msgstr "Pentru a modifica acest mesaj implicit, editați șablonul pentru mesaje
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr "Pentru a schimba acest mesaj implicit, editați șablonul mesajelor commit-urilor squash. %{linkStart}Aflați mai multe.%{linkEnd}"
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr "Utilizatorii care pot scrie în ramurile sursă sau țintă pot rezolva conflictele."
-
msgid "mrWidget|What is a merge train?"
msgstr "Ce este un merge train?"
@@ -51487,6 +52414,9 @@ msgstr "trebuie să fie o adresă IPv4 sau IPv6 validă"
msgid "must be a valid json schema"
msgstr "trebuie să fie o schemă json validă"
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr "trebuie să fie după start"
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index f2c7686092a..030ab5b1757 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr " %{start} по %{end}"
@@ -566,6 +566,13 @@ msgstr[1] "%d нерешённые темы"
msgstr[2] "%d нерешённых тем"
msgstr[3] "%d нерешённых тем"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d уÑзвимоÑÑ‚ÑŒ"
@@ -615,6 +622,13 @@ msgstr[1] "найдено %d предупреждениÑ:"
msgstr[2] "найдено %d предупреждений:"
msgstr[3] "найдено %d предупреждений:"
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
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 дополнительный коммит был пропущен Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
@@ -622,6 +636,12 @@ msgstr[1] "%s дополнительных коммита было пропущÐ
msgstr[2] "%s дополнительных коммитов было пропущено Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
msgstr[3] "%s дополнительных коммитов было пропущено Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} & %{openOrClose} %{noteable}"
@@ -812,6 +832,9 @@ msgstr "%{count} ÑвÑзанный %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "%{count} выбрано"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1013,6 +1036,9 @@ msgstr "%{level_name} запрещено, Ñ‚.к. проект-иÑточник Ð
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}, и еще %{awardsListLength}"
@@ -1028,9 +1054,6 @@ msgstr "%{mergeLength}/%{usersLength} можно объединить"
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1168,6 +1191,9 @@ msgstr "%{reportType} обнаружено %{totalStart}%{total}%{totalEnd} по
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1446,6 +1472,9 @@ msgstr "%{user} Ñоздал цель: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} Ñоздал обÑуждение: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} не ÑодержитÑÑ Ð² ÑпиÑке"
@@ -1750,13 +1779,6 @@ msgstr[1] "%d ключа развёртываниÑ"
msgstr[2] "%d ключей развёртываниÑ"
msgstr[3] "%d ключей развёртываниÑ"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "1 подпиÑчик"
-msgstr[1] "%{count} подпиÑчика"
-msgstr[2] "%{count} подпиÑчиков"
-msgstr[3] "%{count} подпиÑчиков"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 группа"
@@ -2089,9 +2111,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr "Справка по API"
@@ -2506,9 +2525,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr "Добавить Ñворачиваемую Ñекцию"
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr "Добавить комментарий к Ñтой Ñтроке"
@@ -2530,6 +2546,9 @@ msgstr "Добавьте домашнюю Ñтраницу в Ñвою Wiki, в
msgid "Add a new issue"
msgstr "Добавить новое обÑуждение"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Добавить нумерованный ÑпиÑок"
@@ -2539,6 +2558,9 @@ 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 ""
@@ -2653,6 +2675,9 @@ msgstr "Добавить новое приложение"
msgid "Add new directory"
msgstr "Добавить новый каталог"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2791,6 +2816,9 @@ msgstr ""
msgid "Additional text"
msgstr "Дополнительный текÑÑ‚"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3970,40 +3998,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4375,6 +4373,9 @@ msgstr "ВеÑÑŒ GitLab"
msgid "All Members"
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 "Ð’Ñе ветви"
@@ -5007,6 +5008,9 @@ msgstr "Произошла Ð½ÐµÐ¿Ñ€ÐµÐ´Ð²Ð¸Ð´ÐµÐ½Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° при за
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Произошла Ð½ÐµÐ¿Ñ€ÐµÐ´Ð²Ð¸Ð´ÐµÐ½Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° при оÑтановке Web Terminal."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr ""
@@ -5016,6 +5020,123 @@ msgstr "Произошла неизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°."
msgid "Analytics"
msgstr "Ðналитика"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Ðнализируйте ваши завиÑимоÑти на предмет извеÑтных уÑзвимоÑтей."
@@ -5094,13 +5215,28 @@ msgstr "Добавить комментарий Ñ %{shrug}"
msgid "Append the comment with %{tableflip}"
msgstr "Добавить комментарий Ñ %{tableflip}"
+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|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."
+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."
@@ -5249,12 +5385,18 @@ 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 ""
@@ -5509,6 +5651,13 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Утвердить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5521,6 +5670,20 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5596,9 +5759,6 @@ msgstr "Вы уверены, что хотите %{action} %{name}?"
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5611,6 +5771,9 @@ msgstr "Вы уверены, что хотите закрыть заблокир
msgid "Are you sure you want to delete %{name}?"
msgstr "Вы точно хотите удалить %{name}?"
+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 ""
@@ -5968,7 +6131,7 @@ msgstr[3] "Прикрепить %d файлов"
msgid "Attaching the file failed."
msgstr "Ðе удалоÑÑŒ прикрепить файл."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6224,9 +6387,6 @@ msgstr "Создано %{author} %{timeago}"
msgid "Authorization code:"
msgstr "Код авторизации:"
-msgid "Authorization required"
-msgstr "ТребуетÑÑ Ð°Ð²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ð¸Ñ"
-
msgid "Authorization token duration (minutes)"
msgstr "Срок дейÑÑ‚Ð²Ð¸Ñ Ñ‚Ð¾ÐºÐµÐ½Ð° авторизации (в минутах)"
@@ -6239,9 +6399,6 @@ msgstr "Ðвторизовать"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "ÐвторизуйтеÑÑŒ %{link_to_client} Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑи?"
-msgid "Authorize %{user} to use your account?"
-msgstr "Разрешить %{user} иÑпользовать вашу учетную запиÑÑŒ?"
-
msgid "Authorized %{new_chat_name}"
msgstr "Ðвторизован %{new_chat_name}"
@@ -6251,9 +6408,18 @@ msgstr "Ðвторизован в"
msgid "Authorized applications (%{size})"
msgstr "Ðвторизованные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6635,6 +6801,9 @@ msgstr "Будьте оÑторожны. Изменение пути проекÑ
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Будьте оÑторожны. Переименование Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð° может вызвать нежелательные побочные Ñффекты."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6662,9 +6831,6 @@ msgstr "Ðиже приведены наÑтройки Ð´Ð»Ñ %{link_to_gitlab_p
msgid "Below you will find all the groups that are public."
msgstr "Ðиже показаны вÑе открытые группы."
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr "Двухнедельное покрытие кода"
@@ -6734,6 +6900,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6749,9 +6918,6 @@ msgstr "ЕÑли вы хотите понизить уровень Ñвоего
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 "Узнайте больше о каждом плане, прочитав %{faq_link}, или начните беÑплатный 30-дневный пробный период GitLab.com Ultimate."
@@ -6887,27 +7053,9 @@ msgstr "Улучшить"
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr "При повторной активации пробного периода вы получите 30 дополнительных дней плана %{planName}. Повторно активировать пробный период можно лишь единожды."
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6917,9 +7065,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr "Реактивировать пробный период"
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7062,6 +7207,9 @@ msgstr "Импорт из BitBucket"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7290,15 +7438,27 @@ msgstr[3] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7311,9 +7471,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7431,9 +7588,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7452,6 +7606,15 @@ 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 ""
@@ -7482,10 +7645,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7527,6 +7693,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8296,6 +8465,15 @@ 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 "Ðе удалоÑÑŒ Ñоздать Ñниппет: %{err}"
@@ -8413,6 +8591,9 @@ 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 ""
@@ -8799,6 +8980,9 @@ msgstr "(x%{numberOfUsers})"
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 ""
@@ -8841,6 +9025,9 @@ 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 "Создать новую группу"
@@ -8850,18 +9037,15 @@ msgstr "Ðе удалоÑÑŒ загрузить форму кредитной кÐ
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "Ðе удалоÑÑŒ загрузить форму кредитной карты: %{message}"
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "Правка"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "Ðе удалить подтвердить ваш заказ! ПожалуйÑта, попробуйте ещё раз."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "Ðе удалоÑÑŒ подтвердить ваш заказ: %{message}. ПожалуйÑта, попробуйте ещё раз."
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "Ðе удалоÑÑŒ загрузить Ñтраны. ПожалуйÑта, попробуйте ещё раз."
@@ -8886,6 +9070,9 @@ msgstr "План GitLab"
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 ""
@@ -8904,6 +9091,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "КоличеÑтво пользователей"
@@ -8922,6 +9112,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "СоÑтоÑние"
@@ -9042,12 +9235,18 @@ msgstr "Выберите Ñодержимое, которое вы хотите
msgid "Choose which Git strategy to use when fetching the project."
msgstr "Выберите, какую Ñтратегию Git иÑпользовать при получении проекта."
+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 "CiCdAnalytics|Date range: %{range}"
msgstr "Диапазон дат: %{range}"
@@ -9126,12 +9325,12 @@ msgstr "в ожидании"
msgid "CiStatus|running"
msgstr "выполнÑетÑÑ"
+msgid "CiVariables|Cancel"
+msgstr ""
+
msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr "Ðевозможно иÑпользовать маÑкируемую переменную Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ значением"
-msgid "CiVariables|Clear inputs"
-msgstr ""
-
msgid "CiVariables|Environments"
msgstr "ОкружениÑ"
@@ -9159,6 +9358,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr "ЗащищеннаÑ"
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr "Удалить переменную"
@@ -9944,6 +10146,9 @@ 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 ""
@@ -10235,7 +10440,7 @@ msgstr "SSL-Ñертификат Kubernetes, иÑпользуемый Ð´Ð»Ñ Ð°Ñ
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "URL, иÑпользуемый Ð´Ð»Ñ Ð´Ð¾Ñтупа к API Kubernetes."
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10629,9 +10834,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "Сравнить верÑии"
-
msgid "Compare branches and continue"
msgstr ""
@@ -10644,6 +10846,9 @@ msgstr "Сравнить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ Ð¿Ð¾Ñледним коммито
msgid "Compare changes with the merge request target branch"
msgstr "Сравнить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ Ñ†ÐµÐ»ÐµÐ²Ð¾Ð¹ веткой запроÑа на ÑлиÑние"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10713,12 +10918,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10827,9 +11041,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10848,9 +11077,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "КонфиденциальноÑÑ‚ÑŒ"
-msgid "Configuration"
-msgstr "КонфигурациÑ"
-
msgid "Configuration help"
msgstr ""
@@ -11478,6 +11704,9 @@ msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ удалить репозиторий %{titl
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "Ð’Ñ‹ можете добавить образ в Ñтот рееÑÑ‚Ñ€ контвейнеров при помощи данных команд:"
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11520,12 +11749,21 @@ msgstr "УчаÑтие"
msgid "Contribution Analytics"
msgstr "Ðналитика вкладов"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11541,6 +11779,9 @@ 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 ""
@@ -11586,7 +11827,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11607,8 +11851,8 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
-msgstr "УчаÑтники"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "Управление адреÑами Ñлектронной почты, ÑвÑзанными Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑью"
@@ -11679,6 +11923,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr "Копировать SHA-Ñумму коммита"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr "Скопировать окружение"
@@ -11925,7 +12172,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12114,6 +12361,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr "Создайте или импортируйте Ñвой первый проект"
@@ -12363,9 +12613,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr "Создана ветка и Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние Ð´Ð»Ñ Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ñтого обÑуждениÑ."
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "Создана ветка %{branch_name} и Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние Ð´Ð»Ñ Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ñтого обÑуждениÑ."
@@ -12573,6 +12820,9 @@ 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 ""
@@ -12672,8 +12922,8 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "ОбÑуждение, первым добавленное в Ñтап"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
-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 "Задача впервые упомÑнута в коммите"
@@ -12841,9 +13091,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13757,6 +14004,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13799,6 +14049,9 @@ msgstr ""
msgid "Delete row"
msgstr "Удалить Ñтроку"
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14566,6 +14819,9 @@ msgstr "уÑпешно"
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14669,12 +14925,15 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "Ðе удалоÑÑŒ Ñоздать новую диÑкуÑÑию. ПожалуйÑта, попробуйте ещё раз."
-msgid "DesignManagement|Could not update discussion. Please try again."
-msgstr "Ðе удалоÑÑŒ обновить обÑуждение. ПожалуйÑта, попробуйте ещё раз."
+msgid "DesignManagement|Could not delete comment. Please try again."
+msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
msgstr ""
+msgid "DesignManagement|Could not update discussion. Please try again."
+msgstr "Ðе удалоÑÑŒ обновить обÑуждение. ПожалуйÑта, попробуйте ещё раз."
+
msgid "DesignManagement|Deselect all"
msgstr "Отменить вÑе"
@@ -14777,6 +15036,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14972,6 +15234,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15131,9 +15396,6 @@ msgstr "Discord УведомлениÑ"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr "Откройте Ð´Ð»Ñ ÑÐµÐ±Ñ GitLab Geo"
@@ -15573,6 +15835,9 @@ msgstr ""
msgid "Edit description"
msgstr "Изменить опиÑание"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15597,6 +15862,9 @@ msgstr "Изменить идентификацию Ð´Ð»Ñ %{user_name}"
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15615,9 +15883,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16074,6 +16348,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "Введите номер"
@@ -16119,8 +16396,8 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
-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 ""
@@ -16137,6 +16414,9 @@ 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 ""
@@ -16431,6 +16711,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "Цель не может быть найдена."
@@ -16542,6 +16825,9 @@ 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 ""
@@ -16830,6 +17116,9 @@ 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 ""
@@ -17110,6 +17399,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17134,6 +17426,9 @@ 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 "ИÑÐºÐ»ÑŽÑ‡Ð°Ñ ÐºÐ¾Ð¼Ð¼Ð¸Ñ‚Ñ‹-ÑлиÑниÑ. Ограничено до %{limit} коммитов."
@@ -17335,6 +17630,9 @@ 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 ""
@@ -17353,6 +17651,9 @@ 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 ""
@@ -17929,9 +18230,6 @@ msgstr "Фев."
msgid "February"
msgstr "Февраль"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18055,6 +18353,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18211,9 +18512,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18355,9 +18653,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19174,13 +19469,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19231,6 +19535,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19255,6 +19562,12 @@ msgstr ""
msgid "GitLab commit"
msgstr "Коммит GitLab"
+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 ""
@@ -19270,9 +19583,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19321,13 +19631,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19421,12 +19724,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19466,6 +19775,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19478,13 +19790,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19502,7 +19814,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19556,6 +19868,9 @@ msgstr "ДоÑтуп предоÑтавлен %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr "Ð”Ð°Ð½Ð½Ð°Ñ Ñ†ÐµÐ»ÑŒ уже ÑвÑзана Ñ Ñтой целью."
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19628,6 +19943,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19682,15 +20000,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19907,6 +20219,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 "Готово"
@@ -20096,6 +20432,9 @@ msgstr "Ðазвание группы (вашей организации)"
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr "Содержание обзора группы"
@@ -20447,6 +20786,9 @@ 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 ""
@@ -20705,6 +21047,9 @@ 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 "Группы также могут быть вложены путем ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ %{linkStart}подгрупп%{linkEnd}."
@@ -20720,6 +21065,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21100,6 +21451,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "Привет, %{username}!"
@@ -21447,6 +21801,9 @@ 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 ""
@@ -21546,6 +21903,9 @@ 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 ""
@@ -21588,15 +21948,24 @@ msgstr "ЕÑли отмечено, владельцы групп могут уп
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "ЕÑли отмечено, новые членÑтва в группах и Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ добавлÑÑ‚ÑŒ только через Ñинхронизацию LDAP"
+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 ""
@@ -21657,7 +22026,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21887,6 +22256,9 @@ msgstr "Ðе удалоÑÑŒ импортировать проект"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22293,7 +22665,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22956,12 +23328,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23137,10 +23515,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23158,6 +23539,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23446,7 +23830,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23575,9 +23959,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23849,6 +24230,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr "ОбÑуждение уже было продвинуто до цели."
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24074,6 +24461,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24611,9 +25001,24 @@ msgstr "Задача была перезапущена"
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "ЗаданиÑ"
@@ -25306,6 +25711,15 @@ 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 ""
@@ -25387,6 +25801,9 @@ 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 ""
@@ -25396,6 +25813,9 @@ 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 ""
@@ -25411,9 +25831,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25429,6 +25846,9 @@ msgstr "Выйти из режима админиÑтратора"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "Выйти из режима редактированиÑ? Ð’Ñе неÑохраненные Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ потерÑны."
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Покинуть группу"
@@ -25690,6 +26110,13 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Line changes"
msgstr ""
@@ -25717,6 +26144,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25810,9 +26240,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25855,6 +26282,9 @@ 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 ""
@@ -25894,6 +26324,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr "Блокировка членÑтва в Ñинхронизации LDAP"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25912,9 +26345,6 @@ msgstr ""
msgid "Locked"
msgstr "Заблокировано"
-msgid "Locked Files"
-msgstr "Заблокированные файлы"
-
msgid "Locked by %{fileLockUserName}"
msgstr "Заблокировано %{fileLockUserName}"
@@ -25984,9 +26414,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "СЛИТО"
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26023,10 +26450,7 @@ msgstr "Показать только изменениÑ"
msgid "MRDiff|Show full file"
msgstr "Показать веÑÑŒ файл"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26518,6 +26942,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr "МакÑимальный размер отправки (Мбайт)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26599,12 +27026,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26829,18 +27265,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26913,9 +27340,6 @@ msgstr "ЗапроÑÑ‹ на ÑлиÑние- Ñто меÑто, где можно
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26928,6 +27352,27 @@ 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 "Коммит в ветку иÑточника"
@@ -27542,6 +27987,9 @@ msgstr[3] "Этапы"
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27722,6 +28170,12 @@ msgstr ""
msgid "Minutes"
msgstr "Минуты"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr "Ðаправление зеркалированиÑ"
@@ -27734,6 +28188,9 @@ msgstr "Зеркалировать репозиторий"
msgid "Mirror settings are only available to GitLab administrators."
msgstr "ÐаÑтройки Ð·ÐµÑ€ÐºÐ°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð¾Ñтупны только админиÑтраторам GitLab."
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27794,31 +28251,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28164,6 +28636,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "ИмÑ, теги, логотип"
@@ -28212,10 +28687,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28330,9 +28811,6 @@ msgstr ""
msgid "New Snippet"
msgstr "Ðовый Ñниппет"
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28420,9 +28898,6 @@ msgstr ""
msgid "New password"
msgstr "Ðовый пароль"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "Ðовый проект"
@@ -28777,6 +29252,15 @@ 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 ""
@@ -28862,13 +29346,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29178,12 +29665,24 @@ 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|%{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 ""
@@ -29232,9 +29731,18 @@ 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 ""
@@ -29262,9 +29770,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29301,6 +29806,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29310,6 +29818,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29322,6 +29833,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29800,6 +30314,9 @@ 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 ""
@@ -29869,9 +30386,6 @@ msgstr "ЧаÑовой поÑÑ"
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30167,28 +30681,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30993,6 +31513,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31182,9 +31705,6 @@ msgstr ""
msgid "Pick a name"
msgstr "Выберите имÑ"
-msgid "Pin code"
-msgstr "Пин-код"
-
msgid "Pipeline"
msgstr "Ð¡Ð±Ð¾Ñ€Ð¾Ñ‡Ð½Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ"
@@ -31383,6 +31903,9 @@ 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 ""
@@ -31608,6 +32131,9 @@ 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 "ÐаÑтройки Ñборочных линий Ð´Ð»Ñ '%{project_name}' были уÑпешно обновлены."
@@ -31659,9 +32185,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31707,6 +32230,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31758,7 +32287,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr "Редактор Ñборочных линий"
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31767,6 +32296,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31803,13 +32335,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31839,6 +32371,12 @@ 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 "ИÑпользуйте шаблон %{codeStart}.gitlab-ci.yml%{codeEnd}, чтобы изучить, как работает CI/CD."
@@ -31860,6 +32398,9 @@ msgstr "ПроÑмотреть объединённый YAML"
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 ""
@@ -31869,6 +32410,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32184,6 +32728,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "ПожалуйÑта, введите неотрицательное чиÑло"
@@ -32205,6 +32752,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32265,8 +32815,8 @@ msgstr "ПожалуйÑта, выберите"
msgid "Please select a Jira project"
msgstr "ПожалуйÑта, выберите проект Jira"
-msgid "Please select a country"
-msgstr "ПожалуйÑта, выберите Ñтрану"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr ""
@@ -32619,6 +33169,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32688,88 +33241,31 @@ msgstr ""
msgid "Proceed"
msgstr "Продолжить"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32778,34 +33274,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32814,24 +33313,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32844,22 +33337,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32868,70 +33370,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33099,6 +33604,12 @@ msgstr "Отключить"
msgid "Profiles|Disconnect %{provider}"
msgstr "Отключить %{provider}"
+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|Do not show on profile"
msgstr "Ðе показывать в профиле"
@@ -33348,7 +33859,7 @@ msgstr "Ð’Ñ‹ должны передать право ÑобÑтвенноÑти
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Перед удалением учётной запиÑи, вам необходимо передать право Ð²Ð»Ð°Ð´ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ удалить Ñти группы."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33522,6 +34033,9 @@ msgstr "УчаÑтники проекта"
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Ð˜Ð¼Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð°"
@@ -33534,6 +34048,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33561,6 +34078,9 @@ 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 ""
@@ -33657,9 +34177,21 @@ msgstr "ID проекта: %{project_id}"
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 ""
@@ -33672,6 +34204,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33714,8 +34249,11 @@ 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 "ProjectSelect| or group"
-msgstr "или группа"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
msgid "ProjectSelect|No matching results"
msgstr ""
@@ -33729,9 +34267,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33861,9 +34396,6 @@ msgstr "Дополнительные параметры, влиÑющие на Ñ
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr "Разрешать"
@@ -34014,9 +34546,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr "ВнутреннÑÑ"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr "ОбÑуждениÑ"
@@ -34059,9 +34588,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr "ÐŸÑ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ ÑлиÑнию"
@@ -34098,9 +34624,6 @@ msgstr "Pages"
msgid "ProjectSettings|Pages for project documentation."
msgstr "Страницы Ð´Ð»Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ð¸ проекта."
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "Сборочные линии должны уÑпешно выполнитьÑÑ"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34143,10 +34666,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr "ПоиÑк по тегу"
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34170,9 +34693,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr "Сниппеты"
@@ -34407,6 +34927,9 @@ msgstr "Проекты (%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34533,6 +35056,9 @@ 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 "Ðет доÑтупных опций импорта"
@@ -34548,6 +35074,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "ОпиÑание проекта %{tag_start}(необÑзательно)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34728,9 +35257,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34839,12 +35365,6 @@ msgstr "При большом количеÑтве обÑуждений Ñлож
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr "Предлагать пользователÑм загружать ключи SSH"
@@ -35016,9 +35536,29 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35028,10 +35568,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35040,15 +35592,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} будет доÑтупно Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ°Ð¼Ð¸. Ð’Ñ‹ уверены?"
@@ -35058,6 +35619,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35514,24 +36078,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr "ПеремеÑтить"
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr "Перемещение в процеÑÑе"
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35607,6 +36162,9 @@ 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] ""
@@ -35644,13 +36202,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr "РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ / Вход"
-msgid "Register Two-Factor Authenticator"
-msgstr "РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð´Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð¾Ð¹ аутентификации"
+msgid "Register a WebAuthn device"
+msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "ЗарегиÑтрируйте универÑальное двухфакторное (U2F) уÑтройÑтво"
+msgid "Register a one-time password authenticator"
+msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35743,6 +36301,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36692,15 +37253,21 @@ msgstr "Требование %{reference} было открыто повторн
msgid "Requirement %{reference} has been updated"
msgstr "Требование %{reference} было обновлено"
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr "Заголовок Ñ‚Ñ€ÐµÐ±Ð¾Ð²Ð°Ð½Ð¸Ñ Ð½Ðµ может Ñодержать больше %{limit} Ñимволов."
-
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] ""
@@ -36883,9 +37450,6 @@ msgstr ""
msgid "Resume"
msgstr "Продолжить"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr "Повторить"
@@ -37059,9 +37623,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37144,6 +37705,9 @@ 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|Administrator"
msgstr ""
@@ -37207,6 +37771,9 @@ 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 ""
@@ -37225,6 +37792,9 @@ 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 ""
@@ -37283,9 +37853,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37298,6 +37874,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37316,6 +37898,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37343,6 +37928,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37352,6 +37943,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37364,6 +37958,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37406,6 +38003,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37440,6 +38040,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37455,6 +38061,9 @@ 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 ""
@@ -37479,6 +38088,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37494,6 +38106,12 @@ 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 ""
@@ -37566,9 +38184,15 @@ 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 ""
@@ -37602,6 +38226,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37611,6 +38241,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37630,6 +38263,9 @@ msgstr[3] ""
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 runner has not run any jobs."
msgstr ""
@@ -37678,6 +38314,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37732,15 +38371,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "ВыполнÑетÑÑ"
@@ -37762,6 +38392,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr "SAML Ð´Ð»Ñ %{group_name}"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37786,9 +38419,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37918,16 +38548,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37969,9 +38602,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38442,24 +39081,27 @@ msgstr ""
msgid "Security"
msgstr "БезопаÑноÑÑ‚ÑŒ"
-msgid "Security & Compliance"
-msgstr "БезопаÑноÑÑ‚ÑŒ и комплаенÑ"
-
-msgid "Security Configuration"
-msgstr ""
-
msgid "Security Dashboard"
msgstr "Панель безопаÑноÑти"
msgid "Security Finding not found"
msgstr ""
-msgid "Security dashboard"
-msgstr "Панель безопаÑноÑти"
+msgid "Security Policy project already exists."
+msgstr ""
+
+msgid "Security and Compliance"
+msgstr ""
+
+msgid "Security capabilities"
+msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
msgstr ""
+msgid "Security dashboard"
+msgstr "Панель безопаÑноÑти"
+
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr "Отчет безопаÑноÑти уÑтарел. ПожалуйÑта, включите в Ñвою ветку поÑледние Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¸Ð· целевой ветки (%{targetBranchName})"
@@ -38586,7 +39228,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38700,6 +39342,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38805,9 +39450,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38898,6 +39552,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38919,6 +39576,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38928,6 +39588,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38994,7 +39657,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39072,6 +39735,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39549,6 +40215,9 @@ msgstr ""
msgid "Select labels"
msgstr "Выбрать метки"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39651,6 +40320,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39663,6 +40335,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39675,6 +40350,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39777,6 +40455,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39912,6 +40596,9 @@ 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 ""
@@ -39939,7 +40626,7 @@ msgstr "ÐаÑтроить интеграцию Ñ Jira"
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40192,6 +40879,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40358,9 +41048,6 @@ msgstr ""
msgid "Sign in"
msgstr "Вход"
-msgid "Sign in / Register"
-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 ""
@@ -40514,15 +41201,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40532,6 +41237,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40541,6 +41249,9 @@ 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 ""
@@ -40574,9 +41285,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40760,12 +41477,18 @@ 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 ""
@@ -41177,9 +41900,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41243,6 +41963,9 @@ msgstr "Защита от Ñпама и ботов"
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41492,6 +42215,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42137,16 +42863,22 @@ 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|Sync subscription request."
+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}."
@@ -42155,7 +42887,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42186,9 +42918,6 @@ msgstr "Пользователи Ñ Ñ€Ð¾Ð»ÑŒÑŽ Guest или те, кто не в
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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42231,9 +42960,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42384,9 +43110,27 @@ 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 ""
@@ -42797,10 +43541,10 @@ msgstr ""
msgid "Test"
msgstr "ТеÑÑ‚"
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42826,9 +43570,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42955,6 +43696,9 @@ 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 ""
@@ -43016,6 +43760,9 @@ msgstr "Трекер обÑуждений - Ñто меÑто, где можно
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr "Сервер Prometheus ответил Ñ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð¾Ð¼ \"bad request\". ПожалуйÑта, убедитеÑÑŒ, что запроÑÑ‹ верны и поддерживаютÑÑ Ð² вашей верÑии Prometheus. %{documentationLink}"
+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 ""
@@ -43058,9 +43805,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Соединение будет отключено через %{timeout}. Ð”Ð»Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸ÐµÐ², требующих больше времени, иÑпользуйте комбинацию clone/push."
@@ -43118,6 +43862,9 @@ msgstr "СпиÑок завиÑимоÑтей Ñодержит подробнуÑ
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "Задание Ñ€Ð°Ð·Ð²Ñ‘Ñ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð½Ð° %{environmentLink} не удалоÑÑŒ."
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr "Каталог уÑпешно Ñоздан."
@@ -43435,7 +44182,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43780,6 +44536,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43969,13 +44728,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44476,6 +45229,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44530,10 +45286,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44988,6 +45741,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45479,6 +46235,9 @@ 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 ""
@@ -45570,9 +46329,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45675,9 +46431,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr "Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ"
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr "Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ"
@@ -45723,12 +46476,6 @@ msgstr "Тип"
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr "УÑтройÑтва U2F (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr "URL"
@@ -45834,6 +46581,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr "Ðе удалоÑÑŒ найти проект Jira, из которого должны быть импортированы данные."
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45933,6 +46683,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45990,6 +46743,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46077,6 +46839,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46146,6 +46911,9 @@ msgstr "Обновите ваши URL-адреÑа из закладок, поÑ
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 "Обновите название Ñвоего проекта, теги, опиÑание и логотип."
@@ -46272,6 +47040,9 @@ msgstr ""
msgid "Usage statistics"
msgstr "СтатиÑтика иÑпользованиÑ"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46443,6 +47214,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46647,6 +47421,9 @@ 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 ""
@@ -46659,6 +47436,9 @@ 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 ""
@@ -46735,6 +47515,9 @@ 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 identity was successfully created."
msgstr "Идентификатор Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð±Ñ‹Ð» уÑпешно Ñоздан."
@@ -47161,6 +47944,9 @@ msgstr "Ðналитика потока ценноÑти поможет вам Ð
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47272,6 +48058,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr "Ð’Ñ€ÐµÐ¼Ñ Ñтапа (медиана)"
@@ -47416,6 +48205,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47447,9 +48239,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr "Увидеть подходÑщих утверждающих"
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "ПроÑмотреть опубликованный артефакт"
@@ -47656,6 +48445,69 @@ 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|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 ""
@@ -48046,12 +48898,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48103,9 +48949,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "Мы воÑпользуемÑÑ Ñтим, чтобы предоÑтавить вам нужные функции и информацию."
@@ -48247,6 +49090,9 @@ 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 ""
@@ -48512,6 +49358,13 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -48552,6 +49405,9 @@ msgstr "Кто будет иÑпользовать Ñту группу?"
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -48771,7 +49627,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48819,6 +49675,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48844,6 +49703,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48868,9 +49736,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48991,6 +49865,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49027,6 +49904,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49057,6 +49937,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr "Ðапишите опиÑание Ñтапа..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "Ðапишите Ñвои заметки к релизу или перетащите ваши файлы Ñюда…"
@@ -49460,9 +50343,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr "У Ð²Ð°Ñ ÐµÑ‰Ñ‘ нет зарегиÑтрированных уÑтройÑтв U2F."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49635,12 +50515,18 @@ 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 ""
@@ -49813,6 +50699,9 @@ 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 ""
@@ -49822,7 +50711,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49852,6 +50741,9 @@ 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 "Ваши Группы"
@@ -49876,6 +50768,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr "Ваши ключи SSH (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49921,6 +50816,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "Ваши Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (%{size})"
@@ -49930,9 +50828,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "Ваш браузер не поддерживает U2F. ПожалуйÑта, иÑпользуйте Google Chrome Desktop (верÑÐ¸Ñ 41 или новее)."
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49963,6 +50858,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50124,6 +51022,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50367,6 +51268,9 @@ 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 ""
@@ -50709,9 +51613,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "РаÑÑледуйте Ñту уÑзвимоÑÑ‚ÑŒ, вынеÑÑ Ð½Ð° обÑуждение"
@@ -50779,6 +51680,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50809,6 +51713,9 @@ 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 ""
@@ -51096,9 +52003,6 @@ msgstr[3] "файлов"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr "подпиÑан"
-
msgid "for"
msgstr ""
@@ -51412,10 +52316,16 @@ msgstr ""
msgid "manual"
msgstr "ручной"
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51477,6 +52387,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51492,6 +52480,12 @@ msgstr "Потребление %{metricsLinkStart} памÑти %{metricsLinkEnd
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "Потребление %{metricsLinkStart} памÑти %{metricsLinkEnd} оÑталоÑÑŒ %{emphasisStart} неизменным %{emphasisEnd} на %{memoryFrom}Мбайт"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51519,12 +52513,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr "Пароль Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ Ð½ÐµÐ´ÐµÐ¹Ñтвителен."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr "Одобрить"
@@ -51540,6 +52528,9 @@ 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 ""
@@ -51623,84 +52614,30 @@ msgstr[1] "Упоминает обÑуждениÑ"
msgstr[2] "Упоминает обÑуждениÑ"
msgstr[3] "Упоминает обÑуждениÑ"
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "СлиÑние не удалоÑÑŒ."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
+msgid "mrWidget|More information"
+msgstr "Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ"
-msgid "mrWidget|Merging! Take a deep breath and relax…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Merging! The changes are leaving the station…"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Merging! This is going to be great…"
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
-msgid "mrWidget|More information"
-msgstr "Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ"
-
-msgid "mrWidget|No users match the rule's criteria."
-msgstr ""
-
-msgid "mrWidget|Please restore it or use a different %{type} branch."
-msgstr ""
-
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "Готово к автоматичеÑкому ÑлиÑнию. ПопроÑите кого-нибудь Ñ Ð¿Ñ€Ð°Ð²Ð¾Ð¼ запиÑи в Ñтот репозиторий Ñделать ÑлиÑние данного запроÑа"
-
msgid "mrWidget|Refresh"
msgstr "Обновить"
@@ -51761,9 +52698,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51788,6 +52722,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/si_LK/gitlab.po b/locale/si_LK/gitlab.po
index 45819dd98d3..664bf5edd92 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr " %{start} සිට %{end}"
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "අවවà·à¶¯ %dක් හමුවිය:"
msgstr[1] "අවවà·à¶¯ %dක් හමුවිය:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr "තේරීම් %{count} කි"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}, සහ තවත් %{awardsListLength}"
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} ඒකà·à¶¶à¶¯à·Šà¶° කිරීමට à
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr "%{message}. ඔබගේ අවධà·à¶±à¶º ඉල්ලීම ඉවත් කෙරිණි."
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (ඉකුත්ය)"
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "සමූහ 1"
@@ -1813,9 +1833,6 @@ msgstr "යෙ.ක්â€à¶».මු."
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr "යෙ.ක්â€à¶».මු. උදව්"
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr "නව යෙදුමක් එක් කරන්න"
msgid "Add new directory"
msgstr "නව නà·à¶¸à·à·€à¶½à·’යක් යෙදීම"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr "පුද්ගලයෙක් එක්/ඉවත් කරන්න."
@@ -2515,6 +2538,9 @@ msgstr "අතිරේක විනà·à¶©à·’:"
msgid "Additional text"
msgstr "අතිරේක පෙළ"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr "සියළු ගිට්ලà·à¶¶à·Š"
msgid "All Members"
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 "සියළු à·à·à¶›à·"
@@ -4727,6 +4726,9 @@ 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 "මෙම ප්â€à¶»à·ƒà·Šà¶®à·à¶»à¶º පූරණය කිරීමේදී නොදන්න෠දà·à·‚යක් සිදු විය."
@@ -4736,6 +4738,123 @@ msgstr "නොදන්න෠දà·à·‚යක් සිදුවිය."
msgid "Analytics"
msgstr "විà·à·Šà¶½à·šà·‚ණ"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr "අනුමතයි"
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr "ඔබට ඒකà·à¶¶à¶¯à·Šà¶°à¶º සඳහ෠තà·à¶­à·Š කිරීමට වුවමනà·à¶¯?"
@@ -5317,6 +5469,9 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr "ඔබට %{name} මà·à¶šà·“මට වුවමන෠ද?"
+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 "ඔබට මෙම %{commentType} මà·à¶šà·“මට වුවමන෠ද?"
@@ -5668,7 +5823,7 @@ msgstr[1] "ගොනු %d ක් අමුණමින්"
msgid "Attaching the file failed."
msgstr "ගොනුව ඇමිණීමට අසමත්!."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr "වේගවත් කේත සමà·à¶½à·à¶ à¶±"
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr "තනි පරිà·à·“ලකයින්ට à·ƒà·à¶¸à¶¯à· නොමිලේ විà·à·šà·‚à·à¶‚ග"
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr "නොමිලේ ස්ථිතික අඩවි ඇතුළත්ය"
-msgid "BillingPlans|Learn more"
-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 "අපගේ %{faq_link} කියවීමෙන් එක් එක් à·ƒà·à¶½à·ƒà·”ම ගà·à¶± තව දà·à¶±à¶œà¶±à·Šà¶±, හෝ දවස් 30 ක නොමිලේ GitLab.com අල්ටිමේට් නà·à·„à·à·ƒà·”මක් අරඹන්න."
@@ -6585,27 +6743,9 @@ msgstr "උත්à·à·Šâ€à¶»à·šà¶«à·’ය"
msgid "BillingPlan|Upgrade for free"
msgstr "නොමිලේ උත්à·à·Šâ€à¶»à·šà¶«à·’ය"
-msgid "Billings|%{planName} plan"
-msgstr "%{planName} à·ƒà·à¶½à·ƒà·”ම"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr "බිට්බකට් ආයà·à¶­à¶º"
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+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 "නොදන්න෠දà·à·‚යක් සිදුවී ඇත. මෙම පිටුව නà·à·€à·”ම් කිරීමෙන් උත්සà·à·„ කරන්න."
@@ -8525,6 +8701,9 @@ 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 "නව සමූහයක් à·ƒà·à¶¯à¶±à·Šà¶±"
@@ -8534,18 +8713,15 @@ msgstr "ණය පතට ආකෘතිය පූරණයට අසමත් à
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "ණය පතට ආකෘතිය පූරණයට අසමත් විය: %{message}"
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "සංස්කරණය"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr "ඉකුත්වීම %{expirationMonth}/%{expirationYear}"
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "ඔබගේ ඇණවුම තහවුරුවට අසමත් විය! යළි උත්සà·à·„ කරන්න."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr ""
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr ""
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr "නම: %{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "පරිà·à·“ලකයින් ගණන"
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr "දින පරà·à·ƒà¶º: %{range}"
@@ -8810,10 +9001,10 @@ msgstr "රà·à¶³à·™à¶¸à·’න්"
msgid "CiStatus|running"
msgstr "ධà·à·€à¶±à¶ºà·š"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr "සම්පූර්ණයි"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "සංරචකය"
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr "වින්â€à¶ºà·à·ƒà¶º"
-
msgid "Configuration help"
msgstr "වින්â€à¶ºà·à·ƒà¶ºà¶§ උපකà·à¶»"
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr ""
msgid "Contributor"
msgstr "දà·à¶ºà¶šà¶ºà·"
-msgid "Contributors"
-msgstr "දà·à¶ºà¶šà¶ºà·’න්"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr ""
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr "පළමු ව්â€à¶ºà·à¶´à·˜à¶­à·’ය à·ƒà·à¶¯à¶±à·Šà¶± හ෠ආයà·à¶­à¶º"
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr "නවම්"
msgid "February"
msgstr "නවම්"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,14 +19089,23 @@ msgstr "à·€à·à¶»à·Šà¶­à· කිරීමේ කà·à¶½ පරà·à·ƒà¶º අංà¶
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "à·€à·à¶»à·Šà¶­à· කිරීමේ කà·à¶½ පරà·à·ƒà¶º තත්. %{minTimePeriod}-%{maxTimePeriod} අතර විය යුතුය."
+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 %{maxExcludedUsers} excluded users."
-msgstr "ඔබට බà·à·„à·à¶» කළ පුද්ගලයින් %{maxExcludedUsers} කට වඩ෠දà·à¶šà·Šà·€à·’ය නොහà·à¶šà·’ය."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr ""
@@ -18859,6 +19155,9 @@ msgstr "ගිට්ලà·à¶¶à·Š KAS"
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr "මෑත ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම්"
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr "සියළුම ගිට්ලà·à¶¶à·Š"
-msgid "GlobalSearch|group"
-msgstr "සමූහය"
-
msgid "GlobalSearch|in %{scope}"
msgstr "%{scope} තුළ"
-msgid "GlobalSearch|project"
-msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ය"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr "සමූහයේ නම (ඔබගේ සංවිධà·à¶±à¶º)"
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "ආයුබ෠%{username}!"
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ msgstr ""
msgid "IdentityVerification|We sent a new code to +%{phoneNumber}"
msgstr "නව කේතයක් +%{phoneNumber} වෙත යà·à·€à·’ණි"
+msgid "IdentityVerification|We've sent a verification code to %{email}"
+msgstr ""
+
msgid "IdentityVerification|We've sent a verification code to +%{phoneNumber}"
msgstr ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,8 +23434,8 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
-msgstr "à·€à·à¶»à¶¯à·’ රීතියකි"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr ""
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr "ගෙවන à·ƒà·à¶½à·ƒà·”ම් ගවේà·à¶±à¶º"
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr "අගුළු ලූ ගොනු"
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr "නව මුරපදය"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "නව ව්â€à¶ºà·à¶´à·˜à¶­à·’ය"
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 "ආයුබ෠%{username}!"
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr ""
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr "මà·à¶šà·“මට තිබෙන"
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "මà·à¶šà·“මට තිබෙන"
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr "රූප සටහන පෙරදසුන"
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
-msgstr "උපකරණ පුවරුවට යොදන්න"
-
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Instrument your application"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr "පà·à¶­à·’කඩෙහි නොපෙන්වන්න"
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ නම"
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ සොයන්න"
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ ගà·à¶±à·“මේදී යම් දෙයක් à·€à·à¶»à¶¯à·“ ඇත"
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr "මà·à¶­à·˜à¶šà·à·€à¶šà·Š සඳහ෠සොයන්න"
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ වින්â€à¶ºà·à·ƒà¶º"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr "ලියà·à¶´à¶¯à·’ංචිය"
msgid "Register / Sign In"
msgstr "ලියà·à¶´à¶¯à·’ංචිය / පිවිසෙන්න"
-msgid "Register Two-Factor Authenticator"
-msgstr "ද්වි-à·ƒà·à¶°à¶š සත්â€à¶ºà·à¶´à¶šà¶º සකසන්න"
+msgid "Register a WebAuthn device"
+msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,24 +38567,27 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr "ආරක්â€à·‚ණ උපකරණ පුවරුව"
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
-msgstr "ආරක්â€à·‚ණ උපකරණ පුවරුව"
+msgid "Security and Compliance"
+msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
+msgstr ""
+
+msgid "Security configuration"
msgstr ""
msgid "Security dashboard"
msgstr "ආරක්â€à·‚ණ උපකරණ පුවරුව"
-msgid "Security navigation"
-msgstr ""
-
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr "පිවිසෙන්න"
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr "තත්â€à·€ පරීක්â€à·‚à·à·€ ඉවත් කරනවà·
msgid "StatusCheck|Service name"
msgstr "සේවà·à·€à·š නම"
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr "තත්â€à·€à¶º පරීක්â€à·‚à·à·€"
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr "ඔබගේ දà·à¶ºà¶šà¶­à·Šâ€à·€à¶º"
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr "ඔබගේ දà·à¶ºà¶šà¶­à·Šà·€ විස්තර ඉක්මනින් සමමුහූර්ත වනු ඇත."
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr "ඔබගේ ව්â€à¶ºà·à¶´à·˜à¶­à·’යට ටෙරà·à·†à·à¶¸à·Š
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 "පෙළ à·à·›à¶½à·’ය"
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 "නà·à¶¸à·à·€à¶½à·’ය à·ƒà·à¶»à·Šà¶®à¶šà·€ à·ƒà·à¶¯à· ඇත."
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr "සුපිරික්සීම à·ƒà·à¶¯à· ඇත."
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 "මව් සමූහයේ දà·à¶±à¶§à¶¸à¶­à·Š උප සමූහයක් හ෠එම මà·à¶»à·Šà¶œà¶ºà¶¸ සහිත ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් ඇත."
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr "ට්විටර්:"
msgid "Two-Factor Authentication"
msgstr "ද්වි-à·ƒà·à¶°à¶š සත්â€à¶ºà·à¶´à¶±à¶º"
-msgid "Two-Factor Authentication code"
-msgstr "ද්වි-à·ƒà·à¶°à¶š සත්â€à¶ºà·à¶´à¶± කේතය"
-
msgid "Two-factor Authentication"
msgstr "ද්වි-à·ƒà·à¶°à¶š සත්â€à¶ºà·à¶´à¶±à¶º"
@@ -45191,12 +45932,6 @@ msgstr "වර්ගය"
msgid "Type to search"
msgstr "සෙවීමට ලියන්න"
-msgid "U2F Devices (%{length})"
-msgstr "U2F උපà·à¶‚ග (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "U2F ක්â€à¶»à·’ය෠කරන්නේ HTTPS-සබල වියමන අඩවි සමඟ පමණි. à·€à·à¶©à·’ විස්තර සඳහ෠පරිපà·à¶½à¶š අමතන්න."
-
msgid "URL"
msgstr "ඒ.ස.නි."
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr "දත්ත ආයà·à¶­à¶ºà¶§ ජිර෠ව්â€à¶ºà·à¶´à·˜à¶­à·’ය සොය෠ගà·à¶±à·“මට නොහà·à¶šà·’යි."
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr "අසීමිත"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr "භà·à·€à·’ත෠නොකළ"
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr "භà·à·€à·’ත සංඛ්â€à¶ºà·à¶½à·šà¶›à¶±"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr "උඩුගත කිරීම්"
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr "පරිà·à·“ලකයà·à¶œà·š අනන්â€à¶ºà¶­à·à·€à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ සෑදිණි."
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr "ප්â€à¶»à¶½à·šà¶›à¶±à¶º බලන්න"
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "අපට ප්â€à¶»à·à¶¸à·’තියස් සේවà·à¶¯à·à¶ºà¶šà¶º වෙත ළඟ෠වීමට නොහà·à¶šà·’යි. සේවà·à¶¯à·à¶ºà¶šà¶º නොපවතී හ෠වින්â€à¶ºà·à·ƒ විස්තර යà·à·€à¶­à·Šà¶šà·à¶½ කළ යුතුය."
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr "මෙම සමූහය භà·à·€à·’ත෠කරන්නේ කවà·
msgid "Why are you signing up? (optional)"
msgstr "ඔබ ලියà·à¶´à¶¯à·’ංචි වන්නේ ඇයි? (විකල්ප)"
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr "වස෠ඇත"
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr "ඔබ නව à·à·à¶›à·à·€à¶šà·Š සෑදීමට කà·à¶¸à¶­à·’ද?"
@@ -48511,6 +49377,9 @@ msgstr "අභ්â€à¶ºà¶±à·Šà¶­à¶» සටහනක් ලියන්න à·„à·
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "ඔබගේ නිකුතු සටහන් ලියන්න හ෠ගොනු මෙතà·à¶±à¶§ අදින්න…"
@@ -48912,9 +49781,6 @@ msgstr "පරිසරය යà·à·€à¶­à·Šà¶šà·à¶½ කිරීම සඳහà·
msgid "You do not have permissions to run the import."
msgstr "ඔබට ආයà·à¶­à¶º ධà·à·€à¶±à¶º කිරීමට අවසර නà·à¶­."
-msgid "You don't have any U2F devices registered yet."
-msgstr "ඔබ සතුව ලියà·à¶´à¶¯à·’ංචි කළ U2F උපà·à¶‚ග නà·à¶­."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ msgstr "ඔබගේ %{spammable_entity_type} අයà·à¶ à·’ත ලෙස à·„à¶
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 ""
@@ -49270,7 +50145,7 @@ msgstr "ඔබගේ CSV නිර්යà·à¶­à¶º ආරම්භ වී ඇත.
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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 "ඔබගේ සමූහය"
@@ -49324,6 +50202,9 @@ msgstr "ඔබගේ SSH යතුර මක෠ඇත"
msgid "Your SSH keys (%{count})"
msgstr "ඔබගේ SSH යතුරු (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "ඔබගේ කළ-යුතු ලේඛනය"
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr "ඔබගේ ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º à·ƒà·à¶»à·Šà¶®à¶šà¶ºà·’."
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "ඔබගේ යෙදුම් (%{size})"
@@ -49378,9 +50262,6 @@ msgstr "ඔබගේ බලයලත් යෙදුම්"
msgid "Your browser does not support iFrames"
msgstr "ඔබගේ අතිරික්සුව අයිෆ්රේම්ස් සඳහ෠සහය නොදක්වයි"
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "අතිරික්සුව U2F සඳහ෠සහය නොදක්වයි. ගූගල් ක්â€à¶»à·à¶¸à·Š à·€à·à¶©à¶­à¶½à¶º භà·à·€à·’ත෠කරන්න (අනුවà·à¶¯à¶º 41 හ෠නව)."
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr "ඔබගේ අදහස ඉවත දමනු ඇත."
msgid "Your commit email is used for web based operations, such as edits and merges."
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 "ද්වි-à·ƒà·à¶°à¶š සත්â€à¶ºà·à¶´à¶± යෙදුමක් ලියà·à¶´à¶¯à·’ංචියට ඔබගේ වත්මන් මුරපදය අවà·à·Šâ€à¶º වේ."
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr "IaC සුපිරික්සමින්"
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr "ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම සමඟ විසඳන්න
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "රහස් අනà·à·€à¶»à¶«à¶º"
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] "ගොනු"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr "අනුගමනය"
-
msgid "for"
msgstr "සදහà·"
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr "අතින්"
-msgid "math|Displaying this math block may cause performance issues on this page"
+msgid "math|Displaying this math block may cause performance issues on this page."
msgstr ""
-msgid "math|There was an error rendering this math block"
+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"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr "%{mergeError}."
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr "අනුමà·à¶­à·’ය වෛකල්පිතයි"
msgid "mrWidget|Approval password is invalid."
msgstr "අනුමත මුරපදය වලංගු නොවේ."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr "අනුමත"
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,84 +51998,30 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "ඒකà·à¶¶à¶¯à·Šà¶°à¶ºà¶§ අසමත් විය."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr "ඒකà·à¶¶à¶¯à·Šà¶° වෙමින්! කරුණà·à¶šà¶», බෙර වයන්න…"
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr "ඒකà·à¶¶à¶¯à·Šà¶° වෙමින්! සියල්ල හොඳයි…"
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
+msgid "mrWidget|More information"
+msgstr "තව තොරතුරු"
-msgid "mrWidget|Merging! The changes are leaving the station…"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Merging! This is going to be great…"
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "ඒකà·à¶¶à¶¯à·Šà¶° වෙමින්…"
-
-msgid "mrWidget|More information"
-msgstr "තව තොරතුරු"
-
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "ස්වයංක්â€à¶»à·“යව ඒකà·à¶¶à¶¯à·Šà¶° වීමට සූදà·à¶±à¶¸à·Š. ඉල්ලීම ඒකà·à¶¶à¶¯à·Šà¶° කිරීමට මෙම කà·à·‚්ඨයට ලිවීමේ ප්â€à¶»à·€à·šà·à¶º ඇති යමෙකුගෙන් අසන්න"
-
msgid "mrWidget|Refresh"
msgstr "නà·à·€à·”ම් කරන්න"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr "වලංගු IPv4 à·„à· IPv6 ලිපිනයක් විය යà
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr "ආරම්භයෙන් පසු විය යුතුය"
diff --git a/locale/sk_SK/gitlab.po b/locale/sk_SK/gitlab.po
index c001a05b425..0daa397e003 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -566,6 +566,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -615,6 +622,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -622,6 +636,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -812,6 +832,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1013,6 +1036,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1028,9 +1054,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1168,6 +1191,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1446,6 +1472,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1750,13 +1779,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -2089,9 +2111,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2506,9 +2525,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2530,6 +2546,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2539,6 +2558,9 @@ 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 ""
@@ -2653,6 +2675,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2791,6 +2816,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3970,40 +3998,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4375,6 +4373,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -5007,6 +5008,9 @@ 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 ""
@@ -5016,6 +5020,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5094,13 +5215,28 @@ 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|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."
+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."
@@ -5249,12 +5385,18 @@ 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 ""
@@ -5509,6 +5651,13 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5521,6 +5670,20 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5596,9 +5759,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5611,6 +5771,9 @@ 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 ""
@@ -5968,7 +6131,7 @@ msgstr[3] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6224,9 +6387,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6239,9 +6399,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6251,9 +6408,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6635,6 +6801,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6662,9 +6831,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6734,6 +6900,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6749,9 +6918,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6887,27 +7053,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6917,9 +7065,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7062,6 +7207,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7290,15 +7438,27 @@ msgstr[3] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7311,9 +7471,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7431,9 +7588,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7452,6 +7606,15 @@ 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 ""
@@ -7482,10 +7645,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7527,6 +7693,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8296,6 +8465,15 @@ 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 ""
@@ -8413,6 +8591,9 @@ 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 ""
@@ -8799,6 +8980,9 @@ 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 ""
@@ -8841,6 +9025,9 @@ 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 ""
@@ -8850,16 +9037,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8886,6 +9070,9 @@ 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 ""
@@ -8904,6 +9091,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8922,6 +9112,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9042,12 +9235,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9126,10 +9325,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9159,6 +9358,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9944,6 +10146,9 @@ 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 ""
@@ -10235,7 +10440,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10629,9 +10834,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10644,6 +10846,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10713,12 +10918,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10827,9 +11041,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10848,9 +11077,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11478,6 +11704,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11520,12 +11749,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11541,6 +11779,9 @@ 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 ""
@@ -11586,7 +11827,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11607,7 +11851,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11679,6 +11923,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11925,7 +12172,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12114,6 +12361,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12363,9 +12613,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12573,6 +12820,9 @@ 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 ""
@@ -12672,7 +12922,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12841,9 +13091,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13757,6 +14004,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13799,6 +14049,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14566,6 +14819,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14669,10 +14925,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14777,6 +15036,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14972,6 +15234,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15131,9 +15396,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15573,6 +15835,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15597,6 +15862,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15615,9 +15883,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16074,6 +16348,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16119,7 +16396,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16137,6 +16414,9 @@ 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 ""
@@ -16431,6 +16711,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16542,6 +16825,9 @@ 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 ""
@@ -16830,6 +17116,9 @@ 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 ""
@@ -17110,6 +17399,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17134,6 +17426,9 @@ 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 ""
@@ -17335,6 +17630,9 @@ 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 ""
@@ -17353,6 +17651,9 @@ 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 ""
@@ -17929,9 +18230,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18055,6 +18353,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18211,9 +18512,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18355,9 +18653,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19174,13 +19469,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19231,6 +19535,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19255,6 +19562,12 @@ 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 ""
@@ -19270,9 +19583,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19321,13 +19631,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19421,12 +19724,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19466,6 +19775,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19478,13 +19790,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19502,7 +19814,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19556,6 +19868,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19628,6 +19943,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19682,15 +20000,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19907,6 +20219,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20096,6 +20432,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20447,6 +20786,9 @@ 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 ""
@@ -20705,6 +21047,9 @@ 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 ""
@@ -20720,6 +21065,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21100,6 +21451,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21447,6 +21801,9 @@ 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 ""
@@ -21546,6 +21903,9 @@ 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 ""
@@ -21588,15 +21948,24 @@ 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 ""
@@ -21657,7 +22026,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21887,6 +22256,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22293,7 +22665,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22956,12 +23328,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23137,10 +23515,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23158,6 +23539,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23446,7 +23830,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23575,9 +23959,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23849,6 +24230,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24074,6 +24461,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24611,9 +25001,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25306,6 +25711,15 @@ 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 ""
@@ -25387,6 +25801,9 @@ 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 ""
@@ -25396,6 +25813,9 @@ 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 ""
@@ -25411,9 +25831,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25429,6 +25846,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25690,6 +26110,13 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Line changes"
msgstr ""
@@ -25717,6 +26144,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25810,9 +26240,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25855,6 +26282,9 @@ 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 ""
@@ -25894,6 +26324,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25912,9 +26345,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25984,9 +26414,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26023,10 +26450,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26518,6 +26942,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26599,12 +27026,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26829,18 +27265,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26913,9 +27340,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26928,6 +27352,27 @@ 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 ""
@@ -27542,6 +27987,9 @@ msgstr[3] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27722,6 +28170,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27734,6 +28188,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27794,31 +28251,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28164,6 +28636,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28212,10 +28687,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28330,9 +28811,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28420,9 +28898,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28777,6 +29252,15 @@ 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 ""
@@ -28862,13 +29346,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29178,12 +29665,24 @@ 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|%{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 ""
@@ -29232,9 +29731,18 @@ 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 ""
@@ -29262,9 +29770,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29301,6 +29806,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29310,6 +29818,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29322,6 +29833,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29800,6 +30314,9 @@ 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 ""
@@ -29869,9 +30386,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30167,28 +30681,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30993,6 +31513,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31182,9 +31705,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31383,6 +31903,9 @@ 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 ""
@@ -31608,6 +32131,9 @@ 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 ""
@@ -31659,9 +32185,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31707,6 +32230,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31758,7 +32287,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31767,6 +32296,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31803,13 +32335,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31839,6 +32371,12 @@ 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 ""
@@ -31860,6 +32398,9 @@ 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 ""
@@ -31869,6 +32410,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32184,6 +32728,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32205,6 +32752,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32265,7 +32815,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32619,6 +33169,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32688,88 +33241,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32778,34 +33274,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32814,24 +33313,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32844,22 +33337,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32868,70 +33370,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33099,6 +33604,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33348,7 +33859,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33522,6 +34033,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33534,6 +34048,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33561,6 +34078,9 @@ 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 ""
@@ -33657,9 +34177,21 @@ 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 ""
@@ -33672,6 +34204,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33714,7 +34249,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33729,9 +34267,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33861,9 +34396,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34014,9 +34546,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34059,9 +34588,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34098,9 +34624,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34143,10 +34666,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34170,9 +34693,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34407,6 +34927,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34533,6 +35056,9 @@ 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 ""
@@ -34548,6 +35074,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34728,9 +35257,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34839,12 +35365,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35016,9 +35536,29 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35028,10 +35568,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35040,15 +35592,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35058,6 +35619,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35514,24 +36078,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35607,6 +36162,9 @@ 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] ""
@@ -35644,13 +36202,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35743,6 +36301,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36692,15 +37253,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36883,9 +37450,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37059,9 +37623,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37144,6 +37705,9 @@ 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|Administrator"
msgstr ""
@@ -37207,6 +37771,9 @@ 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 ""
@@ -37225,6 +37792,9 @@ 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 ""
@@ -37283,9 +37853,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37298,6 +37874,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37316,6 +37898,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37343,6 +37928,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37352,6 +37943,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37364,6 +37958,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37406,6 +38003,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37440,6 +38040,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37455,6 +38061,9 @@ 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 ""
@@ -37479,6 +38088,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37494,6 +38106,12 @@ 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 ""
@@ -37566,9 +38184,15 @@ 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 ""
@@ -37602,6 +38226,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37611,6 +38241,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37630,6 +38263,9 @@ msgstr[3] ""
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 runner has not run any jobs."
msgstr ""
@@ -37678,6 +38314,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37732,15 +38371,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37762,6 +38392,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37786,9 +38419,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37918,16 +38548,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37969,9 +38602,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38442,22 +39081,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
msgstr ""
-msgid "Security dashboard"
+msgid "Security configuration"
msgstr ""
-msgid "Security navigation"
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38586,7 +39228,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38700,6 +39342,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38805,9 +39450,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38898,6 +39552,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38919,6 +39576,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38928,6 +39588,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38994,7 +39657,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39072,6 +39735,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39549,6 +40215,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39651,6 +40320,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39663,6 +40335,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39675,6 +40350,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39777,6 +40455,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39912,6 +40596,9 @@ 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 ""
@@ -39939,7 +40626,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40192,6 +40879,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40358,9 +41048,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40514,15 +41201,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40532,6 +41237,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40541,6 +41249,9 @@ 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 ""
@@ -40574,9 +41285,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40760,12 +41477,18 @@ 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 ""
@@ -41177,9 +41900,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41243,6 +41963,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41492,6 +42215,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42137,16 +42863,22 @@ 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|Sync subscription request."
+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}."
@@ -42155,7 +42887,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42186,9 +42918,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42231,9 +42960,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42384,9 +43110,27 @@ 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 ""
@@ -42797,10 +43541,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42826,9 +43570,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42955,6 +43696,9 @@ 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 ""
@@ -43016,6 +43760,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43058,9 +43805,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -43118,6 +43862,9 @@ 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 ""
@@ -43435,7 +44182,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43780,6 +44536,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43969,13 +44728,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44476,6 +45229,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44530,10 +45286,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44988,6 +45741,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45479,6 +46235,9 @@ 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 ""
@@ -45570,9 +46329,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45675,9 +46431,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45723,12 +46476,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45834,6 +46581,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45933,6 +46683,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45990,6 +46743,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46077,6 +46839,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46146,6 +46911,9 @@ 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 ""
@@ -46272,6 +47040,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46443,6 +47214,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46647,6 +47421,9 @@ 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 ""
@@ -46659,6 +47436,9 @@ 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 ""
@@ -46735,6 +47515,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47161,6 +47944,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47272,6 +48058,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47416,6 +48205,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47447,9 +48239,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47656,6 +48445,69 @@ 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|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 ""
@@ -48046,12 +48898,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48103,9 +48949,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48247,6 +49090,9 @@ 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 ""
@@ -48512,6 +49358,13 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -48552,6 +49405,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48771,7 +49627,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48819,6 +49675,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48844,6 +49703,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48868,9 +49736,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48991,6 +49865,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49027,6 +49904,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49057,6 +49937,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49460,9 +50343,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49635,12 +50515,18 @@ 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 ""
@@ -49813,6 +50699,9 @@ 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 ""
@@ -49822,7 +50711,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49852,6 +50741,9 @@ 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 ""
@@ -49876,6 +50768,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49921,6 +50816,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49930,9 +50828,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49963,6 +50858,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50124,6 +51022,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50367,6 +51268,9 @@ 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 ""
@@ -50709,9 +51613,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50779,6 +51680,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50809,6 +51713,9 @@ 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 ""
@@ -51096,9 +52003,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51412,10 +52316,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51477,6 +52387,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51492,6 +52480,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51519,12 +52513,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51540,6 +52528,9 @@ 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 ""
@@ -51623,82 +52614,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51761,9 +52698,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51788,6 +52722,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/sl_SI/gitlab.po b/locale/sl_SI/gitlab.po
index 60785f2b231..099347aedda 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -566,6 +566,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -615,6 +622,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -622,6 +636,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -812,6 +832,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -1013,6 +1036,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -1028,9 +1054,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1168,6 +1191,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1446,6 +1472,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1750,13 +1779,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -2089,9 +2111,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2506,9 +2525,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2530,6 +2546,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2539,6 +2558,9 @@ 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 ""
@@ -2653,6 +2675,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2791,6 +2816,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3970,40 +3998,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4375,6 +4373,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -5007,6 +5008,9 @@ 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 ""
@@ -5016,6 +5020,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5094,13 +5215,28 @@ 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|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."
+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."
@@ -5249,12 +5385,18 @@ 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 ""
@@ -5509,6 +5651,13 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5521,6 +5670,20 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5596,9 +5759,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5611,6 +5771,9 @@ 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 ""
@@ -5968,7 +6131,7 @@ msgstr[3] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6224,9 +6387,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6239,9 +6399,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6251,9 +6408,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6635,6 +6801,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6662,9 +6831,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6734,6 +6900,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6749,9 +6918,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6887,27 +7053,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6917,9 +7065,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7062,6 +7207,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7290,15 +7438,27 @@ msgstr[3] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7311,9 +7471,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7431,9 +7588,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7452,6 +7606,15 @@ 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 ""
@@ -7482,10 +7645,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7527,6 +7693,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8296,6 +8465,15 @@ 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 ""
@@ -8413,6 +8591,9 @@ 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 ""
@@ -8799,6 +8980,9 @@ 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 ""
@@ -8841,6 +9025,9 @@ 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 ""
@@ -8850,16 +9037,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8886,6 +9070,9 @@ 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 ""
@@ -8904,6 +9091,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8922,6 +9112,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -9042,12 +9235,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -9126,10 +9325,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9159,6 +9358,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9944,6 +10146,9 @@ 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 ""
@@ -10235,7 +10440,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10629,9 +10834,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10644,6 +10846,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10713,12 +10918,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10827,9 +11041,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10848,9 +11077,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11478,6 +11704,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11520,12 +11749,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11541,6 +11779,9 @@ 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 ""
@@ -11586,7 +11827,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11607,7 +11851,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11679,6 +11923,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11925,7 +12172,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -12114,6 +12361,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12363,9 +12613,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12573,6 +12820,9 @@ 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 ""
@@ -12672,7 +12922,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12841,9 +13091,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13757,6 +14004,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13799,6 +14049,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14566,6 +14819,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14669,10 +14925,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14777,6 +15036,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14972,6 +15234,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15131,9 +15396,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15573,6 +15835,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15597,6 +15862,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15615,9 +15883,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -16074,6 +16348,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -16119,7 +16396,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16137,6 +16414,9 @@ 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 ""
@@ -16431,6 +16711,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16542,6 +16825,9 @@ 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 ""
@@ -16830,6 +17116,9 @@ 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 ""
@@ -17110,6 +17399,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17134,6 +17426,9 @@ 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 ""
@@ -17335,6 +17630,9 @@ 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 ""
@@ -17353,6 +17651,9 @@ 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 ""
@@ -17929,9 +18230,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -18055,6 +18353,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18211,9 +18512,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18355,9 +18653,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -19174,13 +19469,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19231,6 +19535,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19255,6 +19562,12 @@ 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 ""
@@ -19270,9 +19583,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19321,13 +19631,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19421,12 +19724,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19466,6 +19775,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19478,13 +19790,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19502,7 +19814,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19556,6 +19868,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19628,6 +19943,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19682,15 +20000,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19907,6 +20219,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -20096,6 +20432,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20447,6 +20786,9 @@ 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 ""
@@ -20705,6 +21047,9 @@ 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 ""
@@ -20720,6 +21065,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -21100,6 +21451,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21447,6 +21801,9 @@ 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 ""
@@ -21546,6 +21903,9 @@ 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 ""
@@ -21588,15 +21948,24 @@ 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 ""
@@ -21657,7 +22026,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21887,6 +22256,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22293,7 +22665,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22956,12 +23328,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -23137,10 +23515,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -23158,6 +23539,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23446,7 +23830,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23575,9 +23959,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23849,6 +24230,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -24074,6 +24461,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24611,9 +25001,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25306,6 +25711,15 @@ 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 ""
@@ -25387,6 +25801,9 @@ 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 ""
@@ -25396,6 +25813,9 @@ 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 ""
@@ -25411,9 +25831,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25429,6 +25846,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25690,6 +26110,13 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Line changes"
msgstr ""
@@ -25717,6 +26144,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25810,9 +26240,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25855,6 +26282,9 @@ 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 ""
@@ -25894,6 +26324,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25912,9 +26345,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25984,9 +26414,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -26023,10 +26450,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26518,6 +26942,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26599,12 +27026,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26829,18 +27265,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26913,9 +27340,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26928,6 +27352,27 @@ 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 ""
@@ -27542,6 +27987,9 @@ msgstr[3] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27722,6 +28170,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27734,6 +28188,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27794,31 +28251,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28164,6 +28636,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28212,10 +28687,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28330,9 +28811,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28420,9 +28898,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28777,6 +29252,15 @@ 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 ""
@@ -28862,13 +29346,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29178,12 +29665,24 @@ 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|%{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 ""
@@ -29232,9 +29731,18 @@ 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 ""
@@ -29262,9 +29770,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29301,6 +29806,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29310,6 +29818,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29322,6 +29833,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29800,6 +30314,9 @@ 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 ""
@@ -29869,9 +30386,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30167,28 +30681,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30993,6 +31513,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -31182,9 +31705,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31383,6 +31903,9 @@ 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 ""
@@ -31608,6 +32131,9 @@ 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 ""
@@ -31659,9 +32185,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31707,6 +32230,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31758,7 +32287,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31767,6 +32296,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31803,13 +32335,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31839,6 +32371,12 @@ 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 ""
@@ -31860,6 +32398,9 @@ 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 ""
@@ -31869,6 +32410,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32184,6 +32728,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -32205,6 +32752,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32265,7 +32815,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32619,6 +33169,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32688,88 +33241,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32778,34 +33274,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32814,24 +33313,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32844,22 +33337,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32868,70 +33370,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -33099,6 +33604,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33348,7 +33859,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33522,6 +34033,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33534,6 +34048,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33561,6 +34078,9 @@ 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 ""
@@ -33657,9 +34177,21 @@ 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 ""
@@ -33672,6 +34204,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33714,7 +34249,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33729,9 +34267,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33861,9 +34396,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -34014,9 +34546,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -34059,9 +34588,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -34098,9 +34624,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -34143,10 +34666,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -34170,9 +34693,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34407,6 +34927,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34533,6 +35056,9 @@ 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 ""
@@ -34548,6 +35074,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34728,9 +35257,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34839,12 +35365,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -35016,9 +35536,29 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -35028,10 +35568,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35040,15 +35592,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -35058,6 +35619,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35514,24 +36078,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35607,6 +36162,9 @@ 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] ""
@@ -35644,13 +36202,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35743,6 +36301,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36692,15 +37253,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36883,9 +37450,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -37059,9 +37623,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37144,6 +37705,9 @@ 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|Administrator"
msgstr ""
@@ -37207,6 +37771,9 @@ 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 ""
@@ -37225,6 +37792,9 @@ 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 ""
@@ -37283,9 +37853,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37298,6 +37874,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37316,6 +37898,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37343,6 +37928,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37352,6 +37943,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37364,6 +37958,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37406,6 +38003,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37440,6 +38040,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37455,6 +38061,9 @@ 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 ""
@@ -37479,6 +38088,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37494,6 +38106,12 @@ 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 ""
@@ -37566,9 +38184,15 @@ 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 ""
@@ -37602,6 +38226,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37611,6 +38241,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37630,6 +38263,9 @@ msgstr[3] ""
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 runner has not run any jobs."
msgstr ""
@@ -37678,6 +38314,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37732,15 +38371,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37762,6 +38392,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37786,9 +38419,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37918,16 +38548,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37969,9 +38602,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38442,22 +39081,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Dashboard"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security Finding not found"
+msgid "Security capabilities"
msgstr ""
-msgid "Security dashboard"
+msgid "Security configuration"
msgstr ""
-msgid "Security navigation"
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38586,7 +39228,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38700,6 +39342,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38805,9 +39450,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38898,6 +39552,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38919,6 +39576,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38928,6 +39588,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38994,7 +39657,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39072,6 +39735,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39549,6 +40215,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39651,6 +40320,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39663,6 +40335,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39675,6 +40350,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39777,6 +40455,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39912,6 +40596,9 @@ 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 ""
@@ -39939,7 +40626,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40192,6 +40879,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40358,9 +41048,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40514,15 +41201,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40532,6 +41237,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40541,6 +41249,9 @@ 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 ""
@@ -40574,9 +41285,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40760,12 +41477,18 @@ 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 ""
@@ -41177,9 +41900,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41243,6 +41963,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41492,6 +42215,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42137,16 +42863,22 @@ 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|Sync subscription request."
+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}."
@@ -42155,7 +42887,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42186,9 +42918,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -42231,9 +42960,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42384,9 +43110,27 @@ 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 ""
@@ -42797,10 +43541,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42826,9 +43570,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42955,6 +43696,9 @@ 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 ""
@@ -43016,6 +43760,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -43058,9 +43805,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -43118,6 +43862,9 @@ 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 ""
@@ -43435,7 +44182,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43780,6 +44536,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43969,13 +44728,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44476,6 +45229,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44530,10 +45286,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44988,6 +45741,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45479,6 +46235,9 @@ 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 ""
@@ -45570,9 +46329,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45675,9 +46431,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45723,12 +46476,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45834,6 +46581,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45933,6 +46683,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45990,6 +46743,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46077,6 +46839,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46146,6 +46911,9 @@ 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 ""
@@ -46272,6 +47040,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46443,6 +47214,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46647,6 +47421,9 @@ 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 ""
@@ -46659,6 +47436,9 @@ 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 ""
@@ -46735,6 +47515,9 @@ 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 identity was successfully created."
msgstr ""
@@ -47161,6 +47944,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47272,6 +48058,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47416,6 +48205,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47447,9 +48239,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47656,6 +48445,69 @@ 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|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 ""
@@ -48046,12 +48898,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -48103,9 +48949,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -48247,6 +49090,9 @@ 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 ""
@@ -48512,6 +49358,13 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -48552,6 +49405,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48771,7 +49627,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48819,6 +49675,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48844,6 +49703,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48868,9 +49736,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48991,6 +49865,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -49027,6 +49904,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49057,6 +49937,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49460,9 +50343,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49635,12 +50515,18 @@ 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 ""
@@ -49813,6 +50699,9 @@ 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 ""
@@ -49822,7 +50711,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49852,6 +50741,9 @@ 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 ""
@@ -49876,6 +50768,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49921,6 +50816,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49930,9 +50828,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49963,6 +50858,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50124,6 +51022,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50367,6 +51268,9 @@ 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 ""
@@ -50709,9 +51613,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50779,6 +51680,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50809,6 +51713,9 @@ 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 ""
@@ -51096,9 +52003,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51412,10 +52316,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51477,6 +52387,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51492,6 +52480,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51519,12 +52513,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51540,6 +52528,9 @@ 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 ""
@@ -51623,82 +52614,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51761,9 +52698,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51788,6 +52722,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po
index 0fb1b4b93bb..6d90efea779 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/sr_CS/gitlab.po b/locale/sr_CS/gitlab.po
index ae3b91ea929..497f53b8471 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -496,6 +496,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -538,12 +544,24 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
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] ""
msgstr[2] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -721,6 +739,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -922,6 +943,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -937,9 +961,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1075,6 +1096,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1336,6 +1360,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1627,12 +1654,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1951,9 +1972,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2368,9 +2386,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2392,6 +2407,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2401,6 +2419,9 @@ 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 ""
@@ -2515,6 +2536,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2653,6 +2677,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3832,40 +3859,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4237,6 +4234,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4867,6 +4867,9 @@ 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 ""
@@ -4876,6 +4879,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4954,13 +5074,28 @@ 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|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."
+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."
@@ -5107,12 +5242,18 @@ 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 ""
@@ -5362,6 +5503,12 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5374,6 +5521,18 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+
+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] ""
+msgstr[2] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5449,9 +5608,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5464,6 +5620,9 @@ 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 ""
@@ -5818,7 +5977,7 @@ msgstr[2] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6073,9 +6232,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6088,9 +6244,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6100,9 +6253,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6484,6 +6646,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6511,9 +6676,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6583,6 +6745,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6598,9 +6763,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6736,27 +6898,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6766,9 +6910,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6910,6 +7051,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7135,15 +7279,27 @@ msgstr[2] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7156,9 +7312,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7276,9 +7429,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7297,6 +7447,15 @@ 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 ""
@@ -7327,10 +7486,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7372,6 +7534,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8140,6 +8305,15 @@ 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 ""
@@ -8257,6 +8431,9 @@ 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 ""
@@ -8641,6 +8818,9 @@ 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 ""
@@ -8683,6 +8863,9 @@ 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 ""
@@ -8692,16 +8875,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8728,6 +8908,9 @@ 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 ""
@@ -8746,6 +8929,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8764,6 +8950,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8884,12 +9073,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8968,10 +9163,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9001,6 +9196,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9784,6 +9982,9 @@ 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 ""
@@ -10075,7 +10276,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10468,9 +10669,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10483,6 +10681,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10552,12 +10753,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10666,9 +10876,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10687,9 +10912,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11314,6 +11536,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11356,12 +11581,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11377,6 +11611,9 @@ 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 ""
@@ -11422,7 +11659,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11443,7 +11683,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11515,6 +11755,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11761,7 +12004,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11950,6 +12193,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12199,9 +12445,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12409,6 +12652,9 @@ 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 ""
@@ -12508,7 +12754,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12676,9 +12922,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13591,6 +13834,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13633,6 +13879,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14392,6 +14641,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14494,10 +14746,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14602,6 +14857,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14797,6 +15055,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14953,9 +15214,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15394,6 +15652,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15418,6 +15679,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15436,9 +15700,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15895,6 +16165,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15940,7 +16213,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15958,6 +16231,9 @@ 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 ""
@@ -16252,6 +16528,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16363,6 +16642,9 @@ 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 ""
@@ -16651,6 +16933,9 @@ 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 ""
@@ -16930,6 +17215,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16954,6 +17242,9 @@ 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 ""
@@ -17155,6 +17446,9 @@ 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 ""
@@ -17173,6 +17467,9 @@ 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 ""
@@ -17746,9 +18043,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17872,6 +18166,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18028,9 +18325,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18172,9 +18466,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18988,13 +19279,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19045,6 +19345,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19069,6 +19372,12 @@ 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 ""
@@ -19084,9 +19393,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19135,12 +19441,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19234,12 +19534,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19279,6 +19585,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19291,13 +19600,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19315,7 +19624,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19369,6 +19678,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19441,6 +19753,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19495,15 +19810,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19720,6 +20029,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19909,6 +20242,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20260,6 +20596,9 @@ 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 ""
@@ -20518,6 +20857,9 @@ 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 ""
@@ -20533,6 +20875,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20911,6 +21259,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21256,6 +21607,9 @@ 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 ""
@@ -21355,6 +21709,9 @@ 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 ""
@@ -21397,15 +21754,24 @@ 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 ""
@@ -21466,7 +21832,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21694,6 +22060,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22099,7 +22468,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22762,12 +23131,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22942,10 +23317,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22963,6 +23341,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23251,7 +23632,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23380,9 +23761,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23653,6 +24031,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23878,6 +24262,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24415,9 +24802,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25108,6 +25510,15 @@ 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 ""
@@ -25189,6 +25600,9 @@ 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 ""
@@ -25198,6 +25612,9 @@ 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 ""
@@ -25213,9 +25630,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25231,6 +25645,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25486,6 +25903,12 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Line changes"
msgstr ""
@@ -25513,6 +25936,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25606,9 +26032,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25651,6 +26074,9 @@ 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 ""
@@ -25690,6 +26116,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25708,9 +26137,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25780,9 +26206,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25819,10 +26242,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26314,6 +26734,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26395,12 +26818,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26623,18 +27055,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26707,9 +27130,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26722,6 +27142,27 @@ 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 ""
@@ -27334,6 +27775,9 @@ msgstr[2] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27514,6 +27958,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27526,6 +27976,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27586,31 +28039,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27955,6 +28423,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28003,10 +28474,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28120,9 +28597,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28210,9 +28684,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28567,6 +29038,15 @@ 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 ""
@@ -28651,13 +29131,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28963,12 +29446,24 @@ 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|%{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 ""
@@ -29017,9 +29512,18 @@ 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 ""
@@ -29047,9 +29551,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29086,6 +29587,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29095,6 +29599,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29107,6 +29614,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29584,6 +30094,9 @@ 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 ""
@@ -29653,9 +30166,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29950,28 +30460,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30772,6 +31288,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30961,9 +31480,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31162,6 +31678,9 @@ 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 ""
@@ -31387,6 +31906,9 @@ 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 ""
@@ -31438,9 +31960,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31486,6 +32005,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31537,7 +32062,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31546,6 +32071,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31582,13 +32110,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31618,6 +32146,12 @@ 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 ""
@@ -31639,6 +32173,9 @@ 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 ""
@@ -31648,6 +32185,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31963,6 +32503,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31984,6 +32527,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32044,7 +32590,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32398,6 +32944,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32467,88 +33016,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32557,34 +33049,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32593,24 +33088,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32623,22 +33112,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Instrument your application"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32647,70 +33145,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32878,6 +33379,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33127,7 +33634,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33301,6 +33808,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33313,6 +33823,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33340,6 +33853,9 @@ 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 ""
@@ -33436,9 +33952,21 @@ 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 ""
@@ -33451,6 +33979,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33493,7 +34024,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33508,9 +34042,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33640,9 +34171,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33793,9 +34321,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33838,9 +34363,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33877,9 +34399,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33922,10 +34441,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33949,9 +34468,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34186,6 +34702,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34312,6 +34831,9 @@ 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 ""
@@ -34327,6 +34849,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34507,9 +35032,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34618,12 +35140,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34795,9 +35311,27 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34807,10 +35341,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34819,15 +35365,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34837,6 +35392,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35293,24 +35851,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35386,6 +35935,9 @@ 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] ""
@@ -35422,13 +35974,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35521,6 +36073,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36463,15 +37018,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36652,9 +37213,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36826,9 +37384,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36907,6 +37462,9 @@ 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|Administrator"
msgstr ""
@@ -36970,6 +37528,9 @@ 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 ""
@@ -36988,6 +37549,9 @@ 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 ""
@@ -37045,9 +37609,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37060,6 +37630,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37078,6 +37654,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37105,6 +37684,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37114,6 +37699,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37126,6 +37714,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37168,6 +37759,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37201,6 +37795,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37216,6 +37816,9 @@ 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 ""
@@ -37240,6 +37843,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37255,6 +37861,12 @@ 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 ""
@@ -37327,9 +37939,15 @@ 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 ""
@@ -37363,6 +37981,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37372,6 +37996,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37390,6 +38017,9 @@ msgstr[2] ""
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 runner has not run any jobs."
msgstr ""
@@ -37438,6 +38068,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37492,15 +38125,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37522,6 +38146,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37546,9 +38173,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37678,16 +38302,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37729,9 +38356,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38191,22 +38824,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38335,7 +38971,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38449,6 +39085,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38554,9 +39193,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38647,6 +39295,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38668,6 +39319,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38677,6 +39331,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38743,7 +39400,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38821,6 +39478,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39298,6 +39958,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39400,6 +40063,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39412,6 +40078,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39424,6 +40093,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39526,6 +40198,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39661,6 +40339,9 @@ 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 ""
@@ -39688,7 +40369,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39940,6 +40621,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40105,9 +40789,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40261,15 +40942,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40279,6 +40978,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40288,6 +40990,9 @@ 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 ""
@@ -40321,9 +41026,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40507,12 +41218,18 @@ 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 ""
@@ -40924,9 +41641,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40990,6 +41704,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41239,6 +41956,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41884,16 +42604,22 @@ 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|Sync subscription request."
+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}."
@@ -41902,7 +42628,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41932,9 +42658,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41977,9 +42700,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42130,9 +42850,27 @@ 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 ""
@@ -42541,10 +43279,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42568,9 +43306,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42697,6 +43432,9 @@ 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 ""
@@ -42757,6 +43495,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42799,9 +43540,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42859,6 +43597,9 @@ 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 ""
@@ -43174,7 +43915,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43519,6 +44269,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43708,13 +44461,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44215,6 +44962,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44269,10 +45019,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44725,6 +45472,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45214,6 +45964,9 @@ 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 ""
@@ -45304,9 +46057,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45409,9 +46159,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45457,12 +46204,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45568,6 +46309,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45667,6 +46411,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45724,6 +46471,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45811,6 +46567,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45880,6 +46639,9 @@ 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 ""
@@ -46006,6 +46768,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46177,6 +46942,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46381,6 +47149,9 @@ 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 ""
@@ -46393,6 +47164,9 @@ 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 ""
@@ -46468,6 +47242,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46894,6 +47671,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47005,6 +47785,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47149,6 +47932,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47179,9 +47965,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47386,6 +48169,69 @@ 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|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 ""
@@ -47776,12 +48622,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47833,9 +48673,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47977,6 +48814,9 @@ 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 ""
@@ -48241,6 +49081,12 @@ 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] ""
+msgstr[2] ""
+
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] ""
@@ -48280,6 +49126,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48499,7 +49348,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48547,6 +49396,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48571,6 +49423,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48595,9 +49456,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48718,6 +49585,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48754,6 +49624,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48784,6 +49657,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49186,9 +50062,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49360,12 +50233,18 @@ 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 ""
@@ -49537,6 +50416,9 @@ 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 ""
@@ -49546,7 +50428,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49576,6 +50458,9 @@ 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 ""
@@ -49600,6 +50485,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49645,6 +50533,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49654,9 +50545,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49687,6 +50575,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49846,6 +50737,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50086,6 +50980,9 @@ 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 ""
@@ -50422,9 +51319,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50491,6 +51385,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50521,6 +51418,9 @@ 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 ""
@@ -50803,9 +51703,6 @@ msgstr[2] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51115,10 +52012,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51178,6 +52081,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51193,6 +52174,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51220,12 +52207,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51241,6 +52222,9 @@ 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 ""
@@ -51322,82 +52306,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51460,9 +52390,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51487,6 +52414,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/sr_SP/gitlab.po b/locale/sr_SP/gitlab.po
index e68ed99ef03..d27c4f0459e 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -496,6 +496,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -538,12 +544,24 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
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] ""
msgstr[2] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -721,6 +739,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -922,6 +943,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -937,9 +961,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -1075,6 +1096,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1336,6 +1360,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1627,12 +1654,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1951,9 +1972,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2368,9 +2386,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2392,6 +2407,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2401,6 +2419,9 @@ 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 ""
@@ -2515,6 +2536,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2653,6 +2677,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3832,40 +3859,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4237,6 +4234,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4867,6 +4867,9 @@ 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 ""
@@ -4876,6 +4879,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4954,13 +5074,28 @@ 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|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."
+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."
@@ -5107,12 +5242,18 @@ 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 ""
@@ -5362,6 +5503,12 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5374,6 +5521,18 @@ msgstr ""
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+
+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] ""
+msgstr[2] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5449,9 +5608,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5464,6 +5620,9 @@ 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 ""
@@ -5818,7 +5977,7 @@ msgstr[2] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6073,9 +6232,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -6088,9 +6244,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -6100,9 +6253,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6484,6 +6646,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6511,9 +6676,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6583,6 +6745,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6598,9 +6763,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6736,27 +6898,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6766,9 +6910,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6910,6 +7051,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -7135,15 +7279,27 @@ msgstr[2] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7156,9 +7312,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7276,9 +7429,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7297,6 +7447,15 @@ 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 ""
@@ -7327,10 +7486,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7372,6 +7534,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -8140,6 +8305,15 @@ 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 ""
@@ -8257,6 +8431,9 @@ 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 ""
@@ -8641,6 +8818,9 @@ 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 ""
@@ -8683,6 +8863,9 @@ 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 ""
@@ -8692,16 +8875,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8728,6 +8908,9 @@ 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 ""
@@ -8746,6 +8929,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8764,6 +8950,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8884,12 +9073,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8968,10 +9163,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -9001,6 +9196,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9784,6 +9982,9 @@ 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 ""
@@ -10075,7 +10276,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10468,9 +10669,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10483,6 +10681,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10552,12 +10753,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10666,9 +10876,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10687,9 +10912,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11314,6 +11536,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11356,12 +11581,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11377,6 +11611,9 @@ 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 ""
@@ -11422,7 +11659,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11443,7 +11683,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11515,6 +11755,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11761,7 +12004,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11950,6 +12193,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12199,9 +12445,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12409,6 +12652,9 @@ 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 ""
@@ -12508,7 +12754,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12676,9 +12922,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13591,6 +13834,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13633,6 +13879,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14392,6 +14641,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14494,10 +14746,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14602,6 +14857,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14797,6 +15055,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14953,9 +15214,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15394,6 +15652,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15418,6 +15679,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15436,9 +15700,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15895,6 +16165,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15940,7 +16213,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15958,6 +16231,9 @@ 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 ""
@@ -16252,6 +16528,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16363,6 +16642,9 @@ 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 ""
@@ -16651,6 +16933,9 @@ 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 ""
@@ -16930,6 +17215,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16954,6 +17242,9 @@ 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 ""
@@ -17155,6 +17446,9 @@ 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 ""
@@ -17173,6 +17467,9 @@ 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 ""
@@ -17746,9 +18043,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17872,6 +18166,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -18028,9 +18325,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18172,9 +18466,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18988,13 +19279,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19045,6 +19345,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -19069,6 +19372,12 @@ 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 ""
@@ -19084,9 +19393,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -19135,12 +19441,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19234,12 +19534,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19279,6 +19585,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19291,13 +19600,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19315,7 +19624,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19369,6 +19678,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19441,6 +19753,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19495,15 +19810,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19720,6 +20029,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19909,6 +20242,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20260,6 +20596,9 @@ 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 ""
@@ -20518,6 +20857,9 @@ 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 ""
@@ -20533,6 +20875,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20911,6 +21259,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21256,6 +21607,9 @@ 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 ""
@@ -21355,6 +21709,9 @@ 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 ""
@@ -21397,15 +21754,24 @@ 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 ""
@@ -21466,7 +21832,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21694,6 +22060,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -22099,7 +22468,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22762,12 +23131,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22942,10 +23317,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22963,6 +23341,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23251,7 +23632,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23380,9 +23761,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23653,6 +24031,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23878,6 +24262,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24415,9 +24802,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -25108,6 +25510,15 @@ 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 ""
@@ -25189,6 +25600,9 @@ 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 ""
@@ -25198,6 +25612,9 @@ 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 ""
@@ -25213,9 +25630,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25231,6 +25645,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25486,6 +25903,12 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Line changes"
msgstr ""
@@ -25513,6 +25936,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25606,9 +26032,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25651,6 +26074,9 @@ 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 ""
@@ -25690,6 +26116,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25708,9 +26137,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25780,9 +26206,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25819,10 +26242,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26314,6 +26734,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26395,12 +26818,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26623,18 +27055,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26707,9 +27130,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26722,6 +27142,27 @@ 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 ""
@@ -27334,6 +27775,9 @@ msgstr[2] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27514,6 +27958,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27526,6 +27976,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27586,31 +28039,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27955,6 +28423,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -28003,10 +28474,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28120,9 +28597,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28210,9 +28684,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28567,6 +29038,15 @@ 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 ""
@@ -28651,13 +29131,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28963,12 +29446,24 @@ 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|%{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 ""
@@ -29017,9 +29512,18 @@ 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 ""
@@ -29047,9 +29551,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -29086,6 +29587,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -29095,6 +29599,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -29107,6 +29614,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29584,6 +30094,9 @@ 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 ""
@@ -29653,9 +30166,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29950,28 +30460,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30772,6 +31288,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30961,9 +31480,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -31162,6 +31678,9 @@ 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 ""
@@ -31387,6 +31906,9 @@ 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 ""
@@ -31438,9 +31960,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31486,6 +32005,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31537,7 +32062,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31546,6 +32071,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31582,13 +32110,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31618,6 +32146,12 @@ 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 ""
@@ -31639,6 +32173,9 @@ 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 ""
@@ -31648,6 +32185,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31963,6 +32503,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31984,6 +32527,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32044,7 +32590,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32398,6 +32944,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32467,88 +33016,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32557,34 +33049,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32593,24 +33088,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32623,22 +33112,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Instrument your application"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32647,70 +33145,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32878,6 +33379,12 @@ 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|Do not show on profile"
msgstr ""
@@ -33127,7 +33634,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33301,6 +33808,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33313,6 +33823,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33340,6 +33853,9 @@ 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 ""
@@ -33436,9 +33952,21 @@ 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 ""
@@ -33451,6 +33979,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33493,7 +34024,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33508,9 +34042,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33640,9 +34171,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33793,9 +34321,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33838,9 +34363,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33877,9 +34399,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33922,10 +34441,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33949,9 +34468,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -34186,6 +34702,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34312,6 +34831,9 @@ 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 ""
@@ -34327,6 +34849,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34507,9 +35032,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34618,12 +35140,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34795,9 +35311,27 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34807,10 +35341,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34819,15 +35365,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34837,6 +35392,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35293,24 +35851,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35386,6 +35935,9 @@ 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] ""
@@ -35422,13 +35974,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35521,6 +36073,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36463,15 +37018,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36652,9 +37213,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36826,9 +37384,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36907,6 +37462,9 @@ 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|Administrator"
msgstr ""
@@ -36970,6 +37528,9 @@ 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 ""
@@ -36988,6 +37549,9 @@ 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 ""
@@ -37045,9 +37609,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -37060,6 +37630,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -37078,6 +37654,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -37105,6 +37684,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -37114,6 +37699,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37126,6 +37714,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -37168,6 +37759,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -37201,6 +37795,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -37216,6 +37816,9 @@ 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 ""
@@ -37240,6 +37843,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37255,6 +37861,12 @@ 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 ""
@@ -37327,9 +37939,15 @@ 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 ""
@@ -37363,6 +37981,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37372,6 +37996,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37390,6 +38017,9 @@ msgstr[2] ""
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 runner has not run any jobs."
msgstr ""
@@ -37438,6 +38068,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37492,15 +38125,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37522,6 +38146,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37546,9 +38173,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37678,16 +38302,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37729,9 +38356,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38191,22 +38824,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38335,7 +38971,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38449,6 +39085,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38554,9 +39193,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38647,6 +39295,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38668,6 +39319,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38677,6 +39331,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38743,7 +39400,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38821,6 +39478,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39298,6 +39958,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39400,6 +40063,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39412,6 +40078,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39424,6 +40093,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39526,6 +40198,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39661,6 +40339,9 @@ 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 ""
@@ -39688,7 +40369,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39940,6 +40621,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40105,9 +40789,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40261,15 +40942,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40279,6 +40978,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40288,6 +40990,9 @@ 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 ""
@@ -40321,9 +41026,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40507,12 +41218,18 @@ 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 ""
@@ -40924,9 +41641,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40990,6 +41704,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -41239,6 +41956,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41884,16 +42604,22 @@ 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|Sync subscription request."
+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}."
@@ -41902,7 +42628,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41932,9 +42658,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41977,9 +42700,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -42130,9 +42850,27 @@ 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 ""
@@ -42541,10 +43279,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42568,9 +43306,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42697,6 +43432,9 @@ 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 ""
@@ -42757,6 +43495,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42799,9 +43540,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42859,6 +43597,9 @@ 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 ""
@@ -43174,7 +43915,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43519,6 +44269,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43708,13 +44461,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44215,6 +44962,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44269,10 +45019,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44725,6 +45472,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45214,6 +45964,9 @@ 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 ""
@@ -45304,9 +46057,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45409,9 +46159,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45457,12 +46204,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45568,6 +46309,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45667,6 +46411,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45724,6 +46471,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45811,6 +46567,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45880,6 +46639,9 @@ 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 ""
@@ -46006,6 +46768,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -46177,6 +46942,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46381,6 +47149,9 @@ 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 ""
@@ -46393,6 +47164,9 @@ 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 ""
@@ -46468,6 +47242,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46894,6 +47671,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47005,6 +47785,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47149,6 +47932,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47179,9 +47965,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47386,6 +48169,69 @@ 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|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 ""
@@ -47776,12 +48622,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47833,9 +48673,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47977,6 +48814,9 @@ 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 ""
@@ -48241,6 +49081,12 @@ 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] ""
+msgstr[2] ""
+
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] ""
@@ -48280,6 +49126,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48499,7 +49348,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48547,6 +49396,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48571,6 +49423,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48595,9 +49456,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48718,6 +49585,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48754,6 +49624,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48784,6 +49657,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -49186,9 +50062,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49360,12 +50233,18 @@ 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 ""
@@ -49537,6 +50416,9 @@ 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 ""
@@ -49546,7 +50428,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49576,6 +50458,9 @@ 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 ""
@@ -49600,6 +50485,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49645,6 +50533,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49654,9 +50545,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49687,6 +50575,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49846,6 +50737,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -50086,6 +50980,9 @@ 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 ""
@@ -50422,9 +51319,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50491,6 +51385,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50521,6 +51418,9 @@ 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 ""
@@ -50803,9 +51703,6 @@ msgstr[2] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -51115,10 +52012,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -51178,6 +52081,84 @@ 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|%{mergeError}."
msgstr ""
@@ -51193,6 +52174,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -51220,12 +52207,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -51241,6 +52222,9 @@ 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 ""
@@ -51322,82 +52306,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51460,9 +52390,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51487,6 +52414,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/sv_SE/gitlab.po b/locale/sv_SE/gitlab.po
index 397e0d86366..d8c50db456b 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr "%{count} relaterade %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (utgången)"
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr "Lägg till ny katalog"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "Konfidentialitet"
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/sw_KE/gitlab.po b/locale/sw_KE/gitlab.po
index 90b79fcc6e6..7ddc1287a10 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ta_IN/gitlab.po b/locale/ta_IN/gitlab.po
index e4f2306827d..e5c5cca164e 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/th_TH/gitlab.po b/locale/th_TH/gitlab.po
index 4802c08557d..570c9b2622e 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-02-11 04:22\n"
+"PO-Revision-Date: 2023-03-11 10:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -539,6 +553,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -740,6 +757,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -755,9 +775,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -889,6 +906,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1675,9 +1694,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2092,9 +2108,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2116,6 +2129,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2125,6 +2141,9 @@ 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 ""
@@ -2239,6 +2258,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2377,6 +2399,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3556,40 +3581,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3961,6 +3956,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4587,6 +4585,9 @@ 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 ""
@@ -4596,6 +4597,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4674,13 +4792,28 @@ 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|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."
+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."
@@ -4823,12 +4956,18 @@ 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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5080,6 +5223,14 @@ msgstr ""
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ 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 ""
@@ -5518,7 +5669,7 @@ msgstr[0] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5771,9 +5922,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5786,9 +5934,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5798,9 +5943,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6606,6 +6739,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -6846,9 +6994,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -6987,6 +7129,15 @@ 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 ""
@@ -7017,10 +7168,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7062,6 +7216,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7945,6 +8111,9 @@ 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 ""
@@ -8325,6 +8494,9 @@ 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 ""
@@ -8367,6 +8539,9 @@ 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 ""
@@ -8376,16 +8551,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8412,6 +8584,9 @@ 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 ""
@@ -8430,6 +8605,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8568,12 +8749,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,10 +8839,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10161,6 +10351,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10365,9 +10582,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ 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 ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11115,7 +11347,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11187,6 +11419,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11433,7 +11668,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,7 +12418,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13301,6 +13539,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,10 +14388,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15060,6 +15313,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15582,7 +15847,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 ""
@@ -16795,6 +17078,9 @@ 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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17662,9 +17951,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ 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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19121,15 +19430,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19535,6 +19862,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -19886,6 +20216,9 @@ 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 ""
@@ -20144,6 +20477,9 @@ 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 ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -20874,6 +21219,9 @@ 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 ""
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ 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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21308,6 +21668,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22374,12 +22737,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23261,6 +23633,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23486,6 +23864,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ 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 ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ 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 ""
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25372,9 +25790,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 ""
@@ -26918,6 +27351,9 @@ msgstr[0] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27098,6 +27534,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27110,6 +27552,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28533,12 +29008,24 @@ 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|%{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 ""
@@ -28587,9 +29074,18 @@ 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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29152,6 +29654,9 @@ 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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30330,6 +30838,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30720,6 +31228,9 @@ 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 ""
@@ -30945,6 +31456,9 @@ 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 ""
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 ""
@@ -31197,6 +31723,9 @@ 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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,7 +32140,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -32898,6 +33403,9 @@ 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 ""
@@ -32994,9 +33502,21 @@ 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 ""
@@ -33009,6 +33529,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,7 +33574,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33435,9 +33949,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -33870,6 +34381,9 @@ 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 ""
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34176,12 +34690,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34395,6 +34938,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] ""
@@ -34978,13 +35518,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36005,15 +36548,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr ""
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ 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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ 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 ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37042,6 +37654,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37689,22 +38310,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -37833,7 +38457,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -38796,6 +39444,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ 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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 ""
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41622,9 +42330,27 @@ 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 ""
@@ -42029,10 +42755,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42341,6 +43067,9 @@ 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 ""
@@ -42652,7 +43381,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -43747,10 +44485,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44199,6 +44934,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44684,6 +45422,9 @@ 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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -44877,9 +45615,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -44925,12 +45660,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ 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 ""
@@ -45474,6 +46224,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46360,6 +47125,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46643,9 +47417,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -46846,6 +47617,69 @@ 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|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 ""
@@ -47236,12 +48070,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -47955,7 +48790,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ 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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,7 +49862,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49024,6 +49892,9 @@ 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 ""
@@ -49048,6 +49919,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49102,9 +49979,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -49915,6 +50795,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50521,10 +51404,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,82 +51690,28 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po
index 2e5aee9d0ea..6e72c24841b 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ msgid_plural "%d unresolved threads"
msgstr[0] "%d çözümlenmemiş konu"
msgstr[1] "%d çözümlenmemiş konu"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] "%d uyarı bulundu:"
msgstr[1] "%d uyarı bulundu:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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] "%s performans sorunlarını önlemek için ek işlem konulmuştur."
msgstr[1] "%s performans sorunlarını önlemek için ek işlem konulmuştur."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} ve %{openOrClose} %{noteable}"
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr "%{mergeLength}/%{usersLength} birleÅŸtirebilir"
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (süresi doldu)"
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr "%{user} bir epik oluÅŸturdu: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} bir sorun oluÅŸturdu: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] "1 dağıtım anahtarı"
msgstr[1] "%d dağıtım anahtarı"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "1 takipçi"
-msgstr[1] "%{count} takipçi"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grup"
@@ -1813,9 +1833,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr "API Yardımı"
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr "Bu satıra yorum ekle"
@@ -2254,6 +2268,9 @@ msgstr "Wiki'nize projeniz hakkında bilgi içeren bir ana sayfa ekleyin. GitLab
msgid "Add a new issue"
msgstr "Yeni sorun ekle"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Numaralı liste ekle"
@@ -2263,6 +2280,9 @@ msgstr ""
msgid "Add a related issue"
msgstr "Ä°lgili sorun ekle"
+msgid "Add a reply"
+msgstr ""
+
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -2377,6 +2397,9 @@ msgstr "Yeni uygulama ekle"
msgid "Add new directory"
msgstr "Yeni dizin ekle"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr "Ek dakikalar:"
msgid "Additional text"
msgstr "Ek metin"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
msgstr "Tüm Kullanıcılar"
+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 "Bütün dallar"
@@ -4727,6 +4726,9 @@ msgstr "Web Terminali başlatılırken beklenmeyen bir hata oluştu."
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "Web Terminali durdurulurken beklenmeyen bir hata oluÅŸtu."
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr "Bu grafik yüklenirken bilinmeyen bir hata oluştu."
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr "Analizler"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ msgstr "Yorumu %{shrug} ile ekle"
msgid "Append the comment with %{tableflip}"
msgstr "Yorumu %{tableflip} ile ekle"
+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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Bir birleÅŸtirme talebini onayla"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5227,6 +5372,16 @@ msgstr "Onaylandı"
msgid "Approved MRs"
msgstr "Onaylı MRlar"
+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 "Geçerli birleştirme talebi onaylandı."
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr "%{name} ismini silmek istediÄŸinizden emin misiniz?"
+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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] "%d dosya ekleniyor"
msgid "Attaching the file failed."
msgstr "Dosya ekleme başarısız oldu."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr "%{author} tarafından %{timeago} oluşturuldu"
msgid "Authorization code:"
msgstr "Yetkilendirme kodu:"
-msgid "Authorization required"
-msgstr "Yetkilendirme gerekli"
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr "Yetki Ver"
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr "%{new_chat_name} yetkilendirildi"
@@ -5949,9 +6098,18 @@ msgstr "Yetkili"
msgid "Authorized applications (%{size})"
msgstr "Yetkili uygulamalar (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr "Dikkatli olun. Projenin isim alanını değiştirmek, istenmeyen yan etk
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Dikkatli olun. Bir projenin deposunu yeniden isimlendirmenin istenmeyen yan etkileri olabilir."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr "Yükselt"
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ msgstr[1] ""
msgid "Boards|Collapse"
msgstr "Daralt"
+msgid "Boards|Create new epic"
+msgstr ""
+
+msgid "Boards|Create new issue"
+msgstr ""
+
msgid "Boards|Edit board"
msgstr "Panoyu düzenle"
+msgid "Boards|Edit list settings"
+msgstr ""
+
msgid "Boards|Expand"
msgstr "GeniÅŸlet"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr ""
+msgid "Boards|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 "Parçacık üretemiyor: %{err}"
@@ -8101,6 +8271,9 @@ msgstr ""
msgid "Cannot import because issues are not available in this project."
msgstr "Bu projede sorunlar bulunmadığı için içe aktarılamıyor."
+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 "Gizli olmayan alt epikler içeriyorsa epik gizli hale getirilemez"
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ msgstr "Ãœlke"
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 "Yeni grup oluÅŸtur"
@@ -8534,18 +8713,15 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "Düzenle"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr "Son Erme %{expirationMonth}/%{expirationYear}"
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "Siparişiniz onaylanamadı! Lütfen tekrar deneyin."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "Siparişiniz onaylanamadı: %{message}. Lütfen tekrar deneyin."
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "Ülkeler yüklenemedi. Lütfen tekrar deneyin."
@@ -8570,6 +8746,9 @@ msgstr "GitLab planı"
msgid "Checkout|Group"
msgstr "Grup"
+msgid "Checkout|Invalid coupon code. Enter a valid coupon code."
+msgstr ""
+
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
msgstr ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "Kullanıcı sayısı"
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ msgstr "Bir grubun genel bakış sayfasında hangi içeriği görmek istediğini
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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr "bekliyor"
msgid "CiStatus|running"
msgstr "çalışıyor"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "Düzeltmeleri karşılaştır"
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr "Son işlem ile değişiklikleri karşılaştır"
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "Gizlilik"
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr "Katkı"
msgid "Contribution Analytics"
msgstr "Katkı Analizi"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,8 +11515,8 @@ msgstr "Grup üyesi başına katkılar"
msgid "Contributor"
msgstr ""
-msgid "Contributors"
-msgstr "Katkıda Bulunanlar"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "Hesabınıza bağlı e-postaları kontrol edin"
@@ -11351,6 +11587,9 @@ msgstr "Komutları kopyala"
msgid "Copy commit SHA"
msgstr "İşlem SHA'sını kopyala"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr "OluÅŸturulma tarihi"
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ msgstr "Tercihler"
msgid "CurrentUser|Start an Ultimate trial"
msgstr "Ultimate denemesini baÅŸlat"
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr ""
+
msgid "Currently unable to fetch data for this pipeline."
msgstr ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr "başarılı"
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr "Discord Bildirimleri"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr "Açıklamayı düzenle"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "Ortamı düzenle"
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "Genel dağıtım anahtarını düzenle"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "Epik bulunamıyor."
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 "Birleştirme işlemleri hariçtir. %{limit} işlem ile sınırlıdır."
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr "Åžub"
msgid "February"
msgstr "Åžubat"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "Sonuçları filtrele"
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr "Doğrulanmadı"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use unique domain"
+msgstr ""
+
msgid "GitLabPages|Verified"
msgstr "Doğrulandı"
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr "Gitea içe aktarma"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr "%{time_ago} eriÅŸim verildi"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr "Gruba genel bakış içeriği"
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "Merhaba %{username}!"
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ msgstr ""
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "Yakın zamanda oturum açtıysanız ve IP adresini tanıyorsanız, bu e-postayı dikkate almayabilirsiniz."
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "Öneri ekle"
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr "Geçersiz depo yolu"
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr "Başlık"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "Ä°ÅŸler"
@@ -24910,6 +25309,15 @@ msgstr "Daha fazlasını öğrenin."
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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Gruptan ayrıl"
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ msgstr "Grup üyeleri için katkı istatistikleri yükleniyor"
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr ""
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr "Kilitli"
-msgid "Locked Files"
-msgstr "Kilitli Dosyalar"
-
msgid "Locked by %{fileLockUserName}"
msgstr "%{fileLockUserName} tarafından kilitlendi"
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr "BÄ°RLEÅžTÄ°RÄ°LDÄ°"
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ msgstr "İş hattı başarılı olduğunda birleştir"
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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr "Dakika"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "Ä°simlendirme, konular, profil resmi"
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr "Yeni Parçacık"
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr "Yeni ÅŸifre"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "Yeni proje"
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr "İş Hattı"
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ msgstr "İş hatları"
msgid "Pipelines charts"
msgstr "İş hatları çizelgeleri"
+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 "'%{project_name}' için iş hattı ayarları başarıyla güncellendi."
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,8 +32365,8 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
-msgstr "Lütfen bir ülke seçin"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr ""
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr "Önizleme yükü"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User activity"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ msgstr "Bağlantıyı kes"
msgid "Profiles|Disconnect %{provider}"
msgstr "%{provider} bağlantısını kes"
+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|Do not show on profile"
msgstr "Profilde gösterme"
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Hesabınızı silmeden önce sahipliği devretmeniz veya bu grupları silmeniz gerekir."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr "Proje üyeleri"
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Proje adı"
@@ -33092,6 +33598,9 @@ 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"
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ msgstr "Proje KimliÄŸi: %{project_id}"
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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,8 +33799,11 @@ 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 "ProjectSelect| or group"
-msgstr " veya grup"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
msgid "ProjectSelect|No matching results"
msgstr ""
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr "Sorunlar"
@@ -33617,9 +34138,6 @@ msgstr "BirleÅŸtirme istekleri"
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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr "Birleştirme önerileri"
@@ -33656,9 +34174,6 @@ msgstr "Sayfalar"
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr "Parçacıklar"
@@ -33965,6 +34477,9 @@ msgstr "Projeler (%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "Proje açıklaması %{tag_start}(isteğe bağlı)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+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?"
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "Dağıtıma izin verildi"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] "Güncellenmiş durumu göstermek için bir saniye içinde yenilenecek..."
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr "Kaydol / Oturum Aç"
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr ""
-
msgid "Requirements"
msgstr "Gereksinimler"
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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "Çalışıyor"
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,24 +38567,27 @@ msgstr ""
msgid "Security"
msgstr "Güvenlik"
-msgid "Security & Compliance"
-msgstr "Güvenlik ve Uyumluluk"
-
-msgid "Security Configuration"
-msgstr "Güvenlik Yapılandırması"
-
msgid "Security Dashboard"
msgstr "Güvenlik Kontrol Panosu"
msgid "Security Finding not found"
msgstr ""
-msgid "Security dashboard"
-msgstr "Güvenlik gösterge panosu"
+msgid "Security Policy project already exists."
+msgstr ""
+
+msgid "Security and Compliance"
+msgstr ""
+
+msgid "Security capabilities"
+msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
msgstr ""
+msgid "Security dashboard"
+msgstr "Güvenlik gösterge panosu"
+
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr "Oturum aç"
-msgid "Sign in / Register"
-msgstr "Oturum aç / Kayıt ol"
-
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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr "İki Aşamalı Kimlik Doğrulama"
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr "İki Aşamalı Kimlik Doğrulama"
@@ -45191,12 +45932,6 @@ msgstr "Tür"
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr "Sınırsız"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ msgstr ""
msgid "Update your group name, description, avatar, and visibility."
msgstr "Grup adınızı, açıklamanızı, profil resminizi ve görünürlüğünüzü güncelleyin."
+msgid "Update your project name and description."
+msgstr ""
+
msgid "Update your project name, topics, description, and avatar."
msgstr ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr "Kullanım istatistikleri"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 "%{user} tarafından %{timeago} %{statusStart}onaylandı%{statusEnd}"
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Viki"
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr "Dönüm noktası açıklaması yazın..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ msgstr "Bir kilidi silmeye zorlamak için sorumlu erişiminiz olmalıdır"
msgid "You must provide a valid current password"
msgstr "Geçerli bir mevcut şifre girmelisiniz"
+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 "Değiştirmek için mevcut şifrenizi girmelisiniz."
+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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ msgstr "Gitlab grubunuz"
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 "Gruplarınız"
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "Yapılacaklar Listeniz"
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "Uygulamalarınız (%{size})"
@@ -49378,9 +50262,6 @@ msgstr "Yetkili uygulamalarınız"
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Çözüm"
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST)"
msgstr ""
@@ -50510,9 +51403,6 @@ msgstr[1] "dosya"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr "takip ediliyor"
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr "%{path_lock_user_name} tarafından kilitlendi %{created_at}"
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr "Onayla"
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr "Birleştirme başarısız."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr "BirleÅŸtiren:"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
-msgstr ""
-
msgid "mrWidget|More information"
msgstr "Daha fazla bilgi"
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase"
+msgstr ""
+
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index 0dd9263e079..613c802dccf 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-02-11 15:25\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr " %{start} до %{end}"
@@ -566,6 +566,13 @@ msgstr[1] "%d невирішені теми"
msgstr[2] "%d невирішених тем"
msgstr[3] "%d невирішених тем"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d вразливіÑÑ‚ÑŒ"
@@ -615,6 +622,13 @@ msgstr[1] "%d Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð·Ð½Ð°Ð¹Ð´ÐµÐ½Ð¾:"
msgstr[2] "%d попереджень знайдено:"
msgstr[3] "%d попереджень знайдено:"
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
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 доданий коміт був виключений Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ із продуктивніÑÑ‚ÑŽ."
@@ -622,6 +636,12 @@ msgstr[1] "%s доданих коміта були виключені Ð´Ð»Ñ Ð·Ð
msgstr[2] "%s доданих комітів були виключені Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ із продуктивніÑÑ‚ÑŽ."
msgstr[3] "%s доданих комітів були виключені Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ із продуктивніÑÑ‚ÑŽ."
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} Ñ– %{openOrClose} %{noteable}"
@@ -812,6 +832,9 @@ msgstr "%{count} пов’Ñзаних %{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "Вибрано: %{count}"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "%{count} загальна вага"
@@ -1013,6 +1036,9 @@ msgstr "%{level_name} не допуÑкаєтьÑÑ, оÑкільки проєк
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr "%{linkStart} ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{linkEnd}."
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}та %{awardsListLength} ще"
@@ -1028,9 +1054,6 @@ msgstr "%{mergeLength}/%{usersLength} можуть виконувати злит
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} показує перший %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr "%{message}. Ваш запит на увагу був видалений."
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (термін дії минув)"
@@ -1168,6 +1191,9 @@ msgstr "%{reportType} виÑвив %{totalStart}%{total}%{totalEnd} потенц
msgid "%{reportType} detected no new vulnerabilities."
msgstr "%{reportType} не виÑвило нових вразливоÑтей."
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1446,6 +1472,9 @@ msgstr "%{user} Ñтворив епік: %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} Ñтворив задачу: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr "%{value} не включено до ÑпиÑку"
@@ -1750,13 +1779,6 @@ msgstr[1] "%d ключі Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ"
msgstr[2] "%d ключів Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ"
msgstr[3] "%d ключів Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "1 підпиÑник"
-msgstr[1] "%{count} підпиÑника"
-msgstr[2] "%{count} підпиÑників"
-msgstr[3] "%{count} підпиÑників"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 група"
@@ -2089,9 +2111,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "API Fuzzing"
-msgid "API Fuzzing Configuration"
-msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Fuzzing API"
-
msgid "API Help"
msgstr "Довідка API"
@@ -2506,9 +2525,6 @@ msgstr "Додати ÑпиÑок"
msgid "Add a collapsible section"
msgstr "Додати згорнуту Ñекцію"
-msgid "Add a comment"
-msgstr "Додати коментар"
-
msgid "Add a comment to this line"
msgstr "Додати коментар до цього Ñ€Ñдка"
@@ -2530,6 +2546,9 @@ msgstr "Додати домашню Ñторінку в вікі, Ñка міÑÑ
msgid "Add a new issue"
msgstr "Додати нову задачу"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "Додати нумерований ÑпиÑок"
@@ -2539,6 +2558,9 @@ 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 "Додати ÑÑƒÑ„Ñ–ÐºÑ Ð´Ð¾ електронної адреÑи Ñлужби підтримки. %{linkStart}Докладніше.%{linkEnd}"
@@ -2653,6 +2675,9 @@ msgstr "Додати новий додаток"
msgid "Add new directory"
msgstr "Додати новий каталог"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr "Додати чи видалити кориÑтувача."
@@ -2791,6 +2816,9 @@ msgstr "Додаткові хвилини:"
msgid "Additional text"
msgstr "Додатковий текÑÑ‚"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr "Додатковий текÑÑ‚ Ð´Ð»Ñ Ñторінок входу й довідки."
@@ -3970,41 +3998,11 @@ msgstr "ПіÑÐ»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ñ–Ñ— інтеграції Apple App Store Conne
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 "ПіÑÐ»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ ÐµÐºÑпорту завантажте файл даних із Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ— пошти або з цієї Ñторінки. Потім ви можете імпортувати файл даних із %{strong_text_start}Створити нову Ñторінку групи %{strong_text_end} іншого інÑтанÑа GitLab."
-msgid "After you've reviewed these contribution guidelines, you'll be all set to"
-msgstr "ПіÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк ви ознайомитеÑÑ Ð· цими принципами внеÑÐµÐ½Ð½Ñ Ð²ÐºÐ»Ð°Ð´Ñ–Ð², ви будете готові до"
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
-msgstr ""
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
+msgstr "ПіÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк ви ознайомитеÑÑ Ð· цими принципами внеÑÐµÐ½Ð½Ñ Ð²ÐºÐ»Ð°Ð´Ñ–Ð², ви будете готові до"
msgid "Akismet"
msgstr "Akismet"
@@ -4375,6 +4373,9 @@ msgstr "ВеÑÑŒ GitLab"
msgid "All Members"
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 "Ð’ÑÑ– гілки"
@@ -5007,6 +5008,9 @@ 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 "Під Ñ‡Ð°Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ графіка ÑталаÑÑ Ð½ÐµÐ²Ñ–Ð´Ð¾Ð¼Ð° помилка."
@@ -5016,6 +5020,123 @@ msgstr "СталаÑÑ Ð½ÐµÐ²Ñ–Ð´Ð¾Ð¼Ð° помилка."
msgid "Analytics"
msgstr "Ðналітика"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Проаналізуйте ваші залежноÑÑ‚Ñ– на предмет відомих вразливоÑтей."
@@ -5094,14 +5215,29 @@ msgstr "Додати коментар з %{shrug}"
msgid "Append the comment with %{tableflip}"
msgstr "Додати коментар з %{tableflip}"
+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|The Apple App Store Connect Issuer ID."
msgstr "Ідентифікатор емітента Apple App Store Connect."
msgid "AppleAppStore|The Apple App Store Connect Key ID."
msgstr "Ідентифікатор ключа Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Apple App Store."
-msgid "AppleAppStore|The Apple App Store Connect Private Key."
-msgstr "Приватний ключ Apple App Store Connect."
+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 "ВикориÑтовуйте Gitlab Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð° випуÑку програми у магазині Apple App Store."
@@ -5249,12 +5385,18 @@ msgstr "Зберегти зміни"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "Див. %{linkStart}правила політики паролів%{linkEnd}."
+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 "ТекÑÑ‚, Ñкий відображаєтьÑÑ Ð¿Ñ–ÑÐ»Ñ Ñ€ÐµÑ”Ñтрації кориÑтувача. Markdown увімкнено."
@@ -5509,6 +5651,13 @@ msgstr ""
msgid "Approve a merge request"
msgstr "Затвердити запит на злиттÑ"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approve merge request"
msgstr "Затвердити запит на злиттÑ"
@@ -5521,6 +5670,20 @@ msgstr "Затверджено"
msgid "Approved MRs"
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] ""
+msgstr[2] ""
+msgstr[3] ""
+
+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] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Approved the current merge request."
msgstr "Затверджено поточний запит на злиттÑ."
@@ -5596,9 +5759,6 @@ msgstr "Ви впевнені , що ви хочете %{action}%{name}?"
msgid "Are you sure you want to approve %{user}?"
msgstr "Ви впевнені, що хочете затвердити %{user}?"
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr "Ви впевнені, що бажаєте Ñпробувати об'єднатиÑÑ?"
@@ -5611,6 +5771,9 @@ msgstr "Ви впевнені, що хочете закрити цю заблоÐ
msgid "Are you sure you want to delete %{name}?"
msgstr "Ви впевнені, що хочете видалити %{name}?"
+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 "Ви певні, що хочете видалити цей %{commentType}?"
@@ -5968,7 +6131,7 @@ msgstr[3] "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ %d файлів"
msgid "Attaching the file failed."
msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¸ÐºÑ€Ñ–Ð¿Ð¸Ñ‚Ð¸ файл."
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -6224,9 +6387,6 @@ msgstr "Створено %{author} %{timeago}"
msgid "Authorization code:"
msgstr "Код авторизації:"
-msgid "Authorization required"
-msgstr "Потрібна авторизаціÑ"
-
msgid "Authorization token duration (minutes)"
msgstr "ТриваліÑÑ‚ÑŒ токена авторизації (хвилини)"
@@ -6239,9 +6399,6 @@ msgstr "ÐвторизаціÑ"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "ÐвторизуватиÑÑ %{link_to_client} викориÑтовуючи ваш аккаунт?"
-msgid "Authorize %{user} to use your account?"
-msgstr "ÐвторизуватиÑÑ %{user}, щоб викориÑтовувати ваш обліковий запиÑ?"
-
msgid "Authorized %{new_chat_name}"
msgstr "Ðвторизовано %{new_chat_name}"
@@ -6251,9 +6408,18 @@ msgstr "Ðвторизовано у"
msgid "Authorized applications (%{size})"
msgstr "Ðвторизовані заÑтоÑунки: (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr "Відкликати заÑтоÑунок"
@@ -6635,6 +6801,9 @@ msgstr "Будьте обережні. Зміна проÑтору імен пр
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Будьте обережні. ÐŸÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–ÑŽ проєкту може мати небажані побічні ефекти."
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6662,9 +6831,6 @@ msgstr "Ðижче наведені Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ %{link_to_gi
msgid "Below you will find all the groups that are public."
msgstr "Ðижче ви знайдете вÑÑ– загальнодоÑтупні групи."
-msgid "Beta"
-msgstr "Бета"
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6734,6 +6900,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6749,9 +6918,6 @@ msgstr "Якщо ви хочете перейти на нижчий план, б
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 "Вивчіть детальну інформацію про кожну підпиÑку за поÑиланнÑм %{faq_link} або розпочніть кориÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·ÐºÐ¾ÑˆÑ‚Ð¾Ð²Ð½Ð¸Ð¼ 30-денним періодом GitLab.com Ultimate."
@@ -6887,27 +7053,9 @@ msgstr "Підвищити"
msgid "BillingPlan|Upgrade for free"
msgstr "Безкоштовно перейти на кращий тарифний план"
-msgid "Billings|%{planName} plan"
-msgstr "%{planName} план"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при Ñпробі продовжити ваш пробний період"
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ñ— активації пробного періоду."
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr "При продовженні пробного періоду ви отримаєте додаткові 30 днів %{planName}. Пробний період можна продовжити лише один раз."
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr "При повторній активації пробного періоду ви отримаєте додаткові 30 днів %{planName}. Пробний період можна повторно активувати лише один раз."
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr "ÐŸÑ€Ð¾Ð´Ð¾Ð²Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð½Ð¾Ð³Ð¾ періоду"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6917,9 +7065,6 @@ msgstr "Безкоштовний рівень та пробні групи моÐ
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr "Повторно активувати пробну верÑÑ–ÑŽ"
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -7062,6 +7207,9 @@ msgstr "Імпорт з Bitbucket"
msgid "Blame"
msgstr "ВідповідальніÑÑ‚ÑŒ"
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr "ПереглÑнути на %{environmentName}"
@@ -7290,15 +7438,27 @@ msgstr[3] ""
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 "Помилка при отриманні Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ %{issuableType}s"
+msgid "Boards|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr "ПереміÑтити картку"
@@ -7311,9 +7471,6 @@ msgstr "ПереміÑтити на початок ÑпиÑку"
msgid "Boards|New board"
msgstr "Ðова дошка"
-msgid "Boards|New epic"
-msgstr "Ðовий епік"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7431,9 +7588,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr "Ð’ÑÑ– гілки"
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr "УÑім кориÑтувачам з доÑтупом push дозволено примуÑовий push."
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "Дозволити вÑім кориÑтувачам з push-доÑтупом %{linkStart}примуÑово push%{linkEnd}."
@@ -7452,6 +7606,15 @@ 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 "Під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð³Ñ–Ð»Ð¾Ðº ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°."
@@ -7482,10 +7645,13 @@ msgstr "Створити шаблон: %{searchTerm}"
msgid "BranchRules|Details"
msgstr "Деталі"
-msgid "BranchRules|Force push"
-msgstr "ПримуÑове надÑиланнÑ"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7527,6 +7693,9 @@ msgstr "Ðеобхідні Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ (%{total})"
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr "Ролі"
@@ -8296,6 +8465,15 @@ 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 "Ðеможливо Ñтворити Ñніпет: %{err}"
@@ -8413,6 +8591,9 @@ 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 "Ðе можна зробити конфіденційний ідентифікатор кориÑтувача, Ñкщо він міÑтить неконфіденційні дочірні епіки"
@@ -8799,6 +8980,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+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 "Виникла невідома помилка. Будь лаÑка, Ñпробуйте знову, оновивши цю Ñторінку."
@@ -8841,6 +9025,9 @@ 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 "Створити нову групу"
@@ -8850,18 +9037,15 @@ msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ форму кредитної
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ форму кредитної картки: %{message}"
+msgid "Checkout|Discount"
+msgstr ""
+
msgid "Checkout|Edit"
msgstr "Редагувати"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸ ваше замовленнÑ! Будь лаÑка, Ñпробуйте ще раз."
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "Ðе вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸ ваше замовленнÑ: %{message}. Будь лаÑка, Ñпробуйте ще раз."
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "Помилка при завантаженні країн. Будь лаÑка, Ñпробуйте ще раз."
@@ -8886,6 +9070,9 @@ msgstr "GitLab план"
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 "Має бути %{minimumNumberOfUsers} (ваші вільні міÑцÑ) або більше."
@@ -8904,6 +9091,9 @@ msgstr "Ðазва: %{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "Потрібно більше кориÑтувачів? Придбайте GitLab Ð´Ð»Ñ %{company}."
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr "КількіÑÑ‚ÑŒ кориÑтувачів"
@@ -8922,6 +9112,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr "Стан"
@@ -9042,12 +9235,18 @@ 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 "Виберіть, Ñкі репозиторії ви хочете підключити Ñ– запуÑтити конвеєри CI/CD."
msgid "Choose your framework"
msgstr "Виберіть ваш фреймворк"
+msgid "Ci config already present"
+msgstr ""
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr "Діапазон дат: %{range}"
@@ -9126,12 +9325,12 @@ msgstr "очікуваннÑ"
msgid "CiStatus|running"
msgstr "виконуєтьÑÑ"
+msgid "CiVariables|Cancel"
+msgstr ""
+
msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr "Ðеможливо викориÑтовувати приховану змінну із поточним значеннÑм"
-msgid "CiVariables|Clear inputs"
-msgstr "ОчиÑтити введені дані"
-
msgid "CiVariables|Environments"
msgstr "Середовища"
@@ -9159,6 +9358,9 @@ msgstr "Параметри"
msgid "CiVariables|Protected"
msgstr "Захищений"
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr "Видалити змінну"
@@ -9944,6 +10146,9 @@ msgstr "У вашому інÑтанÑÑ– не налаштовано %{linkStart
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 "У Ð²Ð°Ñ Ð½ÐµÐ´Ð¾Ñтатньо прав Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ»Ð°Ñтерного агента Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
@@ -10235,7 +10440,7 @@ msgstr "Сертифікат Kubernetes, що викориÑтовуєтьÑÑ Ð
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "URL-адреÑа, що викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð´Ð¾Ñтупу до Kubernetes API."
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Kubernetes на оÑнові Ñертифікатів заÑтаріла та буде вимкнена наприкінці лютого 2023 року. Будь лаÑка, %{linkStart}мігруйте на агент GitLab Ð´Ð»Ñ Kubernetes%{linkEnd} або звернітьÑÑ Ð´Ð¾ Ñлужби підтримки GitLab."
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10629,9 +10834,6 @@ msgstr "ПорівнÑйте редакції GitLab"
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr "ПорівнÑÐ½Ð½Ñ Ñ€ÐµÐ´Ð°ÐºÑ†Ñ–Ð¹"
-
msgid "Compare branches and continue"
msgstr ""
@@ -10644,6 +10846,9 @@ msgstr "ПорівнÑти зміни з оÑтаннім комітом"
msgid "Compare changes with the merge request target branch"
msgstr "ПорівнÑти зміни із ціловою гілкою запиту на злиттÑ"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr "ПорівнÑти верÑÑ–Ñ— комітів підмодулÑ"
@@ -10713,12 +10918,21 @@ msgstr "Завершено"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr "Завершено за %{duration_seconds} Ñекунд (%{relative_time})"
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr "Звіт про відповідніÑÑ‚ÑŒ"
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Додати фреймворк"
@@ -10827,9 +11041,24 @@ msgstr "Затверджено комітером"
msgid "ComplianceReport|Less than 2 approvers"
msgstr "Менше, ніж 2 затверджувачі"
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr "ÐŸÐ¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ Ð½Ðµ виÑвлені"
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "Компонент"
@@ -10848,9 +11077,6 @@ msgstr "Конфіденційна нотатка"
msgid "Confidentiality"
msgstr "КонфіденційніÑÑ‚ÑŒ"
-msgid "Configuration"
-msgstr "КонфігураціÑ"
-
msgid "Configuration help"
msgstr "Довідка по конфігурації"
@@ -11478,6 +11704,9 @@ msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ репозиторій %{titl
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "Ви можете додати образ до цього реєÑтру за допомогою наÑтупних команд:"
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr "ВміÑÑ‚ аналізуєтьÑÑ Ð·Ð° допомогою %{link}."
@@ -11520,12 +11749,21 @@ msgstr "ВнеÑок"
msgid "Contribution Analytics"
msgstr "Ðналітика внеÑків"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr "%{created} Ñтворено, %{closed} закрито."
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr "%{created} Ñтворено, %{merged} об’єднано, %{closed} закрито."
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11541,6 +11779,9 @@ msgstr ""
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr "Ðналітика внеÑків Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ñ‡, запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° подій відправки з %{start_date}"
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr ""
+
msgid "ContributionAnalytics|Failed to load the contribution stats"
msgstr ""
@@ -11586,7 +11827,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11607,8 +11851,8 @@ msgstr "КількіÑÑ‚ÑŒ внеÑків на кожного учаÑника Ð
msgid "Contributor"
msgstr "Співавтор"
-msgid "Contributors"
-msgstr "УчаÑники"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "Керувати адреÑами електронної пошти, пов’Ñзаними з вашим обліковим запиÑом"
@@ -11679,6 +11923,9 @@ msgstr "Скопіювати команди"
msgid "Copy commit SHA"
msgstr "Скопіювати SHA коміту"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr "Копіювати Ñередовище"
@@ -11925,8 +12172,8 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
-msgstr "Країна"
+msgid "Country / Region"
+msgstr ""
msgid "Counts"
msgstr ""
@@ -12114,6 +12361,9 @@ msgstr "Створити"
msgid "Create or close an issue."
msgstr "Створити або закрити задачу."
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr "Створіть або імпортуйте Ñвій перший проєкт"
@@ -12363,9 +12613,6 @@ msgstr "Створено"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "Створено гілку та запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ Ñ†Ñ–Ñ”Ñ— задачі."
-msgid "Created at"
-msgstr "Створено в "
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "Створено гілку \"%{branch_name}\" та запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ Ñ†Ñ–Ñ”Ñ— задачі."
@@ -12573,6 +12820,9 @@ 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 ""
@@ -12672,8 +12922,8 @@ msgstr "Задачу вперше додано на дошку"
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "Задачу вперше додано до етапу"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
-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 "Задача, вперше згадана у коміті"
@@ -12841,9 +13091,6 @@ msgstr "Призначений об'єкт не підтримуєтьÑÑ"
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr "Ð”Ð»Ñ Ð²Ñ–Ð·ÑƒÐ°Ð»Ñ–Ð·Ð°Ñ†Ñ–Ñ— DAG потрібно щонайменше 3 залежних завданнÑ."
-msgid "DAST Configuration"
-msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ DAST"
-
msgid "DAST configuration not found"
msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ DAST не знайдена"
@@ -13757,6 +14004,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr "Видалити ключ Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ"
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr "Видалити епік"
@@ -13799,6 +14049,9 @@ msgstr "Видалити реліз %{release}?"
msgid "Delete row"
msgstr "Видалити Ñ€Ñдок"
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14566,6 +14819,9 @@ msgstr "уÑпішно"
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14669,12 +14925,15 @@ msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ новий коментар. Будь Ð
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr "Ðе вдалоÑÑ Ñтворити нове обговореннÑ. Будь лаÑка, Ñпробуйте ще раз."
-msgid "DesignManagement|Could not update discussion. Please try again."
-msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ обговореннÑ. Будь лаÑка, Ñпробуйте ще раз."
+msgid "DesignManagement|Could not delete comment. Please try again."
+msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
msgstr ""
+msgid "DesignManagement|Could not update discussion. Please try again."
+msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ обговореннÑ. Будь лаÑка, Ñпробуйте ще раз."
+
msgid "DesignManagement|Deselect all"
msgstr "ЗнÑти Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ Ð· уÑÑ–Ñ…"
@@ -14777,6 +15036,9 @@ msgstr "ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ DevOps"
msgid "Developer"
msgstr "Розробник"
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr "ПриÑтрої (необов’Ñзково)"
@@ -14972,6 +15234,9 @@ msgstr "Ваше викориÑтаннÑ"
msgid "Diagram (%{language})"
msgstr "Діаграма (%{language})"
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -15131,9 +15396,6 @@ msgstr "Discord СповіщеннÑ"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr "ÐадÑилати ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ події проєкту на канал Discord."
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr "Відкрийте GitLab Geo"
@@ -15573,6 +15835,9 @@ msgstr "Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ»ÑŽÑ‡ Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ"
msgid "Edit description"
msgstr "Редагувати опиÑ"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "Редагувати Ñередовище"
@@ -15597,6 +15862,9 @@ msgstr "Редагувати ідентифікацію Ð´Ð»Ñ %{user_name}"
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr "Редагувати в редакторі конвеєра"
@@ -15615,9 +15883,15 @@ msgstr "Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾ÑиланнÑ"
msgid "Edit merge requests"
msgstr "Редагувати запити на злиттÑ"
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "Редагувати публічний ключ Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr "Редагувати бічну панель"
@@ -16074,6 +16348,9 @@ msgstr "Введіть 2FA Ð´Ð»Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ñƒ адмініÑтратора"
msgid "Enter Admin Mode"
msgstr "Увійти в Режим ÐдмініÑтратора"
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "Введіть номер"
@@ -16119,7 +16396,7 @@ msgstr "Введіть Ð¾Ð¿Ð¸Ñ %{name}"
msgid "Enter the %{name} title"
msgstr "Введіть %{name} заголовок"
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -16137,6 +16414,9 @@ msgstr "Введіть пароль Ð´Ð»Ñ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¸Ñ… паролем ÑÐ
msgid "Enter the username for password-protected Elasticsearch servers."
msgstr "Введіть ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача Ð´Ð»Ñ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¸Ñ… паролем Ñерверів Elasticsearch."
+msgid "Enter verification code"
+msgstr ""
+
msgid "Enter your Packagist server. Defaults to https://packagist.org."
msgstr "Введіть Ñвій Ñервер Packagist. За замовчуваннÑм https://packagist.org."
@@ -16431,6 +16711,9 @@ msgstr "Дошки епіків"
msgid "Epic actions"
msgstr "Дії епіку"
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ епік."
@@ -16542,6 +16825,9 @@ 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 ""
@@ -16830,6 +17116,9 @@ 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 "Створити політику еÑкалації в GitLab"
@@ -17110,6 +17399,9 @@ msgstr "Збір даних"
msgid "Exactly one of %{attributes} is required"
msgstr "Потрібен лише один з %{attributes}"
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -17134,6 +17426,9 @@ 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 "Без ÑƒÑ€Ð°Ñ…ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð² злиттÑ. Обмежено до %{limit} комітів."
@@ -17335,6 +17630,9 @@ 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 "Сертифікат Ð´Ð»Ñ Ð°Ð²Ñ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— із зовнішньою Ñлужбою авторизації. Якщо він пуÑтий, Ñертифікат Ñервера перевірÑєтьÑÑ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу через HTTPS."
@@ -17353,6 +17651,9 @@ 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 "Увімкнути контроль за клаÑифікацією за допомогою зовнішньої Ñлужби"
@@ -17929,9 +18230,6 @@ msgstr "лют."
msgid "February"
msgstr "лютий"
-msgid "Feedback and Updates"
-msgstr "Зворотний зв'Ñзок та оновленнÑ"
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr "Отримайте та перевірте гілку функцій цього запиту на злиттÑ:"
@@ -18055,6 +18353,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr "Фільтр конвеєрів"
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "Фільтрувати результати"
@@ -18211,9 +18512,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr "Ð”Ð»Ñ ÑˆÐ²Ð¸Ð´ÑˆÐ¾Ð³Ð¾ переглÑду, не вÑÑ Ñ–ÑÑ‚Ð¾Ñ€Ñ–Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶Ð°Ñ”Ñ‚ÑŒÑÑ."
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -18355,9 +18653,6 @@ msgstr "Формат: %{dateFormat}"
msgid "Framework successfully deleted"
msgstr "Фреймворк уÑпішно видалено"
-msgid "Free"
-msgstr "Безоплатно"
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Безкоштовна пробна верÑÑ–Ñ GitLab.com Ultimate"
@@ -19174,13 +19469,22 @@ msgstr "Проміжок чаÑу Ð·Ð²Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ” бути чиÑлÐ
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "Ð§Ð°Ñ Ð·Ð²Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ” Ñтановити від %{minTimePeriod}до%{maxTimePeriod} Ñекунд."
+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 "КориÑтувачі, на Ñких не поширюєтьÑÑ Ð»Ñ–Ð¼Ñ–Ñ‚ на Ð·Ð»Ð¾Ð²Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Git."
-msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -19231,6 +19535,9 @@ msgstr "GitLab KAS"
msgid "GitLab Pages"
msgstr "Gitlab Pages"
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr "GitLab Shell"
@@ -19255,6 +19562,12 @@ msgstr "Запит на обліковий Ð·Ð°Ð¿Ð¸Ñ GitLab відхилено"
msgid "GitLab commit"
msgstr "GitLab коміт"
+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 ""
@@ -19270,9 +19583,6 @@ msgstr "GitLab Ð´Ð»Ñ Jira Cloud"
msgid "GitLab group: %{source_link}"
msgstr "GitLab група : %{source_link}"
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr "GitLab повідомлÑÑ” ваÑ, Ñкщо доÑтупна нова верÑÑ–Ñ. %{link_start}Яку інформацію збирає GitLab Inc.?%{link_end}"
@@ -19321,13 +19631,6 @@ msgstr "ВерÑÑ–Ñ GitLab"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab Ñтворить гілку у вашому форку та розпочне запит на злиттÑ."
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -19421,12 +19724,18 @@ msgstr "Ðепідтверджено"
msgid "GitLabPages|Updating your Pages configuration..."
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 "Якщо ввімкнено, уÑÑ– Ñпроби відвідати ваш вебÑайт через HTTP автоматично перенаправлÑÑŽÑ‚ÑŒÑÑ Ð½Ð° HTTPS за допомогою відповіді з кодом ÑтатуÑу 301. Потрібний дійÑний Ñертифікат Ð´Ð»Ñ Ð²ÑÑ–Ñ… доменів. %{docs_link_start}ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ.%{link_end}"
@@ -19466,6 +19775,9 @@ msgstr "URL-адреÑа хоÑту Gitea"
msgid "Gitea Import"
msgstr "Імпорт з Gitea"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19478,13 +19790,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
-msgstr "Ð’ÐºÐ»Ð°Ð´ÐµÐ½Ð½Ñ Ð·Ð°Ð´Ð°Ñ‡"
+msgid "GithubImporter|Issue links"
+msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19502,7 +19814,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19556,6 +19868,9 @@ msgstr "Ðадано доÑтуп %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr "Даний епік уже пов’Ñзаний із цим епіком."
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr "Глобальний пошук Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— облаÑÑ‚Ñ– вимкнено"
@@ -19628,6 +19943,9 @@ msgstr "Свіжі задачі"
msgid "GlobalSearch|Recent merge requests"
msgstr "ОÑтанні запити на злиттÑ"
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19682,15 +20000,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr "група"
-
msgid "GlobalSearch|in %{scope}"
msgstr "в %{scope}"
-msgid "GlobalSearch|project"
-msgstr "проєкт"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19907,6 +20219,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 "Зрозуміло"
@@ -20096,6 +20432,9 @@ msgstr "Ðазва групи (ваша організаціÑ)"
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr "ВміÑÑ‚ оглÑдової Ñторінки групи"
@@ -20447,6 +20786,9 @@ msgstr "Зміна URL-адреÑи групи може мати небажанÑ
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 "Фреймворки відповідноÑÑ‚Ñ–"
@@ -20705,6 +21047,9 @@ 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 ""
@@ -20720,6 +21065,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr "Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð³Ñ€ÑƒÐ¿ через прÑму передачу вимкнуто."
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr "Ðемає доÑтупних параметрів імпорту"
@@ -21100,6 +21451,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "Привіт %{username}!"
@@ -21447,6 +21801,9 @@ 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 "Ð”Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ вам потрібно підтвердити вашу оÑобу. Ми надіÑлали код Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð½Ð° %{email}"
@@ -21546,6 +21903,9 @@ msgstr "Підтвердити Ñвою оÑобу"
msgid "IdentityVerification|We sent a new code to +%{phoneNumber}"
msgstr "Ми надіÑлали новий код на +%{phoneNumber}"
+msgid "IdentityVerification|We've sent a verification code to %{email}"
+msgstr ""
+
msgid "IdentityVerification|We've sent a verification code to +%{phoneNumber}"
msgstr ""
@@ -21588,15 +21948,24 @@ msgstr "Якщо увімкнено, тоді влаÑники груп змож
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "Якщо буде увімкнено цей пункт, нові членÑтва в групах та дозволи будуть додані лише за допомогою Ñинхронізації LDAP"
+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 "Якщо кількіÑÑ‚ÑŒ активних кориÑтувачів перевищує ліміт кориÑтувачів, то за наÑтупної звірки ліцензії з Ð²Ð°Ñ Ð±ÑƒÐ´Ðµ знÑто плату за кількіÑÑ‚ÑŒ %{users_over_license_link}."
@@ -21657,7 +22026,7 @@ msgstr "Якщо ви втратите коди відновленнÑ, ви мÐ
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "Якщо ви нещодавно ввійшли та впізнали цю IP-адреÑу, ви можете проігнорувати цей лиÑÑ‚."
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21887,6 +22256,9 @@ msgstr "Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ невдале"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr "Ðе вдалоÑÑ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ñ‚Ð¸ проєкт: %{reason}"
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr "Запит проÑторів імен не вдавÑÑ"
@@ -22293,8 +22665,8 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr "Швидка розробка, Ñпрощена"
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
-msgstr "Зменште ризик безпеки та відповідноÑÑ‚Ñ–"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
+msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
msgstr ""
@@ -22956,12 +23328,18 @@ msgstr "Ð’Ñтавити зображеннÑ"
msgid "Insert link"
msgstr "Ð’Ñтавити поÑиланнÑ"
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr "Ð’Ñтавити Ñ€Ñдок піÑлÑ"
msgid "Insert row before"
msgstr "Ð’Ñтавити Ñ€Ñдок перед"
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "Додати пропозицію"
@@ -23137,12 +23515,15 @@ 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 GitLab.com slash commands in a Slack workspace."
-msgstr "Увімкнути команди GitLab.com у робочому проÑторі Slack."
-
msgid "Integrations|Enable SSL verification"
msgstr "Увімкнути перевірку SSL"
@@ -23158,6 +23539,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr "Введіть ваш пÑевдонім"
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr "Ðе вдалоÑÑ Ð·Ð²â€™Ñзати проÑÑ‚Ñ–Ñ€ імен. Будь лаÑка, Ñпробуйте ще раз."
@@ -23446,8 +23830,8 @@ msgstr ""
msgid "Invalid repository path"
msgstr "Ðеправильний шлÑÑ… до репозиторію"
-msgid "Invalid rule"
-msgstr "ÐедійÑне правило"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr "Ðеправильна відповідь від Ñервера"
@@ -23575,9 +23959,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr "Працювати в GitLab з колегами краще!"
@@ -23849,6 +24230,12 @@ msgstr "Тип задачі"
msgid "Issue already promoted to epic."
msgstr "Задачу вже переведено до епіку."
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr "Ðеможливо знайти задачу."
@@ -24074,6 +24461,9 @@ msgstr ""
msgid "Issue|Title"
msgstr "Ðазва"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24611,9 +25001,24 @@ msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð±ÑƒÐ»Ð¾ перезапущене"
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr "ЗавданнÑ"
@@ -25306,6 +25711,15 @@ msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ."
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
msgstr "%{percentage}%{percentSymbol} завершено"
+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 "Додати влаÑників коду"
@@ -25387,6 +25801,9 @@ msgstr ""
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "Розпочати безкоштовну пробну верÑÑ–ÑŽ GitLab Ultimate"
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr ""
+
msgid "LearnGitLab|Submit a merge request (MR)"
msgstr ""
@@ -25396,6 +25813,9 @@ 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 ""
@@ -25411,9 +25831,6 @@ msgstr "ЗвернітьÑÑ Ð´Ð¾ Ñвого адмініÑтратора, щоÐ
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr "Ок, поїхали"
@@ -25429,6 +25846,9 @@ msgstr "Вийти з Режиму ÐдмініÑтратора"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "Вийти з режиму редагуваннÑ? УÑÑ– незбережені зміни буде втрачено."
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "Залишити групу"
@@ -25690,6 +26110,13 @@ msgstr "Обмежувати розмір завдань Sidekiq, що зберÑ
msgid "Limiting mode"
msgstr "Режим обмеженнÑ"
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Line changes"
msgstr "Зміни Ñ€Ñдка"
@@ -25717,6 +26144,9 @@ msgstr ""
msgid "Link copied"
msgstr "ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñкопійовано"
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr "ТекÑÑ‚ поÑиланнÑ"
@@ -25810,9 +26240,6 @@ msgstr "СпиÑок доÑтупних репозиторіїв"
msgid "List of all commits"
msgstr "СпиÑок вÑÑ–Ñ… комітів"
-msgid "List of all merge commits"
-msgstr "СпиÑок уÑÑ–Ñ… комітів злиттÑ"
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25855,6 +26282,9 @@ msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÑтатиÑтики учаÑників груÐ
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð², директорій та підмодулів за шлÑхом %{path} Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ %{ref}"
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr "Завантажити більше"
@@ -25894,6 +26324,9 @@ msgstr "Заблокувати файл?"
msgid "Lock memberships to LDAP synchronization"
msgstr "ЗафікÑувати належноÑÑ‚Ñ– (до груп) через LDAP Ñинхронізацію"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr "Заблокувати запит на злиттÑ"
@@ -25912,9 +26345,6 @@ msgstr "Закріпити за поточними проєктами"
msgid "Locked"
msgstr "Заблоковано"
-msgid "Locked Files"
-msgstr "Заблоковані файли"
-
msgid "Locked by %{fileLockUserName}"
msgstr "Заблоковано %{fileLockUserName}"
@@ -25984,9 +26414,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "ЗЛИТО"
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr "ПовернутиÑÑ Ð´Ð¾ запиту на злиттÑ"
@@ -26023,10 +26450,7 @@ msgstr "Показувати лише зміни"
msgid "MRDiff|Show full file"
msgstr "Показувати файл повніÑÑ‚ÑŽ"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26518,6 +26942,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr "МакÑимальний розмір Ð´Ð»Ñ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ (МБ)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26599,12 +27026,21 @@ 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 "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|must be top-level namespace"
msgstr ""
@@ -26829,18 +27265,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: уÑÑ– залежноÑÑ‚Ñ– запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¼Ð°ÑŽÑ‚ÑŒ бути об’єднані."
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¼Ð°Ñ” бути позначений Ñк готовий. Він вÑе ще позначений Ñк чернетка."
-
-msgid "Merge blocked: new changes were just added."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: щойно додані нові зміни."
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: конвеєр має бути уÑпішним. Він чекає ручної роботи, щоб продовжити."
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: вихідна гілка повинна бути перебазована(rebased) на цільову гілку."
-
msgid "Merge commit SHA"
msgstr "SHA коміту злиттÑ"
@@ -26913,9 +27340,6 @@ msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ â€” це ÑпоÑіб запропонувÐ
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26928,6 +27352,27 @@ 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 "Закомітити в гілку-джерело"
@@ -27542,6 +27987,9 @@ msgstr[3] "Етапів"
msgid "Milestone due date"
msgstr "Дата Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ ÐµÑ‚Ð°Ð¿Ñƒ"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "СпиÑки етапів не доÑтупні з вашою поточною ліцензією"
@@ -27722,6 +28170,12 @@ msgstr "Мінімальна доÑтупна пропуÑкна здатніÑÑ
msgid "Minutes"
msgstr "Хвилин"
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr "ÐапрÑмок віддзеркаленнÑ"
@@ -27734,6 +28188,9 @@ msgstr "Віддзеркалити репозиторій"
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr "КориÑтувач Ð´Ð»Ñ Ð²Ñ–Ð´Ð´Ð·ÐµÑ€ÐºÐ°Ð»ÐµÐ½Ð½Ñ"
@@ -27794,31 +28251,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -28164,6 +28636,9 @@ msgstr "ПроÑтори імен"
msgid "Namespaces to index"
msgstr "ПроÑтори імен Ð´Ð»Ñ Ñ–Ð½Ð´ÐµÐºÑуваннÑ"
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "ІменуваннÑ, теми, аватар"
@@ -28212,10 +28687,16 @@ msgstr "Червоний"
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -28330,9 +28811,6 @@ msgstr "Ðова вимога"
msgid "New Snippet"
msgstr "Ðовий Ñніпет"
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr "Ðовий КориÑтувач"
@@ -28420,9 +28898,6 @@ msgstr "Ðова назва"
msgid "New password"
msgstr "Ðовий пароль"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "Ðовий проєкт"
@@ -28777,6 +29252,15 @@ 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 "Ðе вибрано джерело"
@@ -28862,13 +29346,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -29178,12 +29665,24 @@ msgstr "%{paragraph_start}Привіт %{name}!%{paragraph_end} %{paragraph_star
msgid "Notify|%{project_link_start}Download%{project_link_end} the project export."
msgstr "%{project_link_start}Завантажте%{project_link_end} екÑпорт проєкту."
+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|%{update_at_start} Last update at %{update_at_mid} %{last_update_at} %{update_at_end}"
msgstr "%{update_at_start} ОÑтаннє Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ %{update_at_mid} %{last_update_at} %{update_at_end}"
msgid "Notify|%{updated_by_user_name} pushed new commits to merge request %{mr_link}"
msgstr "%{updated_by_user_name} надіÑлав нові коміти Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{mr_link}"
+msgid "Notify|%{work_items} successfully imported."
+msgstr ""
+
msgid "Notify|A new GPG key was added to your account:"
msgstr "Ðовий ключ GPG додано до вашого облікового запиÑу:"
@@ -29232,9 +29731,18 @@ msgstr "Помилка аналізу файлу CSV. ПереконайтеÑÑ
msgid "Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check if these lines have an issue title."
msgstr "Знайдені помилки %{singular_or_plural_line}: %{error_lines}. Будь лаÑка, перевірте, чи ці Ñ€Ñдки мають заголовок проблеми."
+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 "Відбиток: %{fingerprint}"
+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 "Привіт %{username}!"
@@ -29262,9 +29770,6 @@ msgstr "Логи можуть міÑтити конфіденційні дані
msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict."
msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{merge_request} більше не може бути злитий через конфлікт."
-msgid "Notify|Merge request %{merge_request} was %{mr_status}"
-msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{merge_request} був %{mr_status}"
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{merge_request} був %{mr_status} кориÑтувачем %{updated_by}"
@@ -29301,6 +29806,9 @@ msgstr "Ðова задача: %{project_issue_url}"
msgid "Notify|No preview for this file type"
msgstr "Ðемає попереднього переглÑду Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ типу файлу"
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr "Конвеєр #%{pipeline_id} вийшов з ладу!"
@@ -29310,6 +29818,9 @@ msgstr "Конвеєр %{pipeline_link} запущено"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
msgstr "Конвеєр виправлено, і #%{pipeline_id} виконано!"
+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 "Проєкт %{old_path_with_namespace} переміщено в інше міÑце."
@@ -29322,6 +29833,9 @@ msgstr "Проєкт %{project_name} уÑпішно екÑпортовано."
msgid "Notify|Remote mirror"
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 "ÐдмініÑтратор Ñтворив Ð´Ð»Ñ Ð²Ð°Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¸Ð¹ запиÑ. Тепер ви Ñ” учаÑником компанії GitLab заÑтоÑунку."
@@ -29800,6 +30314,9 @@ 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 ""
@@ -29869,9 +30386,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -30167,28 +30681,34 @@ 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 services."
-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 web hooks and services"
-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"
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
msgstr ""
msgid "OutboundRequests|Outbound requests"
msgstr "Вихідні запити"
-msgid "OutboundRequests|Requests to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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 once and uses them to submit requests."
+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."
@@ -30993,6 +31513,9 @@ msgstr "Очікує видаленнÑ"
msgid "Pending comments"
msgstr "Коментарі в очікуванні"
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "Очікує видаленнÑ"
@@ -31182,9 +31705,6 @@ msgstr ""
msgid "Pick a name"
msgstr "Виберіть ім'Ñ"
-msgid "Pin code"
-msgstr "PIN-код"
-
msgid "Pipeline"
msgstr "Конвеєр"
@@ -31383,6 +31903,9 @@ msgstr "ÐžÑ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ð¼Ñ–Ñту CI..."
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 ""
@@ -31608,6 +32131,9 @@ 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 "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð² Ð´Ð»Ñ \"%{project_name}\" уÑпішно оновлено."
@@ -31659,9 +32185,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr "ОчиÑтити кеш раннер"
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31707,6 +32230,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31758,8 +32287,8 @@ msgstr "ВлаÑник"
msgid "Pipelines|Pipeline Editor"
msgstr "Редактор Конвеєрів"
-msgid "Pipelines|Pipeline syntax is correct."
-msgstr "СинтакÑÐ¸Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð° правильний."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr "Кеш проєкту уÑпішно очищено."
@@ -31767,6 +32296,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31803,14 +32335,14 @@ 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."
-msgstr "Ð¦Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ GitLab CI недійÑна."
+msgid "Pipelines|This GitLab CI configuration is invalid. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is invalid:"
msgstr "Ð¦Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ GitLab CI недійÑна:"
-msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}."
-msgstr "Ð¦Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ GitLab CI недійÑна. %{reason}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
msgstr ""
@@ -31839,6 +32371,12 @@ 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 ""
@@ -31860,6 +32398,9 @@ msgstr "ПереглÑнути об’єднаний YAML"
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 ""
@@ -31869,6 +32410,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -32184,6 +32728,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "Будь лаÑка, активуйте Ñ– мігруйте на хешоване Ñховище, щоб уникнути проблем із безпекою та забезпечити ціліÑніÑÑ‚ÑŒ даних. %{migrate_link}"
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "Будь лаÑка, введіть невід'ємне чиÑло"
@@ -32205,6 +32752,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -32265,8 +32815,8 @@ msgstr "Будь лаÑка, виберіть"
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
-msgstr "Будь лаÑка, виберіть країну"
+msgid "Please select a country / region"
+msgstr ""
msgid "Please select a group"
msgstr ""
@@ -32619,6 +33169,9 @@ msgstr ""
msgid "Preview payload"
msgstr "Попередній переглÑд кориÑного навантаженнÑ"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "Попередні артефакти"
@@ -32688,239 +33241,197 @@ msgstr ""
msgid "Proceed"
msgstr "Продовжити"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
+msgid "Product analytics"
+msgstr "Ðналітика продукту"
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|Analyze your product with Product Analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product Analytics|Back to dashboards"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "Product Analytics|Creating your product analytics instance..."
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "Product Analytics|Identifies the sender of tracking events"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "Product Analytics|Import the new package into your JS code:"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
-msgid "Product Analytics|Instrument your application"
+msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
msgstr ""
-msgid "Product Analytics|Instrumentation details"
+msgid "ProductAnalytics|An error occurred while fetching data. Refresh the page to try again."
msgstr ""
-msgid "Product Analytics|SDK App ID"
+msgid "ProductAnalytics|Analyze your product with Product Analytics"
msgstr ""
-msgid "Product Analytics|SDK Host"
-msgstr "ХоÑÑ‚ SDK"
-
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Any Click on elements"
msgstr ""
-msgid "Product Analytics|Set up product analytics"
-msgstr "Ðалаштувати аналітику продукту"
+msgid "ProductAnalytics|Audience"
+msgstr "ÐудиторіÑ"
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
-msgstr ""
+msgid "ProductAnalytics|Cancel Edit"
+msgstr "СкаÑувати редагуваннÑ"
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "Product analytics"
-msgstr "Ðналітика продукту"
-
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
-msgstr "Додати до панелі керуваннÑ"
-
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|Compares click events against each other"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|All pages"
-msgstr "Ð’ÑÑ– Ñторінки"
-
-msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|An error occurred while fetching data. Refresh the page to try again."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Any Click on elements"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
-msgid "ProductAnalytics|Audience"
-msgstr "ÐудиторіÑ"
-
-msgid "ProductAnalytics|Browser"
+msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Event Type"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
-msgstr "СкаÑувати редагуваннÑ"
-
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Events"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Events grouped by %{granularity}"
msgstr ""
-msgid "ProductAnalytics|Click Events"
+msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Code"
-msgstr "Код"
-
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Compares click events against each other"
+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|Compares feature usage of all features against each other"
-msgstr ""
+msgid "ProductAnalytics|Go back"
+msgstr "ПовернутиÑÑ Ð½Ð°Ð·Ð°Ð´"
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Dimensions"
+msgid "ProductAnalytics|Instrument your application"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr "Редагувати"
-
-msgid "ProductAnalytics|Event Type"
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
-msgid "ProductAnalytics|Events"
+msgid "ProductAnalytics|Measure All tracked Events"
msgstr ""
-msgid "ProductAnalytics|Events grouped by %{granularity}"
+msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Events over time"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr "ПовернутиÑÑ Ð½Ð°Ð·Ð°Ð´"
-
-msgid "ProductAnalytics|Host"
-msgstr "ХоÑÑ‚"
-
-msgid "ProductAnalytics|Language"
-msgstr "Мова"
-
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|Measure All tracked Events"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Measure all or specific Page Views"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|OS"
-msgstr "ОС"
-
-msgid "ProductAnalytics|OS Version"
-msgstr "ВерÑÑ–Ñ ÐžÐ¡"
-
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+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|Page Path"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Page Title"
-msgstr "Заголовок Ñторінки"
-
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Pages"
-msgstr "Сторінки"
-
-msgid "ProductAnalytics|Panel"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|The host to send all tracking events to"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+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|Single Statistic"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
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."
+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|URL"
-msgstr "URL"
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
+msgstr ""
msgid "ProductAnalytics|User activity"
msgstr "ÐктивніÑÑ‚ÑŒ кориÑтувача"
@@ -32928,12 +33439,6 @@ msgstr "ÐктивніÑÑ‚ÑŒ кориÑтувача"
msgid "ProductAnalytics|Users"
msgstr "КориÑтувачі"
-msgid "ProductAnalytics|Viewport"
-msgstr "ПереглÑд"
-
-msgid "ProductAnalytics|Visualization Type"
-msgstr "Тип візуалізації"
-
msgid "ProductAnalytics|What do you want to measure?"
msgstr ""
@@ -33099,6 +33604,12 @@ msgstr "Від'єднати"
msgid "Profiles|Disconnect %{provider}"
msgstr "Від'єднати %{provider}"
+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|Do not show on profile"
msgstr "Ðе відображати у профілі"
@@ -33348,7 +33859,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Вам необхідно змінити влаÑника або видалити ці групи перед тим Ñк видалити ваш обліковий запиÑ."
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33522,6 +34033,9 @@ msgstr "УчаÑники проєкту"
msgid "Project milestone"
msgstr "Етап проєкту"
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr "Ðазва проєкту"
@@ -33534,6 +34048,9 @@ msgstr "Проєкт або Група"
msgid "Project order will not be saved as local storage is not available."
msgstr "ПорÑдок проєктів не буде збережено, тому що локальне Ñховище недоÑтупне."
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr "ШлÑÑ… до проєкту"
@@ -33561,6 +34078,9 @@ 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 ""
@@ -33657,9 +34177,21 @@ msgstr "ID проєкту: %{project_id}"
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 ""
@@ -33672,6 +34204,9 @@ msgstr "Допоможіть нам покращити цю Ñторінку"
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Ð¿Ð¾ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ‚ÐµÑтами"
@@ -33714,8 +34249,11 @@ 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 "ProjectSelect| or group"
-msgstr "або групу"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
msgid "ProjectSelect|No matching results"
msgstr ""
@@ -33729,9 +34267,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr "Виберіть проєкт"
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr "Помилка при отриманні проєктів"
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33861,9 +34396,6 @@ msgstr "Додаткові налаштуваннÑ, Ñкі впливають Ð
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr "Дозволити"
@@ -34014,9 +34546,6 @@ msgstr "ІнфраÑтруктура"
msgid "ProjectSettings|Internal"
msgstr "Внутрішній"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr "Задачі"
@@ -34059,9 +34588,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr "Пропозиції щодо злиттÑ"
@@ -34098,9 +34624,6 @@ msgstr "Pages"
msgid "ProjectSettings|Pages for project documentation."
msgstr "Сторінки Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ð½Ð¾Ñ— документації."
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "Конвеєри мають бути уÑпішними"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr "Запобігає прÑмому підключенню до потенційно конфіденційних медіафайлів"
@@ -34143,11 +34666,11 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr "Пошук теми"
-msgid "ProjectSettings|Security & Compliance"
-msgstr "Безпека та відповідніÑÑ‚ÑŒ"
+msgid "ProjectSettings|Security and Compliance"
+msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
-msgstr "Безпека та відповідніÑÑ‚ÑŒ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
+msgid "ProjectSettings|Security and compliance for this project."
+msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
msgstr "Виберіть гілку за замовчуваннÑм Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту та налаштуйте шаблон Ð´Ð»Ñ Ð½Ð°Ð·Ð² гілок."
@@ -34170,9 +34693,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr "Показувати поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‡Ð¸ переглÑду запиту на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ñ€Ð¸ відправці із командного Ñ€Ñдка"
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr "Сніпети"
@@ -34407,6 +34927,9 @@ msgstr "Проєкти (%{count})"
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr "Проєкти уÑпішно отримано"
@@ -34533,6 +35056,9 @@ 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 "Варіанти імпорту не доÑтупні"
@@ -34548,6 +35074,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "ÐžÐ¿Ð¸Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ %{tag_start}(необов’Ñзково)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34728,9 +35257,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34839,12 +35365,6 @@ msgstr "Якщо у Ð²Ð°Ñ Ð±Ð°Ð³Ð°Ñ‚Ð¾ задач, важко зрозумітÐ
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr "шаблони опиÑу"
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr "щоб допомогти вашим учаÑникам ефективно ÑпілкуватиÑÑ!"
-
msgid "Prompt users to upload SSH keys"
msgstr "Пропонувати кориÑтувачам завантажувати Ñвої ключі SSH"
@@ -35016,9 +35536,29 @@ msgstr "Ви можете додавати лише групи, Ñкі ÑпілÑ
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr "Ð Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÐµÐ½Ð¾"
@@ -35028,10 +35568,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -35040,15 +35592,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} буде доÑупне Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу Ð´Ð»Ñ Ñ€Ð¾Ð·Ñ€Ð¾Ð±Ð½Ð¸ÐºÑ–Ð². Ви впевнені?"
@@ -35058,6 +35619,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "Ð Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÐµÐ½Ð¾"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35514,24 +36078,15 @@ msgstr "Готовий до злиттÑ!"
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr "Rebase"
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr "ВідбуваєтьÑÑ rebase"
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35607,6 +36162,9 @@ 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] "ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‡ÐµÑ€ÐµÐ· Ñекунду Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð°ÐºÑ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ Ñтану..."
@@ -35644,13 +36202,13 @@ msgstr "ЗареєÑтруватиÑÑ"
msgid "Register / Sign In"
msgstr "ЗареєÑтруватиÑÑ / Увійти"
-msgid "Register Two-Factor Authenticator"
-msgstr "ЗареєÑтрувати двофакторний автентифікатор"
+msgid "Register a WebAuthn device"
+msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "ЗареєÑтрувати універÑальний двофакторний приÑтрій (U2F)"
+msgid "Register a one-time password authenticator"
+msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35743,6 +36301,9 @@ msgstr "Відхилено (закрито)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr "ВідноÑитьÑÑ Ð´Ð¾ %{issuable_type} %{add_related_issue_link}"
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36692,15 +37253,21 @@ msgstr "Вимога %{reference} була відкрита знову"
msgid "Requirement %{reference} has been updated"
msgstr "Вимогу %{reference} було оновлено"
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr "Заголовок вимоги не може міÑтити більше %{limit} знаків."
-
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] "Ðеобхідно ще %d Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ відповідних кориÑтувачів."
@@ -36883,9 +37450,6 @@ msgstr ""
msgid "Resume"
msgstr "Продовжити"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr "Спробувати знову"
@@ -37059,9 +37623,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr "Виконати ручне Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð½Ð¾Ð²Ñƒ"
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -37144,6 +37705,9 @@ 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|Administrator"
msgstr "ÐдмініÑтратор"
@@ -37207,6 +37771,9 @@ 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 ""
@@ -37225,6 +37792,9 @@ 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 "Скопіювати інÑтрукцію"
@@ -37283,9 +37853,15 @@ msgstr "Увімкнути Ð¾Ñ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð·Ð°Ñтарілого раннер"
msgid "Runners|Enable stale runner cleanup?"
msgstr "Увімкнути Ð¾Ñ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð·Ð°Ñтарілого раннер?"
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr "Введіть кількіÑÑ‚ÑŒ Ñекунд. Цей Ñ‡Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ” пріоритет над меншими чаÑами очікуваннÑ, вÑтановленими Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ."
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr "Виконавець"
@@ -37298,6 +37874,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr "Група"
@@ -37314,7 +37896,10 @@ msgid "Runners|Idle"
msgstr "ПроÑтій"
msgid "Runners|If both settings are disabled, new runners cannot be registered."
-msgstr "Якщо обидва Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾, нові раннери не можуть бути зареєÑтровані. Якщо обидва параметри вимкнено, нових бігунів реєÑтрувати не можна."
+msgstr "Якщо обидва Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾, нові раннери не можуть бути зареєÑтровані."
+
+msgid "Runners|Install GitLab Runner"
+msgstr ""
msgid "Runners|Install a runner"
msgstr "Ð’Ñтановити раннер"
@@ -37343,6 +37928,12 @@ msgstr "Закріплено за цим проєктом"
msgid "Runners|Maintenance note"
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 "МакÑимальний Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ"
@@ -37352,6 +37943,9 @@ msgstr "УчаÑники %{type} можуть зареєÑтрувати ранÐ
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr "Ім'Ñ"
@@ -37364,6 +37958,9 @@ msgstr "Ðіколи не контактував:"
msgid "Runners|Never expires"
msgstr "Ðіколи не закінчуєтьÑÑ"
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr "Можна реєÑтрувати нову групу раннерів"
@@ -37406,6 +38003,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr "ВлаÑник"
@@ -37440,6 +38040,12 @@ msgstr "Захищені"
msgid "Runners|Recommended"
msgstr "Рекомендовано"
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr "ЗареєÑтрувати груповий раннер"
@@ -37455,6 +38061,9 @@ 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 "Токен Ð´Ð»Ñ Ñ€ÐµÑ”Ñтрації"
@@ -37479,6 +38088,9 @@ msgstr "Раннер #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
msgstr "Раннер %{name} було видалено"
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr "РеєÑÑ‚Ñ€Ð°Ñ†Ñ–Ñ Ñ€Ð°Ð½Ð½ÐµÑ€Ð°"
@@ -37494,6 +38106,12 @@ 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 ""
@@ -37566,9 +38184,15 @@ 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 ""
@@ -37602,6 +38226,12 @@ msgstr "ЗаÑтарілі:"
msgid "Runners|Status"
msgstr "СтатуÑ"
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr "Заборонити раннеру приймати нові завданнÑ."
@@ -37611,6 +38241,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr "Проєкт, група або інÑтанÑ, де зареєÑтровано раннер. ІнÑÑ‚Ð°Ð½Ñ Ñ€Ð°Ð½Ð½ÐµÑ€Ð¸ завжди належать адмініÑтратору."
@@ -37630,6 +38263,9 @@ msgstr[3] ""
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 runner has not run any jobs."
msgstr ""
@@ -37678,6 +38314,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr "ВикориÑтовуйте раннер Ð´Ð»Ñ Ð·Ð°Ð²Ð´Ð°Ð½ÑŒ без тегів, крім завдань із тегами."
@@ -37732,15 +38371,6 @@ msgstr "проєкт"
msgid "Runners|shared"
msgstr "Ñпільний"
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr "ВлаÑник"
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr "ВиконуєтьÑÑ"
@@ -37762,6 +38392,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr "SAML Ð´Ð»Ñ %{group_name}"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr "Єдиний вхід SAML"
@@ -37786,9 +38419,6 @@ msgstr "Щоб дозволити %{strongOpen}%{group_name}%{strongClose} кеÑ
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr "Токен SCIM"
@@ -37918,16 +38548,19 @@ msgstr "%{period} %{days} на %{time}"
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr "%{rules} дій Ð´Ð»Ñ %{scopes} %{branches} %{agents} %{namespaces}"
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
-msgstr "%{thenLabelStart}Тоді%{thenLabelEnd} Вимагати ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ %{scan} Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку з профілем Ñайту %{siteProfile} Ñ– профілем Ñканера %{scannerProfile} з тегами %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
+msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
-msgstr "%{thenLabelStart}Потім%{thenLabelEnd} Вимагати ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ %{scan} Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку з тегами %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
+msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr "Конвеєр запущений"
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37969,9 +38602,15 @@ msgstr "агент"
msgid "ScanExecutionPolicy|branch"
msgstr "гілка"
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr "у проÑторі імен"
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -38442,24 +39081,27 @@ msgstr ""
msgid "Security"
msgstr "Безпека"
-msgid "Security & Compliance"
-msgstr "Безпека та відповідніÑÑ‚ÑŒ"
-
-msgid "Security Configuration"
-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 navigation"
-msgstr "ÐÐ°Ð²Ñ–Ð³Ð°Ñ†Ñ–Ñ Ð¿Ð¾ безпеці"
-
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -38586,7 +39228,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38700,6 +39342,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38805,9 +39450,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 "Ðе увімкнено"
@@ -38898,6 +39552,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38919,6 +39576,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38928,6 +39588,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38994,7 +39657,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -39072,6 +39735,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr "ÐктивніÑÑ‚ÑŒ"
+msgid "SecurityReports|Add comment and 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 ""
@@ -39549,6 +40215,9 @@ msgstr "Оберіть мітку"
msgid "Select labels"
msgstr "Вибрати мітки"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "Вибрати момент злиттÑ"
@@ -39651,6 +40320,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr "Увімкнути або вимкнути ÑамоÑтійний моніторинг інÑтанÑів."
@@ -39663,6 +40335,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr "СамоÑтійний моніторинг"
@@ -39675,6 +40350,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr "ÐадіÑлати"
@@ -39777,6 +40455,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39912,6 +40596,9 @@ msgstr "Ð’Ñтановити макÑимальний Ñ‡Ð°Ñ ÑеанÑу длÑ
msgid "Set the milestone to %{milestone_reference}."
msgstr "Ð’Ñтановити етап %{milestone_reference}."
+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 ""
@@ -39939,7 +40626,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -40192,6 +40879,9 @@ msgstr "Показати вміÑÑ‚ файлу"
msgid "Show filters"
msgstr "Показати фільтри"
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -40358,9 +41048,6 @@ msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ€Ñƒ завдань Sidekiq"
msgid "Sign in"
msgstr "Увійти"
-msgid "Sign in / Register"
-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 ""
@@ -40514,15 +41201,33 @@ msgstr "Slack Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»Ð¸Ñ‚ÑŒ вам взаємодіÑÑ
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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40532,6 +41237,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40541,6 +41249,9 @@ 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 ""
@@ -40574,9 +41285,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40760,12 +41477,18 @@ 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 ""
@@ -41177,9 +41900,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -41243,6 +41963,9 @@ msgstr "ЗахиÑÑ‚ від Ñпаму Ñ– ботів"
msgid "Spam log successfully submitted as ham."
msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð¿Ñ€Ð¾ Ñпам уÑпішно анульовано."
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr "Вказана URL-адреÑа не може бути викориÑтана: \"%{reason}\""
@@ -41492,6 +42215,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -42137,16 +42863,22 @@ msgstr "Готові розпочати? План GitLab ідеально під
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|Sync subscription request."
+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}."
@@ -42155,7 +42887,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -42186,9 +42918,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr "Ви можете розпочати безкоштовну пробну верÑÑ–ÑŽ GitLab Ultimate без будь-Ñких зобов'Ñзань чи платіжних даних."
@@ -42231,9 +42960,6 @@ msgstr "Ваша підпиÑка"
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr "Термін дії вашої підпиÑки закінчивÑÑ"
@@ -42384,9 +43110,27 @@ 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 ""
@@ -42797,12 +43541,12 @@ msgstr "Ваш проєкт не має файлів Ñтану Terraform"
msgid "Test"
msgstr "ТеÑÑ‚"
-msgid "Test Cases"
-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] ""
@@ -42826,9 +43570,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42955,6 +43696,9 @@ 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 "Стиль текÑту"
@@ -43016,6 +43760,9 @@ msgstr "Трекер задач — це міÑце, де можна додатÐ
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 "Домен cookie-файлів Snowpow."
@@ -43058,9 +43805,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð±ÑƒÐ´Ðµ припинено піÑÐ»Ñ %{timeout}. Ð”Ð»Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–Ñ—Ð², Ñким потрібно більше чаÑу, викориÑтовуйте комбінацію clone/push."
@@ -43118,6 +43862,9 @@ msgstr "СпиÑок залежноÑтей міÑтить детальну ін
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "Ð Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ð° %{environmentLink} не уÑпішне."
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr "Каталог уÑпішно Ñтворено."
@@ -43435,8 +44182,17 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
-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 "ДоÑтуп до Ñніпета можливий без будь-Ñкої автентифікації."
@@ -43780,6 +44536,9 @@ msgstr "Під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ ÑталаÑÑ Ð¿Ð¾Ð¼Ð
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43969,13 +44728,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -44476,6 +45229,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "Цей раннер буде виконуватиÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ на тих конвеєрах, Ñкі Ñпрацьовують на захищених гілках"
@@ -44530,10 +45286,7 @@ msgstr "Цю змінну не можна замаÑкувати."
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44988,6 +45741,9 @@ msgstr "Спочатку введіть адреÑу Ñервера GÑ–tea Ñ– %{
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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -45479,6 +46235,9 @@ 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 ""
@@ -45570,9 +46329,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr "ЗапуÑкати конвеєри Ð´Ð»Ñ Ð²Ñ–Ð´Ð´Ð·ÐµÑ€ÐºÐ°Ð»ÐµÐ½Ð¸Ñ… змін"
@@ -45675,9 +46431,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr "Двофакторна автентифікаціÑ"
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr "Двофакторна автентифікаціÑ"
@@ -45723,12 +46476,6 @@ msgstr "Тип"
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr "U2F приÑтрої (%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "U2F працює лише з веб-Ñайтами з підтримкою HTTPS. Ð”Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð±Ñ–Ð»ÑŒÑˆ детальної інформації звернітьÑÑ Ð´Ð¾ адмініÑтратора."
-
msgid "URL"
msgstr "URL"
@@ -45834,6 +46581,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45933,6 +46683,9 @@ msgstr ""
msgid "Unban"
msgstr "Розблокувати"
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45990,6 +46743,15 @@ msgstr "Якщо інше не узгоджено з GitLab у пиÑьмовіÐ
msgid "Unlimited"
msgstr "Без обмежень"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -46077,6 +46839,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -46146,6 +46911,9 @@ msgstr "Оновіть Ñвої закладки, тому що URL-адреÑа
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 "Оновіть ім'Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ, теми, Ð¾Ð¿Ð¸Ñ Ñ‚Ð° аватар."
@@ -46272,6 +47040,9 @@ msgstr "Тенденції викориÑтаннÑ"
msgid "Usage statistics"
msgstr "СтатиÑтика викориÑтаннÑ"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr "СтатиÑтичні дані щодо Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð ÐµÑ”Ñтру контейнерів на рівні проєкту Ñ” лише орієнтовними Ñ– не включають економію коштів за рахунок дедуплікації в маÑштабах інÑтанÑів."
@@ -46443,6 +47214,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr "ЗавантаженнÑ"
@@ -46647,6 +47421,9 @@ msgstr ""
msgid "Use the Apple App Store Connect integration to easily connect to the Apple App Store with Fastlane in CI/CD pipelines."
msgstr "ВикориÑтовувати інтеграцію Apple App Store Ð´Ð»Ñ Ð»ÐµÐ³ÐºÐ¾Ð³Ð¾ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ Apple App Store з Fastlane в CI/CD конвеєрах."
+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 ""
@@ -46659,6 +47436,9 @@ msgstr "ВикориÑтовуйте публічну URL-адреÑу інÑÑ‚Ð
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 "ВикориÑтовуйте цей токен Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ отриманого кориÑного навантаженнÑ."
@@ -46735,6 +47515,9 @@ 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 identity was successfully created."
msgstr "Ідентифікацію кориÑтувача уÑпішно Ñтворено."
@@ -47161,6 +47944,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -47272,6 +48058,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -47416,6 +48205,9 @@ msgstr "ПереглÑд Ñ– Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ‚ÐºÐ¸ з можлÐ
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -47447,9 +48239,6 @@ msgstr "ПереглÑнути документацію"
msgid "View eligible approvers"
msgstr "ПереглÑнути доÑтупних оÑіб Ð´Ð»Ñ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ"
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "ПереглÑнути опублікований артефакт"
@@ -47656,6 +48445,69 @@ msgstr "%{formattedStartDate} до Ñьогодні"
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|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 ""
@@ -48046,12 +48898,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "Ðе вдалоÑÑ Ð¿Ñ–Ð´ÐºÑŽÑ‡Ð¸Ñ‚Ð¸ÑÑ Ð´Ð¾ Ñервера Prometheus. Ðбо Ñервер більше не Ñ–Ñнує, або необхідно оновити деталі конфігурації."
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr "Ми виÑвили Ñпробу входу у ваш обліковий Ð·Ð°Ð¿Ð¸Ñ %{host} за допомогою неправильного коду двофакторної автентифікації"
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr "Ми виÑвили Ñпробу входу у ваш обліковий Ð·Ð°Ð¿Ð¸Ñ %{host} за допомогою неправильного коду двофакторної автентифікації з такої IP-адреÑи: %{ip} в %{time}"
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "Ми виÑвили потенційний Ñпам у %{humanized_resource_name}. Будь лаÑка, введіть цей код Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ reCAPTCHA, щоб продовжити."
@@ -48103,9 +48949,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "Це допоможе нам предÑтавити вам перÑоналізовані функції та інформацію."
@@ -48247,6 +49090,9 @@ 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 ""
@@ -48512,6 +49358,13 @@ 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] ""
+msgstr[2] ""
+msgstr[3] ""
+
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] ""
@@ -48552,6 +49405,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Вікі"
@@ -48771,7 +49627,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr "ВиконуєтьÑÑ Ñ€Ð¾Ð±Ð¾Ñ‚Ð° (відкрита та не призначена)"
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48819,6 +49675,9 @@ msgstr "Додати до ітерації"
msgid "WorkItem|Add to milestone"
msgstr "Додати в етап"
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48844,6 +49703,15 @@ msgstr "Дочірній елемент видалено"
msgid "WorkItem|Closed"
msgstr "Закрито"
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr "Створити %{workItemType}"
@@ -48868,9 +49736,15 @@ msgstr "Дата виконаннÑ"
msgid "WorkItem|Existing task"
msgstr "ІÑнуюче підзавданнÑ"
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr "Стан здоров'Ñ"
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr "Інцидент"
@@ -48991,6 +49865,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr "ÐŸÑ–Ð´Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð¾"
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr "ПідзавданнÑ"
@@ -49027,6 +49904,9 @@ msgstr "Робочий елемент"
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -49057,6 +49937,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr "Створити Ð¾Ð¿Ð¸Ñ ÐµÑ‚Ð°Ð¿Ñƒ..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "Створити Ð¾Ð¿Ð¸Ñ Ñ€ÐµÐ»Ñ–Ð·Ñƒ або перетÑгніть файли Ñюди…"
@@ -49460,9 +50343,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” жодного зареєÑтрованого U2F приÑтрою."
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49635,12 +50515,18 @@ 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 ""
@@ -49813,6 +50699,9 @@ 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 ""
@@ -49822,7 +50711,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49852,6 +50741,9 @@ msgstr "Ваша група GitLab"
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 "Ваші групи"
@@ -49876,6 +50768,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr "Ваші ключі SSH (%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr "Ваш ÑпиÑок нагадувань"
@@ -49921,6 +50816,9 @@ msgstr "Вашу дію було відхилено, оÑкільки доÑÑг
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr "Ваші заÑтоÑунки (%{size})"
@@ -49930,9 +50828,6 @@ msgstr "Ваші авторизовані заÑтоÑунки"
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "Ваш браузер не підтримує U2F. Будь лаÑка, викориÑтовйте Google Chrome Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¿'ютера (верÑÑ–ÑŽ 41 або новішу)."
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49963,6 +50858,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -50124,6 +51022,9 @@ msgstr "Ваша група найвищого Ñ€Ñ–Ð²Ð½Ñ %{namespace_name} зн
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr "Ваша група верхнього Ñ€Ñ–Ð²Ð½Ñ %{namespace_name} перевищує Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð° %{free_user_limit} кориÑтувача"
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr "Ваша група верхнього Ñ€Ñ–Ð²Ð½Ñ Ð¿ÐµÑ€ÐµÐ²Ð¸Ñ‰ÑƒÑ” ліміт кориÑтувачів Ñ– пам’ÑÑ‚Ñ–, Ñ– Ñ—Ñ— переведено в Ñтан лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ."
@@ -50367,6 +51268,9 @@ 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 ""
@@ -50709,9 +51613,6 @@ msgstr "Повний звіт"
msgid "ciReport|Generic Report"
msgstr "Загальний звіт"
-msgid "ciReport|IaC Scanning"
-msgstr "Ð¡ÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ IaC"
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "ДоÑлідити цю вразливіÑÑ‚ÑŒ, Ñтворивши задачу"
@@ -50779,6 +51680,9 @@ msgstr "Вирішити за допомогою запиту на злиттÑ"
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "ВиÑÐ²Ð»ÐµÐ½Ð½Ñ Ñекретів"
@@ -50809,6 +51713,9 @@ 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 "ТеÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ Ñтатичних заÑтоÑунків (SAST)"
@@ -51096,9 +52003,6 @@ msgstr[3] "файлів"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "знахідку втрачено або вже закріплено за вразливіÑÑ‚ÑŽ"
-msgid "following"
-msgstr "підпиÑки"
-
msgid "for"
msgstr "длÑ"
@@ -51412,11 +52316,17 @@ msgstr "заблоковано %{path_lock_user_name} %{created_at}"
msgid "manual"
msgstr "вручну"
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
-msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¼Ð°Ñ‚ÐµÐ¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ блоку"
+msgid "math|Too many expansions. Consider using multiple math blocks."
+msgstr ""
msgid "member"
msgid_plural "members"
@@ -51477,6 +52387,84 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr "%{boldHeaderStart}Схоже, що конвеєр тут відÑутній%{boldHeaderEnd}"
+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|%{mergeError}."
msgstr "%{mergeError}."
@@ -51492,6 +52480,12 @@ msgstr "ВикориÑÑ‚Ð°Ð½Ð½Ñ %{metricsLinkStart} пам’ÑÑ‚Ñ– %{metricsLi
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "ВикориÑÑ‚Ð°Ð½Ð½Ñ %{metricsLinkStart} пам’ÑÑ‚Ñ– %{metricsLinkEnd} %{emphasisStart} не змінилоÑÑ %{emphasisEnd} %{memoryFrom}Мб"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr "Ланцюжок змін - це ÑпиÑок запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² черзі, Ñкі очікують на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² цільову гілку. Зміни в кожному запиті на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¾Ð±'єднуютьÑÑ Ð·Ñ– змінами в попередніх запитах на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ– теÑтуютьÑÑ Ð¿ÐµÑ€ÐµÐ´ злиттÑм."
@@ -51519,12 +52513,6 @@ msgstr "Ð—Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð½ÐµÐ¾Ð±Ð¾Ð²â€™Ñзкове"
msgid "mrWidget|Approval password is invalid."
msgstr "Пароль Ð´Ð»Ñ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ñ” недійÑним."
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr "Правило Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ %{rules} Ñ” неприпуÑтимим. GitLab Ñхвалило це правило автоматично, щоб розблокувати запит на злиттÑ. %{link}"
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr "Правила Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ %{rules} Ñ” неприпуÑтимими. GitLab Ñхвалено ці правила автоматично, щоб розблокувати запит на злиттÑ. %{link}"
-
msgid "mrWidget|Approve"
msgstr "Затвердити"
@@ -51540,6 +52528,9 @@ 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 "Призначити ці задачі Ñобі"
@@ -51623,83 +52614,29 @@ msgstr[1] "Задачі зі згадками"
msgstr[2] "Задач зі згадками"
msgstr[3] "Задач зі згадками"
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: у назві чи опиÑÑ– має бути зазначено ключ задачі Jira."
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: повинні бути надані вÑÑ– необхідні дозволи."
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: необхідно пройти вÑÑ– перевірки ÑтатуÑу"
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: вÑÑ– Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ– бути вирішені."
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: заборонені ліцензії повинні бути видалені."
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: швидке злиттÑ(fast-forward) вперед неможливе. Щоб об’єднати цей запит, Ñпочатку локально перебазуйте(rebase)."
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: конфлікти Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ– бути вирішені."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: конвеєр має бути уÑпішним. Він чекає ручних дій Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð²Ð¶ÐµÐ½Ð½Ñ."
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: конвеєр має бути уÑпішним. ÐатиÑніть на фікÑацію, Ñка виправлÑÑ” збій, або %{linkStart}ознайомтеÑÑ Ð· іншими рішеннÑми.%{linkEnd}."
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾: ви можете об'єднатиÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ піÑÐ»Ñ Ð²Ð¸Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ Ð²Ð¸Ñ‰ÐµÐ·Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ… елементів."
-
msgid "mrWidget|Merge failed."
msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ñ€Ð¾Ð¹ÑˆÐ»Ð¾ невдало."
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr "ÐедоÑтупне: запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾Ñтупні лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð· архівних проєктів."
-
msgid "mrWidget|Merged by"
msgstr "Злито"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr "ЗлиттÑ! Зміни відправлÑÑŽÑ‚ÑŒÑÑ…"
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr "ЗлиттÑ! Зміни Ñкоро відбудутьÑÑ…"
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr "ЗлиттÑ! Барабанний дріб…"
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr "ЗлиттÑ! Ð’Ñе добре…"
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr "ЗлиттÑ! Зліт через 5…4…3…"
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr "ЗлиттÑ! Зробіть глибокий вдих Ñ– розÑлабтеÑÑ…"
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr "ЗлиттÑ! Зміни залишають Ñтанцію…"
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr "ЗлиттÑ! Це буде чудовий…"
-
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "ЗлиттÑ! Ми майже на міÑці…"
-
msgid "mrWidget|More information"
msgstr "Детальніше"
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "Ðемає кориÑтувачів, Ñкі відповідають критеріÑм правила."
-
msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr "Будь лаÑка, відновіть Ñ—Ñ— або викориÑтовуйте іншу %{type} гілку."
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "Можливе автоматичне злиттÑ. ЗвернітьÑÑ Ð´Ð¾ когоÑÑŒ із правами на Ð·Ð°Ð¿Ð¸Ñ Ñƒ цей репозиторій Ð´Ð»Ñ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ"
+msgid "mrWidget|Rebase"
+msgstr ""
+
+msgid "mrWidget|Rebase in progress"
+msgstr ""
+
+msgid "mrWidget|Rebase without pipeline"
+msgstr ""
msgid "mrWidget|Refresh"
msgstr "Оновити"
@@ -51761,9 +52698,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr "Що таке ланцюжок змін?"
@@ -51788,6 +52722,9 @@ msgstr "має бути коректною IPv4 або IPv6 адреÑою"
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/ur_PK/gitlab.po b/locale/ur_PK/gitlab.po
index a0eb8ffc4c3..195df01653a 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/uz_UZ/gitlab.po b/locale/uz_UZ/gitlab.po
index 73bbbde0a3a..18e0701d9bb 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -426,6 +426,11 @@ 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] ""
@@ -461,11 +466,22 @@ msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+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 ""
@@ -630,6 +646,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -831,6 +850,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -846,9 +868,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -982,6 +1001,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1226,6 +1248,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1504,11 +1529,6 @@ msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1813,9 +1833,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2230,9 +2247,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2254,6 +2268,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2263,6 +2280,9 @@ 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 ""
@@ -2377,6 +2397,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2515,6 +2538,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3694,40 +3720,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -4099,6 +4095,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4727,6 +4726,9 @@ 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 ""
@@ -4736,6 +4738,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4814,13 +4933,28 @@ 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|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."
+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."
@@ -4965,12 +5099,18 @@ 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 ""
@@ -5215,6 +5355,11 @@ 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 ""
@@ -5227,6 +5372,16 @@ msgstr ""
msgid "Approved MRs"
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 ""
@@ -5302,9 +5457,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5317,6 +5469,9 @@ 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 ""
@@ -5668,7 +5823,7 @@ msgstr[1] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5922,9 +6077,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5937,9 +6089,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5949,9 +6098,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6333,6 +6491,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6360,9 +6521,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6432,6 +6590,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6447,9 +6608,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6585,27 +6743,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6615,9 +6755,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6758,6 +6895,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6980,15 +7120,27 @@ 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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -7001,9 +7153,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -7121,9 +7270,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -7142,6 +7288,15 @@ 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 ""
@@ -7172,10 +7327,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7217,6 +7375,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7984,6 +8145,15 @@ 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 ""
@@ -8101,6 +8271,9 @@ 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 ""
@@ -8483,6 +8656,9 @@ 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 ""
@@ -8525,6 +8701,9 @@ 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 ""
@@ -8534,16 +8713,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8570,6 +8746,9 @@ 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 ""
@@ -8588,6 +8767,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8606,6 +8788,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8726,12 +8911,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8810,10 +9001,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8843,6 +9034,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9624,6 +9818,9 @@ 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 ""
@@ -9915,7 +10112,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10307,9 +10504,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10322,6 +10516,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10391,12 +10588,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10505,9 +10711,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10526,9 +10747,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -11150,6 +11368,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11192,12 +11413,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11213,6 +11443,9 @@ 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 ""
@@ -11258,7 +11491,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11279,7 +11515,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11351,6 +11587,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11597,7 +11836,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11786,6 +12025,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -12035,9 +12277,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12245,6 +12484,9 @@ 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 ""
@@ -12344,7 +12586,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12511,9 +12753,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13425,6 +13664,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13467,6 +13709,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14218,6 +14463,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14319,10 +14567,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14427,6 +14678,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14622,6 +14876,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14775,9 +15032,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15215,6 +15469,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15239,6 +15496,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15257,9 +15517,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15716,6 +15982,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15761,7 +16030,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15779,6 +16048,9 @@ 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 ""
@@ -16073,6 +16345,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16184,6 +16459,9 @@ 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 ""
@@ -16472,6 +16750,9 @@ 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 ""
@@ -16750,6 +17031,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16774,6 +17058,9 @@ 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 ""
@@ -16975,6 +17262,9 @@ 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 ""
@@ -16993,6 +17283,9 @@ 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 ""
@@ -17563,9 +17856,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17689,6 +17979,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17845,9 +18138,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17989,9 +18279,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18802,13 +19089,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18859,6 +19155,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18883,6 +19182,12 @@ 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 ""
@@ -18898,9 +19203,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18949,11 +19251,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19047,12 +19344,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -19092,6 +19395,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -19104,13 +19410,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -19128,7 +19434,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -19182,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19254,6 +19563,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19308,15 +19620,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19533,6 +19839,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19722,6 +20052,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -20073,6 +20406,9 @@ 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 ""
@@ -20331,6 +20667,9 @@ 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 ""
@@ -20346,6 +20685,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20722,6 +21067,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -21065,6 +21413,9 @@ 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 ""
@@ -21164,6 +21515,9 @@ 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 ""
@@ -21206,15 +21560,24 @@ 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 ""
@@ -21275,7 +21638,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21501,6 +21864,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21905,7 +22271,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22568,12 +22934,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22747,10 +23119,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
-msgid "Integrations|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22768,6 +23143,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -23056,7 +23434,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -23185,9 +23563,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23457,6 +23832,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23682,6 +24063,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24219,9 +24603,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24910,6 +25309,15 @@ 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 ""
@@ -24991,6 +25399,9 @@ 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 ""
@@ -25000,6 +25411,9 @@ 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 ""
@@ -25015,9 +25429,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -25033,6 +25444,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25282,6 +25696,11 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Line changes"
msgstr ""
@@ -25309,6 +25728,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25402,9 +25824,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25447,6 +25866,9 @@ 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 ""
@@ -25486,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25504,9 +25929,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25576,9 +25998,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25615,10 +26034,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -26110,6 +26526,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -26191,12 +26610,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26417,18 +26845,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26501,9 +26920,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26516,6 +26932,27 @@ 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 ""
@@ -27126,6 +27563,9 @@ msgstr[1] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27306,6 +27746,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27318,6 +27764,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27378,31 +27827,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27746,6 +28210,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27794,10 +28261,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
+
+msgid "Navigation|FREQUENT PROJECTS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27910,9 +28383,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -28000,9 +28470,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28357,6 +28824,15 @@ 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 ""
@@ -28440,13 +28916,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28748,12 +29227,24 @@ 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|%{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 ""
@@ -28802,9 +29293,18 @@ 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 ""
@@ -28832,9 +29332,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28871,6 +29368,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28880,6 +29380,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28892,6 +29395,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29368,6 +29874,9 @@ 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 ""
@@ -29437,9 +29946,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29733,28 +30239,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30551,6 +31063,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30740,9 +31255,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30941,6 +31453,9 @@ 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 ""
@@ -31166,6 +31681,9 @@ 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 ""
@@ -31217,9 +31735,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31265,6 +31780,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31316,7 +31837,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31325,6 +31846,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31361,13 +31885,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31397,6 +31921,12 @@ 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 ""
@@ -31418,6 +31948,9 @@ 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 ""
@@ -31427,6 +31960,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31742,6 +32278,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31763,6 +32302,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31823,7 +32365,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -32177,6 +32719,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32246,88 +32791,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr ""
-
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32336,34 +32824,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32372,24 +32863,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr ""
-
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32402,22 +32887,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|Import the new package into your JS code:"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32426,70 +32920,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32657,6 +33154,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32906,7 +33409,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -33080,6 +33583,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -33092,6 +33598,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -33119,6 +33628,9 @@ 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 ""
@@ -33215,9 +33727,21 @@ 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 ""
@@ -33230,6 +33754,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33272,7 +33799,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33287,9 +33817,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33419,9 +33946,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33572,9 +34096,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33617,9 +34138,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33656,9 +34174,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33701,10 +34216,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33728,9 +34243,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33965,6 +34477,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -34091,6 +34606,9 @@ 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 ""
@@ -34106,6 +34624,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34286,9 +34807,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34397,12 +34915,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34574,9 +35086,25 @@ 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 ""
@@ -34586,10 +35114,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34598,15 +35138,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34616,6 +35165,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -35072,24 +35624,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -35165,6 +35708,9 @@ 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] ""
@@ -35200,13 +35746,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35299,6 +35845,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36234,15 +36783,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36421,9 +36976,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36593,9 +37145,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36670,6 +37219,9 @@ 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|Administrator"
msgstr ""
@@ -36733,6 +37285,9 @@ 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 ""
@@ -36751,6 +37306,9 @@ 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 ""
@@ -36807,9 +37365,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36822,6 +37386,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36840,6 +37410,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36867,6 +37440,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36876,6 +37455,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36888,6 +37470,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36930,6 +37515,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36962,6 +37550,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36977,6 +37571,9 @@ 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 ""
@@ -37001,6 +37598,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -37016,6 +37616,12 @@ 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 ""
@@ -37088,9 +37694,15 @@ 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 ""
@@ -37124,6 +37736,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -37133,6 +37751,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -37150,6 +37771,9 @@ 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 runner has not run any jobs."
msgstr ""
@@ -37198,6 +37822,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37252,15 +37879,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37282,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37306,9 +37927,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37438,16 +38056,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37489,9 +38110,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37940,22 +38567,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -38084,7 +38714,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -38198,6 +38828,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38303,9 +38936,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38396,6 +39038,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38417,6 +39062,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38426,6 +39074,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38492,7 +39143,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38570,6 +39221,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -39047,6 +39701,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -39149,6 +39806,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -39161,6 +39821,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -39173,6 +39836,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39275,6 +39941,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39410,6 +40082,9 @@ 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 ""
@@ -39437,7 +40112,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39688,6 +40363,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39852,9 +40530,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -40008,15 +40683,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -40026,6 +40719,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -40035,6 +40731,9 @@ 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 ""
@@ -40068,9 +40767,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40254,12 +40959,18 @@ 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 ""
@@ -40671,9 +41382,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40737,6 +41445,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40986,6 +41697,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41631,16 +42345,22 @@ 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|Sync subscription request."
+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}."
@@ -41649,7 +42369,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41678,9 +42398,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41723,9 +42440,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41876,9 +42590,27 @@ 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 ""
@@ -42285,10 +43017,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42310,9 +43042,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42439,6 +43168,9 @@ 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 ""
@@ -42498,6 +43230,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42540,9 +43275,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42600,6 +43332,9 @@ 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 ""
@@ -42913,7 +43648,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -43258,6 +44002,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43447,13 +44194,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43954,6 +44695,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -44008,10 +44752,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44462,6 +45203,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44949,6 +45693,9 @@ 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 ""
@@ -45038,9 +45785,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -45143,9 +45887,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -45191,12 +45932,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45302,6 +46037,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45401,6 +46139,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45458,6 +46199,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45545,6 +46295,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45614,6 +46367,9 @@ 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 ""
@@ -45740,6 +46496,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45911,6 +46670,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -46115,6 +46877,9 @@ 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 ""
@@ -46127,6 +46892,9 @@ 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 ""
@@ -46201,6 +46969,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46627,6 +47398,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46738,6 +47512,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46882,6 +47659,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46911,9 +47691,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -47116,6 +47893,69 @@ 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|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 ""
@@ -47506,12 +48346,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47563,9 +48397,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47707,6 +48538,9 @@ 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 ""
@@ -47970,6 +48804,11 @@ 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] ""
@@ -48008,6 +48847,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -48227,7 +49069,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48275,6 +49117,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48298,6 +49143,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48322,9 +49176,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48445,6 +49305,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48481,6 +49344,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48511,6 +49377,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48912,9 +49781,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -49085,12 +49951,18 @@ 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 ""
@@ -49261,6 +50133,9 @@ 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 ""
@@ -49270,7 +50145,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49300,6 +50175,9 @@ 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 ""
@@ -49324,6 +50202,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49369,6 +50250,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49378,9 +50262,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49411,6 +50292,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49568,6 +50452,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49805,6 +50692,9 @@ 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 ""
@@ -50135,9 +51025,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -50203,6 +51090,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -50233,6 +51123,9 @@ 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 ""
@@ -50510,9 +51403,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50818,10 +51708,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+msgid "math|Too many expansions. Consider using multiple math blocks."
msgstr ""
msgid "member"
@@ -50879,6 +51775,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50894,6 +51868,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50921,12 +51901,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50942,6 +51916,9 @@ 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 ""
@@ -51021,82 +51998,28 @@ msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -51159,9 +52082,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -51186,6 +52106,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/vi_VN/gitlab.po b/locale/vi_VN/gitlab.po
index 534ba6ef93e..9aac2ad5c00 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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] ""
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
@@ -539,6 +553,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -740,6 +757,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -755,9 +775,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -889,6 +906,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1675,9 +1694,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2092,9 +2108,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2116,6 +2129,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2125,6 +2141,9 @@ 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 ""
@@ -2239,6 +2258,9 @@ msgstr ""
msgid "Add new directory"
msgstr ""
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2377,6 +2399,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3556,40 +3581,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3961,6 +3956,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4587,6 +4585,9 @@ 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 ""
@@ -4596,6 +4597,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4674,13 +4792,28 @@ 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|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."
+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."
@@ -4823,12 +4956,18 @@ 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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5080,6 +5223,14 @@ msgstr ""
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ 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 ""
@@ -5518,7 +5669,7 @@ msgstr[0] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5771,9 +5922,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5786,9 +5934,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5798,9 +5943,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6606,6 +6739,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -6846,9 +6994,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -6987,6 +7129,15 @@ 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 ""
@@ -7017,10 +7168,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7062,6 +7216,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7945,6 +8111,9 @@ 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 ""
@@ -8325,6 +8494,9 @@ 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 ""
@@ -8367,6 +8539,9 @@ 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 ""
@@ -8376,16 +8551,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
-msgstr ""
-
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8412,6 +8584,9 @@ 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 ""
@@ -8430,6 +8605,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8568,12 +8749,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,10 +8839,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10161,6 +10351,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10365,9 +10582,6 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ 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 ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11115,7 +11347,7 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
+msgid "Contributor statistics"
msgstr ""
msgid "Control emails linked to your account"
@@ -11187,6 +11419,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11433,7 +11668,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,7 +12418,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13301,6 +13539,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,10 +14388,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+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 note. Please try again."
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15060,6 +15313,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15582,7 +15847,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 ""
@@ -16795,6 +17078,9 @@ 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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr ""
msgid "February"
msgstr ""
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17662,9 +17951,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ 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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19121,15 +19430,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19535,6 +19862,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -19886,6 +20216,9 @@ 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 ""
@@ -20144,6 +20477,9 @@ 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 ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -20874,6 +21219,9 @@ 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 ""
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ 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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21308,6 +21668,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22374,12 +22737,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23261,6 +23633,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23486,6 +23864,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ 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 ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr ""
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ 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 ""
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25372,9 +25790,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 ""
@@ -26918,6 +27351,9 @@ msgstr[0] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -27098,6 +27534,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27110,6 +27552,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr ""
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28533,12 +29008,24 @@ 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|%{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 ""
@@ -28587,9 +29074,18 @@ 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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29152,6 +29654,9 @@ 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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30330,6 +30838,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr ""
@@ -30720,6 +31228,9 @@ 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 ""
@@ -30945,6 +31456,9 @@ 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 ""
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 ""
@@ -31197,6 +31723,9 @@ 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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,7 +32140,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -32898,6 +33403,9 @@ 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 ""
@@ -32994,9 +33502,21 @@ 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 ""
@@ -33009,6 +33529,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,7 +33574,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33435,9 +33949,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -33870,6 +34381,9 @@ 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 ""
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34176,12 +34690,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34395,6 +34938,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] ""
@@ -34978,13 +35518,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36005,15 +36548,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr ""
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ 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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ 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 ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37042,6 +37654,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37689,22 +38310,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -37833,7 +38457,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -38796,6 +39444,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ 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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 ""
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41622,9 +42330,27 @@ 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 ""
@@ -42029,10 +42755,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42341,6 +43067,9 @@ 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 ""
@@ -42652,7 +43381,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -43747,10 +44485,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44199,6 +44934,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44684,6 +45422,9 @@ 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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -44877,9 +45615,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -44925,12 +45660,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ 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 ""
@@ -45474,6 +46224,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46360,6 +47125,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46643,9 +47417,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -46846,6 +47617,69 @@ 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|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 ""
@@ -47236,12 +48070,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -47955,7 +48790,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ 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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,7 +49862,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49024,6 +49892,9 @@ 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 ""
@@ -49048,6 +49919,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49102,9 +49979,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -49915,6 +50795,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50521,10 +51404,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,82 +51690,28 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index 7642d3d16b5..a589db37d3c 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr "从%{start}到%{end}"
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] "%d个未解决的主题"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] "%d 个版本"
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d个æ¼æ´ž"
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] "找到%d个警告:"
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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 ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} 和 %{openOrClose} %{noteable}"
@@ -539,6 +553,9 @@ msgstr "%{count}个相关的%{pluralized_subject}: %{links}"
msgid "%{count} selected"
msgstr "已选择 %{count} 个"
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr "总æƒé‡%{count}"
@@ -740,6 +757,9 @@ msgstr "由于派生的æºé¡¹ç›®å¯è§æ€§è¾ƒä½Žï¼Œå› æ­¤ä¸å…许使用%{level_n
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr "%{linkStart}了解更多%{linkEnd}。"
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow},还有 %{awardsListLength} 个。"
@@ -755,9 +775,6 @@ msgstr "%{mergeLength}/%{usersLength} å¯ä»¥åˆå¹¶"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message}显示第一个%{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr "%{message}。您关注的请求已删除。"
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (已过期)"
@@ -889,6 +906,9 @@ msgstr "%{reportType}检测到%{totalStart}%{total}%{totalEnd}个潜在的%{vuln
msgid "%{reportType} detected no new vulnerabilities."
msgstr "%{reportType} 未检测到新æ¼æ´žã€‚"
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] "%{requireStart}需è¦%{requireEnd} %{approvalsRequired} 个%{approvalStart}批准%{approvalEnd},æ¥è‡ªï¼š"
@@ -1000,7 +1020,7 @@ msgstr[0] "%{strong_start}%{count}ä½æˆå‘˜%{strong_end}必须核准åŽæ‰å¯ä»¥
msgid "%{strong_start}%{count}%{strong_end} Environment"
msgid_plural "%{strong_start}%{count}%{strong_end} Environments"
-msgstr[0] ""
+msgstr[0] "%{strong_start}%{count}%{strong_end} 个环境"
msgid "%{strong_start}%{errors}%{strong_end} %{prefix} finding"
msgid_plural "%{strong_start}%{errors}%{strong_end} %{prefix} findings"
@@ -1116,6 +1136,9 @@ msgstr "%{user} 创建了一个å²è¯—:%{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} 创建了一个议题:%{issue_link}"
+msgid "%{user} user’s menu"
+msgstr "%{user} 用户的èœå•"
+
msgid "%{value} is not included in the list"
msgstr "列表中ä¸åŒ…å«%{value}"
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] "%d个部署密钥"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "%{count} ä½å…³æ³¨è€…"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%d 个群组"
@@ -1675,9 +1694,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "API模糊测试"
-msgid "API Fuzzing Configuration"
-msgstr "API 模糊é…ç½®"
-
msgid "API Help"
msgstr "API帮助"
@@ -2092,9 +2108,6 @@ msgstr "添加检查清å•"
msgid "Add a collapsible section"
msgstr "添加å¯æŠ˜å éƒ¨åˆ†"
-msgid "Add a comment"
-msgstr "添加评论"
-
msgid "Add a comment to this line"
msgstr "å‘此行添加评论"
@@ -2116,6 +2129,9 @@ msgstr "在wiki中添加一个主页,其中包å«æœ‰å…³é¡¹ç›®çš„ä¿¡æ¯ï¼ŒGitLa
msgid "Add a new issue"
msgstr "添加一个新议题"
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr "添加编å·åˆ—表"
@@ -2125,6 +2141,9 @@ 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 "为æœåŠ¡å°ç”µå­é‚®ä»¶åœ°å€æ·»åŠ åŽç¼€ã€‚ %{linkStart}了解更多。%{linkEnd}"
@@ -2239,6 +2258,9 @@ msgstr "新建应用"
msgid "Add new directory"
msgstr "添加目录"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr "增加或删除一个用户。"
@@ -2377,6 +2399,9 @@ msgstr "é¢å¤–的分钟数:"
msgid "Additional text"
msgstr "附加文本"
+msgid "Additional text for deactivation email"
+msgstr "åœç”¨ç”µå­é‚®ä»¶çš„附加文本"
+
msgid "Additional text for the sign-in and Help page."
msgstr "登录和帮助页é¢çš„附加文本。"
@@ -2792,13 +2817,13 @@ msgid "AdminSettings|If not specified at the group or instance level, the defaul
msgstr "如果未指定群组或实例级别,默认值为 %{default_initial_branch_name}。ä¸å½±å“现有的仓库。"
msgid "AdminSettings|If selected, only administrators are able to create internal groups, projects, and snippets."
-msgstr ""
+msgstr "如果选中,则åªæœ‰ç®¡ç†å‘˜èƒ½å¤Ÿåˆ›å»ºå†…部群组ã€é¡¹ç›®å’Œä»£ç ç‰‡æ®µã€‚"
msgid "AdminSettings|If selected, only administrators are able to create private groups, projects, and snippets."
-msgstr ""
+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 ""
+msgstr "如果选中,则åªæœ‰ç®¡ç†å‘˜èƒ½å¤Ÿåˆ›å»ºå…¬å¼€ç¾¤ç»„ã€é¡¹ç›®å’Œç‰‡æ®µã€‚此外,个人资料仅对ç»è¿‡èº«ä»½éªŒè¯çš„用户å¯è§ã€‚"
msgid "AdminSettings|If there isn't any existing index, GitLab creates one."
msgstr "如果没有任何现有索引,系统会创建一个。"
@@ -2882,7 +2907,7 @@ msgid "AdminSettings|Pause Elasticsearch indexing"
msgstr "æš‚åœElasticsearch 索引"
msgid "AdminSettings|Prevent non-administrators from using the selected visibility levels for groups, projects and snippets."
-msgstr ""
+msgstr "防止éžç®¡ç†å‘˜ä½¿ç”¨ç¾¤ç»„ã€é¡¹ç›®å’Œä»£ç ç‰‡æ®µçš„选定å¯è§æ€§çº§åˆ«ã€‚"
msgid "AdminSettings|Preview payload"
msgstr "预览有效负载"
@@ -2912,7 +2937,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 "ä¿å­˜ %{name} é™åˆ¶"
@@ -3556,41 +3581,11 @@ msgstr "激活 Apple App Store Connect 集æˆåŽï¼Œå°†åˆ›å»ºä»¥ä¸‹å—ä¿æŠ¤å˜é‡
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 "导出完æˆåŽï¼Œä»Žé€šçŸ¥ç”µå­é‚®ä»¶æˆ–此页é¢ä¸‹è½½æ•°æ®æ–‡ä»¶ã€‚ 然åŽæ‚¨å¯ä»¥ä»Žå¦ä¸€ä¸ª GitLab 实例的 %{strong_text_start}创建新群组%{strong_text_end} 页é¢å¯¼å…¥æ•°æ®æ–‡ä»¶ã€‚"
-msgid "After you've reviewed these contribution guidelines, you'll be all set to"
-msgstr "在阅读这些贡献指å—åŽï¼Œæ‚¨å°†å‡†å¤‡å¥½"
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
-msgstr ""
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
+msgstr "在阅读这些贡献指å—åŽï¼Œæ‚¨å°†å‡†å¤‡å¥½"
msgid "Akismet"
msgstr "Akismet"
@@ -3961,6 +3956,9 @@ msgstr "整个GitLab"
msgid "All Members"
msgstr "所有æˆå‘˜"
+msgid "All branch names must match %{link_start}this regular expression%{link_end}. If empty, any branch name is allowed."
+msgstr "所有分支åç§°å¿…é¡»åŒ¹é… %{link_start}此正则表达å¼%{link_end}。如果为空,则å…许任何分支å称。"
+
msgid "All branches"
msgstr "所有分支"
@@ -4587,6 +4585,9 @@ msgstr "å¯åŠ¨Web终端时å‘生æ„外错误。"
msgid "An unexpected error occurred while stopping the Web Terminal."
msgstr "åœæ­¢Web终端时å‘生æ„外错误。"
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
msgid "An unknown error occurred while loading this graph."
msgstr "加载此图表时å‘生未知错误。"
@@ -4596,6 +4597,123 @@ msgstr "å‘生未知错误。"
msgid "Analytics"
msgstr "分æž"
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr "分æžä»ªè¡¨ç›˜"
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "分æžä¾èµ–项查找已知æ¼æ´ž."
@@ -4674,14 +4792,29 @@ msgstr "追加 %{shrug} 到评论"
msgid "Append the comment with %{tableflip}"
msgstr "追加%{tableflip}到评论"
+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|The Apple App Store Connect Issuer ID."
msgstr "Apple App Store Connect å‘行者 ID。"
msgid "AppleAppStore|The Apple App Store Connect Key ID."
msgstr "Apple App Store Connect 密钥 ID。"
-msgid "AppleAppStore|The Apple App Store Connect Private Key."
-msgstr "Apple App Store Connect ç§é’¥ã€‚"
+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 "使用 GitLab 在 Apple App Store 中构建和å‘布应用程åºã€‚"
@@ -4823,12 +4956,18 @@ msgstr "ä¿å­˜æ›´æ”¹"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "请å‚阅%{linkStart}密ç ç­–略指å—%{linkEnd}。"
+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 "用户注册åŽæ˜¾ç¤ºçš„文本。Markdownå¯ç”¨ã€‚"
@@ -5063,11 +5202,15 @@ msgid "Approve"
msgstr "批准"
msgid "Approve All"
-msgstr ""
+msgstr "全部批准"
msgid "Approve a merge request"
msgstr "批准åˆå¹¶è¯·æ±‚"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr "批准åˆå¹¶è¯·æ±‚"
@@ -5080,6 +5223,14 @@ msgstr "已核准"
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr "批准了当å‰çš„åˆå¹¶è¯·æ±‚。"
@@ -5155,9 +5306,6 @@ msgstr "æ‚¨ç¡®å®šè¦ %{action} %{name}å—?"
msgid "Are you sure you want to approve %{user}?"
msgstr "您确定è¦æ‰¹å‡† %{user} å—?"
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr "您确定è¦å°è¯•åˆå¹¶å—?"
@@ -5170,6 +5318,9 @@ msgstr "您确定è¦å…³é—­æ­¤è¢«å—阻的议题å—?"
msgid "Are you sure you want to delete %{name}?"
msgstr "您确定è¦åˆ é™¤%{name}å—?"
+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 "您确定è¦åˆ é™¤%{commentType}å—?"
@@ -5518,8 +5669,8 @@ msgstr[0] "添加%d个附件"
msgid "Attaching the file failed."
msgstr "添加附件失败。"
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
-msgstr "å°è¯•ç™»å½•åˆ° %{host} 时,使用了错误的åŒé‡èº«ä»½éªŒè¯ç "
+msgid "Attempted sign in to %{host} using an incorrect verification code"
+msgstr "å°è¯•ç™»å½• %{host} 时,使用了ä¸æ­£ç¡®çš„验è¯ç "
msgid "Audit Events"
msgstr "审计事件"
@@ -5771,9 +5922,6 @@ msgstr "%{author}编写于%{timeago}"
msgid "Authorization code:"
msgstr "授æƒç ï¼š"
-msgid "Authorization required"
-msgstr "需è¦æŽˆæƒ"
-
msgid "Authorization token duration (minutes)"
msgstr "授æƒä»¤ç‰ŒæœŸé™ (分钟)"
@@ -5786,9 +5934,6 @@ msgstr "授æƒ"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "æŽˆæƒ %{link_to_client} 使用您的å¸æˆ·ï¼Ÿ"
-msgid "Authorize %{user} to use your account?"
-msgstr "授æƒ%{user}使用您的å¸æˆ·å—?"
-
msgid "Authorized %{new_chat_name}"
msgstr "已授æƒç»™ %{new_chat_name}"
@@ -5798,9 +5943,18 @@ msgstr "授æƒäºŽ"
msgid "Authorized applications (%{size})"
msgstr "已授æƒåº”用 (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr "撤销申请"
@@ -5907,10 +6061,10 @@ msgid "Automatically update this project's branches and tags from the upstream r
msgstr "自动从上游仓库更新此项目的分支和标记。"
msgid "Automation"
-msgstr ""
+msgstr "自动化"
msgid "Automation|Automation App"
-msgstr ""
+msgstr "自动化应用"
msgid "Autosave|Note"
msgstr "注æ„"
@@ -6182,6 +6336,9 @@ msgstr "请注æ„,更改项目的命å空间å¯èƒ½ä¼šäº§ç”Ÿéžé¢„期的副作
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "请注æ„,é‡å‘½å项目的仓库å¯èƒ½ä¼šäº§ç”Ÿéžé¢„期的副作用。"
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 "因为您å¯ç”¨äº†è‡ªåŠ¨å°ç¦ï¼Œæ‰€ä»¥æˆ‘们åŒæ—¶ä¹Ÿåœ¨ %{scope} 中自动å°ç¦æ­¤ç”¨æˆ·ã€‚如果这是错误的,您å¯ä»¥ %{link_start}å–消å°ç¦ä»–们%{link_end}。"
@@ -6209,9 +6366,6 @@ msgstr "以下是%{link_to_gitlab_pages}的设置。"
msgid "Below you will find all the groups that are public."
msgstr "您将在下é¢æ‰¾åˆ°æ‰€æœ‰å…¬å¼€çš„群组。"
-msgid "Beta"
-msgstr "Beta"
-
msgid "Bi-weekly code coverage"
msgstr "åŒå‘¨ä»£ç è¦†ç›–率"
@@ -6281,6 +6435,9 @@ msgstr "ä¼ä¸šæ•æ·è§„划"
msgid "BillingPlans|Faster code reviews"
msgstr "更快的代ç è¯„审"
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr "为个人用户永久æä¾›å…费功能"
@@ -6296,9 +6453,6 @@ msgstr "如果您想è¦é™çº§æ‚¨çš„订阅计划,请è”ç³»%{support_link_start}
msgid "BillingPlans|Includes free static websites"
msgstr "包括å…è´¹é™æ€ç½‘ç«™"
-msgid "BillingPlans|Learn more"
-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 "å¯ä»¥é˜…读%{faq_link}了解更多付费方案细节,或者开始为期30天的旗舰版试用。"
@@ -6375,7 +6529,7 @@ msgid "BillingPlans|Ultimate"
msgstr "旗舰版"
msgid "BillingPlans|Upgrade"
-msgstr ""
+msgstr "å‡çº§"
msgid "BillingPlans|Upgrade to Premium"
msgstr "å‡çº§åˆ°ä¸“业版"
@@ -6434,27 +6588,9 @@ msgstr "å‡çº§"
msgid "BillingPlan|Upgrade for free"
msgstr "å…è´¹å‡çº§"
-msgid "Billings|%{planName} plan"
-msgstr "%{planName} 方案"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr "延长试用期时出错。"
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr "é‡æ–°æ¿€æ´»æ‚¨çš„试用版时出错。"
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr "通过延长您的试用期,您将收到é¢å¤–30 天的 %{planName}。您的试用åªèƒ½å»¶é•¿ä¸€æ¬¡ã€‚"
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr "通过é‡æ–°æ¿€æ´»æ‚¨çš„试用,您将收到é¢å¤–30 天的 %{planName}。您的试用åªèƒ½é‡æ–°æ¿€æ´»ä¸€æ¬¡ã€‚"
-
msgid "Billings|Error validating card details"
msgstr "验è¯å¡ç‰‡ç»†èŠ‚时出错"
-msgid "Billings|Extend trial"
-msgstr "延长试用期"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr "å…费群组仅é™äºŽ %{number} 个席ä½ã€‚"
@@ -6464,9 +6600,6 @@ msgstr "å…费版和试用群组æ¯å¤©æœ€å¤šå¯ä»¥é‚€è¯· 20 åæˆå‘˜ã€‚"
msgid "Billings|In a seat"
msgstr "å ç”¨å¸­ä½"
-msgid "Billings|Reactivate trial"
-msgstr "é‡æ–°æ¿€æ´»è¯•ç”¨"
-
msgid "Billings|Seats in use / Seats available"
msgstr "正在使用的席ä½æ•° / å¯ç”¨çš„席ä½æ•°"
@@ -6504,7 +6637,7 @@ msgid "Billing|Add seats"
msgstr "添加席ä½"
msgid "Billing|All members were successfully approved"
-msgstr ""
+msgstr "所有æˆå‘˜å·²æˆåŠŸæ‰¹å‡†"
msgid "Billing|An email address is only visible for users with public emails."
msgstr "åªæœ‰ç”¨æˆ·è®¾ç½®äº†å…¬å¼€ç”µå­é‚®ä»¶ï¼Œä»–们的邮件æ‰å¯¹å¤–å¯è§ã€‚"
@@ -6513,7 +6646,7 @@ msgid "Billing|An error occurred while approving %{user}"
msgstr "批准 %{user} 时出错"
msgid "Billing|An error occurred while approving all members"
-msgstr ""
+msgstr "批准所有æˆå‘˜æ—¶å‘生错误"
msgid "Billing|An error occurred while getting a billable member details."
msgstr "获å–计费æˆå‘˜è¯¦ç»†ä¿¡æ¯æ—¶å‘生错误。"
@@ -6606,6 +6739,9 @@ msgstr "从 Bitbucket 导入"
msgid "Blame"
msgstr "Blame"
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr "在 %{environmentName} 查看"
@@ -6825,15 +6961,27 @@ msgstr[0] "被 %{blockedByCount} %{issuableType}ç¦ç”¨"
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 "无法获å–ç¦ç”¨çš„ %{issuableType}"
+msgid "Boards|List actions"
+msgstr "列出æ“作"
+
msgid "Boards|Move card"
msgstr "移动å¡ç‰‡"
@@ -6846,9 +6994,6 @@ msgstr "移动至列表顶部"
msgid "Boards|New board"
msgstr "新建看æ¿"
-msgid "Boards|New epic"
-msgstr "新建å²è¯—"
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr "正在获å–阻塞的%{issuableType}"
@@ -6958,17 +7103,14 @@ msgid "BranchRules|%{total} status %{subject}"
msgstr "%{total} ä¸ªçŠ¶æ€ %{subject}"
msgid "BranchRules|Add branch rule"
-msgstr ""
+msgstr "添加分支规则"
msgid "BranchRules|After a protected branch is created, it will show up in the list as a branch rule."
-msgstr ""
+msgstr "创建å—ä¿æŠ¤çš„分支åŽï¼Œå®ƒå°†ä½œä¸ºåˆ†æ”¯è§„则显示在列表中。"
msgid "BranchRules|All branches"
msgstr "所有分支"
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr "å…许所有具有推é€è®¿é—®æƒé™çš„用户强制推é€ã€‚"
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "å…许所有具有推é€è®¿é—®æƒé™çš„用户%{linkStart}强制推é€%{linkEnd}。"
@@ -6987,6 +7129,15 @@ msgstr "å…许推é€å’Œåˆå¹¶"
msgid "BranchRules|Allowed to push and merge (%{total})"
msgstr "å…许推é€å’Œåˆå¹¶ï¼ˆ%{total})"
+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 "获å–分支时å‘生错误。"
@@ -7009,7 +7160,7 @@ msgid "BranchRules|Check for a status response in merge requests. Failures do no
msgstr "检查åˆå¹¶è¯·æ±‚中的状æ€å“应,失败ä¸ä¼šé˜»æ­¢åˆå¹¶ã€‚%{linkStart} 了解更多信æ¯ã€‚%{linkEnd}"
msgid "BranchRules|Create protected branch"
-msgstr ""
+msgstr "创建å—ä¿æŠ¤çš„分支"
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr "创建通é…符:%{searchTerm}"
@@ -7017,11 +7168,14 @@ msgstr "创建通é…符:%{searchTerm}"
msgid "BranchRules|Details"
msgstr "详情"
-msgid "BranchRules|Force push"
-msgstr "强制推é€"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
-msgid "BranchRules|Force push is not allowed."
-msgstr "ä¸å…许强制推é€ã€‚"
+msgid "BranchRules|From users with push access."
+msgstr ""
msgid "BranchRules|Groups"
msgstr "群组"
@@ -7062,6 +7216,9 @@ msgstr "需è¦æ‰¹å‡†ï¼ˆ%{total} 个)"
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr "éœ€è¦ CODEOWNERS 批准"
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr "角色"
@@ -7075,7 +7232,7 @@ msgid "BranchRules|Target branch"
msgstr "目标分支"
msgid "BranchRules|To create a branch rule, you first need to create a protected branch."
-msgstr ""
+msgstr "è¦åˆ›å»ºåˆ†æ”¯è§„则,您首先需è¦åˆ›å»ºå—ä¿æŠ¤çš„分支。"
msgid "BranchRules|Users"
msgstr "用户"
@@ -7498,7 +7655,7 @@ 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 ""
+msgstr "一分钟内ä¸èƒ½å¯¼å…¥å…­æ¬¡ä»¥ä¸Šã€‚请等待一分钟åŽé‡è¯•ã€‚"
msgid "Bullet list"
msgstr "æ— åºåˆ—表"
@@ -7649,10 +7806,10 @@ 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 ""
+msgstr "å…许æ¥è‡ªä»¥ä¸‹é¡¹ç›®çš„ CI 作业令牌访问此项目"
msgid "CICD|Allow access to this project with a CI_JOB_TOKEN"
-msgstr ""
+msgstr "å…许使用 CI_JOB_TOKEN 访问此项目"
msgid "CICD|An error occurred while update the setting. Please try again."
msgstr "更新设置时出错。请é‡è¯•ã€‚"
@@ -7679,7 +7836,7 @@ msgid "CICD|Deployment strategy"
msgstr "部署策略"
msgid "CICD|Enable feature to allow job token access by the following projects."
-msgstr ""
+msgstr "å¯ç”¨æ­¤åŠŸèƒ½åŽå…许以下项目访问作业令牌。"
msgid "CICD|Enable feature to limit job token access to the following projects."
msgstr "å¯ç”¨åŠŸèƒ½ä»¥é™åˆ¶å¯¹ä»¥ä¸‹é¡¹ç›®çš„作业令牌访问。"
@@ -7828,6 +7985,15 @@ 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 "无法创建代ç ç‰‡æ®µ: %{err}"
@@ -7945,6 +8111,9 @@ 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 "如果å²è¯—包å«éžç§å¯†å­å²è¯—,则无法将该å²è¯—设置为ç§å¯†ã€‚"
@@ -8325,6 +8494,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+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 "出现未知错误。请刷新此页é¢å†è¯•ã€‚"
@@ -8367,6 +8539,9 @@ 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 "创建新群组"
@@ -8376,18 +8551,15 @@ msgstr "信用å¡è¡¨å•åŠ è½½å¤±è´¥ã€‚请é‡è¯•ã€‚"
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "信用å¡è¡¨å•åŠ è½½å¤±è´¥ï¼š %{message}"
+msgid "Checkout|Discount"
+msgstr "折扣"
+
msgid "Checkout|Edit"
msgstr "编辑"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr "有效期至%{expirationMonth}/%{expirationYear}"
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "无法确认您的订å•ï¼è¯·é‡è¯•ã€‚"
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "无法确认您的订å•ï¼š %{message}。请é‡è¯•ã€‚"
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "加载国家失败。请å†è¯•ä¸€æ¬¡ã€‚"
@@ -8412,6 +8584,9 @@ msgstr "GitLab计划"
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 "必须为 %{minimumNumberOfUsers} (使用中的席ä½æ•°ï¼‰æˆ–更多。"
@@ -8430,6 +8605,9 @@ msgstr "å称:%{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "需è¦æ›´å¤šç”¨æˆ·ï¼Ÿè¯·ä¸ºæ‚¨çš„%{company}采购GitLab 。"
+msgid "Checkout|Network Error: %{message}"
+msgstr "网络错误:%{message}"
+
msgid "Checkout|Number of users"
msgstr "用户数é‡"
@@ -8448,6 +8626,9 @@ msgstr "选择国家"
msgid "Checkout|Select a state"
msgstr "选择一个州/çœ"
+msgid "Checkout|Something went wrong while loading price details."
+msgstr "加载价格详细信æ¯æ—¶å‡ºé”™ã€‚"
+
msgid "Checkout|State"
msgstr "å·ž"
@@ -8568,12 +8749,18 @@ msgstr "选择您想è¦åœ¨ç¾¤ç»„概览页é¢æŸ¥çœ‹çš„内容。"
msgid "Choose which Git strategy to use when fetching the project."
msgstr "选择获å–项目时è¦ä½¿ç”¨çš„ Git 策略。"
+msgid "Choose which branches should be mirrored"
+msgstr "选择è¦é•œåƒçš„分支"
+
msgid "Choose which repositories you want to connect and run CI/CD pipelines."
msgstr "请选择è¦è¿žæŽ¥å¹¶è¿è¡Œ CI/CD æµæ°´çº¿çš„代ç ä»“库。"
msgid "Choose your framework"
msgstr "选择你的框架"
+msgid "Ci config already present"
+msgstr "CI é…置已存在"
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr "日期范围:%{range}"
@@ -8652,12 +8839,12 @@ msgstr "等待"
msgid "CiStatus|running"
msgstr "è¿è¡Œä¸­"
+msgid "CiVariables|Cancel"
+msgstr ""
+
msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr "当å‰å€¼æ— æ³•ä½¿ç”¨éšè—å˜é‡"
-msgid "CiVariables|Clear inputs"
-msgstr "清除输入"
-
msgid "CiVariables|Environments"
msgstr "环境"
@@ -8685,6 +8872,9 @@ msgstr "选项"
msgid "CiVariables|Protected"
msgstr "å—ä¿æŠ¤"
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr "删除å˜é‡"
@@ -8692,7 +8882,7 @@ msgid "CiVariables|Remove variable row"
msgstr "删除å˜é‡è¡Œ"
msgid "CiVariables|Run job"
-msgstr ""
+msgstr "è¿è¡Œä½œä¸š"
msgid "CiVariables|Run job again"
msgstr "å†æ¬¡è¿è¡Œä½œä¸š"
@@ -8701,7 +8891,7 @@ 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 ""
+msgstr "指定è¦åœ¨æ­¤è¿è¡Œä¸­ä½¿ç”¨çš„å˜é‡å€¼ã€‚默认使用é…置文件中指定的å˜é‡å’Œ %{linkStart}CI/CD 设置%{linkEnd}。"
msgid "CiVariables|State"
msgstr "状æ€"
@@ -9464,6 +9654,9 @@ msgstr "您的实例没有设置 %{linkStart}GitLab 代ç†æœåŠ¡å™¨ (KAS)%{linkE
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 "您的æƒé™ä¸è¶³ï¼Œæ— æ³•ä¸ºæ­¤é¡¹ç›®åˆ›å»ºé›†ç¾¤ä»£ç†"
@@ -9755,7 +9948,7 @@ msgstr "用于对群集进行身份验è¯çš„ Kubernetes è¯ä¹¦ã€‚"
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "用于访问 Kubernetes API 的 URL。"
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr "基于è¯ä¹¦çš„ Kubernetes 集æˆå·²è¢«å¼ƒç”¨ï¼Œå°†äºŽ 2023 å¹´ 2 月关闭,请%{linkStart}è¿ç§»åˆ°é€‚用于 Kubernetes 的代ç†%{linkEnd}或è”系技术支æŒã€‚"
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr "比较 GitLab 版本"
msgid "Compare GitLab plans"
msgstr "比较 GitLab å„版本"
-msgid "Compare Revisions"
-msgstr "比较版本"
-
msgid "Compare branches and continue"
msgstr "比较分支并继续"
@@ -10161,6 +10351,9 @@ msgstr "与上个æ交比较å˜æ›´å†…容"
msgid "Compare changes with the merge request target branch"
msgstr "与åˆå¹¶è¯·æ±‚的目标分支比较å˜æ›´å†…容"
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr "比较å­æ¨¡å—æ交的版本"
@@ -10230,12 +10423,21 @@ msgstr "已完æˆ"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr "在 %{duration_seconds} 秒内完æˆï¼ˆ%{relative_time})"
+msgid "Compliance Report|Frameworks"
+msgstr "框架"
+
+msgid "Compliance Report|Violations"
+msgstr "è¿è§„"
+
msgid "Compliance framework"
msgstr "åˆè§„框架"
msgid "Compliance report"
msgstr "åˆè§„报告"
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "添加框架"
@@ -10344,9 +10546,24 @@ msgstr "ç”±æ交者批准"
msgid "ComplianceReport|Less than 2 approvers"
msgstr "少于 2 个核准人"
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr "未å‘现è¿è§„行为"
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "组件"
@@ -10365,9 +10582,6 @@ msgstr "ç§å¯†å¤‡æ³¨"
msgid "Confidentiality"
msgstr "ç§å¯†æ€§"
-msgid "Configuration"
-msgstr "é…ç½®"
-
msgid "Configuration help"
msgstr "é…置帮助"
@@ -10986,6 +11200,9 @@ msgstr "您将è¦åˆ é™¤ä»“库%{title}。确认åŽï¼Œæ­¤ä»“库将被永久删除ã
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "您å¯ä»¥é€šè¿‡ä»¥ä¸‹å‘½ä»¤å°†é•œåƒæ·»åŠ åˆ°å®¹å™¨é•œåƒåº“:"
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr "%{link}解æžçš„内容。"
@@ -11028,29 +11245,41 @@ msgstr "贡献"
msgid "Contribution Analytics"
msgstr "贡献度分æž"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr "已创建 %{createdCount} 个,已关闭 %{closedCount} 个。"
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr "已创建 %{createdCount} 个,已åˆå¹¶ %{mergedCount} 个,已关闭 %{closedCount} 个。"
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr "%{created} 个已创建,%{closed} 个已关闭。"
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr "%{created} 个已创建, %{merged} 个已åˆå¹¶ï¼Œ%{closed} 个已关闭。"
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr "%{pushCount} 次推é€ï¼Œæ¥è‡ª %{authorCount} 个作者。"
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr "%{pushes} 次推é€ï¼Œè¶…过 %{contributors} 个贡献者的 %{commits} 次æ交。"
msgid "ContributionAnalytics|Approved MRs"
-msgstr ""
+msgstr "已批准的 MR"
msgid "ContributionAnalytics|Closed MRs"
-msgstr ""
+msgstr "已关闭的 MR"
msgid "ContributionAnalytics|Closed issues"
-msgstr ""
+msgstr "已关闭的议题"
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr "自%{start_date}起的议题,åˆå¹¶è¯·æ±‚和推é€äº‹ä»¶çš„贡献分æž"
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr "æ¯ä¸ªç¾¤ç»„æˆå‘˜çš„贡献"
+
msgid "ContributionAnalytics|Failed to load the contribution stats"
-msgstr ""
+msgstr "加载贡献统计失败"
msgid "ContributionAnalytics|Issues"
msgstr "议题"
@@ -11065,16 +11294,16 @@ msgid "ContributionAnalytics|Last week"
msgstr "上周"
msgid "ContributionAnalytics|Loading contribution stats for group members"
-msgstr ""
+msgstr "正在为群组æˆå‘˜åŠ è½½è´¡çŒ®ç»Ÿè®¡"
msgid "ContributionAnalytics|Merge requests"
msgstr "åˆå¹¶è¯·æ±‚"
msgid "ContributionAnalytics|Merged MRs"
-msgstr ""
+msgstr "å·²åˆå¹¶çš„åˆå¹¶è¯·æ±‚"
msgid "ContributionAnalytics|Name"
-msgstr ""
+msgstr "å称"
msgid "ContributionAnalytics|No issues for the selected time period."
msgstr "在选定的时间段内没有议题。"
@@ -11086,16 +11315,19 @@ msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "在选定的时间段内没有推é€ã€‚"
msgid "ContributionAnalytics|Opened MRs"
-msgstr ""
+msgstr "å¼€å¯çš„åˆå¹¶è¯·æ±‚"
msgid "ContributionAnalytics|Opened issues"
-msgstr ""
+msgstr "å¼€å¯çš„议题"
msgid "ContributionAnalytics|Pushed"
-msgstr ""
+msgstr "已推é€"
+
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr "给定的日期范围大于 %{number_of_days} 天"
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
-msgstr "给定的日期范围大于 31 天"
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
+msgstr "给定的日期范围大于 93 天"
msgid "ContributionAnalytics|The to date is earlier than the given from date"
msgstr "结æŸæ—¥æœŸæ—©äºŽç»™å®šçš„开始日期"
@@ -11104,7 +11336,7 @@ msgid "ContributionAnalytics|There is too much data to calculate. Try lowering t
msgstr "æ•°æ®å¤ªå¤šï¼Œæ— æ³•è®¡ç®—。å°è¯•é™ä½Žæ´žå¯Ÿé…置文件中的 period_limit 设置。"
msgid "ContributionAnalytics|Total Contributions"
-msgstr ""
+msgstr "总贡献"
msgid "Contributions for %{calendar_date}"
msgstr "%{calendar_date}的贡献"
@@ -11115,8 +11347,8 @@ msgstr "群组æˆå‘˜è´¡çŒ®è¯¦æƒ…"
msgid "Contributor"
msgstr "贡献者"
-msgid "Contributors"
-msgstr "贡献者"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr "控制与您å¸æˆ·å…³è”的电å­é‚®ä»¶"
@@ -11187,6 +11419,9 @@ msgstr "å¤åˆ¶å‘½ä»¤"
msgid "Copy commit SHA"
msgstr "å¤åˆ¶æ交SHA"
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr "å¤åˆ¶çŽ¯å¢ƒ"
@@ -11433,7 +11668,7 @@ msgstr "无法将策略分é…给项目或群组"
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr "找ä¸åˆ°å®¡è®¡äº‹ä»¶ç±»åž‹çš„事件类型过滤器:%{missing_filters}"
-msgid "Country"
+msgid "Country / Region"
msgstr "国家/地区"
msgid "Counts"
@@ -11622,6 +11857,9 @@ msgstr "创建一个"
msgid "Create or close an issue."
msgstr "创建或关闭议题。"
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr "创建或导入您的第一个项目"
@@ -11871,9 +12109,6 @@ msgstr "创建于"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "创建了一个分支和一个åˆå¹¶è¯·æ±‚æ¥è§£å†³æ­¤è®®é¢˜ã€‚"
-msgid "Created at"
-msgstr "创建于"
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "创建了分支“%{branch_name}â€å’Œåˆå¹¶è¯·æ±‚以解决此议题。"
@@ -12081,6 +12316,9 @@ 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 "我们目å‰æ— æ³•èŽ·å–æ­¤æµæ°´çº¿çš„æ•°æ®ã€‚"
@@ -12180,8 +12418,8 @@ msgstr "议题首次添加到看æ¿"
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "议题首次与里程碑相关è”"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
-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 "议题首次在æ交中æåŠ"
@@ -12346,9 +12584,6 @@ msgstr "ä¸æ”¯æŒåˆ†é…的对象"
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr "DAGå¯è§†åŒ–至少需è¦3个ä¾èµ–作业。"
-msgid "DAST Configuration"
-msgstr "DAST é…ç½®"
-
msgid "DAST configuration not found"
msgstr "未找到 DAST é…ç½®"
@@ -12638,7 +12873,7 @@ msgid "DastProfiles|Enter URLs in a comma-separated list."
msgstr "在逗å·åˆ†éš”列表中输入 URL。"
msgid "DastProfiles|Enter a comma-separated list of request header names and values. DAST adds header to every request."
-msgstr ""
+msgstr "输入一个逗å·åˆ†éš”的请求 header å称和值的列表。DAST 会为æ¯ä¸ªè¯·æ±‚添加 header。"
msgid "DastProfiles|Error Details"
msgstr "错误详细信æ¯"
@@ -12656,7 +12891,7 @@ msgid "DastProfiles|Excluded paths (optional)"
msgstr "排除的路径(å¯é€‰ï¼‰"
msgid "DastProfiles|Headers will appear in vulnerability reports. %{linkStart}Only some headers are automatically masked%{linkEnd}."
-msgstr ""
+msgstr "Headers 将会在æ¼æ´žæŠ¥å‘Šä¸­å‡ºçŽ°ã€‚%{linkStart}åªæœ‰éƒ¨åˆ† headers 会被自动éšè—%{linkEnd}。"
msgid "DastProfiles|Hide debug messages"
msgstr "éšè—调试消æ¯"
@@ -13251,7 +13486,7 @@ msgid "Delete comment"
msgstr "删除评论"
msgid "Delete comment?"
-msgstr ""
+msgstr "删除评论?"
msgid "Delete corpus"
msgstr "删除语料库"
@@ -13259,6 +13494,9 @@ msgstr "删除语料库"
msgid "Delete deploy key"
msgstr "删除部署密钥"
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr "删除å²è¯—"
@@ -13301,9 +13539,12 @@ msgstr "删除å‘布 %{release}?"
msgid "Delete row"
msgstr "删除行"
-msgid "Delete selected"
+msgid "Delete saved reply"
msgstr ""
+msgid "Delete selected"
+msgstr "删除所选"
+
msgid "Delete self-monitoring project"
msgstr "删除自监控项目"
@@ -14044,6 +14285,9 @@ msgstr "æˆåŠŸ"
msgid "Deprecated API rate limits"
msgstr "已弃用的 API 速率é™åˆ¶"
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr "关于å¯èƒ½æ›¿æ¢çš„ä¿¡æ¯ï¼Œ%{epicStart}了解更多关于 Opstrace %{epicEnd}。"
@@ -14144,12 +14388,15 @@ 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 discussion. Please try again."
msgstr "无法更新讨论。请å†è¯•ä¸€æ¬¡ã€‚"
-msgid "DesignManagement|Could not update note. Please try again."
-msgstr "无法更新注释。请å†è¯•ä¸€æ¬¡ã€‚"
-
msgid "DesignManagement|Deselect all"
msgstr "å–消全部选择"
@@ -14252,6 +14499,9 @@ msgstr "DevOps adoption"
msgid "Developer"
msgstr "å¼€å‘者"
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr "设备(å¯é€‰ï¼‰"
@@ -14447,6 +14697,9 @@ msgstr "您的使用情况"
msgid "Diagram (%{language})"
msgstr "图表(%{language})"
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr "ä¸è¦åˆ é™¤æºåˆ†æ”¯ã€‚"
@@ -14597,9 +14850,6 @@ msgstr "Discord 通知"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr "å‘ Discord 频é“å‘é€æœ‰å…³é¡¹ç›®äº‹ä»¶çš„通知。"
-msgid "Discover"
-msgstr "å‘现"
-
msgid "Discover GitLab Geo"
msgstr "探索GitLab Geo"
@@ -15036,6 +15286,9 @@ msgstr "编辑部署密钥"
msgid "Edit description"
msgstr "编辑æè¿°ä¿¡æ¯"
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr "编辑环境"
@@ -15060,6 +15313,9 @@ msgstr "编辑 %{user_name} 的身份信æ¯"
msgid "Edit image description"
msgstr "编辑图片æè¿°"
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr "在æµæ°´çº¿ç¼–辑器中编辑"
@@ -15078,9 +15334,15 @@ msgstr "编辑链接"
msgid "Edit merge requests"
msgstr "编辑åˆå¹¶è¯·æ±‚"
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr "编辑公共部署密钥"
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr "编辑侧边æ "
@@ -15537,6 +15799,9 @@ msgstr "输入管ç†å‘˜æ¨¡å¼çš„åŒé‡éªŒè¯ç "
msgid "Enter Admin Mode"
msgstr "进入管ç†å‘˜æ¨¡å¼"
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr "输入数字"
@@ -15582,8 +15847,8 @@ msgstr "输入 %{name} çš„æè¿°"
msgid "Enter the %{name} title"
msgstr "输入 %{name} 标题"
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
-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 "输入以下内容以确认:"
@@ -15600,6 +15865,9 @@ msgstr "输入å—密ç ä¿æŠ¤çš„ Elasticsearch æœåŠ¡å™¨çš„密ç ã€‚"
msgid "Enter the username for password-protected Elasticsearch servers."
msgstr "输入å—密ç ä¿æŠ¤çš„ Elasticsearch æœåŠ¡å™¨çš„用户å。"
+msgid "Enter verification code"
+msgstr "输入验è¯ç "
+
msgid "Enter your Packagist server. Defaults to https://packagist.org."
msgstr "输入您的 Packagist æœåŠ¡å™¨ã€‚默认为 https://packagist.org。"
@@ -15619,7 +15887,7 @@ msgid "EnterpriseUsers|The user detail cannot be updated"
msgstr "无法更新用户详细信æ¯"
msgid "EnterpriseUsers|The user does not match the \"Enterprise User\" definition for the group"
-msgstr ""
+msgstr "用户与该群组的ä¼ä¸šç”¨æˆ·å®šä¹‰ä¸åŒ¹é…"
msgid "EnterpriseUsers|The user is already an enterprise user"
msgstr "该用户已ç»æ˜¯ä¼ä¸šç”¨æˆ·"
@@ -15894,6 +16162,9 @@ msgstr "å²è¯—看æ¿"
msgid "Epic actions"
msgstr "å²è¯—æ“作"
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr "找ä¸åˆ°å²è¯—。"
@@ -16005,6 +16276,9 @@ 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 "创建代ç ç‰‡æ®µ%{snippet_id}的代ç åº“时出错"
@@ -16293,6 +16567,9 @@ msgstr "您确定è¦åˆ é™¤â€œ%{escalationPolicy}â€å‡çº§ç­–ç•¥å—?此æ“作æ—
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 "如果首先è”系的人没有回应警报,选择å‘è°å‘电å­é‚®ä»¶ã€‚è¦ä½¿ç”¨è¯¥åŠŸèƒ½ï¼Œæ‚¨éœ€è¦è¯·%{linkStart}项目负责人%{linkEnd}至少授予您维护者的角色。"
+
msgid "EscalationPolicies|Create an escalation policy in GitLab"
msgstr "在 GitLab 中创建å‡çº§ç­–ç•¥"
@@ -16570,6 +16847,9 @@ msgstr "凭è¯é›†"
msgid "Exactly one of %{attributes} is required"
msgstr "其中的一个%{attributes}是必需的"
+msgid "Example"
+msgstr "示例"
+
msgid "Example: (feature|hotfix)\\/*"
msgstr "示例:(feature|hotfix)\\/*"
@@ -16594,6 +16874,9 @@ msgstr "除外(Except)æ¡ä»¶ï¼š"
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 "ä¸åŒ…括åˆå¹¶æ交。仅é™%{limit}次æ交。"
@@ -16795,6 +17078,9 @@ msgstr "未设置分类标签的时候,将使用默认的分类标签`%{defaul
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 "外部授æƒ|用于通过外部授æƒæœåŠ¡è¿›è¡Œèº«ä»½éªŒè¯çš„è¯ä¹¦ã€‚如果为空,则在通过 HTTPS 访问时验è¯æœåŠ¡å™¨è¯ä¹¦ã€‚"
@@ -16813,6 +17099,9 @@ msgstr "客户端授æƒå¯†é’¥å¯†ç ï¼ˆå¯é€‰ï¼‰"
msgid "ExternalAuthorization|Default classification label"
msgstr "默认分类标签"
+msgid "ExternalAuthorization|Does not apply if service URL is specified."
+msgstr "如果指定了æœåŠ¡ URL,则ä¸é€‚用。"
+
msgid "ExternalAuthorization|Enable classification control using an external service"
msgstr "使用外部æœåŠ¡å¯ç”¨åˆ†ç±»æŽ§åˆ¶"
@@ -17380,9 +17669,6 @@ msgstr "2月"
msgid "February"
msgstr "2月"
-msgid "Feedback and Updates"
-msgstr "å馈和更新"
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr "获å–并检出这个åˆå¹¶è¯·æ±‚的功能分支:"
@@ -17506,6 +17792,9 @@ msgstr "筛选å‚数无效。请确ä¿ç»“æŸæ—¥æœŸåœ¨å¼€å§‹æ—¥æœŸä¹‹åŽã€‚"
msgid "Filter pipelines"
msgstr "筛选æµæ°´çº¿"
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr "筛选结果"
@@ -17662,9 +17951,6 @@ msgstr "对于æ¯ä¸ªä½œä¸šï¼Œé‡æ–°ä½¿ç”¨é¡¹ç›®å·¥ä½œåŒºï¼Œå¦‚果工作区ä¸å­˜
msgid "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 "例如,使用令牌的应用程åºæˆ–令牌的用途。ä¸è¦æ供令牌å称的æ•æ„Ÿä¿¡æ¯ï¼Œå› ä¸ºå®ƒå°†å¯¹æ‰€æœ‰ %{resource_type} æˆå‘˜å¯è§ã€‚"
-msgid "For faster browsing, not all history is shown."
-msgstr "为了加快æµè§ˆé€Ÿåº¦ï¼Œä¸ä¼šæ˜¾ç¤ºæ‰€æœ‰åŽ†å²è®°å½•ã€‚"
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr "对于大于此é™åˆ¶çš„文件,仅索引文件å,文件内容既ä¸ç¼–入索引也ä¸å¯æœç´¢ã€‚"
@@ -17806,9 +18092,6 @@ msgstr "æ ¼å¼ï¼š%{dateFormat}"
msgid "Framework successfully deleted"
msgstr "框架删除æˆåŠŸ"
-msgid "Free"
-msgstr "å…è´¹"
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr "å…费试用"
@@ -18616,14 +18899,23 @@ msgstr "报告时间段必须是数字。"
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "报告时间长度应该在 %{minTimePeriod} - %{maxTimePeriod} 秒之间。"
+msgid "GitAbuse|Select between %{minAlertedUsers} and %{maxAlertedUsers} users to notify."
+msgstr "选择通知 %{minAlertedUsers} 到 %{maxAlertedUsers} 个数é‡èŒƒå›´å†…的用户。"
+
+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 "超过 Git 滥用率é™åˆ¶æ—¶åº”收到电å­é‚®ä»¶é€šçŸ¥çš„用户。"
+
msgid "GitAbuse|Users who are excluded from the Git abuse rate limit."
msgstr "被排除在 Git 滥用率é™åˆ¶ä¹‹å¤–的用户。"
-msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
-msgstr "您ä¸èƒ½æŒ‡å®šè¶…过 %{maxExcludedUsers} 个排除的用户。"
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr "您ä¸èƒ½æŒ‡å®šè¶…过 %{maxAllowedUsers} 个除外的用户。"
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr "GitHub API速率超过é™åˆ¶ã€‚请在%{reset_time}åŽé‡è¯•"
@@ -18673,6 +18965,9 @@ msgstr "GitLab KAS"
msgid "GitLab Pages"
msgstr "GitLab Pages"
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr "GitLab Shell"
@@ -18697,6 +18992,12 @@ msgstr "GitLabå¸æˆ·è¯·æ±‚被拒ç»"
msgid "GitLab commit"
msgstr "GitLabæ交"
+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 "GitLab 文档"
@@ -18712,9 +19013,6 @@ msgstr "GitLab for Jira Cloud"
msgid "GitLab group: %{source_link}"
msgstr "GitLab 群组:%{source_link}"
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr "如果有新版本å¯ç”¨ï¼ŒGitLab 会通知您。%{link_start}GitLab Inc. 收集哪些信æ¯ï¼Ÿ%{link_end}"
@@ -18763,10 +19061,6 @@ msgstr "GitLab 版本"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab 将在你的派生项目中创建分支并开始åˆå¹¶è¯·æ±‚。"
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -18860,12 +19154,18 @@ msgstr "未验è¯"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "正在更新您的页é¢é…ç½®..."
+msgid "GitLabPages|Use unique domain"
+msgstr "使用唯一域å"
+
msgid "GitLabPages|Verified"
msgstr "已验è¯"
msgid "GitLabPages|Waiting for the Pages Pipeline to complete..."
msgstr "正在等待 Pages æµæ°´çº¿å®Œæˆ..."
+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 "å¯ç”¨åŽï¼Œæ‰€æœ‰é€šè¿‡HTTP的访问å°è¯•éƒ½ä¼šè‡ªåŠ¨é‡å®šå‘到HTTPS,使用状æ€ä»£ç 301。 需è¦å¯¹æ‰€æœ‰åŸŸå有效的è¯ä¹¦ã€‚%{docs_link_start}了解更多信æ¯ã€‚%{link_end}"
@@ -18905,6 +19205,9 @@ msgstr "Gitea 主机地å€"
msgid "Gitea Import"
msgstr "从Gitea导入"
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr "ID 为 %{gist_id} 的 Gist 因错误而失败:%{error}。"
@@ -18917,14 +19220,14 @@ msgstr "未导入的 GitHub gists:"
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr "超过 10 个文件的 GitHub gists 必须手动è¿ç§»ã€‚"
-msgid "GithubImporter|Issue attachments"
-msgstr "议题附件"
+msgid "GithubImporter|Issue links"
+msgstr ""
-msgid "GithubImporter|Merge request attachments"
-msgstr "åˆå¹¶è¯·æ±‚附件"
+msgid "GithubImporter|Merge request links"
+msgstr ""
-msgid "GithubImporter|Note attachments"
-msgstr "注释附件"
+msgid "GithubImporter|Note links"
+msgstr ""
msgid "GithubImporter|PR mergers"
msgstr "PR åˆå¹¶è€…"
@@ -18941,8 +19244,8 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr "拉å–请求"
-msgid "GithubImporter|Release attachments"
-msgstr "å‘布附件"
+msgid "GithubImporter|Release links"
+msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
msgstr "您将 Github gists 导入GitLab 代ç ç‰‡æ®µçš„æ“作已完æˆã€‚"
@@ -18995,6 +19298,9 @@ msgstr "%{time_ago}授æƒè®¿é—®"
msgid "Given epic is already related to this epic."
msgstr "给定å²è¯—å·²ç»ä¸Žæ­¤å²è¯—å…³è”。"
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr "此范围的全局æœç´¢å·²ç¦ç”¨"
@@ -19067,6 +19373,9 @@ msgstr "最近的议题"
msgid "GlobalSearch|Recent merge requests"
msgstr "最近的åˆå¹¶è¯·æ±‚"
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr "结果计数超过é™åˆ¶ã€‚"
@@ -19121,15 +19430,9 @@ msgstr "您想è¦æœç´¢ä»€ä¹ˆï¼Ÿ"
msgid "GlobalSearch|all GitLab"
msgstr "全局æœç´¢"
-msgid "GlobalSearch|group"
-msgstr "群组"
-
msgid "GlobalSearch|in %{scope}"
msgstr "在%{scope}中"
-msgid "GlobalSearch|project"
-msgstr "项目"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr "å·²å¤åˆ¶æºåˆ†æ”¯å称到剪贴æ¿ã€‚"
@@ -19346,6 +19649,30 @@ msgstr "撤销授æƒ"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "撤销授予 GitLab 的授æƒï¼Œä¸ä¼šä½¿æœåŠ¡å¸æˆ·å¤±æ•ˆã€‚"
+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 "知é“了"
@@ -19535,6 +19862,9 @@ msgstr "群组å称(您的组织)"
msgid "Group navigation"
msgstr "群组导航"
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr "群组概述内容"
@@ -19716,7 +20046,7 @@ msgid "GroupSAML|Enable SAML authentication for this group"
msgstr "为此群组å¯ç”¨ SAML 身份认è¯"
msgid "GroupSAML|Enforce SSO-only authentication for Git and Dependency Proxy activity for this group"
-msgstr "对该组的 Git å’Œä¾èµ–代ç†æ´»åŠ¨å¼ºåˆ¶æ‰§è¡Œä»… SSO 身份验è¯"
+msgstr "对该群组的 Git å’Œä¾èµ–代ç†æ´»åŠ¨å¼ºåˆ¶æ‰§è¡Œä»… SSO 身份验è¯"
msgid "GroupSAML|Enforce SSO-only authentication for web activity for this group"
msgstr "对该群组的 Web 活动强制执行仅 SSO 身份验è¯"
@@ -19886,6 +20216,9 @@ msgstr "更改群组 URL å¯èƒ½ä¼šäº§ç”Ÿæ„外的副作用。"
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 "åˆè§„框架"
@@ -20144,6 +20477,9 @@ msgstr "输入æºå®žä¾‹çš„ URL。"
msgid "GroupsNew|GitLab source instance URL"
msgstr "GitLab æºå®žä¾‹ URL"
+msgid "GroupsNew|Groups"
+msgstr ""
+
msgid "GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}."
msgstr "通过创建 %{linkStart}å­ç»„%{linkEnd} 也å¯ä»¥åµŒå¥—群组。"
@@ -20159,6 +20495,12 @@ msgstr "通过直接传输导入群组"
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr "ç›®å‰å·²ç¦ç”¨é€šè¿‡ç›´æŽ¥ä¼ è¾“导入群组。"
+msgid "GroupsNew|New group"
+msgstr "新建群组"
+
+msgid "GroupsNew|New subgroup"
+msgstr "新建å­ç»„"
+
msgid "GroupsNew|No import options available"
msgstr "æ— å¯ç”¨çš„导入选项"
@@ -20533,6 +20875,9 @@ msgstr "帮助å‡å°‘请求é‡ï¼ˆä¾‹å¦‚æ¥è‡ªçˆ¬è™«æˆ–滥用机器人的请求)
msgid "Helps reduce request volume for protected paths."
msgstr "有助于å‡å°‘å—ä¿æŠ¤è·¯å¾„的请求é‡ã€‚"
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr "%{username},您好!"
@@ -20818,7 +21163,7 @@ msgid "IP subnet restriction only allowed for top-level groups"
msgstr "åªå…许在最顶层群组设置IPå­ç½‘é™åˆ¶"
msgid "Icon will be removed. Are you sure?"
-msgstr ""
+msgstr "图标将被删除。您确定å—?"
msgid "Id"
msgstr "ID"
@@ -20874,6 +21219,9 @@ 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 "为了增加安全性,您需è¦éªŒè¯æ‚¨çš„èº«ä»½ã€‚æˆ‘ä»¬å·²å‘ %{email} å‘é€éªŒè¯ç "
@@ -20973,6 +21321,9 @@ msgstr "验è¯æ‚¨çš„身份"
msgid "IdentityVerification|We sent a new code to +%{phoneNumber}"
msgstr "æˆ‘ä»¬å‘ +%{phoneNumber} å‘é€äº†ä¸€ä¸ªæ–°éªŒè¯ç "
+msgid "IdentityVerification|We've sent a verification code to %{email}"
+msgstr "我们已将验è¯ç å‘é€è‡³ %{email}"
+
msgid "IdentityVerification|We've sent a verification code to +%{phoneNumber}"
msgstr "æˆ‘ä»¬å‘ +%{phoneNumber} å‘é€äº†ä¸€ä¸ªéªŒè¯ç "
@@ -21015,15 +21366,24 @@ msgstr "如选中,则群组所有者å¯ä»¥ç®¡ç†LDAP群组链接和 LDAPæˆå‘˜
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "选中åŽå°†åˆ™åªèƒ½é€šè¿‡LDAPåŒæ­¥æ·»åŠ æ–°çš„组æˆå‘˜èº«ä»½å’Œæƒé™"
+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 "如果ç¦ç”¨ï¼Œåˆ†å‰çš„本地分支将ä¸ä¼šè‡ªåŠ¨æ›´æ–°å…¶è¿œç«¯åˆ†æ”¯çš„æ交,以防止本地数æ®ä¸¢å¤±ã€‚如果默认分支 (%{default_branch}) 分å‰å¹¶ä¸”无法更新,则镜åƒå°†å¤±è´¥ã€‚其他分å‰çš„分支被é™é»˜å¿½ç•¥ã€‚%{link_start}了解更多。%{link_end}"
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 "如果活跃用户数é‡è¶…过了用户é™åˆ¶ï¼Œæ‚¨ä¸‹æ¬¡çš„许å¯è¯å¯¹è´¦æ—¶å°†ä¼šæ”¶å–%{users_over_license_link}个席ä½çš„费用。"
@@ -21084,8 +21444,8 @@ msgstr "如果您丢失了æ¢å¤ç ï¼Œæ‚¨å¯ä»¥ç”Ÿæˆæ–°çš„æ¢å¤ç ï¼Œæ‰€æœ‰ä»¥
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "如果您最近从上述IP地å€ç™»å½•è¿‡ï¼Œåˆ™å¯ä»¥å¿½ç•¥æ­¤ç”µå­é‚®ä»¶ã€‚"
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore 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 "如果您想è¦é‡æ–°å¯ç”¨åŒé‡èº«ä»½éªŒè¯ï¼Œè¯·è®¿é—®%{two_factor_link}"
@@ -21308,6 +21668,9 @@ msgstr "导入项目失败"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr "导入项目失败: %{reason}"
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr "é‡æ–°å¯¼å…¥å°†åˆ›å»ºä¸€ä¸ªæ–°é¡¹ç›®ã€‚它ä¸ä¸ŽçŽ°æœ‰é¡¹ç›®åŒæ­¥ã€‚"
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr "请求命å空间失败"
@@ -21711,8 +22074,8 @@ msgstr "通过使用 DAST 检查部署环境中的æ¼æ´žï¼Œä¿æŠ¤æ‚¨çš„ web 应ç
msgid "InProductMarketing|Rapid development, simplified"
msgstr "快速开å‘,简化"
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
-msgstr "é™ä½Žå®‰å…¨ä¸Žåˆè§„风险"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
+msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
msgstr "在åˆå¹¶è¯·æ±‚时需è¦å¤šä¸ªå®¡æ‰¹ï¼Œæ‰€ä»¥æ‚¨å¯ä»¥çŸ¥é“它处于良好状æ€ï¼Œç„¶åŽæ‰èƒ½åˆå¹¶ã€‚"
@@ -22374,12 +22737,18 @@ msgstr "æ’入图片"
msgid "Insert link"
msgstr "æ’入链接"
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr "下方æ’入行"
msgid "Insert row before"
msgstr "上方æ’入行"
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr "æ’入建议"
@@ -22445,22 +22814,22 @@ msgid "Integration Settings"
msgstr "集æˆè®¾ç½®"
msgid "IntegrationEvents|A comment is added"
-msgstr ""
+msgstr "已添加评论"
msgid "IntegrationEvents|A confidential issue is created, closed, or reopened"
-msgstr ""
+msgstr "已创建,更改或é‡æ–°æ‰“开一个ç§å¯†è®®é¢˜"
msgid "IntegrationEvents|A deployment is started or finished"
msgstr "部署已开始或已完æˆ"
msgid "IntegrationEvents|A merge request is created, merged, closed, or reopened"
-msgstr ""
+msgstr "已创建ã€åˆå¹¶ã€å…³é—­æˆ–é‡æ–°æ‰“开一个åˆå¹¶è¯·æ±‚"
msgid "IntegrationEvents|A new, unique alert is recorded"
-msgstr "记录了一个新的ã€ç‹¬ç‰¹çš„警报"
+msgstr "已记录一个新的ã€ç‹¬ç‰¹çš„警报"
msgid "IntegrationEvents|A new, unique vulnerability is recorded (available only in GitLab Ultimate)"
-msgstr "记录了一个新的独特æ¼æ´žï¼ˆä»…适用于旗舰版)"
+msgstr "已记录一个新的独特æ¼æ´žï¼ˆä»…适用于旗舰版)"
msgid "IntegrationEvents|A pipeline status changes"
msgstr "æµæ°´çº¿çŠ¶æ€å˜æ›´"
@@ -22469,19 +22838,19 @@ msgid "IntegrationEvents|A push is made to the repository"
msgstr "有一个推é€åˆ°æ­¤ä»“库"
msgid "IntegrationEvents|A tag is pushed to the repository or removed"
-msgstr ""
+msgstr "标签被推é€åˆ°ä»“库或被删除"
msgid "IntegrationEvents|A wiki page is created or updated"
msgstr "已创建或更新 wiki 页é¢"
msgid "IntegrationEvents|An incident is created, closed, or reopened"
-msgstr ""
+msgstr "已创建ã€å…³é—­æˆ–é‡æ–°æ‰“开一个事件(incident)"
msgid "IntegrationEvents|An internal note or comment on a confidential issue is added"
-msgstr ""
+msgstr "已添加关于ç§å¯†è®®é¢˜çš„内部备注或评论"
msgid "IntegrationEvents|An issue is created, closed, or reopened"
-msgstr ""
+msgstr "已创建ã€å…³é—­æˆ–é‡æ–°æ‰“开议题"
msgid "Integrations"
msgstr "集æˆ"
@@ -22552,12 +22921,15 @@ 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 GitLab.com slash commands in a Slack workspace."
-msgstr "在 Slack 工作区中å¯ç”¨ GitLab.com 指令。"
-
msgid "Integrations|Enable SSL verification"
msgstr "å¯ç”¨ SSL 验è¯"
@@ -22573,6 +22945,9 @@ msgstr "ç¡®ä¿æ‚¨çš„实例 URL 正确且您的实例é…置正确。%{linkStart}ä
msgid "Integrations|Enter your alias"
msgstr "输入您的别å"
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr "无法链接命å空间,请é‡è¯•ã€‚"
@@ -22861,8 +23236,8 @@ msgstr "针对代ç ç‰‡æ®µ%{snippet_id}的无效仓库包"
msgid "Invalid repository path"
msgstr "无效的仓库路径"
-msgid "Invalid rule"
-msgstr "无效规则"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr "无效的æœåŠ¡å™¨å“应"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr "探索付费方案"
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr "GitLab 与åŒäº‹å…±å¤„æ›´ä½³ï¼"
@@ -23261,6 +23633,12 @@ msgstr "议题类型"
msgid "Issue already promoted to epic."
msgstr "问题已å‡çº§ä¸ºå²è¯—。"
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr "议题无法找到"
@@ -23486,6 +23864,9 @@ msgstr "移动议题时出错。"
msgid "Issue|Title"
msgstr "标题"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr "您似乎正在å°è¯•æ¿€æ´»æ‚¨çš„订阅。请使用 %{a_start}订阅页é¢%{a_end} 代替。"
@@ -23757,7 +24138,7 @@ msgid "JiraConnect|Create branch for Jira issue %{jiraIssue}"
msgstr "为Jira议题%{jiraIssue}创建分支"
msgid "JiraConnect|Enable public key storage"
-msgstr ""
+msgstr "å¯ç”¨å…¬é’¥å­˜å‚¨"
msgid "JiraConnect|Failed to create branch."
msgstr "创建分支失败。"
@@ -23829,7 +24210,7 @@ msgid "JiraService|Automatically transitions Jira issues to the \"Done\" categor
msgstr "自动将 Jira 问题转æ¢ä¸ºâ€œå®Œæˆâ€ç±»åˆ«ã€‚ %{linkStart}了解更多%{linkEnd}"
msgid "JiraService|Base URL of the Jira instance"
-msgstr ""
+msgstr "Jira 实例的 Base URL"
msgid "JiraService|Change GitLab version"
msgstr "更改 GitLab 版本"
@@ -23883,7 +24264,7 @@ msgid "JiraService|IDs must be a list of numbers that can be split with , or ;"
msgstr "ID 必须是å¯ä»¥ç”¨ , 或 ; 分割的数字列表"
msgid "JiraService|If different from the Web URL"
-msgstr ""
+msgstr "如果与 Web URL ä¸åŒ"
msgid "JiraService|In order to complete the set up, you’ll need to complete a few steps in GitLab."
msgstr "为了完æˆè®¾ç½®ï¼Œæ‚¨éœ€è¦åœ¨ GitLab 中完æˆå‡ ä¸ªæ­¥éª¤ã€‚"
@@ -23916,7 +24297,7 @@ msgid "JiraService|Open Jira"
msgstr "打开Jira"
msgid "JiraService|Password for the server version or an API token for the cloud version"
-msgstr ""
+msgstr "æœåŠ¡å™¨ç‰ˆæœ¬çš„密ç æˆ–云版本的 API 令牌。"
msgid "JiraService|Password or API token"
msgstr "密ç æˆ– API 令牌"
@@ -23955,7 +24336,7 @@ msgid "JiraService|Username for the server version or an email for the cloud ver
msgstr ""
msgid "JiraService|Username or email"
-msgstr ""
+msgstr "用户å或电å­é‚®ä»¶"
msgid "JiraService|Using Jira for issue tracking?"
msgstr "使用Jira进行议题跟踪å—?"
@@ -24023,9 +24404,24 @@ msgstr "作业已é‡è¯•"
msgid "JobAssistant|Add job"
msgstr "添加作业"
+msgid "JobAssistant|Job Setup"
+msgstr "作业设置"
+
msgid "JobAssistant|Job assistant"
msgstr "作业助ç†"
+msgid "JobAssistant|Job name"
+msgstr "作业å称"
+
+msgid "JobAssistant|Script"
+msgstr "脚本"
+
+msgid "JobAssistant|Stage (optional)"
+msgstr "阶段(å¯é€‰ï¼‰"
+
+msgid "JobAssistant|Tags (optional)"
+msgstr "标签(å¯é€‰ï¼‰"
+
msgid "Jobs"
msgstr "作业"
@@ -24712,6 +25108,15 @@ msgstr "了解更多。"
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
msgstr "%{percentage}%{percentSymbol} 已完æˆ"
+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 "添加代ç æ‰€æœ‰è€…"
@@ -24793,6 +25198,9 @@ 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 "æ交åˆå¹¶è¯·æ±‚ (MR)"
@@ -24802,6 +25210,9 @@ msgstr "å…费试用旗舰版"
msgid "LearnGitLab|Try all GitLab features for 30 days, no credit card required."
msgstr "试用所有 GitLab 功能 30 天,无需信用å¡ã€‚"
+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 "使用您的新 GitLab 工作æµç¨‹éƒ¨ç½²æ‚¨çš„应用程åºã€ç›‘控其è¿è¡ŒçŠ¶å†µå¹¶ç¡®ä¿å…¶å®‰å…¨ï¼š"
@@ -24817,9 +25228,6 @@ msgstr "请è”系您的管ç†å‘˜ä»¥å¯ç”¨æ­¤æ“作。"
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr "请è”系您的管ç†å‘˜ï¼Œå¼€å§‹å…费的旗舰版试用。"
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr "正在创建您的入门体验..."
-
msgid "LearnGitlab|Ok, let's go"
msgstr "好的,让我们去å§"
@@ -24835,6 +25243,9 @@ msgstr "离开管ç†å‘˜æ¨¡å¼"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "退出编辑模å¼ï¼Ÿæ‰€æœ‰æœªä¿å­˜çš„更改都将丢失。"
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "退出群组"
@@ -25078,6 +25489,10 @@ msgstr "é™åˆ¶å­˜å‚¨åœ¨Redis中的Sidekiq作业的大å°ã€‚"
msgid "Limiting mode"
msgstr "é™åˆ¶æ¨¡å¼"
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr "è¡Œå˜æ›´"
@@ -25105,6 +25520,9 @@ msgstr "从项目的侧边æ é“¾æŽ¥å¤–部 wiki。 %{docs_link}"
msgid "Link copied"
msgstr "链接已å¤åˆ¶"
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr "链接文本"
@@ -25198,9 +25616,6 @@ msgstr "列出å¯ç”¨ä»“库"
msgid "List of all commits"
msgstr "所有æ交列表"
-msgid "List of all merge commits"
-msgstr "所有åˆå¹¶æ交列表"
-
msgid "List of suitable GCP locations"
msgstr "åˆé€‚çš„ GCP ä½ç½®åˆ—表"
@@ -25243,6 +25658,9 @@ msgstr "加载群组æˆå‘˜çš„贡献统计信æ¯"
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr "加载æ交引用%{ref}路径%{path}中的文件,目录和å­æ¨¡å—"
+msgid "Loading full blame..."
+msgstr ""
+
msgid "Loading more"
msgstr "加载更多"
@@ -25282,6 +25700,9 @@ msgstr "é”定文件?"
msgid "Lock memberships to LDAP synchronization"
msgstr "é”定æˆå‘˜èº«ä»½åˆ°LDAPåŒæ­¥"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr "é”定åˆå¹¶è¯·æ±‚"
@@ -25300,9 +25721,6 @@ msgstr "é”定到当å‰é¡¹ç›®"
msgid "Locked"
msgstr "å·²é”定"
-msgid "Locked Files"
-msgstr "å·²é”定文件"
-
msgid "Locked by %{fileLockUserName}"
msgstr "被%{fileLockUserName}é”定"
@@ -25372,9 +25790,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "å·²åˆå¹¶"
-msgid "ML Experiments"
-msgstr "机器学习实验"
-
msgid "MR widget|Back to the merge request"
msgstr "返回åˆå¹¶è¯·æ±‚"
@@ -25411,11 +25826,8 @@ msgstr "åªæŸ¥çœ‹å˜æ›´å†…容"
msgid "MRDiff|Show full file"
msgstr "显示全部文件"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr "机器学习实验跟踪处于孵化阶段"
-
-msgid "Machine Learning Experiments"
-msgstr "机器学习实验"
+msgid "Macbook Touch ID on Edge"
+msgstr ""
msgid "Made this %{type} confidential."
msgstr "已将此 %{type} 设置为ç§å¯†ã€‚"
@@ -25811,7 +26223,7 @@ msgid "Maximum file size is 1 MB. Pages are optimized for a 128x128 px logo."
msgstr "最大文件大å°ä¸º 1 MB,页é¢å·²é’ˆå¯¹ 128x128 åƒç´ å¤§å°çš„ logo 进行了优化。"
msgid "Maximum file size is 1MB."
-msgstr ""
+msgstr "最大文件大å°ä¸º 1MB"
msgid "Maximum file size is 1MB. Pages are optimized for a 24px tall header logo"
msgstr "最大文件大å°ç‚ºä¸º 1MB。页é¢é’ˆå¯¹ 24 åƒç´ é«˜çš„ header logo 进行了优化"
@@ -25906,6 +26318,9 @@ msgstr "最大推é€å¤§å°"
msgid "Maximum push size (MB)"
msgstr "最大推é€å¤§å° (MB)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr "æ¯ä¸ªç”¨æˆ·10分钟内的最大请求数"
@@ -25987,12 +26402,21 @@ 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 "MemberRole|%{role} - custom"
+msgstr "%{role} - 自定义"
+
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|must be top-level namespace"
msgstr "必须是顶级命å空间"
@@ -26211,18 +26635,9 @@ msgstr "自动åˆå¹¶(%{strategy})"
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šå¿…é¡»åˆå¹¶æ‰€æœ‰åˆå¹¶è¯·æ±‚ä¾èµ–项。"
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šåˆå¹¶è¯·æ±‚必须标记为就绪。它ä»ç„¶è¢«æ ‡è®°ä¸ºè‰ç¨¿ã€‚"
-
-msgid "Merge blocked: new changes were just added."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šåˆšåˆšæ·»åŠ äº†æ–°çš„更改。"
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr "åˆå¹¶å·²é˜»æ­¢ï¼šæµæ°´çº¿å¿…é¡»æˆåŠŸã€‚正在等待手动作业继续。"
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr "åˆå¹¶å—阻:æºåˆ†æ”¯å¿…é¡»å˜åŸºï¼ˆrebase)到目标分支。"
-
msgid "Merge commit SHA"
msgstr "åˆå¹¶æ交SHA"
@@ -26295,9 +26710,6 @@ msgstr "åˆå¹¶è¯·æ±‚用于æ出对项目的更改并与他人进行讨论"
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr "如果状æ€æ£€æŸ¥æœªæˆåŠŸæˆ–ä»åœ¨è¿è¡Œï¼Œåˆ™æ— æ³•åˆå¹¶åˆå¹¶è¯·æ±‚。"
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr "åˆå¹¶ä¸å¯ç”¨ï¼šåˆå¹¶è¯·æ±‚åœ¨æ¬¡è¦ Geo 节点中是åªè¯»çš„。"
-
msgid "Merge unverified changes"
msgstr "åˆå¹¶æœªç»éªŒè¯çš„更改"
@@ -26310,6 +26722,27 @@ 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 "æ交到æºåˆ†æ”¯"
@@ -26918,6 +27351,9 @@ msgstr[0] "里程碑"
msgid "Milestone due date"
msgstr "里程碑截止日期"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr "未找到里程碑 ID:%{milestones}"
+
msgid "Milestone lists not available with your current license"
msgstr "当å‰è®¸å¯è¯æ— æ³•ä½¿ç”¨é‡Œç¨‹ç¢‘列表"
@@ -27098,6 +27534,12 @@ msgstr "在我们预先安排更多镜åƒä¹‹å‰å¯ç”¨çš„最å°å®¹é‡ã€‚"
msgid "Minutes"
msgstr "分钟"
+msgid "Mirror all branches"
+msgstr "é•œåƒæ‰€æœ‰åˆ†æ”¯"
+
+msgid "Mirror branches"
+msgstr "é•œåƒåˆ†æ”¯"
+
msgid "Mirror direction"
msgstr "é•œåƒæ–¹å‘"
@@ -27110,6 +27552,9 @@ msgstr "é•œåƒä»“库"
msgid "Mirror settings are only available to GitLab administrators."
msgstr "é•œåƒè®¾ç½®ä»…GitLab管ç†å‘˜å¯ç”¨ã€‚"
+msgid "Mirror specific branches"
+msgstr "é•œåƒç‰¹å®šåˆ†æ”¯"
+
msgid "Mirror user"
msgstr "é•œåƒç”¨æˆ·"
@@ -27170,33 +27615,48 @@ msgstr "-"
msgid "MlExperimentTracking|Artifacts"
msgstr "产物"
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr "创建新实验"
+
msgid "MlExperimentTracking|Created at"
msgstr "创建于"
msgid "MlExperimentTracking|Details"
msgstr "详细信æ¯"
+msgid "MlExperimentTracking|Experiment"
+msgstr "实验"
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr "实验候选项"
msgid "MlExperimentTracking|Filter candidates"
msgstr "筛选候选项"
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr "机器学习实验跟踪"
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr "å称"
msgid "MlExperimentTracking|No candidates to display"
msgstr "没有è¦æ˜¾ç¤ºçš„候选项"
+msgid "MlExperimentTracking|No experiments"
+msgstr "无实验"
+
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
msgid "MlExperimentTracking|User"
msgstr "用户"
-msgid "MlExperimentsEmptyState|No Experiments to Show"
-msgstr "没有è¦æ˜¾ç¤ºçš„实验"
-
msgid "Modal updated"
msgstr "窗å£å·²æ›´æ–°"
@@ -27276,7 +27736,7 @@ msgid "More information."
msgstr "更多信æ¯ã€‚"
msgid "More options"
-msgstr ""
+msgstr "更多选项"
msgid "More than %{number_commits_distance} commits different with %{default_branch}"
msgstr "è¶…å‰ %{number_commits_distance} 个æ交与 %{default_branch} ä¸åŒ"
@@ -27402,7 +27862,7 @@ msgid "My company or team"
msgstr "我的公å¸æˆ–团队"
msgid "My saved replies (%{count})"
-msgstr ""
+msgstr "我ä¿å­˜çš„回å¤ï¼ˆ%{count} 个)"
msgid "My topic"
msgstr "我的主题"
@@ -27417,7 +27877,7 @@ msgid "Name"
msgstr "å称"
msgid "Name can contain only lowercase or uppercase letters, digits, emojis, spaces, dots, underscores, dashes, or pluses."
-msgstr ""
+msgstr "å称åªèƒ½åŒ…å«å°å†™æˆ–大写字æ¯ã€æ•°å­—ã€è¡¨æƒ…符å·ã€ç©ºæ ¼ã€ç‚¹ã€ä¸‹åˆ’线ã€ç ´æŠ˜å·æˆ–加å·ã€‚"
msgid "Name can't be blank"
msgstr "å称ä¸èƒ½ä¸ºç©º"
@@ -27429,7 +27889,7 @@ msgid "Name is already taken."
msgstr "å称已被å ç”¨ã€‚"
msgid "Name must start with a letter, digit, emoji, or underscore."
-msgstr ""
+msgstr "å称必须以字æ¯ã€æ•°å­—ã€è¡¨æƒ…符å·æˆ–下划线开头。"
msgid "Name new label"
msgstr "命å新标记"
@@ -27537,6 +27997,9 @@ msgstr "命å空间"
msgid "Namespaces to index"
msgstr "è¦ç´¢å¼•çš„命å空间"
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr "命å,主题,头åƒ"
@@ -27585,11 +28048,17 @@ msgstr "红色"
msgid "Navigation|Context navigation"
msgstr "上下文导航"
-msgid "Navigation|Recent groups"
-msgstr "最近的群组"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
-msgid "Navigation|Recent projects"
-msgstr "最近的项目"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
+msgstr ""
msgid "Navigation|Switch to..."
msgstr "切æ¢åˆ°..."
@@ -27700,9 +28169,6 @@ msgstr "新建需求"
msgid "New Snippet"
msgstr "新建代ç ç‰‡æ®µ"
-msgid "New Test Case"
-msgstr "新建测试用例"
-
msgid "New User"
msgstr "新建用户"
@@ -27790,9 +28256,6 @@ msgstr "新建å称"
msgid "New password"
msgstr "新密ç "
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr "æ–°æµæ°´çº¿ä¼šå¯¼è‡´åŒä¸€åˆ†æ”¯ä¸Šè¾ƒæ—§çš„挂起或正在è¿è¡Œçš„æµæ°´çº¿è¢«å–消。"
-
msgid "New project"
msgstr "新建项目"
@@ -28147,6 +28610,15 @@ 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 "未选择æº"
@@ -28229,14 +28701,17 @@ msgstr "导航é‡æ–°è®¾è®¡"
msgid "NorthstarNavigation|New navigation"
msgstr "新建导航"
+msgid "NorthstarNavigation|Provide feedback"
+msgstr "æä¾›å馈"
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr "切æ¢æ–°å¯¼èˆª"
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
-msgstr "并éžæ‰€æœ‰æµè§ˆå™¨éƒ½æ”¯æŒU2F设备。因此,我们需è¦æ‚¨é¦–先设置一个åŒé‡èº«ä»½éªŒè¯åº”用。这样å³ä½¿æ‚¨ä½¿ç”¨çš„æµè§ˆå™¨ä¸å—支æŒï¼Œæ‚¨ä¹Ÿå¯ä»¥ç™»å½•ã€‚"
+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. 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 "并éžæ‰€æœ‰æµè§ˆå™¨éƒ½æ”¯æŒWebAuthn。因此,我们需è¦æ‚¨é¦–先设置一个åŒé‡èº«ä»½éªŒè¯åº”用。这样å³ä½¿æ‚¨ä½¿ç”¨çš„æµè§ˆå™¨ä¸å—支æŒï¼Œæ‚¨ä¹Ÿå¯ä»¥ç™»å½•ã€‚"
+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 "尚未处ç†æ‰€æœ‰æ•°æ®ï¼Œå› æ­¤æ‰€é€‰æ—¶é—´èŒƒå›´å†…图表的ä¸ä¸€å®šå®Œå…¨å‡†ç¡®ã€‚"
@@ -28533,12 +29008,24 @@ msgstr "%{paragraph_start}Hi %{name}ï¼%{paragraph_end} %{paragraph_start}您的
msgid "Notify|%{project_link_start}Download%{project_link_end} the project export."
msgstr "%{project_link_start}下载%{project_link_end} 项目导出。"
+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|%{update_at_start} Last update at %{update_at_mid} %{last_update_at} %{update_at_end}"
msgstr "%{update_at_start} 最åŽæ›´æ–°äºŽ %{update_at_mid} %{last_update_at} %{update_at_end}"
msgid "Notify|%{updated_by_user_name} pushed new commits to merge request %{mr_link}"
msgstr "%{updated_by_user_name} 推é€æ–°æ交到åˆå¹¶è¯·æ±‚ %{mr_link}"
+msgid "Notify|%{work_items} successfully imported."
+msgstr ""
+
msgid "Notify|A new GPG key was added to your account:"
msgstr "æ–°çš„ GPG 密钥已添加到您的å¸æˆ·ï¼š"
@@ -28587,9 +29074,18 @@ msgstr "è§£æž CSV 文件时出错。请确ä¿å®ƒå…·æœ‰æ­£ç¡®çš„æ ¼å¼ï¼šä½¿ç”¨é
msgid "Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check if these lines have an issue title."
msgstr "在 %{singular_or_plural_line} 行中å‘现错误: %{error_lines}。请检查这些行是å¦åŒ…å«è®®é¢˜æ ‡é¢˜ã€‚"
+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 "指纹:%{fingerprint}"
+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 "您好,%{username}ï¼"
@@ -28617,9 +29113,6 @@ msgstr "日志å¯èƒ½åŒ…å«æ•æ„Ÿæ•°æ®ã€‚请在转å‘此电å­é‚®ä»¶ä¹‹å‰è€ƒè™‘
msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict."
msgstr "åˆå¹¶è¯·æ±‚ %{merge_request} 由于冲çªæ— æ³•åˆå¹¶ã€‚"
-msgid "Notify|Merge request %{merge_request} was %{mr_status}"
-msgstr "åˆå¹¶è¯·æ±‚ %{merge_request} 的状æ€ä¸º %{mr_status}"
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr "åˆå¹¶è¯·æ±‚ %{merge_request} 的状æ€ç”± %{updated_by} å˜æ›´ä¸º %{mr_status}"
@@ -28656,6 +29149,9 @@ msgstr "新建议题:%{project_issue_url}"
msgid "Notify|No preview for this file type"
msgstr "无法预览此类型文件"
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr "æµæ°´çº¿ #%{pipeline_id} 失败ï¼"
@@ -28665,6 +29161,9 @@ msgstr "æµæ°´çº¿ %{pipeline_link} 的触å‘者为"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
msgstr "æµæ°´çº¿å·²ä¿®å¤ï¼Œ#%{pipeline_id} 已通过ï¼"
+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 "项目 %{old_path_with_namespace} 被移动到å¦ä¸€ä¸ªä½ç½®ã€‚"
@@ -28677,6 +29176,9 @@ msgstr "项目 %{project_name} å·²æˆåŠŸå¯¼å‡ºã€‚"
msgid "Notify|Remote mirror"
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 "管ç†å‘˜ä¸ºæ‚¨åˆ›å»ºäº†ä¸€ä¸ªå¸æˆ·ã€‚现在您是公å¸åº”用程åºçš„æˆå‘˜ã€‚"
@@ -29152,6 +29654,9 @@ msgstr "按需扫æ在DevOps周期之外è¿è¡Œï¼Œå¹¶åœ¨æ‚¨çš„项目中å‘现æ¼
msgid "OnDemandScans|Only project owners and maintainers can select runner tags."
msgstr "åªæœ‰é¡¹ç›®æ‰€æœ‰è€…和维护者å¯ä»¥é€‰æ‹© Runner 标签。"
+msgid "OnDemandScans|Pre-scan verification for %{profile_name} completed with"
+msgstr ""
+
msgid "OnDemandScans|Repeats"
msgstr "é‡å¤"
@@ -29221,9 +29726,6 @@ msgstr "时区"
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr "æ— æ³•èŽ·å– runner 标签。请å°è¯•é‡æ–°åŠ è½½é¡µé¢ã€‚"
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr "验è¯é…ç½®"
@@ -29516,29 +30018,35 @@ 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 services."
-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 web hooks and services"
-msgstr "å…许æ¥è‡ª web hooks å’ŒæœåŠ¡å¯¹æœ¬åœ°ç½‘络的请求"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
+msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
-msgstr "强制执行 DNS é‡æ–°ç»‘定攻击ä¿æŠ¤"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
+msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
-msgstr "é’©å­å’ŒæœåŠ¡å¯ä»¥è®¿é—®çš„本地IP地å€å’ŒåŸŸå。"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
-msgstr "å³ä½¿ä¸å…许本地请求,系统 hook å’Œ Webhook 也å¯ä»¥è®¿é—®å¯¹è¿™äº›åŸŸåå’Œ IP 地å€çš„è¯·æ±‚ã€‚æ”¯æŒ 1:0:0:0:0:0:0:0/124 å’Œ 127.0.0.0/28 ç­‰ IP 范围。ä¸æ”¯æŒåŸŸå通é…符。è¦åˆ†éš”æ¡ç›®ï¼Œè¯·ä½¿ç”¨é€—å·ã€åˆ†å·æˆ–æ¢è¡Œç¬¦ã€‚å…许列表最多å¯åŒ…å« 1000 个æ¡ç›®ã€‚域å必须是 IDNA ç¼–ç çš„。"
+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 once and uses them to submit requests."
-msgstr "解æžIP地å€å¹¶ä½¿ç”¨å®ƒä»¬æ交请求。"
+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 "GitLabå¯èƒ½æ— æ³•æ­£å¸¸å·¥ä½œï¼Œå› ä¸ºæ‚¨æ­£åœ¨ä½¿ç”¨è¿‡æ—¶çš„æµè§ˆå™¨ã€‚"
@@ -29637,7 +30145,7 @@ msgid "Package type"
msgstr "包类型"
msgid "Package type must be Composer"
-msgstr ""
+msgstr "软件包类型必须是 Composer"
msgid "Package type must be Conan"
msgstr "包类型必须是Conan"
@@ -29960,10 +30468,10 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr "软件包由分支%{branch}上的%{link}æ交所更新,由æµæ°´çº¿%{pipeline}构建并于%{datetime}å‘布到库"
msgid "PackageRegistry|Packages and assets cleanup is ready to be executed when the next cleanup job runs."
-msgstr ""
+msgstr "已准备好在下一个清ç†ä½œä¸šè¿è¡Œæ—¶ï¼Œæ‰§è¡Œè½¯ä»¶åŒ…å’Œ assets 清ç†ã€‚"
msgid "PackageRegistry|Packages and assets will not be deleted until cleanup runs in %{nextRunAt}."
-msgstr ""
+msgstr "软件包和 assets å°†ä¸ä¼šè¢«åˆ é™¤ï¼Œç›´åˆ°åœ¨ %{nextRunAt} 中è¿è¡Œæ¸…ç†ã€‚"
msgid "PackageRegistry|Packages deleted successfully"
msgstr "æˆåŠŸåˆ é™¤è½¯ä»¶åŒ…"
@@ -30330,6 +30838,9 @@ msgstr "等待删除"
msgid "Pending comments"
msgstr "待处ç†çš„评论"
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "等待删除"
@@ -30519,9 +31030,6 @@ msgstr "您已达到最大å°è¯•æ¬¡æ•°ã€‚等待 %{interval},然åŽé‡è¯•ã€‚"
msgid "Pick a name"
msgstr "选择一个å称"
-msgid "Pin code"
-msgstr "Pinç "
-
msgid "Pipeline"
msgstr "æµæ°´çº¿"
@@ -30720,6 +31228,9 @@ msgstr "等待 CI 内容加载..."
msgid "PipelineGraph|Are you sure you want to retry %{jobName}?"
msgstr "您确定è¦é‡è¯• %{jobName} å—?"
+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 "é‡è¯•è§¦å‘器作业将创建新的下游æµæ°´çº¿ã€‚"
@@ -30945,6 +31456,9 @@ 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 "“%{project_name}â€çš„æµæ°´çº¿è®¾ç½®å·²æˆåŠŸæ›´æ–°ã€‚"
@@ -30996,9 +31510,6 @@ msgstr "å­æµæ°´çº¿ï¼ˆ%{link_start}父æµæ°´çº¿%{link_end})"
msgid "Pipelines|Clear runner caches"
msgstr "清除Runner缓存"
-msgid "Pipelines|Configuration validation currently not available."
-msgstr "é…置验è¯ç›®å‰ä¸å¯ç”¨ã€‚"
-
msgid "Pipelines|Configure pipeline"
msgstr "é…ç½®æµæ°´çº¿"
@@ -31044,6 +31555,12 @@ msgstr "Runner 是一个与 CI/CD é…åˆä½¿ç”¨ï¼Œåœ¨æµæ°´çº¿ä¸­è¿è¡Œä½œä¸šçš„å
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
msgstr "GitLab Runner 是一个与 GitLab CI/CD åˆä½œåœ¨æµæ°´çº¿ä¸­è¿è¡Œä½œä¸šçš„应用程åºã€‚现在有å¯ç”¨çš„ runner å¯ä»¥è¿è¡Œæ‚¨çš„作业。您å¯ä»¥%{settingsLinkStart}é…置您的 runner%{settingsLinkEnd} 或%{docsLinkStart}了解更多关于 runner çš„ä¿¡æ¯%{docsLinkEnd}。"
+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 "如果您ä¸ç¡®å®šï¼Œè¯·é¡¹ç›®ç»´æŠ¤è€…为您审核。"
@@ -31095,8 +31612,8 @@ msgstr "所有者"
msgid "Pipelines|Pipeline Editor"
msgstr "æµæ°´çº¿ç¼–辑器"
-msgid "Pipelines|Pipeline syntax is correct."
-msgstr "æµæ°´çº¿è¯­æ³•æ˜¯æ­£ç¡®çš„。"
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr "项目缓存é‡ç½®æˆåŠŸã€‚"
@@ -31104,6 +31621,9 @@ msgstr "项目缓存é‡ç½®æˆåŠŸã€‚"
msgid "Pipelines|Ready to set up CI/CD for your project?"
msgstr "准备好为您的项目设置 CI/CD å—?"
+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|Revoke trigger"
msgstr "撤销触å‘器"
@@ -31140,14 +31660,14 @@ 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."
-msgstr "æ­¤GitLab CIé…置无效。"
+msgid "Pipelines|This GitLab CI configuration is invalid. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is invalid:"
msgstr "æ­¤GitLab CIé…置无效:"
-msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}."
-msgstr "æ­¤GitLab CIé…置无效:%{reason}。"
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
msgstr "æ­¤GitLab CIé…置有效。"
@@ -31176,6 +31696,12 @@ 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 "使用 %{codeStart}.gitlab-ci.yml%{codeEnd} 模æ¿æ–‡ä»¶æ¥æŽ¢ç´¢CI/CD 如何工作。"
@@ -31197,6 +31723,9 @@ msgstr "查看åˆå¹¶çš„ YAML"
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 "我们将指导您完æˆä¸€ä¸ªç®€å•çš„æµæ°´çº¿è®¾ç½®ã€‚"
@@ -31206,6 +31735,9 @@ msgstr "我们会带您通过两个简å•çš„步骤部署到 iOS 。"
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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr "您的更改已æˆåŠŸæ交,现在é‡å®šå‘到新的åˆå¹¶è¯·æ±‚页é¢ã€‚"
@@ -31327,7 +31859,7 @@ msgid "Pipeline|Specify variable values to be used in this run. The values speci
msgstr "指定è¦åœ¨æ­¤æ¬¡è¿è¡Œä¸­ä½¿ç”¨çš„å˜é‡å€¼ã€‚%{linkStart}CI/CD设置%{linkEnd}中指定的值将用作默认值."
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 ""
+msgstr "指定è¦åœ¨æ­¤æ¬¡è¿è¡Œä¸­ä½¿ç”¨çš„å˜é‡å€¼ã€‚默认使用é…置文件中和 %{linkStart}CI/CD 设置%{linkEnd}中指定的å˜é‡ã€‚"
msgid "Pipeline|Stages"
msgstr "阶段"
@@ -31521,6 +32053,9 @@ msgstr "如果您想é™çº§åˆ°æ ‡å‡†ç‰ˆï¼Œè¯·åˆ é™¤æ‚¨å½“å‰çš„许å¯è¯ã€‚"
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "请å¯ç”¨å¹¶è¿ç§»åˆ°æ•£åˆ—存储以é¿å…安全问题并确ä¿æ•°æ®å®Œæ•´æ€§ã€‚ %{migrate_link}"
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr "请输入一个éžè´Ÿæ•°"
@@ -31542,6 +32077,9 @@ msgstr "请输入有效的时间间隔"
msgid "Please enter a value of 90 days or more"
msgstr "请输入 90 天或以上的值"
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr "请输入您的当å‰å¯†ç ã€‚"
@@ -31602,7 +32140,7 @@ msgstr "请选择"
msgid "Please select a Jira project"
msgstr "请选择一个Jira项目"
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr "请选择国家/地区"
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr "预览图"
msgid "Preview payload"
msgstr "预览有效数æ®"
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr "å‰ä¸€ä¸ªäº§ç‰©"
@@ -32025,150 +32566,90 @@ msgstr "%{name} 命令出错: %{message}。"
msgid "Proceed"
msgstr "继续"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr "使用您喜欢的软件包管ç†å™¨ï¼Œåœ¨æ‚¨çš„ package.json 中添加 NPM 包:"
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr "添加脚本到页é¢å¹¶å°†å®¢æˆ·ç«¯ SDK 分é…到窗å£ï¼š"
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr "使用产å“分æžæ¥åˆ†æžæ‚¨çš„产å“"
-
-msgid "Product Analytics|Back to dashboards"
-msgstr "返回仪表盘"
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr "正在创建产å“分æžå®žä¾‹..."
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr "如何é…置产å“分æžæ¥æ”¶é›†æ•°æ®çš„详细信æ¯ã€‚"
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr "è¦è®©äº§å“分æžä»ªè¡¨ç›˜å¼€å§‹å‘您显示一些数æ®ï¼Œæ‚¨éœ€è¦å°†åˆ†æžè·Ÿè¸ªä»£ç æ·»åŠ åˆ°æ‚¨çš„项目中。"
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr "识别跟踪事件的å‘件人"
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr "导入新软件包到您的 JS 代ç ï¼š"
-
-msgid "Product Analytics|Instrument your application"
-msgstr "检测您的应用程åº"
-
-msgid "Product Analytics|Instrumentation details"
-msgstr "仪器详细信æ¯"
-
-msgid "Product Analytics|SDK App ID"
-msgstr "SDK App ID"
-
-msgid "Product Analytics|SDK Host"
-msgstr "SDK Host"
-
-msgid "Product Analytics|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 "设置产å“分æžï¼Œè·Ÿè¸ªæ‚¨çš„产å“的性能。将它与您的 GitLab æ•°æ®ç›¸ç»“åˆï¼Œæ‚¨å¯ä»¥æ›´å¥½åœ°äº†è§£å¯ä»¥åœ¨å“ªäº›æ–¹é¢æ”¹è¿›æ‚¨çš„产å“和开å‘æµç¨‹ã€‚"
-
-msgid "Product Analytics|Set up product analytics"
-msgstr "设置产å“分æž"
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr "将产å“分æžæ·»åŠ ä¸º CommonJS 模å—的步骤"
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr "将产å“分æžæ·»åŠ ä¸º HTML 脚本标签的步骤"
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr "将产å“分æžæ·»åŠ ä¸º ESM 模å—的步骤"
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr "è¦å‘é€æ‰€æœ‰è·Ÿè¸ªäº‹ä»¶çš„主机"
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
-msgstr "è¿™å¯èƒ½éœ€è¦ä¸€æ®µæ—¶é—´ï¼Œæ‚¨å¯ä»¥ç¦»å¼€æ­¤é¡µé¢ï¼Œç¨åŽå†å›žæ¥æŸ¥çœ‹ã€‚"
-
-msgid "Product Analytics|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 "Product analytics"
msgstr "产å“分æž"
msgid "ProductAnalytics|Add another dimension"
msgstr "添加å¦ä¸€ä¸ªç»´åº¦"
-msgid "ProductAnalytics|Add to Dashboard"
-msgstr "添加到仪表盘"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
+msgstr ""
-msgid "ProductAnalytics|All clicks compared"
-msgstr "比较所有点击"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
+msgstr ""
-msgid "ProductAnalytics|All events compared"
-msgstr "比较所有事件"
+msgid "ProductAnalytics|All Clicks Compared"
+msgstr ""
-msgid "ProductAnalytics|All features"
-msgstr "所有功能"
+msgid "ProductAnalytics|All Events Compared"
+msgstr ""
-msgid "ProductAnalytics|All pages"
-msgstr "所有页é¢"
+msgid "ProductAnalytics|All Features"
+msgstr ""
-msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
+msgid "ProductAnalytics|All Pages"
msgstr ""
+msgid "ProductAnalytics|All Sessions Compared"
+msgstr ""
+
+msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
+msgstr "加载 %{panelTitle} é¢æ¿æ—¶å‡ºé”™ã€‚"
+
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|Browser"
-msgstr "æµè§ˆå™¨"
+msgid "ProductAnalytics|Average Per User"
+msgstr ""
-msgid "ProductAnalytics|Browser Family"
-msgstr "æµè§ˆå™¨ç³»åˆ—"
+msgid "ProductAnalytics|Average Session Duration"
+msgstr "å¹³å‡ä¼šè¯æŒç»­æ—¶é—´"
-msgid "ProductAnalytics|Cancel Edit"
-msgstr "å–消编辑"
+msgid "ProductAnalytics|Average duration in minutes"
+msgstr "å¹³å‡æŒç»­æ—¶é—´ï¼ˆåˆ†é’Ÿï¼‰"
-msgid "ProductAnalytics|Choose a chart type on the right"
-msgstr "在å³ä¾§é€‰æ‹©ä¸€ä¸ªå›¾è¡¨ç±»åž‹"
+msgid "ProductAnalytics|Back to dashboards"
+msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
-msgstr "选择一个测é‡æ¥å¯åŠ¨"
+msgid "ProductAnalytics|Cancel Edit"
+msgstr "å–消编辑"
msgid "ProductAnalytics|Click Events"
msgstr "点击事件"
-msgid "ProductAnalytics|Code"
-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 pageviews of all pages against each other"
-msgstr "比较所有页é¢çš„综åˆæµè§ˆé‡"
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
-msgstr "通过编辑项目仪表盘文件创建仪表盘。"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
+msgstr ""
-msgid "ProductAnalytics|Data"
-msgstr "æ•°æ®"
+msgid "ProductAnalytics|Creating your product analytics instance..."
+msgstr ""
-msgid "ProductAnalytics|Data Table"
-msgstr "æ•°æ®è¡¨"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
+msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr "维度"
-msgid "ProductAnalytics|Edit"
-msgstr "编辑"
-
msgid "ProductAnalytics|Event Type"
msgstr "事件类型"
@@ -32181,23 +32662,32 @@ msgstr "由 %{granularity} 分组的事件"
msgid "ProductAnalytics|Events over time"
msgstr "éšæ—¶é—´å˜åŒ–的事件"
-msgid "ProductAnalytics|Feature Usage"
-msgstr "功能使用"
+msgid "ProductAnalytics|Feature Usages"
+msgstr ""
-msgid "ProductAnalytics|Feature usage"
-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|Host"
-msgstr "主机"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr "一个用户有多少会è¯"
-msgid "ProductAnalytics|Language"
-msgstr "语言"
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
-msgid "ProductAnalytics|Line Chart"
-msgstr "折线图"
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
+msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
msgstr "测é‡æ‰€æœ‰è·Ÿè¸ªäº‹ä»¶"
@@ -32205,59 +32695,68 @@ msgstr "测é‡æ‰€æœ‰è·Ÿè¸ªäº‹ä»¶"
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr "测é‡æ‰€æœ‰æˆ–特定 Page 视图"
-msgid "ProductAnalytics|Measuring"
-msgstr "测é‡"
+msgid "ProductAnalytics|Measure all sessions"
+msgstr "计算所有会è¯"
-msgid "ProductAnalytics|New Analytics Panel Title"
-msgstr ""
-
-msgid "ProductAnalytics|OS"
-msgstr "æ“作系统"
+msgid "ProductAnalytics|Measure by unique users"
+msgstr "按独立用户计算"
-msgid "ProductAnalytics|OS Version"
-msgstr "æ“作系统版本"
+msgid "ProductAnalytics|Measuring"
+msgstr "测é‡"
msgid "ProductAnalytics|On what do you want to get insights?"
msgstr "您想获得关于什么的洞察?"
-msgid "ProductAnalytics|Page Language"
-msgstr "Page 语言"
+msgid "ProductAnalytics|Page Views"
+msgstr "Page 视图"
-msgid "ProductAnalytics|Page Path"
-msgstr "Page 路径"
+msgid "ProductAnalytics|Repeat Visit Percentage"
+msgstr ""
-msgid "ProductAnalytics|Page Title"
-msgstr "Page 标题"
+msgid "ProductAnalytics|SDK App ID"
+msgstr ""
-msgid "ProductAnalytics|Page Views"
-msgstr "Page 视图"
+msgid "ProductAnalytics|SDK Host"
+msgstr ""
-msgid "ProductAnalytics|Pages"
-msgstr "Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
-msgstr "产å“分æžä»ªè¡¨ç›˜"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
+msgstr ""
-msgid "ProductAnalytics|Referer"
-msgstr "Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
+msgstr ""
-msgid "ProductAnalytics|Resulting Data"
-msgstr "结果数æ®"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
+msgstr ""
-msgid "ProductAnalytics|Single Statistic"
-msgstr "å•ä¸€ç»Ÿè®¡"
+msgid "ProductAnalytics|The host to send all tracking events to"
+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|URL"
-msgstr "URL"
+msgid "ProductAnalytics|Unique Users"
+msgstr "独立用户数"
+
+msgid "ProductAnalytics|User Sessions"
+msgstr "用户会è¯"
msgid "ProductAnalytics|User activity"
msgstr "用户活动"
@@ -32265,12 +32764,6 @@ msgstr "用户活动"
msgid "ProductAnalytics|Users"
msgstr "用户"
-msgid "ProductAnalytics|Viewport"
-msgstr "视点"
-
-msgid "ProductAnalytics|Visualization Type"
-msgstr "å¯è§†åŒ–类型"
-
msgid "ProductAnalytics|What do you want to measure?"
msgstr "您想è¦æµ‹é‡ä»€ä¹ˆï¼Ÿ"
@@ -32436,6 +32929,12 @@ msgstr "æ–­å¼€"
msgid "Profiles|Disconnect %{provider}"
msgstr "与%{provider}断开连接"
+msgid "Profiles|Discord ID is too long (maximum is %{max_length} characters)."
+msgstr "Discord ID 太长(最多为 %{max_length} 个字符)。"
+
+msgid "Profiles|Discord ID is too short (minimum is %{min_length} characters)."
+msgstr "Discord ID 太短(最少为 %{min_length} 个字符)。"
+
msgid "Profiles|Do not show on profile"
msgstr "ä¸åœ¨ä¸ªäººèµ„料中显示"
@@ -32685,8 +33184,8 @@ msgstr "您必须转移所有æƒæˆ–删除这些群组,然åŽæ‰èƒ½åˆ é™¤æ‚¨çš„
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "您必须转移所有æƒæˆ–删除这些群组,然åŽæ‰èƒ½åˆ é™¤æ‚¨çš„å¸æˆ·ã€‚"
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
-msgstr "您的 Discord 用户 ID 长度应在 %{min} å’Œ %{max} 之间。 %{external_accounts_link_start}了解更多信æ¯ã€‚%{external_accounts_link_end}"
+msgid "Profiles|Your Discord user ID. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+msgstr "您的 Discord 用户 ID 。%{external_accounts_link_start}了解更多信æ¯ã€‚%{external_accounts_link_end}"
msgid "Profiles|Your LinkedIn profile name from linkedin.com/in/profilename"
msgstr "您的LinkedInå称,å‚è§linkedin.com/in/profilename"
@@ -32731,10 +33230,10 @@ msgid "Progress tracking"
msgstr "进展跟踪"
msgid "Progressive Web App (PWA)"
-msgstr ""
+msgstr "Progressive Web App(PWA)"
msgid "Progressive Web App (PWA) icon was successfully removed."
-msgstr ""
+msgstr "Progressive Web App(PWA)图标已æˆåŠŸåˆ é™¤ã€‚"
msgid "Project"
msgstr "项目"
@@ -32859,6 +33358,9 @@ msgstr "项目æˆå‘˜"
msgid "Project milestone"
msgstr "项目里程碑"
+msgid "Project must have default branch"
+msgstr "项目必须有默认分支"
+
msgid "Project name"
msgstr "项目å称"
@@ -32871,6 +33373,9 @@ msgstr "项目或群组"
msgid "Project order will not be saved as local storage is not available."
msgstr "由于本地存储ä¸å¯ç”¨ï¼Œå› æ­¤ä¸ä¼šä¿å­˜é¡¹ç›®é¡ºåºã€‚"
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr "项目路径"
@@ -32887,7 +33392,7 @@ msgid "Project slug"
msgstr "项目标识串"
msgid "Project that can be accessed"
-msgstr ""
+msgstr "å¯ä»¥è®¿é—®çš„项目"
msgid "Project uploads"
msgstr "项目上传"
@@ -32898,11 +33403,14 @@ 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 ""
+msgstr "具有访问æƒé™çš„项目"
msgid "Project: %{name}"
msgstr "项目: %{name}"
@@ -32994,9 +33502,21 @@ msgstr "项目ID: %{project_id}"
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 "失败"
@@ -33009,6 +33529,9 @@ msgstr "帮助我们改进此页é¢"
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr "最新æµæ°´çº¿ç»“æžœ"
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr "了解更多关于代ç è´¨é‡çš„ä¿¡æ¯"
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr "了解有关测试覆盖率的更多信æ¯"
@@ -33051,8 +33574,11 @@ 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 "ProjectSelect| or group"
-msgstr "或群组"
+msgid "ProjectQualitySummary|Violations"
+msgstr "è¿è§„"
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr "å‘现è¿è§„"
msgid "ProjectSelect|No matching results"
msgstr "没有匹é…的结果"
@@ -33066,9 +33592,6 @@ msgstr "æœç´¢é¡¹ç›®"
msgid "ProjectSelect|Select a project"
msgstr "选择一个项目"
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr "获å–项目时出错"
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr "获å–项目时出错。请é‡è¯•ã€‚"
@@ -33198,9 +33721,6 @@ msgstr "å½±å“åˆå¹¶å®Œæˆçš„æ–¹å¼å’Œæ—¶é—´çš„其他设置。"
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr "除éžæ‚¨æŒ‡å®šä¸åŒçš„分支,å¦åˆ™æ‰€æœ‰åˆå¹¶è¯·æ±‚å’Œæ交都是针对此分支进行的。"
-msgid "ProjectSettings|All threads must be resolved"
-msgstr "必须解决所有主题"
-
msgid "ProjectSettings|Allow"
msgstr "å…许"
@@ -33351,9 +33871,6 @@ msgstr "基础设施"
msgid "ProjectSettings|Internal"
msgstr "内部"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr "åˆå¹¶æµæ°´çº¿æœªé€šè¿‡çš„更改å¯èƒ½ä¼šå¼•å…¥é£Žé™©ã€‚"
-
msgid "ProjectSettings|Issues"
msgstr "议题"
@@ -33396,9 +33913,6 @@ 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 "已批准的åˆå¹¶è¯·æ±‚已排队,æµæ°´çº¿åœ¨åˆå¹¶å‰éªŒè¯æºå’Œç›®æ ‡åˆ†æ”¯çš„åˆå¹¶ç»“果。 %{link_start}什么是åˆå¹¶é˜Ÿåˆ—?%{link_end}"
-msgid "ProjectSettings|Merge requests can't be merged if the latest pipeline did not succeed or is still running."
-msgstr "如果最新æµæ°´çº¿æœªæˆåŠŸæˆ–ä»åœ¨è¿è¡Œï¼Œåˆ™æ— æ³•åˆå¹¶åˆå¹¶è¯·æ±‚。"
-
msgid "ProjectSettings|Merge suggestions"
msgstr "åˆå¹¶å»ºè®®"
@@ -33435,9 +33949,6 @@ msgstr "Pages"
msgid "ProjectSettings|Pages for project documentation."
msgstr "项目Pages的文档。"
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "æµæ°´çº¿å¿…é¡»æˆåŠŸ"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr "阻止直接链接到潜在的æ•æ„Ÿåª’体文件"
@@ -33480,11 +33991,11 @@ msgstr "推出新功能而无需使用功能标志é‡æ–°éƒ¨ç½²ã€‚"
msgid "ProjectSettings|Search for topic"
msgstr "æœç´¢ä¸»é¢˜"
-msgid "ProjectSettings|Security & Compliance"
-msgstr "安全与åˆè§„"
+msgid "ProjectSettings|Security and Compliance"
+msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
-msgstr "此项目的安全与åˆè§„"
+msgid "ProjectSettings|Security and compliance for this project."
+msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
msgstr "选择此项目的默认分支并é…置分支å称模æ¿ã€‚"
@@ -33507,9 +34018,6 @@ msgstr "显示默认的奖励表情符å·"
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr "从命令行推é€æ—¶æ˜¾ç¤ºç”¨äºŽåˆ›å»ºæˆ–查看åˆå¹¶è¯·æ±‚的链接"
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr "跳过的æµæ°´çº¿è§†ä¸ºæˆåŠŸ"
-
msgid "ProjectSettings|Snippets"
msgstr "代ç ç‰‡æ®µ"
@@ -33744,6 +34252,9 @@ msgstr "项目 (%{count})"
msgid "Projects API"
msgstr "项目 API"
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr "项目æˆåŠŸè¯»å–"
@@ -33868,7 +34379,10 @@ msgid "ProjectsNew|Migrate your data from an external source like GitHub, Bitbuc
msgstr "从外部æºï¼ˆå¦‚ GitHubã€Bitbucket 或 GitLab 的其他实例)è¿ç§»æ•°æ®ã€‚"
msgid "ProjectsNew|Must start with a lowercase or uppercase letter, digit, emoji, or underscore. Can also contain dots, pluses, dashes, or spaces."
-msgstr ""
+msgstr "必须以å°å†™æˆ–大写字æ¯ã€æ•°å­—ã€è¡¨æƒ…符å·æˆ–下划线开头。也å¯ä»¥åŒ…å«ç‚¹ã€åŠ å·ã€ç ´æŠ˜å·æˆ–空格。"
+
+msgid "ProjectsNew|New project"
+msgstr "新建项目"
msgid "ProjectsNew|No import options available"
msgstr "没有å¯ç”¨çš„导入选项"
@@ -33885,6 +34399,9 @@ msgstr "项目é…ç½®"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "项目æè¿°%{tag_start}(å¯é€‰)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr "如果您是 GitLab 新手,建议使用"
@@ -34065,9 +34582,6 @@ msgstr "è”系所有者%{link_start}%{owner_name}%{link_end}以å‡çº§è®¡åˆ’。"
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr "请与管ç†å‘˜è”系以å‡çº§è®¸å¯è¯ã€‚"
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "æ述模æ¿å…许您为项目的议题和åˆå¹¶è¯·æ±‚æ述字段定义特定上下文的模æ¿ã€‚"
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr "关闭æœåŠ¡å°ä¿ƒé”€"
@@ -34176,12 +34690,6 @@ msgstr "当议题数目很多时,很难得到一个整体情况。 通过给è®
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr "您å¯ä»¥é€šè¿‡é€‰æ‹©è§’色(维护者ã€å¼€å‘者)以åŠæŸäº›ç”¨æˆ·æ¥é™åˆ¶å¯¹å—ä¿æŠ¤åˆ†æ”¯çš„访问。"
-msgid "Promotions|description templates"
-msgstr "æ述模æ¿"
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr "帮助您的贡献者有效沟通ï¼"
-
msgid "Prompt users to upload SSH keys"
msgstr "æ示用户上传SSH密钥"
@@ -34225,7 +34733,7 @@ msgid "ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} suc
msgstr "支æŒä¾‹å¦‚%{code_tag_start}*-stable%{code_tag_end}或%{code_tag_start}production/*%{code_tag_end} çš„%{wildcards_link_start}通é…符%{wildcards_link_end}。"
msgid "ProtectedBranch|After you configure a protected branch, merge request approval, or status check, it appears here."
-msgstr ""
+msgstr "当您é…置一个å—ä¿æŠ¤çš„分支ã€åˆå¹¶è¯·æ±‚批准或状æ€æ£€æŸ¥åŽï¼Œå®ƒä¼šå‡ºçŽ°åœ¨è¿™é‡Œã€‚"
msgid "ProtectedBranch|Allow all users with push access to %{tag_start}force push%{tag_end}."
msgstr "å…许所有具有推é€è®¿é—®æƒé™çš„用户%{tag_start}强制推é€%{tag_end}。"
@@ -34353,7 +34861,21 @@ msgstr "您åªèƒ½æ·»åŠ å…±äº«æ­¤é¡¹ç›®çš„群组。%{learn_more_link}"
msgid "ProtectedBranch|default"
msgstr "默认"
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
+msgstr "添加部署规则"
+
+msgid "ProtectedEnvironments|Allowed to approve"
msgstr ""
msgid "ProtectedEnvironments|Allowed to deploy"
@@ -34365,27 +34887,48 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete deployer rule"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+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|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr "统一批准规则已从设置 UI 中删除"
+
msgid "ProtectedEnvironments|Users"
msgstr "用户"
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} 将对开å‘人员å¯å†™ã€‚确定继续å—?"
@@ -34395,6 +34938,9 @@ msgstr "指定了以下部署级别的所有环境å‡å—父组ä¿æŠ¤ã€‚%{link_st
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "å…许部署"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr "å…许部署到 %{project}/%{environment}"
@@ -34576,7 +35122,7 @@ msgid "Purchase|A full name in your profile is required to make a purchase. Chec
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 ""
+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 ""
@@ -34851,24 +35397,15 @@ msgstr "准备åˆå¹¶ï¼"
msgid "Reauthenticating with SAML provider."
msgstr "正在与 SAML æ供商é‡æ–°éªŒè¯ã€‚"
-msgid "Rebase"
-msgstr "å˜åŸº"
-
msgid "Rebase completed"
msgstr "å˜åŸºå·²å®Œæˆ"
-msgid "Rebase in progress"
-msgstr "Rebase正在进行中"
-
msgid "Rebase source branch"
msgstr "Rebaseæºåˆ†æ”¯"
msgid "Rebase source branch on the target branch."
msgstr "在目标分支上Rebaseæºåˆ†æ”¯ã€‚"
-msgid "Rebase without pipeline"
-msgstr "没有æµæ°´çº¿çš„å˜åŸº"
-
msgid "Recaptcha verified?"
msgstr "é‡æ–°éªŒè¯ï¼Ÿ"
@@ -34944,6 +35481,9 @@ msgstr "优化您的æœç´¢æ¡ä»¶ï¼ˆå°½å¯èƒ½é€‰æ‹© %{strong_open}群组%{strong_
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] "%d 秒åŽåˆ·æ–°ä»¥æ˜¾ç¤ºæ›´æ–°çŠ¶æ€..."
@@ -34978,14 +35518,14 @@ msgstr "注册"
msgid "Register / Sign In"
msgstr "注册/登录"
-msgid "Register Two-Factor Authenticator"
-msgstr "注册åŒé‡è®¤è¯"
+msgid "Register a WebAuthn device"
+msgstr "注册 WebAuthn 设备"
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "注册通用åŒé‡è®¤è¯è®¾å¤‡(U2F)"
+msgid "Register a one-time password authenticator"
+msgstr "注册一个一次性密ç éªŒè¯å™¨"
-msgid "Register WebAuthn Device"
-msgstr "注册WebAuthn设备"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
+msgstr ""
msgid "Register device"
msgstr "注册设备"
@@ -35077,6 +35617,9 @@ msgstr "已拒ç»(关闭)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr "å…³è”到 %{issuable_type} %{add_related_issue_link}"
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr "相关的功能标志"
@@ -35304,7 +35847,7 @@ msgid "Remove header logo"
msgstr "删除header logo"
msgid "Remove icon"
-msgstr ""
+msgstr "移除图标"
msgid "Remove iteration"
msgstr "移除迭代"
@@ -36005,15 +36548,21 @@ msgstr "需求%{reference}å·²é‡æ–°æ‰“å¼€"
msgid "Requirement %{reference} has been updated"
msgstr "需求%{reference}已更新"
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr "需求标题ä¸èƒ½è¶…过%{limit}个字符。"
-
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 "旧版需求 ID:%{legacyId}"
+
+msgid "Requirement|Legacy requirement IDs are being deprecated. Update your links to reference this item's new ID %{id}. %{linkStart}Learn more%{linkEnd}."
+msgstr "旧版需求 ID 已弃用。更新您的链接,引用新 ID %{id}。%{linkStart}了解更多%{linkEnd}。"
+
+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 "需求已å˜ä¸ºå·¥ä½œé¡¹ï¼Œæ—§ç‰ˆéœ€æ±‚ ID 已被弃用。更新您的链接,引用新 ID %{id}。%{linkStart}了解更多%{linkEnd}。"
+
msgid "Requires %d approval from eligible users."
msgid_plural "Requires %d approvals from eligible users."
msgstr[0] "需è¦%d个符åˆæ¡ä»¶çš„用户的批准。"
@@ -36190,9 +36739,6 @@ msgstr "已达到结果é™åˆ¶"
msgid "Resume"
msgstr "æ¢å¤"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr "检索åˆè§„性报告失败。请刷新页é¢å¹¶é‡è¯•ã€‚"
-
msgid "Retry"
msgstr "é‡è¯•"
@@ -36358,10 +36904,7 @@ msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabl
msgstr "è¿è¡Œä¾‹è¡Œç»´æŠ¤ä»»åŠ¡æ¥è‡ªåŠ¨ä¼˜åŒ– Git 仓库。ç¦ç”¨æ­¤é€‰é¡¹å°†å¯¼è‡´æ€§èƒ½éšç€æ—¶é—´çš„推移而下é™ã€‚"
msgid "Run job"
-msgstr ""
-
-msgid "Run manual job again"
-msgstr "å†æ¬¡è¿è¡Œæ‰‹åŠ¨ä½œä¸š"
+msgstr "è¿è¡Œä½œä¸š"
msgid "Run manual or delayed jobs"
msgstr "è¿è¡Œæ‰‹åŠ¨æˆ–延迟的作业"
@@ -36431,7 +36974,10 @@ msgid "Runners|Active"
msgstr "å¯ç”¨"
msgid "Runners|Add notes such as the runner owner or what it should be used for."
-msgstr ""
+msgstr "添加备注,如 Runner 的所有者或它应该用于的目的。"
+
+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 "为 Runner è¿›ç¨‹çš„ä»»åŠ¡ç±»åž‹æ·»åŠ æ ‡ç­¾ï¼Œç¡®ä¿ Runner åªè¿è¡Œæ‚¨æƒ³è¦çš„任务。%{helpLinkStart}了解更多。%{helpLinkEnd}"
msgid "Runners|Administrator"
msgstr "管ç†å‘˜"
@@ -36496,6 +37042,9 @@ msgstr "容é‡ä¸º 1,通过自动扩展组é‡æ–°ç”Ÿæˆå¯ç”¨æš– HA。容é‡ä¸º
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 "选择您首选的 GitLab Runner"
@@ -36503,7 +37052,7 @@ msgid "Runners|Clear selection"
msgstr "清除选择"
msgid "Runners|Cloud templates"
-msgstr ""
+msgstr "云模æ¿"
msgid "Runners|Command to register runner"
msgstr "注册runner的命令"
@@ -36512,6 +37061,9 @@ 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"
@@ -36569,9 +37121,15 @@ msgstr "å¯ç”¨é™ˆæ—§çš„ runner 清ç†"
msgid "Runners|Enable stale runner cleanup?"
msgstr "å¯ç”¨é™ˆæ—§çš„ runner 清ç†ï¼Ÿ"
+msgid "Runners|Enter the number of seconds."
+msgstr "输入秒数。"
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr "输入秒数。此超时时间优先级高于为项目设定的较低超时时间。"
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr "执行器"
@@ -36584,6 +37142,12 @@ msgstr "过滤项目"
msgid "Runners|Get started with runners"
msgstr "Runner 入门"
+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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr "群组"
@@ -36602,6 +37166,9 @@ msgstr "空闲"
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr "如果两个设置都被ç¦ç”¨ï¼Œåˆ™æ— æ³•æ³¨å†Œæ–°çš„ runner。"
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr "安装Runner"
@@ -36629,6 +37196,12 @@ msgstr "é”定到此项目"
msgid "Runners|Maintenance note"
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 "Runner 在结æŸå‰å¯ä»¥è¿è¡Œçš„最大时间。 如果一个项目的任务超时时间较短,则使用实例 Runner 的任务超时时间。"
+
msgid "Runners|Maximum job timeout"
msgstr "最大作业超时"
@@ -36638,6 +37211,9 @@ msgstr "%{type}çš„æˆå‘˜å¯ä»¥æ³¨å†ŒRunner"
msgid "Runners|Minor version upgrades are available."
msgstr "次è¦ç‰ˆæœ¬å‡çº§çŽ°åœ¨å¯ç”¨ã€‚"
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr "多个标签必须用逗å·åˆ†éš”。例如,%{example}。"
+
msgid "Runners|Name"
msgstr "å称"
@@ -36650,6 +37226,9 @@ msgstr "从未连接过:"
msgid "Runners|Never expires"
msgstr "æ°¸ä¸è¿‡æœŸ"
+msgid "Runners|New"
+msgstr "新建"
+
msgid "Runners|New group runners can be registered"
msgstr "å¯ä»¥æ³¨å†Œæ–°çš„群组 runners"
@@ -36687,9 +37266,12 @@ msgid "Runners|Online:"
msgstr "在线:"
msgid "Runners|Only administrators can view this."
-msgstr ""
+msgstr "åªæœ‰ç®¡ç†å‘˜å¯ä»¥æŸ¥çœ‹ã€‚"
msgid "Runners|Operating systems"
+msgstr "æ“作系统"
+
+msgid "Runners|Optional. Step 3"
msgstr ""
msgid "Runners|Owner"
@@ -36723,6 +37305,12 @@ msgstr "å—ä¿æŠ¤"
msgid "Runners|Recommended"
msgstr "推è"
+msgid "Runners|Register"
+msgstr "注册"
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr "注册一个群组runner"
@@ -36738,6 +37326,9 @@ msgstr "注册一个实例runner"
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 "注册尽å¯èƒ½å¤šçš„ runner。您å¯ä»¥ç”¨å•ç‹¬çš„用户,或者在ä¸åŒçš„æœåŠ¡å™¨æˆ–者本地计算机上注册 runner。"
+msgid "Runners|Register runner"
+msgstr ""
+
msgid "Runners|Registration token"
msgstr "注册令牌"
@@ -36762,6 +37353,9 @@ msgstr "Runner #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
msgstr "Runner %{name} 已删除"
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr "Runner %{runnerName} 删除失败"
+
msgid "Runners|Runner Registration"
msgstr "Runner 注册"
@@ -36777,6 +37371,12 @@ msgstr "Runner 身份验è¯ä»¤ç‰Œè¿‡æœŸ"
msgid "Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired."
msgstr "Runner 身份验è¯ä»¤ç‰Œå°†æ ¹æ®è®¾ç½®çš„时间间隔过期。一旦过期,它们将自动轮æ¢ã€‚"
+msgid "Runners|Runner created."
+msgstr ""
+
+msgid "Runners|Runner description"
+msgstr "Runner æè¿°"
+
msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
msgstr "在最近 %{elapsedTime} 内,Runner 连接过 GitLab"
@@ -36849,9 +37449,15 @@ 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 "选择è¦åˆ†é…给此 runner 的项目"
@@ -36885,6 +37491,12 @@ msgstr "过期:"
msgid "Runners|Status"
msgstr "状æ€"
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr "åœæ­¢ Runner 接收新的作业。"
@@ -36894,6 +37506,9 @@ 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 "标签控制 runner å¯ä»¥å¤„ç†çš„作业类型。通过为 runner 打标签,您å¯ä»¥ç¡®ä¿å…±äº« runners åªå¤„ç†ä»–们准备è¿è¡Œçš„工作。"
+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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr "注册了 runner 的项目ã€ç¾¤ç»„或实例。实例 runners 始终归管ç†å‘˜æ‰€æœ‰ã€‚"
@@ -36910,6 +37525,9 @@ msgstr[0] "此群组目å‰æœ‰ %d 个陈旧的 runner。"
msgid "Runners|This group currently has no stale runners."
msgstr "此群组当å‰æ²¡æœ‰é™ˆæ—§çš„ runner。"
+msgid "Runners|This may not be needed if you manage your runner as a %{linkStart}system or user service%{linkEnd}."
+msgstr ""
+
msgid "Runners|This runner has not run any jobs."
msgstr "æ­¤ runner 没有è¿è¡Œä»»ä½•ä½œä¸šã€‚"
@@ -36958,6 +37576,9 @@ msgstr "推èå‡çº§"
msgid "Runners|Use Group runners when you want all projects in a group to have access to a set of runners."
msgstr "当您希望群组中的所有项目都å¯ä»¥è®¿é—®ä¸€ç»„Runner时,请使用群组Runner。"
+msgid "Runners|Use the runner for jobs without tags in addition to tagged jobs."
+msgstr "除了标记的任务外,使用 Runner æ¥æ‰§è¡Œæ²¡æœ‰æ ‡ç­¾çš„任务。"
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr "除了带标签的作业外,还å¯ä»¥å°†Runner用于没有标签的作业。"
@@ -37012,15 +37633,6 @@ msgstr "项目"
msgid "Runners|shared"
msgstr "共享"
-msgid "Runner|New"
-msgstr "新建"
-
-msgid "Runner|Owner"
-msgstr "所有者"
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr "Runner %{runnerName} 删除失败"
-
msgid "Running"
msgstr "è¿è¡Œä¸­"
@@ -37042,6 +37654,9 @@ msgstr "SAMLå‘现令牌"
msgid "SAML for %{group_name}"
msgstr "%{group_name} çš„ SAML"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr "SAML å•ç‚¹ç™»å½•"
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "您的组织的 SSO 已连接到您的 GitLab å¸æˆ·"
-msgid "SAST Configuration"
-msgstr "SASTé…ç½®"
-
msgid "SCIM|SCIM Token"
msgstr "SCIM 令牌"
@@ -37181,10 +37793,10 @@ msgid "Save pipeline schedule"
msgstr "ä¿å­˜æµæ°´çº¿è®¡åˆ’"
msgid "Saved Replies"
-msgstr ""
+msgstr "å·²ä¿å­˜çš„回å¤"
msgid "Saved replies can be used when creating comments inside issues, merge requests, and epics."
-msgstr ""
+msgstr "在创建议题ã€åˆå¹¶è¯·æ±‚å’Œå²è¯—æ—¶å¯ä»¥ä½¿ç”¨å·²ä¿å­˜çš„回å¤ã€‚"
msgid "Saving"
msgstr "ä¿å­˜ä¸­"
@@ -37198,17 +37810,20 @@ msgstr "%{period}%{days} 在 %{time}"
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr "%{scopes} %{branches} %{agents} %{namespaces} çš„ %{rules} æ“作"
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
-msgstr "%{thenLabelStart}然åŽ%{thenLabelEnd} éœ€è¦ %{scan} 扫ææ‰èƒ½ä½¿ç”¨ç«™ç‚¹é…置文件 %{siteProfile} 和带有标签 %{tags} 的扫æ器é…置文件 %{scannerProfile} æ¥è¿è¡Œ"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
+msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
-msgstr "%{thenLabelStart}然åŽ%{thenLabelEnd} éœ€è¦ %{scan} 扫ææ‰èƒ½è¿è¡Œï¼Œå¸¦æœ‰æ ‡ç­¾ %{tags} "
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
+msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr "æµæ°´çº¿è¿è¡Œä¸­"
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
-msgstr "Ex,tag-name-1,tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
+msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
msgstr "如果该字段为空,将自动选择 runner"
@@ -37249,9 +37864,15 @@ msgstr "代ç†"
msgid "ScanExecutionPolicy|branch"
msgstr "分支"
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr "在命å空间中"
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr "%{count} 个许å¯è¯"
@@ -37689,24 +38310,27 @@ msgstr "UUID"
msgid "Security"
msgstr "安全"
-msgid "Security & Compliance"
-msgstr "安全与åˆè§„"
-
-msgid "Security Configuration"
-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 navigation"
-msgstr "安全导航"
-
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr "安全报告已过时。请使用目标分支(%{targetBranchName})中的最新更改æ¥æ›´æ–°æ‚¨çš„分支。"
@@ -37833,8 +38457,8 @@ msgstr "应用程åºçŽ¯å¢ƒçš„è¿è¡Œæ—¶å®‰å…¨æŒ‡æ ‡"
msgid "SecurityConfiguration|SAST Analyzers"
msgstr "SAST分æžå·¥å…·"
-msgid "SecurityConfiguration|SAST Configuration"
-msgstr "SASTé…ç½®"
+msgid "SecurityConfiguration|SAST configuration"
+msgstr ""
msgid "SecurityConfiguration|Secure your project"
msgstr "ä¿æŠ¤æ‚¨çš„项目"
@@ -37879,7 +38503,7 @@ msgid "SecurityOrchestration|%{branches} branch"
msgstr "%{branches} 分支"
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
-msgstr ""
+msgstr "%{licenses} 和 %{lastLicense}"
msgid "SecurityOrchestration|%{scannerStart}%{scanner}%{scannerEnd}"
msgstr "%{scannerStart}%{scanner}%{scannerEnd}"
@@ -37936,7 +38560,7 @@ msgid "SecurityOrchestration|An error occurred while fetching the scan result po
msgstr "获å–扫æ结果策略时出错。"
msgid "SecurityOrchestration|Any security scanner finds"
-msgstr ""
+msgstr "任何安全扫æ器å‘现"
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr "确定è¦åˆ é™¤æ­¤ç­–ç•¥å—?此æ“作无法撤消。"
@@ -37947,6 +38571,9 @@ msgstr "选择项目"
msgid "SecurityOrchestration|Choose approver type"
msgstr "选择核准人类型"
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr "创建更强大的æ¼æ´žè§„则并将其应用于您的所有项目。"
@@ -38052,9 +38679,18 @@ msgstr "未定义任何æ“作 - ç­–ç•¥ä¸ä¼šè¿è¡Œã€‚"
msgid "SecurityOrchestration|No description"
msgstr "æ— æè¿°"
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr "未定义规则 - 策略无法è¿è¡Œã€‚"
+msgid "SecurityOrchestration|No tags available"
+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 "未å¯ç”¨"
@@ -38145,6 +38781,9 @@ msgstr "扫æ在å为 %{agents} %{cadence} 的代ç†ä¸Šæ‰§è¡Œ"
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr "在%{branches}上扫ææ¯ä¸ªæµæ°´çº¿"
+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 "安全批准"
@@ -38166,6 +38805,9 @@ msgstr "选择群组"
msgid "SecurityOrchestration|Select policy"
msgstr "选择策略"
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr "选择扫æ类型"
@@ -38175,6 +38817,9 @@ msgstr "选择安全项目"
msgid "SecurityOrchestration|Select users"
msgstr "选择用户"
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr "出现错误,无法获å–ç­–ç•¥"
@@ -38241,8 +38886,8 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
-msgstr "使用扫æ执行策略æ¥åˆ›å»ºè§„则,在特定的时间对特定的分支强制进行安全扫æ。支æŒçš„类型有 SASTã€DASTã€Secret 检测ã€å®¹å™¨æ‰«æå’Œä¾èµ–扫æ。"
+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 "使用扫æ结果策略创建规则,在åˆå¹¶åˆå¹¶è¯·æ±‚之å‰æ£€æŸ¥å®‰å…¨æ¼æ´žå’Œè®¸å¯è¯åˆè§„。"
@@ -38319,6 +38964,9 @@ msgstr "%{firstProject},%{secondProject},åŠ%{rest}"
msgid "SecurityReports|Activity"
msgstr "活动"
+msgid "SecurityReports|Add comment and 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 "添加或删除安全区内的项目。 此列表中项目的扫æ结果将显示在安全仪表盘和æ¼æ´žæŠ¥å‘Šä¸­ã€‚"
@@ -38590,7 +39238,7 @@ msgid "SecurityReports|There was an error deleting the comment."
msgstr "删除评论时出错。"
msgid "SecurityReports|There was an error dismissing the finding. Please try again."
-msgstr ""
+msgstr "关闭查找时出错,请é‡è¯•ã€‚"
msgid "SecurityReports|There was an error dismissing the vulnerabilities."
msgstr "忽略æ¼æ´žæ—¶å‡ºé”™ã€‚"
@@ -38796,6 +39444,9 @@ msgstr "选择标记"
msgid "Select labels"
msgstr "选择标记"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "选择åˆå¹¶æ—¶é—´"
@@ -38898,6 +39549,9 @@ msgstr "自我监控项目已æˆåŠŸåˆ é™¤"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "自我监控项目未被删除。请检查日志中是å¦æœ‰ä»»ä½•é”™è¯¯æ¶ˆæ¯"
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr "å¯ç”¨æˆ–ç¦ç”¨å®žä¾‹è‡ªç›‘控。"
@@ -38910,6 +39564,9 @@ msgstr "åœç”¨è‡ªç›‘控?"
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr "åœç”¨è‡ªç›‘控将会删除自监控项目。您确定è¦åœç”¨è‡ªç›‘控并删除项目å—?"
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr "自监控"
@@ -38922,6 +39579,9 @@ msgstr "自监控项目已æˆåŠŸåˆ›å»ºã€‚"
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr "自监控项目已æˆåŠŸåˆ é™¤ã€‚"
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr "å‘é€"
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr "å¯ç”¨æœåŠ¡å°"
@@ -39073,7 +39739,7 @@ msgid "Set a default description template to be used for new issues. %{link_star
msgstr "设置用于新议题的默认æ述模æ¿ã€‚ %{link_start}什么是æ述模æ¿ï¼Ÿ%{link_end}"
msgid "Set a group, access level or users who are required to deploy."
-msgstr ""
+msgstr "设置群组ã€è®¿é—®çº§åˆ«æˆ–è¦æ±‚执行部署的用户。"
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "为账å·åˆ›å»ºä¸€ä¸ªç”¨äºŽæŽ¨é€æˆ–拉å–çš„ %{protocol} 密ç ã€‚"
@@ -39159,6 +39825,9 @@ msgstr "设置 Web 终端的最长会è¯æ—¶é—´ã€‚"
msgid "Set the milestone to %{milestone_reference}."
msgstr "将里程碑设置为%{milestone_reference}。"
+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 "设置通过 API 按 ID 获å–用户的æ¯ç”¨æˆ·é€ŸçŽ‡é™åˆ¶ã€‚"
@@ -39186,8 +39855,8 @@ msgstr "设置Jira集æˆ"
msgid "Set up a %{type} runner for a project"
msgstr "为项目设置一个 %{type} 的 Runner"
-msgid "Set up a hardware device as a second factor to sign in."
-msgstr "设置一个硬件设备作为登录的第二个因素。"
+msgid "Set up a hardware device to enable two-factor authentication (2FA)."
+msgstr "设置硬件设备,å¯ç”¨åŒé‡èº«ä»½éªŒè¯ (2FA)。"
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "æ ¹æ®%{docsLinkStart}文档%{icon}%{docsLinkEnd}设置断言/属性/声明(email,first_name,last_name)和NameID"
@@ -39368,7 +40037,7 @@ msgid "Shimo|You've enabled the Shimo Workspace integration. You can view your w
msgstr "您已å¯ç”¨çŸ³å¢¨å·¥ä½œåŒºé›†æˆã€‚您å¯ä»¥ç›´æŽ¥åœ¨çŸ³å¢¨æŸ¥çœ‹æ‚¨çš„wiki。"
msgid "Short name"
-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 "如果您丢失手机或访问一次性密ç ï¼Œæ¯ä¸ªæ¢å¤ç éƒ½å¯ä»¥ä½¿ç”¨ä¸€æ¬¡ï¼Œä»¥é‡æ–°èŽ·å¾—您的å¸æˆ·è®¿é—®æƒé™ã€‚请将它们ä¿å­˜åœ¨å®‰å…¨çš„地方,å¦åˆ™æ‚¨%{boldStart}å°†%{boldEnd}无法访问您的å¸æˆ·ã€‚"
@@ -39436,6 +40105,9 @@ msgstr "显示文件内容"
msgid "Show filters"
msgstr "显示过滤器"
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr "显示群组里程碑"
@@ -39599,9 +40271,6 @@ msgstr "Sidekiq作业大å°é™åˆ¶"
msgid "Sign in"
msgstr "登录"
-msgid "Sign in / Register"
-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 "以具有匹é…电å­é‚®ä»¶åœ°å€çš„用户身份登录,将电å­é‚®ä»¶æ·»åŠ åˆ°æ­¤è´¦å·ï¼Œæˆ–使用匹é…的电å­é‚®ä»¶æ³¨å†Œæ–°è´¦å·ã€‚"
@@ -39755,15 +40424,33 @@ msgstr "Slack集æˆå…许您通过èŠå¤©çª—å£ä¸­çš„指令与GitLab交互。"
msgid "Slack logo"
msgstr "Slack logo"
+msgid "Slack notifications integration is deprecated"
+msgstr "Slack 通知集æˆå·²è¢«å¼ƒç”¨"
+
+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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr "您确定è¦ä»Ž GitLab for Slack 应用中删除此项目å—?"
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr "客户端 ID"
msgid "SlackIntegration|Client secret"
msgstr "客户端 secret"
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr "GitLab for Slack"
@@ -39773,6 +40460,9 @@ msgstr "GitLab for Slack å·²æˆåŠŸå®‰è£…。"
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr "安装 GitLab for Slack 应用"
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr "项目别å"
@@ -39782,6 +40472,9 @@ msgstr "é‡æ–°å®‰è£… GitLab for Slack 应用"
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 "设置此集æˆåŽï¼Œè¯·è¾“入以下内容,查看 Slack 中å¯ç”¨å‘½ä»¤çš„列表:"
@@ -39815,9 +40508,15 @@ msgstr "验è¯ä»¤ç‰Œ"
msgid "SlackIntegration|You can now close this window and go to your Slack workspace."
msgstr "您现在å¯ä»¥å…³é—­æ­¤çª—å£å¹¶è½¬åˆ°æ‚¨çš„ Slack 工作区。"
+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 "%{linkStart}更新或更改æƒé™%{linkEnd}时,您å¯èƒ½éœ€è¦é‡æ–°å®‰è£… GitLab for Slack 应用。"
+msgid "SlackIntegration|cannot have more than %{limit} channels"
+msgstr "ä¸èƒ½æœ‰è¶…过 %{limit} 个频é“"
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr "您确定è¦æ›´æ”¹é¡¹ç›®å—?"
@@ -39999,7 +40698,10 @@ msgid "Something went wrong trying to load issue contacts."
msgstr "å°è¯•åŠ è½½è®®é¢˜è”系人时出错。"
msgid "Something went wrong when deleting a comment. Please try again"
-msgstr ""
+msgstr "删除评论时出错。请é‡è¯•ã€‚"
+
+msgid "Something went wrong when deleting a comment. Please try again."
+msgstr "删除评论时出错。请é‡è¯•ã€‚"
msgid "Something went wrong when reordering designs. Please try again"
msgstr "é‡æ–°æŽ’åºè®¾è®¡æ—¶å‡ºäº†ç‚¹é—®é¢˜ã€‚请å†è¯•ä¸€æ¬¡"
@@ -40007,6 +40709,9 @@ msgstr "é‡æ–°æŽ’åºè®¾è®¡æ—¶å‡ºäº†ç‚¹é—®é¢˜ã€‚请å†è¯•ä¸€æ¬¡"
msgid "Something went wrong when sending the incident link to Slack."
msgstr "将事件链接å‘é€åˆ° Slack 时出错。"
+msgid "Something went wrong when updating a comment. Please try again"
+msgstr "更新评论时出错。请é‡è¯•"
+
msgid "Something went wrong while adding timeline event."
msgstr "添加时间线事件时出错。"
@@ -40418,9 +41123,6 @@ msgstr "\"%{prop}()\"方法å称冲çªã€‚"
msgid "SourceEditor|No extension for unuse has been specified."
msgstr "未指定未使用的扩展å。"
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr "éœ€è¦ Source Editor 实例æ¥è®¾ç½®æ‰©å±•ã€‚"
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr "`definition` 属性应该在扩展上。"
@@ -40484,6 +41186,9 @@ msgstr "垃圾信æ¯åŠé˜²æœºå™¨äººä¿æŠ¤"
msgid "Spam log successfully submitted as ham."
msgstr "垃圾信æ¯æ—¥å¿—å·²æˆåŠŸæ”¹ä¸ºæœ‰æ•ˆä¿¡æ¯æ交。"
+msgid "Specific branches"
+msgstr "特定分支"
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr "无法使用指定的URL:“%{reason}â€"
@@ -40733,6 +41438,9 @@ msgstr "移除状æ€æ£€æŸ¥ï¼Ÿ"
msgid "StatusCheck|Service name"
msgstr "æœåŠ¡å称"
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr "状æ€æ£€æŸ¥"
@@ -41378,17 +42086,23 @@ msgstr "准备好开始了å—? GitLab 方案éžå¸¸é€‚åˆæ‰©å±•ç»„织和多团é
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|Sync subscription request."
-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 "激活ç æ— æ•ˆã€‚请确ä¿ä»Žå®¢æˆ·ç«¯é—¨æˆ·æˆ–确认电å­é‚®ä»¶å¤åˆ¶å®ƒã€‚ 了解更多关于 %{linkStart}激活您的订阅%{linkEnd}。"
@@ -41396,8 +42110,8 @@ msgstr "激活ç æ— æ•ˆã€‚请确ä¿ä»Žå®¢æˆ·ç«¯é—¨æˆ·æˆ–确认电å­é‚®ä»¶å¤åˆ¶
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr "激活ç åº”该是一个24个字符的字æ¯æ•°å­—字符串"
-msgid "SuperSonics|There is a connectivity issue."
-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 "这是自许å¯è¯å¯åŠ¨ä»¥æ¥ç”¨æˆ·æ•°çš„最高峰。"
@@ -41424,9 +42138,6 @@ 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 "您å¯ä»¥%{purchaseSubscriptionLinkStart}购买新订阅%{purchaseSubscriptionLinkEnd}并é‡è¯•ã€‚如果您需è¦æ›´å¤šå¸®åŠ©ï¼Œè¯·%{supportLinkStart}è”系技术支æŒ%{supportLinkEnd}。"
-msgid "SuperSonics|You can no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr "您无法å†å°†è®¢é˜…详细信æ¯ä¸Ž GitLab åŒæ­¥ã€‚ %{connectivityHelpLinkStart}通过对激活ç è¿›è¡Œæ•…障排除%{connectivityHelpLinkEnd},获å–有关最常è§è¿žæŽ¥é—®é¢˜çš„帮助。"
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr "您å¯ä»¥å¼€å§‹å…费试用 GitLab 旗舰版,无需任何承诺或付款信æ¯ã€‚"
@@ -41469,9 +42180,6 @@ msgstr "您的订阅"
msgid "SuperSonics|Your subscription cannot be located"
msgstr "无法找到您的订阅"
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr "您的订阅信æ¯å°†å¾ˆå¿«åŒæ­¥"
-
msgid "SuperSonics|Your subscription is expired"
msgstr "您的订阅已过期"
@@ -41622,9 +42330,27 @@ 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 "标签推é€"
@@ -42029,12 +42755,12 @@ msgstr "您的项目没有任何Terraform state文件"
msgid "Test"
msgstr "测试"
-msgid "Test Cases"
-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] "该æµæ°´çº¿çš„æµ‹è¯•è¦†ç›–çŽ‡å€¼æ˜¯é€šè¿‡å¹³å‡ %d 个作业的结果覆盖率值æ¥è®¡ç®—的。"
@@ -42052,9 +42778,6 @@ msgstr "移动测试用例"
msgid "TestCases|Moving test case"
msgstr "移动测试用例"
-msgid "TestCases|New Test Case"
-msgstr "新建测试用例"
-
msgid "TestCases|New test case"
msgstr "新建测试用例"
@@ -42181,6 +42904,9 @@ msgstr "文本(å¯é€‰ï¼‰"
msgid "Text added to the body of all email messages. %{character_limit} character limit"
msgstr "添加到所有电å­é‚®ä»¶æ­£æ–‡çš„文本。 %{character_limit} 字符é™åˆ¶"
+msgid "Text added to the body of user deactivation email messages. 1000 character limit."
+msgstr "添加到用户åœç”¨é€šçŸ¥ç”µå­é‚®ä»¶æ­£æ–‡çš„文本。é™åˆ¶ 1000 个字符。"
+
msgid "Text style"
msgstr "文本样å¼"
@@ -42239,6 +42965,9 @@ msgstr "议题跟踪用于管ç†éœ€æ±‚改进或者解决的问题。请注册或
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr "PrometheusæœåŠ¡å™¨ä»¥â€œé”™è¯¯è¯·æ±‚â€å“应。请检查您的查询是å¦æ­£ç¡®ï¼Œå¹¶ä¸”当å‰çš„Prometheus版本支æŒã€‚ %{documentationLink}"
+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 "Slack 通知集æˆå·²å¼ƒç”¨ï¼Œå°†åœ¨æœªæ¥ç‰ˆæœ¬ä¸­åˆ é™¤ã€‚è¦ç»§ç»­æŽ¥æ”¶æ¥è‡ª Slack 的通知,请改用 GitLab for Slack 应用程åºã€‚ %{learn_more_link_start}了解更多%{link_end}。"
+
msgid "The Snowplow cookie domain."
msgstr "Snowplow cookie 域å。"
@@ -42281,9 +43010,6 @@ 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 "完整的 DevOps å¹³å°ã€‚一个具有无é™å¯èƒ½æ€§çš„应用程åºã€‚组织ä¾é æºä»£ç ç®¡ç†ï¼ŒCI/CD,安全,以åŠæ›´å¤šæ¥å¿«é€Ÿäº¤ä»˜è½¯ä»¶ã€‚"
-msgid "The compliance report shows the merge request violations merged in protected environments."
-msgstr "åˆè§„报告显示åˆå¹¶è¯·æ±‚在å—ä¿æŠ¤çš„环境中åˆå¹¶ã€‚"
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "该连接将在 %{timeout}åŽè¶…时。如仓库导入耗时超过该时间,请使用克隆/推é€ç»„åˆã€‚"
@@ -42341,6 +43067,9 @@ msgstr "ä¾èµ–项列表详细说明了项目中使用组件的信æ¯ã€‚"
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "将此作业部署为 %{environmentLink} 并未æˆåŠŸã€‚"
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr "目录已æˆåŠŸåˆ›å»ºã€‚"
@@ -42652,8 +43381,17 @@ msgstr "您è¦è®¿é—®çš„资æºä¸å­˜åœ¨æˆ–您没有执行此æ“作的æƒé™ã€‚"
msgid "The scan has been created."
msgstr "扫æ已创建。"
-msgid "The secret is only available when you first create the application."
-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 "无需任何身份验è¯å³å¯è®¿é—®è¯¥ä»£ç ç‰‡æ®µã€‚"
@@ -42695,7 +43433,7 @@ msgid "The time period in seconds that the maximum requests per project limit ap
msgstr "æ¯ä¸ªé¡¹ç›®æœ€å¤§è¯·æ±‚所适用的时间间隔(秒)。"
msgid "The top-level group, including any subgroups and projects, will be placed into a %{link_start}read-only%{link_end} state soon. To retain write access, ask your top-level group Owner to %{reduce_link_start}reduce the number of users%{link_end} to %{free_user_limit} or less. An Owner of the top-level group can also start a free trial or upgrade to a paid tier, which do not have user limits. The Owners of the top-level group have also been notified."
-msgstr ""
+msgstr "顶级群组,包括任何å­ç»„和项目,将很快进入%{link_start}åªè¯»%{link_end}状æ€ã€‚è¦ä¿ç•™å†™å…¥æƒé™ï¼Œè¯·è®©æ‚¨çš„顶级群组所有者%{reduce_link_start}将用户数å‡å°‘%{link_end}至 %{free_user_limit} 个或更少。顶级群组的所有者还å¯ä»¥å¼€å§‹å…费试用或å‡çº§åˆ°æ²¡æœ‰ç”¨æˆ·é™åˆ¶çš„付费级别。顶级群组的所有者也已收到通知。"
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "æ›´æ–°æ“作将在 %{number_of_minutes} 分钟åŽè¶…时。对于大型仓库,请使用clone/push组åˆã€‚"
@@ -42997,6 +43735,9 @@ msgstr "获å–作业时出错。"
msgid "There was an error fetching the jobs for your project."
msgstr "为您的项目获å–作业时出错。"
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr "获å–选中群组的顶级标记时出错"
@@ -43186,14 +43927,8 @@ 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 "此附件已被截断,以é¿å…超过最大å…è®¸çš„é™„ä»¶å¤§å° %{size_limit}。 其中包括%{count} 个%{issuables} 中的%{written_count}个。考虑缩å°é€‰æ‹©çš„ %{issuables} å†å¯¼å‡ºã€‚"
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr "此附件已被截断,以é¿å…超过最大å…è®¸çš„é™„ä»¶å¤§å° %{size_limit}。 其中包括了 %{issues_count} 个议题中的 %{written_count} 个,考虑缩å°å¯¼å‡ºçš„选择范围。"
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr "此附件已被截断,以é¿å…超过最大å…è®¸çš„é™„ä»¶å¤§å° %{size_limit}。 其中包括%{merge_requests_count} 个åˆå¹¶è¯·æ±‚中的%{written_count}个。考虑缩å°åˆå¹¶è¯·æ±‚的选择范围。"
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
-msgstr "此附件已被截断,以é¿å…超过最大å…è®¸çš„é™„ä»¶å¤§å° %{size_limit}。 其中包括了 %{requirements_count} 项è¦æ±‚中的 %{written_count} 项;考虑缩å°å¯¼å‡ºçš„选择范围。"
+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 "该阻塞为自我引用"
@@ -43693,6 +44428,9 @@ msgstr "此仓库上次检查于%{last_check_timestamp}。检查%{strong_start}æ
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr "此仓库上次检查于%{last_check_timestamp}。检查通过。"
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "æ­¤Runner仅在å—ä¿æŠ¤åˆ†æ”¯ä¸Šè§¦å‘çš„æµæ°´çº¿ä¸Šè¿è¡Œ"
@@ -43747,11 +44485,8 @@ 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 will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr "这会使您注册的应用程åºå’Œ U2F / WebAuthn 设备无效。"
-
-msgid "This will invalidate your registered applications and U2F devices."
-msgstr "这将使您的注册应用程åºå’Œ U2F 设备无效。"
+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 "这将删除该项目和%{fork_source}之间的派生关系。"
@@ -44199,6 +44934,9 @@ msgstr "首先,请您输入您的 Gitea æœåŠ¡å™¨åœ°å€å’Œä¸€ä¸ª %{link_to_per
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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr "为了帮助改进GitLab,我们会定期%{docs_link}。您å¯ä»¥éšæ—¶é€šè¿‡%{settings_link}更改设置。"
@@ -44252,10 +44990,10 @@ msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
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 ""
+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."
-msgstr ""
+msgstr "è¦ç§»é™¤ %{link_start}åªè¯»%{link_end} 状æ€å¹¶é‡æ–°èŽ·å¾—写入æƒé™ï¼Œæ‚¨å¯ä»¥å°†é¡¶çº§ç¾¤ç»„中的用户数é‡å‡å°‘到 %{free_limit} 个用户或更少。您还å¯ä»¥å‡çº§åˆ°æ²¡æœ‰ç”¨æˆ·é™åˆ¶çš„付费等级。如果您需è¦æ›´å¤šæ—¶é—´ï¼Œæ‚¨å¯ä»¥å¼€å§‹ 30 天的å…费试用,没有用户数é‡é™åˆ¶ã€‚"
msgid "To resolve this, try to:"
msgstr "è¦è§£å†³æ­¤é—®é¢˜ï¼Œè¯·å°è¯•ï¼š"
@@ -44577,7 +45315,7 @@ msgstr "主题已æˆåŠŸæ›´æ–°ã€‚"
msgid "TopicSelect|%d topic found"
msgid_plural "TopicSelect|%d topics found"
-msgstr[0] ""
+msgstr[0] "找到 %d 个主题"
msgid "TopicSelect|No matching results"
msgstr "没有匹é…的结果"
@@ -44684,6 +45422,9 @@ 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 "父组已ç»æœ‰ä¸€ä¸ªå…·æœ‰ç›¸åŒè·¯å¾„çš„å­ç»„或项目。"
@@ -44772,9 +45513,6 @@ msgstr "触å‘集群é‡å»ºã€‚仅使用 13.0 或更高版本创建的索引。"
msgid "Trigger job"
msgstr "触å‘作业"
-msgid "Trigger manual job"
-msgstr "触å‘手动作业"
-
msgid "Trigger pipelines for mirror updates"
msgstr "触å‘é•œåƒæ›´æ–°çš„æµæ°´çº¿"
@@ -44877,9 +45615,6 @@ msgstr "Twitter:"
msgid "Two-Factor Authentication"
msgstr "åŒé‡è®¤è¯"
-msgid "Two-Factor Authentication code"
-msgstr "åŒé‡è®¤è¯éªŒè¯ç "
-
msgid "Two-factor Authentication"
msgstr "åŒé‡è®¤è¯"
@@ -44925,12 +45660,6 @@ msgstr "类型"
msgid "Type to search"
msgstr "输入è¦æœç´¢çš„内容"
-msgid "U2F Devices (%{length})"
-msgstr "U2F设备(%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "U2Fåªæ”¯æŒåœ¨HTTPS的网站。请è”系管ç†å‘˜èŽ·å¾—更多信æ¯"
-
msgid "URL"
msgstr "URL"
@@ -45036,6 +45765,9 @@ msgstr "无法获å–上游和下游æµæ°´çº¿ã€‚"
msgid "Unable to find Jira project to import data from."
msgstr "无法找到è¦å¯¼å…¥æ•°æ®çš„Jira项目。"
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr "无法完全加载默认æ交消æ¯ã€‚您ä»ç„¶å¯ä»¥åº”用此建议,并且æ交消æ¯å°†æ˜¯æ­£ç¡®çš„。"
@@ -45135,6 +45867,9 @@ msgstr "ä¸å¯ç”¨"
msgid "Unban"
msgstr "解å°"
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr "如果您更改分支,未æ交的更改将丢失。您想è¦ç»§ç»­å—?"
@@ -45192,6 +45927,15 @@ msgstr "除éžä¸ŽGitLabå¦æœ‰ä¹¦é¢å议,å¦åˆ™å•å‡»â€œä¸Šä¼ è®¸å¯â€å³è¡¨
msgid "Unlimited"
msgstr "æ— é™"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr "å–消关è”"
@@ -45279,6 +46023,9 @@ msgstr "ä¸æ”¯æŒçš„排åºå€¼ã€‚"
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr "传入了ä¸æ”¯æŒçš„待办事项类型。支æŒçš„待办事项类型为: %{todo_types}"
+msgid "Untitled"
+msgstr "无标题"
+
msgid "Unused"
msgstr "未使用"
@@ -45348,17 +46095,20 @@ msgstr "请更新您的书签 Url, 因为筛选/排åºçš„分支 URL 已更改。
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 ""
+msgstr "您确定è¦æ•´ç†åˆ é™¤æ— æ³•è®¿é—®çš„对象å—?"
msgid "UpdateProject|Are you sure you want to prune?"
-msgstr ""
+msgstr "您确定è¦æ•´ç†åˆ é™¤å—?"
msgid "UpdateProject|Cancel"
-msgstr ""
+msgstr "å–消"
msgid "UpdateProject|Cannot rename project because it contains container registry tags!"
msgstr "因为项目容器镜åƒåº“已有标签,无法更新当å‰é¡¹ç›®ï¼"
@@ -45370,7 +46120,7 @@ msgid "UpdateProject|Could not set the default branch. Do you have a branch name
msgstr "无法设置默认分支。您的代ç åº“中是å¦æœ‰å为 “HEAD†的分支? (%{linkStart}我该如何解决这个问题?%{linkEnd})"
msgid "UpdateProject|Learn more."
-msgstr ""
+msgstr "了解更多。"
msgid "UpdateProject|New visibility level not allowed!"
msgstr "ä¸å…许新的å¯è§æ€§çº§åˆ«ï¼"
@@ -45379,13 +46129,13 @@ msgid "UpdateProject|Project could not be updated!"
msgstr "项目无法更新ï¼"
msgid "UpdateProject|Prune"
-msgstr ""
+msgstr "æ•´ç†åˆ é™¤"
msgid "UpdateProject|Prune unreachable objects"
-msgstr ""
+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 "%{type}仓库校验和验è¯å¤±è´¥ï¼šæ—§%{old}æ–°%{new}"
@@ -45474,6 +46224,9 @@ msgstr "使用趋势"
msgid "Usage statistics"
msgstr "使用情况统计"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr "Container Registry 的项目级存储统计信æ¯ä»…具有方å‘性,ä¸åŒ…括实例范围的é‡å¤æ•°æ®åˆ é™¤ã€‚"
@@ -45645,6 +46398,9 @@ msgstr "这个命å空间没有在当å‰é˜¶æ®µä½¿ç”¨å…±äº« runner 的项目"
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr "此表çœç•¥ä½¿ç”¨ 0 CI/CD 分钟或 0 共享 runner 时长"
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr "上传"
@@ -45849,6 +46605,9 @@ msgstr "使用上é¢çš„ %{strongStart}测试%{strongEnd} 选项创建事件。"
msgid "Use the Apple App Store Connect integration to easily connect to the Apple App Store with Fastlane in CI/CD pipelines."
msgstr "使用 Apple App Store Connect 集æˆï¼Œé€šè¿‡ CI/CD æµæ°´çº¿ä¸­çš„ Fastlane è½»æ¾è¿žæŽ¥åˆ° Apple App Store。"
+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 "使用以下链接确认您的电å­é‚®ä»¶åœ°å€ (%{email})"
@@ -45861,6 +46620,9 @@ msgstr "使用公共云实例 URL (%{kroki_public_url}) 或 %{install_link_start
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 "使用此令牌æ¥éªŒè¯æ”¶åˆ°çš„有效数æ®ã€‚"
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr "å·²æˆåŠŸåˆ›å»ºç”¨æˆ·æ ‡è¯†ã€‚"
@@ -46360,6 +47125,9 @@ msgstr "价值æµåˆ†æžå¯ä»¥å¸®åŠ©æ‚¨äº†è§£å›¢é˜Ÿçš„效率"
msgid "Value Streams Dashboard (Beta)"
msgstr "价值æµä»ªè¡¨ç›˜ï¼ˆBeta)"
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr "值å¯èƒ½åŒ…å«å˜é‡å¼•ç”¨"
@@ -46466,11 +47234,14 @@ msgid "ValueStreamAnalytics|Value stream"
msgstr "价值æµ"
msgid "ValueStreamAnalytics|View details"
-msgstr ""
+msgstr "查看详情"
msgid "ValueStreamEvent|Items in stage"
msgstr "阶段中的事项"
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr "阶段时间(中ä½æ•°ï¼‰"
@@ -46615,6 +47386,9 @@ msgstr "查看和编辑 Markdown, 并选择预览格å¼åŒ–输出。"
msgid "View blame"
msgstr "查看 blame"
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr "查看此å˜æ›´å‰çš„blame模å¼"
@@ -46643,9 +47417,6 @@ msgstr "查看文档"
msgid "View eligible approvers"
msgstr "查看具备相关资格的核准人"
-msgid "View entire blame"
-msgstr "查看完整的 blame"
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "查看%d项已展示产物"
@@ -46846,6 +47617,69 @@ msgstr "%{formattedStartDate}到今天"
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|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 "由%{user}%{statusStart}确认%{statusEnd}于%{timeago}"
@@ -47236,12 +48070,6 @@ msgstr "我们在项目%{project}中找ä¸åˆ°ä¸Ž%{scope}相匹é…çš„%{term}"
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "无法连接PrometheusæœåŠ¡å™¨ã€‚æœåŠ¡å™¨ä¸å†å­˜åœ¨ï¼Œæˆ–者é…置信æ¯éœ€è¦æ›´æ–°ã€‚"
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr "我们检测到有人å°è¯•ä½¿ç”¨é”™è¯¯çš„åŒé‡èº«ä»½éªŒè¯ç ç™»å½•æ‚¨çš„ %{host} å¸æˆ·"
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr "我们检测到有人å°è¯•ä½¿ç”¨é”™è¯¯çš„åŒé‡èº«ä»½éªŒè¯ç ä»Žä»¥ä¸‹ IP 地å€ç™»å½•åˆ°æ‚¨çš„ %{host} å¸æˆ·ï¼š%{ip},%{time}"
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "我们在%{humanized_resource_name}检测到潜在滥用行为。请输入此reCAPTCHA验è¯ç å¹¶ç»§ç»­ã€‚"
@@ -47293,9 +48121,6 @@ msgstr "我们会通知%{inviter} ,您拒ç»äº†æ³¨å†ŒGitLab的邀请。您将ä
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 "我们在此通知您,您的GitLab ä¼ä¸šç‰ˆè®¢é˜…%{plan_name}已接近其用户上é™ã€‚您当å‰æœ‰%{active_user_count}个活跃用户,å³å°†è¾¾åˆ°%{maximum_user_count}的用户é™åˆ¶ã€‚"
-msgid "We'll continuously validate your pipeline configuration. The validation results will appear here."
-msgstr "我们将ä¸æ–­éªŒè¯æ‚¨çš„æµæ°´çº¿é…置。验è¯ç»“果将显示在此处。"
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "我们将使用它æ¥å¸®åŠ©å‘您展示正确的功能和信æ¯ã€‚"
@@ -47437,6 +48262,9 @@ 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 "此项目中的 Webhook 在多次é‡è¯•åŽè‡ªåŠ¨ç¦ç”¨ã€‚"
@@ -47699,6 +48527,10 @@ msgstr "使用%{code_open}http://%{code_close}或%{code_open}https://%{code_clos
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] ""
+
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] "当您的试用期结æŸæ—¶ï¼Œæ‚¨å°†è½¬åˆ°å…费版,席ä½é™åˆ¶ä¸º %{free_user_limit} 个。%{free_user_limit} 个席ä½å°†ä¿æŒæ´»åŠ¨çŠ¶æ€ï¼Œæœªå ç”¨å¸­ä½çš„æˆå‘˜å°†å¤„于%{link_start}超é™çŠ¶æ€%{link_end}并无法访问该群组。"
@@ -47736,6 +48568,9 @@ msgstr "è°å°†ä½¿ç”¨è¿™ä¸ªç¾¤ç»„?"
msgid "Why are you signing up? (optional)"
msgstr "您为什么è¦æ³¨å†Œï¼Ÿï¼ˆå¯é€‰ï¼‰"
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -47955,14 +48790,14 @@ msgstr "ä¸ä¿®å¤/接å—风险"
msgid "Work in progress (open and unassigned)"
msgstr "正在进行中(开放和未分é…)"
-msgid "Work in progress Limit"
-msgstr "“进行中â€é™åˆ¶"
+msgid "Work in progress limit"
+msgstr ""
msgid "WorkItem|%{count} more assignees"
msgstr "%{count} 个更多的指派人"
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 ""
+msgstr "无法添加 %{invalidWorkItemsList}:无法将éžç§å¯† %{childWorkItemType} 分é…ç»™ç§å¯†çš„上级 %{parentWorkItemType}。将选定的 %{childWorkItemType} 标记为ç§å¯†ï¼Œç„¶åŽé‡è¯•ã€‚"
msgid "WorkItem|%{workItemType} deleted"
msgstr "%{workItemType} 已删除"
@@ -48003,6 +48838,9 @@ msgstr "添加到迭代"
msgid "WorkItem|Add to milestone"
msgstr "添加到里程碑"
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "您确定è¦å–消编辑å—?"
@@ -48025,6 +48863,15 @@ msgstr "已删除å­é¡¹"
msgid "WorkItem|Closed"
msgstr "已关闭"
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr "转æ¢ä¸ºä»»åŠ¡"
+
+msgid "WorkItem|Converted to task"
+msgstr "已转æ¢ä¸ºä»»åŠ¡"
+
msgid "WorkItem|Create %{workItemType}"
msgstr "创建 %{workItemType}"
@@ -48049,9 +48896,15 @@ msgstr "截止日期"
msgid "WorkItem|Existing task"
msgstr "现有任务"
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr "å¥åº·çŠ¶å†µ"
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr "事件"
@@ -48172,6 +49025,9 @@ msgstr "任务æ“作"
msgid "WorkItem|Task deleted"
msgstr "任务已删除"
+msgid "WorkItem|Task reverted"
+msgstr "任务已还原"
+
msgid "WorkItem|Tasks"
msgstr "任务"
@@ -48208,6 +49064,9 @@ msgstr "工作项"
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr "您è¦åˆ›å»ºä¸€ä¸ªæ–°åˆ†æ”¯å—?"
@@ -48238,6 +49097,9 @@ msgstr "编写内部备注或将文件拖到此处…"
msgid "Write milestone description..."
msgstr "写入里程碑æè¿°..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "编写å‘行说明(Release Notes) 或将文件拖动到此处..."
@@ -48638,9 +49500,6 @@ msgstr "您没有更新此环境的æƒé™ã€‚"
msgid "You do not have permissions to run the import."
msgstr "您没有æƒé™è¿›è¡Œå¯¼å…¥ã€‚"
-msgid "You don't have any U2F devices registered yet."
-msgstr "您还没有注册任何U2F设备。"
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr "您尚未注册任何WebAuthn设备。"
@@ -48810,12 +49669,18 @@ 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 "您必须登录æ‰èƒ½æœç´¢ç‰¹å®šé¡¹ç›®ã€‚"
@@ -48985,6 +49850,9 @@ msgstr "您的 %{spammable_entity_type} 已被识别为垃圾邮件。请更改å
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
msgstr "您为%{strong}%{namespace_name}%{strong_close}的%{strong}%{plan_name}%{strong_close}订阅将于%{strong}%{expires_on}%{strong_close}到期。"
+msgid "Your Activity"
+msgstr "您的活动"
+
msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details."
msgstr "您的 CI/CD é…置语法无效。选择验è¯é€‰é¡¹å¡äº†è§£æ›´å¤šè¯¦æƒ…。"
@@ -48994,8 +49862,8 @@ msgstr "CSV导出已ç»å¼€å§‹ã€‚完æˆåŽå°†å‘é€ç”µå­é‚®ä»¶è‡³%{email}。"
msgid "Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment."
msgstr "您从项目%{project_link}导出包å«%{count}çš„CSV文件已作为附件添加到此电å­é‚®ä»¶ä¸­ã€‚"
-msgid "Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
-msgstr "您从项目%{project_name}(%{project_url})导出包å«%{written_count}çš„CSV文件已作为附件添加到此电å­é‚®ä»¶ä¸­ã€‚"
+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 import for project"
msgstr "您的项目CSV导入"
@@ -49024,6 +49892,9 @@ msgstr "您的GitLab群组"
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 "您的 GitLab 实例å…许任何人注册一个å¸æˆ·ï¼Œé¢å‘公众的 GitLab 实例存在安全风险。如果ä¸å¸Œæœ›å…¬ä¼—用户注册å¸æˆ·ï¼Œæ‚¨åº”该åœç”¨æ–°çš„注册。"
+msgid "Your GitLab version"
+msgstr "您的 GitLab 版本"
+
msgid "Your Groups"
msgstr "您的群组"
@@ -49048,6 +49919,9 @@ msgstr "您的SSH密钥已删除"
msgid "Your SSH keys (%{count})"
msgstr "您的SSH密钥(%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr "您的基于时间的 OTP 设备已注册ï¼"
+
msgid "Your To-Do List"
msgstr "您的待办事项列表"
@@ -49093,6 +49967,9 @@ msgstr "您的æ“作已被拒ç»ï¼Œå› ä¸ºå…¶å·²è¾¾åˆ°å‘½å空间的存储é™åˆ¶
msgid "Your action succeeded."
msgstr "您的æ“作æˆåŠŸã€‚"
+msgid "Your activity"
+msgstr "您的活动"
+
msgid "Your applications (%{size})"
msgstr "您的应用程åº(%{size})"
@@ -49102,9 +49979,6 @@ msgstr "您已授æƒçš„应用"
msgid "Your browser does not support iFrames"
msgstr "您的æµè§ˆå™¨ä¸æ”¯æŒ iFrame"
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "您的æµè§ˆå™¨ä¸æ”¯æŒU2F。请使用Google Chromeæ¡Œé¢ç‰ˆï¼ˆ41或更高版本)。"
-
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+)。"
@@ -49135,6 +50009,9 @@ msgstr "您的评论将被丢弃。"
msgid "Your commit email is used for web based operations, such as edits and merges."
msgstr "您的æ交电å­é‚®ä»¶ç”¨äºŽåŸºäºŽ web çš„æ“作,例如编辑和åˆå¹¶ã€‚"
+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 "需è¦æ‚¨å½“å‰çš„密ç æ¥æ³¨å†ŒåŒé‡èº«ä»½éªŒè¯ç¨‹åºã€‚"
@@ -49290,6 +50167,9 @@ msgstr "您的顶级群组 %{namespace_name} 已超过 %{free_limit} 个用户çš
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr "您的顶级群组 %{namespace_name} 已超过 %{free_user_limit} 个用户的é™åˆ¶"
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr "您的顶级群组超出了用户和存储é™åˆ¶ï¼Œå·²è¢«ç½®äºŽåªè¯»çŠ¶æ€ã€‚"
@@ -49524,6 +50404,9 @@ 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 "ç¦ç”¨å»¶è¿Ÿç¾¤ç»„删除时无法å¯ç”¨"
@@ -49848,9 +50731,6 @@ msgstr "完整报告"
msgid "ciReport|Generic Report"
msgstr "通用报告"
-msgid "ciReport|IaC Scanning"
-msgstr "IaC 扫æ"
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "通过创建议题æ¥è°ƒæŸ¥æ­¤æ¼æ´ž"
@@ -49915,6 +50795,9 @@ msgstr "通过åˆå¹¶è¯·æ±‚解决"
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "Secret 检测"
@@ -49945,6 +50828,9 @@ msgstr "显示 %{fetchedItems} 项,共 %{totalItems}项"
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 "é™æ€åº”用程åºå®‰å…¨æ€§æµ‹è¯•ï¼ˆSAST)"
@@ -50175,7 +51061,7 @@ msgid "example.com"
msgstr "example.com"
msgid "exceeds maximum length (100 user ids)"
-msgstr ""
+msgstr "超过最大长度(100 个用户 ID)"
msgid "exceeds maximum length (100 usernames)"
msgstr "超过最大长度(100 个用户å)"
@@ -50217,9 +51103,6 @@ msgstr[0] "文件"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "结果无法找到或已与æ¼æ´žå…³è”。"
-msgid "following"
-msgstr "已关注"
-
msgid "for"
msgstr "对于"
@@ -50521,11 +51404,17 @@ msgstr "被 %{path_lock_user_name} 在 %{created_at} é”定"
msgid "manual"
msgstr "手动"
-msgid "math|Displaying this math block may cause performance issues on this page"
-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 "渲染此数学表达å¼æ—¶å‡ºé”™ã€‚%{katexMessage}"
+
+msgid "math|This math block exceeds %{maxMathChars} characters, and may cause performance issues on this page."
+msgstr "此数学表达å¼è¶…过 %{maxMathChars} 个字符,å¯èƒ½ä¼šå¯¼è‡´æ­¤é¡µé¢å‡ºçŽ°æ€§èƒ½é—®é¢˜ã€‚"
-msgid "math|There was an error rendering this math block"
-msgstr "渲染此数学表达å¼æ—¶å‡ºé”™"
+msgid "math|Too many expansions. Consider using multiple math blocks."
+msgstr "扩展太多。考虑使用多个数学表达å¼ã€‚"
msgid "member"
msgid_plural "members"
@@ -50580,6 +51469,84 @@ msgstr "使用åˆå¹¶è¯·æ±‚å‘您的项目æ出更改建议并与您的团队讨
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr "%{boldHeaderStart}此处没有æµæ°´çº¿ã€‚%{boldHeaderEnd}"
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Select %{boldStart}Mark as ready%{boldEnd} to remove it from Draft status."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}选择%{boldStart}标记为就绪%{boldEnd},åˆå¹¶è¯·æ±‚å°†ä¸å†å¤„于è‰ç¨¿çŠ¶æ€ã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Users who can write to the source or target branches can resolve the conflicts."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}å¯ä»¥å†™å…¥æºæˆ–目标分支的用户å¯ä»¥è§£å†³å†²çªã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} a Jira issue key must be mentioned in the title or description."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}必须在标题或æ述中æåŠ Jira issue key。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all required approvals must be given."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}必须获得所有必需的批准。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all status checks must pass."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}所有状æ€æ£€æŸ¥å¿…须通过。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all threads must be resolved."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}必须解决所有主题。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} denied licenses must be removed."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}必须删除被拒ç»çš„许å¯è¯ã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} fast-forward merge is not possible. To merge this request, first rebase locally."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}无法执行快进å¼åˆå¹¶ã€‚è¦åˆå¹¶è¿™ä¸ªåˆå¹¶è¯·æ±‚,首先è¦åœ¨æœ¬åœ°å˜åŸºã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} merge conflicts must be resolved."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}必须解决åˆå¹¶å†²çªã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} new changes were just added."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}刚刚添加了新的å˜æ›´ã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} pipeline must succeed. It's waiting for a manual action to continue."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}æµæ°´çº¿å¿…é¡»æˆåŠŸï¼Œæ­£åœ¨ç­‰å¾…手动æ“作继续。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} pipeline must succeed. Push a commit that fixes the failure or %{linkStart}learn about other solutions.%{linkEnd}"
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}æµæ°´çº¿å¿…é¡»æˆåŠŸã€‚推é€ä¸€ä¸ªæ交修å¤æ•…障或%{linkStart}了解其他的解决方案%{linkEnd}"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} the source branch must be rebased onto the target branch."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}æºåˆ†æ”¯å¿…é¡»å˜åŸºåˆ°ç›®æ ‡åˆ†æ”¯"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} you can only merge after the above items are resolved."
+msgstr "%{boldStart}åˆå¹¶å—阻:%{boldEnd}您åªèƒ½åœ¨è§£å†³ä¸Šè¿°äº‹é¡¹åŽæ‰èƒ½åˆå¹¶ã€‚"
+
+msgid "mrWidget|%{boldStart}Merge unavailable:%{boldEnd} merge requests are read-only in a secondary Geo node."
+msgstr "%{boldStart}åˆå¹¶ä¸å¯ç”¨ï¼š%{boldEnd} åˆå¹¶è¯·æ±‚åœ¨æ¬¡è¦ Geo 节点中是åªè¯»çš„。"
+
+msgid "mrWidget|%{boldStart}Merge unavailable:%{boldEnd} merge requests are read-only on archived projects."
+msgstr "%{boldStart}åˆå¹¶ä¸å¯ç”¨ï¼š%{boldEnd} åˆå¹¶è¯·æ±‚在存档项目上是åªè¯»çš„。"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Changes are being shipped…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd} 更改正在å‘é€â€¦"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Changes will land soon…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd} 更改å³å°†è½åœ°â€¦"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Drum roll, please…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd}请击鼓…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Everything's good…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd} 一切都好…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Lift-off in 5… 4… 3…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd} 五… 四… 三…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Take a deep breath and relax…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd} 深呼å¸ï¼Œæ”¾æ¾â€¦"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} The changes are leaving the station…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd} 更改正在出站…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} This is going to be great…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd} 这将会很赞的…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} We're almost there…"
+msgstr "%{boldStart}åˆå¹¶ä¸­ï¼%{boldEnd} 我们快完æˆäº†â€¦"
+
+msgid "mrWidget|%{boldStart}Ready to be merged automatically.%{boldEnd} Ask someone with write access to this repository to merge this request."
+msgstr "%{boldStart}准备自动åˆå¹¶ã€‚%{boldEnd} 让有此仓库写æƒé™çš„人åˆå¹¶æ­¤è¯·æ±‚。"
+
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}。"
@@ -50595,6 +51562,12 @@ msgstr "%{metricsLinkStart} 内存 %{metricsLinkEnd} å ç”¨ %{emphasisStart} 上
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart} 内存 %{metricsLinkEnd} å ç”¨ %{emphasisStart} æ— å˜åŒ– %{emphasisEnd}, ä¿æŒåœ¨ %{memoryFrom}MB"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr "åˆå¹¶é˜Ÿåˆ—是等待åˆå¹¶åˆ°ç›®æ ‡åˆ†æ”¯çš„åˆå¹¶è¯·æ±‚列表。æ¯ä¸ªåˆå¹¶è¯·æ±‚中的å˜åŠ¨ä¸Žå…ˆå‰åˆå¹¶è¯·æ±‚中的å˜åŠ¨ç›¸ç»“åˆï¼Œç„¶åŽåœ¨åˆå¹¶å‰è¿›è¡Œæµ‹è¯•ã€‚"
@@ -50622,12 +51595,6 @@ msgstr "核准为å¯é€‰"
msgid "mrWidget|Approval password is invalid."
msgstr "批准密ç æ— æ•ˆ"
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr "审批规则 %{rules} 无效。系统已自动批准此规则æ¥è§£é™¤é˜»å¡žåˆå¹¶è¯·æ±‚。%{link}"
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr "审批规则 %{rules} 无效。系统已自动批准这些规则æ¥è§£é™¤é˜»å¡žåˆå¹¶è¯·æ±‚。%{link}"
-
msgid "mrWidget|Approve"
msgstr "批准"
@@ -50643,6 +51610,9 @@ 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 "将这些议题分é…给自己"
@@ -50720,83 +51690,29 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] "æåŠè®®é¢˜"
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šæ ‡é¢˜æˆ–æ述中必须æ到 Jira 议题的 key。"
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šå¿…须获得所有è¦æ±‚的批准。"
-
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šå¿…须通过所有状æ€æ£€æŸ¥ã€‚"
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šå¿…须解决所有主题。"
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šå¿…须删除被拒ç»çš„许å¯è¯ã€‚"
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šå¿«è¿›åˆå¹¶æ˜¯ä¸å¯èƒ½çš„。è¦åˆå¹¶è¿™ä¸ªè¯·æ±‚,首先在本地å˜åŸºã€‚"
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šå¿…须解决åˆå¹¶å†²çªã€‚"
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr "åˆå¹¶è¢«é˜»æ­¢ï¼šæµæ°´çº¿å¿…é¡»æˆåŠŸã€‚等待手动完æˆæ“作。"
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr "åˆå¹¶å—阻:æµæ°´çº¿å¿…é¡»æˆåŠŸã€‚推é€ä¸€ä¸ªä¿®å¤å¤±è´¥çš„æ交,或者%{linkStart}了解其它解决方案。%{linkEnd}"
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr "åˆå¹¶é˜»å¡žï¼šè§£å†³ä¸Šè¿°é—®é¢˜åŽæ‰èƒ½åˆå¹¶ã€‚"
+msgstr "åˆå¹¶å—阻:必须获å–所有必需的批准。"
msgid "mrWidget|Merge failed."
msgstr "åˆå¹¶å¤±è´¥ã€‚"
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr "åˆå¹¶ä¸å¯ç”¨ï¼šåˆå¹¶è¯·æ±‚在归档项目上是åªè¯»çš„。"
-
msgid "mrWidget|Merged by"
msgstr "åˆå¹¶è€…:"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr "åˆå¹¶ä¸­ï¼æ­£åœ¨å‘é€æ›´æ”¹â€¦"
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr "åˆå¹¶ä¸­ï¼å˜åŒ–å³å°†å®Œæˆâ€¦"
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr "åˆå¹¶ä¸­ï¼è¯·ç¨åŽâ€¦"
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr "正在åˆå¹¶ï¼ä¸€åˆ‡éƒ½å¾ˆå¥½â€¦"
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr "正在åˆå¹¶ï¼"
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr "åˆå¹¶ä¸­ï¼è¯·ç¨å€™â€¦"
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr "正在åˆå¹¶ï¼"
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr "åˆå¹¶ä¸­ï¼è¯·ç¨åŽâ€¦"
-
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "正在åˆå¹¶ï¼æˆ‘们快完æˆäº†â€¦"
-
msgid "mrWidget|More information"
msgstr "更多信æ¯"
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "没有用户符åˆè¯¥è§„则的标准。"
-
msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr "请还原它或使用ä¸åŒçš„ %{type} 分支。"
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "å·²å¯è‡ªåŠ¨åˆå¹¶ã€‚ 请具有仓库写入æƒé™çš„用户æ¥åˆå¹¶æ­¤è¯·æ±‚"
+msgid "mrWidget|Rebase"
+msgstr "å˜åŸº"
+
+msgid "mrWidget|Rebase in progress"
+msgstr "正在进行å˜åŸº"
+
+msgid "mrWidget|Rebase without pipeline"
+msgstr "å˜åŸºï¼Œä¸è¿è¡Œæµæ°´çº¿"
msgid "mrWidget|Refresh"
msgstr "刷新"
@@ -50858,9 +51774,6 @@ msgstr "è¦æ›´æ”¹æ­¤é»˜è®¤æ¶ˆæ¯ï¼Œè¯·ç¼–辑åˆå¹¶æ交消æ¯çš„模æ¿ã€‚ %{lin
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr "è¦æ›´æ”¹æ­¤é»˜è®¤æ¶ˆæ¯ï¼Œè¯·ç¼–辑压缩æ交消æ¯çš„模æ¿ã€‚ %{linkStart}了解更多信æ¯ã€‚%{linkEnd}"
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr "å¯ä»¥å†™å…¥æºæˆ–目标分支的用户å¯ä»¥è§£å†³å†²çªã€‚"
-
msgid "mrWidget|What is a merge train?"
msgstr "什么是åˆå¹¶é˜Ÿåˆ—?"
@@ -50885,6 +51798,9 @@ msgstr "必须是有效的IPv4或IPv6地å€"
msgid "must be a valid json schema"
msgstr "必须是有效的 json schema"
+msgid "must be a valid syntax highlighting theme ID"
+msgstr "必须是有效的语法高亮主题 ID"
+
msgid "must be after start"
msgstr "必须在开始之åŽ"
@@ -51235,7 +52151,7 @@ msgid "should be an array of %{object_name} objects"
msgstr "应该是%{object_name}对象的数组"
msgid "should be an array of existing user ids. %{invalid} does not exist"
-msgstr ""
+msgstr "应该是现有用户 ID 的数组。%{invalid} ä¸å­˜åœ¨"
msgid "should be an array of existing usernames. %{invalid} does not exist"
msgstr "应该是现有用户å的数组。%{invalid}ä¸å­˜åœ¨"
@@ -51404,7 +52320,7 @@ 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 ""
+msgstr "%{report_type} 报告类型的 %{report_version} 版本已弃用;但是,GitLab ä»å°†å°è¯•è§£æžå¤„ç†è¯¥æŠ¥å‘Šã€‚请将安全报告å‡çº§åˆ°ä»¥ä¸‹ç‰ˆæœ¬ä¹‹ä¸€ï¼š%{current_schema_versions}。"
msgid "version %{versionIndex}"
msgstr "版本 %{versionIndex}"
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index 077459635f1..735425aac67 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-02-11 04:23\n"
+"PO-Revision-Date: 2023-03-11 10:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] ""
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] ""
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] ""
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+
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 ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} 和 %{openOrClose} %{noteable}"
@@ -539,6 +553,9 @@ msgstr ""
msgid "%{count} selected"
msgstr ""
+msgid "%{count} tags"
+msgstr ""
+
msgid "%{count} total weight"
msgstr ""
@@ -740,6 +757,9 @@ msgstr ""
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr ""
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr ""
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr ""
@@ -755,9 +775,6 @@ msgstr ""
msgid "%{message} showing first %{warnings_displayed}"
msgstr ""
-msgid "%{message}. Your attention request was removed."
-msgstr ""
-
msgid "%{milestone} (expired)"
msgstr ""
@@ -889,6 +906,9 @@ msgstr ""
msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr ""
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@@ -1116,6 +1136,9 @@ msgstr ""
msgid "%{user} created an issue: %{issue_link}"
msgstr ""
+msgid "%{user} user’s menu"
+msgstr ""
+
msgid "%{value} is not included in the list"
msgstr ""
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] ""
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] ""
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%d 個群組"
@@ -1675,9 +1694,6 @@ msgstr ""
msgid "API Fuzzing"
msgstr ""
-msgid "API Fuzzing Configuration"
-msgstr ""
-
msgid "API Help"
msgstr ""
@@ -2092,9 +2108,6 @@ msgstr ""
msgid "Add a collapsible section"
msgstr ""
-msgid "Add a comment"
-msgstr ""
-
msgid "Add a comment to this line"
msgstr ""
@@ -2116,6 +2129,9 @@ msgstr ""
msgid "Add a new issue"
msgstr ""
+msgid "Add a new saved reply"
+msgstr ""
+
msgid "Add a numbered list"
msgstr ""
@@ -2125,6 +2141,9 @@ 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 ""
@@ -2239,6 +2258,9 @@ msgstr ""
msgid "Add new directory"
msgstr "添加新目錄"
+msgid "Add new saved reply"
+msgstr ""
+
msgid "Add or remove a user."
msgstr ""
@@ -2377,6 +2399,9 @@ msgstr ""
msgid "Additional text"
msgstr "附加文字"
+msgid "Additional text for deactivation email"
+msgstr ""
+
msgid "Additional text for the sign-in and Help page."
msgstr ""
@@ -3556,40 +3581,10 @@ 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've reviewed these contribution guidelines, you'll be all set to"
-msgstr ""
-
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
msgstr ""
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr ""
msgid "Akismet"
@@ -3961,6 +3956,9 @@ msgstr ""
msgid "All Members"
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 ""
@@ -4587,6 +4585,9 @@ 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 ""
@@ -4596,6 +4597,123 @@ msgstr ""
msgid "Analytics"
msgstr ""
+msgid "Analytics|Add to Dashboard"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard Title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr ""
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4674,13 +4792,28 @@ 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|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."
+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."
@@ -4823,12 +4956,18 @@ 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 ""
@@ -5068,6 +5207,10 @@ msgstr ""
msgid "Approve a merge request"
msgstr ""
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+
msgid "Approve merge request"
msgstr ""
@@ -5080,6 +5223,14 @@ msgstr ""
msgid "Approved MRs"
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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr ""
@@ -5155,9 +5306,6 @@ msgstr ""
msgid "Are you sure you want to approve %{user}?"
msgstr ""
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr ""
@@ -5170,6 +5318,9 @@ 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 ""
@@ -5518,7 +5669,7 @@ msgstr[0] ""
msgid "Attaching the file failed."
msgstr ""
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
msgstr ""
msgid "Audit Events"
@@ -5771,9 +5922,6 @@ msgstr ""
msgid "Authorization code:"
msgstr ""
-msgid "Authorization required"
-msgstr ""
-
msgid "Authorization token duration (minutes)"
msgstr ""
@@ -5786,9 +5934,6 @@ msgstr ""
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
-msgid "Authorize %{user} to use your account?"
-msgstr ""
-
msgid "Authorized %{new_chat_name}"
msgstr ""
@@ -5798,9 +5943,18 @@ msgstr ""
msgid "Authorized applications (%{size})"
msgstr ""
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr ""
@@ -6182,6 +6336,9 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 ""
@@ -6209,9 +6366,6 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
-msgid "Beta"
-msgstr ""
-
msgid "Bi-weekly code coverage"
msgstr ""
@@ -6281,6 +6435,9 @@ msgstr ""
msgid "BillingPlans|Faster code reviews"
msgstr ""
+msgid "BillingPlans|Free"
+msgstr ""
+
msgid "BillingPlans|Free forever features for individual users"
msgstr ""
@@ -6296,9 +6453,6 @@ msgstr ""
msgid "BillingPlans|Includes free static websites"
msgstr ""
-msgid "BillingPlans|Learn more"
-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 ""
@@ -6434,27 +6588,9 @@ msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
-msgid "Billings|%{planName} plan"
-msgstr ""
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr ""
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr ""
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr ""
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr ""
-
msgid "Billings|Error validating card details"
msgstr ""
-msgid "Billings|Extend trial"
-msgstr ""
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr ""
@@ -6464,9 +6600,6 @@ msgstr ""
msgid "Billings|In a seat"
msgstr ""
-msgid "Billings|Reactivate trial"
-msgstr ""
-
msgid "Billings|Seats in use / Seats available"
msgstr ""
@@ -6606,6 +6739,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
msgid "BlobViewer|View on %{environmentName}"
msgstr ""
@@ -6825,15 +6961,27 @@ msgstr[0] ""
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|List actions"
+msgstr ""
+
msgid "Boards|Move card"
msgstr ""
@@ -6846,9 +6994,6 @@ msgstr ""
msgid "Boards|New board"
msgstr ""
-msgid "Boards|New epic"
-msgstr ""
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr ""
@@ -6966,9 +7111,6 @@ msgstr ""
msgid "BranchRules|All branches"
msgstr ""
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
@@ -6987,6 +7129,15 @@ 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 ""
@@ -7017,10 +7168,13 @@ msgstr ""
msgid "BranchRules|Details"
msgstr ""
-msgid "BranchRules|Force push"
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
msgstr ""
-msgid "BranchRules|Force push is not allowed."
+msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
@@ -7062,6 +7216,9 @@ msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr ""
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
@@ -7828,6 +7985,15 @@ 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 ""
@@ -7945,6 +8111,9 @@ 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 ""
@@ -8325,6 +8494,9 @@ 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 ""
@@ -8367,6 +8539,9 @@ 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 ""
@@ -8376,16 +8551,13 @@ msgstr ""
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
-msgid "Checkout|Edit"
+msgid "Checkout|Discount"
msgstr ""
-msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
-
-msgid "Checkout|Failed to confirm your order! Please try again."
+msgid "Checkout|Edit"
msgstr ""
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
@@ -8412,6 +8584,9 @@ 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 ""
@@ -8430,6 +8605,9 @@ msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
msgid "Checkout|Number of users"
msgstr ""
@@ -8448,6 +8626,9 @@ msgstr ""
msgid "Checkout|Select a state"
msgstr ""
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
msgid "Checkout|State"
msgstr ""
@@ -8568,12 +8749,18 @@ 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 "CiCdAnalytics|Date range: %{range}"
msgstr ""
@@ -8652,10 +8839,10 @@ msgstr ""
msgid "CiStatus|running"
msgstr "é‹è¡Œä¸­"
-msgid "CiVariables|Cannot use Masked Variable with current value"
+msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Clear inputs"
+msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
@@ -8685,6 +8872,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
msgid "CiVariables|Remove variable"
msgstr ""
@@ -9464,6 +9654,9 @@ 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 ""
@@ -9755,7 +9948,7 @@ msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr ""
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr ""
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr ""
msgid "Compare GitLab plans"
msgstr ""
-msgid "Compare Revisions"
-msgstr ""
-
msgid "Compare branches and continue"
msgstr ""
@@ -10161,6 +10351,9 @@ msgstr "與最後æ交進行比較"
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare revisions"
+msgstr ""
+
msgid "Compare submodule commit revisions"
msgstr ""
@@ -10230,12 +10423,21 @@ msgstr ""
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr ""
+msgid "Compliance Report|Frameworks"
+msgstr ""
+
+msgid "Compliance Report|Violations"
+msgstr ""
+
msgid "Compliance framework"
msgstr ""
msgid "Compliance report"
msgstr ""
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -10344,9 +10546,24 @@ msgstr ""
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
+msgid "ComplianceReport|No framework"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
msgid "ComplianceReport|No violations found"
msgstr ""
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr ""
@@ -10365,9 +10582,6 @@ msgstr ""
msgid "Confidentiality"
msgstr "隱密的"
-msgid "Configuration"
-msgstr ""
-
msgid "Configuration help"
msgstr ""
@@ -10986,6 +11200,9 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
+msgid "Content"
+msgstr ""
+
msgid "Content parsed with %{link}."
msgstr ""
@@ -11028,12 +11245,21 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -11049,6 +11275,9 @@ 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 ""
@@ -11094,7 +11323,10 @@ msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
msgstr ""
msgid "ContributionAnalytics|The to date is earlier than the given from date"
@@ -11115,8 +11347,8 @@ msgstr ""
msgid "Contributor"
msgstr ""
-msgid "Contributors"
-msgstr "è²¢ç»è€…"
+msgid "Contributor statistics"
+msgstr ""
msgid "Control emails linked to your account"
msgstr ""
@@ -11187,6 +11419,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
+msgid "Copy diagram URL"
+msgstr ""
+
msgid "Copy environment"
msgstr ""
@@ -11433,7 +11668,7 @@ msgstr ""
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr ""
-msgid "Country"
+msgid "Country / Region"
msgstr ""
msgid "Counts"
@@ -11622,6 +11857,9 @@ msgstr ""
msgid "Create or close an issue."
msgstr ""
+msgid "Create or edit diagram"
+msgstr ""
+
msgid "Create or import your first project"
msgstr ""
@@ -11871,9 +12109,6 @@ msgstr ""
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
-msgid "Created at"
-msgstr ""
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -12081,6 +12316,9 @@ 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 ""
@@ -12180,7 +12418,7 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr ""
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
@@ -12346,9 +12584,6 @@ msgstr ""
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
-msgid "DAST Configuration"
-msgstr ""
-
msgid "DAST configuration not found"
msgstr ""
@@ -13259,6 +13494,9 @@ msgstr ""
msgid "Delete deploy key"
msgstr ""
+msgid "Delete diagram"
+msgstr ""
+
msgid "Delete epic"
msgstr ""
@@ -13301,6 +13539,9 @@ msgstr ""
msgid "Delete row"
msgstr ""
+msgid "Delete saved reply"
+msgstr ""
+
msgid "Delete selected"
msgstr ""
@@ -14044,6 +14285,9 @@ msgstr ""
msgid "Deprecated API rate limits"
msgstr ""
+msgid "Deprecation notice"
+msgstr ""
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr ""
@@ -14144,10 +14388,13 @@ msgstr ""
msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update discussion. Please try again."
+msgid "DesignManagement|Could not delete comment. Please try again."
msgstr ""
-msgid "DesignManagement|Could not update note. Please try again."
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
msgstr ""
msgid "DesignManagement|Deselect all"
@@ -14252,6 +14499,9 @@ msgstr ""
msgid "Developer"
msgstr ""
+msgid "Device name"
+msgstr ""
+
msgid "Devices (optional)"
msgstr ""
@@ -14447,6 +14697,9 @@ msgstr ""
msgid "Diagram (%{language})"
msgstr ""
+msgid "Diagram saved successfully."
+msgstr ""
+
msgid "Did not delete the source branch."
msgstr ""
@@ -14597,9 +14850,6 @@ msgstr ""
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr ""
-msgid "Discover"
-msgstr ""
-
msgid "Discover GitLab Geo"
msgstr ""
@@ -15036,6 +15286,9 @@ msgstr ""
msgid "Edit description"
msgstr ""
+msgid "Edit diagram description"
+msgstr ""
+
msgid "Edit environment"
msgstr ""
@@ -15060,6 +15313,9 @@ msgstr ""
msgid "Edit image description"
msgstr ""
+msgid "Edit image text or link"
+msgstr ""
+
msgid "Edit in pipeline editor"
msgstr ""
@@ -15078,9 +15334,15 @@ msgstr ""
msgid "Edit merge requests"
msgstr ""
+msgid "Edit project: %{project_name}"
+msgstr ""
+
msgid "Edit public deploy key"
msgstr ""
+msgid "Edit saved reply"
+msgstr ""
+
msgid "Edit sidebar"
msgstr ""
@@ -15537,6 +15799,9 @@ msgstr ""
msgid "Enter Admin Mode"
msgstr ""
+msgid "Enter a name for your saved reply"
+msgstr ""
+
msgid "Enter a number"
msgstr ""
@@ -15582,7 +15847,7 @@ msgstr ""
msgid "Enter the %{name} title"
msgstr ""
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
+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:"
@@ -15600,6 +15865,9 @@ 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 ""
@@ -15894,6 +16162,9 @@ msgstr ""
msgid "Epic actions"
msgstr ""
+msgid "Epic boards"
+msgstr ""
+
msgid "Epic cannot be found."
msgstr ""
@@ -16005,6 +16276,9 @@ 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 ""
@@ -16293,6 +16567,9 @@ 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 ""
@@ -16570,6 +16847,9 @@ msgstr ""
msgid "Exactly one of %{attributes} is required"
msgstr ""
+msgid "Example"
+msgstr ""
+
msgid "Example: (feature|hotfix)\\/*"
msgstr ""
@@ -16594,6 +16874,9 @@ 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 ""
@@ -16795,6 +17078,9 @@ 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 ""
@@ -16813,6 +17099,9 @@ 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 ""
@@ -17380,9 +17669,6 @@ msgstr "二月"
msgid "February"
msgstr "二月"
-msgid "Feedback and Updates"
-msgstr ""
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17506,6 +17792,9 @@ msgstr ""
msgid "Filter pipelines"
msgstr ""
+msgid "Filter reports"
+msgstr ""
+
msgid "Filter results"
msgstr ""
@@ -17662,9 +17951,6 @@ msgstr ""
msgid "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 "For faster browsing, not all history is shown."
-msgstr ""
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr ""
@@ -17806,9 +18092,6 @@ msgstr ""
msgid "Framework successfully deleted"
msgstr ""
-msgid "Free"
-msgstr ""
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -18616,13 +18899,22 @@ 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 %{maxExcludedUsers} excluded users."
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
msgstr ""
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
@@ -18673,6 +18965,9 @@ msgstr ""
msgid "GitLab Pages"
msgstr ""
+msgid "GitLab Pages has moved"
+msgstr ""
+
msgid "GitLab Shell"
msgstr ""
@@ -18697,6 +18992,12 @@ 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 ""
@@ -18712,9 +19013,6 @@ msgstr ""
msgid "GitLab group: %{source_link}"
msgstr ""
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr ""
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -18763,10 +19061,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18860,12 +19154,18 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
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 ""
@@ -18905,6 +19205,9 @@ msgstr ""
msgid "Gitea Import"
msgstr ""
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr ""
@@ -18917,13 +19220,13 @@ msgstr ""
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr ""
-msgid "GithubImporter|Issue attachments"
+msgid "GithubImporter|Issue links"
msgstr ""
-msgid "GithubImporter|Merge request attachments"
+msgid "GithubImporter|Merge request links"
msgstr ""
-msgid "GithubImporter|Note attachments"
+msgid "GithubImporter|Note links"
msgstr ""
msgid "GithubImporter|PR mergers"
@@ -18941,7 +19244,7 @@ msgstr ""
msgid "GithubImporter|Pull requests"
msgstr ""
-msgid "GithubImporter|Release attachments"
+msgid "GithubImporter|Release links"
msgstr ""
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
@@ -18995,6 +19298,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Global SAML group membership lock"
+msgstr ""
+
msgid "Global Search is disabled for this scope"
msgstr ""
@@ -19067,6 +19373,9 @@ msgstr ""
msgid "GlobalSearch|Recent merge requests"
msgstr ""
+msgid "GlobalSearch|Reset filters"
+msgstr ""
+
msgid "GlobalSearch|Result count is over limit."
msgstr ""
@@ -19121,15 +19430,9 @@ msgstr ""
msgid "GlobalSearch|all GitLab"
msgstr ""
-msgid "GlobalSearch|group"
-msgstr ""
-
msgid "GlobalSearch|in %{scope}"
msgstr ""
-msgid "GlobalSearch|project"
-msgstr ""
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
@@ -19346,6 +19649,30 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
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 ""
@@ -19535,6 +19862,9 @@ msgstr ""
msgid "Group navigation"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Group overview content"
msgstr ""
@@ -19886,6 +20216,9 @@ 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 ""
@@ -20144,6 +20477,9 @@ 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 ""
@@ -20159,6 +20495,12 @@ msgstr ""
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
msgid "GroupsNew|No import options available"
msgstr ""
@@ -20533,6 +20875,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -20874,6 +21219,9 @@ 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 ""
@@ -20973,6 +21321,9 @@ 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 ""
@@ -21015,15 +21366,24 @@ 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 ""
@@ -21084,7 +21444,7 @@ 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 a wrong two-factor authentication code, you may ignore this email."
+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}"
@@ -21308,6 +21668,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
@@ -21711,7 +22074,7 @@ msgstr ""
msgid "InProductMarketing|Rapid development, simplified"
msgstr ""
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
@@ -22374,12 +22737,18 @@ msgstr ""
msgid "Insert link"
msgstr ""
+msgid "Insert or edit diagram"
+msgstr ""
+
msgid "Insert row after"
msgstr ""
msgid "Insert row before"
msgstr ""
+msgid "Insert saved reply"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -22552,10 +22921,13 @@ msgstr ""
msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
-msgid "Integrations|Edit project alias"
+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|Enable GitLab.com slash commands in a Slack workspace."
+msgid "Integrations|Edit project alias"
msgstr ""
msgid "Integrations|Enable SSL verification"
@@ -22573,6 +22945,9 @@ msgstr ""
msgid "Integrations|Enter your alias"
msgstr ""
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr ""
@@ -22861,7 +23236,7 @@ msgstr ""
msgid "Invalid repository path"
msgstr ""
-msgid "Invalid rule"
+msgid "Invalid rules are automatically approved to unblock the merge request."
msgstr ""
msgid "Invalid server response"
@@ -22990,9 +23365,6 @@ 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|Explore paid plans"
-msgstr ""
-
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -23261,6 +23633,12 @@ msgstr ""
msgid "Issue already promoted to epic."
msgstr ""
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
msgid "Issue cannot be found."
msgstr ""
@@ -23486,6 +23864,9 @@ msgstr ""
msgid "Issue|Title"
msgstr ""
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr ""
@@ -24023,9 +24404,24 @@ msgstr ""
msgid "JobAssistant|Add job"
msgstr ""
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
msgid "JobAssistant|Job assistant"
msgstr ""
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
msgid "Jobs"
msgstr ""
@@ -24712,6 +25108,15 @@ 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 ""
@@ -24793,6 +25198,9 @@ 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 ""
@@ -24802,6 +25210,9 @@ 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 ""
@@ -24817,9 +25228,6 @@ msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr ""
-
msgid "LearnGitlab|Ok, let's go"
msgstr ""
@@ -24835,6 +25243,9 @@ msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
+msgid "Leave feadback."
+msgstr ""
+
msgid "Leave group"
msgstr "退出群組"
@@ -25078,6 +25489,10 @@ msgstr ""
msgid "Limiting mode"
msgstr ""
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr ""
@@ -25105,6 +25520,9 @@ msgstr ""
msgid "Link copied"
msgstr ""
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr ""
@@ -25198,9 +25616,6 @@ msgstr ""
msgid "List of all commits"
msgstr ""
-msgid "List of all merge commits"
-msgstr ""
-
msgid "List of suitable GCP locations"
msgstr ""
@@ -25243,6 +25658,9 @@ 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 ""
@@ -25282,6 +25700,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr ""
@@ -25300,9 +25721,6 @@ msgstr ""
msgid "Locked"
msgstr ""
-msgid "Locked Files"
-msgstr ""
-
msgid "Locked by %{fileLockUserName}"
msgstr ""
@@ -25372,9 +25790,6 @@ msgstr ""
msgid "MERGED"
msgstr ""
-msgid "ML Experiments"
-msgstr ""
-
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25411,10 +25826,7 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr ""
-
-msgid "Machine Learning Experiments"
+msgid "Macbook Touch ID on Edge"
msgstr ""
msgid "Made this %{type} confidential."
@@ -25906,6 +26318,9 @@ msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr ""
@@ -25987,12 +26402,21 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
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|must be top-level namespace"
msgstr ""
@@ -26211,18 +26635,9 @@ msgstr ""
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr ""
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr ""
-
-msgid "Merge blocked: new changes were just added."
-msgstr ""
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr ""
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr ""
-
msgid "Merge commit SHA"
msgstr ""
@@ -26295,9 +26710,6 @@ msgstr ""
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr ""
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr ""
-
msgid "Merge unverified changes"
msgstr ""
@@ -26310,6 +26722,27 @@ 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 ""
@@ -26918,6 +27351,9 @@ msgstr[0] ""
msgid "Milestone due date"
msgstr ""
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
msgid "Milestone lists not available with your current license"
msgstr "ç›®å‰è¨±å¯è­‰ç„¡æ³•ä½¿ç”¨é‡Œç¨‹ç¢‘列表"
@@ -27098,6 +27534,12 @@ msgstr ""
msgid "Minutes"
msgstr ""
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
msgid "Mirror direction"
msgstr ""
@@ -27110,6 +27552,9 @@ msgstr ""
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
+msgid "Mirror specific branches"
+msgstr ""
+
msgid "Mirror user"
msgstr ""
@@ -27170,31 +27615,46 @@ msgstr ""
msgid "MlExperimentTracking|Artifacts"
msgstr ""
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Created at"
msgstr ""
msgid "MlExperimentTracking|Details"
msgstr ""
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr ""
msgid "MlExperimentTracking|Filter candidates"
msgstr ""
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr ""
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
msgid "MlExperimentTracking|Name"
msgstr ""
msgid "MlExperimentTracking|No candidates to display"
msgstr ""
-msgid "MlExperimentTracking|User"
+msgid "MlExperimentTracking|No experiments"
msgstr ""
-msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|User"
msgstr ""
msgid "Modal updated"
@@ -27537,6 +27997,9 @@ msgstr ""
msgid "Namespaces to index"
msgstr ""
+msgid "Naming"
+msgstr ""
+
msgid "Naming, topics, avatar"
msgstr ""
@@ -27585,10 +28048,16 @@ msgstr ""
msgid "Navigation|Context navigation"
msgstr ""
-msgid "Navigation|Recent groups"
+msgid "Navigation|FREQUENT GROUPS"
msgstr ""
-msgid "Navigation|Recent projects"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
msgstr ""
msgid "Navigation|Switch to..."
@@ -27700,9 +28169,6 @@ msgstr ""
msgid "New Snippet"
msgstr ""
-msgid "New Test Case"
-msgstr ""
-
msgid "New User"
msgstr ""
@@ -27790,9 +28256,6 @@ msgstr ""
msgid "New password"
msgstr ""
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr ""
-
msgid "New project"
msgstr "新專案"
@@ -28147,6 +28610,15 @@ 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 ""
@@ -28229,13 +28701,16 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+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. 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."
+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."
@@ -28533,12 +29008,24 @@ 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|%{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 ""
@@ -28587,9 +29074,18 @@ 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 ""
@@ -28617,9 +29113,6 @@ 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}"
-msgstr ""
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr ""
@@ -28656,6 +29149,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr ""
@@ -28665,6 +29161,9 @@ msgstr ""
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
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 ""
@@ -28677,6 +29176,9 @@ msgstr ""
msgid "Notify|Remote mirror"
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 ""
@@ -29152,6 +29654,9 @@ 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 ""
@@ -29221,9 +29726,6 @@ msgstr ""
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr ""
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr ""
@@ -29516,28 +30018,34 @@ 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 services."
+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 web hooks and services"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
+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|Resolve IP addresses once and uses them to submit requests."
+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."
@@ -30330,6 +30838,9 @@ msgstr ""
msgid "Pending comments"
msgstr ""
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr ""
@@ -30519,9 +31030,6 @@ msgstr ""
msgid "Pick a name"
msgstr ""
-msgid "Pin code"
-msgstr ""
-
msgid "Pipeline"
msgstr "æµæ°´ç·š"
@@ -30720,6 +31228,9 @@ 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 ""
@@ -30945,6 +31456,9 @@ 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 ""
@@ -30996,9 +31510,6 @@ msgstr ""
msgid "Pipelines|Clear runner caches"
msgstr ""
-msgid "Pipelines|Configuration validation currently not available."
-msgstr ""
-
msgid "Pipelines|Configure pipeline"
msgstr ""
@@ -31044,6 +31555,12 @@ msgstr ""
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
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 ""
@@ -31095,7 +31612,7 @@ msgstr ""
msgid "Pipelines|Pipeline Editor"
msgstr ""
-msgid "Pipelines|Pipeline syntax is correct."
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
@@ -31104,6 +31621,9 @@ 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|Revoke trigger"
msgstr ""
@@ -31140,13 +31660,13 @@ 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."
+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}."
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
@@ -31176,6 +31696,12 @@ 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 ""
@@ -31197,6 +31723,9 @@ 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 ""
@@ -31206,6 +31735,9 @@ 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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
@@ -31521,6 +32053,9 @@ msgstr ""
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr ""
+msgid "Please enter a name for the saved reply."
+msgstr ""
+
msgid "Please enter a non-negative number"
msgstr ""
@@ -31542,6 +32077,9 @@ msgstr ""
msgid "Please enter a value of 90 days or more"
msgstr ""
+msgid "Please enter the saved reply content."
+msgstr ""
+
msgid "Please enter your current password."
msgstr ""
@@ -31602,7 +32140,7 @@ msgstr ""
msgid "Please select a Jira project"
msgstr ""
-msgid "Please select a country"
+msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
@@ -31956,6 +32494,9 @@ msgstr ""
msgid "Preview payload"
msgstr ""
+msgid "Previous"
+msgstr ""
+
msgid "Previous Artifacts"
msgstr ""
@@ -32025,88 +32566,31 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr ""
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr ""
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr ""
-
-msgid "Product Analytics|Back to dashboards"
-msgstr ""
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr ""
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr ""
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr ""
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr ""
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr ""
-
-msgid "Product Analytics|Instrument your application"
-msgstr ""
-
-msgid "Product Analytics|Instrumentation details"
-msgstr ""
-
-msgid "Product Analytics|SDK App ID"
-msgstr ""
-
-msgid "Product Analytics|SDK Host"
-msgstr ""
-
-msgid "Product Analytics|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 "Product Analytics|Set up product analytics"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr ""
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr ""
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr ""
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
+msgid "Product analytics"
msgstr ""
-msgid "Product Analytics|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."
+msgid "ProductAnalytics|Add another dimension"
msgstr ""
-msgid "Product analytics"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
msgstr ""
-msgid "ProductAnalytics|Add another dimension"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
msgstr ""
-msgid "ProductAnalytics|Add to Dashboard"
+msgid "ProductAnalytics|All Clicks Compared"
msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr ""
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Features"
msgstr ""
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Pages"
msgstr ""
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
@@ -32115,34 +32599,37 @@ 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|Browser"
+msgid "ProductAnalytics|Average Per User"
msgstr ""
-msgid "ProductAnalytics|Browser Family"
+msgid "ProductAnalytics|Average Session Duration"
msgstr ""
-msgid "ProductAnalytics|Cancel Edit"
+msgid "ProductAnalytics|Average duration in minutes"
msgstr ""
-msgid "ProductAnalytics|Choose a chart type on the right"
+msgid "ProductAnalytics|Back to dashboards"
msgstr ""
-msgid "ProductAnalytics|Choose a measurement to start"
+msgid "ProductAnalytics|Cancel Edit"
msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Code"
+msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
-msgid "ProductAnalytics|Compares all events against each other"
+msgid "ProductAnalytics|Compares all user sessions against each other"
msgstr ""
msgid "ProductAnalytics|Compares click events against each other"
@@ -32151,24 +32638,18 @@ msgstr ""
msgid "ProductAnalytics|Compares feature usage of all features against each other"
msgstr ""
-msgid "ProductAnalytics|Compares pageviews of all pages against each other"
-msgstr ""
-
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Data"
+msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
-msgid "ProductAnalytics|Data Table"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr ""
-msgid "ProductAnalytics|Edit"
-msgstr ""
-
msgid "ProductAnalytics|Event Type"
msgstr ""
@@ -32181,22 +32662,31 @@ msgstr ""
msgid "ProductAnalytics|Events over time"
msgstr ""
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr ""
-msgid "ProductAnalytics|Feature usage"
+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|Host"
+msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
-msgid "ProductAnalytics|Language"
+msgid "ProductAnalytics|How often sessions are repeated"
msgstr ""
-msgid "ProductAnalytics|Line Chart"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Instrumentation details"
msgstr ""
msgid "ProductAnalytics|Measure All tracked Events"
@@ -32205,70 +32695,73 @@ msgstr ""
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr ""
-msgid "ProductAnalytics|Measuring"
+msgid "ProductAnalytics|Measure all sessions"
msgstr ""
-msgid "ProductAnalytics|New Analytics Panel Title"
+msgid "ProductAnalytics|Measure by unique users"
msgstr ""
-msgid "ProductAnalytics|OS"
+msgid "ProductAnalytics|Measuring"
msgstr ""
-msgid "ProductAnalytics|OS Version"
+msgid "ProductAnalytics|On what do you want to get insights?"
msgstr ""
-msgid "ProductAnalytics|On what do you want to get insights?"
+msgid "ProductAnalytics|Page Views"
msgstr ""
-msgid "ProductAnalytics|Page Language"
+msgid "ProductAnalytics|Repeat Visit Percentage"
msgstr ""
-msgid "ProductAnalytics|Page Path"
+msgid "ProductAnalytics|SDK App ID"
msgstr ""
-msgid "ProductAnalytics|Page Title"
+msgid "ProductAnalytics|SDK Host"
msgstr ""
-msgid "ProductAnalytics|Page Views"
+msgid "ProductAnalytics|Sessions"
msgstr ""
-msgid "ProductAnalytics|Pages"
+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|Panel"
+msgid "ProductAnalytics|Set up product analytics"
msgstr ""
-msgid "ProductAnalytics|Product analytics dashboards"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
msgstr ""
-msgid "ProductAnalytics|Referer"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
msgstr ""
-msgid "ProductAnalytics|Resulting Data"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
msgstr ""
-msgid "ProductAnalytics|Single Statistic"
+msgid "ProductAnalytics|The host to send all tracking events to"
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|Track specific features"
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
msgstr ""
-msgid "ProductAnalytics|URL"
+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|User activity"
+msgid "ProductAnalytics|Track specific features"
msgstr ""
-msgid "ProductAnalytics|Users"
+msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Viewport"
+msgid "ProductAnalytics|User Sessions"
msgstr ""
-msgid "ProductAnalytics|Visualization Type"
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
msgstr ""
msgid "ProductAnalytics|What do you want to measure?"
@@ -32436,6 +32929,12 @@ 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|Do not show on profile"
msgstr ""
@@ -32685,7 +33184,7 @@ msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+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"
@@ -32859,6 +33358,9 @@ msgstr ""
msgid "Project milestone"
msgstr ""
+msgid "Project must have default branch"
+msgstr ""
+
msgid "Project name"
msgstr ""
@@ -32871,6 +33373,9 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr ""
@@ -32898,6 +33403,9 @@ 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 ""
@@ -32994,9 +33502,21 @@ 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 ""
@@ -33009,6 +33529,9 @@ msgstr ""
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr ""
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr ""
@@ -33051,7 +33574,10 @@ 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 "ProjectSelect| or group"
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
@@ -33066,9 +33592,6 @@ msgstr ""
msgid "ProjectSelect|Select a project"
msgstr ""
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr ""
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr ""
@@ -33198,9 +33721,6 @@ msgstr ""
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
-msgid "ProjectSettings|All threads must be resolved"
-msgstr ""
-
msgid "ProjectSettings|Allow"
msgstr ""
@@ -33351,9 +33871,6 @@ msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr ""
-
msgid "ProjectSettings|Issues"
msgstr ""
@@ -33396,9 +33913,6 @@ 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't be merged if the latest pipeline did not succeed or is still running."
-msgstr ""
-
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -33435,9 +33949,6 @@ msgstr ""
msgid "ProjectSettings|Pages for project documentation."
msgstr ""
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr ""
@@ -33480,10 +33991,10 @@ msgstr ""
msgid "ProjectSettings|Search for topic"
msgstr ""
-msgid "ProjectSettings|Security & Compliance"
+msgid "ProjectSettings|Security and Compliance"
msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
+msgid "ProjectSettings|Security and compliance for this project."
msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
@@ -33507,9 +34018,6 @@ msgstr ""
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr ""
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
-
msgid "ProjectSettings|Snippets"
msgstr ""
@@ -33744,6 +34252,9 @@ msgstr ""
msgid "Projects API"
msgstr ""
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -33870,6 +34381,9 @@ 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 ""
@@ -33885,6 +34399,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -34065,9 +34582,6 @@ msgstr ""
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr ""
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr ""
@@ -34176,12 +34690,6 @@ msgstr ""
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
-msgid "Promotions|description templates"
-msgstr ""
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr ""
-
msgid "Prompt users to upload SSH keys"
msgstr ""
@@ -34353,9 +34861,23 @@ msgstr ""
msgid "ProtectedBranch|default"
msgstr ""
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
msgstr ""
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
msgid "ProtectedEnvironments|Allowed to deploy"
msgstr ""
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr ""
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr ""
+
msgid "ProtectedEnvironments|Users"
msgstr ""
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -34395,6 +34938,9 @@ msgstr ""
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr ""
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr ""
@@ -34851,24 +35397,15 @@ msgstr ""
msgid "Reauthenticating with SAML provider."
msgstr ""
-msgid "Rebase"
-msgstr ""
-
msgid "Rebase completed"
msgstr ""
-msgid "Rebase in progress"
-msgstr ""
-
msgid "Rebase source branch"
msgstr ""
msgid "Rebase source branch on the target branch."
msgstr ""
-msgid "Rebase without pipeline"
-msgstr ""
-
msgid "Recaptcha verified?"
msgstr ""
@@ -34944,6 +35481,9 @@ 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] ""
@@ -34978,13 +35518,13 @@ msgstr ""
msgid "Register / Sign In"
msgstr ""
-msgid "Register Two-Factor Authenticator"
+msgid "Register a WebAuthn device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register a one-time password authenticator"
msgstr ""
-msgid "Register WebAuthn Device"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
msgstr ""
msgid "Register device"
@@ -35077,6 +35617,9 @@ msgstr ""
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr ""
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr ""
@@ -36005,15 +36548,21 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
-msgid "Requirement title cannot have more than %{limit} characters."
-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] ""
@@ -36190,9 +36739,6 @@ msgstr ""
msgid "Resume"
msgstr ""
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr ""
-
msgid "Retry"
msgstr ""
@@ -36360,9 +36906,6 @@ msgstr ""
msgid "Run job"
msgstr ""
-msgid "Run manual job again"
-msgstr ""
-
msgid "Run manual or delayed jobs"
msgstr ""
@@ -36433,6 +36976,9 @@ 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|Administrator"
msgstr ""
@@ -36496,6 +37042,9 @@ 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 ""
@@ -36514,6 +37063,9 @@ 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 ""
@@ -36569,9 +37121,15 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr ""
@@ -36584,6 +37142,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr ""
@@ -36602,6 +37166,9 @@ msgstr ""
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr ""
@@ -36629,6 +37196,12 @@ msgstr ""
msgid "Runners|Maintenance note"
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 ""
@@ -36638,6 +37211,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -36650,6 +37226,9 @@ msgstr ""
msgid "Runners|Never expires"
msgstr ""
+msgid "Runners|New"
+msgstr ""
+
msgid "Runners|New group runners can be registered"
msgstr ""
@@ -36692,6 +37271,9 @@ msgstr ""
msgid "Runners|Operating systems"
msgstr ""
+msgid "Runners|Optional. Step 3"
+msgstr ""
+
msgid "Runners|Owner"
msgstr ""
@@ -36723,6 +37305,12 @@ msgstr ""
msgid "Runners|Recommended"
msgstr ""
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr ""
@@ -36738,6 +37326,9 @@ 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 ""
@@ -36762,6 +37353,9 @@ msgstr ""
msgid "Runners|Runner %{name} was deleted"
msgstr ""
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Runners|Runner Registration"
msgstr ""
@@ -36777,6 +37371,12 @@ 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 ""
@@ -36849,9 +37449,15 @@ 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 ""
@@ -36885,6 +37491,12 @@ msgstr ""
msgid "Runners|Status"
msgstr ""
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr ""
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr ""
@@ -36910,6 +37525,9 @@ msgstr[0] ""
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 runner has not run any jobs."
msgstr ""
@@ -36958,6 +37576,9 @@ 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 runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
@@ -37012,15 +37633,6 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
-msgid "Runner|New"
-msgstr ""
-
-msgid "Runner|Owner"
-msgstr ""
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr ""
-
msgid "Running"
msgstr ""
@@ -37042,6 +37654,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr ""
@@ -37066,9 +37681,6 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
-msgid "SAST Configuration"
-msgstr ""
-
msgid "SCIM|SCIM Token"
msgstr ""
@@ -37198,16 +37810,19 @@ msgstr ""
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
@@ -37249,9 +37864,15 @@ msgstr ""
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr ""
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr ""
@@ -37689,22 +38310,25 @@ msgstr ""
msgid "Security"
msgstr ""
-msgid "Security & Compliance"
+msgid "Security Dashboard"
msgstr ""
-msgid "Security Configuration"
+msgid "Security Finding not found"
msgstr ""
-msgid "Security Dashboard"
+msgid "Security Policy project already exists."
msgstr ""
-msgid "Security Finding not found"
+msgid "Security and Compliance"
msgstr ""
-msgid "Security dashboard"
+msgid "Security capabilities"
msgstr ""
-msgid "Security navigation"
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
msgstr ""
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
@@ -37833,7 +38457,7 @@ msgstr ""
msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST configuration"
msgstr ""
msgid "SecurityConfiguration|Secure your project"
@@ -37947,6 +38571,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose approver type"
msgstr ""
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -38052,9 +38679,18 @@ msgstr ""
msgid "SecurityOrchestration|No description"
msgstr ""
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
+msgid "SecurityOrchestration|No tags available"
+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 ""
@@ -38145,6 +38781,9 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
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 ""
@@ -38166,6 +38805,9 @@ msgstr ""
msgid "SecurityOrchestration|Select policy"
msgstr ""
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr ""
@@ -38175,6 +38817,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -38241,7 +38886,7 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+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."
@@ -38319,6 +38964,9 @@ msgstr ""
msgid "SecurityReports|Activity"
msgstr ""
+msgid "SecurityReports|Add comment and 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 ""
@@ -38796,6 +39444,9 @@ msgstr ""
msgid "Select labels"
msgstr ""
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr ""
@@ -38898,6 +39549,9 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
@@ -38910,6 +39564,9 @@ msgstr ""
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr ""
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr ""
@@ -38922,6 +39579,9 @@ msgstr ""
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr ""
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr ""
@@ -39159,6 +39825,9 @@ 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 ""
@@ -39186,7 +39855,7 @@ msgstr ""
msgid "Set up a %{type} runner for a project"
msgstr ""
-msgid "Set up a hardware device as a second factor to sign in."
+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}"
@@ -39436,6 +40105,9 @@ msgstr ""
msgid "Show filters"
msgstr ""
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr ""
@@ -39599,9 +40271,6 @@ msgstr ""
msgid "Sign in"
msgstr ""
-msgid "Sign in / Register"
-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 ""
@@ -39755,15 +40424,33 @@ 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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr ""
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr ""
msgid "SlackIntegration|Client secret"
msgstr ""
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr ""
@@ -39773,6 +40460,9 @@ msgstr ""
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr ""
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -39782,6 +40472,9 @@ 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 ""
@@ -39815,9 +40508,15 @@ 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|cannot have more than %{limit} channels"
+msgstr ""
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr ""
@@ -40001,12 +40700,18 @@ 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 ""
@@ -40418,9 +41123,6 @@ msgstr ""
msgid "SourceEditor|No extension for unuse has been specified."
msgstr ""
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr ""
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr ""
@@ -40484,6 +41186,9 @@ msgstr ""
msgid "Spam log successfully submitted as ham."
msgstr ""
+msgid "Specific branches"
+msgstr ""
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr ""
@@ -40733,6 +41438,9 @@ msgstr ""
msgid "StatusCheck|Service name"
msgstr ""
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr ""
@@ -41378,16 +42086,22 @@ 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|Sync subscription request."
+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}."
@@ -41396,7 +42110,7 @@ msgstr ""
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr ""
-msgid "SuperSonics|There is a connectivity issue."
+msgid "SuperSonics|There is a connectivity issue"
msgstr ""
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
@@ -41424,9 +42138,6 @@ 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 no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr ""
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
@@ -41469,9 +42180,6 @@ msgstr ""
msgid "SuperSonics|Your subscription cannot be located"
msgstr ""
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr ""
-
msgid "SuperSonics|Your subscription is expired"
msgstr ""
@@ -41622,9 +42330,27 @@ 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 ""
@@ -42029,10 +42755,10 @@ msgstr ""
msgid "Test"
msgstr ""
-msgid "Test Cases"
+msgid "Test case"
msgstr ""
-msgid "Test case"
+msgid "Test cases"
msgstr ""
msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
@@ -42052,9 +42778,6 @@ msgstr ""
msgid "TestCases|Moving test case"
msgstr ""
-msgid "TestCases|New Test Case"
-msgstr ""
-
msgid "TestCases|New test case"
msgstr ""
@@ -42181,6 +42904,9 @@ 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 ""
@@ -42239,6 +42965,9 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
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 ""
@@ -42281,9 +43010,6 @@ 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 compliance report shows the merge request violations merged in protected environments."
-msgstr ""
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -42341,6 +43067,9 @@ 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 ""
@@ -42652,7 +43381,16 @@ msgstr ""
msgid "The scan has been created."
msgstr ""
-msgid "The secret is only available when you first create the application."
+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."
@@ -42997,6 +43735,9 @@ msgstr ""
msgid "There was an error fetching the jobs for your project."
msgstr ""
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr ""
@@ -43186,13 +43927,7 @@ 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 %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr ""
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
+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"
@@ -43693,6 +44428,9 @@ msgstr ""
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr ""
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -43747,10 +44485,7 @@ msgstr ""
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
-msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
-
-msgid "This will invalidate your registered applications and U2F devices."
+msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr ""
msgid "This will remove the fork relationship between this project and %{fork_source}."
@@ -44199,6 +44934,9 @@ 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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr ""
@@ -44684,6 +45422,9 @@ 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 ""
@@ -44772,9 +45513,6 @@ msgstr ""
msgid "Trigger job"
msgstr ""
-msgid "Trigger manual job"
-msgstr ""
-
msgid "Trigger pipelines for mirror updates"
msgstr ""
@@ -44877,9 +45615,6 @@ msgstr ""
msgid "Two-Factor Authentication"
msgstr ""
-msgid "Two-Factor Authentication code"
-msgstr ""
-
msgid "Two-factor Authentication"
msgstr ""
@@ -44925,12 +45660,6 @@ msgstr ""
msgid "Type to search"
msgstr ""
-msgid "U2F Devices (%{length})"
-msgstr ""
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
-
msgid "URL"
msgstr ""
@@ -45036,6 +45765,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
@@ -45135,6 +45867,9 @@ msgstr ""
msgid "Unban"
msgstr ""
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr ""
@@ -45192,6 +45927,15 @@ msgstr ""
msgid "Unlimited"
msgstr ""
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr ""
@@ -45279,6 +46023,9 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
+msgid "Untitled"
+msgstr ""
+
msgid "Unused"
msgstr ""
@@ -45348,6 +46095,9 @@ 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 ""
@@ -45474,6 +46224,9 @@ msgstr ""
msgid "Usage statistics"
msgstr ""
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr ""
@@ -45645,6 +46398,9 @@ msgstr ""
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr ""
@@ -45849,6 +46605,9 @@ 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 ""
@@ -45861,6 +46620,9 @@ 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 ""
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr ""
@@ -46360,6 +47125,9 @@ msgstr ""
msgid "Value Streams Dashboard (Beta)"
msgstr ""
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr ""
@@ -46471,6 +47239,9 @@ msgstr ""
msgid "ValueStreamEvent|Items in stage"
msgstr ""
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr ""
@@ -46615,6 +47386,9 @@ msgstr ""
msgid "View blame"
msgstr ""
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
@@ -46643,9 +47417,6 @@ msgstr ""
msgid "View eligible approvers"
msgstr ""
-msgid "View entire blame"
-msgstr ""
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] ""
@@ -46846,6 +47617,69 @@ 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|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 ""
@@ -47236,12 +48070,6 @@ msgstr ""
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr ""
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr ""
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
@@ -47293,9 +48121,6 @@ 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 continuously validate your pipeline configuration. The validation results will appear here."
-msgstr ""
-
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
@@ -47437,6 +48262,9 @@ 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 ""
@@ -47699,6 +48527,10 @@ 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] ""
+
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] ""
@@ -47736,6 +48568,9 @@ msgstr ""
msgid "Why are you signing up? (optional)"
msgstr ""
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr ""
@@ -47955,7 +48790,7 @@ msgstr ""
msgid "Work in progress (open and unassigned)"
msgstr ""
-msgid "Work in progress Limit"
+msgid "Work in progress limit"
msgstr ""
msgid "WorkItem|%{count} more assignees"
@@ -48003,6 +48838,9 @@ msgstr ""
msgid "WorkItem|Add to milestone"
msgstr ""
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -48025,6 +48863,15 @@ msgstr ""
msgid "WorkItem|Closed"
msgstr ""
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
msgid "WorkItem|Create %{workItemType}"
msgstr ""
@@ -48049,9 +48896,15 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr ""
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr ""
@@ -48172,6 +49025,9 @@ msgstr ""
msgid "WorkItem|Task deleted"
msgstr ""
+msgid "WorkItem|Task reverted"
+msgstr ""
+
msgid "WorkItem|Tasks"
msgstr ""
@@ -48208,6 +49064,9 @@ msgstr ""
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr ""
@@ -48238,6 +49097,9 @@ msgstr ""
msgid "Write milestone description..."
msgstr ""
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -48638,9 +49500,6 @@ msgstr ""
msgid "You do not have permissions to run the import."
msgstr ""
-msgid "You don't have any U2F devices registered yet."
-msgstr ""
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
@@ -48810,12 +49669,18 @@ 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 ""
@@ -48985,6 +49850,9 @@ 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 ""
@@ -48994,7 +49862,7 @@ 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 %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+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 import for project"
@@ -49024,6 +49892,9 @@ 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 ""
@@ -49048,6 +49919,9 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
msgid "Your To-Do List"
msgstr ""
@@ -49093,6 +49967,9 @@ msgstr ""
msgid "Your action succeeded."
msgstr ""
+msgid "Your activity"
+msgstr ""
+
msgid "Your applications (%{size})"
msgstr ""
@@ -49102,9 +49979,6 @@ msgstr ""
msgid "Your browser does not support iFrames"
msgstr ""
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -49135,6 +50009,9 @@ msgstr ""
msgid "Your commit email is used for web based operations, such as edits and merges."
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 ""
@@ -49290,6 +50167,9 @@ msgstr ""
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr ""
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr ""
@@ -49524,6 +50404,9 @@ 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 ""
@@ -49848,9 +50731,6 @@ msgstr ""
msgid "ciReport|Generic Report"
msgstr ""
-msgid "ciReport|IaC Scanning"
-msgstr ""
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
@@ -49915,6 +50795,9 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr ""
@@ -49945,6 +50828,9 @@ 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 ""
@@ -50217,9 +51103,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "following"
-msgstr ""
-
msgid "for"
msgstr ""
@@ -50521,10 +51404,16 @@ msgstr ""
msgid "manual"
msgstr ""
-msgid "math|Displaying this math block may cause performance issues on this page"
+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|There was an error rendering this math block"
+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"
@@ -50580,6 +51469,84 @@ 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|%{mergeError}."
msgstr ""
@@ -50595,6 +51562,12 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
@@ -50622,12 +51595,6 @@ msgstr ""
msgid "mrWidget|Approval password is invalid."
msgstr ""
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr ""
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr ""
-
msgid "mrWidget|Approve"
msgstr ""
@@ -50643,6 +51610,9 @@ 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 ""
@@ -50720,82 +51690,28 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr ""
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr ""
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr ""
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr ""
-
msgid "mrWidget|Merge failed."
msgstr ""
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr ""
-
msgid "mrWidget|Merged by"
msgstr ""
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr ""
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr ""
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr ""
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr ""
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr ""
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr ""
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr ""
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr ""
-
-msgid "mrWidget|Merging! We're almost there…"
+msgid "mrWidget|More information"
msgstr ""
-msgid "mrWidget|More information"
+msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr ""
-msgid "mrWidget|No users match the rule's criteria."
+msgid "mrWidget|Rebase"
msgstr ""
-msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgid "mrWidget|Rebase in progress"
msgstr ""
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
+msgid "mrWidget|Rebase without pipeline"
msgstr ""
msgid "mrWidget|Refresh"
@@ -50858,9 +51774,6 @@ msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
-
msgid "mrWidget|What is a merge train?"
msgstr ""
@@ -50885,6 +51798,9 @@ msgstr ""
msgid "must be a valid json schema"
msgstr ""
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
msgid "must be after start"
msgstr ""
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index 0626b605117..86642363396 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-02-11 04:21\n"
+"PO-Revision-Date: 2023-03-11 10:32\n"
msgid " %{start} to %{end}"
msgstr " %{start} 到 %{end}"
@@ -356,6 +356,10 @@ msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
msgstr[0] "%d 個未解決話題"
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] "%d 版本"
+
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
msgstr[0] "%d 個æ¼æ´ž"
@@ -384,10 +388,20 @@ msgid "%d warning found:"
msgid_plural "%d warnings found:"
msgstr[0] "找到 %d 個警告:"
+msgid "%d work item"
+msgid_plural "%d work items"
+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 "%{actionText} %{actionDetail}"
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr "%{actionText} %{actionDetail} %{timeago} ç”± %{author}"
+
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} 和 %{openOrClose} %{noteable}"
@@ -539,6 +553,9 @@ msgstr "%{count} 個相關的 %{pluralized_subject}:%{links}"
msgid "%{count} selected"
msgstr "å·²é¸å– %{count} 個"
+msgid "%{count} tags"
+msgstr "%{count} 個標籤"
+
msgid "%{count} total weight"
msgstr "ç¸½æ¬Šé‡ %{count}"
@@ -740,6 +757,9 @@ msgstr "由於分å‰ï¼ˆFork)的來æºå°ˆæ¡ˆå¯è¦‹æ€§è¼ƒä½Žï¼Œå› æ­¤ä¸å…許ä½
msgid "%{linkStart} Learn more%{linkEnd}."
msgstr "%{linkStart} 了解更多 %{linkEnd}。"
+msgid "%{linkStart}Approval settings%{linkEnd} prevent approvals by its eligible approvers."
+msgstr "%{linkStart}核准設定%{linkEnd} 阻擋了符åˆæ¢ä»¶çš„核准者批核。"
+
msgid "%{listToShow}, and %{awardsListLength} more"
msgstr "%{listToShow}個,還有 %{awardsListLength} 個。"
@@ -755,9 +775,6 @@ msgstr "%{mergeLength}/%{usersLength} å¯ä»¥åˆä½µ"
msgid "%{message} showing first %{warnings_displayed}"
msgstr "%{message} 顯示第一個 %{warnings_displayed}"
-msgid "%{message}. Your attention request was removed."
-msgstr "%{message}. 您的關注請求已被移除。"
-
msgid "%{milestone} (expired)"
msgstr "%{milestone} (å·²éŽæœŸ)"
@@ -889,6 +906,9 @@ msgstr "%{reportType}檢測到%{totalStart}%{total}%{totalEnd}個潛在的%{vuln
msgid "%{reportType} detected no new vulnerabilities."
msgstr "%{reportType} 未檢測到新的æ¼æ´žã€‚"
+msgid "%{reported} reported for %{category} by %{reporter}"
+msgstr "%{reported} 被 %{reporter} 報告為 %{category}"
+
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] "%{requireStart}需è¦%{requireEnd} %{approvalsRequired} %{approvalStart}核準%{approvalEnd},來自:"
@@ -1000,7 +1020,7 @@ msgstr[0] "%{strong_start}%{count}ä½æˆå“¡%{strong_end}需核准æ‰å¯åˆä½µã€‚
msgid "%{strong_start}%{count}%{strong_end} Environment"
msgid_plural "%{strong_start}%{count}%{strong_end} Environments"
-msgstr[0] ""
+msgstr[0] "%{strong_start}%{count}%{strong_end} 環境"
msgid "%{strong_start}%{errors}%{strong_end} %{prefix} finding"
msgid_plural "%{strong_start}%{errors}%{strong_end} %{prefix} findings"
@@ -1116,6 +1136,9 @@ msgstr "%{user} 建立了å²è©© (epic): %{epic_link}"
msgid "%{user} created an issue: %{issue_link}"
msgstr "%{user} 建立了一個議題: %{issue_link}"
+msgid "%{user} user’s menu"
+msgstr "%{user} 使用者é¸å–®"
+
msgid "%{value} is not included in the list"
msgstr "%{value} 未包å«åœ¨åˆ—表中"
@@ -1381,10 +1404,6 @@ msgid "1 deploy key"
msgid_plural "%d deploy keys"
msgstr[0] "%d 個部署金鑰"
-msgid "1 follower"
-msgid_plural "%{count} followers"
-msgstr[0] "%{count} ä½é—œæ³¨è€…"
-
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%d 個群組"
@@ -1675,9 +1694,6 @@ msgstr "API"
msgid "API Fuzzing"
msgstr "API 模糊測試"
-msgid "API Fuzzing Configuration"
-msgstr "API 模糊測試é…ç½®"
-
msgid "API Help"
msgstr "API 說明"
@@ -2092,9 +2108,6 @@ msgstr "增加清單"
msgid "Add a collapsible section"
msgstr "加入å¯ç¸®åˆå€å¡Šã€‚"
-msgid "Add a comment"
-msgstr "增加評論"
-
msgid "Add a comment to this line"
msgstr "在此行新增評論"
@@ -2116,6 +2129,9 @@ msgstr "在 wiki 中加入首é ï¼Œå…¶ä¸­åŒ…å«æœ‰é—œå°ˆæ¡ˆçš„資訊,GitLab å°
msgid "Add a new issue"
msgstr "建立議題"
+msgid "Add a new saved reply"
+msgstr "增加一個新的已ä¿å­˜å›žå¾©"
+
msgid "Add a numbered list"
msgstr "加入編號列表"
@@ -2125,6 +2141,9 @@ msgstr "新增相關å²è©© (epic) "
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 "為æœå‹™å°é›»å­éƒµä»¶åœ°å€æ·»åŠ å¾Œç¶´ã€‚ %{linkStart}了解詳情。%{linkEnd}"
@@ -2239,6 +2258,9 @@ msgstr "新增應用程å¼"
msgid "Add new directory"
msgstr "新增目錄"
+msgid "Add new saved reply"
+msgstr "加入新的已儲存回復"
+
msgid "Add or remove a user."
msgstr "新增或移除使用者。"
@@ -2377,6 +2399,9 @@ msgstr "é¡å¤–的分é˜æ•¸ï¼š"
msgid "Additional text"
msgstr "附加文字"
+msgid "Additional text for deactivation email"
+msgstr "åœç”¨é›»å­éƒµä»¶çš„附加文字"
+
msgid "Additional text for the sign-in and Help page."
msgstr "登入åŠèªªæ˜Žé é¢çš„é¡å¤–文字。"
@@ -2792,13 +2817,13 @@ msgid "AdminSettings|If not specified at the group or instance level, the defaul
msgstr "如果沒有在群組或實例級別指定,則é è¨­ç‚º %{default_initial_branch_name}。這ä¸æœƒå½±éŸ¿ç¾æœ‰çš„檔案庫。"
msgid "AdminSettings|If selected, only administrators are able to create internal groups, projects, and snippets."
-msgstr ""
+msgstr "如果é¸å–,則åªæœ‰ç®¡ç†å“¡èƒ½å¤ å»ºç«‹å…§éƒ¨ç¾¤çµ„ã€å°ˆæ¡ˆå’Œç¨‹å¼ç¢¼ç‰‡æ®µã€‚"
msgid "AdminSettings|If selected, only administrators are able to create private groups, projects, and snippets."
-msgstr ""
+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 ""
+msgstr "如果é¸å–,則åªæœ‰ç®¡ç†å“¡èƒ½å¤ å»ºç«‹å…¬å…±ç¾¤çµ„ã€å°ˆæ¡ˆå’Œç¨‹å¼ç¢¼ç‰‡æ®µã€‚此外,個人資料僅å°ç¶“éŽèº«ä»½é©—證的使用者å¯è¦‹ã€‚"
msgid "AdminSettings|If there isn't any existing index, GitLab creates one."
msgstr "如果沒有任何ç¾æœ‰ç´¢å¼•ï¼ŒGitLab 會建立一個。"
@@ -2882,7 +2907,7 @@ msgid "AdminSettings|Pause Elasticsearch indexing"
msgstr "æš«åœ Elasticsearch 索引建立"
msgid "AdminSettings|Prevent non-administrators from using the selected visibility levels for groups, projects and snippets."
-msgstr ""
+msgstr "防止éžç®¡ç†è€…å°ç¾¤çµ„ã€å°ˆæ¡ˆå’Œç¨‹å¼ç¢¼ç‰‡æ®µä½¿ç”¨å·²é¸å–çš„çš„å¯è¦‹æ€§ç´šåˆ¥ã€‚"
msgid "AdminSettings|Preview payload"
msgstr "負載é è¦½"
@@ -2912,7 +2937,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 "儲存 %{name} é™åˆ¶"
@@ -3368,10 +3393,10 @@ msgid "AdminUsers|Unban user %{username}?"
msgstr "是å¦è§£é™¤ %{username} çš„å°éŽ–?"
msgid "AdminUsers|Unblock"
-msgstr "å–消阻止"
+msgstr "解鎖"
msgid "AdminUsers|Unblock user %{username}?"
-msgstr "å–消阻止使用者 %{username}?"
+msgstr "解鎖使用者 %{username}?"
msgid "AdminUsers|Unlock user %{username}?"
msgstr "是å¦è§£é™¤ %{username} çš„å°éŽ–?"
@@ -3556,42 +3581,12 @@ msgstr "å•Ÿå‹• App Store Connect æ•´åˆå¾Œï¼Œå°‡æœƒå»ºç«‹ä»¥ä¸‹å—ä¿è­·çš„變æ•
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 "匯出完æˆå¾Œï¼Œå¾žé€šçŸ¥é›»å­éƒµä»¶æˆ–æ­¤é é¢ä¸‹è¼‰æ•¸æ“šæ–‡ä»¶ã€‚然後,您å¯ä»¥å¾žå¦ä¸€å€‹ GitLab 實例的 %{strong_text_start}建立新群組%{strong_text_end} é é¢åŒ¯å…¥æ•¸æ“šæ–‡ä»¶ã€‚"
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
+msgstr "啟用整åˆå¾Œï¼Œå°‡å»ºç«‹ä¸‹åˆ—å—ä¿è­·è®Šæ•¸ä¾› CI/CD 使用:"
+
msgid "After you've reviewed these contribution guidelines, you'll be all set to"
msgstr "在閱讀這些貢ç»æŒ‡å—後,您將準備好"
-msgid "Airflow"
-msgstr ""
-
-msgid "Airflow|Airflow DAGs"
-msgstr ""
-
-msgid "Airflow|DAG"
-msgstr ""
-
-msgid "Airflow|DAG file location"
-msgstr ""
-
-msgid "Airflow|Either the Airflow instance does not contain DAGs or has yet to be configured"
-msgstr ""
-
-msgid "Airflow|GitLab Airflow integration"
-msgstr ""
-
-msgid "Airflow|Is active"
-msgstr ""
-
-msgid "Airflow|Is paused"
-msgstr ""
-
-msgid "Airflow|Next run"
-msgstr ""
-
-msgid "Airflow|Schedule"
-msgstr ""
-
-msgid "Airflow|There are no DAGs to show"
-msgstr ""
-
msgid "Akismet"
msgstr "Akismet"
@@ -3961,6 +3956,9 @@ msgstr "全部 GitLab"
msgid "All Members"
msgstr "全部æˆå“¡"
+msgid "All branch names must match %{link_start}this regular expression%{link_end}. If empty, any branch name is allowed."
+msgstr "所有分支åç¨±å¿…é ˆç¬¦åˆ %{link_start}該正則表é”å¼%{link_end}。如果為空,則å…許使用任æ„分支å稱。"
+
msgid "All branches"
msgstr "全部分支"
@@ -4587,6 +4585,9 @@ 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 "載入圖片時發生錯誤"
@@ -4596,6 +4597,123 @@ msgstr "發生未知的錯誤"
msgid "Analytics"
msgstr "分æž"
+msgid "Analytics|Add to Dashboard"
+msgstr "加入到儀表æ¿"
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr "載入視覺化 %{visualizationTitle} 時發生錯誤。"
+
+msgid "Analytics|Analytics dashboards"
+msgstr "分æžå„€è¡¨æ¿"
+
+msgid "Analytics|Browser"
+msgstr "ç€è¦½å™¨"
+
+msgid "Analytics|Browser Family"
+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|Configure Dashboard Project"
+msgstr "é…置儀表æ¿å°ˆæ¡ˆ"
+
+msgid "Analytics|Custom dashboards"
+msgstr "客製儀表æ¿"
+
+msgid "Analytics|Dashboard Title"
+msgstr "儀表æ¿æ¨™é¡Œ"
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr "儀表æ¿å·²æˆåŠŸå„²å­˜"
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr "儀表æ¿æ˜¯é€éŽç·¨è¼¯å°ˆæ¡ˆå„€è¡¨æ¿æª”案建立的。"
+
+msgid "Analytics|Data"
+msgstr "資料"
+
+msgid "Analytics|Data Table"
+msgstr "資料表格"
+
+msgid "Analytics|Edit"
+msgstr "編輯"
+
+msgid "Analytics|Error while saving Dashboard!"
+msgstr "儲存儀表æ¿æ™‚發生錯誤ï¼"
+
+msgid "Analytics|For being able to create your own dashboards please configure a special project to store your dashboards."
+msgstr "為了能夠建立您自己的儀表æ¿ï¼Œè«‹é…置一個特定專案來儲存您的儀表æ¿ã€‚"
+
+msgid "Analytics|Host"
+msgstr "主機"
+
+msgid "Analytics|Language"
+msgstr "語言"
+
+msgid "Analytics|Line Chart"
+msgstr "折線圖"
+
+msgid "Analytics|New Analytics Visualization Title"
+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"
+msgstr "儲存"
+
+msgid "Analytics|Single Statistic"
+msgstr "單一統計"
+
+msgid "Analytics|URL"
+msgstr "URL"
+
+msgid "Analytics|Updating dashboard %{dashboardId}"
+msgstr "æ›´æ–°å„€è¡¨æ¿ %{dashboardId}"
+
+msgid "Analytics|Users"
+msgstr "使用者"
+
+msgid "Analytics|Viewport"
+msgstr "視å£"
+
+msgid "Analytics|Visualization"
+msgstr "視覺化"
+
+msgid "Analytics|Visualization Designer"
+msgstr "視覺化設計師"
+
+msgid "Analytics|Visualization Type"
+msgstr "視覺化類型"
+
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "分æžå·²çŸ¥æ¼æ´žçš„ä¾è³´é—œä¿‚"
@@ -4674,14 +4792,29 @@ msgstr "添加 %{shrug} 到留言"
msgid "Append the comment with %{tableflip}"
msgstr "添加 %{tableflip} 到留言"
+msgid "AppleAppStore|Drag your Private Key file here or %{linkStart}click to upload%{linkEnd}."
+msgstr "將您的ç§é‘°æ–‡ä»¶æ‹–放到此處或 %{linkStart}單擊上傳%{linkEnd}。"
+
+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|The Apple App Store Connect Issuer ID."
msgstr "Apple App Store Connect 發行者 ID。"
msgid "AppleAppStore|The Apple App Store Connect Key ID."
msgstr "Apple App Store Connect 金鑰 ID。"
-msgid "AppleAppStore|The Apple App Store Connect Private Key."
-msgstr "Apple App Store Connect ç§é‘°ã€‚"
+msgid "AppleAppStore|The Apple App Store Connect Private Key (.p8)"
+msgstr "Apple App Store 連çµç§é‘° (.p8)。"
+
+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 "使用 GitLab 以在 Apple App Store 中建構與釋出應用程å¼ã€‚"
@@ -4823,12 +4956,18 @@ msgstr "ä¿å­˜æ›´æ”¹"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "è«‹åƒé–±%{linkStart}密碼政策指å—%{linkEnd}。"
+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 "使用者註冊後顯示的文字內容。å¯ä»¥ä½¿ç”¨ Markdown。"
@@ -5063,11 +5202,15 @@ msgid "Approve"
msgstr "核准"
msgid "Approve All"
-msgstr ""
+msgstr "核淮全部"
msgid "Approve a merge request"
msgstr "核准åˆä½µè«‹æ±‚"
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] "核准 %d 個等待中的æˆå“¡"
+
msgid "Approve merge request"
msgstr "核准åˆä½µè«‹æ±‚"
@@ -5080,6 +5223,14 @@ msgstr "已核准"
msgid "Approved MRs"
msgstr "已核准的 MRs"
+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] ""
+
+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] ""
+
msgid "Approved the current merge request."
msgstr "核准了目å‰çš„åˆä½µè«‹æ±‚。"
@@ -5155,9 +5306,6 @@ msgstr "您確定è¦%{action}%{name}?"
msgid "Are you sure you want to approve %{user}?"
msgstr "您確定è¦æ ¸å‡†%{user}?"
-msgid "Are you sure you want to approve all users?"
-msgstr ""
-
msgid "Are you sure you want to attempt to merge?"
msgstr "您確定è¦å˜—試åˆä½µï¼Ÿ"
@@ -5170,6 +5318,9 @@ msgstr "您確定è¦é—œé–‰é€™å€‹è¢«å°é˜»çš„å•é¡Œå—Žï¼Ÿ"
msgid "Are you sure you want to delete %{name}?"
msgstr "您確定è¦åˆªé™¤ %{name}嗎?"
+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 "您確定è¦åˆªé™¤æ­¤ %{commentType} 嗎?"
@@ -5421,7 +5572,7 @@ msgid "Assign reviewer(s)"
msgstr "指派審核者"
msgid "Assign severity"
-msgstr "指派嚴é‡åº¦"
+msgstr "指定嚴é‡åº¦"
msgid "Assign some issues to this milestone."
msgstr "為此里程碑分é…一些議題。"
@@ -5518,8 +5669,8 @@ msgstr[0] "加入%d個附件"
msgid "Attaching the file failed."
msgstr "加入附件失敗。"
-msgid "Attempted sign in to %{host} using a wrong two-factor authentication code"
-msgstr "ä¼åœ–使用錯誤的雙因å­èº«ä»½é©—證碼登入 %{host}"
+msgid "Attempted sign in to %{host} using an incorrect verification code"
+msgstr "ä¼åœ–使用ä¸æ­£ç¢ºçš„驗證碼登入 %{host}"
msgid "Audit Events"
msgstr "審計事件"
@@ -5771,9 +5922,6 @@ msgstr "%{author}編寫於%{timeago}"
msgid "Authorization code:"
msgstr "授權碼:"
-msgid "Authorization required"
-msgstr "需è¦æŽˆæ¬Š"
-
msgid "Authorization token duration (minutes)"
msgstr "授權令牌(權æ–)期é™åˆ†é˜ï¼‰"
@@ -5786,9 +5934,6 @@ msgstr "授權"
msgid "Authorize %{link_to_client} to use your account?"
msgstr "授權 %{link_to_client} 使用您的帳號?"
-msgid "Authorize %{user} to use your account?"
-msgstr "授權 %{user} 使用您的帳號?"
-
msgid "Authorized %{new_chat_name}"
msgstr "已授權給 %{new_chat_name}"
@@ -5798,9 +5943,18 @@ msgstr "授權於"
msgid "Authorized applications (%{size})"
msgstr "å·²æŽˆæ¬Šæ‡‰ç”¨ç¨‹å¼ (%{size})"
+msgid "AuthorizedApplication|Application secret was successfully updated."
+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|Revoke application"
msgstr "èªè­‰æ‡‰ç”¨ç¨‹å¼|撤銷申請"
@@ -5907,10 +6061,10 @@ msgid "Automatically update this project's branches and tags from the upstream r
msgstr "從上游版本庫自動更新該專案的分支和標籤。"
msgid "Automation"
-msgstr ""
+msgstr "自動化"
msgid "Automation|Automation App"
-msgstr ""
+msgstr "自動化應用"
msgid "Autosave|Note"
msgstr "注æ„"
@@ -6182,6 +6336,9 @@ msgstr "請注æ„,變更項目的命å空間å¯èƒ½æœƒç”¢ç”Ÿéžé æœŸçš„副作
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "請注æ„,é‡æ–°å‘½å項目的版本庫å¯èƒ½æœƒç”¢ç”Ÿæ„想ä¸åˆ°çš„副作用。"
+msgid "Because you are over the %{free_user_limit} user limit, your top-level group, including any subgroups and projects, will be placed in a %{readonly_link_start}read-only state%{link_end} soon. To retain write access, reduce the number of users of your top-level group to %{free_user_limit} or less, or purchase a paid tier. To minimize the impact to your operations, GitLab is offering a %{promotion_link_start}one-time discount%{link_end} for a new purchase of a one-year subscription of GitLab Premium SaaS."
+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 "因為您啟用了自動ç¦æ­¢ï¼Œæˆ‘們也從 %{scope} 自動ç¦æ­¢è©²ä½¿ç”¨è€…。如果這是一個錯誤,您å¯ä»¥ %{link_start} 解ç¦ä»–們%{link_end}。"
@@ -6209,9 +6366,6 @@ msgstr "以下是 %{link_to_gitlab_pages}的設置。"
msgid "Below you will find all the groups that are public."
msgstr "您將在下é¢æ‰¾åˆ°æ‰€æœ‰å…¬é–‹çš„群組。"
-msgid "Beta"
-msgstr "測試版"
-
msgid "Bi-weekly code coverage"
msgstr "雙周代碼覆蓋率"
@@ -6281,6 +6435,9 @@ msgstr "ä¼æ¥­æ•æ·è¦åŠƒ"
msgid "BillingPlans|Faster code reviews"
msgstr "更快的程å¼ç¢¼å¯©æŸ¥"
+msgid "BillingPlans|Free"
+msgstr "å…è²»"
+
msgid "BillingPlans|Free forever features for individual users"
msgstr "個人使用者永久å…費功能"
@@ -6296,9 +6453,6 @@ msgstr "如果您想è¦é™ç´šæ‚¨çš„訂閱計劃,請è¯çµ¡%{support_link_start}
msgid "BillingPlans|Includes free static websites"
msgstr "包括å…費的éœæ…‹ç¶²ç«™"
-msgid "BillingPlans|Learn more"
-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 "計費計劃|閱讀我們的 %{faq_link}了解有關æ¯å€‹è¨ˆåŠƒçš„更多信æ¯ï¼Œæˆ–開始 GitLab.com Ultimate çš„ 30 天å…費試用。"
@@ -6375,7 +6529,7 @@ msgid "BillingPlans|Ultimate"
msgstr "旗艦級"
msgid "BillingPlans|Upgrade"
-msgstr ""
+msgstr "å‡ç´š"
msgid "BillingPlans|Upgrade to Premium"
msgstr "æå‡åˆ°é«˜ç´š"
@@ -6434,27 +6588,9 @@ msgstr "å‡ç´š"
msgid "BillingPlan|Upgrade for free"
msgstr "å…è²»å‡ç´š"
-msgid "Billings|%{planName} plan"
-msgstr "%{planName} 計劃"
-
-msgid "Billings|An error occurred while extending your trial."
-msgstr "延長試用期時發生錯誤。"
-
-msgid "Billings|An error occurred while reactivating your trial."
-msgstr "é‡æ–°å•Ÿç”¨æ‚¨çš„試用版時發生錯誤。"
-
-msgid "Billings|By extending your trial, you will receive an additional 30 days of %{planName}. Your trial can be only extended once."
-msgstr "通éŽå»¶é•·è©¦ç”¨æœŸï¼Œæ‚¨å°‡é¡å¤–ç²å¾— 30 天 %{planName}。您的試用期åªèƒ½å»¶é•·ä¸€æ¬¡ã€‚"
-
-msgid "Billings|By reactivating your trial, you will receive an additional 30 days of %{planName}. Your trial can be only reactivated once."
-msgstr "通éŽé‡æ–°å•Ÿç”¨æ‚¨çš„試用版,您將ç²å¾—é¡å¤–çš„ 30 天 %{planName}。您的試用版åªèƒ½é‡æ–°å•Ÿç”¨ä¸€æ¬¡ã€‚"
-
msgid "Billings|Error validating card details"
msgstr "é©—è­‰å¡ç‰‡è©³ç´°è³‡è¨ŠéŒ¯èª¤"
-msgid "Billings|Extend trial"
-msgstr "延長試用期"
-
msgid "Billings|Free groups are limited to %{number} seats."
msgstr "å…è²»ç¾¤çµ„åƒ…é™ %{number} 個席次"
@@ -6464,9 +6600,6 @@ msgstr "å…費版或試用版的群組æ¯å¤©æœ€å¤šåªèƒ½é‚€è«‹ 20 åæˆå“¡ã€‚"
msgid "Billings|In a seat"
msgstr "一個席次"
-msgid "Billings|Reactivate trial"
-msgstr "é‡æ–°é–‹å•Ÿè©¦ç”¨"
-
msgid "Billings|Seats in use / Seats available"
msgstr "使用中席次 / å¯ç”¨å¸­æ¬¡"
@@ -6504,7 +6637,7 @@ msgid "Billing|Add seats"
msgstr "增加度次"
msgid "Billing|All members were successfully approved"
-msgstr ""
+msgstr "所有æˆå“¡å‡å·²å¯©æ ¸æˆåŠŸ"
msgid "Billing|An email address is only visible for users with public emails."
msgstr "åªæœ‰æ“有公開電å­ä¿¡ç®±çš„用戶å¯ä»¥çœ‹è¦‹é›»å­éƒµä»¶åœ°å€ã€‚"
@@ -6513,7 +6646,7 @@ msgid "Billing|An error occurred while approving %{user}"
msgstr "核准 %{user} 時發生錯誤"
msgid "Billing|An error occurred while approving all members"
-msgstr ""
+msgstr "核准所有æˆå“¡æ™‚發生錯誤"
msgid "Billing|An error occurred while getting a billable member details."
msgstr "å–得計費會員詳細資訊時發生錯誤"
@@ -6606,6 +6739,9 @@ msgstr "從 Bitbucket 匯入"
msgid "Blame"
msgstr "責任歸屬(blame)"
+msgid "Blame could not be loaded as a single page."
+msgstr "Blame 無法以單é é¢è¼‰å…¥ã€‚"
+
msgid "BlobViewer|View on %{environmentName}"
msgstr "BlobViewer|在 %{environmentName}上檢視"
@@ -6825,15 +6961,27 @@ msgstr[0] "被 %{blockedByCount} %{issuableType}ç¦ç”¨"
msgid "Boards|Collapse"
msgstr "收起"
+msgid "Boards|Create new epic"
+msgstr "建立新å²è©© (epic)"
+
+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 "無法抓å–ç¦ç”¨çš„ %{issuableType}"
+msgid "Boards|List actions"
+msgstr "動作清單"
+
msgid "Boards|Move card"
msgstr "移動å¡ç‰‡"
@@ -6846,9 +6994,6 @@ msgstr "移動到列表的開頭"
msgid "Boards|New board"
msgstr "新建看æ¿"
-msgid "Boards|New epic"
-msgstr "新建å²è©© (epic) "
-
msgid "Boards|Retrieving blocking %{issuableType}s"
msgstr "正在å–回å°éŽ–中的%{issuableType}"
@@ -6958,17 +7103,14 @@ msgid "BranchRules|%{total} status %{subject}"
msgstr "%{total} 狀態 %{subject}"
msgid "BranchRules|Add branch rule"
-msgstr ""
+msgstr "增加分支è¦å‰‡"
msgid "BranchRules|After a protected branch is created, it will show up in the list as a branch rule."
-msgstr ""
+msgstr "建立å—ä¿è­·åˆ†æ”¯å¾Œï¼Œå®ƒå°‡ä½œç‚ºåˆ†æ”¯è¦å‰‡é¡¯ç¤ºåœ¨åˆ—表中"
msgid "BranchRules|All branches"
msgstr "全部分支"
-msgid "BranchRules|All users with push access are allowed to force push."
-msgstr "具有推é€æ¬Šé™çš„全部使用者都å¯ä»¥å¼·åˆ¶æŽ¨é€ã€‚"
-
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "å…許所有具有推é€å­˜å–權é™çš„使用者%{linkStart}強制推é€%{linkEnd}。"
@@ -6987,6 +7129,15 @@ msgstr "å…許推é€èˆ‡åˆä½µ"
msgid "BranchRules|Allowed to push and merge (%{total})"
msgstr "å…許推é€èˆ‡åˆä½µ (%{total})"
+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 "æ“·å–分支時發生錯誤。"
@@ -7009,7 +7160,7 @@ msgid "BranchRules|Check for a status response in merge requests. Failures do no
msgstr "在åˆä½µè«‹æ±‚中檢查狀態回應。失敗並ä¸æœƒé˜»æ­¢åˆä½µã€‚%{linkStart}å–得更多資訊。%{linkEnd}"
msgid "BranchRules|Create protected branch"
-msgstr ""
+msgstr "建立å—ä¿è­·åˆ†æ”¯"
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr "建立è¬ç”¨å­—元:%{searchTerm}"
@@ -7017,12 +7168,15 @@ msgstr "建立è¬ç”¨å­—元:%{searchTerm}"
msgid "BranchRules|Details"
msgstr "詳情"
-msgid "BranchRules|Force push"
-msgstr "強制推é€"
-
-msgid "BranchRules|Force push is not allowed."
+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 "群組"
@@ -7062,6 +7216,9 @@ msgstr "需è¦æ ¸å‡† (%{total})"
msgid "BranchRules|Requires CODEOWNERS approval"
msgstr "éœ€è¦ CODEOWNERS 核准"
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr "角色"
@@ -7075,7 +7232,7 @@ msgid "BranchRules|Target branch"
msgstr "目標分支"
msgid "BranchRules|To create a branch rule, you first need to create a protected branch."
-msgstr ""
+msgstr "è¦å»ºç«‹åˆ†æ”¯è¦å‰‡ï¼Œæ‚¨é¦–先需è¦å»ºç«‹ä¸€å€‹å—ä¿è­·çš„分支。"
msgid "BranchRules|Users"
msgstr "使用者"
@@ -7498,7 +7655,7 @@ 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 ""
+msgstr "一分é˜å…§å·²å˜—試了六次以上的匯入,請至少等待一分é˜å¾Œé‡è©¦ã€‚"
msgid "Bullet list"
msgstr "項目符號清單"
@@ -7649,10 +7806,10 @@ msgid "CICD|Add an existing project to the scope"
msgstr "CICD|å°‡ç¾æœ‰å°ˆæ¡ˆå¢žåŠ åˆ°ç¯„åœ"
msgid "CICD|Allow CI job tokens from the following projects to access this project"
-msgstr ""
+msgstr "å…許來自以下專案的 CI 作業權æ–å­˜å–該專案"
msgid "CICD|Allow access to this project with a CI_JOB_TOKEN"
-msgstr ""
+msgstr "å…許使用 CI_JOB_TOKEN å­˜å–該專案"
msgid "CICD|An error occurred while update the setting. Please try again."
msgstr "更新設定時發生錯誤,請å†è©¦ä¸€é。"
@@ -7679,7 +7836,7 @@ msgid "CICD|Deployment strategy"
msgstr "部署策略"
msgid "CICD|Enable feature to allow job token access by the following projects."
-msgstr ""
+msgstr "啟用功能以å…許以下專案存å–作業權æ–。"
msgid "CICD|Enable feature to limit job token access to the following projects."
msgstr "啟用功能以é™åˆ¶ä½œæ¥­æ¬Šæ–(令牌)å°ä¸‹åˆ—專案的存å–。"
@@ -7697,7 +7854,7 @@ msgid "CICD|Limit JSON Web Token (JWT) access"
msgstr "é™åˆ¶ JSON ç¶²è·¯æ¬Šæ– (JWT) å­˜å–"
msgid "CICD|Manage which projects can use their CI_JOB_TOKEN to access this project. 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 "管ç†å“ªäº›å°ˆæ¡ˆå¯ä»¥ä½¿ç”¨ä»–們的 CI_JOB_TOKEN 來存å–這個專案,ç¦ç”¨æ­¤åŠŸèƒ½å­˜åœ¨å®‰å…¨é¢¨éšªï¼Œå› ç‚ºæœªç¶“授權的專案å¯èƒ½æœƒå˜—試å–得活動權æ–ä¸¦å­˜å– API。 %{linkStart}了解更多。%{linkEnd}"
msgid "CICD|Select the projects that can be accessed by API requests authenticated with this project's CI_JOB_TOKEN CI/CD variable. 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_JOB_TOKEN CI/CD 變數驗證的 API å­˜å–請求的專案。 åœç”¨æ­¤åŠŸèƒ½æœƒå¸¶ä¾†å®‰å…¨é¢¨éšªï¼Œå› ç‚ºæœªç¶“授權的專案å¯èƒ½æœƒå˜—試å–得活動權æ–(令牌)ä¸¦å­˜å– API。 %{linkStart}了解更多。%{linkEnd}"
@@ -7828,6 +7985,15 @@ msgstr "無法套用此建議。"
msgid "Can't be empty"
msgstr "ä¸èƒ½ç‚ºç©º"
+msgid "Can't contain %{chars}"
+msgstr "ä¸èƒ½åŒ…å« %{chars}"
+
+msgid "Can't contain spaces"
+msgstr "ä¸èƒ½åŒ…å«ç©ºæ ¼"
+
+msgid "Can't contain spaces, %{chars}"
+msgstr "ä¸èƒ½åŒ…å«ç©ºæ ¼ï¼Œ %{chars}"
+
msgid "Can't create snippet: %{err}"
msgstr "無法建立程å¼ç¢¼ç‰‡æ®µï¼š %{err}"
@@ -7945,6 +8111,9 @@ 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 "如果å²è©© (epic) 包å«éžç§å¯†å­å²è©© (epic) ,則無法將該å²è©© (epic) 設置為ç§å¯†ã€‚"
@@ -8325,6 +8494,9 @@ msgstr "(x%{numberOfUsers})"
msgid "Checkout|(x%{quantity})"
msgstr "(x%{quantity})"
+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 "發生未知錯誤,請é‡æ–°æ•´ç†æ­¤é é¢å†è©¦ã€‚"
@@ -8367,6 +8539,9 @@ 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 "建立新群組"
@@ -8376,18 +8551,15 @@ msgstr "信用å¡è¡¨å–®è¼‰å…¥å¤±æ•—,請é‡è©¦ã€‚"
msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "信用å¡è¡¨å–®è¼‰å…¥å¤±æ•—:%{message}"
+msgid "Checkout|Discount"
+msgstr "折扣"
+
msgid "Checkout|Edit"
msgstr "編輯"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr "有效期至 %{expirationMonth}/%{expirationYear}"
-msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr "您的訂單確èªå¤±æ•—ï¼è«‹é‡è©¦ã€‚"
-
-msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr "無法確èªæ‚¨çš„訂單: %{message}。請é‡è©¦ã€‚"
-
msgid "Checkout|Failed to load countries. Please try again."
msgstr "加載國家失敗。請é‡è©¦ã€‚"
@@ -8412,6 +8584,9 @@ msgstr "GitLab 方案"
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 "此數字必須為 %{minimumNumberOfUsers} (使用中的席ä½æ•¸ï¼‰æˆ–更多。"
@@ -8430,6 +8605,9 @@ msgstr "å稱:%{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr "需è¦æ›´å¤šä½¿ç”¨è€…嗎?請為您的 %{company} 購買 GitLab。"
+msgid "Checkout|Network Error: %{message}"
+msgstr "網路錯誤:%{message}"
+
msgid "Checkout|Number of users"
msgstr "使用者數"
@@ -8448,6 +8626,9 @@ msgstr "é¸æ“‡ä¸€å€‹åœ‹å®¶"
msgid "Checkout|Select a state"
msgstr "è«‹é¸æ“‡ä¸€å€‹å·ž"
+msgid "Checkout|Something went wrong while loading price details."
+msgstr "載入詳細價格時出了點å•é¡Œã€‚"
+
msgid "Checkout|State"
msgstr "å·ž"
@@ -8568,12 +8749,18 @@ msgstr "é¸æ“‡æ‚¨è¦åœ¨ç¾¤çµ„概覽é é¢ä¸Šçœ‹åˆ°çš„內容。"
msgid "Choose which Git strategy to use when fetching the project."
msgstr "é¸æ“‡æŠ“å–專案時è¦ä½¿ç”¨çš„ Git 策略。"
+msgid "Choose which branches should be mirrored"
+msgstr "é¸å–è¦è¢«é¡åƒçš„分支"
+
msgid "Choose which repositories you want to connect and run CI/CD pipelines."
msgstr "è«‹é¸æ“‡è¦é€£æŽ¥ä¸¦åŸ·è¡Œ CI/CD æµæ°´ç·šçš„程å¼ç¢¼ç‰ˆæœ¬åº«ã€‚"
msgid "Choose your framework"
msgstr "é¸æ“‡æ‚¨çš„框架"
+msgid "Ci config already present"
+msgstr "Ci é…置已經存在"
+
msgid "CiCdAnalytics|Date range: %{range}"
msgstr "日期範åœï¼š%{range}"
@@ -8652,12 +8839,12 @@ msgstr "等待"
msgid "CiStatus|running"
msgstr "執行中"
+msgid "CiVariables|Cancel"
+msgstr "å–消"
+
msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr "ç›®å‰æ•¸å€¼ç„¡æ³•ä½¿ç”¨è®Šæ•¸é®ç½©"
-msgid "CiVariables|Clear inputs"
-msgstr "清除輸入"
-
msgid "CiVariables|Environments"
msgstr "環境"
@@ -8685,6 +8872,9 @@ msgstr "é¸é …"
msgid "CiVariables|Protected"
msgstr "å—ä¿è­·"
+msgid "CiVariables|Remove inputs"
+msgstr "清除輸入"
+
msgid "CiVariables|Remove variable"
msgstr "移除變數"
@@ -8692,7 +8882,7 @@ msgid "CiVariables|Remove variable row"
msgstr "移除變數行"
msgid "CiVariables|Run job"
-msgstr ""
+msgstr "執行作業"
msgid "CiVariables|Run job again"
msgstr "å†æ¬¡åŸ·è¡Œä½œæ¥­"
@@ -8701,7 +8891,7 @@ 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 ""
+msgstr "指定è¦åœ¨æ­¤æ¬¡åŸ·è¡Œä¸­ä½¿ç”¨çš„變數值,é è¨­ä½¿ç”¨é…置文件和 %{linkStart}CI/CD 設定%{linkEnd} 中所指定的變數。"
msgid "CiVariables|State"
msgstr "狀態"
@@ -8719,7 +8909,7 @@ msgid "CiVariables|Variables"
msgstr "變數"
msgid "CiVariables|Variables specified here are %{boldStart}expanded%{boldEnd} and not %{boldStart}masked.%{boldEnd}"
-msgstr ""
+msgstr "此處指定的變數是 %{boldStart}expanded%{boldEnd} 而ä¸æ˜¯ %{boldStart}masked.%{boldEnd}"
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 "變數儲存您å¯ä»¥åœ¨ä½œæ¥­è…³æœ¬ä¸­ä½¿ç”¨çš„資訊,例如密碼和密鑰,æ¯å€‹ %{entity} 最多å¯ä»¥å®šç¾© %{limit} 個變數。"
@@ -9464,6 +9654,9 @@ msgstr "您的實例沒有設置 %{linkStart}GitLab 代ç†æœå‹™å™¨ (KAS)%{linkE
msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
msgstr "ClusterAgent|使用者權é™ä¸è¶³ï¼Œç„¡æ³•ç‚ºæ­¤å°ˆæ¡ˆå»ºç«‹ä»¤ç‰Œ(權æ–)"
+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 "ClusterAgent|您的權é™ä¸è¶³ï¼Œç„¡æ³•ç‚ºæ­¤å°ˆæ¡ˆå»ºç«‹å¢é›†ä»£ç†"
@@ -9755,7 +9948,7 @@ msgstr "用於å°å¢é›†é€²è¡Œèº«ä»½é©—證的 Kubernetes 憑證。"
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
msgstr "ç”¨æ–¼å­˜å– Kubernetes API çš„ URL。"
-msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support."
+msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions."
msgstr "基於證書的 Kubernetes æ•´åˆå·²è¢«æ£„用,將於 2023 å¹´ 2 月關閉。請 %{linkStart}é·ç§»åˆ° GitLab 代ç†çš„ Kubernetes%{linkEnd} 或è¯ç¹« GitLab 支æ´æœå‹™ã€‚"
msgid "ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}."
@@ -10146,9 +10339,6 @@ msgstr "比較GitLab版本"
msgid "Compare GitLab plans"
msgstr "比較 GitLab 方案"
-msgid "Compare Revisions"
-msgstr "比較版本"
-
msgid "Compare branches and continue"
msgstr "比較分支並繼續"
@@ -10161,6 +10351,9 @@ msgstr "與上個æ交比較變更內容"
msgid "Compare changes with the merge request target branch"
msgstr "與åˆä½µè«‹æ±‚的目標分支比較變更內容"
+msgid "Compare revisions"
+msgstr "比較修訂版本"
+
msgid "Compare submodule commit revisions"
msgstr "比較å­æ¨¡çµ„çš„æ交修訂"
@@ -10230,12 +10423,21 @@ msgstr "已完æˆ"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr "在 %{duration_seconds} 秒內完æˆï¼ˆ%{relative_time})"
+msgid "Compliance Report|Frameworks"
+msgstr "框架"
+
+msgid "Compliance Report|Violations"
+msgstr "é•è¦"
+
msgid "Compliance framework"
msgstr "åˆè¦æ¡†æž¶"
msgid "Compliance report"
msgstr "åˆè¦å ±å‘Š"
+msgid "Compliance violations and compliance frameworks for the group."
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "添加框架"
@@ -10344,9 +10546,24 @@ msgstr "ç”±æ交者批准"
msgid "ComplianceReport|Less than 2 approvers"
msgstr "少於 2 個核准人"
+msgid "ComplianceReport|No framework"
+msgstr "無框架"
+
+msgid "ComplianceReport|No projects found"
+msgstr "未找到專案"
+
msgid "ComplianceReport|No violations found"
msgstr "未發ç¾é•è¦è¡Œç‚º"
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+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 "Component"
msgstr "元件"
@@ -10365,9 +10582,6 @@ msgstr "機密備註"
msgid "Confidentiality"
msgstr "機密性"
-msgid "Configuration"
-msgstr "組態"
-
msgid "Configuration help"
msgstr "組態å”助說明"
@@ -10986,6 +11200,9 @@ msgstr "您將è¦ç§»é™¤å€‰åº«%{title},確èªå¾Œï¼Œæ­¤å€‰åº«å°‡è¢«æ°¸ä¹…刪除ã
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr "您å¯ä»¥é€éŽä»¥ä¸‹æŒ‡ä»¤å°‡æ˜ åƒåŠ å…¥åˆ°å®¹å™¨æ˜ åƒåº«ï¼š"
+msgid "Content"
+msgstr "內容"
+
msgid "Content parsed with %{link}."
msgstr "%{link}解æžçš„內容。"
@@ -11028,29 +11245,41 @@ msgstr "è²¢ç»"
msgid "Contribution Analytics"
msgstr "è²¢ç»åº¦åˆ†æž"
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr "已建立 %{createdCount} ,已關閉 %{closedCount} 。"
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr "已建立 %{createdCount},已åˆä½µ %{mergedCount},已關閉 %{closedCount}。"
+
msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr "已建立 %{created} ,已關閉 %{closed} 。"
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr "已建立 %{created} ,已åˆä½µ %{merged} ,已關閉 %{closed} 。"
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr "ç”± %{authorCount} æŽ¨é€ %{pushCount} 次。"
+
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr "%{pushes}ï¼Œè¶…éŽ %{contributors} çš„ %{commits}。"
msgid "ContributionAnalytics|Approved MRs"
-msgstr ""
+msgstr "已核准的 MRs"
msgid "ContributionAnalytics|Closed MRs"
-msgstr ""
+msgstr "已關閉的 MRs"
msgid "ContributionAnalytics|Closed issues"
-msgstr ""
+msgstr "已關閉的議題"
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr "從 %{start_date} 開始å°è­°é¡Œã€åˆä½µè«‹æ±‚åŠæŽ¨é€äº‹ä»¶çš„è²¢ç»çµ±è¨ˆ"
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr "æ¯å€‹ç¾¤çµ„æˆå“¡çš„è²¢ç»"
+
msgid "ContributionAnalytics|Failed to load the contribution stats"
-msgstr ""
+msgstr "載入貢ç»çµ±è¨ˆå¤±æ•—"
msgid "ContributionAnalytics|Issues"
msgstr "議題"
@@ -11065,16 +11294,16 @@ msgid "ContributionAnalytics|Last week"
msgstr "最近 1 週"
msgid "ContributionAnalytics|Loading contribution stats for group members"
-msgstr ""
+msgstr "載入群組æˆå“¡çš„è²¢ç»çµ±è¨ˆ"
msgid "ContributionAnalytics|Merge requests"
msgstr "åˆä½µè«‹æ±‚"
msgid "ContributionAnalytics|Merged MRs"
-msgstr ""
+msgstr "å·²åˆä½µçš„ MRs"
msgid "ContributionAnalytics|Name"
-msgstr ""
+msgstr "å稱"
msgid "ContributionAnalytics|No issues for the selected time period."
msgstr "é¸å–的時間範åœæ²’有議題。"
@@ -11086,16 +11315,19 @@ msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "é¸å–的時間範åœæ²’有推é€ã€‚"
msgid "ContributionAnalytics|Opened MRs"
-msgstr ""
+msgstr "é–‹å•Ÿçš„ MRs"
msgid "ContributionAnalytics|Opened issues"
-msgstr ""
+msgstr "開啟的議題"
msgid "ContributionAnalytics|Pushed"
-msgstr ""
+msgstr "已推é€"
+
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr "給定的日期範åœå¤§æ–¼ %{number_of_days} 天"
-msgid "ContributionAnalytics|The given date range is larger than 31 days"
-msgstr "給定的日期範åœå¤§æ–¼ 31 天"
+msgid "ContributionAnalytics|The given date range is larger than 93 days"
+msgstr "給定的日期範åœå¤§æ–¼ 93 天"
msgid "ContributionAnalytics|The to date is earlier than the given from date"
msgstr "截止日期早於給定的起始日期"
@@ -11104,7 +11336,7 @@ msgid "ContributionAnalytics|There is too much data to calculate. Try lowering t
msgstr "è¦è¨ˆç®—的資料太多。請嘗試é™ä½Žåœ¨æ´žå¯Ÿå ±å‘Šè¨­å®šæª”中的 period_limit 設定。"
msgid "ContributionAnalytics|Total Contributions"
-msgstr ""
+msgstr "總體貢ç»"
msgid "Contributions for %{calendar_date}"
msgstr "%{calendar_date}çš„è²¢ç»"
@@ -11115,8 +11347,8 @@ msgstr "群組æˆå“¡è²¢ç»è©³æƒ…"
msgid "Contributor"
msgstr "è²¢ç»è€…"
-msgid "Contributors"
-msgstr "è²¢ç»è€…"
+msgid "Contributor statistics"
+msgstr "è²¢ç»è€…統計"
msgid "Control emails linked to your account"
msgstr "控制與您帳號關è¯çš„é›»å­éƒµä»¶"
@@ -11187,6 +11419,9 @@ msgstr "複製指令"
msgid "Copy commit SHA"
msgstr "複製æ交SHA"
+msgid "Copy diagram URL"
+msgstr "複製圖表網å€"
+
msgid "Copy environment"
msgstr "複製環境"
@@ -11433,8 +11668,8 @@ msgstr "無法將策略分é…給專案或群組"
msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
msgstr "無法找到事件審核類型: %{missing_filters} éŽæ¿¾å™¨"
-msgid "Country"
-msgstr "國家"
+msgid "Country / Region"
+msgstr "國家/地å€"
msgid "Counts"
msgstr "數目"
@@ -11622,6 +11857,9 @@ msgstr "建立一個"
msgid "Create or close an issue."
msgstr "建立或關閉議題。"
+msgid "Create or edit diagram"
+msgstr "建立或編輯圖表"
+
msgid "Create or import your first project"
msgstr "建立或匯入您的第一個專案"
@@ -11871,9 +12109,6 @@ msgstr "已建立於"
msgid "Created a branch and a merge request to resolve this issue."
msgstr "已建立了一個分支和一個åˆä½µè«‹æ±‚來解決此議題。"
-msgid "Created at"
-msgstr "建立於"
-
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
msgstr "已建立分支「%{branch_name}ã€èˆ‡åˆä½µè«‹æ±‚來解決此議題。"
@@ -12081,6 +12316,9 @@ msgstr "å好設定"
msgid "CurrentUser|Start an Ultimate trial"
msgstr "開始試用旗艦版"
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr "切æ›åˆ° GitLab Next"
+
msgid "Currently unable to fetch data for this pipeline."
msgstr "ç›®å‰ç„¡æ³•å–得該æµæ°´ç·šè³‡æ–™"
@@ -12180,8 +12418,8 @@ msgstr "議題首次加入到看æ¿"
msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
msgstr "議題首次與里程碑相關è¯"
-msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue first added to a board"
-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 "議題首次在æ交中æåŠ"
@@ -12346,9 +12584,6 @@ msgstr "ä¸æ”¯æ´è¢«æŒ‡æ´¾çš„物件"
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr "DAGå¯è¦–化至少需è¦3個相關作業。"
-msgid "DAST Configuration"
-msgstr "DAST é…ç½®"
-
msgid "DAST configuration not found"
msgstr "未找到 DAST 組態"
@@ -12638,7 +12873,7 @@ msgid "DastProfiles|Enter URLs in a comma-separated list."
msgstr "在用逗號分隔的清單中輸入 URL。"
msgid "DastProfiles|Enter a comma-separated list of request header names and values. DAST adds header to every request."
-msgstr ""
+msgstr "輸入以逗號分隔的請求標頭å稱和值列表,DAST 為æ¯å€‹è«‹æ±‚加入標頭。"
msgid "DastProfiles|Error Details"
msgstr "錯誤詳情"
@@ -12656,7 +12891,7 @@ msgid "DastProfiles|Excluded paths (optional)"
msgstr "排除的路徑(å¯é¸ï¼‰"
msgid "DastProfiles|Headers will appear in vulnerability reports. %{linkStart}Only some headers are automatically masked%{linkEnd}."
-msgstr ""
+msgstr "標頭將出ç¾åœ¨æ¼æ´žå ±å‘Šä¸­ï¼Œ %{linkStart}åªæœ‰éƒ¨åˆ†æ¨™é ­æœƒè¢«è‡ªå‹•å±è”½%{linkEnd}。"
msgid "DastProfiles|Hide debug messages"
msgstr "éš±è—除錯訊æ¯"
@@ -13251,7 +13486,7 @@ msgid "Delete comment"
msgstr "刪除留言"
msgid "Delete comment?"
-msgstr ""
+msgstr "刪除留言評論?"
msgid "Delete corpus"
msgstr "刪除語料庫"
@@ -13259,6 +13494,9 @@ msgstr "刪除語料庫"
msgid "Delete deploy key"
msgstr "刪除部署金鑰"
+msgid "Delete diagram"
+msgstr "刪除圖表"
+
msgid "Delete epic"
msgstr "刪除å²è©© (epic) "
@@ -13301,8 +13539,11 @@ msgstr "刪除 %{release} 發布版本?"
msgid "Delete row"
msgstr "刪除行"
+msgid "Delete saved reply"
+msgstr "刪除已儲存的回復"
+
msgid "Delete selected"
-msgstr ""
+msgstr "刪除已é¸å–"
msgid "Delete self-monitoring project"
msgstr "刪除自監控專案"
@@ -14044,6 +14285,9 @@ msgstr "æˆåŠŸ"
msgid "Deprecated API rate limits"
msgstr "已棄用的 API 速率é™åˆ¶"
+msgid "Deprecation notice"
+msgstr "棄用通知"
+
msgid "Deprecations|For information on a possible replacement %{epicStart} learn more about Opstrace %{epicEnd}."
msgstr "關於å¯èƒ½æ›¿æ›çš„訊æ¯ï¼Œ%{epicStart}瞭解更多關於 Opstrace %{epicEnd}。"
@@ -14144,12 +14388,15 @@ 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 discussion. Please try again."
msgstr "無法更新討論。請é‡è©¦ã€‚"
-msgid "DesignManagement|Could not update note. Please try again."
-msgstr "無法更新註釋。請é‡è©¦ã€‚"
-
msgid "DesignManagement|Deselect all"
msgstr "å–消全部é¸æ“‡"
@@ -14252,6 +14499,9 @@ msgstr "DevOps adoption"
msgid "Developer"
msgstr "開發者"
+msgid "Device name"
+msgstr "è£ç½®å稱"
+
msgid "Devices (optional)"
msgstr "設備(å¯é¸ï¼‰"
@@ -14447,6 +14697,9 @@ msgstr "您的使用情æ³"
msgid "Diagram (%{language})"
msgstr "圖表 (%{language})"
+msgid "Diagram saved successfully."
+msgstr "圖表已æˆåŠŸå„²å­˜ã€‚"
+
msgid "Did not delete the source branch."
msgstr "未刪除來æºåˆ†æ”¯"
@@ -14597,9 +14850,6 @@ msgstr "Discord 通知"
msgid "DiscordService|Send notifications about project events to a Discord channel."
msgstr "å‘ Discord é »é“發é€æœ‰é—œå°ˆæ¡ˆäº‹ä»¶çš„通知。"
-msgid "Discover"
-msgstr "Discover"
-
msgid "Discover GitLab Geo"
msgstr "探索 GitLab Geo"
@@ -15036,6 +15286,9 @@ msgstr "編輯部署金鑰"
msgid "Edit description"
msgstr "編輯æ述訊æ¯"
+msgid "Edit diagram description"
+msgstr "編輯圖表說明"
+
msgid "Edit environment"
msgstr "編輯環境"
@@ -15060,6 +15313,9 @@ msgstr "編輯 %{user_name} 的身份訊æ¯"
msgid "Edit image description"
msgstr "編輯映åƒæè¿°"
+msgid "Edit image text or link"
+msgstr "編輯映åƒæ–‡å­—或éˆçµ"
+
msgid "Edit in pipeline editor"
msgstr "在æµæ°´ç·šç·¨è¼¯å™¨ä¸­ç·¨è¼¯"
@@ -15078,9 +15334,15 @@ msgstr "編輯連çµ"
msgid "Edit merge requests"
msgstr "編輯åˆä½µè«‹æ±‚"
+msgid "Edit project: %{project_name}"
+msgstr "編輯專案: %{project_name}"
+
msgid "Edit public deploy key"
msgstr "編輯公共部署金鑰"
+msgid "Edit saved reply"
+msgstr "編輯已儲存的回復"
+
msgid "Edit sidebar"
msgstr "編輯å´é‚Šæ¬„"
@@ -15537,6 +15799,9 @@ msgstr "輸入管ç†å“¡æ¨¡å¼çš„雙因為驗證碼"
msgid "Enter Admin Mode"
msgstr "進入管ç†å“¡æ¨¡å¼"
+msgid "Enter a name for your saved reply"
+msgstr "為您所儲存的回復輸入一個å稱"
+
msgid "Enter a number"
msgstr "輸入數字"
@@ -15582,8 +15847,8 @@ msgstr "輸入 %{name} æè¿°"
msgid "Enter the %{name} title"
msgstr "輸入 %{name} 標題"
-msgid "Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes."
-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 "輸入以下內容進行確èªï¼š"
@@ -15600,6 +15865,9 @@ msgstr "輸入å—密碼ä¿è­·çš„ Elasticsearch 伺æœå™¨çš„密碼。"
msgid "Enter the username for password-protected Elasticsearch servers."
msgstr "輸入å—密碼ä¿è­·çš„ Elasticsearch 伺æœå™¨çš„使用者å稱。"
+msgid "Enter verification code"
+msgstr "輸入驗證碼"
+
msgid "Enter your Packagist server. Defaults to https://packagist.org."
msgstr "輸入您的 Packagist 伺æœå™¨ã€‚é è¨­ç‚º https://packagist.org。"
@@ -15894,6 +16162,9 @@ msgstr "å²è©© (Epic) 看æ¿"
msgid "Epic actions"
msgstr "å²è©© (Epic) 動作"
+msgid "Epic boards"
+msgstr "å²è©© (Epic) 看æ¿"
+
msgid "Epic cannot be found."
msgstr "找ä¸åˆ°å²è©© (epic) 。"
@@ -16005,6 +16276,9 @@ msgstr "建立新目錄時發生錯誤。請é‡è©¦ã€‚"
msgid "Error creating new iteration"
msgstr "建立新迭代時發生錯誤"
+msgid "Error creating or updating PreScanVerificationStep: %{errors}"
+msgstr "建立或更新 PreScanVerificationStep 時發生錯誤: %{errors}"
+
msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr "以id %{snippet_id} 建立程å¼ç¢¼ç‰‡æ®µåº«æ™‚發生錯誤"
@@ -16293,6 +16567,9 @@ msgstr "您確定è¦åˆªé™¤\"%{escalationPolicy}\"å‡ç´šæ”¿ç­–嗎?該動作無æ
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 "é¸æ“‡è­¦å ±æ²’有回應時的最優先電å­éƒµä»¶è¯ç¹«äººã€‚è¦å­˜å–è©²åŠŸèƒ½ï¼Œè«‹è©¢å• %{linkStart}專案æ“有者%{linkEnd} 授予您至少為 Maintainer 的角色。"
+
msgid "EscalationPolicies|Create an escalation policy in GitLab"
msgstr "在 GitLab 中建立å‡ç´šæ”¿ç­–"
@@ -16570,6 +16847,9 @@ msgstr "憑證集"
msgid "Exactly one of %{attributes} is required"
msgstr "其中的一個%{attributes}是必需的"
+msgid "Example"
+msgstr "範例"
+
msgid "Example: (feature|hotfix)\\/*"
msgstr "範例: (feature|hotfix)\\/*"
@@ -16594,6 +16874,9 @@ 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 "ä¸åŒ…括åˆä½µæ交。僅é™%{limit}次æ交。"
@@ -16795,6 +17078,9 @@ msgstr "未設定分類標記的時候,將使用é è¨­çš„分類標記`%{defaul
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 "用於通éŽå¤–部授權æœå‹™é€²è¡Œèº«ä»½é©—è­‰çš„è­‰æ›¸ã€‚å¦‚æžœç‚ºç©ºï¼Œå‰‡åœ¨é€šéŽ HTTPS å­˜å–時驗證æœå‹™å™¨è­‰æ›¸ã€‚"
@@ -16813,6 +17099,9 @@ msgstr "客戶端授權金鑰密碼(é¸é …)"
msgid "ExternalAuthorization|Default classification label"
msgstr "é è¨­åˆ†é¡žæ¨™è¨˜"
+msgid "ExternalAuthorization|Does not apply if service URL is specified."
+msgstr "如果指定了æœå‹™ URL,則ä¸é©ç”¨ã€‚"
+
msgid "ExternalAuthorization|Enable classification control using an external service"
msgstr "使用外部æœå‹™å•Ÿç”¨åˆ†é¡žæŽ§åˆ¶"
@@ -17380,9 +17669,6 @@ msgstr "2月"
msgid "February"
msgstr "2月"
-msgid "Feedback and Updates"
-msgstr "回饋與更新"
-
msgid "Fetch and check out this merge request's feature branch:"
msgstr "å–得並簽出此åˆä½µè«‹æ±‚的功能分支:"
@@ -17506,6 +17792,9 @@ msgstr "éŽæ¿¾åƒæ•¸ç„¡æ•ˆã€‚確ä¿çµæŸæ—¥æœŸæ™šæ–¼é–‹å§‹æ—¥æœŸã€‚"
msgid "Filter pipelines"
msgstr "éŽæ¿¾æµæ°´ç·š"
+msgid "Filter reports"
+msgstr "éŽæ¿¾å ±å‘Š"
+
msgid "Filter results"
msgstr "éŽæ¿¾çµæžœ"
@@ -17662,9 +17951,6 @@ msgstr "é‡å°æ¯å€‹ä½œæ¥­ï¼Œé‡è¤‡ä½¿ç”¨å°ˆæ¡ˆå·¥ä½œç©ºé–“。如果工作空間
msgid "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 "例如,使用權æ–(令牌)的應用程å¼æˆ–權æ–(令牌)的用途。ä¸è¦æ供權æ–(令牌)å稱的æ•æ„Ÿè¨Šæ¯ï¼Œå› ç‚ºå®ƒå°‡å°æ‰€æœ‰ %{resource_type} æˆå“¡å¯è¦‹ã€‚"
-msgid "For faster browsing, not all history is shown."
-msgstr "為了ç€è¦½çš„æµæš¢åº¦ï¼Œä¸æœƒé¡¯ç¤ºæ‰€æœ‰æ­·å²è¨˜éŒ„。"
-
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
msgstr "å°æ–¼å¤§æ–¼æ­¤é™åˆ¶çš„檔案,僅索引檔案å稱。檔案內容沒有索引也ä¸å¯æœå°‹ã€‚"
@@ -17806,9 +18092,6 @@ msgstr "æ ¼å¼ï¼š%{dateFormat}"
msgid "Framework successfully deleted"
msgstr "框架刪除æˆåŠŸ"
-msgid "Free"
-msgstr "å…è²»"
-
msgid "Free Trial of GitLab.com Ultimate"
msgstr "å…費試用 GitLab.com Ultimate"
@@ -17829,7 +18112,7 @@ 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 ""
+msgstr "根據我們在 %{date_time} 執行的檢查,您似乎已é”到“%{namespace_name}†的%{free_user_limit} æˆå“¡é™åˆ¶ã€‚您無法å†å¢žåŠ ï¼Œä½†æ‚¨å¯ä»¥ç®¡ç†ç¾æœ‰æˆå“¡ï¼Œä¾‹å¦‚,通éŽåˆªé™¤ä¸æ´»èºçš„æˆå“¡ä¸¦ç”¨æ–°æˆå“¡æ›¿æ›ä»–們。"
msgid "FreeUserCap|Manage members"
msgstr "æˆå“¡ç®¡ç†"
@@ -18616,14 +18899,23 @@ msgstr "報告時間å€é–“必須為數字。"
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr "報告時間å€é–“應介於 %{minTimePeriod}-%{maxTimePeriod} 秒之間。"
+msgid "GitAbuse|Select between %{minAlertedUsers} and %{maxAlertedUsers} users to notify."
+msgstr "é¸å–在 %{minAlertedUsers} 到 %{maxAlertedUsers} 個使用者間進行通知。"
+
+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 "è¶…éŽ Git 濫用速率é™åˆ¶æ™‚è¦æ”¶åˆ°é›»å­éƒµä»¶çš„使用者。"
+
msgid "GitAbuse|Users who are excluded from the Git abuse rate limit."
msgstr "被排除在 Git 濫用率é™åˆ¶ä¹‹å¤–的使用者。"
-msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
-msgstr "您ä¸èƒ½æŒ‡å®šè¶…éŽ %{maxExcludedUsers} 個排除的使用者。"
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr "您ä¸èƒ½æŒ‡å®šè¶…éŽ %{maxAllowedUsers} 個排除的使用者。"
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr "已超出 GitHub API 速率é™åˆ¶ã€‚%{reset_time} 後é‡è©¦"
@@ -18673,6 +18965,9 @@ msgstr "GitLab KAS"
msgid "GitLab Pages"
msgstr "GitLab Pages"
+msgid "GitLab Pages has moved"
+msgstr "GitLab é é¢å·²ç§»å‹•"
+
msgid "GitLab Shell"
msgstr "GitLab Shell"
@@ -18697,6 +18992,12 @@ msgstr "GitLab帳號請求被拒絕"
msgid "GitLab commit"
msgstr "GitLab æ交"
+msgid "GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code"
+msgstr "GitLab 檢測到有人試圖使用ä¸æ­£ç¢ºçš„驗證碼登入您的 %{host} 帳號"
+
+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 "GitLab 檢測到有人試圖使用來自以下 IP ä½å€çš„錯誤驗證碼登入您的 %{host} 帳號:%{ip},時間為 %{time}"
+
msgid "GitLab documentation"
msgstr "GitLab 文件"
@@ -18712,9 +19013,6 @@ msgstr "é©ç”¨æ–¼ Jira Cloud çš„ GitLab"
msgid "GitLab group: %{source_link}"
msgstr "GitLab 群組:%{source_link}"
-msgid "GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited"
-msgstr "GitLab 孵化功能用以探索新的使用案例,這些功能會經常更新與有é™å®šçš„支æ´ã€‚"
-
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr "如果有新版本å¯ç”¨ï¼ŒGitLab 會通知您。 %{link_start}GitLab Inc. 收集哪些信æ¯ï¼Ÿ%{link_end}"
@@ -18763,10 +19061,6 @@ msgstr "GitLab版本"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab 將在你的分å‰ï¼ˆFork)中建立一個分支並啟動一個åˆä½µè«‹æ±‚。"
-msgid "GitLab will enforce this limit in the future. If you are over %{free_user_limit} user when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} user or less or purchase a paid tier."
-msgid_plural "GitLab will enforce this limit in the future. If you are over %{free_user_limit} users when enforcement begins, your top-level group, including any subgroups and projects, will be placed in a %{link_start}read-only%{link_end} state. To avoid being placed in a read-only state, reduce your top-level group to %{free_user_limit} users or less or purchase a paid tier."
-msgstr[0] "GitLab 將在未來強制執行該é™åˆ¶ï¼Œå¦‚æžœæ‚¨åœ¨å¼·åˆ¶åŸ·è¡Œé–‹å§‹æ™‚è¶…éŽ %{free_user_limit} 個使用者,您的最上層群組(包括任何å­ç¾¤çµ„和專案)將處於 %{link_start} 唯讀 %{link_end} 狀態。為é¿å…處於唯讀狀態,請將您的最上層群組減少到 %{free_user_limit} 個使用者或更少,或購買付費層級。"
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -18860,12 +19154,18 @@ msgstr "未驗證"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "正在更新您的é é¢é…ç½®..."
+msgid "GitLabPages|Use unique domain"
+msgstr "使用唯一網域"
+
msgid "GitLabPages|Verified"
msgstr "已驗證"
msgid "GitLabPages|Waiting for the Pages Pipeline to complete..."
msgstr "正在等待 Pages æµæ°´ç·šå®Œæˆ..."
+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 "啟用後,所有通éŽHTTPçš„å­˜å–嘗試都會自動é‡å®šå‘到HTTPS,使用狀態代碼301。 需è¦å°æ‰€æœ‰åŸŸå有效的證書。%{docs_link_start}瞭解更多訊æ¯ã€‚%{link_end}"
@@ -18905,6 +19205,9 @@ msgstr "Gitea 主機地å€"
msgid "Gitea Import"
msgstr "從Gitea匯入"
+msgid "GithubImporter|Collaborators"
+msgstr "åˆä½œè€…"
+
msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
msgstr "ID %{gist_id} 的 Gist 因為錯誤而失敗:%{error}"
@@ -18917,14 +19220,14 @@ msgstr "未匯入的 GitHub Gists:"
msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
msgstr "超éŽå個檔案的 GitHub gists 必須手動æ¬ç§»ã€‚"
-msgid "GithubImporter|Issue attachments"
-msgstr "議題附件"
+msgid "GithubImporter|Issue links"
+msgstr "è­°é¡Œéˆçµ"
-msgid "GithubImporter|Merge request attachments"
-msgstr "åˆä½µè«‹æ±‚附件"
+msgid "GithubImporter|Merge request links"
+msgstr "åˆä½µè«‹æ±‚éˆçµ"
-msgid "GithubImporter|Note attachments"
-msgstr "註釋附件"
+msgid "GithubImporter|Note links"
+msgstr "註釋éˆçµ"
msgid "GithubImporter|PR mergers"
msgstr "PR åˆä½µ"
@@ -18941,8 +19244,8 @@ msgstr "請追蹤 %{import_snippets_url} 以å–得更多資訊。"
msgid "GithubImporter|Pull requests"
msgstr "拉å–請求"
-msgid "GithubImporter|Release attachments"
-msgstr "發布附件"
+msgid "GithubImporter|Release links"
+msgstr "發布éˆçµ"
msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
msgstr "您將 GitHub gists 匯入 GitLab 程å¼ç¢¼ç‰‡æ®µçš„動作已經完æˆã€‚"
@@ -18995,6 +19298,9 @@ msgstr "%{time_ago}授權存å–"
msgid "Given epic is already related to this epic."
msgstr "給定å²è©© (epic) 已經與此å²è©© (epic) é—œè¯ã€‚"
+msgid "Global SAML group membership lock"
+msgstr "全域 SAML 群組æˆå“¡éŽ–定"
+
msgid "Global Search is disabled for this scope"
msgstr "此範åœçš„全域æœå°‹å·²ç¦ç”¨"
@@ -19067,6 +19373,9 @@ msgstr "近期的議題"
msgid "GlobalSearch|Recent merge requests"
msgstr "近期的åˆä½µæ交"
+msgid "GlobalSearch|Reset filters"
+msgstr "é‡ç½®éŽæ¿¾å™¨"
+
msgid "GlobalSearch|Result count is over limit."
msgstr "çµæžœæ•¸ç›®è¶…éŽé™åˆ¶"
@@ -19121,15 +19430,9 @@ msgstr "您正在æœå°‹ä»€éº¼ï¼Ÿ"
msgid "GlobalSearch|all GitLab"
msgstr "整個 GitLab"
-msgid "GlobalSearch|group"
-msgstr "群組"
-
msgid "GlobalSearch|in %{scope}"
msgstr "在 %{scope}"
-msgid "GlobalSearch|project"
-msgstr "專案"
-
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr "將來æºåˆ†æ”¯å稱複製到剪貼簿。"
@@ -19346,6 +19649,30 @@ msgstr "撤銷授權"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "撤銷授予 GitLab 的授權,ä¸æœƒä½¿æœå‹™å¸³è™Ÿå¤±æ•ˆã€‚"
+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 "Google Play"
+
+msgid "GooglePlay|Leave empty to use your current service account key."
+msgstr ""
+
+msgid "GooglePlay|Service account key (.json)"
+msgstr "æœå‹™å¸³è™Ÿå¯†é‘° (.json)"
+
+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 "知é“了"
@@ -19535,6 +19862,9 @@ msgstr "群組å稱(您的組織)"
msgid "Group navigation"
msgstr "群組導航"
+msgid "Group overview"
+msgstr "群組總覽"
+
msgid "Group overview content"
msgstr "群組概述內容"
@@ -19886,6 +20216,9 @@ msgstr "更改群組 URL å¯èƒ½æœƒç”¢ç”Ÿæ„外的副作用。"
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 "åˆè¦æ¡†æž¶"
@@ -20144,6 +20477,9 @@ msgstr "輸入來æºç«™å°çš„ URL。"
msgid "GroupsNew|GitLab source instance URL"
msgstr "GitLab 來æºç«™å° URL"
+msgid "GroupsNew|Groups"
+msgstr "群組"
+
msgid "GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}."
msgstr "通éŽå»ºç«‹ %{linkStart}å­ç¾¤çµ„%{linkEnd} 也å¯ä»¥åµŒå¥—群組。"
@@ -20159,6 +20495,12 @@ msgstr "é€éŽç›´æŽ¥å‚³è¼¸åŒ¯å…¥ç¾¤çµ„"
msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr "ç›®å‰å·²åœç”¨é€éŽç›´æŽ¥å‚³è¼¸åŒ¯å…¥ç¾¤çµ„。"
+msgid "GroupsNew|New group"
+msgstr "新群組"
+
+msgid "GroupsNew|New subgroup"
+msgstr "æ–°çš„å­ç¾¤çµ„"
+
msgid "GroupsNew|No import options available"
msgstr "GroupsNew|沒有å¯ç”¨çš„匯入é¸é …"
@@ -20533,6 +20875,9 @@ msgstr "å”助減少請求é‡ï¼ˆä¾‹å¦‚來自爬蟲或濫用機器人的請求)
msgid "Helps reduce request volume for protected paths."
msgstr "å”助減少å—ä¿è­·è·¯å¾‘的請求é‡ã€‚"
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr "å—¨ %{user_name} (%{user_username})ï¼"
+
msgid "Hi %{username}!"
msgstr "%{username},您好!"
@@ -20818,7 +21163,7 @@ msgid "IP subnet restriction only allowed for top-level groups"
msgstr "åªå…許在最頂層群組設定IPå­ç¶²é™åˆ¶"
msgid "Icon will be removed. Are you sure?"
-msgstr ""
+msgstr "圖標將被移除,你確定嗎?"
msgid "Id"
msgstr "Id"
@@ -20874,6 +21219,9 @@ 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 "為了增加安全性,您需è¦é©—證您的身份。我們已發é€é©—證碼到 %{email}"
@@ -20973,6 +21321,9 @@ msgstr "驗證您的身份"
msgid "IdentityVerification|We sent a new code to +%{phoneNumber}"
msgstr "æˆ‘å€‘å‘ +%{phoneNumber} 發é€äº†ä¸€å€‹æ–°çš„代碼"
+msgid "IdentityVerification|We've sent a verification code to %{email}"
+msgstr "我們已將驗證碼發é€è‡³ %{email}"
+
msgid "IdentityVerification|We've sent a verification code to +%{phoneNumber}"
msgstr "我們已將驗證碼發é€è‡³ +%{phoneNumber}"
@@ -21015,15 +21366,24 @@ msgstr "如é¸å–,則群組所有者å¯ä»¥ç®¡ç†LDAP群組連çµå’Œ LDAPæˆå“¡
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr "é¸å–後將則åªèƒ½é€éŽLDAPåŒæ­¥åŠ å…¥æ–°çš„組æˆå“¡èº«ä»½å’Œæ¬Šé™"
+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 "如果åœç”¨ï¼Œåˆ†å‰çš„本地分支將ä¸æœƒè‡ªå‹•æ›´æ–°å…¶é ç¨‹åˆ†æ”¯çš„æ交,以防止本地資料丟失。 如果é è¨­åˆ†æ”¯ (%{default_branch}) 已經發散並且無法更新,則é¡åƒå°‡å¤±æ•—。 其他分歧的分支被默默地忽略。 %{link_start}了解更多。%{link_end}"
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 "若啟用的使用者數é‡è¶…éŽé™åˆ¶ï¼Œæ‚¨å°‡æœƒåœ¨ä¸‹æ¬¡çºŒç´„æ™‚è¢«æ”¶å– %{users_over_license_link} 人的費用"
@@ -21084,8 +21444,8 @@ msgstr "如果您éºå¤±äº†å¾©åŽŸç¢¼ï¼Œæ‚¨å¯ä»¥ç”Ÿæˆæ–°çš„復原碼,所有以
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr "如果您最近從上述IP地å€ç™»å…¥éŽï¼Œå‰‡å¯ä»¥å¿½ç•¥æ­¤é›»å­éƒµä»¶ã€‚"
-msgid "If you recently tried to sign in, but mistakenly entered a wrong two-factor authentication code, you may ignore 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 "如果您想è¦é‡æ–°å•Ÿç”¨é›™å› å­èº«ä»½é©—證,請訪å•%{two_factor_link}"
@@ -21308,6 +21668,9 @@ msgstr "匯入專案失敗"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr "匯入專案失敗: %{reason}"
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr "é‡æ–°åŒ¯å…¥å»ºç«‹ä¸€å€‹æ–°å°ˆæ¡ˆï¼Œå®ƒä¸èˆ‡ç¾å­˜å°ˆæ¡ˆåŒæ­¥ã€‚"
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr "請求命å空間失敗"
@@ -21711,8 +22074,8 @@ msgstr "通éŽä½¿ç”¨ DAST 檢查部署環境中的æ¼æ´žï¼Œä¿è­·æ‚¨çš„ web 應ç
msgid "InProductMarketing|Rapid development, simplified"
msgstr "快速開發,簡化"
-msgid "InProductMarketing|Reduce Security & Compliance Risk"
-msgstr "é™ä½Žå®‰å…¨èˆ‡åˆè¦é¢¨éšª"
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
+msgstr ""
msgid "InProductMarketing|Require multiple approvers on a merge request, so you know it's in good shape before it's merged."
msgstr "在åˆä½µè«‹æ±‚時需è¦å¤šå€‹å¯©æ‰¹ï¼Œæ‰€ä»¥æ‚¨å¯ä»¥çŸ¥é“它處於良好狀態,然後æ‰èƒ½åˆä½µã€‚"
@@ -22374,12 +22737,18 @@ msgstr "æ’入圖片"
msgid "Insert link"
msgstr "æ’å…¥éˆæŽ¥"
+msgid "Insert or edit diagram"
+msgstr "æ’入或編輯圖表"
+
msgid "Insert row after"
msgstr "下方æ’入行"
msgid "Insert row before"
msgstr "上方æ’入行"
+msgid "Insert saved reply"
+msgstr "æ’入已儲存的回復"
+
msgid "Insert suggestion"
msgstr "æ’入建議"
@@ -22445,16 +22814,16 @@ msgid "Integration Settings"
msgstr "æ•´åˆè¨­å®š"
msgid "IntegrationEvents|A comment is added"
-msgstr ""
+msgstr "已加入留言評論"
msgid "IntegrationEvents|A confidential issue is created, closed, or reopened"
-msgstr ""
+msgstr "機密性議題被建立ã€é—œé–‰æˆ–é‡æ–°é–‹å•Ÿ"
msgid "IntegrationEvents|A deployment is started or finished"
msgstr "部署已開始或已完æˆ"
msgid "IntegrationEvents|A merge request is created, merged, closed, or reopened"
-msgstr ""
+msgstr "建立ã€åˆä½µã€é—œé–‰æˆ–é‡æ–°é–‹å•Ÿåˆä½µè«‹æ±‚"
msgid "IntegrationEvents|A new, unique alert is recorded"
msgstr "記錄到一個新的ã€ç¨ä¸€ç„¡äºŒçš„警報"
@@ -22469,19 +22838,19 @@ msgid "IntegrationEvents|A push is made to the repository"
msgstr "推é€åˆ°ç‰ˆæœ¬åº«"
msgid "IntegrationEvents|A tag is pushed to the repository or removed"
-msgstr ""
+msgstr "標籤被推é€åˆ°ç‰ˆæœ¬åº«æˆ–被刪除"
msgid "IntegrationEvents|A wiki page is created or updated"
msgstr "wiki é é¢å·²å»ºç«‹æˆ–æ›´æ–° "
msgid "IntegrationEvents|An incident is created, closed, or reopened"
-msgstr ""
+msgstr "建立ã€é—œé–‰æˆ–é‡æ–°é–‹å•Ÿäº‹æ•…"
msgid "IntegrationEvents|An internal note or comment on a confidential issue is added"
-msgstr ""
+msgstr "已增加了關於機密議題的內部說明或評論"
msgid "IntegrationEvents|An issue is created, closed, or reopened"
-msgstr ""
+msgstr "建立ã€é—œé–‰æˆ–é‡æ–°é–‹å•Ÿè­°é¡Œ"
msgid "Integrations"
msgstr "æ•´åˆ"
@@ -22552,12 +22921,15 @@ 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 GitLab.com slash commands in a Slack workspace."
-msgstr "在 Slack 工作å€ä¸­å•Ÿç”¨ GitLab.com 斜槓命令。"
-
msgid "Integrations|Enable SSL verification"
msgstr "啟用 SSL 驗證"
@@ -22573,6 +22945,9 @@ msgstr "確ä¿æ‚¨çš„æœå‹™å¯¦ä¾‹ URL 正確並且您的實例組態é…置是正ç
msgid "Integrations|Enter your alias"
msgstr "輸入您的別å"
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
msgid "Integrations|Failed to link namespace. Please try again."
msgstr "無法éˆæŽ¥å‘½å空間,請é‡è©¦ã€‚"
@@ -22861,8 +23236,8 @@ msgstr "é‡å°ä»£ç¢¼ç‰‡æ®µ%{snippet_id}的無效倉庫包"
msgid "Invalid repository path"
msgstr "無效的倉庫路徑"
-msgid "Invalid rule"
-msgstr "無效的è¦å‰‡"
+msgid "Invalid rules are automatically approved to unblock the merge request."
+msgstr ""
msgid "Invalid server response"
msgstr "無效的æœå‹™å™¨éŸ¿æ‡‰"
@@ -22970,7 +23345,7 @@ msgid "InviteMembersModal|Access expiration date (optional)"
msgstr "å­˜å–到期日期(å¯é¸)"
msgid "InviteMembersModal|Add unlimited members with your trial"
-msgstr ""
+msgstr "在您的試用版中增加無é™åˆ¶çš„æˆå“¡"
msgid "InviteMembersModal|Cancel"
msgstr "å–消"
@@ -22988,10 +23363,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 ""
-
-msgid "InviteMembersModal|Explore paid plans"
-msgstr "ç€ç ä»˜è²»è¨ˆåŠƒ"
+msgstr "在試用期間,您å¯ä»¥é‚€è«‹ä»»æ„數é‡çš„æˆå“¡åŠ å…¥ %{groupName}。試用期çµæŸå¾Œï¼Œæ‚¨çš„å…費等級最多å¯æ“有 %{dashboardLimit} åæˆå“¡ã€‚è¦ç²å¾—更多會員,請%{linkStart}å‡ç´šåˆ°ä»˜è²»è¨ˆåŠƒ%{linkEnd}。"
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr "GitLab 與åŒäº‹å…±è™•æ›´ä½³ï¼"
@@ -23261,6 +23633,12 @@ msgstr "議題類型"
msgid "Issue already promoted to epic."
msgstr "議題已å‡ç´šç‚ºå²è©© (epic) 。"
+msgid "Issue board"
+msgstr "議題看æ¿"
+
+msgid "Issue boards"
+msgstr "議題看æ¿"
+
msgid "Issue cannot be found."
msgstr "議題無法找到"
@@ -23486,6 +23864,9 @@ msgstr "移動議題時發生錯誤。"
msgid "Issue|Title"
msgstr "標題"
+msgid "It doesn't have any %{linkStart}eligible approvers%{linkEnd}."
+msgstr ""
+
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
msgstr "您似乎正在嘗試啟用您的訂閱。請使用 %{a_start}訂閱é é¢%{a_end} 代替。"
@@ -23757,7 +24138,7 @@ msgid "JiraConnect|Create branch for Jira issue %{jiraIssue}"
msgstr "為Jira議題%{jiraIssue}建立分支"
msgid "JiraConnect|Enable public key storage"
-msgstr ""
+msgstr "啟用公鑰儲存"
msgid "JiraConnect|Failed to create branch."
msgstr "建立分支失敗。"
@@ -23829,7 +24210,7 @@ msgid "JiraService|Automatically transitions Jira issues to the \"Done\" categor
msgstr "自動將 Jira å•é¡Œè½‰æ›ç‚ºã€Œå®Œæˆã€é¡žåˆ¥ã€‚ %{linkStart}瞭解更多%{linkEnd}"
msgid "JiraService|Base URL of the Jira instance"
-msgstr ""
+msgstr "Jira 實例的基本 URL"
msgid "JiraService|Change GitLab version"
msgstr "變更 GitLab 版本"
@@ -23883,7 +24264,7 @@ msgid "JiraService|IDs must be a list of numbers that can be split with , or ;"
msgstr "ID 必須是å¯ä»¥ç”¨ , 或 ; 分割的數字列表"
msgid "JiraService|If different from the Web URL"
-msgstr ""
+msgstr "如果與 Web URL ä¸åŒ"
msgid "JiraService|In order to complete the set up, you’ll need to complete a few steps in GitLab."
msgstr "為了完æˆè¨­å®šï¼Œæ‚¨å¿…須在 GitLab 中完æˆå¹¾å€‹æ­¥é©Ÿã€‚"
@@ -23916,7 +24297,7 @@ msgid "JiraService|Open Jira"
msgstr "é–‹å•Ÿ Jira"
msgid "JiraService|Password for the server version or an API token for the cloud version"
-msgstr ""
+msgstr "æœå‹™å™¨ç‰ˆæœ¬çš„密碼或雲版本的 API 權æ–令牌"
msgid "JiraService|Password or API token"
msgstr "密碼或 API 令牌"
@@ -23952,10 +24333,10 @@ msgid "JiraService|Use custom transitions"
msgstr "使用自訂轉æ›"
msgid "JiraService|Username for the server version or an email for the cloud version"
-msgstr ""
+msgstr "æœå‹™å™¨ç‰ˆæœ¬çš„使用者å稱或雲版本的電å­éƒµä»¶"
msgid "JiraService|Username or email"
-msgstr ""
+msgstr "使用者å稱或電å­éƒµä»¶"
msgid "JiraService|Using Jira for issue tracking?"
msgstr "使用 Jira 追蹤å•é¡Œï¼Ÿ"
@@ -24023,9 +24404,24 @@ msgstr "作業已é‡è©¦"
msgid "JobAssistant|Add job"
msgstr "增加作業"
+msgid "JobAssistant|Job Setup"
+msgstr "作業設定"
+
msgid "JobAssistant|Job assistant"
msgstr "作業助手"
+msgid "JobAssistant|Job name"
+msgstr "作業å稱"
+
+msgid "JobAssistant|Script"
+msgstr "指令稿"
+
+msgid "JobAssistant|Stage (optional)"
+msgstr "階段(é¸æ“‡æ€§ï¼‰"
+
+msgid "JobAssistant|Tags (optional)"
+msgstr "標籤(é¸æ“‡æ€§ï¼‰"
+
msgid "Jobs"
msgstr "作業"
@@ -24712,6 +25108,15 @@ msgstr "了解更多。"
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
msgstr "%{percentage}%{percentSymbol} 已完æˆ"
+msgid "LearnGitLab|1. Add code to your project"
+msgstr "1.加入程å¼ç¢¼åˆ°æ‚¨çš„專案"
+
+msgid "LearnGitLab|2. Build"
+msgstr "2.構建"
+
+msgid "LearnGitLab|Add code"
+msgstr "加入程å¼ç¢¼"
+
msgid "LearnGitLab|Add code owners"
msgstr "加入程å¼ç¢¼æ‰€æœ‰è€…"
@@ -24793,6 +25198,9 @@ msgstr "設定您的工作å€"
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "開始å…費試用 GitLab 旗艦版"
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr "從 WebIDE 開始"
+
msgid "LearnGitLab|Submit a merge request (MR)"
msgstr "æ交åˆä½µè«‹æ±‚ (MR)"
@@ -24802,6 +25210,9 @@ msgstr "å…費試用旗艦版"
msgid "LearnGitLab|Try all GitLab features for 30 days, no credit card required."
msgstr "試用所有 GitLab 功能 30 天,無需信用å¡ã€‚"
+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 "使用您的新 GitLab 工作æµç¨‹éƒ¨ç½²æ‚¨çš„應用程å¼ã€ç›£æŽ§å…¶é‹è¡Œç‹€æ³ä¸¦ç¢ºä¿å…¶å®‰å…¨ï¼š"
@@ -24817,9 +25228,6 @@ msgstr "è«‹è¯çµ¡æ‚¨çš„管ç†å“¡ä»¥å•Ÿç”¨æ­¤å‹•ä½œã€‚"
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr "è«‹è¯ç¹«æ‚¨çš„管ç†å“¡ä»¥é–‹å§‹å…費的 Ultimate 試用。"
-msgid "LearnGitlab|Creating your onboarding experience..."
-msgstr "正在建立您的入門體驗..."
-
msgid "LearnGitlab|Ok, let's go"
msgstr "好的,讓我們繼續"
@@ -24835,6 +25243,9 @@ msgstr "退出管ç†å“¡æ¨¡å¼"
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr "退出編輯模å¼ï¼Ÿæ‰€æœ‰æœªå„²å­˜çš„變更都將éºå¤±ã€‚"
+msgid "Leave feadback."
+msgstr "留下æ„見。"
+
msgid "Leave group"
msgstr "退出群組"
@@ -25078,6 +25489,10 @@ msgstr "é™åˆ¶å„²å­˜åœ¨Redis中的Sidekiq作業的大å°ã€‚"
msgid "Limiting mode"
msgstr "é™åˆ¶æ¨¡å¼"
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+
msgid "Line changes"
msgstr "變更的行"
@@ -25105,6 +25520,9 @@ msgstr "從專案的å´é‚Šæ¬„連çµå¤–部 wiki。 %{docs_link}"
msgid "Link copied"
msgstr "連çµå·²è¤‡è£½"
+msgid "Link does not exist"
+msgstr ""
+
msgid "Link text"
msgstr "連çµæ–‡å­—"
@@ -25198,9 +25616,6 @@ msgstr "列出å¯ç”¨ç‰ˆæœ¬åº«"
msgid "List of all commits"
msgstr "所有æ交清單"
-msgid "List of all merge commits"
-msgstr "所有åˆä½µæ交列表"
-
msgid "List of suitable GCP locations"
msgstr "åˆé©çš„ GCP ä½ç½®åˆ—表"
@@ -25243,6 +25658,9 @@ msgstr "載入群組æˆå“¡çš„è²¢ç»çµ±è¨ˆè¨Šæ¯"
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr "載入æ交引用%{ref}路徑%{path}中的文件,目錄和å­æ¨¡çµ„"
+msgid "Loading full blame..."
+msgstr "載入所有的究責 (blame)..."
+
msgid "Loading more"
msgstr "載入更多"
@@ -25282,6 +25700,9 @@ msgstr "鎖定文件?"
msgid "Lock memberships to LDAP synchronization"
msgstr "鎖定æˆå“¡èº«ä»½åˆ°LDAPåŒæ­¥"
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
msgid "Lock merge request"
msgstr "鎖定åˆä½µè«‹æ±‚"
@@ -25300,9 +25721,6 @@ msgstr "鎖定到當å‰å°ˆæ¡ˆ"
msgid "Locked"
msgstr "已鎖定"
-msgid "Locked Files"
-msgstr "已鎖定文件"
-
msgid "Locked by %{fileLockUserName}"
msgstr "被%{fileLockUserName}鎖定"
@@ -25372,9 +25790,6 @@ msgstr "MD5"
msgid "MERGED"
msgstr "å·²åˆä½µ"
-msgid "ML Experiments"
-msgstr "ML 實驗"
-
msgid "MR widget|Back to the merge request"
msgstr "返回åˆä½µè«‹æ±‚"
@@ -25411,11 +25826,8 @@ msgstr "åªæŸ¥çœ‹è®Šæ›´å…§å®¹"
msgid "MRDiff|Show full file"
msgstr "顯示全部文件"
-msgid "Machine Learning Experiment Tracking is in Incubating Phase"
-msgstr "機器學習(ML)實驗追踪處於孵化階段"
-
-msgid "Machine Learning Experiments"
-msgstr "機器學習(ML)實驗"
+msgid "Macbook Touch ID on Edge"
+msgstr "Edge 上的 Macbook Touch ID"
msgid "Made this %{type} confidential."
msgstr "將該 %{type} 設為機密。"
@@ -25811,7 +26223,7 @@ msgid "Maximum file size is 1 MB. Pages are optimized for a 128x128 px logo."
msgstr "最大檔案大å°ç‚º 1 MB。é é¢é‡å° 128x128 畫素的標誌圖示進行了最佳化。"
msgid "Maximum file size is 1MB."
-msgstr ""
+msgstr "最大文件大å°ç‚º 1MB。"
msgid "Maximum file size is 1MB. Pages are optimized for a 24px tall header logo"
msgstr "最大文件大å°ç‚º 1MB。 é é¢é‡å° 24 åƒç´ çš„標題 logo 進行了優化"
@@ -25906,6 +26318,9 @@ msgstr "最大推é€å¤§å°"
msgid "Maximum push size (MB)"
msgstr "最大推é€å¤§å° (MB)"
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
msgid "Maximum requests per 10 minutes per user"
msgstr "æ¯å€‹ä½¿ç”¨è€…10分é˜å…§çš„最大請求數"
@@ -25987,12 +26402,21 @@ 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 "MemberRole|%{role} - custom"
+msgstr "%{role} - 自定義"
+
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|must be top-level namespace"
msgstr "必須是最上層的命å空間"
@@ -26211,18 +26635,9 @@ msgstr "自動åˆä½µ(%{strategy})"
msgid "Merge blocked: all merge request dependencies must be merged."
msgstr "åˆä½µç¦æ­¢ï¼šå¿…é ˆåˆä½µæ‰€æœ‰åˆä½µè«‹æ±‚ä¾è³´é …。"
-msgid "Merge blocked: merge request must be marked as ready. It's still marked as draft."
-msgstr "åˆä½µè¢«ç¦æ­¢ï¼šåˆä½µè«‹æ±‚必須標記為就緒。它ä»ç„¶è¢«æ¨™è¨˜ç‚ºè‰ç¨¿ã€‚"
-
-msgid "Merge blocked: new changes were just added."
-msgstr "åˆä½µè¢«ç¦æ­¢ï¼šå‰›å‰›åŠ å…¥äº†æ–°çš„更改。"
-
msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
msgstr "åˆä½µå·²ç¦æ­¢ï¼šæµæ°´ç·šå¿…é ˆæˆåŠŸã€‚正在等待手動作業繼續。"
-msgid "Merge blocked: the source branch must be rebased onto the target branch."
-msgstr "åˆä½µç¦æ­¢ï¼šä¾†æºåˆ†æ”¯å¿…須變基 (Rebase) 到目標分支。"
-
msgid "Merge commit SHA"
msgstr "åˆä½µæ交SHA"
@@ -26295,9 +26710,6 @@ msgstr "åˆä½µè«‹æ±‚用於æ出å°å°ˆæ¡ˆçš„變更並與他人進行討論"
msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
msgstr "若狀態檢查未æˆåŠŸæˆ–ä»åœ¨åŸ·è¡Œä¸­ï¼Œå‰‡ç„¡æ³•åˆä½µåˆä½µè«‹æ±‚。"
-msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
-msgstr "åˆä½µä¸å¯ç”¨ï¼šåˆä½µè«‹æ±‚åœ¨æ¬¡è¦ Geo 節點中是唯讀的。"
-
msgid "Merge unverified changes"
msgstr "åˆä½µæœªç¶“驗證的更改"
@@ -26310,6 +26722,27 @@ 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 "該設定在群組 %{groupName} 中é…置,並且åªèƒ½ç”±ç®¡ç†å“¡æˆ–群組æ“有者在群組設定中更改。"
+
msgid "MergeConflict|Commit to source branch"
msgstr "æ交到æºåˆ†æ”¯"
@@ -26918,6 +27351,9 @@ msgstr[0] "里程碑"
msgid "Milestone due date"
msgstr "里程碑截止日期"
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr "未找到里程碑 ID: %{milestones}"
+
msgid "Milestone lists not available with your current license"
msgstr "ç›®å‰æŽˆæ¬Šæ¢æ¬¾ç„¡æ³•ä½¿ç”¨é‡Œç¨‹ç¢‘列表"
@@ -27098,6 +27534,12 @@ msgstr "在我們é å…ˆå®‰æŽ’更多映åƒä¹‹å‰å¯ç”¨çš„最å°å®¹é‡ã€‚"
msgid "Minutes"
msgstr "分é˜"
+msgid "Mirror all branches"
+msgstr "é¡åƒæ‰€æœ‰åˆ†æ”¯"
+
+msgid "Mirror branches"
+msgstr "é¡åƒåˆ†æ”¯"
+
msgid "Mirror direction"
msgstr "é¡åƒæ–¹å‘"
@@ -27110,6 +27552,9 @@ msgstr "é¡åƒç‰ˆæœ¬åº«"
msgid "Mirror settings are only available to GitLab administrators."
msgstr "é¡åƒè¨­å®šåƒ…GitLab管ç†å“¡å¯ç”¨ã€‚"
+msgid "Mirror specific branches"
+msgstr "é¡åƒç‰¹å®šåˆ†æ”¯"
+
msgid "Mirror user"
msgstr "é¡åƒä½¿ç”¨è€…"
@@ -27170,33 +27615,48 @@ msgstr "-"
msgid "MlExperimentTracking|Artifacts"
msgstr "產物"
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr "建立新實驗"
+
msgid "MlExperimentTracking|Created at"
msgstr "建立於"
msgid "MlExperimentTracking|Details"
msgstr "詳細"
+msgid "MlExperimentTracking|Experiment"
+msgstr "實驗"
+
msgid "MlExperimentTracking|Experiment candidates"
msgstr "實驗候é¸äºº"
msgid "MlExperimentTracking|Filter candidates"
msgstr "篩é¸å€™é¸äºº"
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr "已記錄的候é¸å¯¦é©—"
+
msgid "MlExperimentTracking|Machine learning experiment tracking"
msgstr "機器學習實驗追踪"
+msgid "MlExperimentTracking|Model experiments"
+msgstr "模型實驗"
+
msgid "MlExperimentTracking|Name"
msgstr "å稱"
msgid "MlExperimentTracking|No candidates to display"
msgstr "沒有å¯é¡¯ç¤ºçš„候é¸è€…"
+msgid "MlExperimentTracking|No experiments"
+msgstr "沒有實驗"
+
+msgid "MlExperimentTracking|There are no logged experiments for this project. Create a new experiment using the MLflow client."
+msgstr "該專案沒有已記錄的實驗,使用 MLflow 客戶端建立新實驗。"
+
msgid "MlExperimentTracking|User"
msgstr "使用者"
-msgid "MlExperimentsEmptyState|No Experiments to Show"
-msgstr "沒有實驗å¯ä»¥å±•ç¤º"
-
msgid "Modal updated"
msgstr "模態更新"
@@ -27276,7 +27736,7 @@ msgid "More information."
msgstr "更多訊æ¯ã€‚"
msgid "More options"
-msgstr ""
+msgstr "更多é¸é …"
msgid "More than %{number_commits_distance} commits different with %{default_branch}"
msgstr "è¶…å‰ %{number_commits_distance} 個æ交與 %{default_branch} ä¸åŒ"
@@ -27402,7 +27862,7 @@ msgid "My company or team"
msgstr "我的公å¸æˆ–團隊"
msgid "My saved replies (%{count})"
-msgstr ""
+msgstr "我留存的回復 (%{count})"
msgid "My topic"
msgstr "我的主題"
@@ -27417,7 +27877,7 @@ msgid "Name"
msgstr "å稱"
msgid "Name can contain only lowercase or uppercase letters, digits, emojis, spaces, dots, underscores, dashes, or pluses."
-msgstr ""
+msgstr "å稱åªèƒ½åŒ…å«å°å¯«æˆ–大寫字æ¯ã€æ•¸å­—ã€è¡¨æƒ…符號ã€ç©ºæ ¼ã€é»žã€ä¸‹åŠƒç·šã€ç ´æŠ˜è™Ÿæˆ–加號。"
msgid "Name can't be blank"
msgstr "å稱ä¸èƒ½ç‚ºç©º"
@@ -27429,7 +27889,7 @@ msgid "Name is already taken."
msgstr "å稱已被佔用。"
msgid "Name must start with a letter, digit, emoji, or underscore."
-msgstr ""
+msgstr "å稱必須以字æ¯ã€æ•¸å­—ã€è¡¨æƒ…符號或下劃線開頭。"
msgid "Name new label"
msgstr "命å新標記"
@@ -27537,6 +27997,9 @@ msgstr "命å空間"
msgid "Namespaces to index"
msgstr "è¦ç´¢å¼•çš„命å空間"
+msgid "Naming"
+msgstr "命å"
+
msgid "Naming, topics, avatar"
msgstr "命å,主題,頭åƒ"
@@ -27585,11 +28048,17 @@ msgstr "紅色"
msgid "Navigation|Context navigation"
msgstr "上下文導覽"
-msgid "Navigation|Recent groups"
-msgstr "最近的群組"
+msgid "Navigation|FREQUENT GROUPS"
+msgstr ""
-msgid "Navigation|Recent projects"
-msgstr "最近的專案"
+msgid "Navigation|FREQUENT PROJECTS"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
+msgstr ""
msgid "Navigation|Switch to..."
msgstr "切æ›è‡³â€¦â€¦"
@@ -27700,9 +28169,6 @@ msgstr "新增需求"
msgid "New Snippet"
msgstr "新增程å¼ç¢¼ç‰‡æ®µ"
-msgid "New Test Case"
-msgstr "新增測試案例"
-
msgid "New User"
msgstr "新增使用者"
@@ -27790,9 +28256,6 @@ msgstr "新增å稱"
msgid "New password"
msgstr "新密碼"
-msgid "New pipelines cause older pending or running pipelines on the same branch to be cancelled."
-msgstr "æ–°æµæ°´ç·šæœƒå°Žè‡´åŒä¸€åˆ†æ”¯ä¸Šè¼ƒèˆŠçš„待處ç†æˆ–正在é‹è¡Œçš„æµæ°´ç·šè¢«å–消。"
-
msgid "New project"
msgstr "新建專案"
@@ -28147,6 +28610,15 @@ 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 "未é¸æ“‡ä¾†æº"
@@ -28229,14 +28701,17 @@ msgstr "導覽é‡æ–°è¨­å®š"
msgid "NorthstarNavigation|New navigation"
msgstr "新導覽"
+msgid "NorthstarNavigation|Provide feedback"
+msgstr "æ供回饋"
+
msgid "NorthstarNavigation|Toggle new navigation"
msgstr "切æ›æ–°å°Žè¦½"
-msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
-msgstr "並éžæ‰€æœ‰ç€è¦½å™¨éƒ½æ”¯æ´ U2F è£ç½®ï¼Œå› æ­¤æˆ‘們è¦æ±‚您設定雙因å­é©—證程å¼ã€‚這樣å³ä½¿æ‚¨ä½¿ç”¨ä¸æ”¯æ´çš„ç€è¦½å™¨ä¹Ÿå¯ä»¥ç™»å…¥ã€‚"
+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. 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 "並éžæ‰€æœ‰ç€è¦½å™¨éƒ½æ”¯æ´ WebAuthn,因此我們è¦æ±‚您設定雙因å­é©—證程å¼ã€‚這樣å³ä½¿æ‚¨ä½¿ç”¨ä¸æ”¯æ´çš„ç€è¦½å™¨ä¹Ÿå¯ä»¥ç™»å…¥ã€‚"
+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 "並éžæ‰€æœ‰ç€è¦½å™¨éƒ½æ”¯æ´ WebAuthn,首次註冊雙因å­â€‹â€‹èº«ä»½é©—證後,您必須ä¿å­˜æ‚¨çš„回復碼æ‰èƒ½ç™»å…¥ï¼Œå³ä½¿æ˜¯ä½¿ç”¨ä¸å—支æ´çš„ç€è¦½å™¨ä¹Ÿæ˜¯å¦‚此。"
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr "尚未處ç†æ‰€æœ‰è³‡æ–™ï¼Œå› æ­¤æ‰€é¸æ™‚間範åœå…§åœ–表的ä¸ä¸€å®šå®Œå…¨æº–確。"
@@ -28317,7 +28792,7 @@ 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 ""
+msgstr "附件通éŽé›»å­éƒµä»¶ç™¼é€ï¼Œè¶…éŽ 10 MB 的附件將以éˆçµåˆ°æ‚¨ GitLab 實例的形å¼å¯„é€ï¼Œä¸¦ä¸”僅供專案æˆå“¡å­˜å–。"
msgid "Notes|Collapse replies"
msgstr "收起復原"
@@ -28533,12 +29008,24 @@ msgstr "%{paragraph_start}å—¨ %{name}!%{paragraph_end} %{paragraph_start}æ–°çš„å
msgid "Notify|%{project_link_start}Download%{project_link_end} the project export."
msgstr "%{project_link_start}下載%{project_link_end}匯出的專案。"
+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|%{update_at_start} Last update at %{update_at_mid} %{last_update_at} %{update_at_end}"
msgstr "%{update_at_start} 最後更新時間為 %{update_at_mid} %{last_update_at} %{update_at_end}"
msgid "Notify|%{updated_by_user_name} pushed new commits to merge request %{mr_link}"
msgstr "%{updated_by_user_name} 推é€æ–°çš„æ交到 %{mr_link} åˆä½µè«‹æ±‚"
+msgid "Notify|%{work_items} successfully imported."
+msgstr ""
+
msgid "Notify|A new GPG key was added to your account:"
msgstr "有支新的 GPG 金鑰已加至您的帳號:"
@@ -28587,9 +29074,18 @@ msgstr "è§£æž CSV 文件時出錯。請確ä¿å®ƒå…·æœ‰æ­£ç¢ºçš„æ ¼å¼ï¼šä½¿ç”¨é
msgid "Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check if these lines have an issue title."
msgstr "在 %{singular_or_plural_line} 上發ç¾éŒ¯èª¤ï¼š%{error_lines}。請檢查這些行是å¦æœ‰è­°é¡Œæ¨™é¡Œã€‚"
+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 "指紋:%{fingerprint}"
+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 "å—¨ %{username}!"
@@ -28617,9 +29113,6 @@ msgstr "日誌å¯èƒ½åŒ…å«æ•æ„Ÿè³‡æ–™ï¼Œè«‹åœ¨è½‰å¯„該電å­éƒµä»¶ä¹‹å‰è€ƒæ…®
msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict."
msgstr "由於è¡çªï¼Œç„¡æ³•å†åˆä½µåˆä½µè«‹æ±‚ %{merge_request}。"
-msgid "Notify|Merge request %{merge_request} was %{mr_status}"
-msgstr "åˆä½µè«‹æ±‚ %{merge_request} 為 %{mr_status}"
-
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
msgstr "åˆä½µè«‹æ±‚ %{merge_request} 為 %{mr_status},由 %{updated_by} æ›´æ–°"
@@ -28656,6 +29149,9 @@ msgstr "新議題: %{project_issue_url}"
msgid "Notify|No preview for this file type"
msgstr "該文件類型無法é è¦½"
+msgid "Notify|No work items have been imported."
+msgstr ""
+
msgid "Notify|Pipeline #%{pipeline_id} has failed!"
msgstr "#%{pipeline_id} æµæ°´ç·šå¤±æ•—ï¼"
@@ -28665,6 +29161,9 @@ msgstr "æµæ°´ç·š %{pipeline_link} 的觸發者為"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
msgstr "æµæ°´ç·šå·²ä¿®å¾©ï¼Œ#%{pipeline_id} 已通éŽï¼"
+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 "專案 %{old_path_with_namespace} 已移到其他ä½ç½®ã€‚"
@@ -28677,6 +29176,9 @@ msgstr "專案 %{project_name} å·²æˆåŠŸåŒ¯å‡ºã€‚"
msgid "Notify|Remote mirror"
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 "管ç†å“¡å·²ç‚ºæ‚¨å»ºç«‹äº†ä¸€å€‹å¸³è™Ÿï¼Œç¾åœ¨æ‚¨æ˜¯å…¬å¸ GitLab 應用程å¼çš„æˆå“¡ã€‚"
@@ -29152,6 +29654,9 @@ msgstr "On-demand 掃æ在DevOps週期之外é‹è¡Œï¼Œä¸¦åœ¨æ‚¨çš„專案中發ç
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 "é‡è¤‡"
@@ -29221,9 +29726,6 @@ msgstr "時å€"
msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
msgstr "無法讀å–執行器標籤,嘗試é‡æ–°è¼‰å…¥è©²é é¢ã€‚"
-msgid "OnDemandScans|Verify"
-msgstr ""
-
msgid "OnDemandScans|Verify configuration"
msgstr "組態確èª"
@@ -29516,29 +30018,35 @@ 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 services."
-msgstr "å…許來自掛鉤(hooks)å’Œæœå‹™å°æœ¬åœ°ç¶²è·¯çš„請求。"
+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 "å…許系統掛鉤(hooks)å‘本地網路發é€è«‹æ±‚"
-msgid "OutboundRequests|Allow requests to the local network from web hooks and services"
-msgstr "å…許來自 web hooks å’Œæœå‹™å°æœ¬åœ°ç¶²è·¯çš„請求"
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
+msgstr ""
-msgid "OutboundRequests|Enforce DNS rebinding attack protection"
-msgstr "強制執行 DNS é‡æ–°ç¶å®šæ”»æ“Šä¿è­·"
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
+msgstr ""
-msgid "OutboundRequests|Local IP addresses and domain names that hooks and services may access"
-msgstr "掛鉤和æœå‹™å¯ä»¥å­˜å–的本地IP地å€å’Œç¶²åŸŸã€‚"
+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 to these domains and IP addresses are accessible to both system hooks and web hooks even when local requests are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 and 127.0.0.0/28 are supported. Domain wildcards are not supported. To separate entries use commas, semicolons, or newlines. The allowlist can hold a maximum of 1000 entries. Domains must be IDNA encoded."
-msgstr "å³ä½¿ä¸å…許本地請求,系統 hook å’Œ Webhook 也å¯ä»¥å­˜å–å°é€™äº›ç¶²åŸŸå’Œ IP 地å€çš„è«‹æ±‚ã€‚æ”¯æ´ 1:0:0:0:0:0:0:0/124 å’Œ 127.0.0.0/28 ç­‰ IP 範åœã€‚ä¸æ”¯æ´åŸŸå通é…符。è¦åˆ†éš”æ¢ç›®ï¼Œè«‹ä½¿ç”¨é€—號ã€åˆ†è™Ÿæˆ–æ›è¡Œç¬¦ã€‚å…許列表最多å¯åŒ…å« 1000 個æ¢ç›®ã€‚網域å必須是 IDNA 編碼的。"
+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|Resolve IP addresses once and uses them to submit requests."
-msgstr "解æžIP地å€ä¸¦ä½¿ç”¨å®ƒå€‘æ交請求。"
+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 "GitLabå¯èƒ½ç„¡æ³•æ­£å¸¸å·¥ä½œï¼Œå› ç‚ºæ‚¨æ­£åœ¨ä½¿ç”¨éŽæ™‚çš„ç€è¦½å™¨ã€‚"
@@ -29637,7 +30145,7 @@ msgid "Package type"
msgstr "軟體套件(Package)類型"
msgid "Package type must be Composer"
-msgstr ""
+msgstr "軟體套件(Package)類型必須是Composer"
msgid "Package type must be Conan"
msgstr "軟體套件(Package)類型必須是Conan"
@@ -29960,10 +30468,10 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr "軟體套件由分支%{branch}上的%{link}æ交所更新,由æµæ°´ç·š%{pipeline}構建並於%{datetime}發布到庫"
msgid "PackageRegistry|Packages and assets cleanup is ready to be executed when the next cleanup job runs."
-msgstr ""
+msgstr "軟體套件包和資產清ç†æº–備好在下一個清ç†ä½œæ¥­åŸ·è¡Œæ™‚é‹ä½œã€‚"
msgid "PackageRegistry|Packages and assets will not be deleted until cleanup runs in %{nextRunAt}."
-msgstr ""
+msgstr "在 %{nextRunAt} 中執行清ç†ä¹‹å‰ï¼Œè»Ÿé«”套件包與資產ä¸æœƒè¢«åˆªé™¤ã€‚"
msgid "PackageRegistry|Packages deleted successfully"
msgstr "æˆåŠŸåˆªé™¤è»Ÿé«”套件"
@@ -30330,6 +30838,9 @@ msgstr "等待刪除"
msgid "Pending comments"
msgstr "待處ç†çš„留言"
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
msgid "Pending deletion"
msgstr "等待刪除"
@@ -30519,9 +31030,6 @@ msgstr "您已é”到最大嘗試次數,請等待 %{interval} 後é‡è©¦ã€‚"
msgid "Pick a name"
msgstr "é¸æ“‡ä¸€å€‹å稱"
-msgid "Pin code"
-msgstr "Pin碼"
-
msgid "Pipeline"
msgstr "æµæ°´ç·š"
@@ -30720,6 +31228,9 @@ msgstr "等待載入 CI 內容..."
msgid "PipelineGraph|Are you sure you want to retry %{jobName}?"
msgstr "您確定è¦é‡è©¦ %{jobName}嗎?"
+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 "é‡è©¦è§¸ç™¼ä½œæ¥­å°‡å»ºç«‹ä¸€å€‹æ–°çš„下游æµæ°´ç·šã€‚"
@@ -30945,6 +31456,9 @@ 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 "「%{project_name}ã€çš„æµæ°´ç·šè¨­å®šå·²æˆåŠŸæ›´æ–°ã€‚"
@@ -30996,9 +31510,6 @@ msgstr "å­æµæ°´ç·šï¼ˆ%{link_start}父æµæ°´ç·š%{link_end})"
msgid "Pipelines|Clear runner caches"
msgstr "清除Runner緩存"
-msgid "Pipelines|Configuration validation currently not available."
-msgstr "設定驗證目å‰ä¸å¯ç”¨ã€‚"
-
msgid "Pipelines|Configure pipeline"
msgstr "é…ç½®æµæ°´ç·š"
@@ -31044,6 +31555,12 @@ msgstr "GitLab Runner 是一個與 GitLab CI/CD 一起使用在æµæ°´ç·šä¸­åŸ·è¡
msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. There are active runners available to run your jobs right now. If you prefer, you can %{settingsLinkStart}configure your runners%{settingsLinkEnd} or %{docsLinkStart}learn more%{docsLinkEnd} about runners."
msgstr "GitLab Runner 是一個與 GitLab CI/CD åˆä½œåœ¨æµæ°´ç·šä¸­é‹è¡Œä½œæ¥­çš„應用程å¼ã€‚ç¾åœ¨æœ‰å•Ÿç”¨çš„ runner å¯ä»¥é‹è¡Œæ‚¨çš„作業。您å¯ä»¥%{settingsLinkStart}設定您的 runner%{settingsLinkEnd} 或%{docsLinkStart}了解更多關於 runner 的訊æ¯%{docsLinkEnd}。"
+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 "如果您ä¸ç¢ºå®šï¼Œè«‹å°ˆæ¡ˆç¶­è­·è€…為您審核。"
@@ -31095,8 +31612,8 @@ msgstr "所有者"
msgid "Pipelines|Pipeline Editor"
msgstr "æµæ°´ç·šç·¨è¼¯å™¨"
-msgid "Pipelines|Pipeline syntax is correct."
-msgstr "æµæ°´ç·šèªžæ³•æ­£ç¢ºã€‚"
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr "專案快å–é‡è¨­æˆåŠŸã€‚"
@@ -31104,6 +31621,9 @@ msgstr "專案快å–é‡è¨­æˆåŠŸã€‚"
msgid "Pipelines|Ready to set up CI/CD for your project?"
msgstr "準備好為您的專案設定 CI/CD 嗎?"
+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|Revoke trigger"
msgstr "撤銷觸發器"
@@ -31140,14 +31660,14 @@ 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."
-msgstr "此GitLab CI設定無效。"
+msgid "Pipelines|This GitLab CI configuration is invalid. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is invalid:"
msgstr "此GitLab CI設定無效:"
-msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}."
-msgstr "此GitLab CI設定無效:%{reason}。"
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
msgid "Pipelines|This GitLab CI configuration is valid."
msgstr "此GitLab CI設定有效。"
@@ -31176,6 +31696,12 @@ 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 "使用 %{codeStart}.gitlab-ci.yml%{codeEnd} 範本文件來探索CI/CD 如何工作。"
@@ -31197,6 +31723,9 @@ msgstr "查看åˆä½µçš„ YAML"
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 "我們將指導您完æˆä¸€å€‹ç°¡å–®çš„æµæ°´ç·šè¨­å®šã€‚"
@@ -31206,6 +31735,9 @@ msgstr "我們將通éŽå…©å€‹ç°¡å–®çš„步驟å‘您介紹如何部署到 iOS。"
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|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr "您的更改已æˆåŠŸæ交,ç¾åœ¨é‡å®šå‘到新的åˆä½µè«‹æ±‚é é¢ã€‚"
@@ -31327,7 +31859,7 @@ msgid "Pipeline|Specify variable values to be used in this run. The values speci
msgstr "指定è¦åœ¨æ­¤æ¬¡åŸ·è¡Œä¸­ä½¿ç”¨çš„變數值。%{linkStart}CI/CD設定%{linkEnd}中指定的值將用作é è¨­å€¼."
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 ""
+msgstr "指定è¦åœ¨æ­¤åŸ·è¡Œä¸­ä½¿ç”¨çš„變數值,é è¨­æƒ…æ³ä¸‹ä½¿ç”¨çµ„æ…‹é…ç½®æ–‡ä»¶ä»¥åŠ %{linkStart}CI/CD 設定%{linkEnd}中指定的變數。"
msgid "Pipeline|Stages"
msgstr "階段"
@@ -31521,6 +32053,9 @@ msgstr "如果您想é™ç´šåˆ°æ¨™æº–版,請刪除您當å‰çš„授權許å¯ã€‚"
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "請啟用並é·ç§»åˆ°æ•£åˆ—儲存以é¿å…安全å•é¡Œä¸¦ç¢ºä¿è³‡æ–™å®Œæ•´æ€§ã€‚%{migrate_link}"
+msgid "Please enter a name for the saved reply."
+msgstr "請輸入已儲存的回復å稱."
+
msgid "Please enter a non-negative number"
msgstr "請輸入一個éžè² æ•¸"
@@ -31542,6 +32077,9 @@ msgstr "請輸入有效的時間間隔"
msgid "Please enter a value of 90 days or more"
msgstr "請輸入 90 天或以上的值"
+msgid "Please enter the saved reply content."
+msgstr "請輸入已儲存的回復內容。"
+
msgid "Please enter your current password."
msgstr "請輸入您的當å‰å¯†ç¢¼ã€‚"
@@ -31602,8 +32140,8 @@ msgstr "è«‹é¸æ“‡"
msgid "Please select a Jira project"
msgstr "è«‹é¸æ“‡ä¸€å€‹Jira專案"
-msgid "Please select a country"
-msgstr "è«‹é¸æ“‡åœ‹å®¶/地å€"
+msgid "Please select a country / region"
+msgstr "è«‹é¸æ“‡ 國家/地å€"
msgid "Please select a group"
msgstr "è«‹é¸æ“‡ä¸€å€‹ç¾¤çµ„"
@@ -31956,6 +32494,9 @@ msgstr "é è¦½åœ–"
msgid "Preview payload"
msgstr "é è¦½ä¸Šå‚³è³‡æ–™"
+msgid "Previous"
+msgstr "之å‰çš„"
+
msgid "Previous Artifacts"
msgstr "å‰ä¸€å€‹ç”¢ç‰©"
@@ -32025,150 +32566,90 @@ msgstr "%{name} 指令發生錯誤: %{message}。"
msgid "Proceed"
msgstr "繼續"
-msgid "Product Analytics|Add the NPM package to your package.json using your preferred package manager:"
-msgstr "使用您å好的軟體包管ç†ç¨‹å¼å°‡ NPM 軟體包新增至 package.json:"
-
-msgid "Product Analytics|Add the script to the page and assign the client SDK to window:"
-msgstr "在é é¢ä¸­æ–°å¢žæŒ‡ä»¤ç¨¿ï¼Œä¸¦å°‡å®¢æˆ¶ç«¯ SDK 指派給視窗:"
-
-msgid "Product Analytics|Analyze your product with Product Analytics"
-msgstr "使用 Product Analytics 分æžæ‚¨çš„產å“"
-
-msgid "Product Analytics|Back to dashboards"
-msgstr "返回儀表æ¿"
-
-msgid "Product Analytics|Creating your product analytics instance..."
-msgstr "建立您的產å“分æžç«™å°â€¦â€¦"
-
-msgid "Product Analytics|Details on how to configure product analytics to collect data."
-msgstr "關於如何設定產å“分æžä»¥æ”¶é›†è³‡æ–™çš„詳細信æ¯ã€‚"
-
-msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
-msgstr "è¦è®“產å“分æžå„€è¡¨æ¿é–‹å§‹å‘您顯示資料,您必須將分æžè¿½è¹¤ç¨‹å¼ç¢¼æ–°å¢žè‡³æ‚¨çš„專案中。"
-
-msgid "Product Analytics|Identifies the sender of tracking events"
-msgstr "辨識追蹤事件的傳é€è€…"
-
-msgid "Product Analytics|Import the new package into your JS code:"
-msgstr "將新的軟體包匯入您的 JS 程å¼ç¢¼ï¼š"
-
-msgid "Product Analytics|Instrument your application"
-msgstr "檢測您的應用程å¼"
-
-msgid "Product Analytics|Instrumentation details"
-msgstr "儀表細節"
-
-msgid "Product Analytics|SDK App ID"
-msgstr "SDK App ID"
-
-msgid "Product Analytics|SDK Host"
-msgstr "SDK 主機"
-
-msgid "Product Analytics|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 "設定 Product Analytics 以追蹤您產å“的表ç¾ï¼Œå°‡å…¶èˆ‡æ‚¨çš„ GitLan 資料çµåˆï¼Œä»¥æ›´åŠ äº†è§£æ‚¨å¯ä»¥åœ¨å“ªäº›æ–¹é¢æ”¹å–„您的產å“與開發æµç¨‹ã€‚"
-
-msgid "Product Analytics|Set up product analytics"
-msgstr "設定產å“分æž"
-
-msgid "Product Analytics|Steps to add product analytics as a CommonJS module"
-msgstr "將產å“分æžæ–°å¢žç‚º CommonJS 模組的步驟"
-
-msgid "Product Analytics|Steps to add product analytics as a HTML script tag"
-msgstr "將產å“分æžæ–°å¢žç‚º HTML 指令稿標籤的步驟"
-
-msgid "Product Analytics|Steps to add product analytics as an ESM module"
-msgstr "將產å“分æžæ–°å¢žç‚º ESM 模組的步驟"
-
-msgid "Product Analytics|The host to send all tracking events to"
-msgstr "所有追蹤事件傳é€åˆ°çš„主機"
-
-msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later."
-msgstr "這å¯èƒ½éœ€è¦ä¸€æ®µæ™‚間,您隨時å¯ä»¥é›¢é–‹æ­¤é é¢ï¼Œç¨å¾Œå†å›žä¾†ã€‚"
-
-msgid "Product Analytics|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 "Product analytics"
msgstr "產å“分æž"
msgid "ProductAnalytics|Add another dimension"
msgstr "新增其他維度"
-msgid "ProductAnalytics|Add to Dashboard"
-msgstr "加入到儀表æ¿"
+msgid "ProductAnalytics|Add the NPM package to your package.json using your preferred package manager:"
+msgstr ""
-msgid "ProductAnalytics|All clicks compared"
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
+msgstr ""
+
+msgid "ProductAnalytics|All Clicks Compared"
msgstr "已比較所有點擊"
-msgid "ProductAnalytics|All events compared"
+msgid "ProductAnalytics|All Events Compared"
msgstr "已比較所有事件"
-msgid "ProductAnalytics|All features"
+msgid "ProductAnalytics|All Features"
msgstr "所有功能"
-msgid "ProductAnalytics|All pages"
+msgid "ProductAnalytics|All Pages"
msgstr "所有é é¢"
+msgid "ProductAnalytics|All Sessions Compared"
+msgstr "已比較所有會話"
+
msgid "ProductAnalytics|An error occured while loading the %{panelTitle} panel."
-msgstr ""
+msgstr "載入 %{panelTitle} é¢æ¿æ™‚發生錯誤。"
msgid "ProductAnalytics|An error occurred while fetching data. Refresh the page to try again."
msgstr "æ“·å–資料時發生錯誤,é‡æ–°æ•´ç†é é¢ä»¥é‡è©¦ã€‚"
+msgid "ProductAnalytics|Analyze your product with Product Analytics"
+msgstr "使用 Product Analytics 分æžæ‚¨çš„產å“"
+
msgid "ProductAnalytics|Any Click on elements"
msgstr "任何在元素上的點擊"
msgid "ProductAnalytics|Audience"
msgstr "觀眾"
-msgid "ProductAnalytics|Browser"
-msgstr "ç€è¦½å™¨"
+msgid "ProductAnalytics|Average Per User"
+msgstr "æ¯å€‹ä½¿ç”¨è€…çš„å¹³å‡å€¼"
-msgid "ProductAnalytics|Browser Family"
-msgstr "ç€è¦½å™¨å®¶æ—"
+msgid "ProductAnalytics|Average Session Duration"
+msgstr "å¹³å‡æœƒè©±æŒçºŒæ™‚é–“"
-msgid "ProductAnalytics|Cancel Edit"
-msgstr "å–消編輯"
+msgid "ProductAnalytics|Average duration in minutes"
+msgstr "å¹³å‡æŒçºŒæ™‚é–“ (分é˜)"
-msgid "ProductAnalytics|Choose a chart type on the right"
-msgstr "é¸æ“‡å³é‚Šçš„圖表類型"
+msgid "ProductAnalytics|Back to dashboards"
+msgstr "返回儀表æ¿"
-msgid "ProductAnalytics|Choose a measurement to start"
-msgstr "é¸æ“‡æ¸¬é‡ä»¥é–‹å§‹"
+msgid "ProductAnalytics|Cancel Edit"
+msgstr "å–消編輯"
msgid "ProductAnalytics|Click Events"
msgstr "點擊事件"
-msgid "ProductAnalytics|Code"
-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 pageviews of all pages against each other"
+msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr "比較所有é é¢çš„ç€è¦½é‡"
-msgid "ProductAnalytics|Dashboards are created by editing the projects dashboard files."
-msgstr "儀表æ¿æ˜¯é€éŽç·¨è¼¯å°ˆæ¡ˆå„€è¡¨æ¿æª”案建立的。"
+msgid "ProductAnalytics|Creating your product analytics instance..."
+msgstr "正在建立您的產å“分æžå¯¦ä¾‹..."
-msgid "ProductAnalytics|Data"
-msgstr "資料"
-
-msgid "ProductAnalytics|Data Table"
-msgstr "資料表格"
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
+msgstr ""
msgid "ProductAnalytics|Dimensions"
msgstr "維度"
-msgid "ProductAnalytics|Edit"
-msgstr "編輯"
-
msgid "ProductAnalytics|Event Type"
msgstr "事件類型"
@@ -32181,23 +32662,32 @@ msgstr "按 %{granularity} 分組的事件"
msgid "ProductAnalytics|Events over time"
msgstr "隨時間變化的事件"
-msgid "ProductAnalytics|Feature Usage"
+msgid "ProductAnalytics|Feature Usages"
msgstr "功能使用狀æ³"
-msgid "ProductAnalytics|Feature usage"
-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|Host"
-msgstr "主機"
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr "一個使用者有多少會話"
-msgid "ProductAnalytics|Language"
-msgstr "語言"
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr "會話é‡è¤‡é »çŽ‡"
-msgid "ProductAnalytics|Line Chart"
-msgstr "折線圖"
+msgid "ProductAnalytics|Identifies the sender of tracking events"
+msgstr "辨識追蹤事件的傳é€è€…"
+
+msgid "ProductAnalytics|Import the new package into your JS code:"
+msgstr "將新的軟體包匯入您的 JS 程å¼ç¢¼ï¼š"
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr "檢測您的應用程å¼"
+
+msgid "ProductAnalytics|Instrumentation details"
+msgstr "儀表細節"
msgid "ProductAnalytics|Measure All tracked Events"
msgstr "測é‡æ‰€æœ‰è¿½è¹¤çš„事件"
@@ -32205,59 +32695,68 @@ msgstr "測é‡æ‰€æœ‰è¿½è¹¤çš„事件"
msgid "ProductAnalytics|Measure all or specific Page Views"
msgstr "測é‡æ‰€æœ‰æˆ–特定é é¢çš„ç€è¦½é‡"
-msgid "ProductAnalytics|Measuring"
-msgstr "測é‡"
+msgid "ProductAnalytics|Measure all sessions"
+msgstr "é‡æ¸¬æ‰€æœ‰æœƒè©±"
-msgid "ProductAnalytics|New Analytics Panel Title"
-msgstr ""
-
-msgid "ProductAnalytics|OS"
-msgstr "作業系統"
+msgid "ProductAnalytics|Measure by unique users"
+msgstr "以ç¨ç«‹ä½¿ç”¨è€…é‡æ¸¬"
-msgid "ProductAnalytics|OS Version"
-msgstr "作業系統版本"
+msgid "ProductAnalytics|Measuring"
+msgstr "測é‡"
msgid "ProductAnalytics|On what do you want to get insights?"
msgstr "您想å–得關於什麼的洞察報告?"
-msgid "ProductAnalytics|Page Language"
-msgstr "é é¢èªžè¨€"
+msgid "ProductAnalytics|Page Views"
+msgstr "é é¢ç€è¦½é‡"
-msgid "ProductAnalytics|Page Path"
-msgstr "é é¢è·¯å¾‘"
+msgid "ProductAnalytics|Repeat Visit Percentage"
+msgstr "é‡è¤‡è¨ªå•çŽ‡"
-msgid "ProductAnalytics|Page Title"
-msgstr "é é¢æ¨™é¡Œ"
+msgid "ProductAnalytics|SDK App ID"
+msgstr "SDK App ID"
-msgid "ProductAnalytics|Page Views"
-msgstr "é é¢ç€è¦½é‡"
+msgid "ProductAnalytics|SDK Host"
+msgstr "SDK 主機"
-msgid "ProductAnalytics|Pages"
-msgstr "é é¢"
+msgid "ProductAnalytics|Sessions"
+msgstr "會話"
-msgid "ProductAnalytics|Panel"
+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|Product analytics dashboards"
-msgstr "產å“分æžå„€è¡¨æ¿"
+msgid "ProductAnalytics|Set up product analytics"
+msgstr ""
-msgid "ProductAnalytics|Referer"
-msgstr "åƒç…§ä½ç½®"
+msgid "ProductAnalytics|Steps to add product analytics as a CommonJS module"
+msgstr ""
-msgid "ProductAnalytics|Resulting Data"
-msgstr "çµæžœè³‡æ–™"
+msgid "ProductAnalytics|Steps to add product analytics as a HTML script tag"
+msgstr ""
-msgid "ProductAnalytics|Single Statistic"
-msgstr "單一統計"
+msgid "ProductAnalytics|Steps to add product analytics as an ESM module"
+msgstr ""
+
+msgid "ProductAnalytics|The host to send all tracking events to"
+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|URL"
-msgstr "URL"
+msgid "ProductAnalytics|Unique Users"
+msgstr "ç¨ç«‹ä½¿ç”¨è€…"
+
+msgid "ProductAnalytics|User Sessions"
+msgstr "使用者會話"
msgid "ProductAnalytics|User activity"
msgstr "使用者活動"
@@ -32265,12 +32764,6 @@ msgstr "使用者活動"
msgid "ProductAnalytics|Users"
msgstr "使用者"
-msgid "ProductAnalytics|Viewport"
-msgstr "視圖"
-
-msgid "ProductAnalytics|Visualization Type"
-msgstr "視覺化類型"
-
msgid "ProductAnalytics|What do you want to measure?"
msgstr "您想測é‡ä»€éº¼ï¼Ÿ"
@@ -32436,6 +32929,12 @@ msgstr "æ–·é–‹"
msgid "Profiles|Disconnect %{provider}"
msgstr "與%{provider}斷開連接"
+msgid "Profiles|Discord ID is too long (maximum is %{max_length} characters)."
+msgstr "Discord ID 太長(最多為 %{max_length} 個字元)。"
+
+msgid "Profiles|Discord ID is too short (minimum is %{min_length} characters)."
+msgstr "Discord ID 太短(最少為 %{min_length} 個字元)。"
+
msgid "Profiles|Do not show on profile"
msgstr "ä¸åœ¨å€‹äººè³‡æ–™ä¸­é¡¯ç¤º"
@@ -32685,8 +33184,8 @@ msgstr "您必須轉移所有權或刪除這些群組,然後æ‰èƒ½åˆªé™¤æ‚¨çš„
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "您必須轉移所有權或刪除這些群組,然後æ‰èƒ½åˆªé™¤æ‚¨çš„帳號。"
-msgid "Profiles|Your Discord user ID. Should be between %{min} and %{max} digits long. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
-msgstr "您的 Discord 使用者 ID。長度應介於 %{min} 到 %{max} ä½æ•¸å­—間。%{external_accounts_link_start}å–得更多資訊。%{external_accounts_link_end}"
+msgid "Profiles|Your Discord user ID. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+msgstr "您的 Discord 使用者 ID。%{external_accounts_link_start}å–得更多資訊。%{external_accounts_link_end}"
msgid "Profiles|Your LinkedIn profile name from linkedin.com/in/profilename"
msgstr "您的LinkedInå稱,åƒè¦‹linkedin.com/in/profilename"
@@ -32731,10 +33230,10 @@ msgid "Progress tracking"
msgstr "進度追蹤"
msgid "Progressive Web App (PWA)"
-msgstr ""
+msgstr "漸進å¼ç¶²çµ¡æ‡‰ç”¨ç¨‹å¼ (PWA)"
msgid "Progressive Web App (PWA) icon was successfully removed."
-msgstr ""
+msgstr "漸進å¼ç¶²è·¯æ‡‰ç”¨ç¨‹å¼ (PWA) 圖標已æˆåŠŸåˆªé™¤ã€‚"
msgid "Project"
msgstr "專案"
@@ -32859,6 +33358,9 @@ msgstr "專案æˆå“¡"
msgid "Project milestone"
msgstr "專案里程碑"
+msgid "Project must have default branch"
+msgstr "專案必須有é è¨­åˆ†æ”¯"
+
msgid "Project name"
msgstr "專案å稱"
@@ -32871,6 +33373,9 @@ msgstr "專案或群組"
msgid "Project order will not be saved as local storage is not available."
msgstr "由於本機儲存ä¸å¯ç”¨ï¼Œå› æ­¤ä¸æœƒå„²å­˜å°ˆæ¡ˆé †åºã€‚"
+msgid "Project overview"
+msgstr ""
+
msgid "Project path"
msgstr "專案路徑"
@@ -32887,7 +33392,7 @@ msgid "Project slug"
msgstr "專案標識"
msgid "Project that can be accessed"
-msgstr ""
+msgstr "å¯è¢«å­˜å–的專案"
msgid "Project uploads"
msgstr "專案上傳"
@@ -32898,11 +33403,14 @@ 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 ""
+msgstr "具有存å–權é™çš„專案"
msgid "Project: %{name}"
msgstr "專案: %{name}"
@@ -32994,9 +33502,21 @@ msgstr "專案ID: %{project_id}"
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 "失敗"
@@ -33009,6 +33529,9 @@ msgstr "å”助我們改進此é é¢"
msgid "ProjectQualitySummary|Latest pipeline results"
msgstr "最新æµæ°´ç·šçµæžœ"
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr "了解更多關於程å¼ç¢¼è³ªé‡çš„訊æ¯"
+
msgid "ProjectQualitySummary|Learn more about test coverage"
msgstr "了解有關測試覆蓋率的更多訊æ¯"
@@ -33051,8 +33574,11 @@ 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 "ProjectSelect| or group"
-msgstr "或群組"
+msgid "ProjectQualitySummary|Violations"
+msgstr "é•è¦"
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr "發ç¾é•è¦"
msgid "ProjectSelect|No matching results"
msgstr "沒有符åˆçš„çµæžœ"
@@ -33066,9 +33592,6 @@ msgstr "æœå°‹å°ˆæ¡ˆ"
msgid "ProjectSelect|Select a project"
msgstr "é¸æ“‡ä¸€å€‹å°ˆæ¡ˆ"
-msgid "ProjectSelect|Something went wrong while fetching projects"
-msgstr "讀å–專案時發生錯誤。"
-
msgid "ProjectSelect|There was an error fetching the projects. Please try again."
msgstr "å–得專案時發生錯誤。請é‡è©¦ã€‚"
@@ -33198,9 +33721,6 @@ msgstr "影響åˆä½µå®Œæˆçš„æ–¹å¼å’Œæ™‚間的其他設定。"
msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
msgstr "除éžæ‚¨æŒ‡å®šä¸åŒçš„分支,å¦å‰‡æ‰€æœ‰åˆä½µè«‹æ±‚å’Œæ交都是é‡å°è©²åˆ†æ”¯é€²è¡Œçš„,。"
-msgid "ProjectSettings|All threads must be resolved"
-msgstr "必須解決所有線程"
-
msgid "ProjectSettings|Allow"
msgstr "å…許"
@@ -33351,9 +33871,6 @@ msgstr "基礎架構"
msgid "ProjectSettings|Internal"
msgstr "內部"
-msgid "ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline."
-msgstr "未通éŽåˆä½µçš„已變更æµæ°´ç·šå¯èƒ½æœƒå°Žè‡³é¢¨éšªã€‚"
-
msgid "ProjectSettings|Issues"
msgstr "議題"
@@ -33396,9 +33913,6 @@ 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 "已核准的åˆä½µè«‹æ±‚已排入佇列,æµæ°´ç·šåœ¨åˆä½µå‰é©—證來æºå’Œç›®æ¨™åˆ†æ”¯çš„åˆä½µçµæžœã€‚ %{link_start}什麼是åˆä½µä½‡åˆ—?%{link_end}"
-msgid "ProjectSettings|Merge requests can't be merged if the latest pipeline did not succeed or is still running."
-msgstr "如果最新æµæ°´ç·šæœªæˆåŠŸæˆ–ä»åœ¨åŸ·è¡Œï¼Œå‰‡ç„¡æ³•åˆä½µåˆä½µè«‹æ±‚。"
-
msgid "ProjectSettings|Merge suggestions"
msgstr "åˆä½µå»ºè­°"
@@ -33435,9 +33949,6 @@ msgstr "Pages"
msgid "ProjectSettings|Pages for project documentation."
msgstr "專案Pages的文件。"
-msgid "ProjectSettings|Pipelines must succeed"
-msgstr "æµæ°´ç·šå¿…é ˆæˆåŠŸ"
-
msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
msgstr "防止直接éˆæŽ¥åˆ°å¯èƒ½æ•æ„Ÿçš„媒體檔案"
@@ -33480,11 +33991,11 @@ msgstr "無需使用特性標籤é‡æ–°éƒ¨ç½²å³å¯æŽ¨å‡ºæ–°åŠŸèƒ½ã€‚"
msgid "ProjectSettings|Search for topic"
msgstr "æœå°‹ä¸»é¡Œ"
-msgid "ProjectSettings|Security & Compliance"
-msgstr "安全與åˆè¦"
+msgid "ProjectSettings|Security and Compliance"
+msgstr ""
-msgid "ProjectSettings|Security & Compliance for this project"
-msgstr "此專案的安全與åˆè¦"
+msgid "ProjectSettings|Security and compliance for this project."
+msgstr ""
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
msgstr "é¸æ“‡è©²å°ˆæ¡ˆçš„é è¨­åˆ†æ”¯ï¼Œä¸¦è¨­å®šåˆ†æ”¯å稱的範本。"
@@ -33507,9 +34018,6 @@ msgstr "顯示é è¨­çš„çŽå‹µè¡¨æƒ…符號"
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr "從指令行推é€æ™‚顯示用於建立或查看åˆä½µè«‹æ±‚的連çµ"
-msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr "被跳éŽçš„æµæ°´ç·šè¦–為æˆåŠŸ"
-
msgid "ProjectSettings|Snippets"
msgstr "程å¼ç¢¼ç‰‡æ®µ"
@@ -33613,7 +34121,7 @@ msgid "ProjectSettings|What is Analytics Dashboards?"
msgstr "什麼是分æžå„€è¡¨æ¿ï¼Ÿ"
msgid "ProjectSettings|What is squashing?"
-msgstr "什麼是擠壓?"
+msgstr "什麼是壓縮 (Squash) ?"
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 "在 CI/CD 設定文件中啟用åˆä½µè«‹æ±‚æµæ°´ç·šæ™‚,æµæ°´ç·šæœƒé©—證來æºåˆ†æ”¯å’Œç›®æ¨™åˆ†æ”¯çš„åˆä½µçµæžœã€‚%{link_start}如何設定åˆä½µè«‹æ±‚æµæ°´ç·šï¼Ÿ%{link_end}"
@@ -33744,6 +34252,9 @@ msgstr "專案 (%{count})"
msgid "Projects API"
msgstr "專案 API"
+msgid "Projects API rate limit"
+msgstr ""
+
msgid "Projects Successfully Retrieved"
msgstr "專案æˆåŠŸè®€å–"
@@ -33868,7 +34379,10 @@ msgid "ProjectsNew|Migrate your data from an external source like GitHub, Bitbuc
msgstr "從外部來æºï¼ˆå¦‚ GitHubã€Bitbucket 或 GitLab 的其他實例)é·ç§»è³‡æ–™ã€‚"
msgid "ProjectsNew|Must start with a lowercase or uppercase letter, digit, emoji, or underscore. Can also contain dots, pluses, dashes, or spaces."
-msgstr ""
+msgstr "必須以å°å¯«æˆ–大寫字æ¯ã€æ•¸å­—ã€è¡¨æƒ…符號或下劃線開頭,也å¯ä»¥åŒ…å«é»žã€åŠ è™Ÿã€ç ´æŠ˜è™Ÿæˆ–空格。"
+
+msgid "ProjectsNew|New project"
+msgstr "新專案"
msgid "ProjectsNew|No import options available"
msgstr "沒有å¯ç”¨çš„匯入é¸é …"
@@ -33885,6 +34399,9 @@ msgstr "專案設定"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "專案æè¿°%{tag_start}(å¯é¸)%{tag_end}"
+msgid "ProjectsNew|Projects"
+msgstr ""
+
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr "如果您是 GitLab 新手,建議使用"
@@ -34065,9 +34582,6 @@ msgstr "è¯çµ¡æ‰€æœ‰è€…%{link_start}%{owner_name}%{link_end}以å‡ç´šè¨ˆåŠƒã€‚"
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr "請與管ç†å“¡è¯çµ¡ä»¥å‡ç´šæŽˆæ¬Šè¨±å¯ã€‚"
-msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "æ述範本å…許您為專案的議題和åˆä½µè«‹æ±‚æ述文字定義特定上下文的範本。"
-
msgid "Promotions|Dismiss Service Desk promotion"
msgstr "關閉æœå‹™å°æ示"
@@ -34176,12 +34690,6 @@ msgstr "當議題數目很多時,很難得到一個整體情æ³ã€‚ 通éŽçµ¦è­
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr "您å¯ä»¥é€šéŽé¸æ“‡è§’色(維護者ã€é–‹ç™¼è€…)以åŠæŸäº›ä½¿ç”¨è€…來é™åˆ¶å°å—ä¿è­·åˆ†æ”¯çš„å­˜å–。"
-msgid "Promotions|description templates"
-msgstr "æ述範本"
-
-msgid "Promotions|to help your contributors communicate effectively!"
-msgstr "幫助您的貢ç»è€…有效æºé€šï¼"
-
msgid "Prompt users to upload SSH keys"
msgstr "æ示使用者上傳SSH金鑰"
@@ -34225,7 +34733,7 @@ msgid "ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} suc
msgstr "æ”¯æ´ %{wildcards_link_start}è¬å…ƒå­—å…ƒ%{wildcards_link_end},例如 %{code_tag_start}*-stable%{code_tag_end} 或 %{code_tag_start}production/*%{code_tag_end}。"
msgid "ProtectedBranch|After you configure a protected branch, merge request approval, or status check, it appears here."
-msgstr ""
+msgstr "在您設定å—ä¿è­·çš„分支ã€åˆä½µè«‹æ±‚核准或狀態檢查後,它會出ç¾åœ¨é€™è£¡ã€‚"
msgid "ProtectedBranch|Allow all users with push access to %{tag_start}force push%{tag_end}."
msgstr "å…許所有具有推é€å­˜å–權é™çš„使用者%{tag_start}強制推é€%{tag_end}。"
@@ -34282,7 +34790,7 @@ msgid "ProtectedBranch|Does not apply to users allowed to push. Optional section
msgstr "ä¸é©ç”¨æ–¼å…許推é€çš„使用者。ä¸å¼·åˆ¶åŸ·è¡Œå¯é¸éƒ¨åˆ†ã€‚"
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
-msgstr ""
+msgstr "繼承 - 該設定å¯ä»¥åœ¨ç¾¤çµ„級別變更"
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr "ä¿æŒç©©å®šçš„分支安全並強制開發人員使用åˆä½µè«‹æ±‚。"
@@ -34353,7 +34861,21 @@ msgstr "您åªèƒ½å¢žåŠ å…±äº«æ­¤å°ˆæ¡ˆçš„群組。 %{learn_more_link}"
msgid "ProtectedBranch|default"
msgstr "é è¨­"
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
msgid "ProtectedEnvironments|Add deployment rules"
+msgstr "增加部署è¦å‰‡"
+
+msgid "ProtectedEnvironments|Allowed to approve"
msgstr ""
msgid "ProtectedEnvironments|Allowed to deploy"
@@ -34365,10 +34887,22 @@ 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 deployment rule"
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
msgstr ""
msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
@@ -34377,15 +34911,24 @@ msgstr "å—ä¿è­·çš„環境清單 (%{protectedEnvironmentsCount})"
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr "批准數é‡å¿…須介於 1 至 5 之間"
+msgid "ProtectedEnvironments|Save"
+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|Unified approval rules have been removed from the settings UI"
+msgstr "統一審核è¦å‰‡å·²å¾žè¨­å®š UI 中移除"
+
msgid "ProtectedEnvironments|Users"
msgstr "使用者"
+msgid "ProtectedEnvironments|You can still use the %{apiLinkStart}API%{apiLinkEnd} to configure unified approval rules. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead, because they provide greater flexibility."
+msgstr "您ä»ç„¶å¯ä»¥ä½¿ç”¨ %{apiLinkStart}API%{apiLinkEnd} é…置統一審核è¦å‰‡ï¼Œä½†å¯ä»¥è€ƒæ…®æ”¹ç”¨ %{docsLinkStart}多個審核è¦å‰‡%{docsLinkEnd},因為它們æ供了更大的éˆæ´»æ€§ã€‚"
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} å°‡å°é–‹ç™¼äººå“¡å¯å¯«å…¥ï¼Œç¢ºå®šç¹¼çºŒå—Žï¼Ÿ"
@@ -34395,6 +34938,9 @@ msgstr "使用以下部署層級所指定的所有環境å‡å—父群組的ä¿è­·
msgid "ProtectedEnvironment|Allowed to deploy"
msgstr "å…許部署"
+msgid "ProtectedEnvironment|Allowed to deploy and approve"
+msgstr ""
+
msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
msgstr "å…許部署到 %{project} / %{environment}"
@@ -34573,19 +35119,19 @@ msgid "PurchaseStep|An error occurred in the purchase step. If the problem persi
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 ""
+msgstr "購買時需è¦åœ¨æ‚¨çš„個人資料中æ供全å,檢查您 %{userProfileLinkStart} 使用者個人資料 %{userProfileLinkEnd} 中的全å字段是å¦åŒ…å«å字和姓æ°ï¼Œç„¶å¾Œé‡è©¦è³¼è²·ã€‚如果å•é¡Œä»ç„¶å­˜åœ¨ï¼Œè«‹%{supportLinkStart}è¯ç¹«å®¢æœ%{supportLinkEnd}。"
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 ""
+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}Customers Portal%{customersPortalLinkEnd} 帳號,但它尚未éˆçµåˆ°æ‚¨çš„ GitLab.com 帳號。請按照 %{linkCustomersPortalHelpLinkStart}說明éˆçµæ‚¨çš„Customers Portal 帳號%{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 ""
+msgstr "由於款項ä¸è¶³ï¼Œæ‚¨çš„å¡è¢«æ‹’絕。請確ä¿æ‚¨æœ‰è¶³å¤ çš„款項,然後é‡è©¦è³¼è²·æˆ–使用ä¸åŒçš„å¡ã€‚如果å•é¡Œä»ç„¶å­˜åœ¨ï¼Œè«‹%{supportLinkStart}è¯ç¹«å®¢æœ%{supportLinkEnd}。"
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 ""
+msgstr "您的信用å¡é­åˆ°æ‹’絕,請è¯ç¹«æ‚¨çš„發å¡æ©Ÿæ§‹äº†è§£æ›´å¤šä¿¡æ¯ï¼Œæˆ–%{salesLinkStart}è¯ç¹«æˆ‘們的銷售團隊%{salesLinkEnd} 以使用其他付費方å¼ä»˜æ¬¾ã€‚"
msgid "Push"
msgstr "推é€"
@@ -34851,24 +35397,15 @@ msgstr "準備åˆä½µï¼"
msgid "Reauthenticating with SAML provider."
msgstr "正在與 SAML æ供商é‡æ–°é©—證。"
-msgid "Rebase"
-msgstr "變基 (Rebase) "
-
msgid "Rebase completed"
msgstr "變基完æˆ"
-msgid "Rebase in progress"
-msgstr "變基 (Rebase) 正在進行中"
-
msgid "Rebase source branch"
msgstr "變基 (Rebase) 來æºåˆ†æ”¯"
msgid "Rebase source branch on the target branch."
msgstr "在目標分支上Rebase來æºåˆ†æ”¯ã€‚"
-msgid "Rebase without pipeline"
-msgstr "沒有æµæ°´ç·šçš„變基 (Rebase) "
-
msgid "Recaptcha verified?"
msgstr "é‡æ–°é©—證?"
@@ -34944,6 +35481,9 @@ msgstr "優化您的æœå°‹æ¢ä»¶ï¼ˆç›¡å¯èƒ½é¸æ“‡ %{strong_open}群組%{strong_
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] "%d 秒後é‡æ–°æ•´ç†ä»¥é¡¯ç¤ºæ›´æ–°ç‹€æ…‹..."
@@ -34978,14 +35518,14 @@ msgstr "註冊"
msgid "Register / Sign In"
msgstr "註冊/登入"
-msgid "Register Two-Factor Authenticator"
-msgstr "註冊雙因å­èªè­‰"
+msgid "Register a WebAuthn device"
+msgstr "註冊 WebAuthn 設備"
-msgid "Register Universal Two-Factor (U2F) Device"
-msgstr "註冊通用雙因å­èªè­‰è¨­å‚™(U2F)"
+msgid "Register a one-time password authenticator"
+msgstr "註冊一個一次性密碼驗證器"
-msgid "Register WebAuthn Device"
-msgstr "註冊WebAuthn設備"
+msgid "Register a one-time password authenticator or a WebAuthn device first."
+msgstr ""
msgid "Register device"
msgstr "註冊設備"
@@ -35077,6 +35617,9 @@ msgstr "已拒絕(關閉)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr "é—œè¯åˆ° %{issuable_type} %{add_related_issue_link}"
+msgid "Related"
+msgstr ""
+
msgid "Related feature flags"
msgstr "相關的特性標籤"
@@ -35304,7 +35847,7 @@ msgid "Remove header logo"
msgstr "移除標題標誌(logo)"
msgid "Remove icon"
-msgstr ""
+msgstr "移除圖示"
msgid "Remove iteration"
msgstr "移除迭代"
@@ -36005,15 +36548,21 @@ msgstr "需求%{reference}å·²é‡æ–°æ‰“é–‹"
msgid "Requirement %{reference} has been updated"
msgstr "需求%{reference}已更新"
-msgid "Requirement title cannot have more than %{limit} characters."
-msgstr "需求標題ä¸èƒ½è¶…éŽ%{limit}個字元。"
-
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 "舊版需求 ID:%{legacyId}"
+
+msgid "Requirement|Legacy requirement IDs are being deprecated. Update your links to reference this item's new ID %{id}. %{linkStart}Learn more%{linkEnd}."
+msgstr "舊的需求 ID 已被棄用,更新您的éˆçµä»¥åƒç…§è©²å°ˆæ¡ˆçš„æ–° ID %{id}。 %{linkStart}了解更多%{linkEnd}。"
+
+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 "需求已æˆç‚ºå·¥ä½œé …目,舊的需求 ID 已被棄用,更新您的éˆçµä»¥åƒç…§è©²å°ˆæ¡ˆçš„æ–° ID %{id}。 %{linkStart}了解更多%{linkEnd}。"
+
msgid "Requires %d approval from eligible users."
msgid_plural "Requires %d approvals from eligible users."
msgstr[0] "需è¦%d個符åˆæ¢ä»¶çš„使用者的核准。"
@@ -36190,9 +36739,6 @@ msgstr "é”到çµæžœé™åˆ¶"
msgid "Resume"
msgstr "æ¢å¾©"
-msgid "Retrieving the compliance report failed. Refresh the page and try again."
-msgstr "檢索åˆè¦æ€§å ±å‘Šå¤±æ•—。請é‡æ–°æ•´ç†é é¢ä¸¦é‡è©¦ã€‚"
-
msgid "Retry"
msgstr "é‡è©¦"
@@ -36358,10 +36904,7 @@ msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabl
msgstr "執行管ç†ä»»å‹™ä¾†è‡ªå‹•å„ªåŒ– Git 版本庫,åœç”¨è©²é¸é …將導致性能隨著時間的推移而下é™ã€‚"
msgid "Run job"
-msgstr ""
-
-msgid "Run manual job again"
-msgstr "å†æ¬¡åŸ·è¡Œæ‰‹å‹•ä½œæ¥­"
+msgstr "執行作業"
msgid "Run manual or delayed jobs"
msgstr "執行手動或延é²çš„作業"
@@ -36431,7 +36974,10 @@ msgid "Runners|Active"
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 "為執行器處ç†çš„作業類型增加標籤,以確ä¿åŸ·è¡Œå™¨åƒ…執行您希望它執行的作業。 %{helpLinkStart}了解更多。%{helpLinkEnd}"
msgid "Runners|Administrator"
msgstr "管ç†å“¡"
@@ -36496,6 +37042,9 @@ msgstr "容é‡ç‚º 1,通éŽè‡ªå‹•æ“´å±•çµ„é‡æ–°ç”Ÿæˆå•Ÿç”¨ warm HA。容é‡ç‚
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 "é¸æ“‡æ‚¨å–œæ­¡çš„GitLab執行器"
@@ -36503,7 +37052,7 @@ msgid "Runners|Clear selection"
msgstr "清除é¸æ“‡"
msgid "Runners|Cloud templates"
-msgstr ""
+msgstr "雲範本"
msgid "Runners|Command to register runner"
msgstr "註冊執行器的指令"
@@ -36512,6 +37061,9 @@ 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"
@@ -36569,9 +37121,15 @@ msgstr "啟用éŽæ™‚的執行器清ç†"
msgid "Runners|Enable stale runner cleanup?"
msgstr "啟用éŽæ™‚的執行器清ç†?"
+msgid "Runners|Enter the number of seconds."
+msgstr "輸入秒數。"
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr "輸入秒數。此逾時優先於為專案設定的較低逾時。"
+msgid "Runners|Environment"
+msgstr ""
+
msgid "Runners|Executor"
msgstr "執行者"
@@ -36584,6 +37142,12 @@ 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 runners page"
+msgstr ""
+
msgid "Runners|Group"
msgstr "群組"
@@ -36602,6 +37166,9 @@ msgstr "é–’ç½®"
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr "è‹¥åœç”¨é€™å…©å€‹è¨­å®šï¼Œå‰‡ç„¡æ³•è¨»å†Šæ–°çš„執行器。"
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
msgid "Runners|Install a runner"
msgstr "安è£åŸ·è¡Œå™¨"
@@ -36629,6 +37196,12 @@ msgstr "已鎖定此專案"
msgid "Runners|Maintenance note"
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 "作業逾時最大值"
@@ -36638,6 +37211,9 @@ msgstr "%{type}的會員å¯ä»¥è¨»å†ŠåŸ·è¡Œå™¨"
msgid "Runners|Minor version upgrades are available."
msgstr "å·²æ供次è¦ç‰ˆæœ¬å‡ç´šã€‚"
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr "多個標籤必須用逗號分隔,例如,%{example}。"
+
msgid "Runners|Name"
msgstr "å稱"
@@ -36650,6 +37226,9 @@ msgstr "從未連接éŽ:"
msgid "Runners|Never expires"
msgstr "無期é™"
+msgid "Runners|New"
+msgstr "新建"
+
msgid "Runners|New group runners can be registered"
msgstr "å¯ä»¥è¨»å†Šæ–°çš„群組執行器(Runner)"
@@ -36687,9 +37266,12 @@ msgid "Runners|Online:"
msgstr "在線:"
msgid "Runners|Only administrators can view this."
-msgstr ""
+msgstr "åªæœ‰ç®¡ç†å“¡å¯ä»¥æŸ¥çœ‹ã€‚"
msgid "Runners|Operating systems"
+msgstr "æ“作系統"
+
+msgid "Runners|Optional. Step 3"
msgstr ""
msgid "Runners|Owner"
@@ -36723,6 +37305,12 @@ msgstr "å—ä¿è­·"
msgid "Runners|Recommended"
msgstr "推薦"
+msgid "Runners|Register"
+msgstr "註冊"
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
msgid "Runners|Register a group runner"
msgstr "註冊一個群組執行器(runner)"
@@ -36738,6 +37326,9 @@ msgstr "註冊一個實例執行器(runner)"
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 "註冊令牌(權æ–)"
@@ -36762,6 +37353,9 @@ msgstr "執行器 #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
msgstr "%{name} 執行器已刪除"
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr "執行器 %{runnerName} 刪除失敗"
+
msgid "Runners|Runner Registration"
msgstr "註冊執行器(Runner)"
@@ -36777,6 +37371,12 @@ 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 "執行器(Runner)æè¿°"
+
msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
msgstr "在最近 %{elapsedTime} 內,執行器(Runner)é€£æŽ¥éŽ GitLab"
@@ -36849,9 +37449,15 @@ 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 "é¸æ“‡è¦æŒ‡æ´¾çµ¦è©²åŸ·è¡Œå™¨(runner)的專案"
@@ -36885,6 +37491,12 @@ msgstr "éŽæœŸï¼š"
msgid "Runners|Status"
msgstr "狀態"
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
msgid "Runners|Stop the runner from accepting new jobs."
msgstr "åœæ­¢åŸ·è¡Œå™¨(runner)接å—新的作業。"
@@ -36894,6 +37506,9 @@ 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 create the runner. It will not be visible once the runner is registered."
+msgstr ""
+
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
msgstr "執行器(runner)所註冊的專案ã€ç¾¤çµ„或實例。實例執行器(runner)始終歸管ç†å“¡æ‰€æœ‰ã€‚"
@@ -36910,6 +37525,9 @@ msgstr[0] "該群組目å‰æœ‰ %d 個éŽæ™‚的執行器。"
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 runner has not run any jobs."
msgstr "此執行器(runner)沒有執行任何作業。"
@@ -36958,6 +37576,9 @@ msgstr "建議å‡ç´š"
msgid "Runners|Use Group runners when you want all projects in a group to have access to a set of runners."
msgstr "如果您希望群組中的所有專案都å¯ä»¥å­˜å–一組執行器(runner),請使用群組執行器。"
+msgid "Runners|Use the runner for jobs without tags in addition to tagged jobs."
+msgstr "除了具有標籤的工作外,還å¯ä»¥å°‡åŸ·è¡Œå™¨ç”¨æ–¼æ²’有被標籤的工作。"
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr "除了帶標籤的作業外,還å¯ä»¥å°‡åŸ·è¡Œå™¨(runner)用於沒有標籤的作業。"
@@ -37012,15 +37633,6 @@ msgstr "專案"
msgid "Runners|shared"
msgstr "共用"
-msgid "Runner|New"
-msgstr "新建"
-
-msgid "Runner|Owner"
-msgstr "所有者"
-
-msgid "Runner|Runner %{runnerName} failed to delete"
-msgstr "執行器 %{runnerName} 刪除失敗"
-
msgid "Running"
msgstr "執行中"
@@ -37042,6 +37654,9 @@ msgstr "SAML探索令牌(權æ–)"
msgid "SAML for %{group_name}"
msgstr "%{group_name} çš„ SAML"
+msgid "SAML group membership settings"
+msgstr ""
+
msgid "SAML single sign-on"
msgstr "SAML 單一登入"
@@ -37066,9 +37681,6 @@ msgstr "è¦åœ¨æ‚¨ä½¿ç”¨å–®é»žç™»å…¥æˆåŠŸç™»å…¥å¾Œå…許 %{strongOpen}%{group_na
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "您組織的 SSO 已連接到您的 GitLab 帳號"
-msgid "SAST Configuration"
-msgstr "SAST設定"
-
msgid "SCIM|SCIM Token"
msgstr "SCIM 憑證"
@@ -37181,10 +37793,10 @@ msgid "Save pipeline schedule"
msgstr "儲存æµæ°´ç·šæŽ’程"
msgid "Saved Replies"
-msgstr ""
+msgstr "ä¿å­˜çš„回復"
msgid "Saved replies can be used when creating comments inside issues, merge requests, and epics."
-msgstr ""
+msgstr "在議題ã€åˆä½µè«‹æ±‚å’Œå²è©©(epics)中建立評論時å¯ä»¥ä½¿ç”¨å·²ä¿å­˜çš„回復。"
msgid "Saving"
msgstr "儲存中"
@@ -37198,17 +37810,20 @@ msgstr "%{period} %{days} æ–¼ %{time}"
msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr "%{scopes} %{branches} %{agents} %{namespaces} 的 %{rules} 動作"
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} with tags %{tags}"
-msgstr "%{thenLabelStart}下一步%{thenLabelEnd} 需è¦ä½¿ç”¨ç«™é»žè¨­å®šæ–‡ä»¶ %{siteProfile} 和帶有標籤 %{tags} 的掃æ設定文件 %{scannerProfile} 執行 %{scan} 掃æ"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan on runner that %{tags}"
+msgstr ""
-msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with tags %{tags}"
-msgstr "%{thenLabelStart}下一步%{thenLabelEnd} 需è¦ä½¿ç”¨æ¨™ç±¤ %{tags} 執行 %{scan} 掃æ"
+msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile} on runner that %{tags}"
+msgstr ""
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr "æµæ°´ç·šåŸ·è¡Œä¸­"
-msgid "ScanExecutionPolicy|Ex, tag-name-1, tag-name-2"
-msgstr "例如,tag-name-1, tag-name-2"
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
+msgstr ""
msgid "ScanExecutionPolicy|If the field is empty, the runner will be automatically selected"
msgstr "如果該欄ä½ç‚ºç©ºï¼ŒåŸ·è¡Œå™¨ (runner) 將被自動é¸å–"
@@ -37249,9 +37864,15 @@ msgstr "代ç†"
msgid "ScanExecutionPolicy|branch"
msgstr "分支"
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
msgid "ScanExecutionPolicy|in namespaces"
msgstr "在命å空間中"
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
msgid "ScanResultPolicy|%{count} licenses"
msgstr "%{count} 個許å¯è­‰"
@@ -37689,24 +38310,27 @@ msgstr "UUID"
msgid "Security"
msgstr "安全"
-msgid "Security & Compliance"
-msgstr "安全與åˆè¦"
-
-msgid "Security Configuration"
-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 navigation"
-msgstr "安全導覽"
-
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr "安全報告已éŽæ™‚。請使用目標分支(%{targetBranchName})中的最新更改來更新您的分支。"
@@ -37833,8 +38457,8 @@ msgstr "應用程å¼ç’°å¢ƒçš„執行時安全指標"
msgid "SecurityConfiguration|SAST Analyzers"
msgstr "SAST分æžå·¥å…·"
-msgid "SecurityConfiguration|SAST Configuration"
-msgstr "SAST設定"
+msgid "SecurityConfiguration|SAST configuration"
+msgstr ""
msgid "SecurityConfiguration|Secure your project"
msgstr "ä¿è­·æ‚¨çš„專案"
@@ -37867,7 +38491,7 @@ msgid "SecurityOrchestration| or "
msgstr "或 "
msgid "SecurityOrchestration| that is %{licenseState} and is"
-msgstr ""
+msgstr "那是 %{licenseState} 並且是"
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr "%{agent} 用於 %{namespaces}"
@@ -37879,7 +38503,7 @@ msgid "SecurityOrchestration|%{branches} branch"
msgstr "%{branches} 分支"
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
-msgstr ""
+msgstr "%{licenses} 和 %{lastLicense}"
msgid "SecurityOrchestration|%{scannerStart}%{scanner}%{scannerEnd}"
msgstr "%{scannerStart}%{scanner}%{scannerEnd}"
@@ -37936,7 +38560,7 @@ msgid "SecurityOrchestration|An error occurred while fetching the scan result po
msgstr "讀å–掃æçµæžœæ”¿ç­–時發生錯誤"
msgid "SecurityOrchestration|Any security scanner finds"
-msgstr ""
+msgstr "任何安全掃æ器發ç¾"
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr "您確定è¦åˆªé™¤æ­¤æ”¿ç­–嗎? æ­¤æ“作無法撤消。"
@@ -37947,6 +38571,9 @@ msgstr "é¸æ“‡å°ˆæ¡ˆ"
msgid "SecurityOrchestration|Choose approver type"
msgstr "é¸æ“‡å¯©æ ¸è€…é¡žåž‹"
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr "建立更å¥å…¨çš„æ¼æ´žè¦å‰‡ä¸¦å°‡å…¶å¥—用於您的所有專案。"
@@ -38035,7 +38662,7 @@ msgid "SecurityOrchestration|License Scan"
msgstr "許å¯è­‰æŽƒæ"
msgid "SecurityOrchestration|License scanner finds any license %{matching} %{licenses}%{detection} in an open merge request targeting %{branches}."
-msgstr ""
+msgstr "許å¯è­‰æŽƒæ器在é‡å° %{branches} é–‹å•Ÿçš„åˆä½µè«‹æ±‚中找到任何許å¯è­‰ %{matching} %{licenses}%{detection}。"
msgid "SecurityOrchestration|New policy"
msgstr "新政策"
@@ -38052,9 +38679,18 @@ msgstr "未定義任何æ“作 - 政略ä¸æœƒåŸ·è¡Œã€‚"
msgid "SecurityOrchestration|No description"
msgstr "ç„¡æè¿°"
+msgid "SecurityOrchestration|No matching results"
+msgstr ""
+
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr "未定義è¦å‰‡ - 政策無法執行。"
+msgid "SecurityOrchestration|No tags available"
+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 "尚未啟用"
@@ -38145,6 +38781,9 @@ msgstr "掃æç”±å為 %{agents} %{cadence} 的代ç†åŸ·è¡Œ"
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr "在%{branches}上掃ææ¯å€‹æµæ°´ç·š"
+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 "安全èªè­‰"
@@ -38166,6 +38805,9 @@ msgstr "é¸æ“‡ç¾¤çµ„"
msgid "SecurityOrchestration|Select policy"
msgstr "é¸æ“‡æ”¿ç­–"
+msgid "SecurityOrchestration|Select runner tags"
+msgstr ""
+
msgid "SecurityOrchestration|Select scan type"
msgstr "é¸æ“‡æŽƒæé¡žåž‹"
@@ -38175,6 +38817,9 @@ msgstr "é¸æ“‡å®‰å…¨å°ˆæ¡ˆ"
msgid "SecurityOrchestration|Select users"
msgstr "é¸æ“‡ä½¿ç”¨è€…"
+msgid "SecurityOrchestration|Selected automatically"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr "出了點å•é¡Œï¼Œç„¡æ³•å–得政策"
@@ -38241,8 +38886,8 @@ 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, DAST, Secret detection, Container scanning, and Dependency scanning."
-msgstr "掃æ執行政策å…許建立在特定時間強制å°ç‰¹å®šåˆ†æ”¯é€²è¡Œå®‰å…¨æŽƒæçš„è¦å‰‡ã€‚支æ´çš„類型是 SASTã€DASTã€Secret 檢測ã€å®¹å™¨æŽƒæ與ä¾è³´é—œä¿‚掃æ。"
+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 "使用掃æçµæžœæ”¿ç­–建立è¦å‰‡ï¼Œåœ¨åˆä½µåˆä½µè«‹æ±‚之å‰æª¢æŸ¥å®‰å…¨æ¼æ´žå’Œè¨±å¯è­‰åˆè¦æ€§ã€‚"
@@ -38319,6 +38964,9 @@ msgstr "%{firstProject},%{secondProject},åŠ%{rest}"
msgid "SecurityReports|Activity"
msgstr "活動"
+msgid "SecurityReports|Add comment and 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 "加入或刪除安全å€å…§çš„專案。 此列表中專案的掃æçµæžœå°‡é¡¯ç¤ºåœ¨å®‰å…¨å„€è¡¨æ¿å’Œæ¼æ´žå ±å‘Šä¸­ã€‚"
@@ -38590,7 +39238,7 @@ msgid "SecurityReports|There was an error deleting the comment."
msgstr "刪除留言時發生錯誤。"
msgid "SecurityReports|There was an error dismissing the finding. Please try again."
-msgstr ""
+msgstr "忽略該çµæžœæ™‚發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚"
msgid "SecurityReports|There was an error dismissing the vulnerabilities."
msgstr "忽略æ¼æ´žæ™‚發生錯誤。"
@@ -38796,6 +39444,9 @@ msgstr "é¸æ“‡æ¨™è¨˜"
msgid "Select labels"
msgstr "é¸æ“‡æ¨™è¨˜(s)"
+msgid "Select labels (optional)"
+msgstr ""
+
msgid "Select merge moment"
msgstr "é¸æ“‡åˆä½µæ™‚é–“"
@@ -38898,6 +39549,9 @@ msgstr "å·²æˆåŠŸåˆªé™¤è‡ªç›£æŽ§å°ˆæ¡ˆ"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "未刪除自監控專案。請檢查記錄檔是å¦æœ‰éŒ¯èª¤è¨Šæ¯"
+msgid "Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr "啟用或åœç”¨å¯¦ä¾‹è‡ªç›£æŽ§ã€‚"
@@ -38910,6 +39564,9 @@ msgstr "åœç”¨è‡ªç›£æŽ§ï¼Ÿ"
msgid "SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
msgstr "åœç”¨è‡ªç›£æŽ§æœƒåˆªé™¤è‡ªç›£æŽ§å°ˆæ¡ˆï¼Œæ‚¨ç¢ºå®šè¦åœç”¨è‡ªç›£æŽ§ä¸¦åˆªé™¤è©²å°ˆæ¡ˆå—Žï¼Ÿ"
+msgid "SelfMonitoring|Deprecation notice"
+msgstr ""
+
msgid "SelfMonitoring|Self-monitoring"
msgstr "自監控"
@@ -38922,6 +39579,9 @@ msgstr "å·²æˆåŠŸå»ºç«‹è‡ªç›£æŽ§å°ˆæ¡ˆã€‚"
msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr "å·²æˆåŠŸåˆªé™¤è‡ªç›£æŽ§å°ˆæ¡ˆã€‚"
+msgid "SelfMonitoring|Self-monitoring was %{deprecation}deprecated%{link_end} in GitLab 14.9, and is %{removal}scheduled for removal%{link_end} in GitLab 16.0. For information on a possible replacement, %{opstrace}learn more about Opstrace%{link_end}."
+msgstr ""
+
msgid "Send"
msgstr "發é€"
@@ -39024,6 +39684,12 @@ 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|Enable Service Desk"
msgstr "啟用æœå‹™å°"
@@ -39073,7 +39739,7 @@ msgid "Set a default description template to be used for new issues. %{link_star
msgstr "設定用於新議題的é è¨­æ述範本。 %{link_start}什麼是æ述範本?%{link_end}"
msgid "Set a group, access level or users who are required to deploy."
-msgstr ""
+msgstr "設定被è¦æ±‚部署的群組ã€å­˜å–級別或使用者。"
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "為帳號建立一個用於推é€æˆ–拉å–çš„ %{protocol} 密碼。"
@@ -39159,6 +39825,9 @@ msgstr "設定 Web 終端的最長會話時間。"
msgid "Set the milestone to %{milestone_reference}."
msgstr "將里程碑設定為%{milestone_reference}。"
+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 "為æ¯å€‹é€éŽAPI以IDå–得的使用者設定速率é™åˆ¶ã€‚"
@@ -39186,8 +39855,8 @@ msgstr "設定Jiraæ•´åˆ"
msgid "Set up a %{type} runner for a project"
msgstr "為專案設定一個%{type}執行器(runner)"
-msgid "Set up a hardware device as a second factor to sign in."
-msgstr "設定一個硬體設備作為登入的第二個因å­ã€‚"
+msgid "Set up a hardware device to enable two-factor authentication (2FA)."
+msgstr "設置硬體設備以啟用雙因å­èº«ä»½é©—è­‰ (2FA)。"
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "根據%{docsLinkStart}文件%{icon}%{docsLinkEnd}設定斷言/屬性/è²æ˜Žï¼ˆemail,first_name,last_name)和NameID"
@@ -39368,7 +40037,7 @@ msgid "Shimo|You've enabled the Shimo Workspace integration. You can view your w
msgstr "您已啟用Shimo工作å€æ•´åˆã€‚您å¯ä»¥ç›´æŽ¥åœ¨Shimo查看您的wiki。"
msgid "Short name"
-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 "如果您éºå¤±æ‰‹æ©Ÿæˆ–一次性存å–密碼,æ¯å€‹æ¢å¾©ç¢¼éƒ½å¯ä»¥ä½¿ç”¨ä¸€æ¬¡ï¼Œä»¥é‡æ–°ç²å¾—您的帳號存å–權é™ã€‚請將它們ä¿å­˜åœ¨å®‰å…¨çš„地方,å¦å‰‡æ‚¨%{boldStart}å°‡%{boldEnd}無法存å–您的帳號。"
@@ -39436,6 +40105,9 @@ msgstr "顯示文件內容"
msgid "Show filters"
msgstr "顯示éŽæ¿¾å™¨"
+msgid "Show full blame"
+msgstr ""
+
msgid "Show group milestones"
msgstr "顯示群組里程碑"
@@ -39599,9 +40271,6 @@ msgstr "Sidekiq 作業大å°é™åˆ¶"
msgid "Sign in"
msgstr "登入"
-msgid "Sign in / Register"
-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 "以具有符åˆé›»å­éƒµä»¶åœ°å€çš„使用者身份登入,將電å­éƒµä»¶åŠ å…¥åˆ°æ­¤å¸³è™Ÿï¼Œæˆ–使用符åˆçš„é›»å­éƒµä»¶è¨»å†Šæ–°å¸³è™Ÿã€‚"
@@ -39755,15 +40424,33 @@ msgstr "Slackæ•´åˆå…許您é€éŽèŠå¤©è¦–窗中的shash指令與GitLab互動ã€
msgid "Slack logo"
msgstr "Slack logo"
+msgid "Slack notifications integration is deprecated"
+msgstr "Slack 通知整åˆå·²è¢«æ£„用"
+
+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|An application called GitLab for Slack app is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
msgstr "您確定è¦å¾ž GitLab for Slack 應用程å¼ä¸­ç§»é™¤è©²å°ˆæ¡ˆå—Žï¼Ÿ"
+msgid "SlackIntegration|Authorize GitLab for Slack app (%{user}) to use your account?"
+msgstr ""
+
msgid "SlackIntegration|Client ID"
msgstr "客戶端 ID"
msgid "SlackIntegration|Client secret"
msgstr "客戶端密鑰"
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
msgid "SlackIntegration|GitLab for Slack"
msgstr "GitLab for Slack"
@@ -39773,6 +40460,9 @@ msgstr "GitLab for Slack å·²æˆåŠŸå®‰è£ã€‚"
msgid "SlackIntegration|Install GitLab for Slack app"
msgstr "å®‰è£ GitLab for Slack 應用程å¼"
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr "專案別å"
@@ -39782,6 +40472,9 @@ msgstr "GitLab for Slack"
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 "通éŽè¼¸å…¥è¨­å®šæ­¤æ•´åˆå¾Œï¼ŒæŸ¥çœ‹ Slack 中å¯ç”¨çš„命令列表"
@@ -39815,9 +40508,15 @@ msgstr "驗證令牌(權æ–)"
msgid "SlackIntegration|You can now close this window and go to your Slack workspace."
msgstr "您ç¾åœ¨å¯ä»¥é—œé–‰æ­¤çª—å£ä¸¦è½‰åˆ°æ‚¨çš„ Slack 工作å€ã€‚"
+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 "當我們%{linkStart}進行更新或更改權é™%{linkEnd}時,您å¯èƒ½éœ€è¦é‡æ–°å®‰è£ GitLab for Slack 應用程å¼ã€‚"
+msgid "SlackIntegration|cannot have more than %{limit} channels"
+msgstr "ä¸èƒ½æœ‰è¶…éŽ %{limit} 個頻é“"
+
msgid "SlackModal|Are you sure you want to change the project?"
msgstr "您確定è¦è®Šæ›´è©²å°ˆæ¡ˆå—Žï¼Ÿ"
@@ -39999,7 +40698,10 @@ msgid "Something went wrong trying to load issue contacts."
msgstr "嘗試載入議題è¯çµ¡äººæ™‚發生錯誤。"
msgid "Something went wrong when deleting a comment. Please try again"
-msgstr ""
+msgstr "刪除評論時發生錯誤,請å†è©¦ä¸€æ¬¡"
+
+msgid "Something went wrong when deleting a comment. Please try again."
+msgstr "刪除留言評論時出了點å•é¡Œï¼Œè«‹å†è©¦ä¸€æ¬¡ã€‚"
msgid "Something went wrong when reordering designs. Please try again"
msgstr "é‡æ–°æŽ’åºè¨­è¨ˆæ™‚出了點å•é¡Œã€‚è«‹å†è©¦ä¸€æ¬¡"
@@ -40007,6 +40709,9 @@ msgstr "é‡æ–°æŽ’åºè¨­è¨ˆæ™‚出了點å•é¡Œã€‚è«‹å†è©¦ä¸€æ¬¡"
msgid "Something went wrong when sending the incident link to Slack."
msgstr "將事故éˆçµç™¼é€åˆ° Slack 時發生錯誤。"
+msgid "Something went wrong when updating a comment. Please try again"
+msgstr "更新評論時發生錯誤,請å†è©¦ä¸€æ¬¡"
+
msgid "Something went wrong while adding timeline event."
msgstr "加入時間線事件時發生錯誤。"
@@ -40418,9 +41123,6 @@ msgstr "\"%{prop}()\"方法å稱è¡çªã€‚"
msgid "SourceEditor|No extension for unuse has been specified."
msgstr "未指定未使用的擴展å。"
-msgid "SourceEditor|Source Editor instance is required to set up an extension."
-msgstr "需è¦ä¾†æºç·¨è¼¯å™¨(Source Editor)實例來設定擴展。"
-
msgid "SourceEditor|`definition` property is expected on the extension."
msgstr "`definition` 屬性應該在擴展上。"
@@ -40484,6 +41186,9 @@ msgstr "垃圾訊æ¯åŠé˜²æ©Ÿå™¨äººä¿è­·"
msgid "Spam log successfully submitted as ham."
msgstr "垃圾訊æ¯æ—¥èªŒå·²æˆåŠŸæ”¹ç‚ºæœ‰æ•ˆè¨Šæ¯æ交。"
+msgid "Specific branches"
+msgstr "特定分支"
+
msgid "Specified URL cannot be used: \"%{reason}\""
msgstr "無法使用指定的URL:「%{reason}ã€"
@@ -40733,6 +41438,9 @@ msgstr "移除狀態檢查?"
msgid "StatusCheck|Service name"
msgstr "æœå‹™å稱"
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
msgid "StatusCheck|Status checks"
msgstr "狀態檢查"
@@ -41378,17 +42086,23 @@ msgstr "準備好開始了嗎? GitLab 方案éžå¸¸é©åˆæ“´å±•çµ„織和多團é
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|Sync subscription request."
-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 "啟用碼無效。請確ä¿å¾žå®¢æˆ¶ç«¯å…¥å£ç¶²æˆ–確èªé›»å­éƒµä»¶ä¸­æº–確複製。 了解更多關於 %{linkStart}啟用您的訂閱%{linkEnd}。"
@@ -41396,8 +42110,8 @@ msgstr "啟用碼無效。請確ä¿å¾žå®¢æˆ¶ç«¯å…¥å£ç¶²æˆ–確èªé›»å­éƒµä»¶ä¸­
msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
msgstr "啟用碼應該是一個24個字元的字æ¯æ•¸å­—字元串"
-msgid "SuperSonics|There is a connectivity issue."
-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 "這是從授權許å¯å•Ÿå‹•ä»¥ä¾†ä½¿ç”¨è€…數的最高峰。"
@@ -41424,9 +42138,6 @@ 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 "您å¯ä»¥%{purchaseSubscriptionLinkStart}購買新訂閱%{purchaseSubscriptionLinkEnd},然後é‡è©¦ã€‚如果您需è¦é€²ä¸€æ­¥çš„幫助,請 %{supportLinkStart}è¯ç¹« GitLab å”助%{supportLinkEnd}。"
-msgid "SuperSonics|You can no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
-msgstr "您無法å†å°‡è¨‚閱詳細訊æ¯èˆ‡ GitLab åŒæ­¥ã€‚ %{connectivityHelpLinkStart}通éŽå°å•Ÿç”¨ç¢¼é€²è¡Œæ•…障排除%{connectivityHelpLinkEnd},å–得有關最常見連接å•é¡Œçš„幫助。"
-
msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr "您å¯ä»¥é–‹å§‹å…費試用 GitLab 旗艦版,無需任何承諾或付款訊æ¯ã€‚"
@@ -41469,9 +42180,6 @@ msgstr "您的訂閱"
msgid "SuperSonics|Your subscription cannot be located"
msgstr "無法找到您的訂閱"
-msgid "SuperSonics|Your subscription details will sync shortly."
-msgstr "您的訂閱訊æ¯å°‡å¾ˆå¿«åŒæ­¥"
-
msgid "SuperSonics|Your subscription is expired"
msgstr "您的訂閱已éŽæœŸ"
@@ -41622,9 +42330,27 @@ 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 "標籤推é€"
@@ -42029,12 +42755,12 @@ msgstr "您的專案沒有任何 Terraform 狀態文件"
msgid "Test"
msgstr "測試"
-msgid "Test Cases"
-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] "該æµæ°´ç·šçš„測試覆蓋率值是通éŽå¹³å‡ %d 個作業的çµæžœè¦†è“‹çŽ‡å€¼ä¾†è¨ˆç®—的。"
@@ -42052,9 +42778,6 @@ msgstr "移動測試案例"
msgid "TestCases|Moving test case"
msgstr "移動中的測試案例"
-msgid "TestCases|New Test Case"
-msgstr "新增測試案例"
-
msgid "TestCases|New test case"
msgstr "新建測試案例"
@@ -42181,6 +42904,9 @@ msgstr "文字(å¯é¸ï¼‰"
msgid "Text added to the body of all email messages. %{character_limit} character limit"
msgstr "加入到所有電å­éƒµä»¶æ­£æ–‡çš„文字。 %{character_limit} å­—å…ƒé™åˆ¶"
+msgid "Text added to the body of user deactivation email messages. 1000 character limit."
+msgstr "增加到使用者åœç”¨é›»å­éƒµä»¶ä¸»é«”的文字,é™åˆ¶ 1000 個字元。"
+
msgid "Text style"
msgstr "文字樣å¼"
@@ -42239,6 +42965,9 @@ msgstr "議題追蹤用於管ç†éœ€æ±‚改進或者解決的å•é¡Œã€‚請註冊或
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr "Prometheus伺æœå™¨ä»¥ã€ŒéŒ¯èª¤è«‹æ±‚ã€å›žæ‡‰ã€‚請檢查您的查詢是å¦æ­£ç¢ºï¼Œä¸¦ä¸”支æ´ç•¶å‰çš„Prometheus版本。%{documentationLink}"
+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 "Slack 通知整åˆå·²è¢«æ£„用,將在未來版本中移除。è¦ç¹¼çºŒæŽ¥æ”¶ä¾†è‡ª Slack 的通知,請改用 GitLab for Slack 應用程å¼ã€‚ %{learn_more_link_start}了解更多%{link_end}。"
+
msgid "The Snowplow cookie domain."
msgstr "Snowplow cookie 網域。"
@@ -42281,9 +43010,6 @@ 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 "完整的 DevOps å¹³å°ï¼Œä¸€ç¨®å…·æœ‰ç„¡é™å¯èƒ½æ€§çš„應用程å¼ã€‚組織ä¾é  GitLab çš„æºç¢¼ç®¡ç†ã€CI/CDã€å®‰å…¨æ€§ç­‰ä¾†å¿«é€Ÿäº¤ä»˜è»Ÿé«”。"
-msgid "The compliance report shows the merge request violations merged in protected environments."
-msgstr "åˆè¦æ€§å ±å‘Šé¡¯ç¤ºåœ¨å—ä¿è­·ç’°å¢ƒä¸­åˆä½µçš„åˆä½µè«‹æ±‚é•è¦ã€‚"
-
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "該連接將在 %{timeout} 後逾時。如版本庫匯入耗時超éŽè©²æ™‚間,請使用克隆 (Clone) /推é€(Push)組åˆã€‚"
@@ -42341,6 +43067,9 @@ msgstr "ä¾è³´é …列表詳細說明了專案中使用元件的訊æ¯ã€‚"
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "將此作業部署至 %{environmentLink} 未æˆåŠŸã€‚"
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
msgid "The directory has been successfully created."
msgstr "目錄已æˆåŠŸå»ºç«‹ã€‚"
@@ -42652,8 +43381,17 @@ msgstr "您嘗試存å–的資æºä¸å­˜åœ¨æˆ–您沒有執行該動作的權é™ã€‚
msgid "The scan has been created."
msgstr "掃瞄已建立。"
-msgid "The secret is only available when you first create the application."
-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 "無需任何身份驗證å³å¯å­˜å–該程å¼ç¢¼ç‰‡æ®µã€‚"
@@ -42695,7 +43433,7 @@ msgid "The time period in seconds that the maximum requests per project limit ap
msgstr "æ¯å€‹å°ˆæ¡ˆæœ€å¤§è«‹æ±‚所é©ç”¨çš„時間間隔(秒)。"
msgid "The top-level group, including any subgroups and projects, will be placed into a %{link_start}read-only%{link_end} state soon. To retain write access, ask your top-level group Owner to %{reduce_link_start}reduce the number of users%{link_end} to %{free_user_limit} or less. An Owner of the top-level group can also start a free trial or upgrade to a paid tier, which do not have user limits. The Owners of the top-level group have also been notified."
-msgstr ""
+msgstr "最上層群組,包括任何å­ç¾¤çµ„和專案,將很快處於 %{link_start}read-only%{link_end} 狀態。è¦ä¿ç•™å¯«å…¥æ¬Šé™ï¼Œè«‹è®“您的最上層群組æ“有者 %{reduce_link_start}將使用者數é‡%{link_end} 減少到 %{free_user_limit} 或更少。最上層群組的æ“有者還å¯ä»¥é–‹å§‹å…費試用或å‡ç´šåˆ°æ²’有使用者é™åˆ¶çš„付費層級,最上層群組的æ“有者也已收到通知。"
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "æ›´æ–°æ“作將在 %{number_of_minutes} 分é˜å¾Œé€¾æ™‚。å°æ–¼å¤§åž‹ç‰ˆæœ¬åº«ï¼Œè«‹ä½¿ç”¨è¤‡è£½ (Clone) /推é€(Push)組åˆã€‚"
@@ -42997,6 +43735,9 @@ msgstr "æå–作業時發生錯誤。"
msgid "There was an error fetching the jobs for your project."
msgstr "為您的專案å–得作業時發生錯誤。"
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
msgid "There was an error fetching the top labels for the selected group"
msgstr "å–å¾—é¸ä¸­ç¾¤çµ„的頂級標記時發生錯誤"
@@ -43186,14 +43927,8 @@ 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 "此附件已被截斷,以é¿å…超éŽæœ€å¤§å…è¨±çš„é™„ä»¶å¤§å° %{size_limit}。 其中包括%{count} 個%{issuables} 中的%{written_count}個。考慮縮å°é¸æ“‡çš„ %{issuables} å†åŒ¯å‡ºã€‚"
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr "此附件已被截斷,以é¿å…超éŽæœ€å¤§å…è¨±çš„é™„ä»¶å¤§å° %{size_limit}。 其中包括了 %{issues_count} 個議題中的 %{written_count} 個,考慮縮å°åŒ¯å‡ºçš„é¸æ“‡ç¯„åœã€‚"
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{merge_requests_count} merge requests have been included. Consider re-exporting with a narrower selection of merge requests."
-msgstr "此附件已被截斷,以é¿å…超éŽæœ€å¤§å…è¨±çš„é™„ä»¶å¤§å° %{size_limit}。 其中包括%{merge_requests_count} 個åˆä½µè«‹æ±‚中的%{written_count}個。考慮縮å°åˆä½µè«‹æ±‚çš„é¸æ“‡ç¯„åœã€‚"
-
-msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{requirements_count} requirements have been included. Consider re-exporting with a narrower selection of requirements."
-msgstr "此附件已被截斷,以é¿å…超éŽæœ€å¤§å…è¨±çš„é™„ä»¶å¤§å° %{size_limit}。 其中包括了 %{requirements_count} é …è¦æ±‚中的 %{written_count} 項;考慮縮å°åŒ¯å‡ºçš„é¸æ“‡ç¯„åœã€‚"
+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 "該å€å¡Šç‚ºè‡ªæˆ‘引用"
@@ -43693,6 +44428,9 @@ msgstr "此版本庫上次檢查於%{last_check_timestamp}。檢查%{strong_star
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr "此版本庫上次檢查於%{last_check_timestamp}。檢查通éŽã€‚"
+msgid "This rule is invalid because no one can approve it for one or more of these reasons:"
+msgstr ""
+
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "此執行器(runner)僅在å—ä¿è­·åˆ†æ”¯ä¸Šè§¸ç™¼çš„æµæ°´ç·šä¸ŠåŸ·è¡Œ"
@@ -43747,11 +44485,8 @@ 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 will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr "這會使您註冊的應用程å¼å’Œ U2F / WebAuthn 設備無效。"
-
-msgid "This will invalidate your registered applications and U2F devices."
-msgstr "這將使您的註冊應用程å¼å’Œ U2F 設備無效。"
+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 "這將移除該專案和 %{fork_source} 之間的分å‰ï¼ˆFork)關係。"
@@ -44199,6 +44934,9 @@ msgstr "首先,請您輸入您的 Gitea 伺æœå™¨åœ°å€å’Œä¸€å€‹ %{link_to_per
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 help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}."
msgstr "為了幫助改進GitLab,我們會定期%{docs_link}。您å¯ä»¥éš¨æ™‚通éŽ%{settings_link}更改設定。"
@@ -44577,7 +45315,7 @@ msgstr "主題已æˆåŠŸæ›´æ–°ã€‚"
msgid "TopicSelect|%d topic found"
msgid_plural "TopicSelect|%d topics found"
-msgstr[0] ""
+msgstr[0] "找到 %d 個主題"
msgid "TopicSelect|No matching results"
msgstr "沒有符åˆçš„çµæžœ"
@@ -44684,6 +45422,9 @@ 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 "父群組已經有一個具有相åŒè·¯å¾‘çš„å­ç¾¤çµ„或專案。"
@@ -44772,9 +45513,6 @@ msgstr "觸發å¢é›†é‡å»ºç´¢å¼•ã€‚僅使用 13.0 或更高版本建立的索引
msgid "Trigger job"
msgstr "觸發作業"
-msgid "Trigger manual job"
-msgstr "觸發手動作業"
-
msgid "Trigger pipelines for mirror updates"
msgstr "觸發映åƒæ›´æ–°çš„æµæ°´ç·š"
@@ -44877,9 +45615,6 @@ msgstr "Twitter:"
msgid "Two-Factor Authentication"
msgstr "雙因å­èªè­‰"
-msgid "Two-Factor Authentication code"
-msgstr "雙因å­èªè­‰é©—證碼"
-
msgid "Two-factor Authentication"
msgstr "雙因å­èªè­‰"
@@ -44925,12 +45660,6 @@ msgstr "é¡žåž‹"
msgid "Type to search"
msgstr "輸入查詢"
-msgid "U2F Devices (%{length})"
-msgstr "U2F設備(%{length})"
-
-msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr "U2Fåªæ”¯æ´åœ¨HTTPS的網站。請è¯çµ¡ç®¡ç†å“¡ç²å¾—更多訊æ¯"
-
msgid "URL"
msgstr "URL"
@@ -45036,6 +45765,9 @@ msgstr "無法å–得上游和下游æµæ°´ç·šã€‚"
msgid "Unable to find Jira project to import data from."
msgstr "無法找到è¦åŒ¯å…¥è³‡æ–™çš„Jira專案。"
+msgid "Unable to find saved reply"
+msgstr ""
+
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr "無法完全載入é è¨­æ交訊æ¯ã€‚ 您ä»ç„¶å¯ä»¥å¥—用此建議,並且æ交訊æ¯å°‡æ˜¯æ­£ç¢ºçš„。"
@@ -45135,6 +45867,9 @@ msgstr "ä¸å¯ç”¨"
msgid "Unban"
msgstr "解除å°éŽ–"
+msgid "Uncategorized"
+msgstr ""
+
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr "如果您更改分支,未æ交的更改將éºå¤±ã€‚您想è¦ç¹¼çºŒå—Žï¼Ÿ"
@@ -45192,6 +45927,15 @@ msgstr "除éžèˆ‡GitLabå¦æœ‰æ›¸é¢å”議,å¦å‰‡é»žæ“Šã€Œä¸Šå‚³è¨±å¯ã€å³è¡¨
msgid "Unlimited"
msgstr "ç„¡é™"
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group} 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 "Unlink"
msgstr "å–消關è¯"
@@ -45279,6 +46023,9 @@ msgstr "ä¸æ”¯æ´çš„排åºå€¼ã€‚"
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr "傳入了ä¸æ”¯æ´çš„待辦事項類型。支æ´çš„待辦事項類型為: %{todo_types}"
+msgid "Untitled"
+msgstr "無標題"
+
msgid "Unused"
msgstr "未使用"
@@ -45348,17 +46095,20 @@ msgstr "請更新您的書籤 URLs, 因為éŽæ¿¾/排åºçš„分支 URL 已變更ã€
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 ""
+msgstr "您確定è¦å¾¹é™¤ç„¡æ³•å­˜å–的物件嗎?"
msgid "UpdateProject|Are you sure you want to prune?"
-msgstr ""
+msgstr "你確定è¦å¾¹é™¤å—Žï¼Ÿ"
msgid "UpdateProject|Cancel"
-msgstr ""
+msgstr "å–消"
msgid "UpdateProject|Cannot rename project because it contains container registry tags!"
msgstr "因為專案容器映åƒåº«å·²æœ‰æ¨™ç±¤ï¼Œç„¡æ³•æ›´æ–°ç•¶å‰å°ˆæ¡ˆï¼"
@@ -45370,7 +46120,7 @@ msgid "UpdateProject|Could not set the default branch. Do you have a branch name
msgstr "無法設定é è¨­åˆ†æ”¯ã€‚您的版本庫中是å¦æœ‰å為「HEADã€çš„分支?(%{linkStart}我è¦å¦‚何解決此å•é¡Œï¼Ÿ%{linkEnd})"
msgid "UpdateProject|Learn more."
-msgstr ""
+msgstr "了解更多。"
msgid "UpdateProject|New visibility level not allowed!"
msgstr "ä¸å…許新的å¯è¦‹æ€§ç´šåˆ¥ï¼"
@@ -45379,13 +46129,13 @@ msgid "UpdateProject|Project could not be updated!"
msgstr "專案無法更新ï¼"
msgid "UpdateProject|Prune"
-msgstr ""
+msgstr "徹除"
msgid "UpdateProject|Prune unreachable objects"
-msgstr ""
+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}版本庫檢查碼驗證失敗"
@@ -45474,6 +46224,9 @@ msgstr "使用趨勢"
msgid "Usage statistics"
msgstr "使用情æ³çµ±è¨ˆ"
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
msgstr "容器註冊表的專案級儲存統計訊æ¯åƒ…是定å‘的,ä¸åŒ…括實例範åœé‡è¤‡è³‡æ–™åˆªé™¤æ‰€ä¿ç•™çš„。"
@@ -45645,6 +46398,9 @@ msgstr "此命å空間目å‰æ²’有使用共享執行器的專案"
msgid "UsageQuota|This table omits projects that used 0 CI/CD minutes or 0 shared runners duration"
msgstr "此表çœç•¥äº†ä½¿ç”¨ 0 CI/CD 分é˜æˆ– 0 共享執行器æŒçºŒæ™‚間的專案"
+msgid "UsageQuota|Transfer"
+msgstr ""
+
msgid "UsageQuota|Uploads"
msgstr "上傳"
@@ -45849,6 +46605,9 @@ msgstr "使用上é¢çš„ %{strongStart}測試%{strongEnd} é¸é …建立事件。"
msgid "Use the Apple App Store Connect integration to easily connect to the Apple App Store with Fastlane in CI/CD pipelines."
msgstr "使用 Apple App Store Connect æ•´åˆï¼Œé€éŽ CI/CD æµæ°´ç·šä¸­çš„ Fastlane 輕鬆連çµè‡³ Apple App Store。"
+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 "使用以下連çµç¢ºèªæ‚¨çš„é›»å­éƒµä»¶åœ°å€ (%{email})"
@@ -45861,6 +46620,9 @@ msgstr "使用公共雲實例 URL (%{kroki_public_url}) 或 %{install_link_start
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 "使用此令牌來驗證收到的有效資料。"
@@ -45934,6 +46696,9 @@ 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 identity was successfully created."
msgstr "å·²æˆåŠŸå»ºç«‹ä½¿ç”¨è€…身份。"
@@ -46360,6 +47125,9 @@ msgstr "價值æµåˆ†æžå¯ä»¥å¹«åŠ©æ‚¨äº†è§£åœ˜éšŠçš„效率"
msgid "Value Streams Dashboard (Beta)"
msgstr "價值æµå„€è¡¨æ¿ï¼ˆæ¸¬è©¦ç‰ˆï¼‰"
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
msgid "Value might contain a variable reference"
msgstr "值å¯èƒ½åŒ…å«è®Šæ•¸å¼•ç”¨"
@@ -46466,11 +47234,14 @@ msgid "ValueStreamAnalytics|Value stream"
msgstr "價值æµ"
msgid "ValueStreamAnalytics|View details"
-msgstr ""
+msgstr "查看詳情"
msgid "ValueStreamEvent|Items in stage"
msgstr "階段中的事項"
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
msgid "ValueStreamEvent|Stage time (median)"
msgstr "階段時間(中ä½æ•¸ï¼‰"
@@ -46615,6 +47386,9 @@ msgstr "檢視與編輯 Markdown,å¯é¸æ“‡é è¦½æ ¼å¼åŒ–的輸出。"
msgid "View blame"
msgstr "查看責任歸屬(blame)"
+msgid "View blame as separate pages"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr "在該變更之å‰æª¢è¦–責任歸屬(blame)"
@@ -46643,9 +47417,6 @@ msgstr "查看文件"
msgid "View eligible approvers"
msgstr "查看具備相關資格的核准者"
-msgid "View entire blame"
-msgstr "查看全部的責任歸屬(blame)"
-
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
msgstr[0] "查看%d項展示產物"
@@ -46846,6 +47617,69 @@ msgstr "%{formattedStartDate}到今天"
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|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 "ç”±%{user}%{statusStart}確èª%{statusEnd}æ–¼%{timeago}"
@@ -47236,12 +48070,6 @@ msgstr "我們在專案%{project}中找ä¸åˆ°èˆ‡%{scope}相符åˆçš„%{term}"
msgid "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
msgstr "無法連接Prometheus伺æœå™¨ã€‚伺æœå™¨ä¸å†å­˜åœ¨ï¼Œæˆ–者設定訊æ¯éœ€è¦æ›´æ–°ã€‚"
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr "我們åµæ¸¬åˆ°æœ‰äººä¼åœ–使用錯誤的雙因å­èº«ä»½é©—證碼登入您的 %{host} 帳號"
-
-msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code, from the following IP address: %{ip}, at %{time}"
-msgstr "我們åµæ¸¬åˆ°æœ‰äººä¼åœ–使用錯誤的雙因å­èº«ä»½é©—證碼從下列 IP ä½å€ç™»å…¥æ‚¨çš„ %{host} 帳號:%{ip},於 %{time}"
-
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr "我們在%{humanized_resource_name}檢測到潛在濫用行為。請輸入此reCAPTCHA驗證碼並繼續。"
@@ -47293,9 +48121,6 @@ msgstr "我們會通知 %{inviter} 您拒絕了他們加入 GitLab 的邀請。æ
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 "您的 GitLab Enterprise Edition %{plan_name} 已經接近使用者上é™ï¼Œç›®å‰æ‚¨æœ‰ %{active_user_count} 個啟用的使用者,已接近é™åˆ¶çš„ %{maximum_user_count} 人。"
-msgid "We'll continuously validate your pipeline configuration. The validation results will appear here."
-msgstr "我們將ä¸æ–·é©—證您的æµæ°´ç·šè¨­å®šã€‚é©—è­‰çµæžœå°‡é¡¯ç¤ºåœ¨æ­¤è™•ã€‚"
-
msgid "We'll use this to help surface the right features and information to you."
msgstr "我們將使用它來幫助å‘您展示正確的功能和訊æ¯ã€‚"
@@ -47437,6 +48262,9 @@ 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 "該專案內的 webhook 在多次é‡è©¦å¾Œå°‡è‡ªå‹•è¢«åœç”¨ã€‚"
@@ -47699,6 +48527,10 @@ msgstr "使用%{code_open}http://%{code_close}或%{code_open}https://%{code_clos
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] ""
+
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] "當您的試用期çµæŸæ™‚,您將轉到å…費版,該版本的使用者人數é™åˆ¶ç‚º %{free_user_limit} ä½ã€‚ %{free_user_limit} 個使用者將ä¿æŒæ´»èºç‹€æ…‹ï¼Œè¶…出人數é™åˆ¶çš„ä½¿ç”¨è€…å°‡è®Šæˆ %{link_start}超é™ç‹€æ…‹%{link_end} 並無法訪å•è©²çµ„。"
@@ -47736,6 +48568,9 @@ msgstr "誰將使用這個群組?"
msgid "Why are you signing up? (optional)"
msgstr "您為什麼註冊?(å¯é¸ï¼‰"
+msgid "Why is this rule invalid?"
+msgstr ""
+
msgid "Wiki"
msgstr "Wiki"
@@ -47955,8 +48790,8 @@ msgstr "ä¸ä¿®å¾©/接å—風險"
msgid "Work in progress (open and unassigned)"
msgstr "正在進行中(開啟且未指派)"
-msgid "Work in progress Limit"
-msgstr "「進行中(Work in progress, WIP)ã€çš„é™åˆ¶"
+msgid "Work in progress limit"
+msgstr ""
msgid "WorkItem|%{count} more assignees"
msgstr "åŠå…¶ä»– %{count} å指派人"
@@ -48003,6 +48838,9 @@ msgstr "加入到迭代"
msgid "WorkItem|Add to milestone"
msgstr "加入到里程碑"
+msgid "WorkItem|All activity"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "您確定è¦å–消編輯嗎?"
@@ -48025,6 +48863,15 @@ msgstr "已移除å­é …"
msgid "WorkItem|Closed"
msgstr "已關閉"
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr "轉æ›ç‚ºä»»å‹™"
+
+msgid "WorkItem|Converted to task"
+msgstr "已轉æ›ç‚ºä»»å‹™"
+
msgid "WorkItem|Create %{workItemType}"
msgstr "建立 %{workItemType}"
@@ -48049,9 +48896,15 @@ msgstr "截止日期"
msgid "WorkItem|Existing task"
msgstr "ç¾æœ‰ä»»å‹™"
+msgid "WorkItem|Failed to award emoji"
+msgstr ""
+
msgid "WorkItem|Health status"
msgstr "å¥åº·ç‹€æ…‹"
+msgid "WorkItem|History only"
+msgstr ""
+
msgid "WorkItem|Incident"
msgstr "事故"
@@ -48172,6 +49025,9 @@ msgstr "任務動作"
msgid "WorkItem|Task deleted"
msgstr "任務已移除"
+msgid "WorkItem|Task reverted"
+msgstr "任務已還原"
+
msgid "WorkItem|Tasks"
msgstr "任務"
@@ -48208,6 +49064,9 @@ msgstr "工作項目"
msgid "WorkItem|Work item not found"
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 "Would you like to create a new branch?"
msgstr "您è¦å»ºç«‹ä¸€å€‹æ–°åˆ†æ”¯å—Žï¼Ÿ"
@@ -48238,6 +49097,9 @@ msgstr "寫一個內部註釋或將您的文件拖到這裡..."
msgid "Write milestone description..."
msgstr "寫入里程碑æè¿°..."
+msgid "Write saved reply content here…"
+msgstr ""
+
msgid "Write your release notes or drag your files here…"
msgstr "撰寫發行說明(Release Notes) 或將文件拖動到此處..."
@@ -48638,9 +49500,6 @@ msgstr "您沒有更新此環境的權é™ã€‚"
msgid "You do not have permissions to run the import."
msgstr "您沒有權é™åŸ·è¡ŒåŒ¯å…¥ã€‚"
-msgid "You don't have any U2F devices registered yet."
-msgstr "您還沒有註冊任何U2F設備。"
-
msgid "You don't have any WebAuthn devices registered yet."
msgstr "您尚未註冊任何WebAuthn設備。"
@@ -48810,12 +49669,18 @@ 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 "您必須登入æ‰èƒ½æœå°‹ç‰¹å®šå°ˆæ¡ˆã€‚"
@@ -48985,6 +49850,9 @@ msgstr "您的 %{spammable_entity_type} 已被識別為垃圾郵件。請更改å
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
msgstr "您為%{strong}%{namespace_name}%{strong_close}的%{strong}%{plan_name}%{strong_close}訂閱將於%{strong}%{expires_on}%{strong_close}到期。"
+msgid "Your Activity"
+msgstr "您的活動"
+
msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details."
msgstr "您的 CI/CD 設定語法無效,請é¸å–é©—è­‰é ç°½äº†è§£æ›´å¤šè©³ç´°è³‡è¨Šã€‚"
@@ -48994,8 +49862,8 @@ msgstr "CSV匯出已經開始。完æˆå¾Œå°‡ç™¼é€é›»å­éƒµä»¶è‡³%{email}。"
msgid "Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment."
msgstr "您從專案%{project_link}匯出包å«%{count}çš„CSV文件已作為附件加入到此電å­éƒµä»¶ä¸­ã€‚"
-msgid "Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
-msgstr "您從專案%{project_name}(%{project_url})匯出包å«%{written_count}çš„CSV文件已作為附件加入到此電å­éƒµä»¶ä¸­ã€‚"
+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 import for project"
msgstr "您的專案CSV匯入"
@@ -49024,6 +49892,9 @@ msgstr "您的GitLab群組"
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 "您的 GitLab æœå‹™å¯¦ä¾‹å…許任何人註冊帳號,這å°æ–¼å…¬é–‹çš„ GitLab æœå‹™å¯¦ä¾‹å­˜åœ¨å®‰å…¨é¢¨éšªã€‚如果ä¸å¸Œæœ›å°å¤–開放使用者註冊帳號,您應該åœç”¨è¨»å†Šæ–°å¸³è™ŸåŠŸèƒ½ã€‚"
+msgid "Your GitLab version"
+msgstr "您的 GitLab 版本"
+
msgid "Your Groups"
msgstr "您的群組"
@@ -49048,6 +49919,9 @@ msgstr "您的SSH金鑰已刪除"
msgid "Your SSH keys (%{count})"
msgstr "您的SSH金鑰(%{count})"
+msgid "Your Time-based OTP device was registered!"
+msgstr "您基於時間的 OTP 設備已註冊ï¼"
+
msgid "Your To-Do List"
msgstr "您的待辦事項列表"
@@ -49093,6 +49967,9 @@ msgstr "您的動作已被拒絕,因為已é”到命å空間儲存é™åˆ¶ã€‚如
msgid "Your action succeeded."
msgstr "您的æ“作æˆåŠŸã€‚"
+msgid "Your activity"
+msgstr "您的活動"
+
msgid "Your applications (%{size})"
msgstr "您的應用程å¼(%{size})"
@@ -49102,9 +49979,6 @@ msgstr "您已授權的應用"
msgid "Your browser does not support iFrames"
msgstr "您的ç€è¦½å™¨ä¸æ”¯æ´ iFrame"
-msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
-msgstr "您的ç€è¦½å™¨ä¸æ”¯æ´U2F。請使用Google Chromeæ¡Œé¢ç‰ˆï¼ˆ41或更高版本)。"
-
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+)。"
@@ -49135,6 +50009,9 @@ msgstr "您的留言將被丟棄。"
msgid "Your commit email is used for web based operations, such as edits and merges."
msgstr "您的æ交電å­éƒµä»¶ç”¨æ–¼åŸºæ–¼ web çš„æ“作,例如編輯和åˆä½µã€‚"
+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 "需è¦æ‚¨ç•¶å‰çš„密碼來註冊雙因å­é©—證程å¼ã€‚"
@@ -49290,6 +50167,9 @@ msgstr "您的最上層群組 %{namespace_name} è¶…éŽ %{free_limit} 個使用è€
msgid "Your top-level group %{namespace_name} is over the %{free_user_limit} user limit"
msgstr "您的最上層群組 %{namespace_name} å·²è¶…éŽ %{free_user_limit} 個使用者é™åˆ¶"
+msgid "Your top-level group %{namespace_name} will move to a read-only state soon"
+msgstr ""
+
msgid "Your top-level group is over the user and storage limits and has been placed in a read-only state."
msgstr "您的最上層群組超出了使用者和儲存é™åˆ¶ï¼Œå·²è¢«ç½®æ–¼å”¯è®€ç‹€æ…‹ã€‚"
@@ -49524,6 +50404,9 @@ 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 "如果延é²ç¾¤çµ„刪除被ç¦ç”¨ï¼Œå‰‡ç„¡æ³•å•Ÿç”¨"
@@ -49848,9 +50731,6 @@ msgstr "完整報告"
msgid "ciReport|Generic Report"
msgstr "一般性報告"
-msgid "ciReport|IaC Scanning"
-msgstr "IaC 掃æ"
-
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr "é€éŽå»ºç«‹è­°é¡Œä¾†èª¿æŸ¥æ­¤æ¼æ´ž"
@@ -49915,6 +50795,9 @@ msgstr "é€éŽåˆä½µè«‹æ±‚解決"
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST IaC"
+msgstr ""
+
msgid "ciReport|Secret Detection"
msgstr "Secret 檢測"
@@ -49945,6 +50828,9 @@ msgstr "顯示 %{fetchedItems} 項,共 %{totalItems}項"
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 "éœæ…‹æ‡‰ç”¨ç¨‹å¼å®‰å…¨æ¸¬è©¦ (SAST)"
@@ -50175,7 +51061,7 @@ msgid "example.com"
msgstr "example.com"
msgid "exceeds maximum length (100 user ids)"
-msgstr ""
+msgstr "超éŽæœ€å¤§é•·åº¦ï¼ˆ100 個使用者 ID)"
msgid "exceeds maximum length (100 usernames)"
msgstr "超éŽæœ€å¤§é•·åº¦ï¼ˆ100 個使用者å)"
@@ -50217,9 +51103,6 @@ msgstr[0] "文件"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "çµæžœç„¡æ³•æ‰¾åˆ°æˆ–已與æ¼æ´žé—œè¯ã€‚"
-msgid "following"
-msgstr "已關注"
-
msgid "for"
msgstr "å°æ–¼"
@@ -50521,11 +51404,17 @@ msgstr "被 %{path_lock_user_name} 在 %{created_at} 鎖定"
msgid "manual"
msgstr "手動"
-msgid "math|Displaying this math block may cause performance issues on this page"
-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 "繪製該數學算å¼å€å¡Šæ™‚發生錯誤,%{katexMessage}"
-msgid "math|There was an error rendering this math block"
-msgstr "繪製此數學表é”å¼æ™‚發生錯誤"
+msgid "math|This math block exceeds %{maxMathChars} characters, and may cause performance issues on this page."
+msgstr "該數學算å¼å€å¡Šè¶…éŽ %{maxMathChars} 個字元,且å¯èƒ½æœƒå°Žè‡´æ­¤é é¢å‡ºç¾æ€§èƒ½å•é¡Œã€‚"
+
+msgid "math|Too many expansions. Consider using multiple math blocks."
+msgstr "太多擴展,請考慮使用多個數學算å¼å€å¡Šã€‚"
msgid "member"
msgid_plural "members"
@@ -50566,7 +51455,7 @@ msgid "mrWidgetCommitsAdded|%{strongStart}1%{strongEnd} merge commit"
msgstr "%{strongStart}1%{strongEnd} 個åˆä½µæ交"
msgid "mrWidgetCommitsAdded|Changes merged into %{targetBranch} with %{mergeCommitSha}%{squashedCommits}."
-msgstr "變更以 %{mergeCommitSha}%{squashedCommits} åˆä½µåˆ° %{targetBranch}。"
+msgstr "%{mergeCommitSha}%{squashedCommits} 的變更已åˆä½µè‡³ %{targetBranch}。"
msgid "mrWidgetCommitsAdded|The changes were not merged into %{targetBranch}."
msgstr "變更未åˆä½µåˆ° %{targetBranch}。"
@@ -50580,6 +51469,84 @@ msgstr "使用åˆä½µè«‹æ±‚å‘您的專案æ出更改建議並與您的團隊討
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr "%{boldHeaderStart}此處沒有æµæ°´ç·šã€‚%{boldHeaderEnd}"
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Select %{boldStart}Mark as ready%{boldEnd} to remove it from Draft status."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} é¸æ“‡ %{boldStart}標示為就緒%{boldEnd} 將其從è‰ç¨¿ç‹€æ…‹ä¸­ç§»é™¤ã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Users who can write to the source or target branches can resolve the conflicts."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} å¯ä»¥å¯«å…¥ä¾†æºæˆ–目標分支的使用者å¯ä»¥è§£æ±ºè¡çªã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} a Jira issue key must be mentioned in the title or description."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 標題或æ述中必須æåŠ Jira 議題密鑰。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all required approvals must be given."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 所有需求須核准。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all status checks must pass."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 所有狀態檢查必須通éŽã€‚"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all threads must be resolved."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 必須解決所有線程。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} denied licenses must be removed."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 被拒絕的許å¯è­‰å¿…須被移除。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} fast-forward merge is not possible. To merge this request, first rebase locally."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 快進 (fast-forward) åˆä½µä¸å¯ç”¨ï¼Œè¦åˆä½µé€™å€‹è«‹æ±‚,首先在本地變基 (Rebase) 。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} merge conflicts must be resolved."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} åˆä½µè¡çªå¿…須解決。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} new changes were just added."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 剛剛加入了新的變改。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} pipeline must succeed. It's waiting for a manual action to continue."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} æµæ°´ç·šå¿…é ˆæˆåŠŸï¼Œå®ƒæ­£åœ¨ç­‰å¾…手動æ“作繼續。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} pipeline must succeed. Push a commit that fixes the failure or %{linkStart}learn about other solutions.%{linkEnd}"
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} æµæ°´ç·šå¿…é ˆæˆåŠŸï¼ŒæŽ¨é€ä¿®å¾©æ•…障的æ交或%{linkStart}了解其他解決方案。%{linkEnd}"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} the source branch must be rebased onto the target branch."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 來æºåˆ†æ”¯å¿…須變基到目標分支。"
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} you can only merge after the above items are resolved."
+msgstr "%{boldStart}åˆä½µå·²å—阻:%{boldEnd} 您åªèƒ½åœ¨ä¸Šè¿°é …目解決後æ‰èƒ½åˆä½µã€‚"
+
+msgid "mrWidget|%{boldStart}Merge unavailable:%{boldEnd} merge requests are read-only in a secondary Geo node."
+msgstr "%{boldStart}åˆä½µä¸å¯ç”¨:%{boldEnd} åˆä½µè«‹æ±‚åœ¨æ¬¡è¦ Geo 節點中是唯讀的。"
+
+msgid "mrWidget|%{boldStart}Merge unavailable:%{boldEnd} merge requests are read-only on archived projects."
+msgstr "%{boldStart}åˆä½µä¸å¯ç”¨ï¼š%{boldEnd} åˆä½µè«‹æ±‚在å°å­˜å°ˆæ¡ˆä¸Šæ˜¯å”¯è®€çš„。"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Changes are being shipped…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 變更正在傳é€ä¸­â€¦â€¦"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Changes will land soon…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 變更很快就會è½å¯¦â€¦â€¦"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Drum roll, please…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 請鳴鼓..."
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Everything's good…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 一切都好…"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Lift-off in 5… 4… 3…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 5…4…3… "
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Take a deep breath and relax…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 放輕鬆並深呼å¸â€¦â€¦"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} The changes are leaving the station…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 變更正在離站..."
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} This is going to be great…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 這將會很棒……"
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} We're almost there…"
+msgstr "%{boldStart}åˆä½µä¸­!%{boldEnd} 我們快到了……"
+
+msgid "mrWidget|%{boldStart}Ready to be merged automatically.%{boldEnd} Ask someone with write access to this repository to merge this request."
+msgstr "%{boldStart}準備好自動åˆä½µã€‚%{boldEnd} è¦æ±‚å°è©²ç‰ˆæœ¬åº«å…·æœ‰å¯«å…¥æ¬Šé™çš„人åˆä½µè©²è«‹æ±‚。"
+
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}。"
@@ -50595,6 +51562,12 @@ msgstr "%{metricsLinkStart} 記憶體 %{metricsLinkEnd} 佔用 %{emphasisStart}
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr "%{metricsLinkStart} 記憶體 %{metricsLinkEnd} 佔用 %{emphasisStart} 無變化 %{emphasisEnd}, ä¿æŒåœ¨ %{memoryFrom}MB"
+msgid "mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it."
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them."
+msgstr ""
+
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr "åˆä½µä½‡åˆ—是等待åˆä½µåˆ°ç›®æ¨™åˆ†æ”¯çš„åˆä½µè«‹æ±‚列表。æ¯å€‹åˆä½µè«‹æ±‚中的變動與先å‰åˆä½µè«‹æ±‚中的變動相çµåˆï¼Œç„¶å¾Œåœ¨åˆä½µå‰é€²è¡Œæ¸¬è©¦ã€‚"
@@ -50622,12 +51595,6 @@ msgstr "核准為å¯é¸"
msgid "mrWidget|Approval password is invalid."
msgstr "核准密碼無效"
-msgid "mrWidget|Approval rule %{rules} is invalid. GitLab has approved this rule automatically to unblock the merge request. %{link}"
-msgstr "審核è¦å‰‡ %{rules} 無效,GitLab 已自動核准此è¦å‰‡ä»¥è§£éŽ–該åˆä½µè«‹æ±‚。%{link}"
-
-msgid "mrWidget|Approval rules %{rules} are invalid. GitLab has approved these rules automatically to unblock the merge request. %{link}"
-msgstr "審核è¦å‰‡ %{rules} 無效,GitLab 已自動核准這些è¦å‰‡ä»¥è§£éŽ–åˆä½µè«‹æ±‚。 %{link}"
-
msgid "mrWidget|Approve"
msgstr "核准"
@@ -50643,6 +51610,9 @@ 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 "將這些議題指派給自己"
@@ -50720,83 +51690,29 @@ msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] "æåŠçš„è­°é¡Œ"
-msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr "阻止åˆä½µï¼šæ¨™é¡Œæˆ–æ述中應æåŠ Jira 議題代號。"
-
msgid "mrWidget|Merge blocked: all required approvals must be given."
msgstr "åˆä½µè¢«é˜»æ­¢ï¼šå¿…é ˆæ供所有必è¦çš„核准。"
-msgid "mrWidget|Merge blocked: all status checks must pass."
-msgstr "åˆä½µè¢«å°éŽ–:所有狀態檢查都必須通éŽã€‚"
-
-msgid "mrWidget|Merge blocked: all threads must be resolved."
-msgstr "åˆä½µå·²å—阻:必須解決所有主題。"
-
-msgid "mrWidget|Merge blocked: denied licenses must be removed."
-msgstr "åˆä½µå·²å—阻:必須移除被拒絕的授權許å¯ã€‚"
-
-msgid "mrWidget|Merge blocked: fast-forward merge is not possible. To merge this request, first rebase locally."
-msgstr "åˆä½µå·²å—阻:快進 (fast-forward) åˆä½µä¸å¯ç”¨ï¼Œè¦åˆä½µé€™å€‹è«‹æ±‚,首先在本地變基 (Rebase) 。"
-
-msgid "mrWidget|Merge blocked: merge conflicts must be resolved."
-msgstr "åˆä½µå·²å—阻:必須解決åˆä½µè¡çªã€‚"
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue."
-msgstr "åˆä½µå·²å—阻:æµæ°´ç·šå¿…é ˆæˆåŠŸã€‚等待手動完æˆæ“作。"
-
-msgid "mrWidget|Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
-msgstr "åˆä½µå·²å—阻:æµæ°´ç·šå¿…é ˆæˆåŠŸã€‚推é€ä¸€å€‹ä¿®å¾©å¤±æ•—çš„æ交,或者%{linkStart}了解其它解決方案。%{linkEnd}"
-
-msgid "mrWidget|Merge blocked: you can only merge after the above items are resolved."
-msgstr "åˆä½µå·²å—阻:解決上述å•é¡Œå¾Œæ‰èƒ½åˆä½µã€‚"
-
msgid "mrWidget|Merge failed."
msgstr "åˆä½µå¤±æ•—。"
-msgid "mrWidget|Merge unavailable: merge requests are read-only on archived projects."
-msgstr "åˆä½µä¸å¯ç”¨ï¼šåˆä½µè«‹æ±‚在歸檔專案上是唯讀的。"
-
msgid "mrWidget|Merged by"
msgstr "åˆä½µè€…:"
-msgid "mrWidget|Merging! Changes are being shipped…"
-msgstr "åˆä½µä¸­ï¼æ­£åœ¨é€å‡ºè®Šæ›´â€¦"
-
-msgid "mrWidget|Merging! Changes will land soon…"
-msgstr "åˆä½µä¸­ï¼å³å°‡å®Œæˆâ€¦"
-
-msgid "mrWidget|Merging! Drum roll, please…"
-msgstr "åˆä½µä¸­ï¼è«‹ç¨å¾Œâ€¦"
-
-msgid "mrWidget|Merging! Everything's good…"
-msgstr "åˆä½µä¸­ï¼ä¸€åˆ‡éƒ½å¾ˆå¥½â€¦"
-
-msgid "mrWidget|Merging! Lift-off in 5… 4… 3…"
-msgstr "åˆä½µä¸­ï¼å³å°‡å®Œæˆ 5… 4… 3…"
-
-msgid "mrWidget|Merging! Take a deep breath and relax…"
-msgstr "åˆä½µä¸­ï¼è«‹ç¨å€™â€¦"
-
-msgid "mrWidget|Merging! The changes are leaving the station…"
-msgstr "åˆä½µä¸­ï¼è«‹ç¨å€™â€¦"
-
-msgid "mrWidget|Merging! This is going to be great…"
-msgstr "åˆä½µä¸­ï¼è«‹ç¨å¾Œâ€¦"
-
-msgid "mrWidget|Merging! We're almost there…"
-msgstr "åˆä½µä¸­ï¼å³å°‡å®Œæˆäº†â€¦"
-
msgid "mrWidget|More information"
msgstr "更多訊æ¯"
-msgid "mrWidget|No users match the rule's criteria."
-msgstr "沒有使用者符åˆè©²è¦å‰‡çš„標準。"
-
msgid "mrWidget|Please restore it or use a different %{type} branch."
msgstr "請還原它或使用ä¸åŒçš„ %{type} 分支。"
-msgid "mrWidget|Ready to be merged automatically. Ask someone with write access to this repository to merge this request"
-msgstr "å·²å¯è‡ªå‹•åˆä½µã€‚請具有版本庫寫入權é™çš„使用者來åˆä½µæ­¤è«‹æ±‚"
+msgid "mrWidget|Rebase"
+msgstr "變基 (Rebase)"
+
+msgid "mrWidget|Rebase in progress"
+msgstr "變基 (Rebase) 正在進行中"
+
+msgid "mrWidget|Rebase without pipeline"
+msgstr "沒有æµæ°´ç·šçš„變基 (Rebase) "
msgid "mrWidget|Refresh"
msgstr "é‡æ–°æ•´ç†"
@@ -50858,9 +51774,6 @@ msgstr "è¦æ›´æ”¹æ­¤é è¨­è¨Šæ¯ï¼Œè«‹ç·¨è¼¯åˆä½µæ交訊æ¯çš„範本。 %{lin
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr "è¦æ›´æ”¹æ­¤é è¨­è¨Šæ¯ï¼Œè«‹ç·¨è¼¯å£“縮 (Squash) æ交訊æ¯çš„範本。 %{linkStart}了解更多訊æ¯ã€‚%{linkEnd}"
-msgid "mrWidget|Users who can write to the source or target branches can resolve the conflicts."
-msgstr "å¯ä»¥å¯«å…¥ä¾†æºæˆ–目標分支的使用者å¯ä»¥è§£æ±ºè¡çªã€‚"
-
msgid "mrWidget|What is a merge train?"
msgstr "什麼是åˆä½µä½‡åˆ—?"
@@ -50885,6 +51798,9 @@ msgstr "必須是有效的IPv4或IPv6地å€"
msgid "must be a valid json schema"
msgstr "必須是有效的 json schema"
+msgid "must be a valid syntax highlighting theme ID"
+msgstr "必須是有效的語法çªé¡¯ä½ˆæ™¯ä¸»é¡Œ ID"
+
msgid "must be after start"
msgstr "必須在開始之後"
@@ -51235,7 +52151,7 @@ msgid "should be an array of %{object_name} objects"
msgstr "應該是%{object_name}物件的陣列"
msgid "should be an array of existing user ids. %{invalid} does not exist"
-msgstr ""
+msgstr "應該是ç¾å­˜ä½¿ç”¨è€… ID 的陣列, %{invalid} ä¸å­˜åœ¨"
msgid "should be an array of existing usernames. %{invalid} does not exist"
msgstr "應為ç¾å­˜ä½¿ç”¨è€…å稱的陣列, %{invalid} ä¸å­˜åœ¨"
diff --git a/package.json b/package.json
index 7b4eb71fe99..f9299d66410 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"block-dependencies": "node scripts/frontend/block_dependencies.js",
"check:startup_css": "scripts/frontend/startup_css/startup_css_changed.sh",
"clean": "rm -rf public/assets tmp/cache/*-loader",
- "dev-server": "NODE_OPTIONS=\"--max-old-space-size=3584\" node scripts/frontend/webpack_dev_server.js",
+ "dev-server": "NODE_OPTIONS=\"--max-old-space-size=4096\" node scripts/frontend/webpack_dev_server.js",
"file-coverage": "scripts/frontend/file_test_coverage.js",
"lint-docs": "scripts/lint-doc.sh",
"internal:eslint": "eslint --cache --max-warnings 0 --report-unused-disable-directives --ext .js,.vue,.graphql",
@@ -42,75 +42,76 @@
"storybook:build": "yarn --cwd ./storybook build --quiet",
"storybook:start": "./scripts/frontend/start_storybook.sh",
"swagger:validate": "swagger-cli validate",
- "webpack": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.config.js",
- "webpack-vendor": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.vendor.config.js",
- "webpack-prod": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.js"
+ "webpack": "NODE_OPTIONS=\"--max-old-space-size=4096\" webpack --config config/webpack.config.js",
+ "webpack-vendor": "NODE_OPTIONS=\"--max-old-space-size=4096\" webpack --config config/webpack.vendor.config.js",
+ "webpack-prod": "NODE_OPTIONS=\"--max-old-space-size=4096\" NODE_ENV=production webpack --config config/webpack.config.js"
},
"dependencies": {
- "@_ueberdosis/prosemirror-tables": "^1.1.3",
"@apollo/client": "^3.5.10",
"@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2",
- "@cubejs-client/core": "^0.31.15",
- "@cubejs-client/vue": "^0.31.19",
+ "@cubejs-client/core": "^0.32.0",
+ "@cubejs-client/vue": "^0.32.0",
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/fonts": "^1.2.0",
- "@gitlab/svgs": "3.20.0",
- "@gitlab/ui": "55.2.1",
+ "@gitlab/svgs": "3.26.0",
+ "@gitlab/ui": "58.2.0",
"@gitlab/visual-review-tools": "1.7.3",
- "@gitlab/web-ide": "0.0.1-dev-20230216131813",
+ "@gitlab/web-ide": "0.0.1-dev-20230223005157",
+ "@mattiasbuelens/web-streams-adapter": "^0.1.0",
"@rails/actioncable": "6.1.4-7",
"@rails/ujs": "6.1.4-7",
"@sourcegraph/code-host-integration": "0.0.84",
- "@tiptap/core": "^2.0.0-beta.202",
- "@tiptap/extension-blockquote": "^2.0.0-beta.202",
- "@tiptap/extension-bold": "^2.0.0-beta.202",
- "@tiptap/extension-bubble-menu": "2.0.0-beta.200",
- "@tiptap/extension-bullet-list": "^2.0.0-beta.202",
- "@tiptap/extension-code": "^2.0.0-beta.202",
- "@tiptap/extension-code-block": "^2.0.0-beta.202",
- "@tiptap/extension-code-block-lowlight": "2.0.0-beta.202",
- "@tiptap/extension-document": "^2.0.0-beta.202",
- "@tiptap/extension-dropcursor": "^2.0.0-beta.202",
- "@tiptap/extension-gapcursor": "^2.0.0-beta.202",
- "@tiptap/extension-hard-break": "^2.0.0-beta.202",
- "@tiptap/extension-heading": "^2.0.0-beta.202",
- "@tiptap/extension-highlight": "^2.0.0-beta.209",
- "@tiptap/extension-history": "^2.0.0-beta.202",
- "@tiptap/extension-horizontal-rule": "^2.0.0-beta.202",
- "@tiptap/extension-image": "^2.0.0-beta.202",
- "@tiptap/extension-italic": "^2.0.0-beta.202",
- "@tiptap/extension-link": "^2.0.0-beta.202",
- "@tiptap/extension-list-item": "^2.0.0-beta.202",
- "@tiptap/extension-ordered-list": "^2.0.0-beta.202",
- "@tiptap/extension-paragraph": "^2.0.0-beta.202",
- "@tiptap/extension-strike": "^2.0.0-beta.202",
- "@tiptap/extension-subscript": "^2.0.0-beta.202",
- "@tiptap/extension-superscript": "^2.0.0-beta.202",
- "@tiptap/extension-table": "^2.0.0-beta.202",
- "@tiptap/extension-table-cell": "^2.0.0-beta.202",
- "@tiptap/extension-table-header": "^2.0.0-beta.202",
- "@tiptap/extension-table-row": "^2.0.0-beta.202",
- "@tiptap/extension-task-item": "^2.0.0-beta.202",
- "@tiptap/extension-task-list": "^2.0.0-beta.202",
- "@tiptap/extension-text": "^2.0.0-beta.202",
- "@tiptap/suggestion": "^2.0.0-beta.202",
- "@tiptap/vue-2": "2.0.0-beta.200",
+ "@tiptap/core": "^2.0.0-beta.220",
+ "@tiptap/extension-blockquote": "^2.0.0-beta.220",
+ "@tiptap/extension-bold": "^2.0.0-beta.220",
+ "@tiptap/extension-bubble-menu": "2.0.0-beta.220",
+ "@tiptap/extension-bullet-list": "^2.0.0-beta.220",
+ "@tiptap/extension-code": "^2.0.0-beta.220",
+ "@tiptap/extension-code-block": "^2.0.0-beta.220",
+ "@tiptap/extension-code-block-lowlight": "2.0.0-beta.220",
+ "@tiptap/extension-document": "^2.0.0-beta.220",
+ "@tiptap/extension-dropcursor": "^2.0.0-beta.220",
+ "@tiptap/extension-gapcursor": "^2.0.0-beta.220",
+ "@tiptap/extension-hard-break": "^2.0.0-beta.220",
+ "@tiptap/extension-heading": "^2.0.0-beta.220",
+ "@tiptap/extension-highlight": "^2.0.0-beta.220",
+ "@tiptap/extension-history": "^2.0.0-beta.220",
+ "@tiptap/extension-horizontal-rule": "^2.0.0-beta.220",
+ "@tiptap/extension-image": "^2.0.0-beta.220",
+ "@tiptap/extension-italic": "^2.0.0-beta.220",
+ "@tiptap/extension-link": "^2.0.0-beta.220",
+ "@tiptap/extension-list-item": "^2.0.0-beta.220",
+ "@tiptap/extension-ordered-list": "^2.0.0-beta.220",
+ "@tiptap/extension-paragraph": "^2.0.0-beta.220",
+ "@tiptap/extension-strike": "^2.0.0-beta.220",
+ "@tiptap/extension-subscript": "^2.0.0-beta.220",
+ "@tiptap/extension-superscript": "^2.0.0-beta.220",
+ "@tiptap/extension-table": "^2.0.0-beta.220",
+ "@tiptap/extension-table-cell": "^2.0.0-beta.220",
+ "@tiptap/extension-table-header": "^2.0.0-beta.220",
+ "@tiptap/extension-table-row": "^2.0.0-beta.220",
+ "@tiptap/extension-task-item": "^2.0.0-beta.220",
+ "@tiptap/extension-task-list": "^2.0.0-beta.220",
+ "@tiptap/extension-text": "^2.0.0-beta.220",
+ "@tiptap/pm": "^2.0.0-beta.220",
+ "@tiptap/suggestion": "^2.0.0-beta.220",
+ "@tiptap/vue-2": "2.0.0-beta.220",
"apollo-upload-client": "15.0.0",
"apollo3-cache-persist": "^0.14.1",
"autosize": "^5.0.1",
"axios": "^0.24.0",
"babel-loader": "^8.2.5",
"babel-plugin-lodash": "^3.3.4",
- "bootstrap": "4.5.3",
+ "bootstrap": "4.6.2",
"browserslist": "^4.21.3",
"cache-loader": "^4.1.0",
"canvas-confetti": "^1.4.0",
"clipboard": "^2.0.8",
"compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1",
- "core-js": "^3.28.0",
+ "core-js": "^3.29.1",
"cron-validator": "^1.1.1",
"cronstrue": "^1.122.0",
"cropper": "^2.3.0",
@@ -121,12 +122,12 @@
"dateformat": "^5.0.1",
"deckar01-task_list": "^2.3.1",
"diff": "^3.4.0",
- "dompurify": "^2.4.3",
+ "dompurify": "^2.4.5",
"dropzone": "^4.2.0",
"editorconfig": "^0.15.3",
"emoji-regex": "^10.0.0",
- "esbuild": "0.17.4",
- "esbuild-loader": "^2.21.0",
+ "esbuild": "0.17.11",
+ "esbuild-loader": "^3.0.1",
"fast-mersenne-twister": "1.0.2",
"file-loader": "^6.2.0",
"fuzzaldrin-plus": "^0.6.0",
@@ -163,9 +164,6 @@
"portal-vue": "^2.1.7",
"postcss": "8.4.14",
"prosemirror-markdown": "1.9.1",
- "prosemirror-model": "^1.18.1",
- "prosemirror-state": "^1.4.1",
- "prosemirror-view": "^1.28.2",
"raphael": "^2.2.7",
"raw-loader": "^4.0.2",
"rehype-raw": "^6.1.1",
@@ -180,13 +178,14 @@
"string-hash": "1.1.3",
"style-loader": "^2.0.0",
"swagger-ui-dist": "4.12.0",
+ "thread-loader": "^3.0.4",
"three": "^0.143.0",
"timeago.js": "^4.0.2",
"tippy.js": "^6.3.7",
"traverse": "^0.6.7",
"unified": "^10.1.2",
- "unist-builder": "^3.0.0",
- "unist-util-visit-parents": "^5.1.0",
+ "unist-builder": "^3.0.1",
+ "unist-util-visit-parents": "^5.1.3",
"url-loader": "^4.1.1",
"uuid": "8.1.0",
"visibilityjs": "^1.2.4",
@@ -200,6 +199,7 @@
"vue-virtual-scroll-list": "^1.4.7",
"vuedraggable": "^2.23.0",
"vuex": "^3.6.2",
+ "web-streams-polyfill": "^3.2.1",
"web-vitals": "^0.2.4",
"webpack": "^4.46.0",
"webpack-bundle-analyzer": "^4.6.1",
@@ -210,13 +210,17 @@
"yaml": "^2.0.0-10"
},
"devDependencies": {
- "@gitlab/eslint-plugin": "18.1.0",
+ "@gitlab/eslint-plugin": "18.2.0",
"@gitlab/stylelint-config": "4.1.0",
- "@graphql-eslint/eslint-plugin": "3.12.0",
+ "@graphql-eslint/eslint-plugin": "3.16.1",
"@testing-library/dom": "^7.16.2",
"@types/jest": "^28.1.3",
+ "@vue/compat": "^3.2.47",
+ "@vue/compiler-sfc": "^3.2.47",
"@vue/test-utils": "1.3.0",
+ "@vue/test-utils-vue3": "npm:@vue/test-utils@2",
"@vue/vue2-jest": "^28.1.0",
+ "@vue/vue3-jest": "^29.2.3",
"ajv": "^8.10.0",
"ajv-formats": "^2.1.1",
"axios-mock-adapter": "^1.15.0",
@@ -225,7 +229,7 @@
"cheerio": "^1.0.0-rc.9",
"commander": "^2.20.3",
"custom-jquery-matchers": "^2.1.0",
- "eslint": "8.32.0",
+ "eslint": "8.36.0",
"eslint-import-resolver-jest": "3.0.2",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-import": "^2.27.5",
@@ -249,8 +253,6 @@
"mock-apollo-client": "1.2.0",
"nodemon": "^2.0.19",
"prettier": "2.2.1",
- "prosemirror-schema-basic": "^1.2.0",
- "prosemirror-schema-list": "^1.2.2",
"prosemirror-test-builder": "^1.1.0",
"purgecss": "^4.0.3",
"purgecss-from-html": "^4.0.3",
@@ -258,6 +260,8 @@
"stylelint": "^14.9.1",
"swagger-cli": "^4.0.4",
"timezone-mock": "^1.0.8",
+ "vue-loader-vue3": "npm:vue-loader@17",
+ "vue-test-utils-compat": "^0.0.11",
"webpack-dev-server": "4.11.1",
"xhr-mock": "^2.5.1",
"yarn-check-webpack-plugin": "^1.2.0",
diff --git a/patches/@vue+compiler-sfc+3.2.47.patch b/patches/@vue+compiler-sfc+3.2.47.patch
new file mode 100644
index 00000000000..9cbedbb0d0f
--- /dev/null
+++ b/patches/@vue+compiler-sfc+3.2.47.patch
@@ -0,0 +1,28 @@
+diff --git a/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js b/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js
+index 6093500..5e9bcbb 100644
+--- a/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js
++++ b/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js
+@@ -5226,7 +5226,8 @@ function parse$4(source, { sourceMap = true, filename = DEFAULT_FILENAME, source
+ const templateBlock = (descriptor.template = createBlock(node, source, false));
+ templateBlock.ast = node;
+ // warn against 2.x <template functional>
+- if (templateBlock.attrs.functional) {
++ // disabled by patch-package in gitlab as temporary migration
++ if (false && templateBlock.attrs.functional) {
+ const err = new SyntaxError(`<template functional> is no longer supported in Vue 3, since ` +
+ `functional components no longer have significant performance ` +
+ `difference from stateful ones. Just use a normal <template> ` +
+diff --git a/node_modules/@vue/compiler-sfc/dist/compiler-sfc.esm-browser.js b/node_modules/@vue/compiler-sfc/dist/compiler-sfc.esm-browser.js
+index 2ce8d7a..2fbe75b 100644
+--- a/node_modules/@vue/compiler-sfc/dist/compiler-sfc.esm-browser.js
++++ b/node_modules/@vue/compiler-sfc/dist/compiler-sfc.esm-browser.js
+@@ -37376,7 +37376,8 @@ function parse$5(source, { sourceMap = true, filename = DEFAULT_FILENAME, source
+ const templateBlock = (descriptor.template = createBlock(node, source, false));
+ templateBlock.ast = node;
+ // warn against 2.x <template functional>
+- if (templateBlock.attrs.functional) {
++ // disabled by patch-package in gitlab as temporary migration
++ if (false && templateBlock.attrs.functional) {
+ const err = new SyntaxError(`<template functional> is no longer supported in Vue 3, since ` +
+ `functional components no longer have significant performance ` +
+ `difference from stateful ones. Just use a normal <template> ` +
diff --git a/patches/@vue+vue3-jest+29.2.3.patch b/patches/@vue+vue3-jest+29.2.3.patch
new file mode 100644
index 00000000000..3b0ced98400
--- /dev/null
+++ b/patches/@vue+vue3-jest+29.2.3.patch
@@ -0,0 +1,22 @@
+diff --git a/node_modules/@vue/vue3-jest/lib/process.js b/node_modules/@vue/vue3-jest/lib/process.js
+index a8d1c5c..a6b2036 100644
+--- a/node_modules/@vue/vue3-jest/lib/process.js
++++ b/node_modules/@vue/vue3-jest/lib/process.js
+@@ -108,12 +108,17 @@ function processTemplate(descriptor, filename, config) {
+ (descriptor.script && descriptor.script.lang)
+ const isTS = /^typescript$|tsx?$/.test(lang)
+
++ const compiler = typeof vueJestConfig.compiler === 'string'
++ ? require(vueJestConfig.compiler)
++ : vueJestConfig.compiler
++
+ const result = compileTemplate({
+ id: filename,
+ source: template.content,
+ filename,
+ preprocessLang: template.lang,
+ preprocessOptions: vueJestConfig[template.lang],
++ compiler,
+ compilerOptions: {
+ bindingMetadata: bindings,
+ mode: 'module',
diff --git a/patches/vue-loader-vue3+17.0.1.patch b/patches/vue-loader-vue3+17.0.1.patch
new file mode 100644
index 00000000000..91979df28a5
--- /dev/null
+++ b/patches/vue-loader-vue3+17.0.1.patch
@@ -0,0 +1,78 @@
+diff --git a/node_modules/vue-loader-vue3/dist/descriptorCache.js b/node_modules/vue-loader-vue3/dist/descriptorCache.js
+index 65a7318..ee425cd 100644
+--- a/node_modules/vue-loader-vue3/dist/descriptorCache.js
++++ b/node_modules/vue-loader-vue3/dist/descriptorCache.js
+@@ -2,7 +2,7 @@
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.getDescriptor = exports.setDescriptor = void 0;
+ const fs = require("fs");
+-const compiler_sfc_1 = require("vue/compiler-sfc");
++const compiler_sfc_1 = require("@vue/compiler-sfc");
+ const cache = new Map();
+ function setDescriptor(filename, entry) {
+ cache.set(cleanQuery(filename), entry);
+diff --git a/node_modules/vue-loader-vue3/dist/formatError.js b/node_modules/vue-loader-vue3/dist/formatError.js
+index b342426..ec51886 100644
+--- a/node_modules/vue-loader-vue3/dist/formatError.js
++++ b/node_modules/vue-loader-vue3/dist/formatError.js
+@@ -1,7 +1,7 @@
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.formatError = void 0;
+-const compiler_sfc_1 = require("vue/compiler-sfc");
++const compiler_sfc_1 = require("@vue/compiler-sfc");
+ const chalk = require("chalk");
+ function formatError(err, source, file) {
+ const loc = err.loc;
+diff --git a/node_modules/vue-loader-vue3/dist/index.js b/node_modules/vue-loader-vue3/dist/index.js
+index 825b3af..263e908 100644
+--- a/node_modules/vue-loader-vue3/dist/index.js
++++ b/node_modules/vue-loader-vue3/dist/index.js
+@@ -5,7 +5,7 @@ const path = require("path");
+ const qs = require("querystring");
+ const loaderUtils = require("loader-utils");
+ const hash = require("hash-sum");
+-const compiler_sfc_1 = require("vue/compiler-sfc");
++const compiler_sfc_1 = require("@vue/compiler-sfc");
+ const select_1 = require("./select");
+ const hotReload_1 = require("./hotReload");
+ const cssModules_1 = require("./cssModules");
+diff --git a/node_modules/vue-loader-vue3/dist/resolveScript.js b/node_modules/vue-loader-vue3/dist/resolveScript.js
+index 31205c6..b15b390 100644
+--- a/node_modules/vue-loader-vue3/dist/resolveScript.js
++++ b/node_modules/vue-loader-vue3/dist/resolveScript.js
+@@ -2,7 +2,7 @@
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.resolveScript = exports.canInlineTemplate = void 0;
+ const util_1 = require("./util");
+-const compiler_sfc_1 = require("vue/compiler-sfc");
++const compiler_sfc_1 = require("@vue/compiler-sfc");
+ const clientCache = new WeakMap();
+ const serverCache = new WeakMap();
+ /**
+diff --git a/node_modules/vue-loader-vue3/dist/stylePostLoader.js b/node_modules/vue-loader-vue3/dist/stylePostLoader.js
+index f694d25..1d15be2 100644
+--- a/node_modules/vue-loader-vue3/dist/stylePostLoader.js
++++ b/node_modules/vue-loader-vue3/dist/stylePostLoader.js
+@@ -1,7 +1,7 @@
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ const qs = require("querystring");
+-const compiler_sfc_1 = require("vue/compiler-sfc");
++const compiler_sfc_1 = require("@vue/compiler-sfc");
+ // This is a post loader that handles scoped CSS transforms.
+ // Injected right before css-loader by the global pitcher (../pitch.js)
+ // for any <style scoped> selection requests initiated from within vue files.
+diff --git a/node_modules/vue-loader-vue3/dist/templateLoader.js b/node_modules/vue-loader-vue3/dist/templateLoader.js
+index 78b603c..538f3ca 100644
+--- a/node_modules/vue-loader-vue3/dist/templateLoader.js
++++ b/node_modules/vue-loader-vue3/dist/templateLoader.js
+@@ -6,7 +6,7 @@ const formatError_1 = require("./formatError");
+ const descriptorCache_1 = require("./descriptorCache");
+ const resolveScript_1 = require("./resolveScript");
+ const util_1 = require("./util");
+-const compiler_sfc_1 = require("vue/compiler-sfc");
++const compiler_sfc_1 = require("@vue/compiler-sfc");
+ // Loader that compiles raw template into JavaScript functions.
+ // This is injected by the global pitcher (../pitch) for template
+ // selection requests initiated from vue files.
diff --git a/public/500.html b/public/500.html
index b9de6994d58..9c04a3db339 100644
--- a/public/500.html
+++ b/public/500.html
@@ -73,7 +73,7 @@
500
</h1>
<div class="container">
- <h3>Whoops, something went wrong on our end.</h3>
+ <h3>We're sorry. Something went wrong on our end.</h3>
<hr />
<!-- REQUEST_ID -->
<p>Try refreshing the page, or going back and attempting the action again.</p>
diff --git a/public/502.html b/public/502.html
index f3ccf40a643..8d6a95f1b1d 100644
--- a/public/502.html
+++ b/public/502.html
@@ -73,7 +73,7 @@
502
</h1>
<div class="container">
- <h3>Whoops, GitLab is taking too much time to respond.</h3>
+ <h3>We're sorry. GitLab is taking too much time to respond.</h3>
<hr />
<p>Try refreshing the page, or going back and attempting the action again.</p>
<p>Please contact your GitLab administrator if this problem persists.</p>
diff --git a/public/503.html b/public/503.html
index a81fa7f889a..5c29808b4a1 100644
--- a/public/503.html
+++ b/public/503.html
@@ -73,7 +73,7 @@
503
</h1>
<div class="container">
- <h3>Whoops, GitLab is currently unavailable.</h3>
+ <h3>We're sorry. GitLab is currently unavailable.</h3>
<hr />
<p>Try refreshing the page, or going back and attempting the action again.</p>
<p>Please contact your GitLab administrator if this problem persists.</p>
diff --git a/qa/Gemfile b/qa/Gemfile
index 9e41b5ddeed..9e35c619c5b 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -2,14 +2,14 @@
source 'https://rubygems.org'
-gem 'gitlab-qa', '~> 9', require: 'gitlab/qa'
+gem 'gitlab-qa', '~> 9', '>= 9.1.2', require: 'gitlab/qa'
gem 'activesupport', '~> 6.1.7.2' # This should stay in sync with the root's Gemfile
gem 'allure-rspec', '~> 2.20.0'
gem 'capybara', '~> 3.38.0'
gem 'capybara-screenshot', '~> 1.0.26'
gem 'rake', '~> 13', '>= 13.0.6'
gem 'rspec', '~> 3.12'
-gem 'selenium-webdriver', '~> 4.8'
+gem 'selenium-webdriver', '~> 4.8', '>= 4.8.1'
gem 'airborne', '~> 0.3.7', require: false # airborne is messing with rspec sandboxed mode so not requiring by default
gem 'rest-client', '~> 2.1.0'
gem 'rspec-retry', '~> 0.6.2', require: 'rspec/retry'
@@ -21,8 +21,8 @@ gem 'rotp', '~> 6.2.2'
gem 'parallel', '~> 1.22', '>= 1.22.1'
gem 'rainbow', '~> 3.1.1'
gem 'rspec-parameterized', '~> 1.0.0'
-gem 'octokit', '~> 6.0.1'
-gem "faraday-retry", "~> 2.0"
+gem 'octokit', '~> 6.1.0'
+gem "faraday-retry", "~> 2.1"
gem 'webdrivers', '~> 5.2'
gem 'zeitwerk', '~> 2.6', '>= 2.6.7'
gem 'influxdb-client', '~> 2.9'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index d544aa685a5..c3faf5841fc 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -51,7 +51,7 @@ GEM
chemlab (~> 0.4)
coderay (1.1.2)
colorize (0.8.1)
- concurrent-ruby (1.1.10)
+ concurrent-ruby (1.2.2)
confiner (0.4.0)
gitlab (>= 4.17)
zeitwerk (>= 2.5, < 3)
@@ -69,7 +69,7 @@ GEM
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.0)
- faraday-retry (2.0.0)
+ faraday-retry (2.1.0)
faraday (~> 2.0)
ffi (1.15.5)
ffi-compiler (1.0.1)
@@ -102,11 +102,12 @@ GEM
gitlab (4.18.0)
httparty (~> 0.18)
terminal-table (>= 1.5.1)
- gitlab-qa (9.0.0)
+ gitlab-qa (9.1.2)
activesupport (~> 6.1)
gitlab (~> 4.18.0)
http (~> 5.0)
nokogiri (~> 1.10)
+ parallel (>= 1, < 2)
rainbow (>= 3, < 4)
table_print (= 1.5.7)
zeitwerk (>= 2, < 3)
@@ -151,8 +152,8 @@ 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)
@@ -173,17 +174,17 @@ GEM
method_source (1.0.0)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
- mime-types-data (3.2022.0105)
+ mime-types-data (3.2023.0218.1)
mini_mime (1.1.0)
mini_portile2 (2.8.1)
- minitest (5.17.0)
+ minitest (5.18.0)
multi_json (1.15.0)
multi_xml (0.6.0)
netrc (0.11.0)
nokogiri (1.14.2)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
- octokit (6.0.1)
+ octokit (6.1.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
oj (3.13.23)
@@ -203,7 +204,7 @@ GEM
pry-byebug (3.10.1)
byebug (~> 11.0)
pry (>= 0.13, < 0.15)
- public_suffix (5.0.0)
+ public_suffix (5.0.1)
racc (1.6.2)
rack (2.2.3.1)
rack-test (1.1.0)
@@ -259,7 +260,7 @@ GEM
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
- selenium-webdriver (4.8.0)
+ selenium-webdriver (4.8.1)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
@@ -274,13 +275,13 @@ GEM
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
- tzinfo (2.0.5)
+ tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
- unicode-display_width (2.3.0)
+ unicode-display_width (2.4.2)
unparser (0.6.5)
diff-lcs (~> 1.3)
parser (>= 3.1.0)
@@ -314,14 +315,14 @@ DEPENDENCIES
confiner (~> 0.4)
deprecation_toolkit (~> 2.0.3)
faker (~> 3.1, >= 3.1.1)
- faraday-retry (~> 2.0)
+ faraday-retry (~> 2.1)
fog-core (= 2.1.0)
fog-google (~> 1.19)
- gitlab-qa (~> 9)
+ gitlab-qa (~> 9, >= 9.1.2)
influxdb-client (~> 2.9)
knapsack (~> 4.0)
nokogiri (~> 1.14, >= 1.14.2)
- octokit (~> 6.0.1)
+ octokit (~> 6.1.0)
parallel (~> 1.22, >= 1.22.1)
parallel_tests (~> 4.2)
pry-byebug (~> 3.10.1)
@@ -334,7 +335,7 @@ DEPENDENCIES
rspec-retry (~> 0.6.2)
rspec_junit_formatter (~> 0.6.0)
ruby-debug-ide (~> 0.7.3)
- selenium-webdriver (~> 4.8)
+ selenium-webdriver (~> 4.8, >= 4.8.1)
slack-notifier (~> 2.4)
terminal-table (~> 3.0.2)
warning (~> 1.3)
@@ -342,4 +343,4 @@ DEPENDENCIES
zeitwerk (~> 2.6, >= 2.6.7)
BUNDLED WITH
- 2.4.6
+ 2.4.8
diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
index 3cb501efe13..22e61c97bdb 100644
--- a/qa/lib/gitlab/page/group/settings/usage_quotas.rb
+++ b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
@@ -23,12 +23,11 @@ module Gitlab
# Storage section
link :storage_tab
link :purchase_more_storage
- div :used_storage_message
+ div :namespace_usage_total
div :group_usage_message
div :dependency_proxy_usage
span :dependency_proxy_size
div :container_registry_usage
- div :project_storage_used
div :project
div :storage_type_legend
span :container_registry_size
diff --git a/qa/qa.rb b/qa/qa.rb
index cb1278771d9..a395dc6e0b0 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -82,7 +82,8 @@ module QA
"jetbrains" => "JetBrains",
"vscode" => "VSCode",
"registry_with_cdn" => "RegistryWithCDN",
- "fips" => "FIPS"
+ "fips" => "FIPS",
+ "ci_cd_settings" => "CICDSettings"
)
loader.setup
diff --git a/qa/qa/fixtures/kubernetes_agent/agentk-manifest.yaml.erb b/qa/qa/fixtures/kubernetes_agent/agentk-manifest.yaml.erb
deleted file mode 100644
index e6ec4528d0d..00000000000
--- a/qa/qa/fixtures/kubernetes_agent/agentk-manifest.yaml.erb
+++ /dev/null
@@ -1,111 +0,0 @@
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: gitlab-agent
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: gitlab-agent
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: gitlab-agent
- template:
- metadata:
- labels:
- app: gitlab-agent
- spec:
- serviceAccountName: gitlab-agent
- containers:
- - name: agent
- image: "registry.gitlab.com/gitlab-org/cluster-integration/gitlab-agent/agentk:<%= Runtime::Env.gitlab_agentk_version %>"
- args:
- - --token-file=/config/token
- - --kas-address
- - "<%= kas_wss_address %>"
- <% if QA::Runtime::Env.qa_cookies.to_s.include?("gitlab_canary=true") %>
- - --kas-header
- - "Cookie: gitlab_canary=true"
- <% end %>
- volumeMounts:
- - name: token-volume
- mountPath: /config
- env:
- - name: POD_NAMESPACE
- valueFrom:
- fieldRef:
- fieldPath: metadata.namespace
- - name: POD_NAME
- valueFrom:
- fieldRef:
- fieldPath: metadata.name
- - name: SERVICE_ACCOUNT_NAME
- valueFrom:
- fieldRef:
- fieldPath: spec.serviceAccountName
- volumes:
- - name: token-volume
- secret:
- secretName: gitlab-agent-token
- strategy:
- type: RollingUpdate
- rollingUpdate:
- maxSurge: 0
- maxUnavailable: 1
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: gitlab-agent-write
-rules:
- - resources:
- - "*"
- apiGroups:
- - "*"
- verbs:
- - create
- - update
- - delete
- - patch
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: gitlab-agent-write-binding
-roleRef:
- name: gitlab-agent-write
- kind: ClusterRole
- apiGroup: rbac.authorization.k8s.io
-subjects:
- - name: gitlab-agent
- kind: ServiceAccount
- namespace: default
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: gitlab-agent-read
-rules:
- - resources:
- - "*"
- apiGroups:
- - "*"
- verbs:
- - get
- - list
- - watch
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: gitlab-agent-read-binding
-roleRef:
- name: gitlab-agent-read
- kind: ClusterRole
- apiGroup: rbac.authorization.k8s.io
-subjects:
- - name: gitlab-agent
- kind: ServiceAccount
- namespace: default
diff --git a/qa/qa/fixtures/mocks/import/github.yml b/qa/qa/fixtures/mocks/import/github.yml
index 9cabdee1025..b8e137abfbb 100644
--- a/qa/qa/fixtures/mocks/import/github.yml
+++ b/qa/qa/fixtures/mocks/import/github.yml
@@ -2741,3 +2741,77 @@
},
"url": "https://api.github.com/repos/gitlab-qa-github/import-test/branches/release/protection"
}
+
+- request:
+ path: /repos/gitlab-qa-github/import-test/collaborators
+ method: GET
+ query_params:
+ page: '1'
+ per_page: '100'
+ headers:
+ Host: api.github.com
+ response:
+ status: 200
+ headers:
+ Content-Type: application/json; charset=utf-8
+ X-Ratelimit-Limit: '5000'
+ X-Ratelimit-Remaining: '5000'
+ body: |
+ [
+ {
+ "avatar_url": "https://avatars.githubusercontent.com/u/40021320?v=4",
+ "events_url": "https://api.github.com/users/gitlab-qa/events{/privacy}",
+ "followers_url": "https://api.github.com/users/gitlab-qa/followers",
+ "following_url": "https://api.github.com/users/gitlab-qa/following{/other_user}",
+ "gists_url": "https://api.github.com/users/gitlab-qa/gists{/gist_id}",
+ "gravatar_id": "",
+ "html_url": "https://github.com/gitlab-qa",
+ "id": 40021320,
+ "login": "gitlab-qa",
+ "node_id": "MDQ6VXNlcjQwMDIxMzIw",
+ "organizations_url": "https://api.github.com/users/gitlab-qa/orgs",
+ "permissions": {
+ "admin": false,
+ "maintain": false,
+ "pull": true,
+ "push": true,
+ "triage": true
+ },
+ "received_events_url": "https://api.github.com/users/gitlab-qa/received_events",
+ "repos_url": "https://api.github.com/users/gitlab-qa/repos",
+ "role_name": "write",
+ "site_admin": false,
+ "starred_url": "https://api.github.com/users/gitlab-qa/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/gitlab-qa/subscriptions",
+ "type": "User",
+ "url": "https://api.github.com/users/gitlab-qa"
+ },
+ {
+ "avatar_url": "https://avatars.githubusercontent.com/u/59606922?v=4",
+ "events_url": "https://api.github.com/users/gitlab-qa-github/events{/privacy}",
+ "followers_url": "https://api.github.com/users/gitlab-qa-github/followers",
+ "following_url": "https://api.github.com/users/gitlab-qa-github/following{/other_user}",
+ "gists_url": "https://api.github.com/users/gitlab-qa-github/gists{/gist_id}",
+ "gravatar_id": "",
+ "html_url": "https://github.com/gitlab-qa-github",
+ "id": 59606922,
+ "login": "gitlab-qa-github",
+ "node_id": "MDQ6VXNlcjU5NjA2OTIy",
+ "organizations_url": "https://api.github.com/users/gitlab-qa-github/orgs",
+ "permissions": {
+ "admin": true,
+ "maintain": true,
+ "pull": true,
+ "push": true,
+ "triage": true
+ },
+ "received_events_url": "https://api.github.com/users/gitlab-qa-github/received_events",
+ "repos_url": "https://api.github.com/users/gitlab-qa-github/repos",
+ "role_name": "admin",
+ "site_admin": false,
+ "starred_url": "https://api.github.com/users/gitlab-qa-github/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/gitlab-qa-github/subscriptions",
+ "type": "User",
+ "url": "https://api.github.com/users/gitlab-qa-github"
+ }
+ ]
diff --git a/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/gitlab_ci.yaml.erb b/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/gitlab_ci.yaml.erb
new file mode 100644
index 00000000000..394c6689eef
--- /dev/null
+++ b/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/gitlab_ci.yaml.erb
@@ -0,0 +1,8 @@
+install:
+ image: maven:3.6-jdk-11
+ script:
+ - "mvn install -U -s settings.xml"
+ only:
+ - "<%= imported_project.default_branch %>"
+ tags:
+ - "runner-for-<%= imported_project.group.name %>" \ No newline at end of file
diff --git a/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/settings.xml.erb b/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/settings.xml.erb
new file mode 100644
index 00000000000..4bcd63b3c6d
--- /dev/null
+++ b/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/settings.xml.erb
@@ -0,0 +1,23 @@
+<settings>
+ <servers>
+ <server>
+ <id>central-proxy</id>
+ <configuration>
+ <httpHeaders>
+ <property>
+ <name>Private-Token</name>
+ <value><%= personal_access_token %></value>
+ </property>
+ </httpHeaders>
+ </configuration>
+ </server>
+ </servers>
+ <mirrors>
+ <mirror>
+ <id>central-proxy</id>
+ <name>GitLab proxy of central repo</name>
+ <url><%= gitlab_address_with_port %>/api/v4/groups/<%= imported_project.group.id %>/-/packages/maven</url>
+ <mirrorOf>central</mirrorOf>
+ </mirror>
+ </mirrors>
+</settings> \ No newline at end of file
diff --git a/qa/qa/flow/login.rb b/qa/qa/flow/login.rb
index 564a51ee483..2702b52f2ef 100644
--- a/qa/qa/flow/login.rb
+++ b/qa/qa/flow/login.rb
@@ -21,8 +21,8 @@ module QA
def sign_in(as: nil, address: :gitlab, skip_page_validation: false, admin: false)
Page::Main::Login.perform { |p| p.redirect_to_login_page(address) }
- unless Page::Main::Login.perform(&:on_login_page?)
- Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?)
+ if !Page::Main::Login.perform(&:on_login_page?) && Page::Main::Menu.perform(&:signed_in?)
+ Page::Main::Menu.perform(&:sign_out)
end
Page::Main::Login.perform do |login|
diff --git a/qa/qa/flow/pipeline.rb b/qa/qa/flow/pipeline.rb
index fb6a5425a6e..0765a8758ec 100644
--- a/qa/qa/flow/pipeline.rb
+++ b/qa/qa/flow/pipeline.rb
@@ -24,6 +24,14 @@ module QA
index.wait_for_latest_pipeline(status: status, wait: wait)
end
end
+
+ def visit_pipeline_job_page(job_name:, pipeline: nil)
+ pipeline.visit! unless pipeline.nil?
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job(job_name)
+ end
+ end
end
end
end
diff --git a/qa/qa/flow/saml.rb b/qa/qa/flow/saml.rb
index 8a0ebb9f551..1cf29e75c67 100644
--- a/qa/qa/flow/saml.rb
+++ b/qa/qa/flow/saml.rb
@@ -19,8 +19,6 @@ module QA
end
def enable_saml_sso(group, saml_idp_service, enforce_sso: false, default_membership_role: 'Guest')
- Runtime::Feature.enable(:group_administration_nav_item)
-
page.visit Runtime::Scenario.gitlab_address
Page::Main::Login.perform(&:sign_in_using_credentials) unless Page::Main::Menu.perform(&:signed_in?)
diff --git a/qa/qa/page/component/dropdown.rb b/qa/qa/page/component/dropdown.rb
index 01ef3533ff8..767cd40daa2 100644
--- a/qa/qa/page/component/dropdown.rb
+++ b/qa/qa/page/component/dropdown.rb
@@ -4,8 +4,18 @@ module QA
module Page
module Component
module Dropdown
- def select_item(item_text)
- find('li.gl-new-dropdown-item', text: item_text, match: :prefer_exact).click
+ # Find and click item using css selector and matching text
+ # If item_text is not provided, select the first item that matches the given css selector
+ #
+ # @param [String] item_text
+ # @param [String] css - css selector of the item
+ # @return [void]
+ def select_item(item_text, css: 'li.gl-new-dropdown-item')
+ if item_text
+ find(css, text: item_text, match: :prefer_exact).click
+ else
+ find(css, match: :first).click
+ end
end
def has_item?(item_text)
@@ -65,8 +75,8 @@ module QA
find('li.gl-new-dropdown-item span:nth-child(2)', text: item_text, exact_text: true).click
end
- def expand_select_list
- find('.gl-new-dropdown-toggle').click
+ def expand_select_list(css: '.gl-new-dropdown-toggle')
+ find(css).click
end
def wait_for_search_to_complete
diff --git a/qa/qa/page/component/groups_filter.rb b/qa/qa/page/component/groups_filter.rb
index ea91ced8679..14e49e53b75 100644
--- a/qa/qa/page/component/groups_filter.rb
+++ b/qa/qa/page/component/groups_filter.rb
@@ -16,10 +16,6 @@ module QA
base.view 'app/assets/javascripts/groups/components/groups.vue' do
element :groups_list_tree_container
end
-
- base.view 'app/views/dashboard/_groups_head.html.haml' do
- element :public_groups_tab
- end
end
private
@@ -29,14 +25,8 @@ module QA
# @return [Boolean] whether a group with given name exists
def has_filtered_group?(name)
filter_group(name)
- return true if page.has_link?(name, wait: 0) # element containing link to group
- return false unless has_element?(:public_groups_tab, wait: 0)
-
- # Check public groups
- click_element(:public_groups_tab)
- filter_group(name)
- page.has_link?(name, wait: 0)
+ page.has_link?(name, wait: 0) # element containing link to group
end
# Filter by group name
diff --git a/qa/qa/page/group/sub_menus/common.rb b/qa/qa/page/group/sub_menus/common.rb
index 2f8a3fdeb4e..3cbca3db359 100644
--- a/qa/qa/page/group/sub_menus/common.rb
+++ b/qa/qa/page/group/sub_menus/common.rb
@@ -21,7 +21,7 @@ module QA
private
def sidebar_element
- :group_sidebar
+ QA::Runtime::Env.super_sidebar_enabled? ? :navbar : :group_sidebar
end
end
end
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index f4f8820bc04..7532154f0cc 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -233,6 +233,7 @@ module QA
terms.accept_terms if terms.visible?
end
+ Page::Main::Menu.perform(&:enable_new_navigation) if Runtime::Env.super_sidebar_enabled?
Page::Main::Menu.validate_elements_present! unless skip_page_validation
end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 1e050d79e23..f86849061e8 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -6,21 +6,35 @@ module QA
class Menu < Page::Base
prepend Mobile::Page::Main::Menu if Runtime::Env.mobile_layout?
- view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
- element :sign_out_link
- element :edit_profile_link
- element :user_profile_link
- 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
+ element :user_menu, required: !QA::Runtime::Env.mobile_layout?
+ element :user_avatar_content, required: !QA::Runtime::Env.mobile_layout?
+ end
- view 'app/views/layouts/header/_default.html.haml' do
- element :navbar, required: true
- element :canary_badge_link
- element :user_avatar_content, required: !QA::Runtime::Env.mobile_layout?
- element :user_menu, required: !QA::Runtime::Env.mobile_layout?
- element :stop_impersonation_link
- element :issues_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
- element :merge_requests_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
- element :todos_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
+ view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do
+ element :sign_out_link
+ element :edit_profile_link
+ end
+ else
+ view 'app/views/layouts/header/_default.html.haml' do
+ element :navbar, required: true
+ element :canary_badge_link
+ element :user_avatar_content, required: !QA::Runtime::Env.mobile_layout?
+ element :user_menu, required: !QA::Runtime::Env.mobile_layout?
+ element :stop_impersonation_link
+ element :issues_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
+ element :merge_requests_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
+ element :todos_shortcut_button, required: !QA::Runtime::Env.mobile_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
end
view 'app/assets/javascripts/nav/components/top_nav_app.vue' do
@@ -39,7 +53,6 @@ module QA
element :admin_area_link
element :projects_dropdown
element :groups_dropdown
- element :snippets_link
element :menu_item_link
end
@@ -64,6 +77,10 @@ module QA
element :global_new_project_link
end
+ view 'app/assets/javascripts/nav/components/new_nav_toggle.vue' do
+ element :new_navigation_toggle
+ end
+
def go_to_groups
within_groups_menu do
click_element(:menu_item_link, title: 'View all groups')
@@ -81,12 +98,18 @@ module QA
end
end
+ def go_to_snippets
+ click_element(:sidebar_menu_link, menu_item: 'Snippets')
+ end
+
def go_to_create_project
click_element(:new_menu_toggle)
click_element(:global_new_project_link)
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)
@@ -211,6 +234,13 @@ module QA
has_element?(:canary_badge_link)
end
+ def enable_new_navigation
+ Runtime::Logger.info("Enabling super sidebar!")
+ 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
+
private
def within_top_menu(&block)
diff --git a/qa/qa/page/merge_request/new.rb b/qa/qa/page/merge_request/new.rb
index a1d91621090..90022616674 100644
--- a/qa/qa/page/merge_request/new.rb
+++ b/qa/qa/page/merge_request/new.rb
@@ -4,6 +4,8 @@ module QA
module Page
module MergeRequest
class New < Page::Issuable::New
+ include QA::Page::Component::Dropdown
+
view 'app/views/shared/issuable/_form.html.haml' do
element :issuable_create_button, required: true
end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index df0c0ec4202..451a9c3ee6e 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -31,6 +31,7 @@ module QA
view 'app/assets/javascripts/diffs/components/tree_list.vue' do
element :file_tree_container
+ element :diff_tree_search
end
view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do
@@ -215,14 +216,25 @@ module QA
def has_file?(file_name)
open_file_tree
+
+ return true if has_element?(:file_name_content, 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)
end
def has_no_file?(file_name)
- open_file_tree
+ # 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)
end
+ def search_file_tree(file_name)
+ open_file_tree
+ fill_element(:diff_tree_search, file_name)
+ end
+
def open_file_tree
click_element(:file_tree_button) unless has_element?(:file_tree_container)
end
@@ -233,6 +245,17 @@ module QA
has_element?(:merge_button)
end
+ def has_no_merge_button?
+ refresh
+
+ has_no_element?(:merge_button)
+ end
+
+ RSpec::Matchers.define :have_merge_button do
+ match(&:has_merge_button?)
+ match_when_negated(&:has_no_merge_button?)
+ end
+
def has_pipeline_status?(text)
# Pipelines can be slow, so we wait a bit longer than the usual 10 seconds
wait_until(max_duration: 120, sleep_interval: 5, reload: true) do
@@ -386,6 +409,7 @@ module QA
click_element(:dropdown_button)
click_element(:edit_in_ide_button)
end
+ page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
end
def add_suggestion_to_diff(suggestion, line)
diff --git a/qa/qa/page/profile/menu.rb b/qa/qa/page/profile/menu.rb
index 947fa2fec0f..651603a77db 100644
--- a/qa/qa/page/profile/menu.rb
+++ b/qa/qa/page/profile/menu.rb
@@ -8,25 +8,35 @@ module QA
# since tablets have the regular top navigation bar but still close the left nav
prepend QA::Mobile::Page::SubMenus::Common if QA::Runtime::Env.remote_mobile_device_name
- view 'app/views/layouts/nav/sidebar/_profile.html.haml' do
- element :access_token_link, 'link_to profile_personal_access_tokens_path' # rubocop:disable QA/ElementWithPattern
- element :access_token_title, 'Access Tokens' # rubocop:disable QA/ElementWithPattern
- element :top_level_items, '.sidebar-top-level-items' # rubocop:disable QA/ElementWithPattern
- element :ssh_keys, 'SSH Keys' # rubocop:disable QA/ElementWithPattern
+ 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_link('Access Tokens')
+ click_element(:access_token_link)
end
end
def click_ssh_keys
within_sidebar do
- click_link('SSH Keys')
+ click_element(:ssh_keys_link)
end
end
diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb
index 24fd34b4d22..444c67cfe4f 100644
--- a/qa/qa/page/project/job/show.rb
+++ b/qa/qa/page/project/job/show.rb
@@ -68,6 +68,14 @@ module QA
end
end
+ def has_locked_artifact?
+ has_text?('will not be deleted')
+ end
+
+ def has_unlocked_artifact?
+ has_text?('will be removed')
+ end
+
private
def loaded?(wait: 60)
diff --git a/qa/qa/page/project/monitor/alerts/index.rb b/qa/qa/page/project/monitor/alerts/index.rb
index 1363fb32498..1738ce170f2 100644
--- a/qa/qa/page/project/monitor/alerts/index.rb
+++ b/qa/qa/page/project/monitor/alerts/index.rb
@@ -13,6 +13,18 @@ module QA
def has_alert_with_title?(title)
has_link?(title, wait: 5)
end
+
+ def go_to_alert(title)
+ click_link_with_text(title)
+ end
+
+ def has_no_alert_with_title?(title)
+ has_no_link?(title, wait: 5)
+ end
+
+ def go_to_tab(name)
+ click_link_with_text(name)
+ end
end
end
end
diff --git a/qa/qa/page/project/monitor/alerts/show.rb b/qa/qa/page/project/monitor/alerts/show.rb
new file mode 100644
index 00000000000..1f3c52d8988
--- /dev/null
+++ b/qa/qa/page/project/monitor/alerts/show.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Monitor
+ module Alerts
+ class Show < Page::Base
+ view 'app/assets/javascripts/vue_shared/alert_details/components/system_notes/system_note.vue' do
+ element :alert_system_note_container
+ end
+
+ def go_to_activity_feed_tab
+ click_link_with_text('Activity feed')
+ end
+
+ def has_system_note?(text)
+ has_element?(:alert_system_note_container, text: text)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/monitor/incidents/index.rb b/qa/qa/page/project/monitor/incidents/index.rb
index 1b30e484723..04cb23da389 100644
--- a/qa/qa/page/project/monitor/incidents/index.rb
+++ b/qa/qa/page/project/monitor/incidents/index.rb
@@ -15,8 +15,16 @@ module QA
click_element :create_incident_button
end
- def has_incident?(wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME)
- wait_until(max_duration: wait) { has_element?(:incident_link) }
+ def has_incident?(wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME, title: nil)
+ 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)
+ end
+
+ def go_to_tab(tab)
+ click_link_with_text(tab)
end
end
end
diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb
index e4511ababfd..25d62ac59af 100644
--- a/qa/qa/page/project/pipeline/show.rb
+++ b/qa/qa/page/project/pipeline/show.rb
@@ -44,6 +44,17 @@ module QA
element :jobs_dropdown_menu
end
+ view 'app/views/layouts/nav/_breadcrumbs.html.haml' do
+ element :breadcrumb_links_content
+ element :breadcrumb_current_link
+ end
+
+ def pipeline_id
+ within_element(:breadcrumb_links_content) do
+ find_element(:breadcrumb_current_link).text.delete_prefix('#')
+ end
+ end
+
def running?(wait: 0)
within_element(:pipeline_header) do
page.has_content?('running', wait: wait)
diff --git a/qa/qa/page/project/settings/alerts.rb b/qa/qa/page/project/settings/alerts.rb
index 901a668f082..3ff4ef20bde 100644
--- a/qa/qa/page/project/settings/alerts.rb
+++ b/qa/qa/page/project/settings/alerts.rb
@@ -5,11 +5,12 @@ module QA
module Project
module Settings
class Alerts < Page::Base
+ 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 :incident_templates_item
element :enable_email_notification_checkbox
end
@@ -42,7 +43,7 @@ module QA
def select_issue_template(template)
click_element(:incident_templates_dropdown)
within_element :incident_templates_dropdown do
- find_element(:incident_templates_item, text: template).click
+ select_item(template)
end
end
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index 3c2b8d56f1d..b89e17910c9 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -163,10 +163,12 @@ module QA
def open_web_ide!
click_element(:web_ide_button)
+ page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
end
def open_web_ide_via_shortcut
page.driver.send_keys('.')
+ page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
end
def has_edit_fork_button?
diff --git a/qa/qa/page/project/sub_menus/common.rb b/qa/qa/page/project/sub_menus/common.rb
index 112f49a90ee..79054ec9802 100644
--- a/qa/qa/page/project/sub_menus/common.rb
+++ b/qa/qa/page/project/sub_menus/common.rb
@@ -29,7 +29,7 @@ module QA
private
def sidebar_element
- :project_sidebar
+ QA::Runtime::Env.super_sidebar_enabled? ? :navbar : :project_sidebar
end
end
end
diff --git a/qa/qa/page/project/sub_menus/monitor.rb b/qa/qa/page/project/sub_menus/monitor.rb
index 27fb58fb146..00774261467 100644
--- a/qa/qa/page/project/sub_menus/monitor.rb
+++ b/qa/qa/page/project/sub_menus/monitor.rb
@@ -31,6 +31,22 @@ module QA
end
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
+ end
+
private
def hover_monitor
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
index f9d55c0009c..b8ebaa10a49 100644
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ b/qa/qa/page/project/sub_menus/repository.rb
@@ -40,7 +40,7 @@ module QA
def go_to_repository_contributors
hover_repository do
within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Contributors')
+ click_element(:sidebar_menu_item_link, menu_item: 'Contributor statistics')
end
end
end
diff --git a/qa/qa/page/user/show.rb b/qa/qa/page/user/show.rb
index ad2de331ad9..9f5f0fae9bc 100644
--- a/qa/qa/page/user/show.rb
+++ b/qa/qa/page/user/show.rb
@@ -6,7 +6,7 @@ module QA
class Show < Page::Base
view 'app/views/users/show.html.haml' do
element :follow_user_link
- element :following_link
+ element :following_tab
end
view 'app/views/shared/users/_user.html.haml' do
@@ -21,8 +21,8 @@ module QA
click_element(:follow_user_link)
end
- def click_following_link
- click_element(:following_link)
+ def click_following_tab
+ click_element(:following_tab)
end
def click_user_link(username)
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb
index d7a220bc83f..cbb68cccdf1 100644
--- a/qa/qa/resource/api_fabricator.rb
+++ b/qa/qa/resource/api_fabricator.rb
@@ -10,6 +10,7 @@ module QA
include Support::API
include Errors
+ attr_reader :api_fabrication_http_method
attr_writer :api_client
attr_accessor :api_user, :api_resource, :api_response
@@ -49,22 +50,6 @@ module QA
end
end
- def api_put(body = api_put_body)
- response = put(
- Runtime::API::Request.new(api_client, api_put_path).url,
- body)
-
- unless response.code == HTTP_STATUS_OK
- raise ResourceFabricationFailedError, "Updating #{self.class.name} using the API failed (#{response.code}) with `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
- end
-
- process_api_response(parse_body(response))
- end
-
- def api_fabrication_http_method
- @api_fabrication_http_method ||= :post
- end
-
# Checks if a resource already exists
#
# @return [Boolean] true if the resource returns HTTP status code 200
@@ -84,14 +69,15 @@ module QA
private
- def resource_web_url(resource)
- resource.fetch(:web_url) do
- raise ResourceURLMissingError, "API resource for #{self.class.name} does not expose a `web_url` property: `#{resource}`."
- end
- end
-
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
def api_get
- process_api_response(parse_body(api_get_from(api_get_path)))
+ process_api_response(parse_body(api_get_from(api_get_path))).tap do
+ # Record method that was used to create certain resource
+ # :get - resource already existed in GitLab instance and was fetched via get request
+ # :post - resource was created from scratch using post request
+ # :put - resource was created from scratch using put request
+ @api_fabrication_http_method ||= :get
+ end
end
def api_get_from(get_path)
@@ -100,27 +86,24 @@ module QA
response = get(request.url)
if response.code == HTTP_STATUS_SERVER_ERROR
- raise InternalServerError, "Failed to GET #{request.mask_url} - (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(InternalServerError, <<~MSG.strip)
+ Failed to GET #{request.mask_url} - (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
elsif response.code != HTTP_STATUS_OK
- raise ResourceNotFoundError, "Resource at #{request.mask_url} could not be found (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(ResourceNotFoundError, <<~MSG.strip)
+ Resource at #{request.mask_url} could not be found (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
- @api_fabrication_http_method ||= :get # rubocop:disable Gitlab/ModuleWithInstanceVariables
-
response
end
- # Query parameters formatted as `?key1=value1&key2=value2...`
- #
- # @return [String]
- def query_parameters_to_string
- query_parameters.each_with_object([]) do |(k, v), arr|
- arr << "#{k}=#{v}"
- end.join('&').prepend('?').chomp('?') # prepend `?` unless the string is blank
- end
-
def api_post
- process_api_response(api_post_to(api_post_path, api_post_body))
+ process_api_response(api_post_to(api_post_path, api_post_body)).tap do
+ @api_fabrication_http_method ||= :post
+ end
end
def api_post_to(post_path, post_body, args = {})
@@ -131,7 +114,7 @@ module QA
body = flatten_hash(parse_body(graphql_response))
unless graphql_response.code == HTTP_STATUS_OK && (body[:errors].nil? || body[:errors].empty?)
- raise(ResourceFabricationFailedError, <<~MSG)
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
Fabrication of #{self.class.name} using the API failed (#{graphql_response.code}) with `#{graphql_response}`.
#{QA::Support::Loglinking.failure_metadata(graphql_response.headers[:x_request_id])}
MSG
@@ -144,36 +127,64 @@ module QA
response = post(Runtime::API::Request.new(api_client, post_path).url, post_body, args)
unless response.code == HTTP_STATUS_CREATED
- raise(
- ResourceFabricationFailedError,
- "Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
- )
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
+ Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
parse_body(response)
end
end
- def flatten_hash(param)
- param.each_pair.reduce({}) do |a, (k, v)|
- v.is_a?(Hash) ? a.merge(flatten_hash(v)) : a.merge(k.to_sym => v)
+ def api_put
+ process_api_response(api_put_to(api_put_path, api_put_body)).tap do
+ @api_fabrication_http_method ||= :put
end
end
+ def api_put_to(put_path, body)
+ response = put(Runtime::API::Request.new(api_client, put_path).url, body)
+
+ unless response.code == HTTP_STATUS_OK
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
+ Updating #{self.class.name} using the API failed (#{response.code}) with `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
+ end
+
+ parse_body(response)
+ end
+
def api_delete
request = Runtime::API::Request.new(api_client, api_delete_path)
response = delete(request.url)
unless [HTTP_STATUS_NO_CONTENT, HTTP_STATUS_ACCEPTED].include? response.code
- raise ResourceNotDeletedError, "Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(ResourceNotDeletedError, <<~MSG.strip)
+ Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
response
end
+ def resource_web_url(resource)
+ resource.fetch(:web_url) do
+ raise ResourceURLMissingError,
+ "API resource for #{self.class.name} does not expose a `web_url` property: `#{resource}`."
+ end
+ end
+
def api_client
- @api_client ||= Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'), user: api_user)
+ @api_client ||= Runtime::API::Client.new(
+ :gitlab,
+ is_new_session: !current_url.start_with?('http'),
+ user: api_user
+ )
end
+ # rubocop:enable Gitlab/ModuleWithInstanceVariables
def process_api_response(parsed_response)
self.api_response = parsed_response
@@ -191,6 +202,21 @@ module QA
def request_url(path, **opts)
Runtime::API::Request.new(api_client, path, **opts).url
end
+
+ # Query parameters formatted as `?key1=value1&key2=value2...`
+ #
+ # @return [String]
+ def query_parameters_to_string
+ query_parameters.each_with_object([]) do |(k, v), arr|
+ arr << "#{k}=#{v}"
+ end.join('&').prepend('?').chomp('?') # prepend `?` unless the string is blank
+ end
+
+ def flatten_hash(param)
+ param.each_pair.reduce({}) do |a, (k, v)|
+ v.is_a?(Hash) ? a.merge(flatten_hash(v)) : a.merge(k.to_sym => v)
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb
index 2abe1904c92..6c03f45bdfd 100644
--- a/qa/qa/resource/base.rb
+++ b/qa/qa/resource/base.rb
@@ -45,7 +45,7 @@ module QA
resource = options.fetch(:resource) { new }
parents = options.fetch(:parents) { [] }
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:browser_ui, resource, parents, args) { resource.fabricate!(*args) }
current_url
@@ -61,7 +61,7 @@ module QA
resource.eager_load_api_client!
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:api, resource, parents, args) { resource.fabricate_via_api! }
end
end
@@ -73,14 +73,14 @@ module QA
resource.eager_load_api_client!
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:api, resource, parents, args) { resource.remove_via_api! }
end
end
private
- def do_fabricate!(resource:, prepare_block:, parents: [])
+ def do_fabricate!(resource:, prepare_block:)
prepare_block.call(resource) if prepare_block
resource_web_url = yield
@@ -89,17 +89,12 @@ module QA
resource
end
- def log_and_record_fabrication(fabrication_method, resource, parents, args)
+ def log_and_record_fabrication(fabrication_method, resource, parents, _args)
start = Time.now
Support::FabricationTracker.start_fabrication
result = yield.tap do
fabrication_time = Time.now - start
- fabrication_http_method = if resource.api_fabrication_http_method == :get || resource.retrieved_from_cache
- "Retrieved"
- else
- "Built"
- end
Support::FabricationTracker.save_fabrication(:"#{fabrication_method}_fabrication", fabrication_time)
@@ -114,7 +109,7 @@ module QA
Runtime::Logger.info do
msg = ["==#{'=' * parents.size}>"]
- msg << "#{fabrication_http_method} a #{Rainbow(name).black.bg(:white)}"
+ msg << "#{fabrication_type(resource, fabrication_method)} a #{Rainbow(name).black.bg(:white)}"
msg << resource.identifier
msg << "as a dependency of #{parents.last}" if parents.any?
msg << "via #{resource.retrieved_from_cache ? 'cache' : fabrication_method}"
@@ -129,6 +124,19 @@ module QA
result
end
+ # Fetch type of fabrication, either resource was built or fetched
+ #
+ # @param [Resource] resource
+ # @param [Symbol] method
+ # @return [String]
+ def fabrication_type(resource, method)
+ return "Built" if method == :browser_ui || [:post, :put].include?(resource.api_fabrication_http_method)
+ return "Retrieved" if resource.api_fabrication_http_method == :get || resource.retrieved_from_cache
+
+ Runtime::Logger.warn("Resource fabrication http method has not been set properly, assuming :get value!")
+ "Built"
+ end
+
# Define custom attribute
#
# @param [Symbol] name
@@ -215,8 +223,7 @@ module QA
def diff(other)
return if self == other
- diff_values = self.comparable.to_a - other.comparable.to_a
- diff_values.to_h
+ (comparable.to_a - other.comparable.to_a).to_h
end
def identifier
@@ -271,7 +278,7 @@ module QA
def all_attributes
@all_attributes ||= self.class.ancestors
.select { |clazz| clazz <= QA::Resource::Base }
- .map { |clazz| clazz.instance_variable_get(:@attribute_names) }
+ .map { |clazz| clazz.instance_variable_get(:@attribute_names) } # rubocop:disable Performance/FlatMap
.flatten
.compact
end
diff --git a/qa/qa/resource/ci_cd_settings.rb b/qa/qa/resource/ci_cd_settings.rb
new file mode 100644
index 00000000000..8240321137b
--- /dev/null
+++ b/qa/qa/resource/ci_cd_settings.rb
@@ -0,0 +1,47 @@
+# rubocop:todo Naming/FileName
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ class CICDSettings < QA::Resource::Base
+ attributes :project_path,
+ :inbound_job_token_scope_enabled
+
+ attribute :mutation_id do
+ SecureRandom.hex(6)
+ end
+
+ def resource_web_url(resource)
+ super
+ rescue ResourceURLMissingError
+ # this particular resource does not expose a web_url property
+ end
+
+ def api_get_path
+ '/graphql'
+ end
+
+ alias_method :api_post_path, :api_get_path
+
+ def api_post_body
+ <<~GQL
+ mutation {
+ projectCiCdSettingsUpdate(input: {
+ clientMutationId: "#{mutation_id}"
+ inboundJobTokenScopeEnabled: #{inbound_job_token_scope_enabled}
+ fullPath: "#{project_path}"
+ })
+ {
+ ciCdSettings {
+ inboundJobTokenScopeEnabled
+ }
+ errors
+ }
+ }
+ GQL
+ end
+ end
+ end
+end
+
+# rubocop:enable Naming/FileName
diff --git a/qa/qa/resource/integrations/web_hook/smockerable.rb b/qa/qa/resource/integrations/web_hook/smockerable.rb
new file mode 100644
index 00000000000..f1d2022477e
--- /dev/null
+++ b/qa/qa/resource/integrations/web_hook/smockerable.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ module Integrations
+ module WebHook
+ module Smockerable
+ def teardown!
+ Service::DockerRun::Smocker.teardown!
+ end
+
+ def setup(mock = Vendor::Smocker::SmockerApi::DEFAULT_MOCK, session: nil, **event_args)
+ Service::DockerRun::Smocker.init(wait: 10) do |smocker|
+ smocker.register(mock, session: session)
+
+ webhook = fabricate_via_api! do |hook|
+ hook.url = smocker.url
+
+ event_args.each do |event, bool|
+ hook.send("#{event}_events=", bool)
+ end
+
+ hook
+ end
+
+ def smocker.events(session_id = nil)
+ history(session_id).map do |history_response|
+ history_response.request.fetch(:body, {})
+ end
+ end
+
+ yield(webhook, smocker)
+
+ smocker.reset
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/resource/project_web_hook.rb b/qa/qa/resource/project_web_hook.rb
index 86e662932e1..c8b6c2a6332 100644
--- a/qa/qa/resource/project_web_hook.rb
+++ b/qa/qa/resource/project_web_hook.rb
@@ -2,7 +2,17 @@
module QA
module Resource
- class ProjectWebHook < Base
+ class ProjectWebHook < WebHookBase
+ extend Integrations::WebHook::Smockerable
+
+ attributes :disabled_until, :alert_status
+
+ attribute :project do
+ Project.fabricate_via_api! do |resource|
+ resource.name = 'project-with-webhooks'
+ end
+ end
+
EVENT_TRIGGERS = %i[
issues
job
@@ -10,24 +20,13 @@ module QA
note
pipeline
push
+ releases
tag_push
wiki_page
confidential_issues
confidential_note
].freeze
- attr_accessor :url, :enable_ssl
-
- attribute :disabled_until
- attribute :id
- attribute :alert_status
-
- attribute :project do
- Project.fabricate_via_api! do |resource|
- resource.name = 'project-with-webhooks'
- end
- end
-
EVENT_TRIGGERS.each do |trigger|
attribute "#{trigger}_events".to_sym do
false
@@ -35,18 +34,13 @@ module QA
end
def initialize
- @id = nil
- @enable_ssl = false
- @alert_status = nil
- @url = nil
- end
+ super
- def fabricate_via_api!
- resource_web_url = super
-
- @id = api_response[:id]
+ @push_events_branch_filter = []
+ end
- resource_web_url
+ def add_push_event_branch_filter(branch)
+ @push_events_branch_filter << branch
end
def resource_web_url(resource)
@@ -65,7 +59,9 @@ module QA
body = {
id: project.id,
url: url,
- enable_ssl_verification: enable_ssl
+ enable_ssl_verification: enable_ssl_verification,
+ token: token,
+ push_events_branch_filter: @push_events_branch_filter.join(',')
}
EVENT_TRIGGERS.each_with_object(body) do |trigger, memo|
attr = "#{trigger}_events"
diff --git a/qa/qa/resource/runner_base.rb b/qa/qa/resource/runner_base.rb
index 399d1153dc2..9e38ba9ab64 100644
--- a/qa/qa/resource/runner_base.rb
+++ b/qa/qa/resource/runner_base.rb
@@ -35,7 +35,6 @@ module QA
@config = nil
@run_untagged = nil
@name = "qa-runner-#{SecureRandom.hex(4)}"
- @image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine-v15.8.3'
@executor = :shell
@executor_image = 'registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7'
end
@@ -95,6 +94,8 @@ module QA
def start_container_and_register
@docker_container ||= Service::DockerRun::GitlabRunner.new(name).tap do |runner|
+ runner.image = image if image
+
Support::Retrier.retry_on_exception(sleep_interval: 5) do
runner.pull
end
@@ -102,7 +103,6 @@ module QA
runner.token = token
runner.address = Runtime::Scenario.gitlab_address
runner.tags = tags if tags
- runner.image = image
runner.config = config if config
runner.executor = executor
runner.executor_image = executor_image if executor == :docker
diff --git a/qa/qa/resource/snippet.rb b/qa/qa/resource/snippet.rb
index a79e8c7de6b..84711075442 100644
--- a/qa/qa/resource/snippet.rb
+++ b/qa/qa/resource/snippet.rb
@@ -22,9 +22,7 @@ module QA
end
def fabricate!
- Page::Main::Menu.perform do |menu|
- menu.go_to_menu_dropdown_option(:snippets_link)
- end
+ Page::Main::Menu.perform(&:go_to_snippets)
Page::Dashboard::Snippet::Index.perform(&:go_to_new_snippet_page)
diff --git a/qa/qa/resource/web_hook_base.rb b/qa/qa/resource/web_hook_base.rb
new file mode 100644
index 00000000000..d7469466212
--- /dev/null
+++ b/qa/qa/resource/web_hook_base.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ class WebHookBase < Base
+ attributes :id, :url
+
+ attribute :token do
+ nil
+ end
+
+ attribute :enable_ssl_verification do
+ false
+ end
+
+ def fabricate_via_api!
+ resource_web_url = super
+
+ @id = api_response[:id]
+
+ resource_web_url
+ end
+
+ # @return [String] the api path to fetch the resource
+ def api_get_path
+ raise NotImplementedError, not_implemented_message(__callee__)
+ end
+
+ # @return [String] the api path to create the resource
+ def api_post_path
+ raise NotImplementedError, not_implemented_message(__callee__)
+ end
+
+ # @return [Hash] the payload needed to create the resource
+ def api_post_body
+ raise NotImplementedError, not_implemented_message(__callee__)
+ end
+
+ private
+
+ def not_implemented_message(callee)
+ "#{self.class} must implement ##{callee}"
+ end
+ end
+ end
+end
diff --git a/qa/qa/runtime/allure_report.rb b/qa/qa/runtime/allure_report.rb
index a9152a5555c..e726f7a316f 100644
--- a/qa/qa/runtime/allure_report.rb
+++ b/qa/qa/runtime/allure_report.rb
@@ -25,11 +25,8 @@ module QA
#
# @return [void]
def configure_allure
- # Match job names like ee:relative, ce:update etc. and set as execution environment
- env_matcher = /^(?<env>\w{2}:\S+)/
-
AllureRspec.configure do |config|
- config.results_directory = 'tmp/allure-results'
+ config.results_directory = ENV['QA_ALLURE_RESULTS_DIRECTORY'] || 'tmp/allure-results'
config.clean_results_directory = true
# automatically attach links to testcases and issues
@@ -38,11 +35,11 @@ module QA
config.issue_tag = :issue
config.link_issue_pattern = '{}'
- config.environment_properties = environment_info if Env.running_in_ci?
-
- # Set custom environment name to separate same specs executed on different environments
- if Env.running_in_ci? && Env.ci_job_name.match?(env_matcher)
- config.environment = Env.ci_job_name.match(env_matcher).named_captures['env']
+ if Env.running_in_ci?
+ config.environment_properties = environment_info
+ # Set custom environment name to separate same specs executed in different jobs
+ # Drop number postfixes from parallel jobs by only matching non whitespace characters
+ config.environment = Env.ci_job_name.match(/^\S+/)[0]
end
end
end
@@ -77,7 +74,7 @@ module QA
config.add_formatter(QA::Support::Formatters::AllureMetadataFormatter)
config.add_formatter(AllureRspecFormatter)
- config.append_after do |example|
+ config.append_after do
Allure.add_attachment(
name: 'browser.log',
source: Capybara.current_session.driver.browser.logs.get(:browser).map(&:to_s).join("\n\n"),
@@ -92,7 +89,7 @@ module QA
#
# @return [Hash]
def environment_info
- lambda do
+ -> do
return {} unless Env.admin_personal_access_token || Env.personal_access_token
client = Env.admin_personal_access_token ? API::Client.as_admin : API::Client.new
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index f01657c8deb..945823fb9c0 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -172,6 +172,7 @@ module QA
}
if QA::Runtime::Env.remote_grid
+ selenium_options[:browser] = :remote
selenium_options[:url] = QA::Runtime::Env.remote_grid
capabilities[:browserVersion] = 'latest'
capabilities['sauce:options'] = { tunnelIdentifier: QA::Runtime::Env.remote_tunnel_id }
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index b53c2320537..810912c7ccf 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -376,13 +376,13 @@ module QA
# Specifies the token that can be used for the GitHub API
def github_access_token
- ENV['GITHUB_ACCESS_TOKEN'].to_s.strip
+ ENV['QA_GITHUB_ACCESS_TOKEN'].to_s.strip
end
def require_github_access_token!
return unless github_access_token.empty?
- raise ArgumentError, "Please provide GITHUB_ACCESS_TOKEN"
+ raise ArgumentError, "Please provide QA_GITHUB_ACCESS_TOKEN"
end
def require_admin_access_token!
@@ -463,6 +463,16 @@ module QA
enabled?(ENV['QA_SAVE_TEST_METRICS'], default: false)
end
+ def ee_license
+ return ENV["QA_EE_LICENSE"] if ENV["QA_EE_LICENSE"]
+
+ ENV["EE_LICENSE"].tap do |license|
+ next unless license
+
+ Runtime::Logger.warn("EE_LICENSE environment variable is deprecated, please use QA_EE_LICENSE instead!")
+ end
+ end
+
def ee_activation_code
ENV['QA_EE_ACTIVATION_CODE']
end
@@ -514,6 +524,10 @@ module QA
ENV['DEFAULT_CHROME_DOWNLOAD_PATH'] || Dir.tmpdir
end
+ def super_sidebar_enabled?
+ enabled?(ENV['QA_SUPER_SIDEBAR_ENABLED'], default: false)
+ 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 749ebca8897..d33ae4915b5 100644
--- a/qa/qa/service/cluster_provider/gcloud.rb
+++ b/qa/qa/service/cluster_provider/gcloud.rb
@@ -33,8 +33,7 @@ module QA
delete_cluster
end
- # kas is hardcoded to staging since this test should only run in staging for now
- def install_kubernetes_agent(agent_token)
+ def install_kubernetes_agent(agent_token:, kas_address:)
install_helm
shell <<~CMD.tr("\n", ' ')
@@ -45,7 +44,8 @@ module QA
--create-namespace
--set image.tag=#{Runtime::Env.gitlab_agentk_version}
--set config.token=#{agent_token}
- --set config.kasAddress=wss://kas.staging.gitlab.com
+ --set config.kasAddress=#{kas_address}
+ --set config.kasHeaders="{Cookie: gitlab_canary=#{target_canary?}}"
CMD
end
@@ -59,6 +59,10 @@ module QA
CMD
end
+ def target_canary?
+ Runtime::Env.qa_cookies.to_s.include?("gitlab_canary=true")
+ end
+
def login_if_not_already_logged_in
if Runtime::Env.has_gcloud_credentials?
attempt_login_with_env_vars
diff --git a/qa/qa/service/docker_run/gitlab_runner.rb b/qa/qa/service/docker_run/gitlab_runner.rb
index a8fcf8f9332..d40517ae535 100644
--- a/qa/qa/service/docker_run/gitlab_runner.rb
+++ b/qa/qa/service/docker_run/gitlab_runner.rb
@@ -16,7 +16,7 @@ module QA
MSG
def initialize(name)
- @image = 'gitlab/gitlab-runner:alpine-v15.8.3'
+ @image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine'
@name = name || "qa-runner-#{SecureRandom.hex(4)}"
@run_untagged = true
@executor = :shell
diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb
index 5362124bee5..ed57d825643 100644
--- a/qa/qa/service/kubernetes_cluster.rb
+++ b/qa/qa/service/kubernetes_cluster.rb
@@ -5,6 +5,7 @@ require 'mkmf'
module QA
module Service
class KubernetesCluster
+ include Support::API
include Service::Shellout
attr_reader :api_url, :ca_certificate, :token, :rbac, :provider
@@ -36,7 +37,7 @@ module QA
end
def install_kubernetes_agent(agent_token)
- @provider.install_kubernetes_agent(agent_token)
+ @provider.install_kubernetes_agent(agent_token: agent_token, kas_address: fetch_kas_address)
end
def create_secret(secret, secret_name)
@@ -73,6 +74,17 @@ module QA
`kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'`
end
+ def fetch_kas_address
+ api_client = Runtime::API::Client.new(:gitlab)
+
+ Support::Retrier.retry_until do
+ response = get(Runtime::API::Request.new(api_client, '/metadata').url)
+ body = parse_body(response)
+
+ body.dig(:kas, :externalUrl) || raise("Failed to fetch KAS address from #{body}")
+ end
+ end
+
def fetch_credentials
return global_credentials unless rbac
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 9017aba8e4a..407e479bda2 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
@@ -1,12 +1,7 @@
# frozen_string_literal: true
module QA
- # https://github.com/gitlab-qa-github/import-test <- project under test
- #
- RSpec.describe 'Manage', product_group: :import, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391228',
- type: :waiting_on
- } do
+ RSpec.describe 'Manage', product_group: :import do
describe 'GitHub import' do
include_context 'with github import'
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 8439b881ed7..a6cdd737341 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
@@ -2,78 +2,57 @@
module QA
RSpec.describe 'Manage' do
- describe 'WebHooks integration', :requires_admin, :integrations, :orchestrated, product_group: :integrations do
+ describe(
+ 'WebHooks integration',
+ :requires_admin,
+ :integrations,
+ :orchestrated,
+ product_group: :integrations
+ ) do
before(:context) do
toggle_local_requests(true)
end
after(:context) do
- Service::DockerRun::Smocker.teardown!
+ Resource::ProjectWebHook.teardown!
end
let(:session) { SecureRandom.hex(5) }
let(:tag_name) { SecureRandom.hex(5) }
it 'sends a push event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348945' do
- setup_webhook(push: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, push: true) do |webhook, smocker|
Resource::Repository::ProjectPush.fabricate! do |project_push|
project_push.project = webhook.project
end
- wait_until do
- !smocker.history(session).empty?
- end
-
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}"
- expect(events[0].project_name).to eql(webhook.project.name)
- expect(events[0].push?).to be(true), "Not push event: \n#{events[0].raw}"
- end
+ expect_web_hook_single_event_success(webhook, smocker, type: 'push')
end
end
it 'sends a merge request event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349720' do
- setup_webhook(merge_requests: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, merge_requests: true) do |webhook, smocker|
Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.project = webhook.project
end
- wait_until do
- !smocker.history(session).empty?
- end
-
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}"
- expect(events[0].project_name).to eql(webhook.project.name)
- expect(events[0].mr?).to be(true), "Not MR event: \n#{events[0].raw}"
- end
+ expect_web_hook_single_event_success(webhook, smocker, type: 'merge_request')
end
end
it 'sends a wiki page event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349722' do
- setup_webhook(wiki_page: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, wiki_page: true) do |webhook, smocker|
Resource::Wiki::ProjectPage.fabricate_via_api! do |page|
page.project = webhook.project
end
- wait_until do
- !smocker.history(session).empty?
- end
-
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}"
- expect(events[0].project_name).to eql(webhook.project.name)
- expect(events[0].wiki?).to be(true), "Not wiki event: \n#{events[0].raw}"
- end
+ expect_web_hook_single_event_success(webhook, smocker, type: 'wiki_page')
end
end
it 'sends an issues and note event',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349723' do
- setup_webhook(issues: true, note: true) do |webhook, smocker|
+ 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
@@ -83,25 +62,24 @@ module QA
note.issue = issue
end
- wait_until do
- smocker.history(session).size > 1
- end
+ expect { smocker.events(session).size }.to eventually_eq(2)
+ .within(max_duration: 30, sleep_interval: 2),
+ -> { "Should have 2 events, got: #{smocker.stringified_history(session)}" }
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- issue_event = events.find(&:issue?)
- note_event = events.find(&:note?)
+ events = smocker.events(session)
- expect(events.size).to be(2), "Should have 2 events: \n#{events.map(&:raw).join("\n")}"
- expect(issue_event).not_to be(nil), "Not issue event: \n#{events[0].raw}"
- expect(note_event).not_to be(nil), "Not note event: \n#{events[1].raw}"
+ aggregate_failures do
+ expect(events).to include(
+ a_hash_including(object_kind: 'note'),
+ a_hash_including(object_kind: 'issue')
+ )
end
end
end
it 'sends a tag event',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/383577' do
- setup_webhook(tag_push: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, tag_push: true) do |webhook, smocker|
project_push = Resource::Repository::ProjectPush.fabricate! do |project_push|
project_push.project = webhook.project
end
@@ -112,16 +90,7 @@ module QA
tag.name = tag_name
end
- wait_until do
- smocker.history(session).size == 1
- end
-
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}"
- expect(events[0].project_name).to eql(webhook.project.name)
- expect(events[0].tag?).to be(true), "Not tag event: \n#{events[0].raw}"
- end
+ expect_web_hook_single_event_success(webhook, smocker, type: 'tag_push')
end
end
@@ -144,16 +113,19 @@ module QA
it 'hook is auto-disabled',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/389595' do
- setup_webhook(fail_mock, issues: true) do |webhook, smocker|
+ 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
+
+ # using sleep to give rate limiter a chance to activate.
+ sleep 0.5
end
- expect { smocker.history(session).size }.to eventually_eq(disabled_after)
+ expect { smocker.events(session).size }.to eventually_eq(disabled_after)
.within(max_duration: 30, sleep_interval: 2),
- -> { "Should have #{disabled_after} events, got: #{smocker.history(session).size}" }
+ -> { "Should have #{disabled_after} events, got: #{smocker.events(session).size}" }
webhook.reload!
@@ -161,34 +133,27 @@ module QA
end
end
end
+ end
- private
-
- def setup_webhook(mock = Vendor::Smocker::SmockerApi::DEFAULT_MOCK, **event_args)
- Service::DockerRun::Smocker.init(wait: 10) do |smocker|
- smocker.register(mock, session: session)
-
- webhook = Resource::ProjectWebHook.fabricate_via_api! do |hook|
- hook.url = smocker.url
-
- event_args.each do |event, bool|
- hook.send("#{event}_events=", bool)
- end
- end
+ private
- yield(webhook, smocker)
+ def expect_web_hook_single_event_success(webhook, smocker, type:)
+ expect { smocker.events(session).size }.to eventually_eq(1)
+ .within(max_duration: 30, sleep_interval: 2),
+ -> { "Should have 1 events, got: #{smocker.stringified_history(session)}" }
- smocker.reset
- end
- end
+ event = smocker.events(session).first
- def toggle_local_requests(on)
- Runtime::ApplicationSettings.set_application_settings(allow_local_requests_from_web_hooks_and_services: on)
+ aggregate_failures do
+ expect(event).to match(a_hash_including(
+ object_kind: type,
+ project: a_hash_including(name: webhook.project.name)
+ ))
end
+ end
- def wait_until(timeout = 120, &block)
- Support::Waiter.wait_until(max_duration: timeout, reload_page: false, raise_on_failure: false, &block)
- end
+ def toggle_local_requests(on)
+ Runtime::ApplicationSettings.set_application_settings(allow_local_requests_from_web_hooks_and_services: on)
end
end
end
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 2dcbbadb4aa..bc057f948a8 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
@@ -15,7 +15,7 @@ module QA
let(:source_issue_comments) do
source_issue.comments.map do |note|
- { **note.except(:id, :noteable_id), author: note[:author].except(:web_url) }
+ { **note.except(:id, :noteable_id, :project_id), author: note[:author].except(:web_url) }
end
end
@@ -32,7 +32,7 @@ module QA
let(:imported_issue_comments) do
imported_issue.comments.map do |note|
- { **note.except(:id, :noteable_id), author: note[:author].except(:web_url) }
+ { **note.except(:id, :noteable_id, :project_id), author: note[:author].except(:web_url) }
end
end
@@ -67,11 +67,7 @@ module QA
it(
'preserves related merge request',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386305',
- quarantine: {
- type: :bug,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/386308'
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386305'
) do
expect_project_import_finished_successfully
expect(imported_related_mrs).to eq([source_mr.iid])
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 9ce028318c3..d01adb5d5b4 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
@@ -65,10 +65,6 @@ module QA
let(:mrs) { fetch_mrs(imported_project, api_client) }
let(:issues) { fetch_issues(imported_project, api_client) }
- before do
- Runtime::Feature.enable(:bulk_import_projects) unless Runtime::Feature.enabled?(:bulk_import_projects)
- end
-
# rubocop:disable RSpec/InstanceVariable
after do |example|
next unless defined?(@import_time)
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 127db36052f..8c20c2cc0e2 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
@@ -37,7 +37,7 @@ module QA
let!(:source_mr_approvers) { [source_admin_user.email] }
let(:source_mr_comments) do
source_mr.comments.map do |note|
- { **note.except(:id, :noteable_id), author: note[:author].except(:web_url) }
+ { **note.except(:id, :noteable_id, :project_id), author: note[:author].except(:web_url) }
end
end
@@ -52,11 +52,11 @@ module QA
let(:imported_mr_comments) do
imported_mr.comments.map do |note|
- { **note.except(:id, :noteable_id), author: note[:author].except(:web_url) }
+ { **note.except(:id, :noteable_id, :project_id), author: note[:author].except(:web_url) }
end
end
- let(:imported_mr_reviewers) { imported_mr.reviewers.map { |reviewer| reviewer[:username] } }
+ let(:imported_mr_reviewers) { imported_mr.reviewers.pluck(:username) }
let(:imported_mr_approvers) do
imported_mr.approval_configuration[:approved_by].map { |usr| usr.dig(:user, :username) }
end
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 60ece89844d..43701a6b740 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
@@ -6,7 +6,7 @@ module QA
include_context 'with gitlab project migration'
# this spec is used as a sanity test for gitlab migration because it can run outside of orchestrated setup
- context 'with import within same instance', orchestrated: false, import: false do
+ context 'with import within same instance', :reliable, orchestrated: false, import: false do
let!(:source_project_with_readme) { true }
let!(:source_gitlab_address) { Runtime::Scenario.gitlab_address }
let!(:source_admin_api_client) { admin_api_client }
diff --git a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb b/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb
index 124b6c9cd44..c50eb2f4fdf 100644
--- a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb
@@ -79,19 +79,24 @@ module QA
'is allowed to commit to sub-group project via the API',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363349'
) do
- expect do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.api_client = parent_group_user_api_client
- commit.project = sub_group_project
- commit.branch = "new_branch_#{SecureRandom.hex(8)}"
- commit.start_branch = sub_group_project.default_branch
- commit.commit_message = 'Add new file'
- commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
- end
- rescue StandardError => e
- QA::Runtime::Logger.error("Full failure message: #{e.message}")
- raise
- end.not_to raise_error
+ # Retry is needed due to delays with project authorization updates
+ # Long term solution to accessing the status of a project authorization update
+ # has been proposed in https://gitlab.com/gitlab-org/gitlab/-/issues/393369
+ 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 = parent_group_user_api_client
+ commit.project = sub_group_project
+ commit.branch = "new_branch_#{SecureRandom.hex(8)}"
+ commit.start_branch = sub_group_project.default_branch
+ commit.commit_message = 'Add new file'
+ commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
+ end
+ rescue StandardError => e
+ QA::Runtime::Logger.error("Full failure message: #{e.message}")
+ raise
+ end.not_to raise_error
+ end
end
after do
diff --git a/qa/qa/specs/features/api/3_create/repository/files_spec.rb b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
index 71bd03fab17..7e329371745 100644
--- a/qa/qa/specs/features/api/3_create/repository/files_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
@@ -99,7 +99,6 @@ module QA
#
expect(response.headers[:cache_control]).to include("no-store")
expect(response.headers[:cache_control]).to include("no-cache")
- expect(response.headers[:pragma]).to eq("no-cache")
expect(response.headers[:expires]).to eq("Fri, 01 Jan 1990 00:00:00 GMT")
expect(response.headers[:content_disposition]).to include("attachment")
expect(response.headers[:content_disposition]).not_to include("inline")
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 8890b3ff317..c66bd16afe9 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pipeline API defined variable inheritance' do
include_context 'variable inheritance test prep'
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 bd0ec13b1f8..2d9deec399c 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pipeline with project file variables' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
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 461928cbf1f..b5a8df15ddc 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
@@ -1,10 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', product_group: :import, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391230',
- type: :waiting_on
- } do
+ RSpec.describe 'Manage', product_group: :import do
describe 'GitHub import' do
include_context 'with github import'
diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb
index 94b383a746d..ac08ecec786 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb
@@ -82,7 +82,7 @@ module QA
Page::Main::Menu.perform(&:click_user_profile_link)
Page::User::Show.perform do |show|
- show.click_following_link
+ show.click_following_tab
show.click_user_link(followed_user.username)
aggregate_failures do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
index 236af93716f..349fa054ff0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
@@ -17,11 +17,9 @@ module QA
settings.enable_ff_only
end
- Resource::Repository::ProjectPush.fabricate! do |push|
- push.project = merge_request.project
- push.file_name = "other.txt"
- push.file_content = "New file added!"
- push.new_branch = false
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = merge_request.project
+ commit.add_files([{ file_path: 'other.txt', content: 'New file added!' }])
end
merge_request.visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb
index feb0f28763c..2b04ede25b0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb
@@ -15,7 +15,7 @@ module QA
end
it 'by adding a home page to the wiki',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347809' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347809' do
project.visit!
Page::Project::Menu.perform(&:click_wiki)
@@ -36,7 +36,7 @@ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347809' do
end
it 'by adding a second page to the wiki',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347808' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347808' do
wiki.visit!
Page::Project::Wiki::Show.perform(&:click_new_page)
@@ -56,7 +56,7 @@ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347808' do
end
it 'by adding a home page to the wiki using git push',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347806' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347806' do
empty_wiki = Resource::Wiki::ProjectPage.new do |empty_wiki|
empty_wiki.project = project
end
@@ -76,7 +76,7 @@ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347806' do
end
it 'by adding a second page to the wiki using git push',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347807' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347807' do
Resource::Repository::WikiPush.fabricate! do |push|
push.file_name = "#{new_wiki_title}.md"
push.file_content = new_wiki_content
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 815a8696ff7..b8a018552c6 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
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', product_group: :source_code, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/352525',
- type: :test_environment,
- only: { job: 'review-qa-*' }
- } do
+ RSpec.describe 'Create', product_group: :source_code do
describe 'Push mirror a repository over HTTP' do
it 'configures and syncs LFS objects for a (push) mirrored repository', :aggregate_failures, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347847' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
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 63e9fdbb881..a63c5cefff4 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
@@ -52,9 +52,7 @@ module QA
shared_examples 'displaying details on index page' do |snippet_type, testcase|
it "shows correct details of #{snippet_type} including file number", testcase: testcase do
send(snippet_type)
- Page::Main::Menu.perform do |menu|
- menu.go_to_menu_dropdown_option(:snippets_link)
- end
+ Page::Main::Menu.perform(&:go_to_snippets)
Page::Dashboard::Snippet::Index.perform do |snippet|
aggregate_failures 'file content verification' do
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
index 6cbbfb9e7e5..cf1e4700863 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
@@ -1,12 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global },
- product_group: :editor,
- quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387033',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Web IDE file templates' do
include Runtime::Fixtures
@@ -16,11 +12,6 @@ module QA
project.description = 'Add file templates via the Web IDE'
project.initialize_with_readme = true
end
- Runtime::Feature.disable(:vscode_web_ide)
- end
-
- after(:all) do
- Runtime::Feature.enable(:vscode_web_ide)
end
templates = [
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb
index ded1b1c9d7c..e5e3941e0cd 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387029',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Add a directory in Web IDE' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
@@ -14,15 +12,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
project.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
context 'when a directory with the same name already exists' do
let(:directory_name) { 'first_directory' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
index 45499ea1999..58afdfe7cd1 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387723',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'First file using Web IDE' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
@@ -16,14 +14,9 @@ module QA
let(:file_name) { 'the very first file.txt' }
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
it "creates the first file in an empty project via Web IDE", testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347803' do
project.visit!
Page::Project::Show.perform(&:create_first_new_file!)
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb
index 3ea87d90c2d..9c40a3abe52 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387035',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Link to line in Web IDE' do
let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:project) do
@@ -14,12 +12,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
end
after do
- Runtime::Feature.enable(:vscode_web_ide)
project.remove_via_api!
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb
deleted file mode 100644
index 7195dd5c970..00000000000
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor do
- describe 'Open a fork in Web IDE',
- skip: {
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/351696",
- type: :flaky
- } do
- let(:parent_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.name = 'parent-project'
- project.initialize_with_readme = true
- end
- end
-
- before do
- Runtime::Feature.disable(:vscode_web_ide)
- end
-
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
- context 'when a user does not have permissions to commit to the project' do
- let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) }
-
- context 'when no fork is present' do
- it 'suggests to create a fork when a user clicks Web IDE in the main project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347823' do
- Flow::Login.sign_in(as: user)
-
- parent_project.visit!
- Page::Project::Show.perform(&:open_web_ide!)
-
- Page::Project::WebIDE::Edit.perform(&:fork_project!)
-
- submit_merge_request_upstream
- end
- end
-
- context 'when a fork is already created' do
- let(:fork_project) do
- Resource::Fork.fabricate_via_api! do |fork|
- fork.user = user
- fork.upstream = parent_project
- end
- end
-
- it 'opens the fork when a user clicks Web IDE in the main project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347824' do
- Flow::Login.sign_in(as: user)
- fork_project.upstream.visit!
- Page::Project::Show.perform do |project_page|
- expect(project_page).to have_edit_fork_button
-
- project_page.open_web_ide!
- end
-
- submit_merge_request_upstream
- end
-
- after do
- fork_project.project.remove_via_api!
- end
- end
-
- def submit_merge_request_upstream
- Page::Project::WebIDE::Edit.perform do |ide|
- ide.wait_until_ide_loads
- expect(ide).to have_project_path("#{user.username}/#{parent_project.name}")
-
- ide.add_file('new file', 'some random text')
- ide.commit_changes(open_merge_request: true)
- end
-
- Page::MergeRequest::New.perform(&:create_merge_request)
-
- parent_project.visit!
- Page::Project::Menu.perform(&:click_merge_requests)
- expect(page).to have_content('Update new file')
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb
index 02d2710656d..bbfc3ba8ccd 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387031',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Open Web IDE from Diff Tab' do
files = [
{
@@ -47,15 +45,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
merge_request.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
it 'opens and edits a multi-file merge request in Web IDE from Diff Tab', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347724' do
Page::MergeRequest::Show.perform do |show|
show.click_diffs_tab
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
index 4c21581781d..05c58b66b09 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387043',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Review a merge request in Web IDE' do
let(:new_file) { 'awesome_new_file.txt' }
let(:original_text) { 'Text' }
@@ -26,15 +24,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
merge_request.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
it 'opens and edits a merge request in Web IDE', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347786' do
Page::MergeRequest::Show.perform do |show|
show.click_open_in_web_ide
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
index 080832990c9..8082c54a6ee 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
@@ -1,13 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' },
- feature_flag: { name: 'vscode_web_ide', scope: :global },
- product_group: :editor,
- quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387928',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' }, product_group: :editor do
describe 'Git Server Hooks' do
let(:file_path) { File.join(Runtime::Path.fixtures_path, 'web_ide', 'README.md') }
@@ -20,15 +15,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
project.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
context 'with custom error messages' do
it 'renders preconfigured error message when user hook failed on commit in WebIDE',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/364751' do
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb
index b83a95694de..abc7c37a1d4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb
@@ -1,9 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', product_group: :editor,
- feature_flag: { name: 'vscode_web_ide', scope: :global },
- quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387032', type: :stale } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Upload a file in Web IDE' do
let(:file_path) { File.join(Runtime::Path.fixtures_path, 'web_ide', file_name) }
@@ -15,17 +14,12 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
project.visit!
Page::Project::Show.perform(&:open_web_ide!)
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
context 'when a file with the same name already exists' do
let(:file_name) { 'README.md' }
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
new file mode 100644
index 00000000000..072c957f4dc
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb
@@ -0,0 +1,448 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security, quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/396855',
+ type: :flaky
+ } do
+ describe "Unlocking job artifacts across parent-child pipelines" do
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'unlock-job-artifacts-parent-child-project'
+ end
+ end
+
+ let!(:runner) do
+ Resource::ProjectRunner.fabricate! do |runner|
+ runner.project = project
+ runner.name = executor
+ runner.tags = [executor]
+ end
+ end
+
+ let(:parent_test_job_name) { 'test-job-parent' }
+ let(:child_test_job_name) { 'test-job-child' }
+
+ let(:previous_successful_pipeline) do
+ Resource::Pipeline.fabricate_via_api! do |pipeline|
+ pipeline.project = project
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ project.visit!
+ end
+
+ context 'without strategy:depend' do
+ let(:strategy) { nil }
+
+ before do
+ add_parent_child_ci_files
+ Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
+ previous_successful_pipeline
+ Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
+ end
+
+ context 'when latest pipeline family is successful' do
+ before do
+ update_parent_child_ci_files
+ end
+
+ it 'unlocks job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/395516' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+ end
+ end
+
+ context 'when latest parent pipeline failed' do
+ before do
+ update_failed_parent_ci_file
+ end
+
+ it 'does not unlock job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396243' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_failed
+ # FIXME: this should be unlocked,
+ # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+ end
+ end
+
+ context 'when latest child pipeline failed' do
+ before do
+ update_failed_child_ci_file
+ end
+
+ it 'unlocks job artifacts from previous successful pipeline family because the latest parent is successful',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396244' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_failed
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+ end
+ end
+ end
+
+ context 'with strategy:depend' do
+ let(:strategy) { 'depend' }
+
+ before do
+ add_parent_child_ci_files
+ Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
+ previous_successful_pipeline
+ Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
+ end
+
+ context 'when latest pipeline family is successful' do
+ before do
+ update_parent_child_ci_files
+ end
+
+ it 'unlocks job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396245' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+ end
+ end
+
+ context 'when latest parent pipeline failed' do
+ before do
+ update_failed_parent_ci_file
+ end
+
+ it 'does not unlock job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396246' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ # FIXME: this should be unlocked,
+ # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575
+ expect(job).to be_failed
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+ end
+ end
+
+ context 'when latest child pipeline failed' do
+ before do
+ update_failed_child_ci_file
+ end
+
+ it 'does not unlock job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396248' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful
+ # FIXME: this should be unlocked,
+ # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_failed
+ # FIXME: this should be unlocked,
+ # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+ end
+ end
+ end
+
+ private
+
+ def update_parent_child_ci_files
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Update parent and child pipelines CI files.'
+ commit.update_files(
+ [
+ parent_ci_file,
+ child_ci_file
+ ]
+ )
+ end
+ end
+
+ def update_failed_parent_ci_file
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Fail parent pipeline.'
+ commit.update_files(
+ [
+ parent_failed_ci_file
+ ]
+ )
+ end
+ end
+
+ def update_failed_child_ci_file
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Fail child pipeline.'
+ commit.update_files(
+ [
+ child_failed_ci_file
+ ]
+ )
+ end
+ end
+
+ def add_parent_child_ci_files
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add parent and child pipelines CI files.'
+ commit.add_files(
+ [
+ parent_ci_file,
+ child_ci_file
+ ]
+ )
+ end
+ end
+
+ def parent_ci_file
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ trigger-child:
+ stage: test
+ trigger:
+ include: ".child-ci.yml"
+ strategy: #{strategy}
+
+ #{parent_test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: echo "parent test"
+ artifacts:
+ paths: ['.gitlab-ci.yml']
+ when: always
+ YAML
+ }
+ end
+
+ def parent_failed_ci_file
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ trigger-child:
+ stage: test
+ trigger:
+ include: ".child-ci.yml"
+ strategy: #{strategy}
+
+ #{parent_test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: echo "parent test" && exit 1
+ artifacts:
+ paths: ['.gitlab-ci.yml']
+ when: always
+ YAML
+ }
+ end
+
+ def child_ci_file
+ {
+ file_path: '.child-ci.yml',
+ content: <<~YAML
+ #{child_test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: echo "child test"
+ artifacts:
+ paths: ['.child-ci.yml']
+ when: always
+ YAML
+ }
+ end
+
+ def child_failed_ci_file
+ {
+ file_path: '.child-ci.yml',
+ content: <<~YAML
+ #{child_test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: echo "child test" && exit 1
+ artifacts:
+ paths: ['.child-ci.yml']
+ when: always
+ YAML
+ }
+ end
+ end
+ end
+end
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
new file mode 100644
index 00000000000..a954bd16386
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb
@@ -0,0 +1,170 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
+ describe "Unlocking job artifacts across pipelines" do
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'unlock-job-artifacts-project'
+ end
+ end
+
+ let!(:runner) do
+ Resource::ProjectRunner.fabricate! do |runner|
+ runner.project = project
+ runner.name = executor
+ runner.tags = [executor]
+ end
+ end
+
+ let(:test_job_name) { 'test-job' }
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ context 'when latest pipeline is successful' do
+ it 'unlocks job artifacts from previous successful pipeline',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/394807' do
+ add_ci_file
+ project.visit!
+
+ previous_successful_pipeline = Resource::Pipeline.fabricate! do |pipeline|
+ pipeline.project = project
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ update_ci_script('echo bye')
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_pipeline_job_page(pipeline: previous_successful_pipeline, job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+ end
+ end
+
+ context 'when latest pipeline failed' do
+ it 'unlocks job artifacts from failed pipelines, keeps job artifacts from latest successful pipeline',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/394808',
+ quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/266958',
+ type: :bug
+ } do
+ add_ci_file
+ project.visit!
+
+ successful_pipeline = Resource::Pipeline.fabricate! do |pipeline|
+ pipeline.project = project
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ update_ci_script('echo test && exit 1')
+
+ failed_pipeline_1 = Resource::Pipeline.fabricate! do |pipeline|
+ pipeline.project = project
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ update_ci_script('echo bye && exit 1')
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ Flow::Pipeline.visit_pipeline_job_page(pipeline: failed_pipeline_1, job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ Flow::Pipeline.visit_pipeline_job_page(pipeline: successful_pipeline, job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+ end
+ end
+
+ private
+
+ def add_ci_file
+ script = 'echo test'
+ ci_file = ci_file_with_job_artifact(script)
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = "Set script #{script}"
+ commit.add_files([ci_file])
+ end
+ end
+
+ def update_ci_script(script)
+ ci_file = ci_file_with_job_artifact(script)
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = "Set script #{script}"
+ commit.update_files([ci_file])
+ end
+ end
+
+ def add_failing_ci_file
+ ci_file = ci_file_with_job_artifact('echo test && exit 1')
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add failing CI file.'
+ commit.add_files([ci_file])
+ end
+ end
+
+ def ci_file_with_job_artifact(script)
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ #{test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: #{script}
+ artifacts:
+ paths: ['.gitlab-ci.yml']
+ when: always
+ YAML
+ }
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
index aec0da99a5c..8474e5c1b37 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Add or Remove CI variable via UI', :smoke, product_group: :pipeline_authoring do
+ describe 'Add or Remove CI variable via UI', :smoke, product_group: :pipeline_security do
let(:project) do
Resource::Project.fabricate_via_api_unless_fips! do |project|
project.name = 'project-with-ci-variables'
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 2ae28d54242..4c1319da0cb 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pipeline with customizable variable' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:pipeline_job_name) { 'customizable-variable' }
@@ -51,11 +51,6 @@ module QA
project.visit!
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button)
-
- # Sometimes the variables will not be prefilled because of reactive cache so we revisit the page again.
- # TODO: Investigate alternatives to deal with cache implementation
- # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/381233
- page.refresh
end
after do
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb
index a8ec0a1c835..e2d25e64687 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pipeline with protected variable' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:protected_value) { Faker::Alphanumeric.alphanumeric(number: 8) }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb
index 1878292015e..b79f8b5f1f4 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Pipeline with prefill variables' do
+ describe 'Pipeline with prefill variables', product_group: :pipeline_security do
let(:prefill_variable_description1) { Faker::Lorem.sentence }
let(:prefill_variable_value1) { Faker::Lorem.word }
let(:prefill_variable_value5) { Faker::Lorem.word }
@@ -54,11 +54,6 @@ module QA
# Navigate to Run Pipeline page
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button)
-
- # Sometimes the variables will not be prefilled because of reactive cache so we revisit the page again.
- # TODO: Investigate alternatives to deal with cache implementation
- # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/381233
- page.refresh
end
it 'shows only variables with description as prefill variables on the run pipeline page',
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb
index 81ccd36c514..15959721935 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify', :runner do
- describe 'Pipeline with raw variables in YAML', product_group: :pipeline_authoring do
+ describe 'Pipeline with raw variables in YAML', product_group: :pipeline_security do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:pipeline_job_name) { 'rspec' }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb
index a5ebd4004d2..12c29ac2363 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'UI defined variable' do
include_context 'variable inheritance test prep'
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb
index f53454b801c..1d354daaa5b 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'UI defined variable' do
include_context 'variable inheritance test prep'
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb
new file mode 100644
index 00000000000..dc8db7ec387
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb
@@ -0,0 +1,154 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring, feature_flag: {
+ name: 'ci_batch_project_includes_context',
+ scope: :global
+ } do
+ describe 'Include multiple files from multiple projects' do
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
+
+ let(:main_project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-with-pipeline'
+ end
+ end
+
+ let(:project1) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'external-project-1'
+ end
+ end
+
+ let(:project2) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'external-project-2'
+ end
+ end
+
+ let!(:runner) do
+ Resource::ProjectRunner.fabricate! do |runner|
+ runner.project = main_project
+ runner.name = executor
+ runner.tags = [executor]
+ end
+ end
+
+ def before_do
+ Flow::Login.sign_in
+
+ add_included_files_for(main_project)
+ add_included_files_for(project1)
+ add_included_files_for(project2)
+ add_main_ci_file(main_project)
+
+ main_project.visit!
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ end
+
+ after do
+ runner.remove_via_api!
+ end
+
+ context 'when FF is on', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396374' do
+ before do
+ Runtime::Feature.enable(:ci_batch_project_includes_context, project: main_project)
+ sleep 60
+
+ before_do
+ end
+
+ it 'runs the pipeline with composed config' do
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ aggregate_failures 'pipeline has all expected jobs' do
+ expect(pipeline).to have_job('test_for_main')
+ expect(pipeline).to have_job("test1_for_#{project1.full_path}")
+ expect(pipeline).to have_job("test1_for_#{project2.full_path}")
+ expect(pipeline).to have_job("test2_for_#{project1.full_path}")
+ expect(pipeline).to have_job("test2_for_#{main_project.full_path}")
+ end
+ end
+ end
+ end
+
+ context 'when FF is off', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396375' do
+ before do
+ Runtime::Feature.disable(:ci_batch_project_includes_context, project: main_project)
+ sleep 60
+
+ before_do
+ end
+
+ it 'runs the pipeline with composed config' do
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ aggregate_failures 'pipeline has all expected jobs' do
+ expect(pipeline).to have_job('test_for_main')
+ expect(pipeline).to have_job("test1_for_#{project1.full_path}")
+ expect(pipeline).to have_job("test1_for_#{project2.full_path}")
+ expect(pipeline).to have_job("test2_for_#{project1.full_path}")
+ expect(pipeline).to have_job("test2_for_#{main_project.full_path}")
+ end
+ end
+ end
+ end
+
+ private
+
+ def add_included_files_for(project)
+ files = [
+ {
+ file_path: 'file1.yml',
+ content: <<~YAML
+ test1_for_#{project.full_path}:
+ tags: ["#{executor}"]
+ script: echo hello1
+ YAML
+ },
+ {
+ file_path: 'file2.yml',
+ content: <<~YAML
+ test2_for_#{project.full_path}:
+ tags: ["#{executor}"]
+ script: echo hello2
+ YAML
+ }
+ ]
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add files'
+ commit.add_files(files)
+ end
+ end
+
+ def add_main_ci_file(project)
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add config file'
+ commit.add_files([main_ci_file])
+ end
+ end
+
+ def main_ci_file
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ include:
+ - project: #{project1.full_path}
+ file: file1.yml
+ - project: #{project2.full_path}
+ file: file1.yml
+ - project: #{project1.full_path}
+ file: file2.yml
+ - project: #{main_project.full_path}
+ file: file2.yml
+
+ test_for_main:
+ tags: ["#{executor}"]
+ script: echo hello
+ YAML
+ }
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb
index 588d22275df..5543e39e38c 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, :requires_admin, product_group: :pipeline_insights do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Artifacts' do
context 'when locked' do
let(:file_name) { 'artifact.txt' }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb
index 7d1339d2c2d..6295c596dda 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pass dotenv variables to downstream via bridge' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:upstream_var) { Faker::Alphanumeric.alphanumeric(number: 8) }
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 d4fee70fbf3..e7ab515c672 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
@@ -9,7 +9,7 @@ module QA
# pipeline created (Sidekiq read/write) ->
# runner picks up pipeline (API read/write) ->
# User views pipeline succeeds (Web read)
- RSpec.describe 'Verify', :runner, product_group: :pipeline_insights do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
context 'Endpoint Coverage' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
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
index b45ccfa5433..ee60483d4de 100644
--- 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_insights do
+ 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
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb
index f95bcc59db1..6252a287fd4 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb
@@ -36,6 +36,8 @@ module QA
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: package_project)
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: client_project)
when :ci_job_token
+ package_project_inbound_job_token_disabled
+ client_project_inbound_job_token_disabled
'${CI_JOB_TOKEN}'
when :project_deploy_token
use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: package_project)
@@ -43,10 +45,7 @@ module QA
end
end
- it "pushes and pulls a helm chart", testcase: params[:testcase], quarantine: {
- type: :stale,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391649'
- } do
+ it "pushes and pulls a helm chart", testcase: params[:testcase] do
Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
Resource::Repository::Commit.fabricate_via_api! do |commit|
helm_upload_yaml = ERB.new(read_fixture('package_managers/helm', 'helm_upload_package.yaml.erb')).result(binding)
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
index 3fb5c921187..879bb7022c8 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry, feature_flag: { name: 'maven_central_request_forwarding', scope: :global } do
describe 'Maven group level endpoint' do
include Runtime::Fixtures
include Support::Helpers::MaskToken
@@ -41,11 +41,7 @@ module QA
'using a ci job token' => {
authentication_token_type: :ci_job_token,
maven_header_name: 'Job-Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347579',
- quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/373189',
- type: :stale
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347579'
}
}
end
@@ -57,6 +53,8 @@ module QA
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: package_project)
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: client_project)
when :ci_job_token
+ package_project_inbound_job_token_disabled
+ client_project_inbound_job_token_disabled
'${CI_JOB_TOKEN}'
when :project_deploy_token
use_ci_variable(name: 'GROUP_DEPLOY_TOKEN', value: group_deploy_token.token, project: package_project)
@@ -64,7 +62,7 @@ module QA
end
end
- it 'pushes and pulls a maven package', testcase: params[:testcase], quarantine: params[:quarantine] do
+ it 'pushes and pulls a maven package', testcase: params[:testcase] do
Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
Resource::Repository::Commit.fabricate_via_api! do |commit|
gitlab_ci_yaml = ERB.new(read_fixture('package_managers/maven/group/producer', 'gitlab_ci.yaml.erb')).result(binding)
@@ -223,5 +221,98 @@ module QA
end
end
end
+
+ describe 'Maven request forwarding' do
+ include Runtime::Fixtures
+
+ let(:group_id) { 'com.gitlab.qa' }
+ let(:artifact_id) { "maven-#{SecureRandom.hex(8)}" }
+ let(:package_name) { "#{group_id}/#{artifact_id}".tr('.', '/') }
+ let(:package_version) { '1.3.7' }
+ let(:personal_access_token) { Runtime::Env.personal_access_token }
+ let(:group) { Resource::Group.fabricate_via_api! }
+
+ let(:imported_project) do
+ Resource::ProjectImportedFromURL.fabricate_via_browser_ui! do |project|
+ project.name = "maven_imported_project"
+ project.group = group
+ project.gitlab_repository_path = 'https://gitlab.com/gitlab-org/quality/imported-projects/maven.git'
+ end
+ end
+
+ let(:gitlab_address_with_port) do
+ uri = URI.parse(Runtime::Scenario.gitlab_address)
+ "#{uri.scheme}://#{uri.host}:#{uri.port}"
+ end
+
+ let(:package) do
+ Resource::Package.init do |package|
+ package.name = package_name
+ package.project = imported_project
+ end
+ end
+
+ let(:runner) do
+ Resource::ProjectRunner.fabricate! do |runner|
+ runner.name = "qa-runner-#{Time.now.to_i}"
+ runner.tags = ["runner-for-#{imported_project.group.name}"]
+ runner.executor = :docker
+ runner.token = imported_project.group.reload!.runners_token
+ end
+ end
+
+ before do
+ Runtime::Feature.enable(:maven_central_request_forwarding)
+ Flow::Login.sign_in_unless_signed_in
+
+ imported_project
+ runner
+ end
+
+ after do
+ Runtime::Feature.disable(:maven_central_request_forwarding)
+
+ runner.remove_via_api!
+ package.remove_via_api!
+ imported_project.remove_via_api!
+ end
+
+ it(
+ 'uses GitLab as a mirror of the central proxy',
+ :skip_live_env,
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/375988',
+ quarantine: {
+ type: :investigating,
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378221'
+ }
+ ) do
+ Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ settings_xml = ERB.new(read_fixture('package_managers/maven/group/consumer/request_forwarding', 'settings.xml.erb')).result(binding)
+ gitlab_ci_yaml = ERB.new(read_fixture('package_managers/maven/group/consumer/request_forwarding', 'gitlab_ci.yaml.erb')).result(binding)
+
+ commit.project = imported_project
+ commit.commit_message = 'Add files'
+ commit.add_files(
+ [
+ { file_path: '.gitlab-ci.yml', content: gitlab_ci_yaml },
+ { file_path: 'settings.xml', content: settings_xml }
+ ])
+ end
+ end
+
+ imported_project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('install')
+ end
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 800)
+ end
+ end
+ end
end
end
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 d86ce09c4e1..9a418f11b1b 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
@@ -25,16 +25,15 @@ module QA
when :personal_access_token
"\"#{personal_access_token}\""
when :ci_job_token
+ package_project_inbound_job_token_disabled
+ client_project_inbound_job_token_disabled
'System.getenv("CI_JOB_TOKEN")'
when :project_deploy_token
"\"#{project_deploy_token.token}\""
end
end
- it 'pushes and pulls a maven package via gradle', testcase: params[:testcase], quarantine: {
- type: :stale,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391650'
- } do
+ it 'pushes and pulls a maven package via gradle', testcase: params[:testcase] do
Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
Resource::Repository::Commit.fabricate_via_api! do |commit|
gradle_upload_yaml = ERB.new(read_fixture('package_managers/maven/gradle', 'gradle_upload_package.yaml.erb')).result(binding)
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 c2cbec3fbb7..48b9fdec2e9 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
@@ -50,6 +50,20 @@ module QA
end
end
+ let(:package_project_inbound_job_token_disabled) do
+ Resource::CICDSettings.fabricate_via_api! do |settings|
+ settings.project_path = project.full_path
+ settings.inbound_job_token_scope_enabled = false
+ end
+ end
+
+ let(:client_project_inbound_job_token_disabled) do
+ Resource::CICDSettings.fabricate_via_api! do |settings|
+ settings.project_path = another_project.full_path
+ settings.inbound_job_token_scope_enabled = false
+ end
+ end
+
let!(:runner) do
Resource::GroupRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
@@ -79,6 +93,8 @@ module QA
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token.token, project: project)
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token.token, project: another_project)
when :ci_job_token
+ package_project_inbound_job_token_disabled
+ client_project_inbound_job_token_disabled
'${CI_JOB_TOKEN}'
when :group_deploy_token
use_ci_variable(name: 'GROUP_DEPLOY_TOKEN', value: group_deploy_token.token, project: project)
@@ -97,10 +113,7 @@ module QA
end
end
- it 'publishes a nuget package at the project endpoint and installs it from the group endpoint', testcase: params[:testcase], quarantine: {
- type: :stale,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391648'
- } do
+ it 'publishes a nuget package at the project endpoint and installs it from the group endpoint', testcase: params[:testcase] do
Flow::Login.sign_in
Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
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 0f6bee951a7..51006dd1e38 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
@@ -19,7 +19,6 @@ module QA
resource.project = project
resource.name = runner_name
resource.tags = [runner_name]
- resource.image = 'gitlab/gitlab-runner:alpine-v15.8.3'
end
end
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb
new file mode 100644
index 00000000000..433d286686b
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Monitor', product_group: :respond do
+ describe 'Recovery alert' do
+ shared_examples 'triggers recovery alert' do
+ it 'only resolves the correct alert', :aggregate_failures do
+ Page::Project::Menu.perform(&:go_to_monitor_alerts)
+ Page::Project::Monitor::Alerts::Index.perform do |index|
+ # Open tab is displayed by default
+ expect(index).to have_alert_with_title(unresolve_title)
+ expect(index).to have_no_alert_with_title(resolve_title)
+
+ index.go_to_tab('Resolved')
+ expect(index).to have_alert_with_title(resolve_title)
+ expect(index).to have_no_alert_with_title(unresolve_title)
+ end
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ project.visit!
+ Flow::AlertSettings.go_to_monitor_settings
+ end
+
+ context(
+ 'when using HTTP endpoint integration',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393589'
+ ) do
+ include_context 'sends and resolves test alerts'
+
+ it_behaves_like 'triggers recovery alert'
+ end
+
+ context(
+ 'when using Prometheus integration',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393590'
+ ) do
+ include_context 'sends and resolves test alerts'
+
+ let(:http) { false }
+
+ it_behaves_like 'triggers recovery alert'
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb b/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb
new file mode 100644
index 00000000000..fe3cd5a432b
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Monitor', product_group: :respond do
+ describe 'Recovery alert' do
+ shared_examples 'triggers recovery alert' do
+ it 'only closes the correct incident', :aggregate_failures do
+ Page::Project::Menu.perform(&:go_to_monitor_incidents)
+ Page::Project::Monitor::Incidents::Index.perform do |index|
+ # Open tab is displayed by default
+ expect(index).to have_incident(title: unresolve_title)
+ expect(index).to have_no_incident(title: resolve_title)
+
+ index.go_to_tab('Closed')
+ expect(index).to have_incident(title: resolve_title)
+ expect(index).to have_no_incident(title: unresolve_title)
+ end
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ project.visit!
+ Flow::AlertSettings.go_to_monitor_settings
+ Flow::AlertSettings.enable_create_incident
+ end
+
+ context(
+ 'when using HTTP endpoint integration',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393842'
+ ) do
+ include_context 'sends and resolves test alerts'
+
+ it_behaves_like 'triggers recovery alert'
+ end
+
+ context(
+ 'when using Prometheus integration',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393843'
+ ) do
+ include_context 'sends and resolves test alerts'
+
+ let(:http) { false }
+
+ it_behaves_like 'triggers recovery alert'
+ end
+ end
+ end
+end
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 481a09f601b..d72144cecec 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
@@ -26,6 +26,7 @@ module QA
let(:imported_project) do
Resource::ProjectImportedFromGithub.fabricate_via_api! do |project|
project.name = 'imported-project'
+ project.github_repo_id = '466994992'
project.group = group
project.github_personal_access_token = Runtime::Env.github_access_token
project.github_repository_path = github_repo
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 728907c708f..900245deca3 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
@@ -25,7 +25,6 @@ module QA
end
before do
- Runtime::Feature.enable(:bulk_import_projects) unless Runtime::Feature.enabled?(:bulk_import_projects)
source_project # fabricate source group and project
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 a611a801b11..5ab7bb331c0 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
@@ -20,6 +20,20 @@ module QA
end
end
+ let(:package_project_inbound_job_token_disabled) do
+ Resource::CICDSettings.fabricate_via_api! do |settings|
+ settings.project_path = package_project.full_path
+ settings.inbound_job_token_scope_enabled = false
+ end
+ end
+
+ let(:client_project_inbound_job_token_disabled) do
+ Resource::CICDSettings.fabricate_via_api! do |settings|
+ settings.project_path = client_project.full_path
+ settings.inbound_job_token_scope_enabled = false
+ end
+ end
+
let(:package) do
Resource::Package.init do |package|
package.name = package_name
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
new file mode 100644
index 00000000000..a72140f41e0
--- /dev/null
+++ b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+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(:resolve_title) { Faker::Lorem.sentence }
+ let(:unresolve_title) { Faker::Lorem.sentence }
+ let(:http) { true }
+
+ let(:payload_to_be_resolved) do
+ payload(resolve_title, http)
+ end
+
+ let(:unresolved_payload) do
+ payload(unresolve_title, http)
+ end
+
+ before do
+ http ? Flow::AlertSettings.setup_http_endpoint_integration : Flow::AlertSettings.setup_prometheus_integration
+
+ [payload_to_be_resolved, unresolved_payload].each do |payload|
+ Flow::AlertSettings.send_test_alert(payload: payload)
+ end
+
+ mark_as_resolved(payload_to_be_resolved, http)
+ Flow::AlertSettings.send_test_alert(payload: payload_to_be_resolved)
+ end
+
+ private
+
+ def mark_as_resolved(payload, http)
+ if http
+ payload[:end_time] = Time.now
+ else
+ payload[:alerts][0][:status] = 'resolved'
+ payload[:alerts][0][:endsAt] = Time.now
+ end
+ end
+
+ def payload(title, http)
+ if http
+ { title: title, description: title }
+ else
+ {
+ version: '4',
+ groupKey: nil,
+ status: 'firing',
+ receiver: '',
+ groupLabels: {},
+ commonLabels: {},
+ commonAnnotations: {},
+ externalURL: '',
+ alerts: [
+ {
+ startsAt: Time.now,
+ generatorURL: Faker::Internet.url,
+ endsAt: nil,
+ status: nil,
+ labels: { gitlab_environment_name: Faker::Lorem.word },
+ annotations: { title: title }
+ }
+ ]
+ }
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/helpers/context_selector.rb b/qa/qa/specs/helpers/context_selector.rb
index dfb00cb807b..59ab7c9722e 100644
--- a/qa/qa/specs/helpers/context_selector.rb
+++ b/qa/qa/specs/helpers/context_selector.rb
@@ -22,7 +22,7 @@ module QA
opts = {}
opts[:domain] = '.+'
- opts[:tld] = '.com'
+ opts[:tld] = opts_tld
uri = URI(Runtime::Scenario.gitlab_address)
@@ -79,6 +79,10 @@ module QA
def production_domain
GitlabEdition.jh? ? 'jihulab' : 'gitlab'
end
+
+ def opts_tld
+ GitlabEdition.jh? ? '(.com|.hk)' : '.com'
+ end
end
end
end
diff --git a/qa/qa/support/json_formatter.rb b/qa/qa/support/json_formatter.rb
index 252ccfe73d3..178b76e1974 100644
--- a/qa/qa/support/json_formatter.rb
+++ b/qa/qa/support/json_formatter.rb
@@ -26,6 +26,10 @@ module QA
class: exception.class.name,
message: exception.message,
message_lines: strip_ansi_codes(notification.message_lines),
+ correlation_id: exception.message[match_data_after(Loglinking::CORRELATION_ID_TITLE)],
+ sentry_url: exception.message[match_data_after(Loglinking::SENTRY_URL_TITLE)],
+ kibana_discover_url: exception.message[match_data_after(Loglinking::KIBANA_DISCOVER_URL_TITLE)],
+ kibana_dashboard_url: exception.message[match_data_after(Loglinking::KIBANA_DASHBOARD_URL_TITLE)],
backtrace: notification.formatted_backtrace
}
end
@@ -70,6 +74,10 @@ module QA
modified = Array(strings).map { |string| string.dup.gsub(/\x1b\[{1,2}[0-9;:?]*m/m, '') }
modified.size == 1 ? modified[0] : modified
end
+
+ def match_data_after(title)
+ /(?<=#{title} ).*/
+ end
end
end
end
diff --git a/qa/qa/support/loglinking.rb b/qa/qa/support/loglinking.rb
index e9202af3965..ac6e596ef6f 100644
--- a/qa/qa/support/loglinking.rb
+++ b/qa/qa/support/loglinking.rb
@@ -4,16 +4,22 @@ module QA
module Support
module Loglinking
# Static address variables declared for mapping environment to logging URLs
- STAGING_ADDRESS = 'https://staging.gitlab.com'
- STAGING_REF_ADDRESS = 'https://staging-ref.gitlab.com'
- PRODUCTION_ADDRESS = 'https://gitlab.com'
- PRE_PROD_ADDRESS = 'https://pre.gitlab.com'
+ STAGING_ADDRESS = 'https://staging.gitlab.com'
+ STAGING_REF_ADDRESS = 'https://staging-ref.gitlab.com'
+ PRODUCTION_ADDRESS = 'https://gitlab.com'
+ PRE_PROD_ADDRESS = 'https://pre.gitlab.com'
+
+ # Text titles used for labeling various IDs and URLs
+ CORRELATION_ID_TITLE = 'Correlation Id:'
+ SENTRY_URL_TITLE = 'Sentry Url:'
+ KIBANA_DISCOVER_URL_TITLE = 'Kibana - Discover Url:'
+ KIBANA_DASHBOARD_URL_TITLE = 'Kibana - Dashboard Url:'
class << self
def failure_metadata(correlation_id)
return if correlation_id.blank?
- errors = ["Correlation Id: #{correlation_id}"]
+ errors = ["#{CORRELATION_ID_TITLE} #{correlation_id}"]
env = logging_environment
@@ -24,9 +30,9 @@ module QA
kibana_discover_url = kibana.discover_url
kibana_dashboard_url = kibana.dashboard_url
- errors << "Sentry Url: #{sentry_url}" if sentry_url
- errors << "Kibana - Discover Url: #{kibana_discover_url}" if kibana_discover_url
- errors << "Kibana - Dashboard Url: #{kibana_dashboard_url}" if kibana_dashboard_url
+ errors << "#{SENTRY_URL_TITLE} #{sentry_url}" if sentry_url
+ errors << "#{KIBANA_DISCOVER_URL_TITLE} #{kibana_discover_url}" if kibana_discover_url
+ errors << "#{KIBANA_DASHBOARD_URL_TITLE} #{kibana_dashboard_url}" if kibana_dashboard_url
errors.join("\n")
end
diff --git a/qa/qa/support/matchers/have_matcher.rb b/qa/qa/support/matchers/have_matcher.rb
index 734a8890536..d843949e6b2 100644
--- a/qa/qa/support/matchers/have_matcher.rb
+++ b/qa/qa/support/matchers/have_matcher.rb
@@ -25,6 +25,9 @@ module QA
tag
label
variable
+ system_note
+ alert_with_title
+ incident
].each do |predicate|
RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs|
match do |page_object|
diff --git a/qa/qa/tools/test_resource_data_processor.rb b/qa/qa/tools/test_resource_data_processor.rb
index a86c94b4914..3312285ecc4 100644
--- a/qa/qa/tools/test_resource_data_processor.rb
+++ b/qa/qa/tools/test_resource_data_processor.rb
@@ -38,7 +38,7 @@ module QA
api_path: api_path,
fabrication_method: fabrication_method,
fabrication_time: fabrication_time,
- http_method: resource.api_fabrication_http_method,
+ http_method: resource.api_fabrication_http_method || :post,
timestamp: Time.now.to_s
}
end
diff --git a/qa/qa/vendor/smocker/event_payload.rb b/qa/qa/vendor/smocker/event_payload.rb
deleted file mode 100644
index 70998e055ea..00000000000
--- a/qa/qa/vendor/smocker/event_payload.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Vendor
- module Smocker
- class EventPayload
- def initialize(hook_data)
- @hook_data = hook_data
- end
-
- def raw
- @hook_data
- end
-
- def event
- raw[:object_kind]&.to_sym
- end
-
- def event_name
- raw[:event_name]&.to_sym
- end
-
- def project_name
- raw.dig(:project, :name)
- end
-
- def mr?
- event == :merge_request
- end
-
- def issue?
- event == :issue
- end
-
- def note?
- event == :note
- end
-
- def push?
- event == :push
- end
-
- def tag?
- event == :tag_push
- end
-
- def wiki?
- event == :wiki_page
- end
-
- def subgroup_create?
- event_name == :subgroup_create
- end
-
- def subgroup_destroy?
- event_name == :subgroup_destroy
- end
- end
- end
- end
-end
diff --git a/qa/qa/vendor/smocker/history_response.rb b/qa/qa/vendor/smocker/history_response.rb
index 53d5759ef8b..426bbe024ae 100644
--- a/qa/qa/vendor/smocker/history_response.rb
+++ b/qa/qa/vendor/smocker/history_response.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require_relative './event_payload'
require 'time'
module QA
@@ -23,12 +22,6 @@ module QA
payload[:request]
end
- # @return [EventPayload] the request body as a webhook event
- def as_hook_event
- body = request&.dig(:body)
- EventPayload.new body if body
- end
-
# @return [Time] Time request was recieved
def received
date = request&.dig(:date)
diff --git a/qa/qa/vendor/smocker/smocker_api.rb b/qa/qa/vendor/smocker/smocker_api.rb
index 359d1497825..111de84ffce 100644
--- a/qa/qa/vendor/smocker/smocker_api.rb
+++ b/qa/qa/vendor/smocker/smocker_api.rb
@@ -113,6 +113,14 @@ module QA
end
end
+ # Returns a stringfied version of the Smocker history
+ #
+ # @param session_name [String] the session name for the mock
+ # @return [String] stringified event payloads
+ def stringified_history(session_name = nil)
+ history(session_name).map(&:payload).join("\n")
+ end
+
private
attr_reader :host, :public_port, :admin_port, :scheme
diff --git a/qa/spec/fixtures/ff/async_commit_diff_files.yml b/qa/spec/fixtures/ff/async_commit_diff_files.yml
new file mode 100644
index 00000000000..0cadf592cc1
--- /dev/null
+++ b/qa/spec/fixtures/ff/async_commit_diff_files.yml
@@ -0,0 +1,8 @@
+---
+name: async_commit_diff_files
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38450
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369439
+milestone: '13.3'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/qa/spec/fixtures/ff/bulk_import_projects.yml b/qa/spec/fixtures/ff/bulk_import_projects.yml
deleted file mode 100644
index 853389577cf..00000000000
--- a/qa/spec/fixtures/ff/bulk_import_projects.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: bulk_import_projects
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68873
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339941
-milestone: '14.3'
-type: development
-group: group::import
-default_enabled: false
diff --git a/qa/spec/resource/api_fabricator_spec.rb b/qa/spec/resource/api_fabricator_spec.rb
index 337c6772a06..96823ea7ada 100644
--- a/qa/spec/resource/api_fabricator_spec.rb
+++ b/qa/spec/resource/api_fabricator_spec.rb
@@ -116,7 +116,7 @@ RSpec.describe QA::Resource::ApiFabricator do
expect { subject.fabricate_via_api! }.to raise_error do |error|
expect(error.class).to eql(described_class::ResourceFabricationFailedError)
- expect(error.to_s).to eql(<<~ERROR.chomp)
+ expect(error.to_s).to eql(<<~ERROR.strip)
Fabrication of FooBarResource using the API failed (400) with `#{raw_post}`.\n
ERROR
end
diff --git a/qa/spec/resource/project_web_hook_spec.rb b/qa/spec/resource/project_web_hook_spec.rb
new file mode 100644
index 00000000000..bca95124c06
--- /dev/null
+++ b/qa/spec/resource/project_web_hook_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe Resource::ProjectWebHook do
+ let(:smocker_api) { instance_double(Vendor::Smocker::SmockerApi) }
+ let(:smocker_docker) { class_double(Service::DockerRun::Smocker) }
+ let(:history_entries) do
+ [
+ {
+ request: {
+ body: {
+ object_kind: 'tag_push'
+ }
+ }
+ },
+ {
+ request: {
+ body: {
+ object_kind: 'merge_request'
+ }
+ }
+ }
+ ]
+ end
+
+ let(:history_response) { Struct.new(:body).new(history_entries.to_json) }
+
+ it 'configures the project hook events' do
+ setup_mocks
+
+ described_class.setup(pipeline: true, wiki_page: true) do |webhook, _|
+ expect(webhook.pipeline_events).to be(true)
+ expect(webhook.wiki_page_events).to be(true)
+ expect(webhook.push_events).to be(false)
+ end
+ end
+
+ it 'adds an #event method to the smocker object that returns webhook events' do
+ setup_mocks
+
+ # rubocop:disable RSpec/AnyInstanceOf
+ expect_any_instance_of(Vendor::Smocker::SmockerApi).to receive(:get_session_id)
+ .and_return('123')
+ expect_any_instance_of(Vendor::Smocker::SmockerApi).to receive(:get)
+ .with(/history/)
+ .and_return(history_response)
+ # rubocop:enable RSpec/AnyInstanceOf
+
+ described_class.setup do |_, smocker|
+ expect(smocker.events('123')).to include(
+ a_hash_including(object_kind: 'merge_request'),
+ a_hash_including(object_kind: 'tag_push')
+ )
+ end
+ end
+
+ def setup_mocks
+ # rubocop:disable RSpec/AnyInstanceOf
+ expect_any_instance_of(Vendor::Smocker::SmockerApi).to receive(:reset)
+ expect_any_instance_of(Vendor::Smocker::SmockerApi).to receive(:register)
+ # rubocop:enable RSpec/AnyInstanceOf
+
+ expect(Service::DockerRun::Smocker).to receive(:init)
+ .and_yield(Vendor::Smocker::SmockerApi.new(host: 'smocker.net'))
+ allow(subject).to receive(:project)
+ allow(described_class).to receive(:fabricate_via_api!)
+ .and_yield(subject)
+ end
+ end
+end
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index e9c2000681b..66720937007 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -189,14 +189,14 @@ RSpec.describe QA::Runtime::Env do
end
describe '.github_access_token' do
- it 'returns "" if GITHUB_ACCESS_TOKEN is not defined' do
- stub_env('GITHUB_ACCESS_TOKEN', nil)
+ it 'returns "" if QA_GITHUB_ACCESS_TOKEN is not defined' do
+ stub_env('QA_GITHUB_ACCESS_TOKEN', nil)
expect(described_class.github_access_token).to eq('')
end
- it 'returns stripped string if GITHUB_ACCESS_TOKEN is defined' do
- stub_env('GITHUB_ACCESS_TOKEN', ' abc123 ')
+ it 'returns stripped string if QA_GITHUB_ACCESS_TOKEN is defined' do
+ stub_env('QA_GITHUB_ACCESS_TOKEN', ' abc123 ')
expect(described_class.github_access_token).to eq('abc123')
end
end
@@ -229,14 +229,14 @@ RSpec.describe QA::Runtime::Env do
end
describe '.require_github_access_token!' do
- it 'raises ArgumentError if GITHUB_ACCESS_TOKEN is not defined' do
- stub_env('GITHUB_ACCESS_TOKEN', nil)
+ it 'raises ArgumentError if QA_GITHUB_ACCESS_TOKEN is not defined' do
+ stub_env('QA_GITHUB_ACCESS_TOKEN', nil)
expect { described_class.require_github_access_token! }.to raise_error(ArgumentError)
end
- it 'does not raise if GITHUB_ACCESS_TOKEN is defined' do
- stub_env('GITHUB_ACCESS_TOKEN', ' abc123 ')
+ it 'does not raise if QA_GITHUB_ACCESS_TOKEN is defined' do
+ stub_env('QA_GITHUB_ACCESS_TOKEN', ' abc123 ')
expect { described_class.require_github_access_token! }.not_to raise_error
end
diff --git a/qa/spec/specs/helpers/context_selector_spec.rb b/qa/spec/specs/helpers/context_selector_spec.rb
index 7541bb45d82..9e46933542e 100644
--- a/qa/spec/specs/helpers/context_selector_spec.rb
+++ b/qa/spec/specs/helpers/context_selector_spec.rb
@@ -43,6 +43,7 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
it 'matches multiple subdomains' do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
aggregate_failures do
@@ -51,13 +52,35 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
+ it 'matches multiple subdomains on jh side' do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, "https://staging.jihulab.com")
+
+ aggregate_failures do
+ expect(described_class.context_matches?(subdomain: [:release, :staging])).to be_truthy
+ expect(described_class.context_matches?(:production, subdomain: [:release, :staging])).to be_truthy
+ end
+ end
+
it 'matches :production' do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, "https://gitlab.com/")
expect(described_class.context_matches?(:production)).to be_truthy
end
+ it 'matches :production on jh side' do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+
+ QA::Runtime::Scenario.define(:gitlab_address, "https://jihulab.com/")
+ expect(described_class.context_matches?(:production)).to be_truthy
+
+ QA::Runtime::Scenario.define(:gitlab_address, "https://jihulab.hk/")
+ expect(described_class.context_matches?(:production)).to be_truthy
+ end
+
it 'matches domain' do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com')
aggregate_failures do
@@ -67,6 +90,26 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
+ it 'matches domain on jh side' do
+ # To simulate run tests in JH
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com')
+
+ aggregate_failures do
+ expect(described_class.context_matches?(:production)).to be_truthy
+ expect(described_class.context_matches?(domain: 'gitlab')).to be_falsey
+ expect(described_class.context_matches?(domain: 'jihulab')).to be_truthy
+ end
+
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.hk')
+
+ aggregate_failures do
+ expect(described_class.context_matches?(:production)).to be_truthy
+ expect(described_class.context_matches?(domain: 'gitlab')).to be_falsey
+ expect(described_class.context_matches?(domain: 'jihulab')).to be_truthy
+ end
+ end
+
it 'matches tld' do
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.cn')
@@ -119,6 +162,7 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
context 'with different environment set' do
before do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.com')
end
@@ -140,6 +184,31 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
end
+
+ context 'with different environment set on jh side' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com')
+ end
+
+ it 'does not run against production' do
+ group = describe_successfully 'Runs in staging', :something, only: { subdomain: :staging } do
+ it('runs in staging') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ end
+
+ context 'when excluding contexts' do
+ it 'runs against production' do
+ group = describe_successfully 'Runs in staging', :something, except: { subdomain: :staging } do
+ it('runs in staging') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ end
+ end
+ end
end
it 'runs only in staging' do
@@ -226,6 +295,7 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
context 'production' do
before do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.com/')
end
@@ -260,6 +330,80 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
+ context 'jh mainland production ' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com/')
+ end
+
+ it 'runs on production' do
+ group = describe_successfully do
+ it('runs on prod', only: :production) {}
+ it('does not run in prod', only: { subdomain: :staging }) {}
+ it('runs in prod and staging', only: { subdomain: /(staging.)?/, domain: 'jihulab' }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ end
+ end
+
+ context 'when excluding contexts' do
+ it 'skips production' do
+ group = describe_successfully do
+ it('skips prod', except: :production) {}
+ it('runs on prod', except: { subdomain: :staging }) {}
+ it('skips prod and staging', except: { subdomain: /(staging.)?/, domain: 'jihulab' }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ expect(group.examples[2].execution_result.status).to eq(:pending)
+ end
+ end
+ end
+ end
+
+ context 'jh hk production ' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.hk/')
+ end
+
+ it 'runs on production' do
+ group = describe_successfully do
+ it('runs on prod', only: :production) {}
+ it('does not run in prod', only: { subdomain: :staging }) {}
+ it('runs in prod and staging', only: { subdomain: /(staging.)?/, domain: 'jihulab' }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ end
+ end
+
+ context 'when excluding contexts' do
+ it 'skips production' do
+ group = describe_successfully do
+ it('skips prod', except: :production) {}
+ it('runs on prod', except: { subdomain: :staging }) {}
+ it('skips prod and staging', except: { subdomain: /(staging.)?/, domain: 'jihulab' }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ expect(group.examples[2].execution_result.status).to eq(:pending)
+ end
+ end
+ end
+ end
+
it 'outputs a message for invalid environments' do
group = describe_successfully do
it('will skip', only: :production) {}
diff --git a/qa/spec/specs/helpers/feature_flag_spec.rb b/qa/spec/specs/helpers/feature_flag_spec.rb
index 491fc22f026..180890b2701 100644
--- a/qa/spec/specs/helpers/feature_flag_spec.rb
+++ b/qa/spec/specs/helpers/feature_flag_spec.rb
@@ -122,6 +122,10 @@ RSpec.describe QA::Specs::Helpers::FeatureFlag do
end
context 'when run on production' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
+ end
+
before(:context) do
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.com')
end
@@ -147,6 +151,66 @@ RSpec.describe QA::Specs::Helpers::FeatureFlag do
it_behaves_like 'skips with given feature flag metadata', { name: 'global_ff', scope: :global }
end
+ context 'when run on jh production mainland' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ end
+
+ before(:context) do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com')
+ end
+
+ context 'when no scope is defined' do
+ it_behaves_like 'skips with given feature flag metadata', { name: 'no_scope_ff' }
+
+ context 'for only one test in the example group' do
+ it 'only skips specified test and runs all others' do
+ group = describe_successfully 'Feature flag set for one test' do
+ it('is skipped', feature_flag: { name: 'single_test_ff' }) {}
+ it('passes') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ end
+ end
+ end
+
+ it_behaves_like 'skips with given feature flag metadata', { name: 'actor_ff', scope: :project }
+
+ it_behaves_like 'skips with given feature flag metadata', { name: 'global_ff', scope: :global }
+ end
+
+ context 'when run on jh production hk' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ end
+
+ before(:context) do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.hk')
+ end
+
+ context 'when no scope is defined' do
+ it_behaves_like 'skips with given feature flag metadata', { name: 'no_scope_ff' }
+
+ context 'for only one test in the example group' do
+ it 'only skips specified test and runs all others' do
+ group = describe_successfully 'Feature flag set for one test' do
+ it('is skipped', feature_flag: { name: 'single_test_ff' }) {}
+ it('passes') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ end
+ end
+ end
+
+ it_behaves_like 'skips with given feature flag metadata', { name: 'actor_ff', scope: :project }
+
+ it_behaves_like 'skips with given feature flag metadata', { name: 'global_ff', scope: :global }
+ end
+
context 'when run on pre' do
before(:context) do
QA::Runtime::Scenario.define(:gitlab_address, 'https://pre.gitlab.com')
diff --git a/qa/spec/tools/ci/ff_changes_spec.rb b/qa/spec/tools/ci/ff_changes_spec.rb
index 71ca26867e0..d0bf6de148d 100644
--- a/qa/spec/tools/ci/ff_changes_spec.rb
+++ b/qa/spec/tools/ci/ff_changes_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe QA::Tools::Ci::FfChanges do
let(:mr_diff) do
[
{
- path: "config/feature_flags/development/bulk_import_projects.yml",
+ path: "config/feature_flags/development/async_commit_diff_files.yml",
deleted_file: deleted_file
}
]
@@ -21,12 +21,12 @@ RSpec.describe QA::Tools::Ci::FfChanges do
before do
allow(File).to receive(:read)
.with(File.expand_path("../#{mr_diff.first[:path]}", QA::Runtime::Path.qa_root))
- .and_return(File.read("spec/fixtures/ff/bulk_import_projects.yml"))
+ .and_return(File.read("spec/fixtures/ff/async_commit_diff_files.yml"))
end
context "with changed feature flag" do
it "returns inverse ff state option" do
- expect(ff_changes.fetch).to eq("bulk_import_projects=enabled")
+ expect(ff_changes.fetch).to eq("async_commit_diff_files=enabled")
end
end
@@ -34,7 +34,7 @@ RSpec.describe QA::Tools::Ci::FfChanges do
let(:deleted_file) { true }
it "returns deleted ff state option" do
- expect(ff_changes.fetch).to eq("bulk_import_projects=deleted")
+ expect(ff_changes.fetch).to eq("async_commit_diff_files=deleted")
end
end
end
diff --git a/qa/spec/vendor/smocker_api_spec.rb b/qa/spec/vendor/smocker_api_spec.rb
new file mode 100644
index 00000000000..b54197b8b1f
--- /dev/null
+++ b/qa/spec/vendor/smocker_api_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe Vendor::Smocker::SmockerApi do
+ let(:host) { 'smocker.bar' }
+
+ subject { described_class.new(host: host) }
+
+ it 'retries until the service is ready' do
+ expect(subject).to receive(:get)
+ .and_raise(StandardError)
+ .and_raise(StandardError)
+ .and_return(200)
+
+ expect { subject.wait_for_ready }.not_to raise_error
+ end
+ end
+end
diff --git a/rubocop/cop/background_migration/missing_dictionary_file.rb b/rubocop/cop/background_migration/missing_dictionary_file.rb
new file mode 100644
index 00000000000..9158b268bf9
--- /dev/null
+++ b/rubocop/cop/background_migration/missing_dictionary_file.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module BackgroundMigration
+ # Checks the batched background migration has the corresponding dictionary file
+ class MissingDictionaryFile < RuboCop::Cop::Base
+ include MigrationHelpers
+
+ MSG = "Missing %{file_name}. " \
+ "Use the generator 'batched_background_migration' to create dictionary files automatically. " \
+ "For more details refer: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#generator"
+
+ DICTIONARY_DIR = "db/docs/batched_background_migrations"
+
+ def_node_matcher :batched_background_migration_name_node, <<~PATTERN
+ `(send nil? :queue_batched_background_migration $_ ...)
+ PATTERN
+
+ def_node_matcher :migration_constant_value, <<~PATTERN
+ `(casgn nil? %const_name ({sym|str} $_))
+ PATTERN
+
+ def on_class(node)
+ return unless time_enforced?(node) && in_post_deployment_migration?(node)
+
+ migration_name_node = batched_background_migration_name_node(node)
+ return unless migration_name_node
+
+ migration_name = if migration_name_node.const_name.present?
+ migration_constant_value(node, const_name: migration_name_node.const_name.to_sym)
+ else
+ migration_name_node.value
+ end
+
+ return if dictionary_file?(migration_name)
+
+ add_offense(node, message: format(MSG, file_name: dictionary_file_path(migration_name)))
+ end
+
+ private
+
+ def dictionary_file?(migration_class_name)
+ File.exist?(dictionary_file_path(migration_class_name))
+ end
+
+ def dictionary_file_path(migration_class_name)
+ File.join(rails_root, DICTIONARY_DIR, "#{migration_class_name.underscore}.yml")
+ end
+
+ def rails_root
+ @rails_root ||= File.expand_path('../../..', __dir__)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/gitlab/feature_available_usage.rb b/rubocop/cop/gitlab/feature_available_usage.rb
index fcf4992a19d..df4409c27e0 100644
--- a/rubocop/cop/gitlab/feature_available_usage.rb
+++ b/rubocop/cop/gitlab/feature_available_usage.rb
@@ -39,7 +39,7 @@ module RuboCop
return if feature_name(node).nil?
return if ALL_FEATURES.include?(feature_name(node)) && args_count(node) == 2
- if !ALL_FEATURES.include?(feature_name(node))
+ if !ALL_FEATURES.include?(feature_name(node)) # rubocop:disable Rails/NegateInclude
add_offense(node, message: licensed_feature_message(node))
elsif args_count(node) < 2
add_offense(node, message: NOT_ENOUGH_ARGS_MSG)
diff --git a/rubocop/cop/gitlab/json.rb b/rubocop/cop/gitlab/json.rb
index cf2ed0ba536..8b10850b894 100644
--- a/rubocop/cop/gitlab/json.rb
+++ b/rubocop/cop/gitlab/json.rb
@@ -6,9 +6,9 @@ module RuboCop
class Json < RuboCop::Cop::Base
extend RuboCop::Cop::AutoCorrector
- MSG = <<~EOL
+ MSG = <<~TEXT
Prefer `Gitlab::Json` over calling `JSON` directly. See https://docs.gitlab.com/ee/development/json.html
- EOL
+ TEXT
AVAILABLE_METHODS = %i[parse parse! load decode dump generate encode pretty_generate].to_set.freeze
@@ -41,7 +41,7 @@ module RuboCop
end
def cbased(node)
- return unless %r{/ee/}.match?(node.location.expression.source_buffer.name)
+ return unless node.location.expression.source_buffer.name.include?('/ee/')
"::"
end
diff --git a/rubocop/cop/gitlab/mark_used_feature_flags.rb b/rubocop/cop/gitlab/mark_used_feature_flags.rb
index ffd59c8fffc..f466ab87aa0 100644
--- a/rubocop/cop/gitlab/mark_used_feature_flags.rb
+++ b/rubocop/cop/gitlab/mark_used_feature_flags.rb
@@ -32,12 +32,6 @@ module RuboCop
RESTRICT_ON_SEND = FEATURE_METHODS + SELF_METHODS
- USAGE_DATA_COUNTERS_EVENTS_YAML_GLOBS = [
- File.expand_path("../../../config/metrics/aggregates/*.yml", __dir__),
- File.expand_path("../../../lib/gitlab/usage_data_counters/known_events/*.yml", __dir__),
- File.expand_path("../../../ee/lib/ee/gitlab/usage_data_counters/known_events/*.yml", __dir__)
- ].freeze
-
class << self
# We track feature flags in `on_new_investigation` only once per
# rubocop whole run instead once per file.
@@ -52,8 +46,6 @@ module RuboCop
return if self.class.feature_flags_already_tracked
self.class.feature_flags_already_tracked = true
-
- track_usage_data_counters_known_events!
end
def on_casgn(node)
@@ -184,22 +176,6 @@ module RuboCop
feature_method?(node) || self_method?(node)
end
- # Marking all event's feature flags as used as Gitlab::UsageDataCounters::HLLRedisCounter.track_event{,context}
- # is mostly used with dynamic event name.
- def track_usage_data_counters_known_events!
- usage_data_counters_known_event_feature_flags.each { |feature_flag_name| save_used_feature_flag(feature_flag_name) }
- end
-
- def usage_data_counters_known_event_feature_flags
- USAGE_DATA_COUNTERS_EVENTS_YAML_GLOBS.each_with_object(Set.new) do |glob, memo|
- Dir.glob(glob).each do |path|
- YAML.safe_load(File.read(path))&.each do |hash|
- memo << hash['feature_flag'] if hash['feature_flag']
- end
- end
- end
- end
-
def defined_feature_flags
@defined_feature_flags ||= begin
flags_paths = [
diff --git a/rubocop/cop/graphql/id_type.rb b/rubocop/cop/graphql/id_type.rb
index eb677aa4507..c9d9b4ea6eb 100644
--- a/rubocop/cop/graphql/id_type.rb
+++ b/rubocop/cop/graphql/id_type.rb
@@ -21,7 +21,7 @@ module RuboCop
private
def does_not_match?(arg)
- !WHITELISTED_ARGUMENTS.include?(arg)
+ !WHITELISTED_ARGUMENTS.include?(arg) # rubocop:disable Rails/NegateInclude
end
end
end
diff --git a/rubocop/cop/migration/add_reference.rb b/rubocop/cop/migration/add_reference.rb
index 02a0ef899b4..8daa85749fd 100644
--- a/rubocop/cop/migration/add_reference.rb
+++ b/rubocop/cop/migration/add_reference.rb
@@ -41,7 +41,7 @@ module RuboCop
private
def existing_table?(new_tables, table)
- !new_tables.include?(table)
+ !new_tables.include?(table) # rubocop:disable Rails/NegateInclude
end
def create_table?(node)
diff --git a/rubocop/cop/rspec/factory_bot/inline_association.rb b/rubocop/cop/rspec/factory_bot/inline_association.rb
index 8d7c73b99a0..acd2c10a63d 100644
--- a/rubocop/cop/rspec/factory_bot/inline_association.rb
+++ b/rubocop/cop/rspec/factory_bot/inline_association.rb
@@ -99,7 +99,7 @@ module RuboCop
def inside_assocation_definition?(node)
node.each_ancestor(:block).any? do |parent|
name = association_definition(parent)
- name && !SKIP_NAMES.include?(name)
+ name && !SKIP_NAMES.include?(name) # rubocop:disable Rails/NegateInclude
end
end
end
diff --git a/rubocop/rubocop-ruby30.yml b/rubocop/rubocop-ruby30.yml
index d46bb9388a3..b984d761b80 100644
--- a/rubocop/rubocop-ruby30.yml
+++ b/rubocop/rubocop-ruby30.yml
@@ -2,8 +2,8 @@
# Ruby 3.0.
#
# After the transition has been completed:
-# * Move all configuration which enable cops to .rubocop.yml.
-# * Remove all reminaing configuration.
+# * 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:
diff --git a/rubocop/rubocop-ruby31.yml b/rubocop/rubocop-ruby31.yml
new file mode 100644
index 00000000000..109c7ca2dfe
--- /dev/null
+++ b/rubocop/rubocop-ruby31.yml
@@ -0,0 +1,10 @@
+# RuboCop configuration adjustments during the transition time from Ruby 3.0 to
+# Ruby 3.1.
+#
+# After the transition has been completed:
+# * Move all configuration which enabled or tweaked cops to .rubocop.yml.
+# * Remove all remaining configuration.
+
+# Short-hand Hash syntax does not work prior 3.1.
+Style/HashSyntax:
+ EnforcedShorthandSyntax: never
diff --git a/scripts/api/base.rb b/scripts/api/base.rb
new file mode 100644
index 00000000000..972b461a09a
--- /dev/null
+++ b/scripts/api/base.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'gitlab'
+require_relative 'default_options'
+
+class Base
+ def initialize(options)
+ @project = options.fetch(:project)
+
+ # If api_token is nil, it's set to '' to allow unauthenticated requests (for forks).
+ api_token = options[:api_token] || ''
+
+ warn "No API token given." if api_token.empty?
+
+ @client = Gitlab.client(
+ endpoint: options.fetch(:endpoint, API::DEFAULT_OPTIONS[:endpoint]),
+ private_token: api_token
+ )
+ end
+
+ def execute
+ raise NotImplementedError
+ end
+
+ private
+
+ attr_reader :project, :client
+end
diff --git a/scripts/api/cancel_pipeline.rb b/scripts/api/cancel_pipeline.rb
index 2667cfb9733..5069527368b 100755
--- a/scripts/api/cancel_pipeline.rb
+++ b/scripts/api/cancel_pipeline.rb
@@ -1,19 +1,13 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
-require 'gitlab'
require 'optparse'
-require_relative 'default_options'
+require_relative 'base'
-class CancelPipeline
+class CancelPipeline < Base
def initialize(options)
- @project = options.delete(:project)
+ super
@pipeline_id = options.delete(:pipeline_id)
-
- @client = Gitlab.client(
- endpoint: options.delete(:endpoint) || API::DEFAULT_OPTIONS[:endpoint],
- private_token: options.delete(:api_token)
- )
end
def execute
@@ -22,7 +16,7 @@ class CancelPipeline
private
- attr_reader :project, :pipeline_id, :client
+ attr_reader :pipeline_id
end
if $PROGRAM_NAME == __FILE__
diff --git a/scripts/api/commit_merge_requests.rb b/scripts/api/commit_merge_requests.rb
index 3cf8dc87497..523d2e769f0 100644
--- a/scripts/api/commit_merge_requests.rb
+++ b/scripts/api/commit_merge_requests.rb
@@ -1,22 +1,11 @@
# frozen_string_literal: true
-require 'gitlab'
-require_relative 'default_options'
+require_relative 'base'
-class CommitMergeRequests
+class CommitMergeRequests < Base
def initialize(options)
- @project = options.fetch(:project)
+ super
@sha = options.fetch(:sha)
-
- # If api_token is nil, it's set to '' to allow unauthenticated requests (for forks).
- api_token = options.fetch(:api_token, '')
-
- warn "No API token given." if api_token.empty?
-
- @client = Gitlab.client(
- endpoint: options.fetch(:endpoint, API::DEFAULT_OPTIONS[:endpoint]),
- private_token: api_token
- )
end
def execute
@@ -25,5 +14,5 @@ class CommitMergeRequests
private
- attr_reader :project, :sha, :client
+ attr_reader :sha
end
diff --git a/scripts/api/create_issue.rb b/scripts/api/create_issue.rb
index 2117c285771..1c385ce41f2 100644
--- a/scripts/api/create_issue.rb
+++ b/scripts/api/create_issue.rb
@@ -1,29 +1,9 @@
# frozen_string_literal: true
-require 'gitlab'
-require_relative 'default_options'
-
-class CreateIssue
- def initialize(options)
- @project = options.fetch(:project)
-
- # Force the token to be a string so that if api_token is nil, it's set to '',
- # allowing unauthenticated requests (for forks).
- api_token = options.delete(:api_token).to_s
-
- warn "No API token given." if api_token.empty?
-
- @client = Gitlab.client(
- endpoint: options.delete(:endpoint) || API::DEFAULT_OPTIONS[:endpoint],
- private_token: api_token
- )
- end
+require_relative 'base'
+class CreateIssue < Base
def execute(issue_data)
client.create_issue(project, issue_data.delete(:title), issue_data)
end
-
- private
-
- attr_reader :project, :client
end
diff --git a/scripts/api/create_issue_discussion.rb b/scripts/api/create_issue_discussion.rb
index 74a9f3ae378..6471a5c2579 100644
--- a/scripts/api/create_issue_discussion.rb
+++ b/scripts/api/create_issue_discussion.rb
@@ -1,32 +1,12 @@
# frozen_string_literal: true
-require 'gitlab'
-require_relative 'default_options'
-
-class CreateIssueDiscussion
- def initialize(options)
- @project = options.fetch(:project)
-
- # Force the token to be a string so that if api_token is nil, it's set to '',
- # allowing unauthenticated requests (for forks).
- api_token = options.delete(:api_token).to_s
-
- warn "No API token given." if api_token.empty?
-
- @client = Gitlab.client(
- endpoint: options.delete(:endpoint) || API::DEFAULT_OPTIONS[:endpoint],
- private_token: api_token
- )
- end
+require_relative 'base'
+class CreateIssueDiscussion < Base
def execute(discussion_data)
client.post(
"/projects/#{client.url_encode project}/issues/#{discussion_data.delete(:issue_iid)}/discussions",
body: discussion_data
)
end
-
- private
-
- attr_reader :project, :client
end
diff --git a/scripts/api/find_issues.rb b/scripts/api/find_issues.rb
index a1c37030319..f74f815fba9 100644
--- a/scripts/api/find_issues.rb
+++ b/scripts/api/find_issues.rb
@@ -1,29 +1,9 @@
# frozen_string_literal: true
-require 'gitlab'
-require_relative 'default_options'
-
-class FindIssues
- def initialize(options)
- @project = options.fetch(:project)
-
- # Force the token to be a string so that if api_token is nil, it's set to '',
- # allowing unauthenticated requests (for forks).
- api_token = options.delete(:api_token).to_s
-
- warn "No API token given." if api_token.empty?
-
- @client = Gitlab.client(
- endpoint: options.delete(:endpoint) || API::DEFAULT_OPTIONS[:endpoint],
- private_token: api_token
- )
- end
+require_relative 'base'
+class FindIssues < Base
def execute(search_data)
client.issues(project, search_data)
end
-
- private
-
- attr_reader :project, :client
end
diff --git a/scripts/api/get_job_id.rb b/scripts/api/get_job_id.rb
index 12535106a4c..babe8f5dee0 100755
--- a/scripts/api/get_job_id.rb
+++ b/scripts/api/get_job_id.rb
@@ -1,11 +1,10 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
-require 'gitlab'
require 'optparse'
-require_relative 'default_options'
+require_relative 'base'
-class JobFinder
+class JobFinder < Base
DEFAULT_OPTIONS = API::DEFAULT_OPTIONS.merge(
pipeline_query: {}.freeze,
job_query: {}.freeze
@@ -13,22 +12,12 @@ class JobFinder
MAX_PIPELINES_TO_ITERATE = 20
def initialize(options)
- @project = options.delete(:project)
+ super
@pipeline_query = options.delete(:pipeline_query) || DEFAULT_OPTIONS[:pipeline_query]
@job_query = options.delete(:job_query) || DEFAULT_OPTIONS[:job_query]
@pipeline_id = options.delete(:pipeline_id)
@job_name = options.delete(:job_name)
@artifact_path = options.delete(:artifact_path)
-
- # Force the token to be a string so that if api_token is nil, it's set to '', allowing unauthenticated requests (for forks).
- api_token = options.delete(:api_token).to_s
-
- warn "No API token given." if api_token.empty?
-
- @client = Gitlab.client(
- endpoint: options.delete(:endpoint) || DEFAULT_OPTIONS[:endpoint],
- private_token: api_token
- )
end
def execute
@@ -37,7 +26,7 @@ class JobFinder
private
- attr_reader :project, :pipeline_query, :job_query, :pipeline_id, :job_name, :artifact_path, :client
+ attr_reader :pipeline_query, :job_query, :pipeline_id, :job_name, :artifact_path
def find_job_with_artifact
return if artifact_path.nil?
diff --git a/scripts/api/pipeline_failed_jobs.rb b/scripts/api/pipeline_failed_jobs.rb
index df9a7e76dcd..9012d48994f 100644
--- a/scripts/api/pipeline_failed_jobs.rb
+++ b/scripts/api/pipeline_failed_jobs.rb
@@ -1,25 +1,12 @@
# frozen_string_literal: true
-require 'gitlab'
+require_relative 'base'
-require_relative 'default_options'
-
-class PipelineFailedJobs
+class PipelineFailedJobs < Base
def initialize(options)
- @project = options.delete(:project)
+ super
@pipeline_id = options.delete(:pipeline_id)
@exclude_allowed_to_fail_jobs = options.delete(:exclude_allowed_to_fail_jobs)
-
- # Force the token to be a string so that if api_token is nil, it's set to '',
- # allowing unauthenticated requests (for forks).
- api_token = options.delete(:api_token).to_s
-
- warn "No API token given." if api_token.empty?
-
- @client = Gitlab.client(
- endpoint: options.delete(:endpoint) || API::DEFAULT_OPTIONS[:endpoint],
- private_token: api_token
- )
end
def execute
@@ -43,5 +30,5 @@ class PipelineFailedJobs
private
- attr_reader :project, :pipeline_id, :exclude_allowed_to_fail_jobs, :client
+ attr_reader :pipeline_id, :exclude_allowed_to_fail_jobs
end
diff --git a/scripts/api/update_issue.rb b/scripts/api/update_issue.rb
new file mode 100644
index 00000000000..ce296ebc358
--- /dev/null
+++ b/scripts/api/update_issue.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'gitlab'
+require_relative 'default_options'
+
+class UpdateIssue
+ def initialize(options)
+ @project = options.fetch(:project)
+
+ # Force the token to be a string so that if api_token is nil, it's set to '',
+ # allowing unauthenticated requests (for forks).
+ api_token = options.delete(:api_token).to_s
+
+ warn "No API token given." if api_token.empty?
+
+ @client = Gitlab.client(
+ endpoint: options.delete(:endpoint) || API::DEFAULT_OPTIONS[:endpoint],
+ private_token: api_token
+ )
+ end
+
+ def execute(issue_iid, issue_data)
+ client.edit_issue(project, issue_iid, issue_data)
+ end
+
+ private
+
+ attr_reader :project, :client
+end
diff --git a/scripts/database/schema_validator.rb b/scripts/database/schema_validator.rb
new file mode 100644
index 00000000000..11a53faa945
--- /dev/null
+++ b/scripts/database/schema_validator.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require_relative '../migration_schema_validator'
+
+class SchemaValidator < MigrationSchemaValidator
+ ALLOW_SCHEMA_CHANGES = 'ALLOW_SCHEMA_CHANGES'
+ COMMIT_MESSAGE_SKIP_TAG = 'skip-db-structure-check'
+
+ def validate!
+ return if should_skip?
+
+ return if schema_changes.empty?
+
+ die "#{FILENAME} was changed, and no migrations were added:\n#{schema_changes}" if committed_migrations.empty?
+ end
+
+ private
+
+ def schema_changes
+ @schema_changes ||= run("git diff #{diff_target} HEAD -- #{FILENAME}")
+ end
+
+ def should_skip?
+ skip_env_present? || skip_commit_present?
+ end
+
+ def skip_env_present?
+ !ENV[ALLOW_SCHEMA_CHANGES].to_s.empty?
+ end
+
+ def skip_commit_present?
+ run("git show -s --format=%B -n 1").to_s.include?(COMMIT_MESSAGE_SKIP_TAG)
+ end
+end
diff --git a/scripts/db_tasks b/scripts/db_tasks
index 36040877abf..645e46e02d9 100755
--- a/scripts/db_tasks
+++ b/scripts/db_tasks
@@ -5,6 +5,7 @@ require 'yaml'
rails_env = ENV.fetch('RAILS_ENV')
database_config = YAML.load_file(File.join(File.expand_path('..', __dir__), 'config', 'database.yml'))[rails_env]
+database_config.reject! { |_k, v| v["database_tasks"] == false }
task = ARGV.shift
raise ArgumentError, 'You need to pass a task name!' unless task
@@ -14,4 +15,4 @@ cmd = ['bundle', 'exec', 'rake', task, *ARGV]
puts "Running: `#{cmd.join(' ')}`"
-system(*cmd)
+exit 1 unless system(*cmd)
diff --git a/scripts/decomposition/generate-loose-foreign-key b/scripts/decomposition/generate-loose-foreign-key
index ad7d6e32aa0..1ea1728732b 100755
--- a/scripts/decomposition/generate-loose-foreign-key
+++ b/scripts/decomposition/generate-loose-foreign-key
@@ -110,15 +110,12 @@ def add_definition_to_yaml(definition)
content = YAML.load_file(Rails.root.join('config/gitlab_loose_foreign_keys.yml'))
table_definitions = content[definition.from_table]
- # insert new entry at random place to avoid conflicts
+ # insert new entry in alphabetic order
unless table_definitions
table_definitions = []
- insert_idx = rand(content.count+1)
- # insert at a given index in ordered hash
- content = content.to_a
- content.insert(insert_idx, [definition.from_table, table_definitions])
- content = content.to_h
+ content[definition.from_table] = table_definitions
+ content = content.sort.to_h
end
on_delete =
@@ -217,7 +214,7 @@ def add_test_to_specs(definition)
puts "Adding test to #{spec_path}..."
spec_test = <<-EOF.strip_heredoc.indent(2)
- context 'loose foreign key on #{definition.from_table}.#{definition.column}' do
+ context 'with loose foreign key on #{definition.from_table}.#{definition.column}' do
it_behaves_like 'cleanup by a loose foreign key' do
let!(:parent) { create(:#{definition.to_table.singularize}) }
let!(:model) { create(:#{definition.from_table.singularize}, #{definition.column.delete_suffix("_id").singularize}: parent) }
diff --git a/scripts/frontend/startup_css/constants.js b/scripts/frontend/startup_css/constants.js
index 5143c04dc37..e6ca4472fe3 100644
--- a/scripts/frontend/startup_css/constants.js
+++ b/scripts/frontend/startup_css/constants.js
@@ -52,11 +52,14 @@ const createMainOutput = ({ outFile, cssKeys, type }) => ({
path.join(FIXTURES_ROOT, `startup_css/project-${type}.html`),
path.join(FIXTURES_ROOT, `startup_css/project-${type}-signed-out.html`),
path.join(FIXTURES_ROOT, `startup_css/project-${type}-search-ff-off.html`),
+ path.join(FIXTURES_ROOT, `startup_css/project-${type}-super-sidebar.html`),
],
cssKeys,
purgeOptions: {
safelist: {
standard: [
+ 'page-with-super-sidebar',
+ 'page-with-super-sidebar-collapsed',
'page-with-icon-sidebar',
'sidebar-collapsed-desktop',
// We want to include the root dropdown-menu style since it should be hidden by default
diff --git a/scripts/generate-e2e-pipeline b/scripts/generate-e2e-pipeline
index c612a700f90..8ca6771bf1f 100755
--- a/scripts/generate-e2e-pipeline
+++ b/scripts/generate-e2e-pipeline
@@ -27,7 +27,7 @@ variables:
GIT_STRATEGY: "clone" # 'GIT_STRATEGY: clone' optimizes the pack-objects cache hit ratio
GIT_SUBMODULE_STRATEGY: "none"
GITLAB_QA_CACHE_KEY: "$qa_cache_key"
- GITLAB_VERSION: "$(cat VERSION)"
+ GITLAB_SEMVER_VERSION: "$(cat VERSION)"
QA_EXPORT_TEST_METRICS: "${QA_EXPORT_TEST_METRICS:-true}"
QA_FEATURE_FLAGS: "${QA_FEATURE_FLAGS}"
QA_FRAMEWORK_CHANGES: "${QA_FRAMEWORK_CHANGES:-false}"
@@ -41,6 +41,7 @@ YML
echo "Using .gitlab/ci/review-apps/main.gitlab-ci.yml and .gitlab/ci/package-and-test/main.gitlab-ci.yml"
cp .gitlab/ci/review-apps/main.gitlab-ci.yml "$REVIEW_PIPELINE_YML"
echo "$variables" >>"$REVIEW_PIPELINE_YML"
+
cp .gitlab/ci/package-and-test/main.gitlab-ci.yml "$OMNIBUS_PIPELINE_YML"
echo "$variables" >>"$OMNIBUS_PIPELINE_YML"
diff --git a/scripts/generate-rspec-foss-impact-pipeline b/scripts/generate-rspec-foss-impact-pipeline
deleted file mode 100755
index 3277f38ebe1..00000000000
--- a/scripts/generate-rspec-foss-impact-pipeline
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-# Script to generate `rspec foss-impact` test child pipeline with dynamically parallelized jobs.
-
-source scripts/utils.sh
-
-rspec_matching_tests_foss_path="${1}"
-pipeline_yml="${2}"
-
-test_file_count=$(wc -w "${rspec_matching_tests_foss_path}" | awk '{ print $1 }')
-echoinfo "test_file_count: ${test_file_count}"
-
-if [[ "${test_file_count}" -eq 0 ]]; then
- skip_pipeline=".gitlab/ci/_skip.yml"
-
- echo "Using ${skip_pipeline} due to no impacted FOSS rspec tests to run"
- cp $skip_pipeline "$pipeline_yml"
- exit
-fi
-
-# As of 2022-09-01:
-# $ find spec -type f | wc -l
-# 12825
-# and
-# $ find ee/spec -type f | wc -l
-# 5610
-# which gives a total of 18435 test files (`number_of_tests_in_total_in_the_test_suite`).
-#
-# Total time to run all tests (based on https://gitlab-org.gitlab.io/rspec_profiling_stats/) is 170183 seconds (`duration_of_the_test_suite_in_seconds`).
-#
-# This gives an approximate 170183 / 18435 = 9.2 seconds per test file (`average_test_file_duration_in_seconds`).
-#
-# If we want each test job to finish in 10 minutes, given we have 3 minutes of setup (`setup_duration_in_seconds`), then we need to give 7 minutes of testing to each test node (`optimal_test_runtime_duration_in_seconds`).
-# (7 * 60) / 9.2 = 45.6
-#
-# So if we'd want to run the full test suites in 10 minutes (`optimal_test_job_duration_in_seconds`), we'd need to run at max 45 test file per nodes (`optimal_test_file_count_per_node`).
-number_of_tests_in_total_in_the_test_suite=18435
-duration_of_the_test_suite_in_seconds=170183
-optimal_test_job_duration_in_seconds=600 # 10 minutes
-setup_duration_in_seconds=180 # 3 minutes
-
-optimal_test_runtime_duration_in_seconds=$(( optimal_test_job_duration_in_seconds - setup_duration_in_seconds ))
-echoinfo "optimal_test_runtime_duration_in_seconds: ${optimal_test_runtime_duration_in_seconds}"
-
-average_test_file_duration_in_seconds=$(( duration_of_the_test_suite_in_seconds / number_of_tests_in_total_in_the_test_suite ))
-echoinfo "average_test_file_duration_in_seconds: ${average_test_file_duration_in_seconds}"
-
-optimal_test_file_count_per_node=$(( optimal_test_runtime_duration_in_seconds / average_test_file_duration_in_seconds ))
-echoinfo "optimal_test_file_count_per_node: ${optimal_test_file_count_per_node}"
-
-node_count=$(( test_file_count / optimal_test_file_count_per_node ))
-echoinfo "node_count: ${node_count}"
-
-echoinfo "Optimal node count for 'rspec foss-impact' jobs is ${node_count}."
-
-MAX_NODES_COUNT=50 # Maximum parallelization allowed by GitLab
-if [[ "${node_count}" -gt "${MAX_NODES_COUNT}" ]]; then
- echoinfo "We don't want to parallelize 'rspec foss-impact' to more than ${MAX_NODES_COUNT} jobs for now! Decreasing the parallelization to ${MAX_NODES_COUNT}."
- node_count=${MAX_NODES_COUNT}
-fi
-
-ruby -rerb -e "puts ERB.new(File.read('.gitlab/ci/rails/rspec-foss-impact.gitlab-ci.yml.erb')).result_with_hash(parallel_value: ${node_count})" > "${pipeline_yml}"
-
-echosuccess "Generated ${pipeline_yml} pipeline with following content:"
-cat "${pipeline_yml}"
diff --git a/scripts/generate_rspec_pipeline.rb b/scripts/generate_rspec_pipeline.rb
new file mode 100755
index 00000000000..e226acc0430
--- /dev/null
+++ b/scripts/generate_rspec_pipeline.rb
@@ -0,0 +1,176 @@
+#!/usr/bin/env ruby
+
+# frozen_string_literal: true
+
+require 'optparse'
+require 'json'
+require 'fileutils'
+require 'erb'
+require_relative '../tooling/quality/test_level'
+
+# Class to generate RSpec test child pipeline with dynamically parallelized jobs.
+class GenerateRspecPipeline
+ SKIP_PIPELINE_YML_FILE = ".gitlab/ci/_skip.yml"
+ TEST_LEVELS = %i[migration background_migration unit integration system].freeze
+ MAX_NODES_COUNT = 50 # Maximum parallelization allowed by GitLab
+
+ OPTIMAL_TEST_JOB_DURATION_IN_SECONDS = 600 # 10 MINUTES
+ SETUP_DURATION_IN_SECONDS = 180.0 # 3 MINUTES
+ OPTIMAL_TEST_RUNTIME_DURATION_IN_SECONDS = OPTIMAL_TEST_JOB_DURATION_IN_SECONDS - SETUP_DURATION_IN_SECONDS
+
+ # As of 2022-09-01:
+ # $ find spec -type f | wc -l
+ # 12825
+ # and
+ # $ find ee/spec -type f | wc -l
+ # 5610
+ # which gives a total of 18435 test files (`NUMBER_OF_TESTS_IN_TOTAL_IN_THE_TEST_SUITE`).
+ #
+ # Total time to run all tests (based on https://gitlab-org.gitlab.io/rspec_profiling_stats/)
+ # is 170183 seconds (`DURATION_OF_THE_TEST_SUITE_IN_SECONDS`).
+ #
+ # This gives an approximate 170183 / 18435 = 9.2 seconds per test file
+ # (`DEFAULT_AVERAGE_TEST_FILE_DURATION_IN_SECONDS`).
+ #
+ # If we want each test job to finish in 10 minutes, given we have 3 minutes of setup (`SETUP_DURATION_IN_SECONDS`),
+ # then we need to give 7 minutes of testing to each test node (`OPTIMAL_TEST_RUNTIME_DURATION_IN_SECONDS`).
+ # (7 * 60) / 9.2 = 45.6
+ #
+ # So if we'd want to run the full test suites in 10 minutes (`OPTIMAL_TEST_JOB_DURATION_IN_SECONDS`),
+ # we'd need to run at max 45 test file per nodes (`#optimal_test_file_count_per_node_per_test_level`).
+ NUMBER_OF_TESTS_IN_TOTAL_IN_THE_TEST_SUITE = 18_435
+ DURATION_OF_THE_TEST_SUITE_IN_SECONDS = 170_183
+ DEFAULT_AVERAGE_TEST_FILE_DURATION_IN_SECONDS =
+ DURATION_OF_THE_TEST_SUITE_IN_SECONDS / NUMBER_OF_TESTS_IN_TOTAL_IN_THE_TEST_SUITE
+
+ # rspec_files_path: A file containing RSpec files to run, separated by a space
+ # pipeline_template_path: A YAML pipeline configuration template to generate the final pipeline config from
+ def initialize(pipeline_template_path:, rspec_files_path: nil, knapsack_report_path: nil)
+ @pipeline_template_path = pipeline_template_path.to_s
+ @rspec_files_path = rspec_files_path.to_s
+ @knapsack_report_path = knapsack_report_path.to_s
+
+ raise ArgumentError unless File.exist?(@pipeline_template_path)
+ end
+
+ def generate!
+ if all_rspec_files.empty?
+ info "Using #{SKIP_PIPELINE_YML_FILE} due to no RSpec files to run"
+ FileUtils.cp(SKIP_PIPELINE_YML_FILE, pipeline_filename)
+ return
+ end
+
+ File.open(pipeline_filename, 'w') do |handle|
+ pipeline_yaml = ERB.new(File.read(pipeline_template_path)).result_with_hash(**erb_binding)
+ handle.write(pipeline_yaml.squeeze("\n").strip)
+ end
+ end
+
+ private
+
+ attr_reader :pipeline_template_path, :rspec_files_path, :knapsack_report_path
+
+ def info(text)
+ $stdout.puts "[#{self.class.name}] #{text}"
+ end
+
+ def all_rspec_files
+ @all_rspec_files ||= File.exist?(rspec_files_path) ? File.read(rspec_files_path).split(' ') : []
+ end
+
+ def pipeline_filename
+ @pipeline_filename ||= "#{pipeline_template_path}.yml"
+ end
+
+ def erb_binding
+ { rspec_files_per_test_level: rspec_files_per_test_level }
+ end
+
+ def rspec_files_per_test_level
+ @rspec_files_per_test_level ||= begin
+ all_remaining_rspec_files = all_rspec_files.dup
+ TEST_LEVELS.each_with_object(Hash.new { |h, k| h[k] = {} }) do |test_level, memo| # rubocop:disable Rails/IndexWith
+ memo[test_level][:files] = all_remaining_rspec_files
+ .grep(Quality::TestLevel.new.regexp(test_level))
+ .tap { |files| files.each { |file| all_remaining_rspec_files.delete(file) } }
+ memo[test_level][:parallelization] = optimal_nodes_count(test_level, memo[test_level][:files])
+ end
+ end
+ end
+
+ def optimal_nodes_count(test_level, rspec_files)
+ nodes_count = (rspec_files.size / optimal_test_file_count_per_node_per_test_level(test_level)).ceil
+ info "Optimal node count for #{rspec_files.size} #{test_level} RSpec files is #{nodes_count}."
+
+ if nodes_count > MAX_NODES_COUNT
+ info "We don't want to parallelize to more than #{MAX_NODES_COUNT} jobs for now! " \
+ "Decreasing the parallelization to #{MAX_NODES_COUNT}."
+
+ MAX_NODES_COUNT
+ else
+ nodes_count
+ end
+ end
+
+ def optimal_test_file_count_per_node_per_test_level(test_level)
+ [
+ (OPTIMAL_TEST_RUNTIME_DURATION_IN_SECONDS / average_test_file_duration_in_seconds_per_test_level[test_level]),
+ 1
+ ].max
+ end
+
+ def average_test_file_duration_in_seconds_per_test_level
+ @optimal_test_file_count_per_node_per_test_level ||=
+ if knapsack_report.any?
+ remaining_knapsack_report = knapsack_report.dup
+ TEST_LEVELS.each_with_object({}) do |test_level, memo|
+ matching_data_per_test_level = remaining_knapsack_report
+ .select { |test_file, _| test_file.match?(Quality::TestLevel.new.regexp(test_level)) }
+ .tap { |test_data| test_data.each { |file, _| remaining_knapsack_report.delete(file) } }
+ memo[test_level] =
+ matching_data_per_test_level.values.sum / matching_data_per_test_level.keys.size
+ end
+ else
+ TEST_LEVELS.each_with_object({}) do |test_level, memo| # rubocop:disable Rails/IndexWith
+ memo[test_level] = DEFAULT_AVERAGE_TEST_FILE_DURATION_IN_SECONDS
+ end
+ end
+ end
+
+ def knapsack_report
+ @knapsack_report ||=
+ begin
+ File.exist?(knapsack_report_path) ? JSON.parse(File.read(knapsack_report_path)) : {}
+ rescue JSON::ParserError => e
+ info "[ERROR] Knapsack report at #{knapsack_report_path} couldn't be parsed! Error:\n#{e}"
+ {}
+ end
+ end
+end
+
+if $PROGRAM_NAME == __FILE__
+ options = {}
+
+ OptionParser.new do |opts|
+ opts.on("-f", "--rspec-files-path path", String, "Path to a file containing RSpec files to run, " \
+ "separated by a space") do |value|
+ options[:rspec_files_path] = value
+ end
+
+ opts.on("-t", "--pipeline-template-path PATH", String, "Path to a YAML pipeline configuration template to " \
+ "generate the final pipeline config from") do |value|
+ options[:pipeline_template_path] = value
+ end
+
+ opts.on("-k", "--knapsack-report-path path", String, "Path to a Knapsack report") do |value|
+ options[:knapsack_report_path] = value
+ end
+
+ opts.on("-h", "--help", "Prints this help") do
+ puts opts
+ exit
+ end
+ end.parse!
+
+ GenerateRspecPipeline.new(**options).generate!
+end
diff --git a/scripts/gitlab_component_helpers.sh b/scripts/gitlab_component_helpers.sh
index c46dbb57a58..309e339de01 100644
--- a/scripts/gitlab_component_helpers.sh
+++ b/scripts/gitlab_component_helpers.sh
@@ -51,6 +51,24 @@ export GITLAB_ASSETS_HASH="${GITLAB_ASSETS_HASH:-"NO_HASH"}"
export GITLAB_ASSETS_PACKAGE="assets-${NODE_ENV}-${GITLAB_EDITION}-${GITLAB_ASSETS_HASH}-${GITLAB_ASSETS_PACKAGE_VERSION}.tar.gz"
export GITLAB_ASSETS_PACKAGE_URL="${API_PACKAGES_BASE_URL}/assets/${NODE_ENV}-${GITLAB_EDITION}-${GITLAB_ASSETS_HASH}/${GITLAB_ASSETS_PACKAGE}"
+# Fixtures constants
+
+# Export the SHA variable for updating/downloading fixture packages, using the following order of precedence:
+# 1. If MERGE_BASE_SHA is defined, use its value.
+# 2. If CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is defined, use its value for merge request pipelines.
+# 3. Otherwise, use the value of CI_COMMIT_SHA for default branch pipelines or merge requests with detached pipelines.
+if [ -n "${MERGE_BASE_SHA:-}" ]; then
+ export FIXTURES_SHA="${MERGE_BASE_SHA}"
+elif [ -n "${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA:-}" ]; then
+ export FIXTURES_SHA="${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA}"
+else
+ export FIXTURES_SHA="${CI_COMMIT_SHA}"
+fi
+
+export FIXTURES_PATH="tmp/tests/frontend/**/*"
+export FIXTURES_PACKAGE="fixtures-${FIXTURES_SHA}.tar.gz"
+export FIXTURES_PACKAGE_URL="${API_PACKAGES_BASE_URL}/fixtures/${FIXTURES_SHA}/${FIXTURES_PACKAGE}"
+
# Generic helper functions
function archive_doesnt_exist() {
local package_url="${1}"
@@ -147,3 +165,16 @@ function create_gitlab_assets_package() {
function upload_gitlab_assets_package() {
upload_package "${GITLAB_ASSETS_PACKAGE}" "${GITLAB_ASSETS_PACKAGE_URL}"
}
+
+# Fixtures functions
+function fixtures_archive_doesnt_exist() {
+ archive_doesnt_exist "${FIXTURES_PACKAGE_URL}"
+}
+
+function create_fixtures_package() {
+ create_package "${FIXTURES_PACKAGE}" "${FIXTURES_PATH}"
+}
+
+function upload_fixtures_package() {
+ upload_package "${FIXTURES_PACKAGE}" "${FIXTURES_PACKAGE_URL}"
+}
diff --git a/scripts/lint-docs-blueprints.rb b/scripts/lint-docs-blueprints.rb
index 35e0013cb34..d0a0a6a05de 100755
--- a/scripts/lint-docs-blueprints.rb
+++ b/scripts/lint-docs-blueprints.rb
@@ -22,7 +22,7 @@ def extract_front_matter(path)
end
class BlueprintFrontMatter
- STATUSES = %w[proposed accepted ongoing implemented rejected]
+ STATUSES = %w[proposed accepted ongoing implemented postponed rejected]
attr_reader :errors
@@ -32,6 +32,8 @@ class BlueprintFrontMatter
end
def validate
+ return if @metadata['redirect_to']
+
validate_status
validate_authors
validate_creation_date
diff --git a/scripts/pipeline/create_test_failure_issues.rb b/scripts/pipeline/create_test_failure_issues.rb
new file mode 100755
index 00000000000..6312d392760
--- /dev/null
+++ b/scripts/pipeline/create_test_failure_issues.rb
@@ -0,0 +1,224 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'optparse'
+require 'json'
+require 'httparty'
+
+require_relative '../api/create_issue'
+require_relative '../api/find_issues'
+require_relative '../api/update_issue'
+
+class CreateTestFailureIssues
+ DEFAULT_OPTIONS = {
+ project: nil,
+ tests_report_file: 'tests_report.json',
+ issue_json_folder: 'tmp/issues/'
+ }.freeze
+
+ def initialize(options)
+ @options = options
+ end
+
+ def execute
+ puts "[CreateTestFailureIssues] No failed tests!" if failed_tests.empty?
+
+ failed_tests.each_with_object([]) do |failed_test, existing_issues|
+ CreateTestFailureIssue.new(options.dup).comment_or_create(failed_test, existing_issues).tap do |issue|
+ existing_issues << issue
+ File.write(File.join(options[:issue_json_folder], "issue-#{issue.iid}.json"), JSON.pretty_generate(issue.to_h))
+ end
+ end
+ end
+
+ private
+
+ attr_reader :options
+
+ def failed_tests
+ @failed_tests ||=
+ if File.exist?(options[:tests_report_file])
+ JSON.parse(File.read(options[:tests_report_file]))
+ else
+ puts "[CreateTestFailureIssues] #{options[:tests_report_file]} doesn't exist!"
+ []
+ end
+ end
+end
+
+class CreateTestFailureIssue
+ MAX_TITLE_LENGTH = 255
+ WWW_GITLAB_COM_SITE = 'https://about.gitlab.com'
+ WWW_GITLAB_COM_GROUPS_JSON = "#{WWW_GITLAB_COM_SITE}/groups.json".freeze
+ WWW_GITLAB_COM_CATEGORIES_JSON = "#{WWW_GITLAB_COM_SITE}/categories.json".freeze
+ FEATURE_CATEGORY_METADATA_REGEX = /(?<=feature_category: :)\w+/
+ DEFAULT_LABELS = ['type::maintenance', 'failure::flaky-test'].freeze
+
+ def initialize(options)
+ @project = options.delete(:project)
+ @api_token = options.delete(:api_token)
+ end
+
+ def comment_or_create(failed_test, existing_issues = [])
+ existing_issue = find(failed_test, existing_issues)
+
+ if existing_issue
+ update_reports(existing_issue, failed_test)
+ existing_issue
+ else
+ create(failed_test)
+ end
+ end
+
+ def find(failed_test, existing_issues = [])
+ failed_test_issue_title = failed_test_issue_title(failed_test)
+ issue_from_existing_issues = existing_issues.find { |issue| issue.title == failed_test_issue_title }
+ issue_from_issue_tracker = FindIssues
+ .new(project: project, api_token: api_token)
+ .execute(state: 'opened', search: failed_test_issue_title)
+ .first
+
+ existing_issue = issue_from_existing_issues || issue_from_issue_tracker
+
+ return unless existing_issue
+
+ puts "[CreateTestFailureIssue] Found issue '#{existing_issue.title}': #{existing_issue.web_url}!"
+
+ existing_issue
+ end
+
+ def update_reports(existing_issue, failed_test)
+ new_issue_description = "#{existing_issue.description}\n- #{failed_test['job_url']} (#{ENV['CI_PIPELINE_URL']})"
+ UpdateIssue
+ .new(project: project, api_token: api_token)
+ .execute(existing_issue.iid, description: new_issue_description)
+ puts "[CreateTestFailureIssue] Added a report in '#{existing_issue.title}': #{existing_issue.web_url}!"
+ end
+
+ def create(failed_test)
+ payload = {
+ title: failed_test_issue_title(failed_test),
+ description: failed_test_issue_description(failed_test),
+ labels: failed_test_issue_labels(failed_test)
+ }
+
+ CreateIssue.new(project: project, api_token: api_token).execute(payload).tap do |issue|
+ puts "[CreateTestFailureIssue] Created issue '#{issue.title}': #{issue.web_url}!"
+ end
+ end
+
+ private
+
+ attr_reader :project, :api_token
+
+ def failed_test_id(failed_test)
+ Digest::SHA256.hexdigest(search_safe(failed_test['name']))[0...12]
+ end
+
+ def failed_test_issue_title(failed_test)
+ title = "#{failed_test['file']} - ID: #{failed_test_id(failed_test)}"
+
+ raise "Title is too long!" if title.size > MAX_TITLE_LENGTH
+
+ title
+ end
+
+ def failed_test_issue_description(failed_test)
+ <<~DESCRIPTION
+ ### Full description
+
+ `#{search_safe(failed_test['name'])}`
+
+ ### File path
+
+ `#{failed_test['file']}`
+
+ <!-- Don't add anything after the report list since it's updated automatically -->
+ ### Reports
+
+ - #{failed_test['job_url']} (#{ENV['CI_PIPELINE_URL']})
+ DESCRIPTION
+ end
+
+ def failed_test_issue_labels(failed_test)
+ labels = DEFAULT_LABELS + category_and_group_labels_for_test_file(failed_test['file'])
+
+ # make sure we don't spam people who are notified to actual labels
+ labels.map { |label| "wip-#{label}" }
+ end
+
+ def category_and_group_labels_for_test_file(test_file)
+ feature_categories = File.open(File.expand_path(File.join('..', '..', test_file), __dir__))
+ .read
+ .scan(FEATURE_CATEGORY_METADATA_REGEX)
+
+ category_labels = feature_categories.filter_map { |category| categories_mapping.dig(category, 'label') }.uniq
+
+ groups = feature_categories.filter_map { |category| categories_mapping.dig(category, 'group') }
+ group_labels = groups.map { |group| groups_mapping.dig(group, 'label') }.uniq
+
+ (category_labels + [group_labels.first]).compact
+ end
+
+ def categories_mapping
+ @categories_mapping ||= self.class.fetch_json(WWW_GITLAB_COM_CATEGORIES_JSON)
+ end
+
+ def groups_mapping
+ @groups_mapping ||= self.class.fetch_json(WWW_GITLAB_COM_GROUPS_JSON)
+ end
+
+ def search_safe(value)
+ value.delete('"')
+ end
+
+ def self.fetch_json(json_url)
+ json = with_retries { HTTParty.get(json_url, format: :plain) } # rubocop:disable Gitlab/HTTParty
+ JSON.parse(json)
+ end
+
+ def self.with_retries(attempts: 3)
+ yield
+ rescue Errno::ECONNRESET, OpenSSL::SSL::SSLError, Net::OpenTimeout
+ retry if (attempts -= 1) > 0
+ raise
+ end
+ private_class_method :with_retries
+end
+
+if $PROGRAM_NAME == __FILE__
+ options = CreateTestFailureIssues::DEFAULT_OPTIONS.dup
+
+ OptionParser.new do |opts|
+ opts.on("-p", "--project PROJECT", String,
+ "Project where to create the issue (defaults to " \
+ "`#{CreateTestFailureIssues::DEFAULT_OPTIONS[:project]}`)") do |value|
+ options[:project] = value
+ end
+
+ opts.on("-r", "--tests-report-file file_path", String,
+ "Path to a JSON file which contains the current pipeline's tests report (defaults to " \
+ "`#{CreateTestFailureIssues::DEFAULT_OPTIONS[:tests_report_file]}`)"
+ ) do |value|
+ options[:tests_report_file] = value
+ end
+
+ opts.on("-f", "--issues-json-folder file_path", String,
+ "Path to a folder where to save the issues JSON data (defaults to " \
+ "`#{CreateTestFailureIssues::DEFAULT_OPTIONS[:issue_json_folder]}`)") do |value|
+ options[:issue_json_folder] = value
+ end
+
+ opts.on("-t", "--api-token API_TOKEN", String,
+ "A valid Project token with the `Reporter` role and `api` scope to create the issue") do |value|
+ options[:api_token] = value
+ end
+
+ opts.on("-h", "--help", "Prints this help") do
+ puts opts
+ exit
+ end
+ end.parse!
+
+ CreateTestFailureIssues.new(options).execute
+end
diff --git a/scripts/pipeline_test_report_builder.rb b/scripts/pipeline_test_report_builder.rb
index 6f69a5c692f..c84acf2fd94 100755
--- a/scripts/pipeline_test_report_builder.rb
+++ b/scripts/pipeline_test_report_builder.rb
@@ -19,7 +19,8 @@ require_relative 'api/default_options'
# Push into expected format for failed tests
class PipelineTestReportBuilder
DEFAULT_OPTIONS = {
- target_project: Host::DEFAULT_OPTIONS[:target_project],
+ target_project: Host::DEFAULT_OPTIONS[:target_project] || API::DEFAULT_OPTIONS[:project],
+ current_pipeline_id: API::DEFAULT_OPTIONS[:pipeline_id],
mr_iid: Host::DEFAULT_OPTIONS[:mr_iid],
api_endpoint: API::DEFAULT_OPTIONS[:endpoint],
output_file_path: 'test_results/test_reports.json',
@@ -28,6 +29,7 @@ class PipelineTestReportBuilder
def initialize(options)
@target_project = options.delete(:target_project)
+ @current_pipeline_id = options.delete(:current_pipeline_id)
@mr_iid = options.delete(:mr_iid)
@api_endpoint = options.delete(:api_endpoint).to_s
@output_file_path = options.delete(:output_file_path).to_s
@@ -47,7 +49,7 @@ class PipelineTestReportBuilder
end
def latest_pipeline
- pipelines_sorted_descending[0]
+ fetch("#{target_project_api_base_url}/pipelines/#{current_pipeline_id}")
end
def previous_pipeline
@@ -58,6 +60,8 @@ class PipelineTestReportBuilder
private
+ attr_reader :target_project, :current_pipeline_id, :mr_iid, :api_endpoint, :output_file_path, :pipeline_index
+
def pipeline
@pipeline ||=
case pipeline_index
@@ -76,8 +80,6 @@ class PipelineTestReportBuilder
pipelines_for_mr.sort_by { |a| -a['id'] }
end
- attr_reader :target_project, :mr_iid, :api_endpoint, :output_file_path, :pipeline_index
-
def pipeline_project_api_base_url(pipeline)
"#{api_endpoint}/projects/#{pipeline['project_id']}"
end
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 500e61ab76a..ca3dd0eec57 100644
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -14,7 +14,13 @@ if [ "$DECOMPOSED_DB" == "true" ]; then
echo "Using decomposed database config (config/database.yml.decomposed-postgresql)"
cp config/database.yml.decomposed-postgresql config/database.yml
else
+ echo "Using decomposed database config (config/database.yml.postgresql)"
cp config/database.yml.postgresql config/database.yml
+
+ if [ "$CI_CONNECTION_DB" == "true" ]; then
+ echo "Enabling ci connection (database_tasks: false) in config/database.yml"
+ sed -i '/ci:/,/geo:/''s/^ # / /g' config/database.yml
+ fi
fi
# Set up Geo database if the job name matches `rspec-ee` or `geo`.
diff --git a/scripts/review_apps/automated_cleanup.rb b/scripts/review_apps/automated_cleanup.rb
index 7e606b74de9..5fff7f4ff88 100755
--- a/scripts/review_apps/automated_cleanup.rb
+++ b/scripts/review_apps/automated_cleanup.rb
@@ -36,8 +36,6 @@ module ReviewApps
@api_endpoint = api_endpoint
@dry_run = options[:dry_run]
@environments_not_found_count = 0
-
- puts "Dry-run mode." if dry_run
end
def gitlab
@@ -65,6 +63,7 @@ module ReviewApps
end
def perform_gitlab_environment_cleanup!(days_for_delete:)
+ puts "Dry-run mode." if dry_run
puts "Checking for Review Apps not updated in the last #{days_for_delete} days..."
checked_environments = []
@@ -106,6 +105,7 @@ module ReviewApps
end
def perform_gitlab_docs_environment_cleanup!(days_for_stop:, days_for_delete:)
+ puts "Dry-run mode." if dry_run
puts "Checking for Docs Review Apps not updated in the last #{days_for_stop} days..."
checked_environments = []
@@ -140,6 +140,7 @@ module ReviewApps
end
def perform_helm_releases_cleanup!(days:)
+ puts "Dry-run mode." if dry_run
puts "Checking for Helm releases that are failed or not updated in the last #{days} days..."
threshold = threshold_time(days: days)
@@ -162,12 +163,14 @@ module ReviewApps
end
def perform_stale_namespace_cleanup!(days:)
+ puts "Dry-run mode." if dry_run
kubernetes_client = Tooling::KubernetesClient.new(namespace: nil)
kubernetes_client.cleanup_review_app_namespaces(created_before: threshold_time(days: days), wait: false) unless dry_run
end
def perform_stale_pvc_cleanup!(days:)
+ puts "Dry-run mode." if dry_run
kubernetes.cleanup_by_created_at(resource_type: 'pvc', created_before: threshold_time(days: days), wait: false) unless dry_run
end
@@ -243,6 +246,7 @@ module ReviewApps
unless dry_run
helm.delete(release_name: releases_names)
kubernetes.cleanup_by_release(release_name: releases_names, wait: false)
+ kubernetes.delete_namespaces_by_exact_names(resource_names: releases_names, wait: false)
end
rescue Tooling::Helm3Client::CommandFailedError => ex
@@ -256,7 +260,11 @@ module ReviewApps
end
def threshold_time(days:)
- Time.now - days * 24 * 3600
+ days_integer = days.to_i
+
+ raise "days should be an integer between 1 and 365 inclusive! Got #{days_integer}" unless days_integer.between?(1, 365)
+
+ Time.now - days_integer * 24 * 3600
end
def ignore_exception?(exception_message, exceptions_ignored)
diff --git a/scripts/setup-test-env b/scripts/setup-test-env
index 97762e1cafa..ae00b569ce3 100755
--- a/scripts/setup-test-env
+++ b/scripts/setup-test-env
@@ -4,66 +4,49 @@
require_relative '../config/bundler_setup'
+require_relative '../spec/rails_autoload'
+
require 'request_store'
require 'rake'
-require 'active_support/dependencies'
-require 'active_support/dependencies/autoload'
-require 'active_support/core_ext/numeric'
-require 'active_support/string_inquirer'
+require 'active_support/all'
ENV['SKIP_RAILS_ENV_IN_RAKE'] = 'true'
-module Rails
- extend self
-
- def root
- Pathname.new(File.expand_path('..', __dir__))
- end
-
- def env
- @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test")
- end
-end
-
-ActiveSupport::Dependencies.autoload_paths << 'lib'
-
load File.expand_path('../lib/tasks/gitlab/helpers.rake', __dir__)
load File.expand_path('../lib/tasks/gitlab/gitaly.rake', __dir__)
-# Required for config/0_inject_enterprise_edition_module.rb, lib/gitlab/access.rb
-require_dependency File.expand_path('../lib/gitlab', __dir__)
-
-require_dependency File.expand_path('../config/initializers/0_inject_enterprise_edition_module', __dir__)
-
-# Require for lib/gitlab/gitaly_client/storage_settings.rb and config/initializers/1_settings.rb
-require 'active_support/hash_with_indifferent_access'
-
-# Required for lib/gitlab/visibility_level.rb and lib/gitlab/safe_request_store.rb
-require 'active_support/concern'
-require 'active_support/core_ext/module/delegation'
-
# Required for lib/system_check/helpers.rb
-require_dependency File.expand_path('../lib/gitlab/task_helpers', __dir__)
+require_relative '../lib/gitlab/task_helpers'
# Required for lib/tasks/gitlab/helpers.rake
-require_dependency File.expand_path('../lib/system_check/helpers', __dir__)
+require_relative '../lib/system_check/helpers'
# Required for config/initializers/1_settings.rb
require 'omniauth'
require 'omniauth-github'
require 'etc'
-require_dependency File.expand_path('../lib/gitlab/access', __dir__)
-require_dependency File.expand_path('../lib/gitlab/utils', __dir__)
+require_relative '../lib/gitlab/access'
+require_relative '../lib/gitlab/utils'
+
+unless defined?(License)
+ # This is needed to allow use of `Gitlab::ImportSources.values` in `1_settings.rb`.
+ # See ee/lib/ee/gitlab/import_sources.rb
+ class License
+ def self.database
+ Struct.new(:cached_table_exists?).new(false)
+ end
+ end
+end
-require_dependency File.expand_path('../config/initializers/1_settings', __dir__)
+require_relative '../config/initializers/1_settings'
Gitlab.ee do
load File.expand_path('../ee/lib/tasks/gitlab/indexer.rake', __dir__)
- require_dependency File.expand_path('../ee/lib/gitlab/elastic/indexer', __dir__)
- require_dependency File.expand_path('../lib/gitlab/utils/override', __dir__)
+ require_relative '../ee/lib/gitlab/elastic/indexer'
+ require_relative '../lib/gitlab/utils/override'
end
-require_dependency File.expand_path('../spec/support/helpers/test_env', __dir__)
+require_relative '../spec/support/helpers/test_env'
TestEnv.init
diff --git a/scripts/trigger-build.rb b/scripts/trigger-build.rb
index 69eea7488fb..c7c09557ff9 100755
--- a/scripts/trigger-build.rb
+++ b/scripts/trigger-build.rb
@@ -278,6 +278,7 @@ module Trigger
def extra_variables
{
"BRANCH_#{project_slug.upcase}" => ENV['CI_COMMIT_REF_NAME'],
+ "MERGE_REQUEST_IID_#{project_slug.upcase}" => ENV['CI_MERGE_REQUEST_IID'],
"REVIEW_SLUG" => review_slug
}
end
diff --git a/scripts/utils.sh b/scripts/utils.sh
index 55005d0abff..df8a5825dab 100644
--- a/scripts/utils.sh
+++ b/scripts/utils.sh
@@ -1,10 +1,19 @@
function retry() {
+ retry_times_sleep 2 3 "$@"
+}
+
+function retry_times_sleep() {
+ number_of_retries="$1"
+ shift
+ sleep_seconds="$1"
+ shift
+
if eval "$@"; then
return 0
fi
- for i in 2 1; do
- sleep 3s
+ for i in $(seq "${number_of_retries}" -1 1); do
+ sleep "$sleep_seconds"s
echo "[$(date '+%H:%M:%S')] Retrying $i..."
if eval "$@"; then
return 0
@@ -32,6 +41,7 @@ function retry_exponential() {
return 0
fi
done
+
return 1
}
diff --git a/scripts/validate_schema_changes b/scripts/validate_schema_changes
new file mode 100755
index 00000000000..a6a01a060ce
--- /dev/null
+++ b/scripts/validate_schema_changes
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+
+# frozen_string_literal: true
+
+require_relative './database/schema_validator'
+
+SchemaValidator.new.validate!
diff --git a/spec/commands/sidekiq_cluster/cli_spec.rb b/spec/commands/sidekiq_cluster/cli_spec.rb
index 0c32fa2571a..428a0588bdd 100644
--- a/spec/commands/sidekiq_cluster/cli_spec.rb
+++ b/spec/commands/sidekiq_cluster/cli_spec.rb
@@ -1,13 +1,12 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
-require 'rspec-parameterized'
+require 'spec_helper'
require_relative '../../support/stub_settings_source'
require_relative '../../../sidekiq_cluster/cli'
require_relative '../../support/helpers/next_instance_of'
-RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubocop:disable RSpec/FilePath
+RSpec.describe Gitlab::SidekiqCluster::CLI, feature_category: :gitlab_cli, stub_settings_source: true do # rubocop:disable RSpec/FilePath
include NextInstanceOf
let(:cli) { described_class.new('/dev/null') }
diff --git a/spec/config/inject_enterprise_edition_module_spec.rb b/spec/config/inject_enterprise_edition_module_spec.rb
index e8c0905ff89..6689fed02f5 100644
--- a/spec/config/inject_enterprise_edition_module_spec.rb
+++ b/spec/config/inject_enterprise_edition_module_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe InjectEnterpriseEditionModule, feature_category: :not_owned do
+RSpec.describe InjectEnterpriseEditionModule, feature_category: :shared do
let(:extension_name) { 'FF' }
let(:extension_namespace) { Module.new }
let(:fish_name) { 'Fish' }
diff --git a/spec/config/object_store_settings_spec.rb b/spec/config/object_store_settings_spec.rb
index 7b4fa495288..025966c8940 100644
--- a/spec/config/object_store_settings_spec.rb
+++ b/spec/config/object_store_settings_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require Rails.root.join('config', 'object_store_settings.rb')
-RSpec.describe ObjectStoreSettings, feature_category: :not_owned do
+RSpec.describe ObjectStoreSettings, feature_category: :shared do
describe '#parse!' do
let(:settings) { Settingslogic.new(config) }
diff --git a/spec/config/settings_spec.rb b/spec/config/settings_spec.rb
index 0928f2b72ff..b464a4eee8b 100644
--- a/spec/config/settings_spec.rb
+++ b/spec/config/settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Settings, feature_category: :authentication_and_authorization do
+RSpec.describe Settings, feature_category: :system_access do
using RSpec::Parameterized::TableSyntax
describe 'omniauth' do
@@ -198,4 +198,18 @@ RSpec.describe Settings, feature_category: :authentication_and_authorization do
end
end
end
+
+ describe '.build_sidekiq_routing_rules' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:input_rules, :result) do
+ nil | [['*', nil]]
+ [] | [['*', nil]]
+ [['name=foobar', 'foobar']] | [['name=foobar', 'foobar']]
+ end
+
+ with_them do
+ it { expect(described_class.send(:build_sidekiq_routing_rules, input_rules)).to eq(result) }
+ end
+ end
end
diff --git a/spec/config/smime_signature_settings_spec.rb b/spec/config/smime_signature_settings_spec.rb
index 477ad4a74ed..73dca66c666 100644
--- a/spec/config/smime_signature_settings_spec.rb
+++ b/spec/config/smime_signature_settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SmimeSignatureSettings, feature_category: :not_owned do
+RSpec.describe SmimeSignatureSettings, feature_category: :shared do
describe '.parse' do
let(:default_smime_key) { Rails.root.join('.gitlab_smime_key') }
let(:default_smime_cert) { Rails.root.join('.gitlab_smime_cert') }
diff --git a/spec/contracts/provider/helpers/contract_source_helper.rb b/spec/contracts/provider/helpers/contract_source_helper.rb
index f59f228722d..e1891b316f3 100644
--- a/spec/contracts/provider/helpers/contract_source_helper.rb
+++ b/spec/contracts/provider/helpers/contract_source_helper.rb
@@ -2,7 +2,6 @@
module Provider
module ContractSourceHelper
- QA_PACT_BROKER_HOST = "http://localhost:9292/pacts"
PREFIX_PATHS = {
rake: {
ce: "../../contracts/project",
@@ -10,7 +9,7 @@ module Provider
},
spec: "../contracts/project"
}.freeze
- SUB_PATH_REGEX = %r{project/(?<file_path>.*?)_helper.rb}.freeze
+ SUB_PATH_REGEX = %r{project/(?<file_path>.*?)_helper.rb}
class << self
def contract_location(requester:, file_path:, edition: :ce)
@@ -26,7 +25,7 @@ module Provider
provider_url = "provider/#{construct_provider_url_path(file_path)}"
consumer_url = "consumer/#{construct_consumer_url_path(file_path)}"
- "#{QA_PACT_BROKER_HOST}/#{provider_url}/#{consumer_url}/latest"
+ "#{ENV['QA_PACT_BROKER_HOST']}/pacts/#{provider_url}/#{consumer_url}/latest"
end
def construct_provider_url_path(file_path)
diff --git a/spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb b/spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb
index 39537aa153d..18da71e0601 100644
--- a/spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb
+++ b/spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_relative '../../../provider/helpers/contract_source_helper'
-RSpec.describe Provider::ContractSourceHelper, feature_category: :not_owned do
+RSpec.describe Provider::ContractSourceHelper, feature_category: :shared do
let(:pact_helper_path) { 'pact_helpers/project/pipelines/new/post_create_pipeline_helper.rb' }
let(:split_pact_helper_path) { %w[pipelines new post_create_pipeline] }
let(:provider_url_path) { 'POST%20create%20pipeline' }
@@ -54,8 +54,12 @@ RSpec.describe Provider::ContractSourceHelper, feature_category: :not_owned do
end
describe '#pact_broker_url' do
+ before do
+ stub_env('QA_PACT_BROKER_HOST', 'http://localhost')
+ end
+
it 'returns the full url to the contract that the provider test is verifying' do
- contract_url_path = "http://localhost:9292/pacts/provider/" \
+ contract_url_path = "http://localhost/pacts/provider/" \
"#{provider_url_path}/consumer/#{consumer_url_path}/latest"
expect(subject.pact_broker_url(split_pact_helper_path)).to eq(contract_url_path)
diff --git a/spec/contracts/publish-contracts.sh b/spec/contracts/publish-contracts.sh
index 8b9d4b6ecc6..b50ba9afae8 100644
--- a/spec/contracts/publish-contracts.sh
+++ b/spec/contracts/publish-contracts.sh
@@ -1,6 +1,5 @@
LATEST_SHA=$(git rev-parse HEAD)
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
-BROKER_BASE_URL="http://localhost:9292"
cd "${0%/*}" || exit 1
@@ -18,7 +17,7 @@ function publish_contract () {
for contract in $CONTRACTS
do
printf "\e[32mPublishing %s...\033[0m\n" "$contract"
- pact-broker publish "$contract" --consumer-app-version "$LATEST_SHA" --branch "$GIT_BRANCH" --broker-base-url "$BROKER_BASE_URL" --output json
+ pact-broker publish "$contract" --consumer-app-version "$LATEST_SHA" --branch "$GIT_BRANCH" --broker-base-url "$QA_PACT_BROKER_HOST" --output json
done
if [ ${ERROR} = 1 ]; then
diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb
index 32ac0f8dc07..253f66579f3 100644
--- a/spec/controllers/admin/application_settings_controller_spec.rb
+++ b/spec/controllers/admin/application_settings_controller_spec.rb
@@ -400,7 +400,7 @@ RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_set
end
end
- describe 'PUT #reset_registration_token', feature_category: :credential_management do
+ describe 'PUT #reset_registration_token', feature_category: :user_management do
before do
sign_in(admin)
end
diff --git a/spec/controllers/admin/applications_controller_spec.rb b/spec/controllers/admin/applications_controller_spec.rb
index bf7707f177c..edb17aefe86 100644
--- a/spec/controllers/admin/applications_controller_spec.rb
+++ b/spec/controllers/admin/applications_controller_spec.rb
@@ -38,44 +38,43 @@ RSpec.describe Admin::ApplicationsController do
end
end
- describe 'POST #create' do
- context 'with hash_oauth_secrets flag off' do
- before do
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'creates the application' do
- create_params = attributes_for(:application, trusted: true, confidential: false, scopes: ['api'])
-
- expect do
- post :create, params: { doorkeeper_application: create_params }
- end.to change { Doorkeeper::Application.count }.by(1)
+ describe 'PUT #renew' do
+ let(:oauth_params) do
+ {
+ id: application.id
+ }
+ end
- application = Doorkeeper::Application.last
+ subject { put :renew, params: oauth_params }
- expect(response).to redirect_to(admin_application_path(application))
- expect(application).to have_attributes(create_params.except(:uid, :owner_type))
- end
- end
+ it { is_expected.to have_gitlab_http_status(:ok) }
+ it { expect { subject }.to change { application.reload.secret } }
- context 'with hash_oauth_secrets flag on' do
+ context 'when renew fails' do
before do
- stub_feature_flags(hash_oauth_secrets: true)
+ allow_next_found_instance_of(Doorkeeper::Application) do |application|
+ allow(application).to receive(:save).and_return(false)
+ end
end
- it 'creates the application' do
- create_params = attributes_for(:application, trusted: true, confidential: false, scopes: ['api'])
+ it { expect { subject }.not_to change { application.reload.secret } }
+ it { is_expected.to redirect_to(admin_application_url(application)) }
+ end
+ end
- expect do
- post :create, params: { doorkeeper_application: create_params }
- end.to change { Doorkeeper::Application.count }.by(1)
+ describe 'POST #create' do
+ it 'creates the application' do
+ create_params = attributes_for(:application, trusted: true, confidential: false, scopes: ['api'])
- application = Doorkeeper::Application.last
+ expect do
+ post :create, params: { doorkeeper_application: create_params }
+ end.to change { Doorkeeper::Application.count }.by(1)
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template :show
- expect(application).to have_attributes(create_params.except(:uid, :owner_type))
- end
+ application = Doorkeeper::Application.last
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template :show
+ expect(application).to have_attributes(create_params.except(:uid, :owner_type))
end
it 'renders the application form on errors' do
@@ -88,43 +87,18 @@ RSpec.describe Admin::ApplicationsController do
end
context 'when the params are for a confidential application' do
- context 'with hash_oauth_secrets flag off' do
- before do
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'creates a confidential application' do
- create_params = attributes_for(:application, confidential: true, scopes: ['read_user'])
-
- expect do
- post :create, params: { doorkeeper_application: create_params }
- end.to change { Doorkeeper::Application.count }.by(1)
-
- application = Doorkeeper::Application.last
-
- expect(response).to redirect_to(admin_application_path(application))
- expect(application).to have_attributes(create_params.except(:uid, :owner_type))
- end
- end
+ it 'creates a confidential application' do
+ create_params = attributes_for(:application, confidential: true, scopes: ['read_user'])
- context 'with hash_oauth_secrets flag on' do
- before do
- stub_feature_flags(hash_oauth_secrets: true)
- end
-
- it 'creates a confidential application' do
- create_params = attributes_for(:application, confidential: true, scopes: ['read_user'])
-
- expect do
- post :create, params: { doorkeeper_application: create_params }
- end.to change { Doorkeeper::Application.count }.by(1)
+ expect do
+ post :create, params: { doorkeeper_application: create_params }
+ end.to change { Doorkeeper::Application.count }.by(1)
- application = Doorkeeper::Application.last
+ application = Doorkeeper::Application.last
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template :show
- expect(application).to have_attributes(create_params.except(:uid, :owner_type))
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template :show
+ expect(application).to have_attributes(create_params.except(:uid, :owner_type))
end
end
diff --git a/spec/controllers/admin/cohorts_controller_spec.rb b/spec/controllers/admin/cohorts_controller_spec.rb
index 50626a5da91..26f6540258e 100644
--- a/spec/controllers/admin/cohorts_controller_spec.rb
+++ b/spec/controllers/admin/cohorts_controller_spec.rb
@@ -17,7 +17,6 @@ RSpec.describe Admin::CohortsController do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject { get :index }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' }
diff --git a/spec/controllers/admin/dev_ops_report_controller_spec.rb b/spec/controllers/admin/dev_ops_report_controller_spec.rb
index 52a46b5e99a..d8166380760 100644
--- a/spec/controllers/admin/dev_ops_report_controller_spec.rb
+++ b/spec/controllers/admin/dev_ops_report_controller_spec.rb
@@ -32,7 +32,6 @@ RSpec.describe Admin::DevOpsReportController do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject { get :show, format: :html }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' }
diff --git a/spec/controllers/admin/integrations_controller_spec.rb b/spec/controllers/admin/integrations_controller_spec.rb
index e75f27589d7..fed96f6a6c7 100644
--- a/spec/controllers/admin/integrations_controller_spec.rb
+++ b/spec/controllers/admin/integrations_controller_spec.rb
@@ -29,11 +29,7 @@ RSpec.describe Admin::IntegrationsController do
end
end
- context 'when GitLab.com' do
- before do
- allow(::Gitlab).to receive(:com?) { true }
- end
-
+ context 'when GitLab.com', :saas do
it 'returns 404' do
get :edit, params: { id: Integration.available_integration_names.sample }
diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb
index a39a1f38a11..b1a2d90589a 100644
--- a/spec/controllers/admin/runners_controller_spec.rb
+++ b/spec/controllers/admin/runners_controller_spec.rb
@@ -35,26 +35,59 @@ RSpec.describe Admin::RunnersController, feature_category: :runner_fleet do
end
describe '#new' do
- context 'when create_runner_workflow is enabled' do
+ it 'renders a :new template' do
+ get :new
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:new)
+ end
+
+ context 'when create_runner_workflow_for_admin is disabled' do
before do
- stub_feature_flags(create_runner_workflow: true)
+ stub_feature_flags(create_runner_workflow_for_admin: false)
end
- it 'renders a :new template' do
+ it 'returns :not_found' do
get :new
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe '#register' do
+ subject(:register) { get :register, params: { id: new_runner.id } }
+
+ context 'when runner can be registered after creation' do
+ let_it_be(:new_runner) { create(:ci_runner, registration_type: :authenticated_user) }
+
+ it 'renders a :register template' do
+ register
+
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:new)
+ expect(response).to render_template(:register)
end
end
- context 'when create_runner_workflow is disabled' do
+ context 'when runner cannot be registered after creation' do
+ let_it_be(:new_runner) { runner }
+
+ it 'returns :not_found' do
+ register
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when create_runner_workflow_for_admin is disabled' do
+ let_it_be(:new_runner) { create(:ci_runner, registration_type: :authenticated_user) }
+
before do
- stub_feature_flags(create_runner_workflow: false)
+ stub_feature_flags(create_runner_workflow_for_admin: false)
end
it 'returns :not_found' do
- get :new
+ register
expect(response).to have_gitlab_http_status(:not_found)
end
diff --git a/spec/controllers/admin/sessions_controller_spec.rb b/spec/controllers/admin/sessions_controller_spec.rb
index 5fa7a7f278d..07088eed6d4 100644
--- a/spec/controllers/admin/sessions_controller_spec.rb
+++ b/spec/controllers/admin/sessions_controller_spec.rb
@@ -220,7 +220,9 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do
end
end
- shared_examples 'when using two-factor authentication via hardware device' do
+ context 'when using two-factor authentication via WebAuthn' do
+ let(:user) { create(:admin, :two_factor_via_webauthn) }
+
def authenticate_2fa(user_params)
post(:create, params: { user: user_params }, session: { otp_user_id: user.id })
end
@@ -237,10 +239,6 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do
end
it 'can login with valid auth' do
- # we can stub both without an differentiation between webauthn / u2f
- # as these not interfere with each other und this saves us passing aroud
- # parameters
- allow(U2fRegistration).to receive(:authenticate).and_return(true)
allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true)
expect(controller.current_user_mode.admin_mode?).to be(false)
@@ -255,7 +253,6 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do
end
it 'cannot login with invalid auth' do
- allow(U2fRegistration).to receive(:authenticate).and_return(false)
allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(false)
expect(controller.current_user_mode.admin_mode?).to be(false)
@@ -267,22 +264,6 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do
expect(controller.current_user_mode.admin_mode?).to be(false)
end
end
-
- context 'when using two-factor authentication via U2F' do
- it_behaves_like 'when using two-factor authentication via hardware device' do
- let(:user) { create(:admin, :two_factor_via_u2f) }
-
- before do
- stub_feature_flags(webauthn: false)
- end
- end
- end
-
- context 'when using two-factor authentication via WebAuthn' do
- it_behaves_like 'when using two-factor authentication via hardware device' do
- let(:user) { create(:admin, :two_factor_via_webauthn) }
- end
- end
end
end
diff --git a/spec/controllers/admin/spam_logs_controller_spec.rb b/spec/controllers/admin/spam_logs_controller_spec.rb
index 51f7ecdece6..b39c3bd009b 100644
--- a/spec/controllers/admin/spam_logs_controller_spec.rb
+++ b/spec/controllers/admin/spam_logs_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Admin::SpamLogsController do
+RSpec.describe Admin::SpamLogsController, feature_category: :instance_resiliency do
let(:admin) { create(:admin) }
let(:user) { create(:user) }
let!(:first_spam) { create(:spam_log, user: user) }
@@ -13,9 +13,10 @@ RSpec.describe Admin::SpamLogsController do
end
describe '#index' do
- it 'lists all spam logs' do
+ it 'lists paginated spam logs' do
get :index
+ expect(assigns(:spam_logs)).to be_kind_of(Kaminari::PaginatableWithoutCount)
expect(response).to have_gitlab_http_status(:ok)
end
end
@@ -33,10 +34,7 @@ RSpec.describe Admin::SpamLogsController do
end.not_to change { SpamLog.count }
expect(response).to have_gitlab_http_status(:found)
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin)
- ).to be_exists
+ expect(Users::GhostUserMigration.where(user: user, initiator_user: admin)).to be_exists
expect(flash[:notice]).to eq("User #{user.username} was successfully removed.")
end
end
diff --git a/spec/controllers/admin/usage_trends_controller_spec.rb b/spec/controllers/admin/usage_trends_controller_spec.rb
index 87cf8988b4e..7b801d53f14 100644
--- a/spec/controllers/admin/usage_trends_controller_spec.rb
+++ b/spec/controllers/admin/usage_trends_controller_spec.rb
@@ -17,7 +17,6 @@ RSpec.describe Admin::UsageTrendsController do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject { get :index }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' }
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index 63e68118066..ec2559550c3 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -185,22 +185,14 @@ RSpec.describe Admin::UsersController do
delete :destroy, params: { id: user.username }, format: :json
expect(response).to have_gitlab_http_status(:ok)
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin,
- hard_delete: false)
- ).to be_exists
+ expect(Users::GhostUserMigration.where(user: user, initiator_user: admin, hard_delete: false)).to be_exists
end
it 'initiates user removal and passes hard delete option' do
delete :destroy, params: { id: user.username, hard_delete: true }, format: :json
expect(response).to have_gitlab_http_status(:ok)
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin,
- hard_delete: true)
- ).to be_exists
+ expect(Users::GhostUserMigration.where(user: user, initiator_user: admin, hard_delete: true)).to be_exists
end
context 'prerequisites for account deletion' do
@@ -231,11 +223,7 @@ RSpec.describe Admin::UsersController do
expect(response).to redirect_to(admin_users_path)
expect(flash[:notice]).to eq(_('The user is being deleted.'))
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin,
- hard_delete: true)
- ).to be_exists
+ expect(Users::GhostUserMigration.where(user: user, initiator_user: admin, hard_delete: true)).to be_exists
end
end
end
@@ -252,10 +240,7 @@ RSpec.describe Admin::UsersController do
it 'initiates user removal', :sidekiq_inline do
subject
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin)
- ).to be_exists
+ expect(Users::GhostUserMigration.where(user: user, initiator_user: admin)).to be_exists
end
it 'displays the rejection message' do
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index f1adb9020fa..35e374d3b7f 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe ApplicationController do
+RSpec.describe ApplicationController, feature_category: :shared do
include TermsHelper
let(:user) { create(:user) }
@@ -736,23 +736,11 @@ RSpec.describe ApplicationController do
end
end
- context 'user not logged in' do
- it 'sets the default headers' do
- get :index
-
- expect(response.headers['Cache-Control']).to be_nil
- expect(response.headers['Pragma']).to be_nil
- end
- end
-
- context 'user logged in' do
- it 'sets the default headers' do
- sign_in(user)
-
- get :index
+ it 'sets the default headers' do
+ get :index
- expect(response.headers['Pragma']).to eq 'no-cache'
- end
+ expect(response.headers['Cache-Control']).to be_nil
+ expect(response.headers['Pragma']).to be_nil
end
end
@@ -779,7 +767,6 @@ RSpec.describe ApplicationController do
subject
expect(response.headers['Cache-Control']).to eq 'private, no-store'
- expect(response.headers['Pragma']).to eq 'no-cache'
expect(response.headers['Expires']).to eq 'Fri, 01 Jan 1990 00:00:00 GMT'
end
diff --git a/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb b/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb
index 246119a8118..a6a0f2c11b4 100644
--- a/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb
+++ b/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
+
require 'spec_helper'
RSpec.describe Analytics::CycleAnalytics::ValueStreamActions, type: :controller,
-feature_category: :planning_analytics do
+ feature_category: :planning_analytics do
subject(:controller) do
Class.new(ApplicationController) do
include Analytics::CycleAnalytics::ValueStreamActions
diff --git a/spec/controllers/concerns/confirm_email_warning_spec.rb b/spec/controllers/concerns/confirm_email_warning_spec.rb
index 334c156e1ae..fca99d37000 100644
--- a/spec/controllers/concerns/confirm_email_warning_spec.rb
+++ b/spec/controllers/concerns/confirm_email_warning_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe ConfirmEmailWarning do
before do
- stub_feature_flags(soft_email_confirmation: true)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
end
controller(ApplicationController) do
diff --git a/spec/controllers/concerns/content_security_policy_patch_spec.rb b/spec/controllers/concerns/content_security_policy_patch_spec.rb
index 6322950977c..9b4ddb35993 100644
--- a/spec/controllers/concerns/content_security_policy_patch_spec.rb
+++ b/spec/controllers/concerns/content_security_policy_patch_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
# Based on https://github.com/rails/rails/pull/45115/files#diff-35ef6d1bd8b8d3b037ec819a704cd78db55db916a57abfc2859882826fc679b6
-RSpec.describe ContentSecurityPolicyPatch, feature_category: :not_owned do
+RSpec.describe ContentSecurityPolicyPatch, feature_category: :shared do
include Rack::Test::Methods
let(:routes) do
diff --git a/spec/controllers/concerns/continue_params_spec.rb b/spec/controllers/concerns/continue_params_spec.rb
index ba600b8156a..9ac7087430e 100644
--- a/spec/controllers/concerns/continue_params_spec.rb
+++ b/spec/controllers/concerns/continue_params_spec.rb
@@ -31,10 +31,7 @@ RSpec.describe ContinueParams do
it 'cleans up any params that are not allowed' do
allow(controller).to receive(:params) do
- strong_continue_params(to: '/hello',
- notice: 'world',
- notice_now: '!',
- something: 'else')
+ strong_continue_params(to: '/hello', notice: 'world', notice_now: '!', something: 'else')
end
expect(controller.continue_params.keys).to contain_exactly(*%w(to notice notice_now))
diff --git a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb
index a58b83dc42c..fc8b1efd226 100644
--- a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb
+++ b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb
@@ -25,9 +25,7 @@ RSpec.describe ControllerWithCrossProjectAccessCheck do
# `described_class` is not available in this context
include ControllerWithCrossProjectAccessCheck
- requires_cross_project_access :index, show: false,
- unless: -> { unless_condition },
- if: -> { if_condition }
+ requires_cross_project_access :index, show: false, unless: -> { unless_condition }, if: -> { if_condition }
def index
head :ok
@@ -86,9 +84,10 @@ RSpec.describe ControllerWithCrossProjectAccessCheck do
requires_cross_project_access
- skip_cross_project_access_check index: true, show: false,
- unless: -> { unless_condition },
- if: -> { if_condition }
+ skip_cross_project_access_check index: true,
+ show: false,
+ unless: -> { unless_condition },
+ if: -> { if_condition }
def index
head :ok
diff --git a/spec/controllers/concerns/kas_cookie_spec.rb b/spec/controllers/concerns/kas_cookie_spec.rb
new file mode 100644
index 00000000000..e2ca19457ff
--- /dev/null
+++ b/spec/controllers/concerns/kas_cookie_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe KasCookie, feature_category: :kubernetes_management do
+ describe '#set_kas_cookie' do
+ controller(ApplicationController) do
+ include KasCookie
+
+ def index
+ set_kas_cookie
+
+ render json: {}, status: :ok
+ end
+ end
+
+ before do
+ allow(::Gitlab::Kas).to receive(:enabled?).and_return(true)
+ end
+
+ subject(:kas_cookie) do
+ get :index
+
+ request.env['action_dispatch.cookies'][Gitlab::Kas::COOKIE_KEY]
+ end
+
+ context 'when user is signed out' do
+ it { is_expected.to be_blank }
+ end
+
+ context 'when user is signed in' do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'sets the KAS cookie', :aggregate_failures do
+ allow(::Gitlab::Kas::UserAccess).to receive(:cookie_data).and_return('foobar')
+
+ expect(kas_cookie).to be_present
+ expect(kas_cookie).to eq('foobar')
+ expect(::Gitlab::Kas::UserAccess).to have_received(:cookie_data)
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(kas_user_access: false)
+ end
+
+ it { is_expected.to be_blank }
+ end
+ end
+ end
+end
diff --git a/spec/controllers/concerns/product_analytics_tracking_spec.rb b/spec/controllers/concerns/product_analytics_tracking_spec.rb
index 12b4065b89c..b0074b52aa2 100644
--- a/spec/controllers/concerns/product_analytics_tracking_spec.rb
+++ b/spec/controllers/concerns/product_analytics_tracking_spec.rb
@@ -8,7 +8,11 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a
let(:user) { create(:user) }
let(:event_name) { 'an_event' }
+ let(:event_action) { 'an_action' }
+ let(:event_label) { 'a_label' }
+
let!(:group) { create(:group) }
+ let_it_be(:project) { create(:project) }
before do
allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
@@ -19,8 +23,15 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a
include ProductAnalyticsTracking
skip_before_action :authenticate_user!, only: :show
- track_event(:index, :show, name: 'an_event', destinations: [:redis_hll, :snowplow],
- conditions: [:custom_condition_one?, :custom_condition_two?]) { |controller| controller.get_custom_id }
+ track_event(
+ :index,
+ :show,
+ name: 'an_event',
+ action: 'an_action',
+ label: 'a_label',
+ destinations: [:redis_hll, :snowplow],
+ conditions: [:custom_condition_one?, :custom_condition_two?]
+ ) { |controller| controller.get_custom_id }
def index
render html: 'index'
@@ -44,6 +55,10 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a
Group.first
end
+ def tracking_project_source
+ Project.first
+ end
+
def custom_condition_one?
true
end
@@ -64,7 +79,10 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a
expect_snowplow_event(
category: anything,
- action: event_name,
+ action: event_action,
+ property: event_name,
+ label: event_label,
+ project: project,
namespace: group,
user: user,
context: [context]
diff --git a/spec/controllers/concerns/renders_commits_spec.rb b/spec/controllers/concerns/renders_commits_spec.rb
index 6a504681527..45f194b63e7 100644
--- a/spec/controllers/concerns/renders_commits_spec.rb
+++ b/spec/controllers/concerns/renders_commits_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe RendersCommits do
@merge_request = MergeRequest.find(params[:id])
@commits = set_commits_for_rendering(
@merge_request.recent_commits.with_latest_pipeline(@merge_request.source_branch),
- commits_count: @merge_request.commits_count
+ commits_count: @merge_request.commits_count
)
render json: { html: view_to_html_string('projects/merge_requests/_commits') }
diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb
index 6acbff6e745..3fe6d62329e 100644
--- a/spec/controllers/concerns/send_file_upload_spec.rb
+++ b/spec/controllers/concerns/send_file_upload_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe SendFileUpload do
Class.new(GitlabUploader) do
include ObjectStorage::Concern
- storage_options Gitlab.config.uploads
+ storage_location :uploads
private
diff --git a/spec/controllers/concerns/sorting_preference_spec.rb b/spec/controllers/concerns/sorting_preference_spec.rb
index 82a920215ca..6880d83142d 100644
--- a/spec/controllers/concerns/sorting_preference_spec.rb
+++ b/spec/controllers/concerns/sorting_preference_spec.rb
@@ -26,11 +26,14 @@ RSpec.describe SortingPreference do
describe '#set_sort_order' do
let(:group) { build(:group) }
+ let(:controller_name) { 'issues' }
+ let(:action_name) { 'issues' }
let(:issue_weights_available) { true }
before do
allow(controller).to receive(:default_sort_order).and_return('updated_desc')
- allow(controller).to receive(:action_name).and_return('issues')
+ allow(controller).to receive(:controller_name).and_return(controller_name)
+ allow(controller).to receive(:action_name).and_return(action_name)
allow(controller).to receive(:can_sort_by_issue_weight?).and_return(issue_weights_available)
user.user_preference.update!(issues_sort: sorting_field)
end
@@ -62,6 +65,42 @@ RSpec.describe SortingPreference do
end
end
end
+
+ context 'when user preference contains merged date sorting' do
+ let(:sorting_field) { 'merged_at_desc' }
+ let(:can_sort_by_merged_date?) { false }
+
+ before do
+ allow(controller)
+ .to receive(:can_sort_by_merged_date?)
+ .with(can_sort_by_merged_date?)
+ .and_return(can_sort_by_merged_date?)
+ end
+
+ it 'sets default sort order' do
+ is_expected.to eq('updated_desc')
+ end
+
+ shared_examples 'user can sort by merged date' do
+ it 'sets sort order from user_preference' do
+ is_expected.to eq('merged_at_desc')
+ end
+ end
+
+ context 'when controller_name is merge_requests' do
+ let(:controller_name) { 'merge_requests' }
+ let(:can_sort_by_merged_date?) { true }
+
+ it_behaves_like 'user can sort by merged date'
+ end
+
+ context 'when action_name is merge_requests' do
+ let(:action_name) { 'merge_requests' }
+ let(:can_sort_by_merged_date?) { true }
+
+ it_behaves_like 'user can sort by merged date'
+ end
+ end
end
describe '#set_sort_order_from_user_preference' do
diff --git a/spec/controllers/confirmations_controller_spec.rb b/spec/controllers/confirmations_controller_spec.rb
index 773a416dcb4..b1aa40d4d7b 100644
--- a/spec/controllers/confirmations_controller_spec.rb
+++ b/spec/controllers/confirmations_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ConfirmationsController do
+RSpec.describe ConfirmationsController, feature_category: :system_access do
include DeviseHelpers
before do
@@ -58,8 +58,7 @@ RSpec.describe ConfirmationsController do
m.call(*args)
expect(Gitlab::ApplicationContext.current)
- .to include('meta.user' => user.username,
- 'meta.caller_id' => 'ConfirmationsController#show')
+ .to include('meta.user' => user.username, 'meta.caller_id' => 'ConfirmationsController#show')
end
perform_request
@@ -94,8 +93,7 @@ RSpec.describe ConfirmationsController do
m.call(*args)
expect(Gitlab::ApplicationContext.current)
- .to include('meta.user' => user.username,
- 'meta.caller_id' => 'ConfirmationsController#show')
+ .to include('meta.user' => user.username, 'meta.caller_id' => 'ConfirmationsController#show')
end
travel_to(3.days.from_now) { perform_request }
@@ -150,51 +148,71 @@ RSpec.describe ConfirmationsController do
end
end
- context 'when reCAPTCHA is disabled' do
+ context "when `email_confirmation_setting` is set to `soft`" do
before do
- stub_application_setting(recaptcha_enabled: false)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
end
- it 'successfully sends password reset when reCAPTCHA is not solved' do
- perform_request
+ context 'when reCAPTCHA is disabled' do
+ before do
+ stub_application_setting(recaptcha_enabled: false)
+ end
- expect(response).to redirect_to(dashboard_projects_path)
- end
- end
+ it 'successfully sends password reset when reCAPTCHA is not solved' do
+ perform_request
- context 'when reCAPTCHA is enabled' do
- before do
- stub_application_setting(recaptcha_enabled: true)
+ expect(response).to redirect_to(dashboard_projects_path)
+ end
end
- context 'when the reCAPTCHA is not solved' do
+ context 'when reCAPTCHA is enabled' do
before do
- Recaptcha.configuration.skip_verify_env.delete('test')
+ stub_application_setting(recaptcha_enabled: true)
end
- it 'displays an error' do
- perform_request
+ context 'when the reCAPTCHA is not solved' do
+ before do
+ Recaptcha.configuration.skip_verify_env.delete('test')
+ end
- expect(response).to render_template(:new)
- expect(flash[:alert]).to include _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')
+ it 'displays an error' do
+ alert_text = _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')
+
+ perform_request
+
+ expect(response).to render_template(:new)
+ expect(flash[:alert]).to include alert_text
+ end
+
+ it 'sets gon variables' do
+ Gon.clear
+
+ perform_request
+
+ expect(response).to render_template(:new)
+ expect(Gon.all_variables).not_to be_empty
+ end
end
- it 'sets gon variables' do
- Gon.clear
+ it 'successfully sends password reset when reCAPTCHA is solved' do
+ Recaptcha.configuration.skip_verify_env << 'test'
perform_request
- expect(response).to render_template(:new)
- expect(Gon.all_variables).not_to be_empty
+ expect(response).to redirect_to(dashboard_projects_path)
end
end
+ end
- it 'successfully sends password reset when reCAPTCHA is solved' do
- Recaptcha.configuration.skip_verify_env << 'test'
+ context "when `email_confirmation_setting` is not set to `soft`" do
+ before do
+ stub_feature_flags(soft_email_confirmation: false)
+ end
+ it 'redirects to the users_almost_there path' do
perform_request
- expect(response).to redirect_to(dashboard_projects_path)
+ expect(response).to redirect_to(users_almost_there_path)
end
end
end
diff --git a/spec/controllers/dashboard/projects_controller_spec.rb b/spec/controllers/dashboard/projects_controller_spec.rb
index e8ee146a13a..0e4771b20f7 100644
--- a/spec/controllers/dashboard/projects_controller_spec.rb
+++ b/spec/controllers/dashboard/projects_controller_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures, feature_categ
before_all do
project.add_developer(user)
project2.add_developer(user)
+ user.toggle_star(project2)
end
before do
@@ -39,6 +40,21 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures, feature_categ
expect(assigns(:projects)).to eq(projects)
end
+ it 'assigns the correct total_user_projects_count' do
+ get :index
+ total_user_projects_count = assigns(:total_user_projects_count)
+
+ expect(total_user_projects_count.count).to eq(2)
+ end
+
+ it 'assigns the correct total_starred_projects_count' do
+ get :index
+ total_starred_projects_count = assigns(:total_starred_projects_count)
+
+ expect(total_starred_projects_count.count).to eq(1)
+ expect(total_starred_projects_count).to include(project2)
+ end
+
context 'project sorting' do
it_behaves_like 'set sort order from user preference' do
let(:sorting_param) { 'created_asc' }
@@ -62,6 +78,36 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures, feature_categ
end
end
+ context 'with archived project' do
+ let_it_be(:archived_project) do
+ project2.tap { |p| p.update!(archived: true) }
+ end
+
+ it 'does not display archived project' do
+ get :index
+ projects_result = assigns(:projects)
+
+ expect(projects_result).not_to include(archived_project)
+ expect(projects_result).to include(project)
+ end
+
+ it 'excludes archived project from total_user_projects_count' do
+ get :index
+ total_user_projects_count = assigns(:total_user_projects_count)
+
+ expect(total_user_projects_count.count).to eq(1)
+ expect(total_user_projects_count).not_to include(archived_project)
+ end
+
+ it 'excludes archived project from total_starred_projects_count' do
+ get :index
+ total_starred_projects_count = assigns(:total_starred_projects_count)
+
+ expect(total_starred_projects_count.count).to eq(0)
+ expect(total_starred_projects_count).not_to include(archived_project)
+ end
+ end
+
context 'with deleted project' do
let!(:pending_delete_project) do
project.tap { |p| p.update!(pending_delete: true) }
diff --git a/spec/controllers/every_controller_spec.rb b/spec/controllers/every_controller_spec.rb
index 902872b6e92..b76da85ad72 100644
--- a/spec/controllers/every_controller_spec.rb
+++ b/spec/controllers/every_controller_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
+
RSpec.describe "Every controller" do
context "feature categories" do
let_it_be(:feature_categories) do
@@ -52,7 +53,7 @@ RSpec.describe "Every controller" do
non_existing_used_actions = used_actions - existing_actions
expect(non_existing_used_actions).to be_empty,
- "#{controller} used #{non_existing_used_actions} to define feature category, but the route does not exist"
+ "#{controller} used #{non_existing_used_actions} to define feature category, but the route does not exist"
end
end
end
diff --git a/spec/controllers/explore/groups_controller_spec.rb b/spec/controllers/explore/groups_controller_spec.rb
index a3bd8102462..76bd94fd681 100644
--- a/spec/controllers/explore/groups_controller_spec.rb
+++ b/spec/controllers/explore/groups_controller_spec.rb
@@ -41,9 +41,9 @@ RSpec.describe Explore::GroupsController do
it_behaves_like 'explore groups'
- context 'generic_explore_groups flag is disabled' do
+ context 'gitlab.com' do
before do
- stub_feature_flags(generic_explore_groups: false)
+ allow(Gitlab).to receive(:com?).and_return(true)
end
it_behaves_like 'explore groups'
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb
index 7aad67b01e8..cd72dbe394a 100644
--- a/spec/controllers/graphql_controller_spec.rb
+++ b/spec/controllers/graphql_controller_spec.rb
@@ -43,8 +43,9 @@ RSpec.describe GraphqlController, feature_category: :integrations do
post :execute
expect(json_response).to include(
- 'errors' => include(a_hash_including('message' => /Internal server error/,
- 'raisedAt' => /graphql_controller_spec.rb/))
+ 'errors' => include(
+ a_hash_including('message' => /Internal server error/, 'raisedAt' => /graphql_controller_spec.rb/)
+ )
)
end
@@ -108,6 +109,41 @@ RSpec.describe GraphqlController, feature_category: :integrations do
])
end
+ it 'executes a multiplexed queries with variables with no errors' do
+ query = <<~GQL
+ mutation($a: String!, $b: String!) {
+ echoCreate(input: { messages: [$a, $b] }) { echoes }
+ }
+ GQL
+ multiplex = [
+ { query: query, variables: { a: 'A', b: 'B' } },
+ { query: query, variables: { a: 'a', b: 'b' } }
+ ]
+
+ post :execute, params: { _json: multiplex }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq(
+ [
+ { 'data' => { 'echoCreate' => { 'echoes' => %w[A B] } } },
+ { 'data' => { 'echoCreate' => { 'echoes' => %w[a b] } } }
+ ])
+ end
+
+ it 'does not allow string as _json parameter' do
+ post :execute, params: { _json: 'bad' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq({
+ "errors" => [
+ {
+ "message" => "Unexpected end of document",
+ "locations" => []
+ }
+ ]
+ })
+ end
+
it 'sets a limit on the total query size' do
graphql_query = "{#{(['__typename'] * 1000).join(' ')}}"
@@ -172,14 +208,28 @@ RSpec.describe GraphqlController, feature_category: :integrations do
post :execute
end
- it 'calls the track gitlab cli when trackable method' do
- agent = 'GLab - GitLab CLI'
- request.env['HTTP_USER_AGENT'] = agent
+ context 'if using the GitLab CLI' do
+ it 'call trackable for the old UserAgent' do
+ agent = 'GLab - GitLab CLI'
- expect(Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter)
- .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user)
+ request.env['HTTP_USER_AGENT'] = agent
- post :execute
+ expect(Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter)
+ .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user)
+
+ post :execute
+ end
+
+ it 'call trackable for the current UserAgent' do
+ agent = 'glab/v1.25.3-27-g7ec258fb (built 2023-02-16), darwin'
+
+ request.env['HTTP_USER_AGENT'] = agent
+
+ expect(Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter)
+ .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user)
+
+ post :execute
+ end
end
it "assigns username in ApplicationContext" do
diff --git a/spec/controllers/groups/children_controller_spec.rb b/spec/controllers/groups/children_controller_spec.rb
index d0656ee47ce..2e37ed95c1c 100644
--- a/spec/controllers/groups/children_controller_spec.rb
+++ b/spec/controllers/groups/children_controller_spec.rb
@@ -275,6 +275,18 @@ RSpec.describe Groups::ChildrenController, feature_category: :subgroups do
allow(Kaminari.config).to receive(:default_per_page).and_return(per_page)
end
+ it 'rejects negative per_page parameter' do
+ get :index, params: { group_id: group.to_param, per_page: -1 }, format: :json
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'rejects non-numeric per_page parameter' do
+ get :index, params: { group_id: group.to_param, per_page: 'abc' }, format: :json
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
context 'with only projects' do
let!(:other_project) { create(:project, :public, namespace: group) }
let!(:first_page_projects) { create_list(:project, per_page, :public, namespace: group) }
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 f1ca9e11a1a..a59c90a3cf2 100644
--- a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
+++ b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
@@ -249,7 +249,7 @@ RSpec.describe Groups::DependencyProxyForContainersController do
expect(send_data_type).to eq('send-dependency')
expect(header).to eq(
"Authorization" => ["Bearer abcd1234"],
- "Accept" => ::ContainerRegistry::Client::ACCEPTED_TYPES
+ "Accept" => ::DependencyProxy::Manifest::ACCEPTED_TYPES
)
expect(url).to eq(DependencyProxy::Registry.manifest_url(image, tag))
expect(response.headers['Content-Type']).to eq('application/gzip')
diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb
index 4e5dc01f466..35efcb664c0 100644
--- a/spec/controllers/groups/group_members_controller_spec.rb
+++ b/spec/controllers/groups/group_members_controller_spec.rb
@@ -55,6 +55,20 @@ RSpec.describe Groups::GroupMembersController do
expect(assigns(:invited_members).count).to eq(1)
end
+
+ context 'when filtering by user type' do
+ let_it_be(:service_account) { create(:user, :service_account) }
+
+ before do
+ group.add_developer(service_account)
+ end
+
+ it 'returns only service accounts' do
+ get :index, params: { group_id: group, user_type: 'service_account' }
+
+ expect(assigns(:members).map(&:user_id)).to match_array([service_account.id])
+ end
+ end
end
context 'when user cannot manage members' do
@@ -67,6 +81,21 @@ RSpec.describe Groups::GroupMembersController do
expect(assigns(:invited_members)).to be_nil
end
+
+ context 'when filtering by user type' do
+ let_it_be(:service_account) { create(:user, :service_account) }
+
+ before do
+ group.add_developer(user)
+ group.add_developer(service_account)
+ end
+
+ it 'returns only service accounts' do
+ get :index, params: { group_id: group, user_type: 'service_account' }
+
+ expect(assigns(:members).map(&:user_id)).to match_array([user.id, service_account.id])
+ end
+ end
end
context 'when user has owner access to subgroup' do
@@ -489,13 +518,11 @@ RSpec.describe Groups::GroupMembersController do
describe 'PUT #update' do
it 'is successful' do
- put :update,
- params: {
- group_member: { access_level: Gitlab::Access::GUEST },
- group_id: group,
- id: membership
- },
- format: :json
+ put :update, params: {
+ group_member: { access_level: Gitlab::Access::GUEST },
+ group_id: group,
+ id: membership
+ }, format: :json
expect(response).to have_gitlab_http_status(:ok)
end
diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb
index a3c4c47ab15..f4046cb97a0 100644
--- a/spec/controllers/groups/milestones_controller_spec.rb
+++ b/spec/controllers/groups/milestones_controller_spec.rb
@@ -230,11 +230,10 @@ RSpec.describe Groups::MilestonesController do
describe "#create" do
it "creates group milestone with Chinese title" do
- post :create,
- params: {
- group_id: group.to_param,
- milestone: milestone_params
- }
+ post :create, params: {
+ group_id: group.to_param,
+ milestone: milestone_params
+ }
milestone = Milestone.find_by_title(title)
@@ -251,12 +250,11 @@ RSpec.describe Groups::MilestonesController do
it "updates group milestone" do
milestone_params[:title] = "title changed"
- put :update,
- params: {
- id: milestone.iid,
- group_id: group.to_param,
- milestone: milestone_params
- }
+ put :update, params: {
+ id: milestone.iid,
+ group_id: group.to_param,
+ milestone: milestone_params
+ }
milestone.reload
expect(response).to redirect_to(group_milestone_path(group, milestone.iid))
@@ -390,21 +388,19 @@ RSpec.describe Groups::MilestonesController do
context 'for a non-GET request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
- post :create,
- params: {
- group_id: group.to_param,
- milestone: { title: title }
- }
+ post :create, params: {
+ group_id: group.to_param,
+ milestone: { title: title }
+ }
expect(response).not_to have_gitlab_http_status(:not_found)
end
it 'does not redirect to the correct casing' do
- post :create,
- params: {
- group_id: group.to_param,
- milestone: { title: title }
- }
+ post :create, params: {
+ group_id: group.to_param,
+ milestone: { title: title }
+ }
expect(response).not_to have_gitlab_http_status(:moved_permanently)
end
@@ -414,11 +410,10 @@ RSpec.describe Groups::MilestonesController do
let(:redirect_route) { group.redirect_routes.create!(path: 'old-path') }
it 'returns not found' do
- post :create,
- params: {
- group_id: redirect_route.path,
- milestone: { title: title }
- }
+ post :create, params: {
+ group_id: redirect_route.path,
+ milestone: { title: title }
+ }
expect(response).to have_gitlab_http_status(:not_found)
end
diff --git a/spec/controllers/groups/settings/applications_controller_spec.rb b/spec/controllers/groups/settings/applications_controller_spec.rb
index b9457770ed6..2fadac2dc17 100644
--- a/spec/controllers/groups/settings/applications_controller_spec.rb
+++ b/spec/controllers/groups/settings/applications_controller_spec.rb
@@ -71,43 +71,18 @@ RSpec.describe Groups::Settings::ApplicationsController do
group.add_owner(user)
end
- context 'with hash_oauth_secrets flag on' do
- before do
- stub_feature_flags(hash_oauth_secrets: true)
- end
-
- it 'creates the application' do
- create_params = attributes_for(:application, trusted: false, confidential: false, scopes: ['api'])
-
- expect do
- post :create, params: { group_id: group, doorkeeper_application: create_params }
- end.to change { Doorkeeper::Application.count }.by(1)
-
- application = Doorkeeper::Application.last
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template :show
- expect(application).to have_attributes(create_params.except(:uid, :owner_type))
- end
- end
-
- context 'with hash_oauth_secrets flag off' do
- before do
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'creates the application' do
- create_params = attributes_for(:application, trusted: false, confidential: false, scopes: ['api'])
+ it 'creates the application' do
+ create_params = attributes_for(:application, trusted: false, confidential: false, scopes: ['api'])
- expect do
- post :create, params: { group_id: group, doorkeeper_application: create_params }
- end.to change { Doorkeeper::Application.count }.by(1)
+ expect do
+ post :create, params: { group_id: group, doorkeeper_application: create_params }
+ end.to change { Doorkeeper::Application.count }.by(1)
- application = Doorkeeper::Application.last
+ application = Doorkeeper::Application.last
- expect(response).to redirect_to(group_settings_application_path(group, application))
- expect(application).to have_attributes(create_params.except(:uid, :owner_type))
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template :show
+ expect(application).to have_attributes(create_params.except(:uid, :owner_type))
end
it 'renders the application form on errors' do
@@ -120,43 +95,18 @@ RSpec.describe Groups::Settings::ApplicationsController do
end
context 'when the params are for a confidential application' do
- context 'with hash_oauth_secrets flag off' do
- before do
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'creates a confidential application' do
- create_params = attributes_for(:application, confidential: true, scopes: ['read_user'])
-
- expect do
- post :create, params: { group_id: group, doorkeeper_application: create_params }
- end.to change { Doorkeeper::Application.count }.by(1)
-
- application = Doorkeeper::Application.last
-
- expect(response).to redirect_to(group_settings_application_path(group, application))
- expect(application).to have_attributes(create_params.except(:uid, :owner_type))
- end
- end
-
- context 'with hash_oauth_secrets flag on' do
- before do
- stub_feature_flags(hash_oauth_secrets: true)
- end
-
- it 'creates a confidential application' do
- create_params = attributes_for(:application, confidential: true, scopes: ['read_user'])
+ it 'creates a confidential application' do
+ create_params = attributes_for(:application, confidential: true, scopes: ['read_user'])
- expect do
- post :create, params: { group_id: group, doorkeeper_application: create_params }
- end.to change { Doorkeeper::Application.count }.by(1)
+ expect do
+ post :create, params: { group_id: group, doorkeeper_application: create_params }
+ end.to change { Doorkeeper::Application.count }.by(1)
- application = Doorkeeper::Application.last
+ application = Doorkeeper::Application.last
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template :show
- expect(application).to have_attributes(create_params.except(:uid, :owner_type))
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template :show
+ expect(application).to have_attributes(create_params.except(:uid, :owner_type))
end
end
@@ -188,6 +138,55 @@ RSpec.describe Groups::Settings::ApplicationsController do
end
end
+ describe 'PUT #renew' do
+ context 'when user is owner' do
+ before do
+ group.add_owner(user)
+ end
+
+ let(:oauth_params) do
+ {
+ group_id: group,
+ id: application.id
+ }
+ end
+
+ subject { put :renew, params: oauth_params }
+
+ it { is_expected.to have_gitlab_http_status(:ok) }
+ it { expect { subject }.to change { application.reload.secret } }
+
+ context 'when renew fails' do
+ before do
+ allow_next_found_instance_of(Doorkeeper::Application) do |application|
+ allow(application).to receive(:save).and_return(false)
+ end
+ end
+
+ it { expect { subject }.not_to change { application.reload.secret } }
+ it { is_expected.to redirect_to(group_settings_application_url(group, application)) }
+ end
+ end
+
+ context 'when user is not owner' do
+ before do
+ group.add_maintainer(user)
+ end
+
+ let(:oauth_params) do
+ {
+ group_id: group,
+ id: application.id
+ }
+ end
+
+ it 'renders a 404' do
+ put :renew, params: oauth_params
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
describe 'PATCH #update' do
context 'when user is owner' do
before do
diff --git a/spec/controllers/groups/variables_controller_spec.rb b/spec/controllers/groups/variables_controller_spec.rb
index 6dbe75bb1df..8c6efae89c3 100644
--- a/spec/controllers/groups/variables_controller_spec.rb
+++ b/spec/controllers/groups/variables_controller_spec.rb
@@ -77,12 +77,10 @@ RSpec.describe Groups::VariablesController do
describe 'PATCH #update' do
it 'is successful' do
- patch :update,
- params: {
- group_id: group,
- variables_attributes: [{ id: variable.id, key: 'hello' }]
- },
- format: :json
+ patch :update, params: {
+ group_id: group,
+ variables_attributes: [{ id: variable.id, key: 'hello' }]
+ }, format: :json
expect(response).to have_gitlab_http_status(:ok)
end
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
index 2375146f346..ac6715bacd5 100644
--- a/spec/controllers/help_controller_spec.rb
+++ b/spec/controllers/help_controller_spec.rb
@@ -261,11 +261,7 @@ RSpec.describe HelpController do
context 'for image formats' do
context 'when requested file exists' do
it 'renders the raw file' do
- get :show,
- params: {
- path: 'user/img/markdown_logo'
- },
- format: :png
+ get :show, params: { path: 'user/img/markdown_logo' }, format: :png
aggregate_failures do
expect(response).to be_successful
@@ -277,11 +273,7 @@ RSpec.describe HelpController do
context 'when requested file is missing' do
it 'renders not found' do
- get :show,
- params: {
- path: 'foo/bar'
- },
- format: :png
+ get :show, params: { path: 'foo/bar' }, format: :png
expect(response).to be_not_found
end
end
@@ -289,11 +281,7 @@ RSpec.describe HelpController do
context 'for other formats' do
it 'always renders not found' do
- get :show,
- params: {
- path: 'user/ssh'
- },
- format: :foo
+ get :show, params: { path: 'user/ssh' }, format: :foo
expect(response).to be_not_found
end
end
diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb
index 35f712dc50d..055c98ebdbc 100644
--- a/spec/controllers/import/bitbucket_controller_spec.rb
+++ b/spec/controllers/import/bitbucket_controller_spec.rb
@@ -48,11 +48,13 @@ RSpec.describe Import::BitbucketController do
let(:expires_at) { Time.current + 1.day }
let(:expires_in) { 1.day }
let(:access_token) do
- double(token: token,
- secret: secret,
- expires_at: expires_at,
- expires_in: expires_in,
- refresh_token: refresh_token)
+ double(
+ token: token,
+ secret: secret,
+ expires_at: expires_at,
+ expires_in: expires_in,
+ refresh_token: refresh_token
+ )
end
before do
@@ -63,10 +65,10 @@ RSpec.describe Import::BitbucketController do
allow_any_instance_of(OAuth2::Client)
.to receive(:get_token)
.with(hash_including(
- 'grant_type' => 'authorization_code',
- 'code' => code,
- 'redirect_uri' => users_import_bitbucket_callback_url),
- {})
+ 'grant_type' => 'authorization_code',
+ 'code' => code,
+ 'redirect_uri' => users_import_bitbucket_callback_url),
+ {})
.and_return(access_token)
stub_omniauth_provider('bitbucket')
diff --git a/spec/controllers/import/bulk_imports_controller_spec.rb b/spec/controllers/import/bulk_imports_controller_spec.rb
index a3992ae850e..4e7f9572f65 100644
--- a/spec/controllers/import/bulk_imports_controller_spec.rb
+++ b/spec/controllers/import/bulk_imports_controller_spec.rb
@@ -121,12 +121,12 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do
params = { page: 1, per_page: 20, filter: '' }.merge(params_override)
get :status,
- params: params,
- format: format,
- session: {
- bulk_import_gitlab_url: 'https://gitlab.example.com',
- bulk_import_gitlab_access_token: 'demo-pat'
- }
+ params: params,
+ format: format,
+ session: {
+ bulk_import_gitlab_url: 'https://gitlab.example.com',
+ bulk_import_gitlab_access_token: 'demo-pat'
+ }
end
include_context 'bulk imports requests context', 'https://gitlab.example.com'
@@ -157,8 +157,7 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do
end
let(:source_version) do
- Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION,
- ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT)
+ Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT)
end
before do
@@ -270,8 +269,7 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do
context 'when connection error occurs' do
let(:source_version) do
- Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION,
- ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT)
+ Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT)
end
before do
diff --git a/spec/controllers/import/fogbugz_controller_spec.rb b/spec/controllers/import/fogbugz_controller_spec.rb
index ed2a588eadf..e2d59fc213a 100644
--- a/spec/controllers/import/fogbugz_controller_spec.rb
+++ b/spec/controllers/import/fogbugz_controller_spec.rb
@@ -116,8 +116,7 @@ RSpec.describe Import::FogbugzController do
describe 'GET status' do
let(:repo) do
- instance_double(Gitlab::FogbugzImport::Repository,
- id: 'demo', name: 'vim', safe_name: 'vim', path: 'vim')
+ instance_double(Gitlab::FogbugzImport::Repository, id: 'demo', name: 'vim', safe_name: 'vim', path: 'vim')
end
it 'redirects to new page form when client is invalid' do
diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb
index 406a3604b23..4928cc46d7f 100644
--- a/spec/controllers/import/github_controller_spec.rb
+++ b/spec/controllers/import/github_controller_spec.rb
@@ -139,7 +139,7 @@ RSpec.describe Import::GithubController, feature_category: :importers do
expect_next_instance_of(Gitlab::GithubImport::Clients::Proxy) do |client|
expect(client).to receive(:repos)
.with(expected_filter, expected_options)
- .and_return({ repos: [], page_info: {} })
+ .and_return({ repos: [], page_info: {}, count: 0 })
end
get :status, params: params, format: :json
@@ -149,6 +149,7 @@ RSpec.describe Import::GithubController, feature_category: :importers do
expect(json_response['provider_repos'].size).to eq 0
expect(json_response['incompatible_repos'].size).to eq 0
expect(json_response['page_info']).to eq({})
+ expect(json_response['provider_repo_count']).to eq(0)
end
end
@@ -161,9 +162,7 @@ RSpec.describe Import::GithubController, feature_category: :importers do
let(:provider_repos) { [] }
let(:expected_filter) { '' }
let(:expected_options) do
- pagination_params.merge(relation_params).merge(
- first: 25, page: 1, per_page: 25
- )
+ pagination_params.merge(relation_params).merge(first: 25)
end
before do
@@ -171,6 +170,9 @@ RSpec.describe Import::GithubController, feature_category: :importers do
if client_auth_success
allow(proxy).to receive(:repos).and_return({ repos: provider_repos })
allow(proxy).to receive(:client).and_return(client_stub)
+ allow_next_instance_of(Gitlab::GithubImport::ProjectRelationType) do |instance|
+ allow(instance).to receive(:for).with('example/repo').and_return('owned')
+ end
else
allow(proxy).to receive(:repos).and_raise(Octokit::Unauthorized)
end
@@ -279,22 +281,12 @@ RSpec.describe Import::GithubController, feature_category: :importers do
it_behaves_like 'calls repos through Clients::Proxy with expected args'
end
-
- context 'when page is specified' do
- let(:pagination_params) { { before: nil, after: nil, page: 2 } }
- let(:params) { pagination_params }
- let(:expected_options) do
- pagination_params.merge(relation_params).merge(first: 25, page: 2, per_page: 25)
- end
-
- it_behaves_like 'calls repos through Clients::Proxy with expected args'
- end
end
context 'when relation type params present' do
let(:organization_login) { 'test-login' }
let(:params) { pagination_params.merge(relation_type: 'organization', organization_login: organization_login) }
- let(:pagination_defaults) { { first: 25, page: 1, per_page: 25 } }
+ let(:pagination_defaults) { { first: 25 } }
let(:expected_options) do
pagination_defaults.merge(pagination_params).merge(
relation_type: 'organization', organization_login: organization_login
@@ -359,7 +351,13 @@ RSpec.describe Import::GithubController, feature_category: :importers do
end
end
- describe "POST create" do
+ describe "POST create", :clean_gitlab_redis_cache do
+ before do
+ allow_next_instance_of(Gitlab::GithubImport::ProjectRelationType) do |instance|
+ allow(instance).to receive(:for).with("#{provider_username}/vim").and_return('owned')
+ end
+ end
+
it_behaves_like 'a GitHub-ish import controller: POST create'
it_behaves_like 'project import rate limiter'
@@ -388,13 +386,22 @@ RSpec.describe Import::GithubController, feature_category: :importers do
end
describe "POST cancel" do
- let_it_be(:project) { create(:project, :import_started, import_type: 'github', import_url: 'https://fake.url') }
+ let_it_be(:project) do
+ create(
+ :project, :import_started,
+ import_type: 'github', import_url: 'https://fake.url', import_source: 'login/repo'
+ )
+ end
context 'when project import was canceled' do
before do
allow(Import::Github::CancelProjectImportService)
.to receive(:new).with(project, user)
.and_return(double(execute: { status: :success, project: project }))
+
+ allow_next_instance_of(Gitlab::GithubImport::ProjectRelationType) do |instance|
+ allow(instance).to receive(:for).with('login/repo').and_return('owned')
+ end
end
it 'returns success' do
@@ -471,4 +478,26 @@ RSpec.describe Import::GithubController, feature_category: :importers do
end
end
end
+
+ describe 'GET counts' do
+ let(:expected_result) do
+ {
+ 'owned' => 3,
+ 'collaborated' => 2,
+ 'organization' => 1
+ }
+ end
+
+ it 'returns repos count by type' do
+ expect_next_instance_of(Gitlab::GithubImport::Clients::Proxy) do |client_proxy|
+ expect(client_proxy).to receive(:count_repos_by).with('owned', user.id).and_return(3)
+ expect(client_proxy).to receive(:count_repos_by).with('collaborated', user.id).and_return(2)
+ expect(client_proxy).to receive(:count_repos_by).with('organization', user.id).and_return(1)
+ end
+
+ get :counts
+
+ expect(json_response).to eq(expected_result)
+ end
+ end
end
diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb
index 9b16dc9a463..e7ec268a5a2 100644
--- a/spec/controllers/oauth/applications_controller_spec.rb
+++ b/spec/controllers/oauth/applications_controller_spec.rb
@@ -71,6 +71,33 @@ RSpec.describe Oauth::ApplicationsController do
it_behaves_like 'redirects to 2fa setup page when the user requires it'
end
+ describe 'PUT #renew' do
+ let(:oauth_params) do
+ {
+ id: application.id
+ }
+ end
+
+ subject { put :renew, params: oauth_params }
+
+ it { is_expected.to have_gitlab_http_status(:ok) }
+ it { expect { subject }.to change { application.reload.secret } }
+
+ 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'
+
+ context 'when renew fails' do
+ before do
+ allow_next_found_instance_of(Doorkeeper::Application) do |application|
+ allow(application).to receive(:save).and_return(false)
+ end
+ end
+
+ it { expect { subject }.not_to change { application.reload.secret } }
+ it { is_expected.to redirect_to(oauth_application_url(application)) }
+ end
+ end
+
describe 'GET #show' do
subject { get :show, params: { id: application.id } }
@@ -113,30 +140,11 @@ RSpec.describe Oauth::ApplicationsController do
subject { post :create, params: oauth_params }
- context 'when hash_oauth_tokens flag set' do
- before do
- stub_feature_flags(hash_oauth_secrets: true)
- end
-
- it 'creates an application' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template :show
- end
- end
-
- context 'when hash_oauth_tokens flag not set' do
- before do
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'creates an application' do
- subject
+ it 'creates an application' do
+ subject
- expect(response).to have_gitlab_http_status(:found)
- expect(response).to redirect_to(oauth_application_path(Doorkeeper::Application.last))
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template :show
end
it 'redirects back to profile page if OAuth applications are disabled' do
diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb
index 5185aa64d9f..3476c7b8465 100644
--- a/spec/controllers/oauth/authorizations_controller_spec.rb
+++ b/spec/controllers/oauth/authorizations_controller_spec.rb
@@ -7,8 +7,7 @@ RSpec.describe Oauth::AuthorizationsController do
let(:application_scopes) { 'api read_user' }
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')
end
let(:params) do
diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb
index ab3f3fd397d..ebfa48870a9 100644
--- a/spec/controllers/omniauth_callbacks_controller_spec.rb
+++ b/spec/controllers/omniauth_callbacks_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe OmniauthCallbacksController, type: :controller do
+RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: :system_access do
include LoginHelpers
describe 'omniauth' do
@@ -202,20 +202,30 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
end
end
- context 'when user with 2FA is unconfirmed' do
+ context 'when a user has 2FA enabled' do
render_views
let(:user) { create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider) }
- before do
- user.update_column(:confirmed_at, nil)
- end
+ context 'when a user is unconfirmed' do
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'hard')
- it 'redirects to login page' do
- post provider
+ user.update!(confirmed_at: nil)
+ end
+
+ it 'redirects to login page' do
+ post provider
+
+ expect(response).to redirect_to(new_user_session_path)
+ expect(flash[:alert]).to match(/You have to confirm your email address before continuing./)
+ end
+ end
- expect(response).to redirect_to(new_user_session_path)
- expect(flash[:alert]).to match(/You have to confirm your email address before continuing./)
+ context 'when a user is confirmed' do
+ it 'returns 200 response' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
end
end
@@ -324,9 +334,10 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
expect(controller).to receive(:atlassian_oauth2).and_wrap_original do |m, *args|
m.call(*args)
- expect(Gitlab::ApplicationContext.current)
- .to include('meta.user' => user.username,
- 'meta.caller_id' => 'OmniauthCallbacksController#atlassian_oauth2')
+ expect(Gitlab::ApplicationContext.current).to include(
+ 'meta.user' => user.username,
+ 'meta.caller_id' => 'OmniauthCallbacksController#atlassian_oauth2'
+ )
end
post :atlassian_oauth2
@@ -419,6 +430,31 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
end
end
+ describe '#openid_connect' do
+ let(:user) { create(:omniauth_user, extern_uid: extern_uid, provider: provider) }
+ let(:extern_uid) { 'my-uid' }
+ let(:provider) { 'openid_connect' }
+
+ before do
+ prepare_provider_route('openid_connect')
+
+ mock_auth_hash(provider, extern_uid, user.email, additional_info: {})
+
+ request.env['devise.mapping'] = Devise.mappings[:user]
+ request.env['omniauth.auth'] = Rails.application.env_config['omniauth.auth']
+ end
+
+ it_behaves_like 'known sign in' do
+ let(:post_action) { post provider }
+ end
+
+ it 'allows sign in' do
+ post provider
+
+ expect(request.env['warden']).to be_authenticated
+ end
+ end
+
describe '#saml' do
let(:last_request_id) { 'ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685' }
let(:user) { create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml') }
@@ -431,8 +467,12 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
before do
stub_last_request_id(last_request_id)
- stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'],
- providers: [saml_config])
+ stub_omniauth_saml_config(
+ enabled: true,
+ auto_link_saml_user: true,
+ allow_single_sign_on: ['saml'],
+ providers: [saml_config]
+ )
mock_auth_hash_with_saml_xml('saml', +'my-uid', user.email, mock_saml_response)
request.env['devise.mapping'] = Devise.mappings[:user]
request.env['omniauth.auth'] = Rails.application.env_config['omniauth.auth']
@@ -523,9 +563,10 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
expect(controller).to receive(:saml).and_wrap_original do |m, *args|
m.call(*args)
- expect(Gitlab::ApplicationContext.current)
- .to include('meta.user' => user.username,
- 'meta.caller_id' => 'OmniauthCallbacksController#saml')
+ expect(Gitlab::ApplicationContext.current).to include(
+ 'meta.user' => user.username,
+ 'meta.caller_id' => 'OmniauthCallbacksController#saml'
+ )
end
post :saml, params: { SAMLResponse: mock_saml_response }
diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb
index 9494f55c631..aad946acad4 100644
--- a/spec/controllers/passwords_controller_spec.rb
+++ b/spec/controllers/passwords_controller_spec.rb
@@ -99,8 +99,7 @@ RSpec.describe PasswordsController do
m.call(*args)
expect(Gitlab::ApplicationContext.current)
- .to include('meta.user' => user.username,
- 'meta.caller_id' => 'PasswordsController#update')
+ .to include('meta.user' => user.username, 'meta.caller_id' => 'PasswordsController#update')
end
subject
diff --git a/spec/controllers/profiles/two_factor_auths_controller_spec.rb b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
index 7d7cdededdb..dde0af3c543 100644
--- a/spec/controllers/profiles/two_factor_auths_controller_spec.rb
+++ b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Profiles::TwoFactorAuthsController, feature_category: :authentication_and_authorization do
+RSpec.describe Profiles::TwoFactorAuthsController, feature_category: :system_access do
before do
# `user` should be defined within the action-specific describe blocks
sign_in(user)
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
index daf0f36c28b..b1c43a33386 100644
--- a/spec/controllers/profiles_controller_spec.rb
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -11,8 +11,7 @@ RSpec.describe ProfilesController, :request_store do
sign_in(user)
new_password = User.random_password
expect do
- post :update,
- params: { user: { password: new_password, password_confirmation: new_password } }
+ post :update, params: { user: { password: new_password, password_confirmation: new_password } }
end.not_to change { user.reload.encrypted_password }
expect(response).to have_gitlab_http_status(:found)
@@ -23,8 +22,7 @@ RSpec.describe ProfilesController, :request_store do
it 'allows an email update from a user without an external email address' do
sign_in(user)
- put :update,
- params: { user: { email: "john@gmail.com", name: "John", validation_password: password } }
+ put :update, params: { user: { email: "john@gmail.com", name: "John", validation_password: password } }
user.reload
@@ -37,8 +35,7 @@ RSpec.describe ProfilesController, :request_store do
create(:email, :confirmed, user: user, email: 'john@gmail.com')
sign_in(user)
- put :update,
- params: { user: { email: "john@gmail.com", name: "John" } }
+ put :update, params: { user: { email: "john@gmail.com", name: "John" } }
user.reload
@@ -54,8 +51,7 @@ RSpec.describe ProfilesController, :request_store do
ldap_user.create_user_synced_attributes_metadata(provider: 'ldap', name_synced: true, email_synced: true)
sign_in(ldap_user)
- put :update,
- params: { user: { email: "john@gmail.com", name: "John" } }
+ put :update, params: { user: { email: "john@gmail.com", name: "John" } }
ldap_user.reload
@@ -71,8 +67,7 @@ RSpec.describe ProfilesController, :request_store do
ldap_user.create_user_synced_attributes_metadata(provider: 'ldap', name_synced: true, email_synced: true, location_synced: false)
sign_in(ldap_user)
- put :update,
- params: { user: { email: "john@gmail.com", name: "John", location: "City, Country" } }
+ put :update, params: { user: { email: "john@gmail.com", name: "John", location: "City, Country" } }
ldap_user.reload
@@ -85,10 +80,7 @@ RSpec.describe ProfilesController, :request_store do
it 'allows setting a user status', :freeze_time do
sign_in(user)
- put(
- :update,
- params: { user: { status: { message: 'Working hard!', availability: 'busy', clear_status_after: '8_hours' } } }
- )
+ put :update, params: { user: { status: { message: 'Working hard!', availability: 'busy', clear_status_after: '8_hours' } } }
expect(user.reload.status.message).to eq('Working hard!')
expect(user.reload.status.availability).to eq('busy')
@@ -183,22 +175,14 @@ RSpec.describe ProfilesController, :request_store do
end
it 'updates a username using JSON request' do
- put :update_username,
- params: {
- user: { username: new_username }
- },
- format: :json
+ put :update_username, params: { user: { username: new_username } }, format: :json
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['message']).to eq(s_('Profiles|Username successfully changed'))
end
it 'renders an error message when the username was not updated' do
- put :update_username,
- params: {
- user: { username: 'invalid username.git' }
- },
- format: :json
+ put :update_username, params: { user: { username: 'invalid username.git' } }, format: :json
expect(response).to have_gitlab_http_status(:unprocessable_entity)
expect(json_response['message']).to match(/Username change failed/)
diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb
index c707b5dc39d..c91aa562a85 100644
--- a/spec/controllers/projects/artifacts_controller_spec.rb
+++ b/spec/controllers/projects/artifacts_controller_spec.rb
@@ -9,11 +9,13 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts
let_it_be(:project) { create(:project, :repository, :public) }
let_it_be(:pipeline, reload: true) do
- create(:ci_pipeline,
- project: project,
- sha: project.commit.sha,
- ref: project.default_branch,
- status: 'success')
+ create(
+ :ci_pipeline,
+ project: project,
+ sha: project.commit.sha,
+ ref: project.default_branch,
+ status: 'success'
+ )
end
let!(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
@@ -177,9 +179,10 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts
end
it 'sends the codequality report' do
- expect(controller).to receive(:send_file)
- .with(job.job_artifacts_codequality.file.path,
- hash_including(disposition: 'attachment', filename: filename)).and_call_original
+ expect(controller).to receive(:send_file).with(
+ job.job_artifacts_codequality.file.path,
+ hash_including(disposition: 'attachment', filename: filename)
+ ).and_call_original
download_artifact(file_type: file_type)
@@ -557,8 +560,7 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts
context 'with regular branch' do
before do
- pipeline.update!(ref: 'master',
- sha: project.commit('master').sha)
+ pipeline.update!(ref: 'master', sha: project.commit('master').sha)
get :latest_succeeded, params: params_from_ref('master')
end
@@ -568,8 +570,7 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts
context 'with branch name containing slash' do
before do
- pipeline.update!(ref: 'improve/awesome',
- sha: project.commit('improve/awesome').sha)
+ pipeline.update!(ref: 'improve/awesome', sha: project.commit('improve/awesome').sha)
get :latest_succeeded, params: params_from_ref('improve/awesome')
end
@@ -579,8 +580,7 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts
context 'with branch name and path containing slashes' do
before do
- pipeline.update!(ref: 'improve/awesome',
- sha: project.commit('improve/awesome').sha)
+ pipeline.update!(ref: 'improve/awesome', sha: project.commit('improve/awesome').sha)
get :latest_succeeded, params: params_from_ref('improve/awesome', job.name, 'file/README.md')
end
@@ -596,11 +596,13 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts
before do
create_file_in_repo(project, 'master', 'master', 'test.txt', 'This is test')
- create(:ci_pipeline,
+ create(
+ :ci_pipeline,
project: project,
sha: project.commit.sha,
ref: project.default_branch,
- status: 'failed')
+ status: 'failed'
+ )
get :latest_succeeded, params: params_from_ref(project.default_branch)
end
diff --git a/spec/controllers/projects/badges_controller_spec.rb b/spec/controllers/projects/badges_controller_spec.rb
index d41e8d6169f..ef2afd7ca38 100644
--- a/spec/controllers/projects/badges_controller_spec.rb
+++ b/spec/controllers/projects/badges_controller_spec.rb
@@ -98,6 +98,16 @@ RSpec.describe Projects::BadgesController do
expect(response.body).to include('123')
end
end
+
+ if badge_type == :release
+ context 'when value_width param is used' do
+ it 'sets custom value width' do
+ get_badge(badge_type, value_width: '123')
+
+ expect(response.body).to include('123')
+ end
+ end
+ end
end
shared_examples 'a badge resource' do |badge_type|
@@ -186,7 +196,7 @@ RSpec.describe Projects::BadgesController do
namespace_id: project.namespace.to_param,
project_id: project,
ref: pipeline.ref
- }.merge(args.slice(:style, :key_text, :key_width, :ignore_skipped))
+ }.merge(args.slice(:style, :key_text, :key_width, :value_width, :ignore_skipped))
get badge, params: params, format: :svg
end
diff --git a/spec/controllers/projects/blame_controller_spec.rb b/spec/controllers/projects/blame_controller_spec.rb
index 62a544bb3fc..f322c78b5e3 100644
--- a/spec/controllers/projects/blame_controller_spec.rb
+++ b/spec/controllers/projects/blame_controller_spec.rb
@@ -17,12 +17,7 @@ RSpec.describe Projects::BlameController do
render_views
before do
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id
- })
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: id }
end
context "valid branch, valid file" do
@@ -35,8 +30,7 @@ RSpec.describe Projects::BlameController do
let(:id) { 'master/files/ruby/invalid-path.rb' }
it 'redirects' do
- expect(subject)
- .to redirect_to("/#{project.full_path}/-/tree/master")
+ expect(subject).to redirect_to("/#{project.full_path}/-/tree/master")
end
end
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index 887a5ba598f..c091badd09d 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -75,13 +75,7 @@ RSpec.describe Projects::BlobController do
let(:id) { 'master/README.md' }
before do
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id
- },
- format: :json)
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: id }, format: :json
end
it do
@@ -95,14 +89,7 @@ RSpec.describe Projects::BlobController do
let(:id) { 'master/README.md' }
before do
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id,
- viewer: 'none'
- },
- format: :json)
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: id, viewer: 'none' }, format: :json
end
it do
@@ -115,12 +102,8 @@ RSpec.describe Projects::BlobController do
context 'with tree path' do
before do
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id
- })
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: id }
+
controller.instance_variable_set(:@blob, nil)
end
@@ -362,11 +345,23 @@ RSpec.describe Projects::BlobController do
end
end
- it_behaves_like 'tracking unique hll events' do
+ context 'events tracking' do
+ let(:target_event) { 'g_edit_by_sfe' }
+
subject(:request) { put :update, params: default_params }
- let(:target_event) { 'g_edit_by_sfe' }
- let(:expected_value) { instance_of(Integer) }
+ it_behaves_like 'tracking unique hll events' do
+ let(:expected_value) { instance_of(Integer) }
+ end
+
+ it_behaves_like 'Snowplow event tracking with RedisHLL context' do
+ let(:action) { 'perform_sfe_action' }
+ let(:category) { described_class.to_s }
+ let(:namespace) { project.namespace.reload }
+ let(:property) { target_event }
+ let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_sfe_edit' }
+ let(:feature_flag_name) { 'route_hll_to_snowplow_phase4' }
+ end
end
end
@@ -494,6 +489,7 @@ RSpec.describe Projects::BlobController do
describe 'POST create' do
let(:user) { create(:user) }
+ let(:target_event) { 'g_edit_by_sfe' }
let(:default_params) do
{
namespace_id: project.namespace,
@@ -515,10 +511,18 @@ RSpec.describe Projects::BlobController do
subject(:request) { post :create, params: default_params }
it_behaves_like 'tracking unique hll events' do
- let(:target_event) { 'g_edit_by_sfe' }
let(:expected_value) { instance_of(Integer) }
end
+ it_behaves_like 'Snowplow event tracking with RedisHLL context' do
+ let(:action) { 'perform_sfe_action' }
+ let(:category) { described_class.to_s }
+ let(:namespace) { project.namespace }
+ let(:property) { target_event }
+ let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_sfe_edit' }
+ let(:feature_flag_name) { 'route_hll_to_snowplow_phase4' }
+ end
+
it 'redirects to blob' do
request
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index dcde22c1fd6..600f8047a1d 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -22,13 +22,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
before do
sign_in(developer)
- post :create,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- branch_name: branch,
- ref: ref
- }
+ post :create, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ branch_name: branch,
+ ref: ref
+ }
end
context "valid branch name, valid source" do
@@ -83,13 +82,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
end
it 'redirects' do
- post :create,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- branch_name: branch,
- issue_iid: issue.iid
- }
+ post :create, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ branch_name: branch,
+ issue_iid: issue.iid
+ }
expect(subject)
.to redirect_to("/#{project.full_path}/-/tree/1-feature-branch")
@@ -98,13 +96,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
it 'posts a system note' do
expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, developer, "1-feature-branch", branch_project: project)
- post :create,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- branch_name: branch,
- issue_iid: issue.iid
- }
+ post :create, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ branch_name: branch,
+ issue_iid: issue.iid
+ }
end
context 'confidential_issue_project_id is present' do
@@ -167,13 +164,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result)
expect(SystemNoteService).to receive(:new_issue_branch).and_return(true)
- post :create,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project.to_param,
- branch_name: branch,
- issue_iid: issue.iid
- }
+ post :create, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ branch_name: branch,
+ issue_iid: issue.iid
+ }
expect(response).to redirect_to project_tree_path(project, branch)
end
@@ -189,13 +185,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result)
expect(SystemNoteService).to receive(:new_issue_branch).and_return(true)
- post :create,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project.to_param,
- branch_name: branch,
- issue_iid: issue.iid
- }
+ post :create, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ branch_name: branch,
+ issue_iid: issue.iid
+ }
expect(response.location).to include(project_new_blob_path(project, branch))
expect(response).to have_gitlab_http_status(:found)
@@ -210,13 +205,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result)
expect(SystemNoteService).to receive(:new_issue_branch).and_return(true)
- post :create,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project.to_param,
- branch_name: branch,
- issue_iid: issue.iid
- }
+ post :create, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ branch_name: branch,
+ issue_iid: issue.iid
+ }
expect(response.location).to include(project_new_blob_path(project, branch))
expect(response).to have_gitlab_http_status(:found)
@@ -229,13 +223,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
it "doesn't post a system note" do
expect(SystemNoteService).not_to receive(:new_issue_branch)
- post :create,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- branch_name: branch,
- issue_iid: issue.iid
- }
+ post :create, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ branch_name: branch,
+ issue_iid: issue.iid
+ }
end
end
@@ -249,13 +242,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
it "doesn't post a system note" do
expect(SystemNoteService).not_to receive(:new_issue_branch)
- post :create,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- branch_name: branch,
- issue_iid: issue.iid
- }
+ post :create, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ branch_name: branch,
+ issue_iid: issue.iid
+ }
end
end
end
@@ -285,18 +277,17 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
create_branch name: "<script>alert('merge');</script>", ref: "<script>alert('ref');</script>"
expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(response.body).to include 'Failed to create branch'
end
end
def create_branch(name:, ref:)
- post :create,
- format: :json,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project.to_param,
- branch_name: name,
- ref: ref
- }
+ post :create, format: :json, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ branch_name: name,
+ ref: ref
+ }
end
end
@@ -345,13 +336,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
before do
sign_in(developer)
- post :destroy,
- format: format,
- params: {
- id: branch,
- namespace_id: project.namespace,
- project_id: project
- }
+ post :destroy, format: format, params: {
+ id: branch,
+ namespace_id: project.namespace,
+ project_id: project
+ }
end
context 'as JS' do
@@ -445,11 +434,10 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
describe "DELETE destroy_all_merged" do
def destroy_all_merged
- delete :destroy_all_merged,
- params: {
- namespace_id: project.namespace,
- project_id: project
- }
+ delete :destroy_all_merged, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ }
end
context 'when user is allowed to push' do
@@ -492,13 +480,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
context 'when rendering a JSON format' do
it 'filters branches by name' do
- get :index,
- format: :json,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- search: 'master'
- }
+ get :index, format: :json, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ search: 'master'
+ }
expect(json_response.length).to eq 1
expect(json_response.first).to eq 'master'
@@ -523,13 +509,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
status: :success,
created_at: 2.months.ago)
- get :index,
- format: :html,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- state: 'all'
- }
+ get :index, format: :html, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ state: 'all'
+ }
expect(assigns[:branch_pipeline_statuses]["master"].group).to eq("success")
expect(assigns[:sort]).to eq('updated_desc')
@@ -555,13 +539,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
status: :success,
created_at: 2.months.ago)
- get :index,
- format: :html,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- state: 'all'
- }
+ get :index, format: :html, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ state: 'all'
+ }
expect(assigns[:branch_pipeline_statuses]["master"].group).to eq("running")
expect(assigns[:branch_pipeline_statuses]["test"].group).to eq("success")
@@ -570,13 +552,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
context 'when a branch contains no pipelines' do
it 'no commit statuses are received' do
- get :index,
- format: :html,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- state: 'stale'
- }
+ get :index, format: :html, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ state: 'stale'
+ }
expect(assigns[:branch_pipeline_statuses]).to be_blank
expect(assigns[:sort]).to eq('updated_asc')
@@ -589,14 +569,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
# was not raised whenever the cache is enabled yet cold.
context 'when cache is enabled yet cold', :request_store do
it 'return with a status 200' do
- get :index,
- format: :html,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- sort: 'name_asc',
- state: 'all'
- }
+ get :index, format: :html, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ sort: 'name_asc',
+ state: 'all'
+ }
expect(response).to have_gitlab_http_status(:ok)
expect(assigns[:sort]).to eq('name_asc')
@@ -609,13 +587,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
end
it 'return with a status 200' do
- get :index,
- format: :html,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- state: 'all'
- }
+ get :index, format: :html, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ state: 'all'
+ }
expect(response).to have_gitlab_http_status(:ok)
end
@@ -623,37 +599,31 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
context 'when deprecated sort/search/page parameters are specified' do
it 'returns with a status 301 when sort specified' do
- get :index,
- format: :html,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- sort: 'updated_asc'
- }
+ get :index, format: :html, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ sort: 'updated_asc'
+ }
expect(response).to redirect_to project_branches_filtered_path(project, state: 'all')
end
it 'returns with a status 301 when search specified' do
- get :index,
- format: :html,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- search: 'feature'
- }
+ get :index, format: :html, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ search: 'feature'
+ }
expect(response).to redirect_to project_branches_filtered_path(project, state: 'all')
end
it 'returns with a status 301 when page specified' do
- get :index,
- format: :html,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- page: 2
- }
+ get :index, format: :html, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ page: 2
+ }
expect(response).to redirect_to project_branches_filtered_path(project, state: 'all')
end
@@ -747,13 +717,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
end
it 'returns the commit counts behind and ahead of default branch' do
- get :diverging_commit_counts,
- format: :json,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- names: %w[fix add-pdf-file branch-merged]
- }
+ get :diverging_commit_counts, format: :json, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ names: %w[fix add-pdf-file branch-merged]
+ }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq(
@@ -766,12 +734,10 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
it 'returns the commits counts with no names provided' do
allow_any_instance_of(Repository).to receive(:branch_count).and_return(Kaminari.config.default_per_page)
- get :diverging_commit_counts,
- format: :json,
- params: {
- namespace_id: project.namespace,
- project_id: project
- }
+ get :diverging_commit_counts, format: :json, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to be > 1
@@ -783,25 +749,21 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana
end
it 'returns 422 if no names are specified' do
- get :diverging_commit_counts,
- format: :json,
- params: {
- namespace_id: project.namespace,
- project_id: project
- }
+ get :diverging_commit_counts, format: :json, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ }
expect(response).to have_gitlab_http_status(:unprocessable_entity)
expect(json_response['error']).to eq("Specify at least one and at most #{Kaminari.config.default_per_page} branch names")
end
it 'returns the list of counts' do
- get :diverging_commit_counts,
- format: :json,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- names: %w[fix add-pdf-file branch-merged]
- }
+ get :diverging_commit_counts, format: :json, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ names: %w[fix add-pdf-file branch-merged]
+ }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to be > 1
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index a4f7c92f5cd..38f72c769f3 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -420,11 +420,12 @@ RSpec.describe Projects::ClustersController, feature_category: :kubernetes_manag
describe 'PUT update' do
def go(format: :html)
- put :update, params: params.merge(namespace_id: project.namespace.to_param,
- project_id: project.to_param,
- id: cluster,
- format: format
- )
+ put :update, params: params.merge(
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: cluster,
+ format: format
+ )
end
before do
diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb
index 8d3939d8133..36206a88786 100644
--- a/spec/controllers/projects/commit_controller_spec.rb
+++ b/spec/controllers/projects/commit_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::CommitController do
+RSpec.describe Projects::CommitController, feature_category: :source_code_management do
include ProjectForksHelper
let_it_be(:project) { create(:project, :repository) }
@@ -155,12 +155,7 @@ RSpec.describe Projects::CommitController do
let(:commit) { fork_project.commit('remove-submodule') }
it 'renders it' do
- get(:show,
- params: {
- namespace_id: fork_project.namespace,
- project_id: fork_project,
- id: commit.id
- })
+ get :show, params: { namespace_id: fork_project.namespace, project_id: fork_project, id: commit.id }
expect(response).to be_successful
end
@@ -174,10 +169,10 @@ RSpec.describe Projects::CommitController do
go(id: commit.id, merge_request_iid: merge_request.iid)
expect(assigns(:new_diff_note_attrs)).to eq({
- noteable_type: 'MergeRequest',
- noteable_id: merge_request.id,
- commit_id: commit.id
- })
+ noteable_type: 'MergeRequest',
+ noteable_id: merge_request.id,
+ commit_id: commit.id
+ })
expect(response).to be_ok
end
end
@@ -187,12 +182,7 @@ RSpec.describe Projects::CommitController do
it 'contains branch and tags information' do
commit = project.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
- get(:branches,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: commit.id
- })
+ get :branches, params: { namespace_id: project.namespace, project_id: project, id: commit.id }
expect(assigns(:branches)).to include('master', 'feature_conflict')
expect(assigns(:branches_limit_exceeded)).to be_falsey
@@ -205,12 +195,7 @@ RSpec.describe Projects::CommitController do
allow_any_instance_of(Repository).to receive(:branch_count).and_return(1001)
allow_any_instance_of(Repository).to receive(:tag_count).and_return(1001)
- get(:branches,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: commit.id
- })
+ get :branches, params: { namespace_id: project.namespace, project_id: project, id: commit.id }
expect(assigns(:branches)).to eq([])
expect(assigns(:branches_limit_exceeded)).to be_truthy
@@ -234,12 +219,7 @@ RSpec.describe Projects::CommitController do
describe 'POST revert' do
context 'when target branch is not provided' do
it 'renders the 404 page' do
- post(:revert,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: commit.id
- })
+ post :revert, params: { namespace_id: project.namespace, project_id: project, id: commit.id }
expect(response).not_to be_successful
expect(response).to have_gitlab_http_status(:not_found)
@@ -248,13 +228,7 @@ RSpec.describe Projects::CommitController do
context 'when the revert commit is missing' do
it 'renders the 404 page' do
- post(:revert,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- start_branch: 'master',
- id: '1234567890'
- })
+ post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: '1234567890' }
expect(response).not_to be_successful
expect(response).to have_gitlab_http_status(:not_found)
@@ -263,13 +237,7 @@ RSpec.describe Projects::CommitController do
context 'when the revert was successful' do
it 'redirects to the commits page' do
- post(:revert,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- start_branch: 'master',
- id: commit.id
- })
+ post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: commit.id }
expect(response).to redirect_to project_commits_path(project, 'master')
expect(flash[:notice]).to eq('The commit has been successfully reverted.')
@@ -278,27 +246,53 @@ RSpec.describe Projects::CommitController do
context 'when the revert failed' do
before do
- post(:revert,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- start_branch: 'master',
- id: commit.id
- })
+ post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: commit.id }
end
it 'redirects to the commit page' do
# Reverting a commit that has been already reverted.
- post(:revert,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- start_branch: 'master',
- id: commit.id
- })
+ post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: commit.id }
expect(response).to redirect_to project_commit_path(project, commit.id)
- expect(flash[:alert]).to match('Sorry, we cannot revert this commit automatically.')
+ expect(flash[:alert]).to match('Commit revert failed:')
+ end
+ end
+
+ context 'in the context of a merge_request' do
+ let(:merge_request) { create(:merge_request, :merged, source_project: project) }
+ let(:repository) { project.repository }
+
+ before do
+ merge_commit_id = repository.merge(user,
+ merge_request.diff_head_sha,
+ merge_request,
+ 'Test message')
+
+ repository.commit(merge_commit_id)
+ merge_request.update!(merge_commit_sha: merge_commit_id)
+ end
+
+ context 'when the revert was successful' do
+ it 'redirects to the merge request page' do
+ post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: merge_request.merge_commit_sha }
+
+ expect(response).to redirect_to project_merge_request_path(project, merge_request)
+ expect(flash[:notice]).to eq('The merge request has been successfully reverted.')
+ end
+ end
+
+ context 'when the revert failed' do
+ before do
+ post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: merge_request.merge_commit_sha }
+ end
+
+ it 'redirects to the merge request page' do
+ # Reverting a merge request that has been already reverted.
+ post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: merge_request.merge_commit_sha }
+
+ expect(response).to redirect_to project_merge_request_path(project, merge_request)
+ expect(flash[:alert]).to match('Merge request revert failed:')
+ end
end
end
end
@@ -306,12 +300,7 @@ RSpec.describe Projects::CommitController do
describe 'POST cherry_pick' do
context 'when target branch is not provided' do
it 'renders the 404 page' do
- post(:cherry_pick,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: master_pickable_commit.id
- })
+ post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, id: master_pickable_commit.id }
expect(response).not_to be_successful
expect(response).to have_gitlab_http_status(:not_found)
@@ -320,13 +309,7 @@ RSpec.describe Projects::CommitController do
context 'when the cherry-pick commit is missing' do
it 'renders the 404 page' do
- post(:cherry_pick,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- start_branch: 'master',
- id: '1234567890'
- })
+ post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: '1234567890' }
expect(response).not_to be_successful
expect(response).to have_gitlab_http_status(:not_found)
@@ -335,13 +318,7 @@ RSpec.describe Projects::CommitController do
context 'when the cherry-pick was successful' do
it 'redirects to the commits page' do
- post(:cherry_pick,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- start_branch: 'master',
- id: master_pickable_commit.id
- })
+ post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: master_pickable_commit.id }
expect(response).to redirect_to project_commits_path(project, 'master')
expect(flash[:notice]).to eq('The commit has been successfully cherry-picked into master.')
@@ -350,27 +327,52 @@ RSpec.describe Projects::CommitController do
context 'when the cherry_pick failed' do
before do
- post(:cherry_pick,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- start_branch: 'master',
- id: master_pickable_commit.id
- })
+ post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: master_pickable_commit.id }
end
it 'redirects to the commit page' do
# Cherry-picking a commit that has been already cherry-picked.
- post(:cherry_pick,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- start_branch: 'master',
- id: master_pickable_commit.id
- })
+ post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: master_pickable_commit.id }
expect(response).to redirect_to project_commit_path(project, master_pickable_commit.id)
- expect(flash[:alert]).to match('Sorry, we cannot cherry-pick this commit automatically.')
+ expect(flash[:alert]).to match('Commit cherry-pick failed:')
+ end
+ end
+
+ context 'in the context of a merge_request' do
+ let(:merge_request) { create(:merge_request, :merged, source_project: project) }
+ let(:repository) { project.repository }
+
+ before do
+ merge_commit_id = repository.merge(user,
+ merge_request.diff_head_sha,
+ merge_request,
+ 'Test message')
+ repository.commit(merge_commit_id)
+ merge_request.update!(merge_commit_sha: merge_commit_id)
+ end
+
+ context 'when the cherry_pick was successful' do
+ it 'redirects to the merge request page' do
+ post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'merge-test', id: merge_request.merge_commit_sha }
+
+ expect(response).to redirect_to project_merge_request_path(project, merge_request)
+ expect(flash[:notice]).to eq('The merge request has been successfully cherry-picked into merge-test.')
+ end
+ end
+
+ context 'when the cherry_pick failed' do
+ before do
+ post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'merge-test', id: merge_request.merge_commit_sha }
+ end
+
+ it 'redirects to the merge request page' do
+ # Reverting a merge request that has been already cherry-picked.
+ post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'merge-test', id: merge_request.merge_commit_sha }
+
+ expect(response).to redirect_to project_merge_request_path(project, merge_request)
+ expect(flash[:alert]).to match('Merge request cherry-pick failed:')
+ end
end
end
@@ -381,15 +383,14 @@ RSpec.describe Projects::CommitController do
let(:create_merge_request) { nil }
def send_request
- post(:cherry_pick,
- params: {
- namespace_id: forked_project.namespace,
- project_id: forked_project,
- target_project_id: target_project.id,
- start_branch: 'feature',
- id: forked_project.commit.id,
- create_merge_request: create_merge_request
- })
+ post :cherry_pick, params: {
+ namespace_id: forked_project.namespace,
+ project_id: forked_project,
+ target_project_id: target_project.id,
+ start_branch: 'feature',
+ id: forked_project.commit.id,
+ create_merge_request: create_merge_request
+ }
end
def merge_request_url(source_project, branch)
@@ -478,8 +479,7 @@ RSpec.describe Projects::CommitController do
diff_for_path(id: commit2.id, old_path: existing_path, new_path: existing_path)
expect(assigns(:diff_notes_disabled)).to be_falsey
- expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'Commit',
- commit_id: commit2.id)
+ expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'Commit', commit_id: commit2.id)
end
it 'only renders the diffs for the path given' do
diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb
index 67aa82dacbb..9e03d1f315b 100644
--- a/spec/controllers/projects/commits_controller_spec.rb
+++ b/spec/controllers/projects/commits_controller_spec.rb
@@ -18,11 +18,7 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
describe "GET commits_root" do
context "no ref is provided" do
it 'redirects to the default branch of the project' do
- get(:commits_root,
- params: {
- namespace_id: project.namespace,
- project_id: project
- })
+ get :commits_root, params: { namespace_id: project.namespace, project_id: project }
expect(response).to redirect_to project_commits_path(project)
end
@@ -34,12 +30,7 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
context 'with file path' do
before do
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id
- })
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: id }
end
context "valid branch, valid file" do
@@ -78,13 +69,7 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
offset: 0
).and_call_original
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id,
- limit: "foo"
- })
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: id, limit: "foo" }
expect(response).to be_successful
end
@@ -98,27 +83,45 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
offset: 0
).and_call_original
- get(:show, params: {
+ get :show, params: {
namespace_id: project.namespace,
project_id: project,
id: id,
limit: { 'broken' => 'value' }
- })
+ }
expect(response).to be_successful
end
end
end
+ it 'loads tags for commits' do
+ expect_next_instance_of(CommitCollection) do |collection|
+ expect(collection).to receive(:load_tags)
+ end
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: 'master/README.md' }
+ end
+
+ context 'when the show_tags_on_commits_view flag is disabled' do
+ let(:id) { "master/README.md" }
+
+ before do
+ stub_feature_flags(show_tags_on_commits_view: false)
+ end
+
+ it 'does not load tags' do
+ expect_next_instance_of(CommitCollection) do |collection|
+ expect(collection).not_to receive(:load_tags)
+ end
+
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: id }
+ end
+ end
+
context "when the ref name ends in .atom" do
context "when the ref does not exist with the suffix" do
before do
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: "master.atom"
- })
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: "master.atom" }
end
it "renders as atom" do
@@ -138,12 +141,11 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
allow_any_instance_of(Repository).to receive(:commit).and_call_original
allow_any_instance_of(Repository).to receive(:commit).with('master.atom').and_return(commit)
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: "master.atom"
- })
+ get :show, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: "master.atom"
+ }
end
it "renders as HTML" do
@@ -182,13 +184,11 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
before do
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original unless id.include?(' ')
- get(:signatures,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id
- },
- format: :json)
+ get :signatures, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: id
+ }, format: :json
end
context "valid branch" do
diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb
index 034e6104f99..4ff8c21706b 100644
--- a/spec/controllers/projects/cycle_analytics_controller_spec.rb
+++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb
@@ -15,11 +15,7 @@ RSpec.describe Projects::CycleAnalyticsController do
it 'increases the counter' do
expect(Gitlab::UsageDataCounters::CycleAnalyticsCounter).to receive(:count).with(:views)
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project
- })
+ get :show, params: { namespace_id: project.namespace, project_id: project }
expect(response).to be_successful
end
@@ -35,7 +31,6 @@ RSpec.describe Projects::CycleAnalyticsController do
subject { get :show, params: request_params, format: :html }
let(:request_params) { { namespace_id: project.namespace, project_id: project } }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:namespace) { project.namespace }
diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb
index ec63bad22b5..52a605cf548 100644
--- a/spec/controllers/projects/deploy_keys_controller_spec.rb
+++ b/spec/controllers/projects/deploy_keys_controller_spec.rb
@@ -276,9 +276,9 @@ RSpec.describe Projects::DeployKeysController do
let(:extra_params) { {} }
subject do
- put :update, params: extra_params.reverse_merge(id: deploy_key.id,
- namespace_id: project.namespace,
- project_id: project)
+ put :update, params: extra_params.reverse_merge(
+ id: deploy_key.id, namespace_id: project.namespace, project_id: project
+ )
end
def deploy_key_params(title, can_push)
@@ -330,9 +330,7 @@ RSpec.describe Projects::DeployKeysController do
context 'when a different deploy key id param is injected' do
let(:extra_params) { deploy_key_params('updated title', '1') }
let(:hacked_params) do
- extra_params.reverse_merge(id: other_deploy_key_id,
- namespace_id: project.namespace,
- project_id: project)
+ extra_params.reverse_merge(id: other_deploy_key_id, namespace_id: project.namespace, project_id: project)
end
subject { put :update, params: hacked_params }
diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb
index c6532e83441..a696eb933e9 100644
--- a/spec/controllers/projects/deployments_controller_spec.rb
+++ b/spec/controllers/projects/deployments_controller_spec.rb
@@ -210,8 +210,6 @@ RSpec.describe Projects::DeploymentsController do
end
def deployment_params(opts = {})
- opts.reverse_merge(namespace_id: project.namespace,
- project_id: project,
- environment_id: environment.id)
+ opts.reverse_merge(namespace_id: project.namespace, project_id: project, environment_id: environment.id)
end
end
diff --git a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb
index 5cc6e1b1bb4..1bb5112681c 100644
--- a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb
+++ b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb
@@ -139,10 +139,13 @@ RSpec.describe Projects::DesignManagement::Designs::ResizedImageController, feat
let(:sha) { newest_version.sha }
before do
- create(:design, :with_smaller_image_versions,
- issue: create(:issue, project: project),
- versions_count: 1,
- versions_sha: sha)
+ create(
+ :design,
+ :with_smaller_image_versions,
+ issue: create(:issue, project: project),
+ versions_count: 1,
+ versions_sha: sha
+ )
end
it 'serves the newest image' do
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index 169fed1ab17..cbf632bfdb0 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -44,17 +44,9 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d
allow_any_instance_of(Environment).to receive(:has_terminals?).and_return(true)
allow_any_instance_of(Environment).to receive(:rollout_status).and_return(kube_deployment_rollout_status)
- create(:environment, project: project,
- name: 'staging/review-1',
- state: :available)
-
- create(:environment, project: project,
- name: 'staging/review-2',
- state: :available)
-
- create(:environment, project: project,
- name: 'staging/review-3',
- state: :stopped)
+ create(:environment, project: project, name: 'staging/review-1', state: :available)
+ create(:environment, project: project, name: 'staging/review-2', state: :available)
+ create(:environment, project: project, name: 'staging/review-3', state: :stopped)
end
let(:environments) { json_response['environments'] }
@@ -84,9 +76,7 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d
it 'ignores search option if is shorter than a minimum' do
get :index, params: environment_params(format: :json, search: 'st')
- expect(environments.map { |env| env['name'] }).to contain_exactly('production',
- 'staging/review-1',
- 'staging/review-2')
+ expect(environments.map { |env| env['name'] }).to contain_exactly('production', 'staging/review-1', 'staging/review-2')
expect(json_response['available_count']).to eq 3
expect(json_response['stopped_count']).to eq 1
end
@@ -96,9 +86,7 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d
get :index, params: environment_params(format: :json, search: 'review')
- expect(environments.map { |env| env['name'] }).to contain_exactly('review-app',
- 'staging/review-1',
- 'staging/review-2')
+ expect(environments.map { |env| env['name'] }).to contain_exactly('review-app', 'staging/review-1', 'staging/review-2')
expect(json_response['available_count']).to eq 3
expect(json_response['stopped_count']).to eq 1
end
@@ -245,23 +233,18 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d
context 'when using JSON format' do
before do
- create(:environment, project: project,
- name: 'staging-1.0/review',
- state: :available)
- create(:environment, project: project,
- name: 'staging-1.0/zzz',
- state: :available)
+ create(:environment, project: project, name: 'staging-1.0/review', state: :available)
+ create(:environment, project: project, name: 'staging-1.0/zzz', state: :available)
end
let(:environments) { json_response['environments'] }
it 'sorts the subfolders lexicographically' do
get :folder, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: 'staging-1.0'
- },
- format: :json
+ namespace_id: project.namespace,
+ project_id: project,
+ id: 'staging-1.0'
+ }, format: :json
expect(response).to be_ok
expect(response).not_to render_template 'folder'
@@ -1016,98 +999,8 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d
end
end
- describe '#append_info_to_payload' do
- let(:search_param) { 'my search param' }
-
- context 'when search_environment_logging feature is disabled' do
- before do
- stub_feature_flags(environments_search_logging: false)
- end
-
- it 'does not log search params in meta.environment.search' do
- expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload|
- method.call(payload)
-
- expect(payload[:metadata]).not_to have_key('meta.environment.search')
- expect(payload[:action]).to eq("search")
- expect(payload[:controller]).to eq("Projects::EnvironmentsController")
- end
-
- get :search, params: environment_params(format: :json, search: search_param)
- end
-
- it 'logs params correctly when search params are missing' do
- expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload|
- method.call(payload)
-
- expect(payload[:metadata]).not_to have_key('meta.environment.search')
- expect(payload[:action]).to eq("search")
- expect(payload[:controller]).to eq("Projects::EnvironmentsController")
- end
-
- get :search, params: environment_params(format: :json)
- end
-
- it 'logs params correctly when search params is empty string' do
- expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload|
- method.call(payload)
-
- expect(payload[:metadata]).not_to have_key('meta.environment.search')
- expect(payload[:action]).to eq("search")
- expect(payload[:controller]).to eq("Projects::EnvironmentsController")
- end
-
- get :search, params: environment_params(format: :json, search: "")
- end
- end
-
- context 'when search_environment_logging feature is enabled' do
- before do
- stub_feature_flags(environments_search_logging: true)
- end
-
- it 'logs search params in meta.environment.search' do
- expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload|
- method.call(payload)
-
- expect(payload[:metadata]['meta.environment.search']).to eq(search_param)
- expect(payload[:action]).to eq("search")
- expect(payload[:controller]).to eq("Projects::EnvironmentsController")
- end
-
- get :search, params: environment_params(format: :json, search: search_param)
- end
-
- it 'logs params correctly when search params are missing' do
- expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload|
- method.call(payload)
-
- expect(payload[:metadata]).not_to have_key('meta.environment.search')
- expect(payload[:action]).to eq("search")
- expect(payload[:controller]).to eq("Projects::EnvironmentsController")
- end
-
- get :search, params: environment_params(format: :json)
- end
-
- it 'logs params correctly when search params is empty string' do
- expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload|
- method.call(payload)
-
- expect(payload[:metadata]).not_to have_key('meta.environment.search')
- expect(payload[:action]).to eq("search")
- expect(payload[:controller]).to eq("Projects::EnvironmentsController")
- end
-
- get :search, params: environment_params(format: :json, search: "")
- end
- end
- end
-
def environment_params(opts = {})
- opts.reverse_merge(namespace_id: project.namespace,
- project_id: project,
- id: environment.id)
+ opts.reverse_merge(namespace_id: project.namespace, project_id: project, id: environment.id)
end
def additional_metrics(opts = {})
diff --git a/spec/controllers/projects/feature_flags_controller_spec.rb b/spec/controllers/projects/feature_flags_controller_spec.rb
index 29ad51d590f..ac2e4233709 100644
--- a/spec/controllers/projects/feature_flags_controller_spec.rb
+++ b/spec/controllers/projects/feature_flags_controller_spec.rb
@@ -193,8 +193,7 @@ RSpec.describe Projects::FeatureFlagsController do
it 'routes based on iid' do
other_project = create(:project)
other_project.add_developer(user)
- other_feature_flag = create(:operations_feature_flag, project: other_project,
- name: 'other_flag')
+ other_feature_flag = create(:operations_feature_flag, project: other_project, name: 'other_flag')
params = {
namespace_id: other_project.namespace,
project_id: other_project,
@@ -485,8 +484,7 @@ RSpec.describe Projects::FeatureFlagsController do
context 'when creating a version 2 feature flag with a gitlabUserList strategy' do
let!(:user_list) do
- create(:operations_feature_flag_user_list, project: project,
- name: 'My List', user_xids: 'user1,user2')
+ create(:operations_feature_flag_user_list, project: project, name: 'My List', user_xids: 'user1,user2')
end
let(:params) do
@@ -627,10 +625,7 @@ RSpec.describe Projects::FeatureFlagsController do
context 'with a version 2 feature flag' do
let!(:new_version_flag) do
- create(:operations_feature_flag,
- name: 'new-feature',
- active: true,
- project: project)
+ create(:operations_feature_flag, name: 'new-feature', active: true, project: project)
end
it 'creates a new strategy and scope' do
diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb
index a6c71cff74b..68810bae368 100644
--- a/spec/controllers/projects/find_file_controller_spec.rb
+++ b/spec/controllers/projects/find_file_controller_spec.rb
@@ -18,12 +18,7 @@ RSpec.describe Projects::FindFileController do
render_views
before do
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id
- })
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: id }
end
context "valid branch" do
@@ -41,13 +36,7 @@ RSpec.describe Projects::FindFileController do
describe "GET #list" do
def go(format: 'json')
- get :list,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: id
- },
- format: format
+ get :list, params: { namespace_id: project.namespace, project_id: project, id: id }, format: format
end
context "valid branch" do
diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb
index 25c722173c1..3ea7054a64c 100644
--- a/spec/controllers/projects/forks_controller_spec.rb
+++ b/spec/controllers/projects/forks_controller_spec.rb
@@ -168,12 +168,7 @@ RSpec.describe Projects::ForksController, feature_category: :source_code_managem
let(:format) { :html }
subject(:do_request) do
- get :new,
- format: format,
- params: {
- namespace_id: project.namespace,
- project_id: project
- }
+ get :new, format: format, params: { namespace_id: project.namespace, project_id: project }
end
context 'when user is signed in' do
diff --git a/spec/controllers/projects/grafana_api_controller_spec.rb b/spec/controllers/projects/grafana_api_controller_spec.rb
index 90ab49f9467..ae863918d14 100644
--- a/spec/controllers/projects/grafana_api_controller_spec.rb
+++ b/spec/controllers/projects/grafana_api_controller_spec.rb
@@ -87,13 +87,15 @@ RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do
it 'returns a grafana datasource response' do
get :proxy, params: params
- expect(Grafana::ProxyService)
- .to have_received(:new)
- .with(project, '1', 'api/v1/query_range',
- { 'query' => params[:query],
- 'start' => params[:start_time],
- 'end' => params[:end_time],
- 'step' => params[:step] })
+ expect(Grafana::ProxyService).to have_received(:new).with(
+ project, '1', 'api/v1/query_range',
+ {
+ 'query' => params[:query],
+ 'start' => params[:start_time],
+ 'end' => params[:end_time],
+ 'step' => params[:step]
+ }
+ )
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq({})
diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb
index 1e9d999311a..3e5bcbbc9ba 100644
--- a/spec/controllers/projects/graphs_controller_spec.rb
+++ b/spec/controllers/projects/graphs_controller_spec.rb
@@ -141,7 +141,6 @@ RSpec.describe Projects::GraphsController do
end
let(:request_params) { { namespace_id: project.namespace.path, project_id: project.path, id: 'master' } }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:namespace) { project.namespace }
diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb
index a5c00d24e30..2075dd3e7a7 100644
--- a/spec/controllers/projects/group_links_controller_spec.rb
+++ b/spec/controllers/projects/group_links_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::GroupLinksController, feature_category: :authentication_and_authorization do
+RSpec.describe Projects::GroupLinksController, feature_category: :system_access do
let_it_be(:group) { create(:group, :private) }
let_it_be(:group2) { create(:group, :private) }
let_it_be(:project) { create(:project, :private, group: group2) }
diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb
index 815370d428d..c056e7a33aa 100644
--- a/spec/controllers/projects/hooks_controller_spec.rb
+++ b/spec/controllers/projects/hooks_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::HooksController do
+RSpec.describe Projects::HooksController, feature_category: :integrations do
include AfterNextHelpers
let_it_be(:project) { create(:project) }
@@ -173,6 +173,16 @@ RSpec.describe Projects::HooksController do
let(:params) { { namespace_id: project.namespace, project_id: project, id: hook } }
it_behaves_like 'Web hook destroyer'
+
+ context 'when user does not have permission' do
+ let(:user) { create(:user, developer_projects: [project]) }
+
+ it 'renders a 404' do
+ delete :destroy, params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
end
describe '#test' do
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 9c272872a73..f1fe1940414 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -183,18 +183,6 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do
let_it_be(:task) { create(:issue, :task, project: project) }
shared_examples 'redirects to show work item page' do
- context 'when use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- it 'redirects to work item page' do
- make_request
-
- expect(response).to redirect_to(project_work_items_path(project, task.id, query))
- end
- end
-
it 'redirects to work item page using iid' do
make_request
@@ -585,15 +573,13 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do
end
def reorder_issue(issue, move_after_id: nil, move_before_id: nil)
- put :reorder,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: issue.iid,
- move_after_id: move_after_id,
- move_before_id: move_before_id
- },
- format: :json
+ put :reorder, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: issue.iid,
+ move_after_id: move_after_id,
+ move_before_id: move_before_id
+ }, format: :json
end
end
@@ -601,14 +587,12 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do
let(:issue_params) { { title: 'New title' } }
subject do
- put :update,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: issue.to_param,
- issue: issue_params
- },
- format: :json
+ put :update, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: issue.to_param,
+ issue: issue_params
+ }, format: :json
end
before do
@@ -1927,12 +1911,11 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do
end
it 'redirects from an old issue/designs correctly' do
- get :designs,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: issue
- }
+ get :designs, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: issue
+ }
expect(response).to redirect_to(designs_project_issue_path(new_project, issue))
expect(response).to have_gitlab_http_status(:moved_permanently)
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 2d047957430..2e29d87dadd 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -106,9 +106,10 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
def create_job(name, status)
user = create(:user)
pipeline = create(:ci_pipeline, project: project, user: user)
- create(:ci_build, :tags, :triggered, :artifacts,
- pipeline: pipeline, name: name, status: status,
- user: user)
+ create(
+ :ci_build, :tags, :triggered, :artifacts,
+ pipeline: pipeline, name: name, status: status, user: user
+ )
end
end
@@ -832,8 +833,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
retried_build = Ci::Build.last
Ci::Build.clone_accessors.each do |accessor|
- expect(job.read_attribute(accessor))
- .to eq(retried_build.read_attribute(accessor)),
+ expect(job.read_attribute(accessor)).to eq(retried_build.read_attribute(accessor)),
"Mismatched attribute on \"#{accessor}\". " \
"It was \"#{job.read_attribute(accessor)}\" but changed to \"#{retried_build.read_attribute(accessor)}\""
end
@@ -855,10 +855,10 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
def post_retry
post :retry, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: job.id
- }
+ namespace_id: project.namespace,
+ project_id: project,
+ id: job.id
+ }
end
end
@@ -869,8 +869,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
before do
project.add_developer(user)
- create(:protected_branch, :developers_can_merge,
- name: 'protected-branch', project: project)
+ create(:protected_branch, :developers_can_merge, name: 'protected-branch', project: project)
sign_in(user)
end
diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb
index 19a04654114..b5092a0f091 100644
--- a/spec/controllers/projects/mattermosts_controller_spec.rb
+++ b/spec/controllers/projects/mattermosts_controller_spec.rb
@@ -19,11 +19,10 @@ RSpec.describe Projects::MattermostsController do
end
it 'accepts the request' do
- get(:new,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project
- })
+ get :new, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project
+ }
expect(response).to have_gitlab_http_status(:ok)
end
@@ -33,12 +32,11 @@ RSpec.describe Projects::MattermostsController do
let(:mattermost_params) { { trigger: 'http://localhost:3000/trigger', team_id: 'abc' } }
subject do
- post(:create,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- mattermost: mattermost_params
- })
+ post :create, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ mattermost: mattermost_params
+ }
end
context 'no request can be made to mattermost' do
diff --git a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
index 311af26abf6..356741fc4e2 100644
--- a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
@@ -22,13 +22,11 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to receive(:track_loading_conflict_ui_action)
- get :show,
- params: {
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid
- },
- format: 'html'
+ get :show, params: {
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid
+ }, format: 'html'
end
it 'does tracks the resolve call' do
@@ -45,13 +43,11 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
allow(Gitlab::Git::Conflict::Parser).to receive(:parse)
.and_raise(Gitlab::Git::Conflict::Parser::UnmergeableFile)
- get :show,
- params: {
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid
- },
- format: 'json'
+ get :show, params: {
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid
+ }, format: 'json'
end
it 'returns a 200 status code' do
@@ -70,13 +66,11 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
context 'with valid conflicts' do
before do
- get :show,
- params: {
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid
- },
- format: 'json'
+ get :show, params: {
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid
+ }, format: 'json'
end
it 'matches the schema' do
@@ -130,15 +124,13 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
describe 'GET conflict_for_path' do
def conflict_for_path(path)
- get :conflict_for_path,
- params: {
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid,
- old_path: path,
- new_path: path
- },
- format: 'json'
+ get :conflict_for_path, params: {
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid,
+ old_path: path,
+ new_path: path
+ }, format: 'json'
end
context 'when the conflicts cannot be resolved in the UI' do
@@ -178,11 +170,13 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to include('old_path' => path,
- 'new_path' => path,
- 'blob_icon' => 'doc-text',
- 'blob_path' => a_string_ending_with(path),
- 'content' => content)
+ expect(json_response).to include(
+ 'old_path' => path,
+ 'new_path' => path,
+ 'blob_icon' => 'doc-text',
+ 'blob_path' => a_string_ending_with(path),
+ 'content' => content
+ )
end
end
end
@@ -197,15 +191,13 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
end
def resolve_conflicts(files)
- post :resolve_conflicts,
- params: {
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid,
- files: files,
- commit_message: 'Commit message'
- },
- format: 'json'
+ post :resolve_conflicts, params: {
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid,
+ files: files,
+ commit_message: 'Commit message'
+ }, format: 'json'
end
context 'with valid params' do
diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
index 3d4a884587f..c6a4dcbfdf0 100644
--- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
@@ -99,9 +99,7 @@ RSpec.describe Projects::MergeRequests::CreationsController, feature_category: :
describe 'GET pipelines' do
before do
- create(:ci_pipeline, sha: fork_project.commit('remove-submodule').id,
- ref: 'remove-submodule',
- project: fork_project)
+ create(:ci_pipeline, sha: fork_project.commit('remove-submodule').id, ref: 'remove-submodule', project: fork_project)
end
it 'renders JSON including serialized pipelines' do
@@ -188,13 +186,12 @@ RSpec.describe Projects::MergeRequests::CreationsController, feature_category: :
expect(Ability).to receive(:allowed?).with(user, :read_project, project) { true }
expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { true }.at_least(:once)
- get :branch_to,
- params: {
- namespace_id: fork_project.namespace,
- project_id: fork_project,
- target_project_id: project.id,
- ref: 'master'
- }
+ get :branch_to, params: {
+ namespace_id: fork_project.namespace,
+ project_id: fork_project,
+ target_project_id: project.id,
+ ref: 'master'
+ }
expect(assigns(:commit)).not_to be_nil
expect(response).to have_gitlab_http_status(:ok)
@@ -204,13 +201,12 @@ RSpec.describe Projects::MergeRequests::CreationsController, feature_category: :
expect(Ability).to receive(:allowed?).with(user, :read_project, project) { true }
expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { false }.at_least(:once)
- get :branch_to,
- params: {
- namespace_id: fork_project.namespace,
- project_id: fork_project,
- target_project_id: project.id,
- ref: 'master'
- }
+ get :branch_to, params: {
+ namespace_id: fork_project.namespace,
+ project_id: fork_project,
+ target_project_id: project.id,
+ ref: 'master'
+ }
expect(assigns(:commit)).to be_nil
expect(response).to have_gitlab_http_status(:ok)
@@ -220,13 +216,12 @@ RSpec.describe Projects::MergeRequests::CreationsController, feature_category: :
expect(Ability).to receive(:allowed?).with(user, :read_project, project) { false }
expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { true }.at_least(:once)
- get :branch_to,
- params: {
- namespace_id: fork_project.namespace,
- project_id: fork_project,
- target_project_id: project.id,
- ref: 'master'
- }
+ get :branch_to, params: {
+ namespace_id: fork_project.namespace,
+ project_id: fork_project,
+ target_project_id: project.id,
+ ref: 'master'
+ }
expect(assigns(:commit)).to be_nil
expect(response).to have_gitlab_http_status(:ok)
diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
index 23a33d7e0b1..a5dc351201d 100644
--- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
@@ -247,9 +247,11 @@ RSpec.describe Projects::MergeRequests::DiffsController, feature_category: :code
straight: true)
end
- go(diff_head: true,
- diff_id: merge_request.merge_request_diff.id,
- start_sha: merge_request.merge_request_diff.start_commit_sha)
+ go(
+ diff_head: true,
+ diff_id: merge_request.merge_request_diff.id,
+ start_sha: merge_request.merge_request_diff.start_commit_sha
+ )
end
end
end
@@ -329,9 +331,11 @@ RSpec.describe Projects::MergeRequests::DiffsController, feature_category: :code
diff_for_path(old_path: existing_path, new_path: existing_path)
expect(assigns(:diff_notes_disabled)).to be_falsey
- expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'MergeRequest',
- noteable_id: merge_request.id,
- commit_id: nil)
+ expect(assigns(:new_diff_note_attrs)).to eq(
+ noteable_type: 'MergeRequest',
+ noteable_id: merge_request.id,
+ commit_id: nil
+ )
end
it 'only renders the diffs for the path given' do
@@ -528,8 +532,7 @@ RSpec.describe Projects::MergeRequests::DiffsController, feature_category: :code
context 'with diff_id and start_sha params' do
subject do
- go(diff_id: merge_request.merge_request_diff.id,
- start_sha: merge_request.merge_request_diff.start_commit_sha)
+ go(diff_id: merge_request.merge_request_diff.id, start_sha: merge_request.merge_request_diff.start_commit_sha)
end
it_behaves_like 'serializes diffs with expected arguments' do
diff --git a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
index 39482938a8b..6632473a85c 100644
--- a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb
@@ -299,8 +299,7 @@ RSpec.describe Projects::MergeRequests::DraftsController do
it 'publishes a draft note with quick actions and applies them', :sidekiq_inline do
project.add_developer(user2)
- create(:draft_note, merge_request: merge_request, author: user,
- note: "/assign #{user2.to_reference}")
+ create(:draft_note, merge_request: merge_request, author: user, note: "/assign #{user2.to_reference}")
expect(merge_request.assignees).to be_empty
@@ -350,12 +349,13 @@ RSpec.describe Projects::MergeRequests::DraftsController do
let(:note) { create(:discussion_note_on_merge_request, noteable: merge_request, project: project) }
def create_reply(discussion_id, resolves: false)
- create(:draft_note,
- merge_request: merge_request,
- author: user,
- discussion_id: discussion_id,
- resolve_discussion: resolves
- )
+ create(
+ :draft_note,
+ merge_request: merge_request,
+ author: user,
+ discussion_id: discussion_id,
+ resolve_discussion: resolves
+ )
end
it 'resolves a thread if the draft note resolves it' do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index ceb3f803db5..9e18089bb23 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -210,9 +210,7 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
diff = merge_request.merge_request_diff
diff.clean!
- diff.update!(real_size: nil,
- start_commit_sha: nil,
- base_commit_sha: nil)
+ diff.update!(real_size: nil, start_commit_sha: nil, base_commit_sha: nil)
go(format: :html)
@@ -270,24 +268,22 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
end
it 'redirects from an old merge request correctly' do
- get :show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: merge_request
- }
+ get :show, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: merge_request
+ }
expect(response).to redirect_to(project_merge_request_path(new_project, merge_request))
expect(response).to have_gitlab_http_status(:moved_permanently)
end
it 'redirects from an old merge request commits correctly' do
- get :commits,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: merge_request
- }
+ get :commits, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: merge_request
+ }
expect(response).to redirect_to(commits_project_merge_request_path(new_project, merge_request))
expect(response).to have_gitlab_http_status(:moved_permanently)
@@ -385,13 +381,12 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
def get_merge_requests(page = nil)
- get :index,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- state: 'opened',
- page: page.to_param
- }
+ get :index, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ state: 'opened',
+ page: page.to_param
+ }
end
it_behaves_like "issuables list meta-data", :merge_request
@@ -842,15 +837,13 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
describe 'GET commits' do
def go(page: nil, per_page: 1, format: 'html')
- get :commits,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: merge_request.iid,
- page: page,
- per_page: per_page
- },
- format: format
+ get :commits, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.iid,
+ page: page,
+ per_page: per_page
+ }, format: format
end
it 'renders the commits template to a string' do
@@ -884,17 +877,18 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
describe 'GET pipelines' do
before do
- create(:ci_pipeline, project: merge_request.source_project,
- ref: merge_request.source_branch,
- sha: merge_request.diff_head_sha)
+ create(
+ :ci_pipeline,
+ project: merge_request.source_project,
+ ref: merge_request.source_branch,
+ sha: merge_request.diff_head_sha
+ )
- get :pipelines,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: merge_request.iid
- },
- format: :json
+ get :pipelines, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.iid
+ }, format: :json
end
context 'with "enabled" builds on a public project' do
@@ -1955,17 +1949,18 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
let(:issue2) { create(:issue, project: project) }
def post_assign_issues
- merge_request.update!(description: "Closes #{issue1.to_reference} and #{issue2.to_reference}",
- author: user,
- source_branch: 'feature',
- target_branch: 'master')
+ merge_request.update!(
+ description: "Closes #{issue1.to_reference} and #{issue2.to_reference}",
+ author: user,
+ source_branch: 'feature',
+ target_branch: 'master'
+ )
- post :assign_related_issues,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: merge_request.iid
- }
+ post :assign_related_issues, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.iid
+ }
end
it 'displays an flash error message on fail' do
@@ -2143,10 +2138,13 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
describe 'GET pipeline_status.json' do
context 'when head_pipeline exists' do
let!(:pipeline) do
- create(:ci_pipeline, project: merge_request.source_project,
- ref: merge_request.source_branch,
- sha: merge_request.diff_head_sha,
- head_pipeline_of: merge_request)
+ create(
+ :ci_pipeline,
+ project: merge_request.source_project,
+ ref: merge_request.source_branch,
+ sha: merge_request.diff_head_sha,
+ head_pipeline_of: merge_request
+ )
end
let(:status) { pipeline.detailed_status(double('user')) }
@@ -2199,11 +2197,10 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
def get_pipeline_status
get :pipeline_status, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: merge_request.iid
- },
- format: :json
+ namespace_id: project.namespace,
+ project_id: project,
+ id: merge_request.iid
+ }, format: :json
end
end
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 23b0b58158f..5e4e47be2c5 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -37,6 +37,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
project.add_developer(user)
end
+ specify { expect(get(:index, params: request_params)).to have_request_urgency(:medium) }
+
it 'passes last_fetched_at from headers to NotesFinder and MergeIntoNotesService' do
last_fetched_at = Time.zone.at(3.hours.ago.to_i) # remove nanoseconds
@@ -244,6 +246,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
sign_in(user)
end
+ specify { expect(create!).to have_request_urgency(:low) }
+
describe 'making the creation request' do
before do
create!
@@ -432,6 +436,13 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
expect(json_response['commands_changes']).to include('emoji_award', 'time_estimate', 'spend_time')
expect(json_response['commands_changes']).not_to include('target_project', 'title')
end
+
+ it 'includes command_names' do
+ create!
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['command_names']).to include('award', 'estimate', 'spend')
+ end
end
context 'with commands that do not return changes' do
@@ -450,6 +461,13 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['commands_changes']).not_to include('target_project', 'title')
end
+
+ it 'includes command_names' do
+ create!
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['command_names']).to include('move', 'title')
+ end
end
end
end
@@ -484,10 +502,7 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
let(:commit) { create(:commit, project: project) }
let(:existing_comment) do
- create(:note_on_commit,
- note: 'first',
- project: project,
- commit_id: merge_request.commit_shas.first)
+ create(:note_on_commit, note: 'first', project: project, commit_id: merge_request.commit_shas.first)
end
let(:discussion) { existing_comment.discussion }
@@ -735,19 +750,21 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
end
describe 'PUT update' do
- context "should update the note with a valid issue" do
- let(:request_params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- id: note,
- format: :json,
- note: {
- note: "New comment"
- }
+ let(:request_params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: note,
+ format: :json,
+ note: {
+ note: "New comment"
}
- end
+ }
+ end
+
+ specify { expect(put(:update, params: request_params)).to have_request_urgency(:low) }
+ context "should update the note with a valid issue" do
before do
sign_in(note.author)
project.add_developer(note.author)
@@ -793,6 +810,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
}
end
+ specify { expect(delete(:destroy, params: request_params)).to have_request_urgency(:low) }
+
context 'user is the author of a note' do
before do
sign_in(note.author)
@@ -834,6 +853,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
let(:emoji_name) { 'thumbsup' }
+ it { is_expected.to have_request_urgency(:low) }
+
it "toggles the award emoji" do
expect do
subject
@@ -869,6 +890,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
sign_in user
end
+ specify { expect(post(:resolve, params: request_params)).to have_request_urgency(:low) }
+
context "when the user is not authorized to resolve the note" do
it "returns status 404" do
post :resolve, params: request_params
@@ -932,6 +955,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
note.resolve!(user)
end
+ specify { expect(delete(:unresolve, params: request_params)).to have_request_urgency(:low) }
+
context "when the user is not authorized to resolve the note" do
it "returns status 404" do
delete :unresolve, params: request_params
@@ -1001,6 +1026,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
expect(json_response.count).to eq(1)
expect(json_response.first).to include({ "line_text" => "Test" })
end
+
+ specify { expect(get(:outdated_line_change, params: request_params)).to have_request_urgency(:low) }
end
# Convert a time to an integer number of microseconds
diff --git a/spec/controllers/projects/pages_controller_spec.rb b/spec/controllers/projects/pages_controller_spec.rb
index 136f98ac907..ded5dd57e3e 100644
--- a/spec/controllers/projects/pages_controller_spec.rb
+++ b/spec/controllers/projects/pages_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::PagesController do
+RSpec.describe Projects::PagesController, feature_category: :pages do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
@@ -14,7 +14,12 @@ RSpec.describe Projects::PagesController do
end
before do
- allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
+ stub_config(pages: {
+ enabled: true,
+ external_https: true,
+ access_control: false
+ })
+
sign_in(user)
project.add_maintainer(user)
end
@@ -123,49 +128,99 @@ RSpec.describe Projects::PagesController do
end
describe 'PATCH update' do
- let(:request_params) do
- {
- namespace_id: project.namespace,
- project_id: project,
- project: { pages_https_only: 'false' }
- }
- end
+ context 'when updating pages_https_only' do
+ let(:request_params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ project: { pages_https_only: 'true' }
+ }
+ end
- let(:update_service) { double(execute: { status: :success }) }
+ it 'updates project field and redirects back to the pages settings' do
+ project.update!(pages_https_only: false)
- before do
- allow(Projects::UpdateService).to receive(:new) { update_service }
- end
+ expect { patch :update, params: request_params }
+ .to change { project.reload.pages_https_only }
+ .from(false).to(true)
- it 'returns 302 status' do
- patch :update, params: request_params
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(project_pages_path(project))
+ end
- expect(response).to have_gitlab_http_status(:found)
- end
+ context 'when it fails to update' do
+ it 'adds an error message' do
+ expect_next_instance_of(Projects::UpdateService) do |service|
+ expect(service)
+ .to receive(:execute)
+ .and_return(status: :error, message: 'some error happened')
+ end
- it 'redirects back to the pages settings' do
- patch :update, params: request_params
+ expect { patch :update, params: request_params }
+ .not_to change { project.reload.pages_https_only }
- expect(response).to redirect_to(project_pages_path(project))
+ expect(response).to redirect_to(project_pages_path(project))
+ expect(flash[:alert]).to eq('some error happened')
+ end
+ end
end
- it 'calls the update service' do
- expect(Projects::UpdateService)
- .to receive(:new)
- .with(project, user, ActionController::Parameters.new(request_params[:project]).permit!)
- .and_return(update_service)
+ context 'when updating pages_unique_domain' do
+ let(:request_params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ project: {
+ project_setting_attributes: {
+ pages_unique_domain_enabled: 'true'
+ }
+ }
+ }
+ end
- patch :update, params: request_params
- end
+ before do
+ create(:project_setting, project: project, pages_unique_domain_enabled: false)
+ end
- context 'when update_service returns an error message' do
- let(:update_service) { double(execute: { status: :error, message: 'some error happened' }) }
+ context 'with pages_unique_domain feature flag disabled' do
+ it 'does not update pages unique domain' do
+ stub_feature_flags(pages_unique_domain: false)
- it 'adds an error message' do
- patch :update, params: request_params
+ expect { patch :update, params: request_params }
+ .not_to change { project.project_setting.reload.pages_unique_domain_enabled }
+ end
+ end
- expect(response).to redirect_to(project_pages_path(project))
- expect(flash[:alert]).to eq('some error happened')
+ context 'with pages_unique_domain feature flag enabled' do
+ before do
+ stub_feature_flags(pages_unique_domain: true)
+ end
+
+ it 'updates pages_https_only and pages_unique_domain and redirects back to pages settings' do
+ expect { patch :update, params: request_params }
+ .to change { project.project_setting.reload.pages_unique_domain_enabled }
+ .from(false).to(true)
+
+ expect(project.project_setting.pages_unique_domain).not_to be_nil
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(project_pages_path(project))
+ end
+
+ context 'when it fails to update' do
+ it 'adds an error message' do
+ expect_next_instance_of(Projects::UpdateService) do |service|
+ expect(service)
+ .to receive(:execute)
+ .and_return(status: :error, message: 'some error happened')
+ end
+
+ expect { patch :update, params: request_params }
+ .not_to change { project.project_setting.reload.pages_unique_domain_enabled }
+
+ expect(response).to redirect_to(project_pages_path(project))
+ expect(flash[:alert]).to eq('some error happened')
+ end
+ end
end
end
end
diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
index a628c1ab230..6d810fdcd51 100644
--- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb
+++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
@@ -410,9 +410,9 @@ RSpec.describe Projects::PipelineSchedulesController, feature_category: :continu
it { expect { go }.to be_denied_for(:visitor) }
context 'when user is schedule owner' do
- it { expect { go }.to be_denied_for(:owner).of(project).own(pipeline_schedule) }
- it { expect { go }.to be_denied_for(:maintainer).of(project).own(pipeline_schedule) }
- it { expect { go }.to be_denied_for(:developer).of(project).own(pipeline_schedule) }
+ it { expect { go }.to be_allowed_for(:owner).of(project).own(pipeline_schedule) }
+ it { expect { go }.to be_allowed_for(:maintainer).of(project).own(pipeline_schedule) }
+ it { expect { go }.to be_allowed_for(:developer).of(project).own(pipeline_schedule) }
it { expect { go }.to be_denied_for(:reporter).of(project).own(pipeline_schedule) }
it { expect { go }.to be_denied_for(:guest).of(project).own(pipeline_schedule) }
it { expect { go }.to be_denied_for(:user).own(pipeline_schedule) }
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 4e0c098ad81..09b703a48d6 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -199,22 +199,36 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
check_pipeline_response(returned: 6, all: 6)
end
end
+
+ context "with lazy_load_pipeline_dropdown_actions feature flag disabled" do
+ before do
+ stub_feature_flags(lazy_load_pipeline_dropdown_actions: false)
+ end
+
+ it 'returns manual and scheduled actions' do
+ get_pipelines_index_json
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('pipeline')
+
+ expect(json_response.dig('pipelines', 0, 'details')).to include('manual_actions')
+ expect(json_response.dig('pipelines', 0, 'details')).to include('scheduled_actions')
+ end
+ end
end
def get_pipelines_index_html(params = {})
get :index, params: {
- namespace_id: project.namespace,
- project_id: project
- }.merge(params),
- format: :html
+ namespace_id: project.namespace,
+ project_id: project
+ }.merge(params), format: :html
end
def get_pipelines_index_json(params = {})
get :index, params: {
- namespace_id: project.namespace,
- project_id: project
- }.merge(params),
- format: :json
+ namespace_id: project.namespace,
+ project_id: project
+ }.merge(params), format: :json
end
def create_all_pipeline_types
@@ -236,12 +250,15 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
def create_pipeline(status, sha, merge_request: nil)
user = create(:user)
- pipeline = create(:ci_empty_pipeline, status: status,
- project: project,
- sha: sha.id,
- ref: sha.id.first(8),
- user: user,
- merge_request: merge_request)
+ pipeline = create(
+ :ci_empty_pipeline,
+ status: status,
+ project: project,
+ sha: sha.id,
+ ref: sha.id.first(8),
+ user: user,
+ merge_request: merge_request
+ )
build_stage = create(:ci_stage, name: 'build', pipeline: pipeline)
test_stage = create(:ci_stage, name: 'test', pipeline: pipeline)
@@ -378,9 +395,7 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
let(:project) { create(:project, :repository) }
let(:pipeline) do
- create(:ci_empty_pipeline, project: project,
- user: user,
- sha: project.commit.id)
+ create(:ci_empty_pipeline, project: project, user: user, sha: project.commit.id)
end
let(:build_stage) { create(:ci_stage, name: 'build', pipeline: pipeline) }
@@ -598,9 +613,7 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
def create_pipeline(project)
create(:ci_empty_pipeline, project: project).tap do |pipeline|
- create(:ci_build, pipeline: pipeline,
- ci_stage: create(:ci_stage, name: 'test', pipeline: pipeline),
- name: 'rspec')
+ create(:ci_build, pipeline: pipeline, ci_stage: create(:ci_stage, name: 'test', pipeline: pipeline), name: 'rspec')
end
end
@@ -771,11 +784,8 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
before do
get :status, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: pipeline.id
- },
- format: :json
+ namespace_id: project.namespace, project_id: project, id: pipeline.id
+ }, format: :json
end
it 'return a detailed pipeline status in json' do
@@ -825,7 +835,6 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
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(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'perform_analytics_usage_action' }
let(:namespace) { project.namespace }
@@ -868,9 +877,7 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
context 'when latest commit contains [ci skip]' do
before do
- project.repository.create_file(user, 'new-file.txt', 'A new file',
- message: '[skip ci] This is a test',
- branch_name: 'master')
+ project.repository.create_file(user, 'new-file.txt', 'A new file', message: '[skip ci] This is a test', branch_name: 'master')
end
it_behaves_like 'creates a pipeline'
@@ -906,11 +913,8 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
subject do
post :create, params: {
- namespace_id: project.namespace,
- project_id: project,
- pipeline: { ref: 'master' }
- },
- format: :json
+ namespace_id: project.namespace, project_id: project, pipeline: { ref: 'master' }
+ }, format: :json
end
before do
@@ -969,11 +973,8 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
describe 'POST retry.json' do
subject(:post_retry) do
post :retry, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: pipeline.id
- },
- format: :json
+ namespace_id: project.namespace, project_id: project, id: pipeline.id
+ }, format: :json
end
let!(:pipeline) { create(:ci_pipeline, :failed, project: project) }
@@ -1036,11 +1037,8 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
before do
post :cancel, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: pipeline.id
- },
- format: :json
+ namespace_id: project.namespace, project_id: project, id: pipeline.id
+ }, format: :json
end
it 'cancels a pipeline without returning any content', :sidekiq_might_not_need_inline do
@@ -1192,17 +1190,11 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
let(:branch_secondary) { project.repository.branches[1] }
let!(:pipeline_master) do
- create(:ci_pipeline,
- ref: branch_main.name,
- sha: branch_main.target,
- project: project)
+ create(:ci_pipeline, ref: branch_main.name, sha: branch_main.target, project: project)
end
let!(:pipeline_secondary) do
- create(:ci_pipeline,
- ref: branch_secondary.name,
- sha: branch_secondary.target,
- project: project)
+ create(:ci_pipeline, ref: branch_secondary.name, sha: branch_secondary.target, project: project)
end
before do
@@ -1455,10 +1447,9 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
private
def get_config_variables
- get :config_variables, params: { namespace_id: project.namespace,
- project_id: project,
- sha: ref },
- format: :json
+ get :config_variables, params: {
+ namespace_id: project.namespace, project_id: project, sha: ref
+ }, format: :json
end
end
diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb
index 09b9f25c0c6..91d3ba7e106 100644
--- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb
+++ b/spec/controllers/projects/prometheus/alerts_controller_spec.rb
@@ -117,10 +117,7 @@ RSpec.describe Projects::Prometheus::AlertsController do
describe 'GET #metrics_dashboard' do
let!(:alert) do
- create(:prometheus_alert,
- project: project,
- environment: environment,
- prometheus_metric: metric)
+ create(:prometheus_alert, project: project, environment: environment, prometheus_metric: metric)
end
it 'returns a json object with the correct keys' do
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index 40252cf65cd..b15a37d8d90 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -12,13 +12,9 @@ RSpec.describe Projects::RawController, feature_category: :source_code_managemen
describe 'GET #show' do
def get_show
- get(:show,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: file_path,
- inline: inline
- }.merge(params))
+ get :show, params: {
+ namespace_id: project.namespace, project_id: project, id: file_path, inline: inline
+ }.merge(params)
end
subject { get_show }
diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb
index a0d119baf16..0b1d0b75de7 100644
--- a/spec/controllers/projects/refs_controller_spec.rb
+++ b/spec/controllers/projects/refs_controller_spec.rb
@@ -54,14 +54,9 @@ RSpec.describe Projects::RefsController, feature_category: :source_code_manageme
let(:path) { 'foo/bar/baz.html' }
def default_get(format = :html)
- get :logs_tree,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: 'master',
- path: path
- },
- format: format
+ get :logs_tree, params: {
+ namespace_id: project.namespace.to_param, project_id: project, id: 'master', path: path
+ }, format: format
end
def xhr_get(format = :html, params = {})
diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb
index 59bc1ba04e7..834fdddd583 100644
--- a/spec/controllers/projects/registry/repositories_controller_spec.rb
+++ b/spec/controllers/projects/registry/repositories_controller_spec.rb
@@ -59,8 +59,7 @@ RSpec.describe Projects::Registry::RepositoriesController do
context 'when root container repository is not created' do
context 'when there are tags for this repository' do
before do
- stub_container_registry_tags(repository: :any,
- tags: %w[rc1 latest])
+ stub_container_registry_tags(repository: :any, tags: %w[rc1 latest])
end
it 'creates a root container repository' do
@@ -139,19 +138,12 @@ RSpec.describe Projects::Registry::RepositoriesController do
end
def go_to_index(format: :html, params: {})
- get :index, params: params.merge({
- namespace_id: project.namespace,
- project_id: project
- }),
- format: format
+ get :index, params: params.merge({ namespace_id: project.namespace, project_id: project }), format: format
end
def delete_repository(repository)
delete :destroy, params: {
- namespace_id: project.namespace,
- project_id: project,
- id: repository
- },
- format: :json
+ namespace_id: project.namespace, project_id: project, id: repository
+ }, format: :json
end
end
diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb
index 7b786f4a8af..afa7bd6a60d 100644
--- a/spec/controllers/projects/registry/tags_controller_spec.rb
+++ b/spec/controllers/projects/registry/tags_controller_spec.rb
@@ -76,11 +76,8 @@ RSpec.describe Projects::Registry::TagsController do
def get_tags
get :index, params: {
- namespace_id: project.namespace,
- project_id: project,
- repository_id: repository
- },
- format: :json
+ namespace_id: project.namespace, project_id: project, repository_id: repository
+ }, format: :json
end
end
@@ -121,12 +118,11 @@ RSpec.describe Projects::Registry::TagsController do
def destroy_tag(name)
post :destroy, params: {
- namespace_id: project.namespace,
- project_id: project,
- repository_id: repository,
- id: name
- },
- format: :json
+ namespace_id: project.namespace,
+ project_id: project,
+ repository_id: repository,
+ id: name
+ }, format: :json
end
end
@@ -162,12 +158,11 @@ RSpec.describe Projects::Registry::TagsController do
def bulk_destroy_tags(names)
post :bulk_destroy, params: {
- namespace_id: project.namespace,
- project_id: project,
- repository_id: repository,
- ids: names
- },
- format: :json
+ namespace_id: project.namespace,
+ project_id: project,
+ repository_id: repository,
+ ids: names
+ }, format: :json
end
end
diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
index ba917fa3a31..1c332eadc42 100644
--- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
@@ -173,12 +173,11 @@ RSpec.describe Projects::Settings::CiCdController, feature_category: :continuous
let(:params) { { ci_config_path: '' } }
subject do
- patch :update,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- project: params
- }
+ patch :update, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ project: params
+ }
end
it 'redirects to the settings page' do
@@ -241,9 +240,7 @@ RSpec.describe Projects::Settings::CiCdController, feature_category: :continuous
end
it 'creates a pipeline', :sidekiq_inline do
- project.repository.create_file(user, 'Gemfile', 'Gemfile contents',
- message: 'Add Gemfile',
- branch_name: 'master')
+ project.repository.create_file(user, 'Gemfile', 'Gemfile contents', message: 'Add Gemfile', branch_name: 'master')
expect { subject }.to change { Ci::Pipeline.count }.by(1)
end
diff --git a/spec/controllers/projects/settings/merge_requests_controller_spec.rb b/spec/controllers/projects/settings/merge_requests_controller_spec.rb
index 106ec62bea0..398fc97a00d 100644
--- a/spec/controllers/projects/settings/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/settings/merge_requests_controller_spec.rb
@@ -36,12 +36,11 @@ RSpec.describe Projects::Settings::MergeRequestsController do
merge_method: :ff
}
- put :update,
- params: {
- namespace_id: project.namespace,
- project_id: project.id,
- project: params
- }
+ put :update, params: {
+ namespace_id: project.namespace,
+ project_id: project.id,
+ project: params
+ }
expect(response).to redirect_to project_settings_merge_requests_path(project)
params.each do |param, value|
diff --git a/spec/controllers/projects/snippets/blobs_controller_spec.rb b/spec/controllers/projects/snippets/blobs_controller_spec.rb
index ca656705e07..4d12452e3d5 100644
--- a/spec/controllers/projects/snippets/blobs_controller_spec.rb
+++ b/spec/controllers/projects/snippets/blobs_controller_spec.rb
@@ -26,15 +26,14 @@ RSpec.describe Projects::Snippets::BlobsController do
let(:inline) { nil }
subject do
- get(:raw,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- snippet_id: snippet,
- path: filepath,
- ref: ref,
- inline: inline
- })
+ get :raw, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ snippet_id: snippet,
+ path: filepath,
+ ref: ref,
+ inline: inline
+ }
end
context 'with a snippet without a repository' do
diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb
index a388fc4620f..119e52480db 100644
--- a/spec/controllers/projects/snippets_controller_spec.rb
+++ b/spec/controllers/projects/snippets_controller_spec.rb
@@ -102,12 +102,11 @@ RSpec.describe Projects::SnippetsController do
project.add_maintainer(admin)
sign_in(admin)
- post :mark_as_spam,
- params: {
- namespace_id: project.namespace,
- project_id: project,
- id: snippet.id
- }
+ post :mark_as_spam, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: snippet.id
+ }
end
it 'updates the snippet', :enable_admin_mode do
diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb
index 9bc3065b6da..2b3adc719c1 100644
--- a/spec/controllers/projects/tree_controller_spec.rb
+++ b/spec/controllers/projects/tree_controller_spec.rb
@@ -21,12 +21,9 @@ RSpec.describe Projects::TreeController do
before do
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
- get(:show,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: id
- })
+ get :show, params: {
+ namespace_id: project.namespace.to_param, project_id: project, id: id
+ }
end
context "valid branch, no path" do
@@ -113,12 +110,9 @@ RSpec.describe Projects::TreeController do
allow(::Gitlab::GitalyClient).to receive(:call).and_call_original
expect(::Gitlab::GitalyClient).not_to receive(:call).with(anything, :commit_service, :find_commit, anything, anything)
- get(:show,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: id
- })
+ get :show, params: {
+ namespace_id: project.namespace.to_param, project_id: project, id: id
+ }
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -128,12 +122,9 @@ RSpec.describe Projects::TreeController do
render_views
before do
- get(:show,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: id
- })
+ get :show, params: {
+ namespace_id: project.namespace.to_param, project_id: project, id: id
+ }
end
context 'redirect to blob' do
@@ -141,8 +132,7 @@ RSpec.describe Projects::TreeController do
it 'redirects' do
redirect_url = "/#{project.full_path}/-/blob/master/README.md"
- expect(subject)
- .to redirect_to(redirect_url)
+ expect(subject).to redirect_to(redirect_url)
end
end
end
@@ -151,15 +141,14 @@ RSpec.describe Projects::TreeController do
render_views
before do
- post(:create_dir,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: 'master',
- dir_name: path,
- branch_name: branch_name,
- commit_message: 'Test commit message'
- })
+ post :create_dir, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: 'master',
+ dir_name: path,
+ branch_name: branch_name,
+ commit_message: 'Test commit message'
+ }
end
context 'successful creation' do
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 51f8a3b1197..cd6d3990309 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -508,11 +508,7 @@ RSpec.describe ProjectsController, feature_category: :projects do
it 'allows an admin user to access the page', :enable_admin_mode do
sign_in(create(:user, :admin))
- get :edit,
- params: {
- namespace_id: project.namespace.path,
- id: project.path
- }
+ get :edit, params: { namespace_id: project.namespace.path, id: project.path }
expect(response).to have_gitlab_http_status(:ok)
end
@@ -521,11 +517,7 @@ RSpec.describe ProjectsController, feature_category: :projects do
sign_in(user)
project.add_maintainer(user)
- get :edit,
- params: {
- namespace_id: project.namespace.path,
- id: project.path
- }
+ get :edit, params: { namespace_id: project.namespace.path, id: project.path }
expect(assigns(:badge_api_endpoint)).not_to be_nil
end
@@ -543,10 +535,7 @@ RSpec.describe ProjectsController, feature_category: :projects do
before do
group.add_owner(user)
- post :archive, params: {
- namespace_id: project.namespace.path,
- id: project.path
- }
+ post :archive, params: { namespace_id: project.namespace.path, id: project.path }
end
it 'archives the project' do
@@ -790,12 +779,7 @@ RSpec.describe ProjectsController, feature_category: :projects do
merge_method: :ff
}
- put :update,
- params: {
- namespace_id: project.namespace,
- id: project.id,
- project: params
- }
+ put :update, params: { namespace_id: project.namespace, id: project.id, project: params }
expect(response).to have_gitlab_http_status(:found)
params.each do |param, value|
@@ -811,22 +795,12 @@ RSpec.describe ProjectsController, feature_category: :projects do
}
expect do
- put :update,
- params: {
- namespace_id: project.namespace,
- id: project.id,
- project: params
- }
+ put :update, params: { namespace_id: project.namespace, id: project.id, project: params }
end.not_to change { project.namespace.reload }
end
def update_project(**parameters)
- put :update,
- params: {
- namespace_id: project.namespace.path,
- id: project.path,
- project: parameters
- }
+ put :update, params: { namespace_id: project.namespace.path, id: project.path, project: parameters }
end
end
@@ -850,12 +824,9 @@ RSpec.describe ProjectsController, feature_category: :projects do
it_behaves_like 'unauthorized when external service denies access' do
subject do
- put :update,
- params: {
- namespace_id: project.namespace,
- id: project,
- project: { description: 'Hello world' }
- }
+ put :update, params: {
+ namespace_id: project.namespace, id: project, project: { description: 'Hello world' }
+ }
project.reload
end
@@ -975,13 +946,9 @@ RSpec.describe ProjectsController, feature_category: :projects do
old_namespace = project.namespace
- put :transfer,
- params: {
- namespace_id: old_namespace.path,
- new_namespace_id: new_namespace_id,
- id: project.path
- },
- format: :js
+ put :transfer, params: {
+ namespace_id: old_namespace.path, new_namespace_id: new_namespace_id, id: project.path
+ }, format: :js
project.reload
@@ -994,13 +961,9 @@ RSpec.describe ProjectsController, feature_category: :projects do
it 'updates namespace' do
sign_in(admin)
- put :transfer,
- params: {
- namespace_id: project.namespace.path,
- new_namespace_id: new_namespace.id,
- id: project.path
- },
- format: :js
+ put :transfer, params: {
+ namespace_id: project.namespace.path, new_namespace_id: new_namespace.id, id: project.path
+ }, format: :js
project.reload
@@ -1120,32 +1083,19 @@ RSpec.describe ProjectsController, feature_category: :projects do
it "toggles star if user is signed in" do
sign_in(user)
expect(user.starred?(public_project)).to be_falsey
- post(:toggle_star,
- params: {
- namespace_id: public_project.namespace,
- id: public_project
- })
+
+ post :toggle_star, params: { namespace_id: public_project.namespace, id: public_project }
expect(user.starred?(public_project)).to be_truthy
- post(:toggle_star,
- params: {
- namespace_id: public_project.namespace,
- id: public_project
- })
+
+ post :toggle_star, params: { namespace_id: public_project.namespace, id: public_project }
expect(user.starred?(public_project)).to be_falsey
end
it "does nothing if user is not signed in" do
- post(:toggle_star,
- params: {
- namespace_id: project.namespace,
- id: public_project
- })
+ post :toggle_star, params: { namespace_id: project.namespace, id: public_project }
expect(user.starred?(public_project)).to be_falsey
- post(:toggle_star,
- params: {
- namespace_id: project.namespace,
- id: public_project
- })
+
+ post :toggle_star, params: { namespace_id: project.namespace, id: public_project }
expect(user.starred?(public_project)).to be_falsey
end
end
@@ -1160,12 +1110,9 @@ RSpec.describe ProjectsController, feature_category: :projects do
let(:forked_project) { fork_project(create(:project, :public), user) }
it 'removes fork from project' do
- delete(:remove_fork,
- params: {
- namespace_id: forked_project.namespace.to_param,
- id: forked_project.to_param
- },
- format: :js)
+ delete :remove_fork, params: {
+ namespace_id: forked_project.namespace.to_param, id: forked_project.to_param
+ }, format: :js
expect(forked_project.reload.forked?).to be_falsey
expect(flash[:notice]).to eq(s_('The fork relationship has been removed.'))
@@ -1177,12 +1124,9 @@ RSpec.describe ProjectsController, feature_category: :projects do
let(:unforked_project) { create(:project, namespace: user.namespace) }
it 'does nothing if project was not forked' do
- delete(:remove_fork,
- params: {
- namespace_id: unforked_project.namespace,
- id: unforked_project
- },
- format: :js)
+ delete :remove_fork, params: {
+ namespace_id: unforked_project.namespace, id: unforked_project
+ }, format: :js
expect(flash[:notice]).to be_nil
expect(response).to redirect_to(edit_project_path(unforked_project))
@@ -1191,12 +1135,10 @@ RSpec.describe ProjectsController, feature_category: :projects do
end
it "does nothing if user is not signed in" do
- delete(:remove_fork,
- params: {
- namespace_id: project.namespace,
- id: project
- },
- format: :js)
+ delete :remove_fork, params: {
+ namespace_id: project.namespace, id: project
+ }, format: :js
+
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
@@ -1289,6 +1231,19 @@ RSpec.describe ProjectsController, feature_category: :projects do
expect(response).to have_gitlab_http_status(:success)
end
end
+
+ context 'when sort param is invalid' do
+ let(:request) { get :refs, params: { namespace_id: project.namespace, id: project, sort: 'invalid' } }
+
+ it 'uses default sort by name' do
+ request
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(json_response['Branches']).to include('master')
+ expect(json_response['Tags']).to include('v1.0.0')
+ expect(json_response['Commits']).to be_nil
+ end
+ end
end
describe 'POST #preview_markdown' do
@@ -1761,12 +1716,7 @@ RSpec.describe ProjectsController, feature_category: :projects do
service_desk_enabled: true
}
- put :update,
- params: {
- namespace_id: project.namespace,
- id: project,
- project: params
- }
+ put :update, params: { namespace_id: project.namespace, id: project, project: params }
project.reload
expect(response).to have_gitlab_http_status(:found)
diff --git a/spec/controllers/registrations/welcome_controller_spec.rb b/spec/controllers/registrations/welcome_controller_spec.rb
index b5416d226e1..3c631362119 100644
--- a/spec/controllers/registrations/welcome_controller_spec.rb
+++ b/spec/controllers/registrations/welcome_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Registrations::WelcomeController, feature_category: :authentication_and_authorization do
+RSpec.describe Registrations::WelcomeController, feature_category: :system_access do
let(:user) { create(:user) }
describe '#welcome' do
@@ -57,6 +57,32 @@ RSpec.describe Registrations::WelcomeController, feature_category: :authenticati
expect(subject).not_to redirect_to(profile_two_factor_auth_path)
end
end
+
+ context 'when welcome step is completed' do
+ before do
+ user.update!(setup_for_company: true)
+ end
+
+ context 'when user is confirmed' do
+ before do
+ sign_in(user)
+ end
+
+ it { is_expected.to redirect_to dashboard_projects_path }
+ end
+
+ context 'when user is not confirmed' do
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'hard')
+
+ sign_in(user)
+
+ user.update!(confirmed_at: nil)
+ end
+
+ it { is_expected.to redirect_to user_session_path }
+ end
+ end
end
describe '#update' do
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index b217b100349..92329b10426 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -75,7 +75,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
context 'email confirmation' do
- context 'when `email_confirmation_setting` is set to `hard`' do
+ context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
end
@@ -122,7 +122,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
context 'email confirmation' do
- context 'when `email_confirmation_setting` is set to `hard`' do
+ context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
stub_feature_flags(identity_verification: false)
@@ -157,7 +157,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
stub_feature_flags(identity_verification: false)
end
- context 'when `email_confirmation_setting` is set to `off`' do
+ context 'when email confirmation setting is set to `off`' do
it 'signs the user in' do
stub_application_setting_enum('email_confirmation_setting', 'off')
@@ -166,103 +166,97 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- context 'when `email_confirmation_setting` is set to `hard`' do
+ context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
end
- context 'when soft email confirmation is not enabled' do
- before do
- stub_feature_flags(soft_email_confirmation: false)
- allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
- end
+ it 'does not authenticate the user and sends a confirmation email' do
+ expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).to be_nil
+ end
- it 'does not authenticate the user and sends a confirmation email' do
- expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
- expect(controller.current_user).to be_nil
- end
+ it 'tracks an almost there redirect' do
+ post_create
- it 'tracks an almost there redirect' do
- post_create
+ expect_snowplow_event(
+ category: described_class.name,
+ action: 'render',
+ user: User.find_by(email: base_user_params[:email])
+ )
+ end
- expect_snowplow_event(
- category: described_class.name,
- action: 'render',
- user: User.find_by(email: base_user_params[:email])
- )
- end
+ context 'when registration is triggered from an accepted invite' do
+ context 'when it is part from the initial invite email', :snowplow do
+ let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) }
- context 'when registration is triggered from an accepted invite' do
- context 'when it is part from the initial invite email', :snowplow do
- let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) }
+ let(:originating_member_id) { member.id }
+ let(:session_params) do
+ {
+ invite_email: user_params.dig(:user, :email),
+ originating_member_id: originating_member_id
+ }
+ end
- let(:originating_member_id) { member.id }
- let(:session_params) do
- {
- invite_email: user_params.dig(:user, :email),
- originating_member_id: originating_member_id
- }
+ context 'when member exists from the session key value' do
+ it 'tracks the invite acceptance' do
+ subject
+
+ expect_snowplow_event(
+ category: 'RegistrationsController',
+ action: 'accepted',
+ label: 'invite_email',
+ property: member.id.to_s,
+ user: member.reload.user
+ )
+
+ expect_snowplow_event(
+ category: 'RegistrationsController',
+ action: 'create_user',
+ label: 'invited',
+ user: member.reload.user
+ )
end
+ end
- context 'when member exists from the session key value' do
- it 'tracks the invite acceptance' do
- subject
-
- expect_snowplow_event(
- category: 'RegistrationsController',
- action: 'accepted',
- label: 'invite_email',
- property: member.id.to_s,
- user: member.reload.user
- )
-
- expect_snowplow_event(
- category: 'RegistrationsController',
- action: 'create_user',
- label: 'invited',
- user: member.reload.user
- )
- end
- end
+ context 'when member does not exist from the session key value' do
+ let(:originating_member_id) { nil }
+
+ it 'does not track invite acceptance' do
+ subject
- context 'when member does not exist from the session key value' do
- let(:originating_member_id) { nil }
-
- it 'does not track invite acceptance' do
- subject
-
- expect_no_snowplow_event(
- category: 'RegistrationsController',
- action: 'accepted',
- label: 'invite_email'
- )
-
- expect_snowplow_event(
- category: 'RegistrationsController',
- action: 'create_user',
- label: 'signup',
- user: member.reload.user
- )
- end
+ expect_no_snowplow_event(
+ category: 'RegistrationsController',
+ action: 'accepted',
+ label: 'invite_email'
+ )
+
+ expect_snowplow_event(
+ category: 'RegistrationsController',
+ action: 'create_user',
+ label: 'signup',
+ user: member.reload.user
+ )
end
end
+ end
- context 'when invite email matches email used on registration' do
- let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
+ context 'when invite email matches email used on registration' do
+ let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
- it 'signs the user in without sending a confirmation email', :aggregate_failures do
- expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
- expect(controller.current_user).to be_confirmed
- end
+ it 'signs the user in without sending a confirmation email', :aggregate_failures do
+ expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).to be_confirmed
end
+ end
- context 'when invite email does not match the email used on registration' do
- let(:session_params) { { invite_email: 'bogus@email.com' } }
+ context 'when invite email does not match the email used on registration' do
+ let(:session_params) { { invite_email: 'bogus@email.com' } }
- it 'does not authenticate the user and sends a confirmation email', :aggregate_failures do
- expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
- expect(controller.current_user).to be_nil
- end
+ it 'does not authenticate the user and sends a confirmation email', :aggregate_failures do
+ expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).to be_nil
end
end
end
@@ -286,45 +280,45 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
expect(controller.current_user).to be_nil
end
end
+ end
- context 'when soft email confirmation is enabled' do
- before do
- stub_feature_flags(soft_email_confirmation: true)
- allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
- end
+ context 'when email confirmation setting is set to `soft`' do
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
+ end
- it 'authenticates the user and sends a confirmation email' do
- expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
- expect(controller.current_user).to be_present
- expect(response).to redirect_to(users_sign_up_welcome_path)
- end
+ it 'authenticates the user and sends a confirmation email' do
+ expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).to be_present
+ expect(response).to redirect_to(users_sign_up_welcome_path)
+ end
- it 'does not track an almost there redirect' do
- post_create
+ it 'does not track an almost there redirect' do
+ post_create
- expect_no_snowplow_event(
- category: described_class.name,
- action: 'render',
- user: User.find_by(email: base_user_params[:email])
- )
- end
+ expect_no_snowplow_event(
+ category: described_class.name,
+ action: 'render',
+ user: User.find_by(email: base_user_params[:email])
+ )
+ end
- context 'when invite email matches email used on registration' do
- let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
+ context 'when invite email matches email used on registration' do
+ let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
- it 'signs the user in without sending a confirmation email', :aggregate_failures do
- expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
- expect(controller.current_user).to be_confirmed
- end
+ it 'signs the user in without sending a confirmation email', :aggregate_failures do
+ expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).to be_confirmed
end
+ end
- context 'when invite email does not match the email used on registration' do
- let(:session_params) { { invite_email: 'bogus@email.com' } }
+ context 'when invite email does not match the email used on registration' do
+ let(:session_params) { { invite_email: 'bogus@email.com' } }
- it 'authenticates the user and sends a confirmation email without confirming', :aggregate_failures do
- expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
- expect(controller.current_user).not_to be_confirmed
- end
+ it 'authenticates the user and sends a confirmation email without confirming', :aggregate_failures do
+ expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).not_to be_confirmed
end
end
end
@@ -756,8 +750,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
m.call(*args)
expect(Gitlab::ApplicationContext.current)
- .to include('meta.user' => user.username,
- 'meta.caller_id' => 'RegistrationsController#destroy')
+ .to include('meta.user' => user.username, 'meta.caller_id' => 'RegistrationsController#destroy')
end
post :destroy
diff --git a/spec/controllers/repositories/git_http_controller_spec.rb b/spec/controllers/repositories/git_http_controller_spec.rb
index da62acb1fda..276bd9b65b9 100644
--- a/spec/controllers/repositories/git_http_controller_spec.rb
+++ b/spec/controllers/repositories/git_http_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Repositories::GitHttpController do
+RSpec.describe Repositories::GitHttpController, feature_category: :source_code_management do
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository) }
let_it_be(:project_snippet) { create(:project_snippet, :public, :repository, project: project) }
@@ -14,7 +14,7 @@ RSpec.describe Repositories::GitHttpController do
request.headers.merge! auth_env(user.username, user.password, nil)
end
- context 'when Gitaly is unavailable' do
+ context 'when Gitaly is unavailable', :use_clean_rails_redis_caching do
it 'responds with a 503 message' do
expect(Gitlab::GitalyClient).to receive(:call).and_raise(GRPC::Unavailable)
@@ -26,6 +26,58 @@ RSpec.describe Repositories::GitHttpController do
end
end
+ shared_examples 'handles user activity' do
+ it 'updates the user activity' do
+ activity_project = container.is_a?(PersonalSnippet) ? nil : project
+
+ activity_service = instance_double(Users::ActivityService)
+
+ args = { author: user, project: activity_project, namespace: activity_project&.namespace }
+ expect(Users::ActivityService).to receive(:new).with(args).and_return(activity_service)
+
+ expect(activity_service).to receive(:execute)
+
+ get :info_refs, params: params
+ end
+ end
+
+ shared_examples 'handles logging git upload pack operation' do
+ before do
+ password = user.try(:password) || user.try(:token)
+ request.headers.merge! auth_env(user.username, password, nil)
+ end
+
+ context 'with git pull/fetch/clone action' do
+ let(:params) { super().merge(service: 'git-upload-pack') }
+
+ it_behaves_like 'handles user activity'
+ end
+ end
+
+ shared_examples 'handles logging git receive pack operation' do
+ let(:params) { super().merge(service: 'git-receive-pack') }
+
+ before do
+ request.headers.merge! auth_env(user.username, user.password, nil)
+ end
+
+ context 'with git push action when log_user_git_push_activity is enabled' do
+ it_behaves_like 'handles user activity'
+ end
+
+ context 'when log_user_git_push_activity is disabled' do
+ before do
+ stub_feature_flags(log_user_git_push_activity: false)
+ end
+
+ it 'does not log user activity' do
+ expect(controller).not_to receive(:log_user_activity)
+
+ get :info_refs, params: params
+ end
+ end
+ end
+
context 'when repository container is a project' do
it_behaves_like Repositories::GitHttpController do
let(:container) { project }
@@ -33,6 +85,8 @@ RSpec.describe Repositories::GitHttpController do
let(:access_checker_class) { Gitlab::GitAccess }
it_behaves_like 'handles unavailable Gitaly'
+ it_behaves_like 'handles logging git upload pack operation'
+ it_behaves_like 'handles logging git receive pack operation'
describe 'POST #git_upload_pack' do
before do
@@ -83,6 +137,8 @@ RSpec.describe Repositories::GitHttpController do
let(:container) { project }
let(:user) { create(:deploy_token, :project, projects: [project]) }
let(:access_checker_class) { Gitlab::GitAccess }
+
+ it_behaves_like 'handles logging git upload pack operation'
end
end
end
@@ -92,6 +148,9 @@ RSpec.describe Repositories::GitHttpController do
let(:container) { create(:project_wiki, :empty_repo, project: project) }
let(:user) { project.first_owner }
let(:access_checker_class) { Gitlab::GitAccessWiki }
+
+ it_behaves_like 'handles logging git upload pack operation'
+ it_behaves_like 'handles logging git receive pack operation'
end
end
@@ -102,6 +161,8 @@ RSpec.describe Repositories::GitHttpController do
let(:access_checker_class) { Gitlab::GitAccessSnippet }
it_behaves_like 'handles unavailable Gitaly'
+ it_behaves_like 'handles logging git upload pack operation'
+ it_behaves_like 'handles logging git receive pack operation'
end
end
@@ -112,6 +173,8 @@ RSpec.describe Repositories::GitHttpController do
let(:access_checker_class) { Gitlab::GitAccessSnippet }
it_behaves_like 'handles unavailable Gitaly'
+ it_behaves_like 'handles logging git upload pack operation'
+ it_behaves_like 'handles logging git receive pack operation'
end
end
end
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 0f7f4a1910b..ff24b754d7a 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -227,12 +227,10 @@ RSpec.describe SearchController, feature_category: :global_search do
let(:label) { 'redis_hll_counters.search.search_total_unique_counts_monthly' }
let(:property) { 'i_search_total' }
let(:context) do
- [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
- event: property).to_context]
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: property).to_context]
end
let(:namespace) { create(:group) }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
context 'on restricted projects' do
@@ -428,6 +426,15 @@ RSpec.describe SearchController, feature_category: :global_search do
get :autocomplete, params: { term: 'setting', filter: 'generic' }
end
+
+ it 'sets correct cache control headers' do
+ get :autocomplete, params: { term: 'setting', filter: 'generic' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(response.headers['Cache-Control']).to eq('max-age=60, private')
+ expect(response.headers['Pragma']).to be_nil
+ end
end
describe '#append_info_to_payload' do
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index 1f7d169bae5..80856512bba 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -375,8 +375,7 @@ RSpec.describe SessionsController do
context 'when OTP is valid for another user' do
it 'does not authenticate' do
- authenticate_2fa(login: another_user.username,
- otp_attempt: another_user.current_otp)
+ authenticate_2fa(login: another_user.username, otp_attempt: another_user.current_otp)
expect(subject.current_user).not_to eq another_user
end
@@ -384,8 +383,7 @@ RSpec.describe SessionsController do
context 'when OTP is invalid for another user' do
it 'does not authenticate' do
- authenticate_2fa(login: another_user.username,
- otp_attempt: 'invalid')
+ authenticate_2fa(login: another_user.username, otp_attempt: 'invalid')
expect(subject.current_user).not_to eq another_user
end
@@ -495,51 +493,49 @@ RSpec.describe SessionsController do
end
end
- context 'when using two-factor authentication via U2F device' do
- let(:user) { create(:user, :two_factor) }
+ context 'when using two-factor authentication via WebAuthn device' do
+ let(:user) { create(:user, :two_factor_via_webauthn) }
- def authenticate_2fa_u2f(user_params)
+ def authenticate_2fa(user_params)
post(:create, params: { user: user_params }, session: { otp_user_id: user.id })
end
- before do
- stub_feature_flags(webauthn: false)
- end
-
context 'remember_me field' do
it 'sets a remember_user_token cookie when enabled' do
- allow(U2fRegistration).to receive(:authenticate).and_return(true)
+ allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true)
allow(controller).to receive(:find_user).and_return(user)
- expect(controller)
- .to receive(:remember_me).with(user).and_call_original
+ expect(controller).to receive(:remember_me).with(user).and_call_original
- authenticate_2fa_u2f(remember_me: '1', login: user.username, device_response: "{}")
+ authenticate_2fa(remember_me: '1', login: user.username, device_response: "{}")
expect(response.cookies['remember_user_token']).to be_present
end
it 'does nothing when disabled' do
- allow(U2fRegistration).to receive(:authenticate).and_return(true)
+ allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true)
allow(controller).to receive(:find_user).and_return(user)
expect(controller).not_to receive(:remember_me)
- authenticate_2fa_u2f(remember_me: '0', login: user.username, device_response: "{}")
+ authenticate_2fa(remember_me: '0', login: user.username, device_response: "{}")
expect(response.cookies['remember_user_token']).to be_nil
end
end
it "creates an audit log record" do
- allow(U2fRegistration).to receive(:authenticate).and_return(true)
- expect { authenticate_2fa_u2f(login: user.username, device_response: "{}") }.to change { AuditEvent.count }.by(1)
- expect(AuditEvent.last.details[:with]).to eq("two-factor-via-u2f-device")
+ allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true)
+
+ expect { authenticate_2fa(login: user.username, device_response: "{}") }.to(
+ change { AuditEvent.count }.by(1))
+ expect(AuditEvent.last.details[:with]).to eq("two-factor-via-webauthn-device")
end
it "creates an authentication event record" do
- allow(U2fRegistration).to receive(:authenticate).and_return(true)
+ allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true)
- expect { authenticate_2fa_u2f(login: user.username, device_response: "{}") }.to change { AuthenticationEvent.count }.by(1)
- expect(AuthenticationEvent.last.provider).to eq("two-factor-via-u2f-device")
+ expect { authenticate_2fa(login: user.username, device_response: "{}") }.to(
+ change { AuthenticationEvent.count }.by(1))
+ expect(AuthenticationEvent.last.provider).to eq("two-factor-via-webauthn-device")
end
end
end
@@ -567,8 +563,7 @@ RSpec.describe SessionsController do
it 'sets the username and caller_id in the context' do
expect(controller).to receive(:destroy).and_wrap_original do |m, *args|
expect(Gitlab::ApplicationContext.current)
- .to include('meta.user' => user.username,
- 'meta.caller_id' => 'SessionsController#destroy')
+ .to include('meta.user' => user.username, 'meta.caller_id' => 'SessionsController#destroy')
m.call(*args)
end
@@ -607,8 +602,7 @@ RSpec.describe SessionsController do
m.call(*args)
end
- post(:create,
- params: { user: { login: user.username, password: user.password.succ } })
+ post :create, params: { user: { login: user.username, password: user.password.succ } }
end
end
end
diff --git a/spec/controllers/snippets/blobs_controller_spec.rb b/spec/controllers/snippets/blobs_controller_spec.rb
index b9f58587a58..b92621d4041 100644
--- a/spec/controllers/snippets/blobs_controller_spec.rb
+++ b/spec/controllers/snippets/blobs_controller_spec.rb
@@ -17,13 +17,7 @@ RSpec.describe Snippets::BlobsController do
let(:inline) { nil }
subject do
- get(:raw,
- params: {
- snippet_id: snippet,
- path: filepath,
- ref: ref,
- inline: inline
- })
+ get :raw, params: { snippet_id: snippet, path: filepath, ref: ref, inline: inline }
end
where(:snippet_visibility_level, :user, :status) do
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 6019f10eeeb..b2a62bcfbd6 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -11,9 +11,7 @@ RSpec.describe 'Database schema', feature_category: :database do
IGNORED_INDEXES_ON_FKS = {
slack_integrations_scopes: %w[slack_api_scope_id],
- # Will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/391312
- approval_project_rules: %w[scan_result_policy_id],
- approval_merge_request_rules: %w[scan_result_policy_id]
+ p_ci_builds_metadata: %w[partition_id] # composable FK, the columns are reversed in the index definition
}.with_indifferent_access.freeze
TABLE_PARTITIONS = %w[ci_builds_metadata].freeze
@@ -35,24 +33,24 @@ RSpec.describe 'Database schema', feature_category: :database do
boards: %w[milestone_id iteration_id],
chat_names: %w[chat_id team_id user_id integration_id],
chat_teams: %w[team_id],
- ci_build_needs: %w[partition_id],
+ ci_build_needs: %w[partition_id build_id],
ci_build_pending_states: %w[partition_id build_id],
- ci_build_report_results: %w[partition_id],
+ ci_build_report_results: %w[partition_id build_id],
ci_build_trace_chunks: %w[partition_id build_id],
- ci_build_trace_metadata: %w[partition_id],
+ ci_build_trace_metadata: %w[partition_id build_id],
ci_builds: %w[erased_by_id trigger_request_id partition_id],
ci_builds_runner_session: %w[partition_id build_id],
- p_ci_builds_metadata: %w[partition_id],
- ci_job_artifacts: %w[partition_id],
- ci_job_variables: %w[partition_id],
+ p_ci_builds_metadata: %w[partition_id build_id runner_machine_id],
+ ci_job_artifacts: %w[partition_id job_id],
+ ci_job_variables: %w[partition_id job_id],
ci_namespace_monthly_usages: %w[namespace_id],
- ci_pending_builds: %w[partition_id],
+ ci_pending_builds: %w[partition_id build_id],
ci_pipeline_variables: %w[partition_id],
ci_pipelines: %w[partition_id],
ci_resources: %w[partition_id build_id],
ci_runner_projects: %w[runner_id],
- ci_running_builds: %w[partition_id],
- ci_sources_pipelines: %w[partition_id source_partition_id],
+ ci_running_builds: %w[partition_id build_id],
+ ci_sources_pipelines: %w[partition_id source_partition_id source_job_id],
ci_stages: %w[partition_id],
ci_trigger_requests: %w[commit_id],
ci_unit_test_failures: %w[partition_id build_id],
@@ -91,13 +89,14 @@ RSpec.describe 'Database schema', feature_category: :database do
oauth_access_grants: %w[resource_owner_id application_id],
oauth_access_tokens: %w[resource_owner_id application_id],
oauth_applications: %w[owner_id],
+ p_ci_runner_machine_builds: %w[partition_id build_id],
product_analytics_events_experimental: %w[event_id txn_id user_id],
project_build_artifacts_size_refreshes: %w[last_job_artifact_id],
project_data_transfers: %w[project_id namespace_id],
project_error_tracking_settings: %w[sentry_project_id],
project_group_links: %w[group_id],
project_statistics: %w[namespace_id],
- projects: %w[creator_id ci_id mirror_user_id],
+ projects: %w[ci_id mirror_user_id],
redirect_routes: %w[source_id],
repository_languages: %w[programming_language_id],
routes: %w[source_id],
@@ -171,8 +170,13 @@ RSpec.describe 'Database schema', feature_category: :database do
context 'columns ending with _id' do
let(:column_names) { columns.map(&:name) }
let(:column_names_with_id) { column_names.select { |column_name| column_name.ends_with?('_id') } }
- let(:foreign_keys_columns) { all_foreign_keys.reject { |fk| fk.name&.end_with?("_p") }.map(&:column).uniq } # we can have FK and loose FK present at the same time
let(:ignored_columns) { ignored_fk_columns(table) }
+ let(:foreign_keys_columns) do
+ all_foreign_keys
+ .reject { |fk| fk.name&.end_with?("_p") || fk.name&.end_with?("_id_convert_to_bigint") }
+ .map(&:column)
+ .uniq # we can have FK and loose FK present at the same time
+ end
it 'do have the foreign keys' do
expect(column_names_with_id - ignored_columns).to match_array(foreign_keys_columns)
diff --git a/spec/deprecation_warnings.rb b/spec/deprecation_warnings.rb
new file mode 100644
index 00000000000..45fed5fecca
--- /dev/null
+++ b/spec/deprecation_warnings.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative '../lib/gitlab/utils'
+return if Gitlab::Utils.to_boolean(ENV['SILENCE_DEPRECATIONS'], default: false)
+
+# Enable deprecation warnings by default and make them more visible
+# to developers to ease upgrading to newer Ruby versions.
+Warning[:deprecated] = true
+
+# rubocop:disable Layout/LineLength
+case RUBY_VERSION[/\d+\.\d+/, 0]
+when '3.2'
+ warn "#{__FILE__}:#{__LINE__}: warning: Ignored warnings for Ruby < 3.2 are no longer necessary."
+else
+ require 'warning'
+ # Ignore Ruby warnings until Ruby 3.2.
+ # ... ruby/3.1.3/lib/ruby/gems/3.1.0/gems/rspec-parameterized-table_syntax-1.0.0/lib/rspec/parameterized/table_syntax.rb:38: warning: Refinement#include is deprecated and will be removed in Ruby 3.2
+
+ Warning.ignore(%r{rspec-parameterized-table_syntax-1\.0\.0/lib/rspec/parameterized/table_syntax\.rb:\d+: warning: Refinement#include is deprecated})
+end
+# rubocop:enable Layout/LineLength
diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb
index 7aca5e492f4..ef8f8cbce3b 100644
--- a/spec/experiments/application_experiment_spec.rb
+++ b/spec/experiments/application_experiment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ApplicationExperiment, :experiment do
+RSpec.describe ApplicationExperiment, :experiment, feature_category: :experimentation_conversion do
subject(:application_experiment) { described_class.new('namespaced/stub', **context) }
let(:context) { {} }
@@ -187,13 +187,11 @@ RSpec.describe ApplicationExperiment, :experiment do
end
with_them do
- it "returns the url or nil if invalid" do
- allow(Gitlab).to receive(:com?).and_return(true)
+ it "returns the url or nil if invalid on SaaS", :saas do
expect(application_experiment.process_redirect_url(url)).to eq(processed_url)
end
- it "considers all urls invalid when not on dev or com" do
- allow(Gitlab).to receive(:com?).and_return(false)
+ it "considers all urls invalid when not on SaaS" do
expect(application_experiment.process_redirect_url(url)).to be_nil
end
end
diff --git a/spec/factories/abuse_reports.rb b/spec/factories/abuse_reports.rb
index 355fb142994..9f05d183ba4 100644
--- a/spec/factories/abuse_reports.rb
+++ b/spec/factories/abuse_reports.rb
@@ -7,5 +7,9 @@ FactoryBot.define do
message { 'User sends spam' }
reported_from_url { 'http://gitlab.com' }
links_to_spam { ['https://gitlab.com/issue1', 'https://gitlab.com/issue2'] }
+
+ trait :closed do
+ status { 'closed' }
+ end
end
end
diff --git a/spec/factories/achievements/user_achievements.rb b/spec/factories/achievements/user_achievements.rb
new file mode 100644
index 00000000000..a5fd1df38dd
--- /dev/null
+++ b/spec/factories/achievements/user_achievements.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :user_achievement, class: 'Achievements::UserAchievement' do
+ user
+ achievement
+ awarded_by_user factory: :user
+
+ trait :revoked do
+ revoked_by_user factory: :user
+ revoked_at { Time.now }
+ end
+ end
+end
diff --git a/spec/factories/airflow/dags.rb b/spec/factories/airflow/dags.rb
deleted file mode 100644
index ca4276e2c8f..00000000000
--- a/spec/factories/airflow/dags.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-FactoryBot.define do
- factory :airflow_dags, class: '::Airflow::Dags' do
- sequence(:dag_name) { |n| "dag_name_#{n}" }
-
- project
- end
-end
diff --git a/spec/factories/bulk_import/batch_trackers.rb b/spec/factories/bulk_import/batch_trackers.rb
new file mode 100644
index 00000000000..427eefc5f3e
--- /dev/null
+++ b/spec/factories/bulk_import/batch_trackers.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :bulk_import_batch_tracker, class: 'BulkImports::BatchTracker' do
+ association :tracker, factory: :bulk_import_tracker
+
+ status { 0 }
+ fetched_objects_count { 1000 }
+ imported_objects_count { 1000 }
+
+ sequence(:batch_number) { |n| n }
+
+ trait :created do
+ status { 0 }
+ end
+
+ trait :started do
+ status { 1 }
+ end
+
+ trait :finished do
+ status { 2 }
+ end
+
+ trait :timeout do
+ status { 3 }
+ end
+
+ trait :failed do
+ status { -1 }
+ end
+
+ trait :skipped do
+ status { -2 }
+ end
+ end
+end
diff --git a/spec/factories/bulk_import/export_batches.rb b/spec/factories/bulk_import/export_batches.rb
new file mode 100644
index 00000000000..4339b02d27e
--- /dev/null
+++ b/spec/factories/bulk_import/export_batches.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :bulk_import_export_batch, class: 'BulkImports::ExportBatch' do
+ association :export, factory: :bulk_import_export
+
+ upload { association(:bulk_import_export_upload) }
+
+ status { 0 }
+
+ trait :started do
+ status { 0 }
+ end
+
+ trait :finished do
+ status { 1 }
+ end
+
+ trait :failed do
+ status { -1 }
+ end
+ end
+end
diff --git a/spec/factories/chat_names.rb b/spec/factories/chat_names.rb
index 56567394bf5..c872694ee64 100644
--- a/spec/factories/chat_names.rb
+++ b/spec/factories/chat_names.rb
@@ -3,7 +3,6 @@
FactoryBot.define do
factory :chat_name, class: 'ChatName' do
user
- integration
team_id { 'T0001' }
team_domain { 'Awesome Team' }
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 224f460488b..dc75e17499c 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -415,7 +415,7 @@ FactoryBot.define do
runner factory: :ci_runner
after(:create) do |build|
- build.create_runtime_metadata!
+ ::Ci::RunningBuild.upsert_shared_runner_build!(build)
end
end
@@ -694,7 +694,7 @@ FactoryBot.define do
end
end
- trait :non_public_artifacts do
+ trait :with_private_artifacts_config do
options do
{
artifacts: { public: false }
@@ -702,6 +702,14 @@ FactoryBot.define do
end
end
+ trait :with_public_artifacts_config do
+ options do
+ {
+ artifacts: { public: true }
+ }
+ end
+ end
+
trait :non_playable do
status { 'created' }
self.when { 'manual' }
diff --git a/spec/factories/ci/catalog/resources.rb b/spec/factories/ci/catalog/resources.rb
new file mode 100644
index 00000000000..66c2e58cdd9
--- /dev/null
+++ b/spec/factories/ci/catalog/resources.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :catalog_resource, class: 'Ci::Catalog::Resource' do
+ project factory: :project
+ end
+end
diff --git a/spec/factories/ci/runner_machine_builds.rb b/spec/factories/ci/runner_machine_builds.rb
new file mode 100644
index 00000000000..0181def26ba
--- /dev/null
+++ b/spec/factories/ci/runner_machine_builds.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :ci_runner_machine_build, class: 'Ci::RunnerMachineBuild' do
+ build factory: :ci_build, scheduling_type: :dag
+ runner_machine factory: :ci_runner_machine
+ end
+end
diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb
index 4758986b47c..a9a637b4284 100644
--- a/spec/factories/ci/runners.rb
+++ b/spec/factories/ci/runners.rb
@@ -66,6 +66,12 @@ FactoryBot.define do
end
end
+ trait :with_runner_machine do
+ after(:build) do |runner, evaluator|
+ runner.runner_machines << build(:ci_runner_machine, runner: runner)
+ end
+ end
+
trait :inactive do
active { false }
end
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index 0647058d63a..99110a9b841 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -98,15 +98,6 @@ FactoryBot.define do
cluster factory: %i(cluster with_installed_helm provided_by_gcp)
end
- factory :clusters_applications_crossplane, class: 'Clusters::Applications::Crossplane' do
- stack { 'gcp' }
- cluster factory: %i(cluster with_installed_helm provided_by_gcp)
- end
-
- factory :clusters_applications_prometheus, class: 'Clusters::Applications::Prometheus' do
- cluster factory: %i(cluster with_installed_helm provided_by_gcp)
- end
-
factory :clusters_applications_runner, class: 'Clusters::Applications::Runner' do
cluster factory: %i(cluster with_installed_helm provided_by_gcp)
end
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb
index 32cd6beb7ea..d92ee6dcbe7 100644
--- a/spec/factories/clusters/clusters.rb
+++ b/spec/factories/clusters/clusters.rb
@@ -87,15 +87,12 @@ FactoryBot.define do
end
trait :with_installed_prometheus do
- application_prometheus factory: %i(clusters_applications_prometheus installed)
integration_prometheus factory: %i(clusters_integrations_prometheus)
end
trait :with_all_applications do
application_helm factory: %i(clusters_applications_helm installed)
application_ingress factory: %i(clusters_applications_ingress installed)
- application_crossplane factory: %i(clusters_applications_crossplane installed)
- application_prometheus factory: %i(clusters_applications_prometheus installed)
application_runner factory: %i(clusters_applications_runner installed)
application_jupyter factory: %i(clusters_applications_jupyter installed)
application_knative factory: %i(clusters_applications_knative installed)
diff --git a/spec/factories/gitlab/database/async_foreign_keys/postgres_async_constraint_validation.rb b/spec/factories/gitlab/database/async_foreign_keys/postgres_async_constraint_validation.rb
new file mode 100644
index 00000000000..81f67e958c0
--- /dev/null
+++ b/spec/factories/gitlab/database/async_foreign_keys/postgres_async_constraint_validation.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :postgres_async_constraint_validation,
+ class: 'Gitlab::Database::AsyncConstraints::PostgresAsyncConstraintValidation' do
+ sequence(:name) { |n| "fk_users_id_#{n}" }
+ table_name { "users" }
+
+ trait :foreign_key do
+ constraint_type { :foreign_key }
+ end
+
+ trait :check_constraint do
+ constraint_type { :check_constraint }
+ end
+ end
+end
diff --git a/spec/factories/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb b/spec/factories/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb
deleted file mode 100644
index a61b5cde7a0..00000000000
--- a/spec/factories/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :postgres_async_foreign_key_validation,
- class: 'Gitlab::Database::AsyncForeignKeys::PostgresAsyncForeignKeyValidation' do
- sequence(:name) { |n| "fk_users_id_#{n}" }
- table_name { "users" }
- end
-end
diff --git a/spec/factories/integrations.rb b/spec/factories/integrations.rb
index 7740b2da911..caeac6e3b92 100644
--- a/spec/factories/integrations.rb
+++ b/spec/factories/integrations.rb
@@ -261,7 +261,26 @@ FactoryBot.define do
app_store_issuer_id { 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' }
app_store_key_id { 'ABC1' }
- app_store_private_key { File.read('spec/fixtures/ssl_key.pem') }
+ app_store_private_key_file_name { 'auth_key.p8' }
+ app_store_private_key { File.read('spec/fixtures/auth_key.p8') }
+ end
+
+ factory :google_play_integration, class: 'Integrations::GooglePlay' do
+ project
+ active { true }
+ type { 'Integrations::GooglePlay' }
+
+ service_account_key_file_name { 'service_account.json' }
+ service_account_key { File.read('spec/fixtures/service_account.json') }
+ end
+
+ factory :squash_tm_integration, class: 'Integrations::SquashTm' do
+ project
+ active { true }
+ type { 'Integrations::SquashTm' }
+
+ url { 'https://url-to-squash.com' }
+ token { 'squash_tm_token' }
end
# this is for testing storing values inside properties, which is deprecated and will be removed in
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 530b4616765..2a21bde5436 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -12,6 +12,7 @@ FactoryBot.define do
factory :note_on_commit, traits: [:on_commit]
factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note]
+ factory :note_on_work_item, traits: [:on_work_item]
factory :note_on_merge_request, traits: [:on_merge_request]
factory :note_on_project_snippet, traits: [:on_project_snippet]
factory :note_on_personal_snippet, traits: [:on_personal_snippet]
@@ -122,6 +123,10 @@ FactoryBot.define do
noteable { association(:issue, project: project) }
end
+ trait :on_work_item do
+ noteable { association(:work_item, project: project) }
+ end
+
trait :on_merge_request do
noteable { association(:merge_request, source_project: project) }
end
diff --git a/spec/factories/packages/debian/component_file.rb b/spec/factories/packages/debian/component_file.rb
index a2422e4a126..eefc6ab5966 100644
--- a/spec/factories/packages/debian/component_file.rb
+++ b/spec/factories/packages/debian/component_file.rb
@@ -47,5 +47,12 @@ FactoryBot.define do
trait(:object_storage) do
file_store { Packages::PackageFileUploader::Store::REMOTE }
end
+
+ trait(:empty) do
+ file_md5 { 'd41d8cd98f00b204e9800998ecf8427e' }
+ file_sha256 { 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' }
+ file_fixture { nil }
+ size { 0 }
+ end
end
end
diff --git a/spec/factories/packages/debian/file_metadatum.rb b/spec/factories/packages/debian/file_metadatum.rb
index 505b9975f79..ef6c4e1f222 100644
--- a/spec/factories/packages/debian/file_metadatum.rb
+++ b/spec/factories/packages/debian/file_metadatum.rb
@@ -30,7 +30,7 @@ FactoryBot.define do
{
'Format' => '3.0 (native)',
'Source' => package_file.package.name,
- 'Binary' => 'sample-dev, libsample0, sample-udeb',
+ 'Binary' => 'sample-dev, libsample0, sample-udeb, sample-ddeb',
'Architecture' => 'any',
'Version': package_file.package.version,
'Maintainer' => "#{FFaker::Name.name} <#{FFaker::Internet.email}>",
@@ -39,12 +39,13 @@ FactoryBot.define do
'Build-Depends' => 'debhelper-compat (= 13)',
'Package-List' => <<~EOF.rstrip,
libsample0 deb libs optional arch=any',
+ 'sample-ddeb deb libs optional arch=any',
sample-dev deb libdevel optional arch=any',
sample-udeb udeb libs optional arch=any',
EOF
- 'Checksums-Sha1' => "\nc5cfc111ea924842a89a06d5673f07dfd07de8ca 864 sample_1.2.3~alpha2.tar.xz",
- 'Checksums-Sha256' => "\n40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da 864 sample_1.2.3~alpha2.tar.xz",
- 'Files' => "\nd5ca476e4229d135a88f9c729c7606c9 864 sample_1.2.3~alpha2.tar.xz"
+ 'Checksums-Sha1' => "\n4a9cb2a7c77a68dc0fe54ba8ecef133a7c949e9d 964 sample_1.2.3~alpha2.tar.xz",
+ 'Checksums-Sha256' => "\nc9d05185ca158bb804977fa9d7b922e8a0f644a2da41f99d2787dd61b1e2e2c5 964 sample_1.2.3~alpha2.tar.xz",
+ 'Files' => "\nadc69e57cda38d9bb7c8d59cacfb6869 964 sample_1.2.3~alpha2.tar.xz"
}
end
end
@@ -109,6 +110,13 @@ FactoryBot.define do
fields { { 'a': 'b' } }
end
+ trait(:ddeb) do
+ file_type { 'ddeb' }
+ component { 'main' }
+ architecture { 'amd64' }
+ fields { { 'a': 'b' } }
+ end
+
trait(:buildinfo) do
file_type { 'buildinfo' }
component { 'main' }
diff --git a/spec/factories/packages/package_files.rb b/spec/factories/packages/package_files.rb
index 7d3dd274777..ababa8fa7f5 100644
--- a/spec/factories/packages/package_files.rb
+++ b/spec/factories/packages/package_files.rb
@@ -131,9 +131,9 @@ FactoryBot.define do
trait(:source) do
file_name { 'sample_1.2.3~alpha2.tar.xz' }
- file_md5 { 'd5ca476e4229d135a88f9c729c7606c9' }
- file_sha1 { 'c5cfc111ea924842a89a06d5673f07dfd07de8ca' }
- file_sha256 { '40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da' }
+ file_md5 { 'adc69e57cda38d9bb7c8d59cacfb6869' }
+ file_sha1 { '4a9cb2a7c77a68dc0fe54ba8ecef133a7c949e9d' }
+ file_sha256 { 'c9d05185ca158bb804977fa9d7b922e8a0f644a2da41f99d2787dd61b1e2e2c5' }
transient do
file_metadatum_trait { :source }
@@ -142,9 +142,9 @@ FactoryBot.define do
trait(:dsc) do
file_name { 'sample_1.2.3~alpha2.dsc' }
- file_md5 { 'ceccb6bb3e45ce6550b24234d4023e0f' }
- file_sha1 { '375ba20ea1789e1e90d469c3454ce49a431d0442' }
- file_sha256 { '81fc156ba937cdb6215362cc4bf6b8dc47be9b4253ba0f1a4ab10c7ea0c4c4e5' }
+ file_md5 { '629921cfc477bfa84adfd2ccaba89783' }
+ file_sha1 { '443c98a4cf4acd21e2259ae8f2d60fc9932de353' }
+ file_sha256 { 'f91070524a59bbb3a1f05a78409e92cb9ee86470b34018bc0b93bd5b2dd3868c' }
transient do
file_metadatum_trait { :dsc }
@@ -184,11 +184,22 @@ FactoryBot.define do
end
end
+ trait(:ddeb) do
+ file_name { 'sample-ddeb_1.2.3~alpha2_amd64.ddeb' }
+ file_md5 { '90d1107471eed48c73ad78b19ac83639' }
+ file_sha1 { '9c5af97cf8dfbe8126c807f540c88757f382b307' }
+ file_sha256 { 'a6bcc8a4b010f99ce0ea566ac69088e1910e754593c77f2b4942e3473e784e4d' }
+
+ transient do
+ file_metadatum_trait { :ddeb }
+ end
+ end
+
trait(:buildinfo) do
file_name { 'sample_1.2.3~alpha2_amd64.buildinfo' }
- file_md5 { '12a5ac4f16ad75f8741327ac23b4c0d7' }
- file_sha1 { '661f7507efa6fdd3763c95581d0baadb978b7ef5' }
- file_sha256 { 'd0c169e9caa5b303a914b27b5adf69768fe6687d4925905b7d0cd9c0f9d4e56c' }
+ file_md5 { 'cc07ff4d741aec132816f9bd67c6875d' }
+ file_sha1 { 'bcc4ca85f17a31066b726cd4e04485ab24a682c6' }
+ file_sha256 { '5a3dac17c4ff0d49fa5f47baa973902b59ad2ee05147062b8ed8f19d196731d1' }
transient do
file_metadatum_trait { :buildinfo }
diff --git a/spec/factories/packages/packages.rb b/spec/factories/packages/packages.rb
index d0fde0a16cd..1d5119638ca 100644
--- a/spec/factories/packages/packages.rb
+++ b/spec/factories/packages/packages.rb
@@ -91,6 +91,7 @@ FactoryBot.define do
create :debian_package_file, :deb, evaluator.file_metadatum_trait, package: package
create :debian_package_file, :deb_dev, evaluator.file_metadatum_trait, package: package
create :debian_package_file, :udeb, evaluator.file_metadatum_trait, package: package
+ create :debian_package_file, :ddeb, evaluator.file_metadatum_trait, package: package
create :debian_package_file, :buildinfo, evaluator.file_metadatum_trait, package: package
create :debian_package_file, :changes, evaluator.file_metadatum_trait, package: package
end
diff --git a/spec/factories/project_error_tracking_settings.rb b/spec/factories/project_error_tracking_settings.rb
index a8ad1af6345..dc0277cb58d 100644
--- a/spec/factories/project_error_tracking_settings.rb
+++ b/spec/factories/project_error_tracking_settings.rb
@@ -16,7 +16,12 @@ FactoryBot.define do
end
trait :integrated do
+ api_url { nil }
integrated { true }
+ token { nil }
+ project_name { nil }
+ organization_name { nil }
+ sentry_project_id { nil }
end
end
end
diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb
index 946b3925ee9..a7f562df92d 100644
--- a/spec/factories/project_hooks.rb
+++ b/spec/factories/project_hooks.rb
@@ -35,7 +35,7 @@ FactoryBot.define do
end
trait :permanently_disabled do
- recent_failures { WebHook::FAILURE_THRESHOLD + 1 }
+ recent_failures { WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1 }
end
end
end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index f113ca2425f..299dd165807 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -222,7 +222,7 @@ FactoryBot.define do
# the transient `files` attribute. Each file will be created in its own
# commit, operating against the master branch. So, the following call:
#
- # create(:project, :custom_repo, files: { 'foo/a.txt' => 'foo', 'b.txt' => bar' })
+ # create(:project, :custom_repo, files: { 'foo/a.txt' => 'foo', 'b.txt' => 'bar' })
#
# will create a repository containing two files, and two commits, in master
trait :custom_repo do
@@ -245,6 +245,19 @@ FactoryBot.define do
end
end
+ # A basic repository with a single file 'test.txt'. It also has the HEAD as the default branch.
+ trait :small_repo do
+ custom_repo
+
+ files { { 'test.txt' => 'test' } }
+
+ after(:create) do |project|
+ Sidekiq::Worker.skipping_transaction_check do
+ raise "Failed to assign the repository head!" unless project.change_head(project.default_branch_or_main)
+ end
+ end
+ end
+
# Test repository - https://gitlab.com/gitlab-org/gitlab-test
trait :repository do
test_repo
@@ -354,6 +367,18 @@ FactoryBot.define do
end
end
+ trait :stubbed_commit_count do
+ after(:build) do |project|
+ stub_method(project.repository, :commit_count) { 2 }
+ end
+ end
+
+ trait :stubbed_branch_count do
+ after(:build) do |project|
+ stub_method(project.repository, :branch_count) { 2 }
+ end
+ end
+
trait :wiki_repo do
after(:create) do |project|
stub_feature_flags(main_branch_over_master: false)
diff --git a/spec/factories/serverless/domain.rb b/spec/factories/serverless/domain.rb
deleted file mode 100644
index c09af068d19..00000000000
--- a/spec/factories/serverless/domain.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :serverless_domain, class: '::Serverless::Domain' do
- function_name { 'test-function' }
- serverless_domain_cluster { association(:serverless_domain_cluster) }
- environment { association(:environment) }
-
- skip_create
- end
-end
diff --git a/spec/factories/serverless/domain_cluster.rb b/spec/factories/serverless/domain_cluster.rb
deleted file mode 100644
index e8ff6cf42b2..00000000000
--- a/spec/factories/serverless/domain_cluster.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :serverless_domain_cluster, class: '::Serverless::DomainCluster' do
- pages_domain { association(:pages_domain) }
- knative { association(:clusters_applications_knative) }
- creator { association(:user) }
-
- certificate do
- File.read(Rails.root.join('spec/fixtures/', 'ssl_certificate.pem'))
- end
-
- key do
- File.read(Rails.root.join('spec/fixtures/', 'ssl_key.pem'))
- end
- end
-end
diff --git a/spec/factories/service_desk/custom_email_verification.rb b/spec/factories/service_desk/custom_email_verification.rb
new file mode 100644
index 00000000000..614be5da71e
--- /dev/null
+++ b/spec/factories/service_desk/custom_email_verification.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :service_desk_custom_email_verification, class: '::ServiceDesk::CustomEmailVerification' do
+ project
+ state { "running" }
+ end
+end
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index e641f925758..10de7bc3b5b 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -10,6 +10,7 @@ FactoryBot.define do
confirmed_at { Time.now }
confirmation_token { nil }
can_create_group { true }
+ color_scheme_id { 1 }
trait :admin do
admin { true }
@@ -59,6 +60,10 @@ FactoryBot.define do
user_type { :project_bot }
end
+ trait :service_account do
+ user_type { :service_account }
+ end
+
trait :migration_bot do
user_type { :migration_bot }
end
diff --git a/spec/factories/users/banned_users.rb b/spec/factories/users/banned_users.rb
new file mode 100644
index 00000000000..f2b6eb5893a
--- /dev/null
+++ b/spec/factories/users/banned_users.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :banned_user, class: 'Users::BannedUser' do
+ user { association(:user) }
+ end
+end
diff --git a/spec/factories/work_items.rb b/spec/factories/work_items.rb
index cff246d4071..3cb4d8cd8bc 100644
--- a/spec/factories/work_items.rb
+++ b/spec/factories/work_items.rb
@@ -37,5 +37,12 @@ FactoryBot.define do
issue_type { :key_result }
association :work_item_type, :default, :key_result
end
+
+ before(:create, :build) do |work_item, evaluator|
+ if evaluator.namespace.present?
+ work_item.project = nil
+ work_item.namespace = evaluator.namespace
+ end
+ end
end
end
diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb
index 0df771b4025..fcf0c43243f 100644
--- a/spec/fast_spec_helper.rb
+++ b/spec/fast_spec_helper.rb
@@ -11,34 +11,24 @@ require_relative '../config/bundler_setup'
ENV['GITLAB_ENV'] = 'test'
ENV['IN_MEMORY_APPLICATION_SETTINGS'] = 'true'
+require './spec/deprecation_warnings'
+
# Enable zero monkey patching mode before loading any other RSpec code.
RSpec.configure(&:disable_monkey_patching!)
-require 'active_support/dependencies'
-require_relative '../config/initializers/0_inject_enterprise_edition_module'
+require 'active_support/all'
+require 'pry'
+require_relative 'rails_autoload'
+
require_relative '../config/settings'
require_relative 'support/rspec'
require_relative '../lib/gitlab/utils'
require_relative '../lib/gitlab/utils/strong_memoize'
-require 'active_support/all'
-require 'pry'
require_relative 'simplecov_env'
SimpleCovEnv.start!
-unless ActiveSupport::Dependencies.autoload_paths.frozen?
- ActiveSupport::Dependencies.autoload_paths << 'lib'
- ActiveSupport::Dependencies.autoload_paths << 'ee/lib'
- ActiveSupport::Dependencies.autoload_paths << 'jh/lib'
-end
-
ActiveSupport::XmlMini.backend = 'Nokogiri'
-RSpec.configure do |config|
- # Makes diffs show entire non-truncated values.
- config.before(:each, unlimited_max_formatted_output_length: true) do |_example|
- config.expect_with :rspec do |c|
- c.max_formatted_output_length = nil
- end
- end
-end
+# Consider tweaking configuration in `spec/support/rspec.rb` which is also
+# used by `spec/spec_helper.rb`.
diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb
index 1267025a7bf..474ab4c7b8e 100644
--- a/spec/features/abuse_report_spec.rb
+++ b/spec/features/abuse_report_spec.rb
@@ -15,25 +15,6 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
end
describe 'report abuse to administrator' do
- shared_examples 'reports the user with an abuse category' do
- it do
- fill_and_submit_abuse_category_form
- fill_and_submit_report_abuse_form
-
- expect(page).to have_content 'Thank you for your report'
- end
- end
-
- shared_examples 'reports the user without an abuse category' do
- it do
- click_link 'Report abuse to administrator'
-
- fill_and_submit_report_abuse_form
-
- expect(page).to have_content 'Thank you for your report'
- end
- end
-
context 'when reporting an issue for abuse' do
before do
visit project_issue_path(project, issue)
diff --git a/spec/features/action_cable_logging_spec.rb b/spec/features/action_cable_logging_spec.rb
index c02a41c4c59..c8a4e1efb7a 100644
--- a/spec/features/action_cable_logging_spec.rb
+++ b/spec/features/action_cable_logging_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'ActionCable logging', :js, feature_category: :not_owned do
+RSpec.describe 'ActionCable logging', :js, feature_category: :shared do
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb
index 10f12d7116f..9fe72b981f1 100644
--- a/spec/features/admin/admin_abuse_reports_spec.rb
+++ b/spec/features/admin/admin_abuse_reports_spec.rb
@@ -2,79 +2,210 @@
require 'spec_helper'
-RSpec.describe "Admin::AbuseReports", :js, feature_category: :not_owned do
- let(:user) { create(:user) }
+RSpec.describe "Admin::AbuseReports", :js, feature_category: :shared do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:admin) { create(:admin) }
context 'as an admin' do
- before do
- admin = create(:admin)
- sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
- end
+ describe 'displayed reports' do
+ include FilteredSearchHelpers
- describe 'if a user has been reported for abuse' do
- let!(:abuse_report) { create(:abuse_report, user: user) }
+ let_it_be(:open_report) { create(:abuse_report, created_at: 5.days.ago, updated_at: 2.days.ago) }
+ let_it_be(:open_report2) { create(:abuse_report, created_at: 4.days.ago, updated_at: 3.days.ago, category: 'phishing') }
+ let_it_be(:closed_report) { create(:abuse_report, :closed) }
- describe 'in the abuse report view' do
- it 'presents information about abuse report' do
- visit admin_abuse_reports_path
+ let(:abuse_report_row_selector) { '[data-testid="abuse-report-row"]' }
- expect(page).to have_content('Abuse Reports')
- expect(page).to have_content(abuse_report.message)
- expect(page).to have_link(user.name, href: user_path(user))
- expect(page).to have_link('Remove user')
- end
+ before do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+
+ visit admin_abuse_reports_path
end
- describe 'in the profile page of the user' do
- it 'shows a link to the admin view of the user' do
- visit user_path(user)
+ it 'only includes open reports by default' do
+ expect_displayed_reports_count(2)
- expect(page).to have_link '', href: admin_user_path(user)
+ 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
- end
- describe 'if a many users have been reported for abuse' do
- let(:report_count) { AbuseReport.default_per_page + 3 }
+ 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)
- before do
- report_count.times do
- create(:abuse_report, user: create(:user))
+ 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)
+
+ # filter by reporter
+ filter(['Reporter', open_report.reporter.username])
+
+ expect_displayed_reports_count(1)
+ expect_report_shown(open_report)
+ expect_report_not_shown(open_report2, closed_report)
+
+ # filter by category
+ filter(['Category', open_report2.category])
+
+ expect_displayed_reports_count(1)
+ expect_report_shown(open_report2)
+ expect_report_not_shown(open_report, closed_report)
+ end
+
+ it 'can be sorted by created_at and updated_at in desc and asc order', :aggregate_failures do
+ # created_at desc (default)
+ 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))
+
+ # updated_at ascending
+ sort_by 'Updated date'
+
+ expect(report_rows[0].text).to include(report_text(open_report2))
+ expect(report_rows[1].text).to include(report_text(open_report))
+
+ # updated_at descending
+ 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
+
+ def report_rows
+ page.all(abuse_report_row_selector)
+ end
+
+ def report_text(report)
+ "#{report.user.name} reported for #{report.category}"
+ end
+
+ def expect_report_shown(*reports)
+ reports.each do |r|
+ expect(page).to have_content(report_text(r))
end
end
- describe 'in the abuse report view' do
- it 'presents information about abuse report' do
- visit admin_abuse_reports_path
+ def expect_report_not_shown(*reports)
+ reports.each do |r|
+ expect(page).not_to have_content(report_text(r))
+ end
+ end
- 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)
+ def expect_displayed_reports_count(count)
+ expect(page).to have_css(abuse_report_row_selector, count: count)
+ end
+
+ def filter(tokens)
+ # remove all existing filters first
+ page.find_all('.gl-token-close').each(&:click)
+
+ select_tokens(*tokens, submit: true, input_text: 'Filter reports')
+ end
+
+ def sort_by(sort)
+ page.within('.vue-filtered-search-bar-container .sort-dropdown-container') do
+ page.find('.gl-dropdown-toggle').click
+
+ page.within('.dropdown-menu') do
+ click_button sort
+ wait_for_requests
+ end
end
end
end
- describe 'filtering by user' do
- let!(:user2) { create(:user) }
- let!(:abuse_report) { create(:abuse_report, user: user) }
- let!(:abuse_report_2) { create(:abuse_report, user: user2) }
+ context 'when abuse_reports_list feature flag is disabled' do
+ before do
+ stub_feature_flags(abuse_reports_list: false)
+
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ end
+
+ describe 'if a user has been reported for abuse' do
+ let!(:abuse_report) { create(:abuse_report, user: user) }
- it 'shows only single user report' do
- visit admin_abuse_reports_path
+ describe 'in the abuse report view' do
+ it 'presents information about abuse report' do
+ visit admin_abuse_reports_path
+
+ expect(page).to have_content('Abuse Reports')
+ expect(page).to have_content(abuse_report.message)
+ expect(page).to have_link(user.name, href: user_path(user))
+ expect(page).to have_link('Remove user')
+ end
+ end
+
+ describe 'in the profile page of the user' do
+ it 'shows a link to the admin view of the user' do
+ visit user_path(user)
- page.within '.filter-form' do
- click_button 'User'
- wait_for_requests
+ expect(page).to have_link '', href: admin_user_path(user)
+ end
+ end
+ end
+
+ describe 'if a many users have been reported for abuse' do
+ let(:report_count) { AbuseReport.default_per_page + 3 }
- page.within '.dropdown-menu-user' do
- click_link user2.name
+ before do
+ report_count.times do
+ create(:abuse_report, user: create(:user))
end
+ end
+
+ describe 'in the abuse report view' do
+ it 'presents information about abuse report' do
+ visit admin_abuse_reports_path
- wait_for_requests
+ 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
+ end
- expect(page).to have_content(user2.name)
- expect(page).not_to have_content(user.name)
+ describe 'filtering by user' do
+ let!(:user2) { create(:user) }
+ let!(:abuse_report) { create(:abuse_report, user: user) }
+ let!(:abuse_report_2) { create(:abuse_report, user: user2) }
+
+ it 'shows only single user report' 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 user2.name
+ end
+
+ wait_for_requests
+ end
+
+ expect(page).to have_content(user2.name)
+ expect(page).not_to have_content(user.name)
+ end
end
end
end
diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb
index 252d9ac5bac..fee75496a1e 100644
--- a/spec/features/admin/admin_appearance_spec.rb
+++ b/spec/features/admin/admin_appearance_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin Appearance', feature_category: :not_owned do
+RSpec.describe 'Admin Appearance', feature_category: :shared do
let!(:appearance) { create(:appearance) }
let(:admin) { create(:admin) }
diff --git a/spec/features/admin/admin_browse_spam_logs_spec.rb b/spec/features/admin/admin_browse_spam_logs_spec.rb
index 461c9d08273..c272a8630b7 100644
--- a/spec/features/admin/admin_browse_spam_logs_spec.rb
+++ b/spec/features/admin/admin_browse_spam_logs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin browse spam logs', feature_category: :not_owned do
+RSpec.describe 'Admin browse spam logs', feature_category: :shared do
let!(:spam_log) { create(:spam_log, description: 'abcde ' * 20) }
before do
diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb
index e55e1cce6b9..f59b4db5cc2 100644
--- a/spec/features/admin/admin_deploy_keys_spec.rb
+++ b/spec/features/admin/admin_deploy_keys_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'admin deploy keys', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'admin deploy keys', :js, feature_category: :system_access do
include Spec::Support::Helpers::ModalHelpers
let_it_be(:admin) { create(:admin) }
diff --git a/spec/features/admin/admin_health_check_spec.rb b/spec/features/admin/admin_health_check_spec.rb
index de71a48d2dc..23a9ab74a7a 100644
--- a/spec/features/admin/admin_health_check_spec.rb
+++ b/spec/features/admin/admin_health_check_spec.rb
@@ -2,8 +2,9 @@
require 'spec_helper'
-RSpec.describe "Admin Health Check", feature_category: :continuous_verification do
+RSpec.describe "Admin Health Check", :js, feature_category: :continuous_verification do
include StubENV
+ include Spec::Support::Helpers::ModalHelpers
let_it_be(:admin) { create(:admin) }
before do
@@ -30,7 +31,8 @@ RSpec.describe "Admin Health Check", feature_category: :continuous_verification
describe 'reload access token' do
it 'changes the access token' do
orig_token = Gitlab::CurrentSettings.health_check_access_token
- click_button 'Reset health check access token'
+ click_link 'Reset health check access token'
+ accept_gl_confirm('Are you sure you want to reset the health check token?')
expect(page).to have_content('New health check access token has been generated!')
expect(find('#health-check-token').text).not_to eq orig_token
diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb
index 393721fe451..853e4763872 100644
--- a/spec/features/admin/admin_mode/login_spec.rb
+++ b/spec/features/admin/admin_mode/login_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authorization do
+RSpec.describe 'Admin Mode Login', feature_category: :system_access do
include TermsHelper
include UserLoginHelper
include LdapHelpers
@@ -25,13 +25,13 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
it 'blocks login if we reuse the same code immediately' do
gitlab_sign_in(user, remember: true)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
repeated_otp = user.current_otp
enter_code(repeated_otp)
gitlab_enable_admin_mode_sign_in(user)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
enter_code(repeated_otp)
@@ -43,12 +43,12 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
before do
gitlab_sign_in(user, remember: true)
- expect(page).to have_content('Two-factor authentication code')
+ expect(page).to have_content('Enter verification code')
enter_code(user.current_otp)
gitlab_enable_admin_mode_sign_in(user)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
end
it 'allows login with valid code' do
@@ -145,11 +145,11 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
it 'signs user in without prompting for second factor' do
sign_in_using_saml!
- expect(page).not_to have_content('Two-Factor Authentication')
+ expect(page).not_to have_content(_('Enter verification code'))
enable_admin_mode_using_saml!
- expect(page).not_to have_content('Two-Factor Authentication')
+ expect(page).not_to have_content(_('Enter verification code'))
expect(page).to have_current_path admin_root_path, ignore_query: true
expect(page).to have_content('Admin mode enabled')
end
@@ -159,12 +159,12 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
it 'shows 2FA prompt after omniauth login' do
sign_in_using_saml!
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
enter_code(user.current_otp)
enable_admin_mode_using_saml!
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
# Cannot reuse the TOTP
travel_to(30.seconds.from_now) do
@@ -210,12 +210,12 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori
context 'when two factor authentication is required' do
it 'shows 2FA prompt after ldap login' do
sign_in_using_ldap!(user, provider_label)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
enter_code(user.current_otp)
enable_admin_mode_using_ldap!(user)
- expect(page).to have_content('Two-Factor Authentication')
+ expect(page).to have_content(_('Enter verification code'))
# Cannot reuse the TOTP
travel_to(30.seconds.from_now) do
diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb
index f4e8941d25a..25f77da4401 100644
--- a/spec/features/admin/admin_mode/logout_spec.rb
+++ b/spec/features/admin/admin_mode/logout_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin Mode Logout', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'Admin Mode Logout', :js, feature_category: :system_access do
include TermsHelper
include UserLoginHelper
include Spec::Support::Helpers::Features::TopNavSpecHelpers
diff --git a/spec/features/admin/admin_mode/workers_spec.rb b/spec/features/admin/admin_mode/workers_spec.rb
index f3639fd0800..305927663e9 100644
--- a/spec/features/admin/admin_mode/workers_spec.rb
+++ b/spec/features/admin/admin_mode/workers_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# Test an operation that triggers background jobs requiring administrative rights
-RSpec.describe 'Admin mode for workers', :request_store, feature_category: :authentication_and_authorization do
+RSpec.describe 'Admin mode for workers', :request_store, feature_category: :system_access do
include Spec::Support::Helpers::Features::AdminUsersHelpers
let(:user) { create(:user) }
diff --git a/spec/features/admin/admin_mode_spec.rb b/spec/features/admin/admin_mode_spec.rb
index 769ff75b5a2..3c47a991fd1 100644
--- a/spec/features/admin/admin_mode_spec.rb
+++ b/spec/features/admin/admin_mode_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin mode', :js, feature_category: :not_owned do
+RSpec.describe 'Admin mode', :js, feature_category: :shared do
include MobileHelpers
include Spec::Support::Helpers::Features::TopNavSpecHelpers
include StubENV
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index f08e6521184..405a254dc84 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -161,4 +161,29 @@ RSpec.describe "Admin::Projects", feature_category: :projects do
expect(page).to have_current_path(dashboard_projects_path, ignore_query: true, url: false)
end
end
+
+ describe 'project edit' do
+ it 'updates project details' do
+ project = create(:project, :private, name: 'Garfield', description: 'Funny Cat')
+
+ visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param })
+
+ aggregate_failures do
+ expect(page).to have_content(project.name)
+ expect(page).to have_content(project.description)
+ end
+
+ fill_in 'Project name', with: 'Scooby-Doo'
+ fill_in 'Project description (optional)', with: 'Funny Dog'
+
+ click_button 'Save changes'
+
+ visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param })
+
+ aggregate_failures do
+ expect(page).to have_content('Scooby-Doo')
+ expect(page).to have_content('Funny Dog')
+ end
+ end
+ end
end
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 04dc206f052..d9867c2e704 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -23,8 +23,6 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
describe "runners creation" do
before do
- stub_feature_flags(create_runner_workflow: true)
-
visit admin_runners_path
end
@@ -35,7 +33,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
describe "runners registration" do
before do
- stub_feature_flags(create_runner_workflow: false)
+ stub_feature_flags(create_runner_workflow_for_admin: false)
visit admin_runners_path
end
@@ -493,6 +491,29 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
end
end
+ describe "Runner create page", :js do
+ before do
+ visit new_admin_runner_path
+ end
+
+ context 'when runner is saved' do
+ before do
+ fill_in s_('Runners|Runner description'), with: 'runner-foo'
+ fill_in s_('Runners|Tags'), with: 'tag1'
+ click_on _('Submit')
+ wait_for_requests
+ end
+
+ it 'navigates to registration page and opens install instructions drawer' do
+ expect(page.find('[data-testid="alert-success"]')).to have_content(s_('Runners|Runner created.'))
+ expect(current_url).to match(register_admin_runner_path(Ci::Runner.last))
+
+ click_on 'How do I install GitLab Runner?'
+ expect(page.find('[data-testid="runner-platforms-drawer"]')).to have_content('gitlab-runner install')
+ end
+ end
+ end
+
describe "Runner show page", :js do
let_it_be(:runner) do
create(
diff --git a/spec/features/admin/admin_sees_background_migrations_spec.rb b/spec/features/admin/admin_sees_background_migrations_spec.rb
index cad1bf74d2e..77266e65e4c 100644
--- a/spec/features/admin/admin_sees_background_migrations_spec.rb
+++ b/spec/features/admin/admin_sees_background_migrations_spec.rb
@@ -191,7 +191,7 @@ RSpec.describe "Admin > Admin sees background migrations", feature_category: :da
visit admin_background_migrations_path
within '#content-body' do
- expect(page).to have_link('Learn more', href: help_page_path('user/admin_area/monitoring/background_migrations'))
+ expect(page).to have_link('Learn more', href: help_page_path('update/background_migrations'))
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 26efed85513..3a1aa36208e 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin updates settings', feature_category: :not_owned do
+RSpec.describe 'Admin updates settings', feature_category: :shared do
include StubENV
include TermsHelper
include UsageDataHelpers
@@ -666,11 +666,11 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
visit network_admin_application_settings_path
page.within('.as-outbound') do
- check 'Allow requests to the local network from web hooks and services'
+ check 'Allow requests to the local network from webhooks and integrations'
# Enabled by default
uncheck 'Allow requests to the local network from system hooks'
# Enabled by default
- uncheck 'Enforce DNS rebinding attack protection'
+ uncheck 'Enforce DNS-rebinding attack protection'
click_button 'Save changes'
end
@@ -762,6 +762,18 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
expect(current_settings.users_get_by_id_limit_allowlist).to eq(%w[someone someone_else])
end
+ it 'changes Projects API rate limits settings' do
+ visit network_admin_application_settings_path
+
+ page.within('.as-projects-api-limits') do
+ fill_in 'Maximum requests per 10 minutes per IP address', with: 100
+ click_button 'Save changes'
+ end
+
+ expect(page).to have_content "Application settings saved successfully"
+ expect(current_settings.projects_api_rate_limit_unauthenticated).to eq(100)
+ end
+
shared_examples 'regular throttle rate limit settings' do
it 'changes rate limit settings' do
visit network_admin_application_settings_path
diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb
index 6c4a316ae77..21a001f12c3 100644
--- a/spec/features/admin/admin_system_info_spec.rb
+++ b/spec/features/admin/admin_system_info_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin System Info', feature_category: :not_owned do
+RSpec.describe 'Admin System Info', feature_category: :shared do
before do
admin = create(:admin)
sign_in(admin)
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 5e6cc206883..342e23d0cab 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Admin > Users > Impersonation Tokens', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'Admin > Users > Impersonation Tokens', :js, feature_category: :system_access do
include Spec::Support::Helpers::ModalHelpers
include Spec::Support::Helpers::AccessTokenHelpers
diff --git a/spec/features/admin_variables_spec.rb b/spec/features/admin_variables_spec.rb
index d1adbf59984..274e62defd9 100644
--- a/spec/features/admin_variables_spec.rb
+++ b/spec/features/admin_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Instance variables', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Instance variables', :js, feature_category: :pipeline_composition do
let(:admin) { create(:admin) }
let(:page_path) { ci_cd_admin_application_settings_path }
@@ -12,9 +12,21 @@ RSpec.describe 'Instance variables', :js, feature_category: :pipeline_authoring
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
+
visit page_path
wait_for_requests
end
- it_behaves_like 'variable list', isAdmin: true
+ context 'when ci_variables_pages FF is enabled' do
+ it_behaves_like 'variable list', is_admin: true
+ it_behaves_like 'variable list pagination', :ci_instance_variable
+ end
+
+ context 'when ci_variables_pages FF is disabled' do
+ before do
+ stub_feature_flags(ci_variables_pages: false)
+ end
+
+ it_behaves_like 'variable list', is_admin: true
+ end
end
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index 3e2e391d060..1ea6e079104 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -150,8 +150,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do
find('.board .board-list')
inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
- evaluate_script("window.scrollTo(0, document.body.scrollHeight)")
- evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
+ evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()")
end
expect(page).to have_selector('.board-card', count: 20)
@@ -160,8 +159,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do
find('.board .board-list')
inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
- evaluate_script("window.scrollTo(0, document.body.scrollHeight)")
- evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
+ evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()")
end
expect(page).to have_selector('.board-card', count: 30)
@@ -170,8 +168,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do
find('.board .board-list')
inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
- evaluate_script("window.scrollTo(0, document.body.scrollHeight)")
- evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
+ evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()")
end
expect(page).to have_selector('.board-card', count: 38)
@@ -594,7 +591,9 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do
def remove_list
page.within(find('.board:nth-child(2)')) do
- find('button[title="List settings"]').click
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button('Edit list settings')
end
page.within(find('.js-board-settings-sidebar')) do
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index d597c57ac1c..6753f0ea009 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -32,18 +32,23 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
end
it 'displays new issue button' do
- expect(first('.board')).to have_button('New issue', count: 1)
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ expect(first('.board')).to have_button('Create new issue', count: 1)
end
it 'does not display new issue button in closed list' do
page.within('.board:nth-child(3)') do
- expect(page).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(page).not_to have_button('Create new issue')
end
end
it 'shows form when clicking button' do
page.within(first('.board')) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
expect(page).to have_selector('.board-new-issue-form')
end
@@ -51,7 +56,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
it 'hides form when clicking cancel' do
page.within(first('.board')) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
expect(page).to have_selector('.board-new-issue-form')
@@ -63,7 +70,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
it 'creates new issue, places it on top of the list, and opens sidebar' do
page.within(first('.board')) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
end
page.within(first('.board-new-issue-form')) do
@@ -91,7 +100,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
it 'successfuly loads labels to be added to newly created issue' do
page.within(first('.board')) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
end
page.within(first('.board-new-issue-form')) do
@@ -121,7 +132,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
wait_for_all_requests
page.within('.board:nth-child(2)') do
- click_button('New issue')
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button('Create new issue')
page.within(first('.board-new-issue-form')) do
find('.form-control').set('new issue')
@@ -144,12 +157,14 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
end
it 'does not display new issue button in open list' do
- expect(first('.board')).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(first('.board')).not_to have_button('Create new issue')
end
it 'does not display new issue button in label list' do
page.within('.board:nth-child(2)') do
- expect(page).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(page).not_to have_button('Create new issue')
end
end
end
@@ -173,7 +188,8 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
context 'when backlog does not exist' do
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
- expect(page).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(page).not_to have_button('Create new issue')
end
end
end
@@ -182,12 +198,14 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
let_it_be(:backlog_list) { create(:backlog_list, board: group_board) }
it 'does not display new issue button in open list' do
- expect(first('.board')).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(first('.board')).not_to have_button('Create new issue')
end
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
- expect(page).not_to have_button('New issue')
+ expect(page).not_to have_selector("[data-testid='header-list-actions']")
+ expect(page).not_to have_button('Create new issue')
end
end
end
@@ -205,7 +223,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
context 'when backlog does not exist' do
it 'display new issue button in label list' do
- expect(board_list_header).to have_button('New issue')
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ expect(board_list_header).to have_button('Create new issue')
end
end
@@ -214,7 +234,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d
before do
page.within(board_list_header) do
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ click_button 'Create new issue'
end
project_select_dropdown.click
diff --git a/spec/features/breadcrumbs_schema_markup_spec.rb b/spec/features/breadcrumbs_schema_markup_spec.rb
index d924423c9a9..6610519cd24 100644
--- a/spec/features/breadcrumbs_schema_markup_spec.rb
+++ b/spec/features/breadcrumbs_schema_markup_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures, feature_category: :not_owned do
+RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures, feature_category: :shared do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, namespace: user.namespace) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index b2a29c88b68..67baed5dc91 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -44,15 +44,25 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do
"#{get_cell_level_selector(contributions)}[title='#{contribution_text}<br /><span class=\"gl-text-gray-300\">#{date}</span>']"
end
+ def get_days_of_week
+ page.all('[data-testid="user-contrib-cell-group"]')[1]
+ .all('[data-testid="user-contrib-cell"]')
+ .map do |node|
+ node[:title].match(/(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)/)[0]
+ end
+ end
+
def push_code_contribution
event = create(:push_event, project: contributed_project, author: user)
- create(:push_event_payload,
- event: event,
- commit_from: '11f9ac0a48b62cef25eedede4c1819964f08d5ce',
- commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2',
- commit_count: 3,
- ref: 'master')
+ create(
+ :push_event_payload,
+ event: event,
+ commit_from: '11f9ac0a48b62cef25eedede4c1819964f08d5ce',
+ commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2',
+ commit_count: 3,
+ ref: 'master'
+ )
end
def note_comment_contribution
@@ -70,162 +80,331 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do
find('#js-overview .user-calendar-activities', visible: visible).text
end
- before do
- stub_feature_flags(profile_tabs_vue: false)
- sign_in user
- end
-
- describe 'calendar day selection' do
+ shared_context 'when user page is visited' do
before do
visit user.username
- page.find('.js-overview-tab a').click
+ page.click_link('Overview')
wait_for_requests
end
+ end
- it 'displays calendar' do
- expect(find('#js-overview')).to have_css('.js-contrib-calendar')
+ context 'with `profile_tabs_vue` feature flag disabled' do
+ before do
+ stub_feature_flags(profile_tabs_vue: false)
+ sign_in user
end
- describe 'select calendar day' do
- let(:cells) { page.all('#js-overview .user-contrib-cell') }
+ describe 'calendar day selection' do
+ include_context 'when user page is visited'
- before do
- cells[0].click
- wait_for_requests
- @first_day_activities = selected_day_activities
+ it 'displays calendar' do
+ expect(find('#js-overview')).to have_css('.js-contrib-calendar')
end
- it 'displays calendar day activities' do
- expect(selected_day_activities).not_to be_empty
- end
+ describe 'select calendar day' do
+ let(:cells) { page.all('#js-overview .user-contrib-cell') }
- describe 'select another calendar day' do
before do
- cells[1].click
+ cells[0].click
wait_for_requests
end
- it 'displays different calendar day activities' do
- expect(selected_day_activities).not_to eq(@first_day_activities)
+ it 'displays calendar day activities' do
+ expect(selected_day_activities).not_to be_empty
end
- end
- describe 'deselect calendar day' do
- before do
- cells[0].click
- wait_for_requests
- cells[0].click
+ describe 'select another calendar day' do
+ it 'displays different calendar day activities' do
+ first_day_activities = selected_day_activities
+
+ cells[1].click
+ wait_for_requests
+
+ expect(selected_day_activities).not_to eq(first_day_activities)
+ end
end
- it 'hides calendar day activities' do
- expect(selected_day_activities(visible: false)).to be_empty
+ describe 'deselect calendar day' do
+ before do
+ cells[0].click
+ wait_for_requests
+ cells[0].click
+ end
+
+ it 'hides calendar day activities' do
+ expect(selected_day_activities(visible: false)).to be_empty
+ end
end
end
end
- end
- shared_context 'visit user page' do
- before do
- visit user.username
- page.find('.js-overview-tab a').click
- wait_for_requests
- end
- end
+ describe 'calendar daily activities' do
+ shared_examples 'a day with activity' do |contribution_count:|
+ include_context 'when user page is visited'
+
+ it 'displays calendar activity square for 1 contribution', :sidekiq_inline do
+ expect(find('#js-overview')).to have_selector(get_cell_level_selector(contribution_count), count: 1)
+
+ today = Date.today.strftime(date_format)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
+ end
+ end
- describe 'calendar daily activities' do
- shared_examples 'a day with activity' do |contribution_count:|
- include_context 'visit user page'
+ describe '1 issue and 1 work item creation calendar activity' do
+ before do
+ Issues::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: issue_params,
+ spam_params: nil
+ ).execute
+ WorkItems::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: { title: 'new task' },
+ spam_params: nil
+ ).execute
+ end
- it 'displays calendar activity square for 1 contribution', :sidekiq_might_not_need_inline do
- expect(find('#js-overview')).to have_selector(get_cell_level_selector(contribution_count), count: 1)
+ it_behaves_like 'a day with activity', contribution_count: 2
- today = Date.today.strftime(date_format)
- expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
+ describe 'issue title is shown on activity page' do
+ include_context 'when user page is visited'
+
+ it 'displays calendar activity log', :sidekiq_inline do
+ expect(all('#js-overview .overview-content-list .event-target-title').map(&:text)).to contain_exactly(
+ match(/#{issue_title}/),
+ match(/new task/)
+ )
+ end
+ end
end
- end
- describe '1 issue and 1 work item creation calendar activity' do
- before do
- Issues::CreateService.new(container: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute
- WorkItems::CreateService.new(
- container: contributed_project,
- current_user: user,
- params: { title: 'new task' },
- spam_params: nil
- ).execute
+ describe '1 comment calendar activity' do
+ before do
+ note_comment_contribution
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 1
end
- it_behaves_like 'a day with activity', contribution_count: 2
+ describe '10 calendar activities' do
+ before do
+ 10.times { push_code_contribution }
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 10
+ end
+
+ describe 'calendar activity on two days' do
+ before do
+ push_code_contribution
+
+ travel_to(Date.yesterday) do
+ Issues::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: issue_params,
+ spam_params: nil
+ ).execute
+ end
+ end
+
+ include_context 'when user page is visited'
- describe 'issue title is shown on activity page' do
- include_context 'visit user page'
+ it 'displays calendar activity squares for both days', :sidekiq_inline do
+ expect(find('#js-overview')).to have_selector(get_cell_level_selector(1), count: 2)
+ end
- it 'displays calendar activity log', :sidekiq_inline do
- expect(all('#js-overview .overview-content-list .event-target-title').map(&:text)).to contain_exactly(
- match(/#{issue_title}/),
- match(/new task/)
- )
+ it 'displays calendar activity square for yesterday', :sidekiq_inline do
+ yesterday = Date.yesterday.strftime(date_format)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
+ end
+
+ it 'displays calendar activity square for today' do
+ today = Date.today.strftime(date_format)
+ expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1)
end
end
end
- describe '1 comment calendar activity' do
- before do
- note_comment_contribution
+ describe 'on smaller screens' do
+ shared_examples 'hidden activity calendar' do
+ include_context 'when user page is visited'
+
+ it 'hides the activity calender' do
+ expect(find('#js-overview')).not_to have_css('.js-contrib-calendar')
+ end
end
- it_behaves_like 'a day with activity', contribution_count: 1
+ context 'when screen size is xs' do
+ before do
+ resize_screen_xs
+ end
+
+ it_behaves_like 'hidden activity calendar'
+ end
end
- describe '10 calendar activities' do
- before do
- 10.times { push_code_contribution }
+ describe 'first_day_of_week setting' do
+ context 'when first day of the week is set to Monday' do
+ before do
+ stub_application_setting(first_day_of_week: 1)
+ end
+
+ include_context 'when user page is visited'
+
+ it 'shows calendar with Monday as the first day of the week' do
+ expect(get_days_of_week).to eq(%w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday])
+ end
+ end
+
+ context 'when first day of the week is set to Sunday' do
+ before do
+ stub_application_setting(first_day_of_week: 0)
+ end
+
+ include_context 'when user page is visited'
+
+ it 'shows calendar with Sunday as the first day of the week' do
+ expect(get_days_of_week).to eq(%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday])
+ end
end
+ end
+ end
+
+ context 'with `profile_tabs_vue` feature flag enabled' do
+ before do
+ sign_in user
+ end
- it_behaves_like 'a day with activity', contribution_count: 10
+ include_context 'when user page is visited'
+
+ it 'displays calendar' do
+ expect(page).to have_css('[data-testid="contrib-calendar"]')
end
- describe 'calendar activity on two days' do
- before do
- push_code_contribution
+ describe 'calendar daily activities' do
+ shared_examples 'a day with activity' do |contribution_count:|
+ include_context 'when user page is visited'
- travel_to(Date.yesterday) do
- Issues::CreateService.new(container: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute
+ it 'displays calendar activity square for 1 contribution', :sidekiq_inline do
+ expect(page).to have_selector(get_cell_level_selector(contribution_count), count: 1)
+
+ today = Date.today.strftime(date_format)
+ expect(page).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
end
end
- include_context 'visit user page'
- it 'displays calendar activity squares for both days', :sidekiq_might_not_need_inline do
- expect(find('#js-overview')).to have_selector(get_cell_level_selector(1), count: 2)
+ describe '1 issue and 1 work item creation calendar activity' do
+ before do
+ Issues::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: issue_params,
+ spam_params: nil
+ ).execute
+ WorkItems::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: { title: 'new task' },
+ spam_params: nil
+ ).execute
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 2
end
- it 'displays calendar activity square for yesterday', :sidekiq_might_not_need_inline do
- yesterday = Date.yesterday.strftime(date_format)
- expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
+ describe '1 comment calendar activity' do
+ before do
+ note_comment_contribution
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 1
end
- it 'displays calendar activity square for today' do
- today = Date.today.strftime(date_format)
- expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1)
+ describe '10 calendar activities' do
+ before do
+ 10.times { push_code_contribution }
+ end
+
+ it_behaves_like 'a day with activity', contribution_count: 10
+ end
+
+ describe 'calendar activity on two days' do
+ before do
+ push_code_contribution
+
+ travel_to(Date.yesterday) do
+ Issues::CreateService.new(
+ container: contributed_project,
+ current_user: user,
+ params: issue_params,
+ spam_params: nil
+ ).execute
+ end
+ end
+
+ include_context 'when user page is visited'
+
+ it 'displays calendar activity squares for both days', :sidekiq_inline do
+ expect(page).to have_selector(get_cell_level_selector(1), count: 2)
+ end
+
+ it 'displays calendar activity square for yesterday', :sidekiq_inline do
+ yesterday = Date.yesterday.strftime(date_format)
+ expect(page).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
+ end
+
+ it 'displays calendar activity square for today' do
+ today = Date.today.strftime(date_format)
+ expect(page).to have_selector(get_cell_date_selector(1, today), count: 1)
+ end
end
end
- end
- describe 'on smaller screens' do
- shared_examples 'hidden activity calendar' do
- include_context 'visit user page'
+ describe 'on smaller screens' do
+ shared_examples 'hidden activity calendar' do
+ include_context 'when user page is visited'
- it 'hides the activity calender' do
- expect(find('#js-overview')).not_to have_css('.js-contrib-calendar')
+ it 'hides the activity calender' do
+ expect(page).not_to have_css('[data-testid="contrib-calendar"]')
+ end
+ end
+
+ context 'when screen size is xs' do
+ before do
+ resize_screen_xs
+ end
+
+ it_behaves_like 'hidden activity calendar'
end
end
- context 'size xs' do
- before do
- resize_screen_xs
+ describe 'first_day_of_week setting' do
+ context 'when first day of the week is set to Monday' do
+ before do
+ stub_application_setting(first_day_of_week: 1)
+ end
+
+ include_context 'when user page is visited'
+
+ it 'shows calendar with Monday as the first day of the week' do
+ expect(get_days_of_week).to eq(%w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday])
+ end
end
- it_behaves_like 'hidden activity calendar'
+ context 'when first day of the week is set to Sunday' do
+ before do
+ stub_application_setting(first_day_of_week: 0)
+ end
+
+ include_context 'when user page is visited'
+
+ it 'shows calendar with Sunday as the first day of the week' do
+ expect(get_days_of_week).to eq(%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday])
+ end
+ end
end
end
end
diff --git a/spec/features/callouts/registration_enabled_spec.rb b/spec/features/callouts/registration_enabled_spec.rb
index 15c900592a1..3282a40854d 100644
--- a/spec/features/callouts/registration_enabled_spec.rb
+++ b/spec/features/callouts/registration_enabled_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Registration enabled callout', feature_category: :authentication_and_authorization do
+RSpec.describe 'Registration enabled callout', feature_category: :system_access do
let_it_be(:admin) { create(:admin) }
let_it_be(:non_admin) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/features/commit_spec.rb b/spec/features/commit_spec.rb
index a9672569a4a..dd96b763e55 100644
--- a/spec/features/commit_spec.rb
+++ b/spec/features/commit_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Commit', feature_category: :source_code_management do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
- describe "single commit view" do
+ shared_examples "single commit view" do
let(:commit) do
project.repository.commits(nil, limit: 100).find do |commit|
commit.diffs.size > 1
@@ -16,7 +16,6 @@ RSpec.describe 'Commit', feature_category: :source_code_management do
let(:files) { commit.diffs.diff_files.to_a }
before do
- stub_feature_flags(async_commit_diff_files: false)
project.add_maintainer(user)
sign_in(user)
end
@@ -28,15 +27,9 @@ RSpec.describe 'Commit', feature_category: :source_code_management do
visit project_commit_path(project, commit)
end
- it "shows the short commit message" do
+ it "shows the short commit message, number of total changes and stats", :js, :aggregate_failures do
expect(page).to have_content(commit.title)
- end
-
- it "reports the correct number of total changes" do
expect(page).to have_content("Changes #{commit.diffs.size}")
- end
-
- it 'renders diff stats', :js do
expect(page).to have_selector(".diff-stats")
end
@@ -50,23 +43,36 @@ RSpec.describe 'Commit', feature_category: :source_code_management do
visit project_commit_path(project, commit)
end
- it "shows an adjusted count for changed files on this page", :js do
- expect(page).to have_content("Showing 1 changed file")
+ def diff_files_on_page
+ page.all('.files .diff-file').pluck(:id)
end
- it "shows only the first diff on the first page" do
- expect(page).to have_selector(".files ##{files[0].file_hash}")
- expect(page).not_to have_selector(".files ##{files[1].file_hash}")
- end
+ it "shows paginated content and controls to navigate", :js, :aggregate_failures do
+ expect(page).to have_content("Showing 1 changed file")
+
+ wait_for_requests
+
+ expect(diff_files_on_page).to eq([files[0].file_hash])
- it "can navigate to the second page" do
within(".files .gl-pagination") do
click_on("2")
end
- expect(page).not_to have_selector(".files ##{files[0].file_hash}")
- expect(page).to have_selector(".files ##{files[1].file_hash}")
+ wait_for_requests
+
+ expect(diff_files_on_page).to eq([files[1].file_hash])
end
end
end
+
+ it_behaves_like "single commit view"
+
+ context "when super sidebar is enabled" do
+ before do
+ user.update!(use_new_navigation: true)
+ stub_feature_flags(super_sidebar_nav: true)
+ end
+
+ it_behaves_like "single commit view"
+ end
end
diff --git a/spec/features/contextual_sidebar_spec.rb b/spec/features/contextual_sidebar_spec.rb
index 2b671d4b3f1..132c8eb7192 100644
--- a/spec/features/contextual_sidebar_spec.rb
+++ b/spec/features/contextual_sidebar_spec.rb
@@ -39,74 +39,5 @@ RSpec.describe 'Contextual sidebar', :js, feature_category: :remote_development
expect(page).to have_selector('.is-showing-fly-out')
end
end
-
- context 'with invite_members_in_side_nav experiment', :experiment do
- it 'allows opening of modal for the candidate experience' do
- stub_experiments(invite_members_in_side_nav: :candidate)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: project.group)
- .on_next_instance
-
- visit project_path(project)
-
- page.within '[data-test-id="side-nav-invite-members"' do
- find('[data-test-id="invite-members-button"').click
- end
-
- expect(page).to have_content("You're inviting members to the")
- end
-
- it 'does not have invite members link in side nav for the control experience' do
- stub_experiments(invite_members_in_side_nav: :control)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: project.group)
- .on_next_instance
-
- visit project_path(project)
-
- expect(page).not_to have_css('[data-test-id="side-nav-invite-members"')
- end
- end
- end
-
- context 'when context is a group' do
- let_it_be(:user) { create(:user) }
- let_it_be(:group) do
- create(:group).tap do |g|
- g.add_owner(user)
- end
- end
-
- before do
- sign_in(user)
- end
-
- context 'with invite_members_in_side_nav experiment', :experiment do
- it 'allows opening of modal for the candidate experience' do
- stub_experiments(invite_members_in_side_nav: :candidate)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: group)
- .on_next_instance
-
- visit group_path(group)
-
- page.within '[data-test-id="side-nav-invite-members"' do
- find('[data-test-id="invite-members-button"').click
- end
-
- expect(page).to have_content("You're inviting members to the")
- end
-
- it 'does not have invite members link in side nav for the control experience' do
- stub_experiments(invite_members_in_side_nav: :control)
- expect(experiment(:invite_members_in_side_nav)).to track(:assignment)
- .with_context(group: group)
- .on_next_instance
-
- visit group_path(group)
-
- expect(page).not_to have_css('[data-test-id="side-nav-invite-members"')
- end
- end
end
end
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 f5b02a87758..a5d6ba58ffa 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
@@ -21,9 +21,8 @@ RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do
within_top_nav do
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).to have_link('Activity')
- expect(page).to have_link('Milestones')
- expect(page).to have_link('Snippets')
+ expect(page).to have_link('Your work')
+ expect(page).to have_link('Explore')
end
end
@@ -36,9 +35,8 @@ RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do
within_top_nav do
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).not_to have_link('Activity')
- expect(page).not_to have_link('Milestones')
- expect(page).to have_link('Snippets')
+ expect(page).to have_link('Your work')
+ expect(page).to have_link('Explore')
end
end
end
diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb
index a45e0a58ed6..1fb393e1769 100644
--- a/spec/features/dashboard/groups_list_spec.rb
+++ b/spec/features/dashboard/groups_list_spec.rb
@@ -230,4 +230,11 @@ RSpec.describe 'Dashboard Groups page', :js, feature_category: :subgroups do
expect(page).not_to have_content(another_group.name)
end
end
+
+ it 'links to the "Explore groups" page' do
+ sign_in(user)
+ visit dashboard_groups_path
+
+ expect(page).to have_link("Explore groups", href: explore_groups_path)
+ end
end
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 779fbb48ddb..eafc41c0f40 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Dashboard Projects', feature_category: :projects do
let_it_be(:user) { create(:user) }
- let_it_be(:project, reload: true) { create(:project, :repository) }
+ 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) }
before do
@@ -20,6 +20,12 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do
it_behaves_like "a dashboard page with sidebar", :dashboard_projects_path, :projects
+ it 'links to the "Explore projects" page' do
+ visit dashboard_projects_path
+
+ expect(page).to have_link("Explore projects", href: explore_projects_path)
+ end
+
context 'when user has access to the project' do
it 'shows role badge' do
visit dashboard_projects_path
@@ -239,7 +245,7 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do
create(:ci_pipeline, :with_job, status: :success, project: project, ref: project.default_branch, sha: project.commit.sha)
visit dashboard_projects_path
- control_count = ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }.count
+ control = ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }
new_project = create(:project, :repository, name: 'new project')
create(:ci_pipeline, :with_job, status: :success, project: new_project, ref: new_project.commit.sha)
@@ -247,15 +253,11 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do
ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }.count
- # There are seven known N+1 queries: https://gitlab.com/gitlab-org/gitlab/-/issues/214037
- # 1. Project#open_issues_count
- # 2. Project#open_merge_requests_count
- # 3. Project#forks_count
- # 4. ProjectsHelper#load_pipeline_status
- # 5. RendersMemberAccess#preload_max_member_access_for_collection
- # 6. User#max_member_access_for_project_ids
- # 7. Ci::CommitWithPipeline#last_pipeline
+ # There are a few known N+1 queries: https://gitlab.com/gitlab-org/gitlab/-/issues/214037
+ # - User#max_member_access_for_project_ids
+ # - ProjectsHelper#load_pipeline_status / Ci::CommitWithPipeline#last_pipeline
+ # - Ci::Pipeline#detailed_status
- expect { visit dashboard_projects_path }.not_to exceed_query_limit(control_count + 7)
+ expect { visit dashboard_projects_path }.not_to exceed_query_limit(control).with_threshold(4)
end
end
diff --git a/spec/features/dashboard/root_explore_spec.rb b/spec/features/dashboard/root_explore_spec.rb
index a232ebec68e..9e844f81a29 100644
--- a/spec/features/dashboard/root_explore_spec.rb
+++ b/spec/features/dashboard/root_explore_spec.rb
@@ -2,16 +2,12 @@
require 'spec_helper'
-RSpec.describe 'Root explore', feature_category: :not_owned do
+RSpec.describe 'Root explore', :saas, feature_category: :shared do
let_it_be(:public_project) { create(:project, :public) }
let_it_be(:archived_project) { create(:project, :archived) }
let_it_be(:internal_project) { create(:project, :internal) }
let_it_be(:private_project) { create(:project, :private) }
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
context 'when logged in' do
let_it_be(:user) { create(:user) }
diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb
index 30587756505..155f7e93961 100644
--- a/spec/features/dashboard/shortcuts_spec.rb
+++ b/spec/features/dashboard/shortcuts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Dashboard shortcuts', :js, feature_category: :not_owned do
+RSpec.describe 'Dashboard shortcuts', :js, feature_category: :shared do
context 'logged in' do
let(:user) { create(:user) }
let(:project) { create(:project) }
diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb
index ba40290d866..f4234b433f8 100644
--- a/spec/features/dashboard/snippets_spec.rb
+++ b/spec/features/dashboard/snippets_spec.rb
@@ -7,6 +7,13 @@ RSpec.describe 'Dashboard snippets', feature_category: :source_code_management d
it_behaves_like 'a dashboard page with sidebar', :dashboard_snippets_path, :snippets
+ it 'links to the "Explore snippets" page' do
+ sign_in(user)
+ visit dashboard_snippets_path
+
+ expect(page).to have_link("Explore snippets", href: explore_snippets_path)
+ end
+
context 'when the project has snippets' do
let(:project) { create(:project, :public, creator: user) }
let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.first_owner, project: project) }
diff --git a/spec/features/display_system_header_and_footer_bar_spec.rb b/spec/features/display_system_header_and_footer_bar_spec.rb
index 22fd0987418..9b2bf0ef1fa 100644
--- a/spec/features/display_system_header_and_footer_bar_spec.rb
+++ b/spec/features/display_system_header_and_footer_bar_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Display system header and footer bar', feature_category: :not_owned do
+RSpec.describe 'Display system header and footer bar', feature_category: :shared do
let(:header_message) { "Foo" }
let(:footer_message) { "Bar" }
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 1f09b01ddec..43dd80187ce 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -19,6 +19,8 @@ RSpec.describe 'Expand and collapse diffs', :js, feature_category: :source_code_
# Ensure that undiffable.md is in .gitattributes
project.repository.copy_gitattributes(branch)
visit project_commit_path(project, project.commit(branch))
+
+ wait_for_requests
end
def file_container(filename)
@@ -222,10 +224,16 @@ RSpec.describe 'Expand and collapse diffs', :js, feature_category: :source_code_
let(:branch) { 'expand-collapse-files' }
# safe-files -> 100 | safe-lines -> 5000 | commit-files -> 105
- it 'does collapsing from the safe number of files to the end on small files' do
- expect(page).to have_link('Expand all')
+ it 'does collapsing from the safe number of files to the end on small files', :aggregate_failures do
+ expect(page).not_to have_link('Expand all')
+ expect(page).to have_selector('.diff-content', count: 20)
+ expect(page).to have_selector('.diff-collapsed', count: 0)
- expect(page).to have_selector('.diff-content', count: 105)
+ visit project_commit_path(project, project.commit(branch), page: 6)
+ wait_for_requests
+
+ expect(page).to have_link('Expand all')
+ expect(page).to have_selector('.diff-content', count: 5)
expect(page).to have_selector('.diff-collapsed', count: 5)
%w(file-95.txt file-96.txt file-97.txt file-98.txt file-99.txt).each do |filename|
diff --git a/spec/features/explore/navbar_spec.rb b/spec/features/explore/navbar_spec.rb
new file mode 100644
index 00000000000..8f281abe6a7
--- /dev/null
+++ b/spec/features/explore/navbar_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe '"Explore" navbar', feature_category: :navigation do
+ include_context '"Explore" navbar structure'
+
+ it_behaves_like 'verified navigation bar' do
+ before do
+ visit explore_projects_path
+ end
+ end
+end
diff --git a/spec/features/frequently_visited_projects_and_groups_spec.rb b/spec/features/frequently_visited_projects_and_groups_spec.rb
index 50e20910e16..19495230795 100644
--- a/spec/features/frequently_visited_projects_and_groups_spec.rb
+++ b/spec/features/frequently_visited_projects_and_groups_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Frequently visited items', :js, feature_category: :not_owned do
+RSpec.describe 'Frequently visited items', :js, feature_category: :shared do
include Spec::Support::Helpers::Features::TopNavSpecHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb
index 117f50aefc6..8644a15a093 100644
--- a/spec/features/group_variables_spec.rb
+++ b/spec/features/group_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Group variables', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Group variables', :js, feature_category: :pipeline_composition do
let(:user) { create(:user) }
let(:group) { create(:group) }
let!(:variable) { create(:ci_group_variable, key: 'test_key', value: 'test_value', masked: true, group: group) }
@@ -15,5 +15,16 @@ RSpec.describe 'Group variables', :js, feature_category: :pipeline_authoring do
wait_for_requests
end
- it_behaves_like 'variable list'
+ context 'when ci_variables_pages FF is enabled' do
+ it_behaves_like 'variable list'
+ it_behaves_like 'variable list pagination', :ci_group_variable
+ end
+
+ context 'when ci_variables_pages FF is disabled' do
+ before do
+ stub_feature_flags(ci_variables_pages: false)
+ end
+
+ it_behaves_like 'variable list'
+ end
end
diff --git a/spec/features/groups/board_spec.rb b/spec/features/groups/board_spec.rb
index c451a97bed5..8acf3ffe441 100644
--- a/spec/features/groups/board_spec.rb
+++ b/spec/features/groups/board_spec.rb
@@ -25,8 +25,10 @@ RSpec.describe 'Group Boards', feature_category: :team_planning do
it 'adds an issue to the backlog' do
page.within(find('.board', match: :first)) do
- issue_title = 'New Issue'
- click_button 'New issue'
+ dropdown = first("[data-testid='header-list-actions']")
+ dropdown.click
+ issue_title = 'Create new issue'
+ click_button issue_title
wait_for_requests
diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb
index 5510e73ef0f..2aa70ec1953 100644
--- a/spec/features/groups/group_settings_spec.rb
+++ b/spec/features/groups/group_settings_spec.rb
@@ -147,14 +147,14 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
selected_group.add_owner(user)
end
- it 'can successfully transfer the group', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/384966' do
+ it 'can successfully transfer the group' do
visit edit_group_path(selected_group)
page.within('[data-testid="transfer-locations-dropdown"]') do
click_button _('Select parent group')
fill_in _('Search'), with: target_group_name
wait_for_requests
- click_button target_group_name
+ click_button(target_group_name || 'No parent group')
end
click_button s_('GroupSettings|Transfer group')
@@ -166,7 +166,10 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
click_button 'Confirm'
end
- expect(page).to have_text "Group '#{selected_group.name}' was successfully transferred."
+ within('[data-testid="breadcrumb-links"]') do
+ expect(page).to have_content(target_group_name) if target_group_name
+ expect(page).to have_content(selected_group.name)
+ end
expect(current_url).to include(selected_group.reload.full_path)
end
end
@@ -175,7 +178,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do
let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) }
context 'when transfering to no parent group' do
- let(:target_group_name) { 'No parent group' }
+ let(:target_group_name) { nil }
it_behaves_like 'can transfer the group'
end
diff --git a/spec/features/groups/import_export/connect_instance_spec.rb b/spec/features/groups/import_export/connect_instance_spec.rb
index 8aea18a268b..f6548c035f0 100644
--- a/spec/features/groups/import_export/connect_instance_spec.rb
+++ b/spec/features/groups/import_export/connect_instance_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe 'Import/Export - Connect to another instance', :js, feature_categ
pat = 'demo-pat'
expect(page).to have_content 'Import groups by direct transfer'
- expect(page).to have_content 'Not all related objects are migrated'
+ expect(page).to have_content 'Not all group items are migrated'
fill_in :bulk_import_gitlab_url, with: source_url
fill_in :bulk_import_gitlab_access_token, with: pat
diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb
index 5634122ec16..fa5a14f18b4 100644
--- a/spec/features/groups/members/sort_members_spec.rb
+++ b/spec/features/groups/members/sort_members_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe 'Groups > Members > Sort members', :js, feature_category: :subgro
def expect_sort_by(text, sort_direction)
within('[data-testid="members-sort-dropdown"]') do
- expect(page).to have_css('button[aria-haspopup="true"]', text: text)
+ expect(page).to have_css('button[aria-haspopup="menu"]', text: text)
expect(page).to have_button("Sorting Direction: #{sort_direction == :asc ? 'Ascending' : 'Descending'}")
end
end
diff --git a/spec/features/groups/new_group_page_spec.rb b/spec/features/groups/new_group_page_spec.rb
index a07c27331d9..6d9513ce84f 100644
--- a/spec/features/groups/new_group_page_spec.rb
+++ b/spec/features/groups/new_group_page_spec.rb
@@ -3,15 +3,14 @@
require 'spec_helper'
RSpec.describe 'New group page', :js, feature_category: :subgroups do
- let(:user) { create(:user) }
- let(:group) { create(:group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:parent_group) { create(:group) }
before do
+ parent_group.add_owner(user)
sign_in(user)
end
- it_behaves_like 'a dashboard page with sidebar', :new_group_path, :groups
-
describe 'new top level group alert' do
context 'when a user visits the new group page' do
it 'shows the new top level group alert' do
@@ -22,8 +21,6 @@ RSpec.describe 'New group page', :js, feature_category: :subgroups do
end
context 'when a user visits the new sub group page' do
- let(:parent_group) { create(:group) }
-
it 'does not show the new top level group alert' do
visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
@@ -31,4 +28,45 @@ RSpec.describe 'New group page', :js, feature_category: :subgroups do
end
end
end
+
+ describe 'sidebar' do
+ context 'in the current navigation' do
+ before do
+ user.update!(use_new_navigation: false)
+ end
+
+ context 'for a new top-level group' do
+ it_behaves_like 'a dashboard page with sidebar', :new_group_path, :groups
+ end
+
+ context 'for a new subgroup' do
+ it 'shows the group sidebar of the parent group' do
+ visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
+ expect(page).to have_selector(
+ ".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]"
+ )
+ end
+ end
+ end
+
+ context 'in the new navigation' do
+ before do
+ user.update!(use_new_navigation: true)
+ end
+
+ 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")
+ 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)
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/groups/settings/access_tokens_spec.rb b/spec/features/groups/settings/access_tokens_spec.rb
index 1bee3be1ddb..cb92f9abdf5 100644
--- a/spec/features/groups/settings/access_tokens_spec.rb
+++ b/spec/features/groups/settings/access_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Group > Settings > Access Tokens', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'Group > Settings > Access Tokens', :js, feature_category: :system_access do
include Spec::Support::Helpers::ModalHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/features/groups/settings/packages_and_registries_spec.rb b/spec/features/groups/settings/packages_and_registries_spec.rb
index 80e2dcd5174..a6c980f539c 100644
--- a/spec/features/groups/settings/packages_and_registries_spec.rb
+++ b/spec/features/groups/settings/packages_and_registries_spec.rb
@@ -56,6 +56,14 @@ RSpec.describe 'Group Package and registry settings', feature_category: :package
expect(sidebar).to have_link _('Packages and registries')
end
+ it 'passes axe automated accessibility testing', :js do
+ visit_settings_page
+
+ wait_for_requests
+
+ expect(page).to be_axe_clean.within '[data-testid="packages-and-registries-group-settings"]'
+ end
+
it 'has a Duplicate packages section', :js do
visit_settings_page
diff --git a/spec/features/help_dropdown_spec.rb b/spec/features/help_dropdown_spec.rb
index a5c9221ad26..5f1d3a5e2b7 100644
--- a/spec/features/help_dropdown_spec.rb
+++ b/spec/features/help_dropdown_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Help Dropdown", :js, feature_category: :not_owned do
+RSpec.describe "Help Dropdown", :js, feature_category: :shared do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index 6c0901d6169..905c5e25f6e 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Help Pages', feature_category: :not_owned do
+RSpec.describe 'Help Pages', feature_category: :shared do
describe 'Get the main help page' do
before do
allow(File).to receive(:read).and_call_original
diff --git a/spec/features/incidents/incident_timeline_events_spec.rb b/spec/features/incidents/incident_timeline_events_spec.rb
index 7404ac64cc9..a4449ee2608 100644
--- a/spec/features/incidents/incident_timeline_events_spec.rb
+++ b/spec/features/incidents/incident_timeline_events_spec.rb
@@ -96,5 +96,6 @@ RSpec.describe 'Incident timeline events', :js, feature_category: :incident_mana
it_behaves_like 'for each incident details route',
'add, edit, and delete timeline events',
- tab_text: s_('Incident|Timeline')
+ tab_text: s_('Incident|Timeline'),
+ tab: 'timeline'
end
diff --git a/spec/features/incidents/user_views_alert_details_spec.rb b/spec/features/incidents/user_views_alert_details_spec.rb
new file mode 100644
index 00000000000..f3d0273071c
--- /dev/null
+++ b/spec/features/incidents/user_views_alert_details_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User uploads alerts to incident', :js, feature_category: :incident_management do
+ let_it_be(:incident) { create(:incident) }
+ let_it_be(:project) { incident.project }
+ let_it_be(:user) { create(:user, developer_projects: [project]) }
+
+ context 'with alert' do
+ let_it_be(:alert) { create(:alert_management_alert, issue_id: incident.id, project: project) }
+
+ shared_examples 'shows alert tab with details' do
+ specify do
+ expect(page).to have_link(s_('Incident|Alert details'))
+ expect(page).to have_content(alert.title)
+ end
+ end
+
+ it_behaves_like 'for each incident details route',
+ 'shows alert tab with details',
+ tab_text: s_('Incident|Alert details'),
+ tab: 'alerts'
+ end
+
+ context 'with no alerts' do
+ it 'hides the Alert details tab' do
+ sign_in(user)
+ visit project_issue_path(project, incident)
+
+ expect(page).not_to have_link(s_('Incident|Alert details'))
+ end
+ end
+end
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index 1091bea1ce3..cb7e933e472 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -244,9 +244,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
context 'the user sign-up using a different email address' do
let(:invite_email) { build_stubbed(:user).email }
- context 'when soft email confirmation is not enabled' do
+ context 'when email confirmation is not set to `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
stub_feature_flags(identity_verification: false)
end
@@ -261,9 +260,9 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
- context 'when soft email confirmation is enabled' do
+ context 'when email confirmation setting is set to `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: true)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
end
diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb
index 350b0582565..c979aff2147 100644
--- a/spec/features/issuables/issuable_list_spec.rb
+++ b/spec/features/issuables/issuable_list_spec.rb
@@ -48,7 +48,7 @@ RSpec.describe 'issuable list', :js, feature_category: :team_planning do
end
end
- it 'displays a warning if counting the number of issues times out' do
+ it 'displays a warning if counting the number of issues times out', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393344' do
allow_any_instance_of(IssuesFinder).to receive(:count_by_state).and_raise(ActiveRecord::QueryCanceled)
visit_issuable_list(:issue)
diff --git a/spec/features/issues/discussion_lock_spec.rb b/spec/features/issues/discussion_lock_spec.rb
index 33fc9a6fd96..47865d2b6ba 100644
--- a/spec/features/issues/discussion_lock_spec.rb
+++ b/spec/features/issues/discussion_lock_spec.rb
@@ -99,7 +99,7 @@ RSpec.describe 'Discussion Lock', :js, feature_category: :team_planning do
it 'the user can not create a comment' do
page.within('#notes') do
expect(page).not_to have_selector('js-main-target-form')
- expect(page.find('.disabled-comment'))
+ expect(page.find('.disabled-comments'))
.to have_content('This issue is locked. Only project members can comment.')
end
end
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 585740f7782..fa5dd8c893c 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
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 }
@@ -477,14 +478,69 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
end
describe 'inline edit' do
- before do
- visit project_issue_path(project, issue)
+ context 'within issue 1' do
+ before do
+ visit project_issue_path(project, issue)
+ wait_for_requests
+ end
+
+ it 'opens inline edit form with shortcut' do
+ find('body').send_keys('e')
+
+ expect(page).to have_selector('.detail-page-description form')
+ end
+
+ 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)
+
+ find('body').send_keys('e')
+
+ click_link 'Boards'
+
+ expect(page).not_to have_content(expected_content)
+ end
+ end
+
+ describe 'when user has made changes' do
+ it 'shows a warning and can stay on page' do
+ content = 'new issue content'
+
+ find('body').send_keys('e')
+ fill_in 'issue-description', with: content
+
+ click_link 'Boards'
+
+ page.driver.browser.switch_to.alert.dismiss
+
+ click_button 'Save changes'
+ wait_for_requests
+
+ expect(page).to have_content(content)
+ end
+ end
end
- it 'opens inline edit form with shortcut' do
- find('body').send_keys('e')
+ context 'within issue 2' do
+ before do
+ visit project_issue_path(project, issue2)
+ wait_for_requests
+ end
+
+ describe 'when user has made changes' do
+ 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'
- expect(page).to have_selector('.detail-page-description form')
+ page.driver.browser.switch_to.alert.accept
+
+ expect(page).not_to have_content(content)
+ end
+ end
end
end
diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb
index 20a69c61871..d5f90bb9260 100644
--- a/spec/features/issues/issue_detail_spec.rb
+++ b/spec/features/issues/issue_detail_spec.rb
@@ -48,6 +48,30 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do
end
end
+ context 'when issue description has task list items' do
+ before do
+ description = '- [ ] I am a task
+
+| Table |
+|-------|
+| <ul><li>[ ] I am inside a table</li><ul> |'
+ issue.update!(description: description)
+
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ end
+
+ it 'shows task actions ellipsis button when hovering over the task list item, but not within a table', :aggregate_failures do
+ find('li', text: 'I am a task').hover
+
+ expect(page).to have_button 'Task actions'
+
+ find('li', text: 'I am inside a table').hover
+
+ expect(page).not_to have_button 'Task actions'
+ end
+ end
+
context 'when issue description has xss snippet' do
before do
issue.update!(description: '![xss" onload=alert(1);//](a)')
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index 686074f7412..95277caf0f5 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -119,8 +119,6 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite members')
- expect(page).to have_selector('[data-track-action="click_invite_members"]')
- expect(page).to have_selector('[data-track-label="edit_assignee"]')
click_link 'Invite members'
end
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index ea68f2266b3..e2329e5e287 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -97,7 +97,7 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning
end
end
- context 'service desk issue moved to a project with service desk disabled', :js do
+ context 'service desk issue moved to a project with service desk disabled', :saas, :js do
let(:project_title) { 'service desk disabled project' }
let(:warning_selector) { '.js-alert-moved-from-service-desk-warning' }
let(:namespace) { create(:namespace) }
@@ -106,7 +106,6 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning
let(:service_desk_issue) { create(:issue, project: service_desk_project, author: ::User.support_bot) }
before do
- allow(Gitlab).to receive(:com?).and_return(true)
allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true)
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb
index 59e1413fc97..145fa3c4a9e 100644
--- a/spec/features/issues/user_comments_on_issue_spec.rb
+++ b/spec/features/issues/user_comments_on_issue_spec.rb
@@ -32,6 +32,8 @@ RSpec.describe "User comments on issue", :js, feature_category: :team_planning d
end
end
+ it_behaves_like 'edits content using the content editor'
+
it "adds comment with code block" do
code_block_content = "Command [1]: /usr/local/bin/git , see [text](doc/text)"
comment = "```\n#{code_block_content}\n```"
diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
index bbc14368d82..6325f226ccf 100644
--- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
@@ -113,6 +113,26 @@ RSpec.describe 'User creates branch and merge request on issue page', :js, featu
expect(page).to have_current_path project_tree_path(project, branch_name), ignore_query: true
end
end
+
+ context 'when branch name is invalid' do
+ shared_examples 'has error message' do |dropdown|
+ it 'has error message' do
+ select_dropdown_option(dropdown, 'custom-branch-name w~th ^bad chars?')
+
+ wait_for_requests
+
+ expect(page).to have_text("Can't contain spaces, ~, ^, ?")
+ end
+ end
+
+ context 'when creating a merge request', :sidekiq_might_not_need_inline do
+ it_behaves_like 'has error message', 'create-mr'
+ end
+
+ context 'when creating a branch', :sidekiq_might_not_need_inline do
+ it_behaves_like 'has error message', 'create-branch'
+ end
+ end
end
context "when there is a referenced merge request" do
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index bf2af918f39..06c1b2afdb0 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -111,23 +111,29 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
markdown_field_focused_selector = 'textarea:focus'
click_edit_issue_description
- expect(page).to have_selector(markdown_field_focused_selector)
+ issuable_form = find('[data-testid="issuable-form"]')
- click_on _('View rich text')
- click_on _('Rich text')
+ expect(issuable_form).to have_selector(markdown_field_focused_selector)
- expect(page).not_to have_selector(content_editor_focused_selector)
+ page.within issuable_form do
+ click_on _('Viewing markdown')
+ click_on _('Rich text')
+ end
+
+ expect(issuable_form).not_to have_selector(content_editor_focused_selector)
refresh
click_edit_issue_description
- expect(page).to have_selector(content_editor_focused_selector)
+ expect(issuable_form).to have_selector(content_editor_focused_selector)
- click_on _('View markdown')
- click_on _('Markdown')
+ page.within issuable_form do
+ click_on _('Viewing rich text')
+ click_on _('Markdown')
+ end
- expect(page).not_to have_selector(markdown_field_focused_selector)
+ expect(issuable_form).not_to have_selector(markdown_field_focused_selector)
end
end
diff --git a/spec/features/markdown/observability_spec.rb b/spec/features/markdown/observability_spec.rb
index 86caf3eb1b1..ec414d4396e 100644
--- a/spec/features/markdown/observability_spec.rb
+++ b/spec/features/markdown/observability_spec.rb
@@ -2,82 +2,44 @@
require 'spec_helper'
-RSpec.describe 'Observability rendering', :js do
+RSpec.describe 'Observability rendering', :js, feature_category: :metrics do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :repository, group: group) }
let_it_be(:user) { create(:user) }
- let_it_be(:observable_url) { "https://observe.gitlab.com/" }
-
- let_it_be(:expected) do
- %(<iframe src="#{observable_url}?theme=light&amp;kiosk" frameborder="0")
- end
+ let_it_be(:observable_url) { "https://www.gitlab.com/groups/#{group.path}/-/observability/explore?observability_path=/explore?foo=bar" }
+ let_it_be(:expected_observable_url) { "https://observe.gitlab.com/-/#{group.id}/explore?foo=bar" }
before do
- project.add_maintainer(user)
+ stub_config_setting(url: "https://www.gitlab.com")
+ group.add_developer(user)
sign_in(user)
end
- context 'when embedding in an issue' do
- let(:issue) do
- create(:issue, project: project, description: observable_url)
- end
-
- before do
- visit project_issue_path(project, issue)
- wait_for_requests
- end
-
- it 'renders iframe in description' do
- page.within('.description') do
- expect(page.html).to include(expected)
- end
- end
-
- it 'renders iframe in comment' do
- expect(page).not_to have_css('.note-text')
-
- page.within('.js-main-target-form') do
- fill_in('note[note]', with: observable_url)
- click_button('Comment')
+ context 'when user is a developer of the embedded group' do
+ context 'when embedding in an issue' do
+ let(:issue) do
+ create(:issue, project: project, description: observable_url)
end
- wait_for_requests
-
- page.within('.note-text') do
- expect(page.html).to include(expected)
+ before do
+ visit project_issue_path(project, issue)
+ wait_for_requests
end
- end
- end
-
- context 'when embedding in an MR' do
- let(:merge_request) do
- create(:merge_request, source_project: project, target_project: project, description: observable_url)
- end
- before do
- visit merge_request_path(merge_request)
- wait_for_requests
+ it_behaves_like 'embeds observability'
end
- it 'renders iframe in description' do
- page.within('.description') do
- expect(page.html).to include(expected)
+ context 'when embedding in an MR' do
+ let(:merge_request) do
+ create(:merge_request, source_project: project, target_project: project, description: observable_url)
end
- end
- it 'renders iframe in comment' do
- expect(page).not_to have_css('.note-text')
-
- page.within('.js-main-target-form') do
- fill_in('note[note]', with: observable_url)
- click_button('Comment')
+ before do
+ visit merge_request_path(merge_request)
+ wait_for_requests
end
- wait_for_requests
-
- page.within('.note-text') do
- expect(page.html).to include(expected)
- end
+ it_behaves_like 'embeds observability'
end
end
@@ -96,28 +58,7 @@ RSpec.describe 'Observability rendering', :js do
wait_for_requests
end
- it 'does not render iframe in description' do
- page.within('.description') do
- expect(page.html).not_to include(expected)
- expect(page.html).to include(observable_url)
- end
- end
-
- it 'does not render iframe in comment' do
- expect(page).not_to have_css('.note-text')
-
- page.within('.js-main-target-form') do
- fill_in('note[note]', with: observable_url)
- click_button('Comment')
- end
-
- wait_for_requests
-
- page.within('.note-text') do
- expect(page.html).not_to include(expected)
- expect(page.html).to include(observable_url)
- end
- end
+ it_behaves_like 'does not embed observability'
end
context 'when embedding in an MR' do
@@ -130,28 +71,7 @@ RSpec.describe 'Observability rendering', :js do
wait_for_requests
end
- it 'does not render iframe in description' do
- page.within('.description') do
- expect(page.html).not_to include(expected)
- expect(page.html).to include(observable_url)
- end
- end
-
- it 'does not render iframe in comment' do
- expect(page).not_to have_css('.note-text')
-
- page.within('.js-main-target-form') do
- fill_in('note[note]', with: observable_url)
- click_button('Comment')
- end
-
- wait_for_requests
-
- page.within('.note-text') do
- expect(page.html).not_to include(expected)
- expect(page.html).to include(observable_url)
- end
- end
+ it_behaves_like 'does not embed observability'
end
end
end
diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb
index 66b87148eb2..9ab53a00903 100644
--- a/spec/features/merge_request/user_comments_on_diff_spec.rb
+++ b/spec/features/merge_request/user_comments_on_diff_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe 'User comments on a diff', :js, feature_category: :code_review_wo
end
context 'in multiple files' do
- it 'toggles comments' do
+ it 'toggles comments', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393518' do
first_line_element = find_by_scrolling("[id='#{sample_compare.changes[0][:line_code]}']").find(:xpath, "..")
first_root_element = first_line_element.ancestor('[data-path]')
click_diff_line(first_line_element)
diff --git a/spec/features/merge_request/user_comments_on_merge_request_spec.rb b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
index 9335615b4c7..e113e305af5 100644
--- a/spec/features/merge_request/user_comments_on_merge_request_spec.rb
+++ b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
@@ -30,6 +30,8 @@ RSpec.describe 'User comments on a merge request', :js, feature_category: :code_
end
end
+ it_behaves_like 'edits content using the content editor'
+
it 'replys to a new comment' do
page.within('.js-main-target-form') do
fill_in('note[note]', with: 'comment 1')
diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
index 1d7a3fae371..6d3268ffe3a 100644
--- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
@@ -174,7 +174,7 @@ RSpec.describe 'Merge request > User creates image diff notes', :js, feature_cat
end
shared_examples 'onion skin' do
- it 'resets opacity when toggling between view modes' do
+ it 'resets opacity when toggling between view modes', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393331' do
# Simulate dragging onion-skin slider
drag_and_drop_by(find('.dragger'), -30, 0)
diff --git a/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb b/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
index cf5024ad59e..becbf0ccfa7 100644
--- a/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
+++ b/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
@@ -162,8 +162,6 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js, feature_cate
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite members')
- expect(page).to have_selector('[data-track-action="click_invite_members"]')
- expect(page).to have_selector('[data-track-label="edit_assignee"]')
click_link 'Invite members'
end
diff --git a/spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb b/spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb
index 26a9b955e2d..52d058aeabc 100644
--- a/spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb
+++ b/spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb
@@ -26,8 +26,6 @@ RSpec.describe 'Merge request > User edits reviewers sidebar', :js, feature_cate
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite Members')
- expect(page).to have_selector('[data-track-action="click_invite_members"]')
- expect(page).to have_selector('[data-track-label="edit_reviewer"]')
end
click_link 'Invite Members'
diff --git a/spec/features/merge_request/user_reverts_merge_request_spec.rb b/spec/features/merge_request/user_reverts_merge_request_spec.rb
index 43ce473b407..e09a4569caf 100644
--- a/spec/features/merge_request/user_reverts_merge_request_spec.rb
+++ b/spec/features/merge_request/user_reverts_merge_request_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe 'User reverts a merge request', :js, feature_category: :code_revi
revert_commit
- expect(page).to have_content('Sorry, we cannot revert this merge request automatically.')
+ expect(page).to have_content('Merge request revert failed:')
end
it 'reverts a merge request in a new merge request', :sidekiq_might_not_need_inline do
diff --git a/spec/features/merge_request/user_sees_discussions_navigation_spec.rb b/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
index 6e6c2cddfbf..06276d2a933 100644
--- a/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
+++ b/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe 'Merge request > User sees discussions navigation', :js, feature_
expect(page).to have_selector(second_discussion_selector, obscured: false)
end
- it 'navigates through active threads' do
+ it 'navigates through active threads', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391912' do
goto_next_thread
goto_next_thread
expect(page).to have_selector(second_discussion_selector, obscured: false)
diff --git a/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb b/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb
new file mode 100644
index 00000000000..e967787d2c7
--- /dev/null
+++ b/spec/features/merge_request/user_sees_real_time_reviewers_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > Real-time reviewers', feature_category: :code_review_workflow do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let(:user) { project.creator }
+ let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user) }
+
+ before do
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'updates in real-time', :js do
+ wait_for_requests
+
+ # Simulate a real-time update of reviewers
+ merge_request.update!(reviewer_ids: [user.id])
+ GraphqlTriggers.merge_request_reviewers_updated(merge_request)
+
+ expect(find('.reviewer')).to have_content(user.name)
+ end
+end
diff --git a/spec/features/merge_request/user_views_open_merge_request_spec.rb b/spec/features/merge_request/user_views_open_merge_request_spec.rb
index e481e3f2dfb..afa57cb0f8f 100644
--- a/spec/features/merge_request/user_views_open_merge_request_spec.rb
+++ b/spec/features/merge_request/user_views_open_merge_request_spec.rb
@@ -7,6 +7,18 @@ RSpec.describe 'User views an open merge request', feature_category: :code_revie
create(:merge_request, source_project: project, target_project: project, description: '# Description header')
end
+ context 'feature flags' do
+ let_it_be(:project) { create(:project, :public, :repository) }
+
+ it 'pushes content_editor_on_issues feature flag to frontend' do
+ stub_feature_flags(content_editor_on_issues: true)
+
+ visit merge_request_path(merge_request)
+
+ expect(page).to have_pushed_frontend_feature_flags(contentEditorOnIssues: true)
+ end
+ end
+
context 'when a merge request does not have repository' do
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
index 3171ae89fe6..371c40b40a5 100644
--- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
milestone: create(:milestone, project: project, due_date: '2013-12-11'),
created_at: 1.minute.ago,
updated_at: 1.minute.ago)
- @fix.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 10.seconds.ago)
+ @fix.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 20.seconds.ago)
@markdown = create(:merge_request,
title: 'markdown',
@@ -33,7 +33,8 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
reviewers: [user, user2, user3, user4],
milestone: create(:milestone, project: project, due_date: '2013-12-12'),
created_at: 2.minutes.ago,
- updated_at: 2.minutes.ago)
+ updated_at: 2.minutes.ago,
+ state: 'merged')
@markdown.metrics.update!(merged_at: 10.minutes.ago, latest_closed_at: 10.seconds.ago)
@merge_test = create(:merge_request,
@@ -49,7 +50,8 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
source_project: project,
source_branch: 'feautre',
created_at: 2.minutes.ago,
- updated_at: 1.minute.ago)
+ updated_at: 1.minute.ago,
+ state: 'merged')
@feature.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 10.minutes.ago)
end
@@ -79,10 +81,9 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
expect(page).to have_current_path(project_merge_requests_path(project), ignore_query: true)
expect(page).to have_content 'merge-test'
- expect(page).to have_content 'feature'
expect(page).not_to have_content 'fix'
expect(page).not_to have_content 'markdown'
- expect(count_merge_requests).to eq(2)
+ expect(count_merge_requests).to eq(1)
end
it 'filters on a specific assignee' do
@@ -90,8 +91,7 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
expect(page).not_to have_content 'merge-test'
expect(page).to have_content 'fix'
- expect(page).to have_content 'markdown'
- expect(count_merge_requests).to eq(2)
+ expect(count_merge_requests).to eq(1)
end
it 'sorts by newest' do
@@ -99,35 +99,35 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
expect(first_merge_request).to include('fix')
expect(last_merge_request).to include('merge-test')
- expect(count_merge_requests).to eq(4)
+ expect(count_merge_requests).to eq(2)
end
it 'sorts by last updated' do
visit_merge_requests(project, sort: sort_value_recently_updated)
expect(first_merge_request).to include('merge-test')
- expect(count_merge_requests).to eq(4)
+ expect(count_merge_requests).to eq(2)
end
it 'sorts by milestone due date' do
visit_merge_requests(project, sort: sort_value_milestone)
expect(first_merge_request).to include('fix')
- expect(count_merge_requests).to eq(4)
+ expect(count_merge_requests).to eq(2)
end
- it 'sorts by merged at' do
+ it 'ignores sorting by merged at' do
visit_merge_requests(project, sort: sort_value_merged_date)
- expect(first_merge_request).to include('markdown')
- expect(count_merge_requests).to eq(4)
+ expect(first_merge_request).to include('fix')
+ expect(count_merge_requests).to eq(2)
end
it 'sorts by closed at' do
visit_merge_requests(project, sort: sort_value_closed_date)
- expect(first_merge_request).to include('feature')
- expect(count_merge_requests).to eq(4)
+ expect(first_merge_request).to include('fix')
+ expect(count_merge_requests).to eq(2)
end
it 'filters on one label and sorts by milestone due date' do
@@ -141,6 +141,15 @@ RSpec.describe 'Merge requests > User lists merge requests', feature_category: :
expect(count_merge_requests).to eq(1)
end
+ context 'when viewing merged merge requests' do
+ it 'sorts by merged at' do
+ visit_merge_requests(project, state: 'merged', sort: sort_value_merged_date)
+
+ expect(first_merge_request).to include('markdown')
+ expect(count_merge_requests).to eq(2)
+ end
+ end
+
context 'while filtering on two labels' do
let(:label) { create(:label, project: project) }
let(:label2) { create(:label, project: project) }
diff --git a/spec/features/monitor_sidebar_link_spec.rb b/spec/features/monitor_sidebar_link_spec.rb
index d5f987d15c2..c4114b28b47 100644
--- a/spec/features/monitor_sidebar_link_spec.rb
+++ b/spec/features/monitor_sidebar_link_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category: :not_owned do
+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) }
diff --git a/spec/features/nav/new_nav_toggle_spec.rb b/spec/features/nav/new_nav_toggle_spec.rb
index 8e5cc7df053..2cdaf12bb15 100644
--- a/spec/features/nav/new_nav_toggle_spec.rb
+++ b/spec/features/nav/new_nav_toggle_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe 'new navigation toggle', :js, feature_category: :navigation do
it 'allows to disable new nav', :aggregate_failures do
within '[data-testid="super-sidebar"] [data-testid="user-dropdown"]' do
- find('button').click
+ click_button "#{user.name} user’s menu"
expect(page).to have_content('Navigation redesign')
toggle = page.find('.gl-toggle.is-checked')
diff --git a/spec/features/nav/top_nav_responsive_spec.rb b/spec/features/nav/top_nav_responsive_spec.rb
index 56f9d373f00..9ac63c26ba0 100644
--- a/spec/features/nav/top_nav_responsive_spec.rb
+++ b/spec/features/nav/top_nav_responsive_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
include MobileHelpers
+ include Spec::Support::Helpers::Features::InviteMembersModalHelper
let_it_be(:user) { create(:user) }
@@ -20,7 +21,7 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
context 'when menu is closed' do
it 'has page content and hides responsive menu', :aggregate_failures do
- expect(page).to have_css('.page-title', text: 'Projects')
+ expect(page).to have_css('.page-title', text: 'Explore projects')
expect(page).to have_link('Dashboard', id: 'logo')
expect(page).to have_no_css('.top-nav-responsive')
@@ -33,14 +34,15 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
end
it 'hides everything and shows responsive menu', :aggregate_failures do
- expect(page).to have_no_css('.page-title', text: 'Projects')
+ expect(page).to have_no_css('.page-title', text: 'Explore projects')
expect(page).to have_no_link('Dashboard', id: 'logo')
within '.top-nav-responsive' do
expect(page).to have_link(nil, href: search_path)
expect(page).to have_button('Projects')
expect(page).to have_button('Groups')
- expect(page).to have_link('Snippets', href: dashboard_snippets_path)
+ expect(page).to have_link('Your work', href: dashboard_projects_path)
+ expect(page).to have_link('Explore', href: explore_projects_path)
end
end
@@ -61,10 +63,12 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
visit project_path(project)
end
- it 'the add menu contains invite members dropdown option and goes to the members page' do
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
invite_members_from_menu
- expect(page).to have_current_path(project_project_members_path(project))
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{project.name} project")
+ end
end
end
@@ -75,10 +79,12 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
visit group_path(group)
end
- it 'the add menu contains invite members dropdown option and goes to the members page' do
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
invite_members_from_menu
- expect(page).to have_current_path(group_group_members_path(group))
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{group.name} group")
+ end
end
end
@@ -86,7 +92,7 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
click_button('Menu')
create_new_button.click
- click_link('Invite members')
+ click_button('Invite members')
end
def create_new_button
diff --git a/spec/features/nav/top_nav_spec.rb b/spec/features/nav/top_nav_spec.rb
index cc20b626e30..d2c0286cb4d 100644
--- a/spec/features/nav/top_nav_spec.rb
+++ b/spec/features/nav/top_nav_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
+ include Spec::Support::Helpers::Features::InviteMembersModalHelper
+
let_it_be(:user) { create(:user) }
before do
@@ -16,10 +18,12 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
visit project_path(project)
end
- it 'the add menu contains invite members dropdown option and goes to the members page' do
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
invite_members_from_menu
- expect(page).to have_current_path(project_project_members_path(project))
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{project.name} project")
+ end
end
end
@@ -30,10 +34,12 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
visit group_path(group)
end
- it 'the add menu contains invite members dropdown option and goes to the members page' do
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
invite_members_from_menu
- expect(page).to have_current_path(group_group_members_path(group))
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{group.name} group")
+ end
end
end
diff --git a/spec/features/populate_new_pipeline_vars_with_params_spec.rb b/spec/features/populate_new_pipeline_vars_with_params_spec.rb
index a83b5a81a41..b3ba0a874e9 100644
--- a/spec/features/populate_new_pipeline_vars_with_params_spec.rb
+++ b/spec/features/populate_new_pipeline_vars_with_params_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Populate new pipeline CI variables with url params", :js, feature_category: :pipeline_authoring do
+RSpec.describe "Populate new pipeline CI variables with url params", :js, feature_category: :pipeline_composition do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:page_path) { new_project_pipeline_path(project) }
diff --git a/spec/features/profiles/chat_names_spec.rb b/spec/features/profiles/chat_names_spec.rb
index 299ecdb6032..9e1bd69a239 100644
--- a/spec/features/profiles/chat_names_spec.rb
+++ b/spec/features/profiles/chat_names_spec.rb
@@ -3,8 +3,7 @@
require 'spec_helper'
RSpec.describe 'Profile > Chat', feature_category: :user_profile do
- let(:user) { create(:user) }
- let(:integration) { create(:integration) }
+ let_it_be(:user) { create(:user) }
before do
sign_in(user)
@@ -60,7 +59,7 @@ RSpec.describe 'Profile > Chat', feature_category: :user_profile do
end
describe 'visits chat accounts' do
- let!(:chat_name) { create(:chat_name, user: user, integration: integration) }
+ let_it_be(:chat_name) { create(:chat_name, user: user) }
before do
visit profile_chat_names_path
diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb
index 0fc59f21489..f39d9ddaf56 100644
--- a/spec/features/profiles/gpg_keys_spec.rb
+++ b/spec/features/profiles/gpg_keys_spec.rb
@@ -37,12 +37,13 @@ RSpec.describe 'Profile > GPG Keys', feature_category: :user_profile do
end
it 'user sees their key' do
- create(:gpg_key, user: user, key: GpgHelpers::User2.public_key)
+ gpg_key = create(:gpg_key, user: user, key: GpgHelpers::User2.public_key)
visit profile_gpg_keys_path
expect(page).to have_content('bette.cartwright@example.com Verified')
expect(page).to have_content('bette.cartwright@example.net Unverified')
expect(page).to have_content(GpgHelpers::User2.fingerprint)
+ expect(page).to have_selector('time.js-timeago', text: gpg_key.created_at.strftime('%b %d, %Y'))
end
it 'user removes a key via the key index' do
diff --git a/spec/features/profiles/user_creates_saved_reply_spec.rb b/spec/features/profiles/user_creates_saved_reply_spec.rb
new file mode 100644
index 00000000000..1d851b5cea0
--- /dev/null
+++ b/spec/features/profiles/user_creates_saved_reply_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Profile > Saved replies > User creates saved reply', :js,
+ feature_category: :user_profile do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+
+ visit profile_saved_replies_path
+
+ wait_for_requests
+ end
+
+ it 'shows the user a list of their saved replies' do
+ find('[data-testid="saved-reply-name-input"]').set('test')
+ find('[data-testid="saved-reply-content-input"]').set('Test content')
+
+ click_button 'Save'
+
+ wait_for_requests
+
+ expect(page).to have_content('My saved replies (1)')
+ expect(page).to have_content('test')
+ expect(page).to have_content('Test content')
+ end
+end
diff --git a/spec/features/profiles/user_deletes_saved_reply_spec.rb b/spec/features/profiles/user_deletes_saved_reply_spec.rb
new file mode 100644
index 00000000000..35bd6018ee3
--- /dev/null
+++ b/spec/features/profiles/user_deletes_saved_reply_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Profile > Saved replies > User deletes saved reply', :js,
+ feature_category: :user_profile do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:saved_reply) { create(:saved_reply, user: user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'shows the user a list of their saved replies' do
+ visit profile_saved_replies_path
+
+ find('[data-testid="saved-reply-delete-btn"]').click
+
+ page.within('.gl-modal') do
+ click_button 'Delete'
+ end
+
+ wait_for_requests
+
+ expect(page).not_to have_content(saved_reply.name)
+ end
+end
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index 3819723cc09..196134a0bda 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -97,6 +97,26 @@ RSpec.describe 'User edit profile', feature_category: :user_profile do
expect(page).to have_content('Website url is not a valid URL')
end
+ it 'validates that the dicord id has a valid length', :js do
+ valid_dicord_id = '123456789123456789'
+ too_short_discord_id = '123456'
+ too_long_discord_id = '123456789abcdefghijkl'
+
+ fill_in 'user_discord', with: too_short_discord_id
+ expect(page).to have_content('Discord ID is too short')
+
+ fill_in 'user_discord', with: too_long_discord_id
+ expect(page).to have_content('Discord ID is too long')
+
+ fill_in 'user_discord', with: valid_dicord_id
+
+ submit_settings
+
+ expect(user.reload).to have_attributes(
+ discord: valid_dicord_id
+ )
+ end
+
describe 'when I change my email', :js do
before do
user.send_reset_password_instructions
diff --git a/spec/features/profiles/user_updates_saved_reply_spec.rb b/spec/features/profiles/user_updates_saved_reply_spec.rb
new file mode 100644
index 00000000000..e341076ed0a
--- /dev/null
+++ b/spec/features/profiles/user_updates_saved_reply_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Profile > Saved replies > User updated saved reply', :js,
+ feature_category: :user_profile do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:saved_reply) { create(:saved_reply, user: user) }
+
+ before do
+ sign_in(user)
+
+ visit profile_saved_replies_path
+
+ wait_for_requests
+ end
+
+ it 'shows the user a list of their saved replies' do
+ find('[data-testid="saved-reply-edit-btn"]').click
+ find('[data-testid="saved-reply-name-input"]').set('test')
+
+ click_button 'Save'
+
+ wait_for_requests
+
+ expect(page).to have_selector('[data-testid="saved-reply-name"]', text: 'test')
+ end
+end
diff --git a/spec/features/profiles/user_uses_saved_reply_spec.rb b/spec/features/profiles/user_uses_saved_reply_spec.rb
new file mode 100644
index 00000000000..f9a4f4a7fa6
--- /dev/null
+++ b/spec/features/profiles/user_uses_saved_reply_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User uses saved reply', :js,
+ feature_category: :user_profile do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:saved_reply) { create(:saved_reply, user: user) }
+
+ before do
+ project.add_owner(user)
+
+ sign_in(user)
+ end
+
+ it 'applies saved reply' do
+ visit project_merge_request_path(merge_request.project, merge_request)
+
+ find('[data-testid="saved-replies-dropdown-toggle"]').click
+
+ wait_for_requests
+
+ find('[data-testid="saved-reply-dropdown-item"]').click
+
+ expect(find('.note-textarea').value).to eq(saved_reply.content)
+ end
+end
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 90f24c5b866..ac0ed91468c 100644
--- a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb
+++ b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'User visits the authentication log', feature_category: :user_pro
it 'shows correct menu item' do
visit(audit_log_profile_path)
- expect(page).to have_active_navigation('Authentication log')
+ expect(page).to have_active_navigation('Authentication Log')
end
end
diff --git a/spec/features/project_group_variables_spec.rb b/spec/features/project_group_variables_spec.rb
index 0e1e6e49c6d..8d600edadde 100644
--- a/spec/features/project_group_variables_spec.rb
+++ b/spec/features/project_group_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project group variables', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Project group variables', :js, feature_category: :pipeline_composition do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb
index 1a951980141..69b8408dcd6 100644
--- a/spec/features/project_variables_spec.rb
+++ b/spec/features/project_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project variables', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Project variables', :js, feature_category: :pipeline_composition do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:variable) { create(:ci_variable, key: 'test_key', value: 'test_value', masked: true) }
@@ -16,7 +16,18 @@ RSpec.describe 'Project variables', :js, feature_category: :pipeline_authoring d
wait_for_requests
end
- it_behaves_like 'variable list'
+ context 'when ci_variables_pages FF is enabled' do
+ it_behaves_like 'variable list'
+ it_behaves_like 'variable list pagination', :ci_variable
+ end
+
+ context 'when ci_variables_pages FF is disabled' do
+ before do
+ stub_feature_flags(ci_variables_pages: false)
+ end
+
+ it_behaves_like 'variable list'
+ end
it 'adds a new variable with an environment scope' do
click_button('Add variable')
diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb
index e6bd4b22b0a..c9e4aabe72a 100644
--- a/spec/features/projects/badges/list_spec.rb
+++ b/spec/features/projects/badges/list_spec.rb
@@ -43,13 +43,46 @@ RSpec.describe 'list of badges', feature_category: :continuous_integration do
it 'user changes current ref of build status badge', :js do
page.within('.pipeline-status') do
- first('.js-project-refs-dropdown').click
+ find('.ref-selector').click
+ wait_for_requests
- page.within '.project-refs-form' do
- click_link 'improve/awesome'
+ page.within('.ref-selector') do
+ fill_in 'Search by Git revision', with: 'improve/awesome'
+ wait_for_requests
+ find('li', text: 'improve/awesome', match: :prefer_exact).click
end
expect(page).to have_content 'badges/improve/awesome/pipeline.svg'
end
end
+
+ it 'user changes current ref of coverage status badge', :js do
+ page.within('.coverage-report') do
+ find('.ref-selector').click
+ wait_for_requests
+
+ page.within('.ref-selector') do
+ fill_in 'Search by Git revision', with: 'improve/awesome'
+ wait_for_requests
+ find('li', text: 'improve/awesome', match: :prefer_exact).click
+ end
+
+ expect(page).to have_content 'badges/improve/awesome/coverage.svg'
+ end
+ end
+
+ it 'user changes current ref of latest release status badge', :js do
+ page.within('.Latest-Release') do
+ find('.ref-selector').click
+ wait_for_requests
+
+ page.within('.ref-selector') do
+ fill_in 'Search by Git revision', with: 'improve/awesome'
+ wait_for_requests
+ find('li', text: 'improve/awesome', match: :prefer_exact).click
+ end
+
+ expect(page).to have_content '-/badges/release.svg'
+ end
+ end
end
diff --git a/spec/features/projects/blobs/blame_spec.rb b/spec/features/projects/blobs/blame_spec.rb
index 27b7c6ef2d5..d3558af81b8 100644
--- a/spec/features/projects/blobs/blame_spec.rb
+++ b/spec/features/projects/blobs/blame_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
within '[data-testid="blob-content-holder"]' do
expect(page).to have_css('.blame-commit')
expect(page).not_to have_css('.gl-pagination')
- expect(page).not_to have_link _('View entire blame')
+ expect(page).not_to have_link _('Show full blame')
end
end
@@ -53,7 +53,7 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
within '[data-testid="blob-content-holder"]' do
expect(page).to have_css('.blame-commit')
expect(page).to have_css('.gl-pagination')
- expect(page).to have_link _('View entire blame')
+ expect(page).to have_link _('Show full blame')
expect(page).to have_css('#L1')
expect(page).not_to have_css('#L3')
@@ -85,19 +85,42 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
end
end
- context 'when user clicks on View entire blame button' do
+ shared_examples 'a full blame page' do
+ context 'when user clicks on Show full blame button' do
+ before do
+ visit_blob_blame(path)
+ click_link _('Show full blame')
+ end
+
+ it 'displays the blame page without pagination' do
+ within '[data-testid="blob-content-holder"]' do
+ expect(page).to have_css('#L1')
+ expect(page).to have_css('#L667')
+ expect(page).not_to have_css('.gl-pagination')
+ end
+ end
+ end
+ end
+
+ context 'when streaming is disabled' do
before do
- visit_blob_blame(path)
+ stub_feature_flags(blame_page_streaming: false)
end
- it 'displays the blame page without pagination' do
- within '[data-testid="blob-content-holder"]' do
- click_link _('View entire blame')
+ it_behaves_like 'a full blame page'
+ end
- expect(page).to have_css('#L1')
- expect(page).to have_css('#L3')
- expect(page).not_to have_css('.gl-pagination')
- end
+ context 'when streaming is enabled' do
+ before do
+ stub_const('Projects::BlameService::STREAMING_PER_PAGE', 50)
+ end
+
+ it_behaves_like 'a full blame page'
+
+ it 'shows loading text' do
+ visit_blob_blame(path)
+ click_link _('Show full blame')
+ expect(page).to have_text('Loading full blame...')
end
end
@@ -112,7 +135,7 @@ RSpec.describe 'File blame', :js, feature_category: :projects do
within '[data-testid="blob-content-holder"]' do
expect(page).to have_css('.blame-commit')
expect(page).not_to have_css('.gl-pagination')
- expect(page).not_to have_link _('View entire blame')
+ expect(page).not_to have_link _('Show full blame')
end
end
end
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 7faf0e1a6b1..f9e3ff1670c 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -137,11 +137,13 @@ RSpec.describe 'File blob', :js, feature_category: :projects do
context 'when ref switch' do
def switch_ref_to(ref_name)
- first('[data-testid="branches-select"]').click
+ find('.ref-selector').click
+ wait_for_requests
- page.within '.project-refs-form' do
- click_link ref_name
+ page.within('.ref-selector') do
+ fill_in 'Search by Git revision', with: ref_name
wait_for_requests
+ find('li', text: ref_name, match: :prefer_exact).click
end
end
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index fc7833809b3..e1f1a63565c 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -201,6 +201,12 @@ RSpec.describe 'Branches', feature_category: :projects do
end
end
+ describe 'Link to branch rules' do
+ it 'does not have possibility to navigate to branch rules', :js do
+ expect(page).not_to have_content(s_("Branches|View branch rules"))
+ end
+ end
+
context 'on project with 0 branch' do
let(:project) { create(:project, :public, :empty_repo) }
let(:repository) { project.repository }
@@ -239,6 +245,17 @@ RSpec.describe 'Branches', feature_category: :projects do
expect(page).not_to have_content 'Merge request'
end
end
+
+ describe 'Navigate to branch rules from branches page' do
+ it 'shows repository settings page with Branch rules section expanded' do
+ visit project_branches_path(project)
+
+ view_branch_rules
+
+ expect(page).to have_content(
+ _('Define rules for who can push, merge, and the required approvals for each branch.'))
+ end
+ end
end
end
@@ -353,4 +370,11 @@ RSpec.describe 'Branches', feature_category: :projects do
click_button 'Yes, delete branch'
end
end
+
+ def view_branch_rules
+ page.within('.nav-controls') do
+ click_link s_("Branches|View branch rules")
+ end
+ wait_for_requests
+ end
end
diff --git a/spec/features/projects/ci/editor_spec.rb b/spec/features/projects/ci/editor_spec.rb
index 536152626af..ed03491d69a 100644
--- a/spec/features/projects/ci/editor_spec.rb
+++ b/spec/features/projects/ci/editor_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Pipeline Editor', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'Pipeline Editor', :js, feature_category: :pipeline_composition do
include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
let(:project) { create(:project_empty_repo, :public) }
diff --git a/spec/features/projects/ci/lint_spec.rb b/spec/features/projects/ci/lint_spec.rb
index 4fea07b18bc..aa9556761c6 100644
--- a/spec/features/projects/ci/lint_spec.rb
+++ b/spec/features/projects/ci/lint_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'CI Lint', :js, feature_category: :pipeline_authoring do
+RSpec.describe 'CI Lint', :js, feature_category: :pipeline_composition do
include Spec::Support::Helpers::Features::SourceEditorSpecHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb
index 93ce851521f..b608fc953f3 100644
--- a/spec/features/projects/commit/cherry_pick_spec.rb
+++ b/spec/features/projects/commit/cherry_pick_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe 'Cherry-pick Commits', :js, feature_category: :source_code_manage
cherry_pick_commit
- expect(page).to have_content('Sorry, we cannot cherry-pick this commit automatically.')
+ expect(page).to have_content('Commit cherry-pick failed:')
end
end
diff --git a/spec/features/projects/commit/user_reverts_commit_spec.rb b/spec/features/projects/commit/user_reverts_commit_spec.rb
index 8c7b8e6ba32..4d2abf55675 100644
--- a/spec/features/projects/commit/user_reverts_commit_spec.rb
+++ b/spec/features/projects/commit/user_reverts_commit_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe 'User reverts a commit', :js, feature_category: :source_code_mana
revert_commit
- expect(page).to have_content('Sorry, we cannot revert this commit automatically.')
+ expect(page).to have_content('Commit revert failed:')
end
end
diff --git a/spec/features/projects/integrations/apple_app_store_spec.rb b/spec/features/projects/integrations/apple_app_store_spec.rb
new file mode 100644
index 00000000000..b6dc6557e20
--- /dev/null
+++ b/spec/features/projects/integrations/apple_app_store_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Upload Dropzone Field', feature_category: :integrations do
+ include_context 'project integration activation'
+
+ it 'uploads the file data to the correct form fields and updates the messaging correctly', :js, :aggregate_failures do
+ visit_project_integration('Apple App Store Connect')
+
+ expect(page).to have_content('Drag your Private Key file here or click to upload.')
+ expect(page).not_to have_content('auth_key.p8')
+
+ find("input[name='service[dropzone_file_name]']",
+ visible: false).set(Rails.root.join('spec/fixtures/auth_key.p8'))
+
+ expect(find("input[name='service[app_store_private_key]']",
+ visible: false).value).to eq(File.read(Rails.root.join('spec/fixtures/auth_key.p8')))
+ expect(find("input[name='service[app_store_private_key_file_name]']", visible: false).value).to eq('auth_key.p8')
+
+ expect(page).not_to have_content('Drag your Private Key file here or click to upload.')
+ expect(page).to have_content('auth_key.p8')
+ end
+end
diff --git a/spec/features/projects/integrations/google_play_spec.rb b/spec/features/projects/integrations/google_play_spec.rb
new file mode 100644
index 00000000000..5db4bc8809f
--- /dev/null
+++ b/spec/features/projects/integrations/google_play_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Upload Dropzone Field', feature_category: :integrations do
+ include_context 'project integration activation'
+
+ it 'uploads the file data to the correct form fields and updates the messaging correctly', :js, :aggregate_failures do
+ visit_project_integration('Google Play')
+
+ expect(page).to have_content('Drag your key file here or click to upload.')
+ expect(page).not_to have_content('service_account.json')
+
+ find("input[name='service[dropzone_file_name]']",
+ visible: false).set(Rails.root.join('spec/fixtures/service_account.json'))
+
+ expect(find("input[name='service[service_account_key]']",
+ visible: false).value).to eq(File.read(Rails.root.join('spec/fixtures/service_account.json')))
+ expect(find("input[name='service[service_account_key_file_name]']",
+ visible: false).value).to eq('service_account.json')
+
+ expect(page).not_to have_content('Drag your key file here or click to upload.')
+ expect(page).to have_content('service_account.json')
+ end
+end
diff --git a/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb
index 16c7a3ff226..07cb138c414 100644
--- a/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb
+++ b/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb
@@ -145,7 +145,7 @@ RSpec.describe 'Set up Mattermost slash commands', :js, feature_category: :integ
it 'shows a token placeholder' do
token_placeholder = find_field('service_token')['placeholder']
- expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx')
+ expect(token_placeholder).to eq('')
end
end
end
diff --git a/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb b/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb
index ec00dcaf046..01c202baf70 100644
--- a/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb
+++ b/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe 'User activates Slack notifications', :js, feature_category: :int
context 'when integration is not configured yet' do
before do
- stub_feature_flags(integration_slack_app_notifications: false)
visit_project_integration('Slack notifications')
end
diff --git a/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb b/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb
index 0f6d721565e..38491501c65 100644
--- a/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb
+++ b/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'Slack slash commands', :js, feature_category: :integrations do
it 'shows a token placeholder' do
token_placeholder = find_field('Token')['placeholder']
- expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx')
+ expect(token_placeholder).to eq('')
end
it 'shows a help message' do
diff --git a/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb b/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
index a9e0fce1a1c..e4394010e8c 100644
--- a/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
+++ b/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'User triggers manual job with variables', :js, feature_category:
find("[data-testid='ci-variable-value']").set('key_value')
end
- find("[data-testid='trigger-manual-job-btn']").click
+ find("[data-testid='run-manual-job-btn']").click
wait_for_requests
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 67389fdda8a..07b8f8339eb 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -1065,16 +1065,19 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :proj
end
context "Build from other project" do
+ let(:other_job_download_path) { download_project_job_artifacts_path(project, job2) }
+
before do
create(:ci_job_artifact, :archive, file: artifacts_file, job: job2)
end
- it do
- requests = inspect_requests do
- visit download_project_job_artifacts_path(project, job2)
- end
+ it 'receive 404 from download request', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391632' do
+ requests = inspect_requests { visit other_job_download_path }
+
+ request = requests.find { |request| request.url == other_job_download_path }
- expect(requests.first.status_code).to eq(404)
+ expect(request).to be_present
+ expect(request.status_code).to eq(404)
end
end
end
diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb
index 6df1e974f42..78fad9b0b55 100644
--- a/spec/features/projects/members/sorting_spec.rb
+++ b/spec/features/projects/members/sorting_spec.rb
@@ -148,7 +148,7 @@ RSpec.describe 'Projects > Members > Sorting', :js, feature_category: :subgroups
def expect_sort_by(text, sort_direction)
within('[data-testid="members-sort-dropdown"]') do
- expect(page).to have_css('button[aria-haspopup="true"]', text: text)
+ expect(page).to have_css('button[aria-haspopup="menu"]', text: text)
expect(page).to have_button("Sorting Direction: #{sort_direction == :asc ? 'Ascending' : 'Descending'}")
end
end
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb
index 6090d132e3a..03ad5f9a292 100644
--- a/spec/features/projects/navbar_spec.rb
+++ b/spec/features/projects/navbar_spec.rb
@@ -22,6 +22,7 @@ RSpec.describe 'Project navbar', :with_license, feature_category: :projects do
insert_package_nav(_('Deployments'))
insert_infrastructure_registry_nav
insert_infrastructure_google_cloud_nav
+ insert_infrastructure_aws_nav
end
it_behaves_like 'verified navigation bar' do
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index c6a6ee68185..439ae4275ae 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -578,4 +578,53 @@ RSpec.describe 'New project', :js, feature_category: :projects do
it_behaves_like 'has instructions to enable OAuth'
end
end
+
+ describe 'sidebar' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:parent_group) { create(:group) }
+
+ before do
+ parent_group.add_owner(user)
+ sign_in(user)
+ end
+
+ context 'in the current navigation' do
+ before do
+ user.update!(use_new_navigation: false)
+ end
+
+ context 'for a new top-level project' do
+ it_behaves_like 'a dashboard page with sidebar', :new_project_path, :projects
+ 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(".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]")
+ end
+ end
+ end
+
+ context 'in the new navigation' do
+ before do
+ parent_group.add_owner(user)
+ user.update!(use_new_navigation: true)
+ sign_in(user)
+ end
+
+ 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")
+ 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)
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb b/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb
index a7da59200e9..16e64ade665 100644
--- a/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb
+++ b/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb
@@ -48,13 +48,13 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled, feature_categor
expect(domain.auto_ssl_enabled).to eq false
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false'
- expect(page).to have_selector '.card-header', text: 'Certificate'
+ expect(page).to have_selector '.gl-card-header', text: 'Certificate'
expect(page).to have_text domain.subject
find('.js-auto-ssl-toggle-container .js-project-feature-toggle button').click
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true'
- expect(page).not_to have_selector '.card-header', text: 'Certificate'
+ expect(page).not_to have_selector '.gl-card-header', text: 'Certificate'
expect(page).not_to have_text domain.subject
click_on 'Save Changes'
@@ -108,7 +108,7 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled, feature_categor
it 'user do not see private key' do
visit project_pages_domain_path(project, domain)
- expect(page).not_to have_selector '.card-header', text: 'Certificate'
+ expect(page).not_to have_selector '.gl-card-header', text: 'Certificate'
expect(page).not_to have_text domain.subject
end
end
@@ -131,16 +131,16 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled, feature_categor
it 'user sees certificate subject' do
visit project_pages_domain_path(project, domain)
- expect(page).to have_selector '.card-header', text: 'Certificate'
+ expect(page).to have_selector '.gl-card-header', text: 'Certificate'
expect(page).to have_text domain.subject
end
it 'user can delete the certificate', :js do
visit project_pages_domain_path(project, domain)
- expect(page).to have_selector '.card-header', text: 'Certificate'
+ expect(page).to have_selector '.gl-card-header', text: 'Certificate'
expect(page).to have_text domain.subject
- within('.card') { click_on 'Remove' }
+ within('.gl-card') { click_on 'Remove' }
accept_gl_confirm(button_text: 'Remove certificate')
expect(page).to have_field 'Certificate (PEM)', with: ''
expect(page).to have_field 'Key (PEM)', with: ''
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index 3ede76d3360..acb2af07e50 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -193,7 +193,7 @@ RSpec.describe 'Pipeline Schedules', :js, feature_category: :projects do
save_pipeline_schedule
end
- it 'user sees the new variable in edit window' do
+ 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')
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 343c7f53022..098d1201939 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -113,6 +113,50 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do
end
end
+ describe 'pipeline stats text' do
+ let(:finished_pipeline) do
+ create(:ci_pipeline, :success, project: project,
+ ref: 'master', sha: project.commit.id, user: user)
+ end
+
+ before do
+ finished_pipeline.update!(started_at: "2023-01-01 01:01:05", created_at: "2023-01-01 01:01:01",
+ finished_at: "2023-01-01 01:01:10", duration: 9)
+ end
+
+ context 'pipeline has finished' do
+ it 'shows pipeline stats with flag on' do
+ visit project_pipeline_path(project, finished_pipeline)
+
+ within '.pipeline-info' do
+ expect(page).to have_content("in #{finished_pipeline.duration} seconds")
+ expect(page).to have_content("and was queued for #{finished_pipeline.queued_duration} seconds")
+ end
+ end
+
+ it 'shows pipeline stats with flag off' do
+ stub_feature_flags(refactor_ci_minutes_consumption: false)
+
+ visit project_pipeline_path(project, finished_pipeline)
+
+ within '.pipeline-info' do
+ expect(page).to have_content("in #{finished_pipeline.duration} seconds " \
+ "and was queued for #{finished_pipeline.queued_duration} seconds")
+ end
+ end
+ end
+
+ context 'pipeline has not finished' do
+ it 'does not show pipeline stats' do
+ visit_pipeline
+
+ within '.pipeline-info' do
+ expect(page).not_to have_selector('[data-testid="pipeline-stats-text"]')
+ end
+ end
+ end
+ end
+
describe 'related merge requests' do
context 'when there are no related merge requests' do
it 'shows a "no related merge requests" message' do
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index b5f640f1cca..c46605fa9a8 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -278,6 +278,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
end
before do
+ stub_feature_flags(lazy_load_pipeline_dropdown_actions: false)
visit_project_pipelines
end
@@ -312,6 +313,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
end
before do
+ stub_feature_flags(lazy_load_pipeline_dropdown_actions: false)
visit_project_pipelines
end
@@ -695,7 +697,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
end
context 'when variables are specified' do
- it 'creates a new pipeline with variables', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/375552' do
+ it 'creates a new pipeline with variables' do
page.within(find("[data-testid='ci-variable-row']")) do
find("[data-testid='pipeline-form-ci-variable-key']").set('key_name')
find("[data-testid='pipeline-form-ci-variable-value']").set('value')
@@ -721,7 +723,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do
it { expect(page).to have_content('Missing CI config file') }
- it 'creates a pipeline after first request failed and a valid gitlab-ci.yml file is available when trying again', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/375552' do
+ it 'creates a pipeline after first request failed and a valid gitlab-ci.yml file is available when trying again' do
stub_ci_pipeline_to_return_yaml_file
expect do
diff --git a/spec/features/projects/settings/access_tokens_spec.rb b/spec/features/projects/settings/access_tokens_spec.rb
index 12e14f5193f..a38c10c6bab 100644
--- a/spec/features/projects/settings/access_tokens_spec.rb
+++ b/spec/features/projects/settings/access_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project > Settings > Access Tokens', :js, feature_category: :credential_management do
+RSpec.describe 'Project > Settings > Access Tokens', :js, feature_category: :user_management do
include Spec::Support::Helpers::ModalHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/features/projects/settings/monitor_settings_spec.rb b/spec/features/projects/settings/monitor_settings_spec.rb
index 4b553b57331..900f18bf49e 100644
--- a/spec/features/projects/settings/monitor_settings_spec.rb
+++ b/spec/features/projects/settings/monitor_settings_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Settings > For a forked project', :js, feature_category: :projects do
+ include ListboxHelpers
+
let_it_be(:project) { create(:project, :repository, create_templates: :issue) }
let(:user) { project.first_owner }
@@ -47,7 +49,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js, feature_catego
check(create_issue)
uncheck(send_email)
click_on('No template selected')
- click_on('bug')
+ select_listbox_item('bug')
save_form
click_settings_tab
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 d4c1fe4d43e..57aa3a56c6d 100644
--- a/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
+++ b/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
@@ -38,6 +38,15 @@ feature_category: :projects do
expect(section).to have_text 'Clean up image tags'
end
+ it 'passes axe automated accessibility testing' do
+ subject
+
+ wait_for_requests
+
+ expect(page).to be_axe_clean.within('[data-testid="container-expiration-policy-project-settings"]')
+ .skipping :'link-in-text-block'
+ end
+
it 'saves cleanup policy submit the form' do
subject
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index 072b5f7f3b0..628fa23afdc 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -21,6 +21,15 @@ feature_category: :projects do
end
context 'as owner', :js do
+ it 'passes axe automated accessibility testing' do
+ subject
+
+ wait_for_requests
+
+ expect(page).to be_axe_clean.within('[data-testid="packages-and-registries-project-settings"]')
+ .skipping :'link-in-text-block'
+ end
+
it 'shows active tab on sidebar' do
subject
diff --git a/spec/features/projects/user_changes_project_visibility_spec.rb b/spec/features/projects/user_changes_project_visibility_spec.rb
index 5daa5b98b6e..64af25aea28 100644
--- a/spec/features/projects/user_changes_project_visibility_spec.rb
+++ b/spec/features/projects/user_changes_project_visibility_spec.rb
@@ -91,23 +91,4 @@ RSpec.describe 'User changes public project visibility', :js, feature_category:
it_behaves_like 'does not require confirmation'
end
-
- context 'with unlink_fork_network_upon_visibility_decrease = false' do
- let(:project) { create(:project, :empty_repo, :public) }
-
- before do
- stub_feature_flags(unlink_fork_network_upon_visibility_decrease: false)
-
- fork_project(project, project.first_owner)
-
- sign_in(project.first_owner)
-
- visit edit_project_path(project)
-
- # https://gitlab.com/gitlab-org/gitlab/-/issues/381259
- allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(110)
- end
-
- it_behaves_like 'does not require confirmation'
- end
end
diff --git a/spec/features/projects/work_items/work_item_children_spec.rb b/spec/features/projects/work_items/work_item_children_spec.rb
new file mode 100644
index 00000000000..43a6b2771f6
--- /dev/null
+++ b/spec/features/projects/work_items/work_item_children_spec.rb
@@ -0,0 +1,179 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Work item children', :js, feature_category: :team_planning do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :public, namespace: group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:issue) { create(:issue, project: project) }
+
+ context 'for signed in user' do
+ before do
+ project.add_developer(user)
+
+ sign_in(user)
+
+ stub_feature_flags(work_items: true)
+
+ visit project_issue_path(project, issue)
+
+ wait_for_requests
+ end
+
+ it 'are not displayed when issue does not have work item children', :aggregate_failures do
+ page.within('[data-testid="work-item-links"]') do
+ expect(find('[data-testid="links-empty"]')).to have_content(_('No tasks are currently assigned.'))
+ expect(page).not_to have_selector('[data-testid="add-links-form"]')
+ expect(page).not_to have_selector('[data-testid="links-child"]')
+ end
+ end
+
+ it 'toggles widget body', :aggregate_failures do
+ page.within('[data-testid="work-item-links"]') do
+ expect(page).to have_selector('[data-testid="widget-body"]')
+
+ click_button 'Collapse'
+
+ expect(page).not_to have_selector('[data-testid="widget-body"]')
+
+ click_button 'Expand'
+
+ expect(page).to have_selector('[data-testid="widget-body"]')
+ end
+ end
+
+ it 'toggles form', :aggregate_failures do
+ page.within('[data-testid="work-item-links"]') do
+ expect(page).not_to have_selector('[data-testid="add-links-form"]')
+
+ click_button 'Add'
+ click_button 'New task'
+
+ expect(page).to have_selector('[data-testid="add-links-form"]')
+
+ click_button 'Cancel'
+
+ expect(page).not_to have_selector('[data-testid="add-links-form"]')
+ end
+ end
+
+ it 'adds a new child task', :aggregate_failures do
+ page.within('[data-testid="work-item-links"]') do
+ click_button 'Add'
+ click_button 'New task'
+
+ expect(page).to have_button('Create task', disabled: true)
+ fill_in 'Add a title', with: 'Task 1'
+
+ expect(page).to have_button('Create task', disabled: false)
+
+ click_button 'Create task'
+
+ wait_for_all_requests
+
+ expect(find('[data-testid="links-child"]')).to have_content('Task 1')
+ end
+ end
+
+ it 'removes a child task and undoing', :aggregate_failures do
+ page.within('[data-testid="work-item-links"]') do
+ click_button 'Add'
+ click_button 'New task'
+ fill_in 'Add a title', with: 'Task 1'
+ click_button 'Create task'
+ wait_for_all_requests
+
+ expect(find('[data-testid="links-child"]')).to have_content('Task 1')
+ expect(find('[data-testid="children-count"]')).to have_content('1')
+
+ find('[data-testid="links-menu"]').click
+ click_button 'Remove'
+
+ wait_for_all_requests
+
+ expect(page).not_to have_content('Task 1')
+ expect(find('[data-testid="children-count"]')).to have_content('0')
+ end
+
+ page.within('.gl-toast') do
+ expect(find('.toast-body')).to have_content(_('Child removed'))
+ find('.b-toaster a', text: 'Undo').click
+ end
+
+ wait_for_all_requests
+
+ page.within('[data-testid="work-item-links"]') do
+ expect(find('[data-testid="links-child"]')).to have_content('Task 1')
+ expect(find('[data-testid="children-count"]')).to have_content('1')
+ end
+ end
+
+ context 'with existing task' do
+ let_it_be(:task) { create(:work_item, :task, project: project) }
+
+ it 'adds an existing child task', :aggregate_failures do
+ page.within('[data-testid="work-item-links"]') do
+ click_button 'Add'
+ click_button 'Existing task'
+
+ expect(page).to have_button('Add task', disabled: true)
+ find('[data-testid="work-item-token-select-input"]').set(task.title)
+ wait_for_all_requests
+ click_button task.title
+
+ expect(page).to have_button('Add task', disabled: false)
+
+ click_button 'Add task'
+
+ wait_for_all_requests
+
+ expect(find('[data-testid="links-child"]')).to have_content(task.title)
+ end
+ end
+ end
+
+ context 'in work item metadata' do
+ let_it_be(:label) { create(:label, title: 'Label 1', project: project) }
+ let_it_be(:milestone) { create(:milestone, project: project, title: 'v1') }
+ let_it_be(:task) do
+ create(
+ :work_item,
+ :task,
+ project: project,
+ labels: [label],
+ assignees: [user],
+ milestone: milestone
+ )
+ end
+
+ before do
+ visit project_issue_path(project, issue)
+
+ wait_for_requests
+ end
+
+ it 'displays labels, milestone and assignee for work item children', :aggregate_failures do
+ page.within('[data-testid="work-item-links"]') do
+ click_button 'Add'
+ click_button 'Existing task'
+
+ find('[data-testid="work-item-token-select-input"]').set(task.title)
+ wait_for_all_requests
+ click_button task.title
+
+ click_button 'Add task'
+
+ wait_for_all_requests
+ end
+
+ page.within('[data-testid="links-child"]') do
+ expect(page).to have_content(task.title)
+ expect(page).to have_content(label.title)
+ expect(page).to have_link(user.name)
+ expect(page).to have_content(milestone.title)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/work_items/work_item_spec.rb b/spec/features/projects/work_items/work_item_spec.rb
new file mode 100644
index 00000000000..d0d458350b5
--- /dev/null
+++ b/spec/features/projects/work_items/work_item_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Work item', :js, feature_category: :team_planning do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:work_item) { create(:work_item, project: project) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:milestones) { create_list(:milestone, 25, project: project) }
+
+ context 'for signed in user' do
+ before do
+ project.add_developer(user)
+
+ sign_in(user)
+ end
+
+ context 'with internal id' do
+ before do
+ visit project_work_items_path(project, work_items_path: work_item.iid, iid_path: true)
+ end
+
+ it_behaves_like 'work items title'
+ it_behaves_like 'work items status'
+ it_behaves_like 'work items assignees'
+ it_behaves_like 'work items labels'
+ it_behaves_like 'work items comments'
+ it_behaves_like 'work items description'
+ it_behaves_like 'work items milestone'
+ end
+
+ context 'with global id' do
+ before do
+ stub_feature_flags(use_iid_in_work_items_path: false)
+ visit project_work_items_path(project, work_items_path: work_item.id)
+ end
+
+ it_behaves_like 'work items status'
+ it_behaves_like 'work items assignees'
+ it_behaves_like 'work items labels'
+ it_behaves_like 'work items comments'
+ it_behaves_like 'work items description'
+ end
+ end
+
+ context 'for signed in owner' do
+ before do
+ project.add_owner(user)
+
+ sign_in(user)
+
+ visit project_work_items_path(project, work_items_path: work_item.id)
+ end
+
+ it_behaves_like 'work items invite members'
+ end
+end
diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb
index c2058a5c345..45315f53fd6 100644
--- a/spec/features/protected_tags_spec.rb
+++ b/spec/features/protected_tags_spec.rb
@@ -16,8 +16,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
it "allows creating explicit protected tags" do
visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") { expect(page).to have_content('some-tag') }
expect(ProtectedTag.count).to eq(1)
@@ -30,8 +30,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") { expect(page).to have_content(commit.id[0..7]) }
end
@@ -39,8 +39,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
it "displays an error message if the named tag does not exist" do
visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") { expect(page).to have_content('tag was removed') }
end
@@ -50,8 +50,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
it "allows creating protected tags with a wildcard" do
visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") { expect(page).to have_content('*-stable') }
expect(ProtectedTag.count).to eq(1)
@@ -64,8 +64,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
within(".protected-tags-list") do
expect(page).to have_content("Protected tags (2)")
@@ -80,8 +80,8 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
- set_allowed_to('create') if Gitlab.ee?
- click_on "Protect"
+ set_allowed_to('create')
+ click_on_protect
visit project_protected_tags_path(project)
click_on "2 matching tags"
@@ -101,4 +101,14 @@ RSpec.describe 'Protected Tags', :js, :with_license, feature_category: :source_c
include_examples "protected tags > access control > CE"
end
+
+ context 'when the users for protected tags feature is off' do
+ before do
+ stub_licensed_features(protected_refs_for_users: false)
+ end
+
+ include_examples 'Deploy keys with protected tags' do
+ let(:all_dropdown_sections) { ['Roles', 'Deploy Keys'] }
+ end
+ end
end
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 334a192bec4..127176da3fb 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -26,11 +26,21 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
wait_for_all_requests
end
- it 'starts searching by pressing the enter key' do
- submit_search('gitlab')
+ context 'when searching by pressing the enter key' do
+ before do
+ submit_search('gitlab')
+ end
+
+ it 'renders page title' do
+ page.within('.page-title') do
+ expect(page).to have_content('Search')
+ end
+ end
- page.within('.page-title') do
- expect(page).to have_content('Search')
+ it 'renders breadcrumbs' do
+ page.within('.breadcrumbs-links') do
+ expect(page).to have_content('Search')
+ end
end
end
diff --git a/spec/features/security/admin_access_spec.rb b/spec/features/security/admin_access_spec.rb
index de81444ed71..d162b24175f 100644
--- a/spec/features/security/admin_access_spec.rb
+++ b/spec/features/security/admin_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Admin::Projects", feature_category: :permissions do
+RSpec.describe "Admin::Projects", feature_category: :system_access do
include AccessMatchers
describe "GET /admin/projects" do
diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb
index 948a4567624..0d60f1b1d11 100644
--- a/spec/features/security/dashboard_access_spec.rb
+++ b/spec/features/security/dashboard_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Dashboard access", feature_category: :permissions do
+RSpec.describe "Dashboard access", feature_category: :system_access do
include AccessMatchers
describe "GET /dashboard" do
diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb
index ad2df4a1882..49f81600ac2 100644
--- a/spec/features/security/group/internal_access_spec.rb
+++ b/spec/features/security/group/internal_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Internal Group access', feature_category: :permissions do
+RSpec.describe 'Internal Group access', feature_category: :system_access do
include AccessMatchers
let(:group) { create(:group, :internal) }
diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb
index 2e7b7512b45..5206667427e 100644
--- a/spec/features/security/group/private_access_spec.rb
+++ b/spec/features/security/group/private_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Private Group access', feature_category: :permissions do
+RSpec.describe 'Private Group access', feature_category: :system_access do
include AccessMatchers
let(:group) { create(:group, :private) }
diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb
index 513c5710c8f..5c5580908aa 100644
--- a/spec/features/security/group/public_access_spec.rb
+++ b/spec/features/security/group/public_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Public Group access', feature_category: :permissions do
+RSpec.describe 'Public Group access', feature_category: :system_access do
include AccessMatchers
let(:group) { create(:group, :public) }
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index e35e7ed742b..8ad4bedfdf8 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Internal Project Access", feature_category: :permissions do
+RSpec.describe "Internal Project Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project, reload: true) { create(:project, :internal, :repository, :with_namespace_settings) }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index 59ddb18ae8a..d2d74ecf5c9 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Private Project Access", feature_category: :permissions do
+RSpec.describe "Private Project Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project, reload: true) do
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 425691001f2..916f289b0b8 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Public Project Access", feature_category: :permissions do
+RSpec.describe "Public Project Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project, reload: true) do
diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb
index b7dcc5f31d3..6ed0ec20210 100644
--- a/spec/features/security/project/snippet/internal_access_spec.rb
+++ b/spec/features/security/project/snippet/internal_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Internal Project Snippets Access", feature_category: :permissions do
+RSpec.describe "Internal Project Snippets Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project) { create(:project, :internal) }
diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb
index 0ae45abb7ec..ef61f79a1b5 100644
--- a/spec/features/security/project/snippet/private_access_spec.rb
+++ b/spec/features/security/project/snippet/private_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Private Project Snippets Access", feature_category: :permissions do
+RSpec.describe "Private Project Snippets Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project) { create(:project, :private) }
diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb
index b98f665c0dc..27fee745635 100644
--- a/spec/features/security/project/snippet/public_access_spec.rb
+++ b/spec/features/security/project/snippet/public_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Public Project Snippets Access", feature_category: :permissions do
+RSpec.describe "Public Project Snippets Access", feature_category: :system_access do
include AccessMatchers
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/features/signed_commits_spec.rb b/spec/features/signed_commits_spec.rb
index 5d9b451cdf6..541f94a9340 100644
--- a/spec/features/signed_commits_spec.rb
+++ b/spec/features/signed_commits_spec.rb
@@ -139,7 +139,7 @@ RSpec.describe 'GPG signed commits', feature_category: :source_code_management d
end
end
- it "verified and the gpg user's profile doesn't exist anymore" do
+ it "verified and the gpg user's profile doesn't exist anymore", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/395802' do
user_1_key
visit project_commit_path(project, GpgHelpers::SIGNED_AND_AUTHORED_SHA)
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
index dc2fcdd7305..d6ff8c066c4 100644
--- a/spec/features/snippets/show_spec.rb
+++ b/spec/features/snippets/show_spec.rb
@@ -28,11 +28,10 @@ RSpec.describe 'Snippet', :js, feature_category: :source_code_management do
it_behaves_like 'a dashboard page with sidebar', :dashboard_snippets_path, :snippets
context 'when unauthenticated' do
- it 'does not have the sidebar' do
+ it 'shows the "Explore" sidebar' do
visit snippet_path(snippet)
- expect(page).to have_title _('Snippets')
- expect(page).not_to have_css('aside.nav-sidebar')
+ expect(page).to have_css('aside.nav-sidebar[aria-label="Explore"]')
end
end
diff --git a/spec/features/topic_show_spec.rb b/spec/features/topic_show_spec.rb
index d640e4e4edb..39b8782ea58 100644
--- a/spec/features/topic_show_spec.rb
+++ b/spec/features/topic_show_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Topic show page', feature_category: :projects do
it 'shows title, avatar and description as markdown' do
expect(page).to have_content(topic.title)
expect(page).not_to have_content(topic.name)
- expect(page).to have_selector('.avatar-container > img.topic-avatar')
+ expect(page).to have_selector('.gl-avatar.gl-avatar-s64')
expect(find('.topic-description')).to have_selector('p > strong')
expect(find('.topic-description')).to have_selector('p > a[rel]')
expect(find('.topic-description')).to have_selector('p > gl-emoji')
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
deleted file mode 100644
index 9ef0626b2b2..00000000000
--- a/spec/features/u2f_spec.rb
+++ /dev/null
@@ -1,216 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js,
-feature_category: :authentication_and_authorization do
- include Spec::Support::Helpers::Features::TwoFactorHelpers
-
- before do
- stub_feature_flags(webauthn: false)
- end
-
- it_behaves_like 'hardware device for 2fa', 'U2F'
-
- describe "registration" do
- let(:user) { create(:user) }
-
- before do
- gitlab_sign_in(user)
- user.update_attribute(:otp_required_for_login, true)
- end
-
- describe 'when 2FA via OTP is enabled' do
- it 'allows registering more than one device' do
- visit profile_account_path
-
- # First device
- manage_two_factor_authentication
- first_device = register_u2f_device
- expect(page).to have_content('Your U2F device was registered')
-
- # Second device
- second_device = register_u2f_device(name: 'My other device')
- expect(page).to have_content('Your U2F device was registered')
-
- expect(page).to have_content(first_device.name)
- expect(page).to have_content(second_device.name)
- expect(U2fRegistration.count).to eq(2)
- end
- end
-
- it 'allows the same device to be registered for multiple users' do
- # U2f specs will be removed after WebAuthn migration completed
- pending('FakeU2fDevice has static key handle, '\
- 'leading to duplicate credential_xid for WebAuthn during migration, '\
- 'resulting in unique constraint violation')
-
- # First user
- visit profile_account_path
- manage_two_factor_authentication
- u2f_device = register_u2f_device
- expect(page).to have_content('Your U2F device was registered')
- gitlab_sign_out
-
- # Second user
- user = gitlab_sign_in(:user)
- user.update_attribute(:otp_required_for_login, true)
- visit profile_account_path
- manage_two_factor_authentication
- register_u2f_device(u2f_device, name: 'My other device')
- expect(page).to have_content('Your U2F device was registered')
-
- expect(U2fRegistration.count).to eq(2)
- end
-
- context "when there are form errors" do
- it "doesn't register the device if there are errors" do
- visit profile_account_path
- manage_two_factor_authentication
-
- # Have the "u2f device" respond with bad data
- page.execute_script("u2f.register = function(_,_,_,callback) { callback('bad response'); };")
- click_on 'Set up new device'
- expect(page).to have_content('Your device was successfully set up')
- click_on 'Register device'
-
- expect(U2fRegistration.count).to eq(0)
- expect(page).to have_content("The form contains the following error")
- expect(page).to have_content("did not send a valid JSON response")
- end
-
- it "allows retrying registration" do
- visit profile_account_path
- manage_two_factor_authentication
-
- # Failed registration
- page.execute_script("u2f.register = function(_,_,_,callback) { callback('bad response'); };")
- click_on 'Set up new device'
- expect(page).to have_content('Your device was successfully set up')
- click_on 'Register device'
- expect(page).to have_content("The form contains the following error")
-
- # Successful registration
- register_u2f_device
-
- expect(page).to have_content('Your U2F device was registered')
- expect(U2fRegistration.count).to eq(1)
- end
- end
- end
-
- describe "authentication" do
- let(:user) { create(:user) }
-
- before do
- # Register and logout
- gitlab_sign_in(user)
- user.update_attribute(:otp_required_for_login, true)
- visit profile_account_path
- manage_two_factor_authentication
- @u2f_device = register_u2f_device
- gitlab_sign_out
- end
-
- describe "when 2FA via OTP is disabled" do
- it "allows logging in with the U2F device" do
- user.update_attribute(:otp_required_for_login, false)
- gitlab_sign_in(user)
-
- @u2f_device.respond_to_u2f_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
- end
- end
-
- describe "when 2FA via OTP is enabled" do
- it "allows logging in with the U2F device" do
- user.update_attribute(:otp_required_for_login, true)
- gitlab_sign_in(user)
-
- @u2f_device.respond_to_u2f_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
- end
- end
-
- describe "when a given U2F device has already been registered by another user" do
- describe "but not the current user" do
- it "does not allow logging in with that particular device" do
- # Register current user with the different U2F device
- current_user = gitlab_sign_in(:user)
- current_user.update_attribute(:otp_required_for_login, true)
- visit profile_account_path
- manage_two_factor_authentication
- register_u2f_device(name: 'My other device')
- gitlab_sign_out
-
- # Try authenticating user with the old U2F device
- gitlab_sign_in(current_user)
- @u2f_device.respond_to_u2f_authentication
- expect(page).to have_content('Authentication via U2F device failed')
- end
- end
-
- describe "and also the current user" do
- it "allows logging in with that particular device" do
- # U2f specs will be removed after WebAuthn migration completed
- pending('FakeU2fDevice has static key handle, '\
- 'leading to duplicate credential_xid for WebAuthn during migration, '\
- 'resulting in unique constraint violation')
-
- # Register current user with the same U2F device
- current_user = gitlab_sign_in(:user)
- current_user.update_attribute(:otp_required_for_login, true)
- visit profile_account_path
- manage_two_factor_authentication
- register_u2f_device(@u2f_device)
- gitlab_sign_out
-
- # Try authenticating user with the same U2F device
- gitlab_sign_in(current_user)
- @u2f_device.respond_to_u2f_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
- end
- end
- end
-
- describe "when a given U2F device has not been registered" do
- it "does not allow logging in with that particular device" do
- unregistered_device = FakeU2fDevice.new(page, 'My device')
- gitlab_sign_in(user)
- unregistered_device.respond_to_u2f_authentication
-
- expect(page).to have_content('Authentication via U2F device failed')
- end
- end
-
- describe "when more than one device has been registered by the same user" do
- it "allows logging in with either device" do
- # Register first device
- user = gitlab_sign_in(:user)
- user.update_attribute(:otp_required_for_login, true)
- visit profile_two_factor_auth_path
- expect(page).to have_content("Your device needs to be set up.")
- first_device = register_u2f_device
-
- # Register second device
- visit profile_two_factor_auth_path
- expect(page).to have_content("Your device needs to be set up.")
- second_device = register_u2f_device(name: 'My other device')
- gitlab_sign_out
-
- # Authenticate as both devices
- [first_device, second_device].each do |device|
- gitlab_sign_in(user)
- device.respond_to_u2f_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
-
- gitlab_sign_out
- end
- end
- end
- end
-end
diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb
index 23fa6261bd5..28699bc2c24 100644
--- a/spec/features/unsubscribe_links_spec.rb
+++ b/spec/features/unsubscribe_links_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Unsubscribe links', :sidekiq_inline, feature_category: :not_owned do
+RSpec.describe 'Unsubscribe links', :sidekiq_inline, feature_category: :shared do
include Warden::Test::Helpers
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 5e683befeec..37b5d80ed61 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -109,6 +109,10 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'within the grace period' do
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
+ end
+
it 'allows to login' do
expect(authentication_metrics).to increment(:user_authenticated_counter)
@@ -137,11 +141,9 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'when resending the confirmation email' do
- it 'redirects to the "almost there" page' do
- stub_feature_flags(soft_email_confirmation: false)
-
- user = create(:user)
+ let_it_be(:user) { create(:user) }
+ it 'redirects to the "almost there" page' do
visit new_user_confirmation_path
fill_in 'user_email', with: user.email
click_button 'Resend'
@@ -207,8 +209,89 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
describe 'with two-factor authentication', :js do
def enter_code(code)
- fill_in 'user_otp_attempt', with: code
- click_button 'Verify code'
+ if page.has_content?("Sign in via 2FA code")
+ click_on("Sign in via 2FA code")
+ enter_code(code)
+ else
+ fill_in 'user_otp_attempt', with: code
+ click_button 'Verify code'
+ end
+ end
+
+ shared_examples_for 'can login with recovery codes' do
+ context 'using backup code' do
+ let(:codes) { user.generate_otp_backup_codes! }
+
+ before do
+ expect(codes.size).to eq 10
+
+ # Ensure the generated codes get saved
+ user.save!(touch: false)
+ end
+
+ context 'with valid code' do
+ it 'allows login' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_two_factor_authenticated_counter)
+
+ enter_code(codes.sample)
+
+ expect(page).to have_current_path root_path, ignore_query: true
+ end
+
+ it 'invalidates the used code' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_two_factor_authenticated_counter)
+
+ expect { enter_code(codes.sample) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+ end
+
+ it 'invalidates backup codes twice in a row' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter).twice
+ .and increment(:user_two_factor_authenticated_counter).twice
+ .and increment(:user_session_destroyed_counter)
+
+ random_code = codes.delete(codes.sample)
+ expect { enter_code(random_code) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+
+ gitlab_sign_out
+ gitlab_sign_in(user)
+
+ expect { enter_code(codes.sample) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+ end
+
+ it 'triggers ActiveSession.cleanup for the user' do
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
+ .and increment(:user_two_factor_authenticated_counter)
+ expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original
+
+ enter_code(codes.sample)
+ end
+ end
+
+ context 'with invalid code' do
+ it 'blocks login' do
+ # TODO, invalid two factor authentication does not increment
+ # metrics / counters, see gitlab-org/gitlab-ce#49785
+
+ code = codes.sample
+ expect(user.invalidate_otp_backup_code!(code)).to eq true
+
+ user.save!(touch: false)
+ expect(user.reload.otp_backup_codes.size).to eq 9
+
+ enter_code(code)
+ expect(page).to have_content('Invalid two-factor code.')
+ end
+ end
+ end
end
context 'with valid username/password' do
@@ -216,8 +299,6 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
before do
gitlab_sign_in(user, remember: true)
-
- expect(page).to have_content('Two-factor authentication code')
end
it 'does not show a "You are already signed in." error message' do
@@ -290,78 +371,16 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
end
- context 'using backup code' do
- let(:codes) { user.generate_otp_backup_codes! }
-
- before do
- expect(codes.size).to eq 10
-
- # Ensure the generated codes get saved
- user.save!(touch: false)
- end
-
- context 'with valid code' do
- it 'allows login' do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
- .and increment(:user_two_factor_authenticated_counter)
-
- enter_code(codes.sample)
-
- expect(page).to have_current_path root_path, ignore_query: true
- end
+ context 'when user with TOTP enabled' do
+ let(:user) { create(:user, :two_factor) }
- it 'invalidates the used code' do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
- .and increment(:user_two_factor_authenticated_counter)
-
- expect { enter_code(codes.sample) }
- .to change { user.reload.otp_backup_codes.size }.by(-1)
- end
-
- it 'invalidates backup codes twice in a row' do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter).twice
- .and increment(:user_two_factor_authenticated_counter).twice
- .and increment(:user_session_destroyed_counter)
-
- random_code = codes.delete(codes.sample)
- expect { enter_code(random_code) }
- .to change { user.reload.otp_backup_codes.size }.by(-1)
-
- gitlab_sign_out
- gitlab_sign_in(user)
-
- expect { enter_code(codes.sample) }
- .to change { user.reload.otp_backup_codes.size }.by(-1)
- end
-
- it 'triggers ActiveSession.cleanup for the user' do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
- .and increment(:user_two_factor_authenticated_counter)
- expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original
-
- enter_code(codes.sample)
- end
- end
-
- context 'with invalid code' do
- it 'blocks login' do
- # TODO, invalid two factor authentication does not increment
- # metrics / counters, see gitlab-org/gitlab-ce#49785
-
- code = codes.sample
- expect(user.invalidate_otp_backup_code!(code)).to eq true
+ include_examples 'can login with recovery codes'
+ end
- user.save!(touch: false)
- expect(user.reload.otp_backup_codes.size).to eq 9
+ context 'when user with only Webauthn enabled' do
+ let(:user) { create(:user, :two_factor_via_webauthn, registrations_count: 1) }
- enter_code(code)
- expect(page).to have_content('Invalid two-factor code.')
- end
- end
+ include_examples 'can login with recovery codes'
end
end
@@ -379,8 +398,8 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
context 'when authn_context is worth two factors' do
let(:mock_saml_response) do
File.read('spec/fixtures/authentication/saml_response.xml')
- .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
- 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS')
+ .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
+ 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS')
end
it 'signs user in without prompting for second factor' do
@@ -394,7 +413,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
sign_in_using_saml!
expect_single_session_with_authenticated_ttl
- expect(page).not_to have_content('Two-Factor Authentication')
+ expect(page).not_to have_content(_('Enter verification code'))
expect(page).to have_current_path root_path, ignore_query: true
end
end
@@ -408,7 +427,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
sign_in_using_saml!
- expect(page).to have_content('Two-factor authentication code')
+ expect(page).to have_content('Enter verification code')
enter_code(user.current_otp)
@@ -928,22 +947,22 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
it 'asks the user to accept the terms before setting an email',
quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/388049', type: :flaky } do
- expect(authentication_metrics)
- .to increment(:user_authenticated_counter)
+ expect(authentication_metrics)
+ .to increment(:user_authenticated_counter)
- gitlab_sign_in_via('saml', user, 'my-uid')
+ gitlab_sign_in_via('saml', user, 'my-uid')
- expect_to_be_on_terms_page
- click_button 'Accept terms'
+ expect_to_be_on_terms_page
+ click_button 'Accept terms'
- expect(page).to have_current_path(profile_path, ignore_query: true)
+ expect(page).to have_current_path(profile_path, ignore_query: true)
- fill_in 'Email', with: 'hello@world.com'
+ fill_in 'Email', with: 'hello@world.com'
- click_button 'Update profile settings'
+ click_button 'Update profile settings'
- expect(page).to have_content('Profile was successfully updated')
- end
+ expect(page).to have_content('Profile was successfully updated')
+ end
end
end
@@ -954,8 +973,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
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" }
before do
- stub_application_setting_enum('email_confirmation_setting', 'hard')
- stub_feature_flags(soft_email_confirmation: true)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
stub_feature_flags(identity_verification: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period
end
diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb
index 88b2d918976..9aef3ed7cd6 100644
--- a/spec/features/users/show_spec.rb
+++ b/spec/features/users/show_spec.rb
@@ -149,7 +149,7 @@ RSpec.describe 'User page', feature_category: :user_profile do
end
end
- context 'follow/unfollow and followers/following' do
+ context 'follow/unfollow and followers/following', :js do
let_it_be(:followee) { create(:user) }
let_it_be(:follower) { create(:user) }
@@ -159,21 +159,33 @@ RSpec.describe 'User page', feature_category: :user_profile do
expect(page).not_to have_button(text: 'Follow', class: 'gl-button')
end
- it 'shows 0 followers and 0 following' do
- subject
+ shared_examples 'follower tabs with count badges' do
+ it 'shows 0 followers and 0 following' do
+ subject
+
+ expect(page).to have_content('Followers 0')
+ expect(page).to have_content('Following 0')
+ end
+
+ it 'shows 1 followers and 1 following' do
+ follower.follow(user)
+ user.follow(followee)
- expect(page).to have_content('0 followers')
- expect(page).to have_content('0 following')
+ subject
+
+ expect(page).to have_content('Followers 1')
+ expect(page).to have_content('Following 1')
+ end
end
- it 'shows 1 followers and 1 following' do
- follower.follow(user)
- user.follow(followee)
+ it_behaves_like 'follower tabs with count badges'
- subject
+ context 'with profile_tabs_vue feature flag disabled' do
+ before_all do
+ stub_feature_flags(profile_tabs_vue: false)
+ end
- expect(page).to have_content('1 follower')
- expect(page).to have_content('1 following')
+ it_behaves_like 'follower tabs with count badges'
end
it 'does show button to follow' do
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index 11ff318c346..a762198d3c3 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -200,9 +200,8 @@ RSpec.describe 'Signup', feature_category: :user_profile do
stub_application_setting_enum('email_confirmation_setting', 'hard')
end
- context 'when soft email confirmation is not enabled' do
+ context 'when email confirmation setting is not `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: false)
stub_feature_flags(identity_verification: false)
end
@@ -221,9 +220,9 @@ RSpec.describe 'Signup', feature_category: :user_profile do
end
end
- context 'when soft email confirmation is enabled' do
+ context 'when email confirmation setting is `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: true)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
end
it 'creates the user account and sends a confirmation email' do
@@ -384,7 +383,7 @@ RSpec.describe 'Signup', feature_category: :user_profile do
expect(page.body).not_to match(/#{new_user.password}/)
end
- context 'with invalid email', :saas, :js do
+ context 'with invalid email', :js do
it_behaves_like 'user email validation' do
let(:path) { new_user_registration_path }
end
diff --git a/spec/features/webauthn_spec.rb b/spec/features/webauthn_spec.rb
index 859793d1353..fbbc746c0b0 100644
--- a/spec/features/webauthn_spec.rb
+++ b/spec/features/webauthn_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_category: :authentication_and_authorization do
+RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_category: :system_access do
include Spec::Support::Helpers::Features::TwoFactorHelpers
let(:app_id) { "http://#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}" }
@@ -10,6 +10,113 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
WebAuthn.configuration.origin = app_id
end
+ context 'when the webauth_without_totp feature flag is enabled' do
+ # Some of the shared tests don't apply. After removing U2F support and the `webauthn_without_totp` feature flag, refactor the shared tests.
+ # TODO: it_behaves_like 'hardware device for 2fa', 'WebAuthn'
+
+ describe 'registration' do
+ let(:user) { create(:user) }
+
+ before do
+ gitlab_sign_in(user)
+ end
+
+ it 'shows an error when using a wrong password' do
+ visit profile_account_path
+
+ # First device
+ enable_two_factor_authentication
+ webauthn_device_registration(password: 'fake')
+ expect(page).to have_content(_('You must provide a valid current password.'))
+ end
+
+ it 'allows registering more than one device' do
+ visit profile_account_path
+
+ # First device
+ enable_two_factor_authentication
+ first_device = webauthn_device_registration(password: user.password)
+ expect(page).to have_content('Your WebAuthn device was registered!')
+ copy_recovery_codes
+ manage_two_factor_authentication
+
+ # Second device
+ second_device = webauthn_device_registration(name: 'My other device', password: user.password)
+ expect(page).to have_content('Your WebAuthn device was registered!')
+
+ expect(page).to have_content(first_device.name)
+ expect(page).to have_content(second_device.name)
+ expect(WebauthnRegistration.count).to eq(2)
+ end
+
+ it 'allows the same device to be registered for multiple users' do
+ # First user
+ visit profile_account_path
+ enable_two_factor_authentication
+ webauthn_device = webauthn_device_registration(password: user.password)
+ expect(page).to have_content('Your WebAuthn device was registered!')
+ gitlab_sign_out
+
+ # Second user
+ user = 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)
+ expect(page).to have_content('Your WebAuthn device was registered!')
+
+ expect(WebauthnRegistration.count).to eq(2)
+ end
+
+ context 'when there are form errors' do
+ let(:mock_register_js) do
+ <<~JS
+ const mockResponse = {
+ type: 'public-key',
+ id: '',
+ rawId: '',
+ response: {
+ clientDataJSON: '',
+ attestationObject: '',
+ },
+ getClientExtensionResults: () => {},
+ };
+ navigator.credentials.create = () => Promise.resolve(mockResponse);
+ JS
+ end
+
+ it "doesn't register the device if there are errors" do
+ visit profile_account_path
+ enable_two_factor_authentication
+
+ # Have the "webauthn device" respond with bad data
+ page.execute_script(mock_register_js)
+ click_on _('Set up new device')
+ webauthn_fill_form_and_submit(password: user.password)
+ expect(page).to have_content(_('Your WebAuthn device did not send a valid JSON response.'))
+
+ expect(WebauthnRegistration.count).to eq(0)
+ end
+
+ it 'allows retrying registration' do
+ visit profile_account_path
+ enable_two_factor_authentication
+
+ # Failed registration
+ page.execute_script(mock_register_js)
+ click_on _('Set up new device')
+ webauthn_fill_form_and_submit(password: user.password)
+ expect(page).to have_content(_('Your WebAuthn device did not send a valid JSON response.'))
+
+ # Successful registration
+ webauthn_device_registration(password: user.password)
+
+ expect(page).to have_content('Your WebAuthn device was registered!')
+ expect(WebauthnRegistration.count).to eq(1)
+ end
+ end
+ end
+ end
+
context 'when the webauth_without_totp feature flag is disabled' do
before do
stub_feature_flags(webauthn_without_totp: false)
@@ -114,99 +221,99 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
end
end
end
+ end
- 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!(:webauthn_device) do
- add_webauthn_device(app_id, user)
- end
+ 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!(:webauthn_device) do
+ add_webauthn_device(app_id, user)
+ end
- describe 'when 2FA via OTP is disabled' do
- let(:otp_required_for_login) { false }
+ describe 'when 2FA via OTP is disabled' do
+ let(:otp_required_for_login) { false }
- it 'allows logging in with the WebAuthn device' do
- gitlab_sign_in(user)
+ it 'allows logging in with the WebAuthn device' do
+ gitlab_sign_in(user)
- webauthn_device.respond_to_webauthn_authentication
+ webauthn_device.respond_to_webauthn_authentication
- expect(page).to have_css('.sign-out-link', visible: false)
- end
+ expect(page).to have_css('.sign-out-link', visible: false)
end
+ end
- describe 'when 2FA via OTP is enabled' do
- it 'allows logging in with the WebAuthn device' do
- gitlab_sign_in(user)
+ describe 'when 2FA via OTP is enabled' do
+ it 'allows logging in with the WebAuthn device' do
+ gitlab_sign_in(user)
- webauthn_device.respond_to_webauthn_authentication
+ webauthn_device.respond_to_webauthn_authentication
- expect(page).to have_css('.sign-out-link', visible: false)
- end
+ expect(page).to have_css('.sign-out-link', visible: false)
end
+ end
- 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) }
+ 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) }
- it 'does not allow logging in with that particular device' do
- # Register other user with a different WebAuthn device
- other_device = add_webauthn_device(app_id, other_user)
+ it 'does not allow logging in with that particular device' do
+ # Register other user with a different WebAuthn device
+ other_device = add_webauthn_device(app_id, other_user)
- # Try authenticating user with the old WebAuthn device
- gitlab_sign_in(user)
- other_device.respond_to_webauthn_authentication
- expect(page).to have_content('Authentication via WebAuthn device failed')
- end
+ # Try authenticating user with the old WebAuthn device
+ gitlab_sign_in(user)
+ other_device.respond_to_webauthn_authentication
+ expect(page).to have_content('Authentication via WebAuthn device failed')
end
+ end
+
+ describe "and also the current user" do
+ # TODO Uncomment once WebAuthn::FakeClient supports passing credential options
+ # (especially allow_credentials, as this is needed to specify which credential the
+ # fake client should use. Currently, the first credential is always used).
+ # There is an issue open for this: https://github.com/cedarcode/webauthn-ruby/issues/259
+ 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)
+ visit profile_account_path
+ manage_two_factor_authentication
+ register_webauthn_device(webauthn_device)
+ gitlab_sign_out
+
+ # Try authenticating user with the same WebAuthn device
+ gitlab_sign_in(current_user)
+ webauthn_device.respond_to_webauthn_authentication
- describe "and also the current user" do
- # TODO Uncomment once WebAuthn::FakeClient supports passing credential options
- # (especially allow_credentials, as this is needed to specify which credential the
- # fake client should use. Currently, the first credential is always used).
- # There is an issue open for this: https://github.com/cedarcode/webauthn-ruby/issues/259
- 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)
- visit profile_account_path
- manage_two_factor_authentication
- register_webauthn_device(webauthn_device)
- gitlab_sign_out
-
- # Try authenticating user with the same WebAuthn device
- gitlab_sign_in(current_user)
- webauthn_device.respond_to_webauthn_authentication
-
- expect(page).to have_css('.sign-out-link', visible: false)
- end
+ expect(page).to have_css('.sign-out-link', visible: false)
end
end
+ end
- describe 'when a given WebAuthn device has not been registered' do
- it 'does not allow logging in with that particular device' do
- unregistered_device = FakeWebauthnDevice.new(page, 'My device')
- gitlab_sign_in(user)
- unregistered_device.respond_to_webauthn_authentication
+ describe 'when a given WebAuthn device has not been registered' do
+ it 'does not allow logging in with that particular device' do
+ unregistered_device = FakeWebauthnDevice.new(page, 'My device')
+ gitlab_sign_in(user)
+ unregistered_device.respond_to_webauthn_authentication
- expect(page).to have_content('Authentication via WebAuthn device failed')
- end
+ expect(page).to have_content('Authentication via WebAuthn device failed')
end
+ end
- describe 'when more than one device has been registered by the same user' do
- it 'allows logging in with either device' do
- first_device = add_webauthn_device(app_id, user)
- second_device = add_webauthn_device(app_id, user)
+ describe 'when more than one device has been registered by the same user' do
+ it 'allows logging in with either device' do
+ first_device = add_webauthn_device(app_id, user)
+ second_device = add_webauthn_device(app_id, user)
- # Authenticate as both devices
- [first_device, second_device].each do |device|
- gitlab_sign_in(user)
- # register_webauthn_device(device)
- device.respond_to_webauthn_authentication
+ # Authenticate as both devices
+ [first_device, second_device].each do |device|
+ gitlab_sign_in(user)
+ # register_webauthn_device(device)
+ device.respond_to_webauthn_authentication
- expect(page).to have_css('.sign-out-link', visible: false)
+ expect(page).to have_css('.sign-out-link', visible: false)
- gitlab_sign_out
- end
+ gitlab_sign_out
end
end
end
diff --git a/spec/features/whats_new_spec.rb b/spec/features/whats_new_spec.rb
index 6b19ab28b44..3668d90f2e9 100644
--- a/spec/features/whats_new_spec.rb
+++ b/spec/features/whats_new_spec.rb
@@ -2,13 +2,11 @@
require "spec_helper"
-RSpec.describe "renders a `whats new` dropdown item", feature_category: :not_owned do
+RSpec.describe "renders a `whats new` dropdown item", feature_category: :onboarding do
let_it_be(:user) { create(:user) }
context 'when not logged in' do
- it 'and on .com it renders' do
- allow(Gitlab).to receive(:com?).and_return(true)
-
+ it 'and on SaaS it renders', :saas do
visit user_path(user)
page.within '.header-help' do
diff --git a/spec/features/work_items/work_item_children_spec.rb b/spec/features/work_items/work_item_children_spec.rb
deleted file mode 100644
index f41fb86d13c..00000000000
--- a/spec/features/work_items/work_item_children_spec.rb
+++ /dev/null
@@ -1,136 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Work item children', :js, feature_category: :team_planning do
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, :public, namespace: group) }
- let_it_be(:user) { create(:user) }
- let_it_be(:issue) { create(:issue, project: project) }
-
- context 'for signed in user' do
- before do
- project.add_developer(user)
-
- sign_in(user)
-
- stub_feature_flags(work_items: true)
-
- visit project_issue_path(project, issue)
-
- wait_for_requests
- end
-
- it 'are not displayed when issue does not have work item children', :aggregate_failures do
- page.within('[data-testid="work-item-links"]') do
- expect(find('[data-testid="links-empty"]')).to have_content(_('No tasks are currently assigned.'))
- expect(page).not_to have_selector('[data-testid="add-links-form"]')
- expect(page).not_to have_selector('[data-testid="links-child"]')
- end
- end
-
- it 'toggles widget body', :aggregate_failures do
- page.within('[data-testid="work-item-links"]') do
- expect(page).to have_selector('[data-testid="widget-body"]')
-
- click_button 'Collapse'
-
- expect(page).not_to have_selector('[data-testid="widget-body"]')
-
- click_button 'Expand'
-
- expect(page).to have_selector('[data-testid="widget-body"]')
- end
- end
-
- it 'toggles form', :aggregate_failures do
- page.within('[data-testid="work-item-links"]') do
- expect(page).not_to have_selector('[data-testid="add-links-form"]')
-
- click_button 'Add'
- click_button 'New task'
-
- expect(page).to have_selector('[data-testid="add-links-form"]')
-
- click_button 'Cancel'
-
- expect(page).not_to have_selector('[data-testid="add-links-form"]')
- end
- end
-
- it 'adds a new child task', :aggregate_failures do
- page.within('[data-testid="work-item-links"]') do
- click_button 'Add'
- click_button 'New task'
-
- expect(page).to have_button('Create task', disabled: true)
- fill_in 'Add a title', with: 'Task 1'
-
- expect(page).to have_button('Create task', disabled: false)
-
- click_button 'Create task'
-
- wait_for_all_requests
-
- expect(find('[data-testid="links-child"]')).to have_content('Task 1')
- end
- end
-
- it 'removes a child task and undoing', :aggregate_failures do
- page.within('[data-testid="work-item-links"]') do
- click_button 'Add'
- click_button 'New task'
- fill_in 'Add a title', with: 'Task 1'
- click_button 'Create task'
- wait_for_all_requests
-
- expect(find('[data-testid="links-child"]')).to have_content('Task 1')
- expect(find('[data-testid="children-count"]')).to have_content('1')
-
- find('[data-testid="links-menu"]').click
- click_button 'Remove'
-
- wait_for_all_requests
-
- expect(page).not_to have_content('Task 1')
- expect(find('[data-testid="children-count"]')).to have_content('0')
- end
-
- page.within('.gl-toast') do
- expect(find('.toast-body')).to have_content(_('Child removed'))
- find('.b-toaster a', text: 'Undo').click
- end
-
- wait_for_all_requests
-
- page.within('[data-testid="work-item-links"]') do
- expect(find('[data-testid="links-child"]')).to have_content('Task 1')
- expect(find('[data-testid="children-count"]')).to have_content('1')
- end
- end
-
- context 'with existing task' do
- let_it_be(:task) { create(:work_item, :task, project: project) }
-
- it 'adds an existing child task', :aggregate_failures do
- page.within('[data-testid="work-item-links"]') do
- click_button 'Add'
- click_button 'Existing task'
-
- expect(page).to have_button('Add task', disabled: true)
- find('[data-testid="work-item-token-select-input"]').set(task.title)
- wait_for_all_requests
- click_button task.title
-
- expect(page).to have_button('Add task', disabled: false)
-
- click_button 'Add task'
-
- wait_for_all_requests
-
- expect(find('[data-testid="links-child"]')).to have_content(task.title)
- end
- end
- end
- end
-end
diff --git a/spec/features/work_items/work_item_spec.rb b/spec/features/work_items/work_item_spec.rb
deleted file mode 100644
index 3c71a27ff82..00000000000
--- a/spec/features/work_items/work_item_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Work item', :js, feature_category: :team_planning do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:user) { create(:user) }
- let_it_be(:work_item) { create(:work_item, project: project) }
-
- context 'for signed in user' do
- before do
- project.add_developer(user)
-
- sign_in(user)
-
- visit project_work_items_path(project, work_items_path: work_item.id)
- end
-
- it_behaves_like 'work items status'
- it_behaves_like 'work items assignees'
- it_behaves_like 'work items labels'
- it_behaves_like 'work items comments'
- it_behaves_like 'work items description'
- end
-
- context 'for signed in owner' do
- before do
- project.add_owner(user)
-
- sign_in(user)
-
- visit project_work_items_path(project, work_items_path: work_item.id)
- end
-
- it_behaves_like 'work items invite members'
- end
-end
diff --git a/spec/finders/abuse_reports_finder_spec.rb b/spec/finders/abuse_reports_finder_spec.rb
index 52620b3e421..d3b148375d4 100644
--- a/spec/finders/abuse_reports_finder_spec.rb
+++ b/spec/finders/abuse_reports_finder_spec.rb
@@ -3,25 +3,124 @@
require 'spec_helper'
RSpec.describe AbuseReportsFinder, '#execute' do
+ let_it_be(:user1) { create(:user) }
+ let_it_be(:user2) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:abuse_report_1) { create(:abuse_report, id: 20, category: 'spam', user: user1) }
+ let_it_be(:abuse_report_2) do
+ create(:abuse_report, :closed, id: 30, category: 'phishing', user: user2, reporter: reporter)
+ end
+
let(:params) { {} }
- let!(:user1) { create(:user) }
- let!(:user2) { create(:user) }
- let!(:abuse_report_1) { create(:abuse_report, user: user1) }
- let!(:abuse_report_2) { create(:abuse_report, user: user2) }
subject { described_class.new(params).execute }
- context 'empty params' do
+ 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 'params[:user_id] is present' do
+ context 'when params[:user_id] is present' do
let(:params) { { user_id: user2 } }
it 'returns abuse reports for the specified user' do
expect(subject).to match_array([abuse_report_2])
end
end
+
+ shared_examples 'returns filtered reports' do |filter_field|
+ it "returns abuse reports filtered by #{filter_field}_id" do
+ expect(subject).to match_array(filtered_reports)
+ end
+
+ context "when no user has username = params[:#{filter_field}]" do
+ before do
+ allow(User).to receive_message_chain(:by_username, :pick)
+ .with(params[filter_field])
+ .with(:id)
+ .and_return(nil)
+ end
+
+ it 'returns all abuse reports' do
+ expect(subject).to match_array([abuse_report_1, abuse_report_2])
+ end
+ end
+ end
+
+ context 'when params[:user] is present' do
+ it_behaves_like 'returns filtered reports', :user do
+ let(:params) { { user: user1.username } }
+ let(:filtered_reports) { [abuse_report_1] }
+ end
+ end
+
+ context 'when params[:reporter] is present' do
+ it_behaves_like 'returns filtered reports', :reporter do
+ let(:params) { { reporter: reporter.username } }
+ let(:filtered_reports) { [abuse_report_2] }
+ end
+ end
+
+ context 'when params[:status] is present' do
+ context 'when value is "open"' do
+ let(:params) { { status: 'open' } }
+
+ it 'returns only open abuse reports' do
+ expect(subject).to match_array([abuse_report_1])
+ end
+ end
+
+ context 'when value is "closed"' do
+ let(:params) { { status: 'closed' } }
+
+ it 'returns only closed abuse reports' do
+ expect(subject).to match_array([abuse_report_2])
+ end
+ end
+ end
+
+ context 'when params[:category] is present' do
+ let(:params) { { category: 'phishing' } }
+
+ it 'returns abuse reports with the specified category' do
+ expect(subject).to match_array([abuse_report_2])
+ end
+ end
+
+ describe 'sorting' do
+ let(:params) { { sort: 'created_at_asc' } }
+
+ it 'returns reports sorted by the specified sort attribute' do
+ expect(subject).to eq [abuse_report_1, abuse_report_2]
+ end
+
+ context 'when sort is not specified' do
+ let(:params) { {} }
+
+ it "returns reports sorted by #{described_class::DEFAULT_SORT}" do
+ expect(subject).to eq [abuse_report_2, abuse_report_1]
+ end
+ end
+
+ context 'when sort is not supported' do
+ let(:params) { { sort: 'superiority' } }
+
+ it "returns reports sorted by #{described_class::DEFAULT_SORT}" do
+ expect(subject).to eq [abuse_report_2, abuse_report_1]
+ end
+ end
+
+ context 'when abuse_reports_list feature flag is disabled' do
+ let_it_be(:abuse_report_3) { create(:abuse_report, id: 10) }
+
+ before do
+ stub_feature_flags(abuse_reports_list: false)
+ end
+
+ it 'returns reports sorted by id in descending order' do
+ expect(subject).to eq [abuse_report_2, abuse_report_1, abuse_report_3]
+ end
+ end
+ end
end
diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb
index 4a5eb389906..5d748f71816 100644
--- a/spec/finders/group_members_finder_spec.rb
+++ b/spec/finders/group_members_finder_spec.rb
@@ -225,4 +225,56 @@ RSpec.describe GroupMembersFinder, '#execute', feature_category: :subgroups do
end
end
end
+
+ context 'filter by user type' do
+ subject(:by_user_type) { described_class.new(group, user1, params: { user_type: user_type }).execute }
+
+ let_it_be(:service_account) { create(:user, :service_account) }
+ let_it_be(:project_bot) { create(:user, :project_bot) }
+
+ let_it_be(:service_account_member) { group.add_developer(service_account) }
+ let_it_be(:project_bot_member) { group.add_developer(project_bot) }
+
+ context 'when the user is an owner' do
+ before do
+ group.add_owner(user1)
+ end
+
+ context 'when filtering by project bots' do
+ let(:user_type) { 'project_bot' }
+
+ it 'returns filtered members' do
+ expect(by_user_type).to match_array([project_bot_member])
+ end
+ end
+
+ context 'when filtering by service accounts' do
+ let(:user_type) { 'service_account' }
+
+ it 'returns filtered members' do
+ expect(by_user_type).to match_array([service_account_member])
+ end
+ end
+ end
+
+ context 'when the user is a maintainer' do
+ let(:user_type) { 'service_account' }
+
+ let_it_be(:user1_member) { group.add_maintainer(user1) }
+
+ it 'returns unfiltered members' do
+ expect(by_user_type).to match_array([user1_member, service_account_member, project_bot_member])
+ end
+ end
+
+ context 'when the user is a developer' do
+ let(:user_type) { 'service_account' }
+
+ let_it_be(:user1_member) { group.add_developer(user1) }
+
+ it 'returns unfiltered members' do
+ expect(by_user_type).to match_array([user1_member, service_account_member, project_bot_member])
+ end
+ end
+ end
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index e8099924638..306acb9391d 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -493,6 +493,24 @@ RSpec.describe MergeRequestsFinder, feature_category: :code_review_workflow do
end
end
+ context 'filtering by approved' do
+ before do
+ create(:approval, merge_request: merge_request3, user: user2)
+ end
+
+ it 'for approved' do
+ merge_requests = described_class.new(user, { approved: true }).execute
+
+ expect(merge_requests).to contain_exactly(merge_request3)
+ end
+
+ it 'for not approved' do
+ merge_requests = described_class.new(user, { approved: false }).execute
+
+ expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request4, merge_request5)
+ end
+ end
+
context 'filtering by approved by username' do
let(:params) { { approved_by_usernames: user2.username } }
diff --git a/spec/finders/milestones_finder_spec.rb b/spec/finders/milestones_finder_spec.rb
index 8dd83df3a28..c4c62e21ad9 100644
--- a/spec/finders/milestones_finder_spec.rb
+++ b/spec/finders/milestones_finder_spec.rb
@@ -62,9 +62,31 @@ RSpec.describe MilestonesFinder do
end
context 'with filters' do
- let_it_be(:milestone_1) { create(:milestone, group: group, state: 'closed', title: 'one test', start_date: now - 1.day, due_date: now) }
- let_it_be(:milestone_3) { create(:milestone, project: project_1, state: 'closed', start_date: now + 2.days, due_date: now + 3.days) }
+ let_it_be(:milestone_1) do
+ create(
+ :milestone,
+ group: group,
+ state: 'closed',
+ title: 'one test',
+ start_date: now - 1.day,
+ due_date: now,
+ updated_at: now - 3.days
+ )
+ end
+
+ let_it_be(:milestone_3) do
+ create(
+ :milestone,
+ project: project_1,
+ state: 'closed',
+ description: 'three test',
+ start_date: now + 2.days,
+ due_date: now + 3.days,
+ updated_at: now - 5.days
+ )
+ end
+ let(:result) { described_class.new(params).execute }
let(:params) do
{
project_ids: [project_1.id, project_2.id],
@@ -76,62 +98,96 @@ RSpec.describe MilestonesFinder do
it 'filters by id' do
params[:ids] = [milestone_1.id, milestone_2.id]
- result = described_class.new(params).execute
-
expect(result).to contain_exactly(milestone_1, milestone_2)
end
it 'filters by active state' do
params[:state] = 'active'
- result = described_class.new(params).execute
expect(result).to contain_exactly(milestone_2, milestone_4)
end
it 'filters by closed state' do
params[:state] = 'closed'
- result = described_class.new(params).execute
expect(result).to contain_exactly(milestone_1, milestone_3)
end
it 'filters by title' do
- result = described_class.new(params.merge(title: 'one test')).execute
+ params[:title] = 'one test'
- expect(result.to_a).to contain_exactly(milestone_1)
+ expect(result).to contain_exactly(milestone_1)
end
it 'filters by search_title' do
- result = described_class.new(params.merge(search_title: 'one t')).execute
+ params[:search_title] = 'test'
+
+ expect(result).to contain_exactly(milestone_1)
+ end
+
+ it 'filters by search (title, description)' do
+ params[:search] = 'test'
- expect(result.to_a).to contain_exactly(milestone_1)
+ expect(result).to contain_exactly(milestone_1, milestone_3)
end
context 'by timeframe' do
it 'returns milestones with start_date and due_date between timeframe' do
params.merge!(start_date: now - 1.day, end_date: now + 3.days)
- milestones = described_class.new(params).execute
-
- expect(milestones).to match_array([milestone_1, milestone_2, milestone_3])
+ expect(result).to contain_exactly(milestone_1, milestone_2, milestone_3)
end
it 'returns milestones which starts before the timeframe' do
milestone = create(:milestone, project: project_2, start_date: now - 5.days)
params.merge!(start_date: now - 3.days, end_date: now - 2.days)
- milestones = described_class.new(params).execute
-
- expect(milestones).to match_array([milestone])
+ expect(result).to contain_exactly(milestone)
end
it 'returns milestones which ends after the timeframe' do
milestone = create(:milestone, project: project_2, due_date: now + 6.days)
params.merge!(start_date: now + 6.days, end_date: now + 7.days)
- milestones = described_class.new(params).execute
+ expect(result).to contain_exactly(milestone)
+ end
+ end
+
+ context 'by updated_at' do
+ it 'returns milestones updated before a given date' do
+ params[:updated_before] = 4.days.ago.iso8601
+
+ expect(result).to contain_exactly(milestone_3)
+ end
+
+ it 'returns milestones updated after a given date' do
+ params[:updated_after] = 4.days.ago.iso8601
+
+ expect(result).to contain_exactly(milestone_1, milestone_2, milestone_4)
+ end
+
+ it 'returns milestones updated between the given dates' do
+ params.merge!(updated_after: 6.days.ago.iso8601, updated_before: 4.days.ago.iso8601)
+
+ expect(result).to contain_exactly(milestone_3)
+ end
+ end
+
+ context 'by iids' do
+ before do
+ params[:iids] = 1
+ end
- expect(milestones).to match_array([milestone])
+ it 'returns milestone for the given iids' do
+ expect(result).to contain_exactly(milestone_2, milestone_3, milestone_4)
+ end
+
+ context 'when include_parent_milestones is true' do
+ it 'ignores the iid filter' do
+ params[:include_parent_milestones] = true
+
+ expect(result).to contain_exactly(milestone_1, milestone_2, milestone_3, milestone_4)
+ end
end
end
end
diff --git a/spec/finders/serverless_domain_finder_spec.rb b/spec/finders/serverless_domain_finder_spec.rb
deleted file mode 100644
index 4e6b9f07544..00000000000
--- a/spec/finders/serverless_domain_finder_spec.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ServerlessDomainFinder do
- let(:function_name) { 'test-function' }
- let(:pages_domain_name) { 'serverless.gitlab.io' }
- let(:valid_cluster_uuid) { 'aba1cdef123456f278' }
- let(:invalid_cluster_uuid) { 'aba1cdef123456f178' }
- let!(:environment) { create(:environment, name: 'test') }
-
- let(:pages_domain) do
- create(
- :pages_domain,
- :instance_serverless,
- domain: pages_domain_name
- )
- end
-
- let(:knative_with_ingress) do
- create(
- :clusters_applications_knative,
- external_ip: '10.0.0.1'
- )
- end
-
- let!(:serverless_domain_cluster) do
- create(
- :serverless_domain_cluster,
- uuid: 'abcdef12345678',
- pages_domain: pages_domain,
- knative: knative_with_ingress
- )
- end
-
- let(:valid_uri) { "https://#{function_name}-#{valid_cluster_uuid}#{"%x" % environment.id}-#{environment.slug}.#{pages_domain_name}" }
- let(:valid_fqdn) { "#{function_name}-#{valid_cluster_uuid}#{"%x" % environment.id}-#{environment.slug}.#{pages_domain_name}" }
- let(:invalid_uri) { "https://#{function_name}-#{invalid_cluster_uuid}#{"%x" % environment.id}-#{environment.slug}.#{pages_domain_name}" }
-
- let(:valid_finder) { described_class.new(valid_uri) }
- let(:invalid_finder) { described_class.new(invalid_uri) }
-
- describe '#serverless?' do
- context 'with a valid URI' do
- subject { valid_finder.serverless? }
-
- it { is_expected.to be_truthy }
- end
-
- context 'with an invalid URI' do
- subject { invalid_finder.serverless? }
-
- it { is_expected.to be_falsy }
- end
- end
-
- describe '#serverless_domain_cluster_uuid' do
- context 'with a valid URI' do
- subject { valid_finder.serverless_domain_cluster_uuid }
-
- it { is_expected.to eq serverless_domain_cluster.uuid }
- end
-
- context 'with an invalid URI' do
- subject { invalid_finder.serverless_domain_cluster_uuid }
-
- it { is_expected.to be_nil }
- end
- end
-
- describe '#execute' do
- context 'with a valid URI' do
- let(:serverless_domain) do
- create(
- :serverless_domain,
- function_name: function_name,
- serverless_domain_cluster: serverless_domain_cluster,
- environment: environment
- )
- end
-
- subject { valid_finder.execute }
-
- it 'has the correct function_name' do
- expect(subject.function_name).to eq function_name
- end
-
- it 'has the correct serverless_domain_cluster' do
- expect(subject.serverless_domain_cluster).to eq serverless_domain_cluster
- end
-
- it 'has the correct environment' do
- expect(subject.environment).to eq environment
- end
- end
-
- context 'with an invalid URI' do
- subject { invalid_finder.execute }
-
- it { is_expected.to be_nil }
- end
- end
-end
diff --git a/spec/fixtures/api/schemas/cluster_status.json b/spec/fixtures/api/schemas/cluster_status.json
index efc609b3c3f..0ef4d6f82a9 100644
--- a/spec/fixtures/api/schemas/cluster_status.json
+++ b/spec/fixtures/api/schemas/cluster_status.json
@@ -1,8 +1,7 @@
{
"type": "object",
"required": [
- "status",
- "applications"
+ "status"
],
"properties": {
"status": {
@@ -10,12 +9,6 @@
},
"status_reason": {
"$ref": "types/nullable_string.json"
- },
- "applications": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/application_status"
- }
}
},
"additionalProperties": false,
@@ -115,4 +108,4 @@
}
}
}
-} \ No newline at end of file
+}
diff --git a/spec/fixtures/api/schemas/entities/discussion.json b/spec/fixtures/api/schemas/entities/discussion.json
index 45271926547..4af36b5814b 100644
--- a/spec/fixtures/api/schemas/entities/discussion.json
+++ b/spec/fixtures/api/schemas/entities/discussion.json
@@ -103,6 +103,9 @@
"noteable_type": {
"type": "string"
},
+ "project_id": {
+ "type": "integer"
+ },
"resolved": {
"type": "boolean"
},
@@ -207,4 +210,4 @@
}
}
}
-} \ No newline at end of file
+}
diff --git a/spec/fixtures/api/schemas/internal/pages/lookup_path.json b/spec/fixtures/api/schemas/internal/pages/lookup_path.json
index 9d81ea495f1..8ca71870911 100644
--- a/spec/fixtures/api/schemas/internal/pages/lookup_path.json
+++ b/spec/fixtures/api/schemas/internal/pages/lookup_path.json
@@ -23,7 +23,8 @@
},
"additionalProperties": false
},
- "prefix": { "type": "string" }
+ "prefix": { "type": "string" },
+ "unique_domain": { "type": ["string", "null"] }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/public_api/v4/notes.json b/spec/fixtures/api/schemas/public_api/v4/notes.json
index 1987a0f2f71..60d6bb90b79 100644
--- a/spec/fixtures/api/schemas/public_api/v4/notes.json
+++ b/spec/fixtures/api/schemas/public_api/v4/notes.json
@@ -78,6 +78,9 @@
"noteable_type": {
"type": "string"
},
+ "project_id": {
+ "type": "integer"
+ },
"resolved": {
"type": "boolean"
},
@@ -122,4 +125,4 @@
],
"additionalProperties": false
}
-} \ No newline at end of file
+}
diff --git a/spec/fixtures/auth_key.p8 b/spec/fixtures/auth_key.p8
new file mode 100644
index 00000000000..1b53126536e
--- /dev/null
+++ b/spec/fixtures/auth_key.p8
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKS+CfS9GcRSdYSN
+SzyH5QJQBr5umRL6E+KilOV39iYFO/9oHjUdapTRWkrwnNPCp7qaeck4Jr8iv14t
+PVNDfNr76eGb6/3YknOAP0QOjLWunoC8kjU+N/JHU52NrUeX3qEy8EKV9LeCDJcB
+kBk+Yejn9nypg8c7sLsn33CB6i3bAgMBAAECgYA2D26w80T7WZvazYr86BNMePpd
+j2mIAqx32KZHzt/lhh40J/SRtX9+Kl0Y7nBoRR5Ja9u/HkAIxNxLiUjwg9r6cpg/
+uITEF5nMt7lAk391BuI+7VOZZGbJDsq2ulPd6lO+C8Kq/PI/e4kXcIjeH6KwQsuR
+5vrXfBZ3sQfflaiN4QJBANBt8JY2LIGQF8o89qwUpRL5vbnKQ4IzZ5+TOl4RLR7O
+AQpJ81tGuINghO7aunctb6rrcKJrxmEH1whzComybrMCQQDKV49nOBudRBAIgG4K
+EnLzsRKISUHMZSJiYTYnablof8cKw1JaQduw7zgrUlLwnroSaAGX88+Jw1f5n2Lh
+Vlg5AkBDdUGnrDLtYBCDEQYZHblrkc7ZAeCllDOWjxUV+uMqlCv8A4Ey6omvY57C
+m6I8DkWVAQx8VPtozhvHjUw80rZHAkB55HWHAM3h13axKG0htCt7klhPsZHpx6MH
+EPjGlXIT+aW2XiPmK3ZlCDcWIenE+lmtbOpI159Wpk8BGXs/s/xBAkEAlAY3ymgx
+63BDJEwvOb2IaP8lDDxNsXx9XJNVvQbv5n15vNsLHbjslHfAhAbxnLQ1fLhUPqSi
+nNp/xedE1YxutQ==
+-----END PRIVATE KEY-----
diff --git a/spec/fixtures/diagram.drawio.svg b/spec/fixtures/diagram.drawio.svg
new file mode 100644
index 00000000000..3eb6eb29921
--- /dev/null
+++ b/spec/fixtures/diagram.drawio.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
+ width="177px" height="97px" viewBox="-0.5 -0.5 177 97"
+ content="&lt;mxfile host=&quot;embed.diagrams.net&quot; modified=&quot;2022-11-18T14:21:55.551Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36&quot; version=&quot;20.5.3&quot; etag=&quot;cTK3wL1ch5_8VL-J45NP&quot; type=&quot;embed&quot;&gt;&lt;diagram id=&quot;mWELjHy14aEMRdjyCi3_&quot; name=&quot;Page-1&quot;&gt;jZLBcoQgDIafhrvItPVcu+1eevLQMyOpMAPGYbFqn75Ygq7d2ZmeSL4kkPyEidrNb14O+h0VWFYWambihZUlr554PFayJFI9FAl03ihK2kFjvoFgThuNgsshMSDaYIYjbLHvoQ0HJr3H6Zj2ifb46iA7uAFNK+0t/TAq6D9TrPwMptP5ZV5QxMmcTOCipcLpCokTE7VHDMlycw12FS/rkupe70S3xjz04T8FZSr4knak2ZSRnZeO2gtLntnj2CtYywomnidtAjSDbNfoFH85Mh2cjR6PJt0KPsB8tzO+zRsXBdBB8EtMoQKRNaMdiSD50644fySmr9SuiEn65G67etchGiRFdnfJf2NXiytOPw==&lt;/diagram&gt;&lt;/mxfile&gt;"
+ style="background-color: rgb(255, 255, 255);">
+ <defs />
+ <g>
+ <rect x="8" y="8" width="160" height="80" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)"
+ pointer-events="all" />
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml"
+ style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 48px; margin-left: 9px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); "
+ style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div
+ style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
+ diagram</div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="88" y="52" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px"
+ text-anchor="middle">diagram</text>
+ </switch>
+ </g>
+ </g>
+ <switch>
+ <g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" />
+ <a transform="translate(0,-5)"
+ xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
+ <text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text>
+ </a>
+ </switch>
+</svg>
diff --git a/spec/fixtures/lib/gitlab/email/basic.html b/spec/fixtures/lib/gitlab/email/basic.html
index 807b23c46e3..8c2c4c116b8 100644
--- a/spec/fixtures/lib/gitlab/email/basic.html
+++ b/spec/fixtures/lib/gitlab/email/basic.html
@@ -7,17 +7,17 @@
Even though it has whitespace and newlines, the e-mail converter
will handle it correctly.
- <p><em>Even</em> mismatched tags.</p>
+ <p><em class="class" style="color:red" title="strong">Even</em> mismatched tags.</p>
<div>A div</div>
<div>Another div</div>
- <div>A div<div><strong>within</strong> a div</div></div>
+ <div>A div<div><strong class="class" style="color:red" title="strong">within</strong> a div</div></div>
<p>Another line<br />Yet another line</p>
<a href="http://foo.com">A link</a>
- <p><details><summary>One</summary>Some details</details></p>
+ <p><details class="class" style="color:red" title="strong"><summary>One</summary>Some details</details></p>
<p><details><summary>Two</summary>Some details</details></p>
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/project.json b/spec/fixtures/lib/gitlab/import_export/complex/project.json
index 0bca7b0f494..a0ac70d7d9c 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/project.json
+++ b/spec/fixtures/lib/gitlab/import_export/complex/project.json
@@ -7327,7 +7327,7 @@
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
- "statuses": [
+ "builds": [
{
"id": 71,
"project_id": 5,
@@ -7364,7 +7364,41 @@
"artifacts_file_store": 1,
"artifacts_metadata_store": 1,
"artifacts_size": 10
- },
+ }
+ ],
+ "bridges": [
+ {
+ "id": 72,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.",
+ "created_at": "2016-03-22T15:20:35.777Z",
+ "updated_at": "2016-03-22T15:20:35.777Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 36,
+ "commands": "$ deploy command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "deploy",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "stage_id": 12,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ],
+ "generic_commit_statuses": [
{
"id": 72,
"project_id": 5,
@@ -7435,7 +7469,7 @@
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
- "statuses": [
+ "builds": [
{
"id": 74,
"project_id": 5,
@@ -7549,7 +7583,7 @@
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
- "statuses": [
+ "builds": [
{
"id": 76,
"project_id": 5,
@@ -7637,7 +7671,7 @@
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
- "statuses": [
+ "builds": [
{
"id": 78,
"project_id": 5,
@@ -7843,6 +7877,95 @@
}
}
],
+ "commit_notes": [
+ {
+ "note": "Commit note 1",
+ "noteable_type": "Commit",
+ "author_id": 1,
+ "created_at": "2023-01-30T19:27:36.585Z",
+ "updated_at": "2023-02-10T14:43:01.308Z",
+ "project_id": 5,
+ "attachment": {
+ "url": null
+ },
+ "line_code": null,
+ "commit_id": "sha-notes",
+ "system": false,
+ "st_diff": null,
+ "updated_by_id": 1,
+ "type": null,
+ "position": null,
+ "original_position": null,
+ "resolved_at": null,
+ "resolved_by_id": null,
+ "discussion_id": "e3fde7d585c6467a7a5147e83617eb6daa61aaf4",
+ "change_position": null,
+ "resolved_by_push": null,
+ "confidential": null,
+ "last_edited_at": "2023-02-10T14:43:01.306Z",
+ "author": {
+ "name": "Administrator"
+ },
+ "events": [
+ {
+ "project_id": 1,
+ "author_id": 1,
+ "created_at": "2023-01-30T19:27:36.815Z",
+ "updated_at": "2023-01-30T19:27:36.815Z",
+ "action": "commented",
+ "target_type": "Note",
+ "fingerprint": null,
+ "push_event_payload": {
+ "commit_count": 1,
+ "action": "pushed",
+ "ref_type": "branch",
+ "commit_to": "sha-notes",
+ "ref": "master"
+ }
+ }
+ ]
+ },
+ {
+ "note": "Commit note 2",
+ "noteable_type": "Commit",
+ "author_id": 1,
+ "created_at": "2023-02-10T14:44:08.138Z",
+ "updated_at": "2023-02-10T14:54:42.828Z",
+ "project_id": 1,
+ "attachment": {
+ "url": null
+ },
+ "line_code": null,
+ "commit_id": "sha-notes",
+ "system": false,
+ "st_diff": null,
+ "updated_by_id": 1,
+ "type": null,
+ "position": null,
+ "original_position": null,
+ "resolved_at": null,
+ "resolved_by_id": null,
+ "discussion_id": "53ca55a01732aff4f17daecdf076853f4ab152eb",
+ "change_position": null,
+ "resolved_by_push": null,
+ "confidential": null,
+ "last_edited_at": "2023-02-10T14:54:42.827Z",
+ "author": {
+ "name": "Administrator"
+ },
+ "events": [
+ {
+ "project_id": 1,
+ "author_id": 1,
+ "created_at": "2023-02-10T16:37:16.659Z",
+ "updated_at": "2023-02-10T16:37:16.659Z",
+ "action": "commented",
+ "target_type": "Note",
+ "fingerprint": null
+ }
+ ]
+ }
+ ],
"pipeline_schedules": [
{
"id": 1,
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson
index cadaa5abfcd..348a01372ab 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson
+++ b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson
@@ -1,7 +1,7 @@
{"id":19,"project_id":5,"ref":"master","sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":24,"project_id":5,"pipeline_id":40,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","statuses":[{"id":79,"project_id":5,"status":"failed","finished_at":"2016-03-29T06:28:12.695Z","trace":"Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.","created_at":"2016-03-22T15:20:35.950Z","updated_at":"2016-03-29T06:28:12.696Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":40,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":80,"project_id":5,"status":"success","finished_at":null,"trace":"Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.","created_at":"2016-03-22T15:20:35.966Z","updated_at":"2016-03-22T15:20:35.966Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":40,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
{"id":20,"project_id":5,"ref":"master","sha":"ce84140e8b878ce6e7c4d298c7202ff38170e3ac","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":false,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[],"source":"external_pull_request_event","external_pull_request":{"id":3,"pull_request_iid":4,"source_branch":"feature","target_branch":"master","source_repository":"the-repository","target_repository":"the-repository","source_sha":"ce84140e8b878ce6e7c4d298c7202ff38170e3ac","target_sha":"a09386439ca39abe575675ffd4b89ae824fec22f","status":"open","created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z"}}
-{"id":26,"project_id":5,"ref":"master","sha":"048721d90c449b244b7b4c53a9186b04330174ec","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.757Z","updated_at":"2016-03-22T15:20:35.757Z","tag":false,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"source":"merge_request_event","merge_request_id":27,"stages":[{"id":21,"project_id":5,"pipeline_id":37,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","statuses":[{"id":74,"project_id":5,"status":"success","finished_at":null,"trace":"Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.","created_at":"2016-03-22T15:20:35.846Z","updated_at":"2016-03-22T15:20:35.846Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":37,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":73,"project_id":5,"status":"canceled","finished_at":null,"trace":null,"created_at":"2016-03-22T15:20:35.842Z","updated_at":"2016-03-22T15:20:35.842Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":37,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}],"merge_request":{"id":27,"target_branch":"feature","source_branch":"feature_conflict","source_project_id":2147483547,"author_id":1,"assignee_id":null,"title":"MR1","created_at":"2016-06-14T15:02:36.568Z","updated_at":"2016-06-14T15:02:56.815Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":9,"description":null,"position":0,"updated_by_id":null,"merge_error":null,"diff_head_sha":"HEAD","source_branch_sha":"ABCD","target_branch_sha":"DCBA","merge_params":{"force_remove_source_branch":null}}}
-{"id":36,"project_id":5,"ref":null,"sha":"sha-notes","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.755Z","updated_at":"2016-03-22T15:20:35.755Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"user_id":2147483547,"duration":null,"source":"push","merge_request_id":null,"pipeline_metadata": {"id": 2, "project_id": 5, "pipeline_id": 36, "name": "Build pipeline"},"notes":[{"id":2147483547,"note":"Natus rerum qui dolorem dolorum voluptas.","noteable_type":"Commit","author_id":1,"created_at":"2016-03-22T15:19:59.469Z","updated_at":"2016-03-22T15:19:59.469Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":"be93687618e4b132087f430a4d8fc3a609c9b77c","noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"}}],"stages":[{"id":11,"project_id":5,"pipeline_id":36,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","statuses":[{"id":71,"project_id":5,"status":"failed","finished_at":"2016-03-29T06:28:12.630Z","trace":null,"created_at":"2016-03-22T15:20:35.772Z","updated_at":"2016-03-29T06:28:12.634Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":{"image":"busybox:latest"},"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"stage_id":11,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null,"type":"Ci::Build","token":"abcd","artifacts_file_store":1,"artifacts_metadata_store":1,"artifacts_size":10},{"id":72,"project_id":5,"status":"success","finished_at":null,"trace":"Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]},{"id":12,"project_id":5,"pipeline_id":36,"name":"deploy","status":2,"created_at":"2016-03-22T15:45:45.772Z","updated_at":"2016-03-29T06:45:45.634Z"}]}
-{"id":38,"iid":1,"project_id":5,"ref":"master","sha":"5f923865dde3436854e9ceb9cdb7815618d4e849","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.759Z","updated_at":"2016-03-22T15:20:35.759Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":22,"project_id":5,"pipeline_id":38,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","statuses":[{"id":76,"project_id":5,"status":"success","finished_at":null,"trace":"Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.","created_at":"2016-03-22T15:20:35.882Z","updated_at":"2016-03-22T15:20:35.882Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":38,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":75,"project_id":5,"status":"failed","finished_at":null,"trace":"Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.","created_at":"2016-03-22T15:20:35.864Z","updated_at":"2016-03-22T15:20:35.864Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":38,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
-{"id":39,"project_id":5,"ref":"master","sha":"d2d430676773caa88cdaf7c55944073b2fd5561a","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.761Z","updated_at":"2016-03-22T15:20:35.761Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":23,"project_id":5,"pipeline_id":39,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","statuses":[{"id":78,"project_id":5,"status":"success","finished_at":null,"trace":"Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.","created_at":"2016-03-22T15:20:35.927Z","updated_at":"2016-03-22T15:20:35.927Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":39,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":77,"project_id":5,"status":"failed","finished_at":null,"trace":"Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.","created_at":"2016-03-22T15:20:35.905Z","updated_at":"2016-03-22T15:20:35.905Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":39,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
+{"id":26,"project_id":5,"ref":"master","sha":"048721d90c449b244b7b4c53a9186b04330174ec","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.757Z","updated_at":"2016-03-22T15:20:35.757Z","tag":false,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"source":"merge_request_event","merge_request_id":27,"stages":[{"id":21,"project_id":5,"pipeline_id":37,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":74,"project_id":5,"status":"success","finished_at":null,"trace":"Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.","created_at":"2016-03-22T15:20:35.846Z","updated_at":"2016-03-22T15:20:35.846Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":37,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":73,"project_id":5,"status":"canceled","finished_at":null,"trace":null,"created_at":"2016-03-22T15:20:35.842Z","updated_at":"2016-03-22T15:20:35.842Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":37,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}],"merge_request":{"id":27,"target_branch":"feature","source_branch":"feature_conflict","source_project_id":2147483547,"author_id":1,"assignee_id":null,"title":"MR1","created_at":"2016-06-14T15:02:36.568Z","updated_at":"2016-06-14T15:02:56.815Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":9,"description":null,"position":0,"updated_by_id":null,"merge_error":null,"diff_head_sha":"HEAD","source_branch_sha":"ABCD","target_branch_sha":"DCBA","merge_params":{"force_remove_source_branch":null}}}
+{"id":36,"project_id":5,"ref":null,"sha":"sha-notes","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.755Z","updated_at":"2016-03-22T15:20:35.755Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"user_id":2147483547,"duration":null,"source":"push","merge_request_id":null,"pipeline_metadata": {"id": 2, "project_id": 5, "pipeline_id": 36, "name": "Build pipeline"},"notes":[{"id":2147483547,"note":"Natus rerum qui dolorem dolorum voluptas.","noteable_type":"Commit","author_id":1,"created_at":"2016-03-22T15:19:59.469Z","updated_at":"2016-03-22T15:19:59.469Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":"be93687618e4b132087f430a4d8fc3a609c9b77c","noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"}}],"stages":[{"id":11,"project_id":5,"pipeline_id":36,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":71,"project_id":5,"status":"failed","finished_at":"2016-03-29T06:28:12.630Z","trace":null,"created_at":"2016-03-22T15:20:35.772Z","updated_at":"2016-03-29T06:28:12.634Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":{"image":"busybox:latest"},"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"stage_id":11,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null,"type":"Ci::Build","token":"abcd","artifacts_file_store":1,"artifacts_metadata_store":1,"artifacts_size":10}],"bridges":[{"id":72,"project_id":5,"status":"success","finished_at":null,"trace":"Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}], "generic_commit_statuses": [{"id":72,"project_id":5,"status":"success","finished_at":null,"trace":"Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]},{"id":12,"project_id":5,"pipeline_id":36,"name":"deploy","status":2,"created_at":"2016-03-22T15:45:45.772Z","updated_at":"2016-03-29T06:45:45.634Z"}]}
+{"id":38,"iid":1,"project_id":5,"ref":"master","sha":"5f923865dde3436854e9ceb9cdb7815618d4e849","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.759Z","updated_at":"2016-03-22T15:20:35.759Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":22,"project_id":5,"pipeline_id":38,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":76,"project_id":5,"status":"success","finished_at":null,"trace":"Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.","created_at":"2016-03-22T15:20:35.882Z","updated_at":"2016-03-22T15:20:35.882Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":38,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":75,"project_id":5,"status":"failed","finished_at":null,"trace":"Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.","created_at":"2016-03-22T15:20:35.864Z","updated_at":"2016-03-22T15:20:35.864Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":38,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
+{"id":39,"project_id":5,"ref":"master","sha":"d2d430676773caa88cdaf7c55944073b2fd5561a","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.761Z","updated_at":"2016-03-22T15:20:35.761Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":23,"project_id":5,"pipeline_id":39,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":78,"project_id":5,"status":"success","finished_at":null,"trace":"Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.","created_at":"2016-03-22T15:20:35.927Z","updated_at":"2016-03-22T15:20:35.927Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":39,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":77,"project_id":5,"status":"failed","finished_at":null,"trace":"Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.","created_at":"2016-03-22T15:20:35.905Z","updated_at":"2016-03-22T15:20:35.905Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":39,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
{"id":41,"project_id":5,"ref":"master","sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[]}
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/commit_notes.ndjson b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/commit_notes.ndjson
new file mode 100644
index 00000000000..b623c388b4f
--- /dev/null
+++ b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/commit_notes.ndjson
@@ -0,0 +1,2 @@
+{"note":"Commit note 1","noteable_type":"Commit","author_id":1,"created_at":"2023-01-30T19:27:36.585Z","updated_at":"2023-02-10T14:43:01.308Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":"sha-notes","system":false,"st_diff":null,"updated_by_id":1,"type":null,"position":null,"original_position":null,"resolved_at":null,"resolved_by_id":null,"discussion_id":"e3fde7d585c6467a7a5147e83617eb6daa61aaf4","change_position":null,"resolved_by_push":null,"confidential":null,"last_edited_at":"2023-02-10T14:43:01.306Z","author":{"name":"Administrator"},"events":[{"project_id":1,"author_id":1,"created_at":"2023-01-30T19:27:36.815Z","updated_at":"2023-01-30T19:27:36.815Z","action":"commented","target_type":"Note","fingerprint":null,"push_event_payload":{"commit_count":1,"action":"pushed","ref_type":"branch","commit_to":"sha-notes","ref":"master"}}]}
+{"note":"Commit note 2","noteable_type":"Commit","author_id":1,"created_at":"2023-02-10T14:44:08.138Z","updated_at":"2023-02-10T14:54:42.828Z","project_id":1,"attachment":{"url":null},"line_code":null,"commit_id":"sha-notes","system":false,"st_diff":null,"updated_by_id":1,"type":null,"position":null,"original_position":null,"resolved_at":null,"resolved_by_id":null,"discussion_id":"53ca55a01732aff4f17daecdf076853f4ab152eb","change_position":null,"resolved_by_push":null,"confidential":null,"last_edited_at":"2023-02-10T14:54:42.827Z","author":{"name":"Administrator"},"events":[{"project_id":1,"author_id":1,"created_at":"2023-02-10T16:37:16.659Z","updated_at":"2023-02-10T16:37:16.659Z","action":"commented","target_type":"Note","fingerprint":null}]}
diff --git a/spec/fixtures/packages/debian/README.md b/spec/fixtures/packages/debian/README.md
index e398222ce62..af8e19a2de8 100644
--- a/spec/fixtures/packages/debian/README.md
+++ b/spec/fixtures/packages/debian/README.md
@@ -10,7 +10,7 @@ Go to the `spec/fixtures/packages/debian` directory and clean up old files:
```shell
cd spec/fixtures/packages/debian
-rm -v *.tar.* *.dsc *.deb *.udeb *.buildinfo *.changes
+rm -v *.tar.* *.dsc *.deb *.udeb *.ddeb *.buildinfo *.changes
```
Go to the package source directory and build:
diff --git a/spec/fixtures/packages/debian/sample-ddeb_1.2.3~alpha2_amd64.ddeb b/spec/fixtures/packages/debian/sample-ddeb_1.2.3~alpha2_amd64.ddeb
new file mode 100644
index 00000000000..fb4631219df
--- /dev/null
+++ b/spec/fixtures/packages/debian/sample-ddeb_1.2.3~alpha2_amd64.ddeb
Binary files differ
diff --git a/spec/fixtures/packages/debian/sample/debian/.gitignore b/spec/fixtures/packages/debian/sample/debian/.gitignore
index cb63a746c89..5eb910775ff 100644
--- a/spec/fixtures/packages/debian/sample/debian/.gitignore
+++ b/spec/fixtures/packages/debian/sample/debian/.gitignore
@@ -5,4 +5,4 @@ files
libsample0
sample-dev
sample-udeb
-
+sample-ddeb
diff --git a/spec/fixtures/packages/debian/sample/debian/control b/spec/fixtures/packages/debian/sample/debian/control
index 26d84e1c35d..f9f1b29e3a6 100644
--- a/spec/fixtures/packages/debian/sample/debian/control
+++ b/spec/fixtures/packages/debian/sample/debian/control
@@ -33,3 +33,7 @@ Package-Type: udeb
Architecture: any
Depends: installed-base
Description: Some mostly empty udeb
+
+Package: sample-ddeb
+Architecture: any
+Description: Some fake Ubuntu ddeb
diff --git a/spec/fixtures/packages/debian/sample/debian/rules b/spec/fixtures/packages/debian/sample/debian/rules
index 8ae87843489..9d55aace045 100755
--- a/spec/fixtures/packages/debian/sample/debian/rules
+++ b/spec/fixtures/packages/debian/sample/debian/rules
@@ -1,6 +1,13 @@
#!/usr/bin/make -f
%:
dh $@
+
override_dh_gencontrol:
dh_gencontrol -psample-dev -- -v'1.2.3~binary'
dh_gencontrol --remaining-packages
+
+override_dh_builddeb:
+ # Hack to mimic Ubuntu ddebs
+ dh_builddeb
+ mv ../sample-ddeb_1.2.3~alpha2_amd64.deb ../sample-ddeb_1.2.3~alpha2_amd64.ddeb
+ sed -i 's/sample-ddeb_1.2.3~alpha2_amd64.deb libs optional/sample-ddeb_1.2.3~alpha2_amd64.ddeb libs optional/' debian/files \ No newline at end of file
diff --git a/spec/fixtures/packages/debian/sample_1.2.3~alpha2.dsc b/spec/fixtures/packages/debian/sample_1.2.3~alpha2.dsc
index 4a5755cd612..21539c229e3 100644
--- a/spec/fixtures/packages/debian/sample_1.2.3~alpha2.dsc
+++ b/spec/fixtures/packages/debian/sample_1.2.3~alpha2.dsc
@@ -1,6 +1,6 @@
Format: 3.0 (native)
Source: sample
-Binary: sample-dev, libsample0, sample-udeb
+Binary: sample-dev, libsample0, sample-udeb, sample-ddeb
Architecture: any
Version: 1.2.3~alpha2
Maintainer: John Doe <john.doe@example.com>
@@ -9,11 +9,12 @@ Standards-Version: 4.5.0
Build-Depends: debhelper-compat (= 13)
Package-List:
libsample0 deb libs optional arch=any
+ sample-ddeb deb libs optional arch=any
sample-dev deb libdevel optional arch=any
sample-udeb udeb libs optional arch=any
Checksums-Sha1:
- c5cfc111ea924842a89a06d5673f07dfd07de8ca 864 sample_1.2.3~alpha2.tar.xz
+ 4a9cb2a7c77a68dc0fe54ba8ecef133a7c949e9d 964 sample_1.2.3~alpha2.tar.xz
Checksums-Sha256:
- 40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da 864 sample_1.2.3~alpha2.tar.xz
+ c9d05185ca158bb804977fa9d7b922e8a0f644a2da41f99d2787dd61b1e2e2c5 964 sample_1.2.3~alpha2.tar.xz
Files:
- d5ca476e4229d135a88f9c729c7606c9 864 sample_1.2.3~alpha2.tar.xz
+ adc69e57cda38d9bb7c8d59cacfb6869 964 sample_1.2.3~alpha2.tar.xz
diff --git a/spec/fixtures/packages/debian/sample_1.2.3~alpha2.tar.xz b/spec/fixtures/packages/debian/sample_1.2.3~alpha2.tar.xz
index 2bad3f065b8..d4a43b01821 100644
--- a/spec/fixtures/packages/debian/sample_1.2.3~alpha2.tar.xz
+++ b/spec/fixtures/packages/debian/sample_1.2.3~alpha2.tar.xz
Binary files differ
diff --git a/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.buildinfo b/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.buildinfo
index 36e2390b8c7..7bbf1517a53 100644
--- a/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.buildinfo
+++ b/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.buildinfo
@@ -1,186 +1,198 @@
Format: 1.0
Source: sample
-Binary: libsample0 sample-dev sample-udeb
+Binary: libsample0 sample-ddeb sample-dev sample-udeb
Architecture: amd64 source
Version: 1.2.3~alpha2
Checksums-Md5:
- ceccb6bb3e45ce6550b24234d4023e0f 671 sample_1.2.3~alpha2.dsc
+ 629921cfc477bfa84adfd2ccaba89783 724 sample_1.2.3~alpha2.dsc
fb0842b21adc44207996296fe14439dd 1124 libsample0_1.2.3~alpha2_amd64.deb
+ 90d1107471eed48c73ad78b19ac83639 1068 sample-ddeb_1.2.3~alpha2_amd64.ddeb
5fafc04dcae1525e1367b15413e5a5c7 1164 sample-dev_1.2.3~binary_amd64.deb
72b1dd7d98229e2fb0355feda1d3a165 736 sample-udeb_1.2.3~alpha2_amd64.udeb
Checksums-Sha1:
- 375ba20ea1789e1e90d469c3454ce49a431d0442 671 sample_1.2.3~alpha2.dsc
+ 443c98a4cf4acd21e2259ae8f2d60fc9932de353 724 sample_1.2.3~alpha2.dsc
5248b95600e85bfe7f63c0dfce330a75f5777366 1124 libsample0_1.2.3~alpha2_amd64.deb
+ 9c5af97cf8dfbe8126c807f540c88757f382b307 1068 sample-ddeb_1.2.3~alpha2_amd64.ddeb
fcd5220b1501ec150ccf37f06e4da919a8612be4 1164 sample-dev_1.2.3~binary_amd64.deb
e42e8f2fe04ed1bb73b44a187674480d0e49dcba 736 sample-udeb_1.2.3~alpha2_amd64.udeb
Checksums-Sha256:
- 81fc156ba937cdb6215362cc4bf6b8dc47be9b4253ba0f1a4ab10c7ea0c4c4e5 671 sample_1.2.3~alpha2.dsc
+ f91070524a59bbb3a1f05a78409e92cb9ee86470b34018bc0b93bd5b2dd3868c 724 sample_1.2.3~alpha2.dsc
1c383a525bfcba619c7305ccd106d61db501a6bbaf0003bf8d0c429fbdb7fcc1 1124 libsample0_1.2.3~alpha2_amd64.deb
+ a6bcc8a4b010f99ce0ea566ac69088e1910e754593c77f2b4942e3473e784e4d 1068 sample-ddeb_1.2.3~alpha2_amd64.ddeb
b8aa8b73a14bc1e0012d4c5309770f5160a8ea7f9dfe6f45222ea6b8a3c35325 1164 sample-dev_1.2.3~binary_amd64.deb
2b0c152b3ab4cc07663350424de972c2b7621d69fe6df2e0b94308a191e4632f 736 sample-udeb_1.2.3~alpha2_amd64.udeb
Build-Origin: Debian
Build-Architecture: amd64
-Build-Date: Fri, 14 May 2021 16:51:32 +0200
+Build-Date: Sat, 04 Mar 2023 09:42:57 +0100
Build-Tainted-By:
merged-usr-via-aliased-dirs
usr-local-has-includes
usr-local-has-libraries
usr-local-has-programs
Installed-Build-Depends:
- autoconf (= 2.69-14),
- automake (= 1:1.16.3-2),
- autopoint (= 0.21-4),
- autotools-dev (= 20180224.1+nmu1),
- base-files (= 11),
- base-passwd (= 3.5.49),
- bash (= 5.1-2+b1),
- binutils (= 2.35.2-2),
- binutils-common (= 2.35.2-2),
- binutils-x86-64-linux-gnu (= 2.35.2-2),
- bsdextrautils (= 2.36.1-7),
+ autoconf (= 2.71-3),
+ automake (= 1:1.16.5-1.3),
+ autopoint (= 0.21-11),
+ autotools-dev (= 20220109.1),
+ base-files (= 12.3),
+ base-passwd (= 3.6.1),
+ bash (= 5.2.15-2+b1),
+ binutils (= 2.40-2),
+ binutils-common (= 2.40-2),
+ binutils-x86-64-linux-gnu (= 2.40-2),
+ bsdextrautils (= 2.38.1-4),
bsdmainutils (= 12.1.7+nmu3),
- bsdutils (= 1:2.36.1-7),
+ bsdutils (= 1:2.38.1-4),
build-essential (= 12.9),
- bzip2 (= 1.0.8-4),
- coreutils (= 8.32-4+b1),
- cpp (= 4:10.2.1-1),
- cpp-10 (= 10.2.1-6),
- cpp-9 (= 9.3.0-22),
- dash (= 0.5.11+git20200708+dd9ef66-5),
- debconf (= 1.5.75),
- debhelper (= 13.3.4),
- debianutils (= 4.11.2),
+ bzip2 (= 1.0.8-5+b1),
+ coreutils (= 9.1-1),
+ cpp (= 4:12.2.0-3),
+ cpp-10 (= 10.4.0-7),
+ cpp-12 (= 12.2.0-14),
+ dash (= 0.5.12-2),
+ debconf (= 1.5.82),
+ debhelper (= 13.11.4),
+ debianutils (= 5.7-0.4),
dh-autoreconf (= 20),
- dh-strip-nondeterminism (= 1.11.0-1),
- diffutils (= 1:3.7-5),
- dpkg (= 1.20.9),
- dpkg-dev (= 1.20.9),
- dwz (= 0.13+20210201-1),
- file (= 1:5.39-3),
- findutils (= 4.8.0-1),
- g++ (= 4:10.2.1-1),
- g++-10 (= 10.2.1-6),
- gcc (= 4:10.2.1-1),
- gcc-10 (= 10.2.1-6),
- gcc-10-base (= 10.2.1-6),
- gcc-9 (= 9.3.0-22),
- gcc-9-base (= 9.3.0-22),
- gettext (= 0.21-4),
- gettext-base (= 0.21-4),
- grep (= 3.6-1),
- groff-base (= 1.22.4-6),
- gzip (= 1.10-4),
- hostname (= 3.23),
- init-system-helpers (= 1.60),
- intltool-debian (= 0.35.0+20060710.5),
- libacl1 (= 2.2.53-10),
+ dh-strip-nondeterminism (= 1.13.1-1),
+ diffutils (= 1:3.8-4),
+ dpkg (= 1.21.20),
+ dpkg-dev (= 1.21.20),
+ dwz (= 0.15-1),
+ file (= 1:5.44-3),
+ findutils (= 4.9.0-4),
+ g++ (= 4:12.2.0-3),
+ g++-12 (= 12.2.0-14),
+ gcc (= 4:12.2.0-3),
+ gcc-10 (= 10.4.0-7),
+ gcc-10-base (= 10.4.0-7),
+ gcc-11-base (= 11.3.0-11),
+ gcc-12 (= 12.2.0-14),
+ gcc-12-base (= 12.2.0-14),
+ gettext (= 0.21-11),
+ gettext-base (= 0.21-11),
+ grep (= 3.8-5),
+ groff-base (= 1.22.4-9),
+ gzip (= 1.12-1),
+ hostname (= 3.23+nmu1),
+ init-system-helpers (= 1.65.2),
+ intltool-debian (= 0.35.0+20060710.6),
+ libacl1 (= 2.3.1-3),
libarchive-zip-perl (= 1.68-1),
- libasan5 (= 9.3.0-22),
- libasan6 (= 10.2.1-6),
- libatomic1 (= 10.2.1-6),
- libattr1 (= 1:2.4.48-6),
- libaudit-common (= 1:3.0-2),
- libaudit1 (= 1:3.0-2),
- libbinutils (= 2.35.2-2),
- libblkid1 (= 2.36.1-7),
- libbz2-1.0 (= 1.0.8-4),
- libc-bin (= 2.31-11),
- libc-dev-bin (= 2.31-11),
- libc6 (= 2.31-11),
- libc6-dev (= 2.31-11),
- libcap-ng0 (= 0.7.9-2.2+b1),
- libcc1-0 (= 10.2.1-6),
- libcom-err2 (= 1.46.2-1),
- libcrypt-dev (= 1:4.4.18-2),
- libcrypt1 (= 1:4.4.18-2),
- libctf-nobfd0 (= 2.35.2-2),
- libctf0 (= 2.35.2-2),
- libdb5.3 (= 5.3.28+dfsg1-0.8),
- libdebconfclient0 (= 0.257),
- libdebhelper-perl (= 13.3.4),
- libdpkg-perl (= 1.20.9),
- libelf1 (= 0.183-1),
- libfile-stripnondeterminism-perl (= 1.11.0-1),
- libgcc-10-dev (= 10.2.1-6),
- libgcc-9-dev (= 9.3.0-22),
- libgcc-s1 (= 10.2.1-6),
- libgcrypt20 (= 1.8.7-3),
- libgdbm-compat4 (= 1.19-2),
- libgdbm6 (= 1.19-2),
- libgmp10 (= 2:6.2.1+dfsg-1),
- libgomp1 (= 10.2.1-6),
- libgpg-error0 (= 1.38-2),
- libgssapi-krb5-2 (= 1.18.3-5),
- libicu67 (= 67.1-6),
- libisl23 (= 0.23-1),
- libitm1 (= 10.2.1-6),
- libk5crypto3 (= 1.18.3-5),
- libkeyutils1 (= 1.6.1-2),
- libkrb5-3 (= 1.18.3-5),
- libkrb5support0 (= 1.18.3-5),
- liblsan0 (= 10.2.1-6),
- liblz4-1 (= 1.9.3-1),
- liblzma5 (= 5.2.5-2),
- libmagic-mgc (= 1:5.39-3),
- libmagic1 (= 1:5.39-3),
- libmount1 (= 2.36.1-7),
- libmpc3 (= 1.2.0-1),
- libmpfr6 (= 4.1.0-3),
+ libasan6 (= 11.3.0-11),
+ libasan8 (= 12.2.0-14),
+ libatomic1 (= 12.2.0-14),
+ libattr1 (= 1:2.5.1-4),
+ libaudit-common (= 1:3.0.9-1),
+ libaudit1 (= 1:3.0.9-1),
+ libbinutils (= 2.40-2),
+ libblkid1 (= 2.38.1-4),
+ libbz2-1.0 (= 1.0.8-5+b1),
+ libc-bin (= 2.36-8),
+ libc-dev-bin (= 2.36-8),
+ libc6 (= 2.36-8),
+ libc6-dev (= 2.36-8),
+ libcap-ng0 (= 0.8.3-1+b3),
+ libcap2 (= 1:2.66-3),
+ libcc1-0 (= 12.2.0-14),
+ libcom-err2 (= 1.46.6-1),
+ libcrypt-dev (= 1:4.4.33-2),
+ libcrypt1 (= 1:4.4.33-2),
+ libctf-nobfd0 (= 2.40-2),
+ libctf0 (= 2.40-2),
+ libdb5.3 (= 5.3.28+dfsg2-1),
+ libdebconfclient0 (= 0.267),
+ libdebhelper-perl (= 13.11.4),
+ libdpkg-perl (= 1.21.20),
+ libelf1 (= 0.188-2.1),
+ libfile-find-rule-perl (= 0.34-3),
+ libfile-stripnondeterminism-perl (= 1.13.1-1),
+ libgcc-10-dev (= 10.4.0-7),
+ libgcc-12-dev (= 12.2.0-14),
+ libgcc-s1 (= 12.2.0-14),
+ libgcrypt20 (= 1.10.1-3),
+ libgdbm-compat4 (= 1.23-3),
+ libgdbm6 (= 1.23-3),
+ libgmp10 (= 2:6.2.1+dfsg1-1.1),
+ libgomp1 (= 12.2.0-14),
+ libgpg-error0 (= 1.46-1),
+ libgprofng0 (= 2.40-2),
+ libgssapi-krb5-2 (= 1.20.1-1),
+ libicu72 (= 72.1-3),
+ libisl23 (= 0.25-1),
+ libitm1 (= 12.2.0-14),
+ libjansson4 (= 2.14-2),
+ libk5crypto3 (= 1.20.1-1),
+ libkeyutils1 (= 1.6.3-2),
+ libkrb5-3 (= 1.20.1-1),
+ libkrb5support0 (= 1.20.1-1),
+ liblsan0 (= 12.2.0-14),
+ liblz4-1 (= 1.9.4-1),
+ liblzma5 (= 5.4.1-0.1),
+ libmagic-mgc (= 1:5.44-3),
+ libmagic1 (= 1:5.44-3),
+ libmd0 (= 1.0.4-2),
+ libmount1 (= 2.38.1-4),
+ libmpc3 (= 1.3.1-1),
+ libmpfr6 (= 4.2.0-1),
libnsl-dev (= 1.3.0-2),
libnsl2 (= 1.3.0-2),
- libpam-modules (= 1.4.0-7),
- libpam-modules-bin (= 1.4.0-7),
- libpam-runtime (= 1.4.0-7),
- libpam0g (= 1.4.0-7),
- libpcre2-8-0 (= 10.36-2),
- libpcre3 (= 2:8.39-13),
- libperl5.32 (= 5.32.1-4),
- libpipeline1 (= 1.5.3-1),
- libquadmath0 (= 10.2.1-6),
- libseccomp2 (= 2.5.1-1),
- libselinux1 (= 3.1-3),
- libsigsegv2 (= 2.13-1),
- libsmartcols1 (= 2.36.1-7),
- libssl1.1 (= 1.1.1k-1),
- libstdc++-10-dev (= 10.2.1-6),
- libstdc++6 (= 10.2.1-6),
- libsub-override-perl (= 0.09-2),
- libsystemd0 (= 247.3-5),
- libtinfo6 (= 6.2+20201114-2),
- libtirpc-common (= 1.3.1-1),
- libtirpc-dev (= 1.3.1-1),
- libtirpc3 (= 1.3.1-1),
- libtool (= 2.4.6-15),
- libtsan0 (= 10.2.1-6),
- libubsan1 (= 10.2.1-6),
+ libnumber-compare-perl (= 0.03-3),
+ libpam-modules (= 1.5.2-6),
+ libpam-modules-bin (= 1.5.2-6),
+ libpam-runtime (= 1.5.2-6),
+ libpam0g (= 1.5.2-6),
+ libpcre2-8-0 (= 10.42-1),
+ libperl5.36 (= 5.36.0-7),
+ libpipeline1 (= 1.5.7-1),
+ libquadmath0 (= 12.2.0-14),
+ libseccomp2 (= 2.5.4-1+b3),
+ libselinux1 (= 3.4-1+b5),
+ libsmartcols1 (= 2.38.1-4),
+ libssl3 (= 3.0.8-1),
+ libstdc++-12-dev (= 12.2.0-14),
+ libstdc++6 (= 12.2.0-14),
+ libsub-override-perl (= 0.09-4),
+ libsystemd0 (= 252.5-2),
+ libtext-glob-perl (= 0.11-3),
+ libtinfo6 (= 6.4-2),
+ libtirpc-common (= 1.3.3+ds-1),
+ libtirpc-dev (= 1.3.3+ds-1),
+ libtirpc3 (= 1.3.3+ds-1),
+ libtool (= 2.4.7-5),
+ libtsan0 (= 11.3.0-11),
+ libtsan2 (= 12.2.0-14),
+ libubsan1 (= 12.2.0-14),
libuchardet0 (= 0.0.7-1),
- libudev1 (= 247.3-5),
- libunistring2 (= 0.9.10-4),
- libuuid1 (= 2.36.1-7),
- libxml2 (= 2.9.10+dfsg-6.3+b1),
- libzstd1 (= 1.4.8+dfsg-2.1),
- linux-libc-dev (= 5.10.28-1),
- login (= 1:4.8.1-1),
- lsb-base (= 11.1.0),
- m4 (= 1.4.18-5),
+ libudev1 (= 252.5-2),
+ libunistring2 (= 1.0-2),
+ libuuid1 (= 2.38.1-4),
+ libxml2 (= 2.9.14+dfsg-1.1+b3),
+ libzstd1 (= 1.5.2+dfsg2-3),
+ linux-libc-dev (= 6.1.8-1),
+ login (= 1:4.13+dfsg1-1),
+ m4 (= 1.4.19-3),
make (= 4.3-4.1),
- man-db (= 2.9.4-2),
- mawk (= 1.3.4.20200120-2),
+ man-db (= 2.11.2-1),
+ mawk (= 1.3.4.20200120-3.1),
ncal (= 12.1.7+nmu3),
- ncurses-base (= 6.2+20201114-2),
- ncurses-bin (= 6.2+20201114-2),
+ ncurses-base (= 6.4-2),
+ ncurses-bin (= 6.4-2),
patch (= 2.7.6-7),
- perl (= 5.32.1-4),
- perl-base (= 5.32.1-4),
- perl-modules-5.32 (= 5.32.1-4),
+ perl (= 5.36.0-7),
+ perl-base (= 5.36.0-7),
+ perl-modules-5.36 (= 5.36.0-7),
po-debconf (= 1.0.21+nmu1),
- sed (= 4.7-1),
- sensible-utils (= 0.0.14),
- sysvinit-utils (= 2.96-7),
+ rpcsvc-proto (= 1.4.3-1),
+ sed (= 4.9-1),
+ sensible-utils (= 0.0.17+nmu1),
+ sysvinit-utils (= 3.06-2),
tar (= 1.34+dfsg-1),
- util-linux (= 2.36.1-7),
- xz-utils (= 5.2.5-2),
- zlib1g (= 1:1.2.11.dfsg-2)
+ usrmerge (= 35),
+ util-linux (= 2.38.1-4),
+ util-linux-extra (= 2.38.1-4),
+ xz-utils (= 5.4.1-0.1),
+ zlib1g (= 1:1.2.13.dfsg-1)
Environment:
DEB_BUILD_OPTIONS="parallel=8"
LANG="fr_FR.UTF-8"
diff --git a/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.changes b/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.changes
index 7aa4761c49c..a1d2f95e231 100644
--- a/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.changes
+++ b/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.changes
@@ -17,23 +17,26 @@ Changes:
.
* Initial release
Checksums-Sha1:
- 375ba20ea1789e1e90d469c3454ce49a431d0442 671 sample_1.2.3~alpha2.dsc
- c5cfc111ea924842a89a06d5673f07dfd07de8ca 864 sample_1.2.3~alpha2.tar.xz
+ 443c98a4cf4acd21e2259ae8f2d60fc9932de353 724 sample_1.2.3~alpha2.dsc
+ 4a9cb2a7c77a68dc0fe54ba8ecef133a7c949e9d 964 sample_1.2.3~alpha2.tar.xz
5248b95600e85bfe7f63c0dfce330a75f5777366 1124 libsample0_1.2.3~alpha2_amd64.deb
+ 9c5af97cf8dfbe8126c807f540c88757f382b307 1068 sample-ddeb_1.2.3~alpha2_amd64.ddeb
fcd5220b1501ec150ccf37f06e4da919a8612be4 1164 sample-dev_1.2.3~binary_amd64.deb
e42e8f2fe04ed1bb73b44a187674480d0e49dcba 736 sample-udeb_1.2.3~alpha2_amd64.udeb
- 661f7507efa6fdd3763c95581d0baadb978b7ef5 5507 sample_1.2.3~alpha2_amd64.buildinfo
+ bcc4ca85f17a31066b726cd4e04485ab24a682c6 6032 sample_1.2.3~alpha2_amd64.buildinfo
Checksums-Sha256:
- 81fc156ba937cdb6215362cc4bf6b8dc47be9b4253ba0f1a4ab10c7ea0c4c4e5 671 sample_1.2.3~alpha2.dsc
- 40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da 864 sample_1.2.3~alpha2.tar.xz
+ f91070524a59bbb3a1f05a78409e92cb9ee86470b34018bc0b93bd5b2dd3868c 724 sample_1.2.3~alpha2.dsc
+ c9d05185ca158bb804977fa9d7b922e8a0f644a2da41f99d2787dd61b1e2e2c5 964 sample_1.2.3~alpha2.tar.xz
1c383a525bfcba619c7305ccd106d61db501a6bbaf0003bf8d0c429fbdb7fcc1 1124 libsample0_1.2.3~alpha2_amd64.deb
+ a6bcc8a4b010f99ce0ea566ac69088e1910e754593c77f2b4942e3473e784e4d 1068 sample-ddeb_1.2.3~alpha2_amd64.ddeb
b8aa8b73a14bc1e0012d4c5309770f5160a8ea7f9dfe6f45222ea6b8a3c35325 1164 sample-dev_1.2.3~binary_amd64.deb
2b0c152b3ab4cc07663350424de972c2b7621d69fe6df2e0b94308a191e4632f 736 sample-udeb_1.2.3~alpha2_amd64.udeb
- d0c169e9caa5b303a914b27b5adf69768fe6687d4925905b7d0cd9c0f9d4e56c 5507 sample_1.2.3~alpha2_amd64.buildinfo
+ 5a3dac17c4ff0d49fa5f47baa973902b59ad2ee05147062b8ed8f19d196731d1 6032 sample_1.2.3~alpha2_amd64.buildinfo
Files:
- ceccb6bb3e45ce6550b24234d4023e0f 671 libs optional sample_1.2.3~alpha2.dsc
- d5ca476e4229d135a88f9c729c7606c9 864 libs optional sample_1.2.3~alpha2.tar.xz
+ 629921cfc477bfa84adfd2ccaba89783 724 libs optional sample_1.2.3~alpha2.dsc
+ adc69e57cda38d9bb7c8d59cacfb6869 964 libs optional sample_1.2.3~alpha2.tar.xz
fb0842b21adc44207996296fe14439dd 1124 libs optional libsample0_1.2.3~alpha2_amd64.deb
+ 90d1107471eed48c73ad78b19ac83639 1068 libs optional sample-ddeb_1.2.3~alpha2_amd64.ddeb
5fafc04dcae1525e1367b15413e5a5c7 1164 libdevel optional sample-dev_1.2.3~binary_amd64.deb
72b1dd7d98229e2fb0355feda1d3a165 736 libs optional sample-udeb_1.2.3~alpha2_amd64.udeb
- 12a5ac4f16ad75f8741327ac23b4c0d7 5507 libs optional sample_1.2.3~alpha2_amd64.buildinfo
+ cc07ff4d741aec132816f9bd67c6875d 6032 libs optional sample_1.2.3~alpha2_amd64.buildinfo
diff --git a/spec/fixtures/service_account.json b/spec/fixtures/service_account.json
new file mode 100644
index 00000000000..9f7f5526cf5
--- /dev/null
+++ b/spec/fixtures/service_account.json
@@ -0,0 +1,12 @@
+{
+ "type": "service_account",
+ "project_id": "demo-app-123",
+ "private_key_id": "47f0b1700983da548af6fcd37007f42996099999",
+ "private_key": "-----BEGIN PRIVATE KEY-----\nABCDEFIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJn8w20WcN+fi5\nIhO1BEFCv7ExK8J5rW5Pc8XpJgpQoL5cfv6qC6aS+x4maI7S4AG7diqXBLCfjlnA\nqBzXwCRnnPtQhu+v1ehAj5fGNa7F51f9aacRNmKdHzNmWZEPDuLqq0I/Ewcsotu+\nnb+tCYk1o2ahyPZau8JtXFZs7oZb7SrfgoSJemccxeVreGm1Dt6SM74/3qJAeHN/\niK/v0IiQP1GS4Jxgz38XQGo+jiTpNrFcf4S0RNxKcNf+tuuEBDi57LBLwdotM7E5\nF1l9pZZMWkmQKQIxeER6+2HuE56V6QPITwkQ/u9XZFQSgl4SBIw2sHr5D/xaUxjw\n+kMy2Jt9AgMBAAECggEACL7E34rRIWbP043cv3ZQs1RiWzY2mvWmCiMEzkz0rRRv\nyqNv0yXVYtzVV7KjdpY56leLgjM1Sv0PEQoUUtpWFJAXSXdKLaewSXPrpXCoz5OD\nekMgeItnQcE7nECdyAKsCSQw/SXg4t4p0a3WGsCwt3If2TwWIrov9R4zGcn1wMZn\n922WtZDmh2NqdTZIKElWZLxNlIr/1v88mAp7oSa1DLfqWkwEEnxK7GGAiwN8ARIF\nkvgiuKdsHBf5aNKg70xN6AcZx/Z4+KZxXxyKKF5VkjCtDzA97EjJqftDPwGTkela\n2bgiDSJs0Un0wQpFFRDrlfyo7rr9Ey/Gf4rR66NWeQKBgQD7qPP55xoWHCDvoK9P\nMN67qFLNDPWcKVKr8siwUlZ6/+acATXjfNUjsJLM7vBxYLjdtFxQ/vojJTQyMxHt\n80wARDk1DTu2zhltL2rKo6LfbwjQsot1MLZFXAMwqtHTLfURaj8kO1JDV/j+4a94\nP0gzNMiBYAKWm6z08akEz2TrhQKBgQDNGfFvtxo4Mf6AA3iYXCwc0CJXb+cqZkW/\n7glnV+vDqYVo23HJaKHFD+Xqaj+cUrOUNglWgT9WSCZR++Hzw1OCPZvX2V9Z6eQh\ngqOBX6D19q9jfShfxLywEAD5pk7LMINumsNm6H+6shJQK5c67bsM9/KQbSnIlWhw\n7JBe8OlFmQKBgQDREyF2mb/7ZG0ch8N9qB0zjHkV79FRZqdPQUnn6s/8KgO90eei\nUkCFARpE9bF+kBul3UTg6aSIdE0z82fO51VZ11Qrtg3JJtrK8hznsyEKPaX2NI9V\n0h1r7DCeSxw9NS4nxLwmbr4+QqUTpA3yeaiTGiQGD+y2kSkU6nxACclPPQKBgFkb\nkVqg6YJKrjB90ZIYUY3/GzxzwLIaFumpCGretu6eIvkIhiokDExqeNBccuB+ych1\npZ7wrkzVMdjinythzFFEZQXlSdjtlhC9Cj52Bp92GoMV6EmbVwMDIPlVuNvsat3N\n3WFDV+ML5IryNVUD3gVnX/pBgyrDRsnw7VRiRGbZAoGBANxZwGKZo0zpyb5O5hS6\nxVrgJtIySlV5BOEjFXKeLwzByht8HmrHhSWix6WpPejfK1RHhl3boU6t9yeC0cre\nvUI/Y9LBhHXjSwWCWlqVe9yYqsde+xf0UYRS8IoaoJjus7YVJr9yPpCboEF28ZmQ\ndVBlpZYg6oLIar6waaLMz/1B\n-----END PRIVATE KEY-----\n",
+ "client_email": "demo-app-account@demo-app-374914.iam.gserviceaccount.com",
+ "client_id": "111111116847110173051",
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+ "token_uri": "https://oauth2.googleapis.com/token",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/demo-app-account%40demo-app-374914.iam.gserviceaccount.com"
+}
diff --git a/spec/fixtures/structure.sql b/spec/fixtures/structure.sql
index 49061dfa8ea..800c33bb9b9 100644
--- a/spec/fixtures/structure.sql
+++ b/spec/fixtures/structure.sql
@@ -18,3 +18,11 @@ CREATE TABLE ci_project_mirrors (
project_id integer NOT NULL,
namespace_id integer NOT NULL
);
+
+CREATE TRIGGER trigger AFTER INSERT ON public.t1 FOR EACH ROW EXECUTE FUNCTION t1();
+
+CREATE TRIGGER wrong_trigger BEFORE UPDATE ON public.t2 FOR EACH ROW EXECUTE FUNCTION my_function();
+
+CREATE TRIGGER missing_trigger_1 BEFORE INSERT OR UPDATE ON public.t3 FOR EACH ROW EXECUTE FUNCTION t3();
+
+CREATE TRIGGER projects_loose_fk_trigger AFTER DELETE ON projects REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
diff --git a/spec/fixtures/work_items_invalid_types.csv b/spec/fixtures/work_items_invalid_types.csv
new file mode 100644
index 00000000000..b82e9035451
--- /dev/null
+++ b/spec/fixtures/work_items_invalid_types.csv
@@ -0,0 +1,4 @@
+title,type
+Invalid issue,isssue
+Invalid Issue,issue!!
+Missing type,
diff --git a/spec/fixtures/work_items_missing_header.csv b/spec/fixtures/work_items_missing_header.csv
new file mode 100644
index 00000000000..1a2e7ed42ab
--- /dev/null
+++ b/spec/fixtures/work_items_missing_header.csv
@@ -0,0 +1,3 @@
+type,created_at
+issue,2021-01-01
+other_issue,2023-02-02
diff --git a/spec/fixtures/work_items_valid.csv b/spec/fixtures/work_items_valid.csv
new file mode 100644
index 00000000000..12f2f8bc816
--- /dev/null
+++ b/spec/fixtures/work_items_valid.csv
@@ -0,0 +1,3 @@
+title,type
+馬ã®ã‚¹ãƒ¢ãƒ¢ãƒ¢ãƒ¢ãƒ¢ãƒ¢ãƒ¢ãƒ¢,Issue
+Issue with alternate case,ISSUE
diff --git a/spec/fixtures/work_items_valid_types.csv b/spec/fixtures/work_items_valid_types.csv
new file mode 100644
index 00000000000..f4cca9e65f1
--- /dev/null
+++ b/spec/fixtures/work_items_valid_types.csv
@@ -0,0 +1,3 @@
+title,type
+Valid issue,issue
+Valid issue with alternate case,ISSUE
diff --git a/spec/frontend/.eslintrc.yml b/spec/frontend/.eslintrc.yml
index 45639f4c948..200f539fb3e 100644
--- a/spec/frontend/.eslintrc.yml
+++ b/spec/frontend/.eslintrc.yml
@@ -12,6 +12,7 @@ settings:
jest:
jestConfigFile: 'jest.config.js'
rules:
+ '@gitlab/vtu-no-explicit-wrapper-destroy': error
jest/expect-expect:
- off
- assertFunctionNames:
diff --git a/spec/frontend/__helpers__/create_mock_source_editor_extension.js b/spec/frontend/__helpers__/create_mock_source_editor_extension.js
new file mode 100644
index 00000000000..fa529604d6f
--- /dev/null
+++ b/spec/frontend/__helpers__/create_mock_source_editor_extension.js
@@ -0,0 +1,12 @@
+export const createMockSourceEditorExtension = (ActualExtension) => {
+ const { extensionName } = ActualExtension;
+ const providedKeys = Object.keys(new ActualExtension().provides());
+
+ const mockedMethods = Object.fromEntries(providedKeys.map((key) => [key, jest.fn()]));
+ const MockExtension = function MockExtension() {};
+ MockExtension.extensionName = extensionName;
+ MockExtension.mockedMethods = mockedMethods;
+ MockExtension.prototype.provides = jest.fn().mockReturnValue(mockedMethods);
+
+ return MockExtension;
+};
diff --git a/spec/frontend/__helpers__/experimentation_helper.js b/spec/frontend/__helpers__/experimentation_helper.js
index d5044be88d7..7e8dd463d28 100644
--- a/spec/frontend/__helpers__/experimentation_helper.js
+++ b/spec/frontend/__helpers__/experimentation_helper.js
@@ -2,16 +2,9 @@ import { merge } from 'lodash';
// This helper is for specs that use `gitlab/experimentation` module
export function withGonExperiment(experimentKey, value = true) {
- let origGon;
-
beforeEach(() => {
- origGon = window.gon;
window.gon = merge({}, window.gon || {}, { experiments: { [experimentKey]: value } });
});
-
- afterEach(() => {
- window.gon = origGon;
- });
}
// The following helper is for specs that use `gitlab-experiment` utilities,
diff --git a/spec/frontend/__helpers__/gon_helper.js b/spec/frontend/__helpers__/gon_helper.js
new file mode 100644
index 00000000000..51d5ece5fc1
--- /dev/null
+++ b/spec/frontend/__helpers__/gon_helper.js
@@ -0,0 +1,5 @@
+export const createGon = (IS_EE) => {
+ return {
+ ee: IS_EE,
+ };
+};
diff --git a/spec/frontend/__helpers__/keep_alive_component_helper_spec.js b/spec/frontend/__helpers__/keep_alive_component_helper_spec.js
index 54d397d0997..8b6cdedfd9f 100644
--- a/spec/frontend/__helpers__/keep_alive_component_helper_spec.js
+++ b/spec/frontend/__helpers__/keep_alive_component_helper_spec.js
@@ -12,10 +12,6 @@ describe('keepAlive', () => {
wrapper = mount(keepAlive(component));
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('converts a component to a keep-alive component', async () => {
const { element } = wrapper.findComponent(component);
diff --git a/spec/frontend/__helpers__/shared_test_setup.js b/spec/frontend/__helpers__/shared_test_setup.js
index 2fe9fe89a90..0217835b2a3 100644
--- a/spec/frontend/__helpers__/shared_test_setup.js
+++ b/spec/frontend/__helpers__/shared_test_setup.js
@@ -1,10 +1,12 @@
/* Common setup for both unit and integration test environments */
+import { ReadableStream, WritableStream } from 'node:stream/web';
import * as jqueryMatchers from 'custom-jquery-matchers';
import Vue from 'vue';
import { enableAutoDestroy } from '@vue/test-utils';
import 'jquery';
import Translate from '~/vue_shared/translate';
import setWindowLocation from './set_window_location_helper';
+import { createGon } from './gon_helper';
import { setGlobalDateToFakeDate } from './fake_date';
import { TEST_HOST } from './test_constants';
import * as customMatchers from './matchers';
@@ -13,6 +15,9 @@ import './dom_shims';
import './jquery';
import '~/commons/bootstrap';
+global.ReadableStream = ReadableStream;
+global.WritableStream = WritableStream;
+
enableAutoDestroy(afterEach);
// This module has some fairly decent visual test coverage in it's own repository.
@@ -67,8 +72,13 @@ beforeEach(() => {
// eslint-disable-next-line jest/no-standalone-expect
expect.hasAssertions();
- // Reset the mocked window.location. This ensures tests don't interfere with
- // each other, and removes the need to tidy up if it was changed for a given
- // test.
+ // Reset globals: This ensures tests don't interfere with
+ // each other, and removes the need to tidy up if it was
+ // changed for a given test.
+
+ // Reset the mocked window.location
setWindowLocation(TEST_HOST);
+
+ // Reset window.gon object
+ window.gon = createGon(window.IS_EE);
});
diff --git a/spec/frontend/__helpers__/vue_mock_directive.js b/spec/frontend/__helpers__/vue_mock_directive.js
index e952f258c4d..e7a2aa7f10d 100644
--- a/spec/frontend/__helpers__/vue_mock_directive.js
+++ b/spec/frontend/__helpers__/vue_mock_directive.js
@@ -2,7 +2,7 @@ export const getKey = (name) => `$_gl_jest_${name}`;
export const getBinding = (el, name) => el[getKey(name)];
-const writeBindingToElement = (el, { name, value, arg, modifiers }) => {
+const writeBindingToElement = (el, name, { value, arg, modifiers }) => {
el[getKey(name)] = {
value,
arg,
@@ -10,16 +10,24 @@ const writeBindingToElement = (el, { name, value, arg, modifiers }) => {
};
};
-export const createMockDirective = () => ({
- bind(el, binding) {
- writeBindingToElement(el, binding);
- },
+export const createMockDirective = (name) => {
+ if (!name) {
+ throw new Error(
+ 'Vue 3 no longer passes the name of the directive to its hooks, an explicit name is required',
+ );
+ }
- update(el, binding) {
- writeBindingToElement(el, binding);
- },
+ return {
+ bind(el, binding) {
+ writeBindingToElement(el, name, binding);
+ },
- unbind(el, { name }) {
- delete el[getKey(name)];
- },
-});
+ update(el, binding) {
+ writeBindingToElement(el, name, binding);
+ },
+
+ unbind(el) {
+ delete el[getKey(name)];
+ },
+ };
+};
diff --git a/spec/frontend/__helpers__/vuex_action_helper.js b/spec/frontend/__helpers__/vuex_action_helper.js
index bdd5a0a9034..94164814879 100644
--- a/spec/frontend/__helpers__/vuex_action_helper.js
+++ b/spec/frontend/__helpers__/vuex_action_helper.js
@@ -78,6 +78,8 @@ export default (
}
actions.push(dispatchedAction);
+
+ return Promise.resolve();
};
const validateResults = () => {
diff --git a/spec/frontend/__helpers__/vuex_action_helper_spec.js b/spec/frontend/__helpers__/vuex_action_helper_spec.js
index 4bd21ff150a..64081ca11a3 100644
--- a/spec/frontend/__helpers__/vuex_action_helper_spec.js
+++ b/spec/frontend/__helpers__/vuex_action_helper_spec.js
@@ -83,6 +83,20 @@ describe.each([testActionFn, testActionFnWithOptionsArg])(
});
});
+ describe('given an async action (chaining off a dispatch)', () => {
+ it('mocks dispatch accurately', () => {
+ const asyncAction = ({ commit, dispatch }) => {
+ return dispatch('ACTION').then(() => {
+ commit('MUTATION');
+ });
+ };
+
+ assertion = { actions: [{ type: 'ACTION' }], mutations: [{ type: 'MUTATION' }] };
+
+ return testAction(asyncAction, null, {}, assertion.mutations, assertion.actions);
+ });
+ });
+
describe('given an async action (returning a promise)', () => {
const data = { FOO: 'BAR' };
diff --git a/spec/frontend/__mocks__/@gitlab/ui.js b/spec/frontend/__mocks__/@gitlab/ui.js
index 4d893bcd0bd..c51f37db384 100644
--- a/spec/frontend/__mocks__/@gitlab/ui.js
+++ b/spec/frontend/__mocks__/@gitlab/ui.js
@@ -13,13 +13,18 @@ export * from '@gitlab/ui';
* are imported internally in `@gitlab/ui`.
*/
-jest.mock('@gitlab/ui/dist/directives/tooltip.js', () => ({
+/* eslint-disable global-require */
+
+jest.mock('@gitlab/ui/src/directives/tooltip.js', () => ({
GlTooltipDirective: {
bind() {},
},
}));
+jest.mock('@gitlab/ui/dist/directives/tooltip.js', () =>
+ require('@gitlab/ui/src/directives/tooltip'),
+);
-jest.mock('@gitlab/ui/dist/components/base/tooltip/tooltip.js', () => ({
+jest.mock('@gitlab/ui/src/components/base/tooltip/tooltip.vue', () => ({
props: ['target', 'id', 'triggers', 'placement', 'container', 'boundary', 'disabled', 'show'],
render(h) {
return h(
@@ -33,7 +38,11 @@ jest.mock('@gitlab/ui/dist/components/base/tooltip/tooltip.js', () => ({
},
}));
-jest.mock('@gitlab/ui/dist/components/base/popover/popover.js', () => ({
+jest.mock('@gitlab/ui/dist/components/base/tooltip/tooltip.js', () =>
+ require('@gitlab/ui/src/components/base/tooltip/tooltip.vue'),
+);
+
+jest.mock('@gitlab/ui/src/components/base/popover/popover.vue', () => ({
props: {
cssClasses: {
type: Array,
@@ -65,3 +74,6 @@ jest.mock('@gitlab/ui/dist/components/base/popover/popover.js', () => ({
);
},
}));
+jest.mock('@gitlab/ui/dist/components/base/popover/popover.js', () =>
+ require('@gitlab/ui/src/components/base/popover/popover.vue'),
+);
diff --git a/spec/frontend/__mocks__/lodash/debounce.js b/spec/frontend/__mocks__/lodash/debounce.js
index d4fe2ce5406..15f806fc31a 100644
--- a/spec/frontend/__mocks__/lodash/debounce.js
+++ b/spec/frontend/__mocks__/lodash/debounce.js
@@ -9,9 +9,22 @@
// Further reference: https://github.com/facebook/jest/issues/3465
export default (fn) => {
- const debouncedFn = jest.fn().mockImplementation(fn);
- debouncedFn.cancel = jest.fn();
- debouncedFn.flush = jest.fn().mockImplementation(() => {
+ let id;
+ const debouncedFn = jest.fn(function run(...args) {
+ // this is calculated in runtime so beforeAll hook works in tests
+ const timeout = global.JEST_DEBOUNCE_THROTTLE_TIMEOUT;
+ if (timeout) {
+ id = setTimeout(() => {
+ fn.apply(this, args);
+ }, timeout);
+ } else {
+ fn.apply(this, args);
+ }
+ });
+ debouncedFn.cancel = jest.fn(() => {
+ clearTimeout(id);
+ });
+ debouncedFn.flush = jest.fn(() => {
const errorMessage =
"The .flush() method returned by lodash.debounce is not yet implemented/mocked by the mock in 'spec/frontend/__mocks__/lodash/debounce.js'.";
diff --git a/spec/frontend/__mocks__/lodash/throttle.js b/spec/frontend/__mocks__/lodash/throttle.js
index e8a82654c78..b1014662918 100644
--- a/spec/frontend/__mocks__/lodash/throttle.js
+++ b/spec/frontend/__mocks__/lodash/throttle.js
@@ -1,4 +1,4 @@
// Similar to `lodash/debounce`, `lodash/throttle` also causes flaky specs.
// See `./debounce.js` for more details.
-export default (fn) => fn;
+export { default } from './debounce';
diff --git a/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js b/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
index ec20088c443..5de5f495f01 100644
--- a/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
+++ b/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
@@ -33,10 +33,6 @@ describe('AbuseCategorySelector', () => {
createComponent({ showDrawer: true });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDrawer = () => wrapper.findComponent(GlDrawer);
const findTitle = () => wrapper.findByTestId('category-drawer-title');
diff --git a/spec/frontend/access_tokens/components/expires_at_field_spec.js b/spec/frontend/access_tokens/components/expires_at_field_spec.js
index 491d2a0e323..6605faadc17 100644
--- a/spec/frontend/access_tokens/components/expires_at_field_spec.js
+++ b/spec/frontend/access_tokens/components/expires_at_field_spec.js
@@ -25,10 +25,6 @@ describe('~/access_tokens/components/expires_at_field', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render datepicker with input info', () => {
createComponent();
diff --git a/spec/frontend/access_tokens/components/new_access_token_app_spec.js b/spec/frontend/access_tokens/components/new_access_token_app_spec.js
index e4313bdfa26..fb92cc34ce9 100644
--- a/spec/frontend/access_tokens/components/new_access_token_app_spec.js
+++ b/spec/frontend/access_tokens/components/new_access_token_app_spec.js
@@ -4,12 +4,12 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import NewAccessTokenApp from '~/access_tokens/components/new_access_token_app.vue';
import { EVENT_ERROR, EVENT_SUCCESS, FORM_SELECTOR } from '~/access_tokens/components/constants';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { __, sprintf } from '~/locale';
import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('~/access_tokens/components/new_access_token_app', () => {
let wrapper;
@@ -52,7 +52,6 @@ describe('~/access_tokens/components/new_access_token_app', () => {
afterEach(() => {
resetHTMLFixture();
- wrapper.destroy();
createAlert.mockClear();
});
diff --git a/spec/frontend/access_tokens/components/token_spec.js b/spec/frontend/access_tokens/components/token_spec.js
index 1af21aaa8cd..f62f7d72e3b 100644
--- a/spec/frontend/access_tokens/components/token_spec.js
+++ b/spec/frontend/access_tokens/components/token_spec.js
@@ -23,10 +23,6 @@ describe('Token', () => {
wrapper = mountExtended(Token, { propsData: defaultPropsData, slots: defaultSlots });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders title slot', () => {
createComponent();
diff --git a/spec/frontend/access_tokens/components/tokens_app_spec.js b/spec/frontend/access_tokens/components/tokens_app_spec.js
index d7acfbb47eb..6e7dee6a2cc 100644
--- a/spec/frontend/access_tokens/components/tokens_app_spec.js
+++ b/spec/frontend/access_tokens/components/tokens_app_spec.js
@@ -54,10 +54,6 @@ describe('TokensApp', () => {
expect(container.props()).toMatchObject(expectedProps);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders all enabled tokens', () => {
createComponent();
diff --git a/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js b/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js
index 1d57473943b..5e96da9af7e 100644
--- a/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js
+++ b/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js
@@ -55,10 +55,6 @@ describe('AddContextCommitsModal', () => {
wrapper = createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders modal with 2 tabs', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js b/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js
index f679576182f..975f115c4bb 100644
--- a/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js
+++ b/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js
@@ -26,10 +26,6 @@ describe('ReviewTabContainer', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows loading icon when commits are being loaded', () => {
createWrapper({ isLoading: true });
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
diff --git a/spec/frontend/add_context_commits_modal/store/actions_spec.js b/spec/frontend/add_context_commits_modal/store/actions_spec.js
index 27c8d760a96..3863eee3795 100644
--- a/spec/frontend/add_context_commits_modal/store/actions_spec.js
+++ b/spec/frontend/add_context_commits_modal/store/actions_spec.js
@@ -31,10 +31,10 @@ describe('AddContextCommitsModalStoreActions', () => {
short_id: 'abcdef',
committed_date: '2020-06-12',
};
- gon.api_version = 'v4';
let mock;
beforeEach(() => {
+ gon.api_version = 'v4';
mock = new MockAdapter(axios);
});
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
new file mode 100644
index 00000000000..d32fa25d238
--- /dev/null
+++ b/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js
@@ -0,0 +1,43 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import AbuseReportRow from '~/admin/abuse_reports/components/abuse_report_row.vue';
+import ListItem from '~/vue_shared/components/registry/list_item.vue';
+import { getTimeago } from '~/lib/utils/datetime_utility';
+import { mockAbuseReports } from '../mock_data';
+
+describe('AbuseReportRow', () => {
+ let wrapper;
+ const mockAbuseReport = mockAbuseReports[0];
+
+ const findListItem = () => wrapper.findComponent(ListItem);
+ const findTitle = () => wrapper.findByTestId('title');
+ const findUpdatedAt = () => wrapper.findByTestId('updated-at');
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(AbuseReportRow, {
+ propsData: {
+ report: mockAbuseReport,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders a ListItem', () => {
+ expect(findListItem().exists()).toBe(true);
+ });
+
+ it('displays correctly formatted title', () => {
+ const { reporter, reportedUser, category } = mockAbuseReport;
+ expect(findTitle().text()).toMatchInterpolatedText(
+ `${reportedUser.name} reported for ${category} by ${reporter.name}`,
+ );
+ });
+
+ it('displays correctly formatted updated at', () => {
+ expect(findUpdatedAt().text()).toMatchInterpolatedText(
+ `Updated ${getTimeago().format(mockAbuseReport.updatedAt)}`,
+ );
+ });
+});
diff --git a/spec/frontend/admin/abuse_reports/components/abuse_reports_filtered_search_bar_spec.js b/spec/frontend/admin/abuse_reports/components/abuse_reports_filtered_search_bar_spec.js
new file mode 100644
index 00000000000..9efab8403a0
--- /dev/null
+++ b/spec/frontend/admin/abuse_reports/components/abuse_reports_filtered_search_bar_spec.js
@@ -0,0 +1,214 @@
+import { shallowMount } from '@vue/test-utils';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import { redirectTo, updateHistory } from '~/lib/utils/url_utility';
+import AbuseReportsFilteredSearchBar from '~/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue';
+import {
+ FILTERED_SEARCH_TOKENS,
+ FILTERED_SEARCH_TOKEN_USER,
+ FILTERED_SEARCH_TOKEN_REPORTER,
+ FILTERED_SEARCH_TOKEN_STATUS,
+ FILTERED_SEARCH_TOKEN_CATEGORY,
+ DEFAULT_SORT,
+ SORT_OPTIONS,
+} from '~/admin/abuse_reports/constants';
+import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
+import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
+import { buildFilteredSearchCategoryToken } from '~/admin/abuse_reports/utils';
+
+jest.mock('~/lib/utils/url_utility', () => {
+ const urlUtility = jest.requireActual('~/lib/utils/url_utility');
+
+ return {
+ __esModule: true,
+ ...urlUtility,
+ redirectTo: jest.fn(),
+ updateHistory: jest.fn(),
+ };
+});
+
+describe('AbuseReportsFilteredSearchBar', () => {
+ let wrapper;
+
+ const CATEGORIES = ['spam', 'phishing'];
+
+ const createComponent = () => {
+ wrapper = shallowMount(AbuseReportsFilteredSearchBar, {
+ provide: { categories: CATEGORIES },
+ });
+ };
+
+ const findFilteredSearchBar = () => wrapper.findComponent(FilteredSearchBar);
+
+ beforeEach(() => {
+ setWindowLocation('https://localhost');
+ });
+
+ it('passes correct props to `FilteredSearchBar` component', () => {
+ createComponent();
+
+ const categoryToken = buildFilteredSearchCategoryToken(CATEGORIES);
+
+ expect(findFilteredSearchBar().props()).toMatchObject({
+ namespace: 'abuse_reports',
+ recentSearchesStorageKey: 'abuse_reports',
+ searchInputPlaceholder: 'Filter reports',
+ tokens: [...FILTERED_SEARCH_TOKENS, categoryToken],
+ initialSortBy: DEFAULT_SORT,
+ sortOptions: SORT_OPTIONS,
+ });
+ });
+
+ it('sets status=open query when there is no initial status query', () => {
+ createComponent();
+
+ expect(updateHistory).toHaveBeenCalledWith({
+ url: 'https://localhost/?status=open',
+ replace: true,
+ });
+
+ expect(findFilteredSearchBar().props('initialFilterValue')).toMatchObject([
+ {
+ type: FILTERED_SEARCH_TOKEN_STATUS.type,
+ value: { data: 'open', operator: '=' },
+ },
+ ]);
+ });
+
+ it('parses and passes search param to `FilteredSearchBar` component as `initialFilterValue` prop', () => {
+ setWindowLocation('?status=closed&user=mr_abuser&reporter=ms_nitch');
+
+ createComponent();
+
+ expect(findFilteredSearchBar().props('initialFilterValue')).toMatchObject([
+ {
+ type: FILTERED_SEARCH_TOKEN_USER.type,
+ value: { data: 'mr_abuser', operator: '=' },
+ },
+ {
+ type: FILTERED_SEARCH_TOKEN_REPORTER.type,
+ value: { data: 'ms_nitch', operator: '=' },
+ },
+ {
+ type: FILTERED_SEARCH_TOKEN_STATUS.type,
+ value: { data: 'closed', operator: '=' },
+ },
+ ]);
+ });
+
+ describe('initial sort', () => {
+ it.each(
+ SORT_OPTIONS.flatMap(({ sortDirection: { descending, ascending } }) => [
+ descending,
+ ascending,
+ ]),
+ )(
+ 'parses sort=%s query and passes it to `FilteredSearchBar` component as initialSortBy',
+ (sortBy) => {
+ setWindowLocation(`?sort=${sortBy}`);
+
+ createComponent();
+
+ expect(findFilteredSearchBar().props('initialSortBy')).toEqual(sortBy);
+ },
+ );
+
+ it(`uses ${DEFAULT_SORT} as initialSortBy when sort query param is invalid`, () => {
+ setWindowLocation(`?sort=unknown`);
+
+ createComponent();
+
+ expect(findFilteredSearchBar().props('initialSortBy')).toEqual(DEFAULT_SORT);
+ });
+ });
+
+ describe('onFilter', () => {
+ const USER_FILTER_TOKEN = {
+ type: FILTERED_SEARCH_TOKEN_USER.type,
+ value: { data: 'mr_abuser', operator: '=' },
+ };
+ const REPORTER_FILTER_TOKEN = {
+ type: FILTERED_SEARCH_TOKEN_REPORTER.type,
+ value: { data: 'ms_nitch', operator: '=' },
+ };
+ const STATUS_FILTER_TOKEN = {
+ type: FILTERED_SEARCH_TOKEN_STATUS.type,
+ value: { data: 'open', operator: '=' },
+ };
+ const CATEGORY_FILTER_TOKEN = {
+ type: FILTERED_SEARCH_TOKEN_CATEGORY.type,
+ value: { data: 'spam', operator: '=' },
+ };
+
+ const createComponentAndFilter = (filterTokens, initialLocation) => {
+ if (initialLocation) {
+ setWindowLocation(initialLocation);
+ }
+
+ createComponent();
+
+ findFilteredSearchBar().vm.$emit('onFilter', filterTokens);
+ };
+
+ it.each([USER_FILTER_TOKEN, REPORTER_FILTER_TOKEN, STATUS_FILTER_TOKEN, CATEGORY_FILTER_TOKEN])(
+ 'redirects with $type query param',
+ (filterToken) => {
+ createComponentAndFilter([filterToken]);
+ const { type, value } = filterToken;
+ expect(redirectTo).toHaveBeenCalledWith(`https://localhost/?${type}=${value.data}`);
+ },
+ );
+
+ it('ignores search query param', () => {
+ const searchFilterToken = { type: FILTERED_SEARCH_TERM, value: { data: 'ignored' } };
+ createComponentAndFilter([USER_FILTER_TOKEN, searchFilterToken]);
+ expect(redirectTo).toHaveBeenCalledWith('https://localhost/?user=mr_abuser');
+ });
+
+ it('redirects without page query param', () => {
+ createComponentAndFilter([USER_FILTER_TOKEN], '?page=2');
+ expect(redirectTo).toHaveBeenCalledWith('https://localhost/?user=mr_abuser');
+ });
+
+ it('redirects with existing sort query param', () => {
+ createComponentAndFilter([USER_FILTER_TOKEN], `?sort=${DEFAULT_SORT}`);
+ expect(redirectTo).toHaveBeenCalledWith(
+ `https://localhost/?user=mr_abuser&sort=${DEFAULT_SORT}`,
+ );
+ });
+ });
+
+ describe('onSort', () => {
+ const SORT_VALUE = 'updated_at_asc';
+ const EXISTING_QUERY = 'status=closed&user=mr_abuser';
+
+ const createComponentAndSort = (initialLocation) => {
+ setWindowLocation(initialLocation);
+ createComponent();
+ findFilteredSearchBar().vm.$emit('onSort', SORT_VALUE);
+ };
+
+ it('redirects to URL with existing query params and the sort query param', () => {
+ createComponentAndSort(`?${EXISTING_QUERY}`);
+
+ expect(redirectTo).toHaveBeenCalledWith(
+ `https://localhost/?${EXISTING_QUERY}&sort=${SORT_VALUE}`,
+ );
+ });
+
+ it('redirects without page query param', () => {
+ createComponentAndSort(`?${EXISTING_QUERY}&page=2`);
+
+ expect(redirectTo).toHaveBeenCalledWith(
+ `https://localhost/?${EXISTING_QUERY}&sort=${SORT_VALUE}`,
+ );
+ });
+
+ it('redirects with existing sort query param replaced with the new one', () => {
+ createComponentAndSort(`?${EXISTING_QUERY}&sort=created_at_desc`);
+
+ expect(redirectTo).toHaveBeenCalledWith(
+ `https://localhost/?${EXISTING_QUERY}&sort=${SORT_VALUE}`,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/admin/abuse_reports/components/app_spec.js b/spec/frontend/admin/abuse_reports/components/app_spec.js
new file mode 100644
index 00000000000..41728baaf33
--- /dev/null
+++ b/spec/frontend/admin/abuse_reports/components/app_spec.js
@@ -0,0 +1,104 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlEmptyState, GlPagination } from '@gitlab/ui';
+import { queryToObject, objectToQuery } from '~/lib/utils/url_utility';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import AbuseReportsApp from '~/admin/abuse_reports/components/app.vue';
+import AbuseReportsFilteredSearchBar from '~/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue';
+import AbuseReportRow from '~/admin/abuse_reports/components/abuse_report_row.vue';
+import { mockAbuseReports } from '../mock_data';
+
+describe('AbuseReportsApp', () => {
+ let wrapper;
+
+ const findFilteredSearchBar = () => wrapper.findComponent(AbuseReportsFilteredSearchBar);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findAbuseReportRows = () => wrapper.findAllComponents(AbuseReportRow);
+ const findPagination = () => wrapper.findComponent(GlPagination);
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(AbuseReportsApp, {
+ propsData: {
+ abuseReports: mockAbuseReports,
+ pagination: { currentPage: 1, perPage: 20, totalItems: mockAbuseReports.length },
+ ...props,
+ },
+ });
+ };
+
+ it('renders AbuseReportsFilteredSearchBar', () => {
+ createComponent();
+
+ expect(findFilteredSearchBar().exists()).toBe(true);
+ });
+
+ it('renders one AbuseReportRow for each abuse report', () => {
+ createComponent();
+
+ expect(findEmptyState().exists()).toBe(false);
+ expect(findAbuseReportRows().length).toBe(mockAbuseReports.length);
+ });
+
+ it('renders empty state when there are no reports', () => {
+ createComponent({
+ abuseReports: [],
+ pagination: { currentPage: 1, perPage: 20, totalItems: 0 },
+ });
+
+ expect(findEmptyState().exists()).toBe(true);
+ });
+
+ describe('pagination', () => {
+ const pagination = {
+ currentPage: 1,
+ perPage: 1,
+ totalItems: mockAbuseReports.length,
+ };
+
+ it('renders GlPagination with the correct props when needed', () => {
+ createComponent({ pagination });
+
+ expect(findPagination().exists()).toBe(true);
+ expect(findPagination().props()).toMatchObject({
+ value: pagination.currentPage,
+ perPage: pagination.perPage,
+ totalItems: pagination.totalItems,
+ prevText: 'Prev',
+ nextText: 'Next',
+ labelNextPage: 'Go to next page',
+ labelPrevPage: 'Go to previous page',
+ align: 'center',
+ });
+ });
+
+ it('does not render GlPagination when not needed', () => {
+ createComponent({ pagination: { currentPage: 1, perPage: 2, totalItems: 2 } });
+
+ expect(findPagination().exists()).toBe(false);
+ });
+
+ describe('linkGen prop', () => {
+ const existingQuery = {
+ user: 'mr_okay',
+ status: 'closed',
+ };
+ const expectedGeneratedQuery = {
+ ...existingQuery,
+ page: '2',
+ };
+
+ beforeEach(() => {
+ setWindowLocation(`https://localhost?${objectToQuery(existingQuery)}`);
+ });
+
+ it('generates the correct page URL', () => {
+ createComponent({ pagination });
+
+ const linkGen = findPagination().props('linkGen');
+ const generatedUrl = linkGen(expectedGeneratedQuery.page);
+ const [, generatedQuery] = generatedUrl.split('?');
+
+ expect(queryToObject(generatedQuery)).toMatchObject(expectedGeneratedQuery);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/abuse_reports/mock_data.js b/spec/frontend/admin/abuse_reports/mock_data.js
new file mode 100644
index 00000000000..778f055eb82
--- /dev/null
+++ b/spec/frontend/admin/abuse_reports/mock_data.js
@@ -0,0 +1,14 @@
+export const mockAbuseReports = [
+ {
+ category: 'spam',
+ updatedAt: '2022-12-07T06:45:39.977Z',
+ reporter: { name: 'Ms. Admin' },
+ reportedUser: { name: 'Mr. Abuser' },
+ },
+ {
+ category: 'phishing',
+ updatedAt: '2022-12-07T06:45:39.977Z',
+ reporter: { name: 'Ms. Reporter' },
+ reportedUser: { name: 'Mr. Phisher' },
+ },
+];
diff --git a/spec/frontend/admin/abuse_reports/utils_spec.js b/spec/frontend/admin/abuse_reports/utils_spec.js
new file mode 100644
index 00000000000..17f0b9acb26
--- /dev/null
+++ b/spec/frontend/admin/abuse_reports/utils_spec.js
@@ -0,0 +1,13 @@
+import { FILTERED_SEARCH_TOKEN_CATEGORY } from '~/admin/abuse_reports/constants';
+import { buildFilteredSearchCategoryToken } from '~/admin/abuse_reports/utils';
+
+describe('buildFilteredSearchCategoryToken', () => {
+ it('adds correctly formatted options to FILTERED_SEARCH_TOKEN_CATEGORY', () => {
+ const categories = ['tuxedo', 'tabby'];
+
+ expect(buildFilteredSearchCategoryToken(categories)).toMatchObject({
+ ...FILTERED_SEARCH_TOKEN_CATEGORY,
+ options: categories.map((c) => ({ value: c, title: c })),
+ });
+ });
+});
diff --git a/spec/frontend/admin/analytics/devops_score/components/devops_score_callout_spec.js b/spec/frontend/admin/analytics/devops_score/components/devops_score_callout_spec.js
index c9a899ab78b..06f9ffeffcd 100644
--- a/spec/frontend/admin/analytics/devops_score/components/devops_score_callout_spec.js
+++ b/spec/frontend/admin/analytics/devops_score/components/devops_score_callout_spec.js
@@ -19,10 +19,6 @@ describe('DevopsScoreCallout', () => {
const findBanner = () => wrapper.findComponent(GlBanner);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with no cookie set', () => {
beforeEach(() => {
utils.setCookie = jest.fn();
diff --git a/spec/frontend/admin/application_settings/inactive_project_deletion/components/form_spec.js b/spec/frontend/admin/application_settings/inactive_project_deletion/components/form_spec.js
index 2db997942a7..969844f981c 100644
--- a/spec/frontend/admin/application_settings/inactive_project_deletion/components/form_spec.js
+++ b/spec/frontend/admin/application_settings/inactive_project_deletion/components/form_spec.js
@@ -29,10 +29,6 @@ describe('Form component', () => {
wrapper = mountFn(SettingsForm, { propsData });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Enable inactive project deletion', () => {
it('has the checkbox', () => {
createComponent();
diff --git a/spec/frontend/admin/application_settings/network_outbound_spec.js b/spec/frontend/admin/application_settings/network_outbound_spec.js
new file mode 100644
index 00000000000..2c06a3fd67f
--- /dev/null
+++ b/spec/frontend/admin/application_settings/network_outbound_spec.js
@@ -0,0 +1,70 @@
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+
+import initNetworkOutbound from '~/admin/application_settings/network_outbound';
+
+describe('initNetworkOutbound', () => {
+ const findAllowCheckboxes = () => document.querySelectorAll('.js-allow-local-requests');
+ const findDenyCheckbox = () => document.querySelector('.js-deny-all-requests');
+ const findWarningBanner = () => document.querySelector('.js-deny-all-requests-warning');
+ const clickDenyCheckbox = () => {
+ findDenyCheckbox().click();
+ };
+
+ const createFixture = (denyAll = false) => {
+ setHTMLFixture(`
+ <input class="js-deny-all-requests" type="checkbox" name="application_setting[deny_all_requests_except_allowed]" ${
+ denyAll ? 'checked="checked"' : ''
+ }/>
+ <div class="js-deny-all-requests-warning ${denyAll ? '' : 'gl-display-none'}"></div>
+ <input class="js-allow-local-requests" type="checkbox" name="application_setting[allow_local_requests_from_web_hooks_and_services]" />
+ <input class="js-allow-local-requests" type="checkbox" name="application_setting[allow_local_requests_from_system_hooks]" />
+ `);
+ };
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ describe('when the checkbox is not checked', () => {
+ beforeEach(() => {
+ createFixture();
+ initNetworkOutbound();
+ });
+
+ it('shows banner and disables allow checkboxes on change', () => {
+ expect(findDenyCheckbox().checked).toBe(false);
+ expect(findWarningBanner().classList).toContain('gl-display-none');
+
+ clickDenyCheckbox();
+
+ expect(findDenyCheckbox().checked).toBe(true);
+ expect(findWarningBanner().classList).not.toContain('gl-display-none');
+ const allowCheckboxes = findAllowCheckboxes();
+ allowCheckboxes.forEach((checkbox) => {
+ expect(checkbox.checked).toBe(false);
+ expect(checkbox.disabled).toBe(true);
+ });
+ });
+ });
+
+ describe('when the checkbox is checked', () => {
+ beforeEach(() => {
+ createFixture(true);
+ initNetworkOutbound();
+ });
+
+ it('hides banner and enables allow checkboxes on change', () => {
+ expect(findDenyCheckbox().checked).toBe(true);
+ expect(findWarningBanner().classList).not.toContain('gl-display-none');
+
+ clickDenyCheckbox();
+
+ expect(findDenyCheckbox().checked).toBe(false);
+ expect(findWarningBanner().classList).toContain('gl-display-none');
+ const allowCheckboxes = findAllowCheckboxes();
+ allowCheckboxes.forEach((checkbox) => {
+ expect(checkbox.disabled).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/applications/components/delete_application_spec.js b/spec/frontend/admin/applications/components/delete_application_spec.js
index 1a400a101b5..315c38a2bbc 100644
--- a/spec/frontend/admin/applications/components/delete_application_spec.js
+++ b/spec/frontend/admin/applications/components/delete_application_spec.js
@@ -31,7 +31,6 @@ describe('DeleteApplication', () => {
});
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/admin/background_migrations/components/database_listbox_spec.js b/spec/frontend/admin/background_migrations/components/database_listbox_spec.js
index 212f4c0842c..d7b319a3d5e 100644
--- a/spec/frontend/admin/background_migrations/components/database_listbox_spec.js
+++ b/spec/frontend/admin/background_migrations/components/database_listbox_spec.js
@@ -26,10 +26,6 @@ describe('BackgroundMigrationsDatabaseListbox', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlCollapsibleListbox = () => wrapper.findComponent(GlCollapsibleListbox);
describe('template always', () => {
diff --git a/spec/frontend/admin/broadcast_messages/components/base_spec.js b/spec/frontend/admin/broadcast_messages/components/base_spec.js
index d69bf4a22bf..50d8eeb563d 100644
--- a/spec/frontend/admin/broadcast_messages/components/base_spec.js
+++ b/spec/frontend/admin/broadcast_messages/components/base_spec.js
@@ -4,7 +4,7 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
-import { createAlert } from '~/flash';
+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 { redirectTo } from '~/lib/utils/url_utility';
@@ -12,7 +12,7 @@ import BroadcastMessagesBase from '~/admin/broadcast_messages/components/base.vu
import MessagesTable from '~/admin/broadcast_messages/components/messages_table.vue';
import { generateMockMessages, MOCK_MESSAGES } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
describe('BroadcastMessagesBase', () => {
@@ -41,7 +41,6 @@ describe('BroadcastMessagesBase', () => {
afterEach(() => {
axiosMock.restore();
- wrapper.destroy();
});
it('renders the table and pagination when there are existing messages', () => {
diff --git a/spec/frontend/admin/broadcast_messages/components/message_form_spec.js b/spec/frontend/admin/broadcast_messages/components/message_form_spec.js
index 36c0ac303ba..292575c984b 100644
--- a/spec/frontend/admin/broadcast_messages/components/message_form_spec.js
+++ b/spec/frontend/admin/broadcast_messages/components/message_form_spec.js
@@ -1,7 +1,7 @@
import { mount } from '@vue/test-utils';
import { GlBroadcastMessage, GlForm } from '@gitlab/ui';
import AxiosMockAdapter from 'axios-mock-adapter';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST } from '~/lib/utils/http_status';
import MessageForm from '~/admin/broadcast_messages/components/message_form.vue';
@@ -15,7 +15,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { MOCK_TARGET_ACCESS_LEVELS } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('MessageForm', () => {
let wrapper;
diff --git a/spec/frontend/admin/broadcast_messages/components/messages_table_spec.js b/spec/frontend/admin/broadcast_messages/components/messages_table_spec.js
index 349fab03853..432bfefeb18 100644
--- a/spec/frontend/admin/broadcast_messages/components/messages_table_spec.js
+++ b/spec/frontend/admin/broadcast_messages/components/messages_table_spec.js
@@ -21,10 +21,6 @@ describe('MessagesTable', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a table row for each message', () => {
createComponent();
diff --git a/spec/frontend/admin/deploy_keys/components/table_spec.js b/spec/frontend/admin/deploy_keys/components/table_spec.js
index 4d4a2caedde..a05654a1d25 100644
--- a/spec/frontend/admin/deploy_keys/components/table_spec.js
+++ b/spec/frontend/admin/deploy_keys/components/table_spec.js
@@ -9,10 +9,10 @@ import { stubComponent } from 'helpers/stub_component';
import DeployKeysTable from '~/admin/deploy_keys/components/table.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import Api, { DEFAULT_PER_PAGE } from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
jest.mock('~/api');
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
describe('DeployKeysTable', () => {
@@ -91,10 +91,6 @@ describe('DeployKeysTable', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders page title', () => {
createComponent();
@@ -242,7 +238,7 @@ describe('DeployKeysTable', () => {
itRendersTheEmptyState();
- it('displays flash', () => {
+ it('displays alert', () => {
expect(createAlert).toHaveBeenCalledWith({
message: DeployKeysTable.i18n.apiErrorMessage,
captureError: true,
diff --git a/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js b/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js
index eecc21e206b..9e55716cc30 100644
--- a/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js
+++ b/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js
@@ -28,10 +28,6 @@ describe('Signup Form', () => {
const findCheckboxLabel = () => findByTestId('label');
const findHelpText = () => findByTestId('helpText');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Signup Checkbox', () => {
beforeEach(() => {
mountComponent();
diff --git a/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
index f2a951bcc76..9192fc12401 100644
--- a/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
+++ b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
@@ -40,8 +40,6 @@ describe('Signup Form', () => {
const findModal = () => wrapper.findComponent(GlModal);
afterEach(() => {
- wrapper.destroy();
-
formSubmitSpy = null;
});
diff --git a/spec/frontend/admin/statistics_panel/components/app_spec.js b/spec/frontend/admin/statistics_panel/components/app_spec.js
index 4c362a31068..60e46cddd7e 100644
--- a/spec/frontend/admin/statistics_panel/components/app_spec.js
+++ b/spec/frontend/admin/statistics_panel/components/app_spec.js
@@ -30,10 +30,6 @@ describe('Admin statistics app', () => {
store = createStore();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findStats = (idx) => wrapper.findAll('.js-stats').at(idx);
describe('template', () => {
diff --git a/spec/frontend/admin/topics/components/remove_avatar_spec.js b/spec/frontend/admin/topics/components/remove_avatar_spec.js
index 97d257c682c..c069203d046 100644
--- a/spec/frontend/admin/topics/components/remove_avatar_spec.js
+++ b/spec/frontend/admin/topics/components/remove_avatar_spec.js
@@ -20,7 +20,7 @@ describe('RemoveAvatar', () => {
name,
},
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
},
stubs: {
GlSprintf,
@@ -36,10 +36,6 @@ describe('RemoveAvatar', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('the button component', () => {
it('displays the remove button', () => {
const button = findButton();
diff --git a/spec/frontend/admin/topics/components/topic_select_spec.js b/spec/frontend/admin/topics/components/topic_select_spec.js
index 738cbd88c4c..113a0e3d404 100644
--- a/spec/frontend/admin/topics/components/topic_select_spec.js
+++ b/spec/frontend/admin/topics/components/topic_select_spec.js
@@ -59,7 +59,6 @@ describe('TopicSelect', () => {
}
afterEach(() => {
- wrapper.destroy();
jest.clearAllMocks();
});
diff --git a/spec/frontend/admin/users/components/actions/actions_spec.js b/spec/frontend/admin/users/components/actions/actions_spec.js
index 8e9652332c1..4aeaa5356b4 100644
--- a/spec/frontend/admin/users/components/actions/actions_spec.js
+++ b/spec/frontend/admin/users/components/actions/actions_spec.js
@@ -22,11 +22,6 @@ describe('Action components', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('CONFIRMATION_ACTIONS', () => {
it.each(CONFIRMATION_ACTIONS)('renders a dropdown item for "%s"', (action) => {
initComponent({
diff --git a/spec/frontend/admin/users/components/app_spec.js b/spec/frontend/admin/users/components/app_spec.js
index 913732aae42..d40089edc82 100644
--- a/spec/frontend/admin/users/components/app_spec.js
+++ b/spec/frontend/admin/users/components/app_spec.js
@@ -17,11 +17,6 @@ describe('AdminUsersApp component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when initialized', () => {
beforeEach(() => {
initComponent();
diff --git a/spec/frontend/admin/users/components/modals/delete_user_modal_spec.js b/spec/frontend/admin/users/components/modals/delete_user_modal_spec.js
index 2e892e292d7..efb951f4ad2 100644
--- a/spec/frontend/admin/users/components/modals/delete_user_modal_spec.js
+++ b/spec/frontend/admin/users/components/modals/delete_user_modal_spec.js
@@ -73,11 +73,6 @@ describe('Delete user modal', () => {
formSubmitSpy = jest.spyOn(HTMLFormElement.prototype, 'submit').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders modal with form included', () => {
createComponent();
expect(findForm().element).toMatchSnapshot();
diff --git a/spec/frontend/admin/users/components/user_actions_spec.js b/spec/frontend/admin/users/components/user_actions_spec.js
index 1b080b05c95..1a2cc3e5c34 100644
--- a/spec/frontend/admin/users/components/user_actions_spec.js
+++ b/spec/frontend/admin/users/components/user_actions_spec.js
@@ -32,16 +32,11 @@ describe('AdminUserActions component', () => {
showButtonLabels,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('edit button', () => {
describe('when the user has an edit action attached', () => {
beforeEach(() => {
diff --git a/spec/frontend/admin/users/components/user_avatar_spec.js b/spec/frontend/admin/users/components/user_avatar_spec.js
index 94fac875fbe..02e648d2b77 100644
--- a/spec/frontend/admin/users/components/user_avatar_spec.js
+++ b/spec/frontend/admin/users/components/user_avatar_spec.js
@@ -26,7 +26,7 @@ describe('AdminUserAvatar component', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
stubs: {
GlAvatarLabeled,
@@ -34,11 +34,6 @@ describe('AdminUserAvatar component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when initialized', () => {
beforeEach(() => {
initComponent();
diff --git a/spec/frontend/admin/users/components/user_date_spec.js b/spec/frontend/admin/users/components/user_date_spec.js
index 73be33d5a9d..19c1cd38a50 100644
--- a/spec/frontend/admin/users/components/user_date_spec.js
+++ b/spec/frontend/admin/users/components/user_date_spec.js
@@ -17,11 +17,6 @@ describe('FormatDate component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it.each`
date | dateFormat | output
${mockDate} | ${undefined} | ${'Nov 13, 2020'}
diff --git a/spec/frontend/admin/users/components/users_table_spec.js b/spec/frontend/admin/users/components/users_table_spec.js
index a0aec347b6b..6f658fd2e59 100644
--- a/spec/frontend/admin/users/components/users_table_spec.js
+++ b/spec/frontend/admin/users/components/users_table_spec.js
@@ -10,12 +10,12 @@ import AdminUserActions from '~/admin/users/components/user_actions.vue';
import AdminUserAvatar from '~/admin/users/components/user_avatar.vue';
import AdminUsersTable from '~/admin/users/components/users_table.vue';
import getUsersGroupCountsQuery from '~/admin/users/graphql/queries/get_users_group_counts.query.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import AdminUserDate from '~/vue_shared/components/user_date.vue';
import { users, paths, createGroupCountResponse } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -57,11 +57,6 @@ describe('AdminUsersTable component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when there are users', () => {
beforeEach(() => {
initComponent();
@@ -134,7 +129,7 @@ describe('AdminUsersTable component', () => {
await waitForPromises();
});
- it('creates a flash message and captures the error', () => {
+ it('creates an alert message and captures the error', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'Could not load user group counts. Please refresh the page to try again.',
captureError: true,
diff --git a/spec/frontend/admin/users/index_spec.js b/spec/frontend/admin/users/index_spec.js
index b51858d5129..d8a94ee5e1d 100644
--- a/spec/frontend/admin/users/index_spec.js
+++ b/spec/frontend/admin/users/index_spec.js
@@ -19,8 +19,6 @@ describe('initAdminUsersApp', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
el = null;
});
@@ -47,8 +45,6 @@ describe('initAdminUserActions', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
el = null;
});
diff --git a/spec/frontend/airflow/dags/components/dags_spec.js b/spec/frontend/airflow/dags/components/dags_spec.js
deleted file mode 100644
index f9cf4fc87af..00000000000
--- a/spec/frontend/airflow/dags/components/dags_spec.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import { GlAlert, GlPagination, GlTableLite } from '@gitlab/ui';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { TEST_HOST } from 'helpers/test_constants';
-import AirflowDags from '~/airflow/dags/components/dags.vue';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import { mockDags } from './mock_data';
-
-describe('AirflowDags', () => {
- let wrapper;
-
- const createWrapper = (
- dags = [],
- pagination = { page: 1, isLastPage: false, per_page: 2, totalItems: 0 },
- ) => {
- wrapper = mountExtended(AirflowDags, {
- propsData: {
- dags,
- pagination,
- },
- });
- };
-
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findEmptyState = () => wrapper.findByText('There are no DAGs to show');
- const findPagination = () => wrapper.findComponent(GlPagination);
-
- describe('default (no dags)', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('shows incubation warning', () => {
- expect(findAlert().exists()).toBe(true);
- });
-
- it('shows empty state', () => {
- expect(findEmptyState().exists()).toBe(true);
- });
-
- it('does not show pagination', () => {
- expect(findPagination().exists()).toBe(false);
- });
- });
-
- describe('with dags', () => {
- const createWrapperWithDags = (pagination = {}) => {
- createWrapper(mockDags, {
- page: 1,
- isLastPage: false,
- per_page: 2,
- totalItems: 5,
- ...pagination,
- });
- };
-
- const findDagsData = () => {
- return wrapper
- .findComponent(GlTableLite)
- .findAll('tbody tr')
- .wrappers.map((tr) => {
- return tr.findAll('td').wrappers.map((td) => {
- const timeAgo = td.findComponent(TimeAgo);
-
- if (timeAgo.exists()) {
- return {
- type: 'time',
- value: timeAgo.props('time'),
- };
- }
-
- return {
- type: 'text',
- value: td.text(),
- };
- });
- });
- };
-
- it('renders the table of Dags with data', () => {
- createWrapperWithDags();
-
- expect(findDagsData()).toEqual(
- mockDags.map((x) => [
- { type: 'text', value: x.dag_name },
- { type: 'text', value: x.schedule },
- { type: 'time', value: x.next_run },
- { type: 'text', value: String(x.is_active) },
- { type: 'text', value: String(x.is_paused) },
- { type: 'text', value: x.fileloc },
- ]),
- );
- });
-
- describe('Pagination behaviour', () => {
- it.each`
- pagination | expected
- ${{}} | ${{ value: 1, prevPage: null, nextPage: 2 }}
- ${{ page: 2 }} | ${{ value: 2, prevPage: 1, nextPage: 3 }}
- ${{ isLastPage: true, page: 2 }} | ${{ value: 2, prevPage: 1, nextPage: null }}
- `('with $pagination, sets pagination props', ({ pagination, expected }) => {
- createWrapperWithDags({ ...pagination });
-
- expect(findPagination().props()).toMatchObject(expected);
- });
-
- it('generates link for each page', () => {
- createWrapperWithDags();
-
- const generateLink = findPagination().props('linkGen');
-
- expect(generateLink(3)).toBe(`${TEST_HOST}/?page=3`);
- });
- });
- });
-});
diff --git a/spec/frontend/airflow/dags/components/mock_data.js b/spec/frontend/airflow/dags/components/mock_data.js
deleted file mode 100644
index 9547282517d..00000000000
--- a/spec/frontend/airflow/dags/components/mock_data.js
+++ /dev/null
@@ -1,67 +0,0 @@
-export const mockDags = [
- {
- id: 1,
- project_id: 7,
- created_at: '2023-01-05T14:07:02.975Z',
- updated_at: '2023-01-05T14:07:02.975Z',
- has_import_errors: false,
- is_active: false,
- is_paused: true,
- next_run: '2023-01-05T14:07:02.975Z',
- dag_name: 'Dag number 1',
- schedule: 'Manual',
- fileloc: '/opt/dag.py',
- },
- {
- id: 2,
- project_id: 7,
- created_at: '2023-01-05T14:07:02.975Z',
- updated_at: '2023-01-05T14:07:02.975Z',
- has_import_errors: false,
- is_active: false,
- is_paused: true,
- next_run: '2023-01-05T14:07:02.975Z',
- dag_name: 'Dag number 2',
- schedule: 'Manual',
- fileloc: '/opt/dag.py',
- },
- {
- id: 3,
- project_id: 7,
- created_at: '2023-01-05T14:07:02.975Z',
- updated_at: '2023-01-05T14:07:02.975Z',
- has_import_errors: false,
- is_active: false,
- is_paused: true,
- next_run: '2023-01-05T14:07:02.975Z',
- dag_name: 'Dag number 3',
- schedule: 'Manual',
- fileloc: '/opt/dag.py',
- },
- {
- id: 4,
- project_id: 7,
- created_at: '2023-01-05T14:07:02.975Z',
- updated_at: '2023-01-05T14:07:02.975Z',
- has_import_errors: false,
- is_active: false,
- is_paused: true,
- next_run: '2023-01-05T14:07:02.975Z',
- dag_name: 'Dag number 4',
- schedule: 'Manual',
- fileloc: '/opt/dag.py',
- },
- {
- id: 5,
- project_id: 7,
- created_at: '2023-01-05T14:07:02.975Z',
- updated_at: '2023-01-05T14:07:02.975Z',
- has_import_errors: false,
- is_active: false,
- is_paused: true,
- next_run: '2023-01-05T14:07:02.975Z',
- dag_name: 'Dag number 5',
- schedule: 'Manual',
- fileloc: '/opt/dag.py',
- },
-];
diff --git a/spec/frontend/alert_management/components/alert_management_table_spec.js b/spec/frontend/alert_management/components/alert_management_table_spec.js
index 7fb4f2d2463..3f709d8c9f5 100644
--- a/spec/frontend/alert_management/components/alert_management_table_spec.js
+++ b/spec/frontend/alert_management/components/alert_management_table_spec.js
@@ -68,7 +68,7 @@ describe('AlertManagementTable', () => {
},
stubs,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
}),
);
diff --git a/spec/frontend/alert_spec.js b/spec/frontend/alert_spec.js
new file mode 100644
index 00000000000..1ae8373016b
--- /dev/null
+++ b/spec/frontend/alert_spec.js
@@ -0,0 +1,276 @@
+import * as Sentry from '@sentry/browser';
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import { createAlert, VARIANT_WARNING } from '~/alert';
+
+jest.mock('@sentry/browser');
+
+describe('Flash', () => {
+ const findTextContent = (containerSelector = '.flash-container') =>
+ document.querySelector(containerSelector).textContent.replace(/\s+/g, ' ').trim();
+
+ describe('createAlert', () => {
+ const mockMessage = 'a message';
+ let alert;
+
+ describe('no flash-container', () => {
+ it('does not add to the DOM', () => {
+ alert = createAlert({ message: mockMessage });
+
+ expect(alert).toBeNull();
+ expect(document.querySelector('.gl-alert')).toBeNull();
+ });
+ });
+
+ describe('with flash-container', () => {
+ beforeEach(() => {
+ setHTMLFixture('<div class="flash-container"></div>');
+ });
+
+ afterEach(() => {
+ if (alert) {
+ alert.$destroy();
+ }
+ resetHTMLFixture();
+ });
+
+ it('adds alert element into the document by default', () => {
+ alert = createAlert({ message: mockMessage });
+
+ expect(findTextContent()).toBe(mockMessage);
+ expect(document.querySelector('.flash-container .gl-alert')).not.toBeNull();
+ });
+
+ it('adds flash of a warning type', () => {
+ alert = createAlert({ message: mockMessage, variant: VARIANT_WARNING });
+
+ expect(
+ document.querySelector('.flash-container .gl-alert.gl-alert-warning'),
+ ).not.toBeNull();
+ });
+
+ it('escapes text', () => {
+ alert = createAlert({ message: '<script>alert("a");</script>' });
+
+ const html = document.querySelector('.flash-container').innerHTML;
+
+ expect(html).toContain('&lt;script&gt;alert("a");&lt;/script&gt;');
+ expect(html).not.toContain('<script>alert("a");</script>');
+ });
+
+ it('adds alert into specified container', () => {
+ setHTMLFixture(`
+ <div class="my-alert-container"></div>
+ <div class="my-other-container"></div>
+ `);
+
+ alert = createAlert({ message: mockMessage, containerSelector: '.my-alert-container' });
+
+ expect(document.querySelector('.my-alert-container .gl-alert')).not.toBeNull();
+ expect(document.querySelector('.my-alert-container').innerText.trim()).toBe(mockMessage);
+
+ expect(document.querySelector('.my-other-container .gl-alert')).toBeNull();
+ expect(document.querySelector('.my-other-container').innerText.trim()).toBe('');
+ });
+
+ it('adds alert into specified parent', () => {
+ setHTMLFixture(`
+ <div id="my-parent">
+ <div class="flash-container"></div>
+ </div>
+ <div id="my-other-parent">
+ <div class="flash-container"></div>
+ </div>
+ `);
+
+ alert = createAlert({ message: mockMessage, parent: document.getElementById('my-parent') });
+
+ expect(document.querySelector('#my-parent .flash-container .gl-alert')).not.toBeNull();
+ expect(document.querySelector('#my-parent .flash-container').innerText.trim()).toBe(
+ mockMessage,
+ );
+
+ expect(document.querySelector('#my-other-parent .flash-container .gl-alert')).toBeNull();
+ expect(document.querySelector('#my-other-parent .flash-container').innerText.trim()).toBe(
+ '',
+ );
+ });
+
+ it('removes element after clicking', () => {
+ alert = createAlert({ message: mockMessage });
+
+ expect(document.querySelector('.flash-container .gl-alert')).not.toBeNull();
+
+ document.querySelector('.gl-dismiss-btn').click();
+
+ expect(document.querySelector('.flash-container .gl-alert')).toBeNull();
+ });
+
+ it('does not capture error using Sentry', () => {
+ alert = createAlert({
+ message: mockMessage,
+ captureError: false,
+ error: new Error('Error!'),
+ });
+
+ expect(Sentry.captureException).not.toHaveBeenCalled();
+ });
+
+ it('captures error using Sentry', () => {
+ alert = createAlert({
+ message: mockMessage,
+ captureError: true,
+ error: new Error('Error!'),
+ });
+
+ expect(Sentry.captureException).toHaveBeenCalledWith(expect.any(Error));
+ expect(Sentry.captureException).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: 'Error!',
+ }),
+ );
+ });
+
+ describe('with title', () => {
+ const mockTitle = 'my title';
+
+ it('shows title and message', () => {
+ createAlert({
+ title: mockTitle,
+ message: mockMessage,
+ });
+
+ expect(findTextContent()).toBe(`${mockTitle} ${mockMessage}`);
+ });
+ });
+
+ describe('with buttons', () => {
+ const findAlertAction = () => document.querySelector('.flash-container .gl-alert-action');
+
+ it('adds primary button', () => {
+ alert = createAlert({
+ message: mockMessage,
+ primaryButton: {
+ text: 'Ok',
+ },
+ });
+
+ expect(findAlertAction().textContent.trim()).toBe('Ok');
+ });
+
+ it('creates link with href', () => {
+ alert = createAlert({
+ message: mockMessage,
+ primaryButton: {
+ link: '/url',
+ text: 'Ok',
+ },
+ });
+
+ const action = findAlertAction();
+
+ expect(action.textContent.trim()).toBe('Ok');
+ expect(action.nodeName).toBe('A');
+ expect(action.getAttribute('href')).toBe('/url');
+ });
+
+ it('create button as href when no href is present', () => {
+ alert = createAlert({
+ message: mockMessage,
+ primaryButton: {
+ text: 'Ok',
+ },
+ });
+
+ const action = findAlertAction();
+
+ expect(action.nodeName).toBe('BUTTON');
+ expect(action.getAttribute('href')).toBe(null);
+ });
+
+ it('escapes the title text', () => {
+ alert = createAlert({
+ message: mockMessage,
+ primaryButton: {
+ text: '<script>alert("a")</script>',
+ },
+ });
+
+ const html = findAlertAction().innerHTML;
+
+ expect(html).toContain('&lt;script&gt;alert("a")&lt;/script&gt;');
+ expect(html).not.toContain('<script>alert("a")</script>');
+ });
+
+ it('calls actionConfig clickHandler on click', () => {
+ const clickHandler = jest.fn();
+
+ alert = createAlert({
+ message: mockMessage,
+ primaryButton: {
+ text: 'Ok',
+ clickHandler,
+ },
+ });
+
+ expect(clickHandler).toHaveBeenCalledTimes(0);
+
+ findAlertAction().click();
+
+ expect(clickHandler).toHaveBeenCalledTimes(1);
+ expect(clickHandler).toHaveBeenCalledWith(expect.any(MouseEvent));
+ });
+ });
+
+ describe('Alert API', () => {
+ describe('dismiss', () => {
+ it('dismiss programmatically with .dismiss()', () => {
+ expect(document.querySelector('.gl-alert')).toBeNull();
+
+ alert = createAlert({ message: mockMessage });
+
+ expect(document.querySelector('.gl-alert')).not.toBeNull();
+
+ alert.dismiss();
+
+ expect(document.querySelector('.gl-alert')).toBeNull();
+ });
+
+ it('does not crash if calling .dismiss() twice', () => {
+ alert = createAlert({ message: mockMessage });
+
+ alert.dismiss();
+ expect(() => alert.dismiss()).not.toThrow();
+ });
+
+ it('calls onDismiss when dismissed', () => {
+ const dismissHandler = jest.fn();
+
+ alert = createAlert({ message: mockMessage, onDismiss: dismissHandler });
+
+ expect(dismissHandler).toHaveBeenCalledTimes(0);
+
+ alert.dismiss();
+
+ expect(dismissHandler).toHaveBeenCalledTimes(1);
+ });
+ });
+ });
+
+ describe('when called multiple times', () => {
+ it('clears previous alerts', () => {
+ createAlert({ message: 'message 1' });
+ createAlert({ message: 'message 2' });
+
+ expect(findTextContent()).toBe('message 2');
+ });
+
+ it('preserves alerts when `preservePrevious` is true', () => {
+ createAlert({ message: 'message 1' });
+ createAlert({ message: 'message 2', preservePrevious: true });
+
+ expect(findTextContent()).toBe('message 1 message 2');
+ });
+ });
+ });
+ });
+});
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 0e402e61bcc..4a60d605cae 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
@@ -51,36 +51,23 @@ exports[`Alert integration settings form default state should match the default
</gl-link-stub>
</label>
- <gl-dropdown-stub
+ <gl-collapsible-listbox-stub
block="true"
category="primary"
- clearalltext="Clear all"
- clearalltextclass="gl-px-5"
data-qa-selector="incident_templates_dropdown"
headertext=""
- hideheaderborder="true"
- highlighteditemstitle="Selected"
- highlighteditemstitleclass="gl-px-5"
+ icon=""
id="alert-integration-settings-issue-template"
+ items="[object Object]"
+ noresultstext="No results found"
+ placement="left"
+ resetbuttonlabel=""
+ searchplaceholder="Search"
+ selected="selecte_tmpl"
size="medium"
- text="selecte_tmpl"
+ toggletext=""
variant="default"
- >
- <gl-dropdown-item-stub
- avatarurl=""
- data-qa-selector="incident_templates_item"
- iconcolor=""
- iconname=""
- iconrightarialabel=""
- iconrightname=""
- ischeckitem="true"
- secondarytext=""
- >
-
- No template selected
-
- </gl-dropdown-item-stub>
- </gl-dropdown-stub>
+ />
</gl-form-group-stub>
<gl-form-group-stub
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 a15c78cc456..67d8619f157 100644
--- a/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
+++ b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
@@ -30,7 +30,7 @@ import {
INTEGRATION_INACTIVE_PAYLOAD_TEST_ERROR,
DELETE_INTEGRATION_ERROR,
} from '~/alerts_settings/utils/error_messages';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_FORBIDDEN, HTTP_STATUS_UNPROCESSABLE_ENTITY } from '~/lib/utils/http_status';
import {
@@ -48,7 +48,7 @@ import {
} from './mocks/apollo_mock';
import mockIntegrations from './mocks/integrations.json';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('AlertsSettingsWrapper', () => {
let wrapper;
@@ -128,10 +128,6 @@ describe('AlertsSettingsWrapper', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
beforeEach(() => {
createComponent({
@@ -478,7 +474,7 @@ describe('AlertsSettingsWrapper', () => {
expect(destroyIntegrationHandler).toHaveBeenCalled();
});
- it('displays flash if mutation had a recoverable error', async () => {
+ it('displays alert if mutation had a recoverable error', async () => {
createComponentWithApollo({
destroyHandler: jest.fn().mockResolvedValue(destroyIntegrationResponseWithErrors),
});
@@ -489,7 +485,7 @@ describe('AlertsSettingsWrapper', () => {
expect(createAlert).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
});
- it('displays flash if mutation had a non-recoverable error', async () => {
+ it('displays alert if mutation had a non-recoverable error', async () => {
createComponentWithApollo({
destroyHandler: jest.fn().mockRejectedValue('Error'),
});
diff --git a/spec/frontend/analytics/components/activity_chart_spec.js b/spec/frontend/analytics/components/activity_chart_spec.js
index c26407f5c1d..4f8126aaacf 100644
--- a/spec/frontend/analytics/components/activity_chart_spec.js
+++ b/spec/frontend/analytics/components/activity_chart_spec.js
@@ -13,11 +13,6 @@ describe('Activity Chart Bundle', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findChart = () => wrapper.findComponent(GlColumnChart);
const findNoData = () => wrapper.find('[data-testid="noActivityChartData"]');
diff --git a/spec/frontend/analytics/cycle_analytics/base_spec.js b/spec/frontend/analytics/cycle_analytics/base_spec.js
index 58588ff49ce..033916eabcd 100644
--- a/spec/frontend/analytics/cycle_analytics/base_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/base_spec.js
@@ -31,13 +31,15 @@ Vue.use(Vuex);
let wrapper;
-const { id: groupId, path: groupPath } = currentGroup;
+const { path } = currentGroup;
+const groupPath = `groups/${path}`;
const defaultState = {
currentGroup,
createdBefore,
createdAfter,
stageCounts,
- endpoints: { fullPath, groupId, groupPath },
+ groupPath,
+ namespace: { fullPath },
};
function createStore({ initialState = {}, initialGetters = {} }) {
@@ -93,11 +95,6 @@ describe('Value stream analytics component', () => {
wrapper = createComponent({ initialState: { selectedStage, selectedStageEvents, pagination } });
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders the path navigation component', () => {
expect(findPathNavigation().exists()).toBe(true);
});
@@ -139,7 +136,6 @@ describe('Value stream analytics component', () => {
it('passes the paths to the filter bar', () => {
expect(findFilters().props()).toEqual({
- groupId,
groupPath,
endDate: createdBefore,
hasDateRangeFilter: true,
@@ -157,6 +153,10 @@ describe('Value stream analytics component', () => {
expect(findPagination().exists()).toBe(true);
});
+ it('does not render a link to the value streams dashboard', () => {
+ expect(findOverviewMetrics().props('dashboardsPath')).toBeNull();
+ });
+
describe('with `cycleAnalyticsForGroups=true` license', () => {
beforeEach(() => {
wrapper = createComponent({ initialState: { features: { cycleAnalyticsForGroups: true } } });
@@ -167,6 +167,23 @@ describe('Value stream analytics component', () => {
});
});
+ describe('with `groupAnalyticsDashboardsPage=true` and `groupLevelAnalyticsDashboard=true` license', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ initialState: {
+ features: { groupAnalyticsDashboardsPage: true, groupLevelAnalyticsDashboard: true },
+ },
+ });
+ });
+
+ it('renders a link to the value streams dashboard', () => {
+ expect(findOverviewMetrics().props('dashboardsPath')).toBeDefined();
+ expect(findOverviewMetrics().props('dashboardsPath')).toBe(
+ '/groups/foo/-/analytics/dashboards/value_streams_dashboard?query=full/path/to/foo',
+ );
+ });
+ });
+
describe('isLoading = true', () => {
beforeEach(() => {
wrapper = createComponent({
diff --git a/spec/frontend/analytics/cycle_analytics/filter_bar_spec.js b/spec/frontend/analytics/cycle_analytics/filter_bar_spec.js
index 2b26b202882..da7824adbf9 100644
--- a/spec/frontend/analytics/cycle_analytics/filter_bar_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/filter_bar_spec.js
@@ -98,7 +98,6 @@ describe('Filter bar', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/analytics/cycle_analytics/formatted_stage_count_spec.js b/spec/frontend/analytics/cycle_analytics/formatted_stage_count_spec.js
index 9be92bb92bc..6dd7e2e6223 100644
--- a/spec/frontend/analytics/cycle_analytics/formatted_stage_count_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/formatted_stage_count_spec.js
@@ -16,10 +16,6 @@ describe('Formatted Stage Count', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
stageCount | expectedOutput
${null} | ${'-'}
diff --git a/spec/frontend/analytics/cycle_analytics/mock_data.js b/spec/frontend/analytics/cycle_analytics/mock_data.js
index f820f755400..216e07844b8 100644
--- a/spec/frontend/analytics/cycle_analytics/mock_data.js
+++ b/spec/frontend/analytics/cycle_analytics/mock_data.js
@@ -219,6 +219,8 @@ export const group = {
};
export const currentGroup = convertObjectPropsToCamelCase(group, { deep: true });
+export const groupNamespace = { id: currentGroup.id, fullPath: `groups/${currentGroup.path}` };
+export const projectNamespace = { fullPath: 'some/cool/path' };
export const selectedProjects = [
{
diff --git a/spec/frontend/analytics/cycle_analytics/path_navigation_spec.js b/spec/frontend/analytics/cycle_analytics/path_navigation_spec.js
index 107e62035c3..9a598ee0ad1 100644
--- a/spec/frontend/analytics/cycle_analytics/path_navigation_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/path_navigation_spec.js
@@ -50,8 +50,6 @@ describe('Project PathNavigation', () => {
afterEach(() => {
unmockTracking();
- wrapper.destroy();
- wrapper = null;
});
describe('displays correctly', () => {
diff --git a/spec/frontend/analytics/cycle_analytics/stage_table_spec.js b/spec/frontend/analytics/cycle_analytics/stage_table_spec.js
index cfccce7eae9..fbc63a80de8 100644
--- a/spec/frontend/analytics/cycle_analytics/stage_table_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/stage_table_spec.js
@@ -51,10 +51,6 @@ function createComponent(props = {}, shallow = false) {
}
describe('StageTable', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('is loaded with data', () => {
beforeEach(() => {
wrapper = createComponent();
@@ -258,7 +254,6 @@ describe('StageTable', () => {
afterEach(() => {
unmockTracking();
- wrapper.destroy();
});
it('will display the pagination component', () => {
@@ -305,7 +300,6 @@ describe('StageTable', () => {
afterEach(() => {
unmockTracking();
- wrapper.destroy();
});
it('can sort the end event or duration', () => {
diff --git a/spec/frontend/analytics/cycle_analytics/store/actions_spec.js b/spec/frontend/analytics/cycle_analytics/store/actions_spec.js
index 3030fca126b..b2ce8596c22 100644
--- a/spec/frontend/analytics/cycle_analytics/store/actions_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/store/actions_spec.js
@@ -13,21 +13,13 @@ import {
createdBefore,
initialPaginationState,
reviewEvents,
+ projectNamespace as namespace,
} from '../mock_data';
-const { id: groupId, path: groupPath } = currentGroup;
-const mockMilestonesPath = 'mock-milestones.json';
-const mockLabelsPath = 'mock-labels.json';
-const mockRequestPath = 'some/cool/path';
+const { path: groupPath } = currentGroup;
+const mockMilestonesPath = `/${namespace.fullPath}/-/milestones.json`;
+const mockLabelsPath = `/${namespace.fullPath}/-/labels.json`;
const mockFullPath = '/namespace/-/analytics/value_stream_analytics/value_streams';
-const mockEndpoints = {
- fullPath: mockFullPath,
- requestPath: mockRequestPath,
- labelsPath: mockLabelsPath,
- milestonesPath: mockMilestonesPath,
- groupId,
- groupPath,
-};
const mockSetDateActionCommit = {
payload: { createdAfter, createdBefore },
type: 'SET_DATE_RANGE',
@@ -35,6 +27,7 @@ const mockSetDateActionCommit = {
const defaultState = {
...getters,
+ namespace,
selectedValueStream,
createdAfter,
createdBefore,
@@ -81,7 +74,8 @@ describe('Project Value Stream Analytics actions', () => {
const selectedAssigneeList = ['Assignee 1', 'Assignee 2'];
const selectedLabelList = ['Label 1', 'Label 2'];
const payload = {
- endpoints: mockEndpoints,
+ namespace,
+ groupPath,
selectedAuthor,
selectedMilestone,
selectedAssigneeList,
@@ -92,7 +86,7 @@ describe('Project Value Stream Analytics actions', () => {
groupEndpoint: 'foo',
labelsEndpoint: mockLabelsPath,
milestonesEndpoint: mockMilestonesPath,
- projectEndpoint: '/namespace/-/analytics/value_stream_analytics/value_streams',
+ projectEndpoint: namespace.fullPath,
};
it('will dispatch fetchValueStreams actions and commit SET_LOADING and INITIALIZE_VSA', () => {
@@ -193,7 +187,6 @@ describe('Project Value Stream Analytics actions', () => {
beforeEach(() => {
state = {
...defaultState,
- endpoints: mockEndpoints,
selectedStage,
};
mock = new MockAdapter(axios);
@@ -219,7 +212,6 @@ describe('Project Value Stream Analytics actions', () => {
beforeEach(() => {
state = {
...defaultState,
- endpoints: mockEndpoints,
selectedStage,
};
mock = new MockAdapter(axios);
@@ -243,7 +235,6 @@ describe('Project Value Stream Analytics actions', () => {
beforeEach(() => {
state = {
...defaultState,
- endpoints: mockEndpoints,
selectedStage,
};
mock = new MockAdapter(axios);
@@ -265,9 +256,7 @@ describe('Project Value Stream Analytics actions', () => {
const mockValueStreamPath = /\/analytics\/value_stream_analytics\/value_streams/;
beforeEach(() => {
- state = {
- endpoints: mockEndpoints,
- };
+ state = { namespace };
mock = new MockAdapter(axios);
mock.onGet(mockValueStreamPath).reply(HTTP_STATUS_OK);
});
@@ -333,7 +322,7 @@ describe('Project Value Stream Analytics actions', () => {
beforeEach(() => {
state = {
- endpoints: mockEndpoints,
+ namespace,
selectedValueStream,
};
mock = new MockAdapter(axios);
diff --git a/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js b/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js
index 567fac81e1f..70b7454f4a0 100644
--- a/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js
@@ -17,12 +17,14 @@ import {
rawStageCounts,
stageCounts,
initialPaginationState as pagination,
+ projectNamespace as mockNamespace,
} from '../mock_data';
let state;
const rawEvents = rawIssueEvents.events;
const convertedEvents = issueEvents.events;
-const mockRequestPath = 'fake/request/path';
+const mockGroupPath = 'groups/path';
+const mockFeatures = { some: 'feature' };
const mockCreatedAfter = '2020-06-18';
const mockCreatedBefore = '2020-07-18';
@@ -64,19 +66,22 @@ describe('Project Value Stream Analytics mutations', () => {
const mockSetDatePayload = { createdAfter: mockCreatedAfter, createdBefore: mockCreatedBefore };
const mockInitialPayload = {
- endpoints: { requestPath: mockRequestPath },
currentGroup: { title: 'cool-group' },
id: 1337,
+ groupPath: mockGroupPath,
+ namespace: mockNamespace,
+ features: mockFeatures,
...mockSetDatePayload,
};
const mockInitializedObj = {
- endpoints: { requestPath: mockRequestPath },
...mockSetDatePayload,
};
it.each`
mutation | stateKey | value
- ${types.INITIALIZE_VSA} | ${'endpoints'} | ${{ requestPath: mockRequestPath }}
+ ${types.INITIALIZE_VSA} | ${'features'} | ${mockFeatures}
+ ${types.INITIALIZE_VSA} | ${'namespace'} | ${mockNamespace}
+ ${types.INITIALIZE_VSA} | ${'groupPath'} | ${mockGroupPath}
${types.INITIALIZE_VSA} | ${'createdAfter'} | ${mockCreatedAfter}
${types.INITIALIZE_VSA} | ${'createdBefore'} | ${mockCreatedBefore}
`('$mutation will set $stateKey', ({ mutation, stateKey, value }) => {
diff --git a/spec/frontend/analytics/cycle_analytics/total_time_spec.js b/spec/frontend/analytics/cycle_analytics/total_time_spec.js
index 47ee7aad8c4..6597b6fa3d5 100644
--- a/spec/frontend/analytics/cycle_analytics/total_time_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/total_time_spec.js
@@ -10,10 +10,6 @@ describe('TotalTime', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with a valid time object', () => {
it.each`
time
diff --git a/spec/frontend/analytics/cycle_analytics/utils_spec.js b/spec/frontend/analytics/cycle_analytics/utils_spec.js
index fe412bf7498..e6d17edcadc 100644
--- a/spec/frontend/analytics/cycle_analytics/utils_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/utils_spec.js
@@ -91,9 +91,9 @@ describe('Value stream analytics utils', () => {
const projectId = '5';
const createdAfter = '2021-09-01';
const createdBefore = '2021-11-06';
- const groupId = '146';
const groupPath = 'fake-group';
- const fullPath = 'fake-group/fake-project';
+ const namespaceName = 'Fake project';
+ const namespaceFullPath = 'fake-group/fake-project';
const labelsPath = '/fake-group/fake-project/-/labels.json';
const milestonesPath = '/fake-group/fake-project/-/milestones.json';
const requestPath = '/fake-group/fake-project/-/value_stream_analytics';
@@ -102,11 +102,11 @@ describe('Value stream analytics utils', () => {
projectId,
createdBefore,
createdAfter,
- fullPath,
+ namespaceName,
+ namespaceFullPath,
requestPath,
labelsPath,
milestonesPath,
- groupId,
groupPath,
};
@@ -124,14 +124,13 @@ describe('Value stream analytics utils', () => {
expect(res.createdAfter).toEqual(new Date(createdAfter));
});
+ it('sets the namespace', () => {
+ expect(res.namespace.name).toBe(namespaceName);
+ expect(res.namespace.fullPath).toBe(namespaceFullPath);
+ });
+
it('sets the endpoints', () => {
- const { endpoints } = res;
- expect(endpoints.fullPath).toBe(fullPath);
- expect(endpoints.requestPath).toBe(requestPath);
- expect(endpoints.labelsPath).toBe(labelsPath);
- expect(endpoints.milestonesPath).toBe(milestonesPath);
- expect(endpoints.groupId).toBe(parseInt(groupId, 10));
- expect(endpoints.groupPath).toBe(groupPath);
+ expect(res.groupPath).toBe(`groups/${groupPath}`);
});
it('returns null when there is no stage', () => {
@@ -164,7 +163,7 @@ describe('Value stream analytics utils', () => {
...rawData,
gon: { licensed_features: fakeFeatures },
});
- expect(res.features).toEqual(fakeFeatures);
+ expect(res.features).toMatchObject(fakeFeatures);
});
});
});
diff --git a/spec/frontend/analytics/cycle_analytics/value_stream_filters_spec.js b/spec/frontend/analytics/cycle_analytics/value_stream_filters_spec.js
index 4f333e95d89..160f6ce0563 100644
--- a/spec/frontend/analytics/cycle_analytics/value_stream_filters_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/value_stream_filters_spec.js
@@ -34,11 +34,6 @@ describe('ValueStreamFilters', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('will render the filter bar', () => {
expect(findFilterBar().exists()).toBe(true);
});
diff --git a/spec/frontend/analytics/cycle_analytics/value_stream_metrics_spec.js b/spec/frontend/analytics/cycle_analytics/value_stream_metrics_spec.js
index 948dc5c9be2..6a64737bc80 100644
--- a/spec/frontend/analytics/cycle_analytics/value_stream_metrics_spec.js
+++ b/spec/frontend/analytics/cycle_analytics/value_stream_metrics_spec.js
@@ -8,10 +8,11 @@ import { METRIC_TYPE_SUMMARY } from '~/api/analytics_api';
import { VSA_METRICS_GROUPS, METRICS_POPOVER_CONTENT } from '~/analytics/shared/constants';
import { prepareTimeMetricsData } from '~/analytics/shared/utils';
import MetricTile from '~/analytics/shared/components/metric_tile.vue';
-import { createAlert } from '~/flash';
+import ValueStreamsDashboardLink from '~/analytics/shared/components/value_streams_dashboard_link.vue';
+import { createAlert } from '~/alert';
import { group } from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('ValueStreamMetrics', () => {
let wrapper;
@@ -37,6 +38,7 @@ describe('ValueStreamMetrics', () => {
});
};
+ const findVSDLink = () => wrapper.findComponent(ValueStreamsDashboardLink);
const findMetrics = () => wrapper.findAllComponents(MetricTile);
const findMetricsGroups = () => wrapper.findAllByTestId('vsa-metrics-group');
@@ -48,10 +50,6 @@ describe('ValueStreamMetrics', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with successful requests', () => {
beforeEach(() => {
mockGetValueStreamSummaryMetrics = jest.fn().mockResolvedValue({ data: metricsData });
@@ -168,6 +166,25 @@ describe('ValueStreamMetrics', () => {
});
});
+ describe('Value Streams Dashboard Link', () => {
+ it('will render when a dashboardsPath is set', async () => {
+ wrapper = createComponent({ groupBy: VSA_METRICS_GROUPS, dashboardsPath: 'fake-group-path' });
+ await waitForPromises();
+
+ const vsdLink = findVSDLink();
+
+ expect(vsdLink.exists()).toBe(true);
+ expect(vsdLink.props()).toEqual({ requestPath: 'fake-group-path' });
+ });
+
+ it('does not render without a dashboardsPath', async () => {
+ wrapper = createComponent({ groupBy: VSA_METRICS_GROUPS });
+ await waitForPromises();
+
+ expect(findVSDLink().exists()).toBe(false);
+ });
+ });
+
describe('with a request failing', () => {
beforeEach(async () => {
mockGetValueStreamSummaryMetrics = jest.fn().mockRejectedValue();
diff --git a/spec/frontend/analytics/devops_reports/components/service_ping_disabled_spec.js b/spec/frontend/analytics/devops_reports/components/service_ping_disabled_spec.js
index c62bfb11f7b..70bfce41c82 100644
--- a/spec/frontend/analytics/devops_reports/components/service_ping_disabled_spec.js
+++ b/spec/frontend/analytics/devops_reports/components/service_ping_disabled_spec.js
@@ -6,10 +6,6 @@ import ServicePingDisabled from '~/analytics/devops_reports/components/service_p
describe('~/analytics/devops_reports/components/service_ping_disabled.vue', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
const createWrapper = ({ isAdmin = false } = {}) => {
wrapper = mountExtended(ServicePingDisabled, {
provide: {
diff --git a/spec/frontend/analytics/shared/components/daterange_spec.js b/spec/frontend/analytics/shared/components/daterange_spec.js
index 562e86529ee..5f0847e0db6 100644
--- a/spec/frontend/analytics/shared/components/daterange_spec.js
+++ b/spec/frontend/analytics/shared/components/daterange_spec.js
@@ -22,10 +22,6 @@ describe('Daterange component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDaterangePicker = () => wrapper.findComponent(GlDaterangePicker);
const findDateRangeIndicator = () => wrapper.findByTestId('daterange-picker-indicator');
@@ -90,18 +86,19 @@ describe('Daterange component', () => {
});
describe('set', () => {
- it('emits the change event with an object containing startDate and endDate', () => {
+ it('emits the change event with an object containing startDate and endDate', async () => {
const startDate = new Date('2019-10-01');
const endDate = new Date('2019-10-05');
- wrapper.vm.dateRange = { startDate, endDate };
- expect(wrapper.emitted().change).toEqual([[{ startDate, endDate }]]);
+ await findDaterangePicker().vm.$emit('input', { startDate, endDate });
+
+ expect(wrapper.emitted('change')).toEqual([[{ startDate, endDate }]]);
});
});
describe('get', () => {
- it("returns value of dateRange from state's startDate and endDate", () => {
- expect(wrapper.vm.dateRange).toEqual({
+ it("datepicker to have default of dateRange from state's startDate and endDate", () => {
+ expect(findDaterangePicker().props('value')).toEqual({
startDate: defaultProps.startDate,
endDate: defaultProps.endDate,
});
diff --git a/spec/frontend/analytics/shared/components/metric_popover_spec.js b/spec/frontend/analytics/shared/components/metric_popover_spec.js
index e0bfff3e664..d7e6606cdc6 100644
--- a/spec/frontend/analytics/shared/components/metric_popover_spec.js
+++ b/spec/frontend/analytics/shared/components/metric_popover_spec.js
@@ -34,10 +34,6 @@ describe('MetricPopover', () => {
const findMetricDocsLinkIcon = () => findMetricDocsLink().findComponent(GlIcon);
const findMetricDetailsIcon = () => findMetricLink().findComponent(GlIcon);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the metric label', () => {
wrapper = createComponent({ metric: MOCK_METRIC });
expect(findMetricLabel().text()).toBe(MOCK_METRIC.label);
diff --git a/spec/frontend/analytics/shared/components/metric_tile_spec.js b/spec/frontend/analytics/shared/components/metric_tile_spec.js
index 980dfad9eb0..00e82cff0f0 100644
--- a/spec/frontend/analytics/shared/components/metric_tile_spec.js
+++ b/spec/frontend/analytics/shared/components/metric_tile_spec.js
@@ -21,10 +21,6 @@ describe('MetricTile', () => {
const findSingleStat = () => wrapper.findComponent(GlSingleStat);
const findPopover = () => wrapper.findComponent(MetricPopover);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
describe('links', () => {
it('when the metric has links, it redirects the user on click', () => {
diff --git a/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js b/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js
index 3871fd530d8..d2cbe0d39e4 100644
--- a/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js
+++ b/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js
@@ -70,10 +70,6 @@ describe('ProjectsDropdownFilter component', () => {
return waitForPromises();
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findHighlightedItems = () => wrapper.findByTestId('vsa-highlighted-items');
const findUnhighlightedItems = () => wrapper.findByTestId('vsa-default-items');
const findClearAllButton = () => wrapper.findByText('Clear all');
diff --git a/spec/frontend/analytics/shared/utils_spec.js b/spec/frontend/analytics/shared/utils_spec.js
index b48e2d971b5..24af7b836d5 100644
--- a/spec/frontend/analytics/shared/utils_spec.js
+++ b/spec/frontend/analytics/shared/utils_spec.js
@@ -5,6 +5,7 @@ import {
extractPaginationQueryParameters,
getDataZoomOption,
prepareTimeMetricsData,
+ generateValueStreamsDashboardLink,
} from '~/analytics/shared/utils';
import { slugify } from '~/lib/utils/text_utility';
import { objectToQuery } from '~/lib/utils/url_utility';
@@ -212,3 +213,30 @@ describe('prepareTimeMetricsData', () => {
]);
});
});
+
+describe('generateValueStreamsDashboardLink', () => {
+ it.each`
+ groupPath | projectPaths | result
+ ${''} | ${[]} | ${''}
+ ${'groups/fake-group'} | ${[]} | ${'/groups/fake-group/-/analytics/dashboards/value_streams_dashboard'}
+ ${'groups/fake-group'} | ${['fake-path/project_1']} | ${'/groups/fake-group/-/analytics/dashboards/value_streams_dashboard?query=fake-path/project_1'}
+ ${'groups/fake-group'} | ${['fake-path/project_1', 'fake-path/project_2']} | ${'/groups/fake-group/-/analytics/dashboards/value_streams_dashboard?query=fake-path/project_1,fake-path/project_2'}
+ `(
+ 'generates the dashboard link when groupPath=$groupPath and projectPaths=$projectPaths',
+ ({ groupPath, projectPaths, result }) => {
+ expect(generateValueStreamsDashboardLink(groupPath, projectPaths)).toBe(result);
+ },
+ );
+
+ describe('with a relative url rool set', () => {
+ beforeEach(() => {
+ gon.relative_url_root = '/foobar';
+ });
+
+ it('with includes a relative path if one is set', () => {
+ expect(generateValueStreamsDashboardLink('groups/fake-path', ['project_1'])).toBe(
+ '/foobar/groups/fake-path/-/analytics/dashboards/value_streams_dashboard?query=project_1',
+ );
+ });
+ });
+});
diff --git a/spec/frontend/analytics/usage_trends/components/app_spec.js b/spec/frontend/analytics/usage_trends/components/app_spec.js
index c732dc22322..f9338661ebf 100644
--- a/spec/frontend/analytics/usage_trends/components/app_spec.js
+++ b/spec/frontend/analytics/usage_trends/components/app_spec.js
@@ -15,11 +15,6 @@ describe('UsageTrendsApp', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('displays the usage counts component', () => {
expect(wrapper.findComponent(UsageCounts).exists()).toBe(true);
});
diff --git a/spec/frontend/analytics/usage_trends/components/usage_counts_spec.js b/spec/frontend/analytics/usage_trends/components/usage_counts_spec.js
index f4cbc56be5c..a71ce090955 100644
--- a/spec/frontend/analytics/usage_trends/components/usage_counts_spec.js
+++ b/spec/frontend/analytics/usage_trends/components/usage_counts_spec.js
@@ -26,10 +26,6 @@ describe('UsageCounts', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findAllSingleStats = () => wrapper.findAllComponents(GlSingleStat);
diff --git a/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js b/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js
index ad6089f74b5..322d05e663a 100644
--- a/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js
+++ b/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js
@@ -45,11 +45,6 @@ describe('UsageTrendsCountChart', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findLoader = () => wrapper.findComponent(ChartSkeletonLoader);
const findChart = () => wrapper.findComponent(GlLineChart);
const findAlert = () => wrapper.findComponent(GlAlert);
diff --git a/spec/frontend/analytics/usage_trends/components/users_chart_spec.js b/spec/frontend/analytics/usage_trends/components/users_chart_spec.js
index e7abd4d4323..20836d7cc70 100644
--- a/spec/frontend/analytics/usage_trends/components/users_chart_spec.js
+++ b/spec/frontend/analytics/usage_trends/components/users_chart_spec.js
@@ -42,11 +42,6 @@ describe('UsersChart', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findLoader = () => wrapper.findComponent(ChartSkeletonLoader);
const findAlert = () => wrapper.findComponent(GlAlert);
const findChart = () => wrapper.findComponent(GlAreaChart);
diff --git a/spec/frontend/api/alert_management_alerts_api_spec.js b/spec/frontend/api/alert_management_alerts_api_spec.js
index 507f659a170..86052a05b76 100644
--- a/spec/frontend/api/alert_management_alerts_api_spec.js
+++ b/spec/frontend/api/alert_management_alerts_api_spec.js
@@ -9,7 +9,6 @@ import {
describe('~/api/alert_management_alerts_api.js', () => {
let mock;
- let originalGon;
const projectId = 1;
const alertIid = 2;
@@ -19,13 +18,11 @@ describe('~/api/alert_management_alerts_api.js', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
- originalGon = window.gon;
window.gon = { api_version: 'v4' };
});
afterEach(() => {
mock.restore();
- window.gon = originalGon;
});
describe('fetchAlertMetricImages', () => {
diff --git a/spec/frontend/api/groups_api_spec.js b/spec/frontend/api/groups_api_spec.js
index 0315db02cf2..642edb33624 100644
--- a/spec/frontend/api/groups_api_spec.js
+++ b/spec/frontend/api/groups_api_spec.js
@@ -10,23 +10,18 @@ const mockUrlRoot = '/gitlab';
const mockGroupId = '99';
describe('GroupsApi', () => {
- let originalGon;
let mock;
- const dummyGon = {
- api_version: mockApiVersion,
- relative_url_root: mockUrlRoot,
- };
-
beforeEach(() => {
mock = new MockAdapter(axios);
- originalGon = window.gon;
- window.gon = { ...dummyGon };
+ window.gon = {
+ api_version: mockApiVersion,
+ relative_url_root: mockUrlRoot,
+ };
});
afterEach(() => {
mock.restore();
- window.gon = originalGon;
});
describe('updateGroup', () => {
diff --git a/spec/frontend/api/packages_api_spec.js b/spec/frontend/api/packages_api_spec.js
index 5f517bcf358..37c4b926ec2 100644
--- a/spec/frontend/api/packages_api_spec.js
+++ b/spec/frontend/api/packages_api_spec.js
@@ -6,22 +6,18 @@ import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
describe('Api', () => {
const dummyApiVersion = 'v3000';
const dummyUrlRoot = '/gitlab';
- const dummyGon = {
- api_version: dummyApiVersion,
- relative_url_root: dummyUrlRoot,
- };
- let originalGon;
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
- originalGon = window.gon;
- window.gon = { ...dummyGon };
+ window.gon = {
+ api_version: dummyApiVersion,
+ relative_url_root: dummyUrlRoot,
+ };
});
afterEach(() => {
mock.restore();
- window.gon = originalGon;
});
describe('packages', () => {
diff --git a/spec/frontend/api/projects_api_spec.js b/spec/frontend/api/projects_api_spec.js
index 2d4ed39dad0..2de56fae0c2 100644
--- a/spec/frontend/api/projects_api_spec.js
+++ b/spec/frontend/api/projects_api_spec.js
@@ -7,7 +7,6 @@ import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
describe('~/api/projects_api.js', () => {
let mock;
- let originalGon;
const projectId = 1;
const setfullPathProjectSearch = (value) => {
@@ -17,13 +16,11 @@ describe('~/api/projects_api.js', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
- originalGon = window.gon;
window.gon = { api_version: 'v7', features: { fullPathProjectSearch: true } };
});
afterEach(() => {
mock.restore();
- window.gon = originalGon;
});
describe('getProjects', () => {
diff --git a/spec/frontend/api/tags_api_spec.js b/spec/frontend/api/tags_api_spec.js
index af3533f52b7..0a1177d4f60 100644
--- a/spec/frontend/api/tags_api_spec.js
+++ b/spec/frontend/api/tags_api_spec.js
@@ -5,20 +5,17 @@ import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
describe('~/api/tags_api.js', () => {
let mock;
- let originalGon;
const projectId = 1;
beforeEach(() => {
mock = new MockAdapter(axios);
- originalGon = window.gon;
window.gon = { api_version: 'v7' };
});
afterEach(() => {
mock.restore();
- window.gon = originalGon;
});
describe('getTag', () => {
diff --git a/spec/frontend/api/user_api_spec.js b/spec/frontend/api/user_api_spec.js
index 4d0252aad23..6636d77a09b 100644
--- a/spec/frontend/api/user_api_spec.js
+++ b/spec/frontend/api/user_api_spec.js
@@ -12,19 +12,16 @@ import { timeRanges } from '~/vue_shared/constants';
describe('~/api/user_api', () => {
let axiosMock;
- let originalGon;
beforeEach(() => {
axiosMock = new MockAdapter(axios);
- originalGon = window.gon;
window.gon = { api_version: 'v4' };
});
afterEach(() => {
axiosMock.restore();
axiosMock.resetHistory();
- window.gon = originalGon;
});
describe('followUser', () => {
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
index 6fd106502c4..4ef37311e51 100644
--- a/spec/frontend/api_spec.js
+++ b/spec/frontend/api_spec.js
@@ -10,27 +10,22 @@ import {
HTTP_STATUS_OK,
} from '~/lib/utils/http_status';
-jest.mock('~/flash');
-
describe('Api', () => {
const dummyApiVersion = 'v3000';
const dummyUrlRoot = '/gitlab';
- const dummyGon = {
- api_version: dummyApiVersion,
- relative_url_root: dummyUrlRoot,
- };
- let originalGon;
+
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
- originalGon = window.gon;
- window.gon = { ...dummyGon };
+ window.gon = {
+ api_version: dummyApiVersion,
+ relative_url_root: dummyUrlRoot,
+ };
});
afterEach(() => {
mock.restore();
- window.gon = originalGon;
});
describe('buildUrl', () => {
@@ -1423,7 +1418,7 @@ describe('Api', () => {
describe('when service data increment counter is called with feature flag disabled', () => {
beforeEach(() => {
- gon.features = { ...gon.features, usageDataApi: false };
+ gon.features = { usageDataApi: false };
});
it('returns null', () => {
@@ -1437,7 +1432,7 @@ describe('Api', () => {
describe('when service data increment counter is called', () => {
beforeEach(() => {
- gon.features = { ...gon.features, usageDataApi: true };
+ gon.features = { usageDataApi: true };
});
it('resolves the Promise', () => {
@@ -1468,7 +1463,7 @@ describe('Api', () => {
describe('when service data increment unique users is called with feature flag disabled', () => {
beforeEach(() => {
- gon.features = { ...gon.features, usageDataApi: false };
+ gon.features = { usageDataApi: false };
});
it('returns null and does not call the endpoint', () => {
@@ -1483,7 +1478,7 @@ describe('Api', () => {
describe('when service data increment unique users is called', () => {
beforeEach(() => {
- gon.features = { ...gon.features, usageDataApi: true };
+ gon.features = { usageDataApi: true };
});
it('resolves the Promise', () => {
@@ -1500,7 +1495,7 @@ describe('Api', () => {
describe('when user is not set and feature flag enabled', () => {
beforeEach(() => {
- gon.features = { ...gon.features, usageDataApi: true };
+ gon.features = { usageDataApi: true };
});
it('returns null and does not call the endpoint', () => {
diff --git a/spec/frontend/approvals/mock_data.js b/spec/frontend/approvals/mock_data.js
new file mode 100644
index 00000000000..e0e90c09791
--- /dev/null
+++ b/spec/frontend/approvals/mock_data.js
@@ -0,0 +1,10 @@
+import approvedByCurrentUser from 'test_fixtures/graphql/merge_requests/approvals/approvals.query.graphql.json';
+
+export const createCanApproveResponse = () => {
+ const response = JSON.parse(JSON.stringify(approvedByCurrentUser));
+ response.data.project.mergeRequest.userPermissions.canApprove = true;
+ response.data.project.mergeRequest.approved = false;
+ response.data.project.mergeRequest.approvedBy.nodes = [];
+
+ return response;
+};
diff --git a/spec/frontend/artifacts/components/artifact_row_spec.js b/spec/frontend/artifacts/components/artifact_row_spec.js
index 2a7156bf480..268772ed4c0 100644
--- a/spec/frontend/artifacts/components/artifact_row_spec.js
+++ b/spec/frontend/artifacts/components/artifact_row_spec.js
@@ -1,9 +1,10 @@
-import { GlBadge, GlButton, GlFriendlyWrap } from '@gitlab/ui';
+import { GlBadge, GlButton, GlFriendlyWrap, GlFormCheckbox } from '@gitlab/ui';
import mockGetJobArtifactsResponse from 'test_fixtures/graphql/artifacts/graphql/queries/get_job_artifacts.query.graphql.json';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import ArtifactRow from '~/artifacts/components/artifact_row.vue';
+import { BULK_DELETE_FEATURE_FLAG } from '~/artifacts/constants';
describe('ArtifactRow component', () => {
let wrapper;
@@ -15,23 +16,21 @@ describe('ArtifactRow component', () => {
const findSize = () => wrapper.findByTestId('job-artifact-row-size');
const findDownloadButton = () => wrapper.findByTestId('job-artifact-row-download-button');
const findDeleteButton = () => wrapper.findByTestId('job-artifact-row-delete-button');
+ const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
- const createComponent = ({ canDestroyArtifacts = true } = {}) => {
+ const createComponent = ({ canDestroyArtifacts = true, glFeatures = {} } = {}) => {
wrapper = shallowMountExtended(ArtifactRow, {
propsData: {
artifact,
+ isSelected: false,
isLoading: false,
isLastRow: false,
},
- provide: { canDestroyArtifacts },
+ provide: { canDestroyArtifacts, glFeatures },
stubs: { GlBadge, GlButton, GlFriendlyWrap },
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('artifact details', () => {
beforeEach(async () => {
createComponent();
@@ -77,4 +76,30 @@ describe('ArtifactRow component', () => {
expect(wrapper.emitted('delete')).toBeDefined();
});
});
+
+ describe('bulk delete checkbox', () => {
+ describe('with permission and feature flag enabled', () => {
+ beforeEach(() => {
+ createComponent({ glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true } });
+ });
+
+ it('emits selectArtifact when toggled', () => {
+ findCheckbox().vm.$emit('input', true);
+
+ expect(wrapper.emitted('selectArtifact')).toStrictEqual([[artifact, true]]);
+ });
+ });
+
+ it('is not shown without permission', () => {
+ createComponent({ canDestroyArtifacts: false });
+
+ expect(findCheckbox().exists()).toBe(false);
+ });
+
+ it('is not shown with feature flag disabled', () => {
+ createComponent();
+
+ expect(findCheckbox().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/artifacts/components/artifacts_bulk_delete_spec.js b/spec/frontend/artifacts/components/artifacts_bulk_delete_spec.js
new file mode 100644
index 00000000000..876906b2c3c
--- /dev/null
+++ b/spec/frontend/artifacts/components/artifacts_bulk_delete_spec.js
@@ -0,0 +1,96 @@
+import { GlSprintf, GlModal } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import mockGetJobArtifactsResponse from 'test_fixtures/graphql/artifacts/graphql/queries/get_job_artifacts.query.graphql.json';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import ArtifactsBulkDelete from '~/artifacts/components/artifacts_bulk_delete.vue';
+import bulkDestroyArtifactsMutation from '~/artifacts/graphql/mutations/bulk_destroy_job_artifacts.mutation.graphql';
+
+Vue.use(VueApollo);
+
+describe('ArtifactsBulkDelete component', () => {
+ let wrapper;
+ let requestHandlers;
+
+ const projectId = '123';
+ const selectedArtifacts = [
+ mockGetJobArtifactsResponse.data.project.jobs.nodes[0].artifacts.nodes[0].id,
+ mockGetJobArtifactsResponse.data.project.jobs.nodes[0].artifacts.nodes[1].id,
+ ];
+
+ const findText = () => wrapper.findComponent(GlSprintf).text();
+ const findDeleteButton = () => wrapper.findByTestId('bulk-delete-delete-button');
+ const findClearButton = () => wrapper.findByTestId('bulk-delete-clear-button');
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const createComponent = ({
+ handlers = {
+ bulkDestroyArtifactsMutation: jest.fn(),
+ },
+ } = {}) => {
+ requestHandlers = handlers;
+ wrapper = mountExtended(ArtifactsBulkDelete, {
+ apolloProvider: createMockApollo([
+ [bulkDestroyArtifactsMutation, requestHandlers.bulkDestroyArtifactsMutation],
+ ]),
+ propsData: {
+ selectedArtifacts,
+ queryVariables: {},
+ isLoading: false,
+ isLastRow: false,
+ },
+ provide: { projectId },
+ });
+ };
+
+ describe('selected artifacts box', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('displays selected artifacts count', () => {
+ expect(findText()).toContain(String(selectedArtifacts.length));
+ });
+
+ it('opens the confirmation modal when the delete button is clicked', async () => {
+ expect(findModal().props('visible')).toBe(false);
+
+ findDeleteButton().trigger('click');
+ await waitForPromises();
+
+ expect(findModal().props('visible')).toBe(true);
+ });
+
+ it('emits clearSelectedArtifacts event when the clear button is clicked', () => {
+ findClearButton().trigger('click');
+
+ expect(wrapper.emitted('clearSelectedArtifacts')).toBeDefined();
+ });
+ });
+
+ describe('bulk delete confirmation modal', () => {
+ beforeEach(async () => {
+ createComponent();
+ findDeleteButton().trigger('click');
+ await waitForPromises();
+ });
+
+ it('calls the bulk delete mutation with the selected artifacts on confirm', () => {
+ findModal().vm.$emit('primary');
+
+ expect(requestHandlers.bulkDestroyArtifactsMutation).toHaveBeenCalledWith({
+ projectId: `gid://gitlab/Project/${projectId}`,
+ ids: selectedArtifacts,
+ });
+ });
+
+ it('does not call the bulk delete mutation on cancel', () => {
+ findModal().vm.$emit('cancel');
+
+ expect(requestHandlers.bulkDestroyArtifactsMutation).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/artifacts/components/artifacts_table_row_details_spec.js b/spec/frontend/artifacts/components/artifacts_table_row_details_spec.js
index d006e0285d2..6bf3498f9b0 100644
--- a/spec/frontend/artifacts/components/artifacts_table_row_details_spec.js
+++ b/spec/frontend/artifacts/components/artifacts_table_row_details_spec.js
@@ -10,9 +10,9 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import destroyArtifactMutation from '~/artifacts/graphql/mutations/destroy_artifact.mutation.graphql';
import { I18N_DESTROY_ERROR, I18N_MODAL_TITLE } from '~/artifacts/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
-jest.mock('~/flash');
+jest.mock('~/alert');
const { artifacts } = getJobArtifactsResponse.data.project.jobs.nodes[0];
const refetchArtifacts = jest.fn();
@@ -25,11 +25,12 @@ describe('ArtifactsTableRowDetails component', () => {
const findModal = () => wrapper.findComponent(GlModal);
- const createComponent = (
+ const createComponent = ({
handlers = {
destroyArtifactMutation: jest.fn(),
},
- ) => {
+ selectedArtifacts = [],
+ } = {}) => {
requestHandlers = handlers;
wrapper = mountExtended(ArtifactsTableRowDetails, {
apolloProvider: createMockApollo([
@@ -37,6 +38,7 @@ describe('ArtifactsTableRowDetails component', () => {
]),
propsData: {
artifacts,
+ selectedArtifacts,
refetchArtifacts,
queryVariables: {},
},
@@ -47,10 +49,6 @@ describe('ArtifactsTableRowDetails component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('passes correct props', () => {
beforeEach(() => {
createComponent();
@@ -92,7 +90,7 @@ describe('ArtifactsTableRowDetails component', () => {
});
});
- it('displays a flash message and refetches artifacts when the mutation fails', async () => {
+ it('displays an alert message and refetches artifacts when the mutation fails', async () => {
createComponent({
destroyArtifactMutation: jest.fn().mockRejectedValue(new Error('Error!')),
});
@@ -120,4 +118,20 @@ describe('ArtifactsTableRowDetails component', () => {
expect(requestHandlers.destroyArtifactMutation).not.toHaveBeenCalled();
});
});
+
+ describe('bulk delete selection', () => {
+ it('is not selected for unselected artifact', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(wrapper.findAllComponents(ArtifactRow).at(0).props('isSelected')).toBe(false);
+ });
+
+ it('is selected for selected artifacts', async () => {
+ createComponent({ selectedArtifacts: [artifacts.nodes[0].id] });
+ await waitForPromises();
+
+ expect(wrapper.findAllComponents(ArtifactRow).at(0).props('isSelected')).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/artifacts/components/feedback_banner_spec.js b/spec/frontend/artifacts/components/feedback_banner_spec.js
index 3421486020a..af9599daefa 100644
--- a/spec/frontend/artifacts/components/feedback_banner_spec.js
+++ b/spec/frontend/artifacts/components/feedback_banner_spec.js
@@ -32,10 +32,6 @@ describe('Artifacts management feedback banner', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('is displayed with the correct props', () => {
createComponent();
diff --git a/spec/frontend/artifacts/components/job_artifacts_table_spec.js b/spec/frontend/artifacts/components/job_artifacts_table_spec.js
index dbe4598f599..40f3c9633ab 100644
--- a/spec/frontend/artifacts/components/job_artifacts_table_spec.js
+++ b/spec/frontend/artifacts/components/job_artifacts_table_spec.js
@@ -1,4 +1,12 @@
-import { GlLoadingIcon, GlTable, GlLink, GlBadge, GlPagination, GlModal } from '@gitlab/ui';
+import {
+ GlLoadingIcon,
+ GlTable,
+ GlLink,
+ GlBadge,
+ GlPagination,
+ GlModal,
+ GlFormCheckbox,
+} from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import getJobArtifactsResponse from 'test_fixtures/graphql/artifacts/graphql/queries/get_job_artifacts.query.graphql.json';
@@ -8,15 +16,22 @@ import JobArtifactsTable from '~/artifacts/components/job_artifacts_table.vue';
import FeedbackBanner from '~/artifacts/components/feedback_banner.vue';
import ArtifactsTableRowDetails from '~/artifacts/components/artifacts_table_row_details.vue';
import ArtifactDeleteModal from '~/artifacts/components/artifact_delete_modal.vue';
+import ArtifactsBulkDelete from '~/artifacts/components/artifacts_bulk_delete.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import getJobArtifactsQuery from '~/artifacts/graphql/queries/get_job_artifacts.query.graphql';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { ARCHIVE_FILE_TYPE, JOBS_PER_PAGE, I18N_FETCH_ERROR } from '~/artifacts/constants';
+import {
+ ARCHIVE_FILE_TYPE,
+ JOBS_PER_PAGE,
+ I18N_FETCH_ERROR,
+ INITIAL_CURRENT_PAGE,
+ BULK_DELETE_FEATURE_FLAG,
+} from '~/artifacts/constants';
import { totalArtifactsSizeForJob } from '~/artifacts/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -24,6 +39,8 @@ describe('JobArtifactsTable component', () => {
let wrapper;
let requestHandlers;
+ const mockToastShow = jest.fn();
+
const findBanner = () => wrapper.findComponent(FeedbackBanner);
const findLoadingState = () => wrapper.findComponent(GlLoadingIcon);
@@ -55,6 +72,11 @@ describe('JobArtifactsTable component', () => {
const findDeleteButton = () => wrapper.findByTestId('job-artifacts-delete-button');
const findArtifactDeleteButton = () => wrapper.findByTestId('job-artifact-row-delete-button');
+ // first checkbox is a "select all", this finder should get the first job checkbox
+ const findJobCheckbox = () => wrapper.findAllComponents(GlFormCheckbox).at(1);
+ const findAnyCheckbox = () => wrapper.findComponent(GlFormCheckbox);
+ const findBulkDelete = () => wrapper.findComponent(ArtifactsBulkDelete);
+
const findPagination = () => wrapper.findComponent(GlPagination);
const setPage = async (page) => {
findPagination().vm.$emit('input', page);
@@ -69,7 +91,14 @@ describe('JobArtifactsTable component', () => {
];
}
const getJobArtifactsResponseThatPaginates = {
- data: { project: { jobs: { nodes: enoughJobsToPaginate } } },
+ data: {
+ project: {
+ jobs: {
+ nodes: enoughJobsToPaginate,
+ pageInfo: { ...getJobArtifactsResponse.data.project.jobs.pageInfo, hasNextPage: true },
+ },
+ },
+ },
};
const job = getJobArtifactsResponse.data.project.jobs.nodes[0];
@@ -77,13 +106,14 @@ describe('JobArtifactsTable component', () => {
(artifact) => artifact.fileType === ARCHIVE_FILE_TYPE,
);
- const createComponent = (
+ const createComponent = ({
handlers = {
getJobArtifactsQuery: jest.fn().mockResolvedValue(getJobArtifactsResponse),
},
data = {},
canDestroyArtifacts = true,
- ) => {
+ glFeatures = {},
+ } = {}) => {
requestHandlers = handlers;
wrapper = mountExtended(JobArtifactsTable, {
apolloProvider: createMockApollo([
@@ -91,8 +121,15 @@ describe('JobArtifactsTable component', () => {
]),
provide: {
projectPath: 'project/path',
+ projectId: 'gid://projects/id',
canDestroyArtifacts,
artifactsManagementFeedbackImagePath: 'banner/image/path',
+ glFeatures,
+ },
+ mocks: {
+ $toast: {
+ show: mockToastShow,
+ },
},
data() {
return data;
@@ -100,10 +137,6 @@ describe('JobArtifactsTable component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders feedback banner', () => {
createComponent();
@@ -118,7 +151,9 @@ describe('JobArtifactsTable component', () => {
it('on error, shows an alert', async () => {
createComponent({
- getJobArtifactsQuery: jest.fn().mockRejectedValue(new Error('Error!')),
+ handlers: {
+ getJobArtifactsQuery: jest.fn().mockRejectedValue(new Error('Error!')),
+ },
});
await waitForPromises();
@@ -259,10 +294,10 @@ describe('JobArtifactsTable component', () => {
archive: { downloadPath: null },
};
- createComponent(
- { getJobArtifactsQuery: jest.fn() },
- { jobArtifacts: [jobWithoutDownloadPath] },
- );
+ createComponent({
+ handlers: { getJobArtifactsQuery: jest.fn() },
+ data: { jobArtifacts: [jobWithoutDownloadPath] },
+ });
await waitForPromises();
@@ -285,10 +320,10 @@ describe('JobArtifactsTable component', () => {
browseArtifactsPath: null,
};
- createComponent(
- { getJobArtifactsQuery: jest.fn() },
- { jobArtifacts: [jobWithoutBrowsePath] },
- );
+ createComponent({
+ handlers: { getJobArtifactsQuery: jest.fn() },
+ data: { jobArtifacts: [jobWithoutBrowsePath] },
+ });
await waitForPromises();
@@ -298,7 +333,7 @@ describe('JobArtifactsTable component', () => {
describe('delete button', () => {
it('does not show when user does not have permission', async () => {
- createComponent({}, {}, false);
+ createComponent({ canDestroyArtifacts: false });
await waitForPromises();
@@ -314,50 +349,125 @@ describe('JobArtifactsTable component', () => {
});
});
+ describe('bulk delete', () => {
+ describe('with permission and feature flag enabled', () => {
+ beforeEach(async () => {
+ createComponent({
+ canDestroyArtifacts: true,
+ glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true },
+ });
+
+ await waitForPromises();
+ });
+
+ it('shows selected artifacts when a job is checked', async () => {
+ expect(findBulkDelete().exists()).toBe(false);
+
+ await findJobCheckbox().vm.$emit('input', true);
+
+ expect(findBulkDelete().exists()).toBe(true);
+ expect(findBulkDelete().props('selectedArtifacts')).toStrictEqual(
+ job.artifacts.nodes.map((node) => node.id),
+ );
+ });
+
+ it('disappears when selected artifacts are cleared', async () => {
+ await findJobCheckbox().vm.$emit('input', true);
+
+ expect(findBulkDelete().exists()).toBe(true);
+
+ await findBulkDelete().vm.$emit('clearSelectedArtifacts');
+
+ expect(findBulkDelete().exists()).toBe(false);
+ });
+
+ it('shows a toast when artifacts are deleted', async () => {
+ const count = job.artifacts.nodes.length;
+
+ await findJobCheckbox().vm.$emit('input', true);
+ findBulkDelete().vm.$emit('deleted', count);
+
+ expect(mockToastShow).toHaveBeenCalledWith(`${count} selected artifacts deleted`);
+ });
+ });
+
+ it('shows no checkboxes without permission', async () => {
+ createComponent({
+ canDestroyArtifacts: false,
+ glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true },
+ });
+
+ await waitForPromises();
+
+ expect(findAnyCheckbox().exists()).toBe(false);
+ });
+
+ it('shows no checkboxes with feature flag disabled', async () => {
+ createComponent({
+ canDestroyArtifacts: true,
+ glFeatures: { [BULK_DELETE_FEATURE_FLAG]: false },
+ });
+
+ await waitForPromises();
+
+ expect(findAnyCheckbox().exists()).toBe(false);
+ });
+ });
+
describe('pagination', () => {
- const { pageInfo } = getJobArtifactsResponse.data.project.jobs;
+ const { pageInfo } = getJobArtifactsResponseThatPaginates.data.project.jobs;
+ const query = jest.fn().mockResolvedValue(getJobArtifactsResponseThatPaginates);
beforeEach(async () => {
- createComponent(
- {
- getJobArtifactsQuery: jest.fn().mockResolvedValue(getJobArtifactsResponseThatPaginates),
+ createComponent({
+ handlers: {
+ getJobArtifactsQuery: query,
},
- {
- count: enoughJobsToPaginate.length,
- pageInfo,
- },
- );
+ data: { pageInfo },
+ });
await waitForPromises();
});
it('renders pagination and passes page props', () => {
- expect(findPagination().exists()).toBe(true);
expect(findPagination().props()).toMatchObject({
- value: wrapper.vm.pagination.currentPage,
- prevPage: wrapper.vm.prevPage,
- nextPage: wrapper.vm.nextPage,
+ value: INITIAL_CURRENT_PAGE,
+ prevPage: Number(pageInfo.hasPreviousPage),
+ nextPage: Number(pageInfo.hasNextPage),
+ });
+
+ expect(query).toHaveBeenCalledWith({
+ projectPath: 'project/path',
+ firstPageSize: JOBS_PER_PAGE,
+ lastPageSize: null,
+ nextPageCursor: '',
+ prevPageCursor: '',
});
});
- it('updates query variables when going to previous page', () => {
- return setPage(1).then(() => {
- expect(wrapper.vm.queryVariables).toMatchObject({
- projectPath: 'project/path',
- nextPageCursor: undefined,
- prevPageCursor: pageInfo.startCursor,
- });
+ it('updates query variables when going to previous page', async () => {
+ await setPage(1);
+
+ expect(query).toHaveBeenLastCalledWith({
+ projectPath: 'project/path',
+ firstPageSize: null,
+ lastPageSize: JOBS_PER_PAGE,
+ prevPageCursor: pageInfo.startCursor,
});
+ expect(findPagination().props('value')).toEqual(1);
});
- it('updates query variables when going to next page', () => {
- return setPage(2).then(() => {
- expect(wrapper.vm.queryVariables).toMatchObject({
- lastPageSize: null,
- nextPageCursor: pageInfo.endCursor,
- prevPageCursor: '',
- });
+ it('updates query variables when going to next page', async () => {
+ await setPage(2);
+
+ expect(query).toHaveBeenLastCalledWith({
+ projectPath: 'project/path',
+ firstPageSize: JOBS_PER_PAGE,
+ lastPageSize: null,
+ prevPageCursor: '',
+ nextPageCursor: pageInfo.endCursor,
});
+ expect(findPagination().props('value')).toEqual(2);
});
});
});
diff --git a/spec/frontend/artifacts/components/job_checkbox_spec.js b/spec/frontend/artifacts/components/job_checkbox_spec.js
new file mode 100644
index 00000000000..95cc548b8c8
--- /dev/null
+++ b/spec/frontend/artifacts/components/job_checkbox_spec.js
@@ -0,0 +1,71 @@
+import { GlFormCheckbox } from '@gitlab/ui';
+import mockGetJobArtifactsResponse from 'test_fixtures/graphql/artifacts/graphql/queries/get_job_artifacts.query.graphql.json';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import JobCheckbox from '~/artifacts/components/job_checkbox.vue';
+
+describe('JobCheckbox component', () => {
+ let wrapper;
+
+ const mockArtifactNodes = mockGetJobArtifactsResponse.data.project.jobs.nodes[0].artifacts.nodes;
+ const mockSelectedArtifacts = [mockArtifactNodes[0], mockArtifactNodes[1]];
+ const mockUnselectedArtifacts = [mockArtifactNodes[2]];
+
+ const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
+
+ const createComponent = ({
+ hasArtifacts = true,
+ selectedArtifacts = mockSelectedArtifacts,
+ unselectedArtifacts = mockUnselectedArtifacts,
+ } = {}) => {
+ wrapper = shallowMountExtended(JobCheckbox, {
+ propsData: {
+ hasArtifacts,
+ selectedArtifacts,
+ unselectedArtifacts,
+ },
+ mocks: { GlFormCheckbox },
+ });
+ };
+
+ it('is disabled when the job has no artifacts', () => {
+ createComponent({ hasArtifacts: false });
+
+ expect(findCheckbox().attributes('disabled')).toBe('true');
+ });
+
+ describe('when some artifacts are selected', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('is indeterminate', () => {
+ expect(findCheckbox().attributes('indeterminate')).toBe('true');
+ expect(findCheckbox().attributes('checked')).toBeUndefined();
+ });
+
+ it('selects the unselected artifacts on click', () => {
+ findCheckbox().vm.$emit('input', true);
+
+ expect(wrapper.emitted('selectArtifact')).toMatchObject([[mockUnselectedArtifacts[0], true]]);
+ });
+ });
+
+ describe('when all artifacts are selected', () => {
+ beforeEach(() => {
+ createComponent({ unselectedArtifacts: [] });
+ });
+
+ it('is checked', () => {
+ expect(findCheckbox().attributes('checked')).toBe('true');
+ });
+
+ it('deselects the selected artifacts on click', () => {
+ findCheckbox().vm.$emit('input', false);
+
+ expect(wrapper.emitted('selectArtifact')).toMatchObject([
+ [mockSelectedArtifacts[0], false],
+ [mockSelectedArtifacts[1], false],
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js b/spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js
index ca94acfa444..efdebe5f3b0 100644
--- a/spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js
+++ b/spec/frontend/artifacts_settings/components/keep_latest_artifact_checkbox_spec.js
@@ -78,8 +78,6 @@ describe('Keep latest artifact checkbox', () => {
};
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
apolloProvider = null;
});
diff --git a/spec/frontend/authentication/u2f/authenticate_spec.js b/spec/frontend/authentication/u2f/authenticate_spec.js
deleted file mode 100644
index 3ae7fcf1c49..00000000000
--- a/spec/frontend/authentication/u2f/authenticate_spec.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import $ from 'jquery';
-import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import U2FAuthenticate from '~/authentication/u2f/authenticate';
-import 'vendor/u2f';
-import MockU2FDevice from './mock_u2f_device';
-
-describe('U2FAuthenticate', () => {
- let u2fDevice;
- let container;
- let component;
-
- beforeEach(() => {
- loadHTMLFixture('u2f/authenticate.html');
- u2fDevice = new MockU2FDevice();
- container = $('#js-authenticate-token-2fa');
- component = new U2FAuthenticate(
- container,
- '#js-login-token-2fa-form',
- {
- sign_requests: [],
- },
- document.querySelector('#js-login-2fa-device'),
- document.querySelector('.js-2fa-form'),
- );
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- describe('with u2f unavailable', () => {
- let oldu2f;
-
- beforeEach(() => {
- jest.spyOn(component, 'switchToFallbackUI').mockImplementation(() => {});
- oldu2f = window.u2f;
- window.u2f = null;
- });
-
- afterEach(() => {
- window.u2f = oldu2f;
- });
-
- it('falls back to normal 2fa', async () => {
- await component.start();
- expect(component.switchToFallbackUI).toHaveBeenCalled();
- });
- });
-
- describe('with u2f available', () => {
- beforeEach(() => {
- // bypass automatic form submission within renderAuthenticated
- jest.spyOn(component, 'renderAuthenticated').mockReturnValue(true);
- u2fDevice = new MockU2FDevice();
-
- return component.start();
- });
-
- it('allows authenticating via a U2F device', () => {
- const inProgressMessage = container.find('p');
-
- expect(inProgressMessage.text()).toContain('Trying to communicate with your device');
- u2fDevice.respondToAuthenticateRequest({
- deviceData: 'this is data from the device',
- });
-
- expect(component.renderAuthenticated).toHaveBeenCalledWith(
- '{"deviceData":"this is data from the device"}',
- );
- });
-
- describe('errors', () => {
- it('displays an error message', () => {
- const setupButton = container.find('#js-login-2fa-device');
- setupButton.trigger('click');
- u2fDevice.respondToAuthenticateRequest({
- errorCode: 'error!',
- });
- const errorMessage = container.find('p');
-
- expect(errorMessage.text()).toContain('There was a problem communicating with your device');
- });
-
- it('allows retrying authentication after an error', () => {
- let setupButton = container.find('#js-login-2fa-device');
- setupButton.trigger('click');
- u2fDevice.respondToAuthenticateRequest({
- errorCode: 'error!',
- });
- const retryButton = container.find('#js-token-2fa-try-again');
- retryButton.trigger('click');
- setupButton = container.find('#js-login-2fa-device');
- setupButton.trigger('click');
- u2fDevice.respondToAuthenticateRequest({
- deviceData: 'this is data from the device',
- });
-
- expect(component.renderAuthenticated).toHaveBeenCalledWith(
- '{"deviceData":"this is data from the device"}',
- );
- });
- });
- });
-});
diff --git a/spec/frontend/authentication/u2f/mock_u2f_device.js b/spec/frontend/authentication/u2f/mock_u2f_device.js
deleted file mode 100644
index ec8425a4e3e..00000000000
--- a/spec/frontend/authentication/u2f/mock_u2f_device.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable no-unused-expressions */
-
-export default class MockU2FDevice {
- constructor() {
- this.respondToAuthenticateRequest = this.respondToAuthenticateRequest.bind(this);
- this.respondToRegisterRequest = this.respondToRegisterRequest.bind(this);
- window.u2f || (window.u2f = {});
- window.u2f.register = (appId, registerRequests, signRequests, callback) => {
- this.registerCallback = callback;
- };
- window.u2f.sign = (appId, challenges, signRequests, callback) => {
- this.authenticateCallback = callback;
- };
- }
-
- respondToRegisterRequest(params) {
- return this.registerCallback(params);
- }
-
- respondToAuthenticateRequest(params) {
- return this.authenticateCallback(params);
- }
-}
diff --git a/spec/frontend/authentication/u2f/register_spec.js b/spec/frontend/authentication/u2f/register_spec.js
deleted file mode 100644
index 23d1e5c7dee..00000000000
--- a/spec/frontend/authentication/u2f/register_spec.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import $ from 'jquery';
-import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import { trimText } from 'helpers/text_helper';
-import U2FRegister from '~/authentication/u2f/register';
-import 'vendor/u2f';
-import MockU2FDevice from './mock_u2f_device';
-
-describe('U2FRegister', () => {
- let u2fDevice;
- let container;
- let component;
-
- beforeEach(() => {
- loadHTMLFixture('u2f/register.html');
- u2fDevice = new MockU2FDevice();
- container = $('#js-register-token-2fa');
- component = new U2FRegister(container, {});
- return component.start();
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- it('allows registering a U2F device', () => {
- const setupButton = container.find('#js-setup-token-2fa-device');
-
- expect(trimText(setupButton.text())).toBe('Set up new device');
- setupButton.trigger('click');
- const inProgressMessage = container.children('p');
-
- expect(inProgressMessage.text()).toContain('Trying to communicate with your device');
- u2fDevice.respondToRegisterRequest({
- deviceData: 'this is data from the device',
- });
- const registeredMessage = container.find('p');
- const deviceResponse = container.find('#js-device-response');
-
- expect(registeredMessage.text()).toContain('Your device was successfully set up!');
- expect(deviceResponse.val()).toBe('{"deviceData":"this is data from the device"}');
- });
-
- describe('errors', () => {
- it("doesn't allow the same device to be registered twice (for the same user", () => {
- const setupButton = container.find('#js-setup-token-2fa-device');
- setupButton.trigger('click');
- u2fDevice.respondToRegisterRequest({
- errorCode: 4,
- });
- const errorMessage = container.find('p');
-
- expect(errorMessage.text()).toContain('already been registered with us');
- });
-
- it('displays an error message for other errors', () => {
- const setupButton = container.find('#js-setup-token-2fa-device');
- setupButton.trigger('click');
- u2fDevice.respondToRegisterRequest({
- errorCode: 'error!',
- });
- const errorMessage = container.find('p');
-
- expect(errorMessage.text()).toContain('There was a problem communicating with your device');
- });
-
- it('allows retrying registration after an error', () => {
- let setupButton = container.find('#js-setup-token-2fa-device');
- setupButton.trigger('click');
- u2fDevice.respondToRegisterRequest({
- errorCode: 'error!',
- });
- const retryButton = container.find('#js-token-2fa-try-again');
- retryButton.trigger('click');
- setupButton = container.find('#js-setup-token-2fa-device');
- setupButton.trigger('click');
- u2fDevice.respondToRegisterRequest({
- deviceData: 'this is data from the device',
- });
- const registeredMessage = container.find('p');
-
- expect(registeredMessage.text()).toContain('Your device was successfully set up!');
- });
- });
-});
diff --git a/spec/frontend/authentication/u2f/util_spec.js b/spec/frontend/authentication/u2f/util_spec.js
deleted file mode 100644
index 67fd4c73243..00000000000
--- a/spec/frontend/authentication/u2f/util_spec.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import { canInjectU2fApi } from '~/authentication/u2f/util';
-
-describe('U2F Utils', () => {
- describe('canInjectU2fApi', () => {
- it('returns false for Chrome < 41', () => {
- const userAgent =
- 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.28 Safari/537.36';
-
- expect(canInjectU2fApi(userAgent)).toBe(false);
- });
-
- it('returns true for Chrome >= 41', () => {
- const userAgent =
- 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36';
-
- expect(canInjectU2fApi(userAgent)).toBe(true);
- });
-
- it('returns false for Opera < 40', () => {
- const userAgent =
- 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36 OPR/32.0.1948.25';
-
- expect(canInjectU2fApi(userAgent)).toBe(false);
- });
-
- it('returns true for Opera >= 40', () => {
- const userAgent =
- 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.991';
-
- expect(canInjectU2fApi(userAgent)).toBe(true);
- });
-
- it('returns false for Safari', () => {
- const userAgent =
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4';
-
- expect(canInjectU2fApi(userAgent)).toBe(false);
- });
-
- it('returns false for Chrome on Android', () => {
- const userAgent =
- 'Mozilla/5.0 (Linux; Android 7.0; VS988 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3145.0 Mobile Safari/537.36';
-
- expect(canInjectU2fApi(userAgent)).toBe(false);
- });
-
- it('returns false for Chrome on iOS', () => {
- const userAgent =
- 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1';
-
- expect(canInjectU2fApi(userAgent)).toBe(false);
- });
-
- it('returns false for Safari on iOS', () => {
- const userAgent =
- 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A356 Safari/604.1';
-
- expect(canInjectU2fApi(userAgent)).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/authentication/webauthn/components/registration_spec.js b/spec/frontend/authentication/webauthn/components/registration_spec.js
new file mode 100644
index 00000000000..1221626db7d
--- /dev/null
+++ b/spec/frontend/authentication/webauthn/components/registration_spec.js
@@ -0,0 +1,255 @@
+import { nextTick } from 'vue';
+import { GlAlert, GlButton, GlForm, GlLoadingIcon } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import Registration from '~/authentication/webauthn/components/registration.vue';
+import {
+ I18N_BUTTON_REGISTER,
+ I18N_BUTTON_SETUP,
+ I18N_BUTTON_TRY_AGAIN,
+ I18N_ERROR_HTTP,
+ I18N_ERROR_UNSUPPORTED_BROWSER,
+ I18N_INFO_TEXT,
+ I18N_STATUS_SUCCESS,
+ I18N_STATUS_WAITING,
+ STATE_ERROR,
+ STATE_READY,
+ STATE_SUCCESS,
+ STATE_UNSUPPORTED,
+ STATE_WAITING,
+ WEBAUTHN_REGISTER,
+} from '~/authentication/webauthn/constants';
+import * as WebAuthnUtils from '~/authentication/webauthn/util';
+import WebAuthnError from '~/authentication/webauthn/error';
+
+const csrfToken = 'mock-csrf-token';
+jest.mock('~/lib/utils/csrf', () => ({ token: csrfToken }));
+jest.mock('~/authentication/webauthn/util');
+jest.mock('~/authentication/webauthn/error');
+
+describe('Registration', () => {
+ const initialError = null;
+ const passwordRequired = true;
+ const targetPath = '/-/profile/two_factor_auth/create_webauthn';
+ let wrapper;
+
+ const createComponent = (provide = {}) => {
+ wrapper = shallowMountExtended(Registration, {
+ provide: { initialError, passwordRequired, targetPath, ...provide },
+ });
+ };
+
+ const findButton = () => wrapper.findComponent(GlButton);
+
+ describe(`when ${STATE_UNSUPPORTED} state`, () => {
+ it('shows an error if using unsecure scheme (HTTP)', () => {
+ // `supported` function returns false for HTTP because `navigator.credentials` is undefined.
+ WebAuthnUtils.supported.mockReturnValue(false);
+ WebAuthnUtils.isHTTPS.mockReturnValue(false);
+ createComponent();
+
+ const alert = wrapper.findComponent(GlAlert);
+ expect(alert.props('variant')).toBe('danger');
+ expect(alert.text()).toBe(I18N_ERROR_HTTP);
+ });
+
+ it('shows an error if using unsupported browser', () => {
+ WebAuthnUtils.supported.mockReturnValue(false);
+ WebAuthnUtils.isHTTPS.mockReturnValue(true);
+ createComponent();
+
+ const alert = wrapper.findComponent(GlAlert);
+ expect(alert.props('variant')).toBe('danger');
+ expect(alert.text()).toBe(I18N_ERROR_UNSUPPORTED_BROWSER);
+ });
+ });
+
+ describe('when scheme or browser are supported', () => {
+ const mockCreate = jest.fn();
+
+ const clickSetupDeviceButton = () => {
+ findButton().vm.$emit('click');
+ return nextTick();
+ };
+
+ const setupDevice = () => {
+ clickSetupDeviceButton();
+ return waitForPromises();
+ };
+
+ beforeEach(() => {
+ WebAuthnUtils.isHTTPS.mockReturnValue(true);
+ WebAuthnUtils.supported.mockReturnValue(true);
+ global.navigator.credentials = { create: mockCreate };
+ gon.webauthn = { options: {} };
+ });
+
+ afterEach(() => {
+ global.navigator.credentials = undefined;
+ });
+
+ describe(`when ${STATE_READY} state`, () => {
+ it('shows button and explanation text', () => {
+ createComponent();
+
+ expect(findButton().text()).toBe(I18N_BUTTON_SETUP);
+ expect(wrapper.text()).toContain(I18N_INFO_TEXT);
+ });
+ });
+
+ describe(`when ${STATE_WAITING} state`, () => {
+ it('shows loading icon and message after pressing the button', async () => {
+ createComponent();
+
+ await clickSetupDeviceButton();
+
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.text()).toContain(I18N_STATUS_WAITING);
+ });
+ });
+
+ describe(`when ${STATE_SUCCESS} state`, () => {
+ const credentials = 1;
+
+ const findCurrentPasswordInput = () => wrapper.findByTestId('current-password-input');
+ const findDeviceNameInput = () => wrapper.findByTestId('device-name-input');
+
+ beforeEach(() => {
+ mockCreate.mockResolvedValueOnce(true);
+ WebAuthnUtils.convertCreateResponse.mockReturnValue(credentials);
+ });
+
+ describe('registration form', () => {
+ it('has correct action', async () => {
+ createComponent();
+
+ await setupDevice();
+
+ expect(wrapper.findComponent(GlForm).attributes('action')).toBe(targetPath);
+ });
+
+ describe('when password is required', () => {
+ it('shows device name and password fields', async () => {
+ createComponent();
+
+ await setupDevice();
+
+ expect(wrapper.text()).toContain(I18N_STATUS_SUCCESS);
+
+ // Visible inputs
+ expect(findCurrentPasswordInput().attributes('name')).toBe('current_password');
+ expect(findDeviceNameInput().attributes('name')).toBe('device_registration[name]');
+
+ // Hidden inputs
+ expect(
+ wrapper
+ .find('input[name="device_registration[device_response]"]')
+ .attributes('value'),
+ ).toBe(`${credentials}`);
+ expect(wrapper.find('input[name=authenticity_token]').attributes('value')).toBe(
+ csrfToken,
+ );
+
+ expect(findButton().text()).toBe(I18N_BUTTON_REGISTER);
+ });
+
+ it('enables the register device button when device name and password are filled', async () => {
+ createComponent();
+
+ await setupDevice();
+
+ expect(findButton().props('disabled')).toBe(true);
+
+ // Visible inputs
+ findCurrentPasswordInput().vm.$emit('input', 'my current password');
+ findDeviceNameInput().vm.$emit('input', 'my device name');
+ await nextTick();
+
+ expect(findButton().props('disabled')).toBe(false);
+ });
+ });
+
+ describe('when password is not required', () => {
+ it('shows a device name field', async () => {
+ createComponent({ passwordRequired: false });
+
+ await setupDevice();
+
+ expect(wrapper.text()).toContain(I18N_STATUS_SUCCESS);
+
+ // Visible inputs
+ expect(findCurrentPasswordInput().exists()).toBe(false);
+ expect(findDeviceNameInput().attributes('name')).toBe('device_registration[name]');
+
+ // Hidden inputs
+ expect(
+ wrapper
+ .find('input[name="device_registration[device_response]"]')
+ .attributes('value'),
+ ).toBe(`${credentials}`);
+ expect(wrapper.find('input[name=authenticity_token]').attributes('value')).toBe(
+ csrfToken,
+ );
+
+ expect(findButton().text()).toBe(I18N_BUTTON_REGISTER);
+ });
+
+ it('enables the register device button when device name is filled', async () => {
+ createComponent({ passwordRequired: false });
+
+ await setupDevice();
+
+ expect(findButton().props('disabled')).toBe(true);
+
+ findDeviceNameInput().vm.$emit('input', 'my device name');
+ await nextTick();
+
+ expect(findButton().props('disabled')).toBe(false);
+ });
+ });
+ });
+ });
+
+ describe(`when ${STATE_ERROR} state`, () => {
+ it('shows an initial error message and a retry button', async () => {
+ const myError = 'my error';
+ createComponent({ initialError: myError });
+
+ const alert = wrapper.findComponent(GlAlert);
+ expect(alert.props()).toMatchObject({
+ variant: 'danger',
+ secondaryButtonText: I18N_BUTTON_TRY_AGAIN,
+ });
+ expect(alert.text()).toContain(myError);
+ });
+
+ it('shows an error message and a retry button', async () => {
+ createComponent();
+ const error = new Error();
+ mockCreate.mockRejectedValueOnce(error);
+
+ await setupDevice();
+
+ expect(WebAuthnError).toHaveBeenCalledWith(error, WEBAUTHN_REGISTER);
+ expect(wrapper.findComponent(GlAlert).props()).toMatchObject({
+ variant: 'danger',
+ secondaryButtonText: I18N_BUTTON_TRY_AGAIN,
+ });
+ });
+
+ it('recovers after an error (error to success state)', async () => {
+ createComponent();
+ mockCreate.mockRejectedValueOnce(new Error()).mockResolvedValueOnce(true);
+
+ await setupDevice();
+
+ expect(wrapper.findComponent(GlAlert).props('variant')).toBe('danger');
+
+ wrapper.findComponent(GlAlert).vm.$emit('secondaryAction');
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlAlert).props('variant')).toBe('info');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/authentication/webauthn/error_spec.js b/spec/frontend/authentication/webauthn/error_spec.js
index 9b71f77dde2..b979173edc6 100644
--- a/spec/frontend/authentication/webauthn/error_spec.js
+++ b/spec/frontend/authentication/webauthn/error_spec.js
@@ -1,16 +1,17 @@
import setWindowLocation from 'helpers/set_window_location_helper';
import WebAuthnError from '~/authentication/webauthn/error';
+import { WEBAUTHN_AUTHENTICATE, WEBAUTHN_REGISTER } from '~/authentication/webauthn/constants';
describe('WebAuthnError', () => {
it.each([
[
'NotSupportedError',
'Your device is not compatible with GitLab. Please try another device',
- 'authenticate',
+ WEBAUTHN_AUTHENTICATE,
],
- ['InvalidStateError', 'This device has not been registered with us.', 'authenticate'],
- ['InvalidStateError', 'This device has already been registered with us.', 'register'],
- ['UnknownError', 'There was a problem communicating with your device.', 'register'],
+ ['InvalidStateError', 'This device has not been registered with us.', WEBAUTHN_AUTHENTICATE],
+ ['InvalidStateError', 'This device has already been registered with us.', WEBAUTHN_REGISTER],
+ ['UnknownError', 'There was a problem communicating with your device.', WEBAUTHN_REGISTER],
])('exception %s will have message %s, flow type: %s', (exception, expectedMessage, flowType) => {
expect(new WebAuthnError(new DOMException('', exception), flowType).message()).toEqual(
expectedMessage,
@@ -24,7 +25,7 @@ describe('WebAuthnError', () => {
const expectedMessage =
'WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details.';
expect(
- new WebAuthnError(new DOMException('', 'SecurityError'), 'authenticate').message(),
+ new WebAuthnError(new DOMException('', 'SecurityError'), WEBAUTHN_AUTHENTICATE).message(),
).toEqual(expectedMessage);
});
@@ -33,7 +34,7 @@ describe('WebAuthnError', () => {
const expectedMessage = 'There was a problem communicating with your device.';
expect(
- new WebAuthnError(new DOMException('', 'SecurityError'), 'authenticate').message(),
+ new WebAuthnError(new DOMException('', 'SecurityError'), WEBAUTHN_AUTHENTICATE).message(),
).toEqual(expectedMessage);
});
});
diff --git a/spec/frontend/authentication/webauthn/util_spec.js b/spec/frontend/authentication/webauthn/util_spec.js
index bc44b47d0ba..831d1636b8c 100644
--- a/spec/frontend/authentication/webauthn/util_spec.js
+++ b/spec/frontend/authentication/webauthn/util_spec.js
@@ -1,4 +1,9 @@
-import { base64ToBuffer, bufferToBase64, base64ToBase64Url } from '~/authentication/webauthn/util';
+import {
+ base64ToBuffer,
+ bufferToBase64,
+ base64ToBase64Url,
+ supported,
+} from '~/authentication/webauthn/util';
const encodedString = 'SGVsbG8gd29ybGQh';
const stringBytes = [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33];
@@ -31,4 +36,28 @@ describe('Webauthn utils', () => {
expect(base64ToBase64Url(argument)).toBe(expectedResult);
});
});
+
+ describe('supported', () => {
+ afterEach(() => {
+ global.navigator.credentials = undefined;
+ window.PublicKeyCredential = undefined;
+ });
+
+ it.each`
+ credentials | PublicKeyCredential | expected
+ ${undefined} | ${undefined} | ${false}
+ ${{}} | ${undefined} | ${false}
+ ${{ create: true }} | ${undefined} | ${false}
+ ${{ create: true, get: true }} | ${undefined} | ${false}
+ ${{ create: true, get: true }} | ${true} | ${true}
+ `(
+ 'returns $expected when credentials is $credentials and PublicKeyCredential is $PublicKeyCredential',
+ ({ credentials, PublicKeyCredential, expected }) => {
+ global.navigator.credentials = credentials;
+ window.PublicKeyCredential = PublicKeyCredential;
+
+ expect(supported()).toBe(expected);
+ },
+ );
+ });
});
diff --git a/spec/frontend/awards_handler_spec.js b/spec/frontend/awards_handler_spec.js
index 1a54b9909ba..35a1603d375 100644
--- a/spec/frontend/awards_handler_spec.js
+++ b/spec/frontend/awards_handler_spec.js
@@ -6,10 +6,8 @@ import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_fra
import loadAwardsHandler from '~/awards_handler';
window.gl = window.gl || {};
-window.gon = window.gon || {};
let awardsHandler = null;
-const urlRoot = gon.relative_url_root;
describe('AwardsHandler', () => {
useFakeRequestAnimationFrame();
@@ -95,9 +93,6 @@ describe('AwardsHandler', () => {
});
afterEach(() => {
- // restore original url root value
- gon.relative_url_root = urlRoot;
-
clearEmojiMock();
// Undo what we did to the shared <body>
diff --git a/spec/frontend/badges/components/badge_form_spec.js b/spec/frontend/badges/components/badge_form_spec.js
index 0a736df7075..d7519f1f80d 100644
--- a/spec/frontend/badges/components/badge_form_spec.js
+++ b/spec/frontend/badges/components/badge_form_spec.js
@@ -43,7 +43,6 @@ describe('BadgeForm component', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
});
diff --git a/spec/frontend/badges/components/badge_list_row_spec.js b/spec/frontend/badges/components/badge_list_row_spec.js
index ee7ccac974a..cbbeb36ff33 100644
--- a/spec/frontend/badges/components/badge_list_row_spec.js
+++ b/spec/frontend/badges/components/badge_list_row_spec.js
@@ -43,7 +43,6 @@ describe('BadgeListRow component', () => {
};
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/badges/components/badge_list_spec.js b/spec/frontend/badges/components/badge_list_spec.js
index 606b1bc9cce..374b7b50af4 100644
--- a/spec/frontend/badges/components/badge_list_spec.js
+++ b/spec/frontend/badges/components/badge_list_spec.js
@@ -38,10 +38,6 @@ describe('BadgeList component', () => {
wrapper = mount(BadgeList, { store });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('for project badges', () => {
it('renders a header with the badge count', () => {
createComponent({
diff --git a/spec/frontend/badges/components/badge_settings_spec.js b/spec/frontend/badges/components/badge_settings_spec.js
index bddb6d3801c..7ad2c99869c 100644
--- a/spec/frontend/badges/components/badge_settings_spec.js
+++ b/spec/frontend/badges/components/badge_settings_spec.js
@@ -32,10 +32,6 @@ describe('BadgeSettings component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays modal if button for deleting a badge is clicked', async () => {
const button = wrapper.find('[data-testid="delete-badge"]');
diff --git a/spec/frontend/badges/components/badge_spec.js b/spec/frontend/badges/components/badge_spec.js
index b468e38f19e..c933c1b5434 100644
--- a/spec/frontend/badges/components/badge_spec.js
+++ b/spec/frontend/badges/components/badge_spec.js
@@ -24,10 +24,6 @@ describe('Badge component', () => {
wrapper = mount(Badge, { propsData });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
return createComponent({ ...dummyProps }, '#dummy-element');
});
diff --git a/spec/frontend/batch_comments/components/diff_file_drafts_spec.js b/spec/frontend/batch_comments/components/diff_file_drafts_spec.js
index c922d6a9809..f667ebc0fcb 100644
--- a/spec/frontend/batch_comments/components/diff_file_drafts_spec.js
+++ b/spec/frontend/batch_comments/components/diff_file_drafts_spec.js
@@ -28,10 +28,6 @@ describe('Batch comments diff file drafts component', () => {
});
}
- afterEach(() => {
- vm.destroy();
- });
-
it('renders list of draft notes', () => {
factory();
diff --git a/spec/frontend/batch_comments/components/draft_note_spec.js b/spec/frontend/batch_comments/components/draft_note_spec.js
index 924d88866ee..159e36c1364 100644
--- a/spec/frontend/batch_comments/components/draft_note_spec.js
+++ b/spec/frontend/batch_comments/components/draft_note_spec.js
@@ -49,10 +49,6 @@ describe('Batch comments draft note component', () => {
draft = createDraft();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders template', () => {
createComponent();
expect(wrapper.findComponent(GlBadge).exists()).toBe(true);
diff --git a/spec/frontend/batch_comments/components/drafts_count_spec.js b/spec/frontend/batch_comments/components/drafts_count_spec.js
index c3a7946c85c..850a7efb4ed 100644
--- a/spec/frontend/batch_comments/components/drafts_count_spec.js
+++ b/spec/frontend/batch_comments/components/drafts_count_spec.js
@@ -15,10 +15,6 @@ describe('Batch comments drafts count component', () => {
wrapper = mount(DraftsCount, { store });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders count', () => {
expect(wrapper.text()).toContain('1');
});
diff --git a/spec/frontend/batch_comments/components/preview_dropdown_spec.js b/spec/frontend/batch_comments/components/preview_dropdown_spec.js
index f86e003ab5f..3a28bf4ade8 100644
--- a/spec/frontend/batch_comments/components/preview_dropdown_spec.js
+++ b/spec/frontend/batch_comments/components/preview_dropdown_spec.js
@@ -1,7 +1,6 @@
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
-import { GlDisclosureDropdown } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { mount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
import { visitUrl } from '~/lib/utils/url_utility';
import PreviewDropdown from '~/batch_comments/components/preview_dropdown.vue';
@@ -46,9 +45,11 @@ function factory({ viewDiffsFileByFile = false, draftsCount = 1, sortedDrafts =
},
});
- wrapper = shallowMount(PreviewDropdown, {
+ wrapper = mount(PreviewDropdown, {
store,
- stubs: { GlDisclosureDropdown },
+ stubs: {
+ PreviewItem: true,
+ },
});
}
@@ -59,12 +60,12 @@ describe('Batch comments preview dropdown', () => {
viewDiffsFileByFile: true,
sortedDrafts: [{ id: 1, file_hash: 'hash' }],
});
-
- findPreviewItem().vm.$emit('click');
-
+ findPreviewItem().trigger('click');
await nextTick();
expect(setCurrentFileHash).toHaveBeenCalledWith(expect.anything(), 'hash');
+
+ await nextTick();
expect(scrollToDraft).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ id: 1, file_hash: 'hash' }),
@@ -77,7 +78,7 @@ describe('Batch comments preview dropdown', () => {
sortedDrafts: [{ id: 1 }],
});
- findPreviewItem().vm.$emit('click');
+ findPreviewItem().trigger('click');
await nextTick();
@@ -93,7 +94,7 @@ describe('Batch comments preview dropdown', () => {
sortedDrafts: [{ id: 1, position: { head_sha: '1234' } }],
});
- findPreviewItem().vm.$emit('click');
+ findPreviewItem().trigger('click');
await nextTick();
diff --git a/spec/frontend/batch_comments/components/preview_item_spec.js b/spec/frontend/batch_comments/components/preview_item_spec.js
index 6a99294f855..a19a72af813 100644
--- a/spec/frontend/batch_comments/components/preview_item_spec.js
+++ b/spec/frontend/batch_comments/components/preview_item_spec.js
@@ -26,10 +26,6 @@ describe('Batch comments draft preview item component', () => {
wrapper = mount(PreviewItem, { store, propsData: { draft, isLast } });
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders text content', () => {
createComponent(false, { note_html: '<img src="" /><p>Hello world</p>' });
diff --git a/spec/frontend/batch_comments/components/review_bar_spec.js b/spec/frontend/batch_comments/components/review_bar_spec.js
index 0a4c9ff62e4..923e86a7e64 100644
--- a/spec/frontend/batch_comments/components/review_bar_spec.js
+++ b/spec/frontend/batch_comments/components/review_bar_spec.js
@@ -20,10 +20,6 @@ describe('Batch comments review bar component', () => {
document.body.className = '';
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('adds review-bar-visible class to body when review bar is mounted', async () => {
expect(document.body.classList.contains(REVIEW_BAR_VISIBLE_CLASS_NAME)).toBe(false);
diff --git a/spec/frontend/batch_comments/components/submit_dropdown_spec.js b/spec/frontend/batch_comments/components/submit_dropdown_spec.js
index 003a6d86371..ac6198ec8b5 100644
--- a/spec/frontend/batch_comments/components/submit_dropdown_spec.js
+++ b/spec/frontend/batch_comments/components/submit_dropdown_spec.js
@@ -47,7 +47,6 @@ const findForm = () => wrapper.findByTestId('submit-gl-form');
describe('Batch comments submit dropdown', () => {
afterEach(() => {
- wrapper.destroy();
window.mrTabs = null;
});
diff --git a/spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js b/spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js
index 20eedcbb25b..57bafb51cd6 100644
--- a/spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js
+++ b/spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js
@@ -317,4 +317,10 @@ describe('Batch comments store actions', () => {
expect(window.mrTabs.tabShown).toHaveBeenCalledWith('diffs');
});
});
+
+ describe('clearDrafts', () => {
+ it('commits CLEAR_DRAFTS', () => {
+ return testAction(actions.clearDrafts, null, null, [{ type: 'CLEAR_DRAFTS' }], []);
+ });
+ });
});
diff --git a/spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js b/spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js
index fe01de638c2..ad6a1a38164 100644
--- a/spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js
+++ b/spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js
@@ -104,4 +104,14 @@ describe('Batch comments mutations', () => {
]);
});
});
+
+ describe(types.CLEAR_DRAFTS, () => {
+ it('clears drafts array', () => {
+ state.drafts.push({ id: 1 });
+
+ mutations[types.CLEAR_DRAFTS](state);
+
+ expect(state.drafts).toEqual([]);
+ });
+ });
});
diff --git a/spec/frontend/behaviors/components/diagram_performance_warning_spec.js b/spec/frontend/behaviors/components/diagram_performance_warning_spec.js
index c58c2bc55a9..7e6b20da4d4 100644
--- a/spec/frontend/behaviors/components/diagram_performance_warning_spec.js
+++ b/spec/frontend/behaviors/components/diagram_performance_warning_spec.js
@@ -11,10 +11,6 @@ describe('DiagramPerformanceWarning component', () => {
wrapper = shallowMount(DiagramPerformanceWarning);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders warning alert with button', () => {
expect(findAlert().props()).toMatchObject({
primaryButtonText: DiagramPerformanceWarning.i18n.buttonText,
diff --git a/spec/frontend/behaviors/components/json_table_spec.js b/spec/frontend/behaviors/components/json_table_spec.js
index 42b4a051d4d..a82310873ed 100644
--- a/spec/frontend/behaviors/components/json_table_spec.js
+++ b/spec/frontend/behaviors/components/json_table_spec.js
@@ -59,10 +59,6 @@ describe('behaviors/components/json_table', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findTable = () => wrapper.findComponent(GlTable);
const findTableCaption = () => wrapper.findByTestId('slot-table-caption');
const findFilterInput = () => wrapper.findComponent(GlFormInput);
diff --git a/spec/frontend/behaviors/copy_to_clipboard_spec.js b/spec/frontend/behaviors/copy_to_clipboard_spec.js
index c5beaa0ba5d..74a396eb8cb 100644
--- a/spec/frontend/behaviors/copy_to_clipboard_spec.js
+++ b/spec/frontend/behaviors/copy_to_clipboard_spec.js
@@ -31,7 +31,7 @@ describe('initCopyToClipboard', () => {
const defaultButtonAttributes = {
'data-clipboard-text': 'foo bar',
title,
- 'data-title': title,
+ 'data-original-title': title,
};
const createButton = (attributes = {}) => {
const combinedAttributes = { ...defaultButtonAttributes, ...attributes };
diff --git a/spec/frontend/behaviors/markdown/highlight_current_user_spec.js b/spec/frontend/behaviors/markdown/highlight_current_user_spec.js
index 38d19ac3808..ad70efdf7c3 100644
--- a/spec/frontend/behaviors/markdown/highlight_current_user_spec.js
+++ b/spec/frontend/behaviors/markdown/highlight_current_user_spec.js
@@ -22,14 +22,9 @@ describe('highlightCurrentUser', () => {
describe('without current user', () => {
beforeEach(() => {
- window.gon = window.gon || {};
window.gon.current_user_id = null;
});
- afterEach(() => {
- delete window.gon.current_user_id;
- });
-
it('does not highlight the user', () => {
const initialHtml = rootElement.outerHTML;
@@ -41,14 +36,9 @@ describe('highlightCurrentUser', () => {
describe('with current user', () => {
beforeEach(() => {
- window.gon = window.gon || {};
window.gon.current_user_id = 2;
});
- afterEach(() => {
- delete window.gon.current_user_id;
- });
-
it('highlights current user', () => {
highlightCurrentUser(elements);
diff --git a/spec/frontend/behaviors/markdown/render_observability_spec.js b/spec/frontend/behaviors/markdown/render_observability_spec.js
index c87d11742dc..f464c01ac15 100644
--- a/spec/frontend/behaviors/markdown/render_observability_spec.js
+++ b/spec/frontend/behaviors/markdown/render_observability_spec.js
@@ -1,38 +1,43 @@
+import Vue from 'vue';
+import { createWrapper } from '@vue/test-utils';
import renderObservability from '~/behaviors/markdown/render_observability';
-import * as ColorUtils from '~/lib/utils/color_utils';
+import { INLINE_EMBED_DIMENSIONS, SKELETON_VARIANT_EMBED } from '~/observability/constants';
+import ObservabilityApp from '~/observability/components/observability_app.vue';
-describe('Observability iframe renderer', () => {
- const findObservabilityIframes = (theme = 'light') =>
- document.querySelectorAll(`iframe[src="https://observe.gitlab.com/?theme=${theme}&kiosk"]`);
-
- const renderEmbeddedObservability = () => {
- renderObservability([...document.querySelectorAll('.js-render-observability')]);
- jest.runAllTimers();
- };
+describe('renderObservability', () => {
+ let subject;
beforeEach(() => {
- document.body.dataset.page = '';
- document.body.innerHTML = '';
+ subject = document.createElement('div');
+ subject.classList.add('js-render-observability');
+ subject.dataset.frameUrl = 'https://observe.gitlab.com/';
+ document.body.appendChild(subject);
});
- it('renders an observability iframe', () => {
- document.body.innerHTML = `<div class="js-render-observability" data-frame-url="https://observe.gitlab.com/"></div>`;
-
- expect(findObservabilityIframes()).toHaveLength(0);
-
- renderEmbeddedObservability();
-
- expect(findObservabilityIframes()).toHaveLength(1);
+ afterEach(() => {
+ subject.remove();
});
- it('renders iframe with dark param when GL has dark theme', () => {
- document.body.innerHTML = `<div class="js-render-observability" data-frame-url="https://observe.gitlab.com/"></div>`;
- jest.spyOn(ColorUtils, 'darkModeEnabled').mockImplementation(() => true);
+ it('should return an array of Vue instances', () => {
+ const vueInstances = renderObservability([
+ ...document.querySelectorAll('.js-render-observability'),
+ ]);
+ expect(vueInstances).toEqual([expect.any(Vue)]);
+ });
- expect(findObservabilityIframes('dark')).toHaveLength(0);
+ it('should correctly pass props to the ObservabilityApp component', () => {
+ const vueInstances = renderObservability([
+ ...document.querySelectorAll('.js-render-observability'),
+ ]);
- renderEmbeddedObservability();
+ const wrapper = createWrapper(vueInstances[0]);
- expect(findObservabilityIframes('dark')).toHaveLength(1);
+ expect(wrapper.findComponent(ObservabilityApp).props()).toMatchObject({
+ observabilityIframeSrc: 'https://observe.gitlab.com/',
+ skeletonVariant: SKELETON_VARIANT_EMBED,
+ inlineEmbed: true,
+ height: INLINE_EMBED_DIMENSIONS.HEIGHT,
+ width: INLINE_EMBED_DIMENSIONS.WIDTH,
+ });
});
});
diff --git a/spec/frontend/blame/blame_redirect_spec.js b/spec/frontend/blame/blame_redirect_spec.js
index beb10139b3a..326f60a5b13 100644
--- a/spec/frontend/blame/blame_redirect_spec.js
+++ b/spec/frontend/blame/blame_redirect_spec.js
@@ -1,8 +1,8 @@
import redirectToCorrectPage from '~/blame/blame_redirect';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Blame page redirect', () => {
beforeEach(() => {
diff --git a/spec/frontend/blame/streaming/index_spec.js b/spec/frontend/blame/streaming/index_spec.js
new file mode 100644
index 00000000000..e048ce3f70e
--- /dev/null
+++ b/spec/frontend/blame/streaming/index_spec.js
@@ -0,0 +1,110 @@
+import waitForPromises from 'helpers/wait_for_promises';
+import { renderBlamePageStreams } from '~/blame/streaming';
+import { setHTMLFixture } from 'helpers/fixtures';
+import { renderHtmlStreams } from '~/streaming/render_html_streams';
+import { rateLimitStreamRequests } from '~/streaming/rate_limit_stream_requests';
+import { handleStreamedAnchorLink } from '~/streaming/handle_streamed_anchor_link';
+import { toPolyfillReadable } from '~/streaming/polyfills';
+import { createAlert } from '~/alert';
+
+jest.mock('~/streaming/render_html_streams');
+jest.mock('~/streaming/rate_limit_stream_requests');
+jest.mock('~/streaming/handle_streamed_anchor_link');
+jest.mock('~/streaming/polyfills');
+jest.mock('~/sentry');
+jest.mock('~/alert');
+
+global.fetch = jest.fn();
+
+describe('renderBlamePageStreams', () => {
+ let stopAnchor;
+ const PAGES_URL = 'https://example.com/';
+ const findStreamContainer = () => document.querySelector('#blame-stream-container');
+ const findStreamLoadingIndicator = () => document.querySelector('#blame-stream-loading');
+
+ const setupHtml = (totalExtraPages = 0) => {
+ setHTMLFixture(`
+ <div id="blob-content-holder"
+ data-total-extra-pages="${totalExtraPages}"
+ data-pages-url="${PAGES_URL}"
+ ></div>
+ <div id="blame-stream-container"></div>
+ <div id="blame-stream-loading"></div>
+ `);
+ };
+
+ handleStreamedAnchorLink.mockImplementation(() => stopAnchor);
+ rateLimitStreamRequests.mockImplementation(({ factory, total }) => {
+ return Array.from({ length: total }, (_, i) => {
+ return Promise.resolve(factory(i));
+ });
+ });
+ toPolyfillReadable.mockImplementation((obj) => obj);
+
+ beforeEach(() => {
+ stopAnchor = jest.fn();
+ fetch.mockClear();
+ });
+
+ it('does nothing for an empty page', async () => {
+ await renderBlamePageStreams();
+
+ expect(handleStreamedAnchorLink).not.toHaveBeenCalled();
+ expect(renderHtmlStreams).not.toHaveBeenCalled();
+ });
+
+ it('renders a single stream', async () => {
+ let res;
+ const stream = new Promise((resolve) => {
+ res = resolve;
+ });
+ renderHtmlStreams.mockImplementationOnce(() => stream);
+ setupHtml();
+
+ renderBlamePageStreams(stream);
+
+ expect(handleStreamedAnchorLink).toHaveBeenCalledTimes(1);
+ expect(stopAnchor).toHaveBeenCalledTimes(0);
+ expect(renderHtmlStreams).toHaveBeenCalledWith([stream], findStreamContainer());
+ expect(findStreamLoadingIndicator()).not.toBe(null);
+
+ res();
+ await waitForPromises();
+
+ expect(stopAnchor).toHaveBeenCalledTimes(1);
+ expect(findStreamLoadingIndicator()).toBe(null);
+ });
+
+ it('renders rest of the streams', async () => {
+ const stream = Promise.resolve();
+ const stream2 = Promise.resolve({ body: null });
+ fetch.mockImplementationOnce(() => stream2);
+ setupHtml(1);
+
+ await renderBlamePageStreams(stream);
+
+ expect(fetch.mock.calls[0][0].toString()).toBe(`${PAGES_URL}?page=3`);
+ expect(renderHtmlStreams).toHaveBeenCalledWith([stream, stream2], findStreamContainer());
+ });
+
+ it('shows an error message when failed', async () => {
+ const stream = Promise.resolve();
+ const error = new Error();
+ renderHtmlStreams.mockImplementationOnce(() => Promise.reject(error));
+ setupHtml();
+
+ try {
+ await renderBlamePageStreams(stream);
+ } catch (err) {
+ expect(err).toBe(error);
+ }
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'Blame could not be loaded as a single page.',
+ primaryButton: {
+ text: 'View blame as separate pages',
+ clickHandler: expect.any(Function),
+ },
+ });
+ });
+});
diff --git a/spec/frontend/blob/components/blob_content_error_spec.js b/spec/frontend/blob/components/blob_content_error_spec.js
index 0f5885c2acf..203fab94a5c 100644
--- a/spec/frontend/blob/components/blob_content_error_spec.js
+++ b/spec/frontend/blob/components/blob_content_error_spec.js
@@ -18,10 +18,6 @@ describe('Blob Content Error component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('collapsed and too large blobs', () => {
it.each`
error | reason | options
diff --git a/spec/frontend/blob/components/blob_content_spec.js b/spec/frontend/blob/components/blob_content_spec.js
index f7b819b6e94..91af5f7bfed 100644
--- a/spec/frontend/blob/components/blob_content_spec.js
+++ b/spec/frontend/blob/components/blob_content_spec.js
@@ -29,10 +29,6 @@ describe('Blob Content component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
it('renders loader if `loading: true`', () => {
createComponent({ loading: true });
diff --git a/spec/frontend/blob/components/blob_edit_header_spec.js b/spec/frontend/blob/components/blob_edit_header_spec.js
index c84b5896348..2b1bd1ac4ad 100644
--- a/spec/frontend/blob/components/blob_edit_header_spec.js
+++ b/spec/frontend/blob/components/blob_edit_header_spec.js
@@ -22,10 +22,6 @@ describe('Blob Header Editing', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
diff --git a/spec/frontend/blob/components/blob_header_default_actions_spec.js b/spec/frontend/blob/components/blob_header_default_actions_spec.js
index 0f015715dc2..e12021a48d2 100644
--- a/spec/frontend/blob/components/blob_header_default_actions_spec.js
+++ b/spec/frontend/blob/components/blob_header_default_actions_spec.js
@@ -34,10 +34,6 @@ describe('Blob Header Default Actions', () => {
buttons = wrapper.findAllComponents(GlButton);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('renders', () => {
const findCopyButton = () => wrapper.findByTestId('copyContentsButton');
const findViewRawButton = () => wrapper.findByTestId('viewRawButton');
diff --git a/spec/frontend/blob/components/blob_header_filepath_spec.js b/spec/frontend/blob/components/blob_header_filepath_spec.js
index 8c32cba1ba4..be49146ff8a 100644
--- a/spec/frontend/blob/components/blob_header_filepath_spec.js
+++ b/spec/frontend/blob/components/blob_header_filepath_spec.js
@@ -21,10 +21,6 @@ describe('Blob Header Filepath', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findBadge = () => wrapper.findComponent(GlBadge);
describe('rendering', () => {
diff --git a/spec/frontend/blob/components/blob_header_spec.js b/spec/frontend/blob/components/blob_header_spec.js
index 46740958090..47e09bb38bc 100644
--- a/spec/frontend/blob/components/blob_header_spec.js
+++ b/spec/frontend/blob/components/blob_header_spec.js
@@ -1,9 +1,14 @@
import { shallowMount, mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+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';
import BlobFilepath from '~/blob/components/blob_header_filepath.vue';
import ViewerSwitcher from '~/blob/components/blob_header_viewer_switcher.vue';
+import {
+ RICH_BLOB_VIEWER_TITLE,
+ SIMPLE_BLOB_VIEWER,
+ SIMPLE_BLOB_VIEWER_TITLE,
+} from '~/blob/components/constants';
import TableContents from '~/blob/components/table_contents.vue';
import { Blob } from './mock_data';
@@ -11,12 +16,26 @@ import { Blob } from './mock_data';
describe('Blob Header Default Actions', () => {
let wrapper;
- function createComponent(blobProps = {}, options = {}, propsData = {}, shouldMount = false) {
- const method = shouldMount ? mount : shallowMount;
- const blobHash = 'foo-bar';
- wrapper = method.call(this, BlobHeader, {
+ const defaultProvide = {
+ blobHash: 'foo-bar',
+ };
+
+ const findDefaultActions = () => wrapper.findComponent(DefaultActions);
+ const findTableContents = () => wrapper.findComponent(TableContents);
+ const findViewSwitcher = () => wrapper.findComponent(ViewerSwitcher);
+ const findBlobFilePath = () => wrapper.findComponent(BlobFilepath);
+ const findRichTextEditorBtn = () => wrapper.findByLabelText(RICH_BLOB_VIEWER_TITLE);
+ const findSimpleTextEditorBtn = () => wrapper.findByLabelText(SIMPLE_BLOB_VIEWER_TITLE);
+
+ function createComponent({
+ blobProps = {},
+ options = {},
+ propsData = {},
+ mountFn = shallowMount,
+ } = {}) {
+ wrapper = mountFn(BlobHeader, {
provide: {
- blobHash,
+ ...defaultProvide,
},
propsData: {
blob: { ...Blob, ...blobProps },
@@ -26,143 +45,123 @@ describe('Blob Header Default Actions', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
- const findDefaultActions = () => wrapper.findComponent(DefaultActions);
-
- const slots = {
- prepend: 'Foo Prepend',
- actions: 'Actions Bar',
- };
-
it('matches the snapshot', () => {
createComponent();
expect(wrapper.element).toMatchSnapshot();
});
- it('renders all components', () => {
- createComponent();
- expect(wrapper.findComponent(TableContents).exists()).toBe(true);
- expect(wrapper.findComponent(ViewerSwitcher).exists()).toBe(true);
- expect(findDefaultActions().exists()).toBe(true);
- expect(wrapper.findComponent(BlobFilepath).exists()).toBe(true);
+ describe('default render', () => {
+ it.each`
+ findComponent | componentName
+ ${findTableContents} | ${'TableContents'}
+ ${findViewSwitcher} | ${'ViewSwitcher'}
+ ${findDefaultActions} | ${'DefaultActions'}
+ ${findBlobFilePath} | ${'BlobFilePath'}
+ `('renders $componentName component by default', ({ findComponent }) => {
+ createComponent();
+
+ expect(findComponent().exists()).toBe(true);
+ });
});
it('does not render viewer switcher if the blob has only the simple viewer', () => {
createComponent({
- richViewer: null,
+ blobProps: {
+ richViewer: null,
+ },
});
- expect(wrapper.findComponent(ViewerSwitcher).exists()).toBe(false);
+ expect(findViewSwitcher().exists()).toBe(false);
});
it('does not render viewer switcher if a corresponding prop is passed', () => {
- createComponent(
- {},
- {},
- {
+ createComponent({
+ propsData: {
hideViewerSwitcher: true,
},
- );
- expect(wrapper.findComponent(ViewerSwitcher).exists()).toBe(false);
+ });
+ expect(findViewSwitcher().exists()).toBe(false);
});
it('does not render default actions is corresponding prop is passed', () => {
- createComponent(
- {},
- {},
- {
+ createComponent({
+ propsData: {
hideDefaultActions: true,
},
- );
- expect(wrapper.findComponent(DefaultActions).exists()).toBe(false);
+ });
+ expect(findDefaultActions().exists()).toBe(false);
});
- Object.keys(slots).forEach((slot) => {
- it('renders the slots', () => {
- const slotContent = slots[slot];
- createComponent(
- {},
- {
- scopedSlots: {
- [slot]: `<span>${slotContent}</span>`,
- },
+ it.each`
+ slotContent | key
+ ${'Foo Prepend'} | ${'prepend'}
+ ${'Actions Bar'} | ${'actions'}
+ `('renders the slot $key', ({ key, slotContent }) => {
+ createComponent({
+ options: {
+ scopedSlots: {
+ [key]: `<span>${slotContent}</span>`,
},
- {},
- true,
- );
- expect(wrapper.text()).toContain(slotContent);
+ },
+ mountFn: mount,
});
+ expect(wrapper.text()).toContain(slotContent);
});
it('passes information about render error down to default actions', () => {
- createComponent(
- {},
- {},
- {
+ createComponent({
+ propsData: {
hasRenderError: true,
},
- );
+ });
expect(findDefaultActions().props('hasRenderError')).toBe(true);
});
it('passes the correct isBinary value to default actions when viewing a binary file', () => {
- createComponent({}, {}, { isBinary: true });
+ createComponent({ propsData: { isBinary: true } });
expect(findDefaultActions().props('isBinary')).toBe(true);
});
});
describe('functionality', () => {
- const newViewer = 'Foo Bar';
- const activeViewerType = 'Alpha Beta';
-
const factory = (hideViewerSwitcher = false) => {
- createComponent(
- {},
- {},
- {
- activeViewerType,
+ createComponent({
+ propsData: {
+ activeViewerType: SIMPLE_BLOB_VIEWER,
hideViewerSwitcher,
},
- );
+ mountFn: mountExtended,
+ });
};
- it('by default sets viewer data based on activeViewerType', () => {
+ it('shows the correctly selected view by default', () => {
factory();
- expect(wrapper.vm.viewer).toBe(activeViewerType);
+
+ expect(findViewSwitcher().exists()).toBe(true);
+ expect(findRichTextEditorBtn().props().selected).toBe(false);
+ expect(findSimpleTextEditorBtn().props().selected).toBe(true);
});
- it('sets viewer to null if the viewer switcher should be hidden', () => {
+ it('Does not show the viewer switcher should be hidden', () => {
factory(true);
- expect(wrapper.vm.viewer).toBe(null);
+
+ expect(findViewSwitcher().exists()).toBe(false);
});
it('watches the changes in viewer data and emits event when the change is registered', async () => {
factory();
- jest.spyOn(wrapper.vm, '$emit');
- wrapper.vm.viewer = newViewer;
- await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('viewer-changed', newViewer);
- });
-
- it('does not emit event if the switcher is not rendered', async () => {
- factory(true);
-
- expect(wrapper.vm.showViewerSwitcher).toBe(false);
- jest.spyOn(wrapper.vm, '$emit');
- wrapper.vm.viewer = newViewer;
+ await findRichTextEditorBtn().trigger('click');
- await nextTick();
- expect(wrapper.vm.$emit).not.toHaveBeenCalled();
+ expect(wrapper.emitted('viewer-changed')).toBeDefined();
});
it('sets different icons depending on the blob file type', async () => {
factory();
- expect(wrapper.vm.blobSwitcherDocIcon).toBe('document');
+
+ expect(findViewSwitcher().props('docIcon')).toBe('document');
+
await wrapper.setProps({
blob: {
...Blob,
@@ -172,7 +171,8 @@ describe('Blob Header Default Actions', () => {
},
},
});
- expect(wrapper.vm.blobSwitcherDocIcon).toBe('table');
+
+ expect(findViewSwitcher().props('docIcon')).toBe('table');
});
});
});
diff --git a/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js b/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js
index 1eac0733646..2ef87f6664b 100644
--- a/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js
+++ b/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js
@@ -18,14 +18,14 @@ describe('Blob Header Viewer Switcher', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
+ const findSimpleViewerButton = () => wrapper.findComponent('[data-viewer="simple"]');
+ const findRichViewerButton = () => wrapper.findComponent('[data-viewer="rich"]');
describe('intiialization', () => {
it('is initialized with simple viewer as active', () => {
createComponent();
- expect(wrapper.vm.value).toBe(SIMPLE_BLOB_VIEWER);
+ expect(findSimpleViewerButton().props('selected')).toBe(true);
+ expect(findRichViewerButton().props('selected')).toBe(false);
});
});
@@ -52,45 +52,34 @@ describe('Blob Header Viewer Switcher', () => {
});
describe('viewer changes', () => {
- let buttons;
- let simpleBtn;
- let richBtn;
+ it('does not switch the viewer if the selected one is already active', async () => {
+ createComponent();
+ expect(findSimpleViewerButton().props('selected')).toBe(true);
- function factory(propsData = {}) {
- createComponent(propsData);
- buttons = wrapper.findAllComponents(GlButton);
- simpleBtn = buttons.at(0);
- richBtn = buttons.at(1);
-
- jest.spyOn(wrapper.vm, '$emit');
- }
-
- it('does not switch the viewer if the selected one is already active', () => {
- factory();
- expect(wrapper.vm.value).toBe(SIMPLE_BLOB_VIEWER);
- simpleBtn.vm.$emit('click');
- expect(wrapper.vm.value).toBe(SIMPLE_BLOB_VIEWER);
- expect(wrapper.vm.$emit).not.toHaveBeenCalled();
+ findSimpleViewerButton().vm.$emit('click');
+ await nextTick();
+
+ expect(findSimpleViewerButton().props('selected')).toBe(true);
+ expect(wrapper.emitted('input')).toBe(undefined);
});
it('emits an event when a Rich Viewer button is clicked', async () => {
- factory();
- expect(wrapper.vm.value).toBe(SIMPLE_BLOB_VIEWER);
-
- richBtn.vm.$emit('click');
+ createComponent();
+ expect(findSimpleViewerButton().props('selected')).toBe(true);
+ findRichViewerButton().vm.$emit('click');
await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('input', RICH_BLOB_VIEWER);
+
+ expect(wrapper.emitted('input')).toEqual([[RICH_BLOB_VIEWER]]);
});
it('emits an event when a Simple Viewer button is clicked', async () => {
- factory({
- value: RICH_BLOB_VIEWER,
- });
- simpleBtn.vm.$emit('click');
+ createComponent({ value: RICH_BLOB_VIEWER });
+ findSimpleViewerButton().vm.$emit('click');
await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('input', SIMPLE_BLOB_VIEWER);
+
+ expect(wrapper.emitted('input')).toEqual([[SIMPLE_BLOB_VIEWER]]);
});
});
});
diff --git a/spec/frontend/blob/components/table_contents_spec.js b/spec/frontend/blob/components/table_contents_spec.js
index 6af9cdcae7d..acfcef9704c 100644
--- a/spec/frontend/blob/components/table_contents_spec.js
+++ b/spec/frontend/blob/components/table_contents_spec.js
@@ -31,7 +31,6 @@ describe('Markdown table of contents component', () => {
});
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/blob/csv/csv_viewer_spec.js b/spec/frontend/blob/csv/csv_viewer_spec.js
index 9364f76da5e..8f105f04aa7 100644
--- a/spec/frontend/blob/csv/csv_viewer_spec.js
+++ b/spec/frontend/blob/csv/csv_viewer_spec.js
@@ -29,10 +29,6 @@ describe('app/assets/javascripts/blob/csv/csv_viewer.vue', () => {
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findAlert = () => wrapper.findComponent(PapaParseAlert);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render loading spinner', () => {
createComponent();
diff --git a/spec/frontend/blob/notebook/notebook_viever_spec.js b/spec/frontend/blob/notebook/notebook_viever_spec.js
index 2e7eadc912d..97b32a42afe 100644
--- a/spec/frontend/blob/notebook/notebook_viever_spec.js
+++ b/spec/frontend/blob/notebook/notebook_viever_spec.js
@@ -42,8 +42,6 @@ describe('iPython notebook renderer', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
mock.restore();
});
diff --git a/spec/frontend/blob/pdf/pdf_viewer_spec.js b/spec/frontend/blob/pdf/pdf_viewer_spec.js
index 23227df6357..19d404f504b 100644
--- a/spec/frontend/blob/pdf/pdf_viewer_spec.js
+++ b/spec/frontend/blob/pdf/pdf_viewer_spec.js
@@ -26,11 +26,6 @@ describe('PDF renderer', () => {
mountComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('shows loading icon', () => {
expect(findLoading().exists()).toBe(true);
});
diff --git a/spec/frontend/blob/pipeline_tour_success_modal_spec.js b/spec/frontend/blob/pipeline_tour_success_modal_spec.js
index 81b38cfc278..84efa6041e4 100644
--- a/spec/frontend/blob/pipeline_tour_success_modal_spec.js
+++ b/spec/frontend/blob/pipeline_tour_success_modal_spec.js
@@ -38,7 +38,6 @@ describe('PipelineTourSuccessModal', () => {
});
afterEach(() => {
- wrapper.destroy();
unmockTracking();
Cookies.remove(modalProps.commitCookie);
});
diff --git a/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js b/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
index 6b329dc078a..b30b0287a34 100644
--- a/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
+++ b/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
@@ -36,11 +36,6 @@ describe('Suggest gitlab-ci.yml Popover', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when no dismiss cookie is set', () => {
beforeEach(() => {
createWrapper(defaultTrackLabel);
diff --git a/spec/frontend/blob_edit/blob_bundle_spec.js b/spec/frontend/blob_edit/blob_bundle_spec.js
index ed42322b0e6..89d507b4ec5 100644
--- a/spec/frontend/blob_edit/blob_bundle_spec.js
+++ b/spec/frontend/blob_edit/blob_bundle_spec.js
@@ -5,10 +5,10 @@ import waitForPromises from 'helpers/wait_for_promises';
import blobBundle from '~/blob_edit/blob_bundle';
import SourceEditor from '~/blob_edit/edit_blob';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
jest.mock('~/blob_edit/edit_blob');
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('BlobBundle', () => {
it('does not load SourceEditor by default', () => {
diff --git a/spec/frontend/blob_edit/edit_blob_spec.js b/spec/frontend/blob_edit/edit_blob_spec.js
index dda46e97b85..9ab20fc2cd7 100644
--- a/spec/frontend/blob_edit/edit_blob_spec.js
+++ b/spec/frontend/blob_edit/edit_blob_spec.js
@@ -20,9 +20,9 @@ jest.mock('~/editor/extensions/source_editor_toolbar_ext');
const PREVIEW_MARKDOWN_PATH = '/foo/bar/preview_markdown';
const defaultExtensions = [
+ { definition: ToolbarExtension },
{ definition: SourceEditorExtension },
{ definition: FileTemplateExtension },
- { definition: ToolbarExtension },
];
const markdownExtensions = [
{ definition: EditorMarkdownExtension },
diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js
index 1e823e3321a..a612e863d46 100644
--- a/spec/frontend/boards/board_card_inner_spec.js
+++ b/spec/frontend/boards/board_card_inner_spec.js
@@ -84,7 +84,7 @@ describe('Board card component', () => {
BoardCardMoveToPosition: true,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
provide: {
rootPath: '/',
@@ -110,8 +110,6 @@ describe('Board card component', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
store = null;
jest.clearAllMocks();
});
@@ -314,10 +312,6 @@ describe('Board card component', () => {
});
});
- afterEach(() => {
- global.gon.default_avatar_url = null;
- });
-
it('displays defaults avatar if users avatar is null', () => {
expect(wrapper.find('.board-card-assignee img').exists()).toBe(true);
expect(wrapper.find('.board-card-assignee img').attributes('src')).toBe(
diff --git a/spec/frontend/boards/board_list_helper.js b/spec/frontend/boards/board_list_helper.js
index d882ff071b7..43cf6ead1c1 100644
--- a/spec/frontend/boards/board_list_helper.js
+++ b/spec/frontend/boards/board_list_helper.js
@@ -92,6 +92,7 @@ export default function createComponent({
boardItems: [issue],
canAdminList: true,
boardId: 'gid://gitlab/Board/1',
+ filterParams: {},
...componentProps,
},
provide: {
diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js
index fc8dbf8dc3a..9ec43c6e892 100644
--- a/spec/frontend/boards/board_list_spec.js
+++ b/spec/frontend/boards/board_list_spec.js
@@ -36,10 +36,6 @@ describe('Board list component', () => {
useFakeRequestAnimationFrame();
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('When Expanded', () => {
beforeEach(() => {
wrapper = createComponent({ issuesCount: 1 });
diff --git a/spec/frontend/boards/components/board_add_new_column_form_spec.js b/spec/frontend/boards/components/board_add_new_column_form_spec.js
index 0b3c6cb24c4..4fc9a6859a6 100644
--- a/spec/frontend/boards/components/board_add_new_column_form_spec.js
+++ b/spec/frontend/boards/components/board_add_new_column_form_spec.js
@@ -1,15 +1,13 @@
-import { GlDropdown, GlFormGroup, GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form.vue';
import defaultState from '~/boards/stores/state';
import { mockLabelList } from '../mock_data';
Vue.use(Vuex);
-describe('Board card layout', () => {
+describe('BoardAddNewColumnForm', () => {
let wrapper;
const createStore = ({ actions = {}, getters = {}, state = {} } = {}) => {
@@ -23,56 +21,30 @@ describe('Board card layout', () => {
});
};
- const mountComponent = ({
- loading = false,
- noneSelected = '',
- searchLabel = '',
- searchPlaceholder = '',
- selectedId,
- actions,
- slots,
- } = {}) => {
- wrapper = extendedWrapper(
- shallowMount(BoardAddNewColumnForm, {
- propsData: {
- loading,
- noneSelected,
- searchLabel,
- searchPlaceholder,
- selectedId,
- },
- slots,
- store: createStore({
- actions: {
- setAddColumnFormVisibility: jest.fn(),
- ...actions,
- },
- }),
- stubs: {
- GlDropdown,
+ const mountComponent = ({ searchLabel = '', selectedIdValid = true, actions, slots } = {}) => {
+ wrapper = shallowMountExtended(BoardAddNewColumnForm, {
+ propsData: {
+ searchLabel,
+ selectedIdValid,
+ },
+ slots,
+ store: createStore({
+ actions: {
+ setAddColumnFormVisibility: jest.fn(),
+ ...actions,
},
}),
- );
+ });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const formTitle = () => wrapper.findByTestId('board-add-column-form-title').text();
- const findSearchInput = () => wrapper.findComponent(GlSearchBoxByType);
- const findSearchLabelFormGroup = () => wrapper.findComponent(GlFormGroup);
const cancelButton = () => wrapper.findByTestId('cancelAddNewColumn');
const submitButton = () => wrapper.findByTestId('addNewColumnButton');
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- it('shows form title & search input', () => {
+ it('shows form title', () => {
mountComponent();
- findDropdown().vm.$emit('show');
-
expect(formTitle()).toEqual(BoardAddNewColumnForm.i18n.newList);
- expect(findSearchInput().exists()).toBe(true);
});
it('clicking cancel hides the form', () => {
@@ -88,61 +60,6 @@ describe('Board card layout', () => {
expect(setAddColumnFormVisibility).toHaveBeenCalledWith(expect.anything(), false);
});
- describe('items', () => {
- const mountWithItems = (loading) =>
- mountComponent({
- loading,
- slots: {
- items: '<div class="item-slot">Some kind of list</div>',
- },
- });
-
- it('hides items slot and shows skeleton while loading', () => {
- mountWithItems(true);
-
- expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
- expect(wrapper.find('.item-slot').exists()).toBe(false);
- });
-
- it('shows items slot and hides skeleton while not loading', () => {
- mountWithItems(false);
-
- expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(false);
- expect(wrapper.find('.item-slot').exists()).toBe(true);
- });
- });
-
- describe('search box', () => {
- it('sets label and placeholder text from props', () => {
- const props = {
- searchLabel: 'Some items',
- searchPlaceholder: 'Search for an item',
- };
-
- mountComponent(props);
-
- expect(findSearchLabelFormGroup().attributes('label')).toEqual(props.searchLabel);
- expect(findSearchInput().attributes('placeholder')).toEqual(props.searchPlaceholder);
- });
-
- it('does not show the dropdown as invalid by default', () => {
- mountComponent();
-
- expect(findSearchLabelFormGroup().attributes('state')).toBe('true');
- expect(findDropdown().props('toggleClass')).not.toContain('gl-inset-border-1-red-400!');
- });
-
- it('emits filter event on input', () => {
- mountComponent();
-
- const searchText = 'some text';
-
- findSearchInput().vm.$emit('input', searchText);
-
- expect(wrapper.emitted('filter-items')).toEqual([[searchText]]);
- });
- });
-
describe('Add list button', () => {
it('is enabled by default', () => {
mountComponent();
@@ -159,16 +76,5 @@ describe('Board card layout', () => {
expect(wrapper.emitted('add-list')).toEqual([[]]);
});
-
- it('does not emit the add-list event on click and shows the dropdown as invalid when no ID is selected', async () => {
- mountComponent();
-
- await submitButton().vm.$emit('click');
-
- expect(findSearchLabelFormGroup().attributes('state')).toBeUndefined();
- expect(findDropdown().props('toggleClass')).toContain('gl-inset-border-1-red-400!');
-
- expect(wrapper.emitted('add-list')).toBeUndefined();
- });
});
});
diff --git a/spec/frontend/boards/components/board_add_new_column_spec.js b/spec/frontend/boards/components/board_add_new_column_spec.js
index a3b2988ce75..a09c3aaa55e 100644
--- a/spec/frontend/boards/components/board_add_new_column_spec.js
+++ b/spec/frontend/boards/components/board_add_new_column_spec.js
@@ -1,8 +1,7 @@
-import { GlFormRadioGroup } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlCollapsibleListbox } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import BoardAddNewColumn from '~/boards/components/board_add_new_column.vue';
import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form.vue';
import defaultState from '~/boards/stores/state';
@@ -13,8 +12,9 @@ Vue.use(Vuex);
describe('Board card layout', () => {
let wrapper;
+ const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
const selectLabel = (id) => {
- wrapper.findComponent(GlFormRadioGroup).vm.$emit('change', id);
+ findDropdown().vm.$emit('select', id);
};
const createStore = ({ actions = {}, getters = {}, state = {} } = {}) => {
@@ -34,33 +34,34 @@ describe('Board card layout', () => {
getListByLabelId = jest.fn(),
actions = {},
} = {}) => {
- wrapper = extendedWrapper(
- shallowMount(BoardAddNewColumn, {
- data() {
- return {
- selectedId,
- };
+ wrapper = shallowMountExtended(BoardAddNewColumn, {
+ data() {
+ return {
+ selectedId,
+ };
+ },
+ store: createStore({
+ actions: {
+ fetchLabels: jest.fn(),
+ setAddColumnFormVisibility: jest.fn(),
+ ...actions,
},
- store: createStore({
- actions: {
- fetchLabels: jest.fn(),
- setAddColumnFormVisibility: jest.fn(),
- ...actions,
- },
- getters: {
- getListByLabelId: () => getListByLabelId,
- },
- state: {
- labels,
- labelsLoading: false,
- },
- }),
- provide: {
- scopedLabelsAvailable: true,
- isEpicBoard: false,
+ getters: {
+ getListByLabelId: () => getListByLabelId,
+ },
+ state: {
+ labels,
+ labelsLoading: false,
},
}),
- );
+ provide: {
+ scopedLabelsAvailable: true,
+ isEpicBoard: false,
+ },
+ stubs: {
+ GlCollapsibleListbox,
+ },
+ });
// trigger change event
if (selectedId) {
@@ -68,10 +69,6 @@ describe('Board card layout', () => {
}
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Add list button', () => {
it('calls addList', async () => {
const getListByLabelId = jest.fn().mockReturnValue(null);
diff --git a/spec/frontend/boards/components/board_add_new_column_trigger_spec.js b/spec/frontend/boards/components/board_add_new_column_trigger_spec.js
index 354eb7bff16..d8b93e1f3b6 100644
--- a/spec/frontend/boards/components/board_add_new_column_trigger_spec.js
+++ b/spec/frontend/boards/components/board_add_new_column_trigger_spec.js
@@ -17,7 +17,7 @@ describe('BoardAddNewColumnTrigger', () => {
const mountComponent = () => {
wrapper = mountExtended(BoardAddNewColumnTrigger, {
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
store: createStore(),
});
@@ -27,10 +27,6 @@ describe('BoardAddNewColumnTrigger', () => {
mountComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when button is active', () => {
it('does not show the tooltip', () => {
const tooltip = findTooltipText();
diff --git a/spec/frontend/boards/components/board_app_spec.js b/spec/frontend/boards/components/board_app_spec.js
index 12318fb5d16..148e696b57b 100644
--- a/spec/frontend/boards/components/board_app_spec.js
+++ b/spec/frontend/boards/components/board_app_spec.js
@@ -28,13 +28,12 @@ describe('BoardApp', () => {
store,
provide: {
initialBoardId: 'gid://gitlab/Board/1',
+ initialFilterParams: {},
},
});
};
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
store = null;
});
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js
index 84e6318d98e..46116bed4cf 100644
--- a/spec/frontend/boards/components/board_card_spec.js
+++ b/spec/frontend/boards/components/board_card_spec.js
@@ -82,8 +82,6 @@ describe('Board card', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
store = null;
});
diff --git a/spec/frontend/boards/components/board_column_spec.js b/spec/frontend/boards/components/board_column_spec.js
index c0bb51620f2..011665eee68 100644
--- a/spec/frontend/boards/components/board_column_spec.js
+++ b/spec/frontend/boards/components/board_column_spec.js
@@ -10,11 +10,6 @@ describe('Board Column Component', () => {
let wrapper;
let store;
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const initStore = () => {
store = createStore();
};
@@ -36,6 +31,7 @@ describe('Board Column Component', () => {
propsData: {
list: listMock,
boardId: 'gid://gitlab/Board/1',
+ filters: {},
},
provide: {
isApolloBoard: false,
diff --git a/spec/frontend/boards/components/board_configuration_options_spec.js b/spec/frontend/boards/components/board_configuration_options_spec.js
index 6f0971a9458..d2948daf121 100644
--- a/spec/frontend/boards/components/board_configuration_options_spec.js
+++ b/spec/frontend/boards/components/board_configuration_options_spec.js
@@ -16,10 +16,6 @@ describe('BoardConfigurationOptions', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const backlogListCheckbox = () => wrapper.find('[data-testid="backlog-list-checkbox"]');
const closedListCheckbox = () => wrapper.find('[data-testid="closed-list-checkbox"]');
diff --git a/spec/frontend/boards/components/board_content_sidebar_spec.js b/spec/frontend/boards/components/board_content_sidebar_spec.js
index 955267a415c..90376a4a553 100644
--- a/spec/frontend/boards/components/board_content_sidebar_spec.js
+++ b/spec/frontend/boards/components/board_content_sidebar_spec.js
@@ -89,10 +89,6 @@ describe('BoardContentSidebar', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('confirms we render GlDrawer', () => {
expect(wrapper.findComponent(GlDrawer).exists()).toBe(true);
});
diff --git a/spec/frontend/boards/components/board_content_spec.js b/spec/frontend/boards/components/board_content_spec.js
index 97596c86198..33351bf8efd 100644
--- a/spec/frontend/boards/components/board_content_spec.js
+++ b/spec/frontend/boards/components/board_content_spec.js
@@ -4,6 +4,8 @@ import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import Draggable from 'vuedraggable';
import Vuex from 'vuex';
+
+import eventHub from '~/boards/eventhub';
import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
import EpicsSwimlanes from 'ee_component/boards/components/epics_swimlanes.vue';
@@ -24,7 +26,6 @@ const actions = {
describe('BoardContent', () => {
let wrapper;
let fakeApollo;
- window.gon = {};
const defaultState = {
isShowingEpicsSwimlanes: false,
@@ -61,6 +62,8 @@ describe('BoardContent', () => {
apolloProvider: fakeApollo,
propsData: {
boardId: 'gid://gitlab/Board/1',
+ filterParams: {},
+ isSwimlanesOn: false,
...props,
},
provide: {
@@ -102,7 +105,6 @@ describe('BoardContent', () => {
});
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -203,5 +205,14 @@ describe('BoardContent', () => {
it('renders BoardContentSidebar', () => {
expect(wrapper.findComponent(BoardContentSidebar).exists()).toBe(true);
});
+
+ it('refetches lists when updateBoard event is received', async () => {
+ jest.spyOn(eventHub, '$on').mockImplementation(() => {});
+
+ createComponent({ isApolloBoard: true });
+ await waitForPromises();
+
+ expect(eventHub.$on).toHaveBeenCalledWith('updateBoard', wrapper.vm.refetchLists);
+ });
});
});
diff --git a/spec/frontend/boards/components/board_filtered_search_spec.js b/spec/frontend/boards/components/board_filtered_search_spec.js
index 4c0cc36889c..d8bc7f95f18 100644
--- a/spec/frontend/boards/components/board_filtered_search_spec.js
+++ b/spec/frontend/boards/components/board_filtered_search_spec.js
@@ -55,10 +55,10 @@ describe('BoardFilteredSearch', () => {
},
];
- const createComponent = ({ initialFilterParams = {}, props = {} } = {}) => {
+ const createComponent = ({ initialFilterParams = {}, props = {}, provide = {} } = {}) => {
store = createStore();
wrapper = shallowMount(BoardFilteredSearch, {
- provide: { initialFilterParams, fullPath: '' },
+ provide: { initialFilterParams, fullPath: '', isApolloBoard: false, ...provide },
store,
propsData: {
...props,
@@ -69,10 +69,6 @@ describe('BoardFilteredSearch', () => {
const findFilteredSearch = () => wrapper.findComponent(FilteredSearchBarRoot);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
@@ -191,4 +187,24 @@ describe('BoardFilteredSearch', () => {
]);
});
});
+
+ describe('when Apollo boards FF is on', () => {
+ beforeEach(() => {
+ createComponent({ provide: { isApolloBoard: true } });
+ });
+
+ it('emits setFilters and updates URL when onFilter is emitted', () => {
+ jest.spyOn(urlUtility, 'updateHistory');
+
+ findFilteredSearch().vm.$emit('onFilter', [{ value: { data: '' } }]);
+
+ expect(urlUtility.updateHistory).toHaveBeenCalledWith({
+ title: '',
+ replace: true,
+ url: 'http://test.host/',
+ });
+
+ expect(wrapper.emitted('setFilters')).toHaveLength(1);
+ });
+ });
});
diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js
index f8154145d43..62db59f8f57 100644
--- a/spec/frontend/boards/components/board_form_spec.js
+++ b/spec/frontend/boards/components/board_form_spec.js
@@ -10,12 +10,14 @@ import { formType } from '~/boards/constants';
import createBoardMutation from '~/boards/graphql/board_create.mutation.graphql';
import destroyBoardMutation from '~/boards/graphql/board_destroy.mutation.graphql';
import updateBoardMutation from '~/boards/graphql/board_update.mutation.graphql';
+import eventHub from '~/boards/eventhub';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
visitUrl: jest.fn().mockName('visitUrlMock'),
}));
+jest.mock('~/boards/eventhub');
Vue.use(Vuex);
@@ -59,18 +61,14 @@ describe('BoardForm', () => {
},
});
- const createComponent = (props, data) => {
+ const createComponent = (props, provide) => {
wrapper = shallowMountExtended(BoardForm, {
propsData: { ...defaultProps, ...props },
- data() {
- return {
- ...data,
- };
- },
provide: {
boardBaseUrl: 'root',
isGroupBoard: true,
isProjectBoard: false,
+ ...provide,
},
mocks: {
$apollo: {
@@ -83,8 +81,6 @@ describe('BoardForm', () => {
};
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
mutate = null;
});
@@ -140,7 +136,7 @@ describe('BoardForm', () => {
it('passes correct primary action text and variant', () => {
expect(findModalActionPrimary().text).toBe('Create board');
- expect(findModalActionPrimary().attributes[0].variant).toBe('confirm');
+ expect(findModalActionPrimary().attributes.variant).toBe('confirm');
});
it('does not render delete confirmation message', () => {
@@ -209,6 +205,30 @@ describe('BoardForm', () => {
expect(setBoardMock).not.toHaveBeenCalled();
expect(setErrorMock).toHaveBeenCalled();
});
+
+ describe('when Apollo boards FF is on', () => {
+ it('calls a correct GraphQL mutation and emits addBoard event when creating a board', async () => {
+ createComponent(
+ { canAdminBoard: true, currentPage: formType.new },
+ { isApolloBoard: true },
+ );
+ fillForm();
+
+ await waitForPromises();
+
+ expect(mutate).toHaveBeenCalledWith({
+ mutation: createBoardMutation,
+ variables: {
+ input: expect.objectContaining({
+ name: 'test',
+ }),
+ },
+ });
+
+ await waitForPromises();
+ expect(wrapper.emitted('addBoard')).toHaveLength(1);
+ });
+ });
});
});
@@ -228,7 +248,7 @@ describe('BoardForm', () => {
it('passes correct primary action text and variant', () => {
expect(findModalActionPrimary().text).toBe('Save changes');
- expect(findModalActionPrimary().attributes[0].variant).toBe('confirm');
+ expect(findModalActionPrimary().attributes.variant).toBe('confirm');
});
it('does not render delete confirmation message', () => {
@@ -308,13 +328,48 @@ describe('BoardForm', () => {
expect(setBoardMock).not.toHaveBeenCalled();
expect(setErrorMock).toHaveBeenCalled();
});
+
+ describe('when Apollo boards FF is on', () => {
+ it('calls a correct GraphQL mutation and emits updateBoard event when updating a board', async () => {
+ mutate = jest.fn().mockResolvedValue({
+ data: {
+ updateBoard: { board: { id: 'gid://gitlab/Board/321', webPath: 'test-path' } },
+ },
+ });
+ setWindowLocation('https://test/boards/1');
+
+ createComponent(
+ { canAdminBoard: true, currentPage: formType.edit },
+ { isApolloBoard: true },
+ );
+ findInput().trigger('keyup.enter', { metaKey: true });
+
+ await waitForPromises();
+
+ expect(mutate).toHaveBeenCalledWith({
+ mutation: updateBoardMutation,
+ variables: {
+ input: expect.objectContaining({
+ id: currentBoard.id,
+ }),
+ },
+ });
+
+ await waitForPromises();
+ expect(eventHub.$emit).toHaveBeenCalledTimes(1);
+ expect(eventHub.$emit).toHaveBeenCalledWith('updateBoard', {
+ id: 'gid://gitlab/Board/321',
+ webPath: 'test-path',
+ });
+ });
+ });
});
describe('when deleting a board', () => {
it('passes correct primary action text and variant', () => {
createComponent({ canAdminBoard: true, currentPage: formType.delete });
expect(findModalActionPrimary().text).toBe('Delete');
- expect(findModalActionPrimary().attributes[0].variant).toBe('danger');
+ expect(findModalActionPrimary().attributes.variant).toBe('danger');
});
it('renders delete confirmation message', () => {
diff --git a/spec/frontend/boards/components/board_list_header_spec.js b/spec/frontend/boards/components/board_list_header_spec.js
index 9e65e900440..466321cf1cc 100644
--- a/spec/frontend/boards/components/board_list_header_spec.js
+++ b/spec/frontend/boards/components/board_list_header_spec.js
@@ -1,10 +1,9 @@
-import { shallowMount } from '@vue/test-utils';
+import { GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex';
import createMockApollo from 'helpers/mock_apollo_helper';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { boardListQueryResponse, mockLabelList } from 'jest/boards/mock_data';
import BoardListHeader from '~/boards/components/board_list_header.vue';
import { ListType } from '~/boards/constants';
@@ -22,8 +21,6 @@ describe('Board List Header Component', () => {
const toggleListCollapsedSpy = jest.fn();
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
fakeApollo = null;
localStorage.clear();
@@ -64,31 +61,34 @@ describe('Board List Header Component', () => {
fakeApollo = createMockApollo([[listQuery, listQueryHandler]]);
- wrapper = extendedWrapper(
- shallowMount(BoardListHeader, {
- apolloProvider: fakeApollo,
- store,
- propsData: {
- list: listMock,
- },
- provide: {
- boardId,
- weightFeatureAvailable: false,
- currentUserId,
- isEpicBoard: false,
- disabled: false,
- ...injectedProps,
- },
- }),
- );
+ wrapper = shallowMountExtended(BoardListHeader, {
+ apolloProvider: fakeApollo,
+ store,
+ propsData: {
+ list: listMock,
+ filterParams: {},
+ },
+ provide: {
+ boardId,
+ weightFeatureAvailable: false,
+ currentUserId,
+ isEpicBoard: false,
+ disabled: false,
+ ...injectedProps,
+ },
+ stubs: {
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ },
+ });
};
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
const isCollapsed = () => wrapper.vm.list.collapsed;
-
- const findAddIssueButton = () => wrapper.findComponent({ ref: 'newIssueBtn' });
const findTitle = () => wrapper.find('.board-title');
const findCaret = () => wrapper.findByTestId('board-title-caret');
- const findSettingsButton = () => wrapper.findComponent({ ref: 'settingsBtn' });
+ const findNewIssueButton = () => wrapper.findByTestId('newIssueBtn');
+ const findSettingsButton = () => wrapper.findByTestId('settingsBtn');
describe('Add issue button', () => {
const hasNoAddButton = [ListType.closed];
@@ -100,59 +100,49 @@ describe('Board List Header Component', () => {
ListType.assignee,
];
- it.each(hasNoAddButton)('does not render when List Type is `%s`', (listType) => {
+ it.each(hasNoAddButton)('does not render dropdown when List Type is `%s`', (listType) => {
createComponent({ listType });
- expect(findAddIssueButton().exists()).toBe(false);
+ expect(findDropdown().exists()).toBe(false);
});
it.each(hasAddButton)('does render when List Type is `%s`', (listType) => {
createComponent({ listType });
- expect(findAddIssueButton().exists()).toBe(true);
+ expect(findDropdown().exists()).toBe(true);
+ expect(findNewIssueButton().exists()).toBe(true);
});
- it('has a test for each list type', () => {
- createComponent();
-
- Object.values(ListType).forEach((value) => {
- expect([...hasAddButton, ...hasNoAddButton]).toContain(value);
- });
- });
-
- it('does not render when logged out', () => {
+ it('does not render dropdown when logged out', () => {
createComponent({
currentUserId: null,
});
- expect(findAddIssueButton().exists()).toBe(false);
+ expect(findDropdown().exists()).toBe(false);
});
});
describe('Settings Button', () => {
- describe('with disabled=true', () => {
- const hasSettings = [
- ListType.assignee,
- ListType.milestone,
- ListType.iteration,
- ListType.label,
- ];
- const hasNoSettings = [ListType.backlog, ListType.closed];
-
- it.each(hasSettings)('does render for List Type `%s` when disabled=true', (listType) => {
- createComponent({ listType, injectedProps: { disabled: true } });
-
- expect(findSettingsButton().exists()).toBe(true);
- });
+ const hasSettings = [ListType.assignee, ListType.milestone, ListType.iteration, ListType.label];
- it.each(hasNoSettings)(
- 'does not render for List Type `%s` when disabled=true',
- (listType) => {
- createComponent({ listType });
+ it.each(hasSettings)('does render for List Type `%s`', (listType) => {
+ createComponent({ listType });
- expect(findSettingsButton().exists()).toBe(false);
- },
- );
+ expect(findDropdown().exists()).toBe(true);
+ expect(findSettingsButton().exists()).toBe(true);
+ });
+
+ it('does not render dropdown when ListType `closed`', () => {
+ createComponent({ listType: ListType.closed });
+
+ expect(findDropdown().exists()).toBe(false);
+ });
+
+ it('renders dropdown but not the Settings button when ListType `backlog`', () => {
+ createComponent({ listType: ListType.backlog });
+
+ expect(findDropdown().exists()).toBe(true);
+ expect(findSettingsButton().exists()).toBe(false);
});
});
diff --git a/spec/frontend/boards/components/board_new_issue_spec.js b/spec/frontend/boards/components/board_new_issue_spec.js
index c3e69ba0e40..651d1daee52 100644
--- a/spec/frontend/boards/components/board_new_issue_spec.js
+++ b/spec/frontend/boards/components/board_new_issue_spec.js
@@ -51,10 +51,6 @@ describe('Issue boards new issue form', () => {
await nextTick();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders board-new-item component', () => {
const boardNewItem = findBoardNewItem();
expect(boardNewItem.exists()).toBe(true);
diff --git a/spec/frontend/boards/components/board_new_item_spec.js b/spec/frontend/boards/components/board_new_item_spec.js
index f4e9901aad2..f11eb2baca7 100644
--- a/spec/frontend/boards/components/board_new_item_spec.js
+++ b/spec/frontend/boards/components/board_new_item_spec.js
@@ -35,10 +35,6 @@ describe('BoardNewItem', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
describe('when the user provides a valid input', () => {
it('finds an enabled create button', async () => {
diff --git a/spec/frontend/boards/components/board_settings_sidebar_spec.js b/spec/frontend/boards/components/board_settings_sidebar_spec.js
index 7d602042685..d0928485caf 100644
--- a/spec/frontend/boards/components/board_settings_sidebar_spec.js
+++ b/spec/frontend/boards/components/board_settings_sidebar_spec.js
@@ -48,7 +48,7 @@ describe('BoardSettingsSidebar', () => {
isIssueBoard: true,
},
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
},
stubs: {
GlDrawer: stubComponent(GlDrawer, {
@@ -65,8 +65,6 @@ describe('BoardSettingsSidebar', () => {
afterEach(() => {
jest.restoreAllMocks();
- wrapper.destroy();
- wrapper = null;
});
it('finds a MountingPortal component', () => {
diff --git a/spec/frontend/boards/components/board_top_bar_spec.js b/spec/frontend/boards/components/board_top_bar_spec.js
index 8258d9fe7f4..d97a1dbff47 100644
--- a/spec/frontend/boards/components/board_top_bar_spec.js
+++ b/spec/frontend/boards/components/board_top_bar_spec.js
@@ -11,7 +11,7 @@ import ConfigToggle from '~/boards/components/config_toggle.vue';
import IssueBoardFilteredSearch from '~/boards/components/issue_board_filtered_search.vue';
import NewBoardButton from '~/boards/components/new_board_button.vue';
import ToggleFocus from '~/boards/components/toggle_focus.vue';
-import { BoardType } from '~/boards/constants';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import groupBoardQuery from '~/boards/graphql/group_board.query.graphql';
import projectBoardQuery from '~/boards/graphql/project_board.query.graphql';
@@ -43,8 +43,9 @@ describe('BoardTopBar', () => {
wrapper = shallowMount(BoardTopBar, {
store,
apolloProvider: mockApollo,
- props: {
+ propsData: {
boardId: 'gid://gitlab/Board/1',
+ isSwimlanesOn: false,
},
provide: {
swimlanesFeatureAvailable: false,
@@ -64,7 +65,6 @@ describe('BoardTopBar', () => {
};
afterEach(() => {
- wrapper.destroy();
mockApollo = null;
});
@@ -96,6 +96,11 @@ describe('BoardTopBar', () => {
it('does not render BoardAddNewColumnTrigger component', () => {
expect(wrapper.findComponent(BoardAddNewColumnTrigger).exists()).toBe(false);
});
+
+ it('emits setFilters when setFilters is emitted by filtered search', () => {
+ wrapper.findComponent(IssueBoardFilteredSearch).vm.$emit('setFilters');
+ expect(wrapper.emitted('setFilters')).toHaveLength(1);
+ });
});
describe('when user can admin list', () => {
@@ -111,14 +116,14 @@ describe('BoardTopBar', () => {
describe('Apollo boards', () => {
it.each`
boardType | queryHandler | notCalledHandler
- ${BoardType.group} | ${groupBoardQueryHandlerSuccess} | ${projectBoardQueryHandlerSuccess}
- ${BoardType.project} | ${projectBoardQueryHandlerSuccess} | ${groupBoardQueryHandlerSuccess}
+ ${WORKSPACE_GROUP} | ${groupBoardQueryHandlerSuccess} | ${projectBoardQueryHandlerSuccess}
+ ${WORKSPACE_PROJECT} | ${projectBoardQueryHandlerSuccess} | ${groupBoardQueryHandlerSuccess}
`('fetches $boardType boards', async ({ boardType, queryHandler, notCalledHandler }) => {
createComponent({
provide: {
boardType,
- isProjectBoard: boardType === BoardType.project,
- isGroupBoard: boardType === BoardType.group,
+ isProjectBoard: boardType === WORKSPACE_PROJECT,
+ isGroupBoard: boardType === WORKSPACE_GROUP,
isApolloBoard: true,
},
});
diff --git a/spec/frontend/boards/components/boards_selector_spec.js b/spec/frontend/boards/components/boards_selector_spec.js
index 28f51e0ecbf..aa146eb4609 100644
--- a/spec/frontend/boards/components/boards_selector_spec.js
+++ b/spec/frontend/boards/components/boards_selector_spec.js
@@ -5,11 +5,11 @@ import Vuex from 'vuex';
import waitForPromises from 'helpers/wait_for_promises';
import { TEST_HOST } from 'spec/test_constants';
import BoardsSelector from '~/boards/components/boards_selector.vue';
-import { BoardType } from '~/boards/constants';
import groupBoardsQuery from '~/boards/graphql/group_boards.query.graphql';
import projectBoardsQuery from '~/boards/graphql/project_boards.query.graphql';
import groupRecentBoardsQuery from '~/boards/graphql/group_recent_boards.query.graphql';
import projectRecentBoardsQuery from '~/boards/graphql/project_recent_boards.query.graphql';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import {
@@ -116,7 +116,6 @@ describe('BoardsSelector', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -228,13 +227,13 @@ describe('BoardsSelector', () => {
describe('fetching all boards', () => {
it.each`
boardType | queryHandler | notCalledHandler
- ${BoardType.group} | ${groupBoardsQueryHandlerSuccess} | ${projectBoardsQueryHandlerSuccess}
- ${BoardType.project} | ${projectBoardsQueryHandlerSuccess} | ${groupBoardsQueryHandlerSuccess}
+ ${WORKSPACE_GROUP} | ${groupBoardsQueryHandlerSuccess} | ${projectBoardsQueryHandlerSuccess}
+ ${WORKSPACE_PROJECT} | ${projectBoardsQueryHandlerSuccess} | ${groupBoardsQueryHandlerSuccess}
`('fetches $boardType boards', async ({ boardType, queryHandler, notCalledHandler }) => {
createStore();
createComponent({
- isGroupBoard: boardType === BoardType.group,
- isProjectBoard: boardType === BoardType.project,
+ isGroupBoard: boardType === WORKSPACE_GROUP,
+ isProjectBoard: boardType === WORKSPACE_PROJECT,
});
await nextTick();
diff --git a/spec/frontend/boards/components/config_toggle_spec.js b/spec/frontend/boards/components/config_toggle_spec.js
index 47d4692453d..5330721451e 100644
--- a/spec/frontend/boards/components/config_toggle_spec.js
+++ b/spec/frontend/boards/components/config_toggle_spec.js
@@ -23,10 +23,6 @@ describe('ConfigToggle', () => {
const findButton = () => wrapper.findComponent(GlButton);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a button with label `View scope` when `canAdminList` is `false`', () => {
wrapper = createComponent({ canAdminList: false });
expect(findButton().text()).toBe('View scope');
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 57a30ddc512..5b5b68d5dbe 100644
--- a/spec/frontend/boards/components/issue_board_filtered_search_spec.js
+++ b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
@@ -2,10 +2,10 @@ import { orderBy } from 'lodash';
import { shallowMount } from '@vue/test-utils';
import BoardFilteredSearch from 'ee_else_ce/boards/components/board_filtered_search.vue';
import IssueBoardFilteredSpec from '~/boards/components/issue_board_filtered_search.vue';
-import issueBoardFilters from '~/boards/issue_board_filters';
+import issueBoardFilters from 'ee_else_ce/boards/issue_board_filters';
import { mockTokens } from '../mock_data';
-jest.mock('~/boards/issue_board_filters');
+jest.mock('ee_else_ce/boards/issue_board_filters');
describe('IssueBoardFilter', () => {
let wrapper;
@@ -14,6 +14,9 @@ describe('IssueBoardFilter', () => {
const createComponent = ({ isSignedIn = false } = {}) => {
wrapper = shallowMount(IssueBoardFilteredSpec, {
+ propsData: {
+ boardId: 'gid://gitlab/Board/1',
+ },
provide: {
isSignedIn,
releasesFetchPath: '/releases',
@@ -35,10 +38,6 @@ describe('IssueBoardFilter', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
@@ -48,6 +47,11 @@ describe('IssueBoardFilter', () => {
expect(findBoardsFilteredSearch().exists()).toBe(true);
});
+ it('emits setFilters when setFilters is emitted', () => {
+ findBoardsFilteredSearch().vm.$emit('setFilters');
+ expect(wrapper.emitted('setFilters')).toHaveLength(1);
+ });
+
it.each`
isSignedIn
${true}
diff --git a/spec/frontend/boards/components/issue_due_date_spec.js b/spec/frontend/boards/components/issue_due_date_spec.js
index 45fa10bf03a..dee8febfe4d 100644
--- a/spec/frontend/boards/components/issue_due_date_spec.js
+++ b/spec/frontend/boards/components/issue_due_date_spec.js
@@ -20,10 +20,6 @@ describe('Issue Due Date component', () => {
date = new Date();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render "Today" if the due date is today', () => {
wrapper = createComponent();
diff --git a/spec/frontend/boards/components/issue_time_estimate_spec.js b/spec/frontend/boards/components/issue_time_estimate_spec.js
index 948a7a20f7f..42507ef560b 100644
--- a/spec/frontend/boards/components/issue_time_estimate_spec.js
+++ b/spec/frontend/boards/components/issue_time_estimate_spec.js
@@ -7,10 +7,6 @@ describe('Issue Time Estimate component', () => {
const findIssueTimeEstimate = () => wrapper.find('[data-testid="issue-time-estimate"]');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when limitToHours is false', () => {
beforeEach(() => {
wrapper = shallowMount(IssueTimeEstimate, {
diff --git a/spec/frontend/boards/components/item_count_spec.js b/spec/frontend/boards/components/item_count_spec.js
index 0c0c7f66933..f2cc8eb1167 100644
--- a/spec/frontend/boards/components/item_count_spec.js
+++ b/spec/frontend/boards/components/item_count_spec.js
@@ -41,10 +41,6 @@ describe('IssueCount', () => {
createComponent({ maxIssueCount, itemsSize });
});
- afterEach(() => {
- vm.destroy();
- });
-
it('contains issueSize in the template', () => {
expect(vm.find('[data-testid="board-items-count"]').text()).toEqual(String(itemsSize));
});
@@ -66,10 +62,6 @@ describe('IssueCount', () => {
createComponent({ maxIssueCount, itemsSize });
});
- afterEach(() => {
- vm.destroy();
- });
-
it('contains issueSize in the template', () => {
expect(vm.find('[data-testid="board-items-count"]').text()).toEqual(String(itemsSize));
});
diff --git a/spec/frontend/boards/components/sidebar/board_editable_item_spec.js b/spec/frontend/boards/components/sidebar/board_editable_item_spec.js
index 5e2222ac3d7..6dbeac3864f 100644
--- a/spec/frontend/boards/components/sidebar/board_editable_item_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_editable_item_spec.js
@@ -21,11 +21,6 @@ describe('boards sidebar remove issue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('template', () => {
it('renders title', () => {
const title = 'Sidebar item title';
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_time_tracker_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_time_tracker_spec.js
index e2e4baefad0..b01ee01120e 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_time_tracker_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_time_tracker_spec.js
@@ -37,11 +37,6 @@ describe('BoardSidebarTimeTracker', () => {
store.state.activeId = '1';
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it.each`
timeTrackingLimitToHours | canUpdate
${true} | ${false}
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 bc66a0515aa..a20884baf3b 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js
@@ -27,9 +27,7 @@ describe('~/boards/components/sidebar/board_sidebar_title.vue', () => {
afterEach(() => {
localStorage.clear();
- wrapper.destroy();
store = null;
- wrapper = null;
});
const createWrapper = (item = TEST_ISSUE_A) => {
diff --git a/spec/frontend/boards/components/toggle_focus_spec.js b/spec/frontend/boards/components/toggle_focus_spec.js
index 3cbaac91f8d..cad287954d7 100644
--- a/spec/frontend/boards/components/toggle_focus_spec.js
+++ b/spec/frontend/boards/components/toggle_focus_spec.js
@@ -10,7 +10,7 @@ describe('ToggleFocus', () => {
const createComponent = () => {
wrapper = shallowMountExtended(ToggleFocus, {
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
attachTo: document.body,
});
@@ -18,10 +18,6 @@ describe('ToggleFocus', () => {
const findButton = () => wrapper.findComponent(GlButton);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a button with `maximize` icon', () => {
createComponent();
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 1d011eacf1c..e5167120542 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -477,6 +477,9 @@ export const mockList = {
loading: false,
issuesCount: 1,
maxIssueCount: 0,
+ metadata: {
+ epicsCount: 1,
+ },
__typename: 'BoardList',
};
@@ -915,6 +918,7 @@ export const epicBoardListQueryResponse = (totalWeight = 5) => ({
__typename: 'EpicList',
id: 'gid://gitlab/Boards::EpicList/3',
metadata: {
+ epicsCount: 1,
totalWeight,
},
},
diff --git a/spec/frontend/boards/project_select_spec.js b/spec/frontend/boards/project_select_spec.js
index 4324e7068e0..74ce4b6b786 100644
--- a/spec/frontend/boards/project_select_spec.js
+++ b/spec/frontend/boards/project_select_spec.js
@@ -71,11 +71,6 @@ describe('ProjectSelect component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('displays a header title', () => {
createWrapper();
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index ab959abaa99..f430062bb73 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -2,13 +2,7 @@ import * as Sentry from '@sentry/browser';
import { cloneDeep } from 'lodash';
import Vue from 'vue';
import Vuex from 'vuex';
-import {
- inactiveId,
- ISSUABLE,
- ListType,
- BoardType,
- DraggableItemTypes,
-} from 'ee_else_ce/boards/constants';
+import { inactiveId, ISSUABLE, ListType, DraggableItemTypes } from 'ee_else_ce/boards/constants';
import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql';
import testAction from 'helpers/vuex_action_helper';
import {
@@ -26,7 +20,7 @@ import actions from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types';
import mutations from '~/boards/stores/mutations';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import projectBoardMilestones from '~/boards/graphql/project_board_milestones.query.graphql';
import groupBoardMilestones from '~/boards/graphql/group_board_milestones.query.graphql';
@@ -49,7 +43,7 @@ import {
mockMilestones,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
// We need this helper to make sure projectPath is including
// subgroups when the movIssue action is called.
@@ -300,8 +294,8 @@ describe('fetchLists', () => {
it.each`
issuableType | boardType | fullBoardId | isGroup | isProject
- ${TYPE_ISSUE} | ${BoardType.group} | ${'gid://gitlab/Board/1'} | ${true} | ${false}
- ${TYPE_ISSUE} | ${BoardType.project} | ${'gid://gitlab/Board/1'} | ${false} | ${true}
+ ${TYPE_ISSUE} | ${WORKSPACE_GROUP} | ${'gid://gitlab/Board/1'} | ${true} | ${false}
+ ${TYPE_ISSUE} | ${WORKSPACE_PROJECT} | ${'gid://gitlab/Board/1'} | ${false} | ${true}
`(
'calls $issuableType query with correct variables',
async ({ issuableType, boardType, fullBoardId, isGroup, isProject }) => {
@@ -336,7 +330,7 @@ describe('fetchLists', () => {
describe('fetchMilestones', () => {
const queryResponse = {
data: {
- project: {
+ workspace: {
milestones: {
nodes: mockMilestones,
},
@@ -346,7 +340,7 @@ describe('fetchMilestones', () => {
const queryErrors = {
data: {
- project: {
+ workspace: {
errors: ['You cannot view these milestones'],
milestones: {},
},
diff --git a/spec/frontend/boards/stores/getters_spec.js b/spec/frontend/boards/stores/getters_spec.js
index c86a256bd96..944a7493504 100644
--- a/spec/frontend/boards/stores/getters_spec.js
+++ b/spec/frontend/boards/stores/getters_spec.js
@@ -31,10 +31,6 @@ describe('Boards - Getters', () => {
});
describe('isSwimlanesOn', () => {
- afterEach(() => {
- window.gon = { features: {} };
- });
-
it('returns false', () => {
expect(getters.isSwimlanesOn()).toBe(false);
});
@@ -171,10 +167,6 @@ describe('Boards - Getters', () => {
});
describe('isEpicBoard', () => {
- afterEach(() => {
- window.gon = { features: {} };
- });
-
it('returns false', () => {
expect(getters.isEpicBoard()).toBe(false);
});
diff --git a/spec/frontend/branches/components/delete_branch_button_spec.js b/spec/frontend/branches/components/delete_branch_button_spec.js
index b029f34c3d7..5b2ec443c59 100644
--- a/spec/frontend/branches/components/delete_branch_button_spec.js
+++ b/spec/frontend/branches/components/delete_branch_button_spec.js
@@ -25,10 +25,6 @@ describe('Delete branch button', () => {
eventHubSpy = jest.spyOn(eventHub, '$emit');
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the button with default tooltip, style, and icon', () => {
createComponent();
diff --git a/spec/frontend/branches/components/delete_branch_modal_spec.js b/spec/frontend/branches/components/delete_branch_modal_spec.js
index c977868ca93..dd5b7fca564 100644
--- a/spec/frontend/branches/components/delete_branch_modal_spec.js
+++ b/spec/frontend/branches/components/delete_branch_modal_spec.js
@@ -52,10 +52,6 @@ describe('Delete branch modal', () => {
const expectedUnmergedWarning =
"This branch hasn't been merged into default. To avoid data loss, consider merging this branch before deleting it.";
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Deleting a regular branch', () => {
const expectedTitle = 'Delete branch. Are you ABSOLUTELY SURE?';
const expectedWarning = "You're about to permanently delete the branch test_modal.";
diff --git a/spec/frontend/branches/components/delete_merged_branches_spec.js b/spec/frontend/branches/components/delete_merged_branches_spec.js
index 4f1e772f4a4..75a669c78f2 100644
--- a/spec/frontend/branches/components/delete_merged_branches_spec.js
+++ b/spec/frontend/branches/components/delete_merged_branches_spec.js
@@ -27,7 +27,7 @@ const createComponent = (mountFn = shallowMountExtended, stubs = {}) => {
...propsDataMock,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
stubs,
});
@@ -78,10 +78,6 @@ describe('Delete merged branches component', () => {
createComponent(shallowMountExtended, stubsData);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders correct modal title and text', () => {
const modalText = findModal().text();
expect(findModal().props('title')).toBe(i18n.modalTitle);
diff --git a/spec/frontend/branches/components/divergence_graph_spec.js b/spec/frontend/branches/components/divergence_graph_spec.js
index 9429a6e982c..66193c2ebf0 100644
--- a/spec/frontend/branches/components/divergence_graph_spec.js
+++ b/spec/frontend/branches/components/divergence_graph_spec.js
@@ -9,10 +9,6 @@ function factory(propsData = {}) {
}
describe('Branch divergence graph component', () => {
- afterEach(() => {
- vm.destroy();
- });
-
it('renders ahead and behind count', () => {
factory({
defaultBranch: 'main',
diff --git a/spec/frontend/branches/components/graph_bar_spec.js b/spec/frontend/branches/components/graph_bar_spec.js
index 61c051b49c6..585b376081b 100644
--- a/spec/frontend/branches/components/graph_bar_spec.js
+++ b/spec/frontend/branches/components/graph_bar_spec.js
@@ -8,10 +8,6 @@ function factory(propsData = {}) {
}
describe('Branch divergence graph bar component', () => {
- afterEach(() => {
- vm.destroy();
- });
-
it.each`
position | positionClass
${'left'} | ${'position-right-0'}
diff --git a/spec/frontend/captcha/captcha_modal_spec.js b/spec/frontend/captcha/captcha_modal_spec.js
index 20e69b5a834..6d6d8043797 100644
--- a/spec/frontend/captcha/captcha_modal_spec.js
+++ b/spec/frontend/captcha/captcha_modal_spec.js
@@ -1,6 +1,5 @@
import { GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
import { stubComponent } from 'helpers/stub_component';
import CaptchaModal from '~/captcha/captcha_modal.vue';
import { initRecaptchaScript } from '~/captcha/init_recaptcha_script';
@@ -9,10 +8,11 @@ jest.mock('~/captcha/init_recaptcha_script');
describe('Captcha Modal', () => {
let wrapper;
- let modal;
let grecaptcha;
const captchaSiteKey = 'abc123';
+ const showSpy = jest.fn();
+ const hideSpy = jest.fn();
function createComponent({ props = {} } = {}) {
wrapper = shallowMount(CaptchaModal, {
@@ -21,11 +21,18 @@ describe('Captcha Modal', () => {
...props,
},
stubs: {
- GlModal: stubComponent(GlModal),
+ GlModal: stubComponent(GlModal, {
+ methods: {
+ show: showSpy,
+ hide: hideSpy,
+ },
+ }),
},
});
}
+ const findGlModal = () => wrapper.findComponent(GlModal);
+
beforeEach(() => {
grecaptcha = {
render: jest.fn(),
@@ -34,38 +41,17 @@ describe('Captcha Modal', () => {
initRecaptchaScript.mockResolvedValue(grecaptcha);
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- const findGlModal = () => {
- const glModal = wrapper.findComponent(GlModal);
-
- jest.spyOn(glModal.vm, 'show').mockImplementation(() => glModal.vm.$emit('shown'));
- jest
- .spyOn(glModal.vm, 'hide')
- .mockImplementation(() => glModal.vm.$emit('hide', { trigger: '' }));
-
- return glModal;
- };
-
- const showModal = () => {
- wrapper.setProps({ needsCaptchaResponse: true });
- };
-
- beforeEach(() => {
- createComponent();
- modal = findGlModal();
- });
-
describe('rendering', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
it('renders', () => {
- expect(modal.exists()).toBe(true);
+ expect(findGlModal().exists()).toBe(true);
});
it('assigns the modal a unique ID', () => {
- const firstInstanceModalId = modal.props('modalId');
+ const firstInstanceModalId = findGlModal().props('modalId');
createComponent();
const secondInstanceModalId = findGlModal().props('modalId');
expect(firstInstanceModalId).not.toEqual(secondInstanceModalId);
@@ -76,13 +62,12 @@ describe('Captcha Modal', () => {
describe('when modal is shown', () => {
describe('when initRecaptchaScript promise resolves successfully', () => {
beforeEach(async () => {
- showModal();
-
- await nextTick();
+ createComponent({ props: { needsCaptchaResponse: true } });
+ findGlModal().vm.$emit('shown');
});
it('shows modal', async () => {
- expect(findGlModal().vm.show).toHaveBeenCalled();
+ expect(showSpy).toHaveBeenCalled();
});
it('renders window.grecaptcha', () => {
@@ -108,7 +93,7 @@ describe('Captcha Modal', () => {
it('hides modal with null trigger', async () => {
// Assert that hide is called with zero args, so that we don't trigger the logic
// for hiding the modal via cancel, esc, headerclose, etc, without a captcha response
- expect(modal.vm.hide).toHaveBeenCalledWith();
+ expect(hideSpy).toHaveBeenCalledWith();
});
});
@@ -127,7 +112,7 @@ describe('Captcha Modal', () => {
const bvModalEvent = {
trigger,
};
- modal.vm.$emit('hide', bvModalEvent);
+ findGlModal().vm.$emit('hide', bvModalEvent);
});
it(`emits receivedCaptchaResponse with ${JSON.stringify(expected)}`, () => {
@@ -141,21 +126,24 @@ describe('Captcha Modal', () => {
const fakeError = {};
beforeEach(() => {
- initRecaptchaScript.mockImplementation(() => Promise.reject(fakeError));
+ createComponent({
+ props: { needsCaptchaResponse: true },
+ });
+ initRecaptchaScript.mockImplementation(() => Promise.reject(fakeError));
jest.spyOn(console, 'error').mockImplementation();
- showModal();
+ findGlModal().vm.$emit('shown');
});
it('emits receivedCaptchaResponse exactly once with null', () => {
expect(wrapper.emitted('receivedCaptchaResponse')).toEqual([[null]]);
});
- it('hides modal with null trigger', async () => {
+ it('hides modal with null trigger', () => {
// Assert that hide is called with zero args, so that we don't trigger the logic
// for hiding the modal via cancel, esc, headerclose, etc, without a captcha response
- expect(modal.vm.hide).toHaveBeenCalledWith();
+ expect(hideSpy).toHaveBeenCalledWith();
});
it('calls console.error with a message and the exception', () => {
diff --git a/spec/frontend/ci/ci_lint/components/ci_lint_spec.js b/spec/frontend/ci/ci_lint/components/ci_lint_spec.js
index d4f588a0e09..4b7ca36f331 100644
--- a/spec/frontend/ci/ci_lint/components/ci_lint_spec.js
+++ b/spec/frontend/ci/ci_lint/components/ci_lint_spec.js
@@ -48,7 +48,6 @@ describe('CI Lint', () => {
afterEach(() => {
mockMutate.mockClear();
- wrapper.destroy();
});
it('displays the editor', () => {
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_admin_variables_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_admin_variables_spec.js
index 5e0c35c9f90..8e012883f09 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_admin_variables_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_admin_variables_spec.js
@@ -16,10 +16,6 @@ describe('Ci Project Variable wrapper', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Passes down the correct props to ci_variable_shared', () => {
expect(findCiShared().props()).toEqual({
areScopedVariablesAvailable: false,
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
index 2fd395a1230..7181398c2a6 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
@@ -27,10 +27,6 @@ describe('Ci environments dropdown', () => {
findListbox().vm.$emit('search', searchTerm);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('No environments found', () => {
beforeEach(() => {
createComponent({ searchTerm: 'stable' });
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js
index c0fb133b9b1..77d90a7667d 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_group_variables_spec.js
@@ -24,10 +24,6 @@ describe('Ci Group Variable wrapper', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Props', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_project_variables_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_project_variables_spec.js
index bd1e6b17d6b..ce5237a84f7 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_project_variables_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_project_variables_spec.js
@@ -25,10 +25,6 @@ describe('Ci Project Variable wrapper', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Passes down the correct props to ci_variable_shared', () => {
expect(findCiShared().props()).toEqual({
id: convertToGraphQLId(TYPENAME_PROJECT, mockProvide.projectId),
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
index 508af964ca3..8f3fccc2804 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_modal_spec.js
@@ -85,10 +85,6 @@ describe('Ci variable modal', () => {
const findVariableTypeDropdown = () => wrapper.find('#ci-variable-type');
const findEnvironmentScopeText = () => wrapper.findByText('Environment scope');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Adding a variable', () => {
describe('when no key/value pair are present', () => {
beforeEach(() => {
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 32af2ec4de9..0141232a299 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
@@ -22,6 +22,7 @@ describe('Ci variable table', () => {
hideEnvironmentScope: false,
isLoading: false,
maxVariableLimit: 5,
+ pageInfo: { after: '' },
variables: mockVariablesWithScopes(projectString),
};
@@ -37,10 +38,6 @@ describe('Ci variable table', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('props passing', () => {
it('passes props down correctly to the ci table', () => {
createComponent();
@@ -49,6 +46,7 @@ describe('Ci variable table', () => {
entity: 'project',
isLoading: defaultProps.isLoading,
maxVariableLimit: defaultProps.maxVariableLimit,
+ pageInfo: defaultProps.pageInfo,
variables: defaultProps.variables,
});
});
@@ -144,4 +142,22 @@ describe('Ci variable table', () => {
expect(wrapper.emitted(eventName)).toEqual([[newVariable]]);
});
});
+
+ describe('pages events', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it.each`
+ eventName | args
+ ${'handle-prev-page'} | ${undefined}
+ ${'handle-next-page'} | ${undefined}
+ ${'sort-changed'} | ${{ sortDesc: true }}
+ `('bubbles up the $eventName event', async ({ args, eventName }) => {
+ findCiVariableTable().vm.$emit(eventName, args);
+ await nextTick();
+
+ expect(wrapper.emitted(eventName)).toEqual([[args]]);
+ });
+ });
});
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
index c977ae773db..87192006efc 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
@@ -4,7 +4,7 @@ import { GlLoadingIcon, GlTable } 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 '~/flash';
+import { createAlert } from '~/alert';
import { resolvers } from '~/ci/ci_variable_list/graphql/settings';
import { TYPENAME_GROUP } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
@@ -41,7 +41,7 @@ import {
mockAdminVariables,
} from '../mocks';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -53,6 +53,7 @@ const mockProvide = {
const defaultProps = {
areScopedVariablesAvailable: true,
+ pageInfo: {},
hideEnvironmentScope: false,
refetchAfterMutation: false,
};
@@ -105,345 +106,378 @@ describe('Ci Variable Shared Component', () => {
mockVariables = jest.fn();
});
- describe('while queries are being fetch', () => {
- beforeEach(() => {
- createComponentWithApollo({ isLoading: true });
- });
-
- it('shows a loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findCiTable().exists()).toBe(false);
- });
- });
-
- describe('when queries are resolved', () => {
- describe('successfully', () => {
- beforeEach(async () => {
- mockEnvironments.mockResolvedValue(mockProjectEnvironments);
- mockVariables.mockResolvedValue(mockProjectVariables);
-
- await createComponentWithApollo({ provide: createProjectProvide() });
+ describe.each`
+ isVariablePagesEnabled | text
+ ${true} | ${'enabled'}
+ ${false} | ${'disabled'}
+ `('When Pages FF is $text', ({ isVariablePagesEnabled }) => {
+ const featureFlagProvide = isVariablePagesEnabled
+ ? { glFeatures: { ciVariablesPages: true } }
+ : {};
+
+ describe('while queries are being fetch', () => {
+ beforeEach(() => {
+ createComponentWithApollo({ isLoading: true });
});
- it('passes down the expected max variable limit as props', () => {
- expect(findCiSettings().props('maxVariableLimit')).toBe(
- mockProjectVariables.data.project.ciVariables.limit,
- );
+ it('shows a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ expect(findCiTable().exists()).toBe(false);
});
+ });
- it('passes down the expected environments as props', () => {
- expect(findCiSettings().props('environments')).toEqual([prodName, devName]);
- });
+ describe('when queries are resolved', () => {
+ describe('successfully', () => {
+ beforeEach(async () => {
+ mockEnvironments.mockResolvedValue(mockProjectEnvironments);
+ mockVariables.mockResolvedValue(mockProjectVariables);
- it('passes down the expected variables as props', () => {
- expect(findCiSettings().props('variables')).toEqual(
- mockProjectVariables.data.project.ciVariables.nodes,
- );
- });
+ await createComponentWithApollo({
+ provide: { ...createProjectProvide(), ...featureFlagProvide },
+ });
+ });
- it('createAlert was not called', () => {
- expect(createAlert).not.toHaveBeenCalled();
- });
- });
+ it('passes down the expected max variable limit as props', () => {
+ expect(findCiSettings().props('maxVariableLimit')).toBe(
+ mockProjectVariables.data.project.ciVariables.limit,
+ );
+ });
- describe('with an error for variables', () => {
- beforeEach(async () => {
- mockEnvironments.mockResolvedValue(mockProjectEnvironments);
- mockVariables.mockRejectedValue();
+ it('passes down the expected environments as props', () => {
+ expect(findCiSettings().props('environments')).toEqual([prodName, devName]);
+ });
- await createComponentWithApollo();
- });
+ it('passes down the expected variables as props', () => {
+ expect(findCiSettings().props('variables')).toEqual(
+ mockProjectVariables.data.project.ciVariables.nodes,
+ );
+ });
- it('calls createAlert with the expected error message', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: variableFetchErrorText });
+ it('createAlert was not called', () => {
+ expect(createAlert).not.toHaveBeenCalled();
+ });
});
- });
- describe('with an error for environments', () => {
- beforeEach(async () => {
- mockEnvironments.mockRejectedValue();
- mockVariables.mockResolvedValue(mockProjectVariables);
+ describe('with an error for variables', () => {
+ beforeEach(async () => {
+ mockEnvironments.mockResolvedValue(mockProjectEnvironments);
+ mockVariables.mockRejectedValue();
- await createComponentWithApollo();
- });
+ await createComponentWithApollo({ provide: featureFlagProvide });
+ });
- it('calls createAlert with the expected error message', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: environmentFetchErrorText });
+ it('calls createAlert with the expected error message', () => {
+ expect(createAlert).toHaveBeenCalledWith({ message: variableFetchErrorText });
+ });
});
- });
- });
- describe('environment query', () => {
- describe('when there is an environment key in queryData', () => {
- beforeEach(async () => {
- mockEnvironments.mockResolvedValue(mockProjectEnvironments);
- mockVariables.mockResolvedValue(mockProjectVariables);
+ describe('with an error for environments', () => {
+ beforeEach(async () => {
+ mockEnvironments.mockRejectedValue();
+ mockVariables.mockResolvedValue(mockProjectVariables);
- await createComponentWithApollo({ props: { ...createProjectProps() } });
- });
+ await createComponentWithApollo({ provide: featureFlagProvide });
+ });
- it('is executed', () => {
- expect(mockVariables).toHaveBeenCalled();
+ it('calls createAlert with the expected error message', () => {
+ expect(createAlert).toHaveBeenCalledWith({ message: environmentFetchErrorText });
+ });
});
});
- describe('when there isnt an environment key in queryData', () => {
- beforeEach(async () => {
- mockVariables.mockResolvedValue(mockGroupVariables);
+ describe('environment query', () => {
+ describe('when there is an environment key in queryData', () => {
+ beforeEach(async () => {
+ mockEnvironments.mockResolvedValue(mockProjectEnvironments);
+ mockVariables.mockResolvedValue(mockProjectVariables);
- await createComponentWithApollo({ props: { ...createGroupProps() } });
- });
+ await createComponentWithApollo({
+ props: { ...createProjectProps() },
+ provide: featureFlagProvide,
+ });
+ });
- it('is skipped', () => {
- expect(mockVariables).not.toHaveBeenCalled();
+ it('is executed', () => {
+ expect(mockVariables).toHaveBeenCalled();
+ });
});
- });
- });
- describe('mutations', () => {
- const groupProps = createGroupProps();
+ describe('when there isnt an environment key in queryData', () => {
+ beforeEach(async () => {
+ mockVariables.mockResolvedValue(mockGroupVariables);
- beforeEach(async () => {
- mockVariables.mockResolvedValue(mockGroupVariables);
+ await createComponentWithApollo({
+ props: { ...createGroupProps() },
+ provide: featureFlagProvide,
+ });
+ });
- await createComponentWithApollo({
- customHandlers: [[getGroupVariables, mockVariables]],
- props: groupProps,
+ it('is skipped', () => {
+ expect(mockVariables).not.toHaveBeenCalled();
+ });
});
});
- it.each`
- actionName | mutation | event
- ${'add'} | ${groupProps.mutationData[ADD_MUTATION_ACTION]} | ${'add-variable'}
- ${'update'} | ${groupProps.mutationData[UPDATE_MUTATION_ACTION]} | ${'update-variable'}
- ${'delete'} | ${groupProps.mutationData[DELETE_MUTATION_ACTION]} | ${'delete-variable'}
- `(
- 'calls the right mutation from propsData when user performs $actionName variable',
- async ({ event, mutation }) => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue();
-
- await findCiSettings().vm.$emit(event, newVariable);
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation,
- variables: {
- endpoint: mockProvide.endpoint,
- fullPath: groupProps.fullPath,
- id: convertToGraphQLId(TYPENAME_GROUP, groupProps.id),
- variable: newVariable,
- },
- });
- },
- );
-
- it.each`
- actionName | event
- ${'add'} | ${'add-variable'}
- ${'update'} | ${'update-variable'}
- ${'delete'} | ${'delete-variable'}
- `(
- 'throws with the specific graphql error if present when user performs $actionName variable',
- async ({ event }) => {
- const graphQLErrorMessage = 'There is a problem with this graphQL action';
- jest
- .spyOn(wrapper.vm.$apollo, 'mutate')
- .mockResolvedValue({ data: { ciVariableMutation: { errors: [graphQLErrorMessage] } } });
- await findCiSettings().vm.$emit(event, newVariable);
- await nextTick();
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled();
- expect(createAlert).toHaveBeenCalledWith({ message: graphQLErrorMessage });
- },
- );
-
- it.each`
- actionName | event
- ${'add'} | ${'add-variable'}
- ${'update'} | ${'update-variable'}
- ${'delete'} | ${'delete-variable'}
- `(
- 'throws generic error on failure with no graphql errors and user performs $actionName variable',
- async ({ event }) => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockImplementationOnce(() => {
- throw new Error();
- });
- await findCiSettings().vm.$emit(event, newVariable);
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled();
- expect(createAlert).toHaveBeenCalledWith({ message: genericMutationErrorText });
- },
- );
+ describe('mutations', () => {
+ const groupProps = createGroupProps();
- describe('without fullpath and ID props', () => {
beforeEach(async () => {
- mockVariables.mockResolvedValue(mockAdminVariables);
+ mockVariables.mockResolvedValue(mockGroupVariables);
await createComponentWithApollo({
- customHandlers: [[getAdminVariables, mockVariables]],
- props: createInstanceProps(),
+ customHandlers: [[getGroupVariables, mockVariables]],
+ props: groupProps,
+ provide: featureFlagProvide,
});
});
-
- it('does not pass fullPath and ID to the mutation', async () => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue();
-
- await findCiSettings().vm.$emit('add-variable', newVariable);
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: wrapper.props().mutationData[ADD_MUTATION_ACTION],
- variables: {
- endpoint: mockProvide.endpoint,
- variable: newVariable,
- },
- });
- });
- });
- });
-
- describe('Props', () => {
- const mockGroupCiVariables = mockGroupVariables.data.group.ciVariables;
- const mockProjectCiVariables = mockProjectVariables.data.project.ciVariables;
-
- describe('in a specific context as', () => {
it.each`
- name | mockVariablesValue | mockEnvironmentsValue | withEnvironments | expectedEnvironments | propsFn | provideFn | mutation | maxVariableLimit
- ${'project'} | ${mockProjectVariables} | ${mockProjectEnvironments} | ${true} | ${['prod', 'dev']} | ${createProjectProps} | ${createProjectProvide} | ${null} | ${mockProjectCiVariables.limit}
- ${'group'} | ${mockGroupVariables} | ${[]} | ${false} | ${[]} | ${createGroupProps} | ${createGroupProvide} | ${getGroupVariables} | ${mockGroupCiVariables.limit}
- ${'instance'} | ${mockAdminVariables} | ${[]} | ${false} | ${[]} | ${createInstanceProps} | ${() => {}} | ${getAdminVariables} | ${0}
+ actionName | mutation | event
+ ${'add'} | ${groupProps.mutationData[ADD_MUTATION_ACTION]} | ${'add-variable'}
+ ${'update'} | ${groupProps.mutationData[UPDATE_MUTATION_ACTION]} | ${'update-variable'}
+ ${'delete'} | ${groupProps.mutationData[DELETE_MUTATION_ACTION]} | ${'delete-variable'}
`(
- 'passes down all the required props when its a $name component',
- async ({
- mutation,
- maxVariableLimit,
- mockVariablesValue,
- mockEnvironmentsValue,
- withEnvironments,
- expectedEnvironments,
- propsFn,
- provideFn,
- }) => {
- const props = propsFn();
- const provide = provideFn();
-
- mockVariables.mockResolvedValue(mockVariablesValue);
-
- if (withEnvironments) {
- mockEnvironments.mockResolvedValue(mockEnvironmentsValue);
- }
-
- let customHandlers = null;
-
- if (mutation) {
- customHandlers = [[mutation, mockVariables]];
- }
+ 'calls the right mutation from propsData when user performs $actionName variable',
+ async ({ event, mutation }) => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue();
+
+ await findCiSettings().vm.$emit(event, newVariable);
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation,
+ variables: {
+ endpoint: mockProvide.endpoint,
+ fullPath: groupProps.fullPath,
+ id: convertToGraphQLId(TYPENAME_GROUP, groupProps.id),
+ variable: newVariable,
+ },
+ });
+ },
+ );
- await createComponentWithApollo({ customHandlers, props, provide });
+ it.each`
+ actionName | event
+ ${'add'} | ${'add-variable'}
+ ${'update'} | ${'update-variable'}
+ ${'delete'} | ${'delete-variable'}
+ `(
+ 'throws with the specific graphql error if present when user performs $actionName variable',
+ async ({ event }) => {
+ const graphQLErrorMessage = 'There is a problem with this graphQL action';
+ jest
+ .spyOn(wrapper.vm.$apollo, 'mutate')
+ .mockResolvedValue({ data: { ciVariableMutation: { errors: [graphQLErrorMessage] } } });
+ await findCiSettings().vm.$emit(event, newVariable);
+ await nextTick();
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalledWith({ message: graphQLErrorMessage });
+ },
+ );
- expect(findCiSettings().props()).toEqual({
- areScopedVariablesAvailable: wrapper.props().areScopedVariablesAvailable,
- hideEnvironmentScope: defaultProps.hideEnvironmentScope,
- isLoading: false,
- maxVariableLimit,
- variables: wrapper.props().queryData.ciVariables.lookup(mockVariablesValue.data)?.nodes,
- entity: props.entity,
- environments: expectedEnvironments,
+ it.each`
+ actionName | event
+ ${'add'} | ${'add-variable'}
+ ${'update'} | ${'update-variable'}
+ ${'delete'} | ${'delete-variable'}
+ `(
+ 'throws generic error on failure with no graphql errors and user performs $actionName variable',
+ async ({ event }) => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockImplementationOnce(() => {
+ throw new Error();
});
+ await findCiSettings().vm.$emit(event, newVariable);
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalledWith({ message: genericMutationErrorText });
},
);
- });
- describe('refetchAfterMutation', () => {
- it.each`
- bool | text
- ${true} | ${'refetches the variables'}
- ${false} | ${'does not refetch the variables'}
- `('when $bool it $text', async ({ bool }) => {
- await createComponentWithApollo({
- props: { ...createInstanceProps(), refetchAfterMutation: bool },
- });
+ describe('without fullpath and ID props', () => {
+ beforeEach(async () => {
+ mockVariables.mockResolvedValue(mockAdminVariables);
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({ data: {} });
- jest.spyOn(wrapper.vm.$apollo.queries.ciVariables, 'refetch').mockImplementation(jest.fn());
+ await createComponentWithApollo({
+ customHandlers: [[getAdminVariables, mockVariables]],
+ props: createInstanceProps(),
+ provide: featureFlagProvide,
+ });
+ });
- await findCiSettings().vm.$emit('add-variable', newVariable);
+ it('does not pass fullPath and ID to the mutation', async () => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue();
- await nextTick();
+ await findCiSettings().vm.$emit('add-variable', newVariable);
- if (bool) {
- expect(wrapper.vm.$apollo.queries.ciVariables.refetch).toHaveBeenCalled();
- } else {
- expect(wrapper.vm.$apollo.queries.ciVariables.refetch).not.toHaveBeenCalled();
- }
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: wrapper.props().mutationData[ADD_MUTATION_ACTION],
+ variables: {
+ endpoint: mockProvide.endpoint,
+ variable: newVariable,
+ },
+ });
+ });
});
});
- describe('Validators', () => {
- describe('queryData', () => {
- let error;
+ describe('Props', () => {
+ const mockGroupCiVariables = mockGroupVariables.data.group.ciVariables;
+ const mockProjectCiVariables = mockProjectVariables.data.project.ciVariables;
+
+ describe('in a specific context as', () => {
+ it.each`
+ name | mockVariablesValue | mockEnvironmentsValue | withEnvironments | expectedEnvironments | propsFn | provideFn | mutation | maxVariableLimit
+ ${'project'} | ${mockProjectVariables} | ${mockProjectEnvironments} | ${true} | ${['prod', 'dev']} | ${createProjectProps} | ${createProjectProvide} | ${null} | ${mockProjectCiVariables.limit}
+ ${'group'} | ${mockGroupVariables} | ${[]} | ${false} | ${[]} | ${createGroupProps} | ${createGroupProvide} | ${getGroupVariables} | ${mockGroupCiVariables.limit}
+ ${'instance'} | ${mockAdminVariables} | ${[]} | ${false} | ${[]} | ${createInstanceProps} | ${() => {}} | ${getAdminVariables} | ${0}
+ `(
+ 'passes down all the required props when its a $name component',
+ async ({
+ mutation,
+ maxVariableLimit,
+ mockVariablesValue,
+ mockEnvironmentsValue,
+ withEnvironments,
+ expectedEnvironments,
+ propsFn,
+ provideFn,
+ }) => {
+ const props = propsFn();
+ const provide = provideFn();
- beforeEach(async () => {
- mockVariables.mockResolvedValue(mockGroupVariables);
- });
+ mockVariables.mockResolvedValue(mockVariablesValue);
+
+ if (withEnvironments) {
+ mockEnvironments.mockResolvedValue(mockEnvironmentsValue);
+ }
+
+ let customHandlers = null;
+
+ if (mutation) {
+ customHandlers = [[mutation, mockVariables]];
+ }
- it('will mount component with right data', async () => {
- try {
await createComponentWithApollo({
- customHandlers: [[getGroupVariables, mockVariables]],
- props: { ...createGroupProps() },
+ customHandlers,
+ props,
+ provide: { ...provide, ...featureFlagProvide },
});
- } catch (e) {
- error = e;
- } finally {
- expect(wrapper.exists()).toBe(true);
- expect(error).toBeUndefined();
- }
- });
- it('will not mount component with wrong data', async () => {
- try {
- await createComponentWithApollo({
- customHandlers: [[getGroupVariables, mockVariables]],
- props: { ...createGroupProps(), queryData: { wrongKey: {} } },
+ expect(findCiSettings().props()).toEqual({
+ areScopedVariablesAvailable: wrapper.props().areScopedVariablesAvailable,
+ hideEnvironmentScope: defaultProps.hideEnvironmentScope,
+ pageInfo: defaultProps.pageInfo,
+ isLoading: false,
+ maxVariableLimit,
+ variables: wrapper.props().queryData.ciVariables.lookup(mockVariablesValue.data)
+ ?.nodes,
+ entity: props.entity,
+ environments: expectedEnvironments,
});
- } catch (e) {
- error = e;
- } finally {
- expect(wrapper.exists()).toBe(false);
- expect(error.toString()).toContain('custom validator check failed for prop');
+ },
+ );
+ });
+
+ describe('refetchAfterMutation', () => {
+ it.each`
+ bool | text
+ ${true} | ${'refetches the variables'}
+ ${false} | ${'does not refetch the variables'}
+ `('when $bool it $text', async ({ bool }) => {
+ await createComponentWithApollo({
+ props: { ...createInstanceProps(), refetchAfterMutation: bool },
+ provide: featureFlagProvide,
+ });
+
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({ data: {} });
+ jest
+ .spyOn(wrapper.vm.$apollo.queries.ciVariables, 'refetch')
+ .mockImplementation(jest.fn());
+
+ await findCiSettings().vm.$emit('add-variable', newVariable);
+
+ await nextTick();
+
+ if (bool) {
+ expect(wrapper.vm.$apollo.queries.ciVariables.refetch).toHaveBeenCalled();
+ } else {
+ expect(wrapper.vm.$apollo.queries.ciVariables.refetch).not.toHaveBeenCalled();
}
});
});
- describe('mutationData', () => {
- let error;
+ describe('Validators', () => {
+ describe('queryData', () => {
+ let error;
- beforeEach(async () => {
- mockVariables.mockResolvedValue(mockGroupVariables);
- });
+ beforeEach(async () => {
+ mockVariables.mockResolvedValue(mockGroupVariables);
+ });
- it('will mount component with right data', async () => {
- try {
- await createComponentWithApollo({
- props: { ...createGroupProps() },
- });
- } catch (e) {
- error = e;
- } finally {
- expect(wrapper.exists()).toBe(true);
- expect(error).toBeUndefined();
- }
+ it('will mount component with right data', async () => {
+ try {
+ await createComponentWithApollo({
+ customHandlers: [[getGroupVariables, mockVariables]],
+ props: { ...createGroupProps() },
+ provide: featureFlagProvide,
+ });
+ } catch (e) {
+ error = e;
+ } finally {
+ expect(wrapper.exists()).toBe(true);
+ expect(error).toBeUndefined();
+ }
+ });
+
+ it('will not mount component with wrong data', async () => {
+ try {
+ await createComponentWithApollo({
+ customHandlers: [[getGroupVariables, mockVariables]],
+ props: { ...createGroupProps(), queryData: { wrongKey: {} } },
+ provide: featureFlagProvide,
+ });
+ } catch (e) {
+ error = e;
+ } finally {
+ expect(wrapper.exists()).toBe(false);
+ expect(error.toString()).toContain('custom validator check failed for prop');
+ }
+ });
});
- it('will not mount component with wrong data', async () => {
- try {
- await createComponentWithApollo({
- props: { ...createGroupProps(), mutationData: { wrongKey: {} } },
- });
- } catch (e) {
- error = e;
- } finally {
- expect(wrapper.exists()).toBe(false);
- expect(error.toString()).toContain('custom validator check failed for prop');
- }
+ describe('mutationData', () => {
+ let error;
+
+ beforeEach(async () => {
+ mockVariables.mockResolvedValue(mockGroupVariables);
+ });
+
+ it('will mount component with right data', async () => {
+ try {
+ await createComponentWithApollo({
+ props: { ...createGroupProps() },
+ provide: featureFlagProvide,
+ });
+ } catch (e) {
+ error = e;
+ } finally {
+ expect(wrapper.exists()).toBe(true);
+ expect(error).toBeUndefined();
+ }
+ });
+
+ it('will not mount component with wrong data', async () => {
+ try {
+ await createComponentWithApollo({
+ props: { ...createGroupProps(), mutationData: { wrongKey: {} } },
+ provide: featureFlagProvide,
+ });
+ } catch (e) {
+ error = e;
+ } finally {
+ expect(wrapper.exists()).toBe(false);
+ expect(error.toString()).toContain('custom validator check failed for prop');
+ }
+ });
});
});
});
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 9e2508c56ee..2ef789e89c3 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
@@ -12,18 +12,25 @@ describe('Ci variable table', () => {
entity: 'project',
isLoading: false,
maxVariableLimit: mockVariables(projectString).length + 1,
+ pageInfo: {},
variables: mockVariables(projectString),
};
const mockMaxVariableLimit = defaultProps.variables.length;
- const createComponent = ({ props = {} } = {}) => {
+ const createComponent = ({ props = {}, provide = {} } = {}) => {
wrapper = mountExtended(CiVariableTable, {
attachTo: document.body,
propsData: {
...defaultProps,
...props,
},
+ provide: {
+ glFeatures: {
+ ciVariablesPages: false,
+ },
+ ...provide,
+ },
});
};
@@ -41,132 +48,136 @@ describe('Ci variable table', () => {
return sprintf(EXCEEDS_VARIABLE_LIMIT_TEXT, { entity, currentVariableCount, maxVariableLimit });
};
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('When table is empty', () => {
- beforeEach(() => {
- createComponent({ props: { variables: [] } });
- });
+ describe.each`
+ isVariablePagesEnabled | text
+ ${true} | ${'enabled'}
+ ${false} | ${'disabled'}
+ `('When Pages FF is $text', ({ isVariablePagesEnabled }) => {
+ const provide = isVariablePagesEnabled ? { glFeatures: { ciVariablesPages: true } } : {};
- it('displays empty message', () => {
- expect(findEmptyVariablesPlaceholder().exists()).toBe(true);
- });
-
- it('hides the reveal button', () => {
- expect(findRevealButton().exists()).toBe(false);
- });
- });
+ describe('When table is empty', () => {
+ beforeEach(() => {
+ createComponent({ props: { variables: [] }, provide });
+ });
- describe('When table has variables', () => {
- beforeEach(() => {
- createComponent();
- });
+ it('displays empty message', () => {
+ expect(findEmptyVariablesPlaceholder().exists()).toBe(true);
+ });
- it('does not display the empty message', () => {
- expect(findEmptyVariablesPlaceholder().exists()).toBe(false);
+ it('hides the reveal button', () => {
+ expect(findRevealButton().exists()).toBe(false);
+ });
});
- it('displays the reveal button', () => {
- expect(findRevealButton().exists()).toBe(true);
- });
+ describe('When table has variables', () => {
+ beforeEach(() => {
+ createComponent({ provide });
+ });
- it('displays the correct amount of variables', async () => {
- expect(wrapper.findAll('.js-ci-variable-row')).toHaveLength(defaultProps.variables.length);
- });
+ it('does not display the empty message', () => {
+ expect(findEmptyVariablesPlaceholder().exists()).toBe(false);
+ });
- it('displays the correct variable options', async () => {
- expect(findOptionsValues(0)).toBe('Protected, Expanded');
- expect(findOptionsValues(1)).toBe('Masked');
- });
+ it('displays the reveal button', () => {
+ expect(findRevealButton().exists()).toBe(true);
+ });
- it('enables the Add Variable button', () => {
- expect(findAddButton().props('disabled')).toBe(false);
- });
- });
+ it('displays the correct amount of variables', async () => {
+ expect(wrapper.findAll('.js-ci-variable-row')).toHaveLength(defaultProps.variables.length);
+ });
- describe('When variables have exceeded the max limit', () => {
- beforeEach(() => {
- createComponent({ props: { maxVariableLimit: mockVariables(projectString).length } });
- });
+ it('displays the correct variable options', async () => {
+ expect(findOptionsValues(0)).toBe('Protected, Expanded');
+ expect(findOptionsValues(1)).toBe('Masked');
+ });
- it('disables the Add Variable button', () => {
- expect(findAddButton().props('disabled')).toBe(true);
+ it('enables the Add Variable button', () => {
+ expect(findAddButton().props('disabled')).toBe(false);
+ });
});
- });
- describe('max limit reached alert', () => {
- describe('when there is no variable limit', () => {
+ describe('When variables have exceeded the max limit', () => {
beforeEach(() => {
createComponent({
- props: { maxVariableLimit: 0 },
+ props: { maxVariableLimit: mockVariables(projectString).length },
+ provide,
});
});
- it('hides alert', () => {
- expect(findLimitReachedAlerts().length).toBe(0);
+ it('disables the Add Variable button', () => {
+ expect(findAddButton().props('disabled')).toBe(true);
});
});
- describe('when variable limit exists', () => {
- it('hides alert when limit has not been reached', () => {
- createComponent();
+ describe('max limit reached alert', () => {
+ describe('when there is no variable limit', () => {
+ beforeEach(() => {
+ createComponent({
+ props: { maxVariableLimit: 0 },
+ provide,
+ });
+ });
- expect(findLimitReachedAlerts().length).toBe(0);
+ it('hides alert', () => {
+ expect(findLimitReachedAlerts().length).toBe(0);
+ });
});
- it('shows alert when limit has been reached', () => {
- const exceedsVariableLimitText = generateExceedsVariableLimitText(
- defaultProps.entity,
- defaultProps.variables.length,
- mockMaxVariableLimit,
- );
+ describe('when variable limit exists', () => {
+ it('hides alert when limit has not been reached', () => {
+ createComponent({ provide });
- createComponent({
- props: { maxVariableLimit: mockMaxVariableLimit },
+ expect(findLimitReachedAlerts().length).toBe(0);
});
- expect(findLimitReachedAlerts().length).toBe(2);
+ it('shows alert when limit has been reached', () => {
+ const exceedsVariableLimitText = generateExceedsVariableLimitText(
+ defaultProps.entity,
+ defaultProps.variables.length,
+ mockMaxVariableLimit,
+ );
+
+ createComponent({
+ props: { maxVariableLimit: mockMaxVariableLimit },
+ });
- expect(findLimitReachedAlerts().at(0).props('dismissible')).toBe(false);
- expect(findLimitReachedAlerts().at(0).text()).toContain(exceedsVariableLimitText);
+ expect(findLimitReachedAlerts().length).toBe(2);
- expect(findLimitReachedAlerts().at(1).props('dismissible')).toBe(false);
- expect(findLimitReachedAlerts().at(1).text()).toContain(exceedsVariableLimitText);
+ expect(findLimitReachedAlerts().at(0).props('dismissible')).toBe(false);
+ expect(findLimitReachedAlerts().at(0).text()).toContain(exceedsVariableLimitText);
+
+ expect(findLimitReachedAlerts().at(1).props('dismissible')).toBe(false);
+ expect(findLimitReachedAlerts().at(1).text()).toContain(exceedsVariableLimitText);
+ });
});
});
- });
- describe('Table click actions', () => {
- beforeEach(() => {
- createComponent();
- });
+ describe('Table click actions', () => {
+ beforeEach(() => {
+ createComponent({ provide });
+ });
- it('reveals secret values when button is clicked', async () => {
- expect(findHiddenValues()).toHaveLength(defaultProps.variables.length);
- expect(findRevealedValues()).toHaveLength(0);
+ it('reveals secret values when button is clicked', async () => {
+ expect(findHiddenValues()).toHaveLength(defaultProps.variables.length);
+ expect(findRevealedValues()).toHaveLength(0);
- await findRevealButton().trigger('click');
+ await findRevealButton().trigger('click');
- expect(findHiddenValues()).toHaveLength(0);
- expect(findRevealedValues()).toHaveLength(defaultProps.variables.length);
- });
+ expect(findHiddenValues()).toHaveLength(0);
+ expect(findRevealedValues()).toHaveLength(defaultProps.variables.length);
+ });
- it('dispatches `setSelectedVariable` with correct variable to edit', async () => {
- await findEditButton().trigger('click');
+ it('dispatches `setSelectedVariable` with correct variable to edit', async () => {
+ await findEditButton().trigger('click');
- expect(wrapper.emitted('set-selected-variable')).toEqual([[defaultProps.variables[0]]]);
- });
+ expect(wrapper.emitted('set-selected-variable')).toEqual([[defaultProps.variables[0]]]);
+ });
- it('dispatches `setSelectedVariable` with no variable when adding a new one', async () => {
- await findAddButton().trigger('click');
+ it('dispatches `setSelectedVariable` with no variable when adding a new one', async () => {
+ await findAddButton().trigger('click');
- expect(wrapper.emitted('set-selected-variable')).toEqual([[null]]);
+ expect(wrapper.emitted('set-selected-variable')).toEqual([[null]]);
+ });
});
});
});
diff --git a/spec/frontend/ci/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js b/spec/frontend/ci/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js
index b00e1adab63..48a85eba433 100644
--- a/spec/frontend/ci/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/code_snippet_alert/code_snippet_alert_spec.js
@@ -41,10 +41,6 @@ describe('EE - CodeSnippetAlert', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it("provides a link to the feature's documentation", () => {
const docsLink = findDocsLink();
diff --git a/spec/frontend/ci/pipeline_editor/components/commit/commit_form_spec.js b/spec/frontend/ci/pipeline_editor/components/commit/commit_form_spec.js
index 8e1d8081dd8..b2dfa900b1d 100644
--- a/spec/frontend/ci/pipeline_editor/components/commit/commit_form_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/commit/commit_form_spec.js
@@ -33,10 +33,6 @@ describe('Pipeline Editor | Commit Form', () => {
const findSubmitBtn = () => wrapper.find('[type="submit"]');
const findCancelBtn = () => wrapper.find('[type="reset"]');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the form is displayed', () => {
beforeEach(async () => {
createComponent();
diff --git a/spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js b/spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js
index f6e93c55bbb..f8be035d33c 100644
--- a/spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js
@@ -113,10 +113,6 @@ describe('Pipeline Editor | Commit section', () => {
await waitForPromises();
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the user commits a new file', () => {
beforeEach(async () => {
mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse);
diff --git a/spec/frontend/ci/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js b/spec/frontend/ci/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js
index 137137ec657..0ecb77674d5 100644
--- a/spec/frontend/ci/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/drawer/cards/first_pipeline_card_spec.js
@@ -21,10 +21,6 @@ describe('First pipeline card', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the title', () => {
expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.title);
});
diff --git a/spec/frontend/ci/pipeline_editor/components/drawer/cards/getting_started_card_spec.js b/spec/frontend/ci/pipeline_editor/components/drawer/cards/getting_started_card_spec.js
index cdce757ce7c..417597eaf1f 100644
--- a/spec/frontend/ci/pipeline_editor/components/drawer/cards/getting_started_card_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/drawer/cards/getting_started_card_spec.js
@@ -12,10 +12,6 @@ describe('Getting started card', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the title', () => {
expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.title);
});
diff --git a/spec/frontend/ci/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js b/spec/frontend/ci/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js
index 6909916c3e6..5399924b462 100644
--- a/spec/frontend/ci/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/drawer/cards/pipeline_config_reference_card_spec.js
@@ -33,10 +33,6 @@ describe('Pipeline config reference card', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the title', () => {
expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.title);
});
diff --git a/spec/frontend/ci/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js b/spec/frontend/ci/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js
index 0c6879020de..547ba3cbd8b 100644
--- a/spec/frontend/ci/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/drawer/cards/visualize_and_lint_card_spec.js
@@ -12,10 +12,6 @@ describe('Visual and Lint card', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the title', () => {
expect(wrapper.text()).toContain(wrapper.vm.$options.i18n.title);
});
diff --git a/spec/frontend/ci/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js b/spec/frontend/ci/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js
index 42e372cc1db..b07d63dd5d9 100644
--- a/spec/frontend/ci/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js
@@ -11,10 +11,6 @@ describe('Pipeline editor drawer', () => {
wrapper = shallowMount(PipelineEditorDrawer);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('emits close event when closing the drawer', () => {
createComponent();
diff --git a/spec/frontend/ci/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js b/spec/frontend/ci/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js
index f510c61ee74..b0c889cfc9f 100644
--- a/spec/frontend/ci/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/drawer/ui/demo_job_pill_spec.js
@@ -17,10 +17,6 @@ describe('Demo job pill', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the jobName', () => {
expect(wrapper.text()).toContain(jobName);
});
diff --git a/spec/frontend/ci/pipeline_editor/components/editor/ci_config_merged_preview_spec.js b/spec/frontend/ci/pipeline_editor/components/editor/ci_config_merged_preview_spec.js
index 2a2bc2547cc..2182b6e9cc6 100644
--- a/spec/frontend/ci/pipeline_editor/components/editor/ci_config_merged_preview_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/editor/ci_config_merged_preview_spec.js
@@ -34,10 +34,6 @@ describe('Text editor component', () => {
const findIcon = () => wrapper.findComponent(GlIcon);
const findEditor = () => wrapper.findComponent(MockSourceEditor);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when status is valid', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ci/pipeline_editor/components/editor/ci_editor_header_spec.js b/spec/frontend/ci/pipeline_editor/components/editor/ci_editor_header_spec.js
index dc72694d26f..560e8840d57 100644
--- a/spec/frontend/ci/pipeline_editor/components/editor/ci_editor_header_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/editor/ci_editor_header_spec.js
@@ -26,7 +26,6 @@ describe('CI Editor Header', () => {
const findHelpBtn = () => wrapper.findByTestId('drawer-toggle');
afterEach(() => {
- wrapper.destroy();
unmockTracking();
});
diff --git a/spec/frontend/ci/pipeline_editor/components/editor/text_editor_spec.js b/spec/frontend/ci/pipeline_editor/components/editor/text_editor_spec.js
index ec987be8cb8..0be26570fbf 100644
--- a/spec/frontend/ci/pipeline_editor/components/editor/text_editor_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/editor/text_editor_spec.js
@@ -1,7 +1,11 @@
import { shallowMount } from '@vue/test-utils';
+import { editor as monacoEditor } from 'monaco-editor';
+import SourceEditor from '~/vue_shared/components/source_editor.vue';
import { EDITOR_READY_EVENT } from '~/editor/constants';
+import { CiSchemaExtension as MockedCiSchemaExtension } from '~/editor/extensions/source_editor_ci_schema_ext';
import { SOURCE_EDITOR_DEBOUNCE } from '~/ci/pipeline_editor/constants';
+import eventHub, { SCROLL_EDITOR_TO_BOTTOM } from '~/ci/pipeline_editor/event_hub';
import TextEditor from '~/ci/pipeline_editor/components/editor/text_editor.vue';
import {
mockCiConfigPath,
@@ -12,19 +16,26 @@ import {
mockDefaultBranch,
} from '../../mock_data';
+jest.mock('monaco-editor');
+jest.mock('~/editor/extensions/source_editor_ci_schema_ext', () => {
+ const { createMockSourceEditorExtension } = jest.requireActual(
+ 'helpers/create_mock_source_editor_extension',
+ );
+ const { CiSchemaExtension } = jest.requireActual(
+ '~/editor/extensions/source_editor_ci_schema_ext',
+ );
+
+ return {
+ CiSchemaExtension: createMockSourceEditorExtension(CiSchemaExtension),
+ };
+});
+
describe('Pipeline Editor | Text editor component', () => {
let wrapper;
let editorReadyListener;
- let mockUse;
- let mockRegisterCiSchema;
- let mockEditorInstance;
- let editorInstanceDetail;
-
- const MockSourceEditor = {
- template: '<div/>',
- props: ['value', 'fileName', 'editorOptions', 'debounceValue'],
- };
+
+ const getMonacoEditor = () => monacoEditor.create.mock.results[0].value;
const createComponent = (mountFn = shallowMount) => {
wrapper = mountFn(TextEditor, {
@@ -44,33 +55,17 @@ describe('Pipeline Editor | Text editor component', () => {
[EDITOR_READY_EVENT]: editorReadyListener,
},
stubs: {
- SourceEditor: MockSourceEditor,
+ SourceEditor,
},
});
};
- const findEditor = () => wrapper.findComponent(MockSourceEditor);
+ const findEditor = () => wrapper.findComponent(SourceEditor);
beforeEach(() => {
- editorReadyListener = jest.fn();
- mockUse = jest.fn();
- mockRegisterCiSchema = jest.fn();
- mockEditorInstance = {
- use: mockUse,
- registerCiSchema: mockRegisterCiSchema,
- };
- editorInstanceDetail = {
- detail: {
- instance: mockEditorInstance,
- },
- };
- });
+ jest.spyOn(monacoEditor, 'create');
- afterEach(() => {
- wrapper.destroy();
-
- mockUse.mockClear();
- mockRegisterCiSchema.mockClear();
+ editorReadyListener = jest.fn();
});
describe('template', () => {
@@ -99,21 +94,34 @@ describe('Pipeline Editor | Text editor component', () => {
});
it('bubbles up events', () => {
- findEditor().vm.$emit(EDITOR_READY_EVENT, editorInstanceDetail);
-
expect(editorReadyListener).toHaveBeenCalled();
});
+
+ it('scrolls editor to bottom on scroll editor to bottom event', () => {
+ const setScrollTop = jest.spyOn(getMonacoEditor(), 'setScrollTop');
+
+ eventHub.$emit(SCROLL_EDITOR_TO_BOTTOM);
+
+ expect(setScrollTop).toHaveBeenCalledWith(getMonacoEditor().getScrollHeight());
+ });
+
+ it('when destroyed, destroys scroll listener', () => {
+ const setScrollTop = jest.spyOn(getMonacoEditor(), 'setScrollTop');
+
+ wrapper.destroy();
+ eventHub.$emit(SCROLL_EDITOR_TO_BOTTOM);
+
+ expect(setScrollTop).not.toHaveBeenCalled();
+ });
});
describe('CI schema', () => {
beforeEach(() => {
createComponent();
- findEditor().vm.$emit(EDITOR_READY_EVENT, editorInstanceDetail);
});
it('configures editor with syntax highlight', () => {
- expect(mockUse).toHaveBeenCalledTimes(1);
- expect(mockRegisterCiSchema).toHaveBeenCalledTimes(1);
+ expect(MockedCiSchemaExtension.mockedMethods.registerCiSchema).toHaveBeenCalledTimes(1);
});
});
});
diff --git a/spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js b/spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js
index a26232df58f..bf14f4c4cd6 100644
--- a/spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/file-nav/branch_switcher_spec.js
@@ -133,10 +133,6 @@ describe('Pipeline editor branch switcher', () => {
mockAvailableBranchQuery = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const testErrorHandling = () => {
expect(wrapper.emitted('showError')).toBeDefined();
expect(wrapper.emitted('showError')[0]).toEqual([
diff --git a/spec/frontend/ci/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js b/spec/frontend/ci/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
index 907db16913c..19c113689c2 100644
--- a/spec/frontend/ci/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
@@ -48,10 +48,6 @@ describe('Pipeline editor file nav', () => {
const findFileTreeBtn = () => wrapper.findByTestId('file-tree-toggle');
const findPopoverContainer = () => wrapper.findComponent(FileTreePopover);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ci/pipeline_editor/components/file-tree/container_spec.js b/spec/frontend/ci/pipeline_editor/components/file-tree/container_spec.js
index 11ba517e0eb..306dd78d395 100644
--- a/spec/frontend/ci/pipeline_editor/components/file-tree/container_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/file-tree/container_spec.js
@@ -22,7 +22,7 @@ describe('Pipeline editor file nav', () => {
includes,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
stubs,
}),
@@ -35,7 +35,6 @@ describe('Pipeline editor file nav', () => {
afterEach(() => {
localStorage.clear();
- wrapper.destroy();
});
describe('template', () => {
diff --git a/spec/frontend/ci/pipeline_editor/components/file-tree/file_item_spec.js b/spec/frontend/ci/pipeline_editor/components/file-tree/file_item_spec.js
index bceb741f91c..80737e9a8ab 100644
--- a/spec/frontend/ci/pipeline_editor/components/file-tree/file_item_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/file-tree/file_item_spec.js
@@ -18,10 +18,6 @@ describe('Pipeline editor file nav', () => {
const fileIcon = () => wrapper.findComponent(FileIcon);
const link = () => wrapper.findComponent(GlLink);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
beforeEach(() => {
createComponent();
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 555b9f29fbf..a651664851e 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
@@ -26,11 +26,6 @@ describe('Pipeline editor header', () => {
const findPipelineStatus = () => wrapper.findComponent(PipelineStatus);
const findValidationSegment = () => wrapper.findComponent(ValidationSegment);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('template', () => {
it('hides the pipeline status for new projects without a CI file', () => {
createComponent({ props: { isNewCiConfigFile: true } });
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 a62c51ffb59..3faa2890254 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
@@ -48,7 +48,6 @@ describe('Pipeline Status', () => {
afterEach(() => {
mockPipelineQuery.mockReset();
- wrapper.destroy();
});
describe('loading icon', () => {
diff --git a/spec/frontend/ci/pipeline_editor/components/header/validation_segment_spec.js b/spec/frontend/ci/pipeline_editor/components/header/validation_segment_spec.js
index 0853a6f4ca4..a107a626c6d 100644
--- a/spec/frontend/ci/pipeline_editor/components/header/validation_segment_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/header/validation_segment_spec.js
@@ -1,11 +1,10 @@
import VueApollo from 'vue-apollo';
-import { GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
import Vue from 'vue';
import { escape } from 'lodash';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
import { sprintf } from '~/locale';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
import ValidationSegment, {
i18n,
} from '~/ci/pipeline_editor/components/header/validation_segment.vue';
@@ -20,8 +19,8 @@ import {
} from '~/ci/pipeline_editor/constants';
import {
mergeUnwrappedCiConfig,
+ mockCiTroubleshootingPath,
mockCiYml,
- mockLintUnavailableHelpPagePath,
mockYmlHelpPagePath,
} from '../../mock_data';
@@ -43,29 +42,27 @@ describe('Validation segment component', () => {
},
});
- wrapper = extendedWrapper(
- shallowMount(ValidationSegment, {
- apolloProvider: mockApollo,
- provide: {
- ymlHelpPagePath: mockYmlHelpPagePath,
- lintUnavailableHelpPagePath: mockLintUnavailableHelpPagePath,
- },
- propsData: {
- ciConfig: mergeUnwrappedCiConfig(),
- ciFileContent: mockCiYml,
- ...props,
- },
- }),
- );
+ wrapper = shallowMountExtended(ValidationSegment, {
+ apolloProvider: mockApollo,
+ provide: {
+ ymlHelpPagePath: mockYmlHelpPagePath,
+ ciTroubleshootingPath: mockCiTroubleshootingPath,
+ },
+ propsData: {
+ ciConfig: mergeUnwrappedCiConfig(),
+ ciFileContent: mockCiYml,
+ ...props,
+ },
+ stubs: {
+ GlSprintf,
+ },
+ });
};
const findIcon = () => wrapper.findComponent(GlIcon);
- const findLearnMoreLink = () => wrapper.findByTestId('learnMoreLink');
- const findValidationMsg = () => wrapper.findByTestId('validationMsg');
-
- afterEach(() => {
- wrapper.destroy();
- });
+ const findHelpLink = () => wrapper.findComponent(GlLink);
+ const findValidationMsg = () => wrapper.findComponent(GlSprintf);
+ const findValidationSegment = () => wrapper.findByTestId('validation-segment');
it('shows the loading state', () => {
createComponent({ appStatus: EDITOR_APP_STATUS_LOADING });
@@ -82,8 +79,12 @@ describe('Validation segment component', () => {
expect(findIcon().props('name')).toBe('check');
});
+ it('does not render a link', () => {
+ expect(findHelpLink().exists()).toBe(false);
+ });
+
it('shows a message for empty state', () => {
- expect(findValidationMsg().text()).toBe(i18n.empty);
+ expect(findValidationSegment().text()).toBe(i18n.empty);
});
});
@@ -97,12 +98,15 @@ describe('Validation segment component', () => {
});
it('shows a message for valid state', () => {
- expect(findValidationMsg().text()).toContain(i18n.valid);
+ expect(findValidationSegment().text()).toBe(
+ sprintf(i18n.valid, { linkStart: '', linkEnd: '' }),
+ );
});
it('shows the learn more link', () => {
- expect(findLearnMoreLink().attributes('href')).toBe(mockYmlHelpPagePath);
- expect(findLearnMoreLink().text()).toBe(i18n.learnMore);
+ expect(findValidationMsg().exists()).toBe(true);
+ expect(findValidationMsg().text()).toBe('Learn more');
+ expect(findHelpLink().attributes('href')).toBe(mockYmlHelpPagePath);
});
});
@@ -117,13 +121,16 @@ describe('Validation segment component', () => {
expect(findIcon().props('name')).toBe('warning-solid');
});
- it('has message for invalid state', () => {
- expect(findValidationMsg().text()).toBe(i18n.invalid);
+ it('shows a message for invalid state', () => {
+ expect(findValidationSegment().text()).toBe(
+ sprintf(i18n.invalid, { linkStart: '', linkEnd: '' }),
+ );
});
it('shows the learn more link', () => {
- expect(findLearnMoreLink().attributes('href')).toBe(mockYmlHelpPagePath);
- expect(findLearnMoreLink().text()).toBe('Learn more');
+ expect(findValidationMsg().exists()).toBe(true);
+ expect(findValidationMsg().text()).toBe('Learn more');
+ expect(findHelpLink().attributes('href')).toBe(mockYmlHelpPagePath);
});
describe('with multiple errors', () => {
@@ -140,11 +147,16 @@ describe('Validation segment component', () => {
},
});
});
+
+ it('shows the learn more link', () => {
+ expect(findValidationMsg().exists()).toBe(true);
+ expect(findValidationMsg().text()).toBe('Learn more');
+ expect(findHelpLink().attributes('href')).toBe(mockYmlHelpPagePath);
+ });
+
it('shows an invalid state with an error', () => {
- // Test the error is shown _and_ the string matches
- expect(findValidationMsg().text()).toContain(firstError);
- expect(findValidationMsg().text()).toBe(
- sprintf(i18n.invalidWithReason, { reason: firstError }),
+ expect(findValidationSegment().text()).toBe(
+ sprintf(i18n.invalidWithReason, { reason: firstError, linkStart: '', linkEnd: '' }),
);
});
});
@@ -163,10 +175,8 @@ describe('Validation segment component', () => {
});
});
it('shows an invalid state with an error while preventing XSS', () => {
- const { innerHTML } = findValidationMsg().element;
-
- expect(innerHTML).not.toContain(evilError);
- expect(innerHTML).toContain(escape(evilError));
+ expect(findValidationSegment().html()).not.toContain(evilError);
+ expect(findValidationSegment().html()).toContain(escape(evilError));
});
});
});
@@ -182,16 +192,18 @@ describe('Validation segment component', () => {
});
it('show a message that the service is unavailable', () => {
- expect(findValidationMsg().text()).toBe(i18n.unavailableValidation);
+ expect(findValidationSegment().text()).toBe(
+ sprintf(i18n.unavailableValidation, { linkStart: '', linkEnd: '' }),
+ );
});
it('shows the time-out icon', () => {
expect(findIcon().props('name')).toBe('time-out');
});
- it('shows the learn more link', () => {
- expect(findLearnMoreLink().attributes('href')).toBe(mockLintUnavailableHelpPagePath);
- expect(findLearnMoreLink().text()).toBe(i18n.learnMore);
+ it('shows the link to ci troubleshooting', () => {
+ expect(findValidationMsg().exists()).toBe(true);
+ expect(findHelpLink().attributes('href')).toBe(mockCiTroubleshootingPath);
});
});
});
diff --git a/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item_spec.js b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item_spec.js
new file mode 100644
index 00000000000..c7c40c3a4b9
--- /dev/null
+++ b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item_spec.js
@@ -0,0 +1,39 @@
+import ImageItem from '~/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item.vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { JOB_TEMPLATE } from '~/ci/pipeline_editor/components/job_assistant_drawer/constants';
+
+describe('Image item', () => {
+ let wrapper;
+
+ const findImageNameInput = () => wrapper.findByTestId('image-name-input');
+ const findImageEntrypointInput = () => wrapper.findByTestId('image-entrypoint-input');
+
+ const dummyImageName = 'dummyImageName';
+ const dummyImageEntrypoint = 'dummyImageEntrypoint';
+
+ const createComponent = ({ job = JSON.parse(JSON.stringify(JOB_TEMPLATE)) } = {}) => {
+ wrapper = shallowMountExtended(ImageItem, {
+ propsData: {
+ job,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should emit update job event when filling inputs', () => {
+ expect(wrapper.emitted('update-job')).toBeUndefined();
+
+ findImageNameInput().vm.$emit('input', dummyImageName);
+
+ expect(wrapper.emitted('update-job')).toHaveLength(1);
+ expect(wrapper.emitted('update-job')[0]).toEqual(['image.name', dummyImageName]);
+
+ findImageEntrypointInput().vm.$emit('input', dummyImageEntrypoint);
+
+ expect(wrapper.emitted('update-job')).toHaveLength(2);
+ expect(wrapper.emitted('update-job')[1]).toEqual(['image.entrypoint', [dummyImageEntrypoint]]);
+ });
+});
diff --git a/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item_spec.js b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item_spec.js
new file mode 100644
index 00000000000..eaad0dae90d
--- /dev/null
+++ b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item_spec.js
@@ -0,0 +1,61 @@
+import createStore from '~/ci/pipeline_editor/store';
+import JobSetupItem from '~/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item.vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { JOB_TEMPLATE } from '~/ci/pipeline_editor/components/job_assistant_drawer/constants';
+
+describe('Job setup item', () => {
+ let wrapper;
+
+ const findJobNameInput = () => wrapper.findByTestId('job-name-input');
+ const findJobScriptInput = () => wrapper.findByTestId('job-script-input');
+ const findJobTagsInput = () => wrapper.findByTestId('job-tags-input');
+ const findJobStageInput = () => wrapper.findByTestId('job-stage-input');
+
+ const dummyJobName = 'dummyJobName';
+ const dummyJobScript = 'dummyJobScript';
+ const dummyJobStage = 'dummyJobStage';
+ const dummyJobTags = ['tag1'];
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(JobSetupItem, {
+ store: createStore(),
+ propsData: {
+ tagOptions: [
+ { id: 'tag1', name: 'tag1' },
+ { id: 'tag2', name: 'tag2' },
+ ],
+ isNameValid: true,
+ isScriptValid: true,
+ job: JSON.parse(JSON.stringify(JOB_TEMPLATE)),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should emit update job event when filling inputs', () => {
+ expect(wrapper.emitted('update-job')).toBeUndefined();
+
+ findJobNameInput().vm.$emit('input', dummyJobName);
+
+ expect(wrapper.emitted('update-job')).toHaveLength(1);
+ expect(wrapper.emitted('update-job')[0]).toEqual(['name', dummyJobName]);
+
+ findJobScriptInput().vm.$emit('input', dummyJobScript);
+
+ expect(wrapper.emitted('update-job')).toHaveLength(2);
+ expect(wrapper.emitted('update-job')[1]).toEqual(['script', dummyJobScript]);
+
+ findJobStageInput().vm.$emit('input', dummyJobStage);
+
+ expect(wrapper.emitted('update-job')).toHaveLength(3);
+ expect(wrapper.emitted('update-job')[2]).toEqual(['stage', dummyJobStage]);
+
+ findJobTagsInput().vm.$emit('input', dummyJobTags);
+
+ expect(wrapper.emitted('update-job')).toHaveLength(4);
+ expect(wrapper.emitted('update-job')[3]).toEqual(['tags', dummyJobTags]);
+ });
+});
diff --git a/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js
index 79200d92598..b293805d653 100644
--- a/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js
@@ -1,24 +1,47 @@
import { GlDrawer } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
+import { stringify } from 'yaml';
import JobAssistantDrawer from '~/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer.vue';
+import JobSetupItem from '~/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item.vue';
+import ImageItem from '~/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item.vue';
+import getAllRunners from '~/ci/runner/graphql/list/all_runners.query.graphql';
+import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
+import createStore from '~/ci/pipeline_editor/store';
+import { mockAllRunnersQueryResponse } from 'jest/ci/pipeline_editor/mock_data';
import { mountExtended } from 'helpers/vue_test_utils_helper';
+import eventHub, { SCROLL_EDITOR_TO_BOTTOM } from '~/ci/pipeline_editor/event_hub';
Vue.use(VueApollo);
describe('Job assistant drawer', () => {
let wrapper;
+ let mockApollo;
+
+ const dummyJobName = 'a';
+ const dummyJobScript = 'b';
+ const dummyImageName = 'c';
+ const dummyImageEntrypoint = 'd';
const findDrawer = () => wrapper.findComponent(GlDrawer);
+ const findJobSetupItem = () => wrapper.findComponent(JobSetupItem);
+ const findImageItem = () => wrapper.findComponent(ImageItem);
+ const findConfirmButton = () => wrapper.findByTestId('confirm-button');
const findCancelButton = () => wrapper.findByTestId('cancel-button');
const createComponent = () => {
+ mockApollo = createMockApollo([
+ [getAllRunners, jest.fn().mockResolvedValue(mockAllRunnersQueryResponse)],
+ ]);
+
wrapper = mountExtended(JobAssistantDrawer, {
+ store: createStore(),
propsData: {
isVisible: true,
},
+ apolloProvider: mockApollo,
});
};
@@ -27,6 +50,14 @@ describe('Job assistant drawer', () => {
await waitForPromises();
});
+ it('should contain job setup accordion', () => {
+ expect(findJobSetupItem().exists()).toBe(true);
+ });
+
+ it('should contain image accordion', () => {
+ expect(findImageItem().exists()).toBe(true);
+ });
+
it('should emit close job assistant drawer event when closing the drawer', () => {
expect(wrapper.emitted('close-job-assistant-drawer')).toBeUndefined();
@@ -42,4 +73,83 @@ describe('Job assistant drawer', () => {
expect(wrapper.emitted('close-job-assistant-drawer')).toHaveLength(1);
});
+
+ it('trigger validate if job name is empty', async () => {
+ const updateCiConfigSpy = jest.spyOn(wrapper.vm, 'updateCiConfig');
+ findJobSetupItem().vm.$emit('update-job', 'script', 'b');
+ findConfirmButton().trigger('click');
+
+ await nextTick();
+
+ expect(findJobSetupItem().props('isNameValid')).toBe(false);
+ expect(findJobSetupItem().props('isScriptValid')).toBe(true);
+ expect(updateCiConfigSpy).toHaveBeenCalledTimes(0);
+ });
+
+ describe('when enter valid input', () => {
+ beforeEach(() => {
+ findJobSetupItem().vm.$emit('update-job', 'name', dummyJobName);
+ findJobSetupItem().vm.$emit('update-job', 'script', dummyJobScript);
+ findImageItem().vm.$emit('update-job', 'image.name', dummyImageName);
+ findImageItem().vm.$emit('update-job', 'image.entrypoint', [dummyImageEntrypoint]);
+ });
+
+ it('passes correct prop to accordions', () => {
+ const accordions = [findJobSetupItem(), findImageItem()];
+ accordions.forEach((accordion) => {
+ expect(accordion.props('job')).toMatchObject({
+ name: dummyJobName,
+ script: dummyJobScript,
+ image: {
+ name: dummyImageName,
+ entrypoint: [dummyImageEntrypoint],
+ },
+ });
+ });
+ });
+
+ it('job name and script state should be valid', () => {
+ expect(findJobSetupItem().props('isNameValid')).toBe(true);
+ expect(findJobSetupItem().props('isScriptValid')).toBe(true);
+ });
+
+ it('should clear job data when click confirm button', async () => {
+ findConfirmButton().trigger('click');
+
+ await nextTick();
+
+ expect(findJobSetupItem().props('job')).toMatchObject({ name: '', script: '' });
+ });
+
+ it('should clear job data when click cancel button', async () => {
+ findCancelButton().trigger('click');
+
+ await nextTick();
+
+ expect(findJobSetupItem().props('job')).toMatchObject({ name: '', script: '' });
+ });
+
+ it('should update correct ci content when click add button', () => {
+ const updateCiConfigSpy = jest.spyOn(wrapper.vm, 'updateCiConfig');
+
+ findConfirmButton().trigger('click');
+
+ expect(updateCiConfigSpy).toHaveBeenCalledWith(
+ `\n${stringify({
+ [dummyJobName]: {
+ script: dummyJobScript,
+ image: { name: dummyImageName, entrypoint: [dummyImageEntrypoint] },
+ },
+ })}`,
+ );
+ });
+
+ it('should emit scroll editor to button event when click add button', () => {
+ const eventHubSpy = jest.spyOn(eventHub, '$emit');
+
+ findConfirmButton().trigger('click');
+
+ expect(eventHubSpy).toHaveBeenCalledWith(SCROLL_EDITOR_TO_BOTTOM);
+ });
+ });
});
diff --git a/spec/frontend/ci/pipeline_editor/components/lint/ci_lint_results_spec.js b/spec/frontend/ci/pipeline_editor/components/lint/ci_lint_results_spec.js
index d43bdec3a33..cc9a77ae525 100644
--- a/spec/frontend/ci/pipeline_editor/components/lint/ci_lint_results_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/lint/ci_lint_results_spec.js
@@ -40,10 +40,6 @@ describe('CI Lint Results', () => {
const findAfterScripts = findAllByTestId('after-script');
const filterEmptyScripts = (property) => mockJobs.filter((job) => job[property].length !== 0);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Empty results', () => {
it('renders with no jobs, errors or warnings defined', () => {
createComponent({ jobs: undefined, errors: undefined, warnings: undefined }, shallowMount);
diff --git a/spec/frontend/ci/pipeline_editor/components/lint/ci_lint_warnings_spec.js b/spec/frontend/ci/pipeline_editor/components/lint/ci_lint_warnings_spec.js
index b5e3ea06c2c..d09e22898cd 100644
--- a/spec/frontend/ci/pipeline_editor/components/lint/ci_lint_warnings_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/lint/ci_lint_warnings_spec.js
@@ -21,11 +21,6 @@ describe('CI lint warnings', () => {
const findWarnings = () => wrapper.findAll('[data-testid="ci-lint-warning"]');
const findWarningMessage = () => trimText(wrapper.findComponent(GlSprintf).text());
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('displays the warning alert', () => {
createComponent();
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 f40db50aab7..52a543c7686 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
@@ -119,6 +119,7 @@ describe('Pipeline editor tabs component', () => {
});
afterEach(() => {
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
wrapper.destroy();
});
diff --git a/spec/frontend/ci/pipeline_editor/components/popovers/file_tree_popover_spec.js b/spec/frontend/ci/pipeline_editor/components/popovers/file_tree_popover_spec.js
index 63ebfc0559d..a9aabb103f2 100644
--- a/spec/frontend/ci/pipeline_editor/components/popovers/file_tree_popover_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/popovers/file_tree_popover_spec.js
@@ -22,7 +22,6 @@ describe('FileTreePopover component', () => {
afterEach(() => {
localStorage.clear();
- wrapper.destroy();
});
describe('default', () => {
diff --git a/spec/frontend/ci/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js b/spec/frontend/ci/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js
index cf0b974081e..23f9c7a87ee 100644
--- a/spec/frontend/ci/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/popovers/validate_pipeline_popover_spec.js
@@ -19,10 +19,6 @@ describe('ValidatePopover component', () => {
const findHelpLink = () => wrapper.findByTestId('help-link');
const findFeedbackLink = () => wrapper.findByTestId('feedback-link');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
beforeEach(async () => {
createComponent({
diff --git a/spec/frontend/ci/pipeline_editor/components/popovers/walkthrough_popover_spec.js b/spec/frontend/ci/pipeline_editor/components/popovers/walkthrough_popover_spec.js
index ca6033f2ff5..186fd803d47 100644
--- a/spec/frontend/ci/pipeline_editor/components/popovers/walkthrough_popover_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/popovers/walkthrough_popover_spec.js
@@ -12,10 +12,6 @@ describe('WalkthroughPopover component', () => {
return extendedWrapper(mountFn(WalkthroughPopover));
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('CTA button clicked', () => {
beforeEach(async () => {
wrapper = createComponent(mount);
diff --git a/spec/frontend/ci/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js b/spec/frontend/ci/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js
index b22c98e5544..8b8dd4d22c2 100644
--- a/spec/frontend/ci/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/ui/confirm_unsaved_changes_dialog_spec.js
@@ -4,10 +4,9 @@ import ConfirmDialog from '~/ci/pipeline_editor/components/ui/confirm_unsaved_ch
describe('pipeline_editor/components/ui/confirm_unsaved_changes_dialog', () => {
let beforeUnloadEvent;
let setDialogContent;
- let wrapper;
const createComponent = (propsData = {}) => {
- wrapper = shallowMount(ConfirmDialog, {
+ shallowMount(ConfirmDialog, {
propsData,
});
};
@@ -21,7 +20,6 @@ describe('pipeline_editor/components/ui/confirm_unsaved_changes_dialog', () => {
afterEach(() => {
beforeUnloadEvent.preventDefault.mockRestore();
setDialogContent.mockRestore();
- wrapper.destroy();
});
it('shows confirmation dialog when there are unsaved changes', () => {
diff --git a/spec/frontend/ci/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js b/spec/frontend/ci/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js
index 3c68f74af43..e636a89c6d9 100644
--- a/spec/frontend/ci/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js
@@ -23,10 +23,6 @@ describe('Pipeline editor empty state', () => {
const findConfirmButton = () => wrapper.findComponent(GlButton);
const findDescription = () => wrapper.findComponent(GlSprintf);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when project uses an external CI config', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/ci/pipeline_editor/components/validate/ci_validate_spec.js b/spec/frontend/ci/pipeline_editor/components/validate/ci_validate_spec.js
index ae25142b455..8874add6bb2 100644
--- a/spec/frontend/ci/pipeline_editor/components/validate/ci_validate_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/validate/ci_validate_spec.js
@@ -99,10 +99,6 @@ describe('Pipeline Editor Validate Tab', () => {
mockBlobContentData = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('while initial CI content is loading', () => {
beforeEach(() => {
createComponent({ isBlobLoading: true });
diff --git a/spec/frontend/ci/pipeline_editor/mock_data.js b/spec/frontend/ci/pipeline_editor/mock_data.js
index 541123d7efc..ecfc477184b 100644
--- a/spec/frontend/ci/pipeline_editor/mock_data.js
+++ b/spec/frontend/ci/pipeline_editor/mock_data.js
@@ -12,7 +12,7 @@ export const mockCommitSha = 'aabbccdd';
export const mockCommitNextSha = 'eeffgghh';
export const mockIncludesHelpPagePath = '/-/includes/help';
export const mockLintHelpPagePath = '/-/lint-help';
-export const mockLintUnavailableHelpPagePath = '/-/pipeline-editor/troubleshoot';
+export const mockCiTroubleshootingPath = '/-/pipeline-editor/troubleshoot';
export const mockSimulatePipelineHelpPagePath = '/-/simulate-pipeline-help';
export const mockYmlHelpPagePath = '/-/yml-help';
export const mockCommitMessage = 'My commit message';
@@ -583,6 +583,91 @@ export const mockCommitCreateResponse = {
},
};
+export const mockAllRunnersQueryResponse = {
+ data: {
+ runners: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Ci::Runner/1',
+ description: 'test',
+ runnerType: 'PROJECT_TYPE',
+ shortSha: 'DdTYMQGS',
+ version: '15.6.1',
+ ipAddress: '127.0.0.1',
+ active: true,
+ locked: true,
+ jobCount: 0,
+ jobExecutionStatus: 'IDLE',
+ tagList: ['tag1', 'tag2', 'tag3'],
+ createdAt: '2022-11-29T09:37:43Z',
+ contactedAt: null,
+ status: 'NEVER_CONTACTED',
+ userPermissions: {
+ updateRunner: true,
+ deleteRunner: true,
+ __typename: 'RunnerPermissions',
+ },
+ groups: null,
+ ownerProject: {
+ id: 'gid://gitlab/Project/1',
+ name: '123',
+ nameWithNamespace: 'Administrator / 123',
+ webUrl: 'http://127.0.0.1:3000/root/test',
+ __typename: 'Project',
+ },
+ __typename: 'CiRunner',
+ upgradeStatus: 'NOT_AVAILABLE',
+ adminUrl: 'http://127.0.0.1:3000/admin/runners/1',
+ editAdminUrl: 'http://127.0.0.1:3000/admin/runners/1/edit',
+ },
+ {
+ id: 'gid://gitlab/Ci::Runner/2',
+ description: 'test',
+ runnerType: 'PROJECT_TYPE',
+ shortSha: 'DdTYMQGA',
+ version: '15.6.1',
+ ipAddress: '127.0.0.1',
+ active: true,
+ locked: true,
+ jobCount: 0,
+ jobExecutionStatus: 'IDLE',
+ tagList: ['tag3', 'tag4'],
+ createdAt: '2022-11-29T09:37:43Z',
+ contactedAt: null,
+ status: 'NEVER_CONTACTED',
+ userPermissions: {
+ updateRunner: true,
+ deleteRunner: true,
+ __typename: 'RunnerPermissions',
+ },
+ groups: null,
+ ownerProject: {
+ id: 'gid://gitlab/Project/1',
+ name: '123',
+ nameWithNamespace: 'Administrator / 123',
+ webUrl: 'http://127.0.0.1:3000/root/test',
+ __typename: 'Project',
+ },
+ __typename: 'CiRunner',
+ upgradeStatus: 'NOT_AVAILABLE',
+ adminUrl: 'http://127.0.0.1:3000/admin/runners/2',
+ editAdminUrl: 'http://127.0.0.1:3000/admin/runners/2/edit',
+ },
+ ],
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor:
+ 'eyJjcmVhdGVkX2F0IjoiMjAyMi0xMS0yOSAwOTozNzo0My40OTEwNTEwMDAgKzAwMDAiLCJpZCI6IjIifQ',
+ endCursor:
+ 'eyJjcmVhdGVkX2F0IjoiMjAyMi0xMS0yOSAwOTozNzo0My40OTEwNTEwMDAgKzAwMDAiLCJpZCI6IjIifQ',
+ __typename: 'PageInfo',
+ },
+ __typename: 'CiRunnerConnection',
+ },
+ },
+};
+
export const mockCommitCreateResponseNewEtag = {
data: {
commitCreate: {
diff --git a/spec/frontend/ci/pipeline_editor/pipeline_editor_app_spec.js b/spec/frontend/ci/pipeline_editor/pipeline_editor_app_spec.js
index a103acb33bc..7a13bfbd1ab 100644
--- a/spec/frontend/ci/pipeline_editor/pipeline_editor_app_spec.js
+++ b/spec/frontend/ci/pipeline_editor/pipeline_editor_app_spec.js
@@ -1,4 +1,4 @@
-import { GlAlert, GlButton, GlLoadingIcon } from '@gitlab/ui';
+import { GlAlert, GlButton, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
@@ -8,6 +8,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
import { objectToQuery, redirectTo } from '~/lib/utils/url_utility';
import { resolvers } from '~/ci/pipeline_editor/graphql/resolvers';
+import createStore from '~/ci/pipeline_editor/store';
import PipelineEditorTabs from '~/ci/pipeline_editor/components/pipeline_editor_tabs.vue';
import PipelineEditorEmptyState from '~/ci/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
import PipelineEditorMessages from '~/ci/pipeline_editor/components/ui/pipeline_editor_messages.vue';
@@ -80,7 +81,9 @@ describe('Pipeline editor app component', () => {
provide = {},
stubs = {},
} = {}) => {
+ const store = createStore();
wrapper = shallowMount(PipelineEditorApp, {
+ store,
provide: { ...defaultProvide, ...provide },
stubs,
mocks: {
@@ -162,10 +165,6 @@ describe('Pipeline editor app component', () => {
mockPipelineQuery = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('loading state', () => {
it('displays a loading icon if the blob query is loading', () => {
createComponent({ blobLoading: true });
@@ -256,6 +255,10 @@ describe('Pipeline editor app component', () => {
.mockImplementation(jest.fn());
});
+ it('available stages is updated', () => {
+ expect(wrapper.vm.$store.state.availableStages).toStrictEqual(['test', 'build']);
+ });
+
it('shows pipeline editor home component', () => {
expect(findEditorHome().exists()).toBe(true);
});
@@ -351,7 +354,9 @@ describe('Pipeline editor app component', () => {
});
it('shows that the lint service is down', () => {
- expect(findValidationSegment().text()).toContain(
+ const validationMessage = findValidationSegment().findComponent(GlSprintf);
+
+ expect(validationMessage.attributes('message')).toContain(
validationSegmenti18n.unavailableValidation,
);
});
diff --git a/spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js b/spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js
index 4f8f2112abe..7ec6d4c6a01 100644
--- a/spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js
+++ b/spec/frontend/ci/pipeline_editor/pipeline_editor_home_spec.js
@@ -67,7 +67,6 @@ describe('Pipeline editor home wrapper', () => {
afterEach(() => {
localStorage.clear();
- wrapper.destroy();
});
describe('renders', () => {
diff --git a/spec/frontend/ci/pipeline_new/components/pipeline_new_form_spec.js b/spec/frontend/ci/pipeline_new/components/pipeline_new_form_spec.js
index 6f18899ebac..1349461d8bc 100644
--- a/spec/frontend/ci/pipeline_new/components/pipeline_new_form_spec.js
+++ b/spec/frontend/ci/pipeline_new/components/pipeline_new_form_spec.js
@@ -32,6 +32,7 @@ import {
mockProjectId,
mockRefs,
mockYamlVariables,
+ mockPipelineConfigButtonText,
} from '../mock_data';
Vue.use(VueApollo);
@@ -42,6 +43,7 @@ jest.mock('~/lib/utils/url_utility', () => ({
const projectRefsEndpoint = '/root/project/refs';
const pipelinesPath = '/root/project/-/pipelines';
+const pipelinesEditorPath = '/root/project/-/ci/editor';
const projectPath = '/root/project/-/pipelines/config_variables';
const newPipelinePostResponse = { id: 1 };
const defaultBranch = 'main';
@@ -65,6 +67,7 @@ describe('Pipeline New Form', () => {
wrapper.findAllByTestId('pipeline-form-ci-variable-value-dropdown');
const findValueDropdownItems = (dropdown) => dropdown.findAllComponents(GlDropdownItem);
const findErrorAlert = () => wrapper.findByTestId('run-pipeline-error-alert');
+ const findPipelineConfigButton = () => wrapper.findByTestId('ci-cd-pipeline-configuration');
const findWarningAlert = () => wrapper.findByTestId('run-pipeline-warning-alert');
const findWarningAlertSummary = () => findWarningAlert().findComponent(GlSprintf);
const findWarnings = () => wrapper.findAllByTestId('run-pipeline-warning');
@@ -106,6 +109,8 @@ describe('Pipeline New Form', () => {
propsData: {
projectId: mockProjectId,
pipelinesPath,
+ pipelinesEditorPath,
+ canViewPipelineEditor: true,
projectPath,
defaultBranch,
refParam: defaultBranch,
@@ -128,7 +133,6 @@ describe('Pipeline New Form', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('Form', () => {
@@ -500,6 +504,17 @@ describe('Pipeline New Form', () => {
expect(findSubmitButton().props('disabled')).toBe(false);
});
+ it('shows pipeline configuration button for user who can view', () => {
+ expect(findPipelineConfigButton().exists()).toBe(true);
+ expect(findPipelineConfigButton().text()).toBe(mockPipelineConfigButtonText);
+ });
+
+ it('does not show pipeline configuration button for user who can not view', () => {
+ createComponentWithApollo({ props: { canViewPipelineEditor: false } });
+
+ expect(findPipelineConfigButton().exists()).toBe(false);
+ });
+
it('does not show the credit card validation required alert', () => {
expect(findCCAlert().exists()).toBe(false);
});
diff --git a/spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js b/spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js
index cf8009e388f..60ace483712 100644
--- a/spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js
+++ b/spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js
@@ -1,4 +1,4 @@
-import { GlListbox, GlListboxItem } from '@gitlab/ui';
+import { GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
@@ -13,13 +13,13 @@ const projectRefsEndpoint = '/root/project/refs';
const refShortName = 'main';
const refFullName = 'refs/heads/main';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Pipeline New Form', () => {
let wrapper;
let mock;
- const findDropdown = () => wrapper.findComponent(GlListbox);
+ const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
const findRefsDropdownItems = () => wrapper.findAllComponents(GlListboxItem);
const findSearchBox = () => wrapper.findByTestId('listbox-search-input');
const findListboxGroups = () => wrapper.findAll('ul[role="group"]');
diff --git a/spec/frontend/ci/pipeline_new/mock_data.js b/spec/frontend/ci/pipeline_new/mock_data.js
index 5b935c0c819..175f513217b 100644
--- a/spec/frontend/ci/pipeline_new/mock_data.js
+++ b/spec/frontend/ci/pipeline_new/mock_data.js
@@ -133,3 +133,5 @@ export const mockCiConfigVariablesResponseWithoutDesc = mockCiConfigVariablesQue
mockYamlVariablesWithoutDesc,
);
export const mockNoCachedCiConfigVariablesResponse = mockCiConfigVariablesQueryResponse(null);
+
+export const mockPipelineConfigButtonText = 'Go to the pipeline editor';
diff --git a/spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js b/spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js
index ba948f12b33..c45267e5a47 100644
--- a/spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js
@@ -20,10 +20,6 @@ describe('Delete pipeline schedule modal', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('emits the deleteSchedule event', async () => {
findModal().vm.$emit('primary');
diff --git a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js
index 611993556e3..50008cedd9c 100644
--- a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js
@@ -16,6 +16,7 @@ import getPipelineSchedulesQuery from '~/ci/pipeline_schedules/graphql/queries/g
import {
mockGetPipelineSchedulesGraphQLResponse,
mockPipelineScheduleNodes,
+ mockPipelineScheduleCurrentUser,
deleteMutationResponse,
playMutationResponse,
takeOwnershipMutationResponse,
@@ -79,10 +80,6 @@ describe('Pipeline schedules app', () => {
const findSchedulesCharacteristics = () =>
wrapper.findByTestId('pipeline-schedules-characteristics');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
@@ -115,6 +112,7 @@ describe('Pipeline schedules app', () => {
await waitForPromises();
expect(findTable().props('schedules')).toEqual(mockPipelineScheduleNodes);
+ expect(findTable().props('currentUser')).toEqual(mockPipelineScheduleCurrentUser);
});
it('shows query error alert', async () => {
diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js
index 6fb6a8bc33b..be0052fc7cf 100644
--- a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js
@@ -3,6 +3,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PipelineScheduleActions from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue';
import {
mockPipelineScheduleNodes,
+ mockPipelineScheduleCurrentUser,
mockPipelineScheduleAsGuestNodes,
mockTakeOwnershipNodes,
} from '../../../mock_data';
@@ -12,6 +13,7 @@ describe('Pipeline schedule actions', () => {
const defaultProps = {
schedule: mockPipelineScheduleNodes[0],
+ currentUser: mockPipelineScheduleCurrentUser,
};
const createComponent = (props = defaultProps) => {
@@ -27,18 +29,17 @@ describe('Pipeline schedule actions', () => {
const findTakeOwnershipBtn = () => wrapper.findByTestId('take-ownership-pipeline-schedule-btn');
const findPlayScheduleBtn = () => wrapper.findByTestId('play-pipeline-schedule-btn');
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays action buttons', () => {
+ it('displays buttons when user is the owner of schedule and has adminPipelineSchedule permissions', () => {
createComponent();
expect(findAllButtons()).toHaveLength(3);
});
- it('does not display action buttons', () => {
- createComponent({ schedule: mockPipelineScheduleAsGuestNodes[0] });
+ it('does not display action buttons when user is not owner and does not have adminPipelineSchedule permission', () => {
+ createComponent({
+ schedule: mockPipelineScheduleAsGuestNodes[0],
+ currentUser: mockPipelineScheduleCurrentUser,
+ });
expect(findAllButtons()).toHaveLength(0);
});
@@ -54,7 +55,10 @@ describe('Pipeline schedule actions', () => {
});
it('take ownership button emits showTakeOwnershipModal event and schedule id', () => {
- createComponent({ schedule: mockTakeOwnershipNodes[0] });
+ createComponent({
+ schedule: mockTakeOwnershipNodes[0],
+ currentUser: mockPipelineScheduleCurrentUser,
+ });
findTakeOwnershipBtn().vm.$emit('click');
diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
index 0821c59c8a0..ae069145292 100644
--- a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
@@ -21,10 +21,6 @@ describe('Pipeline schedule last pipeline', () => {
const findCIBadgeLink = () => wrapper.findComponent(CiBadgeLink);
const findStatusText = () => wrapper.findByTestId('pipeline-schedule-status-text');
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays pipeline status', () => {
createComponent();
diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js
index 1c06c411097..3bdbb371ddc 100644
--- a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js
@@ -21,10 +21,6 @@ describe('Pipeline schedule next run', () => {
const findTimeAgo = () => wrapper.findComponent(TimeAgoTooltip);
const findInactive = () => wrapper.findByTestId('pipeline-schedule-inactive');
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays time ago', () => {
createComponent();
diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js
index 6c1991cb4ac..849bef80f42 100644
--- a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js
@@ -25,10 +25,6 @@ describe('Pipeline schedule owner', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays avatar', () => {
expect(findAvatar().exists()).toBe(true);
expect(findAvatar().props('src')).toBe(defaultProps.schedule.owner.avatarUrl);
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 f531f04a736..5cc3829efbd 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
@@ -25,10 +25,6 @@ describe('Pipeline schedule target', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays icon', () => {
expect(findIcon().exists()).toBe(true);
expect(findIcon().props('name')).toBe('fork');
diff --git a/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
index 316b3bcf926..e488a36f3dc 100644
--- a/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
@@ -1,13 +1,14 @@
import { GlTableLite } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import PipelineSchedulesTable from '~/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue';
-import { mockPipelineScheduleNodes } from '../../mock_data';
+import { mockPipelineScheduleNodes, mockPipelineScheduleCurrentUser } from '../../mock_data';
describe('Pipeline schedules table', () => {
let wrapper;
const defaultProps = {
schedules: mockPipelineScheduleNodes,
+ currentUser: mockPipelineScheduleCurrentUser,
};
const createComponent = (props = defaultProps) => {
@@ -25,10 +26,6 @@ describe('Pipeline schedules table', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays table', () => {
expect(findTable().exists()).toBe(true);
});
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
index 7e6d4ec4bf8..e4ff9a0545b 100644
--- 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
@@ -25,14 +25,12 @@ describe('Take ownership modal', () => {
const actionPrimary = findModal().props('actionPrimary');
expect(actionPrimary.attributes).toEqual(
- expect.objectContaining([
- {
- category: 'primary',
- variant: 'confirm',
- href: url,
- 'data-method': 'post',
- },
- ]),
+ expect.objectContaining({
+ category: 'primary',
+ variant: 'confirm',
+ href: url,
+ 'data-method': 'post',
+ }),
);
});
diff --git a/spec/frontend/ci/pipeline_schedules/mock_data.js b/spec/frontend/ci/pipeline_schedules/mock_data.js
index 2826c054249..1485f6beea4 100644
--- a/spec/frontend/ci/pipeline_schedules/mock_data.js
+++ b/spec/frontend/ci/pipeline_schedules/mock_data.js
@@ -5,6 +5,7 @@ import mockGetPipelineSchedulesTakeOwnershipGraphQLResponse from 'test_fixtures/
const {
data: {
+ currentUser,
project: {
pipelineSchedules: { nodes },
},
@@ -28,6 +29,7 @@ const {
} = mockGetPipelineSchedulesTakeOwnershipGraphQLResponse;
export const mockPipelineScheduleNodes = nodes;
+export const mockPipelineScheduleCurrentUser = currentUser;
export const mockPipelineScheduleAsGuestNodes = guestNodes;
diff --git a/spec/frontend/ci/reports/codequality_report/components/codequality_issue_body_spec.js b/spec/frontend/ci/reports/codequality_report/components/codequality_issue_body_spec.js
index 90ca2a07266..f7386cfec74 100644
--- a/spec/frontend/ci/reports/codequality_report/components/codequality_issue_body_spec.js
+++ b/spec/frontend/ci/reports/codequality_report/components/codequality_issue_body_spec.js
@@ -30,11 +30,6 @@ describe('code quality issue body issue body', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('severity rating', () => {
it.each`
severity | iconClass | iconName
diff --git a/spec/frontend/ci/reports/components/grouped_issues_list_spec.js b/spec/frontend/ci/reports/components/grouped_issues_list_spec.js
index 3e4adfc7794..8beec220802 100644
--- a/spec/frontend/ci/reports/components/grouped_issues_list_spec.js
+++ b/spec/frontend/ci/reports/components/grouped_issues_list_spec.js
@@ -15,10 +15,6 @@ describe('Grouped Issues List', () => {
const findHeading = (groupName) => wrapper.find(`[data-testid="${groupName}Heading"`);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a smart virtual list with the correct props', () => {
createComponent({
propsData: {
diff --git a/spec/frontend/ci/reports/components/issue_status_icon_spec.js b/spec/frontend/ci/reports/components/issue_status_icon_spec.js
index fb13d4407e2..82b655dd598 100644
--- a/spec/frontend/ci/reports/components/issue_status_icon_spec.js
+++ b/spec/frontend/ci/reports/components/issue_status_icon_spec.js
@@ -13,11 +13,6 @@ describe('IssueStatusIcon', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it.each([STATUS_SUCCESS, STATUS_NEUTRAL, STATUS_FAILED])(
'renders "%s" state correctly',
(status) => {
diff --git a/spec/frontend/ci/reports/components/report_link_spec.js b/spec/frontend/ci/reports/components/report_link_spec.js
index ba541ba0303..4a97afd77df 100644
--- a/spec/frontend/ci/reports/components/report_link_spec.js
+++ b/spec/frontend/ci/reports/components/report_link_spec.js
@@ -4,10 +4,6 @@ import ReportLink from '~/ci/reports/components/report_link.vue';
describe('app/assets/javascripts/ci/reports/components/report_link.vue', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
const defaultProps = {
issue: {},
};
diff --git a/spec/frontend/ci/reports/components/report_section_spec.js b/spec/frontend/ci/reports/components/report_section_spec.js
index f032b210184..f4012fe0215 100644
--- a/spec/frontend/ci/reports/components/report_section_spec.js
+++ b/spec/frontend/ci/reports/components/report_section_spec.js
@@ -49,10 +49,6 @@ describe('ReportSection component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
describe('isCollapsible', () => {
const testMatrix = [
diff --git a/spec/frontend/ci/reports/components/summary_row_spec.js b/spec/frontend/ci/reports/components/summary_row_spec.js
index fb2ae5371d5..b1ae9e26b5b 100644
--- a/spec/frontend/ci/reports/components/summary_row_spec.js
+++ b/spec/frontend/ci/reports/components/summary_row_spec.js
@@ -31,11 +31,6 @@ describe('Summary row', () => {
const findStatusIcon = () => wrapper.findByTestId('summary-row-icon');
const findHelpPopover = () => wrapper.findComponent(HelpPopover);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders provided summary', () => {
createComponent();
expect(findSummary().text()).toContain(summary);
diff --git a/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js b/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js
index edf3d1706cc..85b1d3b1b2f 100644
--- a/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js
+++ b/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js
@@ -1,40 +1,53 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import AdminNewRunnerApp from '~/ci/runner/admin_new_runner/admin_new_runner_app.vue';
+import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_alert_to_local_storage';
import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
import RunnerPlatformsRadioGroup from '~/ci/runner/components/runner_platforms_radio_group.vue';
-import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
-import { DEFAULT_PLATFORM } from '~/ci/runner/constants';
+import { PARAM_KEY_PLATFORM, DEFAULT_PLATFORM, WINDOWS_PLATFORM } from '~/ci/runner/constants';
+import RunnerCreateForm from '~/ci/runner/components/runner_create_form.vue';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { runnerCreateResult } from '../mock_data';
const mockLegacyRegistrationToken = 'LEGACY_REGISTRATION_TOKEN';
Vue.use(VueApollo);
+jest.mock('~/ci/runner/local_storage_alert/save_alert_to_local_storage');
+jest.mock('~/alert');
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ redirectTo: jest.fn(),
+}));
+
+const mockCreatedRunner = runnerCreateResult.data.runnerCreate.runner;
+
describe('AdminNewRunnerApp', () => {
let wrapper;
const findLegacyInstructionsLink = () => wrapper.findByTestId('legacy-instructions-link');
const findRunnerInstructionsModal = () => wrapper.findComponent(RunnerInstructionsModal);
const findRunnerPlatformsRadioGroup = () => wrapper.findComponent(RunnerPlatformsRadioGroup);
- const findRunnerFormFields = () => wrapper.findComponent(RunnerFormFields);
+ const findRunnerCreateForm = () => wrapper.findComponent(RunnerCreateForm);
- const createComponent = ({ props = {}, mountFn = shallowMountExtended, ...options } = {}) => {
- wrapper = mountFn(AdminNewRunnerApp, {
+ const createComponent = () => {
+ wrapper = shallowMountExtended(AdminNewRunnerApp, {
propsData: {
legacyRegistrationToken: mockLegacyRegistrationToken,
- ...props,
},
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
},
stubs: {
GlSprintf,
},
- ...options,
});
};
@@ -56,25 +69,59 @@ describe('AdminNewRunnerApp', () => {
});
});
- describe('New runner form fields', () => {
- describe('Platform', () => {
- it('shows the platforms radio group', () => {
- expect(findRunnerPlatformsRadioGroup().props('value')).toBe(DEFAULT_PLATFORM);
- });
+ describe('Platform', () => {
+ it('shows the platforms radio group', () => {
+ expect(findRunnerPlatformsRadioGroup().props('value')).toBe(DEFAULT_PLATFORM);
+ });
+ });
+
+ describe('Runner form', () => {
+ it('shows the runner create form', () => {
+ expect(findRunnerCreateForm().exists()).toBe(true);
});
- describe('Runner', () => {
- it('shows the runners fields', () => {
- expect(findRunnerFormFields().props('value')).toEqual({
- accessLevel: 'NOT_PROTECTED',
- paused: false,
- description: '',
- maintenanceNote: '',
- maximumTimeout: ' ',
- runUntagged: false,
- tagList: '',
+ describe('When a runner is saved', () => {
+ beforeEach(() => {
+ findRunnerCreateForm().vm.$emit('saved', mockCreatedRunner);
+ });
+
+ it('pushes an alert to be shown after redirection', () => {
+ expect(saveAlertToLocalStorage).toHaveBeenCalledWith({
+ message: s__('Runners|Runner created.'),
+ variant: VARIANT_SUCCESS,
});
});
+
+ it('redirects to the registration page', () => {
+ const url = `${mockCreatedRunner.registerAdminUrl}?${PARAM_KEY_PLATFORM}=${DEFAULT_PLATFORM}`;
+
+ expect(redirectTo).toHaveBeenCalledWith(url);
+ });
+ });
+
+ describe('When another platform is selected and a runner is saved', () => {
+ beforeEach(() => {
+ findRunnerPlatformsRadioGroup().vm.$emit('input', WINDOWS_PLATFORM);
+ findRunnerCreateForm().vm.$emit('saved', mockCreatedRunner);
+ });
+
+ it('redirects to the registration page with the platform', () => {
+ const url = `${mockCreatedRunner.registerAdminUrl}?${PARAM_KEY_PLATFORM}=${WINDOWS_PLATFORM}`;
+
+ expect(redirectTo).toHaveBeenCalledWith(url);
+ });
+ });
+
+ describe('When runner fails to save', () => {
+ const ERROR_MSG = 'Cannot save!';
+
+ beforeEach(() => {
+ findRunnerCreateForm().vm.$emit('error', new Error(ERROR_MSG));
+ });
+
+ it('shows an error message', () => {
+ expect(createAlert).toHaveBeenCalledWith({ message: ERROR_MSG });
+ });
});
});
});
diff --git a/spec/frontend/ci/runner/admin_register_runner/admin_register_runner_app_spec.js b/spec/frontend/ci/runner/admin_register_runner/admin_register_runner_app_spec.js
new file mode 100644
index 00000000000..d04df85d58f
--- /dev/null
+++ b/spec/frontend/ci/runner/admin_register_runner/admin_register_runner_app_spec.js
@@ -0,0 +1,122 @@
+import { nextTick } from 'vue';
+import { GlButton } from '@gitlab/ui';
+
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import { TEST_HOST } from 'helpers/test_constants';
+
+import { updateHistory } from '~/lib/utils/url_utility';
+import { PARAM_KEY_PLATFORM, DEFAULT_PLATFORM, WINDOWS_PLATFORM } from '~/ci/runner/constants';
+import AdminRegisterRunnerApp from '~/ci/runner/admin_register_runner/admin_register_runner_app.vue';
+import RegistrationInstructions from '~/ci/runner/components/registration/registration_instructions.vue';
+import PlatformsDrawer from '~/ci/runner/components/registration/platforms_drawer.vue';
+import { runnerForRegistration } from '../mock_data';
+
+const mockRunnerId = runnerForRegistration.data.runner.id;
+const mockRunnersPath = '/admin/runners';
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ updateHistory: jest.fn(),
+}));
+
+describe('AdminRegisterRunnerApp', () => {
+ let wrapper;
+
+ const findRegistrationInstructions = () => wrapper.findComponent(RegistrationInstructions);
+ const findPlatformsDrawer = () => wrapper.findComponent(PlatformsDrawer);
+ const findBtn = () => wrapper.findComponent(GlButton);
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(AdminRegisterRunnerApp, {
+ propsData: {
+ runnerId: mockRunnerId,
+ runnersPath: mockRunnersPath,
+ },
+ });
+ };
+
+ describe('When showing runner details', () => {
+ beforeEach(async () => {
+ createComponent();
+ });
+
+ describe('when runner token is available', () => {
+ it('shows registration instructions', () => {
+ expect(findRegistrationInstructions().props()).toEqual({
+ platform: DEFAULT_PLATFORM,
+ runnerId: mockRunnerId,
+ });
+ });
+
+ it('configures platform drawer', () => {
+ expect(findPlatformsDrawer().props()).toEqual({
+ open: false,
+ platform: DEFAULT_PLATFORM,
+ });
+ });
+
+ it('shows runner list button', () => {
+ expect(findBtn().attributes('href')).toBe(mockRunnersPath);
+ expect(findBtn().props('variant')).toBe('confirm');
+ });
+ });
+ });
+
+ describe('When another platform has been selected', () => {
+ beforeEach(async () => {
+ setWindowLocation(`?${PARAM_KEY_PLATFORM}=${WINDOWS_PLATFORM}`);
+
+ createComponent();
+ });
+
+ it('shows registration instructions for the platform', () => {
+ expect(findRegistrationInstructions().props('platform')).toBe(WINDOWS_PLATFORM);
+ });
+ });
+
+ describe('When opening install instructions', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ findRegistrationInstructions().vm.$emit('toggleDrawer');
+ await nextTick();
+ });
+
+ it('opens platform drawer', () => {
+ expect(findPlatformsDrawer().props('open')).toBe(true);
+ });
+
+ it('closes platform drawer', async () => {
+ findRegistrationInstructions().vm.$emit('toggleDrawer');
+ await nextTick();
+
+ expect(findPlatformsDrawer().props('open')).toBe(false);
+ });
+
+ it('closes platform drawer from drawer', async () => {
+ findPlatformsDrawer().vm.$emit('close');
+ await nextTick();
+
+ expect(findPlatformsDrawer().props('open')).toBe(false);
+ });
+
+ describe('when selecting a platform', () => {
+ beforeEach(async () => {
+ findPlatformsDrawer().vm.$emit('selectPlatform', WINDOWS_PLATFORM);
+ await nextTick();
+ });
+
+ it('updates the url', () => {
+ expect(updateHistory).toHaveBeenCalledTimes(1);
+ expect(updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/?${PARAM_KEY_PLATFORM}=${WINDOWS_PLATFORM}`,
+ });
+ });
+
+ it('updates the registration instructions', () => {
+ expect(findRegistrationInstructions().props('platform')).toBe(WINDOWS_PLATFORM);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/admin_runner_show/admin_runner_show_app_spec.js b/spec/frontend/ci/runner/admin_runner_show/admin_runner_show_app_spec.js
index ed4f43c12d8..9d9142f2c68 100644
--- a/spec/frontend/ci/runner/admin_runner_show/admin_runner_show_app_spec.js
+++ b/spec/frontend/ci/runner/admin_runner_show/admin_runner_show_app_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -24,7 +24,7 @@ import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_al
import { runnerData } from '../mock_data';
jest.mock('~/ci/runner/local_storage_alert/save_alert_to_local_storage');
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
jest.mock('~/lib/utils/url_utility');
@@ -72,7 +72,6 @@ describe('AdminRunnerShowApp', () => {
afterEach(() => {
mockRunnerQuery.mockReset();
- wrapper.destroy();
});
describe('When showing runner details', () => {
diff --git a/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js
index 7fc240e520b..0cf6241c24f 100644
--- a/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js
+++ b/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js
@@ -9,7 +9,7 @@ import {
mountExtended,
} from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { updateHistory } from '~/lib/utils/url_utility';
@@ -70,7 +70,7 @@ const mockRunnersCount = runnersCountData.data.runners.count;
const mockRunnersHandler = jest.fn();
const mockRunnersCountHandler = jest.fn();
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
@@ -143,7 +143,6 @@ describe('AdminRunnersApp', () => {
mockRunnersHandler.mockReset();
mockRunnersCountHandler.mockReset();
showToast.mockReset();
- wrapper.destroy();
});
it('shows the runner setup instructions', () => {
diff --git a/spec/frontend/ci/runner/components/cells/runner_actions_cell_spec.js b/spec/frontend/ci/runner/components/cells/runner_actions_cell_spec.js
index 82e262d1b73..8ac0c5a61f8 100644
--- a/spec/frontend/ci/runner/components/cells/runner_actions_cell_spec.js
+++ b/spec/frontend/ci/runner/components/cells/runner_actions_cell_spec.js
@@ -31,10 +31,6 @@ describe('RunnerActionsCell', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Edit Action', () => {
it('Displays the runner edit link with the correct href', () => {
createComponent();
diff --git a/spec/frontend/ci/runner/components/cells/runner_owner_cell_spec.js b/spec/frontend/ci/runner/components/cells/runner_owner_cell_spec.js
index 3097e43e583..03f1ace3897 100644
--- a/spec/frontend/ci/runner/components/cells/runner_owner_cell_spec.js
+++ b/spec/frontend/ci/runner/components/cells/runner_owner_cell_spec.js
@@ -16,7 +16,7 @@ describe('RunnerOwnerCell', () => {
const createComponent = ({ runner } = {}) => {
wrapper = shallowMount(RunnerOwnerCell, {
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: {
runner,
@@ -24,10 +24,6 @@ describe('RunnerOwnerCell', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('When its an instance runner', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/ci/runner/components/cells/runner_status_cell_spec.js b/spec/frontend/ci/runner/components/cells/runner_status_cell_spec.js
index 1ff60ff1a9d..ec23d8415e8 100644
--- a/spec/frontend/ci/runner/components/cells/runner_status_cell_spec.js
+++ b/spec/frontend/ci/runner/components/cells/runner_status_cell_spec.js
@@ -34,10 +34,6 @@ describe('RunnerStatusCell', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays online status', () => {
createComponent();
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 1711df42491..585a03c0811 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
@@ -45,10 +45,6 @@ describe('RunnerTypeCell', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays the runner name as id and short token', () => {
expect(wrapper.text()).toContain(
`#${getIdFromGraphQLId(mockRunner.id)} (${mockRunner.shortSha})`,
diff --git a/spec/frontend/ci/runner/components/cells/runner_summary_field_spec.js b/spec/frontend/ci/runner/components/cells/runner_summary_field_spec.js
index f536e0dcbcf..7748890cf77 100644
--- a/spec/frontend/ci/runner/components/cells/runner_summary_field_spec.js
+++ b/spec/frontend/ci/runner/components/cells/runner_summary_field_spec.js
@@ -17,16 +17,12 @@ describe('RunnerSummaryField', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
...options,
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows content in slot', () => {
createComponent({
slots: { default: 'content' },
diff --git a/spec/frontend/ci/runner/components/registration/__snapshots__/utils_spec.js.snap b/spec/frontend/ci/runner/components/registration/__snapshots__/utils_spec.js.snap
new file mode 100644
index 00000000000..09d032fd32d
--- /dev/null
+++ b/spec/frontend/ci/runner/components/registration/__snapshots__/utils_spec.js.snap
@@ -0,0 +1,204 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`registration utils for "linux" platform commandPrompt is correct 1`] = `"$"`;
+
+exports[`registration utils for "linux" platform installScript is correct for "386" architecture 1`] = `
+"# Download the binary for your system
+sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-386
+
+# Give it permission to execute
+sudo chmod +x /usr/local/bin/gitlab-runner
+
+# Create a GitLab Runner user
+sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
+
+# Install and run as a service
+sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
+sudo gitlab-runner start"
+`;
+
+exports[`registration utils for "linux" platform installScript is correct for "amd64" architecture 1`] = `
+"# Download the binary for your system
+sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
+
+# Give it permission to execute
+sudo chmod +x /usr/local/bin/gitlab-runner
+
+# Create a GitLab Runner user
+sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
+
+# Install and run as a service
+sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
+sudo gitlab-runner start"
+`;
+
+exports[`registration utils for "linux" platform installScript is correct for "arm" architecture 1`] = `
+"# Download the binary for your system
+sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm
+
+# Give it permission to execute
+sudo chmod +x /usr/local/bin/gitlab-runner
+
+# Create a GitLab Runner user
+sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
+
+# Install and run as a service
+sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
+sudo gitlab-runner start"
+`;
+
+exports[`registration utils for "linux" platform installScript is correct for "arm64" architecture 1`] = `
+"# Download the binary for your system
+sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm64
+
+# Give it permission to execute
+sudo chmod +x /usr/local/bin/gitlab-runner
+
+# Create a GitLab Runner user
+sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
+
+# Install and run as a service
+sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
+sudo gitlab-runner start"
+`;
+
+exports[`registration utils for "linux" platform platformArchitectures returns correct list of architectures 1`] = `
+Array [
+ "amd64",
+ "386",
+ "arm",
+ "arm64",
+]
+`;
+
+exports[`registration utils for "linux" platform registerCommand is correct 1`] = `
+Array [
+ "gitlab-runner register",
+ " --url http://test.host",
+ " --registration-token REGISTRATION_TOKEN",
+ " --description 'RUNNER'",
+]
+`;
+
+exports[`registration utils for "linux" platform registerCommand is correct 2`] = `
+Array [
+ "gitlab-runner register",
+ " --url http://test.host",
+]
+`;
+
+exports[`registration utils for "linux" platform runCommand is correct 1`] = `"gitlab-runner run"`;
+
+exports[`registration utils for "osx" platform commandPrompt is correct 1`] = `"$"`;
+
+exports[`registration utils for "osx" platform installScript is correct for "amd64" architecture 1`] = `
+"# Download the binary for your system
+sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64
+
+# Give it permission to execute
+sudo chmod +x /usr/local/bin/gitlab-runner
+
+# The rest of the commands execute as the user who will run the runner
+# Register the runner (steps below), then run
+cd ~
+gitlab-runner install
+gitlab-runner start"
+`;
+
+exports[`registration utils for "osx" platform installScript is correct for "arm64" architecture 1`] = `
+"# Download the binary for your system
+sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-arm64
+
+# Give it permission to execute
+sudo chmod +x /usr/local/bin/gitlab-runner
+
+# The rest of the commands execute as the user who will run the runner
+# Register the runner (steps below), then run
+cd ~
+gitlab-runner install
+gitlab-runner start"
+`;
+
+exports[`registration utils for "osx" platform platformArchitectures returns correct list of architectures 1`] = `
+Array [
+ "amd64",
+ "arm64",
+]
+`;
+
+exports[`registration utils for "osx" platform registerCommand is correct 1`] = `
+Array [
+ "gitlab-runner register",
+ " --url http://test.host",
+ " --registration-token REGISTRATION_TOKEN",
+ " --description 'RUNNER'",
+]
+`;
+
+exports[`registration utils for "osx" platform registerCommand is correct 2`] = `
+Array [
+ "gitlab-runner register",
+ " --url http://test.host",
+]
+`;
+
+exports[`registration utils for "osx" platform runCommand is correct 1`] = `"gitlab-runner run"`;
+
+exports[`registration utils for "windows" platform commandPrompt is correct 1`] = `">"`;
+
+exports[`registration utils for "windows" platform installScript is correct for "386" architecture 1`] = `
+"# Run PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/starting-windows-powershell?view=powershell-7#with-administrative-privileges-run-as-administrator
+# Create a folder somewhere on your system, for example: C:\\\\GitLab-Runner
+New-Item -Path 'C:\\\\GitLab-Runner' -ItemType Directory
+
+# Change to the folder
+cd 'C:\\\\GitLab-Runner'
+
+# Download binary
+Invoke-WebRequest -Uri \\"https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-386.exe\\" -OutFile \\"gitlab-runner.exe\\"
+
+# Register the runner (steps below), then run
+.\\\\gitlab-runner.exe install
+.\\\\gitlab-runner.exe start"
+`;
+
+exports[`registration utils for "windows" platform installScript is correct for "amd64" architecture 1`] = `
+"# Run PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/starting-windows-powershell?view=powershell-7#with-administrative-privileges-run-as-administrator
+# Create a folder somewhere on your system, for example: C:\\\\GitLab-Runner
+New-Item -Path 'C:\\\\GitLab-Runner' -ItemType Directory
+
+# Change to the folder
+cd 'C:\\\\GitLab-Runner'
+
+# Download binary
+Invoke-WebRequest -Uri \\"https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe\\" -OutFile \\"gitlab-runner.exe\\"
+
+# Register the runner (steps below), then run
+.\\\\gitlab-runner.exe install
+.\\\\gitlab-runner.exe start"
+`;
+
+exports[`registration utils for "windows" platform platformArchitectures returns correct list of architectures 1`] = `
+Array [
+ "amd64",
+ "386",
+]
+`;
+
+exports[`registration utils for "windows" platform registerCommand is correct 1`] = `
+Array [
+ ".\\\\gitlab-runner.exe register",
+ " --url http://test.host",
+ " --registration-token REGISTRATION_TOKEN",
+ " --description 'RUNNER'",
+]
+`;
+
+exports[`registration utils for "windows" platform registerCommand is correct 2`] = `
+Array [
+ ".\\\\gitlab-runner.exe register",
+ " --url http://test.host",
+]
+`;
+
+exports[`registration utils for "windows" platform runCommand is correct 1`] = `".\\\\gitlab-runner.exe run"`;
diff --git a/spec/frontend/ci/runner/components/registration/cli_command_spec.js b/spec/frontend/ci/runner/components/registration/cli_command_spec.js
new file mode 100644
index 00000000000..78c2b94c3ea
--- /dev/null
+++ b/spec/frontend/ci/runner/components/registration/cli_command_spec.js
@@ -0,0 +1,39 @@
+import CliCommand from '~/ci/runner/components/registration/cli_command.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+describe('CliCommand', () => {
+ let wrapper;
+
+ // use .textContent instead of .text() to capture whitespace that's visible in <pre>
+ const getPreTextContent = () => wrapper.find('pre').element.textContent;
+ const getClipboardText = () => wrapper.findComponent(ClipboardButton).props('text');
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(CliCommand, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ it('when rendering a command', () => {
+ createComponent({
+ prompt: '#',
+ command: 'echo hi',
+ });
+
+ expect(getPreTextContent()).toBe('# echo hi');
+ expect(getClipboardText()).toBe('echo hi');
+ });
+
+ it('when rendering a multi-line command', () => {
+ createComponent({
+ prompt: '#',
+ command: ['git', ' --version'],
+ });
+
+ expect(getPreTextContent()).toBe('# git --version');
+ expect(getClipboardText()).toBe('git --version');
+ });
+});
diff --git a/spec/frontend/ci/runner/components/registration/platforms_drawer_spec.js b/spec/frontend/ci/runner/components/registration/platforms_drawer_spec.js
new file mode 100644
index 00000000000..0b438455b5b
--- /dev/null
+++ b/spec/frontend/ci/runner/components/registration/platforms_drawer_spec.js
@@ -0,0 +1,108 @@
+import { nextTick } from 'vue';
+import { GlDrawer, GlLink, GlIcon, GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
+
+import PlatformsDrawer from '~/ci/runner/components/registration/platforms_drawer.vue';
+import CliCommand from '~/ci/runner/components/registration/cli_command.vue';
+import {
+ LINUX_PLATFORM,
+ MACOS_PLATFORM,
+ WINDOWS_PLATFORM,
+ INSTALL_HELP_URL,
+} from '~/ci/runner/constants';
+import { installScript, platformArchitectures } from '~/ci/runner/components/registration/utils';
+
+const MOCK_WRAPPER_HEIGHT = '99px';
+const LINUX_ARCHS = platformArchitectures({ platform: LINUX_PLATFORM });
+const MACOS_ARCHS = platformArchitectures({ platform: MACOS_PLATFORM });
+
+jest.mock('~/lib/utils/dom_utils', () => ({
+ getContentWrapperHeight: () => MOCK_WRAPPER_HEIGHT,
+}));
+
+describe('RegistrationInstructions', () => {
+ let wrapper;
+
+ const findDrawer = () => wrapper.findComponent(GlDrawer);
+ const findEnvironmentOptions = () =>
+ wrapper.findByLabelText(s__('Runners|Environment')).findAll('option');
+ const findArchitectureOptions = () =>
+ wrapper.findByLabelText(s__('Runners|Architecture')).findAll('option');
+ const findCliCommand = () => wrapper.findComponent(CliCommand);
+ const findLink = () => wrapper.findComponent(GlLink);
+
+ const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
+ wrapper = mountFn(PlatformsDrawer, {
+ propsData: {
+ open: true,
+ ...props,
+ },
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ it('shows drawer', () => {
+ createComponent();
+
+ expect(findDrawer().props()).toMatchObject({
+ open: true,
+ headerHeight: MOCK_WRAPPER_HEIGHT,
+ });
+ });
+
+ it('closes drawer', () => {
+ createComponent();
+ findDrawer().vm.$emit('close');
+
+ expect(wrapper.emitted('close')).toHaveLength(1);
+ });
+
+ it('shows selection options', () => {
+ createComponent({ mountFn: mountExtended });
+
+ expect(findEnvironmentOptions().wrappers.map((w) => w.attributes('value'))).toEqual([
+ LINUX_PLATFORM,
+ MACOS_PLATFORM,
+ WINDOWS_PLATFORM,
+ ]);
+
+ expect(findArchitectureOptions().wrappers.map((w) => w.attributes('value'))).toEqual(
+ LINUX_ARCHS,
+ );
+ });
+
+ it('shows script', () => {
+ createComponent();
+
+ expect(findCliCommand().props('command')).toBe(
+ installScript({ platform: LINUX_PLATFORM, architecture: LINUX_ARCHS[0] }),
+ );
+ });
+
+ it('shows selection options for another platform', async () => {
+ createComponent({ mountFn: mountExtended });
+
+ findEnvironmentOptions().at(1).setSelected(); // macos
+ await nextTick();
+
+ expect(wrapper.emitted('selectPlatform')).toEqual([[MACOS_PLATFORM]]);
+
+ expect(findArchitectureOptions().wrappers.map((w) => w.attributes('value'))).toEqual(
+ MACOS_ARCHS,
+ );
+
+ expect(findCliCommand().props('command')).toBe(
+ installScript({ platform: MACOS_PLATFORM, architecture: MACOS_ARCHS[0] }),
+ );
+ });
+
+ it('shows external link for more information', () => {
+ createComponent();
+
+ expect(findLink().attributes('href')).toBe(INSTALL_HELP_URL);
+ expect(findLink().findComponent(GlIcon).props('name')).toBe('external-link');
+ });
+});
diff --git a/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js b/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js
index 0daaca9c4ff..9ed59b0a57d 100644
--- a/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js
+++ b/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js
@@ -116,10 +116,6 @@ describe('RegistrationDropdown', () => {
await openModal();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('opens the modal with contents', () => {
const modalText = findModalContent();
diff --git a/spec/frontend/ci/runner/components/registration/registration_instructions_spec.js b/spec/frontend/ci/runner/components/registration/registration_instructions_spec.js
new file mode 100644
index 00000000000..eb4b659091d
--- /dev/null
+++ b/spec/frontend/ci/runner/components/registration/registration_instructions_spec.js
@@ -0,0 +1,293 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
+
+import { s__ } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { extendedWrapper, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { TEST_HOST } from 'helpers/test_constants';
+
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import RegistrationInstructions from '~/ci/runner/components/registration/registration_instructions.vue';
+import runnerForRegistrationQuery from '~/ci/runner/graphql/register/runner_for_registration.query.graphql';
+import CliCommand from '~/ci/runner/components/registration/cli_command.vue';
+import {
+ DEFAULT_PLATFORM,
+ EXECUTORS_HELP_URL,
+ SERVICE_COMMANDS_HELP_URL,
+ STATUS_NEVER_CONTACTED,
+ STATUS_ONLINE,
+ RUNNER_REGISTRATION_POLLING_INTERVAL_MS,
+ I18N_REGISTRATION_SUCCESS,
+} from '~/ci/runner/constants';
+import { runnerForRegistration } from '../../mock_data';
+
+Vue.use(VueApollo);
+
+const MOCK_TOKEN = 'MOCK_TOKEN';
+const mockDescription = runnerForRegistration.data.runner.description;
+
+const mockRunner = {
+ ...runnerForRegistration.data.runner,
+ ephemeralAuthenticationToken: MOCK_TOKEN,
+};
+const mockRunnerWithoutToken = {
+ ...runnerForRegistration.data.runner,
+ ephemeralAuthenticationToken: null,
+};
+
+const mockRunnerId = `${getIdFromGraphQLId(mockRunner.id)}`;
+
+describe('RegistrationInstructions', () => {
+ let wrapper;
+ let mockRunnerQuery;
+
+ const findHeading = () => wrapper.find('h1');
+ const findStepAt = (i) => extendedWrapper(wrapper.findAll('section').at(i));
+ const findByText = (text, container = wrapper) => container.findByText(text);
+
+ const waitForPolling = async () => {
+ jest.advanceTimersByTime(RUNNER_REGISTRATION_POLLING_INTERVAL_MS);
+ await waitForPromises();
+ };
+
+ const mockResolvedRunner = (runner = mockRunner) => {
+ mockRunnerQuery.mockResolvedValue({
+ data: {
+ runner,
+ },
+ });
+ };
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(RegistrationInstructions, {
+ apolloProvider: createMockApollo([[runnerForRegistrationQuery, mockRunnerQuery]]),
+ propsData: {
+ runnerId: mockRunnerId,
+ platform: DEFAULT_PLATFORM,
+ ...props,
+ },
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mockRunnerQuery = jest.fn();
+ mockResolvedRunner();
+ });
+
+ beforeEach(() => {
+ window.gon.gitlab_url = TEST_HOST;
+ });
+
+ it('loads runner with id', async () => {
+ createComponent();
+
+ expect(mockRunnerQuery).toHaveBeenCalledWith({ id: mockRunner.id });
+ });
+
+ describe('heading', () => {
+ it('when runner is loaded, shows heading', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(findHeading().text()).toContain(mockRunner.description);
+ });
+
+ it('when runner is loaded, shows heading safely', async () => {
+ mockResolvedRunner({
+ ...mockRunner,
+ description: '<script>hacked();</script>',
+ });
+
+ createComponent();
+ await waitForPromises();
+
+ expect(findHeading().text()).toBe('Register "<script>hacked();</script>" runner');
+ expect(findHeading().element.innerHTML).toBe(
+ 'Register "&lt;script&gt;hacked();&lt;/script&gt;" runner',
+ );
+ });
+
+ it('when runner is loading, shows default heading', () => {
+ createComponent();
+
+ expect(findHeading().text()).toBe(s__('Runners|Register runner'));
+ });
+ });
+
+ it('renders legacy instructions', () => {
+ createComponent();
+
+ findByText('How do I install GitLab Runner?').vm.$emit('click');
+
+ expect(wrapper.emitted('toggleDrawer')).toHaveLength(1);
+ });
+
+ describe('step 1', () => {
+ it('renders step 1', async () => {
+ createComponent();
+ await waitForPromises();
+
+ const step1 = findStepAt(0);
+
+ expect(step1.findComponent(CliCommand).props()).toEqual({
+ command: [
+ 'gitlab-runner register',
+ ` --url ${TEST_HOST}`,
+ ` --registration-token ${MOCK_TOKEN}`,
+ ` --description '${mockDescription}'`,
+ ],
+ prompt: '$',
+ });
+ expect(step1.find('[data-testid="runner-token"]').text()).toBe(MOCK_TOKEN);
+ expect(step1.findComponent(ClipboardButton).props('text')).toBe(MOCK_TOKEN);
+ });
+
+ it('renders step 1 in loading state', () => {
+ createComponent();
+
+ const step1 = findStepAt(0);
+
+ expect(step1.findComponent(GlSkeletonLoader).exists()).toBe(true);
+ expect(step1.find('code').exists()).toBe(false);
+ expect(step1.findComponent(ClipboardButton).exists()).toBe(false);
+ });
+
+ it('render step 1 after token is not visible', async () => {
+ mockResolvedRunner(mockRunnerWithoutToken);
+
+ createComponent();
+ await waitForPromises();
+
+ const step1 = findStepAt(0);
+
+ expect(step1.findComponent(CliCommand).props('command')).toEqual([
+ 'gitlab-runner register',
+ ` --url ${TEST_HOST}`,
+ ` --description '${mockDescription}'`,
+ ]);
+ expect(step1.find('[data-testid="runner-token"]').exists()).toBe(false);
+ expect(step1.findComponent(ClipboardButton).exists()).toBe(false);
+ });
+
+ describe('polling for changes', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('fetches data', () => {
+ expect(mockRunnerQuery).toHaveBeenCalledTimes(1);
+ });
+
+ it('polls', async () => {
+ await waitForPolling();
+ expect(mockRunnerQuery).toHaveBeenCalledTimes(2);
+
+ await waitForPolling();
+ expect(mockRunnerQuery).toHaveBeenCalledTimes(3);
+ });
+
+ it('when runner is online, stops polling', async () => {
+ mockResolvedRunner({ ...mockRunner, status: STATUS_ONLINE });
+ await waitForPolling();
+
+ expect(mockRunnerQuery).toHaveBeenCalledTimes(2);
+ await waitForPolling();
+
+ expect(mockRunnerQuery).toHaveBeenCalledTimes(2);
+ });
+
+ it('when token is no longer visible in the API, it is still visible in the UI', async () => {
+ mockResolvedRunner(mockRunnerWithoutToken);
+ await waitForPolling();
+
+ const step1 = findStepAt(0);
+ expect(step1.findComponent(CliCommand).props('command')).toEqual([
+ 'gitlab-runner register',
+ ` --url ${TEST_HOST}`,
+ ` --registration-token ${MOCK_TOKEN}`,
+ ` --description '${mockDescription}'`,
+ ]);
+ expect(step1.find('[data-testid="runner-token"]').text()).toBe(MOCK_TOKEN);
+ expect(step1.findComponent(ClipboardButton).props('text')).toBe(MOCK_TOKEN);
+ });
+
+ it('when runner is not available (e.g. deleted), the UI does not update', async () => {
+ mockResolvedRunner(null);
+ await waitForPolling();
+
+ const step1 = findStepAt(0);
+ expect(step1.findComponent(CliCommand).props('command')).toEqual([
+ 'gitlab-runner register',
+ ` --url ${TEST_HOST}`,
+ ` --registration-token ${MOCK_TOKEN}`,
+ ` --description '${mockDescription}'`,
+ ]);
+ expect(step1.find('[data-testid="runner-token"]').text()).toBe(MOCK_TOKEN);
+ expect(step1.findComponent(ClipboardButton).props('text')).toBe(MOCK_TOKEN);
+ });
+ });
+ });
+
+ it('renders step 2', () => {
+ createComponent();
+ const step2 = findStepAt(1);
+
+ expect(findByText('Not sure which one to select?', step2).attributes('href')).toBe(
+ EXECUTORS_HELP_URL,
+ );
+ });
+
+ it('renders step 3', () => {
+ createComponent();
+ const step3 = findStepAt(2);
+
+ expect(step3.findComponent(CliCommand).props()).toEqual({
+ command: 'gitlab-runner run',
+ prompt: '$',
+ });
+
+ expect(findByText('system or user service', step3).attributes('href')).toBe(
+ SERVICE_COMMANDS_HELP_URL,
+ );
+ });
+
+ describe('success state', () => {
+ describe('when the runner has not been registered', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPolling();
+
+ mockResolvedRunner({ ...mockRunner, status: STATUS_NEVER_CONTACTED });
+
+ await waitForPolling();
+ });
+
+ it('does not show success message', () => {
+ expect(wrapper.text()).not.toContain(I18N_REGISTRATION_SUCCESS);
+ });
+ });
+
+ describe('when the runner has been registered', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPolling();
+
+ mockResolvedRunner({ ...mockRunner, status: STATUS_ONLINE });
+ await waitForPolling();
+ });
+
+ it('shows success message', () => {
+ expect(wrapper.text()).toContain('🎉');
+ expect(wrapper.text()).toContain(I18N_REGISTRATION_SUCCESS);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/registration/registration_token_reset_dropdown_item_spec.js b/spec/frontend/ci/runner/components/registration/registration_token_reset_dropdown_item_spec.js
index 783a4d9252a..ff69fd6d3d6 100644
--- a/spec/frontend/ci/runner/components/registration/registration_token_reset_dropdown_item_spec.js
+++ b/spec/frontend/ci/runner/components/registration/registration_token_reset_dropdown_item_spec.js
@@ -5,14 +5,14 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import RegistrationTokenResetDropdownItem from '~/ci/runner/components/registration/registration_token_reset_dropdown_item.vue';
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/ci/runner/constants';
import runnersRegistrationTokenResetMutation from '~/ci/runner/graphql/list/runners_registration_token_reset.mutation.graphql';
import { captureException } from '~/ci/runner/sentry_utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
Vue.use(VueApollo);
@@ -43,7 +43,7 @@ describe('RegistrationTokenResetDropdownItem', () => {
[runnersRegistrationTokenResetMutation, runnersRegistrationTokenResetMutationHandler],
]),
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
},
});
@@ -63,10 +63,6 @@ describe('RegistrationTokenResetDropdownItem', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays reset button', () => {
expect(findDropdownItem().exists()).toBe(true);
});
diff --git a/spec/frontend/ci/runner/components/registration/registration_token_spec.js b/spec/frontend/ci/runner/components/registration/registration_token_spec.js
index d2a51c0d910..4f44e6e10b2 100644
--- a/spec/frontend/ci/runner/components/registration/registration_token_spec.js
+++ b/spec/frontend/ci/runner/components/registration/registration_token_spec.js
@@ -27,10 +27,6 @@ describe('RegistrationToken', () => {
showToast = wrapper.vm.$toast ? jest.spyOn(wrapper.vm.$toast, 'show') : null;
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays value and copy button', () => {
createComponent();
diff --git a/spec/frontend/ci/runner/components/registration/utils_spec.js b/spec/frontend/ci/runner/components/registration/utils_spec.js
new file mode 100644
index 00000000000..acf5993b15b
--- /dev/null
+++ b/spec/frontend/ci/runner/components/registration/utils_spec.js
@@ -0,0 +1,118 @@
+import { TEST_HOST } from 'helpers/test_constants';
+import {
+ DEFAULT_PLATFORM,
+ LINUX_PLATFORM,
+ MACOS_PLATFORM,
+ WINDOWS_PLATFORM,
+} from '~/ci/runner/constants';
+
+import {
+ commandPrompt,
+ registerCommand,
+ runCommand,
+ installScript,
+ platformArchitectures,
+} from '~/ci/runner/components/registration/utils';
+
+const REGISTRATION_TOKEN = 'REGISTRATION_TOKEN';
+const DESCRIPTION = 'RUNNER';
+
+describe('registration utils', () => {
+ beforeEach(() => {
+ window.gon.gitlab_url = TEST_HOST;
+ });
+
+ describe.each([LINUX_PLATFORM, MACOS_PLATFORM, WINDOWS_PLATFORM])(
+ 'for "%s" platform',
+ (platform) => {
+ it('commandPrompt is correct', () => {
+ expect(commandPrompt({ platform })).toMatchSnapshot();
+ });
+
+ it('registerCommand is correct', () => {
+ expect(
+ registerCommand({
+ platform,
+ registrationToken: REGISTRATION_TOKEN,
+ description: DESCRIPTION,
+ }),
+ ).toMatchSnapshot();
+
+ expect(registerCommand({ platform })).toMatchSnapshot();
+ });
+
+ it('runCommand is correct', () => {
+ expect(runCommand({ platform })).toMatchSnapshot();
+ });
+ },
+ );
+
+ describe.each([LINUX_PLATFORM, MACOS_PLATFORM])('for "%s" platform', (platform) => {
+ it.each`
+ description | parameter
+ ${'my runner'} | ${"'my runner'"}
+ ${"bob's runner"} | ${"'bob'\\''s runner'"}
+ `('registerCommand escapes description `$description`', ({ description, parameter }) => {
+ expect(registerCommand({ platform, description })[2]).toBe(` --description ${parameter}`);
+ });
+ });
+
+ describe.each([WINDOWS_PLATFORM])('for "%s" platform', (platform) => {
+ it.each`
+ description | parameter
+ ${'my runner'} | ${"'my runner'"}
+ ${"bob's runner"} | ${"'bob''s runner'"}
+ `('registerCommand escapes description `$description`', ({ description, parameter }) => {
+ expect(registerCommand({ platform, description })[2]).toBe(` --description ${parameter}`);
+ });
+ });
+
+ describe('for missing platform', () => {
+ it('commandPrompt uses the default', () => {
+ const expected = commandPrompt({ platform: DEFAULT_PLATFORM });
+
+ expect(commandPrompt({ platform: null })).toEqual(expected);
+ expect(commandPrompt({ platform: undefined })).toEqual(expected);
+ });
+
+ it('registerCommand uses the default', () => {
+ const expected = registerCommand({
+ platform: DEFAULT_PLATFORM,
+ registrationToken: REGISTRATION_TOKEN,
+ });
+
+ expect(registerCommand({ platform: null, registrationToken: REGISTRATION_TOKEN })).toEqual(
+ expected,
+ );
+ expect(
+ registerCommand({ platform: undefined, registrationToken: REGISTRATION_TOKEN }),
+ ).toEqual(expected);
+ });
+
+ it('runCommand uses the default', () => {
+ const expected = runCommand({ platform: DEFAULT_PLATFORM });
+
+ expect(runCommand({ platform: null })).toEqual(expected);
+ expect(runCommand({ platform: undefined })).toEqual(expected);
+ });
+ });
+
+ describe.each([LINUX_PLATFORM, MACOS_PLATFORM, WINDOWS_PLATFORM])(
+ 'for "%s" platform',
+ (platform) => {
+ describe('platformArchitectures', () => {
+ it('returns correct list of architectures', () => {
+ expect(platformArchitectures({ platform })).toMatchSnapshot();
+ });
+ });
+
+ describe('installScript', () => {
+ const architectures = platformArchitectures({ platform });
+
+ it.each(architectures)('is correct for "%s" architecture', (architecture) => {
+ expect(installScript({ platform, architecture })).toMatchSnapshot();
+ });
+ });
+ },
+ );
+});
diff --git a/spec/frontend/ci/runner/components/runner_assigned_item_spec.js b/spec/frontend/ci/runner/components/runner_assigned_item_spec.js
index 5df2e04c340..a1fd9e4c1aa 100644
--- a/spec/frontend/ci/runner/components/runner_assigned_item_spec.js
+++ b/spec/frontend/ci/runner/components/runner_assigned_item_spec.js
@@ -33,10 +33,6 @@ describe('RunnerAssignedItem', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Shows an avatar', () => {
const avatar = findAvatar();
diff --git a/spec/frontend/ci/runner/components/runner_bulk_delete_spec.js b/spec/frontend/ci/runner/components/runner_bulk_delete_spec.js
index 0dc5a90fb83..f609c6be41a 100644
--- a/spec/frontend/ci/runner/components/runner_bulk_delete_spec.js
+++ b/spec/frontend/ci/runner/components/runner_bulk_delete_spec.js
@@ -2,7 +2,7 @@ import Vue from 'vue';
import { makeVar } from '@apollo/client/core';
import { GlModal, GlSprintf } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { s__ } from '~/locale';
@@ -15,7 +15,7 @@ import { allRunnersData } from '../mock_data';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('RunnerBulkDelete', () => {
let wrapper;
@@ -51,7 +51,7 @@ describe('RunnerBulkDelete', () => {
runners: mockRunners,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
stubs: {
GlSprintf,
diff --git a/spec/frontend/ci/runner/components/runner_create_form_spec.js b/spec/frontend/ci/runner/components/runner_create_form_spec.js
new file mode 100644
index 00000000000..1123a026a4d
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_create_form_spec.js
@@ -0,0 +1,170 @@
+import Vue from 'vue';
+import { GlForm } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import RunnerCreateForm from '~/ci/runner/components/runner_create_form.vue';
+import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
+import { DEFAULT_ACCESS_LEVEL } from '~/ci/runner/constants';
+import runnerCreateMutation from '~/ci/runner/graphql/new/runner_create.mutation.graphql';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { runnerCreateResult } from '../mock_data';
+
+jest.mock('~/ci/runner/sentry_utils');
+
+const mockCreatedRunner = runnerCreateResult.data.runnerCreate.runner;
+
+const defaultRunnerModel = {
+ description: '',
+ accessLevel: DEFAULT_ACCESS_LEVEL,
+ paused: false,
+ maintenanceNote: '',
+ maximumTimeout: '',
+ runUntagged: false,
+ tagList: '',
+};
+
+Vue.use(VueApollo);
+
+describe('RunnerCreateForm', () => {
+ let wrapper;
+ let runnerCreateHandler;
+
+ const findForm = () => wrapper.findComponent(GlForm);
+ const findRunnerFormFields = () => wrapper.findComponent(RunnerFormFields);
+ const findSubmitBtn = () => wrapper.find('[type="submit"]');
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(RunnerCreateForm, {
+ apolloProvider: createMockApollo([[runnerCreateMutation, runnerCreateHandler]]),
+ });
+ };
+
+ beforeEach(() => {
+ runnerCreateHandler = jest.fn().mockResolvedValue(runnerCreateResult);
+
+ createComponent();
+ });
+
+ it('shows default runner values', () => {
+ expect(findRunnerFormFields().props('value')).toEqual(defaultRunnerModel);
+ });
+
+ it('shows a submit button', () => {
+ expect(findSubmitBtn().exists()).toBe(true);
+ });
+
+ describe('when user submits', () => {
+ let preventDefault;
+
+ beforeEach(() => {
+ preventDefault = jest.fn();
+
+ findRunnerFormFields().vm.$emit('input', {
+ ...defaultRunnerModel,
+ description: 'My runner',
+ maximumTimeout: 0,
+ tagList: 'tag1, tag2',
+ });
+ });
+
+ describe('immediately after submit', () => {
+ beforeEach(() => {
+ findForm().vm.$emit('submit', { preventDefault });
+ });
+
+ it('prevents default form submission', () => {
+ expect(preventDefault).toHaveBeenCalledTimes(1);
+ });
+
+ it('shows a saving state', () => {
+ expect(findSubmitBtn().props('loading')).toBe(true);
+ });
+
+ it('saves runner', async () => {
+ expect(runnerCreateHandler).toHaveBeenCalledWith({
+ input: {
+ ...defaultRunnerModel,
+ description: 'My runner',
+ maximumTimeout: 0,
+ tagList: ['tag1', 'tag2'],
+ },
+ });
+ });
+ });
+
+ describe('when saved successfully', () => {
+ beforeEach(async () => {
+ findForm().vm.$emit('submit', { preventDefault });
+ await waitForPromises();
+ });
+
+ it('emits "saved" result', async () => {
+ expect(wrapper.emitted('saved')[0]).toEqual([mockCreatedRunner]);
+ });
+
+ it('does not show a saving state', () => {
+ expect(findSubmitBtn().props('loading')).toBe(false);
+ });
+ });
+
+ describe('when a server error occurs', () => {
+ const error = new Error('Error!');
+
+ beforeEach(async () => {
+ runnerCreateHandler.mockRejectedValue(error);
+
+ findForm().vm.$emit('submit', { preventDefault });
+ await waitForPromises();
+ });
+
+ it('emits "error" result', async () => {
+ expect(wrapper.emitted('error')[0]).toEqual([error]);
+ });
+
+ it('does not show a saving state', () => {
+ expect(findSubmitBtn().props('loading')).toBe(false);
+ });
+
+ it('reports error', () => {
+ expect(captureException).toHaveBeenCalledTimes(1);
+ expect(captureException).toHaveBeenCalledWith({
+ component: 'RunnerCreateForm',
+ error,
+ });
+ });
+ });
+
+ describe('when a validation error occurs', () => {
+ const errorMsg1 = 'Issue1!';
+ const errorMsg2 = 'Issue2!';
+
+ beforeEach(async () => {
+ runnerCreateHandler.mockResolvedValue({
+ data: {
+ runnerCreate: {
+ errors: [errorMsg1, errorMsg2],
+ runner: null,
+ },
+ },
+ });
+
+ findForm().vm.$emit('submit', { preventDefault });
+ await waitForPromises();
+ });
+
+ it('emits "error" results', async () => {
+ expect(wrapper.emitted('error')[0]).toEqual([new Error(`${errorMsg1} ${errorMsg2}`)]);
+ });
+
+ it('does not show a saving state', () => {
+ expect(findSubmitBtn().props('loading')).toBe(false);
+ });
+
+ it('does not report error', () => {
+ expect(captureException).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_delete_button_spec.js b/spec/frontend/ci/runner/components/runner_delete_button_spec.js
index 02960ad427e..f9bea318d84 100644
--- a/spec/frontend/ci/runner/components/runner_delete_button_spec.js
+++ b/spec/frontend/ci/runner/components/runner_delete_button_spec.js
@@ -8,7 +8,7 @@ import runnerDeleteMutation from '~/ci/runner/graphql/shared/runner_delete.mutat
import waitForPromises from 'helpers/wait_for_promises';
import { captureException } from '~/ci/runner/sentry_utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { I18N_DELETE_RUNNER } from '~/ci/runner/constants';
import RunnerDeleteButton from '~/ci/runner/components/runner_delete_button.vue';
@@ -21,7 +21,7 @@ const mockRunnerName = `#${mockRunnerId} (${mockRunner.shortSha})`;
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
describe('RunnerDeleteButton', () => {
@@ -53,8 +53,8 @@ describe('RunnerDeleteButton', () => {
},
apolloProvider,
directives: {
- GlTooltip: createMockDirective(),
- GlModal: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
+ GlModal: createMockDirective('gl-modal'),
},
});
};
@@ -83,10 +83,6 @@ describe('RunnerDeleteButton', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays a delete button without an icon', () => {
expect(findBtn().props()).toMatchObject({
loading: false,
diff --git a/spec/frontend/ci/runner/components/runner_details_spec.js b/spec/frontend/ci/runner/components/runner_details_spec.js
index 65a81973869..c2d9e86aa91 100644
--- a/spec/frontend/ci/runner/components/runner_details_spec.js
+++ b/spec/frontend/ci/runner/components/runner_details_spec.js
@@ -37,10 +37,6 @@ describe('RunnerDetails', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Details tab', () => {
describe.each`
field | runner | expectedValue
diff --git a/spec/frontend/ci/runner/components/runner_edit_button_spec.js b/spec/frontend/ci/runner/components/runner_edit_button_spec.js
index 907cdc90100..5cc1ee049f4 100644
--- a/spec/frontend/ci/runner/components/runner_edit_button_spec.js
+++ b/spec/frontend/ci/runner/components/runner_edit_button_spec.js
@@ -11,7 +11,7 @@ describe('RunnerEditButton', () => {
wrapper = mountFn(RunnerEditButton, {
attrs,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -20,10 +20,6 @@ describe('RunnerEditButton', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays Edit text', () => {
expect(wrapper.attributes('aria-label')).toBe('Edit');
});
diff --git a/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js b/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js
index 408750e646f..ac84c7898bf 100644
--- a/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js
+++ b/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js
@@ -65,10 +65,6 @@ describe('RunnerList', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('binds a namespace to the filtered search', () => {
expect(findFilteredSearch().props('namespace')).toBe('runners');
});
diff --git a/spec/frontend/ci/runner/components/runner_groups_spec.js b/spec/frontend/ci/runner/components/runner_groups_spec.js
index 0991feb2e55..e4f5f55ab4b 100644
--- a/spec/frontend/ci/runner/components/runner_groups_spec.js
+++ b/spec/frontend/ci/runner/components/runner_groups_spec.js
@@ -23,10 +23,6 @@ describe('RunnerGroups', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Shows a heading', () => {
createComponent();
diff --git a/spec/frontend/ci/runner/components/runner_header_spec.js b/spec/frontend/ci/runner/components/runner_header_spec.js
index abe3b47767e..c851966431d 100644
--- a/spec/frontend/ci/runner/components/runner_header_spec.js
+++ b/spec/frontend/ci/runner/components/runner_header_spec.js
@@ -42,10 +42,6 @@ describe('RunnerHeader', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays the runner status', () => {
createComponent({
mountFn: mountExtended,
diff --git a/spec/frontend/ci/runner/components/runner_jobs_spec.js b/spec/frontend/ci/runner/components/runner_jobs_spec.js
index bdb8a4a31a3..365b0f1f5ba 100644
--- a/spec/frontend/ci/runner/components/runner_jobs_spec.js
+++ b/spec/frontend/ci/runner/components/runner_jobs_spec.js
@@ -4,7 +4,7 @@ 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 { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import RunnerJobs from '~/ci/runner/components/runner_jobs.vue';
import RunnerJobsTable from '~/ci/runner/components/runner_jobs_table.vue';
import RunnerPagination from '~/ci/runner/components/runner_pagination.vue';
@@ -15,7 +15,7 @@ import runnerJobsQuery from '~/ci/runner/graphql/show/runner_jobs.query.graphql'
import { runnerData, runnerJobsData } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
const mockRunner = runnerData.data.runner;
@@ -47,7 +47,6 @@ describe('RunnerJobs', () => {
afterEach(() => {
mockRunnerJobsQuery.mockReset();
- wrapper.destroy();
});
it('Requests runner jobs', async () => {
diff --git a/spec/frontend/ci/runner/components/runner_jobs_table_spec.js b/spec/frontend/ci/runner/components/runner_jobs_table_spec.js
index 281aa1aeb77..694c5a6ed17 100644
--- a/spec/frontend/ci/runner/components/runner_jobs_table_spec.js
+++ b/spec/frontend/ci/runner/components/runner_jobs_table_spec.js
@@ -37,10 +37,6 @@ describe('RunnerJobsTable', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Sets job id as a row key', () => {
createComponent();
diff --git a/spec/frontend/ci/runner/components/runner_list_empty_state_spec.js b/spec/frontend/ci/runner/components/runner_list_empty_state_spec.js
index 6aea3ddf58c..3e813723b5b 100644
--- a/spec/frontend/ci/runner/components/runner_list_empty_state_spec.js
+++ b/spec/frontend/ci/runner/components/runner_list_empty_state_spec.js
@@ -31,7 +31,7 @@ describe('RunnerListEmptyState', () => {
...props,
},
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
},
stubs: {
GlEmptyState,
@@ -62,11 +62,11 @@ describe('RunnerListEmptyState', () => {
expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`);
});
- describe('when create_runner_workflow is enabled', () => {
+ describe('when create_runner_workflow_for_admin is enabled', () => {
beforeEach(() => {
createComponent({
provide: {
- glFeatures: { createRunnerWorkflow: true },
+ glFeatures: { createRunnerWorkflowForAdmin: true },
},
});
});
@@ -76,14 +76,14 @@ describe('RunnerListEmptyState', () => {
});
});
- describe('when create_runner_workflow is enabled and newRunnerPath not defined', () => {
+ describe('when create_runner_workflow_for_admin is enabled and newRunnerPath not defined', () => {
beforeEach(() => {
createComponent({
props: {
newRunnerPath: null,
},
provide: {
- glFeatures: { createRunnerWorkflow: true },
+ glFeatures: { createRunnerWorkflowForAdmin: true },
},
});
});
@@ -95,11 +95,11 @@ describe('RunnerListEmptyState', () => {
});
});
- describe('when create_runner_workflow is disabled', () => {
+ describe('when create_runner_workflow_for_admin is disabled', () => {
beforeEach(() => {
createComponent({
provide: {
- glFeatures: { createRunnerWorkflow: false },
+ glFeatures: { createRunnerWorkflowForAdmin: false },
},
});
});
diff --git a/spec/frontend/ci/runner/components/runner_list_spec.js b/spec/frontend/ci/runner/components/runner_list_spec.js
index 2e5d1dbd063..6f4913dca3e 100644
--- a/spec/frontend/ci/runner/components/runner_list_spec.js
+++ b/spec/frontend/ci/runner/components/runner_list_spec.js
@@ -57,10 +57,6 @@ describe('RunnerList', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays headers', () => {
createComponent(
{
diff --git a/spec/frontend/ci/runner/components/runner_membership_toggle_spec.js b/spec/frontend/ci/runner/components/runner_membership_toggle_spec.js
index f089becd400..7ff3ec92042 100644
--- a/spec/frontend/ci/runner/components/runner_membership_toggle_spec.js
+++ b/spec/frontend/ci/runner/components/runner_membership_toggle_spec.js
@@ -18,10 +18,6 @@ describe('RunnerMembershipToggle', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays text', () => {
createComponent({ mountFn: mount });
diff --git a/spec/frontend/ci/runner/components/runner_pagination_spec.js b/spec/frontend/ci/runner/components/runner_pagination_spec.js
index f835ee4514d..6d84eb810f8 100644
--- a/spec/frontend/ci/runner/components/runner_pagination_spec.js
+++ b/spec/frontend/ci/runner/components/runner_pagination_spec.js
@@ -16,10 +16,6 @@ describe('RunnerPagination', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('When in between pages', () => {
const mockPageInfo = {
startCursor: mockStartCursor,
diff --git a/spec/frontend/ci/runner/components/runner_pause_button_spec.js b/spec/frontend/ci/runner/components/runner_pause_button_spec.js
index 12680e01b98..62e6cc902b7 100644
--- a/spec/frontend/ci/runner/components/runner_pause_button_spec.js
+++ b/spec/frontend/ci/runner/components/runner_pause_button_spec.js
@@ -7,7 +7,7 @@ import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_help
import runnerToggleActiveMutation from '~/ci/runner/graphql/shared/runner_toggle_active.mutation.graphql';
import waitForPromises from 'helpers/wait_for_promises';
import { captureException } from '~/ci/runner/sentry_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import {
I18N_PAUSE,
I18N_PAUSE_TOOLTIP,
@@ -22,7 +22,7 @@ const mockRunner = allRunnersData.data.runners.nodes[0];
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
describe('RunnerPauseButton', () => {
@@ -46,7 +46,7 @@ describe('RunnerPauseButton', () => {
},
apolloProvider: createMockApollo([[runnerToggleActiveMutation, runnerToggleActiveHandler]]),
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -74,10 +74,6 @@ describe('RunnerPauseButton', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Pause/Resume action', () => {
describe.each`
runnerState | icon | content | tooltip | isActive | newActiveValue
diff --git a/spec/frontend/ci/runner/components/runner_paused_badge_spec.js b/spec/frontend/ci/runner/components/runner_paused_badge_spec.js
index b051ebe99a7..54768ea50da 100644
--- a/spec/frontend/ci/runner/components/runner_paused_badge_spec.js
+++ b/spec/frontend/ci/runner/components/runner_paused_badge_spec.js
@@ -16,7 +16,7 @@ describe('RunnerTypeBadge', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -25,10 +25,6 @@ describe('RunnerTypeBadge', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders paused state', () => {
expect(wrapper.text()).toBe(I18N_PAUSED);
expect(findBadge().props('variant')).toBe('warning');
diff --git a/spec/frontend/ci/runner/components/runner_projects_spec.js b/spec/frontend/ci/runner/components/runner_projects_spec.js
index 17517c4db66..ccc1bc18675 100644
--- a/spec/frontend/ci/runner/components/runner_projects_spec.js
+++ b/spec/frontend/ci/runner/components/runner_projects_spec.js
@@ -4,7 +4,7 @@ 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 { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { sprintf } from '~/locale';
import {
I18N_ASSIGNED_PROJECTS,
@@ -22,7 +22,7 @@ import runnerProjectsQuery from '~/ci/runner/graphql/show/runner_projects.query.
import { runnerData, runnerProjectsData } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
const mockRunner = runnerData.data.runner;
@@ -56,7 +56,6 @@ describe('RunnerProjects', () => {
afterEach(() => {
mockRunnerProjectsQuery.mockReset();
- wrapper.destroy();
});
it('Requests runner projects', async () => {
diff --git a/spec/frontend/ci/runner/components/runner_status_badge_spec.js b/spec/frontend/ci/runner/components/runner_status_badge_spec.js
index 45b410df2d4..e1eb81f2d23 100644
--- a/spec/frontend/ci/runner/components/runner_status_badge_spec.js
+++ b/spec/frontend/ci/runner/components/runner_status_badge_spec.js
@@ -31,7 +31,7 @@ describe('RunnerTypeBadge', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -43,8 +43,6 @@ describe('RunnerTypeBadge', () => {
afterEach(() => {
jest.useFakeTimers({ legacyFakeTimers: true });
-
- wrapper.destroy();
});
it('renders online state', () => {
diff --git a/spec/frontend/ci/runner/components/runner_tag_spec.js b/spec/frontend/ci/runner/components/runner_tag_spec.js
index 7bcb046ae43..e3d46e5d6df 100644
--- a/spec/frontend/ci/runner/components/runner_tag_spec.js
+++ b/spec/frontend/ci/runner/components/runner_tag_spec.js
@@ -29,8 +29,8 @@ describe('RunnerTag', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
- GlResizeObserver: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
+ GlResizeObserver: createMockDirective('gl-resize-observer'),
},
});
};
@@ -39,10 +39,6 @@ describe('RunnerTag', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays tag text', () => {
expect(wrapper.text()).toBe(mockTag);
});
diff --git a/spec/frontend/ci/runner/components/runner_tags_spec.js b/spec/frontend/ci/runner/components/runner_tags_spec.js
index 96bec00302b..bcb1d1f9e13 100644
--- a/spec/frontend/ci/runner/components/runner_tags_spec.js
+++ b/spec/frontend/ci/runner/components/runner_tags_spec.js
@@ -21,10 +21,6 @@ describe('RunnerTags', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays tags text', () => {
expect(wrapper.text()).toMatchInterpolatedText('tag1 tag2');
diff --git a/spec/frontend/ci/runner/components/runner_type_badge_spec.js b/spec/frontend/ci/runner/components/runner_type_badge_spec.js
index 58f09362759..7a0fb6f69ea 100644
--- a/spec/frontend/ci/runner/components/runner_type_badge_spec.js
+++ b/spec/frontend/ci/runner/components/runner_type_badge_spec.js
@@ -23,15 +23,11 @@ describe('RunnerTypeBadge', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
type | text
${INSTANCE_TYPE} | ${I18N_INSTANCE_TYPE}
diff --git a/spec/frontend/ci/runner/components/runner_type_tabs_spec.js b/spec/frontend/ci/runner/components/runner_type_tabs_spec.js
index 3347c190083..6e15c84ad7e 100644
--- a/spec/frontend/ci/runner/components/runner_type_tabs_spec.js
+++ b/spec/frontend/ci/runner/components/runner_type_tabs_spec.js
@@ -63,10 +63,6 @@ describe('RunnerTypeTabs', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Renders all options to filter runners by default', () => {
createComponent();
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 a0e51ebf958..620e2f85890 100644
--- a/spec/frontend/ci/runner/components/runner_update_form_spec.js
+++ b/spec/frontend/ci/runner/components/runner_update_form_spec.js
@@ -5,7 +5,7 @@ import { __ } from '~/locale';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import RunnerUpdateForm from '~/ci/runner/components/runner_update_form.vue';
import {
@@ -21,7 +21,7 @@ import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_al
import { runnerFormData } from '../mock_data';
jest.mock('~/ci/runner/local_storage_alert/save_alert_to_local_storage');
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
jest.mock('~/lib/utils/url_utility');
@@ -107,10 +107,6 @@ describe('RunnerUpdateForm', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Form has a submit button', () => {
expect(findSubmit().exists()).toBe(true);
});
diff --git a/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js b/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js
index b7d9d3ad23e..e9f2e888b9a 100644
--- a/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js
+++ b/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js
@@ -3,14 +3,14 @@ import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+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 TagToken, { TAG_SUGGESTIONS_PATH } from '~/ci/runner/components/search_tokens/tag_token.vue';
import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
import { getRecentlyUsedSuggestions } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/vue_shared/components/filtered_search_bar/filtered_search_utils', () => ({
...jest.requireActual('~/vue_shared/components/filtered_search_bar/filtered_search_utils'),
@@ -90,7 +90,6 @@ describe('TagToken', () => {
afterEach(() => {
getRecentlyUsedSuggestions.mockReset();
- wrapper.destroy();
});
describe('when the tags token is displayed', () => {
diff --git a/spec/frontend/ci/runner/components/stat/runner_single_stat_spec.js b/spec/frontend/ci/runner/components/stat/runner_single_stat_spec.js
index cad61f26012..f30b75ee614 100644
--- a/spec/frontend/ci/runner/components/stat/runner_single_stat_spec.js
+++ b/spec/frontend/ci/runner/components/stat/runner_single_stat_spec.js
@@ -32,10 +32,6 @@ describe('RunnerStats', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
case | count | value
${'number'} | ${99} | ${'99'}
diff --git a/spec/frontend/ci/runner/components/stat/runner_stats_spec.js b/spec/frontend/ci/runner/components/stat/runner_stats_spec.js
index 3d45674d106..13366a788d5 100644
--- a/spec/frontend/ci/runner/components/stat/runner_stats_spec.js
+++ b/spec/frontend/ci/runner/components/stat/runner_stats_spec.js
@@ -47,10 +47,6 @@ describe('RunnerStats', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Displays all the stats', () => {
createComponent({
mountFn: mount,
diff --git a/spec/frontend/ci/runner/group_runner_show/group_runner_show_app_spec.js b/spec/frontend/ci/runner/group_runner_show/group_runner_show_app_spec.js
index 2ad31dea774..fadc6e5ebc5 100644
--- a/spec/frontend/ci/runner/group_runner_show/group_runner_show_app_spec.js
+++ b/spec/frontend/ci/runner/group_runner_show/group_runner_show_app_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -24,7 +24,7 @@ import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_al
import { runnerData } from '../mock_data';
jest.mock('~/ci/runner/local_storage_alert/save_alert_to_local_storage');
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
jest.mock('~/lib/utils/url_utility');
@@ -74,7 +74,6 @@ describe('GroupRunnerShowApp', () => {
afterEach(() => {
mockRunnerQuery.mockReset();
- wrapper.destroy();
});
describe('When showing runner details', () => {
diff --git a/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js b/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js
index 39ea5cade28..00c7262e38b 100644
--- a/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js
+++ b/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js
@@ -9,7 +9,7 @@ import {
mountExtended,
} from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { updateHistory } from '~/lib/utils/url_utility';
@@ -74,7 +74,7 @@ const mockGroupRunnersCount = mockGroupRunnersEdges.length;
const mockGroupRunnersHandler = jest.fn();
const mockGroupRunnersCountHandler = jest.fn();
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
@@ -138,7 +138,6 @@ describe('GroupRunnersApp', () => {
afterEach(() => {
mockGroupRunnersHandler.mockReset();
mockGroupRunnersCountHandler.mockReset();
- wrapper.destroy();
});
it('shows the runner tabs with a runner count for each type', async () => {
diff --git a/spec/frontend/ci/runner/local_storage_alert/show_alert_from_local_storage_spec.js b/spec/frontend/ci/runner/local_storage_alert/show_alert_from_local_storage_spec.js
index 03908891cfd..30e49fc7644 100644
--- a/spec/frontend/ci/runner/local_storage_alert/show_alert_from_local_storage_spec.js
+++ b/spec/frontend/ci/runner/local_storage_alert/show_alert_from_local_storage_spec.js
@@ -2,9 +2,9 @@ import AccessorUtilities from '~/lib/utils/accessor';
import { showAlertFromLocalStorage } from '~/ci/runner/local_storage_alert/show_alert_from_local_storage';
import { LOCAL_STORAGE_ALERT_KEY } from '~/ci/runner/local_storage_alert/constants';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('showAlertFromLocalStorage', () => {
useLocalStorageSpy();
diff --git a/spec/frontend/ci/runner/mock_data.js b/spec/frontend/ci/runner/mock_data.js
index 5cdf0ea4e3b..092a419c1fe 100644
--- a/spec/frontend/ci/runner/mock_data.js
+++ b/spec/frontend/ci/runner/mock_data.js
@@ -1,6 +1,10 @@
// Fixtures generated by: spec/frontend/fixtures/runner.rb
+// Register runner queries
+import runnerForRegistration from 'test_fixtures/graphql/ci/runner/register/runner_for_registration.query.graphql.json';
+
// Show runner queries
+import runnerCreateResult from 'test_fixtures/graphql/ci/runner/new/runner_create.mutation.graphql.json';
import runnerData from 'test_fixtures/graphql/ci/runner/show/runner.query.graphql.json';
import runnerWithGroupData from 'test_fixtures/graphql/ci/runner/show/runner.query.graphql.with_group.json';
import runnerProjectsData from 'test_fixtures/graphql/ci/runner/show/runner_projects.query.graphql.json';
@@ -9,6 +13,8 @@ import runnerJobsData from 'test_fixtures/graphql/ci/runner/show/runner_jobs.que
// Edit runner queries
import runnerFormData from 'test_fixtures/graphql/ci/runner/edit/runner_form.query.graphql.json';
+// New runner queries
+
// List queries
import allRunnersData from 'test_fixtures/graphql/ci/runner/list/all_runners.query.graphql.json';
import allRunnersDataPaginated from 'test_fixtures/graphql/ci/runner/list/all_runners.query.graphql.paginated.json';
@@ -321,4 +327,6 @@ export {
runnerProjectsData,
runnerJobsData,
runnerFormData,
+ runnerCreateResult,
+ runnerForRegistration,
};
diff --git a/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js b/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js
index a9369a5e626..79bbf95f8f0 100644
--- a/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js
+++ b/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js
@@ -3,7 +3,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import RunnerHeader from '~/ci/runner/components/runner_header.vue';
@@ -15,7 +15,7 @@ import { I18N_STATUS_NEVER_CONTACTED, I18N_INSTANCE_TYPE } from '~/ci/runner/con
import { runnerFormData } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
const mockRunner = runnerFormData.data.runner;
@@ -51,7 +51,6 @@ describe('RunnerEditApp', () => {
afterEach(() => {
mockRunnerQuery.mockReset();
- wrapper.destroy();
});
it('expect GraphQL ID to be requested', async () => {
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 b2084e3a7de..1be89ae832d 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
@@ -15,7 +15,7 @@ exports[`Secure File Metadata Modal when a .cer file is supplied matches cer the
>
<table
- aria-busy="false"
+ aria-busy=""
aria-colcount="2"
class="table b-table gl-table"
role="table"
@@ -196,7 +196,7 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
>
<table
- aria-busy="false"
+ aria-busy=""
aria-colcount="2"
class="table b-table gl-table"
role="table"
diff --git a/spec/frontend/ci_secure_files/components/metadata/button_spec.js b/spec/frontend/ci_secure_files/components/metadata/button_spec.js
index 4ac5b3325d4..5bd4bab25af 100644
--- a/spec/frontend/ci_secure_files/components/metadata/button_spec.js
+++ b/spec/frontend/ci_secure_files/components/metadata/button_spec.js
@@ -12,10 +12,6 @@ describe('Secure File Metadata Button', () => {
const findButton = () => wrapper.findComponent(GlButton);
- afterEach(() => {
- wrapper.destroy();
- });
-
const createWrapper = (secureFile = {}, admin = false) => {
wrapper = mount(Button, {
propsData: {
diff --git a/spec/frontend/ci_secure_files/components/metadata/modal_spec.js b/spec/frontend/ci_secure_files/components/metadata/modal_spec.js
index 230507d32d7..e181d15f2f9 100644
--- a/spec/frontend/ci_secure_files/components/metadata/modal_spec.js
+++ b/spec/frontend/ci_secure_files/components/metadata/modal_spec.js
@@ -37,7 +37,6 @@ describe('Secure File Metadata Modal', () => {
afterEach(() => {
unmockTracking();
- wrapper.destroy();
});
describe('when a .cer file is supplied', () => {
diff --git a/spec/frontend/ci_secure_files/components/secure_files_list_spec.js b/spec/frontend/ci_secure_files/components/secure_files_list_spec.js
index ab6200ca6f4..17b5fdc4dde 100644
--- a/spec/frontend/ci_secure_files/components/secure_files_list_spec.js
+++ b/spec/frontend/ci_secure_files/components/secure_files_list_spec.js
@@ -15,11 +15,6 @@ const dummyApiVersion = 'v3000';
const dummyProjectId = 1;
const fileSizeLimit = 5;
const dummyUrlRoot = '/gitlab';
-const dummyGon = {
- api_version: dummyApiVersion,
- relative_url_root: dummyUrlRoot,
-};
-let originalGon;
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${dummyProjectId}/secure_files`;
describe('SecureFilesList', () => {
@@ -28,16 +23,16 @@ describe('SecureFilesList', () => {
let trackingSpy;
beforeEach(() => {
- originalGon = window.gon;
trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
- window.gon = { ...dummyGon };
+ window.gon = {
+ api_version: dummyApiVersion,
+ relative_url_root: dummyUrlRoot,
+ };
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
unmockTracking();
- window.gon = originalGon;
});
const createWrapper = (admin = true, props = {}) => {
diff --git a/spec/frontend/clusters/agents/components/activity_events_list_spec.js b/spec/frontend/clusters/agents/components/activity_events_list_spec.js
index 6b374b6620d..770815a9403 100644
--- a/spec/frontend/clusters/agents/components/activity_events_list_spec.js
+++ b/spec/frontend/clusters/agents/components/activity_events_list_spec.js
@@ -44,10 +44,6 @@ describe('ActivityEvents', () => {
const findAllActivityHistoryItems = () => wrapper.findAllComponents(ActivityHistoryItem);
const findSectionTitle = (at) => wrapper.findAllByTestId('activity-section-title').at(at);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('while the agentEvents query is loading', () => {
it('displays a loading icon', async () => {
createWrapper();
diff --git a/spec/frontend/clusters/agents/components/activity_history_item_spec.js b/spec/frontend/clusters/agents/components/activity_history_item_spec.js
index 68f6f11aa8f..48460519c6c 100644
--- a/spec/frontend/clusters/agents/components/activity_history_item_spec.js
+++ b/spec/frontend/clusters/agents/components/activity_history_item_spec.js
@@ -25,10 +25,6 @@ describe('ActivityHistoryItem', () => {
const findHistoryItem = () => wrapper.findComponent(HistoryItem);
const findTimeAgo = () => wrapper.findComponent(TimeAgoTooltip);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
kind | icon | title | lineNumber
${'token_created'} | ${EVENT_DETAILS.token_created.eventTypeIcon} | ${sprintf(EVENT_DETAILS.token_created.title, { tokenName: agentName })} | ${0}
diff --git a/spec/frontend/clusters/agents/components/agent_integration_status_row_spec.js b/spec/frontend/clusters/agents/components/agent_integration_status_row_spec.js
index db1219ccb41..ac0ce89f334 100644
--- a/spec/frontend/clusters/agents/components/agent_integration_status_row_spec.js
+++ b/spec/frontend/clusters/agents/components/agent_integration_status_row_spec.js
@@ -25,10 +25,6 @@ describe('IntegrationStatus', () => {
const findIcon = () => wrapper.findComponent(GlIcon);
const findBadge = () => wrapper.findComponent(GlBadge);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('icon', () => {
const icon = 'status-success';
const iconClass = 'gl-text-green-500';
diff --git a/spec/frontend/clusters/agents/components/create_token_button_spec.js b/spec/frontend/clusters/agents/components/create_token_button_spec.js
index 73856b74a8d..5a8906813cf 100644
--- a/spec/frontend/clusters/agents/components/create_token_button_spec.js
+++ b/spec/frontend/clusters/agents/components/create_token_button_spec.js
@@ -21,7 +21,7 @@ describe('CreateTokenButton', () => {
...provideData,
},
directives: {
- GlModalDirective: createMockDirective(),
+ GlModalDirective: createMockDirective('gl-modal-directive'),
},
stubs: {
GlTooltip,
@@ -29,10 +29,6 @@ describe('CreateTokenButton', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when user can create token', () => {
beforeEach(() => {
createWrapper();
diff --git a/spec/frontend/clusters/agents/components/create_token_modal_spec.js b/spec/frontend/clusters/agents/components/create_token_modal_spec.js
index 0d10801e80e..ff698952c6b 100644
--- a/spec/frontend/clusters/agents/components/create_token_modal_spec.js
+++ b/spec/frontend/clusters/agents/components/create_token_modal_spec.js
@@ -119,7 +119,6 @@ describe('CreateTokenModal', () => {
});
afterEach(() => {
- wrapper.destroy();
apolloProvider = null;
createResponse = null;
});
diff --git a/spec/frontend/clusters/agents/components/integration_status_spec.js b/spec/frontend/clusters/agents/components/integration_status_spec.js
index 36f0e622452..28a59391578 100644
--- a/spec/frontend/clusters/agents/components/integration_status_spec.js
+++ b/spec/frontend/clusters/agents/components/integration_status_spec.js
@@ -27,10 +27,6 @@ describe('IntegrationStatus', () => {
const findAgentStatus = () => wrapper.findByTestId('agent-status');
const findAgentIntegrationStatusRows = () => wrapper.findAllComponents(AgentIntegrationStatusRow);
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
lastUsedAt | status | iconName
${null} | ${'Never connected'} | ${'status-neutral'}
diff --git a/spec/frontend/clusters/agents/components/revoke_token_button_spec.js b/spec/frontend/clusters/agents/components/revoke_token_button_spec.js
index 6521221cbd7..ed7c940bb04 100644
--- a/spec/frontend/clusters/agents/components/revoke_token_button_spec.js
+++ b/spec/frontend/clusters/agents/components/revoke_token_button_spec.js
@@ -45,7 +45,7 @@ describe('RevokeTokenButton', () => {
const findInput = () => wrapper.findComponent(GlFormInput);
const findTooltip = () => wrapper.findComponent(GlTooltip);
const findPrimaryAction = () => findModal().props('actionPrimary');
- const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[0][attr];
+ const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[attr];
const createMockApolloProvider = ({ mutationResponse }) => {
revokeSpy = jest.fn().mockResolvedValue(mutationResponse);
@@ -105,7 +105,6 @@ describe('RevokeTokenButton', () => {
});
afterEach(() => {
- wrapper.destroy();
apolloProvider = null;
revokeSpy = null;
});
diff --git a/spec/frontend/clusters/agents/components/show_spec.js b/spec/frontend/clusters/agents/components/show_spec.js
index efa85136b17..118a3af48e0 100644
--- a/spec/frontend/clusters/agents/components/show_spec.js
+++ b/spec/frontend/clusters/agents/components/show_spec.js
@@ -79,10 +79,6 @@ describe('ClusterAgentShow', () => {
const findActivity = () => wrapper.findComponent(ActivityEvents);
const findIntegrationStatus = () => wrapper.findComponent(IntegrationStatus);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default behaviour', () => {
beforeEach(async () => {
createWrapper({ clusterAgent: defaultClusterAgent });
diff --git a/spec/frontend/clusters/agents/components/token_table_spec.js b/spec/frontend/clusters/agents/components/token_table_spec.js
index 334615f1818..1a6aeedb694 100644
--- a/spec/frontend/clusters/agents/components/token_table_spec.js
+++ b/spec/frontend/clusters/agents/components/token_table_spec.js
@@ -57,10 +57,6 @@ describe('ClusterAgentTokenTable', () => {
return createComponent(defaultTokens);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays the create token button', () => {
expect(findCreateTokenBtn().exists()).toBe(true);
});
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 656e72baf77..21ffda8578a 100644
--- a/spec/frontend/clusters/components/__snapshots__/new_cluster_spec.js.snap
+++ b/spec/frontend/clusters/components/__snapshots__/new_cluster_spec.js.snap
@@ -3,7 +3,7 @@
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\\" event=\\"click\\" routertag=\\"a\\" class=\\"gl-link\\">How do I use a certificate to connect to my cluster?</b-link-stub>
+ <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>
</p>
</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 46ee123a12d..67b0ecdf7eb 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
@@ -43,3 +43,212 @@ exports[`Remove cluster confirmation modal renders buttons with modal included 1
<!---->
</div>
`;
+
+exports[`Remove cluster confirmation modal two buttons open modal with "cleanup" option 1`] = `
+<div
+ class="gl-display-flex"
+>
+ <button
+ class="btn gl-mr-3 btn-danger btn-md gl-button"
+ data-testid="remove-integration-and-resources-button"
+ type="button"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+
+ Remove integration and resources
+
+ </span>
+ </button>
+
+ <button
+ class="btn btn-danger btn-md gl-button btn-danger-secondary"
+ data-testid="remove-integration-button"
+ type="button"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+
+ 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
+ </code>
+ </li>
+ </ul>
+ </div>
+
+ <strong>
+ To remove your integration and resources, type
+ <code>
+ my-test-cluster
+ </code>
+ to confirm:
+ </strong>
+
+ <form
+ action="clusterPath"
+ class="gl-mb-5"
+ method="post"
+ >
+ <input
+ name="_method"
+ 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"
+ 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>
+ </div>
+</div>
+`;
+
+exports[`Remove cluster confirmation modal two buttons open modal without "cleanup" option 1`] = `
+<div
+ class="gl-display-flex"
+>
+ <button
+ class="btn gl-mr-3 btn-danger btn-md gl-button"
+ data-testid="remove-integration-and-resources-button"
+ type="button"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+
+ Remove integration and resources
+
+ </span>
+ </button>
+
+ <button
+ class="btn btn-danger btn-md gl-button btn-danger-secondary"
+ data-testid="remove-integration-button"
+ type="button"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+
+ Remove integration
+
+ </span>
+ </button>
+
+ <div
+ kind="danger"
+ >
+ <p>
+ You are about to remove your cluster integration.
+ </p>
+
+ <!---->
+
+ <strong>
+ To remove your integration, type
+ <code>
+ my-test-cluster
+ </code>
+ to confirm:
+ </strong>
+
+ <form
+ action="clusterPath"
+ class="gl-mb-5"
+ method="post"
+ >
+ <input
+ name="_method"
+ 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"
+ name="confirm_cluster_name_input"
+ type="text"
+ />
+ </form>
+
+ <!---->
+ </div>
+</div>
+`;
diff --git a/spec/frontend/clusters/components/new_cluster_spec.js b/spec/frontend/clusters/components/new_cluster_spec.js
index ef39c90aaef..398b472a3a7 100644
--- a/spec/frontend/clusters/components/new_cluster_spec.js
+++ b/spec/frontend/clusters/components/new_cluster_spec.js
@@ -20,10 +20,6 @@ describe('NewCluster', () => {
return createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the cluster component correctly', () => {
expect(wrapper.html()).toMatchSnapshot();
});
diff --git a/spec/frontend/clusters/components/remove_cluster_confirmation_spec.js b/spec/frontend/clusters/components/remove_cluster_confirmation_spec.js
index 53683af893a..04b7909b534 100644
--- a/spec/frontend/clusters/components/remove_cluster_confirmation_spec.js
+++ b/spec/frontend/clusters/components/remove_cluster_confirmation_spec.js
@@ -6,6 +6,7 @@ import RemoveClusterConfirmation from '~/clusters/components/remove_cluster_conf
describe('Remove cluster confirmation modal', () => {
let wrapper;
+ const showMock = jest.fn();
const createComponent = ({ props = {}, stubs = {} } = {}) => {
wrapper = mount(RemoveClusterConfirmation, {
@@ -18,11 +19,6 @@ describe('Remove cluster confirmation modal', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders buttons with modal included', () => {
createComponent();
expect(wrapper.element).toMatchSnapshot();
@@ -38,9 +34,13 @@ describe('Remove cluster confirmation modal', () => {
beforeEach(() => {
createComponent({
props: { clusterName: 'my-test-cluster' },
- stubs: { GlSprintf, GlModal: stubComponent(GlModal) },
+ stubs: {
+ GlSprintf,
+ GlModal: stubComponent(GlModal, {
+ methods: { show: showMock },
+ }),
+ },
});
- jest.spyOn(findModal().vm, 'show').mockReturnValue();
});
it('open modal with "cleanup" option', async () => {
@@ -48,8 +48,8 @@ describe('Remove cluster confirmation modal', () => {
await nextTick();
- expect(findModal().vm.show).toHaveBeenCalled();
- expect(wrapper.vm.confirmCleanup).toEqual(true);
+ expect(showMock).toHaveBeenCalled();
+ expect(wrapper.element).toMatchSnapshot();
expect(findModal().html()).toContain(
'<strong>To remove your integration and resources, type <code>my-test-cluster</code> to confirm:</strong>',
);
@@ -60,8 +60,8 @@ describe('Remove cluster confirmation modal', () => {
await nextTick();
- expect(findModal().vm.show).toHaveBeenCalled();
- expect(wrapper.vm.confirmCleanup).toEqual(false);
+ expect(showMock).toHaveBeenCalled();
+ expect(wrapper.element).toMatchSnapshot();
expect(findModal().html()).toContain(
'<strong>To remove your integration, type <code>my-test-cluster</code> to confirm:</strong>',
);
diff --git a/spec/frontend/clusters/forms/components/integration_form_spec.js b/spec/frontend/clusters/forms/components/integration_form_spec.js
index b17886a5826..396f8215b9f 100644
--- a/spec/frontend/clusters/forms/components/integration_form_spec.js
+++ b/spec/frontend/clusters/forms/components/integration_form_spec.js
@@ -1,6 +1,6 @@
import { GlToggle, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
+import Vue from 'vue';
import Vuex from 'vuex';
import IntegrationForm from '~/clusters/forms/components/integration_form.vue';
import { createStore } from '~/clusters/forms/stores/index';
@@ -27,17 +27,9 @@ describe('ClusterIntegrationForm', () => {
});
};
- const destroyWrapper = () => {
- wrapper.destroy();
- wrapper = null;
- };
-
const findSubmitButton = () => wrapper.findComponent(GlButton);
const findGlToggle = () => wrapper.findComponent(GlToggle);
-
- afterEach(() => {
- destroyWrapper();
- });
+ const findClusterEnvironmentScopeInput = () => wrapper.find('[id="cluster_environment_scope"]');
describe('rendering', () => {
beforeEach(() => createWrapper());
@@ -50,7 +42,9 @@ describe('ClusterIntegrationForm', () => {
});
it('sets the envScope to default', () => {
- expect(wrapper.find('[id="cluster_environment_scope"]').attributes('value')).toBe('*');
+ expect(findClusterEnvironmentScopeInput().attributes('value')).toBe(
+ defaultStoreValues.environmentScope,
+ );
});
it('sets the baseDomain to default', () => {
@@ -76,20 +70,15 @@ describe('ClusterIntegrationForm', () => {
beforeEach(() => createWrapper());
it('enables the submit button on changing toggle to different value', async () => {
- await nextTick();
- // setData is a bad approach because it changes the internal implementation which we should not touch
- // but our GlFormInput lacks the ability to set a new value.
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- await wrapper.setData({ toggleEnabled: !defaultStoreValues.enabled });
+ await findGlToggle().vm.$emit('change', false);
expect(findSubmitButton().props('disabled')).toBe(false);
});
it('enables the submit button on changing input values', async () => {
- await nextTick();
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- await wrapper.setData({ envScope: `${defaultStoreValues.environmentScope}1` });
+ await findClusterEnvironmentScopeInput().vm.$emit(
+ 'input',
+ `${defaultStoreValues.environmentScope}1`,
+ );
expect(findSubmitButton().props('disabled')).toBe(false);
});
});
diff --git a/spec/frontend/clusters_list/components/agent_token_spec.js b/spec/frontend/clusters_list/components/agent_token_spec.js
index a92a03fedb6..edb8b22d79e 100644
--- a/spec/frontend/clusters_list/components/agent_token_spec.js
+++ b/spec/frontend/clusters_list/components/agent_token_spec.js
@@ -53,10 +53,6 @@ describe('InstallAgentModal', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('initial state', () => {
it('shows basic agent installation instructions', () => {
expect(wrapper.text()).toContain(I18N_AGENT_TOKEN.basicInstallTitle);
diff --git a/spec/frontend/clusters_list/components/agents_spec.js b/spec/frontend/clusters_list/components/agents_spec.js
index 2372ab30300..d91245ba9b4 100644
--- a/spec/frontend/clusters_list/components/agents_spec.js
+++ b/spec/frontend/clusters_list/components/agents_spec.js
@@ -83,8 +83,6 @@ describe('Agents', () => {
const findBanner = () => wrapper.findComponent(GlBanner);
afterEach(() => {
- wrapper.destroy();
-
localStorage.removeItem(AGENT_FEEDBACK_KEY);
});
diff --git a/spec/frontend/clusters_list/components/ancestor_notice_spec.js b/spec/frontend/clusters_list/components/ancestor_notice_spec.js
index 758f6586e1a..4a2effa3463 100644
--- a/spec/frontend/clusters_list/components/ancestor_notice_spec.js
+++ b/spec/frontend/clusters_list/components/ancestor_notice_spec.js
@@ -18,10 +18,6 @@ describe('ClustersAncestorNotice', () => {
return createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when cluster does not have ancestors', () => {
beforeEach(async () => {
store.state.hasAncestorClusters = false;
diff --git a/spec/frontend/clusters_list/components/clusters_actions_spec.js b/spec/frontend/clusters_list/components/clusters_actions_spec.js
index f4ee3f93cb5..e4e1986f705 100644
--- a/spec/frontend/clusters_list/components/clusters_actions_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_actions_spec.js
@@ -35,7 +35,7 @@ describe('ClustersActionsComponent', () => {
...provideData,
},
directives: {
- GlModalDirective: createMockDirective(),
+ GlModalDirective: createMockDirective('gl-modal-directive'),
},
});
};
@@ -44,9 +44,6 @@ describe('ClustersActionsComponent', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
describe('when the certificate based clusters are enabled', () => {
it('renders actions menu', () => {
expect(findDropdown().exists()).toBe(true);
diff --git a/spec/frontend/clusters_list/components/clusters_empty_state_spec.js b/spec/frontend/clusters_list/components/clusters_empty_state_spec.js
index 2c3a224f3c8..5a5006d24c4 100644
--- a/spec/frontend/clusters_list/components/clusters_empty_state_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_empty_state_spec.js
@@ -21,10 +21,6 @@ describe('ClustersEmptyStateComponent', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the help text is not provided', () => {
beforeEach(() => {
createWrapper();
diff --git a/spec/frontend/clusters_list/components/clusters_main_view_spec.js b/spec/frontend/clusters_list/components/clusters_main_view_spec.js
index 6f23ed47d2a..af8d3b59869 100644
--- a/spec/frontend/clusters_list/components/clusters_main_view_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_main_view_spec.js
@@ -40,10 +40,6 @@ describe('ClustersMainViewComponent', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findTabs = () => wrapper.findComponent(GlTabs);
const findAllTabs = () => wrapper.findAllComponents(GlTab);
const findGlTabAtIndex = (index) => findAllTabs().at(index);
diff --git a/spec/frontend/clusters_list/components/clusters_spec.js b/spec/frontend/clusters_list/components/clusters_spec.js
index 20dbff9df15..207bfddcb4f 100644
--- a/spec/frontend/clusters_list/components/clusters_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_spec.js
@@ -75,7 +75,6 @@ describe('Clusters', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
captureException.mockRestore();
});
@@ -271,9 +270,7 @@ describe('Clusters', () => {
describe('when updating currentPage', () => {
beforeEach(() => {
mockPollingApi(HTTP_STATUS_OK, apiData, paginationHeader(totalSecondPage, perPage, 2));
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ currentPage: 2 });
+ findPaginatedButtons().vm.$emit('input', 2);
return axios.waitForAll();
});
diff --git a/spec/frontend/clusters_list/components/clusters_view_all_spec.js b/spec/frontend/clusters_list/components/clusters_view_all_spec.js
index b4eb9242003..e81b242dd90 100644
--- a/spec/frontend/clusters_list/components/clusters_view_all_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_view_all_spec.js
@@ -60,10 +60,6 @@ describe('ClustersViewAllComponent', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when agents and clusters are not loaded', () => {
const initialState = {
loadingClusters: true,
diff --git a/spec/frontend/clusters_list/components/delete_agent_button_spec.js b/spec/frontend/clusters_list/components/delete_agent_button_spec.js
index 82850b9dea4..53cf67bca0f 100644
--- a/spec/frontend/clusters_list/components/delete_agent_button_spec.js
+++ b/spec/frontend/clusters_list/components/delete_agent_button_spec.js
@@ -33,7 +33,7 @@ describe('DeleteAgentButton', () => {
const findDeleteBtn = () => wrapper.findComponent(GlButton);
const findInput = () => wrapper.findComponent(GlFormInput);
const findPrimaryAction = () => findModal().props('actionPrimary');
- const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[0][attr];
+ const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[attr];
const findDeleteAgentButtonTooltip = () => wrapper.findByTestId('delete-agent-button-tooltip');
const getTooltipText = (el) => {
const binding = getBinding(el, 'gl-tooltip');
@@ -84,7 +84,7 @@ describe('DeleteAgentButton', () => {
...provideData,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
propsData,
mocks: { $toast: { show: toast } },
@@ -108,7 +108,6 @@ describe('DeleteAgentButton', () => {
});
afterEach(() => {
- wrapper.destroy();
apolloProvider = null;
deleteResponse = null;
toast = null;
diff --git a/spec/frontend/clusters_list/components/install_agent_modal_spec.js b/spec/frontend/clusters_list/components/install_agent_modal_spec.js
index 10264d6a011..3156eaaecfc 100644
--- a/spec/frontend/clusters_list/components/install_agent_modal_spec.js
+++ b/spec/frontend/clusters_list/components/install_agent_modal_spec.js
@@ -139,7 +139,6 @@ describe('InstallAgentModal', () => {
});
afterEach(() => {
- wrapper.destroy();
apolloProvider = null;
});
diff --git a/spec/frontend/clusters_list/components/node_error_help_text_spec.js b/spec/frontend/clusters_list/components/node_error_help_text_spec.js
index 3211ba44eff..a3dfc848fc8 100644
--- a/spec/frontend/clusters_list/components/node_error_help_text_spec.js
+++ b/spec/frontend/clusters_list/components/node_error_help_text_spec.js
@@ -13,10 +13,6 @@ describe('NodeErrorHelpText', () => {
const findPopover = () => wrapper.findComponent(GlPopover);
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
errorType | wrapperText | popoverText
${'authentication_error'} | ${'Unable to Authenticate'} | ${'GitLab failed to authenticate'}
diff --git a/spec/frontend/clusters_list/store/actions_spec.js b/spec/frontend/clusters_list/store/actions_spec.js
index 360fd3b2842..6d23db0517d 100644
--- a/spec/frontend/clusters_list/store/actions_spec.js
+++ b/spec/frontend/clusters_list/store/actions_spec.js
@@ -5,13 +5,13 @@ import waitForPromises from 'helpers/wait_for_promises';
import { MAX_REQUESTS } from '~/clusters_list/constants';
import * as actions from '~/clusters_list/store/actions';
import * as types from '~/clusters_list/store/mutation_types';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import Poll from '~/lib/utils/poll';
import { apiData } from '../mock_data';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
describe('Clusters store actions', () => {
let captureException;
@@ -81,7 +81,7 @@ describe('Clusters store actions', () => {
);
});
- it('should show flash on API error', async () => {
+ it('should show alert on API error', async () => {
mock.onGet().reply(HTTP_STATUS_BAD_REQUEST, 'Not Found');
await testAction(
diff --git a/spec/frontend/code_navigation/components/app_spec.js b/spec/frontend/code_navigation/components/app_spec.js
index b9be262efd0..88861b0d08a 100644
--- a/spec/frontend/code_navigation/components/app_spec.js
+++ b/spec/frontend/code_navigation/components/app_spec.js
@@ -32,10 +32,6 @@ function factory(initialState = {}, props = {}) {
}
describe('Code navigation app component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('sets initial data on mount if the correct props are passed', () => {
const codeNavigationPath = 'code/nav/path.js';
const path = 'blob/path.js';
diff --git a/spec/frontend/code_navigation/components/popover_spec.js b/spec/frontend/code_navigation/components/popover_spec.js
index 874263e046a..1bfaf7e959e 100644
--- a/spec/frontend/code_navigation/components/popover_spec.js
+++ b/spec/frontend/code_navigation/components/popover_spec.js
@@ -61,10 +61,6 @@ function factory({ position, data, definitionPathPrefix, blobPath = 'index.js' }
}
describe('Code navigation popover component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders popover', () => {
factory({
position: { x: 0, y: 0, height: 0 },
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 debd10de118..64623968aa0 100644
--- a/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
+++ b/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
@@ -5,7 +5,7 @@ import { shallowMount } from '@vue/test-utils';
import createMockApollo from 'helpers/mock_apollo_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+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 { COMMIT_BOX_POLL_INTERVAL } from '~/projects/commit_box/info/constants';
@@ -20,7 +20,7 @@ import {
mockUpstreamQueryResponse,
} from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -69,10 +69,6 @@ describe('Commit box pipeline mini graph', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('loading state', () => {
it('should display loading state when loading', () => {
createComponent();
diff --git a/spec/frontend/commit/commit_pipeline_status_component_spec.js b/spec/frontend/commit/commit_pipeline_status_component_spec.js
index e75fb697a7b..e474ef9c635 100644
--- a/spec/frontend/commit/commit_pipeline_status_component_spec.js
+++ b/spec/frontend/commit/commit_pipeline_status_component_spec.js
@@ -3,14 +3,14 @@ import { shallowMount } from '@vue/test-utils';
import Visibility from 'visibilityjs';
import { nextTick } from 'vue';
import fixture from 'test_fixtures/pipelines/pipelines.json';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Poll from '~/lib/utils/poll';
import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
jest.mock('~/lib/utils/poll');
jest.mock('visibilityjs');
-jest.mock('~/flash');
+jest.mock('~/alert');
const mockFetchData = jest.fn();
jest.mock('~/projects/tree/services/commit_pipeline_service', () =>
@@ -41,11 +41,6 @@ describe('Commit pipeline status component', () => {
const findLink = () => wrapper.find('a');
const findCiIcon = () => findLink().findComponent(CiIcon);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('Visibility management', () => {
describe('when component is hidden', () => {
beforeEach(() => {
@@ -169,7 +164,7 @@ describe('Commit pipeline status component', () => {
});
});
- it('displays flash error message', () => {
+ it('displays alert error message', () => {
expect(createAlert).toHaveBeenCalled();
});
});
diff --git a/spec/frontend/commit/components/commit_box_pipeline_status_spec.js b/spec/frontend/commit/components/commit_box_pipeline_status_spec.js
index 8d455f8a3d7..9c7a41b3506 100644
--- a/spec/frontend/commit/components/commit_box_pipeline_status_spec.js
+++ b/spec/frontend/commit/components/commit_box_pipeline_status_spec.js
@@ -4,7 +4,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import CommitBoxPipelineStatus from '~/projects/commit_box/info/components/commit_box_pipeline_status.vue';
import {
@@ -23,7 +23,7 @@ const mockProvide = {
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Commit box pipeline status', () => {
let wrapper;
@@ -54,10 +54,6 @@ describe('Commit box pipeline status', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('loading state', () => {
it('should display loading state when loading', () => {
createComponent();
diff --git a/spec/frontend/commit/components/signature_badge_spec.js b/spec/frontend/commit/components/signature_badge_spec.js
new file mode 100644
index 00000000000..d52ad2b43e2
--- /dev/null
+++ b/spec/frontend/commit/components/signature_badge_spec.js
@@ -0,0 +1,134 @@
+import { GlBadge, GlLink, GlPopover } from '@gitlab/ui';
+import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component';
+import SignatureBadge from '~/commit/components/signature_badge.vue';
+import X509CertificateDetails from '~/commit/components/x509_certificate_details.vue';
+import { typeConfig, statusConfig, verificationStatuses, signatureTypes } from '~/commit/constants';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { sshSignatureProp, gpgSignatureProp, x509SignatureProp } from '../mock_data';
+
+describe('Commit signature', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = mountExtended(SignatureBadge, {
+ propsData: {
+ signature: {
+ ...props,
+ },
+ stubs: {
+ GlBadge,
+ GlLink,
+ X509CertificateDetails,
+ GlPopover: stubComponent(GlPopover, { template: RENDER_ALL_SLOTS_TEMPLATE }),
+ },
+ },
+ });
+ };
+
+ const signatureBadge = () => wrapper.findComponent(GlBadge);
+ const signaturePopover = () => wrapper.findComponent(GlPopover);
+ const signatureDescription = () => wrapper.findByTestId('signature-description');
+ const signatureKeyLabel = () => wrapper.findByTestId('signature-key-label');
+ const signatureKey = () => wrapper.findByTestId('signature-key');
+ const helpLink = () => wrapper.findComponent(GlLink);
+ const X509CertificateDetailsComponents = () => wrapper.findAllComponents(X509CertificateDetails);
+
+ describe.each`
+ signatureType | verificationStatus
+ ${signatureTypes.GPG} | ${verificationStatuses.VERIFIED}
+ ${signatureTypes.GPG} | ${verificationStatuses.UNVERIFIED}
+ ${signatureTypes.GPG} | ${verificationStatuses.UNVERIFIED_KEY}
+ ${signatureTypes.GPG} | ${verificationStatuses.UNKNOWN_KEY}
+ ${signatureTypes.GPG} | ${verificationStatuses.OTHER_USER}
+ ${signatureTypes.GPG} | ${verificationStatuses.SAME_USER_DIFFERENT_EMAIL}
+ ${signatureTypes.GPG} | ${verificationStatuses.MULTIPLE_SIGNATURES}
+ ${signatureTypes.X509} | ${verificationStatuses.VERIFIED}
+ ${signatureTypes.SSH} | ${verificationStatuses.VERIFIED}
+ ${signatureTypes.SSH} | ${verificationStatuses.REVOKED_KEY}
+ `(
+ 'For a specified `$signatureType` and `$verificationStatus` it renders component correctly',
+ ({ signatureType, verificationStatus }) => {
+ beforeEach(() => {
+ createComponent({ __typename: signatureType, verificationStatus });
+ });
+ it('renders correct badge class', () => {
+ expect(signatureBadge().props('variant')).toBe(statusConfig[verificationStatus].variant);
+ });
+ it('renders badge text', () => {
+ expect(signatureBadge().text()).toBe(statusConfig[verificationStatus].label);
+ });
+ it('renders popover header text', () => {
+ expect(signaturePopover().text()).toMatch(statusConfig[verificationStatus].title);
+ });
+ it('renders signature description', () => {
+ expect(signatureDescription().text()).toBe(statusConfig[verificationStatus].description);
+ });
+ it('renders help link with correct path', () => {
+ expect(helpLink().text()).toBe(typeConfig[signatureType].helpLink.label);
+ expect(helpLink().attributes('href')).toBe(
+ helpPagePath(typeConfig[signatureType].helpLink.path),
+ );
+ });
+ },
+ );
+
+ describe('SSH signature', () => {
+ beforeEach(() => {
+ createComponent(sshSignatureProp);
+ });
+
+ it('renders key label', () => {
+ expect(signatureKeyLabel().text()).toMatch(typeConfig[signatureTypes.SSH].keyLabel);
+ });
+
+ it('renders key signature', () => {
+ expect(signatureKey().text()).toBe(sshSignatureProp.keyFingerprintSha256);
+ });
+ });
+
+ describe('GPG signature', () => {
+ beforeEach(() => {
+ createComponent(gpgSignatureProp);
+ });
+
+ it('renders key label', () => {
+ expect(signatureKeyLabel().text()).toMatch(typeConfig[signatureTypes.GPG].keyLabel);
+ });
+
+ it('renders key signature for GGP signature', () => {
+ expect(signatureKey().text()).toBe(gpgSignatureProp.gpgKeyPrimaryKeyid);
+ });
+ });
+
+ describe('X509 signature', () => {
+ beforeEach(() => {
+ createComponent(x509SignatureProp);
+ });
+
+ it('does not render key label', () => {
+ expect(signatureKeyLabel().exists()).toBe(false);
+ });
+
+ it('renders X509 certificate details components', () => {
+ expect(X509CertificateDetailsComponents()).toHaveLength(2);
+ });
+
+ it('passes correct props', () => {
+ expect(X509CertificateDetailsComponents().at(0).props()).toStrictEqual({
+ subject: x509SignatureProp.x509Certificate.subject,
+ title: typeConfig[signatureTypes.X509].subjectTitle,
+ subjectKeyIdentifier: wrapper.vm.getSubjectKeyIdentifierToDisplay(
+ x509SignatureProp.x509Certificate.subjectKeyIdentifier,
+ ),
+ });
+ expect(X509CertificateDetailsComponents().at(1).props()).toStrictEqual({
+ subject: x509SignatureProp.x509Certificate.x509Issuer.subject,
+ title: typeConfig[signatureTypes.X509].issuerTitle,
+ subjectKeyIdentifier: wrapper.vm.getSubjectKeyIdentifierToDisplay(
+ x509SignatureProp.x509Certificate.x509Issuer.subjectKeyIdentifier,
+ ),
+ });
+ });
+ });
+});
diff --git a/spec/frontend/commit/components/x509_certificate_details_spec.js b/spec/frontend/commit/components/x509_certificate_details_spec.js
new file mode 100644
index 00000000000..5d9398b572b
--- /dev/null
+++ b/spec/frontend/commit/components/x509_certificate_details_spec.js
@@ -0,0 +1,36 @@
+import { shallowMount } from '@vue/test-utils';
+import X509CertificateDetails from '~/commit/components/x509_certificate_details.vue';
+import { X509_CERTIFICATE_KEY_IDENTIFIER_TITLE } from '~/commit/constants';
+import { x509CertificateDetailsProp } from '../mock_data';
+
+describe('X509 certificate details', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = shallowMount(X509CertificateDetails, {
+ propsData: x509CertificateDetailsProp,
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ const findTitle = () => wrapper.find('strong');
+ const findSubjectValues = () => wrapper.findAll("[data-testid='subject-value']");
+ const findKeyIdentifier = () => wrapper.find("[data-testid='key-identifier']");
+
+ it('renders a title', () => {
+ expect(findTitle().text()).toBe(x509CertificateDetailsProp.title);
+ });
+
+ it('renders subject values', () => {
+ expect(findSubjectValues()).toHaveLength(3);
+ });
+
+ it('renders key identifier', () => {
+ expect(findKeyIdentifier().text()).toBe(
+ `${X509_CERTIFICATE_KEY_IDENTIFIER_TITLE} ${x509CertificateDetailsProp.subjectKeyIdentifier}`,
+ );
+ });
+});
diff --git a/spec/frontend/commit/mock_data.js b/spec/frontend/commit/mock_data.js
index a13ef9c563e..3b6971d9607 100644
--- a/spec/frontend/commit/mock_data.js
+++ b/spec/frontend/commit/mock_data.js
@@ -201,3 +201,34 @@ export const mockUpstreamQueryResponse = {
},
},
};
+
+export const sshSignatureProp = {
+ __typename: 'SshSignature',
+ verificationStatus: 'VERIFIED',
+ keyFingerprintSha256: 'xxx',
+};
+
+export const gpgSignatureProp = {
+ __typename: 'GpgSignature',
+ verificationStatus: 'VERIFIED',
+ gpgKeyPrimaryKeyid: 'yyy',
+};
+
+export const x509SignatureProp = {
+ __typename: 'X509Signature',
+ verificationStatus: 'VERIFIED',
+ x509Certificate: {
+ subject: 'CN=gitlab@example.org,OU=Example,O=World',
+ subjectKeyIdentifier: 'BC:BC:BC:BC:BC:BC:BC:BC',
+ x509Issuer: {
+ subject: 'CN=PKI,OU=Example,O=World',
+ subjectKeyIdentifier: 'AB:AB:AB:AB:AB:AB:AB:AB:',
+ },
+ },
+};
+
+export const x509CertificateDetailsProp = {
+ title: 'Title',
+ subject: 'CN=gitlab@example.org,OU=Example,O=World',
+ subjectKeyIdentifier: 'BC BC BC BC BC BC BC BC',
+};
diff --git a/spec/frontend/commit/pipelines/pipelines_table_spec.js b/spec/frontend/commit/pipelines/pipelines_table_spec.js
index 4bffb6a0fd3..009ec68ddcf 100644
--- a/spec/frontend/commit/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/commit/pipelines/pipelines_table_spec.js
@@ -4,6 +4,7 @@ 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';
@@ -13,7 +14,7 @@ import {
HTTP_STATUS_OK,
HTTP_STATUS_UNAUTHORIZED,
} from '~/lib/utils/http_status';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TOAST_MESSAGE } from '~/pipelines/constants';
import axios from '~/lib/utils/axios_utils';
@@ -21,12 +22,13 @@ const $toast = {
show: jest.fn(),
};
-jest.mock('~/flash');
+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');
@@ -38,7 +40,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
const findModal = () => wrapper.findComponent(GlModal);
const findMrPipelinesDocsLink = () => wrapper.findByTestId('mr-pipelines-docs-link');
- const createComponent = (props = {}) => {
+ const createComponent = ({ props = {} } = {}) => {
wrapper = extendedWrapper(
mount(PipelinesTable, {
propsData: {
@@ -50,6 +52,12 @@ describe('Pipelines table in Commits and Merge requests', () => {
mocks: {
$toast,
},
+ stubs: {
+ GlModal: stubComponent(GlModal, {
+ template: '<div />',
+ methods: { show: showMock },
+ }),
+ },
}),
);
};
@@ -62,11 +70,6 @@ describe('Pipelines table in Commits and Merge requests', () => {
pipeline = pipelines.find((p) => p.user !== null && p.commit !== null);
});
- afterEach(() => {
- wrapper.destroy();
- mock.restore();
- });
-
describe('successful request', () => {
describe('without pipelines', () => {
beforeEach(async () => {
@@ -95,6 +98,35 @@ describe('Pipelines table in Commits and Merge requests', () => {
});
});
+ 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 });
@@ -111,32 +143,6 @@ describe('Pipelines table in Commits and Merge requests', () => {
expect(findErrorEmptyState().exists()).toBe(false);
});
- describe('with pagination', () => {
- it('should make an API request when using pagination', async () => {
- jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- await wrapper.setData({
- store: {
- state: {
- pageInfo: {
- page: 1,
- total: 10,
- perPage: 2,
- nextPage: 2,
- totalPages: 5,
- },
- },
- },
- });
-
- wrapper.find('.next-page-item').trigger('click');
-
- expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ page: '2' });
- });
- });
-
describe('pipeline badge counts', () => {
it('should receive update-pipelines-count event', () => {
const element = document.createElement('div');
@@ -203,16 +209,18 @@ describe('Pipelines table in Commits and Merge requests', () => {
mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
createComponent({
- canRunPipeline: true,
- projectId: '5',
- mergeRequestId: 3,
+ props: {
+ canRunPipeline: true,
+ projectId: '5',
+ mergeRequestId: 3,
+ },
});
await waitForPromises();
});
describe('success', () => {
beforeEach(() => {
- jest.spyOn(Api, 'postMergeRequestPipeline').mockReturnValue(Promise.resolve());
+ jest.spyOn(Api, 'postMergeRequestPipeline').mockResolvedValue();
});
it('displays a toast message during pipeline creation', async () => {
await findRunPipelineBtn().trigger('click');
@@ -255,9 +263,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
`('displays permissions error message', async ({ status, message }) => {
const response = { response: { status } };
- jest
- .spyOn(Api, 'postMergeRequestPipeline')
- .mockImplementation(() => Promise.reject(response));
+ jest.spyOn(Api, 'postMergeRequestPipeline').mockRejectedValue(response);
await findRunPipelineBtn().trigger('click');
@@ -281,14 +287,16 @@ describe('Pipelines table in Commits and Merge requests', () => {
mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
createComponent({
- projectId: '5',
- mergeRequestId: 3,
- canCreatePipelineInTargetProject: true,
- sourceProjectFullPath: 'test/parent-project',
- targetProjectFullPath: 'test/fork-project',
+ props: {
+ projectId: '5',
+ mergeRequestId: 3,
+ canCreatePipelineInTargetProject: true,
+ sourceProjectFullPath: 'test/parent-project',
+ targetProjectFullPath: 'test/fork-project',
+ },
});
- jest.spyOn(Api, 'postMergeRequestPipeline').mockReturnValue(Promise.resolve());
+ jest.spyOn(Api, 'postMergeRequestPipeline').mockResolvedValue();
await waitForPromises();
});
@@ -313,15 +321,15 @@ describe('Pipelines table in Commits and Merge requests', () => {
mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, []);
createComponent({
- projectId: '5',
- mergeRequestId: 3,
- canCreatePipelineInTargetProject: true,
- sourceProjectFullPath: 'test/parent-project',
- targetProjectFullPath: 'test/fork-project',
+ props: {
+ projectId: '5',
+ mergeRequestId: 3,
+ canCreatePipelineInTargetProject: true,
+ sourceProjectFullPath: 'test/parent-project',
+ targetProjectFullPath: 'test/fork-project',
+ },
});
- jest.spyOn(findModal().vm, 'show').mockReturnValue();
-
await waitForPromises();
});
@@ -331,7 +339,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
findRunPipelineBtn().trigger('click');
- expect(findModal().vm.show).toHaveBeenCalled();
+ expect(showMock).toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/confidential_merge_request/components/project_form_group_spec.js b/spec/frontend/confidential_merge_request/components/project_form_group_spec.js
index d6f16f1a644..a7ae07a36d9 100644
--- a/spec/frontend/confidential_merge_request/components/project_form_group_spec.js
+++ b/spec/frontend/confidential_merge_request/components/project_form_group_spec.js
@@ -46,7 +46,6 @@ function factory(projects = mockData) {
describe('Confidential merge request project form group component', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
it('renders fork dropdown', async () => {
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 a63cca006da..b8e6bcbc3c4 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,7 +1,7 @@
// 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=\\"md\\" variant=\\"default\\" type=\\"button\\" tag=\\"button\\" aria-label=\\"Bold\\" title=\\"Bold\\" class=\\"gl-button btn-default-tertiary btn-icon\\">
+"<b-button-stub size=\\"md\\" tag=\\"button\\" type=\\"button\\" variant=\\"default\\" aria-label=\\"Bold\\" title=\\"Bold\\" class=\\"gl-button btn-default-tertiary btn-icon\\">
<!---->
<gl-icon-stub name=\\"bold\\" size=\\"16\\" class=\\"gl-button-icon\\"></gl-icon-stub>
<!---->
diff --git a/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js
index 0700cf5d529..271e63abf21 100644
--- a/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js
@@ -51,10 +51,6 @@ describe('content_editor/components/bubble_menus/bubble_menu', () => {
setupMocks();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('initializes BubbleMenuPlugin', async () => {
createWrapper({});
diff --git a/spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js
index 378b11f4ae9..085a6d3a28d 100644
--- a/spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/code_block_bubble_menu_spec.js
@@ -64,10 +64,6 @@ describe('content_editor/components/bubble_menus/code_block_bubble_menu', () =>
buildWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders bubble menu component', async () => {
tiptapEditor.commands.insertContent(preTag());
bubbleMenu = wrapper.findComponent(BubbleMenu);
diff --git a/spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js
index 98001858851..7bab473529f 100644
--- a/spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js
@@ -37,10 +37,6 @@ describe('content_editor/components/bubble_menus/formatting_bubble_menu', () =>
buildEditor();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders bubble menu component', () => {
buildWrapper();
const bubbleMenu = wrapper.findComponent(BubbleMenu);
diff --git a/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js
index 9aa9c6483f4..eb5a3b61591 100644
--- a/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js
@@ -71,10 +71,6 @@ describe('content_editor/components/bubble_menus/link_bubble_menu', () => {
.run();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders bubble menu component', async () => {
await buildWrapperAndDisplayMenu();
diff --git a/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js
index 13c6495ac41..c918f068c07 100644
--- a/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js
@@ -4,22 +4,28 @@ import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue
import MediaBubbleMenu from '~/content_editor/components/bubble_menus/media_bubble_menu.vue';
import { stubComponent } from 'helpers/stub_component';
import eventHubFactory from '~/helpers/event_hub_factory';
-import Image from '~/content_editor/extensions/image';
import Audio from '~/content_editor/extensions/audio';
+import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
+import Image from '~/content_editor/extensions/image';
import Video from '~/content_editor/extensions/video';
import { createTestEditor, emitEditorEvent, mockChainedCommands } from '../../test_utils';
import {
PROJECT_WIKI_ATTACHMENT_IMAGE_HTML,
PROJECT_WIKI_ATTACHMENT_AUDIO_HTML,
PROJECT_WIKI_ATTACHMENT_VIDEO_HTML,
+ PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML,
} from '../../test_constants';
-const TIPTAP_IMAGE_HTML = `<p>
+const TIPTAP_AUDIO_HTML = `<p>
+ <span class="media-container audio-container"><audio src="https://gitlab.com/favicon.png" controls="true" data-setup="{}" data-title="gitlab favicon"></audio><a href="https://gitlab.com/favicon.png">gitlab favicon</a></span>
+</p>`;
+
+const TIPTAP_DIAGRAM_HTML = `<p>
<img src="https://gitlab.com/favicon.png" alt="gitlab favicon" title="gitlab favicon">
</p>`;
-const TIPTAP_AUDIO_HTML = `<p>
- <span class="media-container audio-container"><audio src="https://gitlab.com/favicon.png" controls="true" data-setup="{}" data-title="gitlab favicon"></audio><a href="https://gitlab.com/favicon.png">gitlab favicon</a></span>
+const TIPTAP_IMAGE_HTML = `<p>
+ <img src="https://gitlab.com/favicon.png" alt="gitlab favicon" title="gitlab favicon">
</p>`;
const TIPTAP_VIDEO_HTML = `<p>
@@ -29,10 +35,11 @@ const TIPTAP_VIDEO_HTML = `<p>
const createFakeEvent = () => ({ preventDefault: jest.fn(), stopPropagation: jest.fn() });
describe.each`
- mediaType | mediaHTML | filePath | mediaOutputHTML
- ${'image'} | ${PROJECT_WIKI_ATTACHMENT_IMAGE_HTML} | ${'test-file.png'} | ${TIPTAP_IMAGE_HTML}
- ${'audio'} | ${PROJECT_WIKI_ATTACHMENT_AUDIO_HTML} | ${'test-file.mp3'} | ${TIPTAP_AUDIO_HTML}
- ${'video'} | ${PROJECT_WIKI_ATTACHMENT_VIDEO_HTML} | ${'test-file.mp4'} | ${TIPTAP_VIDEO_HTML}
+ mediaType | mediaHTML | filePath | mediaOutputHTML
+ ${'image'} | ${PROJECT_WIKI_ATTACHMENT_IMAGE_HTML} | ${'test-file.png'} | ${TIPTAP_IMAGE_HTML}
+ ${'drawio_diagram'} | ${PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML} | ${'test-file.drawio.svg'} | ${TIPTAP_DIAGRAM_HTML}
+ ${'audio'} | ${PROJECT_WIKI_ATTACHMENT_AUDIO_HTML} | ${'test-file.mp3'} | ${TIPTAP_AUDIO_HTML}
+ ${'video'} | ${PROJECT_WIKI_ATTACHMENT_VIDEO_HTML} | ${'test-file.mp4'} | ${TIPTAP_VIDEO_HTML}
`(
'content_editor/components/bubble_menus/media_bubble_menu ($mediaType)',
({ mediaType, mediaHTML, filePath, mediaOutputHTML }) => {
@@ -43,7 +50,7 @@ describe.each`
let eventHub;
const buildEditor = () => {
- tiptapEditor = createTestEditor({ extensions: [Image, Audio, Video] });
+ tiptapEditor = createTestEditor({ extensions: [Image, Audio, Video, DrawioDiagram] });
contentEditor = { resolveUrl: jest.fn() };
eventHub = eventHubFactory();
};
@@ -93,10 +100,6 @@ describe.each`
bubbleMenu = wrapper.findComponent(BubbleMenu);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders bubble menu component', async () => {
expect(bubbleMenu.classes()).toEqual(['gl-shadow', 'gl-rounded-base', 'gl-bg-white']);
});
@@ -114,6 +117,24 @@ describe.each`
expect(link.text()).toBe(filePath);
});
+ describe('when BubbleMenu emits hidden event', () => {
+ it('resets media bubble menu state', async () => {
+ // Switch to edit mode to access component state in form fields
+ await wrapper.findByTestId('edit-media').vm.$emit('click');
+
+ const mediaSrcInput = wrapper.findByTestId('media-src').vm.$el;
+ const mediaAltInput = wrapper.findByTestId('media-alt').vm.$el;
+
+ expect(mediaSrcInput.value).not.toBe('');
+ expect(mediaAltInput.value).not.toBe('');
+
+ await wrapper.findComponent(BubbleMenu).vm.$emit('hidden');
+
+ expect(mediaSrcInput.value).toBe('');
+ expect(mediaAltInput.value).toBe('');
+ });
+ });
+
describe('copy button', () => {
it(`copies the canonical link to the ${mediaType} to clipboard`, async () => {
jest.spyOn(navigator.clipboard, 'writeText');
@@ -133,23 +154,39 @@ describe.each`
});
describe(`replace ${mediaType} button`, () => {
- it('uploads and replaces the selected image when file input changes', async () => {
- const commands = mockChainedCommands(tiptapEditor, [
- 'focus',
- 'deleteSelection',
- 'uploadAttachment',
- 'run',
- ]);
- const file = new File(['foo'], 'foo.png', { type: 'image/png' });
-
- await wrapper.findByTestId('replace-media').vm.$emit('click');
- await selectFile(file);
-
- expect(commands.focus).toHaveBeenCalled();
- expect(commands.deleteSelection).toHaveBeenCalled();
- expect(commands.uploadAttachment).toHaveBeenCalledWith({ file });
- expect(commands.run).toHaveBeenCalled();
- });
+ if (mediaType !== 'drawio_diagram') {
+ it('uploads and replaces the selected image when file input changes', async () => {
+ const commands = mockChainedCommands(tiptapEditor, [
+ 'focus',
+ 'deleteSelection',
+ 'uploadAttachment',
+ 'run',
+ ]);
+ const file = new File(['foo'], 'foo.png', { type: 'image/png' });
+
+ await wrapper.findByTestId('replace-media').vm.$emit('click');
+ await selectFile(file);
+
+ expect(commands.focus).toHaveBeenCalled();
+ expect(commands.deleteSelection).toHaveBeenCalled();
+ expect(commands.uploadAttachment).toHaveBeenCalledWith({ file });
+ expect(commands.run).toHaveBeenCalled();
+ });
+ } else {
+ // draw.io diagrams are replaced using the edit diagram button
+ it('invokes editDiagram command', async () => {
+ const commands = mockChainedCommands(tiptapEditor, [
+ 'focus',
+ 'createOrEditDiagram',
+ 'run',
+ ]);
+ await wrapper.findByTestId('edit-diagram').vm.$emit('click');
+
+ expect(commands.focus).toHaveBeenCalled();
+ expect(commands.createOrEditDiagram).toHaveBeenCalled();
+ expect(commands.run).toHaveBeenCalled();
+ });
+ }
});
describe('edit button', () => {
diff --git a/spec/frontend/content_editor/components/content_editor_alert_spec.js b/spec/frontend/content_editor/components/content_editor_alert_spec.js
index ee9ead8f8a7..e62e2331d25 100644
--- a/spec/frontend/content_editor/components/content_editor_alert_spec.js
+++ b/spec/frontend/content_editor/components/content_editor_alert_spec.js
@@ -29,10 +29,6 @@ describe('content_editor/components/content_editor_alert', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
variant | message
${'danger'} | ${'An error occurred'}
diff --git a/spec/frontend/content_editor/components/content_editor_spec.js b/spec/frontend/content_editor/components/content_editor_spec.js
index 1a3cd36a8bb..b642ac9c46b 100644
--- a/spec/frontend/content_editor/components/content_editor_spec.js
+++ b/spec/frontend/content_editor/components/content_editor_spec.js
@@ -1,7 +1,8 @@
-import { GlAlert } from '@gitlab/ui';
+import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
import { EditorContent, Editor } from '@tiptap/vue-2';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import EditorModeDropdown from '~/vue_shared/components/markdown/editor_mode_dropdown.vue';
import ContentEditor from '~/content_editor/components/content_editor.vue';
import ContentEditorAlert from '~/content_editor/components/content_editor_alert.vue';
import ContentEditorProvider from '~/content_editor/components/content_editor_provider.vue';
@@ -27,19 +28,23 @@ describe('ContentEditor', () => {
const findEditorStateObserver = () => wrapper.findComponent(EditorStateObserver);
const findLoadingIndicator = () => wrapper.findComponent(LoadingIndicator);
const findContentEditorAlert = () => wrapper.findComponent(ContentEditorAlert);
- const createWrapper = ({ markdown, autofocus, useBottomToolbar } = {}) => {
+ const createWrapper = ({ markdown, autofocus, ...props } = {}) => {
wrapper = shallowMountExtended(ContentEditor, {
propsData: {
renderMarkdown,
uploadsPath,
markdown,
autofocus,
- useBottomToolbar,
+ placeholder: 'Enter some text here...',
+ ...props,
},
stubs: {
EditorStateObserver,
ContentEditorProvider,
ContentEditorAlert,
+ GlLink,
+ GlSprintf,
+ EditorModeDropdown,
},
});
};
@@ -48,10 +53,6 @@ describe('ContentEditor', () => {
renderMarkdown = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('triggers initialized event', () => {
createWrapper();
@@ -87,22 +88,29 @@ describe('ContentEditor', () => {
expect(wrapper.findComponent(ContentEditorProvider).exists()).toBe(true);
});
- it('renders top toolbar component', () => {
+ it('renders toolbar component', () => {
createWrapper();
expect(wrapper.findComponent(FormattingToolbar).exists()).toBe(true);
- expect(wrapper.findComponent(FormattingToolbar).classes('gl-border-t')).toBe(false);
- expect(wrapper.findComponent(FormattingToolbar).classes('gl-border-b')).toBe(true);
});
- it('renders bottom toolbar component', () => {
- createWrapper({
- useBottomToolbar: true,
- });
+ it('renders footer containing quick actions help text if quick actions docs path is defined', () => {
+ createWrapper({ quickActionsDocsPath: '/foo/bar' });
- expect(wrapper.findComponent(FormattingToolbar).exists()).toBe(true);
- expect(wrapper.findComponent(FormattingToolbar).classes('gl-border-t')).toBe(true);
- expect(wrapper.findComponent(FormattingToolbar).classes('gl-border-b')).toBe(false);
+ expect(findEditorElement().text()).toContain('For quick actions, type /');
+ expect(wrapper.findComponent(GlLink).attributes('href')).toBe('/foo/bar');
+ });
+
+ it('does not render footer containing quick actions help text if quick actions docs path is not defined', () => {
+ createWrapper();
+
+ expect(findEditorElement().text()).not.toContain('For quick actions, type /');
+ });
+
+ it('renders an editor mode dropdown', () => {
+ createWrapper();
+
+ expect(wrapper.findComponent(EditorModeDropdown).exists()).toBe(true);
});
describe('when setting initial content', () => {
@@ -124,9 +132,9 @@ describe('ContentEditor', () => {
describe('succeeds', () => {
beforeEach(async () => {
- renderMarkdown.mockResolvedValueOnce('hello world');
+ renderMarkdown.mockResolvedValueOnce('');
- createWrapper({ markddown: 'hello world' });
+ createWrapper({ markddown: '' });
await nextTick();
});
@@ -138,13 +146,17 @@ describe('ContentEditor', () => {
it('emits loadingSuccess event', () => {
expect(wrapper.emitted('loadingSuccess')).toHaveLength(1);
});
+
+ it('shows placeholder text', () => {
+ expect(wrapper.text()).toContain('Enter some text here...');
+ });
});
describe('fails', () => {
beforeEach(async () => {
renderMarkdown.mockRejectedValueOnce(new Error());
- createWrapper({ markddown: 'hello world' });
+ createWrapper({ markdown: 'hello world' });
await nextTick();
});
@@ -209,11 +221,17 @@ describe('ContentEditor', () => {
expect(findEditorElement().classes()).not.toContain('is-focused');
});
+
+ it('hides placeholder text', () => {
+ expect(wrapper.text()).not.toContain('Enter some text here...');
+ });
});
describe('when editorStateObserver emits docUpdate event', () => {
- it('emits change event with the latest markdown', async () => {
- const markdown = 'Loaded content';
+ let markdown;
+
+ beforeEach(async () => {
+ markdown = 'Loaded content';
renderMarkdown.mockResolvedValueOnce(markdown);
@@ -223,7 +241,9 @@ describe('ContentEditor', () => {
await waitForPromises();
findEditorStateObserver().vm.$emit('docUpdate');
+ });
+ it('emits change event with the latest markdown', () => {
expect(wrapper.emitted('change')).toEqual([
[
{
@@ -234,6 +254,10 @@ describe('ContentEditor', () => {
],
]);
});
+
+ it('hides the placeholder text', () => {
+ expect(wrapper.text()).not.toContain('Enter some text here...');
+ });
});
describe('when editorStateObserver emits keydown event', () => {
diff --git a/spec/frontend/content_editor/components/editor_state_observer_spec.js b/spec/frontend/content_editor/components/editor_state_observer_spec.js
index 9b42f61c98c..80fb20e5258 100644
--- a/spec/frontend/content_editor/components/editor_state_observer_spec.js
+++ b/spec/frontend/content_editor/components/editor_state_observer_spec.js
@@ -45,10 +45,6 @@ describe('content_editor/components/editor_state_observer', () => {
buildEditor();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when editor content changes', () => {
it('emits update, selectionUpdate, and transaction events', () => {
const content = '<p>My paragraph</p>';
diff --git a/spec/frontend/content_editor/components/formatting_toolbar_spec.js b/spec/frontend/content_editor/components/formatting_toolbar_spec.js
index c4bf21ba813..4a7b7cedf19 100644
--- a/spec/frontend/content_editor/components/formatting_toolbar_spec.js
+++ b/spec/frontend/content_editor/components/formatting_toolbar_spec.js
@@ -1,3 +1,4 @@
+import { GlTabs, GlTab } from '@gitlab/ui';
import { mockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import FormattingToolbar from '~/content_editor/components/formatting_toolbar.vue';
@@ -6,22 +7,23 @@ import {
CONTENT_EDITOR_TRACKING_LABEL,
} from '~/content_editor/constants';
-describe('content_editor/components/top_toolbar', () => {
+describe('content_editor/components/formatting_toolbar', () => {
let wrapper;
let trackingSpy;
const buildWrapper = () => {
- wrapper = shallowMountExtended(FormattingToolbar);
+ wrapper = shallowMountExtended(FormattingToolbar, {
+ stubs: {
+ GlTabs,
+ GlTab,
+ },
+ });
};
beforeEach(() => {
trackingSpy = mockTracking(undefined, null, jest.spyOn);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
testId | controlProps
${'text-styles'} | ${{}}
diff --git a/spec/frontend/content_editor/components/loading_indicator_spec.js b/spec/frontend/content_editor/components/loading_indicator_spec.js
index 0065103d01b..1b0ffaee6c6 100644
--- a/spec/frontend/content_editor/components/loading_indicator_spec.js
+++ b/spec/frontend/content_editor/components/loading_indicator_spec.js
@@ -11,10 +11,6 @@ describe('content_editor/components/loading_indicator', () => {
wrapper = shallowMountExtended(LoadingIndicator);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when loading content', () => {
beforeEach(() => {
createWrapper();
diff --git a/spec/frontend/content_editor/components/toolbar_button_spec.js b/spec/frontend/content_editor/components/toolbar_button_spec.js
index 1f1f7b338c6..1556f761682 100644
--- a/spec/frontend/content_editor/components/toolbar_button_spec.js
+++ b/spec/frontend/content_editor/components/toolbar_button_spec.js
@@ -42,10 +42,6 @@ describe('content_editor/components/toolbar_button', () => {
buildEditor();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays tertiary, medium button with a provided label and icon', () => {
buildWrapper();
diff --git a/spec/frontend/content_editor/components/toolbar_image_button_spec.js b/spec/frontend/content_editor/components/toolbar_image_button_spec.js
index 5473d43f5a1..0ec950137fc 100644
--- a/spec/frontend/content_editor/components/toolbar_image_button_spec.js
+++ b/spec/frontend/content_editor/components/toolbar_image_button_spec.js
@@ -50,7 +50,6 @@ describe('content_editor/components/toolbar_image_button', () => {
afterEach(() => {
editor.destroy();
- wrapper.destroy();
});
it('sets the image to the value in the URL input when "Insert" button is clicked', async () => {
diff --git a/spec/frontend/content_editor/components/toolbar_link_button_spec.js b/spec/frontend/content_editor/components/toolbar_link_button_spec.js
index 40e859e96af..80090c0278f 100644
--- a/spec/frontend/content_editor/components/toolbar_link_button_spec.js
+++ b/spec/frontend/content_editor/components/toolbar_link_button_spec.js
@@ -43,7 +43,6 @@ describe('content_editor/components/toolbar_link_button', () => {
afterEach(() => {
editor.destroy();
- wrapper.destroy();
});
it('renders dropdown component', () => {
diff --git a/spec/frontend/content_editor/components/toolbar_more_dropdown_spec.js b/spec/frontend/content_editor/components/toolbar_more_dropdown_spec.js
index d4fc47601cf..5af4784f358 100644
--- a/spec/frontend/content_editor/components/toolbar_more_dropdown_spec.js
+++ b/spec/frontend/content_editor/components/toolbar_more_dropdown_spec.js
@@ -9,12 +9,14 @@ import { createTestEditor, mockChainedCommands, emitEditorEvent } from '../test_
describe('content_editor/components/toolbar_more_dropdown', () => {
let wrapper;
let tiptapEditor;
+ let contentEditor;
let eventHub;
const buildEditor = () => {
tiptapEditor = createTestEditor({
extensions: [Diagram, HorizontalRule],
});
+ contentEditor = { drawioEnabled: true };
eventHub = eventHubFactory();
};
@@ -22,6 +24,7 @@ describe('content_editor/components/toolbar_more_dropdown', () => {
wrapper = mountExtended(ToolbarMoreDropdown, {
provide: {
tiptapEditor,
+ contentEditor,
eventHub,
},
propsData,
@@ -32,29 +35,27 @@ describe('content_editor/components/toolbar_more_dropdown', () => {
beforeEach(() => {
buildEditor();
- buildWrapper();
- });
-
- afterEach(() => {
- wrapper.destroy();
});
describe.each`
- name | contentType | command | params
- ${'Code block'} | ${'codeBlock'} | ${'setNode'} | ${['codeBlock']}
- ${'Details block'} | ${'details'} | ${'toggleList'} | ${['details', 'detailsContent']}
- ${'Bullet list'} | ${'bulletList'} | ${'toggleList'} | ${['bulletList', 'listItem']}
- ${'Ordered list'} | ${'orderedList'} | ${'toggleList'} | ${['orderedList', 'listItem']}
- ${'Task list'} | ${'taskList'} | ${'toggleList'} | ${['taskList', 'taskItem']}
- ${'Mermaid diagram'} | ${'diagram'} | ${'setNode'} | ${['diagram', { language: 'mermaid' }]}
- ${'PlantUML diagram'} | ${'diagram'} | ${'setNode'} | ${['diagram', { language: 'plantuml' }]}
- ${'Table of contents'} | ${'tableOfContents'} | ${'insertTableOfContents'} | ${[]}
- ${'Horizontal rule'} | ${'horizontalRule'} | ${'setHorizontalRule'} | ${[]}
+ name | contentType | command | params
+ ${'Code block'} | ${'codeBlock'} | ${'setNode'} | ${['codeBlock']}
+ ${'Details block'} | ${'details'} | ${'toggleList'} | ${['details', 'detailsContent']}
+ ${'Bullet list'} | ${'bulletList'} | ${'toggleList'} | ${['bulletList', 'listItem']}
+ ${'Ordered list'} | ${'orderedList'} | ${'toggleList'} | ${['orderedList', 'listItem']}
+ ${'Task list'} | ${'taskList'} | ${'toggleList'} | ${['taskList', 'taskItem']}
+ ${'Mermaid diagram'} | ${'diagram'} | ${'setNode'} | ${['diagram', { language: 'mermaid' }]}
+ ${'PlantUML diagram'} | ${'diagram'} | ${'setNode'} | ${['diagram', { language: 'plantuml' }]}
+ ${'Table of contents'} | ${'tableOfContents'} | ${'insertTableOfContents'} | ${[]}
+ ${'Horizontal rule'} | ${'horizontalRule'} | ${'setHorizontalRule'} | ${[]}
+ ${'Create or edit diagram'} | ${'drawioDiagram'} | ${'createOrEditDiagram'} | ${[]}
`('when option $name is clicked', ({ name, command, contentType, params }) => {
let commands;
let btn;
beforeEach(async () => {
+ buildWrapper();
+
commands = mockChainedCommands(tiptapEditor, [command, 'focus', 'run']);
btn = wrapper.findByRole('button', { name });
});
@@ -71,8 +72,17 @@ describe('content_editor/components/toolbar_more_dropdown', () => {
});
});
+ it('does not show drawio option when drawio is disabled', () => {
+ contentEditor.drawioEnabled = false;
+ buildWrapper();
+
+ expect(wrapper.findByRole('button', { name: 'Create or edit diagram' }).exists()).toBe(false);
+ });
+
describe('a11y tests', () => {
it('sets toggleText and text-sr-only properties to the table button dropdown', () => {
+ buildWrapper();
+
expect(findDropdown().props()).toMatchObject({
textSrOnly: true,
toggleText: 'More options',
diff --git a/spec/frontend/content_editor/components/toolbar_table_button_spec.js b/spec/frontend/content_editor/components/toolbar_table_button_spec.js
index aa4604661e5..35741971488 100644
--- a/spec/frontend/content_editor/components/toolbar_table_button_spec.js
+++ b/spec/frontend/content_editor/components/toolbar_table_button_spec.js
@@ -30,7 +30,6 @@ describe('content_editor/components/toolbar_table_button', () => {
afterEach(() => {
editor.destroy();
- wrapper.destroy();
});
it('renders a grid of 5x5 buttons to create a table', () => {
diff --git a/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js b/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js
index 5a725ac1ca4..31ed13541e6 100644
--- a/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js
+++ b/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js
@@ -39,10 +39,6 @@ describe('content_editor/components/toolbar_text_style_dropdown', () => {
buildEditor();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders all text styles as dropdown items', () => {
buildWrapper();
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 a5ef19fb8e8..057e50cd0e2 100644
--- a/spec/frontend/content_editor/components/wrappers/code_block_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/code_block_spec.js
@@ -55,10 +55,6 @@ describe('content/components/wrappers/code_block', () => {
codeBlockLanguageLoader.findOrCreateLanguageBySyntax.mockReturnValue({ syntax: language });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a node-view-wrapper as a pre element', () => {
createWrapper();
diff --git a/spec/frontend/content_editor/components/wrappers/details_spec.js b/spec/frontend/content_editor/components/wrappers/details_spec.js
index d746b9fa2f1..232c1e9aede 100644
--- a/spec/frontend/content_editor/components/wrappers/details_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/details_spec.js
@@ -13,10 +13,6 @@ describe('content/components/wrappers/details', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a node-view-content as a ul element', () => {
createWrapper();
diff --git a/spec/frontend/content_editor/components/wrappers/footnote_definition_spec.js b/spec/frontend/content_editor/components/wrappers/footnote_definition_spec.js
index 1ff750eb2ac..91c6799478e 100644
--- a/spec/frontend/content_editor/components/wrappers/footnote_definition_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/footnote_definition_spec.js
@@ -12,10 +12,6 @@ describe('content/components/wrappers/footnote_definition', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders footnote label as a readyonly element', () => {
const label = 'footnote';
diff --git a/spec/frontend/content_editor/components/wrappers/label_spec.js b/spec/frontend/content_editor/components/wrappers/label_spec.js
index 9e58669b0ea..fa32b746142 100644
--- a/spec/frontend/content_editor/components/wrappers/label_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/label_spec.js
@@ -11,10 +11,6 @@ describe('content/components/wrappers/label', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it("renders a GlLabel with the node's text and color", () => {
createWrapper({ attrs: { color: '#ff0000', text: 'foo bar', originalText: '~"foo bar"' } });
diff --git a/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js b/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js
index 1fdddce3962..d8f34565705 100644
--- a/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js
@@ -1,12 +1,12 @@
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { NodeViewWrapper } from '@tiptap/vue-2';
-import { selectedRect as getSelectedRect } from '@_ueberdosis/prosemirror-tables';
+import { selectedRect as getSelectedRect } from '@tiptap/pm/tables';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import TableCellBaseWrapper from '~/content_editor/components/wrappers/table_cell_base.vue';
import { createTestEditor, mockChainedCommands, emitEditorEvent } from '../../test_utils';
-jest.mock('@_ueberdosis/prosemirror-tables');
+jest.mock('@tiptap/pm/tables');
describe('content/components/wrappers/table_cell_base', () => {
let wrapper;
@@ -52,10 +52,6 @@ describe('content/components/wrappers/table_cell_base', () => {
editor = createTestEditor({});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a td node-view-wrapper with relative position', () => {
createWrapper();
expect(wrapper.findComponent(NodeViewWrapper).classes()).toContain('gl-relative');
diff --git a/spec/frontend/content_editor/components/wrappers/table_cell_body_spec.js b/spec/frontend/content_editor/components/wrappers/table_cell_body_spec.js
index 2aefbc77545..506f442bcc7 100644
--- a/spec/frontend/content_editor/components/wrappers/table_cell_body_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/table_cell_body_spec.js
@@ -22,10 +22,6 @@ describe('content/components/wrappers/table_cell_body', () => {
editor = createTestEditor({});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a TableCellBase component', () => {
createWrapper();
expect(wrapper.findComponent(TableCellBaseWrapper).props()).toEqual({
diff --git a/spec/frontend/content_editor/components/wrappers/table_cell_header_spec.js b/spec/frontend/content_editor/components/wrappers/table_cell_header_spec.js
index e48df8734a6..bebe7fb4124 100644
--- a/spec/frontend/content_editor/components/wrappers/table_cell_header_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/table_cell_header_spec.js
@@ -22,10 +22,6 @@ describe('content/components/wrappers/table_cell_header', () => {
editor = createTestEditor({});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a TableCellBase component', () => {
createWrapper();
expect(wrapper.findComponent(TableCellBaseWrapper).props()).toEqual({
diff --git a/spec/frontend/content_editor/components/wrappers/table_of_contents_spec.js b/spec/frontend/content_editor/components/wrappers/table_of_contents_spec.js
index bfda89a8b09..4d5911dda0c 100644
--- a/spec/frontend/content_editor/components/wrappers/table_of_contents_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/table_of_contents_spec.js
@@ -70,10 +70,6 @@ describe('content/components/wrappers/table_of_contents', () => {
await nextTick();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a node-view-wrapper as a ul element', () => {
expect(wrapper.findComponent(NodeViewWrapper).props().as).toBe('ul');
});
diff --git a/spec/frontend/content_editor/extensions/attachment_spec.js b/spec/frontend/content_editor/extensions/attachment_spec.js
index 6b804b3b4c6..24b75ba6805 100644
--- a/spec/frontend/content_editor/extensions/attachment_spec.js
+++ b/spec/frontend/content_editor/extensions/attachment_spec.js
@@ -2,12 +2,13 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
import Attachment from '~/content_editor/extensions/attachment';
+import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
import Image from '~/content_editor/extensions/image';
import Audio from '~/content_editor/extensions/audio';
import Video from '~/content_editor/extensions/video';
import Link from '~/content_editor/extensions/link';
import Loading from '~/content_editor/extensions/loading';
-import { VARIANT_DANGER } from '~/flash';
+import { VARIANT_DANGER } from '~/alert';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import eventHubFactory from '~/helpers/event_hub_factory';
import { createTestEditor, createDocBuilder } from '../test_utils';
@@ -16,6 +17,7 @@ import {
PROJECT_WIKI_ATTACHMENT_AUDIO_HTML,
PROJECT_WIKI_ATTACHMENT_VIDEO_HTML,
PROJECT_WIKI_ATTACHMENT_LINK_HTML,
+ PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML,
} from '../test_constants';
describe('content_editor/extensions/attachment', () => {
@@ -24,6 +26,7 @@ describe('content_editor/extensions/attachment', () => {
let p;
let image;
let audio;
+ let drawioDiagram;
let video;
let loading;
let link;
@@ -35,6 +38,7 @@ describe('content_editor/extensions/attachment', () => {
const imageFile = new File(['foo'], 'test-file.png', { type: 'image/png' });
const audioFile = new File(['foo'], 'test-file.mp3', { type: 'audio/mpeg' });
const videoFile = new File(['foo'], 'test-file.mp4', { type: 'video/mp4' });
+ const drawioDiagramFile = new File(['foo'], 'test-file.drawio.svg', { type: 'image/svg+xml' });
const attachmentFile = new File(['foo'], 'test-file.zip', { type: 'application/zip' });
const expectDocumentAfterTransaction = ({ number, expectedDoc, action }) => {
@@ -67,12 +71,13 @@ describe('content_editor/extensions/attachment', () => {
Image,
Audio,
Video,
+ DrawioDiagram,
Attachment.configure({ renderMarkdown, uploadsPath, eventHub }),
],
});
({
- builders: { doc, p, image, audio, video, loading, link },
+ builders: { doc, p, image, audio, video, loading, link, drawioDiagram },
} = createDocBuilder({
tiptapEditor,
names: {
@@ -81,6 +86,7 @@ describe('content_editor/extensions/attachment', () => {
link: { nodeType: Link.name },
audio: { nodeType: Audio.name },
video: { nodeType: Video.name },
+ drawioDiagram: { nodeType: DrawioDiagram.name },
},
}));
@@ -113,10 +119,11 @@ describe('content_editor/extensions/attachment', () => {
});
describe.each`
- nodeType | mimeType | html | file | mediaType
- ${'image'} | ${'image/png'} | ${PROJECT_WIKI_ATTACHMENT_IMAGE_HTML} | ${imageFile} | ${(attrs) => image(attrs)}
- ${'audio'} | ${'audio/mpeg'} | ${PROJECT_WIKI_ATTACHMENT_AUDIO_HTML} | ${audioFile} | ${(attrs) => audio(attrs)}
- ${'video'} | ${'video/mp4'} | ${PROJECT_WIKI_ATTACHMENT_VIDEO_HTML} | ${videoFile} | ${(attrs) => video(attrs)}
+ nodeType | mimeType | html | file | mediaType
+ ${'image'} | ${'image/png'} | ${PROJECT_WIKI_ATTACHMENT_IMAGE_HTML} | ${imageFile} | ${(attrs) => image(attrs)}
+ ${'audio'} | ${'audio/mpeg'} | ${PROJECT_WIKI_ATTACHMENT_AUDIO_HTML} | ${audioFile} | ${(attrs) => audio(attrs)}
+ ${'video'} | ${'video/mp4'} | ${PROJECT_WIKI_ATTACHMENT_VIDEO_HTML} | ${videoFile} | ${(attrs) => video(attrs)}
+ ${'drawioDiagram'} | ${'image/svg+xml'} | ${PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML} | ${drawioDiagramFile} | ${(attrs) => drawioDiagram(attrs)}
`('when the file has $nodeType mime type', ({ mimeType, html, file, mediaType }) => {
const base64EncodedFile = `data:${mimeType};base64,Zm9v`;
@@ -151,7 +158,7 @@ describe('content_editor/extensions/attachment', () => {
mediaType({
canonicalSrc: file.name,
src: base64EncodedFile,
- alt: 'test-file',
+ alt: expect.stringContaining('test-file'),
uploading: false,
}),
),
diff --git a/spec/frontend/content_editor/extensions/drawio_diagram_spec.js b/spec/frontend/content_editor/extensions/drawio_diagram_spec.js
new file mode 100644
index 00000000000..61dc164c99a
--- /dev/null
+++ b/spec/frontend/content_editor/extensions/drawio_diagram_spec.js
@@ -0,0 +1,103 @@
+import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
+import Image from '~/content_editor/extensions/image';
+import createAssetResolver from '~/content_editor/services/asset_resolver';
+import { create } from '~/drawio/content_editor_facade';
+import { launchDrawioEditor } from '~/drawio/drawio_editor';
+import { createTestEditor, createDocBuilder } from '../test_utils';
+import {
+ PROJECT_WIKI_ATTACHMENT_IMAGE_HTML,
+ PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML,
+} from '../test_constants';
+
+jest.mock('~/content_editor/services/asset_resolver');
+jest.mock('~/drawio/content_editor_facade');
+jest.mock('~/drawio/drawio_editor');
+
+describe('content_editor/extensions/drawio_diagram', () => {
+ let tiptapEditor;
+ let doc;
+ let paragraph;
+ let image;
+ let drawioDiagram;
+ const uploadsPath = '/uploads';
+ const renderMarkdown = () => {};
+
+ beforeEach(() => {
+ tiptapEditor = createTestEditor({
+ extensions: [Image, DrawioDiagram.configure({ uploadsPath, renderMarkdown })],
+ });
+ const { builders } = createDocBuilder({
+ tiptapEditor,
+ names: {
+ image: { nodeType: Image.name },
+ drawioDiagram: { nodeType: DrawioDiagram.name },
+ },
+ });
+
+ doc = builders.doc;
+ paragraph = builders.paragraph;
+ image = builders.image;
+ drawioDiagram = builders.drawioDiagram;
+ });
+
+ describe('parsing', () => {
+ it('distinguishes a drawio diagram from an image', () => {
+ const expectedDocWithDiagram = doc(
+ paragraph(
+ drawioDiagram({
+ alt: 'test-file',
+ canonicalSrc: 'test-file.drawio.svg',
+ src: '/group1/project1/-/wikis/test-file.drawio.svg',
+ }),
+ ),
+ );
+ const expectedDocWithImage = doc(
+ paragraph(
+ image({
+ alt: 'test-file',
+ canonicalSrc: 'test-file.png',
+ src: '/group1/project1/-/wikis/test-file.png',
+ }),
+ ),
+ );
+ tiptapEditor.commands.setContent(PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML);
+
+ expect(tiptapEditor.state.doc.toJSON()).toEqual(expectedDocWithDiagram.toJSON());
+
+ tiptapEditor.commands.setContent(PROJECT_WIKI_ATTACHMENT_IMAGE_HTML);
+
+ expect(tiptapEditor.state.doc.toJSON()).toEqual(expectedDocWithImage.toJSON());
+ });
+ });
+
+ describe('createOrEditDiagram command', () => {
+ let editorFacade;
+ let assetResolver;
+
+ beforeEach(() => {
+ editorFacade = {};
+ assetResolver = {};
+ tiptapEditor.commands.createOrEditDiagram();
+
+ create.mockReturnValueOnce(editorFacade);
+ createAssetResolver.mockReturnValueOnce(assetResolver);
+ });
+
+ it('creates a new instance of asset resolver', () => {
+ expect(createAssetResolver).toHaveBeenCalledWith({ renderMarkdown });
+ });
+
+ it('creates a new instance of the content_editor_facade', () => {
+ expect(create).toHaveBeenCalledWith({
+ tiptapEditor,
+ drawioNodeName: DrawioDiagram.name,
+ uploadsPath,
+ assetResolver,
+ });
+ });
+
+ it('calls launchDrawioEditor and provides content_editor_facade', () => {
+ expect(launchDrawioEditor).toHaveBeenCalledWith({ editorFacade });
+ });
+ });
+});
diff --git a/spec/frontend/content_editor/extensions/paste_markdown_spec.js b/spec/frontend/content_editor/extensions/paste_markdown_spec.js
index 30e798e8817..8f3a4934e77 100644
--- a/spec/frontend/content_editor/extensions/paste_markdown_spec.js
+++ b/spec/frontend/content_editor/extensions/paste_markdown_spec.js
@@ -3,7 +3,7 @@ import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight
import Diagram from '~/content_editor/extensions/diagram';
import Frontmatter from '~/content_editor/extensions/frontmatter';
import Bold from '~/content_editor/extensions/bold';
-import { VARIANT_DANGER } from '~/flash';
+import { VARIANT_DANGER } from '~/alert';
import eventHubFactory from '~/helpers/event_hub_factory';
import { ALERT_EVENT } from '~/content_editor/constants';
import waitForPromises from 'helpers/wait_for_promises';
diff --git a/spec/frontend/content_editor/render_html_and_json_for_all_examples.js b/spec/frontend/content_editor/render_html_and_json_for_all_examples.js
index 5df901e0f15..bf29d4bdf23 100644
--- a/spec/frontend/content_editor/render_html_and_json_for_all_examples.js
+++ b/spec/frontend/content_editor/render_html_and_json_for_all_examples.js
@@ -1,4 +1,4 @@
-import { DOMSerializer } from 'prosemirror-model';
+import { DOMSerializer } from '@tiptap/pm/model';
import createMarkdownDeserializer from '~/content_editor/services/remark_markdown_deserializer';
import { createTiptapEditor } from 'jest/content_editor/test_utils';
diff --git a/spec/frontend/content_editor/services/create_content_editor_spec.js b/spec/frontend/content_editor/services/create_content_editor_spec.js
index e1a30819ac8..00cc628ca72 100644
--- a/spec/frontend/content_editor/services/create_content_editor_spec.js
+++ b/spec/frontend/content_editor/services/create_content_editor_spec.js
@@ -20,7 +20,7 @@ describe('content_editor/services/create_content_editor', () => {
preserveUnchangedMarkdown: false,
},
};
- editor = createContentEditor({ renderMarkdown, uploadsPath });
+ editor = createContentEditor({ renderMarkdown, uploadsPath, drawioEnabled: true });
});
describe('when preserveUnchangedMarkdown feature is on', () => {
@@ -45,10 +45,10 @@ describe('content_editor/services/create_content_editor', () => {
});
});
- it('sets gl-outline-0! class selector to the tiptapEditor instance', () => {
+ it('sets gl-shadow-none! class selector to the tiptapEditor instance', () => {
expect(editor.tiptapEditor.options.editorProps).toMatchObject({
attributes: {
- class: 'gl-outline-0!',
+ class: 'gl-shadow-none!',
},
});
});
@@ -82,4 +82,14 @@ describe('content_editor/services/create_content_editor', () => {
renderMarkdown,
});
});
+
+ it('provides uploadsPath and renderMarkdown function to DrawioDiagram extension', () => {
+ expect(
+ editor.tiptapEditor.extensionManager.extensions.find((e) => e.name === 'drawioDiagram')
+ .options,
+ ).toMatchObject({
+ uploadsPath,
+ renderMarkdown,
+ });
+ });
});
diff --git a/spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js b/spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js
index 90d83820c70..8ee37282ee9 100644
--- a/spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js
+++ b/spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js
@@ -35,12 +35,10 @@ describe('content_editor/services/gl_api_markdown_deserializer', () => {
beforeEach(async () => {
const deserializer = createMarkdownDeserializer({ render: renderMarkdown });
- renderMarkdown.mockResolvedValueOnce(
- `<p><strong>${text}</strong></p><pre lang="javascript"></pre><!-- some comment -->`,
- );
+ renderMarkdown.mockResolvedValueOnce(`<p><strong>${text}</strong></p><!-- some comment -->`);
result = await deserializer.deserialize({
- content: 'content',
+ markdown: '**Bold text**\n<!-- some comment -->',
schema: tiptapEditor.schema,
});
});
@@ -53,12 +51,22 @@ describe('content_editor/services/gl_api_markdown_deserializer', () => {
});
describe('when the render function returns an empty value', () => {
- it('returns an empty object', async () => {
- const deserializer = createMarkdownDeserializer({ render: renderMarkdown });
+ it('returns an empty prosemirror document', async () => {
+ const deserializer = createMarkdownDeserializer({
+ render: renderMarkdown,
+ schema: tiptapEditor.schema,
+ });
renderMarkdown.mockResolvedValueOnce(null);
- expect(await deserializer.deserialize({ content: 'content' })).toEqual({});
+ const result = await deserializer.deserialize({
+ markdown: '',
+ schema: tiptapEditor.schema,
+ });
+
+ const document = doc(p());
+
+ expect(result.document.toJSON()).toEqual(document.toJSON());
});
});
});
diff --git a/spec/frontend/content_editor/services/markdown_serializer_spec.js b/spec/frontend/content_editor/services/markdown_serializer_spec.js
index 2cd8b8a0d6f..c4d302547a5 100644
--- a/spec/frontend/content_editor/services/markdown_serializer_spec.js
+++ b/spec/frontend/content_editor/services/markdown_serializer_spec.js
@@ -8,6 +8,7 @@ import DescriptionItem from '~/content_editor/extensions/description_item';
import DescriptionList from '~/content_editor/extensions/description_list';
import Details from '~/content_editor/extensions/details';
import DetailsContent from '~/content_editor/extensions/details_content';
+import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
import Emoji from '~/content_editor/extensions/emoji';
import Figure from '~/content_editor/extensions/figure';
import FigureCaption from '~/content_editor/extensions/figure_caption';
@@ -57,6 +58,7 @@ const {
div,
descriptionItem,
descriptionList,
+ drawioDiagram,
emoji,
footnoteDefinition,
footnoteReference,
@@ -96,6 +98,7 @@ const {
detailsContent: { nodeType: DetailsContent.name },
descriptionItem: { nodeType: DescriptionItem.name },
descriptionList: { nodeType: DescriptionList.name },
+ drawioDiagram: { nodeType: DrawioDiagram.name },
emoji: { markType: Emoji.name },
figure: { nodeType: Figure.name },
figureCaption: { nodeType: FigureCaption.name },
@@ -397,6 +400,12 @@ this is not really json:table but just trying out whether this case works or not
);
});
+ it('correctly serializes a drawio_diagram', () => {
+ expect(
+ serialize(paragraph(drawioDiagram({ src: 'diagram.drawio.svg', alt: 'Draw.io Diagram' }))),
+ ).toBe('![Draw.io Diagram](diagram.drawio.svg)');
+ });
+
it.each`
width | height | outputAttributes
${300} | ${undefined} | ${'width=300'}
diff --git a/spec/frontend/content_editor/test_constants.js b/spec/frontend/content_editor/test_constants.js
index 45a0e4a8bd1..bd462ecec22 100644
--- a/spec/frontend/content_editor/test_constants.js
+++ b/spec/frontend/content_editor/test_constants.js
@@ -20,6 +20,12 @@ export const PROJECT_WIKI_ATTACHMENT_AUDIO_HTML = `<p data-sourcepos="3:1-3:74"
</span>
</p>`;
+export const PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML = `<p data-sourcepos="1:1-1:27" dir="auto">
+ <a class="no-attachment-icon" href="/group1/project1/-/wikis/test-file.drawio.svg" target="_blank" rel="noopener noreferrer" data-canonical-src="test-file.drawio.svg">
+ <img alt="test-file" class="lazy" data-src="/group1/project1/-/wikis/test-file.drawio.svg" data-canonical-src="test-file.drawio.svg">
+ </a>
+</p>`;
+
export const PROJECT_WIKI_ATTACHMENT_LINK_HTML = `<p data-sourcepos="1:1-1:26" dir="auto">
<a href="/group1/project1/-/wikis/test-file.zip" data-canonical-src="test-file.zip">test-file</a>
</p>`;
diff --git a/spec/frontend/content_editor/test_utils.js b/spec/frontend/content_editor/test_utils.js
index 0fa0e65cd26..16f90a15c24 100644
--- a/spec/frontend/content_editor/test_utils.js
+++ b/spec/frontend/content_editor/test_utils.js
@@ -17,6 +17,7 @@ import DescriptionList from '~/content_editor/extensions/description_list';
import Details from '~/content_editor/extensions/details';
import DetailsContent from '~/content_editor/extensions/details_content';
import Diagram from '~/content_editor/extensions/diagram';
+import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
import Emoji from '~/content_editor/extensions/emoji';
import FootnoteDefinition from '~/content_editor/extensions/footnote_definition';
import FootnoteReference from '~/content_editor/extensions/footnote_reference';
@@ -218,6 +219,7 @@ export const createTiptapEditor = (extensions = []) =>
DescriptionList,
Details,
DetailsContent,
+ DrawioDiagram,
Diagram,
Emoji,
FootnoteDefinition,
diff --git a/spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap b/spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap
index 2f441f0f747..4b7439f6fd2 100644
--- a/spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap
+++ b/spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap
@@ -53,23 +53,22 @@ exports[`Contributors charts should render charts and a RefSelector when loading
Excluding merge commits. Limited to 6,000 commits.
</span>
- <div>
- <glareachart-stub
- annotations=""
- class="gl-mb-5"
- data="[object Object]"
- height="264"
- includelegendavgmax="true"
- legendaveragetext="Avg"
- legendcurrenttext="Current"
- legendlayout="inline"
- legendmaxtext="Max"
- legendmintext="Min"
- option="[object Object]"
- thresholds=""
- width="0"
- />
- </div>
+ <glareachart-stub
+ annotations=""
+ class="gl-mb-5"
+ data="[object Object]"
+ height="264"
+ includelegendavgmax="true"
+ legendaveragetext="Avg"
+ legendcurrenttext="Current"
+ legendlayout="inline"
+ legendmaxtext="Max"
+ legendmintext="Min"
+ option="[object Object]"
+ responsive=""
+ thresholds=""
+ width="auto"
+ />
<div
class="row"
@@ -91,22 +90,21 @@ exports[`Contributors charts should render charts and a RefSelector when loading
</p>
- <div>
- <glareachart-stub
- annotations=""
- data="[object Object]"
- height="216"
- includelegendavgmax="true"
- legendaveragetext="Avg"
- legendcurrenttext="Current"
- legendlayout="inline"
- legendmaxtext="Max"
- legendmintext="Min"
- option="[object Object]"
- thresholds=""
- width="0"
- />
- </div>
+ <glareachart-stub
+ annotations=""
+ data="[object Object]"
+ height="216"
+ includelegendavgmax="true"
+ legendaveragetext="Avg"
+ legendcurrenttext="Current"
+ legendlayout="inline"
+ legendmaxtext="Max"
+ legendmintext="Min"
+ option="[object Object]"
+ responsive=""
+ thresholds=""
+ width="auto"
+ />
</div>
</div>
</div>
diff --git a/spec/frontend/contributors/component/contributors_spec.js b/spec/frontend/contributors/component/contributors_spec.js
index 03b1e977548..f915b834aff 100644
--- a/spec/frontend/contributors/component/contributors_spec.js
+++ b/spec/frontend/contributors/component/contributors_spec.js
@@ -1,5 +1,5 @@
import MockAdapter from 'axios-mock-adapter';
-import Vue, { nextTick } from 'vue';
+import { nextTick } from 'vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import ContributorsCharts from '~/contributors/components/contributors.vue';
import { createStore } from '~/contributors/stores';
@@ -16,7 +16,6 @@ jest.mock('~/lib/utils/url_utility', () => ({
let wrapper;
let mock;
let store;
-const Component = Vue.extend(ContributorsCharts);
const endpoint = 'contributors/-/graphs';
const branch = 'main';
const chartData = [
@@ -32,7 +31,7 @@ function factory() {
mock.onGet().reply(HTTP_STATUS_OK, chartData);
store = createStore();
- wrapper = mountExtended(Component, {
+ wrapper = mountExtended(ContributorsCharts, {
propsData: {
endpoint,
branch,
@@ -60,7 +59,6 @@ describe('Contributors charts', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
it('should fetch chart data when mounted', () => {
diff --git a/spec/frontend/contributors/store/actions_spec.js b/spec/frontend/contributors/store/actions_spec.js
index b2ebdf2f53c..a15b9ad2978 100644
--- a/spec/frontend/contributors/store/actions_spec.js
+++ b/spec/frontend/contributors/store/actions_spec.js
@@ -2,11 +2,11 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/contributors/stores/actions';
import * as types from '~/contributors/stores/mutation_types';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
describe('Contributors store actions', () => {
describe('fetchChartData', () => {
@@ -38,7 +38,7 @@ describe('Contributors store actions', () => {
);
});
- it('should show flash on API error', async () => {
+ it('should show alert on API error', async () => {
mock.onGet().reply(HTTP_STATUS_BAD_REQUEST, 'Not Found');
await testAction(
diff --git a/spec/frontend/crm/contact_form_wrapper_spec.js b/spec/frontend/crm/contact_form_wrapper_spec.js
index 50b432943fb..2fb6940a415 100644
--- a/spec/frontend/crm/contact_form_wrapper_spec.js
+++ b/spec/frontend/crm/contact_form_wrapper_spec.js
@@ -47,7 +47,6 @@ describe('Customer relations contact form wrapper', () => {
});
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
diff --git a/spec/frontend/crm/contacts_root_spec.js b/spec/frontend/crm/contacts_root_spec.js
index ec7172434bf..63b64a6c984 100644
--- a/spec/frontend/crm/contacts_root_spec.js
+++ b/spec/frontend/crm/contacts_root_spec.js
@@ -61,7 +61,6 @@ describe('Customer relations contacts root app', () => {
});
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
router = null;
});
diff --git a/spec/frontend/crm/crm_form_spec.js b/spec/frontend/crm/crm_form_spec.js
index eabcf5b1b1b..fabf43ceb9d 100644
--- a/spec/frontend/crm/crm_form_spec.js
+++ b/spec/frontend/crm/crm_form_spec.js
@@ -188,10 +188,6 @@ describe('Reusable form component', () => {
};
const asTestParams = (...keys) => keys.map((name) => [name, forms[name]]);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each(asTestParams(FORM_CREATE_CONTACT, FORM_UPDATE_CONTACT))(
'%s form save button',
(name, { mountFunction }) => {
diff --git a/spec/frontend/crm/organization_form_wrapper_spec.js b/spec/frontend/crm/organization_form_wrapper_spec.js
index d795c585622..8408c1920a9 100644
--- a/spec/frontend/crm/organization_form_wrapper_spec.js
+++ b/spec/frontend/crm/organization_form_wrapper_spec.js
@@ -40,10 +40,6 @@ describe('Customer relations organization form wrapper', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('in edit mode', () => {
it('should render organization form with correct props', () => {
mountComponent({ isEditMode: true });
diff --git a/spec/frontend/crm/organizations_root_spec.js b/spec/frontend/crm/organizations_root_spec.js
index 1fcf6aa8f50..0b26a49a6b3 100644
--- a/spec/frontend/crm/organizations_root_spec.js
+++ b/spec/frontend/crm/organizations_root_spec.js
@@ -65,7 +65,6 @@ describe('Customer relations organizations root app', () => {
});
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
router = null;
});
diff --git a/spec/frontend/custom_metrics/components/custom_metrics_form_fields_spec.js b/spec/frontend/custom_metrics/components/custom_metrics_form_fields_spec.js
index 7d9ae548c9a..12fef9d5ddf 100644
--- a/spec/frontend/custom_metrics/components/custom_metrics_form_fields_spec.js
+++ b/spec/frontend/custom_metrics/components/custom_metrics_form_fields_spec.js
@@ -42,7 +42,6 @@ describe('custom metrics form fields component', () => {
});
afterEach(() => {
- wrapper.destroy();
mockAxios.restore();
});
diff --git a/spec/frontend/custom_metrics/components/custom_metrics_form_spec.js b/spec/frontend/custom_metrics/components/custom_metrics_form_spec.js
index af56b94f90b..c633583f2cb 100644
--- a/spec/frontend/custom_metrics/components/custom_metrics_form_spec.js
+++ b/spec/frontend/custom_metrics/components/custom_metrics_form_spec.js
@@ -26,10 +26,6 @@ describe('CustomMetricsForm', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Computed', () => {
it('Form button and title text indicate the custom metric is being edited', () => {
mountComponent({ metricPersisted: true });
diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js
index 113e0d8f60d..77118ae140a 100644
--- a/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js
+++ b/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js
@@ -46,11 +46,6 @@ describe('Deploy freeze modal', () => {
wrapper.findComponent(TimezoneDropdown).trigger('input');
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('Basic interactions', () => {
it('button is disabled when freeze period is invalid', () => {
expect(submitDeployFreezeButton().attributes('disabled')).toBe('true');
diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js
index 27d8fea9d5e..883cc6a344a 100644
--- a/spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js
+++ b/spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js
@@ -24,11 +24,6 @@ describe('Deploy freeze settings', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('Deploy freeze table contains components', () => {
it('contains deploy freeze table', () => {
expect(wrapper.findComponent(DeployFreezeTable).exists()).toBe(true);
diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js
index c2d6eb399bc..6a9e482a184 100644
--- a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js
+++ b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js
@@ -37,11 +37,6 @@ describe('Deploy freeze table', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('dispatches fetchFreezePeriods when mounted', () => {
expect(store.dispatch).toHaveBeenCalledWith('fetchFreezePeriods');
});
diff --git a/spec/frontend/deploy_freeze/store/actions_spec.js b/spec/frontend/deploy_freeze/store/actions_spec.js
index 9b96ce5d252..d39577baa59 100644
--- a/spec/frontend/deploy_freeze/store/actions_spec.js
+++ b/spec/frontend/deploy_freeze/store/actions_spec.js
@@ -4,14 +4,14 @@ import Api from '~/api';
import * as actions from '~/deploy_freeze/store/actions';
import * as types from '~/deploy_freeze/store/mutation_types';
import getInitialState from '~/deploy_freeze/store/state';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as logger from '~/lib/logger';
import axios from '~/lib/utils/axios_utils';
import { freezePeriodsFixture } from '../helpers';
import { timezoneDataFixture } from '../../vue_shared/components/timezone_dropdown/helpers';
jest.mock('~/api.js');
-jest.mock('~/flash.js');
+jest.mock('~/alert');
describe('deploy freeze store actions', () => {
const freezePeriodFixture = freezePeriodsFixture[0];
diff --git a/spec/frontend/deploy_keys/components/app_spec.js b/spec/frontend/deploy_keys/components/app_spec.js
index d11ecf95de6..3dfb828b449 100644
--- a/spec/frontend/deploy_keys/components/app_spec.js
+++ b/spec/frontend/deploy_keys/components/app_spec.js
@@ -33,7 +33,6 @@ describe('Deploy keys app component', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/deploy_keys/components/key_spec.js b/spec/frontend/deploy_keys/components/key_spec.js
index 8599c55c908..5f20d4ad542 100644
--- a/spec/frontend/deploy_keys/components/key_spec.js
+++ b/spec/frontend/deploy_keys/components/key_spec.js
@@ -26,11 +26,6 @@ describe('Deploy keys key', () => {
store.keys = data;
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('enabled key', () => {
const deployKey = data.enabled_keys[0];
diff --git a/spec/frontend/deploy_keys/components/keys_panel_spec.js b/spec/frontend/deploy_keys/components/keys_panel_spec.js
index f5f76d5d493..e0f86aadad4 100644
--- a/spec/frontend/deploy_keys/components/keys_panel_spec.js
+++ b/spec/frontend/deploy_keys/components/keys_panel_spec.js
@@ -23,11 +23,6 @@ describe('Deploy keys panel', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders list of keys', () => {
mountComponent();
expect(wrapper.findAll('.deploy-key').length).toBe(wrapper.vm.keys.length);
diff --git a/spec/frontend/deploy_tokens/components/new_deploy_token_spec.js b/spec/frontend/deploy_tokens/components/new_deploy_token_spec.js
index 46f7b2f3604..a3fdab88270 100644
--- a/spec/frontend/deploy_tokens/components/new_deploy_token_spec.js
+++ b/spec/frontend/deploy_tokens/components/new_deploy_token_spec.js
@@ -7,20 +7,12 @@ import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/h
import { TEST_HOST } from 'helpers/test_constants';
import NewDeployToken from '~/deploy_tokens/components/new_deploy_token.vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
const createNewTokenPath = `${TEST_HOST}/create`;
const deployTokensHelpUrl = `${TEST_HOST}/help`;
-jest.mock('~/flash', () => {
- const original = jest.requireActual('~/flash');
-
- return {
- __esModule: true,
- ...original,
- createAlert: jest.fn(),
- };
-});
+jest.mock('~/alert');
describe('New Deploy Token', () => {
let wrapper;
@@ -43,13 +35,12 @@ describe('New Deploy Token', () => {
createNewTokenPath,
tokenType,
},
+ stubs: {
+ GlFormCheckbox,
+ },
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('without a container registry', () => {
beforeEach(() => {
wrapper = factory({ containerRegistryEnabled: false });
@@ -69,7 +60,7 @@ describe('New Deploy Token', () => {
it('should show the read registry scope', () => {
const checkbox = wrapper.findAllComponents(GlFormCheckbox).at(1);
- expect(checkbox.text()).toBe('read_registry');
+ expect(checkbox.text()).toContain('read_registry');
});
function submitTokenThenCheck() {
@@ -91,7 +82,7 @@ describe('New Deploy Token', () => {
});
}
- it('should flash error message if token creation fails', async () => {
+ it('should alert error message if token creation fails', async () => {
const mockAxios = new MockAdapter(axios);
const date = new Date();
@@ -222,4 +213,32 @@ describe('New Deploy Token', () => {
return submitTokenThenCheck();
});
});
+
+ describe('help text for write_package_registry scope', () => {
+ const findWriteRegistryScopeCheckbox = () => wrapper.findAllComponents(GlFormCheckbox).at(4);
+
+ describe('with project tokenType', () => {
+ beforeEach(() => {
+ wrapper = factory();
+ });
+
+ it('should show the correct help text', () => {
+ expect(findWriteRegistryScopeCheckbox().text()).toContain(
+ 'Allows read, write and delete access to the package registry.',
+ );
+ });
+ });
+
+ describe('with group tokenType', () => {
+ beforeEach(() => {
+ wrapper = factory({ tokenType: 'group' });
+ });
+
+ it('should show the correct help text', () => {
+ expect(findWriteRegistryScopeCheckbox().text()).toContain(
+ 'Allows read and write access to the package registry.',
+ );
+ });
+ });
+ });
});
diff --git a/spec/frontend/deploy_tokens/components/revoke_button_spec.js b/spec/frontend/deploy_tokens/components/revoke_button_spec.js
index fa2a7d9b155..6e81205d1c1 100644
--- a/spec/frontend/deploy_tokens/components/revoke_button_spec.js
+++ b/spec/frontend/deploy_tokens/components/revoke_button_spec.js
@@ -52,10 +52,6 @@ describe('RevokeButton', () => {
);
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findRevokeButton = () => wrapper.findByTestId('revoke-button');
const findModal = () => wrapper.findComponent(GlModal);
const findPrimaryModalButton = () => wrapper.findByTestId('primary-revoke-btn');
diff --git a/spec/frontend/design_management/components/delete_button_spec.js b/spec/frontend/design_management/components/delete_button_spec.js
index 426a61f5a47..81e3b21a910 100644
--- a/spec/frontend/design_management/components/delete_button_spec.js
+++ b/spec/frontend/design_management/components/delete_button_spec.js
@@ -21,10 +21,6 @@ describe('Batch delete button component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders non-disabled button by default', () => {
createComponent();
diff --git a/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap b/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap
index 402e55347af..e2f1d6e4b10 100644
--- a/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap
+++ b/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap
@@ -70,6 +70,8 @@ exports[`Design note component should match the snapshot 1`] = `
>
<!---->
+
+ <!---->
</div>
</div>
diff --git a/spec/frontend/design_management/components/design_notes/design_discussion_spec.js b/spec/frontend/design_management/components/design_notes/design_discussion_spec.js
index 2091e1e08dd..56bf0fa60a7 100644
--- a/spec/frontend/design_management/components/design_notes/design_discussion_spec.js
+++ b/spec/frontend/design_management/components/design_notes/design_discussion_spec.js
@@ -1,18 +1,22 @@
import { GlLoadingIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
-import { ApolloMutation } from 'vue-apollo';
import { nextTick } from 'vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import DesignDiscussion from '~/design_management/components/design_notes/design_discussion.vue';
import DesignNote from '~/design_management/components/design_notes/design_note.vue';
import DesignNoteSignedOut from '~/design_management/components/design_notes/design_note_signed_out.vue';
import DesignReplyForm from '~/design_management/components/design_notes/design_reply_form.vue';
import ToggleRepliesWidget from '~/design_management/components/design_notes/toggle_replies_widget.vue';
-import createNoteMutation from '~/design_management/graphql/mutations/create_note.mutation.graphql';
import toggleResolveDiscussionMutation from '~/design_management/graphql/mutations/toggle_resolve_discussion.mutation.graphql';
import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
+import destroyNoteMutation from '~/design_management/graphql/mutations/destroy_note.mutation.graphql';
+import { DELETE_NOTE_ERROR_MSG } from '~/design_management/constants';
import mockDiscussion from '../../mock_data/discussion';
import notes from '../../mock_data/notes';
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
+
const defaultMockDiscussion = {
id: '0',
resolved: false,
@@ -23,7 +27,6 @@ const defaultMockDiscussion = {
const DEFAULT_TODO_COUNT = 2;
describe('Design discussions component', () => {
- const originalGon = window.gon;
let wrapper;
const findDesignNotes = () => wrapper.findAllComponents(DesignNote);
@@ -34,18 +37,7 @@ describe('Design discussions component', () => {
const findResolvedMessage = () => wrapper.find('[data-testid="resolved-message"]');
const findResolveLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findResolveCheckbox = () => wrapper.find('[data-testid="resolve-checkbox"]');
- const findApolloMutation = () => wrapper.findComponent(ApolloMutation);
- const mutationVariables = {
- mutation: createNoteMutation,
- variables: {
- input: {
- noteableId: 'noteable-id',
- body: 'test',
- discussionId: '0',
- },
- },
- };
const registerPath = '/users/sign_up?redirect_to_referer=yes';
const signInPath = '/users/sign_in?redirect_to_referer=yes';
const mutate = jest.fn().mockResolvedValue({ data: { createNote: { errors: [] } } });
@@ -59,7 +51,7 @@ describe('Design discussions component', () => {
provider: { clients: { defaultClient: { readQuery } } },
};
- function createComponent(props = {}, data = {}) {
+ function createComponent({ props = {}, data = {}, apolloConfig = {} } = {}) {
wrapper = mount(DesignDiscussion, {
propsData: {
resolvedDiscussionsExpanded: true,
@@ -82,7 +74,10 @@ describe('Design discussions component', () => {
issueIid: '1',
},
mocks: {
- $apollo,
+ $apollo: {
+ ...$apollo,
+ ...apolloConfig,
+ },
$route: {
hash: '#note_1',
params: {
@@ -101,16 +96,17 @@ describe('Design discussions component', () => {
});
afterEach(() => {
- wrapper.destroy();
- window.gon = originalGon;
+ confirmAction.mockReset();
});
describe('when discussion is not resolvable', () => {
beforeEach(() => {
createComponent({
- discussion: {
- ...defaultMockDiscussion,
- resolvable: false,
+ props: {
+ discussion: {
+ ...defaultMockDiscussion,
+ resolvable: false,
+ },
},
});
});
@@ -171,11 +167,13 @@ describe('Design discussions component', () => {
innerText: DEFAULT_TODO_COUNT,
});
createComponent({
- discussion: {
- ...defaultMockDiscussion,
- resolved: true,
- resolvedBy: notes[0].author,
- resolvedAt: '2020-05-08T07:10:45Z',
+ props: {
+ discussion: {
+ ...defaultMockDiscussion,
+ resolved: true,
+ resolvedBy: notes[0].author,
+ resolvedAt: '2020-05-08T07:10:45Z',
+ },
},
});
});
@@ -206,10 +204,10 @@ describe('Design discussions component', () => {
});
it('emit todo:toggle when discussion is resolved', async () => {
- createComponent(
- { discussionWithOpenForm: defaultMockDiscussion.id },
- { discussionComment: 'test', isFormRendered: true },
- );
+ createComponent({
+ props: { discussionWithOpenForm: defaultMockDiscussion.id },
+ data: { isFormRendered: true },
+ });
findResolveButton().trigger('click');
findReplyForm().vm.$emit('submitForm');
@@ -261,32 +259,28 @@ describe('Design discussions component', () => {
expect(findReplyForm().exists()).toBe(true);
});
- it('calls mutation on submitting form and closes the form', async () => {
- createComponent(
- { discussionWithOpenForm: defaultMockDiscussion.id },
- { discussionComment: 'test', isFormRendered: true },
- );
+ it('closes the form when note submit mutation is completed', async () => {
+ createComponent({
+ props: { discussionWithOpenForm: defaultMockDiscussion.id },
+ data: { isFormRendered: true },
+ });
- findReplyForm().vm.$emit('submit-form');
- expect(mutate).toHaveBeenCalledWith(mutationVariables);
+ findReplyForm().vm.$emit('note-submit-complete', { data: { createNote: {} } });
- await mutate();
await nextTick();
expect(findReplyForm().exists()).toBe(false);
});
it('clears the discussion comment on closing comment form', async () => {
- createComponent(
- { discussionWithOpenForm: defaultMockDiscussion.id },
- { discussionComment: 'test', isFormRendered: true },
- );
+ createComponent({
+ props: { discussionWithOpenForm: defaultMockDiscussion.id },
+ data: { isFormRendered: true },
+ });
await nextTick();
findReplyForm().vm.$emit('cancel-form');
- expect(wrapper.vm.discussionComment).toBe('');
-
await nextTick();
expect(findReplyForm().exists()).toBe(false);
});
@@ -295,15 +289,15 @@ describe('Design discussions component', () => {
it.each([notes[0], notes[0].discussion.notes.nodes[1]])(
'applies correct class to all notes in the active discussion',
(note) => {
- createComponent(
- { discussion: mockDiscussion },
- {
+ createComponent({
+ props: { discussion: mockDiscussion },
+ data: {
activeDiscussion: {
id: note.id,
source: 'pin',
},
},
- );
+ });
expect(
wrapper
@@ -329,10 +323,10 @@ describe('Design discussions component', () => {
});
it('calls toggleResolveDiscussion mutation after adding a note if checkbox was checked', () => {
- createComponent(
- { discussionWithOpenForm: defaultMockDiscussion.id },
- { discussionComment: 'test', isFormRendered: true },
- );
+ createComponent({
+ props: { discussionWithOpenForm: defaultMockDiscussion.id },
+ data: { isFormRendered: true },
+ });
findResolveButton().trigger('click');
findReplyForm().vm.$emit('submitForm');
@@ -359,15 +353,15 @@ describe('Design discussions component', () => {
beforeEach(() => {
window.gon = { current_user_id: null };
- createComponent(
- {
+ createComponent({
+ props: {
discussion: {
...defaultMockDiscussion,
},
discussionWithOpenForm: defaultMockDiscussion.id,
},
- { discussionComment: 'test', isFormRendered: true },
- );
+ data: { isFormRendered: true },
+ });
});
it('does not render resolve discussion button', () => {
@@ -378,10 +372,6 @@ describe('Design discussions component', () => {
expect(findReplyPlaceholder().exists()).toBe(false);
});
- it('does not render apollo-mutation component', () => {
- expect(findApolloMutation().exists()).toBe(false);
- });
-
it('renders design-note-signed-out component', () => {
expect(findDesignNoteSignedOut().exists()).toBe(true);
expect(findDesignNoteSignedOut().props()).toMatchObject({
@@ -390,4 +380,64 @@ describe('Design discussions component', () => {
});
});
});
+
+ it('should open confirmation modal when the note emits `delete-note` event', async () => {
+ createComponent();
+
+ findDesignNotes().at(0).vm.$emit('delete-note', { id: '1' });
+ expect(confirmAction).toHaveBeenCalled();
+ });
+
+ describe('when confirmation modal is opened', () => {
+ const noteId = 'note-test-id';
+
+ it('sends the mutation with correct variables', async () => {
+ confirmAction.mockResolvedValueOnce(true);
+ const destroyNoteMutationSuccess = jest.fn().mockResolvedValue({
+ data: { destroyNote: { note: null, __typename: 'DestroyNote', errors: [] } },
+ });
+ createComponent({ apolloConfig: { mutate: destroyNoteMutationSuccess } });
+
+ findDesignNotes().at(0).vm.$emit('delete-note', { id: noteId });
+
+ expect(confirmAction).toHaveBeenCalled();
+
+ await waitForPromises();
+
+ expect(destroyNoteMutationSuccess).toHaveBeenCalledWith({
+ update: expect.any(Function),
+ mutation: destroyNoteMutation,
+ variables: {
+ input: {
+ id: noteId,
+ },
+ },
+ optimisticResponse: {
+ destroyNote: {
+ note: null,
+ errors: [],
+ __typename: 'DestroyNotePayload',
+ },
+ },
+ });
+ });
+
+ it('emits `delete-note-error` event if GraphQL mutation fails', async () => {
+ confirmAction.mockResolvedValueOnce(true);
+ const destroyNoteMutationError = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+ createComponent({ apolloConfig: { mutate: destroyNoteMutationError } });
+
+ findDesignNotes().at(0).vm.$emit('delete-note', { id: noteId });
+
+ await waitForPromises();
+
+ expect(destroyNoteMutationError).toHaveBeenCalled();
+
+ await waitForPromises();
+
+ expect(wrapper.emitted()).toEqual({
+ 'delete-note-error': [[DELETE_NOTE_ERROR_MSG]],
+ });
+ });
+ });
});
diff --git a/spec/frontend/design_management/components/design_notes/design_note_signed_out_spec.js b/spec/frontend/design_management/components/design_notes/design_note_signed_out_spec.js
index e71bb5ab520..95b08b89809 100644
--- a/spec/frontend/design_management/components/design_notes/design_note_signed_out_spec.js
+++ b/spec/frontend/design_management/components/design_notes/design_note_signed_out_spec.js
@@ -18,10 +18,6 @@ function createComponent(isAddDiscussion = false) {
describe('DesignNoteSignedOut', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders message containing register and sign-in links while user wants to reply to a discussion', () => {
wrapper = createComponent();
diff --git a/spec/frontend/design_management/components/design_notes/design_note_spec.js b/spec/frontend/design_management/components/design_notes/design_note_spec.js
index df511586c10..82848bd1a19 100644
--- a/spec/frontend/design_management/components/design_notes/design_note_spec.js
+++ b/spec/frontend/design_management/components/design_notes/design_note_spec.js
@@ -1,6 +1,6 @@
import { ApolloMutation } from 'vue-apollo';
import { nextTick } from 'vue';
-import { GlAvatar, GlAvatarLink } from '@gitlab/ui';
+import { GlAvatar, GlAvatarLink, GlDropdown } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DesignNote from '~/design_management/components/design_notes/design_note.vue';
import DesignReplyForm from '~/design_management/components/design_notes/design_reply_form.vue';
@@ -38,6 +38,8 @@ describe('Design note component', () => {
const findReplyForm = () => wrapper.findComponent(DesignReplyForm);
const findEditButton = () => wrapper.findByTestId('note-edit');
const findNoteContent = () => wrapper.findByTestId('note-text');
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDeleteNoteButton = () => wrapper.find('[data-testid="delete-note-button"]');
function createComponent(props = {}, data = { isEditing: false }) {
wrapper = shallowMountExtended(DesignNote, {
@@ -63,10 +65,6 @@ describe('Design note component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should match the snapshot', () => {
createComponent({
note,
@@ -112,6 +110,14 @@ describe('Design note component', () => {
expect(findEditButton().exists()).toBe(false);
});
+ it('should not display a dropdown if user does not have a permission to delete note', () => {
+ createComponent({
+ note,
+ });
+
+ expect(findDropdown().exists()).toBe(false);
+ });
+
describe('when user has a permission to edit note', () => {
it('should open an edit form on edit button click', async () => {
createComponent({
@@ -158,15 +164,47 @@ describe('Design note component', () => {
expect(findNoteContent().exists()).toBe(true);
});
- it('calls a mutation on submit-form event and hides a form', async () => {
- findReplyForm().vm.$emit('submit-form');
- expect(mutate).toHaveBeenCalled();
+ it('hides a form after update mutation is completed', async () => {
+ findReplyForm().vm.$emit('note-submit-complete', { data: { updateNote: { errors: [] } } });
- await mutate();
await nextTick();
expect(findReplyForm().exists()).toBe(false);
expect(findNoteContent().exists()).toBe(true);
});
});
});
+
+ describe('when user has a permission to delete note', () => {
+ it('should display a dropdown', () => {
+ createComponent({
+ note: {
+ ...note,
+ userPermissions: {
+ adminNote: true,
+ },
+ },
+ });
+
+ expect(findDropdown().exists()).toBe(true);
+ });
+ });
+
+ it('should emit `delete-note` event with proper payload when delete note button is clicked', async () => {
+ const payload = {
+ ...note,
+ userPermissions: {
+ adminNote: true,
+ },
+ };
+
+ createComponent({
+ note: {
+ ...payload,
+ },
+ });
+
+ findDeleteNoteButton().vm.$emit('click');
+
+ expect(wrapper.emitted()).toEqual({ 'delete-note': [[{ ...payload }]] });
+ });
});
diff --git a/spec/frontend/design_management/components/design_notes/design_reply_form_spec.js b/spec/frontend/design_management/components/design_notes/design_reply_form_spec.js
index f4d4f9cf896..db1cfb4f504 100644
--- a/spec/frontend/design_management/components/design_notes/design_reply_form_spec.js
+++ b/spec/frontend/design_management/components/design_notes/design_reply_form_spec.js
@@ -1,46 +1,96 @@
+import { GlAlert } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import Autosave from '~/autosave';
+import waitForPromises from 'helpers/wait_for_promises';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
+import createNoteMutation from '~/design_management/graphql/mutations/create_note.mutation.graphql';
import DesignReplyForm from '~/design_management/components/design_notes/design_reply_form.vue';
+import {
+ ADD_DISCUSSION_COMMENT_ERROR,
+ ADD_IMAGE_DIFF_NOTE_ERROR,
+ UPDATE_IMAGE_DIFF_NOTE_ERROR,
+ UPDATE_NOTE_ERROR,
+} from '~/design_management/utils/error_messages';
+import {
+ mockNoteSubmitSuccessMutationResponse,
+ mockNoteSubmitFailureMutationResponse,
+} from '../../mock_data/apollo_mock';
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
jest.mock('~/autosave');
describe('Design reply form component', () => {
let wrapper;
- let originalGon;
const findTextarea = () => wrapper.find('textarea');
const findSubmitButton = () => wrapper.findComponent({ ref: 'submitButton' });
const findCancelButton = () => wrapper.findComponent({ ref: 'cancelButton' });
-
- function createComponent(props = {}, mountOptions = {}) {
+ const findAlert = () => wrapper.findComponent(GlAlert);
+
+ const mockNoteableId = 'gid://gitlab/DesignManagement::Design/6';
+ const mockComment = 'New comment';
+ const mockDiscussionId = 'gid://gitlab/Discussion/6466a72f35b163f3c3e52d7976a09387f2c573e8';
+ const createNoteMutationData = {
+ mutation: createNoteMutation,
+ update: expect.anything(),
+ variables: {
+ input: {
+ noteableId: mockNoteableId,
+ discussionId: mockDiscussionId,
+ body: mockComment,
+ },
+ },
+ };
+
+ const ctrlKey = {
+ ctrlKey: true,
+ };
+ const metaKey = {
+ metaKey: true,
+ };
+ const mutationHandler = jest.fn().mockResolvedValue();
+
+ function createComponent({
+ props = {},
+ mountOptions = {},
+ data = {},
+ mutation = mutationHandler,
+ } = {}) {
wrapper = mount(DesignReplyForm, {
propsData: {
+ designNoteMutation: createNoteMutation,
+ noteableId: mockNoteableId,
+ markdownDocsPath: 'path/to/markdown/docs',
+ markdownPreviewPath: 'path/to/markdown/preview',
value: '',
- isSaving: false,
- noteableId: 'gid://gitlab/DesignManagement::Design/6',
...props,
},
...mountOptions,
+ mocks: {
+ $apollo: {
+ mutate: mutation,
+ },
+ },
+ data() {
+ return {
+ ...data,
+ };
+ },
});
}
beforeEach(() => {
- originalGon = window.gon;
window.gon.current_user_id = 1;
});
afterEach(() => {
- wrapper.destroy();
- window.gon = originalGon;
confirmAction.mockReset();
});
it('textarea has focus after component mount', () => {
// We need to attach to document, so that `document.activeElement` is properly set in jsdom
- createComponent({}, { attachTo: document.body });
+ createComponent({ mountOptions: { attachTo: document.body } });
expect(findTextarea().element).toEqual(document.activeElement);
});
@@ -64,7 +114,7 @@ describe('Design reply form component', () => {
});
it('renders button text as "Save comment" when creating a comment', () => {
- createComponent({ isNewComment: false });
+ createComponent({ props: { isNewComment: false } });
expect(findSubmitButton().html()).toMatchSnapshot();
});
@@ -76,7 +126,7 @@ describe('Design reply form component', () => {
`(
'initializes autosave support on discussion with proper key',
async ({ discussionId, shortDiscussionId }) => {
- createComponent({ discussionId });
+ createComponent({ props: { discussionId } });
await nextTick();
expect(Autosave).toHaveBeenCalledWith(expect.any(Element), [
@@ -88,32 +138,24 @@ describe('Design reply form component', () => {
);
describe('when form has no text', () => {
- beforeEach(() => {
- createComponent({
- value: '',
- });
+ beforeEach(async () => {
+ createComponent();
+ await nextTick();
});
it('submit button is disabled', () => {
expect(findSubmitButton().attributes().disabled).toBe('disabled');
});
- it('does not emit submitForm event on textarea ctrl+enter keydown', async () => {
- findTextarea().trigger('keydown.enter', {
- ctrlKey: true,
- });
-
- await nextTick();
- expect(wrapper.emitted('submit-form')).toBeUndefined();
- });
-
- it('does not emit submitForm event on textarea meta+enter keydown', async () => {
- findTextarea().trigger('keydown.enter', {
- metaKey: true,
- });
+ it.each`
+ key | keyData
+ ${'ctrl'} | ${ctrlKey}
+ ${'meta'} | ${metaKey}
+ `('does not perform mutation on textarea $key+enter keydown', async ({ keyData }) => {
+ findTextarea().trigger('keydown.enter', keyData);
await nextTick();
- expect(wrapper.emitted('submit-form')).toBeUndefined();
+ expect(mutationHandler).not.toHaveBeenCalled();
});
it('emits cancelForm event on pressing escape button on textarea', () => {
@@ -129,118 +171,159 @@ describe('Design reply form component', () => {
});
});
- describe('when form has text', () => {
- beforeEach(() => {
- createComponent({
- value: 'test',
- });
- });
-
+ describe('when the form has text', () => {
it('submit button is enabled', () => {
+ createComponent({ props: { value: mockComment } });
expect(findSubmitButton().attributes().disabled).toBeUndefined();
});
- it('emits submitForm event on Comment button click', async () => {
- const autosaveResetSpy = jest.spyOn(Autosave.prototype, 'reset');
+ it('calls a mutation on submit button click event', async () => {
+ const mockMutationVariables = {
+ noteableId: mockNoteableId,
+ discussionId: mockDiscussionId,
+ };
+ const successfulMutation = jest.fn().mockResolvedValue(mockNoteSubmitSuccessMutationResponse);
+ createComponent({
+ props: {
+ designNoteMutation: createNoteMutation,
+ mutationVariables: mockMutationVariables,
+ value: mockComment,
+ },
+ mutation: successfulMutation,
+ });
findSubmitButton().vm.$emit('click');
await nextTick();
- expect(wrapper.emitted('submit-form')).toHaveLength(1);
- expect(autosaveResetSpy).toHaveBeenCalled();
- });
+ expect(successfulMutation).toHaveBeenCalledWith(createNoteMutationData);
- it('emits submitForm event on textarea ctrl+enter keydown', async () => {
- const autosaveResetSpy = jest.spyOn(Autosave.prototype, 'reset');
+ await waitForPromises();
+ expect(wrapper.emitted('note-submit-complete')).toEqual([
+ [mockNoteSubmitSuccessMutationResponse],
+ ]);
+ });
- findTextarea().trigger('keydown.enter', {
- ctrlKey: true,
+ it.each`
+ key | keyData
+ ${'ctrl'} | ${ctrlKey}
+ ${'meta'} | ${metaKey}
+ `('does perform mutation on textarea $key+enter keydown', async ({ keyData }) => {
+ const mockMutationVariables = {
+ noteableId: mockNoteableId,
+ discussionId: mockDiscussionId,
+ };
+ const successfulMutation = jest.fn().mockResolvedValue(mockNoteSubmitSuccessMutationResponse);
+ createComponent({
+ props: {
+ designNoteMutation: createNoteMutation,
+ mutationVariables: mockMutationVariables,
+ value: mockComment,
+ },
+ mutation: successfulMutation,
});
+ findTextarea().trigger('keydown.enter', keyData);
+
await nextTick();
- expect(wrapper.emitted('submit-form')).toHaveLength(1);
- expect(autosaveResetSpy).toHaveBeenCalled();
- });
+ expect(successfulMutation).toHaveBeenCalledWith(createNoteMutationData);
- it('emits submitForm event on textarea meta+enter keydown', async () => {
- const autosaveResetSpy = jest.spyOn(Autosave.prototype, 'reset');
+ await waitForPromises();
+ expect(wrapper.emitted('note-submit-complete')).toEqual([
+ [mockNoteSubmitSuccessMutationResponse],
+ ]);
+ });
- findTextarea().trigger('keydown.enter', {
- metaKey: true,
+ it('shows error message when mutation fails', async () => {
+ const failedMutation = jest.fn().mockRejectedValue(mockNoteSubmitFailureMutationResponse);
+ createComponent({
+ props: {
+ designNoteMutation: createNoteMutation,
+ value: mockComment,
+ },
+ mutation: failedMutation,
+ data: {
+ errorMessage: 'error',
+ },
});
- await nextTick();
- expect(wrapper.emitted('submit-form')).toHaveLength(1);
- expect(autosaveResetSpy).toHaveBeenCalled();
- });
-
- it('emits input event on changing textarea content', async () => {
- findTextarea().setValue('test2');
+ findSubmitButton().vm.$emit('click');
- await nextTick();
- expect(wrapper.emitted('input')).toEqual([['test2']]);
+ await waitForPromises();
+ expect(findAlert().exists()).toBe(true);
});
+ it.each`
+ isDiscussion | isNewComment | errorMessage
+ ${true} | ${true} | ${ADD_IMAGE_DIFF_NOTE_ERROR}
+ ${true} | ${false} | ${UPDATE_IMAGE_DIFF_NOTE_ERROR}
+ ${false} | ${true} | ${ADD_DISCUSSION_COMMENT_ERROR}
+ ${false} | ${false} | ${UPDATE_NOTE_ERROR}
+ `(
+ 'return proper error message on error in case of isDiscussion is $isDiscussion and isNewComment is $isNewComment',
+ async ({ isDiscussion, isNewComment, errorMessage }) => {
+ createComponent({ props: { isDiscussion, isNewComment } });
+
+ expect(wrapper.vm.getErrorMessage()).toBe(errorMessage);
+ },
+ );
+
it('emits cancelForm event on Escape key if text was not changed', () => {
+ createComponent();
+
findTextarea().trigger('keyup.esc');
expect(wrapper.emitted('cancel-form')).toHaveLength(1);
});
it('opens confirmation modal on Escape key when text has changed', async () => {
- wrapper.setProps({ value: 'test2' });
+ createComponent();
+
+ findTextarea().setValue(mockComment);
await nextTick();
findTextarea().trigger('keyup.esc');
- expect(confirmAction).toHaveBeenCalled();
- });
-
- it('emits cancelForm event on Cancel button click if text was not changed', () => {
- findCancelButton().trigger('click');
- expect(wrapper.emitted('cancel-form')).toHaveLength(1);
- });
-
- it('opens confirmation modal on Cancel button click when text has changed', async () => {
- wrapper.setProps({ value: 'test2' });
-
- await nextTick();
- findCancelButton().trigger('click');
expect(confirmAction).toHaveBeenCalled();
});
it('emits cancelForm event when confirmed', async () => {
confirmAction.mockResolvedValueOnce(true);
- const autosaveResetSpy = jest.spyOn(Autosave.prototype, 'reset');
- wrapper.setProps({ value: 'test3' });
- await nextTick();
+ createComponent({ props: { value: mockComment } });
+ findTextarea().setValue('Comment changed');
- findTextarea().trigger('keyup.esc');
await nextTick();
+ findTextarea().trigger('keyup.esc');
expect(confirmAction).toHaveBeenCalled();
- await nextTick();
+ await waitForPromises();
expect(wrapper.emitted('cancel-form')).toHaveLength(1);
- expect(autosaveResetSpy).toHaveBeenCalled();
});
- it("doesn't emit cancelForm event when not confirmed", async () => {
+ it('does not emit cancelForm event when not confirmed', async () => {
confirmAction.mockResolvedValueOnce(false);
- const autosaveResetSpy = jest.spyOn(Autosave.prototype, 'reset');
- wrapper.setProps({ value: 'test3' });
+ createComponent({ props: { value: mockComment } });
+ findTextarea().setValue('Comment changed');
await nextTick();
findTextarea().trigger('keyup.esc');
await nextTick();
expect(confirmAction).toHaveBeenCalled();
- await nextTick();
+ await waitForPromises();
expect(wrapper.emitted('cancel-form')).toBeUndefined();
- expect(autosaveResetSpy).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when component is destroyed', () => {
+ it('calls autosave.reset', async () => {
+ const autosaveResetSpy = jest.spyOn(Autosave.prototype, 'reset');
+ createComponent();
+ await wrapper.destroy();
+ expect(autosaveResetSpy).toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/design_management/components/design_notes/toggle_replies_widget_spec.js b/spec/frontend/design_management/components/design_notes/toggle_replies_widget_spec.js
index 41129e2b58d..eaa5a620fa6 100644
--- a/spec/frontend/design_management/components/design_notes/toggle_replies_widget_spec.js
+++ b/spec/frontend/design_management/components/design_notes/toggle_replies_widget_spec.js
@@ -23,10 +23,6 @@ describe('Toggle replies widget component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when replies are collapsed', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/design_management/components/design_presentation_spec.js b/spec/frontend/design_management/components/design_presentation_spec.js
index 4a339899473..fdcea6d88c0 100644
--- a/spec/frontend/design_management/components/design_presentation_spec.js
+++ b/spec/frontend/design_management/components/design_presentation_spec.js
@@ -15,7 +15,6 @@ const mockOverlayData = {
};
describe('Design management design presentation component', () => {
- const originalGon = window.gon;
let wrapper;
function createComponent(
@@ -114,11 +113,6 @@ describe('Design management design presentation component', () => {
window.gon = { current_user_id: 1 };
});
- afterEach(() => {
- wrapper.destroy();
- window.gon = originalGon;
- });
-
it('renders image and overlay when image provided', async () => {
createComponent(
{
diff --git a/spec/frontend/design_management/components/design_scaler_spec.js b/spec/frontend/design_management/components/design_scaler_spec.js
index e1a66cea329..62a26a8f5dd 100644
--- a/spec/frontend/design_management/components/design_scaler_spec.js
+++ b/spec/frontend/design_management/components/design_scaler_spec.js
@@ -25,11 +25,6 @@ describe('Design management design scaler component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when `scale` value is greater than 1', () => {
beforeEach(async () => {
setScale(1.6);
diff --git a/spec/frontend/design_management/components/design_sidebar_spec.js b/spec/frontend/design_management/components/design_sidebar_spec.js
index af995f75ddc..90424175417 100644
--- a/spec/frontend/design_management/components/design_sidebar_spec.js
+++ b/spec/frontend/design_management/components/design_sidebar_spec.js
@@ -29,7 +29,6 @@ const $route = {
const mutate = jest.fn().mockResolvedValue();
describe('Design management design sidebar component', () => {
- const originalGon = window.gon;
let wrapper;
const findDiscussions = () => wrapper.findAllComponents(DesignDiscussion);
@@ -67,11 +66,6 @@ describe('Design management design sidebar component', () => {
window.gon = { current_user_id: 1 };
});
- afterEach(() => {
- wrapper.destroy();
- window.gon = originalGon;
- });
-
it('renders participants', () => {
createComponent();
@@ -143,8 +137,8 @@ describe('Design management design sidebar component', () => {
expect(findResolvedCommentsToggle().props('visible')).toBe(true);
});
- it('sends a mutation to set an active discussion when clicking on a discussion', () => {
- findFirstDiscussion().trigger('click');
+ it('emits correct event to send a mutation to set an active discussion when clicking on a discussion', () => {
+ findFirstDiscussion().vm.$emit('update-active-discussion');
expect(mutate).toHaveBeenCalledWith(updateActiveDiscussionMutationVariables);
});
diff --git a/spec/frontend/design_management/components/design_todo_button_spec.js b/spec/frontend/design_management/components/design_todo_button_spec.js
index ac26873b692..f713203c0ee 100644
--- a/spec/frontend/design_management/components/design_todo_button_spec.js
+++ b/spec/frontend/design_management/components/design_todo_button_spec.js
@@ -51,8 +51,6 @@ describe('Design management design todo button', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
jest.clearAllMocks();
});
diff --git a/spec/frontend/design_management/components/image_spec.js b/spec/frontend/design_management/components/image_spec.js
index 95d2ad504de..53abcc559d8 100644
--- a/spec/frontend/design_management/components/image_spec.js
+++ b/spec/frontend/design_management/components/image_spec.js
@@ -20,10 +20,6 @@ describe('Design management large image component', () => {
stubPerformanceWebAPI();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders loading state', () => {
createComponent({
isLoading: true,
diff --git a/spec/frontend/design_management/components/list/item_spec.js b/spec/frontend/design_management/components/list/item_spec.js
index e907e2e4ac5..4a0ad5a045b 100644
--- a/spec/frontend/design_management/components/list/item_spec.js
+++ b/spec/frontend/design_management/components/list/item_spec.js
@@ -54,10 +54,6 @@ describe('Design management list item component', () => {
);
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when item is not in view', () => {
it('image is not rendered', () => {
createComponent();
diff --git a/spec/frontend/design_management/components/toolbar/design_navigation_spec.js b/spec/frontend/design_management/components/toolbar/design_navigation_spec.js
index 38a7fadee79..8427d83ceee 100644
--- a/spec/frontend/design_management/components/toolbar/design_navigation_spec.js
+++ b/spec/frontend/design_management/components/toolbar/design_navigation_spec.js
@@ -34,10 +34,6 @@ describe('Design management pagination component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('hides components when designs are empty', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/design_management/components/toolbar/index_spec.js b/spec/frontend/design_management/components/toolbar/index_spec.js
index 1776405ece9..764ad73805f 100644
--- a/spec/frontend/design_management/components/toolbar/index_spec.js
+++ b/spec/frontend/design_management/components/toolbar/index_spec.js
@@ -1,12 +1,18 @@
import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import VueRouter from 'vue-router';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import permissionsQuery from 'shared_queries/design_management/design_permissions.query.graphql';
import DeleteButton from '~/design_management/components/delete_button.vue';
import Toolbar from '~/design_management/components/toolbar/index.vue';
import { DESIGNS_ROUTE_NAME } from '~/design_management/router/constants';
+import { getPermissionsQueryResponse } from '../../mock_data/apollo_mock';
Vue.use(VueRouter);
+Vue.use(VueApollo);
const router = new VueRouter();
const RouterLinkStub = {
@@ -27,7 +33,12 @@ describe('Design management toolbar component', () => {
const updatedAt = new Date();
updatedAt.setHours(updatedAt.getHours() - 1);
+ const mockApollo = createMockApollo([
+ [permissionsQuery, jest.fn().mockResolvedValue(getPermissionsQueryResponse(createDesign))],
+ ]);
+
wrapper = shallowMount(Toolbar, {
+ apolloProvider: mockApollo,
router,
propsData: {
id: '1',
@@ -46,31 +57,20 @@ describe('Design management toolbar component', () => {
'router-link': RouterLinkStub,
},
});
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- permissions: {
- createDesign,
- },
- });
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders design and updated data', async () => {
createComponent();
- await nextTick();
+ await waitForPromises();
+
expect(wrapper.element).toMatchSnapshot();
});
it('links back to designs list', async () => {
createComponent();
- await nextTick();
+ await waitForPromises();
const link = wrapper.find('a');
expect(link.props('to')).toEqual({
@@ -84,35 +84,41 @@ describe('Design management toolbar component', () => {
it('renders delete button on latest designs version with logged in user', async () => {
createComponent();
- await nextTick();
+ await waitForPromises();
+
expect(wrapper.findComponent(DeleteButton).exists()).toBe(true);
});
it('does not render delete button on non-latest version', async () => {
createComponent(false, true, { isLatestVersion: false });
- await nextTick();
+ await waitForPromises();
+
expect(wrapper.findComponent(DeleteButton).exists()).toBe(false);
});
it('does not render delete button when user is not logged in', async () => {
createComponent(false, false);
- await nextTick();
+ await waitForPromises();
+
expect(wrapper.findComponent(DeleteButton).exists()).toBe(false);
});
it('emits `delete` event on deleteButton `delete-selected-designs` event', async () => {
createComponent();
- await nextTick();
+ await waitForPromises();
+
wrapper.findComponent(DeleteButton).vm.$emit('delete-selected-designs');
expect(wrapper.emitted().delete).toHaveLength(1);
});
- it('renders download button with correct link', () => {
+ it('renders download button with correct link', async () => {
createComponent();
+ await waitForPromises();
+
expect(wrapper.findComponent(GlButton).attributes('href')).toBe(
'/-/designs/306/7f747adcd4693afadbe968d7ba7d983349b9012d',
);
diff --git a/spec/frontend/design_management/components/upload/button_spec.js b/spec/frontend/design_management/components/upload/button_spec.js
index 59821218ab8..ceae7920e0d 100644
--- a/spec/frontend/design_management/components/upload/button_spec.js
+++ b/spec/frontend/design_management/components/upload/button_spec.js
@@ -14,10 +14,6 @@ describe('Design management upload button component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders upload design button', () => {
createComponent();
diff --git a/spec/frontend/design_management/components/upload/design_version_dropdown_spec.js b/spec/frontend/design_management/components/upload/design_version_dropdown_spec.js
index 6ad10e707ab..cdfff61ba4f 100644
--- a/spec/frontend/design_management/components/upload/design_version_dropdown_spec.js
+++ b/spec/frontend/design_management/components/upload/design_version_dropdown_spec.js
@@ -42,10 +42,6 @@ describe('Design management design version dropdown component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
const findAllListboxItems = () => wrapper.findAllComponents(GlListboxItem);
const findVersionLink = (index) => wrapper.findAllComponents(GlListboxItem).at(index);
diff --git a/spec/frontend/design_management/mock_data/apollo_mock.js b/spec/frontend/design_management/mock_data/apollo_mock.js
index 2a43b5debee..2b99dcf14da 100644
--- a/spec/frontend/design_management/mock_data/apollo_mock.js
+++ b/spec/frontend/design_management/mock_data/apollo_mock.js
@@ -91,7 +91,7 @@ export const designUploadMutationUpdatedResponse = {
},
};
-export const permissionsQueryResponse = {
+export const getPermissionsQueryResponse = (createDesign = true) => ({
data: {
project: {
__typename: 'Project',
@@ -99,11 +99,11 @@ export const permissionsQueryResponse = {
issue: {
__typename: 'Issue',
id: 'issue-1',
- userPermissions: { __typename: 'UserPermissions', createDesign: true },
+ userPermissions: { __typename: 'UserPermissions', createDesign },
},
},
},
-};
+});
export const reorderedDesigns = [
{
@@ -211,3 +211,109 @@ export const getDesignQueryResponse = {
},
},
};
+
+export const mockNoteSubmitSuccessMutationResponse = [
+ {
+ data: {
+ createNote: {
+ note: {
+ id: 'gid://gitlab/DiffNote/468',
+ author: {
+ id: 'gid://gitlab/User/1',
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ body: 'New comment',
+ bodyHtml: "<p data-sourcepos='1:1-1:4' dir='auto'>asdd</p>",
+ createdAt: '2023-02-24T06:49:20Z',
+ resolved: false,
+ position: {
+ diffRefs: {
+ baseSha: 'f63ae53ed82d8765477c191383e1e6a000c10375',
+ startSha: 'f63ae53ed82d8765477c191383e1e6a000c10375',
+ headSha: 'f348c652f1a737151fc79047895e695fbe81464c',
+ __typename: 'DiffRefs',
+ },
+ x: 441,
+ y: 128,
+ height: 152,
+ width: 695,
+ __typename: 'DiffPosition',
+ },
+ userPermissions: {
+ adminNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ discussion: {
+ id: 'gid://gitlab/Discussion/6466a72f35b163f3c3e52d7976a09387f2c573e8',
+ notes: {
+ nodes: [
+ {
+ id: 'gid://gitlab/DiffNote/459',
+ __typename: 'Note',
+ },
+ ],
+ __typename: 'NoteConnection',
+ },
+ __typename: 'Discussion',
+ },
+ __typename: 'Note',
+ },
+ errors: [],
+ __typename: 'CreateNotePayload',
+ },
+ },
+ },
+];
+
+export const mockNoteSubmitFailureMutationResponse = [
+ {
+ errors: [
+ {
+ message:
+ 'Variable $input of type CreateNoteInput! was provided invalid value for bodyaa (Field is not defined on CreateNoteInput), body (Expected value to not be null)',
+ locations: [
+ {
+ line: 1,
+ column: 21,
+ },
+ ],
+ extensions: {
+ value: {
+ noteableId: 'gid://gitlab/DesignManagement::Design/10',
+ discussionId: 'gid://gitlab/Discussion/6466a72f35b163f3c3e52d7976a09387f2c573e8',
+ bodyaa: 'df',
+ },
+ problems: [
+ {
+ path: ['bodyaa'],
+ explanation: 'Field is not defined on CreateNoteInput',
+ },
+ {
+ path: ['body'],
+ explanation: 'Expected value to not be null',
+ },
+ ],
+ },
+ },
+ ],
+ },
+];
+
+export const mockCreateImageNoteDiffResponse = {
+ data: {
+ createImageDiffNote: {
+ note: {
+ author: {
+ username: '',
+ },
+ discussion: {},
+ },
+ },
+ },
+};
diff --git a/spec/frontend/design_management/mock_data/project.js b/spec/frontend/design_management/mock_data/project.js
new file mode 100644
index 00000000000..e1c2057d8d1
--- /dev/null
+++ b/spec/frontend/design_management/mock_data/project.js
@@ -0,0 +1,17 @@
+import design from './design';
+
+export default {
+ project: {
+ issue: {
+ designCollection: {
+ designs: {
+ nodes: [
+ {
+ ...design,
+ },
+ ],
+ },
+ },
+ },
+ },
+};
diff --git a/spec/frontend/design_management/pages/design/index_spec.js b/spec/frontend/design_management/pages/design/index_spec.js
index a11463ab663..6cec4036d40 100644
--- a/spec/frontend/design_management/pages/design/index_spec.js
+++ b/spec/frontend/design_management/pages/design/index_spec.js
@@ -1,15 +1,14 @@
import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
-import { ApolloMutation } from 'vue-apollo';
import VueRouter from 'vue-router';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import Api from '~/api';
import DesignPresentation from '~/design_management/components/design_presentation.vue';
import DesignSidebar from '~/design_management/components/design_sidebar.vue';
import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management/constants';
-import createImageDiffNoteMutation from '~/design_management/graphql/mutations/create_image_diff_note.mutation.graphql';
import updateActiveDiscussion from '~/design_management/graphql/mutations/update_active_discussion.mutation.graphql';
+import getDesignQuery from '~/design_management/graphql/queries/get_design.query.graphql';
import DesignIndex from '~/design_management/pages/design/index.vue';
import createRouter from '~/design_management/router';
import { DESIGNS_ROUTE_NAME, DESIGN_ROUTE_NAME } from '~/design_management/router/constants';
@@ -23,16 +22,23 @@ import {
DESIGN_SNOWPLOW_EVENT_TYPES,
DESIGN_SERVICE_PING_EVENT_TYPES,
} from '~/design_management/utils/tracking';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import * as cacheUpdate from '~/design_management/utils/cache_update';
import mockAllVersions from '../../mock_data/all_versions';
import design from '../../mock_data/design';
+import mockProject from '../../mock_data/project';
import mockResponseWithDesigns from '../../mock_data/designs';
import mockResponseNoDesigns from '../../mock_data/no_designs';
+import { mockCreateImageNoteDiffResponse } from '../../mock_data/apollo_mock';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/api.js');
const focusInput = jest.fn();
+const mockCacheObject = {
+ readQuery: jest.fn().mockReturnValue(mockProject),
+ writeQuery: jest.fn(),
+};
const mutate = jest.fn().mockResolvedValue();
const mockPageLayoutElement = {
classList: {
@@ -52,32 +58,13 @@ const mockDesignNoDiscussions = {
nodes: [],
},
};
-const newComment = 'new comment';
+
const annotationCoordinates = {
x: 10,
y: 10,
width: 100,
height: 100,
};
-const createDiscussionMutationVariables = {
- mutation: createImageDiffNoteMutation,
- update: expect.anything(),
- variables: {
- input: {
- body: newComment,
- noteableId: design.id,
- position: {
- headSha: 'headSha',
- baseSha: 'baseSha',
- startSha: 'startSha',
- paths: {
- newPath: 'full-design-path',
- },
- ...annotationCoordinates,
- },
- },
- },
-};
Vue.use(VueRouter);
@@ -85,7 +72,7 @@ describe('Design management design index page', () => {
let wrapper;
let router;
- const findDiscussionForm = () => wrapper.findComponent(DesignReplyForm);
+ const findDesignReplyForm = () => wrapper.findComponent(DesignReplyForm);
const findSidebar = () => wrapper.findComponent(DesignSidebar);
const findDesignPresentation = () => wrapper.findComponent(DesignPresentation);
@@ -95,7 +82,7 @@ describe('Design management design index page', () => {
data = {},
intialRouteOptions = {},
provide = {},
- stubs = { ApolloMutation, DesignSidebar, DesignReplyForm },
+ stubs = { DesignSidebar, DesignReplyForm },
} = {},
) {
const $apollo = {
@@ -105,6 +92,11 @@ describe('Design management design index page', () => {
},
},
mutate,
+ getClient() {
+ return {
+ cache: mockCacheObject,
+ };
+ },
};
router = createRouter();
@@ -133,10 +125,6 @@ describe('Design management design index page', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when navigating to component', () => {
it('applies fullscreen layout class', () => {
jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockPageLayoutElement);
@@ -216,7 +204,7 @@ describe('Design management design index page', () => {
findDesignPresentation().vm.$emit('openCommentForm', { x: 0, y: 0 });
await nextTick();
- expect(findDiscussionForm().exists()).toBe(true);
+ expect(findDesignReplyForm().exists()).toBe(true);
});
it('keeps new discussion form focused', () => {
@@ -235,24 +223,36 @@ describe('Design management design index page', () => {
expect(focusInput).toHaveBeenCalled();
});
- it('sends a mutation on submitting form and closes form', async () => {
+ it('sends a update and closes the form when mutation is completed', async () => {
createComponent(
{ loading: false },
{
data: {
design,
annotationCoordinates,
- comment: newComment,
},
},
);
- findDiscussionForm().vm.$emit('submit-form');
- expect(mutate).toHaveBeenCalledWith(createDiscussionMutationVariables);
+ const addImageDiffNoteToStore = jest.spyOn(cacheUpdate, 'updateStoreAfterAddImageDiffNote');
+
+ const mockDesignVariables = {
+ fullPath: 'project-path',
+ iid: '1',
+ filenames: ['gid::/gitlab/Design/1'],
+ atVersion: null,
+ };
+
+ findDesignReplyForm().vm.$emit('note-submit-complete', mockCreateImageNoteDiffResponse);
await nextTick();
- await mutate({ variables: createDiscussionMutationVariables });
- expect(findDiscussionForm().exists()).toBe(false);
+ expect(addImageDiffNoteToStore).toHaveBeenCalledWith(
+ mockCacheObject,
+ mockCreateImageNoteDiffResponse.data.createImageDiffNote,
+ getDesignQuery,
+ mockDesignVariables,
+ );
+ expect(findDesignReplyForm().exists()).toBe(false);
});
it('closes the form and clears the comment on canceling form', async () => {
@@ -262,17 +262,14 @@ describe('Design management design index page', () => {
data: {
design,
annotationCoordinates,
- comment: newComment,
},
},
);
- findDiscussionForm().vm.$emit('cancel-form');
-
- expect(wrapper.vm.comment).toBe('');
+ findDesignReplyForm().vm.$emit('cancel-form');
await nextTick();
- expect(findDiscussionForm().exists()).toBe(false);
+ expect(findDesignReplyForm().exists()).toBe(false);
});
describe('with error', () => {
diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js
index 76ece922ded..1ddf757eb19 100644
--- a/spec/frontend/design_management/pages/index_spec.js
+++ b/spec/frontend/design_management/pages/index_spec.js
@@ -29,19 +29,19 @@ import {
DESIGN_TRACKING_PAGE_NAME,
DESIGN_SNOWPLOW_EVENT_TYPES,
} from '~/design_management/utils/tracking';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import DesignDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
import {
designListQueryResponse,
designUploadMutationCreatedResponse,
designUploadMutationUpdatedResponse,
- permissionsQueryResponse,
+ getPermissionsQueryResponse,
moveDesignMutationResponse,
reorderedDesigns,
moveDesignMutationResponseWithErrors,
} from '../mock_data/apollo_mock';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
const mockPageEl = {
classList: {
remove: jest.fn(),
@@ -181,7 +181,7 @@ describe('Design management index page', () => {
const requestHandlers = [
[getDesignListQuery, jest.fn().mockResolvedValue(designListQueryResponse)],
- [permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
+ [permissionsQuery, jest.fn().mockResolvedValue(getPermissionsQueryResponse())],
[moveDesignMutation, moveDesignHandler],
];
@@ -197,11 +197,6 @@ describe('Design management index page', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('designs', () => {
it('renders loading icon', () => {
createComponent({ loading: true });
@@ -800,7 +795,7 @@ describe('Design management index page', () => {
expect(draggableAttributes().disabled).toBe(false);
});
- it('displays flash if mutation had a recoverable error', async () => {
+ it('displays alert if mutation had a recoverable error', async () => {
createComponentWithApollo({
moveHandler: jest.fn().mockResolvedValue(moveDesignMutationResponseWithErrors),
});
diff --git a/spec/frontend/design_management/router_spec.js b/spec/frontend/design_management/router_spec.js
index b9edde559c8..3503725f741 100644
--- a/spec/frontend/design_management/router_spec.js
+++ b/spec/frontend/design_management/router_spec.js
@@ -11,8 +11,6 @@ import '~/commons/bootstrap';
function factory(routeArg) {
Vue.use(VueRouter);
- window.gon = { sprite_icons: '' };
-
const router = createRouter('/');
if (routeArg !== undefined) {
router.push(routeArg);
@@ -36,10 +34,6 @@ function factory(routeArg) {
}
describe('Design management router', () => {
- afterEach(() => {
- window.location.hash = '';
- });
-
describe.each([['/'], [{ name: DESIGNS_ROUTE_NAME }]])('root route', (routeArg) => {
it('pushes home component', () => {
const wrapper = factory(routeArg);
diff --git a/spec/frontend/design_management/utils/cache_update_spec.js b/spec/frontend/design_management/utils/cache_update_spec.js
index 42777adfd58..e89dfe9f860 100644
--- a/spec/frontend/design_management/utils/cache_update_spec.js
+++ b/spec/frontend/design_management/utils/cache_update_spec.js
@@ -10,10 +10,10 @@ import {
ADD_IMAGE_DIFF_NOTE_ERROR,
UPDATE_IMAGE_DIFF_NOTE_ERROR,
} from '~/design_management/utils/error_messages';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import design from '../mock_data/design';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
describe('Design Management cache update', () => {
const mockErrors = ['code red!'];
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index 513e67ea247..06995706a2b 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -59,6 +59,7 @@ describe('diffs/components/app', () => {
endpoint: TEST_ENDPOINT,
endpointMetadata: `${TEST_HOST}/diff/endpointMetadata`,
endpointBatch: `${TEST_HOST}/diff/endpointBatch`,
+ endpointDiffForPath: TEST_ENDPOINT,
endpointCoverage: `${TEST_HOST}/diff/endpointCoverage`,
endpointCodequality: '',
projectPath: 'namespace/project',
@@ -71,12 +72,6 @@ describe('diffs/components/app', () => {
},
provide,
store,
- stubs: {
- DynamicScroller: {
- template: `<div><slot :item="$store.state.diffs.diffFiles[0]"></slot></div>`,
- },
- DynamicScrollerItem: true,
- },
});
}
@@ -265,7 +260,7 @@ describe('diffs/components/app', () => {
it('sets width of tree list', () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles = [{ file_hash: '111', file_path: '111.js' }];
+ state.diffs.treeEntries = { 111: { type: 'blob', fileHash: '111', path: '111.js' } };
});
expect(wrapper.find('.js-diff-tree-list').element.style.width).toEqual('320px');
@@ -294,13 +289,14 @@ describe('diffs/components/app', () => {
it('does not render empty state when diff files exist', () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles.push({
- id: 1,
- });
+ state.diffs.diffFiles = ['anything'];
+ state.diffs.treeEntries['1'] = { type: 'blob', id: 1 };
});
expect(wrapper.findComponent(NoChanges).exists()).toBe(false);
- expect(wrapper.findAllComponents(DiffFile).length).toBe(1);
+ expect(wrapper.findComponent({ name: 'DynamicScroller' }).props('items')).toBe(
+ store.state.diffs.diffFiles,
+ );
});
});
@@ -388,19 +384,15 @@ describe('diffs/components/app', () => {
beforeEach(() => {
createComponent({}, () => {
- store.state.diffs.diffFiles = [
- { file_hash: '111', file_path: '111.js' },
- { file_hash: '222', file_path: '222.js' },
- { file_hash: '333', file_path: '333.js' },
+ store.state.diffs.treeEntries = [
+ { type: 'blob', fileHash: '111', path: '111.js' },
+ { type: 'blob', fileHash: '222', path: '222.js' },
+ { type: 'blob', fileHash: '333', path: '333.js' },
];
});
spy = jest.spyOn(store, 'dispatch');
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('jumps to next and previous files in the list', async () => {
await nextTick();
@@ -507,7 +499,6 @@ describe('diffs/components/app', () => {
describe('diffs', () => {
it('should render compare versions component', () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles = [{ file_hash: '111', file_path: '111.js' }];
state.diffs.mergeRequestDiffs = diffsMockData;
state.diffs.targetBranchName = 'target-branch';
state.diffs.mergeRequestDiff = mergeRequestDiff;
@@ -578,10 +569,18 @@ describe('diffs/components/app', () => {
it('should display diff file if there are diff files', () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles.push({ sha: '123' });
+ state.diffs.diffFiles = [{ file_hash: '111', file_path: '111.js' }];
+ state.diffs.treeEntries = {
+ 111: { type: 'blob', fileHash: '111', path: '111.js' },
+ 123: { type: 'blob', fileHash: '123', path: '123.js' },
+ 312: { type: 'blob', fileHash: '312', path: '312.js' },
+ };
});
- expect(wrapper.findComponent(DiffFile).exists()).toBe(true);
+ expect(wrapper.findComponent({ name: 'DynamicScroller' }).exists()).toBe(true);
+ expect(wrapper.findComponent({ name: 'DynamicScroller' }).props('items')).toBe(
+ store.state.diffs.diffFiles,
+ );
});
it("doesn't render tree list when no changes exist", () => {
@@ -592,7 +591,7 @@ describe('diffs/components/app', () => {
it('should render tree list', () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles = [{ file_hash: '111', file_path: '111.js' }];
+ state.diffs.treeEntries = { 111: { type: 'blob', fileHash: '111', path: '111.js' } };
});
expect(wrapper.findComponent(TreeList).exists()).toBe(true);
@@ -606,7 +605,7 @@ describe('diffs/components/app', () => {
it('calls setShowTreeList when only 1 file', () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles.push({ sha: '123' });
+ state.diffs.treeEntries = { 123: { type: 'blob', fileHash: '123' } };
});
jest.spyOn(store, 'dispatch');
wrapper.vm.setTreeDisplay();
@@ -617,10 +616,12 @@ describe('diffs/components/app', () => {
});
});
- it('calls setShowTreeList with true when more than 1 file is in diffs array', () => {
+ it('calls setShowTreeList with true when more than 1 file is in tree entries map', () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles.push({ sha: '123' });
- state.diffs.diffFiles.push({ sha: '124' });
+ state.diffs.treeEntries = {
+ 111: { type: 'blob', fileHash: '111', path: '111.js' },
+ 123: { type: 'blob', fileHash: '123', path: '123.js' },
+ };
});
jest.spyOn(store, 'dispatch');
@@ -640,7 +641,7 @@ describe('diffs/components/app', () => {
localStorage.setItem('mr_tree_show', showTreeList);
createComponent({}, ({ state }) => {
- state.diffs.diffFiles.push({ sha: '123' });
+ state.diffs.treeEntries['123'] = { sha: '123' };
});
jest.spyOn(store, 'dispatch');
@@ -656,7 +657,10 @@ describe('diffs/components/app', () => {
describe('file-by-file', () => {
it('renders a single diff', async () => {
createComponent({ fileByFileUserPreference: true }, ({ state }) => {
- state.diffs.diffFiles.push({ file_hash: '123' });
+ state.diffs.treeEntries = {
+ 123: { type: 'blob', fileHash: '123' },
+ 312: { type: 'blob', fileHash: '312' },
+ };
state.diffs.diffFiles.push({ file_hash: '312' });
});
@@ -671,7 +675,10 @@ describe('diffs/components/app', () => {
it('sets previous button as disabled', async () => {
createComponent({ fileByFileUserPreference: true }, ({ state }) => {
- state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });
+ state.diffs.treeEntries = {
+ 123: { type: 'blob', fileHash: '123' },
+ 312: { type: 'blob', fileHash: '312' },
+ };
});
await nextTick();
@@ -682,7 +689,10 @@ describe('diffs/components/app', () => {
it('sets next button as disabled', async () => {
createComponent({ fileByFileUserPreference: true }, ({ state }) => {
- state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });
+ state.diffs.treeEntries = {
+ 123: { type: 'blob', fileHash: '123' },
+ 312: { type: 'blob', fileHash: '312' },
+ };
state.diffs.currentDiffFileId = '312';
});
@@ -694,7 +704,7 @@ describe('diffs/components/app', () => {
it("doesn't display when there's fewer than 2 files", async () => {
createComponent({ fileByFileUserPreference: true }, ({ state }) => {
- state.diffs.diffFiles.push({ file_hash: '123' });
+ state.diffs.treeEntries = { 123: { type: 'blob', fileHash: '123' } };
state.diffs.currentDiffFileId = '123';
});
@@ -711,7 +721,10 @@ describe('diffs/components/app', () => {
'calls navigateToDiffFileIndex with $index when $link is clicked',
async ({ currentDiffFileId, targetFile }) => {
createComponent({ fileByFileUserPreference: true }, ({ state }) => {
- state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });
+ state.diffs.treeEntries = {
+ 123: { type: 'blob', fileHash: '123' },
+ 312: { type: 'blob', fileHash: '312' },
+ };
state.diffs.currentDiffFileId = currentDiffFileId;
});
diff --git a/spec/frontend/diffs/components/collapsed_files_warning_spec.js b/spec/frontend/diffs/components/collapsed_files_warning_spec.js
index eca5b536a35..ae40f6c898d 100644
--- a/spec/frontend/diffs/components/collapsed_files_warning_spec.js
+++ b/spec/frontend/diffs/components/collapsed_files_warning_spec.js
@@ -45,10 +45,6 @@ describe('CollapsedFilesWarning', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when there is more than one file', () => {
it.each`
present | dismissed
diff --git a/spec/frontend/diffs/components/commit_item_spec.js b/spec/frontend/diffs/components/commit_item_spec.js
index 08be3fa2745..4b4b6351d3f 100644
--- a/spec/frontend/diffs/components/commit_item_spec.js
+++ b/spec/frontend/diffs/components/commit_item_spec.js
@@ -41,11 +41,6 @@ describe('diffs/components/commit_item', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('default state', () => {
beforeEach(() => {
mountComponent();
diff --git a/spec/frontend/diffs/components/compare_dropdown_layout_spec.js b/spec/frontend/diffs/components/compare_dropdown_layout_spec.js
index 09128b04caa..785ff537777 100644
--- a/spec/frontend/diffs/components/compare_dropdown_layout_spec.js
+++ b/spec/frontend/diffs/components/compare_dropdown_layout_spec.js
@@ -38,11 +38,6 @@ describe('CompareDropdownLayout', () => {
isActive: listItem.classes().includes('is-active'),
}));
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('with versions', () => {
beforeEach(() => {
const versions = [
diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js
index 21f3ee26bf8..23da1a3601b 100644
--- a/spec/frontend/diffs/components/compare_versions_spec.js
+++ b/spec/frontend/diffs/components/compare_versions_spec.js
@@ -58,11 +58,6 @@ describe('CompareVersions', () => {
store.state.diffs.mergeRequestDiffs = diffsMockData;
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('template', () => {
beforeEach(() => {
createWrapper({}, {}, false);
diff --git a/spec/frontend/diffs/components/diff_code_quality_spec.js b/spec/frontend/diffs/components/diff_code_quality_spec.js
index 7bd9afab648..e5ca90eb7c8 100644
--- a/spec/frontend/diffs/components/diff_code_quality_spec.js
+++ b/spec/frontend/diffs/components/diff_code_quality_spec.js
@@ -11,10 +11,6 @@ const findIcon = () => wrapper.findComponent(GlIcon);
const findHeading = () => wrapper.findByTestId(`diff-codequality-findings-heading`);
describe('DiffCodeQuality', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
const createWrapper = (codeQuality, mountFunction = mountExtended) => {
return mountFunction(DiffCodeQuality, {
propsData: {
diff --git a/spec/frontend/diffs/components/diff_content_spec.js b/spec/frontend/diffs/components/diff_content_spec.js
index 0bce6451ce4..3524973278c 100644
--- a/spec/frontend/diffs/components/diff_content_spec.js
+++ b/spec/frontend/diffs/components/diff_content_spec.js
@@ -93,11 +93,6 @@ describe('DiffContent', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('with text based files', () => {
afterEach(() => {
[isParallelViewGetterMock, isInlineViewGetterMock].forEach((m) => m.mockRestore());
diff --git a/spec/frontend/diffs/components/diff_discussion_reply_spec.js b/spec/frontend/diffs/components/diff_discussion_reply_spec.js
index bf4a1a1c1f7..348439d6006 100644
--- a/spec/frontend/diffs/components/diff_discussion_reply_spec.js
+++ b/spec/frontend/diffs/components/diff_discussion_reply_spec.js
@@ -26,10 +26,6 @@ describe('DiffDiscussionReply', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('if user can reply', () => {
beforeEach(() => {
getters = {
diff --git a/spec/frontend/diffs/components/diff_discussions_spec.js b/spec/frontend/diffs/components/diff_discussions_spec.js
index 5092ae6ab6e..73d9f2d6d45 100644
--- a/spec/frontend/diffs/components/diff_discussions_spec.js
+++ b/spec/frontend/diffs/components/diff_discussions_spec.js
@@ -25,10 +25,6 @@ describe('DiffDiscussions', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
it('should have notes list', () => {
createComponent();
diff --git a/spec/frontend/diffs/components/diff_file_header_spec.js b/spec/frontend/diffs/components/diff_file_header_spec.js
index c23eb2f3d24..4515a8e8926 100644
--- a/spec/frontend/diffs/components/diff_file_header_spec.js
+++ b/spec/frontend/diffs/components/diff_file_header_spec.js
@@ -72,8 +72,6 @@ describe('DiffFileHeader component', () => {
diffHasExpandedDiscussionsResultMock,
...Object.values(mockStoreConfig.modules.diffs.actions),
].forEach((mock) => mock.mockReset());
-
- wrapper.destroy();
});
const findHeader = () => wrapper.findComponent({ ref: 'header' });
diff --git a/spec/frontend/diffs/components/diff_file_row_spec.js b/spec/frontend/diffs/components/diff_file_row_spec.js
index c5b76551fcc..66ee4e955b8 100644
--- a/spec/frontend/diffs/components/diff_file_row_spec.js
+++ b/spec/frontend/diffs/components/diff_file_row_spec.js
@@ -13,10 +13,6 @@ describe('Diff File Row component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders file row component', () => {
const sharedProps = {
level: 4,
diff --git a/spec/frontend/diffs/components/diff_file_spec.js b/spec/frontend/diffs/components/diff_file_spec.js
index ccfc36f8f16..93698396450 100644
--- a/spec/frontend/diffs/components/diff_file_spec.js
+++ b/spec/frontend/diffs/components/diff_file_spec.js
@@ -129,8 +129,6 @@ describe('DiffFile', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
axiosMock.restore();
});
@@ -222,21 +220,10 @@ describe('DiffFile', () => {
describe('computed', () => {
describe('showLocalFileReviews', () => {
- let gon;
-
function setLoggedIn(bool) {
window.gon.current_user_id = bool;
}
- beforeAll(() => {
- gon = window.gon;
- window.gon = {};
- });
-
- afterEach(() => {
- window.gon = gon;
- });
-
it.each`
loggedIn | bool
${true} | ${true}
diff --git a/spec/frontend/diffs/components/diff_gutter_avatars_spec.js b/spec/frontend/diffs/components/diff_gutter_avatars_spec.js
index f13988fc11f..5f2b1a81b91 100644
--- a/spec/frontend/diffs/components/diff_gutter_avatars_spec.js
+++ b/spec/frontend/diffs/components/diff_gutter_avatars_spec.js
@@ -21,10 +21,6 @@ describe('DiffGutterAvatars', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when expanded', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/diffs/components/diff_row_spec.js b/spec/frontend/diffs/components/diff_row_spec.js
index a7a95ed2f35..356c7ef925a 100644
--- a/spec/frontend/diffs/components/diff_row_spec.js
+++ b/spec/frontend/diffs/components/diff_row_spec.js
@@ -89,10 +89,6 @@ describe('DiffRow', () => {
};
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
-
- window.gon = {};
showCommentForm.mockReset();
enterdragging.mockReset();
stopdragging.mockReset();
diff --git a/spec/frontend/diffs/components/hidden_files_warning_spec.js b/spec/frontend/diffs/components/hidden_files_warning_spec.js
index bbd4f5faeec..d9359fb3c7b 100644
--- a/spec/frontend/diffs/components/hidden_files_warning_spec.js
+++ b/spec/frontend/diffs/components/hidden_files_warning_spec.js
@@ -23,10 +23,6 @@ describe('HiddenFilesWarning', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has a correct plain diff URL', () => {
const plainDiffLink = wrapper.findAllComponents(GlButton).at(0);
diff --git a/spec/frontend/diffs/components/image_diff_overlay_spec.js b/spec/frontend/diffs/components/image_diff_overlay_spec.js
index ccf942bdcef..18901781587 100644
--- a/spec/frontend/diffs/components/image_diff_overlay_spec.js
+++ b/spec/frontend/diffs/components/image_diff_overlay_spec.js
@@ -36,10 +36,6 @@ describe('Diffs image diff overlay component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders comment badges', () => {
createComponent();
diff --git a/spec/frontend/diffs/components/merge_conflict_warning_spec.js b/spec/frontend/diffs/components/merge_conflict_warning_spec.js
index 4e47249f5b4..715912b361f 100644
--- a/spec/frontend/diffs/components/merge_conflict_warning_spec.js
+++ b/spec/frontend/diffs/components/merge_conflict_warning_spec.js
@@ -25,10 +25,6 @@ describe('MergeConflictWarning', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
present | resolutionPath
${false} | ${''}
diff --git a/spec/frontend/diffs/components/no_changes_spec.js b/spec/frontend/diffs/components/no_changes_spec.js
index dbfe9770e07..e637b1dd43d 100644
--- a/spec/frontend/diffs/components/no_changes_spec.js
+++ b/spec/frontend/diffs/components/no_changes_spec.js
@@ -34,11 +34,6 @@ describe('Diff no changes empty state', () => {
store.state.diffs.mergeRequestDiffs = diffsMockData;
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findMessage = () => wrapper.find('[data-testid="no-changes-message"]');
it('prevents XSS', () => {
diff --git a/spec/frontend/diffs/components/settings_dropdown_spec.js b/spec/frontend/diffs/components/settings_dropdown_spec.js
index 2ec11ba86fd..3d2bbe43746 100644
--- a/spec/frontend/diffs/components/settings_dropdown_spec.js
+++ b/spec/frontend/diffs/components/settings_dropdown_spec.js
@@ -39,7 +39,6 @@ describe('Diff settings dropdown component', () => {
afterEach(() => {
store.dispatch.mockRestore();
- wrapper.destroy();
});
describe('tree view buttons', () => {
diff --git a/spec/frontend/diffs/components/tree_list_spec.js b/spec/frontend/diffs/components/tree_list_spec.js
index 1656eaf8ba0..87c638d065a 100644
--- a/spec/frontend/diffs/components/tree_list_spec.js
+++ b/spec/frontend/diffs/components/tree_list_spec.js
@@ -1,20 +1,36 @@
-import { shallowMount, mount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import TreeList from '~/diffs/components/tree_list.vue';
import createStore from '~/diffs/store/modules';
-import FileTree from '~/vue_shared/components/file_tree.vue';
+import DiffFileRow from '~/diffs/components//diff_file_row.vue';
+import { stubComponent } from 'helpers/stub_component';
describe('Diffs tree list component', () => {
let wrapper;
let store;
- const getFileRows = () => wrapper.findAll('.file-row');
+ const getScroller = () => wrapper.findComponent({ name: 'RecycleScroller' });
+ const getFileRow = () => wrapper.findComponent(DiffFileRow);
Vue.use(Vuex);
- const createComponent = (mountFn = mount) => {
- wrapper = mountFn(TreeList, {
+ const createComponent = () => {
+ wrapper = shallowMount(TreeList, {
store,
propsData: { hideFileStats: false },
+ stubs: {
+ // eslint will fail if we import the real component
+ RecycleScroller: stubComponent(
+ {
+ name: 'RecycleScroller',
+ props: {
+ items: null,
+ },
+ },
+ {
+ template: '<div><slot :item="{ tree: [] }"></slot></div>',
+ },
+ ),
+ },
});
};
@@ -80,10 +96,6 @@ describe('Diffs tree list component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
@@ -101,26 +113,32 @@ describe('Diffs tree list component', () => {
});
describe('search by file extension', () => {
+ it('hides scroller for no matches', async () => {
+ wrapper.find('[data-testid="diff-tree-search"]').setValue('*.md');
+
+ await nextTick();
+
+ expect(getScroller().exists()).toBe(false);
+ expect(wrapper.text()).toContain('No files found');
+ });
+
it.each`
extension | itemSize
- ${'*.md'} | ${0}
- ${'*.js'} | ${1}
- ${'index.js'} | ${1}
- ${'app/*.js'} | ${1}
- ${'*.js, *.rb'} | ${2}
+ ${'*.js'} | ${2}
+ ${'index.js'} | ${2}
+ ${'app/*.js'} | ${2}
+ ${'*.js, *.rb'} | ${3}
`('returns $itemSize item for $extension', async ({ extension, itemSize }) => {
wrapper.find('[data-testid="diff-tree-search"]').setValue(extension);
await nextTick();
- expect(getFileRows()).toHaveLength(itemSize);
+ expect(getScroller().props('items')).toHaveLength(itemSize);
});
});
it('renders tree', () => {
- expect(getFileRows()).toHaveLength(2);
- expect(getFileRows().at(0).html()).toContain('index.js');
- expect(getFileRows().at(1).html()).toContain('app');
+ expect(getScroller().props('items')).toHaveLength(2);
});
it('hides file stats', async () => {
@@ -133,33 +151,16 @@ describe('Diffs tree list component', () => {
it('calls toggleTreeOpen when clicking folder', () => {
jest.spyOn(wrapper.vm.$store, 'dispatch').mockReturnValue(undefined);
- getFileRows().at(1).trigger('click');
+ getFileRow().vm.$emit('toggleTreeOpen', 'app');
expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith('diffs/toggleTreeOpen', 'app');
});
- it('calls scrollToFile when clicking blob', () => {
- jest.spyOn(wrapper.vm.$store, 'dispatch').mockReturnValue(undefined);
-
- wrapper.find('.file-row').trigger('click');
-
- expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith('diffs/scrollToFile', {
- path: 'app/index.js',
- });
- });
-
- it('renders as file list when renderTreeList is false', async () => {
- wrapper.vm.$store.state.diffs.renderTreeList = false;
-
- await nextTick();
- expect(getFileRows()).toHaveLength(2);
- });
-
- it('renders file paths when renderTreeList is false', async () => {
+ it('renders when renderTreeList is false', async () => {
wrapper.vm.$store.state.diffs.renderTreeList = false;
await nextTick();
- expect(wrapper.find('.file-row').html()).toContain('index.js');
+ expect(getScroller().props('items')).toHaveLength(3);
});
});
@@ -172,12 +173,10 @@ describe('Diffs tree list component', () => {
});
it('passes the viewedDiffFileIds to the FileTree', async () => {
- createComponent(shallowMount);
+ createComponent();
await nextTick();
- // Have to use $attrs['viewed-files'] because we are passing down an object
- // and attributes('') stringifies values (e.g. [object])...
- expect(wrapper.findComponent(FileTree).vm.$attrs['viewed-files']).toBe(viewedDiffFileIds);
+ expect(wrapper.findComponent(DiffFileRow).props('viewedFiles')).toBe(viewedDiffFileIds);
});
});
});
diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js
index 78765204322..b00076504e3 100644
--- a/spec/frontend/diffs/store/actions_spec.js
+++ b/spec/frontend/diffs/store/actions_spec.js
@@ -13,7 +13,7 @@ import * as diffActions from '~/diffs/store/actions';
import * as types from '~/diffs/store/mutation_types';
import * as utils from '~/diffs/store/utils';
import * as treeWorkerUtils from '~/diffs/utils/tree_worker_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import * as commonUtils from '~/lib/utils/common_utils';
import {
@@ -26,7 +26,7 @@ import { mergeUrlParams } from '~/lib/utils/url_utility';
import eventHub from '~/notes/event_hub';
import { diffMetadata } from '../mock_data/diff_metadata';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('DiffsStoreActions', () => {
let mock;
@@ -69,6 +69,7 @@ describe('DiffsStoreActions', () => {
const endpoint = '/diffs/set/endpoint';
const endpointMetadata = '/diffs/set/endpoint/metadata';
const endpointBatch = '/diffs/set/endpoint/batch';
+ const endpointDiffForPath = '/diffs/set/endpoint/path';
const endpointCoverage = '/diffs/set/coverage_reports';
const projectPath = '/root/project';
const dismissEndpoint = '/-/user_callouts';
@@ -83,6 +84,7 @@ describe('DiffsStoreActions', () => {
{
endpoint,
endpointBatch,
+ endpointDiffForPath,
endpointMetadata,
endpointCoverage,
projectPath,
@@ -93,6 +95,7 @@ describe('DiffsStoreActions', () => {
{
endpoint: '',
endpointBatch: '',
+ endpointDiffForPath: '',
endpointMetadata: '',
endpointCoverage: '',
projectPath: '',
@@ -106,6 +109,7 @@ describe('DiffsStoreActions', () => {
endpoint,
endpointMetadata,
endpointBatch,
+ endpointDiffForPath,
endpointCoverage,
projectPath,
dismissEndpoint,
@@ -236,13 +240,17 @@ describe('DiffsStoreActions', () => {
it('should show no warning on any other status code', async () => {
mock.onGet(endpointMetadata).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
- await testAction(
- diffActions.fetchDiffFilesMeta,
- {},
- { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
- [{ type: types.SET_LOADING, payload: true }],
- [],
- );
+ try {
+ await testAction(
+ diffActions.fetchDiffFilesMeta,
+ {},
+ { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
+ [{ type: types.SET_LOADING, payload: true }],
+ [],
+ );
+ } catch (error) {
+ expect(error.response.status).toBe(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ }
expect(createAlert).not.toHaveBeenCalled();
});
@@ -265,7 +273,7 @@ describe('DiffsStoreActions', () => {
);
});
- it('should show flash on API error', async () => {
+ it('should show alert on API error', async () => {
mock.onGet(endpointCoverage).reply(HTTP_STATUS_BAD_REQUEST);
await testAction(diffActions.fetchCoverageFiles, {}, { endpointCoverage }, [], []);
@@ -389,7 +397,7 @@ describe('DiffsStoreActions', () => {
return testAction(
diffActions.assignDiscussionsToDiff,
[],
- { diffFiles: [] },
+ { diffFiles: [], flatBlobsList: [] },
[],
[{ type: 'setCurrentDiffFileIdFromNote', payload: '123' }],
);
@@ -1007,20 +1015,14 @@ describe('DiffsStoreActions', () => {
describe('setShowWhitespace', () => {
const endpointUpdateUser = 'user/prefs';
let putSpy;
- let gon;
beforeEach(() => {
putSpy = jest.spyOn(axios, 'put');
- gon = window.gon;
mock.onPut(endpointUpdateUser).reply(HTTP_STATUS_OK, {});
jest.spyOn(eventHub, '$emit').mockImplementation();
});
- afterEach(() => {
- window.gon = gon;
- });
-
it('commits SET_SHOW_WHITESPACE', () => {
return testAction(
diffActions.setShowWhitespace,
@@ -1393,39 +1395,38 @@ describe('DiffsStoreActions', () => {
describe('setCurrentDiffFileIdFromNote', () => {
it('commits SET_CURRENT_DIFF_FILE', () => {
const commit = jest.fn();
- const state = { diffFiles: [{ file_hash: '123' }] };
+ const getters = { flatBlobsList: [{ fileHash: '123' }] };
const rootGetters = {
getDiscussion: () => ({ diff_file: { file_hash: '123' } }),
notesById: { 1: { discussion_id: '2' } },
};
- diffActions.setCurrentDiffFileIdFromNote({ commit, state, rootGetters }, '1');
+ diffActions.setCurrentDiffFileIdFromNote({ commit, getters, rootGetters }, '1');
expect(commit).toHaveBeenCalledWith(types.SET_CURRENT_DIFF_FILE, '123');
});
it('does not commit SET_CURRENT_DIFF_FILE when discussion has no diff_file', () => {
const commit = jest.fn();
- const state = { diffFiles: [{ file_hash: '123' }] };
const rootGetters = {
getDiscussion: () => ({ id: '1' }),
notesById: { 1: { discussion_id: '2' } },
};
- diffActions.setCurrentDiffFileIdFromNote({ commit, state, rootGetters }, '1');
+ diffActions.setCurrentDiffFileIdFromNote({ commit, rootGetters }, '1');
expect(commit).not.toHaveBeenCalled();
});
it('does not commit SET_CURRENT_DIFF_FILE when diff file does not exist', () => {
const commit = jest.fn();
- const state = { diffFiles: [{ file_hash: '123' }] };
+ const getters = { flatBlobsList: [{ fileHash: '123' }] };
const rootGetters = {
getDiscussion: () => ({ diff_file: { file_hash: '124' } }),
notesById: { 1: { discussion_id: '2' } },
};
- diffActions.setCurrentDiffFileIdFromNote({ commit, state, rootGetters }, '1');
+ diffActions.setCurrentDiffFileIdFromNote({ commit, getters, rootGetters }, '1');
expect(commit).not.toHaveBeenCalled();
});
@@ -1436,7 +1437,7 @@ describe('DiffsStoreActions', () => {
return testAction(
diffActions.navigateToDiffFileIndex,
0,
- { diffFiles: [{ file_hash: '123' }] },
+ { flatBlobsList: [{ fileHash: '123' }] },
[{ type: types.SET_CURRENT_DIFF_FILE, payload: '123' }],
[],
);
diff --git a/spec/frontend/diffs/store/getters_spec.js b/spec/frontend/diffs/store/getters_spec.js
index 2e3a66d5b01..ed7b6699e2c 100644
--- a/spec/frontend/diffs/store/getters_spec.js
+++ b/spec/frontend/diffs/store/getters_spec.js
@@ -288,6 +288,19 @@ describe('Diffs Module Getters', () => {
});
});
+ describe('isTreePathLoaded', () => {
+ it.each`
+ desc | loaded | path | bool
+ ${'the file exists and has been loaded'} | ${true} | ${'path/tofile'} | ${true}
+ ${'the file exists and has not been loaded'} | ${false} | ${'path/tofile'} | ${false}
+ ${'the file does not exist'} | ${false} | ${'tofile/path'} | ${false}
+ `('returns $bool when $desc', ({ loaded, path, bool }) => {
+ localState.treeEntries['path/tofile'] = { diffLoaded: loaded };
+
+ expect(getters.isTreePathLoaded(localState)(path)).toBe(bool);
+ });
+ });
+
describe('allBlobs', () => {
it('returns an array of blobs', () => {
localState.treeEntries = {
@@ -328,7 +341,11 @@ describe('Diffs Module Getters', () => {
describe('currentDiffIndex', () => {
it('returns index of currently selected diff in diffList', () => {
- localState.diffFiles = [{ file_hash: '111' }, { file_hash: '222' }, { file_hash: '333' }];
+ localState.treeEntries = [
+ { type: 'blob', fileHash: '111' },
+ { type: 'blob', fileHash: '222' },
+ { type: 'blob', fileHash: '333' },
+ ];
localState.currentDiffFileId = '222';
expect(getters.currentDiffIndex(localState)).toEqual(1);
@@ -339,7 +356,11 @@ describe('Diffs Module Getters', () => {
});
it('returns 0 if no diff is selected yet or diff is not found', () => {
- localState.diffFiles = [{ file_hash: '111' }, { file_hash: '222' }, { file_hash: '333' }];
+ localState.treeEntries = [
+ { type: 'blob', fileHash: '111' },
+ { type: 'blob', fileHash: '222' },
+ { type: 'blob', fileHash: '333' },
+ ];
localState.currentDiffFileId = '';
expect(getters.currentDiffIndex(localState)).toEqual(0);
diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js
index 031e4fe2be2..ed8d7397bbc 100644
--- a/spec/frontend/diffs/store/mutations_spec.js
+++ b/spec/frontend/diffs/store/mutations_spec.js
@@ -93,15 +93,20 @@ describe('DiffsStoreMutations', () => {
describe('SET_DIFF_DATA_BATCH_DATA', () => {
it('should set diff data batch type properly', () => {
- const state = { diffFiles: [] };
+ const mockFile = getDiffFileMock();
+ const state = {
+ diffFiles: [],
+ treeEntries: { [mockFile.file_path]: { fileHash: mockFile.file_hash } },
+ };
const diffMock = {
- diff_files: [getDiffFileMock()],
+ diff_files: [mockFile],
};
mutations[types.SET_DIFF_DATA_BATCH](state, diffMock);
expect(state.diffFiles[0].renderIt).toEqual(true);
expect(state.diffFiles[0].collapsed).toEqual(false);
+ expect(state.treeEntries[mockFile.file_path].diffLoaded).toBe(true);
});
});
diff --git a/spec/frontend/diffs/store/utils_spec.js b/spec/frontend/diffs/store/utils_spec.js
index b5c44b084d8..4760a8b7166 100644
--- a/spec/frontend/diffs/store/utils_spec.js
+++ b/spec/frontend/diffs/store/utils_spec.js
@@ -892,4 +892,61 @@ describe('DiffsStoreUtils', () => {
expect(files[6].right).toBeNull();
});
});
+
+ describe('isUrlHashNoteLink', () => {
+ it.each`
+ input | bool
+ ${'#note_12345'} | ${true}
+ ${'#12345'} | ${false}
+ ${'note_12345'} | ${true}
+ ${'12345'} | ${false}
+ `('returns $bool for $input', ({ bool, input }) => {
+ expect(utils.isUrlHashNoteLink(input)).toBe(bool);
+ });
+ });
+
+ describe('isUrlHashFileHeader', () => {
+ it.each`
+ input | bool
+ ${'#diff-content-12345'} | ${true}
+ ${'#12345'} | ${false}
+ ${'diff-content-12345'} | ${true}
+ ${'12345'} | ${false}
+ `('returns $bool for $input', ({ bool, input }) => {
+ expect(utils.isUrlHashFileHeader(input)).toBe(bool);
+ });
+ });
+
+ describe('parseUrlHashAsFileHash', () => {
+ it.each`
+ input | currentDiffId | resultId
+ ${'#note_12345'} | ${'1A2B3C'} | ${'1A2B3C'}
+ ${'note_12345'} | ${'1A2B3C'} | ${'1A2B3C'}
+ ${'#note_12345'} | ${undefined} | ${null}
+ ${'note_12345'} | ${undefined} | ${null}
+ ${'#diff-content-12345'} | ${undefined} | ${'12345'}
+ ${'diff-content-12345'} | ${undefined} | ${'12345'}
+ ${'#diff-content-12345'} | ${'98765'} | ${'12345'}
+ ${'diff-content-12345'} | ${'98765'} | ${'12345'}
+ ${'#e334a2a10f036c00151a04cea7938a5d4213a818'} | ${undefined} | ${'e334a2a10f036c00151a04cea7938a5d4213a818'}
+ ${'e334a2a10f036c00151a04cea7938a5d4213a818'} | ${undefined} | ${'e334a2a10f036c00151a04cea7938a5d4213a818'}
+ ${'#Z334a2a10f036c00151a04cea7938a5d4213a818'} | ${undefined} | ${null}
+ ${'Z334a2a10f036c00151a04cea7938a5d4213a818'} | ${undefined} | ${null}
+ `('returns $resultId for $input and $currentDiffId', ({ input, currentDiffId, resultId }) => {
+ expect(utils.parseUrlHashAsFileHash(input, currentDiffId)).toBe(resultId);
+ });
+ });
+
+ describe('markTreeEntriesLoaded', () => {
+ it.each`
+ desc | entries | loaded | outcome
+ ${'marks an existing entry as loaded'} | ${{ abc: {} }} | ${[{ new_path: 'abc' }]} | ${{ abc: { diffLoaded: true } }}
+ ${'does nothing if the new file is not found in the tree entries'} | ${{ abc: {} }} | ${[{ new_path: 'def' }]} | ${{ abc: {} }}
+ ${'leaves entries unmodified if they are not in the loaded files'} | ${{ abc: {}, def: { diffLoaded: true }, ghi: {} }} | ${[{ new_path: 'ghi' }]} | ${{ abc: {}, def: { diffLoaded: true }, ghi: { diffLoaded: true } }}
+ `('$desc', ({ entries, loaded, outcome }) => {
+ expect(utils.markTreeEntriesLoaded({ priorEntries: entries, loadedFiles: loaded })).toEqual(
+ outcome,
+ );
+ });
+ });
});
diff --git a/spec/frontend/diffs/utils/tree_worker_utils_spec.js b/spec/frontend/diffs/utils/tree_worker_utils_spec.js
index 4df5fe75004..b8bd4fcd081 100644
--- a/spec/frontend/diffs/utils/tree_worker_utils_spec.js
+++ b/spec/frontend/diffs/utils/tree_worker_utils_spec.js
@@ -75,8 +75,13 @@ describe('~/diffs/utils/tree_worker_utils', () => {
{
addedLines: 0,
changed: true,
+ diffLoaded: false,
deleted: false,
fileHash: 'test',
+ filePaths: {
+ new: 'app/index.js',
+ old: undefined,
+ },
key: 'app/index.js',
name: 'index.js',
parentPath: 'app/',
@@ -97,8 +102,13 @@ describe('~/diffs/utils/tree_worker_utils', () => {
{
addedLines: 0,
changed: true,
+ diffLoaded: false,
deleted: false,
fileHash: 'test',
+ filePaths: {
+ new: 'app/test/index.js',
+ old: undefined,
+ },
key: 'app/test/index.js',
name: 'index.js',
parentPath: 'app/test/',
@@ -112,8 +122,13 @@ describe('~/diffs/utils/tree_worker_utils', () => {
{
addedLines: 0,
changed: true,
+ diffLoaded: false,
deleted: false,
fileHash: 'test',
+ filePaths: {
+ new: 'app/test/filepathneedstruncating.js',
+ old: undefined,
+ },
key: 'app/test/filepathneedstruncating.js',
name: 'filepathneedstruncating.js',
parentPath: 'app/test/',
@@ -138,8 +153,13 @@ describe('~/diffs/utils/tree_worker_utils', () => {
{
addedLines: 42,
changed: true,
+ diffLoaded: false,
deleted: false,
fileHash: 'test',
+ filePaths: {
+ new: 'constructor/test/aFile.js',
+ old: undefined,
+ },
key: 'constructor/test/aFile.js',
name: 'aFile.js',
parentPath: 'constructor/test/',
@@ -160,10 +180,15 @@ describe('~/diffs/utils/tree_worker_utils', () => {
name: 'submodule @ abcdef123',
type: 'blob',
changed: true,
+ diffLoaded: false,
tempFile: true,
submodule: true,
deleted: false,
fileHash: 'test',
+ filePaths: {
+ new: 'submodule @ abcdef123',
+ old: undefined,
+ },
addedLines: 1,
removedLines: 0,
tree: [],
@@ -175,10 +200,15 @@ describe('~/diffs/utils/tree_worker_utils', () => {
name: 'package.json',
type: 'blob',
changed: true,
+ diffLoaded: false,
tempFile: false,
submodule: undefined,
deleted: true,
fileHash: 'test',
+ filePaths: {
+ new: 'package.json',
+ old: undefined,
+ },
addedLines: 0,
removedLines: 0,
tree: [],
diff --git a/spec/frontend/drawio/content_editor_facade_spec.js b/spec/frontend/drawio/content_editor_facade_spec.js
new file mode 100644
index 00000000000..673968bac9f
--- /dev/null
+++ b/spec/frontend/drawio/content_editor_facade_spec.js
@@ -0,0 +1,138 @@
+import AxiosMockAdapter from 'axios-mock-adapter';
+import { create } from '~/drawio/content_editor_facade';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
+import axios from '~/lib/utils/axios_utils';
+import { PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML } from '../content_editor/test_constants';
+import { createTestEditor } from '../content_editor/test_utils';
+
+describe('drawio/contentEditorFacade', () => {
+ let tiptapEditor;
+ let axiosMock;
+ let contentEditorFacade;
+ let assetResolver;
+ const imageURL = '/group1/project1/-/wikis/test-file.drawio.svg';
+ const diagramSvg = '<svg></svg>';
+ const contentType = 'image/svg+xml';
+ const filename = 'test-file.drawio.svg';
+ const uploadsPath = '/uploads';
+ const canonicalSrc = '/new-diagram.drawio.svg';
+ const src = `/uploads${canonicalSrc}`;
+
+ beforeEach(() => {
+ assetResolver = {
+ resolveUrl: jest.fn(),
+ };
+ tiptapEditor = createTestEditor({ extensions: [DrawioDiagram] });
+ contentEditorFacade = create({
+ tiptapEditor,
+ drawioNodeName: DrawioDiagram.name,
+ uploadsPath,
+ assetResolver,
+ });
+ });
+ beforeEach(() => {
+ axiosMock = new AxiosMockAdapter(axios);
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+ tiptapEditor.destroy();
+ });
+
+ describe('getDiagram', () => {
+ describe('when there is a selected diagram', () => {
+ beforeEach(() => {
+ tiptapEditor
+ .chain()
+ .setContent(PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML)
+ .setNodeSelection(1)
+ .run();
+ axiosMock
+ .onGet(imageURL)
+ .reply(HTTP_STATUS_OK, diagramSvg, { 'content-type': contentType });
+ });
+
+ it('returns diagram information', async () => {
+ const diagram = await contentEditorFacade.getDiagram();
+
+ expect(diagram).toEqual({
+ diagramURL: imageURL,
+ filename,
+ diagramSvg,
+ contentType,
+ });
+ });
+ });
+
+ describe('when there is not a selected diagram', () => {
+ beforeEach(() => {
+ tiptapEditor.chain().setContent('<p>text</p>').setNodeSelection(1).run();
+ });
+
+ it('returns null', async () => {
+ const diagram = await contentEditorFacade.getDiagram();
+
+ expect(diagram).toBe(null);
+ });
+ });
+ });
+
+ describe('updateDiagram', () => {
+ beforeEach(() => {
+ tiptapEditor
+ .chain()
+ .setContent(PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML)
+ .setNodeSelection(1)
+ .run();
+
+ assetResolver.resolveUrl.mockReturnValueOnce(src);
+ contentEditorFacade.updateDiagram({ uploadResults: { file_path: canonicalSrc } });
+ });
+
+ it('updates selected diagram diagram node src and canonicalSrc', () => {
+ tiptapEditor.commands.setNodeSelection(1);
+ expect(tiptapEditor.state.selection.node.attrs).toMatchObject({
+ src,
+ canonicalSrc,
+ });
+ });
+ });
+
+ describe('insertDiagram', () => {
+ beforeEach(() => {
+ tiptapEditor.chain().setContent('<p></p>').run();
+
+ assetResolver.resolveUrl.mockReturnValueOnce(src);
+ contentEditorFacade.insertDiagram({ uploadResults: { file_path: canonicalSrc } });
+ });
+
+ it('inserts a new draw.io diagram in the document', () => {
+ tiptapEditor.commands.setNodeSelection(1);
+ expect(tiptapEditor.state.selection.node.attrs).toMatchObject({
+ src,
+ canonicalSrc,
+ });
+ });
+ });
+
+ describe('uploadDiagram', () => {
+ it('sends a post request to the uploadsPath containing the diagram svg', async () => {
+ const link = { markdown: '![](diagram.drawio.svg)' };
+ const blob = new Blob([diagramSvg], { type: 'image/svg+xml' });
+ const formData = new FormData();
+
+ formData.append('file', blob, filename);
+
+ axiosMock.onPost(uploadsPath, formData).reply(HTTP_STATUS_OK, {
+ data: {
+ link,
+ },
+ });
+
+ const response = await contentEditorFacade.uploadDiagram({ diagramSvg, filename });
+
+ expect(response).not.toBe(link);
+ });
+ });
+});
diff --git a/spec/frontend/drawio/drawio_editor_spec.js b/spec/frontend/drawio/drawio_editor_spec.js
new file mode 100644
index 00000000000..5ef26c04204
--- /dev/null
+++ b/spec/frontend/drawio/drawio_editor_spec.js
@@ -0,0 +1,479 @@
+import { launchDrawioEditor } from '~/drawio/drawio_editor';
+import {
+ DRAWIO_EDITOR_URL,
+ DRAWIO_FRAME_ID,
+ DIAGRAM_BACKGROUND_COLOR,
+ DRAWIO_IFRAME_TIMEOUT,
+ DIAGRAM_MAX_SIZE,
+} from '~/drawio/constants';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
+
+jest.mock('~/alert');
+
+jest.useFakeTimers();
+
+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 filename = 'diagram.drawio.svg';
+
+ const findDrawioIframe = () => document.getElementById(DRAWIO_FRAME_ID);
+ const waitForDrawioIFrameMessage = ({ messageNumber = 1 } = {}) =>
+ new Promise((resolve) => {
+ let messageCounter = 0;
+ const iframe = findDrawioIframe();
+
+ iframe?.contentWindow.addEventListener('message', (event) => {
+ drawioIFrameReceivedMessages.push(event);
+
+ messageCounter += 1;
+
+ if (messageCounter === messageNumber) {
+ resolve();
+ }
+ });
+ });
+ const expectDrawioIframeMessage = ({ expectation, messageNumber = 1 }) => {
+ expect(drawioIFrameReceivedMessages).toHaveLength(messageNumber);
+ expect(JSON.parse(drawioIFrameReceivedMessages[messageNumber - 1].data)).toEqual(expectation);
+ };
+ const postMessageToParentWindow = (data) => {
+ const event = new Event('message');
+
+ Object.setPrototypeOf(event, {
+ source: findDrawioIframe().contentWindow,
+ data: JSON.stringify(data),
+ });
+
+ window.dispatchEvent(event);
+ };
+
+ beforeEach(() => {
+ editorFacade = {
+ getDiagram: jest.fn(),
+ uploadDiagram: jest.fn(),
+ insertDiagram: jest.fn(),
+ updateDiagram: jest.fn(),
+ };
+ drawioIFrameReceivedMessages = [];
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ findDrawioIframe()?.remove();
+ });
+
+ describe('initializing', () => {
+ beforeEach(() => {
+ launchDrawioEditor({ editorFacade });
+ });
+
+ it('creates the drawio editor iframe and attaches it to the body', () => {
+ expect(findDrawioIframe().getAttribute('src')).toBe(DRAWIO_EDITOR_URL);
+ });
+
+ it('sets drawio-editor classname to the iframe', () => {
+ expect(findDrawioIframe().classList).toContain('drawio-editor');
+ });
+ });
+
+ describe(`when parent window does not receive configure event after ${DRAWIO_IFRAME_TIMEOUT} ms`, () => {
+ beforeEach(() => {
+ launchDrawioEditor({ editorFacade });
+ });
+
+ it('disposes draw.io iframe', () => {
+ expect(findDrawioIframe()).not.toBe(null);
+ jest.runAllTimers();
+ expect(findDrawioIframe()).toBe(null);
+ });
+
+ it('displays an alert indicating that the draw.io editor could not be loaded', () => {
+ jest.runAllTimers();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'The diagrams.net editor could not be loaded.',
+ });
+ });
+ });
+
+ describe('when parent window receives configure event', () => {
+ beforeEach(async () => {
+ launchDrawioEditor({ editorFacade });
+ postMessageToParentWindow({ event: 'configure' });
+
+ await waitForDrawioIFrameMessage();
+ });
+
+ it('sends configure action to the draw.io iframe', async () => {
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'configure',
+ config: {
+ darkColor: '#202020',
+ settingsName: 'gitlab',
+ },
+ colorSchemeMeta: false,
+ },
+ });
+ });
+
+ it('does not remove the iframe after the load error timeouts run', async () => {
+ jest.runAllTimers();
+
+ expect(findDrawioIframe()).not.toBe(null);
+ });
+ });
+
+ describe('when parent window receives init event', () => {
+ describe('when there isn’t a diagram selected', () => {
+ beforeEach(() => {
+ editorFacade.getDiagram.mockResolvedValueOnce(null);
+
+ launchDrawioEditor({ editorFacade });
+
+ postMessageToParentWindow({ event: 'init' });
+ });
+
+ it('sends load action to the draw.io iframe with empty svg and title', async () => {
+ await waitForDrawioIFrameMessage();
+
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'load',
+ xml: null,
+ border: 8,
+ background: DIAGRAM_BACKGROUND_COLOR,
+ dark: false,
+ title: null,
+ },
+ });
+ });
+ });
+
+ describe('when there is a diagram selected', () => {
+ const diagramSvg = '<svg></svg>';
+
+ beforeEach(() => {
+ editorFacade.getDiagram.mockResolvedValueOnce({
+ diagramURL,
+ diagramSvg,
+ filename,
+ contentType: 'image/svg+xml',
+ });
+
+ launchDrawioEditor({ editorFacade });
+ postMessageToParentWindow({ event: 'init' });
+ });
+
+ it('sends load action to the draw.io iframe with the selected diagram svg and filename', async () => {
+ await waitForDrawioIFrameMessage();
+
+ // Step 5: The draw.io editor will send the downloaded diagram to the iframe
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'load',
+ xml: diagramSvg,
+ border: 8,
+ background: DIAGRAM_BACKGROUND_COLOR,
+ dark: false,
+ title: filename,
+ },
+ });
+ });
+
+ it('sets the drawio iframe as visible and resets cursor', async () => {
+ await waitForDrawioIFrameMessage();
+
+ expect(findDrawioIframe().style.visibility).toBe('visible');
+ expect(findDrawioIframe().style.cursor).toBe('');
+ });
+
+ it('scrolls window to the top', async () => {
+ await waitForDrawioIFrameMessage();
+
+ expect(window.scrollX).toBe(0);
+ });
+ });
+
+ describe.each`
+ description | errorMessage | diagram
+ ${'when there is an image selected that is not an svg file'} | ${'The selected image is not a valid SVG diagram'} | ${{
+ diagramURL,
+ contentType: 'image/png',
+ filename: 'image.png',
+}}
+ ${'when the selected image is not an asset upload'} | ${'The selected image is not an asset uploaded in the application'} | ${{
+ diagramSvg: '<svg></svg>',
+ filename,
+ contentType: 'image/svg+xml',
+ diagramURL: 'https://example.com/image.drawio.svg',
+}}
+ ${'when the selected image is too large'} | ${'The selected image is too large.'} | ${{
+ diagramSvg: 'x'.repeat(DIAGRAM_MAX_SIZE + 1),
+ filename,
+ contentType: 'image/svg+xml',
+ diagramURL,
+}}
+ `('$description', ({ errorMessage, diagram }) => {
+ beforeEach(() => {
+ editorFacade.getDiagram.mockResolvedValueOnce(diagram);
+
+ launchDrawioEditor({ editorFacade });
+
+ postMessageToParentWindow({ event: 'init' });
+ });
+
+ it('displays an error alert indicating that the image is not a diagram', async () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: errorMessage,
+ error: expect.any(Error),
+ });
+ });
+
+ it('disposes the draw.io diagram iframe', () => {
+ expect(findDrawioIframe()).toBe(null);
+ });
+ });
+
+ describe('when loading a diagram fails', () => {
+ beforeEach(() => {
+ editorFacade.getDiagram.mockRejectedValueOnce(new Error());
+
+ launchDrawioEditor({ editorFacade });
+
+ postMessageToParentWindow({ event: 'init' });
+ });
+
+ it('displays an error alert indicating the failure', async () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'Cannot load the diagram into the diagrams.net editor',
+ error: expect.any(Error),
+ });
+ });
+
+ it('disposes the draw.io diagram iframe', () => {
+ expect(findDrawioIframe()).toBe(null);
+ });
+ });
+ });
+
+ describe('when parent window receives prompt event', () => {
+ describe('when the filename is empty', () => {
+ beforeEach(() => {
+ launchDrawioEditor({ editorFacade });
+
+ postMessageToParentWindow({ event: 'prompt', value: '' });
+ });
+
+ it('sends prompt action to the draw.io iframe requesting a filename', async () => {
+ await waitForDrawioIFrameMessage({ messageNumber: 1 });
+
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'prompt',
+ titleKey: 'filename',
+ okKey: 'save',
+ defaultValue: 'diagram.drawio.svg',
+ },
+ messageNumber: 1,
+ });
+ });
+
+ it('sends dialog action to the draw.io iframe indicating that the filename cannot be empty', async () => {
+ await waitForDrawioIFrameMessage({ messageNumber: 2 });
+
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'dialog',
+ titleKey: 'error',
+ messageKey: 'filenameShort',
+ buttonKey: 'ok',
+ },
+ messageNumber: 2,
+ });
+ });
+ });
+
+ describe('when the event data is not empty', () => {
+ beforeEach(async () => {
+ launchDrawioEditor({ editorFacade });
+ postMessageToParentWindow({ event: 'prompt', value: 'diagram.drawio.svg' });
+
+ await waitForDrawioIFrameMessage();
+ });
+
+ it('starts the saving file process', () => {
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'spinner',
+ show: true,
+ messageKey: 'saving',
+ },
+ });
+ });
+ });
+ });
+
+ describe('when parent receives export event', () => {
+ beforeEach(() => {
+ editorFacade.uploadDiagram.mockResolvedValueOnce({});
+ });
+
+ it('reloads diagram in the draw.io editor', async () => {
+ launchDrawioEditor({ editorFacade });
+ postMessageToParentWindow({ event: 'export', data: testEncodedSvg });
+
+ await waitForDrawioIFrameMessage();
+
+ expectDrawioIframeMessage({
+ expectation: expect.objectContaining({
+ action: 'load',
+ xml: expect.stringContaining(testSvg),
+ }),
+ });
+ });
+
+ it('marks the diagram as modified in the draw.io editor', async () => {
+ launchDrawioEditor({ editorFacade });
+ postMessageToParentWindow({ event: 'export', data: testEncodedSvg });
+
+ await waitForDrawioIFrameMessage({ messageNumber: 2 });
+
+ expectDrawioIframeMessage({
+ expectation: expect.objectContaining({
+ action: 'status',
+ modified: true,
+ }),
+ messageNumber: 2,
+ });
+ });
+
+ describe('when the diagram filename is set', () => {
+ const TEST_FILENAME = 'diagram.drawio.svg';
+
+ beforeEach(() => {
+ launchDrawioEditor({ editorFacade, filename: TEST_FILENAME });
+ });
+
+ it('displays loading spinner in the draw.io editor', async () => {
+ postMessageToParentWindow({ event: 'export', data: testEncodedSvg });
+
+ await waitForDrawioIFrameMessage({ messageNumber: 3 });
+
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'spinner',
+ show: true,
+ messageKey: 'saving',
+ },
+ messageNumber: 3,
+ });
+ });
+
+ it('uploads exported diagram', async () => {
+ postMessageToParentWindow({ event: 'export', data: testEncodedSvg });
+
+ await waitForDrawioIFrameMessage({ messageNumber: 3 });
+
+ expect(editorFacade.uploadDiagram).toHaveBeenCalledWith({
+ filename: TEST_FILENAME,
+ diagramSvg: expect.stringContaining(testSvg),
+ });
+ });
+
+ describe('when uploading the exported diagram succeeds', () => {
+ it('displays an alert indicating that the diagram was uploaded successfully', async () => {
+ postMessageToParentWindow({ event: 'export', data: testEncodedSvg });
+
+ await waitForDrawioIFrameMessage({ messageNumber: 3 });
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: expect.any(String),
+ variant: VARIANT_SUCCESS,
+ fadeTransition: true,
+ });
+ });
+
+ it('disposes iframe', () => {
+ jest.runAllTimers();
+
+ expect(findDrawioIframe()).toBe(null);
+ });
+ });
+
+ describe('when uploading the exported diagram fails', () => {
+ const uploadError = new Error();
+
+ beforeEach(() => {
+ editorFacade.uploadDiagram.mockReset();
+ editorFacade.uploadDiagram.mockRejectedValue(uploadError);
+
+ postMessageToParentWindow({ event: 'export', data: testEncodedSvg });
+ });
+
+ it('hides loading indicator in the draw.io editor', async () => {
+ await waitForDrawioIFrameMessage({ messageNumber: 4 });
+
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'spinner',
+ show: false,
+ },
+ messageNumber: 4,
+ });
+ });
+
+ it('displays an error dialog in the draw.io editor', async () => {
+ await waitForDrawioIFrameMessage({ messageNumber: 5 });
+
+ expectDrawioIframeMessage({
+ expectation: {
+ action: 'dialog',
+ titleKey: 'error',
+ modified: true,
+ buttonKey: 'close',
+ messageKey: 'errorSavingFile',
+ },
+ messageNumber: 5,
+ });
+ });
+ });
+ });
+
+ describe('when diagram filename is not set', () => {
+ it('sends prompt action to the draw.io iframe', async () => {
+ launchDrawioEditor({ editorFacade });
+ postMessageToParentWindow({ event: 'export', data: testEncodedSvg });
+
+ await waitForDrawioIFrameMessage({ messageNumber: 3 });
+
+ expect(drawioIFrameReceivedMessages[2].data).toEqual(
+ JSON.stringify({
+ action: 'prompt',
+ titleKey: 'filename',
+ okKey: 'save',
+ defaultValue: 'diagram.drawio.svg',
+ }),
+ );
+ });
+ });
+ });
+
+ describe('when parent window receives exit event', () => {
+ beforeEach(() => {
+ launchDrawioEditor({ editorFacade });
+ });
+
+ it('disposes the the draw.io iframe', () => {
+ expect(findDrawioIframe()).not.toBe(null);
+
+ postMessageToParentWindow({ event: 'exit' });
+
+ expect(findDrawioIframe()).toBe(null);
+ });
+ });
+});
diff --git a/spec/frontend/drawio/markdown_field_editor_facade_spec.js b/spec/frontend/drawio/markdown_field_editor_facade_spec.js
new file mode 100644
index 00000000000..e3eafc63839
--- /dev/null
+++ b/spec/frontend/drawio/markdown_field_editor_facade_spec.js
@@ -0,0 +1,148 @@
+import AxiosMockAdapter from 'axios-mock-adapter';
+import { create } from '~/drawio/markdown_field_editor_facade';
+import * as textMarkdown from '~/lib/utils/text_markdown';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import axios from '~/lib/utils/axios_utils';
+
+jest.mock('~/lib/utils/text_markdown');
+
+describe('drawio/textareaMarkdownEditor', () => {
+ let textArea;
+ let textareaMarkdownEditor;
+ let axiosMock;
+
+ const markdownPreviewPath = '/markdown/preview';
+ const imageURL = '/assets/image.png';
+ const diagramMarkdown = '![](image.png)';
+ const diagramSvg = '<svg></svg>';
+ const contentType = 'image/svg+xml';
+ const filename = 'image.png';
+ const newDiagramMarkdown = '![](newdiagram.svg)';
+ const uploadsPath = '/uploads';
+
+ beforeEach(() => {
+ textArea = document.createElement('textarea');
+ textareaMarkdownEditor = create({ textArea, markdownPreviewPath, uploadsPath });
+
+ document.body.appendChild(textArea);
+ });
+ beforeEach(() => {
+ axiosMock = new AxiosMockAdapter(axios);
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+ textArea.remove();
+ });
+
+ describe('getDiagram', () => {
+ describe('when there is a selected diagram', () => {
+ beforeEach(() => {
+ textMarkdown.resolveSelectedImage.mockReturnValueOnce({
+ imageURL,
+ imageMarkdown: diagramMarkdown,
+ filename,
+ });
+ axiosMock
+ .onGet(imageURL)
+ .reply(HTTP_STATUS_OK, diagramSvg, { 'content-type': contentType });
+ });
+
+ it('returns diagram information', async () => {
+ const diagram = await textareaMarkdownEditor.getDiagram();
+
+ expect(textMarkdown.resolveSelectedImage).toHaveBeenCalledWith(
+ textArea,
+ markdownPreviewPath,
+ );
+
+ expect(diagram).toEqual({
+ diagramURL: imageURL,
+ diagramMarkdown,
+ filename,
+ diagramSvg,
+ contentType,
+ });
+ });
+ });
+
+ describe('when there is not a selected diagram', () => {
+ beforeEach(() => {
+ textMarkdown.resolveSelectedImage.mockReturnValueOnce(null);
+ });
+
+ it('returns null', async () => {
+ const diagram = await textareaMarkdownEditor.getDiagram();
+
+ expect(textMarkdown.resolveSelectedImage).toHaveBeenCalledWith(
+ textArea,
+ markdownPreviewPath,
+ );
+
+ expect(diagram).toBe(null);
+ });
+ });
+ });
+
+ describe('updateDiagram', () => {
+ beforeEach(() => {
+ jest.spyOn(textArea, 'focus');
+ jest.spyOn(textArea, 'dispatchEvent');
+
+ textArea.value = `diagram ${diagramMarkdown}`;
+
+ textareaMarkdownEditor.updateDiagram({
+ diagramMarkdown,
+ uploadResults: { link: { markdown: newDiagramMarkdown } },
+ });
+ });
+
+ it('focuses the textarea', () => {
+ expect(textArea.focus).toHaveBeenCalled();
+ });
+
+ it('replaces previous diagram markdown with new diagram markdown', () => {
+ expect(textArea.value).toBe(`diagram ${newDiagramMarkdown}`);
+ });
+
+ it('dispatches input event in the textarea', () => {
+ expect(textArea.dispatchEvent).toHaveBeenCalledWith(new Event('input'));
+ });
+ });
+
+ describe('insertDiagram', () => {
+ it('inserts markdown text and replaces any selected markdown in the textarea', () => {
+ textArea.value = `diagram ${diagramMarkdown}`;
+ textArea.setSelectionRange(0, 8);
+
+ textareaMarkdownEditor.insertDiagram({
+ uploadResults: { link: { markdown: newDiagramMarkdown } },
+ });
+
+ expect(textMarkdown.insertMarkdownText).toHaveBeenCalledWith({
+ textArea,
+ text: textArea.value,
+ tag: newDiagramMarkdown,
+ selected: textArea.value.substring(0, 8),
+ });
+ });
+ });
+
+ describe('uploadDiagram', () => {
+ it('sends a post request to the uploadsPath containing the diagram svg', async () => {
+ const link = { markdown: '![](diagram.drawio.svg)' };
+ const blob = new Blob([diagramSvg], { type: 'image/svg+xml' });
+ const formData = new FormData();
+
+ formData.append('file', blob, filename);
+
+ axiosMock.onPost(uploadsPath, formData).reply(HTTP_STATUS_OK, {
+ link,
+ });
+
+ const response = await textareaMarkdownEditor.uploadDiagram({ diagramSvg, filename });
+
+ expect(response).toEqual({ link });
+ });
+ });
+});
diff --git a/spec/frontend/editor/components/helpers.js b/spec/frontend/editor/components/helpers.js
index 12f90390c18..5cc66dd2ae0 100644
--- a/spec/frontend/editor/components/helpers.js
+++ b/spec/frontend/editor/components/helpers.js
@@ -1,4 +1,3 @@
-import { EDITOR_TOOLBAR_RIGHT_GROUP } from '~/editor/constants';
import { apolloProvider } from '~/editor/components/source_editor_toolbar_graphql';
import getToolbarItemsQuery from '~/editor/graphql/get_items.query.graphql';
@@ -9,7 +8,7 @@ export const buildButton = (id = 'foo-bar-btn', options = {}) => {
label: options.label || 'Foo Bar Button',
icon: options.icon || 'check',
selected: options.selected || false,
- group: options.group || EDITOR_TOOLBAR_RIGHT_GROUP,
+ group: options.group,
onClick: options.onClick || (() => {}),
category: options.category || 'primary',
selectedLabel: options.selectedLabel || 'smth',
diff --git a/spec/frontend/editor/components/source_editor_toolbar_button_spec.js b/spec/frontend/editor/components/source_editor_toolbar_button_spec.js
index ff377494312..79692ab4557 100644
--- a/spec/frontend/editor/components/source_editor_toolbar_button_spec.js
+++ b/spec/frontend/editor/components/source_editor_toolbar_button_spec.js
@@ -21,11 +21,6 @@ describe('Source Editor Toolbar button', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('default', () => {
const defaultProps = {
category: 'primary',
diff --git a/spec/frontend/editor/components/source_editor_toolbar_spec.js b/spec/frontend/editor/components/source_editor_toolbar_spec.js
index bead39ca744..f737340a317 100644
--- a/spec/frontend/editor/components/source_editor_toolbar_spec.js
+++ b/spec/frontend/editor/components/source_editor_toolbar_spec.js
@@ -5,7 +5,7 @@ import { shallowMount } from '@vue/test-utils';
import createMockApollo from 'helpers/mock_apollo_helper';
import SourceEditorToolbar from '~/editor/components/source_editor_toolbar.vue';
import SourceEditorToolbarButton from '~/editor/components/source_editor_toolbar_button.vue';
-import { EDITOR_TOOLBAR_LEFT_GROUP, EDITOR_TOOLBAR_RIGHT_GROUP } from '~/editor/constants';
+import { EDITOR_TOOLBAR_BUTTON_GROUPS } from '~/editor/constants';
import getToolbarItemsQuery from '~/editor/graphql/get_items.query.graphql';
import { buildButton } from './helpers';
@@ -40,24 +40,24 @@ describe('Source Editor Toolbar', () => {
};
afterEach(() => {
- wrapper.destroy();
mockApollo = null;
});
describe('groups', () => {
it.each`
- group | expectedGroup
- ${EDITOR_TOOLBAR_LEFT_GROUP} | ${EDITOR_TOOLBAR_LEFT_GROUP}
- ${EDITOR_TOOLBAR_RIGHT_GROUP} | ${EDITOR_TOOLBAR_RIGHT_GROUP}
- ${undefined} | ${EDITOR_TOOLBAR_RIGHT_GROUP}
- ${'non-existing'} | ${EDITOR_TOOLBAR_RIGHT_GROUP}
+ group | expectedGroup
+ ${EDITOR_TOOLBAR_BUTTON_GROUPS.file} | ${EDITOR_TOOLBAR_BUTTON_GROUPS.file}
+ ${EDITOR_TOOLBAR_BUTTON_GROUPS.edit} | ${EDITOR_TOOLBAR_BUTTON_GROUPS.edit}
+ ${EDITOR_TOOLBAR_BUTTON_GROUPS.settings} | ${EDITOR_TOOLBAR_BUTTON_GROUPS.settings}
+ ${undefined} | ${EDITOR_TOOLBAR_BUTTON_GROUPS.settings}
+ ${'non-existing'} | ${EDITOR_TOOLBAR_BUTTON_GROUPS.settings}
`('puts item with group="$group" into $expectedGroup group', ({ group, expectedGroup }) => {
const item = buildButton('first', {
group,
});
createComponentWithApollo([item]);
expect(findButtons()).toHaveLength(1);
- [EDITOR_TOOLBAR_RIGHT_GROUP, EDITOR_TOOLBAR_LEFT_GROUP].forEach((g) => {
+ Object.keys(EDITOR_TOOLBAR_BUTTON_GROUPS).forEach((g) => {
if (g === expectedGroup) {
expect(wrapper.vm.getGroupItems(g)).toEqual([expect.objectContaining({ id: 'first' })]);
} else {
@@ -70,7 +70,7 @@ describe('Source Editor Toolbar', () => {
describe('buttons update', () => {
it('properly updates buttons on Apollo cache update', async () => {
const item = buildButton('first', {
- group: EDITOR_TOOLBAR_RIGHT_GROUP,
+ group: EDITOR_TOOLBAR_BUTTON_GROUPS.edit,
});
createComponentWithApollo();
@@ -95,12 +95,15 @@ describe('Source Editor Toolbar', () => {
describe('click handler', () => {
it('emits the "click" event when a button is clicked', () => {
const item1 = buildButton('first', {
- group: EDITOR_TOOLBAR_LEFT_GROUP,
+ group: EDITOR_TOOLBAR_BUTTON_GROUPS.file,
});
const item2 = buildButton('second', {
- group: EDITOR_TOOLBAR_RIGHT_GROUP,
+ group: EDITOR_TOOLBAR_BUTTON_GROUPS.edit,
});
- createComponentWithApollo([item1, item2]);
+ const item3 = buildButton('third', {
+ group: EDITOR_TOOLBAR_BUTTON_GROUPS.settings,
+ });
+ createComponentWithApollo([item1, item2, item3]);
jest.spyOn(wrapper.vm, '$emit');
expect(wrapper.vm.$emit).not.toHaveBeenCalled();
@@ -110,7 +113,10 @@ describe('Source Editor Toolbar', () => {
findButtons().at(1).vm.$emit('click');
expect(wrapper.vm.$emit).toHaveBeenCalledWith('click', item2);
- expect(wrapper.vm.$emit.mock.calls).toHaveLength(2);
+ findButtons().at(2).vm.$emit('click');
+ expect(wrapper.vm.$emit).toHaveBeenCalledWith('click', item3);
+
+ expect(wrapper.vm.$emit.mock.calls).toHaveLength(3);
});
});
});
diff --git a/spec/frontend/editor/schema/ci/ci_schema_spec.js b/spec/frontend/editor/schema/ci/ci_schema_spec.js
index c822a0bfeaf..87208ec7aa8 100644
--- a/spec/frontend/editor/schema/ci/ci_schema_spec.js
+++ b/spec/frontend/editor/schema/ci/ci_schema_spec.js
@@ -33,6 +33,7 @@ import JobWhenYaml from './yaml_tests/positive_tests/job_when.yml';
import IdTokensYaml from './yaml_tests/positive_tests/id_tokens.yml';
import HooksYaml from './yaml_tests/positive_tests/hooks.yml';
import SecretsYaml from './yaml_tests/positive_tests/secrets.yml';
+import ServicesYaml from './yaml_tests/positive_tests/services.yml';
// YAML NEGATIVE TEST
import ArtifactsNegativeYaml from './yaml_tests/negative_tests/artifacts.yml';
@@ -52,6 +53,7 @@ import VariablesWrongSyntaxUsageExpand from './yaml_tests/negative_tests/variabl
import IdTokensNegativeYaml from './yaml_tests/negative_tests/id_tokens.yml';
import HooksNegative from './yaml_tests/negative_tests/hooks.yml';
import SecretsNegativeYaml from './yaml_tests/negative_tests/secrets.yml';
+import ServicesNegativeYaml from './yaml_tests/negative_tests/services.yml';
const ajv = new Ajv({
strictTypes: false,
@@ -89,6 +91,7 @@ describe('positive tests', () => {
VariablesYaml,
ProjectPathYaml,
IdTokensYaml,
+ ServicesYaml,
SecretsYaml,
}),
)('schema validates %s', (_, input) => {
@@ -113,10 +116,12 @@ describe('negative tests', () => {
// YAML
ArtifactsNegativeYaml,
CacheKeyNeative,
+ HooksNegative,
IdTokensNegativeYaml,
IncludeNegativeYaml,
JobWhenNegativeYaml,
RulesNegativeYaml,
+ TriggerNegative,
VariablesInvalidOptionsYaml,
VariablesInvalidSyntaxDescYaml,
VariablesWrongSyntaxUsageExpand,
@@ -126,8 +131,7 @@ describe('negative tests', () => {
ProjectPathIncludeNoSlashYaml,
ProjectPathIncludeTailSlashYaml,
SecretsNegativeYaml,
- TriggerNegative,
- HooksNegative,
+ ServicesNegativeYaml,
}),
)('schema validates %s', (_, input) => {
// We construct a new "JSON" from each main key that is inside a
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml
new file mode 100644
index 00000000000..6761a603a0a
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml
@@ -0,0 +1,38 @@
+empty_services:
+ services:
+
+without_name:
+ services:
+ - alias: db-postgres
+ entrypoint: ["/usr/local/bin/db-postgres"]
+ command: ["start"]
+
+invalid_entrypoint:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ entrypoint: "/usr/local/bin/db-postgres" # must be array
+
+empty_entrypoint:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ entrypoint: []
+
+invalid_command:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ command: "start" # must be array
+
+empty_command:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ command: []
+
+empty_pull_policy:
+ script: echo "Multiple pull policies."
+ services:
+ - name: postgres:11.6
+ pull_policy: []
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml
new file mode 100644
index 00000000000..8a0f59d1dfd
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml
@@ -0,0 +1,31 @@
+valid_services_list:
+ services:
+ - php:7
+ - node:latest
+ - golang:1.10
+
+valid_services_object:
+ services:
+ - name: my-postgres:11.7
+ alias: db-postgres
+ entrypoint: ["/usr/local/bin/db-postgres"]
+ command: ["start"]
+
+services_with_variables:
+ services:
+ - name: bitnami/nginx
+ alias: nginx
+ variables:
+ NGINX_HTTP_PORT_NUMBER: ${NGINX_HTTP_PORT_NUMBER}
+
+pull_policy_string:
+ script: echo "A single pull policy."
+ services:
+ - name: postgres:11.6
+ pull_policy: if-not-present
+
+pull_policy_array:
+ script: echo "Multiple pull policies."
+ services:
+ - name: postgres:11.6
+ pull_policy: [always, if-not-present]
diff --git a/spec/frontend/editor/source_editor_ci_schema_ext_spec.js b/spec/frontend/editor/source_editor_ci_schema_ext_spec.js
index 21f8979f1a9..e515285601b 100644
--- a/spec/frontend/editor/source_editor_ci_schema_ext_spec.js
+++ b/spec/frontend/editor/source_editor_ci_schema_ext_spec.js
@@ -17,7 +17,6 @@ describe('~/editor/editor_ci_config_ext', () => {
let editor;
let instance;
let editorEl;
- let originalGitlabUrl;
const createMockEditor = ({ blobPath = defaultBlobPath } = {}) => {
setHTMLFixture('<div id="editor"></div>');
@@ -31,16 +30,8 @@ describe('~/editor/editor_ci_config_ext', () => {
instance.use({ definition: CiSchemaExtension });
};
- beforeAll(() => {
- originalGitlabUrl = gon.gitlab_url;
- gon.gitlab_url = TEST_HOST;
- });
-
- afterAll(() => {
- gon.gitlab_url = originalGitlabUrl;
- });
-
beforeEach(() => {
+ gon.gitlab_url = TEST_HOST;
createMockEditor();
});
diff --git a/spec/frontend/editor/source_editor_extension_base_spec.js b/spec/frontend/editor/source_editor_extension_base_spec.js
index eab39ccaba1..b1b8173188c 100644
--- a/spec/frontend/editor/source_editor_extension_base_spec.js
+++ b/spec/frontend/editor/source_editor_extension_base_spec.js
@@ -7,6 +7,7 @@ import {
EDITOR_TYPE_DIFF,
EXTENSION_BASE_LINE_LINK_ANCHOR_CLASS,
EXTENSION_BASE_LINE_NUMBERS_CLASS,
+ EXTENSION_SOFTWRAP_ID,
} from '~/editor/constants';
import { SourceEditorExtension } from '~/editor/extensions/source_editor_extension_base';
import EditorInstance from '~/editor/source_editor_instance';
@@ -35,8 +36,18 @@ describe('The basis for an Source Editor extension', () => {
},
};
};
- const createInstance = (baseInstance = {}) => {
- return new EditorInstance(baseInstance);
+ const baseInstance = {
+ getOption: jest.fn(),
+ };
+
+ const createInstance = (base = baseInstance) => {
+ return new EditorInstance(base);
+ };
+
+ const toolbar = {
+ addItems: jest.fn(),
+ updateItem: jest.fn(),
+ removeItems: jest.fn(),
};
beforeEach(() => {
@@ -49,6 +60,66 @@ describe('The basis for an Source Editor extension', () => {
resetHTMLFixture();
});
+ describe('onSetup callback', () => {
+ let instance;
+ beforeEach(() => {
+ instance = createInstance();
+
+ instance.toolbar = toolbar;
+ });
+
+ it('adds correct buttons to the toolbar', () => {
+ instance.use({ definition: SourceEditorExtension });
+ expect(instance.toolbar.addItems).toHaveBeenCalledWith([
+ expect.objectContaining({
+ id: EXTENSION_SOFTWRAP_ID,
+ }),
+ ]);
+ });
+
+ it('does not fail if toolbar is not available', () => {
+ instance.toolbar = null;
+ expect(() => instance.use({ definition: SourceEditorExtension })).not.toThrow();
+ });
+
+ it.each`
+ optionValue | expectSelected
+ ${'on'} | ${true}
+ ${'off'} | ${false}
+ ${'foo'} | ${false}
+ ${undefined} | ${false}
+ ${null} | ${false}
+ `(
+ 'correctly sets the initial state of the button when wordWrap option is "$optionValue"',
+ ({ optionValue, expectSelected }) => {
+ instance.getOption.mockReturnValue(optionValue);
+ instance.use({ definition: SourceEditorExtension });
+ expect(instance.toolbar.addItems).toHaveBeenCalledWith([
+ expect.objectContaining({
+ selected: expectSelected,
+ }),
+ ]);
+ },
+ );
+ });
+
+ describe('onBeforeUnuse', () => {
+ let instance;
+ let extension;
+
+ beforeEach(() => {
+ instance = createInstance();
+
+ instance.toolbar = toolbar;
+ extension = instance.use({ definition: SourceEditorExtension });
+ });
+ it('removes the registered buttons from the toolbar', () => {
+ expect(instance.toolbar.removeItems).not.toHaveBeenCalled();
+ instance.unuse(extension);
+ expect(instance.toolbar.removeItems).toHaveBeenCalledWith([EXTENSION_SOFTWRAP_ID]);
+ });
+ });
+
describe('onUse callback', () => {
it('initializes the line highlighting', () => {
const instance = createInstance();
@@ -66,6 +137,7 @@ describe('The basis for an Source Editor extension', () => {
'$description the line linking for $instanceType instance',
({ instanceType, shouldBeCalled }) => {
const instance = createInstance({
+ ...baseInstance,
getEditorType: jest.fn().mockReturnValue(instanceType),
onMouseMove: jest.fn(),
onMouseDown: jest.fn(),
@@ -82,10 +154,44 @@ describe('The basis for an Source Editor extension', () => {
);
});
+ describe('toggleSoftwrap', () => {
+ let instance;
+
+ beforeEach(() => {
+ instance = createInstance();
+
+ instance.toolbar = toolbar;
+ instance.use({ definition: SourceEditorExtension });
+ });
+
+ it.each`
+ currentWordWrap | newWordWrap | expectSelected
+ ${'on'} | ${'off'} | ${false}
+ ${'off'} | ${'on'} | ${true}
+ ${'foo'} | ${'on'} | ${true}
+ ${undefined} | ${'on'} | ${true}
+ ${null} | ${'on'} | ${true}
+ `(
+ 'correctly updates wordWrap option in editor and the state of the button when currentWordWrap is "$currentWordWrap"',
+ ({ currentWordWrap, newWordWrap, expectSelected }) => {
+ instance.getOption.mockReturnValue(currentWordWrap);
+ instance.updateOptions = jest.fn();
+ instance.toggleSoftwrap();
+ expect(instance.updateOptions).toHaveBeenCalledWith({
+ wordWrap: newWordWrap,
+ });
+ expect(instance.toolbar.updateItem).toHaveBeenCalledWith(EXTENSION_SOFTWRAP_ID, {
+ selected: expectSelected,
+ });
+ },
+ );
+ });
+
describe('highlightLines', () => {
const revealSpy = jest.fn();
const decorationsSpy = jest.fn();
const instance = createInstance({
+ ...baseInstance,
revealLineInCenter: revealSpy,
deltaDecorations: decorationsSpy,
});
@@ -174,6 +280,7 @@ describe('The basis for an Source Editor extension', () => {
beforeEach(() => {
instance = createInstance({
+ ...baseInstance,
deltaDecorations: decorationsSpy,
lineDecorations,
});
@@ -188,6 +295,7 @@ describe('The basis for an Source Editor extension', () => {
describe('setupLineLinking', () => {
const instance = {
+ ...baseInstance,
onMouseMove: jest.fn(),
onMouseDown: jest.fn(),
deltaDecorations: jest.fn(),
diff --git a/spec/frontend/editor/source_editor_markdown_ext_spec.js b/spec/frontend/editor/source_editor_markdown_ext_spec.js
index 33e4b4bfc8e..b226ef03b33 100644
--- a/spec/frontend/editor/source_editor_markdown_ext_spec.js
+++ b/spec/frontend/editor/source_editor_markdown_ext_spec.js
@@ -17,6 +17,7 @@ describe('Markdown Extension for Source Editor', () => {
const thirdLine = 'string with some **markup**';
const text = `${firstLine}\n${secondLine}\n${thirdLine}`;
const markdownPath = 'foo.md';
+ let extensions;
const setSelection = (startLineNumber = 1, startColumn = 1, endLineNumber = 1, endColumn = 1) => {
const selection = new Range(startLineNumber, startColumn, endLineNumber, endColumn);
@@ -38,7 +39,10 @@ describe('Markdown Extension for Source Editor', () => {
blobPath: markdownPath,
blobContent: text,
});
- instance.use([{ definition: ToolbarExtension }, { definition: EditorMarkdownExtension }]);
+ extensions = instance.use([
+ { definition: ToolbarExtension },
+ { definition: EditorMarkdownExtension },
+ ]);
});
afterEach(() => {
@@ -59,6 +63,25 @@ describe('Markdown Extension for Source Editor', () => {
});
});
+ describe('markdown keystrokes', () => {
+ it('registers all keystrokes as actions', () => {
+ EXTENSION_MARKDOWN_BUTTONS.forEach((button) => {
+ if (button.data.mdShortcuts) {
+ expect(instance.getAction(button.id)).toBeDefined();
+ }
+ });
+ });
+
+ it('disposes all keystrokes on unuse', () => {
+ instance.unuse(extensions[1]);
+ EXTENSION_MARKDOWN_BUTTONS.forEach((button) => {
+ if (button.data.mdShortcuts) {
+ expect(instance.getAction(button.id)).toBeNull();
+ }
+ });
+ });
+ });
+
describe('getSelectedText', () => {
it('does not fail if there is no selection and returns the empty string', () => {
jest.spyOn(instance, 'getSelection');
diff --git a/spec/frontend/editor/source_editor_markdown_livepreview_ext_spec.js b/spec/frontend/editor/source_editor_markdown_livepreview_ext_spec.js
index c42ac28c498..895eb87833d 100644
--- a/spec/frontend/editor/source_editor_markdown_livepreview_ext_spec.js
+++ b/spec/frontend/editor/source_editor_markdown_livepreview_ext_spec.js
@@ -12,14 +12,14 @@ import {
} from '~/editor/constants';
import { EditorMarkdownPreviewExtension } from '~/editor/extensions/source_editor_markdown_livepreview_ext';
import SourceEditor from '~/editor/source_editor';
-import { createAlert } from '~/flash';
+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 syntaxHighlight from '~/syntax_highlight';
import { spyOnApi } from './helpers';
jest.mock('~/syntax_highlight');
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Markdown Live Preview Extension for Source Editor', () => {
let editor;
diff --git a/spec/frontend/editor/source_editor_webide_ext_spec.js b/spec/frontend/editor/source_editor_webide_ext_spec.js
index f418eab668a..7e4079c17f7 100644
--- a/spec/frontend/editor/source_editor_webide_ext_spec.js
+++ b/spec/frontend/editor/source_editor_webide_ext_spec.js
@@ -13,7 +13,6 @@ describe('Source Editor Web IDE Extension', () => {
editorEl = document.getElementById('editor');
editor = new SourceEditor();
});
- afterEach(() => {});
describe('onSetup', () => {
it.each`
diff --git a/spec/frontend/editor/utils_spec.js b/spec/frontend/editor/utils_spec.js
index e561cad1086..13b8a9804b0 100644
--- a/spec/frontend/editor/utils_spec.js
+++ b/spec/frontend/editor/utils_spec.js
@@ -54,19 +54,17 @@ describe('Source Editor utils', () => {
describe('getBlobLanguage', () => {
it.each`
- path | expectedLanguage
- ${'foo.js'} | ${'javascript'}
- ${'foo.js.rb'} | ${'ruby'}
- ${'foo.bar'} | ${'plaintext'}
- ${undefined} | ${'plaintext'}
- `(
- 'sets the $expectedThemeName theme when $themeName is set in the user preference',
- ({ path, expectedLanguage }) => {
- const language = utils.getBlobLanguage(path);
+ path | expectedLanguage
+ ${'foo.js'} | ${'javascript'}
+ ${'foo.js.rb'} | ${'ruby'}
+ ${'foo.bar'} | ${'plaintext'}
+ ${undefined} | ${'plaintext'}
+ ${'foo/bar/foo.js'} | ${'javascript'}
+ `(`returns '$expectedLanguage' for '$path' path`, ({ path, expectedLanguage }) => {
+ const language = utils.getBlobLanguage(path);
- expect(language).toEqual(expectedLanguage);
- },
- );
+ expect(language).toEqual(expectedLanguage);
+ });
});
describe('setupCodeSnipet', () => {
diff --git a/spec/frontend/emoji/components/category_spec.js b/spec/frontend/emoji/components/category_spec.js
index 90816f28d5b..272c1a09a69 100644
--- a/spec/frontend/emoji/components/category_spec.js
+++ b/spec/frontend/emoji/components/category_spec.js
@@ -9,11 +9,12 @@ function factory(propsData = {}) {
wrapper = shallowMount(Category, { propsData });
}
-describe('Emoji category component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
+const triggerGlIntersectionObserver = () => {
+ wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
+ return nextTick();
+};
+describe('Emoji category component', () => {
beforeEach(() => {
factory({
category: 'Activity',
@@ -26,25 +27,19 @@ describe('Emoji category component', () => {
});
it('renders group', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- await wrapper.setData({ renderGroup: true });
+ await triggerGlIntersectionObserver();
expect(wrapper.findComponent(EmojiGroup).attributes('rendergroup')).toBe('true');
});
it('renders group on appear', async () => {
- wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
-
- await nextTick();
+ await triggerGlIntersectionObserver();
expect(wrapper.findComponent(EmojiGroup).attributes('rendergroup')).toBe('true');
});
it('emits appear event on appear', async () => {
- wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
-
- await nextTick();
+ await triggerGlIntersectionObserver();
expect(wrapper.emitted().appear[0]).toEqual(['Activity']);
});
diff --git a/spec/frontend/emoji/components/emoji_group_spec.js b/spec/frontend/emoji/components/emoji_group_spec.js
index 1aca2fbb8fc..75397ce25ff 100644
--- a/spec/frontend/emoji/components/emoji_group_spec.js
+++ b/spec/frontend/emoji/components/emoji_group_spec.js
@@ -15,10 +15,6 @@ function factory(propsData = {}) {
}
describe('Emoji group component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not render any buttons', () => {
factory({
emojis: [],
diff --git a/spec/frontend/emoji/components/emoji_list_spec.js b/spec/frontend/emoji/components/emoji_list_spec.js
index a72ba614d9f..f6f6062f8e8 100644
--- a/spec/frontend/emoji/components/emoji_list_spec.js
+++ b/spec/frontend/emoji/components/emoji_list_spec.js
@@ -1,7 +1,7 @@
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import EmojiList from '~/emoji/components/emoji_list.vue';
+import waitForPromises from 'helpers/wait_for_promises';
jest.mock('~/emoji', () => ({
initEmojiMap: jest.fn(() => Promise.resolve()),
@@ -14,7 +14,8 @@ jest.mock('~/emoji', () => ({
}));
let wrapper;
-async function factory(render, propsData = { searchValue: '' }) {
+
+function factory(propsData = { searchValue: '' }) {
wrapper = extendedWrapper(
shallowMount(EmojiList, {
propsData,
@@ -23,35 +24,23 @@ async function factory(render, propsData = { searchValue: '' }) {
},
}),
);
-
- // Wait for categories to be set
- await nextTick();
-
- if (render) {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ render: true });
-
- // Wait for component to render
- await nextTick();
- }
}
const findDefaultSlot = () => wrapper.findByTestId('default-slot');
describe('Emoji list component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not render until render is set', async () => {
- await factory(false);
+ factory();
expect(findDefaultSlot().exists()).toBe(false);
+ await waitForPromises();
+ expect(findDefaultSlot().exists()).toBe(true);
});
it('renders with none filtered list', async () => {
- await factory(true);
+ factory();
+
+ await waitForPromises();
expect(JSON.parse(findDefaultSlot().text())).toEqual({
activity: {
@@ -63,7 +52,9 @@ describe('Emoji list component', () => {
});
it('renders filtered list of emojis', async () => {
- await factory(true, { searchValue: 'smile' });
+ factory({ searchValue: 'smile' });
+
+ await waitForPromises();
expect(JSON.parse(findDefaultSlot().text())).toEqual({
search: {
diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js
index 82e3b50aeb8..7b160c48501 100644
--- a/spec/frontend/environment.js
+++ b/spec/frontend/environment.js
@@ -8,6 +8,7 @@ const {
setGlobalDateToRealDate,
} = require('./__helpers__/fake_date/fake_date');
const { TEST_HOST } = require('./__helpers__/test_constants');
+const { createGon } = require('./__helpers__/gon_helper');
const ROOT_PATH = path.resolve(__dirname, '../..');
@@ -40,11 +41,12 @@ class CustomEnvironment extends TestEnvironment {
});
const { IS_EE } = projectConfig.testEnvironmentOptions;
- this.global.gon = {
- ee: IS_EE,
- };
+
this.global.IS_EE = IS_EE;
+ // Set up global `gon` object
+ this.global.gon = createGon(IS_EE);
+
// Set up global `gl` object
this.global.gl = {};
diff --git a/spec/frontend/environments/canary_ingress_spec.js b/spec/frontend/environments/canary_ingress_spec.js
index 340740e6499..17ecd93361f 100644
--- a/spec/frontend/environments/canary_ingress_spec.js
+++ b/spec/frontend/environments/canary_ingress_spec.js
@@ -23,7 +23,7 @@ describe('/environments/components/canary_ingress.vue', () => {
...props,
},
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
},
...options,
});
@@ -37,8 +37,6 @@ describe('/environments/components/canary_ingress.vue', () => {
if (wrapper) {
wrapper.destroy();
}
-
- wrapper = null;
});
describe('stable weight', () => {
diff --git a/spec/frontend/environments/canary_update_modal_spec.js b/spec/frontend/environments/canary_update_modal_spec.js
index 31b1770da59..a101ed4e00a 100644
--- a/spec/frontend/environments/canary_update_modal_spec.js
+++ b/spec/frontend/environments/canary_update_modal_spec.js
@@ -34,8 +34,6 @@ describe('/environments/components/canary_update_modal.vue', () => {
if (wrapper) {
wrapper.destroy();
}
-
- wrapper = null;
});
beforeEach(() => {
@@ -47,7 +45,7 @@ describe('/environments/components/canary_update_modal.vue', () => {
modalId: 'confirm-canary-change',
actionPrimary: {
text: 'Change ratio',
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
},
actionCancel: { text: 'Cancel' },
});
diff --git a/spec/frontend/environments/delete_environment_modal_spec.js b/spec/frontend/environments/delete_environment_modal_spec.js
index cc18bf754eb..96f6ce52a9c 100644
--- a/spec/frontend/environments/delete_environment_modal_spec.js
+++ b/spec/frontend/environments/delete_environment_modal_spec.js
@@ -6,10 +6,10 @@ import { s__, sprintf } from '~/locale';
import DeleteEnvironmentModal from '~/environments/components/delete_environment_modal.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { resolvedEnvironment } from './graphql/mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
describe('~/environments/components/delete_environment_modal.vue', () => {
@@ -67,7 +67,7 @@ describe('~/environments/components/delete_environment_modal.vue', () => {
);
});
- it('should flash a message on error', async () => {
+ it('should alert a message on error', async () => {
createComponent({ apolloProvider: mockApollo });
deleteResolver.mockRejectedValue();
diff --git a/spec/frontend/environments/edit_environment_spec.js b/spec/frontend/environments/edit_environment_spec.js
index fb1a8b8c00a..34f338fabe6 100644
--- a/spec/frontend/environments/edit_environment_spec.js
+++ b/spec/frontend/environments/edit_environment_spec.js
@@ -3,13 +3,13 @@ import MockAdapter from 'axios-mock-adapter';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import EditEnvironment from '~/environments/components/edit_environment.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility');
-jest.mock('~/flash');
+jest.mock('~/alert');
const DEFAULT_OPTS = {
provide: {
@@ -37,7 +37,6 @@ describe('~/environments/components/edit.vue', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
const findNameInput = () => wrapper.findByLabelText('Name');
diff --git a/spec/frontend/environments/empty_state_spec.js b/spec/frontend/environments/empty_state_spec.js
index 02cf2dc3c68..d067c4c80e0 100644
--- a/spec/frontend/environments/empty_state_spec.js
+++ b/spec/frontend/environments/empty_state_spec.js
@@ -29,10 +29,6 @@ describe('~/environments/components/empty_state.vue', () => {
provide: { newEnvironmentPath: NEW_PATH },
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows an empty state for available environments', () => {
wrapper = createWrapper();
diff --git a/spec/frontend/environments/enable_review_app_modal_spec.js b/spec/frontend/environments/enable_review_app_modal_spec.js
index 7939bd600dc..ee728775980 100644
--- a/spec/frontend/environments/enable_review_app_modal_spec.js
+++ b/spec/frontend/environments/enable_review_app_modal_spec.js
@@ -18,10 +18,6 @@ describe('Enable Review App Modal', () => {
const findInstructionAt = (i) => wrapper.findAll('ol li').at(i);
const findCopyString = () => wrapper.find(`#${EXPECTED_COPY_PRE_ID}`);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('renders the modal', () => {
beforeEach(() => {
wrapper = extendedWrapper(
diff --git a/spec/frontend/environments/environment_actions_spec.js b/spec/frontend/environments/environment_actions_spec.js
index 48483152f7a..3c9b4144e45 100644
--- a/spec/frontend/environments/environment_actions_spec.js
+++ b/spec/frontend/environments/environment_actions_spec.js
@@ -36,7 +36,7 @@ describe('EnvironmentActions Component', () => {
wrapper = mountFn(EnvironmentActions, {
propsData: { actions: [], ...props },
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
...options,
});
@@ -52,7 +52,6 @@ describe('EnvironmentActions Component', () => {
};
afterEach(() => {
- wrapper.destroy();
confirmAction.mockReset();
});
diff --git a/spec/frontend/environments/environment_folder_spec.js b/spec/frontend/environments/environment_folder_spec.js
index a37515bc3f7..279ff32a13d 100644
--- a/spec/frontend/environments/environment_folder_spec.js
+++ b/spec/frontend/environments/environment_folder_spec.js
@@ -35,7 +35,7 @@ describe('~/environments/components/environments_folder.vue', () => {
...propsData,
},
stubs: { transition: stubTransition() },
- provide: { helpPagePath: '/help' },
+ provide: { helpPagePath: '/help', projectId: '1' },
});
beforeEach(async () => {
diff --git a/spec/frontend/environments/environment_form_spec.js b/spec/frontend/environments/environment_form_spec.js
index b9b34bee80f..50e4e637aa3 100644
--- a/spec/frontend/environments/environment_form_spec.js
+++ b/spec/frontend/environments/environment_form_spec.js
@@ -15,19 +15,16 @@ const PROVIDE = { protectedEnvironmentSettingsPath: '/projects/not_real/settings
describe('~/environments/components/form.vue', () => {
let wrapper;
- const createWrapper = (propsData = {}) =>
+ const createWrapper = (propsData = {}, options = {}) =>
mountExtended(EnvironmentForm, {
provide: PROVIDE,
+ ...options,
propsData: {
...DEFAULT_PROPS,
...propsData,
},
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
wrapper = createWrapper();
@@ -105,6 +102,7 @@ describe('~/environments/components/form.vue', () => {
wrapper = createWrapper({ loading: true });
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
+
describe('when a new environment is being created', () => {
beforeEach(() => {
wrapper = createWrapper({
@@ -133,6 +131,18 @@ describe('~/environments/components/form.vue', () => {
});
});
+ describe('when no protected environment link is provided', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({
+ provide: {},
+ });
+ });
+
+ it('does not show protected environment documentation', () => {
+ expect(wrapper.findByRole('link', { name: 'Protected environments' }).exists()).toBe(false);
+ });
+ });
+
describe('when an existing environment is being edited', () => {
beforeEach(() => {
wrapper = createWrapper({
diff --git a/spec/frontend/environments/environment_item_spec.js b/spec/frontend/environments/environment_item_spec.js
index dd909cf4473..59e94dfd662 100644
--- a/spec/frontend/environments/environment_item_spec.js
+++ b/spec/frontend/environments/environment_item_spec.js
@@ -56,10 +56,6 @@ describe('Environment item', () => {
findUpcomingDeployment().findComponent(GlAvatarLink);
const findUpcomingDeploymentAvatar = () => findUpcomingDeployment().findComponent(GlAvatar);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when item is not folder', () => {
it('should render environment name', () => {
expect(wrapper.find('.environment-name').text()).toContain(environment.name);
@@ -390,10 +386,6 @@ describe('Environment item', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render folder icon and name', () => {
expect(wrapper.find('.folder-name').text()).toContain(folder.name);
expect(wrapper.find('.folder-icon')).toBeDefined();
diff --git a/spec/frontend/environments/environment_pin_spec.js b/spec/frontend/environments/environment_pin_spec.js
index 170036b5b00..2f38dea2833 100644
--- a/spec/frontend/environments/environment_pin_spec.js
+++ b/spec/frontend/environments/environment_pin_spec.js
@@ -31,10 +31,6 @@ describe('Pin Component', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render the component with descriptive text', () => {
expect(wrapper.text()).toBe('Prevent auto-stopping');
});
@@ -64,10 +60,6 @@ describe('Pin Component', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render the component with descriptive text', () => {
expect(wrapper.text()).toBe('Prevent auto-stopping');
});
diff --git a/spec/frontend/environments/environment_table_spec.js b/spec/frontend/environments/environment_table_spec.js
index a86cfdd56ba..652b0f807fe 100644
--- a/spec/frontend/environments/environment_table_spec.js
+++ b/spec/frontend/environments/environment_table_spec.js
@@ -34,10 +34,6 @@ describe('Environment table', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('Should render a table', async () => {
const mockItem = {
name: 'review',
diff --git a/spec/frontend/environments/environments_app_spec.js b/spec/frontend/environments/environments_app_spec.js
index 986ecca4e84..a843f801da5 100644
--- a/spec/frontend/environments/environments_app_spec.js
+++ b/spec/frontend/environments/environments_app_spec.js
@@ -96,10 +96,6 @@ describe('~/environments/components/environments_app.vue', () => {
paginationMock = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should request available environments if the scope is invalid', async () => {
await createWrapperWithMocked({
environmentsApp: resolvedEnvironmentsApp,
diff --git a/spec/frontend/environments/environments_detail_header_spec.js b/spec/frontend/environments/environments_detail_header_spec.js
index 1f233c05fbf..8574743919f 100644
--- a/spec/frontend/environments/environments_detail_header_spec.js
+++ b/spec/frontend/environments/environments_detail_header_spec.js
@@ -47,7 +47,7 @@ describe('Environments detail header component', () => {
TimeAgo,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: {
canAdminEnvironment: false,
@@ -59,10 +59,6 @@ describe('Environments detail header component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default state with minimal access', () => {
beforeEach(() => {
createWrapper({ props: { environment: createEnvironment({ externalUrl: null }) } });
diff --git a/spec/frontend/environments/environments_folder_view_spec.js b/spec/frontend/environments/environments_folder_view_spec.js
index a87060f83d8..75fb3a31120 100644
--- a/spec/frontend/environments/environments_folder_view_spec.js
+++ b/spec/frontend/environments/environments_folder_view_spec.js
@@ -24,7 +24,6 @@ describe('Environments Folder View', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('successful request', () => {
diff --git a/spec/frontend/environments/graphql/mock_data.js b/spec/frontend/environments/graphql/mock_data.js
index 5ea0be41614..b5435990042 100644
--- a/spec/frontend/environments/graphql/mock_data.js
+++ b/spec/frontend/environments/graphql/mock_data.js
@@ -798,3 +798,9 @@ export const resolvedDeploymentDetails = {
},
},
};
+
+export const agent = {
+ project: 'agent-project',
+ id: '1',
+ name: 'agent-name',
+};
diff --git a/spec/frontend/environments/kubernetes_agent_info_spec.js b/spec/frontend/environments/kubernetes_agent_info_spec.js
new file mode 100644
index 00000000000..4a6e2a7373b
--- /dev/null
+++ b/spec/frontend/environments/kubernetes_agent_info_spec.js
@@ -0,0 +1,126 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlIcon, GlLink, GlSprintf, GlLoadingIcon, GlAlert } from '@gitlab/ui';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import KubernetesAgentInfo from '~/environments/components/kubernetes_agent_info.vue';
+import { TOKEN_STATUS_ACTIVE } from '~/clusters/agents/constants';
+import { AGENT_STATUSES, ACTIVE_CONNECTION_TIME } from '~/clusters_list/constants';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import getK8sClusterAgentQuery from '~/environments/graphql/queries/k8s_cluster_agent.query.graphql';
+
+Vue.use(VueApollo);
+
+const propsData = {
+ agentName: 'my-agent',
+ agentId: '1',
+ agentProjectPath: 'path/to/agent-config-project',
+};
+
+const mockClusterAgent = {
+ id: '1',
+ name: 'token-1',
+ webPath: 'path/to/agent-page',
+};
+
+const connectedTimeNow = new Date();
+const connectedTimeInactive = new Date(connectedTimeNow.getTime() - ACTIVE_CONNECTION_TIME);
+
+describe('~/environments/components/kubernetes_agent_info.vue', () => {
+ let wrapper;
+ let agentQueryResponse;
+
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findAgentLink = () => wrapper.findComponent(GlLink);
+ const findAgentStatus = () => wrapper.findByTestId('agent-status');
+ const findAgentStatusIcon = () => findAgentStatus().findComponent(GlIcon);
+ const findAgentLastUsedDate = () => wrapper.findByTestId('agent-last-used-date');
+ const findAlert = () => wrapper.findComponent(GlAlert);
+
+ const createWrapper = ({ tokens = [], queryResponse = null } = {}) => {
+ const clusterAgent = { ...mockClusterAgent, tokens: { nodes: tokens } };
+
+ agentQueryResponse =
+ queryResponse ||
+ jest.fn().mockResolvedValue({ data: { project: { id: 'project-1', clusterAgent } } });
+ const apolloProvider = createMockApollo([[getK8sClusterAgentQuery, agentQueryResponse]]);
+
+ wrapper = extendedWrapper(
+ shallowMount(KubernetesAgentInfo, {
+ apolloProvider,
+ propsData,
+ stubs: { TimeAgoTooltip, GlSprintf },
+ }),
+ );
+ };
+
+ describe('default', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('shows loading icon while fetching the agent details', async () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ await waitForPromises();
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('sends expected params', async () => {
+ await waitForPromises();
+
+ const variables = {
+ agentName: propsData.agentName,
+ projectPath: propsData.agentProjectPath,
+ tokenStatus: TOKEN_STATUS_ACTIVE,
+ };
+
+ expect(agentQueryResponse).toHaveBeenCalledWith(variables);
+ });
+
+ it('renders the agent name with the link', async () => {
+ await waitForPromises();
+
+ expect(findAgentLink().attributes('href')).toBe(mockClusterAgent.webPath);
+ expect(findAgentLink().text()).toContain(mockClusterAgent.id);
+ });
+ });
+
+ describe.each`
+ lastUsedAt | status | lastUsedText
+ ${null} | ${'unused'} | ${KubernetesAgentInfo.i18n.neverConnectedText}
+ ${connectedTimeNow} | ${'active'} | ${'just now'}
+ ${connectedTimeInactive} | ${'inactive'} | ${'8 minutes ago'}
+ `('when agent connection status is "$status"', ({ lastUsedAt, status, lastUsedText }) => {
+ beforeEach(async () => {
+ const tokens = [{ id: 'token-id', lastUsedAt }];
+ createWrapper({ tokens });
+ await waitForPromises();
+ });
+
+ it('displays correct status text', () => {
+ expect(findAgentStatus().text()).toBe(AGENT_STATUSES[status].name);
+ });
+
+ it('displays correct status icon', () => {
+ expect(findAgentStatusIcon().props('name')).toBe(AGENT_STATUSES[status].icon);
+ expect(findAgentStatusIcon().attributes('class')).toBe(AGENT_STATUSES[status].class);
+ });
+
+ it('displays correct last used date status', () => {
+ expect(findAgentLastUsedDate().text()).toBe(lastUsedText);
+ });
+ });
+
+ describe('when the agent query has errored', () => {
+ beforeEach(() => {
+ createWrapper({ clusterAgent: null, queryResponse: jest.fn().mockRejectedValue() });
+ return waitForPromises();
+ });
+
+ it('displays an alert message', () => {
+ expect(findAlert().text()).toBe(KubernetesAgentInfo.i18n.loadingError);
+ });
+ });
+});
diff --git a/spec/frontend/environments/kubernetes_overview_spec.js b/spec/frontend/environments/kubernetes_overview_spec.js
new file mode 100644
index 00000000000..8673c657760
--- /dev/null
+++ b/spec/frontend/environments/kubernetes_overview_spec.js
@@ -0,0 +1,84 @@
+import { nextTick } from 'vue';
+import { shallowMount } from '@vue/test-utils';
+import { GlCollapse, GlButton } from '@gitlab/ui';
+import KubernetesOverview from '~/environments/components/kubernetes_overview.vue';
+import KubernetesAgentInfo from '~/environments/components/kubernetes_agent_info.vue';
+
+const agent = {
+ project: 'agent-project',
+ id: '1',
+ name: 'agent-name',
+};
+
+const propsData = {
+ agentId: agent.id,
+ agentName: agent.name,
+ agentProjectPath: agent.project,
+};
+
+describe('~/environments/components/kubernetes_overview.vue', () => {
+ let wrapper;
+
+ const findCollapse = () => wrapper.findComponent(GlCollapse);
+ const findCollapseButton = () => wrapper.findComponent(GlButton);
+ const findAgentInfo = () => wrapper.findComponent(KubernetesAgentInfo);
+
+ const createWrapper = () => {
+ wrapper = shallowMount(KubernetesOverview, {
+ propsData,
+ });
+ };
+
+ const toggleCollapse = async () => {
+ findCollapseButton().vm.$emit('click');
+ await nextTick();
+ };
+
+ describe('default', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('renders the kubernetes overview title', () => {
+ expect(wrapper.text()).toBe(KubernetesOverview.i18n.sectionTitle);
+ });
+ });
+
+ describe('collapse', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('is collapsed by default', () => {
+ expect(findCollapse().props('visible')).toBeUndefined();
+ expect(findCollapseButton().attributes('aria-label')).toBe(KubernetesOverview.i18n.expand);
+ expect(findCollapseButton().props('icon')).toBe('chevron-right');
+ });
+
+ it("doesn't render components when the collapse is not visible", () => {
+ expect(findAgentInfo().exists()).toBe(false);
+ });
+
+ it('opens on click', async () => {
+ findCollapseButton().vm.$emit('click');
+ await nextTick();
+
+ expect(findCollapse().attributes('visible')).toBe('true');
+ expect(findCollapseButton().attributes('aria-label')).toBe(KubernetesOverview.i18n.collapse);
+ expect(findCollapseButton().props('icon')).toBe('chevron-down');
+ });
+ });
+
+ describe('when section is expanded', () => {
+ it('renders kubernetes agent info', async () => {
+ createWrapper();
+ await toggleCollapse();
+
+ expect(findAgentInfo().props()).toEqual({
+ agentName: agent.name,
+ agentId: agent.id,
+ agentProjectPath: agent.project,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/environments/new_environment_item_spec.js b/spec/frontend/environments/new_environment_item_spec.js
index 76cd09cfb4e..c04ff896794 100644
--- a/spec/frontend/environments/new_environment_item_spec.js
+++ b/spec/frontend/environments/new_environment_item_spec.js
@@ -9,7 +9,8 @@ import { __, s__, sprintf } from '~/locale';
import EnvironmentItem from '~/environments/components/new_environment_item.vue';
import Deployment from '~/environments/components/deployment.vue';
import DeployBoardWrapper from '~/environments/components/deploy_board_wrapper.vue';
-import { resolvedEnvironment, rolloutStatus } from './graphql/mock_data';
+import KubernetesOverview from '~/environments/components/kubernetes_overview.vue';
+import { resolvedEnvironment, rolloutStatus, agent } from './graphql/mock_data';
Vue.use(VueApollo);
@@ -20,15 +21,16 @@ describe('~/environments/components/new_environment_item.vue', () => {
return createMockApollo();
};
- const createWrapper = ({ propsData = {}, apolloProvider } = {}) =>
+ const createWrapper = ({ propsData = {}, provideData = {}, apolloProvider } = {}) =>
mountExtended(EnvironmentItem, {
apolloProvider,
propsData: { environment: resolvedEnvironment, ...propsData },
- provide: { helpPagePath: '/help', projectId: '1', projectPath: '/1' },
+ provide: { helpPagePath: '/help', projectId: '1', projectPath: '/1', ...provideData },
stubs: { transition: stubTransition() },
});
const findDeployment = () => wrapper.findComponent(Deployment);
+ const findKubernetesOverview = () => wrapper.findComponent(KubernetesOverview);
const expandCollapsedSection = async () => {
const button = wrapper.findByRole('button', { name: __('Expand') });
@@ -37,10 +39,6 @@ describe('~/environments/components/new_environment_item.vue', () => {
return button;
};
- afterEach(() => {
- wrapper?.destroy();
- });
-
it('displays the name when not in a folder', () => {
wrapper = createWrapper({ apolloProvider: createApolloProvider() });
@@ -157,7 +155,7 @@ describe('~/environments/components/new_environment_item.vue', () => {
});
describe('stop', () => {
- it('shows a buton to stop the environment if the environment is available', () => {
+ it('shows a button to stop the environment if the environment is available', () => {
wrapper = createWrapper({ apolloProvider: createApolloProvider() });
const stop = wrapper.findByRole('button', { name: s__('Environments|Stop environment') });
@@ -165,7 +163,7 @@ describe('~/environments/components/new_environment_item.vue', () => {
expect(stop.exists()).toBe(true);
});
- it('does not show a buton to stop the environment if the environment is stopped', () => {
+ it('does not show a button to stop the environment if the environment is stopped', () => {
wrapper = createWrapper({
propsData: { environment: { ...resolvedEnvironment, canStop: false } },
apolloProvider: createApolloProvider(),
@@ -515,4 +513,71 @@ describe('~/environments/components/new_environment_item.vue', () => {
expect(deployBoard.exists()).toBe(false);
});
});
+
+ describe('kubernetes overview', () => {
+ const environmentWithAgent = {
+ ...resolvedEnvironment,
+ agent,
+ };
+
+ it('should render if the feature flag is enabled and the environment has an agent object with the required data specified', () => {
+ wrapper = createWrapper({
+ propsData: { environment: environmentWithAgent },
+ provideData: {
+ glFeatures: {
+ kasUserAccessProject: true,
+ },
+ },
+ apolloProvider: createApolloProvider(),
+ });
+
+ expandCollapsedSection();
+
+ expect(findKubernetesOverview().props()).toMatchObject({
+ agentProjectPath: agent.project,
+ agentName: agent.name,
+ agentId: agent.id,
+ });
+ });
+
+ it('should not render if the feature flag is not enabled', () => {
+ wrapper = createWrapper({
+ propsData: { environment: environmentWithAgent },
+ apolloProvider: createApolloProvider(),
+ });
+
+ expandCollapsedSection();
+
+ expect(findKubernetesOverview().exists()).toBe(false);
+ });
+
+ it('should not render if the environment has no agent object', () => {
+ wrapper = createWrapper({
+ apolloProvider: createApolloProvider(),
+ });
+
+ expandCollapsedSection();
+
+ expect(findKubernetesOverview().exists()).toBe(false);
+ });
+
+ it('should not render if the environment has an agent object without agent id specified', () => {
+ const environment = {
+ ...resolvedEnvironment,
+ agent: {
+ project: agent.project,
+ name: agent.name,
+ },
+ };
+
+ wrapper = createWrapper({
+ propsData: { environment },
+ apolloProvider: createApolloProvider(),
+ });
+
+ expandCollapsedSection();
+
+ expect(findKubernetesOverview().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/environments/new_environment_spec.js b/spec/frontend/environments/new_environment_spec.js
index a8cc05b297b..743f4ad6786 100644
--- a/spec/frontend/environments/new_environment_spec.js
+++ b/spec/frontend/environments/new_environment_spec.js
@@ -3,13 +3,13 @@ import MockAdapter from 'axios-mock-adapter';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import NewEnvironment from '~/environments/components/new_environment.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility');
-jest.mock('~/flash');
+jest.mock('~/alert');
const DEFAULT_OPTS = {
provide: {
@@ -41,7 +41,6 @@ describe('~/environments/components/new.vue', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
const showsLoading = () => wrapper.findComponent(GlLoadingIcon).exists();
diff --git a/spec/frontend/environments/stop_stale_environments_modal_spec.js b/spec/frontend/environments/stop_stale_environments_modal_spec.js
index a2ab4f707b5..ddf6670db12 100644
--- a/spec/frontend/environments/stop_stale_environments_modal_spec.js
+++ b/spec/frontend/environments/stop_stale_environments_modal_spec.js
@@ -18,7 +18,6 @@ describe('~/environments/components/stop_stale_environments_modal.vue', () => {
let wrapper;
let mock;
let before;
- let originalGon;
const createWrapper = (opts = {}) =>
shallowMount(StopStaleEnvironmentsModal, {
@@ -28,8 +27,7 @@ describe('~/environments/components/stop_stale_environments_modal.vue', () => {
});
beforeEach(() => {
- originalGon = window.gon;
- window.gon = { api_version: 'v4' };
+ window.gon.api_version = 'v4';
mock = new MockAdapter(axios);
jest.spyOn(axios, 'post');
@@ -39,9 +37,7 @@ describe('~/environments/components/stop_stale_environments_modal.vue', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
jest.resetAllMocks();
- window.gon = originalGon;
});
it('sets the correct min and max dates', async () => {
diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js
index 9d6e46be8c4..3bfade12d27 100644
--- a/spec/frontend/error_tracking/components/error_details_spec.js
+++ b/spec/frontend/error_tracking/components/error_details_spec.js
@@ -18,11 +18,11 @@ import {
trackErrorDetailsViewsOptions,
trackErrorStatusUpdateOptions,
} from '~/error_tracking/utils';
-import { createAlert, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/alert';
import { __ } from '~/locale';
import Tracking from '~/tracking';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(Vuex);
@@ -148,7 +148,7 @@ describe('ErrorDetails', () => {
expect(mocks.$apollo.queries.error.stopPolling).not.toHaveBeenCalled();
});
- it('when timeout is hit and no apollo result, stops loading and shows flash', async () => {
+ it('when timeout is hit and no apollo result, stops loading and shows alert', async () => {
Date.now.mockReturnValue(endTime + 1);
wrapper.vm.onNoApolloResult();
diff --git a/spec/frontend/error_tracking/store/actions_spec.js b/spec/frontend/error_tracking/store/actions_spec.js
index 3ec43010d80..44db4780ba9 100644
--- a/spec/frontend/error_tracking/store/actions_spec.js
+++ b/spec/frontend/error_tracking/store/actions_spec.js
@@ -2,12 +2,12 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/error_tracking/store/actions';
import * as types from '~/error_tracking/store/mutation_types';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
let mock;
diff --git a/spec/frontend/error_tracking/store/details/actions_spec.js b/spec/frontend/error_tracking/store/details/actions_spec.js
index 383d8aaeb20..0aeb8b19a9e 100644
--- a/spec/frontend/error_tracking/store/details/actions_spec.js
+++ b/spec/frontend/error_tracking/store/details/actions_spec.js
@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/error_tracking/store/details/actions';
import * as types from '~/error_tracking/store/details/mutation_types';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import {
HTTP_STATUS_BAD_REQUEST,
@@ -14,7 +14,7 @@ import Poll from '~/lib/utils/poll';
let mockedAdapter;
let mockedRestart;
-jest.mock('~/flash.js');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
describe('Sentry error details store actions', () => {
@@ -48,7 +48,7 @@ describe('Sentry error details store actions', () => {
);
});
- it('should show flash on API error', async () => {
+ it('should show alert on API error', async () => {
mockedAdapter.onGet().reply(HTTP_STATUS_BAD_REQUEST);
await testAction(
diff --git a/spec/frontend/error_tracking/store/list/actions_spec.js b/spec/frontend/error_tracking/store/list/actions_spec.js
index 590983bd93d..24a26476455 100644
--- a/spec/frontend/error_tracking/store/list/actions_spec.js
+++ b/spec/frontend/error_tracking/store/list/actions_spec.js
@@ -2,11 +2,11 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/error_tracking/store/list/actions';
import * as types from '~/error_tracking/store/list/mutation_types';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
describe('error tracking actions', () => {
let mock;
@@ -38,7 +38,7 @@ describe('error tracking actions', () => {
);
});
- it('should show flash on API error', async () => {
+ it('should show alert on API error', async () => {
mock.onGet().reply(HTTP_STATUS_BAD_REQUEST);
await testAction(
diff --git a/spec/frontend/experimentation/components/gitlab_experiment_spec.js b/spec/frontend/experimentation/components/gitlab_experiment_spec.js
index f52ebf0f3c4..73db4b9503c 100644
--- a/spec/frontend/experimentation/components/gitlab_experiment_spec.js
+++ b/spec/frontend/experimentation/components/gitlab_experiment_spec.js
@@ -9,7 +9,6 @@ const defaultSlots = {
};
describe('ExperimentComponent', () => {
- const oldGon = window.gon;
let wrapper;
const createComponent = (propsData = defaultProps, slots = defaultSlots) => {
@@ -20,12 +19,6 @@ describe('ExperimentComponent', () => {
window.gon = { experiment: { experiment_name: { variant: expectedVariant } } };
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- window.gon = oldGon;
- });
-
describe('when variant and experiment is set', () => {
it('renders control when it is the active variant', () => {
mockVariant('control');
diff --git a/spec/frontend/experimentation/utils_spec.js b/spec/frontend/experimentation/utils_spec.js
index 0d663fd055e..6d9c9dfe65a 100644
--- a/spec/frontend/experimentation/utils_spec.js
+++ b/spec/frontend/experimentation/utils_spec.js
@@ -10,18 +10,15 @@ describe('experiment Utilities', () => {
const ABC_KEY = 'abc';
const DEF_KEY = 'def';
- let origGon;
let origGl;
beforeEach(() => {
- origGon = window.gon;
origGl = window.gl;
window.gon.experiment = {};
window.gl.experiments = {};
});
afterEach(() => {
- window.gon = origGon;
window.gl = origGl;
});
diff --git a/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js b/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js
index c1051a14a08..b06e0340991 100644
--- a/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js
+++ b/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js
@@ -42,7 +42,6 @@ describe('Configure Feature Flags Modal', () => {
wrapper.findAllComponents(GlAlert).filter((c) => c.props('variant') === 'danger');
describe('idle', () => {
- afterEach(() => wrapper.destroy());
beforeEach(factory);
it('should have Primary and Secondary actions', () => {
@@ -51,7 +50,7 @@ describe('Configure Feature Flags Modal', () => {
});
it('should default disable the primary action', () => {
- const [{ disabled }] = findSecondaryAction().attributes;
+ const { disabled } = findSecondaryAction().attributes;
expect(disabled).toBe(true);
});
@@ -112,19 +111,17 @@ describe('Configure Feature Flags Modal', () => {
});
describe('verified', () => {
- afterEach(() => wrapper.destroy());
beforeEach(factory);
it('should enable the secondary action', async () => {
findProjectNameInput().vm.$emit('input', provide.projectName);
await nextTick();
- const [{ disabled }] = findSecondaryAction().attributes;
+ const { disabled } = findSecondaryAction().attributes;
expect(disabled).toBe(false);
});
});
describe('cannot rotate token', () => {
- afterEach(() => wrapper.destroy());
beforeEach(factory.bind(null, { canUserRotateToken: false }));
it('should not display the primary action', () => {
@@ -141,7 +138,6 @@ describe('Configure Feature Flags Modal', () => {
});
describe('has rotate error', () => {
- afterEach(() => wrapper.destroy());
beforeEach(() => {
factory({ hasRotateError: true });
});
@@ -153,7 +149,6 @@ describe('Configure Feature Flags Modal', () => {
});
describe('is rotating', () => {
- afterEach(() => wrapper.destroy());
beforeEach(factory.bind(null, { isRotating: true }));
it('should disable the project name input', async () => {
diff --git a/spec/frontend/feature_flags/components/edit_feature_flag_spec.js b/spec/frontend/feature_flags/components/edit_feature_flag_spec.js
index cf4605e21ea..c26fd80865d 100644
--- a/spec/frontend/feature_flags/components/edit_feature_flag_spec.js
+++ b/spec/frontend/feature_flags/components/edit_feature_flag_spec.js
@@ -53,7 +53,6 @@ describe('Edit feature flag form', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/feature_flags/components/empty_state_spec.js b/spec/frontend/feature_flags/components/empty_state_spec.js
index e3cc6f703c4..d983332f7c1 100644
--- a/spec/frontend/feature_flags/components/empty_state_spec.js
+++ b/spec/frontend/feature_flags/components/empty_state_spec.js
@@ -48,8 +48,6 @@ describe('feature_flags/components/feature_flags_tab.vue', () => {
if (wrapper?.destroy) {
wrapper.destroy();
}
-
- wrapper = null;
});
describe('alerts', () => {
diff --git a/spec/frontend/feature_flags/components/environments_dropdown_spec.js b/spec/frontend/feature_flags/components/environments_dropdown_spec.js
index a4738fed37e..9fc0119a6c8 100644
--- a/spec/frontend/feature_flags/components/environments_dropdown_spec.js
+++ b/spec/frontend/feature_flags/components/environments_dropdown_spec.js
@@ -27,7 +27,6 @@ describe('Feature flags > Environments dropdown', () => {
const findDropdownMenu = () => wrapper.find('.dropdown-menu');
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/feature_flags/components/feature_flags_spec.js b/spec/frontend/feature_flags/components/feature_flags_spec.js
index e80f9c559c4..23e86d0eb2f 100644
--- a/spec/frontend/feature_flags/components/feature_flags_spec.js
+++ b/spec/frontend/feature_flags/components/feature_flags_spec.js
@@ -65,8 +65,6 @@ describe('Feature flags', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
- wrapper = null;
});
describe('when limit exceeded', () => {
diff --git a/spec/frontend/feature_flags/components/form_spec.js b/spec/frontend/feature_flags/components/form_spec.js
index 7dd7c709c94..f66e25698e6 100644
--- a/spec/frontend/feature_flags/components/form_spec.js
+++ b/spec/frontend/feature_flags/components/form_spec.js
@@ -42,10 +42,6 @@ describe('feature flag form', () => {
Api.fetchFeatureFlagUserLists.mockResolvedValue({ data: [] });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render provided submitText', () => {
factory(requiredProps);
diff --git a/spec/frontend/feature_flags/components/new_feature_flag_spec.js b/spec/frontend/feature_flags/components/new_feature_flag_spec.js
index 300d0e47082..46c9118cbd9 100644
--- a/spec/frontend/feature_flags/components/new_feature_flag_spec.js
+++ b/spec/frontend/feature_flags/components/new_feature_flag_spec.js
@@ -46,10 +46,6 @@ describe('New feature flag form', () => {
factory();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with error', () => {
it('should render the error', async () => {
store.dispatch('receiveCreateFeatureFlagError', { message: ['The name is required'] });
diff --git a/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js b/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js
index 70a9156b5a9..5feaf094701 100644
--- a/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js
+++ b/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js
@@ -24,8 +24,6 @@ describe('feature_flags/components/strategies/flexible_rollout.vue', () => {
if (wrapper?.destroy) {
wrapper.destroy();
}
-
- wrapper = null;
});
describe('with valid percentage', () => {
diff --git a/spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js b/spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js
index 23ad0d3a08d..365f1e534b5 100644
--- a/spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js
+++ b/spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js
@@ -28,8 +28,6 @@ describe('~/feature_flags/strategies/parameter_form_group.vue', () => {
if (wrapper?.destroy) {
wrapper.destroy();
}
-
- wrapper = null;
});
it('should display the default slot', () => {
diff --git a/spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js b/spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js
index cb422a018f9..b20061c12a2 100644
--- a/spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js
+++ b/spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js
@@ -22,8 +22,6 @@ describe('~/feature_flags/components/strategies/percent_rollout.vue', () => {
if (wrapper?.destroy) {
wrapper.destroy();
}
-
- wrapper = null;
});
describe('with valid percentage', () => {
diff --git a/spec/frontend/feature_flags/components/strategies/users_with_id_spec.js b/spec/frontend/feature_flags/components/strategies/users_with_id_spec.js
index 0a72714c22a..ae489f3a6e6 100644
--- a/spec/frontend/feature_flags/components/strategies/users_with_id_spec.js
+++ b/spec/frontend/feature_flags/components/strategies/users_with_id_spec.js
@@ -22,8 +22,6 @@ describe('~/feature_flags/components/users_with_id.vue', () => {
if (wrapper?.destroy) {
wrapper.destroy();
}
-
- wrapper = null;
});
it('should display the current value of the parameters', () => {
diff --git a/spec/frontend/feature_flags/components/strategy_parameters_spec.js b/spec/frontend/feature_flags/components/strategy_parameters_spec.js
index d0f1f7d0e2a..cd8270f1801 100644
--- a/spec/frontend/feature_flags/components/strategy_parameters_spec.js
+++ b/spec/frontend/feature_flags/components/strategy_parameters_spec.js
@@ -32,8 +32,6 @@ describe('~/feature_flags/components/strategy_parameters.vue', () => {
if (wrapper?.destroy) {
wrapper.destroy();
}
-
- wrapper = null;
});
describe.each`
diff --git a/spec/frontend/feature_highlight/feature_highlight_helper_spec.js b/spec/frontend/feature_highlight/feature_highlight_helper_spec.js
index 4d5cb26810e..4609bfc23d7 100644
--- a/spec/frontend/feature_highlight/feature_highlight_helper_spec.js
+++ b/spec/frontend/feature_highlight/feature_highlight_helper_spec.js
@@ -1,10 +1,10 @@
import MockAdapter from 'axios-mock-adapter';
import { dismiss } from '~/feature_highlight/feature_highlight_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_CREATED, HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('feature highlight helper', () => {
describe('dismiss', () => {
@@ -26,7 +26,7 @@ describe('feature highlight helper', () => {
await expect(dismiss(endpoint, highlightId)).resolves.toEqual(expect.anything());
});
- it('triggers flash when dismiss request fails', async () => {
+ it('triggers an alert when dismiss request fails', async () => {
mockAxios
.onPost(endpoint, { feature_name: highlightId })
.replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
diff --git a/spec/frontend/feature_highlight/feature_highlight_popover_spec.js b/spec/frontend/feature_highlight/feature_highlight_popover_spec.js
index 650f9eb1bbc..66ea22cece3 100644
--- a/spec/frontend/feature_highlight/feature_highlight_popover_spec.js
+++ b/spec/frontend/feature_highlight/feature_highlight_popover_spec.js
@@ -29,11 +29,6 @@ describe('feature_highlight/feature_highlight_popover', () => {
buildWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders popover target', () => {
expect(findPopoverTarget().exists()).toBe(true);
});
diff --git a/spec/frontend/filtered_search/components/recent_searches_dropdown_content_spec.js b/spec/frontend/filtered_search/components/recent_searches_dropdown_content_spec.js
index ebed477fa2f..5f0e928e1fe 100644
--- a/spec/frontend/filtered_search/components/recent_searches_dropdown_content_spec.js
+++ b/spec/frontend/filtered_search/components/recent_searches_dropdown_content_spec.js
@@ -22,11 +22,6 @@ describe('Recent Searches Dropdown Content', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when local storage is not available', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/filtered_search/dropdown_user_spec.js b/spec/frontend/filtered_search/dropdown_user_spec.js
index 26f12673f68..02ef813883f 100644
--- a/spec/frontend/filtered_search/dropdown_user_spec.js
+++ b/spec/frontend/filtered_search/dropdown_user_spec.js
@@ -68,10 +68,6 @@ describe('Dropdown User', () => {
'/gitlab_directory/-/autocomplete/users.json',
);
});
-
- afterEach(() => {
- window.gon = {};
- });
});
describe('hideCurrentUser', () => {
diff --git a/spec/frontend/filtered_search/filtered_search_manager_spec.js b/spec/frontend/filtered_search/filtered_search_manager_spec.js
index 26af7af701b..8c16ff100eb 100644
--- a/spec/frontend/filtered_search/filtered_search_manager_spec.js
+++ b/spec/frontend/filtered_search/filtered_search_manager_spec.js
@@ -8,11 +8,11 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered
import RecentSearchesRoot from '~/filtered_search/recent_searches_root';
import RecentSearchesService from '~/filtered_search/services/recent_searches_service';
import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { BACKSPACE_KEY_CODE, DELETE_KEY_CODE } from '~/lib/utils/keycodes';
import { visitUrl, getParameterByName } from '~/lib/utils/url_utility';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
getParameterByName: jest.fn(),
diff --git a/spec/frontend/filtered_search/visual_token_value_spec.js b/spec/frontend/filtered_search/visual_token_value_spec.js
index d3fa8fae9ab..138a4e183a9 100644
--- a/spec/frontend/filtered_search/visual_token_value_spec.js
+++ b/spec/frontend/filtered_search/visual_token_value_spec.js
@@ -5,11 +5,11 @@ import FilteredSearchSpecHelper from 'helpers/filtered_search_spec_helper';
import { TEST_HOST } from 'helpers/test_constants';
import DropdownUtils from '~/filtered_search/dropdown_utils';
import VisualTokenValue from '~/filtered_search/visual_token_value';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import AjaxCache from '~/lib/utils/ajax_cache';
import UsersCache from '~/lib/utils/users_cache';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Filtered Search Visual Tokens', () => {
const findElements = (tokenElement) => {
diff --git a/spec/frontend/fixtures/abuse_reports.rb b/spec/frontend/fixtures/abuse_reports.rb
index d8c8737b125..ad0fb9be8dc 100644
--- a/spec/frontend/fixtures/abuse_reports.rb
+++ b/spec/frontend/fixtures/abuse_reports.rb
@@ -14,6 +14,8 @@ RSpec.describe Admin::AbuseReportsController, '(JavaScript fixtures)', type: :co
render_views
before do
+ stub_feature_flags(abuse_reports_list: false)
+
sign_in(admin)
enable_admin_mode!(admin)
end
diff --git a/spec/frontend/fixtures/api_deploy_keys.rb b/spec/frontend/fixtures/api_deploy_keys.rb
index 5ffc726f086..8c926296817 100644
--- a/spec/frontend/fixtures/api_deploy_keys.rb
+++ b/spec/frontend/fixtures/api_deploy_keys.rb
@@ -7,6 +7,7 @@ RSpec.describe API::DeployKeys, '(JavaScript fixtures)', type: :request do
include JavaScriptFixturesHelpers
let_it_be(:admin) { create(:admin) }
+ let_it_be(:path) { "/deploy_keys" }
let_it_be(:project) { create(:project) }
let_it_be(:project2) { create(:project) }
let_it_be(:deploy_key) { create(:deploy_key, public: true) }
@@ -17,8 +18,10 @@ RSpec.describe API::DeployKeys, '(JavaScript fixtures)', type: :request do
let_it_be(:deploy_keys_project3) { create(:deploy_keys_project, :write_access, project: project, deploy_key: deploy_key2) }
let_it_be(:deploy_keys_project4) { create(:deploy_keys_project, :write_access, project: project2, deploy_key: deploy_key2) }
+ it_behaves_like 'GET request permissions for admin mode'
+
it 'api/deploy_keys/index.json' do
- get api("/deploy_keys", admin)
+ get api("/deploy_keys", admin, admin_mode: true)
expect(response).to be_successful
end
diff --git a/spec/frontend/fixtures/jobs.rb b/spec/frontend/fixtures/jobs.rb
index 6d452bf1bff..3583beb83c2 100644
--- a/spec/frontend/fixtures/jobs.rb
+++ b/spec/frontend/fixtures/jobs.rb
@@ -93,4 +93,26 @@ RSpec.describe 'Jobs (JavaScript fixtures)' do
expect_graphql_errors_to_be_empty
end
end
+
+ describe 'get_jobs_count.query.graphql', type: :request do
+ let!(:build) { create(:ci_build, :success, name: 'build', pipeline: pipeline) }
+ let!(:cancelable) { create(:ci_build, :cancelable, name: 'cancelable', pipeline: pipeline) }
+ let!(:failed) { create(:ci_build, :failed, name: 'failed', pipeline: pipeline) }
+
+ fixtures_path = 'graphql/jobs/'
+ get_jobs_count_query = 'get_jobs_count.query.graphql'
+ full_path = 'frontend-fixtures/builds-project'
+
+ let_it_be(:query) do
+ get_graphql_query_as_string("jobs/components/table/graphql/queries/#{get_jobs_count_query}")
+ end
+
+ it "#{fixtures_path}#{get_jobs_count_query}.json" do
+ post_graphql(query, current_user: user, variables: {
+ fullPath: full_path
+ })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
end
diff --git a/spec/frontend/fixtures/merge_requests.rb b/spec/frontend/fixtures/merge_requests.rb
index 7ee89ca3694..b6f6d149756 100644
--- a/spec/frontend/fixtures/merge_requests.rb
+++ b/spec/frontend/fixtures/merge_requests.rb
@@ -151,7 +151,7 @@ RSpec.describe Projects::MergeRequestsController, '(JavaScript fixtures)', type:
context 'merge request with no approvals' do
base_input_path = 'vue_merge_request_widget/components/approvals/queries/'
base_output_path = 'graphql/merge_requests/approvals/'
- query_name = 'approved_by.query.graphql'
+ query_name = 'approvals.query.graphql'
it "#{base_output_path}#{query_name}_no_approvals.json" do
query = get_graphql_query_as_string("#{base_input_path}#{query_name}", ee: Gitlab.ee?)
@@ -165,7 +165,7 @@ RSpec.describe Projects::MergeRequestsController, '(JavaScript fixtures)', type:
context 'merge request approved by current user' do
base_input_path = 'vue_merge_request_widget/components/approvals/queries/'
base_output_path = 'graphql/merge_requests/approvals/'
- query_name = 'approved_by.query.graphql'
+ query_name = 'approvals.query.graphql'
it "#{base_output_path}#{query_name}.json" do
merge_request.approved_by_users << user
@@ -181,7 +181,7 @@ RSpec.describe Projects::MergeRequestsController, '(JavaScript fixtures)', type:
context 'merge request approved by multiple users' do
base_input_path = 'vue_merge_request_widget/components/approvals/queries/'
base_output_path = 'graphql/merge_requests/approvals/'
- query_name = 'approved_by.query.graphql'
+ query_name = 'approvals.query.graphql'
it "#{base_output_path}#{query_name}_multiple_users.json" do
merge_request.approved_by_users << user
diff --git a/spec/frontend/fixtures/runner.rb b/spec/frontend/fixtures/runner.rb
index f60e4991292..1581bc58289 100644
--- a/spec/frontend/fixtures/runner.rb
+++ b/spec/frontend/fixtures/runner.rb
@@ -145,6 +145,40 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
expect_graphql_errors_to_be_empty
end
end
+
+ describe 'runner_for_registration.query.graphql', :freeze_time, type: :request do
+ runner_for_registration_query = 'register/runner_for_registration.query.graphql'
+
+ let_it_be(:query) do
+ get_graphql_query_as_string("#{query_path}#{runner_for_registration_query}")
+ end
+
+ it "#{fixtures_path}#{runner_for_registration_query}.json" do
+ post_graphql(query, current_user: admin, variables: {
+ id: runner.to_global_id.to_s
+ })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
+ describe 'runner_create.mutation.graphql', type: :request do
+ runner_create_mutation = 'new/runner_create.mutation.graphql'
+
+ let_it_be(:query) do
+ get_graphql_query_as_string("#{query_path}#{runner_create_mutation}")
+ end
+
+ it "#{fixtures_path}#{runner_create_mutation}.json" do
+ post_graphql(query, current_user: admin, variables: {
+ input: {
+ description: 'My dummy runner'
+ }
+ })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
end
describe 'as group owner', GraphQL::Query do
diff --git a/spec/frontend/fixtures/saved_replies.rb b/spec/frontend/fixtures/saved_replies.rb
index c80ba06bca1..613e4a1b447 100644
--- a/spec/frontend/fixtures/saved_replies.rb
+++ b/spec/frontend/fixtures/saved_replies.rb
@@ -43,4 +43,32 @@ RSpec.describe GraphQL::Query, type: :request, feature_category: :user_profile d
expect_graphql_errors_to_be_empty
end
end
+
+ context 'when user creates saved reply' do
+ base_input_path = 'saved_replies/queries/'
+ base_output_path = 'graphql/saved_replies/'
+ query_name = 'create_saved_reply.mutation.graphql'
+
+ it "#{base_output_path}#{query_name}.json" do
+ query = get_graphql_query_as_string("#{base_input_path}#{query_name}")
+
+ post_graphql(query, current_user: current_user, variables: { name: "Test", content: "Test content" })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
+ context 'when user creates saved reply and it errors' do
+ base_input_path = 'saved_replies/queries/'
+ base_output_path = 'graphql/saved_replies/'
+ query_name = 'create_saved_reply.mutation.graphql'
+
+ it "#{base_output_path}create_saved_reply_with_errors.mutation.graphql.json" do
+ query = get_graphql_query_as_string("#{base_input_path}#{query_name}")
+
+ post_graphql(query, current_user: current_user, variables: { name: nil, content: nil })
+
+ expect(flattened_errors).not_to be_empty
+ end
+ end
end
diff --git a/spec/frontend/fixtures/startup_css.rb b/spec/frontend/fixtures/startup_css.rb
index bd2d63a1827..18a4aa58c00 100644
--- a/spec/frontend/fixtures/startup_css.rb
+++ b/spec/frontend/fixtures/startup_css.rb
@@ -16,7 +16,6 @@ RSpec.describe 'Startup CSS fixtures', type: :controller do
before do
# We want vNext badge to be included and com/canary don't remove/hide any other elements.
# This is why we're turning com and canary on by default for now.
- allow(Gitlab).to receive(:com?).and_return(true)
allow(Gitlab).to receive(:canary?).and_return(true)
sign_in(user)
end
@@ -55,13 +54,28 @@ RSpec.describe 'Startup CSS fixtures', type: :controller do
expect(response).to be_successful
end
+
+ # This Feature Flag is off by default
+ # This ensures that the correct css is generated for super sidebar
+ # When the feature flag is off, the general startup will capture it
+ it "startup_css/project-#{type}-super-sidebar.html" do
+ stub_feature_flags(super_sidebar_nav: true)
+ user.update!(use_new_navigation: true)
+
+ get :show, params: {
+ namespace_id: project.namespace.to_param,
+ id: project
+ }
+
+ expect(response).to be_successful
+ end
end
- describe ProjectsController, '(Startup CSS fixtures)', type: :controller do
+ describe ProjectsController, '(Startup CSS fixtures)', :saas, type: :controller do
it_behaves_like 'startup css project fixtures', 'general'
end
- describe ProjectsController, '(Startup CSS fixtures)', type: :controller do
+ describe ProjectsController, '(Startup CSS fixtures)', :saas, type: :controller do
before do
user.update!(theme_id: 11)
end
diff --git a/spec/frontend/fixtures/u2f.rb b/spec/frontend/fixtures/u2f.rb
deleted file mode 100644
index 96820c9ae80..00000000000
--- a/spec/frontend/fixtures/u2f.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.context 'U2F' do
- include JavaScriptFixturesHelpers
-
- let(:user) { create(:user, :two_factor_via_u2f, otp_secret: 'otpsecret:coolkids') }
-
- before do
- stub_feature_flags(webauthn: false)
- end
-
- describe SessionsController, '(JavaScript fixtures)', type: :controller do
- include DeviseHelpers
-
- render_views
-
- before do
- set_devise_mapping(context: @request)
- end
-
- it 'u2f/authenticate.html' do
- allow(controller).to receive(:find_user).and_return(user)
-
- post :create, params: { user: { login: user.username, password: user.password } }
-
- expect(response).to be_successful
- end
- end
-
- describe Profiles::TwoFactorAuthsController, '(JavaScript fixtures)', type: :controller do
- render_views
-
- before do
- sign_in(user)
- allow_next_instance_of(Profiles::TwoFactorAuthsController) do |instance|
- allow(instance).to receive(:build_qr_code).and_return('qrcode:blackandwhitesquares')
- end
- end
-
- it 'u2f/register.html' do
- get :show
-
- expect(response).to be_successful
- end
- end
-end
diff --git a/spec/frontend/fixtures/users.rb b/spec/frontend/fixtures/users.rb
new file mode 100644
index 00000000000..6271aa87b9a
--- /dev/null
+++ b/spec/frontend/fixtures/users.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Users (GraphQL fixtures)', feature_category: :user_profile do
+ describe GraphQL::Query, type: :request do
+ include ApiHelpers
+ include GraphqlHelpers
+ include JavaScriptFixturesHelpers
+
+ let_it_be(:user) { create(:user) }
+
+ context 'for user achievements' do
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:achievement1) { create(:achievement, namespace: group) }
+ let_it_be(:achievement2) { create(:achievement, namespace: group) }
+ let_it_be(:achievement3) { create(:achievement, namespace: group) }
+ let_it_be(:achievement_with_avatar_and_description) do
+ create(:achievement,
+ namespace: group,
+ description: 'Description',
+ avatar: File.new(Rails.root.join('db/fixtures/development/rocket.jpg'), 'r'))
+ end
+
+ let(:user_achievements_query_path) { 'profile/components/graphql/get_user_achievements.query.graphql' }
+ let(:query) { get_graphql_query_as_string(user_achievements_query_path) }
+
+ before_all do
+ group.add_guest(user)
+ end
+
+ it "graphql/get_user_achievements_empty_response.json" do
+ post_graphql(query, current_user: user, variables: { id: user.to_global_id })
+
+ expect_graphql_errors_to_be_empty
+ end
+
+ it "graphql/get_user_achievements_with_avatar_and_description_response.json" do
+ create(:user_achievement, user: user, achievement: achievement_with_avatar_and_description)
+
+ post_graphql(query, current_user: user, variables: { id: user.to_global_id })
+
+ expect_graphql_errors_to_be_empty
+ end
+
+ it "graphql/get_user_achievements_without_avatar_or_description_response.json" do
+ create(:user_achievement, user: user, achievement: achievement1)
+
+ post_graphql(query, current_user: user, variables: { id: user.to_global_id })
+
+ expect_graphql_errors_to_be_empty
+ end
+
+ it "graphql/get_user_achievements_long_response.json" do
+ [achievement1, achievement2, achievement3, achievement_with_avatar_and_description].each do |achievement|
+ create(:user_achievement, user: user, achievement: achievement)
+ end
+
+ post_graphql(query, current_user: user, variables: { id: user.to_global_id })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+ end
+end
diff --git a/spec/frontend/fixtures/webauthn.rb b/spec/frontend/fixtures/webauthn.rb
index c6e9b41b584..ed6180118f0 100644
--- a/spec/frontend/fixtures/webauthn.rb
+++ b/spec/frontend/fixtures/webauthn.rb
@@ -32,6 +32,7 @@ RSpec.context 'WebAuthn' do
allow_next_instance_of(Profiles::TwoFactorAuthsController) do |instance|
allow(instance).to receive(:build_qr_code).and_return('qrcode:blackandwhitesquares')
end
+ stub_feature_flags(webauthn_without_totp: false)
end
it 'webauthn/register.html' do
diff --git a/spec/frontend/flash_spec.js b/spec/frontend/flash_spec.js
deleted file mode 100644
index 17d6cea23df..00000000000
--- a/spec/frontend/flash_spec.js
+++ /dev/null
@@ -1,276 +0,0 @@
-import * as Sentry from '@sentry/browser';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import { createAlert, VARIANT_WARNING } from '~/flash';
-
-jest.mock('@sentry/browser');
-
-describe('Flash', () => {
- const findTextContent = (containerSelector = '.flash-container') =>
- document.querySelector(containerSelector).textContent.replace(/\s+/g, ' ').trim();
-
- describe('createAlert', () => {
- const mockMessage = 'a message';
- let alert;
-
- describe('no flash-container', () => {
- it('does not add to the DOM', () => {
- alert = createAlert({ message: mockMessage });
-
- expect(alert).toBeNull();
- expect(document.querySelector('.gl-alert')).toBeNull();
- });
- });
-
- describe('with flash-container', () => {
- beforeEach(() => {
- setHTMLFixture('<div class="flash-container"></div>');
- });
-
- afterEach(() => {
- if (alert) {
- alert.$destroy();
- }
- resetHTMLFixture();
- });
-
- it('adds alert element into the document by default', () => {
- alert = createAlert({ message: mockMessage });
-
- expect(findTextContent()).toBe(mockMessage);
- expect(document.querySelector('.flash-container .gl-alert')).not.toBeNull();
- });
-
- it('adds flash of a warning type', () => {
- alert = createAlert({ message: mockMessage, variant: VARIANT_WARNING });
-
- expect(
- document.querySelector('.flash-container .gl-alert.gl-alert-warning'),
- ).not.toBeNull();
- });
-
- it('escapes text', () => {
- alert = createAlert({ message: '<script>alert("a");</script>' });
-
- const html = document.querySelector('.flash-container').innerHTML;
-
- expect(html).toContain('&lt;script&gt;alert("a");&lt;/script&gt;');
- expect(html).not.toContain('<script>alert("a");</script>');
- });
-
- it('adds alert into specified container', () => {
- setHTMLFixture(`
- <div class="my-alert-container"></div>
- <div class="my-other-container"></div>
- `);
-
- alert = createAlert({ message: mockMessage, containerSelector: '.my-alert-container' });
-
- expect(document.querySelector('.my-alert-container .gl-alert')).not.toBeNull();
- expect(document.querySelector('.my-alert-container').innerText.trim()).toBe(mockMessage);
-
- expect(document.querySelector('.my-other-container .gl-alert')).toBeNull();
- expect(document.querySelector('.my-other-container').innerText.trim()).toBe('');
- });
-
- it('adds alert into specified parent', () => {
- setHTMLFixture(`
- <div id="my-parent">
- <div class="flash-container"></div>
- </div>
- <div id="my-other-parent">
- <div class="flash-container"></div>
- </div>
- `);
-
- alert = createAlert({ message: mockMessage, parent: document.getElementById('my-parent') });
-
- expect(document.querySelector('#my-parent .flash-container .gl-alert')).not.toBeNull();
- expect(document.querySelector('#my-parent .flash-container').innerText.trim()).toBe(
- mockMessage,
- );
-
- expect(document.querySelector('#my-other-parent .flash-container .gl-alert')).toBeNull();
- expect(document.querySelector('#my-other-parent .flash-container').innerText.trim()).toBe(
- '',
- );
- });
-
- it('removes element after clicking', () => {
- alert = createAlert({ message: mockMessage });
-
- expect(document.querySelector('.flash-container .gl-alert')).not.toBeNull();
-
- document.querySelector('.gl-dismiss-btn').click();
-
- expect(document.querySelector('.flash-container .gl-alert')).toBeNull();
- });
-
- it('does not capture error using Sentry', () => {
- alert = createAlert({
- message: mockMessage,
- captureError: false,
- error: new Error('Error!'),
- });
-
- expect(Sentry.captureException).not.toHaveBeenCalled();
- });
-
- it('captures error using Sentry', () => {
- alert = createAlert({
- message: mockMessage,
- captureError: true,
- error: new Error('Error!'),
- });
-
- expect(Sentry.captureException).toHaveBeenCalledWith(expect.any(Error));
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({
- message: 'Error!',
- }),
- );
- });
-
- describe('with title', () => {
- const mockTitle = 'my title';
-
- it('shows title and message', () => {
- createAlert({
- title: mockTitle,
- message: mockMessage,
- });
-
- expect(findTextContent()).toBe(`${mockTitle} ${mockMessage}`);
- });
- });
-
- describe('with buttons', () => {
- const findAlertAction = () => document.querySelector('.flash-container .gl-alert-action');
-
- it('adds primary button', () => {
- alert = createAlert({
- message: mockMessage,
- primaryButton: {
- text: 'Ok',
- },
- });
-
- expect(findAlertAction().textContent.trim()).toBe('Ok');
- });
-
- it('creates link with href', () => {
- alert = createAlert({
- message: mockMessage,
- primaryButton: {
- link: '/url',
- text: 'Ok',
- },
- });
-
- const action = findAlertAction();
-
- expect(action.textContent.trim()).toBe('Ok');
- expect(action.nodeName).toBe('A');
- expect(action.getAttribute('href')).toBe('/url');
- });
-
- it('create button as href when no href is present', () => {
- alert = createAlert({
- message: mockMessage,
- primaryButton: {
- text: 'Ok',
- },
- });
-
- const action = findAlertAction();
-
- expect(action.nodeName).toBe('BUTTON');
- expect(action.getAttribute('href')).toBe(null);
- });
-
- it('escapes the title text', () => {
- alert = createAlert({
- message: mockMessage,
- primaryButton: {
- text: '<script>alert("a")</script>',
- },
- });
-
- const html = findAlertAction().innerHTML;
-
- expect(html).toContain('&lt;script&gt;alert("a")&lt;/script&gt;');
- expect(html).not.toContain('<script>alert("a")</script>');
- });
-
- it('calls actionConfig clickHandler on click', () => {
- const clickHandler = jest.fn();
-
- alert = createAlert({
- message: mockMessage,
- primaryButton: {
- text: 'Ok',
- clickHandler,
- },
- });
-
- expect(clickHandler).toHaveBeenCalledTimes(0);
-
- findAlertAction().click();
-
- expect(clickHandler).toHaveBeenCalledTimes(1);
- expect(clickHandler).toHaveBeenCalledWith(expect.any(MouseEvent));
- });
- });
-
- describe('Alert API', () => {
- describe('dismiss', () => {
- it('dismiss programmatically with .dismiss()', () => {
- expect(document.querySelector('.gl-alert')).toBeNull();
-
- alert = createAlert({ message: mockMessage });
-
- expect(document.querySelector('.gl-alert')).not.toBeNull();
-
- alert.dismiss();
-
- expect(document.querySelector('.gl-alert')).toBeNull();
- });
-
- it('does not crash if calling .dismiss() twice', () => {
- alert = createAlert({ message: mockMessage });
-
- alert.dismiss();
- expect(() => alert.dismiss()).not.toThrow();
- });
-
- it('calls onDismiss when dismissed', () => {
- const dismissHandler = jest.fn();
-
- alert = createAlert({ message: mockMessage, onDismiss: dismissHandler });
-
- expect(dismissHandler).toHaveBeenCalledTimes(0);
-
- alert.dismiss();
-
- expect(dismissHandler).toHaveBeenCalledTimes(1);
- });
- });
- });
-
- describe('when called multiple times', () => {
- it('clears previous alerts', () => {
- createAlert({ message: 'message 1' });
- createAlert({ message: 'message 2' });
-
- expect(findTextContent()).toBe('message 2');
- });
-
- it('preserves alerts when `preservePrevious` is true', () => {
- createAlert({ message: 'message 1' });
- createAlert({ message: 'message 2', preservePrevious: true });
-
- expect(findTextContent()).toBe('message 1 message 2');
- });
- });
- });
- });
-});
diff --git a/spec/frontend/frequent_items/components/app_spec.js b/spec/frontend/frequent_items/components/app_spec.js
index e1890555de0..4f5788dcb77 100644
--- a/spec/frontend/frequent_items/components/app_spec.js
+++ b/spec/frontend/frequent_items/components/app_spec.js
@@ -69,7 +69,6 @@ describe('Frequent Items App Component', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('default', () => {
diff --git a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js
index c54a2a1d039..7c8592fdf0c 100644
--- a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js
+++ b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js
@@ -59,8 +59,6 @@ describe('FrequentItemsListItemComponent', () => {
afterEach(() => {
unmockTracking();
- wrapper.destroy();
- wrapper = null;
});
describe('computed', () => {
diff --git a/spec/frontend/frequent_items/components/frequent_items_list_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_spec.js
index d024925f62b..87f8e131b77 100644
--- a/spec/frontend/frequent_items/components/frequent_items_list_spec.js
+++ b/spec/frontend/frequent_items/components/frequent_items_list_spec.js
@@ -29,10 +29,6 @@ describe('FrequentItemsListComponent', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
describe('isListEmpty', () => {
it('should return `true` or `false` representing whether if `items` is empty or not with projects', async () => {
diff --git a/spec/frontend/gitlab_pages/new/pages/pages_pipeline_wizard_spec.js b/spec/frontend/gitlab_pages/new/pages/pages_pipeline_wizard_spec.js
index 685b5144a95..b1adc3f794a 100644
--- a/spec/frontend/gitlab_pages/new/pages/pages_pipeline_wizard_spec.js
+++ b/spec/frontend/gitlab_pages/new/pages/pages_pipeline_wizard_spec.js
@@ -50,10 +50,6 @@ describe('PagesPipelineWizard', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows the pipeline wizard', () => {
expect(findPipelineWizardWrapper().exists()).toBe(true);
});
diff --git a/spec/frontend/gitlab_version_check/components/gitlab_version_check_badge_spec.js b/spec/frontend/gitlab_version_check/components/gitlab_version_check_badge_spec.js
index 949bcf71ff5..e87f7e950cd 100644
--- a/spec/frontend/gitlab_version_check/components/gitlab_version_check_badge_spec.js
+++ b/spec/frontend/gitlab_version_check/components/gitlab_version_check_badge_spec.js
@@ -25,7 +25,6 @@ describe('GitlabVersionCheckBadge', () => {
afterEach(() => {
unmockTracking();
- wrapper.destroy();
});
const findGlBadgeClickWrapper = () => wrapper.findByTestId('badge-click-wrapper');
diff --git a/spec/frontend/google_cloud/components/google_cloud_menu_spec.js b/spec/frontend/google_cloud/components/google_cloud_menu_spec.js
index 4809ea37045..a0c988830ed 100644
--- a/spec/frontend/google_cloud/components/google_cloud_menu_spec.js
+++ b/spec/frontend/google_cloud/components/google_cloud_menu_spec.js
@@ -15,10 +15,6 @@ describe('google_cloud/components/google_cloud_menu', () => {
wrapper = mountExtended(GoogleCloudMenu, { propsData: props });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains active configuration link', () => {
const link = wrapper.findByTestId('configurationLink');
expect(link.text()).toBe(GoogleCloudMenu.i18n.configuration.title);
diff --git a/spec/frontend/google_cloud/components/incubation_banner_spec.js b/spec/frontend/google_cloud/components/incubation_banner_spec.js
index 09a4d92dca2..92bc39bdff9 100644
--- a/spec/frontend/google_cloud/components/incubation_banner_spec.js
+++ b/spec/frontend/google_cloud/components/incubation_banner_spec.js
@@ -15,10 +15,6 @@ describe('google_cloud/components/incubation_banner', () => {
wrapper = mount(IncubationBanner);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains alert', () => {
expect(findAlert().exists()).toBe(true);
});
diff --git a/spec/frontend/google_cloud/components/revoke_oauth_spec.js b/spec/frontend/google_cloud/components/revoke_oauth_spec.js
index faaec07fc35..2b39bb9ca74 100644
--- a/spec/frontend/google_cloud/components/revoke_oauth_spec.js
+++ b/spec/frontend/google_cloud/components/revoke_oauth_spec.js
@@ -20,10 +20,6 @@ describe('google_cloud/components/revoke_oauth', () => {
wrapper = shallowMount(RevokeOauth, { propsData });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains title', () => {
const title = findTitle();
expect(title.text()).toContain('Revoke authorizations');
diff --git a/spec/frontend/google_cloud/configuration/panel_spec.js b/spec/frontend/google_cloud/configuration/panel_spec.js
index 79eb4cb4918..dd85b4c90a7 100644
--- a/spec/frontend/google_cloud/configuration/panel_spec.js
+++ b/spec/frontend/google_cloud/configuration/panel_spec.js
@@ -25,10 +25,6 @@ describe('google_cloud/configuration/panel', () => {
wrapper = shallowMountExtended(Panel, { propsData: props });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains incubation banner', () => {
const target = wrapper.findComponent(IncubationBanner);
expect(target.exists()).toBe(true);
diff --git a/spec/frontend/google_cloud/databases/cloudsql/create_instance_form_spec.js b/spec/frontend/google_cloud/databases/cloudsql/create_instance_form_spec.js
index 48e4b0ca1ad..6e2d3147a54 100644
--- a/spec/frontend/google_cloud/databases/cloudsql/create_instance_form_spec.js
+++ b/spec/frontend/google_cloud/databases/cloudsql/create_instance_form_spec.js
@@ -25,10 +25,6 @@ describe('google_cloud/databases/cloudsql/create_instance_form', () => {
wrapper = shallowMountExtended(InstanceForm, { propsData, stubs: { GlFormCheckbox } });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains header', () => {
expect(findHeader().exists()).toBe(true);
});
diff --git a/spec/frontend/google_cloud/databases/cloudsql/instance_table_spec.js b/spec/frontend/google_cloud/databases/cloudsql/instance_table_spec.js
index a5736d0a524..a2ee75f9fbf 100644
--- a/spec/frontend/google_cloud/databases/cloudsql/instance_table_spec.js
+++ b/spec/frontend/google_cloud/databases/cloudsql/instance_table_spec.js
@@ -8,10 +8,6 @@ describe('google_cloud/databases/cloudsql/instance_table', () => {
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findTable = () => wrapper.findComponent(GlTable);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when there are no instances', () => {
beforeEach(() => {
const propsData = {
diff --git a/spec/frontend/google_cloud/databases/panel_spec.js b/spec/frontend/google_cloud/databases/panel_spec.js
index e6a0d74f348..779258bbdbb 100644
--- a/spec/frontend/google_cloud/databases/panel_spec.js
+++ b/spec/frontend/google_cloud/databases/panel_spec.js
@@ -23,10 +23,6 @@ describe('google_cloud/databases/panel', () => {
wrapper = shallowMountExtended(Panel, { propsData: props });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains incubation banner', () => {
const target = wrapper.findComponent(IncubationBanner);
expect(target.exists()).toBe(true);
diff --git a/spec/frontend/google_cloud/databases/service_table_spec.js b/spec/frontend/google_cloud/databases/service_table_spec.js
index 4a622e544e1..4594e1758ad 100644
--- a/spec/frontend/google_cloud/databases/service_table_spec.js
+++ b/spec/frontend/google_cloud/databases/service_table_spec.js
@@ -19,10 +19,6 @@ describe('google_cloud/databases/service_table', () => {
wrapper = mountExtended(ServiceTable, { propsData });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should contain a table', () => {
expect(findTable().exists()).toBe(true);
});
diff --git a/spec/frontend/google_cloud/deployments/panel_spec.js b/spec/frontend/google_cloud/deployments/panel_spec.js
index 729db1707a7..0748d8f9377 100644
--- a/spec/frontend/google_cloud/deployments/panel_spec.js
+++ b/spec/frontend/google_cloud/deployments/panel_spec.js
@@ -19,10 +19,6 @@ describe('google_cloud/deployments/panel', () => {
wrapper = shallowMountExtended(Panel, { propsData: props });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains incubation banner', () => {
const target = wrapper.findComponent(IncubationBanner);
expect(target.exists()).toBe(true);
diff --git a/spec/frontend/google_cloud/deployments/service_table_spec.js b/spec/frontend/google_cloud/deployments/service_table_spec.js
index 8faad64e313..49220a6007e 100644
--- a/spec/frontend/google_cloud/deployments/service_table_spec.js
+++ b/spec/frontend/google_cloud/deployments/service_table_spec.js
@@ -18,10 +18,6 @@ describe('google_cloud/deployments/service_table', () => {
wrapper = mount(DeploymentsServiceTable, { propsData });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should contain a table', () => {
expect(findTable().exists()).toBe(true);
});
diff --git a/spec/frontend/google_cloud/gcp_regions/form_spec.js b/spec/frontend/google_cloud/gcp_regions/form_spec.js
index 1030e9c8a18..be37ff092f0 100644
--- a/spec/frontend/google_cloud/gcp_regions/form_spec.js
+++ b/spec/frontend/google_cloud/gcp_regions/form_spec.js
@@ -16,10 +16,6 @@ describe('google_cloud/gcp_regions/form', () => {
wrapper = shallowMount(GcpRegionsForm, { propsData });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains header', () => {
expect(findHeader().exists()).toBe(true);
});
diff --git a/spec/frontend/google_cloud/gcp_regions/list_spec.js b/spec/frontend/google_cloud/gcp_regions/list_spec.js
index 6d8c389e5a1..74a54b93183 100644
--- a/spec/frontend/google_cloud/gcp_regions/list_spec.js
+++ b/spec/frontend/google_cloud/gcp_regions/list_spec.js
@@ -18,10 +18,6 @@ describe('google_cloud/gcp_regions/list', () => {
wrapper = mount(GcpRegionsList, { propsData });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows the empty state component', () => {
expect(findEmptyState().exists()).toBe(true);
});
diff --git a/spec/frontend/google_cloud/service_accounts/form_spec.js b/spec/frontend/google_cloud/service_accounts/form_spec.js
index 8be481774fa..c86c8876b15 100644
--- a/spec/frontend/google_cloud/service_accounts/form_spec.js
+++ b/spec/frontend/google_cloud/service_accounts/form_spec.js
@@ -17,10 +17,6 @@ describe('google_cloud/service_accounts/form', () => {
wrapper = shallowMount(ServiceAccountsForm, { propsData, stubs: { GlFormCheckbox } });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains header', () => {
expect(findHeader().exists()).toBe(true);
});
diff --git a/spec/frontend/google_cloud/service_accounts/list_spec.js b/spec/frontend/google_cloud/service_accounts/list_spec.js
index c2bd2005b5d..ae5776081d7 100644
--- a/spec/frontend/google_cloud/service_accounts/list_spec.js
+++ b/spec/frontend/google_cloud/service_accounts/list_spec.js
@@ -18,10 +18,6 @@ describe('google_cloud/service_accounts/list', () => {
wrapper = mount(ServiceAccountsList, { propsData });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows the empty state component', () => {
expect(findEmptyState().exists()).toBe(true);
});
diff --git a/spec/frontend/grafana_integration/components/grafana_integration_spec.js b/spec/frontend/grafana_integration/components/grafana_integration_spec.js
index 021a3aa41ed..9cb27670c98 100644
--- a/spec/frontend/grafana_integration/components/grafana_integration_spec.js
+++ b/spec/frontend/grafana_integration/components/grafana_integration_spec.js
@@ -3,14 +3,14 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { TEST_HOST } from 'helpers/test_constants';
import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import GrafanaIntegration from '~/grafana_integration/components/grafana_integration.vue';
import { createStore } from '~/grafana_integration/store';
import axios from '~/lib/utils/axios_utils';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility');
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('grafana integration component', () => {
let wrapper;
@@ -103,7 +103,7 @@ describe('grafana integration component', () => {
expect(refreshCurrentPage).toHaveBeenCalled();
});
- it('creates flash banner on error', async () => {
+ it('creates alert banner on error', async () => {
const message = 'mockErrorMessage';
axios.patch.mockRejectedValue({ response: { data: { message } } });
diff --git a/spec/frontend/group_settings/components/shared_runners_form_spec.js b/spec/frontend/group_settings/components/shared_runners_form_spec.js
index 85475c749b0..e92493315f7 100644
--- a/spec/frontend/group_settings/components/shared_runners_form_spec.js
+++ b/spec/frontend/group_settings/components/shared_runners_form_spec.js
@@ -45,9 +45,6 @@ describe('group_settings/components/shared_runners_form', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
-
updateGroup.mockReset();
});
diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js
index 4e6ddd89a55..98868de8475 100644
--- a/spec/frontend/groups/components/app_spec.js
+++ b/spec/frontend/groups/components/app_spec.js
@@ -3,7 +3,7 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import appComponent from '~/groups/components/app.vue';
import groupFolderComponent from '~/groups/components/group_folder.vue';
import groupItemComponent from '~/groups/components/group_item.vue';
@@ -34,7 +34,7 @@ import {
const $toast = {
show: jest.fn(),
};
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('AppComponent', () => {
let wrapper;
@@ -65,11 +65,6 @@ describe('AppComponent', () => {
vm = wrapper.vm;
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
beforeEach(async () => {
mock = new AxiosMockAdapter(axios);
mock.onGet('/dashboard/groups.json').reply(HTTP_STATUS_OK, mockGroups);
@@ -117,7 +112,7 @@ describe('AppComponent', () => {
});
});
- it('should show flash error when request fails', () => {
+ it('should show alert error when request fails', () => {
mock.onGet('/dashboard/groups.json').reply(HTTP_STATUS_BAD_REQUEST);
jest.spyOn(window, 'scrollTo').mockImplementation(() => {});
@@ -325,7 +320,7 @@ describe('AppComponent', () => {
});
});
- it('should show error flash message if request failed to leave group', () => {
+ it('should show error alert message if request failed to leave group', () => {
const message = 'An error occurred. Please try again.';
jest
.spyOn(vm.service, 'leaveGroup')
@@ -342,7 +337,7 @@ describe('AppComponent', () => {
});
});
- it('should show appropriate error flash message if request forbids to leave group', () => {
+ it('should show appropriate error alert message if request forbids to leave group', () => {
const message = 'Failed to leave the group. Please make sure you are not the only owner.';
jest.spyOn(vm.service, 'leaveGroup').mockRejectedValue({ status: HTTP_STATUS_FORBIDDEN });
jest.spyOn(vm.store, 'removeGroup');
diff --git a/spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js b/spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js
index 75edc602fbf..dc4271b98ee 100644
--- a/spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js
+++ b/spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js
@@ -24,10 +24,6 @@ const createComponent = ({ provide = {} } = {}) => {
});
};
-afterEach(() => {
- wrapper.destroy();
-});
-
const findNewSubgroupLink = () =>
wrapper.findByRole('link', {
name: new RegExp(SubgroupsAndProjectsEmptyState.i18n.withLinks.subgroup.title),
diff --git a/spec/frontend/groups/components/group_folder_spec.js b/spec/frontend/groups/components/group_folder_spec.js
index f223333360d..da31fb02f69 100644
--- a/spec/frontend/groups/components/group_folder_spec.js
+++ b/spec/frontend/groups/components/group_folder_spec.js
@@ -20,10 +20,6 @@ describe('GroupFolder component', () => {
},
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not render more children stats link when children count of group is under limit', () => {
wrapper = createComponent();
diff --git a/spec/frontend/groups/components/group_item_spec.js b/spec/frontend/groups/components/group_item_spec.js
index 4570aa33a6c..663dd341a58 100644
--- a/spec/frontend/groups/components/group_item_spec.js
+++ b/spec/frontend/groups/components/group_item_spec.js
@@ -37,10 +37,6 @@ describe('GroupItemComponent', () => {
return waitForPromises();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const withMicrodata = (group) => ({
...group,
microdata: getGroupItemMicrodata(group),
diff --git a/spec/frontend/groups/components/group_name_and_path_spec.js b/spec/frontend/groups/components/group_name_and_path_spec.js
index 9965b608f27..0a18e657c94 100644
--- a/spec/frontend/groups/components/group_name_and_path_spec.js
+++ b/spec/frontend/groups/components/group_name_and_path_spec.js
@@ -7,11 +7,11 @@ import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
import GroupNameAndPath from '~/groups/components/group_name_and_path.vue';
import { getGroupPathAvailability } from '~/rest_api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { helpPagePath } from '~/helpers/help_page_helper';
import searchGroupsWhereUserCanCreateSubgroups from '~/groups/queries/search_groups_where_user_can_create_subgroups.query.graphql';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/rest_api', () => ({
getGroupPathAvailability: jest.fn(),
}));
diff --git a/spec/frontend/groups/components/groups_spec.js b/spec/frontend/groups/components/groups_spec.js
index cae29a8f15a..9ee785d688a 100644
--- a/spec/frontend/groups/components/groups_spec.js
+++ b/spec/frontend/groups/components/groups_spec.js
@@ -37,10 +37,6 @@ describe('GroupsComponent', () => {
Vue.component('GroupItem', GroupItemComponent);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('methods', () => {
describe('change', () => {
it('should emit `fetchPage` event when page is changed via pagination', () => {
diff --git a/spec/frontend/groups/components/invite_members_banner_spec.js b/spec/frontend/groups/components/invite_members_banner_spec.js
index 4a385cb00ee..c4bc35dcd57 100644
--- a/spec/frontend/groups/components/invite_members_banner_spec.js
+++ b/spec/frontend/groups/components/invite_members_banner_spec.js
@@ -42,8 +42,6 @@ describe('InviteMembersBanner', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
mockAxios.restore();
unmockTracking();
});
@@ -59,7 +57,6 @@ describe('InviteMembersBanner', () => {
});
const trackCategory = undefined;
- const buttonClickEvent = 'invite_members_banner_button_clicked';
it('sends the displayEvent when the banner is displayed', () => {
const displayEvent = 'invite_members_banner_displayed';
@@ -80,12 +77,6 @@ describe('InviteMembersBanner', () => {
source: 'invite_members_banner',
});
});
-
- it('sends the buttonClickEvent with correct trackCategory and trackLabel', () => {
- expect(trackingSpy).toHaveBeenCalledWith(trackCategory, buttonClickEvent, {
- label: provide.trackLabel,
- });
- });
});
it('sends the dismissEvent when the banner is dismissed', () => {
diff --git a/spec/frontend/groups/components/item_actions_spec.js b/spec/frontend/groups/components/item_actions_spec.js
index 3ceb038dd3c..fac6fb77709 100644
--- a/spec/frontend/groups/components/item_actions_spec.js
+++ b/spec/frontend/groups/components/item_actions_spec.js
@@ -18,11 +18,6 @@ describe('ItemActions', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findEditGroupBtn = () => wrapper.findByTestId(`edit-group-${mockParentGroupItem.id}-btn`);
const findLeaveGroupBtn = () => wrapper.findByTestId(`leave-group-${mockParentGroupItem.id}-btn`);
const findRemoveGroupBtn = () =>
diff --git a/spec/frontend/groups/components/new_top_level_group_alert_spec.js b/spec/frontend/groups/components/new_top_level_group_alert_spec.js
index db9a5c7b16b..060663747e4 100644
--- a/spec/frontend/groups/components/new_top_level_group_alert_spec.js
+++ b/spec/frontend/groups/components/new_top_level_group_alert_spec.js
@@ -30,10 +30,6 @@ describe('NewTopLevelGroupAlert', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the component is created', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js
index d1ae2c4be17..906609c97f9 100644
--- a/spec/frontend/groups/components/overview_tabs_spec.js
+++ b/spec/frontend/groups/components/overview_tabs_spec.js
@@ -76,7 +76,6 @@ describe('OverviewTabs', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
});
diff --git a/spec/frontend/groups/components/transfer_group_form_spec.js b/spec/frontend/groups/components/transfer_group_form_spec.js
index 0065820f78f..fd0c3907e04 100644
--- a/spec/frontend/groups/components/transfer_group_form_spec.js
+++ b/spec/frontend/groups/components/transfer_group_form_spec.js
@@ -48,10 +48,6 @@ describe('Transfer group form', () => {
const findTransferLocations = () => wrapper.findComponent(TransferLocations);
const findHiddenInput = () => wrapper.find('[name="new_parent_group_id"]');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/groups_projects/components/transfer_locations_spec.js b/spec/frontend/groups_projects/components/transfer_locations_spec.js
index 77c0966ba1e..86913bb4c09 100644
--- a/spec/frontend/groups_projects/components/transfer_locations_spec.js
+++ b/spec/frontend/groups_projects/components/transfer_locations_spec.js
@@ -109,10 +109,6 @@ describe('TransferLocations', () => {
const intersectionObserverEmitAppear = () => findIntersectionObserver().vm.$emit('appear');
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when `GlDropdown` is opened', () => {
it('shows loading icon', async () => {
getTransferLocations.mockReturnValueOnce(new Promise(() => {}));
diff --git a/spec/frontend/header_search/components/app_spec.js b/spec/frontend/header_search/components/app_spec.js
index d6263c663d2..8e84c672d90 100644
--- a/spec/frontend/header_search/components/app_spec.js
+++ b/spec/frontend/header_search/components/app_spec.js
@@ -80,10 +80,6 @@ describe('HeaderSearchApp', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findHeaderSearchForm = () => wrapper.findByTestId('header-search-form');
const findHeaderSearchInput = () => wrapper.findComponent(GlSearchBoxByType);
const findScopeToken = () => wrapper.findComponent(GlToken);
@@ -187,10 +183,10 @@ describe('HeaderSearchApp', () => {
describe.each`
username | showDropdown | expectedDesc
- ${null} | ${false} | ${HeaderSearchApp.i18n.searchInputDescribeByNoDropdown}
- ${null} | ${true} | ${HeaderSearchApp.i18n.searchInputDescribeByNoDropdown}
- ${MOCK_USERNAME} | ${false} | ${HeaderSearchApp.i18n.searchInputDescribeByWithDropdown}
- ${MOCK_USERNAME} | ${true} | ${HeaderSearchApp.i18n.searchInputDescribeByWithDropdown}
+ ${null} | ${false} | ${HeaderSearchApp.i18n.SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN}
+ ${null} | ${true} | ${HeaderSearchApp.i18n.SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN}
+ ${MOCK_USERNAME} | ${false} | ${HeaderSearchApp.i18n.SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN}
+ ${MOCK_USERNAME} | ${true} | ${HeaderSearchApp.i18n.SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN}
`('Search Input Description', ({ username, showDropdown, expectedDesc }) => {
describe(`current_username is ${username} and showDropdown is ${showDropdown}`, () => {
beforeEach(() => {
@@ -212,7 +208,7 @@ describe('HeaderSearchApp', () => {
${MOCK_USERNAME} | ${true} | ${''} | ${false} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${`${MOCK_DEFAULT_SEARCH_OPTIONS.length} default results provided. Use the up and down arrow keys to navigate search results list.`}
${MOCK_USERNAME} | ${true} | ${''} | ${true} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${`${MOCK_DEFAULT_SEARCH_OPTIONS.length} default results provided. Use the up and down arrow keys to navigate search results list.`}
${MOCK_USERNAME} | ${true} | ${MOCK_SEARCH} | ${false} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${`Results updated. ${MOCK_SCOPED_SEARCH_OPTIONS.length} results available. Use the up and down arrow keys to navigate search results list, or ENTER to submit.`}
- ${MOCK_USERNAME} | ${true} | ${MOCK_SEARCH} | ${true} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${HeaderSearchApp.i18n.searchResultsLoading}
+ ${MOCK_USERNAME} | ${true} | ${MOCK_SEARCH} | ${true} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${HeaderSearchApp.i18n.SEARCH_RESULTS_LOADING}
`(
'Search Results Description',
({ username, showDropdown, search, loading, searchOptions, expectedDesc }) => {
@@ -354,8 +350,8 @@ describe('HeaderSearchApp', () => {
describe('events', () => {
beforeEach(() => {
- createComponent();
window.gon.current_username = MOCK_USERNAME;
+ createComponent();
});
describe('Header Search Input', () => {
@@ -463,8 +459,8 @@ describe('HeaderSearchApp', () => {
${2} | ${'test1'}
`('currentFocusedOption', ({ MOCK_INDEX, search }) => {
beforeEach(() => {
- createComponent({ search });
window.gon.current_username = MOCK_USERNAME;
+ createComponent({ search });
findHeaderSearchInput().vm.$emit('click');
});
@@ -504,8 +500,8 @@ describe('HeaderSearchApp', () => {
const MOCK_INDEX = 1;
beforeEach(() => {
- createComponent();
window.gon.current_username = MOCK_USERNAME;
+ createComponent();
findHeaderSearchInput().vm.$emit('click');
});
diff --git a/spec/frontend/header_search/components/header_search_autocomplete_items_spec.js b/spec/frontend/header_search/components/header_search_autocomplete_items_spec.js
index 7952661e2d2..e77a9231b7a 100644
--- a/spec/frontend/header_search/components/header_search_autocomplete_items_spec.js
+++ b/spec/frontend/header_search/components/header_search_autocomplete_items_spec.js
@@ -3,15 +3,14 @@ import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import HeaderSearchAutocompleteItems from '~/header_search/components/header_search_autocomplete_items.vue';
+import { LARGE_AVATAR_PX, SMALL_AVATAR_PX } from '~/header_search/constants';
import {
- GROUPS_CATEGORY,
- LARGE_AVATAR_PX,
PROJECTS_CATEGORY,
- SMALL_AVATAR_PX,
+ GROUPS_CATEGORY,
ISSUES_CATEGORY,
MERGE_REQUEST_CATEGORY,
RECENT_EPICS_CATEGORY,
-} from '~/header_search/constants';
+} from '~/vue_shared/global_search/constants';
import {
MOCK_GROUPED_AUTOCOMPLETE_OPTIONS,
MOCK_SORTED_AUTOCOMPLETE_OPTIONS,
@@ -46,10 +45,6 @@ describe('HeaderSearchAutocompleteItems', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findGlDropdownDividers = () => wrapper.findAllComponents(GlDropdownDivider);
const findFirstDropdownItem = () => findDropdownItems().at(0);
diff --git a/spec/frontend/header_search/components/header_search_default_items_spec.js b/spec/frontend/header_search/components/header_search_default_items_spec.js
index abcacc487df..3768862d83e 100644
--- a/spec/frontend/header_search/components/header_search_default_items_spec.js
+++ b/spec/frontend/header_search/components/header_search_default_items_spec.js
@@ -29,10 +29,6 @@ describe('HeaderSearchDefaultItems', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDropdownHeader = () => wrapper.findComponent(GlDropdownSectionHeader);
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findFirstDropdownItem = () => findDropdownItems().at(0);
diff --git a/spec/frontend/header_search/components/header_search_scoped_items_spec.js b/spec/frontend/header_search/components/header_search_scoped_items_spec.js
index 2db9f71d702..51d67198f04 100644
--- a/spec/frontend/header_search/components/header_search_scoped_items_spec.js
+++ b/spec/frontend/header_search/components/header_search_scoped_items_spec.js
@@ -5,7 +5,8 @@ import Vuex from 'vuex';
import { trimText } from 'helpers/text_helper';
import HeaderSearchScopedItems from '~/header_search/components/header_search_scoped_items.vue';
import { truncate } from '~/lib/utils/text_utility';
-import { MSG_IN_ALL_GITLAB, SCOPE_TOKEN_MAX_LENGTH } from '~/header_search/constants';
+import { SCOPE_TOKEN_MAX_LENGTH } from '~/header_search/constants';
+import { MSG_IN_ALL_GITLAB } from '~/vue_shared/global_search/constants';
import {
MOCK_SEARCH,
MOCK_SCOPED_SEARCH_OPTIONS,
@@ -38,10 +39,6 @@ describe('HeaderSearchScopedItems', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findFirstDropdownItem = () => findDropdownItems().at(0);
const findDropdownItemTitles = () => findDropdownItems().wrappers.map((w) => trimText(w.text()));
diff --git a/spec/frontend/header_search/mock_data.js b/spec/frontend/header_search/mock_data.js
index 3a8624ad9dd..2218c81efc3 100644
--- a/spec/frontend/header_search/mock_data.js
+++ b/spec/frontend/header_search/mock_data.js
@@ -1,16 +1,14 @@
+import { ICON_PROJECT, ICON_GROUP, ICON_SUBGROUP } from '~/header_search/constants';
import {
+ PROJECTS_CATEGORY,
+ GROUPS_CATEGORY,
MSG_ISSUES_ASSIGNED_TO_ME,
MSG_ISSUES_IVE_CREATED,
MSG_MR_ASSIGNED_TO_ME,
MSG_MR_IM_REVIEWER,
MSG_MR_IVE_CREATED,
MSG_IN_ALL_GITLAB,
- PROJECTS_CATEGORY,
- ICON_PROJECT,
- GROUPS_CATEGORY,
- ICON_GROUP,
- ICON_SUBGROUP,
-} from '~/header_search/constants';
+} from '~/vue_shared/global_search/constants';
export const MOCK_USERNAME = 'anyone';
diff --git a/spec/frontend/header_search/store/actions_spec.js b/spec/frontend/header_search/store/actions_spec.js
index bd93b0edadf..95a619ebeca 100644
--- a/spec/frontend/header_search/store/actions_spec.js
+++ b/spec/frontend/header_search/store/actions_spec.js
@@ -16,7 +16,7 @@ import {
MOCK_ISSUE_PATH,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Header Search Store Actions', () => {
let state;
diff --git a/spec/frontend/header_search/store/getters_spec.js b/spec/frontend/header_search/store/getters_spec.js
index a1d9481b5cc..7a7a00178f1 100644
--- a/spec/frontend/header_search/store/getters_spec.js
+++ b/spec/frontend/header_search/store/getters_spec.js
@@ -241,6 +241,13 @@ describe('Header Search Store Getters', () => {
MOCK_DEFAULT_SEARCH_OPTIONS,
);
});
+
+ it('returns the correct array if issues path is false', () => {
+ mockGetters.scopedIssuesPath = undefined;
+ expect(getters.defaultSearchOptions(state, mockGetters)).toStrictEqual(
+ MOCK_DEFAULT_SEARCH_OPTIONS.slice(2, MOCK_DEFAULT_SEARCH_OPTIONS.length),
+ );
+ });
});
describe('scopedSearchOptions', () => {
diff --git a/spec/frontend/helpers/startup_css_helper_spec.js b/spec/frontend/helpers/startup_css_helper_spec.js
index 05161437c22..28c742386cc 100644
--- a/spec/frontend/helpers/startup_css_helper_spec.js
+++ b/spec/frontend/helpers/startup_css_helper_spec.js
@@ -21,17 +21,10 @@ describe('waitForCSSLoaded', () => {
});
describe('when gon features is not provided', () => {
- let originalGon;
-
beforeEach(() => {
- originalGon = window.gon;
window.gon = null;
});
- afterEach(() => {
- window.gon = originalGon;
- });
-
it('should invoke the action right away', async () => {
const events = waitForCSSLoaded(mockedCallback);
await events;
diff --git a/spec/frontend/ide/components/activity_bar_spec.js b/spec/frontend/ide/components/activity_bar_spec.js
index a97e883a8bf..ff04f9a84f1 100644
--- a/spec/frontend/ide/components/activity_bar_spec.js
+++ b/spec/frontend/ide/components/activity_bar_spec.js
@@ -22,10 +22,6 @@ describe('IDE ActivityBar component', () => {
wrapper = shallowMount(ActivityBar, { store });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('updateActivityBarView', () => {
beforeEach(() => {
mountComponent();
diff --git a/spec/frontend/ide/components/branches/item_spec.js b/spec/frontend/ide/components/branches/item_spec.js
index 3dbd1210916..4cae146cbd2 100644
--- a/spec/frontend/ide/components/branches/item_spec.js
+++ b/spec/frontend/ide/components/branches/item_spec.js
@@ -34,10 +34,6 @@ describe('IDE branch item', () => {
router = createRouter(store);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('if not active', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ide/components/branches/search_list_spec.js b/spec/frontend/ide/components/branches/search_list_spec.js
index bbde45d700f..eeab26f7559 100644
--- a/spec/frontend/ide/components/branches/search_list_spec.js
+++ b/spec/frontend/ide/components/branches/search_list_spec.js
@@ -35,11 +35,6 @@ describe('IDE branches search list', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('calls fetch on mounted', () => {
createComponent();
expect(fetchBranchesMock).toHaveBeenCalled();
diff --git a/spec/frontend/ide/components/cannot_push_code_alert_spec.js b/spec/frontend/ide/components/cannot_push_code_alert_spec.js
index ff659ecdf3f..d4db2246008 100644
--- a/spec/frontend/ide/components/cannot_push_code_alert_spec.js
+++ b/spec/frontend/ide/components/cannot_push_code_alert_spec.js
@@ -10,10 +10,6 @@ const TEST_BUTTON_TEXT = 'Fork text';
describe('ide/components/cannot_push_code_alert', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
const createComponent = (props = {}) => {
wrapper = shallowMount(CannotPushCodeAlert, {
propsData: {
diff --git a/spec/frontend/ide/components/commit_sidebar/actions_spec.js b/spec/frontend/ide/components/commit_sidebar/actions_spec.js
index dc103fec5d0..019469cbf87 100644
--- a/spec/frontend/ide/components/commit_sidebar/actions_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/actions_spec.js
@@ -46,10 +46,6 @@ describe('IDE commit sidebar actions', () => {
jest.spyOn(store, 'dispatch').mockImplementation(() => {});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findText = () => wrapper.text();
const findRadios = () => wrapper.findAll('input[type="radio"]');
diff --git a/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js b/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js
index f6d5833edee..ce43e648b43 100644
--- a/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/editor_header_spec.js
@@ -1,7 +1,9 @@
-import { mount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import EditorHeader from '~/ide/components/commit_sidebar/editor_header.vue';
+import { stubComponent } from 'helpers/stub_component';
import { createStore } from '~/ide/stores';
import { file } from '../../helpers';
@@ -12,9 +14,10 @@ const TEST_FILE_PATH = 'test/file/path';
describe('IDE commit editor header', () => {
let wrapper;
let store;
+ const showMock = jest.fn();
const createComponent = (fileProps = {}) => {
- wrapper = mount(EditorHeader, {
+ wrapper = shallowMount(EditorHeader, {
store,
propsData: {
activeFile: {
@@ -23,22 +26,17 @@ describe('IDE commit editor header', () => {
...fileProps,
},
},
+ stubs: {
+ GlModal: stubComponent(GlModal, {
+ methods: { show: showMock },
+ }),
+ },
});
};
const findDiscardModal = () => wrapper.findComponent({ ref: 'discardModal' });
const findDiscardButton = () => wrapper.findComponent({ ref: 'discardButton' });
- beforeEach(() => {
- store = createStore();
- jest.spyOn(store, 'dispatch').mockImplementation();
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it.each`
fileProps | shouldExist
${{ staged: false, changed: false }} | ${false}
@@ -52,20 +50,19 @@ describe('IDE commit editor header', () => {
});
describe('discard button', () => {
- beforeEach(() => {
+ it('opens a dialog confirming discard', () => {
createComponent();
+ findDiscardButton().vm.$emit('click');
- const modal = findDiscardModal();
- jest.spyOn(modal.vm, 'show');
-
- findDiscardButton().trigger('click');
- });
-
- it('opens a dialog confirming discard', () => {
- expect(findDiscardModal().vm.show).toHaveBeenCalled();
+ expect(showMock).toHaveBeenCalled();
});
it('calls discardFileChanges if dialog result is confirmed', () => {
+ store = createStore();
+ jest.spyOn(store, 'dispatch').mockImplementation();
+
+ createComponent();
+
expect(store.dispatch).not.toHaveBeenCalled();
findDiscardModal().vm.$emit('primary');
diff --git a/spec/frontend/ide/components/commit_sidebar/empty_state_spec.js b/spec/frontend/ide/components/commit_sidebar/empty_state_spec.js
index 7c48c0e6f95..4a6aafe42ae 100644
--- a/spec/frontend/ide/components/commit_sidebar/empty_state_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/empty_state_spec.js
@@ -11,10 +11,6 @@ describe('IDE commit panel EmptyState component', () => {
wrapper = shallowMount(EmptyState, { store });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders no changes text when last commit message is empty', () => {
expect(wrapper.find('h4').text()).toBe('No changes');
});
diff --git a/spec/frontend/ide/components/commit_sidebar/form_spec.js b/spec/frontend/ide/components/commit_sidebar/form_spec.js
index a8ee81afa0b..0c0998c037a 100644
--- a/spec/frontend/ide/components/commit_sidebar/form_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/form_spec.js
@@ -26,7 +26,7 @@ describe('IDE commit form', () => {
wrapper = shallowMount(CommitForm, {
store,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
stubs: {
GlModal: stubComponent(GlModal),
@@ -73,10 +73,6 @@ describe('IDE commit form', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
// Notes:
// - When there are no changes, there is no commit button so there's nothing to test :)
describe.each`
diff --git a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
index c9571d39acb..c2a33c0d71e 100644
--- a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
@@ -36,10 +36,6 @@ describe('Multi-file editor commit sidebar list item', () => {
findPathEl = wrapper.find('.multi-file-commit-list-path');
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findPathText = () => trimText(findPathEl.text());
it('renders file path', () => {
diff --git a/spec/frontend/ide/components/commit_sidebar/list_spec.js b/spec/frontend/ide/components/commit_sidebar/list_spec.js
index 4406d14d990..6b9ba939a87 100644
--- a/spec/frontend/ide/components/commit_sidebar/list_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/list_spec.js
@@ -19,10 +19,6 @@ describe('Multi-file editor commit sidebar list', () => {
},
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with a list of files', () => {
beforeEach(async () => {
const f = file('file name');
diff --git a/spec/frontend/ide/components/commit_sidebar/message_field_spec.js b/spec/frontend/ide/components/commit_sidebar/message_field_spec.js
index c2ef29c1059..3403a7b8ad9 100644
--- a/spec/frontend/ide/components/commit_sidebar/message_field_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/message_field_spec.js
@@ -15,10 +15,6 @@ describe('IDE commit message field', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findMessage = () => wrapper.find('textarea');
const findHighlights = () => wrapper.findAll('.highlights span');
const findMarks = () => wrapper.findAll('mark');
diff --git a/spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js b/spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js
index 2a455c9d7c1..adc9a0f1421 100644
--- a/spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js
@@ -33,15 +33,11 @@ describe('NewMergeRequestOption component', () => {
},
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the `shouldHideNewMrOption` getter returns false', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ide/components/commit_sidebar/radio_group_spec.js b/spec/frontend/ide/components/commit_sidebar/radio_group_spec.js
index a3fa03a4aa5..cdf14056523 100644
--- a/spec/frontend/ide/components/commit_sidebar/radio_group_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/radio_group_spec.js
@@ -19,15 +19,11 @@ describe('IDE commit sidebar radio group', () => {
propsData: config.props,
slots: config.slots,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('without input', () => {
const props = {
value: '1',
diff --git a/spec/frontend/ide/components/commit_sidebar/success_message_spec.js b/spec/frontend/ide/components/commit_sidebar/success_message_spec.js
index 63d51953915..d1a81dd1639 100644
--- a/spec/frontend/ide/components/commit_sidebar/success_message_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/success_message_spec.js
@@ -12,10 +12,6 @@ describe('IDE commit panel successful commit state', () => {
wrapper = shallowMount(SuccessMessage, { store });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders last commit message when it exists', () => {
expect(wrapper.text()).toContain('testing commit message');
});
diff --git a/spec/frontend/ide/components/error_message_spec.js b/spec/frontend/ide/components/error_message_spec.js
index 204d39de741..5f6579654bc 100644
--- a/spec/frontend/ide/components/error_message_spec.js
+++ b/spec/frontend/ide/components/error_message_spec.js
@@ -32,11 +32,6 @@ describe('IDE error message component', () => {
setErrorMessageMock.mockReset();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findDismissButton = () => wrapper.find('button[aria-label=Dismiss]');
const findActionButton = () => wrapper.find('button.gl-alert-action');
diff --git a/spec/frontend/ide/components/file_row_extra_spec.js b/spec/frontend/ide/components/file_row_extra_spec.js
index 281c549a1b4..f5a6e7222f9 100644
--- a/spec/frontend/ide/components/file_row_extra_spec.js
+++ b/spec/frontend/ide/components/file_row_extra_spec.js
@@ -37,8 +37,6 @@ describe('IDE extra file row component', () => {
};
afterEach(() => {
- wrapper.destroy();
-
stagedFilesCount = 0;
unstagedFilesCount = 0;
changesCount = 0;
diff --git a/spec/frontend/ide/components/file_templates/bar_spec.js b/spec/frontend/ide/components/file_templates/bar_spec.js
index 60f37260393..b8c850fdd13 100644
--- a/spec/frontend/ide/components/file_templates/bar_spec.js
+++ b/spec/frontend/ide/components/file_templates/bar_spec.js
@@ -21,10 +21,6 @@ describe('IDE file templates bar component', () => {
wrapper = mount(Bar, { store });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template type dropdown', () => {
it('renders dropdown component', () => {
expect(wrapper.find('.dropdown').text()).toContain('Choose a type');
diff --git a/spec/frontend/ide/components/file_templates/dropdown_spec.js b/spec/frontend/ide/components/file_templates/dropdown_spec.js
index ee90d87357c..72fdd05eb2c 100644
--- a/spec/frontend/ide/components/file_templates/dropdown_spec.js
+++ b/spec/frontend/ide/components/file_templates/dropdown_spec.js
@@ -49,11 +49,6 @@ describe('IDE file templates dropdown component', () => {
({ element } = wrapper);
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('calls clickItem on click', async () => {
const itemData = { name: 'test.yml ' };
createComponent({ props: { data: [itemData] } });
diff --git a/spec/frontend/ide/components/ide_file_row_spec.js b/spec/frontend/ide/components/ide_file_row_spec.js
index aa66224fa19..331877ff112 100644
--- a/spec/frontend/ide/components/ide_file_row_spec.js
+++ b/spec/frontend/ide/components/ide_file_row_spec.js
@@ -34,11 +34,6 @@ describe('Ide File Row component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findFileRowExtra = () => wrapper.findComponent(FileRowExtra);
const findFileRow = () => wrapper.findComponent(FileRow);
const hasDropdownOpen = () => findFileRowExtra().props('dropdownOpen');
diff --git a/spec/frontend/ide/components/ide_project_header_spec.js b/spec/frontend/ide/components/ide_project_header_spec.js
index d0636352a3f..7613f407e45 100644
--- a/spec/frontend/ide/components/ide_project_header_spec.js
+++ b/spec/frontend/ide/components/ide_project_header_spec.js
@@ -20,10 +20,6 @@ describe('IDE project header', () => {
wrapper = shallowMount(IDEProjectHeader, { propsData: { project: mockProject } });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ide/components/ide_review_spec.js b/spec/frontend/ide/components/ide_review_spec.js
index 0759f957374..e6fd018969f 100644
--- a/spec/frontend/ide/components/ide_review_spec.js
+++ b/spec/frontend/ide/components/ide_review_spec.js
@@ -30,10 +30,6 @@ describe('IDE review mode', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders list of files', () => {
expect(wrapper.text()).toContain('fileName');
});
diff --git a/spec/frontend/ide/components/ide_side_bar_spec.js b/spec/frontend/ide/components/ide_side_bar_spec.js
index 4784d6c516f..c258c5312d8 100644
--- a/spec/frontend/ide/components/ide_side_bar_spec.js
+++ b/spec/frontend/ide/components/ide_side_bar_spec.js
@@ -29,11 +29,6 @@ describe('IdeSidebar', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders a sidebar', () => {
wrapper = createComponent();
diff --git a/spec/frontend/ide/components/ide_sidebar_nav_spec.js b/spec/frontend/ide/components/ide_sidebar_nav_spec.js
index 80e8aba4072..4ee24f63f76 100644
--- a/spec/frontend/ide/components/ide_sidebar_nav_spec.js
+++ b/spec/frontend/ide/components/ide_sidebar_nav_spec.js
@@ -25,10 +25,6 @@ describe('ide/components/ide_sidebar_nav', () => {
let wrapper;
const createComponent = (props = {}) => {
- if (wrapper) {
- throw new Error('wrapper already exists');
- }
-
wrapper = shallowMount(IdeSidebarNav, {
propsData: {
tabs: TEST_TABS,
@@ -37,16 +33,11 @@ describe('ide/components/ide_sidebar_nav', () => {
...props,
},
directives: {
- tooltip: createMockDirective(),
+ tooltip: createMockDirective('tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findButtons = () => wrapper.findAll('li button');
const findButtonsData = () =>
findButtons().wrappers.map((button) => {
diff --git a/spec/frontend/ide/components/ide_spec.js b/spec/frontend/ide/components/ide_spec.js
index a575f428a69..1c8d570cdce 100644
--- a/spec/frontend/ide/components/ide_spec.js
+++ b/spec/frontend/ide/components/ide_spec.js
@@ -52,8 +52,6 @@ describe('WebIDE', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
window.onbeforeunload = null;
});
diff --git a/spec/frontend/ide/components/ide_status_bar_spec.js b/spec/frontend/ide/components/ide_status_bar_spec.js
index e6e0ebaf1e8..0ee16f98e7e 100644
--- a/spec/frontend/ide/components/ide_status_bar_spec.js
+++ b/spec/frontend/ide/components/ide_status_bar_spec.js
@@ -34,10 +34,6 @@ describe('IdeStatusBar component', () => {
wrapper = mount(IdeStatusBar, { store });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
it('triggers a setInterval', () => {
mountComponent();
diff --git a/spec/frontend/ide/components/ide_status_list_spec.js b/spec/frontend/ide/components/ide_status_list_spec.js
index 0b54e8b6afb..344a1fbc4f6 100644
--- a/spec/frontend/ide/components/ide_status_list_spec.js
+++ b/spec/frontend/ide/components/ide_status_list_spec.js
@@ -53,10 +53,7 @@ describe('ide/components/ide_status_list', () => {
});
afterEach(() => {
- wrapper.destroy();
-
store = null;
- wrapper = null;
});
describe('with regular file', () => {
diff --git a/spec/frontend/ide/components/ide_status_mr_spec.js b/spec/frontend/ide/components/ide_status_mr_spec.js
index 0b9111c0e2a..3501ecce061 100644
--- a/spec/frontend/ide/components/ide_status_mr_spec.js
+++ b/spec/frontend/ide/components/ide_status_mr_spec.js
@@ -17,10 +17,6 @@ describe('ide/components/ide_status_mr', () => {
const findIcon = () => wrapper.findComponent(GlIcon);
const findLink = () => wrapper.findComponent(GlLink);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when mounted', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/ide/components/ide_tree_list_spec.js b/spec/frontend/ide/components/ide_tree_list_spec.js
index 0f61aa80e53..427daa57324 100644
--- a/spec/frontend/ide/components/ide_tree_list_spec.js
+++ b/spec/frontend/ide/components/ide_tree_list_spec.js
@@ -25,10 +25,6 @@ describe('IdeTreeList component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('normal branch', () => {
const tree = [file('fileName')];
diff --git a/spec/frontend/ide/components/ide_tree_spec.js b/spec/frontend/ide/components/ide_tree_spec.js
index f00017a2736..9f452910496 100644
--- a/spec/frontend/ide/components/ide_tree_spec.js
+++ b/spec/frontend/ide/components/ide_tree_spec.js
@@ -29,10 +29,6 @@ describe('IdeTree', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders list of files', () => {
expect(wrapper.text()).toContain('fileName');
});
diff --git a/spec/frontend/ide/components/jobs/detail/description_spec.js b/spec/frontend/ide/components/jobs/detail/description_spec.js
index 629c4424314..2bb0f3fccf4 100644
--- a/spec/frontend/ide/components/jobs/detail/description_spec.js
+++ b/spec/frontend/ide/components/jobs/detail/description_spec.js
@@ -14,10 +14,6 @@ describe('IDE job description', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders job details', () => {
expect(wrapper.text()).toContain('#1');
expect(wrapper.text()).toContain('test');
diff --git a/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js b/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js
index 5eb66f75978..eec1bd6b123 100644
--- a/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js
+++ b/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js
@@ -15,10 +15,6 @@ describe('IDE job log scroll button', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
direction | icon | title
${'up'} | ${'scroll_up'} | ${'Scroll to top'}
diff --git a/spec/frontend/ide/components/jobs/detail_spec.js b/spec/frontend/ide/components/jobs/detail_spec.js
index bf2be3aa595..60e03a7b882 100644
--- a/spec/frontend/ide/components/jobs/detail_spec.js
+++ b/spec/frontend/ide/components/jobs/detail_spec.js
@@ -34,10 +34,6 @@ describe('IDE jobs detail view', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('mounted', () => {
const findJobOutput = () => wrapper.find('.bash');
const findBuildLoaderAnimation = () => wrapper.find('.build-loader-animation');
diff --git a/spec/frontend/ide/components/jobs/item_spec.js b/spec/frontend/ide/components/jobs/item_spec.js
index 32e27333e42..ab442a27817 100644
--- a/spec/frontend/ide/components/jobs/item_spec.js
+++ b/spec/frontend/ide/components/jobs/item_spec.js
@@ -12,10 +12,6 @@ describe('IDE jobs item', () => {
wrapper = mount(JobItem, { propsData: { job } });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders job details', () => {
expect(wrapper.text()).toContain(job.name);
expect(wrapper.text()).toContain(`#${job.id}`);
diff --git a/spec/frontend/ide/components/jobs/stage_spec.js b/spec/frontend/ide/components/jobs/stage_spec.js
index 52fbff2f497..23ef92f9682 100644
--- a/spec/frontend/ide/components/jobs/stage_spec.js
+++ b/spec/frontend/ide/components/jobs/stage_spec.js
@@ -31,11 +31,6 @@ describe('IDE pipeline stage', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('emits fetch event when mounted', () => {
createComponent();
expect(wrapper.emitted().fetch).toBeDefined();
diff --git a/spec/frontend/ide/components/merge_requests/item_spec.js b/spec/frontend/ide/components/merge_requests/item_spec.js
index d6cf8127b53..2fbb6919b8b 100644
--- a/spec/frontend/ide/components/merge_requests/item_spec.js
+++ b/spec/frontend/ide/components/merge_requests/item_spec.js
@@ -39,11 +39,6 @@ describe('IDE merge request item', () => {
router = createRouter(store);
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ide/components/merge_requests/list_spec.js b/spec/frontend/ide/components/merge_requests/list_spec.js
index ea6e2741a85..3b0e8c632fb 100644
--- a/spec/frontend/ide/components/merge_requests/list_spec.js
+++ b/spec/frontend/ide/components/merge_requests/list_spec.js
@@ -48,11 +48,6 @@ describe('IDE merge requests list', () => {
fetchMergeRequestsMock = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('calls fetch on mounted', () => {
createComponent();
expect(fetchMergeRequestsMock).toHaveBeenCalledWith(expect.any(Object), {
diff --git a/spec/frontend/ide/components/nav_dropdown_button_spec.js b/spec/frontend/ide/components/nav_dropdown_button_spec.js
index 8eebcdd9e08..3aae2c83e80 100644
--- a/spec/frontend/ide/components/nav_dropdown_button_spec.js
+++ b/spec/frontend/ide/components/nav_dropdown_button_spec.js
@@ -9,10 +9,6 @@ describe('NavDropdownButton component', () => {
const TEST_MR_ID = '12345';
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
const createComponent = ({ props = {}, state = {} } = {}) => {
const store = createStore();
store.replaceState(state);
diff --git a/spec/frontend/ide/components/nav_dropdown_spec.js b/spec/frontend/ide/components/nav_dropdown_spec.js
index 33e638843f5..794aaba6d01 100644
--- a/spec/frontend/ide/components/nav_dropdown_spec.js
+++ b/spec/frontend/ide/components/nav_dropdown_spec.js
@@ -30,10 +30,6 @@ describe('IDE NavDropdown', () => {
jest.spyOn(store, 'dispatch').mockImplementation(() => {});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const createComponent = () => {
wrapper = mount(NavDropdown, {
store,
diff --git a/spec/frontend/ide/components/new_dropdown/button_spec.js b/spec/frontend/ide/components/new_dropdown/button_spec.js
index a9cfdfd20c1..bfd5cdf7263 100644
--- a/spec/frontend/ide/components/new_dropdown/button_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/button_spec.js
@@ -14,10 +14,6 @@ describe('IDE new entry dropdown button component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders button with label', () => {
createComponent();
diff --git a/spec/frontend/ide/components/new_dropdown/index_spec.js b/spec/frontend/ide/components/new_dropdown/index_spec.js
index 747c099db33..01dcb174c41 100644
--- a/spec/frontend/ide/components/new_dropdown/index_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/index_spec.js
@@ -30,10 +30,6 @@ describe('new dropdown component', () => {
jest.spyOn(wrapper.vm.$refs.newModal, 'open').mockImplementation(() => {});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders new file, upload and new directory links', () => {
expect(findAllButtons().at(0).text()).toBe('New file');
expect(findAllButtons().at(1).text()).toBe('Upload file');
diff --git a/spec/frontend/ide/components/new_dropdown/modal_spec.js b/spec/frontend/ide/components/new_dropdown/modal_spec.js
index c6f9fd0c4ea..36c3d323e63 100644
--- a/spec/frontend/ide/components/new_dropdown/modal_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/modal_spec.js
@@ -1,13 +1,13 @@
import { GlButton, GlModal } from '@gitlab/ui';
import { nextTick } from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Modal from '~/ide/components/new_dropdown/modal.vue';
import { createStore } from '~/ide/stores';
import { stubComponent } from 'helpers/stub_component';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createEntriesFromPaths } from '../../helpers';
-jest.mock('~/flash');
+jest.mock('~/alert');
const NEW_NAME = 'babar';
@@ -79,7 +79,6 @@ describe('new file modal component', () => {
afterEach(() => {
store = null;
- wrapper.destroy();
document.body.innerHTML = '';
});
@@ -94,11 +93,11 @@ describe('new file modal component', () => {
it('renders modal', () => {
expect(findGlModal().props()).toMatchObject({
actionCancel: {
- attributes: [{ variant: 'default' }],
+ attributes: { variant: 'default' },
text: 'Cancel',
},
actionPrimary: {
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
text: 'Create file',
},
actionSecondary: null,
@@ -170,7 +169,7 @@ describe('new file modal component', () => {
expect(findGlModal().props()).toMatchObject({
title: modalTitle,
actionPrimary: {
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
text: btnTitle,
},
});
@@ -298,7 +297,7 @@ describe('new file modal component', () => {
expect(findGlModal().props()).toMatchObject({
title,
actionPrimary: {
- attributes: [{ variant: 'confirm' }],
+ attributes: { variant: 'confirm' },
text: title,
},
});
@@ -340,7 +339,7 @@ describe('new file modal component', () => {
});
});
- it('does not trigger flash', () => {
+ it('does not trigger alert', () => {
expect(createAlert).not.toHaveBeenCalled();
});
});
@@ -359,7 +358,7 @@ describe('new file modal component', () => {
});
});
- it('does not trigger flash', () => {
+ it('does not trigger alert', () => {
expect(createAlert).not.toHaveBeenCalled();
});
});
@@ -379,7 +378,7 @@ describe('new file modal component', () => {
triggerSubmitModal();
});
- it('creates flash', () => {
+ it('creates alert', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'The name "src" is already taken in this directory.',
fadeTransition: false,
@@ -404,7 +403,7 @@ describe('new file modal component', () => {
triggerSubmitModal();
});
- it('does not create flash', () => {
+ it('does not create alert', () => {
expect(createAlert).not.toHaveBeenCalled();
});
diff --git a/spec/frontend/ide/components/new_dropdown/upload_spec.js b/spec/frontend/ide/components/new_dropdown/upload_spec.js
index fc643589d51..40780c7f0bd 100644
--- a/spec/frontend/ide/components/new_dropdown/upload_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/upload_spec.js
@@ -12,10 +12,6 @@ describe('new dropdown upload', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('openFile', () => {
it('calls for each file', () => {
const files = ['test', 'test2', 'test3'];
diff --git a/spec/frontend/ide/components/panes/collapsible_sidebar_spec.js b/spec/frontend/ide/components/panes/collapsible_sidebar_spec.js
index e92f843ae6e..42eb5b3fc7a 100644
--- a/spec/frontend/ide/components/panes/collapsible_sidebar_spec.js
+++ b/spec/frontend/ide/components/panes/collapsible_sidebar_spec.js
@@ -35,11 +35,6 @@ describe('ide/components/panes/collapsible_sidebar.vue', () => {
jest.spyOn(store, 'dispatch').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('with a tab', () => {
let fakeView;
let extensionTabs;
diff --git a/spec/frontend/ide/components/panes/right_spec.js b/spec/frontend/ide/components/panes/right_spec.js
index 1d81c3ea89d..832983edf21 100644
--- a/spec/frontend/ide/components/panes/right_spec.js
+++ b/spec/frontend/ide/components/panes/right_spec.js
@@ -28,11 +28,6 @@ describe('ide/components/panes/right.vue', () => {
store = createStore();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ide/components/pipelines/empty_state_spec.js b/spec/frontend/ide/components/pipelines/empty_state_spec.js
index 31081e8f9d5..71de9aecb52 100644
--- a/spec/frontend/ide/components/pipelines/empty_state_spec.js
+++ b/spec/frontend/ide/components/pipelines/empty_state_spec.js
@@ -22,10 +22,6 @@ describe('~/ide/components/pipelines/empty_state.vue', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/ide/components/pipelines/list_spec.js b/spec/frontend/ide/components/pipelines/list_spec.js
index d82b97561f0..e913fa84d56 100644
--- a/spec/frontend/ide/components/pipelines/list_spec.js
+++ b/spec/frontend/ide/components/pipelines/list_spec.js
@@ -65,11 +65,6 @@ describe('IDE pipelines list', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('fetches latest pipeline', () => {
createComponent();
diff --git a/spec/frontend/ide/components/repo_commit_section_spec.js b/spec/frontend/ide/components/repo_commit_section_spec.js
index d3312358402..92bb645b1c0 100644
--- a/spec/frontend/ide/components/repo_commit_section_spec.js
+++ b/spec/frontend/ide/components/repo_commit_section_spec.js
@@ -63,11 +63,6 @@ describe('RepoCommitSection', () => {
jest.spyOn(router, 'push').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('empty state', () => {
beforeEach(() => {
store.state.noChangesStateSvgPath = TEST_NO_CHANGES_SVG;
diff --git a/spec/frontend/ide/components/repo_editor_spec.js b/spec/frontend/ide/components/repo_editor_spec.js
index c9f033bffbb..9253bfc7e71 100644
--- a/spec/frontend/ide/components/repo_editor_spec.js
+++ b/spec/frontend/ide/components/repo_editor_spec.js
@@ -162,8 +162,6 @@ describe('RepoEditor', () => {
// create a new model each time, otherwise tests conflict with each other
// because of same model being used in multiple tests
monacoEditor.getModels().forEach((model) => model.dispose());
- wrapper.destroy();
- wrapper = null;
});
describe('default', () => {
diff --git a/spec/frontend/ide/components/repo_tab_spec.js b/spec/frontend/ide/components/repo_tab_spec.js
index b26edc5a85b..b329baea783 100644
--- a/spec/frontend/ide/components/repo_tab_spec.js
+++ b/spec/frontend/ide/components/repo_tab_spec.js
@@ -37,11 +37,6 @@ describe('RepoTab', () => {
jest.spyOn(router, 'push').mockImplementation(() => {});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders a close link and a name link', () => {
createComponent({
tab: file(),
diff --git a/spec/frontend/ide/components/repo_tabs_spec.js b/spec/frontend/ide/components/repo_tabs_spec.js
index 1cfc1f12745..06ad162d398 100644
--- a/spec/frontend/ide/components/repo_tabs_spec.js
+++ b/spec/frontend/ide/components/repo_tabs_spec.js
@@ -25,10 +25,6 @@ describe('RepoTabs', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a list of tabs', async () => {
store.state.openFiles[0].active = true;
diff --git a/spec/frontend/ide/components/resizable_panel_spec.js b/spec/frontend/ide/components/resizable_panel_spec.js
index fe2a128c9c8..240e675a38e 100644
--- a/spec/frontend/ide/components/resizable_panel_spec.js
+++ b/spec/frontend/ide/components/resizable_panel_spec.js
@@ -19,11 +19,6 @@ describe('~/ide/components/resizable_panel', () => {
jest.spyOn(store, 'dispatch').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const createComponent = (props = {}) => {
wrapper = shallowMount(ResizablePanel, {
propsData: {
diff --git a/spec/frontend/ide/components/shared/commit_message_field_spec.js b/spec/frontend/ide/components/shared/commit_message_field_spec.js
index 94da06f4cb2..186b1997497 100644
--- a/spec/frontend/ide/components/shared/commit_message_field_spec.js
+++ b/spec/frontend/ide/components/shared/commit_message_field_spec.js
@@ -23,10 +23,6 @@ describe('CommitMessageField', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findTextArea = () => wrapper.find('textarea');
const findHighlights = () => wrapper.findByTestId('highlights');
const findHighlightsText = () => wrapper.findByTestId('highlights-text');
diff --git a/spec/frontend/ide/components/shared/tokened_input_spec.js b/spec/frontend/ide/components/shared/tokened_input_spec.js
index b70c9659e46..4bd5a6527e2 100644
--- a/spec/frontend/ide/components/shared/tokened_input_spec.js
+++ b/spec/frontend/ide/components/shared/tokened_input_spec.js
@@ -28,10 +28,6 @@ describe('IDE shared/TokenedInput', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders tokens', () => {
createComponent();
const renderedTokens = getTokenElements(wrapper).wrappers.map((w) => w.text());
diff --git a/spec/frontend/ide/components/terminal/empty_state_spec.js b/spec/frontend/ide/components/terminal/empty_state_spec.js
index 15fb0fe9013..3a691c151d5 100644
--- a/spec/frontend/ide/components/terminal/empty_state_spec.js
+++ b/spec/frontend/ide/components/terminal/empty_state_spec.js
@@ -16,10 +16,6 @@ describe('IDE TerminalEmptyState', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not show illustration, if no path specified', () => {
factory();
diff --git a/spec/frontend/ide/components/terminal/terminal_spec.js b/spec/frontend/ide/components/terminal/terminal_spec.js
index 0d22f7f73fe..0500c116d23 100644
--- a/spec/frontend/ide/components/terminal/terminal_spec.js
+++ b/spec/frontend/ide/components/terminal/terminal_spec.js
@@ -59,10 +59,6 @@ describe('IDE Terminal', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('loading text', () => {
[STARTING, PENDING].forEach((status) => {
it(`shows when starting (${status})`, () => {
diff --git a/spec/frontend/ide/components/terminal/view_spec.js b/spec/frontend/ide/components/terminal/view_spec.js
index 57c8da9f5b7..b8ffaa89047 100644
--- a/spec/frontend/ide/components/terminal/view_spec.js
+++ b/spec/frontend/ide/components/terminal/view_spec.js
@@ -59,10 +59,6 @@ describe('IDE TerminalView', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders empty state', async () => {
await factory();
diff --git a/spec/frontend/ide/components/terminal_sync/terminal_sync_status_safe_spec.js b/spec/frontend/ide/components/terminal_sync/terminal_sync_status_safe_spec.js
index 5b1502cc190..e420e28c7b6 100644
--- a/spec/frontend/ide/components/terminal_sync/terminal_sync_status_safe_spec.js
+++ b/spec/frontend/ide/components/terminal_sync/terminal_sync_status_safe_spec.js
@@ -22,10 +22,6 @@ describe('ide/components/terminal_sync/terminal_sync_status_safe', () => {
beforeEach(createComponent);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with terminal sync module in store', () => {
beforeEach(() => {
store.registerModule('terminalSync', {
diff --git a/spec/frontend/ide/components/terminal_sync/terminal_sync_status_spec.js b/spec/frontend/ide/components/terminal_sync/terminal_sync_status_spec.js
index 147235abc8e..4541c3b5ec8 100644
--- a/spec/frontend/ide/components/terminal_sync/terminal_sync_status_spec.js
+++ b/spec/frontend/ide/components/terminal_sync/terminal_sync_status_spec.js
@@ -48,10 +48,6 @@ describe('ide/components/terminal_sync/terminal_sync_status', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when doing nothing', () => {
it('shows nothing', () => {
createComponent();
diff --git a/spec/frontend/ide/services/index_spec.js b/spec/frontend/ide/services/index_spec.js
index 623dee387e5..cd099e60070 100644
--- a/spec/frontend/ide/services/index_spec.js
+++ b/spec/frontend/ide/services/index_spec.js
@@ -252,12 +252,10 @@ describe('IDE services', () => {
describe('pingUsage', () => {
let mock;
- let relativeUrlRoot;
const TEST_RELATIVE_URL_ROOT = 'blah-blah';
beforeEach(() => {
jest.spyOn(axios, 'post');
- relativeUrlRoot = gon.relative_url_root;
gon.relative_url_root = TEST_RELATIVE_URL_ROOT;
mock = new MockAdapter(axios);
@@ -265,7 +263,6 @@ describe('IDE services', () => {
afterEach(() => {
mock.restore();
- gon.relative_url_root = relativeUrlRoot;
});
it('posts to usage endpoint', () => {
diff --git a/spec/frontend/ide/services/terminals_spec.js b/spec/frontend/ide/services/terminals_spec.js
index 5f752197e13..5b6b60a250c 100644
--- a/spec/frontend/ide/services/terminals_spec.js
+++ b/spec/frontend/ide/services/terminals_spec.js
@@ -9,7 +9,6 @@ const TEST_BRANCH = 'ref';
describe('~/ide/services/terminals', () => {
let axiosSpy;
let mock;
- const prevRelativeUrlRoot = gon.relative_url_root;
beforeEach(() => {
axiosSpy = jest.fn().mockReturnValue([HTTP_STATUS_OK, {}]);
@@ -19,7 +18,6 @@ describe('~/ide/services/terminals', () => {
});
afterEach(() => {
- gon.relative_url_root = prevRelativeUrlRoot;
mock.restore();
});
diff --git a/spec/frontend/ide/stores/actions/file_spec.js b/spec/frontend/ide/stores/actions/file_spec.js
index 90ca8526698..7f4e1cf761d 100644
--- a/spec/frontend/ide/stores/actions/file_spec.js
+++ b/spec/frontend/ide/stores/actions/file_spec.js
@@ -16,7 +16,6 @@ const RELATIVE_URL_ROOT = '/gitlab';
describe('IDE store file actions', () => {
let mock;
- let originalGon;
let store;
let router;
@@ -24,9 +23,7 @@ describe('IDE store file actions', () => {
stubPerformanceWebAPI();
mock = new MockAdapter(axios);
- originalGon = window.gon;
window.gon = {
- ...window.gon,
relative_url_root: RELATIVE_URL_ROOT,
};
@@ -44,7 +41,6 @@ describe('IDE store file actions', () => {
afterEach(() => {
mock.restore();
- window.gon = originalGon;
});
describe('closeFile', () => {
diff --git a/spec/frontend/ide/stores/actions/merge_request_spec.js b/spec/frontend/ide/stores/actions/merge_request_spec.js
index fbae84631ee..a41ffdb0a31 100644
--- a/spec/frontend/ide/stores/actions/merge_request_spec.js
+++ b/spec/frontend/ide/stores/actions/merge_request_spec.js
@@ -3,7 +3,7 @@ import { range } from 'lodash';
import { stubPerformanceWebAPI } from 'helpers/performance';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { leftSidebarViews, PERMISSION_READ_MR, MAX_MR_FILES_AUTO_OPEN } from '~/ide/constants';
import service from '~/ide/services';
import { createStore } from '~/ide/stores';
@@ -30,7 +30,7 @@ const createMergeRequestChangesCount = (n) =>
const testGetUrlForPath = (path) => `${TEST_HOST}/test/${path}`;
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('IDE store merge request actions', () => {
let store;
@@ -135,7 +135,7 @@ describe('IDE store merge request actions', () => {
mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests/).networkError();
});
- it('flashes message, if error', () => {
+ it('shows an alert, if error', () => {
return store
.dispatch('getMergeRequestsForBranch', {
projectId: TEST_PROJECT,
@@ -519,7 +519,7 @@ describe('IDE store merge request actions', () => {
);
});
- it('flashes message, if error', () => {
+ it('shows an alert, if error', () => {
store.dispatch.mockRejectedValue();
return openMergeRequest(store, mr).catch(() => {
diff --git a/spec/frontend/ide/stores/actions/project_spec.js b/spec/frontend/ide/stores/actions/project_spec.js
index 5a5ead4c544..b13228c20f5 100644
--- a/spec/frontend/ide/stores/actions/project_spec.js
+++ b/spec/frontend/ide/stores/actions/project_spec.js
@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import testAction from 'helpers/vuex_action_helper';
import api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import service from '~/ide/services';
import { createStore } from '~/ide/stores';
import {
@@ -19,7 +19,7 @@ import {
import { logError } from '~/lib/logger';
import axios from '~/lib/utils/axios_utils';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/logger');
const TEST_PROJECT_ID = 'abc/def';
@@ -104,7 +104,7 @@ describe('IDE store project actions', () => {
desc | projectPath | responseSuccess | expectedMutations
${'does not fetch permissions if project does not exist'} | ${undefined} | ${true} | ${[]}
${'fetches permission when project is specified'} | ${TEST_PROJECT_ID} | ${true} | ${[...permissionsMutations]}
- ${'flashes an error if the request fails'} | ${TEST_PROJECT_ID} | ${false} | ${[]}
+ ${'alerts an error if the request fails'} | ${TEST_PROJECT_ID} | ${false} | ${[]}
`('$desc', async ({ projectPath, expectedMutations, responseSuccess } = {}) => {
store.state.currentProjectId = projectPath;
if (responseSuccess) {
diff --git a/spec/frontend/ide/stores/actions_spec.js b/spec/frontend/ide/stores/actions_spec.js
index 1c90c0f943a..63b63af667c 100644
--- a/spec/frontend/ide/stores/actions_spec.js
+++ b/spec/frontend/ide/stores/actions_spec.js
@@ -4,7 +4,7 @@ import testAction from 'helpers/vuex_action_helper';
import eventHub from '~/ide/eventhub';
import { createRouter } from '~/ide/ide_router';
import { createStore } from '~/ide/stores';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import {
init,
stageAllChanges,
@@ -31,7 +31,7 @@ jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn(),
joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
}));
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Multi-file store actions', () => {
let store;
@@ -210,7 +210,7 @@ describe('Multi-file store actions', () => {
expect(store.dispatch).toHaveBeenCalledWith('setFileActive', 'test');
});
- it('creates flash message if file already exists', async () => {
+ it('creates alert message if file already exists', async () => {
const f = file('test', '1', 'blob');
store.state.trees['abcproject/mybranch'].tree = [f];
store.state.entries[f.path] = f;
@@ -927,7 +927,7 @@ describe('Multi-file store actions', () => {
expect(document.querySelector('.flash-alert')).toBeNull();
});
- it('does not pass the error further and flashes an alert if error is not 404', async () => {
+ it('does not pass the error further and creates an alert if error is not 404', async () => {
mock.onGet(/(.*)/).replyOnce(HTTP_STATUS_IM_A_TEAPOT);
await expect(getBranchData(...callParams)).rejects.toEqual(
diff --git a/spec/frontend/ide/stores/extend_spec.js b/spec/frontend/ide/stores/extend_spec.js
index ffb00f9ef5b..88909999c82 100644
--- a/spec/frontend/ide/stores/extend_spec.js
+++ b/spec/frontend/ide/stores/extend_spec.js
@@ -6,12 +6,10 @@ jest.mock('~/ide/stores/plugins/terminal', () => jest.fn());
jest.mock('~/ide/stores/plugins/terminal_sync', () => jest.fn());
describe('ide/stores/extend', () => {
- let prevGon;
let store;
let el;
beforeEach(() => {
- prevGon = global.gon;
store = {};
el = {};
@@ -23,13 +21,12 @@ describe('ide/stores/extend', () => {
});
afterEach(() => {
- global.gon = prevGon;
terminalPlugin.mockClear();
terminalSyncPlugin.mockClear();
});
const withGonFeatures = (features) => {
- global.gon = { ...global.gon, features };
+ global.gon.features = features;
};
describe('terminalPlugin', () => {
diff --git a/spec/frontend/ide/stores/getters_spec.js b/spec/frontend/ide/stores/getters_spec.js
index d4166a3bd6d..0fe6a16c676 100644
--- a/spec/frontend/ide/stores/getters_spec.js
+++ b/spec/frontend/ide/stores/getters_spec.js
@@ -24,11 +24,8 @@ const TEST_FORK_PATH = '/test/fork/path';
describe('IDE store getters', () => {
let localState;
let localStore;
- let origGon;
beforeEach(() => {
- origGon = window.gon;
-
// Feature flag is defaulted to on in prod
window.gon = { features: { rejectUnsignedCommitsByGitlab: true } };
@@ -36,10 +33,6 @@ describe('IDE store getters', () => {
localState = localStore.state;
});
- afterEach(() => {
- window.gon = origGon;
- });
-
describe('activeFile', () => {
it('returns the current active file', () => {
localState.openFiles.push(file());
diff --git a/spec/frontend/ide/stores/modules/commit/actions_spec.js b/spec/frontend/ide/stores/modules/commit/actions_spec.js
index 4068a9d0919..872aa9b6e6b 100644
--- a/spec/frontend/ide/stores/modules/commit/actions_spec.js
+++ b/spec/frontend/ide/stores/modules/commit/actions_spec.js
@@ -1,6 +1,7 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { file } from 'jest/ide/helpers';
import { commitActionTypes, PERMISSION_CREATE_MR } from '~/ide/constants';
import eventHub from '~/ide/eventhub';
@@ -39,12 +40,14 @@ describe('IDE commit module actions', () => {
let mock;
let store;
let router;
+ let trackingSpy;
beforeEach(() => {
store = createStore();
router = createRouter(store);
gon.api_version = 'v1';
mock = new MockAdapter(axios);
+ trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
jest.spyOn(router, 'push').mockImplementation();
mock
@@ -53,7 +56,7 @@ describe('IDE commit module actions', () => {
});
afterEach(() => {
- delete gon.api_version;
+ unmockTracking();
mock.restore();
});
@@ -81,19 +84,12 @@ describe('IDE commit module actions', () => {
});
describe('updateBranchName', () => {
- let originalGon;
-
beforeEach(() => {
- originalGon = window.gon;
- window.gon = { current_username: 'johndoe' };
+ window.gon.current_username = 'johndoe';
store.state.currentBranchId = 'main';
});
- afterEach(() => {
- window.gon = originalGon;
- });
-
it('updates store with new branch name', async () => {
await store.dispatch('commit/updateBranchName', 'branch-name');
@@ -430,6 +426,28 @@ describe('IDE commit module actions', () => {
});
});
});
+
+ describe('learnGitlabSource', () => {
+ describe('learnGitlabSource is true', () => {
+ it('tracks commit', async () => {
+ store.state.learnGitlabSource = true;
+
+ await store.dispatch('commit/commitChanges');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'commit', {
+ label: 'web_ide_learn_gitlab_source',
+ });
+ });
+ });
+
+ describe('learnGitlabSource is false', () => {
+ it('does not track commit', async () => {
+ await store.dispatch('commit/commitChanges');
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+ });
});
describe('success response with failed message', () => {
@@ -447,6 +465,26 @@ describe('IDE commit module actions', () => {
expect(alert.textContent.trim()).toBe('failed message');
});
+
+ describe('learnGitlabSource', () => {
+ describe('learnGitlabSource is true', () => {
+ it('does not track commit', async () => {
+ store.state.learnGitlabSource = true;
+
+ await store.dispatch('commit/commitChanges');
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('learnGitlabSource is false', () => {
+ it('does not track commit', async () => {
+ await store.dispatch('commit/commitChanges');
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+ });
});
describe('failed response', () => {
@@ -466,6 +504,26 @@ describe('IDE commit module actions', () => {
['commit/SET_ERROR', createUnexpectedCommitError(), undefined],
]);
});
+
+ describe('learnGitlabSource', () => {
+ describe('learnGitlabSource is true', () => {
+ it('does not track commit', async () => {
+ store.state.learnGitlabSource = true;
+
+ await store.dispatch('commit/commitChanges').catch(() => {});
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('learnGitlabSource is false', () => {
+ it('does not track commit', async () => {
+ await store.dispatch('commit/commitChanges').catch(() => {});
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+ });
});
describe('first commit of a branch', () => {
diff --git a/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js b/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js
index 0287e5269ee..3f7ded5e718 100644
--- a/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js
+++ b/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as actions from '~/ide/stores/modules/terminal/actions/session_controls';
import { STARTING, PENDING, STOPPING, STOPPED } from '~/ide/stores/modules/terminal/constants';
import * as messages from '~/ide/stores/modules/terminal/messages';
@@ -13,7 +13,7 @@ import {
HTTP_STATUS_UNPROCESSABLE_ENTITY,
} from '~/lib/utils/http_status';
-jest.mock('~/flash');
+jest.mock('~/alert');
const TEST_PROJECT_PATH = 'lorem/root';
const TEST_BRANCH_ID = 'main';
@@ -91,7 +91,7 @@ describe('IDE store terminal session controls actions', () => {
});
describe('receiveStartSessionError', () => {
- it('flashes message', () => {
+ it('shows an alert', () => {
actions.receiveStartSessionError({ dispatch });
expect(createAlert).toHaveBeenCalledWith({
@@ -165,7 +165,7 @@ describe('IDE store terminal session controls actions', () => {
});
describe('receiveStopSessionError', () => {
- it('flashes message', () => {
+ it('shows an alert', () => {
actions.receiveStopSessionError({ dispatch });
expect(createAlert).toHaveBeenCalledWith({
diff --git a/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js b/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js
index 9616733f052..30ae7d203a9 100644
--- a/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js
+++ b/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as actions from '~/ide/stores/modules/terminal/actions/session_status';
import { PENDING, RUNNING, STOPPING, STOPPED } from '~/ide/stores/modules/terminal/constants';
import * as messages from '~/ide/stores/modules/terminal/messages';
@@ -8,7 +8,7 @@ import * as mutationTypes from '~/ide/stores/modules/terminal/mutation_types';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-jest.mock('~/flash');
+jest.mock('~/alert');
const TEST_SESSION = {
id: 7,
@@ -113,7 +113,7 @@ describe('IDE store terminal session controls actions', () => {
});
describe('receiveSessionStatusError', () => {
- it('flashes message', () => {
+ it('shows an alert', () => {
actions.receiveSessionStatusError({ dispatch });
expect(createAlert).toHaveBeenCalledWith({
diff --git a/spec/frontend/import_entities/components/group_dropdown_spec.js b/spec/frontend/import_entities/components/group_dropdown_spec.js
index 31e097cfa7b..b44bc33de6f 100644
--- a/spec/frontend/import_entities/components/group_dropdown_spec.js
+++ b/spec/frontend/import_entities/components/group_dropdown_spec.js
@@ -64,10 +64,6 @@ describe('Import entities group dropdown component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('passes namespaces from graphql query to default slot', async () => {
createComponent();
jest.advanceTimersByTime(DEBOUNCE_DELAY);
diff --git a/spec/frontend/import_entities/components/import_status_spec.js b/spec/frontend/import_entities/components/import_status_spec.js
index 56c4ed827d7..3488d9f60c8 100644
--- a/spec/frontend/import_entities/components/import_status_spec.js
+++ b/spec/frontend/import_entities/components/import_status_spec.js
@@ -12,10 +12,6 @@ describe('Import entities status component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('success status', () => {
const getStatusText = () => wrapper.findComponent(GlBadge).text();
const getStatusIcon = () => wrapper.findComponent(GlBadge).props('icon');
diff --git a/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js b/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js
index 163a60bae36..1a52485f779 100644
--- a/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js
@@ -1,4 +1,4 @@
-import { GlButton, GlIcon, GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlDropdown, GlIcon, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import ImportActionsCell from '~/import_entities/import_groups/components/import_actions_cell.vue';
@@ -8,7 +8,6 @@ describe('import actions cell', () => {
const createComponent = (props) => {
wrapper = shallowMount(ImportActionsCell, {
propsData: {
- isProjectsImportEnabled: false,
isFinished: false,
isAvailableForImport: false,
isInvalid: false,
@@ -17,19 +16,15 @@ describe('import actions cell', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when group is available for import', () => {
beforeEach(() => {
createComponent({ isAvailableForImport: true });
});
- it('renders import button', () => {
- const button = wrapper.findComponent(GlButton);
- expect(button.exists()).toBe(true);
- expect(button.text()).toBe('Import');
+ it('renders import dropdown', () => {
+ const dropdown = wrapper.findComponent(GlDropdown);
+ expect(dropdown.exists()).toBe(true);
+ expect(dropdown.props('text')).toBe('Import with projects');
});
it('does not render icon with a hint', () => {
@@ -42,10 +37,10 @@ describe('import actions cell', () => {
createComponent({ isAvailableForImport: false, isFinished: true });
});
- it('renders re-import button', () => {
- const button = wrapper.findComponent(GlButton);
- expect(button.exists()).toBe(true);
- expect(button.text()).toBe('Re-import');
+ it('renders re-import dropdown', () => {
+ const dropdown = wrapper.findComponent(GlDropdown);
+ expect(dropdown.exists()).toBe(true);
+ expect(dropdown.props('text')).toBe('Re-import with projects');
});
it('renders icon with a hint', () => {
@@ -57,25 +52,25 @@ describe('import actions cell', () => {
});
});
- it('does not render import button when group is not available for import', () => {
+ it('does not render import dropdown when group is not available for import', () => {
createComponent({ isAvailableForImport: false });
- const button = wrapper.findComponent(GlButton);
- expect(button.exists()).toBe(false);
+ const dropdown = wrapper.findComponent(GlDropdown);
+ expect(dropdown.exists()).toBe(false);
});
- it('renders import button as disabled when group is invalid', () => {
+ it('renders import dropdown as disabled when group is invalid', () => {
createComponent({ isInvalid: true, isAvailableForImport: true });
- const button = wrapper.findComponent(GlButton);
- expect(button.props().disabled).toBe(true);
+ const dropdown = wrapper.findComponent(GlDropdown);
+ expect(dropdown.props().disabled).toBe(true);
});
it('emits import-group event when import button is clicked', () => {
createComponent({ isAvailableForImport: true });
- const button = wrapper.findComponent(GlButton);
- button.vm.$emit('click');
+ const dropdown = wrapper.findComponent(GlDropdown);
+ dropdown.vm.$emit('click');
expect(wrapper.emitted('import-group')).toHaveLength(1);
});
@@ -85,10 +80,10 @@ describe('import actions cell', () => {
${false} | ${'Import'}
${true} | ${'Re-import'}
`(
- 'when import projects is enabled, group is available for import and finish status is $status',
+ 'group is available for import and finish status is $isFinished',
({ isFinished, expectedAction }) => {
beforeEach(() => {
- createComponent({ isProjectsImportEnabled: true, isAvailableForImport: true, isFinished });
+ createComponent({ isAvailableForImport: true, isFinished });
});
it('render import dropdown', () => {
diff --git a/spec/frontend/import_entities/import_groups/components/import_source_cell_spec.js b/spec/frontend/import_entities/import_groups/components/import_source_cell_spec.js
index f2735d86493..9ead483d02f 100644
--- a/spec/frontend/import_entities/import_groups/components/import_source_cell_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_source_cell_spec.js
@@ -22,10 +22,6 @@ describe('import source cell', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when group status is NONE', () => {
beforeEach(() => {
group = generateFakeTableEntry({ id: 1, status: STATUSES.NONE });
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 c7bda5a60ec..205218fdabd 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
@@ -6,7 +6,7 @@ import MockAdapter from 'axios-mock-adapter';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_OK, HTTP_STATUS_TOO_MANY_REQUESTS } from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
import { STATUSES } from '~/import_entities/constants';
@@ -23,7 +23,7 @@ import {
generateFakeEntry,
} from '../graphql/fixtures';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/import_entities/import_groups/services/status_poller');
Vue.use(VueApollo);
@@ -49,12 +49,12 @@ describe('import table', () => {
},
};
- const findImportSelectedButton = () =>
- wrapper.findAll('button').wrappers.find((w) => w.text() === 'Import selected');
const findImportSelectedDropdown = () =>
- wrapper.findAll('.gl-dropdown').wrappers.find((w) => w.text().includes('Import with projects'));
- const findImportButtons = () =>
- wrapper.findAll('button').wrappers.filter((w) => w.text() === 'Import');
+ wrapper.find('[data-testid="import-selected-groups-dropdown"]');
+ const findRowImportDropdownAtIndex = (idx) =>
+ wrapper.findAll('tbody td button').wrappers.filter((w) => w.text() === 'Import with projects')[
+ idx
+ ];
const findPaginationDropdown = () => wrapper.find('[data-testid="page-size"]');
const findTargetNamespaceDropdown = (rowWrapper) =>
rowWrapper.find('[data-testid="target-namespace-selector"]');
@@ -70,12 +70,7 @@ describe('import table', () => {
const findRowCheckbox = (idx) => wrapper.findAll('tbody td input[type=checkbox]').at(idx);
const selectRow = (idx) => findRowCheckbox(idx).setChecked(true);
- const createComponent = ({
- bulkImportSourceGroups,
- importGroups,
- defaultTargetNamespace,
- glFeatures = {},
- }) => {
+ const createComponent = ({ bulkImportSourceGroups, importGroups, defaultTargetNamespace }) => {
apolloProvider = createMockApollo(
[
[
@@ -102,10 +97,7 @@ describe('import table', () => {
defaultTargetNamespace,
},
directives: {
- GlTooltip: createMockDirective(),
- },
- provide: {
- glFeatures,
+ GlTooltip: createMockDirective('gl-tooltip'),
},
apolloProvider,
});
@@ -120,10 +112,6 @@ describe('import table', () => {
axiosMock.onGet(/.*\/exists$/, () => []).reply(HTTP_STATUS_OK, { exists: false });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('loading state', () => {
it('renders loading icon while performing request', async () => {
createComponent({
@@ -134,7 +122,7 @@ describe('import table', () => {
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
- it('does not renders loading icon when request is completed', async () => {
+ it('does not render loading icon when request is completed', async () => {
createComponent({
bulkImportSourceGroups: () => [],
});
@@ -245,12 +233,13 @@ describe('import table', () => {
await waitForPromises();
- await findImportButtons()[0].trigger('click');
+ await findRowImportDropdownAtIndex(0).trigger('click');
expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith({
mutation: importGroupsMutation,
variables: {
importRequests: [
{
+ migrateProjects: true,
newName: FAKE_GROUP.lastImportTarget.newName,
sourceGroupId: FAKE_GROUP.id,
targetNamespace: AVAILABLE_NAMESPACES[0].fullPath,
@@ -273,7 +262,7 @@ describe('import table', () => {
});
await waitForPromises();
- await findImportButtons()[0].trigger('click');
+ await findRowImportDropdownAtIndex(0).trigger('click');
await waitForPromises();
expect(createAlert).toHaveBeenCalledWith(
@@ -298,7 +287,7 @@ describe('import table', () => {
});
await waitForPromises();
- await findImportButtons()[0].trigger('click');
+ await findRowImportDropdownAtIndex(0).trigger('click');
await waitForPromises();
expect(createAlert).not.toHaveBeenCalled();
@@ -476,7 +465,7 @@ describe('import table', () => {
});
await waitForPromises();
- expect(findImportSelectedButton().props().disabled).toBe(true);
+ expect(findImportSelectedDropdown().props().disabled).toBe(true);
});
it('import selected button is enabled when groups were selected for import', async () => {
@@ -491,7 +480,7 @@ describe('import table', () => {
await selectRow(0);
- expect(findImportSelectedButton().props().disabled).toBe(false);
+ expect(findImportSelectedDropdown().props().disabled).toBe(false);
});
it('does not allow selecting already started groups', async () => {
@@ -509,7 +498,7 @@ describe('import table', () => {
await selectRow(0);
await nextTick();
- expect(findImportSelectedButton().props().disabled).toBe(true);
+ expect(findImportSelectedDropdown().props().disabled).toBe(true);
});
it('does not allow selecting groups with validation errors', async () => {
@@ -534,10 +523,10 @@ describe('import table', () => {
await selectRow(0);
await nextTick();
- expect(findImportSelectedButton().props().disabled).toBe(true);
+ expect(findImportSelectedDropdown().props().disabled).toBe(true);
});
- it('invokes importGroups mutation when import selected button is clicked', async () => {
+ it('invokes importGroups mutation when import selected dropdown is clicked', async () => {
const NEW_GROUPS = [
generateFakeEntry({ id: 1, status: STATUSES.NONE }),
generateFakeEntry({ id: 2, status: STATUSES.NONE }),
@@ -558,7 +547,7 @@ describe('import table', () => {
await selectRow(1);
await nextTick();
- await findImportSelectedButton().trigger('click');
+ await findImportSelectedDropdown().find('button').trigger('click');
expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith({
mutation: importGroupsMutation,
@@ -679,7 +668,7 @@ describe('import table', () => {
});
});
- describe('when import projects is enabled', () => {
+ describe('importing projects', () => {
const NEW_GROUPS = [
generateFakeEntry({ id: 1, status: STATUSES.NONE }),
generateFakeEntry({ id: 2, status: STATUSES.NONE }),
@@ -693,9 +682,6 @@ describe('import table', () => {
pageInfo: FAKE_PAGE_INFO,
versionValidation: FAKE_VERSION_VALIDATION,
}),
- glFeatures: {
- bulkImportProjects: true,
- },
});
jest.spyOn(apolloProvider.defaultClient, 'mutate');
return waitForPromises();
diff --git a/spec/frontend/import_entities/import_groups/components/import_target_cell_spec.js b/spec/frontend/import_entities/import_groups/components/import_target_cell_spec.js
index d5286e71c44..a524d9ebdb0 100644
--- a/spec/frontend/import_entities/import_groups/components/import_target_cell_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_target_cell_spec.js
@@ -57,11 +57,6 @@ describe('import target cell', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('events', () => {
beforeEach(async () => {
group = generateFakeTableEntry({ id: 1, status: STATUSES.NONE });
diff --git a/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js b/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js
index ce111a0c10c..83566469176 100644
--- a/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js
+++ b/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js
@@ -16,7 +16,7 @@ import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { statusEndpointFixture } from './fixtures';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/import_entities/import_groups/graphql/services/local_storage_cache', () => ({
LocalStorageCache: jest.fn().mockImplementation(function mock() {
this.get = jest.fn();
diff --git a/spec/frontend/import_entities/import_groups/services/status_poller_spec.js b/spec/frontend/import_entities/import_groups/services/status_poller_spec.js
index 4a1b85d24e3..5ee2b2e698f 100644
--- a/spec/frontend/import_entities/import_groups/services/status_poller_spec.js
+++ b/spec/frontend/import_entities/import_groups/services/status_poller_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import Visibility from 'visibilityjs';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { STATUSES } from '~/import_entities/constants';
import { StatusPoller } from '~/import_entities/import_groups/services/status_poller';
import axios from '~/lib/utils/axios_utils';
@@ -8,7 +8,7 @@ import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import Poll from '~/lib/utils/poll';
jest.mock('visibilityjs');
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/poll');
const FAKE_POLL_PATH = '/fake/poll/path';
@@ -81,7 +81,7 @@ describe('Bulk import status poller', () => {
expect(pollInstance.makeRequest).toHaveBeenCalled();
});
- it('when error occurs shows flash with error', () => {
+ it('when error occurs shows alert with error', () => {
const [[pollConfig]] = Poll.mock.calls;
pollConfig.errorCallback();
expect(createAlert).toHaveBeenCalled();
diff --git a/spec/frontend/import_entities/import_projects/components/advanced_settings_spec.js b/spec/frontend/import_entities/import_projects/components/advanced_settings_spec.js
index 68716600592..2294d236e8b 100644
--- a/spec/frontend/import_entities/import_projects/components/advanced_settings_spec.js
+++ b/spec/frontend/import_entities/import_projects/components/advanced_settings_spec.js
@@ -25,10 +25,6 @@ describe('Import Advanced Settings', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders GLFormCheckbox for each optional stage', () => {
expect(wrapper.findAllComponents(GlFormCheckbox)).toHaveLength(OPTIONAL_STAGES.length);
});
diff --git a/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js b/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js
index e613b9756af..8e73f76382a 100644
--- a/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js
+++ b/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js
@@ -60,11 +60,6 @@ describe('ProviderRepoTableRow', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when rendering importable project', () => {
const repo = {
importSource: {
diff --git a/spec/frontend/import_entities/import_projects/store/actions_spec.js b/spec/frontend/import_entities/import_projects/store/actions_spec.js
index 990587d4af7..f78016eefcf 100644
--- a/spec/frontend/import_entities/import_projects/store/actions_spec.js
+++ b/spec/frontend/import_entities/import_projects/store/actions_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { STATUSES, PROVIDERS } from '~/import_entities/constants';
import actionsFactory from '~/import_entities/import_projects/store/actions';
import { getImportTarget } from '~/import_entities/import_projects/store/getters';
@@ -27,7 +27,7 @@ import {
HTTP_STATUS_TOO_MANY_REQUESTS,
} from '~/lib/utils/http_status';
-jest.mock('~/flash');
+jest.mock('~/alert');
const MOCK_ENDPOINT = `${TEST_HOST}/endpoint.json`;
const endpoints = {
diff --git a/spec/frontend/incidents_settings/components/incidents_settings_service_spec.js b/spec/frontend/incidents_settings/components/incidents_settings_service_spec.js
index 1d1b285c1b6..c5c29b4bb19 100644
--- a/spec/frontend/incidents_settings/components/incidents_settings_service_spec.js
+++ b/spec/frontend/incidents_settings/components/incidents_settings_service_spec.js
@@ -1,12 +1,12 @@
import AxiosMockAdapter from 'axios-mock-adapter';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { ERROR_MSG } from '~/incidents_settings/constants';
import IncidentsSettingsService from '~/incidents_settings/incidents_settings_service';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
describe('IncidentsSettingsService', () => {
@@ -33,7 +33,7 @@ describe('IncidentsSettingsService', () => {
});
});
- it('should display a flash message on update error', () => {
+ it('should display an alert message on update error', () => {
mock.onPatch().reply(HTTP_STATUS_BAD_REQUEST);
return service.updateSettings({}).then(() => {
diff --git a/spec/frontend/incidents_settings/components/pagerduty_form_spec.js b/spec/frontend/incidents_settings/components/pagerduty_form_spec.js
index 521a861829b..77258db437d 100644
--- a/spec/frontend/incidents_settings/components/pagerduty_form_spec.js
+++ b/spec/frontend/incidents_settings/components/pagerduty_form_spec.js
@@ -26,10 +26,6 @@ describe('Alert integration settings form', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should match the default snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/integrations/edit/components/active_checkbox_spec.js b/spec/frontend/integrations/edit/components/active_checkbox_spec.js
index 1f7a5f0dbc9..8afff842a85 100644
--- a/spec/frontend/integrations/edit/components/active_checkbox_spec.js
+++ b/spec/frontend/integrations/edit/components/active_checkbox_spec.js
@@ -17,10 +17,6 @@ describe('ActiveCheckbox', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlFormCheckbox = () => wrapper.findComponent(GlFormCheckbox);
const findInputInCheckbox = () => findGlFormCheckbox().find('input');
diff --git a/spec/frontend/integrations/edit/components/confirmation_modal_spec.js b/spec/frontend/integrations/edit/components/confirmation_modal_spec.js
index cbe3402727a..dfb6b7d9a9c 100644
--- a/spec/frontend/integrations/edit/components/confirmation_modal_spec.js
+++ b/spec/frontend/integrations/edit/components/confirmation_modal_spec.js
@@ -14,10 +14,6 @@ describe('ConfirmationModal', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlModal = () => wrapper.findComponent(GlModal);
describe('template', () => {
diff --git a/spec/frontend/integrations/edit/components/dynamic_field_spec.js b/spec/frontend/integrations/edit/components/dynamic_field_spec.js
index 7589b04b0fd..e1d9aef752f 100644
--- a/spec/frontend/integrations/edit/components/dynamic_field_spec.js
+++ b/spec/frontend/integrations/edit/components/dynamic_field_spec.js
@@ -21,10 +21,6 @@ describe('DynamicField', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlFormGroup = () => wrapper.findComponent(GlFormGroup);
const findGlFormCheckbox = () => wrapper.findComponent(GlFormCheckbox);
const findGlFormInput = () => wrapper.findComponent(GlFormInput);
diff --git a/spec/frontend/integrations/edit/components/integration_form_spec.js b/spec/frontend/integrations/edit/components/integration_form_spec.js
index 383dfb36aa5..58fb456eb53 100644
--- a/spec/frontend/integrations/edit/components/integration_form_spec.js
+++ b/spec/frontend/integrations/edit/components/integration_form_spec.js
@@ -84,7 +84,6 @@ describe('IntegrationForm', () => {
});
afterEach(() => {
- wrapper.destroy();
mockAxios.restore();
});
@@ -507,30 +506,21 @@ describe('IntegrationForm', () => {
const dummyHelp = 'Foo Help';
it.each`
- integration | flagIsOn | helpHtml | sections | shouldShowSections | shouldShowHelp
- ${INTEGRATION_FORM_TYPE_SLACK} | ${false} | ${''} | ${[]} | ${false} | ${false}
- ${INTEGRATION_FORM_TYPE_SLACK} | ${false} | ${dummyHelp} | ${[]} | ${false} | ${true}
- ${INTEGRATION_FORM_TYPE_SLACK} | ${false} | ${undefined} | ${[mockSectionConnection]} | ${false} | ${false}
- ${INTEGRATION_FORM_TYPE_SLACK} | ${false} | ${dummyHelp} | ${[mockSectionConnection]} | ${false} | ${true}
- ${INTEGRATION_FORM_TYPE_SLACK} | ${true} | ${''} | ${[]} | ${false} | ${false}
- ${INTEGRATION_FORM_TYPE_SLACK} | ${true} | ${dummyHelp} | ${[]} | ${false} | ${true}
- ${INTEGRATION_FORM_TYPE_SLACK} | ${true} | ${undefined} | ${[mockSectionConnection]} | ${true} | ${false}
- ${INTEGRATION_FORM_TYPE_SLACK} | ${true} | ${dummyHelp} | ${[mockSectionConnection]} | ${true} | ${true}
- ${'foo'} | ${false} | ${''} | ${[]} | ${false} | ${false}
- ${'foo'} | ${false} | ${dummyHelp} | ${[]} | ${false} | ${true}
- ${'foo'} | ${false} | ${undefined} | ${[mockSectionConnection]} | ${true} | ${false}
- ${'foo'} | ${false} | ${dummyHelp} | ${[mockSectionConnection]} | ${true} | ${false}
- ${'foo'} | ${true} | ${''} | ${[]} | ${false} | ${false}
- ${'foo'} | ${true} | ${dummyHelp} | ${[]} | ${false} | ${true}
- ${'foo'} | ${true} | ${undefined} | ${[mockSectionConnection]} | ${true} | ${false}
- ${'foo'} | ${true} | ${dummyHelp} | ${[mockSectionConnection]} | ${true} | ${false}
+ integration | helpHtml | sections | shouldShowSections | shouldShowHelp
+ ${INTEGRATION_FORM_TYPE_SLACK} | ${''} | ${[]} | ${false} | ${false}
+ ${INTEGRATION_FORM_TYPE_SLACK} | ${dummyHelp} | ${[]} | ${false} | ${true}
+ ${INTEGRATION_FORM_TYPE_SLACK} | ${undefined} | ${[mockSectionConnection]} | ${true} | ${false}
+ ${INTEGRATION_FORM_TYPE_SLACK} | ${dummyHelp} | ${[mockSectionConnection]} | ${true} | ${true}
+ ${'foo'} | ${''} | ${[]} | ${false} | ${false}
+ ${'foo'} | ${dummyHelp} | ${[]} | ${false} | ${true}
+ ${'foo'} | ${undefined} | ${[mockSectionConnection]} | ${true} | ${false}
+ ${'foo'} | ${dummyHelp} | ${[mockSectionConnection]} | ${true} | ${false}
`(
- '$sections sections, and "$helpHtml" helpHtml when the FF is "$flagIsOn" for "$integration" integration',
- ({ integration, flagIsOn, helpHtml, sections, shouldShowSections, shouldShowHelp }) => {
+ '$sections sections, and "$helpHtml" helpHtml for "$integration" integration',
+ ({ integration, helpHtml, sections, shouldShowSections, shouldShowHelp }) => {
createComponent({
provide: {
helpHtml,
- glFeatures: { integrationSlackAppNotifications: flagIsOn },
},
customStateProps: {
sections,
@@ -553,20 +543,15 @@ describe('IntegrationForm', () => {
${false} | ${true} | ${'When having only the fields without a section'}
`('$description', ({ hasSections, hasFieldsWithoutSections }) => {
it.each`
- prefix | integration | shouldUpgradeSlack | flagIsOn | shouldShowAlert
- ${'does'} | ${INTEGRATION_FORM_TYPE_SLACK} | ${true} | ${true} | ${true}
- ${'does not'} | ${INTEGRATION_FORM_TYPE_SLACK} | ${false} | ${true} | ${false}
- ${'does not'} | ${INTEGRATION_FORM_TYPE_SLACK} | ${true} | ${false} | ${false}
- ${'does not'} | ${'foo'} | ${true} | ${true} | ${false}
- ${'does not'} | ${'foo'} | ${false} | ${true} | ${false}
- ${'does not'} | ${'foo'} | ${true} | ${false} | ${false}
+ prefix | integration | shouldUpgradeSlack | shouldShowAlert
+ ${'does'} | ${INTEGRATION_FORM_TYPE_SLACK} | ${true} | ${true}
+ ${'does not'} | ${INTEGRATION_FORM_TYPE_SLACK} | ${false} | ${false}
+ ${'does not'} | ${'foo'} | ${true} | ${false}
+ ${'does not'} | ${'foo'} | ${false} | ${false}
`(
- '$prefix render the upgrade warning when we are in "$integration" integration with the flag "$flagIsOn" and Slack-needs-upgrade is "$shouldUpgradeSlack" and have sections',
- ({ integration, shouldUpgradeSlack, flagIsOn, shouldShowAlert }) => {
+ '$prefix render the upgrade warning when we are in "$integration" integration with Slack-needs-upgrade is "$shouldUpgradeSlack" and have sections',
+ ({ integration, shouldUpgradeSlack, shouldShowAlert }) => {
createComponent({
- provide: {
- glFeatures: { integrationSlackAppNotifications: flagIsOn },
- },
customStateProps: {
shouldUpgradeSlack,
type: integration,
diff --git a/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js b/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
index fa91f8de45a..90ee69ef2dc 100644
--- a/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
+++ b/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
@@ -31,10 +31,6 @@ describe('JiraIssuesFields', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findEnableCheckbox = () => wrapper.findComponent(GlFormCheckbox);
const findEnableCheckboxDisabled = () =>
findEnableCheckbox().find('[type=checkbox]').attributes('disabled');
diff --git a/spec/frontend/integrations/edit/components/jira_trigger_fields_spec.js b/spec/frontend/integrations/edit/components/jira_trigger_fields_spec.js
index 6011b3e6edc..f876a497f98 100644
--- a/spec/frontend/integrations/edit/components/jira_trigger_fields_spec.js
+++ b/spec/frontend/integrations/edit/components/jira_trigger_fields_spec.js
@@ -22,10 +22,6 @@ describe('JiraTriggerFields', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findCommentSettings = () => wrapper.findByTestId('comment-settings');
const findCommentDetail = () => wrapper.findByTestId('comment-detail');
const findCommentSettingsCheckbox = () => findCommentSettings().findComponent(GlFormCheckbox);
diff --git a/spec/frontend/integrations/edit/components/override_dropdown_spec.js b/spec/frontend/integrations/edit/components/override_dropdown_spec.js
index 90facaff1f9..2d1a6b3ace1 100644
--- a/spec/frontend/integrations/edit/components/override_dropdown_spec.js
+++ b/spec/frontend/integrations/edit/components/override_dropdown_spec.js
@@ -26,10 +26,6 @@ describe('OverrideDropdown', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlLink = () => wrapper.findComponent(GlLink);
const findGlDropdown = () => wrapper.findComponent(GlDropdown);
diff --git a/spec/frontend/integrations/edit/components/sections/apple_app_store_spec.js b/spec/frontend/integrations/edit/components/sections/apple_app_store_spec.js
new file mode 100644
index 00000000000..62f0439a13f
--- /dev/null
+++ b/spec/frontend/integrations/edit/components/sections/apple_app_store_spec.js
@@ -0,0 +1,57 @@
+import { shallowMount } from '@vue/test-utils';
+
+import IntegrationSectionAppleAppStore from '~/integrations/edit/components/sections/apple_app_store.vue';
+import UploadDropzoneField from '~/integrations/edit/components/upload_dropzone_field.vue';
+import { createStore } from '~/integrations/edit/store';
+
+describe('IntegrationSectionAppleAppStore', () => {
+ let wrapper;
+
+ const createComponent = (componentFields) => {
+ const store = createStore({
+ customState: { ...componentFields },
+ });
+ wrapper = shallowMount(IntegrationSectionAppleAppStore, {
+ store,
+ });
+ };
+
+ const componentFields = (fileName = '') => {
+ return {
+ fields: [
+ {
+ name: 'app_store_private_key_file_name',
+ value: fileName,
+ },
+ ],
+ };
+ };
+
+ const findUploadDropzoneField = () => wrapper.findComponent(UploadDropzoneField);
+
+ describe('computed properties', () => {
+ it('renders UploadDropzoneField with default values', () => {
+ createComponent(componentFields());
+
+ const field = findUploadDropzoneField();
+
+ expect(field.exists()).toBe(true);
+ expect(field.props()).toMatchObject({
+ label: 'The Apple App Store Connect Private Key (.p8)',
+ helpText: '',
+ });
+ });
+
+ it('renders UploadDropzoneField with custom values for an attached file', () => {
+ createComponent(componentFields('fileName.txt'));
+
+ const field = findUploadDropzoneField();
+
+ expect(field.exists()).toBe(true);
+ expect(field.props()).toMatchObject({
+ label: 'Upload a new Apple App Store Connect Private Key (replace fileName.txt)',
+ helpText: 'Leave empty to use your current Private Key.',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/integrations/edit/components/sections/configuration_spec.js b/spec/frontend/integrations/edit/components/sections/configuration_spec.js
index e697212ea0b..c8a7d17c041 100644
--- a/spec/frontend/integrations/edit/components/sections/configuration_spec.js
+++ b/spec/frontend/integrations/edit/components/sections/configuration_spec.js
@@ -19,10 +19,6 @@ describe('IntegrationSectionCoonfiguration', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findAllDynamicFields = () => wrapper.findAllComponents(DynamicField);
describe('template', () => {
diff --git a/spec/frontend/integrations/edit/components/sections/connection_spec.js b/spec/frontend/integrations/edit/components/sections/connection_spec.js
index 1eb92e80723..a24253d542d 100644
--- a/spec/frontend/integrations/edit/components/sections/connection_spec.js
+++ b/spec/frontend/integrations/edit/components/sections/connection_spec.js
@@ -20,10 +20,6 @@ describe('IntegrationSectionConnection', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findActiveCheckbox = () => wrapper.findComponent(ActiveCheckbox);
const findAllDynamicFields = () => wrapper.findAllComponents(DynamicField);
diff --git a/spec/frontend/integrations/edit/components/sections/google_play_spec.js b/spec/frontend/integrations/edit/components/sections/google_play_spec.js
new file mode 100644
index 00000000000..c0d6d17f639
--- /dev/null
+++ b/spec/frontend/integrations/edit/components/sections/google_play_spec.js
@@ -0,0 +1,54 @@
+import { shallowMount } from '@vue/test-utils';
+
+import IntegrationSectionGooglePlay from '~/integrations/edit/components/sections/google_play.vue';
+import UploadDropzoneField from '~/integrations/edit/components/upload_dropzone_field.vue';
+import { createStore } from '~/integrations/edit/store';
+
+describe('IntegrationSectionGooglePlay', () => {
+ let wrapper;
+
+ const createComponent = (fileName = '') => {
+ const store = createStore({
+ customState: {
+ fields: [
+ {
+ name: 'service_account_key_file_name',
+ value: fileName,
+ },
+ ],
+ },
+ });
+
+ wrapper = shallowMount(IntegrationSectionGooglePlay, {
+ store,
+ });
+ };
+
+ const findUploadDropzoneField = () => wrapper.findComponent(UploadDropzoneField);
+
+ describe('computed properties', () => {
+ it('renders UploadDropzoneField with default values', () => {
+ createComponent();
+
+ const field = findUploadDropzoneField();
+
+ expect(field.exists()).toBe(true);
+ expect(field.props()).toMatchObject({
+ label: 'Service account key (.json)',
+ helpText: '',
+ });
+ });
+
+ it('renders UploadDropzoneField with custom values for an attached file', () => {
+ createComponent('fileName.txt');
+
+ const field = findUploadDropzoneField();
+
+ expect(field.exists()).toBe(true);
+ expect(field.props()).toMatchObject({
+ label: 'Upload a new service account key (replace fileName.txt)',
+ helpText: 'Leave empty to use your current service account key.',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/integrations/edit/components/sections/jira_issues_spec.js b/spec/frontend/integrations/edit/components/sections/jira_issues_spec.js
index a7c1cc2a03f..8b39fa8f583 100644
--- a/spec/frontend/integrations/edit/components/sections/jira_issues_spec.js
+++ b/spec/frontend/integrations/edit/components/sections/jira_issues_spec.js
@@ -18,10 +18,6 @@ describe('IntegrationSectionJiraIssue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findJiraIssuesFields = () => wrapper.findComponent(JiraIssuesFields);
describe('template', () => {
diff --git a/spec/frontend/integrations/edit/components/sections/jira_trigger_spec.js b/spec/frontend/integrations/edit/components/sections/jira_trigger_spec.js
index d4ab9864fab..b3b7f508e25 100644
--- a/spec/frontend/integrations/edit/components/sections/jira_trigger_spec.js
+++ b/spec/frontend/integrations/edit/components/sections/jira_trigger_spec.js
@@ -18,10 +18,6 @@ describe('IntegrationSectionJiraTrigger', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findJiraTriggerFields = () => wrapper.findComponent(JiraTriggerFields);
describe('template', () => {
diff --git a/spec/frontend/integrations/edit/components/sections/trigger_spec.js b/spec/frontend/integrations/edit/components/sections/trigger_spec.js
index 883f5c7bf79..b9c1efbb0a2 100644
--- a/spec/frontend/integrations/edit/components/sections/trigger_spec.js
+++ b/spec/frontend/integrations/edit/components/sections/trigger_spec.js
@@ -18,10 +18,6 @@ describe('IntegrationSectionTrigger', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findAllTriggerFields = () => wrapper.findAllComponents(TriggerField);
describe('template', () => {
diff --git a/spec/frontend/integrations/edit/components/trigger_field_spec.js b/spec/frontend/integrations/edit/components/trigger_field_spec.js
index ed0b3324708..3b736b33a2f 100644
--- a/spec/frontend/integrations/edit/components/trigger_field_spec.js
+++ b/spec/frontend/integrations/edit/components/trigger_field_spec.js
@@ -23,10 +23,6 @@ describe('TriggerField', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlFormCheckbox = () => wrapper.findComponent(GlFormCheckbox);
const findGlFormInput = () => wrapper.findComponent(GlFormInput);
const findHiddenInput = () => wrapper.find('input[type="hidden"]');
diff --git a/spec/frontend/integrations/edit/components/trigger_fields_spec.js b/spec/frontend/integrations/edit/components/trigger_fields_spec.js
index 082eeea30f1..defa02aefd2 100644
--- a/spec/frontend/integrations/edit/components/trigger_fields_spec.js
+++ b/spec/frontend/integrations/edit/components/trigger_fields_spec.js
@@ -20,10 +20,6 @@ describe('TriggerFields', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findTriggerLabel = () => wrapper.findByTestId('trigger-fields-group').find('label');
const findAllGlFormGroups = () => wrapper.find('#trigger-fields').findAllComponents(GlFormGroup);
const findAllGlFormCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
diff --git a/spec/frontend/integrations/edit/components/upload_dropzone_field_spec.js b/spec/frontend/integrations/edit/components/upload_dropzone_field_spec.js
new file mode 100644
index 00000000000..36e20db0022
--- /dev/null
+++ b/spec/frontend/integrations/edit/components/upload_dropzone_field_spec.js
@@ -0,0 +1,88 @@
+import { mount } from '@vue/test-utils';
+import { GlAlert } from '@gitlab/ui';
+import { nextTick } from 'vue';
+
+import UploadDropzoneField from '~/integrations/edit/components/upload_dropzone_field.vue';
+import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
+import { mockField } from '../mock_data';
+
+describe('UploadDropzoneField', () => {
+ let wrapper;
+
+ const contentsInputName = 'service[app_store_private_key]';
+ const fileNameInputName = 'service[app_store_private_key_file_name]';
+
+ const createComponent = (props) => {
+ wrapper = mount(UploadDropzoneField, {
+ propsData: {
+ ...mockField,
+ ...props,
+ name: contentsInputName,
+ label: 'Input Label',
+ fileInputName: fileNameInputName,
+ },
+ });
+ };
+
+ const findGlAlert = () => wrapper.findComponent(GlAlert);
+ const findUploadDropzone = () => wrapper.findComponent(UploadDropzone);
+ const findFileContentsHiddenInput = () => wrapper.find(`input[name="${contentsInputName}"]`);
+ const findFileNameHiddenInput = () => wrapper.find(`input[name="${fileNameInputName}"]`);
+
+ describe('template', () => {
+ it('adds the expected file inputFieldName', () => {
+ createComponent();
+
+ expect(findUploadDropzone().props('inputFieldName')).toBe('service[dropzone_file_name]');
+ });
+
+ it('adds a disabled, hidden text input for the file contents', () => {
+ createComponent();
+
+ expect(findFileContentsHiddenInput().attributes('name')).toBe(contentsInputName);
+ expect(findFileContentsHiddenInput().attributes('disabled')).toBeDefined();
+ });
+
+ it('adds a disabled, hidden text input for the file name', () => {
+ createComponent();
+
+ expect(findFileNameHiddenInput().attributes('name')).toBe(fileNameInputName);
+ expect(findFileNameHiddenInput().attributes('disabled')).toBeDefined();
+ });
+ });
+
+ describe('clearError', () => {
+ it('clears uploadError when called', async () => {
+ createComponent();
+
+ expect(findGlAlert().exists()).toBe(false);
+
+ findUploadDropzone().vm.$emit('error');
+ await nextTick();
+
+ expect(findGlAlert().exists()).toBe(true);
+ expect(findGlAlert().text()).toBe(
+ 'Error: You are trying to upload something other than an allowed file.',
+ );
+
+ findGlAlert().vm.$emit('dismiss');
+ await nextTick();
+
+ expect(findGlAlert().exists()).toBe(false);
+ });
+ });
+
+ describe('onError', () => {
+ it('assigns uploadError to the supplied custom message', async () => {
+ const message = 'test error message';
+ createComponent({ errorMessage: message });
+
+ findUploadDropzone().vm.$emit('error');
+
+ await nextTick();
+
+ expect(findGlAlert().exists()).toBe(true);
+ expect(findGlAlert().text()).toBe(message);
+ });
+ });
+});
diff --git a/spec/frontend/integrations/index/components/integrations_list_spec.js b/spec/frontend/integrations/index/components/integrations_list_spec.js
index ee54a5fd359..155a3d1c6be 100644
--- a/spec/frontend/integrations/index/components/integrations_list_spec.js
+++ b/spec/frontend/integrations/index/components/integrations_list_spec.js
@@ -13,10 +13,6 @@ describe('IntegrationsList', () => {
wrapper = shallowMountExtended(IntegrationsList, { propsData });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('provides correct `integrations` prop to the IntegrationsTable instance', () => {
createComponent({ integrations: [...mockInactiveIntegrations, ...mockActiveIntegrations] });
diff --git a/spec/frontend/integrations/index/components/integrations_table_spec.js b/spec/frontend/integrations/index/components/integrations_table_spec.js
index 976c7b74890..5456a23a98d 100644
--- a/spec/frontend/integrations/index/components/integrations_table_spec.js
+++ b/spec/frontend/integrations/index/components/integrations_table_spec.js
@@ -1,6 +1,5 @@
-import { GlTable, GlIcon, GlLink } from '@gitlab/ui';
+import { GlTable, GlIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
-import { INTEGRATION_TYPE_SLACK } from '~/integrations/constants';
import IntegrationsTable from '~/integrations/index/components/integrations_table.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
@@ -11,24 +10,15 @@ describe('IntegrationsTable', () => {
const findTable = () => wrapper.findComponent(GlTable);
- const createComponent = (propsData = {}, flagIsOn = false) => {
+ const createComponent = (propsData = {}) => {
wrapper = mount(IntegrationsTable, {
propsData: {
integrations: mockActiveIntegrations,
...propsData,
},
- provide: {
- glFeatures: {
- integrationSlackAppNotifications: flagIsOn,
- },
- },
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each([true, false])('when `showUpdatedAt` is %p', (showUpdatedAt) => {
beforeEach(() => {
createComponent({ showUpdatedAt });
@@ -56,51 +46,4 @@ describe('IntegrationsTable', () => {
expect(findTable().findComponent(GlIcon).exists()).toBe(shouldRenderActiveIcon);
});
});
-
- describe('integrations filtering', () => {
- const slackActive = {
- ...mockActiveIntegrations[0],
- name: INTEGRATION_TYPE_SLACK,
- title: 'Slack',
- };
- const slackInactive = {
- ...mockInactiveIntegrations[0],
- name: INTEGRATION_TYPE_SLACK,
- title: 'Slack',
- };
-
- describe.each`
- desc | flagIsOn | integrations | expectedIntegrations
- ${'only active'} | ${false} | ${mockActiveIntegrations} | ${mockActiveIntegrations}
- ${'only active'} | ${true} | ${mockActiveIntegrations} | ${mockActiveIntegrations}
- ${'only inactive'} | ${true} | ${mockInactiveIntegrations} | ${mockInactiveIntegrations}
- ${'only inactive'} | ${false} | ${mockInactiveIntegrations} | ${mockInactiveIntegrations}
- ${'active and inactive'} | ${true} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]}
- ${'active and inactive'} | ${false} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]}
- ${'Slack active with active'} | ${false} | ${[slackActive, ...mockActiveIntegrations]} | ${[slackActive, ...mockActiveIntegrations]}
- ${'Slack active with active'} | ${true} | ${[slackActive, ...mockActiveIntegrations]} | ${[slackActive, ...mockActiveIntegrations]}
- ${'Slack active with inactive'} | ${false} | ${[slackActive, ...mockInactiveIntegrations]} | ${[slackActive, ...mockInactiveIntegrations]}
- ${'Slack active with inactive'} | ${true} | ${[slackActive, ...mockInactiveIntegrations]} | ${[slackActive, ...mockInactiveIntegrations]}
- ${'Slack inactive with active'} | ${false} | ${[slackInactive, ...mockActiveIntegrations]} | ${[slackInactive, ...mockActiveIntegrations]}
- ${'Slack inactive with active'} | ${true} | ${[slackInactive, ...mockActiveIntegrations]} | ${mockActiveIntegrations}
- ${'Slack inactive with inactive'} | ${false} | ${[slackInactive, ...mockInactiveIntegrations]} | ${[slackInactive, ...mockInactiveIntegrations]}
- ${'Slack inactive with inactive'} | ${true} | ${[slackInactive, ...mockInactiveIntegrations]} | ${mockInactiveIntegrations}
- ${'Slack active with active and inactive'} | ${true} | ${[slackActive, ...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[slackActive, ...mockActiveIntegrations, ...mockInactiveIntegrations]}
- ${'Slack active with active and inactive'} | ${false} | ${[slackActive, ...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[slackActive, ...mockActiveIntegrations, ...mockInactiveIntegrations]}
- ${'Slack inactive with active and inactive'} | ${true} | ${[slackInactive, ...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]}
- ${'Slack inactive with active and inactive'} | ${false} | ${[slackInactive, ...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[slackInactive, ...mockActiveIntegrations, ...mockInactiveIntegrations]}
- `('when $desc and flag "$flagIsOn"', ({ flagIsOn, integrations, expectedIntegrations }) => {
- beforeEach(() => {
- createComponent({ integrations }, flagIsOn);
- });
-
- it('renders correctly', () => {
- const links = wrapper.findAllComponents(GlLink);
- expect(links).toHaveLength(expectedIntegrations.length);
- expectedIntegrations.forEach((integration, index) => {
- expect(links.at(index).text()).toBe(integration.title);
- });
- });
- });
- });
});
diff --git a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js
index fdb728281b5..9e863eaecfd 100644
--- a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js
+++ b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js
@@ -47,7 +47,6 @@ describe('IntegrationOverrides', () => {
afterEach(() => {
mockAxios.restore();
- wrapper.destroy();
});
const findGlTable = () => wrapper.findComponent(GlTable);
diff --git a/spec/frontend/integrations/overrides/components/integration_tabs_spec.js b/spec/frontend/integrations/overrides/components/integration_tabs_spec.js
index a728b4d391f..b35a40d69c1 100644
--- a/spec/frontend/integrations/overrides/components/integration_tabs_spec.js
+++ b/spec/frontend/integrations/overrides/components/integration_tabs_spec.js
@@ -21,10 +21,6 @@ describe('IntegrationTabs', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlBadge = () => wrapper.findComponent(GlBadge);
const findGlTab = () => wrapper.findComponent(GlTab);
const findSettingsLink = () => wrapper.find('a');
diff --git a/spec/frontend/invite_members/components/confetti_spec.js b/spec/frontend/invite_members/components/confetti_spec.js
index 2f361f1dc1e..382569abfd9 100644
--- a/spec/frontend/invite_members/components/confetti_spec.js
+++ b/spec/frontend/invite_members/components/confetti_spec.js
@@ -6,16 +6,10 @@ jest.mock('canvas-confetti', () => ({
create: jest.fn(),
}));
-let wrapper;
-
const createComponent = () => {
- wrapper = shallowMount(Confetti);
+ shallowMount(Confetti);
};
-afterEach(() => {
- wrapper.destroy();
-});
-
describe('Confetti', () => {
it('initiates confetti', () => {
const basicCannon = jest.spyOn(Confetti.methods, 'basicCannon').mockImplementation(() => {});
diff --git a/spec/frontend/invite_members/components/group_select_spec.js b/spec/frontend/invite_members/components/group_select_spec.js
index e1563a7bb3a..a1ca9a69926 100644
--- a/spec/frontend/invite_members/components/group_select_spec.js
+++ b/spec/frontend/invite_members/components/group_select_spec.js
@@ -26,14 +26,9 @@ describe('GroupSelect', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDropdownToggle = () => findDropdown().find('button[aria-haspopup="true"]');
+ const findDropdownToggle = () => findDropdown().find('button[aria-haspopup="menu"]');
const findAvatarByLabel = (text) =>
wrapper
.findAllComponents(GlAvatarLabeled)
@@ -66,6 +61,7 @@ describe('GroupSelect', () => {
expect(groupsApi.getGroups).toHaveBeenCalledWith(group1.name, {
exclude_internal: true,
active: true,
+ order_by: 'similarity',
});
});
diff --git a/spec/frontend/invite_members/components/import_project_members_modal_spec.js b/spec/frontend/invite_members/components/import_project_members_modal_spec.js
index d839cde163c..74cb59a9b52 100644
--- a/spec/frontend/invite_members/components/import_project_members_modal_spec.js
+++ b/spec/frontend/invite_members/components/import_project_members_modal_spec.js
@@ -54,7 +54,6 @@ beforeEach(() => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/invite_members/components/import_project_members_trigger_spec.js b/spec/frontend/invite_members/components/import_project_members_trigger_spec.js
index b6375fcfa22..0e8243491a8 100644
--- a/spec/frontend/invite_members/components/import_project_members_trigger_spec.js
+++ b/spec/frontend/invite_members/components/import_project_members_trigger_spec.js
@@ -17,10 +17,6 @@ const createComponent = (props = {}) => {
describe('ImportProjectMembersTrigger', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
const findButton = () => wrapper.findComponent(GlButton);
describe('displayText', () => {
diff --git a/spec/frontend/invite_members/components/invite_group_trigger_spec.js b/spec/frontend/invite_members/components/invite_group_trigger_spec.js
index 84ddb779a9e..e088dc41a2b 100644
--- a/spec/frontend/invite_members/components/invite_group_trigger_spec.js
+++ b/spec/frontend/invite_members/components/invite_group_trigger_spec.js
@@ -17,11 +17,6 @@ const createComponent = (props = {}) => {
describe('InviteGroupTrigger', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findButton = () => wrapper.findComponent(GlButton);
describe('displayText', () => {
diff --git a/spec/frontend/invite_members/components/invite_groups_modal_spec.js b/spec/frontend/invite_members/components/invite_groups_modal_spec.js
index c2a55517405..82b4717fbf1 100644
--- a/spec/frontend/invite_members/components/invite_groups_modal_spec.js
+++ b/spec/frontend/invite_members/components/invite_groups_modal_spec.js
@@ -44,11 +44,6 @@ describe('InviteGroupsModal', () => {
createComponent({ isProject: false });
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findModal = () => wrapper.findComponent(GlModal);
const findGroupSelect = () => wrapper.findComponent(GroupSelect);
const findInviteGroupAlert = () => wrapper.findComponent(InviteGroupNotification);
@@ -58,11 +53,13 @@ describe('InviteGroupsModal', () => {
findMembersFormGroup().attributes('invalid-feedback');
const findBase = () => wrapper.findComponent(InviteModalBase);
const triggerGroupSelect = (val) => findGroupSelect().vm.$emit('input', val);
- const emitEventFromModal = (eventName) => () =>
- findModal().vm.$emit(eventName, { preventDefault: jest.fn() });
- const hideModal = emitEventFromModal('hidden');
- const clickInviteButton = emitEventFromModal('primary');
- const clickCancelButton = emitEventFromModal('cancel');
+ const hideModal = () => findModal().vm.$emit('hidden', { preventDefault: jest.fn() });
+
+ const emitClickFromModal = (testId) => () =>
+ wrapper.findByTestId(testId).vm.$emit('click', { preventDefault: jest.fn() });
+
+ const clickInviteButton = emitClickFromModal('invite-modal-submit');
+ const clickCancelButton = emitClickFromModal('invite-modal-cancel');
describe('displaying the correct introText and form group description', () => {
describe('when inviting to a project', () => {
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 9687d528321..39d5ddee723 100644
--- a/spec/frontend/invite_members/components/invite_members_modal_spec.js
+++ b/spec/frontend/invite_members/components/invite_members_modal_spec.js
@@ -73,6 +73,7 @@ describe('InviteMembersModal', () => {
wrapper = shallowMountExtended(InviteMembersModal, {
provide: {
newProjectPath,
+ name: propsData.name,
},
propsData: {
usersLimitDataset: {},
@@ -116,8 +117,6 @@ describe('InviteMembersModal', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
mock.restore();
});
@@ -134,10 +133,15 @@ describe('InviteMembersModal', () => {
`${Object.keys(invitationsApiResponse.EXPANDED_RESTRICTED.message)[element]}: ${
Object.values(invitationsApiResponse.EXPANDED_RESTRICTED.message)[element]
}`;
- const emitEventFromModal = (eventName) => () =>
- findModal().vm.$emit(eventName, { preventDefault: jest.fn() });
- const clickInviteButton = emitEventFromModal('primary');
- const clickCancelButton = emitEventFromModal('cancel');
+ const findActionButton = () => wrapper.findByTestId('invite-modal-submit');
+ const findCancelButton = () => wrapper.findByTestId('invite-modal-cancel');
+
+ const emitClickFromModal = (findButton) => () =>
+ findButton().vm.$emit('click', { preventDefault: jest.fn() });
+
+ const clickInviteButton = emitClickFromModal(findActionButton);
+ const clickCancelButton = emitClickFromModal(findCancelButton);
+
const findMembersFormGroup = () => wrapper.findByTestId('members-form-group');
const membersFormGroupInvalidFeedback = () =>
findMembersFormGroup().attributes('invalid-feedback');
@@ -368,13 +372,11 @@ describe('InviteMembersModal', () => {
it('tracks actions', async () => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- const mockEvent = { preventDefault: jest.fn() };
-
await triggerOpenModal({ mode: 'celebrate', source: ON_CELEBRATION_TRACK_LABEL });
expectTracking('render', ON_CELEBRATION_TRACK_LABEL);
- findModal().vm.$emit('cancel', mockEvent);
+ clickCancelButton();
expectTracking('click_cancel', ON_CELEBRATION_TRACK_LABEL);
findModal().vm.$emit('close');
@@ -411,13 +413,11 @@ describe('InviteMembersModal', () => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- const mockEvent = { preventDefault: jest.fn() };
-
await triggerOpenModal(source);
expectTracking('render', label);
- findModal().vm.$emit('cancel', mockEvent);
+ clickCancelButton();
expectTracking('click_cancel', label);
findModal().vm.$emit('close');
@@ -734,7 +734,7 @@ describe('InviteMembersModal', () => {
expect(membersFormGroupInvalidFeedback()).toBe(expectedSyntaxError);
expect(findMembersSelect().props('exceptionState')).toBe(false);
- expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
+ expect(findActionButton().props('loading')).toBe(false);
});
it('clears the error when the modal is hidden', async () => {
@@ -746,7 +746,7 @@ describe('InviteMembersModal', () => {
expect(membersFormGroupInvalidFeedback()).toBe(expectedSyntaxError);
expect(findMembersSelect().props('exceptionState')).toBe(false);
- expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
+ expect(findActionButton().props('loading')).toBe(false);
findModal().vm.$emit('hidden');
@@ -768,7 +768,7 @@ describe('InviteMembersModal', () => {
expect(findMemberErrorAlert().text()).toContain(expectedEmailRestrictedError);
expect(membersFormGroupInvalidFeedback()).toBe('');
expect(findMembersSelect().props('exceptionState')).not.toBe(false);
- expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
+ expect(findActionButton().props('loading')).toBe(false);
});
it('displays all errors when there are multiple emails that return a restricted error message', async () => {
diff --git a/spec/frontend/invite_members/components/invite_members_trigger_spec.js b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
index c522abe63c5..cdb6182e2ae 100644
--- a/spec/frontend/invite_members/components/invite_members_trigger_spec.js
+++ b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
@@ -1,12 +1,14 @@
-import { GlButton, GlLink, GlIcon } from '@gitlab/ui';
+import { GlButton, GlLink, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import eventHub from '~/invite_members/event_hub';
import {
TRIGGER_ELEMENT_BUTTON,
- TRIGGER_ELEMENT_SIDE_NAV,
TRIGGER_DEFAULT_QA_SELECTOR,
+ TRIGGER_ELEMENT_WITH_EMOJI,
+ TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
} from '~/invite_members/constants';
+import { GlEmoji } from '../mock_data/member_modal';
jest.mock('~/experimentation/experiment_tracking');
@@ -19,7 +21,8 @@ let findButton;
const triggerComponent = {
button: GlButton,
anchor: GlLink,
- 'side-nav': GlLink,
+ 'text-emoji': GlLink,
+ 'dropdown-text-emoji': GlDropdownItem,
};
const createComponent = (props = {}) => {
@@ -29,6 +32,9 @@ const createComponent = (props = {}) => {
...triggerProps,
...props,
},
+ stubs: {
+ GlEmoji,
+ },
});
};
@@ -40,8 +46,8 @@ const triggerItems = [
triggerElement: 'anchor',
},
{
- triggerElement: TRIGGER_ELEMENT_SIDE_NAV,
- icon: 'plus',
+ triggerElement: TRIGGER_ELEMENT_WITH_EMOJI,
+ icon: 'shaking_hands',
},
];
@@ -50,10 +56,6 @@ describe.each(triggerItems)('with triggerElement as %s', (triggerItem) => {
findButton = () => wrapper.findComponent(triggerComponent[triggerItem.triggerElement]);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('configurable attributes', () => {
it('includes the correct displayText for the button', () => {
createComponent();
@@ -91,31 +93,26 @@ describe.each(triggerItems)('with triggerElement as %s', (triggerItem) => {
});
});
});
+});
- describe('tracking', () => {
- it('does not add tracking attributes', () => {
- createComponent();
-
- expect(findButton().attributes('data-track-action')).toBeUndefined();
- expect(findButton().attributes('data-track-label')).toBeUndefined();
- });
+describe('link with emoji', () => {
+ it('includes the specified icon with correct size when triggerElement is link', () => {
+ const findEmoji = () => wrapper.findComponent(GlEmoji);
- it('adds tracking attributes', () => {
- createComponent({ label: '_label_', event: '_event_' });
+ createComponent({ triggerElement: TRIGGER_ELEMENT_WITH_EMOJI, icon: 'shaking_hands' });
- expect(findButton().attributes('data-track-action')).toBe('_event_');
- expect(findButton().attributes('data-track-label')).toBe('_label_');
- });
+ expect(findEmoji().exists()).toBe(true);
+ expect(findEmoji().attributes('data-name')).toBe('shaking_hands');
});
});
-describe('side-nav with icon', () => {
+describe('dropdown item with emoji', () => {
it('includes the specified icon with correct size when triggerElement is link', () => {
- const findIcon = () => wrapper.findComponent(GlIcon);
+ const findEmoji = () => wrapper.findComponent(GlEmoji);
- createComponent({ triggerElement: TRIGGER_ELEMENT_SIDE_NAV, icon: 'plus' });
+ createComponent({ triggerElement: TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI, icon: 'shaking_hands' });
- expect(findIcon().exists()).toBe(true);
- expect(findIcon().props('name')).toBe('plus');
+ expect(findEmoji().exists()).toBe(true);
+ expect(findEmoji().attributes('data-name')).toBe('shaking_hands');
});
});
diff --git a/spec/frontend/invite_members/components/invite_modal_base_spec.js b/spec/frontend/invite_members/components/invite_modal_base_spec.js
index f34f9902514..e70c83a424e 100644
--- a/spec/frontend/invite_members/components/invite_modal_base_spec.js
+++ b/spec/frontend/invite_members/components/invite_modal_base_spec.js
@@ -54,10 +54,6 @@ describe('InviteModalBase', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findFormSelect = () => wrapper.findComponent(GlFormSelect);
const findFormSelectOptions = () => findFormSelect().findAllComponents('option');
const findDatepicker = () => wrapper.findComponent(GlDatepicker);
@@ -66,8 +62,8 @@ describe('InviteModalBase', () => {
const findIntroText = () => wrapper.findByTestId('modal-base-intro-text').text();
const findMembersFormGroup = () => wrapper.findByTestId('members-form-group');
const findDisabledInput = () => wrapper.findByTestId('disabled-input');
- const findCancelButton = () => wrapper.find('.js-modal-action-cancel');
- const findActionButton = () => wrapper.find('.js-modal-action-primary');
+ const findCancelButton = () => wrapper.findByTestId('invite-modal-cancel');
+ const findActionButton = () => wrapper.findByTestId('invite-modal-submit');
describe('rendering the modal', () => {
let trackingSpy;
@@ -88,20 +84,19 @@ describe('InviteModalBase', () => {
});
it('renders the Cancel button text correctly', () => {
- expect(wrapper.findComponent(GlModal).props('actionCancel')).toMatchObject({
- text: CANCEL_BUTTON_TEXT,
- });
+ expect(findCancelButton().text()).toBe(CANCEL_BUTTON_TEXT);
});
it('renders the Invite button correctly', () => {
- expect(wrapper.findComponent(GlModal).props('actionPrimary')).toMatchObject({
- text: INVITE_BUTTON_TEXT,
- attributes: {
- variant: 'confirm',
- disabled: false,
- loading: false,
- 'data-qa-selector': 'invite_button',
- },
+ const actionButton = findActionButton();
+
+ expect(actionButton.text()).toBe(INVITE_BUTTON_TEXT);
+ expect(actionButton.attributes('data-qa-selector')).toBe('invite_button');
+
+ expect(actionButton.props()).toMatchObject({
+ variant: 'confirm',
+ disabled: false,
+ loading: false,
});
});
@@ -235,7 +230,7 @@ describe('InviteModalBase', () => {
},
});
- expect(wrapper.findComponent(GlModal).props('actionPrimary').attributes.loading).toBe(true);
+ expect(findActionButton().props('loading')).toBe(true);
});
it('with invalidFeedbackMessage, set members form group exception state', () => {
diff --git a/spec/frontend/invite_members/components/members_token_select_spec.js b/spec/frontend/invite_members/components/members_token_select_spec.js
index 0455460918c..c7e9905dee3 100644
--- a/spec/frontend/invite_members/components/members_token_select_spec.js
+++ b/spec/frontend/invite_members/components/members_token_select_spec.js
@@ -30,11 +30,6 @@ const createComponent = (props) => {
describe('MembersTokenSelect', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findTokenSelector = () => wrapper.findComponent(GlTokenSelector);
describe('rendering the token-selector component', () => {
diff --git a/spec/frontend/invite_members/components/project_select_spec.js b/spec/frontend/invite_members/components/project_select_spec.js
index 6fbf95362fa..20db4f20408 100644
--- a/spec/frontend/invite_members/components/project_select_spec.js
+++ b/spec/frontend/invite_members/components/project_select_spec.js
@@ -23,10 +23,6 @@ describe('ProjectSelect', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlCollapsibleListbox = () => wrapper.findComponent(GlCollapsibleListbox);
const findAvatarLabeled = (index) => wrapper.findAllComponents(GlAvatarLabeled).at(index);
diff --git a/spec/frontend/invite_members/utils/trigger_successful_invite_alert_spec.js b/spec/frontend/invite_members/utils/trigger_successful_invite_alert_spec.js
index 38b16dd0c2c..fd011658f95 100644
--- a/spec/frontend/invite_members/utils/trigger_successful_invite_alert_spec.js
+++ b/spec/frontend/invite_members/utils/trigger_successful_invite_alert_spec.js
@@ -6,10 +6,10 @@ import {
TOAST_MESSAGE_LOCALSTORAGE_KEY,
TOAST_MESSAGE_SUCCESSFUL,
} from '~/invite_members/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-jest.mock('~/flash');
+jest.mock('~/alert');
useLocalStorageSpy();
describe('Display Successful Invitation Alert', () => {
diff --git a/spec/frontend/issuable/components/csv_export_modal_spec.js b/spec/frontend/issuable/components/csv_export_modal_spec.js
index f798f87b6b2..ccd53e64c4d 100644
--- a/spec/frontend/issuable/components/csv_export_modal_spec.js
+++ b/spec/frontend/issuable/components/csv_export_modal_spec.js
@@ -17,7 +17,7 @@ describe('CsvExportModal', () => {
...props,
},
provide: {
- issuableType: 'issues',
+ issuableType: 'issue',
...injectedProperties,
},
stubs: {
@@ -29,19 +29,15 @@ describe('CsvExportModal', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findModal = () => wrapper.findComponent(GlModal);
const findIcon = () => wrapper.findComponent(GlIcon);
describe('template', () => {
describe.each`
- issuableType | modalTitle
- ${'issues'} | ${'Export issues'}
- ${'merge-requests'} | ${'Export merge requests'}
- `('with the issuableType "$issuableType"', ({ issuableType, modalTitle }) => {
+ issuableType | modalTitle | dataTrackLabel
+ ${'issue'} | ${'Export issues'} | ${'export_issues_csv'}
+ ${'merge_request'} | ${'Export merge requests'} | ${'export_merge-requests_csv'}
+ `('with the issuableType "$issuableType"', ({ issuableType, modalTitle, dataTrackLabel }) => {
beforeEach(() => {
wrapper = createComponent({ injectedProperties: { issuableType } });
});
@@ -57,9 +53,9 @@ describe('CsvExportModal', () => {
href: 'export/csv/path',
variant: 'confirm',
'data-method': 'post',
- 'data-qa-selector': `export_${issuableType}_button`,
+ 'data-qa-selector': `export_issues_button`,
'data-track-action': 'click_button',
- 'data-track-label': `export_${issuableType}_csv`,
+ 'data-track-label': dataTrackLabel,
},
});
});
diff --git a/spec/frontend/issuable/components/csv_import_export_buttons_spec.js b/spec/frontend/issuable/components/csv_import_export_buttons_spec.js
index 118c12d968b..a861148abb6 100644
--- a/spec/frontend/issuable/components/csv_import_export_buttons_spec.js
+++ b/spec/frontend/issuable/components/csv_import_export_buttons_spec.js
@@ -16,7 +16,7 @@ describe('CsvImportExportButtons', () => {
glModalDirective = jest.fn();
return mountExtended(CsvImportExportButtons, {
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
glModal: {
bind(_, { value }) {
glModalDirective(value);
@@ -33,10 +33,6 @@ describe('CsvImportExportButtons', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findExportCsvButton = () => wrapper.findComponent(GlButton);
const findImportDropdown = () => wrapper.findComponent(GlDropdown);
const findImportCsvButton = () => wrapper.findByRole('menuitem', { name: 'Import CSV' });
diff --git a/spec/frontend/issuable/components/csv_import_modal_spec.js b/spec/frontend/issuable/components/csv_import_modal_spec.js
index 6e954c91f46..9069d2b3ab3 100644
--- a/spec/frontend/issuable/components/csv_import_modal_spec.js
+++ b/spec/frontend/issuable/components/csv_import_modal_spec.js
@@ -32,10 +32,6 @@ describe('CsvImportModal', () => {
formSubmitSpy = jest.spyOn(HTMLFormElement.prototype, 'submit').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findModal = () => wrapper.findComponent(GlModal);
const findForm = () => wrapper.find('form');
const findFileInput = () => wrapper.findByLabelText('Upload CSV file');
diff --git a/spec/frontend/issuable/components/issuable_by_email_spec.js b/spec/frontend/issuable/components/issuable_by_email_spec.js
index b04a6c0b8fd..4cc5775b54e 100644
--- a/spec/frontend/issuable/components/issuable_by_email_spec.js
+++ b/spec/frontend/issuable/components/issuable_by_email_spec.js
@@ -53,8 +53,6 @@ describe('IssuableByEmail', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
mockAxios.restore();
});
diff --git a/spec/frontend/issuable/components/issuable_header_warnings_spec.js b/spec/frontend/issuable/components/issuable_header_warnings_spec.js
index 99aa6778e1e..ff772040d22 100644
--- a/spec/frontend/issuable/components/issuable_header_warnings_spec.js
+++ b/spec/frontend/issuable/components/issuable_header_warnings_spec.js
@@ -25,16 +25,11 @@ describe('IssuableHeaderWarnings', () => {
store,
provide,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe.each`
issuableType
${ISSUABLE_TYPE_ISSUE} | ${ISSUABLE_TYPE_MR}
diff --git a/spec/frontend/issuable/components/issue_assignees_spec.js b/spec/frontend/issuable/components/issue_assignees_spec.js
index 9a33bfae240..8ed51120508 100644
--- a/spec/frontend/issuable/components/issue_assignees_spec.js
+++ b/spec/frontend/issuable/components/issue_assignees_spec.js
@@ -21,11 +21,6 @@ describe('IssueAssigneesComponent', () => {
vm = wrapper.vm;
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findTooltipText = () => wrapper.find('.js-assignee-tooltip').text();
const findAvatars = () => wrapper.findAllComponents(UserAvatarLink);
const findOverflowCounter = () => wrapper.find('.avatar-counter');
diff --git a/spec/frontend/issuable/components/issue_milestone_spec.js b/spec/frontend/issuable/components/issue_milestone_spec.js
index eac53c5f761..232d6177862 100644
--- a/spec/frontend/issuable/components/issue_milestone_spec.js
+++ b/spec/frontend/issuable/components/issue_milestone_spec.js
@@ -1,160 +1,61 @@
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltip } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-
import { mockMilestone } from 'jest/boards/mock_data';
import IssueMilestone from '~/issuable/components/issue_milestone.vue';
-const createComponent = (milestone = mockMilestone) => {
- const Component = Vue.extend(IssueMilestone);
-
- return shallowMount(Component, {
- propsData: {
- milestone,
- },
- });
-};
-
-describe('IssueMilestoneComponent', () => {
+describe('IssueMilestone component', () => {
let wrapper;
- let vm;
- beforeEach(async () => {
- wrapper = createComponent();
+ const findTooltip = () => wrapper.findComponent(GlTooltip);
- ({ vm } = wrapper);
+ const createComponent = (milestone = mockMilestone) =>
+ shallowMount(IssueMilestone, { propsData: { milestone } });
- await nextTick();
+ beforeEach(() => {
+ wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
+ it('renders milestone icon', () => {
+ expect(wrapper.findComponent(GlIcon).props('name')).toBe('clock');
});
- describe('computed', () => {
- describe('isMilestoneStarted', () => {
- it('should return `false` when milestoneStart prop is not defined', async () => {
- wrapper.setProps({
- milestone: { ...mockMilestone, start_date: '' },
- });
- await nextTick();
-
- expect(wrapper.vm.isMilestoneStarted).toBe(false);
- });
-
- it('should return `true` when milestone start date is past current date', async () => {
- await wrapper.setProps({
- milestone: { ...mockMilestone, start_date: '1990-07-22' },
- });
- await nextTick();
+ it('renders milestone title', () => {
+ expect(wrapper.find('.milestone-title').text()).toBe(mockMilestone.title);
+ });
- expect(wrapper.vm.isMilestoneStarted).toBe(true);
- });
+ describe('tooltip', () => {
+ it('renders `Milestone`', () => {
+ expect(findTooltip().text()).toContain('Milestone');
});
- describe('isMilestonePastDue', () => {
- it('should return `false` when milestoneDue prop is not defined', async () => {
- wrapper.setProps({
- milestone: { ...mockMilestone, due_date: '' },
- });
- await nextTick();
-
- expect(wrapper.vm.isMilestonePastDue).toBe(false);
- });
-
- it('should return `true` when milestone due is past current date', () => {
- wrapper.setProps({
- milestone: { ...mockMilestone, due_date: '1990-07-22' },
- });
-
- expect(wrapper.vm.isMilestonePastDue).toBe(true);
- });
+ it('renders milestone title', () => {
+ expect(findTooltip().text()).toContain(mockMilestone.title);
});
- describe('milestoneDatesAbsolute', () => {
- it('returns string containing absolute milestone due date', () => {
- expect(vm.milestoneDatesAbsolute).toBe('(December 31, 2019)');
- });
+ describe('humanized dates', () => {
+ it('renders `Expired` when there is a due date in the past', () => {
+ wrapper = createComponent({ ...mockMilestone, due_date: '2019-12-31', start_date: '' });
- it('returns string containing absolute milestone start date when due date is not present', async () => {
- wrapper.setProps({
- milestone: { ...mockMilestone, due_date: '' },
- });
- await nextTick();
-
- expect(wrapper.vm.milestoneDatesAbsolute).toBe('(January 1, 2018)');
+ expect(findTooltip().text()).toContain('Expired 6 months ago(December 31, 2019)');
});
- it('returns empty string when both milestone start and due dates are not present', async () => {
- wrapper.setProps({
- milestone: { ...mockMilestone, start_date: '', due_date: '' },
- });
- await nextTick();
+ it('renders `remaining` when there is a due date in the future', () => {
+ wrapper = createComponent({ ...mockMilestone, due_date: '2020-12-31', start_date: '' });
- expect(wrapper.vm.milestoneDatesAbsolute).toBe('');
+ expect(findTooltip().text()).toContain('5 months remaining(December 31, 2020)');
});
- });
- describe('milestoneDatesHuman', () => {
- it('returns string containing milestone due date when date is yet to be due', async () => {
- wrapper.setProps({
- milestone: { ...mockMilestone, due_date: `${new Date().getFullYear() + 10}-01-01` },
- });
- await nextTick();
+ it('renders `Started` when there is a start date in the past', () => {
+ wrapper = createComponent({ ...mockMilestone, due_date: '', start_date: '2019-12-31' });
- expect(wrapper.vm.milestoneDatesHuman).toContain('years remaining');
+ expect(findTooltip().text()).toContain('Started 6 months ago(December 31, 2019)');
});
- it('returns string containing milestone start date when date has already started and due date is not present', async () => {
- wrapper.setProps({
- milestone: { ...mockMilestone, start_date: '1990-07-22', due_date: '' },
- });
- await nextTick();
+ it('renders `Starts` when there is a start date in the future', () => {
+ wrapper = createComponent({ ...mockMilestone, due_date: '', start_date: '2020-12-31' });
- expect(wrapper.vm.milestoneDatesHuman).toContain('Started');
+ expect(findTooltip().text()).toContain('Starts in 5 months(December 31, 2020)');
});
-
- it('returns string containing milestone start date when date is yet to start and due date is not present', async () => {
- wrapper.setProps({
- milestone: {
- ...mockMilestone,
- start_date: `${new Date().getFullYear() + 10}-01-01`,
- due_date: '',
- },
- });
- await nextTick();
-
- expect(wrapper.vm.milestoneDatesHuman).toContain('Starts');
- });
-
- it('returns empty string when milestone start and due dates are not present', async () => {
- wrapper.setProps({
- milestone: { ...mockMilestone, start_date: '', due_date: '' },
- });
- await nextTick();
-
- expect(wrapper.vm.milestoneDatesHuman).toBe('');
- });
- });
- });
-
- describe('template', () => {
- it('renders component root element with class `issue-milestone-details`', () => {
- expect(vm.$el.classList.contains('issue-milestone-details')).toBe(true);
- });
-
- it('renders milestone icon', () => {
- expect(wrapper.findComponent(GlIcon).props('name')).toBe('clock');
- });
-
- it('renders milestone title', () => {
- expect(vm.$el.querySelector('.milestone-title').innerText.trim()).toBe(mockMilestone.title);
- });
-
- it('renders milestone tooltip', () => {
- expect(vm.$el.querySelector('.js-item-milestone').innerText.trim()).toContain(
- mockMilestone.title,
- );
});
});
});
diff --git a/spec/frontend/issuable/components/related_issuable_item_spec.js b/spec/frontend/issuable/components/related_issuable_item_spec.js
index 3f9f048605a..3e23558ceb4 100644
--- a/spec/frontend/issuable/components/related_issuable_item_spec.js
+++ b/spec/frontend/issuable/components/related_issuable_item_spec.js
@@ -53,10 +53,6 @@ describe('RelatedIssuableItem', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains issuable-info-container class when canReorder is false', () => {
mountComponent({ props: { canReorder: false } });
diff --git a/spec/frontend/issuable/components/status_box_spec.js b/spec/frontend/issuable/components/status_box_spec.js
index 728b8958b9b..d26f287d90c 100644
--- a/spec/frontend/issuable/components/status_box_spec.js
+++ b/spec/frontend/issuable/components/status_box_spec.js
@@ -11,11 +11,6 @@ function factory(propsData) {
describe('Merge request status box component', () => {
const findBadge = () => wrapper.findComponent(GlBadge);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe.each`
issuableType | badgeText | initialState | badgeClass | badgeVariant | badgeIcon
${'merge_request'} | ${'Open'} | ${'opened'} | ${'issuable-status-badge-open'} | ${'success'} | ${'merge-request-open'}
diff --git a/spec/frontend/issuable/popover/components/issue_popover_spec.js b/spec/frontend/issuable/popover/components/issue_popover_spec.js
index 444165f61c7..a7605016039 100644
--- a/spec/frontend/issuable/popover/components/issue_popover_spec.js
+++ b/spec/frontend/issuable/popover/components/issue_popover_spec.js
@@ -33,10 +33,6 @@ describe('Issue Popover', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows skeleton-loader while apollo is loading', () => {
mountComponent();
diff --git a/spec/frontend/issuable/popover/components/mr_popover_spec.js b/spec/frontend/issuable/popover/components/mr_popover_spec.js
index 5fdd1e6e8fc..d9e113eeaae 100644
--- a/spec/frontend/issuable/popover/components/mr_popover_spec.js
+++ b/spec/frontend/issuable/popover/components/mr_popover_spec.js
@@ -71,10 +71,6 @@ describe('MR Popover', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows skeleton-loader while apollo is loading', () => {
mountComponent();
diff --git a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
index 72fcab63ba7..f8e47bc0a4b 100644
--- a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
+++ b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
@@ -1,9 +1,9 @@
-import { GlFormGroup } from '@gitlab/ui';
+import { GlButton, GlFormGroup, GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
import AddIssuableForm from '~/related_issues/components/add_issuable_form.vue';
import IssueToken from '~/related_issues/components/issue_token.vue';
+import RelatedIssuableInput from '~/related_issues/components/related_issuable_input.vue';
import { linkedIssueTypesMap, PathIdSeparator } from '~/related_issues/constants';
const issuable1 = {
@@ -26,71 +26,60 @@ const issuable2 = {
const pathIdSeparator = PathIdSeparator.Issue;
-const findFormInput = (wrapper) => wrapper.find('input').element;
-
-const findRadioInput = (inputs, value) =>
- inputs.filter((input) => input.element.value === value)[0];
-
-const findRadioInputs = (wrapper) => wrapper.findAll('[name="linked-issue-type-radio"]');
-
-const constructWrapper = (props) => {
- return shallowMount(AddIssuableForm, {
- propsData: {
- inputValue: '',
- pendingReferences: [],
- pathIdSeparator,
- ...props,
- },
- });
-};
-
describe('AddIssuableForm', () => {
let wrapper;
- afterEach(() => {
- // Jest doesn't blur an item even if it is destroyed,
- // so blur the input manually after each test
- const input = findFormInput(wrapper);
- if (input) input.blur();
+ const createComponent = (props = {}, mountFn = shallowMount) => {
+ wrapper = mountFn(AddIssuableForm, {
+ propsData: {
+ inputValue: '',
+ pendingReferences: [],
+ pathIdSeparator,
+ ...props,
+ },
+ stubs: {
+ RelatedIssuableInput,
+ },
+ });
+ };
- if (wrapper) {
- wrapper.destroy();
- wrapper = null;
- }
- });
+ const findAddIssuableForm = () => wrapper.find('form');
+ const findFormInput = () => wrapper.find('input').element;
+ const findRadioInput = (inputs, value) =>
+ inputs.filter((input) => input.element.value === value)[0];
+ const findAllIssueTokens = () => wrapper.findAllComponents(IssueToken);
+ const findRadioGroup = () => wrapper.findComponent(GlFormRadioGroup);
+ const findRadioInputs = () => wrapper.findAllComponents(GlFormRadio);
+
+ const findFormGroup = () => wrapper.findComponent(GlFormGroup);
+ const findFormButtons = () => wrapper.findAllComponents(GlButton);
+ const findSubmitButton = () => findFormButtons().at(0);
+ const findRelatedIssuableInput = () => wrapper.findComponent(RelatedIssuableInput);
describe('with data', () => {
describe('without references', () => {
describe('without any input text', () => {
beforeEach(() => {
- wrapper = shallowMount(AddIssuableForm, {
- propsData: {
- inputValue: '',
- pendingReferences: [],
- pathIdSeparator,
- },
- });
+ createComponent();
});
it('should have disabled submit button', () => {
- expect(wrapper.vm.$refs.addButton.disabled).toBe(true);
- expect(wrapper.vm.$refs.loadingIcon).toBeUndefined();
+ expect(findSubmitButton().props('disabled')).toBe(true);
+ expect(findSubmitButton().props('loading')).toBe(false);
});
});
describe('with input text', () => {
beforeEach(() => {
- wrapper = shallowMount(AddIssuableForm, {
- propsData: {
- inputValue: 'foo',
- pendingReferences: [],
- pathIdSeparator,
- },
+ createComponent({
+ inputValue: 'foo',
+ pendingReferences: [],
+ pathIdSeparator,
});
});
it('should not have disabled submit button', () => {
- expect(wrapper.vm.$refs.addButton.disabled).toBe(false);
+ expect(findSubmitButton().props('disabled')).toBe(false);
});
});
});
@@ -99,59 +88,56 @@ describe('AddIssuableForm', () => {
const inputValue = 'foo #123';
beforeEach(() => {
- wrapper = mount(AddIssuableForm, {
- propsData: {
- inputValue,
- pendingReferences: [issuable1.reference, issuable2.reference],
- pathIdSeparator,
- },
+ createComponent({
+ inputValue,
+ pendingReferences: [issuable1.reference, issuable2.reference],
+ pathIdSeparator,
});
- });
+ }, mount);
it('should put input value in place', () => {
expect(findFormInput(wrapper).value).toBe(inputValue);
});
it('should render pending issuables items', () => {
- expect(wrapper.findAllComponents(IssueToken)).toHaveLength(2);
+ expect(findAllIssueTokens()).toHaveLength(2);
});
it('should not have disabled submit button', () => {
- expect(wrapper.vm.$refs.addButton.disabled).toBe(false);
+ expect(findSubmitButton().props('disabled')).toBe(false);
});
});
describe('when issuable type is "issue"', () => {
beforeEach(() => {
- wrapper = mount(AddIssuableForm, {
- propsData: {
+ createComponent(
+ {
inputValue: '',
issuableType: TYPE_ISSUE,
pathIdSeparator,
pendingReferences: [],
},
- });
+ mount,
+ );
});
it('does not show radio inputs', () => {
- expect(findRadioInputs(wrapper).length).toBe(0);
+ expect(findRadioInputs()).toHaveLength(0);
});
});
describe('when issuable type is "epic"', () => {
beforeEach(() => {
- wrapper = shallowMount(AddIssuableForm, {
- propsData: {
- inputValue: '',
- issuableType: TYPE_EPIC,
- pathIdSeparator,
- pendingReferences: [],
- },
+ createComponent({
+ inputValue: '',
+ issuableType: TYPE_EPIC,
+ pathIdSeparator,
+ pendingReferences: [],
});
});
it('does not show radio inputs', () => {
- expect(findRadioInputs(wrapper).length).toBe(0);
+ expect(findRadioInputs()).toHaveLength(0);
});
});
@@ -163,17 +149,15 @@ describe('AddIssuableForm', () => {
`(
'show header text as "$contextHeader" and footer text as "$contextFooter" issuableType is set to $issuableType',
({ issuableType, contextHeader, contextFooter }) => {
- wrapper = shallowMount(AddIssuableForm, {
- propsData: {
- issuableType,
- inputValue: '',
- showCategorizedIssues: true,
- pathIdSeparator,
- pendingReferences: [],
- },
+ createComponent({
+ issuableType,
+ inputValue: '',
+ showCategorizedIssues: true,
+ pathIdSeparator,
+ pendingReferences: [],
});
- expect(wrapper.findComponent(GlFormGroup).attributes('label')).toBe(contextHeader);
+ expect(findFormGroup().attributes('label')).toBe(contextHeader);
expect(wrapper.find('p.bold').text()).toContain(contextFooter);
},
);
@@ -181,26 +165,24 @@ describe('AddIssuableForm', () => {
describe('when it is a Linked Issues form', () => {
beforeEach(() => {
- wrapper = mount(AddIssuableForm, {
- propsData: {
- inputValue: '',
- showCategorizedIssues: true,
- issuableType: TYPE_ISSUE,
- pathIdSeparator,
- pendingReferences: [],
- },
+ createComponent({
+ inputValue: '',
+ showCategorizedIssues: true,
+ issuableType: TYPE_ISSUE,
+ pathIdSeparator,
+ pendingReferences: [],
});
});
it('shows radio inputs to allow categorisation of blocking issues', () => {
- expect(findRadioInputs(wrapper).length).toBeGreaterThan(0);
+ expect(findRadioGroup().props('options').length).toBeGreaterThan(0);
});
describe('form radio buttons', () => {
let radioInputs;
beforeEach(() => {
- radioInputs = findRadioInputs(wrapper);
+ radioInputs = findRadioInputs();
});
it('shows "relates to" option', () => {
@@ -216,58 +198,59 @@ describe('AddIssuableForm', () => {
});
it('shows 3 options in total', () => {
- expect(radioInputs.length).toBe(3);
+ expect(findRadioGroup().props('options')).toHaveLength(3);
});
});
describe('when the form is submitted', () => {
- it('emits an event with a "relates_to" link type when the "relates to" radio input selected', async () => {
- jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {});
-
- wrapper.vm.linkedIssueType = linkedIssueTypesMap.RELATES_TO;
- wrapper.vm.onFormSubmit();
-
- await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('addIssuableFormSubmit', {
- pendingReferences: '',
- linkedIssueType: linkedIssueTypesMap.RELATES_TO,
- });
+ it('emits an event with a "relates_to" link type when the "relates to" radio input selected', () => {
+ findAddIssuableForm().trigger('submit');
+
+ expect(wrapper.emitted('addIssuableFormSubmit')).toEqual([
+ [
+ {
+ pendingReferences: '',
+ linkedIssueType: linkedIssueTypesMap.RELATES_TO,
+ },
+ ],
+ ]);
});
- it('emits an event with a "blocks" link type when the "blocks" radio input selected', async () => {
- jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {});
-
- wrapper.vm.linkedIssueType = linkedIssueTypesMap.BLOCKS;
- wrapper.vm.onFormSubmit();
-
- await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('addIssuableFormSubmit', {
- pendingReferences: '',
- linkedIssueType: linkedIssueTypesMap.BLOCKS,
- });
+ it('emits an event with a "blocks" link type when the "blocks" radio input selected', () => {
+ findRadioGroup().vm.$emit('input', linkedIssueTypesMap.BLOCKS);
+ findAddIssuableForm().trigger('submit');
+
+ expect(wrapper.emitted('addIssuableFormSubmit')).toEqual([
+ [
+ {
+ pendingReferences: '',
+ linkedIssueType: linkedIssueTypesMap.BLOCKS,
+ },
+ ],
+ ]);
});
it('emits an event with a "is_blocked_by" link type when the "is blocked by" radio input selected', async () => {
- jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {});
-
- wrapper.vm.linkedIssueType = linkedIssueTypesMap.IS_BLOCKED_BY;
- wrapper.vm.onFormSubmit();
-
- await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('addIssuableFormSubmit', {
- pendingReferences: '',
- linkedIssueType: linkedIssueTypesMap.IS_BLOCKED_BY,
- });
+ findRadioGroup().vm.$emit('input', linkedIssueTypesMap.IS_BLOCKED_BY);
+ findAddIssuableForm().trigger('submit');
+
+ expect(wrapper.emitted('addIssuableFormSubmit')).toEqual([
+ [
+ {
+ pendingReferences: '',
+ linkedIssueType: linkedIssueTypesMap.IS_BLOCKED_BY,
+ },
+ ],
+ ]);
});
- it('shows error message when error is present', async () => {
+ it('shows error message when error is present', () => {
const itemAddFailureMessage = 'Something went wrong while submitting.';
- wrapper.setProps({
+ createComponent({
hasError: true,
itemAddFailureMessage,
});
- await nextTick();
expect(wrapper.find('.gl-field-error').exists()).toBe(true);
expect(wrapper.find('.gl-field-error').text()).toContain(itemAddFailureMessage);
});
@@ -283,27 +266,31 @@ describe('AddIssuableForm', () => {
};
it('returns autocomplete object', () => {
- wrapper = constructWrapper({
+ createComponent({
autoCompleteSources,
});
- expect(wrapper.vm.transformedAutocompleteSources).toBe(autoCompleteSources);
+ expect(findRelatedIssuableInput().props('autoCompleteSources')).toEqual(
+ autoCompleteSources,
+ );
- wrapper = constructWrapper({
+ createComponent({
autoCompleteSources,
confidential: false,
});
- expect(wrapper.vm.transformedAutocompleteSources).toBe(autoCompleteSources);
+ expect(findRelatedIssuableInput().props('autoCompleteSources')).toEqual(
+ autoCompleteSources,
+ );
});
it('returns autocomplete sources with query `confidential_only`, when it is confidential', () => {
- wrapper = constructWrapper({
+ createComponent({
autoCompleteSources,
confidential: true,
});
- const actualSources = wrapper.vm.transformedAutocompleteSources;
+ const actualSources = findRelatedIssuableInput().props('autoCompleteSources');
expect(actualSources.epics).toContain('?confidential_only=true');
expect(actualSources.issues).toContain('?confidential_only=true');
diff --git a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js
index ff8d5073005..b9580b90c12 100644
--- a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js
+++ b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js
@@ -1,5 +1,5 @@
import { nextTick } from 'vue';
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlCard } from '@gitlab/ui';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import {
issuable1,
@@ -78,6 +78,9 @@ describe('RelatedIssuesBlock', () => {
pathIdSeparator: PathIdSeparator.Issue,
issuableType: 'issue',
},
+ stubs: {
+ GlCard,
+ },
slots: { 'header-text': headerText },
});
@@ -94,6 +97,9 @@ describe('RelatedIssuesBlock', () => {
pathIdSeparator: PathIdSeparator.Issue,
issuableType: 'issue',
},
+ stubs: {
+ GlCard,
+ },
slots: { 'header-actions': headerActions },
});
@@ -222,6 +228,9 @@ describe('RelatedIssuesBlock', () => {
pathIdSeparator: PathIdSeparator.Issue,
issuableType,
},
+ stubs: {
+ GlCard,
+ },
});
const iconComponent = wrapper.findComponent(GlIcon);
@@ -239,6 +248,9 @@ describe('RelatedIssuesBlock', () => {
relatedIssues: [issuable1, issuable2, issuable3],
issuableType: TYPE_ISSUE,
},
+ stubs: {
+ GlCard,
+ },
});
});
diff --git a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
index 96c0b87e2cb..1383013aedb 100644
--- a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
+++ b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
@@ -7,7 +7,7 @@ import {
issuable1,
issuable2,
} from 'jest/issuable/components/related_issuable_mock_data';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import {
HTTP_STATUS_CONFLICT,
@@ -19,7 +19,7 @@ import RelatedIssuesBlock from '~/related_issues/components/related_issues_block
import RelatedIssuesRoot from '~/related_issues/components/related_issues_root.vue';
import relatedIssuesService from '~/related_issues/services/related_issues_service';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('RelatedIssuesRoot', () => {
let wrapper;
@@ -34,7 +34,6 @@ describe('RelatedIssuesRoot', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
const createComponent = ({ props = {}, data = {} } = {}) => {
diff --git a/spec/frontend/issues/create_merge_request_dropdown_spec.js b/spec/frontend/issues/create_merge_request_dropdown_spec.js
index cc2ee84348a..21ae844e2dd 100644
--- a/spec/frontend/issues/create_merge_request_dropdown_spec.js
+++ b/spec/frontend/issues/create_merge_request_dropdown_spec.js
@@ -65,6 +65,14 @@ describe('CreateMergeRequestDropdown', () => {
expect(dropdown.createMrPath).toBe(
`${TEST_HOST}/create_merge_request?merge_request%5Bsource_branch%5D=contains%23hash&merge_request%5Btarget_branch%5D=master&merge_request%5Bissue_iid%5D=42`,
);
+
+ expect(dropdown.wrapperEl.dataset.createBranchPath).toBe(
+ `${TEST_HOST}/branches?branch_name=contains%23hash&issue=42`,
+ );
+
+ expect(dropdown.wrapperEl.dataset.createMrPath).toBe(
+ `${TEST_HOST}/create_merge_request?merge_request%5Bsource_branch%5D=contains%23hash&merge_request%5Btarget_branch%5D=master&merge_request%5Bissue_iid%5D=42`,
+ );
});
});
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 77d5a0579a4..ebf4771e97f 100644
--- a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
+++ b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
@@ -18,6 +18,7 @@ import {
setSortPreferenceMutationResponse,
setSortPreferenceMutationResponseWithErrors,
} from 'jest/issues/list/mock_data';
+import { STATUS_ALL, STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import IssuesDashboardApp from '~/issues/dashboard/components/issues_dashboard_app.vue';
import getIssuesCountsQuery from '~/issues/dashboard/queries/get_issues_counts.query.graphql';
import { CREATED_DESC, i18n, UPDATED_DESC, urlSortParams } from '~/issues/list/constants';
@@ -36,7 +37,6 @@ import {
TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { IssuableStates } from '~/vue_shared/issuable/list/constants';
import {
emptyIssuesQueryResponse,
issuesCountsQueryResponse,
@@ -124,7 +124,7 @@ describe('IssuesDashboardApp component', () => {
// eslint-disable-next-line jest/no-disabled-tests
it.skip('renders IssuableList component', () => {
expect(findIssuableList().props()).toMatchObject({
- currentTab: IssuableStates.Opened,
+ currentTab: STATUS_OPEN,
hasNextPage: true,
hasPreviousPage: false,
hasScopedLabelsFeature: defaultProvide.hasScopedLabelsFeature,
@@ -148,7 +148,7 @@ describe('IssuesDashboardApp component', () => {
tabs: IssuesDashboardApp.IssuableListTabs,
urlParams: {
sort: urlSortParams[CREATED_DESC],
- state: IssuableStates.Opened,
+ state: STATUS_OPEN,
},
useKeysetPagination: true,
});
@@ -283,7 +283,7 @@ describe('IssuesDashboardApp component', () => {
describe('state', () => {
it('is set from the url params', () => {
- const initialState = IssuableStates.All;
+ const initialState = STATUS_ALL;
setWindowLocation(`?state=${initialState}`);
mountComponent();
@@ -337,11 +337,9 @@ describe('IssuesDashboardApp component', () => {
username: 'root',
avatar_url: 'avatar/url',
};
- const originalGon = window.gon;
beforeEach(() => {
window.gon = {
- ...originalGon,
current_user_id: mockCurrentUser.id,
current_user_fullname: mockCurrentUser.name,
current_username: mockCurrentUser.username,
@@ -350,10 +348,6 @@ describe('IssuesDashboardApp component', () => {
mountComponent();
});
- afterEach(() => {
- window.gon = originalGon;
- });
-
it('renders all tokens alphabetically', () => {
const preloadedUsers = [{ ...mockCurrentUser, id: mockCurrentUser.id }];
@@ -375,16 +369,16 @@ describe('IssuesDashboardApp component', () => {
beforeEach(() => {
mountComponent();
- findIssuableList().vm.$emit('click-tab', IssuableStates.Closed);
+ findIssuableList().vm.$emit('click-tab', STATUS_CLOSED);
});
it('updates ui to the new tab', () => {
- expect(findIssuableList().props('currentTab')).toBe(IssuableStates.Closed);
+ expect(findIssuableList().props('currentTab')).toBe(STATUS_CLOSED);
});
it('updates url to the new tab', () => {
expect(findIssuableList().props('urlParams')).toMatchObject({
- state: IssuableStates.Closed,
+ state: STATUS_CLOSED,
});
});
});
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 ab4d023ee39..e80ffea0591 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
@@ -45,10 +45,6 @@ describe('CE IssueCardTimeInfo component', () => {
},
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('milestone', () => {
it('renders', () => {
wrapper = mountComponent();
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 8281ce0ed1a..b28a08e2fce 100644
--- a/spec/frontend/issues/list/components/issues_list_app_spec.js
+++ b/spec/frontend/issues/list/components/issues_list_app_spec.js
@@ -15,19 +15,21 @@ import waitForPromises from 'helpers/wait_for_promises';
import {
getIssuesCountsQueryResponse,
getIssuesQueryResponse,
+ getIssuesQueryEmptyResponse,
filteredTokens,
locationSearch,
setSortPreferenceMutationResponse,
setSortPreferenceMutationResponseWithErrors,
urlParams,
} from 'jest/issues/list/mock_data';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import { TYPENAME_USER } from '~/graphql_shared/constants';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { STATUS_ALL, STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
import IssuableByEmail from '~/issuable/components/issuable_by_email.vue';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/constants';
+import { IssuableListTabs } from '~/vue_shared/issuable/list/constants';
import EmptyStateWithAnyIssues from '~/issues/list/components/empty_state_with_any_issues.vue';
import EmptyStateWithoutAnyIssues from '~/issues/list/components/empty_state_without_any_issues.vue';
import IssuesListApp from '~/issues/list/components/issues_list_app.vue';
@@ -70,7 +72,7 @@ import('~/issuable');
import('~/users_select');
jest.mock('@sentry/browser');
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/scroll_utils', () => ({ scrollUp: jest.fn() }));
describe('CE IssuesListApp component', () => {
@@ -154,7 +156,24 @@ describe('CE IssuesListApp component', () => {
router = new VueRouter({ mode: 'history' });
return mountFn(IssuesListApp, {
- apolloProvider: createMockApollo(requestHandlers),
+ apolloProvider: createMockApollo(
+ requestHandlers,
+ {},
+ {
+ typePolicies: {
+ Query: {
+ fields: {
+ project: {
+ merge: true,
+ },
+ group: {
+ merge: true,
+ },
+ },
+ },
+ },
+ },
+ ),
router,
provide: {
...defaultProvide,
@@ -174,13 +193,11 @@ describe('CE IssuesListApp component', () => {
afterEach(() => {
axiosMock.reset();
- wrapper.destroy();
});
describe('IssuableList', () => {
beforeEach(() => {
wrapper = mountComponent();
- jest.runOnlyPendingTimers();
return waitForPromises();
});
@@ -197,7 +214,7 @@ describe('CE IssuesListApp component', () => {
initialSortBy: CREATED_DESC,
issuables: getIssuesQueryResponse.data.project.issues.nodes,
tabs: IssuableListTabs,
- currentTab: IssuableStates.Opened,
+ currentTab: STATUS_OPEN,
tabCounts: {
opened: 1,
closed: 1,
@@ -247,7 +264,6 @@ describe('CE IssuesListApp component', () => {
mountFn: mount,
});
- jest.runOnlyPendingTimers();
return waitForPromises();
});
@@ -416,7 +432,7 @@ describe('CE IssuesListApp component', () => {
describe('state', () => {
it('is set from the url params', () => {
- const initialState = IssuableStates.All;
+ const initialState = STATUS_ALL;
setWindowLocation(`?state=${initialState}`);
wrapper = mountComponent();
@@ -477,7 +493,12 @@ describe('CE IssuesListApp component', () => {
describe('empty states', () => {
describe('when there are issues', () => {
beforeEach(() => {
- wrapper = mountComponent({ provide: { hasAnyIssues: true }, mountFn: mount });
+ wrapper = mountComponent({
+ provide: { hasAnyIssues: true },
+ mountFn: mount,
+ issuesQueryResponse: getIssuesQueryEmptyResponse,
+ });
+ return waitForPromises();
});
it('shows EmptyStateWithAnyIssues empty state', () => {
@@ -543,11 +564,8 @@ describe('CE IssuesListApp component', () => {
});
describe('when all tokens are available', () => {
- const originalGon = window.gon;
-
beforeEach(() => {
window.gon = {
- ...originalGon,
current_user_id: mockCurrentUser.id,
current_user_fullname: mockCurrentUser.name,
current_username: mockCurrentUser.username,
@@ -563,10 +581,6 @@ describe('CE IssuesListApp component', () => {
});
});
- afterEach(() => {
- window.gon = originalGon;
- });
-
it('renders all tokens alphabetically', () => {
const preloadedUsers = [
{ ...mockCurrentUser, id: convertToGraphQLId(TYPENAME_USER, mockCurrentUser.id) },
@@ -599,7 +613,6 @@ describe('CE IssuesListApp component', () => {
wrapper = mountComponent({
[mountOption]: jest.fn().mockRejectedValue(new Error('ERROR')),
});
- jest.runOnlyPendingTimers();
return waitForPromises();
});
@@ -620,20 +633,21 @@ describe('CE IssuesListApp component', () => {
describe('events', () => {
describe('when "click-tab" event is emitted by IssuableList', () => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = mountComponent();
+ await waitForPromises();
router.push = jest.fn();
- findIssuableList().vm.$emit('click-tab', IssuableStates.Closed);
+ findIssuableList().vm.$emit('click-tab', STATUS_CLOSED);
});
it('updates ui to the new tab', () => {
- expect(findIssuableList().props('currentTab')).toBe(IssuableStates.Closed);
+ expect(findIssuableList().props('currentTab')).toBe(STATUS_CLOSED);
});
it('updates url to the new tab', () => {
expect(router.push).toHaveBeenCalledWith({
- query: expect.objectContaining({ state: IssuableStates.Closed }),
+ query: expect.objectContaining({ state: STATUS_CLOSED }),
});
});
});
@@ -641,19 +655,25 @@ describe('CE IssuesListApp component', () => {
describe.each`
event | params
${'next-page'} | ${{
- page_after: 'endCursor',
+ page_after: 'endcursor',
page_before: undefined,
first_page_size: 20,
last_page_size: undefined,
+ search: undefined,
+ sort: 'created_date',
+ state: 'opened',
}}
${'previous-page'} | ${{
page_after: undefined,
- page_before: 'startCursor',
+ page_before: 'startcursor',
first_page_size: undefined,
last_page_size: 20,
+ search: undefined,
+ sort: 'created_date',
+ state: 'opened',
}}
`('when "$event" event is emitted by IssuableList', ({ event, params }) => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = mountComponent({
data: {
pageInfo: {
@@ -662,6 +682,7 @@ describe('CE IssuesListApp component', () => {
},
},
});
+ await waitForPromises();
router.push = jest.fn();
findIssuableList().vm.$emit(event);
@@ -735,7 +756,6 @@ describe('CE IssuesListApp component', () => {
provide: { isProject },
issuesQueryResponse: jest.fn().mockResolvedValue(response(isProject)),
});
- jest.runOnlyPendingTimers();
return waitForPromises();
});
@@ -761,7 +781,6 @@ describe('CE IssuesListApp component', () => {
wrapper = mountComponent({
issuesQueryResponse: jest.fn().mockResolvedValue(response()),
});
- jest.runOnlyPendingTimers();
return waitForPromises();
});
@@ -793,8 +812,6 @@ describe('CE IssuesListApp component', () => {
router.push = jest.fn();
findIssuableList().vm.$emit('sort', sortKey);
- jest.runOnlyPendingTimers();
- await nextTick();
expect(router.push).toHaveBeenCalledWith({
query: expect.objectContaining({ sort: urlSortParams[sortKey] }),
@@ -914,13 +931,13 @@ describe('CE IssuesListApp component', () => {
${'shows users when public visibility is not restricted and is signed in'} | ${false} | ${true} | ${false}
${'hides users when public visibility is restricted and is not signed in'} | ${true} | ${false} | ${true}
${'shows users when public visibility is restricted and is signed in'} | ${true} | ${true} | ${false}
- `('$description', ({ isPublicVisibilityRestricted, isSignedIn, hideUsers }) => {
+ `('$description', async ({ isPublicVisibilityRestricted, isSignedIn, hideUsers }) => {
const mockQuery = jest.fn().mockResolvedValue(defaultQueryResponse);
wrapper = mountComponent({
provide: { isPublicVisibilityRestricted, isSignedIn },
issuesQueryResponse: mockQuery,
});
- jest.runOnlyPendingTimers();
+ await waitForPromises();
expect(mockQuery).toHaveBeenCalledWith(expect.objectContaining({ hideUsers }));
});
@@ -929,7 +946,6 @@ describe('CE IssuesListApp component', () => {
describe('fetching issues', () => {
beforeEach(() => {
wrapper = mountComponent();
- jest.runOnlyPendingTimers();
});
it('fetches issue, incident, test case, and task types', () => {
diff --git a/spec/frontend/issues/list/components/jira_issues_import_status_app_spec.js b/spec/frontend/issues/list/components/jira_issues_import_status_app_spec.js
index 406b1fbc1af..7bbb5a954ae 100644
--- a/spec/frontend/issues/list/components/jira_issues_import_status_app_spec.js
+++ b/spec/frontend/issues/list/components/jira_issues_import_status_app_spec.js
@@ -38,11 +38,6 @@ describe('JiraIssuesImportStatus', () => {
},
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when Jira import is neither in progress nor finished', () => {
beforeEach(() => {
wrapper = mountComponent();
diff --git a/spec/frontend/issues/list/mock_data.js b/spec/frontend/issues/list/mock_data.js
index 1e8a81116f3..0332f68ddb6 100644
--- a/spec/frontend/issues/list/mock_data.js
+++ b/spec/frontend/issues/list/mock_data.js
@@ -101,6 +101,26 @@ export const getIssuesQueryResponse = {
},
};
+export const getIssuesQueryEmptyResponse = {
+ data: {
+ project: {
+ id: '1',
+ __typename: 'Project',
+ issues: {
+ __persist: true,
+ pageInfo: {
+ __typename: 'PageInfo',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'startcursor',
+ endCursor: 'endcursor',
+ },
+ nodes: [],
+ },
+ },
+ },
+};
+
export const getIssuesCountsQueryResponse = {
data: {
project: {
diff --git a/spec/frontend/issues/list/utils_spec.js b/spec/frontend/issues/list/utils_spec.js
index a281ed1c989..e4ecdc6c29e 100644
--- a/spec/frontend/issues/list/utils_spec.js
+++ b/spec/frontend/issues/list/utils_spec.js
@@ -10,7 +10,7 @@ import {
urlParams,
urlParamsWithSpecialValues,
} from 'jest/issues/list/mock_data';
-import { PAGE_SIZE, urlSortParams } from '~/issues/list/constants';
+import { urlSortParams } from '~/issues/list/constants';
import {
convertToApiParams,
convertToSearchQuery,
@@ -22,10 +22,11 @@ import {
isSortKey,
} from '~/issues/list/utils';
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
+import { DEFAULT_PAGE_SIZE } from '~/vue_shared/issuable/list/constants';
describe('getInitialPageParams', () => {
it('returns page params with a default page size when no arguments are given', () => {
- expect(getInitialPageParams()).toEqual({ firstPageSize: PAGE_SIZE });
+ expect(getInitialPageParams()).toEqual({ firstPageSize: DEFAULT_PAGE_SIZE });
});
it('returns page params with the given page size', () => {
diff --git a/spec/frontend/issues/new/components/title_suggestions_item_spec.js b/spec/frontend/issues/new/components/title_suggestions_item_spec.js
index c54a762440f..4454ef81416 100644
--- a/spec/frontend/issues/new/components/title_suggestions_item_spec.js
+++ b/spec/frontend/issues/new/components/title_suggestions_item_spec.js
@@ -25,10 +25,6 @@ describe('Issue title suggestions item component', () => {
const findTooltip = () => wrapper.findComponent(GlTooltip);
const findUserAvatar = () => wrapper.findComponent(UserAvatarImage);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders title', () => {
createComponent();
diff --git a/spec/frontend/issues/new/components/title_suggestions_spec.js b/spec/frontend/issues/new/components/title_suggestions_spec.js
index 1cd6576967a..343bdbba301 100644
--- a/spec/frontend/issues/new/components/title_suggestions_spec.js
+++ b/spec/frontend/issues/new/components/title_suggestions_spec.js
@@ -1,106 +1,95 @@
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import TitleSuggestions from '~/issues/new/components/title_suggestions.vue';
import TitleSuggestionsItem from '~/issues/new/components/title_suggestions_item.vue';
+import getIssueSuggestionsQuery from '~/issues/new/queries/issues.query.graphql';
+import { mockIssueSuggestionResponse } from '../mock_data';
+
+Vue.use(VueApollo);
+
+const MOCK_PROJECT_PATH = 'project';
+const MOCK_ISSUES_COUNT = mockIssueSuggestionResponse.data.project.issues.edges.length;
describe('Issue title suggestions component', () => {
let wrapper;
+ let mockApollo;
+
+ function createComponent({
+ search = 'search',
+ queryResponse = jest.fn().mockResolvedValue(mockIssueSuggestionResponse),
+ } = {}) {
+ mockApollo = createMockApollo([[getIssueSuggestionsQuery, queryResponse]]);
- function createComponent(search = 'search') {
wrapper = shallowMount(TitleSuggestions, {
propsData: {
search,
- projectPath: 'project',
+ projectPath: MOCK_PROJECT_PATH,
},
+ apolloProvider: mockApollo,
});
}
- beforeEach(() => {
- createComponent();
- });
+ const waitForDebounce = () => {
+ jest.runOnlyPendingTimers();
+ return waitForPromises();
+ };
afterEach(() => {
- wrapper.destroy();
+ mockApollo = null;
});
it('does not render with empty search', async () => {
- wrapper.setProps({ search: '' });
+ createComponent({ search: '' });
+ await waitForDebounce();
- await nextTick();
expect(wrapper.isVisible()).toBe(false);
});
- describe('with data', () => {
- let data;
-
- beforeEach(() => {
- data = { issues: [{ id: 1 }, { id: 2 }] };
- });
-
- it('renders component', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
-
- await nextTick();
- expect(wrapper.findAll('li').length).toBe(data.issues.length);
- });
+ it('does not render when loading', () => {
+ createComponent();
+ expect(wrapper.isVisible()).toBe(false);
+ });
- it('does not render with empty search', async () => {
- wrapper.setProps({ search: '' });
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
+ it('does not render with empty issues data', async () => {
+ const emptyIssuesResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/1',
+ issues: {
+ edges: [],
+ },
+ },
+ },
+ };
- await nextTick();
- expect(wrapper.isVisible()).toBe(false);
- });
+ createComponent({ queryResponse: jest.fn().mockResolvedValue(emptyIssuesResponse) });
+ await waitForDebounce();
- it('does not render when loading', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- ...data,
- loading: 1,
- });
+ expect(wrapper.isVisible()).toBe(false);
+ });
- await nextTick();
- expect(wrapper.isVisible()).toBe(false);
+ describe('with data', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForDebounce();
});
- it('does not render with empty issues data', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ issues: [] });
-
- await nextTick();
- expect(wrapper.isVisible()).toBe(false);
+ it('renders component', () => {
+ expect(wrapper.findAll('li').length).toBe(MOCK_ISSUES_COUNT);
});
- it('renders list of issues', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
-
- await nextTick();
- expect(wrapper.findAllComponents(TitleSuggestionsItem).length).toBe(2);
+ it('renders list of issues', () => {
+ expect(wrapper.findAllComponents(TitleSuggestionsItem).length).toBe(MOCK_ISSUES_COUNT);
});
- it('adds margin class to first item', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
-
- await nextTick();
+ it('adds margin class to first item', () => {
expect(wrapper.findAll('li').at(0).classes()).toContain('gl-mb-3');
});
- it('does not add margin class to last item', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
-
- await nextTick();
+ it('does not add margin class to last item', () => {
expect(wrapper.findAll('li').at(1).classes()).not.toContain('gl-mb-3');
});
});
diff --git a/spec/frontend/issues/new/components/type_popover_spec.js b/spec/frontend/issues/new/components/type_popover_spec.js
index fe3d5207516..1ae150797c3 100644
--- a/spec/frontend/issues/new/components/type_popover_spec.js
+++ b/spec/frontend/issues/new/components/type_popover_spec.js
@@ -8,10 +8,6 @@ describe('Issue type info popover', () => {
wrapper = shallowMount(TypePopover);
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders', () => {
createComponent();
diff --git a/spec/frontend/issues/new/mock_data.js b/spec/frontend/issues/new/mock_data.js
index 74b569d9833..0d2a388cd86 100644
--- a/spec/frontend/issues/new/mock_data.js
+++ b/spec/frontend/issues/new/mock_data.js
@@ -26,3 +26,67 @@ export default () => ({
webUrl: `${TEST_HOST}/author`,
},
});
+
+export const mockIssueSuggestionResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/278964',
+ issues: {
+ edges: [
+ {
+ node: {
+ id: 'gid://gitlab/Issue/123725957',
+ iid: '696',
+ title: 'Remove unused MR widget extension expand success, failed, warning events',
+ confidential: false,
+ userNotesCount: 16,
+ upvotes: 0,
+ webUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/696',
+ state: 'opened',
+ closedAt: null,
+ createdAt: '2023-02-15T12:29:59Z',
+ updatedAt: '2023-03-01T19:38:22Z',
+ author: {
+ id: 'gid://gitlab/User/325',
+ name: 'User Name',
+ username: 'user-name',
+ avatarUrl: '/uploads/-/system/user/avatar/325/avatar.png',
+ webUrl: 'https://gitlab.com/user-name',
+ __typename: 'UserCore',
+ },
+ __typename: 'Issue',
+ },
+ __typename: 'IssueEdge',
+ },
+ {
+ node: {
+ id: 'gid://gitlab/Issue/123',
+ iid: '391',
+ title: 'Remove unused MR widget extension expand success, failed, warning events',
+ confidential: false,
+ userNotesCount: 16,
+ upvotes: 0,
+ webUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391',
+ state: 'opened',
+ closedAt: null,
+ createdAt: '2023-02-15T12:29:59Z',
+ updatedAt: '2023-03-01T19:38:22Z',
+ author: {
+ id: 'gid://gitlab/User/2080',
+ name: 'User Name',
+ username: 'user-name',
+ avatarUrl: '/uploads/-/system/user/avatar/2080/avatar.png',
+ webUrl: 'https://gitlab.com/user-name',
+ __typename: 'UserCore',
+ },
+ __typename: 'Issue',
+ },
+ __typename: 'IssueEdge',
+ },
+ ],
+ __typename: 'IssueConnection',
+ },
+ __typename: 'Project',
+ },
+ },
+};
diff --git a/spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js b/spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js
index 010c719bd84..c5507c88fd7 100644
--- a/spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js
+++ b/spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js
@@ -34,7 +34,6 @@ describe('RelatedMergeRequests', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/issues/related_merge_requests/store/actions_spec.js b/spec/frontend/issues/related_merge_requests/store/actions_spec.js
index 7339372a8d1..31c96265f8d 100644
--- a/spec/frontend/issues/related_merge_requests/store/actions_spec.js
+++ b/spec/frontend/issues/related_merge_requests/store/actions_spec.js
@@ -1,12 +1,12 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import * as actions from '~/issues/related_merge_requests/store/actions';
import * as types from '~/issues/related_merge_requests/store/mutation_types';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('RelatedMergeRequest store actions', () => {
let state;
diff --git a/spec/frontend/issues/show/components/app_spec.js b/spec/frontend/issues/show/components/app_spec.js
index 9fa0ce6f93d..1006f54eeaf 100644
--- a/spec/frontend/issues/show/components/app_spec.js
+++ b/spec/frontend/issues/show/components/app_spec.js
@@ -1,11 +1,10 @@
import { GlIcon, GlIntersectionObserver } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import { setHTMLFixture } from 'helpers/fixtures';
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 '~/flash';
+import { createAlert } from '~/alert';
import {
IssuableStatusText,
STATUS_CLOSED,
@@ -21,29 +20,27 @@ import FormComponent from '~/issues/show/components/form.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';
-import { POLLING_DELAY } from '~/issues/show/constants';
import eventHub from '~/issues/show/event_hub';
import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import { HTTP_STATUS_OK, HTTP_STATUS_UNAUTHORIZED } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
import {
appProps,
initialRequest,
publishedIncidentUrl,
+ putRequest,
secondRequest,
zoomMeetingUrl,
} from '../mock_data/mock_data';
-jest.mock('~/flash');
-jest.mock('~/issues/show/event_hub');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
jest.mock('~/behaviors/markdown/render_gfm');
const REALTIME_REQUEST_STACK = [initialRequest, secondRequest];
describe('Issuable output', () => {
- let mock;
- let realtimeRequestCount = 0;
+ let axiosMock;
let wrapper;
const findStickyHeader = () => wrapper.findByTestId('issue-sticky-header');
@@ -57,15 +54,14 @@ describe('Issuable output', () => {
const findForm = () => wrapper.findComponent(FormComponent);
const findPinnedLinks = () => wrapper.findComponent(PinnedLinks);
- const mountComponent = (props = {}, options = {}, data = {}) => {
+ const createComponent = ({ props = {}, options = {}, data = {} } = {}) => {
wrapper = shallowMountExtended(IssuableApp, {
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: { ...appProps, ...props },
provide: {
fullPath: 'gitlab-org/incidents',
- iid: '19',
uploadMetricsFeatureAvailable: false,
},
stubs: {
@@ -79,6 +75,28 @@ describe('Issuable output', () => {
},
...options,
});
+
+ jest.advanceTimersToNextTimer(2);
+ return waitForPromises();
+ };
+
+ const emitHubEvent = (event) => {
+ eventHub.$emit(event);
+ return waitForPromises();
+ };
+
+ const openForm = () => {
+ return emitHubEvent('open.form');
+ };
+
+ const updateIssuable = () => {
+ return emitHubEvent('update.issuable');
+ };
+
+ const advanceToNextPoll = () => {
+ // We get new data through the HTTP request.
+ jest.advanceTimersToNextTimer();
+ return waitForPromises();
};
beforeEach(() => {
@@ -98,79 +116,100 @@ describe('Issuable output', () => {
</div>
`);
- mock = new MockAdapter(axios);
- mock
- .onGet('/gitlab-org/gitlab-shell/-/issues/9/realtime_changes/realtime_changes')
- .reply(() => {
- const res = Promise.resolve([HTTP_STATUS_OK, REALTIME_REQUEST_STACK[realtimeRequestCount]]);
- realtimeRequestCount += 1;
- return res;
- });
+ jest.spyOn(eventHub, '$emit');
- mountComponent();
+ axiosMock = new MockAdapter(axios);
+ const endpoint = '/gitlab-org/gitlab-shell/-/issues/9/realtime_changes/realtime_changes';
- jest.advanceTimersByTime(2);
+ axiosMock.onGet(endpoint).replyOnce(HTTP_STATUS_OK, REALTIME_REQUEST_STACK[0], {
+ 'POLL-INTERVAL': '1',
+ });
+ axiosMock.onGet(endpoint).reply(HTTP_STATUS_OK, REALTIME_REQUEST_STACK[1], {
+ 'POLL-INTERVAL': '-1',
+ });
+ axiosMock.onPut().reply(HTTP_STATUS_OK, putRequest);
});
- afterEach(() => {
- mock.restore();
- realtimeRequestCount = 0;
- wrapper.vm.poll.stop();
- wrapper.destroy();
- resetHTMLFixture();
- });
+ describe('update', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
- it('should render a title/description/edited and update title/description/edited on update', () => {
- return axios
- .waitForAll()
- .then(() => {
- expect(findTitle().props('titleText')).toContain('this is a title');
- expect(findDescription().props('descriptionText')).toContain('this is a description');
-
- expect(findEdited().exists()).toBe(true);
- expect(findEdited().props('updatedByPath')).toMatch(/\/some_user$/);
- expect(findEdited().props('updatedAt')).toBe(initialRequest.updated_at);
- expect(wrapper.vm.state.lock_version).toBe(initialRequest.lock_version);
- })
- .then(() => {
- wrapper.vm.poll.makeRequest();
- return axios.waitForAll();
- })
- .then(() => {
- expect(findTitle().props('titleText')).toContain('2');
- expect(findDescription().props('descriptionText')).toContain('42');
-
- expect(findEdited().exists()).toBe(true);
- expect(findEdited().props('updatedByName')).toBe('Other User');
- expect(findEdited().props('updatedByPath')).toMatch(/\/other_user$/);
- expect(findEdited().props('updatedAt')).toBe(secondRequest.updated_at);
- });
- });
+ it('should render a title/description/edited and update title/description/edited on update', async () => {
+ expect(findTitle().props('titleText')).toContain(initialRequest.title_text);
+ expect(findDescription().props('descriptionText')).toContain('this is a description');
- it('shows actions if permissions are correct', async () => {
- wrapper.vm.showForm = true;
+ expect(findEdited().exists()).toBe(true);
+ expect(findEdited().props('updatedByPath')).toMatch(/\/some_user$/);
+ expect(findEdited().props('updatedAt')).toBe(initialRequest.updated_at);
+ expect(findDescription().props().lockVersion).toBe(initialRequest.lock_version);
- await nextTick();
- expect(findForm().exists()).toBe(true);
- });
+ await advanceToNextPoll();
- it('does not show actions if permissions are incorrect', async () => {
- wrapper.vm.showForm = true;
- wrapper.setProps({ canUpdate: false });
+ expect(findTitle().props('titleText')).toContain('2');
+ expect(findDescription().props('descriptionText')).toContain('42');
- await nextTick();
- expect(findForm().exists()).toBe(false);
+ expect(findEdited().exists()).toBe(true);
+ expect(findEdited().props('updatedByName')).toBe('Other User');
+ expect(findEdited().props('updatedByPath')).toMatch(/\/other_user$/);
+ expect(findEdited().props('updatedAt')).toBe(secondRequest.updated_at);
+ });
});
- it('does not update formState if form is already open', async () => {
- wrapper.vm.updateAndShowForm();
+ describe('with permissions', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
- wrapper.vm.state.titleText = 'testing 123';
+ it('shows actions on `open.form` event', async () => {
+ expect(findForm().exists()).toBe(false);
- wrapper.vm.updateAndShowForm();
+ await openForm();
- await nextTick();
- expect(wrapper.vm.store.formState.title).not.toBe('testing 123');
+ expect(findForm().exists()).toBe(true);
+ });
+
+ it('update formState if form is not open', async () => {
+ const titleValue = initialRequest.title_text;
+
+ expect(findTitle().exists()).toBe(true);
+ expect(findTitle().props('titleText')).toBe(titleValue);
+
+ await advanceToNextPoll();
+
+ // The title component has the new data, so the state was updated
+ expect(findTitle().exists()).toBe(true);
+ expect(findTitle().props('titleText')).toBe(secondRequest.title_text);
+ });
+
+ it('does not update formState if form is already open', async () => {
+ const titleValue = initialRequest.title_text;
+
+ expect(findTitle().exists()).toBe(true);
+ expect(findTitle().props('titleText')).toBe(titleValue);
+
+ await openForm();
+
+ // Opening the form, the data has not changed
+ expect(findForm().props().formState.title).toBe(titleValue);
+
+ await advanceToNextPoll();
+
+ // We expect the prop value not to have changed after another API call
+ expect(findForm().props().formState.title).toBe(titleValue);
+ });
+ });
+
+ describe('without permissions', () => {
+ beforeEach(async () => {
+ await createComponent({ props: { canUpdate: false } });
+ });
+
+ it('does not show actions if permissions are incorrect', async () => {
+ await openForm();
+
+ expect(findForm().exists()).toBe(false);
+ });
});
describe('Pinned links propagated', () => {
@@ -178,288 +217,130 @@ describe('Issuable output', () => {
prop | value
${'zoomMeetingUrl'} | ${zoomMeetingUrl}
${'publishedIncidentUrl'} | ${publishedIncidentUrl}
- `('sets the $prop correctly on underlying pinned links', ({ prop, value }) => {
+ `('sets the $prop correctly on underlying pinned links', async ({ prop, value }) => {
+ await createComponent();
+
expect(findPinnedLinks().props(prop)).toBe(value);
});
});
- describe('updateIssuable', () => {
+ describe('updating an issue', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
it('fetches new data after update', async () => {
- const updateStoreSpy = jest.spyOn(wrapper.vm, 'updateStoreState');
- const getDataSpy = jest.spyOn(wrapper.vm.service, 'getData');
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: { web_url: window.location.pathname },
- });
+ await advanceToNextPoll();
- await wrapper.vm.updateIssuable();
- expect(updateStoreSpy).toHaveBeenCalled();
- expect(getDataSpy).toHaveBeenCalled();
+ await updateIssuable();
+
+ expect(axiosMock.history.put).toHaveLength(1);
+ // The call was made with the new data
+ expect(axiosMock.history.put[0].data.title).toEqual(findTitle().props().title);
});
- it('correctly updates issuable data', async () => {
- const spy = jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: { web_url: window.location.pathname },
- });
+ it('closes the form after fetching data', async () => {
+ await updateIssuable();
- await wrapper.vm.updateIssuable();
- expect(spy).toHaveBeenCalledWith(wrapper.vm.formState);
expect(eventHub.$emit).toHaveBeenCalledWith('close.form');
});
it('does not redirect if issue has not moved', async () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: {
- web_url: window.location.pathname,
- confidential: wrapper.vm.isConfidential,
- },
+ axiosMock.onPut().reply(HTTP_STATUS_OK, {
+ ...putRequest,
+ confidential: appProps.isConfidential,
});
- await wrapper.vm.updateIssuable();
+ await updateIssuable();
+
expect(visitUrl).not.toHaveBeenCalled();
});
it('does not redirect if issue has not moved and user has switched tabs', async () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: {
- web_url: '',
- confidential: wrapper.vm.isConfidential,
- },
+ axiosMock.onPut().reply(HTTP_STATUS_OK, {
+ ...putRequest,
+ web_url: '',
+ confidential: appProps.isConfidential,
});
- await wrapper.vm.updateIssuable();
+ await updateIssuable();
+
expect(visitUrl).not.toHaveBeenCalled();
});
it('redirects if returned web_url has changed', async () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: {
- web_url: '/testing-issue-move',
- confidential: wrapper.vm.isConfidential,
- },
- });
-
- wrapper.vm.updateIssuable();
-
- await wrapper.vm.updateIssuable();
- expect(visitUrl).toHaveBeenCalledWith('/testing-issue-move');
- });
-
- describe('shows dialog when issue has unsaved changed', () => {
- it('confirms on title change', async () => {
- wrapper.vm.showForm = true;
- wrapper.vm.state.titleText = 'title has changed';
- const e = { returnValue: null };
- wrapper.vm.handleBeforeUnloadEvent(e);
-
- await nextTick();
- expect(e.returnValue).not.toBeNull();
- });
-
- it('confirms on description change', async () => {
- wrapper.vm.showForm = true;
- wrapper.vm.state.descriptionText = 'description has changed';
- const e = { returnValue: null };
- wrapper.vm.handleBeforeUnloadEvent(e);
+ const webUrl = '/testing-issue-move';
- await nextTick();
- expect(e.returnValue).not.toBeNull();
+ axiosMock.onPut().reply(HTTP_STATUS_OK, {
+ ...putRequest,
+ web_url: webUrl,
+ confidential: appProps.isConfidential,
});
- it('does nothing when nothing has changed', async () => {
- const e = { returnValue: null };
- wrapper.vm.handleBeforeUnloadEvent(e);
+ await updateIssuable();
- await nextTick();
- expect(e.returnValue).toBeNull();
- });
+ expect(visitUrl).toHaveBeenCalledWith(webUrl);
});
describe('error when updating', () => {
- it('closes form on error', async () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockRejectedValue();
+ it('closes form', async () => {
+ axiosMock.onPut().reply(HTTP_STATUS_UNAUTHORIZED);
- await wrapper.vm.updateIssuable();
- expect(eventHub.$emit).not.toHaveBeenCalledWith('close.form');
- expect(createAlert).toHaveBeenCalledWith({ message: `Error updating issue` });
- });
+ await updateIssuable();
- it('returns the correct error message for issuableType', async () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockRejectedValue();
- wrapper.setProps({ issuableType: 'merge request' });
-
- await nextTick();
- await wrapper.vm.updateIssuable();
expect(eventHub.$emit).not.toHaveBeenCalledWith('close.form');
- expect(createAlert).toHaveBeenCalledWith({ message: `Error updating merge request` });
- });
-
- it('shows error message from backend if exists', async () => {
- const msg = 'Custom error message from backend';
- jest
- .spyOn(wrapper.vm.service, 'updateIssuable')
- .mockRejectedValue({ response: { data: { errors: [msg] } } });
-
- await wrapper.vm.updateIssuable();
expect(createAlert).toHaveBeenCalledWith({
- message: `${wrapper.vm.defaultErrorMessage}. ${msg}`,
+ message: `Error updating issue. Request failed with status code 401`,
});
});
- });
- });
-
- describe('updateAndShowForm', () => {
- it('shows locked warning if form is open & data is different', async () => {
- await nextTick();
- wrapper.vm.updateAndShowForm();
-
- wrapper.vm.poll.makeRequest();
- await new Promise((resolve) => {
- wrapper.vm.$watch('formState.lockedWarningVisible', (value) => {
- if (value) {
- resolve();
- }
- });
- });
-
- expect(wrapper.vm.formState.lockedWarningVisible).toBe(true);
- expect(wrapper.vm.formState.lock_version).toBe(1);
- });
- });
-
- describe('requestTemplatesAndShowForm', () => {
- let formSpy;
-
- beforeEach(() => {
- formSpy = jest.spyOn(wrapper.vm, 'updateAndShowForm');
- });
-
- it('shows the form if template names as hash request is successful', () => {
- const mockData = {
- test: [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }],
- };
- mock
- .onGet('/issuable-templates-path')
- .reply(() => Promise.resolve([HTTP_STATUS_OK, mockData]));
-
- return wrapper.vm.requestTemplatesAndShowForm().then(() => {
- expect(formSpy).toHaveBeenCalledWith(mockData);
- });
- });
+ it('returns the correct error message for issuableType', async () => {
+ axiosMock.onPut().reply(HTTP_STATUS_UNAUTHORIZED);
- it('shows the form if template names as array request is successful', () => {
- const mockData = [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }];
- mock
- .onGet('/issuable-templates-path')
- .reply(() => Promise.resolve([HTTP_STATUS_OK, mockData]));
+ await updateIssuable();
- return wrapper.vm.requestTemplatesAndShowForm().then(() => {
- expect(formSpy).toHaveBeenCalledWith(mockData);
- });
- });
-
- it('shows the form if template names request failed', () => {
- mock
- .onGet('/issuable-templates-path')
- .reply(() => Promise.reject(new Error('something went wrong')));
+ wrapper.setProps({ issuableType: 'merge request' });
- return wrapper.vm.requestTemplatesAndShowForm().then(() => {
- expect(createAlert).toHaveBeenCalledWith({ message: 'Error updating issue' });
+ await updateIssuable();
- expect(formSpy).toHaveBeenCalledWith();
+ expect(eventHub.$emit).not.toHaveBeenCalledWith('close.form');
+ expect(createAlert).toHaveBeenCalledWith({
+ message: `Error updating merge request. Request failed with status code 401`,
+ });
});
- });
- });
-
- describe('show inline edit button', () => {
- it('should render by default', () => {
- expect(findTitle().props('showInlineEditButton')).toBe(true);
- });
-
- it('should render if showInlineEditButton', async () => {
- wrapper.setProps({ showInlineEditButton: true });
-
- await nextTick();
- expect(findTitle().props('showInlineEditButton')).toBe(true);
- });
- it('should not render if showInlineEditButton is false', async () => {
- wrapper.setProps({ showInlineEditButton: false });
-
- await nextTick();
- expect(findTitle().props('showInlineEditButton')).toBe(false);
- });
- });
-
- describe('updateStoreState', () => {
- it('should make a request and update the state of the store', () => {
- const data = { foo: 1 };
- const getDataSpy = jest.spyOn(wrapper.vm.service, 'getData').mockResolvedValue({ data });
- const updateStateSpy = jest
- .spyOn(wrapper.vm.store, 'updateState')
- .mockImplementation(jest.fn);
-
- return wrapper.vm.updateStoreState().then(() => {
- expect(getDataSpy).toHaveBeenCalled();
- expect(updateStateSpy).toHaveBeenCalledWith(data);
- });
- });
+ it('shows error message from backend if exists', async () => {
+ const msg = 'Custom error message from backend';
+ axiosMock.onPut().reply(HTTP_STATUS_UNAUTHORIZED, { errors: [msg] });
- it('should show error message if store update fails', () => {
- jest.spyOn(wrapper.vm.service, 'getData').mockRejectedValue();
- wrapper.setProps({ issuableType: 'merge request' });
+ await updateIssuable();
- return wrapper.vm.updateStoreState().then(() => {
expect(createAlert).toHaveBeenCalledWith({
- message: `Error updating ${wrapper.vm.issuableType}`,
+ message: `Error updating issue. ${msg}`,
});
});
});
});
- describe('issueChanged', () => {
- beforeEach(() => {
- wrapper.vm.store.formState.title = '';
- wrapper.vm.store.formState.description = '';
- wrapper.setProps({
- initialDescriptionText: '',
- initialTitleText: '',
- });
- });
-
- it('returns true when title is changed', () => {
- wrapper.vm.store.formState.title = 'RandomText';
-
- expect(wrapper.vm.issueChanged).toBe(true);
- });
-
- it('returns false when title is empty null', () => {
- wrapper.vm.store.formState.title = null;
-
- expect(wrapper.vm.issueChanged).toBe(false);
- });
-
- it('returns true when description is changed', () => {
- wrapper.vm.store.formState.description = 'RandomText';
-
- expect(wrapper.vm.issueChanged).toBe(true);
+ describe('Locked warning', () => {
+ beforeEach(async () => {
+ await createComponent();
});
- it('returns false when description is empty null', () => {
- wrapper.vm.store.formState.description = null;
-
- expect(wrapper.vm.issueChanged).toBe(false);
- });
-
- it('returns false when `initialDescriptionText` is null and `formState.description` is empty string', () => {
- wrapper.vm.store.formState.description = '';
- wrapper.setProps({ initialDescriptionText: null });
+ it('shows locked warning if form is open & data is different', async () => {
+ await openForm();
+ await advanceToNextPoll();
- expect(wrapper.vm.issueChanged).toBe(false);
+ expect(findForm().props().formState.lockedWarningVisible).toBe(true);
+ expect(findForm().props().formState.lock_version).toBe(1);
});
});
describe('sticky header', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
describe('when title is in view', () => {
it('is not shown', () => {
expect(findStickyHeader().exists()).toBe(false);
@@ -467,21 +348,18 @@ describe('Issuable output', () => {
});
describe('when title is not in view', () => {
- beforeEach(() => {
- wrapper.vm.state.titleText = 'Sticky header title';
+ beforeEach(async () => {
wrapper.findComponent(GlIntersectionObserver).vm.$emit('disappear');
});
it('shows with title', () => {
- expect(findStickyHeader().text()).toContain('Sticky header title');
+ expect(findStickyHeader().text()).toContain(initialRequest.title_text);
});
it('shows with title for an epic', async () => {
- wrapper.setProps({ issuableType: 'epic' });
-
- await nextTick();
+ await wrapper.setProps({ issuableType: 'epic' });
- expect(findStickyHeader().text()).toContain('Sticky header title');
+ expect(findStickyHeader().text()).toContain(' this is a title');
});
it.each`
@@ -493,9 +371,7 @@ describe('Issuable output', () => {
`(
'shows with state icon "$statusIcon" for $issuableType when status is $issuableStatus',
async ({ issuableType, issuableStatus, statusIcon }) => {
- wrapper.setProps({ issuableType, issuableStatus });
-
- await nextTick();
+ await wrapper.setProps({ issuableType, issuableStatus });
expect(findStickyHeader().findComponent(GlIcon).props('name')).toBe(statusIcon);
},
@@ -507,9 +383,7 @@ describe('Issuable output', () => {
${'shows with Closed when status is closed'} | ${STATUS_CLOSED}
${'shows with Open when status is reopened'} | ${STATUS_REOPENED}
`('$title', async ({ state }) => {
- wrapper.setProps({ issuableStatus: state });
-
- await nextTick();
+ await wrapper.setProps({ issuableStatus: state });
expect(findStickyHeader().text()).toContain(IssuableStatusText[state]);
});
@@ -519,9 +393,7 @@ describe('Issuable output', () => {
${'does not show confidential badge when issue is not confidential'} | ${false}
${'shows confidential badge when issue is confidential'} | ${true}
`('$title', async ({ isConfidential }) => {
- wrapper.setProps({ isConfidential });
-
- await nextTick();
+ await wrapper.setProps({ isConfidential });
const confidentialEl = findConfidentialBadge();
expect(confidentialEl.exists()).toBe(isConfidential);
@@ -538,9 +410,7 @@ describe('Issuable output', () => {
${'does not show locked badge when issue is not locked'} | ${false}
${'shows locked badge when issue is locked'} | ${true}
`('$title', async ({ isLocked }) => {
- wrapper.setProps({ isLocked });
-
- await nextTick();
+ await wrapper.setProps({ isLocked });
expect(findLockedBadge().exists()).toBe(isLocked);
});
@@ -550,9 +420,7 @@ describe('Issuable output', () => {
${'does not show hidden badge when issue is not hidden'} | ${false}
${'shows hidden badge when issue is hidden'} | ${true}
`('$title', async ({ isHidden }) => {
- wrapper.setProps({ isHidden });
-
- await nextTick();
+ await wrapper.setProps({ isHidden });
const hiddenBadge = findHiddenBadge();
@@ -569,6 +437,10 @@ describe('Issuable output', () => {
});
describe('Composable description component', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
const findIncidentTabs = () => wrapper.findComponent(IncidentTabs);
const borderClass = 'gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-mb-6';
@@ -587,13 +459,13 @@ describe('Issuable output', () => {
});
describe('when using incident tabs description wrapper', () => {
- beforeEach(() => {
- mountComponent(
- {
+ beforeEach(async () => {
+ await createComponent({
+ props: {
descriptionComponent: IncidentTabs,
showTitleBorder: false,
},
- {
+ options: {
mocks: {
$apollo: {
queries: {
@@ -604,7 +476,7 @@ describe('Issuable output', () => {
},
},
},
- );
+ });
});
it('does not the description component', () => {
@@ -622,48 +494,77 @@ describe('Issuable output', () => {
});
describe('taskListUpdateStarted', () => {
- it('stops polling', () => {
- jest.spyOn(wrapper.vm.poll, 'stop');
+ beforeEach(async () => {
+ await createComponent();
+ });
+
+ it('stops polling', async () => {
+ expect(findTitle().props().titleText).toBe(initialRequest.title_text);
+
+ findDescription().vm.$emit('taskListUpdateStarted');
- wrapper.vm.taskListUpdateStarted();
+ await advanceToNextPoll();
- expect(wrapper.vm.poll.stop).toHaveBeenCalled();
+ expect(findTitle().props().titleText).toBe(initialRequest.title_text);
});
});
describe('taskListUpdateSucceeded', () => {
- it('enables polling', () => {
- jest.spyOn(wrapper.vm.poll, 'enable');
- jest.spyOn(wrapper.vm.poll, 'makeDelayedRequest');
+ beforeEach(async () => {
+ await createComponent();
+ findDescription().vm.$emit('taskListUpdateStarted');
+ });
+
+ it('enables polling', async () => {
+ // Ensure that polling is not working before
+ expect(findTitle().props().titleText).toBe(initialRequest.title_text);
+ await advanceToNextPoll();
+
+ expect(findTitle().props().titleText).toBe(initialRequest.title_text);
- wrapper.vm.taskListUpdateSucceeded();
+ // Enable Polling an move forward
+ findDescription().vm.$emit('taskListUpdateSucceeded');
+ await advanceToNextPoll();
- expect(wrapper.vm.poll.enable).toHaveBeenCalled();
- expect(wrapper.vm.poll.makeDelayedRequest).toHaveBeenCalledWith(POLLING_DELAY);
+ // Title has changed: polling works!
+ expect(findTitle().props().titleText).toBe(secondRequest.title_text);
});
});
describe('taskListUpdateFailed', () => {
- it('enables polling and calls updateStoreState', () => {
- jest.spyOn(wrapper.vm.poll, 'enable');
- jest.spyOn(wrapper.vm.poll, 'makeDelayedRequest');
- jest.spyOn(wrapper.vm, 'updateStoreState');
+ beforeEach(async () => {
+ await createComponent();
+ findDescription().vm.$emit('taskListUpdateStarted');
+ });
+
+ it('enables polling and calls updateStoreState', async () => {
+ // Ensure that polling is not working before
+ expect(findTitle().props().titleText).toBe(initialRequest.title_text);
+ await advanceToNextPoll();
- wrapper.vm.taskListUpdateFailed();
+ expect(findTitle().props().titleText).toBe(initialRequest.title_text);
- expect(wrapper.vm.poll.enable).toHaveBeenCalled();
- expect(wrapper.vm.poll.makeDelayedRequest).toHaveBeenCalledWith(POLLING_DELAY);
- expect(wrapper.vm.updateStoreState).toHaveBeenCalled();
+ // Enable Polling an move forward
+ findDescription().vm.$emit('taskListUpdateFailed');
+ await advanceToNextPoll();
+
+ // Title has changed: polling works!
+ expect(findTitle().props().titleText).toBe(secondRequest.title_text);
});
});
describe('saveDescription event', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
it('makes request to update issue', async () => {
const description = 'I have been updated!';
findDescription().vm.$emit('saveDescription', description);
+
await waitForPromises();
- expect(mock.history.put[0].data).toContain(description);
+ expect(axiosMock.history.put[0].data).toContain(description);
});
});
});
diff --git a/spec/frontend/issues/show/components/delete_issue_modal_spec.js b/spec/frontend/issues/show/components/delete_issue_modal_spec.js
index 97a091a1748..b8adeb24005 100644
--- a/spec/frontend/issues/show/components/delete_issue_modal_spec.js
+++ b/spec/frontend/issues/show/components/delete_issue_modal_spec.js
@@ -20,10 +20,6 @@ describe('DeleteIssueModal component', () => {
const mountComponent = (props = {}) =>
shallowMount(DeleteIssueModal, { propsData: { ...defaultProps, ...props } });
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('modal', () => {
it('renders', () => {
wrapper = mountComponent();
diff --git a/spec/frontend/issues/show/components/description_spec.js b/spec/frontend/issues/show/components/description_spec.js
index da51372dd3d..740b2f782e4 100644
--- a/spec/frontend/issues/show/components/description_spec.js
+++ b/spec/frontend/issues/show/components/description_spec.js
@@ -1,25 +1,19 @@
import $ from 'jquery';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
-import { GlModal } from '@gitlab/ui';
import getIssueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql';
import setWindowLocation from 'helpers/set_window_location_helper';
-import { stubComponent } from 'helpers/stub_component';
import { TEST_HOST } from 'helpers/test_constants';
-import { mockTracking } from 'helpers/tracking_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Description from '~/issues/show/components/description.vue';
import eventHub from '~/issues/show/event_hub';
-import { updateHistory } from '~/lib/utils/url_utility';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import createWorkItemMutation from '~/work_items/graphql/create_work_item.mutation.graphql';
import workItemTypesQuery from '~/work_items/graphql/project_work_item_types.query.graphql';
import TaskList from '~/task_list';
-import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
-import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
import {
createWorkItemMutationErrorResponse,
@@ -27,14 +21,9 @@ import {
getIssueDetailsResponse,
projectWorkItemTypesQueryResponse,
} from 'jest/work_items/mock_data';
-import {
- descriptionProps as initialProps,
- descriptionHtmlWithList,
- descriptionHtmlWithCheckboxes,
- descriptionHtmlWithTask,
-} from '../mock_data/mock_data';
+import { descriptionProps as initialProps, descriptionHtmlWithList } from '../mock_data/mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
updateHistory: jest.fn(),
@@ -43,9 +32,6 @@ jest.mock('~/task_list');
jest.mock('~/behaviors/markdown/render_gfm');
const mockSpriteIcons = '/icons.svg';
-const showModal = jest.fn();
-const hideModal = jest.fn();
-const showDetailsModal = jest.fn();
const $toast = {
show: jest.fn(),
};
@@ -62,7 +48,6 @@ const workItemTypesQueryHandler = jest.fn().mockResolvedValue(projectWorkItemTyp
describe('Description component', () => {
let wrapper;
- let originalGon;
Vue.use(VueApollo);
@@ -70,21 +55,16 @@ describe('Description component', () => {
const findTextarea = () => wrapper.find('[data-testid="textarea"]');
const findListItems = () => findGfmContent().findAll('ul > li');
const findTaskActionButtons = () => wrapper.findAll('.task-list-item-actions');
- const findTaskLink = () => wrapper.find('a.gfm-issue');
- const findModal = () => wrapper.findComponent(GlModal);
- const findWorkItemDetailModal = () => wrapper.findComponent(WorkItemDetailModal);
function createComponent({
props = {},
provide,
issueDetailsQueryHandler = jest.fn().mockResolvedValue(issueDetailsResponse),
createWorkItemMutationHandler,
- ...options
} = {}) {
wrapper = shallowMountExtended(Description, {
propsData: {
issueId: 1,
- issueIid: 1,
...initialProps,
...props,
},
@@ -102,25 +82,10 @@ describe('Description component', () => {
mocks: {
$toast,
},
- stubs: {
- GlModal: stubComponent(GlModal, {
- methods: {
- show: showModal,
- hide: hideModal,
- },
- }),
- WorkItemDetailModal: stubComponent(WorkItemDetailModal, {
- methods: {
- show: showDetailsModal,
- },
- }),
- },
- ...options,
});
}
beforeEach(() => {
- originalGon = window.gon;
window.gon = { sprite_icons: mockSpriteIcons };
setWindowLocation(TEST_HOST);
@@ -136,8 +101,6 @@ describe('Description component', () => {
});
afterAll(() => {
- window.gon = originalGon;
-
$('.issuable-meta .flash-container').remove();
});
@@ -285,7 +248,6 @@ describe('Description component', () => {
props: {
descriptionHtml: descriptionHtmlWithList,
},
- attachTo: document.body,
});
await nextTick();
});
@@ -325,33 +287,6 @@ describe('Description component', () => {
});
});
- describe('description with checkboxes', () => {
- beforeEach(() => {
- createComponent({
- props: {
- descriptionHtml: descriptionHtmlWithCheckboxes,
- },
- });
- return nextTick();
- });
-
- it('renders a list of hidden buttons corresponding to checkboxes in description HTML', () => {
- expect(findTaskActionButtons()).toHaveLength(3);
- });
-
- it('does not show a modal by default', () => {
- expect(findModal().exists()).toBe(false);
- });
-
- it('shows toast after delete success', async () => {
- const newDesc = 'description';
- findWorkItemDetailModal().vm.$emit('workItemDeleted', newDesc);
-
- expect(wrapper.emitted('updateDescription')).toEqual([[newDesc]]);
- expect($toast.show).toHaveBeenCalledWith('Task deleted');
- });
- });
-
describe('task list item actions', () => {
describe('converting the task list item to a task', () => {
describe('when successful', () => {
@@ -391,11 +326,7 @@ describe('Description component', () => {
});
it('calls a mutation to create a task', () => {
- const {
- confidential,
- iteration,
- milestone,
- } = issueDetailsResponse.data.workspace.issuable;
+ const { confidential, iteration, milestone } = issueDetailsResponse.data.issue;
expect(createWorkItemMutationHandler).toHaveBeenCalledWith({
input: {
confidential,
@@ -468,109 +399,4 @@ describe('Description component', () => {
});
});
});
-
- describe('work items detail', () => {
- describe('when opening and closing', () => {
- beforeEach(() => {
- createComponent({
- props: {
- descriptionHtml: descriptionHtmlWithTask,
- },
- });
- return nextTick();
- });
-
- it('opens when task button is clicked', async () => {
- await findTaskLink().trigger('click');
-
- expect(showDetailsModal).toHaveBeenCalled();
- expect(updateHistory).toHaveBeenCalledWith({
- url: `${TEST_HOST}/?work_item_id=2`,
- replace: true,
- });
- });
-
- it('closes from an open state', async () => {
- await findTaskLink().trigger('click');
-
- findWorkItemDetailModal().vm.$emit('close');
- await nextTick();
-
- expect(updateHistory).toHaveBeenLastCalledWith({
- url: `${TEST_HOST}/`,
- replace: true,
- });
- });
-
- it('tracks when opened', async () => {
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
-
- await findTaskLink().trigger('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(
- TRACKING_CATEGORY_SHOW,
- 'viewed_work_item_from_modal',
- {
- category: TRACKING_CATEGORY_SHOW,
- label: 'work_item_view',
- property: 'type_task',
- },
- );
- });
- });
-
- describe('when url query `work_item_id` exists', () => {
- it.each`
- behavior | workItemId | modalOpened
- ${'opens'} | ${'2'} | ${1}
- ${'does not open'} | ${'123'} | ${0}
- ${'does not open'} | ${'123e'} | ${0}
- ${'does not open'} | ${'12e3'} | ${0}
- ${'does not open'} | ${'1e23'} | ${0}
- ${'does not open'} | ${'x'} | ${0}
- ${'does not open'} | ${'undefined'} | ${0}
- `(
- '$behavior when url contains `work_item_id=$workItemId`',
- async ({ workItemId, modalOpened }) => {
- setWindowLocation(`?work_item_id=${workItemId}`);
-
- createComponent({
- props: { descriptionHtml: descriptionHtmlWithTask },
- });
-
- expect(showDetailsModal).toHaveBeenCalledTimes(modalOpened);
- },
- );
- });
- });
-
- describe('when hovering task links', () => {
- beforeEach(() => {
- createComponent({
- props: {
- descriptionHtml: descriptionHtmlWithTask,
- },
- });
- return nextTick();
- });
-
- it('prefetches work item detail after work item link is hovered for 150ms', async () => {
- await findTaskLink().trigger('mouseover');
- jest.advanceTimersByTime(150);
- await waitForPromises();
-
- expect(queryHandler).toHaveBeenCalledWith({
- id: 'gid://gitlab/WorkItem/2',
- });
- });
-
- it('does not work item detail after work item link is hovered for less than 150ms', async () => {
- await findTaskLink().trigger('mouseover');
- await findTaskLink().trigger('mouseout');
- jest.advanceTimersByTime(150);
- await waitForPromises();
-
- expect(queryHandler).not.toHaveBeenCalled();
- });
- });
});
diff --git a/spec/frontend/issues/show/components/edit_actions_spec.js b/spec/frontend/issues/show/components/edit_actions_spec.js
index 11c43ea4388..ca561149806 100644
--- a/spec/frontend/issues/show/components/edit_actions_spec.js
+++ b/spec/frontend/issues/show/components/edit_actions_spec.js
@@ -56,10 +56,6 @@ describe('Edit Actions component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders all buttons as enabled', () => {
const buttons = findEditButtons().wrappers;
buttons.forEach((button) => {
diff --git a/spec/frontend/issues/show/components/edited_spec.js b/spec/frontend/issues/show/components/edited_spec.js
index aa6e0a9dceb..a509627c347 100644
--- a/spec/frontend/issues/show/components/edited_spec.js
+++ b/spec/frontend/issues/show/components/edited_spec.js
@@ -15,10 +15,6 @@ describe('Edited component', () => {
const mountComponent = (propsData) => mount(Edited, { propsData });
const updatedAt = '2017-05-15T12:31:04.428Z';
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders an edited at+by string', () => {
wrapper = mountComponent({
updatedAt,
diff --git a/spec/frontend/issues/show/components/fields/description_spec.js b/spec/frontend/issues/show/components/fields/description_spec.js
index 273ddfdd5d4..5c145ed4707 100644
--- a/spec/frontend/issues/show/components/fields/description_spec.js
+++ b/spec/frontend/issues/show/components/fields/description_spec.js
@@ -33,11 +33,6 @@ describe('Description field component', () => {
jest.spyOn(eventHub, '$emit');
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders markdown field with description', () => {
wrapper = mountComponent();
@@ -80,17 +75,18 @@ describe('Description field component', () => {
});
it('uses the MarkdownEditor component to edit markdown', () => {
- expect(findMarkdownEditor().props()).toEqual(
- expect.objectContaining({
- value: 'test',
- renderMarkdownPath: '/',
- markdownDocsPath: '/',
- quickActionsDocsPath: expect.any(String),
- autofocus: true,
- supportsQuickActions: true,
- enableAutocomplete: true,
- }),
- );
+ expect(findMarkdownEditor().props()).toMatchObject({
+ value: 'test',
+ renderMarkdownPath: '/',
+ autofocus: true,
+ supportsQuickActions: true,
+ quickActionsDocsPath: expect.any(String),
+ });
+
+ expect(findMarkdownEditor().vm.$attrs).toMatchObject({
+ 'enable-autocomplete': true,
+ 'markdown-docs-path': '/',
+ });
});
it('triggers update with meta+enter', () => {
diff --git a/spec/frontend/issues/show/components/fields/description_template_spec.js b/spec/frontend/issues/show/components/fields/description_template_spec.js
index 79a3bfa9840..1e8d5e2dd95 100644
--- a/spec/frontend/issues/show/components/fields/description_template_spec.js
+++ b/spec/frontend/issues/show/components/fields/description_template_spec.js
@@ -22,10 +22,6 @@ describe('Issue description template component with templates as hash', () => {
wrapper = shallowMount(descriptionTemplate, options);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders templates as JSON hash in data attribute', () => {
createComponent();
expect(findIssuableSelector().attributes('data-data')).toBe(
diff --git a/spec/frontend/issues/show/components/fields/title_spec.js b/spec/frontend/issues/show/components/fields/title_spec.js
index a5fa96d8d64..b28762f1520 100644
--- a/spec/frontend/issues/show/components/fields/title_spec.js
+++ b/spec/frontend/issues/show/components/fields/title_spec.js
@@ -17,11 +17,6 @@ describe('Title field component', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders form control with formState title', () => {
expect(findInput().element.value).toBe('test');
});
diff --git a/spec/frontend/issues/show/components/fields/type_spec.js b/spec/frontend/issues/show/components/fields/type_spec.js
index 27ac0e1baf3..e655cf3b37d 100644
--- a/spec/frontend/issues/show/components/fields/type_spec.js
+++ b/spec/frontend/issues/show/components/fields/type_spec.js
@@ -1,4 +1,4 @@
-import { GlFormGroup, GlListbox, GlIcon } from '@gitlab/ui';
+import { GlFormGroup, GlCollapsibleListbox, GlIcon } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
@@ -32,7 +32,7 @@ describe('Issue type field component', () => {
},
};
- const findListBox = () => wrapper.findComponent(GlListbox);
+ const findListBox = () => wrapper.findComponent(GlCollapsibleListbox);
const findFormGroup = () => wrapper.findComponent(GlFormGroup);
const findAllIssueItems = () => wrapper.findAll('[data-testid="issue-type-list-item"]');
const findIssueItemAt = (at) => findAllIssueItems().at(at);
@@ -60,10 +60,6 @@ describe('Issue type field component', () => {
mockIssueStateData = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
at | text | icon
${0} | ${issuableTypes[0].text} | ${issuableTypes[0].icon}
diff --git a/spec/frontend/issues/show/components/form_spec.js b/spec/frontend/issues/show/components/form_spec.js
index aedb974cbd0..b8ed33801f2 100644
--- a/spec/frontend/issues/show/components/form_spec.js
+++ b/spec/frontend/issues/show/components/form_spec.js
@@ -30,10 +30,6 @@ describe('Inline edit form component', () => {
projectNamespace: '/',
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const createComponent = (props) => {
wrapper = shallowMount(formComponent, {
propsData: {
diff --git a/spec/frontend/issues/show/components/header_actions_spec.js b/spec/frontend/issues/show/components/header_actions_spec.js
index 3d9dad3a721..58ec7387851 100644
--- a/spec/frontend/issues/show/components/header_actions_spec.js
+++ b/spec/frontend/issues/show/components/header_actions_spec.js
@@ -1,20 +1,22 @@
import Vue, { nextTick } from 'vue';
-import { GlButton, GlDropdownItem, GlLink, GlModal } from '@gitlab/ui';
+import { GlDropdownItem, GlLink, GlModal, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import { mockTracking } from 'helpers/tracking_helper';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
-import { IssueType, STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
+import { STATUS_CLOSED, STATUS_OPEN, TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import DeleteIssueModal from '~/issues/show/components/delete_issue_modal.vue';
import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
import HeaderActions from '~/issues/show/components/header_actions.vue';
import { ISSUE_STATE_EVENT_CLOSE, ISSUE_STATE_EVENT_REOPEN } from '~/issues/show/constants';
+import issuesEventHub from '~/issues/show/event_hub';
import promoteToEpicMutation from '~/issues/show/queries/promote_to_epic.mutation.graphql';
import * as urlUtility from '~/lib/utils/url_utility';
import eventHub from '~/notes/event_hub';
import createStore from '~/notes/stores';
-jest.mock('~/flash');
+jest.mock('~/alert');
+jest.mock('~/issues/show/event_hub', () => ({ $emit: jest.fn() }));
describe('HeaderActions component', () => {
let dispatchEventSpy;
@@ -36,7 +38,7 @@ describe('HeaderActions component', () => {
iid: '32',
isIssueAuthor: true,
issuePath: 'gitlab-org/gitlab-test/-/issues/1',
- issueType: IssueType.Issue,
+ issueType: TYPE_ISSUE,
newIssuePath: 'gitlab-org/gitlab-test/-/issues/new',
projectPath: 'gitlab-org/gitlab-test',
reportAbusePath: '-/abuse_reports/add_category',
@@ -67,7 +69,8 @@ describe('HeaderActions component', () => {
},
};
- const findToggleIssueStateButton = () => wrapper.findComponent(GlButton);
+ const findToggleIssueStateButton = () => wrapper.find(`[data-testid="toggle-button"]`);
+ const findEditButton = () => wrapper.find(`[data-testid="edit-button"]`);
const findDropdownBy = (dataTestId) => wrapper.find(`[data-testid="${dataTestId}"]`);
const findMobileDropdown = () => findDropdownBy('mobile-dropdown');
@@ -103,6 +106,9 @@ describe('HeaderActions component', () => {
mutate: mutateMock,
},
},
+ stubs: {
+ GlButton,
+ },
});
};
@@ -113,13 +119,12 @@ describe('HeaderActions component', () => {
if (visitUrlSpy) {
visitUrlSpy.mockRestore();
}
- wrapper.destroy();
});
describe.each`
issueType
- ${IssueType.Issue}
- ${IssueType.Incident}
+ ${TYPE_ISSUE}
+ ${TYPE_INCIDENT}
`('when issue type is $issueType', ({ issueType }) => {
describe('close/reopen button', () => {
describe.each`
@@ -240,6 +245,30 @@ describe('HeaderActions component', () => {
});
});
});
+
+ describe(`show edit button ${issueType}`, () => {
+ beforeEach(() => {
+ wrapper = mountComponent({
+ props: {
+ canUpdateIssue: true,
+ canCreateIssue: false,
+ isIssueAuthor: true,
+ issueType,
+ canReportSpam: false,
+ canPromoteToEpic: false,
+ },
+ });
+ });
+ it(`shows the edit button`, () => {
+ expect(findEditButton().exists()).toBe(true);
+ });
+
+ it('should trigger "open.form" event when clicked', async () => {
+ expect(issuesEventHub.$emit).not.toHaveBeenCalled();
+ await findEditButton().trigger('click');
+ expect(issuesEventHub.$emit).toHaveBeenCalledWith('open.form');
+ });
+ });
});
describe('delete issue button', () => {
diff --git a/spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js b/spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js
index 6c923cae0cc..6b68e7a0da6 100644
--- a/spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js
+++ b/spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js
@@ -9,7 +9,7 @@ import createTimelineEventMutation from '~/issues/show/components/incidents/grap
import getTimelineEvents from '~/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql';
import { timelineFormI18n } from '~/issues/show/components/incidents/constants';
import createMockApollo from 'helpers/mock_apollo_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { useFakeDate } from 'helpers/fake_date';
import {
timelineEventsCreateEventResponse,
@@ -19,7 +19,7 @@ import {
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
const fakeDate = '2020-07-08T00:00:00.000Z';
@@ -99,7 +99,6 @@ describe('Create Timeline events', () => {
afterEach(() => {
createAlert.mockReset();
- wrapper.destroy();
});
describe('createIncidentTimelineEvent', () => {
diff --git a/spec/frontend/issues/show/components/incidents/incident_tabs_spec.js b/spec/frontend/issues/show/components/incidents/incident_tabs_spec.js
index 33a3a6eddfc..0f4fb02a40b 100644
--- a/spec/frontend/issues/show/components/incidents/incident_tabs_spec.js
+++ b/spec/frontend/issues/show/components/incidents/incident_tabs_spec.js
@@ -1,4 +1,5 @@
import merge from 'lodash/merge';
+import { nextTick } from 'vue';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { trackIncidentDetailsViewsOptions } from '~/incidents/constants';
import DescriptionComponent from '~/issues/show/components/description.vue';
@@ -11,6 +12,11 @@ import Tracking from '~/tracking';
import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
import { descriptionProps } from '../../mock_data/mock_data';
+const push = jest.fn();
+const $router = {
+ push,
+};
+
const mockAlert = {
__typename: 'AlertManagementAlert',
detailsUrl: INVALID_URL,
@@ -28,12 +34,20 @@ const defaultMocks = {
},
},
},
+ $route: { params: {} },
+ $router,
};
describe('Incident Tabs component', () => {
let wrapper;
- const mountComponent = ({ data = {}, options = {}, mount = shallowMountExtended } = {}) => {
+ const mountComponent = ({
+ data = {},
+ options = {},
+ mount = shallowMountExtended,
+ hasLinkedAlerts = false,
+ mocks = {},
+ } = {}) => {
wrapper = mount(
IncidentTabs,
merge(
@@ -54,11 +68,12 @@ describe('Incident Tabs component', () => {
slaFeatureAvailable: true,
canUpdate: true,
canUpdateTimelineEvent: true,
+ hasLinkedAlerts,
},
data() {
return { alert: mockAlert, ...data };
},
- mocks: defaultMocks,
+ mocks: { ...defaultMocks, ...mocks },
},
options,
),
@@ -102,11 +117,13 @@ describe('Incident Tabs component', () => {
});
it('renders the alert details tab', () => {
+ mountComponent({ hasLinkedAlerts: true });
expect(findAlertDetailsTab().exists()).toBe(true);
expect(findAlertDetailsTab().attributes('title')).toBe('Alert details');
});
it('renders the alert details table with the correct props', () => {
+ mountComponent({ hasLinkedAlerts: true });
const alert = { iid: mockAlert.iid };
expect(findAlertDetailsComponent().props('alert')).toMatchObject(alert);
@@ -156,6 +173,40 @@ describe('Incident Tabs component', () => {
expect(findActiveTabs()).toHaveLength(1);
expect(findActiveTabs().at(0).text()).toBe(incidentTabsI18n.timelineTitle);
+ expect(push).toHaveBeenCalledWith('/timeline');
+ });
+ });
+
+ describe('loading page with tab', () => {
+ it('shows the timeline tab when timeline path is passed', async () => {
+ mountComponent({
+ mount: mountExtended,
+ mocks: { $route: { params: { tabId: 'timeline' } } },
+ });
+ await nextTick();
+ expect(findActiveTabs()).toHaveLength(1);
+ expect(findActiveTabs().at(0).text()).toBe(incidentTabsI18n.timelineTitle);
+ });
+
+ it('shows the alerts tab when timeline path is passed', async () => {
+ mountComponent({
+ mount: mountExtended,
+ mocks: { $route: { params: { tabId: 'alerts' } } },
+ hasLinkedAlerts: true,
+ });
+ await nextTick();
+ expect(findActiveTabs()).toHaveLength(1);
+ expect(findActiveTabs().at(0).text()).toBe(incidentTabsI18n.alertsTitle);
+ });
+
+ it('shows the metrics tab when metrics path is passed', async () => {
+ mountComponent({
+ mount: mountExtended,
+ mocks: { $route: { params: { tabId: 'metrics' } } },
+ });
+ await nextTick();
+ expect(findActiveTabs()).toHaveLength(1);
+ expect(findActiveTabs().at(0).text()).toBe(incidentTabsI18n.metricsTitle);
});
});
});
diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js
index e352f9708e4..af01fd34336 100644
--- a/spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js
+++ b/spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js
@@ -10,12 +10,12 @@ import {
TIMELINE_EVENT_TAGS,
timelineEventTagsI18n,
} from '~/issues/show/components/incidents/constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { useFakeDate } from 'helpers/fake_date';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
const fakeDate = '2020-07-08T00:00:00.000Z';
@@ -51,7 +51,6 @@ describe('Timeline events form', () => {
afterEach(() => {
createAlert.mockReset();
- wrapper.destroy();
});
const findMarkdownField = () => wrapper.findComponent(MarkdownField);
diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js
index 26fda877089..8d79dece888 100644
--- a/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js
+++ b/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js
@@ -11,7 +11,7 @@ import deleteTimelineEventMutation from '~/issues/show/components/incidents/grap
import editTimelineEventMutation from '~/issues/show/components/incidents/graphql/queries/edit_timeline_event.mutation.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import { useFakeDate } from 'helpers/fake_date';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import {
mockEvents,
timelineEventsDeleteEventResponse,
@@ -26,7 +26,7 @@ import {
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
const mockConfirmAction = ({ confirmed }) => {
@@ -77,10 +77,6 @@ describe('IncidentTimelineEventList', () => {
mountComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
it('groups items correctly', () => {
expect(findTimelineEventGroups()).toHaveLength(2);
diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js
index 63474070701..48c3f0984a0 100644
--- a/spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js
+++ b/spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js
@@ -8,13 +8,13 @@ import IncidentTimelineEventsList from '~/issues/show/components/incidents/timel
import CreateTimelineEvent from '~/issues/show/components/incidents/create_timeline_event.vue';
import timelineEventsQuery from '~/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { timelineTabI18n } from '~/issues/show/components/incidents/constants';
import { timelineEventsQueryListResponse, timelineEventsQueryEmptyResponse } from './mock_data';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
const graphQLError = new Error('GraphQL error');
const listResponse = jest.fn().mockResolvedValue(timelineEventsQueryListResponse);
diff --git a/spec/frontend/issues/show/components/incidents/utils_spec.js b/spec/frontend/issues/show/components/incidents/utils_spec.js
index 75be17f9889..8ee0d906dd4 100644
--- a/spec/frontend/issues/show/components/incidents/utils_spec.js
+++ b/spec/frontend/issues/show/components/incidents/utils_spec.js
@@ -5,10 +5,10 @@ import {
getUtcShiftedDate,
getPreviousEventTags,
} from '~/issues/show/components/incidents/utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { mockTimelineEventTags } from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('incident utils', () => {
describe('display and log error', () => {
diff --git a/spec/frontend/issues/show/components/locked_warning_spec.js b/spec/frontend/issues/show/components/locked_warning_spec.js
index dd3c7c58380..f8a8c999632 100644
--- a/spec/frontend/issues/show/components/locked_warning_spec.js
+++ b/spec/frontend/issues/show/components/locked_warning_spec.js
@@ -13,11 +13,6 @@ describe('LockedWarning component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findAlert = () => wrapper.findComponent(GlAlert);
const findLink = () => wrapper.findComponent(GlLink);
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 d52f9d57453..8caa5236796 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
@@ -17,7 +17,7 @@ describe('TaskListItemActions component', () => {
document.body.appendChild(li);
wrapper = shallowMount(TaskListItemActions, {
- provide: { canUpdate: true, toggleClass: 'task-list-item-actions' },
+ provide: { canUpdate: true },
attachTo: document.querySelector('div'),
});
};
diff --git a/spec/frontend/issues/show/components/title_spec.js b/spec/frontend/issues/show/components/title_spec.js
index 7560b733ae6..16ac675e12c 100644
--- a/spec/frontend/issues/show/components/title_spec.js
+++ b/spec/frontend/issues/show/components/title_spec.js
@@ -1,96 +1,59 @@
-import Vue, { nextTick } from 'vue';
+import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import titleComponent from '~/issues/show/components/title.vue';
-import eventHub from '~/issues/show/event_hub';
-import Store from '~/issues/show/stores';
+import Title from '~/issues/show/components/title.vue';
describe('Title component', () => {
- let vm;
- beforeEach(() => {
+ let wrapper;
+
+ const getTitleHeader = () => wrapper.findByTestId('issue-title');
+
+ const createWrapper = (props) => {
setHTMLFixture(`<title />`);
- const Component = Vue.extend(titleComponent);
- const store = new Store({
- titleHtml: '',
- descriptionHtml: '',
- issuableRef: '',
- });
- vm = new Component({
+ wrapper = shallowMountExtended(Title, {
propsData: {
issuableRef: '#1',
titleHtml: 'Testing <img />',
titleText: 'Testing',
- showForm: false,
- formState: store.formState,
+ ...props,
},
- }).$mount();
- });
+ });
+ };
afterEach(() => {
resetHTMLFixture();
});
it('renders title HTML', () => {
- expect(vm.$el.querySelector('.title').innerHTML.trim()).toBe('Testing <img>');
- });
-
- it('updates page title when changing titleHtml', async () => {
- const spy = jest.spyOn(vm, 'setPageTitle');
- vm.titleHtml = 'test';
+ createWrapper();
- await nextTick();
- expect(spy).toHaveBeenCalled();
+ expect(getTitleHeader().element.innerHTML.trim()).toBe('Testing <img>');
});
it('animates title changes', async () => {
- vm.titleHtml = 'test';
+ createWrapper();
- await nextTick();
+ await wrapper.setProps({
+ titleHtml: 'test',
+ });
- expect(vm.$el.querySelector('.title').classList).toContain('issue-realtime-pre-pulse');
- jest.runAllTimers();
+ expect(getTitleHeader().classes('issue-realtime-pre-pulse')).toBe(true);
+ jest.runAllTimers();
await nextTick();
- expect(vm.$el.querySelector('.title').classList).toContain('issue-realtime-trigger-pulse');
+ expect(getTitleHeader().classes('issue-realtime-trigger-pulse')).toBe(true);
});
it('updates page title after changing title', async () => {
- vm.titleHtml = 'changed';
- vm.titleText = 'changed';
-
- await nextTick();
- expect(document.querySelector('title').textContent.trim()).toContain('changed');
- });
+ createWrapper();
- describe('inline edit button', () => {
- it('should not show by default', () => {
- expect(vm.$el.querySelector('.btn-edit')).toBeNull();
+ await wrapper.setProps({
+ titleHtml: 'changed',
+ titleText: 'changed',
});
- it('should not show if canUpdate is false', () => {
- vm.showInlineEditButton = true;
- vm.canUpdate = false;
-
- expect(vm.$el.querySelector('.btn-edit')).toBeNull();
- });
-
- it('should show if showInlineEditButton and canUpdate', () => {
- vm.showInlineEditButton = true;
- vm.canUpdate = true;
-
- expect(vm.$el.querySelector('.btn-edit')).toBeDefined();
- });
-
- it('should trigger open.form event when clicked', async () => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- vm.showInlineEditButton = true;
- vm.canUpdate = true;
-
- await nextTick();
- vm.$el.querySelector('.btn-edit').click();
-
- expect(eventHub.$emit).toHaveBeenCalledWith('open.form');
- });
+ expect(document.querySelector('title').textContent.trim()).toContain('changed');
});
});
diff --git a/spec/frontend/issues/show/mock_data/mock_data.js b/spec/frontend/issues/show/mock_data/mock_data.js
index 9f0b6fb1148..86d09665947 100644
--- a/spec/frontend/issues/show/mock_data/mock_data.js
+++ b/spec/frontend/issues/show/mock_data/mock_data.js
@@ -24,6 +24,19 @@ export const secondRequest = {
lock_version: 2,
};
+export const putRequest = {
+ web_url: window.location.pathname,
+ title: '<p>PUT</p>',
+ title_text: 'PUT',
+ description: '<p>PUT_DESC</p>',
+ description_text: 'PUT_DESC',
+ task_status: '0 of 0 completed',
+ updated_at: '2016-05-15T12:31:04.428Z',
+ updated_by_name: 'Other User',
+ updated_by_path: '/other_user',
+ lock_version: 2,
+};
+
export const descriptionProps = {
canUpdate: true,
descriptionHtml: 'test',
@@ -66,47 +79,3 @@ export const descriptionHtmlWithList = `
<li data-sourcepos="3:1-3:8">todo 3</li>
</ul>
`;
-
-export const descriptionHtmlWithCheckboxes = `
- <ul dir="auto" class="task-list" data-sourcepos"3:1-5:12">
- <li class="task-list-item" data-sourcepos="3:1-3:11">
- <input class="task-list-item-checkbox" type="checkbox"> todo 1
- </li>
- <li class="task-list-item" data-sourcepos="4:1-4:12">
- <input class="task-list-item-checkbox" type="checkbox"> todo 2
- </li>
- <li class="task-list-item" data-sourcepos="5:1-5:12">
- <input class="task-list-item-checkbox" type="checkbox"> todo 3
- </li>
- </ul>
-`;
-
-export const descriptionHtmlWithTask = `
- <ul data-sourcepos="1:1-3:7" class="task-list" dir="auto">
- <li data-sourcepos="1:1-1:10" class="task-list-item">
- <input type="checkbox" class="task-list-item-checkbox" disabled>
- <a href="/gitlab-org/gitlab-test/-/issues/48" data-original="#48+" data-link="false" data-link-reference="false" data-project="1" data-issue="2" data-reference-format="+" data-reference-type="task" data-container="body" data-placement="top" title="1" class="gfm gfm-issue has-tooltip" data-issue-type="task">1 (#48)</a>
- </li>
- <li data-sourcepos="2:1-2:7" class="task-list-item">
- <input type="checkbox" class="task-list-item-checkbox" disabled> 2
- </li>
- <li data-sourcepos="3:1-3:7" class="task-list-item">
- <input type="checkbox" class="task-list-item-checkbox" disabled> 3
- </li>
- </ul>
-`;
-
-export const descriptionHtmlWithIssue = `
- <ul data-sourcepos="1:1-3:7" class="task-list" dir="auto">
- <li data-sourcepos="1:1-1:10" class="task-list-item">
- <input type="checkbox" class="task-list-item-checkbox" disabled>
- <a href="/gitlab-org/gitlab-test/-/issues/48" data-original="#48+" data-link="false" data-link-reference="false" data-project="1" data-issue="2" data-reference-format="+" data-reference-type="task" data-container="body" data-placement="top" title="1" class="gfm gfm-issue has-tooltip" data-issue-type="issue">1 (#48)</a>
- </li>
- <li data-sourcepos="2:1-2:7" class="task-list-item">
- <input type="checkbox" class="task-list-item-checkbox" disabled> 2
- </li>
- <li data-sourcepos="3:1-3:7" class="task-list-item">
- <input type="checkbox" class="task-list-item-checkbox" disabled> 3
- </li>
- </ul>
-`;
diff --git a/spec/frontend/jira_connect/branches/components/new_branch_form_spec.js b/spec/frontend/jira_connect/branches/components/new_branch_form_spec.js
index d41031f9eaa..5e6b67aec40 100644
--- a/spec/frontend/jira_connect/branches/components/new_branch_form_spec.js
+++ b/spec/frontend/jira_connect/branches/components/new_branch_form_spec.js
@@ -78,10 +78,6 @@ describe('NewBranchForm', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when selecting items from dropdowns', () => {
describe('when no project selected', () => {
beforeEach(() => {
diff --git a/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js b/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js
index 944854faab3..0a887efee4b 100644
--- a/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js
+++ b/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js
@@ -49,10 +49,6 @@ describe('ProjectDropdown', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when loading projects', () => {
beforeEach(() => {
createComponent({
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 56e425fa4eb..701512953df 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
@@ -54,10 +54,6 @@ describe('SourceBranchDropdown', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when `selectedProject` prop is not specified', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/jira_connect/branches/pages/index_spec.js b/spec/frontend/jira_connect/branches/pages/index_spec.js
index 92976dd28da..4b79d5feab5 100644
--- a/spec/frontend/jira_connect/branches/pages/index_spec.js
+++ b/spec/frontend/jira_connect/branches/pages/index_spec.js
@@ -25,10 +25,6 @@ describe('NewBranchForm', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('page title', () => {
it.each`
initialBranchName | pageTitle
diff --git a/spec/frontend/jira_connect/subscriptions/api_spec.js b/spec/frontend/jira_connect/subscriptions/api_spec.js
index e2a14a9102f..5a28c6d9789 100644
--- a/spec/frontend/jira_connect/subscriptions/api_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/api_spec.js
@@ -17,7 +17,6 @@ jest.mock('~/jira_connect/subscriptions/utils', () => ({
describe('JiraConnect API', () => {
let axiosMock;
- let originalGon;
let response;
const mockAddPath = 'addPath';
@@ -29,13 +28,11 @@ describe('JiraConnect API', () => {
beforeEach(() => {
axiosMock = new MockAdapter(axiosInstance);
- originalGon = window.gon;
window.gon = { api_version: 'v4' };
});
afterEach(() => {
axiosMock.restore();
- window.gon = originalGon;
response = null;
});
diff --git a/spec/frontend/jira_connect/subscriptions/components/add_namespace_button_spec.js b/spec/frontend/jira_connect/subscriptions/components/add_namespace_button_spec.js
index 9f92ad2adc1..934473c15ba 100644
--- a/spec/frontend/jira_connect/subscriptions/components/add_namespace_button_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/add_namespace_button_spec.js
@@ -11,7 +11,7 @@ describe('AddNamespaceButton', () => {
const createComponent = () => {
wrapper = shallowMount(AddNamespaceButton, {
directives: {
- glModal: createMockDirective(),
+ glModal: createMockDirective('gl-modal'),
},
});
};
@@ -23,10 +23,6 @@ describe('AddNamespaceButton', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays a button', () => {
expect(findButton().exists()).toBe(true);
});
diff --git a/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/add_namespace_modal_spec.js b/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/add_namespace_modal_spec.js
index d80381107f2..dbe8a734bb4 100644
--- a/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/add_namespace_modal_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/add_namespace_modal_spec.js
@@ -17,10 +17,6 @@ describe('AddNamespaceModal', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays modal with correct props', () => {
const modal = findModal();
expect(modal.exists()).toBe(true);
diff --git a/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js b/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js
index 5df54abfc05..e437e6e0398 100644
--- a/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js
@@ -40,10 +40,6 @@ describe('GroupsListItem', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGroupItemName = () => wrapper.findComponent(GroupItemName);
const findLinkButton = () => wrapper.findComponent(GlButton);
const clickLinkButton = () => findLinkButton().trigger('click');
diff --git a/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_spec.js b/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_spec.js
index 97038a2a231..9d5bc8dff2a 100644
--- a/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_spec.js
@@ -48,10 +48,6 @@ describe('GroupsList', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlAlert = () => wrapper.findComponent(GlAlert);
const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findAllItems = () => wrapper.findAllComponents(GroupsListItem);
diff --git a/spec/frontend/jira_connect/subscriptions/components/app_spec.js b/spec/frontend/jira_connect/subscriptions/components/app_spec.js
index 369ddda8dbe..aa4feaa5261 100644
--- a/spec/frontend/jira_connect/subscriptions/components/app_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/app_spec.js
@@ -41,10 +41,6 @@ describe('JiraConnectApp', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
describe.each`
scenario | usersPath | shouldRenderSignInPage | shouldRenderSubscriptionsPage
diff --git a/spec/frontend/jira_connect/subscriptions/components/browser_support_alert_spec.js b/spec/frontend/jira_connect/subscriptions/components/browser_support_alert_spec.js
index aa93a6be3c8..a8aa383d917 100644
--- a/spec/frontend/jira_connect/subscriptions/components/browser_support_alert_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/browser_support_alert_spec.js
@@ -12,10 +12,6 @@ describe('BrowserSupportAlert', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findLink = () => wrapper.findComponent(GlLink);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays a non-dismissible alert', () => {
createComponent();
diff --git a/spec/frontend/jira_connect/subscriptions/components/group_item_name_spec.js b/spec/frontend/jira_connect/subscriptions/components/group_item_name_spec.js
index b5fe08486b1..e4da10569f3 100644
--- a/spec/frontend/jira_connect/subscriptions/components/group_item_name_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/group_item_name_spec.js
@@ -14,10 +14,6 @@ describe('GroupItemName', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
it('matches the snapshot', () => {
createComponent();
diff --git a/spec/frontend/jira_connect/subscriptions/components/sign_in_legacy_button_spec.js b/spec/frontend/jira_connect/subscriptions/components/sign_in_legacy_button_spec.js
index 4ebfaed261e..0dadec598e4 100644
--- a/spec/frontend/jira_connect/subscriptions/components/sign_in_legacy_button_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/sign_in_legacy_button_spec.js
@@ -22,10 +22,6 @@ describe('SignInLegacyButton', () => {
const findButton = () => wrapper.findComponent(GlButton);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays a button', () => {
createComponent();
diff --git a/spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js b/spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js
index e20c4b62e77..9d39b82c05f 100644
--- a/spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js
@@ -56,10 +56,6 @@ describe('SignInOauthButton', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findButton = () => wrapper.findComponent(GlButton);
describe('when `gitlabBasePath` is GitLab.com', () => {
it('displays a button', () => {
diff --git a/spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js b/spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js
index 2d7c58fc278..5337575d5ef 100644
--- a/spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js
@@ -29,10 +29,6 @@ describe('SubscriptionsList', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findUnlinkButton = () => wrapper.findComponent(GlButton);
const clickUnlinkButton = () => findUnlinkButton().trigger('click');
diff --git a/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js b/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js
index e16121243a0..c0bd908da0f 100644
--- a/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js
@@ -28,10 +28,6 @@ describe('UserLink', () => {
const findSprintf = () => wrapper.findComponent(GlSprintf);
const findOauthButton = () => wrapper.findComponent(SignInOauthButton);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
userSignedIn | hasSubscriptions | expectGlSprintf | expectGlLink | expectOauthButton | jiraConnectOauthEnabled
${true} | ${false} | ${true} | ${false} | ${false} | ${false}
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com_spec.js
index b9a8451f3b3..be46c1d1609 100644
--- a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com_spec.js
@@ -42,10 +42,6 @@ describe('SignInGitlabCom', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
describe.each`
scenario | hasSubscriptions | signInButtonText
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js
index e98c6ff1054..d99d8986296 100644
--- a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js
@@ -32,10 +32,6 @@ describe('SignInGitlabMultiversion', () => {
wrapper = shallowMountExtended(SignInGitlabMultiversion);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when version is not selected', () => {
describe('VersionSelectForm', () => {
it('renders version select form', () => {
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js
index 29e7fe7a5b2..428aa1d734b 100644
--- a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js
@@ -17,10 +17,6 @@ describe('VersionSelectForm', () => {
wrapper = shallowMountExtended(VersionSelectForm);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default state', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js
index b27eba6b040..7639c3a9c3f 100644
--- a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js
@@ -34,10 +34,6 @@ describe('SignInPage', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
jiraConnectOauthEnabled | publicKeyStorageEnabled | shouldRenderDotCom | shouldRenderMultiversion
${false} | ${true} | ${true} | ${false}
diff --git a/spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js b/spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js
index 4956af76ead..d262f4b2735 100644
--- a/spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js
@@ -26,10 +26,6 @@ describe('SubscriptionsPage', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
describe.each`
scenario | subscriptionsLoading | hasSubscriptions | expectSubscriptionsList | expectEmptyState
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 40e627262db..6766456d09c 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
@@ -2,7 +2,7 @@
exports[`JiraImportForm table body shows correct information in each cell 1`] = `
<table
- aria-busy="false"
+ aria-busy=""
aria-colcount="3"
class="table b-table gl-table b-table-fixed"
role="table"
@@ -92,7 +92,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<!---->
<button
aria-expanded="false"
- aria-haspopup="true"
+ aria-haspopup="menu"
class="btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle"
type="button"
>
@@ -217,7 +217,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<!---->
<button
aria-expanded="false"
- aria-haspopup="true"
+ aria-haspopup="menu"
class="btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle"
type="button"
>
diff --git a/spec/frontend/jira_import/components/jira_import_app_spec.js b/spec/frontend/jira_import/components/jira_import_app_spec.js
index 022a0f81aaa..dc1b75f5d9e 100644
--- a/spec/frontend/jira_import/components/jira_import_app_spec.js
+++ b/spec/frontend/jira_import/components/jira_import_app_spec.js
@@ -67,11 +67,6 @@ describe('JiraImportApp', () => {
},
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when Jira integration is not configured', () => {
beforeEach(() => {
wrapper = mountComponent({ isJiraConfigured: false });
diff --git a/spec/frontend/jira_import/components/jira_import_form_spec.js b/spec/frontend/jira_import/components/jira_import_form_spec.js
index d43a9f8a145..c7db9f429de 100644
--- a/spec/frontend/jira_import/components/jira_import_form_spec.js
+++ b/spec/frontend/jira_import/components/jira_import_form_spec.js
@@ -106,7 +106,6 @@ describe('JiraImportForm', () => {
axiosMock.restore();
mutateSpy.mockRestore();
querySpy.mockRestore();
- wrapper.destroy();
});
describe('select dropdown project selection', () => {
diff --git a/spec/frontend/jira_import/components/jira_import_progress_spec.js b/spec/frontend/jira_import/components/jira_import_progress_spec.js
index 42356763492..c0d415a2130 100644
--- a/spec/frontend/jira_import/components/jira_import_progress_spec.js
+++ b/spec/frontend/jira_import/components/jira_import_progress_spec.js
@@ -25,11 +25,6 @@ describe('JiraImportProgress', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('empty state', () => {
beforeEach(() => {
wrapper = mountComponent();
diff --git a/spec/frontend/jira_import/components/jira_import_setup_spec.js b/spec/frontend/jira_import/components/jira_import_setup_spec.js
index 0085a2b5572..5331467d669 100644
--- a/spec/frontend/jira_import/components/jira_import_setup_spec.js
+++ b/spec/frontend/jira_import/components/jira_import_setup_spec.js
@@ -17,11 +17,6 @@ describe('JiraImportSetup', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('contains illustration', () => {
expect(getGlEmptyStateProp('svgPath')).toBe(illustration);
});
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
index 14613775791..5ecddc7efd6 100644
--- a/spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js
+++ b/spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js
@@ -27,10 +27,6 @@ describe('Jobs filtered search', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays filtered search', () => {
createComponent();
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
index fbe5f6a2e11..6755b854f01 100644
--- 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
@@ -45,10 +45,6 @@ describe('Job Status Token', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('passes config correctly', () => {
expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
});
diff --git a/spec/frontend/jobs/components/job/artifacts_block_spec.js b/spec/frontend/jobs/components/job/artifacts_block_spec.js
index c75deb64d84..ea5d727bd08 100644
--- a/spec/frontend/jobs/components/job/artifacts_block_spec.js
+++ b/spec/frontend/jobs/components/job/artifacts_block_spec.js
@@ -55,11 +55,6 @@ describe('Artifacts block', () => {
locked: true,
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('with expired artifacts that are not locked', () => {
beforeEach(() => {
wrapper = createWrapper({
diff --git a/spec/frontend/jobs/components/job/commit_block_spec.js b/spec/frontend/jobs/components/job/commit_block_spec.js
index 4fcc754c82c..1c28b5079d7 100644
--- a/spec/frontend/jobs/components/job/commit_block_spec.js
+++ b/spec/frontend/jobs/components/job/commit_block_spec.js
@@ -32,10 +32,6 @@ describe('Commit block', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('without merge request', () => {
beforeEach(() => {
mountComponent();
diff --git a/spec/frontend/jobs/components/job/environments_block_spec.js b/spec/frontend/jobs/components/job/environments_block_spec.js
index 134533e2af8..ab36f79ea5e 100644
--- a/spec/frontend/jobs/components/job/environments_block_spec.js
+++ b/spec/frontend/jobs/components/job/environments_block_spec.js
@@ -51,11 +51,6 @@ describe('Environments block', () => {
const findEnvironmentLink = () => wrapper.find('[data-testid="job-environment-link"]');
const findClusterLink = () => wrapper.find('[data-testid="job-cluster-link"]');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('with last deployment', () => {
it('renders info for most recent deployment', () => {
createComponent({
diff --git a/spec/frontend/jobs/components/job/erased_block_spec.js b/spec/frontend/jobs/components/job/erased_block_spec.js
index c6aba01fa53..aeab676fc7e 100644
--- a/spec/frontend/jobs/components/job/erased_block_spec.js
+++ b/spec/frontend/jobs/components/job/erased_block_spec.js
@@ -18,10 +18,6 @@ describe('Erased block', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with job erased by user', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/jobs/components/job/job_app_spec.js b/spec/frontend/jobs/components/job/job_app_spec.js
index cefedcd82fb..394fc8ad43c 100644
--- a/spec/frontend/jobs/components/job/job_app_spec.js
+++ b/spec/frontend/jobs/components/job/job_app_spec.js
@@ -83,8 +83,9 @@ describe('Job App', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
+ wrapper.destroy();
});
describe('while loading', () => {
diff --git a/spec/frontend/jobs/components/job/job_container_item_spec.js b/spec/frontend/jobs/components/job/job_container_item_spec.js
index 05c38dd74b7..8121aa1172f 100644
--- a/spec/frontend/jobs/components/job/job_container_item_spec.js
+++ b/spec/frontend/jobs/components/job/job_container_item_spec.js
@@ -24,11 +24,6 @@ describe('JobContainerItem', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when a job is not active and not retried', () => {
beforeEach(() => {
createComponent(job);
diff --git a/spec/frontend/jobs/components/job/job_log_controllers_spec.js b/spec/frontend/jobs/components/job/job_log_controllers_spec.js
index 5e9a73b4387..9917c63b2d0 100644
--- a/spec/frontend/jobs/components/job/job_log_controllers_spec.js
+++ b/spec/frontend/jobs/components/job/job_log_controllers_spec.js
@@ -285,6 +285,18 @@ describe('Job log controllers', () => {
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);
+ });
+ });
});
});
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
index d60043f33f7..712269a1e83 100644
--- 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
@@ -64,13 +64,11 @@ describe('Job Retry Forward Deployment Modal', () => {
beforeEach(createWrapper);
it('should correctly configure the primary action', () => {
- expect(findModal().props('actionPrimary').attributes).toMatchObject([
- {
- 'data-method': 'post',
- href: job.retry_path,
- variant: 'danger',
- },
- ]);
+ expect(findModal().props('actionPrimary').attributes).toMatchObject({
+ 'data-method': 'post',
+ href: job.retry_path,
+ variant: 'danger',
+ });
});
});
});
diff --git a/spec/frontend/jobs/components/job/jobs_container_spec.js b/spec/frontend/jobs/components/job/jobs_container_spec.js
index 2fde4d3020b..05660880751 100644
--- a/spec/frontend/jobs/components/job/jobs_container_spec.js
+++ b/spec/frontend/jobs/components/job/jobs_container_spec.js
@@ -68,10 +68,6 @@ describe('Jobs List block', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a list of jobs', () => {
createComponent({
jobs: [job, retried, active],
diff --git a/spec/frontend/jobs/components/job/manual_variables_form_spec.js b/spec/frontend/jobs/components/job/manual_variables_form_spec.js
index a5b3b0e3b47..98b9ca78a45 100644
--- a/spec/frontend/jobs/components/job/manual_variables_form_spec.js
+++ b/spec/frontend/jobs/components/job/manual_variables_form_spec.js
@@ -2,24 +2,28 @@ 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';
import ManualVariablesForm from '~/jobs/components/job/manual_variables_form.vue';
import getJobQuery from '~/jobs/components/job/graphql/queries/get_job.query.graphql';
-import retryJobMutation from '~/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql';
+import playJobMutation from '~/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql';
import {
mockFullPath,
mockId,
mockJobResponse,
mockJobWithVariablesResponse,
- mockJobMutationData,
+ mockJobPlayMutationData,
+ mockJobRetryMutationData,
} from './mock_data';
const localVue = createLocalVue();
+jest.mock('~/alert');
localVue.use(VueApollo);
jest.mock('~/lib/utils/url_utility', () => ({
@@ -39,9 +43,9 @@ describe('Manual Variables Form', () => {
const createComponent = ({ options = {}, props = {} } = {}) => {
wrapper = mountExtended(ManualVariablesForm, {
propsData: {
- ...props,
jobId: mockId,
- isRetryable: true,
+ isRetryable: false,
+ ...props,
},
provide: {
...defaultProvide,
@@ -71,7 +75,7 @@ describe('Manual Variables Form', () => {
const findHelpText = () => wrapper.findComponent(GlSprintf);
const findHelpLink = () => wrapper.findComponent(GlLink);
const findCancelBtn = () => wrapper.findByTestId('cancel-btn');
- const findRerunBtn = () => wrapper.findByTestId('run-manual-job-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');
@@ -97,7 +101,7 @@ describe('Manual Variables Form', () => {
});
afterEach(() => {
- wrapper.destroy();
+ createAlert.mockClear();
});
describe('when page renders', () => {
@@ -112,10 +116,30 @@ describe('Manual Variables Form', () => {
'/help/ci/variables/index#add-a-cicd-variable-to-a-project',
);
});
+ });
- it('renders buttons', () => {
- expect(findCancelBtn().exists()).toBe(true);
- expect(findRerunBtn().exists()).toBe(true);
+ describe('when query is unsuccessful', () => {
+ beforeEach(async () => {
+ getJobQueryResponse.mockRejectedValue({});
+ await createComponentWithApollo();
+ });
+
+ it('shows an alert with error', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText,
+ });
+ });
+ });
+
+ describe('when job has not been retried', () => {
+ beforeEach(async () => {
+ getJobQueryResponse.mockResolvedValue(mockJobWithVariablesResponse);
+ await createComponentWithApollo();
+ });
+
+ it('does not render the cancel button', () => {
+ expect(findCancelBtn().exists()).toBe(false);
+ expect(findRunBtn().exists()).toBe(true);
});
});
@@ -135,10 +159,10 @@ describe('Manual Variables Form', () => {
});
});
- describe('when mutation fires', () => {
+ describe('when play mutation fires', () => {
beforeEach(async () => {
await createComponentWithApollo();
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockJobMutationData);
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockJobPlayMutationData);
});
it('passes variables in correct format', async () => {
@@ -146,11 +170,11 @@ describe('Manual Variables Form', () => {
await findCiVariableValue().setValue('new value');
- await findRerunBtn().vm.$emit('click');
+ await findRunBtn().vm.$emit('click');
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: retryJobMutation,
+ mutation: playJobMutation,
variables: {
id: convertToGraphQLId(TYPENAME_CI_BUILD, mockId),
variables: [
@@ -163,13 +187,63 @@ describe('Manual Variables Form', () => {
});
});
- // redirect to job after initial trigger assertion will be added in https://gitlab.com/gitlab-org/gitlab/-/issues/377268
+ it('redirects to job properly after job is run', async () => {
+ findRunBtn().vm.$emit('click');
+ await waitForPromises();
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(1);
+ expect(redirectTo).toHaveBeenCalledWith(mockJobPlayMutationData.data.jobPlay.job.webPath);
+ });
+ });
+
+ describe('when play mutation is unsuccessful', () => {
+ beforeEach(async () => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockRejectedValue({});
+ await createComponentWithApollo();
+ });
+
+ 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 createComponentWithApollo({ props: { isRetryable: true } });
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockJobRetryMutationData);
+ });
+
+ it('renders cancel button', () => {
+ expect(findCancelBtn().exists()).toBe(true);
+ });
+
it('redirects to job properly after rerun', async () => {
- findRerunBtn().vm.$emit('click');
+ findRunBtn().vm.$emit('click');
await waitForPromises();
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(1);
- expect(redirectTo).toHaveBeenCalledWith(mockJobMutationData.data.jobRetry.job.webPath);
+ expect(redirectTo).toHaveBeenCalledWith(mockJobRetryMutationData.data.jobRetry.job.webPath);
+ });
+ });
+
+ describe('when retry mutation is unsuccessful', () => {
+ beforeEach(async () => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockRejectedValue({});
+ await createComponentWithApollo({ props: { isRetryable: true } });
+ });
+
+ it('shows an alert with error', async () => {
+ findRunBtn().vm.$emit('click');
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText,
+ });
});
});
diff --git a/spec/frontend/jobs/components/job/mock_data.js b/spec/frontend/jobs/components/job/mock_data.js
index 8a838acca7a..fb3a361c9c9 100644
--- a/spec/frontend/jobs/components/job/mock_data.js
+++ b/spec/frontend/jobs/components/job/mock_data.js
@@ -50,7 +50,32 @@ export const mockJobWithVariablesResponse = {
},
};
-export const mockJobMutationData = {
+export const mockJobPlayMutationData = {
+ data: {
+ jobPlay: {
+ job: {
+ id: 'gid://gitlab/Ci::Build/401',
+ manualVariables: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Ci::JobVariable/151',
+ key: 'new key',
+ value: 'new value',
+ __typename: 'CiManualVariable',
+ },
+ ],
+ __typename: 'CiManualVariableConnection',
+ },
+ webPath: '/Commit451/lab-coat/-/jobs/401',
+ __typename: 'CiJob',
+ },
+ errors: [],
+ __typename: 'JobPlayPayload',
+ },
+ },
+};
+
+export const mockJobRetryMutationData = {
data: {
jobRetry: {
job: {
diff --git a/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js b/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js
index 5c9c011b4ab..dd5a9e3491d 100644
--- a/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js
+++ b/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js
@@ -19,11 +19,6 @@ describe('Sidebar detail row', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('with title/value and without helpUrl', () => {
beforeEach(() => {
createComponent({ title, value });
diff --git a/spec/frontend/jobs/components/job/sidebar_spec.js b/spec/frontend/jobs/components/job/sidebar_spec.js
index aa9ca932023..cefa4582c15 100644
--- a/spec/frontend/jobs/components/job/sidebar_spec.js
+++ b/spec/frontend/jobs/components/job/sidebar_spec.js
@@ -48,10 +48,6 @@ describe('Sidebar details block', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('without terminal path', () => {
it('does not render terminal link', async () => {
createWrapper();
diff --git a/spec/frontend/jobs/components/job/stages_dropdown_spec.js b/spec/frontend/jobs/components/job/stages_dropdown_spec.js
index 61dec585e82..f782d5600e6 100644
--- a/spec/frontend/jobs/components/job/stages_dropdown_spec.js
+++ b/spec/frontend/jobs/components/job/stages_dropdown_spec.js
@@ -37,10 +37,6 @@ describe('Stages Dropdown', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('without a merge request pipeline', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/jobs/components/job/trigger_block_spec.js b/spec/frontend/jobs/components/job/trigger_block_spec.js
index a1de8fd143f..8bb2c1f3ad8 100644
--- a/spec/frontend/jobs/components/job/trigger_block_spec.js
+++ b/spec/frontend/jobs/components/job/trigger_block_spec.js
@@ -20,10 +20,6 @@ describe('Trigger block', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with short token and no variables', () => {
it('renders short token', () => {
createComponent({
diff --git a/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js b/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js
index fb7d389c4d6..1072cdd6781 100644
--- a/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js
+++ b/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js
@@ -18,10 +18,6 @@ describe('Unmet Prerequisites Block Job component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders an alert with the correct message', () => {
const container = wrapper.findComponent(GlAlert);
const alertMessage =
diff --git a/spec/frontend/jobs/components/log/collapsible_section_spec.js b/spec/frontend/jobs/components/log/collapsible_section_spec.js
index 646935568b1..5adedea28a5 100644
--- a/spec/frontend/jobs/components/log/collapsible_section_spec.js
+++ b/spec/frontend/jobs/components/log/collapsible_section_spec.js
@@ -19,10 +19,6 @@ describe('Job Log Collapsible Section', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with closed section', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/jobs/components/log/duration_badge_spec.js b/spec/frontend/jobs/components/log/duration_badge_spec.js
index 84dae386bdb..644d05366a0 100644
--- a/spec/frontend/jobs/components/log/duration_badge_spec.js
+++ b/spec/frontend/jobs/components/log/duration_badge_spec.js
@@ -20,10 +20,6 @@ describe('Job Log Duration Badge', () => {
createComponent(data);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
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
index ec8e79bba13..16fe753e08a 100644
--- a/spec/frontend/jobs/components/log/line_header_spec.js
+++ b/spec/frontend/jobs/components/log/line_header_spec.js
@@ -29,10 +29,6 @@ describe('Job Log Header Line', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('line', () => {
beforeEach(() => {
createComponent(data);
diff --git a/spec/frontend/jobs/components/log/line_number_spec.js b/spec/frontend/jobs/components/log/line_number_spec.js
index 96aa31baab9..4130c124a30 100644
--- a/spec/frontend/jobs/components/log/line_number_spec.js
+++ b/spec/frontend/jobs/components/log/line_number_spec.js
@@ -21,10 +21,6 @@ describe('Job Log Line Number', () => {
createComponent(data);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders incremented lineNunber by 1', () => {
expect(wrapper.text()).toBe('1');
});
diff --git a/spec/frontend/jobs/components/log/log_spec.js b/spec/frontend/jobs/components/log/log_spec.js
index c933ed5c3e1..265f72ff344 100644
--- a/spec/frontend/jobs/components/log/log_spec.js
+++ b/spec/frontend/jobs/components/log/log_spec.js
@@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
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';
@@ -10,6 +11,7 @@ describe('Job Log', () => {
let actions;
let state;
let store;
+ let toggleCollapsibleLineMock;
Vue.use(Vuex);
@@ -20,8 +22,9 @@ describe('Job Log', () => {
};
beforeEach(() => {
+ toggleCollapsibleLineMock = jest.fn();
actions = {
- toggleCollapsibleLine: () => {},
+ toggleCollapsibleLine: toggleCollapsibleLineMock,
};
state = {
@@ -37,11 +40,7 @@ describe('Job Log', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
- const findCollapsibleLine = () => wrapper.find('.collapsible-line');
+ const findCollapsibleLine = () => wrapper.findComponent(LogLineHeader);
describe('line numbers', () => {
it('renders a line number for each open line', () => {
@@ -68,11 +67,9 @@ describe('Job Log', () => {
describe('on click header section', () => {
it('calls toggleCollapsibleLine', () => {
- jest.spyOn(wrapper.vm, 'toggleCollapsibleLine');
-
findCollapsibleLine().trigger('click');
- expect(wrapper.vm.toggleCollapsibleLine).toHaveBeenCalled();
+ expect(toggleCollapsibleLineMock).toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/jobs/components/table/cells/duration_cell_spec.js b/spec/frontend/jobs/components/table/cells/duration_cell_spec.js
index 763a4b0eaa2..d015edb0e91 100644
--- a/spec/frontend/jobs/components/table/cells/duration_cell_spec.js
+++ b/spec/frontend/jobs/components/table/cells/duration_cell_spec.js
@@ -22,10 +22,6 @@ describe('Duration Cell', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not display duration or finished time when no properties are present', () => {
createComponent();
diff --git a/spec/frontend/jobs/components/table/cells/job_cell_spec.js b/spec/frontend/jobs/components/table/cells/job_cell_spec.js
index ddc196129a7..73e37eed5f1 100644
--- a/spec/frontend/jobs/components/table/cells/job_cell_spec.js
+++ b/spec/frontend/jobs/components/table/cells/job_cell_spec.js
@@ -39,10 +39,6 @@ describe('Job Cell', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Job Id', () => {
it('displays the job id and links to the job', () => {
createComponent();
diff --git a/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js b/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js
index 1f5e0a7aa21..3d424b20964 100644
--- a/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js
+++ b/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js
@@ -42,10 +42,6 @@ describe('Pipeline Cell', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Pipeline Id', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/jobs/components/table/graphql/cache_config_spec.js b/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
index 88c97285b85..e3b1ca1cce3 100644
--- a/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
+++ b/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
@@ -84,4 +84,23 @@ describe('jobs/components/table/graphql/cache_config', () => {
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
index 109cef6f817..6247cfcc640 100644
--- a/spec/frontend/jobs/components/table/job_table_app_spec.js
+++ b/spec/frontend/jobs/components/table/job_table_app_spec.js
@@ -12,8 +12,9 @@ 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 '~/flash';
+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';
@@ -23,12 +24,13 @@ import {
mockJobsResponsePaginated,
mockJobsResponseEmpty,
mockFailedSearchToken,
+ mockJobsCountResponse,
} from '../../mock_data';
const projectPath = 'gitlab-org/gitlab';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Job table app', () => {
let wrapper;
@@ -37,6 +39,8 @@ describe('Job table app', () => {
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(GlSkeletonLoader);
const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
const findTable = () => wrapper.findComponent(JobsTable);
@@ -48,14 +52,18 @@ describe('Job table app', () => {
const triggerInfiniteScroll = () =>
wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
- const createMockApolloProvider = (handler) => {
- const requestHandlers = [[getJobsQuery, handler]];
+ const createMockApolloProvider = (handler, countHandler) => {
+ const requestHandlers = [
+ [getJobsQuery, handler],
+ [getJobsCountQuery, countHandler],
+ ];
return createMockApollo(requestHandlers);
};
const createComponent = ({
handler = successHandler,
+ countHandler = countSuccessHandler,
mountFn = shallowMount,
data = {},
} = {}) => {
@@ -68,14 +76,10 @@ describe('Job table app', () => {
provide: {
fullPath: projectPath,
},
- apolloProvider: createMockApolloProvider(handler),
+ apolloProvider: createMockApolloProvider(handler, countHandler),
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('loading state', () => {
it('should display skeleton loader when loading', () => {
createComponent();
@@ -148,12 +152,39 @@ describe('Job table app', () => {
});
describe('error state', () => {
- it('should show an alert if there is an error fetching the data', async () => {
+ it('should show an alert if there is an error fetching the jobs data', async () => {
createComponent({ handler: failedHandler });
await waitForPromises();
- expect(findAlert().exists()).toBe(true);
+ 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);
});
});
diff --git a/spec/frontend/jobs/components/table/jobs_table_spec.js b/spec/frontend/jobs/components/table/jobs_table_spec.js
index 3c4f2d624fe..06b13aa4372 100644
--- a/spec/frontend/jobs/components/table/jobs_table_spec.js
+++ b/spec/frontend/jobs/components/table/jobs_table_spec.js
@@ -30,10 +30,6 @@ describe('Jobs Table', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays the jobs table', () => {
expect(findTable().exists()).toBe(true);
});
diff --git a/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js b/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js
index 23632001060..70bcac82a3f 100644
--- a/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js
+++ b/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js
@@ -42,10 +42,6 @@ describe('Jobs Table Tabs', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays All tab with count', () => {
expect(trimText(findAllTab().text())).toBe(`All ${defaultProps.allJobsCount}`);
});
diff --git a/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js b/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js
index 1d3845b19bb..098a63719fe 100644
--- a/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js
+++ b/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js
@@ -16,11 +16,6 @@ describe('DelayedJobMixin', () => {
template: '<div>{{remainingTime}}</div>',
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('if job is empty object', () => {
beforeEach(() => {
wrapper = shallowMount(dummyComponent, {
diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js
index 9abd610c26d..483b4ca711f 100644
--- a/spec/frontend/jobs/mock_data.js
+++ b/spec/frontend/jobs/mock_data.js
@@ -1,3 +1,4 @@
+import mockJobsCount from 'test_fixtures/graphql/jobs/get_jobs_count.query.graphql.json';
import mockJobsEmpty from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.empty.json';
import mockJobsPaginated from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.paginated.json';
import mockJobs from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.json';
@@ -13,6 +14,7 @@ export const mockJobsResponsePaginated = mockJobsPaginated;
export const mockJobsResponseEmpty = mockJobsEmpty;
export const mockJobsNodes = mockJobs.data.project.jobs.nodes;
export const mockJobsNodesAsGuest = mockJobsAsGuest.data.project.jobs.nodes;
+export const mockJobsCountResponse = mockJobsCount;
export const stages = [
{
diff --git a/spec/frontend/labels/components/delete_label_modal_spec.js b/spec/frontend/labels/components/delete_label_modal_spec.js
index 24a803d3f16..7654d218209 100644
--- a/spec/frontend/labels/components/delete_label_modal_spec.js
+++ b/spec/frontend/labels/components/delete_label_modal_spec.js
@@ -30,10 +30,6 @@ describe('~/labels/components/delete_label_modal', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findModal = () => wrapper.findComponent(GlModal);
const findPrimaryModalButton = () => wrapper.findByTestId('delete-button');
diff --git a/spec/frontend/labels/components/promote_label_modal_spec.js b/spec/frontend/labels/components/promote_label_modal_spec.js
index 97913c20229..5983c16a9d1 100644
--- a/spec/frontend/labels/components/promote_label_modal_spec.js
+++ b/spec/frontend/labels/components/promote_label_modal_spec.js
@@ -41,7 +41,6 @@ describe('Promote label modal', () => {
afterEach(() => {
axiosMock.reset();
- wrapper.destroy();
});
describe('Modal title and description', () => {
diff --git a/spec/frontend/language_switcher/components/app_spec.js b/spec/frontend/language_switcher/components/app_spec.js
index 7f6fb138d89..036ff55fef7 100644
--- a/spec/frontend/language_switcher/components/app_spec.js
+++ b/spec/frontend/language_switcher/components/app_spec.js
@@ -24,10 +24,6 @@ describe('<LanguageSwitcher />', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const getPreferredLanguage = () => wrapper.find('.gl-new-dropdown-button-text').text();
const findLanguageDropdownItem = (code) => wrapper.findByTestId(`language_switcher_lang_${code}`);
const findFooter = () => wrapper.findByTestId('footer');
diff --git a/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js b/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js
index 5ac7a7985a8..b8847f0fca3 100644
--- a/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js
+++ b/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js
@@ -6,13 +6,8 @@ import { isNavigatingAway } from '~/lib/utils/is_navigating_away';
jest.mock('~/lib/utils/is_navigating_away');
describe('getSuppressNetworkErrorsDuringNavigationLink', () => {
- const originalGon = window.gon;
let subscription;
- beforeEach(() => {
- window.gon = originalGon;
- });
-
afterEach(() => {
if (subscription) {
subscription.unsubscribe();
diff --git a/spec/frontend/lib/dompurify_spec.js b/spec/frontend/lib/dompurify_spec.js
index f767a673553..fdc8789c1a8 100644
--- a/spec/frontend/lib/dompurify_spec.js
+++ b/spec/frontend/lib/dompurify_spec.js
@@ -49,8 +49,6 @@ const forbiddenDataAttrs = defaultConfig.FORBID_ATTR;
const acceptedDataAttrs = ['data-random', 'data-custom'];
describe('~/lib/dompurify', () => {
- let originalGon;
-
it('uses local configuration when given', () => {
// As dompurify uses a "Persistent Configuration", it might
// ignore config, this check verifies we respect
@@ -104,15 +102,10 @@ describe('~/lib/dompurify', () => {
${'root'} | ${rootGon}
${'absolute'} | ${absoluteGon}
`('when gon contains $type icon urls', ({ type, gon }) => {
- beforeAll(() => {
- originalGon = window.gon;
+ beforeEach(() => {
window.gon = gon;
});
- afterAll(() => {
- window.gon = originalGon;
- });
-
it('allows no href attrs', () => {
const htmlHref = `<svg><use></use></svg>`;
expect(sanitize(htmlHref)).toBe(htmlHref);
@@ -137,14 +130,9 @@ describe('~/lib/dompurify', () => {
describe('when gon does not contain icon urls', () => {
beforeAll(() => {
- originalGon = window.gon;
window.gon = {};
});
- afterAll(() => {
- window.gon = originalGon;
- });
-
it.each([...safeUrls.root, ...safeUrls.absolute, ...unsafeUrls])('sanitizes URL %s', (url) => {
const htmlHref = `<svg><use href="${url}"></use></svg>`;
const htmlXlink = `<svg><use xlink:href="${url}"></use></svg>`;
diff --git a/spec/frontend/lib/utils/axios_startup_calls_spec.js b/spec/frontend/lib/utils/axios_startup_calls_spec.js
index 4471b781446..3d063ff9b46 100644
--- a/spec/frontend/lib/utils/axios_startup_calls_spec.js
+++ b/spec/frontend/lib/utils/axios_startup_calls_spec.js
@@ -113,17 +113,10 @@ describe('setupAxiosStartupCalls', () => {
});
describe('startup call', () => {
- let oldGon;
-
beforeEach(() => {
- oldGon = window.gon;
window.gon = { gitlab_url: 'https://example.org/gitlab' };
});
- afterEach(() => {
- window.gon = oldGon;
- });
-
it('removes GitLab Base URL from startup call', async () => {
window.gl.startup_calls = {
'/startup': {
diff --git a/spec/frontend/lib/utils/common_utils_spec.js b/spec/frontend/lib/utils/common_utils_spec.js
index 7b068f7d248..b4ec00ab766 100644
--- a/spec/frontend/lib/utils/common_utils_spec.js
+++ b/spec/frontend/lib/utils/common_utils_spec.js
@@ -534,18 +534,10 @@ describe('common_utils', () => {
});
describe('spriteIcon', () => {
- let beforeGon;
-
beforeEach(() => {
- window.gon = window.gon || {};
- beforeGon = { ...window.gon };
window.gon.sprite_icons = 'icons.svg';
});
- afterEach(() => {
- window.gon = beforeGon;
- });
-
it('should return the svg for a linked icon', () => {
expect(commonUtils.spriteIcon('test')).toEqual(
'<svg ><use xlink:href="icons.svg#test" /></svg>',
diff --git a/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js b/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js
index 142c76f7bc0..9b790e739fb 100644
--- a/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js
+++ b/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js
@@ -44,7 +44,6 @@ describe('confirmAction', () => {
resetHTMLFixture();
Vue.prototype.$mount.mockRestore();
modalWrapper?.destroy();
- modalWrapper = null;
modal?.destroy();
modal = null;
});
diff --git a/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_modal_spec.js b/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_modal_spec.js
index 313e028d861..c135180c9df 100644
--- a/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_modal_spec.js
+++ b/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_modal_spec.js
@@ -28,10 +28,6 @@ describe('Confirm Modal', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlModal = () => wrapper.findComponent(GlModal);
describe('Modal events', () => {
diff --git a/spec/frontend/lib/utils/datetime/timeago_utility_spec.js b/spec/frontend/lib/utils/datetime/timeago_utility_spec.js
index 1ef7047d959..c13d55f978e 100644
--- a/spec/frontend/lib/utils/datetime/timeago_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime/timeago_utility_spec.js
@@ -3,16 +3,6 @@ import { s__ } from '~/locale';
import '~/commons/bootstrap';
describe('TimeAgo utils', () => {
- let oldGon;
-
- afterEach(() => {
- window.gon = oldGon;
- });
-
- beforeEach(() => {
- oldGon = window.gon;
- });
-
describe('getTimeago', () => {
describe('with User Setting timeDisplayRelative: true', () => {
beforeEach(() => {
diff --git a/spec/frontend/lib/utils/error_message_spec.js b/spec/frontend/lib/utils/error_message_spec.js
new file mode 100644
index 00000000000..17b5168c32f
--- /dev/null
+++ b/spec/frontend/lib/utils/error_message_spec.js
@@ -0,0 +1,65 @@
+import { parseErrorMessage, USER_FACING_ERROR_MESSAGE_PREFIX } from '~/lib/utils/error_message';
+
+const defaultErrorMessage = 'Something caused this error';
+const userFacingErrorMessage = 'User facing error message';
+const nonUserFacingErrorMessage = 'NonUser facing error message';
+const genericErrorMessage = 'Some error message';
+
+describe('error message', () => {
+ describe('when given an errormessage object', () => {
+ const errorMessageObject = {
+ options: {
+ cause: defaultErrorMessage,
+ },
+ filename: 'error.js',
+ linenumber: 7,
+ };
+
+ it('returns the correct values for userfacing errors', () => {
+ const userFacingObject = errorMessageObject;
+ userFacingObject.message = `${USER_FACING_ERROR_MESSAGE_PREFIX} ${userFacingErrorMessage}`;
+
+ expect(parseErrorMessage(userFacingObject)).toEqual({
+ message: userFacingErrorMessage,
+ userFacing: true,
+ });
+ });
+
+ it('returns the correct values for non userfacing errors', () => {
+ const nonUserFacingObject = errorMessageObject;
+ nonUserFacingObject.message = nonUserFacingErrorMessage;
+
+ expect(parseErrorMessage(nonUserFacingObject)).toEqual({
+ message: nonUserFacingErrorMessage,
+ userFacing: false,
+ });
+ });
+ });
+
+ describe('when given an errormessage string', () => {
+ it('returns the correct values for userfacing errors', () => {
+ expect(
+ parseErrorMessage(`${USER_FACING_ERROR_MESSAGE_PREFIX} ${genericErrorMessage}`),
+ ).toEqual({
+ message: genericErrorMessage,
+ userFacing: true,
+ });
+ });
+
+ it('returns the correct values for non userfacing errors', () => {
+ expect(parseErrorMessage(genericErrorMessage)).toEqual({
+ message: genericErrorMessage,
+ userFacing: false,
+ });
+ });
+ });
+
+ describe('when given nothing', () => {
+ it('returns an empty error message', () => {
+ expect(parseErrorMessage()).toEqual({
+ message: '',
+ userFacing: false,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/file_upload_spec.js b/spec/frontend/lib/utils/file_upload_spec.js
index f63af2fe0a4..509ddc7ce86 100644
--- a/spec/frontend/lib/utils/file_upload_spec.js
+++ b/spec/frontend/lib/utils/file_upload_spec.js
@@ -1,5 +1,9 @@
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import fileUpload, { getFilename, validateImageName } from '~/lib/utils/file_upload';
+import fileUpload, {
+ getFilename,
+ validateImageName,
+ validateFileFromAllowList,
+} from '~/lib/utils/file_upload';
describe('File upload', () => {
beforeEach(() => {
@@ -89,3 +93,19 @@ describe('file name validator', () => {
expect(validateImageName(file)).toBe('image.png');
});
});
+
+describe('validateFileFromAllowList', () => {
+ it('returns true if the file type is in the allowed list', () => {
+ const allowList = ['.foo', '.bar'];
+ const fileName = 'file.foo';
+
+ expect(validateFileFromAllowList(fileName, allowList)).toBe(true);
+ });
+
+ it('returns false if the file type is in the allowed list', () => {
+ const allowList = ['.foo', '.bar'];
+ const fileName = 'file.baz';
+
+ expect(validateFileFromAllowList(fileName, allowList)).toBe(false);
+ });
+});
diff --git a/spec/frontend/lib/utils/number_utility_spec.js b/spec/frontend/lib/utils/number_utility_spec.js
index dc4aa0ea5ed..d2591cd2328 100644
--- a/spec/frontend/lib/utils/number_utility_spec.js
+++ b/spec/frontend/lib/utils/number_utility_spec.js
@@ -3,6 +3,7 @@ import {
bytesToKiB,
bytesToMiB,
bytesToGiB,
+ numberToHumanSizeSplit,
numberToHumanSize,
numberToMetricPrefix,
sum,
@@ -13,6 +14,12 @@ import {
isNumeric,
isPositiveInteger,
} from '~/lib/utils/number_utils';
+import {
+ BYTES_FORMAT_BYTES,
+ BYTES_FORMAT_KIB,
+ BYTES_FORMAT_MIB,
+ BYTES_FORMAT_GIB,
+} from '~/lib/utils/constants';
describe('Number Utils', () => {
describe('formatRelevantDigits', () => {
@@ -78,6 +85,28 @@ describe('Number Utils', () => {
});
});
+ describe('numberToHumanSizeSplit', () => {
+ it('should return bytes', () => {
+ expect(numberToHumanSizeSplit(654)).toEqual(['654', BYTES_FORMAT_BYTES]);
+ expect(numberToHumanSizeSplit(-654)).toEqual(['-654', BYTES_FORMAT_BYTES]);
+ });
+
+ it('should return KiB', () => {
+ expect(numberToHumanSizeSplit(1079)).toEqual(['1.05', BYTES_FORMAT_KIB]);
+ expect(numberToHumanSizeSplit(-1079)).toEqual(['-1.05', BYTES_FORMAT_KIB]);
+ });
+
+ it('should return MiB', () => {
+ expect(numberToHumanSizeSplit(10485764)).toEqual(['10.00', BYTES_FORMAT_MIB]);
+ expect(numberToHumanSizeSplit(-10485764)).toEqual(['-10.00', BYTES_FORMAT_MIB]);
+ });
+
+ it('should return GiB', () => {
+ expect(numberToHumanSizeSplit(10737418240)).toEqual(['10.00', BYTES_FORMAT_GIB]);
+ expect(numberToHumanSizeSplit(-10737418240)).toEqual(['-10.00', BYTES_FORMAT_GIB]);
+ });
+ });
+
describe('numberToHumanSize', () => {
it('should return bytes', () => {
expect(numberToHumanSize(654)).toEqual('654 bytes');
diff --git a/spec/frontend/lib/utils/ref_validator_spec.js b/spec/frontend/lib/utils/ref_validator_spec.js
new file mode 100644
index 00000000000..7185ebf0a24
--- /dev/null
+++ b/spec/frontend/lib/utils/ref_validator_spec.js
@@ -0,0 +1,79 @@
+import { validateTag, validationMessages } from '~/lib/utils/ref_validator';
+
+describe('~/lib/utils/ref_validator', () => {
+ describe('validateTag', () => {
+ describe.each([
+ ['foo'],
+ ['FOO'],
+ ['foo/a.lockx'],
+ ['foo.123'],
+ ['foo/123'],
+ ['foo/bar/123'],
+ ['foo.bar.123'],
+ ['foo-bar_baz'],
+ ['head'],
+ ['"foo"-'],
+ ['foo@bar'],
+ ['\ud83e\udd8a'],
+ ['ünicöde'],
+ ['\x80}'],
+ ])('tag with the name "%s"', (tagName) => {
+ it('is valid', () => {
+ const result = validateTag(tagName);
+ expect(result.isValid).toBe(true);
+ expect(result.validationErrors).toEqual([]);
+ });
+ });
+
+ describe.each([
+ [' ', validationMessages.EmptyNameValidationMessage],
+
+ ['refs/heads/tagName', validationMessages.DisallowedPrefixesValidationMessage],
+ ['/foo', validationMessages.DisallowedPrefixesValidationMessage],
+ ['-tagName', validationMessages.DisallowedPrefixesValidationMessage],
+
+ ['HEAD', validationMessages.DisallowedNameValidationMessage],
+ ['@', validationMessages.DisallowedNameValidationMessage],
+
+ ['tag name with spaces', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag\\name', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag^name', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag..name', validationMessages.DisallowedSubstringsValidationMessage],
+ ['..', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag?name', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag*name', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag[name', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag@{name', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag:name', validationMessages.DisallowedSubstringsValidationMessage],
+ ['tag~name', validationMessages.DisallowedSubstringsValidationMessage],
+
+ ['/', validationMessages.DisallowedSequenceEmptyValidationMessage],
+ ['//', validationMessages.DisallowedSequenceEmptyValidationMessage],
+ ['foo//123', validationMessages.DisallowedSequenceEmptyValidationMessage],
+
+ ['.', validationMessages.DisallowedSequencePrefixesValidationMessage],
+ ['/./', validationMessages.DisallowedSequencePrefixesValidationMessage],
+ ['./.', validationMessages.DisallowedSequencePrefixesValidationMessage],
+ ['.tagName', validationMessages.DisallowedSequencePrefixesValidationMessage],
+ ['tag/.Name', validationMessages.DisallowedSequencePrefixesValidationMessage],
+ ['foo/.123/bar', validationMessages.DisallowedSequencePrefixesValidationMessage],
+
+ ['foo.', validationMessages.DisallowedSequencePostfixesValidationMessage],
+ ['a.lock', validationMessages.DisallowedSequencePostfixesValidationMessage],
+ ['foo/a.lock', validationMessages.DisallowedSequencePostfixesValidationMessage],
+ ['foo/a.lock/b', validationMessages.DisallowedSequencePostfixesValidationMessage],
+ ['foo.123.', validationMessages.DisallowedSequencePostfixesValidationMessage],
+
+ ['foo/', validationMessages.DisallowedPostfixesValidationMessage],
+
+ ['control-character\x7f', validationMessages.ControlCharactersValidationMessage],
+ ['control-character\x15', validationMessages.ControlCharactersValidationMessage],
+ ])('tag with name "%s"', (tagName, validationMessage) => {
+ it(`should be invalid with validation message "${validationMessage}"`, () => {
+ const result = validateTag(tagName);
+ expect(result.isValid).toBe(false);
+ expect(result.validationErrors).toContain(validationMessage);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/text_markdown_spec.js b/spec/frontend/lib/utils/text_markdown_spec.js
index 7aab1013fc0..2180ea7e6c2 100644
--- a/spec/frontend/lib/utils/text_markdown_spec.js
+++ b/spec/frontend/lib/utils/text_markdown_spec.js
@@ -1,12 +1,16 @@
import $ from 'jquery';
+import AxiosMockAdapter from 'axios-mock-adapter';
import {
insertMarkdownText,
keypressNoteText,
compositionStartNoteText,
compositionEndNoteText,
updateTextForToolbarBtn,
+ resolveSelectedImage,
} from '~/lib/utils/text_markdown';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import '~/lib/utils/jquery_at_who';
+import axios from '~/lib/utils/axios_utils';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
describe('init markdown', () => {
@@ -14,6 +18,7 @@ describe('init markdown', () => {
let textArea;
let indentButton;
let outdentButton;
+ let axiosMock;
beforeAll(() => {
setHTMLFixture(
@@ -34,6 +39,14 @@ describe('init markdown', () => {
document.execCommand = jest.fn(() => false);
});
+ beforeEach(() => {
+ axiosMock = new AxiosMockAdapter(axios);
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+ });
+
afterAll(() => {
resetHTMLFixture();
});
@@ -707,6 +720,55 @@ describe('init markdown', () => {
});
});
+ describe('resolveSelectedImage', () => {
+ const markdownPreviewPath = '/markdown/preview';
+ const imageMarkdown = '![image](/uploads/image.png)';
+ const imageAbsoluteUrl = '/abs/uploads/image.png';
+
+ describe('when textarea cursor is positioned on an image', () => {
+ beforeEach(() => {
+ axiosMock.onPost(markdownPreviewPath, { text: imageMarkdown }).reply(HTTP_STATUS_OK, {
+ body: `
+ <p><a href="${imageAbsoluteUrl}"><img src="${imageAbsoluteUrl}"></a></p>
+ `,
+ });
+ });
+
+ it('returns the image absolute URL, markdown, and filename', async () => {
+ textArea.value = `image ${imageMarkdown}`;
+ textArea.setSelectionRange(8, 8);
+ expect(await resolveSelectedImage(textArea, markdownPreviewPath)).toEqual({
+ imageURL: imageAbsoluteUrl,
+ imageMarkdown,
+ filename: 'image.png',
+ });
+ });
+ });
+
+ describe('when textarea cursor is not positioned on an image', () => {
+ it.each`
+ markdown | selectionRange
+ ${`image ${imageMarkdown}`} | ${[4, 4]}
+ ${`!2 (issue)`} | ${[2, 2]}
+ `('returns null', async ({ markdown, selectionRange }) => {
+ textArea.value = markdown;
+ textArea.setSelectionRange(...selectionRange);
+ expect(await resolveSelectedImage(textArea, markdownPreviewPath)).toBe(null);
+ });
+ });
+
+ describe('when textarea cursor is positioned between images', () => {
+ it('returns null', async () => {
+ const position = imageMarkdown.length + 1;
+
+ textArea.value = `${imageMarkdown}\n\n${imageMarkdown}`;
+ textArea.setSelectionRange(position, position);
+
+ expect(await resolveSelectedImage(textArea, markdownPreviewPath)).toBe(null);
+ });
+ });
+ });
+
describe('Source Editor', () => {
let editor;
diff --git a/spec/frontend/lib/utils/text_utility_spec.js b/spec/frontend/lib/utils/text_utility_spec.js
index f2572ca0ad2..71a84d56791 100644
--- a/spec/frontend/lib/utils/text_utility_spec.js
+++ b/spec/frontend/lib/utils/text_utility_spec.js
@@ -398,4 +398,36 @@ describe('text_utility', () => {
expect(textUtils.base64DecodeUnicode('8J+YgA==')).toBe('😀');
});
});
+
+ describe('findInvalidBranchNameCharacters', () => {
+ const invalidChars = [' ', '~', '^', ':', '?', '*', '[', '..', '@{', '\\', '//'];
+ const badBranchName = 'branch-with all these ~ ^ : ? * [ ] \\ // .. @{ } //';
+ const goodBranch = 'branch-with-no-errrors';
+
+ it('returns an array of invalid characters in a branch name', () => {
+ const chars = textUtils.findInvalidBranchNameCharacters(badBranchName);
+ chars.forEach((char) => {
+ expect(invalidChars).toContain(char);
+ });
+ });
+
+ it('returns an empty array with no invalid characters', () => {
+ expect(textUtils.findInvalidBranchNameCharacters(goodBranch)).toEqual([]);
+ });
+ });
+
+ describe('humanizeBranchValidationErrors', () => {
+ it.each`
+ errors | message
+ ${[' ']} | ${"Can't contain spaces"}
+ ${['?', '//', ' ']} | ${"Can't contain spaces, ?, //"}
+ ${['\\', '[', '..']} | ${"Can't contain \\, [, .."}
+ `('returns an $message with $errors', ({ errors, message }) => {
+ expect(textUtils.humanizeBranchValidationErrors(errors)).toEqual(message);
+ });
+
+ it('returns an empty string with no invalid characters', () => {
+ expect(textUtils.humanizeBranchValidationErrors([])).toEqual('');
+ });
+ });
});
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index 6afdab455a6..72556e6bbe2 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -45,10 +45,6 @@ describe('URL utility', () => {
});
describe('webIDEUrl', () => {
- afterEach(() => {
- gon.relative_url_root = '';
- });
-
it('escapes special characters', () => {
expect(urlUtils.webIDEUrl('/gitlab-org/gitlab-#-foss/merge_requests/1')).toBe(
'/-/ide/project/gitlab-org/gitlab-%23-foss/merge_requests/1',
@@ -505,10 +501,6 @@ describe('URL utility', () => {
gon.gitlab_url = gitlabUrl;
});
- afterEach(() => {
- gon.gitlab_url = '';
- });
-
it.each`
url | urlType | external
${'/gitlab-org/gitlab-test/-/issues/2'} | ${'relative'} | ${false}
diff --git a/spec/frontend/lib/utils/vuex_module_mappers_spec.js b/spec/frontend/lib/utils/vuex_module_mappers_spec.js
index d25a692dfea..abd5095c1d2 100644
--- a/spec/frontend/lib/utils/vuex_module_mappers_spec.js
+++ b/spec/frontend/lib/utils/vuex_module_mappers_spec.js
@@ -96,10 +96,6 @@ describe('~/lib/utils/vuex_module_mappers', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('from module defined by prop', () => {
it('maps state', () => {
expect(getMappedState()).toEqual({
diff --git a/spec/frontend/locale/sprintf_spec.js b/spec/frontend/locale/sprintf_spec.js
index e0d0e117ea4..a7e245e2b78 100644
--- a/spec/frontend/locale/sprintf_spec.js
+++ b/spec/frontend/locale/sprintf_spec.js
@@ -84,5 +84,16 @@ describe('locale', () => {
expect(output).toBe('contains duplicated 15%');
});
});
+
+ describe('ignores special replacements in the input', () => {
+ it.each(['$$', '$&', '$`', `$'`])('replacement "%s" is ignored', (replacement) => {
+ const input = 'My odd %{replacement} is preserved';
+
+ const parameters = { replacement };
+
+ const output = sprintf(input, parameters, false);
+ expect(output).toBe(`My odd ${replacement} is preserved`);
+ });
+ });
});
});
diff --git a/spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js b/spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js
index b94964dc482..c2e0e44f97f 100644
--- a/spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js
+++ b/spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js
@@ -20,10 +20,6 @@ describe('AccessRequestActionButtons', () => {
const findRemoveMemberButton = () => wrapper.findComponent(RemoveMemberButton);
const findApproveButton = () => wrapper.findComponent(ApproveAccessRequestButton);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders remove member button', () => {
createComponent();
diff --git a/spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js b/spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js
index 15bb03480e1..7a4cd844425 100644
--- a/spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js
+++ b/spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js
@@ -38,7 +38,7 @@ describe('ApproveAccessRequestButton', () => {
...propsData,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -50,10 +50,6 @@ describe('ApproveAccessRequestButton', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays a tooltip', () => {
const button = findButton();
diff --git a/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js b/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js
index 68009708c99..a852443844b 100644
--- a/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js
+++ b/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js
@@ -19,10 +19,6 @@ describe('InviteActionButtons', () => {
const findRemoveMemberButton = () => wrapper.findComponent(RemoveMemberButton);
const findResendInviteButton = () => wrapper.findComponent(ResendInviteButton);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when user has `canRemove` permissions', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js b/spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js
index b511cebdf28..1d83a2e0e71 100644
--- a/spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js
+++ b/spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js
@@ -37,7 +37,7 @@ describe('RemoveGroupLinkButton', () => {
groupLink: group,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -48,11 +48,6 @@ describe('RemoveGroupLinkButton', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('displays a tooltip', () => {
const button = findButton();
diff --git a/spec/frontend/members/components/action_buttons/remove_member_button_spec.js b/spec/frontend/members/components/action_buttons/remove_member_button_spec.js
index cca340169b7..3879279b559 100644
--- a/spec/frontend/members/components/action_buttons/remove_member_button_spec.js
+++ b/spec/frontend/members/components/action_buttons/remove_member_button_spec.js
@@ -47,7 +47,7 @@ describe('RemoveMemberButton', () => {
...propsData,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -58,10 +58,6 @@ describe('RemoveMemberButton', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('sets attributes on button', () => {
expect(wrapper.attributes()).toMatchObject({
'aria-label': 'Remove member',
diff --git a/spec/frontend/members/components/action_buttons/resend_invite_button_spec.js b/spec/frontend/members/components/action_buttons/resend_invite_button_spec.js
index 51cfd47ddf4..a6b5978b566 100644
--- a/spec/frontend/members/components/action_buttons/resend_invite_button_spec.js
+++ b/spec/frontend/members/components/action_buttons/resend_invite_button_spec.js
@@ -38,7 +38,7 @@ describe('ResendInviteButton', () => {
...propsData,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -50,10 +50,6 @@ describe('ResendInviteButton', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays a tooltip', () => {
expect(getBinding(findButton().element, 'gl-tooltip')).not.toBeUndefined();
expect(findButton().attributes('title')).toBe('Resend invite');
diff --git a/spec/frontend/members/components/action_dropdowns/leave_group_dropdown_item_spec.js b/spec/frontend/members/components/action_dropdowns/leave_group_dropdown_item_spec.js
index 90f5b217007..679ad7897ed 100644
--- a/spec/frontend/members/components/action_dropdowns/leave_group_dropdown_item_spec.js
+++ b/spec/frontend/members/components/action_dropdowns/leave_group_dropdown_item_spec.js
@@ -18,7 +18,7 @@ describe('LeaveGroupDropdownItem', () => {
...propsData,
},
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
},
slots: {
default: text,
@@ -32,10 +32,6 @@ describe('LeaveGroupDropdownItem', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a slot with red text', () => {
expect(findDropdownItem().html()).toContain(`<span class="gl-text-red-500">${text}</span>`);
});
diff --git a/spec/frontend/members/components/action_dropdowns/remove_member_dropdown_item_spec.js b/spec/frontend/members/components/action_dropdowns/remove_member_dropdown_item_spec.js
index e1c498249d7..125f1f8fff3 100644
--- a/spec/frontend/members/components/action_dropdowns/remove_member_dropdown_item_spec.js
+++ b/spec/frontend/members/components/action_dropdowns/remove_member_dropdown_item_spec.js
@@ -58,10 +58,6 @@ describe('RemoveMemberDropdownItem', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a slot with red text', () => {
expect(findDropdownItem().html()).toContain(`<span class="gl-text-red-500">${text}</span>`);
});
diff --git a/spec/frontend/members/components/action_dropdowns/user_action_dropdown_spec.js b/spec/frontend/members/components/action_dropdowns/user_action_dropdown_spec.js
index 5a2de1cac80..448c04bcb69 100644
--- a/spec/frontend/members/components/action_dropdowns/user_action_dropdown_spec.js
+++ b/spec/frontend/members/components/action_dropdowns/user_action_dropdown_spec.js
@@ -24,17 +24,13 @@ describe('UserActionDropdown', () => {
...propsData,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
const findRemoveMemberDropdownItem = () => wrapper.findComponent(RemoveMemberDropdownItem);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when user has `canRemove` permissions', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/members/components/app_spec.js b/spec/frontend/members/components/app_spec.js
index d105a4d9fde..b2147163233 100644
--- a/spec/frontend/members/components/app_spec.js
+++ b/spec/frontend/members/components/app_spec.js
@@ -49,7 +49,6 @@ describe('MembersApp', () => {
});
afterEach(() => {
- wrapper.destroy();
store = null;
});
diff --git a/spec/frontend/members/components/avatars/group_avatar_spec.js b/spec/frontend/members/components/avatars/group_avatar_spec.js
index 13c50de9835..8e4263f88fe 100644
--- a/spec/frontend/members/components/avatars/group_avatar_spec.js
+++ b/spec/frontend/members/components/avatars/group_avatar_spec.js
@@ -25,10 +25,6 @@ describe('MemberList', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders link to group', () => {
const link = wrapper.findComponent(GlAvatarLink);
diff --git a/spec/frontend/members/components/avatars/invite_avatar_spec.js b/spec/frontend/members/components/avatars/invite_avatar_spec.js
index b197a46c0d1..84878fb9be2 100644
--- a/spec/frontend/members/components/avatars/invite_avatar_spec.js
+++ b/spec/frontend/members/components/avatars/invite_avatar_spec.js
@@ -24,10 +24,6 @@ describe('MemberList', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders email as name', () => {
expect(getByText(invite.email).exists()).toBe(true);
});
diff --git a/spec/frontend/members/components/avatars/user_avatar_spec.js b/spec/frontend/members/components/avatars/user_avatar_spec.js
index 9172876e76f..4808bcb9363 100644
--- a/spec/frontend/members/components/avatars/user_avatar_spec.js
+++ b/spec/frontend/members/components/avatars/user_avatar_spec.js
@@ -26,10 +26,6 @@ describe('UserAvatar', () => {
const findStatusEmoji = (emoji) => wrapper.find(`gl-emoji[data-name="${emoji}"]`);
- afterEach(() => {
- wrapper.destroy();
- });
-
it("renders link to user's profile", () => {
createComponent();
diff --git a/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js b/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js
index ef3c8bde3cf..526f839ece8 100644
--- a/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js
+++ b/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js
@@ -46,7 +46,7 @@ describe('SortDropdown', () => {
const findSortingComponent = () => wrapper.findComponent(GlSorting);
const findSortDirectionToggle = () =>
findSortingComponent().find('button[title^="Sort direction"]');
- const findDropdownToggle = () => wrapper.find('button[aria-haspopup="true"]');
+ const findDropdownToggle = () => wrapper.find('button[aria-haspopup="menu"]');
const findDropdownItemByText = (text) =>
wrapper
.findAllComponents(GlSortingItem)
diff --git a/spec/frontend/members/components/members_tabs_spec.js b/spec/frontend/members/components/members_tabs_spec.js
index 77af5e7293e..9078bd87d62 100644
--- a/spec/frontend/members/components/members_tabs_spec.js
+++ b/spec/frontend/members/components/members_tabs_spec.js
@@ -100,10 +100,6 @@ describe('MembersTabs', () => {
setWindowLocation('https://localhost');
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders `GlTabs` with `syncActiveTabWithQueryParams` and `queryParamName` props set', async () => {
await createComponent();
diff --git a/spec/frontend/members/components/modals/leave_modal_spec.js b/spec/frontend/members/components/modals/leave_modal_spec.js
index ba587c6f0b3..cec5f192e59 100644
--- a/spec/frontend/members/components/modals/leave_modal_spec.js
+++ b/spec/frontend/members/components/modals/leave_modal_spec.js
@@ -60,10 +60,6 @@ describe('LeaveModal', () => {
const findForm = () => findModal().findComponent(GlForm);
const findUserDeletionObstaclesList = () => findModal().findComponent(UserDeletionObstaclesList);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('sets modal ID', async () => {
await createComponent();
diff --git a/spec/frontend/members/components/modals/remove_group_link_modal_spec.js b/spec/frontend/members/components/modals/remove_group_link_modal_spec.js
index af96396f09f..e4782ac7f2e 100644
--- a/spec/frontend/members/components/modals/remove_group_link_modal_spec.js
+++ b/spec/frontend/members/components/modals/remove_group_link_modal_spec.js
@@ -52,11 +52,6 @@ describe('RemoveGroupLinkModal', () => {
const getByText = (text, options) =>
createWrapper(within(findModal().element).getByText(text, options));
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when modal is open', () => {
beforeEach(async () => {
createComponent();
diff --git a/spec/frontend/members/components/modals/remove_member_modal_spec.js b/spec/frontend/members/components/modals/remove_member_modal_spec.js
index 47a03b5083a..baef0b30b02 100644
--- a/spec/frontend/members/components/modals/remove_member_modal_spec.js
+++ b/spec/frontend/members/components/modals/remove_member_modal_spec.js
@@ -54,10 +54,6 @@ describe('RemoveMemberModal', () => {
const findGlModal = () => wrapper.findComponent(GlModal);
const findUserDeletionObstaclesList = () => wrapper.findComponent(UserDeletionObstaclesList);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
state | memberModelType | isAccessRequest | isInvite | actionText | removeSubMembershipsCheckboxExpected | unassignIssuablesCheckboxExpected | message | userDeletionObstacles | isPartOfOncall
${'removing a group member'} | ${MEMBER_MODEL_TYPE_GROUP_MEMBER} | ${false} | ${false} | ${'Remove member'} | ${true} | ${true} | ${'Are you sure you want to remove Jane Doe from the Gitlab Org / Gitlab Test project?'} | ${{}} | ${false}
diff --git a/spec/frontend/members/components/table/created_at_spec.js b/spec/frontend/members/components/table/created_at_spec.js
index fa31177564b..2c0493e7c59 100644
--- a/spec/frontend/members/components/table/created_at_spec.js
+++ b/spec/frontend/members/components/table/created_at_spec.js
@@ -20,10 +20,6 @@ describe('CreatedAt', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('created at text', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/members/components/table/expiration_datepicker_spec.js b/spec/frontend/members/components/table/expiration_datepicker_spec.js
index 9b8f053348b..15812ee6572 100644
--- a/spec/frontend/members/components/table/expiration_datepicker_spec.js
+++ b/spec/frontend/members/components/table/expiration_datepicker_spec.js
@@ -58,10 +58,6 @@ describe('ExpirationDatepicker', () => {
const findInput = () => wrapper.find('input');
const findDatepicker = () => wrapper.findComponent(GlDatepicker);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('datepicker input', () => {
it('sets `member.expiresAt` as initial date', async () => {
createComponent({ member: { ...member, expiresAt: '2020-03-17T00:00:00Z' } });
diff --git a/spec/frontend/members/components/table/member_action_buttons_spec.js b/spec/frontend/members/components/table/member_action_buttons_spec.js
index 95db30a3683..3a04d1dcb0a 100644
--- a/spec/frontend/members/components/table/member_action_buttons_spec.js
+++ b/spec/frontend/members/components/table/member_action_buttons_spec.js
@@ -23,10 +23,6 @@ describe('MemberActions', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
memberType | member | expectedComponent | expectedComponentName
${MEMBER_TYPES.user} | ${memberMock} | ${UserActionDropdown} | ${'UserActionDropdown'}
diff --git a/spec/frontend/members/components/table/member_avatar_spec.js b/spec/frontend/members/components/table/member_avatar_spec.js
index dc5c97f41df..369f8a06cfd 100644
--- a/spec/frontend/members/components/table/member_avatar_spec.js
+++ b/spec/frontend/members/components/table/member_avatar_spec.js
@@ -18,10 +18,6 @@ describe('MemberList', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
memberType | member | expectedComponent | expectedComponentName
${MEMBER_TYPES.user} | ${memberMock} | ${UserAvatar} | ${'UserAvatar'}
diff --git a/spec/frontend/members/components/table/member_source_spec.js b/spec/frontend/members/components/table/member_source_spec.js
index fbfd0ca7ae7..bbfbb19fd92 100644
--- a/spec/frontend/members/components/table/member_source_spec.js
+++ b/spec/frontend/members/components/table/member_source_spec.js
@@ -23,17 +23,13 @@ describe('MemberSource', () => {
...propsData,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
const getTooltipDirective = (elementWrapper) => getBinding(elementWrapper.element, 'gl-tooltip');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('direct member', () => {
describe('when created by is available', () => {
it('displays "Direct member by <user name>"', () => {
diff --git a/spec/frontend/members/components/table/members_table_cell_spec.js b/spec/frontend/members/components/table/members_table_cell_spec.js
index ac5d83d028d..1c6f1b086cf 100644
--- a/spec/frontend/members/components/table/members_table_cell_spec.js
+++ b/spec/frontend/members/components/table/members_table_cell_spec.js
@@ -97,11 +97,6 @@ describe('MembersTableCell', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it.each`
member | expectedMemberType
${memberMock} | ${MEMBER_TYPES.user}
diff --git a/spec/frontend/members/components/table/members_table_spec.js b/spec/frontend/members/components/table/members_table_spec.js
index b8e0d73d8f6..e3c89bfed53 100644
--- a/spec/frontend/members/components/table/members_table_spec.js
+++ b/spec/frontend/members/components/table/members_table_spec.js
@@ -96,10 +96,6 @@ describe('MembersTable', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('fields', () => {
const memberCanUpdate = {
...directMember,
diff --git a/spec/frontend/members/components/table/role_dropdown_spec.js b/spec/frontend/members/components/table/role_dropdown_spec.js
index a11f67be8f5..d6e63b1930f 100644
--- a/spec/frontend/members/components/table/role_dropdown_spec.js
+++ b/spec/frontend/members/components/table/role_dropdown_spec.js
@@ -67,21 +67,13 @@ describe('RoleDropdown', () => {
.findAllComponents(GlDropdownItem)
.wrappers.find((dropdownItemWrapper) => dropdownItemWrapper.props('isChecked'));
- const findDropdownToggle = () => wrapper.find('button[aria-haspopup="true"]');
+ const findDropdownToggle = () => wrapper.find('button[aria-haspopup="menu"]');
const findDropdown = () => wrapper.findComponent(GlDropdown);
- let originalGon;
-
beforeEach(() => {
- originalGon = window.gon;
gon.features = { showOverageOnRolePromotion: true };
});
- afterEach(() => {
- window.gon = originalGon;
- wrapper.destroy();
- });
-
describe('when dropdown is open', () => {
beforeEach(() => {
guestOverageConfirmAction.mockReturnValue(true);
diff --git a/spec/frontend/members/index_spec.js b/spec/frontend/members/index_spec.js
index 5c813eb2a67..b1730cf3746 100644
--- a/spec/frontend/members/index_spec.js
+++ b/spec/frontend/members/index_spec.js
@@ -31,9 +31,6 @@ describe('initMembersApp', () => {
afterEach(() => {
el = null;
-
- wrapper.destroy();
- wrapper = null;
});
it('renders `MembersTabs`', () => {
diff --git a/spec/frontend/merge_conflicts/components/merge_conflict_resolver_app_spec.js b/spec/frontend/merge_conflicts/components/merge_conflict_resolver_app_spec.js
index 9b5641ef7b3..ab913b30f3c 100644
--- a/spec/frontend/merge_conflicts/components/merge_conflict_resolver_app_spec.js
+++ b/spec/frontend/merge_conflicts/components/merge_conflict_resolver_app_spec.js
@@ -37,10 +37,6 @@ describe('Merge Conflict Resolver App', () => {
store.dispatch('setConflictsData', conflictsMock);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findLoadingSpinner = () => wrapper.findByTestId('loading-spinner');
const findConflictsCount = () => wrapper.findByTestId('conflicts-count');
const findFiles = () => wrapper.findAllByTestId('files');
diff --git a/spec/frontend/merge_conflicts/store/actions_spec.js b/spec/frontend/merge_conflicts/store/actions_spec.js
index 19ef4b7db25..d2c4c8b796c 100644
--- a/spec/frontend/merge_conflicts/store/actions_spec.js
+++ b/spec/frontend/merge_conflicts/store/actions_spec.js
@@ -4,13 +4,13 @@ import Cookies from '~/lib/utils/cookies';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { INTERACTIVE_RESOLVE_MODE, EDIT_RESOLVE_MODE } from '~/merge_conflicts/constants';
import * as actions from '~/merge_conflicts/store/actions';
import * as types from '~/merge_conflicts/store/mutation_types';
import { restoreFileLinesState, markLine, decorateFiles } from '~/merge_conflicts/utils';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
jest.mock('~/merge_conflicts/utils');
jest.mock('~/lib/utils/cookies');
@@ -114,7 +114,7 @@ describe('merge conflicts actions', () => {
expect(window.location.assign).toHaveBeenCalledWith('hrefPath');
});
- it('on errors shows flash', async () => {
+ it('on errors shows an alert', async () => {
mock.onPost(resolveConflictsPath).reply(HTTP_STATUS_BAD_REQUEST);
await testAction(
actions.submitResolvedConflicts,
diff --git a/spec/frontend/merge_request_spec.js b/spec/frontend/merge_request_spec.js
index 579cee8c022..be16b5ebfd2 100644
--- a/spec/frontend/merge_request_spec.js
+++ b/spec/frontend/merge_request_spec.js
@@ -3,12 +3,12 @@ import $ from 'jquery';
import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'spec/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_CONFLICT, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import MergeRequest from '~/merge_request';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('MergeRequest', () => {
const test = {};
diff --git a/spec/frontend/merge_request_tabs_spec.js b/spec/frontend/merge_request_tabs_spec.js
index 6d434d7e654..76d1fa3a332 100644
--- a/spec/frontend/merge_request_tabs_spec.js
+++ b/spec/frontend/merge_request_tabs_spec.js
@@ -354,8 +354,6 @@ describe('MergeRequestTabs', () => {
testContext.class.expandSidebar.forEach((el) => {
expect(el.classList.contains('gl-display-none!')).toBe(hides);
});
-
- window.gon = {};
});
describe('when switching tabs', () => {
diff --git a/spec/frontend/merge_requests/components/compare_app_spec.js b/spec/frontend/merge_requests/components/compare_app_spec.js
index 8f84341b653..ba129363ffd 100644
--- a/spec/frontend/merge_requests/components/compare_app_spec.js
+++ b/spec/frontend/merge_requests/components/compare_app_spec.js
@@ -30,10 +30,6 @@ function factory(provideData = {}) {
}
describe('Merge requests compare app component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows commit box when selected branch is empty', () => {
factory({
currentBranch: {
diff --git a/spec/frontend/merge_requests/components/compare_dropdown_spec.js b/spec/frontend/merge_requests/components/compare_dropdown_spec.js
index ab5c315816c..ce03b80bdcb 100644
--- a/spec/frontend/merge_requests/components/compare_dropdown_spec.js
+++ b/spec/frontend/merge_requests/components/compare_dropdown_spec.js
@@ -47,7 +47,6 @@ describe('Merge requests compare dropdown component', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/milestones/components/delete_milestone_modal_spec.js b/spec/frontend/milestones/components/delete_milestone_modal_spec.js
index 87235fa843a..f8730fd93a3 100644
--- a/spec/frontend/milestones/components/delete_milestone_modal_spec.js
+++ b/spec/frontend/milestones/components/delete_milestone_modal_spec.js
@@ -6,10 +6,10 @@ import DeleteMilestoneModal from '~/milestones/components/delete_milestone_modal
import eventHub from '~/milestones/event_hub';
import { HTTP_STATUS_IM_A_TEAPOT, HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
import { redirectTo } from '~/lib/utils/url_utility';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
jest.mock('~/lib/utils/url_utility');
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Delete milestone modal', () => {
let wrapper;
@@ -39,10 +39,6 @@ describe('Delete milestone modal', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('onSubmit', () => {
beforeEach(() => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
diff --git a/spec/frontend/milestones/components/milestone_combobox_spec.js b/spec/frontend/milestones/components/milestone_combobox_spec.js
index f8ddca1a2ad..748e01d4291 100644
--- a/spec/frontend/milestones/components/milestone_combobox_spec.js
+++ b/spec/frontend/milestones/components/milestone_combobox_spec.js
@@ -85,11 +85,6 @@ describe('Milestone combobox component', () => {
mock.onGet(`/api/v4/projects/${projectId}/search`).reply((config) => searchApiCallSpy(config));
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
//
// Finders
//
diff --git a/spec/frontend/milestones/components/promote_milestone_modal_spec.js b/spec/frontend/milestones/components/promote_milestone_modal_spec.js
index d7ad3d29d0a..e91e792afe8 100644
--- a/spec/frontend/milestones/components/promote_milestone_modal_spec.js
+++ b/spec/frontend/milestones/components/promote_milestone_modal_spec.js
@@ -3,14 +3,14 @@ import { shallowMount } from '@vue/test-utils';
import { setHTMLFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
import * as urlUtils from '~/lib/utils/url_utility';
import PromoteMilestoneModal from '~/milestones/components/promote_milestone_modal.vue';
jest.mock('~/lib/utils/url_utility');
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Promote milestone modal', () => {
let wrapper;
@@ -33,10 +33,6 @@ describe('Promote milestone modal', () => {
wrapper = shallowMount(PromoteMilestoneModal);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Modal opener button', () => {
it('button gets disabled when the modal opens', () => {
expect(promoteButton().disabled).toBe(false);
diff --git a/spec/frontend/ml/experiment_tracking/components/__snapshots__/ml_candidate_spec.js.snap b/spec/frontend/ml/experiment_tracking/components/__snapshots__/ml_candidate_spec.js.snap
deleted file mode 100644
index 7d7eee2bc2c..00000000000
--- a/spec/frontend/ml/experiment_tracking/components/__snapshots__/ml_candidate_spec.js.snap
+++ /dev/null
@@ -1,268 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`MlCandidate renders correctly 1`] = `
-<div>
- <div
- class="gl-alert gl-alert-warning"
- >
- <svg
- aria-hidden="true"
- class="gl-icon s16 gl-alert-icon"
- data-testid="warning-icon"
- role="img"
- >
- <use
- href="#warning"
- />
- </svg>
-
- <div
- aria-live="assertive"
- class="gl-alert-content"
- role="alert"
- >
- <h2
- class="gl-alert-title"
- >
- Machine learning experiment tracking is in incubating phase
- </h2>
-
- <div
- class="gl-alert-body"
- >
-
- GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited.
-
- <a
- class="gl-link"
- href="https://about.gitlab.com/handbook/engineering/incubation/"
- rel="noopener noreferrer"
- target="_blank"
- >
- Learn more about incubating features
- </a>
- </div>
-
- <div
- class="gl-alert-actions"
- >
- <a
- class="btn gl-alert-action btn-confirm btn-md gl-button"
- href="https://gitlab.com/gitlab-org/gitlab/-/issues/381660"
- >
- <!---->
-
- <!---->
-
- <span
- class="gl-button-text"
- >
-
- Give feedback on this feature
-
- </span>
- </a>
- </div>
- </div>
-
- <button
- aria-label="Dismiss"
- class="btn gl-dismiss-btn btn-default btn-sm gl-button btn-default-tertiary btn-icon"
- type="button"
- >
- <!---->
-
- <svg
- aria-hidden="true"
- class="gl-button-icon gl-icon s16"
- data-testid="close-icon"
- role="img"
- >
- <use
- href="#close"
- />
- </svg>
-
- <!---->
- </button>
- </div>
-
- <h3>
-
- Model candidate details
-
- </h3>
-
- <table
- class="candidate-details"
- >
- <tbody>
- <tr
- class="divider"
- />
-
- <tr>
- <td
- class="gl-text-secondary gl-font-weight-bold"
- >
- Info
- </td>
-
- <td
- class="gl-font-weight-bold"
- >
- ID
- </td>
-
- <td>
- candidate_iid
- </td>
- </tr>
-
- <tr>
- <td />
-
- <td
- class="gl-font-weight-bold"
- >
- Status
- </td>
-
- <td>
- SUCCESS
- </td>
- </tr>
-
- <tr>
- <td />
-
- <td
- class="gl-font-weight-bold"
- >
- Experiment
- </td>
-
- <td>
- <a
- class="gl-link"
- href="#"
- >
- The Experiment
- </a>
- </td>
- </tr>
-
- <!---->
-
- <tr
- class="divider"
- />
-
- <tr>
- <td
- class="gl-text-secondary gl-font-weight-bold"
- >
-
- Parameters
-
- </td>
-
- <td
- class="gl-font-weight-bold"
- >
- Algorithm
- </td>
-
- <td>
- Decision Tree
- </td>
- </tr>
- <tr>
- <td />
-
- <td
- class="gl-font-weight-bold"
- >
- MaxDepth
- </td>
-
- <td>
- 3
- </td>
- </tr>
- <tr
- class="divider"
- />
-
- <tr>
- <td
- class="gl-text-secondary gl-font-weight-bold"
- >
-
- Metrics
-
- </td>
-
- <td
- class="gl-font-weight-bold"
- >
- AUC
- </td>
-
- <td>
- .55
- </td>
- </tr>
- <tr>
- <td />
-
- <td
- class="gl-font-weight-bold"
- >
- Accuracy
- </td>
-
- <td>
- .99
- </td>
- </tr>
- <tr
- class="divider"
- />
-
- <tr>
- <td
- class="gl-text-secondary gl-font-weight-bold"
- >
-
- Metadata
-
- </td>
-
- <td
- class="gl-font-weight-bold"
- >
- FileName
- </td>
-
- <td>
- test.py
- </td>
- </tr>
- <tr>
- <td />
-
- <td
- class="gl-font-weight-bold"
- >
- ExecutionTime
- </td>
-
- <td>
- .0856
- </td>
- </tr>
- </tbody>
- </table>
-</div>
-`;
diff --git a/spec/frontend/ml/experiment_tracking/components/ml_candidate_spec.js b/spec/frontend/ml/experiment_tracking/components/ml_candidate_spec.js
deleted file mode 100644
index 483e454d7d7..00000000000
--- a/spec/frontend/ml/experiment_tracking/components/ml_candidate_spec.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { GlAlert } from '@gitlab/ui';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import MlCandidate from '~/ml/experiment_tracking/components/ml_candidate.vue';
-
-describe('MlCandidate', () => {
- let wrapper;
-
- const createWrapper = () => {
- const candidate = {
- params: [
- { name: 'Algorithm', value: 'Decision Tree' },
- { name: 'MaxDepth', value: '3' },
- ],
- metrics: [
- { name: 'AUC', value: '.55' },
- { name: 'Accuracy', value: '.99' },
- ],
- metadata: [
- { name: 'FileName', value: 'test.py' },
- { name: 'ExecutionTime', value: '.0856' },
- ],
- info: {
- iid: 'candidate_iid',
- artifact_link: 'path_to_artifact',
- experiment_name: 'The Experiment',
- experiment_path: 'path/to/experiment',
- status: 'SUCCESS',
- },
- };
-
- return mountExtended(MlCandidate, { propsData: { candidate } });
- };
-
- const findAlert = () => wrapper.findComponent(GlAlert);
-
- it('shows incubation warning', () => {
- wrapper = createWrapper();
-
- expect(findAlert().exists()).toBe(true);
- });
-
- it('renders correctly', () => {
- wrapper = createWrapper();
-
- expect(wrapper.element).toMatchSnapshot();
- });
-});
diff --git a/spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js b/spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js
deleted file mode 100644
index f307d2c5a58..00000000000
--- a/spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js
+++ /dev/null
@@ -1,316 +0,0 @@
-import { GlAlert, GlTable, GlLink } from '@gitlab/ui';
-import { nextTick } from 'vue';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import MlExperiment from '~/ml/experiment_tracking/components/ml_experiment.vue';
-import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
-import Pagination from '~/vue_shared/components/incubation/pagination.vue';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import * as urlHelpers from '~/lib/utils/url_utility';
-
-describe('MlExperiment', () => {
- let wrapper;
-
- const startCursor = 'eyJpZCI6IjE2In0';
- const defaultPageInfo = {
- startCursor,
- endCursor: 'eyJpZCI6IjIifQ',
- hasNextPage: true,
- hasPreviousPage: true,
- };
-
- const createWrapper = (
- candidates = [],
- metricNames = [],
- paramNames = [],
- pageInfo = defaultPageInfo,
- ) => {
- wrapper = mountExtended(MlExperiment, {
- provide: { candidates, metricNames, paramNames, pageInfo },
- });
- };
-
- const candidates = [
- {
- rmse: 1,
- l1_ratio: 0.4,
- details: 'link_to_candidate1',
- artifact: 'link_to_artifact',
- name: 'aCandidate',
- created_at: '2023-01-05T14:07:02.975Z',
- user: { username: 'root', path: '/root' },
- },
- {
- auc: 0.3,
- l1_ratio: 0.5,
- details: 'link_to_candidate2',
- created_at: '2023-01-05T14:07:02.975Z',
- name: null,
- user: null,
- },
- {
- auc: 0.3,
- l1_ratio: 0.5,
- details: 'link_to_candidate3',
- created_at: '2023-01-05T14:07:02.975Z',
- name: null,
- user: null,
- },
- {
- auc: 0.3,
- l1_ratio: 0.5,
- details: 'link_to_candidate4',
- created_at: '2023-01-05T14:07:02.975Z',
- name: null,
- user: null,
- },
- {
- auc: 0.3,
- l1_ratio: 0.5,
- details: 'link_to_candidate5',
- created_at: '2023-01-05T14:07:02.975Z',
- name: null,
- user: null,
- },
- ];
-
- const createWrapperWithCandidates = (pageInfo = defaultPageInfo) => {
- createWrapper(candidates, ['rmse', 'auc', 'mae'], ['l1_ratio'], pageInfo);
- };
-
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findPagination = () => wrapper.findComponent(Pagination);
- const findEmptyState = () => wrapper.findByText('No candidates to display');
- const findRegistrySearch = () => wrapper.findComponent(RegistrySearch);
- const findTable = () => wrapper.findComponent(GlTable);
- const findTableHeaders = () => findTable().findAll('th');
- const findTableRows = () => findTable().findAll('tbody > tr');
- const findNthTableRow = (idx) => findTableRows().at(idx);
- const findColumnInRow = (row, col) => findNthTableRow(row).findAll('td').at(col);
- const hrefInRowAndColumn = (row, col) =>
- findColumnInRow(row, col).findComponent(GlLink).attributes().href;
-
- it('shows incubation warning', () => {
- createWrapper();
-
- expect(findAlert().exists()).toBe(true);
- });
-
- describe('default inputs', () => {
- beforeEach(async () => {
- createWrapper();
-
- await nextTick();
- });
-
- it('shows empty state', () => {
- expect(findEmptyState().exists()).toBe(true);
- });
-
- it('does not show pagination', () => {
- expect(findPagination().exists()).toBe(false);
- });
-
- it('there are no columns', () => {
- expect(findTable().findAll('th')).toHaveLength(0);
- });
-
- it('initializes sorting correctly', () => {
- expect(findRegistrySearch().props('sorting')).toMatchObject({
- orderBy: 'created_at',
- sort: 'desc',
- });
- });
-
- it('initializes filters correctly', () => {
- expect(findRegistrySearch().props('filters')).toMatchObject([{ value: { data: '' } }]);
- });
- });
-
- describe('Search', () => {
- it('shows search box', () => {
- createWrapper();
-
- expect(findRegistrySearch().exists()).toBe(true);
- });
-
- it('metrics are added as options for sorting', () => {
- createWrapper([], ['bar']);
-
- const labels = findRegistrySearch()
- .props('sortableFields')
- .map((e) => e.orderBy);
- expect(labels).toContain('metric.bar');
- });
-
- it('sets the component filters based on the querystring', () => {
- setWindowLocation('https://blah?name=A&orderBy=B&sort=C');
-
- createWrapper();
-
- expect(findRegistrySearch().props('filters')).toMatchObject([{ value: { data: 'A' } }]);
- });
-
- it('sets the component sort based on the querystring', () => {
- setWindowLocation('https://blah?name=A&orderBy=B&sort=C');
-
- createWrapper();
-
- expect(findRegistrySearch().props('sorting')).toMatchObject({ orderBy: 'B', sort: 'c' });
- });
-
- it('sets the component sort based on the querystring, when order by is a metric', () => {
- setWindowLocation('https://blah?name=A&orderBy=B&sort=C&orderByType=metric');
-
- createWrapper();
-
- expect(findRegistrySearch().props('sorting')).toMatchObject({
- orderBy: 'metric.B',
- sort: 'c',
- });
- });
-
- describe('Search submit', () => {
- beforeEach(() => {
- setWindowLocation('https://blah.com/?name=query&orderBy=name&orderByType=column&sort=asc');
- jest.spyOn(urlHelpers, 'visitUrl').mockImplementation(() => {});
-
- createWrapper();
- });
-
- it('On submit, resets the cursor and reloads to correct page', () => {
- findRegistrySearch().vm.$emit('filter:submit');
-
- expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
- expect(urlHelpers.visitUrl).toHaveBeenCalledWith(
- 'https://blah.com/?name=query&orderBy=name&orderByType=column&sort=asc',
- );
- });
-
- it('On sorting changed, resets cursor and reloads to correct page', () => {
- findRegistrySearch().vm.$emit('sorting:changed', { orderBy: 'created_at' });
-
- expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
- expect(urlHelpers.visitUrl).toHaveBeenCalledWith(
- 'https://blah.com/?name=query&orderBy=created_at&orderByType=column&sort=asc',
- );
- });
-
- it('On sorting changed and is metric, resets cursor and reloads to correct page', () => {
- findRegistrySearch().vm.$emit('sorting:changed', { orderBy: 'metric.auc' });
-
- expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
- expect(urlHelpers.visitUrl).toHaveBeenCalledWith(
- 'https://blah.com/?name=query&orderBy=auc&orderByType=metric&sort=asc',
- );
- });
-
- it('On direction changed, reloads to correct page', () => {
- findRegistrySearch().vm.$emit('sorting:changed', { sort: 'desc' });
-
- expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
- expect(urlHelpers.visitUrl).toHaveBeenCalledWith(
- 'https://blah.com/?name=query&orderBy=name&orderByType=column&sort=desc',
- );
- });
- });
- });
-
- describe('Pagination behaviour', () => {
- beforeEach(() => {
- createWrapperWithCandidates();
- });
-
- it('should show', () => {
- expect(findPagination().exists()).toBe(true);
- });
-
- it('Passes pagination to pagination component', () => {
- createWrapperWithCandidates();
-
- expect(findPagination().props('startCursor')).toBe(startCursor);
- });
- });
-
- describe('Candidate table', () => {
- const firstCandidateIndex = 0;
- const secondCandidateIndex = 1;
- const firstCandidate = candidates[firstCandidateIndex];
-
- beforeEach(() => {
- createWrapperWithCandidates();
- });
-
- it('renders all rows', () => {
- expect(findTableRows()).toHaveLength(candidates.length);
- });
-
- it('sets the correct columns in the table', () => {
- const expectedColumnNames = [
- 'Name',
- 'Created at',
- 'User',
- 'L1 Ratio',
- 'Rmse',
- 'Auc',
- 'Mae',
- '',
- '',
- ];
-
- expect(findTableHeaders().wrappers.map((h) => h.text())).toEqual(expectedColumnNames);
- });
-
- describe('Artifact column', () => {
- const artifactColumnIndex = -1;
-
- it('shows the a link to the artifact', () => {
- expect(hrefInRowAndColumn(firstCandidateIndex, artifactColumnIndex)).toBe(
- firstCandidate.artifact,
- );
- });
-
- it('shows empty state when no artifact', () => {
- expect(findColumnInRow(secondCandidateIndex, artifactColumnIndex).text()).toBe('-');
- });
- });
-
- describe('User column', () => {
- const userColumn = 2;
-
- it('creates a link to the user', () => {
- const column = findColumnInRow(firstCandidateIndex, userColumn).findComponent(GlLink);
-
- expect(column.attributes().href).toBe(firstCandidate.user.path);
- expect(column.text()).toBe(`@${firstCandidate.user.username}`);
- });
-
- it('when there is no user shows empty state', () => {
- createWrapperWithCandidates();
-
- expect(findColumnInRow(secondCandidateIndex, userColumn).text()).toBe('-');
- });
- });
-
- describe('Candidate name column', () => {
- const nameColumnIndex = 0;
-
- it('Sets the name', () => {
- expect(findColumnInRow(firstCandidateIndex, nameColumnIndex).text()).toBe(
- firstCandidate.name,
- );
- });
-
- it('when there is no user shows nothing', () => {
- expect(findColumnInRow(secondCandidateIndex, nameColumnIndex).text()).toBe('');
- });
- });
-
- describe('Detail column', () => {
- const detailColumn = -2;
-
- it('is a link to details', () => {
- expect(hrefInRowAndColumn(firstCandidateIndex, detailColumn)).toBe(firstCandidate.details);
- });
- });
- });
-});
diff --git a/spec/frontend/ml/experiment_tracking/routes/candidates/show/__snapshots__/ml_candidates_show_spec.js.snap b/spec/frontend/ml/experiment_tracking/routes/candidates/show/__snapshots__/ml_candidates_show_spec.js.snap
new file mode 100644
index 00000000000..dc21db39259
--- /dev/null
+++ b/spec/frontend/ml/experiment_tracking/routes/candidates/show/__snapshots__/ml_candidates_show_spec.js.snap
@@ -0,0 +1,285 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`MlCandidatesShow renders correctly 1`] = `
+<div>
+ <div
+ class="gl-alert gl-alert-warning"
+ >
+ <svg
+ aria-hidden="true"
+ class="gl-icon s16 gl-alert-icon"
+ data-testid="warning-icon"
+ role="img"
+ >
+ <use
+ href="#warning"
+ />
+ </svg>
+
+ <div
+ aria-live="assertive"
+ class="gl-alert-content"
+ role="alert"
+ >
+ <h2
+ class="gl-alert-title"
+ >
+ Machine learning experiment tracking is in incubating phase
+ </h2>
+
+ <div
+ class="gl-alert-body"
+ >
+
+ GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited.
+
+ <a
+ class="gl-link"
+ href="https://about.gitlab.com/handbook/engineering/incubation/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ Learn more about incubating features
+ </a>
+ </div>
+
+ <div
+ class="gl-alert-actions"
+ >
+ <a
+ class="btn gl-alert-action btn-confirm btn-md gl-button"
+ href="https://gitlab.com/gitlab-org/gitlab/-/issues/381660"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+
+ Give feedback on this feature
+
+ </span>
+ </a>
+ </div>
+ </div>
+
+ <button
+ aria-label="Dismiss"
+ class="btn gl-dismiss-btn btn-default btn-sm gl-button btn-default-tertiary btn-icon"
+ type="button"
+ >
+ <!---->
+
+ <svg
+ aria-hidden="true"
+ class="gl-button-icon gl-icon s16"
+ data-testid="close-icon"
+ role="img"
+ >
+ <use
+ href="#close"
+ />
+ </svg>
+
+ <!---->
+ </button>
+ </div>
+
+ <h3>
+
+ Model candidate details
+
+ </h3>
+
+ <table
+ class="candidate-details"
+ >
+ <tbody>
+ <tr
+ class="divider"
+ />
+
+ <tr>
+ <td
+ class="gl-text-secondary gl-font-weight-bold"
+ >
+ Info
+ </td>
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ ID
+ </td>
+
+ <td>
+ candidate_iid
+ </td>
+ </tr>
+
+ <tr>
+ <td />
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ Status
+ </td>
+
+ <td>
+ SUCCESS
+ </td>
+ </tr>
+
+ <tr>
+ <td />
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ Experiment
+ </td>
+
+ <td>
+ <a
+ class="gl-link"
+ href="#"
+ >
+ The Experiment
+ </a>
+ </td>
+ </tr>
+
+ <tr>
+ <td />
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ Artifacts
+ </td>
+
+ <td>
+ <a
+ class="gl-link"
+ href="path_to_artifact"
+ >
+ Artifacts
+ </a>
+ </td>
+ </tr>
+
+ <tr
+ class="divider"
+ />
+
+ <tr>
+ <td
+ class="gl-text-secondary gl-font-weight-bold"
+ >
+
+ Parameters
+
+ </td>
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ Algorithm
+ </td>
+
+ <td>
+ Decision Tree
+ </td>
+ </tr>
+ <tr>
+ <td />
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ MaxDepth
+ </td>
+
+ <td>
+ 3
+ </td>
+ </tr>
+ <tr
+ class="divider"
+ />
+
+ <tr>
+ <td
+ class="gl-text-secondary gl-font-weight-bold"
+ >
+
+ Metrics
+
+ </td>
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ AUC
+ </td>
+
+ <td>
+ .55
+ </td>
+ </tr>
+ <tr>
+ <td />
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ Accuracy
+ </td>
+
+ <td>
+ .99
+ </td>
+ </tr>
+ <tr
+ class="divider"
+ />
+
+ <tr>
+ <td
+ class="gl-text-secondary gl-font-weight-bold"
+ >
+
+ Metadata
+
+ </td>
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ FileName
+ </td>
+
+ <td>
+ test.py
+ </td>
+ </tr>
+ <tr>
+ <td />
+
+ <td
+ class="gl-font-weight-bold"
+ >
+ ExecutionTime
+ </td>
+
+ <td>
+ .0856
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+`;
diff --git a/spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js b/spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js
new file mode 100644
index 00000000000..36455339041
--- /dev/null
+++ b/spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js
@@ -0,0 +1,47 @@
+import { GlAlert } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import MlCandidatesShow from '~/ml/experiment_tracking/routes/candidates/show';
+
+describe('MlCandidatesShow', () => {
+ let wrapper;
+
+ const createWrapper = () => {
+ const candidate = {
+ params: [
+ { name: 'Algorithm', value: 'Decision Tree' },
+ { name: 'MaxDepth', value: '3' },
+ ],
+ metrics: [
+ { name: 'AUC', value: '.55' },
+ { name: 'Accuracy', value: '.99' },
+ ],
+ metadata: [
+ { name: 'FileName', value: 'test.py' },
+ { name: 'ExecutionTime', value: '.0856' },
+ ],
+ info: {
+ iid: 'candidate_iid',
+ path_to_artifact: 'path_to_artifact',
+ experiment_name: 'The Experiment',
+ experiment_path: 'path/to/experiment',
+ status: 'SUCCESS',
+ },
+ };
+
+ return mountExtended(MlCandidatesShow, { propsData: { candidate } });
+ };
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+
+ it('shows incubation warning', () => {
+ wrapper = createWrapper();
+
+ expect(findAlert().exists()).toBe(true);
+ });
+
+ it('renders correctly', () => {
+ wrapper = createWrapper();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js
new file mode 100644
index 00000000000..97a5049ea88
--- /dev/null
+++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js
@@ -0,0 +1,255 @@
+import { GlAlert, GlTableLite, GlLink, GlEmptyState } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import MlExperimentsShow from '~/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue';
+import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
+import Pagination from '~/vue_shared/components/incubation/pagination.vue';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import * as urlHelpers from '~/lib/utils/url_utility';
+import { MOCK_START_CURSOR, MOCK_PAGE_INFO, MOCK_CANDIDATES } from './mock_data';
+
+describe('MlExperimentsShow', () => {
+ let wrapper;
+
+ const createWrapper = (
+ candidates = [],
+ metricNames = [],
+ paramNames = [],
+ pageInfo = MOCK_PAGE_INFO,
+ ) => {
+ wrapper = mountExtended(MlExperimentsShow, {
+ propsData: { candidates, metricNames, paramNames, pageInfo },
+ });
+ };
+
+ const createWrapperWithCandidates = (pageInfo = MOCK_PAGE_INFO) => {
+ createWrapper(MOCK_CANDIDATES, ['rmse', 'auc', 'mae'], ['l1_ratio'], pageInfo);
+ };
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findPagination = () => wrapper.findComponent(Pagination);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findRegistrySearch = () => wrapper.findComponent(RegistrySearch);
+ const findTable = () => wrapper.findComponent(GlTableLite);
+ const findTableHeaders = () => findTable().findAll('th');
+ const findTableRows = () => findTable().findAll('tbody > tr');
+ const findNthTableRow = (idx) => findTableRows().at(idx);
+ const findColumnInRow = (row, col) => findNthTableRow(row).findAll('td').at(col);
+ const hrefInRowAndColumn = (row, col) =>
+ findColumnInRow(row, col).findComponent(GlLink).attributes().href;
+
+ it('shows incubation warning', () => {
+ createWrapper();
+
+ expect(findAlert().exists()).toBe(true);
+ });
+
+ describe('default inputs', () => {
+ beforeEach(async () => {
+ createWrapper();
+ });
+
+ it('shows empty state', () => {
+ expect(findEmptyState().exists()).toBe(true);
+ });
+
+ it('does not show pagination', () => {
+ expect(findPagination().exists()).toBe(false);
+ });
+
+ it('does not show table', () => {
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('initializes sorting correctly', () => {
+ expect(findRegistrySearch().props('sorting')).toMatchObject({
+ orderBy: 'created_at',
+ sort: 'desc',
+ });
+ });
+
+ it('initializes filters correctly', () => {
+ expect(findRegistrySearch().props('filters')).toMatchObject([{ value: { data: '' } }]);
+ });
+ });
+
+ describe('Search', () => {
+ it('shows search box', () => {
+ createWrapper();
+
+ expect(findRegistrySearch().exists()).toBe(true);
+ });
+
+ it('metrics are added as options for sorting', () => {
+ createWrapper([], ['bar']);
+
+ const labels = findRegistrySearch()
+ .props('sortableFields')
+ .map((e) => e.orderBy);
+ expect(labels).toContain('metric.bar');
+ });
+
+ it('sets the component filters based on the querystring', () => {
+ setWindowLocation('https://blah?name=A&orderBy=B&sort=C');
+
+ createWrapper();
+
+ expect(findRegistrySearch().props('filters')).toMatchObject([{ value: { data: 'A' } }]);
+ });
+
+ it('sets the component sort based on the querystring', () => {
+ setWindowLocation('https://blah?name=A&orderBy=B&sort=C');
+
+ createWrapper();
+
+ expect(findRegistrySearch().props('sorting')).toMatchObject({ orderBy: 'B', sort: 'c' });
+ });
+
+ it('sets the component sort based on the querystring, when order by is a metric', () => {
+ setWindowLocation('https://blah?name=A&orderBy=B&sort=C&orderByType=metric');
+
+ createWrapper();
+
+ expect(findRegistrySearch().props('sorting')).toMatchObject({
+ orderBy: 'metric.B',
+ sort: 'c',
+ });
+ });
+
+ describe('Search submit', () => {
+ beforeEach(() => {
+ setWindowLocation('https://blah.com/?name=query&orderBy=name&orderByType=column&sort=asc');
+ jest.spyOn(urlHelpers, 'visitUrl').mockImplementation(() => {});
+
+ createWrapper();
+ });
+
+ it('On submit, resets the cursor and reloads to correct page', () => {
+ findRegistrySearch().vm.$emit('filter:submit');
+
+ expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
+ expect(urlHelpers.visitUrl).toHaveBeenCalledWith(
+ 'https://blah.com/?name=query&orderBy=name&orderByType=column&sort=asc',
+ );
+ });
+
+ it('On sorting changed, resets cursor and reloads to correct page', () => {
+ findRegistrySearch().vm.$emit('sorting:changed', { orderBy: 'created_at' });
+
+ expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
+ expect(urlHelpers.visitUrl).toHaveBeenCalledWith(
+ 'https://blah.com/?name=query&orderBy=created_at&orderByType=column&sort=asc',
+ );
+ });
+
+ it('On sorting changed and is metric, resets cursor and reloads to correct page', () => {
+ findRegistrySearch().vm.$emit('sorting:changed', { orderBy: 'metric.auc' });
+
+ expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
+ expect(urlHelpers.visitUrl).toHaveBeenCalledWith(
+ 'https://blah.com/?name=query&orderBy=auc&orderByType=metric&sort=asc',
+ );
+ });
+
+ it('On direction changed, reloads to correct page', () => {
+ findRegistrySearch().vm.$emit('sorting:changed', { sort: 'desc' });
+
+ expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
+ expect(urlHelpers.visitUrl).toHaveBeenCalledWith(
+ 'https://blah.com/?name=query&orderBy=name&orderByType=column&sort=desc',
+ );
+ });
+ });
+ });
+
+ describe('Pagination behaviour', () => {
+ beforeEach(() => {
+ createWrapperWithCandidates();
+ });
+
+ it('should show', () => {
+ expect(findPagination().exists()).toBe(true);
+ });
+
+ it('Passes pagination to pagination component', () => {
+ createWrapperWithCandidates();
+
+ expect(findPagination().props('startCursor')).toBe(MOCK_START_CURSOR);
+ });
+ });
+
+ describe('Candidate table', () => {
+ const firstCandidateIndex = 0;
+ const secondCandidateIndex = 1;
+ const firstCandidate = MOCK_CANDIDATES[firstCandidateIndex];
+
+ beforeEach(() => {
+ createWrapperWithCandidates();
+ });
+
+ it('renders all rows', () => {
+ expect(findTableRows()).toHaveLength(MOCK_CANDIDATES.length);
+ });
+
+ it('sets the correct columns in the table', () => {
+ const expectedColumnNames = [
+ 'Name',
+ 'Created at',
+ 'Author',
+ 'L1 Ratio',
+ 'Rmse',
+ 'Auc',
+ 'Mae',
+ 'Artifacts',
+ ];
+
+ expect(findTableHeaders().wrappers.map((h) => h.text())).toEqual(expectedColumnNames);
+ });
+
+ describe('Artifact column', () => {
+ const artifactColumnIndex = -1;
+
+ it('shows the a link to the artifact', () => {
+ expect(hrefInRowAndColumn(firstCandidateIndex, artifactColumnIndex)).toBe(
+ firstCandidate.artifact,
+ );
+ });
+
+ it('shows empty state when no artifact', () => {
+ expect(findColumnInRow(secondCandidateIndex, artifactColumnIndex).text()).toBe(
+ 'No artifacts',
+ );
+ });
+ });
+
+ describe('User column', () => {
+ const userColumn = 2;
+
+ it('creates a link to the user', () => {
+ const column = findColumnInRow(firstCandidateIndex, userColumn).findComponent(GlLink);
+
+ expect(column.attributes().href).toBe(firstCandidate.user.path);
+ expect(column.text()).toBe(`@${firstCandidate.user.username}`);
+ });
+
+ it('when there is no user shows empty state', () => {
+ createWrapperWithCandidates();
+
+ expect(findColumnInRow(secondCandidateIndex, userColumn).text()).toBe('-');
+ });
+ });
+
+ describe('Candidate name column', () => {
+ const nameColumnIndex = 0;
+
+ it('Sets the name', () => {
+ expect(findColumnInRow(firstCandidateIndex, nameColumnIndex).text()).toBe(
+ firstCandidate.name,
+ );
+ });
+
+ it('when there is no user shows nothing', () => {
+ expect(findColumnInRow(secondCandidateIndex, nameColumnIndex).text()).toBe('No name');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js
new file mode 100644
index 00000000000..66378cd3f0d
--- /dev/null
+++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js
@@ -0,0 +1,52 @@
+export const MOCK_START_CURSOR = 'eyJpZCI6IjE2In0';
+
+export const MOCK_PAGE_INFO = {
+ startCursor: MOCK_START_CURSOR,
+ endCursor: 'eyJpZCI6IjIifQ',
+ hasNextPage: true,
+ hasPreviousPage: true,
+};
+
+export const MOCK_CANDIDATES = [
+ {
+ rmse: 1,
+ l1_ratio: 0.4,
+ details: 'link_to_candidate1',
+ artifact: 'link_to_artifact',
+ name: 'aCandidate',
+ created_at: '2023-01-05T14:07:02.975Z',
+ user: { username: 'root', path: '/root' },
+ },
+ {
+ auc: 0.3,
+ l1_ratio: 0.5,
+ details: 'link_to_candidate2',
+ created_at: '2023-01-05T14:07:02.975Z',
+ name: null,
+ user: null,
+ },
+ {
+ auc: 0.3,
+ l1_ratio: 0.5,
+ details: 'link_to_candidate3',
+ created_at: '2023-01-05T14:07:02.975Z',
+ name: null,
+ user: null,
+ },
+ {
+ auc: 0.3,
+ l1_ratio: 0.5,
+ details: 'link_to_candidate4',
+ created_at: '2023-01-05T14:07:02.975Z',
+ name: null,
+ user: null,
+ },
+ {
+ auc: 0.3,
+ l1_ratio: 0.5,
+ details: 'link_to_candidate5',
+ created_at: '2023-01-05T14:07:02.975Z',
+ name: null,
+ user: null,
+ },
+];
diff --git a/spec/frontend/monitoring/components/charts/column_spec.js b/spec/frontend/monitoring/components/charts/column_spec.js
index 0158966997f..cc38a3fd8a1 100644
--- a/spec/frontend/monitoring/components/charts/column_spec.js
+++ b/spec/frontend/monitoring/components/charts/column_spec.js
@@ -51,10 +51,6 @@ describe('Column component', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('xAxisLabel', () => {
const mockDate = Date.UTC(2020, 4, 26, 20); // 8:00 PM in GMT
diff --git a/spec/frontend/monitoring/components/charts/gauge_spec.js b/spec/frontend/monitoring/components/charts/gauge_spec.js
index 484199698ea..33ea5e83598 100644
--- a/spec/frontend/monitoring/components/charts/gauge_spec.js
+++ b/spec/frontend/monitoring/components/charts/gauge_spec.js
@@ -21,11 +21,6 @@ describe('Gauge Chart component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('chart component', () => {
it('is rendered when props are passed', () => {
createWrapper();
diff --git a/spec/frontend/monitoring/components/charts/heatmap_spec.js b/spec/frontend/monitoring/components/charts/heatmap_spec.js
index e163d4e73a0..54245cbdbc1 100644
--- a/spec/frontend/monitoring/components/charts/heatmap_spec.js
+++ b/spec/frontend/monitoring/components/charts/heatmap_spec.js
@@ -28,10 +28,6 @@ describe('Heatmap component', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should display a label on the x axis', () => {
expect(wrapper.vm.xAxisName).toBe(graphData.xLabel);
});
diff --git a/spec/frontend/monitoring/components/charts/single_stat_spec.js b/spec/frontend/monitoring/components/charts/single_stat_spec.js
index 62a0b7e6ad3..fa31b479296 100644
--- a/spec/frontend/monitoring/components/charts/single_stat_spec.js
+++ b/spec/frontend/monitoring/components/charts/single_stat_spec.js
@@ -21,10 +21,6 @@ describe('Single Stat Chart component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
describe('statValue', () => {
it('should display the correct value', () => {
diff --git a/spec/frontend/monitoring/components/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js
index 503dee7b937..c1b51f71a7e 100644
--- a/spec/frontend/monitoring/components/charts/time_series_spec.js
+++ b/spec/frontend/monitoring/components/charts/time_series_spec.js
@@ -58,10 +58,6 @@ describe('Time series component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('With a single time series', () => {
describe('general functions', () => {
const findChart = () => wrapper.findComponent({ ref: 'chart' });
diff --git a/spec/frontend/monitoring/components/create_dashboard_modal_spec.js b/spec/frontend/monitoring/components/create_dashboard_modal_spec.js
index 88de3467580..eb05b1f184a 100644
--- a/spec/frontend/monitoring/components/create_dashboard_modal_spec.js
+++ b/spec/frontend/monitoring/components/create_dashboard_modal_spec.js
@@ -29,10 +29,6 @@ describe('Create dashboard modal', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has button that links to the project url', async () => {
findRepoButton().trigger('click');
diff --git a/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js b/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js
index bb57420d406..2758103fd6e 100644
--- a/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js
@@ -55,11 +55,6 @@ describe('Actions menu', () => {
store = createStore();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('add metric item', () => {
it('is rendered when custom metrics are available', async () => {
createShallowWrapper();
diff --git a/spec/frontend/monitoring/components/dashboard_header_spec.js b/spec/frontend/monitoring/components/dashboard_header_spec.js
index 18ccda2c41c..ab259249772 100644
--- a/spec/frontend/monitoring/components/dashboard_header_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_header_spec.js
@@ -59,10 +59,6 @@ describe('Dashboard header', () => {
store = createStore();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('dashboards dropdown', () => {
beforeEach(() => {
store.commit(`monitoringDashboard/${types.SET_INITIAL_STATE}`, {
diff --git a/spec/frontend/monitoring/components/dashboard_panel_builder_spec.js b/spec/frontend/monitoring/components/dashboard_panel_builder_spec.js
index d71f6374967..1cfd132b123 100644
--- a/spec/frontend/monitoring/components/dashboard_panel_builder_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_panel_builder_spec.js
@@ -49,8 +49,6 @@ describe('dashboard invalid url parameters', () => {
jest.spyOn(store, 'dispatch').mockResolvedValue();
});
- afterEach(() => {});
-
it('is mounted', () => {
expect(wrapper.exists()).toBe(true);
});
diff --git a/spec/frontend/monitoring/components/dashboard_panel_spec.js b/spec/frontend/monitoring/components/dashboard_panel_spec.js
index 339c1710a9e..491649e5b96 100644
--- a/spec/frontend/monitoring/components/dashboard_panel_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_panel_spec.js
@@ -106,10 +106,6 @@ describe('Dashboard Panel', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the chart title', () => {
expect(findTitle().text()).toBe(graphDataEmpty.title);
});
@@ -134,10 +130,6 @@ describe('Dashboard Panel', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders no chart title', () => {
expect(findTitle().text()).toBe('');
});
@@ -160,10 +152,6 @@ describe('Dashboard Panel', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the chart title', () => {
expect(findTitle().text()).toBe(graphData.title);
});
@@ -377,10 +365,6 @@ describe('Dashboard Panel', () => {
await nextTick();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('csvText', () => {
it('converts metrics data from json to csv', () => {
const header = `timestamp,"${graphData.y_label} > ${graphData.metrics[0].label}"`;
diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js
index 1d17a9116df..1f995965003 100644
--- a/spec/frontend/monitoring/components/dashboard_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_spec.js
@@ -4,7 +4,7 @@ import { nextTick } from 'vue';
import setWindowLocation from 'helpers/set_window_location_helper';
import { TEST_HOST } from 'helpers/test_constants';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { ESC_KEY } from '~/lib/utils/keys';
import { objectToQuery } from '~/lib/utils/url_utility';
@@ -33,7 +33,7 @@ import {
setupStoreWithLinks,
} from '../store_utils';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Dashboard', () => {
let store;
@@ -75,7 +75,6 @@ describe('Dashboard', () => {
if (store.dispatch.mockReset) {
store.dispatch.mockReset();
}
- wrapper.destroy();
});
describe('request information to the server', () => {
diff --git a/spec/frontend/monitoring/components/dashboard_url_time_spec.js b/spec/frontend/monitoring/components/dashboard_url_time_spec.js
index 9873654bdda..98791906700 100644
--- a/spec/frontend/monitoring/components/dashboard_url_time_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_url_time_spec.js
@@ -1,7 +1,7 @@
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import {
queryToObject,
@@ -18,7 +18,7 @@ import { defaultTimeRange } from '~/vue_shared/constants';
import { dashboardProps } from '../fixture_data';
import { mockProjectDir } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
describe('dashboard invalid url parameters', () => {
diff --git a/spec/frontend/monitoring/components/graph_group_spec.js b/spec/frontend/monitoring/components/graph_group_spec.js
index 104263e73e0..593d832f297 100644
--- a/spec/frontend/monitoring/components/graph_group_spec.js
+++ b/spec/frontend/monitoring/components/graph_group_spec.js
@@ -18,10 +18,6 @@ describe('Graph group component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('When group is not collapsed', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/monitoring/components/group_empty_state_spec.js b/spec/frontend/monitoring/components/group_empty_state_spec.js
index e3cd26b0e48..d3a48be7939 100644
--- a/spec/frontend/monitoring/components/group_empty_state_spec.js
+++ b/spec/frontend/monitoring/components/group_empty_state_spec.js
@@ -23,10 +23,6 @@ function createComponent(props) {
describe('GroupEmptyState', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each([
metricStates.NO_DATA,
metricStates.TIMEOUT,
diff --git a/spec/frontend/monitoring/components/refresh_button_spec.js b/spec/frontend/monitoring/components/refresh_button_spec.js
index cb300870689..f6cc6789b1f 100644
--- a/spec/frontend/monitoring/components/refresh_button_spec.js
+++ b/spec/frontend/monitoring/components/refresh_button_spec.js
@@ -40,6 +40,7 @@ describe('RefreshButton', () => {
afterEach(() => {
dispatch.mockReset();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
wrapper.destroy();
});
diff --git a/spec/frontend/monitoring/components/variables/dropdown_field_spec.js b/spec/frontend/monitoring/components/variables/dropdown_field_spec.js
index 012e2e9c3e2..96b228fd3b2 100644
--- a/spec/frontend/monitoring/components/variables/dropdown_field_spec.js
+++ b/spec/frontend/monitoring/components/variables/dropdown_field_spec.js
@@ -1,6 +1,5 @@
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
import DropdownField from '~/monitoring/components/variables/dropdown_field.vue';
describe('Custom variable component', () => {
@@ -56,11 +55,8 @@ describe('Custom variable component', () => {
it('changing dropdown items triggers update', async () => {
createShallowWrapper();
- jest.spyOn(wrapper.vm, '$emit');
-
findDropdownItems().at(1).vm.$emit('click');
- await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('input', 'canary');
+ expect(wrapper.emitted('input')).toEqual([['canary']]);
});
});
diff --git a/spec/frontend/monitoring/components/variables/text_field_spec.js b/spec/frontend/monitoring/components/variables/text_field_spec.js
index 3073b3968aa..20e1937c5ac 100644
--- a/spec/frontend/monitoring/components/variables/text_field_spec.js
+++ b/spec/frontend/monitoring/components/variables/text_field_spec.js
@@ -33,25 +33,23 @@ describe('Text variable component', () => {
it('triggers keyup enter', async () => {
createShallowWrapper();
- jest.spyOn(wrapper.vm, '$emit');
findInput().element.value = 'prod-pod';
findInput().trigger('input');
findInput().trigger('keyup.enter');
await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('input', 'prod-pod');
+ expect(wrapper.emitted('input')).toEqual([['prod-pod']]);
});
it('triggers blur enter', async () => {
createShallowWrapper();
- jest.spyOn(wrapper.vm, '$emit');
findInput().element.value = 'canary-pod';
findInput().trigger('input');
findInput().trigger('blur');
await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('input', 'canary-pod');
+ expect(wrapper.emitted('input')).toEqual([['canary-pod']]);
});
});
diff --git a/spec/frontend/monitoring/pages/panel_new_page_spec.js b/spec/frontend/monitoring/pages/panel_new_page_spec.js
index fa112fca2db..98ee6c1cb29 100644
--- a/spec/frontend/monitoring/pages/panel_new_page_spec.js
+++ b/spec/frontend/monitoring/pages/panel_new_page_spec.js
@@ -49,10 +49,6 @@ describe('monitoring/pages/panel_new_page', () => {
mountComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('back to dashboard button', () => {
it('is rendered', () => {
expect(findBackButton().exists()).toBe(true);
diff --git a/spec/frontend/monitoring/store/actions_spec.js b/spec/frontend/monitoring/store/actions_spec.js
index 8eda46a2ff1..8097857f226 100644
--- a/spec/frontend/monitoring/store/actions_spec.js
+++ b/spec/frontend/monitoring/store/actions_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import { backoffMockImplementation } from 'helpers/backoff_helper';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import * as commonUtils from '~/lib/utils/common_utils';
import {
@@ -61,7 +61,7 @@ import {
mockDashboardsErrorResponse,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Monitoring store actions', () => {
const { convertObjectPropsToCamelCase } = commonUtils;
@@ -177,7 +177,6 @@ describe('Monitoring store actions', () => {
});
it('dispatches when feature metricsDashboardAnnotations is on', () => {
- const origGon = window.gon;
window.gon = { features: { metricsDashboardAnnotations: true } };
return testAction(
@@ -190,9 +189,7 @@ describe('Monitoring store actions', () => {
{ type: 'fetchDashboard' },
{ type: 'fetchAnnotations' },
],
- ).then(() => {
- window.gon = origGon;
- });
+ );
});
});
@@ -263,7 +260,7 @@ describe('Monitoring store actions', () => {
});
});
- it('does not show a flash error when showErrorBanner is disabled', async () => {
+ it('does not show an alert error when showErrorBanner is disabled', async () => {
state.showErrorBanner = false;
await result();
diff --git a/spec/frontend/nav/components/new_nav_toggle_spec.js b/spec/frontend/nav/components/new_nav_toggle_spec.js
index bad24345f9d..fe543a346b5 100644
--- a/spec/frontend/nav/components/new_nav_toggle_spec.js
+++ b/spec/frontend/nav/components/new_nav_toggle_spec.js
@@ -1,16 +1,16 @@
import { mount, createWrapper } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { getByText as getByTextHelper } from '@testing-library/dom';
-import { GlToggle } from '@gitlab/ui';
+import { GlDisclosureDropdownItem, GlToggle } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { s__ } from '~/locale';
-jest.mock('~/flash');
+jest.mock('~/alert');
const TEST_ENDPONT = 'https://example.com/toggle';
@@ -20,6 +20,7 @@ describe('NewNavToggle', () => {
let wrapper;
const findToggle = () => wrapper.findComponent(GlToggle);
+ const findDisclosureItem = () => wrapper.findComponent(GlDisclosureDropdownItem);
const createComponent = (propsData = { enabled: false }) => {
wrapper = mount(NewNavToggle, {
@@ -30,83 +31,156 @@ describe('NewNavToggle', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const getByText = (text, options) =>
createWrapper(getByTextHelper(wrapper.element, text, options));
- it('renders its title', () => {
- createComponent();
- expect(getByText('Navigation redesign').exists()).toBe(true);
- });
+ describe('When rendered in scope of the new navigation', () => {
+ it('renders the disclosure item', () => {
+ createComponent({ newNavigation: true, enabled: true });
+ expect(findDisclosureItem().exists()).toBe(true);
+ });
- describe('when user preference is enabled', () => {
- beforeEach(() => {
- createComponent({ enabled: true });
+ describe('when user preference is enabled', () => {
+ beforeEach(() => {
+ createComponent({ newNavigation: true, enabled: true });
+ });
+
+ it('renders the toggle as enabled', () => {
+ expect(findToggle().props('value')).toBe(true);
+ });
});
- it('renders the toggle as enabled', () => {
- expect(findToggle().props('value')).toBe(true);
+ describe('when user preference is disabled', () => {
+ beforeEach(() => {
+ createComponent({ enabled: false });
+ });
+
+ it('renders the toggle as disabled', () => {
+ expect(findToggle().props('value')).toBe(false);
+ });
+ });
+
+ describe.each`
+ desc | actFn
+ ${'when toggle button is clicked'} | ${() => findToggle().trigger('click')}
+ ${'on menu item action'} | ${() => findDisclosureItem().vm.$emit('action')}
+ `('$desc', ({ actFn }) => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ createComponent({ enabled: false, newNavigation: true });
+ });
+
+ it('reloads the page on success', async () => {
+ mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_OK);
+
+ actFn();
+ await waitForPromises();
+
+ expect(window.location.reload).toHaveBeenCalled();
+ });
+
+ it('shows an alert on error', async () => {
+ mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+
+ actFn();
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: s__(
+ 'NorthstarNavigation|Could not update the new navigation preference. Please try again later.',
+ ),
+ }),
+ );
+ expect(window.location.reload).not.toHaveBeenCalled();
+ });
+
+ it('changes the toggle', async () => {
+ await actFn();
+
+ expect(findToggle().props('value')).toBe(true);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
});
});
- describe('when user preference is disabled', () => {
- beforeEach(() => {
- createComponent({ enabled: false });
+ describe('When rendered in scope of the current navigation', () => {
+ it('renders its title', () => {
+ createComponent();
+ expect(getByText('Navigation redesign').exists()).toBe(true);
});
- it('renders the toggle as disabled', () => {
- expect(findToggle().props('value')).toBe(false);
+ describe('when user preference is enabled', () => {
+ beforeEach(() => {
+ createComponent({ enabled: true });
+ });
+
+ it('renders the toggle as enabled', () => {
+ expect(findToggle().props('value')).toBe(true);
+ });
});
- });
- describe.each`
- desc | actFn
- ${'when toggle button is clicked'} | ${() => findToggle().trigger('click')}
- ${'when menu item text is clicked'} | ${() => getByText('New navigation').trigger('click')}
- `('$desc', ({ actFn }) => {
- let mock;
+ describe('when user preference is disabled', () => {
+ beforeEach(() => {
+ createComponent({ enabled: false });
+ });
- beforeEach(() => {
- mock = new MockAdapter(axios);
- createComponent({ enabled: false });
+ it('renders the toggle as disabled', () => {
+ expect(findToggle().props('value')).toBe(false);
+ });
});
- it('reloads the page on success', async () => {
- mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_OK);
+ describe.each`
+ desc | actFn
+ ${'when toggle button is clicked'} | ${() => findToggle().trigger('click')}
+ ${'when menu item text is clicked'} | ${() => getByText('New navigation').trigger('click')}
+ `('$desc', ({ actFn }) => {
+ let mock;
- actFn();
- await waitForPromises();
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ createComponent({ enabled: false });
+ });
- expect(window.location.reload).toHaveBeenCalled();
- });
+ it('reloads the page on success', async () => {
+ mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_OK);
- it('shows an alert on error', async () => {
- mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ actFn();
+ await waitForPromises();
- actFn();
- await waitForPromises();
+ expect(window.location.reload).toHaveBeenCalled();
+ });
- expect(createAlert).toHaveBeenCalledWith(
- expect.objectContaining({
- message: s__(
- 'NorthstarNavigation|Could not update the new navigation preference. Please try again later.',
- ),
- }),
- );
- expect(window.location.reload).not.toHaveBeenCalled();
- });
+ it('shows an alert on error', async () => {
+ mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
- it('changes the toggle', async () => {
- await actFn();
+ actFn();
+ await waitForPromises();
- expect(findToggle().props('value')).toBe(true);
- });
+ expect(createAlert).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: s__(
+ 'NorthstarNavigation|Could not update the new navigation preference. Please try again later.',
+ ),
+ }),
+ );
+ expect(window.location.reload).not.toHaveBeenCalled();
+ });
+
+ it('changes the toggle', async () => {
+ await actFn();
+
+ expect(findToggle().props('value')).toBe(true);
+ });
- afterEach(() => {
- mock.restore();
+ afterEach(() => {
+ mock.restore();
+ });
});
});
});
diff --git a/spec/frontend/nav/components/responsive_app_spec.js b/spec/frontend/nav/components/responsive_app_spec.js
index 76b8ebdc92f..9d3b43520ec 100644
--- a/spec/frontend/nav/components/responsive_app_spec.js
+++ b/spec/frontend/nav/components/responsive_app_spec.js
@@ -33,10 +33,6 @@ describe('~/nav/components/responsive_app.vue', () => {
document.body.className = 'test-class';
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/nav/components/responsive_header_spec.js b/spec/frontend/nav/components/responsive_header_spec.js
index f87de0afb14..2514035270a 100644
--- a/spec/frontend/nav/components/responsive_header_spec.js
+++ b/spec/frontend/nav/components/responsive_header_spec.js
@@ -14,7 +14,7 @@ describe('~/nav/components/top_nav_menu_sections.vue', () => {
default: TEST_SLOT_CONTENT,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -25,10 +25,6 @@ describe('~/nav/components/top_nav_menu_sections.vue', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders slot', () => {
expect(wrapper.text()).toBe(TEST_SLOT_CONTENT);
});
diff --git a/spec/frontend/nav/components/responsive_home_spec.js b/spec/frontend/nav/components/responsive_home_spec.js
index 8f198d92747..5a5cfc93607 100644
--- a/spec/frontend/nav/components/responsive_home_spec.js
+++ b/spec/frontend/nav/components/responsive_home_spec.js
@@ -29,7 +29,7 @@ describe('~/nav/components/responsive_home.vue', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
listeners: {
'menu-item-click': menuItemClickListener,
@@ -45,10 +45,6 @@ describe('~/nav/components/responsive_home.vue', () => {
menuItemClickListener = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/nav/components/top_nav_app_spec.js b/spec/frontend/nav/components/top_nav_app_spec.js
index e70f70afc97..7f39552eb42 100644
--- a/spec/frontend/nav/components/top_nav_app_spec.js
+++ b/spec/frontend/nav/components/top_nav_app_spec.js
@@ -28,10 +28,6 @@ describe('~/nav/components/top_nav_app.vue', () => {
const findNavItemDropdowToggle = () => findNavItemDropdown().find('.js-top-nav-dropdown-toggle');
const findMenu = () => wrapper.findComponent(TopNavDropdownMenu);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponentShallow();
diff --git a/spec/frontend/nav/components/top_nav_container_view_spec.js b/spec/frontend/nav/components/top_nav_container_view_spec.js
index 293fe361fa9..388ac243648 100644
--- a/spec/frontend/nav/components/top_nav_container_view_spec.js
+++ b/spec/frontend/nav/components/top_nav_container_view_spec.js
@@ -48,10 +48,6 @@ describe('~/nav/components/top_nav_container_view.vue', () => {
};
const findFrequentItemsContainer = () => wrapper.find('[data-testid="frequent-items-container"]');
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each(['projects', 'groups'])(
'emits frequent items event to event hub (%s)',
async (frequentItemsDropdownType) => {
diff --git a/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js b/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
index 8a0340087ec..08d6650b5bb 100644
--- a/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
+++ b/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
@@ -36,10 +36,6 @@ describe('~/nav/components/top_nav_dropdown_menu.vue', () => {
active: idx === activeIndex,
}));
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
jest.spyOn(console, 'error').mockImplementation();
});
diff --git a/spec/frontend/nav/components/top_nav_menu_sections_spec.js b/spec/frontend/nav/components/top_nav_menu_sections_spec.js
index 7a5a8475ab7..7a3e58fd964 100644
--- a/spec/frontend/nav/components/top_nav_menu_sections_spec.js
+++ b/spec/frontend/nav/components/top_nav_menu_sections_spec.js
@@ -54,10 +54,6 @@ describe('~/nav/components/top_nav_menu_sections.vue', () => {
menuItems: findMenuItemModels(x),
}));
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
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 18210658b89..2cd65307b0b 100644
--- a/spec/frontend/nav/components/top_nav_new_dropdown_spec.js
+++ b/spec/frontend/nav/components/top_nav_new_dropdown_spec.js
@@ -1,6 +1,8 @@
import { GlDropdown } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import TopNavNewDropdown from '~/nav/components/top_nav_new_dropdown.vue';
+import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
+import { TOP_NAV_INVITE_MEMBERS_COMPONENT } from '~/invite_members/constants';
const TEST_VIEW_MODEL = {
title: 'Dropdown',
@@ -18,6 +20,16 @@ const TEST_VIEW_MODEL = {
menu_items: [
{ id: 'bar-1', title: 'Bar 1', href: '/bar/1' },
{ id: 'bar-2', title: 'Bar 2', href: '/bar/2' },
+ {
+ id: 'invite',
+ title: '_invite members title_',
+ component: TOP_NAV_INVITE_MEMBERS_COMPONENT,
+ icon: '_icon_',
+ data: {
+ trigger_element: '_trigger_element_',
+ trigger_source: '_trigger_source_',
+ },
+ },
],
},
],
@@ -36,6 +48,7 @@ describe('~/nav/components/top_nav_menu_sections.vue', () => {
};
const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findInviteMembersTrigger = () => wrapper.findComponent(InviteMembersTrigger);
const findDropdownContents = () =>
findDropdown()
.findAll('[data-testid]')
@@ -55,10 +68,6 @@ describe('~/nav/components/top_nav_menu_sections.vue', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
@@ -73,6 +82,10 @@ describe('~/nav/components/top_nav_menu_sections.vue', () => {
});
it('renders dropdown content', () => {
+ const hrefItems = TEST_VIEW_MODEL.menu_sections[1].menu_items.filter((item) =>
+ Boolean(item.href),
+ );
+
expect(findDropdownContents()).toEqual([
{
type: 'header',
@@ -90,12 +103,18 @@ describe('~/nav/components/top_nav_menu_sections.vue', () => {
type: 'header',
text: TEST_VIEW_MODEL.menu_sections[1].title,
},
- ...TEST_VIEW_MODEL.menu_sections[1].menu_items.map(({ title, href }) => ({
+ ...hrefItems.map(({ title, href }) => ({
type: 'item',
href,
text: title,
})),
]);
+ expect(findInviteMembersTrigger().props()).toMatchObject({
+ displayText: '_invite members title_',
+ icon: '_icon_',
+ triggerElement: 'dropdown-_trigger_element_',
+ triggerSource: '_trigger_source_',
+ });
});
});
diff --git a/spec/frontend/notebook/cells/code_spec.js b/spec/frontend/notebook/cells/code_spec.js
index 10762a1c3a2..9836400a366 100644
--- a/spec/frontend/notebook/cells/code_spec.js
+++ b/spec/frontend/notebook/cells/code_spec.js
@@ -13,10 +13,6 @@ describe('Code component', () => {
json = JSON.parse(JSON.stringify(fixture));
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('without output', () => {
beforeEach(() => {
wrapper = mountComponent(json.cells[0]);
diff --git a/spec/frontend/notebook/cells/markdown_spec.js b/spec/frontend/notebook/cells/markdown_spec.js
index a7776bd5b69..f226776212a 100644
--- a/spec/frontend/notebook/cells/markdown_spec.js
+++ b/spec/frontend/notebook/cells/markdown_spec.js
@@ -1,18 +1,16 @@
import { mount } from '@vue/test-utils';
import katex from 'katex';
-import Vue, { nextTick } from 'vue';
+import { nextTick } from 'vue';
import markdownTableJson from 'test_fixtures/blob/notebook/markdown-table.json';
import basicJson from 'test_fixtures/blob/notebook/basic.json';
import mathJson from 'test_fixtures/blob/notebook/math.json';
import MarkdownComponent from '~/notebook/cells/markdown.vue';
import Prompt from '~/notebook/cells/prompt.vue';
-const Component = Vue.extend(MarkdownComponent);
-
window.katex = katex;
function buildCellComponent(cell, relativePath = '', hidePrompt) {
- return mount(Component, {
+ return mount(MarkdownComponent, {
propsData: {
cell,
hidePrompt,
diff --git a/spec/frontend/notebook/cells/output/error_spec.js b/spec/frontend/notebook/cells/output/error_spec.js
new file mode 100644
index 00000000000..2e4ca8c1761
--- /dev/null
+++ b/spec/frontend/notebook/cells/output/error_spec.js
@@ -0,0 +1,48 @@
+import { mount } from '@vue/test-utils';
+import ErrorOutput from '~/notebook/cells/output/error.vue';
+import Prompt from '~/notebook/cells/prompt.vue';
+import Markdown from '~/notebook/cells/markdown.vue';
+import { errorOutputContent, relativeRawPath } from '../../mock_data';
+
+describe('notebook/cells/output/error.vue', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = mount(ErrorOutput, {
+ propsData: {
+ rawCode: errorOutputContent,
+ index: 1,
+ count: 2,
+ },
+ provide: { relativeRawPath },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ const findPrompt = () => wrapper.findComponent(Prompt);
+ const findMarkdown = () => wrapper.findComponent(Markdown);
+
+ it('renders the prompt', () => {
+ expect(findPrompt().props()).toMatchObject({ count: 2, showOutput: true, type: 'Out' });
+ });
+
+ it('renders the markdown', () => {
+ const expectedParsedMarkdown =
+ '```error\n' +
+ '---------------------------------------------------------------------------\n' +
+ 'NameError Traceback (most recent call last)\n' +
+ '/var/folders/cq/l637k4x13gx6y9p_gfs4c_gc0000gn/T/ipykernel_79203/294318627.py in <module>\n' +
+ '----> 1 To\n' +
+ '\n' +
+ "NameError: name 'To' is not defined\n" +
+ '```';
+
+ expect(findMarkdown().props()).toMatchObject({
+ cell: { source: [expectedParsedMarkdown] },
+ hidePrompt: true,
+ });
+ });
+});
diff --git a/spec/frontend/notebook/cells/output/index_spec.js b/spec/frontend/notebook/cells/output/index_spec.js
index 585cbb68eeb..1241c133b89 100644
--- a/spec/frontend/notebook/cells/output/index_spec.js
+++ b/spec/frontend/notebook/cells/output/index_spec.js
@@ -17,10 +17,6 @@ describe('Output component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('text output', () => {
beforeEach(() => {
const textType = json.cells[2];
diff --git a/spec/frontend/notebook/cells/prompt_spec.js b/spec/frontend/notebook/cells/prompt_spec.js
index 0cda0c5bc2b..4c864a9b930 100644
--- a/spec/frontend/notebook/cells/prompt_spec.js
+++ b/spec/frontend/notebook/cells/prompt_spec.js
@@ -6,10 +6,6 @@ describe('Prompt component', () => {
const mountComponent = ({ type }) => shallowMount(Prompt, { propsData: { type, count: 1 } });
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('input', () => {
beforeEach(() => {
wrapper = mountComponent({ type: 'In' });
diff --git a/spec/frontend/notebook/index_spec.js b/spec/frontend/notebook/index_spec.js
index b79000a3505..3c73d420703 100644
--- a/spec/frontend/notebook/index_spec.js
+++ b/spec/frontend/notebook/index_spec.js
@@ -1,16 +1,14 @@
import { mount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
+import { nextTick } from 'vue';
import json from 'test_fixtures/blob/notebook/basic.json';
import jsonWithWorksheet from 'test_fixtures/blob/notebook/worksheets.json';
import Notebook from '~/notebook/index.vue';
-const Component = Vue.extend(Notebook);
-
describe('Notebook component', () => {
let vm;
function buildComponent(notebook) {
- return mount(Component, {
+ return mount(Notebook, {
propsData: { notebook },
provide: { relativeRawPath: '' },
}).vm;
diff --git a/spec/frontend/notebook/mock_data.js b/spec/frontend/notebook/mock_data.js
index b1419e1256f..5c47cb5aa9b 100644
--- a/spec/frontend/notebook/mock_data.js
+++ b/spec/frontend/notebook/mock_data.js
@@ -1,2 +1,8 @@
export const relativeRawPath = '/test';
export const markdownCellContent = ['# Test'];
+export const errorOutputContent = [
+ '\u001b[0;31m---------------------------------------------------------------------------\u001b[0m',
+ '\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)',
+ '\u001b[0;32m/var/folders/cq/l637k4x13gx6y9p_gfs4c_gc0000gn/T/ipykernel_79203/294318627.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mTo\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m',
+ "\u001b[0;31mNameError\u001b[0m: name 'To' is not defined",
+];
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index dfb05c85fc8..062cd098640 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -5,11 +5,12 @@ import MockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import Autosave from '~/autosave';
import batchComments from '~/batch_comments/stores/modules/batch_comments';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
+import { STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import axios from '~/lib/utils/axios_utils';
+import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import { HTTP_STATUS_UNPROCESSABLE_ENTITY } from '~/lib/utils/http_status';
import CommentForm from '~/notes/components/comment_form.vue';
import CommentTypeDropdown from '~/notes/components/comment_type_dropdown.vue';
@@ -21,8 +22,7 @@ import { loggedOutnoteableData, notesDataMock, userDataMock, noteableDataMock }
jest.mock('autosize');
jest.mock('~/commons/nav/user_merge_requests');
-jest.mock('~/flash');
-jest.mock('~/autosave');
+jest.mock('~/alert');
Vue.use(Vuex);
@@ -32,7 +32,8 @@ describe('issue_comment_form component', () => {
let axiosMock;
const findCloseReopenButton = () => wrapper.findByTestId('close-reopen-button');
- const findTextArea = () => wrapper.findByTestId('comment-field');
+ const findMarkdownEditor = () => wrapper.findComponent(MarkdownEditor);
+ const findMarkdownEditorTextarea = () => findMarkdownEditor().find('textarea');
const findAddToReviewButton = () => wrapper.findByTestId('add-to-review-button');
const findAddCommentNowButton = () => wrapper.findByTestId('add-comment-now-button');
const findConfidentialNoteCheckbox = () => wrapper.findByTestId('internal-note-checkbox');
@@ -127,7 +128,6 @@ describe('issue_comment_form component', () => {
afterEach(() => {
axiosMock.restore();
- wrapper.destroy();
});
describe('user is logged in', () => {
@@ -136,7 +136,6 @@ describe('issue_comment_form component', () => {
mountComponent({ mountFunction: mount, initialData: { note: 'hello world' } });
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
- jest.spyOn(wrapper.vm, 'resizeTextarea');
jest.spyOn(wrapper.vm, 'stopPolling');
findCloseReopenButton().trigger('click');
@@ -145,7 +144,6 @@ describe('issue_comment_form component', () => {
expect(wrapper.vm.note).toBe('');
expect(wrapper.vm.saveNote).toHaveBeenCalled();
expect(wrapper.vm.stopPolling).toHaveBeenCalled();
- expect(wrapper.vm.resizeTextarea).toHaveBeenCalled();
});
it('does not report errors in the UI when the save succeeds', async () => {
@@ -260,6 +258,18 @@ describe('issue_comment_form component', () => {
});
});
+ it('hides content editor switcher if feature flag content_editor_on_issues is off', () => {
+ mountComponent({ mountFunction: mount, features: { contentEditorOnIssues: false } });
+
+ expect(wrapper.text()).not.toContain('Rich text');
+ });
+
+ it('shows content editor switcher if feature flag content_editor_on_issues is on', () => {
+ mountComponent({ mountFunction: mount, features: { contentEditorOnIssues: true } });
+
+ expect(wrapper.text()).toContain('Rich text');
+ });
+
describe('textarea', () => {
describe('general', () => {
it.each`
@@ -268,13 +278,13 @@ describe('issue_comment_form component', () => {
${'internal note'} | ${true} | ${'Write an internal note or drag your files here…'}
`(
'should render textarea with placeholder for $noteType',
- ({ noteIsInternal, placeholder }) => {
- mountComponent({
- mountFunction: mount,
- initialData: { noteIsInternal },
- });
+ async ({ noteIsInternal, placeholder }) => {
+ mountComponent();
+
+ wrapper.vm.noteIsInternal = noteIsInternal;
+ await nextTick();
- expect(findTextArea().attributes('placeholder')).toBe(placeholder);
+ expect(findMarkdownEditor().props('formFieldProps').placeholder).toBe(placeholder);
},
);
@@ -290,13 +300,13 @@ describe('issue_comment_form component', () => {
await findCommentButton().trigger('click');
- expect(findTextArea().attributes('disabled')).toBe('disabled');
+ expect(findMarkdownEditor().find('textarea').attributes('disabled')).toBe('disabled');
});
it('should support quick actions', () => {
mountComponent({ mountFunction: mount });
- expect(findTextArea().attributes('data-supports-quick-actions')).toBe('true');
+ expect(findMarkdownEditor().props('supportsQuickActions')).toBe(true);
});
it('should link to markdown docs', () => {
@@ -336,63 +346,51 @@ describe('issue_comment_form component', () => {
it('should enter edit mode when arrow up is pressed', () => {
jest.spyOn(wrapper.vm, 'editCurrentUserLastNote');
- findTextArea().trigger('keydown.up');
+ findMarkdownEditorTextarea().trigger('keydown.up');
expect(wrapper.vm.editCurrentUserLastNote).toHaveBeenCalled();
});
- it('inits autosave', () => {
- expect(Autosave).toHaveBeenCalledWith(expect.any(Element), [
- 'Note',
- 'Issue',
- noteableDataMock.id,
- ]);
- });
- });
+ describe('event enter', () => {
+ describe('when no draft exists', () => {
+ it('should save note when cmd+enter is pressed', () => {
+ jest.spyOn(wrapper.vm, 'handleSave');
- describe('event enter', () => {
- beforeEach(() => {
- mountComponent({ mountFunction: mount });
- });
-
- describe('when no draft exists', () => {
- it('should save note when cmd+enter is pressed', () => {
- jest.spyOn(wrapper.vm, 'handleSave');
-
- findTextArea().trigger('keydown.enter', { metaKey: true });
+ findMarkdownEditorTextarea().trigger('keydown.enter', { metaKey: true });
- expect(wrapper.vm.handleSave).toHaveBeenCalledWith();
- });
+ expect(wrapper.vm.handleSave).toHaveBeenCalledWith();
+ });
- it('should save note when ctrl+enter is pressed', () => {
- jest.spyOn(wrapper.vm, 'handleSave');
+ it('should save note when ctrl+enter is pressed', () => {
+ jest.spyOn(wrapper.vm, 'handleSave');
- findTextArea().trigger('keydown.enter', { ctrlKey: true });
+ findMarkdownEditorTextarea().trigger('keydown.enter', { ctrlKey: true });
- expect(wrapper.vm.handleSave).toHaveBeenCalledWith();
+ expect(wrapper.vm.handleSave).toHaveBeenCalledWith();
+ });
});
- });
- describe('when a draft exists', () => {
- beforeEach(() => {
- store.registerModule('batchComments', batchComments());
- store.state.batchComments.drafts = [{ note: 'A' }];
- });
+ describe('when a draft exists', () => {
+ beforeEach(() => {
+ store.registerModule('batchComments', batchComments());
+ store.state.batchComments.drafts = [{ note: 'A' }];
+ });
- it('should save note draft when cmd+enter is pressed', () => {
- jest.spyOn(wrapper.vm, 'handleSaveDraft');
+ it('should save note draft when cmd+enter is pressed', () => {
+ jest.spyOn(wrapper.vm, 'handleSaveDraft');
- findTextArea().trigger('keydown.enter', { metaKey: true });
+ findMarkdownEditorTextarea().trigger('keydown.enter', { metaKey: true });
- expect(wrapper.vm.handleSaveDraft).toHaveBeenCalledWith();
- });
+ expect(wrapper.vm.handleSaveDraft).toHaveBeenCalledWith();
+ });
- it('should save note draft when ctrl+enter is pressed', () => {
- jest.spyOn(wrapper.vm, 'handleSaveDraft');
+ it('should save note draft when ctrl+enter is pressed', () => {
+ jest.spyOn(wrapper.vm, 'handleSaveDraft');
- findTextArea().trigger('keydown.enter', { ctrlKey: true });
+ findMarkdownEditorTextarea().trigger('keydown.enter', { ctrlKey: true });
- expect(wrapper.vm.handleSaveDraft).toHaveBeenCalledWith();
+ expect(wrapper.vm.handleSaveDraft).toHaveBeenCalledWith();
+ });
});
});
});
@@ -482,7 +480,7 @@ describe('issue_comment_form component', () => {
it(`makes an API call to open it`, () => {
mountComponent({
noteableType,
- noteableData: { ...noteableDataMock, state: constants.OPENED },
+ noteableData: { ...noteableDataMock, state: STATUS_OPEN },
mountFunction: mount,
});
@@ -496,7 +494,7 @@ describe('issue_comment_form component', () => {
it(`shows an error when the API call fails`, async () => {
mountComponent({
noteableType,
- noteableData: { ...noteableDataMock, state: constants.OPENED },
+ noteableData: { ...noteableDataMock, state: STATUS_OPEN },
mountFunction: mount,
});
@@ -517,7 +515,7 @@ describe('issue_comment_form component', () => {
it('makes an API call to close it', () => {
mountComponent({
noteableType,
- noteableData: { ...noteableDataMock, state: constants.CLOSED },
+ noteableData: { ...noteableDataMock, state: STATUS_CLOSED },
mountFunction: mount,
});
@@ -532,7 +530,7 @@ describe('issue_comment_form component', () => {
it(`shows an error when the API call fails`, async () => {
mountComponent({
noteableType,
- noteableData: { ...noteableDataMock, state: constants.CLOSED },
+ noteableData: { ...noteableDataMock, state: STATUS_CLOSED },
mountFunction: mount,
});
@@ -661,7 +659,7 @@ describe('issue_comment_form component', () => {
});
it('should not render submission form', () => {
- expect(findTextArea().exists()).toBe(false);
+ expect(findMarkdownEditor().exists()).toBe(false);
});
});
diff --git a/spec/frontend/notes/components/comment_type_dropdown_spec.js b/spec/frontend/notes/components/comment_type_dropdown_spec.js
index cabf551deba..b891c1f553d 100644
--- a/spec/frontend/notes/components/comment_type_dropdown_spec.js
+++ b/spec/frontend/notes/components/comment_type_dropdown_spec.js
@@ -24,10 +24,6 @@ describe('CommentTypeDropdown component', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
isInternalNote | buttonText
${false} | ${COMMENT_FORM.comment}
diff --git a/spec/frontend/notes/components/diff_discussion_header_spec.js b/spec/frontend/notes/components/diff_discussion_header_spec.js
index bb44563b87a..66b86ed3ce0 100644
--- a/spec/frontend/notes/components/diff_discussion_header_spec.js
+++ b/spec/frontend/notes/components/diff_discussion_header_spec.js
@@ -22,10 +22,6 @@ describe('diff_discussion_header component', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Avatar', () => {
const firstNoteAuthor = discussionMock.notes[0].author;
const findAvatarLink = () => wrapper.findComponent(GlAvatarLink);
diff --git a/spec/frontend/notes/components/discussion_actions_spec.js b/spec/frontend/notes/components/discussion_actions_spec.js
index e414ada1854..a9a20bd8bc3 100644
--- a/spec/frontend/notes/components/discussion_actions_spec.js
+++ b/spec/frontend/notes/components/discussion_actions_spec.js
@@ -38,15 +38,12 @@ describe('DiscussionActions', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
const createComponent = createComponentFactory();
it('renders reply placeholder, resolve discussion button, resolve with issue button and jump to next discussion button', () => {
createComponent();
+
expect(wrapper.findComponent(ReplyPlaceholder).exists()).toBe(true);
expect(wrapper.findComponent(ResolveDiscussionButton).exists()).toBe(true);
expect(wrapper.findComponent(ResolveWithIssueButton).exists()).toBe(true);
@@ -94,17 +91,15 @@ describe('DiscussionActions', () => {
it('emits showReplyForm event when clicking on reply placeholder', () => {
createComponent({}, { attachTo: document.body });
- jest.spyOn(wrapper.vm, '$emit');
wrapper.findComponent(ReplyPlaceholder).find('textarea').trigger('focus');
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('showReplyForm');
+ expect(wrapper.emitted().showReplyForm).toHaveLength(1);
});
it('emits resolve event when clicking on resolve button', () => {
createComponent();
- jest.spyOn(wrapper.vm, '$emit');
wrapper.findComponent(ResolveDiscussionButton).find('button').trigger('click');
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('resolve');
+ expect(wrapper.emitted().resolve).toHaveLength(1);
});
});
});
diff --git a/spec/frontend/notes/components/discussion_counter_spec.js b/spec/frontend/notes/components/discussion_counter_spec.js
index f4ec7f835bb..ac677841ee1 100644
--- a/spec/frontend/notes/components/discussion_counter_spec.js
+++ b/spec/frontend/notes/components/discussion_counter_spec.js
@@ -40,7 +40,6 @@ describe('DiscussionCounter component', () => {
afterEach(() => {
wrapper.vm.$destroy();
- wrapper = null;
});
describe('has no discussions', () => {
@@ -119,8 +118,6 @@ describe('DiscussionCounter component', () => {
toggleAllButton = wrapper.find('[data-testid="toggle-all-discussions-btn"]');
};
- afterEach(() => wrapper.destroy());
-
it('calls button handler when clicked', async () => {
await updateStoreWithExpanded(true);
diff --git a/spec/frontend/notes/components/discussion_filter_note_spec.js b/spec/frontend/notes/components/discussion_filter_note_spec.js
index 48f5030aa1a..e31155a028f 100644
--- a/spec/frontend/notes/components/discussion_filter_note_spec.js
+++ b/spec/frontend/notes/components/discussion_filter_note_spec.js
@@ -18,11 +18,6 @@ describe('DiscussionFilterNote component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('timelineContent renders a string containing instruction for switching feed type', () => {
expect(wrapper.find('[data-testid="discussion-filter-timeline-content"]').html()).toBe(
'<div data-testid="discussion-filter-timeline-content">You\'re only seeing <b>other activity</b> in the feed. To add a comment, switch to one of the following options.</div>',
diff --git a/spec/frontend/notes/components/discussion_navigator_spec.js b/spec/frontend/notes/components/discussion_navigator_spec.js
index 77ae7b2c3b5..6e095f63003 100644
--- a/spec/frontend/notes/components/discussion_navigator_spec.js
+++ b/spec/frontend/notes/components/discussion_navigator_spec.js
@@ -37,7 +37,6 @@ describe('notes/components/discussion_navigator', () => {
if (wrapper) {
wrapper.destroy();
}
- wrapper = null;
});
describe('on create', () => {
diff --git a/spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js b/spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js
index 8d5ea108b50..d11ca7ad1ec 100644
--- a/spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js
+++ b/spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js
@@ -19,10 +19,6 @@ describe('DiscussionNotesRepliesWrapper', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when normal discussion', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/notes/components/discussion_notes_spec.js b/spec/frontend/notes/components/discussion_notes_spec.js
index add2ed1ba8a..bc0c04f2d8a 100644
--- a/spec/frontend/notes/components/discussion_notes_spec.js
+++ b/spec/frontend/notes/components/discussion_notes_spec.js
@@ -53,11 +53,6 @@ describe('DiscussionNotes', () => {
store.dispatch('setNotesData', notesDataMock);
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('rendering', () => {
it('renders an element for each note in the discussion', () => {
createComponent();
diff --git a/spec/frontend/notes/components/discussion_reply_placeholder_spec.js b/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
index 971e3987929..a9201b78669 100644
--- a/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
+++ b/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
@@ -17,10 +17,6 @@ describe('ReplyPlaceholder', () => {
const findTextarea = () => wrapper.findComponent({ ref: 'textarea' });
- afterEach(() => {
- wrapper.destroy();
- });
-
it('emits focus event on button click', async () => {
createComponent({ options: { attachTo: document.body } });
diff --git a/spec/frontend/notes/components/discussion_resolve_button_spec.js b/spec/frontend/notes/components/discussion_resolve_button_spec.js
index 17c3523cf48..4bd21842fec 100644
--- a/spec/frontend/notes/components/discussion_resolve_button_spec.js
+++ b/spec/frontend/notes/components/discussion_resolve_button_spec.js
@@ -23,10 +23,6 @@ describe('resolveDiscussionButton', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should emit a onClick event on button click', async () => {
const button = wrapper.findComponent(GlButton);
diff --git a/spec/frontend/notes/components/discussion_resolve_with_issue_button_spec.js b/spec/frontend/notes/components/discussion_resolve_with_issue_button_spec.js
index a185f11ffaa..3dfae45ec49 100644
--- a/spec/frontend/notes/components/discussion_resolve_with_issue_button_spec.js
+++ b/spec/frontend/notes/components/discussion_resolve_with_issue_button_spec.js
@@ -15,10 +15,6 @@ describe('ResolveWithIssueButton', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should have a link with the provided link property as href', () => {
const button = wrapper.findComponent(GlButton);
diff --git a/spec/frontend/notes/components/email_participants_warning_spec.js b/spec/frontend/notes/components/email_participants_warning_spec.js
index ab1a6b152a4..34b7524d8fb 100644
--- a/spec/frontend/notes/components/email_participants_warning_spec.js
+++ b/spec/frontend/notes/components/email_participants_warning_spec.js
@@ -4,11 +4,6 @@ import EmailParticipantsWarning from '~/notes/components/email_participants_warn
describe('Email Participants Warning Component', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findMoreButton = () => wrapper.find('button');
const createWrapper = (emails) => {
diff --git a/spec/frontend/notes/components/note_actions/reply_button_spec.js b/spec/frontend/notes/components/note_actions/reply_button_spec.js
index 20b32b8c178..68b11fb3b1a 100644
--- a/spec/frontend/notes/components/note_actions/reply_button_spec.js
+++ b/spec/frontend/notes/components/note_actions/reply_button_spec.js
@@ -9,11 +9,6 @@ describe('ReplyButton', () => {
wrapper = shallowMount(ReplyButton);
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('emits startReplying on click', () => {
wrapper.findComponent(GlButton).vm.$emit('click');
diff --git a/spec/frontend/notes/components/note_actions/timeline_event_button_spec.js b/spec/frontend/notes/components/note_actions/timeline_event_button_spec.js
index 658e844a9b1..bee08ee0605 100644
--- a/spec/frontend/notes/components/note_actions/timeline_event_button_spec.js
+++ b/spec/frontend/notes/components/note_actions/timeline_event_button_spec.js
@@ -20,10 +20,6 @@ describe('NoteTimelineEventButton', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findTimelineButton = () => wrapper.findComponent(GlButton);
it('emits click-promote-comment-to-event', async () => {
diff --git a/spec/frontend/notes/components/note_actions_spec.js b/spec/frontend/notes/components/note_actions_spec.js
index 8630b7b7d07..63286927d53 100644
--- a/spec/frontend/notes/components/note_actions_spec.js
+++ b/spec/frontend/notes/components/note_actions_spec.js
@@ -77,7 +77,6 @@ describe('noteActions', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
});
@@ -203,7 +202,6 @@ describe('noteActions', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
});
@@ -226,7 +224,6 @@ describe('noteActions', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
});
@@ -248,10 +245,6 @@ describe('noteActions', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should not be possible to assign the comment author', testButtonDoesNotRender);
it('should not be possible to unassign the comment author', testButtonDoesNotRender);
});
diff --git a/spec/frontend/notes/components/note_attachment_spec.js b/spec/frontend/notes/components/note_attachment_spec.js
index 24632f8e427..7f44171f6cc 100644
--- a/spec/frontend/notes/components/note_attachment_spec.js
+++ b/spec/frontend/notes/components/note_attachment_spec.js
@@ -15,11 +15,6 @@ describe('Issue note attachment', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders attachment image if it is passed in attachment prop', () => {
createComponent({
image: 'test-image',
diff --git a/spec/frontend/notes/components/note_body_spec.js b/spec/frontend/notes/components/note_body_spec.js
index c71cf7666ab..b4f185004bb 100644
--- a/spec/frontend/notes/components/note_body_spec.js
+++ b/spec/frontend/notes/components/note_body_spec.js
@@ -49,10 +49,6 @@ describe('issue_note_body component', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render the note', () => {
expect(wrapper.find('.note-text').html()).toContain(note.note_html);
});
diff --git a/spec/frontend/notes/components/note_edited_text_spec.js b/spec/frontend/notes/components/note_edited_text_spec.js
index 0a5fe48ef94..577e1044588 100644
--- a/spec/frontend/notes/components/note_edited_text_spec.js
+++ b/spec/frontend/notes/components/note_edited_text_spec.js
@@ -1,3 +1,4 @@
+import { GlSprintf, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import NoteEditedText from '~/notes/components/note_edited_text.vue';
@@ -5,41 +6,63 @@ const propsData = {
actionText: 'Edited',
className: 'foo-bar',
editedAt: '2017-08-04T09:52:31.062Z',
- editedBy: {
- avatar_url: 'path',
- id: 1,
- name: 'Root',
- path: '/root',
- state: 'active',
- username: 'root',
- },
+ editedBy: null,
};
describe('NoteEditedText', () => {
let wrapper;
- beforeEach(() => {
+ const createWrapper = (props = {}) => {
wrapper = shallowMount(NoteEditedText, {
- propsData,
+ propsData: {
+ ...propsData,
+ ...props,
+ },
+ stubs: {
+ GlSprintf,
+ },
});
- });
+ };
- afterEach(() => {
- wrapper.destroy();
- });
+ const findUserElement = () => wrapper.findComponent(GlLink);
- it('should render block with provided className', () => {
- expect(wrapper.classes()).toContain(propsData.className);
- });
+ describe('default', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
- it('should render provided actionText', () => {
- expect(wrapper.text().trim()).toContain(propsData.actionText);
+ it('should render block with provided className', () => {
+ expect(wrapper.classes()).toContain(propsData.className);
+ });
+
+ it('should render provided actionText', () => {
+ expect(wrapper.text().trim()).toContain(propsData.actionText);
+ });
+
+ it('should not render user information', () => {
+ expect(findUserElement().exists()).toBe(false);
+ });
});
- it('should render provided user information', () => {
- const authorLink = wrapper.find('.js-user-link');
+ describe('edited note', () => {
+ const editedBy = {
+ avatar_url: 'path',
+ id: 1,
+ name: 'Root',
+ path: '/root',
+ state: 'active',
+ username: 'root',
+ };
+
+ beforeEach(() => {
+ createWrapper({ editedBy });
+ });
+
+ it('should render user information', () => {
+ const authorLink = findUserElement();
- expect(authorLink.attributes('href')).toEqual(propsData.editedBy.path);
- expect(authorLink.text().trim()).toEqual(propsData.editedBy.name);
+ expect(authorLink.attributes('href')).toEqual(editedBy.path);
+ expect(authorLink.text().trim()).toEqual(editedBy.name);
+ });
});
});
diff --git a/spec/frontend/notes/components/note_form_spec.js b/spec/frontend/notes/components/note_form_spec.js
index 90473e7ccba..59362e18098 100644
--- a/spec/frontend/notes/components/note_form_spec.js
+++ b/spec/frontend/notes/components/note_form_spec.js
@@ -48,10 +48,6 @@ describe('issue_note_form component', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('noteHash', () => {
beforeEach(() => {
wrapper = createComponentWrapper();
diff --git a/spec/frontend/notes/components/note_header_spec.js b/spec/frontend/notes/components/note_header_spec.js
index 56c22b09e1b..b3d6fab7f91 100644
--- a/spec/frontend/notes/components/note_header_spec.js
+++ b/spec/frontend/notes/components/note_header_spec.js
@@ -44,11 +44,6 @@ describe('NoteHeader component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('does not render discussion actions when includeToggle is false', () => {
createComponent({
includeToggle: false,
diff --git a/spec/frontend/notes/components/note_signed_out_widget_spec.js b/spec/frontend/notes/components/note_signed_out_widget_spec.js
index 84f20e4ad58..d56ee234cd9 100644
--- a/spec/frontend/notes/components/note_signed_out_widget_spec.js
+++ b/spec/frontend/notes/components/note_signed_out_widget_spec.js
@@ -12,10 +12,6 @@ describe('NoteSignedOutWidget component', () => {
wrapper = shallowMount(NoteSignedOutWidget, { store });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders sign in link provided in the store', () => {
expect(wrapper.find(`a[href="${notesDataMock.newSessionPath}"]`).text()).toBe('sign in');
});
diff --git a/spec/frontend/notes/components/noteable_discussion_spec.js b/spec/frontend/notes/components/noteable_discussion_spec.js
index a90d8bdde06..ac0c037fe36 100644
--- a/spec/frontend/notes/components/noteable_discussion_spec.js
+++ b/spec/frontend/notes/components/noteable_discussion_spec.js
@@ -22,7 +22,6 @@ jest.mock('~/behaviors/markdown/render_gfm');
describe('noteable_discussion component', () => {
let store;
let wrapper;
- let originalGon;
beforeEach(() => {
window.mrTabs = {};
@@ -36,10 +35,6 @@ describe('noteable_discussion component', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should not render thread header for non diff threads', () => {
expect(wrapper.find('.discussion-header').exists()).toBe(false);
});
@@ -167,16 +162,6 @@ describe('noteable_discussion component', () => {
});
describe('signout widget', () => {
- beforeEach(() => {
- originalGon = { ...window.gon };
- window.gon = window.gon || {};
- });
-
- afterEach(() => {
- wrapper.destroy();
- window.gon = originalGon;
- });
-
describe('user is logged in', () => {
beforeEach(() => {
window.gon.current_user_id = userDataMock.id;
diff --git a/spec/frontend/notes/components/noteable_note_spec.js b/spec/frontend/notes/components/noteable_note_spec.js
index af1b4f64037..b158cfff10d 100644
--- a/spec/frontend/notes/components/noteable_note_spec.js
+++ b/spec/frontend/notes/components/noteable_note_spec.js
@@ -71,10 +71,6 @@ describe('issue_note', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('mutiline comments', () => {
beforeEach(() => {
createWrapper();
diff --git a/spec/frontend/notes/components/notes_activity_header_spec.js b/spec/frontend/notes/components/notes_activity_header_spec.js
index 5b3165bf401..2de491477b6 100644
--- a/spec/frontend/notes/components/notes_activity_header_spec.js
+++ b/spec/frontend/notes/components/notes_activity_header_spec.js
@@ -24,10 +24,6 @@ describe('~/notes/components/notes_activity_header.vue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js
index b08a22f8674..832264aa7d3 100644
--- a/spec/frontend/notes/components/notes_app_spec.js
+++ b/spec/frontend/notes/components/notes_app_spec.js
@@ -90,8 +90,9 @@ describe('note_app', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
+ wrapper.destroy();
});
describe('render', () => {
diff --git a/spec/frontend/notes/components/toggle_replies_widget_spec.js b/spec/frontend/notes/components/toggle_replies_widget_spec.js
index 8c3696e88b7..ef5f06ad2fa 100644
--- a/spec/frontend/notes/components/toggle_replies_widget_spec.js
+++ b/spec/frontend/notes/components/toggle_replies_widget_spec.js
@@ -30,10 +30,6 @@ describe('toggle replies widget for notes', () => {
const mountComponent = ({ collapsed = false }) =>
mountExtended(ToggleRepliesWidget, { propsData: { replies, collapsed } });
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('collapsed state', () => {
beforeEach(() => {
wrapper = mountComponent({ collapsed: true });
diff --git a/spec/frontend/notes/deprecated_notes_spec.js b/spec/frontend/notes/deprecated_notes_spec.js
index 6d3bc19bd45..40f10ca901b 100644
--- a/spec/frontend/notes/deprecated_notes_spec.js
+++ b/spec/frontend/notes/deprecated_notes_spec.js
@@ -23,7 +23,6 @@ const fixture = 'snippets/show.html';
let mockAxios;
window.project_uploads_path = `${TEST_HOST}/uploads`;
-window.gon = window.gon || {};
window.gl = window.gl || {};
gl.utils = gl.utils || {};
gl.utils.disableButtonIfEmptyField = () => {};
diff --git a/spec/frontend/notes/stores/actions_spec.js b/spec/frontend/notes/stores/actions_spec.js
index c4c0dc58b0d..0d3ebea7af2 100644
--- a/spec/frontend/notes/stores/actions_spec.js
+++ b/spec/frontend/notes/stores/actions_spec.js
@@ -3,7 +3,7 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import testAction from 'helpers/vuex_action_helper';
import { TEST_HOST } from 'spec/test_constants';
import Api from '~/api';
-import { createAlert } from '~/flash';
+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';
@@ -36,7 +36,7 @@ import {
const TEST_ERROR_MESSAGE = 'Test error message';
const mockAlertDismiss = jest.fn();
-jest.mock('~/flash', () => ({
+jest.mock('~/alert', () => ({
createAlert: jest.fn().mockImplementation(() => ({
dismiss: mockAlertDismiss,
})),
@@ -876,7 +876,7 @@ describe('Actions Notes Store', () => {
const res = { errors: { base: ['something went wrong'] } };
const error = { message: 'Unprocessable entity', response: { data: res } };
- it('sets flash alert using errors.base message', async () => {
+ it('sets an alert using errors.base message', async () => {
const resp = await actions.saveNote(
{
commit() {},
@@ -906,6 +906,20 @@ describe('Actions Notes Store', () => {
expect(data).toBe(res);
expect(createAlert).not.toHaveBeenCalled();
});
+
+ it('dispatches clearDrafts is command names contains submit_review', async () => {
+ const response = { command_names: ['submit_review'], valid: true };
+ dispatch = jest.fn().mockResolvedValue(response);
+ await actions.saveNote(
+ {
+ commit() {},
+ dispatch,
+ },
+ payload,
+ );
+
+ expect(dispatch).toHaveBeenCalledWith('batchComments/clearDrafts');
+ });
});
});
@@ -946,7 +960,7 @@ describe('Actions Notes Store', () => {
});
});
- it('when service fails, flashes error message', () => {
+ it('when service fails, creates an alert with error message', () => {
const response = { response: { data: { message: TEST_ERROR_MESSAGE } } };
Api.applySuggestion.mockReturnValue(Promise.reject(response));
@@ -1439,10 +1453,6 @@ describe('Actions Notes Store', () => {
describe('fetchDiscussions', () => {
const discussion = { notes: [] };
- afterEach(() => {
- window.gon = {};
- });
-
it('updates the discussions and dispatches `updateResolvableDiscussionsCounts`', () => {
axiosMock.onAny().reply(HTTP_STATUS_OK, { discussion });
return testAction(
diff --git a/spec/frontend/notifications/components/custom_notifications_modal_spec.js b/spec/frontend/notifications/components/custom_notifications_modal_spec.js
index 70749557e61..0fbd073191e 100644
--- a/spec/frontend/notifications/components/custom_notifications_modal_spec.js
+++ b/spec/frontend/notifications/components/custom_notifications_modal_spec.js
@@ -2,7 +2,6 @@ import { GlSprintf, GlModal, GlFormGroup, GlFormCheckbox, GlLoadingIcon } from '
import { shallowMount } from '@vue/test-utils';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
@@ -66,8 +65,6 @@ describe('CustomNotificationsModal', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
mockAxios.restore();
});
@@ -87,24 +84,23 @@ describe('CustomNotificationsModal', () => {
describe('checkbox items', () => {
beforeEach(async () => {
+ const endpointUrl = '/api/v4/notification_settings';
+
+ mockAxios
+ .onGet(endpointUrl)
+ .reply(HTTP_STATUS_OK, mockNotificationSettingsResponses.default);
+
wrapper = createComponent();
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- events: [
- { id: 'new_release', enabled: true, name: 'New release', loading: false },
- { id: 'new_note', enabled: false, name: 'New note', loading: true },
- ],
- });
+ wrapper.findComponent(GlModal).vm.$emit('show');
- await nextTick();
+ await waitForPromises();
});
it.each`
index | eventId | eventName | enabled | loading
${0} | ${'new_release'} | ${'New release'} | ${true} | ${false}
- ${1} | ${'new_note'} | ${'New note'} | ${false} | ${true}
+ ${1} | ${'new_note'} | ${'New note'} | ${false} | ${false}
`(
'renders a checkbox for "$eventName" with checked=$enabled',
async ({ index, eventName, enabled, loading }) => {
@@ -214,16 +210,9 @@ describe('CustomNotificationsModal', () => {
wrapper = createComponent({ injectedProperties });
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- events: [
- { id: 'new_release', enabled: true, name: 'New release', loading: false },
- { id: 'new_note', enabled: false, name: 'New note', loading: false },
- ],
- });
+ wrapper.findComponent(GlModal).vm.$emit('show');
- await nextTick();
+ await waitForPromises();
findCheckboxAt(1).vm.$emit('change', true);
@@ -241,19 +230,18 @@ describe('CustomNotificationsModal', () => {
);
it('shows a toast message when the request fails', async () => {
- mockAxios.onPut('/api/v4/notification_settings').reply(HTTP_STATUS_NOT_FOUND, {});
+ const endpointUrl = '/api/v4/notification_settings';
+
+ mockAxios
+ .onGet(endpointUrl)
+ .reply(HTTP_STATUS_OK, mockNotificationSettingsResponses.default);
+
+ mockAxios.onPut(endpointUrl).reply(HTTP_STATUS_NOT_FOUND, {});
wrapper = createComponent();
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- events: [
- { id: 'new_release', enabled: true, name: 'New release', loading: false },
- { id: 'new_note', enabled: false, name: 'New note', loading: false },
- ],
- });
+ wrapper.findComponent(GlModal).vm.$emit('show');
- await nextTick();
+ await waitForPromises();
findCheckboxAt(1).vm.$emit('change', true);
diff --git a/spec/frontend/notifications/components/notifications_dropdown_spec.js b/spec/frontend/notifications/components/notifications_dropdown_spec.js
index 0f13de0e6d8..bae9b028cf7 100644
--- a/spec/frontend/notifications/components/notifications_dropdown_spec.js
+++ b/spec/frontend/notifications/components/notifications_dropdown_spec.js
@@ -25,7 +25,7 @@ describe('NotificationsDropdown', () => {
CustomNotificationsModal,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
provide: {
dropdownItems: mockDropdownItems,
@@ -61,8 +61,6 @@ describe('NotificationsDropdown', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
mockAxios.restore();
});
diff --git a/spec/frontend/observability/index_spec.js b/spec/frontend/observability/index_spec.js
new file mode 100644
index 00000000000..83f72ff72b5
--- /dev/null
+++ b/spec/frontend/observability/index_spec.js
@@ -0,0 +1,64 @@
+import { createWrapper } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import renderObservability from '~/observability/index';
+import ObservabilityApp from '~/observability/components/observability_app.vue';
+import { SKELETON_VARIANTS_BY_ROUTE } from '~/observability/constants';
+
+describe('renderObservability', () => {
+ let element;
+ let vueInstance;
+ let component;
+
+ const OBSERVABILITY_ROUTES = Object.keys(SKELETON_VARIANTS_BY_ROUTE);
+ const SKELETON_VARIANTS = Object.values(SKELETON_VARIANTS_BY_ROUTE);
+
+ beforeEach(() => {
+ element = document.createElement('div');
+ element.setAttribute('id', 'js-observability-app');
+ element.dataset.observabilityIframeSrc = 'https://observe.gitlab.com/';
+ document.body.appendChild(element);
+
+ vueInstance = renderObservability();
+ component = createWrapper(vueInstance).findComponent(ObservabilityApp);
+ });
+
+ afterEach(() => {
+ element.remove();
+ });
+
+ it('should return a Vue instance', () => {
+ expect(vueInstance).toEqual(expect.any(Vue));
+ });
+
+ it('should render the ObservabilityApp component', () => {
+ expect(component.props('observabilityIframeSrc')).toBe('https://observe.gitlab.com/');
+ });
+
+ describe('skeleton variant', () => {
+ it.each`
+ pathDescription | path | variant
+ ${'dashboards'} | ${OBSERVABILITY_ROUTES[0]} | ${SKELETON_VARIANTS[0]}
+ ${'explore'} | ${OBSERVABILITY_ROUTES[1]} | ${SKELETON_VARIANTS[1]}
+ ${'manage dashboards'} | ${OBSERVABILITY_ROUTES[2]} | ${SKELETON_VARIANTS[2]}
+ ${'any other'} | ${'unknown/route'} | ${SKELETON_VARIANTS[0]}
+ `(
+ 'renders the $variant skeleton variant for $pathDescription path',
+ async ({ path, variant }) => {
+ component.vm.$router.push(path);
+ await nextTick();
+
+ expect(component.props('skeletonVariant')).toBe(variant);
+ },
+ );
+ });
+
+ it('handle route-update events', async () => {
+ component.vm.$router.push('/something?foo=bar');
+ component.vm.$emit('route-update', { url: '/some_path' });
+ expect(component.vm.$router.currentRoute.path).toBe('/something');
+ expect(component.vm.$router.currentRoute.query).toEqual({
+ foo: 'bar',
+ observability_path: '/some_path',
+ });
+ });
+});
diff --git a/spec/frontend/observability/observability_app_spec.js b/spec/frontend/observability/observability_app_spec.js
index e3bcd140d60..4a9be71b880 100644
--- a/spec/frontend/observability/observability_app_spec.js
+++ b/spec/frontend/observability/observability_app_spec.js
@@ -1,19 +1,20 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ObservabilityApp from '~/observability/components/observability_app.vue';
import ObservabilitySkeleton from '~/observability/components/skeleton/index.vue';
-
-import { MESSAGE_EVENT_TYPE, SKELETON_VARIANTS_BY_ROUTE } from '~/observability/constants';
+import {
+ MESSAGE_EVENT_TYPE,
+ INLINE_EMBED_DIMENSIONS,
+ FULL_APP_DIMENSIONS,
+ SKELETON_VARIANT_EMBED,
+} from '~/observability/constants';
import { darkModeEnabled } from '~/lib/utils/color_utils';
jest.mock('~/lib/utils/color_utils');
-describe('Observability root app', () => {
+describe('ObservabilityApp', () => {
let wrapper;
- const replace = jest.fn();
- const $router = {
- replace,
- };
+
const $route = {
pathname: 'https://gitlab.com/gitlab-org/',
path: 'https://gitlab.com/gitlab-org/-/observability/dashboards',
@@ -26,21 +27,19 @@ describe('Observability root app', () => {
const TEST_IFRAME_SRC = 'https://observe.gitlab.com/9970/?groupId=14485840';
- const OBSERVABILITY_ROUTES = Object.keys(SKELETON_VARIANTS_BY_ROUTE);
-
- const SKELETON_VARIANTS = Object.values(SKELETON_VARIANTS_BY_ROUTE);
+ const TEST_USERNAME = 'test-user';
- const mountComponent = (route = $route) => {
+ const mountComponent = (props) => {
wrapper = shallowMountExtended(ObservabilityApp, {
propsData: {
observabilityIframeSrc: TEST_IFRAME_SRC,
+ ...props,
},
stubs: {
'observability-skeleton': ObservabilitySkeleton,
},
mocks: {
- $router,
- $route: route,
+ $route,
},
});
};
@@ -48,17 +47,11 @@ describe('Observability root app', () => {
const dispatchMessageEvent = (message) =>
window.dispatchEvent(new MessageEvent('message', message));
- afterEach(() => {
- wrapper.destroy();
+ beforeEach(() => {
+ gon.current_username = TEST_USERNAME;
});
describe('iframe src', () => {
- const TEST_USERNAME = 'test-user';
-
- beforeAll(() => {
- gon.current_username = TEST_USERNAME;
- });
-
it('should render an iframe with observabilityIframeSrc, decorated with light theme and username', () => {
darkModeEnabled.mockReturnValueOnce(false);
mountComponent();
@@ -92,48 +85,70 @@ describe('Observability root app', () => {
});
});
- describe('on GOUI_ROUTE_UPDATE', () => {
- it('should not call replace method from vue router if message event does not have url', () => {
- mountComponent();
- dispatchMessageEvent({
- type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE,
- payload: { data: 'some other data' },
+ describe('iframe kiosk query param', () => {
+ it('when inlineEmbed, it should set the proper kiosk query parameter', () => {
+ mountComponent({
+ inlineEmbed: true,
});
- expect(replace).not.toHaveBeenCalled();
+
+ const iframe = findIframe();
+
+ expect(iframe.attributes('src')).toBe(
+ `${TEST_IFRAME_SRC}&theme=light&username=${TEST_USERNAME}&kiosk=inline-embed`,
+ );
});
+ });
- it.each`
- condition | origin | observability_path | url
- ${'message origin is different from iframe source origin'} | ${'https://example.com'} | ${'/'} | ${'/explore'}
- ${'path is same as before (observability_path)'} | ${'https://observe.gitlab.com'} | ${'/foo?bar=test'} | ${'/foo?bar=test'}
- `(
- 'should not call replace method from vue router if $condition',
- async ({ origin, observability_path, url }) => {
- mountComponent({ ...$route, query: { observability_path } });
- dispatchMessageEvent({
- data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url } },
- origin,
- });
- expect(replace).not.toHaveBeenCalled();
- },
- );
+ describe('iframe size', () => {
+ it('should set the specified size', () => {
+ mountComponent({
+ height: INLINE_EMBED_DIMENSIONS.HEIGHT,
+ width: INLINE_EMBED_DIMENSIONS.WIDTH,
+ });
+
+ const iframe = findIframe();
+
+ expect(iframe.attributes('width')).toBe(INLINE_EMBED_DIMENSIONS.WIDTH);
+ expect(iframe.attributes('height')).toBe(INLINE_EMBED_DIMENSIONS.HEIGHT);
+ });
+
+ it('should fallback to default size', () => {
+ mountComponent({});
+
+ const iframe = findIframe();
- it('should call replace method from vue router on message event callback', () => {
+ expect(iframe.attributes('width')).toBe(FULL_APP_DIMENSIONS.WIDTH);
+ expect(iframe.attributes('height')).toBe(FULL_APP_DIMENSIONS.HEIGHT);
+ });
+ });
+
+ describe('skeleton variant', () => {
+ it('sets the specified skeleton variant', () => {
+ mountComponent({ skeletonVariant: SKELETON_VARIANT_EMBED });
+ const props = wrapper.findComponent(ObservabilitySkeleton).props();
+
+ expect(props.variant).toBe(SKELETON_VARIANT_EMBED);
+ });
+
+ it('should have a default skeleton variant', () => {
+ mountComponent();
+ const props = wrapper.findComponent(ObservabilitySkeleton).props();
+
+ expect(props.variant).toBe('dashboards');
+ });
+ });
+
+ describe('on GOUI_ROUTE_UPDATE', () => {
+ it('should emit a route-update event', () => {
mountComponent();
+ const payload = { url: '/explore' };
dispatchMessageEvent({
- data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url: '/explore' } },
+ data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload },
origin: 'https://observe.gitlab.com',
});
- expect(replace).toHaveBeenCalled();
- expect(replace).toHaveBeenCalledWith({
- name: 'https://gitlab.com/gitlab-org/',
- query: {
- otherQuery: 100,
- observability_path: '/explore',
- },
- });
+ expect(wrapper.emitted('route-update')[0]).toEqual([payload]);
});
});
@@ -167,34 +182,17 @@ describe('Observability root app', () => {
});
});
- describe('skeleton variant', () => {
- it.each`
- pathDescription | path | variant
- ${'dashboards'} | ${OBSERVABILITY_ROUTES[0]} | ${SKELETON_VARIANTS[0]}
- ${'explore'} | ${OBSERVABILITY_ROUTES[1]} | ${SKELETON_VARIANTS[1]}
- ${'manage dashboards'} | ${OBSERVABILITY_ROUTES[2]} | ${SKELETON_VARIANTS[2]}
- ${'any other'} | ${'unknown/route'} | ${SKELETON_VARIANTS[0]}
- `('renders the $variant skeleton variant for $pathDescription path', ({ path, variant }) => {
- mountComponent({ ...$route, path });
- const props = wrapper.findComponent(ObservabilitySkeleton).props();
-
- expect(props.variant).toBe(variant);
- });
- });
-
- describe('on observability ui unmount', () => {
- it('should remove message event and should not call replace method from vue router', () => {
+ describe('on unmount', () => {
+ it('should not emit any even on route update', () => {
mountComponent();
wrapper.destroy();
- // testing event cleanup logic, should not call on messege event after component is destroyed
-
dispatchMessageEvent({
data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url: '/explore' } },
origin: 'https://observe.gitlab.com',
});
- expect(replace).not.toHaveBeenCalled();
+ expect(wrapper.emitted('route-update')).toBeUndefined();
});
});
});
diff --git a/spec/frontend/observability/skeleton_spec.js b/spec/frontend/observability/skeleton_spec.js
index a95597d8516..65dbb003743 100644
--- a/spec/frontend/observability/skeleton_spec.js
+++ b/spec/frontend/observability/skeleton_spec.js
@@ -6,8 +6,13 @@ import Skeleton from '~/observability/components/skeleton/index.vue';
import DashboardsSkeleton from '~/observability/components/skeleton/dashboards.vue';
import ExploreSkeleton from '~/observability/components/skeleton/explore.vue';
import ManageSkeleton from '~/observability/components/skeleton/manage.vue';
+import EmbedSkeleton from '~/observability/components/skeleton/embed.vue';
-import { SKELETON_VARIANTS_BY_ROUTE, DEFAULT_TIMERS } from '~/observability/constants';
+import {
+ SKELETON_VARIANTS_BY_ROUTE,
+ DEFAULT_TIMERS,
+ SKELETON_VARIANT_EMBED,
+} from '~/observability/constants';
describe('Skeleton component', () => {
let wrapper;
@@ -22,6 +27,8 @@ describe('Skeleton component', () => {
const findManageSkeleton = () => wrapper.findComponent(ManageSkeleton);
+ const findEmbedSkeleton = () => wrapper.findComponent(EmbedSkeleton);
+
const findAlert = () => wrapper.findComponent(GlAlert);
const mountComponent = ({ ...props } = {}) => {
@@ -97,16 +104,20 @@ describe('Skeleton component', () => {
${'dashboards'} | ${'variant is dashboards'} | ${SKELETON_VARIANTS[0]}
${'explore'} | ${'variant is explore'} | ${SKELETON_VARIANTS[1]}
${'manage'} | ${'variant is manage'} | ${SKELETON_VARIANTS[2]}
+ ${'embed'} | ${'variant is embed'} | ${SKELETON_VARIANT_EMBED}
${'default'} | ${'variant is not manage, dashboards or explore'} | ${'unknown'}
`('should render $skeletonType skeleton if $condition', async ({ skeletonType, variant }) => {
mountComponent({ variant });
jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS);
await nextTick();
- const showsDefaultSkeleton = !SKELETON_VARIANTS.includes(variant);
+ const showsDefaultSkeleton = ![...SKELETON_VARIANTS, SKELETON_VARIANT_EMBED].includes(
+ variant,
+ );
expect(findDashboardsSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[0]);
expect(findExploreSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[1]);
expect(findManageSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[2]);
+ expect(findEmbedSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANT_EMBED);
expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(showsDefaultSkeleton);
});
diff --git a/spec/frontend/operation_settings/components/metrics_settings_spec.js b/spec/frontend/operation_settings/components/metrics_settings_spec.js
index 732dfdd42fb..ee450dfc851 100644
--- a/spec/frontend/operation_settings/components/metrics_settings_spec.js
+++ b/spec/frontend/operation_settings/components/metrics_settings_spec.js
@@ -2,7 +2,7 @@ import { GlButton, GlLink, GlFormGroup, GlFormInput, GlFormSelect } from '@gitla
import { mount, shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { TEST_HOST } from 'helpers/test_constants';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { timezones } from '~/monitoring/format_date';
@@ -13,7 +13,7 @@ import MetricsSettings from '~/operation_settings/components/metrics_settings.vu
import store from '~/operation_settings/store';
jest.mock('~/lib/utils/url_utility');
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('operation settings external dashboard component', () => {
let wrapper;
@@ -198,7 +198,7 @@ describe('operation settings external dashboard component', () => {
expect(refreshCurrentPage).toHaveBeenCalled();
});
- it('creates flash banner on error', async () => {
+ it('creates alert banner on error', async () => {
mountComponent(false);
const message = 'mockErrorMessage';
axios.patch.mockRejectedValue({ response: { data: { message } } });
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js
index ff11c8843bb..8ba7e40d728 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js
@@ -27,11 +27,6 @@ describe('delete_button', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('tooltip', () => {
it('the title is controlled by tooltipTitle prop', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_image_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_image_spec.js
index 620c96e8c9e..5a7cbdcff5b 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_image_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_image_spec.js
@@ -46,11 +46,6 @@ describe('Delete Image', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('executes apollo mutate on doDelete', () => {
const mutate = jest.fn().mockResolvedValue({});
mountComponent({ mutate });
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_alert_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_alert_spec.js
index d45b993b5a2..9d187439ca3 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_alert_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_alert_spec.js
@@ -19,11 +19,6 @@ describe('Delete alert', () => {
wrapper = shallowMount(component, { stubs: { GlSprintf }, propsData });
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when deleteAlertType is null', () => {
it('does not show the alert', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js
index 16c9485e69e..860f9b3a0c1 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js
@@ -30,15 +30,10 @@ describe('Delete Modal', () => {
const expectPrimaryActionStatus = (disabled = true) =>
expect(findModal().props('actionPrimary')).toMatchObject(
expect.objectContaining({
- attributes: [{ variant: 'danger' }, { disabled }],
+ attributes: { variant: 'danger', disabled },
}),
);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('contains a GlModal', () => {
mountComponent();
expect(findModal().exists()).toBe(true);
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js
index b37edac83f7..9e443234c34 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js
@@ -73,7 +73,7 @@ describe('Details Header', () => {
apolloProvider,
propsData,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
stubs: {
TitleArea,
@@ -85,9 +85,7 @@ describe('Details Header', () => {
afterEach(() => {
// if we want to mix createMockApollo and manual mocks we need to reset everything
- wrapper.destroy();
apolloProvider = undefined;
- wrapper = null;
});
describe('image name', () => {
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/partial_cleanup_alert_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/partial_cleanup_alert_spec.js
index ce5ecfe4608..d6c1b2c3f51 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/partial_cleanup_alert_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/partial_cleanup_alert_spec.js
@@ -23,11 +23,6 @@ describe('Partial Cleanup alert', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it(`gl-alert has the correct properties`, () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/status_alert_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/status_alert_spec.js
index d83a5099bcd..3e1fd14475d 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/status_alert_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/status_alert_spec.js
@@ -27,11 +27,6 @@ describe('Status Alert', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it.each`
status | title | variant | message | link
${DELETE_SCHEDULED} | ${SCHEDULED_FOR_DELETION_STATUS_TITLE} | ${'info'} | ${SCHEDULED_FOR_DELETION_STATUS_MESSAGE} | ${PACKAGE_DELETE_HELP_PAGE_PATH}
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js
index fa0d76762df..bfefe46c09b 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js
@@ -50,16 +50,11 @@ describe('tags list row', () => {
},
propsData,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('checkbox', () => {
it('exists', () => {
mountComponent();
@@ -283,26 +278,30 @@ describe('tags list row', () => {
textSrOnly: true,
category: 'tertiary',
right: true,
+ disabled: false,
});
});
- it.each`
- canDelete | digest | disabled | buttonDisabled
- ${true} | ${null} | ${true} | ${true}
- ${false} | ${'foo'} | ${true} | ${true}
- ${false} | ${null} | ${true} | ${true}
- ${true} | ${'foo'} | ${true} | ${true}
- ${true} | ${'foo'} | ${false} | ${false}
- `(
- 'is $visible that is visible when canDelete is $canDelete and digest is $digest and disabled is $disabled',
- ({ canDelete, digest, disabled, buttonDisabled }) => {
- mountComponent({ ...defaultProps, tag: { ...tag, canDelete, digest }, disabled });
+ it('has the correct classes', () => {
+ mountComponent();
- expect(findAdditionalActionsMenu().props('disabled')).toBe(buttonDisabled);
- expect(findAdditionalActionsMenu().classes('gl-opacity-0')).toBe(buttonDisabled);
- expect(findAdditionalActionsMenu().classes('gl-pointer-events-none')).toBe(buttonDisabled);
- },
- );
+ expect(findAdditionalActionsMenu().classes('gl-opacity-0')).toBe(false);
+ expect(findAdditionalActionsMenu().classes('gl-pointer-events-none')).toBe(false);
+ });
+
+ it('is not rendered when tag.canDelete is false', () => {
+ mountComponent({ ...defaultProps, tag: { ...tag, canDelete: false } });
+
+ expect(findAdditionalActionsMenu().exists()).toBe(false);
+ });
+
+ it('is hidden when disabled prop is set to true', () => {
+ mountComponent({ ...defaultProps, disabled: true });
+
+ expect(findAdditionalActionsMenu().props('disabled')).toBe(true);
+ expect(findAdditionalActionsMenu().classes('gl-opacity-0')).toBe(true);
+ expect(findAdditionalActionsMenu().classes('gl-pointer-events-none')).toBe(true);
+ });
describe('delete button', () => {
it('exists and has the correct attrs', () => {
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js
index 1017ff06a25..09d0370efbf 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js
@@ -68,15 +68,11 @@ describe('Tags List', () => {
resolver = jest.fn().mockResolvedValue(imageTagsMock());
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('registry list', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mountComponent();
fireFirstSortUpdate();
- return waitForApolloRequestRender();
+ await waitForApolloRequestRender();
});
it('has a persisted search', () => {
@@ -98,6 +94,7 @@ describe('Tags List', () => {
pagination: tagsPageInfo,
items: tags,
idProperty: 'name',
+ hiddenDelete: false,
});
});
@@ -186,12 +183,23 @@ describe('Tags List', () => {
});
});
+ describe('when user does not have permission to delete list rows', () => {
+ it('sets registry list hiddenDelete prop to true', async () => {
+ resolver = jest.fn().mockResolvedValue(imageTagsMock({ canDelete: false }));
+ mountComponent();
+ fireFirstSortUpdate();
+ await waitForApolloRequestRender();
+
+ expect(findRegistryList().props('hiddenDelete')).toBe(true);
+ });
+ });
+
describe('when the list of tags is empty', () => {
- beforeEach(() => {
- resolver = jest.fn().mockResolvedValue(imageTagsMock([]));
+ beforeEach(async () => {
+ resolver = jest.fn().mockResolvedValue(imageTagsMock({ nodes: [] }));
mountComponent();
fireFirstSortUpdate();
- return waitForApolloRequestRender();
+ await waitForApolloRequestRender();
});
it('does not show the loader', () => {
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js
index 88e79c513bc..8896185ce67 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js
@@ -20,11 +20,6 @@ describe('TagsLoader component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('produces the correct amount of loaders', () => {
mountComponent();
expect(findGlSkeletonLoaders().length).toBe(1);
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
index 535faebdd4e..0d1d2c53cab 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
@@ -36,10 +36,6 @@ describe('cleanup_status', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
status | visible | text
${UNFINISHED_STATUS} | ${true} | ${CLEANUP_STATUS_UNFINISHED}
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/group_empty_state_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/group_empty_state_spec.js
index d2086943e4f..900ea61e4ea 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/group_empty_state_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/group_empty_state_spec.js
@@ -26,10 +26,6 @@ describe('Registry Group Empty state', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('to match the default snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js
index 75068591007..7da9c7533a0 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js
@@ -1,4 +1,4 @@
-import { GlIcon, GlSprintf, GlSkeletonLoader, GlButton } from '@gitlab/ui';
+import { GlSprintf, GlSkeletonLoader, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createMockDirective } from 'helpers/vue_mock_directive';
import { mockTracking } from 'helpers/tracking_helper';
@@ -49,16 +49,11 @@ describe('Image List Row', () => {
config: {},
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('image title and path', () => {
it('renders shortened name of image and contains a link to the details page', () => {
mountComponent();
@@ -206,13 +201,6 @@ describe('Image List Row', () => {
expect(findTagsCount().exists()).toBe(true);
});
- it('contains a tag icon', () => {
- mountComponent();
- const icon = findTagsCount().findComponent(GlIcon);
- expect(icon.exists()).toBe(true);
- expect(icon.props('name')).toBe('tag');
- });
-
describe('loading state', () => {
it('shows a loader when metadataLoading is true', () => {
mountComponent({ metadataLoading: true });
@@ -231,12 +219,12 @@ describe('Image List Row', () => {
it('with one tag in the image', () => {
mountComponent({ item: { ...item, tagsCount: 1 } });
- expect(findTagsCount().text()).toMatchInterpolatedText('1 Tag');
+ expect(findTagsCount().text()).toMatchInterpolatedText('1 tag');
});
it('with more than one tag in the image', () => {
mountComponent({ item: { ...item, tagsCount: 3 } });
- expect(findTagsCount().text()).toMatchInterpolatedText('3 Tags');
+ expect(findTagsCount().text()).toMatchInterpolatedText('3 tags');
});
});
});
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js
index 042b8383571..6c771887b88 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js
@@ -21,11 +21,6 @@ describe('Image List', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('list', () => {
it('contains one list element for each image', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/project_empty_state_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/project_empty_state_spec.js
index 8cfa8128021..e4d13143484 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/project_empty_state_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/project_empty_state_spec.js
@@ -34,10 +34,6 @@ describe('Registry Project Empty state', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('to match the default snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
index bcc8e41fce8..45304cc2329 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
@@ -35,11 +35,6 @@ describe('registry_header', () => {
await nextTick();
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('header', () => {
it('has a title', () => {
mountComponent({ metadataLoading: true });
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
index e5b99f15e8c..cd54b856c97 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
@@ -177,11 +177,12 @@ export const tagsMock = [
},
];
-export const imageTagsMock = (nodes = tagsMock) => ({
+export const imageTagsMock = ({ nodes = tagsMock, canDelete = true } = {}) => ({
data: {
containerRepository: {
id: containerRepositoryMock.id,
tagsCount: nodes.length,
+ canDelete,
tags: {
nodes,
pageInfo: { ...tagsPageInfo },
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
index 26f0e506829..888c3e5bffa 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js
@@ -127,11 +127,6 @@ describe('Details Page', () => {
jest.spyOn(Tracking, 'event');
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when isLoading is true', () => {
it('shows the loader', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
index 1e514d85e82..acc61157ab5 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
@@ -113,10 +113,6 @@ describe('List Page', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains registry header', async () => {
mountComponent();
fireFirstSortUpdate();
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 601f8abd34d..c2ae34ce697 100644
--- a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
+++ b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
@@ -31,11 +31,6 @@ import { proxyDetailsQuery, proxyData, pagination, proxyManifests } from './mock
const dummyApiVersion = 'v3000';
const dummyGrouptId = 1;
const dummyUrlRoot = '/gitlab';
-const dummyGon = {
- api_version: dummyApiVersion,
- relative_url_root: dummyUrlRoot,
-};
-let originalGon;
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${dummyGrouptId}/dependency_proxy/cache`;
Vue.use(VueApollo);
@@ -89,16 +84,16 @@ describe('DependencyProxyApp', () => {
beforeEach(() => {
resolver = jest.fn().mockResolvedValue(proxyDetailsQuery());
- originalGon = window.gon;
- window.gon = { ...dummyGon };
+ window.gon = {
+ api_version: dummyApiVersion,
+ relative_url_root: dummyUrlRoot,
+ };
mock = new MockAdapter(axios);
mock.onDelete(expectedUrl).reply(HTTP_STATUS_ACCEPTED, {});
});
afterEach(() => {
- wrapper.destroy();
- window.gon = originalGon;
mock.restore();
});
diff --git a/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_list_spec.js b/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_list_spec.js
index 2f415bfd6f9..639a4fbb99d 100644
--- a/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_list_spec.js
+++ b/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_list_spec.js
@@ -25,10 +25,6 @@ describe('Manifests List', () => {
const findRows = () => wrapper.findAllComponents(ManifestRow);
const findPagination = () => wrapper.findComponent(GlKeysetPagination);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has the correct title', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js b/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js
index be3236d1f9c..ace5ce3a58d 100644
--- a/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js
+++ b/spec/frontend/packages_and_registries/dependency_proxy/components/manifest_row_spec.js
@@ -29,10 +29,6 @@ describe('Manifest Row', () => {
const findTimeAgoTooltip = () => wrapper.findComponent(TimeagoTooltip);
const findStatus = () => wrapper.findByTestId('status');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('With a manifest on the DEFAULT status', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js
index a2e5cbdce8b..1e9b9b1ce47 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js
@@ -63,10 +63,6 @@ describe('Harbor artifact list row', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('list item', () => {
beforeEach(() => {
mountComponent({
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_spec.js
index b9d6dc2679e..786a4715731 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_spec.js
@@ -26,10 +26,6 @@ describe('Harbor artifacts list', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when isLoading is true', () => {
beforeEach(() => {
mountComponent({
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/details/details_header_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/details/details_header_spec.js
index e8cc2b2e22d..d8fb91c085c 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/details/details_header_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/details/details_header_spec.js
@@ -20,10 +20,6 @@ describe('Harbor Details Header', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('artifact name', () => {
describe('missing image name', () => {
beforeEach(() => {
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js
index 7a6169d300c..9a7ad759dba 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_header_spec.js
@@ -29,10 +29,6 @@ describe('harbor_list_header', () => {
await nextTick();
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('header', () => {
it('has a title', () => {
mountComponent({ metadataLoading: true });
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js
index b62d4e8836b..1e031e0557a 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_row_spec.js
@@ -28,10 +28,6 @@ describe('Harbor List Row', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('image title and path', () => {
it('contains a link to the details page', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js
index e7e74a0da58..a1803ecf7fb 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/list/harbor_list_spec.js
@@ -20,10 +20,6 @@ describe('Harbor List', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('list', () => {
it('contains one list element for each image', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_header_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_header_spec.js
index 5e299a269e3..9370ff1fdd4 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_header_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_header_spec.js
@@ -26,10 +26,6 @@ describe('Harbor Tags Header', () => {
totalPages: 1,
};
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
mountComponent({
propsData: { artifactDetail: mockArtifactDetail, pageInfo: mockPageInfo, tagsLoading: false },
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_row_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_row_spec.js
index 849215e286b..0b2ce01ebf6 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_row_spec.js
@@ -37,10 +37,6 @@ describe('Harbor tag list row', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('list item', () => {
beforeEach(() => {
mountComponent({
diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_spec.js
index 4c6b2b6daaa..e2a2a584b7d 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/components/tags/tags_list_spec.js
@@ -24,10 +24,6 @@ describe('Harbor Tags List', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when isLoading is true', () => {
beforeEach(() => {
mountComponent({
diff --git a/spec/frontend/packages_and_registries/harbor_registry/pages/details_spec.js b/spec/frontend/packages_and_registries/harbor_registry/pages/details_spec.js
index 69765d31674..90c3d9082f7 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/pages/details_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/pages/details_spec.js
@@ -74,10 +74,6 @@ describe('Harbor Details Page', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when isLoading is true', () => {
it('shows the loader', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js b/spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js
index 97d30e6fe99..63ea8feb1e7 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/pages/list_spec.js
@@ -60,10 +60,6 @@ describe('Harbor List Page', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains harbor registry header', async () => {
mountComponent();
fireFirstSortUpdate();
diff --git a/spec/frontend/packages_and_registries/harbor_registry/pages/tags_spec.js b/spec/frontend/packages_and_registries/harbor_registry/pages/tags_spec.js
index 10901c6ec1e..6002faa1fa3 100644
--- a/spec/frontend/packages_and_registries/harbor_registry/pages/tags_spec.js
+++ b/spec/frontend/packages_and_registries/harbor_registry/pages/tags_spec.js
@@ -60,10 +60,6 @@ describe('Harbor Tags page', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains tags header', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js
index e74375b7705..f8130287c12 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js
@@ -86,10 +86,6 @@ describe('PackagesApp', () => {
const findTerraformInstallation = () => wrapper.findComponent(TerraformInstallation);
const findPackageFiles = () => wrapper.findComponent(PackageFiles);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the app and displays the package title', async () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js
index b504f7489ab..148e87699f1 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js
@@ -39,10 +39,6 @@ describe('PackageTitle', () => {
const pipelineProject = () => wrapper.find('[data-testid="pipeline-project"]');
const packageRef = () => wrapper.find('[data-testid="package-ref"]');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('module title', () => {
it('is correctly bound', async () => {
await createComponent();
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/file_sha_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/file_sha_spec.js
index d7caa8ca2d8..7352afff051 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/file_sha_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/file_sha_spec.js
@@ -23,10 +23,6 @@ describe('FileSha', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js
index b76d7c2b57b..c3e0818fc11 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_files_spec.js
@@ -37,11 +37,6 @@ describe('Package Files', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('rows', () => {
it('renders a single file for an npm package', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_history_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_history_spec.js
index 0cbe2755f7e..a650aba464e 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_history_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/package_history_spec.js
@@ -30,11 +30,6 @@ describe('Package History', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findHistoryElement = (testId) => wrapper.find(`[data-testid="${testId}"]`);
const findElementLink = (container) => container.findComponent(GlLink);
const findElementTimeAgo = (container) => container.findComponent(TimeAgoTooltip);
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/terraform_installation_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/terraform_installation_spec.js
index 78c1b840dbc..94797f01d16 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/terraform_installation_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/terraform_installation_spec.js
@@ -30,10 +30,6 @@ describe('TerraformInstallation', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders all the messages', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
index bb970336b94..ea4d268d84e 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
@@ -1,6 +1,6 @@
import testAction from 'helpers/vuex_action_helper';
import Api from '~/api';
-import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/alert';
import { FETCH_PACKAGE_VERSIONS_ERROR } from '~/packages_and_registries/infrastructure_registry/details/constants';
import {
fetchPackageVersions,
@@ -15,7 +15,7 @@ import {
} from '~/packages_and_registries/shared/constants';
import { npmPackage as packageEntity } from '../../mock_data';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
jest.mock('~/api.js');
describe('Actions Package details store', () => {
@@ -53,7 +53,7 @@ describe('Actions Package details store', () => {
expect(Api.projectPackage).toHaveBeenCalledWith(packageEntity.project_id, packageEntity.id);
});
- it('should create flash on API error', async () => {
+ it('should create alert on API error', async () => {
Api.projectPackage = jest.fn().mockRejectedValue();
await testAction(
@@ -83,7 +83,7 @@ describe('Actions Package details store', () => {
packageEntity.id,
);
});
- it('should create flash on API error', async () => {
+ it('should create alert on API error', async () => {
Api.deleteProjectPackage = jest.fn().mockRejectedValue();
await testAction(deletePackage, undefined, { packageEntity }, [], []);
@@ -118,7 +118,7 @@ describe('Actions Package details store', () => {
});
});
- it('should create flash on API error', async () => {
+ it('should create alert on API error', async () => {
Api.deleteProjectPackageFile = jest.fn().mockRejectedValue();
await testAction(deletePackageFile, fileId, { packageEntity }, [], []);
expect(createAlert).toHaveBeenCalledWith({
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 801cde8582e..d0841c6110f 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
@@ -49,9 +49,7 @@ exports[`packages_list_app renders 1`] = `
Learn how to
<b-link-stub
class="gl-link"
- event="click"
href="helpUrl"
- routertag="a"
target="_blank"
>
publish and share your packages
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js
index a086c20a5e7..a89247c0a97 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_search_spec.js
@@ -55,11 +55,6 @@ describe('Infrastructure Search', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('has a registry search component', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_title_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_title_spec.js
index aca6b0942cc..7c7faa8a3b0 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_title_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/infrastructure_title_spec.js
@@ -22,11 +22,6 @@ describe('Infrastructure Title', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('title area', () => {
beforeEach(() => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js
index d237023d0cd..47d36d11e35 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js
@@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import setWindowLocation from 'helpers/set_window_location_helper';
-import { createAlert, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_INFO } from '~/alert';
import * as commonUtils from '~/lib/utils/common_utils';
import PackageListApp from '~/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue';
import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '~/packages_and_registries/infrastructure_registry/list/constants';
@@ -14,7 +14,7 @@ import InfrastructureSearch from '~/packages_and_registries/infrastructure_regis
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
jest.mock('~/lib/utils/common_utils');
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(Vuex);
@@ -72,10 +72,6 @@ describe('packages_list_app', () => {
mountComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders', () => {
createStore({ packageCount: 1 });
mountComponent();
@@ -217,7 +213,7 @@ describe('packages_list_app', () => {
setWindowLocation(originalLocation);
});
- it(`creates a flash if the query string contains ${SHOW_DELETE_SUCCESS_ALERT}`, () => {
+ it(`creates an alert if the query string contains ${SHOW_DELETE_SUCCESS_ALERT}`, () => {
mountComponent();
expect(createAlert).toHaveBeenCalledWith({
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js
index 0164d92ce34..51445942eaa 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js
@@ -4,13 +4,13 @@ import Vue from 'vue';
import { last } from 'lodash';
import Vuex from 'vuex';
import stubChildren from 'helpers/stub_children';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import PackagesList from '~/packages_and_registries/infrastructure_registry/list/components/packages_list.vue';
import PackagesListRow from '~/packages_and_registries/infrastructure_registry/shared/package_list_row.vue';
import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
import DeletePackageModal from '~/packages_and_registries/shared/components/delete_package_modal.vue';
import { TRACKING_ACTIONS } from '~/packages_and_registries/shared/constants';
import { TRACK_CATEGORY } from '~/packages_and_registries/infrastructure_registry/shared/constants';
-import Tracking from '~/tracking';
import { packageList } from '../../mock_data';
Vue.use(Vuex);
@@ -72,11 +72,6 @@ describe('packages_list', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when is loading', () => {
beforeEach(() => {
mountComponent({
@@ -179,23 +174,23 @@ describe('packages_list', () => {
});
describe('tracking', () => {
- let eventSpy;
+ let trackingSpy = null;
beforeEach(() => {
mountComponent();
- eventSpy = jest.spyOn(Tracking, 'event');
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ itemToBeDeleted: { package_type: 'conan' } });
- });
-
- it('deleteItemConfirmation calls event', () => {
- wrapper.vm.deleteItemConfirmation();
- expect(eventSpy).toHaveBeenCalledWith(
- TRACK_CATEGORY,
- TRACKING_ACTIONS.DELETE_PACKAGE,
- expect.any(Object),
- );
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('deleteItemConfirmation calls event', async () => {
+ await findPackageListDeleteModal().vm.$emit('ok');
+
+ expect(trackingSpy).toHaveBeenCalledWith(TRACK_CATEGORY, TRACKING_ACTIONS.DELETE_PACKAGE, {
+ category: TRACK_CATEGORY,
+ });
});
});
});
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
index 2c185e040f4..4f051264172 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
@@ -2,14 +2,14 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { MISSING_DELETE_PATH_ERROR } from '~/packages_and_registries/infrastructure_registry/list/constants';
import * as actions from '~/packages_and_registries/infrastructure_registry/list/stores/actions';
import * as types from '~/packages_and_registries/infrastructure_registry/list/stores/mutation_types';
import { DELETE_PACKAGE_ERROR_MESSAGE } from '~/packages_and_registries/shared/constants';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
jest.mock('~/api.js');
describe('Actions Package list store', () => {
@@ -96,7 +96,7 @@ describe('Actions Package list store', () => {
});
});
- it('should create flash on API error', async () => {
+ it('should create alert on API error', async () => {
Api.projectPackages = jest.fn().mockRejectedValue();
await testAction(
actions.requestPackagesList,
@@ -198,7 +198,7 @@ describe('Actions Package list store', () => {
);
});
- it('should stop the loading and call create flash on api error', async () => {
+ it('should stop the loading and call create alert on api error', async () => {
mock.onDelete(payload._links.delete_api_path).replyOnce(HTTP_STATUS_BAD_REQUEST);
await testAction(
actions.requestDeletePackage,
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js
index 721bdd34a4f..37ca420ae77 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js
@@ -49,16 +49,11 @@ describe('packages_list_row', () => {
disableDelete,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders', () => {
mountComponent();
expect(wrapper.element).toMatchSnapshot();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js b/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
index 9c1ebf5a2eb..d0817a8678e 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
@@ -45,7 +45,7 @@ describe('DeleteModal', () => {
it('passes actionPrimary prop', () => {
expect(findModal().props('actionPrimary')).toStrictEqual({
text: 'Permanently delete',
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ attributes: { variant: 'danger', category: 'primary' },
});
});
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 67f1906f6fd..9b429c39faa 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
@@ -89,8 +89,9 @@ exports[`MavenInstallation maven renders all the messages 1`] = `
/>
<code-instruction-stub
+ class="gl-w-20 gl-mt-5"
copytext="Copy Maven command"
- instruction="mvn dependency:get -Dartifact=appGroup:appName:appVersion"
+ instruction="mvn install"
label="Maven Command"
trackingaction="copy_maven_command"
trackinglabel="code_instruction"
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 b2375da7b11..5d390730ef1 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
@@ -20,7 +20,7 @@ exports[`PypiInstallation renders all the messages 1`] = `
<!---->
<button
aria-expanded="false"
- aria-haspopup="true"
+ aria-haspopup="menu"
class="btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle"
id="__BVID__27__BV_toggle_"
type="button"
@@ -59,7 +59,6 @@ exports[`PypiInstallation renders all the messages 1`] = `
</div>
<fieldset
- aria-describedby="installation-pip-command-group__BV_description_"
class="form-group gl-form-group"
id="installation-pip-command-group"
>
@@ -75,12 +74,7 @@ exports[`PypiInstallation renders all the messages 1`] = `
<!---->
</legend>
- <div
- aria-labelledby="installation-pip-command-group__BV_label_"
- class="bv-no-focus-ring"
- role="group"
- tabindex="-1"
- >
+ <div>
<div
data-testid="pip-command"
id="installation-pip-command"
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js
index 4f3d780b149..2e59c27cc1b 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js
@@ -65,11 +65,6 @@ describe('Package Additional metadata', () => {
jest.spyOn(Sentry, 'captureException').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findTitle = () => wrapper.findByTestId('title');
const findMainArea = () => wrapper.findByTestId('main');
const findComponentIs = () => wrapper.findByTestId('component-is');
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/composer_installation_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/composer_installation_spec.js
index 0aba8f7efc7..a6298ebdea7 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/composer_installation_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/composer_installation_spec.js
@@ -34,10 +34,6 @@ describe('ComposerInstallation', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('install command switch', () => {
it('has the installation title component', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/conan_installation_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/conan_installation_spec.js
index bf9425def9a..70534b1d0a6 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/conan_installation_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/conan_installation_spec.js
@@ -33,10 +33,6 @@ describe('ConanInstallation', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders all the messages', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/dependency_row_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/dependency_row_spec.js
index 9aed5b90c73..19aedf120b2 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/dependency_row_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/dependency_row_spec.js
@@ -19,10 +19,6 @@ describe('DependencyRow', () => {
const dependencyVersion = () => wrapper.findByTestId('version-pattern');
const dependencyFramework = () => wrapper.findByTestId('target-framework');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('renders', () => {
it('full dependency', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/file_sha_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/file_sha_spec.js
index feed7a7c46c..a9428773a60 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/file_sha_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/file_sha_spec.js
@@ -23,10 +23,6 @@ describe('FileSha', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/installation_title_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/installation_title_spec.js
index 5fe795f768e..a2d30be13c2 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/installation_title_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/installation_title_spec.js
@@ -20,10 +20,6 @@ describe('InstallationTitle', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has a title', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/installations_commands_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/installations_commands_spec.js
index 8bb05b00e65..d35d95e319f 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/installations_commands_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/installations_commands_spec.js
@@ -40,10 +40,6 @@ describe('InstallationCommands', () => {
const pypiInstallation = () => wrapper.findComponent(PypiInstallation);
const composerInstallation = () => wrapper.findComponent(ComposerInstallation);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('installation instructions', () => {
describe.each`
packageEntity | selector
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/maven_installation_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/maven_installation_spec.js
index fc60039db30..5ea81dccf7d 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/maven_installation_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/maven_installation_spec.js
@@ -35,7 +35,7 @@ describe('MavenInstallation', () => {
<artifactId>appName</artifactId>
<version>appVersion</version>
</dependency>`;
- const mavenCommandStr = 'mvn dependency:get -Dartifact=appGroup:appName:appVersion';
+ const mavenCommandStr = 'mvn install';
const mavenSetupXml = `<repositories>
<repository>
<id>gitlab-maven</id>
@@ -79,10 +79,6 @@ describe('MavenInstallation', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('install command switch', () => {
it('has the installation title component', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js
index bb6846d354f..f2f3b8507c3 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/composer_spec.js
@@ -18,11 +18,6 @@ describe('Composer Metadata', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findComposerTargetSha = () => wrapper.findByTestId('composer-target-sha');
const findComposerTargetShaCopyButton = () => wrapper.findComponent(ClipboardButton);
const findComposerJson = () => wrapper.findByTestId('composer-json');
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js
index e7e47401aa1..2832dc3a712 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/conan_spec.js
@@ -19,11 +19,6 @@ describe('Conan Metadata', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findConanRecipe = () => wrapper.findByTestId('conan-recipe');
beforeEach(() => {
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js
index 8680d983042..7b253a26fc7 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/maven_spec.js
@@ -19,11 +19,6 @@ describe('Maven Metadata', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findMavenApp = () => wrapper.findByTestId('maven-app');
const findMavenGroup = () => wrapper.findByTestId('maven-group');
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js
index af3692023f0..9fb467f9af1 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/nuget_spec.js
@@ -19,11 +19,6 @@ describe('Nuget Metadata', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findNugetSource = () => wrapper.findByTestId('nuget-source');
const findNugetLicense = () => wrapper.findByTestId('nuget-license');
const findElementLink = (container) => container.findComponent(GlLink);
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js
index d7c6ea8379d..67f5fbc9e80 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/metadata/pypi_spec.js
@@ -20,11 +20,6 @@ describe('Package Additional Metadata', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findPypiRequiredPython = () => wrapper.findByTestId('pypi-required-python');
beforeEach(() => {
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/npm_installation_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/npm_installation_spec.js
index 8c0e2d948ca..e711f9ee45d 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/npm_installation_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/npm_installation_spec.js
@@ -51,10 +51,6 @@ describe('NpmInstallation', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders all the messages', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/nuget_installation_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/nuget_installation_spec.js
index 9449c40c7c6..bcc0b78bfce 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/nuget_installation_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/nuget_installation_spec.js
@@ -36,10 +36,6 @@ describe('NugetInstallation', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders all the messages', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js
index 529a6a22ddf..1dcac017ccf 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_files_spec.js
@@ -48,10 +48,6 @@ describe('Package Files', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rows', () => {
it('renders a single file for an npm package', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js
index bb2fa9eb6f5..ed470f63b8a 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_history_spec.js
@@ -63,11 +63,6 @@ describe('Package History', () => {
jest.spyOn(Sentry, 'captureException').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findPackageHistoryLoader = () => wrapper.findComponent(PackageHistoryLoader);
const findHistoryElement = (testId) => wrapper.findByTestId(testId);
const findElementLink = (container) => container.findComponent(GlLink);
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js
index 1fda77f2aaa..ba21cdaca3b 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js
@@ -38,7 +38,7 @@ describe('PackageTitle', () => {
},
provide,
directives: {
- GlResizeObserver: createMockDirective(),
+ GlResizeObserver: createMockDirective('gl-resize-observer'),
},
});
await nextTick();
@@ -55,10 +55,6 @@ describe('PackageTitle', () => {
const findSubHeaderText = () => wrapper.findByTestId('sub-header');
const findSubHeaderTimeAgo = () => wrapper.findComponent(TimeAgoTooltip);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('renders', () => {
it('without tags', async () => {
await createComponent({ ...packageData(), packageFiles: { nodes: packageFiles() } });
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/package_versions_list_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/package_versions_list_spec.js
index 27c0ab96cfc..fc7f5c80d45 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/package_versions_list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_versions_list_spec.js
@@ -1,14 +1,18 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent } from 'helpers/stub_component';
import DeleteModal from '~/packages_and_registries/package_registry/components/delete_modal.vue';
+import DeletePackageModal from '~/packages_and_registries/shared/components/delete_package_modal.vue';
import PackageVersionsList from '~/packages_and_registries/package_registry/components/details/package_versions_list.vue';
import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
import Tracking from '~/tracking';
import {
+ CANCEL_DELETE_PACKAGE_VERSION_TRACKING_ACTION,
CANCEL_DELETE_PACKAGE_VERSIONS_TRACKING_ACTION,
+ DELETE_PACKAGE_VERSION_TRACKING_ACTION,
DELETE_PACKAGE_VERSIONS_TRACKING_ACTION,
+ REQUEST_DELETE_PACKAGE_VERSION_TRACKING_ACTION,
REQUEST_DELETE_PACKAGE_VERSIONS_TRACKING_ACTION,
} from '~/packages_and_registries/package_registry/constants';
import { packageData } from '../../mock_data';
@@ -22,7 +26,7 @@ describe('PackageVersionsList', () => {
name: 'version 1',
}),
packageData({
- id: `gid://gitlab/Packages::Package/112`,
+ id: 'gid://gitlab/Packages::Package/112',
name: 'version 2',
}),
];
@@ -31,8 +35,10 @@ describe('PackageVersionsList', () => {
findLoader: () => wrapper.findComponent(PackagesListLoader),
findRegistryList: () => wrapper.findComponent(RegistryList),
findEmptySlot: () => wrapper.findComponent(EmptySlotStub),
- findListRow: () => wrapper.findAllComponents(VersionRow),
+ findListRow: () => wrapper.findComponent(VersionRow),
+ findAllListRow: () => wrapper.findAllComponents(VersionRow),
findDeletePackagesModal: () => wrapper.findComponent(DeleteModal),
+ findPackageListDeleteModal: () => wrapper.findComponent(DeletePackageModal),
};
const mountComponent = (props) => {
wrapper = shallowMountExtended(PackageVersionsList, {
@@ -118,16 +124,16 @@ describe('PackageVersionsList', () => {
});
it('displays package version rows', () => {
- expect(uiElements.findListRow().exists()).toEqual(true);
- expect(uiElements.findListRow()).toHaveLength(packageList.length);
+ expect(uiElements.findAllListRow().exists()).toEqual(true);
+ expect(uiElements.findAllListRow()).toHaveLength(packageList.length);
});
it('binds the correct props', () => {
- expect(uiElements.findListRow().at(0).props()).toMatchObject({
+ expect(uiElements.findAllListRow().at(0).props()).toMatchObject({
packageEntity: expect.objectContaining(packageList[0]),
});
- expect(uiElements.findListRow().at(1).props()).toMatchObject({
+ expect(uiElements.findAllListRow().at(1).props()).toMatchObject({
packageEntity: expect.objectContaining(packageList[1]),
});
});
@@ -159,6 +165,68 @@ describe('PackageVersionsList', () => {
});
});
+ describe.each`
+ description | finderFunction | deletePayload
+ ${'when the user can destroy the package'} | ${uiElements.findListRow} | ${packageList[0]}
+ ${'when the user can bulk destroy packages and deletes only one package'} | ${uiElements.findRegistryList} | ${[packageList[0]]}
+ `('$description', ({ finderFunction, deletePayload }) => {
+ let eventSpy;
+ const category = 'UI::NpmPackages';
+ const { findPackageListDeleteModal } = uiElements;
+
+ beforeEach(() => {
+ eventSpy = jest.spyOn(Tracking, 'event');
+ mountComponent({ canDestroy: true });
+ finderFunction().vm.$emit('delete', deletePayload);
+ });
+
+ it('passes itemToBeDeleted to the modal', () => {
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toStrictEqual(packageList[0]);
+ });
+
+ it('requesting delete tracks the right action', () => {
+ expect(eventSpy).toHaveBeenCalledWith(
+ category,
+ REQUEST_DELETE_PACKAGE_VERSION_TRACKING_ACTION,
+ expect.any(Object),
+ );
+ });
+
+ describe('when modal confirms', () => {
+ beforeEach(() => {
+ findPackageListDeleteModal().vm.$emit('ok');
+ });
+
+ it('emits delete when modal confirms', () => {
+ expect(wrapper.emitted('delete')[0][0]).toEqual([packageList[0]]);
+ });
+
+ it('tracks the right action', () => {
+ expect(eventSpy).toHaveBeenCalledWith(
+ category,
+ DELETE_PACKAGE_VERSION_TRACKING_ACTION,
+ expect.any(Object),
+ );
+ });
+ });
+
+ it.each(['ok', 'cancel'])('resets itemToBeDeleted when modal emits %s', async (event) => {
+ await findPackageListDeleteModal().vm.$emit(event);
+
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toBeNull();
+ });
+
+ it('canceling delete tracks the right action', () => {
+ findPackageListDeleteModal().vm.$emit('cancel');
+
+ expect(eventSpy).toHaveBeenCalledWith(
+ category,
+ CANCEL_DELETE_PACKAGE_VERSION_TRACKING_ACTION,
+ expect.any(Object),
+ );
+ });
+ });
+
describe('when the user can bulk destroy versions', () => {
let eventSpy;
const { findDeletePackagesModal, findRegistryList } = uiElements;
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/pypi_installation_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/pypi_installation_spec.js
index 4a27f8011df..3f4358bb3b0 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/pypi_installation_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/pypi_installation_spec.js
@@ -29,10 +29,13 @@ password = <your personal access token>`;
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
const findSetupDocsLink = () => wrapper.findByTestId('pypi-docs-link');
- function createComponent() {
+ function createComponent(props = {}) {
wrapper = mountExtended(PypiInstallation, {
propsData: {
- packageEntity,
+ packageEntity: {
+ ...packageEntity,
+ ...props,
+ },
},
stubs: {
GlSprintf,
@@ -44,10 +47,6 @@ password = <your personal access token>`;
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('install command switch', () => {
it('has the installation title component', () => {
expect(findInstallationTitle().exists()).toBe(true);
@@ -86,6 +85,12 @@ password = <your personal access token>`;
});
});
+ it('does not have a link to personal access token docs when package is public', () => {
+ createComponent({ publicPackage: true });
+
+ expect(findAccessTokenLink().exists()).toBe(false);
+ });
+
it('has a link to the docs', () => {
expect(findSetupDocsLink().attributes()).toMatchObject({
href: PYPI_HELP_PATH,
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js
index 67340822fa5..f7c8e909ff6 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js
@@ -1,4 +1,4 @@
-import { GlFormCheckbox, GlIcon, GlLink, GlSprintf, GlTruncate } from '@gitlab/ui';
+import { GlDropdownItem, GlFormCheckbox, GlIcon, GlLink, GlSprintf, GlTruncate } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
@@ -24,6 +24,7 @@ describe('VersionRow', () => {
const findPackageName = () => wrapper.findComponent(GlTruncate);
const findWarningIcon = () => wrapper.findComponent(GlIcon);
const findBulkDeleteAction = () => wrapper.findComponent(GlFormCheckbox);
+ const findDeleteDropdownItem = () => wrapper.findComponent(GlDropdownItem);
function createComponent({ packageEntity = packageVersion, selected = false } = {}) {
wrapper = shallowMountExtended(VersionRow, {
@@ -36,15 +37,11 @@ describe('VersionRow', () => {
GlTruncate,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has a link to the version detail', () => {
createComponent();
@@ -112,6 +109,31 @@ describe('VersionRow', () => {
});
});
+ describe('delete button', () => {
+ it('does not exist when package cannot be destroyed', () => {
+ createComponent({ packageEntity: { ...packageVersion, canDestroy: false } });
+
+ expect(findDeleteDropdownItem().exists()).toBe(false);
+ });
+
+ it('exists and has the correct props', () => {
+ createComponent();
+
+ expect(findDeleteDropdownItem().exists()).toBe(true);
+ expect(findDeleteDropdownItem().attributes()).toMatchObject({
+ variant: 'danger',
+ });
+ });
+
+ it('emits the delete event when the delete button is clicked', () => {
+ createComponent();
+
+ findDeleteDropdownItem().vm.$emit('click');
+
+ expect(wrapper.emitted('delete')).toHaveLength(1);
+ });
+ });
+
describe(`when the package is in ${PACKAGE_ERROR_STATUS} status`, () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/packages_and_registries/package_registry/components/functional/delete_packages_spec.js b/spec/frontend/packages_and_registries/package_registry/components/functional/delete_packages_spec.js
index 689b53fa2a4..04546c4cea4 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/functional/delete_packages_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/functional/delete_packages_spec.js
@@ -3,7 +3,7 @@ import VueApollo from 'vue-apollo';
import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
-import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/alert';
import DeletePackages from '~/packages_and_registries/package_registry/components/functional/delete_packages.vue';
import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
@@ -14,7 +14,7 @@ import {
packagesListQuery,
} from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('DeletePackages', () => {
let wrapper;
@@ -67,10 +67,6 @@ describe('DeletePackages', () => {
mutationResolver = jest.fn().mockResolvedValue(packagesDestroyMutation());
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('binds deletePackages method to the default slot', () => {
createComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js
index 2a78cfb13f9..91417d2fc9f 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js
@@ -1,5 +1,5 @@
import { GlFormCheckbox, GlSprintf, GlTruncate } from '@gitlab/ui';
-import Vue, { nextTick } from 'vue';
+import Vue from 'vue';
import VueRouter from 'vue-router';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
@@ -67,15 +67,11 @@ describe('packages_list_row', () => {
selected,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders', () => {
mountComponent();
expect(wrapper.element).toMatchSnapshot();
@@ -141,7 +137,6 @@ describe('packages_list_row', () => {
findDeleteDropdown().vm.$emit('click');
- await nextTick();
expect(wrapper.emitted('delete')).toHaveLength(1);
});
});
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 610640e0ca3..ae990f3ea00 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
@@ -73,10 +73,6 @@ describe('packages_list', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when is loading', () => {
beforeEach(() => {
mountComponent({ isLoading: true });
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 a884959ab62..1250ecaf61f 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
@@ -46,10 +46,6 @@ describe('Package Search', () => {
extractFilterAndSorting.mockReturnValue(defaultQueryParamsMock);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has a registry search component', async () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js
index b47515e15c3..1296458155a 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_title_spec.js
@@ -20,11 +20,6 @@ describe('PackageTitle', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('title area', () => {
it('exists', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/publish_method_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/publish_method_spec.js
index fcbd7cc6a50..e9119b736c2 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/publish_method_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/publish_method_spec.js
@@ -19,10 +19,6 @@ describe('publish_method', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders', () => {
mountComponent();
expect(wrapper.element).toMatchSnapshot();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js
index 8f3c8667c47..c98f5f32344 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js
@@ -19,11 +19,6 @@ describe('packages_filter', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('binds all of his attrs to filtered search token', () => {
mountComponent({ attrs: { foo: 'bar' } });
diff --git a/spec/frontend/packages_and_registries/package_registry/mock_data.js b/spec/frontend/packages_and_registries/package_registry/mock_data.js
index d897be1f344..19c098e1f82 100644
--- a/spec/frontend/packages_and_registries/package_registry/mock_data.js
+++ b/spec/frontend/packages_and_registries/package_registry/mock_data.js
@@ -147,6 +147,7 @@ export const packageData = (extend) => ({
conanUrl: 'http://gdk.test:3000/api/v4/projects/1/packages/conan',
pypiUrl:
'http://__token__:<your_personal_token>@gdk.test:3000/api/v4/projects/1/packages/pypi/simple',
+ publicPackage: false,
pypiSetupUrl: 'http://gdk.test:3000/api/v4/projects/1/packages/pypi',
...extend,
});
diff --git a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js
index b494965a3cb..49f69a46395 100644
--- a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js
@@ -6,7 +6,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue';
import PackagesApp from '~/packages_and_registries/package_registry/pages/details.vue';
@@ -45,7 +45,7 @@ import {
pagination,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
useMockLocationHelper();
describe('PackagesApp', () => {
@@ -131,10 +131,6 @@ describe('PackagesApp', () => {
const findDeletePackageModal = () => wrapper.findAllComponents(DeletePackages).at(1);
const findDeletePackages = () => wrapper.findComponent(DeletePackages);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders an empty state component', async () => {
createComponent({ resolver: jest.fn().mockResolvedValue(emptyPackageDetailsQuery) });
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 a2ec527ce12..60bb055b1db 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
@@ -4,14 +4,13 @@ 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 { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import ListPage from '~/packages_and_registries/package_registry/pages/list.vue';
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 OriginalPackageList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
import DeletePackages from '~/packages_and_registries/package_registry/components/functional/delete_packages.vue';
import {
- PROJECT_RESOURCE_TYPE,
- GROUP_RESOURCE_TYPE,
GRAPHQL_PAGE_SIZE,
EMPTY_LIST_HELP_URL,
PACKAGE_HELP_URL,
@@ -21,7 +20,7 @@ import getPackagesQuery from '~/packages_and_registries/package_registry/graphql
import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
import { packagesListQuery, packageData, pagination } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('PackagesListApp', () => {
let wrapper;
@@ -78,10 +77,6 @@ describe('PackagesListApp', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const waitForFirstRequest = async () => {
// emit a search update so the query is executed
findSearch().vm.$emit('update', { sort: 'NAME_DESC', filters: [] });
@@ -171,14 +166,14 @@ describe('PackagesListApp', () => {
});
describe.each`
- type | sortType
- ${PROJECT_RESOURCE_TYPE} | ${'sort'}
- ${GROUP_RESOURCE_TYPE} | ${'groupSort'}
+ type | sortType
+ ${WORKSPACE_PROJECT} | ${'sort'}
+ ${WORKSPACE_GROUP} | ${'groupSort'}
`('$type query', ({ type, sortType }) => {
let provide;
let resolver;
- const isGroupPage = type === GROUP_RESOURCE_TYPE;
+ const isGroupPage = type === WORKSPACE_GROUP;
beforeEach(() => {
provide = { ...defaultProvide, isGroupPage };
@@ -198,9 +193,13 @@ describe('PackagesListApp', () => {
});
});
- describe('empty state', () => {
+ describe.each`
+ description | resolverResponse
+ ${'empty response'} | ${packagesListQuery({ extend: { nodes: [] } })}
+ ${'error response'} | ${{ data: { group: null } }}
+ `(`$description renders empty state`, ({ resolverResponse }) => {
beforeEach(() => {
- const resolver = jest.fn().mockResolvedValue(packagesListQuery({ extend: { nodes: [] } }));
+ const resolver = jest.fn().mockResolvedValue(resolverResponse);
mountComponent({ resolver });
return waitForFirstRequest();
diff --git a/spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js b/spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js
index 796d89231f4..6dd4b9f2d20 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/dependency_proxy_settings_spec.js
@@ -28,7 +28,7 @@ import {
dependencyProxyUpdateTllPolicyMutationMock,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/packages_and_registries/settings/group/graphql/utils/optimistic_responses');
describe('DependencyProxySettings', () => {
@@ -82,10 +82,6 @@ describe('DependencyProxySettings', () => {
.mockResolvedValue(dependencyProxyUpdateTllPolicyMutationMock());
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
const findEnableProxyToggle = () => wrapper.findByTestId('dependency-proxy-setting-toggle');
const findEnableTtlPoliciesToggle = () =>
diff --git a/spec/frontend/packages_and_registries/settings/group/components/exceptions_input_spec.js b/spec/frontend/packages_and_registries/settings/group/components/exceptions_input_spec.js
index 86f14961690..461200e6983 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/exceptions_input_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/exceptions_input_spec.js
@@ -23,10 +23,6 @@ describe('Exceptions Input', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findInputGroup = () => wrapper.findComponent(GlFormGroup);
const findInput = () => wrapper.findComponent(GlFormInput);
diff --git a/spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js b/spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js
index 7edc321867c..3ce8e91d43d 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js
@@ -19,7 +19,7 @@ import {
dependencyProxyImageTtlPolicy,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Group Settings App', () => {
let wrapper;
@@ -55,10 +55,6 @@ describe('Group Settings App', () => {
show = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findAlert = () => wrapper.findComponent(GlAlert);
const findPackageSettings = () => wrapper.findComponent(PackagesSettings);
const findPackageForwardingSettings = () => wrapper.findComponent(PackagesForwardingSettings);
diff --git a/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js b/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js
index 807f332f4d3..22e42f8c0ab 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js
@@ -23,7 +23,7 @@ import {
groupPackageSettingsMutationErrorMock,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/packages_and_registries/settings/group/graphql/utils/optimistic_responses');
describe('Packages Settings', () => {
@@ -56,10 +56,6 @@ describe('Packages Settings', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
const findDescription = () => wrapper.findByTestId('description');
const findMavenSettings = () => wrapper.findByTestId('maven-settings');
diff --git a/spec/frontend/packages_and_registries/settings/group/components/packages_forwarding_settings_spec.js b/spec/frontend/packages_and_registries/settings/group/components/packages_forwarding_settings_spec.js
index a0b257a9496..d57077b31c8 100644
--- a/spec/frontend/packages_and_registries/settings/group/components/packages_forwarding_settings_spec.js
+++ b/spec/frontend/packages_and_registries/settings/group/components/packages_forwarding_settings_spec.js
@@ -25,7 +25,7 @@ import {
mavenProps,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/packages_and_registries/settings/group/graphql/utils/optimistic_responses');
describe('Packages Forwarding Settings', () => {
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/cleanup_image_tags_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/cleanup_image_tags_spec.js
index 2bb99fb8e8f..49e8601da88 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/cleanup_image_tags_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/cleanup_image_tags_spec.js
@@ -61,10 +61,6 @@ describe('Cleanup image tags project settings', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('isEdited status', () => {
it.each`
description | apiResponse | workingCopy | result
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_form_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_form_spec.js
index cbb5aa52694..57b48407174 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_form_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_form_spec.js
@@ -124,10 +124,6 @@ describe('Container Expiration Policy Settings Form', () => {
jest.spyOn(Tracking, 'event');
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
model | finder | fieldName | type | defaultValue
${'enabled'} | ${findEnableToggle} | ${'Enable'} | ${'toggle'} | ${false}
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js
index 43484d26d76..19f25d0aef7 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/container_expiration_policy_spec.js
@@ -63,10 +63,6 @@ describe('Container expiration policy project settings', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the setting form', async () => {
mountComponentWithApollo({
resolver: jest.fn().mockResolvedValue(expirationPolicyPayload()),
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js
index ae41fdf65e0..058fe427106 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js
@@ -32,11 +32,6 @@ describe('ExpirationDropdown', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('structure', () => {
it('has a form-select component', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js
index 1cea0704154..be12d108d1e 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js
@@ -38,11 +38,6 @@ describe('ExpirationInput', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('structure', () => {
it('has a label', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js
index 653f2a8b40e..f950a9d5add 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js
@@ -23,11 +23,6 @@ describe('ExpirationToggle', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('structure', () => {
it('has an input component', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js
index 55a66cebd83..ec7b89aa927 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js
@@ -23,11 +23,6 @@ describe('ExpirationToggle', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('structure', () => {
it('has a toggle component', () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js
index 0fbbf4ae58f..b9c0c38bf9e 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_form_spec.js
@@ -115,7 +115,6 @@ describe('Packages Cleanup Policy Settings Form', () => {
});
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js
index 6dfeeca6862..94277d34f30 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/packages_cleanup_policy_spec.js
@@ -47,7 +47,6 @@ describe('Packages cleanup policy project settings', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
index 07d13839c61..54655acdf2a 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/registry_settings_app_spec.js
@@ -20,11 +20,6 @@ describe('Registry Settings app', () => {
const findPackagesCleanupPolicy = () => wrapper.findComponent(PackagesCleanupPolicy);
const findAlert = () => wrapper.findComponent(GlAlert);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const defaultProvide = {
showContainerRegistrySettings: true,
showPackageRegistrySettings: true,
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 18084766db9..41482e6e681 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
@@ -38,11 +38,6 @@ describe('cli_commands', () => {
mountComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('shows the correct text on the button', () => {
expect(findDropdownButton().text()).toContain(QUICK_START);
});
diff --git a/spec/frontend/packages_and_registries/shared/components/delete_package_modal_spec.js b/spec/frontend/packages_and_registries/shared/components/delete_package_modal_spec.js
index 357dab593e8..ba5ba8f9884 100644
--- a/spec/frontend/packages_and_registries/shared/components/delete_package_modal_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/delete_package_modal_spec.js
@@ -19,11 +19,6 @@ describe('DeletePackageModal', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when itemToBeDeleted prop is defined', () => {
beforeEach(() => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/shared/components/package_path_spec.js b/spec/frontend/packages_and_registries/shared/components/package_path_spec.js
index 93425d4f399..2490e9a1f6a 100644
--- a/spec/frontend/packages_and_registries/shared/components/package_path_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/package_path_spec.js
@@ -9,7 +9,7 @@ describe('PackagePath', () => {
wrapper = shallowMount(PackagePath, {
propsData,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -24,11 +24,6 @@ describe('PackagePath', () => {
const findItem = (name) => wrapper.find(`[data-testid="${name}"]`);
const findTooltip = (w) => getBinding(w.element, 'gl-tooltip');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe.each`
path | rootUrl | shouldExist | shouldNotExist
${'foo/bar'} | ${'/foo/bar'} | ${[]} | ${[ROOT_CHEVRON, ELLIPSIS_ICON, ELLIPSIS_CHEVRON, LEAF_LINK]}
diff --git a/spec/frontend/packages_and_registries/shared/components/packages_list_loader_spec.js b/spec/frontend/packages_and_registries/shared/components/packages_list_loader_spec.js
index 0005162e0bb..e43a9f57255 100644
--- a/spec/frontend/packages_and_registries/shared/components/packages_list_loader_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/packages_list_loader_spec.js
@@ -17,11 +17,6 @@ describe('PackagesListLoader', () => {
beforeEach(createComponent);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('desktop loader', () => {
it('produces the right loader', () => {
expect(findDesktopShapes().findAll('rect[width="1000"]')).toHaveLength(20);
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 db9f96bff39..1484377a475 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
@@ -43,10 +43,6 @@ describe('Persisted Search', () => {
extractFilterAndSorting.mockReturnValue(defaultQueryParamsMock);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has a registry search component', async () => {
mountComponent();
diff --git a/spec/frontend/packages_and_registries/shared/components/publish_method_spec.js b/spec/frontend/packages_and_registries/shared/components/publish_method_spec.js
index fa8f8f7641a..167599a54ea 100644
--- a/spec/frontend/packages_and_registries/shared/components/publish_method_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/publish_method_spec.js
@@ -20,11 +20,6 @@ describe('publish_method', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders', () => {
mountComponent(packageWithPipeline);
expect(wrapper.element).toMatchSnapshot();
diff --git a/spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js b/spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js
index 15db454ac68..c1f1a25d53b 100644
--- a/spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/registry_breadcrumb_spec.js
@@ -31,10 +31,6 @@ describe('Registry Breadcrumb', () => {
nameGenerator.mockClear();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when is rootRoute', () => {
beforeEach(() => {
mountComponent(routes[0]);
diff --git a/spec/frontend/packages_and_registries/shared/components/registry_list_spec.js b/spec/frontend/packages_and_registries/shared/components/registry_list_spec.js
index 2e2d5e26d33..a4e0d267023 100644
--- a/spec/frontend/packages_and_registries/shared/components/registry_list_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/registry_list_spec.js
@@ -36,10 +36,6 @@ describe('Registry List', () => {
const findScopedSlotFirstValue = (index) => findScopedSlots().at(index).find('span');
const findScopedSlotIsSelectedValue = (index) => findScopedSlots().at(index).find('p');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('header', () => {
it('renders the title passed in the prop', () => {
mountComponent();
@@ -111,10 +107,21 @@ describe('Registry List', () => {
expect(findDeleteSelected().text()).toBe(component.i18n.deleteSelected);
});
- it('is hidden when hiddenDelete is true', () => {
- mountComponent({ propsData: { ...defaultPropsData, hiddenDelete: true } });
+ describe('when hiddenDelete is true', () => {
+ beforeEach(() => {
+ mountComponent({ propsData: { ...defaultPropsData, hiddenDelete: true } });
+ });
- expect(findDeleteSelected().exists()).toBe(false);
+ it('is hidden', () => {
+ expect(findDeleteSelected().exists()).toBe(false);
+ });
+
+ it('populates the first slot prop correctly', async () => {
+ expect(findScopedSlots().at(0).exists()).toBe(true);
+
+ // it's the first slot
+ expect(findScopedSlotFirstValue(0).text()).toBe('false');
+ });
});
it('is disabled when isLoading is true', () => {
diff --git a/spec/frontend/packages_and_registries/shared/components/settings_block_spec.js b/spec/frontend/packages_and_registries/shared/components/settings_block_spec.js
index a4c1b989dac..664a821c275 100644
--- a/spec/frontend/packages_and_registries/shared/components/settings_block_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/settings_block_spec.js
@@ -15,10 +15,6 @@ describe('SettingsBlock', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDefaultSlot = () => wrapper.findByTestId('default-slot');
const findTitleSlot = () => wrapper.findByTestId('title-slot');
const findDescriptionSlot = () => wrapper.findByTestId('description-slot');
diff --git a/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js b/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js
index ec6369e7119..de6d44eabdc 100644
--- a/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js
+++ b/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js
@@ -19,8 +19,8 @@ describe('CancelJobs component', () => {
const createComponent = (props = {}) => {
wrapper = shallowMountExtended(CancelJobs, {
directives: {
- GlModal: createMockDirective(),
- GlTooltip: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: {
url: `${TEST_HOST}/cancel_jobs_modal.vue/cancelAll`,
diff --git a/spec/frontend/pages/groups/new/components/app_spec.js b/spec/frontend/pages/groups/new/components/app_spec.js
index ab483316086..7ccded9b0f1 100644
--- a/spec/frontend/pages/groups/new/components/app_spec.js
+++ b/spec/frontend/pages/groups/new/components/app_spec.js
@@ -6,7 +6,7 @@ describe('App component', () => {
let wrapper;
const createComponent = (propsData = {}) => {
- wrapper = shallowMount(App, { propsData });
+ wrapper = shallowMount(App, { propsData: { groupsUrl: '/dashboard/groups', ...propsData } });
};
const findNewNamespacePage = () => wrapper.findComponent(NewNamespacePage);
@@ -16,24 +16,31 @@ describe('App component', () => {
.props('panels')
.find((panel) => panel.name === 'create-group-pane');
- afterEach(() => {
- wrapper.destroy();
- });
-
it('creates correct component for group creation', () => {
createComponent();
- expect(findNewNamespacePage().props('initialBreadcrumb')).toBe('New group');
+ expect(findNewNamespacePage().props('initialBreadcrumbs')).toEqual([
+ { href: '/dashboard/groups', text: 'Groups' },
+ { href: '#', text: 'New group' },
+ ]);
expect(findCreateGroupPanel().title).toBe('Create group');
});
it('creates correct component for subgroup creation', () => {
- const props = { parentGroupName: 'parent', importExistingGroupPath: '/path' };
+ const detailProps = {
+ parentGroupName: 'parent',
+ importExistingGroupPath: '/path',
+ };
+
+ const props = { ...detailProps, parentGroupUrl: '/parent' };
createComponent(props);
- expect(findNewNamespacePage().props('initialBreadcrumb')).toBe('parent');
+ expect(findNewNamespacePage().props('initialBreadcrumbs')).toEqual([
+ { href: '/parent', text: 'parent' },
+ { href: '#', text: 'New subgroup' },
+ ]);
expect(findCreateGroupPanel().title).toBe('Create subgroup');
- expect(findCreateGroupPanel().detailProps).toEqual(props);
+ expect(findCreateGroupPanel().detailProps).toEqual(detailProps);
});
});
diff --git a/spec/frontend/pages/groups/new/components/create_group_description_details_spec.js b/spec/frontend/pages/groups/new/components/create_group_description_details_spec.js
index 56a1fd03f71..35015d84085 100644
--- a/spec/frontend/pages/groups/new/components/create_group_description_details_spec.js
+++ b/spec/frontend/pages/groups/new/components/create_group_description_details_spec.js
@@ -15,10 +15,6 @@ describe('CreateGroupDescriptionDetails component', () => {
const findLinkHref = (at) => wrapper.findAllComponents(GlLink).at(at);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('creates correct component for group creation', () => {
createComponent();
diff --git a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
index da3954b4918..477511cde64 100644
--- a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
+++ b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
@@ -68,15 +68,10 @@ describe('BulkImportsHistoryApp', () => {
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
- const originalApiVersion = gon.api_version;
- beforeAll(() => {
+ beforeEach(() => {
gon.api_version = 'v4';
});
- afterAll(() => {
- gon.api_version = originalApiVersion;
- });
-
beforeEach(() => {
mock = new MockAdapter(axios);
mock.onGet(API_URL).reply(HTTP_STATUS_OK, DUMMY_RESPONSE, DEFAULT_HEADERS);
@@ -84,7 +79,6 @@ describe('BulkImportsHistoryApp', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('general behavior', () => {
diff --git a/spec/frontend/pages/import/history/components/import_error_details_spec.js b/spec/frontend/pages/import/history/components/import_error_details_spec.js
index 628ee8d7999..239826c1458 100644
--- a/spec/frontend/pages/import/history/components/import_error_details_spec.js
+++ b/spec/frontend/pages/import/history/components/import_error_details_spec.js
@@ -21,22 +21,13 @@ describe('ImportErrorDetails', () => {
});
}
- const originalApiVersion = gon.api_version;
- beforeAll(() => {
- gon.api_version = 'v4';
- });
-
- afterAll(() => {
- gon.api_version = originalApiVersion;
- });
-
beforeEach(() => {
+ gon.api_version = 'v4';
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('general behavior', () => {
diff --git a/spec/frontend/pages/import/history/components/import_history_app_spec.js b/spec/frontend/pages/import/history/components/import_history_app_spec.js
index 7d79583be19..43cbac25fe8 100644
--- a/spec/frontend/pages/import/history/components/import_history_app_spec.js
+++ b/spec/frontend/pages/import/history/components/import_history_app_spec.js
@@ -59,23 +59,14 @@ describe('ImportHistoryApp', () => {
});
}
- const originalApiVersion = gon.api_version;
- beforeAll(() => {
+ beforeEach(() => {
gon.api_version = 'v4';
gon.features = { fullPathProjectSearch: true };
- });
-
- afterAll(() => {
- gon.api_version = originalApiVersion;
- });
-
- beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('general behavior', () => {
diff --git a/spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js b/spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js
index c30b996437d..18a0098a715 100644
--- a/spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js
+++ b/spec/frontend/pages/profiles/password_prompt/password_prompt_modal_spec.js
@@ -25,8 +25,7 @@ describe('Password prompt modal', () => {
const findField = () => wrapper.findByTestId('password-prompt-field');
const findModal = () => wrapper.findComponent(GlModal);
const findConfirmBtn = () => findModal().props('actionPrimary');
- const findConfirmBtnDisabledState = () =>
- findModal().props('actionPrimary').attributes[2].disabled;
+ const findConfirmBtnDisabledState = () => findModal().props('actionPrimary').attributes.disabled;
const findCancelBtn = () => findModal().props('actionCancel');
@@ -41,10 +40,6 @@ describe('Password prompt modal', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the password field', () => {
expect(findField().exists()).toBe(true);
});
diff --git a/spec/frontend/pages/projects/forks/new/components/app_spec.js b/spec/frontend/pages/projects/forks/new/components/app_spec.js
index 0342b94a44d..e9a94878867 100644
--- a/spec/frontend/pages/projects/forks/new/components/app_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/app_spec.js
@@ -22,10 +22,6 @@ describe('App component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays the correct svg illustration', () => {
expect(wrapper.find('img').attributes('src')).toBe('illustrations/project-create-new-sm.svg');
});
diff --git a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
index f0593a854b2..9dce6fde6f6 100644
--- a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
@@ -6,7 +6,7 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import { kebabCase } from 'lodash';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as urlUtility from '~/lib/utils/url_utility';
import ForkForm from '~/pages/projects/forks/new/components/fork_form.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
@@ -14,7 +14,7 @@ import searchQuery from '~/pages/projects/forks/new/queries/search_forkable_name
import ProjectNamespace from '~/pages/projects/forks/new/components/project_namespace.vue';
import { START_RULE, CONTAINS_RULE } from '~/projects/project_name_rules';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
describe('ForkForm component', () => {
@@ -111,7 +111,6 @@ describe('ForkForm component', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
});
@@ -553,7 +552,7 @@ describe('ForkForm component', () => {
expect(urlUtility.redirectTo).toHaveBeenCalledWith(webUrl);
});
- it('display flash when POST is unsuccessful', async () => {
+ it('displays an alert when POST is unsuccessful', async () => {
const dummyError = 'Fork project failed';
jest.spyOn(axios, 'post').mockRejectedValue(dummyError);
diff --git a/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js b/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
index 82f451ed6ef..af578b69a81 100644
--- a/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
@@ -3,15 +3,14 @@ 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 { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import searchQuery from '~/pages/projects/forks/new/queries/search_forkable_namespaces.query.graphql';
import ProjectNamespace from '~/pages/projects/forks/new/components/project_namespace.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('ProjectNamespace component', () => {
let wrapper;
- let originalGon;
const data = {
project: {
@@ -85,14 +84,8 @@ describe('ProjectNamespace component', () => {
findListBox().vm.$emit('shown');
};
- beforeAll(() => {
- originalGon = window.gon;
- window.gon = { gitlab_url: gitlabUrl };
- });
-
- afterAll(() => {
- window.gon = originalGon;
- wrapper.destroy();
+ beforeEach(() => {
+ gon.gitlab_url = gitlabUrl;
});
describe('Initial state', () => {
@@ -152,7 +145,7 @@ describe('ProjectNamespace component', () => {
await nextTick();
});
- it('creates a flash message and captures the error', () => {
+ it('creates an alert message and captures the error', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while loading data. Please refresh the page to try again.',
captureError: true,
diff --git a/spec/frontend/pages/projects/graphs/code_coverage_spec.js b/spec/frontend/pages/projects/graphs/code_coverage_spec.js
index 5356953060a..882730d90ae 100644
--- a/spec/frontend/pages/projects/graphs/code_coverage_spec.js
+++ b/spec/frontend/pages/projects/graphs/code_coverage_spec.js
@@ -1,4 +1,4 @@
-import { GlAlert, GlListbox, GlListboxItem } from '@gitlab/ui';
+import { GlAlert, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
import { GlAreaChart } from '@gitlab/ui/dist/charts';
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
@@ -22,7 +22,7 @@ describe('Code Coverage', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findAreaChart = () => wrapper.findComponent(GlAreaChart);
- const findListBox = () => wrapper.findComponent(GlListbox);
+ const findListBox = () => wrapper.findComponent(GlCollapsibleListbox);
const findListBoxItems = () => wrapper.findAllComponents(GlListboxItem);
const findFirstListBoxItem = () => findListBoxItems().at(0);
const findSecondListBoxItem = () => findListBoxItems().at(1);
@@ -37,15 +37,10 @@ describe('Code Coverage', () => {
graphRef,
graphCsvPath,
},
- stubs: { GlListbox },
+ stubs: { GlCollapsibleListbox },
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when fetching data is successful', () => {
beforeEach(() => {
mockAxios = new MockAdapter(axios);
diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js
index 2d3b9afa8f6..07d05293a3c 100644
--- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js
+++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js
@@ -37,10 +37,6 @@ describe('Interval Pattern Input Component', () => {
const selectCustomRadio = () => findCustomRadio().setChecked(true);
const createWrapper = (props = {}, data = {}) => {
- if (wrapper) {
- throw new Error('A wrapper already exists');
- }
-
wrapper = mount(IntervalPatternInput, {
propsData: { ...props },
data() {
@@ -64,8 +60,6 @@ describe('Interval Pattern Input Component', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
window.gl = oldWindowGl;
});
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
index a633332ab65..e20c2fa47a7 100644
--- 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
@@ -31,10 +31,6 @@ describe('Pipeline Schedule Callout', () => {
await nextTick();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not render the callout', () => {
expect(findInnerContentOfCallout().exists()).toBe(false);
});
@@ -46,10 +42,6 @@ describe('Pipeline Schedule Callout', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the callout container', () => {
expect(findInnerContentOfCallout().exists()).toBe(true);
});
diff --git a/spec/frontend/pages/projects/shared/permissions/components/project_feature_settings_spec.js b/spec/frontend/pages/projects/shared/permissions/components/project_feature_settings_spec.js
index 5771e1b88e8..03c65ab4c9c 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/project_feature_settings_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/project_feature_settings_spec.js
@@ -31,11 +31,6 @@ describe('Project Feature Settings', () => {
},
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('Hidden name input', () => {
it('should set the hidden name input if the name exists', () => {
wrapper = mountComponent();
diff --git a/spec/frontend/pages/projects/shared/permissions/components/project_setting_row_spec.js b/spec/frontend/pages/projects/shared/permissions/components/project_setting_row_spec.js
index 6230809a6aa..91d3057aec5 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/project_setting_row_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/project_setting_row_spec.js
@@ -15,10 +15,6 @@ describe('Project Setting Row', () => {
wrapper = mountComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should show the label if it is set', async () => {
wrapper.setProps({ label: 'Test label' });
diff --git a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
index ff20b72c72c..0812be9745e 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
@@ -140,11 +140,6 @@ describe('Settings Panel', () => {
const findMonitorVisibilityInput = () =>
findMonitorSettings().findComponent(ProjectFeatureSetting);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('Project Visibility', () => {
it('should set the project visibility help path', () => {
wrapper = mountComponent();
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_alert_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_alert_spec.js
index 6a18473b1a7..1858a56b0e1 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_alert_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_alert_spec.js
@@ -15,11 +15,6 @@ describe('WikiAlert', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findGlAlert = () => wrapper.findComponent(GlAlert);
const findGlLink = () => wrapper.findComponent(GlLink);
const findGlSprintf = () => wrapper.findComponent(GlSprintf);
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
index c8e9a31b526..8e26453b564 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
@@ -31,11 +31,6 @@ describe('pages/shared/wikis/components/wiki_content', () => {
mock = new MockAdapter(axios);
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findGlAlert = () => wrapper.findComponent(GlAlert);
const findGlSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findContent = () => wrapper.find('[data-testid="wiki-page-content"]');
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
index ffcfd1d9f78..1be4a974f7a 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
@@ -103,8 +103,6 @@ describe('WikiForm', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
- wrapper = null;
});
it('displays markdown editor', () => {
@@ -116,7 +114,6 @@ describe('WikiForm', () => {
expect.objectContaining({
value: pageInfoPersisted.content,
renderMarkdownPath: pageInfoPersisted.markdownPreviewPath,
- markdownDocsPath: pageInfoPersisted.markdownHelpPath,
uploadsPath: pageInfoPersisted.uploadsPath,
autofocus: pageInfoPersisted.persisted,
}),
@@ -126,6 +123,10 @@ describe('WikiForm', () => {
id: 'wiki_content',
name: 'wiki[content]',
});
+
+ expect(markdownEditor.vm.$attrs['markdown-docs-path']).toEqual(
+ pageInfoPersisted.markdownHelpPath,
+ );
});
it.each`
@@ -172,7 +173,7 @@ describe('WikiForm', () => {
nextTick();
- expect(findMarkdownEditor().props('enablePreview')).toBe(enabled);
+ expect(findMarkdownEditor().vm.$attrs['enable-preview']).toBe(enabled);
});
it.each`
diff --git a/spec/frontend/pdf/index_spec.js b/spec/frontend/pdf/index_spec.js
index 98946412264..23477c73ba0 100644
--- a/spec/frontend/pdf/index_spec.js
+++ b/spec/frontend/pdf/index_spec.js
@@ -7,10 +7,6 @@ describe('PDFLab component', () => {
const mountComponent = ({ pdf }) => shallowMount(PDFLab, { propsData: { pdf } });
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('without PDF data', () => {
beforeEach(() => {
wrapper = mountComponent({ pdf: '' });
diff --git a/spec/frontend/pdf/page_spec.js b/spec/frontend/pdf/page_spec.js
index 4cf83a3252d..1d5c5cd98c4 100644
--- a/spec/frontend/pdf/page_spec.js
+++ b/spec/frontend/pdf/page_spec.js
@@ -9,10 +9,6 @@ jest.mock('pdfjs-dist/webpack', () => {
describe('Page component', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the page when mounting', async () => {
const testPage = {
render: jest.fn().mockReturnValue({ promise: Promise.resolve() }),
diff --git a/spec/frontend/performance_bar/components/add_request_spec.js b/spec/frontend/performance_bar/components/add_request_spec.js
index 5460feb66fe..de9cc1e8008 100644
--- a/spec/frontend/performance_bar/components/add_request_spec.js
+++ b/spec/frontend/performance_bar/components/add_request_spec.js
@@ -13,10 +13,6 @@ describe('add request form', () => {
wrapper = mount(AddRequest);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('hides the input on load', () => {
expect(findGlFormInput().exists()).toBe(false);
});
diff --git a/spec/frontend/performance_bar/components/detailed_metric_spec.js b/spec/frontend/performance_bar/components/detailed_metric_spec.js
index 5ab2c9abe5d..4194639fffe 100644
--- a/spec/frontend/performance_bar/components/detailed_metric_spec.js
+++ b/spec/frontend/performance_bar/components/detailed_metric_spec.js
@@ -38,10 +38,6 @@ describe('detailedMetric', () => {
const findAllSummaryItems = () =>
wrapper.findAllByTestId('performance-bar-summary-item').wrappers.map((w) => w.text());
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the current request has no details', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/performance_bar/components/request_warning_spec.js b/spec/frontend/performance_bar/components/request_warning_spec.js
index 9dd8ea9f933..7b6d8ff695d 100644
--- a/spec/frontend/performance_bar/components/request_warning_spec.js
+++ b/spec/frontend/performance_bar/components/request_warning_spec.js
@@ -5,10 +5,6 @@ describe('request warning', () => {
let wrapper;
const htmlId = 'request-123';
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the request has warnings', () => {
beforeEach(() => {
wrapper = shallowMount(RequestWarning, {
diff --git a/spec/frontend/persistent_user_callout_spec.js b/spec/frontend/persistent_user_callout_spec.js
index 6519989661f..376575a8acb 100644
--- a/spec/frontend/persistent_user_callout_spec.js
+++ b/spec/frontend/persistent_user_callout_spec.js
@@ -1,12 +1,12 @@
import MockAdapter from 'axios-mock-adapter';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+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 PersistentUserCallout from '~/persistent_user_callout';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('PersistentUserCallout', () => {
const dismissEndpoint = '/dismiss';
diff --git a/spec/frontend/pipeline_wizard/components/commit_spec.js b/spec/frontend/pipeline_wizard/components/commit_spec.js
index fa30b9c2b97..8f44a6c085b 100644
--- a/spec/frontend/pipeline_wizard/components/commit_spec.js
+++ b/spec/frontend/pipeline_wizard/components/commit_spec.js
@@ -74,10 +74,6 @@ describe('Pipeline Wizard - Commit Page', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows a commit message input with the correct label', () => {
expect(wrapper.findByTestId('commit_message').exists()).toBe(true);
expect(wrapper.find('label[for="commit_message"]').text()).toBe(i18n.commitMessageLabel);
@@ -121,10 +117,6 @@ describe('Pipeline Wizard - Commit Page', () => {
expect(wrapper.findByTestId('load-error').exists()).toBe(true);
expect(wrapper.findByTestId('load-error').text()).toBe(i18n.errors.loadError);
});
-
- afterEach(() => {
- wrapper.destroy();
- });
});
describe('commit result handling', () => {
@@ -151,7 +143,6 @@ describe('Pipeline Wizard - Commit Page', () => {
});
afterEach(() => {
- wrapper.destroy();
jest.clearAllMocks();
});
});
@@ -178,7 +169,6 @@ describe('Pipeline Wizard - Commit Page', () => {
});
afterEach(() => {
- wrapper.destroy();
jest.clearAllMocks();
});
});
@@ -246,10 +236,6 @@ describe('Pipeline Wizard - Commit Page', () => {
await waitForPromises();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('sets up without error', async () => {
expect(consoleSpy).not.toHaveBeenCalled();
});
diff --git a/spec/frontend/pipeline_wizard/components/editor_spec.js b/spec/frontend/pipeline_wizard/components/editor_spec.js
index dd0a609043a..6d7d4363189 100644
--- a/spec/frontend/pipeline_wizard/components/editor_spec.js
+++ b/spec/frontend/pipeline_wizard/components/editor_spec.js
@@ -9,10 +9,6 @@ describe('Pages Yaml Editor wrapper', () => {
propsData: { doc: new Document({ foo: 'bar' }), filename: 'foo.yml' },
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('mount hook', () => {
beforeEach(() => {
wrapper = mount(YamlEditor, defaultOptions);
diff --git a/spec/frontend/pipeline_wizard/components/input_wrapper_spec.js b/spec/frontend/pipeline_wizard/components/input_wrapper_spec.js
index f288264a11e..7f521e2523e 100644
--- a/spec/frontend/pipeline_wizard/components/input_wrapper_spec.js
+++ b/spec/frontend/pipeline_wizard/components/input_wrapper_spec.js
@@ -33,10 +33,6 @@ describe('Pipeline Wizard -- Input Wrapper', () => {
inputChild = wrapper.findComponent(TextWidget);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('will replace its value in compiled', async () => {
await inputChild.vm.$emit('input', inputValue);
const expected = new Document({
@@ -54,10 +50,6 @@ describe('Pipeline Wizard -- Input Wrapper', () => {
});
describe('Target Path Discovery', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
scenario | template | target | expected
${'simple nested object'} | ${{ foo: { bar: { baz: '$BOO' } } }} | ${'$BOO'} | ${['foo', 'bar', 'baz']}
diff --git a/spec/frontend/pipeline_wizard/components/step_nav_spec.js b/spec/frontend/pipeline_wizard/components/step_nav_spec.js
index c6eac1386fa..8e2f0ab0281 100644
--- a/spec/frontend/pipeline_wizard/components/step_nav_spec.js
+++ b/spec/frontend/pipeline_wizard/components/step_nav_spec.js
@@ -19,10 +19,6 @@ describe('Pipeline Wizard - Step Navigation Component', () => {
nextButton = wrapper.findByTestId('next-button');
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
scenario | showBackButton | showNextButton
${'does not show prev button'} | ${false} | ${false}
diff --git a/spec/frontend/pipeline_wizard/components/widgets/checklist_spec.js b/spec/frontend/pipeline_wizard/components/widgets/checklist_spec.js
index b8e194015b0..52e5d49ec99 100644
--- a/spec/frontend/pipeline_wizard/components/widgets/checklist_spec.js
+++ b/spec/frontend/pipeline_wizard/components/widgets/checklist_spec.js
@@ -39,10 +39,6 @@ describe('Pipeline Wizard - Checklist Widget', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('creates the component', () => {
createComponent();
expect(wrapper.exists()).toBe(true);
diff --git a/spec/frontend/pipeline_wizard/components/widgets/list_spec.js b/spec/frontend/pipeline_wizard/components/widgets/list_spec.js
index c9e9f5caebe..b0eb7279a94 100644
--- a/spec/frontend/pipeline_wizard/components/widgets/list_spec.js
+++ b/spec/frontend/pipeline_wizard/components/widgets/list_spec.js
@@ -39,10 +39,6 @@ describe('Pipeline Wizard - List Widget', () => {
};
describe('component setup and interface', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('prints the label inside the legend', () => {
createComponent();
@@ -168,10 +164,6 @@ describe('Pipeline Wizard - List Widget', () => {
});
describe('form validation', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not show validation state when untouched', async () => {
createComponent({}, mountExtended);
expect(findGlFormGroup().classes()).not.toContain('is-valid');
diff --git a/spec/frontend/pipeline_wizard/components/wrapper_spec.js b/spec/frontend/pipeline_wizard/components/wrapper_spec.js
index 33c6394eb41..1056602c912 100644
--- a/spec/frontend/pipeline_wizard/components/wrapper_spec.js
+++ b/spec/frontend/pipeline_wizard/components/wrapper_spec.js
@@ -48,10 +48,6 @@ describe('Pipeline Wizard - wrapper.vue', () => {
wrapper.find(`[data-input-target="${target}"]`).find('input');
describe('display', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('shows the steps', () => {
createComponent();
@@ -145,10 +141,6 @@ describe('Pipeline Wizard - wrapper.vue', () => {
}
});
- afterEach(() => {
- wrapper.destroy();
- });
-
if (expectCommitStepShown) {
it('does not show the step wrapper', async () => {
expect(wrapper.findComponent(WizardStep).isVisible()).toBe(false);
@@ -188,10 +180,6 @@ describe('Pipeline Wizard - wrapper.vue', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('initially shows a placeholder', async () => {
const editorContent = getEditorContent();
@@ -240,10 +228,6 @@ describe('Pipeline Wizard - wrapper.vue', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('highlight requests by the step get passed on to the editor', async () => {
const highlight = 'foo';
@@ -309,7 +293,6 @@ describe('Pipeline Wizard - wrapper.vue', () => {
});
afterEach(() => {
- wrapper.destroy();
inputField = undefined;
});
@@ -331,10 +314,6 @@ describe('Pipeline Wizard - wrapper.vue', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('emits done', () => {
expect(wrapper.emitted('done')).toBeUndefined();
diff --git a/spec/frontend/pipeline_wizard/pipeline_wizard_spec.js b/spec/frontend/pipeline_wizard/pipeline_wizard_spec.js
index 13234525159..e7bd7f686b6 100644
--- a/spec/frontend/pipeline_wizard/pipeline_wizard_spec.js
+++ b/spec/frontend/pipeline_wizard/pipeline_wizard_spec.js
@@ -24,10 +24,6 @@ describe('PipelineWizard', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('mounts without error', () => {
const consoleSpy = jest.spyOn(console, 'error');
diff --git a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
index 28a08b6da0f..aecaa640266 100644
--- a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
@@ -28,11 +28,6 @@ describe('The DAG annotations', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when there is one annotation', () => {
const currentNote = singleNote['dag-link103'];
diff --git a/spec/frontend/pipelines/components/dag/dag_graph_spec.js b/spec/frontend/pipelines/components/dag/dag_graph_spec.js
index 4619548d1bb..6b46be3dd49 100644
--- a/spec/frontend/pipelines/components/dag/dag_graph_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_graph_spec.js
@@ -36,11 +36,6 @@ describe('The DAG graph', () => {
createComponent({ graphData: parsedData });
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('in the basic case', () => {
beforeEach(() => {
/*
diff --git a/spec/frontend/pipelines/components/dag/dag_spec.js b/spec/frontend/pipelines/components/dag/dag_spec.js
index b0c26976c85..e2dc8120309 100644
--- a/spec/frontend/pipelines/components/dag/dag_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_spec.js
@@ -51,11 +51,6 @@ describe('Pipeline DAG graph wrapper', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when a query argument is undefined', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js
index d1da7cb3acf..169e3666cbd 100644
--- a/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js
+++ b/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js
@@ -4,7 +4,7 @@ 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 '~/flash';
+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';
@@ -12,7 +12,7 @@ import { mockFailedJobsQueryResponse, mockFailedJobsSummaryData } from '../../mo
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Failed Jobs App', () => {
let wrapper;
@@ -44,10 +44,6 @@ describe('Failed Jobs App', () => {
resolverSpy = jest.fn().mockResolvedValue(mockFailedJobsQueryResponse);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('loading spinner', () => {
it('displays loading spinner when fetching failed jobs', () => {
createComponent(resolverSpy);
diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
index 0df15afd70d..0ac3b6c9074 100644
--- a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
+++ b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import FailedJobsTable from '~/pipelines/components/jobs/failed_jobs_table.vue';
import RetryFailedJobMutation from '~/pipelines/graphql/mutations/retry_failed_job.mutation.graphql';
@@ -15,7 +15,7 @@ import {
mockPreparedFailedJobsDataNoPermission,
} from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
Vue.use(VueApollo);
@@ -45,10 +45,6 @@ describe('Failed Jobs Table', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays the failed jobs table', () => {
createComponent();
diff --git a/spec/frontend/pipelines/components/jobs/jobs_app_spec.js b/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
index 9bc14266593..52df7b4500b 100644
--- a/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
+++ b/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
@@ -4,7 +4,7 @@ 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 '~/flash';
+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';
@@ -12,7 +12,7 @@ import { mockPipelineJobsQueryResponse } from '../../mock_data';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Jobs app', () => {
let wrapper;
@@ -45,10 +45,6 @@ describe('Jobs app', () => {
resolverSpy = jest.fn().mockResolvedValue(mockPipelineJobsQueryResponse);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('loading spinner', () => {
const setup = async () => {
createComponent(resolverSpy);
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
index 5ea57c51e70..a4ecb9041c9 100644
--- 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
@@ -19,7 +19,7 @@ describe('Linked pipeline mini list', () => {
const createComponent = (props = {}) => {
wrapper = mount(LinkedPipelinesMiniList, {
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: {
...props,
@@ -34,11 +34,6 @@ describe('Linked pipeline mini list', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render one linked pipeline item', () => {
expect(findLinkedPipelineMiniItem().exists()).toBe(true);
});
@@ -102,11 +97,6 @@ describe('Linked pipeline mini list', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render three linked pipeline items', () => {
expect(findLinkedPipelineMiniItems().exists()).toBe(true);
expect(findLinkedPipelineMiniItems().length).toBe(3);
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
index 036b82530d5..e7415a6c596 100644
--- 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
@@ -33,11 +33,6 @@ describe('Pipeline Mini Graph', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render the pipeline stages', () => {
expect(findPipelineStages().exists()).toBe(true);
});
@@ -71,11 +66,6 @@ describe('Pipeline Mini Graph', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should have the correct props', () => {
expect(findPipelineMiniGraph().props()).toMatchObject({
downstreamPipelines: [],
@@ -118,11 +108,6 @@ describe('Pipeline Mini Graph', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render the downstream linked pipelines mini list only', () => {
expect(findLinkedPipelineDownstream().exists()).toBe(true);
expect(findLinkedPipelineUpstream().exists()).toBe(false);
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
index ab2056b4035..864f2d66f60 100644
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stage_spec.js
+++ b/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stage_spec.js
@@ -45,11 +45,10 @@ describe('Pipelines stage component', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
-
eventHub.$emit.mockRestore();
mock.restore();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
+ wrapper.destroy();
});
const findCiActionBtn = () => wrapper.find('.js-ci-action');
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
index c123f53886e..73e810bde99 100644
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stages_spec.js
+++ b/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stages_spec.js
@@ -60,9 +60,4 @@ describe('Pipeline Stages', () => {
expect(findPipelineStagesAt(0).props('isMergeTrain')).toBe(true);
expect(findPipelineStagesAt(1).props('isMergeTrain')).toBe(true);
});
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
});
diff --git a/spec/frontend/pipelines/components/pipeline_tabs_spec.js b/spec/frontend/pipelines/components/pipeline_tabs_spec.js
index c2cb95d4320..337af6c1f60 100644
--- a/spec/frontend/pipelines/components/pipeline_tabs_spec.js
+++ b/spec/frontend/pipelines/components/pipeline_tabs_spec.js
@@ -39,10 +39,6 @@ describe('The Pipeline Tabs', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Tabs', () => {
it.each`
tabName | tabComponent
diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
index ba7262353f0..51a4487a3ef 100644
--- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
+++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
@@ -51,8 +51,6 @@ describe('Pipelines filtered search', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
- wrapper = null;
});
it('displays UI elements', () => {
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
index 6531a15ab8e..b560eea4882 100644
--- 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
@@ -29,11 +29,6 @@ describe('CI Templates', () => {
const findTemplateName = () => wrapper.findByTestId('template-name');
const findTemplateLogo = () => wrapper.findByTestId('template-logo');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('renders template list', () => {
beforeEach(() => {
createWrapper();
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
index 0c2938921d6..700be076e0c 100644
--- 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
@@ -37,11 +37,6 @@ describe('iOS Templates', () => {
const findSetupRunnerLink = () => wrapper.findByText('Set up a runner');
const configurePipelineLink = () => wrapper.findByTestId('configure-pipeline-link');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when ios runners are not available', () => {
beforeEach(() => {
wrapper = createWrapper({ iosRunnersAvailable: false });
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
index f255e0d857f..0f4a2b1d02f 100644
--- 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
@@ -42,11 +42,6 @@ describe('Pipelines CI Templates', () => {
const findDocumentationLink = () => wrapper.findByTestId('documentation-link');
const findSettingsButton = () => wrapper.findByTestId('settings-button');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('renders test template', () => {
beforeEach(() => {
wrapper = createWrapper();
diff --git a/spec/frontend/pipelines/empty_state_spec.js b/spec/frontend/pipelines/empty_state_spec.js
index 0abf7f59717..5465e4d77da 100644
--- a/spec/frontend/pipelines/empty_state_spec.js
+++ b/spec/frontend/pipelines/empty_state_spec.js
@@ -35,11 +35,6 @@ describe('Pipelines Empty State', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when user can configure CI', () => {
describe('when the ios_specific_templates experiment is active', () => {
beforeEach(() => {
diff --git a/spec/frontend/pipelines/graph/action_component_spec.js b/spec/frontend/pipelines/graph/action_component_spec.js
index e3eea503b46..890255f225e 100644
--- a/spec/frontend/pipelines/graph/action_component_spec.js
+++ b/spec/frontend/pipelines/graph/action_component_spec.js
@@ -33,7 +33,6 @@ describe('pipeline graph action component', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('render', () => {
diff --git a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
index 99bccd21656..42e47a23db8 100644
--- a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
@@ -101,10 +101,6 @@ describe('Pipeline graph wrapper', () => {
createComponent({ apolloProvider, data, provide, mountFn });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when data is loading', () => {
it('displays the loading icon', () => {
createComponentWithApollo();
diff --git a/spec/frontend/pipelines/graph/graph_view_selector_spec.js b/spec/frontend/pipelines/graph/graph_view_selector_spec.js
index 43587bebedf..78265165d1f 100644
--- a/spec/frontend/pipelines/graph/graph_view_selector_spec.js
+++ b/spec/frontend/pipelines/graph/graph_view_selector_spec.js
@@ -42,10 +42,6 @@ describe('the graph view selector component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when showing stage view', () => {
beforeEach(() => {
createComponent({ mountFn: mount });
diff --git a/spec/frontend/pipelines/graph/job_group_dropdown_spec.js b/spec/frontend/pipelines/graph/job_group_dropdown_spec.js
index d8afb33e148..1419a7b9982 100644
--- a/spec/frontend/pipelines/graph/job_group_dropdown_spec.js
+++ b/spec/frontend/pipelines/graph/job_group_dropdown_spec.js
@@ -69,10 +69,6 @@ describe('job group dropdown component', () => {
wrapper = mountFn(JobGroupDropdown, { propsData: { group } });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
createComponent({ mountFn: mount });
});
diff --git a/spec/frontend/pipelines/graph/job_item_spec.js b/spec/frontend/pipelines/graph/job_item_spec.js
index 3224c87ab6b..5cc2c76f3dd 100644
--- a/spec/frontend/pipelines/graph/job_item_spec.js
+++ b/spec/frontend/pipelines/graph/job_item_spec.js
@@ -1,10 +1,11 @@
import MockAdapter from 'axios-mock-adapter';
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import { GlBadge, GlModal } from '@gitlab/ui';
+import { shallowMount, mount } from '@vue/test-utils';
+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 { extendedWrapper } from 'helpers/vue_test_utils_helper';
import {
@@ -19,12 +20,14 @@ import {
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');
@@ -41,9 +44,9 @@ describe('pipeline graph job item', () => {
job: mockJob,
};
- const createWrapper = ({ props, data } = {}) => {
+ const createWrapper = ({ props, data, mountFn = mount, mocks = {} } = {}) => {
wrapper = extendedWrapper(
- mount(JobItem, {
+ mountFn(JobItem, {
data() {
return {
...data,
@@ -53,6 +56,9 @@ describe('pipeline graph job item', () => {
...defaultProps,
...props,
},
+ mocks: {
+ ...mocks,
+ },
}),
);
};
@@ -238,6 +244,37 @@ describe('pipeline graph job item', () => {
});
});
+ describe('when retrying', () => {
+ const mockToastShow = jest.fn();
+
+ beforeEach(async () => {
+ createWrapper({
+ mountFn: shallowMount,
+ data: {
+ currentSkipModalValue: true,
+ },
+ props: {
+ skipRetryModal: true,
+ job: triggerJobWithRetryAction,
+ },
+ mocks: {
+ $toast: {
+ show: mockToastShow,
+ },
+ },
+ });
+
+ jest.spyOn(wrapper.vm.$toast, 'show');
+
+ 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
diff --git a/spec/frontend/pipelines/graph/linked_pipeline_spec.js b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
index f396fe2aff4..b5ef10dee12 100644
--- a/spec/frontend/pipelines/graph/linked_pipeline_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
@@ -58,10 +58,6 @@ describe('Linked pipeline', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendered output', () => {
const props = {
pipeline: mockPipeline,
diff --git a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
index 63e2d8707ea..6e4b9498918 100644
--- a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
@@ -65,10 +65,6 @@ describe('Linked Pipelines Column', () => {
createComponent({ apolloProvider, mountFn, props });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('it renders correctly', () => {
beforeEach(() => {
createComponentWithApollo();
diff --git a/spec/frontend/pipelines/graph/stage_column_component_spec.js b/spec/frontend/pipelines/graph/stage_column_component_spec.js
index 19f597a7267..d4d7f1618c5 100644
--- a/spec/frontend/pipelines/graph/stage_column_component_spec.js
+++ b/spec/frontend/pipelines/graph/stage_column_component_spec.js
@@ -54,10 +54,6 @@ describe('stage column component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when mounted', () => {
beforeEach(() => {
createComponent({ method: mount });
diff --git a/spec/frontend/pipelines/graph_shared/links_inner_spec.js b/spec/frontend/pipelines/graph_shared/links_inner_spec.js
index 2c6d126e12c..50f754393fe 100644
--- a/spec/frontend/pipelines/graph_shared/links_inner_spec.js
+++ b/spec/frontend/pipelines/graph_shared/links_inner_spec.js
@@ -81,7 +81,6 @@ describe('Links Inner component', () => {
afterEach(() => {
jest.restoreAllMocks();
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/pipelines/graph_shared/links_layer_spec.js b/spec/frontend/pipelines/graph_shared/links_layer_spec.js
index e2699d6ff2e..9d39c86ed5e 100644
--- a/spec/frontend/pipelines/graph_shared/links_layer_spec.js
+++ b/spec/frontend/pipelines/graph_shared/links_layer_spec.js
@@ -35,10 +35,6 @@ describe('links layer component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with show links off', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/pipelines/header_component_spec.js b/spec/frontend/pipelines/header_component_spec.js
index e583c0798f5..a4d7d0e30f8 100644
--- a/spec/frontend/pipelines/header_component_spec.js
+++ b/spec/frontend/pipelines/header_component_spec.js
@@ -71,11 +71,6 @@ describe('Pipeline details header', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('initial loading', () => {
beforeEach(() => {
wrapper = createComponent(null, { isLoading: true });
diff --git a/spec/frontend/pipelines/nav_controls_spec.js b/spec/frontend/pipelines/nav_controls_spec.js
index 2c4740df174..15de7dc51f1 100644
--- a/spec/frontend/pipelines/nav_controls_spec.js
+++ b/spec/frontend/pipelines/nav_controls_spec.js
@@ -1,23 +1,20 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+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 = shallowMount(NavControls, {
+ wrapper = shallowMountExtended(NavControls, {
propsData: {
...props,
},
});
};
- const findRunPipeline = () => wrapper.find('.js-run-pipeline');
-
- afterEach(() => {
- wrapper.destroy();
- });
+ 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 = {
@@ -28,9 +25,9 @@ describe('Pipelines Nav Controls', () => {
createComponent(mockData);
- const runPipeline = findRunPipeline();
- expect(runPipeline.text()).toContain('Run pipeline');
- expect(runPipeline.attributes('href')).toBe(mockData.newPipelinePath);
+ 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', () => {
@@ -42,7 +39,7 @@ describe('Pipelines Nav Controls', () => {
createComponent(mockData);
- expect(findRunPipeline().exists()).toBe(false);
+ expect(findRunPipelineButton().exists()).toBe(false);
});
it('should render link for CI lint', () => {
@@ -54,9 +51,10 @@ describe('Pipelines Nav Controls', () => {
};
createComponent(mockData);
+ const ciLintButton = findCiLintButton();
- expect(wrapper.find('.js-ci-lint').text().trim()).toContain('CI lint');
- expect(wrapper.find('.js-ci-lint').attributes('href')).toBe(mockData.ciLintPath);
+ expect(ciLintButton.text()).toContain('CI lint');
+ expect(ciLintButton.attributes('href')).toBe(mockData.ciLintPath);
});
describe('Reset Runners Cache', () => {
@@ -70,16 +68,13 @@ describe('Pipelines Nav Controls', () => {
});
it('should render button for resetting runner caches', () => {
- expect(wrapper.find('.js-clear-cache').text().trim()).toContain('Clear runner caches');
+ expect(findClearCacheButton().text()).toContain('Clear runner caches');
});
- it('should emit postAction event when reset runner cache button is clicked', async () => {
- jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {});
-
- wrapper.find('.js-clear-cache').vm.$emit('click');
- await nextTick();
+ it('should emit postAction event when reset runner cache button is clicked', () => {
+ findClearCacheButton().vm.$emit('click');
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('resetRunnersCache', 'foo');
+ expect(wrapper.emitted('resetRunnersCache')).toEqual([['foo']]);
});
});
});
diff --git a/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js b/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
index df10742fd93..123f2e011c3 100644
--- a/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
+++ b/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
@@ -39,10 +39,6 @@ describe('pipeline graph component', () => {
const findLinksLayer = () => wrapper.findComponent(LinksLayer);
const findPipelineGraph = () => wrapper.find('[data-testid="graph-container"]');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with `VALID` status', () => {
beforeEach(() => {
wrapper = createComponent({
diff --git a/spec/frontend/pipelines/pipeline_labels_spec.js b/spec/frontend/pipelines/pipeline_labels_spec.js
index ca0229b1cbe..6a37e36352b 100644
--- a/spec/frontend/pipelines/pipeline_labels_spec.js
+++ b/spec/frontend/pipelines/pipeline_labels_spec.js
@@ -30,10 +30,6 @@ describe('Pipeline label component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should not render tags when flags are not set', () => {
createComponent();
diff --git a/spec/frontend/pipelines/pipeline_multi_actions_spec.js b/spec/frontend/pipelines/pipeline_multi_actions_spec.js
index bedde71c48d..e3c9983aa52 100644
--- a/spec/frontend/pipelines/pipeline_multi_actions_spec.js
+++ b/spec/frontend/pipelines/pipeline_multi_actions_spec.js
@@ -67,8 +67,6 @@ describe('Pipeline Multi Actions Dropdown', () => {
afterEach(() => {
mockAxios.restore();
-
- wrapper.destroy();
});
it('should render the dropdown', () => {
diff --git a/spec/frontend/pipelines/pipeline_triggerer_spec.js b/spec/frontend/pipelines/pipeline_triggerer_spec.js
index 58bfb68e85c..856c0484075 100644
--- a/spec/frontend/pipelines/pipeline_triggerer_spec.js
+++ b/spec/frontend/pipelines/pipeline_triggerer_spec.js
@@ -22,15 +22,11 @@ describe('Pipelines Triggerer', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findAvatarLink = () => wrapper.findComponent(GlAvatarLink);
const findAvatar = () => wrapper.findComponent(GlAvatar);
const findTriggerer = () => wrapper.findByText('API');
diff --git a/spec/frontend/pipelines/pipeline_url_spec.js b/spec/frontend/pipelines/pipeline_url_spec.js
index c62898f0c83..f00ee4a6367 100644
--- a/spec/frontend/pipelines/pipeline_url_spec.js
+++ b/spec/frontend/pipelines/pipeline_url_spec.js
@@ -35,10 +35,6 @@ describe('Pipeline Url Component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render pipeline url table cell', () => {
createComponent();
diff --git a/spec/frontend/pipelines/pipelines_actions_spec.js b/spec/frontend/pipelines/pipelines_actions_spec.js
index e034d52a33c..2db9f5c2a83 100644
--- a/spec/frontend/pipelines/pipelines_actions_spec.js
+++ b/spec/frontend/pipelines/pipelines_actions_spec.js
@@ -5,7 +5,7 @@ import { nextTick } from 'vue';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { TEST_HOST } from 'spec/test_constants';
-import { createAlert } from '~/flash';
+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';
@@ -13,7 +13,7 @@ import PipelinesManualActions from '~/pipelines/components/pipelines_list/pipeli
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
describe('Pipelines Actions dropdown', () => {
@@ -37,9 +37,6 @@ describe('Pipelines Actions dropdown', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
-
mock.restore();
confirmAction.mockReset();
});
diff --git a/spec/frontend/pipelines/pipelines_artifacts_spec.js b/spec/frontend/pipelines/pipelines_artifacts_spec.js
index e3e54716a7b..9fedbaf9b56 100644
--- a/spec/frontend/pipelines/pipelines_artifacts_spec.js
+++ b/spec/frontend/pipelines/pipelines_artifacts_spec.js
@@ -34,11 +34,6 @@ describe('Pipelines Artifacts dropdown', () => {
const findAllGlDropdownItems = () =>
wrapper.findComponent(GlDropdown).findAllComponents(GlDropdownItem);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render a dropdown with all the provided artifacts', () => {
createComponent();
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
index 2523b901506..48539d84024 100644
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ b/spec/frontend/pipelines/pipelines_spec.js
@@ -11,7 +11,7 @@ import { mockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import Api from '~/api';
-import { createAlert, VARIANT_WARNING } from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/alert';
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';
@@ -25,7 +25,7 @@ import TablePagination from '~/vue_shared/components/pagination/table_pagination
import { stageReply, users, mockSearch, branches } from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const mockProjectPath = 'twitter/flight';
const mockProjectId = '21';
@@ -114,7 +114,6 @@ describe('Pipelines', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.reset();
window.history.pushState.mockReset();
});
diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js
index 6ec8901038b..8d2a52eb6d0 100644
--- a/spec/frontend/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_spec.js
@@ -69,12 +69,6 @@ describe('Pipelines Table', () => {
pipeline = createMockPipeline();
});
- afterEach(() => {
- wrapper.destroy();
-
- wrapper = null;
- });
-
describe('Pipelines Table', () => {
beforeEach(() => {
createComponent({ pipelines: [pipeline], viewType: 'root' });
diff --git a/spec/frontend/pipelines/test_reports/stores/actions_spec.js b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
index f6287107ed0..e05d2151f0a 100644
--- a/spec/frontend/pipelines/test_reports/stores/actions_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
@@ -2,13 +2,13 @@ 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 '~/flash';
+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('~/flash.js');
+jest.mock('~/alert');
describe('Actions TestReports Store', () => {
let mock;
@@ -49,7 +49,7 @@ describe('Actions TestReports Store', () => {
);
});
- it('should create flash on API error', async () => {
+ it('should create alert on API error', async () => {
await testAction(
actions.fetchSummary,
null,
diff --git a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
index ed0cc71eb97..9c374ea817a 100644
--- a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
@@ -1,9 +1,9 @@
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 '~/flash';
+import { createAlert } from '~/alert';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
describe('Mutations TestReports Store', () => {
let mockState;
@@ -58,7 +58,7 @@ describe('Mutations TestReports Store', () => {
expect(mockState.errorMessage).toBe(message);
});
- it('should show a flash message otherwise', () => {
+ it('should show an alert message otherwise', () => {
mutations[types.SET_SUITE_ERROR](mockState, {});
expect(createAlert).toHaveBeenCalled();
diff --git a/spec/frontend/pipelines/test_reports/test_case_details_spec.js b/spec/frontend/pipelines/test_reports/test_case_details_spec.js
index f194864447c..f8663408817 100644
--- a/spec/frontend/pipelines/test_reports/test_case_details_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_case_details_spec.js
@@ -45,11 +45,6 @@ describe('Test case details', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('required details', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/pipelines/test_reports/test_reports_spec.js b/spec/frontend/pipelines/test_reports/test_reports_spec.js
index 9b9ee4172f9..c8c917a1b9e 100644
--- a/spec/frontend/pipelines/test_reports/test_reports_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_reports_spec.js
@@ -60,10 +60,6 @@ describe('Test reports app', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when component is created', () => {
it('should call fetchSummary when pipeline has test report', () => {
createComponent();
diff --git a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
index da13df833e7..8eb83f17f4d 100644
--- a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
@@ -65,10 +65,6 @@ describe('Test reports suite table', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render a message when there are no test cases', () => {
createComponent({ suite: [] });
diff --git a/spec/frontend/pipelines/time_ago_spec.js b/spec/frontend/pipelines/time_ago_spec.js
index f0da0df2ba6..efb1bf09d20 100644
--- a/spec/frontend/pipelines/time_ago_spec.js
+++ b/spec/frontend/pipelines/time_ago_spec.js
@@ -30,11 +30,6 @@ describe('Timeago component', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const duration = () => wrapper.find('.duration');
const finishedAt = () => wrapper.find('.finished-at');
const findInProgress = () => wrapper.findByTestId('pipeline-in-progress');
diff --git a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
index caa66502e11..d518519a424 100644
--- a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
@@ -71,11 +71,6 @@ describe('Pipeline Branch Name Token', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('passes config correctly', () => {
expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
});
diff --git a/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js
index c090fd353f7..cf4ccb5ce43 100644
--- a/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js
@@ -45,11 +45,6 @@ describe('Pipeline Status Token', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('passes config correctly', () => {
expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
});
diff --git a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
index 7311a5d2f5a..88c88d8f16f 100644
--- a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
@@ -53,11 +53,6 @@ describe('Pipeline Branch Name Token', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('passes config correctly', () => {
expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
});
diff --git a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
index c763bfe1b27..e9ec684a350 100644
--- a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
@@ -52,11 +52,6 @@ describe('Pipeline Trigger Author Token', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('passes config correctly', () => {
expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
});
diff --git a/spec/frontend/popovers/components/popovers_spec.js b/spec/frontend/popovers/components/popovers_spec.js
index 1299e7277d1..7f247fbbd4f 100644
--- a/spec/frontend/popovers/components/popovers_spec.js
+++ b/spec/frontend/popovers/components/popovers_spec.js
@@ -33,11 +33,6 @@ describe('popovers/components/popovers.vue', () => {
const allPopovers = () => wrapper.findAllComponents(GlPopover);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('addPopovers', () => {
it('attaches popovers to the targets specified', async () => {
const target = createPopoverTarget();
diff --git a/spec/frontend/profile/account/components/delete_account_modal_spec.js b/spec/frontend/profile/account/components/delete_account_modal_spec.js
index e4a316e1ee7..9a8f82f0028 100644
--- a/spec/frontend/profile/account/components/delete_account_modal_spec.js
+++ b/spec/frontend/profile/account/components/delete_account_modal_spec.js
@@ -40,12 +40,6 @@ describe('DeleteAccountModal component', () => {
vm = wrapper.vm;
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- vm = null;
- });
-
const findElements = () => {
const confirmation = vm.confirmWithPassword ? 'password' : 'username';
return {
diff --git a/spec/frontend/profile/account/components/update_username_spec.js b/spec/frontend/profile/account/components/update_username_spec.js
index fa0e86a7b05..d922820601e 100644
--- a/spec/frontend/profile/account/components/update_username_spec.js
+++ b/spec/frontend/profile/account/components/update_username_spec.js
@@ -1,14 +1,15 @@
import { GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import waitForPromises from 'helpers/wait_for_promises';
import { TEST_HOST } from 'helpers/test_constants';
-import { createAlert } from '~/flash';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import UpdateUsername from '~/profile/account/components/update_username.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('UpdateUsername component', () => {
const rootUrl = TEST_HOST;
@@ -21,8 +22,10 @@ describe('UpdateUsername component', () => {
let wrapper;
let axiosMock;
+ const findNewUsernameInput = () => wrapper.findByTestId('new-username-input');
+
const createComponent = (props = {}) => {
- wrapper = shallowMount(UpdateUsername, {
+ wrapper = shallowMountExtended(UpdateUsername, {
propsData: {
...defaultProps,
...props,
@@ -39,8 +42,8 @@ describe('UpdateUsername component', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
+ Vue.config.errorHandler = null;
});
const findElements = () => {
@@ -56,6 +59,13 @@ describe('UpdateUsername component', () => {
};
};
+ const clickModalWithErrorResponse = () => {
+ Vue.config.errorHandler = jest.fn(); // silence thrown error
+ const { modal } = findElements();
+ modal.vm.$emit('primary');
+ return waitForPromises();
+ };
+
it('has a disabled button if the username was not changed', async () => {
const { openModalBtn } = findElements();
@@ -80,11 +90,7 @@ describe('UpdateUsername component', () => {
beforeEach(async () => {
createComponent();
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ newUsername });
-
- await nextTick();
+ await findNewUsernameInput().setValue(newUsername);
});
it('confirmation modal contains proper header and body', async () => {
@@ -100,14 +106,15 @@ describe('UpdateUsername component', () => {
axiosMock.onPut(actionUrl).replyOnce(() => [HTTP_STATUS_OK, { message: 'Username changed' }]);
jest.spyOn(axios, 'put');
- await wrapper.vm.onConfirm();
- await nextTick();
+ const { modal } = findElements();
+ modal.vm.$emit('primary');
+ await waitForPromises();
expect(axios.put).toHaveBeenCalledWith(actionUrl, { user: { username: newUsername } });
});
it('sets the username after a successful update', async () => {
- const { input, openModalBtn } = findElements();
+ const { input, openModalBtn, modal } = findElements();
axiosMock.onPut(actionUrl).replyOnce(() => {
expect(input.attributes('disabled')).toBe('disabled');
@@ -117,8 +124,8 @@ describe('UpdateUsername component', () => {
return [HTTP_STATUS_OK, { message: 'Username changed' }];
});
- await wrapper.vm.onConfirm();
- await nextTick();
+ modal.vm.$emit('primary');
+ await waitForPromises();
expect(input.attributes('disabled')).toBe(undefined);
expect(openModalBtn.props('disabled')).toBe(true);
@@ -136,7 +143,8 @@ describe('UpdateUsername component', () => {
return [HTTP_STATUS_BAD_REQUEST, { message: 'Invalid username' }];
});
- await expect(wrapper.vm.onConfirm()).rejects.toThrow();
+ await clickModalWithErrorResponse();
+
expect(input.attributes('disabled')).toBe(undefined);
expect(openModalBtn.props('disabled')).toBe(false);
expect(openModalBtn.props('loading')).toBe(false);
@@ -147,7 +155,7 @@ describe('UpdateUsername component', () => {
return [HTTP_STATUS_BAD_REQUEST, { message: 'Invalid username' }];
});
- await expect(wrapper.vm.onConfirm()).rejects.toThrow();
+ await clickModalWithErrorResponse();
expect(createAlert).toHaveBeenCalledWith({
message: 'Invalid username',
@@ -159,7 +167,7 @@ describe('UpdateUsername component', () => {
return [HTTP_STATUS_BAD_REQUEST];
});
- await expect(wrapper.vm.onConfirm()).rejects.toThrow();
+ await clickModalWithErrorResponse();
expect(createAlert).toHaveBeenCalledWith({
message: 'An error occurred while updating your username, please try again.',
diff --git a/spec/frontend/profile/components/activity_calendar_spec.js b/spec/frontend/profile/components/activity_calendar_spec.js
new file mode 100644
index 00000000000..fb9dc7b22f7
--- /dev/null
+++ b/spec/frontend/profile/components/activity_calendar_spec.js
@@ -0,0 +1,120 @@
+import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
+import * as GitLabUIUtils from '@gitlab/ui/dist/utils';
+
+import ActivityCalendar from '~/profile/components/activity_calendar.vue';
+import AjaxCache from '~/lib/utils/ajax_cache';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { useFakeDate } from 'helpers/fake_date';
+import { userCalendarResponse } from '../mock_data';
+
+jest.mock('~/lib/utils/ajax_cache');
+jest.mock('@gitlab/ui/dist/utils');
+
+describe('ActivityCalendar', () => {
+ // Feb 21st, 2023
+ useFakeDate(2023, 1, 21);
+
+ let wrapper;
+
+ const defaultProvide = {
+ userCalendarPath: '/users/root/calendar.json',
+ utcOffset: '0',
+ };
+
+ const createComponent = () => {
+ wrapper = mountExtended(ActivityCalendar, { provide: defaultProvide });
+ };
+
+ const mockSuccessfulApiRequest = () =>
+ AjaxCache.retrieve.mockResolvedValueOnce(userCalendarResponse);
+ const mockUnsuccessfulApiRequest = () => AjaxCache.retrieve.mockRejectedValueOnce();
+
+ const findCalendar = () => wrapper.findByTestId('contrib-calendar');
+
+ describe('when API request is loading', () => {
+ beforeEach(() => {
+ AjaxCache.retrieve.mockReturnValueOnce(new Promise(() => {}));
+ });
+
+ it('renders loading icon', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ });
+ });
+
+ describe('when API request is successful', () => {
+ beforeEach(() => {
+ mockSuccessfulApiRequest();
+ });
+
+ it('renders the calendar', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findCalendar().exists()).toBe(true);
+ expect(wrapper.findByText(ActivityCalendar.i18n.calendarHint).exists()).toBe(true);
+ });
+
+ describe('when window is resized', () => {
+ it('re-renders the calendar', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ mockSuccessfulApiRequest();
+ window.innerWidth = 1200;
+ window.dispatchEvent(new Event('resize'));
+
+ await waitForPromises();
+
+ expect(findCalendar().exists()).toBe(true);
+ expect(AjaxCache.retrieve).toHaveBeenCalledTimes(2);
+ });
+ });
+ });
+
+ describe('when API request is not successful', () => {
+ beforeEach(() => {
+ mockUnsuccessfulApiRequest();
+ });
+
+ it('renders error', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlAlert).exists()).toBe(true);
+ });
+
+ describe('when retry button is clicked', () => {
+ it('retries API request', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ mockSuccessfulApiRequest();
+
+ await wrapper.findByRole('button', { name: ActivityCalendar.i18n.retry }).trigger('click');
+
+ await waitForPromises();
+
+ expect(findCalendar().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('when screen is extra small', () => {
+ beforeEach(() => {
+ GitLabUIUtils.GlBreakpointInstance.getBreakpointSize.mockReturnValueOnce('xs');
+ });
+
+ it('does not render the calendar', () => {
+ createComponent();
+
+ expect(findCalendar().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/profile/components/followers_tab_spec.js b/spec/frontend/profile/components/followers_tab_spec.js
index 4af428c4e0c..9cc5bdea9be 100644
--- a/spec/frontend/profile/components/followers_tab_spec.js
+++ b/spec/frontend/profile/components/followers_tab_spec.js
@@ -1,4 +1,4 @@
-import { GlTab } from '@gitlab/ui';
+import { GlBadge, GlTab } from '@gitlab/ui';
import { s__ } from '~/locale';
import FollowersTab from '~/profile/components/followers_tab.vue';
@@ -8,12 +8,25 @@ describe('FollowersTab', () => {
let wrapper;
const createComponent = () => {
- wrapper = shallowMountExtended(FollowersTab);
+ wrapper = shallowMountExtended(FollowersTab, {
+ provide: {
+ followers: 2,
+ },
+ });
};
- it('renders `GlTab` and sets `title` prop', () => {
+ it('renders `GlTab` and sets title', () => {
createComponent();
- expect(wrapper.findComponent(GlTab).attributes('title')).toBe(s__('UserProfile|Followers'));
+ expect(wrapper.findComponent(GlTab).element.textContent).toContain(
+ s__('UserProfile|Followers'),
+ );
+ });
+
+ it('renders `GlBadge`, sets size and content', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(GlBadge).attributes('size')).toBe('sm');
+ expect(wrapper.findComponent(GlBadge).element.textContent).toBe('2');
});
});
diff --git a/spec/frontend/profile/components/following_tab_spec.js b/spec/frontend/profile/components/following_tab_spec.js
index 75123274ccb..c9d56360c3e 100644
--- a/spec/frontend/profile/components/following_tab_spec.js
+++ b/spec/frontend/profile/components/following_tab_spec.js
@@ -1,4 +1,4 @@
-import { GlTab } from '@gitlab/ui';
+import { GlBadge, GlTab } from '@gitlab/ui';
import { s__ } from '~/locale';
import FollowingTab from '~/profile/components/following_tab.vue';
@@ -8,12 +8,25 @@ describe('FollowingTab', () => {
let wrapper;
const createComponent = () => {
- wrapper = shallowMountExtended(FollowingTab);
+ wrapper = shallowMountExtended(FollowingTab, {
+ provide: {
+ followees: 3,
+ },
+ });
};
- it('renders `GlTab` and sets `title` prop', () => {
+ it('renders `GlTab` and sets title', () => {
createComponent();
- expect(wrapper.findComponent(GlTab).attributes('title')).toBe(s__('UserProfile|Following'));
+ expect(wrapper.findComponent(GlTab).element.textContent).toContain(
+ s__('UserProfile|Following'),
+ );
+ });
+
+ it('renders `GlBadge`, sets size and content', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(GlBadge).attributes('size')).toBe('sm');
+ expect(wrapper.findComponent(GlBadge).element.textContent).toBe('3');
});
});
diff --git a/spec/frontend/profile/components/overview_tab_spec.js b/spec/frontend/profile/components/overview_tab_spec.js
index eb27515bca3..d4cb1dfd15d 100644
--- a/spec/frontend/profile/components/overview_tab_spec.js
+++ b/spec/frontend/profile/components/overview_tab_spec.js
@@ -3,6 +3,7 @@ import { GlTab } from '@gitlab/ui';
import { s__ } from '~/locale';
import OverviewTab from '~/profile/components/overview_tab.vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ActivityCalendar from '~/profile/components/activity_calendar.vue';
describe('OverviewTab', () => {
let wrapper;
@@ -16,4 +17,10 @@ describe('OverviewTab', () => {
expect(wrapper.findComponent(GlTab).attributes('title')).toBe(s__('UserProfile|Overview'));
});
+
+ it('renders `ActivityCalendar` component', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(ActivityCalendar).exists()).toBe(true);
+ });
});
diff --git a/spec/frontend/profile/components/user_achievements_spec.js b/spec/frontend/profile/components/user_achievements_spec.js
new file mode 100644
index 00000000000..5b584eff362
--- /dev/null
+++ b/spec/frontend/profile/components/user_achievements_spec.js
@@ -0,0 +1,102 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import getUserAchievementsEmptyResponse from 'test_fixtures/graphql/get_user_achievements_empty_response.json';
+import getUserAchievementsLongResponse from 'test_fixtures/graphql/get_user_achievements_long_response.json';
+import getUserAchievementsResponse from 'test_fixtures/graphql/get_user_achievements_with_avatar_and_description_response.json';
+import getUserAchievementsNoAvatarResponse from 'test_fixtures/graphql/get_user_achievements_without_avatar_or_description_response.json';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import UserAchievements from '~/profile/components/user_achievements.vue';
+import getUserAchievements from '~/profile/components//graphql/get_user_achievements.query.graphql';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+
+const USER_ID = 123;
+const ROOT_URL = 'https://gitlab.com/';
+const PLACEHOLDER_URL = 'https://gitlab.com/assets/gitlab_logo.png';
+const userAchievement1 = getUserAchievementsResponse.data.user.userAchievements.nodes[0];
+
+Vue.use(VueApollo);
+
+describe('UserAchievements', () => {
+ let wrapper;
+
+ const getUserAchievementsQueryHandler = jest.fn().mockResolvedValue(getUserAchievementsResponse);
+ const achievement = () => wrapper.findByTestId('user-achievement');
+
+ const createComponent = ({ queryHandler = getUserAchievementsQueryHandler } = {}) => {
+ const fakeApollo = createMockApollo([[getUserAchievements, queryHandler]]);
+
+ wrapper = mountExtended(UserAchievements, {
+ apolloProvider: fakeApollo,
+ provide: {
+ rootUrl: ROOT_URL,
+ userId: USER_ID,
+ },
+ });
+ };
+
+ it('renders no achievements on reject', async () => {
+ createComponent({ queryHandler: jest.fn().mockRejectedValue('ERROR') });
+
+ await waitForPromises();
+
+ expect(wrapper.findAllByTestId('user-achievement').length).toBe(0);
+ });
+
+ it('renders no achievements when none are present', async () => {
+ createComponent({
+ queryHandler: jest.fn().mockResolvedValue(getUserAchievementsEmptyResponse),
+ });
+
+ await waitForPromises();
+
+ expect(wrapper.findAllByTestId('user-achievement').length).toBe(0);
+ });
+
+ it('only renders 3 achievements when more are present', async () => {
+ createComponent({ queryHandler: jest.fn().mockResolvedValue(getUserAchievementsLongResponse) });
+
+ await waitForPromises();
+
+ expect(wrapper.findAllByTestId('user-achievement').length).toBe(3);
+ });
+
+ it('renders achievement correctly', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(achievement().text()).toContain(userAchievement1.achievement.name);
+ expect(achievement().text()).toContain(
+ `Awarded ${timeagoMixin.methods.timeFormatted(userAchievement1.createdAt)} by`,
+ );
+ expect(achievement().text()).toContain(userAchievement1.achievement.namespace.fullPath);
+ expect(achievement().text()).toContain(userAchievement1.achievement.description);
+ expect(achievement().find('img').attributes('src')).toBe(
+ userAchievement1.achievement.avatarUrl,
+ );
+ });
+
+ it('renders a placeholder when no avatar is present', async () => {
+ gon.gitlab_logo = PLACEHOLDER_URL;
+ createComponent({
+ queryHandler: jest.fn().mockResolvedValue(getUserAchievementsNoAvatarResponse),
+ });
+
+ await waitForPromises();
+
+ expect(achievement().find('img').attributes('src')).toBe(PLACEHOLDER_URL);
+ });
+
+ it('does not render a description when none is present', async () => {
+ gon.gitlab_logo = PLACEHOLDER_URL;
+ createComponent({
+ queryHandler: jest.fn().mockResolvedValue(getUserAchievementsNoAvatarResponse),
+ });
+
+ await waitForPromises();
+
+ expect(wrapper.findAllByTestId('achievement-description').length).toBe(0);
+ });
+});
diff --git a/spec/frontend/profile/mock_data.js b/spec/frontend/profile/mock_data.js
new file mode 100644
index 00000000000..7106ea84619
--- /dev/null
+++ b/spec/frontend/profile/mock_data.js
@@ -0,0 +1,22 @@
+export const userCalendarResponse = {
+ '2022-11-18': 13,
+ '2022-11-19': 21,
+ '2022-11-20': 14,
+ '2022-11-21': 15,
+ '2022-11-22': 20,
+ '2022-11-23': 21,
+ '2022-11-24': 15,
+ '2022-11-25': 14,
+ '2022-11-26': 16,
+ '2022-11-27': 13,
+ '2022-11-28': 4,
+ '2022-11-29': 1,
+ '2022-11-30': 1,
+ '2022-12-13': 1,
+ '2023-01-10': 3,
+ '2023-01-11': 2,
+ '2023-01-20': 1,
+ '2023-02-02': 1,
+ '2023-02-06': 2,
+ '2023-02-07': 2,
+};
diff --git a/spec/frontend/profile/preferences/components/diffs_colors_preview_spec.js b/spec/frontend/profile/preferences/components/diffs_colors_preview_spec.js
index e60602ab336..e69bfad765a 100644
--- a/spec/frontend/profile/preferences/components/diffs_colors_preview_spec.js
+++ b/spec/frontend/profile/preferences/components/diffs_colors_preview_spec.js
@@ -12,11 +12,6 @@ describe('DiffsColorsPreview component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders diff colors preview', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/profile/preferences/components/diffs_colors_spec.js b/spec/frontend/profile/preferences/components/diffs_colors_spec.js
index 02f501a0b06..e80851d0629 100644
--- a/spec/frontend/profile/preferences/components/diffs_colors_spec.js
+++ b/spec/frontend/profile/preferences/components/diffs_colors_spec.js
@@ -29,11 +29,6 @@ describe('DiffsColors component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('mounts', () => {
createComponent();
diff --git a/spec/frontend/profile/preferences/components/integration_view_spec.js b/spec/frontend/profile/preferences/components/integration_view_spec.js
index f650bee7fda..b809f2f4aed 100644
--- a/spec/frontend/profile/preferences/components/integration_view_spec.js
+++ b/spec/frontend/profile/preferences/components/integration_view_spec.js
@@ -38,11 +38,6 @@ describe('IntegrationView component', () => {
const findHiddenField = () =>
wrapper.findByTestId('profile-preferences-integration-hidden-field');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render the form group legend correctly', () => {
wrapper = createComponent();
diff --git a/spec/frontend/profile/preferences/components/profile_preferences_spec.js b/spec/frontend/profile/preferences/components/profile_preferences_spec.js
index 91cd868daac..21167dccda9 100644
--- a/spec/frontend/profile/preferences/components/profile_preferences_spec.js
+++ b/spec/frontend/profile/preferences/components/profile_preferences_spec.js
@@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { createAlert, VARIANT_DANGER, VARIANT_INFO } from '~/flash';
+import { createAlert, VARIANT_DANGER, VARIANT_INFO } from '~/alert';
import IntegrationView from '~/profile/preferences/components/integration_view.vue';
import ProfilePreferences from '~/profile/preferences/components/profile_preferences.vue';
import { i18n } from '~/profile/preferences/constants';
@@ -17,7 +17,7 @@ import {
lightModeThemeId2,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const expectedUrl = '/foo';
useMockLocationHelper();
@@ -83,11 +83,6 @@ describe('ProfilePreferences component', () => {
document.body.classList.add('content-wrapper');
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should not render Integrations section', () => {
wrapper = createComponent();
const views = wrapper.findAllComponents(IntegrationView);
diff --git a/spec/frontend/profile/utils_spec.js b/spec/frontend/profile/utils_spec.js
new file mode 100644
index 00000000000..43537afe169
--- /dev/null
+++ b/spec/frontend/profile/utils_spec.js
@@ -0,0 +1,15 @@
+import { getVisibleCalendarPeriod } from '~/profile/utils';
+import { CALENDAR_PERIOD_12_MONTHS, CALENDAR_PERIOD_6_MONTHS } from '~/profile/constants';
+
+describe('getVisibleCalendarPeriod', () => {
+ it.each`
+ width | expected
+ ${1000} | ${CALENDAR_PERIOD_12_MONTHS}
+ ${900} | ${CALENDAR_PERIOD_6_MONTHS}
+ `('returns $expected when container width is $width', ({ width, expected }) => {
+ const container = document.createElement('div');
+ jest.spyOn(container, 'getBoundingClientRect').mockReturnValueOnce({ width });
+
+ expect(getVisibleCalendarPeriod(container)).toBe(expected);
+ });
+});
diff --git a/spec/frontend/projects/clusters_deprecation_slert/components/clusters_deprecation_alert_spec.js b/spec/frontend/projects/clusters_deprecation_slert/components/clusters_deprecation_alert_spec.js
index d230b96ad82..68ea3a4dc4d 100644
--- a/spec/frontend/projects/clusters_deprecation_slert/components/clusters_deprecation_alert_spec.js
+++ b/spec/frontend/projects/clusters_deprecation_slert/components/clusters_deprecation_alert_spec.js
@@ -26,10 +26,6 @@ describe('ClustersDeprecationAlert', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
it('should render a non-dismissible warning alert', () => {
expect(findAlert().props()).toMatchObject({
diff --git a/spec/frontend/projects/commit/components/branches_dropdown_spec.js b/spec/frontend/projects/commit/components/branches_dropdown_spec.js
index 6aa5a9a5a3a..0e68bd21cd4 100644
--- a/spec/frontend/projects/commit/components/branches_dropdown_spec.js
+++ b/spec/frontend/projects/commit/components/branches_dropdown_spec.js
@@ -12,7 +12,7 @@ describe('BranchesDropdown', () => {
let store;
const spyFetchBranches = jest.fn();
- const createComponent = (props, state = { isFetching: false }) => {
+ const createComponent = (props, state = { isFetching: false, branch: '_main_' }) => {
store = new Vuex.Store({
getters: {
joinedBranches: () => ['_main_', '_branch_1_', '_branch_2_'],
@@ -41,8 +41,6 @@ describe('BranchesDropdown', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
spyFetchBranches.mockReset();
});
diff --git a/spec/frontend/projects/commit/components/form_modal_spec.js b/spec/frontend/projects/commit/components/form_modal_spec.js
index c59cf700e0d..84cb30953c3 100644
--- a/spec/frontend/projects/commit/components/form_modal_spec.js
+++ b/spec/frontend/projects/commit/components/form_modal_spec.js
@@ -55,7 +55,6 @@ describe('CommitFormModal', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
});
@@ -166,7 +165,7 @@ describe('CommitFormModal', () => {
it('Changes the target_project_id input value', async () => {
createComponent(shallowMount, {}, {}, { isCherryPick: true });
- findProjectsDropdown().vm.$emit('selectProject', '_changed_project_value_');
+ findProjectsDropdown().vm.$emit('input', '_changed_project_value_');
await nextTick();
diff --git a/spec/frontend/projects/commit/components/projects_dropdown_spec.js b/spec/frontend/projects/commit/components/projects_dropdown_spec.js
index 0e213ff388a..baf2ea2656f 100644
--- a/spec/frontend/projects/commit/components/projects_dropdown_spec.js
+++ b/spec/frontend/projects/commit/components/projects_dropdown_spec.js
@@ -1,6 +1,6 @@
import { GlCollapsibleListbox } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import ProjectsDropdown from '~/projects/commit/components/projects_dropdown.vue';
@@ -38,7 +38,6 @@ describe('ProjectsDropdown', () => {
const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
afterEach(() => {
- wrapper.destroy();
spyFetchProjects.mockReset();
});
@@ -48,20 +47,24 @@ describe('ProjectsDropdown', () => {
});
describe('Custom events', () => {
- it('should emit selectProject if a project is clicked', () => {
+ it('should emit input if a project is clicked', () => {
findDropdown().vm.$emit('select', '1');
- expect(wrapper.emitted('selectProject')).toEqual([['1']]);
+ expect(wrapper.emitted('input')).toEqual([['1']]);
});
});
});
describe('Case insensitive for search term', () => {
beforeEach(() => {
- createComponent('_PrOjEcT_1_');
+ createComponent('_PrOjEcT_1_', { targetProjectId: '1' });
});
- it('renders only the project searched for', () => {
+ it('renders only the project searched for', async () => {
+ findDropdown().vm.$emit('search', '_project_1_');
+
+ await nextTick();
+
expect(findDropdown().props('items')).toEqual([{ text: '_project_1_', value: '1' }]);
});
});
diff --git a/spec/frontend/projects/commit/store/actions_spec.js b/spec/frontend/projects/commit/store/actions_spec.js
index 008710984b9..d48f9fd6fc0 100644
--- a/spec/frontend/projects/commit/store/actions_spec.js
+++ b/spec/frontend/projects/commit/store/actions_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { PROJECT_BRANCHES_ERROR } from '~/projects/commit/constants';
import * as actions from '~/projects/commit/store/actions';
@@ -8,7 +8,7 @@ import * as types from '~/projects/commit/store/mutation_types';
import getInitialState from '~/projects/commit/store/state';
import mockData from '../mock_data';
-jest.mock('~/flash.js');
+jest.mock('~/alert');
describe('Commit form modal store actions', () => {
let axiosMock;
@@ -63,7 +63,7 @@ describe('Commit form modal store actions', () => {
);
});
- it('should show flash error and set error in state on fetchBranches failure', async () => {
+ it('should show alert error and set error in state on fetchBranches failure', async () => {
jest.spyOn(axios, 'get').mockRejectedValue();
await testAction(actions.fetchBranches, {}, state, [], [{ type: 'requestBranches' }]);
diff --git a/spec/frontend/projects/commits/components/author_select_spec.js b/spec/frontend/projects/commits/components/author_select_spec.js
index 907e0e226b6..ff1d860fd53 100644
--- a/spec/frontend/projects/commits/components/author_select_spec.js
+++ b/spec/frontend/projects/commits/components/author_select_spec.js
@@ -54,7 +54,6 @@ describe('Author Select', () => {
});
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/projects/commits/store/actions_spec.js b/spec/frontend/projects/commits/store/actions_spec.js
index bae9c48fc1e..f5184e59420 100644
--- a/spec/frontend/projects/commits/store/actions_spec.js
+++ b/spec/frontend/projects/commits/store/actions_spec.js
@@ -1,13 +1,13 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import actions from '~/projects/commits/store/actions';
import * as types from '~/projects/commits/store/mutation_types';
import createState from '~/projects/commits/store/state';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Project commits actions', () => {
let state;
@@ -34,8 +34,8 @@ describe('Project commits actions', () => {
]));
});
- describe('shows a flash message when there is an error', () => {
- it('creates a flash', () => {
+ describe('shows an alert message when there is an error', () => {
+ it('creates an alert', () => {
const mockDispatchContext = { dispatch: () => {}, commit: () => {}, state };
actions.receiveAuthorsError(mockDispatchContext);
diff --git a/spec/frontend/projects/compare/components/app_spec.js b/spec/frontend/projects/compare/components/app_spec.js
index 9b052a17caa..ee96f46ea0c 100644
--- a/spec/frontend/projects/compare/components/app_spec.js
+++ b/spec/frontend/projects/compare/components/app_spec.js
@@ -21,11 +21,6 @@ describe('CompareApp component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
beforeEach(() => {
createComponent();
});
diff --git a/spec/frontend/projects/compare/components/repo_dropdown_spec.js b/spec/frontend/projects/compare/components/repo_dropdown_spec.js
index 21cca857c6a..0b1085470b8 100644
--- a/spec/frontend/projects/compare/components/repo_dropdown_spec.js
+++ b/spec/frontend/projects/compare/components/repo_dropdown_spec.js
@@ -16,11 +16,6 @@ describe('RepoDropdown component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findGlDropdown = () => wrapper.findComponent(GlDropdown);
const findHiddenInput = () => wrapper.find('input[type="hidden"]');
diff --git a/spec/frontend/projects/compare/components/revision_card_spec.js b/spec/frontend/projects/compare/components/revision_card_spec.js
index b23bd91ceda..3c9c61c8903 100644
--- a/spec/frontend/projects/compare/components/revision_card_spec.js
+++ b/spec/frontend/projects/compare/components/revision_card_spec.js
@@ -16,11 +16,6 @@ describe('RepoDropdown component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
beforeEach(() => {
createComponent();
});
diff --git a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
index 53763bd7d8f..645d0483a5f 100644
--- a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
+++ b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
@@ -1,8 +1,8 @@
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
-import { createAlert } from '~/flash';
+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';
@@ -14,7 +14,7 @@ const defaultProps = {
paramsBranch: 'main',
};
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('RevisionDropdown component', () => {
let wrapper;
@@ -35,11 +35,14 @@ describe('RevisionDropdown component', () => {
});
afterEach(() => {
- wrapper.destroy();
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(
@@ -58,10 +61,21 @@ describe('RevisionDropdown component', () => {
createComponent();
- await axios.waitForAll();
+ expect(findBranchesDropdownItem()).toHaveLength(0);
+ expect(findTagsDropdownItem()).toHaveLength(0);
- expect(wrapper.vm.branches).toEqual(Branches);
- expect(wrapper.vm.tags).toEqual(Tags);
+ 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 () => {
@@ -70,16 +84,17 @@ describe('RevisionDropdown component', () => {
Tags: undefined,
});
- await axios.waitForAll();
+ await waitForPromises();
- expect(wrapper.vm.branches).toEqual([]);
- expect(wrapper.vm.tags).toEqual([]);
+ expect(findBranchesDropdownItem()).toHaveLength(0);
+ expect(findTagsDropdownItem()).toHaveLength(0);
});
- it('shows flash message on error', async () => {
+ it('shows alert message on error', async () => {
axiosMock.onGet('some/invalid/path').replyOnce(HTTP_STATUS_NOT_FOUND);
- await wrapper.vm.fetchBranchesAndTags();
+ await waitForPromises();
+
expect(createAlert).toHaveBeenCalled();
});
@@ -102,17 +117,19 @@ describe('RevisionDropdown component', () => {
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';
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ branches: ['some-branch'] });
+ axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(HTTP_STATUS_OK, {
+ Branches: [branchName],
+ });
- await nextTick();
+ createComponent();
+ await waitForPromises();
findFirstGlDropdownItem().vm.$emit('click');
expect(wrapper.emitted()).toEqual({
- selectRevision: [[{ direction: 'from', revision: 'some-branch' }]],
+ selectRevision: [[{ direction: 'from', revision: branchName }]],
});
});
});
diff --git a/spec/frontend/projects/compare/components/revision_dropdown_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_spec.js
index db4a1158996..3a256682549 100644
--- a/spec/frontend/projects/compare/components/revision_dropdown_spec.js
+++ b/spec/frontend/projects/compare/components/revision_dropdown_spec.js
@@ -2,13 +2,14 @@ import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
-import { createAlert } from '~/flash';
+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.vue';
import { revisionDropdownDefaultProps as defaultProps } from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('RevisionDropdown component', () => {
let wrapper;
@@ -32,12 +33,15 @@ describe('RevisionDropdown component', () => {
});
afterEach(() => {
- wrapper.destroy();
axiosMock.restore();
});
const findGlDropdown = () => wrapper.findComponent(GlDropdown);
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findBranchesDropdownItem = () =>
+ wrapper.findAllComponents('[data-testid="branches-dropdown-item"]');
+ const findTagsDropdownItem = () =>
+ wrapper.findAllComponents('[data-testid="tags-dropdown-item"]');
it('sets hidden input', () => {
createComponent();
@@ -57,17 +61,29 @@ describe('RevisionDropdown component', () => {
createComponent();
- await axios.waitForAll();
- expect(wrapper.vm.branches).toEqual(Branches);
- expect(wrapper.vm.tags).toEqual(Tags);
+ expect(findBranchesDropdownItem()).toHaveLength(0);
+ expect(findTagsDropdownItem()).toHaveLength(0);
+
+ await waitForPromises();
+
+ expect(findBranchesDropdownItem()).toHaveLength(Branches.length);
+ expect(findTagsDropdownItem()).toHaveLength(Tags.length);
+
+ Branches.forEach((branch, index) => {
+ expect(findBranchesDropdownItem().at(index).text()).toBe(branch);
+ });
+
+ Tags.forEach((tag, index) => {
+ expect(findTagsDropdownItem().at(index).text()).toBe(tag);
+ });
});
- it('shows flash message on error', async () => {
+ it('shows alert message on error', async () => {
axiosMock.onGet('some/invalid/path').replyOnce(HTTP_STATUS_NOT_FOUND);
createComponent();
+ await waitForPromises();
- await wrapper.vm.fetchBranchesAndTags();
expect(createAlert).toHaveBeenCalled();
});
@@ -83,17 +99,17 @@ describe('RevisionDropdown component', () => {
refsProjectPath: newRefsProjectPath,
});
- await axios.waitForAll();
+ await waitForPromises();
expect(axios.get).toHaveBeenLastCalledWith(newRefsProjectPath);
});
describe('search', () => {
- it('shows flash message on error', async () => {
+ it('shows alert message on error', async () => {
axiosMock.onGet('some/invalid/path').replyOnce(HTTP_STATUS_NOT_FOUND);
createComponent();
+ await waitForPromises();
- await wrapper.vm.searchBranchesAndTags();
expect(createAlert).toHaveBeenCalled();
});
@@ -108,7 +124,7 @@ describe('RevisionDropdown component', () => {
const mockSearchTerm = 'foobar';
createComponent();
findSearchBox().vm.$emit('input', mockSearchTerm);
- await axios.waitForAll();
+ await waitForPromises();
expect(axios.get).toHaveBeenCalledWith(
defaultProps.refsProjectPath,
@@ -141,8 +157,14 @@ describe('RevisionDropdown component', () => {
});
it('emits `selectRevision` event when another revision is selected', async () => {
+ jest.spyOn(axios, 'get').mockResolvedValue({
+ data: {
+ Branches: ['some-branch'],
+ Tags: [],
+ },
+ });
+
createComponent();
- wrapper.vm.branches = ['some-branch'];
await nextTick();
findGlDropdown().findAllComponents(GlDropdownItem).at(0).vm.$emit('click');
diff --git a/spec/frontend/projects/components/project_delete_button_spec.js b/spec/frontend/projects/components/project_delete_button_spec.js
index 49e3218e5bc..bae76e7eeb6 100644
--- a/spec/frontend/projects/components/project_delete_button_spec.js
+++ b/spec/frontend/projects/components/project_delete_button_spec.js
@@ -33,11 +33,6 @@ describe('Project remove modal', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('initialized', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/projects/components/shared/delete_button_spec.js b/spec/frontend/projects/components/shared/delete_button_spec.js
index 097b18025a3..364a29d0e41 100644
--- a/spec/frontend/projects/components/shared/delete_button_spec.js
+++ b/spec/frontend/projects/components/shared/delete_button_spec.js
@@ -45,11 +45,6 @@ describe('Project remove modal', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('intialized', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/projects/details/upload_button_spec.js b/spec/frontend/projects/details/upload_button_spec.js
index 50638755260..e9b11ce544a 100644
--- a/spec/frontend/projects/details/upload_button_spec.js
+++ b/spec/frontend/projects/details/upload_button_spec.js
@@ -27,10 +27,6 @@ describe('UploadButton', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays an upload button', () => {
expect(wrapper.findComponent(GlButton).exists()).toBe(true);
});
diff --git a/spec/frontend/projects/new/components/app_spec.js b/spec/frontend/projects/new/components/app_spec.js
index f6edbab3cca..5b2dc25077e 100644
--- a/spec/frontend/projects/new/components/app_spec.js
+++ b/spec/frontend/projects/new/components/app_spec.js
@@ -6,12 +6,12 @@ describe('Experimental new project creation app', () => {
let wrapper;
const createComponent = (propsData) => {
- wrapper = shallowMount(App, { propsData });
+ wrapper = shallowMount(App, {
+ propsData: { projectsUrl: '/dashboard/projects', ...propsData },
+ });
};
- afterEach(() => {
- wrapper.destroy();
- });
+ const findNewNamespacePage = () => wrapper.findComponent(NewNamespacePage);
it('passes custom new project guideline text to underlying component', () => {
const DEMO_GUIDELINES = 'Demo guidelines';
@@ -34,11 +34,28 @@ describe('Experimental new project creation app', () => {
expect(
Boolean(
- wrapper
- .findComponent(NewNamespacePage)
+ findNewNamespacePage()
.props()
.panels.find((p) => p.name === 'cicd_for_external_repo'),
),
).toBe(isCiCdAvailable);
});
+
+ it('creates correct breadcrumbs for top-level projects', () => {
+ createComponent();
+
+ expect(findNewNamespacePage().props('initialBreadcrumbs')).toEqual([
+ { href: '/dashboard/projects', text: 'Projects' },
+ { href: '#', text: 'New project' },
+ ]);
+ });
+
+ it('creates correct breadcrumbs for projects within groups', () => {
+ createComponent({ parentGroupUrl: '/parent-group', parentGroupName: 'Parent Group' });
+
+ expect(findNewNamespacePage().props('initialBreadcrumbs')).toEqual([
+ { href: '/parent-group', text: 'Parent Group' },
+ { href: '#', text: 'New project' },
+ ]);
+ });
});
diff --git a/spec/frontend/projects/new/components/deployment_target_select_spec.js b/spec/frontend/projects/new/components/deployment_target_select_spec.js
index f3b22d4a1b9..bec738f7765 100644
--- a/spec/frontend/projects/new/components/deployment_target_select_spec.js
+++ b/spec/frontend/projects/new/components/deployment_target_select_spec.js
@@ -47,7 +47,6 @@ describe('Deployment target select', () => {
});
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js b/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js
index 16b4493c622..1a43dcb682b 100644
--- a/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js
+++ b/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js
@@ -37,7 +37,6 @@ describe('New project push tip popover', () => {
});
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/projects/new/components/new_project_url_select_spec.js b/spec/frontend/projects/new/components/new_project_url_select_spec.js
index 67532cea61e..fa720f4487c 100644
--- a/spec/frontend/projects/new/components/new_project_url_select_spec.js
+++ b/spec/frontend/projects/new/components/new_project_url_select_spec.js
@@ -3,8 +3,8 @@ import {
GlDropdown,
GlDropdownItem,
GlDropdownSectionHeader,
- GlSearchBoxByType,
GlTruncate,
+ GlSearchBoxByType,
} from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
@@ -12,6 +12,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { stubComponent } from 'helpers/stub_component';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import eventHub from '~/projects/new/event_hub';
import NewProjectUrlSelect from '~/projects/new/components/new_project_url_select.vue';
@@ -68,6 +69,7 @@ describe('NewProjectUrlSelect component', () => {
};
let mockQueryResponse;
+ let focusInputSpy;
const mountComponent = ({
search = '',
@@ -78,6 +80,7 @@ describe('NewProjectUrlSelect component', () => {
mockQueryResponse = jest.fn().mockResolvedValue({ data: queryResponse });
const requestHandlers = [[searchQuery, mockQueryResponse]];
const apolloProvider = createMockApollo(requestHandlers);
+ focusInputSpy = jest.fn();
return mountFn(NewProjectUrlSelect, {
apolloProvider,
@@ -87,13 +90,17 @@ describe('NewProjectUrlSelect component', () => {
search,
};
},
+ stubs: {
+ GlSearchBoxByType: stubComponent(GlSearchBoxByType, {
+ methods: { focusInput: focusInputSpy },
+ }),
+ },
});
};
const findButtonLabel = () => wrapper.findComponent(GlButton);
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findSelectedPath = () => wrapper.findComponent(GlTruncate);
- const findInput = () => wrapper.findComponent(GlSearchBoxByType);
const findHiddenNamespaceInput = () => wrapper.find(`[name="${defaultProvide.inputName}`);
const findHiddenSelectedNamespaceInput = () =>
@@ -111,10 +118,6 @@ describe('NewProjectUrlSelect component', () => {
await waitForPromises();
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the root url as a label', () => {
wrapper = mountComponent();
@@ -177,13 +180,11 @@ describe('NewProjectUrlSelect component', () => {
});
it('focuses on the input when the dropdown is opened', async () => {
- wrapper = mountComponent({ mountFn: mount });
-
- const spy = jest.spyOn(findInput().vm, 'focusInput');
+ wrapper = mountComponent();
await showDropdown();
- expect(spy).toHaveBeenCalledTimes(1);
+ expect(focusInputSpy).toHaveBeenCalledTimes(1);
});
it('renders expected dropdown items', async () => {
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 fc51825f15b..1545c52d7cb 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
@@ -8,20 +8,19 @@ exports[`CiCdAnalyticsAreaChart matches the snapshot 1`] = `
Some title
</p>
- <div>
- <glareachart-stub
- annotations=""
- data="[object Object],[object Object]"
- height="300"
- legendaveragetext="Avg"
- legendcurrenttext="Current"
- legendlayout="inline"
- legendmaxtext="Max"
- legendmintext="Min"
- option="[object Object]"
- thresholds=""
- width="0"
- />
- </div>
+ <glareachart-stub
+ annotations=""
+ data="[object Object],[object Object]"
+ height="300"
+ legendaveragetext="Avg"
+ legendcurrenttext="Current"
+ legendlayout="inline"
+ legendmaxtext="Max"
+ legendmintext="Min"
+ option="[object Object]"
+ responsive=""
+ thresholds=""
+ width="auto"
+ />
</div>
`;
diff --git a/spec/frontend/projects/pipelines/charts/components/app_spec.js b/spec/frontend/projects/pipelines/charts/components/app_spec.js
index d8876349c5e..94f421239da 100644
--- a/spec/frontend/projects/pipelines/charts/components/app_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/app_spec.js
@@ -49,10 +49,6 @@ describe('ProjectsPipelinesChartsApp', () => {
);
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlTabs = () => wrapper.findComponent(GlTabs);
const findAllGlTabs = () => wrapper.findAllComponents(GlTab);
const findGlTabAtIndex = (index) => findAllGlTabs().at(index);
diff --git a/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_area_chart_spec.js b/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_area_chart_spec.js
index 2b523467379..5fc121b5c9f 100644
--- a/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_area_chart_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_area_chart_spec.js
@@ -28,11 +28,6 @@ describe('CiCdAnalyticsAreaChart', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
index 8fb59f38ee1..ab2a12219e5 100644
--- a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js
@@ -37,11 +37,6 @@ describe('~/projects/pipelines/charts/components/pipeline_charts.vue', () => {
await waitForPromises();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('overall statistics', () => {
it('displays the statistics list', () => {
const list = wrapper.findComponent(StatisticsList);
diff --git a/spec/frontend/projects/pipelines/charts/components/statistics_list_spec.js b/spec/frontend/projects/pipelines/charts/components/statistics_list_spec.js
index 57a864cb2c4..24dbc628ce6 100644
--- a/spec/frontend/projects/pipelines/charts/components/statistics_list_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/statistics_list_spec.js
@@ -21,10 +21,6 @@ describe('StatisticsList', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays the counts data with labels', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/projects/prune_unreachable_objects_button_spec.js b/spec/frontend/projects/prune_unreachable_objects_button_spec.js
index b345f264ca7..012b19ea3d3 100644
--- a/spec/frontend/projects/prune_unreachable_objects_button_spec.js
+++ b/spec/frontend/projects/prune_unreachable_objects_button_spec.js
@@ -22,16 +22,11 @@ describe('Project remove modal', () => {
wrapper = shallowMountExtended(PruneObjectsButton, {
propsData: defaultProps,
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-modal'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('intialized', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js
index 11f219c1f90..6d3317a5f78 100644
--- a/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js
@@ -8,10 +8,10 @@ import BranchDropdown, {
import createMockApollo from 'helpers/mock_apollo_helper';
import branchesQuery from '~/projects/settings/branch_rules/queries/branches.query.graphql';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Branch dropdown', () => {
let wrapper;
@@ -46,10 +46,6 @@ describe('Branch dropdown', () => {
beforeEach(() => createComponent());
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a GlDropdown component with the correct props', () => {
expect(findGlDropdown().props()).toMatchObject({ text: value });
});
diff --git a/spec/frontend/projects/settings/branch_rules/components/edit/index_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/index_spec.js
index 21e63fdb24d..e9982872e03 100644
--- a/spec/frontend/projects/settings/branch_rules/components/edit/index_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/index_spec.js
@@ -24,10 +24,6 @@ describe('Edit branch rule', () => {
beforeEach(() => createComponent());
- afterEach(() => {
- wrapper.destroy();
- });
-
it('gets the branch param from url', () => {
expect(getParameterByName).toHaveBeenCalledWith('branch');
});
diff --git a/spec/frontend/projects/settings/branch_rules/components/edit/protections/index_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/protections/index_spec.js
index ee90ff8318f..14edaf31a1f 100644
--- a/spec/frontend/projects/settings/branch_rules/components/edit/protections/index_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/protections/index_spec.js
@@ -26,10 +26,6 @@ describe('Branch Protections', () => {
beforeEach(() => createComponent());
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a heading', () => {
expect(findHeading().text()).toBe(i18n.protections);
});
diff --git a/spec/frontend/projects/settings/branch_rules/components/edit/protections/merge_protections_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/protections/merge_protections_spec.js
index b5fdc46d600..ca561ef87ec 100644
--- a/spec/frontend/projects/settings/branch_rules/components/edit/protections/merge_protections_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/protections/merge_protections_spec.js
@@ -24,10 +24,6 @@ describe('Merge Protections', () => {
beforeEach(() => createComponent());
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a form group with the correct label', () => {
expect(findFormGroup().text()).toContain(i18n.allowedToMerge);
});
diff --git a/spec/frontend/projects/settings/branch_rules/components/edit/protections/push_protections_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/protections/push_protections_spec.js
index 60bb7a51dcb..82998640f17 100644
--- a/spec/frontend/projects/settings/branch_rules/components/edit/protections/push_protections_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/edit/protections/push_protections_spec.js
@@ -24,10 +24,6 @@ describe('Push Protections', () => {
beforeEach(() => createComponent());
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a form group with the correct label', () => {
expect(findFormGroup().attributes('label')).toBe(i18n.allowedToPush);
});
diff --git a/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js
index 714e0df596e..077995ab6e4 100644
--- a/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js
@@ -9,6 +9,10 @@ import Protection from '~/projects/settings/branch_rules/components/view/protect
import {
I18N,
ALL_BRANCHES_WILDCARD,
+ REQUIRED_ICON,
+ NOT_REQUIRED_ICON,
+ REQUIRED_ICON_CLASS,
+ NOT_REQUIRED_ICON_CLASS,
} from '~/projects/settings/branch_rules/components/view/constants';
import branchRulesQuery from 'ee_else_ce/projects/settings/branch_rules/queries/branch_rules_details.query.graphql';
import { sprintf } from '~/locale';
@@ -19,7 +23,7 @@ import {
jest.mock('~/lib/utils/url_utility', () => ({
getParameterByName: jest.fn().mockReturnValue('main'),
- mergeUrlParams: jest.fn().mockReturnValue('/branches?state=all&search=main'),
+ mergeUrlParams: jest.fn().mockReturnValue('/branches?state=all&search=%5Emain%24'),
joinPaths: jest.fn(),
}));
@@ -39,12 +43,13 @@ describe('View branch rules', () => {
let fakeApollo;
const projectPath = 'test/testing';
const protectedBranchesPath = 'protected/branches';
- const branchProtectionsMockRequestHandler = jest
- .fn()
- .mockResolvedValue(branchProtectionsMockResponse);
+ const branchProtectionsMockRequestHandler = (response = branchProtectionsMockResponse) =>
+ jest.fn().mockResolvedValue(response);
- const createComponent = async () => {
- fakeApollo = createMockApollo([[branchRulesQuery, branchProtectionsMockRequestHandler]]);
+ const createComponent = async (mockResponse) => {
+ fakeApollo = createMockApollo([
+ [branchRulesQuery, branchProtectionsMockRequestHandler(mockResponse)],
+ ]);
wrapper = shallowMountExtended(RuleView, {
apolloProvider: fakeApollo,
@@ -57,13 +62,13 @@ describe('View branch rules', () => {
beforeEach(() => createComponent());
- afterEach(() => wrapper.destroy());
-
const findBranchName = () => wrapper.findByTestId('branch');
const findBranchTitle = () => wrapper.findByTestId('branch-title');
const findBranchProtectionTitle = () => wrapper.findByText(I18N.protectBranchTitle);
const findBranchProtections = () => wrapper.findAllComponents(Protection);
- const findForcePushTitle = () => wrapper.findByText(I18N.allowForcePushDescription);
+ const findForcePushIcon = () => wrapper.findByTestId('force-push-icon');
+ const findForcePushTitle = (title) => wrapper.findByText(title);
+ const findForcePushDescription = () => wrapper.findByText(I18N.forcePushDescription);
const findApprovalsTitle = () => wrapper.findByText(I18N.approvalsTitle);
const findStatusChecksTitle = () => wrapper.findByText(I18N.statusChecksTitle);
const findMatchingBranchesLink = () =>
@@ -94,9 +99,12 @@ describe('View branch rules', () => {
});
it('renders matching branches link', () => {
+ const mergeUrlParams = jest.spyOn(util, 'mergeUrlParams');
const matchingBranchesLink = findMatchingBranchesLink();
+
+ expect(mergeUrlParams).toHaveBeenCalledWith({ state: 'all', search: `^main$` }, '');
expect(matchingBranchesLink.exists()).toBe(true);
- expect(matchingBranchesLink.attributes().href).toBe('/branches?state=all&search=main');
+ expect(matchingBranchesLink.attributes().href).toBe('/branches?state=all&search=%5Emain%24');
});
it('renders a branch protection title', () => {
@@ -123,9 +131,23 @@ describe('View branch rules', () => {
});
});
- it('renders force push protection', () => {
- expect(findForcePushTitle().exists()).toBe(true);
- });
+ it.each`
+ allowForcePush | iconName | iconClass | title
+ ${true} | ${REQUIRED_ICON} | ${REQUIRED_ICON_CLASS} | ${I18N.allowForcePushTitle}
+ ${false} | ${NOT_REQUIRED_ICON} | ${NOT_REQUIRED_ICON_CLASS} | ${I18N.doesNotAllowForcePushTitle}
+ `(
+ 'renders force push section with the correct icon, title and description',
+ async ({ allowForcePush, iconName, iconClass, title }) => {
+ const mockResponse = branchProtectionsMockResponse;
+ mockResponse.data.project.branchRules.nodes[0].branchProtection.allowForcePush = allowForcePush;
+ await createComponent(mockResponse);
+
+ expect(findForcePushIcon().props('name')).toBe(iconName);
+ expect(findForcePushIcon().attributes('class')).toBe(iconClass);
+ expect(findForcePushTitle(title).exists()).toBe(true);
+ expect(findForcePushDescription().exists()).toBe(true);
+ },
+ );
it('renders a branch protection component for merge rules', () => {
expect(findBranchProtections().at(1).props()).toMatchObject({
diff --git a/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js
index a98b156f94e..1bfd04e10a1 100644
--- a/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js
@@ -18,8 +18,6 @@ describe('Branch rule protection row', () => {
beforeEach(() => createComponent());
- afterEach(() => wrapper.destroy());
-
const findTitle = () => wrapper.findByText(protectionRowPropsMock.title);
const findAvatarsInline = () => wrapper.findComponent(GlAvatarsInline);
const findAvatarLinks = () => wrapper.findAllComponents(GlAvatarLink);
diff --git a/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js
index caf967b4257..f10d8d6d770 100644
--- a/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js
+++ b/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js
@@ -16,8 +16,6 @@ describe('Branch rule protection', () => {
beforeEach(() => createComponent());
- afterEach(() => wrapper.destroy());
-
const findCard = () => wrapper.findComponent(GlCard);
const findHeader = () => wrapper.findByText(protectionPropsMock.header);
const findLink = () => wrapper.findComponent(GlLink);
diff --git a/spec/frontend/projects/settings/components/default_branch_selector_spec.js b/spec/frontend/projects/settings/components/default_branch_selector_spec.js
index ca9a72663d2..c1412d01b53 100644
--- a/spec/frontend/projects/settings/components/default_branch_selector_spec.js
+++ b/spec/frontend/projects/settings/components/default_branch_selector_spec.js
@@ -19,10 +19,6 @@ describe('projects/settings/components/default_branch_selector', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
buildWrapper();
});
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 26297d0c3ff..f3e536de703 100644
--- a/spec/frontend/projects/settings/components/new_access_dropdown_spec.js
+++ b/spec/frontend/projects/settings/components/new_access_dropdown_spec.js
@@ -89,15 +89,12 @@ describe('Access Level Dropdown', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findDropdownToggleLabel = () => findDropdown().props('text');
const findAllDropdownItems = () => findDropdown().findAllComponents(GlDropdownItem);
const findAllDropdownHeaders = () => findDropdown().findAllComponents(GlDropdownSectionHeader);
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findDeployKeyDropdownItem = () => wrapper.findByTestId('deploy_key-dropdown-item');
const findDropdownItemWithText = (items, text) =>
items.filter((item) => item.text().includes(text)).at(0);
@@ -142,6 +139,21 @@ describe('Access Level Dropdown', () => {
it('renders dropdown item for each access level type', () => {
expect(findAllDropdownItems()).toHaveLength(12);
});
+
+ it.each`
+ accessLevel | shouldRenderDeployKeyItems
+ ${ACCESS_LEVELS.PUSH} | ${true}
+ ${ACCESS_LEVELS.CREATE} | ${true}
+ ${ACCESS_LEVELS.MERGE} | ${false}
+ `(
+ 'conditionally renders deploy keys based on access levels',
+ async ({ accessLevel, shouldRenderDeployKeyItems }) => {
+ createComponent({ accessLevel });
+ await waitForPromises();
+
+ expect(findDeployKeyDropdownItem().exists()).toBe(shouldRenderDeployKeyItems);
+ },
+ );
});
describe('toggleLabel', () => {
diff --git a/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js b/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js
index f82ad80135e..0ec0e981d65 100644
--- a/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js
+++ b/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js
@@ -9,7 +9,7 @@ import SharedRunnersToggleComponent from '~/projects/settings/components/shared_
const TEST_UPDATE_PATH = '/test/update_shared_runners';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('projects/settings/components/shared_runners', () => {
let wrapper;
@@ -41,8 +41,6 @@ describe('projects/settings/components/shared_runners', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
mockAxios.restore();
});
diff --git a/spec/frontend/projects/settings/components/transfer_project_form_spec.js b/spec/frontend/projects/settings/components/transfer_project_form_spec.js
index e091f3e25c3..d8c2cf83f38 100644
--- a/spec/frontend/projects/settings/components/transfer_project_form_spec.js
+++ b/spec/frontend/projects/settings/components/transfer_project_form_spec.js
@@ -31,10 +31,6 @@ describe('Transfer project form', () => {
const findTransferLocations = () => wrapper.findComponent(TransferLocations);
const findConfirmDanger = () => wrapper.findComponent(ConfirmDanger);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the namespace selector and passes `groupTransferLocationsApiMethod` prop', () => {
createComponent();
diff --git a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js
index 56b39f04580..dd534bec25d 100644
--- a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js
+++ b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js
@@ -7,7 +7,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
import BranchRules from '~/projects/settings/repository/branch_rules/app.vue';
import BranchRule from '~/projects/settings/repository/branch_rules/components/branch_rule.vue';
import branchRulesQuery from 'ee_else_ce/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import {
branchRulesMockResponse,
appProvideMock,
@@ -22,7 +22,7 @@ import { expandSection } from '~/settings_panels';
import { scrollToElement } from '~/lib/utils/common_utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/settings_panels');
jest.mock('~/lib/utils/common_utils');
@@ -41,7 +41,7 @@ describe('Branch rules app', () => {
apolloProvider: fakeApollo,
provide: appProvideMock,
stubs: { GlModal: stubComponent(GlModal, { template: RENDER_ALL_SLOTS_TEMPLATE }) },
- directives: { GlModal: createMockDirective() },
+ directives: { GlModal: createMockDirective('gl-modal') },
});
await waitForPromises();
diff --git a/spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js b/spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js
index 8d0fd390e35..8bea84f4429 100644
--- a/spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js
+++ b/spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js
@@ -71,8 +71,10 @@ describe('Branch rule', () => {
});
it('renders a detail button with the correct href', () => {
+ const encodedBranchName = encodeURIComponent(branchRulePropsMock.name);
+
expect(findDetailsButton().attributes('href')).toBe(
- `${branchRuleProvideMock.branchRulesPath}?branch=${branchRulePropsMock.name}`,
+ `${branchRuleProvideMock.branchRulesPath}?branch=${encodedBranchName}`,
);
});
});
diff --git a/spec/frontend/projects/settings/repository/branch_rules/mock_data.js b/spec/frontend/projects/settings/repository/branch_rules/mock_data.js
index de7f6c8b88d..d169397241d 100644
--- a/spec/frontend/projects/settings/repository/branch_rules/mock_data.js
+++ b/spec/frontend/projects/settings/repository/branch_rules/mock_data.js
@@ -74,7 +74,7 @@ export const branchRuleProvideMock = {
};
export const branchRulePropsMock = {
- name: 'main',
+ name: 'branch-with-$speci@l-#-chars',
isDefault: true,
matchingBranchesCount: 1,
branchProtection: {
diff --git a/spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js b/spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js
index 8b8e7d1454d..4b94c179f74 100644
--- a/spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js
+++ b/spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js
@@ -64,7 +64,6 @@ describe('TopicsTokenSelector', () => {
});
afterEach(() => {
- wrapper.destroy();
div.remove();
input.remove();
});
diff --git a/spec/frontend/projects/settings/utils_spec.js b/spec/frontend/projects/settings/utils_spec.js
index 319aa4000b5..d85f43778b1 100644
--- a/spec/frontend/projects/settings/utils_spec.js
+++ b/spec/frontend/projects/settings/utils_spec.js
@@ -1,4 +1,5 @@
-import { getAccessLevels } from '~/projects/settings/utils';
+import { getAccessLevels, generateRefDestinationPath } from '~/projects/settings/utils';
+import setWindowLocation from 'helpers/set_window_location_helper';
import { pushAccessLevelsMockResponse, pushAccessLevelsMockResult } from './mock_data';
describe('Utils', () => {
@@ -8,4 +9,25 @@ describe('Utils', () => {
expect(pushAccessLevels).toEqual(pushAccessLevelsMockResult);
});
});
+
+ describe('generateRefDestinationPath', () => {
+ const projectRootPath = 'http://test.host/root/Project1';
+ const settingsCi = '-/settings/ci_cd';
+
+ it.each`
+ currentPath | selectedRef | result
+ ${`${projectRootPath}`} | ${undefined} | ${`${projectRootPath}`}
+ ${`${projectRootPath}`} | ${'test'} | ${`${projectRootPath}`}
+ ${`${projectRootPath}/${settingsCi}`} | ${'test'} | ${`${projectRootPath}/${settingsCi}?ref=test`}
+ ${`${projectRootPath}/${settingsCi}`} | ${'branch-hyphen'} | ${`${projectRootPath}/${settingsCi}?ref=branch-hyphen`}
+ ${`${projectRootPath}/${settingsCi}`} | ${'test/branch'} | ${`${projectRootPath}/${settingsCi}?ref=test%2Fbranch`}
+ ${`${projectRootPath}/${settingsCi}`} | ${'test/branch-hyphen'} | ${`${projectRootPath}/${settingsCi}?ref=test%2Fbranch-hyphen`}
+ `(
+ 'generates the correct destination path for the `$selectedRef` ref and current url $currentPath by outputting $result',
+ ({ currentPath, selectedRef, result }) => {
+ setWindowLocation(currentPath);
+ expect(generateRefDestinationPath(selectedRef)).toBe(result);
+ },
+ );
+ });
});
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
index 5fc9f9ba629..4d0d2191176 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
@@ -41,7 +41,6 @@ describe('ServiceDeskRoot', () => {
afterEach(() => {
axiosMock.restore();
- wrapper.destroy();
if (spy) {
spy.mockRestore();
}
diff --git a/spec/frontend/projects/terraform_notification/terraform_notification_spec.js b/spec/frontend/projects/terraform_notification/terraform_notification_spec.js
index 6576ce70d60..1d0faebbcb2 100644
--- a/spec/frontend/projects/terraform_notification/terraform_notification_spec.js
+++ b/spec/frontend/projects/terraform_notification/terraform_notification_spec.js
@@ -41,10 +41,6 @@ describe('TerraformNotificationBanner', () => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when user has already dismissed the banner', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/protected_branches/protected_branch_edit_spec.js b/spec/frontend/protected_branches/protected_branch_edit_spec.js
index b4029d94980..4141d000a1c 100644
--- a/spec/frontend/protected_branches/protected_branch_edit_spec.js
+++ b/spec/frontend/protected_branches/protected_branch_edit_spec.js
@@ -2,12 +2,12 @@ import MockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'helpers/test_constants';
-import { createAlert } from '~/flash';
+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 ProtectedBranchEdit from '~/protected_branches/protected_branch_edit';
-jest.mock('~/flash');
+jest.mock('~/alert');
const TEST_URL = `${TEST_HOST}/url`;
const FORCE_PUSH_TOGGLE_TESTID = 'force-push-toggle';
@@ -149,7 +149,7 @@ describe('ProtectedBranchEdit', () => {
toggle.click();
});
- it('flashes error', async () => {
+ it('alerts error', async () => {
await axios.waitForAll();
expect(createAlert).toHaveBeenCalled();
diff --git a/spec/frontend/ref/components/__snapshots__/ref_selector_spec.js.snap b/spec/frontend/ref/components/__snapshots__/ref_selector_spec.js.snap
deleted file mode 100644
index 5053778369e..00000000000
--- a/spec/frontend/ref/components/__snapshots__/ref_selector_spec.js.snap
+++ /dev/null
@@ -1,80 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Ref selector component footer slot passes the expected slot props 1`] = `
-Object {
- "isLoading": false,
- "matches": Object {
- "branches": Object {
- "error": null,
- "list": Array [
- Object {
- "default": false,
- "name": "add_images_and_changes",
- "value": undefined,
- },
- Object {
- "default": false,
- "name": "conflict-contains-conflict-markers",
- "value": undefined,
- },
- Object {
- "default": false,
- "name": "deleted-image-test",
- "value": undefined,
- },
- Object {
- "default": false,
- "name": "diff-files-image-to-symlink",
- "value": undefined,
- },
- Object {
- "default": false,
- "name": "diff-files-symlink-to-image",
- "value": undefined,
- },
- Object {
- "default": false,
- "name": "markdown",
- "value": undefined,
- },
- Object {
- "default": true,
- "name": "master",
- "value": undefined,
- },
- ],
- "totalCount": 123,
- },
- "commits": Object {
- "error": null,
- "list": Array [
- Object {
- "name": "b83d6e39",
- "subtitle": "Merge branch 'branch-merged' into 'master'",
- "value": "b83d6e391c22777fca1ed3012fce84f633d7fed0",
- },
- ],
- "totalCount": 1,
- },
- "tags": Object {
- "error": null,
- "list": Array [
- Object {
- "name": "v1.1.1",
- "value": undefined,
- },
- Object {
- "name": "v1.1.0",
- "value": undefined,
- },
- Object {
- "name": "v1.0.0",
- "value": undefined,
- },
- ],
- "totalCount": 456,
- },
- },
- "query": "abcd1234",
-}
-`;
diff --git a/spec/frontend/ref/components/ref_selector_spec.js b/spec/frontend/ref/components/ref_selector_spec.js
index 40d3a291074..6b90827f9c2 100644
--- a/spec/frontend/ref/components/ref_selector_spec.js
+++ b/spec/frontend/ref/components/ref_selector_spec.js
@@ -4,9 +4,9 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { merge, last } from 'lodash';
import Vuex from 'vuex';
+import tags from 'test_fixtures/api/tags/tags.json';
import commit from 'test_fixtures/api/commits/commit.json';
import branches from 'test_fixtures/api/branches/branches.json';
-import tags from 'test_fixtures/api/tags/tags.json';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { trimText } from 'helpers/text_helper';
import {
@@ -33,6 +33,8 @@ describe('Ref selector component', () => {
const fixtures = { branches, tags, commit };
const projectId = '8';
+ const totalBranchesCount = 123;
+ const totalTagsCount = 456;
let wrapper;
let branchesApiCallSpy;
@@ -69,10 +71,14 @@ describe('Ref selector component', () => {
branchesApiCallSpy = jest
.fn()
- .mockReturnValue([HTTP_STATUS_OK, fixtures.branches, { [X_TOTAL_HEADER]: '123' }]);
+ .mockReturnValue([
+ HTTP_STATUS_OK,
+ fixtures.branches,
+ { [X_TOTAL_HEADER]: totalBranchesCount },
+ ]);
tagsApiCallSpy = jest
.fn()
- .mockReturnValue([HTTP_STATUS_OK, fixtures.tags, { [X_TOTAL_HEADER]: '456' }]);
+ .mockReturnValue([HTTP_STATUS_OK, fixtures.tags, { [X_TOTAL_HEADER]: totalTagsCount }]);
commitApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_OK, fixtures.commit]);
requestSpies = { branchesApiCallSpy, tagsApiCallSpy, commitApiCallSpy };
@@ -690,7 +696,46 @@ describe('Ref selector component', () => {
// is updated. For the sake of this test, we'll just test the last call, which
// represents the final state of the slot props.
const lastCallProps = last(createFooter.mock.calls)[0];
- expect(lastCallProps).toMatchSnapshot();
+ expect(lastCallProps.isLoading).toBe(false);
+ expect(lastCallProps.query).toBe('abcd1234');
+
+ const branchesList = fixtures.branches.map((branch) => {
+ return {
+ default: branch.default,
+ name: branch.name,
+ };
+ });
+
+ const commitsList = [
+ {
+ name: fixtures.commit.short_id,
+ subtitle: fixtures.commit.title,
+ value: fixtures.commit.id,
+ },
+ ];
+
+ const tagsList = fixtures.tags.map((tag) => {
+ return {
+ name: tag.name,
+ };
+ });
+
+ const expectedMatches = {
+ branches: {
+ list: branchesList,
+ totalCount: totalBranchesCount,
+ },
+ commits: {
+ list: commitsList,
+ totalCount: 1,
+ },
+ tags: {
+ list: tagsList,
+ totalCount: totalTagsCount,
+ },
+ };
+
+ expect(lastCallProps.matches).toMatchObject(expectedMatches);
});
});
});
diff --git a/spec/frontend/releases/components/app_edit_new_spec.js b/spec/frontend/releases/components/app_edit_new_spec.js
index bd61e4537f9..dcb6a3293a6 100644
--- a/spec/frontend/releases/components/app_edit_new_spec.js
+++ b/spec/frontend/releases/components/app_edit_new_spec.js
@@ -16,6 +16,7 @@ import AssetLinksForm from '~/releases/components/asset_links_form.vue';
import ConfirmDeleteModal from '~/releases/components/confirm_delete_modal.vue';
import { BACK_URL_PARAM } from '~/releases/constants';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+import { ValidationResult } from '~/lib/utils/ref_validator';
const originalRelease = originalOneReleaseForEditingQueryResponse.data.project.release;
const originalMilestones = originalRelease.milestones;
@@ -58,6 +59,7 @@ describe('Release edit/new component', () => {
assets: {
links: [],
},
+ tagNameValidation: new ValidationResult(),
}),
formattedReleaseNotes: () => 'these notes are formatted',
};
@@ -101,11 +103,6 @@ describe('Release edit/new component', () => {
release = convertOneReleaseGraphQLResponse(originalOneReleaseForEditingQueryResponse).data;
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findSubmitButton = () => wrapper.find('button[type=submit]');
const findForm = () => wrapper.find('form');
diff --git a/spec/frontend/releases/components/app_index_spec.js b/spec/frontend/releases/components/app_index_spec.js
index ef3bd5ca873..7a0e9fb7326 100644
--- a/spec/frontend/releases/components/app_index_spec.js
+++ b/spec/frontend/releases/components/app_index_spec.js
@@ -6,7 +6,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { historyPushState } from '~/lib/utils/common_utils';
import { sprintf, __ } from '~/locale';
import ReleasesIndexApp from '~/releases/components/app_index.vue';
@@ -20,7 +20,7 @@ import { deleteReleaseSessionKey } from '~/releases/util';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
let mockQueryParams;
jest.mock('~/lib/utils/common_utils', () => ({
@@ -114,7 +114,7 @@ describe('app_index.vue', () => {
const toDescription = (bool) => (bool ? 'does' : 'does not');
describe.each`
- description | singleResponseFn | fullResponseFn | loadingIndicator | emptyState | flashMessage | releaseCount | pagination
+ description | singleResponseFn | fullResponseFn | loadingIndicator | emptyState | alertMessage | releaseCount | pagination
${'both requests loading'} | ${getInProgressResponse} | ${getInProgressResponse} | ${true} | ${false} | ${false} | ${0} | ${false}
${'both requests failed'} | ${getErrorResponse} | ${getErrorResponse} | ${false} | ${false} | ${true} | ${0} | ${false}
${'both requests loaded'} | ${getSingleRequestLoadedResponse} | ${getFullRequestLoadedResponse} | ${false} | ${false} | ${false} | ${2} | ${true}
@@ -134,7 +134,7 @@ describe('app_index.vue', () => {
fullResponseFn,
loadingIndicator,
emptyState,
- flashMessage,
+ alertMessage,
releaseCount,
pagination,
}) => {
@@ -154,9 +154,9 @@ describe('app_index.vue', () => {
expect(findEmptyState().exists()).toBe(emptyState);
});
- it(`${toDescription(flashMessage)} show a flash message`, async () => {
+ it(`${toDescription(alertMessage)} show a flash message`, async () => {
await waitForPromises();
- if (flashMessage) {
+ if (alertMessage) {
expect(createAlert).toHaveBeenCalledWith({
message: ReleasesIndexApp.i18n.errorMessage,
captureError: true,
diff --git a/spec/frontend/releases/components/app_show_spec.js b/spec/frontend/releases/components/app_show_spec.js
index efe72e8000a..942280cb6a2 100644
--- a/spec/frontend/releases/components/app_show_spec.js
+++ b/spec/frontend/releases/components/app_show_spec.js
@@ -4,14 +4,14 @@ import VueApollo from 'vue-apollo';
import oneReleaseQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release.query.graphql.json';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { popCreateReleaseNotification } from '~/releases/release_notification_service';
import ReleaseShowApp from '~/releases/components/app_show.vue';
import ReleaseBlock from '~/releases/components/release_block.vue';
import ReleaseSkeletonLoader from '~/releases/components/release_skeleton_loader.vue';
import oneReleaseQuery from '~/releases/graphql/queries/one_release.query.graphql';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/releases/release_notification_service');
Vue.use(VueApollo);
@@ -33,11 +33,6 @@ describe('Release show component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findLoadingSkeleton = () => wrapper.findComponent(ReleaseSkeletonLoader);
const findReleaseBlock = () => wrapper.findComponent(ReleaseBlock);
@@ -54,13 +49,13 @@ describe('Release show component', () => {
};
const expectNoFlash = () => {
- it('does not show a flash message', () => {
+ it('does not show an alert message', () => {
expect(createAlert).not.toHaveBeenCalled();
});
};
const expectFlashWithMessage = (message) => {
- it(`shows a flash message that reads "${message}"`, () => {
+ it(`shows an alert message that reads "${message}"`, () => {
expect(createAlert).toHaveBeenCalledWith({
message,
captureError: true,
@@ -152,7 +147,7 @@ describe('Release show component', () => {
beforeEach(async () => {
// As we return a release as `null`, Apollo also throws an error to the console
// about the missing field. We need to suppress console.error in order to check
- // that flash message was called
+ // that alert message was called
// eslint-disable-next-line no-console
console.error = jest.fn();
diff --git a/spec/frontend/releases/components/asset_links_form_spec.js b/spec/frontend/releases/components/asset_links_form_spec.js
index b1e9d8d1256..8eee9acd808 100644
--- a/spec/frontend/releases/components/asset_links_form_spec.js
+++ b/spec/frontend/releases/components/asset_links_form_spec.js
@@ -60,11 +60,6 @@ describe('Release edit component', () => {
release = commonUtils.convertObjectPropsToCamelCase(originalRelease, { deep: true });
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('with a basic store state', () => {
beforeEach(() => {
factory();
diff --git a/spec/frontend/releases/components/confirm_delete_modal_spec.js b/spec/frontend/releases/components/confirm_delete_modal_spec.js
index f7c526c1ced..b4699302779 100644
--- a/spec/frontend/releases/components/confirm_delete_modal_spec.js
+++ b/spec/frontend/releases/components/confirm_delete_modal_spec.js
@@ -42,10 +42,6 @@ describe('~/releases/components/confirm_delete_modal.vue', () => {
factory();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('button', () => {
it('should open the modal on click', async () => {
await wrapper.findByRole('button', { name: 'Delete' }).trigger('click');
diff --git a/spec/frontend/releases/components/evidence_block_spec.js b/spec/frontend/releases/components/evidence_block_spec.js
index 69443cb7a11..42eac31e5ac 100644
--- a/spec/frontend/releases/components/evidence_block_spec.js
+++ b/spec/frontend/releases/components/evidence_block_spec.js
@@ -27,10 +27,6 @@ describe('Evidence Block', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the evidence icon', () => {
expect(wrapper.findComponent(GlIcon).props('name')).toBe('review-list');
});
diff --git a/spec/frontend/releases/components/issuable_stats_spec.js b/spec/frontend/releases/components/issuable_stats_spec.js
index 3ac75e138ee..c8cdf9cb951 100644
--- a/spec/frontend/releases/components/issuable_stats_spec.js
+++ b/spec/frontend/releases/components/issuable_stats_spec.js
@@ -34,11 +34,6 @@ describe('~/releases/components/issuable_stats.vue', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('matches snapshot', () => {
createComponent();
diff --git a/spec/frontend/releases/components/release_block_footer_spec.js b/spec/frontend/releases/components/release_block_footer_spec.js
index 19b41d05a44..12e3807c9fa 100644
--- a/spec/frontend/releases/components/release_block_footer_spec.js
+++ b/spec/frontend/releases/components/release_block_footer_spec.js
@@ -33,11 +33,6 @@ describe('Release block footer', () => {
release = cloneDeep(originalRelease);
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const commitInfoSection = () => wrapper.find('.js-commit-info');
const commitInfoSectionLink = () => commitInfoSection().findComponent(GlLink);
const tagInfoSection = () => wrapper.find('.js-tag-info');
diff --git a/spec/frontend/releases/components/release_block_header_spec.js b/spec/frontend/releases/components/release_block_header_spec.js
index fc421776d60..dd39a1bce53 100644
--- a/spec/frontend/releases/components/release_block_header_spec.js
+++ b/spec/frontend/releases/components/release_block_header_spec.js
@@ -25,10 +25,6 @@ describe('Release block header', () => {
release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findHeader = () => wrapper.find('h2');
const findHeaderLink = () => findHeader().findComponent(GlLink);
const findEditButton = () => wrapper.find('.js-edit-button');
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 541d487091c..b8030ae1fd2 100644
--- a/spec/frontend/releases/components/release_block_milestone_info_spec.js
+++ b/spec/frontend/releases/components/release_block_milestone_info_spec.js
@@ -25,11 +25,6 @@ describe('Release block milestone info', () => {
milestones = convertObjectPropsToCamelCase(originalMilestones, { deep: true });
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const milestoneProgressBarContainer = () => wrapper.find('.js-milestone-progress-bar-container');
const milestoneListContainer = () => wrapper.find('.js-milestone-list-container');
const issuesContainer = () => wrapper.find('[data-testid="issue-stats"]');
diff --git a/spec/frontend/releases/components/release_block_spec.js b/spec/frontend/releases/components/release_block_spec.js
index f1b8554fbc3..3355b5ab2c3 100644
--- a/spec/frontend/releases/components/release_block_spec.js
+++ b/spec/frontend/releases/components/release_block_spec.js
@@ -39,10 +39,6 @@ describe('Release block', () => {
release = convertOneReleaseGraphQLResponse(originalOneReleaseQueryResponse).data;
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with default props', () => {
beforeEach(() => factory(release));
diff --git a/spec/frontend/releases/components/releases_pagination_spec.js b/spec/frontend/releases/components/releases_pagination_spec.js
index 59be808c802..923d84ae2b3 100644
--- a/spec/frontend/releases/components/releases_pagination_spec.js
+++ b/spec/frontend/releases/components/releases_pagination_spec.js
@@ -29,10 +29,6 @@ describe('releases_pagination.vue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const singlePageInfo = {
hasPreviousPage: false,
hasNextPage: false,
diff --git a/spec/frontend/releases/components/releases_sort_spec.js b/spec/frontend/releases/components/releases_sort_spec.js
index c6e1846d252..92199896ab4 100644
--- a/spec/frontend/releases/components/releases_sort_spec.js
+++ b/spec/frontend/releases/components/releases_sort_spec.js
@@ -17,10 +17,6 @@ describe('releases_sort.vue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSorting = () => wrapper.findComponent(GlSorting);
const findSortingItems = () => wrapper.findAllComponents(GlSortingItem);
const findReleasedDateItem = () =>
diff --git a/spec/frontend/releases/components/tag_field_exsting_spec.js b/spec/frontend/releases/components/tag_field_exsting_spec.js
index 8105aa4f6f2..0e896eb645c 100644
--- a/spec/frontend/releases/components/tag_field_exsting_spec.js
+++ b/spec/frontend/releases/components/tag_field_exsting_spec.js
@@ -37,11 +37,6 @@ describe('releases/components/tag_field_existing', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('default', () => {
it('shows the tag name', () => {
createComponent();
diff --git a/spec/frontend/releases/components/tag_field_new_spec.js b/spec/frontend/releases/components/tag_field_new_spec.js
index fcba0da3462..2508495429c 100644
--- a/spec/frontend/releases/components/tag_field_new_spec.js
+++ b/spec/frontend/releases/components/tag_field_new_spec.js
@@ -9,6 +9,7 @@ import { __ } from '~/locale';
import TagFieldNew from '~/releases/components/tag_field_new.vue';
import createStore from '~/releases/stores';
import createEditNewModule from '~/releases/stores/modules/edit_new';
+import { i18n } from '~/releases/constants';
const TEST_TAG_NAME = 'test-tag-name';
const TEST_TAG_MESSAGE = 'Test tag message';
@@ -81,7 +82,6 @@ describe('releases/components/tag_field_new', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
@@ -210,9 +210,7 @@ describe('releases/components/tag_field_new', () => {
store.state.editNew.existingRelease = {};
await expectValidationMessageToBe('shown');
- expect(findTagNameFormGroup().text()).toContain(
- __('Selected tag is already in use. Choose another option.'),
- );
+ expect(findTagNameFormGroup().text()).toContain(i18n.tagIsAlredyInUseMessage);
});
});
@@ -222,7 +220,7 @@ describe('releases/components/tag_field_new', () => {
findTagNameDropdown().vm.$emit('hide');
await expectValidationMessageToBe('shown');
- expect(findTagNameFormGroup().text()).toContain(__('Tag name is required.'));
+ expect(findTagNameFormGroup().text()).toContain(i18n.tagNameIsRequiredMessage);
});
});
});
diff --git a/spec/frontend/releases/components/tag_field_spec.js b/spec/frontend/releases/components/tag_field_spec.js
index 85a40f02c53..8509c347291 100644
--- a/spec/frontend/releases/components/tag_field_spec.js
+++ b/spec/frontend/releases/components/tag_field_spec.js
@@ -24,11 +24,6 @@ describe('releases/components/tag_field', () => {
const findTagFieldNew = () => wrapper.findComponent(TagFieldNew);
const findTagFieldExisting = () => wrapper.findComponent(TagFieldExisting);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when an existing release is being edited', () => {
beforeEach(() => {
createComponent({ isExistingRelease: true });
diff --git a/spec/frontend/releases/release_notification_service_spec.js b/spec/frontend/releases/release_notification_service_spec.js
index 2344d4b929a..a90bfa3dcbd 100644
--- a/spec/frontend/releases/release_notification_service_spec.js
+++ b/spec/frontend/releases/release_notification_service_spec.js
@@ -2,9 +2,9 @@ import {
popCreateReleaseNotification,
putCreateReleaseNotification,
} from '~/releases/release_notification_service';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('~/releases/release_notification_service', () => {
const projectPath = 'test-project-path';
@@ -35,7 +35,7 @@ describe('~/releases/release_notification_service', () => {
expect(item).toBe(null);
});
- it('should create a flash message', () => {
+ it('should create an alert message', () => {
expect(createAlert).toHaveBeenCalledTimes(1);
expect(createAlert).toHaveBeenCalledWith({
message: `Release ${releaseName} has been successfully created.`,
@@ -49,7 +49,7 @@ describe('~/releases/release_notification_service', () => {
popCreateReleaseNotification(projectPath);
});
- it('should not create a flash message', () => {
+ it('should not create an alert message', () => {
expect(createAlert).toHaveBeenCalledTimes(0);
});
});
diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js
index ca3b2d5f734..2fca3396a1f 100644
--- a/spec/frontend/releases/stores/modules/detail/actions_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js
@@ -2,7 +2,7 @@ import { cloneDeep } from 'lodash';
import originalOneReleaseForEditingQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release_for_editing.query.graphql.json';
import testAction from 'helpers/vuex_action_helper';
import { getTag } from '~/api/tags_api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import { ASSET_LINK_TYPE } from '~/releases/constants';
@@ -21,7 +21,7 @@ import {
jest.mock('~/api/tags_api');
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/releases/release_notification_service');
@@ -154,7 +154,7 @@ describe('Release edit/new actions', () => {
]);
});
- it(`shows a flash message`, () => {
+ it(`shows an alert message`, () => {
return actions.fetchRelease({ commit: jest.fn(), state, rootState: state }).then(() => {
expect(createAlert).toHaveBeenCalledTimes(1);
expect(createAlert).toHaveBeenCalledWith({
@@ -380,7 +380,7 @@ describe('Release edit/new actions', () => {
]);
});
- it(`shows a flash message`, () => {
+ it(`shows an alert message`, () => {
return actions
.createRelease({ commit: jest.fn(), dispatch: jest.fn(), state, getters: {} })
.then(() => {
@@ -406,7 +406,7 @@ describe('Release edit/new actions', () => {
]);
});
- it(`shows a flash message`, () => {
+ it(`shows an alert message`, () => {
return actions
.createRelease({ commit: jest.fn(), dispatch: jest.fn(), state, getters: {} })
.then(() => {
@@ -538,7 +538,7 @@ describe('Release edit/new actions', () => {
expect(commit.mock.calls).toEqual([[types.RECEIVE_SAVE_RELEASE_ERROR, error]]);
});
- it('shows a flash message', async () => {
+ it('shows an alert message', async () => {
await actions.updateRelease({ commit, dispatch, state, getters });
expect(createAlert).toHaveBeenCalledTimes(1);
@@ -558,7 +558,7 @@ describe('Release edit/new actions', () => {
]);
});
- it('shows a flash message', async () => {
+ it('shows an alert message', async () => {
await actions.updateRelease({ commit, dispatch, state, getters });
expect(createAlert).toHaveBeenCalledTimes(1);
@@ -711,7 +711,7 @@ describe('Release edit/new actions', () => {
expect(commit.mock.calls).toContainEqual([types.RECEIVE_SAVE_RELEASE_ERROR, error]);
});
- it('shows a flash message', async () => {
+ it('shows an alert message', async () => {
await actions.deleteRelease({ commit, dispatch, state, getters });
expect(createAlert).toHaveBeenCalledTimes(1);
@@ -747,7 +747,7 @@ describe('Release edit/new actions', () => {
]);
});
- it('shows a flash message', async () => {
+ it('shows an alert message', async () => {
await actions.deleteRelease({ commit, dispatch, state, getters });
expect(createAlert).toHaveBeenCalledTimes(1);
@@ -778,7 +778,7 @@ describe('Release edit/new actions', () => {
expect(getTag).toHaveBeenCalledWith(state.projectId, tagName);
});
- it('creates a flash on error', async () => {
+ it('creates an alert on error', async () => {
error = new Error();
getTag.mockRejectedValue(error);
diff --git a/spec/frontend/releases/stores/modules/detail/getters_spec.js b/spec/frontend/releases/stores/modules/detail/getters_spec.js
index f8b87ec71dc..649e772f956 100644
--- a/spec/frontend/releases/stores/modules/detail/getters_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/getters_spec.js
@@ -1,5 +1,16 @@
import { s__ } from '~/locale';
import * as getters from '~/releases/stores/modules/edit_new/getters';
+import { i18n } from '~/releases/constants';
+import { validateTag, ValidationResult } from '~/lib/utils/ref_validator';
+
+jest.mock('~/lib/utils/ref_validator', () => {
+ const original = jest.requireActual('~/lib/utils/ref_validator');
+ return {
+ __esModule: true,
+ ValidationResult: original.ValidationResult,
+ validateTag: jest.fn(() => new original.ValidationResult()),
+ };
+});
describe('Release edit/new getters', () => {
describe('releaseLinksToCreate', () => {
@@ -59,23 +70,23 @@ describe('Release edit/new getters', () => {
});
describe('validationErrors', () => {
+ const validState = {
+ release: {
+ tagName: 'test-tag-name',
+ assets: {
+ links: [
+ { id: 1, url: 'https://example.com/valid', name: 'Link 1' },
+ { id: 2, url: '', name: '' },
+ { id: 3, url: '', name: ' ' },
+ { id: 4, url: ' ', name: '' },
+ { id: 5, url: ' ', name: ' ' },
+ ],
+ },
+ },
+ };
describe('when the form is valid', () => {
+ const state = validState;
it('returns no validation errors', () => {
- const state = {
- release: {
- tagName: 'test-tag-name',
- assets: {
- links: [
- { id: 1, url: 'https://example.com/valid', name: 'Link 1' },
- { id: 2, url: '', name: '' },
- { id: 3, url: '', name: ' ' },
- { id: 4, url: ' ', name: '' },
- { id: 5, url: ' ', name: ' ' },
- ],
- },
- },
- };
-
const expectedErrors = {
assets: {
links: {
@@ -88,7 +99,27 @@ describe('Release edit/new getters', () => {
},
};
- expect(getters.validationErrors(state)).toEqual(expectedErrors);
+ expect(getters.validationErrors(state).assets).toEqual(expectedErrors.assets);
+ expect(getters.validationErrors(state).tagNameValidation.isValid).toBe(true);
+ });
+ });
+
+ describe('when validating tag', () => {
+ const state = validState;
+ it('validateTag is called with right parameters', () => {
+ getters.validationErrors(state);
+ expect(validateTag).toHaveBeenCalledWith(state.release.tagName);
+ });
+
+ it('validation error is correctly returned', () => {
+ const validationError = new ValidationResult();
+ const errorText = 'Tag format validation error';
+ validationError.addValidationError(errorText);
+ validateTag.mockReturnValue(validationError);
+
+ const result = getters.validationErrors(state);
+ expect(validateTag).toHaveBeenCalledWith(state.release.tagName);
+ expect(result.tagNameValidation.validationErrors).toContain(errorText);
});
});
@@ -140,19 +171,17 @@ describe('Release edit/new getters', () => {
});
it('returns a validation error if the tag name is empty', () => {
- const expectedErrors = {
- isTagNameEmpty: true,
- };
-
- expect(actualErrors).toMatchObject(expectedErrors);
+ expect(actualErrors.tagNameValidation.isValid).toBe(false);
+ expect(actualErrors.tagNameValidation.validationErrors).toContain(
+ i18n.tagNameIsRequiredMessage,
+ );
});
it('returns a validation error if the tag has an existing release', () => {
- const expectedErrors = {
- existingRelease: true,
- };
-
- expect(actualErrors).toMatchObject(expectedErrors);
+ expect(actualErrors.tagNameValidation.isValid).toBe(false);
+ expect(actualErrors.tagNameValidation.validationErrors).toContain(
+ i18n.tagIsAlredyInUseMessage,
+ );
});
it('returns a validation error if links share a URL', () => {
diff --git a/spec/frontend/repository/commits_service_spec.js b/spec/frontend/repository/commits_service_spec.js
index e56975d021a..22ef552c2f9 100644
--- a/spec/frontend/repository/commits_service_spec.js
+++ b/spec/frontend/repository/commits_service_spec.js
@@ -2,11 +2,11 @@ import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { loadCommits, isRequested, resetRequestedCommits } from '~/repository/commits_service';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { I18N_COMMIT_DATA_FETCH_ERROR } from '~/repository/constants';
import { refWithSpecialCharMock } from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('commits service', () => {
let mock;
diff --git a/spec/frontend/repository/components/blob_button_group_spec.js b/spec/frontend/repository/components/blob_button_group_spec.js
index 33a85c04fcf..96dedd54126 100644
--- a/spec/frontend/repository/components/blob_button_group_spec.js
+++ b/spec/frontend/repository/components/blob_button_group_spec.js
@@ -38,10 +38,6 @@ describe('BlobButtonGroup component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDeleteBlobModal = () => wrapper.findComponent(DeleteBlobModal);
const findUploadBlobModal = () => wrapper.findComponent(UploadBlobModal);
const findDeleteButton = () => wrapper.findByTestId('delete');
diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js
index 03a8ee6ac5d..a588251c4bd 100644
--- a/spec/frontend/repository/components/blob_content_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_content_viewer_spec.js
@@ -175,7 +175,6 @@ describe('Blob content viewer component', () => {
});
afterEach(() => {
- wrapper.destroy();
mockAxios.reset();
});
@@ -482,11 +481,6 @@ describe('Blob content viewer component', () => {
repository: { empty },
} = projectMock;
- afterEach(() => {
- delete gon.current_user_id;
- delete gon.current_username;
- });
-
it('renders component', async () => {
window.gon.current_user_id = 1;
window.gon.current_username = 'root';
diff --git a/spec/frontend/repository/components/blob_controls_spec.js b/spec/frontend/repository/components/blob_controls_spec.js
index 0d52542397f..3ced5f6c4d2 100644
--- a/spec/frontend/repository/components/blob_controls_spec.js
+++ b/spec/frontend/repository/components/blob_controls_spec.js
@@ -50,8 +50,6 @@ describe('Blob controls component', () => {
beforeEach(() => createComponent());
- afterEach(() => wrapper.destroy());
-
it('renders a find button with the correct href', () => {
expect(findFindButton().attributes('href')).toBe('find/file.js');
});
diff --git a/spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js b/spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js
index 599443bf862..b4f4b0058de 100644
--- a/spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_viewers/lfs_viewer_spec.js
@@ -21,8 +21,6 @@ describe('LFS Viewer', () => {
beforeEach(() => createComponent());
- afterEach(() => wrapper.destroy());
-
it('renders the correct text', () => {
expect(wrapper.text()).toBe(
'This content could not be displayed because it is stored in LFS. You can download it instead.',
diff --git a/spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js b/spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js
index 51f3d31ec72..5d37692bf90 100644
--- a/spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js
@@ -1,7 +1,6 @@
-import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import NotebookViewer from '~/repository/components/blob_viewers/notebook_viewer.vue';
-import notebookLoader from '~/blob/notebook';
+import Notebook from '~/blob/notebook/notebook_viewer.vue';
jest.mock('~/blob/notebook');
@@ -17,24 +16,11 @@ describe('Notebook Viewer', () => {
});
};
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findNotebookWrapper = () => wrapper.findByTestId('notebook');
+ const findNotebook = () => wrapper.findComponent(Notebook);
beforeEach(() => createComponent());
- it('calls the notebook loader', () => {
- expect(notebookLoader).toHaveBeenCalledWith({
- el: wrapper.vm.$refs.viewer,
- relativeRawPath: ROOT_RELATIVE_PATH,
- });
- });
-
- it('renders a loading icon component', () => {
- expect(findLoadingIcon().props('size')).toBe('lg');
- });
-
- it('renders the notebook wrapper', () => {
- expect(findNotebookWrapper().exists()).toBe(true);
- expect(findNotebookWrapper().attributes('data-endpoint')).toBe(DEFAULT_BLOB_DATA.rawPath);
+ it('renders a Notebook component', () => {
+ expect(findNotebook().props('endpoint')).toBe(DEFAULT_BLOB_DATA.rawPath);
});
});
diff --git a/spec/frontend/repository/components/breadcrumbs_spec.js b/spec/frontend/repository/components/breadcrumbs_spec.js
index c2f34f79f89..8b7a7d91125 100644
--- a/spec/frontend/repository/components/breadcrumbs_spec.js
+++ b/spec/frontend/repository/components/breadcrumbs_spec.js
@@ -42,10 +42,6 @@ describe('Repository breadcrumbs component', () => {
const findUploadBlobModal = () => wrapper.findComponent(UploadBlobModal);
const findNewDirectoryModal = () => wrapper.findComponent(NewDirectoryModal);
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
path | linkCount
${'/'} | ${1}
diff --git a/spec/frontend/repository/components/delete_blob_modal_spec.js b/spec/frontend/repository/components/delete_blob_modal_spec.js
index b5996816ad8..9ca45bfb655 100644
--- a/spec/frontend/repository/components/delete_blob_modal_spec.js
+++ b/spec/frontend/repository/components/delete_blob_modal_spec.js
@@ -49,10 +49,6 @@ describe('DeleteBlobModal', () => {
await findCommitTextarea().vm.$emit('input', commitText);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders Modal component', () => {
createComponent();
@@ -187,7 +183,7 @@ describe('DeleteBlobModal', () => {
});
it('disables submit button', async () => {
- expect(findModal().props('actionPrimary').attributes[0]).toEqual(
+ expect(findModal().props('actionPrimary').attributes).toEqual(
expect.objectContaining({ disabled: true }),
);
});
@@ -207,7 +203,7 @@ describe('DeleteBlobModal', () => {
});
it('enables submit button', async () => {
- expect(findModal().props('actionPrimary').attributes[0]).toEqual(
+ expect(findModal().props('actionPrimary').attributes).toEqual(
expect.objectContaining({ disabled: false }),
);
});
diff --git a/spec/frontend/repository/components/directory_download_links_spec.js b/spec/frontend/repository/components/directory_download_links_spec.js
index 72c4165c2e9..3739829c759 100644
--- a/spec/frontend/repository/components/directory_download_links_spec.js
+++ b/spec/frontend/repository/components/directory_download_links_spec.js
@@ -16,10 +16,6 @@ function factory(currentPath) {
}
describe('Repository directory download links component', () => {
- afterEach(() => {
- vm.destroy();
- });
-
it.each`
path
${'app'}
diff --git a/spec/frontend/repository/components/fork_info_spec.js b/spec/frontend/repository/components/fork_info_spec.js
index f327a8cfae7..7a2b03a8d8f 100644
--- a/spec/frontend/repository/components/fork_info_spec.js
+++ b/spec/frontend/repository/components/fork_info_spec.js
@@ -1,42 +1,75 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
-import { GlSkeletonLoader, GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
+import { GlSkeletonLoader, GlIcon, GlLink, GlSprintf, GlButton, GlLoadingIcon } from '@gitlab/ui';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
+import { stubComponent } from 'helpers/stub_component';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import ForkInfo, { i18n } from '~/repository/components/fork_info.vue';
+import ConflictsModal from '~/repository/components/fork_sync_conflicts_modal.vue';
import forkDetailsQuery from '~/repository/queries/fork_details.query.graphql';
+import syncForkMutation from '~/repository/mutations/sync_fork.mutation.graphql';
import { propsForkInfo } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('ForkInfo component', () => {
let wrapper;
let mockResolver;
const forkInfoError = new Error('Something went wrong');
const projectId = 'gid://gitlab/Project/1';
+ const showMock = jest.fn();
+ const synchronizeFork = true;
Vue.use(VueApollo);
- const createCommitData = ({ ahead = 3, behind = 7 }) => {
+ const createForkDetailsData = (
+ forkDetails = { ahead: 3, behind: 7, isSyncing: false, hasConflicts: false },
+ ) => {
return {
data: {
- project: { id: projectId, forkDetails: { ahead, behind, __typename: 'ForkDetails' } },
+ project: { id: projectId, forkDetails },
},
};
};
- const createComponent = (props = {}, data = {}, isRequestFailed = false) => {
+ const createSyncForkDetailsData = (
+ forkDetails = { ahead: 3, behind: 7, isSyncing: false, hasConflicts: false },
+ ) => {
+ return {
+ data: {
+ projectSyncFork: { details: forkDetails, errors: [] },
+ },
+ };
+ };
+
+ const createComponent = (props = {}, data = {}, mutationData = {}, isRequestFailed = false) => {
mockResolver = isRequestFailed
? jest.fn().mockRejectedValue(forkInfoError)
- : jest.fn().mockResolvedValue(createCommitData(data));
+ : jest.fn().mockResolvedValue(createForkDetailsData(data));
wrapper = shallowMountExtended(ForkInfo, {
- apolloProvider: createMockApollo([[forkDetailsQuery, mockResolver]]),
+ apolloProvider: createMockApollo([
+ [forkDetailsQuery, mockResolver],
+ [syncForkMutation, jest.fn().mockResolvedValue(createSyncForkDetailsData(mutationData))],
+ ]),
propsData: { ...propsForkInfo, ...props },
- stubs: { GlSprintf },
+ stubs: {
+ GlSprintf,
+ GlButton,
+ ConflictsModal: stubComponent(ConflictsModal, {
+ template:
+ '<div><slot name="modal-title"></slot><slot></slot><slot name="modal-footer"></slot></div>',
+ methods: { show: showMock },
+ }),
+ },
+ provide: {
+ glFeatures: {
+ synchronizeFork,
+ },
+ },
});
return waitForPromises();
};
@@ -44,6 +77,8 @@ describe('ForkInfo component', () => {
const findLink = () => wrapper.findComponent(GlLink);
const findSkeleton = () => wrapper.findComponent(GlSkeletonLoader);
const findIcon = () => wrapper.findComponent(GlIcon);
+ const findUpdateForkButton = () => wrapper.findComponent(GlButton);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findDivergenceMessage = () => wrapper.findByTestId('divergence-message');
const findInaccessibleMessage = () => wrapper.findByTestId('inaccessible-project');
const findCompareLinks = () => findDivergenceMessage().findAllComponents(GlLink);
@@ -87,14 +122,50 @@ describe('ForkInfo component', () => {
expect(link.attributes('href')).toBe(propsForkInfo.sourcePath);
});
- it('renders unknown divergence message when divergence is unknown', async () => {
- await createComponent({}, { ahead: null, behind: null });
- expect(findDivergenceMessage().text()).toBe(i18n.unknown);
+ describe('Unknown divergence', () => {
+ beforeEach(async () => {
+ await createComponent(
+ {},
+ { ahead: null, behind: null, isSyncing: false, hasConflicts: false },
+ );
+ });
+
+ it('renders unknown divergence message when divergence is unknown', async () => {
+ expect(findDivergenceMessage().text()).toBe(i18n.unknown);
+ });
+
+ it('renders Update Fork button', async () => {
+ expect(findUpdateForkButton().exists()).toBe(true);
+ expect(findUpdateForkButton().text()).toBe(i18n.sync);
+ });
+ });
+
+ describe('Up to date divergence', () => {
+ beforeEach(async () => {
+ await createComponent({}, { ahead: 0, behind: 0, isSyncing: false, hasConflicts: false });
+ });
+
+ it('renders up to date message when fork is up to date', async () => {
+ expect(findDivergenceMessage().text()).toBe(i18n.upToDate);
+ });
+
+ it('does not render Update Fork button', async () => {
+ expect(findUpdateForkButton().exists()).toBe(false);
+ });
});
- it('renders up to date message when divergence is unknown', async () => {
- await createComponent({}, { ahead: 0, behind: 0 });
- expect(findDivergenceMessage().text()).toBe(i18n.upToDate);
+ describe('Limited visibility project', () => {
+ beforeEach(async () => {
+ await createComponent({}, null);
+ });
+
+ it('renders limited visibility messsage when forkDetails are empty', async () => {
+ expect(findDivergenceMessage().text()).toBe(i18n.limitedVisibility);
+ });
+
+ it('does not render Update Fork button', async () => {
+ expect(findUpdateForkButton().exists()).toBe(false);
+ });
});
describe.each([
@@ -104,6 +175,7 @@ describe('ForkInfo component', () => {
message: '3 commits behind, 7 commits ahead of the upstream repository.',
firstLink: propsForkInfo.behindComparePath,
secondLink: propsForkInfo.aheadComparePath,
+ hasButton: true,
},
{
ahead: 7,
@@ -111,6 +183,7 @@ describe('ForkInfo component', () => {
message: '7 commits ahead of the upstream repository.',
firstLink: propsForkInfo.aheadComparePath,
secondLink: '',
+ hasButton: false,
},
{
ahead: 0,
@@ -118,12 +191,13 @@ describe('ForkInfo component', () => {
message: '3 commits behind the upstream repository.',
firstLink: propsForkInfo.behindComparePath,
secondLink: '',
+ hasButton: true,
},
])(
'renders correct divergence message for ahead: $ahead, behind: $behind divergence commits',
- ({ ahead, behind, message, firstLink, secondLink }) => {
+ ({ ahead, behind, message, firstLink, secondLink, hasButton }) => {
beforeEach(async () => {
- await createComponent({}, { ahead, behind });
+ await createComponent({}, { ahead, behind, isSyncing: false, hasConflicts: false });
});
it('displays correct text', () => {
@@ -138,9 +212,38 @@ describe('ForkInfo component', () => {
expect(links.at(1).attributes('href')).toBe(secondLink);
}
});
+
+ it('renders Update Fork button when fork is behind', () => {
+ expect(findUpdateForkButton().exists()).toBe(hasButton);
+ if (hasButton) {
+ expect(findUpdateForkButton().text()).toBe(i18n.sync);
+ }
+ });
},
);
+ describe('when sync is not possible due to conflicts', () => {
+ it('opens Conflicts Modal', async () => {
+ await createComponent({}, { ahead: 7, behind: 3, isSyncing: false, hasConflicts: true });
+ findUpdateForkButton().vm.$emit('click');
+ expect(showMock).toHaveBeenCalled();
+ });
+ });
+
+ describe('projectSyncFork mutation', () => {
+ it('changes button to have loading state', async () => {
+ await createComponent(
+ {},
+ { ahead: 0, behind: 3, isSyncing: false, hasConflicts: false },
+ { ahead: 0, behind: 3, isSyncing: true, hasConflicts: false },
+ );
+ expect(findLoadingIcon().exists()).toBe(false);
+ findUpdateForkButton().vm.$emit('click');
+ await waitForPromises();
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
it('renders alert with error message when request fails', async () => {
await createComponent({}, {}, true);
expect(createAlert).toHaveBeenCalledWith({
diff --git a/spec/frontend/repository/components/fork_suggestion_spec.js b/spec/frontend/repository/components/fork_suggestion_spec.js
index 36a48a3fdb8..a9e5c18c0a9 100644
--- a/spec/frontend/repository/components/fork_suggestion_spec.js
+++ b/spec/frontend/repository/components/fork_suggestion_spec.js
@@ -14,8 +14,6 @@ describe('ForkSuggestion component', () => {
beforeEach(() => createComponent());
- afterEach(() => wrapper.destroy());
-
const { i18n } = ForkSuggestion;
const findMessage = () => wrapper.findByTestId('message');
const findForkButton = () => wrapper.findByTestId('fork');
diff --git a/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js b/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js
new file mode 100644
index 00000000000..f97c970275b
--- /dev/null
+++ b/spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js
@@ -0,0 +1,42 @@
+import { GlModal } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import ConflictsModal, { i18n } from '~/repository/components/fork_sync_conflicts_modal.vue';
+import { propsConflictsModal } from '../mock_data';
+
+describe('ConflictsModal', () => {
+ let wrapper;
+
+ function createComponent({ props = {} } = {}) {
+ wrapper = shallowMount(ConflictsModal, {
+ propsData: props,
+ stubs: { GlModal },
+ });
+ }
+
+ beforeEach(() => {
+ createComponent({ props: propsConflictsModal });
+ });
+
+ const findModal = () => wrapper.findComponent(GlModal);
+ const findInstructions = () => wrapper.findAll('[ data-testid="resolve-conflict-instructions"]');
+
+ it('renders a modal', () => {
+ expect(findModal().exists()).toBe(true);
+ });
+
+ it('passes title as a prop to a gl-modal component', () => {
+ expect(findModal().props().title).toBe(i18n.modalTitle);
+ });
+
+ it('renders a selection of markdown fields', () => {
+ expect(findInstructions().length).toBe(3);
+ });
+
+ it('renders a source url in a first intruction', () => {
+ expect(findInstructions().at(0).text()).toContain(propsConflictsModal.sourcePath);
+ });
+
+ it('renders default branch name in a first intruction', () => {
+ expect(findInstructions().at(0).text()).toContain(propsConflictsModal.sourceDefaultBranch);
+ });
+});
diff --git a/spec/frontend/repository/components/last_commit_spec.js b/spec/frontend/repository/components/last_commit_spec.js
index 7226e7baa36..f16edcb0b7c 100644
--- a/spec/frontend/repository/components/last_commit_spec.js
+++ b/spec/frontend/repository/components/last_commit_spec.js
@@ -6,6 +6,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import LastCommit from '~/repository/components/last_commit.vue';
+import SignatureBadge from '~/commit/components/signature_badge.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import pathLastCommitQuery from 'shared_queries/repository/path_last_commit.query.graphql';
import { refMock } from '../mock_data';
@@ -20,7 +21,7 @@ const findUserAvatarLink = () => wrapper.findComponent(UserAvatarLink);
const findLastCommitLabel = () => wrapper.findByTestId('last-commit-id-label');
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findCommitRowDescription = () => wrapper.find('.commit-row-description');
-const findStatusBox = () => wrapper.find('.signature-badge');
+const findStatusBox = () => wrapper.findComponent(SignatureBadge);
const findItemTitle = () => wrapper.find('.item-title');
const defaultPipelineEdges = [
@@ -56,7 +57,7 @@ const createCommitData = ({
pipelineEdges = defaultPipelineEdges,
author = defaultAuthor,
descriptionHtml = '',
- signatureHtml = null,
+ signature = null,
message = defaultMessage,
}) => {
return {
@@ -84,7 +85,7 @@ const createCommitData = ({
authorName: 'Test',
authorGravatar: 'https://test.com',
author,
- signatureHtml,
+ signature,
pipelines: {
__typename: 'PipelineConnection',
edges: pipelineEdges,
@@ -110,11 +111,13 @@ const createComponent = async (data = {}) => {
apolloProvider: createMockApollo([[pathLastCommitQuery, mockResolver]]),
propsData: { currentPath },
mixins: [{ data: () => ({ ref: refMock }) }],
+ stubs: {
+ SignatureBadge,
+ },
});
};
afterEach(() => {
- wrapper.destroy();
mockResolver = null;
});
@@ -204,23 +207,19 @@ describe('Repository last commit component', () => {
});
it('renders the signature HTML as returned by the backend', async () => {
+ const signatureResponse = {
+ __typename: 'GpgSignature',
+ gpgKeyPrimaryKeyid: 'xxx',
+ verificationStatus: 'VERIFIED',
+ };
createComponent({
- signatureHtml: `<a
- class="btn signature-badge"
- data-content="signature-content"
- data-html="true"
- data-placement="top"
- data-title="signature-title"
- data-toggle="popover"
- role="button"
- tabindex="0"
- ><span class="gl-badge badge badge-pill badge-success md">Verified</span></a>`,
+ signature: {
+ ...signatureResponse,
+ },
});
await waitForPromises();
- expect(findStatusBox().html()).toBe(
- `<a class="btn signature-badge" data-content="signature-content" data-html="true" data-placement="top" data-title="signature-title" data-toggle="popover" role="button" tabindex="0"><span class="gl-badge badge badge-pill badge-success md">Verified</span></a>`,
- );
+ expect(findStatusBox().props()).toMatchObject({ signature: signatureResponse });
});
it('sets correct CSS class if the commit message is empty', async () => {
diff --git a/spec/frontend/repository/components/new_directory_modal_spec.js b/spec/frontend/repository/components/new_directory_modal_spec.js
index 4e5c9a685c4..c920159375f 100644
--- a/spec/frontend/repository/components/new_directory_modal_spec.js
+++ b/spec/frontend/repository/components/new_directory_modal_spec.js
@@ -4,12 +4,12 @@ import { nextTick } from 'vue';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
import NewDirectoryModal from '~/repository/components/new_directory_modal.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn(),
}));
@@ -76,10 +76,6 @@ describe('NewDirectoryModal', () => {
await waitForPromises();
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders modal component', () => {
createComponent();
@@ -185,10 +181,10 @@ describe('NewDirectoryModal', () => {
it('disables submit button', async () => {
await fillForm({ dirName: '', branchName: '', commitMessage: '' });
- expect(findModal().props('actionPrimary').attributes[0].disabled).toBe(true);
+ expect(findModal().props('actionPrimary').attributes.disabled).toBe(true);
});
- it('creates a flash error', async () => {
+ it('creates an alert error', async () => {
mock.onPost(initialProps.path).timeout();
await fillForm({ dirName: 'foo', branchName: 'master', commitMessage: 'foo' });
diff --git a/spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap b/spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap
deleted file mode 100644
index 48a4feca1e5..00000000000
--- a/spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap
+++ /dev/null
@@ -1,42 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Repository file preview component renders file HTML 1`] = `
-<article
- class="file-holder limited-width-container readme-holder"
->
- <div
- class="js-file-title file-title-flex-parent"
- >
- <div
- class="file-header-content"
- >
- <gl-icon-stub
- name="doc-text"
- size="16"
- />
-
- <gl-link-stub
- href="http://test.com"
- >
- <strong>
- README.md
- </strong>
- </gl-link-stub>
- </div>
- </div>
-
- <div
- class="blob-viewer"
- data-qa-selector="blob_viewer_content"
- itemprop="about"
- >
- <div>
- <div
- class="blob"
- >
- test
- </div>
- </div>
- </div>
-</article>
-`;
diff --git a/spec/frontend/repository/components/preview/index_spec.js b/spec/frontend/repository/components/preview/index_spec.js
index d4c746b67d6..8a88c5b9c61 100644
--- a/spec/frontend/repository/components/preview/index_spec.js
+++ b/spec/frontend/repository/components/preview/index_spec.js
@@ -1,77 +1,60 @@
import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
import { handleLocationHash } from '~/lib/utils/common_utils';
+import waitForPromises from 'helpers/wait_for_promises';
import Preview from '~/repository/components/preview/index.vue';
+const PROPS_DATA = {
+ blob: {
+ webPath: 'http://test.com',
+ name: 'README.md',
+ },
+};
+
+const MOCK_README_DATA = {
+ __typename: 'ReadmeFile',
+ html: '<div class="blob">test</div>',
+};
+
jest.mock('~/lib/utils/common_utils');
-let vm;
-let $apollo;
+Vue.use(VueApollo);
+
+let wrapper;
+let mockApollo;
+let mockReadmeData;
-function factory(blob, loading) {
- $apollo = {
- queries: {
- readme: {
- query: jest.fn().mockReturnValue(Promise.resolve({})),
- loading,
- },
- },
- };
+const mockResolvers = {
+ Query: {
+ readme: () => mockReadmeData(),
+ },
+};
- vm = shallowMount(Preview, {
- propsData: {
- blob,
- },
- mocks: {
- $apollo,
- },
+function createComponent() {
+ mockApollo = createMockApollo([], mockResolvers);
+
+ return shallowMount(Preview, {
+ propsData: PROPS_DATA,
+ apolloProvider: mockApollo,
});
}
describe('Repository file preview component', () => {
- afterEach(() => {
- vm.destroy();
- });
-
- it('renders file HTML', async () => {
- factory({
- webPath: 'http://test.com',
- name: 'README.md',
- });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- vm.setData({ readme: { html: '<div class="blob">test</div>' } });
-
- await nextTick();
- expect(vm.element).toMatchSnapshot();
+ beforeEach(() => {
+ mockReadmeData = jest.fn();
+ wrapper = createComponent();
+ mockReadmeData.mockResolvedValue(MOCK_README_DATA);
});
it('handles hash after render', async () => {
- factory({
- webPath: 'http://test.com',
- name: 'README.md',
- });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- vm.setData({ readme: { html: '<div class="blob">test</div>' } });
-
- await nextTick();
+ await waitForPromises();
expect(handleLocationHash).toHaveBeenCalled();
});
it('renders loading icon', async () => {
- factory(
- {
- webPath: 'http://test.com',
- name: 'README.md',
- },
- true,
- );
-
- await nextTick();
- expect(vm.findComponent(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
});
diff --git a/spec/frontend/repository/components/table/index_spec.js b/spec/frontend/repository/components/table/index_spec.js
index 8b987551b33..f7be367887c 100644
--- a/spec/frontend/repository/components/table/index_spec.js
+++ b/spec/frontend/repository/components/table/index_spec.js
@@ -88,10 +88,6 @@ function factory({ path, isLoading = false, hasMore = true, entries = {}, commit
const findTableRows = () => vm.findAllComponents(TableRow);
describe('Repository table component', () => {
- afterEach(() => {
- vm.destroy();
- });
-
it.each`
path | ref
${'/'} | ${'main'}
diff --git a/spec/frontend/repository/components/table/parent_row_spec.js b/spec/frontend/repository/components/table/parent_row_spec.js
index 03fb4242e40..77822a148b7 100644
--- a/spec/frontend/repository/components/table/parent_row_spec.js
+++ b/spec/frontend/repository/components/table/parent_row_spec.js
@@ -26,10 +26,6 @@ function factory(path, loadingPath) {
}
describe('Repository parent row component', () => {
- afterEach(() => {
- vm.destroy();
- });
-
it.each`
path | to
${'app'} | ${'/-/tree/main/'}
diff --git a/spec/frontend/repository/components/table/row_spec.js b/spec/frontend/repository/components/table/row_spec.js
index 5d9138ab9cd..055616d6e8e 100644
--- a/spec/frontend/repository/components/table/row_spec.js
+++ b/spec/frontend/repository/components/table/row_spec.js
@@ -28,7 +28,7 @@ function factory(propsData = {}) {
rowNumber: 123,
},
directives: {
- GlHoverLoad: createMockDirective(),
+ GlHoverLoad: createMockDirective('gl-hover-load'),
},
mocks: {
$router,
@@ -47,10 +47,6 @@ describe('Repository table row component', () => {
const findRouterLink = () => vm.findComponent(RouterLinkStub);
const findIntersectionObserver = () => vm.findComponent(GlIntersectionObserver);
- afterEach(() => {
- vm.destroy();
- });
-
it('renders table row', async () => {
factory({
id: '1',
diff --git a/spec/frontend/repository/components/tree_content_spec.js b/spec/frontend/repository/components/tree_content_spec.js
index f694c8e9166..9597d8a7b77 100644
--- a/spec/frontend/repository/components/tree_content_spec.js
+++ b/spec/frontend/repository/components/tree_content_spec.js
@@ -1,12 +1,11 @@
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
-import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql';
import FilePreview from '~/repository/components/preview/index.vue';
import FileTable from '~/repository/components/table/index.vue';
import TreeContent from 'jh_else_ce/repository/components/tree_content.vue';
import { loadCommits, isRequested, resetRequestedCommits } from '~/repository/commits_service';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { i18n } from '~/repository/constants';
import { graphQLErrors } from '../mock_data';
@@ -15,15 +14,15 @@ jest.mock('~/repository/commits_service', () => ({
isRequested: jest.fn(),
resetRequestedCommits: jest.fn(),
}));
-jest.mock('~/flash');
+jest.mock('~/alert');
let vm;
let $apollo;
const mockResponse = jest.fn().mockReturnValue(Promise.resolve({ data: {} }));
-function factory(path, appoloMockResponse = mockResponse) {
+function factory(path, apolloMockResponse = mockResponse) {
$apollo = {
- query: appoloMockResponse,
+ query: apolloMockResponse,
};
vm = shallowMount(TreeContent, {
@@ -33,22 +32,12 @@ function factory(path, appoloMockResponse = mockResponse) {
mocks: {
$apollo,
},
- provide: {
- glFeatures: {
- increasePageSizeExponentially: true,
- paginatedTreeGraphqlQuery: true,
- },
- },
});
}
describe('Repository table component', () => {
const findFileTable = () => vm.findComponent(FileTable);
- afterEach(() => {
- vm.destroy();
- });
-
it('renders file preview', async () => {
factory('/');
@@ -171,37 +160,6 @@ describe('Repository table component', () => {
expect(findFileTable().props('hasMore')).toBe(limitReached);
});
-
- it.each`
- fetchCounter | pageSize
- ${0} | ${10}
- ${2} | ${30}
- ${4} | ${50}
- ${6} | ${70}
- ${8} | ${90}
- ${10} | ${100}
- ${20} | ${100}
- ${100} | ${100}
- ${200} | ${100}
- `('exponentially increases page size, to a maximum of 100', ({ fetchCounter, pageSize }) => {
- factory('/');
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- vm.setData({ fetchCounter });
-
- vm.vm.fetchFiles();
-
- expect($apollo.query).toHaveBeenCalledWith({
- query: paginatedTreeQuery,
- variables: {
- pageSize,
- nextPageCursor: '',
- path: '/',
- projectPath: '',
- ref: '',
- },
- });
- });
});
describe('commit data', () => {
diff --git a/spec/frontend/repository/components/upload_blob_modal_spec.js b/spec/frontend/repository/components/upload_blob_modal_spec.js
index 9de0666f27a..319321cfcb4 100644
--- a/spec/frontend/repository/components/upload_blob_modal_spec.js
+++ b/spec/frontend/repository/components/upload_blob_modal_spec.js
@@ -4,13 +4,13 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn(),
joinPaths: () => '/new_upload',
@@ -53,14 +53,9 @@ describe('UploadBlobModal', () => {
const findBranchName = () => wrapper.findComponent(GlFormInput);
const findMrToggle = () => wrapper.findComponent(GlToggle);
const findUploadDropzone = () => wrapper.findComponent(UploadDropzone);
- const actionButtonDisabledState = () => findModal().props('actionPrimary').attributes[0].disabled;
- const cancelButtonDisabledState = () => findModal().props('actionCancel').attributes[0].disabled;
- const actionButtonLoadingState = () => findModal().props('actionPrimary').attributes[0].loading;
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
+ const actionButtonDisabledState = () => findModal().props('actionPrimary').attributes.disabled;
+ const cancelButtonDisabledState = () => findModal().props('actionCancel').attributes.disabled;
+ const actionButtonLoadingState = () => findModal().props('actionPrimary').attributes.loading;
describe.each`
canPushCode | displayBranchName | displayForkedBranchMessage
@@ -110,9 +105,7 @@ describe('UploadBlobModal', () => {
if (canPushCode) {
describe('when changing the branch name', () => {
it('displays the MR toggle', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ target: 'Not main' });
+ createComponent({ targetBranch: 'Not main' });
await nextTick();
@@ -123,12 +116,10 @@ describe('UploadBlobModal', () => {
describe('completed form', () => {
beforeEach(() => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- file: { type: 'jpg' },
- filePreviewURL: 'http://file.com?format=jpg',
- });
+ findUploadDropzone().vm.$emit(
+ 'change',
+ new File(['http://file.com?format=jpg'], 'file.jpg'),
+ );
});
it('enables the upload button when the form is completed', () => {
@@ -184,7 +175,7 @@ describe('UploadBlobModal', () => {
await waitForPromises();
});
- it('creates a flash error', () => {
+ it('creates an alert error', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'Error uploading file. Please try again.',
});
@@ -199,13 +190,6 @@ describe('UploadBlobModal', () => {
);
describe('blob file submission type', () => {
- const submitForm = async () => {
- wrapper.vm.uploadFile = jest.fn();
- wrapper.vm.replaceFile = jest.fn();
- wrapper.vm.submitForm();
- await nextTick();
- };
-
const submitRequest = async () => {
mock = new MockAdapter(axios);
findModal().vm.$emit('primary', mockEvent);
@@ -225,13 +209,6 @@ describe('UploadBlobModal', () => {
expect(findModal().props('actionPrimary').text).toBe('Upload file');
});
- it('calls the default uploadFile when the form submit', async () => {
- await submitForm();
-
- expect(wrapper.vm.uploadFile).toHaveBeenCalled();
- expect(wrapper.vm.replaceFile).not.toHaveBeenCalled();
- });
-
it('makes a POST request', async () => {
await submitRequest();
@@ -261,13 +238,6 @@ describe('UploadBlobModal', () => {
expect(findModal().props('actionPrimary').text).toBe(primaryBtnText);
});
- it('calls the replaceFile when the form submit', async () => {
- await submitForm();
-
- expect(wrapper.vm.replaceFile).toHaveBeenCalled();
- expect(wrapper.vm.uploadFile).not.toHaveBeenCalled();
- });
-
it('makes a PUT request', async () => {
await submitRequest();
diff --git a/spec/frontend/repository/mixins/highlight_mixin_spec.js b/spec/frontend/repository/mixins/highlight_mixin_spec.js
index 7c48fe440d2..5f872749581 100644
--- a/spec/frontend/repository/mixins/highlight_mixin_spec.js
+++ b/spec/frontend/repository/mixins/highlight_mixin_spec.js
@@ -44,8 +44,6 @@ describe('HighlightMixin', () => {
beforeEach(() => createComponent());
- afterEach(() => wrapper.destroy());
-
describe('initHighlightWorker', () => {
const firstSeventyLines = contentArray.slice(0, LINES_PER_CHUNK).join('\n');
diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js
index 04ffe52bc3f..418a93a10cc 100644
--- a/spec/frontend/repository/mock_data.js
+++ b/spec/frontend/repository/mock_data.js
@@ -126,3 +126,9 @@ export const propsForkInfo = {
aheadComparePath: '/nataliia/myGitLab/-/compare/main...ref?from_project_id=1',
behindComparePath: 'gitlab-org/gitlab/-/compare/ref...main?from_project_id=2',
};
+
+export const propsConflictsModal = {
+ sourceDefaultBranch: 'branch-name',
+ sourceName: 'source-name',
+ sourcePath: 'path/to/project',
+};
diff --git a/spec/frontend/repository/pages/blob_spec.js b/spec/frontend/repository/pages/blob_spec.js
index 4fe6188370e..366523e2b8b 100644
--- a/spec/frontend/repository/pages/blob_spec.js
+++ b/spec/frontend/repository/pages/blob_spec.js
@@ -16,10 +16,6 @@ describe('Repository blob page component', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has a Blob Content Viewer component', () => {
expect(findBlobContentViewer().exists()).toBe(true);
expect(findBlobContentViewer().props('path')).toBe(path);
diff --git a/spec/frontend/repository/pages/index_spec.js b/spec/frontend/repository/pages/index_spec.js
index 559257d414c..e50557e7d61 100644
--- a/spec/frontend/repository/pages/index_spec.js
+++ b/spec/frontend/repository/pages/index_spec.js
@@ -13,8 +13,6 @@ describe('Repository index page component', () => {
}
afterEach(() => {
- wrapper.destroy();
-
updateElementsVisibility.mockClear();
});
diff --git a/spec/frontend/repository/pages/tree_spec.js b/spec/frontend/repository/pages/tree_spec.js
index 36662696c91..b1529d77c7d 100644
--- a/spec/frontend/repository/pages/tree_spec.js
+++ b/spec/frontend/repository/pages/tree_spec.js
@@ -12,8 +12,6 @@ describe('Repository tree page component', () => {
}
afterEach(() => {
- wrapper.destroy();
-
updateElementsVisibility.mockClear();
});
diff --git a/spec/frontend/saved_replies/components/__snapshots__/list_item_spec.js.snap b/spec/frontend/saved_replies/components/__snapshots__/list_item_spec.js.snap
index 3abdfcdaf20..204afc744e7 100644
--- a/spec/frontend/saved_replies/components/__snapshots__/list_item_spec.js.snap
+++ b/spec/frontend/saved_replies/components/__snapshots__/list_item_spec.js.snap
@@ -7,9 +7,39 @@ exports[`Saved replies list item component renders list item 1`] = `
<div
class="gl-display-flex gl-align-items-center"
>
- <strong>
+ <strong
+ data-testid="saved-reply-name"
+ >
test
</strong>
+
+ <div
+ class="gl-ml-auto"
+ >
+ <gl-button-stub
+ aria-label="Edit"
+ buttontextclasses=""
+ category="primary"
+ class="gl-mr-3"
+ data-testid="saved-reply-edit-btn"
+ icon="pencil"
+ size="medium"
+ title="Edit"
+ to="[object Object]"
+ variant="default"
+ />
+
+ <gl-button-stub
+ aria-label="Delete"
+ buttontextclasses=""
+ category="secondary"
+ data-testid="saved-reply-delete-btn"
+ icon="remove"
+ size="medium"
+ title="Delete"
+ variant="danger"
+ />
+ </div>
</div>
<div
@@ -17,5 +47,21 @@ exports[`Saved replies list item component renders list item 1`] = `
>
/assign_reviewer
</div>
+
+ <gl-modal-stub
+ actionprimary="[object Object]"
+ actionsecondary="[object Object]"
+ arialabel=""
+ dismisslabel="Close"
+ modalclass=""
+ modalid="delete-saved-reply-2"
+ size="sm"
+ title="Delete saved reply"
+ titletag="h4"
+ >
+ <gl-sprintf-stub
+ message="Are you sure you want to delete %{name}? This action cannot be undone."
+ />
+ </gl-modal-stub>
</li>
`;
diff --git a/spec/frontend/saved_replies/components/form_spec.js b/spec/frontend/saved_replies/components/form_spec.js
new file mode 100644
index 00000000000..adeda498e6f
--- /dev/null
+++ b/spec/frontend/saved_replies/components/form_spec.js
@@ -0,0 +1,144 @@
+import Vue, { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
+import { GlAlert } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createdSavedReplyResponse from 'test_fixtures/graphql/saved_replies/create_saved_reply.mutation.graphql.json';
+import createdSavedReplyErrorResponse from 'test_fixtures/graphql/saved_replies/create_saved_reply_with_errors.mutation.graphql.json';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import Form from '~/saved_replies/components/form.vue';
+import createSavedReplyMutation from '~/saved_replies/queries/create_saved_reply.mutation.graphql';
+import updateSavedReplyMutation from '~/saved_replies/queries/update_saved_reply.mutation.graphql';
+
+let wrapper;
+let createSavedReplyResponseSpy;
+let updateSavedReplyResponseSpy;
+
+function createMockApolloProvider(response) {
+ Vue.use(VueApollo);
+
+ createSavedReplyResponseSpy = jest.fn().mockResolvedValue(response);
+ updateSavedReplyResponseSpy = jest.fn().mockResolvedValue(response);
+
+ const requestHandlers = [
+ [createSavedReplyMutation, createSavedReplyResponseSpy],
+ [updateSavedReplyMutation, updateSavedReplyResponseSpy],
+ ];
+
+ return createMockApollo(requestHandlers);
+}
+
+function createComponent(id = null, response = createdSavedReplyResponse) {
+ const mockApollo = createMockApolloProvider(response);
+
+ return mount(Form, {
+ propsData: {
+ id,
+ },
+ apolloProvider: mockApollo,
+ });
+}
+
+const findSavedReplyNameInput = () => wrapper.find('[data-testid="saved-reply-name-input"]');
+const findSavedReplyNameFormGroup = () =>
+ wrapper.find('[data-testid="saved-reply-name-form-group"]');
+const findSavedReplyContentInput = () => wrapper.find('[data-testid="saved-reply-content-input"]');
+const findSavedReplyContentFormGroup = () =>
+ wrapper.find('[data-testid="saved-reply-content-form-group"]');
+const findSavedReplyFrom = () => wrapper.find('[data-testid="saved-reply-form"]');
+const findAlerts = () => wrapper.findAllComponents(GlAlert);
+const findSubmitBtn = () => wrapper.find('[data-testid="saved-reply-form-submit-btn"]');
+
+describe('Saved replies form component', () => {
+ describe('create saved reply', () => {
+ it('calls apollo mutation', async () => {
+ wrapper = createComponent();
+
+ findSavedReplyNameInput().setValue('Test');
+ findSavedReplyContentInput().setValue('Test content');
+ findSavedReplyFrom().trigger('submit');
+
+ await waitForPromises();
+
+ expect(createSavedReplyResponseSpy).toHaveBeenCalledWith({
+ id: null,
+ content: 'Test content',
+ name: 'Test',
+ });
+ });
+
+ it('does not submit when form validation fails', async () => {
+ wrapper = createComponent();
+
+ findSavedReplyFrom().trigger('submit');
+
+ await waitForPromises();
+
+ expect(createSavedReplyResponseSpy).not.toHaveBeenCalled();
+ });
+
+ it.each`
+ findFormGroup | findInput | fieldName
+ ${findSavedReplyNameFormGroup} | ${findSavedReplyContentInput} | ${'name'}
+ ${findSavedReplyContentFormGroup} | ${findSavedReplyNameInput} | ${'content'}
+ `('shows errors for empty $fieldName input', async ({ findFormGroup, findInput }) => {
+ wrapper = createComponent(null, createdSavedReplyErrorResponse);
+
+ findInput().setValue('Test');
+ findSavedReplyFrom().trigger('submit');
+
+ await waitForPromises();
+
+ expect(findFormGroup().classes('is-invalid')).toBe(true);
+ });
+
+ it('displays errors when mutation fails', async () => {
+ wrapper = createComponent(null, createdSavedReplyErrorResponse);
+
+ findSavedReplyNameInput().setValue('Test');
+ findSavedReplyContentInput().setValue('Test content');
+ findSavedReplyFrom().trigger('submit');
+
+ await waitForPromises();
+
+ const { errors } = createdSavedReplyErrorResponse;
+ const alertMessages = findAlerts().wrappers.map((x) => x.text());
+
+ expect(alertMessages).toEqual(errors.map((x) => x.message));
+ });
+
+ it('shows loading state when saving', async () => {
+ wrapper = createComponent();
+
+ findSavedReplyNameInput().setValue('Test');
+ findSavedReplyContentInput().setValue('Test content');
+ findSavedReplyFrom().trigger('submit');
+
+ await nextTick();
+
+ expect(findSubmitBtn().props('loading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findSubmitBtn().props('loading')).toBe(false);
+ });
+ });
+
+ describe('updates saved reply', () => {
+ it('calls apollo mutation', async () => {
+ wrapper = createComponent('1');
+
+ findSavedReplyNameInput().setValue('Test');
+ findSavedReplyContentInput().setValue('Test content');
+ findSavedReplyFrom().trigger('submit');
+
+ await waitForPromises();
+
+ expect(updateSavedReplyResponseSpy).toHaveBeenCalledWith({
+ id: '1',
+ content: 'Test content',
+ name: 'Test',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/saved_replies/components/list_item_spec.js b/spec/frontend/saved_replies/components/list_item_spec.js
index cad1000473b..f1ecdfecb15 100644
--- a/spec/frontend/saved_replies/components/list_item_spec.js
+++ b/spec/frontend/saved_replies/components/list_item_spec.js
@@ -1,22 +1,50 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import { shallowMount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { createMockDirective } from 'helpers/vue_mock_directive';
+import waitForPromises from 'helpers/wait_for_promises';
import ListItem from '~/saved_replies/components/list_item.vue';
+import deleteSavedReplyMutation from '~/saved_replies/queries/delete_saved_reply.mutation.graphql';
let wrapper;
+let deleteSavedReplyMutationResponse;
function createComponent(propsData = {}) {
+ Vue.use(VueApollo);
+
+ deleteSavedReplyMutationResponse = jest
+ .fn()
+ .mockResolvedValue({ data: { savedReplyDestroy: { errors: [] } } });
+
return shallowMount(ListItem, {
propsData,
+ directives: {
+ GlModal: createMockDirective('gl-modal'),
+ },
+ apolloProvider: createMockApollo([
+ [deleteSavedReplyMutation, deleteSavedReplyMutationResponse],
+ ]),
});
}
describe('Saved replies list item component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders list item', async () => {
wrapper = createComponent({ reply: { name: 'test', content: '/assign_reviewer' } });
expect(wrapper.element).toMatchSnapshot();
});
+
+ describe('delete button', () => {
+ it('calls Apollo mutate', async () => {
+ wrapper = createComponent({ reply: { name: 'test', content: '/assign_reviewer', id: 1 } });
+
+ wrapper.findComponent(GlModal).vm.$emit('primary');
+
+ await waitForPromises();
+
+ expect(deleteSavedReplyMutationResponse).toHaveBeenCalledWith({ id: 1 });
+ });
+ });
});
diff --git a/spec/frontend/saved_replies/components/list_spec.js b/spec/frontend/saved_replies/components/list_spec.js
index 66e9ddfe148..bc69cb852e0 100644
--- a/spec/frontend/saved_replies/components/list_spec.js
+++ b/spec/frontend/saved_replies/components/list_spec.js
@@ -1,61 +1,39 @@
-import Vue from 'vue';
import { mount } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
import noSavedRepliesResponse from 'test_fixtures/graphql/saved_replies/saved_replies_empty.query.graphql.json';
import savedRepliesResponse from 'test_fixtures/graphql/saved_replies/saved_replies.query.graphql.json';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
import List from '~/saved_replies/components/list.vue';
import ListItem from '~/saved_replies/components/list_item.vue';
-import savedRepliesQuery from '~/saved_replies/queries/saved_replies.query.graphql';
let wrapper;
-function createMockApolloProvider(response) {
- Vue.use(VueApollo);
-
- const requestHandlers = [[savedRepliesQuery, jest.fn().mockResolvedValue(response)]];
-
- return createMockApollo(requestHandlers);
-}
-
-function createComponent(options = {}) {
- const { mockApollo } = options;
+function createComponent(res = {}) {
+ const { savedReplies } = res.data.currentUser;
return mount(List, {
- apolloProvider: mockApollo,
+ propsData: {
+ savedReplies: savedReplies.nodes,
+ pageInfo: savedReplies.pageInfo,
+ count: savedReplies.count,
+ },
});
}
describe('Saved replies list component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('does not render any list items when response is empty', async () => {
- const mockApollo = createMockApolloProvider(noSavedRepliesResponse);
- wrapper = createComponent({ mockApollo });
-
- await waitForPromises();
+ it('does not render any list items when response is empty', () => {
+ wrapper = createComponent(noSavedRepliesResponse);
expect(wrapper.findAllComponents(ListItem).length).toBe(0);
});
- it('render saved replies count', async () => {
- const mockApollo = createMockApolloProvider(savedRepliesResponse);
- wrapper = createComponent({ mockApollo });
-
- await waitForPromises();
+ it('render saved replies count', () => {
+ wrapper = createComponent(savedRepliesResponse);
expect(wrapper.find('[data-testid="title"]').text()).toEqual('My saved replies (2)');
});
- it('renders list of saved replies', async () => {
- const mockApollo = createMockApolloProvider(savedRepliesResponse);
+ it('renders list of saved replies', () => {
const savedReplies = savedRepliesResponse.data.currentUser.savedReplies.nodes;
- wrapper = createComponent({ mockApollo });
-
- await waitForPromises();
+ wrapper = createComponent(savedRepliesResponse);
expect(wrapper.findAllComponents(ListItem).length).toBe(2);
expect(wrapper.findAllComponents(ListItem).at(0).props('reply')).toEqual(
diff --git a/spec/frontend/saved_replies/pages/index_spec.js b/spec/frontend/saved_replies/pages/index_spec.js
new file mode 100644
index 00000000000..771025d64ec
--- /dev/null
+++ b/spec/frontend/saved_replies/pages/index_spec.js
@@ -0,0 +1,45 @@
+import Vue from 'vue';
+import { mount } from '@vue/test-utils';
+import VueApollo from 'vue-apollo';
+import savedRepliesResponse from 'test_fixtures/graphql/saved_replies/saved_replies.query.graphql.json';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import IndexPage from '~/saved_replies/pages/index.vue';
+import ListItem from '~/saved_replies/components/list_item.vue';
+import savedRepliesQuery from '~/saved_replies/queries/saved_replies.query.graphql';
+
+let wrapper;
+
+function createMockApolloProvider(response) {
+ Vue.use(VueApollo);
+
+ const requestHandlers = [[savedRepliesQuery, jest.fn().mockResolvedValue(response)]];
+
+ return createMockApollo(requestHandlers);
+}
+
+function createComponent(options = {}) {
+ const { mockApollo } = options;
+
+ return mount(IndexPage, {
+ apolloProvider: mockApollo,
+ });
+}
+
+describe('Saved replies index page component', () => {
+ it('renders list of saved replies', async () => {
+ const mockApollo = createMockApolloProvider(savedRepliesResponse);
+ const savedReplies = savedRepliesResponse.data.currentUser.savedReplies.nodes;
+ wrapper = createComponent({ mockApollo });
+
+ await waitForPromises();
+
+ expect(wrapper.findAllComponents(ListItem).length).toBe(2);
+ expect(wrapper.findAllComponents(ListItem).at(0).props('reply')).toEqual(
+ expect.objectContaining(savedReplies[0]),
+ );
+ expect(wrapper.findAllComponents(ListItem).at(1).props('reply')).toEqual(
+ expect.objectContaining(savedReplies[1]),
+ );
+ });
+});
diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js
index fb9c0a93907..0aa4f0e1c84 100644
--- a/spec/frontend/search/mock_data.js
+++ b/spec/frontend/search/mock_data.js
@@ -653,3 +653,10 @@ export const TEST_FILTER_DATA = {
JSON: { label: 'JSON', value: 'JSON', count: 15 },
},
};
+
+export const SMALL_MOCK_AGGREGATIONS = [
+ {
+ name: 'language',
+ buckets: TEST_RAW_BUCKETS,
+ },
+];
diff --git a/spec/frontend/search/sidebar/components/app_spec.js b/spec/frontend/search/sidebar/components/app_spec.js
index 83302b90233..8a35ae96d5e 100644
--- a/spec/frontend/search/sidebar/components/app_spec.js
+++ b/spec/frontend/search/sidebar/components/app_spec.js
@@ -17,6 +17,10 @@ describe('GlobalSearchSidebar', () => {
resetQuery: jest.fn(),
};
+ const getterSpies = {
+ currentScope: jest.fn(() => 'issues'),
+ };
+
const createComponent = (initialState, featureFlags) => {
const store = new Vuex.Store({
state: {
@@ -24,6 +28,7 @@ describe('GlobalSearchSidebar', () => {
...initialState,
},
actions: actionSpies,
+ getters: getterSpies,
});
wrapper = shallowMount(GlobalSearchSidebar, {
@@ -52,22 +57,23 @@ describe('GlobalSearchSidebar', () => {
});
describe.each`
- scope | showFilters | ShowsLanguage
+ scope | showFilters | showsLanguage
${'issues'} | ${true} | ${false}
${'merge_requests'} | ${true} | ${false}
${'projects'} | ${false} | ${false}
${'blobs'} | ${false} | ${true}
- `('sidebar scope: $scope', ({ scope, showFilters, ShowsLanguage }) => {
+ `('sidebar scope: $scope', ({ scope, showFilters, showsLanguage }) => {
beforeEach(() => {
- createComponent({ urlQuery: { scope } }, { searchBlobsLanguageAggregation: true });
+ getterSpies.currentScope = jest.fn(() => scope);
+ createComponent({ urlQuery: { scope } });
});
it(`${!showFilters ? "doesn't" : ''} shows filters`, () => {
expect(findFilters().exists()).toBe(showFilters);
});
- it(`${!ShowsLanguage ? "doesn't" : ''} shows language filters`, () => {
- expect(findLanguageAggregation().exists()).toBe(ShowsLanguage);
+ it(`${!showsLanguage ? "doesn't" : ''} shows language filters`, () => {
+ expect(findLanguageAggregation().exists()).toBe(showsLanguage);
});
});
@@ -80,22 +86,4 @@ describe('GlobalSearchSidebar', () => {
});
});
});
-
- describe('when search_blobs_language_aggregation is enabled', () => {
- beforeEach(() => {
- createComponent({ urlQuery: { scope: 'blobs' } }, { searchBlobsLanguageAggregation: true });
- });
- it('shows the language filter', () => {
- expect(findLanguageAggregation().exists()).toBe(true);
- });
- });
-
- describe('when search_blobs_language_aggregation is disabled', () => {
- beforeEach(() => {
- createComponent({ urlQuery: { scope: 'blobs' } }, { searchBlobsLanguageAggregation: false });
- });
- it('hides the language filter', () => {
- expect(findLanguageAggregation().exists()).toBe(false);
- });
- });
});
diff --git a/spec/frontend/search/sidebar/components/checkbox_filter_spec.js b/spec/frontend/search/sidebar/components/checkbox_filter_spec.js
index 82017754b23..f7b35c7bb14 100644
--- a/spec/frontend/search/sidebar/components/checkbox_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/checkbox_filter_spec.js
@@ -17,8 +17,12 @@ describe('CheckboxFilter', () => {
setQuery: jest.fn(),
};
+ const getterSpies = {
+ queryLanguageFilters: jest.fn(() => []),
+ };
+
const defaultProps = {
- filterData: convertFiltersData(MOCK_LANGUAGE_AGGREGATIONS_BUCKETS),
+ filtersData: convertFiltersData(MOCK_LANGUAGE_AGGREGATIONS_BUCKETS),
};
const createComponent = () => {
@@ -27,6 +31,7 @@ describe('CheckboxFilter', () => {
query: MOCK_QUERY,
},
actions: actionSpies,
+ getters: getterSpies,
});
wrapper = shallowMountExtended(CheckboxFilter, {
@@ -73,7 +78,7 @@ describe('CheckboxFilter', () => {
describe('actions', () => {
it('triggers setQuery', () => {
const filter =
- defaultProps.filterData.filters[Object.keys(defaultProps.filterData.filters)[0]].value;
+ defaultProps.filtersData.filters[Object.keys(defaultProps.filtersData.filters)[0]].value;
findFormCheckboxGroup().vm.$emit('input', filter);
expect(actionSpies.setQuery).toHaveBeenCalledWith(expect.any(Object), {
diff --git a/spec/frontend/search/sidebar/components/filters_spec.js b/spec/frontend/search/sidebar/components/filters_spec.js
index 7e564bfa005..51c7bdd9609 100644
--- a/spec/frontend/search/sidebar/components/filters_spec.js
+++ b/spec/frontend/search/sidebar/components/filters_spec.js
@@ -17,6 +17,10 @@ describe('GlobalSearchSidebarFilters', () => {
resetQuery: jest.fn(),
};
+ const defaultGetters = {
+ currentScope: () => 'issues',
+ };
+
const createComponent = (initialState) => {
const store = new Vuex.Store({
state: {
@@ -24,6 +28,7 @@ describe('GlobalSearchSidebarFilters', () => {
...initialState,
},
actions: actionSpies,
+ getters: defaultGetters,
});
wrapper = shallowMount(ResultsFilters, {
@@ -31,10 +36,6 @@ describe('GlobalSearchSidebarFilters', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSidebarForm = () => wrapper.find('form');
const findStatusFilter = () => wrapper.findComponent(StatusFilter);
const findConfidentialityFilter = () => wrapper.findComponent(ConfidentialityFilter);
@@ -142,7 +143,11 @@ describe('GlobalSearchSidebarFilters', () => {
${'blobs'} | ${false}
`(`ConfidentialityFilter`, ({ scope, showFilter }) => {
beforeEach(() => {
- createComponent({ urlQuery: { scope } });
+ defaultGetters.currentScope = () => scope;
+ createComponent();
+ });
+ afterEach(() => {
+ defaultGetters.currentScope = () => 'issues';
});
it(`does${showFilter ? '' : ' not'} render when scope is ${scope}`, () => {
@@ -162,7 +167,11 @@ describe('GlobalSearchSidebarFilters', () => {
${'blobs'} | ${false}
`(`StatusFilter`, ({ scope, showFilter }) => {
beforeEach(() => {
- createComponent({ urlQuery: { scope } });
+ defaultGetters.currentScope = () => scope;
+ createComponent();
+ });
+ afterEach(() => {
+ defaultGetters.currentScope = () => 'issues';
});
it(`does${showFilter ? '' : ' not'} render when scope is ${scope}`, () => {
diff --git a/spec/frontend/search/sidebar/components/language_filter_spec.js b/spec/frontend/search/sidebar/components/language_filter_spec.js
new file mode 100644
index 00000000000..17656ba749b
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/language_filter_spec.js
@@ -0,0 +1,173 @@
+import { GlAlert, GlFormCheckbox, GlForm } from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import {
+ MOCK_QUERY,
+ MOCK_AGGREGATIONS,
+ MOCK_LANGUAGE_AGGREGATIONS_BUCKETS,
+} from 'jest/search/mock_data';
+import LanguageFilter from '~/search/sidebar/components/language_filter.vue';
+import CheckboxFilter from '~/search/sidebar/components/checkbox_filter.vue';
+import { MAX_ITEM_LENGTH } from '~/search/sidebar/constants/language_filter_data';
+
+Vue.use(Vuex);
+
+describe('GlobalSearchSidebarLanguageFilter', () => {
+ let wrapper;
+
+ const actionSpies = {
+ fetchLanguageAggregation: jest.fn(),
+ applyQuery: jest.fn(),
+ };
+
+ const getterSpies = {
+ languageAggregationBuckets: jest.fn(() => MOCK_LANGUAGE_AGGREGATIONS_BUCKETS),
+ queryLanguageFilters: jest.fn(() => []),
+ };
+
+ const createComponent = (initialState) => {
+ const store = new Vuex.Store({
+ state: {
+ query: MOCK_QUERY,
+ urlQuery: MOCK_QUERY,
+ aggregations: MOCK_AGGREGATIONS,
+ ...initialState,
+ },
+ actions: actionSpies,
+ getters: getterSpies,
+ });
+
+ wrapper = shallowMountExtended(LanguageFilter, {
+ store,
+ stubs: {
+ CheckboxFilter,
+ },
+ });
+ };
+
+ const findForm = () => wrapper.findComponent(GlForm);
+ const findCheckboxFilter = () => wrapper.findComponent(CheckboxFilter);
+ const findApplyButton = () => wrapper.findByTestId('apply-button');
+ const findResetButton = () => wrapper.findByTestId('reset-button');
+ const findShowMoreButton = () => wrapper.findByTestId('show-more-button');
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findAllCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
+ const findHasOverMax = () => wrapper.findByTestId('has-over-max-text');
+
+ describe('Renders correctly', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders form', () => {
+ expect(findForm().exists()).toBe(true);
+ });
+
+ it('renders checkbox-filter', () => {
+ expect(findCheckboxFilter().exists()).toBe(true);
+ });
+
+ it('renders all checkbox-filter checkboxes', () => {
+ // 11th checkbox is hidden
+ expect(findAllCheckboxes()).toHaveLength(10);
+ });
+
+ it('renders ApplyButton', () => {
+ expect(findApplyButton().exists()).toBe(true);
+ });
+
+ it('renders Show More button', () => {
+ expect(findShowMoreButton().exists()).toBe(true);
+ });
+
+ it("doesn't render Alert", () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+ });
+
+ describe('resetButton', () => {
+ describe.each`
+ description | sidebarDirty | queryFilters | isDisabled
+ ${'sidebar dirty only'} | ${true} | ${[]} | ${undefined}
+ ${'query filters only'} | ${false} | ${['JSON', 'C']} | ${undefined}
+ ${'sidebar dirty and query filters'} | ${true} | ${['JSON', 'C']} | ${undefined}
+ ${'no sidebar and no query filters'} | ${false} | ${[]} | ${'true'}
+ `('$description', ({ sidebarDirty, queryFilters, isDisabled }) => {
+ beforeEach(() => {
+ getterSpies.queryLanguageFilters = jest.fn(() => queryFilters);
+ createComponent({ sidebarDirty, query: { ...MOCK_QUERY, language: queryFilters } });
+ });
+
+ it(`button is ${isDisabled ? 'enabled' : 'disabled'}`, () => {
+ expect(findResetButton().attributes('disabled')).toBe(isDisabled);
+ });
+ });
+ });
+
+ describe('ApplyButton', () => {
+ describe('when sidebarDirty is false', () => {
+ beforeEach(() => {
+ createComponent({ sidebarDirty: false });
+ });
+
+ it('disables the button', () => {
+ expect(findApplyButton().attributes('disabled')).toBe('true');
+ });
+ });
+
+ describe('when sidebarDirty is true', () => {
+ beforeEach(() => {
+ createComponent({ sidebarDirty: true });
+ });
+
+ it('enables the button', () => {
+ expect(findApplyButton().attributes('disabled')).toBe(undefined);
+ });
+ });
+ });
+
+ describe('Show All button works', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it(`renders ${MAX_ITEM_LENGTH} amount of items`, async () => {
+ findShowMoreButton().vm.$emit('click');
+ await nextTick();
+ expect(findAllCheckboxes()).toHaveLength(MAX_ITEM_LENGTH);
+ });
+
+ it(`renders more then ${MAX_ITEM_LENGTH} text`, async () => {
+ findShowMoreButton().vm.$emit('click');
+ await nextTick();
+ expect(findHasOverMax().exists()).toBe(true);
+ });
+
+ it(`doesn't render show more button after click`, async () => {
+ findShowMoreButton().vm.$emit('click');
+ await nextTick();
+ expect(findShowMoreButton().exists()).toBe(false);
+ });
+ });
+
+ describe('actions', () => {
+ beforeEach(() => {
+ createComponent({});
+ });
+
+ it('uses getter languageAggregationBuckets', () => {
+ expect(getterSpies.languageAggregationBuckets).toHaveBeenCalled();
+ });
+
+ it('uses action fetchLanguageAggregation', () => {
+ expect(actionSpies.fetchLanguageAggregation).toHaveBeenCalled();
+ });
+
+ it('clicking ApplyButton calls applyQuery', () => {
+ findForm().vm.$emit('submit', { preventDefault: () => {} });
+
+ expect(actionSpies.applyQuery).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/search/sidebar/components/language_filters_spec.js b/spec/frontend/search/sidebar/components/language_filters_spec.js
deleted file mode 100644
index e297d1c33b0..00000000000
--- a/spec/frontend/search/sidebar/components/language_filters_spec.js
+++ /dev/null
@@ -1,152 +0,0 @@
-import { GlAlert, GlFormCheckbox, GlForm } from '@gitlab/ui';
-import Vue, { nextTick } from 'vue';
-import Vuex from 'vuex';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import {
- MOCK_QUERY,
- MOCK_AGGREGATIONS,
- MOCK_LANGUAGE_AGGREGATIONS_BUCKETS,
-} from 'jest/search/mock_data';
-import LanguageFilter from '~/search/sidebar/components/language_filter.vue';
-import CheckboxFilter from '~/search/sidebar/components/checkbox_filter.vue';
-import { MAX_ITEM_LENGTH } from '~/search/sidebar/constants/language_filter_data';
-
-Vue.use(Vuex);
-
-describe('GlobalSearchSidebarLanguageFilter', () => {
- let wrapper;
-
- const actionSpies = {
- fetchLanguageAggregation: jest.fn(),
- applyQuery: jest.fn(),
- };
-
- const getterSpies = {
- langugageAggregationBuckets: jest.fn(() => MOCK_LANGUAGE_AGGREGATIONS_BUCKETS),
- };
-
- const createComponent = (initialState) => {
- const store = new Vuex.Store({
- state: {
- query: MOCK_QUERY,
- urlQuery: MOCK_QUERY,
- aggregations: MOCK_AGGREGATIONS,
- ...initialState,
- },
- actions: actionSpies,
- getters: getterSpies,
- });
-
- wrapper = shallowMountExtended(LanguageFilter, {
- store,
- stubs: {
- CheckboxFilter,
- },
- });
- };
-
- const findForm = () => wrapper.findComponent(GlForm);
- const findCheckboxFilter = () => wrapper.findComponent(CheckboxFilter);
- const findApplyButton = () => wrapper.findByTestId('apply-button');
- const findShowMoreButton = () => wrapper.findByTestId('show-more-button');
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findAllCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
- const findHasOverMax = () => wrapper.findByTestId('has-over-max-text');
-
- describe('Renders correctly', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders form', () => {
- expect(findForm().exists()).toBe(true);
- });
-
- it('renders checkbox-filter', () => {
- expect(findCheckboxFilter().exists()).toBe(true);
- });
-
- it('renders all checkbox-filter checkboxes', () => {
- // 11th checkbox is hidden
- expect(findAllCheckboxes()).toHaveLength(10);
- });
-
- it('renders ApplyButton', () => {
- expect(findApplyButton().exists()).toBe(true);
- });
-
- it('renders Show More button', () => {
- expect(findShowMoreButton().exists()).toBe(true);
- });
-
- it("doesn't render Alert", () => {
- expect(findAlert().exists()).toBe(false);
- });
- });
-
- describe('ApplyButton', () => {
- describe('when sidebarDirty is false', () => {
- beforeEach(() => {
- createComponent({ sidebarDirty: false });
- });
-
- it('disables the button', () => {
- expect(findApplyButton().attributes('disabled')).toBe('true');
- });
- });
-
- describe('when sidebarDirty is true', () => {
- beforeEach(() => {
- createComponent({ sidebarDirty: true });
- });
-
- it('enables the button', () => {
- expect(findApplyButton().attributes('disabled')).toBe(undefined);
- });
- });
- });
-
- describe('Show All button works', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it(`renders ${MAX_ITEM_LENGTH} amount of items`, async () => {
- findShowMoreButton().vm.$emit('click');
- await nextTick();
- expect(findAllCheckboxes()).toHaveLength(MAX_ITEM_LENGTH);
- });
-
- it(`renders more then ${MAX_ITEM_LENGTH} text`, async () => {
- findShowMoreButton().vm.$emit('click');
- await nextTick();
- expect(findHasOverMax().exists()).toBe(true);
- });
-
- it(`doesn't render show more button after click`, async () => {
- findShowMoreButton().vm.$emit('click');
- await nextTick();
- expect(findShowMoreButton().exists()).toBe(false);
- });
- });
-
- describe('actions', () => {
- beforeEach(() => {
- createComponent({});
- });
-
- it('uses getter langugageAggregationBuckets', () => {
- expect(getterSpies.langugageAggregationBuckets).toHaveBeenCalled();
- });
-
- it('uses action fetchLanguageAggregation', () => {
- expect(actionSpies.fetchLanguageAggregation).toHaveBeenCalled();
- });
-
- it('clicking ApplyButton calls applyQuery', () => {
- findForm().vm.$emit('submit', { preventDefault: () => {} });
-
- expect(actionSpies.applyQuery).toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/search/sidebar/components/radio_filter_spec.js b/spec/frontend/search/sidebar/components/radio_filter_spec.js
index 94d529348a9..47235b828c3 100644
--- a/spec/frontend/search/sidebar/components/radio_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/radio_filter_spec.js
@@ -16,6 +16,10 @@ describe('RadioFilter', () => {
setQuery: jest.fn(),
};
+ const defaultGetters = {
+ currentScope: jest.fn(() => 'issues'),
+ };
+
const defaultProps = {
filterData: stateFilterData,
};
@@ -27,6 +31,7 @@ describe('RadioFilter', () => {
...initialState,
},
actions: actionSpies,
+ getters: defaultGetters,
});
wrapper = shallowMount(RadioFilter, {
@@ -38,11 +43,6 @@ describe('RadioFilter', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findGlRadioButtonGroup = () => wrapper.findComponent(GlFormRadioGroup);
const findGlRadioButtons = () => findGlRadioButtonGroup().findAllComponents(GlFormRadio);
const findGlRadioButtonsText = () => findGlRadioButtons().wrappers.map((w) => w.text());
diff --git a/spec/frontend/search/sidebar/components/scope_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_navigation_spec.js
index 23c158239dc..3b2d528e1d7 100644
--- a/spec/frontend/search/sidebar/components/scope_navigation_spec.js
+++ b/spec/frontend/search/sidebar/components/scope_navigation_spec.js
@@ -14,6 +14,10 @@ describe('ScopeNavigation', () => {
fetchSidebarCount: jest.fn(),
};
+ const getterSpies = {
+ currentScope: jest.fn(() => 'issues'),
+ };
+
const createComponent = (initialState) => {
const store = new Vuex.Store({
state: {
@@ -22,6 +26,7 @@ describe('ScopeNavigation', () => {
...initialState,
},
actions: actionSpies,
+ getters: getterSpies,
});
wrapper = shallowMount(ScopeNavigation, {
@@ -29,16 +34,12 @@ describe('ScopeNavigation', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findNavElement = () => wrapper.find('nav');
const findGlNav = () => wrapper.findComponent(GlNav);
const findGlNavItems = () => wrapper.findAllComponents(GlNavItem);
- const findGlNavItemActive = () => findGlNavItems().wrappers.filter((w) => w.attributes('active'));
- const findGlNavItemActiveLabel = () => findGlNavItemActive().at(0).findAll('span').at(0).text();
- const findGlNavItemActiveCount = () => findGlNavItemActive().at(0).findAll('span').at(1);
+ const findGlNavItemActive = () => wrapper.find('[active=true]');
+ const findGlNavItemActiveLabel = () => findGlNavItemActive().find('[data-testid="label"]');
+ const findGlNavItemActiveCount = () => findGlNavItemActive().find('[data-testid="count"]');
describe('scope navigation', () => {
beforeEach(() => {
@@ -71,8 +72,8 @@ describe('ScopeNavigation', () => {
});
it('has correct active item', () => {
- expect(findGlNavItemActive()).toHaveLength(1);
- expect(findGlNavItemActiveLabel()).toBe('Issues');
+ expect(findGlNavItemActive().exists()).toBe(true);
+ expect(findGlNavItemActiveLabel().text()).toBe('Issues');
});
it('has correct active item count', () => {
@@ -80,7 +81,7 @@ describe('ScopeNavigation', () => {
});
it('does not have plus sign after count text', () => {
- expect(findGlNavItemActive().at(0).findComponent(GlIcon).exists()).toBe(false);
+ expect(findGlNavItemActive().findComponent(GlIcon).exists()).toBe(false);
});
it('has count is highlighted correctly', () => {
@@ -90,14 +91,26 @@ describe('ScopeNavigation', () => {
describe('scope navigation sets proper state with NO url scope set', () => {
beforeEach(() => {
+ getterSpies.currentScope = jest.fn(() => 'projects');
createComponent({
urlQuery: {},
+ navigation: {
+ ...MOCK_NAVIGATION,
+ projects: {
+ ...MOCK_NAVIGATION.projects,
+ active: true,
+ },
+ issues: {
+ ...MOCK_NAVIGATION.issues,
+ active: false,
+ },
+ },
});
});
it('has correct active item', () => {
- expect(findGlNavItems().at(0).attributes('active')).toBe('true');
- expect(findGlNavItemActiveLabel()).toBe('Projects');
+ expect(findGlNavItemActive().exists()).toBe(true);
+ expect(findGlNavItemActiveLabel().text()).toBe('Projects');
});
it('has correct active item count', () => {
@@ -105,7 +118,7 @@ describe('ScopeNavigation', () => {
});
it('has correct active item count and over limit sign', () => {
- expect(findGlNavItemActive().at(0).findComponent(GlIcon).exists()).toBe(true);
+ expect(findGlNavItemActive().findComponent(GlIcon).exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/search/sort/components/app_spec.js b/spec/frontend/search/sort/components/app_spec.js
index a566b9b99d3..322ce1b16ef 100644
--- a/spec/frontend/search/sort/components/app_spec.js
+++ b/spec/frontend/search/sort/components/app_spec.js
@@ -38,11 +38,6 @@ describe('GlobalSearchSort', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findSortButtonGroup = () => wrapper.findComponent(GlButtonGroup);
const findSortDropdown = () => wrapper.findComponent(GlDropdown);
const findSortDirectionButton = () => wrapper.findComponent(GlButton);
diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js
index 2f87802dfe6..0884411df0c 100644
--- a/spec/frontend/search/store/actions_spec.js
+++ b/spec/frontend/search/store/actions_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as logger from '~/lib/logger';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
@@ -33,7 +33,7 @@ import {
MOCK_AGGREGATIONS,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility', () => ({
setUrlParams: jest.fn(),
joinPaths: jest.fn().mockReturnValue(''),
@@ -47,7 +47,7 @@ describe('Global Search Store Actions', () => {
let mock;
let state;
- const flashCallback = (callCount) => {
+ const alertCallback = (callCount) => {
expect(createAlert).toHaveBeenCalledTimes(callCount);
createAlert.mockClear();
};
@@ -63,12 +63,12 @@ describe('Global Search Store Actions', () => {
});
describe.each`
- action | axiosMock | type | expectedMutations | flashCallCount
+ action | axiosMock | type | expectedMutations | alertCallCount
${actions.fetchGroups} | ${{ method: 'onGet', code: HTTP_STATUS_OK, res: MOCK_GROUPS }} | ${'success'} | ${[{ type: types.REQUEST_GROUPS }, { type: types.RECEIVE_GROUPS_SUCCESS, payload: MOCK_GROUPS }]} | ${0}
${actions.fetchGroups} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR, res: null }} | ${'error'} | ${[{ type: types.REQUEST_GROUPS }, { type: types.RECEIVE_GROUPS_ERROR }]} | ${1}
${actions.fetchProjects} | ${{ method: 'onGet', code: HTTP_STATUS_OK, res: MOCK_PROJECTS }} | ${'success'} | ${[{ type: types.REQUEST_PROJECTS }, { type: types.RECEIVE_PROJECTS_SUCCESS, payload: MOCK_PROJECTS }]} | ${0}
${actions.fetchProjects} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR, res: null }} | ${'error'} | ${[{ type: types.REQUEST_PROJECTS }, { type: types.RECEIVE_PROJECTS_ERROR }]} | ${1}
- `(`axios calls`, ({ action, axiosMock, type, expectedMutations, flashCallCount }) => {
+ `(`axios calls`, ({ action, axiosMock, type, expectedMutations, alertCallCount }) => {
describe(action.name, () => {
describe(`on ${type}`, () => {
beforeEach(() => {
@@ -76,7 +76,7 @@ describe('Global Search Store Actions', () => {
});
it(`should dispatch the correct mutations`, () => {
return testAction({ action, state, expectedMutations }).then(() =>
- flashCallback(flashCallCount),
+ alertCallback(alertCallCount),
);
});
});
@@ -84,12 +84,12 @@ describe('Global Search Store Actions', () => {
});
describe.each`
- action | axiosMock | type | expectedMutations | flashCallCount
+ action | axiosMock | type | expectedMutations | alertCallCount
${actions.loadFrequentGroups} | ${{ method: 'onGet', code: HTTP_STATUS_OK }} | ${'success'} | ${[PROMISE_ALL_EXPECTED_MUTATIONS.resGroups]} | ${0}
${actions.loadFrequentGroups} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR }} | ${'error'} | ${[]} | ${1}
${actions.loadFrequentProjects} | ${{ method: 'onGet', code: HTTP_STATUS_OK }} | ${'success'} | ${[PROMISE_ALL_EXPECTED_MUTATIONS.resProjects]} | ${0}
${actions.loadFrequentProjects} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR }} | ${'error'} | ${[]} | ${1}
- `('Promise.all calls', ({ action, axiosMock, type, expectedMutations, flashCallCount }) => {
+ `('Promise.all calls', ({ action, axiosMock, type, expectedMutations, alertCallCount }) => {
describe(action.name, () => {
describe(`on ${type}`, () => {
beforeEach(() => {
@@ -103,7 +103,7 @@ describe('Global Search Store Actions', () => {
it(`should dispatch the correct mutations`, () => {
return testAction({ action, state, expectedMutations }).then(() => {
- flashCallback(flashCallCount);
+ alertCallback(alertCallCount);
});
});
});
@@ -275,7 +275,7 @@ describe('Global Search Store Actions', () => {
describe.each`
action | axiosMock | type | scope | expectedMutations | errorLogs
${actions.fetchSidebarCount} | ${{ method: 'onGet', code: HTTP_STATUS_OK }} | ${'success'} | ${'issues'} | ${[MOCK_NAVIGATION_ACTION_MUTATION]} | ${0}
- ${actions.fetchSidebarCount} | ${{ method: null, code: 0 }} | ${'success'} | ${'projects'} | ${[]} | ${0}
+ ${actions.fetchSidebarCount} | ${{ method: null, code: 0 }} | ${'error'} | ${'projects'} | ${[]} | ${1}
${actions.fetchSidebarCount} | ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR }} | ${'error'} | ${'issues'} | ${[]} | ${1}
`('fetchSidebarCount', ({ action, axiosMock, type, expectedMutations, scope, errorLogs }) => {
describe(`on ${type}`, () => {
@@ -290,9 +290,9 @@ describe('Global Search Store Actions', () => {
}
});
- it(`should ${expectedMutations.length === 0 ? 'NOT ' : ''}dispatch ${
- expectedMutations.length === 0 ? '' : 'the correct '
- }mutations for ${scope}`, () => {
+ it(`should ${expectedMutations.length === 0 ? 'NOT' : ''} dispatch ${
+ expectedMutations.length === 0 ? '' : 'the correct'
+ } mutations for ${scope}`, () => {
return testAction({ action, state, expectedMutations }).then(() => {
expect(logger.logError).toHaveBeenCalledTimes(errorLogs);
});
@@ -325,4 +325,26 @@ describe('Global Search Store Actions', () => {
});
});
});
+
+ describe('resetLanguageQueryWithRedirect', () => {
+ it('calls visitUrl and setParams with the state.query', () => {
+ return testAction(actions.resetLanguageQueryWithRedirect, null, state, [], [], () => {
+ expect(urlUtils.setUrlParams).toHaveBeenCalledWith({ ...state.query, page: null });
+ expect(urlUtils.visitUrl).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('resetLanguageQuery', () => {
+ it('calls commit SET_QUERY with value []', () => {
+ state = { ...state, query: { ...state.query, language: ['YAML', 'Text', 'Markdown'] } };
+ return testAction(
+ actions.resetLanguageQuery,
+ null,
+ state,
+ [{ type: types.SET_QUERY, payload: { key: 'language', value: [] } }],
+ [],
+ );
+ });
+ });
});
diff --git a/spec/frontend/search/store/getters_spec.js b/spec/frontend/search/store/getters_spec.js
index 818902ee720..0ef0922c4b0 100644
--- a/spec/frontend/search/store/getters_spec.js
+++ b/spec/frontend/search/store/getters_spec.js
@@ -1,12 +1,15 @@
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from '~/search/store/constants';
import * as getters from '~/search/store/getters';
import createState from '~/search/store/state';
+import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import {
MOCK_QUERY,
MOCK_GROUPS,
MOCK_PROJECTS,
MOCK_AGGREGATIONS,
MOCK_LANGUAGE_AGGREGATIONS_BUCKETS,
+ TEST_FILTER_DATA,
+ MOCK_NAVIGATION,
} from '../mock_data';
describe('Global Search Store Getters', () => {
@@ -14,37 +17,55 @@ describe('Global Search Store Getters', () => {
beforeEach(() => {
state = createState({ query: MOCK_QUERY });
+ useMockLocationHelper();
});
describe('frequentGroups', () => {
- beforeEach(() => {
- state.frequentItems[GROUPS_LOCAL_STORAGE_KEY] = MOCK_GROUPS;
- });
-
it('returns the correct data', () => {
+ state.frequentItems[GROUPS_LOCAL_STORAGE_KEY] = MOCK_GROUPS;
expect(getters.frequentGroups(state)).toStrictEqual(MOCK_GROUPS);
});
});
describe('frequentProjects', () => {
- beforeEach(() => {
- state.frequentItems[PROJECTS_LOCAL_STORAGE_KEY] = MOCK_PROJECTS;
- });
-
it('returns the correct data', () => {
+ state.frequentItems[PROJECTS_LOCAL_STORAGE_KEY] = MOCK_PROJECTS;
expect(getters.frequentProjects(state)).toStrictEqual(MOCK_PROJECTS);
});
});
- describe('langugageAggregationBuckets', () => {
- beforeEach(() => {
+ describe('languageAggregationBuckets', () => {
+ it('returns the correct data', () => {
state.aggregations.data = MOCK_AGGREGATIONS;
+ expect(getters.languageAggregationBuckets(state)).toStrictEqual(
+ MOCK_LANGUAGE_AGGREGATIONS_BUCKETS,
+ );
});
+ });
+ describe('queryLanguageFilters', () => {
it('returns the correct data', () => {
- expect(getters.langugageAggregationBuckets(state)).toStrictEqual(
- MOCK_LANGUAGE_AGGREGATIONS_BUCKETS,
- );
+ state.query.language = Object.keys(TEST_FILTER_DATA.filters);
+ expect(getters.queryLanguageFilters(state)).toStrictEqual(state.query.language);
+ });
+ });
+
+ describe('currentScope', () => {
+ it('returns the correct scope name', () => {
+ state.navigation = MOCK_NAVIGATION;
+ expect(getters.currentScope(state)).toBe('issues');
+ });
+ });
+
+ describe('currentUrlQueryHasLanguageFilters', () => {
+ it.each`
+ description | lang | result
+ ${'has valid language'} | ${{ language: ['a', 'b'] }} | ${true}
+ ${'has empty lang'} | ${{ language: [] }} | ${false}
+ ${'has no lang'} | ${{}} | ${false}
+ `('$description', ({ lang, result }) => {
+ state.urlQuery = lang;
+ expect(getters.currentUrlQueryHasLanguageFilters(state)).toBe(result);
});
});
});
diff --git a/spec/frontend/search/store/utils_spec.js b/spec/frontend/search/store/utils_spec.js
index 487ed7bfe03..dfe4e801f11 100644
--- a/spec/frontend/search/store/utils_spec.js
+++ b/spec/frontend/search/store/utils_spec.js
@@ -7,6 +7,7 @@ import {
isSidebarDirty,
formatSearchResultCount,
getAggregationsUrl,
+ prepareSearchAggregations,
} from '~/search/store/utils';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import {
@@ -15,6 +16,9 @@ import {
MOCK_INFLATED_DATA,
FRESH_STORED_DATA,
STALE_STORED_DATA,
+ MOCK_AGGREGATIONS,
+ SMALL_MOCK_AGGREGATIONS,
+ TEST_RAW_BUCKETS,
} from '../mock_data';
const PREV_TIME = new Date().getTime() - 1;
@@ -226,11 +230,14 @@ describe('Global Search Store Utils', () => {
});
describe.each`
- description | currentQuery | urlQuery | isDirty
- ${'identical'} | ${{ [SIDEBAR_PARAMS[0]]: 'default', [SIDEBAR_PARAMS[1]]: 'default' }} | ${{ [SIDEBAR_PARAMS[0]]: 'default', [SIDEBAR_PARAMS[1]]: 'default' }} | ${false}
- ${'different'} | ${{ [SIDEBAR_PARAMS[0]]: 'default', [SIDEBAR_PARAMS[1]]: 'new' }} | ${{ [SIDEBAR_PARAMS[0]]: 'default', [SIDEBAR_PARAMS[1]]: 'default' }} | ${true}
- ${'null/undefined'} | ${{ [SIDEBAR_PARAMS[0]]: null, [SIDEBAR_PARAMS[1]]: null }} | ${{ [SIDEBAR_PARAMS[0]]: undefined, [SIDEBAR_PARAMS[1]]: undefined }} | ${false}
- ${'updated/undefined'} | ${{ [SIDEBAR_PARAMS[0]]: 'new', [SIDEBAR_PARAMS[1]]: 'new' }} | ${{ [SIDEBAR_PARAMS[0]]: undefined, [SIDEBAR_PARAMS[1]]: undefined }} | ${true}
+ description | currentQuery | urlQuery | isDirty
+ ${'identical'} | ${{ [SIDEBAR_PARAMS[0]]: 'default', [SIDEBAR_PARAMS[1]]: 'default', [SIDEBAR_PARAMS[2]]: ['a', 'b'] }} | ${{ [SIDEBAR_PARAMS[0]]: 'default', [SIDEBAR_PARAMS[1]]: 'default', [SIDEBAR_PARAMS[2]]: ['a', 'b'] }} | ${false}
+ ${'different'} | ${{ [SIDEBAR_PARAMS[0]]: 'default', [SIDEBAR_PARAMS[1]]: 'new', [SIDEBAR_PARAMS[2]]: ['a', 'b'] }} | ${{ [SIDEBAR_PARAMS[0]]: 'default', [SIDEBAR_PARAMS[1]]: 'default', [SIDEBAR_PARAMS[2]]: ['a', 'c'] }} | ${true}
+ ${'null/undefined'} | ${{ [SIDEBAR_PARAMS[0]]: null, [SIDEBAR_PARAMS[1]]: null, [SIDEBAR_PARAMS[2]]: null }} | ${{ [SIDEBAR_PARAMS[0]]: undefined, [SIDEBAR_PARAMS[1]]: undefined, [SIDEBAR_PARAMS[2]]: undefined }} | ${false}
+ ${'updated/undefined'} | ${{ [SIDEBAR_PARAMS[0]]: 'new', [SIDEBAR_PARAMS[1]]: 'new', [SIDEBAR_PARAMS[2]]: ['a', 'b'] }} | ${{ [SIDEBAR_PARAMS[0]]: undefined, [SIDEBAR_PARAMS[1]]: undefined, [SIDEBAR_PARAMS[2]]: [] }} | ${true}
+ ${'language only no url params'} | ${{ [SIDEBAR_PARAMS[2]]: ['a', 'b'] }} | ${{ [SIDEBAR_PARAMS[2]]: undefined }} | ${true}
+ ${'language only url params symetric'} | ${{ [SIDEBAR_PARAMS[2]]: ['a', 'b'] }} | ${{ [SIDEBAR_PARAMS[2]]: ['a', 'b'] }} | ${false}
+ ${'language only url params asymetric'} | ${{ [SIDEBAR_PARAMS[2]]: ['a'] }} | ${{ [SIDEBAR_PARAMS[2]]: ['a', 'b'] }} | ${true}
`('isSidebarDirty', ({ description, currentQuery, urlQuery, isDirty }) => {
describe(`with ${description} sidebar query data`, () => {
let res;
@@ -263,4 +270,22 @@ describe('Global Search Store Utils', () => {
expect(getAggregationsUrl()).toStrictEqual(`${testURL}search/aggregations`);
});
});
+
+ const TEST_LANGUAGE_QUERY = ['Markdown', 'JSON'];
+ const TEST_EXPECTED_ORDERED_BUCKETS = [
+ TEST_RAW_BUCKETS.find((x) => x.key === 'Markdown'),
+ TEST_RAW_BUCKETS.find((x) => x.key === 'JSON'),
+ ...TEST_RAW_BUCKETS.filter((x) => !TEST_LANGUAGE_QUERY.includes(x.key)),
+ ];
+
+ describe('prepareSearchAggregations', () => {
+ it.each`
+ description | query | data | result
+ ${'has no query'} | ${undefined} | ${MOCK_AGGREGATIONS} | ${MOCK_AGGREGATIONS}
+ ${'has query'} | ${{ language: TEST_LANGUAGE_QUERY }} | ${SMALL_MOCK_AGGREGATIONS} | ${[{ ...SMALL_MOCK_AGGREGATIONS[0], buckets: TEST_EXPECTED_ORDERED_BUCKETS }]}
+ ${'has bad query'} | ${{ language: ['sdf', 'wrt'] }} | ${SMALL_MOCK_AGGREGATIONS} | ${SMALL_MOCK_AGGREGATIONS}
+ `('$description', ({ query, data, result }) => {
+ expect(prepareSearchAggregations({ query }, data)).toStrictEqual(result);
+ });
+ });
});
diff --git a/spec/frontend/search/topbar/components/app_spec.js b/spec/frontend/search/topbar/components/app_spec.js
index 3975887cfff..423ec6ff63b 100644
--- a/spec/frontend/search/topbar/components/app_spec.js
+++ b/spec/frontend/search/topbar/components/app_spec.js
@@ -36,10 +36,6 @@ describe('GlobalSearchTopbar', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlSearchBox = () => wrapper.findComponent(GlSearchBoxByClick);
const findGroupFilter = () => wrapper.findComponent(GroupFilter);
const findProjectFilter = () => wrapper.findComponent(ProjectFilter);
diff --git a/spec/frontend/search/topbar/components/group_filter_spec.js b/spec/frontend/search/topbar/components/group_filter_spec.js
index b2d0297fdc2..78d9efbd686 100644
--- a/spec/frontend/search/topbar/components/group_filter_spec.js
+++ b/spec/frontend/search/topbar/components/group_filter_spec.js
@@ -49,10 +49,6 @@ describe('GroupFilter', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSearchableDropdown = () => wrapper.findComponent(SearchableDropdown);
describe('template', () => {
diff --git a/spec/frontend/search/topbar/components/project_filter_spec.js b/spec/frontend/search/topbar/components/project_filter_spec.js
index 297a536e075..9eda34b1633 100644
--- a/spec/frontend/search/topbar/components/project_filter_spec.js
+++ b/spec/frontend/search/topbar/components/project_filter_spec.js
@@ -49,10 +49,6 @@ describe('ProjectFilter', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSearchableDropdown = () => wrapper.findComponent(SearchableDropdown);
describe('template', () => {
diff --git a/spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js b/spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js
index e51fe9a4cf9..c911fe53d40 100644
--- a/spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js
+++ b/spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js
@@ -24,10 +24,6 @@ describe('Global Search Searchable Dropdown Item', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlDropdownItem = () => wrapper.findComponent(GlDropdownItem);
const findGlAvatar = () => wrapper.findComponent(GlAvatar);
const findDropdownTitle = () => wrapper.findByTestId('item-title');
diff --git a/spec/frontend/search/topbar/components/searchable_dropdown_spec.js b/spec/frontend/search/topbar/components/searchable_dropdown_spec.js
index de1cefa9e9d..5e5f46ff34e 100644
--- a/spec/frontend/search/topbar/components/searchable_dropdown_spec.js
+++ b/spec/frontend/search/topbar/components/searchable_dropdown_spec.js
@@ -1,6 +1,6 @@
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { MOCK_GROUPS, MOCK_GROUP, MOCK_QUERY } from 'jest/search/mock_data';
@@ -40,10 +40,6 @@ describe('Global Search Searchable Dropdown', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlDropdown = () => wrapper.findComponent(GlDropdown);
const findGlDropdownSearch = () => findGlDropdown().findComponent(GlSearchBoxByType);
const findDropdownText = () => findGlDropdown().find('.dropdown-toggle-text');
@@ -133,9 +129,7 @@ describe('Global Search Searchable Dropdown', () => {
describe(`when search is ${searchText} and frequentItems length is ${frequentItems.length}`, () => {
beforeEach(() => {
createComponent({}, { frequentItems });
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ searchText });
+ findGlDropdownSearch().vm.$emit('input', searchText);
});
it(`should${length ? '' : ' not'} render frequent dropdown items`, () => {
@@ -191,28 +185,33 @@ describe('Global Search Searchable Dropdown', () => {
});
describe('opening the dropdown', () => {
- describe('for the first time', () => {
- beforeEach(() => {
- findGlDropdown().vm.$emit('show');
- });
+ beforeEach(() => {
+ findGlDropdown().vm.$emit('show');
+ });
- it('$emits @search and @first-open', () => {
- expect(wrapper.emitted('search')[0]).toStrictEqual([wrapper.vm.searchText]);
- expect(wrapper.emitted('first-open')[0]).toStrictEqual([]);
- });
+ it('$emits @search and @first-open on the first open', async () => {
+ expect(wrapper.emitted('search')[0]).toStrictEqual(['']);
+ expect(wrapper.emitted('first-open')[0]).toStrictEqual([]);
});
- describe('not for the first time', () => {
- beforeEach(() => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ hasBeenOpened: true });
- findGlDropdown().vm.$emit('show');
+ describe('when the dropdown has been opened', () => {
+ it('$emits @search with the searchText', async () => {
+ const searchText = 'foo';
+
+ findGlDropdownSearch().vm.$emit('input', searchText);
+ await nextTick();
+
+ expect(wrapper.emitted('search')[1]).toStrictEqual([searchText]);
+ expect(wrapper.emitted('first-open')).toHaveLength(1);
});
- it('$emits @search and not @first-open', () => {
- expect(wrapper.emitted('search')[0]).toStrictEqual([wrapper.vm.searchText]);
- expect(wrapper.emitted('first-open')).toBeUndefined();
+ it('does not emit @first-open again', async () => {
+ expect(wrapper.emitted('first-open')).toHaveLength(1);
+
+ findGlDropdownSearch().vm.$emit('input');
+ await nextTick();
+
+ expect(wrapper.emitted('first-open')).toHaveLength(1);
});
});
});
diff --git a/spec/frontend/search_autocomplete_spec.js b/spec/frontend/search_autocomplete_spec.js
index a3098fb81ea..dfb31eeda78 100644
--- a/spec/frontend/search_autocomplete_spec.js
+++ b/spec/frontend/search_autocomplete_spec.js
@@ -119,7 +119,6 @@ describe('Search autocomplete dropdown', () => {
afterEach(() => {
// Undo what we did to the shared <body>
removeBodyAttributes();
- window.gon = {};
resetHTMLFixture();
});
diff --git a/spec/frontend/search_settings/components/search_settings_spec.js b/spec/frontend/search_settings/components/search_settings_spec.js
index 3f856968db6..fe761049a70 100644
--- a/spec/frontend/search_settings/components/search_settings_spec.js
+++ b/spec/frontend/search_settings/components/search_settings_spec.js
@@ -79,10 +79,6 @@ describe('search_settings/components/search_settings.vue', () => {
buildWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('hides sections that do not match the search term', () => {
const hiddenSection = document.querySelector(`#${GENERAL_SETTINGS_ID}`);
search(SEARCH_TERM);
diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js
index ddefda2ffc3..0ca350f9ed7 100644
--- a/spec/frontend/security_configuration/components/app_spec.js
+++ b/spec/frontend/security_configuration/components/app_spec.js
@@ -26,6 +26,8 @@ import {
REPORT_TYPE_LICENSE_COMPLIANCE,
REPORT_TYPE_SAST,
} from '~/vue_shared/security_reports/constants';
+import { USER_FACING_ERROR_MESSAGE_PREFIX } from '~/lib/utils/error_message';
+import { manageViaMRErrorMessage } from '../constants';
const upgradePath = '/upgrade';
const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath';
@@ -129,10 +131,6 @@ describe('App component', () => {
const findAutoDevopsEnabledAlert = () => wrapper.findComponent(AutoDevopsEnabledAlert);
const findVulnerabilityManagementTab = () => wrapper.findByTestId('vulnerability-management-tab');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('basic structure', () => {
beforeEach(() => {
createComponent();
@@ -141,7 +139,7 @@ describe('App component', () => {
it('renders main-heading with correct text', () => {
const mainHeading = findMainHeading();
expect(mainHeading.exists()).toBe(true);
- expect(mainHeading.text()).toContain('Security Configuration');
+ expect(mainHeading.text()).toContain('Security configuration');
});
describe('tabs', () => {
@@ -204,18 +202,21 @@ describe('App component', () => {
});
});
- describe('when error occurs', () => {
+ describe('when user facing error occurs', () => {
it('should show Alert with error Message', async () => {
expect(findManageViaMRErrorAlert().exists()).toBe(false);
- findFeatureCards().at(1).vm.$emit('error', 'There was a manage via MR error');
+ // Prefixed with USER_FACING_ERROR_MESSAGE_PREFIX as used in lib/gitlab/utils/error_message.rb to indicate a user facing error
+ findFeatureCards()
+ .at(1)
+ .vm.$emit('error', `${USER_FACING_ERROR_MESSAGE_PREFIX} ${manageViaMRErrorMessage}`);
await nextTick();
expect(findManageViaMRErrorAlert().exists()).toBe(true);
- expect(findManageViaMRErrorAlert().text()).toEqual('There was a manage via MR error');
+ expect(findManageViaMRErrorAlert().text()).toEqual(manageViaMRErrorMessage);
});
it('should hide Alert when it is dismissed', async () => {
- findFeatureCards().at(1).vm.$emit('error', 'There was a manage via MR error');
+ findFeatureCards().at(1).vm.$emit('error', manageViaMRErrorMessage);
await nextTick();
expect(findManageViaMRErrorAlert().exists()).toBe(true);
@@ -225,6 +226,17 @@ describe('App component', () => {
expect(findManageViaMRErrorAlert().exists()).toBe(false);
});
});
+
+ describe('when non-user facing error occurs', () => {
+ it('should show Alert with generic error Message', async () => {
+ expect(findManageViaMRErrorAlert().exists()).toBe(false);
+ findFeatureCards().at(1).vm.$emit('error', manageViaMRErrorMessage);
+
+ await nextTick();
+ expect(findManageViaMRErrorAlert().exists()).toBe(true);
+ expect(findManageViaMRErrorAlert().text()).toEqual(i18n.genericErrorText);
+ });
+ });
});
describe('Auto DevOps hint alert', () => {
diff --git a/spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js b/spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js
index 467ae35408c..df1fa1a8084 100644
--- a/spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js
+++ b/spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js
@@ -23,10 +23,6 @@ describe('AutoDevopsAlert component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains correct body text', () => {
expect(wrapper.text()).toContain('Quickly enable all');
});
diff --git a/spec/frontend/security_configuration/components/auto_dev_ops_enabled_alert_spec.js b/spec/frontend/security_configuration/components/auto_dev_ops_enabled_alert_spec.js
index 778fea2896a..22f45a92f70 100644
--- a/spec/frontend/security_configuration/components/auto_dev_ops_enabled_alert_spec.js
+++ b/spec/frontend/security_configuration/components/auto_dev_ops_enabled_alert_spec.js
@@ -21,10 +21,6 @@ describe('AutoDevopsEnabledAlert component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('contains correct body text', () => {
expect(wrapper.text()).toMatchInterpolatedText(AutoDevopsEnabledAlert.i18n.body);
});
diff --git a/spec/frontend/security_configuration/components/feature_card_spec.js b/spec/frontend/security_configuration/components/feature_card_spec.js
index d10722be8ea..23edd8a69de 100644
--- a/spec/frontend/security_configuration/components/feature_card_spec.js
+++ b/spec/frontend/security_configuration/components/feature_card_spec.js
@@ -5,6 +5,7 @@ import FeatureCard from '~/security_configuration/components/feature_card.vue';
import FeatureCardBadge from '~/security_configuration/components/feature_card_badge.vue';
import ManageViaMr from '~/vue_shared/security_configuration/components/manage_via_mr.vue';
import { REPORT_TYPE_SAST } from '~/vue_shared/security_reports/constants';
+import { manageViaMRErrorMessage } from '../constants';
import { makeFeature } from './utils';
describe('FeatureCard component', () => {
@@ -78,7 +79,6 @@ describe('FeatureCard component', () => {
};
afterEach(() => {
- wrapper.destroy();
feature = undefined;
});
@@ -107,8 +107,8 @@ describe('FeatureCard component', () => {
});
it('should catch and emit manage-via-mr-error', () => {
- findManageViaMr().vm.$emit('error', 'There was a manage via MR error');
- expect(wrapper.emitted('error')).toEqual([['There was a manage via MR error']]);
+ findManageViaMr().vm.$emit('error', manageViaMRErrorMessage);
+ expect(wrapper.emitted('error')).toEqual([[manageViaMRErrorMessage]]);
});
});
diff --git a/spec/frontend/security_configuration/components/training_provider_list_spec.js b/spec/frontend/security_configuration/components/training_provider_list_spec.js
index 8f2b5383191..1f8f306c931 100644
--- a/spec/frontend/security_configuration/components/training_provider_list_spec.js
+++ b/spec/frontend/security_configuration/components/training_provider_list_spec.js
@@ -106,7 +106,7 @@ describe('TrainingProviderList component', () => {
projectFullPath: testProjectPath,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: {
securityTrainingEnabled: true,
@@ -132,7 +132,6 @@ describe('TrainingProviderList component', () => {
const toggleFirstProvider = () => findFirstToggle().vm.$emit('change', testProviderIds[0]);
afterEach(() => {
- wrapper.destroy();
apolloProvider = null;
});
diff --git a/spec/frontend/security_configuration/components/upgrade_banner_spec.js b/spec/frontend/security_configuration/components/upgrade_banner_spec.js
index c34d8e47a6c..97087877224 100644
--- a/spec/frontend/security_configuration/components/upgrade_banner_spec.js
+++ b/spec/frontend/security_configuration/components/upgrade_banner_spec.js
@@ -44,7 +44,6 @@ describe('UpgradeBanner component', () => {
});
afterEach(() => {
- wrapper.destroy();
unmockTracking();
});
diff --git a/spec/frontend/security_configuration/constants.js b/spec/frontend/security_configuration/constants.js
new file mode 100644
index 00000000000..d31036a2534
--- /dev/null
+++ b/spec/frontend/security_configuration/constants.js
@@ -0,0 +1 @@
+export const manageViaMRErrorMessage = 'There was a manage via MR error';
diff --git a/spec/frontend/self_monitor/components/__snapshots__/self_monitor_form_spec.js.snap b/spec/frontend/self_monitor/components/__snapshots__/self_monitor_form_spec.js.snap
index efe3f7e8dbf..c278bb4579f 100644
--- a/spec/frontend/self_monitor/components/__snapshots__/self_monitor_form_spec.js.snap
+++ b/spec/frontend/self_monitor/components/__snapshots__/self_monitor_form_spec.js.snap
@@ -40,6 +40,41 @@ exports[`self-monitor component When the self-monitor project has not been creat
</p>
</div>
+ <gl-alert-stub
+ class="gl-mb-3"
+ dismissible="true"
+ dismisslabel="Dismiss"
+ primarybuttonlink=""
+ primarybuttontext=""
+ secondarybuttonlink=""
+ secondarybuttontext=""
+ showicon="true"
+ title="Deprecation notice"
+ variant="danger"
+ >
+ <div>
+ Self-monitoring was
+ <a
+ href="/help/update/deprecations.md#gitlab-self-monitoring-project"
+ >
+ deprecated
+ </a>
+ in GitLab 14.9, and is
+ <a
+ href="https://gitlab.com/gitlab-org/gitlab/-/issues/348909"
+ >
+ scheduled for removal
+ </a>
+ in GitLab 16.0. For information on a possible replacement,
+ <a
+ href="https://gitlab.com/groups/gitlab-org/-/epics/6976"
+ >
+ learn more about Opstrace
+ </a>
+ .
+ </div>
+ </gl-alert-stub>
+
<div
class="settings-content"
>
diff --git a/spec/frontend/sentry/index_spec.js b/spec/frontend/sentry/index_spec.js
index 2dd528a8a1c..83195e9d306 100644
--- a/spec/frontend/sentry/index_spec.js
+++ b/spec/frontend/sentry/index_spec.js
@@ -4,8 +4,6 @@ import LegacySentryConfig from '~/sentry/legacy_sentry_config';
import SentryConfig from '~/sentry/sentry_config';
describe('Sentry init', () => {
- let originalGon;
-
const dsn = 'https://123@sentry.gitlab.test/123';
const environment = 'test';
const currentUserId = '1';
@@ -14,7 +12,6 @@ describe('Sentry init', () => {
const featureCategory = 'my_feature_category';
beforeEach(() => {
- originalGon = window.gon;
window.gon = {
sentry_dsn: dsn,
sentry_environment: environment,
@@ -28,10 +25,6 @@ describe('Sentry init', () => {
jest.spyOn(SentryConfig, 'init').mockImplementation();
});
- afterEach(() => {
- window.gon = originalGon;
- });
-
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\./);
diff --git a/spec/frontend/sentry/legacy_index_spec.js b/spec/frontend/sentry/legacy_index_spec.js
index 5c336f8392e..493b4dfde67 100644
--- a/spec/frontend/sentry/legacy_index_spec.js
+++ b/spec/frontend/sentry/legacy_index_spec.js
@@ -4,8 +4,6 @@ import LegacySentryConfig from '~/sentry/legacy_sentry_config';
import SentryConfig from '~/sentry/sentry_config';
describe('Sentry init', () => {
- let originalGon;
-
const dsn = 'https://123@sentry.gitlab.test/123';
const environment = 'test';
const currentUserId = '1';
@@ -14,7 +12,6 @@ describe('Sentry init', () => {
const featureCategory = 'my_feature_category';
beforeEach(() => {
- originalGon = window.gon;
window.gon = {
sentry_dsn: dsn,
sentry_environment: environment,
@@ -28,10 +25,6 @@ describe('Sentry init', () => {
jest.spyOn(SentryConfig, 'init').mockImplementation();
});
- afterEach(() => {
- window.gon = originalGon;
- });
-
it('exports legacy version of Sentry in the global object', () => {
// eslint-disable-next-line no-underscore-dangle
expect(window._Sentry.SDK_VERSION).toMatch(/^5\./);
diff --git a/spec/frontend/sentry/sentry_config_spec.js b/spec/frontend/sentry/sentry_config_spec.js
index 44acbee9b38..34c5221ef0d 100644
--- a/spec/frontend/sentry/sentry_config_spec.js
+++ b/spec/frontend/sentry/sentry_config_spec.js
@@ -1,5 +1,4 @@
import * as Sentry from 'sentrybrowser7';
-import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from '~/sentry/constants';
import SentryConfig from '~/sentry/sentry_config';
@@ -62,11 +61,8 @@ describe('SentryConfig', () => {
expect(Sentry.init).toHaveBeenCalledWith({
dsn: options.dsn,
release: options.release,
- sampleRate: SAMPLE_RATE,
allowUrls: options.allowUrls,
environment: options.environment,
- ignoreErrors: IGNORE_ERRORS,
- denyUrls: DENY_URLS,
});
});
@@ -82,11 +78,8 @@ describe('SentryConfig', () => {
expect(Sentry.init).toHaveBeenCalledWith({
dsn: options.dsn,
release: options.release,
- sampleRate: SAMPLE_RATE,
allowUrls: options.allowUrls,
environment: 'development',
- ignoreErrors: IGNORE_ERRORS,
- denyUrls: DENY_URLS,
});
});
});
diff --git a/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js b/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js
index 85cd8d51272..b5bf739b35a 100644
--- a/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js
+++ b/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js
@@ -5,13 +5,13 @@ import { useFakeDate } from 'helpers/fake_date';
import { initEmojiMock, clearEmojiMock } from 'helpers/emoji';
import * as UserApi from '~/api/user_api';
import EmojiPicker from '~/emoji/components/picker.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import stubChildren from 'helpers/stub_children';
import SetStatusModalWrapper from '~/set_status_modal/set_status_modal_wrapper.vue';
import { AVAILABILITY_STATUS } from '~/set_status_modal/constants';
import SetStatusForm from '~/set_status_modal/set_status_form.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('SetStatusModalWrapper', () => {
let wrapper;
@@ -72,7 +72,6 @@ describe('SetStatusModalWrapper', () => {
};
afterEach(() => {
- wrapper.destroy();
clearEmojiMock();
});
@@ -244,7 +243,7 @@ describe('SetStatusModalWrapper', () => {
return initModal({ mockOnUpdateFailure: false });
});
- it('flashes an error message', async () => {
+ it('alerts an error message', async () => {
findModal().vm.$emit('primary');
await nextTick();
diff --git a/spec/frontend/set_status_modal/user_profile_set_status_wrapper_spec.js b/spec/frontend/set_status_modal/user_profile_set_status_wrapper_spec.js
index a4a2a86dc73..a6ad90123b7 100644
--- a/spec/frontend/set_status_modal/user_profile_set_status_wrapper_spec.js
+++ b/spec/frontend/set_status_modal/user_profile_set_status_wrapper_spec.js
@@ -37,10 +37,6 @@ describe('UserProfileSetStatusWrapper', () => {
const findInput = (name) => wrapper.find(`[name="${name}"]`);
const findSetStatusForm = () => wrapper.findComponent(SetStatusForm);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders `SetStatusForm` component and passes expected props', () => {
createComponent();
diff --git a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js
index 60edab8766a..81b65f4f050 100644
--- a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js
+++ b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js
@@ -30,10 +30,6 @@ describe('AssigneeAvatarLink component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findTooltipText = () => wrapper.attributes('title');
const findUserLink = () => wrapper.findComponent(GlLink);
diff --git a/spec/frontend/sidebar/components/assignees/assignee_avatar_spec.js b/spec/frontend/sidebar/components/assignees/assignee_avatar_spec.js
index 7df37d11987..b6b3dbd5b6b 100644
--- a/spec/frontend/sidebar/components/assignees/assignee_avatar_spec.js
+++ b/spec/frontend/sidebar/components/assignees/assignee_avatar_spec.js
@@ -7,7 +7,6 @@ const TEST_AVATAR = `${TEST_HOST}/avatar.png`;
const TEST_DEFAULT_AVATAR_URL = `${TEST_HOST}/default/avatar/url.png`;
describe('AssigneeAvatar', () => {
- let origGon;
let wrapper;
function createComponent(props = {}) {
@@ -24,15 +23,9 @@ describe('AssigneeAvatar', () => {
}
beforeEach(() => {
- origGon = window.gon;
window.gon = { default_avatar_url: TEST_DEFAULT_AVATAR_URL };
});
- afterEach(() => {
- window.gon = origGon;
- wrapper.destroy();
- });
-
const findImg = () => wrapper.find('img');
it('does not show warning icon if assignee can merge', () => {
diff --git a/spec/frontend/sidebar/components/assignees/assignee_title_spec.js b/spec/frontend/sidebar/components/assignees/assignee_title_spec.js
index 14a6bdbf907..d561c761c99 100644
--- a/spec/frontend/sidebar/components/assignees/assignee_title_spec.js
+++ b/spec/frontend/sidebar/components/assignees/assignee_title_spec.js
@@ -17,11 +17,6 @@ describe('AssigneeTitle component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('assignee title', () => {
it('renders assignee', () => {
wrapper = createComponent({
diff --git a/spec/frontend/sidebar/components/assignees/assignees_realtime_spec.js b/spec/frontend/sidebar/components/assignees/assignees_realtime_spec.js
index 080171fb2ea..0501c1bae23 100644
--- a/spec/frontend/sidebar/components/assignees/assignees_realtime_spec.js
+++ b/spec/frontend/sidebar/components/assignees/assignees_realtime_spec.js
@@ -49,7 +49,6 @@ describe('Assignees Realtime', () => {
});
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
SidebarMediator.singleton = null;
});
diff --git a/spec/frontend/sidebar/components/assignees/assignees_spec.js b/spec/frontend/sidebar/components/assignees/assignees_spec.js
index d422292ed9e..1661e28abd2 100644
--- a/spec/frontend/sidebar/components/assignees/assignees_spec.js
+++ b/spec/frontend/sidebar/components/assignees/assignees_spec.js
@@ -25,10 +25,6 @@ describe('Assignee component', () => {
const findComponentTextNoUsers = () => wrapper.find('[data-testid="no-value"]');
const findCollapsedChildren = () => wrapper.findAll('.sidebar-collapsed-icon > *');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('No assignees/users', () => {
it('displays no assignee icon when collapsed', () => {
createWrapper();
diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js
index 7e7d4921cfa..40d3d090bb4 100644
--- a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js
+++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js
@@ -26,10 +26,6 @@ describe('CollapsedAssigneeList component', () => {
const findAssignees = () => wrapper.findAllComponents(CollapsedAssignee);
const getTooltipTitle = () => wrapper.attributes('title');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('No assignees/users', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js
index 4db95114b96..851eaedf0bd 100644
--- a/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js
+++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js
@@ -21,10 +21,6 @@ describe('CollapsedAssignee assignee component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has author name', () => {
createComponent();
diff --git a/spec/frontend/sidebar/components/assignees/issuable_assignees_spec.js b/spec/frontend/sidebar/components/assignees/issuable_assignees_spec.js
index 1161fefcc64..82145b82e21 100644
--- a/spec/frontend/sidebar/components/assignees/issuable_assignees_spec.js
+++ b/spec/frontend/sidebar/components/assignees/issuable_assignees_spec.js
@@ -20,11 +20,6 @@ describe('IssuableAssignees', () => {
const findUncollapsedAssigneeList = () => wrapper.findComponent(UncollapsedAssigneeList);
const findEmptyAssignee = () => wrapper.find('[data-testid="none"]');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when no assignees are present', () => {
it.each`
signedIn | editable | message
diff --git a/spec/frontend/sidebar/components/assignees/sidebar_assignees_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_assignees_spec.js
index 58b174059fa..a189d3656a2 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_assignees_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_assignees_spec.js
@@ -39,9 +39,6 @@ describe('sidebar assignees', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
-
SidebarService.singleton = null;
SidebarStore.singleton = null;
SidebarMediator.singleton = null;
diff --git a/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
index 3aca346ff5f..9f7c587ca9d 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
@@ -5,8 +5,8 @@ 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 '~/flash';
-import { IssuableType } from '~/issues/constants';
+import { createAlert } from '~/alert';
+import { TYPE_MERGE_REQUEST } from '~/issues/constants';
import SidebarAssigneesRealtime from '~/sidebar/components/assignees/assignees_realtime.vue';
import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees.vue';
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
@@ -17,7 +17,7 @@ import updateIssueAssigneesMutation from '~/sidebar/queries/update_issue_assigne
import UserSelect from '~/vue_shared/components/user_select/user_select.vue';
import { issuableQueryResponse, updateIssueAssigneesMutationResponse } from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const updateIssueAssigneesMutationSuccess = jest
.fn()
@@ -98,10 +98,7 @@ describe('Sidebar assignees widget', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
fakeApollo = null;
- delete gon.current_username;
});
describe('with passed initial assignees', () => {
@@ -397,7 +394,7 @@ describe('Sidebar assignees widget', () => {
});
it('does not render invite members link on non-issue sidebar', async () => {
- createComponent({ props: { issuableType: IssuableType.MergeRequest } });
+ createComponent({ props: { issuableType: TYPE_MERGE_REQUEST } });
await waitForPromises();
expect(findInviteMembersLink().exists()).toBe(false);
});
diff --git a/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js
index 6c22d2f687d..27c31ac56c9 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js
@@ -21,11 +21,6 @@ describe('boards sidebar remove issue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('template', () => {
it('renders title', () => {
const title = 'Sidebar item title';
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 b738d931040..501048bf056 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_invite_members_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_invite_members_spec.js
@@ -16,10 +16,6 @@ describe('Sidebar invite members component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when directly inviting members', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js
index be0b14fa997..7895274ab6d 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js
@@ -1,6 +1,6 @@
import { GlAvatarLabeled, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import SidebarParticipant from '~/sidebar/components/assignees/sidebar_participant.vue';
const user = {
@@ -32,10 +32,6 @@ describe('Sidebar participant component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not show `Busy` status when user is not busy', () => {
createComponent();
@@ -56,13 +52,13 @@ describe('Sidebar participant component', () => {
describe('when on merge request sidebar', () => {
it('when project member cannot merge', () => {
- createComponent({ issuableType: IssuableType.MergeRequest });
+ createComponent({ issuableType: TYPE_MERGE_REQUEST });
expect(findIcon().exists()).toBe(true);
});
it('when project member can merge', () => {
- createComponent({ issuableType: IssuableType.MergeRequest, canMerge: true });
+ createComponent({ issuableType: TYPE_MERGE_REQUEST, canMerge: true });
expect(findIcon().exists()).toBe(false);
});
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 03c2e1a37a9..c74a714cca4 100644
--- a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js
+++ b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js
@@ -24,10 +24,6 @@ describe('UncollapsedAssigneeList component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findMoreButton = () => wrapper.find('.user-list-more button');
describe('One assignee/user', () => {
diff --git a/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js b/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
index 37c16bc9235..877d7cd61ee 100644
--- a/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
+++ b/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
@@ -18,10 +18,6 @@ describe('UserNameWithStatus', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('will render the users name', () => {
expect(wrapper.html()).toContain(name);
});
diff --git a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js
index 81354d64a90..4a2b3b30e6d 100644
--- a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js
+++ b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_content_spec.js
@@ -18,10 +18,6 @@ describe('Sidebar Confidentiality Content', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('emits `expandSidebar` event on collapsed icon click', () => {
createComponent();
findCollapsedIcon().trigger('click');
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 b27f7c6b4e1..1ca20dad1c6 100644
--- a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js
+++ b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js
@@ -2,11 +2,11 @@ import { GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import SidebarConfidentialityForm from '~/sidebar/components/confidential/sidebar_confidentiality_form.vue';
import { confidentialityQueries } from '~/sidebar/constants';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Sidebar Confidentiality Form', () => {
let wrapper;
@@ -38,10 +38,6 @@ describe('Sidebar Confidentiality Form', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('emits a `closeForm` event when Cancel button is clicked', () => {
createComponent();
findCancelButton().vm.$emit('click');
@@ -58,7 +54,7 @@ describe('Sidebar Confidentiality Form', () => {
expect(findConfidentialToggle().props('loading')).toBe(true);
});
- it('creates a flash if mutation is rejected', async () => {
+ it('creates an alert if mutation is rejected', async () => {
createComponent({ mutate: jest.fn().mockRejectedValue('Error!') });
findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
await waitForPromises();
@@ -68,7 +64,7 @@ describe('Sidebar Confidentiality Form', () => {
});
});
- it('creates a flash if mutation contains errors', async () => {
+ it('creates an alert if mutation contains errors', async () => {
createComponent({
mutate: jest.fn().mockResolvedValue({
data: { issuableSetConfidential: { errors: ['Houston, we have a problem!'] } },
diff --git a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js
index e486a8e9ec7..39b30307dd7 100644
--- a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js
+++ b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js
@@ -4,7 +4,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import SidebarConfidentialityContent from '~/sidebar/components/confidential/sidebar_confidentiality_content.vue';
import SidebarConfidentialityForm from '~/sidebar/components/confidential/sidebar_confidentiality_form.vue';
import SidebarConfidentialityWidget, {
@@ -14,7 +14,7 @@ import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'
import issueConfidentialQuery from '~/sidebar/queries/issue_confidential.query.graphql';
import { issueConfidentialityResponse } from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -48,7 +48,6 @@ describe('Sidebar Confidentiality Widget', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -120,7 +119,7 @@ describe('Sidebar Confidentiality Widget', () => {
});
});
- it('displays a flash message when query is rejected', async () => {
+ it('displays an alert message when query is rejected', async () => {
createComponent({
confidentialQueryHandler: jest.fn().mockRejectedValue('Houston, we have a problem'),
});
diff --git a/spec/frontend/sidebar/components/copy/copyable_field_spec.js b/spec/frontend/sidebar/components/copy/copyable_field_spec.js
index 7790d77bc65..03e131aab35 100644
--- a/spec/frontend/sidebar/components/copy/copyable_field_spec.js
+++ b/spec/frontend/sidebar/components/copy/copyable_field_spec.js
@@ -20,10 +20,6 @@ describe('SidebarCopyableField', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
diff --git a/spec/frontend/sidebar/components/copy/sidebar_reference_widget_spec.js b/spec/frontend/sidebar/components/copy/sidebar_reference_widget_spec.js
index c3de076d6aa..2ae80b2c97b 100644
--- a/spec/frontend/sidebar/components/copy/sidebar_reference_widget_spec.js
+++ b/spec/frontend/sidebar/components/copy/sidebar_reference_widget_spec.js
@@ -3,7 +3,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { IssuableType, TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import SidebarReferenceWidget from '~/sidebar/components/copy/sidebar_reference_widget.vue';
import issueReferenceQuery from '~/sidebar/queries/issue_reference.query.graphql';
import mergeRequestReferenceQuery from '~/sidebar/queries/merge_request_reference.query.graphql';
@@ -39,10 +39,6 @@ describe('Sidebar Reference Widget', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when reference is loading', () => {
it('sets CopyableField `is-loading` prop to `true`', () => {
createComponent({ referenceQueryHandler: jest.fn().mockReturnValue(new Promise(() => {})) });
@@ -52,7 +48,7 @@ describe('Sidebar Reference Widget', () => {
describe.each([
[TYPE_ISSUE, issueReferenceQuery],
- [IssuableType.MergeRequest, mergeRequestReferenceQuery],
+ [TYPE_MERGE_REQUEST, mergeRequestReferenceQuery],
])('when issuableType is %s', (issuableType, referenceQuery) => {
it('sets CopyableField `value` prop to reference value', async () => {
createComponent({
diff --git a/spec/frontend/sidebar/components/crm_contacts/crm_contacts_spec.js b/spec/frontend/sidebar/components/crm_contacts/crm_contacts_spec.js
index ca43c219d92..546cabd07d3 100644
--- a/spec/frontend/sidebar/components/crm_contacts/crm_contacts_spec.js
+++ b/spec/frontend/sidebar/components/crm_contacts/crm_contacts_spec.js
@@ -3,7 +3,7 @@ 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 { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import CrmContacts from '~/sidebar/components/crm_contacts/crm_contacts.vue';
import getIssueCrmContactsQuery from '~/sidebar/queries/get_issue_crm_contacts.query.graphql';
import issueCrmContactsSubscription from '~/sidebar/queries/issue_crm_contacts.subscription.graphql';
@@ -13,7 +13,7 @@ import {
issueCrmContactsUpdateNullResponse,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Issue crm contacts component', () => {
Vue.use(VueApollo);
@@ -39,7 +39,6 @@ describe('Issue crm contacts component', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
diff --git a/spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js b/spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js
index 67413cffdda..b9c8655d5d8 100644
--- a/spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js
+++ b/spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js
@@ -4,7 +4,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import SidebarDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue';
import SidebarFormattedDate from '~/sidebar/components/date/sidebar_formatted_date.vue';
import SidebarInheritDate from '~/sidebar/components/date/sidebar_inherit_date.vue';
@@ -13,7 +13,7 @@ import epicStartDateQuery from '~/sidebar/queries/epic_start_date.query.graphql'
import issueDueDateQuery from '~/sidebar/queries/issue_due_date.query.graphql';
import { issuableDueDateResponse, issuableStartDateResponse } from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -22,10 +22,6 @@ describe('Sidebar date Widget', () => {
let fakeApollo;
const date = '2021-04-15';
- window.gon = {
- first_day_of_week: 1,
- };
-
const findEditableItem = () => wrapper.findComponent(SidebarEditableItem);
const findPopoverIcon = () => wrapper.find('[data-testid="inherit-date-popover"]');
const findDatePicker = () => wrapper.findComponent(GlDatepicker);
@@ -61,8 +57,11 @@ describe('Sidebar date Widget', () => {
});
};
+ beforeEach(() => {
+ window.gon.first_day_of_week = 1;
+ });
+
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -159,7 +158,7 @@ describe('Sidebar date Widget', () => {
expect(wrapper.findComponent(SidebarInheritDate).exists()).toBe(false);
});
- it('displays a flash message when query is rejected', async () => {
+ it('displays an alert message when query is rejected', async () => {
createComponent({
dueDateQueryHandler: jest.fn().mockRejectedValue('Houston, we have a problem'),
});
diff --git a/spec/frontend/sidebar/components/date/sidebar_formatted_date_spec.js b/spec/frontend/sidebar/components/date/sidebar_formatted_date_spec.js
index cbe01263dcd..1bb910c53ea 100644
--- a/spec/frontend/sidebar/components/date/sidebar_formatted_date_spec.js
+++ b/spec/frontend/sidebar/components/date/sidebar_formatted_date_spec.js
@@ -27,10 +27,6 @@ describe('SidebarFormattedDate', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays formatted date', () => {
expect(findFormattedDate().text()).toBe('Apr 15, 2021');
});
diff --git a/spec/frontend/sidebar/components/date/sidebar_inherit_date_spec.js b/spec/frontend/sidebar/components/date/sidebar_inherit_date_spec.js
index a7556b9110c..97debe3088d 100644
--- a/spec/frontend/sidebar/components/date/sidebar_inherit_date_spec.js
+++ b/spec/frontend/sidebar/components/date/sidebar_inherit_date_spec.js
@@ -31,10 +31,6 @@ describe('SidebarInheritDate', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays formatted fixed and inherited dates with radio buttons', () => {
expect(wrapper.findAllComponents(SidebarFormattedDate)).toHaveLength(2);
expect(wrapper.findAllComponents(GlFormRadio)).toHaveLength(2);
diff --git a/spec/frontend/sidebar/components/incidents/escalation_status_spec.js b/spec/frontend/sidebar/components/incidents/escalation_status_spec.js
index 1a78ce4ddee..e356f02a36b 100644
--- a/spec/frontend/sidebar/components/incidents/escalation_status_spec.js
+++ b/spec/frontend/sidebar/components/incidents/escalation_status_spec.js
@@ -17,10 +17,6 @@ describe('EscalationStatus', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDropdownComponent = () => wrapper.findComponent(GlDropdown);
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findDropdownMenu = () => findDropdownComponent().find('.dropdown-menu');
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 2dded61c073..00b57b4916e 100644
--- a/spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js
+++ b/spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js
@@ -18,11 +18,11 @@ import {
} from '~/sidebar/constants';
import waitForPromises from 'helpers/wait_for_promises';
import EscalationStatus from 'ee_else_ce/sidebar/components/incidents/escalation_status.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { logError } from '~/lib/logger';
jest.mock('~/lib/logger');
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -57,7 +57,7 @@ describe('SidebarEscalationStatus', () => {
canUpdate: true,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
apolloProvider,
});
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_button_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_button_spec.js
index 4f2a89e20db..084ca5ed3fc 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_button_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_button_spec.js
@@ -29,10 +29,6 @@ describe('DropdownButton', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDropdownButton = () => wrapper.findComponent(GlButton);
const findDropdownText = () => wrapper.find('.dropdown-toggle-text');
const findDropdownIcon = () => wrapper.findComponent(GlIcon);
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js
index 59e95edfa20..bb7554ff21d 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js
@@ -32,10 +32,6 @@ describe('DropdownContentsCreateView', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
describe('disableCreate', () => {
it('returns `true` when label title and color is not defined', () => {
@@ -174,11 +170,17 @@ describe('DropdownContentsCreateView', () => {
});
await nextTick();
- const colorPreviewEl = wrapper.find('.color-input-container > .dropdown-label-color-preview');
- const colorInputEl = wrapper.find('.color-input-container').findComponent(GlFormInput);
+ const colorPreviewEl = wrapper
+ .find('.color-input-container')
+ .findAllComponents(GlFormInput)
+ .at(0);
+ const colorInputEl = wrapper
+ .find('.color-input-container')
+ .findAllComponents(GlFormInput)
+ .at(1);
expect(colorPreviewEl.exists()).toBe(true);
- expect(colorPreviewEl.attributes('style')).toContain('background-color');
+ expect(colorPreviewEl.attributes('value')).toBe('#ff0000');
expect(colorInputEl.exists()).toBe(true);
expect(colorInputEl.attributes('placeholder')).toBe('Use custom color #FF0000');
expect(colorInputEl.attributes('value')).toBe('#ff0000');
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js
index 865dc8fe8fb..7940518f1e8 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js
@@ -51,10 +51,6 @@ describe('DropdownContentsLabelsView', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDropdownContent = () => wrapper.find('[data-testid="dropdown-content"]');
const findDropdownTitle = () => wrapper.find('[data-testid="dropdown-title"]');
const findDropdownFooter = () => wrapper.find('[data-testid="dropdown-footer"]');
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_spec.js
index e9ffda7c251..0a17c5f8721 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_spec.js
@@ -28,10 +28,6 @@ describe('DropdownContent', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
describe('dropdownContentsView', () => {
it('returns string "dropdown-contents-create-view" when `showDropdownContentsCreateView` prop is `true`', () => {
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_title_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_title_spec.js
index 6c3fda421ff..367f6007194 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_title_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_title_spec.js
@@ -31,10 +31,6 @@ describe('DropdownTitle', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
it('renders component container element with string "Labels"', () => {
expect(wrapper.text()).toContain('Labels');
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_collapsed_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_collapsed_spec.js
index 56f25a1c6a4..6684cf0c5f4 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_collapsed_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_collapsed_spec.js
@@ -19,15 +19,11 @@ describe('DropdownValueCollapsedComponent', () => {
wrapper = shallowMount(DropdownValueCollapsedComponent, {
propsData: { ...defaultProps, ...props },
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlIcon = () => wrapper.findComponent(GlIcon);
const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip');
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_spec.js
index a1ccc9d2ab1..70aafceb00c 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_value_spec.js
@@ -28,10 +28,6 @@ describe('DropdownValue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('methods', () => {
describe('labelFilterUrl', () => {
it('returns a label filter URL based on provided label param', () => {
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/label_item_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/label_item_spec.js
index e14c0e308ce..468dd14c9ee 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/label_item_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/label_item_spec.js
@@ -26,10 +26,6 @@ describe('LabelItem', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
it('renders gl-link component', () => {
expect(wrapper.findComponent(GlLink).exists()).toBe(true);
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/labels_select_root_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/labels_select_root_spec.js
index a3b10c18374..806064b2202 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/labels_select_root_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/labels_select_root_spec.js
@@ -40,10 +40,6 @@ describe('LabelsSelectRoot', () => {
store = new Vuex.Store(labelsSelectModule());
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('methods', () => {
describe('handleVuexActionDispatch', () => {
const touchedLabels = [
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/store/actions_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/store/actions_spec.js
index 55651bccaa8..c27afb75375 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/store/actions_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/store/actions_spec.js
@@ -1,14 +1,14 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+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 * as actions from '~/sidebar/components/labels/labels_select_vue/store/actions';
import * as types from '~/sidebar/components/labels/labels_select_vue/store/mutation_types';
import defaultState from '~/sidebar/components/labels/labels_select_vue/store/state';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('LabelsSelect Actions', () => {
let state;
@@ -100,7 +100,7 @@ describe('LabelsSelect Actions', () => {
);
});
- it('shows flash error', () => {
+ it('shows alert error', () => {
actions.receiveLabelsFailure({ commit: () => {} });
expect(createAlert).toHaveBeenCalledWith({ message: 'Error fetching labels.' });
@@ -184,7 +184,7 @@ describe('LabelsSelect Actions', () => {
);
});
- it('shows flash error', () => {
+ it('shows alert error', () => {
actions.receiveCreateLabelFailure({ commit: () => {} });
expect(createAlert).toHaveBeenCalledWith({ message: 'Error creating label.' });
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 79b164b0ea7..4ca0a813da2 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
@@ -4,7 +4,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import { workspaceLabelsQueries } from '~/sidebar/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';
@@ -15,7 +15,7 @@ import {
workspaceLabelsQueryResponse,
} from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const colors = Object.keys(mockSuggestedColors);
@@ -87,10 +87,6 @@ describe('DropdownContentsCreateView', () => {
gon.suggested_label_colors = mockSuggestedColors;
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a palette of 21 colors', () => {
createComponent();
expect(findAllColors()).toHaveLength(21);
@@ -103,7 +99,7 @@ describe('DropdownContentsCreateView', () => {
findAllColors().at(0).vm.$emit('click', new Event('mouseclick'));
await nextTick();
- expect(findSelectedColor().attributes('style')).toBe('background-color: rgb(0, 153, 102);');
+ expect(findSelectedColor().attributes('value')).toBe('#009966');
});
it('shows correct color hex code after selecting a color', async () => {
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view_spec.js
index 913badccbe4..c351a60735b 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view_spec.js
@@ -9,7 +9,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { DropdownVariant } from '~/sidebar/components/labels/labels_select_widget/constants';
import DropdownContentsLabelsView from '~/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue';
@@ -17,7 +17,7 @@ import projectLabelsQuery from '~/sidebar/components/labels/labels_select_widget
import LabelItem from '~/sidebar/components/labels/labels_select_widget/label_item.vue';
import { mockConfig, workspaceLabelsQueryResponse } from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -64,10 +64,6 @@ describe('DropdownContentsLabelsView', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findLabels = () => wrapper.findAllComponents(LabelItem);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findObserver = () => wrapper.findComponent(GlIntersectionObserver);
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_spec.js
index 9bbb1413ee9..e9023cb9ff6 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_spec.js
@@ -66,10 +66,6 @@ describe('DropdownContent', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findCreateView = () => wrapper.findComponent(DropdownContentsCreateView);
const findLabelsView = () => wrapper.findComponent(DropdownContentsLabelsView);
const findDropdownHeader = () => wrapper.findComponent(DropdownHeaderStub);
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 9a6e0ca3ccd..ad1edaa6671 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
@@ -20,10 +20,6 @@ describe('DropdownFooter', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findCreateLabelButton = () => wrapper.find('[data-testid="create-label-button"]');
describe('Labels view', () => {
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_header_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_header_spec.js
index d9001dface4..824f91812fb 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_header_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_header_spec.js
@@ -28,10 +28,6 @@ describe('DropdownHeader', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSearchInput = () => wrapper.findComponent(GlSearchBoxByType);
const findGoBackButton = () => wrapper.findByTestId('go-back-button');
const findDropdownTitle = () => wrapper.findByTestId('dropdown-header-title');
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js
index 585048983c9..d70b989b493 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_value_spec.js
@@ -30,10 +30,6 @@ describe('DropdownValue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when there are no labels', () => {
beforeEach(() => {
createComponent(
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/embedded_labels_list_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/embedded_labels_list_spec.js
index 4fa65c752f9..715dd4e034e 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/embedded_labels_list_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/embedded_labels_list_spec.js
@@ -30,10 +30,6 @@ describe('EmbeddedLabelsList', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when there are no labels', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/label_item_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/label_item_spec.js
index 74188a77994..377d1894411 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/label_item_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/label_item_spec.js
@@ -19,10 +19,6 @@ describe('LabelItem', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
it('renders label color element', () => {
const colorEl = wrapper.find('[data-testid="label-color-box"]');
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js
index fd8e72bac49..3101fd90f2e 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/labels_select_root_spec.js
@@ -3,8 +3,8 @@ 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 '~/flash';
-import { IssuableType, TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
+import { createAlert } from '~/alert';
+import { TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST, TYPE_TEST_CASE } from '~/issues/constants';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import DropdownContents from '~/sidebar/components/labels/labels_select_widget/dropdown_contents.vue';
import DropdownValue from '~/sidebar/components/labels/labels_select_widget/dropdown_value.vue';
@@ -25,7 +25,7 @@ import {
mockRegularLabel,
} from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -36,9 +36,9 @@ const errorQueryHandler = jest.fn().mockRejectedValue('Houston, we have a proble
const updateLabelsMutation = {
[TYPE_ISSUE]: updateIssueLabelsMutation,
- [IssuableType.MergeRequest]: updateMergeRequestLabelsMutation,
+ [TYPE_MERGE_REQUEST]: updateMergeRequestLabelsMutation,
[TYPE_EPIC]: updateEpicLabelsMutation,
- [IssuableType.TestCase]: updateTestCaseLabelsMutation,
+ [TYPE_TEST_CASE]: updateTestCaseLabelsMutation,
};
describe('LabelsSelectRoot', () => {
@@ -83,10 +83,6 @@ describe('LabelsSelectRoot', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders component with classes `labels-select-wrapper gl-relative`', () => {
createComponent();
expect(wrapper.classes()).toEqual(['labels-select-wrapper', 'gl-relative']);
@@ -150,7 +146,7 @@ describe('LabelsSelectRoot', () => {
});
});
- it('creates flash with error message when query is rejected', async () => {
+ it('creates alert with error message when query is rejected', async () => {
createComponent({ queryHandler: errorQueryHandler });
await waitForPromises();
expect(createAlert).toHaveBeenCalledWith({ message: 'Error fetching labels.' });
@@ -214,9 +210,9 @@ describe('LabelsSelectRoot', () => {
describe.each`
issuableType
${TYPE_ISSUE}
- ${IssuableType.MergeRequest}
+ ${TYPE_MERGE_REQUEST}
${TYPE_EPIC}
- ${IssuableType.TestCase}
+ ${TYPE_TEST_CASE}
`('when updating labels for $issuableType', ({ issuableType }) => {
const label = { id: 'gid://gitlab/ProjectLabel/2' };
diff --git a/spec/frontend/sidebar/components/lock/edit_form_buttons_spec.js b/spec/frontend/sidebar/components/lock/edit_form_buttons_spec.js
index 2abb0c24d7d..ad9efc371f0 100644
--- a/spec/frontend/sidebar/components/lock/edit_form_buttons_spec.js
+++ b/spec/frontend/sidebar/components/lock/edit_form_buttons_spec.js
@@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { createStore as createMrStore } from '~/mr_notes/stores';
import createStore from '~/notes/stores';
import EditFormButtons from '~/sidebar/components/lock/edit_form_buttons.vue';
@@ -8,7 +8,7 @@ import eventHub from '~/sidebar/event_hub';
import { ISSUABLE_TYPE_ISSUE, ISSUABLE_TYPE_MR } from './constants';
jest.mock('~/sidebar/event_hub', () => ({ $emit: jest.fn() }));
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('EditFormButtons', () => {
let wrapper;
@@ -51,11 +51,6 @@ describe('EditFormButtons', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe.each`
pageType
${ISSUABLE_TYPE_ISSUE} | ${ISSUABLE_TYPE_MR}
@@ -128,7 +123,7 @@ describe('EditFormButtons', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('closeLockForm');
});
- it('does not flash an error message', () => {
+ it('does not alert an error message', () => {
expect(createAlert).not.toHaveBeenCalled();
});
});
@@ -161,7 +156,7 @@ describe('EditFormButtons', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('closeLockForm');
});
- it('calls flash with the correct message', () => {
+ it('calls alert with the correct message', () => {
expect(createAlert).toHaveBeenCalledWith({
message: `Something went wrong trying to change the locked state of this ${issuableDisplayName}`,
});
diff --git a/spec/frontend/sidebar/components/lock/edit_form_spec.js b/spec/frontend/sidebar/components/lock/edit_form_spec.js
index 4ae9025ee39..06cce7bd7ca 100644
--- a/spec/frontend/sidebar/components/lock/edit_form_spec.js
+++ b/spec/frontend/sidebar/components/lock/edit_form_spec.js
@@ -24,11 +24,6 @@ describe('Edit Form Dropdown', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe.each`
pageType
${ISSUABLE_TYPE_ISSUE} | ${ISSUABLE_TYPE_MR}
diff --git a/spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js b/spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js
index 8f825847cfc..d26ef7298ce 100644
--- a/spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js
+++ b/spec/frontend/sidebar/components/lock/issuable_lock_form_spec.js
@@ -62,16 +62,11 @@ describe('IssuableLockForm', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe.each`
pageType
${ISSUABLE_TYPE_ISSUE} | ${ISSUABLE_TYPE_MR}
diff --git a/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js b/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js
index b492753867b..8a0db1715f3 100644
--- a/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js
+++ b/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js
@@ -1,7 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { TYPE_ISSUE, WorkspaceType } from '~/issues/constants';
+import { TYPE_ISSUE, WORKSPACE_PROJECT } from '~/issues/constants';
import { __ } from '~/locale';
import MilestoneDropdown from '~/sidebar/components/milestone/milestone_dropdown.vue';
import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
@@ -12,7 +12,7 @@ describe('MilestoneDropdown component', () => {
const propsData = {
attrWorkspacePath: 'full/path',
issuableType: TYPE_ISSUE,
- workspaceType: WorkspaceType.project,
+ workspaceType: WORKSPACE_PROJECT,
};
const findHiddenInput = () => wrapper.find('input');
diff --git a/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js b/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
index 72279f44e80..e247f5d27fa 100644
--- a/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
+++ b/spec/frontend/sidebar/components/move/issuable_move_dropdown_spec.js
@@ -63,7 +63,6 @@ describe('IssuableMoveDropdown', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/sidebar/components/move/move_issue_button_spec.js b/spec/frontend/sidebar/components/move/move_issue_button_spec.js
index acd6b23c1f5..eb5e23c6047 100644
--- a/spec/frontend/sidebar/components/move/move_issue_button_spec.js
+++ b/spec/frontend/sidebar/components/move/move_issue_button_spec.js
@@ -4,14 +4,14 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { visitUrl } from '~/lib/utils/url_utility';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import ProjectSelect from '~/sidebar/components/move/issuable_move_dropdown.vue';
import MoveIssueButton from '~/sidebar/components/move/move_issue_button.vue';
import moveIssueMutation from '~/sidebar/queries/move_issue.mutation.graphql';
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn(),
}));
@@ -118,7 +118,7 @@ describe('MoveIssueButton', () => {
expect(findProjectSelect().props('moveInProgress')).toBe(false);
});
- it('creates a flash and logs errors when a mutation returns errors', async () => {
+ it('creates an alert and logs errors when a mutation returns errors', async () => {
createComponent(resolvedMutationWithErrorsMock);
emitProjectSelectEvent();
diff --git a/spec/frontend/sidebar/components/move/move_issues_button_spec.js b/spec/frontend/sidebar/components/move/move_issues_button_spec.js
index c65bad642a0..662a39c829d 100644
--- a/spec/frontend/sidebar/components/move/move_issues_button_spec.js
+++ b/spec/frontend/sidebar/components/move/move_issues_button_spec.js
@@ -6,7 +6,7 @@ import { GlAlert } from '@gitlab/ui';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { logError } from '~/lib/logger';
import IssuableMoveDropdown from '~/sidebar/components/move/issuable_move_dropdown.vue';
import issuableEventHub from '~/issues/list/eventhub';
@@ -22,7 +22,7 @@ import {
WORK_ITEM_TYPE_ENUM_TEST_CASE,
} from '~/work_items/constants';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/logger');
useMockLocationHelper();
@@ -159,7 +159,6 @@ describe('MoveIssuesButton', () => {
});
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -389,7 +388,7 @@ describe('MoveIssuesButton', () => {
});
describe('shows errors', () => {
- it('does not create flashes or logs errors when no issue is selected', async () => {
+ it('does not create alerts or logs errors when no issue is selected', async () => {
createComponent();
emitMoveIssuablesEvent();
@@ -399,7 +398,7 @@ describe('MoveIssuesButton', () => {
expect(createAlert).not.toHaveBeenCalled();
});
- it('does not create flashes or logs errors when only tasks are selected', async () => {
+ it('does not create alerts or logs errors when only tasks are selected', async () => {
createComponent({ selectedIssuables: selectedIssuesMocks.tasksOnly });
emitMoveIssuablesEvent();
@@ -409,7 +408,7 @@ describe('MoveIssuesButton', () => {
expect(createAlert).not.toHaveBeenCalled();
});
- it('does not create flashes or logs errors when only test cases are selected', async () => {
+ it('does not create alerts or logs errors when only test cases are selected', async () => {
createComponent({ selectedIssuables: selectedIssuesMocks.testCasesOnly });
emitMoveIssuablesEvent();
@@ -419,7 +418,7 @@ describe('MoveIssuesButton', () => {
expect(createAlert).not.toHaveBeenCalled();
});
- it('does not create flashes or logs errors when only tasks and test cases are selected', async () => {
+ it('does not create alerts or logs errors when only tasks and test cases are selected', async () => {
createComponent({ selectedIssuables: selectedIssuesMocks.tasksAndTestCases });
emitMoveIssuablesEvent();
@@ -429,7 +428,7 @@ describe('MoveIssuesButton', () => {
expect(createAlert).not.toHaveBeenCalled();
});
- it('does not create flashes or logs errors when issues are moved without errors', async () => {
+ it('does not create alerts or logs errors when issues are moved without errors', async () => {
createComponent(
{ selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
resolvedMutationWithoutErrorsMock,
@@ -442,7 +441,7 @@ describe('MoveIssuesButton', () => {
expect(createAlert).not.toHaveBeenCalled();
});
- it('creates a flash and logs errors when a mutation returns errors', async () => {
+ it('creates an alert and logs errors when a mutation returns errors', async () => {
createComponent(
{ selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
resolvedMutationWithErrorsMock,
@@ -462,14 +461,14 @@ describe('MoveIssuesButton', () => {
`Error moving issue. Error message: ${mockMutationErrorMessage}`,
);
- // Only one flash is created even if multiple errors are reported
+ // Only one alert is created even if multiple errors are reported
expect(createAlert).toHaveBeenCalledTimes(1);
expect(createAlert).toHaveBeenCalledWith({
message: 'There was an error while moving the issues.',
});
});
- it('creates a flash but not logs errors when a mutation is rejected', async () => {
+ it('creates an alert but not logs errors when a mutation is rejected', async () => {
createComponent({ selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases });
emitMoveIssuablesEvent();
diff --git a/spec/frontend/sidebar/components/participants/participants_spec.js b/spec/frontend/sidebar/components/participants/participants_spec.js
index f7a626a189c..72d83ebeca4 100644
--- a/spec/frontend/sidebar/components/participants/participants_spec.js
+++ b/spec/frontend/sidebar/components/participants/participants_spec.js
@@ -1,203 +1,114 @@
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
import Participants from '~/sidebar/components/participants/participants.vue';
-const PARTICIPANT = {
- id: 1,
- state: 'active',
- username: 'marcene',
- name: 'Allie Will',
- web_url: 'foo.com',
- avatar_url: 'gravatar.com/avatar/xxx',
-};
-
-const PARTICIPANT_LIST = [PARTICIPANT, { ...PARTICIPANT, id: 2 }, { ...PARTICIPANT, id: 3 }];
-
-describe('Participants', () => {
+describe('Participants component', () => {
let wrapper;
- const getMoreParticipantsButton = () => wrapper.find('[data-testid="more-participants"]');
- const getCollapsedParticipantsCount = () => wrapper.find('[data-testid="collapsed-count"]');
+ const participant = {
+ id: 1,
+ state: 'active',
+ username: 'marcene',
+ name: 'Allie Will',
+ web_url: 'foo.com',
+ avatar_url: 'gravatar.com/avatar/xxx',
+ };
- const mountComponent = (propsData) =>
- shallowMount(Participants, {
- propsData,
- });
+ const participants = [participant, { ...participant, id: 2 }, { ...participant, id: 3 }];
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findMoreParticipantsButton = () => wrapper.findComponent(GlButton);
+ const findCollapsedIcon = () => wrapper.find('.sidebar-collapsed-icon');
+ const findParticipantsAuthor = () => wrapper.findAll('.participants-author');
+
+ const mountComponent = (propsData) => shallowMount(Participants, { propsData });
describe('collapsed sidebar state', () => {
it('shows loading spinner when loading', () => {
- wrapper = mountComponent({
- loading: true,
- });
+ wrapper = mountComponent({ loading: true });
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ expect(findLoadingIcon().exists()).toBe(true);
});
- it('does not show loading spinner not loading', () => {
- wrapper = mountComponent({
- loading: false,
- });
+ it('does not show loading spinner when not loading', () => {
+ wrapper = mountComponent({ loading: false });
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
+ expect(findLoadingIcon().exists()).toBe(false);
});
it('shows participant count when given', () => {
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- });
+ wrapper = mountComponent({ participants });
- expect(getCollapsedParticipantsCount().text()).toBe(`${PARTICIPANT_LIST.length}`);
+ expect(findCollapsedIcon().text()).toBe(participants.length.toString());
});
it('shows full participant count when there are hidden participants', () => {
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- numberOfLessParticipants: 1,
- });
+ wrapper = mountComponent({ participants, numberOfLessParticipants: 1 });
- expect(getCollapsedParticipantsCount().text()).toBe(`${PARTICIPANT_LIST.length}`);
+ expect(findCollapsedIcon().text()).toBe(participants.length.toString());
});
});
describe('expanded sidebar state', () => {
it('shows loading spinner when loading', () => {
- wrapper = mountComponent({
- loading: true,
- });
+ wrapper = mountComponent({ loading: true });
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ expect(findLoadingIcon().exists()).toBe(true);
});
- it('when only showing visible participants, shows an avatar only for each participant under the limit', async () => {
+ it('when only showing visible participants, shows an avatar only for each participant under the limit', () => {
const numberOfLessParticipants = 2;
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- numberOfLessParticipants,
- });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- isShowingMoreParticipants: false,
- });
-
- await nextTick();
- expect(wrapper.findAll('.participants-author')).toHaveLength(numberOfLessParticipants);
+ wrapper = mountComponent({ participants, numberOfLessParticipants });
+
+ expect(findParticipantsAuthor()).toHaveLength(numberOfLessParticipants);
});
it('when only showing all participants, each has an avatar', async () => {
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- numberOfLessParticipants: 2,
- });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- isShowingMoreParticipants: true,
- });
-
- await nextTick();
- expect(wrapper.findAll('.participants-author')).toHaveLength(PARTICIPANT_LIST.length);
+ wrapper = mountComponent({ participants, numberOfLessParticipants: 2 });
+
+ await findMoreParticipantsButton().vm.$emit('click');
+
+ expect(findParticipantsAuthor()).toHaveLength(participants.length);
});
it('does not have more participants link when they can all be shown', () => {
const numberOfLessParticipants = 100;
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- numberOfLessParticipants,
- });
-
- expect(PARTICIPANT_LIST.length).toBeLessThan(numberOfLessParticipants);
- expect(getMoreParticipantsButton().exists()).toBe(false);
- });
+ wrapper = mountComponent({ participants, numberOfLessParticipants });
- it('when too many participants, has more participants link to show more', async () => {
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- numberOfLessParticipants: 2,
- });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- isShowingMoreParticipants: false,
- });
-
- await nextTick();
- expect(getMoreParticipantsButton().text()).toBe('+ 1 more');
+ expect(participants.length).toBeLessThan(numberOfLessParticipants);
+ expect(findMoreParticipantsButton().exists()).toBe(false);
});
- it('when too many participants and already showing them, has more participants link to show less', async () => {
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- numberOfLessParticipants: 2,
- });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- isShowingMoreParticipants: true,
- });
-
- await nextTick();
- expect(getMoreParticipantsButton().text()).toBe('- show less');
- });
+ it('when too many participants, has more participants link to show more', () => {
+ wrapper = mountComponent({ participants, numberOfLessParticipants: 2 });
- it('clicking more participants link emits event', () => {
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- numberOfLessParticipants: 2,
- });
+ expect(findMoreParticipantsButton().text()).toBe('+ 1 more');
+ });
- expect(wrapper.vm.isShowingMoreParticipants).toBe(false);
+ it('when too many participants and already showing them, has more participants link to show less', async () => {
+ wrapper = mountComponent({ participants, numberOfLessParticipants: 2 });
- getMoreParticipantsButton().vm.$emit('click');
+ await findMoreParticipantsButton().vm.$emit('click');
- expect(wrapper.vm.isShowingMoreParticipants).toBe(true);
+ expect(findMoreParticipantsButton().text()).toBe('- show less');
});
- it('clicking on participants icon emits `toggleSidebar` event', async () => {
- wrapper = mountComponent({
- loading: false,
- participants: PARTICIPANT_LIST,
- numberOfLessParticipants: 2,
- });
-
- const spy = jest.spyOn(wrapper.vm, '$emit');
+ it('clicking on participants icon emits `toggleSidebar` event', () => {
+ wrapper = mountComponent({ participants, numberOfLessParticipants: 2 });
- wrapper.find('.sidebar-collapsed-icon').trigger('click');
+ findCollapsedIcon().trigger('click');
- await nextTick();
- expect(spy).toHaveBeenCalledWith('toggleSidebar');
- spy.mockRestore();
+ expect(wrapper.emitted('toggleSidebar')).toEqual([[]]);
});
});
describe('when not showing participants label', () => {
beforeEach(() => {
- wrapper = mountComponent({
- participants: PARTICIPANT_LIST,
- showParticipantLabel: false,
- });
+ wrapper = mountComponent({ participants, showParticipantLabel: false });
});
it('does not show sidebar collapsed icon', () => {
- expect(wrapper.find('.sidebar-collapsed-icon').exists()).toBe(false);
+ expect(findCollapsedIcon().exists()).toBe(false);
});
it('does not show participants label title', () => {
diff --git a/spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js b/spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js
index 859e63b3df6..914e848eced 100644
--- a/spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js
+++ b/spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js
@@ -35,7 +35,6 @@ describe('Sidebar Participants Widget', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
diff --git a/spec/frontend/sidebar/components/reviewers/reviewer_title_spec.js b/spec/frontend/sidebar/components/reviewers/reviewer_title_spec.js
index 68ecd62e4c6..0f595ab21a5 100644
--- a/spec/frontend/sidebar/components/reviewers/reviewer_title_spec.js
+++ b/spec/frontend/sidebar/components/reviewers/reviewer_title_spec.js
@@ -16,11 +16,6 @@ describe('ReviewerTitle component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('reviewer title', () => {
it('renders reviewer', () => {
wrapper = createComponent({
diff --git a/spec/frontend/sidebar/components/reviewers/reviewers_spec.js b/spec/frontend/sidebar/components/reviewers/reviewers_spec.js
index 229f7ffbe04..016ec9225da 100644
--- a/spec/frontend/sidebar/components/reviewers/reviewers_spec.js
+++ b/spec/frontend/sidebar/components/reviewers/reviewers_spec.js
@@ -35,10 +35,6 @@ describe('Reviewer component', () => {
const findCollapsedChildren = () => wrapper.findAll('.sidebar-collapsed-icon > *');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('No reviewers/users', () => {
it('displays no reviewer icon when collapsed', () => {
createWrapper();
diff --git a/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js
index 57ae146a27a..a221d28704b 100644
--- a/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js
+++ b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_spec.js
@@ -44,9 +44,6 @@ describe('sidebar reviewers', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
-
SidebarService.singleton = null;
SidebarStore.singleton = null;
SidebarMediator.singleton = null;
diff --git a/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js b/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
index d00c8dcb653..483449f924b 100644
--- a/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
+++ b/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
@@ -38,10 +38,6 @@ describe('UncollapsedReviewerList component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('single reviewer', () => {
const user = userDataMock();
diff --git a/spec/frontend/sidebar/components/severity/sidebar_severity_spec.js b/spec/frontend/sidebar/components/severity/sidebar_severity_spec.js
index 71c6c259c32..8a27e82093d 100644
--- a/spec/frontend/sidebar/components/severity/sidebar_severity_spec.js
+++ b/spec/frontend/sidebar/components/severity/sidebar_severity_spec.js
@@ -2,13 +2,14 @@ import { GlDropdown, GlDropdownItem, GlLoadingIcon, GlTooltip, GlSprintf } from
import { nextTick } from 'vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
-import { INCIDENT_SEVERITY, ISSUABLE_TYPES } from '~/sidebar/constants';
+import { createAlert } from '~/alert';
+import { TYPE_INCIDENT } from '~/issues/constants';
+import { INCIDENT_SEVERITY } from '~/sidebar/constants';
import updateIssuableSeverity from '~/sidebar/queries/update_issuable_severity.mutation.graphql';
import SeverityToken from '~/sidebar/components/severity/severity.vue';
import SidebarSeverityWidget from '~/sidebar/components/severity/sidebar_severity_widget.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('SidebarSeverity', () => {
let wrapper;
@@ -22,7 +23,7 @@ describe('SidebarSeverity', () => {
const propsData = {
projectPath,
iid,
- issuableType: ISSUABLE_TYPES.INCIDENT,
+ issuableType: TYPE_INCIDENT,
initialSeverity: severity,
...props,
};
@@ -47,10 +48,6 @@ describe('SidebarSeverity', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSeverityToken = () => wrapper.findAllComponents(SeverityToken);
const findEditBtn = () => wrapper.findByTestId('edit-button');
const findDropdown = () => wrapper.findComponent(GlDropdown);
diff --git a/spec/frontend/sidebar/components/sidebar_dropdown_spec.js b/spec/frontend/sidebar/components/sidebar_dropdown_spec.js
index 9f3d689edee..7a0044c00ac 100644
--- a/spec/frontend/sidebar/components/sidebar_dropdown_spec.js
+++ b/spec/frontend/sidebar/components/sidebar_dropdown_spec.js
@@ -10,7 +10,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
import { IssuableAttributeType } from '~/sidebar/constants';
@@ -23,7 +23,7 @@ import {
noCurrentMilestoneResponse,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('SidebarDropdown component', () => {
let wrapper;
diff --git a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
index 060a2873e04..53d81e3fcaf 100644
--- a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
+++ b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
@@ -7,7 +7,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { TYPE_ISSUE } from '~/issues/constants';
import { timeFor } from '~/lib/utils/datetime_utility';
@@ -27,7 +27,7 @@ import {
mockMilestone2,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('SidebarDropdownWidget', () => {
let wrapper;
@@ -140,7 +140,7 @@ describe('SidebarDropdownWidget', () => {
},
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
stubs: {
SidebarEditableItem,
@@ -157,11 +157,6 @@ describe('SidebarDropdownWidget', () => {
jest.spyOn(wrapper.vm, 'showDropdown').mockImplementation();
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when not editing', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/sidebar/components/status/status_dropdown_spec.js b/spec/frontend/sidebar/components/status/status_dropdown_spec.js
index 5a75299c3a4..229b51ea568 100644
--- a/spec/frontend/sidebar/components/status/status_dropdown_spec.js
+++ b/spec/frontend/sidebar/components/status/status_dropdown_spec.js
@@ -14,10 +14,6 @@ describe('SubscriptionsDropdown component', () => {
wrapper = shallowMount(StatusDropdown);
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with no value selected', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js b/spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js
index c94f9918243..7275557e7f2 100644
--- a/spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js
+++ b/spec/frontend/sidebar/components/subscriptions/sidebar_subscriptions_widget_spec.js
@@ -4,7 +4,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import SidebarSubscriptionWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue';
import issueSubscribedQuery from '~/sidebar/queries/issue_subscribed.query.graphql';
@@ -15,7 +15,7 @@ import {
mergeRequestSubscriptionMutationResponse,
} from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/vue_shared/plugins/global_toast');
Vue.use(VueApollo);
@@ -62,7 +62,6 @@ describe('Sidebar Subscriptions Widget', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -138,7 +137,7 @@ describe('Sidebar Subscriptions Widget', () => {
});
});
- it('displays a flash message when query is rejected', async () => {
+ it('displays an alert message when query is rejected', async () => {
createComponent({
subscriptionsQueryHandler: jest.fn().mockRejectedValue('Houston, we have a problem'),
});
diff --git a/spec/frontend/sidebar/components/subscriptions/subscriptions_dropdown_spec.js b/spec/frontend/sidebar/components/subscriptions/subscriptions_dropdown_spec.js
index 3fb8214606c..eaf7bc13d20 100644
--- a/spec/frontend/sidebar/components/subscriptions/subscriptions_dropdown_spec.js
+++ b/spec/frontend/sidebar/components/subscriptions/subscriptions_dropdown_spec.js
@@ -15,10 +15,6 @@ describe('SubscriptionsDropdown component', () => {
wrapper = shallowMount(SubscriptionsDropdown);
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with no value selected', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js b/spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js
index 1a1aa370eef..cae21189ee0 100644
--- a/spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js
+++ b/spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js
@@ -16,11 +16,6 @@ describe('Subscriptions', () => {
}),
);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('shows loading spinner when loading', () => {
wrapper = mountComponent({
loading: true,
diff --git a/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js b/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js
index 715f66d305a..a7c3867c359 100644
--- a/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js
+++ b/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js
@@ -47,8 +47,8 @@ describe('Create Timelog Form', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findDocsLink = () => wrapper.findByTestId('timetracking-docs-link');
const findSaveButton = () => findModal().props('actionPrimary');
- const findSaveButtonLoadingState = () => findSaveButton().attributes[0].loading;
- const findSaveButtonDisabledState = () => findSaveButton().attributes[0].disabled;
+ const findSaveButtonLoadingState = () => findSaveButton().attributes.loading;
+ const findSaveButtonDisabledState = () => findSaveButton().attributes.disabled;
const submitForm = () => findForm().trigger('submit');
diff --git a/spec/frontend/sidebar/components/time_tracking/report_spec.js b/spec/frontend/sidebar/components/time_tracking/report_spec.js
index 0259aee48f0..713ae83cbf1 100644
--- a/spec/frontend/sidebar/components/time_tracking/report_spec.js
+++ b/spec/frontend/sidebar/components/time_tracking/report_spec.js
@@ -6,7 +6,7 @@ import VueApollo from 'vue-apollo';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Report from '~/sidebar/components/time_tracking/report.vue';
import getIssueTimelogsQuery from '~/sidebar/queries/get_issue_timelogs.query.graphql';
import getMrTimelogsQuery from '~/sidebar/queries/get_mr_timelogs.query.graphql';
@@ -17,7 +17,7 @@ import {
timelogToRemoveId,
} from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Issuable Time Tracking Report', () => {
Vue.use(VueApollo);
@@ -51,7 +51,6 @@ describe('Issuable Time Tracking Report', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
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 45d8b5e4647..91c013596d7 100644
--- a/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js
+++ b/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js
@@ -32,7 +32,7 @@ describe('Issuable Time Tracker', () => {
const mountComponent = ({ props = {}, issuableType = 'issue', loading = false } = {}) => {
return mount(TimeTracker, {
propsData: { ...defaultProps, ...props },
- directives: { GlTooltip: createMockDirective() },
+ directives: { GlTooltip: createMockDirective('gl-tooltip') },
stubs: {
transition: stubTransition(),
},
@@ -53,10 +53,6 @@ describe('Issuable Time Tracker', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Initialization', () => {
beforeEach(() => {
wrapper = mountComponent();
diff --git a/spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js b/spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js
index 5bfe3b59eb3..39b480b295c 100644
--- a/spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js
+++ b/spec/frontend/sidebar/components/todo_toggle/sidebar_todo_widget_spec.js
@@ -4,13 +4,13 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue';
import epicTodoQuery from '~/sidebar/queries/epic_todo.query.graphql';
import TodoButton from '~/sidebar/components/todo_toggle/todo_button.vue';
import { todosResponse, noTodosResponse } from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -41,7 +41,6 @@ describe('Sidebar Todo Widget', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -77,7 +76,7 @@ describe('Sidebar Todo Widget', () => {
});
});
- it('displays a flash message when query is rejected', async () => {
+ it('displays an alert message when query is rejected', async () => {
createComponent({
todosQueryHandler: jest.fn().mockRejectedValue('Houston, we have a problem'),
});
diff --git a/spec/frontend/sidebar/components/todo_toggle/todo_button_spec.js b/spec/frontend/sidebar/components/todo_toggle/todo_button_spec.js
index fb07029a249..472a89e9b21 100644
--- a/spec/frontend/sidebar/components/todo_toggle/todo_button_spec.js
+++ b/spec/frontend/sidebar/components/todo_toggle/todo_button_spec.js
@@ -22,7 +22,6 @@ describe('Todo Button', () => {
});
afterEach(() => {
- wrapper.destroy();
dispatchEventSpy = null;
jest.clearAllMocks();
});
diff --git a/spec/frontend/sidebar/components/todo_toggle/todo_spec.js b/spec/frontend/sidebar/components/todo_toggle/todo_spec.js
index 8e6597bf80f..4da915f0dd3 100644
--- a/spec/frontend/sidebar/components/todo_toggle/todo_spec.js
+++ b/spec/frontend/sidebar/components/todo_toggle/todo_spec.js
@@ -21,10 +21,6 @@ describe('SidebarTodo', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
state | classes
${false} | ${['gl-button', 'btn', 'btn-default', 'btn-todo', 'issuable-header-btn', 'float-right']}
diff --git a/spec/frontend/sidebar/components/toggle/toggle_sidebar_spec.js b/spec/frontend/sidebar/components/toggle/toggle_sidebar_spec.js
index cf9b2828dde..0370d5e337d 100644
--- a/spec/frontend/sidebar/components/toggle/toggle_sidebar_spec.js
+++ b/spec/frontend/sidebar/components/toggle/toggle_sidebar_spec.js
@@ -17,10 +17,6 @@ describe('ToggleSidebar', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findGlButton = () => wrapper.findComponent(GlButton);
it('should render the "chevron-double-lg-left" icon when collapsed', () => {
diff --git a/spec/frontend/sidebar/mock_data.js b/spec/frontend/sidebar/mock_data.js
index 391cbb1e0d5..844320efc1c 100644
--- a/spec/frontend/sidebar/mock_data.js
+++ b/spec/frontend/sidebar/mock_data.js
@@ -243,6 +243,7 @@ export const issuableDueDateResponse = (dueDate = null) => ({
__typename: 'Issue',
id: 'gid://gitlab/Issue/4',
dueDate,
+ dueDateFixed: dueDate,
},
},
},
diff --git a/spec/frontend/sidebar/sidebar_mediator_spec.js b/spec/frontend/sidebar/sidebar_mediator_spec.js
index 77b1ccb4f9a..f2003aee96e 100644
--- a/spec/frontend/sidebar/sidebar_mediator_spec.js
+++ b/spec/frontend/sidebar/sidebar_mediator_spec.js
@@ -7,7 +7,7 @@ import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarStore from '~/sidebar/stores/sidebar_store';
import Mock from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/vue_shared/plugins/global_toast');
jest.mock('~/commons/nav/user_merge_requests');
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 fec300ddd7e..7eb0468c5be 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
@@ -28,10 +28,13 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
data-uploads-path=""
>
<markdown-header-stub
+ data-testid="markdownHeader"
enablepreview="true"
linecontent=""
+ markdownpreviewpath="foo/"
restrictedtoolbaritems=""
suggestionstartindex="0"
+ uploadspath=""
/>
<div
diff --git a/spec/frontend/snippets/components/edit_spec.js b/spec/frontend/snippets/components/edit_spec.js
index e7dab0ad79d..0d0e78e9179 100644
--- a/spec/frontend/snippets/components/edit_spec.js
+++ b/spec/frontend/snippets/components/edit_spec.js
@@ -9,7 +9,7 @@ import { stubPerformanceWebAPI } from 'helpers/performance';
import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import GetSnippetQuery from 'shared_queries/snippet/snippet.query.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as urlUtils from '~/lib/utils/url_utility';
import SnippetEditApp from '~/snippets/components/edit.vue';
import SnippetBlobActionsEdit from '~/snippets/components/snippet_blob_actions_edit.vue';
@@ -25,7 +25,7 @@ import UpdateSnippetMutation from '~/snippets/mutations/update_snippet.mutation.
import FormFooterActions from '~/vue_shared/components/form/form_footer_actions.vue';
import { testEntries, createGQLSnippetsQueryResponse, createGQLSnippet } from '../test_utils';
-jest.mock('~/flash');
+jest.mock('~/alert');
const TEST_UPLOADED_FILES = ['foo/bar.txt', 'alpha/beta.js'];
const TEST_API_ERROR = new Error('TEST_API_ERROR');
@@ -94,7 +94,6 @@ describe('Snippet Edit app', () => {
let mutateSpy;
const relativeUrlRoot = '/foo/';
- const originalRelativeUrlRoot = gon.relative_url_root;
beforeEach(() => {
stubPerformanceWebAPI();
@@ -108,12 +107,6 @@ describe('Snippet Edit app', () => {
jest.spyOn(urlUtils, 'redirectTo').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- gon.relative_url_root = originalRelativeUrlRoot;
- });
-
const findBlobActions = () => wrapper.findComponent(SnippetBlobActionsEdit);
const findCancelButton = () => wrapper.findByTestId('snippet-cancel-btn');
const clickSubmitBtn = () => wrapper.findByTestId('snippet-edit-form').trigger('submit');
@@ -132,10 +125,6 @@ describe('Snippet Edit app', () => {
props = {},
selectedLevel = VISIBILITY_LEVEL_PRIVATE_STRING,
} = {}) => {
- if (wrapper) {
- throw new Error('wrapper already created');
- }
-
const requestHandlers = [
[GetSnippetQuery, getSpy],
// See `mutateSpy` declaration comment for why we send a key
@@ -347,7 +336,7 @@ describe('Snippet Edit app', () => {
projectPath
${'project/path'}
${''}
- `('should flash error (projectPath=$projectPath)', async ({ projectPath }) => {
+ `('should alert error (projectPath=$projectPath)', async ({ projectPath }) => {
mutateSpy.mockResolvedValue(createMutationResponseWithErrors('createSnippet'));
await createComponentAndLoad({
@@ -373,7 +362,7 @@ describe('Snippet Edit app', () => {
${'project/path'}
${''}
`(
- 'should flash error with (snippet=$snippetGid, projectPath=$projectPath)',
+ 'should alert error with (snippet=$snippetGid, projectPath=$projectPath)',
async ({ projectPath }) => {
mutateSpy.mockResolvedValue(createMutationResponseWithErrors('updateSnippet'));
@@ -405,7 +394,7 @@ describe('Snippet Edit app', () => {
expect(urlUtils.redirectTo).not.toHaveBeenCalled();
});
- it('should flash', () => {
+ it('should alert', () => {
// Apollo automatically wraps the resolver's error in a NetworkError
expect(createAlert).toHaveBeenCalledWith({
message: `Can't update snippet: ${TEST_API_ERROR.message}`,
diff --git a/spec/frontend/snippets/components/embed_dropdown_spec.js b/spec/frontend/snippets/components/embed_dropdown_spec.js
index ed5ea6cab8a..d8c6ad3278a 100644
--- a/spec/frontend/snippets/components/embed_dropdown_spec.js
+++ b/spec/frontend/snippets/components/embed_dropdown_spec.js
@@ -17,11 +17,6 @@ describe('snippets/components/embed_dropdown', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findSectionsData = () => {
const sections = [];
let current = {};
diff --git a/spec/frontend/snippets/components/show_spec.js b/spec/frontend/snippets/components/show_spec.js
index 032dcf8e5f5..45a7c7b0b4a 100644
--- a/spec/frontend/snippets/components/show_spec.js
+++ b/spec/frontend/snippets/components/show_spec.js
@@ -50,10 +50,6 @@ describe('Snippet view app', () => {
stubPerformanceWebAPI();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders loader while the query is in flight', () => {
createComponent({ loading: true });
expect(findLoadingIcon().exists()).toBe(true);
diff --git a/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js b/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
index a650353093d..58f47e8b0dc 100644
--- a/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
@@ -56,11 +56,6 @@ describe('snippets/components/snippet_blob_actions_edit', () => {
const triggerBlobDelete = (idx) => findBlobEdits().at(idx).vm.$emit('delete');
const triggerBlobUpdate = (idx, props) => findBlobEdits().at(idx).vm.$emit('blob-updated', props);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('multi-file snippets rendering', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/snippets/components/snippet_blob_edit_spec.js b/spec/frontend/snippets/components/snippet_blob_edit_spec.js
index 82c4a37ccc9..b699e056576 100644
--- a/spec/frontend/snippets/components/snippet_blob_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_edit_spec.js
@@ -4,14 +4,14 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue';
-import { createAlert } from '~/flash';
+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 { joinPaths } from '~/lib/utils/url_utility';
import SnippetBlobEdit from '~/snippets/components/snippet_blob_edit.vue';
import SourceEditor from '~/vue_shared/components/source_editor.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
const TEST_ID = 'blob_local_7';
const TEST_PATH = 'foo/bar/test.md';
@@ -62,8 +62,6 @@ describe('Snippet Blob Edit component', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
axiosMock.restore();
});
@@ -123,7 +121,7 @@ describe('Snippet Blob Edit component', () => {
createComponent();
});
- it('should call flash', async () => {
+ it('should call alert', async () => {
await waitForPromises();
expect(createAlert).toHaveBeenCalledWith({
diff --git a/spec/frontend/snippets/components/snippet_blob_view_spec.js b/spec/frontend/snippets/components/snippet_blob_view_spec.js
index c7ff8c21d80..840bca8c9c8 100644
--- a/spec/frontend/snippets/components/snippet_blob_view_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_view_spec.js
@@ -62,10 +62,6 @@ describe('Blob Embeddable', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
it('renders correct components', () => {
createComponent();
diff --git a/spec/frontend/snippets/components/snippet_description_edit_spec.js b/spec/frontend/snippets/components/snippet_description_edit_spec.js
index ff75515e71a..2b42eba19c2 100644
--- a/spec/frontend/snippets/components/snippet_description_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_description_edit_spec.js
@@ -30,10 +30,6 @@ describe('Snippet Description Edit component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
diff --git a/spec/frontend/snippets/components/snippet_description_view_spec.js b/spec/frontend/snippets/components/snippet_description_view_spec.js
index 14f116f2aaf..3c5d50ccaa6 100644
--- a/spec/frontend/snippets/components/snippet_description_view_spec.js
+++ b/spec/frontend/snippets/components/snippet_description_view_spec.js
@@ -17,10 +17,6 @@ describe('Snippet Description component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/snippets/components/snippet_header_spec.js b/spec/frontend/snippets/components/snippet_header_spec.js
index c930c9f635b..994cf65c1f5 100644
--- a/spec/frontend/snippets/components/snippet_header_spec.js
+++ b/spec/frontend/snippets/components/snippet_header_spec.js
@@ -1,8 +1,9 @@
-import { GlButton, GlModal, GlDropdown } from '@gitlab/ui';
+import { GlModal, GlButton, GlDropdown } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
-import { ApolloMutation } from 'vue-apollo';
+import VueApollo from 'vue-apollo';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
@@ -10,31 +11,41 @@ import { differenceInMilliseconds } from '~/lib/utils/datetime_utility';
import SnippetHeader, { i18n } from '~/snippets/components/snippet_header.vue';
import DeleteSnippetMutation from '~/snippets/mutations/delete_snippet.mutation.graphql';
import axios from '~/lib/utils/axios_utils';
-import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/alert';
+import CanCreateProjectSnippet from 'shared_queries/snippet/project_permissions.query.graphql';
+import CanCreatePersonalSnippet from 'shared_queries/snippet/user_permissions.query.graphql';
+import { getCanCreateProjectSnippetMock, getCanCreatePersonalSnippetMock } from '../mock_data';
-jest.mock('~/flash');
+const ERROR_MSG = 'Foo bar';
+const ERR = { message: ERROR_MSG };
+
+const MUTATION_TYPES = {
+ RESOLVE: jest.fn().mockResolvedValue({ data: { destroySnippet: { errors: [] } } }),
+ REJECT: jest.fn().mockRejectedValue(ERR),
+};
+
+jest.mock('~/alert');
+
+Vue.use(VueApollo);
describe('Snippet header component', () => {
let wrapper;
let snippet;
- let mutationTypes;
- let mutationVariables;
let mock;
+ let mockApollo;
- let errorMsg;
- let err;
- const originalRelativeUrlRoot = gon.relative_url_root;
const reportAbusePath = '/-/snippets/42/mark_as_spam';
const canReportSpam = true;
const GlEmoji = { template: '<img/>' };
function createComponent({
- loading = false,
permissions = {},
- mutationRes = mutationTypes.RESOLVE,
snippetProps = {},
provide = {},
+ canCreateProjectSnippetMock = jest.fn().mockResolvedValue(getCanCreateProjectSnippetMock()),
+ canCreatePersonalSnippetMock = jest.fn().mockResolvedValue(getCanCreatePersonalSnippetMock()),
+ deleteSnippetMock = MUTATION_TYPES.RESOLVE,
} = {}) {
const defaultProps = Object.assign(snippet, snippetProps);
if (permissions) {
@@ -42,17 +53,14 @@ describe('Snippet header component', () => {
...permissions,
});
}
- const $apollo = {
- queries: {
- canCreateSnippet: {
- loading,
- },
- },
- mutate: mutationRes,
- };
+
+ mockApollo = createMockApollo([
+ [CanCreateProjectSnippet, canCreateProjectSnippetMock],
+ [CanCreatePersonalSnippet, canCreatePersonalSnippetMock],
+ [DeleteSnippetMutation, deleteSnippetMock],
+ ]);
wrapper = mount(SnippetHeader, {
- mocks: { $apollo },
provide: {
reportAbusePath,
canReportSpam,
@@ -64,9 +72,9 @@ describe('Snippet header component', () => {
},
},
stubs: {
- ApolloMutation,
GlEmoji,
},
+ apolloProvider: mockApollo,
});
}
@@ -91,6 +99,7 @@ describe('Snippet header component', () => {
title: x.attributes('title'),
text: x.text(),
}));
+ const findDeleteModal = () => wrapper.findComponent(GlModal);
beforeEach(() => {
gon.relative_url_root = '/foo/';
@@ -113,28 +122,12 @@ describe('Snippet header component', () => {
createdAt: new Date(differenceInMilliseconds(32 * 24 * 3600 * 1000)).toISOString(),
};
- mutationVariables = {
- mutation: DeleteSnippetMutation,
- variables: {
- id: snippet.id,
- },
- };
-
- errorMsg = 'Foo bar';
- err = { message: errorMsg };
-
- mutationTypes = {
- RESOLVE: jest.fn(() => Promise.resolve({ data: { destroySnippet: { errors: [] } } })),
- REJECT: jest.fn(() => Promise.reject(err)),
- };
-
mock = new MockAdapter(axios);
});
afterEach(() => {
- wrapper.destroy();
+ mockApollo = null;
mock.restore();
- gon.relative_url_root = originalRelativeUrlRoot;
});
it('renders itself', () => {
@@ -238,15 +231,16 @@ describe('Snippet header component', () => {
});
it('with canCreateSnippet permission, renders create button', async () => {
- createComponent();
+ createComponent({
+ canCreateProjectSnippetMock: jest
+ .fn()
+ .mockResolvedValue(getCanCreateProjectSnippetMock(true)),
+ canCreatePersonalSnippetMock: jest
+ .fn()
+ .mockResolvedValue(getCanCreatePersonalSnippetMock(true)),
+ });
- // TODO: we should avoid `wrapper.setData` since they
- // are component internals. Let's use the apollo mock helpers
- // in a follow-up.
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ canCreateSnippet: true });
- await nextTick();
+ await waitForPromises();
expect(findButtonsAsModel()).toEqual(
expect.arrayContaining([
@@ -271,7 +265,7 @@ describe('Snippet header component', () => {
${200} | ${VARIANT_SUCCESS} | ${i18n.snippetSpamSuccess}
${500} | ${VARIANT_DANGER} | ${i18n.snippetSpamFailure}
`(
- 'renders a "$variant" flash message with "$text" message for a request with a "$request" response',
+ 'renders a "$variant" alert message with "$text" message for a request with a "$request" response',
async ({ request, variant, text }) => {
const submitAsSpamBtn = findButtons().at(2);
mock.onPost(reportAbusePath).reply(request);
@@ -329,21 +323,37 @@ describe('Snippet header component', () => {
});
describe('Delete mutation', () => {
- it('dispatches a mutation to delete the snippet with correct variables', () => {
+ const deleteSnippet = async () => {
+ // Click delete action
+ findButtons().at(1).trigger('click');
+ await nextTick();
+
+ expect(findDeleteModal().props().visible).toBe(true);
+
+ // Click delete button in delete modal
+ document.querySelector('[data-testid="delete-snippet"').click();
+ await waitForPromises();
+ };
+
+ it('dispatches a mutation to delete the snippet with correct variables', async () => {
createComponent();
- wrapper.vm.deleteSnippet();
- expect(mutationTypes.RESOLVE).toHaveBeenCalledWith(mutationVariables);
+
+ await deleteSnippet();
+
+ expect(MUTATION_TYPES.RESOLVE).toHaveBeenCalledWith({
+ id: snippet.id,
+ });
});
it('sets error message if mutation fails', async () => {
- createComponent({ mutationRes: mutationTypes.REJECT });
+ createComponent({ deleteSnippetMock: MUTATION_TYPES.REJECT });
expect(Boolean(wrapper.vm.errorMessage)).toBe(false);
- wrapper.vm.deleteSnippet();
-
- await waitForPromises();
+ await deleteSnippet();
- expect(wrapper.vm.errorMessage).toEqual(errorMsg);
+ expect(document.querySelector('[data-testid="delete-alert"').textContent.trim()).toBe(
+ ERROR_MSG,
+ );
});
describe('in case of successful mutation, closes modal and redirects to correct listing', () => {
@@ -353,15 +363,16 @@ describe('Snippet header component', () => {
createComponent({
snippetProps,
});
- wrapper.vm.closeDeleteModal = jest.fn();
- wrapper.vm.deleteSnippet();
- await nextTick();
+ await deleteSnippet();
};
it('redirects to dashboard/snippets for personal snippet', async () => {
await createDeleteSnippet();
- expect(wrapper.vm.closeDeleteModal).toHaveBeenCalled();
+
+ // Check that the modal is hidden after deleting the snippet
+ expect(findDeleteModal().props().visible).toBe(false);
+
expect(window.location.pathname).toBe(`${gon.relative_url_root}dashboard/snippets`);
});
@@ -372,7 +383,10 @@ describe('Snippet header component', () => {
fullPath,
},
});
- expect(wrapper.vm.closeDeleteModal).toHaveBeenCalled();
+
+ // Check that the modal is hidden after deleting the snippet
+ expect(findDeleteModal().props().visible).toBe(false);
+
expect(window.location.pathname).toBe(`${fullPath}/-/snippets`);
});
});
diff --git a/spec/frontend/snippets/components/snippet_title_spec.js b/spec/frontend/snippets/components/snippet_title_spec.js
index 7c40735d64e..0a3b57c9244 100644
--- a/spec/frontend/snippets/components/snippet_title_spec.js
+++ b/spec/frontend/snippets/components/snippet_title_spec.js
@@ -26,10 +26,6 @@ describe('Snippet header component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders itself', () => {
createComponent();
expect(wrapper.find('.snippet-header').exists()).toBe(true);
diff --git a/spec/frontend/snippets/components/snippet_visibility_edit_spec.js b/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
index 29eb002ef4a..70eb719f706 100644
--- a/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
@@ -51,10 +51,6 @@ describe('Snippet Visibility Edit component', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
it('matches the snapshot', () => {
createComponent();
diff --git a/spec/frontend/snippets/mock_data.js b/spec/frontend/snippets/mock_data.js
new file mode 100644
index 00000000000..7546fa575c6
--- /dev/null
+++ b/spec/frontend/snippets/mock_data.js
@@ -0,0 +1,19 @@
+export const getCanCreateProjectSnippetMock = (createSnippet = false) => ({
+ data: {
+ project: {
+ userPermissions: {
+ createSnippet,
+ },
+ },
+ },
+});
+
+export const getCanCreatePersonalSnippetMock = (createSnippet = false) => ({
+ data: {
+ currentUser: {
+ userPermissions: {
+ createSnippet,
+ },
+ },
+ },
+});
diff --git a/spec/frontend/streaming/chunk_writer_spec.js b/spec/frontend/streaming/chunk_writer_spec.js
new file mode 100644
index 00000000000..2aadb332838
--- /dev/null
+++ b/spec/frontend/streaming/chunk_writer_spec.js
@@ -0,0 +1,214 @@
+import { ChunkWriter } from '~/streaming/chunk_writer';
+import { RenderBalancer } from '~/streaming/render_balancer';
+
+jest.mock('~/streaming/render_balancer');
+
+describe('ChunkWriter', () => {
+ let accumulator = '';
+ let write;
+ let close;
+ let abort;
+ let config;
+ let render;
+
+ const createChunk = (text) => {
+ const encoder = new TextEncoder();
+ return encoder.encode(text);
+ };
+
+ const createHtmlStream = () => {
+ write = jest.fn((part) => {
+ accumulator += part;
+ });
+ close = jest.fn();
+ abort = jest.fn();
+ return {
+ write,
+ close,
+ abort,
+ };
+ };
+
+ const createWriter = () => {
+ return new ChunkWriter(createHtmlStream(), config);
+ };
+
+ const pushChunks = (...chunks) => {
+ const writer = createWriter();
+ chunks.forEach((chunk) => {
+ writer.write(createChunk(chunk));
+ });
+ writer.close();
+ };
+
+ afterAll(() => {
+ global.JEST_DEBOUNCE_THROTTLE_TIMEOUT = undefined;
+ });
+
+ beforeEach(() => {
+ global.JEST_DEBOUNCE_THROTTLE_TIMEOUT = 100;
+ accumulator = '';
+ config = undefined;
+ render = jest.fn((cb) => {
+ while (cb()) {
+ // render until 'false'
+ }
+ });
+ RenderBalancer.mockImplementation(() => ({ render }));
+ });
+
+ describe('when chunk length must be "1"', () => {
+ beforeEach(() => {
+ config = { minChunkSize: 1, maxChunkSize: 1 };
+ });
+
+ it('splits big chunks into smaller ones', () => {
+ const text = 'foobar';
+ pushChunks(text);
+ expect(accumulator).toBe(text);
+ expect(write).toHaveBeenCalledTimes(text.length);
+ });
+
+ it('handles small emoji chunks', () => {
+ const text = 'foo👀bar👨â€ðŸ‘©â€ðŸ‘§baz👧👧ðŸ»ðŸ‘§ðŸ¼ðŸ‘§ðŸ½ðŸ‘§ðŸ¾ðŸ‘§ðŸ¿';
+ pushChunks(text);
+ expect(accumulator).toBe(text);
+ expect(write).toHaveBeenCalledTimes(createChunk(text).length);
+ });
+ });
+
+ describe('when chunk length must not be lower than "5" and exceed "10"', () => {
+ beforeEach(() => {
+ config = { minChunkSize: 5, maxChunkSize: 10 };
+ });
+
+ it('joins small chunks', () => {
+ const text = '12345';
+ pushChunks(...text.split(''));
+ expect(accumulator).toBe(text);
+ expect(write).toHaveBeenCalledTimes(1);
+ expect(close).toHaveBeenCalledTimes(1);
+ });
+
+ it('handles overflow with small chunks', () => {
+ const text = '123456789';
+ pushChunks(...text.split(''));
+ expect(accumulator).toBe(text);
+ expect(write).toHaveBeenCalledTimes(2);
+ expect(close).toHaveBeenCalledTimes(1);
+ });
+
+ it('calls flush on small chunks', () => {
+ global.JEST_DEBOUNCE_THROTTLE_TIMEOUT = undefined;
+ const flushAccumulator = jest.spyOn(ChunkWriter.prototype, 'flushAccumulator');
+ const text = '1';
+ pushChunks(text);
+ expect(accumulator).toBe(text);
+ expect(flushAccumulator).toHaveBeenCalledTimes(1);
+ });
+
+ it('calls flush on large chunks', () => {
+ const flushAccumulator = jest.spyOn(ChunkWriter.prototype, 'flushAccumulator');
+ const text = '1234567890123';
+ const writer = createWriter();
+ writer.write(createChunk(text));
+ jest.runAllTimers();
+ expect(accumulator).toBe(text);
+ expect(flushAccumulator).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('chunk balancing', () => {
+ let increase;
+ let decrease;
+ let renderOnce;
+
+ beforeEach(() => {
+ render = jest.fn((cb) => {
+ let next = true;
+ renderOnce = () => {
+ if (!next) return;
+ next = cb();
+ };
+ });
+ RenderBalancer.mockImplementation(({ increase: inc, decrease: dec }) => {
+ increase = jest.fn(inc);
+ decrease = jest.fn(dec);
+ return {
+ render,
+ };
+ });
+ });
+
+ describe('when frame time exceeds low limit', () => {
+ beforeEach(() => {
+ config = {
+ minChunkSize: 1,
+ maxChunkSize: 5,
+ balanceRate: 10,
+ };
+ });
+
+ it('increases chunk size', () => {
+ const text = '111222223';
+ const writer = createWriter();
+ const chunk = createChunk(text);
+
+ writer.write(chunk);
+
+ renderOnce();
+ increase();
+ renderOnce();
+ renderOnce();
+
+ writer.close();
+
+ expect(accumulator).toBe(text);
+ expect(write.mock.calls).toMatchObject([['111'], ['22222'], ['3']]);
+ expect(close).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when frame time exceeds high limit', () => {
+ beforeEach(() => {
+ config = {
+ minChunkSize: 1,
+ maxChunkSize: 10,
+ balanceRate: 2,
+ };
+ });
+
+ it('decreases chunk size', () => {
+ const text = '1111112223345';
+ const writer = createWriter();
+ const chunk = createChunk(text);
+
+ writer.write(chunk);
+
+ renderOnce();
+ decrease();
+
+ renderOnce();
+ decrease();
+
+ renderOnce();
+ decrease();
+
+ renderOnce();
+ renderOnce();
+
+ writer.close();
+
+ expect(accumulator).toBe(text);
+ expect(write.mock.calls).toMatchObject([['111111'], ['222'], ['33'], ['4'], ['5']]);
+ expect(close).toHaveBeenCalledTimes(1);
+ });
+ });
+ });
+
+ it('calls abort on htmlStream', () => {
+ const writer = createWriter();
+ writer.abort();
+ expect(abort).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/spec/frontend/streaming/handle_streamed_anchor_link_spec.js b/spec/frontend/streaming/handle_streamed_anchor_link_spec.js
new file mode 100644
index 00000000000..ef17957b2fc
--- /dev/null
+++ b/spec/frontend/streaming/handle_streamed_anchor_link_spec.js
@@ -0,0 +1,132 @@
+import { resetHTMLFixture, setHTMLFixture } from 'helpers/fixtures';
+import waitForPromises from 'helpers/wait_for_promises';
+import { handleStreamedAnchorLink } from '~/streaming/handle_streamed_anchor_link';
+import { scrollToElement } from '~/lib/utils/common_utils';
+import LineHighlighter from '~/blob/line_highlighter';
+import { TEST_HOST } from 'spec/test_constants';
+
+jest.mock('~/lib/utils/common_utils');
+jest.mock('~/blob/line_highlighter');
+
+describe('handleStreamedAnchorLink', () => {
+ const ANCHOR_START = 'L100';
+ const ANCHOR_END = '300';
+ const findRoot = () => document.querySelector('#root');
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ describe('when single line anchor is given', () => {
+ beforeEach(() => {
+ delete window.location;
+ window.location = new URL(`${TEST_HOST}#${ANCHOR_START}`);
+ });
+
+ describe('when element is present', () => {
+ beforeEach(() => {
+ setHTMLFixture(`<div id="root"><div id="${ANCHOR_START}"></div></div>`);
+ handleStreamedAnchorLink(findRoot());
+ });
+
+ it('does nothing', async () => {
+ await waitForPromises();
+ expect(scrollToElement).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when element is streamed', () => {
+ let stop;
+ const insertElement = () => {
+ findRoot().insertAdjacentHTML('afterbegin', `<div id="${ANCHOR_START}"></div>`);
+ };
+
+ beforeEach(() => {
+ setHTMLFixture('<div id="root"></div>');
+ stop = handleStreamedAnchorLink(findRoot());
+ });
+
+ afterEach(() => {
+ stop = undefined;
+ });
+
+ it('scrolls to the anchor when inserted', async () => {
+ insertElement();
+ await waitForPromises();
+ expect(scrollToElement).toHaveBeenCalledTimes(1);
+ expect(LineHighlighter).toHaveBeenCalledTimes(1);
+ });
+
+ it("doesn't scroll to the anchor when destroyed", async () => {
+ stop();
+ insertElement();
+ await waitForPromises();
+ expect(scrollToElement).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('when line range anchor is given', () => {
+ beforeEach(() => {
+ delete window.location;
+ window.location = new URL(`${TEST_HOST}#${ANCHOR_START}-${ANCHOR_END}`);
+ });
+
+ describe('when last element is present', () => {
+ beforeEach(() => {
+ setHTMLFixture(`<div id="root"><div id="L${ANCHOR_END}"></div></div>`);
+ handleStreamedAnchorLink(findRoot());
+ });
+
+ it('does nothing', async () => {
+ await waitForPromises();
+ expect(scrollToElement).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when last element is streamed', () => {
+ let stop;
+ const insertElement = () => {
+ findRoot().insertAdjacentHTML(
+ 'afterbegin',
+ `<div id="${ANCHOR_START}"></div><div id="L${ANCHOR_END}"></div>`,
+ );
+ };
+
+ beforeEach(() => {
+ setHTMLFixture('<div id="root"></div>');
+ stop = handleStreamedAnchorLink(findRoot());
+ });
+
+ afterEach(() => {
+ stop = undefined;
+ });
+
+ it('scrolls to the anchor when inserted', async () => {
+ insertElement();
+ await waitForPromises();
+ expect(scrollToElement).toHaveBeenCalledTimes(1);
+ expect(LineHighlighter).toHaveBeenCalledTimes(1);
+ });
+
+ it("doesn't scroll to the anchor when destroyed", async () => {
+ stop();
+ insertElement();
+ await waitForPromises();
+ expect(scrollToElement).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('when anchor is not given', () => {
+ beforeEach(() => {
+ setHTMLFixture(`<div id="root"></div>`);
+ handleStreamedAnchorLink(findRoot());
+ });
+
+ it('does nothing', async () => {
+ await waitForPromises();
+ expect(scrollToElement).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/streaming/html_stream_spec.js b/spec/frontend/streaming/html_stream_spec.js
new file mode 100644
index 00000000000..115a9ddc803
--- /dev/null
+++ b/spec/frontend/streaming/html_stream_spec.js
@@ -0,0 +1,46 @@
+import { HtmlStream } from '~/streaming/html_stream';
+import { ChunkWriter } from '~/streaming/chunk_writer';
+
+jest.mock('~/streaming/chunk_writer');
+
+describe('HtmlStream', () => {
+ let write;
+ let close;
+ let streamingElement;
+
+ beforeEach(() => {
+ write = jest.fn();
+ close = jest.fn();
+ jest.spyOn(Document.prototype, 'write').mockImplementation(write);
+ jest.spyOn(Document.prototype, 'close').mockImplementation(close);
+ jest.spyOn(Document.prototype, 'querySelector').mockImplementation(() => {
+ streamingElement = document.createElement('div');
+ return streamingElement;
+ });
+ });
+
+ it('attaches to original document', () => {
+ // eslint-disable-next-line no-new
+ new HtmlStream(document.body);
+ expect(document.body.contains(streamingElement)).toBe(true);
+ });
+
+ it('can write to a document', () => {
+ const htmlStream = new HtmlStream(document.body);
+ htmlStream.write('foo');
+ htmlStream.close();
+ expect(write.mock.calls).toEqual([['<streaming-element>'], ['foo'], ['</streaming-element>']]);
+ expect(close).toHaveBeenCalledTimes(1);
+ });
+
+ it('returns chunked writer', () => {
+ const htmlStream = new HtmlStream(document.body).withChunkWriter();
+ expect(htmlStream).toBeInstanceOf(ChunkWriter);
+ });
+
+ it('closes on abort', () => {
+ const htmlStream = new HtmlStream(document.body);
+ htmlStream.abort();
+ expect(close).toHaveBeenCalled();
+ });
+});
diff --git a/spec/frontend/streaming/rate_limit_stream_requests_spec.js b/spec/frontend/streaming/rate_limit_stream_requests_spec.js
new file mode 100644
index 00000000000..02e3cf93014
--- /dev/null
+++ b/spec/frontend/streaming/rate_limit_stream_requests_spec.js
@@ -0,0 +1,155 @@
+import waitForPromises from 'helpers/wait_for_promises';
+import { rateLimitStreamRequests } from '~/streaming/rate_limit_stream_requests';
+
+describe('rateLimitStreamRequests', () => {
+ const encoder = new TextEncoder('utf-8');
+ const createStreamResponse = (content = 'foo') =>
+ new ReadableStream({
+ pull(controller) {
+ controller.enqueue(encoder.encode(content));
+ controller.close();
+ },
+ });
+
+ const createFactory = (content) => {
+ return jest.fn(() => {
+ return Promise.resolve(createStreamResponse(content));
+ });
+ };
+
+ it('does nothing for zero total requests', () => {
+ const factory = jest.fn();
+ const requests = rateLimitStreamRequests({
+ factory,
+ total: 0,
+ });
+ expect(factory).toHaveBeenCalledTimes(0);
+ expect(requests.length).toBe(0);
+ });
+
+ it('does not exceed total requests', () => {
+ const factory = createFactory();
+ const requests = rateLimitStreamRequests({
+ factory,
+ immediateCount: 100,
+ maxConcurrentRequests: 100,
+ total: 2,
+ });
+ expect(factory).toHaveBeenCalledTimes(2);
+ expect(requests.length).toBe(2);
+ });
+
+ it('creates immediate requests', () => {
+ const factory = createFactory();
+ const requests = rateLimitStreamRequests({
+ factory,
+ maxConcurrentRequests: 2,
+ total: 2,
+ });
+ expect(factory).toHaveBeenCalledTimes(2);
+ expect(requests.length).toBe(2);
+ });
+
+ it('returns correct values', async () => {
+ const fixture = 'foobar';
+ const factory = createFactory(fixture);
+ const requests = rateLimitStreamRequests({
+ factory,
+ maxConcurrentRequests: 2,
+ total: 2,
+ });
+
+ const decoder = new TextDecoder('utf-8');
+ let result = '';
+ for await (const stream of requests) {
+ await stream.pipeTo(
+ new WritableStream({
+ // eslint-disable-next-line no-loop-func
+ write(content) {
+ result += decoder.decode(content);
+ },
+ }),
+ );
+ }
+
+ expect(result).toBe(fixture + fixture);
+ });
+
+ it('delays rate limited requests', async () => {
+ const factory = createFactory();
+ const requests = rateLimitStreamRequests({
+ factory,
+ maxConcurrentRequests: 2,
+ total: 3,
+ });
+ expect(factory).toHaveBeenCalledTimes(2);
+ expect(requests.length).toBe(3);
+
+ await waitForPromises();
+
+ expect(factory).toHaveBeenCalledTimes(3);
+ });
+
+ it('runs next request after previous has been fulfilled', async () => {
+ let res;
+ const factory = jest
+ .fn()
+ .mockImplementationOnce(
+ () =>
+ new Promise((resolve) => {
+ res = resolve;
+ }),
+ )
+ .mockImplementationOnce(() => Promise.resolve(createStreamResponse()));
+ const requests = rateLimitStreamRequests({
+ factory,
+ maxConcurrentRequests: 1,
+ total: 2,
+ });
+ expect(factory).toHaveBeenCalledTimes(1);
+ expect(requests.length).toBe(2);
+
+ await waitForPromises();
+
+ expect(factory).toHaveBeenCalledTimes(1);
+
+ res(createStreamResponse());
+
+ await waitForPromises();
+
+ expect(factory).toHaveBeenCalledTimes(2);
+ });
+
+ it('uses timer to schedule next request', async () => {
+ let res;
+ const factory = jest
+ .fn()
+ .mockImplementationOnce(
+ () =>
+ new Promise((resolve) => {
+ res = resolve;
+ }),
+ )
+ .mockImplementationOnce(() => Promise.resolve(createStreamResponse()));
+ const requests = rateLimitStreamRequests({
+ factory,
+ immediateCount: 1,
+ maxConcurrentRequests: 2,
+ total: 2,
+ timeout: 9999,
+ });
+ expect(factory).toHaveBeenCalledTimes(1);
+ expect(requests.length).toBe(2);
+
+ await waitForPromises();
+
+ expect(factory).toHaveBeenCalledTimes(1);
+
+ jest.runAllTimers();
+
+ await waitForPromises();
+
+ expect(factory).toHaveBeenCalledTimes(2);
+ res(createStreamResponse());
+ });
+});
diff --git a/spec/frontend/streaming/render_balancer_spec.js b/spec/frontend/streaming/render_balancer_spec.js
new file mode 100644
index 00000000000..dae0c98d678
--- /dev/null
+++ b/spec/frontend/streaming/render_balancer_spec.js
@@ -0,0 +1,69 @@
+import { RenderBalancer } from '~/streaming/render_balancer';
+
+const HIGH_FRAME_TIME = 100;
+const LOW_FRAME_TIME = 10;
+
+describe('renderBalancer', () => {
+ let frameTime = 0;
+ let frameTimeDelta = 0;
+ let decrease;
+ let increase;
+
+ const createBalancer = () => {
+ decrease = jest.fn();
+ increase = jest.fn();
+ return new RenderBalancer({
+ highFrameTime: HIGH_FRAME_TIME,
+ lowFrameTime: LOW_FRAME_TIME,
+ increase,
+ decrease,
+ });
+ };
+
+ const renderTimes = (times) => {
+ const balancer = createBalancer();
+ return new Promise((resolve) => {
+ let counter = 0;
+ balancer.render(() => {
+ if (counter === times) {
+ resolve(counter);
+ return false;
+ }
+ counter += 1;
+ return true;
+ });
+ });
+ };
+
+ beforeEach(() => {
+ jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => {
+ frameTime += frameTimeDelta;
+ cb(frameTime);
+ });
+ });
+
+ afterEach(() => {
+ window.requestAnimationFrame.mockRestore();
+ frameTime = 0;
+ frameTimeDelta = 0;
+ });
+
+ it('renders in a loop', async () => {
+ const count = await renderTimes(5);
+ expect(count).toBe(5);
+ });
+
+ it('calls decrease', async () => {
+ frameTimeDelta = 200;
+ await renderTimes(5);
+ expect(decrease).toHaveBeenCalled();
+ expect(increase).not.toHaveBeenCalled();
+ });
+
+ it('calls increase', async () => {
+ frameTimeDelta = 1;
+ await renderTimes(5);
+ expect(increase).toHaveBeenCalled();
+ expect(decrease).not.toHaveBeenCalled();
+ });
+});
diff --git a/spec/frontend/streaming/render_html_streams_spec.js b/spec/frontend/streaming/render_html_streams_spec.js
new file mode 100644
index 00000000000..55cef0ea469
--- /dev/null
+++ b/spec/frontend/streaming/render_html_streams_spec.js
@@ -0,0 +1,96 @@
+import { ReadableStream } from 'node:stream/web';
+import { renderHtmlStreams } from '~/streaming/render_html_streams';
+import { HtmlStream } from '~/streaming/html_stream';
+import waitForPromises from 'helpers/wait_for_promises';
+
+jest.mock('~/streaming/html_stream');
+jest.mock('~/streaming/constants', () => {
+ return {
+ HIGH_FRAME_TIME: 0,
+ LOW_FRAME_TIME: 0,
+ MAX_CHUNK_SIZE: 1,
+ MIN_CHUNK_SIZE: 1,
+ };
+});
+
+const firstStreamContent = 'foobar';
+const secondStreamContent = 'bazqux';
+
+describe('renderHtmlStreams', () => {
+ let htmlWriter;
+ const encoder = new TextEncoder();
+ const createSingleChunkStream = (chunk) => {
+ const encoded = encoder.encode(chunk);
+ const stream = new ReadableStream({
+ pull(controller) {
+ controller.enqueue(encoded);
+ controller.close();
+ },
+ });
+ return [stream, encoded];
+ };
+
+ beforeEach(() => {
+ htmlWriter = {
+ write: jest.fn(),
+ close: jest.fn(),
+ abort: jest.fn(),
+ };
+ jest.spyOn(HtmlStream.prototype, 'withChunkWriter').mockReturnValue(htmlWriter);
+ });
+
+ it('renders a single stream', async () => {
+ const [stream, encoded] = createSingleChunkStream(firstStreamContent);
+
+ await renderHtmlStreams([Promise.resolve(stream)], document.body);
+
+ expect(htmlWriter.write).toHaveBeenCalledWith(encoded);
+ expect(htmlWriter.close).toHaveBeenCalledTimes(1);
+ });
+
+ it('renders stream sequence', async () => {
+ const [stream1, encoded1] = createSingleChunkStream(firstStreamContent);
+ const [stream2, encoded2] = createSingleChunkStream(secondStreamContent);
+
+ await renderHtmlStreams([Promise.resolve(stream1), Promise.resolve(stream2)], document.body);
+
+ expect(htmlWriter.write.mock.calls).toMatchObject([[encoded1], [encoded2]]);
+ expect(htmlWriter.close).toHaveBeenCalledTimes(1);
+ });
+
+ it("doesn't wait for the whole sequence to resolve before streaming", async () => {
+ const [stream1, encoded1] = createSingleChunkStream(firstStreamContent);
+ const [stream2, encoded2] = createSingleChunkStream(secondStreamContent);
+
+ let res;
+ const delayedStream = new Promise((resolve) => {
+ res = resolve;
+ });
+
+ renderHtmlStreams([Promise.resolve(stream1), delayedStream], document.body);
+
+ await waitForPromises();
+
+ expect(htmlWriter.write.mock.calls).toMatchObject([[encoded1]]);
+ expect(htmlWriter.close).toHaveBeenCalledTimes(0);
+
+ res(stream2);
+ await waitForPromises();
+
+ expect(htmlWriter.write.mock.calls).toMatchObject([[encoded1], [encoded2]]);
+ expect(htmlWriter.close).toHaveBeenCalledTimes(1);
+ });
+
+ it('closes HtmlStream on error', async () => {
+ const [stream1] = createSingleChunkStream(firstStreamContent);
+ const error = new Error();
+
+ try {
+ await renderHtmlStreams([Promise.resolve(stream1), Promise.reject(error)], document.body);
+ } catch (err) {
+ expect(err).toBe(error);
+ }
+
+ expect(htmlWriter.abort).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/context_switcher_spec.js b/spec/frontend/super_sidebar/components/context_switcher_spec.js
new file mode 100644
index 00000000000..538e87cf843
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/context_switcher_spec.js
@@ -0,0 +1,219 @@
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlSearchBoxByType } 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 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 { 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 username = 'root';
+const projectsPath = 'projectsPath';
+const groupsPath = 'groupsPath';
+
+Vue.use(VueApollo);
+
+describe('ContextSwitcher component', () => {
+ let wrapper;
+ let mockApollo;
+
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findProjectsList = () => wrapper.findComponent(ProjectsList);
+ const findGroupsList = () => wrapper.findComponent(GroupsList);
+
+ 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,
+ propsData: {
+ username,
+ projectsPath,
+ groupsPath,
+ ...props,
+ },
+ stubs: {
+ GlSearchBoxByType: stubComponent(GlSearchBoxByType, {
+ props: ['placeholder'],
+ }),
+ ProjectsList: stubComponent(ProjectsList, {
+ props: ['username', 'viewAllLink', 'isSearch', 'searchResults'],
+ }),
+ GroupsList: stubComponent(GroupsList, {
+ props: ['username', 'viewAllLink', 'isSearch', 'searchResults'],
+ }),
+ },
+ });
+ };
+
+ describe('default', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('passes the placeholder to the search box', () => {
+ expect(findSearchBox().props('placeholder')).toBe(
+ s__('Navigation|Search for projects or groups'),
+ );
+ });
+
+ it('passes the correct props the frequent projects list', () => {
+ expect(findProjectsList().props()).toEqual({
+ username,
+ viewAllLink: projectsPath,
+ isSearch: false,
+ searchResults: [],
+ });
+ });
+
+ it('passes the correct props 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();
+ });
+ });
+
+ 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('triggers the search query on search', () => {
+ expect(searchUserProjectsAndGroupsHandlerSuccess).toHaveBeenCalled();
+ });
+
+ 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 if response is formatted incorrectly', async () => {
+ createWrapper({
+ requestHandlers: {
+ searchUserProjectsAndGroupsQueryHandler: jest.fn().mockResolvedValue({
+ data: {},
+ }),
+ },
+ });
+ await triggerSearchQuery();
+
+ expect(Sentry.captureException).toHaveBeenCalled();
+ });
+
+ it('captures exception if query fails', async () => {
+ createWrapper({
+ requestHandlers: {
+ searchUserProjectsAndGroupsQueryHandler: jest.fn().mockRejectedValue(),
+ },
+ });
+ await triggerSearchQuery();
+
+ expect(Sentry.captureException).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js b/spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js
new file mode 100644
index 00000000000..7172b60d0fa
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js
@@ -0,0 +1,50 @@
+import { GlAvatar } 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 findGlAvatar = () => wrapper.getComponent(GlAvatar);
+
+ const createWrapper = (props = {}) => {
+ wrapper = shallowMountExtended(ContextSwitcherToggle, {
+ 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/frequent_items_list_spec.js b/spec/frontend/super_sidebar/components/frequent_items_list_spec.js
new file mode 100644
index 00000000000..1e98db091f2
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/frequent_items_list_spec.js
@@ -0,0 +1,68 @@
+import { shallowMountExtended } 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 createWrapper = ({ props = {} } = {}) => {
+ wrapper = shallowMountExtended(FrequentItemsList, {
+ propsData: {
+ title,
+ pristineText,
+ storageKey,
+ maxItems,
+ ...props,
+ },
+ });
+ };
+
+ 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);
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js b/spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js
new file mode 100644
index 00000000000..e5ba1c63996
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js
@@ -0,0 +1,238 @@
+import { GlDropdownItem, GlLoadingIcon, GlAvatar, GlAlert, GlDropdownDivider } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
+import HeaderSearchAutocompleteItems from '~/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue';
+import {
+ LARGE_AVATAR_PX,
+ SMALL_AVATAR_PX,
+} from '~/super_sidebar/components/global_search/constants';
+import {
+ PROJECTS_CATEGORY,
+ GROUPS_CATEGORY,
+ ISSUES_CATEGORY,
+ MERGE_REQUEST_CATEGORY,
+ RECENT_EPICS_CATEGORY,
+} from '~/vue_shared/global_search/constants';
+import {
+ MOCK_GROUPED_AUTOCOMPLETE_OPTIONS,
+ MOCK_SORTED_AUTOCOMPLETE_OPTIONS,
+ MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_SETTINGS_HELP,
+ MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_HELP,
+ MOCK_SEARCH,
+ MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_2,
+} from '../mock_data';
+
+Vue.use(Vuex);
+
+describe('HeaderSearchAutocompleteItems', () => {
+ let wrapper;
+
+ const createComponent = (initialState, mockGetters, props) => {
+ const store = new Vuex.Store({
+ state: {
+ loading: false,
+ ...initialState,
+ },
+ getters: {
+ autocompleteGroupedSearchOptions: () => MOCK_GROUPED_AUTOCOMPLETE_OPTIONS,
+ ...mockGetters,
+ },
+ });
+
+ wrapper = shallowMount(HeaderSearchAutocompleteItems, {
+ store,
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findGlDropdownDividers = () => wrapper.findAllComponents(GlDropdownDivider);
+ const findFirstDropdownItem = () => findDropdownItems().at(0);
+ const findDropdownItemTitles = () =>
+ findDropdownItems().wrappers.map((w) => w.findAll('span').at(1).text());
+ const findDropdownItemSubTitles = () =>
+ findDropdownItems()
+ .wrappers.filter((w) => w.findAll('span').length > 2)
+ .map((w) => w.findAll('span').at(2).text());
+ const findDropdownItemLinks = () => findDropdownItems().wrappers.map((w) => w.attributes('href'));
+ const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findGlAvatar = () => wrapper.findComponent(GlAvatar);
+ const findGlAlert = () => wrapper.findComponent(GlAlert);
+
+ describe('template', () => {
+ describe('when loading is true', () => {
+ beforeEach(() => {
+ createComponent({ loading: true });
+ });
+
+ it('renders GlLoadingIcon', () => {
+ expect(findGlLoadingIcon().exists()).toBe(true);
+ });
+
+ it('does not render autocomplete options', () => {
+ expect(findDropdownItems()).toHaveLength(0);
+ });
+ });
+
+ describe('when api returns error', () => {
+ beforeEach(() => {
+ createComponent({ autocompleteError: true });
+ });
+
+ it('renders Alert', () => {
+ expect(findGlAlert().exists()).toBe(true);
+ });
+ });
+ describe('when loading is false', () => {
+ beforeEach(() => {
+ createComponent({ loading: false });
+ });
+
+ it('does not render GlLoadingIcon', () => {
+ expect(findGlLoadingIcon().exists()).toBe(false);
+ });
+
+ describe('Dropdown items', () => {
+ it('renders item for each option in autocomplete option', () => {
+ expect(findDropdownItems()).toHaveLength(MOCK_SORTED_AUTOCOMPLETE_OPTIONS.length);
+ });
+
+ it('renders titles correctly', () => {
+ const expectedTitles = MOCK_SORTED_AUTOCOMPLETE_OPTIONS.map((o) => o.value || o.label);
+ expect(findDropdownItemTitles()).toStrictEqual(expectedTitles);
+ });
+
+ it('renders sub-titles correctly', () => {
+ const expectedSubTitles = MOCK_SORTED_AUTOCOMPLETE_OPTIONS.filter((o) => o.value).map(
+ (o) => o.label,
+ );
+ expect(findDropdownItemSubTitles()).toStrictEqual(expectedSubTitles);
+ });
+
+ it('renders links correctly', () => {
+ const expectedLinks = MOCK_SORTED_AUTOCOMPLETE_OPTIONS.map((o) => o.url);
+ expect(findDropdownItemLinks()).toStrictEqual(expectedLinks);
+ });
+ });
+
+ describe.each`
+ item | showAvatar | avatarSize | searchContext | entityId | entityName
+ ${{ data: [{ category: PROJECTS_CATEGORY, avatar_url: null }] }} | ${true} | ${String(LARGE_AVATAR_PX)} | ${{ project: { id: 29 } }} | ${'29'} | ${''}
+ ${{ data: [{ category: GROUPS_CATEGORY, avatar_url: '/123' }] }} | ${true} | ${String(LARGE_AVATAR_PX)} | ${{ group: { id: 12 } }} | ${'12'} | ${''}
+ ${{ data: [{ category: 'Help', avatar_url: '' }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${null} | ${'0'} | ${''}
+ ${{ data: [{ category: 'Settings' }] }} | ${false} | ${false} | ${null} | ${false} | ${false}
+ ${{ data: [{ category: GROUPS_CATEGORY, avatar_url: null }] }} | ${true} | ${String(LARGE_AVATAR_PX)} | ${{ group: { id: 1, name: 'test1' } }} | ${'1'} | ${'test1'}
+ ${{ data: [{ category: PROJECTS_CATEGORY, avatar_url: null }] }} | ${true} | ${String(LARGE_AVATAR_PX)} | ${{ project: { id: 2, name: 'test2' } }} | ${'2'} | ${'test2'}
+ ${{ data: [{ category: ISSUES_CATEGORY, avatar_url: null }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${{ project: { id: 3, name: 'test3' } }} | ${'3'} | ${'test3'}
+ ${{ data: [{ category: MERGE_REQUEST_CATEGORY, avatar_url: null }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${{ project: { id: 4, name: 'test4' } }} | ${'4'} | ${'test4'}
+ ${{ data: [{ category: RECENT_EPICS_CATEGORY, avatar_url: null }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${{ group: { id: 5, name: 'test5' } }} | ${'5'} | ${'test5'}
+ ${{ data: [{ category: GROUPS_CATEGORY, avatar_url: null, group_id: 6, group_name: 'test6' }] }} | ${true} | ${String(LARGE_AVATAR_PX)} | ${null} | ${'6'} | ${'test6'}
+ ${{ data: [{ category: PROJECTS_CATEGORY, avatar_url: null, project_id: 7, project_name: 'test7' }] }} | ${true} | ${String(LARGE_AVATAR_PX)} | ${null} | ${'7'} | ${'test7'}
+ ${{ data: [{ category: ISSUES_CATEGORY, avatar_url: null, project_id: 8, project_name: 'test8' }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${null} | ${'8'} | ${'test8'}
+ ${{ data: [{ category: MERGE_REQUEST_CATEGORY, avatar_url: null, project_id: 9, project_name: 'test9' }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${null} | ${'9'} | ${'test9'}
+ ${{ data: [{ category: RECENT_EPICS_CATEGORY, avatar_url: null, group_id: 10, group_name: 'test10' }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${null} | ${'10'} | ${'test10'}
+ ${{ data: [{ category: GROUPS_CATEGORY, avatar_url: null, group_id: 11, group_name: 'test11' }] }} | ${true} | ${String(LARGE_AVATAR_PX)} | ${{ group: { id: 1, name: 'test1' } }} | ${'11'} | ${'test11'}
+ ${{ data: [{ category: PROJECTS_CATEGORY, avatar_url: null, project_id: 12, project_name: 'test12' }] }} | ${true} | ${String(LARGE_AVATAR_PX)} | ${{ project: { id: 2, name: 'test2' } }} | ${'12'} | ${'test12'}
+ ${{ data: [{ category: ISSUES_CATEGORY, avatar_url: null, project_id: 13, project_name: 'test13' }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${{ project: { id: 3, name: 'test3' } }} | ${'13'} | ${'test13'}
+ ${{ data: [{ category: MERGE_REQUEST_CATEGORY, avatar_url: null, project_id: 14, project_name: 'test14' }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${{ project: { id: 4, name: 'test4' } }} | ${'14'} | ${'test14'}
+ ${{ data: [{ category: RECENT_EPICS_CATEGORY, avatar_url: null, group_id: 15, group_name: 'test15' }] }} | ${true} | ${String(SMALL_AVATAR_PX)} | ${{ group: { id: 5, name: 'test5' } }} | ${'15'} | ${'test15'}
+ `('GlAvatar', ({ item, showAvatar, avatarSize, searchContext, entityId, entityName }) => {
+ describe(`when category is ${item.data[0].category} and avatar_url is ${item.data[0].avatar_url}`, () => {
+ beforeEach(() => {
+ createComponent({ searchContext }, { autocompleteGroupedSearchOptions: () => [item] });
+ });
+
+ it(`should${showAvatar ? '' : ' not'} render`, () => {
+ expect(findGlAvatar().exists()).toBe(showAvatar);
+ });
+
+ it(`should set avatarSize to ${avatarSize}`, () => {
+ expect(findGlAvatar().exists() && findGlAvatar().attributes('size')).toBe(avatarSize);
+ });
+
+ it(`should set avatar entityId to ${entityId}`, () => {
+ expect(findGlAvatar().exists() && findGlAvatar().attributes('entityid')).toBe(entityId);
+ });
+
+ it(`should set avatar entityName to ${entityName}`, () => {
+ expect(findGlAvatar().exists() && findGlAvatar().attributes('entityname')).toBe(
+ entityName,
+ );
+ });
+ });
+ });
+ });
+
+ describe.each`
+ currentFocusedOption | isFocused | ariaSelected
+ ${null} | ${false} | ${undefined}
+ ${{ html_id: 'not-a-match' }} | ${false} | ${undefined}
+ ${MOCK_SORTED_AUTOCOMPLETE_OPTIONS[0]} | ${true} | ${'true'}
+ `('isOptionFocused', ({ currentFocusedOption, isFocused, ariaSelected }) => {
+ describe(`when currentFocusedOption.html_id is ${currentFocusedOption?.html_id}`, () => {
+ beforeEach(() => {
+ createComponent({}, {}, { currentFocusedOption });
+ });
+
+ it(`should${isFocused ? '' : ' not'} have gl-bg-gray-50 applied`, () => {
+ expect(findFirstDropdownItem().classes('gl-bg-gray-50')).toBe(isFocused);
+ });
+
+ it(`sets "aria-selected to ${ariaSelected}`, () => {
+ expect(findFirstDropdownItem().attributes('aria-selected')).toBe(ariaSelected);
+ });
+ });
+ });
+
+ describe.each`
+ search | items | dividerCount
+ ${null} | ${[]} | ${0}
+ ${''} | ${[]} | ${0}
+ ${'1'} | ${[]} | ${0}
+ ${')'} | ${[]} | ${0}
+ ${'t'} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_SETTINGS_HELP} | ${1}
+ ${'te'} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_HELP} | ${0}
+ ${'tes'} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_2} | ${1}
+ ${MOCK_SEARCH} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_2} | ${1}
+ `('Header Search Dropdown Dividers', ({ search, items, dividerCount }) => {
+ describe(`when search is ${search}`, () => {
+ beforeEach(() => {
+ createComponent(
+ { search },
+ {
+ autocompleteGroupedSearchOptions: () => items,
+ },
+ {},
+ );
+ });
+
+ it(`component should have ${dividerCount} dividers`, () => {
+ expect(findGlDropdownDividers()).toHaveLength(dividerCount);
+ });
+ });
+ });
+ });
+
+ describe('watchers', () => {
+ describe('currentFocusedOption', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('when focused changes to existing element calls scroll into view on the newly focused element', async () => {
+ const focusedElement = findFirstDropdownItem().element;
+ const scrollSpy = jest.spyOn(focusedElement, 'scrollIntoView');
+
+ wrapper.setProps({ currentFocusedOption: MOCK_SORTED_AUTOCOMPLETE_OPTIONS[0] });
+
+ await nextTick();
+
+ expect(scrollSpy).toHaveBeenCalledWith(false);
+ scrollSpy.mockRestore();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js b/spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js
new file mode 100644
index 00000000000..132f8e60598
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js
@@ -0,0 +1,102 @@
+import { GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import Vuex from 'vuex';
+import HeaderSearchDefaultItems from '~/super_sidebar/components/global_search/components/global_search_default_items.vue';
+import { MOCK_SEARCH_CONTEXT, MOCK_DEFAULT_SEARCH_OPTIONS } from '../mock_data';
+
+Vue.use(Vuex);
+
+describe('HeaderSearchDefaultItems', () => {
+ let wrapper;
+
+ const createComponent = (initialState, props) => {
+ const store = new Vuex.Store({
+ state: {
+ searchContext: MOCK_SEARCH_CONTEXT,
+ ...initialState,
+ },
+ getters: {
+ defaultSearchOptions: () => MOCK_DEFAULT_SEARCH_OPTIONS,
+ },
+ });
+
+ wrapper = shallowMount(HeaderSearchDefaultItems, {
+ store,
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findDropdownHeader = () => wrapper.findComponent(GlDropdownSectionHeader);
+ const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findFirstDropdownItem = () => findDropdownItems().at(0);
+ const findDropdownItemTitles = () => findDropdownItems().wrappers.map((w) => w.text());
+ const findDropdownItemLinks = () => findDropdownItems().wrappers.map((w) => w.attributes('href'));
+
+ describe('template', () => {
+ describe('Dropdown items', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders item for each option in defaultSearchOptions', () => {
+ expect(findDropdownItems()).toHaveLength(MOCK_DEFAULT_SEARCH_OPTIONS.length);
+ });
+
+ it('renders titles correctly', () => {
+ const expectedTitles = MOCK_DEFAULT_SEARCH_OPTIONS.map((o) => o.title);
+ expect(findDropdownItemTitles()).toStrictEqual(expectedTitles);
+ });
+
+ it('renders links correctly', () => {
+ const expectedLinks = MOCK_DEFAULT_SEARCH_OPTIONS.map((o) => o.url);
+ expect(findDropdownItemLinks()).toStrictEqual(expectedLinks);
+ });
+ });
+
+ describe.each`
+ group | project | dropdownTitle
+ ${null} | ${null} | ${'All GitLab'}
+ ${{ name: 'Test Group' }} | ${null} | ${'Test Group'}
+ ${{ name: 'Test Group' }} | ${{ name: 'Test Project' }} | ${'Test Project'}
+ `('Dropdown Header', ({ group, project, dropdownTitle }) => {
+ describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
+ beforeEach(() => {
+ createComponent({
+ searchContext: {
+ group,
+ project,
+ },
+ });
+ });
+
+ it(`should render as ${dropdownTitle}`, () => {
+ expect(findDropdownHeader().text()).toBe(dropdownTitle);
+ });
+ });
+ });
+
+ describe.each`
+ currentFocusedOption | isFocused | ariaSelected
+ ${null} | ${false} | ${undefined}
+ ${{ html_id: 'not-a-match' }} | ${false} | ${undefined}
+ ${MOCK_DEFAULT_SEARCH_OPTIONS[0]} | ${true} | ${'true'}
+ `('isOptionFocused', ({ currentFocusedOption, isFocused, ariaSelected }) => {
+ describe(`when currentFocusedOption.html_id is ${currentFocusedOption?.html_id}`, () => {
+ beforeEach(() => {
+ createComponent({}, { currentFocusedOption });
+ });
+
+ it(`should${isFocused ? '' : ' not'} have gl-bg-gray-50 applied`, () => {
+ expect(findFirstDropdownItem().classes('gl-bg-gray-50')).toBe(isFocused);
+ });
+
+ it(`sets "aria-selected to ${ariaSelected}`, () => {
+ expect(findFirstDropdownItem().attributes('aria-selected')).toBe(ariaSelected);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/components/global_search_scoped_items_spec.js b/spec/frontend/super_sidebar/components/global_search/components/global_search_scoped_items_spec.js
new file mode 100644
index 00000000000..fa91ef43ced
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_scoped_items_spec.js
@@ -0,0 +1,120 @@
+import { GlDropdownItem, GlToken, GlIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { trimText } from 'helpers/text_helper';
+import HeaderSearchScopedItems from '~/super_sidebar/components/global_search/components/global_search_scoped_items.vue';
+import { truncate } from '~/lib/utils/text_utility';
+import { SCOPE_TOKEN_MAX_LENGTH } from '~/super_sidebar/components/global_search/constants';
+import { MSG_IN_ALL_GITLAB } from '~/vue_shared/global_search/constants';
+import {
+ MOCK_SEARCH,
+ MOCK_SCOPED_SEARCH_OPTIONS,
+ MOCK_GROUPED_AUTOCOMPLETE_OPTIONS,
+} from '../mock_data';
+
+Vue.use(Vuex);
+
+describe('HeaderSearchScopedItems', () => {
+ let wrapper;
+
+ const createComponent = (initialState, mockGetters, props) => {
+ const store = new Vuex.Store({
+ state: {
+ search: MOCK_SEARCH,
+ ...initialState,
+ },
+ getters: {
+ scopedSearchOptions: () => MOCK_SCOPED_SEARCH_OPTIONS,
+ autocompleteGroupedSearchOptions: () => MOCK_GROUPED_AUTOCOMPLETE_OPTIONS,
+ ...mockGetters,
+ },
+ });
+
+ wrapper = shallowMount(HeaderSearchScopedItems, {
+ store,
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findFirstDropdownItem = () => findDropdownItems().at(0);
+ const findDropdownItemTitles = () => findDropdownItems().wrappers.map((w) => trimText(w.text()));
+ const findScopeTokens = () => wrapper.findAllComponents(GlToken);
+ const findScopeTokensText = () => findScopeTokens().wrappers.map((w) => trimText(w.text()));
+ const findScopeTokensIcons = () =>
+ findScopeTokens().wrappers.map((w) => w.findAllComponents(GlIcon));
+ const findDropdownItemAriaLabels = () =>
+ findDropdownItems().wrappers.map((w) => trimText(w.attributes('aria-label')));
+ const findDropdownItemLinks = () => findDropdownItems().wrappers.map((w) => w.attributes('href'));
+
+ describe('template', () => {
+ describe('Dropdown items', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders item for each option in scopedSearchOptions', () => {
+ expect(findDropdownItems()).toHaveLength(MOCK_SCOPED_SEARCH_OPTIONS.length);
+ });
+
+ it('renders titles correctly', () => {
+ findDropdownItemTitles().forEach((title) => expect(title).toContain(MOCK_SEARCH));
+ });
+
+ it('renders scope names correctly', () => {
+ const expectedTitles = MOCK_SCOPED_SEARCH_OPTIONS.map((o) =>
+ truncate(trimText(`in ${o.description || o.scope}`), SCOPE_TOKEN_MAX_LENGTH),
+ );
+
+ expect(findScopeTokensText()).toStrictEqual(expectedTitles);
+ });
+
+ it('renders scope icons correctly', () => {
+ findScopeTokensIcons().forEach((icon, i) => {
+ const w = icon.wrappers[0];
+ expect(w?.attributes('name')).toBe(MOCK_SCOPED_SEARCH_OPTIONS[i].icon);
+ });
+ });
+
+ it(`renders scope ${MSG_IN_ALL_GITLAB} correctly`, () => {
+ expect(findScopeTokens().at(-1).findComponent(GlIcon).exists()).toBe(false);
+ });
+
+ it('renders aria-labels correctly', () => {
+ const expectedLabels = MOCK_SCOPED_SEARCH_OPTIONS.map((o) =>
+ trimText(`${MOCK_SEARCH} ${o.description || o.icon} ${o.scope || ''}`),
+ );
+ expect(findDropdownItemAriaLabels()).toStrictEqual(expectedLabels);
+ });
+
+ it('renders links correctly', () => {
+ const expectedLinks = MOCK_SCOPED_SEARCH_OPTIONS.map((o) => o.url);
+ expect(findDropdownItemLinks()).toStrictEqual(expectedLinks);
+ });
+ });
+
+ describe.each`
+ currentFocusedOption | isFocused | ariaSelected
+ ${null} | ${false} | ${undefined}
+ ${{ html_id: 'not-a-match' }} | ${false} | ${undefined}
+ ${MOCK_SCOPED_SEARCH_OPTIONS[0]} | ${true} | ${'true'}
+ `('isOptionFocused', ({ currentFocusedOption, isFocused, ariaSelected }) => {
+ describe(`when currentFocusedOption.html_id is ${currentFocusedOption?.html_id}`, () => {
+ beforeEach(() => {
+ createComponent({}, {}, { currentFocusedOption });
+ });
+
+ it(`should${isFocused ? '' : ' not'} have gl-bg-gray-50 applied`, () => {
+ expect(findFirstDropdownItem().classes('gl-bg-gray-50')).toBe(isFocused);
+ });
+
+ it(`sets "aria-selected to ${ariaSelected}`, () => {
+ expect(findFirstDropdownItem().attributes('aria-selected')).toBe(ariaSelected);
+ });
+ });
+ });
+ });
+});
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
new file mode 100644
index 00000000000..0dcfc448125
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js
@@ -0,0 +1,516 @@
+import { GlSearchBoxByType, GlToken, GlIcon } from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mockTracking } from 'helpers/tracking_helper';
+import { s__, sprintf } from '~/locale';
+import HeaderSearchApp from '~/super_sidebar/components/global_search/components/global_search.vue';
+import HeaderSearchAutocompleteItems from '~/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue';
+import HeaderSearchDefaultItems from '~/super_sidebar/components/global_search/components/global_search_default_items.vue';
+import HeaderSearchScopedItems from '~/super_sidebar/components/global_search/components/global_search_scoped_items.vue';
+import {
+ SEARCH_INPUT_DESCRIPTION,
+ SEARCH_RESULTS_DESCRIPTION,
+ SEARCH_BOX_INDEX,
+ ICON_PROJECT,
+ ICON_GROUP,
+ ICON_SUBGROUP,
+ SCOPE_TOKEN_MAX_LENGTH,
+ IS_SEARCHING,
+ IS_NOT_FOCUSED,
+ IS_FOCUSED,
+ SEARCH_SHORTCUTS_MIN_CHARACTERS,
+} from '~/super_sidebar/components/global_search/constants';
+import DropdownKeyboardNavigation from '~/vue_shared/components/dropdown_keyboard_navigation.vue';
+import { ENTER_KEY } from '~/lib/utils/keys';
+import { visitUrl } from '~/lib/utils/url_utility';
+import { truncate } from '~/lib/utils/text_utility';
+import {
+ MOCK_SEARCH,
+ MOCK_SEARCH_QUERY,
+ MOCK_USERNAME,
+ MOCK_DEFAULT_SEARCH_OPTIONS,
+ MOCK_SCOPED_SEARCH_OPTIONS,
+ MOCK_SEARCH_CONTEXT_FULL,
+} from '../mock_data';
+
+Vue.use(Vuex);
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ visitUrl: jest.fn(),
+}));
+
+describe('HeaderSearchApp', () => {
+ let wrapper;
+
+ const actionSpies = {
+ setSearch: jest.fn(),
+ fetchAutocompleteOptions: jest.fn(),
+ clearAutocomplete: jest.fn(),
+ };
+
+ const createComponent = (initialState, mockGetters) => {
+ const store = new Vuex.Store({
+ state: {
+ ...initialState,
+ },
+ actions: actionSpies,
+ getters: {
+ searchQuery: () => MOCK_SEARCH_QUERY,
+ searchOptions: () => MOCK_DEFAULT_SEARCH_OPTIONS,
+ ...mockGetters,
+ },
+ });
+
+ wrapper = shallowMountExtended(HeaderSearchApp, {
+ store,
+ });
+ };
+
+ const formatScopeName = (scopeName) => {
+ if (!scopeName) {
+ return false;
+ }
+ const searchResultsScope = s__('GlobalSearch|in %{scope}');
+ return truncate(
+ sprintf(searchResultsScope, {
+ scope: scopeName,
+ }),
+ SCOPE_TOKEN_MAX_LENGTH,
+ );
+ };
+
+ const findHeaderSearchForm = () => wrapper.findByTestId('header-search-form');
+ const findHeaderSearchInput = () => wrapper.findComponent(GlSearchBoxByType);
+ const findScopeToken = () => wrapper.findComponent(GlToken);
+ const findHeaderSearchInputKBD = () => wrapper.find('.keyboard-shortcut-helper');
+ const findHeaderSearchDropdown = () => wrapper.findByTestId('header-search-dropdown-menu');
+ const findHeaderSearchDefaultItems = () => wrapper.findComponent(HeaderSearchDefaultItems);
+ const findHeaderSearchScopedItems = () => wrapper.findComponent(HeaderSearchScopedItems);
+ const findHeaderSearchAutocompleteItems = () =>
+ wrapper.findComponent(HeaderSearchAutocompleteItems);
+ const findDropdownKeyboardNavigation = () => wrapper.findComponent(DropdownKeyboardNavigation);
+ const findSearchInputDescription = () => wrapper.find(`#${SEARCH_INPUT_DESCRIPTION}`);
+ const findSearchResultsDescription = () => wrapper.findByTestId(SEARCH_RESULTS_DESCRIPTION);
+
+ describe('template', () => {
+ describe('always renders', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('Header Search Input', () => {
+ expect(findHeaderSearchInput().exists()).toBe(true);
+ });
+
+ it('Header Search Input KBD hint', () => {
+ expect(findHeaderSearchInputKBD().exists()).toBe(true);
+ expect(findHeaderSearchInputKBD().text()).toContain('/');
+ expect(findHeaderSearchInputKBD().attributes('title')).toContain(
+ 'Use the shortcut key <kbd>/</kbd> to start a search',
+ );
+ });
+
+ it('Search Input Description', () => {
+ expect(findSearchInputDescription().exists()).toBe(true);
+ });
+
+ it('Search Results Description', () => {
+ expect(findSearchResultsDescription().exists()).toBe(true);
+ });
+ });
+
+ describe.each`
+ showDropdown | username | showSearchDropdown
+ ${false} | ${null} | ${false}
+ ${false} | ${MOCK_USERNAME} | ${false}
+ ${true} | ${null} | ${false}
+ ${true} | ${MOCK_USERNAME} | ${true}
+ `('Header Search Dropdown', ({ showDropdown, username, showSearchDropdown }) => {
+ describe(`when showDropdown is ${showDropdown} and current_username is ${username}`, () => {
+ beforeEach(() => {
+ window.gon.current_username = username;
+ createComponent();
+ findHeaderSearchInput().vm.$emit(showDropdown ? 'click' : '');
+ });
+
+ it(`should${showSearchDropdown ? '' : ' not'} render`, () => {
+ expect(findHeaderSearchDropdown().exists()).toBe(showSearchDropdown);
+ });
+ });
+ });
+
+ describe.each`
+ search | showDefault | showScoped | showAutocomplete
+ ${null} | ${true} | ${false} | ${false}
+ ${''} | ${true} | ${false} | ${false}
+ ${'t'} | ${false} | ${false} | ${true}
+ ${'te'} | ${false} | ${false} | ${true}
+ ${'tes'} | ${false} | ${true} | ${true}
+ ${MOCK_SEARCH} | ${false} | ${true} | ${true}
+ `('Header Search Dropdown Items', ({ search, showDefault, showScoped, showAutocomplete }) => {
+ describe(`when search is ${search}`, () => {
+ beforeEach(() => {
+ window.gon.current_username = MOCK_USERNAME;
+ createComponent({ search }, {});
+ findHeaderSearchInput().vm.$emit('click');
+ });
+
+ it(`should${showDefault ? '' : ' not'} render the Default Dropdown Items`, () => {
+ expect(findHeaderSearchDefaultItems().exists()).toBe(showDefault);
+ });
+
+ it(`should${showScoped ? '' : ' not'} render the Scoped Dropdown Items`, () => {
+ expect(findHeaderSearchScopedItems().exists()).toBe(showScoped);
+ });
+
+ it(`should${showAutocomplete ? '' : ' not'} render the Autocomplete Dropdown Items`, () => {
+ expect(findHeaderSearchAutocompleteItems().exists()).toBe(showAutocomplete);
+ });
+
+ it(`should render the Dropdown Navigation Component`, () => {
+ expect(findDropdownKeyboardNavigation().exists()).toBe(true);
+ });
+
+ it(`should close the dropdown when press escape key`, async () => {
+ findHeaderSearchInput().vm.$emit('keydown', new KeyboardEvent({ key: 27 }));
+ await nextTick();
+ expect(findHeaderSearchDropdown().exists()).toBe(false);
+ expect(wrapper.emitted().expandSearchBar.length).toBe(1);
+ });
+ });
+ });
+
+ describe.each`
+ username | showDropdown | expectedDesc
+ ${null} | ${false} | ${HeaderSearchApp.i18n.SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN}
+ ${null} | ${true} | ${HeaderSearchApp.i18n.SEARCH_INPUT_DESCRIBE_BY_NO_DROPDOWN}
+ ${MOCK_USERNAME} | ${false} | ${HeaderSearchApp.i18n.SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN}
+ ${MOCK_USERNAME} | ${true} | ${HeaderSearchApp.i18n.SEARCH_INPUT_DESCRIBE_BY_WITH_DROPDOWN}
+ `('Search Input Description', ({ username, showDropdown, expectedDesc }) => {
+ describe(`current_username is ${username} and showDropdown is ${showDropdown}`, () => {
+ beforeEach(() => {
+ window.gon.current_username = username;
+ createComponent();
+ findHeaderSearchInput().vm.$emit(showDropdown ? 'click' : '');
+ });
+
+ it(`sets description to ${expectedDesc}`, () => {
+ expect(findSearchInputDescription().text()).toBe(expectedDesc);
+ });
+ });
+ });
+
+ describe.each`
+ username | showDropdown | search | loading | searchOptions | expectedDesc
+ ${null} | ${true} | ${''} | ${false} | ${[]} | ${''}
+ ${MOCK_USERNAME} | ${false} | ${''} | ${false} | ${[]} | ${''}
+ ${MOCK_USERNAME} | ${true} | ${''} | ${false} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${`${MOCK_DEFAULT_SEARCH_OPTIONS.length} default results provided. Use the up and down arrow keys to navigate search results list.`}
+ ${MOCK_USERNAME} | ${true} | ${''} | ${true} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${`${MOCK_DEFAULT_SEARCH_OPTIONS.length} default results provided. Use the up and down arrow keys to navigate search results list.`}
+ ${MOCK_USERNAME} | ${true} | ${MOCK_SEARCH} | ${false} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${`Results updated. ${MOCK_SCOPED_SEARCH_OPTIONS.length} results available. Use the up and down arrow keys to navigate search results list, or ENTER to submit.`}
+ ${MOCK_USERNAME} | ${true} | ${MOCK_SEARCH} | ${true} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${HeaderSearchApp.i18n.SEARCH_RESULTS_LOADING}
+ `(
+ 'Search Results Description',
+ ({ username, showDropdown, search, loading, searchOptions, expectedDesc }) => {
+ describe(`search is "${search}", loading is ${loading}, and showSearchDropdown is ${showDropdown}`, () => {
+ beforeEach(() => {
+ window.gon.current_username = username;
+ createComponent(
+ {
+ search,
+ loading,
+ },
+ {
+ searchOptions: () => searchOptions,
+ },
+ );
+ findHeaderSearchInput().vm.$emit(showDropdown ? 'click' : '');
+ });
+
+ it(`sets description to ${expectedDesc}`, () => {
+ expect(findSearchResultsDescription().text()).toBe(expectedDesc);
+ });
+ });
+ },
+ );
+
+ describe('input box', () => {
+ describe.each`
+ search | searchOptions | hasToken
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[0]]} | ${true}
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[1]]} | ${true}
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[2]]} | ${true}
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[3]]} | ${true}
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[4]]} | ${true}
+ ${'te'} | ${[MOCK_SCOPED_SEARCH_OPTIONS[5]]} | ${false}
+ ${'x'} | ${[]} | ${false}
+ `('token', ({ search, searchOptions, hasToken }) => {
+ beforeEach(() => {
+ window.gon.current_username = MOCK_USERNAME;
+ createComponent(
+ { search },
+ {
+ searchOptions: () => searchOptions,
+ },
+ );
+ findHeaderSearchInput().vm.$emit('click');
+ });
+
+ it(`${hasToken ? 'is' : 'is NOT'} rendered when data set has type "${
+ searchOptions[0]?.html_id
+ }"`, () => {
+ expect(findScopeToken().exists()).toBe(hasToken);
+ });
+
+ it(`text ${hasToken ? 'is correctly' : 'is NOT'} rendered when text is "${
+ searchOptions[0]?.scope || searchOptions[0]?.description
+ }"`, () => {
+ expect(findScopeToken().exists() && findScopeToken().text()).toBe(
+ formatScopeName(searchOptions[0]?.scope || searchOptions[0]?.description),
+ );
+ });
+ });
+ });
+
+ describe('form', () => {
+ describe.each`
+ searchContext | search | searchOptions | isFocused
+ ${MOCK_SEARCH_CONTEXT_FULL} | ${null} | ${[]} | ${true}
+ ${MOCK_SEARCH_CONTEXT_FULL} | ${MOCK_SEARCH} | ${[]} | ${true}
+ ${MOCK_SEARCH_CONTEXT_FULL} | ${MOCK_SEARCH} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${true}
+ ${MOCK_SEARCH_CONTEXT_FULL} | ${MOCK_SEARCH} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${false}
+ ${null} | ${MOCK_SEARCH} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${true}
+ ${null} | ${null} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${true}
+ ${null} | ${null} | ${[]} | ${true}
+ `('wrapper', ({ searchContext, search, searchOptions, isFocused }) => {
+ beforeEach(() => {
+ window.gon.current_username = MOCK_USERNAME;
+ createComponent({ search, searchContext }, { searchOptions: () => searchOptions });
+ if (isFocused) {
+ findHeaderSearchInput().vm.$emit('click');
+ }
+ });
+
+ const isSearching = search?.length > SEARCH_SHORTCUTS_MIN_CHARACTERS;
+
+ it(`classes ${isSearching ? 'contain' : 'do not contain'} "${IS_SEARCHING}"`, () => {
+ if (isSearching) {
+ expect(findHeaderSearchForm().classes()).toContain(IS_SEARCHING);
+ return;
+ }
+ if (!isSearching) {
+ expect(findHeaderSearchForm().classes()).not.toContain(IS_SEARCHING);
+ }
+ });
+
+ it(`classes ${isSearching ? 'contain' : 'do not contain'} "${
+ isFocused ? IS_FOCUSED : IS_NOT_FOCUSED
+ }"`, () => {
+ expect(findHeaderSearchForm().classes()).toContain(
+ isFocused ? IS_FOCUSED : IS_NOT_FOCUSED,
+ );
+ });
+ });
+ });
+
+ describe.each`
+ search | searchOptions | hasIcon | iconName
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[0]]} | ${true} | ${ICON_PROJECT}
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[2]]} | ${true} | ${ICON_GROUP}
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[3]]} | ${true} | ${ICON_SUBGROUP}
+ ${MOCK_SEARCH} | ${[MOCK_SCOPED_SEARCH_OPTIONS[4]]} | ${false} | ${false}
+ `('token', ({ search, searchOptions, hasIcon, iconName }) => {
+ beforeEach(() => {
+ window.gon.current_username = MOCK_USERNAME;
+ createComponent(
+ { search },
+ {
+ searchOptions: () => searchOptions,
+ },
+ );
+ findHeaderSearchInput().vm.$emit('click');
+ });
+
+ it(`icon for data set type "${searchOptions[0]?.html_id}" ${
+ hasIcon ? 'is' : 'is NOT'
+ } rendered`, () => {
+ expect(findScopeToken().findComponent(GlIcon).exists()).toBe(hasIcon);
+ });
+
+ it(`render ${iconName ? `"${iconName}"` : 'NO'} icon for data set type "${
+ searchOptions[0]?.html_id
+ }"`, () => {
+ expect(
+ findScopeToken().findComponent(GlIcon).exists() &&
+ findScopeToken().findComponent(GlIcon).attributes('name'),
+ ).toBe(iconName);
+ });
+ });
+ });
+
+ describe('events', () => {
+ beforeEach(() => {
+ window.gon.current_username = MOCK_USERNAME;
+ createComponent();
+ });
+
+ describe('Header Search Input', () => {
+ describe('when dropdown is closed', () => {
+ let trackingSpy;
+
+ beforeEach(() => {
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ it('onFocus opens dropdown and triggers snowplow event', async () => {
+ expect(findHeaderSearchDropdown().exists()).toBe(false);
+ findHeaderSearchInput().vm.$emit('focus');
+
+ await nextTick();
+
+ expect(findHeaderSearchDropdown().exists()).toBe(true);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'focus_input', {
+ label: 'global_search',
+ property: 'navigation_top',
+ });
+ });
+
+ it('onClick opens dropdown and triggers snowplow event', async () => {
+ expect(findHeaderSearchDropdown().exists()).toBe(false);
+ findHeaderSearchInput().vm.$emit('click');
+
+ await nextTick();
+
+ expect(findHeaderSearchDropdown().exists()).toBe(true);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'focus_input', {
+ label: 'global_search',
+ property: 'navigation_top',
+ });
+ });
+
+ it('onClick followed by onFocus only triggers a single snowplow event', async () => {
+ findHeaderSearchInput().vm.$emit('click');
+ findHeaderSearchInput().vm.$emit('focus');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('onInput', () => {
+ describe('when search has text', () => {
+ beforeEach(() => {
+ findHeaderSearchInput().vm.$emit('input', MOCK_SEARCH);
+ });
+
+ it('calls setSearch with search term', () => {
+ expect(actionSpies.setSearch).toHaveBeenCalledWith(expect.any(Object), MOCK_SEARCH);
+ });
+
+ it('calls fetchAutocompleteOptions', () => {
+ expect(actionSpies.fetchAutocompleteOptions).toHaveBeenCalled();
+ });
+
+ it('does not call clearAutocomplete', () => {
+ expect(actionSpies.clearAutocomplete).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when search is emptied', () => {
+ beforeEach(() => {
+ findHeaderSearchInput().vm.$emit('input', '');
+ });
+
+ it('calls setSearch with empty term', () => {
+ expect(actionSpies.setSearch).toHaveBeenCalledWith(expect.any(Object), '');
+ });
+
+ it('does not call fetchAutocompleteOptions', () => {
+ expect(actionSpies.fetchAutocompleteOptions).not.toHaveBeenCalled();
+ });
+
+ it('calls clearAutocomplete', () => {
+ expect(actionSpies.clearAutocomplete).toHaveBeenCalled();
+ });
+ });
+ });
+ });
+
+ describe('Dropdown Keyboard Navigation', () => {
+ beforeEach(() => {
+ findHeaderSearchInput().vm.$emit('click');
+ });
+
+ it('closes dropdown when @tab is emitted', async () => {
+ expect(findHeaderSearchDropdown().exists()).toBe(true);
+ findDropdownKeyboardNavigation().vm.$emit('tab');
+
+ await nextTick();
+
+ expect(findHeaderSearchDropdown().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('computed', () => {
+ describe.each`
+ MOCK_INDEX | search
+ ${1} | ${null}
+ ${SEARCH_BOX_INDEX} | ${'test'}
+ ${2} | ${'test1'}
+ `('currentFocusedOption', ({ MOCK_INDEX, search }) => {
+ beforeEach(() => {
+ window.gon.current_username = MOCK_USERNAME;
+ createComponent({ search });
+ findHeaderSearchInput().vm.$emit('click');
+ });
+
+ it(`when currentFocusIndex changes to ${MOCK_INDEX} updates the data to searchOptions[${MOCK_INDEX}]`, () => {
+ findDropdownKeyboardNavigation().vm.$emit('change', MOCK_INDEX);
+ expect(wrapper.vm.currentFocusedOption).toBe(MOCK_DEFAULT_SEARCH_OPTIONS[MOCK_INDEX]);
+ });
+ });
+ });
+
+ describe('Submitting a search', () => {
+ describe('with no currentFocusedOption', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('onKey-enter submits a search', () => {
+ findHeaderSearchInput().vm.$emit('keydown', new KeyboardEvent({ key: ENTER_KEY }));
+
+ expect(visitUrl).toHaveBeenCalledWith(MOCK_SEARCH_QUERY);
+ });
+ });
+
+ describe('with less than min characters and no dropdown results', () => {
+ beforeEach(() => {
+ createComponent({ search: 'x' });
+ });
+
+ it('onKey-enter will NOT submit a search', () => {
+ findHeaderSearchInput().vm.$emit('keydown', new KeyboardEvent({ key: ENTER_KEY }));
+
+ expect(visitUrl).not.toHaveBeenCalledWith(MOCK_SEARCH_QUERY);
+ });
+ });
+
+ describe('with currentFocusedOption', () => {
+ const MOCK_INDEX = 1;
+
+ beforeEach(() => {
+ window.gon.current_username = MOCK_USERNAME;
+ createComponent();
+ findHeaderSearchInput().vm.$emit('click');
+ });
+
+ it('onKey-enter clicks the selected dropdown item rather than submitting a search', () => {
+ findDropdownKeyboardNavigation().vm.$emit('change', MOCK_INDEX);
+
+ findHeaderSearchInput().vm.$emit('keydown', new KeyboardEvent({ key: ENTER_KEY }));
+ expect(visitUrl).toHaveBeenCalledWith(MOCK_DEFAULT_SEARCH_OPTIONS[MOCK_INDEX].url);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/mock_data.js b/spec/frontend/super_sidebar/components/global_search/mock_data.js
new file mode 100644
index 00000000000..58e578e4c4c
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/mock_data.js
@@ -0,0 +1,404 @@
+import {
+ ICON_PROJECT,
+ ICON_GROUP,
+ ICON_SUBGROUP,
+} from '~/super_sidebar/components/global_search/constants';
+import {
+ PROJECTS_CATEGORY,
+ GROUPS_CATEGORY,
+ MSG_ISSUES_ASSIGNED_TO_ME,
+ MSG_ISSUES_IVE_CREATED,
+ MSG_MR_ASSIGNED_TO_ME,
+ MSG_MR_IM_REVIEWER,
+ MSG_MR_IVE_CREATED,
+ MSG_IN_ALL_GITLAB,
+} from '~/vue_shared/global_search/constants';
+
+export const MOCK_USERNAME = 'anyone';
+
+export const MOCK_SEARCH_PATH = '/search';
+
+export const MOCK_ISSUE_PATH = '/dashboard/issues';
+
+export const MOCK_MR_PATH = '/dashboard/merge_requests';
+
+export const MOCK_ALL_PATH = '/';
+
+export const MOCK_AUTOCOMPLETE_PATH = '/autocomplete';
+
+export const MOCK_PROJECT = {
+ id: 123,
+ name: 'MockProject',
+ path: '/mock-project',
+};
+
+export const MOCK_PROJECT_LONG = {
+ id: 124,
+ name: 'Mock Project Name That Is Ridiculously Long And It Goes Forever',
+ path: '/mock-project-name-that-is-ridiculously-long-and-it-goes-forever',
+};
+
+export const MOCK_GROUP = {
+ id: 321,
+ name: 'MockGroup',
+ path: '/mock-group',
+};
+
+export const MOCK_SUBGROUP = {
+ id: 322,
+ name: 'MockSubGroup',
+ path: `${MOCK_GROUP}/mock-subgroup`,
+};
+
+export const MOCK_SEARCH_QUERY = 'http://gitlab.com/search?search=test';
+
+export const MOCK_SEARCH = 'test';
+
+export const MOCK_SEARCH_CONTEXT = {
+ project: null,
+ project_metadata: {},
+ group: null,
+ group_metadata: {},
+};
+
+export const MOCK_SEARCH_CONTEXT_FULL = {
+ group: {
+ id: 31,
+ name: 'testGroup',
+ full_name: 'testGroup',
+ },
+ group_metadata: {
+ group_path: 'testGroup',
+ name: 'testGroup',
+ issues_path: '/groups/testGroup/-/issues',
+ mr_path: '/groups/testGroup/-/merge_requests',
+ },
+};
+
+export const MOCK_DEFAULT_SEARCH_OPTIONS = [
+ {
+ html_id: 'default-issues-assigned',
+ title: MSG_ISSUES_ASSIGNED_TO_ME,
+ url: `${MOCK_ISSUE_PATH}/?assignee_username=${MOCK_USERNAME}`,
+ },
+ {
+ html_id: 'default-issues-created',
+ title: MSG_ISSUES_IVE_CREATED,
+ url: `${MOCK_ISSUE_PATH}/?author_username=${MOCK_USERNAME}`,
+ },
+ {
+ html_id: 'default-mrs-assigned',
+ title: MSG_MR_ASSIGNED_TO_ME,
+ url: `${MOCK_MR_PATH}/?assignee_username=${MOCK_USERNAME}`,
+ },
+ {
+ html_id: 'default-mrs-reviewer',
+ title: MSG_MR_IM_REVIEWER,
+ url: `${MOCK_MR_PATH}/?reviewer_username=${MOCK_USERNAME}`,
+ },
+ {
+ html_id: 'default-mrs-created',
+ title: MSG_MR_IVE_CREATED,
+ url: `${MOCK_MR_PATH}/?author_username=${MOCK_USERNAME}`,
+ },
+];
+
+export const MOCK_SCOPED_SEARCH_OPTIONS = [
+ {
+ html_id: 'scoped-in-project',
+ scope: MOCK_PROJECT.name,
+ scopeCategory: PROJECTS_CATEGORY,
+ icon: ICON_PROJECT,
+ url: MOCK_PROJECT.path,
+ },
+ {
+ html_id: 'scoped-in-project-long',
+ scope: MOCK_PROJECT_LONG.name,
+ scopeCategory: PROJECTS_CATEGORY,
+ icon: ICON_PROJECT,
+ url: MOCK_PROJECT_LONG.path,
+ },
+ {
+ html_id: 'scoped-in-group',
+ scope: MOCK_GROUP.name,
+ scopeCategory: GROUPS_CATEGORY,
+ icon: ICON_GROUP,
+ url: MOCK_GROUP.path,
+ },
+ {
+ html_id: 'scoped-in-subgroup',
+ scope: MOCK_SUBGROUP.name,
+ scopeCategory: GROUPS_CATEGORY,
+ icon: ICON_SUBGROUP,
+ url: MOCK_SUBGROUP.path,
+ },
+ {
+ html_id: 'scoped-in-all',
+ description: MSG_IN_ALL_GITLAB,
+ url: MOCK_ALL_PATH,
+ },
+];
+
+export const MOCK_SCOPED_SEARCH_OPTIONS_DEF = [
+ {
+ html_id: 'scoped-in-project',
+ scope: MOCK_PROJECT.name,
+ scopeCategory: PROJECTS_CATEGORY,
+ icon: ICON_PROJECT,
+ url: MOCK_PROJECT.path,
+ },
+ {
+ html_id: 'scoped-in-group',
+ scope: MOCK_GROUP.name,
+ scopeCategory: GROUPS_CATEGORY,
+ icon: ICON_GROUP,
+ url: MOCK_GROUP.path,
+ },
+ {
+ html_id: 'scoped-in-all',
+ description: MSG_IN_ALL_GITLAB,
+ url: MOCK_ALL_PATH,
+ },
+];
+
+export const MOCK_AUTOCOMPLETE_OPTIONS_RES = [
+ {
+ category: 'Projects',
+ id: 1,
+ label: 'Gitlab Org / MockProject1',
+ value: 'MockProject1',
+ url: 'project/1',
+ },
+ {
+ category: 'Groups',
+ id: 1,
+ label: 'Gitlab Org / MockGroup1',
+ value: 'MockGroup1',
+ url: 'group/1',
+ },
+ {
+ category: 'Projects',
+ id: 2,
+ label: 'Gitlab Org / MockProject2',
+ value: 'MockProject2',
+ url: 'project/2',
+ },
+ {
+ category: 'Help',
+ label: 'GitLab Help',
+ url: 'help/gitlab',
+ },
+];
+
+export const MOCK_AUTOCOMPLETE_OPTIONS = [
+ {
+ category: 'Projects',
+ html_id: 'autocomplete-Projects-0',
+ id: 1,
+ label: 'Gitlab Org / MockProject1',
+ value: 'MockProject1',
+ url: 'project/1',
+ },
+ {
+ category: 'Groups',
+ html_id: 'autocomplete-Groups-1',
+ id: 1,
+ label: 'Gitlab Org / MockGroup1',
+ value: 'MockGroup1',
+ url: 'group/1',
+ },
+ {
+ category: 'Projects',
+ html_id: 'autocomplete-Projects-2',
+ id: 2,
+ label: 'Gitlab Org / MockProject2',
+ value: 'MockProject2',
+ url: 'project/2',
+ },
+ {
+ category: 'Help',
+ html_id: 'autocomplete-Help-3',
+ label: 'GitLab Help',
+ url: 'help/gitlab',
+ },
+];
+
+export const MOCK_GROUPED_AUTOCOMPLETE_OPTIONS = [
+ {
+ category: 'Groups',
+ data: [
+ {
+ category: 'Groups',
+ html_id: 'autocomplete-Groups-1',
+
+ id: 1,
+ label: 'Gitlab Org / MockGroup1',
+ value: 'MockGroup1',
+ url: 'group/1',
+ },
+ ],
+ },
+ {
+ category: 'Projects',
+ data: [
+ {
+ category: 'Projects',
+ html_id: 'autocomplete-Projects-0',
+
+ id: 1,
+ label: 'Gitlab Org / MockProject1',
+ value: 'MockProject1',
+ url: 'project/1',
+ },
+ {
+ category: 'Projects',
+ html_id: 'autocomplete-Projects-2',
+
+ id: 2,
+ label: 'Gitlab Org / MockProject2',
+ value: 'MockProject2',
+ url: 'project/2',
+ },
+ ],
+ },
+ {
+ category: 'Help',
+ data: [
+ {
+ category: 'Help',
+ html_id: 'autocomplete-Help-3',
+
+ label: 'GitLab Help',
+ url: 'help/gitlab',
+ },
+ ],
+ },
+];
+
+export const MOCK_SORTED_AUTOCOMPLETE_OPTIONS = [
+ {
+ category: 'Groups',
+ html_id: 'autocomplete-Groups-1',
+ id: 1,
+ label: 'Gitlab Org / MockGroup1',
+ value: 'MockGroup1',
+ url: 'group/1',
+ },
+ {
+ category: 'Projects',
+ html_id: 'autocomplete-Projects-0',
+ id: 1,
+ label: 'Gitlab Org / MockProject1',
+ value: 'MockProject1',
+ url: 'project/1',
+ },
+ {
+ category: 'Projects',
+ html_id: 'autocomplete-Projects-2',
+ id: 2,
+ label: 'Gitlab Org / MockProject2',
+ value: 'MockProject2',
+ url: 'project/2',
+ },
+ {
+ category: 'Help',
+ html_id: 'autocomplete-Help-3',
+ label: 'GitLab Help',
+ url: 'help/gitlab',
+ },
+];
+
+export const MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_HELP = [
+ {
+ category: 'Help',
+ data: [
+ {
+ html_id: 'autocomplete-Help-1',
+ category: 'Help',
+ label: 'Rake Tasks Help',
+ url: '/help/raketasks/index',
+ },
+ {
+ html_id: 'autocomplete-Help-2',
+ category: 'Help',
+ label: 'System Hooks Help',
+ url: '/help/system_hooks/system_hooks',
+ },
+ ],
+ },
+];
+
+export const MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_SETTINGS_HELP = [
+ {
+ category: 'Settings',
+ data: [
+ {
+ html_id: 'autocomplete-Settings-0',
+ category: 'Settings',
+ label: 'User settings',
+ url: '/-/profile',
+ },
+ {
+ html_id: 'autocomplete-Settings-3',
+ category: 'Settings',
+ label: 'Admin Section',
+ url: '/admin',
+ },
+ ],
+ },
+ {
+ category: 'Help',
+ data: [
+ {
+ html_id: 'autocomplete-Help-1',
+ category: 'Help',
+ label: 'Rake Tasks Help',
+ url: '/help/raketasks/index',
+ },
+ {
+ html_id: 'autocomplete-Help-2',
+ category: 'Help',
+ label: 'System Hooks Help',
+ url: '/help/system_hooks/system_hooks',
+ },
+ ],
+ },
+];
+
+export const MOCK_GROUPED_AUTOCOMPLETE_OPTIONS_2 = [
+ {
+ category: 'Groups',
+ data: [
+ {
+ html_id: 'autocomplete-Groups-0',
+ category: 'Groups',
+ id: 148,
+ label: 'Jashkenas / Test Subgroup / test-subgroup',
+ url: '/jashkenas/test-subgroup/test-subgroup',
+ avatar_url: '',
+ },
+ {
+ html_id: 'autocomplete-Groups-1',
+ category: 'Groups',
+ id: 147,
+ label: 'Jashkenas / Test Subgroup',
+ url: '/jashkenas/test-subgroup',
+ avatar_url: '',
+ },
+ ],
+ },
+ {
+ category: 'Projects',
+ data: [
+ {
+ html_id: 'autocomplete-Projects-2',
+ category: 'Projects',
+ id: 1,
+ value: 'Gitlab Test',
+ label: 'Gitlab Org / Gitlab Test',
+ url: '/gitlab-org/gitlab-test',
+ avatar_url: '/uploads/-/system/project/avatar/1/icons8-gitlab-512.png',
+ },
+ ],
+ },
+];
diff --git a/spec/frontend/super_sidebar/components/global_search/store/actions_spec.js b/spec/frontend/super_sidebar/components/global_search/store/actions_spec.js
new file mode 100644
index 00000000000..c87b4513309
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/store/actions_spec.js
@@ -0,0 +1,113 @@
+import MockAdapter from 'axios-mock-adapter';
+import testAction from 'helpers/vuex_action_helper';
+import * as actions from '~/super_sidebar/components/global_search/store/actions';
+import * as types from '~/super_sidebar/components/global_search/store/mutation_types';
+import initState from '~/super_sidebar/components/global_search/store/state';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import {
+ MOCK_SEARCH,
+ MOCK_AUTOCOMPLETE_OPTIONS_RES,
+ MOCK_AUTOCOMPLETE_PATH,
+ MOCK_PROJECT,
+ MOCK_SEARCH_CONTEXT,
+ MOCK_SEARCH_PATH,
+ MOCK_MR_PATH,
+ MOCK_ISSUE_PATH,
+} from '../mock_data';
+
+jest.mock('~/alert');
+
+describe('Header Search Store Actions', () => {
+ let state;
+ let mock;
+
+ const createState = (initialState) =>
+ initState({
+ searchPath: MOCK_SEARCH_PATH,
+ issuesPath: MOCK_ISSUE_PATH,
+ mrPath: MOCK_MR_PATH,
+ autocompletePath: MOCK_AUTOCOMPLETE_PATH,
+ searchContext: MOCK_SEARCH_CONTEXT,
+ ...initialState,
+ });
+
+ afterEach(() => {
+ state = null;
+ mock.restore();
+ });
+
+ describe.each`
+ axiosMock | type | expectedMutations
+ ${{ method: 'onGet', code: HTTP_STATUS_OK, res: MOCK_AUTOCOMPLETE_OPTIONS_RES }} | ${'success'} | ${[{ type: types.REQUEST_AUTOCOMPLETE }, { type: types.RECEIVE_AUTOCOMPLETE_SUCCESS, payload: MOCK_AUTOCOMPLETE_OPTIONS_RES }, { type: types.RECEIVE_AUTOCOMPLETE_SUCCESS, payload: MOCK_AUTOCOMPLETE_OPTIONS_RES }]}
+ ${{ method: 'onGet', code: HTTP_STATUS_INTERNAL_SERVER_ERROR, res: null }} | ${'error'} | ${[{ type: types.REQUEST_AUTOCOMPLETE }, { type: types.RECEIVE_AUTOCOMPLETE_ERROR }, { type: types.RECEIVE_AUTOCOMPLETE_ERROR }]}
+ `('fetchAutocompleteOptions', ({ axiosMock, type, expectedMutations }) => {
+ describe(`on ${type}`, () => {
+ beforeEach(() => {
+ state = createState({});
+ mock = new MockAdapter(axios);
+ mock[axiosMock.method]().reply(axiosMock.code, axiosMock.res);
+ });
+ it(`should dispatch the correct mutations`, () => {
+ return testAction({
+ action: actions.fetchAutocompleteOptions,
+ state,
+ expectedMutations,
+ });
+ });
+ });
+ });
+
+ describe.each`
+ project | ref | fetchType | expectedPath
+ ${null} | ${null} | ${null} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}`}
+ ${MOCK_PROJECT} | ${null} | ${'generic'} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}&project_id=${MOCK_PROJECT.id}&filter=generic`}
+ ${null} | ${MOCK_PROJECT.id} | ${'generic'} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}&project_ref=${MOCK_PROJECT.id}&filter=generic`}
+ ${MOCK_PROJECT} | ${MOCK_PROJECT.id} | ${'search'} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}&project_id=${MOCK_PROJECT.id}&project_ref=${MOCK_PROJECT.id}&filter=search`}
+ `('autocompleteQuery', ({ project, ref, fetchType, expectedPath }) => {
+ describe(`when project is ${project?.name} and project ref is ${ref}`, () => {
+ beforeEach(() => {
+ state = createState({
+ search: MOCK_SEARCH,
+ searchContext: {
+ project,
+ ref,
+ },
+ });
+ });
+
+ it(`should return ${expectedPath}`, () => {
+ expect(actions.autocompleteQuery({ state, fetchType })).toBe(expectedPath);
+ });
+ });
+ });
+
+ describe('clearAutocomplete', () => {
+ beforeEach(() => {
+ state = createState({});
+ });
+
+ it('calls the CLEAR_AUTOCOMPLETE mutation', () => {
+ return testAction({
+ action: actions.clearAutocomplete,
+ state,
+ expectedMutations: [{ type: types.CLEAR_AUTOCOMPLETE }],
+ });
+ });
+ });
+
+ describe('setSearch', () => {
+ beforeEach(() => {
+ state = createState({});
+ });
+
+ it('calls the SET_SEARCH mutation', () => {
+ return testAction({
+ action: actions.setSearch,
+ payload: MOCK_SEARCH,
+ state,
+ expectedMutations: [{ type: types.SET_SEARCH, payload: MOCK_SEARCH }],
+ });
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js b/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js
new file mode 100644
index 00000000000..dca96da01a7
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js
@@ -0,0 +1,333 @@
+import * as getters from '~/super_sidebar/components/global_search/store/getters';
+import initState from '~/super_sidebar/components/global_search/store/state';
+import {
+ MOCK_USERNAME,
+ MOCK_SEARCH_PATH,
+ MOCK_ISSUE_PATH,
+ MOCK_MR_PATH,
+ MOCK_AUTOCOMPLETE_PATH,
+ MOCK_SEARCH_CONTEXT,
+ MOCK_DEFAULT_SEARCH_OPTIONS,
+ MOCK_SCOPED_SEARCH_OPTIONS,
+ MOCK_SCOPED_SEARCH_OPTIONS_DEF,
+ MOCK_PROJECT,
+ MOCK_GROUP,
+ MOCK_ALL_PATH,
+ MOCK_SEARCH,
+ MOCK_AUTOCOMPLETE_OPTIONS,
+ MOCK_GROUPED_AUTOCOMPLETE_OPTIONS,
+ MOCK_SORTED_AUTOCOMPLETE_OPTIONS,
+} from '../mock_data';
+
+describe('Header Search Store Getters', () => {
+ let state;
+
+ const createState = (initialState) => {
+ state = initState({
+ searchPath: MOCK_SEARCH_PATH,
+ issuesPath: MOCK_ISSUE_PATH,
+ mrPath: MOCK_MR_PATH,
+ autocompletePath: MOCK_AUTOCOMPLETE_PATH,
+ searchContext: MOCK_SEARCH_CONTEXT,
+ ...initialState,
+ });
+ };
+
+ afterEach(() => {
+ state = null;
+ });
+
+ describe.each`
+ group | project | scope | forSnippets | codeSearch | ref | expectedPath
+ ${null} | ${null} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${null} | ${null} | ${null} | ${true} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&snippets=true`}
+ ${null} | ${null} | ${null} | ${false} | ${true} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&search_code=true`}
+ ${null} | ${null} | ${null} | ${false} | ${false} | ${'test-branch'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&repository_ref=test-branch`}
+ ${MOCK_GROUP} | ${null} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}`}
+ ${null} | ${MOCK_PROJECT} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${true} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true&search_code=true`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${true} | ${'test-branch'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true&search_code=true&repository_ref=test-branch`}
+ `('searchQuery', ({ group, project, scope, forSnippets, codeSearch, ref, expectedPath }) => {
+ describe(`when group is ${group?.name}, project is ${project?.name}, scope is ${scope}, for_snippets is ${forSnippets}, code_search is ${codeSearch}, and ref is ${ref}`, () => {
+ beforeEach(() => {
+ createState({
+ searchContext: {
+ group,
+ project,
+ scope,
+ for_snippets: forSnippets,
+ code_search: codeSearch,
+ ref,
+ },
+ });
+ state.search = MOCK_SEARCH;
+ });
+
+ it(`should return ${expectedPath}`, () => {
+ expect(getters.searchQuery(state)).toBe(expectedPath);
+ });
+ });
+ });
+
+ describe.each`
+ group | group_metadata | project | project_metadata | expectedPath
+ ${null} | ${null} | ${null} | ${null} | ${MOCK_ISSUE_PATH}
+ ${{ name: 'Test Group' }} | ${{ issues_path: 'group/path' }} | ${null} | ${null} | ${'group/path'}
+ ${{ name: 'Test Group' }} | ${{ issues_path: 'group/path' }} | ${{ name: 'Test Project' }} | ${{ issues_path: 'project/path' }} | ${'project/path'}
+ `('scopedIssuesPath', ({ group, group_metadata, project, project_metadata, expectedPath }) => {
+ describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
+ beforeEach(() => {
+ createState({
+ searchContext: {
+ group,
+ group_metadata,
+ project,
+ project_metadata,
+ },
+ });
+ });
+
+ it(`should return ${expectedPath}`, () => {
+ expect(getters.scopedIssuesPath(state)).toBe(expectedPath);
+ });
+ });
+ });
+
+ describe.each`
+ group | group_metadata | project | project_metadata | expectedPath
+ ${null} | ${null} | ${null} | ${null} | ${MOCK_MR_PATH}
+ ${{ name: 'Test Group' }} | ${{ mr_path: 'group/path' }} | ${null} | ${null} | ${'group/path'}
+ ${{ name: 'Test Group' }} | ${{ mr_path: 'group/path' }} | ${{ name: 'Test Project' }} | ${{ mr_path: 'project/path' }} | ${'project/path'}
+ `('scopedMRPath', ({ group, group_metadata, project, project_metadata, expectedPath }) => {
+ describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
+ beforeEach(() => {
+ createState({
+ searchContext: {
+ group,
+ group_metadata,
+ project,
+ project_metadata,
+ },
+ });
+ });
+
+ it(`should return ${expectedPath}`, () => {
+ expect(getters.scopedMRPath(state)).toBe(expectedPath);
+ });
+ });
+ });
+
+ describe.each`
+ group | project | scope | forSnippets | codeSearch | ref | expectedPath
+ ${null} | ${null} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${null} | ${null} | ${null} | ${true} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&snippets=true`}
+ ${null} | ${null} | ${null} | ${false} | ${true} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&search_code=true`}
+ ${null} | ${null} | ${null} | ${false} | ${false} | ${'test-branch'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&repository_ref=test-branch`}
+ ${MOCK_GROUP} | ${null} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}`}
+ ${null} | ${MOCK_PROJECT} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${true} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true&search_code=true`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${true} | ${'test-branch'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true&search_code=true&repository_ref=test-branch`}
+ `('projectUrl', ({ group, project, scope, forSnippets, codeSearch, ref, expectedPath }) => {
+ describe(`when group is ${group?.name}, project is ${project?.name}, scope is ${scope}, for_snippets is ${forSnippets}, code_search is ${codeSearch}, and ref is ${ref}`, () => {
+ beforeEach(() => {
+ createState({
+ searchContext: {
+ group,
+ project,
+ scope,
+ for_snippets: forSnippets,
+ code_search: codeSearch,
+ ref,
+ },
+ });
+ state.search = MOCK_SEARCH;
+ });
+
+ it(`should return ${expectedPath}`, () => {
+ expect(getters.projectUrl(state)).toBe(expectedPath);
+ });
+ });
+ });
+
+ describe.each`
+ group | project | scope | forSnippets | codeSearch | ref | expectedPath
+ ${null} | ${null} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${null} | ${null} | ${null} | ${true} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&snippets=true`}
+ ${null} | ${null} | ${null} | ${false} | ${true} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&search_code=true`}
+ ${null} | ${null} | ${null} | ${false} | ${false} | ${'test-branch'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&repository_ref=test-branch`}
+ ${MOCK_GROUP} | ${null} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}`}
+ ${null} | ${MOCK_PROJECT} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}&scope=issues`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${true} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true&search_code=true`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${true} | ${'test-branch'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}&scope=issues&snippets=true&search_code=true&repository_ref=test-branch`}
+ `('groupUrl', ({ group, project, scope, forSnippets, codeSearch, ref, expectedPath }) => {
+ describe(`when group is ${group?.name}, project is ${project?.name}, scope is ${scope}, for_snippets is ${forSnippets}, code_search is ${codeSearch}, and ref is ${ref}`, () => {
+ beforeEach(() => {
+ createState({
+ searchContext: {
+ group,
+ project,
+ scope,
+ for_snippets: forSnippets,
+ code_search: codeSearch,
+ ref,
+ },
+ });
+ state.search = MOCK_SEARCH;
+ });
+
+ it(`should return ${expectedPath}`, () => {
+ expect(getters.groupUrl(state)).toBe(expectedPath);
+ });
+ });
+ });
+
+ describe.each`
+ group | project | scope | forSnippets | codeSearch | ref | expectedPath
+ ${null} | ${null} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${null} | ${null} | ${null} | ${true} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&snippets=true`}
+ ${null} | ${null} | ${null} | ${false} | ${true} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&search_code=true`}
+ ${null} | ${null} | ${null} | ${false} | ${false} | ${'test-branch'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&repository_ref=test-branch`}
+ ${MOCK_GROUP} | ${null} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${null} | ${MOCK_PROJECT} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${null} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${false} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&scope=issues`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${false} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&scope=issues&snippets=true`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${true} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&scope=issues&snippets=true&search_code=true`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${true} | ${true} | ${'test-branch'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&scope=issues&snippets=true&search_code=true&repository_ref=test-branch`}
+ `('allUrl', ({ group, project, scope, forSnippets, codeSearch, ref, expectedPath }) => {
+ describe(`when group is ${group?.name}, project is ${project?.name}, scope is ${scope}, for_snippets is ${forSnippets}, code_search is ${codeSearch}, and ref is ${ref}`, () => {
+ beforeEach(() => {
+ createState({
+ searchContext: {
+ group,
+ project,
+ scope,
+ for_snippets: forSnippets,
+ code_search: codeSearch,
+ ref,
+ },
+ });
+ state.search = MOCK_SEARCH;
+ });
+
+ it(`should return ${expectedPath}`, () => {
+ expect(getters.allUrl(state)).toBe(expectedPath);
+ });
+ });
+ });
+
+ describe('defaultSearchOptions', () => {
+ const mockGetters = {
+ scopedIssuesPath: MOCK_ISSUE_PATH,
+ scopedMRPath: MOCK_MR_PATH,
+ };
+
+ beforeEach(() => {
+ createState();
+ window.gon.current_username = MOCK_USERNAME;
+ });
+
+ it('returns the correct array', () => {
+ expect(getters.defaultSearchOptions(state, mockGetters)).toStrictEqual(
+ MOCK_DEFAULT_SEARCH_OPTIONS,
+ );
+ });
+
+ it('returns the correct array if issues path is false', () => {
+ mockGetters.scopedIssuesPath = undefined;
+ expect(getters.defaultSearchOptions(state, mockGetters)).toStrictEqual(
+ MOCK_DEFAULT_SEARCH_OPTIONS.slice(2, MOCK_DEFAULT_SEARCH_OPTIONS.length),
+ );
+ });
+ });
+
+ describe('scopedSearchOptions', () => {
+ const mockGetters = {
+ projectUrl: MOCK_PROJECT.path,
+ groupUrl: MOCK_GROUP.path,
+ allUrl: MOCK_ALL_PATH,
+ };
+
+ beforeEach(() => {
+ createState({
+ searchContext: {
+ project: MOCK_PROJECT,
+ group: MOCK_GROUP,
+ },
+ });
+ });
+
+ it('returns the correct array', () => {
+ expect(getters.scopedSearchOptions(state, mockGetters)).toStrictEqual(
+ MOCK_SCOPED_SEARCH_OPTIONS_DEF,
+ );
+ });
+ });
+
+ describe('autocompleteGroupedSearchOptions', () => {
+ beforeEach(() => {
+ createState();
+ state.autocompleteOptions = MOCK_AUTOCOMPLETE_OPTIONS;
+ });
+
+ it('returns the correct grouped array', () => {
+ expect(getters.autocompleteGroupedSearchOptions(state)).toStrictEqual(
+ MOCK_GROUPED_AUTOCOMPLETE_OPTIONS,
+ );
+ });
+ });
+
+ describe.each`
+ search | defaultSearchOptions | scopedSearchOptions | autocompleteGroupedSearchOptions | expectedArray
+ ${null} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS} | ${MOCK_DEFAULT_SEARCH_OPTIONS}
+ ${MOCK_SEARCH} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${[]} | ${MOCK_SCOPED_SEARCH_OPTIONS}
+ ${MOCK_SEARCH} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${[]} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS} | ${MOCK_SORTED_AUTOCOMPLETE_OPTIONS}
+ ${MOCK_SEARCH} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS} | ${MOCK_SCOPED_SEARCH_OPTIONS.concat(MOCK_SORTED_AUTOCOMPLETE_OPTIONS)}
+ ${1} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${[]} | ${[]} | ${[]}
+ ${'('} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${[]} | ${[]} | ${[]}
+ ${'t'} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS} | ${MOCK_SORTED_AUTOCOMPLETE_OPTIONS}
+ ${'te'} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS} | ${MOCK_SORTED_AUTOCOMPLETE_OPTIONS}
+ ${'tes'} | ${MOCK_DEFAULT_SEARCH_OPTIONS} | ${MOCK_SCOPED_SEARCH_OPTIONS} | ${MOCK_GROUPED_AUTOCOMPLETE_OPTIONS} | ${MOCK_SCOPED_SEARCH_OPTIONS.concat(MOCK_SORTED_AUTOCOMPLETE_OPTIONS)}
+ `(
+ 'searchOptions',
+ ({
+ search,
+ defaultSearchOptions,
+ scopedSearchOptions,
+ autocompleteGroupedSearchOptions,
+ expectedArray,
+ }) => {
+ describe(`when search is ${search} and the defaultSearchOptions${
+ defaultSearchOptions.length ? '' : ' do not'
+ } exist, scopedSearchOptions${
+ scopedSearchOptions.length ? '' : ' do not'
+ } exist, and autocompleteGroupedSearchOptions${
+ autocompleteGroupedSearchOptions.length ? '' : ' do not'
+ } exist`, () => {
+ const mockGetters = {
+ defaultSearchOptions,
+ scopedSearchOptions,
+ autocompleteGroupedSearchOptions,
+ };
+
+ beforeEach(() => {
+ createState();
+ state.search = search;
+ });
+
+ it(`should return the correct combined array`, () => {
+ expect(getters.searchOptions(state, mockGetters)).toStrictEqual(expectedArray);
+ });
+ });
+ },
+ );
+});
diff --git a/spec/frontend/super_sidebar/components/global_search/store/mutations_spec.js b/spec/frontend/super_sidebar/components/global_search/store/mutations_spec.js
new file mode 100644
index 00000000000..d2dc484e825
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/global_search/store/mutations_spec.js
@@ -0,0 +1,63 @@
+import * as types from '~/super_sidebar/components/global_search/store/mutation_types';
+import mutations from '~/super_sidebar/components/global_search/store/mutations';
+import createState from '~/super_sidebar/components/global_search/store/state';
+import {
+ MOCK_SEARCH,
+ MOCK_AUTOCOMPLETE_OPTIONS_RES,
+ MOCK_AUTOCOMPLETE_OPTIONS,
+} from '../mock_data';
+
+describe('Header Search Store Mutations', () => {
+ let state;
+
+ beforeEach(() => {
+ state = createState({});
+ });
+
+ describe('REQUEST_AUTOCOMPLETE', () => {
+ it('sets loading to true and empties autocompleteOptions array', () => {
+ mutations[types.REQUEST_AUTOCOMPLETE](state);
+
+ expect(state.loading).toBe(true);
+ expect(state.autocompleteOptions).toStrictEqual([]);
+ expect(state.autocompleteError).toBe(false);
+ });
+ });
+
+ describe('RECEIVE_AUTOCOMPLETE_SUCCESS', () => {
+ it('sets loading to false and then formats and sets the autocompleteOptions array', () => {
+ mutations[types.RECEIVE_AUTOCOMPLETE_SUCCESS](state, MOCK_AUTOCOMPLETE_OPTIONS_RES);
+
+ expect(state.loading).toBe(false);
+ expect(state.autocompleteOptions).toStrictEqual(MOCK_AUTOCOMPLETE_OPTIONS);
+ expect(state.autocompleteError).toBe(false);
+ });
+ });
+
+ describe('RECEIVE_AUTOCOMPLETE_ERROR', () => {
+ it('sets loading to false and empties autocompleteOptions array', () => {
+ mutations[types.RECEIVE_AUTOCOMPLETE_ERROR](state);
+
+ expect(state.loading).toBe(false);
+ expect(state.autocompleteOptions).toStrictEqual([]);
+ expect(state.autocompleteError).toBe(true);
+ });
+ });
+
+ describe('CLEAR_AUTOCOMPLETE', () => {
+ it('empties autocompleteOptions array', () => {
+ mutations[types.CLEAR_AUTOCOMPLETE](state);
+
+ expect(state.autocompleteOptions).toStrictEqual([]);
+ expect(state.autocompleteError).toBe(false);
+ });
+ });
+
+ describe('SET_SEARCH', () => {
+ it('sets search to value', () => {
+ mutations[types.SET_SEARCH](state, MOCK_SEARCH);
+
+ expect(state.search).toBe(MOCK_SEARCH);
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/groups_list_spec.js b/spec/frontend/super_sidebar/components/groups_list_spec.js
new file mode 100644
index 00000000000..6aee895f611
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/groups_list_spec.js
@@ -0,0 +1,87 @@
+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', () => {
+ expect(findViewAllLink().props('item')).toEqual({
+ icon: 'group',
+ link: viewAllLink,
+ title: s__('Navigation|View all groups'),
+ });
+ });
+ };
+
+ 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|Frequent 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/help_center_spec.js b/spec/frontend/super_sidebar/components/help_center_spec.js
index bc847a3e159..1d072c0ba3c 100644
--- a/spec/frontend/super_sidebar/components/help_center_spec.js
+++ b/spec/frontend/super_sidebar/components/help_center_spec.js
@@ -68,18 +68,23 @@ describe('HelpCenter component', () => {
});
describe('showKeyboardShortcuts', () => {
+ let button;
+
beforeEach(() => {
jest.spyOn(wrapper.vm.$refs.dropdown, 'close');
- window.toggleShortcutsHelp = jest.fn();
- findButton('Keyboard shortcuts ?').click();
+
+ button = findButton('Keyboard shortcuts ?');
});
it('closes the dropdown', () => {
+ button.click();
expect(wrapper.vm.$refs.dropdown.close).toHaveBeenCalled();
});
it('shows the keyboard shortcuts modal', () => {
- expect(window.toggleShortcutsHelp).toHaveBeenCalled();
+ // This relies on the event delegation set up by the Shortcuts class in
+ // ~/behaviors/shortcuts/shortcuts.js.
+ expect(button.classList.contains('js-shortcuts-modal-trigger')).toBe(true);
});
});
diff --git a/spec/frontend/super_sidebar/components/items_list_spec.js b/spec/frontend/super_sidebar/components/items_list_spec.js
new file mode 100644
index 00000000000..8e00984f500
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/items_list_spec.js
@@ -0,0 +1,63 @@
+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/nav_item_spec.js b/spec/frontend/super_sidebar/components/nav_item_spec.js
new file mode 100644
index 00000000000..22989c1a5f9
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/nav_item_spec.js
@@ -0,0 +1,49 @@
+import { GlBadge } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import NavItem from '~/super_sidebar/components/nav_item.vue';
+
+describe('NavItem component', () => {
+ let wrapper;
+
+ const findLink = () => wrapper.findByTestId('nav-item-link');
+ const findPill = () => wrapper.findComponent(GlBadge);
+ const createWrapper = (item, props = {}) => {
+ wrapper = shallowMountExtended(NavItem, {
+ propsData: {
+ item,
+ ...props,
+ },
+ });
+ };
+
+ describe('pills', () => {
+ it.each([0, 5, 3.4, 'foo', '10%'])('item with pill_data `%p` renders a pill', (pillCount) => {
+ createWrapper({ title: 'Foo', pill_count: pillCount });
+
+ expect(findPill().text()).toEqual(pillCount.toString());
+ });
+
+ it.each([null, undefined, false, true, '', NaN, Number.POSITIVE_INFINITY])(
+ 'item with pill_data `%p` renders no pill',
+ (pillCount) => {
+ createWrapper({ title: 'Foo', pill_count: pillCount });
+
+ expect(findPill().exists()).toEqual(false);
+ },
+ );
+ });
+
+ it('applies custom link classes', () => {
+ const customClass = 'customClass';
+ createWrapper(
+ { title: 'Foo' },
+ {
+ linkClasses: {
+ [customClass]: true,
+ },
+ },
+ );
+
+ expect(findLink().attributes('class')).toContain(customClass);
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/projects_list_spec.js b/spec/frontend/super_sidebar/components/projects_list_spec.js
new file mode 100644
index 00000000000..cdc003b14e0
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/projects_list_spec.js
@@ -0,0 +1,82 @@
+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', () => {
+ expect(findViewAllLink().props('item')).toEqual({
+ icon: 'project',
+ link: viewAllLink,
+ title: s__('Navigation|View all projects'),
+ });
+ });
+ };
+
+ 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|Frequent 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
new file mode 100644
index 00000000000..dd48935c138
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/search_results_spec.js
@@ -0,0 +1,57 @@
+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';
+
+const title = s__('Navigation|PROJECTS');
+const noResultsText = s__('Navigation|No project matches found');
+
+describe('SearchResults component', () => {
+ let wrapper;
+
+ const findListTitle = () => wrapper.findByTestId('list-title');
+ const findItemsList = () => wrapper.findComponent(ItemsList);
+ const findEmptyText = () => wrapper.findByTestId('empty-text');
+
+ const createWrapper = ({ props = {} } = {}) => {
+ wrapper = shallowMountExtended(SearchResults, {
+ propsData: {
+ title,
+ noResultsText,
+ ...props,
+ },
+ });
+ };
+
+ describe('default state', () => {
+ 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(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_portal_spec.js b/spec/frontend/super_sidebar/components/sidebar_portal_spec.js
new file mode 100644
index 00000000000..3ef1cb7e692
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/sidebar_portal_spec.js
@@ -0,0 +1,68 @@
+import { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
+import SidebarPortal from '~/super_sidebar/components/sidebar_portal.vue';
+import SidebarPortalTarget from '~/super_sidebar/components/sidebar_portal_target.vue';
+
+describe('SidebarPortal', () => {
+ let targetWrapper;
+
+ const Target = {
+ components: { SidebarPortalTarget },
+ props: ['show'],
+ template: '<sidebar-portal-target v-if="show" />',
+ };
+
+ const Source = {
+ components: { SidebarPortal },
+ template: '<sidebar-portal><br data-testid="test"></sidebar-portal>',
+ };
+
+ const mountSource = () => {
+ mount(Source);
+ };
+
+ const mountTarget = ({ show = true } = {}) => {
+ targetWrapper = mount(Target, {
+ propsData: { show },
+ attachTo: document.body,
+ });
+ };
+
+ const findTestContent = () => targetWrapper.find('[data-testid="test"]');
+
+ it('renders content into the target', async () => {
+ mountTarget();
+ await nextTick();
+
+ mountSource();
+ await nextTick();
+
+ expect(findTestContent().exists()).toBe(true);
+ });
+
+ it('waits for target to be available before rendering', async () => {
+ mountSource();
+ await nextTick();
+
+ mountTarget();
+ await nextTick();
+
+ expect(findTestContent().exists()).toBe(true);
+ });
+
+ it('supports conditional rendering of target', async () => {
+ mountTarget({ show: false });
+ await nextTick();
+
+ mountSource();
+ await nextTick();
+
+ expect(findTestContent().exists()).toBe(false);
+
+ await targetWrapper.setProps({ show: true });
+ expect(findTestContent().exists()).toBe(true);
+
+ await targetWrapper.setProps({ show: false });
+ expect(findTestContent().exists()).toBe(false);
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/super_sidebar_spec.js b/spec/frontend/super_sidebar/components/super_sidebar_spec.js
index 45fc30c08f0..32921da23aa 100644
--- a/spec/frontend/super_sidebar/components/super_sidebar_spec.js
+++ b/spec/frontend/super_sidebar/components/super_sidebar_spec.js
@@ -2,13 +2,21 @@ 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 SidebarPortalTarget from '~/super_sidebar/components/sidebar_portal_target.vue';
+import { isCollapsed } from '~/super_sidebar/super_sidebar_collapsed_state_manager';
import { sidebarData } from '../mock_data';
+jest.mock('~/super_sidebar/super_sidebar_collapsed_state_manager', () => ({
+ isCollapsed: jest.fn(),
+}));
+
describe('SuperSidebar component', () => {
let wrapper;
+ const findSidebar = () => wrapper.find('.super-sidebar');
const findUserBar = () => wrapper.findComponent(UserBar);
const findHelpCenter = () => wrapper.findComponent(HelpCenter);
+ const findSidebarPortalTarget = () => wrapper.findComponent(SidebarPortalTarget);
const createWrapper = (props = {}) => {
wrapper = shallowMountExtended(SuperSidebar, {
@@ -20,16 +28,33 @@ describe('SuperSidebar component', () => {
};
describe('default', () => {
- beforeEach(() => {
+ it('add aria-hidden and inert attributes when collapsed', () => {
+ isCollapsed.mockReturnValue(true);
createWrapper();
+ expect(findSidebar().attributes('aria-hidden')).toBe('true');
+ expect(findSidebar().attributes('inert')).toBe('inert');
+ });
+
+ it('does not add aria-hidden and inert attributes when expanded', () => {
+ isCollapsed.mockReturnValue(false);
+ createWrapper();
+ expect(findSidebar().attributes('aria-hidden')).toBe('false');
+ expect(findSidebar().attributes('inert')).toBe(undefined);
});
it('renders UserBar with sidebarData', () => {
+ createWrapper();
expect(findUserBar().props('sidebarData')).toBe(sidebarData);
});
it('renders HelpCenter with sidebarData', () => {
+ createWrapper();
expect(findHelpCenter().props('sidebarData')).toBe(sidebarData);
});
+
+ it('renders SidebarPortalTarget', () => {
+ createWrapper();
+ expect(findSidebarPortalTarget().exists()).toBe(true);
+ });
});
});
diff --git a/spec/frontend/super_sidebar/components/user_bar_spec.js b/spec/frontend/super_sidebar/components/user_bar_spec.js
index eceb792c3db..ae15dd55644 100644
--- a/spec/frontend/super_sidebar/components/user_bar_spec.js
+++ b/spec/frontend/super_sidebar/components/user_bar_spec.js
@@ -1,3 +1,4 @@
+import { GlBadge } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { __ } from '~/locale';
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
@@ -12,12 +13,12 @@ describe('UserBar component', () => {
const findCreateMenu = () => wrapper.findComponent(CreateMenu);
const findCounter = (at) => wrapper.findAllComponents(Counter).at(at);
const findMergeRequestMenu = () => wrapper.findComponent(MergeRequestMenu);
+ const findBrandLogo = () => wrapper.findByTestId('brand-header-custom-logo');
- const createWrapper = (props = {}) => {
+ const createWrapper = (extraSidebarData = {}) => {
wrapper = shallowMountExtended(UserBar, {
propsData: {
- sidebarData,
- ...props,
+ sidebarData: { ...sidebarData, ...extraSidebarData },
},
provide: {
rootPath: '/',
@@ -55,5 +56,29 @@ describe('UserBar component', () => {
expect(findCounter(2).props('href')).toBe('/dashboard/todos');
expect(findCounter(2).props('label')).toBe(__('To-Do list'));
});
+
+ it('renders branding logo', () => {
+ expect(findBrandLogo().exists()).toBe(true);
+ expect(findBrandLogo().attributes('src')).toBe(sidebarData.logo_url);
+ });
+ });
+
+ describe('GitLab Next badge', () => {
+ describe('when on canary', () => {
+ it('should render a badge to switch off GitLab Next', () => {
+ createWrapper({ gitlab_com_and_canary: true });
+ const badge = wrapper.findComponent(GlBadge);
+ expect(badge.text()).toBe('Next');
+ expect(badge.attributes('href')).toBe(sidebarData.canary_toggle_com_url);
+ });
+ });
+
+ describe('when not on canary', () => {
+ it('should not render the GitLab Next badge', () => {
+ createWrapper({ gitlab_com_and_canary: false });
+ const badge = wrapper.findComponent(GlBadge);
+ expect(badge.exists()).toBe(false);
+ });
+ });
});
});
diff --git a/spec/frontend/super_sidebar/components/user_menu_spec.js b/spec/frontend/super_sidebar/components/user_menu_spec.js
new file mode 100644
index 00000000000..b6231e03722
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/user_menu_spec.js
@@ -0,0 +1,375 @@
+import { GlAvatar, GlDisclosureDropdown } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import UserMenu from '~/super_sidebar/components/user_menu.vue';
+import UserNameGroup from '~/super_sidebar/components/user_name_group.vue';
+import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
+import invalidUrl from '~/lib/utils/invalid_url';
+import { mockTracking } from 'helpers/tracking_helper';
+import PersistentUserCallout from '~/persistent_user_callout';
+import { userMenuMockData, userMenuMockStatus, userMenuMockPipelineMinutes } from '../mock_data';
+
+describe('UserMenu component', () => {
+ let wrapper;
+ let trackingSpy;
+
+ const GlEmoji = { template: '<img/>' };
+ const toggleNewNavEndpoint = invalidUrl;
+ const showDropdown = () => wrapper.findComponent(GlDisclosureDropdown).vm.$emit('shown');
+
+ const createWrapper = (userDataChanges = {}) => {
+ wrapper = mountExtended(UserMenu, {
+ propsData: {
+ data: {
+ ...userMenuMockData,
+ ...userDataChanges,
+ },
+ },
+ stubs: {
+ GlEmoji,
+ GlAvatar: true,
+ },
+ provide: {
+ toggleNewNavEndpoint,
+ },
+ });
+
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ };
+
+ describe('Toggle button', () => {
+ let toggle;
+
+ beforeEach(() => {
+ createWrapper();
+ toggle = wrapper.findByTestId('base-dropdown-toggle');
+ });
+
+ it('renders User Avatar in a toggle', () => {
+ const avatar = toggle.findComponent(GlAvatar);
+ expect(avatar.exists()).toBe(true);
+ expect(avatar.props()).toMatchObject({
+ entityName: userMenuMockData.name,
+ src: userMenuMockData.avatar_url,
+ });
+ });
+
+ it('renders screen reader text', () => {
+ expect(toggle.find('.gl-sr-only').text()).toBe(`${userMenuMockData.name} user’s menu`);
+ });
+ });
+
+ describe('User Menu Group', () => {
+ it('renders and passes data to it', () => {
+ createWrapper();
+ const userNameGroup = wrapper.findComponent(UserNameGroup);
+ expect(userNameGroup.exists()).toBe(true);
+ expect(userNameGroup.props('user')).toEqual(userMenuMockData);
+ });
+ });
+
+ describe('User status item', () => {
+ let item;
+
+ const setItem = ({ can_update, busy, customized } = {}) => {
+ createWrapper({ status: { ...userMenuMockStatus, can_update, busy, customized } });
+ item = wrapper.findByTestId('status-item');
+ };
+
+ describe('When user cannot update the status', () => {
+ it('does not render the status menu item', () => {
+ setItem();
+ expect(item.exists()).toBe(false);
+ });
+ });
+
+ describe('When user can update the status', () => {
+ it('renders the status menu item', () => {
+ setItem({ can_update: true });
+ expect(item.exists()).toBe(true);
+ });
+
+ it('should set the CSS class for triggering status update modal', () => {
+ setItem({ can_update: true });
+ expect(item.find('.js-set-status-modal-trigger').exists()).toBe(true);
+ });
+
+ describe('renders correct label', () => {
+ it.each`
+ busy | customized | label
+ ${false} | ${false} | ${'Set status'}
+ ${false} | ${true} | ${'Edit status'}
+ ${true} | ${false} | ${'Edit status'}
+ ${true} | ${true} | ${'Edit status'}
+ `(
+ 'when busy is "$busy" and customized is "$customized" the label is "$label"',
+ ({ busy, customized, label }) => {
+ setItem({ can_update: true, busy, customized });
+ expect(item.text()).toBe(label);
+ },
+ );
+ });
+
+ describe('Status update modal wrapper', () => {
+ const findModalWrapper = () => wrapper.find('.js-set-status-modal-wrapper');
+
+ it('renders the modal wrapper', () => {
+ setItem({ can_update: true });
+ expect(findModalWrapper().exists()).toBe(true);
+ });
+
+ it('sets default data attributes when status is not customized', () => {
+ setItem({ can_update: true });
+ expect(findModalWrapper().attributes()).toMatchObject({
+ 'data-current-emoji': '',
+ 'data-current-message': '',
+ 'data-default-emoji': 'speech_balloon',
+ });
+ });
+
+ it('sets user status as data attributes when status is customized', () => {
+ setItem({ can_update: true, customized: true });
+ expect(findModalWrapper().attributes()).toMatchObject({
+ 'data-current-emoji': userMenuMockStatus.emoji,
+ 'data-current-message': userMenuMockStatus.message,
+ 'data-current-availability': userMenuMockStatus.availability,
+ 'data-current-clear-status-after': userMenuMockStatus.clear_after,
+ });
+ });
+ });
+ });
+ });
+
+ describe('Start Ultimate trial item', () => {
+ let item;
+
+ const setItem = ({ has_start_trial } = {}) => {
+ createWrapper({ trial: { has_start_trial } });
+ item = wrapper.findByTestId('start-trial-item');
+ };
+
+ describe('When Ultimate trial is not suggested for the user', () => {
+ it('does not render the start trial menu item', () => {
+ setItem();
+ expect(item.exists()).toBe(false);
+ });
+ });
+
+ describe('When Ultimate trial can be suggested for the user', () => {
+ it('does render the start trial menu item', () => {
+ setItem({ has_start_trial: true });
+ expect(item.exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('Buy Pipeline Minutes item', () => {
+ let item;
+
+ const setItem = ({
+ show_buy_pipeline_minutes,
+ show_with_subtext,
+ show_notification_dot,
+ } = {}) => {
+ createWrapper({
+ pipeline_minutes: {
+ ...userMenuMockPipelineMinutes,
+ show_buy_pipeline_minutes,
+ show_with_subtext,
+ show_notification_dot,
+ },
+ });
+ item = wrapper.findByTestId('buy-pipeline-minutes-item');
+ };
+
+ describe('When does NOT meet the condition to buy CI minutes', () => {
+ beforeEach(() => {
+ setItem();
+ });
+
+ it('does NOT render the buy pipeline minutes item', () => {
+ expect(item.exists()).toBe(false);
+ });
+
+ it('does not track the Sentry event', () => {
+ showDropdown();
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('When does meet the condition to buy CI minutes', () => {
+ it('does render the menu item', () => {
+ setItem({ show_buy_pipeline_minutes: true });
+ expect(item.exists()).toBe(true);
+ });
+
+ it('tracks the Sentry event', () => {
+ setItem({ show_buy_pipeline_minutes: true });
+ showDropdown();
+ expect(trackingSpy).toHaveBeenCalledWith(
+ undefined,
+ userMenuMockPipelineMinutes.tracking_attrs['track-action'],
+ {
+ label: userMenuMockPipelineMinutes.tracking_attrs['track-label'],
+ property: userMenuMockPipelineMinutes.tracking_attrs['track-property'],
+ },
+ );
+ });
+
+ describe('Callout & notification dot', () => {
+ let spyFactory;
+
+ beforeEach(() => {
+ spyFactory = jest.spyOn(PersistentUserCallout, 'factory');
+ });
+
+ describe('When `show_notification_dot` is `false`', () => {
+ beforeEach(() => {
+ setItem({ show_buy_pipeline_minutes: true, show_notification_dot: false });
+ showDropdown();
+ });
+
+ it('does not set callout attributes', () => {
+ expect(item.attributes()).not.toEqual(
+ expect.objectContaining({
+ 'data-feature-id': userMenuMockPipelineMinutes.callout_attrs.feature_id,
+ 'data-dismiss-endpoint': userMenuMockPipelineMinutes.callout_attrs.dismiss_endpoint,
+ }),
+ );
+ });
+
+ it('does not initialize the Persistent Callout', () => {
+ expect(spyFactory).not.toHaveBeenCalled();
+ });
+
+ it('does not render notification dot', () => {
+ expect(wrapper.findByTestId('buy-pipeline-minutes-notification-dot').exists()).toBe(
+ false,
+ );
+ });
+ });
+
+ describe('When `show_notification_dot` is `true`', () => {
+ beforeEach(() => {
+ setItem({ show_buy_pipeline_minutes: true, show_notification_dot: true });
+ showDropdown();
+ });
+
+ it('sets the callout data attributes', () => {
+ expect(item.attributes()).toEqual(
+ expect.objectContaining({
+ 'data-feature-id': userMenuMockPipelineMinutes.callout_attrs.feature_id,
+ 'data-dismiss-endpoint': userMenuMockPipelineMinutes.callout_attrs.dismiss_endpoint,
+ }),
+ );
+ });
+
+ it('initializes the Persistent Callout', () => {
+ expect(spyFactory).toHaveBeenCalled();
+ });
+
+ it('renders notification dot', () => {
+ expect(wrapper.findByTestId('buy-pipeline-minutes-notification-dot').exists()).toBe(
+ true,
+ );
+ });
+ });
+ });
+
+ describe('Warning message', () => {
+ it('does not display the warning message when `show_with_subtext` is `false`', () => {
+ setItem({ show_buy_pipeline_minutes: true });
+
+ expect(item.text()).not.toContain(UserMenu.i18n.oneOfGroupsRunningOutOfPipelineMinutes);
+ });
+
+ it('displays the text and warning message when `show_with_subtext` is true', () => {
+ setItem({ show_buy_pipeline_minutes: true, show_with_subtext: true });
+
+ expect(item.text()).toContain(UserMenu.i18n.oneOfGroupsRunningOutOfPipelineMinutes);
+ });
+ });
+ });
+ });
+
+ describe('Edit profile item', () => {
+ it('should render a link to the profile page', () => {
+ createWrapper();
+ const item = wrapper.findByTestId('edit-profile-item');
+ expect(item.text()).toBe(UserMenu.i18n.editProfile);
+ expect(item.find('a').attributes('href')).toBe(userMenuMockData.settings.profile_path);
+ });
+ });
+
+ describe('Preferences item', () => {
+ it('should render a link to the profile page', () => {
+ createWrapper();
+ const item = wrapper.findByTestId('preferences-item');
+ expect(item.text()).toBe(UserMenu.i18n.preferences);
+ expect(item.find('a').attributes('href')).toBe(
+ userMenuMockData.settings.profile_preferences_path,
+ );
+ });
+ });
+
+ describe('GitLab Next item', () => {
+ describe('on gitlab.com', () => {
+ it('should render a link to switch to GitLab Next', () => {
+ createWrapper({ gitlab_com_but_not_canary: true });
+ const item = wrapper.findByTestId('gitlab-next-item');
+ expect(item.text()).toBe(UserMenu.i18n.gitlabNext);
+ expect(item.find('a').attributes('href')).toBe(userMenuMockData.canary_toggle_com_url);
+ });
+ });
+
+ describe('anywhere else', () => {
+ it('should not render the GitLab Next link', () => {
+ createWrapper({ gitlab_com_but_not_canary: false });
+ const item = wrapper.findByTestId('gitlab-next-item');
+ expect(item.exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('New navigation toggle item', () => {
+ it('should render menu item with new navigation toggle', () => {
+ createWrapper();
+ const toggleItem = wrapper.findComponent(NewNavToggle);
+ expect(toggleItem.exists()).toBe(true);
+ expect(toggleItem.props('endpoint')).toBe(toggleNewNavEndpoint);
+ });
+ });
+
+ describe('Feedback item', () => {
+ it('should render feedback item with a link to a new GitLab issue', () => {
+ createWrapper();
+ const feedbackItem = wrapper.findByTestId('feedback-item');
+ expect(feedbackItem.find('a').attributes('href')).toBe(UserMenu.feedbackUrl);
+ });
+ });
+
+ describe('Sign out group', () => {
+ const findSignOutGroup = () => wrapper.findByTestId('sign-out-group');
+
+ it('should not render sign out group when user cannot sign out', () => {
+ createWrapper();
+ expect(findSignOutGroup().exists()).toBe(false);
+ });
+
+ describe('when user can sign out', () => {
+ beforeEach(() => {
+ createWrapper({ can_sign_out: true });
+ });
+
+ it('should render sign out group', () => {
+ expect(findSignOutGroup().exists()).toBe(true);
+ });
+
+ it('should render the menu item with a link to sign out and correct data attribute', () => {
+ expect(findSignOutGroup().find('a').attributes('href')).toBe(
+ userMenuMockData.sign_out_link,
+ );
+ expect(findSignOutGroup().find('a').attributes('data-method')).toBe('post');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/user_name_group_spec.js b/spec/frontend/super_sidebar/components/user_name_group_spec.js
new file mode 100644
index 00000000000..c06c8c218d4
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/user_name_group_spec.js
@@ -0,0 +1,100 @@
+import { GlDisclosureDropdownGroup, GlDisclosureDropdownItem, GlTooltip } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import UserNameGroup from '~/super_sidebar/components/user_name_group.vue';
+import { userMenuMockData, userMenuMockStatus } from '../mock_data';
+
+describe('UserNameGroup component', () => {
+ let wrapper;
+
+ const findGlDisclosureDropdownGroup = () => wrapper.findComponent(GlDisclosureDropdownGroup);
+ const findGlDisclosureDropdownItem = () => wrapper.findComponent(GlDisclosureDropdownItem);
+ const findGlTooltip = () => wrapper.findComponent(GlTooltip);
+ const findUserStatus = () => wrapper.findByTestId('user-menu-status');
+
+ const GlEmoji = { template: '<img/>' };
+
+ const createWrapper = (userDataChanges = {}) => {
+ wrapper = shallowMountExtended(UserNameGroup, {
+ propsData: {
+ user: {
+ ...userMenuMockData,
+ ...userDataChanges,
+ },
+ },
+ stubs: {
+ GlEmoji,
+ GlDisclosureDropdownItem,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('renders the menu item in a separate group', () => {
+ expect(findGlDisclosureDropdownGroup().exists()).toBe(true);
+ });
+
+ it('renders menu item', () => {
+ expect(findGlDisclosureDropdownItem().exists()).toBe(true);
+ });
+
+ it('passes the item to the disclosure dropdown item', () => {
+ expect(findGlDisclosureDropdownItem().props('item')).toEqual({
+ text: userMenuMockData.name,
+ href: userMenuMockData.link_to_profile,
+ });
+ });
+
+ it("renders user's name", () => {
+ expect(findGlDisclosureDropdownItem().text()).toContain(userMenuMockData.name);
+ });
+
+ it("renders user's username", () => {
+ expect(findGlDisclosureDropdownItem().text()).toContain(userMenuMockData.username);
+ });
+
+ describe('Busy status', () => {
+ it('should not render "Busy" when user is NOT busy', () => {
+ expect(findGlDisclosureDropdownItem().text()).not.toContain('Busy');
+ });
+ it('should render "Busy" when user is busy', () => {
+ createWrapper({ status: { customized: true, busy: true } });
+
+ expect(findGlDisclosureDropdownItem().text()).toContain('Busy');
+ });
+ });
+
+ describe('User status', () => {
+ describe('when not customized', () => {
+ it('should not render it', () => {
+ expect(findUserStatus().exists()).toBe(false);
+ });
+ });
+
+ describe('when customized', () => {
+ beforeEach(() => {
+ createWrapper({ status: { ...userMenuMockStatus, customized: true } });
+ });
+
+ it('should render it', () => {
+ expect(findUserStatus().exists()).toBe(true);
+ });
+
+ it('should render status emoji', () => {
+ expect(findUserStatus().findComponent(GlEmoji).attributes('data-name')).toBe(
+ userMenuMockData.status.emoji,
+ );
+ });
+
+ it('should render status message', () => {
+ expect(findUserStatus().text()).toContain(userMenuMockData.status.message);
+ });
+
+ it("sets the tooltip's target to the status container", () => {
+ expect(findGlTooltip().props('target')?.()).toBe(findUserStatus().element);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js
index 91a2dc93a47..b540f85d9fe 100644
--- a/spec/frontend/super_sidebar/mock_data.js
+++ b/spec/frontend/super_sidebar/mock_data.js
@@ -1,3 +1,5 @@
+import invalidUrl from '~/lib/utils/invalid_url';
+
export const createNewMenuGroups = [
{
name: 'This group',
@@ -58,15 +60,23 @@ export const mergeRequestMenuGroup = [
];
export const sidebarData = {
+ current_menu_items: [],
+ current_context_header: {
+ title: 'Your Work',
+ icon: 'work',
+ },
name: 'Administrator',
username: 'root',
avatar_url: 'path/to/img_administrator',
+ logo_url: 'path/to/logo',
assigned_open_issues_count: 1,
todos_pending_count: 3,
issues_dashboard_path: 'path/to/issues',
total_merge_requests_count: 4,
create_new_menu_groups: createNewMenuGroups,
merge_request_menu: mergeRequestMenuGroup,
+ projects_path: 'path/to/projects',
+ groups_path: 'path/to/groups',
support_path: '/support',
display_whats_new: true,
whats_new_most_recent_release_items_count: 5,
@@ -74,4 +84,181 @@ export const sidebarData = {
show_version_check: false,
gitlab_version: { major: 16, minor: 0 },
gitlab_version_check: { severity: 'success' },
+ gitlab_com_and_canary: false,
+ canary_toggle_com_url: 'https://next.gitlab.com',
+};
+
+export const userMenuMockStatus = {
+ can_update: false,
+ busy: false,
+ customized: false,
+ emoji: 'art',
+ message: 'Working on user menu in super sidebar',
+ availability: 'busy',
+ clear_after: '2023-02-09 20:06:35 UTC',
+};
+
+export const userMenuMockPipelineMinutes = {
+ show_buy_pipeline_minutes: false,
+ show_notification_dot: false,
+ callout_attrs: {
+ feature_id: 'pipeline_minutes',
+ dismiss_endpoint: '/-/dismiss',
+ },
+ buy_pipeline_minutes_path: '/buy/pipeline_minutes',
+ tracking_attrs: {
+ 'track-action': 'trackAction',
+ 'track-label': 'label',
+ 'track-property': 'property',
+ },
+};
+
+export const userMenuMockData = {
+ name: 'Orange Fox',
+ username: 'thefox',
+ avatar_url: invalidUrl,
+ has_link_to_profile: true,
+ link_to_profile: '/thefox',
+ status: userMenuMockStatus,
+ trial: {
+ has_start_trial: false,
+ },
+ settings: {
+ profile_path: invalidUrl,
+ profile_preferences_path: invalidUrl,
+ },
+ pipeline_minutes: userMenuMockPipelineMinutes,
+ can_sign_out: false,
+ sign_out_link: invalidUrl,
+ gitlab_com_but_not_canary: true,
+ canary_toggle_com_url: 'https://next.gitlab.com',
+};
+
+export const cachedFrequentProjects = JSON.stringify([
+ {
+ id: 1,
+ name: 'Cached project 1',
+ namespace: 'Cached Namespace 1 / Cached project 1',
+ webUrl: '/cached-namespace-1/cached-project-1',
+ avatarUrl: '/uploads/-/avatar1.png',
+ lastAccessedOn: 1676325329054,
+ frequency: 10,
+ },
+ {
+ id: 2,
+ name: 'Cached project 2',
+ namespace: 'Cached Namespace 2 / Cached project 2',
+ webUrl: '/cached-namespace-2/cached-project-2',
+ avatarUrl: '/uploads/-/avatar2.png',
+ lastAccessedOn: 1674314684308,
+ frequency: 8,
+ },
+ {
+ id: 3,
+ name: 'Cached project 3',
+ namespace: 'Cached Namespace 3 / Cached project 3',
+ webUrl: '/cached-namespace-3/cached-project-3',
+ avatarUrl: '/uploads/-/avatar3.png',
+ lastAccessedOn: 1664977333191,
+ frequency: 12,
+ },
+ {
+ id: 4,
+ name: 'Cached project 4',
+ namespace: 'Cached Namespace 4 / Cached project 4',
+ webUrl: '/cached-namespace-4/cached-project-4',
+ avatarUrl: '/uploads/-/avatar4.png',
+ lastAccessedOn: 1674315407569,
+ frequency: 3,
+ },
+ {
+ id: 5,
+ name: 'Cached project 5',
+ namespace: 'Cached Namespace 5 / Cached project 5',
+ webUrl: '/cached-namespace-5/cached-project-5',
+ avatarUrl: '/uploads/-/avatar5.png',
+ lastAccessedOn: 1677084729436,
+ frequency: 21,
+ },
+ {
+ id: 6,
+ name: 'Cached project 6',
+ namespace: 'Cached Namespace 6 / Cached project 6',
+ webUrl: '/cached-namespace-6/cached-project-6',
+ avatarUrl: '/uploads/-/avatar6.png',
+ lastAccessedOn: 1676325329679,
+ frequency: 5,
+ },
+]);
+
+export const cachedFrequentGroups = JSON.stringify([
+ {
+ id: 1,
+ name: 'Cached group 1',
+ namespace: 'Cached Namespace 1',
+ webUrl: '/cached-namespace-1/cached-group-1',
+ avatarUrl: '/uploads/-/avatar1.png',
+ lastAccessedOn: 1676325329054,
+ frequency: 10,
+ },
+ {
+ id: 2,
+ name: 'Cached group 2',
+ namespace: 'Cached Namespace 2',
+ webUrl: '/cached-namespace-2/cached-group-2',
+ avatarUrl: '/uploads/-/avatar2.png',
+ lastAccessedOn: 1674314684308,
+ frequency: 8,
+ },
+ {
+ id: 3,
+ name: 'Cached group 3',
+ namespace: 'Cached Namespace 3',
+ webUrl: '/cached-namespace-3/cached-group-3',
+ avatarUrl: '/uploads/-/avatar3.png',
+ lastAccessedOn: 1664977333191,
+ frequency: 12,
+ },
+ {
+ id: 4,
+ name: 'Cached group 4',
+ namespace: 'Cached Namespace 4',
+ webUrl: '/cached-namespace-4/cached-group-4',
+ avatarUrl: '/uploads/-/avatar4.png',
+ lastAccessedOn: 1674315407569,
+ 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/super_sidebar_collapsed_state_manager_spec.js b/spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js
new file mode 100644
index 00000000000..3824965970b
--- /dev/null
+++ b/spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js
@@ -0,0 +1,157 @@
+import { GlBreakpointInstance as bp, breakpoints } from '@gitlab/ui/dist/utils';
+import { getCookie, setCookie } from '~/lib/utils/common_utils';
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import {
+ SIDEBAR_COLLAPSED_CLASS,
+ SIDEBAR_COLLAPSED_COOKIE,
+ SIDEBAR_COLLAPSED_COOKIE_EXPIRATION,
+ toggleSuperSidebarCollapsed,
+ initSuperSidebarCollapsedState,
+ bindSuperSidebarCollapsedEvents,
+ findPage,
+ findSidebar,
+ findToggles,
+} from '~/super_sidebar/super_sidebar_collapsed_state_manager';
+
+const { xl, sm } = breakpoints;
+
+jest.mock('~/lib/utils/common_utils', () => ({
+ getCookie: jest.fn(),
+ setCookie: jest.fn(),
+}));
+
+const pageHasCollapsedClass = (hasClass) => {
+ if (hasClass) {
+ expect(findPage().classList).toContain(SIDEBAR_COLLAPSED_CLASS);
+ } else {
+ expect(findPage().classList).not.toContain(SIDEBAR_COLLAPSED_CLASS);
+ }
+};
+
+describe('Super Sidebar Collapsed State Manager', () => {
+ beforeEach(() => {
+ setHTMLFixture(`
+ <div class="page-with-super-sidebar">
+ <aside class="super-sidebar"></aside>
+ <button class="js-super-sidebar-toggle"></button>
+ </div>
+ `);
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ describe('toggleSuperSidebarCollapsed', () => {
+ it.each`
+ collapsed | saveCookie | windowWidth | hasClass
+ ${true} | ${true} | ${xl} | ${true}
+ ${true} | ${false} | ${xl} | ${true}
+ ${true} | ${true} | ${sm} | ${true}
+ ${true} | ${false} | ${sm} | ${true}
+ ${false} | ${true} | ${xl} | ${false}
+ ${false} | ${false} | ${xl} | ${false}
+ ${false} | ${true} | ${sm} | ${false}
+ ${false} | ${false} | ${sm} | ${false}
+ `(
+ 'when collapsed is $collapsed, saveCookie is $saveCookie, and windowWidth is $windowWidth then page class contains `page-with-super-sidebar-collapsed` is $hasClass',
+ ({ collapsed, saveCookie, windowWidth, hasClass }) => {
+ jest.spyOn(bp, 'windowWidth').mockReturnValue(windowWidth);
+
+ toggleSuperSidebarCollapsed(collapsed, saveCookie);
+
+ pageHasCollapsedClass(hasClass);
+ expect(findSidebar().ariaHidden).toBe(collapsed);
+ expect(findSidebar().inert).toBe(collapsed);
+
+ if (saveCookie && windowWidth >= xl) {
+ expect(setCookie).toHaveBeenCalledWith(SIDEBAR_COLLAPSED_COOKIE, collapsed, {
+ expires: SIDEBAR_COLLAPSED_COOKIE_EXPIRATION,
+ });
+ } else {
+ expect(setCookie).not.toHaveBeenCalled();
+ }
+ },
+ );
+
+ describe('focus', () => {
+ it.each`
+ collapsed | isUserAction
+ ${false} | ${true}
+ ${false} | ${false}
+ ${true} | ${true}
+ ${true} | ${false}
+ `(
+ 'when collapsed is $collapsed, isUserAction is $isUserAction',
+ ({ collapsed, isUserAction }) => {
+ const sidebar = findSidebar();
+ jest.spyOn(sidebar, 'focus');
+ toggleSuperSidebarCollapsed(collapsed, false, isUserAction);
+
+ if (!collapsed && isUserAction) {
+ expect(sidebar.focus).toHaveBeenCalled();
+ } else {
+ expect(sidebar.focus).not.toHaveBeenCalled();
+ }
+ },
+ );
+ });
+ });
+
+ describe('initSuperSidebarCollapsedState', () => {
+ it.each`
+ windowWidth | cookie | hasClass
+ ${xl} | ${undefined} | ${false}
+ ${sm} | ${undefined} | ${true}
+ ${xl} | ${'true'} | ${true}
+ ${sm} | ${'true'} | ${true}
+ `(
+ 'sets page class to `page-with-super-sidebar-collapsed` when windowWidth is $windowWidth and cookie value is $cookie',
+ ({ windowWidth, cookie, hasClass }) => {
+ jest.spyOn(bp, 'windowWidth').mockReturnValue(windowWidth);
+ getCookie.mockReturnValue(cookie);
+
+ initSuperSidebarCollapsedState();
+
+ pageHasCollapsedClass(hasClass);
+ expect(setCookie).not.toHaveBeenCalled();
+ },
+ );
+ });
+
+ describe('bindSuperSidebarCollapsedEvents', () => {
+ it.each`
+ windowWidth | cookie | hasClass
+ ${xl} | ${undefined} | ${true}
+ ${sm} | ${undefined} | ${true}
+ ${xl} | ${'true'} | ${false}
+ ${sm} | ${'true'} | ${false}
+ `(
+ 'toggle click sets page class to `page-with-super-sidebar-collapsed` when windowWidth is $windowWidth and cookie value is $cookie',
+ ({ windowWidth, cookie, hasClass }) => {
+ setHTMLFixture(`
+ <div class="page-with-super-sidebar ${cookie ? SIDEBAR_COLLAPSED_CLASS : ''}">
+ <aside class="super-sidebar"></aside>
+ <button class="js-super-sidebar-toggle"></button>
+ </div>
+ `);
+ jest.spyOn(bp, 'windowWidth').mockReturnValue(windowWidth);
+ getCookie.mockReturnValue(cookie);
+
+ bindSuperSidebarCollapsedEvents();
+
+ findToggles()[0].click();
+
+ pageHasCollapsedClass(hasClass);
+
+ if (windowWidth >= xl) {
+ expect(setCookie).toHaveBeenCalledWith(SIDEBAR_COLLAPSED_COOKIE, !cookie, {
+ expires: SIDEBAR_COLLAPSED_COOKIE_EXPIRATION,
+ });
+ } else {
+ expect(setCookie).not.toHaveBeenCalled();
+ }
+ },
+ );
+ });
+});
diff --git a/spec/frontend/super_sidebar/utils_spec.js b/spec/frontend/super_sidebar/utils_spec.js
new file mode 100644
index 00000000000..1f236616e77
--- /dev/null
+++ b/spec/frontend/super_sidebar/utils_spec.js
@@ -0,0 +1,160 @@
+import {
+ getTopFrequentItems,
+ trackContextAccess,
+ formatContextSwitcherItems,
+} from '~/super_sidebar/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 { unsortedFrequentItems, sortedFrequentItems } from '../frequent_items/mock_data';
+import { searchUserProjectsAndGroupsResponseMock } from './mock_data';
+
+describe('Super sidebar utils spec', () => {
+ describe('getTopFrequentItems', () => {
+ const maxItems = 3;
+
+ it('returns empty array if no items provided', () => {
+ const result = getTopFrequentItems();
+
+ expect(result.length).toBe(0);
+ });
+
+ it('returns the requested amount of items', () => {
+ const result = getTopFrequentItems(unsortedFrequentItems, maxItems);
+
+ expect(result.length).toBe(maxItems);
+ });
+
+ it('sorts frequent items in order of frequency and lastAccessedOn', () => {
+ const result = getTopFrequentItems(unsortedFrequentItems, maxItems);
+ const expectedResult = sortedFrequentItems.slice(0, maxItems);
+
+ expect(result).toEqual(expectedResult);
+ });
+ });
+
+ describe('trackContextAccess', () => {
+ useLocalStorageSpy();
+
+ const username = 'root';
+ const context = {
+ namespace: 'groups',
+ item: { id: 1 },
+ };
+ const storageKey = `${username}/frequent-${context.namespace}`;
+
+ it('returns `false` if local storage is not available', () => {
+ jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(false);
+
+ expect(trackContextAccess()).toBe(false);
+ });
+
+ it('creates a new item if it does not exist in the local storage', () => {
+ trackContextAccess(username, context);
+
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(
+ storageKey,
+ JSON.stringify([
+ {
+ id: 1,
+ frequency: 1,
+ lastAccessedOn: Date.now(),
+ },
+ ]),
+ );
+ });
+
+ it('updates existing item if it was persisted to the local storage over 15 minutes ago', () => {
+ window.localStorage.setItem(
+ storageKey,
+ JSON.stringify([
+ {
+ id: 1,
+ frequency: 2,
+ lastAccessedOn: Date.now() - FIFTEEN_MINUTES_IN_MS - 1,
+ },
+ ]),
+ );
+ trackContextAccess(username, context);
+
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(
+ storageKey,
+ JSON.stringify([
+ {
+ id: 1,
+ frequency: 3,
+ lastAccessedOn: Date.now(),
+ },
+ ]),
+ );
+ });
+
+ it('leaves item as is if it was persisted to the local storage under 15 minutes ago', () => {
+ const jsonString = JSON.stringify([
+ {
+ id: 1,
+ frequency: 2,
+ lastAccessedOn: Date.now() - FIFTEEN_MINUTES_IN_MS,
+ },
+ ]);
+ window.localStorage.setItem(storageKey, jsonString);
+
+ expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(storageKey, jsonString);
+
+ trackContextAccess(username, context);
+
+ expect(window.localStorage.setItem).toHaveBeenCalledTimes(3);
+ expect(window.localStorage.setItem).toHaveBeenLastCalledWith(storageKey, jsonString);
+ });
+
+ it('replaces the least popular item in the local storage once the persisted items limit has been hit', () => {
+ // Add the maximum amount of items to the local storage, in increasing popularity
+ const storedItems = Array.from({ length: FREQUENT_ITEMS.MAX_COUNT }).map((_, i) => ({
+ id: i + 1,
+ frequency: i + 1,
+ lastAccessedOn: Date.now(),
+ }));
+ // The first item is considered the least popular one as it has the lowest frequency (1)
+ const [leastPopularItem] = storedItems;
+ // Persist the list to the local storage
+ const jsonString = JSON.stringify(storedItems);
+ window.localStorage.setItem(storageKey, jsonString);
+ // Track some new item that hasn't been visited yet
+ const newItem = {
+ id: FREQUENT_ITEMS.MAX_COUNT + 1,
+ };
+ trackContextAccess(username, {
+ namespace: 'groups',
+ item: newItem,
+ });
+ // Finally, retrieve the final data from the local storage
+ const finallyStoredItems = JSON.parse(window.localStorage.getItem(storageKey));
+
+ expect(finallyStoredItems).not.toEqual(expect.arrayContaining([leastPopularItem]));
+ expect(finallyStoredItems).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ id: newItem.id,
+ frequency: 1,
+ }),
+ ]),
+ );
+ });
+ });
+
+ 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,
+ },
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/syntax_highlight_spec.js b/spec/frontend/syntax_highlight_spec.js
index 1be6c213350..a573c37ca44 100644
--- a/spec/frontend/syntax_highlight_spec.js
+++ b/spec/frontend/syntax_highlight_spec.js
@@ -1,14 +1,10 @@
-/* eslint-disable no-return-assign */
import $ from 'jquery';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import syntaxHighlight from '~/syntax_highlight';
describe('Syntax Highlighter', () => {
const stubUserColorScheme = (value) => {
- if (window.gon == null) {
- window.gon = {};
- }
- return (window.gon.user_color_scheme = value);
+ window.gon.user_color_scheme = value;
};
// We have to bind `document.querySelectorAll` to `document` to not mess up the fn's context
diff --git a/spec/frontend/tags/components/delete_tag_modal_spec.js b/spec/frontend/tags/components/delete_tag_modal_spec.js
index b1726a2c0ef..8438bdb7db0 100644
--- a/spec/frontend/tags/components/delete_tag_modal_spec.js
+++ b/spec/frontend/tags/components/delete_tag_modal_spec.js
@@ -44,10 +44,6 @@ const findFormInput = () => wrapper.findComponent(GlFormInput);
const findForm = () => wrapper.find('form');
describe('Delete tag modal', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Deleting a regular tag', () => {
const expectedTitle = 'Delete tag. Are you ABSOLUTELY SURE?';
const expectedMessage = "You're about to permanently delete the tag test-tag.";
diff --git a/spec/frontend/terms/components/app_spec.js b/spec/frontend/terms/components/app_spec.js
index 99f61a31dbd..c60c6c79f17 100644
--- a/spec/frontend/terms/components/app_spec.js
+++ b/spec/frontend/terms/components/app_spec.js
@@ -37,10 +37,6 @@ describe('TermsApp', () => {
isLoggedIn.mockReturnValue(true);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findFormWithAction = (path) => wrapper.find(`form[action="${path}"]`);
const findButton = (path) => findFormWithAction(path).find('button[type="submit"]');
const findScrollableViewport = () => wrapper.findByTestId('scrollable-viewport');
diff --git a/spec/frontend/terraform/components/empty_state_spec.js b/spec/frontend/terraform/components/empty_state_spec.js
index 21bfff5f1be..db3de556244 100644
--- a/spec/frontend/terraform/components/empty_state_spec.js
+++ b/spec/frontend/terraform/components/empty_state_spec.js
@@ -16,10 +16,6 @@ describe('EmptyStateComponent', () => {
wrapper = shallowMount(EmptyState, { propsData });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render content', () => {
expect(findEmptyState().props('title')).toBe(
"Your project doesn't have any Terraform state files",
diff --git a/spec/frontend/terraform/components/init_command_modal_spec.js b/spec/frontend/terraform/components/init_command_modal_spec.js
index 911bb8878da..ca9aa26a776 100644
--- a/spec/frontend/terraform/components/init_command_modal_spec.js
+++ b/spec/frontend/terraform/components/init_command_modal_spec.js
@@ -49,10 +49,6 @@ describe('InitCommandModal', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('on rendering', () => {
it('renders the explanatory text', () => {
expect(findExplanatoryText().text()).toContain('personal access token');
diff --git a/spec/frontend/terraform/components/states_table_actions_spec.js b/spec/frontend/terraform/components/states_table_actions_spec.js
index 40b7448d78d..31a644b39b4 100644
--- a/spec/frontend/terraform/components/states_table_actions_spec.js
+++ b/spec/frontend/terraform/components/states_table_actions_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdown, GlModal, GlSprintf } from '@gitlab/ui';
+import { GlDropdown, GlModal, GlSprintf, GlFormInput } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
@@ -85,6 +85,7 @@ describe('StatesTableActions', () => {
const findDownloadBtn = () => wrapper.find('[data-testid="terraform-state-download"]');
const findRemoveBtn = () => wrapper.find('[data-testid="terraform-state-remove"]');
const findRemoveModal = () => wrapper.findComponent(GlModal);
+ const findFormInput = () => wrapper.findComponent(GlFormInput);
beforeEach(() => {
return createComponent();
@@ -96,7 +97,6 @@ describe('StatesTableActions', () => {
toast = null;
unlockResponse = null;
updateStateResponse = null;
- wrapper.destroy();
});
describe('when the state is loading', () => {
@@ -296,9 +296,7 @@ describe('StatesTableActions', () => {
describe('when state name is present', () => {
beforeEach(async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- await wrapper.setData({ removeConfirmText: defaultProps.state.name });
+ await findFormInput().vm.$emit('input', defaultProps.state.name);
findRemoveModal().vm.$emit('ok');
diff --git a/spec/frontend/terraform/components/states_table_spec.js b/spec/frontend/terraform/components/states_table_spec.js
index 0b3b169891b..7c783c9f717 100644
--- a/spec/frontend/terraform/components/states_table_spec.js
+++ b/spec/frontend/terraform/components/states_table_spec.js
@@ -127,7 +127,7 @@ describe('StatesTable', () => {
propsData,
provide: { projectPath: 'path/to/project' },
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
}),
);
@@ -140,11 +140,6 @@ describe('StatesTable', () => {
return createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it.each`
name | toolTipText | hasBadge | loading | lineNumber
${'state-1'} | ${'Locked by user-1 2 days ago'} | ${true} | ${false} | ${0}
diff --git a/spec/frontend/terraform/components/terraform_list_spec.js b/spec/frontend/terraform/components/terraform_list_spec.js
index 580951e799a..dc59e2769f6 100644
--- a/spec/frontend/terraform/components/terraform_list_spec.js
+++ b/spec/frontend/terraform/components/terraform_list_spec.js
@@ -63,11 +63,6 @@ describe('TerraformList', () => {
const findStatesTable = () => wrapper.findComponent(StatesTable);
const findTab = () => wrapper.findComponent(GlTab);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when the terraform query has succeeded', () => {
describe('when there is a list of terraform states', () => {
const states = [
diff --git a/spec/frontend/toggles/index_spec.js b/spec/frontend/toggles/index_spec.js
index f8c43e0ad0c..89e35991914 100644
--- a/spec/frontend/toggles/index_spec.js
+++ b/spec/frontend/toggles/index_spec.js
@@ -44,7 +44,6 @@ describe('toggles/index.js', () => {
afterEach(() => {
document.body.innerHTML = '';
instance = null;
- toggleWrapper = null;
});
describe('initToggle', () => {
diff --git a/spec/frontend/token_access/inbound_token_access_spec.js b/spec/frontend/token_access/inbound_token_access_spec.js
index fcd1a33fa68..1ca58053e68 100644
--- a/spec/frontend/token_access/inbound_token_access_spec.js
+++ b/spec/frontend/token_access/inbound_token_access_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import InboundTokenAccess from '~/token_access/components/inbound_token_access.vue';
import inboundAddProjectCIJobTokenScopeMutation from '~/token_access/graphql/mutations/inbound_add_project_ci_job_token_scope.mutation.graphql';
import inboundRemoveProjectCIJobTokenScopeMutation from '~/token_access/graphql/mutations/inbound_remove_project_ci_job_token_scope.mutation.graphql';
@@ -26,7 +26,7 @@ const error = new Error(message);
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('TokenAccess component', () => {
let wrapper;
diff --git a/spec/frontend/token_access/opt_in_jwt_spec.js b/spec/frontend/token_access/opt_in_jwt_spec.js
index 3a68f247aa6..cdb385aa743 100644
--- a/spec/frontend/token_access/opt_in_jwt_spec.js
+++ b/spec/frontend/token_access/opt_in_jwt_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { OPT_IN_JWT_HELP_LINK } from '~/token_access/constants';
import OptInJwt from '~/token_access/components/opt_in_jwt.vue';
import getOptInJwtSettingQuery from '~/token_access/graphql/queries/get_opt_in_jwt_setting.query.graphql';
@@ -16,7 +16,7 @@ const error = new Error(errorMessage);
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('OptInJwt component', () => {
let wrapper;
diff --git a/spec/frontend/token_access/outbound_token_access_spec.js b/spec/frontend/token_access/outbound_token_access_spec.js
index 893a021197f..347ea1178bc 100644
--- a/spec/frontend/token_access/outbound_token_access_spec.js
+++ b/spec/frontend/token_access/outbound_token_access_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import OutboundTokenAccess from '~/token_access/components/outbound_token_access.vue';
import addProjectCIJobTokenScopeMutation from '~/token_access/graphql/mutations/add_project_ci_job_token_scope.mutation.graphql';
import removeProjectCIJobTokenScopeMutation from '~/token_access/graphql/mutations/remove_project_ci_job_token_scope.mutation.graphql';
@@ -26,7 +26,7 @@ const error = new Error(message);
Vue.use(VueApollo);
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('TokenAccess component', () => {
let wrapper;
diff --git a/spec/frontend/token_access/token_access_app_spec.js b/spec/frontend/token_access/token_access_app_spec.js
index 7f269ee5fda..cff16fd125c 100644
--- a/spec/frontend/token_access/token_access_app_spec.js
+++ b/spec/frontend/token_access/token_access_app_spec.js
@@ -11,12 +11,8 @@ describe('TokenAccessApp component', () => {
const findInboundTokenAccess = () => wrapper.findComponent(InboundTokenAccess);
const findOptInJwt = () => wrapper.findComponent(OptInJwt);
- const createComponent = (flagState = false) => {
- wrapper = shallowMount(TokenAccessApp, {
- provide: {
- glFeatures: { ciInboundJobTokenScope: flagState },
- },
- });
+ const createComponent = () => {
+ wrapper = shallowMount(TokenAccessApp);
};
describe('default', () => {
@@ -32,12 +28,6 @@ describe('TokenAccessApp component', () => {
expect(findOutboundTokenAccess().exists()).toBe(true);
});
- it('does not render the inbound token access component', () => {
- expect(findInboundTokenAccess().exists()).toBe(false);
- });
- });
-
- describe('with feature flag enabled', () => {
it('renders the inbound token access component', () => {
createComponent(true);
diff --git a/spec/frontend/token_access/token_projects_table_spec.js b/spec/frontend/token_access/token_projects_table_spec.js
index b51d8b3ccea..7654aa09b0a 100644
--- a/spec/frontend/token_access/token_projects_table_spec.js
+++ b/spec/frontend/token_access/token_projects_table_spec.js
@@ -6,14 +6,19 @@ import { mockProjects, mockFields } from './mock_data';
describe('Token projects table', () => {
let wrapper;
- const createComponent = () => {
+ const defaultProps = {
+ tableFields: mockFields,
+ projects: mockProjects,
+ };
+
+ const createComponent = (props) => {
wrapper = mountExtended(TokenProjectsTable, {
provide: {
fullPath: 'root/ci-project',
},
propsData: {
- tableFields: mockFields,
- projects: mockProjects,
+ ...defaultProps,
+ ...props,
},
});
};
@@ -25,31 +30,52 @@ describe('Token projects table', () => {
const findProjectNameCell = () => wrapper.findByTestId('token-access-project-name');
const findProjectNamespaceCell = () => wrapper.findByTestId('token-access-project-namespace');
- beforeEach(() => {
+ it('displays a table', () => {
createComponent();
- });
- it('displays a table', () => {
expect(findTable().exists()).toBe(true);
});
it('displays the correct amount of table rows', () => {
+ createComponent();
+
expect(findAllTableRows()).toHaveLength(mockProjects.length);
});
it('delete project button emits event with correct project to delete', async () => {
+ createComponent();
+
await findDeleteProjectBtn().trigger('click');
expect(wrapper.emitted('removeProject')).toEqual([[mockProjects[0].fullPath]]);
});
it('does not show the remove icon if the project is locked', () => {
+ createComponent();
+
// currently two mock projects with one being a locked project
expect(findAllDeleteProjectBtn()).toHaveLength(1);
});
it('displays project and namespace cells', () => {
+ createComponent();
+
expect(findProjectNameCell().text()).toBe('merge-train-stuff');
expect(findProjectNamespaceCell().text()).toBe('root');
});
+
+ it('displays empty string for namespace when namespace is null', () => {
+ const nullNamespace = {
+ id: '1',
+ name: 'merge-train-stuff',
+ namespace: null,
+ fullPath: 'root/merge-train-stuff',
+ isLocked: false,
+ __typename: 'Project',
+ };
+
+ createComponent({ projects: [nullNamespace] });
+
+ expect(findProjectNamespaceCell().text()).toBe('');
+ });
});
diff --git a/spec/frontend/tooltips/components/tooltips_spec.js b/spec/frontend/tooltips/components/tooltips_spec.js
index d5a63a99601..e473091f405 100644
--- a/spec/frontend/tooltips/components/tooltips_spec.js
+++ b/spec/frontend/tooltips/components/tooltips_spec.js
@@ -30,11 +30,6 @@ describe('tooltips/components/tooltips.vue', () => {
const allTooltips = () => wrapper.findAllComponents(GlTooltip);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('addTooltips', () => {
let target;
diff --git a/spec/frontend/usage_quotas/components/usage_quotas_app_spec.js b/spec/frontend/usage_quotas/components/usage_quotas_app_spec.js
index cb70ea4e72d..3508bf7cfde 100644
--- a/spec/frontend/usage_quotas/components/usage_quotas_app_spec.js
+++ b/spec/frontend/usage_quotas/components/usage_quotas_app_spec.js
@@ -23,10 +23,6 @@ describe('UsageQuotasApp', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSubTitle = () => wrapper.findByTestId('usage-quotas-page-subtitle');
it('renders the view title', () => {
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 3379af3f41c..1a200090805 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
@@ -53,10 +53,6 @@ describe('ProjectStorageApp', () => {
const findUsageQuotasHelpLink = () => wrapper.findByTestId('usage-quotas-help-link');
const findUsageGraph = () => wrapper.findComponent(UsageGraph);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with apollo fetching successful', () => {
let mockApollo;
diff --git a/spec/frontend/usage_quotas/storage/components/project_storage_detail_spec.js b/spec/frontend/usage_quotas/storage/components/project_storage_detail_spec.js
index ce489f69cad..6065ec9e4bf 100644
--- a/spec/frontend/usage_quotas/storage/components/project_storage_detail_spec.js
+++ b/spec/frontend/usage_quotas/storage/components/project_storage_detail_spec.js
@@ -54,9 +54,6 @@ describe('ProjectStorageDetail', () => {
beforeEach(() => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
describe('with storage types', () => {
it.each(storageTypes)(
diff --git a/spec/frontend/usage_quotas/storage/components/storage_type_icon_spec.js b/spec/frontend/usage_quotas/storage/components/storage_type_icon_spec.js
index 1eb3386bfb8..364cf1e587b 100644
--- a/spec/frontend/usage_quotas/storage/components/storage_type_icon_spec.js
+++ b/spec/frontend/usage_quotas/storage/components/storage_type_icon_spec.js
@@ -16,10 +16,6 @@ describe('StorageTypeIcon', () => {
const findGlIcon = () => wrapper.findComponent(GlIcon);
describe('rendering icon', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
expected | provided
${'doc-image'} | ${'lfsObjectsSize'}
diff --git a/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js b/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js
index 75b970d937a..02268e1c9d8 100644
--- a/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js
+++ b/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js
@@ -39,10 +39,6 @@ describe('Storage Counter usage graph component', () => {
mountComponent(data);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the legend in order', () => {
const types = wrapper.findAll('[data-testid="storage-type-legend"]');
diff --git a/spec/frontend/user_lists/components/user_lists_spec.js b/spec/frontend/user_lists/components/user_lists_spec.js
index 161eb036361..603289ac11e 100644
--- a/spec/frontend/user_lists/components/user_lists_spec.js
+++ b/spec/frontend/user_lists/components/user_lists_spec.js
@@ -39,11 +39,6 @@ describe('~/user_lists/components/user_lists.vue', () => {
const newButton = () => within(wrapper.element).queryAllByText('New user list');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('without permissions', () => {
const provideData = {
...mockProvide,
diff --git a/spec/frontend/user_lists/components/user_lists_table_spec.js b/spec/frontend/user_lists/components/user_lists_table_spec.js
index 3324b040b86..96e9705f02b 100644
--- a/spec/frontend/user_lists/components/user_lists_table_spec.js
+++ b/spec/frontend/user_lists/components/user_lists_table_spec.js
@@ -22,10 +22,6 @@ describe('User Lists Table', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should display the details of a user list', () => {
expect(wrapper.find('[data-testid="ffUserListName"]').text()).toBe(userList.name);
expect(wrapper.find('[data-testid="ffUserListIds"]').text()).toBe(
diff --git a/spec/frontend/user_popovers_spec.js b/spec/frontend/user_popovers_spec.js
index 8ce071c075f..3808cc8b0fc 100644
--- a/spec/frontend/user_popovers_spec.js
+++ b/spec/frontend/user_popovers_spec.js
@@ -10,8 +10,6 @@ jest.mock('~/api/user_api', () => ({
}));
describe('User Popovers', () => {
- let origGon;
-
const fixtureTemplate = 'merge_requests/merge_request_with_mentions.html';
const selector = '.js-user-link[data-user], .js-user-link[data-user-id]';
@@ -60,15 +58,6 @@ describe('User Popovers', () => {
});
};
- beforeEach(() => {
- origGon = window.gon;
- window.gon = {};
- });
-
- afterEach(() => {
- window.gon = origGon;
- });
-
describe('when signed out', () => {
beforeEach(() => {
setupTestSubject();
diff --git a/spec/frontend/validators/length_validator_spec.js b/spec/frontend/validators/length_validator_spec.js
new file mode 100644
index 00000000000..ece8238b3e3
--- /dev/null
+++ b/spec/frontend/validators/length_validator_spec.js
@@ -0,0 +1,91 @@
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import LengthValidator, { isAboveMaxLength, isBelowMinLength } from '~/validators/length_validator';
+
+describe('length_validator', () => {
+ describe('isAboveMaxLength', () => {
+ it('should return true if the string is longer than the maximum length', () => {
+ expect(isAboveMaxLength('123456', '5')).toBe(true);
+ });
+
+ it('should return false if the string is shorter than the maximum length', () => {
+ expect(isAboveMaxLength('1234', '5')).toBe(false);
+ });
+ });
+
+ describe('isBelowMinLength', () => {
+ it('should return true if the string is shorter than the minimum length and not empty', () => {
+ expect(isBelowMinLength('1234', '5', 'false')).toBe(true);
+ });
+
+ it('should return false if the string is longer than the minimum length', () => {
+ expect(isBelowMinLength('123456', '5', 'false')).toBe(false);
+ });
+
+ it('should return false if the string is empty and allowed to be empty', () => {
+ expect(isBelowMinLength('', '5', 'true')).toBe(false);
+ });
+
+ it('should return true if the string is empty and not allowed to be empty', () => {
+ expect(isBelowMinLength('', '5', 'false')).toBe(true);
+ });
+ });
+
+ describe('LengthValidator', () => {
+ let input;
+ let validator;
+
+ beforeEach(() => {
+ setHTMLFixture(
+ '<div class="container"><input class="js-validate-length" /><span class="gl-field-error"></span></div>',
+ );
+ input = document.querySelector('input');
+ input.dataset.minLength = '3';
+ input.dataset.maxLength = '5';
+ input.dataset.minLengthMessage = 'Too short';
+ input.dataset.maxLengthMessage = 'Too long';
+ validator = new LengthValidator({ container: '.container' });
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ it('sets error message for input with value longer than max length', () => {
+ input.value = '123456';
+ input.dispatchEvent(new Event('input'));
+ expect(validator.errorMessage).toBe('Too long');
+ });
+
+ it('sets error message for input with value shorter than min length', () => {
+ input.value = '12';
+ input.dispatchEvent(new Event('input'));
+ expect(validator.errorMessage).toBe('Too short');
+ });
+
+ it('does not set error message for input with valid length', () => {
+ input.value = '123';
+ input.dispatchEvent(new Event('input'));
+ expect(validator.errorMessage).toBeNull();
+ });
+
+ it('does not set error message for empty input if allowEmpty is true', () => {
+ input.dataset.allowEmpty = 'true';
+ input.value = '';
+ input.dispatchEvent(new Event('input'));
+ expect(validator.errorMessage).toBeNull();
+ });
+
+ it('sets error message for empty input if allowEmpty is false', () => {
+ input.dataset.allowEmpty = 'false';
+ input.value = '';
+ input.dispatchEvent(new Event('input'));
+ expect(validator.errorMessage).toBe('Too short');
+ });
+
+ it('sets error message for empty input if allowEmpty is not defined', () => {
+ input.value = '';
+ input.dispatchEvent(new Event('input'));
+ expect(validator.errorMessage).toBe('Too short');
+ });
+ });
+});
diff --git a/spec/frontend/vue_compat_test_setup.js b/spec/frontend/vue_compat_test_setup.js
new file mode 100644
index 00000000000..b6234c51535
--- /dev/null
+++ b/spec/frontend/vue_compat_test_setup.js
@@ -0,0 +1,60 @@
+/* eslint-disable import/no-commonjs */
+const Vue = require('vue');
+const VTU = require('@vue/test-utils');
+const { installCompat: installVTUCompat, fullCompatConfig } = require('vue-test-utils-compat');
+
+if (global.document) {
+ const compatConfig = {
+ MODE: 2,
+
+ GLOBAL_MOUNT: 'suppress-warning',
+ GLOBAL_EXTEND: 'suppress-warning',
+ GLOBAL_PROTOTYPE: 'suppress-warning',
+ RENDER_FUNCTION: 'suppress-warning',
+
+ INSTANCE_DESTROY: 'suppress-warning',
+ INSTANCE_DELETE: 'suppress-warning',
+
+ INSTANCE_ATTRS_CLASS_STYLE: 'suppress-warning',
+ INSTANCE_CHILDREN: 'suppress-warning',
+ INSTANCE_SCOPED_SLOTS: 'suppress-warning',
+ INSTANCE_LISTENERS: 'suppress-warning',
+ INSTANCE_EVENT_EMITTER: 'suppress-warning',
+ INSTANCE_EVENT_HOOKS: 'suppress-warning',
+ INSTANCE_SET: 'suppress-warning',
+ GLOBAL_OBSERVABLE: 'suppress-warning',
+ GLOBAL_SET: 'suppress-warning',
+ COMPONENT_FUNCTIONAL: 'suppress-warning',
+ COMPONENT_V_MODEL: 'suppress-warning',
+ CUSTOM_DIR: 'suppress-warning',
+ OPTIONS_BEFORE_DESTROY: 'suppress-warning',
+ OPTIONS_DATA_MERGE: 'suppress-warning',
+ OPTIONS_DATA_FN: 'suppress-warning',
+ OPTIONS_DESTROYED: 'suppress-warning',
+ ATTR_FALSE_VALUE: 'suppress-warning',
+
+ COMPILER_V_ON_NATIVE: 'suppress-warning',
+ COMPILER_V_BIND_OBJECT_ORDER: 'suppress-warning',
+
+ CONFIG_WHITESPACE: 'suppress-warning',
+ CONFIG_OPTION_MERGE_STRATS: 'suppress-warning',
+ PRIVATE_APIS: 'suppress-warning',
+ WATCH_ARRAY: 'suppress-warning',
+ };
+
+ let compatH;
+ Vue.config.compilerOptions.whitespace = 'condense';
+ Vue.createApp({
+ compatConfig: {
+ MODE: 3,
+ RENDER_FUNCTION: 'suppress-warning',
+ },
+ render(h) {
+ compatH = h;
+ },
+ }).mount(document.createElement('div'));
+
+ Vue.configureCompat(compatConfig);
+ installVTUCompat(VTU, fullCompatConfig, compatH);
+ VTU.config.global.renderStubDefaultSlot = true;
+}
diff --git a/spec/frontend/vue_merge_request_widget/components/action_buttons.js b/spec/frontend/vue_merge_request_widget/components/action_buttons.js
index 6d714aeaf18..7334f061dc9 100644
--- a/spec/frontend/vue_merge_request_widget/components/action_buttons.js
+++ b/spec/frontend/vue_merge_request_widget/components/action_buttons.js
@@ -11,10 +11,6 @@ function factory(propsData = {}) {
}
describe('MR widget extension actions', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('tertiaryButtons', () => {
it('renders buttons', () => {
factory({
diff --git a/spec/frontend/vue_merge_request_widget/components/added_commit_message_spec.js b/spec/frontend/vue_merge_request_widget/components/added_commit_message_spec.js
index 063425454d7..4164a7df482 100644
--- a/spec/frontend/vue_merge_request_widget/components/added_commit_message_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/added_commit_message_spec.js
@@ -14,10 +14,6 @@ function factory(propsData) {
}
describe('Widget added commit message', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('displays changes where not merged when state is closed', () => {
factory({ state: 'closed' });
diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
index bf208f16d18..e78e1be7882 100644
--- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js
@@ -1,26 +1,32 @@
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
import { GlButton, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { createAlert } from '~/flash';
+import approvedByCurrentUser from 'test_fixtures/graphql/merge_requests/approvals/approvals.query.graphql.json';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { createAlert } from '~/alert';
import Approvals from '~/vue_merge_request_widget/components/approvals/approvals.vue';
import ApprovalsSummary from '~/vue_merge_request_widget/components/approvals/approvals_summary.vue';
import ApprovalsSummaryOptional from '~/vue_merge_request_widget/components/approvals/approvals_summary_optional.vue';
import {
- FETCH_LOADING,
- FETCH_ERROR,
APPROVE_ERROR,
UNAPPROVE_ERROR,
} from '~/vue_merge_request_widget/components/approvals/messages';
import eventHub from '~/vue_merge_request_widget/event_hub';
+import approvedByQuery from 'ee_else_ce/vue_merge_request_widget/components/approvals/queries/approvals.query.graphql';
+import { createCanApproveResponse } from 'jest/approvals/mock_data';
+
+Vue.use(VueApollo);
const mockAlertDismiss = jest.fn();
-jest.mock('~/flash', () => ({
+jest.mock('~/alert', () => ({
createAlert: jest.fn().mockImplementation(() => ({
dismiss: mockAlertDismiss,
})),
}));
-const RULE_NAME = 'first_rule';
const TEST_HELP_PATH = 'help/path';
const testApprovedBy = () => [1, 7, 10].map((id) => ({ id }));
const testApprovals = () => ({
@@ -34,15 +40,18 @@ const testApprovals = () => ({
require_password_to_approve: false,
invalid_approvers_rules: [],
});
-const testApprovalRulesResponse = () => ({ rules: [{ id: 2 }] });
describe('MRWidget approvals', () => {
let wrapper;
let service;
let mr;
- const createComponent = (props = {}) => {
+ const createComponent = (props = {}, response = approvedByCurrentUser) => {
+ const requestHandlers = [[approvedByQuery, jest.fn().mockResolvedValue(response)]];
+ const apolloProvider = createMockApollo(requestHandlers);
+
wrapper = shallowMount(Approvals, {
+ apolloProvider,
propsData: {
mr,
service,
@@ -68,15 +77,10 @@ describe('MRWidget approvals', () => {
};
const findSummary = () => wrapper.findComponent(ApprovalsSummary);
const findOptionalSummary = () => wrapper.findComponent(ApprovalsSummaryOptional);
- const findInvalidRules = () => wrapper.find('[data-testid="invalid-rules"]');
beforeEach(() => {
service = {
...{
- fetchApprovals: jest.fn().mockReturnValue(Promise.resolve(testApprovals())),
- fetchApprovalSettings: jest
- .fn()
- .mockReturnValue(Promise.resolve(testApprovalRulesResponse())),
approveMergeRequest: jest.fn().mockReturnValue(Promise.resolve(testApprovals())),
unapproveMergeRequest: jest.fn().mockReturnValue(Promise.resolve(testApprovals())),
approveMergeRequestWithAuth: jest.fn().mockReturnValue(Promise.resolve(testApprovals())),
@@ -97,55 +101,21 @@ describe('MRWidget approvals', () => {
};
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- });
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('when created', () => {
- it('shows loading message', async () => {
- service = {
- fetchApprovals: jest.fn().mockReturnValue(new Promise(() => {})),
- };
-
- createComponent();
- await nextTick();
- expect(wrapper.text()).toContain(FETCH_LOADING);
- });
-
- it('fetches approvals', () => {
- createComponent();
- expect(service.fetchApprovals).toHaveBeenCalled();
- });
- });
-
- describe('when fetch approvals error', () => {
- beforeEach(() => {
- jest.spyOn(service, 'fetchApprovals').mockReturnValue(Promise.reject());
- createComponent();
- return nextTick();
- });
-
- it('still shows loading message', () => {
- expect(wrapper.text()).toContain(FETCH_LOADING);
- });
-
- it('flashes error', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: FETCH_ERROR });
- });
+ gon.current_user_id = getIdFromGraphQLId(
+ approvedByCurrentUser.data.project.mergeRequest.approvedBy.nodes[0].id,
+ );
});
describe('action button', () => {
describe('when mr is closed', () => {
- beforeEach(() => {
+ beforeEach(async () => {
+ const response = createCanApproveResponse();
+
mr.isOpen = false;
- mr.approvals.user_has_approved = false;
- mr.approvals.user_can_approve = true;
- createComponent();
- return nextTick();
+ createComponent({}, response);
+ await waitForPromises();
});
it('action is not rendered', () => {
@@ -154,12 +124,12 @@ describe('MRWidget approvals', () => {
});
describe('when user cannot approve', () => {
- beforeEach(() => {
- mr.approvals.user_has_approved = false;
- mr.approvals.user_can_approve = false;
+ beforeEach(async () => {
+ const response = JSON.parse(JSON.stringify(approvedByCurrentUser));
+ response.data.project.mergeRequest.approvedBy.nodes = [];
- createComponent();
- return nextTick();
+ createComponent({}, response);
+ await waitForPromises();
});
it('action is not rendered', () => {
@@ -168,15 +138,16 @@ describe('MRWidget approvals', () => {
});
describe('when user can approve', () => {
+ let canApproveResponse;
+
beforeEach(() => {
- mr.approvals.user_has_approved = false;
- mr.approvals.user_can_approve = true;
+ canApproveResponse = createCanApproveResponse();
});
describe('and MR is unapproved', () => {
- beforeEach(() => {
- createComponent();
- return nextTick();
+ beforeEach(async () => {
+ createComponent({}, canApproveResponse);
+ await waitForPromises();
});
it('approve action is rendered', () => {
@@ -190,30 +161,33 @@ describe('MRWidget approvals', () => {
describe('and MR is approved', () => {
beforeEach(() => {
- mr.approvals.approved = true;
+ canApproveResponse.data.project.mergeRequest.approved = true;
});
describe('with no approvers', () => {
- beforeEach(() => {
- mr.approvals.approved_by = [];
- createComponent();
- return nextTick();
+ beforeEach(async () => {
+ canApproveResponse.data.project.mergeRequest.approvedBy.nodes = [];
+ createComponent({}, canApproveResponse);
+ await nextTick();
});
- it('approve action (with inverted style) is rendered', () => {
- expect(findActionData()).toEqual({
+ it('approve action is rendered', () => {
+ expect(findActionData()).toMatchObject({
variant: 'confirm',
text: 'Approve',
- category: 'secondary',
});
});
});
describe('with approvers', () => {
- beforeEach(() => {
- mr.approvals.approved_by = [{ user: { id: 7 } }];
- createComponent();
- return nextTick();
+ beforeEach(async () => {
+ canApproveResponse.data.project.mergeRequest.approvedBy.nodes =
+ approvedByCurrentUser.data.project.mergeRequest.approvedBy.nodes;
+
+ canApproveResponse.data.project.mergeRequest.approvedBy.nodes[0].id = 2;
+
+ createComponent({}, canApproveResponse);
+ await waitForPromises();
});
it('approve additionally action is rendered', () => {
@@ -227,9 +201,9 @@ describe('MRWidget approvals', () => {
});
describe('when approve action is clicked', () => {
- beforeEach(() => {
- createComponent();
- return nextTick();
+ beforeEach(async () => {
+ createComponent({}, canApproveResponse);
+ await waitForPromises();
});
it('shows loading icon', () => {
@@ -258,10 +232,6 @@ describe('MRWidget approvals', () => {
it('emits to eventHub', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
});
-
- it('calls store setApprovals', () => {
- expect(mr.setApprovals).toHaveBeenCalledWith(testApprovals());
- });
});
describe('and error', () => {
@@ -286,12 +256,12 @@ describe('MRWidget approvals', () => {
});
describe('when user has approved', () => {
- beforeEach(() => {
- mr.approvals.user_has_approved = true;
- mr.approvals.user_can_approve = false;
+ beforeEach(async () => {
+ const response = JSON.parse(JSON.stringify(approvedByCurrentUser));
- createComponent();
- return nextTick();
+ createComponent({}, response);
+
+ await waitForPromises();
});
it('revoke action is rendered', () => {
@@ -316,10 +286,6 @@ describe('MRWidget approvals', () => {
it('emits to eventHub', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
});
-
- it('calls store setApprovals', () => {
- expect(mr.setApprovals).toHaveBeenCalledWith(testApprovals());
- });
});
describe('and error', () => {
@@ -329,7 +295,7 @@ describe('MRWidget approvals', () => {
return nextTick();
});
- it('flashes error message', () => {
+ it('alerts error message', () => {
expect(createAlert).toHaveBeenCalledWith({ message: UNAPPROVE_ERROR });
});
});
@@ -338,19 +304,24 @@ describe('MRWidget approvals', () => {
});
describe('approvals optional summary', () => {
+ let optionalApprovalsResponse;
+
+ beforeEach(() => {
+ optionalApprovalsResponse = JSON.parse(JSON.stringify(approvedByCurrentUser));
+ });
+
describe('when no approvals required and no approvers', () => {
beforeEach(() => {
- mr.approvals.approved_by = [];
- mr.approvals.approvals_required = 0;
- mr.approvals.user_has_approved = false;
+ optionalApprovalsResponse.data.project.mergeRequest.approvedBy.nodes = [];
+ optionalApprovalsResponse.data.project.mergeRequest.approvalsRequired = 0;
});
describe('and can approve', () => {
- beforeEach(() => {
- mr.approvals.user_can_approve = true;
+ beforeEach(async () => {
+ optionalApprovalsResponse.data.project.mergeRequest.userPermissions.canApprove = true;
- createComponent();
- return nextTick();
+ createComponent({}, optionalApprovalsResponse);
+ await waitForPromises();
});
it('is shown', () => {
@@ -363,11 +334,9 @@ describe('MRWidget approvals', () => {
});
describe('and cannot approve', () => {
- beforeEach(() => {
- mr.approvals.user_can_approve = false;
-
- createComponent();
- return nextTick();
+ beforeEach(async () => {
+ createComponent({}, optionalApprovalsResponse);
+ await nextTick();
});
it('is shown', () => {
@@ -382,9 +351,9 @@ describe('MRWidget approvals', () => {
});
describe('approvals summary', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createComponent();
- return nextTick();
+ await nextTick();
});
it('is rendered with props', () => {
@@ -393,41 +362,7 @@ describe('MRWidget approvals', () => {
expect(findOptionalSummary().exists()).toBe(false);
expect(summary.exists()).toBe(true);
expect(summary.props()).toMatchObject({
- projectPath: 'gitlab-org/gitlab',
- iid: '1',
- updatedCount: 0,
- });
- });
- });
-
- describe('invalid rules', () => {
- beforeEach(() => {
- mr.approvals.merge_request_approvers_available = true;
- createComponent();
- });
-
- it('does not render related components', () => {
- expect(findInvalidRules().exists()).toBe(false);
- });
-
- describe('when invalid rules are present', () => {
- beforeEach(() => {
- mr.approvals.invalid_approvers_rules = [{ name: RULE_NAME }];
- createComponent();
- });
-
- it('renders related components', () => {
- const invalidRules = findInvalidRules();
-
- expect(invalidRules.exists()).toBe(true);
-
- const invalidRulesText = invalidRules.text();
-
- expect(invalidRulesText).toContain(RULE_NAME);
- expect(invalidRulesText).toContain(
- 'GitLab has approved this rule automatically to unblock the merge request.',
- );
- expect(invalidRulesText).toContain('Learn more.');
+ approvalState: approvedByCurrentUser.data.project.mergeRequest,
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js
index e6fb0495947..bf3df70d423 100644
--- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_optional_spec.js
@@ -13,11 +13,6 @@ describe('MRWidget approvals summary optional', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findHelpLink = () => wrapper.findComponent(GlLink);
describe('when can approve', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js
index e75ce7c60c9..8c6b3cc464c 100644
--- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js
@@ -1,11 +1,10 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { mount } from '@vue/test-utils';
-import approvedByMultipleUsers from 'test_fixtures/graphql/merge_requests/approvals/approved_by.query.graphql_multiple_users.json';
-import noApprovalsResponse from 'test_fixtures/graphql/merge_requests/approvals/approved_by.query.graphql_no_approvals.json';
-import approvedByCurrentUser from 'test_fixtures/graphql/merge_requests/approvals/approved_by.query.graphql.json';
+import approvedByMultipleUsers from 'test_fixtures/graphql/merge_requests/approvals/approvals.query.graphql_multiple_users.json';
+import noApprovalsResponse from 'test_fixtures/graphql/merge_requests/approvals/approvals.query.graphql_no_approvals.json';
+import approvedByCurrentUser from 'test_fixtures/graphql/merge_requests/approvals/approvals.query.graphql.json';
import waitForPromises from 'helpers/wait_for_promises';
-import createMockApollo from 'helpers/mock_apollo_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import ApprovalsSummary from '~/vue_merge_request_widget/components/approvals/approvals_summary.vue';
import {
@@ -14,32 +13,22 @@ import {
APPROVED_BY_YOU_AND_OTHERS,
} from '~/vue_merge_request_widget/components/approvals/messages';
import UserAvatarList from '~/vue_shared/components/user_avatar/user_avatar_list.vue';
-import approvedByQuery from 'ee_else_ce/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql';
Vue.use(VueApollo);
describe('MRWidget approvals summary', () => {
- const originalUserId = gon.current_user_id;
let wrapper;
- const createComponent = (response = approvedByCurrentUser) => {
+ const createComponent = (data = approvedByCurrentUser) => {
wrapper = mount(ApprovalsSummary, {
propsData: {
- projectPath: 'gitlab-org/gitlab',
- iid: '1',
+ approvalState: data.data.project.mergeRequest,
},
- apolloProvider: createMockApollo([[approvedByQuery, jest.fn().mockResolvedValue(response)]]),
});
};
const findAvatars = () => wrapper.findComponent(UserAvatarList);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- gon.current_user_id = originalUserId;
- });
-
describe('when approved', () => {
beforeEach(async () => {
createComponent();
diff --git a/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js b/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js
index 52e2393bf05..332f14a1721 100644
--- a/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/artifacts_list_app_spec.js
@@ -26,7 +26,6 @@ describe('Merge Requests Artifacts list app', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js b/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js
index b7bf72cd215..bb049a5d52f 100644
--- a/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/artifacts_list_spec.js
@@ -18,10 +18,6 @@ describe('Artifacts List', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
mountComponent(data);
});
diff --git a/spec/frontend/vue_merge_request_widget/components/extensions/child_content_spec.js b/spec/frontend/vue_merge_request_widget/components/extensions/child_content_spec.js
index 198a4c2823a..3a621db7b44 100644
--- a/spec/frontend/vue_merge_request_widget/components/extensions/child_content_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/extensions/child_content_spec.js
@@ -20,11 +20,6 @@ function factory(propsData) {
}
describe('MR widget extension child content', () => {
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders child components', () => {
factory({
data: {
diff --git a/spec/frontend/vue_merge_request_widget/components/extensions/status_icon_spec.js b/spec/frontend/vue_merge_request_widget/components/extensions/status_icon_spec.js
index f3aa5bb774f..ffa6b5538d3 100644
--- a/spec/frontend/vue_merge_request_widget/components/extensions/status_icon_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/extensions/status_icon_spec.js
@@ -11,10 +11,6 @@ function factory(propsData = {}) {
}
describe('MR widget extensions status icon', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders loading icon', () => {
factory({ name: 'test', isLoading: true, iconName: 'failed' });
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js
index 81f266d8070..6b22c2e26ac 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_collapsible_extension_spec.js
@@ -25,10 +25,6 @@ describe('Merge Request Collapsible Extension', () => {
const findErrorMessage = () => wrapper.find('.js-error-state');
const findIcon = () => wrapper.findComponent(GlIcon);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('while collapsed', () => {
beforeEach(() => {
mountComponent(data);
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_alert_message_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_alert_message_spec.js
index 5d923d0383f..01178dab9bb 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_alert_message_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_alert_message_spec.js
@@ -11,10 +11,6 @@ function createComponent(propsData = {}) {
}
describe('MrWidgetAlertMessage', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render a GlAert', () => {
createComponent({ type: 'danger' });
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_author_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_author_spec.js
index 8a42e2e2ce7..7eafccae083 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_author_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_author_spec.js
@@ -29,7 +29,6 @@ describe('MrWidgetAuthor', () => {
});
afterEach(() => {
- wrapper.destroy();
window.gl = oldWindowGl;
});
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js
index 90a29d15488..534b745aed2 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_author_time_spec.js
@@ -23,10 +23,6 @@ describe('MrWidgetAuthorTime', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders provided action text', () => {
expect(wrapper.text()).toContain('Merged by');
});
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_container_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_container_spec.js
index 8dadb0c65d0..25de76ba33c 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_container_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_container_spec.js
@@ -13,10 +13,6 @@ describe('MrWidgetContainer', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has layout', () => {
factory();
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js
index 6a9b019fb4f..090a96d576c 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_icon_spec.js
@@ -15,10 +15,6 @@ describe('MrWidgetIcon', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders icon and container', () => {
expect(wrapper.element.className).toContain('circle-icon-container');
expect(wrapper.findComponent(GlIcon).props('name')).toEqual(TEST_ICON);
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js
index 13beb43e10b..18842e996de 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js
@@ -29,10 +29,6 @@ describe('MrWidgetPipelineContainer', () => {
mock.onGet().reply(HTTP_STATUS_OK, {});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDeploymentList = () => wrapper.findComponent(DeploymentList);
const findCIErrorMessage = () => wrapper.findByTestId('ci-error-message');
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
index ec047fe0714..f284ec98a73 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
@@ -1,3 +1,4 @@
+import { GlModal } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import WidgetRebase from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue';
@@ -8,8 +9,11 @@ jest.mock('~/vue_shared/plugins/global_toast');
let wrapper;
-function createWrapper(propsData) {
+function createWrapper(propsData, provideData) {
wrapper = mount(WidgetRebase, {
+ provide: {
+ ...provideData,
+ },
propsData,
data() {
return {
@@ -19,6 +23,7 @@ function createWrapper(propsData) {
userPermissions: {
pushToSourceBranch: propsData.mr.canPushToSourceBranch,
},
+ pipelines: propsData.mr.pipelines,
},
};
},
@@ -37,11 +42,8 @@ describe('Merge request widget rebase component', () => {
const findRebaseMessageText = () => findRebaseMessage().text();
const findStandardRebaseButton = () => wrapper.find('[data-testid="standard-rebase-button"]');
const findRebaseWithoutCiButton = () => wrapper.find('[data-testid="rebase-without-ci-button"]');
+ const findModal = () => wrapper.findComponent(GlModal);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
describe('while rebasing', () => {
it('should show progress message', () => {
createWrapper({
@@ -199,6 +201,72 @@ describe('Merge request widget rebase component', () => {
expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
});
});
+
+ describe('security modal', () => {
+ it('displays modal and rebases after confirming', () => {
+ createWrapper(
+ {
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ sourceProjectFullPath: 'user/forked',
+ targetProjectFullPath: 'root/original',
+ pipelines: {
+ nodes: [
+ {
+ id: '1',
+ project: {
+ id: '2',
+ fullPath: 'user/forked',
+ },
+ },
+ ],
+ },
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ { canCreatePipelineInTargetProject: true },
+ );
+
+ findModal().vm.show = jest.fn();
+
+ findStandardRebaseButton().vm.$emit('click');
+
+ expect(findModal().vm.show).toHaveBeenCalled();
+
+ findModal().vm.$emit('primary');
+
+ expect(rebaseMock).toHaveBeenCalled();
+ });
+
+ it('does not display modal', () => {
+ createWrapper(
+ {
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ sourceProjectFullPath: 'user/forked',
+ targetProjectFullPath: 'root/original',
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ { canCreatePipelineInTargetProject: false },
+ );
+
+ findModal().vm.show = jest.fn();
+
+ findStandardRebaseButton().vm.$emit('click');
+
+ expect(findModal().vm.show).not.toHaveBeenCalled();
+ expect(rebaseMock).toHaveBeenCalled();
+ });
+ });
});
describe('without permissions', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_related_links_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_related_links_spec.js
index 15522f7ac1d..42a16090510 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_related_links_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_related_links_spec.js
@@ -9,10 +9,6 @@ describe('MRWidgetRelatedLinks', () => {
wrapper = shallowMount(RelatedLinks, { propsData });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
describe('closesText', () => {
it('returns Closes text for open merge request', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_status_icon_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_status_icon_spec.js
index 530549b7b9c..b210327aa31 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_status_icon_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_status_icon_spec.js
@@ -17,11 +17,6 @@ describe('MR widget status icon component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('while loading', () => {
it('renders loading icon', () => {
createWrapper({ status: 'loading' });
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js
index 73358edee78..70c76687a79 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_suggest_pipeline_spec.js
@@ -18,10 +18,6 @@ describe('MRWidgetSuggestPipeline', () => {
describe('template', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('core functionality', () => {
const findOkBtn = () => wrapper.find('[data-testid="ok"]');
let trackingSpy;
diff --git a/spec/frontend/vue_merge_request_widget/components/review_app_link_spec.js b/spec/frontend/vue_merge_request_widget/components/review_app_link_spec.js
index e393b56034d..48484551d59 100644
--- a/spec/frontend/vue_merge_request_widget/components/review_app_link_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/review_app_link_spec.js
@@ -17,10 +17,6 @@ describe('review app link', () => {
wrapper = shallowMount(ReviewAppLink, { propsData: props });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders provided link as href attribute', () => {
expect(wrapper.attributes('href')).toBe(props.link);
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/commit_edit_spec.js b/spec/frontend/vue_merge_request_widget/components/states/commit_edit_spec.js
index c0add94e6ed..f520c6a4f78 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/commit_edit_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/commit_edit_spec.js
@@ -26,10 +26,6 @@ describe('Commits edit component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findTextarea = () => wrapper.find('.form-control');
it('has a correct label', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js
index e4448346685..c2ab0e384e8 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js
@@ -12,10 +12,6 @@ function factory(propsData = {}) {
}
describe('Merge request widget merge checks failed state component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
mrState | displayText
${{ approvals: true, isApproved: false }} | ${'approvalNeeded'}
diff --git a/spec/frontend/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js b/spec/frontend/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js
index c9aca01083d..7d471b91c37 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js
@@ -37,10 +37,6 @@ describe('MergeFailedPipelineConfirmationDialog', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render informational text explaining why merging immediately can be dangerous', () => {
expect(trimText(wrapper.text())).toContain(
'The latest pipeline for this merge request did not succeed. The latest changes are unverified. Are you sure you want to attempt to merge?',
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_archived_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_archived_spec.js
index 08700e834d7..3e18ee75125 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_archived_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_archived_spec.js
@@ -10,11 +10,6 @@ describe('MRWidgetArchived', () => {
wrapper = shallowMount(archivedComponent, { propsData: { mr: {} } });
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders error icon', () => {
expect(wrapper.findComponent(StateContainer).exists()).toBe(true);
expect(wrapper.findComponent(StateContainer).props().status).toBe('failed');
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js
index fef5fee5f19..65d170cae8b 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js
@@ -83,8 +83,6 @@ describe('MRWidgetAutoMergeEnabled', () => {
afterEach(() => {
window.gl = oldWindowGl;
- wrapper.destroy();
- wrapper = null;
});
describe('computed', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js
index 826f708069c..9b043bda72d 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js
@@ -18,10 +18,6 @@ describe('MRWidgetAutoMergeFailed', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
createComponent({
mr: { mergeError },
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_checking_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_checking_spec.js
index ac18ccf9e26..6c3b7f76fe6 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_checking_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_checking_spec.js
@@ -9,11 +9,6 @@ describe('MRWidgetChecking', () => {
wrapper = shallowMount(CheckingComponent, { propsData: { mr: {} } });
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders loading icon', () => {
expect(wrapper.findComponent(StateContainer).exists()).toBe(true);
expect(wrapper.findComponent(StateContainer).props().status).toBe('loading');
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js
index 5d2d1fdd6f1..e4febda1daa 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commit_message_dropdown_spec.js
@@ -36,10 +36,6 @@ describe('Commits message dropdown component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDropdownElements = () => wrapper.findAllComponents(GlDropdownItem);
const findFirstDropdownElement = () => findDropdownElements().at(0);
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commits_header_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commits_header_spec.js
index a6d3a6286a7..b3843b066df 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commits_header_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_commits_header_spec.js
@@ -21,10 +21,6 @@ describe('Commits header component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findHeaderWrapper = () => wrapper.find('.js-mr-widget-commits-count');
const findCommitToggle = () => wrapper.find('.commit-edit-toggle');
const findTargetBranchMessage = () => wrapper.find('.label-branch');
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js
index 2ca9dc61745..7f0a171d712 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js
@@ -50,10 +50,6 @@ describe('MRWidgetConflicts', () => {
await nextTick();
}
- afterEach(() => {
- wrapper.destroy();
- });
-
// There are two permissions we need to consider:
//
// 1. Is the user allowed to merge to the target branch?
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_failed_to_merge_spec.js
index 833fa27d453..38e5422325a 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_failed_to_merge_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_failed_to_merge_spec.js
@@ -28,10 +28,6 @@ describe('MRWidgetFailedToMerge', () => {
jest.spyOn(window, 'clearInterval').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('interval', () => {
it('sets interval to refresh', () => {
createComponent();
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 a3aa563b516..e44e2834a0e 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
@@ -62,10 +62,6 @@ describe('MRWidgetMerged', () => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findButtonByText = (text) =>
wrapper.findAll('button').wrappers.find((w) => w.text() === text);
const findRemoveSourceBranchButton = () => findButtonByText('Delete source branch');
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merging_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merging_spec.js
index 5408f731b34..ca75ca11e5b 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merging_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merging_spec.js
@@ -29,10 +29,6 @@ describe('MRWidgetMerging', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders information about merge request being merged', () => {
const message = wrapper.findComponent(BoldText).props('message');
expect(message).toContain('Merging!');
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_missing_branch_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_missing_branch_spec.js
index f29cf55f7ce..fca25b8bb94 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_missing_branch_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_missing_branch_spec.js
@@ -15,10 +15,6 @@ function factory(sourceBranchRemoved) {
}
describe('MRWidgetMissingBranch', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
sourceBranchRemoved | branchName
${true} | ${'source'}
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_not_allowed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_not_allowed_spec.js
index 42515c597c5..40b053282de 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_not_allowed_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_not_allowed_spec.js
@@ -10,11 +10,6 @@ describe('MRWidgetNotAllowed', () => {
wrapper = shallowMount(notAllowedComponent);
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders success icon', () => {
expect(wrapper.findComponent(StatusIcon).exists()).toBe(true);
expect(wrapper.findComponent(StatusIcon).props().status).toBe('success');
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge_spec.js
index 6de0c06c33d..c8fa1399dcb 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_nothing_to_merge_spec.js
@@ -1,28 +1,58 @@
-import Vue, { nextTick } from 'vue';
+import { GlSprintf } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import NothingToMerge from '~/vue_merge_request_widget/components/states/nothing_to_merge.vue';
describe('NothingToMerge', () => {
- describe('template', () => {
- const Component = Vue.extend(NothingToMerge);
- const newBlobPath = '/foo';
- const vm = new Component({
- el: document.createElement('div'),
+ let wrapper;
+ const newBlobPath = '/foo';
+
+ const defaultProps = {
+ mr: {
+ newBlobPath,
+ },
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = shallowMountExtended(NothingToMerge, {
propsData: {
- mr: { newBlobPath },
+ ...props,
+ },
+ stubs: {
+ GlSprintf,
},
});
+ };
+
+ const findCreateButton = () => wrapper.findByTestId('createFileButton');
+ const findNothingToMergeTextBody = () => wrapper.findByTestId('nothing-to-merge-body');
+
+ describe('With Blob link', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('shows the component with the correct text and highlights', () => {
+ expect(wrapper.text()).toContain('This merge request contains no changes.');
+ expect(findNothingToMergeTextBody().text()).toContain(
+ 'Use merge requests to propose changes to your project and discuss them with your team. To make changes, push a commit or edit this merge request to use a different branch.',
+ );
+ });
+
+ it('shows the Create file button with the correct attributes', () => {
+ const createButton = findCreateButton();
+
+ expect(createButton.exists()).toBe(true);
+ expect(createButton.attributes('href')).toBe(newBlobPath);
+ });
+ });
- it('should have correct elements', () => {
- expect(vm.$el.classList.contains('mr-widget-body')).toBe(true);
- expect(vm.$el.querySelector('[data-testid="createFileButton"]').href).toContain(newBlobPath);
- expect(vm.$el.innerText).toContain('Use merge requests to propose changes to your project');
+ describe('Without Blob link', () => {
+ beforeEach(() => {
+ createComponent({ mr: { newBlobPath: '' } });
});
- it('should not show new blob link if there is no link available', () => {
- vm.mr.newBlobPath = null;
- nextTick(() => {
- expect(vm.$el.querySelector('[data-testid="createFileButton"]')).toEqual(null);
- });
+ it('does not show the Create file button', () => {
+ expect(findCreateButton().exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked_spec.js
index c0197b5e20a..d99106df0a2 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked_spec.js
@@ -10,11 +10,6 @@ describe('MRWidgetPipelineBlocked', () => {
wrapper = shallowMount(PipelineBlockedComponent);
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders error icon', () => {
expect(wrapper.findComponent(StatusIcon).exists()).toBe(true);
expect(wrapper.findComponent(StatusIcon).props().status).toBe('failed');
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js
index 8bae2b62ed1..ea93463f3ab 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_pipeline_failed_spec.js
@@ -19,11 +19,6 @@ describe('PipelineFailed', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render error status icon', () => {
createComponent();
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_sha_mismatch_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_sha_mismatch_spec.js
index aaa4591d67d..02b71ebf183 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_sha_mismatch_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_sha_mismatch_spec.js
@@ -20,10 +20,6 @@ describe('ShaMismatch', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render warning message', () => {
expect(wrapper.text()).toContain('Merge blocked: new changes were just added.');
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js
index c839fa17fe5..97f8e695df9 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_squash_before_merge_spec.js
@@ -14,10 +14,6 @@ describe('Squash before merge component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
describe('checkbox', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions_spec.js
index c97b42f61ac..58b9f162815 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions_spec.js
@@ -21,10 +21,6 @@ describe('UnresolvedDiscussions', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('triggers the correct notes event when the jump to first unresolved discussion button is clicked', () => {
jest.spyOn(notesEventHub, '$emit');
@@ -38,10 +34,6 @@ describe('UnresolvedDiscussions', () => {
wrapper = createComponent({ path: TEST_HOST });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should have correct elements', () => {
const text = removeBreakLine(wrapper.text()).trim();
expect(text).toContain('Merge blocked:');
diff --git a/spec/frontend/vue_merge_request_widget/components/states/new_ready_to_merge_spec.js b/spec/frontend/vue_merge_request_widget/components/states/new_ready_to_merge_spec.js
index 5ec9654a4af..20d06a7aaee 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/new_ready_to_merge_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/new_ready_to_merge_spec.js
@@ -15,10 +15,6 @@ function factory({ canMerge }) {
}
describe('New ready to merge state component', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
canMerge
${true}
diff --git a/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js b/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js
index e610ceb2122..43ce1769ff3 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js
@@ -1,7 +1,7 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import getStateQueryResponse from 'test_fixtures/graphql/merge_requests/get_state.query.graphql.json';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import WorkInProgress, {
MSG_SOMETHING_WENT_WRONG,
MSG_MARK_READY,
@@ -22,7 +22,7 @@ const TEST_MR_IID = '23';
const TEST_MR_TITLE = 'Test MR Title';
const TEST_PROJECT_PATH = 'lorem/ipsum';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/merge_request');
describe('~/vue_merge_request_widget/components/states/work_in_progress.vue', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/action_buttons_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/action_buttons_spec.js
index 366ea113162..adefce9060c 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/action_buttons_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/widget/action_buttons_spec.js
@@ -11,10 +11,6 @@ function factory(propsData = {}) {
}
describe('~/vue_merge_request_widget/components/widget/action_buttons.vue', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('tertiaryButtons', () => {
it('renders buttons', () => {
factory({
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
index 973866176c2..5887670a58d 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
@@ -50,10 +50,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('on mount', () => {
it('fetches collapsed', async () => {
const fetchCollapsedData = jest
diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_action_button_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_action_button_spec.js
index 1bad5dacefa..785515ae846 100644
--- a/spec/frontend/vue_merge_request_widget/deployment/deployment_action_button_spec.js
+++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_action_button_spec.js
@@ -25,10 +25,6 @@ describe('Deployment action button', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when passed only icon via props', () => {
beforeEach(() => {
factory({
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 41df485b0de..1fdbbadf8b0 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
@@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+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 {
@@ -21,7 +21,7 @@ import {
retryDetails,
} from './deployment_mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/lib/utils/url_utility');
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
@@ -54,7 +54,6 @@ describe('DeploymentAction component', () => {
});
afterEach(() => {
- wrapper.destroy();
confirmAction.mockReset();
});
diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_list_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_list_spec.js
index 948d7ebab5e..77dac4204db 100644
--- a/spec/frontend/vue_merge_request_widget/deployment/deployment_list_spec.js
+++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_list_spec.js
@@ -28,7 +28,6 @@ describe('~/vue_merge_request_widget/components/deployment/deployment_list.vue',
afterEach(() => {
wrapper?.destroy?.();
- wrapper = null;
});
describe('with few deployments', () => {
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 f310f7669a9..74122f47ad3 100644
--- a/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js
+++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js
@@ -32,10 +32,6 @@ describe('Deployment component', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('always renders DeploymentInfo', () => {
expect(wrapper.findComponent(DeploymentInfo).exists()).toBe(true);
});
diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js
index 8994fa522d0..7a151c26934 100644
--- a/spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js
+++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_view_button_spec.js
@@ -28,10 +28,6 @@ describe('Deployment View App button', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findReviewAppLink = () => wrapper.findComponent(ReviewAppLink);
const findMrWigdetDeploymentDropdown = () => wrapper.findComponent(GlDropdown);
const findMrWigdetDeploymentDropdownIcon = () =>
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 548b68bc103..d2d622d0534 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
@@ -73,7 +73,6 @@ describe('Test report extension', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js b/spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js
index 01049e54a7f..40158917f52 100644
--- a/spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js
@@ -39,7 +39,6 @@ describe('Accessibility extension', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js b/spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js
index 67b327217ef..4b7870842bd 100644
--- a/spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js
@@ -61,7 +61,6 @@ describe('Code Quality extension', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js b/spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js
index 13384e1efca..52a244107bd 100644
--- a/spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js
@@ -48,7 +48,6 @@ describe('Terraform extension', () => {
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
});
diff --git a/spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js b/spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js
index 015d394312a..20f1796008a 100644
--- a/spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js
+++ b/spec/frontend/vue_merge_request_widget/mr_widget_how_to_merge_modal_spec.js
@@ -15,11 +15,6 @@ describe('MRWidgetHowToMerge', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
beforeEach(() => {
mountComponent();
});
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 f37276ad594..fad501ee7f5 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
@@ -1,9 +1,10 @@
import { GlBadge, GlLink, GlIcon, GlButton, GlDropdown } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
+import { mount, shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import * as Sentry from '@sentry/browser';
+import approvedByCurrentUser from 'test_fixtures/graphql/merge_requests/approvals/approvals.query.graphql.json';
import getStateQueryResponse from 'test_fixtures/graphql/merge_requests/get_state.query.graphql.json';
import readyToMergeResponse from 'test_fixtures/graphql/merge_requests/states/ready_to_merge.query.graphql.json';
import createMockApollo from 'helpers/mock_apollo_helper';
@@ -20,6 +21,7 @@ import {
registerExtension,
registeredExtensions,
} from '~/vue_merge_request_widget/components/extensions';
+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';
@@ -28,6 +30,7 @@ import StatusIcon from '~/vue_merge_request_widget/components/extensions/status_
import securityReportMergeRequestDownloadPathsQuery from '~/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql';
import getStateQuery from '~/vue_merge_request_widget/queries/get_state.query.graphql';
import readyToMergeQuery from 'ee_else_ce/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql';
+import approvalsQuery from 'ee_else_ce/vue_merge_request_widget/components/approvals/queries/approvals.query.graphql';
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';
@@ -60,6 +63,8 @@ jest.mock('@sentry/browser', () => ({
Vue.use(VueApollo);
describe('MrWidgetOptions', () => {
+ let stateQueryHandler;
+ let queryResponse;
let wrapper;
let mock;
@@ -83,37 +88,41 @@ describe('MrWidgetOptions', () => {
afterEach(() => {
mock.restore();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
wrapper.destroy();
-
gl.mrWidgetData = {};
- gon.features = {};
});
- const createComponent = (mrData = mockData, options = {}) => {
- wrapper = mount(MrWidgetOptions, {
+ const createComponent = (mrData = mockData, options = {}, data = {}, fullMount = true) => {
+ const mounting = fullMount ? mount : shallowMount;
+
+ queryResponse = {
+ data: {
+ project: {
+ ...getStateQueryResponse.data.project,
+ mergeRequest: {
+ ...getStateQueryResponse.data.project.mergeRequest,
+ mergeError: mrData.mergeError || null,
+ },
+ },
+ },
+ };
+ stateQueryHandler = jest.fn().mockResolvedValue(queryResponse);
+ wrapper = mounting(MrWidgetOptions, {
propsData: {
mrData: { ...mrData },
},
data() {
- return { loading: false };
+ return {
+ loading: false,
+ ...data,
+ };
},
...options,
apolloProvider: createMockApollo([
- [
- getStateQuery,
- jest.fn().mockResolvedValue({
- data: {
- project: {
- ...getStateQueryResponse.data.project,
- mergeRequest: {
- ...getStateQueryResponse.data.project.mergeRequest,
- mergeError: mrData.mergeError || null,
- },
- },
- },
- }),
- ],
+ [approvalsQuery, jest.fn().mockResolvedValue(approvedByCurrentUser)],
+ [getStateQuery, stateQueryHandler],
[readyToMergeQuery, jest.fn().mockResolvedValue(readyToMergeResponse)],
[
userPermissionsQuery,
@@ -351,18 +360,6 @@ describe('MrWidgetOptions', () => {
});
});
- describe('initPolling', () => {
- it('should call SmartInterval', () => {
- wrapper.vm.initPolling();
-
- expect(SmartInterval).toHaveBeenCalledWith(
- expect.objectContaining({
- callback: wrapper.vm.checkStatus,
- }),
- );
- });
- });
-
describe('initDeploymentsPolling', () => {
it('should call SmartInterval', () => {
wrapper.vm.initDeploymentsPolling();
@@ -529,23 +526,64 @@ describe('MrWidgetOptions', () => {
});
});
- describe('resumePolling', () => {
- it('should call stopTimer on pollingInterval', () => {
- jest.spyOn(wrapper.vm.pollingInterval, 'resume').mockImplementation(() => {});
+ describe('Apollo query', () => {
+ const interval = 5;
+ const data = 'foo';
+ const mockCheckStatus = jest.fn().mockResolvedValue({ data });
+ const mockSetGraphqlData = jest.fn();
+ const mockSetData = jest.fn();
- wrapper.vm.resumePolling();
+ beforeEach(() => {
+ wrapper.destroy();
+
+ return createComponent(
+ mockData,
+ {},
+ {
+ pollInterval: interval,
+ startingPollInterval: interval,
+ mr: {
+ setData: mockSetData,
+ setGraphqlData: mockSetGraphqlData,
+ },
+ service: {
+ checkStatus: mockCheckStatus,
+ },
+ },
+ false,
+ );
+ });
- expect(wrapper.vm.pollingInterval.resume).toHaveBeenCalled();
+ describe('normal polling behavior', () => {
+ it('responds to the GraphQL query finishing', () => {
+ expect(mockSetGraphqlData).toHaveBeenCalledWith(queryResponse.data.project);
+ expect(mockCheckStatus).toHaveBeenCalled();
+ expect(mockSetData).toHaveBeenCalledWith(data, undefined);
+ expect(stateQueryHandler).toHaveBeenCalledTimes(1);
+ });
});
- });
- describe('stopPolling', () => {
- it('should call stopTimer on pollingInterval', () => {
- jest.spyOn(wrapper.vm.pollingInterval, 'stopTimer').mockImplementation(() => {});
+ describe('external event control', () => {
+ describe('enablePolling', () => {
+ it('enables the Apollo query polling using the event hub', () => {
+ eventHub.$emit('EnablePolling');
+
+ expect(stateQueryHandler).toHaveBeenCalled();
+ jest.advanceTimersByTime(interval * STATE_QUERY_POLLING_INTERVAL_BACKOFF);
+ expect(stateQueryHandler).toHaveBeenCalledTimes(2);
+ });
+ });
+
+ describe('disablePolling', () => {
+ it('disables the Apollo query polling using the event hub', () => {
+ expect(stateQueryHandler).toHaveBeenCalledTimes(1);
- wrapper.vm.stopPolling();
+ eventHub.$emit('DisablePolling');
+ jest.advanceTimersByTime(interval * STATE_QUERY_POLLING_INTERVAL_BACKOFF);
- expect(wrapper.vm.pollingInterval.stopTimer).toHaveBeenCalled();
+ expect(stateQueryHandler).toHaveBeenCalledTimes(1); // no additional polling after a real interval timeout
+ });
+ });
});
});
});
@@ -890,11 +928,7 @@ describe('MrWidgetOptions', () => {
});
describe('mock extension', () => {
- let pollRequest;
-
beforeEach(() => {
- pollRequest = jest.spyOn(Poll.prototype, 'makeRequest');
-
registerExtension(workingExtension());
createComponent();
@@ -945,10 +979,6 @@ describe('MrWidgetOptions', () => {
expect(collapsedSection.findComponent(GlButton).exists()).toBe(true);
expect(collapsedSection.findComponent(GlButton).text()).toBe('Full report');
});
-
- it('extension polling is not called if enablePolling flag is not passed', () => {
- expect(pollRequest).toHaveBeenCalledTimes(0);
- });
});
describe('expansion', () => {
@@ -1235,10 +1265,6 @@ describe('MrWidgetOptions', () => {
});
describe('widget container', () => {
- afterEach(() => {
- delete window.gon.features.refactorSecurityExtension;
- });
-
it('should not be displayed when the refactor_security_extension feature flag is turned off', () => {
createComponent();
expect(findWidgetContainer().exists()).toBe(false);
diff --git a/spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js b/spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js
index 88d9d0b4cff..a6288b9c725 100644
--- a/spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js
+++ b/spec/frontend/vue_merge_request_widget/stores/get_state_key_spec.js
@@ -20,7 +20,7 @@ describe('getStateKey', () => {
};
const bound = getStateKey.bind(context);
- expect(bound()).toEqual(null);
+ expect(bound()).toEqual('checking');
context.detailedMergeStatus = 'MERGEABLE';
diff --git a/spec/frontend/vue_shared/alert_details/alert_management_sidebar_todo_spec.js b/spec/frontend/vue_shared/alert_details/alert_management_sidebar_todo_spec.js
index 12c5c190e26..217103ab25c 100644
--- a/spec/frontend/vue_shared/alert_details/alert_management_sidebar_todo_spec.js
+++ b/spec/frontend/vue_shared/alert_details/alert_management_sidebar_todo_spec.js
@@ -32,10 +32,6 @@ describe('Alert Details Sidebar To Do', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findToDoButton = () => wrapper.find('[data-testid="alert-todo-button"]');
describe('updating the alert to do', () => {
diff --git a/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap
deleted file mode 100644
index ca9d4488870..00000000000
--- a/spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap
+++ /dev/null
@@ -1,40 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`File row header component adds multiple ellipsises after 40 characters 1`] = `
-<div
- class="file-row-header bg-white sticky-top p-2 js-file-row-header"
- title="app/assets/javascripts/merge_requests/widget/diffs/notes"
->
- <gl-truncate-stub
- class="bold"
- position="middle"
- text="app/assets/javascripts/merge_requests/widget/diffs/notes"
- />
-</div>
-`;
-
-exports[`File row header component renders file path 1`] = `
-<div
- class="file-row-header bg-white sticky-top p-2 js-file-row-header"
- title="app/assets"
->
- <gl-truncate-stub
- class="bold"
- position="middle"
- text="app/assets"
- />
-</div>
-`;
-
-exports[`File row header component trucates path after 40 characters 1`] = `
-<div
- class="file-row-header bg-white sticky-top p-2 js-file-row-header"
- title="app/assets/javascripts/merge_requests"
->
- <gl-truncate-stub
- class="bold"
- position="middle"
- text="app/assets/javascripts/merge_requests"
- />
-</div>
-`;
diff --git a/spec/frontend/vue_shared/components/actions_button_spec.js b/spec/frontend/vue_shared/components/actions_button_spec.js
index f3fb840b270..8c2f2b52f8e 100644
--- a/spec/frontend/vue_shared/components/actions_button_spec.js
+++ b/spec/frontend/vue_shared/components/actions_button_spec.js
@@ -34,10 +34,6 @@ describe('Actions button component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findButton = () => wrapper.findComponent(GlButton);
const findTooltip = () => wrapper.findComponent(GlTooltip);
const findDropdown = () => wrapper.findComponent(GlDropdown);
diff --git a/spec/frontend/vue_shared/components/alert_details_table_spec.js b/spec/frontend/vue_shared/components/alert_details_table_spec.js
index 8a9ee4699bd..8e7a10c4d77 100644
--- a/spec/frontend/vue_shared/components/alert_details_table_spec.js
+++ b/spec/frontend/vue_shared/components/alert_details_table_spec.js
@@ -41,11 +41,6 @@ describe('AlertDetails', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findTableComponent = () => wrapper.findComponent(GlTable);
const findTableKeys = () => findTableComponent().findAll('tbody td:first-child');
const findTableFieldValueByKey = (fieldKey) =>
diff --git a/spec/frontend/vue_shared/components/awards_list_spec.js b/spec/frontend/vue_shared/components/awards_list_spec.js
index c7f9d8fd8d5..da5516f8db1 100644
--- a/spec/frontend/vue_shared/components/awards_list_spec.js
+++ b/spec/frontend/vue_shared/components/awards_list_spec.js
@@ -64,16 +64,7 @@ const REACTION_CONTROL_CLASSES = [
describe('vue_shared/components/awards_list', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const createComponent = (props = {}) => {
- if (wrapper) {
- throw new Error('There should only be one wrapper created per test');
- }
-
wrapper = mount(AwardsList, { propsData: props });
};
const matchingEmojiTag = (name) => expect.stringMatching(`gl-emoji data-name="${name}"`);
@@ -98,7 +89,6 @@ describe('vue_shared/components/awards_list', () => {
addButtonClass: TEST_ADD_BUTTON_CLASS,
});
});
-
it('shows awards in correct order', () => {
expect(findAwardsData()).toEqual([
{
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 ce7fd40937f..6acd1f51a86 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
@@ -24,10 +24,6 @@ describe('Blob Rich Viewer component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the passed content without transformations', () => {
expect(wrapper.html()).toContain(content);
});
diff --git a/spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js b/spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js
index 4b44311b253..a480e0869e8 100644
--- a/spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js
+++ b/spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js
@@ -23,10 +23,6 @@ describe('Blob Simple Viewer component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('does not fail if content is empty', () => {
const spy = jest.spyOn(window.console, 'error');
createComponent('');
diff --git a/spec/frontend/vue_shared/components/changed_file_icon_spec.js b/spec/frontend/vue_shared/components/changed_file_icon_spec.js
index ea708b6f3fe..d1b1e58f5d7 100644
--- a/spec/frontend/vue_shared/components/changed_file_icon_spec.js
+++ b/spec/frontend/vue_shared/components/changed_file_icon_spec.js
@@ -21,10 +21,6 @@ describe('Changed file icon', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findIcon = () => wrapper.findComponent(GlIcon);
const findIconName = () => findIcon().props('name');
const findIconClasses = () => findIcon().classes();
diff --git a/spec/frontend/vue_shared/components/chronic_duration_input_spec.js b/spec/frontend/vue_shared/components/chronic_duration_input_spec.js
index 6932a812287..2a40511affb 100644
--- a/spec/frontend/vue_shared/components/chronic_duration_input_spec.js
+++ b/spec/frontend/vue_shared/components/chronic_duration_input_spec.js
@@ -10,8 +10,6 @@ describe('vue_shared/components/chronic_duration_input', () => {
let hiddenElement;
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
textElement = null;
hiddenElement = null;
});
@@ -22,10 +20,6 @@ describe('vue_shared/components/chronic_duration_input', () => {
};
const createComponent = (props = {}) => {
- if (wrapper) {
- throw new Error('There should only be one wrapper created per test');
- }
-
wrapper = mount(ChronicDurationInput, { propsData: props });
findComponents();
};
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 4f24ec2d015..afb509b9fe6 100644
--- a/spec/frontend/vue_shared/components/ci_badge_link_spec.js
+++ b/spec/frontend/vue_shared/components/ci_badge_link_spec.js
@@ -82,10 +82,6 @@ describe('CI Badge Link Component', () => {
wrapper = shallowMount(CiBadgeLink, { propsData });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each(Object.keys(statuses))('should render badge for status: %s', (status) => {
createComponent({ status: statuses[status] });
diff --git a/spec/frontend/vue_shared/components/ci_icon_spec.js b/spec/frontend/vue_shared/components/ci_icon_spec.js
index 2064bee9673..31d63654168 100644
--- a/spec/frontend/vue_shared/components/ci_icon_spec.js
+++ b/spec/frontend/vue_shared/components/ci_icon_spec.js
@@ -7,11 +7,6 @@ describe('CI Icon component', () => {
const findIconWrapper = () => wrapper.find('[data-testid="ci-icon-wrapper"]');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render a span element with an svg', () => {
wrapper = shallowMount(ciIcon, {
propsData: {
diff --git a/spec/frontend/vue_shared/components/clipboard_button_spec.js b/spec/frontend/vue_shared/components/clipboard_button_spec.js
index b18b00e70bb..08a9c2a42d8 100644
--- a/spec/frontend/vue_shared/components/clipboard_button_spec.js
+++ b/spec/frontend/vue_shared/components/clipboard_button_spec.js
@@ -59,11 +59,6 @@ describe('clipboard button', () => {
expect(wrapper.vm.$root.$emit).toHaveBeenCalledWith('bv::hide::tooltip', 'clipboard-button-1');
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('without gfm', () => {
beforeEach(() => {
createWrapper({
diff --git a/spec/frontend/vue_shared/components/clone_dropdown_spec.js b/spec/frontend/vue_shared/components/clone_dropdown_spec.js
index 31c08260dd0..584e29d94c4 100644
--- a/spec/frontend/vue_shared/components/clone_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/clone_dropdown_spec.js
@@ -21,11 +21,6 @@ describe('Clone Dropdown Button', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('rendering', () => {
it('matches the snapshot', () => {
createComponent();
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 181692e61b5..25283eb1211 100644
--- a/spec/frontend/vue_shared/components/code_block_highlighted_spec.js
+++ b/spec/frontend/vue_shared/components/code_block_highlighted_spec.js
@@ -11,10 +11,6 @@ describe('Code Block Highlighted', () => {
wrapper = shallowMount(CodeBlock, { propsData });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders highlighted code if language is supported', async () => {
createComponent({ code, language: 'javascript' });
diff --git a/spec/frontend/vue_shared/components/code_block_spec.js b/spec/frontend/vue_shared/components/code_block_spec.js
index 9a4dbcc47ff..0fdfb96cb23 100644
--- a/spec/frontend/vue_shared/components/code_block_spec.js
+++ b/spec/frontend/vue_shared/components/code_block_spec.js
@@ -13,10 +13,6 @@ describe('Code Block', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('overwrites the default slot', () => {
createComponent({}, { default: 'DEFAULT SLOT' });
diff --git a/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js b/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js
index 060048c4bbd..a839af3b709 100644
--- a/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js
+++ b/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js
@@ -34,10 +34,6 @@ describe('ColorPicker', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('label', () => {
it('hides the label if the label is not passed', () => {
createComponent(shallowMount);
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js
index fe614f03119..700556edfd5 100644
--- a/spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js
@@ -20,10 +20,6 @@ describe('ColorItem', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the correct title', () => {
expect(wrapper.text()).toBe(propsData.title);
});
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js
index 5b0772f6e34..61a9ab3225e 100644
--- a/spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js
@@ -3,7 +3,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import DropdownContents from '~/vue_shared/components/color_select_dropdown/dropdown_contents.vue';
import DropdownValue from '~/vue_shared/components/color_select_dropdown/dropdown_value.vue';
@@ -13,7 +13,7 @@ import ColorSelectRoot from '~/vue_shared/components/color_select_dropdown/color
import { DROPDOWN_VARIANT } from '~/vue_shared/components/color_select_dropdown/constants';
import { colorQueryResponse, updateColorMutationResponse, color } from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
@@ -60,10 +60,6 @@ describe('LabelsSelectRoot', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
const defaultClasses = ['labels-select-wrapper', 'gl-relative'];
@@ -145,7 +141,7 @@ describe('LabelsSelectRoot', () => {
await waitForPromises();
});
- it('creates flash with error message', () => {
+ it('creates alert with error message', () => {
expect(createAlert).toHaveBeenCalledWith({
captureError: true,
message: 'Error fetching epic color.',
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js
index 303824c77b3..914dfdbaab0 100644
--- a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js
@@ -22,10 +22,6 @@ describe('DropdownContentsColorView', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findColors = () => wrapper.findAllComponents(ColorItem);
const findColorList = () => wrapper.findComponent(GlDropdownForm);
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js
index ee4d3a2630a..c07faab20d0 100644
--- a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js
@@ -28,10 +28,6 @@ describe('DropdownContent', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findColorView = () => wrapper.findComponent(DropdownContentsColorView);
const findDropdownHeader = () => wrapper.findComponent(DropdownHeader);
const findDropdown = () => wrapper.findComponent(GlDropdown);
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js
index d203d78477f..6c8aabe1c7f 100644
--- a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js
@@ -15,10 +15,6 @@ describe('DropdownHeader', () => {
const findButton = () => wrapper.findComponent(GlButton);
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
createComponent();
});
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js
index 5bbdb136353..825f37c97e0 100644
--- a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js
@@ -22,10 +22,6 @@ describe('DropdownValue', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when there is a color set', () => {
it('renders the color', () => {
expect(findColorItems()).toHaveLength(2);
diff --git a/spec/frontend/vue_shared/components/commit_spec.js b/spec/frontend/vue_shared/components/commit_spec.js
index 1893e127f6f..62a2738d8df 100644
--- a/spec/frontend/vue_shared/components/commit_spec.js
+++ b/spec/frontend/vue_shared/components/commit_spec.js
@@ -24,10 +24,6 @@ describe('Commit component', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render a fork icon if it does not represent a tag', () => {
createComponent({
tag: false,
diff --git a/spec/frontend/vue_shared/components/confidentiality_badge_spec.js b/spec/frontend/vue_shared/components/confidentiality_badge_spec.js
index 3f7ec156c19..92cd7597637 100644
--- a/spec/frontend/vue_shared/components/confidentiality_badge_spec.js
+++ b/spec/frontend/vue_shared/components/confidentiality_badge_spec.js
@@ -1,14 +1,11 @@
import { GlBadge } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { WorkspaceType, TYPE_ISSUE, TYPE_EPIC } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_EPIC, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
-const createComponent = ({
- workspaceType = WorkspaceType.project,
- issuableType = TYPE_ISSUE,
-} = {}) =>
+const createComponent = ({ workspaceType = WORKSPACE_PROJECT, issuableType = TYPE_ISSUE } = {}) =>
shallowMount(ConfidentialityBadge, {
propsData: {
workspaceType,
@@ -23,14 +20,10 @@ describe('ConfidentialityBadge', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
- workspaceType | issuableType | expectedTooltip
- ${WorkspaceType.project} | ${TYPE_ISSUE} | ${'Only project members with at least the Reporter role, the author, and assignees can view or be notified about this issue.'}
- ${WorkspaceType.group} | ${TYPE_EPIC} | ${'Only group members with at least the Reporter role can view or be notified about this epic.'}
+ 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.'}
+ ${WORKSPACE_GROUP} | ${TYPE_EPIC} | ${'Only group members with at least the Reporter role can view or be notified about this epic.'}
`(
'should render gl-badge with correct tooltip when workspaceType is $workspaceType and issuableType is $issuableType',
({ workspaceType, issuableType, expectedTooltip }) => {
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 a660643d74f..d7f94c00d09 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
@@ -24,7 +24,7 @@ describe('Confirm Danger Modal', () => {
const findAdditionalMessage = () => wrapper.findByTestId('confirm-danger-message');
const findPrimaryAction = () => findModal().props('actionPrimary');
const findCancelAction = () => findModal().props('actionCancel');
- const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[0][attr];
+ const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[attr];
const createComponent = ({ provide = {} } = {}) =>
shallowMountExtended(ConfirmDangerModal, {
@@ -42,10 +42,6 @@ describe('Confirm Danger Modal', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the default warning message', () => {
expect(findDefaultWarning().text()).toBe(CONFIRM_DANGER_WARNING);
});
diff --git a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_spec.js b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_spec.js
index a179afccae0..379b5cde4d5 100644
--- a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_spec.js
@@ -32,10 +32,6 @@ describe('Confirm Danger Modal', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the button', () => {
expect(wrapper.html()).toContain(buttonText);
});
diff --git a/spec/frontend/vue_shared/components/confirm_fork_modal_spec.js b/spec/frontend/vue_shared/components/confirm_fork_modal_spec.js
index 1cde92cf522..fbfef5cbe46 100644
--- a/spec/frontend/vue_shared/components/confirm_fork_modal_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_fork_modal_spec.js
@@ -21,10 +21,6 @@ describe('vue_shared/components/confirm_fork_modal', () => {
},
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('visible = false', () => {
beforeEach(() => {
wrapper = createComponent();
diff --git a/spec/frontend/vue_shared/components/confirm_modal_spec.js b/spec/frontend/vue_shared/components/confirm_modal_spec.js
index c1e682a1aae..283ef52cee7 100644
--- a/spec/frontend/vue_shared/components/confirm_modal_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_modal_spec.js
@@ -47,10 +47,6 @@ describe('vue_shared/components/confirm_modal', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findModal = () => wrapper.findComponent(GlModalStub);
const findForm = () => wrapper.find('form');
const findFormData = () =>
diff --git a/spec/frontend/vue_shared/components/content_transition_spec.js b/spec/frontend/vue_shared/components/content_transition_spec.js
index 8bb6d31cce7..5f2b1f096f3 100644
--- a/spec/frontend/vue_shared/components/content_transition_spec.js
+++ b/spec/frontend/vue_shared/components/content_transition_spec.js
@@ -13,11 +13,6 @@ const TEST_SLOTS = [
describe('~/vue_shared/components/content_transition.vue', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const createComponent = (props = {}, slots = {}) => {
wrapper = shallowMount(ContentTransition, {
propsData: {
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
index c1495e8264a..a3e5f187f9b 100644
--- 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
@@ -18,10 +18,6 @@ describe('DateTimePickerInput', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders label above the input', () => {
createComponent({
label: inputLabel,
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
index aa41df438d2..5620b569409 100644
--- 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
@@ -26,10 +26,6 @@ describe('DateTimePicker', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders dropdown toggle button with selected text', async () => {
createComponent();
await nextTick();
diff --git a/spec/frontend/vue_shared/components/deployment_instance/deployment_instance_spec.js b/spec/frontend/vue_shared/components/deployment_instance/deployment_instance_spec.js
index 79001b9282f..dde2540e121 100644
--- a/spec/frontend/vue_shared/components/deployment_instance/deployment_instance_spec.js
+++ b/spec/frontend/vue_shared/components/deployment_instance/deployment_instance_spec.js
@@ -17,10 +17,6 @@ describe('Deploy Board Instance', () => {
});
describe('as a non-canary deployment', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render a div with the correct css status and tooltip data', () => {
wrapper = createComponent({
tooltipText: 'This is a pod',
@@ -43,10 +39,6 @@ describe('Deploy Board Instance', () => {
});
describe('as a canary deployment', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render a div with canary class when stable prop is provided as false', async () => {
wrapper = createComponent({
stable: false,
@@ -58,10 +50,6 @@ describe('Deploy Board Instance', () => {
});
describe('as a legend item', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should not have a tooltip', () => {
wrapper = createComponent();
diff --git a/spec/frontend/vue_shared/components/design_management/design_note_pin_spec.js b/spec/frontend/vue_shared/components/design_management/design_note_pin_spec.js
index 353d493add9..ca9c2b7d381 100644
--- a/spec/frontend/vue_shared/components/design_management/design_note_pin_spec.js
+++ b/spec/frontend/vue_shared/components/design_management/design_note_pin_spec.js
@@ -16,10 +16,6 @@ describe('Design note pin component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should match the snapshot of note without index', () => {
createComponent();
expect(wrapper.element).toMatchSnapshot();
diff --git a/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js b/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js
index 99c973bdd26..930d2fc8cfe 100644
--- a/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js
@@ -110,10 +110,6 @@ describe('Diff Stats Dropdown', () => {
createComponent({ changed, added, deleted });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it(`dropdown header should be '${expectedDropdownHeader}'`, () => {
expect(findChanged().props('text')).toBe(expectedDropdownHeader);
});
diff --git a/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js b/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js
index 6e0717c29d7..694c69fbe9f 100644
--- a/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js
+++ b/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js
@@ -18,10 +18,6 @@ describe('DiffViewer', () => {
wrapper = mount(DiffViewer, { propsData });
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders image diff', () => {
window.gon = {
relative_url_root: '',
diff --git a/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js b/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js
index 16f924b44d8..7863ef45817 100644
--- a/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js
+++ b/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js
@@ -42,10 +42,6 @@ describe('ImageDiffViewer component', () => {
triggerEvent('mouseup', doc.body);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders image diff for replaced', () => {
createComponent(allProps);
const metaInfoElements = wrapper.findAll('.image-info');
diff --git a/spec/frontend/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js b/spec/frontend/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js
index c4358f0d9cb..661db19ff0e 100644
--- a/spec/frontend/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js
+++ b/spec/frontend/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js
@@ -13,10 +13,6 @@ describe('Diff viewer mode changed component', () => {
});
});
- afterEach(() => {
- vm.destroy();
- });
-
it('renders aMode & bMode', () => {
expect(vm.text()).toContain('File mode changed from 123 to 321');
});
diff --git a/spec/frontend/vue_shared/components/dismissible_alert_spec.js b/spec/frontend/vue_shared/components/dismissible_alert_spec.js
index 8b1189f25d5..53e7d9fc7fc 100644
--- a/spec/frontend/vue_shared/components/dismissible_alert_spec.js
+++ b/spec/frontend/vue_shared/components/dismissible_alert_spec.js
@@ -16,10 +16,6 @@ describe('vue_shared/components/dismissible_alert', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findAlert = () => wrapper.findComponent(GlAlert);
describe('default', () => {
diff --git a/spec/frontend/vue_shared/components/dismissible_container_spec.js b/spec/frontend/vue_shared/components/dismissible_container_spec.js
index 7d8581e11e9..6d179434d1d 100644
--- a/spec/frontend/vue_shared/components/dismissible_container_spec.js
+++ b/spec/frontend/vue_shared/components/dismissible_container_spec.js
@@ -11,10 +11,6 @@ describe('DismissibleContainer', () => {
featureId: 'some-feature-id',
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
const findBtn = () => wrapper.find('[data-testid="close"]');
let mockAxios;
diff --git a/spec/frontend/vue_shared/components/dismissible_feedback_alert_spec.js b/spec/frontend/vue_shared/components/dismissible_feedback_alert_spec.js
index 4b32fbffebe..b184ec4ac54 100644
--- a/spec/frontend/vue_shared/components/dismissible_feedback_alert_spec.js
+++ b/spec/frontend/vue_shared/components/dismissible_feedback_alert_spec.js
@@ -23,11 +23,6 @@ describe('Dismissible Feedback Alert', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const createFullComponent = () => createComponent({ mountFn: mount });
const findAlert = () => wrapper.findComponent(GlAlert);
diff --git a/spec/frontend/vue_shared/components/dom_element_listener_spec.js b/spec/frontend/vue_shared/components/dom_element_listener_spec.js
index a848c34b7ce..d31e9b867e4 100644
--- a/spec/frontend/vue_shared/components/dom_element_listener_spec.js
+++ b/spec/frontend/vue_shared/components/dom_element_listener_spec.js
@@ -42,10 +42,6 @@ describe('~/vue_shared/components/dom_element_listener.vue', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js b/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js
index e34ed31b4bf..82130500458 100644
--- a/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js
+++ b/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js
@@ -11,10 +11,6 @@ describe('DropdownButton component', () => {
wrapper = mount(DropdownButton, { propsData: props, slots });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
describe('dropdownToggleText', () => {
it('returns default toggle text', () => {
diff --git a/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js b/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js
index dd3e55c82bb..4dfee20764c 100644
--- a/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js
+++ b/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js
@@ -31,10 +31,6 @@ describe('DropdownWidget component', () => {
},
});
- // We need to mock out `showDropdown` which
- // invokes `show` method of BDropdown used inside GlDropdown.
- // Context: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54895#note_524281679
- jest.spyOn(wrapper.vm, 'showDropdown').mockImplementation();
jest.spyOn(findDropdown().vm, 'hide').mockImplementation();
};
@@ -42,11 +38,6 @@ describe('DropdownWidget component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('passes default selectText prop to dropdown', () => {
expect(findDropdown().props('text')).toBe('Select');
});
diff --git a/spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js b/spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js
index 119d6448507..ef42c17984a 100644
--- a/spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js
+++ b/spec/frontend/vue_shared/components/dropdown_keyboard_navigation_spec.js
@@ -39,10 +39,6 @@ describe('DropdownKeyboardNavigation', () => {
},
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('onInit', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/ensure_data_spec.js b/spec/frontend/vue_shared/components/ensure_data_spec.js
index eef8b452f5f..217e795bc64 100644
--- a/spec/frontend/vue_shared/components/ensure_data_spec.js
+++ b/spec/frontend/vue_shared/components/ensure_data_spec.js
@@ -59,7 +59,6 @@ describe('EnsureData', () => {
});
afterEach(() => {
- wrapper.destroy();
Sentry.captureException.mockClear();
});
diff --git a/spec/frontend/vue_shared/components/entity_select/project_select_spec.js b/spec/frontend/vue_shared/components/entity_select/project_select_spec.js
index 57dce032d30..32ce2155494 100644
--- a/spec/frontend/vue_shared/components/entity_select/project_select_spec.js
+++ b/spec/frontend/vue_shared/components/entity_select/project_select_spec.js
@@ -63,11 +63,8 @@ describe('ProjectSelect', () => {
};
const openListbox = () => findListbox().vm.$emit('shown');
- beforeAll(() => {
- gon.api_version = apiVersion;
- });
-
beforeEach(() => {
+ gon.api_version = apiVersion;
mock = new MockAdapter(axios);
});
diff --git a/spec/frontend/vue_shared/components/expand_button_spec.js b/spec/frontend/vue_shared/components/expand_button_spec.js
index 170c947e520..ad2a57d90eb 100644
--- a/spec/frontend/vue_shared/components/expand_button_spec.js
+++ b/spec/frontend/vue_shared/components/expand_button_spec.js
@@ -27,10 +27,6 @@ describe('Expand button', () => {
});
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the prepended collapse button', () => {
expect(expanderPrependEl().isVisible()).toBe(true);
expect(expanderAppendEl().isVisible()).toBe(false);
diff --git a/spec/frontend/vue_shared/components/file_finder/item_spec.js b/spec/frontend/vue_shared/components/file_finder/item_spec.js
index f0998b1b5c6..dce6c85b5b3 100644
--- a/spec/frontend/vue_shared/components/file_finder/item_spec.js
+++ b/spec/frontend/vue_shared/components/file_finder/item_spec.js
@@ -22,10 +22,6 @@ describe('File finder item spec', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders file name & path', () => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/file_icon_spec.js b/spec/frontend/vue_shared/components/file_icon_spec.js
index 0fcc0678c13..d95773f2218 100644
--- a/spec/frontend/vue_shared/components/file_icon_spec.js
+++ b/spec/frontend/vue_shared/components/file_icon_spec.js
@@ -16,10 +16,6 @@ describe('File Icon component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render a span element and an icon', () => {
createComponent({
fileName: 'test.js',
diff --git a/spec/frontend/vue_shared/components/file_row_header_spec.js b/spec/frontend/vue_shared/components/file_row_header_spec.js
index 80f4c275dcc..885a80f73b5 100644
--- a/spec/frontend/vue_shared/components/file_row_header_spec.js
+++ b/spec/frontend/vue_shared/components/file_row_header_spec.js
@@ -1,36 +1,24 @@
import { shallowMount } from '@vue/test-utils';
+import { GlTruncate } from '@gitlab/ui';
import FileRowHeader from '~/vue_shared/components/file_row_header.vue';
describe('File row header component', () => {
- let vm;
+ let wrapper;
function createComponent(path) {
- vm = shallowMount(FileRowHeader, {
+ wrapper = shallowMount(FileRowHeader, {
propsData: {
path,
},
});
}
- afterEach(() => {
- vm.destroy();
- });
-
it('renders file path', () => {
- createComponent('app/assets');
-
- expect(vm.element).toMatchSnapshot();
- });
-
- it('trucates path after 40 characters', () => {
- createComponent('app/assets/javascripts/merge_requests');
-
- expect(vm.element).toMatchSnapshot();
- });
-
- it('adds multiple ellipsises after 40 characters', () => {
- createComponent('app/assets/javascripts/merge_requests/widget/diffs/notes');
+ const path = 'app/assets';
+ createComponent(path);
- expect(vm.element).toMatchSnapshot();
+ const truncate = wrapper.findComponent(GlTruncate);
+ expect(truncate.exists()).toBe(true);
+ expect(truncate.props('text')).toBe(path);
});
});
diff --git a/spec/frontend/vue_shared/components/file_row_spec.js b/spec/frontend/vue_shared/components/file_row_spec.js
index b70d4565f56..976866af27c 100644
--- a/spec/frontend/vue_shared/components/file_row_spec.js
+++ b/spec/frontend/vue_shared/components/file_row_spec.js
@@ -6,6 +6,9 @@ import FileIcon from '~/vue_shared/components/file_icon.vue';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileHeader from '~/vue_shared/components/file_row_header.vue';
+const scrollIntoViewMock = jest.fn();
+HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
+
describe('File row component', () => {
let wrapper;
@@ -18,10 +21,6 @@ describe('File row component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders name', () => {
const fileName = 't4';
createComponent({
@@ -72,11 +71,10 @@ describe('File row component', () => {
},
level: 0,
});
- jest.spyOn(wrapper.vm, '$emit');
wrapper.element.click();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('toggleTreeOpen', fileName);
+ expect(wrapper.emitted('toggleTreeOpen')[0][0]).toEqual(fileName);
});
it('calls scrollIntoView if made active', () => {
@@ -89,14 +87,12 @@ describe('File row component', () => {
level: 0,
});
- jest.spyOn(wrapper.vm, 'scrollIntoView');
-
wrapper.setProps({
file: { ...wrapper.props('file'), active: true },
});
return nextTick().then(() => {
- expect(wrapper.vm.scrollIntoView).toHaveBeenCalled();
+ expect(scrollIntoViewMock).toHaveBeenCalled();
});
});
diff --git a/spec/frontend/vue_shared/components/file_tree_spec.js b/spec/frontend/vue_shared/components/file_tree_spec.js
index e8818e09dc0..9d2fa369910 100644
--- a/spec/frontend/vue_shared/components/file_tree_spec.js
+++ b/spec/frontend/vue_shared/components/file_tree_spec.js
@@ -33,10 +33,6 @@ describe('File Tree component', () => {
...pick(x.attributes(), Object.keys(TEST_EXTA_ARGS)),
}));
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('file row component', () => {
beforeEach(() => {
createComponent({ file: {} });
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js
index b0e393bbf5e..123714353e2 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js
@@ -82,10 +82,6 @@ describe('FilteredSearchBarRoot', () => {
wrapper = createComponent({ sortOptions: mockSortOptions });
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('data', () => {
it('initializes `filterValue`, `selectedSortOption` and `selectedSortDirection` data props and displays the sort dropdown', () => {
expect(wrapper.vm.filterValue).toEqual([]);
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js
index 63c22aff3d5..dd0ec65c871 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js
@@ -3,7 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import { mockBranches } from 'jest/vue_shared/components/filtered_search_bar/mock_data';
import Api from '~/api';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { HTTP_STATUS_OK, HTTP_STATUS_SERVICE_UNAVAILABLE } from '~/lib/utils/http_status';
import * as actions from '~/vue_shared/components/filtered_search_bar/store/modules/filters/actions';
import * as types from '~/vue_shared/components/filtered_search_bar/store/modules/filters/mutation_types';
@@ -15,7 +15,7 @@ const labelsEndpoint = 'fake_labels_endpoint';
const groupEndpoint = 'fake_group_endpoint';
const projectEndpoint = 'fake_project_endpoint';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Filters actions', () => {
let state;
@@ -165,16 +165,10 @@ describe('Filters actions', () => {
});
describe('fetchAuthors', () => {
- let restoreVersion;
beforeEach(() => {
- restoreVersion = gon.api_version;
gon.api_version = 'v1';
});
- afterEach(() => {
- gon.api_version = restoreVersion;
- });
-
describe('success', () => {
beforeEach(() => {
mock.onAny().replyOnce(HTTP_STATUS_OK, filterUsers);
@@ -305,17 +299,11 @@ describe('Filters actions', () => {
describe('fetchAssignees', () => {
describe('success', () => {
- let restoreVersion;
beforeEach(() => {
mock.onAny().replyOnce(HTTP_STATUS_OK, filterUsers);
- restoreVersion = gon.api_version;
gon.api_version = 'v1';
});
- afterEach(() => {
- gon.api_version = restoreVersion;
- });
-
it('dispatches RECEIVE_ASSIGNEES_SUCCESS with received data and groupEndpoint set', () => {
return testAction(
actions.fetchAssignees,
@@ -350,17 +338,11 @@ describe('Filters actions', () => {
});
describe('error', () => {
- let restoreVersion;
beforeEach(() => {
mock.onAny().replyOnce(HTTP_STATUS_SERVICE_UNAVAILABLE);
- restoreVersion = gon.api_version;
gon.api_version = 'v1';
});
- afterEach(() => {
- gon.api_version = restoreVersion;
- });
-
it('dispatches RECEIVE_ASSIGNEES_ERROR and groupEndpoint set', () => {
return testAction(
actions.fetchAssignees,
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
index 164235e4bb9..9941abbfaea 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
@@ -120,10 +120,6 @@ describe('BaseToken', () => {
const getMockSuggestionListSuggestions = () =>
JSON.parse(findMockSuggestionList().attributes('data-suggestions'));
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('data', () => {
it('calls `getRecentlyUsedSuggestions` to populate `recentSuggestions` when `recentSuggestionsStorageKey` is defined', () => {
wrapper = createComponent();
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
index 311d5a13280..a6bb32736db 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
@@ -9,14 +9,15 @@ import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { OPTIONS_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
import BranchToken from '~/vue_shared/components/filtered_search_bar/tokens/branch_token.vue';
+import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { mockBranches, mockBranchToken } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const defaultStubs = {
Portal: true,
GlFilteredSearchSuggestionList: {
@@ -54,58 +55,83 @@ describe('BranchToken', () => {
let mock;
let wrapper;
+ const findBaseToken = () => wrapper.findComponent(BaseToken);
+ const triggerFetchBranches = (searchTerm = null) => {
+ findBaseToken().vm.$emit('fetch-suggestions', searchTerm);
+ return waitForPromises();
+ };
+
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('methods', () => {
- beforeEach(() => {
- wrapper = createComponent();
- });
-
describe('fetchBranches', () => {
- it('calls `config.fetchBranches` with provided searchTerm param', () => {
- jest.spyOn(wrapper.vm.config, 'fetchBranches');
-
- wrapper.vm.fetchBranches('foo');
+ it('sets loading state', async () => {
+ wrapper = createComponent({
+ config: {
+ fetchBranches: jest.fn().mockResolvedValue(new Promise(() => {})),
+ },
+ });
+ await nextTick();
- expect(wrapper.vm.config.fetchBranches).toHaveBeenCalledWith('foo');
+ expect(findBaseToken().props('suggestionsLoading')).toBe(true);
});
- it('sets response to `branches` when request is succesful', () => {
- jest.spyOn(wrapper.vm.config, 'fetchBranches').mockResolvedValue({ data: mockBranches });
+ describe('when request is successful', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ config: {
+ fetchBranches: jest.fn().mockResolvedValue({ data: mockBranches }),
+ },
+ });
+ });
+
+ it('calls `config.fetchBranches` with provided searchTerm param', async () => {
+ const searchTerm = 'foo';
+ await triggerFetchBranches(searchTerm);
- wrapper.vm.fetchBranches('foo');
+ expect(findBaseToken().props('config').fetchBranches).toHaveBeenCalledWith(searchTerm);
+ });
+
+ it('sets response to `branches`', async () => {
+ await triggerFetchBranches();
- return waitForPromises().then(() => {
- expect(wrapper.vm.branches).toEqual(mockBranches);
+ expect(findBaseToken().props('suggestions')).toEqual(mockBranches);
+ });
+
+ it('sets `loading` to false when request completes', async () => {
+ await triggerFetchBranches();
+
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
- it('calls `createAlert` with flash error message when request fails', () => {
- jest.spyOn(wrapper.vm.config, 'fetchBranches').mockRejectedValue({});
+ describe('when request fails', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ config: {
+ fetchBranches: jest.fn().mockRejectedValue({}),
+ },
+ });
+ });
- wrapper.vm.fetchBranches('foo');
+ it('calls `createAlert` with alert error message when request fails', async () => {
+ await triggerFetchBranches();
- return waitForPromises().then(() => {
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching branches.',
});
});
- });
-
- it('sets `loading` to false when request completes', () => {
- jest.spyOn(wrapper.vm.config, 'fetchBranches').mockRejectedValue({});
- wrapper.vm.fetchBranches('foo');
+ it('sets `loading` to false when request completes', async () => {
+ await triggerFetchBranches();
- return waitForPromises().then(() => {
- expect(wrapper.vm.loading).toBe(false);
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
});
@@ -120,16 +146,13 @@ describe('BranchToken', () => {
await nextTick();
}
- beforeEach(async () => {
- wrapper = createComponent({ value: { data: mockBranches[0].name } });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- branches: mockBranches,
+ beforeEach(() => {
+ wrapper = createComponent({
+ value: { data: mockBranches[0].name },
+ config: {
+ initialBranches: mockBranches,
+ },
});
-
- await nextTick();
});
it('renders gl-filtered-search-token component', () => {
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_contact_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_contact_token_spec.js
index 7be7035a0f2..ce134f7d24e 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_contact_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_contact_token_spec.js
@@ -8,7 +8,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { OPTIONS_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
@@ -22,7 +22,7 @@ import {
mockProjectCrmContactsQueryResponse,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const defaultStubs = {
Portal: true,
@@ -79,7 +79,6 @@ describe('CrmContactToken', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -159,7 +158,7 @@ describe('CrmContactToken', () => {
});
});
- it('calls `createAlert` with flash error message when request fails', async () => {
+ it('calls `createAlert` with alert error message when request fails', async () => {
mountComponent();
jest.spyOn(wrapper.vm.$apollo, 'query').mockRejectedValue({});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_organization_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_organization_token_spec.js
index ecd3e8a04f1..8526631c63d 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_organization_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/crm_organization_token_spec.js
@@ -8,7 +8,7 @@ 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 '~/flash';
+import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { OPTIONS_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
@@ -22,7 +22,7 @@ import {
mockProjectCrmOrganizationsQueryResponse,
} from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const defaultStubs = {
Portal: true,
@@ -78,7 +78,6 @@ describe('CrmOrganizationToken', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -158,7 +157,7 @@ describe('CrmOrganizationToken', () => {
});
});
- it('calls `createAlert` with flash error message when request fails', async () => {
+ it('calls `createAlert` with alert error message when request fails', async () => {
mountComponent();
jest.spyOn(wrapper.vm.$apollo, 'query').mockRejectedValue({});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js
index 773df01ada7..4e00b6837a3 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js
@@ -8,7 +8,7 @@ import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import {
@@ -17,10 +17,11 @@ import {
OPTIONS_NONE_ANY,
} from '~/vue_shared/components/filtered_search_bar/constants';
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
+import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { mockReactionEmojiToken, mockEmojis } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const GlEmoji = { template: '<img/>' };
const defaultStubs = {
Portal: true,
@@ -60,58 +61,72 @@ describe('EmojiToken', () => {
let mock;
let wrapper;
+ const findBaseToken = () => wrapper.findComponent(BaseToken);
+ const triggerFetchEmojis = (searchTerm = null) => {
+ findBaseToken().vm.$emit('fetch-suggestions', searchTerm);
+ return waitForPromises();
+ };
+
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('methods', () => {
- beforeEach(() => {
- wrapper = createComponent();
- });
-
describe('fetchEmojis', () => {
- it('calls `config.fetchEmojis` with provided searchTerm param', () => {
- jest.spyOn(wrapper.vm.config, 'fetchEmojis');
-
- wrapper.vm.fetchEmojis('foo');
+ it('sets loading state', async () => {
+ wrapper = createComponent({
+ config: {
+ fetchEmojis: jest.fn().mockResolvedValue(new Promise(() => {})),
+ },
+ });
+ await nextTick();
- expect(wrapper.vm.config.fetchEmojis).toHaveBeenCalledWith('foo');
+ expect(findBaseToken().props('suggestionsLoading')).toBe(true);
});
- it('sets response to `emojis` when request is successful', () => {
- jest.spyOn(wrapper.vm.config, 'fetchEmojis').mockResolvedValue(mockEmojis);
+ describe('when request is successful', () => {
+ const searchTerm = 'foo';
- wrapper.vm.fetchEmojis('foo');
+ beforeEach(async () => {
+ wrapper = createComponent({
+ config: {
+ fetchEmojis: jest.fn().mockResolvedValue({ data: mockEmojis }),
+ },
+ });
+ return triggerFetchEmojis(searchTerm);
+ });
- return waitForPromises().then(() => {
- expect(wrapper.vm.emojis).toEqual(mockEmojis);
+ it('calls `config.fetchEmojis` with provided searchTerm param', () => {
+ expect(findBaseToken().props('config').fetchEmojis).toHaveBeenCalledWith(searchTerm);
});
- });
- it('calls `createAlert` with flash error message when request fails', () => {
- jest.spyOn(wrapper.vm.config, 'fetchEmojis').mockRejectedValue({});
+ it('sets response to `emojis`', () => {
+ expect(findBaseToken().props('suggestions')).toEqual(mockEmojis);
+ });
+ });
- wrapper.vm.fetchEmojis('foo');
+ describe('when request fails', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ config: {
+ fetchEmojis: jest.fn().mockRejectedValue({}),
+ },
+ });
+ return triggerFetchEmojis();
+ });
- return waitForPromises().then(() => {
+ it('calls `createAlert` with alert error message', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching emojis.',
});
});
- });
-
- it('sets `loading` to false when request completes', () => {
- jest.spyOn(wrapper.vm.config, 'fetchEmojis').mockRejectedValue({});
-
- wrapper.vm.fetchEmojis('foo');
- return waitForPromises().then(() => {
- expect(wrapper.vm.loading).toBe(false);
+ it('sets `loading` to false when request completes', () => {
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
});
@@ -123,15 +138,10 @@ describe('EmojiToken', () => {
beforeEach(async () => {
wrapper = createComponent({
value: { data: `"${mockEmojis[0].name}"` },
+ config: {
+ initialEmojis: mockEmojis,
+ },
});
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- emojis: mockEmojis,
- });
-
- await nextTick();
});
it('renders gl-filtered-search-token component', () => {
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js
index 9d96123c17f..b9275409125 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js
@@ -11,7 +11,7 @@ import {
mockRegularLabel,
mockLabels,
} from 'jest/sidebar/components/labels/labels_select_vue/mock_data';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { OPTIONS_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
@@ -20,7 +20,7 @@ import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label
import { mockLabelToken } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const defaultStubs = {
Portal: true,
BaseToken,
@@ -60,103 +60,125 @@ function createComponent(options = {}) {
describe('LabelToken', () => {
let mock;
let wrapper;
+ const defaultLabels = OPTIONS_NONE_ANY;
beforeEach(() => {
mock = new MockAdapter(axios);
});
+ const findBaseToken = () => wrapper.findComponent(BaseToken);
+ const findSuggestions = () => wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const findTokenSegments = () => wrapper.findAllComponents(GlFilteredSearchTokenSegment);
+ const triggerFetchLabels = (searchTerm = null) => {
+ findBaseToken().vm.$emit('fetch-suggestions', searchTerm);
+ return waitForPromises();
+ };
+
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('methods', () => {
- beforeEach(() => {
- wrapper = createComponent();
- });
-
describe('getActiveLabel', () => {
it('returns label object from labels array based on provided `currentValue` param', () => {
- expect(wrapper.vm.getActiveLabel(mockLabels, 'Foo Label')).toEqual(mockRegularLabel);
+ wrapper = createComponent();
+
+ expect(findBaseToken().props('getActiveTokenValue')(mockLabels, 'Foo Label')).toEqual(
+ mockRegularLabel,
+ );
});
});
describe('getLabelName', () => {
- it('returns value of `name` or `title` property present in provided label param', () => {
- let mockLabel = {
- title: 'foo',
- };
+ it('returns value of `name` or `title` property present in provided label param', async () => {
+ const customMockLabels = [
+ { title: 'Title with no name label' },
+ { name: 'Name Label', title: 'Title with name label' },
+ ];
+
+ wrapper = createComponent({
+ active: true,
+ config: {
+ ...mockLabelToken,
+ fetchLabels: jest.fn().mockResolvedValue({ data: customMockLabels }),
+ },
+ stubs: { Portal: true },
+ });
- expect(wrapper.vm.getLabelName(mockLabel)).toBe(mockLabel.title);
+ await waitForPromises();
- mockLabel = {
- name: 'foo',
- };
+ const suggestions = findSuggestions();
+ const indexWithTitle = defaultLabels.length;
+ const indexWithName = defaultLabels.length + 1;
- expect(wrapper.vm.getLabelName(mockLabel)).toBe(mockLabel.name);
+ expect(suggestions.at(indexWithTitle).text()).toBe(customMockLabels[0].title);
+ expect(suggestions.at(indexWithName).text()).toBe(customMockLabels[1].name);
});
});
describe('fetchLabels', () => {
- it('calls `config.fetchLabels` with provided searchTerm param', () => {
- jest.spyOn(wrapper.vm.config, 'fetchLabels');
-
- wrapper.vm.fetchLabels('foo');
-
- expect(wrapper.vm.config.fetchLabels).toHaveBeenCalledWith('foo');
- });
+ describe('when request is successful', () => {
+ const searchTerm = 'foo';
+
+ beforeEach(async () => {
+ wrapper = createComponent({
+ config: {
+ fetchLabels: jest.fn().mockResolvedValue({ data: mockLabels }),
+ },
+ });
+ await triggerFetchLabels(searchTerm);
+ });
- it('sets response to `labels` when request is succesful', () => {
- jest.spyOn(wrapper.vm.config, 'fetchLabels').mockResolvedValue(mockLabels);
+ it('calls `config.fetchLabels` with provided searchTerm param', () => {
+ expect(findBaseToken().props('config').fetchLabels).toHaveBeenCalledWith(searchTerm);
+ });
- wrapper.vm.fetchLabels('foo');
+ it('sets response to `labels`', () => {
+ expect(findBaseToken().props('suggestions')).toEqual(mockLabels);
+ });
- return waitForPromises().then(() => {
- expect(wrapper.vm.labels).toEqual(mockLabels);
+ it('sets `loading` to false when request completes', () => {
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
- it('calls `createAlert` with flash error message when request fails', () => {
- jest.spyOn(wrapper.vm.config, 'fetchLabels').mockRejectedValue({});
-
- wrapper.vm.fetchLabels('foo');
+ describe('when request fails', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({
+ config: {
+ fetchLabels: jest.fn().mockRejectedValue({}),
+ },
+ });
+ await triggerFetchLabels();
+ });
- return waitForPromises().then(() => {
+ it('calls `createAlert` with alert error message', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching labels.',
});
});
- });
-
- it('sets `loading` to false when request completes', () => {
- jest.spyOn(wrapper.vm.config, 'fetchLabels').mockRejectedValue({});
-
- wrapper.vm.fetchLabels('foo');
- return waitForPromises().then(() => {
- expect(wrapper.vm.loading).toBe(false);
+ it('sets `loading` to false when request completes', () => {
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
});
});
describe('template', () => {
- const defaultLabels = OPTIONS_NONE_ANY;
-
beforeEach(async () => {
- wrapper = createComponent({ value: { data: `"${mockRegularLabel.title}"` } });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- labels: mockLabels,
+ wrapper = createComponent({
+ value: { data: `"${mockRegularLabel.title}"` },
+ config: {
+ initialLabels: mockLabels,
+ },
});
await nextTick();
});
it('renders base-token component', () => {
- const baseTokenEl = wrapper.findComponent(BaseToken);
+ const baseTokenEl = findBaseToken();
expect(baseTokenEl.exists()).toBe(true);
expect(baseTokenEl.props()).toMatchObject({
@@ -166,7 +188,7 @@ describe('LabelToken', () => {
});
it('renders token item when value is selected', () => {
- const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
+ const tokenSegments = findTokenSegments();
expect(tokenSegments).toHaveLength(3); // Label, =, "Foo Label"
expect(tokenSegments.at(2).text()).toBe(`~${mockRegularLabel.title}`); // "Foo Label"
@@ -181,12 +203,12 @@ describe('LabelToken', () => {
config: { ...mockLabelToken, defaultLabels },
stubs: { Portal: true },
});
- const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
+ const tokenSegments = findTokenSegments();
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
await nextTick();
- const suggestions = wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const suggestions = findSuggestions();
expect(suggestions).toHaveLength(defaultLabels.length);
defaultLabels.forEach((label, index) => {
@@ -200,7 +222,7 @@ describe('LabelToken', () => {
config: { ...mockLabelToken, defaultLabels: [] },
stubs: { Portal: true },
});
- const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
+ const tokenSegments = findTokenSegments();
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
await nextTick();
@@ -215,11 +237,10 @@ describe('LabelToken', () => {
config: { ...mockLabelToken },
stubs: { Portal: true },
});
- const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
+ const tokenSegments = findTokenSegments();
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
-
- const suggestions = wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const suggestions = findSuggestions();
expect(suggestions).toHaveLength(OPTIONS_NONE_ANY.length);
OPTIONS_NONE_ANY.forEach((label, index) => {
@@ -234,7 +255,7 @@ describe('LabelToken', () => {
input: mockInput,
},
});
- wrapper.findComponent(BaseToken).vm.$emit('input', [{ data: 'mockData', operator: '=' }]);
+ findBaseToken().vm.$emit('input', [{ data: 'mockData', operator: '=' }]);
expect(mockInput).toHaveBeenLastCalledWith([{ data: 'mockData', operator: '=' }]);
});
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 589697fe542..fea1496a80b 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
@@ -8,16 +8,17 @@ import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { sortMilestonesByDueDate } from '~/milestones/utils';
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';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/milestones/utils');
const defaultStubs = {
@@ -57,6 +58,12 @@ describe('MilestoneToken', () => {
let mock;
let wrapper;
+ const findBaseToken = () => wrapper.findComponent(BaseToken);
+ const triggerFetchMilestones = (searchTerm = null) => {
+ findBaseToken().vm.$emit('fetch-suggestions', searchTerm);
+ return waitForPromises();
+ };
+
beforeEach(() => {
mock = new MockAdapter(axios);
wrapper = createComponent();
@@ -64,73 +71,77 @@ describe('MilestoneToken', () => {
afterEach(() => {
mock.restore();
- wrapper.destroy();
});
describe('methods', () => {
describe('fetchMilestones', () => {
- describe('when config.shouldSkipSort is true', () => {
- beforeEach(() => {
- wrapper.vm.config.shouldSkipSort = true;
+ it('sets loading state', async () => {
+ wrapper = createComponent({
+ config: {
+ fetchMilestones: jest.fn().mockResolvedValue(new Promise(() => {})),
+ },
});
+ await nextTick();
- afterEach(() => {
- wrapper.vm.config.shouldSkipSort = false;
- });
+ expect(findBaseToken().props('suggestionsLoading')).toBe(true);
+ });
+
+ describe('when config.shouldSkipSort is true', () => {
it('does not call sortMilestonesByDueDate', async () => {
- jest.spyOn(wrapper.vm.config, 'fetchMilestones').mockResolvedValue({
- data: mockMilestones,
+ wrapper = createComponent({
+ config: {
+ shouldSkipSort: true,
+ fetchMilestones: jest.fn().mockResolvedValue({ data: mockMilestones }),
+ },
});
- wrapper.vm.fetchMilestones();
-
- await waitForPromises();
+ await triggerFetchMilestones();
expect(sortMilestonesByDueDate).toHaveBeenCalledTimes(0);
});
});
- it('calls `config.fetchMilestones` with provided searchTerm param', () => {
- jest.spyOn(wrapper.vm.config, 'fetchMilestones');
-
- wrapper.vm.fetchMilestones('foo');
+ describe('when request is successful', () => {
+ const searchTerm = 'foo';
- expect(wrapper.vm.config.fetchMilestones).toHaveBeenCalledWith('foo');
- });
-
- it('sets response to `milestones` when request is successful', () => {
- wrapper.vm.config.shouldSkipSort = false;
+ beforeEach(() => {
+ wrapper = createComponent({
+ config: {
+ shouldSkipSort: false,
+ fetchMilestones: jest.fn().mockResolvedValue({ data: mockMilestones }),
+ },
+ });
+ return triggerFetchMilestones(searchTerm);
+ });
- jest.spyOn(wrapper.vm.config, 'fetchMilestones').mockResolvedValue({
- data: mockMilestones,
+ it('calls `config.fetchMilestones` with provided searchTerm param', () => {
+ expect(findBaseToken().props('config').fetchMilestones).toHaveBeenCalledWith(searchTerm);
});
- wrapper.vm.fetchMilestones();
- return waitForPromises().then(() => {
- expect(wrapper.vm.milestones).toEqual(mockMilestones);
+ it('sets response to `milestones`', () => {
expect(sortMilestonesByDueDate).toHaveBeenCalled();
+ expect(findBaseToken().props('suggestions')).toEqual(mockMilestones);
});
});
- it('calls `createAlert` with flash error message when request fails', () => {
- jest.spyOn(wrapper.vm.config, 'fetchMilestones').mockRejectedValue({});
-
- wrapper.vm.fetchMilestones('foo');
+ describe('when request fails', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ config: {
+ fetchMilestones: jest.fn().mockRejectedValue({}),
+ },
+ });
+ return triggerFetchMilestones();
+ });
- return waitForPromises().then(() => {
+ it('calls `createAlert` with alert error message', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching milestones.',
});
});
- });
- it('sets `loading` to false when request completes', () => {
- jest.spyOn(wrapper.vm.config, 'fetchMilestones').mockRejectedValue({});
-
- wrapper.vm.fetchMilestones('foo');
-
- return waitForPromises().then(() => {
- expect(wrapper.vm.loading).toBe(false);
+ it('sets `loading` to false when request completes', () => {
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
});
});
});
@@ -143,15 +154,12 @@ describe('MilestoneToken', () => {
];
beforeEach(async () => {
- wrapper = createComponent({ value: { data: `"${mockRegularMilestone.title}"` } });
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- milestones: mockMilestones,
+ wrapper = createComponent({
+ value: { data: `"${mockRegularMilestone.title}"` },
+ config: {
+ initialMilestones: mockMilestones,
+ },
});
-
- await nextTick();
});
it('renders gl-filtered-search-token component', () => {
@@ -228,7 +236,7 @@ describe('MilestoneToken', () => {
it('finds the correct value from the activeToken', () => {
DEFAULT_MILESTONES.forEach(({ value, title }) => {
- const activeToken = wrapper.vm.getActiveMilestone([], value);
+ const activeToken = findBaseToken().props('getActiveTokenValue')([], value);
expect(activeToken.title).toEqual(title);
});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js
index 0e5fa0f66d4..5190ab919b1 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js
@@ -2,11 +2,11 @@ import { GlFilteredSearchToken, GlFilteredSearchTokenSegment } from '@gitlab/ui'
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import ReleaseToken from '~/vue_shared/components/filtered_search_bar/tokens/release_token.vue';
import { mockReleaseToken } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('ReleaseToken', () => {
const id = '123';
@@ -27,10 +27,6 @@ describe('ReleaseToken', () => {
},
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders release value', async () => {
wrapper = createComponent({ value: { data: id } });
await nextTick();
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js
index 32cb74d5f80..89003296854 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/user_token_spec.js
@@ -8,7 +8,7 @@ import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { OPTIONS_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
@@ -17,7 +17,7 @@ import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_t
import { mockAuthorToken, mockUsers } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const defaultStubs = {
Portal: true,
GlFilteredSearchSuggestionList: {
@@ -67,99 +67,82 @@ function createComponent(options = {}) {
}
describe('UserToken', () => {
- const originalGon = window.gon;
const currentUserLength = 1;
let mock;
let wrapper;
- const getBaseToken = () => wrapper.findComponent(BaseToken);
+ const findBaseToken = () => wrapper.findComponent(BaseToken);
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
- window.gon = originalGon;
mock.restore();
- wrapper.destroy();
});
describe('methods', () => {
describe('fetchUsers', () => {
+ const triggerFetchUsers = (searchTerm = null) => {
+ findBaseToken().vm.$emit('fetch-suggestions', searchTerm);
+ return waitForPromises();
+ };
+
beforeEach(() => {
wrapper = createComponent();
});
- it('calls `config.fetchUsers` with provided searchTerm param', () => {
- jest.spyOn(wrapper.vm.config, 'fetchUsers');
-
- getBaseToken().vm.$emit('fetch-suggestions', mockUsers[0].username);
-
- expect(wrapper.vm.config.fetchUsers).toHaveBeenCalledWith(
- mockAuthorToken.fetchPath,
- mockUsers[0].username,
- );
- });
-
- it('sets response to `users` when request is successful', () => {
- jest.spyOn(wrapper.vm.config, 'fetchUsers').mockResolvedValue(mockUsers);
-
- getBaseToken().vm.$emit('fetch-suggestions', 'root');
-
- return waitForPromises().then(() => {
- expect(getBaseToken().props('suggestions')).toEqual(mockUsers);
+ it('sets loading state', async () => {
+ wrapper = createComponent({
+ config: {
+ fetchUsers: jest.fn().mockResolvedValue(new Promise(() => {})),
+ },
});
+ await nextTick();
+
+ expect(findBaseToken().props('suggestionsLoading')).toBe(true);
});
- // TODO: rm when completed https://gitlab.com/gitlab-org/gitlab/-/issues/345756
- describe('when there are null users presents', () => {
- const mockUsersWithNullUser = mockUsers.concat([null]);
+ describe('when request is successful', () => {
+ const searchTerm = 'foo';
beforeEach(() => {
- jest
- .spyOn(wrapper.vm.config, 'fetchUsers')
- .mockResolvedValue({ data: mockUsersWithNullUser });
-
- getBaseToken().vm.$emit('fetch-suggestions', 'root');
+ wrapper = createComponent({
+ config: {
+ fetchUsers: jest.fn().mockResolvedValue({ data: mockUsers }),
+ },
+ });
+ return triggerFetchUsers(searchTerm);
});
- describe('when res.data is present', () => {
- it('filters the successful response when null values are present', () => {
- return waitForPromises().then(() => {
- expect(getBaseToken().props('suggestions')).toEqual(mockUsers);
- });
- });
+ it('calls `config.fetchUsers` with provided searchTerm param', () => {
+ expect(findBaseToken().props('config').fetchUsers).toHaveBeenCalledWith(searchTerm);
});
- describe('when response is an array', () => {
- it('filters the successful response when null values are present', () => {
- return waitForPromises().then(() => {
- expect(getBaseToken().props('suggestions')).toEqual(mockUsers);
- });
- });
+ it('sets response to `users` when request is successful', () => {
+ expect(findBaseToken().props('suggestions')).toEqual(mockUsers);
});
});
- it('calls `createAlert` with flash error message when request fails', () => {
- jest.spyOn(wrapper.vm.config, 'fetchUsers').mockRejectedValue({});
-
- getBaseToken().vm.$emit('fetch-suggestions', 'root');
+ describe('when request fails', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ config: {
+ fetchUsers: jest.fn().mockRejectedValue({}),
+ },
+ });
+ return triggerFetchUsers();
+ });
- return waitForPromises().then(() => {
+ it('calls `createAlert` with alert error message', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching users.',
});
});
- });
-
- it('sets `loading` to false when request completes', async () => {
- jest.spyOn(wrapper.vm.config, 'fetchUsers').mockRejectedValue({});
-
- getBaseToken().vm.$emit('fetch-suggestions', 'root');
- await waitForPromises();
-
- expect(getBaseToken().props('suggestionsLoading')).toBe(false);
+ it('sets `loading` to false when request completes', async () => {
+ expect(findBaseToken().props('suggestionsLoading')).toBe(false);
+ });
});
});
});
@@ -178,12 +161,12 @@ describe('UserToken', () => {
data: { users: mockUsers },
});
- const baseTokenEl = getBaseToken();
+ const baseTokenEl = findBaseToken();
expect(baseTokenEl.exists()).toBe(true);
expect(baseTokenEl.props()).toMatchObject({
suggestions: mockUsers,
- getActiveTokenValue: wrapper.vm.getActiveUser,
+ getActiveTokenValue: baseTokenEl.props('getActiveTokenValue'),
});
});
@@ -191,7 +174,6 @@ describe('UserToken', () => {
wrapper = createComponent({
value: { data: mockUsers[0].username },
data: { users: mockUsers },
- stubs: { Portal: true },
});
await nextTick();
@@ -215,30 +197,13 @@ describe('UserToken', () => {
users: [
{
...mockUsers[0],
+ avatarUrl: mockUsers[0].avatar_url,
+ avatar_url: undefined,
},
],
},
- stubs: { Portal: true },
});
- await nextTick();
-
- expect(getAvatarEl().props('src')).toBe(mockUsers[0].avatar_url);
-
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- users: [
- {
- ...mockUsers[0],
- avatarUrl: mockUsers[0].avatar_url,
- avatar_url: undefined,
- },
- ],
- });
-
- await nextTick();
-
expect(getAvatarEl().props('src')).toBe(mockUsers[0].avatar_url);
});
@@ -264,7 +229,6 @@ describe('UserToken', () => {
wrapper = createComponent({
active: true,
config: { ...mockAuthorToken, defaultUsers: [] },
- stubs: { Portal: true },
});
const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
const suggestionsSegment = tokenSegments.at(2);
diff --git a/spec/frontend/vue_shared/components/form/form_footer_actions_spec.js b/spec/frontend/vue_shared/components/form/form_footer_actions_spec.js
index 361b162b6a0..eee8a0c4532 100644
--- a/spec/frontend/vue_shared/components/form/form_footer_actions_spec.js
+++ b/spec/frontend/vue_shared/components/form/form_footer_actions_spec.js
@@ -10,10 +10,6 @@ describe('Form Footer Actions', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders content properly', () => {
const defaultSlot = 'Foo';
const prepend = 'Bar';
diff --git a/spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js b/spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js
index e1da8b690af..4f1603f93ba 100644
--- a/spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js
+++ b/spec/frontend/vue_shared/components/form/input_copy_toggle_visibility_spec.js
@@ -10,10 +10,6 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
describe('InputCopyToggleVisibility', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
const valueProp = 'hR8x1fuJbzwu5uFKLf9e';
const createComponent = (options = {}) => {
@@ -21,7 +17,7 @@ describe('InputCopyToggleVisibility', () => {
InputCopyToggleVisibility,
merge({}, options, {
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
}),
);
diff --git a/spec/frontend/vue_shared/components/form/title_spec.js b/spec/frontend/vue_shared/components/form/title_spec.js
index 452f3723e76..d499f847c72 100644
--- a/spec/frontend/vue_shared/components/form/title_spec.js
+++ b/spec/frontend/vue_shared/components/form/title_spec.js
@@ -12,10 +12,6 @@ describe('Title edit field', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/vue_shared/components/gl_countdown_spec.js b/spec/frontend/vue_shared/components/gl_countdown_spec.js
index af53d256236..1de206123fe 100644
--- a/spec/frontend/vue_shared/components/gl_countdown_spec.js
+++ b/spec/frontend/vue_shared/components/gl_countdown_spec.js
@@ -10,10 +10,6 @@ describe('GlCountdown', () => {
jest.spyOn(Date, 'now').mockImplementation(() => new Date(now).getTime());
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when there is time remaining', () => {
beforeEach(async () => {
wrapper = mount(GlCountdown, {
diff --git a/spec/frontend/vue_shared/components/header_ci_component_spec.js b/spec/frontend/vue_shared/components/header_ci_component_spec.js
index 458f2cc5374..da9bc0f8a2f 100644
--- a/spec/frontend/vue_shared/components/header_ci_component_spec.js
+++ b/spec/frontend/vue_shared/components/header_ci_component_spec.js
@@ -48,11 +48,6 @@ describe('Header CI Component', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('render', () => {
beforeEach(() => {
createComponent({ itemName: 'Pipeline' });
diff --git a/spec/frontend/vue_shared/components/help_popover_spec.js b/spec/frontend/vue_shared/components/help_popover_spec.js
index 77c03dc0c3c..76e66d07fa0 100644
--- a/spec/frontend/vue_shared/components/help_popover_spec.js
+++ b/spec/frontend/vue_shared/components/help_popover_spec.js
@@ -23,10 +23,6 @@ describe('HelpPopover', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('with title and content', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/integration_help_text_spec.js b/spec/frontend/vue_shared/components/integration_help_text_spec.js
index c63e46313b3..dd20b09f176 100644
--- a/spec/frontend/vue_shared/components/integration_help_text_spec.js
+++ b/spec/frontend/vue_shared/components/integration_help_text_spec.js
@@ -22,11 +22,6 @@ describe('IntegrationHelpText component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should use the gl components', () => {
wrapper = createComponent();
diff --git a/spec/frontend/vue_shared/components/keep_alive_slots_spec.js b/spec/frontend/vue_shared/components/keep_alive_slots_spec.js
index 10c6cbe6d94..f69a883ee4d 100644
--- a/spec/frontend/vue_shared/components/keep_alive_slots_spec.js
+++ b/spec/frontend/vue_shared/components/keep_alive_slots_spec.js
@@ -37,10 +37,6 @@ describe('~/vue_shared/components/keep_alive_slots.vue', () => {
isVisible: x.isVisible(),
}));
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/listbox_input/listbox_input_spec.js b/spec/frontend/vue_shared/components/listbox_input/listbox_input_spec.js
index 7ed6a59c844..4e83f3e1c06 100644
--- a/spec/frontend/vue_shared/components/listbox_input/listbox_input_spec.js
+++ b/spec/frontend/vue_shared/components/listbox_input/listbox_input_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlFormGroup, GlListbox } from '@gitlab/ui';
+import { GlFormGroup, GlCollapsibleListbox } from '@gitlab/ui';
import ListboxInput from '~/vue_shared/components/listbox_input/listbox_input.vue';
describe('ListboxInput', () => {
@@ -27,7 +27,7 @@ describe('ListboxInput', () => {
// Finders
const findGlFormGroup = () => wrapper.findComponent(GlFormGroup);
- const findGlListbox = () => wrapper.findComponent(GlListbox);
+ const findGlListbox = () => wrapper.findComponent(GlCollapsibleListbox);
const findInput = () => wrapper.find('input');
const createComponent = (propsData) => {
@@ -153,7 +153,7 @@ describe('ListboxInput', () => {
expect(findGlListbox().props('searchable')).toBe(true);
});
- it('passes all items to GlListbox by default', () => {
+ it('passes all items to GlCollapsibleListbox by default', () => {
createComponent();
expect(findGlListbox().props('items')).toStrictEqual(items);
diff --git a/spec/frontend/vue_shared/components/local_storage_sync_spec.js b/spec/frontend/vue_shared/components/local_storage_sync_spec.js
index a80717a1aea..1c7f419b118 100644
--- a/spec/frontend/vue_shared/components/local_storage_sync_spec.js
+++ b/spec/frontend/vue_shared/components/local_storage_sync_spec.js
@@ -17,7 +17,6 @@ describe('Local Storage Sync', () => {
const getStorageValue = (value) => localStorage.getItem(STORAGE_KEY, value);
afterEach(() => {
- wrapper.destroy();
localStorage.clear();
});
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 ecb2b37c3a5..8aab867f32a 100644
--- a/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js
@@ -17,11 +17,6 @@ describe('Apply Suggestion component', () => {
beforeEach(() => createWrapper());
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('initial template', () => {
it('renders a dropdown with the correct props', () => {
const dropdown = findDropdown();
diff --git a/spec/frontend/vue_shared/components/markdown/drawio_toolbar_button_spec.js b/spec/frontend/vue_shared/components/markdown/drawio_toolbar_button_spec.js
new file mode 100644
index 00000000000..67f296b1bf0
--- /dev/null
+++ b/spec/frontend/vue_shared/components/markdown/drawio_toolbar_button_spec.js
@@ -0,0 +1,66 @@
+import { GlButton } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import DrawioToolbarButton from '~/vue_shared/components/markdown/drawio_toolbar_button.vue';
+import { launchDrawioEditor } from '~/drawio/drawio_editor';
+import { create } from '~/drawio/markdown_field_editor_facade';
+
+jest.mock('~/drawio/drawio_editor');
+jest.mock('~/drawio/markdown_field_editor_facade');
+
+describe('vue_shared/components/markdown/drawio_toolbar_button', () => {
+ let wrapper;
+ let textArea;
+ const uploadsPath = '/uploads';
+ const markdownPreviewPath = '/markdown/preview';
+
+ const buildWrapper = (props = { uploadsPath, markdownPreviewPath }) => {
+ wrapper = shallowMount(DrawioToolbarButton, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ textArea = document.createElement('textarea');
+ textArea.classList.add('js-gfm-input');
+
+ document.body.appendChild(textArea);
+ });
+
+ afterEach(() => {
+ textArea.remove();
+ });
+
+ describe('default', () => {
+ it('renders button that launches draw.io editor', () => {
+ buildWrapper();
+
+ expect(wrapper.findComponent(GlButton).props()).toMatchObject({
+ icon: 'diagram',
+ category: 'tertiary',
+ });
+ });
+ });
+
+ describe('when clicking button', () => {
+ it('launches draw.io editor', async () => {
+ const editorFacadeStub = {};
+
+ create.mockReturnValueOnce(editorFacadeStub);
+
+ buildWrapper();
+
+ await wrapper.findComponent(GlButton).vm.$emit('click');
+
+ expect(create).toHaveBeenCalledWith({
+ markdownPreviewPath,
+ textArea,
+ uploadsPath,
+ });
+ expect(launchDrawioEditor).toHaveBeenCalledWith({
+ editorFacade: editorFacadeStub,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/markdown/editor_mode_dropdown_spec.js b/spec/frontend/vue_shared/components/markdown/editor_mode_dropdown_spec.js
index 34071775b9c..becd4257cbe 100644
--- a/spec/frontend/vue_shared/components/markdown/editor_mode_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/editor_mode_dropdown_spec.js
@@ -21,14 +21,10 @@ describe('vue_shared/component/markdown/editor_mode_dropdown', () => {
.filter((item) => item.text().startsWith(text))
.at(0);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
- modeText | value | dropdownText | otherMode
- ${'Rich text'} | ${'richText'} | ${'View markdown'} | ${'Markdown'}
- ${'Markdown'} | ${'markdown'} | ${'View rich text'} | ${'Rich text'}
+ modeText | value | dropdownText | otherMode
+ ${'Rich text'} | ${'richText'} | ${'Viewing rich text'} | ${'Markdown'}
+ ${'Markdown'} | ${'markdown'} | ${'Viewing markdown'} | ${'Rich text'}
`('$modeText', ({ modeText, value, dropdownText, otherMode }) => {
beforeEach(() => {
createComponent({ value });
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 176ccfc5a69..1bbbe0896f2 100644
--- a/spec/frontend/vue_shared/components/markdown/field_view_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/field_view_spec.js
@@ -6,20 +6,14 @@ import { renderGFM } from '~/behaviors/markdown/render_gfm';
jest.mock('~/behaviors/markdown/render_gfm');
describe('Markdown Field View component', () => {
- let wrapper;
-
function createComponent() {
- wrapper = shallowMount(MarkdownFieldView);
+ shallowMount(MarkdownFieldView);
}
beforeEach(() => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('processes rendering with GFM', () => {
expect(renderGFM).toHaveBeenCalledTimes(1);
});
diff --git a/spec/frontend/vue_shared/components/markdown/header_spec.js b/spec/frontend/vue_shared/components/markdown/header_spec.js
index ed417097e1e..68f05e5119d 100644
--- a/spec/frontend/vue_shared/components/markdown/header_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/header_spec.js
@@ -3,6 +3,7 @@ import { nextTick } from 'vue';
import { GlTabs } from '@gitlab/ui';
import HeaderComponent from '~/vue_shared/components/markdown/header.vue';
import ToolbarButton from '~/vue_shared/components/markdown/toolbar_button.vue';
+import DrawioToolbarButton from '~/vue_shared/components/markdown/drawio_toolbar_button.vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
describe('Markdown field header component', () => {
@@ -26,6 +27,7 @@ describe('Markdown field header component', () => {
findToolbarButtons()
.filter((button) => button.props(prop) === value)
.at(0);
+ const findDrawioToolbarButton = () => wrapper.findComponent(DrawioToolbarButton);
beforeEach(() => {
window.gl = {
@@ -37,10 +39,6 @@ describe('Markdown field header component', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('markdown header buttons', () => {
it('renders the buttons with the correct title', () => {
const buttons = [
@@ -197,4 +195,24 @@ describe('Markdown field header component', () => {
expect(findToolbarButtons().length).toBe(defaultCount);
});
});
+
+ describe('when drawIOEnabled is true', () => {
+ const uploadsPath = '/uploads';
+ const markdownPreviewPath = '/preview';
+
+ beforeEach(() => {
+ createWrapper({
+ drawioEnabled: true,
+ uploadsPath,
+ markdownPreviewPath,
+ });
+ });
+
+ it('renders drawio toolbar button', () => {
+ expect(findDrawioToolbarButton().props()).toEqual({
+ uploadsPath,
+ markdownPreviewPath,
+ });
+ });
+ });
});
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 26b536984ff..681ff6c8dd3 100644
--- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
@@ -1,4 +1,5 @@
import axios from 'axios';
+import Autosize from 'autosize';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
@@ -9,10 +10,15 @@ import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import { stubComponent } from 'helpers/stub_component';
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+import waitForPromises from 'helpers/wait_for_promises';
jest.mock('~/emoji');
+jest.mock('autosize');
describe('vue_shared/component/markdown/markdown_editor', () => {
+ useLocalStorageSpy();
+
let wrapper;
const value = 'test markdown';
const renderMarkdownPath = '/api/markdown';
@@ -57,14 +63,27 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
const findContentEditor = () => wrapper.findComponent(ContentEditor);
+ const enableContentEditor = async () => {
+ findMarkdownField().vm.$emit('enableContentEditor');
+ await nextTick();
+ await waitForPromises();
+ };
+
+ const enableMarkdownEditor = async () => {
+ findContentEditor().vm.$emit('enableMarkdownEditor');
+ await nextTick();
+ await waitForPromises();
+ };
+
beforeEach(() => {
window.uploads_path = 'uploads';
mock = new MockAdapter(axios);
});
afterEach(() => {
- wrapper.destroy();
mock.restore();
+
+ localStorage.clear();
});
it('displays markdown field by default', () => {
@@ -83,8 +102,133 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
});
});
+ it('enables content editor switcher when contentEditorEnabled prop is true', () => {
+ buildWrapper({ propsData: { enableContentEditor: true } });
+
+ expect(findMarkdownField().text()).toContain('Rich text');
+ });
+
+ it('hides content editor switcher when contentEditorEnabled prop is false', () => {
+ buildWrapper({ propsData: { enableContentEditor: false } });
+
+ expect(findMarkdownField().text()).not.toContain('Rich text');
+ });
+
+ it('passes down any additional props to markdown field component', () => {
+ const propsData = {
+ line: { text: 'hello world', richText: 'hello world' },
+ lines: [{ text: 'hello world', richText: 'hello world' }],
+ canSuggest: true,
+ };
+
+ buildWrapper({
+ propsData: { ...propsData, myCustomProp: 'myCustomValue', 'data-testid': 'custom id' },
+ });
+
+ expect(findMarkdownField().props()).toMatchObject(propsData);
+ expect(findMarkdownField().vm.$attrs).toMatchObject({
+ myCustomProp: 'myCustomValue',
+
+ // data-testid isn't copied over
+ 'data-testid': 'markdown-field',
+ });
+ });
+
+ describe('disabled', () => {
+ it('disables markdown field when disabled prop is true', () => {
+ buildWrapper({ propsData: { disabled: true } });
+
+ expect(findMarkdownField().find('textarea').attributes('disabled')).toBe('disabled');
+ });
+
+ it('enables markdown field when disabled prop is false', () => {
+ buildWrapper({ propsData: { disabled: false } });
+
+ expect(findMarkdownField().find('textarea').attributes('disabled')).toBe(undefined);
+ });
+
+ it('disables content editor when disabled prop is true', async () => {
+ buildWrapper({ propsData: { disabled: true } });
+
+ await enableContentEditor();
+
+ expect(findContentEditor().props('editable')).toBe(false);
+ });
+
+ it('enables content editor when disabled prop is false', async () => {
+ buildWrapper({ propsData: { disabled: false } });
+
+ await enableContentEditor();
+
+ expect(findContentEditor().props('editable')).toBe(true);
+ });
+ });
+
+ describe('autosize', () => {
+ it('autosizes the textarea when the value changes', async () => {
+ buildWrapper();
+ await findTextarea().setValue('Lots of newlines\n\n\n\n\n\n\nMore content\n\n\nand newlines');
+
+ expect(Autosize.update).toHaveBeenCalled();
+ });
+
+ it('autosizes the textarea when the value changes from outside the component', async () => {
+ buildWrapper();
+ wrapper.setProps({ value: 'Lots of newlines\n\n\n\n\n\n\nMore content\n\n\nand newlines' });
+
+ await nextTick();
+ await waitForPromises();
+ expect(Autosize.update).toHaveBeenCalled();
+ });
+
+ it('does not autosize the textarea if markdown editor is disabled', async () => {
+ buildWrapper();
+ await enableContentEditor();
+
+ wrapper.setProps({ value: 'Lots of newlines\n\n\n\n\n\n\nMore content\n\n\nand newlines' });
+
+ expect(Autosize.update).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('autosave', () => {
+ it('automatically saves the textarea value to local storage if autosaveKey is defined', () => {
+ buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: 'This is **markdown**' } });
+
+ expect(localStorage.getItem('autosave/issue/1234')).toBe('This is **markdown**');
+ });
+
+ it("loads value from local storage if autosaveKey is defined, and value isn't", () => {
+ localStorage.setItem('autosave/issue/1234', 'This is **markdown**');
+
+ buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: '' } });
+
+ expect(findTextarea().element.value).toBe('This is **markdown**');
+ });
+
+ it("doesn't load value from local storage if autosaveKey is defined, and value is", () => {
+ localStorage.setItem('autosave/issue/1234', 'This is **markdown**');
+
+ buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
+
+ expect(findTextarea().element.value).toBe('test markdown');
+ });
+
+ it('does not save the textarea value to local storage if autosaveKey is not defined', () => {
+ buildWrapper({ propsData: { value: 'This is **markdown**' } });
+
+ expect(localStorage.setItem).not.toHaveBeenCalled();
+ });
+
+ it('does not save the textarea value to local storage if value is empty', () => {
+ buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: '' } });
+
+ expect(localStorage.setItem).not.toHaveBeenCalled();
+ });
+ });
+
it('renders markdown field textarea', () => {
- buildWrapper();
+ buildWrapper({ propsData: { supportsQuickActions: true } });
expect(findTextarea().attributes()).toEqual(
expect.objectContaining({
@@ -92,6 +236,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
name: formFieldName,
placeholder: formFieldPlaceholder,
'aria-label': formFieldAriaLabel,
+ 'data-supports-quick-actions': 'true',
}),
);
@@ -107,9 +252,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
it(`emits ${EDITING_MODE_CONTENT_EDITOR} event when enableContentEditor emitted from markdown editor`, async () => {
buildWrapper();
- findMarkdownField().vm.$emit('enableContentEditor');
-
- await nextTick();
+ await enableContentEditor();
expect(wrapper.emitted(EDITING_MODE_CONTENT_EDITOR)).toHaveLength(1);
});
@@ -119,11 +262,8 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
stubs: { ContentEditor: stubComponent(ContentEditor) },
});
- findMarkdownField().vm.$emit('enableContentEditor');
-
- await nextTick();
-
- findContentEditor().vm.$emit('enableMarkdownEditor');
+ await enableContentEditor();
+ await enableMarkdownEditor();
expect(wrapper.emitted(EDITING_MODE_MARKDOWN_FIELD)).toHaveLength(1);
});
@@ -138,6 +278,16 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(wrapper.emitted('input')).toEqual([[newValue]]);
});
+ it('autosaves the markdown value to local storage', async () => {
+ buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
+
+ const newValue = 'new value';
+
+ await findTextarea().setValue(newValue);
+
+ expect(localStorage.getItem('autosave/issue/1234')).toBe(newValue);
+ });
+
describe('when autofocus is true', () => {
beforeEach(async () => {
buildWrapper({ attachTo: document.body, propsData: { autofocus: true } });
@@ -159,9 +309,9 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
});
describe(`when markdown field triggers enableContentEditor event`, () => {
- beforeEach(() => {
+ beforeEach(async () => {
buildWrapper();
- findMarkdownField().vm.$emit('enableContentEditor');
+ await enableContentEditor();
});
it('displays the content editor', () => {
@@ -169,7 +319,6 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect.objectContaining({
renderMarkdown: expect.any(Function),
uploadsPath: window.uploads_path,
- useBottomToolbar: false,
markdown: value,
}),
);
@@ -198,9 +347,9 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
});
describe(`when editingMode is ${EDITING_MODE_CONTENT_EDITOR}`, () => {
- beforeEach(() => {
- buildWrapper();
- findMarkdownField().vm.$emit('enableContentEditor');
+ beforeEach(async () => {
+ buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
+ await enableContentEditor();
});
describe('when autofocus is true', () => {
@@ -224,6 +373,14 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(wrapper.emitted('input')).toEqual([[newValue]]);
});
+ it('autosaves the content editor value to local storage', async () => {
+ const newValue = 'new value';
+
+ await findContentEditor().vm.$emit('change', { markdown: newValue });
+
+ expect(localStorage.getItem('autosave/issue/1234')).toBe(newValue);
+ });
+
it('bubbles up keydown event', () => {
const event = new Event('keydown');
@@ -233,9 +390,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
});
describe(`when richText editor triggers enableMarkdownEditor event`, () => {
- beforeEach(() => {
- findContentEditor().vm.$emit('enableMarkdownEditor');
- });
+ beforeEach(enableMarkdownEditor);
it('hides the content editor', () => {
expect(findContentEditor().exists()).toBe(false);
diff --git a/spec/frontend/vue_shared/components/markdown/saved_replies_dropdown_spec.js b/spec/frontend/vue_shared/components/markdown/saved_replies_dropdown_spec.js
new file mode 100644
index 00000000000..8ad9ad30c1d
--- /dev/null
+++ b/spec/frontend/vue_shared/components/markdown/saved_replies_dropdown_spec.js
@@ -0,0 +1,62 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import savedRepliesResponse from 'test_fixtures/graphql/saved_replies/saved_replies.query.graphql.json';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import SavedRepliesDropdown from '~/vue_shared/components/markdown/saved_replies_dropdown.vue';
+import savedRepliesQuery from '~/vue_shared/components/markdown/saved_replies.query.graphql';
+
+let wrapper;
+let savedRepliesResp;
+
+function createMockApolloProvider(response) {
+ Vue.use(VueApollo);
+
+ savedRepliesResp = jest.fn().mockResolvedValue(response);
+
+ const requestHandlers = [[savedRepliesQuery, savedRepliesResp]];
+
+ return createMockApollo(requestHandlers);
+}
+
+function createComponent(options = {}) {
+ const { mockApollo } = options;
+
+ return mountExtended(SavedRepliesDropdown, {
+ propsData: {
+ newSavedRepliesPath: '/new',
+ },
+ apolloProvider: mockApollo,
+ });
+}
+
+describe('Saved replies dropdown', () => {
+ it('fetches data when dropdown gets opened', async () => {
+ const mockApollo = createMockApolloProvider(savedRepliesResponse);
+ wrapper = createComponent({ mockApollo });
+
+ wrapper.findByTestId('saved-replies-dropdown-toggle').trigger('click');
+
+ await waitForPromises();
+
+ expect(savedRepliesResp).toHaveBeenCalled();
+ });
+
+ it('adds markdown toolbar attributes to dropdown items', async () => {
+ const mockApollo = createMockApolloProvider(savedRepliesResponse);
+ wrapper = createComponent({ mockApollo });
+
+ wrapper.findByTestId('saved-replies-dropdown-toggle').trigger('click');
+
+ await waitForPromises();
+
+ expect(wrapper.findByTestId('saved-reply-dropdown-item').attributes()).toEqual(
+ expect.objectContaining({
+ 'data-md-cursor-offset': '0',
+ 'data-md-prepend': 'true',
+ 'data-md-tag': 'Saved Reply Content',
+ }),
+ );
+ });
+});
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 9db1b779a04..9768bc7a6dd 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
@@ -25,7 +25,7 @@ describe('Suggestion Diff component', () => {
...props,
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
@@ -34,10 +34,6 @@ describe('Suggestion Diff component', () => {
window.gon.current_user_id = 1;
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findApplyButton = () => wrapper.findComponent(ApplySuggestion);
const findApplyBatchButton = () => wrapper.find('.js-apply-batch-btn');
const findAddToBatchButton = () => wrapper.find('.js-add-to-batch-btn');
diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js
index f9a8b64f89b..c46a2d3e117 100644
--- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js
@@ -36,10 +36,6 @@ describe('SuggestionDiffRow', () => {
const findNewLineWrapper = () => wrapper.find('.new_line');
const findSuggestionContent = () => wrapper.find('[data-testid="suggestion-diff-content"]');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('renders correctly', () => {
it('renders the correct base suggestion markup', () => {
factory({
diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js
index d84483c1663..8c7f51664ad 100644
--- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js
@@ -61,11 +61,6 @@ describe('Suggestion Diff component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('matches snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js b/spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js
index 82210e79799..33e9d6add99 100644
--- a/spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js
@@ -20,11 +20,6 @@ describe('toolbar_button', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const getButtonShortcutsAttr = () => {
return wrapper.findComponent(GlButton).attributes('data-md-shortcuts');
};
diff --git a/spec/frontend/vue_shared/components/markdown/toolbar_spec.js b/spec/frontend/vue_shared/components/markdown/toolbar_spec.js
index b1a1dbbeb7a..fea14f80496 100644
--- a/spec/frontend/vue_shared/components/markdown/toolbar_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/toolbar_spec.js
@@ -11,10 +11,6 @@ describe('toolbar', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('user can attach file', () => {
beforeEach(() => {
createMountedWrapper();
diff --git a/spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js b/spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js
index 2b311b75f85..37b0767616a 100644
--- a/spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js
+++ b/spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js
@@ -36,8 +36,6 @@ describe('MarkdownDrawer', () => {
};
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
Object.keys(cache).forEach((key) => delete cache[key]);
});
diff --git a/spec/frontend/vue_shared/components/memory_graph_spec.js b/spec/frontend/vue_shared/components/memory_graph_spec.js
index ae8d5ff78ba..81325fb3269 100644
--- a/spec/frontend/vue_shared/components/memory_graph_spec.js
+++ b/spec/frontend/vue_shared/components/memory_graph_spec.js
@@ -1,10 +1,8 @@
import { GlSparklineChart } from '@gitlab/ui/dist/charts';
import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
import MemoryGraph from '~/vue_shared/components/memory_graph.vue';
describe('MemoryGraph', () => {
- const Component = Vue.extend(MemoryGraph);
let wrapper;
const metrics = [
[1573586253.853, '2.87'],
@@ -13,12 +11,10 @@ describe('MemoryGraph', () => {
[1573586433.853, '3.0066964285714284'],
];
- afterEach(() => {
- wrapper.destroy();
- });
+ const findGlSparklineChart = () => wrapper.findComponent(GlSparklineChart);
beforeEach(() => {
- wrapper = shallowMount(Component, {
+ wrapper = shallowMount(MemoryGraph, {
propsData: {
metrics,
width: 100,
@@ -27,19 +23,15 @@ describe('MemoryGraph', () => {
});
});
- describe('chartData', () => {
- it('should calculate chartData', () => {
- expect(wrapper.vm.chartData.length).toEqual(metrics.length);
- });
-
- it('should format date & MB values', () => {
+ describe('Chart data', () => {
+ it('should have formatted date & MB values', () => {
const formattedData = [
['Nov 12 2019 19:17:33', '2.87'],
['Nov 12 2019 19:18:33', '2.78'],
['Nov 12 2019 19:19:33', '2.78'],
['Nov 12 2019 19:20:33', '3.01'],
];
- expect(wrapper.vm.chartData).toEqual(formattedData);
+ expect(findGlSparklineChart().props('data')).toEqual(formattedData);
});
});
@@ -47,7 +39,7 @@ describe('MemoryGraph', () => {
it('should draw container with chart', () => {
expect(wrapper.element).toMatchSnapshot();
expect(wrapper.find('.memory-graph-container').exists()).toBe(true);
- expect(wrapper.findComponent(GlSparklineChart).exists()).toBe(true);
+ expect(findGlSparklineChart().exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/vue_shared/components/metric_images/store/actions_spec.js b/spec/frontend/vue_shared/components/metric_images/store/actions_spec.js
index 537367940e0..626f6fc735e 100644
--- a/spec/frontend/vue_shared/components/metric_images/store/actions_spec.js
+++ b/spec/frontend/vue_shared/components/metric_images/store/actions_spec.js
@@ -4,11 +4,11 @@ import actionsFactory from '~/vue_shared/components/metric_images/store/actions'
import * as types from '~/vue_shared/components/metric_images/store/mutation_types';
import createStore from '~/vue_shared/components/metric_images/store';
import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { fileList, initialData } from '../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
const service = {
getMetricImages: jest.fn(),
uploadMetricImage: jest.fn(),
diff --git a/spec/frontend/vue_shared/components/modal_copy_button_spec.js b/spec/frontend/vue_shared/components/modal_copy_button_spec.js
index 61e4e774420..a649b06c50e 100644
--- a/spec/frontend/vue_shared/components/modal_copy_button_spec.js
+++ b/spec/frontend/vue_shared/components/modal_copy_button_spec.js
@@ -6,10 +6,6 @@ import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
describe('modal copy button', () => {
let wrapper;
- afterEach(() => {
- wrapper.destroy();
- });
-
beforeEach(() => {
wrapper = shallowMount(ModalCopyButton, {
propsData: {
diff --git a/spec/frontend/vue_shared/components/navigation_tabs_spec.js b/spec/frontend/vue_shared/components/navigation_tabs_spec.js
index b1bec28bffb..947ee756259 100644
--- a/spec/frontend/vue_shared/components/navigation_tabs_spec.js
+++ b/spec/frontend/vue_shared/components/navigation_tabs_spec.js
@@ -38,11 +38,6 @@ describe('navigation tabs component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('should render tabs', () => {
expect(wrapper.findAllComponents(GlTab)).toHaveLength(data.length);
});
diff --git a/spec/frontend/vue_shared/components/new_resource_dropdown/new_resource_dropdown_spec.js b/spec/frontend/vue_shared/components/new_resource_dropdown/new_resource_dropdown_spec.js
index 31320b1d2a6..a116233a065 100644
--- a/spec/frontend/vue_shared/components/new_resource_dropdown/new_resource_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/new_resource_dropdown/new_resource_dropdown_spec.js
@@ -21,7 +21,7 @@ import {
searchProjectsWithinGroupQueryResponse,
} from './mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('NewResourceDropdown component', () => {
useLocalStorageSpy();
diff --git a/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js b/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js
index 17a62ae8a33..f87674246d1 100644
--- a/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js
+++ b/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js
@@ -132,12 +132,6 @@ describe('Issue Warning Component', () => {
});
});
- afterEach(() => {
- wrapperLocked.destroy();
- wrapperConfidential.destroy();
- wrapperLockedAndConfidential.destroy();
- });
-
it('renders confidential & locked messages with noteable "issue"', () => {
expect(findLockedBlock(wrapperLocked).text()).toContain('This issue is locked.');
expect(findConfidentialBlock(wrapperConfidential).text()).toContain(
diff --git a/spec/frontend/vue_shared/components/notes/placeholder_note_spec.js b/spec/frontend/vue_shared/components/notes/placeholder_note_spec.js
index 8f9f1bb336f..7e669fb7c71 100644
--- a/spec/frontend/vue_shared/components/notes/placeholder_note_spec.js
+++ b/spec/frontend/vue_shared/components/notes/placeholder_note_spec.js
@@ -30,11 +30,6 @@ describe('Issue placeholder note component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('matches snapshot', () => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/notes/placeholder_system_note_spec.js b/spec/frontend/vue_shared/components/notes/placeholder_system_note_spec.js
index de6ab43bc41..5897b9e0ffc 100644
--- a/spec/frontend/vue_shared/components/notes/placeholder_system_note_spec.js
+++ b/spec/frontend/vue_shared/components/notes/placeholder_system_note_spec.js
@@ -12,11 +12,6 @@ describe('Placeholder system note component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('matches snapshot', () => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/notes/system_note_spec.js b/spec/frontend/vue_shared/components/notes/system_note_spec.js
index bcfd7a8ec70..29e1a9ccf4d 100644
--- a/spec/frontend/vue_shared/components/notes/system_note_spec.js
+++ b/spec/frontend/vue_shared/components/notes/system_note_spec.js
@@ -46,7 +46,6 @@ describe('system note component', () => {
});
afterEach(() => {
- vm.destroy();
mock.restore();
});
diff --git a/spec/frontend/vue_shared/components/notes/timeline_entry_item_spec.js b/spec/frontend/vue_shared/components/notes/timeline_entry_item_spec.js
index bd4b6a463ab..fa9d3cd28a9 100644
--- a/spec/frontend/vue_shared/components/notes/timeline_entry_item_spec.js
+++ b/spec/frontend/vue_shared/components/notes/timeline_entry_item_spec.js
@@ -10,10 +10,6 @@ describe(`TimelineEntryItem`, () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders correctly', () => {
factory();
diff --git a/spec/frontend/vue_shared/components/ordered_layout_spec.js b/spec/frontend/vue_shared/components/ordered_layout_spec.js
index 21588569d6a..b6c8c467028 100644
--- a/spec/frontend/vue_shared/components/ordered_layout_spec.js
+++ b/spec/frontend/vue_shared/components/ordered_layout_spec.js
@@ -37,10 +37,6 @@ describe('Ordered Layout', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when slotKeys are in initial slot order', () => {
beforeEach(() => {
createComponent({ slotKeys: regularSlotOrder });
diff --git a/spec/frontend/vue_shared/components/page_size_selector_spec.js b/spec/frontend/vue_shared/components/page_size_selector_spec.js
index 5ec0b863afd..fce7ceee2fe 100644
--- a/spec/frontend/vue_shared/components/page_size_selector_spec.js
+++ b/spec/frontend/vue_shared/components/page_size_selector_spec.js
@@ -14,10 +14,6 @@ describe('Page size selector component', () => {
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each(PAGE_SIZES)('shows expected text in the dropdown button for page size %s', (pageSize) => {
createWrapper({ pageSize });
diff --git a/spec/frontend/vue_shared/components/paginated_list_spec.js b/spec/frontend/vue_shared/components/paginated_list_spec.js
index ae9c920ebd2..fc9adab2e2b 100644
--- a/spec/frontend/vue_shared/components/paginated_list_spec.js
+++ b/spec/frontend/vue_shared/components/paginated_list_spec.js
@@ -33,10 +33,6 @@ describe('Pagination links component', () => {
[glPaginatedList] = wrapper.vm.$children;
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Paginated List Component', () => {
describe('props', () => {
// We test attrs and not props because we pass through to child component using v-bind:"$attrs"
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 86a63db0d9e..25bfa688e5b 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
@@ -108,16 +108,23 @@ describe('AlertManagementEmptyState', () => {
const findStatusTabs = () => wrapper.findComponent(GlTabs);
const findStatusFilterBadge = () => wrapper.findAllComponents(GlBadge);
+ const handleFilterItems = (filters) => {
+ Filters().vm.$emit('onFilter', filters);
+ return nextTick();
+ };
+
describe('Snowplow tracking', () => {
+ const category = 'category';
+ const action = 'action';
+
beforeEach(() => {
jest.spyOn(Tracking, 'event');
mountComponent({
- props: { trackViewsOptions: { category: 'category', action: 'action' } },
+ props: { trackViewsOptions: { category, action } },
});
});
it('should track the items list page views', () => {
- const { category, action } = wrapper.vm.trackViewsOptions;
expect(Tracking.event).toHaveBeenCalledWith(category, action);
});
});
@@ -234,14 +241,14 @@ describe('AlertManagementEmptyState', () => {
findPagination().vm.$emit('input', 3);
await nextTick();
- expect(wrapper.vm.previousPage).toBe(2);
+ expect(findPagination().props('prevPage')).toBe(2);
});
it('returns 0 when it is the first page', async () => {
findPagination().vm.$emit('input', 1);
await nextTick();
- expect(wrapper.vm.previousPage).toBe(0);
+ expect(findPagination().props('prevPage')).toBe(0);
});
});
@@ -265,14 +272,14 @@ describe('AlertManagementEmptyState', () => {
findPagination().vm.$emit('input', 1);
await nextTick();
- expect(wrapper.vm.nextPage).toBe(2);
+ expect(findPagination().props('nextPage')).toBe(2);
});
it('returns `null` when currentPage is already last page', async () => {
findStatusTabs().vm.$emit('input', 1);
findPagination().vm.$emit('input', 1);
await nextTick();
- expect(wrapper.vm.nextPage).toBeNull();
+ expect(findPagination().props('nextPage')).toBeNull();
});
});
});
@@ -320,36 +327,32 @@ describe('AlertManagementEmptyState', () => {
it('returns correctly applied filter search values', async () => {
const searchTerm = 'foo';
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- searchTerm,
- });
-
+ await handleFilterItems([{ type: 'filtered-search-term', value: { data: searchTerm } }]);
await nextTick();
- expect(wrapper.vm.filteredSearchValue).toEqual([searchTerm]);
+ expect(Filters().props('initialFilterValue')).toEqual([searchTerm]);
});
- it('updates props tied to getIncidents GraphQL query', () => {
- wrapper.vm.handleFilterItems(mockFilters);
-
- expect(wrapper.vm.authorUsername).toBe('root');
- expect(wrapper.vm.assigneeUsername).toEqual('root2');
- expect(wrapper.vm.searchTerm).toBe(mockFilters[2].value.data);
- });
+ it('updates props tied to getIncidents GraphQL query', async () => {
+ await handleFilterItems(mockFilters);
- it('updates props `searchTerm` and `authorUsername` with empty values when passed filters param is empty', () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- authorUsername: 'foo',
- searchTerm: 'bar',
- });
+ const [
+ {
+ value: { data: authorUsername },
+ },
+ {
+ value: { data: assigneeUsername },
+ },
+ searchTerm,
+ ] = Filters().props('initialFilterValue');
- wrapper.vm.handleFilterItems([]);
+ expect(authorUsername).toBe('root');
+ expect(assigneeUsername).toEqual('root2');
+ expect(searchTerm).toBe(mockFilters[2].value.data);
+ });
- expect(wrapper.vm.authorUsername).toBe('');
- expect(wrapper.vm.searchTerm).toBe('');
+ it('updates props `searchTerm` and `authorUsername` with empty values when passed filters param is empty', async () => {
+ await handleFilterItems([]);
+ expect(Filters().props('initialFilterValue')).toEqual([]);
});
});
});
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 112cdaf74c6..2a1a6342c38 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
@@ -25,10 +25,6 @@ describe('Pagination bar', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('events', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/pagination_links_spec.js b/spec/frontend/vue_shared/components/pagination_links_spec.js
index d444ad7a733..99a4f776305 100644
--- a/spec/frontend/vue_shared/components/pagination_links_spec.js
+++ b/spec/frontend/vue_shared/components/pagination_links_spec.js
@@ -44,10 +44,6 @@ describe('Pagination links component', () => {
glPagination = wrapper.findComponent(GlPagination);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should provide translated text to GitLab UI pagination', () => {
Object.entries(translations).forEach((entry) => {
expect(glPagination.vm[entry[0]]).toBe(entry[1]);
diff --git a/spec/frontend/vue_shared/components/panel_resizer_spec.js b/spec/frontend/vue_shared/components/panel_resizer_spec.js
index 0e261124cbf..a535fe4939c 100644
--- a/spec/frontend/vue_shared/components/panel_resizer_spec.js
+++ b/spec/frontend/vue_shared/components/panel_resizer_spec.js
@@ -27,10 +27,6 @@ describe('Panel Resizer component', () => {
el.dispatchEvent(event);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render a div element with the correct classes and styles', () => {
wrapper = mount(PanelResizer, {
propsData: {
diff --git a/spec/frontend/vue_shared/components/papa_parse_alert_spec.js b/spec/frontend/vue_shared/components/papa_parse_alert_spec.js
index ff4febd647e..a44a1aba8c0 100644
--- a/spec/frontend/vue_shared/components/papa_parse_alert_spec.js
+++ b/spec/frontend/vue_shared/components/papa_parse_alert_spec.js
@@ -16,10 +16,6 @@ describe('app/assets/javascripts/vue_shared/components/papa_parse_alert.vue', ()
const findAlert = () => wrapper.findComponent(GlAlert);
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render alert with correct props', async () => {
createComponent({ errorMessages: [{ code: 'MissingQuotes' }] });
await nextTick();
diff --git a/spec/frontend/vue_shared/components/project_avatar_spec.js b/spec/frontend/vue_shared/components/project_avatar_spec.js
index af828fbca51..9378f6e3f1b 100644
--- a/spec/frontend/vue_shared/components/project_avatar_spec.js
+++ b/spec/frontend/vue_shared/components/project_avatar_spec.js
@@ -15,10 +15,6 @@ describe('ProjectAvatar', () => {
wrapper = shallowMount(ProjectAvatar, { propsData: { ...defaultProps, ...props }, attrs });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders GlAvatar with correct props', () => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/project_selector/project_list_item_spec.js b/spec/frontend/vue_shared/components/project_selector/project_list_item_spec.js
index 4e0c318c84e..d704fcc0e7b 100644
--- a/spec/frontend/vue_shared/components/project_selector/project_list_item_spec.js
+++ b/spec/frontend/vue_shared/components/project_selector/project_list_item_spec.js
@@ -1,57 +1,49 @@
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
+import { GlButton } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import mockProjects from 'test_fixtures_static/projects.json';
import { trimText } from 'helpers/text_helper';
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
import ProjectListItem from '~/vue_shared/components/project_selector/project_list_item.vue';
describe('ProjectListItem component', () => {
- const Component = Vue.extend(ProjectListItem);
let wrapper;
- let vm;
- let options;
const project = JSON.parse(JSON.stringify(mockProjects))[0];
- beforeEach(() => {
- options = {
+ const createWrapper = ({ propsData } = {}) => {
+ wrapper = shallowMountExtended(ProjectListItem, {
propsData: {
project,
selected: false,
+ ...propsData,
},
- };
- });
-
- afterEach(() => {
- wrapper.vm.$destroy();
- });
-
- it('does not render a check mark icon if selected === false', () => {
- wrapper = shallowMount(Component, options);
-
- expect(wrapper.find('.js-selected-icon').exists()).toBe(false);
- });
+ });
+ };
- it('renders a check mark icon if selected === true', () => {
- options.propsData.selected = true;
+ const findProjectNamespace = () => wrapper.findByTestId('project-namespace');
+ const findProjectName = () => wrapper.findByTestId('project-name');
- wrapper = shallowMount(Component, options);
+ it.each([true, false])('renders a checkmark correctly when selected === "%s"', (selected) => {
+ createWrapper({
+ propsData: {
+ selected,
+ },
+ });
- expect(wrapper.find('.js-selected-icon').exists()).toBe(true);
+ expect(wrapper.findByTestId('selected-icon').exists()).toBe(selected);
});
- it(`emits a "clicked" event when clicked`, () => {
- wrapper = shallowMount(Component, options);
- ({ vm } = wrapper);
+ it(`emits a "clicked" event when the button is clicked`, () => {
+ createWrapper();
- jest.spyOn(vm, '$emit').mockImplementation(() => {});
- wrapper.vm.onClick();
+ expect(wrapper.emitted('click')).toBeUndefined();
+ wrapper.findComponent(GlButton).vm.$emit('click');
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('click');
+ expect(wrapper.emitted('click')).toHaveLength(1);
});
it(`renders the project avatar`, () => {
- wrapper = shallowMount(Component, options);
+ createWrapper();
const avatar = wrapper.findComponent(ProjectAvatar);
expect(avatar.exists()).toBe(true);
@@ -63,48 +55,73 @@ describe('ProjectListItem component', () => {
});
it(`renders a simple namespace name with a trailing slash`, () => {
- options.propsData.project.name_with_namespace = 'a / b';
-
- wrapper = shallowMount(Component, options);
- const renderedNamespace = trimText(wrapper.find('.js-project-namespace').text());
+ createWrapper({
+ propsData: {
+ project: {
+ ...project,
+ name_with_namespace: 'a / b',
+ },
+ },
+ });
+ const renderedNamespace = trimText(findProjectNamespace().text());
expect(renderedNamespace).toBe('a /');
});
it(`renders a properly truncated namespace with a trailing slash`, () => {
- options.propsData.project.name_with_namespace = 'a / b / c / d / e / f';
-
- wrapper = shallowMount(Component, options);
- const renderedNamespace = trimText(wrapper.find('.js-project-namespace').text());
+ createWrapper({
+ propsData: {
+ project: {
+ ...project,
+ name_with_namespace: 'a / b / c / d / e / f',
+ },
+ },
+ });
+ const renderedNamespace = trimText(findProjectNamespace().text());
expect(renderedNamespace).toBe('a / ... / e /');
});
it(`renders a simple namespace name of a GraphQL project`, () => {
- options.propsData.project.name_with_namespace = undefined;
- options.propsData.project.nameWithNamespace = 'test';
-
- wrapper = shallowMount(Component, options);
- const renderedNamespace = trimText(wrapper.find('.js-project-namespace').text());
+ createWrapper({
+ propsData: {
+ project: {
+ ...project,
+ name_with_namespace: undefined,
+ nameWithNamespace: 'test',
+ },
+ },
+ });
+ const renderedNamespace = trimText(findProjectNamespace().text());
expect(renderedNamespace).toBe('test /');
});
it(`renders the project name`, () => {
- options.propsData.project.name = 'my-test-project';
-
- wrapper = shallowMount(Component, options);
- const renderedName = trimText(wrapper.find('.js-project-name').text());
+ createWrapper({
+ propsData: {
+ project: {
+ ...project,
+ name: 'my-test-project',
+ },
+ },
+ });
+ const renderedName = trimText(findProjectName().text());
expect(renderedName).toBe('my-test-project');
});
it(`renders the project name with highlighting in the case of a search query match`, () => {
- options.propsData.project.name = 'my-test-project';
- options.propsData.matcher = 'pro';
-
- wrapper = shallowMount(Component, options);
- const renderedName = trimText(wrapper.find('.js-project-name').html());
+ createWrapper({
+ propsData: {
+ project: {
+ ...project,
+ name: 'my-test-project',
+ },
+ matcher: 'pro',
+ },
+ });
+ const renderedName = trimText(findProjectName().html());
const expected = 'my-test-<b>p</b><b>r</b><b>o</b>ject';
expect(renderedName).toContain(expected);
@@ -112,11 +129,16 @@ describe('ProjectListItem component', () => {
it('prevents search query and project name XSS', () => {
const alertSpy = jest.spyOn(window, 'alert');
- options.propsData.project.name = "my-xss-pro<script>alert('XSS');</script>ject";
- options.propsData.matcher = "pro<script>alert('XSS');</script>";
-
- wrapper = shallowMount(Component, options);
- const renderedName = trimText(wrapper.find('.js-project-name').html());
+ createWrapper({
+ propsData: {
+ project: {
+ ...project,
+ name: "my-xss-pro<script>alert('XSS');</script>ject",
+ },
+ matcher: "pro<script>alert('XSS');</script>",
+ },
+ });
+ const renderedName = trimText(findProjectName().html());
const expected = 'my-xss-project';
expect(renderedName).toContain(expected);
diff --git a/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js b/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js
index a0832dd7030..5e304f1c118 100644
--- a/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js
+++ b/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js
@@ -1,7 +1,7 @@
import { GlSearchBoxByType, GlInfiniteScroll } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { head } from 'lodash';
-import Vue, { nextTick } from 'vue';
+import { nextTick } from 'vue';
import mockProjects from 'test_fixtures_static/projects.json';
import { trimText } from 'helpers/text_helper';
import ProjectListItem from '~/vue_shared/components/project_selector/project_list_item.vue';
@@ -25,7 +25,7 @@ describe('ProjectSelector component', () => {
};
beforeEach(() => {
- wrapper = mount(Vue.extend(ProjectSelector), {
+ wrapper = mount(ProjectSelector, {
propsData: {
projectSearchResults: searchResults,
selectedProjects: selected,
diff --git a/spec/frontend/vue_shared/components/registry/code_instruction_spec.js b/spec/frontend/vue_shared/components/registry/code_instruction_spec.js
index 8f19f0ea14d..60c1293b7c1 100644
--- a/spec/frontend/vue_shared/components/registry/code_instruction_spec.js
+++ b/spec/frontend/vue_shared/components/registry/code_instruction_spec.js
@@ -26,10 +26,6 @@ describe('Package code instruction', () => {
const findInputElement = () => wrapper.find('[data-testid="instruction-input"]');
const findMultilineInstruction = () => wrapper.find('[data-testid="multiline-instruction"]');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('single line', () => {
beforeEach(() =>
createComponent({
diff --git a/spec/frontend/vue_shared/components/registry/details_row_spec.js b/spec/frontend/vue_shared/components/registry/details_row_spec.js
index ebc9816f983..9ef1ce5647d 100644
--- a/spec/frontend/vue_shared/components/registry/details_row_spec.js
+++ b/spec/frontend/vue_shared/components/registry/details_row_spec.js
@@ -20,11 +20,6 @@ describe('DetailsRow', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('has a default slot', () => {
mountComponent();
expect(findDefaultSlot().exists()).toBe(true);
diff --git a/spec/frontend/vue_shared/components/registry/history_item_spec.js b/spec/frontend/vue_shared/components/registry/history_item_spec.js
index 947520567e6..17abe06dbee 100644
--- a/spec/frontend/vue_shared/components/registry/history_item_spec.js
+++ b/spec/frontend/vue_shared/components/registry/history_item_spec.js
@@ -22,11 +22,6 @@ describe('History Item', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findTimelineEntry = () => wrapper.findComponent(TimelineEntryItem);
const findGlIcon = () => wrapper.findComponent(GlIcon);
const findDefaultSlot = () => wrapper.find('[data-testid="default-slot"]');
diff --git a/spec/frontend/vue_shared/components/registry/list_item_spec.js b/spec/frontend/vue_shared/components/registry/list_item_spec.js
index b941eb77c32..298fa163d59 100644
--- a/spec/frontend/vue_shared/components/registry/list_item_spec.js
+++ b/spec/frontend/vue_shared/components/registry/list_item_spec.js
@@ -30,11 +30,6 @@ describe('list item', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe.each`
slotName | finderFunction
${'left-primary'} | ${findLeftPrimarySlot}
diff --git a/spec/frontend/vue_shared/components/registry/metadata_item_spec.js b/spec/frontend/vue_shared/components/registry/metadata_item_spec.js
index a04e1e237d4..278b09d80b2 100644
--- a/spec/frontend/vue_shared/components/registry/metadata_item_spec.js
+++ b/spec/frontend/vue_shared/components/registry/metadata_item_spec.js
@@ -14,16 +14,11 @@ describe('Metadata Item', () => {
wrapper = shallowMount(component, {
propsData,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findIcon = () => wrapper.findComponent(GlIcon);
const findLink = (w = wrapper) => w.findComponent(GlLink);
const findText = () => wrapper.find('[data-testid="metadata-item-text"]');
diff --git a/spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js b/spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js
index 616fefe847e..b93fa37546f 100644
--- a/spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js
+++ b/spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js
@@ -31,10 +31,6 @@ describe('Persisted dropdown selection', () => {
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('local storage sync', () => {
it('uses the local storage sync component with the correct props', () => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/registry/registry_search_spec.js b/spec/frontend/vue_shared/components/registry/registry_search_spec.js
index 591447a37c2..59bb0646350 100644
--- a/spec/frontend/vue_shared/components/registry/registry_search_spec.js
+++ b/spec/frontend/vue_shared/components/registry/registry_search_spec.js
@@ -36,11 +36,6 @@ describe('Registry Search', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('searching', () => {
it('has a filtered-search component', () => {
mountComponent();
diff --git a/spec/frontend/vue_shared/components/registry/title_area_spec.js b/spec/frontend/vue_shared/components/registry/title_area_spec.js
index efb57ddd310..ec1451de470 100644
--- a/spec/frontend/vue_shared/components/registry/title_area_spec.js
+++ b/spec/frontend/vue_shared/components/registry/title_area_spec.js
@@ -36,11 +36,6 @@ describe('title area', () => {
return acc;
}, {});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('title', () => {
it('if slot is not present defaults to prop', () => {
mountComponent();
diff --git a/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap b/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap
deleted file mode 100644
index cdfe311acd9..00000000000
--- a/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap
+++ /dev/null
@@ -1,23 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Resizable Chart Container renders the component 1`] = `
-<div>
- <template>
- <div
- class="slot"
- >
- <span
- class="width"
- >
- 0
- </span>
-
- <span
- class="height"
- >
- 0
- </span>
- </div>
- </template>
-</div>
-`;
diff --git a/spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js b/spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js
deleted file mode 100644
index 7536df24ac6..00000000000
--- a/spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import { mount } from '@vue/test-utils';
-import $ from 'jquery';
-import { nextTick } from 'vue';
-import ResizableChartContainer from '~/vue_shared/components/resizable_chart/resizable_chart_container.vue';
-
-jest.mock('~/lib/utils/common_utils', () => ({
- debounceByAnimationFrame(callback) {
- return jest.spyOn({ callback }, 'callback');
- },
-}));
-
-describe('Resizable Chart Container', () => {
- let wrapper;
-
- beforeEach(() => {
- wrapper = mount(ResizableChartContainer, {
- scopedSlots: {
- default: `
- <template #default="{ width, height }">
- <div class="slot">
- <span class="width">{{width}}</span>
- <span class="height">{{height}}</span>
- </div>
- </template>
- `,
- },
- });
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders the component', () => {
- expect(wrapper.element).toMatchSnapshot();
- });
-
- it('updates the slot width and height props', async () => {
- const width = 1920;
- const height = 1080;
-
- // JSDOM mocks and sets clientWidth/clientHeight to 0 so we set manually
- wrapper.vm.$refs.chartWrapper = { clientWidth: width, clientHeight: height };
-
- $(document).trigger('content.resize');
-
- await nextTick();
- const widthNode = wrapper.find('.slot > .width');
- const heightNode = wrapper.find('.slot > .height');
-
- expect(parseInt(widthNode.text(), 10)).toEqual(width);
- expect(parseInt(heightNode.text(), 10)).toEqual(height);
- });
-
- it('calls onResize on manual resize', () => {
- $(document).trigger('content.resize');
- expect(wrapper.vm.debouncedResize).toHaveBeenCalled();
- });
-
- it('calls onResize on page resize', () => {
- window.dispatchEvent(new Event('resize'));
- expect(wrapper.vm.debouncedResize).toHaveBeenCalled();
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_timestamp_tooltip_spec.js b/spec/frontend/vue_shared/components/rich_timestamp_tooltip_spec.js
index 5d96fe27676..11ee2e56c14 100644
--- a/spec/frontend/vue_shared/components/rich_timestamp_tooltip_spec.js
+++ b/spec/frontend/vue_shared/components/rich_timestamp_tooltip_spec.js
@@ -27,10 +27,6 @@ describe('RichTimestampTooltip', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders the tooltip text header', () => {
expect(wrapper.findByTestId('header-text').text()).toBe('Created just now');
});
diff --git a/spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js b/spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js
index f9d700fe67f..c4d4f80c573 100644
--- a/spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js
+++ b/spec/frontend/vue_shared/components/runner_instructions/instructions/runner_cli_instructions_spec.js
@@ -59,10 +59,6 @@ describe('RunnerCliInstructions component', () => {
runnerSetupInstructionsHandler = jest.fn().mockResolvedValue(mockInstructions);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the instructions are shown', () => {
beforeEach(async () => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js
index 8f593b6aa1b..cb35cbd35ad 100644
--- a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js
+++ b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js
@@ -74,10 +74,6 @@ describe('RunnerInstructionsModal component', () => {
runnerPlatformsHandler = jest.fn().mockResolvedValue(mockRunnerPlatforms);
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when the modal is shown', () => {
beforeEach(async () => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js
index 986d76d2b95..260eddbb37d 100644
--- a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js
+++ b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js
@@ -12,7 +12,7 @@ describe('RunnerInstructions component', () => {
const createComponent = () => {
wrapper = shallowMountExtended(RunnerInstructions, {
directives: {
- GlModal: createMockDirective(),
+ GlModal: createMockDirective('gl-tooltip'),
},
});
};
@@ -21,10 +21,6 @@ describe('RunnerInstructions component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should show the "Show runner installation instructions" button', () => {
expect(findModalButton().text()).toBe('Show runner installation instructions');
});
diff --git a/spec/frontend/vue_shared/components/security_reports/artifact_downloads/merge_request_artifact_download_spec.js b/spec/frontend/vue_shared/components/security_reports/artifact_downloads/merge_request_artifact_download_spec.js
index 09b0b3d43ad..6eebd129beb 100644
--- a/spec/frontend/vue_shared/components/security_reports/artifact_downloads/merge_request_artifact_download_spec.js
+++ b/spec/frontend/vue_shared/components/security_reports/artifact_downloads/merge_request_artifact_download_spec.js
@@ -6,7 +6,7 @@ import {
expectedDownloadDropdownPropsWithTitle,
securityReportMergeRequestDownloadPathsQueryResponse,
} from 'jest/vue_shared/security_reports/mock_data';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import Component from '~/vue_shared/security_reports/components/artifact_downloads/merge_request_artifact_download.vue';
import SecurityReportDownloadDropdown from '~/vue_shared/security_reports/components/security_report_download_dropdown.vue';
import {
@@ -15,7 +15,7 @@ import {
} from '~/vue_shared/security_reports/constants';
import securityReportMergeRequestDownloadPathsQuery from '~/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('Merge request artifact Download', () => {
let wrapper;
@@ -52,10 +52,6 @@ describe('Merge request artifact Download', () => {
const findDownloadDropdown = () => wrapper.findComponent(SecurityReportDownloadDropdown);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('given the query is loading', () => {
beforeEach(() => {
createWrapper({
diff --git a/spec/frontend/vue_shared/components/security_reports/help_icon_spec.js b/spec/frontend/vue_shared/components/security_reports/help_icon_spec.js
index 08d3d5b19d4..2f6e633fb34 100644
--- a/spec/frontend/vue_shared/components/security_reports/help_icon_spec.js
+++ b/spec/frontend/vue_shared/components/security_reports/help_icon_spec.js
@@ -21,11 +21,6 @@ describe('HelpIcon component', () => {
const findPopover = () => wrapper.findComponent(GlPopover);
const findPopoverTarget = () => wrapper.findComponent({ ref: 'discoverProjectSecurity' });
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('given a help path only', () => {
beforeEach(() => {
createWrapper();
diff --git a/spec/frontend/vue_shared/components/security_reports/security_summary_spec.js b/spec/frontend/vue_shared/components/security_reports/security_summary_spec.js
index f186eb848f2..61cdc329220 100644
--- a/spec/frontend/vue_shared/components/security_reports/security_summary_spec.js
+++ b/spec/frontend/vue_shared/components/security_reports/security_summary_spec.js
@@ -15,11 +15,6 @@ describe('SecuritySummary component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe.each([
{ message: '' },
{ message: 'foo' },
diff --git a/spec/frontend/vue_shared/components/segmented_control_button_group_spec.js b/spec/frontend/vue_shared/components/segmented_control_button_group_spec.js
index 88445b6684c..c1feb64dacb 100644
--- a/spec/frontend/vue_shared/components/segmented_control_button_group_spec.js
+++ b/spec/frontend/vue_shared/components/segmented_control_button_group_spec.js
@@ -40,10 +40,6 @@ describe('~/vue_shared/components/segmented_control_button_group.vue', () => {
disabled,
}));
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('default', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/settings/settings_block_spec.js b/spec/frontend/vue_shared/components/settings/settings_block_spec.js
index 5e829653c13..94d634f79bd 100644
--- a/spec/frontend/vue_shared/components/settings/settings_block_spec.js
+++ b/spec/frontend/vue_shared/components/settings/settings_block_spec.js
@@ -16,10 +16,6 @@ describe('Settings Block', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findDefaultSlot = () => wrapper.findByTestId('default-slot');
const findTitleSlot = () => wrapper.findByTestId('title-slot');
const findDescriptionSlot = () => wrapper.findByTestId('description-slot');
diff --git a/spec/frontend/vue_shared/components/smart_virtual_list_spec.js b/spec/frontend/vue_shared/components/smart_virtual_list_spec.js
index 8802a832781..e5d988f75f5 100644
--- a/spec/frontend/vue_shared/components/smart_virtual_list_spec.js
+++ b/spec/frontend/vue_shared/components/smart_virtual_list_spec.js
@@ -1,5 +1,4 @@
import { mount } from '@vue/test-utils';
-import Vue from 'vue';
import SmartVirtualScrollList from '~/vue_shared/components/smart_virtual_list.vue';
describe('Toggle Button', () => {
@@ -16,7 +15,7 @@ describe('Toggle Button', () => {
remain,
};
- const Component = Vue.extend({
+ const Component = {
components: {
SmartVirtualScrollList,
},
@@ -26,7 +25,7 @@ describe('Toggle Button', () => {
<smart-virtual-scroll-list v-bind="$options.smartListProperties">
<li v-for="(val, key) in $options.items" :key="key">{{ key + 1 }}</li>
</smart-virtual-scroll-list>`,
- });
+ };
return mount(Component).vm;
};
diff --git a/spec/frontend/vue_shared/components/source_editor_spec.js b/spec/frontend/vue_shared/components/source_editor_spec.js
index ca5b990bc29..5b155207029 100644
--- a/spec/frontend/vue_shared/components/source_editor_spec.js
+++ b/spec/frontend/vue_shared/components/source_editor_spec.js
@@ -47,10 +47,6 @@ describe('Source Editor component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const triggerChangeContent = (val) => {
mockInstance.getValue.mockReturnValue(val);
const [cb] = mockInstance.onDidChangeModelContent.mock.calls[0];
diff --git a/spec/frontend/vue_shared/components/source_viewer/components/chunk_deprecated_spec.js b/spec/frontend/vue_shared/components/source_viewer/components/chunk_deprecated_spec.js
index da9067a8ddc..395ba92d4c6 100644
--- a/spec/frontend/vue_shared/components/source_viewer/components/chunk_deprecated_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/components/chunk_deprecated_spec.js
@@ -45,8 +45,6 @@ describe('Chunk component', () => {
createComponent();
});
- afterEach(() => wrapper.destroy());
-
describe('Intersection observer', () => {
it('renders an Intersection observer component', () => {
expect(findIntersectionObserver().exists()).toBe(true);
diff --git a/spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js b/spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js
index f661bd6747a..6c8fc244fa0 100644
--- a/spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js
@@ -31,8 +31,6 @@ describe('Chunk Line component', () => {
createComponent();
});
- afterEach(() => wrapper.destroy());
-
describe('rendering', () => {
it('renders a blame link', () => {
expect(findBlameLink().attributes()).toMatchObject({
diff --git a/spec/frontend/vue_shared/components/source_viewer/components/chunk_spec.js b/spec/frontend/vue_shared/components/source_viewer/components/chunk_spec.js
index 95ef11d776a..59880496d74 100644
--- a/spec/frontend/vue_shared/components/source_viewer/components/chunk_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/components/chunk_spec.js
@@ -24,8 +24,6 @@ describe('Chunk component', () => {
createComponent();
});
- afterEach(() => wrapper.destroy());
-
describe('Intersection observer', () => {
it('renders an Intersection observer component', () => {
expect(findIntersectionObserver().exists()).toBe(true);
diff --git a/spec/frontend/vue_shared/components/source_viewer/source_viewer_deprecated_spec.js b/spec/frontend/vue_shared/components/source_viewer/source_viewer_deprecated_spec.js
index 0beec8e9d3e..c911e3d308b 100644
--- a/spec/frontend/vue_shared/components/source_viewer/source_viewer_deprecated_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/source_viewer_deprecated_spec.js
@@ -68,8 +68,6 @@ describe('Source Viewer component', () => {
return createComponent();
});
- afterEach(() => wrapper.destroy());
-
describe('event tracking', () => {
it('fires a tracking event when the component is created', () => {
const eventData = { label: EVENT_LABEL_VIEWER, property: language };
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 1c75442b4a8..46b582c3668 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
@@ -25,8 +25,6 @@ describe('Source Viewer component', () => {
return createComponent();
});
- afterEach(() => wrapper.destroy());
-
describe('event tracking', () => {
it('fires a tracking event when the component is created', () => {
const eventData = { label: EVENT_LABEL_VIEWER, property: LANGUAGE_MOCK };
diff --git a/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js b/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js
index 79b1f17afa0..13911d487f2 100644
--- a/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js
+++ b/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js
@@ -18,10 +18,6 @@ describe('StackedProgressBarComponent', () => {
wrapper = mount(StackedProgressBarComponent, { propsData: defaultConfig });
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findSuccessBar = () => wrapper.find('.status-green');
const findNeutralBar = () => wrapper.find('.status-neutral');
const findFailureBar = () => wrapper.find('.status-red');
diff --git a/spec/frontend/vue_shared/components/table_pagination_spec.js b/spec/frontend/vue_shared/components/table_pagination_spec.js
index 99de26ce2ae..79aba1b2516 100644
--- a/spec/frontend/vue_shared/components/table_pagination_spec.js
+++ b/spec/frontend/vue_shared/components/table_pagination_spec.js
@@ -16,10 +16,6 @@ describe('Pagination component', () => {
spy = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('render', () => {
it('should not render anything', () => {
mountComponent({
diff --git a/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js b/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
index 28c5acc8110..a1757952dc0 100644
--- a/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
+++ b/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js
@@ -25,7 +25,6 @@ describe('Time ago with tooltip component', () => {
};
afterEach(() => {
- vm.destroy();
timezoneMock.unregister();
});
diff --git a/spec/frontend/vue_shared/components/timezone_dropdown/timezone_dropdown_spec.js b/spec/frontend/vue_shared/components/timezone_dropdown/timezone_dropdown_spec.js
index c8351ed61d7..d8dedd8240b 100644
--- a/spec/frontend/vue_shared/components/timezone_dropdown/timezone_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/timezone_dropdown/timezone_dropdown_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdownItem, GlDropdown } from '@gitlab/ui';
+import { GlDropdownItem, GlDropdown, GlSearchBoxByType } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown/timezone_dropdown.vue';
@@ -9,7 +9,9 @@ describe('Deploy freeze timezone dropdown', () => {
let wrapper;
let store;
- const createComponent = (searchTerm, selectedTimezone) => {
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+
+ const createComponent = async (searchTerm, selectedTimezone) => {
wrapper = shallowMountExtended(TimezoneDropdown, {
store,
propsData: {
@@ -19,9 +21,8 @@ describe('Deploy freeze timezone dropdown', () => {
},
});
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ searchTerm });
+ findSearchBox().vm.$emit('input', searchTerm);
+ await nextTick();
};
const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
@@ -29,14 +30,9 @@ describe('Deploy freeze timezone dropdown', () => {
const findEmptyResultsItem = () => wrapper.findByTestId('noMatchingResults');
const findHiddenInput = () => wrapper.find('input');
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('No time zones found', () => {
- beforeEach(() => {
- createComponent('UTC timezone');
+ beforeEach(async () => {
+ await createComponent('UTC timezone');
});
it('renders empty results message', () => {
@@ -45,8 +41,8 @@ describe('Deploy freeze timezone dropdown', () => {
});
describe('Search term is empty', () => {
- beforeEach(() => {
- createComponent('');
+ beforeEach(async () => {
+ await createComponent('');
});
it('renders all timezones when search term is empty', () => {
@@ -55,8 +51,8 @@ describe('Deploy freeze timezone dropdown', () => {
});
describe('Time zones found', () => {
- beforeEach(() => {
- createComponent('Alaska');
+ beforeEach(async () => {
+ await createComponent('Alaska');
});
it('renders only the time zone searched for', () => {
@@ -87,8 +83,8 @@ describe('Deploy freeze timezone dropdown', () => {
});
describe('Selected time zone not found', () => {
- beforeEach(() => {
- createComponent('', 'Berlin');
+ beforeEach(async () => {
+ await createComponent('', 'Berlin');
});
it('renders empty selections', () => {
@@ -101,8 +97,8 @@ describe('Deploy freeze timezone dropdown', () => {
});
describe('Selected time zone found', () => {
- beforeEach(() => {
- createComponent('', 'Europe/Berlin');
+ beforeEach(async () => {
+ await createComponent('', 'Europe/Berlin');
});
it('renders selected time zone as dropdown label', () => {
diff --git a/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js b/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
index ca1f7996ad6..3807bb4cc63 100644
--- a/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
+++ b/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
@@ -30,8 +30,8 @@ describe('TooltipOnTruncate component', () => {
default: [MOCK_TITLE],
},
directives: {
- GlTooltip: createMockDirective(),
- GlResizeObserver: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
+ GlResizeObserver: createMockDirective('gl-resize-observer'),
},
...options,
});
@@ -42,8 +42,8 @@ describe('TooltipOnTruncate component', () => {
...TooltipOnTruncate,
directives: {
...TooltipOnTruncate.directives,
- GlTooltip: createMockDirective(),
- GlResizeObserver: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
+ GlResizeObserver: createMockDirective('gl-resize-observer'),
},
};
@@ -78,10 +78,6 @@ describe('TooltipOnTruncate component', () => {
await nextTick();
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when truncated', () => {
beforeEach(async () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
@@ -90,7 +86,7 @@ describe('TooltipOnTruncate component', () => {
it('renders tooltip', async () => {
expect(hasHorizontalOverflow).toHaveBeenLastCalledWith(wrapper.element);
- expect(getTooltipValue()).toMatchObject({
+ expect(getTooltipValue()).toStrictEqual({
title: MOCK_TITLE,
placement: 'top',
disabled: false,
@@ -144,7 +140,7 @@ describe('TooltipOnTruncate component', () => {
await nextTick();
- expect(getTooltipValue()).toMatchObject({
+ expect(getTooltipValue()).toStrictEqual({
title: MOCK_TITLE,
placement: 'top',
disabled: false,
@@ -194,20 +190,22 @@ describe('TooltipOnTruncate component', () => {
});
});
- describe('placement', () => {
- it('sets placement when tooltip is rendered', () => {
- const mockPlacement = 'bottom';
-
+ describe('tooltip customization', () => {
+ it.each`
+ property | mockValue
+ ${'placement'} | ${'bottom'}
+ ${'boundary'} | ${'viewport'}
+ `('sets $property when the tooltip is rendered', ({ property, mockValue }) => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({
propsData: {
- placement: mockPlacement,
+ [property]: mockValue,
},
});
expect(hasHorizontalOverflow).toHaveBeenLastCalledWith(wrapper.element);
expect(getTooltipValue()).toMatchObject({
- placement: mockPlacement,
+ [property]: mockValue,
});
});
});
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 f9d615d4f68..c816fe790a8 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
@@ -5,7 +5,7 @@ exports[`Upload dropzone component correctly overrides description and drop mess
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ 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"
type="button"
>
<div
@@ -86,7 +86,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ 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"
type="button"
>
<div
@@ -171,7 +171,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ 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"
type="button"
>
<div
@@ -256,7 +256,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ 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"
type="button"
>
<div
@@ -342,7 +342,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ 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"
type="button"
>
<div
@@ -428,7 +428,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ 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"
type="button"
>
<div
@@ -514,7 +514,7 @@ exports[`Upload dropzone component when no slot provided renders default dropzon
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ 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"
type="button"
>
<div
diff --git a/spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js b/spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js
index a063a5591e3..24f96195e05 100644
--- a/spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js
+++ b/spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js
@@ -3,8 +3,6 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
-jest.mock('~/flash');
-
describe('Upload dropzone component', () => {
let wrapper;
@@ -34,11 +32,6 @@ describe('Upload dropzone component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('when slot provided', () => {
it('renders dropzone with slot content', () => {
createComponent({
diff --git a/spec/frontend/vue_shared/components/url_sync_spec.js b/spec/frontend/vue_shared/components/url_sync_spec.js
index 30a7439579f..2718be74111 100644
--- a/spec/frontend/vue_shared/components/url_sync_spec.js
+++ b/spec/frontend/vue_shared/components/url_sync_spec.js
@@ -33,10 +33,6 @@ describe('url sync component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const expectUrlSyncWithMergeUrlParams = (
query,
times,
diff --git a/spec/frontend/vue_shared/components/usage_quotas/usage_banner_spec.js b/spec/frontend/vue_shared/components/usage_quotas/usage_banner_spec.js
index 662c09d02bf..ba55df5512f 100644
--- a/spec/frontend/vue_shared/components/usage_quotas/usage_banner_spec.js
+++ b/spec/frontend/vue_shared/components/usage_quotas/usage_banner_spec.js
@@ -24,10 +24,6 @@ describe('usage banner', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
slotName | finderFunction
${'left-primary-text'} | ${findLeftPrimaryTextSlot}
diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js
index d63b13981ac..3ae3d89af27 100644
--- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js
+++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js
@@ -20,10 +20,6 @@ describe('User Avatar Image Component', () => {
const findAvatar = () => wrapper.findComponent(GlAvatar);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('Initialization', () => {
beforeEach(() => {
wrapper = shallowMount(UserAvatarImage, {
diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
index df7ce449678..90f9156af38 100644
--- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
+++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
@@ -34,10 +34,6 @@ describe('User Avatar Link Component', () => {
createWrapper();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('should render GlLink with correct props', () => {
const link = wrapper.findComponent(GlAvatarLink);
expect(link.exists()).toBe(true);
diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js
index 63371b1492b..1754292cb63 100644
--- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js
+++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js
@@ -50,10 +50,6 @@ describe('UserAvatarList', () => {
props = { imgSize: TEST_IMAGE_SIZE };
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('empty text', () => {
it('shows when items are empty', () => {
factory({ propsData: { items: [] } });
diff --git a/spec/frontend/vue_shared/components/user_callout_dismisser_spec.js b/spec/frontend/vue_shared/components/user_callout_dismisser_spec.js
index 521744154ba..b04e578c931 100644
--- a/spec/frontend/vue_shared/components/user_callout_dismisser_spec.js
+++ b/spec/frontend/vue_shared/components/user_callout_dismisser_spec.js
@@ -28,8 +28,6 @@ const initialSlotProps = (changes = {}) => ({
});
describe('UserCalloutDismisser', () => {
- let wrapper;
-
const MOCK_FEATURE_NAME = 'mock_feature_name';
// Query handlers
@@ -52,7 +50,7 @@ describe('UserCalloutDismisser', () => {
const callDismissSlotProp = () => defaultScopedSlotSpy.mock.calls[0][0].dismiss();
const createComponent = ({ queryHandler, mutationHandler, ...options }) => {
- wrapper = mount(
+ mount(
UserCalloutDismisser,
merge(
{
@@ -72,10 +70,6 @@ describe('UserCalloutDismisser', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when loading', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list_spec.js b/spec/frontend/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list_spec.js
index 78abb89e7b8..6491e5a66cd 100644
--- a/spec/frontend/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list_spec.js
+++ b/spec/frontend/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list_spec.js
@@ -51,10 +51,6 @@ describe('User deletion obstacles list', () => {
);
}
- afterEach(() => {
- wrapper.destroy();
- });
-
const findLinks = () => wrapper.findAllComponents(GlLink);
const findTitle = () => wrapper.findByTestId('title');
const findFooter = () => wrapper.findByTestId('footer');
diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
index f6316af6ad8..8ecab5cc043 100644
--- a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
+++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
@@ -13,11 +13,11 @@ import {
I18N_ERROR_UNFOLLOW,
} from '~/vue_shared/components/user_popover/constants';
import axios from '~/lib/utils/axios_utils';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import { followUser, unfollowUser } from '~/api/user_api';
import { mockTracking } from 'helpers/tracking_helper';
-jest.mock('~/flash');
+jest.mock('~/alert');
jest.mock('~/api/user_api', () => ({
followUser: jest.fn(),
unfollowUser: jest.fn(),
@@ -51,7 +51,6 @@ describe('User Popover Component', () => {
});
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/vue_shared/components/user_select_spec.js b/spec/frontend/vue_shared/components/user_select_spec.js
index b0e9584a15b..e881bfed35e 100644
--- a/spec/frontend/vue_shared/components/user_select_spec.js
+++ b/spec/frontend/vue_shared/components/user_select_spec.js
@@ -7,7 +7,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import searchUsersQuery from '~/graphql_shared/queries/users_search.query.graphql';
import searchUsersQueryOnMR from '~/graphql_shared/queries/users_search_with_mr_permissions.graphql';
-import { IssuableType } from '~/issues/constants';
+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';
@@ -105,7 +105,6 @@ describe('User select dropdown', () => {
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -409,7 +408,7 @@ describe('User select dropdown', () => {
describe('when on merge request sidebar', () => {
beforeEach(() => {
- createComponent({ props: { issuableType: IssuableType.MergeRequest, issuableId: 1 } });
+ createComponent({ props: { issuableType: TYPE_MERGE_REQUEST, issuableId: 1 } });
return waitForPromises();
});
diff --git a/spec/frontend/vue_shared/components/vuex_module_provider_spec.js b/spec/frontend/vue_shared/components/vuex_module_provider_spec.js
index c136c2054ac..acbb931b7b6 100644
--- a/spec/frontend/vue_shared/components/vuex_module_provider_spec.js
+++ b/spec/frontend/vue_shared/components/vuex_module_provider_spec.js
@@ -27,10 +27,6 @@ describe('~/vue_shared/components/vuex_module_provider', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('provides "vuexModule" set from prop', () => {
createComponent();
expect(findProvidedVuexModule()).toBe(TEST_VUEX_MODULE);
diff --git a/spec/frontend/vue_shared/components/web_ide_link_spec.js b/spec/frontend/vue_shared/components/web_ide_link_spec.js
index 18afe049149..f6eb11aaddf 100644
--- a/spec/frontend/vue_shared/components/web_ide_link_spec.js
+++ b/spec/frontend/vue_shared/components/web_ide_link_spec.js
@@ -137,10 +137,6 @@ describe('Web IDE link component', () => {
localStorage.setItem(PREFERRED_EDITOR_RESET_KEY, 'true');
});
- afterEach(() => {
- wrapper.destroy();
- });
-
const findActionsButton = () => wrapper.findComponent(ActionsButton);
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
const findModal = () => wrapper.findComponent(GlModal);
diff --git a/spec/frontend/vue_shared/directives/validation_spec.js b/spec/frontend/vue_shared/directives/validation_spec.js
index dcd3a44a6fc..72a348c1a79 100644
--- a/spec/frontend/vue_shared/directives/validation_spec.js
+++ b/spec/frontend/vue_shared/directives/validation_spec.js
@@ -80,11 +80,6 @@ describe('validation directive', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const getFormData = () => wrapper.vm.form;
const findForm = () => wrapper.find('form');
const findInput = () => wrapper.find('input');
diff --git a/spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js b/spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js
index 7b0f0f7e344..e983519d9fc 100644
--- a/spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js
+++ b/spec/frontend/vue_shared/issuable/create/components/issuable_create_root_spec.js
@@ -34,10 +34,6 @@ describe('IssuableCreateRoot', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
it('renders component container element with class "issuable-create-container"', () => {
expect(wrapper.classes()).toContain('issuable-create-container');
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 ff21b3bc356..ae2fd5ebffa 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
@@ -36,10 +36,6 @@ describe('IssuableForm', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('methods', () => {
describe('handleUpdateSelectedLabels', () => {
it('sets provided `labels` param to prop `selectedLabels`', () => {
diff --git a/spec/frontend/vue_shared/issuable/create/components/issuable_label_selector_spec.js b/spec/frontend/vue_shared/issuable/create/components/issuable_label_selector_spec.js
index 76b6efa15b6..ce9e23d9a00 100644
--- a/spec/frontend/vue_shared/issuable/create/components/issuable_label_selector_spec.js
+++ b/spec/frontend/vue_shared/issuable/create/components/issuable_label_selector_spec.js
@@ -6,11 +6,8 @@ import {
} from 'jest/sidebar/components/labels/labels_select_widget/mock_data';
import IssuableLabelSelector from '~/vue_shared/issuable/create/components/issuable_label_selector.vue';
import LabelsSelect from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue';
-import {
- DropdownVariant,
- LabelType,
-} from '~/sidebar/components/labels/labels_select_widget/constants';
-import { WorkspaceType } from '~/issues/constants';
+import { DropdownVariant } from '~/sidebar/components/labels/labels_select_widget/constants';
+import { WORKSPACE_PROJECT } from '~/issues/constants';
import { __ } from '~/locale';
const allowLabelRemove = true;
@@ -20,9 +17,9 @@ const fullPath = '/full-path';
const labelsFilterBasePath = '/labels-filter-base-path';
const initialLabels = [];
const issuableType = 'issue';
-const labelType = LabelType.project;
+const labelType = WORKSPACE_PROJECT;
const variant = DropdownVariant.Embedded;
-const workspaceType = WorkspaceType.project;
+const workspaceType = WORKSPACE_PROJECT;
describe('IssuableLabelSelector', () => {
let wrapper;
@@ -50,10 +47,6 @@ describe('IssuableLabelSelector', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const expectTitleWithCount = (count) => {
const title = findTitle();
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 a0b1d64b97c..61e6d2a420a 100644
--- a/spec/frontend/vue_shared/issuable/issuable_blocked_icon_spec.js
+++ b/spec/frontend/vue_shared/issuable/issuable_blocked_icon_spec.js
@@ -7,8 +7,7 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue';
import { blockingIssuablesQueries } from '~/vue_shared/components/issuable_blocked_icon/constants';
-import { issuableTypes } from '~/boards/constants';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
import { truncate } from '~/lib/utils/text_utility';
import {
mockIssue,
@@ -49,11 +48,6 @@ describe('IssuableBlockedIcon', () => {
await waitForApollo();
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const createWrapperWithApollo = ({
item = mockBlockedIssue1,
blockingIssuablesSpy = jest.fn().mockResolvedValue(mockBlockingIssuablesResponse1),
@@ -121,9 +115,9 @@ describe('IssuableBlockedIcon', () => {
};
it.each`
- mockIssuable | issuableType | expectedIcon
- ${mockIssue} | ${TYPE_ISSUE} | ${'issue-block'}
- ${mockEpic} | ${issuableTypes.epic} | ${'entity-blocked'}
+ mockIssuable | issuableType | expectedIcon
+ ${mockIssue} | ${TYPE_ISSUE} | ${'issue-block'}
+ ${mockEpic} | ${TYPE_EPIC} | ${'entity-blocked'}
`(
'should render blocked icon for $issuableType',
({ mockIssuable, issuableType, expectedIcon }) => {
@@ -153,9 +147,9 @@ describe('IssuableBlockedIcon', () => {
describe('on mouseenter on blocked icon', () => {
it.each`
- item | issuableType | mockBlockingIssuable | issuableItem | blockingIssuablesSpy
- ${mockBlockedIssue1} | ${TYPE_ISSUE} | ${mockBlockingIssue1} | ${mockIssue} | ${jest.fn().mockResolvedValue(mockBlockingIssuablesResponse1)}
- ${mockBlockedEpic1} | ${issuableTypes.epic} | ${mockBlockingEpic1} | ${mockEpic} | ${jest.fn().mockResolvedValue(mockBlockingEpicIssuablesResponse1)}
+ item | issuableType | mockBlockingIssuable | issuableItem | blockingIssuablesSpy
+ ${mockBlockedIssue1} | ${TYPE_ISSUE} | ${mockBlockingIssue1} | ${mockIssue} | ${jest.fn().mockResolvedValue(mockBlockingIssuablesResponse1)}
+ ${mockBlockedEpic1} | ${TYPE_EPIC} | ${mockBlockingEpic1} | ${mockEpic} | ${jest.fn().mockResolvedValue(mockBlockingEpicIssuablesResponse1)}
`(
'should query for blocking issuables and render the result for $issuableType',
async ({ item, issuableType, issuableItem, mockBlockingIssuable, blockingIssuablesSpy }) => {
diff --git a/spec/frontend/vue_shared/issuable/list/components/issuable_bulk_edit_sidebar_spec.js b/spec/frontend/vue_shared/issuable/list/components/issuable_bulk_edit_sidebar_spec.js
index a25f92c9cf2..c23bd002ee5 100644
--- a/spec/frontend/vue_shared/issuable/list/components/issuable_bulk_edit_sidebar_spec.js
+++ b/spec/frontend/vue_shared/issuable/list/components/issuable_bulk_edit_sidebar_spec.js
@@ -28,7 +28,6 @@ describe('IssuableBulkEditSidebar', () => {
});
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
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 2fac004875a..45daf0dc34b 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
@@ -39,7 +39,6 @@ describe('IssuableItem', () => {
const mockLabels = mockIssuable.labels.nodes;
const mockAuthor = mockIssuable.author;
- const originalUrl = gon.gitlab_url;
let wrapper;
const findTimestampWrapper = () => wrapper.find('[data-testid="issuable-timestamp"]');
@@ -49,11 +48,6 @@ describe('IssuableItem', () => {
gon.gitlab_url = MOCK_GITLAB_URL;
});
- afterEach(() => {
- wrapper.destroy();
- gon.gitlab_url = originalUrl;
- });
-
describe('computed', () => {
describe('author', () => {
it('returns `issuable.author` reference', () => {
diff --git a/spec/frontend/vue_shared/issuable/list/components/issuable_list_root_spec.js b/spec/frontend/vue_shared/issuable/list/components/issuable_list_root_spec.js
index 371844e66f4..9a4636e0f4d 100644
--- a/spec/frontend/vue_shared/issuable/list/components/issuable_list_root_spec.js
+++ b/spec/frontend/vue_shared/issuable/list/components/issuable_list_root_spec.js
@@ -47,10 +47,6 @@ describe('IssuableListRoot', () => {
const findVueDraggable = () => wrapper.findComponent(VueDraggable);
const findPageSizeSelector = () => wrapper.findComponent(PageSizeSelector);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
beforeEach(() => {
wrapper = createComponent();
diff --git a/spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js b/spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js
index 27985895c62..9cdd4d75c42 100644
--- a/spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js
+++ b/spec/frontend/vue_shared/issuable/list/components/issuable_tabs_spec.js
@@ -35,7 +35,6 @@ describe('IssuableTabs', () => {
afterEach(() => {
setLanguage(null);
- wrapper.destroy();
});
const findAllGlBadges = () => wrapper.findAllComponents(GlBadge);
diff --git a/spec/frontend/vue_shared/issuable/show/components/issuable_body_spec.js b/spec/frontend/vue_shared/issuable/show/components/issuable_body_spec.js
index 6b20f0c77a3..7e665b7c76e 100644
--- a/spec/frontend/vue_shared/issuable/show/components/issuable_body_spec.js
+++ b/spec/frontend/vue_shared/issuable/show/components/issuable_body_spec.js
@@ -13,7 +13,7 @@ import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { mockIssuableShowProps, mockIssuable } from '../mock_data';
jest.mock('~/autosave');
-jest.mock('~/flash');
+jest.mock('~/alert');
const issuableBodyProps = {
...mockIssuableShowProps,
@@ -48,10 +48,6 @@ describe('IssuableBody', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('computed', () => {
describe('isUpdated', () => {
it.each`
diff --git a/spec/frontend/vue_shared/issuable/show/components/issuable_description_spec.js b/spec/frontend/vue_shared/issuable/show/components/issuable_description_spec.js
index ea58cc2baf5..b4f1c286158 100644
--- a/spec/frontend/vue_shared/issuable/show/components/issuable_description_spec.js
+++ b/spec/frontend/vue_shared/issuable/show/components/issuable_description_spec.js
@@ -24,10 +24,6 @@ describe('IssuableDescription', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('mounted', () => {
it('calls `renderGFM`', () => {
expect(renderGFM).toHaveBeenCalledTimes(1);
diff --git a/spec/frontend/vue_shared/issuable/show/components/issuable_edit_form_spec.js b/spec/frontend/vue_shared/issuable/show/components/issuable_edit_form_spec.js
index 159be4cd1ef..0d6cd1ad00b 100644
--- a/spec/frontend/vue_shared/issuable/show/components/issuable_edit_form_spec.js
+++ b/spec/frontend/vue_shared/issuable/show/components/issuable_edit_form_spec.js
@@ -43,6 +43,9 @@ describe('IssuableEditForm', () => {
});
afterEach(() => {
+ // note: the order of wrapper.destroy() and jest.resetAllMocks() matters.
+ // maybe it'll help with investigation on how to remove this wrapper.destroy() call
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
wrapper.destroy();
jest.resetAllMocks();
});
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 6a8b9ef77a9..d9f1b6c15a8 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
@@ -33,7 +33,6 @@ describe('IssuableHeader', () => {
};
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/vue_shared/issuable/show/components/issuable_show_root_spec.js b/spec/frontend/vue_shared/issuable/show/components/issuable_show_root_spec.js
index edfd55c8bb4..f976e0499f0 100644
--- a/spec/frontend/vue_shared/issuable/show/components/issuable_show_root_spec.js
+++ b/spec/frontend/vue_shared/issuable/show/components/issuable_show_root_spec.js
@@ -41,10 +41,6 @@ describe('IssuableShowRoot', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('template', () => {
const {
statusIcon,
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 6f62fb77353..39316dfa249 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
@@ -22,35 +22,35 @@ const createComponent = (propsData = issuableTitleProps) =>
'status-badge': 'Open',
},
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
describe('IssuableTitle', () => {
let wrapper;
+ const findStickyHeader = () => wrapper.findComponent('[data-testid="header"]');
+
beforeEach(() => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('methods', () => {
describe('handleTitleAppear', () => {
- it('sets value of `stickyTitleVisible` prop to false', () => {
+ it('sets value of `stickyTitleVisible` prop to false', async () => {
wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
+ await nextTick();
- expect(wrapper.vm.stickyTitleVisible).toBe(false);
+ expect(findStickyHeader().exists()).toBe(false);
});
});
describe('handleTitleDisappear', () => {
- it('sets value of `stickyTitleVisible` prop to true', () => {
+ it('sets value of `stickyTitleVisible` prop to true', async () => {
wrapper.findComponent(GlIntersectionObserver).vm.$emit('disappear');
+ await nextTick();
- expect(wrapper.vm.stickyTitleVisible).toBe(true);
+ expect(findStickyHeader().exists()).toBe(true);
});
});
});
@@ -87,14 +87,10 @@ describe('IssuableTitle', () => {
});
it('renders sticky header when `stickyTitleVisible` prop is true', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- stickyTitleVisible: true,
- });
-
+ wrapper.findComponent(GlIntersectionObserver).vm.$emit('disappear');
await nextTick();
- const stickyHeaderEl = wrapper.find('[data-testid="header"]');
+
+ const stickyHeaderEl = findStickyHeader();
expect(stickyHeaderEl.exists()).toBe(true);
expect(stickyHeaderEl.findComponent(GlBadge).props('variant')).toBe('success');
diff --git a/spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js b/spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js
index 6c9e5f85fa0..f2509aead77 100644
--- a/spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js
+++ b/spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js
@@ -38,7 +38,6 @@ describe('IssuableSidebarRoot', () => {
};
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
});
diff --git a/spec/frontend/vue_shared/new_namespace/components/legacy_container_spec.js b/spec/frontend/vue_shared/new_namespace/components/legacy_container_spec.js
index 52f36aa0e77..052ff518468 100644
--- a/spec/frontend/vue_shared/new_namespace/components/legacy_container_spec.js
+++ b/spec/frontend/vue_shared/new_namespace/components/legacy_container_spec.js
@@ -11,9 +11,7 @@ describe('Legacy container component', () => {
};
afterEach(() => {
- wrapper.destroy();
resetHTMLFixture();
- wrapper = null;
});
describe('when selector targets real node', () => {
diff --git a/spec/frontend/vue_shared/new_namespace/components/welcome_spec.js b/spec/frontend/vue_shared/new_namespace/components/welcome_spec.js
index c90131fea9a..cc8a8d86d19 100644
--- a/spec/frontend/vue_shared/new_namespace/components/welcome_spec.js
+++ b/spec/frontend/vue_shared/new_namespace/components/welcome_spec.js
@@ -27,9 +27,7 @@ describe('Welcome page', () => {
});
afterEach(() => {
- wrapper.destroy();
window.location.hash = '';
- wrapper = null;
});
it('tracks link clicks', async () => {
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 6115dc6e61b..5ff7b9f390a 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
@@ -14,7 +14,7 @@ describe('Experimental new project creation app', () => {
const DEFAULT_PROPS = {
title: 'Create something',
- initialBreadcrumb: 'Something',
+ initialBreadcrumbs: [{ text: 'Something', href: '#' }],
panels: [
{ name: 'panel1', selector: '#some-selector1' },
{ name: 'panel2', selector: '#some-selector2' },
@@ -33,7 +33,6 @@ describe('Experimental new project creation app', () => {
};
afterEach(() => {
- wrapper.destroy();
window.location.hash = '';
});
@@ -46,8 +45,8 @@ describe('Experimental new project creation app', () => {
expect(findWelcomePage().exists()).toBe(true);
});
- it('does not render breadcrumbs', () => {
- expect(findBreadcrumb().exists()).toBe(false);
+ it('renders breadcrumbs', () => {
+ expect(findBreadcrumb().exists()).toBe(true);
});
});
@@ -75,7 +74,7 @@ describe('Experimental new project creation app', () => {
it('renders breadcrumbs', () => {
const breadcrumb = findBreadcrumb();
expect(breadcrumb.exists()).toBe(true);
- expect(breadcrumb.props().items[0].text).toBe(DEFAULT_PROPS.initialBreadcrumb);
+ expect(breadcrumb.props().items[0].text).toBe(DEFAULT_PROPS.initialBreadcrumbs[0].text);
});
});
diff --git a/spec/frontend/vue_shared/plugins/global_toast_spec.js b/spec/frontend/vue_shared/plugins/global_toast_spec.js
index 322586a772c..0bf2737fb2b 100644
--- a/spec/frontend/vue_shared/plugins/global_toast_spec.js
+++ b/spec/frontend/vue_shared/plugins/global_toast_spec.js
@@ -1,14 +1,16 @@
-import toast, { instance } from '~/vue_shared/plugins/global_toast';
+import toast from '~/vue_shared/plugins/global_toast';
-describe('Global toast', () => {
- let spyFunc;
-
- beforeEach(() => {
- spyFunc = jest.spyOn(instance.$toast, 'show').mockImplementation(() => {});
- });
+const mockSpy = jest.fn();
+jest.mock('@gitlab/ui', () => ({
+ GlToast: (Vue) => {
+ // eslint-disable-next-line no-param-reassign
+ Vue.prototype.$toast = { show: (...args) => mockSpy(...args) };
+ },
+}));
+describe('Global toast', () => {
afterEach(() => {
- spyFunc.mockRestore();
+ mockSpy.mockRestore();
});
it("should call GitLab UI's toast method", () => {
@@ -17,7 +19,7 @@ describe('Global toast', () => {
toast(arg1, arg2);
- expect(instance.$toast.show).toHaveBeenCalledTimes(1);
- expect(instance.$toast.show).toHaveBeenCalledWith(arg1, arg2);
+ expect(mockSpy).toHaveBeenCalledTimes(1);
+ expect(mockSpy).toHaveBeenCalledWith(arg1, arg2);
});
});
diff --git a/spec/frontend/vue_shared/security_configuration/components/section_layout_spec.js b/spec/frontend/vue_shared/security_configuration/components/section_layout_spec.js
index 136fe74b0d6..d258658d5e2 100644
--- a/spec/frontend/vue_shared/security_configuration/components/section_layout_spec.js
+++ b/spec/frontend/vue_shared/security_configuration/components/section_layout_spec.js
@@ -21,10 +21,6 @@ describe('Section Layout component', () => {
const findHeading = () => wrapper.find('h2');
const findLoader = () => wrapper.findComponent(SectionLoader);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('basic structure', () => {
beforeEach(() => {
createComponent({ heading: 'testheading' });
diff --git a/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js b/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js
index 0a5e46d9263..6345393951c 100644
--- a/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js
+++ b/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js
@@ -56,10 +56,6 @@ describe('ManageViaMr component', () => {
);
}
- afterEach(() => {
- wrapper.destroy();
- });
-
// This component supports different report types/mutations depending on
// whether it's in a CE or EE context. This makes sure we are only testing
// the ones available in the current test context.
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 5f2b13a79c9..299a3d62421 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
@@ -15,11 +15,6 @@ describe('SecurityReportDownloadDropdown component', () => {
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('given report artifacts', () => {
beforeEach(() => {
artifacts = [
diff --git a/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js b/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js
index 221da35de3d..257f59612e8 100644
--- a/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js
+++ b/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js
@@ -14,7 +14,7 @@ import {
sastDiffSuccessMock,
secretDetectionDiffSuccessMock,
} from 'jest/vue_shared/security_reports/mock_data';
-import { createAlert } from '~/flash';
+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 HelpIcon from '~/vue_shared/security_reports/components/help_icon.vue';
@@ -26,7 +26,7 @@ import {
import securityReportMergeRequestDownloadPathsQuery from '~/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql';
import SecurityReportsApp from '~/vue_shared/security_reports/security_reports_app.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
Vue.use(VueApollo);
Vue.use(Vuex);
@@ -74,10 +74,6 @@ describe('Security reports app', () => {
const findDownloadDropdown = () => wrapper.findComponent(SecurityReportDownloadDropdown);
const findHelpIconComponent = () => wrapper.findComponent(HelpIcon);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('given the artifacts query is loading', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/webhooks/components/form_url_app_spec.js b/spec/frontend/webhooks/components/form_url_app_spec.js
index 45a39d2dd58..cbeff184e9d 100644
--- a/spec/frontend/webhooks/components/form_url_app_spec.js
+++ b/spec/frontend/webhooks/components/form_url_app_spec.js
@@ -19,10 +19,6 @@ describe('FormUrlApp', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findAllRadioButtons = () => wrapper.findAllComponents(GlFormRadio);
const findRadioGroup = () => wrapper.findComponent(GlFormRadioGroup);
const findUrlMaskDisable = () => findAllRadioButtons().at(0);
diff --git a/spec/frontend/whats_new/components/app_spec.js b/spec/frontend/whats_new/components/app_spec.js
index ee15034daff..000b07f4dfd 100644
--- a/spec/frontend/whats_new/components/app_spec.js
+++ b/spec/frontend/whats_new/components/app_spec.js
@@ -49,7 +49,7 @@ describe('App', () => {
store,
propsData: buildProps(),
directives: {
- GlResizeObserver: createMockDirective(),
+ GlResizeObserver: createMockDirective('gl-resize-observer'),
},
});
};
@@ -71,7 +71,6 @@ describe('App', () => {
};
afterEach(() => {
- wrapper.destroy();
unmockTracking();
});
diff --git a/spec/frontend/whats_new/components/feature_spec.js b/spec/frontend/whats_new/components/feature_spec.js
index 099054bf8ca..d69ac2803df 100644
--- a/spec/frontend/whats_new/components/feature_spec.js
+++ b/spec/frontend/whats_new/components/feature_spec.js
@@ -30,11 +30,6 @@ describe("What's new single feature", () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
it('renders the date', () => {
createWrapper({ feature: exampleFeature });
diff --git a/spec/frontend/whats_new/utils/get_drawer_body_height_spec.js b/spec/frontend/whats_new/utils/get_drawer_body_height_spec.js
index b199f4f0c49..79717b8767e 100644
--- a/spec/frontend/whats_new/utils/get_drawer_body_height_spec.js
+++ b/spec/frontend/whats_new/utils/get_drawer_body_height_spec.js
@@ -11,10 +11,6 @@ describe('~/whats_new/utils/get_drawer_body_height', () => {
});
});
- afterEach(() => {
- drawerWrapper.destroy();
- });
-
const setClientHeight = (el, height) => {
Object.defineProperty(el, 'clientHeight', {
get() {
diff --git a/spec/frontend/work_items/components/app_spec.js b/spec/frontend/work_items/components/app_spec.js
index 95034085493..d799e8042b1 100644
--- a/spec/frontend/work_items/components/app_spec.js
+++ b/spec/frontend/work_items/components/app_spec.js
@@ -12,10 +12,6 @@ describe('Work Items Application', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a component', () => {
createComponent();
diff --git a/spec/frontend/work_items/components/item_state_spec.js b/spec/frontend/work_items/components/item_state_spec.js
index c3cc2fbc556..c3bdbfe030e 100644
--- a/spec/frontend/work_items/components/item_state_spec.js
+++ b/spec/frontend/work_items/components/item_state_spec.js
@@ -21,10 +21,6 @@ describe('ItemState', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders label and dropdown', () => {
createComponent();
diff --git a/spec/frontend/work_items/components/item_title_spec.js b/spec/frontend/work_items/components/item_title_spec.js
index 6361f8dafc4..aef310319ab 100644
--- a/spec/frontend/work_items/components/item_title_spec.js
+++ b/spec/frontend/work_items/components/item_title_spec.js
@@ -19,10 +19,6 @@ describe('ItemTitle', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders title contents', () => {
expect(findInputEl().attributes()).toMatchObject({
'data-placeholder': 'Add a title...',
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 5901642b8a1..1c01451f047 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,3 @@
// 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\\"></note-header-stub>"`;
+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=\\"\\"></note-header-stub>"`;
diff --git a/spec/frontend/work_items/components/notes/activity_filter_spec.js b/spec/frontend/work_items/components/notes/activity_filter_spec.js
deleted file mode 100644
index eb4bcbf942b..00000000000
--- a/spec/frontend/work_items/components/notes/activity_filter_spec.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { nextTick } from 'vue';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import ActivityFilter from '~/work_items/components/notes/activity_filter.vue';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-import { ASC, DESC } from '~/notes/constants';
-
-import { mockTracking } from 'helpers/tracking_helper';
-import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
-
-describe('Activity Filter', () => {
- let wrapper;
-
- const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findNewestFirstItem = () => wrapper.findByTestId('js-newest-first');
-
- const createComponent = ({ sortOrder = ASC, loading = false, workItemType = 'Task' } = {}) => {
- wrapper = shallowMountExtended(ActivityFilter, {
- propsData: {
- sortOrder,
- loading,
- workItemType,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- describe('default', () => {
- it('has a dropdown with 2 options', () => {
- expect(findDropdown().exists()).toBe(true);
- expect(findAllDropdownItems()).toHaveLength(ActivityFilter.SORT_OPTIONS.length);
- });
-
- it('has local storage sync with the correct props', () => {
- expect(findLocalStorageSync().props('asString')).toBe(true);
- });
-
- it('emits `updateSavedSortOrder` event when update is emitted', async () => {
- findLocalStorageSync().vm.$emit('input', ASC);
-
- await nextTick();
- expect(wrapper.emitted('updateSavedSortOrder')).toHaveLength(1);
- expect(wrapper.emitted('updateSavedSortOrder')).toEqual([[ASC]]);
- });
- });
-
- describe('when asc', () => {
- describe('when the dropdown is clicked', () => {
- it('calls the right actions', async () => {
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- findNewestFirstItem().vm.$emit('click');
- await nextTick();
-
- expect(wrapper.emitted('changeSortOrder')).toHaveLength(1);
- expect(wrapper.emitted('changeSortOrder')).toEqual([[DESC]]);
-
- expect(trackingSpy).toHaveBeenCalledWith(
- TRACKING_CATEGORY_SHOW,
- 'notes_sort_order_changed',
- {
- category: TRACKING_CATEGORY_SHOW,
- label: 'item_track_notes_sorting',
- property: 'type_Task',
- },
- );
- });
- });
- });
-});
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
new file mode 100644
index 00000000000..5ed9d581446
--- /dev/null
+++ b/spec/frontend/work_items/components/notes/work_item_activity_sort_filter_spec.js
@@ -0,0 +1,109 @@
+import { GlDropdown, GlDropdownItem } 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';
+import { ASC, DESC } from '~/notes/constants';
+import {
+ WORK_ITEM_ACTIVITY_SORT_OPTIONS,
+ WORK_ITEM_NOTES_SORT_ORDER_KEY,
+ WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS,
+ WORK_ITEM_NOTES_FILTER_KEY,
+ WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ WORK_ITEM_ACTIVITY_FILTER_OPTIONS,
+ TRACKING_CATEGORY_SHOW,
+} from '~/work_items/constants';
+
+import { mockTracking } from 'helpers/tracking_helper';
+
+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 createComponent = ({
+ loading = false,
+ workItemType = 'Task',
+ sortFilterProp = ASC,
+ filterOptions = WORK_ITEM_ACTIVITY_SORT_OPTIONS,
+ trackingLabel = 'item_track_notes_sorting',
+ trackingAction = 'work_item_notes_sort_order_changed',
+ filterEvent = 'changeSort',
+ defaultSortFilterProp = ASC,
+ storageKey = WORK_ITEM_NOTES_SORT_ORDER_KEY,
+ } = {}) => {
+ wrapper = shallowMountExtended(WorkItemActivitySortFilter, {
+ propsData: {
+ loading,
+ workItemType,
+ sortFilterProp,
+ filterOptions,
+ trackingLabel,
+ trackingAction,
+ filterEvent,
+ defaultSortFilterProp,
+ storageKey,
+ },
+ });
+ };
+
+ 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'}
+ `(
+ 'When used for $usedFor',
+ ({
+ filterOptions,
+ storageKey,
+ filterEvent,
+ trackingLabel,
+ trackingAction,
+ newInputOption,
+ defaultSortFilterProp,
+ sortFilterProp,
+ nonDefaultDataTestId,
+ }) => {
+ beforeEach(() => {
+ createComponent({
+ sortFilterProp,
+ filterOptions,
+ trackingLabel,
+ trackingAction,
+ filterEvent,
+ defaultSortFilterProp,
+ storageKey,
+ });
+ });
+
+ it('has a dropdown with options equal to the length of `filterOptions`', () => {
+ expect(findDropdown().exists()).toBe(true);
+ expect(findAllDropdownItems()).toHaveLength(filterOptions.length);
+ });
+
+ it('has local storage sync with the correct props', () => {
+ expect(findLocalStorageSync().props('asString')).toBe(true);
+ expect(findLocalStorageSync().props('storageKey')).toBe(storageKey);
+ });
+
+ it(`emits ${filterEvent} event when local storage input is emitted`, () => {
+ findLocalStorageSync().vm.$emit('input', newInputOption);
+
+ expect(wrapper.emitted(filterEvent)).toEqual([[newInputOption]]);
+ });
+
+ 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');
+
+ expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, trackingAction, {
+ category: TRACKING_CATEGORY_SHOW,
+ label: trackingLabel,
+ property: 'type_Task',
+ });
+ });
+ },
+ );
+});
diff --git a/spec/frontend/work_items/components/notes/work_item_discussion_spec.js b/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
index bb65b75c4d8..6b95da0910b 100644
--- a/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
@@ -1,7 +1,5 @@
-import { GlAvatarLink, GlAvatar } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
-import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import ToggleRepliesWidget from '~/notes/components/toggle_replies_widget.vue';
import WorkItemDiscussion from '~/work_items/components/notes/work_item_discussion.vue';
import WorkItemNote from '~/work_items/components/notes/work_item_note.vue';
@@ -21,9 +19,6 @@ describe('Work Item Discussion', () => {
let wrapper;
const mockWorkItemId = 'gid://gitlab/WorkItem/625';
- const findTimelineEntryItem = () => wrapper.findComponent(TimelineEntryItem);
- const findAvatarLink = () => wrapper.findComponent(GlAvatarLink);
- const findAvatar = () => wrapper.findComponent(GlAvatar);
const findToggleRepliesWidget = () => wrapper.findComponent(ToggleRepliesWidget);
const findAllThreads = () => wrapper.findAllComponents(WorkItemNote);
const findThreadAtIndex = (index) => findAllThreads().at(index);
@@ -55,19 +50,6 @@ describe('Work Item Discussion', () => {
createComponent();
});
- it('Should be wrapped inside the timeline entry item', () => {
- expect(findTimelineEntryItem().exists()).toBe(true);
- });
-
- it('should have the author avatar of the work item note', () => {
- expect(findAvatarLink().exists()).toBe(true);
- expect(findAvatarLink().attributes('href')).toBe(mockWorkItemCommentNote.author.webUrl);
-
- expect(findAvatar().exists()).toBe(true);
- expect(findAvatar().props('src')).toBe(mockWorkItemCommentNote.author.avatarUrl);
- expect(findAvatar().props('entityName')).toBe(mockWorkItemCommentNote.author.username);
- });
-
it('should not show the the toggle replies widget wrapper when no replies', () => {
expect(findToggleRepliesWidget().exists()).toBe(false);
});
@@ -89,13 +71,17 @@ describe('Work Item Discussion', () => {
});
it('the number of threads should be equal to the response length', async () => {
- findToggleRepliesWidget().vm.$emit('toggle');
- await nextTick();
expect(findAllThreads()).toHaveLength(
mockWorkItemNotesWidgetResponseWithComments.discussions.nodes[0].notes.nodes.length,
);
});
+ it('should collapse when we click on toggle replies widget', async () => {
+ findToggleRepliesWidget().vm.$emit('toggle');
+ await nextTick();
+ expect(findAllThreads()).toHaveLength(1);
+ });
+
it('should autofocus when we click expand replies', async () => {
const mainComment = findThreadAtIndex(0);
diff --git a/spec/frontend/work_items/components/notes/work_item_history_only_filter_note_spec.js b/spec/frontend/work_items/components/notes/work_item_history_only_filter_note_spec.js
new file mode 100644
index 00000000000..339efad0608
--- /dev/null
+++ b/spec/frontend/work_items/components/notes/work_item_history_only_filter_note_spec.js
@@ -0,0 +1,44 @@
+import { GlSprintf } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import WorkItemHistoryOnlyFilterNote from '~/work_items/components/notes/work_item_history_only_filter_note.vue';
+import {
+ WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS,
+} from '~/work_items/constants';
+
+describe('Work Item History Filter note', () => {
+ let wrapper;
+
+ const findShowAllActivityButton = () => wrapper.findByTestId('show-all-activity');
+ const findShowCommentsButton = () => wrapper.findByTestId('show-comments-only');
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(WorkItemHistoryOnlyFilterNote, {
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('timelineContent renders a string containing instruction for switching feed type', () => {
+ expect(wrapper.text()).toContain(
+ "You're only seeing other activity in the feed. To add a comment, switch to one of the following options.",
+ );
+ });
+
+ it('emits `changeFilter` event with 0 parameter on clicking Show all activity button', () => {
+ findShowAllActivityButton().vm.$emit('click');
+
+ expect(wrapper.emitted('changeFilter')).toEqual([[WORK_ITEM_NOTES_FILTER_ALL_NOTES]]);
+ });
+
+ it('emits `changeFilter` event with 1 parameter on clicking Show comments only button', () => {
+ findShowCommentsButton().vm.$emit('click');
+
+ expect(wrapper.emitted('changeFilter')).toEqual([[WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS]]);
+ });
+});
diff --git a/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js b/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js
index d85cd46c1c3..b293127b6af 100644
--- a/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js
@@ -1,52 +1,116 @@
import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import EmojiPicker from '~/emoji/components/picker.vue';
+import waitForPromises from 'helpers/wait_for_promises';
import ReplyButton from '~/notes/components/note_actions/reply_button.vue';
import WorkItemNoteActions from '~/work_items/components/notes/work_item_note_actions.vue';
+import addAwardEmojiMutation from '~/work_items/graphql/notes/work_item_note_add_award_emoji.mutation.graphql';
+
+Vue.use(VueApollo);
describe('Work Item Note Actions', () => {
let wrapper;
+ const noteId = '1';
const findReplyButton = () => wrapper.findComponent(ReplyButton);
const findEditButton = () => wrapper.find('[data-testid="edit-work-item-note"]');
+ const findEmojiButton = () => wrapper.find('[data-testid="note-emoji-button"]');
+
+ const addEmojiMutationResolver = jest.fn().mockResolvedValue({
+ data: {
+ errors: [],
+ },
+ });
+
+ const EmojiPickerStub = {
+ props: EmojiPicker.props,
+ template: '<div></div>',
+ };
- const createComponent = ({ showReply = true, showEdit = true } = {}) => {
+ const createComponent = ({ showReply = true, showEdit = true, showAwardEmoji = true } = {}) => {
wrapper = shallowMount(WorkItemNoteActions, {
propsData: {
showReply,
showEdit,
+ noteId,
+ showAwardEmoji,
+ },
+ provide: {
+ glFeatures: {
+ workItemsMvc2: true,
+ },
},
+ stubs: {
+ EmojiPicker: EmojiPickerStub,
+ },
+ apolloProvider: createMockApollo([[addAwardEmojiMutation, addEmojiMutationResolver]]),
});
};
- describe('Default', () => {
- it('Should show the reply button by default', () => {
+ describe('reply button', () => {
+ it('is visible by default', () => {
createComponent();
+
expect(findReplyButton().exists()).toBe(true);
});
- });
- describe('When the reply button needs to be hidden', () => {
- it('Should show the reply button by default', () => {
+ it('is hidden when showReply false', () => {
createComponent({ showReply: false });
+
expect(findReplyButton().exists()).toBe(false);
});
});
- it('shows edit button when `showEdit` prop is true', () => {
- createComponent();
+ describe('edit button', () => {
+ it('is visible when `showEdit` prop is true', () => {
+ createComponent();
- expect(findEditButton().exists()).toBe(true);
- });
+ expect(findEditButton().exists()).toBe(true);
+ });
+
+ it('is hidden when `showEdit` prop is false', () => {
+ createComponent({ showEdit: false });
+
+ expect(findEditButton().exists()).toBe(false);
+ });
- it('does not show edit button when `showEdit` prop is false', () => {
- createComponent({ showEdit: false });
+ it('emits `startEditing` event when clicked', () => {
+ createComponent();
+ findEditButton().vm.$emit('click');
- expect(findEditButton().exists()).toBe(false);
+ expect(wrapper.emitted('startEditing')).toEqual([[]]);
+ });
});
- it('emits `startEditing` event when edit button is clicked', () => {
- createComponent();
- findEditButton().vm.$emit('click');
+ describe('emoji picker', () => {
+ it('is visible when `showAwardEmoji` prop is true', () => {
+ createComponent();
+
+ expect(findEmojiButton().exists()).toBe(true);
+ });
+
+ it('is hidden when `showAwardEmoji` prop is false', () => {
+ createComponent({ showAwardEmoji: false });
- expect(wrapper.emitted('startEditing')).toEqual([[]]);
+ expect(findEmojiButton().exists()).toBe(false);
+ });
+
+ it('commits mutation on click', async () => {
+ const awardName = 'carrot';
+
+ createComponent();
+
+ findEmojiButton().vm.$emit('click', awardName);
+
+ await waitForPromises();
+
+ expect(findEmojiButton().emitted('errors')).toEqual(undefined);
+ expect(addEmojiMutationResolver).toHaveBeenCalledWith({
+ awardableId: noteId,
+ name: awardName,
+ });
+ });
});
});
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 9b87419cee7..8e574dc1a81 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
@@ -198,10 +198,6 @@ describe('Work Item Note', () => {
expect(findNoteActions().exists()).toBe(true);
});
- it('should not have the Avatar link for main thread inside the timeline-entry', () => {
- expect(findAuthorAvatarLink().exists()).toBe(false);
- });
-
it('should have the reply button props', () => {
expect(findNoteActions().props('showReply')).toBe(true);
});
@@ -228,7 +224,7 @@ describe('Work Item Note', () => {
});
});
- it('should display a dropdown if user has a permission to delete a note', () => {
+ it('should display the `Delete comment` dropdown item if user has a permission to delete a note', () => {
createComponent({
note: {
...mockWorkItemCommentNote,
@@ -237,12 +233,14 @@ describe('Work Item Note', () => {
});
expect(findDropdown().exists()).toBe(true);
+ expect(findDeleteNoteButton().exists()).toBe(true);
});
- it('should not display a dropdown if user has no permission to delete a note', () => {
+ it('should not display the `Delete comment` dropdown item if user has no permission to delete a note', () => {
createComponent();
- expect(findDropdown().exists()).toBe(false);
+ expect(findDropdown().exists()).toBe(true);
+ expect(findDeleteNoteButton().exists()).toBe(false);
});
it('should emit `deleteNote` event when delete note action is clicked', () => {
diff --git a/spec/frontend/work_items/components/notes/work_item_notes_activity_header_spec.js b/spec/frontend/work_items/components/notes/work_item_notes_activity_header_spec.js
new file mode 100644
index 00000000000..daf74f7a93b
--- /dev/null
+++ b/spec/frontend/work_items/components/notes/work_item_notes_activity_header_spec.js
@@ -0,0 +1,63 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import WorkItemNotesActivityHeader from '~/work_items/components/notes/work_item_notes_activity_header.vue';
+import { ASC } from '~/notes/constants';
+import {
+ WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ WORK_ITEM_NOTES_FILTER_ONLY_HISTORY,
+} from '~/work_items/constants';
+
+describe('Work Item Note Activity Header', () => {
+ let wrapper;
+
+ const findActivityLabelHeading = () => wrapper.find('h3');
+ const findActivityFilterDropdown = () => wrapper.findByTestId('work-item-filter');
+ const findActivitySortDropdown = () => wrapper.findByTestId('work-item-sort');
+
+ const createComponent = ({
+ disableActivityFilterSort = false,
+ sortOrder = ASC,
+ workItemType = 'Task',
+ discussionFilter = WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ } = {}) => {
+ wrapper = shallowMountExtended(WorkItemNotesActivityHeader, {
+ propsData: {
+ disableActivityFilterSort,
+ sortOrder,
+ workItemType,
+ discussionFilter,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('Should have the Activity label', () => {
+ expect(findActivityLabelHeading().text()).toBe(WorkItemNotesActivityHeader.i18n.activityLabel);
+ });
+
+ it('Should have Activity filtering dropdown', () => {
+ expect(findActivityFilterDropdown().exists()).toBe(true);
+ });
+
+ it('Should have Activity sorting dropdown', () => {
+ expect(findActivitySortDropdown().exists()).toBe(true);
+ });
+
+ describe('Activity Filter', () => {
+ it('emits `changeFilter` when filtering discussions', () => {
+ findActivityFilterDropdown().vm.$emit('changeFilter', WORK_ITEM_NOTES_FILTER_ONLY_HISTORY);
+
+ expect(wrapper.emitted('changeFilter')).toEqual([[WORK_ITEM_NOTES_FILTER_ONLY_HISTORY]]);
+ });
+ });
+
+ describe('Activity Sorting', () => {
+ it('emits `changeSort` when sorting discussions/activity', () => {
+ findActivitySortDropdown().vm.$emit('changeSort', ASC);
+
+ expect(wrapper.emitted('changeSort')).toEqual([[ASC]]);
+ });
+ });
+});
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 3c312fb4552..a0db8172bf6 100644
--- a/spec/frontend/work_items/components/work_item_actions_spec.js
+++ b/spec/frontend/work_items/components/work_item_actions_spec.js
@@ -52,10 +52,6 @@ describe('WorkItemActions component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders modal', () => {
createComponent();
diff --git a/spec/frontend/work_items/components/work_item_assignees_spec.js b/spec/frontend/work_items/components/work_item_assignees_spec.js
index e85f62b881d..2a8159f7294 100644
--- a/spec/frontend/work_items/components/work_item_assignees_spec.js
+++ b/spec/frontend/work_items/components/work_item_assignees_spec.js
@@ -113,10 +113,6 @@ describe('WorkItemAssignees component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('passes the correct data-user-id attribute', () => {
createComponent();
diff --git a/spec/frontend/work_items/components/work_item_description_rendered_spec.js b/spec/frontend/work_items/components/work_item_description_rendered_spec.js
index 0ab2546440b..4f1d49ee2e5 100644
--- a/spec/frontend/work_items/components/work_item_description_rendered_spec.js
+++ b/spec/frontend/work_items/components/work_item_description_rendered_spec.js
@@ -29,10 +29,6 @@ describe('WorkItemDescription', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders gfm', async () => {
createComponent();
diff --git a/spec/frontend/work_items/components/work_item_description_spec.js b/spec/frontend/work_items/components/work_item_description_spec.js
index a12ec23c15a..b4b7b8989ea 100644
--- a/spec/frontend/work_items/components/work_item_description_spec.js
+++ b/spec/frontend/work_items/components/work_item_description_spec.js
@@ -99,10 +99,6 @@ describe('WorkItemDescription', () => {
}
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('editing description with workItemsMvc FF enabled', () => {
beforeEach(() => {
workItemsMvc = true;
@@ -117,11 +113,14 @@ describe('WorkItemDescription', () => {
await createComponent({ isEditing: true });
expect(findMarkdownEditor().props()).toMatchObject({
- autocompleteDataSources: autocompleteDataSources(fullPath, iid),
supportsQuickActions: true,
renderMarkdownPath: markdownPreviewPath(fullPath, iid),
quickActionsDocsPath: wrapper.vm.$options.quickActionsDocsPath,
});
+
+ expect(findMarkdownEditor().vm.$attrs).toMatchObject({
+ 'autocomplete-data-sources': autocompleteDataSources(fullPath, iid),
+ });
});
});
diff --git a/spec/frontend/work_items/components/work_item_detail_modal_spec.js b/spec/frontend/work_items/components/work_item_detail_modal_spec.js
index 938cf6e6f51..1bdf5d1c840 100644
--- a/spec/frontend/work_items/components/work_item_detail_modal_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_modal_spec.js
@@ -82,10 +82,6 @@ describe('WorkItemDetailModal component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders WorkItemDetail', () => {
createComponent();
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 64a7502671e..fe7556f8ec6 100644
--- a/spec/frontend/work_items/components/work_item_detail_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_spec.js
@@ -99,9 +99,7 @@ describe('WorkItemDetail component', () => {
subscriptionHandler = titleSubscriptionHandler,
confidentialityMock = [updateWorkItemMutation, jest.fn()],
error = undefined,
- workItemsMvcEnabled = false,
workItemsMvc2Enabled = false,
- fetchByIid = false,
} = {}) => {
const handlers = [
[workItemQuery, handler],
@@ -124,9 +122,7 @@ describe('WorkItemDetail component', () => {
},
provide: {
glFeatures: {
- workItemsMvc: workItemsMvcEnabled,
workItemsMvc2: workItemsMvc2Enabled,
- useIidInWorkItemsPath: fetchByIid,
},
hasIssueWeightsFeature: true,
hasIterationsFeature: true,
@@ -149,7 +145,6 @@ describe('WorkItemDetail component', () => {
};
afterEach(() => {
- wrapper.destroy();
setWindowLocation('');
});
@@ -420,6 +415,12 @@ describe('WorkItemDetail component', () => {
expect(findParentButton().props('icon')).toBe(mockParent.parent.workItemType.iconName);
});
+ it('shows parent title and iid', () => {
+ expect(findParentButton().text()).toBe(
+ `${mockParent.parent.title} #${mockParent.parent.iid}`,
+ );
+ });
+
it('sets the parent breadcrumb URL pointing to issue page when parent type is `Issue`', () => {
expect(findParentButton().attributes().href).toBe('../../issues/5');
});
@@ -441,6 +442,11 @@ describe('WorkItemDetail component', () => {
expect(findParentButton().attributes().href).toBe(mockParentObjective.parent.webUrl);
});
+
+ it('shows work item type and iid', () => {
+ const { iid, workItemType } = workItemQueryResponse.data.workItem;
+ expect(findParent().text()).toContain(`${workItemType.name} #${iid}`);
+ });
});
});
@@ -626,7 +632,7 @@ describe('WorkItemDetail component', () => {
});
});
- it('calls the global ID work item query when `useIidInWorkItemsPath` feature flag is false', async () => {
+ it('calls the global ID work item query when there is no `iid_path` parameter in URL', async () => {
createComponent();
await waitForPromises();
@@ -636,20 +642,10 @@ describe('WorkItemDetail component', () => {
expect(successByIidHandler).not.toHaveBeenCalled();
});
- it('calls the global ID work item query when `useIidInWorkItemsPath` feature flag is true but there is no `iid_path` parameter in URL', async () => {
- createComponent({ fetchByIid: true });
- await waitForPromises();
-
- expect(successHandler).toHaveBeenCalledWith({
- id: workItemQueryResponse.data.workItem.id,
- });
- expect(successByIidHandler).not.toHaveBeenCalled();
- });
-
- it('calls the IID work item query when `useIidInWorkItemsPath` feature flag is true and `iid_path` route parameter is present', async () => {
+ it('calls the IID work item query when `iid_path` route parameter is present', async () => {
setWindowLocation(`?iid_path=true`);
- createComponent({ fetchByIid: true, iidPathQueryParam: 'true' });
+ createComponent();
await waitForPromises();
expect(successHandler).not.toHaveBeenCalled();
@@ -659,10 +655,10 @@ describe('WorkItemDetail component', () => {
});
});
- it('calls the IID work item query when `useIidInWorkItemsPath` feature flag is true and `iid_path` route parameter is present and is a modal', async () => {
+ it('calls the IID work item query when `iid_path` route parameter is present and is a modal', async () => {
setWindowLocation(`?iid_path=true`);
- createComponent({ fetchByIid: true, iidPathQueryParam: 'true', isModal: true });
+ createComponent({ isModal: true });
await waitForPromises();
expect(successHandler).not.toHaveBeenCalled();
@@ -748,21 +744,10 @@ describe('WorkItemDetail component', () => {
});
describe('notes widget', () => {
- it('does not render notes by default', async () => {
+ it('renders notes by default', async () => {
createComponent();
await waitForPromises();
- expect(findNotesWidget().exists()).toBe(false);
- });
-
- it('renders notes when the work_items_mvc flag is on', async () => {
- const notesWorkItem = workItemResponseFactory({
- notesWidgetPresent: true,
- });
- const handler = jest.fn().mockResolvedValue(notesWorkItem);
- createComponent({ workItemsMvcEnabled: true, handler });
- await waitForPromises();
-
expect(findNotesWidget().exists()).toBe(true);
});
});
diff --git a/spec/frontend/work_items/components/work_item_due_date_spec.js b/spec/frontend/work_items/components/work_item_due_date_spec.js
index 7ebaf8209c7..b4811db8bed 100644
--- a/spec/frontend/work_items/components/work_item_due_date_spec.js
+++ b/spec/frontend/work_items/components/work_item_due_date_spec.js
@@ -46,10 +46,6 @@ describe('WorkItemDueDate component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when can update', () => {
describe('start date', () => {
describe('`Add start date` button', () => {
diff --git a/spec/frontend/work_items/components/work_item_labels_spec.js b/spec/frontend/work_items/components/work_item_labels_spec.js
index 0b6ab5c3290..6d51448194b 100644
--- a/spec/frontend/work_items/components/work_item_labels_spec.js
+++ b/spec/frontend/work_items/components/work_item_labels_spec.js
@@ -72,10 +72,6 @@ describe('WorkItemLabels component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('has a label', () => {
createComponent();
diff --git a/spec/frontend/work_items/components/work_item_links/okr_actions_split_button_spec.js b/spec/frontend/work_items/components/work_item_links/okr_actions_split_button_spec.js
index 5fbd8e7e1a7..688dccbda79 100644
--- a/spec/frontend/work_items/components/work_item_links/okr_actions_split_button_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/okr_actions_split_button_spec.js
@@ -15,10 +15,6 @@ describe('RelatedItemsTree', () => {
wrapper = createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('OkrActionsSplitButton', () => {
describe('template', () => {
it('renders objective and key results sections', () => {
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 0470249d7ce..721436e217e 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
@@ -7,7 +7,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import WorkItemLinkChildMetadata from 'ee_else_ce/work_items/components/work_item_links/work_item_link_child_metadata.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue';
import getWorkItemTreeQuery from '~/work_items/graphql/work_item_tree.query.graphql';
@@ -31,7 +31,7 @@ import {
workItemObjectiveMetadataWidgets,
} from '../../mock_data';
-jest.mock('~/flash');
+jest.mock('~/alert');
describe('WorkItemLinkChild', () => {
const WORK_ITEM_ID = 'gid://gitlab/WorkItem/2';
@@ -67,10 +67,6 @@ describe('WorkItemLinkChild', () => {
createAlert.mockClear();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it.each`
status | childItem | statusIconName | statusIconColorClass | rawTimestamp | tooltipContents
${'open'} | ${workItemTask} | ${'issue-open-m'} | ${'gl-text-green-500'} | ${workItemTask.createdAt} | ${'Created'}
@@ -109,10 +105,30 @@ describe('WorkItemLinkChild', () => {
});
it('renders item title', () => {
- expect(titleEl.attributes('href')).toBe('/gitlab-org/gitlab-test/-/work_items/4');
+ expect(titleEl.attributes('href')).toBe(
+ '/gitlab-org/gitlab-test/-/work_items/4?iid_path=true',
+ );
expect(titleEl.text()).toBe(workItemTask.title);
});
+ describe('renders item title correctly for relative instance', () => {
+ beforeEach(() => {
+ window.gon = { relative_url_root: '/test' };
+ createComponent();
+ titleEl = wrapper.findByTestId('item-title');
+ });
+
+ it('renders item title with correct href', () => {
+ expect(titleEl.attributes('href')).toBe(
+ '/test/gitlab-org/gitlab-test/-/work_items/4?iid_path=true',
+ );
+ });
+
+ it('renders item title with correct text', () => {
+ expect(titleEl.text()).toBe(workItemTask.title);
+ });
+ });
+
it.each`
action | event | emittedEvent
${'doing mouseover on'} | ${'mouseover'} | ${'mouseover'}
@@ -149,6 +165,8 @@ describe('WorkItemLinkChild', () => {
expect(metadataEl.props()).toMatchObject({
metadataWidgets: workItemObjectiveMetadataWidgets,
});
+
+ expect(wrapper.find('[data-testid="links-child"]').classes()).toContain('gl-py-3');
});
it('does not render item metadata component when item has no metadata present', () => {
@@ -158,6 +176,8 @@ describe('WorkItemLinkChild', () => {
});
expect(findMetadataComponent().exists()).toBe(false);
+
+ expect(wrapper.find('[data-testid="links-child"]').classes()).toContain('gl-py-0');
});
});
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 480f8fbcc58..5184b24d202 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
@@ -75,10 +75,6 @@ describe('WorkItemLinksForm', () => {
const findConfidentialCheckbox = () => wrapper.findComponent(GlFormCheckbox);
const findAddChildButton = () => wrapper.findByTestId('add-child-button');
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('creating a new work item', () => {
beforeEach(async () => {
await createComponent();
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
index e3f3b74f296..4e53fc2987b 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
@@ -17,10 +17,6 @@ describe('WorkItemLinksMenu', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders dropdown and dropdown items', () => {
expect(findDropdown().exists()).toBe(true);
expect(findRemoveDropdownItem().exists()).toBe(true);
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js
index ec51f92b578..99e44b4d89c 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js
@@ -54,7 +54,6 @@ describe('WorkItemLinks', () => {
mutationHandler = mutationChangeParentHandler,
issueDetailsQueryHandler = jest.fn().mockResolvedValue(getIssueDetailsResponse()),
hasIterationsFeature = false,
- fetchByIid = false,
} = {}) => {
mockApollo = createMockApollo(
[
@@ -76,11 +75,7 @@ describe('WorkItemLinks', () => {
},
provide: {
projectPath: 'project/path',
- iid: '1',
hasIterationsFeature,
- glFeatures: {
- useIidInWorkItemsPath: fetchByIid,
- },
},
propsData: { issuableId: 1 },
apolloProvider: mockApollo,
@@ -351,7 +346,7 @@ describe('WorkItemLinks', () => {
beforeEach(async () => {
setWindowLocation('?iid_path=true');
- await createComponent({ fetchByIid: true });
+ await createComponent();
firstChild = findFirstWorkItemLinkChild();
});
@@ -391,7 +386,7 @@ describe('WorkItemLinks', () => {
it('starts prefetching work item by iid if URL contains work item id', async () => {
setWindowLocation('?work_item_iid=5&iid_path=true');
- await createComponent({ fetchByIid: true });
+ await createComponent();
expect(childWorkItemByIidHandler).toHaveBeenCalledWith({
iid: '5',
@@ -402,7 +397,7 @@ describe('WorkItemLinks', () => {
it('does not open the modal if work item iid URL parameter is not found in child items', async () => {
setWindowLocation('?work_item_iid=555&iid_path=true');
- await createComponent({ fetchByIid: true });
+ await createComponent();
expect(showModal).not.toHaveBeenCalled();
expect(wrapper.findComponent(WorkItemDetailModal).props('workItemIid')).toBe(null);
@@ -410,7 +405,7 @@ describe('WorkItemLinks', () => {
it('opens the modal if work item iid URL parameter is found in child items', async () => {
setWindowLocation('?work_item_iid=2&iid_path=true');
- await createComponent({ fetchByIid: true });
+ await createComponent();
expect(showModal).toHaveBeenCalled();
expect(wrapper.findComponent(WorkItemDetailModal).props('workItemIid')).toBe('2');
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 3db848a0ad2..a067923b9fc 100644
--- a/spec/frontend/work_items/components/work_item_notes_spec.js
+++ b/spec/frontend/work_items/components/work_item_notes_spec.js
@@ -9,10 +9,13 @@ import SystemNote from '~/work_items/components/notes/system_note.vue';
import WorkItemNotes from '~/work_items/components/work_item_notes.vue';
import WorkItemDiscussion from '~/work_items/components/notes/work_item_discussion.vue';
import WorkItemAddNote from '~/work_items/components/notes/work_item_add_note.vue';
-import ActivityFilter from '~/work_items/components/notes/activity_filter.vue';
+import WorkItemNotesActivityHeader from '~/work_items/components/notes/work_item_notes_activity_header.vue';
import workItemNotesQuery from '~/work_items/graphql/notes/work_item_notes.query.graphql';
import workItemNotesByIidQuery from '~/work_items/graphql/notes/work_item_notes_by_iid.query.graphql';
import deleteWorkItemNoteMutation from '~/work_items/graphql/notes/delete_work_item_notes.mutation.graphql';
+import workItemNoteCreatedSubscription from '~/work_items/graphql/notes/work_item_note_created.subscription.graphql';
+import workItemNoteUpdatedSubscription from '~/work_items/graphql/notes/work_item_note_updated.subscription.graphql';
+import workItemNoteDeletedSubscription from '~/work_items/graphql/notes/work_item_note_deleted.subscription.graphql';
import { DEFAULT_PAGE_SIZE_NOTES, WIDGET_TYPE_NOTES } from '~/work_items/constants';
import { ASC, DESC } from '~/notes/constants';
import {
@@ -21,6 +24,9 @@ import {
mockWorkItemNotesByIidResponse,
mockMoreWorkItemNotesResponse,
mockWorkItemNotesResponseWithComments,
+ workItemNotesCreateSubscriptionResponse,
+ workItemNotesUpdateSubscriptionResponse,
+ workItemNotesDeleteSubscriptionResponse,
} from '../mock_data';
const mockWorkItemId = workItemQueryResponse.data.workItem.id;
@@ -53,10 +59,9 @@ describe('WorkItemNotes component', () => {
const findAllSystemNotes = () => wrapper.findAllComponents(SystemNote);
const findAllListItems = () => wrapper.findAll('ul.timeline > *');
- const findActivityLabel = () => wrapper.find('label');
const findWorkItemAddNote = () => wrapper.findComponent(WorkItemAddNote);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
- const findSortingFilter = () => wrapper.findComponent(ActivityFilter);
+ const findActivityHeader = () => wrapper.findComponent(WorkItemNotesActivityHeader);
const findSystemNoteAtIndex = (index) => findAllSystemNotes().at(index);
const findAllWorkItemCommentNotes = () => wrapper.findAllComponents(WorkItemDiscussion);
const findWorkItemCommentNoteAtIndex = (index) => findAllWorkItemCommentNotes().at(index);
@@ -73,6 +78,15 @@ describe('WorkItemNotes component', () => {
const deleteWorkItemNoteMutationSuccessHandler = jest.fn().mockResolvedValue({
data: { destroyNote: { note: null, __typename: 'DestroyNote' } },
});
+ const notesCreateSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemNotesCreateSubscriptionResponse);
+ const notesUpdateSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemNotesUpdateSubscriptionResponse);
+ const notesDeleteSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemNotesDeleteSubscriptionResponse);
const errorHandler = jest.fn().mockRejectedValue('Houston, we have a problem');
const createComponent = ({
@@ -86,6 +100,9 @@ describe('WorkItemNotes component', () => {
[workItemNotesQuery, defaultWorkItemNotesQueryHandler],
[workItemNotesByIidQuery, workItemNotesByIidQueryHandler],
[deleteWorkItemNoteMutation, deleteWINoteMutationHandler],
+ [workItemNoteCreatedSubscription, notesCreateSubscriptionHandler],
+ [workItemNoteUpdatedSubscription, notesUpdateSubscriptionHandler],
+ [workItemNoteDeletedSubscription, notesDeleteSubscriptionHandler],
]),
propsData: {
workItemId,
@@ -96,11 +113,6 @@ describe('WorkItemNotes component', () => {
fetchByIid,
workItemType: 'task',
},
- provide: {
- glFeatures: {
- useIidInWorkItemsPath: fetchByIid,
- },
- },
stubs: {
GlModal: stubComponent(GlModal, { methods: { show: showModal } }),
},
@@ -111,8 +123,8 @@ describe('WorkItemNotes component', () => {
createComponent();
});
- it('renders activity label', () => {
- expect(findActivityLabel().exists()).toBe(true);
+ it('has the work item note activity header', () => {
+ expect(findActivityHeader().exists()).toBe(true);
});
it('passes correct props to comment form component', async () => {
@@ -203,26 +215,22 @@ describe('WorkItemNotes component', () => {
await waitForPromises();
});
- it('filter exists', () => {
- expect(findSortingFilter().exists()).toBe(true);
- });
-
- it('sorts the list when the `changeSortOrder` event is emitted', async () => {
+ it('sorts the list when the `changeSort` event is emitted', async () => {
expect(findSystemNoteAtIndex(0).props('note').id).toEqual(firstSystemNodeId);
- await findSortingFilter().vm.$emit('changeSortOrder', DESC);
+ await findActivityHeader().vm.$emit('changeSort', DESC);
expect(findSystemNoteAtIndex(0).props('note').id).not.toEqual(firstSystemNodeId);
});
it('puts form at start of list in when sorting by newest first', async () => {
- await findSortingFilter().vm.$emit('changeSortOrder', DESC);
+ await findActivityHeader().vm.$emit('changeSort', DESC);
expect(findAllListItems().at(0).is(WorkItemAddNote)).toEqual(true);
});
it('puts form at end of list in when sorting by oldest first', async () => {
- await findSortingFilter().vm.$emit('changeSortOrder', ASC);
+ await findActivityHeader().vm.$emit('changeSort', ASC);
expect(findAllListItems().at(-1).is(WorkItemAddNote)).toEqual(true);
});
@@ -334,4 +342,31 @@ describe('WorkItemNotes component', () => {
['Something went wrong when deleting a comment. Please try again'],
]);
});
+
+ describe('Notes subscriptions', () => {
+ beforeEach(async () => {
+ createComponent({
+ defaultWorkItemNotesQueryHandler: workItemNotesWithCommentsQueryHandler,
+ });
+ await waitForPromises();
+ });
+
+ it('has create notes subscription', () => {
+ expect(notesCreateSubscriptionHandler).toHaveBeenCalledWith({
+ noteableId: mockWorkItemId,
+ });
+ });
+
+ it('has delete notes subscription', () => {
+ expect(notesDeleteSubscriptionHandler).toHaveBeenCalledWith({
+ noteableId: mockWorkItemId,
+ });
+ });
+
+ it('has update notes subscription', () => {
+ expect(notesUpdateSubscriptionHandler).toHaveBeenCalledWith({
+ noteableId: mockWorkItemId,
+ });
+ });
+ });
});
diff --git a/spec/frontend/work_items/components/work_item_state_spec.js b/spec/frontend/work_items/components/work_item_state_spec.js
index b24d940d56a..d1262057c73 100644
--- a/spec/frontend/work_items/components/work_item_state_spec.js
+++ b/spec/frontend/work_items/components/work_item_state_spec.js
@@ -44,10 +44,6 @@ describe('WorkItemState component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders state', () => {
createComponent();
diff --git a/spec/frontend/work_items/components/work_item_title_spec.js b/spec/frontend/work_items/components/work_item_title_spec.js
index a549aad5cd8..34391b74cf7 100644
--- a/spec/frontend/work_items/components/work_item_title_spec.js
+++ b/spec/frontend/work_items/components/work_item_title_spec.js
@@ -41,10 +41,6 @@ describe('WorkItemTitle component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders title', () => {
createComponent();
diff --git a/spec/frontend/work_items/components/work_item_type_icon_spec.js b/spec/frontend/work_items/components/work_item_type_icon_spec.js
index 182fb0f8cb6..a5e955c4dbf 100644
--- a/spec/frontend/work_items/components/work_item_type_icon_spec.js
+++ b/spec/frontend/work_items/components/work_item_type_icon_spec.js
@@ -9,7 +9,7 @@ function createComponent(propsData) {
wrapper = shallowMount(WorkItemTypeIcon, {
propsData,
directives: {
- GlTooltip: createMockDirective(),
+ GlTooltip: createMockDirective('gl-tooltip'),
},
});
}
@@ -17,10 +17,6 @@ function createComponent(propsData) {
describe('Work Item type component', () => {
const findIcon = () => wrapper.findComponent(GlIcon);
- afterEach(() => {
- wrapper.destroy();
- });
-
describe.each`
workItemType | workItemIconName | iconName | text | showTooltipOnHover
${'TASK'} | ${''} | ${'issue-type-task'} | ${'Task'} | ${false}
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index d4832fe376d..fecf98b2651 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -82,6 +82,7 @@ export const workItemQueryResponse = {
userPermissions: {
deleteWorkItem: false,
updateWorkItem: false,
+ __typename: 'WorkItemPermissions',
},
widgets: [
{
@@ -182,6 +183,7 @@ export const updateWorkItemMutationResponse = {
userPermissions: {
deleteWorkItem: false,
updateWorkItem: false,
+ __typename: 'WorkItemPermissions',
},
widgets: [
{
@@ -330,6 +332,7 @@ export const workItemResponseFactory = ({
userPermissions: {
deleteWorkItem: canDelete,
updateWorkItem: canUpdate,
+ __typename: 'WorkItemPermissions',
},
widgets: [
{
@@ -473,23 +476,20 @@ export const workItemResponseFactory = ({
export const getIssueDetailsResponse = ({ confidential = false } = {}) => ({
data: {
- workspace: {
- id: 'gid://gitlab/Project/1',
- issuable: {
- id: 'gid://gitlab/Issue/4',
- confidential,
- iteration: {
- id: 'gid://gitlab/Iteration/1124',
- __typename: 'Iteration',
- },
- milestone: {
- id: 'gid://gitlab/Milestone/28',
- __typename: 'Milestone',
- },
- __typename: 'Issue',
+ issue: {
+ id: 'gid://gitlab/Issue/4',
+ confidential,
+ iteration: {
+ id: 'gid://gitlab/Iteration/1124',
+ __typename: 'Iteration',
},
- __typename: 'Project',
+ milestone: {
+ id: 'gid://gitlab/Milestone/28',
+ __typename: 'Milestone',
+ },
+ __typename: 'Issue',
},
+ __typename: 'Project',
},
});
@@ -542,6 +542,7 @@ export const createWorkItemMutationResponse = {
userPermissions: {
deleteWorkItem: false,
updateWorkItem: false,
+ __typename: 'WorkItemPermissions',
},
widgets: [],
},
@@ -590,6 +591,7 @@ export const createWorkItemFromTaskMutationResponse = {
userPermissions: {
deleteWorkItem: false,
updateWorkItem: false,
+ __typename: 'WorkItemPermissions',
},
widgets: [
{
@@ -630,6 +632,7 @@ export const createWorkItemFromTaskMutationResponse = {
userPermissions: {
deleteWorkItem: false,
updateWorkItem: false,
+ __typename: 'WorkItemPermissions',
},
widgets: [],
},
@@ -831,15 +834,20 @@ export const workItemHierarchyEmptyResponse = {
data: {
workItem: {
id: 'gid://gitlab/WorkItem/1',
+ iid: 1,
+ state: 'OPEN',
workItemType: {
- id: 'gid://gitlab/WorkItems::Type/6',
+ id: 'gid://gitlab/WorkItems::Type/1',
name: 'Issue',
iconName: 'issue-type-issue',
__typename: 'WorkItemType',
},
title: 'New title',
+ description: '',
createdAt: '2022-08-03T12:41:54Z',
+ updatedAt: null,
closedAt: null,
+ author: mockAssignees[0],
project: {
__typename: 'Project',
id: '1',
@@ -849,14 +857,11 @@ export const workItemHierarchyEmptyResponse = {
userPermissions: {
deleteWorkItem: false,
updateWorkItem: false,
+ __typename: 'WorkItemPermissions',
},
confidential: false,
widgets: [
{
- type: 'DESCRIPTION',
- __typename: 'WorkItemWidgetDescription',
- },
- {
type: 'HIERARCHY',
parent: null,
hasChildren: false,
@@ -876,6 +881,8 @@ export const workItemHierarchyNoUpdatePermissionResponse = {
data: {
workItem: {
id: 'gid://gitlab/WorkItem/1',
+ iid: 1,
+ state: 'OPEN',
workItemType: {
id: 'gid://gitlab/WorkItems::Type/6',
name: 'Issue',
@@ -883,9 +890,15 @@ export const workItemHierarchyNoUpdatePermissionResponse = {
__typename: 'WorkItemType',
},
title: 'New title',
+ description: '',
+ createdAt: '2022-08-03T12:41:54Z',
+ updatedAt: null,
+ closedAt: null,
+ author: mockAssignees[0],
userPermissions: {
deleteWorkItem: false,
updateWorkItem: false,
+ __typename: 'WorkItemPermissions',
},
project: {
__typename: 'Project',
@@ -896,10 +909,6 @@ export const workItemHierarchyNoUpdatePermissionResponse = {
confidential: false,
widgets: [
{
- type: 'DESCRIPTION',
- __typename: 'WorkItemWidgetDescription',
- },
- {
type: 'HIERARCHY',
parent: null,
hasChildren: true,
@@ -952,6 +961,7 @@ export const workItemTask = {
confidential: false,
createdAt: '2022-08-03T12:41:54Z',
closedAt: null,
+ widgets: [],
__typename: 'WorkItem',
};
@@ -969,6 +979,7 @@ export const confidentialWorkItemTask = {
confidential: true,
createdAt: '2022-08-03T12:41:54Z',
closedAt: null,
+ widgets: [],
__typename: 'WorkItem',
};
@@ -986,6 +997,7 @@ export const closedWorkItemTask = {
confidential: false,
createdAt: '2022-08-03T12:41:54Z',
closedAt: '2022-08-12T13:07:52Z',
+ widgets: [],
__typename: 'WorkItem',
};
@@ -1007,6 +1019,7 @@ export const childrenWorkItems = [
confidential: false,
createdAt: '2022-08-03T12:41:54Z',
closedAt: null,
+ widgets: [],
__typename: 'WorkItem',
},
];
@@ -1017,15 +1030,19 @@ export const workItemHierarchyResponse = {
id: 'gid://gitlab/WorkItem/1',
iid: '1',
workItemType: {
- id: 'gid://gitlab/WorkItems::Type/6',
- name: 'Objective',
- iconName: 'issue-type-objective',
+ id: 'gid://gitlab/WorkItems::Type/1',
+ name: 'Issue',
+ iconName: 'issue-type-issue',
__typename: 'WorkItemType',
},
title: 'New title',
userPermissions: {
deleteWorkItem: true,
updateWorkItem: true,
+ __typename: 'WorkItemPermissions',
+ },
+ author: {
+ ...mockAssignees[0],
},
confidential: false,
project: {
@@ -1034,12 +1051,13 @@ export const workItemHierarchyResponse = {
fullPath: 'test-project-path',
archived: false,
},
+ description: 'Issue description',
+ state: 'OPEN',
+ createdAt: '2022-08-03T12:41:54Z',
+ updatedAt: null,
+ closedAt: null,
widgets: [
{
- type: 'DESCRIPTION',
- __typename: 'WorkItemWidgetDescription',
- },
- {
type: 'HIERARCHY',
parent: null,
hasChildren: true,
@@ -1110,6 +1128,7 @@ export const workItemObjectiveWithChild = {
userPermissions: {
deleteWorkItem: true,
updateWorkItem: true,
+ __typename: 'WorkItemPermissions',
},
author: {
...mockAssignees[0],
@@ -1176,6 +1195,7 @@ export const workItemHierarchyTreeResponse = {
userPermissions: {
deleteWorkItem: true,
updateWorkItem: true,
+ __typename: 'WorkItemPermissions',
},
confidential: false,
project: {
@@ -1252,6 +1272,7 @@ export const changeWorkItemParentMutationResponse = {
userPermissions: {
deleteWorkItem: true,
updateWorkItem: true,
+ __typename: 'WorkItemPermissions',
},
description: null,
id: 'gid://gitlab/WorkItem/2',
@@ -1624,6 +1645,7 @@ export const projectWorkItemResponse = {
workItems: {
nodes: [workItemQueryResponse.data.workItem],
},
+ __typename: 'Project',
},
},
};
@@ -1681,6 +1703,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -1724,6 +1748,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -1766,6 +1792,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -1868,6 +1896,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -1913,6 +1943,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -1959,6 +1991,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -2059,6 +2093,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -2102,6 +2138,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -2144,6 +2182,8 @@ 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',
lastEditedBy: null,
system: true,
internal: false,
@@ -2205,6 +2245,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',
lastEditedBy: null,
discussion: {
id: 'gid://gitlab/Discussion/c872ba2d7d3eb780d2255138d67ca8b04f65b122',
@@ -2252,6 +2293,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',
lastEditedBy: null,
system: false,
internal: false,
@@ -2331,6 +2373,8 @@ 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',
lastEditedBy: null,
discussion: {
id: 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
@@ -2365,6 +2409,8 @@ 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',
lastEditedBy: null,
discussion: {
id: 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
@@ -2406,6 +2452,8 @@ 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',
lastEditedBy: null,
system: false,
internal: false,
@@ -2447,3 +2495,129 @@ export const mockWorkItemNotesResponseWithComments = {
},
},
};
+
+export const workItemNotesCreateSubscriptionResponse = {
+ data: {
+ workItemNoteCreated: {
+ id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a7d81864',
+ body: 'changed weight to **89**',
+ bodyHtml: '<p dir="auto">changed weight to <strong>89</strong></p>',
+ 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',
+ lastEditedBy: null,
+ system: true,
+ internal: false,
+ discussion: {
+ id: 'gid://gitlab/Discussion/8bbc4890b6ff0f2cde93a5a0947cd2b8a13d3b6e',
+ notes: {
+ nodes: [
+ {
+ id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a9881864',
+ body: 'changed weight to **89**',
+ bodyHtml: '<p dir="auto">changed weight to <strong>89</strong></p>',
+ 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',
+ lastEditedBy: null,
+ system: true,
+ internal: false,
+ discussion: {
+ id: 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da12723560987',
+ },
+ userPermissions: {
+ adminNote: false,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ author: {
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 'gid://gitlab/User/1',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ __typename: 'Note',
+ },
+ ],
+ },
+ },
+ userPermissions: {
+ adminNote: false,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ author: {
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 'gid://gitlab/User/1',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ __typename: 'Note',
+ },
+ },
+};
+
+export const workItemNotesUpdateSubscriptionResponse = {
+ data: {
+ workItemNoteUpdated: {
+ id: 'gid://gitlab/Note/0f2f195ec0d1ef95ee9d5b10446b8e96a9883894',
+ body: 'changed title',
+ bodyHtml: '<p dir="auto">changed title<strong>89</strong></p>',
+ 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',
+ lastEditedBy: null,
+ system: true,
+ internal: false,
+ discussion: {
+ id: 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da12723560987',
+ },
+ userPermissions: {
+ adminNote: false,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ author: {
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 'gid://gitlab/User/1',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ __typename: 'Note',
+ },
+ },
+};
+
+export const workItemNotesDeleteSubscriptionResponse = {
+ data: {
+ workItemNoteDeleted: {
+ id: 'gid://gitlab/DiscussionNote/235',
+ discussionId: 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
+ lastDiscussionNote: false,
+ },
+ },
+};
diff --git a/spec/frontend/work_items/pages/create_work_item_spec.js b/spec/frontend/work_items/pages/create_work_item_spec.js
index 387c8a355fa..b963f041dd9 100644
--- a/spec/frontend/work_items/pages/create_work_item_spec.js
+++ b/spec/frontend/work_items/pages/create_work_item_spec.js
@@ -37,7 +37,6 @@ describe('Create work item component', () => {
props = {},
queryHandler = querySuccessHandler,
mutationHandler = createWorkItemSuccessHandler,
- fetchByIid = false,
} = {}) => {
fakeApollo = createMockApollo(
[
@@ -66,15 +65,11 @@ describe('Create work item component', () => {
},
provide: {
fullPath: 'full-path',
- glFeatures: {
- useIidInWorkItemsPath: fetchByIid,
- },
},
});
};
afterEach(() => {
- wrapper.destroy();
fakeApollo = null;
});
@@ -109,9 +104,8 @@ describe('Create work item component', () => {
expect(wrapper.vm.$router.push).toHaveBeenCalledWith({
name: 'workItem',
- params: {
- id: '1',
- },
+ params: { id: '1' },
+ query: { iid_path: 'true' },
});
});
@@ -210,18 +204,4 @@ describe('Create work item component', () => {
'Something went wrong when creating work item. Please try again.',
);
});
-
- it('performs a correct redirect when `useIidInWorkItemsPath` feature flag is enabled', async () => {
- createComponent({ fetchByIid: true });
- findTitleInput().vm.$emit('title-input', 'Test title');
-
- wrapper.find('form').trigger('submit');
- await waitForPromises();
-
- expect(wrapper.vm.$router.push).toHaveBeenCalledWith({
- name: 'workItem',
- params: { id: '1' },
- query: { iid_path: 'true' },
- });
- });
});
diff --git a/spec/frontend/work_items/pages/work_item_root_spec.js b/spec/frontend/work_items/pages/work_item_root_spec.js
index a766962771a..37326910e13 100644
--- a/spec/frontend/work_items/pages/work_item_root_spec.js
+++ b/spec/frontend/work_items/pages/work_item_root_spec.js
@@ -44,10 +44,6 @@ describe('Work items root component', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders WorkItemDetail', () => {
createComponent();
diff --git a/spec/frontend/work_items/router_spec.js b/spec/frontend/work_items/router_spec.js
index ef9ae4a2eab..5dad7f7c43f 100644
--- a/spec/frontend/work_items/router_spec.js
+++ b/spec/frontend/work_items/router_spec.js
@@ -75,6 +75,7 @@ describe('Work items router', () => {
WorkItemWeight: true,
WorkItemIteration: true,
WorkItemHealthStatus: true,
+ WorkItemNotes: true,
},
});
};
@@ -88,6 +89,7 @@ describe('Work items router', () => {
});
afterEach(() => {
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
wrapper.destroy();
window.location.hash = '';
});
diff --git a/spec/frontend/work_items_hierarchy/components/app_spec.js b/spec/frontend/work_items_hierarchy/components/app_spec.js
index 124ff5f1608..22fd7d5f48a 100644
--- a/spec/frontend/work_items_hierarchy/components/app_spec.js
+++ b/spec/frontend/work_items_hierarchy/components/app_spec.js
@@ -24,10 +24,6 @@ describe('WorkItemsHierarchy App', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('survey banner', () => {
it('shows when the banner is visible', () => {
createComponent({}, { bannerVisible: true });
diff --git a/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js b/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js
index 084aaa754ab..dfdef7915dd 100644
--- a/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js
+++ b/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js
@@ -40,10 +40,6 @@ describe('WorkItemsHierarchy Hierarchy', () => {
);
};
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('available structure', () => {
let items = [];
diff --git a/spec/frontend/zen_mode_spec.js b/spec/frontend/zen_mode_spec.js
index 85f1dbdc305..025a92464f1 100644
--- a/spec/frontend/zen_mode_spec.js
+++ b/spec/frontend/zen_mode_spec.js
@@ -15,6 +15,8 @@ describe('ZenMode', () => {
let dropzoneForElementSpy;
const fixtureName = 'snippets/show.html';
+ const getTextarea = () => $('.notes-form textarea');
+
function enterZen() {
$('.notes-form .js-zen-enter').click();
}
@@ -24,7 +26,7 @@ describe('ZenMode', () => {
}
function escapeKeydown() {
- $('.notes-form textarea').trigger(
+ getTextarea().trigger(
$.Event('keydown', {
keyCode: 27,
}),
@@ -50,6 +52,12 @@ describe('ZenMode', () => {
});
afterEach(() => {
+ $(document).off('click', '.js-zen-enter');
+ $(document).off('click', '.js-zen-leave');
+ $(document).off('zen_mode:enter');
+ $(document).off('zen_mode:leave');
+ $(document).off('keydown');
+
resetHTMLFixture();
});
@@ -62,14 +70,14 @@ describe('ZenMode', () => {
$('.div-dropzone').addClass('js-invalid-dropzone');
exitZen();
- expect(dropzoneForElementSpy.mock.calls.length).toEqual(0);
+ expect(dropzoneForElementSpy).not.toHaveBeenCalled();
});
it('should call dropzone if element is dropzone valid', () => {
$('.div-dropzone').removeClass('js-invalid-dropzone');
exitZen();
- expect(dropzoneForElementSpy.mock.calls.length).toEqual(2);
+ expect(dropzoneForElementSpy).toHaveBeenCalledTimes(1);
});
});
@@ -82,10 +90,10 @@ describe('ZenMode', () => {
});
it('removes textarea styling', () => {
- $('.notes-form textarea').attr('style', 'height: 400px');
+ getTextarea().attr('style', 'height: 400px');
enterZen();
- expect($('.notes-form textarea')).not.toHaveAttr('style');
+ expect(getTextarea()).not.toHaveAttr('style');
});
});
@@ -116,4 +124,15 @@ describe('ZenMode', () => {
expect(utils.scrollToElement).toHaveBeenCalled();
});
});
+
+ it('restores textarea style', () => {
+ const style = 'color: red; overflow-y: hidden;';
+ getTextarea().attr('style', style);
+ expect(getTextarea()).toHaveAttr('style', style);
+
+ enterZen();
+ exitZen();
+
+ expect(getTextarea()).toHaveAttr('style', style);
+ });
});
diff --git a/spec/frontend_integration/content_editor/content_editor_integration_spec.js b/spec/frontend_integration/content_editor/content_editor_integration_spec.js
index 8521e85a971..a80c4db19b5 100644
--- a/spec/frontend_integration/content_editor/content_editor_integration_spec.js
+++ b/spec/frontend_integration/content_editor/content_editor_integration_spec.js
@@ -38,10 +38,6 @@ describe('content_editor', () => {
renderMarkdown = jest.fn();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('when loading initial content', () => {
describe('when the initial content is empty', () => {
it('still hides the loading indicator', async () => {
diff --git a/spec/frontend_integration/ide/ide_integration_spec.js b/spec/frontend_integration/ide/ide_integration_spec.js
index a6108fd71e1..5711b004f70 100644
--- a/spec/frontend_integration/ide/ide_integration_spec.js
+++ b/spec/frontend_integration/ide/ide_integration_spec.js
@@ -22,7 +22,6 @@ describe('WebIDE', () => {
afterEach(() => {
vm.$destroy();
- vm = null;
resetHTMLFixture();
});
diff --git a/spec/frontend_integration/ide/user_opens_file_spec.js b/spec/frontend_integration/ide/user_opens_file_spec.js
index af6e2f3b44b..93c9fff309f 100644
--- a/spec/frontend_integration/ide/user_opens_file_spec.js
+++ b/spec/frontend_integration/ide/user_opens_file_spec.js
@@ -23,7 +23,6 @@ describe('IDE: User opens a file in the Web IDE', () => {
afterEach(() => {
vm.$destroy();
- vm = null;
resetHTMLFixture();
});
diff --git a/spec/frontend_integration/ide/user_opens_ide_spec.js b/spec/frontend_integration/ide/user_opens_ide_spec.js
index 552888f04a5..d4656b1098e 100644
--- a/spec/frontend_integration/ide/user_opens_ide_spec.js
+++ b/spec/frontend_integration/ide/user_opens_ide_spec.js
@@ -20,7 +20,6 @@ describe('IDE: User opens IDE', () => {
afterEach(() => {
vm.$destroy();
- vm = null;
resetHTMLFixture();
});
diff --git a/spec/frontend_integration/ide/user_opens_mr_spec.js b/spec/frontend_integration/ide/user_opens_mr_spec.js
index af0276a5055..4e90cef6016 100644
--- a/spec/frontend_integration/ide/user_opens_mr_spec.js
+++ b/spec/frontend_integration/ide/user_opens_mr_spec.js
@@ -34,7 +34,6 @@ describe('IDE: User opens Merge Request', () => {
afterEach(() => {
vm.$destroy();
- vm = null;
resetHTMLFixture();
});
diff --git a/spec/graphql/mutations/achievements/award_spec.rb b/spec/graphql/mutations/achievements/award_spec.rb
new file mode 100644
index 00000000000..1bfad46a616
--- /dev/null
+++ b/spec/graphql/mutations/achievements/award_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Achievements::Award, feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:recipient) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+
+ describe '#resolve' do
+ subject(:resolve_mutation) do
+ described_class.new(object: nil, context: { current_user: current_user }, field: nil).resolve(
+ achievement_id: achievement&.to_global_id, user_id: recipient&.to_global_id
+ )
+ end
+
+ before_all do
+ group.add_developer(developer)
+ group.add_maintainer(maintainer)
+ end
+
+ context 'when the user does not have permission' do
+ let(:current_user) { developer }
+
+ it 'raises an error' do
+ expect { resolve_mutation }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ .with_message(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { maintainer }
+
+ context 'when the params are invalid' do
+ let(:achievement) { nil }
+
+ it 'returns the validation error' do
+ expect { resolve_mutation }.to raise_error { Gitlab::Graphql::Errors::ArgumentError }
+ end
+ end
+
+ it 'creates user_achievement with correct values' do
+ expect(resolve_mutation[:user_achievement]).to have_attributes({ achievement: achievement, user: recipient })
+ end
+ end
+ end
+
+ specify { expect(described_class).to require_graphql_authorizations(:award_achievement) }
+end
diff --git a/spec/graphql/mutations/achievements/revoke_spec.rb b/spec/graphql/mutations/achievements/revoke_spec.rb
new file mode 100644
index 00000000000..0c221b492af
--- /dev/null
+++ b/spec/graphql/mutations/achievements/revoke_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Achievements::Revoke, feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:recipient) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+ let_it_be(:user_achievement) { create(:user_achievement, achievement: achievement) }
+
+ describe '#resolve' do
+ subject(:resolve_mutation) do
+ described_class.new(object: nil, context: { current_user: current_user }, field: nil).resolve(
+ user_achievement_id: user_achievement&.to_global_id
+ )
+ end
+
+ before_all do
+ group.add_developer(developer)
+ group.add_maintainer(maintainer)
+ end
+
+ context 'when the user does not have permission' do
+ let(:current_user) { developer }
+
+ it 'raises an error' do
+ expect { resolve_mutation }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ .with_message(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { maintainer }
+
+ context 'when the params are invalid' do
+ let(:user_achievement) { nil }
+
+ it 'returns the validation error' do
+ expect { resolve_mutation }.to raise_error { Gitlab::Graphql::Errors::ArgumentError }
+ end
+ end
+
+ it 'revokes user_achievement' do
+ response = resolve_mutation[:user_achievement]
+
+ expect(response.revoked_at).not_to be_nil
+ expect(response.revoked_by_user_id).to be(current_user.id)
+ end
+ end
+ end
+
+ specify { expect(described_class).to require_graphql_authorizations(:award_achievement) }
+end
diff --git a/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb b/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
index 125e15b70cf..da5531d2b93 100644
--- a/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
+++ b/spec/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
@@ -58,7 +58,6 @@ RSpec.describe Mutations::AlertManagement::Alerts::SetAssignees do
it_behaves_like 'an incident management tracked event', :incident_management_alert_assigned
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb b/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb
index bcb7c74fa09..8ba1e785b63 100644
--- a/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb
+++ b/spec/graphql/mutations/alert_management/alerts/todo/create_spec.rb
@@ -20,7 +20,6 @@ RSpec.describe Mutations::AlertManagement::Alerts::Todo::Create do
it_behaves_like 'an incident management tracked event', :incident_management_alert_todo
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
index e49596b37c9..f86046bb0d6 100644
--- a/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
+++ b/spec/graphql/mutations/alert_management/create_alert_issue_spec.rb
@@ -32,7 +32,6 @@ RSpec.describe Mutations::AlertManagement::CreateAlertIssue do
it_behaves_like 'an incident management tracked event', :incident_management_alert_create_incident
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
@@ -57,7 +56,6 @@ RSpec.describe Mutations::AlertManagement::CreateAlertIssue do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
index 22ad93df79b..fb11ec7065b 100644
--- a/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
+++ b/spec/graphql/mutations/alert_management/update_alert_status_spec.rb
@@ -36,7 +36,6 @@ RSpec.describe Mutations::AlertManagement::UpdateAlertStatus do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/graphql/mutations/members/bulk_update_base_spec.rb b/spec/graphql/mutations/members/bulk_update_base_spec.rb
new file mode 100644
index 00000000000..61a27984824
--- /dev/null
+++ b/spec/graphql/mutations/members/bulk_update_base_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Members::BulkUpdateBase, feature_category: :subgroups do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group).tap { |group| group.add_owner(user) } }
+
+ it 'raises a NotImplementedError error if the source_type method is called on the base class' do
+ mutation = described_class.new(context: { current_user: user }, object: nil, field: nil)
+
+ expect { mutation.resolve(group_id: group.to_gid.to_s) }.to raise_error(NotImplementedError)
+ end
+end
diff --git a/spec/graphql/mutations/release_asset_links/create_spec.rb b/spec/graphql/mutations/release_asset_links/create_spec.rb
index a5291a00799..cc6c1554866 100644
--- a/spec/graphql/mutations/release_asset_links/create_spec.rb
+++ b/spec/graphql/mutations/release_asset_links/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::ReleaseAssetLinks::Create do
+RSpec.describe Mutations::ReleaseAssetLinks::Create, feature_category: :release_orchestration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
diff --git a/spec/graphql/mutations/release_asset_links/delete_spec.rb b/spec/graphql/mutations/release_asset_links/delete_spec.rb
index cca7bd2ba38..3aecc44afd1 100644
--- a/spec/graphql/mutations/release_asset_links/delete_spec.rb
+++ b/spec/graphql/mutations/release_asset_links/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::ReleaseAssetLinks::Delete do
+RSpec.describe Mutations::ReleaseAssetLinks::Delete, feature_category: :release_orchestration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
@@ -60,6 +60,18 @@ RSpec.describe Mutations::ReleaseAssetLinks::Delete do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
+
+ context 'when destroy process fails' do
+ before do
+ allow_next_instance_of(::Releases::Links::DestroyService) do |service|
+ allow(service).to receive(:execute).and_return(ServiceResponse.error(message: 'error'))
+ end
+ end
+
+ it 'returns errors' do
+ expect(resolve).to include(errors: 'error')
+ end
+ end
end
context 'when the current user does not have access to delete the link' do
diff --git a/spec/graphql/mutations/release_asset_links/update_spec.rb b/spec/graphql/mutations/release_asset_links/update_spec.rb
index e119cf9cc77..abb091fc68d 100644
--- a/spec/graphql/mutations/release_asset_links/update_spec.rb
+++ b/spec/graphql/mutations/release_asset_links/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::ReleaseAssetLinks::Update do
+RSpec.describe Mutations::ReleaseAssetLinks::Update, feature_category: :release_orchestration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
diff --git a/spec/graphql/resolvers/achievements/achievements_resolver_spec.rb b/spec/graphql/resolvers/achievements/achievements_resolver_spec.rb
new file mode 100644
index 00000000000..666610dca33
--- /dev/null
+++ b/spec/graphql/resolvers/achievements/achievements_resolver_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Achievements::AchievementsResolver, feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::Achievements::AchievementType.connection_type)
+ end
+
+ describe '#resolve' do
+ it 'is not empty' do
+ expect(resolve_achievements).not_to be_empty
+ end
+
+ context 'when `achievements` feature flag is diabled' do
+ before do
+ stub_feature_flags(achievements: false)
+ end
+
+ it 'is empty' do
+ expect(resolve_achievements).to be_empty
+ end
+ end
+ end
+
+ def resolve_achievements
+ resolve(described_class, obj: group)
+ end
+end
diff --git a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
index 5d06db904d5..ff343f3f43d 100644
--- a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
@@ -78,7 +78,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
status_status: 'active',
type_type: :group_type,
tag_name: ['active_runner'],
- preload: { tag_name: false },
+ preload: false,
search: 'abc',
sort: 'contacted_asc',
membership: :descendants,
diff --git a/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb
index 4cc00ced104..83435db2ea7 100644
--- a/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb
@@ -67,7 +67,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
status_status: 'active',
type_type: :group_type,
tag_name: ['active_runner'],
- preload: { tag_name: false },
+ preload: false,
search: 'abc',
sort: 'contacted_asc',
project: project
diff --git a/spec/graphql/resolvers/ci/runners_resolver_spec.rb b/spec/graphql/resolvers/ci/runners_resolver_spec.rb
index d6da8222234..e4620b96cae 100644
--- a/spec/graphql/resolvers/ci/runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/runners_resolver_spec.rb
@@ -83,7 +83,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
upgrade_status: 'recommended',
type_type: :instance_type,
tag_name: ['active_runner'],
- preload: { tag_name: false },
+ preload: false,
search: 'abc',
sort: 'contacted_asc'
}
@@ -108,7 +108,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
let(:expected_params) do
{
active: false,
- preload: { tag_name: false }
+ preload: false
}
end
@@ -128,7 +128,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
let(:expected_params) do
{
active: false,
- preload: { tag_name: false }
+ preload: false
}
end
@@ -146,9 +146,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
end
let(:expected_params) do
- {
- preload: { tag_name: false }
- }
+ { preload: false }
end
it 'calls RunnersFinder with expected arguments' do
diff --git a/spec/graphql/resolvers/ci/variables_resolver_spec.rb b/spec/graphql/resolvers/ci/variables_resolver_spec.rb
index 16b72e8cb7f..1bfc63df71d 100644
--- a/spec/graphql/resolvers/ci/variables_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/variables_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Resolvers::Ci::VariablesResolver, feature_category: :pipeline_authoring do
+RSpec.describe Resolvers::Ci::VariablesResolver, feature_category: :pipeline_composition do
include GraphqlHelpers
describe '#resolve' do
diff --git a/spec/graphql/types/achievements/achievement_type_spec.rb b/spec/graphql/types/achievements/achievement_type_spec.rb
index f967dc8e25e..08fadcdff22 100644
--- a/spec/graphql/types/achievements/achievement_type_spec.rb
+++ b/spec/graphql/types/achievements/achievement_type_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe GitlabSchema.types['Achievement'], feature_category: :user_profil
description
created_at
updated_at
+ user_achievements
]
end
diff --git a/spec/graphql/types/achievements/user_achievement_type_spec.rb b/spec/graphql/types/achievements/user_achievement_type_spec.rb
new file mode 100644
index 00000000000..6b1512ff841
--- /dev/null
+++ b/spec/graphql/types/achievements/user_achievement_type_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['UserAchievement'], feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let(:fields) do
+ %w[
+ id
+ achievement
+ user
+ awarded_by_user
+ revoked_by_user
+ created_at
+ updated_at
+ revoked_at
+ ]
+ end
+
+ it { expect(described_class.graphql_name).to eq('UserAchievement') }
+ it { expect(described_class).to have_graphql_fields(fields) }
+ it { expect(described_class).to require_graphql_authorizations(:read_achievement) }
+end
diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb
index 714eaebfe73..a761a256899 100644
--- a/spec/graphql/types/ci/job_type_spec.rb
+++ b/spec/graphql/types/ci/job_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::Ci::JobType do
+RSpec.describe Types::Ci::JobType, feature_category: :continuous_integration do
include GraphqlHelpers
specify { expect(described_class.graphql_name).to eq('CiJob') }
@@ -40,6 +40,7 @@ RSpec.describe Types::Ci::JobType do
refPath
retryable
retried
+ runnerMachine
scheduledAt
schedulingType
shortSha
@@ -51,6 +52,9 @@ RSpec.describe Types::Ci::JobType do
triggered
userPermissions
webPath
+ playPath
+ canPlayJob
+ scheduled
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/runner_machine_type_spec.rb b/spec/graphql/types/ci/runner_machine_type_spec.rb
new file mode 100644
index 00000000000..289cc52e27b
--- /dev/null
+++ b/spec/graphql/types/ci/runner_machine_type_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CiRunnerMachine'], feature_category: :runner_fleet do
+ specify { expect(described_class.graphql_name).to eq('CiRunnerMachine') }
+
+ specify { expect(described_class).to require_graphql_authorizations(:read_runner_machine) }
+
+ it 'contains attributes related to a runner machine' do
+ expected_fields = %w[
+ architecture_name contacted_at created_at executor_name id ip_address platform_name revision
+ runner status system_id version
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb
index a2d107ae295..9e360f44a4f 100644
--- a/spec/graphql/types/ci/runner_type_spec.rb
+++ b/spec/graphql/types/ci/runner_type_spec.rb
@@ -9,11 +9,11 @@ RSpec.describe GitlabSchema.types['CiRunner'], feature_category: :runner do
it 'contains attributes related to a runner' do
expected_fields = %w[
- id description created_at contacted_at maximum_timeout access_level active paused status
+ id description created_by created_at contacted_at machines maximum_timeout access_level active paused status
version short_sha revision locked run_untagged ip_address runner_type tag_list
- project_count job_count admin_url edit_admin_url user_permissions executor_name architecture_name platform_name
- maintenance_note maintenance_note_html groups projects jobs token_expires_at owner_project job_execution_status
- ephemeral_authentication_token
+ project_count job_count admin_url edit_admin_url register_admin_url user_permissions executor_name
+ architecture_name platform_name maintenance_note maintenance_note_html groups projects jobs token_expires_at
+ owner_project job_execution_status ephemeral_authentication_token
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/variable_sort_enum_spec.rb b/spec/graphql/types/ci/variable_sort_enum_spec.rb
index 1702360a21f..0a86597b70d 100644
--- a/spec/graphql/types/ci/variable_sort_enum_spec.rb
+++ b/spec/graphql/types/ci/variable_sort_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::Ci::VariableSortEnum, feature_category: :pipeline_authoring do
+RSpec.describe Types::Ci::VariableSortEnum, feature_category: :pipeline_composition do
it 'exposes the available order methods' do
expect(described_class.values).to match(
'KEY_ASC' => have_attributes(value: :key_asc),
diff --git a/spec/graphql/types/commit_signature_interface_spec.rb b/spec/graphql/types/commit_signature_interface_spec.rb
index 4962131d9b5..d37c0d1b4fa 100644
--- a/spec/graphql/types/commit_signature_interface_spec.rb
+++ b/spec/graphql/types/commit_signature_interface_spec.rb
@@ -18,6 +18,11 @@ RSpec.describe GitlabSchema.types['CommitSignature'] do
Types::CommitSignatures::X509SignatureType)
end
+ it 'resolves SSH signatures' do
+ expect(described_class.resolve_type(build(:ssh_signature), {})).to eq(
+ Types::CommitSignatures::SshSignatureType)
+ end
+
it 'raises an error when type is not known' do
expect { described_class.resolve_type(Class, {}) }.to raise_error('Unsupported commit signature type')
end
diff --git a/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb b/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb
index 4ffb70a0b22..c16e29312a3 100644
--- a/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb
+++ b/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe GitlabSchema.types['SshSignature'], feature_category: :source_cod
it 'contains attributes related to SSH signatures' do
expect(described_class).to have_graphql_fields(
- :user, :verification_status, :commit_sha, :project, :key
+ :user, :verification_status, :commit_sha, :project, :key, :key_fingerprint_sha256
)
end
end
diff --git a/spec/graphql/types/design_management/design_at_version_type_spec.rb b/spec/graphql/types/design_management/design_at_version_type_spec.rb
index 4d61ecf62cc..06aefb6fea3 100644
--- a/spec/graphql/types/design_management/design_at_version_type_spec.rb
+++ b/spec/graphql/types/design_management/design_at_version_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['DesignAtVersion'] do
+RSpec.describe GitlabSchema.types['DesignAtVersion'], feature_category: :portfolio_management do
it_behaves_like 'a GraphQL type with design fields' do
let(:extra_design_fields) { %i[version design] }
let_it_be(:design) { create(:design, :with_versions) }
diff --git a/spec/graphql/types/design_management/design_type_spec.rb b/spec/graphql/types/design_management/design_type_spec.rb
index 24b007a6b33..a093f785eb7 100644
--- a/spec/graphql/types/design_management/design_type_spec.rb
+++ b/spec/graphql/types/design_management/design_type_spec.rb
@@ -2,13 +2,16 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['Design'] do
+RSpec.describe GitlabSchema.types['Design'], feature_category: :portfolio_management do
specify { expect(described_class.interfaces).to include(Types::CurrentUserTodos) }
specify { expect(described_class.interfaces).to include(Types::TodoableInterface) }
it_behaves_like 'a GraphQL type with design fields' do
- let(:extra_design_fields) { %i[notes current_user_todos discussions versions web_url commenters] }
+ let(:extra_design_fields) do
+ %i[notes current_user_todos discussions versions web_url commenters description descriptionHtml]
+ end
+
let_it_be(:design) { create(:design, :with_versions) }
let(:object_id) { GitlabSchema.id_from_object(design) }
let_it_be(:object_id_b) { GitlabSchema.id_from_object(create(:design, :with_versions)) }
diff --git a/spec/graphql/types/key_type_spec.rb b/spec/graphql/types/key_type_spec.rb
index 78144076467..13c00d94b37 100644
--- a/spec/graphql/types/key_type_spec.rb
+++ b/spec/graphql/types/key_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabSchema.types['Key'], feature_category: :authentication_and_authorization do
+RSpec.describe GitlabSchema.types['Key'], feature_category: :system_access do
specify { expect(described_class.graphql_name).to eq('Key') }
it 'contains attributes for SSH keys' do
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 7f26190830e..0bfca9a290b 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -291,7 +291,7 @@ RSpec.describe GitlabSchema.types['Project'] do
let_it_be(:project) { create(:project_empty_repo) }
it 'raises an error' do
- expect(subject['errors'][0]['message']).to eq('You must <a target="_blank" rel="noopener noreferrer" ' \
+ expect(subject['errors'][0]['message']).to eq('UF: You must <a target="_blank" rel="noopener noreferrer" ' \
'href="http://localhost/help/user/project/repository/index.md#' \
'add-files-to-a-repository">add at least one file to the ' \
'repository</a> before using Security features.')
diff --git a/spec/graphql/types/projects/fork_details_type_spec.rb b/spec/graphql/types/projects/fork_details_type_spec.rb
index 8e20e2c8299..f79371ce4ca 100644
--- a/spec/graphql/types/projects/fork_details_type_spec.rb
+++ b/spec/graphql/types/projects/fork_details_type_spec.rb
@@ -9,6 +9,8 @@ RSpec.describe GitlabSchema.types['ForkDetails'], feature_category: :source_code
fields = %i[
ahead
behind
+ isSyncing
+ hasConflicts
]
expect(described_class).to have_graphql_fields(*fields)
diff --git a/spec/graphql/types/root_storage_statistics_type_spec.rb b/spec/graphql/types/root_storage_statistics_type_spec.rb
index 07c8378e7a6..5dde6aa8b14 100644
--- a/spec/graphql/types/root_storage_statistics_type_spec.rb
+++ b/spec/graphql/types/root_storage_statistics_type_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe GitlabSchema.types['RootStorageStatistics'] do
expect(described_class).to have_graphql_fields(:storage_size, :repository_size, :lfs_objects_size,
:build_artifacts_size, :packages_size, :wiki_size, :snippets_size,
:pipeline_artifacts_size, :uploads_size, :dependency_proxy_size,
- :container_registry_size)
+ :container_registry_size, :registry_size_estimated)
end
specify { expect(described_class).to require_graphql_authorizations(:read_statistics) }
diff --git a/spec/graphql/types/user_type_spec.rb b/spec/graphql/types/user_type_spec.rb
index a6b5d454b60..7a0b6c90ace 100644
--- a/spec/graphql/types/user_type_spec.rb
+++ b/spec/graphql/types/user_type_spec.rb
@@ -47,6 +47,7 @@ RSpec.describe GitlabSchema.types['User'], feature_category: :user_profile do
profileEnableGitpodPath
savedReplies
savedReply
+ user_achievements
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/work_items/available_export_fields_enum_spec.rb b/spec/graphql/types/work_items/available_export_fields_enum_spec.rb
new file mode 100644
index 00000000000..5aa51160880
--- /dev/null
+++ b/spec/graphql/types/work_items/available_export_fields_enum_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['AvailableExportFields'], feature_category: :team_planning do
+ specify { expect(described_class.graphql_name).to eq('AvailableExportFields') }
+
+ describe 'enum values' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:field_name, :field_value) do
+ 'ID' | 'id'
+ 'TYPE' | 'type'
+ 'TITLE' | 'title'
+ 'AUTHOR' | 'author'
+ 'AUTHOR_USERNAME' | 'author username'
+ 'CREATED_AT' | 'created_at'
+ end
+
+ with_them do
+ it 'exposes correct available fields' do
+ expect(described_class.values[field_name].value).to eq(field_value)
+ end
+ end
+ end
+end
diff --git a/spec/graphql/types/work_items/widget_interface_spec.rb b/spec/graphql/types/work_items/widget_interface_spec.rb
index a2b12ed52dc..d1dcfb961cb 100644
--- a/spec/graphql/types/work_items/widget_interface_spec.rb
+++ b/spec/graphql/types/work_items/widget_interface_spec.rb
@@ -15,11 +15,12 @@ RSpec.describe Types::WorkItems::WidgetInterface do
using RSpec::Parameterized::TableSyntax
where(:widget_class, :widget_type_name) do
- WorkItems::Widgets::Description | Types::WorkItems::Widgets::DescriptionType
- WorkItems::Widgets::Hierarchy | Types::WorkItems::Widgets::HierarchyType
- WorkItems::Widgets::Assignees | Types::WorkItems::Widgets::AssigneesType
- WorkItems::Widgets::Labels | Types::WorkItems::Widgets::LabelsType
- WorkItems::Widgets::Notes | Types::WorkItems::Widgets::NotesType
+ WorkItems::Widgets::Description | Types::WorkItems::Widgets::DescriptionType
+ WorkItems::Widgets::Hierarchy | Types::WorkItems::Widgets::HierarchyType
+ WorkItems::Widgets::Assignees | Types::WorkItems::Widgets::AssigneesType
+ WorkItems::Widgets::Labels | Types::WorkItems::Widgets::LabelsType
+ WorkItems::Widgets::Notes | Types::WorkItems::Widgets::NotesType
+ WorkItems::Widgets::Notifications | Types::WorkItems::Widgets::NotificationsType
end
with_them do
diff --git a/spec/graphql/types/work_items/widgets/notifications_type_spec.rb b/spec/graphql/types/work_items/widgets/notifications_type_spec.rb
new file mode 100644
index 00000000000..4f457a24710
--- /dev/null
+++ b/spec/graphql/types/work_items/widgets/notifications_type_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::WorkItems::Widgets::NotificationsType, feature_category: :team_planning do
+ it 'exposes the expected fields' do
+ expected_fields = %i[subscribed type]
+
+ expect(described_class.graphql_name).to eq('WorkItemWidgetNotifications')
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/work_items/widgets/notifications_update_input_type_spec.rb b/spec/graphql/types/work_items/widgets/notifications_update_input_type_spec.rb
new file mode 100644
index 00000000000..db0d02c597c
--- /dev/null
+++ b/spec/graphql/types/work_items/widgets/notifications_update_input_type_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Types::WorkItems::Widgets::NotificationsUpdateInputType, feature_category: :team_planning do
+ it { expect(described_class.graphql_name).to eq('WorkItemWidgetNotificationsUpdateInput') }
+
+ it { expect(described_class.arguments.keys).to contain_exactly('subscribed') }
+end
diff --git a/spec/helpers/admin/abuse_reports_helper_spec.rb b/spec/helpers/admin/abuse_reports_helper_spec.rb
new file mode 100644
index 00000000000..83393cc641d
--- /dev/null
+++ b/spec/helpers/admin/abuse_reports_helper_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::AbuseReportsHelper, feature_category: :insider_threat do
+ describe '#abuse_reports_list_data' do
+ let!(:report) { create(:abuse_report) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
+ let(:reports) { AbuseReport.all.page(1) }
+ let(:data) do
+ data = helper.abuse_reports_list_data(reports)[:abuse_reports_data]
+ Gitlab::Json.parse(data)
+ end
+
+ it 'has expected attributes', :aggregate_failures do
+ expect(data['pagination']).to include(
+ "current_page" => 1,
+ "per_page" => 20,
+ "total_items" => 1
+ )
+ expect(data['reports'].first).to include("category", "updated_at", "reported_user", "reporter")
+ expect(data['categories']).to match_array(AbuseReport.categories.keys)
+ end
+ end
+end
diff --git a/spec/helpers/analytics/cycle_analytics_helper_spec.rb b/spec/helpers/analytics/cycle_analytics_helper_spec.rb
deleted file mode 100644
index d906646e25c..00000000000
--- a/spec/helpers/analytics/cycle_analytics_helper_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-require "spec_helper"
-
-RSpec.describe Analytics::CycleAnalyticsHelper do
- describe '#cycle_analytics_initial_data' do
- let(:user) { create(:user, name: 'fake user', username: 'fake_user') }
- let(:image_path_keys) { [:empty_state_svg_path, :no_data_svg_path, :no_access_svg_path] }
- let(:api_path_keys) { [:milestones_path, :labels_path] }
- let(:additional_data_keys) { [:full_path, :group_id, :group_path, :project_id, :request_path] }
- let(:group) { create(:group) }
-
- subject(:cycle_analytics_data) { helper.cycle_analytics_initial_data(project, group) }
-
- before do
- project.add_maintainer(user)
- end
-
- context 'when a group is present' do
- let(:project) { create(:project, group: group) }
-
- it "sets the correct data keys" do
- expect(cycle_analytics_data.keys)
- .to match_array(api_path_keys + image_path_keys + additional_data_keys)
- end
-
- it "sets group paths" do
- expect(cycle_analytics_data)
- .to include({
- full_path: project.full_path,
- group_path: "/#{project.namespace.name}",
- group_id: project.namespace.id,
- request_path: "/#{project.full_path}/-/value_stream_analytics",
- milestones_path: "/groups/#{group.name}/-/milestones.json",
- labels_path: "/groups/#{group.name}/-/labels.json"
- })
- end
- end
-
- context 'when a group is not present' do
- let(:group) { nil }
- let(:project) { create(:project) }
-
- it "sets the correct data keys" do
- expect(cycle_analytics_data.keys)
- .to match_array(image_path_keys + api_path_keys + additional_data_keys)
- end
-
- it "sets project name space paths" do
- expect(cycle_analytics_data)
- .to include({
- full_path: project.full_path,
- group_path: project.namespace.path,
- group_id: project.namespace.id,
- request_path: "/#{project.full_path}/-/value_stream_analytics",
- milestones_path: "/#{project.full_path}/-/milestones.json",
- labels_path: "/#{project.full_path}/-/labels.json"
- })
- end
- end
- end
-end
diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb
index 19cb970553b..93db4661c82 100644
--- a/spec/helpers/application_settings_helper_spec.rb
+++ b/spec/helpers/application_settings_helper_spec.rb
@@ -68,11 +68,7 @@ RSpec.describe ApplicationSettingsHelper do
))
end
- context 'when GitLab.com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
+ context 'when on SaaS', :saas do
it 'does not contain :deactivate_dormant_users' do
expect(helper.visible_attributes).not_to include(:deactivate_dormant_users)
end
diff --git a/spec/helpers/artifacts_helper_spec.rb b/spec/helpers/artifacts_helper_spec.rb
index cf48f0ecc39..7c577cbf11c 100644
--- a/spec/helpers/artifacts_helper_spec.rb
+++ b/spec/helpers/artifacts_helper_spec.rb
@@ -17,6 +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')
})
end
diff --git a/spec/helpers/ci/catalog/resources_helper_spec.rb b/spec/helpers/ci/catalog/resources_helper_spec.rb
new file mode 100644
index 00000000000..c4abdebd12e
--- /dev/null
+++ b/spec/helpers/ci/catalog/resources_helper_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::Catalog::ResourcesHelper, feature_category: :pipeline_composition do
+ let_it_be(:project) { build(:project) }
+
+ describe 'can_view_private_catalog?' do
+ subject { helper.can_view_private_catalog?(project) }
+
+ before do
+ allow(helper).to receive(:can_collaborate_with_project?).and_return(true)
+ stub_licensed_features(ci_private_catalog: false)
+ end
+
+ it 'user cannot view the Catalog in CE regardless of permissions' do
+ expect(subject).to be false
+ end
+ end
+
+ describe '#js_ci_catalog_data' do
+ let(:project) { build(:project, :repository) }
+ let(:default_helper_data) do
+ {}
+ end
+
+ subject(:catalog_data) { helper.js_ci_catalog_data }
+
+ it 'returns catalog data' do
+ expect(catalog_data).to eq(default_helper_data)
+ end
+ end
+end
diff --git a/spec/helpers/ci/pipeline_editor_helper_spec.rb b/spec/helpers/ci/pipeline_editor_helper_spec.rb
index c9aac63a883..1a0f2e10a20 100644
--- a/spec/helpers/ci/pipeline_editor_helper_spec.rb
+++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb
@@ -29,12 +29,12 @@ RSpec.describe Ci::PipelineEditorHelper do
"ci-examples-help-page-path" => help_page_path('ci/examples/index'),
"ci-help-page-path" => help_page_path('ci/index'),
"ci-lint-path" => project_ci_lint_path(project),
+ "ci-troubleshooting-path" => help_page_path('ci/troubleshooting', anchor: 'common-cicd-issues'),
"default-branch" => project.default_branch_or_main,
"empty-state-illustration-path" => 'illustrations/empty.svg',
"initial-branch-name" => nil,
"includes-help-page-path" => help_page_path('ci/yaml/includes'),
"lint-help-page-path" => help_page_path('ci/lint', anchor: 'check-cicd-syntax'),
- "lint-unavailable-help-page-path" => help_page_path('ci/pipeline_editor/index', anchor: 'configuration-validation-currently-not-available-message'),
"needs-help-page-path" => help_page_path('ci/yaml/index', anchor: 'needs'),
"new-merge-request-path" => '/mock/project/-/merge_requests/new',
"pipeline-page-path" => project_pipelines_path(project),
diff --git a/spec/helpers/ci/pipelines_helper_spec.rb b/spec/helpers/ci/pipelines_helper_spec.rb
index 19946afb1a4..535e8f3170e 100644
--- a/spec/helpers/ci/pipelines_helper_spec.rb
+++ b/spec/helpers/ci/pipelines_helper_spec.rb
@@ -192,11 +192,7 @@ RSpec.describe Ci::PipelinesHelper do
end
end
- describe 'the `ios_runners_available` attribute' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
+ describe 'the `ios_runners_available` attribute', :saas do
subject { data[:ios_runners_available] }
context 'when the `ios_specific_templates` experiment variant is control' do
diff --git a/spec/helpers/ci/variables_helper_spec.rb b/spec/helpers/ci/variables_helper_spec.rb
index d032e7f9087..da727fd1b6b 100644
--- a/spec/helpers/ci/variables_helper_spec.rb
+++ b/spec/helpers/ci/variables_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::VariablesHelper, feature_category: :pipeline_authoring do
+RSpec.describe Ci::VariablesHelper, feature_category: :pipeline_composition do
describe '#ci_variable_maskable_raw_regex' do
it 'converts to a javascript regex' do
expect(helper.ci_variable_maskable_raw_regex).to eq("^\\S{8,}$")
diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb
index 27738f73ea5..c947d11e9de 100644
--- a/spec/helpers/commits_helper_spec.rb
+++ b/spec/helpers/commits_helper_spec.rb
@@ -325,21 +325,41 @@ RSpec.describe CommitsHelper do
assign(:path, current_path)
end
- it { is_expected.to be_an(Array) }
- it { is_expected.to include(commit) }
- it { is_expected.to include(commit.author) }
- it { is_expected.to include(ref) }
-
specify do
- is_expected.to include(
+ expect(subject).to eq([
+ commit,
+ commit.author,
+ ref,
{
merge_request: merge_request.cache_key,
pipeline_status: pipeline.cache_key,
xhr: true,
controller: "commits",
- path: current_path
+ path: current_path,
+ referenced_by: helper.tag_checksum(commit.referenced_by)
}
- )
+ ])
+ end
+
+ context 'when the show_tags_on_commits_view flag is disabled' do
+ before do
+ stub_feature_flags(show_tags_on_commits_view: false)
+ end
+
+ specify do
+ expect(subject).to eq([
+ commit,
+ commit.author,
+ ref,
+ {
+ merge_request: merge_request.cache_key,
+ pipeline_status: pipeline.cache_key,
+ xhr: true,
+ controller: "commits",
+ path: current_path
+ }
+ ])
+ end
end
describe "final cache key output" do
diff --git a/spec/helpers/device_registration_helper_spec.rb b/spec/helpers/device_registration_helper_spec.rb
new file mode 100644
index 00000000000..7556d037b3d
--- /dev/null
+++ b/spec/helpers/device_registration_helper_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe DeviceRegistrationHelper, feature_category: :system_access do
+ describe "#device_registration_data" do
+ it "returns a hash with device registration properties without initial error" do
+ device_registration_data = helper.device_registration_data(
+ current_password_required: false,
+ target_path: "/my/path",
+ webauthn_error: nil
+ )
+
+ expect(device_registration_data).to eq(
+ {
+ initial_error: nil,
+ target_path: "/my/path",
+ password_required: "false"
+ })
+ end
+
+ it "returns a hash with device registration properties with initial error" do
+ device_registration_data = helper.device_registration_data(
+ current_password_required: true,
+ target_path: "/my/path",
+ webauthn_error: { message: "my error" }
+ )
+
+ expect(device_registration_data).to eq(
+ {
+ initial_error: "my error",
+ target_path: "/my/path",
+ password_required: "true"
+ })
+ end
+ end
+end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index a46f8c13f00..2318bbf861a 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -47,6 +47,12 @@ RSpec.describe DiffHelper do
end
describe 'diff_options' do
+ let(:large_notebooks_enabled) { false }
+
+ before do
+ stub_feature_flags(large_ipynb_diffs: large_notebooks_enabled)
+ end
+
it 'returns no collapse false' do
expect(diff_options).to include(expanded: false)
end
@@ -56,21 +62,48 @@ RSpec.describe DiffHelper do
expect(diff_options).to include(expanded: true)
end
- it 'returns no collapse true if action name diff_for_path' do
- allow(controller).to receive(:action_name) { 'diff_for_path' }
- expect(diff_options).to include(expanded: true)
- end
+ context 'when action name is diff_for_path' do
+ before do
+ allow(controller).to receive(:action_name) { 'diff_for_path' }
+ end
- it 'returns paths if action name diff_for_path and param old path' do
- allow(controller).to receive(:params) { { old_path: 'lib/wadus.rb' } }
- allow(controller).to receive(:action_name) { 'diff_for_path' }
- expect(diff_options[:paths]).to include('lib/wadus.rb')
- end
+ it 'returns expanded true' do
+ expect(diff_options).to include(expanded: true)
+ end
- it 'returns paths if action name diff_for_path and param new path' do
- allow(controller).to receive(:params) { { new_path: 'lib/wadus.rb' } }
- allow(controller).to receive(:action_name) { 'diff_for_path' }
- expect(diff_options[:paths]).to include('lib/wadus.rb')
+ it 'returns paths if param old path' do
+ allow(controller).to receive(:params) { { old_path: 'lib/wadus.rb' } }
+ expect(diff_options[:paths]).to include('lib/wadus.rb')
+ end
+
+ it 'returns paths if param new path' do
+ allow(controller).to receive(:params) { { new_path: 'lib/wadus.rb' } }
+ expect(diff_options[:paths]).to include('lib/wadus.rb')
+ end
+
+ it 'does not set max_patch_bytes_for_file_extension' do
+ expect(diff_options[:max_patch_bytes_for_file_extension]).to be_nil
+ end
+
+ context 'when file_identifier include .ipynb' do
+ before do
+ allow(controller).to receive(:params) { { file_identifier: 'something.ipynb' } }
+ end
+
+ context 'when large_ipynb_diffs is disabled' do
+ it 'does not set max_patch_bytes_for_file_extension' do
+ expect(diff_options[:max_patch_bytes_for_file_extension]).to be_nil
+ end
+ end
+
+ context 'when large_ipynb_diffs is enabled' do
+ let(:large_notebooks_enabled) { true }
+
+ it 'sets max_patch_bytes_for_file_extension' do
+ expect(diff_options[:max_patch_bytes_for_file_extension]).to eq({ '.ipynb' => 1.megabyte })
+ end
+ end
+ end
end
end
diff --git a/spec/helpers/explore_helper_spec.rb b/spec/helpers/explore_helper_spec.rb
index 4ae1b738858..68c5289a85f 100644
--- a/spec/helpers/explore_helper_spec.rb
+++ b/spec/helpers/explore_helper_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe ExploreHelper do
describe '#explore_nav_links' do
it 'has all the expected links by default' do
- menu_items = [:projects, :groups, :snippets]
+ menu_items = [:projects, :groups, :topics, :snippets]
expect(helper.explore_nav_links).to contain_exactly(*menu_items)
end
diff --git a/spec/helpers/groups/observability_helper_spec.rb b/spec/helpers/groups/observability_helper_spec.rb
index ee33a853f9c..f0e6aa0998a 100644
--- a/spec/helpers/groups/observability_helper_spec.rb
+++ b/spec/helpers/groups/observability_helper_spec.rb
@@ -4,77 +4,46 @@ require "spec_helper"
RSpec.describe Groups::ObservabilityHelper do
let(:group) { build_stubbed(:group) }
- let(:observability_url) { Gitlab::Observability.observability_url }
describe '#observability_iframe_src' do
- context 'if observability_path is missing from params' do
- it 'returns the iframe src for action: dashboards' do
- allow(helper).to receive(:params).and_return({ action: 'dashboards' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/")
- end
-
- it 'returns the iframe src for action: manage' do
- allow(helper).to receive(:params).and_return({ action: 'manage' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/dashboards")
- end
-
- it 'returns the iframe src for action: explore' do
- allow(helper).to receive(:params).and_return({ action: 'explore' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/explore")
- end
-
- it 'returns the iframe src for action: datasources' do
- allow(helper).to receive(:params).and_return({ action: 'datasources' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/datasources")
- end
+ before do
+ allow(Gitlab::Observability).to receive(:build_full_url).and_return('full-url')
end
- context 'if observability_path exists in params' do
- context 'if observability_path is valid' do
- it 'returns the iframe src by injecting the observability path' do
- allow(helper).to receive(:params).and_return({ action: '/explore', observability_path: '/foo?bar=foobar' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/-/#{group.id}/foo?bar=foobar")
- end
- end
-
- context 'if observability_path is not valid' do
- it 'returns the iframe src by injecting the sanitised observability path' do
- allow(helper).to receive(:params).and_return({
- action: '/explore',
- observability_path:
- "/test?groupId=<script>alert('attack!')</script>"
- })
- expect(helper.observability_iframe_src(group)).to eq(
- "#{observability_url}/-/#{group.id}/test?groupId=alert('attack!')"
- )
- end
- end
+ it 'returns the iframe src for action: dashboards' do
+ allow(helper).to receive(:params).and_return({ action: 'dashboards', observability_path: '/foo?bar=foobar' })
+ expect(helper.observability_iframe_src(group)).to eq('full-url')
+ expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/')
end
- context 'when observability ui is standalone' do
- before do
- stub_env('STANDALONE_OBSERVABILITY_UI', 'true')
- end
+ it 'returns the iframe src for action: manage' do
+ allow(helper).to receive(:params).and_return({ action: 'manage', observability_path: '/foo?bar=foobar' })
+ expect(helper.observability_iframe_src(group)).to eq('full-url')
+ expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/dashboards')
+ end
- it 'returns the iframe src without group.id for action: dashboards' do
- allow(helper).to receive(:params).and_return({ action: 'dashboards' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/")
- end
+ it 'returns the iframe src for action: explore' do
+ allow(helper).to receive(:params).and_return({ action: 'explore', observability_path: '/foo?bar=foobar' })
+ expect(helper.observability_iframe_src(group)).to eq('full-url')
+ expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/explore')
+ end
- it 'returns the iframe src without group.id for action: manage' do
- allow(helper).to receive(:params).and_return({ action: 'manage' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/dashboards")
- end
+ it 'returns the iframe src for action: datasources' do
+ allow(helper).to receive(:params).and_return({ action: 'datasources', observability_path: '/foo?bar=foobar' })
+ expect(helper.observability_iframe_src(group)).to eq('full-url')
+ expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/datasources')
+ end
- it 'returns the iframe src without group.id for action: explore' do
- allow(helper).to receive(:params).and_return({ action: 'explore' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/explore")
- end
+ it 'returns the iframe src when action is not recognised' do
+ allow(helper).to receive(:params).and_return({ action: 'unrecognised', observability_path: '/foo?bar=foobar' })
+ expect(helper.observability_iframe_src(group)).to eq('full-url')
+ expect(Gitlab::Observability).to have_received(:build_full_url).with(group, '/foo?bar=foobar', '/')
+ end
- it 'returns the iframe src without group.id for action: datasources' do
- allow(helper).to receive(:params).and_return({ action: 'datasources' })
- expect(helper.observability_iframe_src(group)).to eq("#{observability_url}/datasources")
- end
+ it 'returns the iframe src when observability_path is missing' do
+ allow(helper).to receive(:params).and_return({ action: 'dashboards' })
+ expect(helper.observability_iframe_src(group)).to eq('full-url')
+ expect(Gitlab::Observability).to have_received(:build_full_url).with(group, nil, '/')
end
end
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 8b4ac6a7cfd..ce439e5bcdd 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -436,7 +436,8 @@ RSpec.describe GroupsHelper do
it 'returns expected hash' do
expect(subgroup_creation_data(subgroup)).to eq({
import_existing_group_path: '/groups/new#import-group-pane',
- parent_group_name: name
+ parent_group_name: name,
+ parent_group_url: group_url(group)
})
end
end
@@ -445,7 +446,8 @@ RSpec.describe GroupsHelper do
it 'returns expected hash' do
expect(subgroup_creation_data(group)).to eq({
import_existing_group_path: '/groups/new#import-group-pane',
- parent_group_name: nil
+ parent_group_name: nil,
+ parent_group_url: nil
})
end
end
diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb
index e2ee4f33eee..e5a39f6a24e 100644
--- a/spec/helpers/ide_helper_spec.rb
+++ b/spec/helpers/ide_helper_spec.rb
@@ -6,117 +6,135 @@ RSpec.describe IdeHelper, feature_category: :web_ide do
describe '#ide_data' do
let_it_be(:project) { create(:project) }
let_it_be(:user) { project.creator }
+ let_it_be(:fork_info) { { ide_path: '/test/ide/path' } }
+
+ let_it_be(:params) do
+ {
+ branch: 'master',
+ path: 'foo/bar',
+ merge_request_id: '1'
+ }
+ end
+
+ let(:base_data) do
+ {
+ 'can-use-new-web-ide' => 'false',
+ 'use-new-web-ide' => 'false',
+ 'user-preferences-path' => profile_preferences_path,
+ 'project' => nil,
+ 'preview-markdown-path' => nil
+ }
+ end
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:content_security_policy_nonce).and_return('test-csp-nonce')
end
- context 'with vscode_web_ide=true and instance vars set' do
- before do
- stub_feature_flags(vscode_web_ide: true)
- end
+ it 'returns hash' do
+ expect(helper.ide_data(project: nil, fork_info: fork_info, params: params))
+ .to include(base_data)
+ end
- it 'returns hash' do
- expect(helper.ide_data(project: project, branch: 'master', path: 'foo/README.md', merge_request: '7',
-fork_info: nil))
- .to match(
- 'can-use-new-web-ide' => 'true',
- 'use-new-web-ide' => 'true',
- 'user-preferences-path' => profile_preferences_path,
- 'new-web-ide-help-page-path' =>
- help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'),
- 'branch-name' => 'master',
- 'project-path' => project.path_with_namespace,
- 'csp-nonce' => 'test-csp-nonce',
- 'ide-remote-path' => ide_remote_path(remote_host: ':remote_host', remote_path: ':remote_path'),
- 'file-path' => 'foo/README.md',
- 'editor-font-family' => 'JetBrains Mono',
- 'editor-font-format' => 'woff2',
- 'editor-font-src-url' => a_string_matching(%r{jetbrains-mono/JetBrainsMono}),
- 'merge-request' => '7',
- 'fork-info' => nil
- )
+ context 'with project' do
+ it 'returns hash with parameters' do
+ serialized_project = API::Entities::Project.represent(project, current_user: user).to_json
+
+ expect(
+ helper.ide_data(project: project, fork_info: nil, params: params)
+ ).to include(base_data.merge(
+ 'fork-info' => nil,
+ 'branch-name' => params[:branch],
+ 'file-path' => params[:path],
+ 'merge-request' => params[:merge_request_id],
+ 'project' => serialized_project,
+ 'preview-markdown-path' => Gitlab::Routing.url_helpers.preview_markdown_project_path(project)
+ ))
end
- it 'does not use new web ide if user.use_legacy_web_ide' do
- allow(user).to receive(:use_legacy_web_ide).and_return(true)
-
- expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil,
-fork_info: nil)).to include('use-new-web-ide' => 'false')
+ context 'with fork info' do
+ it 'returns hash with fork info' do
+ expect(helper.ide_data(project: project, fork_info: fork_info, params: params))
+ .to include('fork-info' => fork_info.to_json)
+ end
end
end
- context 'with vscode_web_ide=false' do
+ context 'with environments guidance experiment', :experiment do
before do
- stub_feature_flags(vscode_web_ide: false)
+ stub_experiments(in_product_guidance_environments_webide: :candidate)
end
- context 'when instance vars and parameters are not set' do
- it 'returns instance data in the hash as nil' do
- expect(helper.ide_data(project: nil, branch: nil, path: nil, merge_request: nil, fork_info: nil))
- .to include(
- 'can-use-new-web-ide' => 'false',
- 'use-new-web-ide' => 'false',
- 'user-preferences-path' => profile_preferences_path,
- 'branch-name' => nil,
- 'file-path' => nil,
- 'merge-request' => nil,
- 'fork-info' => nil,
- 'project' => nil,
- 'preview-markdown-path' => nil
- )
+ context 'when project has no enviornments' do
+ it 'enables environment guidance' do
+ expect(helper.ide_data(project: project, fork_info: fork_info, params: params))
+ .to include('enable-environments-guidance' => 'true')
end
- end
- context 'when instance vars are set' do
- it 'returns instance data in the hash' do
- fork_info = { ide_path: '/test/ide/path' }
-
- serialized_project = API::Entities::Project.represent(project, current_user: project.creator).to_json
-
- expect(helper.ide_data(project: project, branch: 'master', path: 'foo/bar', merge_request: '1',
-fork_info: fork_info))
- .to include(
- 'branch-name' => 'master',
- 'file-path' => 'foo/bar',
- 'merge-request' => '1',
- 'fork-info' => fork_info.to_json,
- 'project' => serialized_project,
- 'preview-markdown-path' => Gitlab::Routing.url_helpers.preview_markdown_project_path(project)
- )
+ context 'and the callout has been dismissed' do
+ it 'disables environment guidance' do
+ callout = create(:callout, feature_name: :web_ide_ci_environments_guidance, user: user)
+ callout.update!(dismissed_at: Time.now - 1.week)
+ allow(helper).to receive(:current_user).and_return(User.find(user.id))
+
+ expect(helper.ide_data(project: project, fork_info: fork_info, params: params))
+ .to include('enable-environments-guidance' => 'false')
+ end
end
end
- context 'environments guidance experiment', :experiment do
- before do
- stub_experiments(in_product_guidance_environments_webide: :candidate)
+ context 'when the project has environments' do
+ it 'disables environment guidance' do
+ create(:environment, project: project)
+
+ expect(helper.ide_data(project: project, fork_info: fork_info, params: params))
+ .to include('enable-environments-guidance' => 'false')
end
+ end
+ end
- context 'when project has no enviornments' do
- it 'enables environment guidance' do
- expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil,
-fork_info: nil)).to include('enable-environments-guidance' => 'true')
- end
+ context 'with vscode_web_ide=true' do
+ let(:base_data) do
+ {
+ 'can-use-new-web-ide' => 'true',
+ 'use-new-web-ide' => 'true',
+ 'user-preferences-path' => profile_preferences_path,
+ 'new-web-ide-help-page-path' =>
+ help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'),
+ 'csp-nonce' => 'test-csp-nonce',
+ 'ide-remote-path' => ide_remote_path(remote_host: ':remote_host', remote_path: ':remote_path'),
+ 'editor-font-family' => 'JetBrains Mono',
+ 'editor-font-format' => 'woff2',
+ 'editor-font-src-url' => a_string_matching(%r{jetbrains-mono/JetBrainsMono})
+ }
+ end
- context 'and the callout has been dismissed' do
- it 'disables environment guidance' do
- callout = create(:callout, feature_name: :web_ide_ci_environments_guidance, user: project.creator)
- callout.update!(dismissed_at: Time.now - 1.week)
- allow(helper).to receive(:current_user).and_return(User.find(project.creator.id))
- expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil,
-fork_info: nil)).to include('enable-environments-guidance' => 'false')
- end
- end
- end
+ before do
+ stub_feature_flags(vscode_web_ide: true)
+ end
- context 'when the project has environments' do
- it 'disables environment guidance' do
- create(:environment, project: project)
+ it 'returns hash' do
+ expect(helper.ide_data(project: nil, fork_info: fork_info, params: params))
+ .to include(base_data)
+ end
- expect(helper.ide_data(project: project, branch: nil, path: nil, merge_request: nil,
-fork_info: nil)).to include('enable-environments-guidance' => 'false')
- end
+ it 'does not use new web ide if user.use_legacy_web_ide' do
+ allow(user).to receive(:use_legacy_web_ide).and_return(true)
+
+ expect(helper.ide_data(project: nil, fork_info: fork_info, params: params))
+ .to include('use-new-web-ide' => 'false')
+ end
+
+ context 'with project' do
+ it 'returns hash with parameters' do
+ expect(
+ helper.ide_data(project: project, fork_info: nil, params: params)
+ ).to include(base_data.merge(
+ 'branch-name' => params[:branch],
+ 'file-path' => params[:path],
+ 'merge-request' => params[:merge_request_id],
+ 'fork-info' => nil
+ ))
end
end
end
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 1ae834c0769..fd10b204e50 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -293,10 +293,13 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
describe '#issuable_reference' do
+ let(:project_namespace) { build_stubbed(:project_namespace) }
+ let(:project) { build_stubbed(:project, project_namespace: project_namespace) }
+
context 'when show_full_reference truthy' do
it 'display issuable full reference' do
assign(:show_full_reference, true)
- issue = build_stubbed(:issue)
+ issue = build_stubbed(:issue, project: project)
expect(helper.issuable_reference(issue)).to eql(issue.to_reference(full: true))
end
@@ -305,12 +308,10 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
context 'when show_full_reference falsey' do
context 'when @group present' do
it 'display issuable reference to @group' do
- project = build_stubbed(:project)
-
assign(:show_full_reference, nil)
assign(:group, project.namespace)
- issue = build_stubbed(:issue)
+ issue = build_stubbed(:issue, project: project)
expect(helper.issuable_reference(issue)).to eql(issue.to_reference(project.namespace))
end
@@ -318,13 +319,11 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
context 'when @project present' do
it 'display issuable reference to @project' do
- project = build_stubbed(:project)
-
assign(:show_full_reference, nil)
assign(:group, nil)
assign(:project, project)
- issue = build_stubbed(:issue)
+ issue = build_stubbed(:issue, project: project)
expect(helper.issuable_reference(issue)).to eql(issue.to_reference(project))
end
@@ -333,8 +332,11 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
describe '#issuable_project_reference' do
+ let(:project_namespace) { build_stubbed(:project_namespace) }
+ let(:project) { build_stubbed(:project, project_namespace: project_namespace) }
+
it 'display project name and simple reference with `#` to an issue' do
- issue = build_stubbed(:issue)
+ issue = build_stubbed(:issue, project: project)
expect(helper.issuable_project_reference(issue)).to eq("#{issue.project.full_name} ##{issue.iid}")
end
@@ -430,7 +432,8 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
action: "show",
namespace_id: "foo",
project_id: "bar",
- id: incident.iid
+ id: incident.iid,
+ incident_tab: 'timeline'
}).permit!
end
@@ -441,7 +444,9 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
expected_data = {
issueType: 'incident',
hasLinkedAlerts: false,
- canUpdateTimelineEvent: true
+ canUpdateTimelineEvent: true,
+ currentPath: "/foo/bar/-/issues/incident/#{incident.iid}/timeline",
+ currentTab: 'timeline'
}
expect(helper.issuable_initial_data(incident)).to match(hash_including(expected_data))
diff --git a/spec/helpers/jira_connect_helper_spec.rb b/spec/helpers/jira_connect_helper_spec.rb
index 31aeff85c70..4f56bb7467f 100644
--- a/spec/helpers/jira_connect_helper_spec.rb
+++ b/spec/helpers/jira_connect_helper_spec.rb
@@ -9,8 +9,7 @@ RSpec.describe JiraConnectHelper, feature_category: :integrations do
let(:user) { create(:user) }
let(:client_id) { '123' }
- let(:enable_public_keys_storage_config) { false }
- let(:enable_public_keys_storage_setting) { false }
+ let(:enable_public_keys_storage) { false }
before do
stub_application_setting(jira_connect_application_key: client_id)
@@ -22,9 +21,7 @@ RSpec.describe JiraConnectHelper, feature_category: :integrations do
before do
allow(view).to receive(:current_user).and_return(nil)
allow(Gitlab.config.gitlab).to receive(:url).and_return('http://test.host')
- allow(Gitlab.config.jira_connect).to receive(:enable_public_keys_storage)
- .and_return(enable_public_keys_storage_config)
- stub_application_setting(jira_connect_public_key_storage_enabled: enable_public_keys_storage_setting)
+ stub_application_setting(jira_connect_public_key_storage_enabled: enable_public_keys_storage)
end
it 'includes Jira Connect app attributes' do
@@ -108,16 +105,8 @@ RSpec.describe JiraConnectHelper, feature_category: :integrations do
expect(subject[:public_key_storage_enabled]).to eq(false)
end
- context 'when public_key_storage is enabled via config' do
- let(:enable_public_keys_storage_config) { true }
-
- it 'assignes public_key_storage_enabled to true' do
- expect(subject[:public_key_storage_enabled]).to eq(true)
- end
- end
-
- context 'when public_key_storage is enabled via setting' do
- let(:enable_public_keys_storage_setting) { true }
+ context 'when public_key_storage is enabled' do
+ let(:enable_public_keys_storage) { true }
it 'assignes public_key_storage_enabled to true' do
expect(subject[:public_key_storage_enabled]).to eq(true)
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 088519248c6..a9f99f29f6d 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -534,6 +534,45 @@ RSpec.describe MarkupHelper do
helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project)
end.not_to change { Gitlab::GitalyClient.get_request_count }
end
+
+ it 'strips non-user links' do
+ html = 'This a cool [website](https://gitlab.com/).'
+
+ object = create_object(html)
+ result = helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project)
+
+ expect(result).to include('This a cool website.')
+ end
+
+ it 'styles the current user link', :aggregate_failures do
+ another_user = create(:user)
+ html = "Please have a look, @#{user.username} @#{another_user.username}!"
+
+ object = create_object(html)
+ result = helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project)
+ links = Nokogiri::HTML.parse(result).css('//a')
+
+ expect(links[0].classes).to include('current-user')
+ expect(links[1].classes).not_to include('current-user')
+ end
+
+ context 'when current_user is nil' do
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ end
+
+ it 'renders the link with no styling when current_user is nil' do
+ another_user = create(:user)
+ html = "Please have a look, @#{user.username} @#{another_user.username}!"
+
+ object = create_object(html)
+ result = helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project)
+ links = Nokogiri::HTML.parse(result).css('//a')
+
+ expect(links[0].classes).not_to include('current-user')
+ expect(links[1].classes).not_to include('current-user')
+ end
+ end
end
context 'when the asked attribute can be redacted' do
diff --git a/spec/helpers/nav/new_dropdown_helper_spec.rb b/spec/helpers/nav/new_dropdown_helper_spec.rb
index 3a66fe474ab..5ae057dc97d 100644
--- a/spec/helpers/nav/new_dropdown_helper_spec.rb
+++ b/spec/helpers/nav/new_dropdown_helper_spec.rb
@@ -11,8 +11,11 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
let(:with_can_create_project) { false }
let(:with_can_create_group) { false }
let(:with_can_create_snippet) { false }
+ let(:title) { 'Create new...' }
- subject(:view_model) { helper.new_dropdown_view_model(project: current_project, group: current_group) }
+ subject(:view_model) do
+ helper.new_dropdown_view_model(project: current_project, group: current_group)
+ end
before do
allow(helper).to receive(:current_user) { current_user }
@@ -22,7 +25,7 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
allow(user).to receive(:can?).with(:create_snippet) { with_can_create_snippet }
end
- shared_examples 'invite member item' do
+ shared_examples 'invite member item' do |partial|
it 'shows invite member link with emoji' do
expect(view_model[:menu_sections]).to eq(
expected_menu_section(
@@ -30,12 +33,12 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'invite',
title: 'Invite members',
- emoji: 'shaking_hands',
- href: expected_href,
+ icon: 'shaking_hands',
+ partial: partial,
+ component: 'invite_members',
data: {
- track_action: 'click_link_invite_members',
- track_label: 'plus_menu_dropdown',
- track_property: 'navigation_top'
+ trigger_source: 'top-nav',
+ trigger_element: 'text-emoji'
}
)
)
@@ -54,8 +57,13 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
end
context 'when group and project are nil' do
- it 'has no menu sections' do
- expect(view_model[:menu_sections]).to eq([])
+ it 'has base results' do
+ results = {
+ title: title,
+ menu_sections: []
+ }
+
+ expect(view_model).to eq(results)
end
context 'when can create project' do
@@ -145,8 +153,13 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
.to receive(:can?).with(current_user, :admin_group_member, group) { with_can_admin_in_group }
end
- it 'has no menu sections' do
- expect(view_model[:menu_sections]).to eq([])
+ it 'has base results' do
+ results = {
+ title: title,
+ menu_sections: []
+ }
+
+ expect(view_model).to eq(results)
end
context 'when can create projects in group' do
@@ -199,7 +212,7 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
let(:expected_title) { 'In this group' }
let(:expected_href) { "/groups/#{group.full_path}/-/group_members" }
- it_behaves_like 'invite member item'
+ it_behaves_like 'invite member item', 'groups/invite_members_top_nav_link'
end
end
@@ -219,8 +232,13 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
allow(helper).to receive(:can_admin_project_member?) { with_can_admin_project_member }
end
- it 'has no menu sections' do
- expect(view_model[:menu_sections]).to eq([])
+ it 'has base results' do
+ results = {
+ title: title,
+ menu_sections: []
+ }
+
+ expect(view_model).to eq(results)
end
context 'with show_new_issue_link?' do
@@ -296,7 +314,7 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
let(:expected_title) { 'In this project' }
let(:expected_href) { "/#{project.path_with_namespace}/-/project_members" }
- it_behaves_like 'invite member item'
+ it_behaves_like 'invite member item', 'projects/invite_members_top_nav_link'
end
end
@@ -311,22 +329,27 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
allow(helper).to receive(:can?).with(current_user, :create_projects, group).and_return(true)
end
- it 'gives precedence to group over project' do
- group_section = expected_menu_section(
- title: 'In this group',
+ it 'gives precedence to project over group' do
+ project_section = expected_menu_section(
+ title: 'In this project',
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
- id: 'new_project',
- title: 'New project/repository',
- href: "/projects/new?namespace_id=#{group.id}",
+ id: 'new_issue',
+ title: 'New issue',
+ href: "/#{project.path_with_namespace}/-/issues/new",
data: {
- track_action: 'click_link_new_project_group',
+ track_action: 'click_link_new_issue',
track_label: 'plus_menu_dropdown',
- track_property: 'navigation_top'
+ track_property: 'navigation_top',
+ qa_selector: 'new_issue_link'
}
)
)
+ results = {
+ title: title,
+ menu_sections: project_section
+ }
- expect(view_model[:menu_sections]).to eq(group_section)
+ expect(view_model).to eq(results)
end
end
diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb
index ce5ac2e5404..2b69557b840 100644
--- a/spec/helpers/nav/top_nav_helper_spec.rb
+++ b/spec/helpers/nav/top_nav_helper_spec.rb
@@ -56,6 +56,7 @@ RSpec.describe Nav::TopNavHelper do
expected_primary = [
{ href: '/explore', icon: 'project', id: 'project', title: 'Projects' },
{ href: '/explore/groups', icon: 'group', id: 'groups', title: 'Groups' },
+ { href: '/explore/projects/topics', icon: 'labels', id: 'topics', title: 'Topics' },
{ href: '/explore/snippets', icon: 'snippet', id: 'snippets', title: 'Snippets' }
].map do |item|
::Gitlab::Nav::TopNavMenuItem.build(**item)
@@ -79,6 +80,12 @@ RSpec.describe Nav::TopNavHelper do
css_class: 'dashboard-shortcuts-groups'
},
{
+ href: '/explore/projects/topics',
+ id: 'topics-shortcut',
+ title: 'Topics',
+ css_class: 'dashboard-shortcuts-topics'
+ },
+ {
href: '/explore/snippets',
id: 'snippets-shortcut',
title: 'Snippets',
@@ -320,20 +327,6 @@ RSpec.describe Nav::TopNavHelper do
context 'with milestones' do
let(:with_milestones) { true }
- it 'has expected :primary' do
- expected_header = ::Gitlab::Nav::TopNavMenuHeader.build(
- title: 'Explore'
- )
- expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
- data: { **menu_data_tracking_attrs('milestones') },
- href: '/dashboard/milestones',
- icon: 'clock',
- id: 'milestones',
- title: 'Milestones'
- )
- expect(subject[:primary]).to eq([expected_header, expected_primary])
- end
-
it 'has expected :shortcuts' do
expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build(
id: 'milestones-shortcut',
@@ -348,23 +341,6 @@ RSpec.describe Nav::TopNavHelper do
context 'with snippets' do
let(:with_snippets) { true }
- it 'has expected :primary' do
- expected_header = ::Gitlab::Nav::TopNavMenuHeader.build(
- title: 'Explore'
- )
- expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'snippets_link',
- **menu_data_tracking_attrs('snippets')
- },
- href: '/dashboard/snippets',
- icon: 'snippet',
- id: 'snippets',
- title: 'Snippets'
- )
- expect(subject[:primary]).to eq([expected_header, expected_primary])
- end
-
it 'has expected :shortcuts' do
expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build(
id: 'snippets-shortcut',
@@ -379,20 +355,6 @@ RSpec.describe Nav::TopNavHelper do
context 'with activity' do
let(:with_activity) { true }
- it 'has expected :primary' do
- expected_header = ::Gitlab::Nav::TopNavMenuHeader.build(
- title: 'Explore'
- )
- expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
- data: { **menu_data_tracking_attrs('activity') },
- href: '/dashboard/activity',
- icon: 'history',
- id: 'activity',
- title: 'Activity'
- )
- expect(subject[:primary]).to eq([expected_header, expected_primary])
- end
-
it 'has expected :shortcuts' do
expected_shortcuts = ::Gitlab::Nav::TopNavMenuItem.build(
id: 'activity-shortcut',
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index 68a6b6293c8..91635ffcdc0 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe NotesHelper do
+RSpec.describe NotesHelper, feature_category: :team_planning do
include RepoHelpers
let_it_be(:owner) { create(:owner) }
@@ -223,6 +223,17 @@ RSpec.describe NotesHelper do
end
end
+ describe '#initial_notes_data' do
+ it 'return initial notes data for issuable' do
+ autocomplete = '/autocomplete/users'
+ @project = project
+ @noteable = create(:issue, project: @project)
+
+ expect(helper.initial_notes_data(autocomplete).keys).to match_array(%i[notesUrl now diffView enableGFM])
+ expect(helper.initial_notes_data(autocomplete)[:enableGFM].keys).to match(%i[emojis members issues mergeRequests vulnerabilities epics milestones labels])
+ end
+ end
+
describe '#notes_url' do
it 'return snippet notes path for personal snippet' do
@snippet = create(:personal_snippet)
diff --git a/spec/helpers/packages_helper_spec.rb b/spec/helpers/packages_helper_spec.rb
index fc69aee4e04..b6546a2eaf3 100644
--- a/spec/helpers/packages_helper_spec.rb
+++ b/spec/helpers/packages_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PackagesHelper do
+RSpec.describe PackagesHelper, feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
let_it_be_with_reload(:project) { create(:project) }
@@ -38,11 +38,18 @@ RSpec.describe PackagesHelper do
describe '#pypi_registry_url' do
let_it_be(:base_url_with_token) { base_url.sub('://', '://__token__:<your_personal_token>@') }
+ let_it_be(:public_project) { create(:project, :public) }
- it 'returns the pypi registry url' do
- url = helper.pypi_registry_url(1)
+ it 'returns the pypi registry url with token when project is private' do
+ url = helper.pypi_registry_url(project)
- expect(url).to eq("#{base_url_with_token}projects/1/packages/pypi/simple")
+ expect(url).to eq("#{base_url_with_token}projects/#{project.id}/packages/pypi/simple")
+ end
+
+ it 'returns the pypi registry url without token when project is public' do
+ url = helper.pypi_registry_url(public_project)
+
+ expect(url).to eq("#{base_url}projects/#{public_project.id}/packages/pypi/simple")
end
end
diff --git a/spec/helpers/plan_limits_helper_spec.rb b/spec/helpers/plan_limits_helper_spec.rb
new file mode 100644
index 00000000000..121338c9cf2
--- /dev/null
+++ b/spec/helpers/plan_limits_helper_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe PlanLimitsHelper, feature_category: :continuous_integration do
+ describe '#plan_limit_setting_description' do
+ it 'describes known limits', :aggregate_failures do
+ [
+ :ci_pipeline_size,
+ :ci_active_jobs,
+ :ci_active_pipelines,
+ :ci_project_subscriptions,
+ :ci_pipeline_schedules,
+ :ci_needs_size_limit,
+ :ci_registered_group_runners,
+ :ci_registered_project_runners,
+ :pipeline_hierarchy_size
+ ].each do |limit_name|
+ expect(helper.plan_limit_setting_description(limit_name)).to be_present
+ end
+ end
+
+ it 'raises an ArgumentError on invalid arguments' do
+ expect { helper.plan_limit_setting_description(:some_invalid_limit) }.to(
+ raise_error(ArgumentError, /No description/)
+ )
+ end
+ end
+end
diff --git a/spec/helpers/projects/settings/branch_rules_helper_spec.rb b/spec/helpers/projects/settings/branch_rules_helper_spec.rb
new file mode 100644
index 00000000000..35a21f72f11
--- /dev/null
+++ b/spec/helpers/projects/settings/branch_rules_helper_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::Settings::BranchRulesHelper, feature_category: :source_code_management do
+ let_it_be(:project) { build_stubbed(:project) }
+
+ describe '#branch_rules_data' do
+ subject(:data) { helper.branch_rules_data(project) }
+
+ it 'returns branch rules data' do
+ expect(data).to match({
+ project_path: project.full_path,
+ protected_branches_path: project_settings_repository_path(project, anchor: 'js-protected-branches-settings'),
+ approval_rules_path: project_settings_merge_requests_path(project,
+ anchor: 'js-merge-request-approval-settings'),
+ status_checks_path: project_settings_merge_requests_path(project, anchor: 'js-merge-request-settings'),
+ branches_path: project_branches_path(project),
+ show_status_checks: 'false',
+ show_approvers: 'false',
+ show_code_owners: 'false'
+ })
+ end
+ end
+end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 477b5cd7753..93352715ff4 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -1286,7 +1286,7 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
let_it_be(:has_active_license) { true }
it 'displays the correct messagee' do
- expect(subject).to eq(s_('Clusters|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support.'))
+ expect(subject).to eq(s_('Clusters|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions.'))
end
end
@@ -1373,9 +1373,36 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
source_name: source_project.full_name,
source_path: project_path(source_project),
ahead_compare_path: ahead_path,
- behind_compare_path: behind_path
+ behind_compare_path: behind_path,
+ source_default_branch: source_project.default_branch
})
end
end
end
+
+ describe '#remote_mirror_setting_enabled?' do
+ it 'returns false' do
+ expect(helper.remote_mirror_setting_enabled?).to be_falsy
+ end
+ end
+
+ describe '#http_clone_url_to_repo' do
+ before do
+ allow(project).to receive(:http_url_to_repo).and_return('http_url_to_repo')
+ end
+
+ subject { helper.http_clone_url_to_repo(project) }
+
+ it { expect(subject).to eq('http_url_to_repo') }
+ end
+
+ describe '#ssh_clone_url_to_repo' do
+ before do
+ allow(project).to receive(:ssh_url_to_repo).and_return('ssh_url_to_repo')
+ end
+
+ subject { helper.ssh_clone_url_to_repo(project) }
+
+ it { expect(subject).to eq('ssh_url_to_repo') }
+ end
end
diff --git a/spec/helpers/registrations_helper_spec.rb b/spec/helpers/registrations_helper_spec.rb
index eec87bc8712..b2f9a794cb3 100644
--- a/spec/helpers/registrations_helper_spec.rb
+++ b/spec/helpers/registrations_helper_spec.rb
@@ -8,20 +8,4 @@ RSpec.describe RegistrationsHelper do
expect(helper.signup_username_data_attributes.keys).to include(:min_length, :min_length_message, :max_length, :max_length_message, :qa_selector)
end
end
-
- describe '#arkose_labs_challenge_enabled?' do
- before do
- stub_application_setting(
- arkose_labs_private_api_key: nil,
- arkose_labs_public_api_key: nil,
- arkose_labs_namespace: nil
- )
- stub_env('ARKOSE_LABS_PRIVATE_KEY', nil)
- stub_env('ARKOSE_LABS_PUBLIC_KEY', nil)
- end
-
- it 'is false' do
- expect(helper.arkose_labs_challenge_enabled?).to eq false
- end
- end
end
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index c7afe0bf391..ba703914049 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -829,6 +829,21 @@ RSpec.describe SearchHelper, feature_category: :global_search do
expect(header_search_context[:project_metadata]).to eq(project_metadata)
end
+ context 'feature issues is not available' do
+ let(:feature_available) { false }
+ let(:project_metadata) { { mr_path: project_merge_requests_path(project) } }
+
+ before do
+ allow(project).to receive(:feature_available?).and_call_original
+ allow(project).to receive(:feature_available?).with(:issues, current_user).and_return(feature_available)
+ end
+
+ it 'adds the :project and :project-metadata correctly to hash' do
+ expect(header_search_context[:project]).to eq({ id: project.id, name: project.name })
+ expect(header_search_context[:project_metadata]).to eq(project_metadata)
+ end
+ end
+
context 'with scope' do
let(:scope) { 'issues' }
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index 672c2ef7589..dbb6f9bd9f3 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -62,36 +62,71 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
end
describe '#super_sidebar_context' do
- let(:user) { build(:user) }
- let(:group) { build(:group) }
+ let_it_be(:user) { build(:user) }
+ let_it_be(:group) { build(:group) }
+ let_it_be(:panel) { {} }
- subject { helper.super_sidebar_context(user, group: group, project: nil) }
+ subject do
+ helper.super_sidebar_context(user, group: group, project: nil, panel: panel)
+ end
before do
allow(helper).to receive(:current_user) { user }
- 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)
- Rails.cache.write(['users', user.id, 'total_merge_requests_count'], 4)
+ allow(helper).to receive(:can?).and_return(true)
+ allow(panel).to receive(:super_sidebar_menu_items).and_return(nil)
+ allow(panel).to receive(:super_sidebar_context_header).and_return(nil)
+ allow(user).to receive(:assigned_open_issues_count).and_return(1)
+ allow(user).to receive(:assigned_open_merge_requests_count).and_return(4)
+ allow(user).to receive(:review_requested_open_merge_requests_count).and_return(0)
+ allow(user).to receive(:todos_pending_count).and_return(3)
+ allow(user).to receive(:total_merge_requests_count).and_return(4)
end
it 'returns sidebar values from user', :use_clean_rails_memory_store_caching do
expect(subject).to include({
+ current_context_header: nil,
+ current_menu_items: nil,
name: user.name,
username: user.username,
avatar_url: user.avatar_url,
+ has_link_to_profile: helper.current_user_menu?(:profile),
+ link_to_profile: user_url(user),
+ status: {
+ can_update: helper.can?(user, :update_user_status, user),
+ busy: user.status&.busy?,
+ customized: user.status&.customized?,
+ availability: user.status&.availability.to_s,
+ emoji: user.status&.emoji,
+ message: user.status&.message_html&.html_safe,
+ clear_after: nil
+ },
+ trial: {
+ has_start_trial: helper.current_user_menu?(:start_trial),
+ url: helper.trials_link_url
+ },
+ settings: {
+ has_settings: helper.current_user_menu?(:settings),
+ profile_path: profile_path,
+ profile_preferences_path: profile_preferences_path
+ },
+ can_sign_out: helper.current_user_menu?(:sign_out),
+ sign_out_link: destroy_user_session_path,
assigned_open_issues_count: 1,
todos_pending_count: 3,
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username),
total_merge_requests_count: 4,
+ projects_path: projects_path,
+ groups_path: groups_path,
support_path: helper.support_url,
display_whats_new: helper.display_whats_new?,
whats_new_most_recent_release_items_count: helper.whats_new_most_recent_release_items_count,
whats_new_version_digest: helper.whats_new_version_digest,
show_version_check: helper.show_version_check?,
gitlab_version: Gitlab.version_info,
- gitlab_version_check: helper.gitlab_version_check
+ gitlab_version_check: helper.gitlab_version_check,
+ gitlab_com_but_not_canary: Gitlab.com_but_not_canary?,
+ gitlab_com_and_canary: Gitlab.com_and_canary?,
+ canary_toggle_com_url: Gitlab::Saas.canary_toggle_com_url
})
end
@@ -138,7 +173,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
items: array_including(
{ href: "/projects/new", text: "New project/repository" },
{ href: "/groups/new#create-group-pane", text: "New subgroup" },
- { href: "/groups/#{group.full_path}/-/group_members", text: "Invite members" }
+ { href: '', text: "Invite members" }
)
),
a_hash_including(
@@ -151,5 +186,108 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
)
)
end
+
+ describe 'current context' do
+ context 'when current context is a project' do
+ let_it_be(:project) { build(:project) }
+
+ subject do
+ helper.super_sidebar_context(user, group: nil, project: project, panel: panel)
+ end
+
+ before do
+ allow(project).to receive(:persisted?).and_return(true)
+ end
+
+ it 'returns project context' do
+ expect(subject[:current_context]).to eq({
+ namespace: 'projects',
+ item: {
+ id: project.id,
+ avatarUrl: project.avatar_url,
+ name: project.name,
+ namespace: project.full_name,
+ webUrl: project_path(project)
+ }
+ })
+ end
+ end
+
+ context 'when current context is a group' do
+ subject do
+ helper.super_sidebar_context(user, group: group, project: nil, panel: panel)
+ end
+
+ before do
+ allow(group).to receive(:persisted?).and_return(true)
+ end
+
+ it 'returns group context' do
+ expect(subject[:current_context]).to eq({
+ namespace: 'groups',
+ item: {
+ id: group.id,
+ avatarUrl: group.avatar_url,
+ name: group.name,
+ namespace: group.full_name,
+ webUrl: group_path(group)
+ }
+ })
+ end
+ end
+
+ context 'when current context is not tracked' do
+ subject do
+ helper.super_sidebar_context(user, group: nil, project: nil, panel: panel)
+ end
+
+ it 'returns no context' do
+ expect(subject[:current_context]).to eq({})
+ end
+ end
+ end
+ end
+
+ describe '#super_sidebar_nav_panel' do
+ let(:user) { build(:user) }
+ let(:group) { build(:group) }
+ let(:project) { build(:project) }
+
+ before do
+ allow(helper).to receive(:project_sidebar_context_data).and_return(
+ { current_user: nil, container: project, can_view_pipeline_editor: false, learn_gitlab_enabled: false })
+ allow(helper).to receive(:group_sidebar_context_data).and_return({ current_user: nil, container: group })
+
+ 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)
+ Rails.cache.write(['users', user.id, 'total_merge_requests_count'], 4)
+ end
+
+ it 'returns Project Panel for project nav' do
+ expect(helper.super_sidebar_nav_panel(nav: 'project')).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 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
+ expect(helper.super_sidebar_nav_panel(nav: 'user_profile')).to be_a(Sidebars::UserProfile::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
end
end
diff --git a/spec/helpers/sorting_helper_spec.rb b/spec/helpers/sorting_helper_spec.rb
index d561b08efac..d625b46e286 100644
--- a/spec/helpers/sorting_helper_spec.rb
+++ b/spec/helpers/sorting_helper_spec.rb
@@ -10,6 +10,60 @@ RSpec.describe SortingHelper do
allow(self).to receive(:request).and_return(double(path: 'http://test.com', query_parameters: { label_name: option }))
end
+ describe '#issuable_sort_options' do
+ let(:viewing_issues) { false }
+ let(:viewing_merge_requests) { false }
+ let(:params) { {} }
+
+ subject(:options) { helper.issuable_sort_options(viewing_issues, viewing_merge_requests) }
+
+ before do
+ allow(helper).to receive(:params).and_return(params)
+ end
+
+ shared_examples 'with merged date option' do
+ it 'adds merged date option' do
+ expect(options).to include(
+ a_hash_including(
+ value: 'merged_at',
+ text: 'Merged date'
+ )
+ )
+ end
+ end
+
+ shared_examples 'without merged date option' do
+ it 'does not set merged date option' do
+ expect(options).not_to include(
+ a_hash_including(
+ value: 'merged_at',
+ text: 'Merged date'
+ )
+ )
+ end
+ end
+
+ it_behaves_like 'without merged date option'
+
+ context 'when viewing_merge_requests is true' do
+ let(:viewing_merge_requests) { true }
+
+ it_behaves_like 'without merged date option'
+
+ context 'when state param is all' do
+ let(:params) { { state: 'all' } }
+
+ it_behaves_like 'with merged date option'
+ end
+
+ context 'when state param is merged' do
+ let(:params) { { state: 'merged' } }
+
+ it_behaves_like 'with merged date option'
+ end
+ end
+ end
+
describe '#admin_users_sort_options' do
it 'returns correct link attributes in array' do
options = admin_users_sort_options(filter: 'filter', search_query: 'search')
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index 26951b0c1e7..8d24e9576e0 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -135,18 +135,6 @@ RSpec.describe TodosHelper do
context 'when given a task' do
let(:todo) { task_todo }
- context 'when the use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- it 'responds with an appropriate path' do
- path = helper.todo_target_path(todo)
-
- expect(path).to eq("/#{todo.project.full_path}/-/work_items/#{todo.target.id}")
- end
- end
-
it 'responds with an appropriate path using iid' do
path = helper.todo_target_path(todo)
diff --git a/spec/helpers/users/callouts_helper_spec.rb b/spec/helpers/users/callouts_helper_spec.rb
index 4cb179e4f60..cb724816daf 100644
--- a/spec/helpers/users/callouts_helper_spec.rb
+++ b/spec/helpers/users/callouts_helper_spec.rb
@@ -165,7 +165,27 @@ RSpec.describe Users::CalloutsHelper do
end
end
- describe '#web_hook_disabled_dismissed?' do
+ describe '.show_pages_menu_callout?' do
+ subject { helper.show_pages_menu_callout? }
+
+ before do
+ allow(helper).to receive(:user_dismissed?).with(described_class::PAGES_MOVED_CALLOUT) { dismissed }
+ end
+
+ context 'when user has not dismissed' do
+ let(:dismissed) { false }
+
+ it { is_expected.to be true }
+ end
+
+ context 'when user dismissed' do
+ let(:dismissed) { true }
+
+ it { is_expected.to be false }
+ end
+ end
+
+ describe '#web_hook_disabled_dismissed?', feature_category: :integrations do
context 'without a project' do
it 'is false' do
expect(helper).not_to be_web_hook_disabled_dismissed(nil)
@@ -174,50 +194,12 @@ RSpec.describe Users::CalloutsHelper do
context 'with a project' do
let_it_be(:project) { create(:project) }
+ let(:factory) { :project_callout }
+ let(:container_key) { :project }
+ let(:container) { project }
+ let(:key) { "web_hooks:last_failure:project-#{project.id}" }
- context 'the web-hook failure callout has never been dismissed' do
- it 'is false' do
- expect(helper).not_to be_web_hook_disabled_dismissed(project)
- end
- end
-
- context 'the web-hook failure callout has been dismissed', :freeze_time do
- before do
- create(:project_callout,
- feature_name: described_class::WEB_HOOK_DISABLED,
- user: user,
- project: project,
- dismissed_at: 1.week.ago)
- end
-
- it 'is true' do
- expect(helper).to be_web_hook_disabled_dismissed(project)
- end
-
- context 'when there was an older failure', :clean_gitlab_redis_shared_state do
- let(:key) { "web_hooks:last_failure:project-#{project.id}" }
-
- before do
- Gitlab::Redis::SharedState.with { |r| r.set(key, 1.month.ago.iso8601) }
- end
-
- it 'is true' do
- expect(helper).to be_web_hook_disabled_dismissed(project)
- end
- end
-
- context 'when there has been a more recent failure', :clean_gitlab_redis_shared_state do
- let(:key) { "web_hooks:last_failure:project-#{project.id}" }
-
- before do
- Gitlab::Redis::SharedState.with { |r| r.set(key, 1.day.ago.iso8601) }
- end
-
- it 'is false' do
- expect(helper).not_to be_web_hook_disabled_dismissed(project)
- end
- end
- end
+ include_examples 'CalloutsHelper#web_hook_disabled_dismissed shared examples'
end
end
end
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index c2c78be6a0f..2829236f7d1 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe UsersHelper do
include TermsHelper
- let(:user) { create(:user) }
+ let_it_be(:user) { create(:user, timezone: ActiveSupport::TimeZone::MAPPING['UTC']) }
def filter_ee_badges(badges)
badges.reject { |badge| badge[:text] == 'Is using seat' }
@@ -37,6 +37,35 @@ RSpec.describe UsersHelper do
end
end
+ describe '#user_clear_status_at' do
+ context 'when status exists' do
+ context 'with clear_status_at set' do
+ it 'has the correct iso formatted date', time_travel_to: '2020-01-01 00:00:00 +0000' do
+ clear_status_at = 1.day.from_now
+ status = build_stubbed(:user_status, clear_status_at: clear_status_at)
+
+ expect(user_clear_status_at(status.user)).to eq('2020-01-02T00:00:00Z')
+ end
+ end
+
+ context 'without clear_status_at set' do
+ it 'returns nil' do
+ status = build_stubbed(:user_status, clear_status_at: nil)
+
+ expect(user_clear_status_at(status.user)).to be_nil
+ end
+ end
+ end
+
+ context 'without status' do
+ it 'returns nil' do
+ user = build_stubbed(:user)
+
+ expect(user_clear_status_at(user)).to be_nil
+ end
+ end
+ end
+
describe '#profile_tabs' do
subject(:tabs) { helper.profile_tabs }
@@ -468,4 +497,31 @@ RSpec.describe UsersHelper do
expect(data[:paths]).to match_schema('entities/admin_users_data_attributes_paths')
end
end
+
+ describe '#trials_link_url' do
+ it 'returns the correct URL' do
+ if Gitlab.ee?
+ expect(trials_link_url).to eq('/-/trial_registrations/new?glm_content=top-right-dropdown&glm_source=gitlab.com')
+ else
+ expect(trials_link_url).to eq('https://about.gitlab.com/free-trial/')
+ end
+ end
+ end
+
+ describe '#user_profile_tabs_app_data' do
+ before do
+ allow(helper).to receive(:user_calendar_path).with(user, :json).and_return('/users/root/calendar.json')
+ allow(user).to receive_message_chain(:followers, :count).and_return(2)
+ allow(user).to receive_message_chain(:followees, :count).and_return(3)
+ end
+
+ it 'returns expected hash' do
+ expect(helper.user_profile_tabs_app_data(user)).to eq({
+ followees: 3,
+ followers: 2,
+ user_calendar_path: '/users/root/calendar.json',
+ utc_offset: 0
+ })
+ end
+ end
end
diff --git a/spec/initializers/check_forced_decomposition_spec.rb b/spec/initializers/check_forced_decomposition_spec.rb
index a216f078932..64cb1184e7a 100644
--- a/spec/initializers/check_forced_decomposition_spec.rb
+++ b/spec/initializers/check_forced_decomposition_spec.rb
@@ -95,11 +95,7 @@ RSpec.describe 'check_forced_decomposition initializer', feature_category: :pods
it { expect { check_forced_decomposition }.to raise_error(/Separate CI database is not ready/) }
- context 'for GitLab.com' do
- before do
- allow(::Gitlab).to receive(:com?).and_return(true)
- end
-
+ context 'for SaaS', :saas do
it { expect { check_forced_decomposition }.not_to raise_error }
end
diff --git a/spec/initializers/direct_upload_support_spec.rb b/spec/initializers/direct_upload_support_spec.rb
index 670deecb4f1..68dd12fdb6e 100644
--- a/spec/initializers/direct_upload_support_spec.rb
+++ b/spec/initializers/direct_upload_support_spec.rb
@@ -69,7 +69,7 @@ RSpec.describe 'Direct upload support' do
end
context 'when other provider is used' do
- let(:provider) { 'Rackspace' }
+ let(:provider) { 'Aliyun' }
it 'raises an error' do
expect { subject }.to raise_error /Object storage provider '#{provider}' is not supported when 'direct_upload' is used for '#{config_name}'/
@@ -103,7 +103,7 @@ RSpec.describe 'Direct upload support' do
context 'when object storage is disabled' do
let(:enabled) { false }
let(:direct_upload) { false }
- let(:provider) { 'Rackspace' }
+ let(:provider) { 'Aliyun' }
it 'succeeds' do
expect { subject }.not_to raise_error
diff --git a/spec/initializers/google_cloud_profiler_spec.rb b/spec/initializers/google_cloud_profiler_spec.rb
new file mode 100644
index 00000000000..493d1e0bea5
--- /dev/null
+++ b/spec/initializers/google_cloud_profiler_spec.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'google cloud profiler', :aggregate_failures, feature_category: :application_performance do
+ subject(:load_initializer) do
+ load rails_root_join('config/initializers/google_cloud_profiler.rb')
+ end
+
+ shared_examples 'does not call profiler agent' do
+ it do
+ expect(CloudProfilerAgent::Agent).not_to receive(:new)
+
+ load_initializer
+ end
+ end
+
+ context 'when GITLAB_GOOGLE_CLOUD_PROFILER_ENABLED is set to true' do
+ before do
+ stub_env('GITLAB_GOOGLE_CLOUD_PROFILER_ENABLED', true)
+ end
+
+ context 'when GITLAB_GOOGLE_CLOUD_PROFILER_PROJECT_ID is not set' do
+ include_examples 'does not call profiler agent'
+ end
+
+ context 'when GITLAB_GOOGLE_CLOUD_PROFILER_PROJECT_ID is set' do
+ let(:project_id) { 'gitlab-staging-1' }
+ let(:agent) { instance_double(CloudProfilerAgent::Agent) }
+
+ before do
+ stub_env('GITLAB_GOOGLE_CLOUD_PROFILER_PROJECT_ID', project_id)
+ end
+
+ context 'when run in Puma context' do
+ before do
+ allow(::Gitlab::Runtime).to receive(:puma?).and_return(true)
+ allow(::Gitlab::Runtime).to receive(:sidekiq?).and_return(false)
+ end
+
+ it 'calls the agent' do
+ expect(CloudProfilerAgent::Agent)
+ .to receive(:new).with(service: 'gitlab-web', project_id: project_id,
+ logger: an_instance_of(::Gitlab::AppJsonLogger),
+ log_labels: hash_including(
+ message: 'Google Cloud Profiler Ruby',
+ pid: be_a(Integer),
+ worker_id: be_a(String)
+ )).and_return(agent)
+ expect(agent).to receive(:start)
+
+ load_initializer
+ end
+ end
+
+ context 'when run in Sidekiq context' do
+ before do
+ allow(::Gitlab::Runtime).to receive(:puma?).and_return(false)
+ allow(::Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
+ end
+
+ include_examples 'does not call profiler agent'
+ end
+
+ context 'when run in another context' do
+ before do
+ allow(::Gitlab::Runtime).to receive(:puma?).and_return(false)
+ allow(::Gitlab::Runtime).to receive(:sidekiq?).and_return(false)
+ end
+
+ include_examples 'does not call profiler agent'
+ end
+ end
+ end
+
+ context 'when GITLAB_GOOGLE_CLOUD_PROFILER_ENABLED is not set' do
+ include_examples 'does not call profiler agent'
+ end
+
+ context 'when GITLAB_GOOGLE_CLOUD_PROFILER_ENABLED is set to false' do
+ before do
+ stub_env('GITLAB_GOOGLE_CLOUD_PROFILER_ENABLED', false)
+ end
+
+ include_examples 'does not call profiler agent'
+ end
+end
diff --git a/spec/initializers/safe_session_store_patch_spec.rb b/spec/initializers/safe_session_store_patch_spec.rb
new file mode 100644
index 00000000000..b48aae02e9a
--- /dev/null
+++ b/spec/initializers/safe_session_store_patch_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'safe_sesion_store_patch', feature_category: :integrations do
+ shared_examples 'safe session store' do
+ it 'allows storing a String' do
+ session[:good_data] = 'hello world'
+
+ expect(session[:good_data]).to eq('hello world')
+ end
+
+ it 'raises error when session attempts to store an unsafe object' do
+ expect { session[:test] = Struct.new(:test) }
+ .to raise_error(/Serializing novel Ruby objects can cause uninitialized constants in mixed deployments/)
+ end
+
+ it 'allows instance double of OneLogin::RubySaml::Response' do
+ response_double = instance_double(OneLogin::RubySaml::Response)
+
+ session[:response_double] = response_double
+
+ expect(session[:response_double]).to eq(response_double)
+ end
+
+ it 'raises an error for instance double of REXML::Document' do
+ response_double = instance_double(REXML::Document)
+
+ expect { session[:response_double] = response_double }
+ .to raise_error(/Serializing novel Ruby objects can cause uninitialized constants in mixed deployments/)
+ end
+ end
+
+ context 'with ActionController::TestSession' do
+ let(:session) { ActionController::TestSession.new }
+
+ it_behaves_like 'safe session store'
+ end
+
+ context 'with ActionDispatch::Request::Session' do
+ let(:dummy_store) do
+ Class.new do
+ def load_session(_env)
+ [1, {}]
+ end
+
+ def session_exists?(_env)
+ true
+ end
+
+ def delete_session(_env, _id, _options)
+ 123
+ end
+ end.new
+ end
+
+ let(:request) { ActionDispatch::Request.new({}) }
+ let(:session) { ActionDispatch::Request::Session.create(dummy_store, request, {}) }
+
+ it_behaves_like 'safe session store'
+ end
+end
diff --git a/spec/lib/api/entities/ssh_key_spec.rb b/spec/lib/api/entities/ssh_key_spec.rb
index b4310035a66..14561beedc5 100644
--- a/spec/lib/api/entities/ssh_key_spec.rb
+++ b/spec/lib/api/entities/ssh_key_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Entities::SSHKey, feature_category: :authentication_and_authorization do
+RSpec.describe API::Entities::SSHKey, feature_category: :system_access do
describe '#as_json' do
subject { entity.as_json }
diff --git a/spec/lib/api/helpers/internal_helpers_spec.rb b/spec/lib/api/helpers/internal_helpers_spec.rb
new file mode 100644
index 00000000000..847b711f829
--- /dev/null
+++ b/spec/lib/api/helpers/internal_helpers_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe API::Helpers::InternalHelpers, feature_category: :api do
+ describe "log user git operation activity" do
+ let_it_be(:project) { create(:project) }
+ let(:user) { project.first_owner }
+ let(:internal_helper) do
+ Class.new { include API::Helpers::InternalHelpers }.new
+ end
+
+ before do
+ allow(internal_helper).to receive(:project).and_return(project)
+ end
+
+ shared_examples "handles log git operation activity" do
+ it "log the user activity" do
+ activity_service = instance_double(::Users::ActivityService)
+
+ args = { author: user, project: project, namespace: project&.namespace }
+
+ expect(Users::ActivityService).to receive(:new).with(args).and_return(activity_service)
+ expect(activity_service).to receive(:execute)
+
+ internal_helper.log_user_activity(user)
+ end
+ end
+
+ context "when git pull/fetch/clone action" do
+ before do
+ allow(internal_helper).to receive(:params).and_return(action: "git-upload-pack")
+ end
+
+ context "with log the user activity" do
+ it_behaves_like "handles log git operation activity"
+ end
+ end
+
+ context "when git push action" do
+ before do
+ allow(internal_helper).to receive(:params).and_return(action: "git-receive-pack")
+ end
+
+ it "does not log the user activity when log_user_git_push_activity is disabled" do
+ stub_feature_flags(log_user_git_push_activity: false)
+
+ expect(::Users::ActivityService).not_to receive(:new)
+
+ internal_helper.log_user_activity(user)
+ end
+
+ context "with log the user activity when log_user_git_push_activity is enabled" do
+ stub_feature_flags(log_user_git_push_activity: true)
+
+ it_behaves_like "handles log git operation activity"
+ end
+ end
+ end
+end
diff --git a/spec/lib/api/helpers/packages_helpers_spec.rb b/spec/lib/api/helpers/packages_helpers_spec.rb
index 2a663d5e9b2..6ba4396c396 100644
--- a/spec/lib/api/helpers/packages_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages_helpers_spec.rb
@@ -306,7 +306,8 @@ RSpec.describe API::Helpers::PackagesHelpers, feature_category: :package_registr
label: label,
namespace: namespace,
property: property,
- project: project
+ project: project,
+ user: user
)
end
end
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 0fcf36ca9dd..b70bcb5ab0d 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Helpers, feature_category: :not_owned do
+RSpec.describe API::Helpers, feature_category: :shared do
using RSpec::Parameterized::TableSyntax
subject(:helper) { Class.new.include(described_class).new }
diff --git a/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb b/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb
index 48787f2a0d2..f05adb49651 100644
--- a/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb
+++ b/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb
@@ -29,11 +29,11 @@ RSpec.describe Atlassian::JiraConnect::Serializers::BuildEntity, feature_categor
end
context 'when the pipeline does belong to a Jira issue' do
- let(:pipeline) { create(:ci_pipeline, merge_request: merge_request) }
+ let(:pipeline) { create(:ci_pipeline, merge_request: merge_request, project: project) }
%i[jira_branch jira_title jira_description].each do |trait|
context "because it belongs to an MR with a #{trait}" do
- let(:merge_request) { create(:merge_request, trait) }
+ let(:merge_request) { create(:merge_request, trait, source_project: project) }
describe '#issue_keys' do
it 'is not empty' do
@@ -48,5 +48,22 @@ RSpec.describe Atlassian::JiraConnect::Serializers::BuildEntity, feature_categor
end
end
end
+
+ context 'in the pipeline\'s commit messsage' do
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:commit_message) { "Merge branch 'staging' into 'master'\n\nFixes bug described in PROJ-1234" }
+
+ before do
+ allow(pipeline).to receive(:git_commit_message).and_return(commit_message)
+ end
+
+ describe '#issue_keys' do
+ it { expect(subject.issue_keys).to match_array(['PROJ-1234']) }
+ end
+
+ describe '#to_json' do
+ it { expect(subject.to_json).to be_valid_json.and match_schema(Atlassian::Schemata.build_info) }
+ end
+ end
end
end
diff --git a/spec/lib/atlassian/jira_connect_spec.rb b/spec/lib/atlassian/jira_connect_spec.rb
index 14bf13b8fe6..5238fbdb7cd 100644
--- a/spec/lib/atlassian/jira_connect_spec.rb
+++ b/spec/lib/atlassian/jira_connect_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
RSpec.describe Atlassian::JiraConnect, feature_category: :integrations do
describe '.app_name' do
diff --git a/spec/lib/atlassian/jira_issue_key_extractor_spec.rb b/spec/lib/atlassian/jira_issue_key_extractor_spec.rb
index ce29e03f818..42fc441b868 100644
--- a/spec/lib/atlassian/jira_issue_key_extractor_spec.rb
+++ b/spec/lib/atlassian/jira_issue_key_extractor_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Atlassian::JiraIssueKeyExtractor do
+RSpec.describe Atlassian::JiraIssueKeyExtractor, feature_category: :integrations do
describe '.has_keys?' do
subject { described_class.has_keys?(string) }
diff --git a/spec/lib/backup/gitaly_backup_spec.rb b/spec/lib/backup/gitaly_backup_spec.rb
index 7cc8ce2cbae..ad0e5553fa1 100644
--- a/spec/lib/backup/gitaly_backup_spec.rb
+++ b/spec/lib/backup/gitaly_backup_spec.rb
@@ -17,7 +17,8 @@ RSpec.describe Backup::GitalyBackup do
let(:expected_env) do
{
'SSL_CERT_FILE' => Gitlab::X509::Certificate.default_cert_file,
- 'SSL_CERT_DIR' => Gitlab::X509::Certificate.default_cert_dir
+ 'SSL_CERT_DIR' => Gitlab::X509::Certificate.default_cert_dir,
+ 'GITALY_SERVERS' => anything
}.merge(ENV)
end
@@ -125,12 +126,18 @@ RSpec.describe Backup::GitalyBackup do
}
end
+ let(:expected_env) do
+ ssl_env.merge(
+ 'GITALY_SERVERS' => anything
+ )
+ end
+
before do
stub_const('ENV', ssl_env)
end
it 'passes through SSL envs' do
- expect(Open3).to receive(:popen2).with(ssl_env, anything, 'create', '-path', anything, '-layout', 'pointer', '-id', backup_id).and_call_original
+ expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything, '-layout', 'pointer', '-id', backup_id).and_call_original
subject.start(:create, destination, backup_id: backup_id)
subject.finish!
diff --git a/spec/lib/banzai/filter/inline_observability_filter_spec.rb b/spec/lib/banzai/filter/inline_observability_filter_spec.rb
index fb1ba46e76c..81896faced8 100644
--- a/spec/lib/banzai/filter/inline_observability_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_observability_filter_spec.rb
@@ -2,25 +2,20 @@
require 'spec_helper'
-RSpec.describe Banzai::Filter::InlineObservabilityFilter do
+RSpec.describe Banzai::Filter::InlineObservabilityFilter, feature_category: :metrics do
include FilterSpecHelper
let(:input) { %(<a href="#{url}">example</a>) }
let(:doc) { filter(input) }
- let(:group) { create(:group) }
- let(:user) { create(:user) }
- describe '#filter?' do
- context 'when the document has an external link' do
- let(:url) { 'https://foo.com' }
-
- it 'leaves regular non-observability links unchanged' do
- expect(doc.to_s).to eq(input)
- end
- end
+ before do
+ allow(Gitlab::Observability).to receive(:embeddable_url).and_return('embeddable-url')
+ stub_config_setting(url: "https://www.gitlab.com")
+ end
- context 'when the document contains an embeddable observability link' do
- let(:url) { 'https://observe.gitlab.com/12345' }
+ describe '#filter?' do
+ context 'when the document contains a valid observability link' do
+ let(:url) { "https://www.gitlab.com/groups/some-group/-/observability/test" }
it 'leaves the original link unchanged' do
expect(doc.at_css('a').to_s).to eq(input)
@@ -30,17 +25,34 @@ RSpec.describe Banzai::Filter::InlineObservabilityFilter do
node = doc.at_css('.js-render-observability')
expect(node).to be_present
- expect(node.attribute('data-frame-url').to_s).to eq(url)
+ expect(node.attribute('data-frame-url').to_s).to eq('embeddable-url')
+ expect(Gitlab::Observability).to have_received(:embeddable_url).with(url).once
end
end
- context 'when feature flag is disabled' do
- let(:url) { 'https://observe.gitlab.com/12345' }
+ context 'with duplicate URLs' do
+ let(:url) { "https://www.gitlab.com/groups/some-group/-/observability/test" }
+ let(:input) { %(<a href="#{url}">example1</a><a href="#{url}">example2</a>) }
- before do
- stub_feature_flags(observability_group_tab: false)
+ where(:embeddable_url) do
+ [
+ 'not-nil',
+ nil
+ ]
end
+ with_them do
+ it 'calls Gitlab::Observability.embeddable_url only once' do
+ allow(Gitlab::Observability).to receive(:embeddable_url).with(url).and_return(embeddable_url)
+
+ filter(input)
+
+ expect(Gitlab::Observability).to have_received(:embeddable_url).with(url).once
+ end
+ end
+ end
+
+ shared_examples 'does not embed observabilty' do
it 'leaves the original link unchanged' do
expect(doc.at_css('a').to_s).to eq(input)
end
@@ -51,5 +63,39 @@ RSpec.describe Banzai::Filter::InlineObservabilityFilter do
expect(node).not_to be_present
end
end
+
+ context 'when the embeddable url is nil' do
+ let(:url) { "https://www.gitlab.com/groups/some-group/-/something-else/test" }
+
+ before do
+ allow(Gitlab::Observability).to receive(:embeddable_url).and_return(nil)
+ end
+
+ it_behaves_like 'does not embed observabilty'
+ end
+
+ context 'when the document has an unrecognised link' do
+ let(:url) { "https://www.gitlab.com/groups/some-group/-/something-else/test" }
+
+ it_behaves_like 'does not embed observabilty'
+
+ it 'does not build the embeddable url' do
+ expect(Gitlab::Observability).not_to have_received(:embeddable_url)
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ let(:url) { "https://www.gitlab.com/groups/some-group/-/observability/test" }
+
+ before do
+ stub_feature_flags(observability_group_tab: false)
+ end
+
+ it_behaves_like 'does not embed observabilty'
+
+ it 'does not build the embeddable url' do
+ expect(Gitlab::Observability).not_to have_received(:embeddable_url)
+ end
+ end
end
end
diff --git a/spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb b/spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb
index 1fdb29b688e..80061539a0b 100644
--- a/spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb
+++ b/spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb
@@ -162,6 +162,54 @@ RSpec.describe Banzai::Filter::IssuableReferenceExpansionFilter, feature_categor
expect(doc.css('a').last.text).to eq("#{issue.title} (#{issue.to_reference} - closed)")
end
+
+ it 'shows title for references with +s' do
+ issue = create_issue(:opened, title: 'Some issue')
+ link = create_link(issue.to_reference, issue: issue.id, reference_type: 'issue', reference_format: '+s')
+ doc = filter(link, context)
+
+ expect(doc.css('a').last.text).to eq("#{issue.title} (#{issue.to_reference}) • Unassigned")
+ end
+
+ context 'when extended summary props are present' do
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:assignees) { create_list(:user, 3) }
+ let_it_be(:issue) { create_issue(:opened, title: 'Some issue', milestone: milestone, assignees: assignees) }
+ let_it_be(:link) do
+ create_link(issue.to_reference, issue: issue.id, reference_type: 'issue', reference_format: '+s')
+ end
+
+ it 'shows extended summary for references with +s' do
+ doc = filter(link, context)
+
+ expect(doc.css('a').last.text).to eq(
+ "#{issue.title} (#{issue.to_reference}) • #{assignees[0].name}, #{assignees[1].name}+ • #{milestone.title}"
+ )
+ end
+
+ describe 'checking N+1' do
+ let_it_be(:milestone2) { create(:milestone, project: project) }
+ let_it_be(:assignees2) { create_list(:user, 3) }
+
+ it 'does not have N+1 for extended summary', :use_sql_query_cache do
+ issue2 = create_issue(:opened, title: 'Another issue', milestone: milestone2, assignees: assignees2)
+ link2 = create_link(issue2.to_reference, issue: issue2.id, reference_type: 'issue', reference_format: '+s')
+
+ # warm up
+ filter(link, context)
+
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ filter(link, context)
+ end.count
+
+ expect(control_count).to eq 10
+
+ expect do
+ filter("#{link} #{link2}", context)
+ end.not_to exceed_all_query_limit(control_count)
+ end
+ end
+ end
end
context 'for merge request references' do
@@ -235,5 +283,80 @@ RSpec.describe Banzai::Filter::IssuableReferenceExpansionFilter, feature_categor
expect(doc.css('a').last.text).to eq("#{merge_request.title} (#{merge_request.to_reference})")
end
+
+ it 'shows title for references with +s' do
+ merge_request = create_merge_request(:opened, title: 'Some merge request')
+
+ link = create_link(
+ merge_request.to_reference,
+ merge_request: merge_request.id,
+ reference_type: 'merge_request',
+ reference_format: '+s'
+ )
+
+ doc = filter(link, context)
+
+ expect(doc.css('a').last.text).to eq("#{merge_request.title} (#{merge_request.to_reference}) • Unassigned")
+ end
+
+ context 'when extended summary props are present' do
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:assignees) { create_list(:user, 2) }
+ let_it_be(:merge_request) do
+ create_merge_request(:opened, title: 'Some merge request', milestone: milestone, assignees: assignees)
+ end
+
+ let_it_be(:link) do
+ create_link(
+ merge_request.to_reference,
+ merge_request: merge_request.id,
+ reference_type: 'merge_request',
+ reference_format: '+s'
+ )
+ end
+
+ it 'shows extended summary for references with +s' do
+ doc = filter(link, context)
+
+ expect(doc.css('a').last.text).to eq(
+ "#{merge_request.title} (#{merge_request.to_reference}) • #{assignees[0].name}, #{assignees[1].name} • " \
+ "#{milestone.title}"
+ )
+ end
+
+ describe 'checking N+1' do
+ let_it_be(:milestone2) { create(:milestone, project: project) }
+ let_it_be(:assignees2) { create_list(:user, 3) }
+
+ it 'does not have N+1 for extended summary', :use_sql_query_cache do
+ merge_request2 = create_merge_request(
+ :closed,
+ title: 'Some merge request',
+ milestone: milestone2,
+ assignees: assignees2
+ )
+
+ link2 = create_link(
+ merge_request2.to_reference,
+ merge_request: merge_request2.id,
+ reference_type: 'merge_request',
+ reference_format: '+s'
+ )
+
+ # warm up
+ filter(link, context)
+
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ filter(link, context)
+ end.count
+
+ expect(control_count).to eq 10
+
+ expect do
+ filter("#{link} #{link2}", context)
+ end.not_to exceed_all_query_limit(control_count)
+ end
+ end
+ end
end
end
diff --git a/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb
index d8a97c6c3dc..aadd726ac40 100644
--- a/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb
@@ -150,6 +150,15 @@ RSpec.describe Banzai::Filter::References::IssueReferenceFilter, feature_categor
expect(link.attr('href')).to eq(issue_url)
end
+ it 'includes a data-reference-format attribute for extended summary URL references' do
+ doc = reference_filter("Issue #{issue_url}+s")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-reference-format')
+ expect(link.attr('data-reference-format')).to eq('+s')
+ expect(link.attr('href')).to eq(issue_url)
+ end
+
it 'supports an :only_path context' do
doc = reference_filter("Issue #{written_reference}", only_path: true)
link = doc.css('a').first.attr('href')
diff --git a/spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb
index 9853d6f4093..156455221cf 100644
--- a/spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb
@@ -128,6 +128,15 @@ RSpec.describe Banzai::Filter::References::MergeRequestReferenceFilter, feature_
expect(link.attr('href')).to eq(merge_request_url)
end
+ it 'includes a data-reference-format attribute for extended summary URL references' do
+ doc = reference_filter("Merge #{merge_request_url}+s")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-reference-format')
+ expect(link.attr('data-reference-format')).to eq('+s')
+ expect(link.attr('href')).to eq(merge_request_url)
+ end
+
it 'supports an :only_path context' do
doc = reference_filter("Merge #{reference}", only_path: true)
link = doc.css('a').first.attr('href')
diff --git a/spec/lib/banzai/filter/references/reference_cache_spec.rb b/spec/lib/banzai/filter/references/reference_cache_spec.rb
index 7307daca516..7e5ca00f118 100644
--- a/spec/lib/banzai/filter/references/reference_cache_spec.rb
+++ b/spec/lib/banzai/filter/references/reference_cache_spec.rb
@@ -76,8 +76,7 @@ RSpec.describe Banzai::Filter::References::ReferenceCache, feature_category: :te
cache_single.load_records_per_parent
end.count
- expect(control_count).to eq 1
-
+ expect(control_count).to eq 2
# Since this is an issue filter that is not batching issue queries
# across projects, we have to account for that.
# 1 for original issue, 2 for second route/project, 1 for other issue
diff --git a/spec/lib/bulk_imports/clients/http_spec.rb b/spec/lib/bulk_imports/clients/http_spec.rb
index 780f61f8c61..40261947750 100644
--- a/spec/lib/bulk_imports/clients/http_spec.rb
+++ b/spec/lib/bulk_imports/clients/http_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe BulkImports::Clients::HTTP, feature_category: :importers do
let(:resource) { 'resource' }
let(:version) { "#{BulkImport::MIN_MAJOR_VERSION}.0.0" }
let(:enterprise) { false }
+ let(:sidekiq_request_timeout) { described_class::SIDEKIQ_REQUEST_TIMEOUT }
let(:response_double) { double(code: 200, success?: true, parsed_response: {}) }
let(:metadata_response) do
double(
@@ -123,6 +124,36 @@ RSpec.describe BulkImports::Clients::HTTP, feature_category: :importers do
allow(Gitlab::HTTP).to receive(:get).with(uri, params).and_return(response)
end
end
+
+ context 'when the request is asynchronous' do
+ let(:expected_args) do
+ [
+ 'http://gitlab.example/api/v4/resource',
+ hash_including(
+ query: {
+ page: described_class::DEFAULT_PAGE,
+ per_page: described_class::DEFAULT_PER_PAGE,
+ private_token: token
+ },
+ headers: {
+ 'Content-Type' => 'application/json'
+ },
+ follow_redirects: true,
+ resend_on_redirect: false,
+ limit: 2,
+ timeout: sidekiq_request_timeout
+ )
+ ]
+ end
+
+ it 'sets a timeout that is double the default read timeout' do
+ allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
+
+ expect(Gitlab::HTTP).to receive(method).with(*expected_args).and_return(response_double)
+
+ subject.public_send(method, resource)
+ end
+ end
end
describe '#post' do
@@ -253,7 +284,7 @@ RSpec.describe BulkImports::Clients::HTTP, feature_category: :importers do
stub_request(:get, 'http://gitlab.example/api/v4/metadata?private_token=token')
.to_return(status: 404, body: "", headers: { 'Content-Type' => 'application/json' })
- expect { subject.instance_version }.to raise_exception(BulkImports::Error, 'Import aborted as it was not possible to connect to the provided GitLab instance URL.')
+ expect { subject.instance_version }.to raise_exception(BulkImports::Error, 'Invalid source URL. Enter only the base URL of the source GitLab instance.')
end
end
diff --git a/spec/lib/bulk_imports/features_spec.rb b/spec/lib/bulk_imports/features_spec.rb
deleted file mode 100644
index a92e4706bbe..00000000000
--- a/spec/lib/bulk_imports/features_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe BulkImports::Features do
- describe '.project_migration_enabled' do
- let_it_be(:top_level_namespace) { create(:group) }
-
- context 'when bulk_import_projects feature flag is enabled' do
- it 'returns true' do
- stub_feature_flags(bulk_import_projects: true)
-
- expect(described_class.project_migration_enabled?).to eq(true)
- end
-
- context 'when feature flag is enabled on root ancestor level' do
- it 'returns true' do
- stub_feature_flags(bulk_import_projects: top_level_namespace)
-
- expect(described_class.project_migration_enabled?(top_level_namespace.full_path)).to eq(true)
- end
- end
-
- context 'when feature flag is enabled on a different top level namespace' do
- it 'returns false' do
- stub_feature_flags(bulk_import_projects: top_level_namespace)
-
- different_namepace = create(:group)
-
- expect(described_class.project_migration_enabled?(different_namepace.full_path)).to eq(false)
- end
- end
- end
-
- context 'when bulk_import_projects feature flag is disabled' do
- it 'returns false' do
- stub_feature_flags(bulk_import_projects: false)
-
- expect(described_class.project_migration_enabled?(top_level_namespace.full_path)).to eq(false)
- end
- end
- end
-end
diff --git a/spec/lib/bulk_imports/groups/stage_spec.rb b/spec/lib/bulk_imports/groups/stage_spec.rb
index cc772f07d21..7c3127beb97 100644
--- a/spec/lib/bulk_imports/groups/stage_spec.rb
+++ b/spec/lib/bulk_imports/groups/stage_spec.rb
@@ -68,40 +68,16 @@ RSpec.describe BulkImports::Groups::Stage, feature_category: :importers do
end
end
- context 'when bulk_import_projects feature flag is enabled' do
- it 'includes project entities pipeline' do
- stub_feature_flags(bulk_import_projects: true)
-
- expect(described_class.new(entity).pipelines).to include(
- hash_including({ pipeline: BulkImports::Groups::Pipelines::ProjectEntitiesPipeline })
- )
- end
-
- describe 'migrate projects flag' do
- context 'when true' do
- it 'includes project entities pipeline' do
- entity.update!(migrate_projects: true)
-
- expect(described_class.new(entity).pipelines).to include(
- hash_including({ pipeline: BulkImports::Groups::Pipelines::ProjectEntitiesPipeline })
- )
- end
- end
-
- context 'when false' do
- it 'does not include project entities pipeline' do
- entity.update!(migrate_projects: false)
-
- expect(described_class.new(entity).pipelines).not_to include(
- hash_including({ pipeline: BulkImports::Groups::Pipelines::ProjectEntitiesPipeline })
- )
- end
- end
- end
+ it 'includes project entities pipeline' do
+ expect(described_class.new(entity).pipelines).to include(
+ hash_including({ pipeline: BulkImports::Groups::Pipelines::ProjectEntitiesPipeline })
+ )
+ end
- context 'when feature flag is enabled on root ancestor level' do
+ describe 'migrate projects flag' do
+ context 'when true' do
it 'includes project entities pipeline' do
- stub_feature_flags(bulk_import_projects: ancestor)
+ entity.update!(migrate_projects: true)
expect(described_class.new(entity).pipelines).to include(
hash_including({ pipeline: BulkImports::Groups::Pipelines::ProjectEntitiesPipeline })
@@ -109,24 +85,22 @@ RSpec.describe BulkImports::Groups::Stage, feature_category: :importers do
end
end
- context 'when destination namespace is not present' do
- it 'includes project entities pipeline' do
- stub_feature_flags(bulk_import_projects: true)
-
- entity = create(:bulk_import_entity, destination_namespace: '')
+ context 'when false' do
+ it 'does not include project entities pipeline' do
+ entity.update!(migrate_projects: false)
- expect(described_class.new(entity).pipelines).to include(
+ expect(described_class.new(entity).pipelines).not_to include(
hash_including({ pipeline: BulkImports::Groups::Pipelines::ProjectEntitiesPipeline })
)
end
end
end
- context 'when bulk_import_projects feature flag is disabled' do
- it 'does not include project entities pipeline' do
- stub_feature_flags(bulk_import_projects: false)
+ context 'when destination namespace is not present' do
+ it 'includes project entities pipeline' do
+ entity = create(:bulk_import_entity, destination_namespace: '')
- expect(described_class.new(entity).pipelines).not_to include(
+ expect(described_class.new(entity).pipelines).to include(
hash_including({ pipeline: BulkImports::Groups::Pipelines::ProjectEntitiesPipeline })
)
end
diff --git a/spec/lib/bulk_imports/ndjson_pipeline_spec.rb b/spec/lib/bulk_imports/ndjson_pipeline_spec.rb
index 25edc9feea8..29f42ab3366 100644
--- a/spec/lib/bulk_imports/ndjson_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/ndjson_pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::NdjsonPipeline do
+RSpec.describe BulkImports::NdjsonPipeline, feature_category: :importers do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
@@ -150,13 +150,63 @@ RSpec.describe BulkImports::NdjsonPipeline do
describe '#load' do
context 'when object is not persisted' do
+ it 'saves the object using RelationObjectSaver' do
+ object = double(persisted?: false, new_record?: true)
+
+ allow(subject).to receive(:relation_definition)
+
+ expect_next_instance_of(Gitlab::ImportExport::Base::RelationObjectSaver) do |saver|
+ expect(saver).to receive(:execute)
+ end
+
+ subject.load(nil, object)
+ end
+
+ context 'when object is invalid' do
+ it 'captures invalid subrelations' do
+ entity = create(:bulk_import_entity, group: group)
+ tracker = create(:bulk_import_tracker, entity: entity)
+ context = BulkImports::Pipeline::Context.new(tracker)
+
+ allow(subject).to receive(:context).and_return(context)
+
+ object = group.labels.new(priorities: [LabelPriority.new])
+ object.validate
+
+ allow_next_instance_of(Gitlab::ImportExport::Base::RelationObjectSaver) do |saver|
+ allow(saver).to receive(:execute)
+ allow(saver).to receive(:invalid_subrelations).and_return(object.priorities)
+ end
+
+ subject.load(context, object)
+
+ failure = entity.failures.first
+
+ expect(failure.pipeline_class).to eq(tracker.pipeline_name)
+ expect(failure.exception_class).to eq('RecordInvalid')
+ expect(failure.exception_message).to eq("Project can't be blank, Priority can't be blank, and Priority is not a number")
+ end
+ end
+ end
+
+ context 'when object is persisted' do
it 'saves the object' do
- object = double(persisted?: false)
+ object = double(new_record?: false, invalid?: false)
expect(object).to receive(:save!)
subject.load(nil, object)
end
+
+ context 'when object is invalid' do
+ it 'raises ActiveRecord::RecordInvalid exception' do
+ object = build_stubbed(:issue)
+
+ expect(Gitlab::Import::Errors).to receive(:merge_nested_errors).with(object)
+
+ expect { subject.load(nil, object) }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+ end
end
context 'when object is missing' do
diff --git a/spec/lib/bulk_imports/projects/pipelines/ci_pipelines_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/ci_pipelines_pipeline_spec.rb
index a78f524b227..63e7cdf2e5a 100644
--- a/spec/lib/bulk_imports/projects/pipelines/ci_pipelines_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/projects/pipelines/ci_pipelines_pipeline_spec.rb
@@ -109,6 +109,13 @@ RSpec.describe BulkImports::Projects::Pipelines::CiPipelinesPipeline do
'name' => 'first status',
'status' => 'created'
}
+ ],
+ 'builds' => [
+ {
+ 'name' => 'second status',
+ 'status' => 'created',
+ 'ref' => 'abcd'
+ }
]
}
]
@@ -119,6 +126,7 @@ RSpec.describe BulkImports::Projects::Pipelines::CiPipelinesPipeline do
stage = project.all_pipelines.first.stages.first
expect(stage.name).to eq('test stage')
expect(stage.statuses.first.name).to eq('first status')
+ expect(stage.builds.first.name).to eq('second status')
end
end
diff --git a/spec/lib/bulk_imports/projects/pipelines/commit_notes_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/commit_notes_pipeline_spec.rb
new file mode 100644
index 00000000000..f5f31c83033
--- /dev/null
+++ b/spec/lib/bulk_imports/projects/pipelines/commit_notes_pipeline_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::Projects::Pipelines::CommitNotesPipeline, feature_category: :importers do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:bulk_import) { create(:bulk_import, user: user) }
+ let_it_be(:entity) do
+ create(
+ :bulk_import_entity,
+ :project_entity,
+ project: project,
+ bulk_import: bulk_import,
+ source_full_path: 'source/full/path',
+ destination_slug: 'destination-project',
+ destination_namespace: group.full_path
+ )
+ end
+
+ let(:ci_pipeline_note) do
+ {
+ "note" => "Commit note 1",
+ "noteable_type" => "Commit",
+ "author_id" => 1,
+ "created_at" => "2023-01-30T19:27:36.585Z",
+ "updated_at" => "2023-02-10T14:43:01.308Z",
+ "project_id" => 1,
+ "commit_id" => "sha-notes",
+ "system" => false,
+ "updated_by_id" => 1,
+ "discussion_id" => "e3fde7d585c6467a7a5147e83617eb6daa61aaf4",
+ "last_edited_at" => "2023-02-10T14:43:01.306Z",
+ "author" => {
+ "name" => "Administrator"
+ },
+ "events" => [
+ {
+ "project_id" => 1,
+ "author_id" => 1,
+ "action" => "commented",
+ "target_type" => "Note"
+ }
+ ]
+ }
+ end
+
+ let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
+ let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
+
+ subject(:pipeline) { described_class.new(context) }
+
+ describe '#run' do
+ before do
+ group.add_owner(user)
+
+ allow_next_instance_of(BulkImports::Common::Extractors::NdjsonExtractor) do |extractor|
+ allow(extractor).to receive(:extract).and_return(
+ BulkImports::Pipeline::ExtractedData.new(data: [ci_pipeline_note])
+ )
+ end
+ end
+
+ it 'imports ci pipeline notes into destination project' do
+ expect { pipeline.run }.to change { project.notes.for_commit_id("sha-notes").count }.from(0).to(1)
+ end
+ end
+end
diff --git a/spec/lib/container_registry/gitlab_api_client_spec.rb b/spec/lib/container_registry/gitlab_api_client_spec.rb
index 7d78aad8b13..73364ec9698 100644
--- a/spec/lib/container_registry/gitlab_api_client_spec.rb
+++ b/spec/lib/container_registry/gitlab_api_client_spec.rb
@@ -320,6 +320,98 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
end
end
+ describe '#sub_repositories_with_tag' do
+ let(:path) { 'namespace/path/to/repository' }
+ let(:page_size) { 100 }
+ let(:last) { nil }
+ let(:response) do
+ [
+ {
+ "name": "docker-alpine",
+ "path": "gitlab-org/build/cng/docker-alpine",
+ "created_at": "2022-06-07T12:11:13.633+00:00",
+ "updated_at": "2022-06-07T14:37:49.251+00:00"
+ },
+ {
+ "name": "git-base",
+ "path": "gitlab-org/build/cng/git-base",
+ "created_at": "2022-06-07T12:11:13.633+00:00",
+ "updated_at": "2022-06-07T14:37:49.251+00:00"
+ }
+ ]
+ end
+
+ let(:result_with_no_pagination) do
+ {
+ pagination: {},
+ response_body: ::Gitlab::Json.parse(response.to_json)
+ }
+ end
+
+ subject { client.sub_repositories_with_tag(path, page_size: page_size, last: last) }
+
+ context 'with valid parameters' do
+ before do
+ stub_sub_repositories_with_tag(path, page_size: page_size, respond_with: response)
+ end
+
+ it { is_expected.to eq(result_with_no_pagination) }
+ end
+
+ context 'with a response with a link header' do
+ let(:next_page_url) { 'http://sandbox.org/test?last=c' }
+ let(:expected) do
+ {
+ pagination: { next: { uri: URI(next_page_url) } },
+ response_body: ::Gitlab::Json.parse(response.to_json)
+ }
+ end
+
+ before do
+ stub_sub_repositories_with_tag(path, page_size: page_size, next_page_url: next_page_url, respond_with: response)
+ end
+
+ it { is_expected.to eq(expected) }
+ end
+
+ context 'with a large page size set' do
+ let(:page_size) { described_class::MAX_TAGS_PAGE_SIZE + 1000 }
+
+ before do
+ stub_sub_repositories_with_tag(path, page_size: described_class::MAX_TAGS_PAGE_SIZE, respond_with: response)
+ end
+
+ it { is_expected.to eq(result_with_no_pagination) }
+ end
+
+ context 'with a last parameter set' do
+ let(:last) { 'test' }
+
+ before do
+ stub_sub_repositories_with_tag(path, page_size: page_size, last: last, respond_with: response)
+ end
+
+ it { is_expected.to eq(result_with_no_pagination) }
+ end
+
+ context 'with non successful response' do
+ before do
+ stub_sub_repositories_with_tag(path, page_size: page_size, status_code: 404)
+ end
+
+ it 'logs an error and returns an empty hash' do
+ expect(Gitlab::ErrorTracking)
+ .to receive(:log_exception).with(
+ instance_of(described_class::UnsuccessfulResponseError),
+ class: described_class.name,
+ url: "/gitlab/v1/repository-paths/#{path}/repositories/list/",
+ status_code: 404
+ )
+ expect(subject).to eq({})
+ end
+ end
+ end
+
describe '.supports_gitlab_api?' do
subject { described_class.supports_gitlab_api? }
@@ -439,6 +531,90 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
end
end
+ describe '.one_project_with_container_registry_tag' do
+ let(:path) { 'build/cng/docker-alpine' }
+ let(:response_body) do
+ [
+ {
+ "name" => "docker-alpine",
+ "path" => path,
+ "created_at" => "2022-06-07T12:11:13.633+00:00",
+ "updated_at" => "2022-06-07T14:37:49.251+00:00"
+ }
+ ]
+ end
+
+ let(:response) do
+ {
+ pagination: { next: { uri: URI('http://sandbox.org/test?last=x') } },
+ response_body: ::Gitlab::Json.parse(response_body.to_json)
+ }
+ end
+
+ let_it_be(:group) { create(:group, path: 'build') }
+ let_it_be(:project) { create(:project, name: 'cng', namespace: group) }
+ let_it_be(:container_repository) { create(:container_repository, project: project, name: "docker-alpine") }
+
+ shared_examples 'fetching the project from container repository and path' do
+ it 'fetches the project from the given path details' do
+ expect(ContainerRegistry::Path).to receive(:new).with(path).and_call_original
+ expect(ContainerRepository).to receive(:find_by_path).and_call_original
+
+ expect(subject).to eq(project)
+ end
+
+ it 'returns nil when path is invalid' do
+ registry_path = ContainerRegistry::Path.new('invalid')
+ expect(ContainerRegistry::Path).to receive(:new).with(path).and_return(registry_path)
+ expect(registry_path.valid?).to eq(false)
+
+ expect(subject).to eq(nil)
+ end
+
+ it 'returns nil when there is no container_repository matching the path' do
+ expect(ContainerRegistry::Path).to receive(:new).with(path).and_call_original
+ expect(ContainerRepository).to receive(:find_by_path).and_return(nil)
+
+ expect(subject).to eq(nil)
+ end
+ end
+
+ subject { described_class.one_project_with_container_registry_tag(path) }
+
+ before do
+ expect(Auth::ContainerRegistryAuthenticationService).to receive(:pull_nested_repositories_access_token).with(path.downcase).and_return(token)
+ stub_container_registry_config(enabled: true, api_url: registry_api_url, key: 'spec/fixtures/x509_certificate_pk.key')
+ end
+
+ context 'with successful response' do
+ before do
+ stub_sub_repositories_with_tag(path, page_size: 1, respond_with: response_body)
+ end
+
+ it_behaves_like 'fetching the project from container repository and path'
+ end
+
+ context 'with unsuccessful response' do
+ before do
+ stub_sub_repositories_with_tag(path, page_size: 1, status_code: 404, respond_with: {})
+ end
+
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'with uppercase path' do
+ let(:path) { 'BuilD/CNG/docker-alpine' }
+
+ before do
+ expect_next_instance_of(described_class) do |client|
+ expect(client).to receive(:sub_repositories_with_tag).with(path.downcase, page_size: 1).and_return(response.with_indifferent_access).once
+ end
+ end
+
+ it_behaves_like 'fetching the project from container repository and path'
+ end
+ end
+
def stub_pre_import(path, status_code, pre:)
import_type = pre ? 'pre' : 'final'
stub_request(:put, "#{registry_api_url}/gitlab/v1/import/#{path}/?import_type=#{import_type}")
@@ -525,4 +701,30 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
headers: response_headers
)
end
+
+ def stub_sub_repositories_with_tag(path, page_size: nil, last: nil, next_page_url: nil, status_code: 200, respond_with: {})
+ params = { n: page_size, last: last }.compact
+
+ url = "#{registry_api_url}/gitlab/v1/repository-paths/#{path}/repositories/list/"
+
+ if params.present?
+ url += "?#{params.map { |param, val| "#{param}=#{val}" }.join('&')}"
+ end
+
+ request_headers = { 'Accept' => described_class::JSON_TYPE }
+ request_headers['Authorization'] = "bearer #{token}" if token
+
+ response_headers = { 'Content-Type' => described_class::JSON_TYPE }
+ if next_page_url
+ response_headers['Link'] = "<#{next_page_url}>; rel=\"next\""
+ end
+
+ stub_request(:get, url)
+ .with(headers: request_headers)
+ .to_return(
+ status: status_code,
+ body: respond_with.to_json,
+ headers: response_headers
+ )
+ end
end
diff --git a/spec/lib/error_tracking/collector/payload_validator_spec.rb b/spec/lib/error_tracking/collector/payload_validator_spec.rb
index 94708f63bf4..96ad66e9b58 100644
--- a/spec/lib/error_tracking/collector/payload_validator_spec.rb
+++ b/spec/lib/error_tracking/collector/payload_validator_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe ErrorTracking::Collector::PayloadValidator do
end
with_them do
- let(:payload) { Gitlab::Json.parse(fixture_file(event_fixture)) }
+ let(:payload) { Gitlab::Json.parse(File.read(event_fixture)) }
it_behaves_like 'valid payload'
end
diff --git a/spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb b/spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb
new file mode 100644
index 00000000000..d533bcf0039
--- /dev/null
+++ b/spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'rails/generators/testing/behaviour'
+require 'rails/generators/testing/assertions'
+
+RSpec.describe BatchedBackgroundMigration::BatchedBackgroundMigrationGenerator, feature_category: :database do
+ include Rails::Generators::Testing::Behaviour
+ include Rails::Generators::Testing::Assertions
+ include FileUtils
+
+ tests described_class
+ destination File.expand_path('tmp', __dir__)
+
+ before do
+ prepare_destination
+ end
+
+ after do
+ rm_rf(destination_root)
+ end
+
+ context 'with valid arguments' do
+ let(:expected_migration_file) { load_expected_file('queue_my_batched_migration.txt') }
+ let(:expected_migration_spec_file) { load_expected_file('queue_my_batched_migration_spec.txt') }
+ let(:expected_migration_job_file) { load_expected_file('my_batched_migration.txt') }
+ let(:expected_migration_job_spec_file) { load_expected_file('my_batched_migration_spec_matcher.txt') }
+ let(:expected_migration_dictionary) { load_expected_file('my_batched_migration_dictionary_matcher.txt') }
+
+ it 'generates expected files' do
+ run_generator %w[my_batched_migration --table_name=projects --column_name=id --feature_category=database]
+
+ assert_migration('db/post_migrate/queue_my_batched_migration.rb') do |migration_file|
+ expect(migration_file).to eq(expected_migration_file)
+ end
+
+ assert_migration('spec/migrations/queue_my_batched_migration_spec.rb') do |migration_spec_file|
+ expect(migration_spec_file).to eq(expected_migration_spec_file)
+ end
+
+ assert_file('lib/gitlab/background_migration/my_batched_migration.rb') do |migration_job_file|
+ expect(migration_job_file).to eq(expected_migration_job_file)
+ end
+
+ assert_file('spec/lib/gitlab/background_migration/my_batched_migration_spec.rb') do |migration_job_spec_file|
+ # Regex is used to match the dynamic schema: <version> in the specs
+ expect(migration_job_spec_file).to match(/#{expected_migration_job_spec_file}/)
+ end
+
+ assert_file('db/docs/batched_background_migrations/my_batched_migration.yml') do |migration_dictionary|
+ # Regex is used to match the dynamically generated 'milestone' in the dictionary
+ expect(migration_dictionary).to match(/#{expected_migration_dictionary}/)
+ end
+ end
+ end
+
+ context 'without required arguments' do
+ it 'throws table_name is required error' do
+ expect do
+ run_generator %w[my_batched_migration]
+ end.to raise_error(ArgumentError, 'table_name is required')
+ end
+
+ it 'throws column_name is required error' do
+ expect do
+ run_generator %w[my_batched_migration --table_name=projects]
+ end.to raise_error(ArgumentError, 'column_name is required')
+ end
+
+ it 'throws feature_category is required error' do
+ expect do
+ run_generator %w[my_batched_migration --table_name=projects --column_name=id]
+ end.to raise_error(ArgumentError, 'feature_category is required')
+ end
+ end
+
+ private
+
+ def load_expected_file(file_name)
+ File.read(File.expand_path("expected_files/#{file_name}", __dir__))
+ end
+end
diff --git a/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration.txt b/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration.txt
new file mode 100644
index 00000000000..b2378b414b1
--- /dev/null
+++ b/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration.txt
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/database/batched_background_migrations.html
+# for more information on how to use batched background migrations
+
+# Update below commented lines with appropriate values.
+
+module Gitlab
+ module BackgroundMigration
+ class MyBatchedMigration < BatchedMigrationJob
+ # operation_name :my_operation
+ # scope_to ->(relation) { relation.where(column: "value") }
+ feature_category :database
+
+ def perform
+ each_sub_batch do |sub_batch|
+ # Your action on each sub_batch
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_dictionary_matcher.txt b/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_dictionary_matcher.txt
new file mode 100644
index 00000000000..6280d35177e
--- /dev/null
+++ b/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_dictionary_matcher.txt
@@ -0,0 +1,6 @@
+---
+migration_job_name: MyBatchedMigration
+description: # Please capture what MyBatchedMigration does
+feature_category: database
+introduced_by_url: # URL of the MR \(or issue/commit\) that introduced the migration
+milestone: [0-9\.]+
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
new file mode 100644
index 00000000000..2728d65d54b
--- /dev/null
+++ b/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_spec_matcher.txt
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::MyBatchedMigration, schema: [0-9]+, feature_category: :database do # rubocop:disable Layout/LineLength
+ # Tests go here
+end
diff --git a/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt b/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt
new file mode 100644
index 00000000000..536e07d56aa
--- /dev/null
+++ b/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/database/batched_background_migrations.html
+# for more information on when/how to queue batched background migrations
+
+# Update below commented lines with appropriate values.
+
+class QueueMyBatchedMigration < Gitlab::Database::Migration[2.1]
+ MIGRATION = "MyBatchedMigration"
+ # DELAY_INTERVAL = 2.minutes
+ # BATCH_SIZE = 1000
+ # SUB_BATCH_SIZE = 100
+
+ def up
+ 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/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration_spec.txt b/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration_spec.txt
new file mode 100644
index 00000000000..6f33de4ae83
--- /dev/null
+++ b/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration_spec.txt
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueMyBatchedMigration, feature_category: :database 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: :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
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 d9fa6b931ad..6826006949e 100644
--- a/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb
+++ b/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb
@@ -2,10 +2,10 @@
require 'spec_helper'
-RSpec.describe Gitlab::SnowplowEventDefinitionGenerator, :silence_stdout do
+RSpec.describe Gitlab::SnowplowEventDefinitionGenerator, :silence_stdout, feature_category: :product_analytics do
let(:ce_temp_dir) { Dir.mktmpdir }
let(:ee_temp_dir) { Dir.mktmpdir }
- let(:timestamp) { Time.current.to_i }
+ let(:timestamp) { Time.now.utc.strftime('%Y%m%d%H%M%S') }
let(:generator_options) { { 'category' => 'Groups::EmailCampaignsController', 'action' => 'click' } }
before do
@@ -30,7 +30,8 @@ RSpec.describe Gitlab::SnowplowEventDefinitionGenerator, :silence_stdout do
let(:file_name) { Dir.children(ce_temp_dir).first }
it 'creates CE event definition file using the template' do
- sample_event = ::Gitlab::Config::Loader::Yaml.new(fixture_file(File.join(sample_event_dir, 'sample_event.yml'))).load_raw!
+ sample_event = ::Gitlab::Config::Loader::Yaml
+ .new(fixture_file(File.join(sample_event_dir, 'sample_event.yml'))).load_raw!
described_class.new([], generator_options).invoke_all
@@ -62,25 +63,13 @@ RSpec.describe Gitlab::SnowplowEventDefinitionGenerator, :silence_stdout do
end
end
- context 'event definition already exists' do
+ context 'when event definition with same file name already exists' do
before do
stub_const('Gitlab::VERSION', '12.11.0-pre')
described_class.new([], generator_options).invoke_all
end
- it 'overwrites event definition --force flag set to true' do
- sample_event = ::Gitlab::Config::Loader::Yaml.new(fixture_file(File.join(sample_event_dir, 'sample_event.yml'))).load_raw!
-
- stub_const('Gitlab::VERSION', '13.11.0-pre')
- described_class.new([], generator_options.merge('force' => true)).invoke_all
-
- event_definition_path = File.join(ce_temp_dir, file_name)
- event_data = ::Gitlab::Config::Loader::Yaml.new(File.read(event_definition_path)).load_raw!
-
- expect(event_data).to eq(sample_event)
- end
-
- it 'raises error when --force flag set to false' do
+ it 'raises error' do
expect { described_class.new([], generator_options.merge('force' => false)).invoke_all }
.to raise_error(StandardError, /Event definition already exists at/)
end
@@ -90,7 +79,8 @@ RSpec.describe Gitlab::SnowplowEventDefinitionGenerator, :silence_stdout do
let(:file_name) { Dir.children(ee_temp_dir).first }
it 'creates EE event definition file using the template' do
- sample_event = ::Gitlab::Config::Loader::Yaml.new(fixture_file(File.join(sample_event_dir, 'sample_event_ee.yml'))).load_raw!
+ sample_event = ::Gitlab::Config::Loader::Yaml
+ .new(fixture_file(File.join(sample_event_dir, 'sample_event_ee.yml'))).load_raw!
described_class.new([], generator_options.merge('ee' => true)).invoke_all
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb
index de325454b34..122a94a39c2 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::Average do
subject(:average_duration_in_seconds) { average.seconds }
context 'when no results' do
- let(:query) { Issue.none }
+ let(:query) { Issue.joins(:metrics).none }
it { is_expected.to eq(nil) }
end
@@ -54,7 +54,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::Average do
subject(:average_duration_in_days) { average.days }
context 'when no results' do
- let(:query) { Issue.none }
+ let(:query) { Issue.joins(:metrics).none }
it { is_expected.to eq(nil) }
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb
new file mode 100644
index 00000000000..3c171d684d6
--- /dev/null
+++ b/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Analytics::CycleAnalytics::RequestParams, feature_category: :value_stream_management do
+ it_behaves_like 'unlicensed cycle analytics request params' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:root_group) { create(:group) }
+ let_it_be_with_refind(:project) { create(:project, group: root_group) }
+
+ let(:namespace) { project.project_namespace }
+
+ describe 'project-level data attributes' do
+ subject(:attributes) { described_class.new(params).to_data_attributes }
+
+ it 'includes the namespace attribute' do
+ expect(attributes).to match(hash_including({
+ namespace: {
+ name: project.name,
+ full_path: project.full_path
+ }
+ }))
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
index 1e0034e386e..24248c557bd 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
-RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent, feature_category: :product_analytics do
let(:instance) { described_class.new({}) }
it { expect(described_class).to respond_to(:name) }
diff --git a/spec/lib/gitlab/api_authentication/token_resolver_spec.rb b/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
index c0c8e7aba63..48cae42dcd2 100644
--- a/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
+++ b/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::APIAuthentication::TokenResolver, feature_category: :authentication_and_authorization do
+RSpec.describe Gitlab::APIAuthentication::TokenResolver, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :public) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
diff --git a/spec/lib/gitlab/app_logger_spec.rb b/spec/lib/gitlab/app_logger_spec.rb
index 85ca60d539f..e3415f4ad8c 100644
--- a/spec/lib/gitlab/app_logger_spec.rb
+++ b/spec/lib/gitlab/app_logger_spec.rb
@@ -5,22 +5,27 @@ require 'spec_helper'
RSpec.describe Gitlab::AppLogger do
subject { described_class }
- it 'builds two Logger instances' do
- expect(Gitlab::Logger).to receive(:new).and_call_original
- expect(Gitlab::JsonLogger).to receive(:new).and_call_original
+ context 'when UNSTRUCTURED_RAILS_LOG is enabled' do
+ before do
+ stub_env('UNSTRUCTURED_RAILS_LOG', 'true')
+ end
- subject.info('Hello World!')
- end
+ it 'builds two Logger instances' do
+ expect(Gitlab::Logger).to receive(:new).and_call_original
+ expect(Gitlab::JsonLogger).to receive(:new).and_call_original
- it 'logs info to AppLogger and AppJsonLogger' do
- expect_any_instance_of(Gitlab::AppTextLogger).to receive(:info).and_call_original
- expect_any_instance_of(Gitlab::AppJsonLogger).to receive(:info).and_call_original
+ subject.info('Hello World!')
+ end
- subject.info('Hello World!')
+ it 'logs info to AppLogger and AppJsonLogger' do
+ expect_any_instance_of(Gitlab::AppTextLogger).to receive(:info).and_call_original
+ expect_any_instance_of(Gitlab::AppJsonLogger).to receive(:info).and_call_original
+
+ subject.info('Hello World!')
+ end
end
it 'logs info to only the AppJsonLogger when unstructured logs are disabled' do
- stub_env('UNSTRUCTURED_RAILS_LOG', 'false')
expect_any_instance_of(Gitlab::AppTextLogger).not_to receive(:info).and_call_original
expect_any_instance_of(Gitlab::AppJsonLogger).to receive(:info).and_call_original
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index cb9d1e9eae8..21cd87e89dc 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -369,7 +369,7 @@ module Gitlab
<div>
<div>
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre lang="javascript" class="code highlight js-syntax-highlight language-javascript" data-canonical-lang="js" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>
+ <pre lang="javascript" class="code highlight js-syntax-highlight language-javascript" data-canonical-lang="js" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>
<copy-code></copy-code>
</div>
</div>
diff --git a/spec/lib/gitlab/audit/auditor_spec.rb b/spec/lib/gitlab/audit/auditor_spec.rb
index 4b16333d913..2b3c8506440 100644
--- a/spec/lib/gitlab/audit/auditor_spec.rb
+++ b/spec/lib/gitlab/audit/auditor_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Audit::Auditor do
+RSpec.describe Gitlab::Audit::Auditor, feature_category: :audit_events do
let(:name) { 'audit_operation' }
let(:author) { create(:user, :with_sign_ins) }
let(:group) { create(:group) }
@@ -22,9 +22,9 @@ RSpec.describe Gitlab::Audit::Auditor do
subject(:auditor) { described_class }
describe '.audit' do
- context 'when authentication event' do
- let(:audit!) { auditor.audit(context) }
+ let(:audit!) { auditor.audit(context) }
+ context 'when authentication event' do
it 'creates an authentication event' do
expect(AuthenticationEvent).to receive(:new).with(
{
@@ -210,19 +210,38 @@ RSpec.describe Gitlab::Audit::Auditor do
end
context 'when authentication event is false' do
+ let(:target) { group }
let(:context) do
{ name: name, author: author, scope: group,
- target: group, authentication_event: false, message: "sample message" }
+ target: target, authentication_event: false, message: "sample message" }
end
it 'does not create an authentication event' do
expect { auditor.audit(context) }.not_to change(AuthenticationEvent, :count)
end
+
+ context 'with permitted target' do
+ { feature_flag: :operations_feature_flag }.each do |target_type, factory_name|
+ context "with #{target_type}" do
+ let(:target) { build_stubbed factory_name }
+
+ it 'logs audit events to database', :aggregate_failures, :freeze_time do
+ audit!
+ audit_event = AuditEvent.last
+
+ expect(audit_event.author_id).to eq(author.id)
+ expect(audit_event.entity_id).to eq(group.id)
+ expect(audit_event.entity_type).to eq(group.class.name)
+ expect(audit_event.created_at).to eq(Time.zone.now)
+ expect(audit_event.details[:target_id]).to eq(target.id)
+ expect(audit_event.details[:target_type]).to eq(target.class.name)
+ end
+ end
+ end
+ end
end
context 'when authentication event is invalid' do
- let(:audit!) { auditor.audit(context) }
-
before do
allow(AuthenticationEvent).to receive(:new).and_raise(ActiveRecord::RecordInvalid)
allow(Gitlab::ErrorTracking).to receive(:track_exception)
@@ -243,8 +262,6 @@ RSpec.describe Gitlab::Audit::Auditor do
end
context 'when audit events are invalid' do
- let(:audit!) { auditor.audit(context) }
-
before do
expect_next_instance_of(AuditEvent) do |instance|
allow(instance).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb
index 6aedd0a0a23..ecc5c688228 100644
--- a/spec/lib/gitlab/auth/auth_finders_spec.rb
+++ b/spec/lib/gitlab/auth/auth_finders_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Auth::AuthFinders, feature_category: :authentication_and_authorization do
+RSpec.describe Gitlab::Auth::AuthFinders, feature_category: :system_access do
include described_class
include HttpBasicAuthHelpers
diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb
index 04fbbff3559..8a86b306604 100644
--- a/spec/lib/gitlab/auth/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Auth::OAuth::User, feature_category: :authentication_and_authorization do
+RSpec.describe Gitlab::Auth::OAuth::User, feature_category: :system_access do
include LdapHelpers
let(:oauth_user) { described_class.new(auth_hash) }
diff --git a/spec/lib/gitlab/auth/otp/strategies/duo_auth/manual_otp_spec.rb b/spec/lib/gitlab/auth/otp/strategies/duo_auth/manual_otp_spec.rb
new file mode 100644
index 00000000000..d04e0ad9fb4
--- /dev/null
+++ b/spec/lib/gitlab/auth/otp/strategies/duo_auth/manual_otp_spec.rb
@@ -0,0 +1,94 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Auth::Otp::Strategies::DuoAuth::ManualOtp, feature_category: :system_access do
+ let_it_be(:user) { create(:user) }
+
+ let_it_be(:otp_code) { 42 }
+
+ let_it_be(:hostname) { 'duo_auth.example.com' }
+ let_it_be(:integration_key) { 'int3gr4t1on' }
+ let_it_be(:secret_key) { 's3cr3t' }
+
+ let_it_be(:duo_response_builder) { Struct.new(:body) }
+
+ let_it_be(:response_status) { 200 }
+
+ let_it_be(:duo_auth_url) { "https://#{hostname}/auth/v2/auth/" }
+ let_it_be(:params) do
+ { username: user.username,
+ factor: "passcode",
+ passcode: otp_code }
+ end
+
+ let_it_be(:manual_otp) { described_class.new(user) }
+
+ subject(:response) { manual_otp.validate(otp_code) }
+
+ before do
+ stub_duo_auth_config(
+ enabled: true,
+ hostname: hostname,
+ secret_key: secret_key,
+ integration_key: integration_key
+ )
+ end
+
+ context 'when successful validation' do
+ before do
+ allow(duo_client).to receive(:request)
+ .with("POST", "/auth/v2/auth", params)
+ .and_return(duo_response_builder.new('{ "response": { "result": "allow" }}'))
+
+ allow(manual_otp).to receive(:duo_client).and_return(duo_client)
+ end
+
+ it 'returns success' do
+ response
+
+ expect(response[:status]).to eq(:success)
+ end
+ end
+
+ context 'when unsuccessful validation' do
+ before do
+ allow(duo_client).to receive(:request)
+ .with("POST", "/auth/v2/auth", params)
+ .and_return(duo_response_builder.new('{ "response": { "result": "deny" }}'))
+
+ allow(manual_otp).to receive(:duo_client).and_return(duo_client)
+ end
+
+ it 'returns error' do
+ response
+
+ expect(response[:status]).to eq(:error)
+ end
+ end
+
+ context 'when unexpected error' do
+ before do
+ allow(duo_client).to receive(:request)
+ .with("POST", "/auth/v2/auth", params)
+ .and_return(duo_response_builder.new('aaa'))
+
+ allow(manual_otp).to receive(:duo_client).and_return(duo_client)
+ end
+
+ it 'returns error' do
+ response
+
+ expect(response[:status]).to eq(:error)
+ expect(response[:message]).to match(/unexpected character/)
+ end
+ end
+
+ def stub_duo_auth_config(duo_auth_settings)
+ allow(::Gitlab.config.duo_auth).to(receive_messages(duo_auth_settings))
+ end
+
+ def duo_client
+ manual_otp.send(:duo_client)
+ end
+end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index a5f46aa1f35..11e9ecdb878 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_category: :authentication_and_authorization do
+RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_category: :system_access do
let_it_be(:project) { create(:project) }
let(:auth_failure) { { actor: nil, project: nil, type: nil, authentication_abilities: nil } }
diff --git a/spec/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens_spec.rb b/spec/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens_spec.rb
index 7075d4694ae..d2da6867773 100644
--- a/spec/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_admin_mode_scope_for_personal_access_tokens_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillAdminModeScopeForPersonalAccessTokens,
- :migration, schema: 20221228103133, feature_category: :authentication_and_authorization do
+ :migration, schema: 20221228103133, feature_category: :system_access do
let(:users) { table(:users) }
let(:personal_access_tokens) { table(:personal_access_tokens) }
diff --git a/spec/lib/gitlab/background_migration/backfill_prepared_at_merge_requests_spec.rb b/spec/lib/gitlab/background_migration/backfill_prepared_at_merge_requests_spec.rb
new file mode 100644
index 00000000000..b33a1a31c40
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_prepared_at_merge_requests_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillPreparedAtMergeRequests, :migration,
+ feature_category: :code_review_workflow, schema: 20230202135758 do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:mr_table) { table(:merge_requests) }
+
+ let(:namespace) { namespaces.create!(name: 'batchtest1', type: 'Group', path: 'space1') }
+ let(:proj_namespace) { namespaces.create!(name: 'proj1', path: 'proj1', type: 'Project', parent_id: namespace.id) }
+ let(:project) do
+ projects.create!(name: 'proj1', path: 'proj1', namespace_id: namespace.id, project_namespace_id: proj_namespace.id)
+ end
+
+ let(:test_worker) do
+ described_class.new(
+ start_id: 1,
+ end_id: 100,
+ batch_table: :merge_requests,
+ batch_column: :id,
+ sub_batch_size: 10,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection
+ )
+ end
+
+ it 'updates merge requests with prepared_at nil' do
+ time = Time.current
+
+ mr_1 = mr_table.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'feature',
+ prepared_at: nil, merge_status: 'checking')
+ mr_2 = mr_table.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'feature',
+ prepared_at: nil, merge_status: 'preparing')
+ mr_3 = mr_table.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'feature',
+ prepared_at: time)
+ mr_4 = mr_table.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'feature',
+ prepared_at: time, merge_status: 'checking')
+ mr_5 = mr_table.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'feature',
+ prepared_at: time, merge_status: 'preparing')
+
+ expect(mr_1.prepared_at).to be_nil
+ expect(mr_2.prepared_at).to be_nil
+ expect(mr_3.prepared_at.to_i).to eq(time.to_i)
+ expect(mr_4.prepared_at.to_i).to eq(time.to_i)
+ expect(mr_5.prepared_at.to_i).to eq(time.to_i)
+
+ test_worker.perform
+
+ expect(mr_1.reload.prepared_at.to_i).to eq(mr_1.created_at.to_i)
+ expect(mr_2.reload.prepared_at).to be_nil
+ expect(mr_3.reload.prepared_at.to_i).to eq(time.to_i)
+ expect(mr_4.reload.prepared_at.to_i).to eq(time.to_i)
+ expect(mr_5.reload.prepared_at.to_i).to eq(time.to_i)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/backfill_project_wiki_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_wiki_repositories_spec.rb
new file mode 100644
index 00000000000..e81bd0604e6
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_project_wiki_repositories_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe(
+ Gitlab::BackgroundMigration::BackfillProjectWikiRepositories,
+ schema: 20230306195007,
+ feature_category: :geo_replication) do
+ let!(:namespaces) { table(:namespaces) }
+ let!(:projects) { table(:projects) }
+ let!(:project_wiki_repositories) { table(:project_wiki_repositories) }
+
+ subject(:migration) do
+ described_class.new(
+ start_id: projects.minimum(:id),
+ end_id: projects.maximum(:id),
+ batch_table: :projects,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ )
+ end
+
+ describe '#perform' do
+ it 'creates project_wiki_repositories entries for all projects in range' do
+ namespace1 = create_namespace('test1')
+ namespace2 = create_namespace('test2')
+ project1 = create_project(namespace1, 'test1')
+ project2 = create_project(namespace2, 'test2')
+ project_wiki_repositories.create!(project_id: project2.id)
+
+ expect { migration.perform }
+ .to change { project_wiki_repositories.pluck(:project_id) }
+ .from([project2.id])
+ .to match_array([project1.id, project2.id])
+ end
+
+ it 'does nothing if project_id already exist in project_wiki_repositories' do
+ namespace = create_namespace('test1')
+ project = create_project(namespace, 'test1')
+ project_wiki_repositories.create!(project_id: project.id)
+
+ expect { migration.perform }
+ .not_to change { project_wiki_repositories.pluck(:project_id) }
+ end
+
+ def create_namespace(name)
+ namespaces.create!(
+ name: name,
+ path: name,
+ type: 'Project'
+ )
+ end
+
+ def create_project(namespace, name)
+ projects.create!(
+ namespace_id: namespace.id,
+ project_namespace_id: namespace.id,
+ name: name,
+ path: name
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb b/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb
index faaaccfdfaf..781bf93dd85 100644
--- a/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb
+++ b/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb
@@ -301,6 +301,28 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
perform_job
end
+ context 'when using a sub batch exception for timeouts' do
+ let(:job_class) do
+ Class.new(described_class) do
+ operation_name :update
+
+ def perform(*_)
+ each_sub_batch { raise ActiveRecord::StatementTimeout } # rubocop:disable Lint/UnreachableLoop
+ end
+ end
+ end
+
+ let(:job_instance) do
+ job_class.new(start_id: 1, end_id: 10, batch_table: '_test_table', batch_column: 'id',
+ sub_batch_size: 2, pause_ms: 1000, connection: connection,
+ sub_batch_exception: StandardError)
+ end
+
+ it 'raises the expected error type' do
+ expect { job_instance.perform }.to raise_error(StandardError)
+ end
+ end
+
context 'when batching_arguments are given' do
it 'forwards them for batching' do
expect(job_instance).to receive(:base_relation).and_return(test_table)
diff --git a/spec/lib/gitlab/background_migration/delete_orphaned_packages_dependencies_spec.rb b/spec/lib/gitlab/background_migration/delete_orphaned_packages_dependencies_spec.rb
new file mode 100644
index 00000000000..0d82717c7de
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/delete_orphaned_packages_dependencies_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::DeleteOrphanedPackagesDependencies, schema: 20230303105806,
+ feature_category: :package_registry do
+ let!(:migration_attrs) do
+ {
+ start_id: 1,
+ end_id: 1000,
+ batch_table: :packages_dependencies,
+ batch_column: :id,
+ sub_batch_size: 500,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection
+ }
+ end
+
+ let!(:migration) { described_class.new(**migration_attrs) }
+
+ let(:packages_dependencies) { table(:packages_dependencies) }
+
+ 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) do
+ table(:packages_packages).create!(name: 'test', version: '1.2.3', package_type: 2, project_id: project.id)
+ end
+
+ let!(:orphan_dependency_1) { packages_dependencies.create!(name: 'dependency 1', version_pattern: '~0.0.1') }
+ let!(:orphan_dependency_2) { packages_dependencies.create!(name: 'dependency 2', version_pattern: '~0.0.2') }
+ let!(:orphan_dependency_3) { packages_dependencies.create!(name: 'dependency 3', version_pattern: '~0.0.3') }
+ let!(:linked_dependency) do
+ packages_dependencies.create!(name: 'dependency 4', version_pattern: '~0.0.4').tap do |dependency|
+ table(:packages_dependency_links).create!(package_id: package.id, dependency_id: dependency.id,
+ dependency_type: 'dependencies')
+ end
+ end
+
+ subject(:perform_migration) { migration.perform }
+
+ it 'executes 3 queries' do
+ queries = ActiveRecord::QueryRecorder.new do
+ perform_migration
+ end
+
+ expect(queries.count).to eq(3)
+ end
+
+ it 'deletes only orphaned dependencies' do
+ expect { perform_migration }.to change { packages_dependencies.count }.by(-3)
+ expect(packages_dependencies.all).to eq([linked_dependency])
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/fix_vulnerability_reads_has_issues_spec.rb b/spec/lib/gitlab/background_migration/fix_vulnerability_reads_has_issues_spec.rb
new file mode 100644
index 00000000000..9f431c43f39
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/fix_vulnerability_reads_has_issues_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::FixVulnerabilityReadsHasIssues, schema: 20230302185739, feature_category: :vulnerability_management 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(:work_item_types) { table(:work_item_types) }
+ let(:issues) { table(:issues) }
+ let(:vulnerability_issue_links) { table(:vulnerability_issue_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(:work_item_type) { work_item_types.create!(name: 'test') }
+
+ let(:vulnerability_records) do
+ Array.new(4).map do |_, n|
+ vulnerabilities.create!(
+ project_id: project.id,
+ author_id: user.id,
+ title: "vulnerability #{n}",
+ severity: 1,
+ confidence: 1,
+ report_type: 1
+ )
+ end
+ end
+
+ let(:vulnerabilities_with_issues) { [vulnerability_records.first, vulnerability_records.third] }
+ let(:vulnerabilities_without_issues) { vulnerability_records - vulnerabilities_with_issues }
+
+ let(:vulnerability_read_records) do
+ vulnerability_records.map do |vulnerability|
+ vulnerability_reads.create!(
+ project_id: project.id,
+ vulnerability_id: vulnerability.id,
+ scanner_id: scanner.id,
+ has_issues: false,
+ severity: 1,
+ report_type: 1,
+ state: 1,
+ uuid: SecureRandom.uuid
+ )
+ end
+ end
+
+ let!(:issue_links) do
+ vulnerabilities_with_issues.map do |vulnerability|
+ issue = issues.create!(
+ title: vulnerability.title,
+ author_id: user.id,
+ project_id: project.id,
+ confidential: true,
+ work_item_type_id: work_item_type.id,
+ namespace_id: namespace.id
+ )
+
+ vulnerability_issue_links.create!(
+ vulnerability_id: vulnerability.id,
+ issue_id: issue.id
+ )
+ end
+ end
+
+ def vulnerability_read_for(vulnerability)
+ vulnerability_read_records.find { |read| read.vulnerability_id == vulnerability.id }
+ end
+
+ subject(:perform_migration) do
+ described_class.new(
+ start_id: issue_links.first.vulnerability_id,
+ end_id: issue_links.last.vulnerability_id,
+ batch_table: :vulnerability_issue_links,
+ batch_column: :vulnerability_id,
+ sub_batch_size: issue_links.size,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
+ end
+
+ it 'only changes records with issue links' do
+ expect(vulnerability_read_records).to all(have_attributes(has_issues: false))
+
+ perform_migration
+
+ vulnerabilities_with_issues.each do |vulnerability|
+ expect(vulnerability_read_for(vulnerability).reload.has_issues).to eq(true)
+ end
+
+ vulnerabilities_without_issues.each do |vulnerability|
+ expect(vulnerability_read_for(vulnerability).reload.has_issues).to eq(false)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/issues_internal_id_scope_updater_spec.rb b/spec/lib/gitlab/background_migration/issues_internal_id_scope_updater_spec.rb
new file mode 100644
index 00000000000..1adff322b41
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/issues_internal_id_scope_updater_spec.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+# this needs the schema to be before we introduce the not null constraint on routes#namespace_id
+# rubocop:disable RSpec/MultipleMemoizedHelpers
+RSpec.describe Gitlab::BackgroundMigration::IssuesInternalIdScopeUpdater, feature_category: :team_planning do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:internal_ids) { table(:internal_ids) }
+
+ let(:gr1) { namespaces.create!(name: 'batchtest1', type: 'Group', path: 'space1') }
+ let(:gr2) { namespaces.create!(name: 'batchtest2', type: 'Group', parent_id: gr1.id, path: 'space2') }
+
+ let(:pr_nmsp1) { namespaces.create!(name: 'proj1', path: 'proj1', type: 'Project', parent_id: gr1.id) }
+ let(:pr_nmsp2) { namespaces.create!(name: 'proj2', path: 'proj2', type: 'Project', parent_id: gr1.id) }
+ let(:pr_nmsp3) { namespaces.create!(name: 'proj3', path: 'proj3', type: 'Project', parent_id: gr2.id) }
+ let(:pr_nmsp4) { namespaces.create!(name: 'proj4', path: 'proj4', type: 'Project', parent_id: gr2.id) }
+ let(:pr_nmsp5) { namespaces.create!(name: 'proj5', path: 'proj5', type: 'Project', parent_id: gr2.id) }
+ let(:pr_nmsp6) { namespaces.create!(name: 'proj6', path: 'proj6', type: 'Project', parent_id: gr2.id) }
+
+ # rubocop:disable Layout/LineLength
+ let(:p1) { projects.create!(name: 'proj1', path: 'proj1', namespace_id: gr1.id, project_namespace_id: pr_nmsp1.id) }
+ let(:p2) { projects.create!(name: 'proj2', path: 'proj2', namespace_id: gr1.id, project_namespace_id: pr_nmsp2.id) }
+ let(:p3) { projects.create!(name: 'proj3', path: 'proj3', namespace_id: gr2.id, project_namespace_id: pr_nmsp3.id) }
+ let(:p4) { projects.create!(name: 'proj4', path: 'proj4', namespace_id: gr2.id, project_namespace_id: pr_nmsp4.id) }
+ let(:p5) { projects.create!(name: 'proj5', path: 'proj5', namespace_id: gr2.id, project_namespace_id: pr_nmsp5.id) }
+ let(:p6) { projects.create!(name: 'proj6', path: 'proj6', namespace_id: gr2.id, project_namespace_id: pr_nmsp6.id) }
+ # rubocop:enable Layout/LineLength
+
+ # a project that already is covered by a record for its namespace. This should result in no new record added and
+ # project related record deleted
+ let!(:issues_internal_ids_p1) { internal_ids.create!(project_id: p1.id, usage: 0, last_value: 100) }
+ let!(:issues_internal_ids_pr_nmsp1) { internal_ids.create!(namespace_id: pr_nmsp1.id, usage: 0, last_value: 111) }
+
+ # project records that do not have a corresponding namespace record. This should result 2 new records
+ # scoped to corresponding project namespaces being added and the project related records being deleted.
+ let!(:issues_internal_ids_p2) { internal_ids.create!(project_id: p2.id, usage: 0, last_value: 200) }
+ let!(:issues_internal_ids_p3) { internal_ids.create!(project_id: p3.id, usage: 0, last_value: 300) }
+
+ # a project record on a different usage, should not be affected by the migration and
+ # no new record should be created for this case
+ let!(:issues_internal_ids_p4) { internal_ids.create!(project_id: p4.id, usage: 4, last_value: 400) }
+
+ # a project namespace scoped record without a corresponding project record, should not affect anything.
+ let!(:issues_internal_ids_pr_nmsp5) { internal_ids.create!(namespace_id: pr_nmsp5.id, usage: 0, last_value: 500) }
+
+ # a record scoped to a group, should not affect anything.
+ let!(:issues_internal_ids_gr1) { internal_ids.create!(namespace_id: gr1.id, usage: 0, last_value: 600) }
+
+ # a project that is covered by a record for its namespace, but has a higher last_value, due to updates during rolling
+ # deploy for instance, see https://gitlab.com/gitlab-com/gl-infra/production/-/issues/8548
+ let!(:issues_internal_ids_p6) { internal_ids.create!(project_id: p6.id, usage: 0, last_value: 111) }
+ let!(:issues_internal_ids_pr_nmsp6) { internal_ids.create!(namespace_id: pr_nmsp6.id, usage: 0, last_value: 100) }
+
+ subject(:perform_migration) do
+ described_class.new(
+ start_id: internal_ids.minimum(:id),
+ end_id: internal_ids.maximum(:id),
+ batch_table: :internal_ids,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
+ end
+
+ it 'backfills internal_ids records and removes related project records', :aggregate_failures do
+ perform_migration
+
+ expected_recs = [pr_nmsp1.id, pr_nmsp2.id, pr_nmsp3.id, pr_nmsp5.id, gr1.id, pr_nmsp6.id]
+
+ # all namespace scoped records for issues(0) usage
+ expect(internal_ids.where.not(namespace_id: nil).where(usage: 0).count).to eq(6)
+ # all namespace_ids for issues(0) usage
+ expect(internal_ids.where.not(namespace_id: nil).where(usage: 0).pluck(:namespace_id)).to match_array(expected_recs)
+ # this is the record with usage: 4
+ expect(internal_ids.where.not(project_id: nil).count).to eq(1)
+ # no project scoped records for issues usage left
+ expect(internal_ids.where.not(project_id: nil).where(usage: 0).count).to eq(0)
+
+ # the case when the project_id scoped record had the higher last_value,
+ # see `issues_internal_ids_p6` and issues_internal_ids_pr_nmsp6 definitions above
+ expect(internal_ids.where(namespace_id: pr_nmsp6.id).first.last_value).to eq(111)
+
+ # the case when the namespace_id scoped record had the higher last_value,
+ # see `issues_internal_ids_p1` and issues_internal_ids_pr_nmsp1 definitions above.
+ expect(internal_ids.where(namespace_id: pr_nmsp1.id).first.last_value).to eq(111)
+ end
+end
+# rubocop:enable RSpec/MultipleMemoizedHelpers
diff --git a/spec/lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings_spec.rb b/spec/lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings_spec.rb
new file mode 100644
index 00000000000..b70044ab2a4
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings_spec.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::MigrateEvidencesForVulnerabilityFindings,
+ feature_category: :vulnerability_management do
+ let(:vulnerability_occurrences) { table(:vulnerability_occurrences) }
+ let(:vulnerability_finding_evidences) { table(:vulnerability_finding_evidences) }
+ let(:evidence_hash) { { url: 'http://test.com' } }
+ let(:namespace1) { table(:namespaces).create!(name: 'namespace 1', path: 'namespace1') }
+ let(:project1) { table(:projects).create!(namespace_id: namespace1.id, project_namespace_id: namespace1.id) }
+ let(:user) { table(:users).create!(email: 'test1@example.com', projects_limit: 5) }
+
+ let(:scanner1) do
+ table(:vulnerability_scanners).create!(project_id: project1.id, external_id: 'test 1', name: 'test scanner 1')
+ end
+
+ let(:stating_id) { vulnerability_occurrences.pluck(:id).min }
+ let(:end_id) { vulnerability_occurrences.pluck(:id).max }
+
+ let(:migration) do
+ described_class.new(
+ start_id: stating_id,
+ end_id: end_id,
+ batch_table: :vulnerability_occurrences,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 2,
+ connection: ApplicationRecord.connection
+ )
+ end
+
+ subject(:perform_migration) { migration.perform }
+
+ context 'without the presence of evidence key' do
+ before do
+ create_finding!(project1.id, scanner1.id, { other_keys: 'test' })
+ end
+
+ it 'does not create any evidence' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_finding_evidences.count }
+ end
+ end
+
+ context 'with evidence equals to nil' do
+ before do
+ create_finding!(project1.id, scanner1.id, { evidence: nil })
+ end
+
+ it 'does not create any evidence' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_finding_evidences.count }
+ end
+ end
+
+ context 'with existing evidence within raw_metadata' do
+ let!(:finding1) { create_finding!(project1.id, scanner1.id, { evidence: evidence_hash }) }
+ let!(:finding2) { create_finding!(project1.id, scanner1.id, { evidence: evidence_hash }) }
+
+ it 'creates new evidence for each finding' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.to change { vulnerability_finding_evidences.count }.by(2)
+ end
+
+ context 'when create throws exception StandardError' do
+ before do
+ allow(migration).to receive(:create_evidences).and_raise(StandardError)
+ end
+
+ it 'logs StandardError' do
+ expect(Gitlab::AppLogger).to receive(:error).with({
+ class: described_class.name, message: StandardError.to_s
+ })
+ expect { perform_migration }.not_to change { vulnerability_finding_evidences.count }
+ end
+ end
+
+ context 'when parse throws exception JSON::ParserError' do
+ before do
+ allow(Gitlab::Json).to receive(:parse).and_raise(JSON::ParserError)
+ end
+
+ it 'does not log this error nor create new records' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_finding_evidences.count }
+ end
+ end
+ end
+
+ context 'with existing evidence records' do
+ let!(:finding) { create_finding!(project1.id, scanner1.id, { evidence: evidence_hash }) }
+
+ before do
+ vulnerability_finding_evidences.create!(vulnerability_occurrence_id: finding.id, data: evidence_hash)
+ end
+
+ it 'does not create new evidence' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_finding_evidences.count }
+ end
+
+ context 'with non-existing evidence' do
+ let!(:finding3) { create_finding!(project1.id, scanner1.id, { evidence: { url: 'http://secondary.com' } }) }
+
+ it 'creates a new evidence only to the non-existing evidence' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.to change { vulnerability_finding_evidences.count }.by(1)
+ end
+ end
+ end
+
+ private
+
+ def create_finding!(project_id, scanner_id, raw_metadata)
+ vulnerability = table(:vulnerabilities).create!(project_id: project_id, author_id: user.id, title: 'test',
+ severity: 4, confidence: 4, report_type: 0)
+
+ identifier = table(:vulnerability_identifiers).create!(project_id: project_id, external_type: 'uuid-v5',
+ external_id: 'uuid-v5', fingerprint: OpenSSL::Digest::SHA256.hexdigest(vulnerability.id.to_s),
+ name: 'Identifier for UUIDv5 2 2')
+
+ table(:vulnerability_occurrences).create!(
+ vulnerability_id: vulnerability.id, project_id: project_id, scanner_id: scanner_id,
+ primary_identifier_id: identifier.id, name: 'test', severity: 4, confidence: 4, report_type: 0,
+ uuid: SecureRandom.uuid, project_fingerprint: '123qweasdzxc', location: { "image" => "alpine:3.4" },
+ location_fingerprint: 'test', metadata_version: 'test',
+ raw_metadata: raw_metadata.to_json)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/migrate_links_for_vulnerability_findings_spec.rb b/spec/lib/gitlab/background_migration/migrate_links_for_vulnerability_findings_spec.rb
new file mode 100644
index 00000000000..fd2e3ffb670
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_links_for_vulnerability_findings_spec.rb
@@ -0,0 +1,141 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::MigrateLinksForVulnerabilityFindings,
+ feature_category: :vulnerability_management do
+ let(:vulnerability_occurrences) { table(:vulnerability_occurrences) }
+ let(:vulnerability_finding_links) { table(:vulnerability_finding_links) }
+ let(:link_hash) { { url: 'http://test.com' } }
+ let(:namespace1) { table(:namespaces).create!(name: 'namespace 1', path: 'namespace1') }
+ let(:project1) { table(:projects).create!(namespace_id: namespace1.id, project_namespace_id: namespace1.id) }
+ let(:user) { table(:users).create!(email: 'test1@example.com', projects_limit: 5) }
+
+ let(:scanner1) do
+ table(:vulnerability_scanners).create!(project_id: project1.id, external_id: 'test 1', name: 'test scanner 1')
+ end
+
+ let(:stating_id) { vulnerability_occurrences.pluck(:id).min }
+ let(:end_id) { vulnerability_occurrences.pluck(:id).max }
+
+ let(:migration) do
+ described_class.new(
+ start_id: stating_id,
+ end_id: end_id,
+ batch_table: :vulnerability_occurrences,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 2,
+ connection: ApplicationRecord.connection
+ )
+ end
+
+ subject(:perform_migration) { migration.perform }
+
+ context 'without the presence of links key' do
+ before do
+ create_finding!(project1.id, scanner1.id, { other_keys: 'test' })
+ end
+
+ it 'does not create any link' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_finding_links.count }
+ end
+ end
+
+ context 'with links equals to an array of nil element' do
+ before do
+ create_finding!(project1.id, scanner1.id, { links: [nil] })
+ end
+
+ it 'does not create any link' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_finding_links.count }
+ end
+ end
+
+ context 'with links equals to an array of duplicated elements' do
+ let!(:finding) do
+ create_finding!(project1.id, scanner1.id, { links: [link_hash, link_hash] })
+ end
+
+ it 'creates one new link' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.to change { vulnerability_finding_links.count }.by(1)
+ end
+ end
+
+ context 'with existing links within raw_metadata' do
+ let!(:finding1) { create_finding!(project1.id, scanner1.id, { links: [link_hash] }) }
+ let!(:finding2) { create_finding!(project1.id, scanner1.id, { links: [link_hash] }) }
+
+ it 'creates new link for each finding' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.to change { vulnerability_finding_links.count }.by(2)
+ end
+
+ context 'when create throws exception ActiveRecord::RecordNotUnique' do
+ before do
+ allow(migration).to receive(:create_links).and_raise(ActiveRecord::RecordNotUnique)
+ end
+
+ it 'does not log this error nor create new records' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_finding_links.count }
+ end
+ end
+
+ context 'when create throws exception StandardError' do
+ before do
+ allow(migration).to receive(:create_links).and_raise(StandardError)
+ end
+
+ it 'logs StandardError' do
+ expect(Gitlab::AppLogger).to receive(:error).with({
+ class: described_class.name, message: StandardError.to_s, model_id: finding1.id
+ })
+ expect(Gitlab::AppLogger).to receive(:error).with({
+ class: described_class.name, message: StandardError.to_s, model_id: finding2.id
+ })
+ expect { perform_migration }.not_to change { vulnerability_finding_links.count }
+ end
+ end
+ end
+
+ context 'with existing link records' do
+ let!(:finding) { create_finding!(project1.id, scanner1.id, { links: [link_hash] }) }
+
+ before do
+ vulnerability_finding_links.create!(vulnerability_occurrence_id: finding.id, url: link_hash[:url])
+ end
+
+ it 'does not create new link' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_finding_links.count }
+ end
+ end
+
+ private
+
+ def create_finding!(project_id, scanner_id, raw_metadata)
+ vulnerability = table(:vulnerabilities).create!(project_id: project_id, author_id: user.id, title: 'test',
+ severity: 4, confidence: 4, report_type: 0)
+
+ identifier = table(:vulnerability_identifiers).create!(project_id: project_id, external_type: 'uuid-v5',
+ external_id: 'uuid-v5', fingerprint: OpenSSL::Digest::SHA256.hexdigest(vulnerability.id.to_s),
+ name: 'Identifier for UUIDv5 2 2')
+
+ table(:vulnerability_occurrences).create!(
+ vulnerability_id: vulnerability.id, project_id: project_id, scanner_id: scanner_id,
+ primary_identifier_id: identifier.id, name: 'test', severity: 4, confidence: 4, report_type: 0,
+ uuid: SecureRandom.uuid, project_fingerprint: '123qweasdzxc', location: { "image" => "alpine:3.4" },
+ location_fingerprint: 'test', metadata_version: 'test',
+ raw_metadata: raw_metadata.to_json)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb b/spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb
new file mode 100644
index 00000000000..b75c0e61b19
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb
@@ -0,0 +1,173 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::MigrateRemediationsForVulnerabilityFindings,
+ feature_category: :vulnerability_management do
+ let(:vulnerability_occurrences) { table(:vulnerability_occurrences) }
+ let(:vulnerability_findings_remediations) { table(:vulnerability_findings_remediations) }
+ let(:vulnerability_remediations) { table(:vulnerability_remediations) }
+ let(:remediation_hash) { { summary: 'summary', diff: "ZGlmZiAtLWdp" } }
+ let(:namespace1) { table(:namespaces).create!(name: 'namespace 1', path: 'namespace1') }
+ let(:project1) { table(:projects).create!(namespace_id: namespace1.id, project_namespace_id: namespace1.id) }
+ let(:user) { table(:users).create!(email: 'test1@example.com', projects_limit: 5) }
+
+ let(:scanner1) do
+ table(:vulnerability_scanners).create!(project_id: project1.id, external_id: 'test 1', name: 'test scanner 1')
+ end
+
+ let(:stating_id) { vulnerability_occurrences.pluck(:id).min }
+ let(:end_id) { vulnerability_occurrences.pluck(:id).max }
+
+ let(:migration) do
+ described_class.new(
+ start_id: stating_id,
+ end_id: end_id,
+ batch_table: :vulnerability_occurrences,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 2,
+ connection: ApplicationRecord.connection
+ )
+ end
+
+ subject(:perform_migration) { migration.perform }
+
+ context 'without the presence of remediation key' do
+ before do
+ create_finding!(project1.id, scanner1.id, { other_keys: 'test' })
+ end
+
+ it 'does not create any remediation' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_remediations.count }
+ end
+ end
+
+ context 'with remediation equals to an array of nil element' do
+ before do
+ create_finding!(project1.id, scanner1.id, { remediations: [nil] })
+ end
+
+ it 'does not create any remediation' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_remediations.count }
+ end
+ end
+
+ context 'with remediation with empty string as the diff key' do
+ let!(:finding) do
+ create_finding!(project1.id, scanner1.id, { remediations: [{ summary: 'summary', diff: '' }] })
+ end
+
+ it 'does not create any remediation' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_remediations.count }
+ end
+ end
+
+ context 'with remediation equals to an array of duplicated elements' do
+ let!(:finding) do
+ create_finding!(project1.id, scanner1.id, { remediations: [remediation_hash, remediation_hash] })
+ end
+
+ it 'creates new remediation' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.to change { vulnerability_remediations.count }.by(1)
+ expect(vulnerability_findings_remediations.where(vulnerability_occurrence_id: finding.id).length).to eq(1)
+ end
+ end
+
+ context 'with existing remediations within raw_metadata' do
+ let!(:finding1) { create_finding!(project1.id, scanner1.id, { remediations: [remediation_hash] }) }
+ let!(:finding2) { create_finding!(project1.id, scanner1.id, { remediations: [remediation_hash] }) }
+
+ it 'creates new remediation' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.to change { vulnerability_remediations.count }.by(1)
+ expect(vulnerability_findings_remediations.where(vulnerability_occurrence_id: finding1.id).length).to eq(1)
+ expect(vulnerability_findings_remediations.where(vulnerability_occurrence_id: finding2.id).length).to eq(1)
+ end
+
+ context 'when create throws exception other than ActiveRecord::RecordNotUnique' do
+ before do
+ allow(migration).to receive(:create_finding_remediations).and_raise(StandardError)
+ end
+
+ it 'rolls back all related transactions' do
+ expect(Gitlab::AppLogger).to receive(:error).with({
+ class: described_class.name, message: StandardError.to_s, model_id: finding1.id
+ })
+ expect(Gitlab::AppLogger).to receive(:error).with({
+ class: described_class.name, message: StandardError.to_s, model_id: finding2.id
+ })
+ expect { perform_migration }.not_to change { vulnerability_remediations.count }
+ expect(vulnerability_findings_remediations.where(vulnerability_occurrence_id: finding1.id).length).to eq(0)
+ expect(vulnerability_findings_remediations.where(vulnerability_occurrence_id: finding2.id).length).to eq(0)
+ end
+ end
+ end
+
+ context 'with existing remediation records' do
+ let!(:finding) { create_finding!(project1.id, scanner1.id, { remediations: [remediation_hash] }) }
+
+ before do
+ vulnerability_remediations.create!(project_id: project1.id, summary: remediation_hash[:summary],
+ checksum: checksum(remediation_hash[:diff]), file: Tempfile.new.path)
+ end
+
+ it 'does not create new remediation' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.not_to change { vulnerability_remediations.count }
+ expect(vulnerability_findings_remediations.where(vulnerability_occurrence_id: finding.id).length).to eq(1)
+ end
+ end
+
+ context 'with same raw_metadata for different projects' do
+ let(:namespace2) { table(:namespaces).create!(name: 'namespace 2', path: 'namespace2') }
+ let(:project2) { table(:projects).create!(namespace_id: namespace2.id, project_namespace_id: namespace2.id) }
+ let(:scanner2) do
+ table(:vulnerability_scanners).create!(project_id: project2.id, external_id: 'test 2', name: 'test scanner 2')
+ end
+
+ let!(:finding1) { create_finding!(project1.id, scanner1.id, { remediations: [remediation_hash] }) }
+ let!(:finding2) { create_finding!(project2.id, scanner2.id, { remediations: [remediation_hash] }) }
+
+ it 'creates new remediation for each project' do
+ expect(Gitlab::AppLogger).not_to receive(:error)
+
+ expect { perform_migration }.to change { vulnerability_remediations.count }.by(2)
+ expect(vulnerability_findings_remediations.where(vulnerability_occurrence_id: finding1.id).length).to eq(1)
+ expect(vulnerability_findings_remediations.where(vulnerability_occurrence_id: finding2.id).length).to eq(1)
+ end
+ end
+
+ private
+
+ def create_finding!(project_id, scanner_id, raw_metadata)
+ vulnerability = table(:vulnerabilities).create!(project_id: project_id, author_id: user.id, title: 'test',
+ severity: 4, confidence: 4, report_type: 0)
+
+ identifier = table(:vulnerability_identifiers).create!(project_id: project_id, external_type: 'uuid-v5',
+ external_id: 'uuid-v5', fingerprint: OpenSSL::Digest::SHA256.hexdigest(vulnerability.id.to_s),
+ name: 'Identifier for UUIDv5 2 2')
+
+ table(:vulnerability_occurrences).create!(
+ vulnerability_id: vulnerability.id, project_id: project_id, scanner_id: scanner_id,
+ primary_identifier_id: identifier.id, name: 'test', severity: 4, confidence: 4, report_type: 0,
+ uuid: SecureRandom.uuid, project_fingerprint: '123qweasdzxc', location: { "image" => "alpine:3.4" },
+ location_fingerprint: 'test', metadata_version: 'test',
+ raw_metadata: raw_metadata.to_json)
+ end
+
+ def checksum(value)
+ sha = Digest::SHA256.hexdigest(value)
+ Gitlab::Database::ShaAttribute.new.serialize(sha)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects_spec.rb b/spec/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects_spec.rb
index a8574411957..f671a673a08 100644
--- a/spec/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects_spec.rb
+++ b/spec/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::BackgroundMigration::NullifyCreatorIdColumnOfOrphanedProjects, feature_category: :projects do
+RSpec.describe Gitlab::BackgroundMigration::NullifyCreatorIdColumnOfOrphanedProjects, feature_category: :projects,
+ schema: 20230130073109 do
let(:users) { table(:users) }
let(:projects) { table(:projects) }
let(:namespaces) { table(:namespaces) }
diff --git a/spec/lib/gitlab/background_task_spec.rb b/spec/lib/gitlab/background_task_spec.rb
index 102556b6b2f..da92fc9e765 100644
--- a/spec/lib/gitlab/background_task_spec.rb
+++ b/spec/lib/gitlab/background_task_spec.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
# We need to capture task state from a closure, which requires instance variables.
# rubocop: disable RSpec/InstanceVariable
-RSpec.describe Gitlab::BackgroundTask do
+RSpec.describe Gitlab::BackgroundTask, feature_category: :build do
let(:options) { {} }
let(:task) do
proc do
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 1526a1a9f2d..48ceda9e8d8 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -358,7 +358,7 @@ RSpec.describe Gitlab::BitbucketImport::Importer, feature_category: :integration
describe 'issue import' do
it 'allocates internal ids' do
- expect(Issue).to receive(:track_project_iid!).with(project, 6)
+ expect(Issue).to receive(:track_namespace_iid!).with(project.project_namespace, 6)
importer.execute
end
diff --git a/spec/lib/gitlab/cache/client_spec.rb b/spec/lib/gitlab/cache/client_spec.rb
new file mode 100644
index 00000000000..ec22fcdee7e
--- /dev/null
+++ b/spec/lib/gitlab/cache/client_spec.rb
@@ -0,0 +1,165 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Cache::Client, feature_category: :source_code_management do
+ subject(:client) { described_class.new(metadata, backend: backend) }
+
+ let(:backend) { Rails.cache }
+ let(:metadata) do
+ Gitlab::Cache::Metadata.new(
+ caller_id: caller_id,
+ cache_identifier: cache_identifier,
+ feature_category: feature_category,
+ backing_resource: backing_resource
+ )
+ end
+
+ let(:caller_id) { 'caller-id' }
+ let(:cache_identifier) { 'MyClass#cache' }
+ let(:feature_category) { :source_code_management }
+ let(:backing_resource) { :cpu }
+
+ let(:metadata_mock) do
+ Gitlab::Cache::Metadata.new(
+ cache_identifier: cache_identifier,
+ feature_category: feature_category
+ )
+ end
+
+ let(:metrics_mock) { Gitlab::Cache::Metrics.new(metadata_mock) }
+
+ describe '.build_with_metadata' do
+ it 'builds a cache client with metrics support' do
+ attributes = {
+ caller_id: caller_id,
+ cache_identifier: cache_identifier,
+ feature_category: feature_category,
+ backing_resource: backing_resource
+ }
+
+ instance = described_class.build_with_metadata(**attributes)
+
+ expect(instance).to be_a(described_class)
+ expect(instance.metadata).to have_attributes(**attributes)
+ end
+ end
+
+ describe 'Methods', :use_clean_rails_memory_store_caching do
+ let(:expected_key) { 'key' }
+
+ before do
+ allow(Gitlab::Cache::Metrics).to receive(:new).and_return(metrics_mock)
+ end
+
+ describe '#read' do
+ context 'when key does not exist' do
+ it 'returns nil' do
+ expect(client.read('key')).to be_nil
+ end
+
+ it 'increments cache miss' do
+ expect(metrics_mock).to receive(:increment_cache_miss)
+
+ client.read('key')
+ end
+ end
+
+ context 'when key exists' do
+ before do
+ backend.write(expected_key, 'value')
+ end
+
+ it 'returns key value' do
+ expect(client.read('key')).to eq('value')
+ end
+
+ it 'increments cache hit' do
+ expect(metrics_mock).to receive(:increment_cache_hit)
+
+ client.read('key')
+ end
+ end
+ end
+
+ describe '#write' do
+ it 'calls backend "#write" method with the expected key' do
+ expect(backend).to receive(:write).with(expected_key, 'value')
+
+ client.write('key', 'value')
+ end
+ end
+
+ describe '#exist?' do
+ it 'calls backend "#exist?" method with the expected key' do
+ expect(backend).to receive(:exist?).with(expected_key)
+
+ client.exist?('key')
+ end
+ end
+
+ describe '#delete' do
+ it 'calls backend "#delete" method with the expected key' do
+ expect(backend).to receive(:delete).with(expected_key)
+
+ client.delete('key')
+ end
+ end
+
+ # rubocop:disable Style/RedundantFetchBlock
+ describe '#fetch' do
+ it 'creates key in the specific format' do
+ client.fetch('key') { 'value' }
+
+ expect(backend.fetch(expected_key)).to eq('value')
+ end
+
+ it 'yields the block once' do
+ expect { |b| client.fetch('key', &b) }.to yield_control.once
+ end
+
+ context 'when key already exists' do
+ before do
+ backend.write(expected_key, 'value')
+ end
+
+ it 'does not redefine the value' do
+ expect(client.fetch('key') { 'new-value' }).to eq('value')
+ end
+
+ it 'increments a cache hit' do
+ expect(metrics_mock).to receive(:increment_cache_hit)
+
+ client.fetch('key')
+ end
+
+ it 'does not measure the cache generation time' do
+ expect(metrics_mock).not_to receive(:observe_cache_generation)
+
+ client.fetch('key') { 'new-value' }
+ end
+ end
+
+ context 'when key does not exist' do
+ it 'caches the key' do
+ expect(client.fetch('key') { 'value' }).to eq('value')
+
+ expect(client.fetch('key')).to eq('value')
+ end
+
+ it 'increments a cache miss' do
+ expect(metrics_mock).to receive(:increment_cache_miss)
+
+ client.fetch('key')
+ end
+
+ it 'measures the cache generation time' do
+ expect(metrics_mock).to receive(:observe_cache_generation)
+
+ client.fetch('key') { 'value' }
+ end
+ end
+ end
+ end
+ # rubocop:enable Style/RedundantFetchBlock
+end
diff --git a/spec/lib/gitlab/changes_list_spec.rb b/spec/lib/gitlab/changes_list_spec.rb
index 762a121340e..77deffe4b37 100644
--- a/spec/lib/gitlab/changes_list_spec.rb
+++ b/spec/lib/gitlab/changes_list_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::ChangesList do
+RSpec.describe Gitlab::ChangesList, feature_category: :source_code_management do
let(:valid_changes_string) { "\n000000 570e7b2 refs/heads/my_branch\nd14d6c 6fd24d refs/heads/master" }
let(:invalid_changes) { 1 }
diff --git a/spec/lib/gitlab/chat/responder_spec.rb b/spec/lib/gitlab/chat/responder_spec.rb
index a9d290cb87c..15ca3427ae8 100644
--- a/spec/lib/gitlab/chat/responder_spec.rb
+++ b/spec/lib/gitlab/chat/responder_spec.rb
@@ -4,68 +4,32 @@ require 'spec_helper'
RSpec.describe Gitlab::Chat::Responder, feature_category: :integrations do
describe '.responder_for' do
- context 'when the feature flag is disabled' do
- before do
- stub_feature_flags(use_response_url_for_chat_responder: false)
- end
-
- context 'using a regular build' do
- it 'returns nil' do
- build = create(:ci_build)
+ context 'using a regular build' do
+ it 'returns nil' do
+ build = create(:ci_build)
- expect(described_class.responder_for(build)).to be_nil
- end
- end
-
- context 'using a chat build' do
- it 'returns the responder for the build' do
- pipeline = create(:ci_pipeline)
- build = create(:ci_build, pipeline: pipeline)
- integration = double(:integration, chat_responder: Gitlab::Chat::Responder::Slack)
- chat_name = double(:chat_name, integration: integration)
- chat_data = double(:chat_data, chat_name: chat_name)
-
- allow(pipeline)
- .to receive(:chat_data)
- .and_return(chat_data)
-
- expect(described_class.responder_for(build))
- .to be_an_instance_of(Gitlab::Chat::Responder::Slack)
- end
+ expect(described_class.responder_for(build)).to be_nil
end
end
- context 'when the feature flag is enabled' do
- before do
- stub_feature_flags(use_response_url_for_chat_responder: true)
- end
-
- context 'using a regular build' do
- it 'returns nil' do
- build = create(:ci_build)
+ context 'using a chat build' do
+ let_it_be(:pipeline) { create(:ci_pipeline) }
+ let_it_be(:build) { create(:ci_build, pipeline: pipeline) }
- expect(described_class.responder_for(build)).to be_nil
+ context "when response_url starts with 'https://hooks.slack.com/'" do
+ before do
+ pipeline.build_chat_data(response_url: 'https://hooks.slack.com/services/12345', chat_name_id: 'U123')
end
+
+ it { expect(described_class.responder_for(build)).to be_an_instance_of(Gitlab::Chat::Responder::Slack) }
end
- context 'using a chat build' do
- let(:chat_name) { create(:chat_name, chat_id: 'U123') }
- let(:pipeline) do
- pipeline = create(:ci_pipeline)
- pipeline.create_chat_data!(
- response_url: 'https://hooks.slack.com/services/12345',
- chat_name_id: chat_name.id
- )
- pipeline
+ context "when response_url does not start with 'https://hooks.slack.com/'" do
+ before do
+ pipeline.build_chat_data(response_url: 'https://mattermost.example.com/services/12345', chat_name_id: 'U123')
end
- let(:build) { create(:ci_build, pipeline: pipeline) }
- let(:responder) { described_class.new(build) }
-
- it 'returns the responder for the build' do
- expect(described_class.responder_for(build))
- .to be_an_instance_of(Gitlab::Chat::Responder::Slack)
- end
+ it { expect(described_class.responder_for(build)).to be_an_instance_of(Gitlab::Chat::Responder::Mattermost) }
end
end
end
diff --git a/spec/lib/gitlab/checks/changes_access_spec.rb b/spec/lib/gitlab/checks/changes_access_spec.rb
index 60118823b5a..552afcdb180 100644
--- a/spec/lib/gitlab/checks/changes_access_spec.rb
+++ b/spec/lib/gitlab/checks/changes_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Checks::ChangesAccess do
+RSpec.describe Gitlab::Checks::ChangesAccess, feature_category: :source_code_management do
include_context 'changes access checks context'
subject { changes_access }
@@ -47,6 +47,16 @@ RSpec.describe Gitlab::Checks::ChangesAccess do
expect(subject.commits).to match_array([])
end
+ context 'when change is for notes ref' do
+ let(:changes) do
+ [{ oldrev: oldrev, newrev: newrev, ref: 'refs/notes/commit' }]
+ end
+
+ it 'does not return any commits' do
+ expect(subject.commits).to match_array([])
+ end
+ end
+
context 'when changes contain empty revisions' do
let(:expected_commit) { instance_double(Commit) }
diff --git a/spec/lib/gitlab/checks/diff_check_spec.rb b/spec/lib/gitlab/checks/diff_check_spec.rb
index 6b45b8d4628..0845c746545 100644
--- a/spec/lib/gitlab/checks/diff_check_spec.rb
+++ b/spec/lib/gitlab/checks/diff_check_spec.rb
@@ -2,10 +2,20 @@
require 'spec_helper'
-RSpec.describe Gitlab::Checks::DiffCheck do
+RSpec.describe Gitlab::Checks::DiffCheck, feature_category: :source_code_management do
include_context 'change access checks context'
describe '#validate!' do
+ context 'when ref is not tag or branch ref' do
+ let(:ref) { 'refs/notes/commit' }
+
+ it 'does not call find_changed_paths' do
+ expect(project.repository).not_to receive(:find_changed_paths)
+
+ subject.validate!
+ end
+ end
+
context 'when commits is empty' do
it 'does not call find_changed_paths' do
expect(project.repository).not_to receive(:find_changed_paths)
diff --git a/spec/lib/gitlab/ci/badge/release/template_spec.rb b/spec/lib/gitlab/ci/badge/release/template_spec.rb
index 2b66c296a94..6be0dcaae99 100644
--- a/spec/lib/gitlab/ci/badge/release/template_spec.rb
+++ b/spec/lib/gitlab/ci/badge/release/template_spec.rb
@@ -59,9 +59,30 @@ RSpec.describe Gitlab::Ci::Badge::Release::Template do
end
describe '#value_width' do
- it 'has a fixed value width' do
+ it 'returns the default value width' do
expect(template.value_width).to eq 54
end
+
+ it 'returns custom value width' do
+ value_width = 100
+ badge = Gitlab::Ci::Badge::Release::LatestRelease.new(project, user, opts: { value_width: value_width })
+
+ expect(described_class.new(badge).value_width).to eq value_width
+ end
+
+ it 'returns VALUE_WIDTH_DEFAULT if the custom value_width supplied is greater than permissible limit' do
+ value_width = 250
+ badge = Gitlab::Ci::Badge::Release::LatestRelease.new(project, user, opts: { value_width: value_width })
+
+ expect(described_class.new(badge).value_width).to eq 54
+ end
+
+ it 'returns VALUE_WIDTH_DEFAULT if value_width is not a number' do
+ value_width = "string"
+ badge = Gitlab::Ci::Badge::Release::LatestRelease.new(project, user, opts: { value_width: value_width })
+
+ expect(described_class.new(badge).value_width).to eq 54
+ end
end
describe '#key_color' do
diff --git a/spec/lib/gitlab/ci/build/auto_retry_spec.rb b/spec/lib/gitlab/ci/build/auto_retry_spec.rb
index 314714c543b..0b275e7d564 100644
--- a/spec/lib/gitlab/ci/build/auto_retry_spec.rb
+++ b/spec/lib/gitlab/ci/build/auto_retry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Build::AutoRetry, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Build::AutoRetry, feature_category: :pipeline_composition do
let(:auto_retry) { described_class.new(build) }
describe '#allowed?' do
diff --git a/spec/lib/gitlab/ci/build/context/build_spec.rb b/spec/lib/gitlab/ci/build/context/build_spec.rb
index 74739a67be0..4fdeffb033a 100644
--- a/spec/lib/gitlab/ci/build/context/build_spec.rb
+++ b/spec/lib/gitlab/ci/build/context/build_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Build::Context::Build, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Build::Context::Build, feature_category: :pipeline_composition do
let(:pipeline) { create(:ci_pipeline) }
let(:seed_attributes) { { 'name' => 'some-job' } }
diff --git a/spec/lib/gitlab/ci/build/hook_spec.rb b/spec/lib/gitlab/ci/build/hook_spec.rb
index 6ed40a44c97..6c9175b4260 100644
--- a/spec/lib/gitlab/ci/build/hook_spec.rb
+++ b/spec/lib/gitlab/ci/build/hook_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Build::Hook, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Build::Hook, feature_category: :pipeline_composition do
let_it_be(:build1) do
FactoryBot.build(:ci_build,
options: { hooks: { pre_get_sources_script: ["echo 'hello pre_get_sources_script'"] } })
diff --git a/spec/lib/gitlab/ci/components/header_spec.rb b/spec/lib/gitlab/ci/components/header_spec.rb
new file mode 100644
index 00000000000..b1af4ca9238
--- /dev/null
+++ b/spec/lib/gitlab/ci/components/header_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Components::Header, feature_category: :pipeline_composition do
+ subject { described_class.new(spec) }
+
+ context 'when spec is valid' do
+ let(:spec) do
+ {
+ spec: {
+ inputs: {
+ website: nil,
+ run: {
+ options: %w[opt1 opt2]
+ }
+ }
+ }
+ }
+ end
+
+ it 'fabricates a spec from valid data' do
+ expect(subject).not_to be_empty
+ end
+
+ describe '#inputs' do
+ it 'fabricates input data' do
+ input = subject.inputs({ website: 'https//gitlab.com', run: 'opt1' })
+
+ expect(input.count).to eq 2
+ end
+ end
+
+ describe '#context' do
+ it 'fabricates interpolation context' do
+ ctx = subject.context({ website: 'https//gitlab.com', run: 'opt1' })
+
+ expect(ctx).to be_valid
+ end
+ end
+ end
+
+ context 'when spec is empty' do
+ let(:spec) { { spec: {} } }
+
+ it 'returns an empty header' do
+ expect(subject).to be_empty
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/components/instance_path_spec.rb b/spec/lib/gitlab/ci/components/instance_path_spec.rb
index d9beae0555c..fbe5e0b9d42 100644
--- a/spec/lib/gitlab/ci/components/instance_path_spec.rb
+++ b/spec/lib/gitlab/ci/components/instance_path_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Components::InstancePath, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Components::InstancePath, feature_category: :pipeline_composition do
let_it_be(:user) { create(:user) }
let(:path) { described_class.new(address: address, content_filename: 'template.yml') }
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index c1b9bd58d98..c8b4a8b8a0e 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_composition do
let(:entry) { described_class.new(config, name: :rspec) }
it_behaves_like 'with inheritable CI config' do
@@ -728,27 +728,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_autho
scheduling_type: :stage,
id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } })
end
-
- context 'when the FF ci_hooks_pre_get_sources_script is disabled' do
- before do
- stub_feature_flags(ci_hooks_pre_get_sources_script: false)
- end
-
- it 'returns correct value' do
- expect(entry.value)
- .to eq(name: :rspec,
- before_script: %w[ls pwd],
- script: %w[rspec],
- stage: 'test',
- ignore: false,
- after_script: %w[cleanup],
- only: { refs: %w[branches tags] },
- job_variables: {},
- root_variables_inheritance: true,
- scheduling_type: :stage,
- id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } })
- end
- end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/policy_spec.rb b/spec/lib/gitlab/ci/config/entry/policy_spec.rb
index 378c0947e8a..7093a0a6edf 100644
--- a/spec/lib/gitlab/ci/config/entry/policy_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/policy_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Entry::Policy do
+RSpec.describe Gitlab::Ci::Config::Entry::Policy, feature_category: :continuous_integration do
let(:entry) { described_class.new(config) }
context 'when using simplified policy' do
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index b28562ba2ea..4f13940d7e2 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Entry::Processable, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::Entry::Processable, feature_category: :pipeline_composition do
let(:node_class) do
Class.new(::Gitlab::Config::Entry::Node) do
include Gitlab::Ci::Config::Entry::Processable
diff --git a/spec/lib/gitlab/ci/config/entry/pull_policy_spec.rb b/spec/lib/gitlab/ci/config/entry/pull_policy_spec.rb
index c35355b10c6..40507a66c2d 100644
--- a/spec/lib/gitlab/ci/config/entry/pull_policy_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/pull_policy_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Entry::PullPolicy do
+RSpec.describe Gitlab::Ci::Config::Entry::PullPolicy, feature_category: :continuous_integration do
let(:entry) { described_class.new(config) }
describe '#value' do
diff --git a/spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb b/spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb
index ccd6f6ab427..6f37dd72083 100644
--- a/spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Entry::Reports::CoverageReport, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::Entry::Reports::CoverageReport, feature_category: :pipeline_composition do
let(:entry) { described_class.new(config) }
describe 'validations' do
diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
index 715cb18fb92..73bf2d422b7 100644
--- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Entry::Reports, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::Entry::Reports, feature_category: :pipeline_composition do
let(:entry) { described_class.new(config) }
describe 'validates ALLOWED_KEYS' do
diff --git a/spec/lib/gitlab/ci/config/entry/trigger_spec.rb b/spec/lib/gitlab/ci/config/entry/trigger_spec.rb
index f47923af45a..fdd598c2ab2 100644
--- a/spec/lib/gitlab/ci/config/entry/trigger_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/trigger_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Entry::Trigger, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::Entry::Trigger, feature_category: :pipeline_composition do
subject { described_class.new(config) }
context 'when trigger config is a non-empty string' do
diff --git a/spec/lib/gitlab/ci/config/external/context_spec.rb b/spec/lib/gitlab/ci/config/external/context_spec.rb
index 1fd3cf3c99f..fc68d3d62a2 100644
--- a/spec/lib/gitlab/ci/config/external/context_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/context_spec.rb
@@ -2,12 +2,21 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipeline_composition do
let(:project) { build(:project) }
let(:user) { double('User') }
let(:sha) { '12345' }
let(:variables) { Gitlab::Ci::Variables::Collection.new([{ 'key' => 'a', 'value' => 'b' }]) }
- let(:attributes) { { project: project, user: user, sha: sha, variables: variables } }
+ let(:pipeline_config) { instance_double(Gitlab::Ci::ProjectConfig) }
+ let(:attributes) do
+ {
+ project: project,
+ user: user,
+ sha: sha,
+ variables: variables,
+ pipeline_config: pipeline_config
+ }
+ end
subject(:subject) { described_class.new(**attributes) }
@@ -15,11 +24,12 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
context 'with values' do
it { is_expected.to have_attributes(**attributes) }
it { expect(subject.expandset).to eq([]) }
- it { expect(subject.max_includes).to eq(Gitlab::Ci::Config::External::Context::NEW_MAX_INCLUDES) }
+ it { expect(subject.max_includes).to eq(Gitlab::Ci::Config::External::Context::MAX_INCLUDES) }
it { expect(subject.execution_deadline).to eq(0) }
it { expect(subject.variables).to be_instance_of(Gitlab::Ci::Variables::Collection) }
it { expect(subject.variables_hash).to be_instance_of(ActiveSupport::HashWithIndifferentAccess) }
it { expect(subject.variables_hash).to include('a' => 'b') }
+ it { expect(subject.pipeline_config).to eq(pipeline_config) }
end
context 'without values' do
@@ -27,37 +37,11 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
it { is_expected.to have_attributes(**attributes) }
it { expect(subject.expandset).to eq([]) }
- it { expect(subject.max_includes).to eq(Gitlab::Ci::Config::External::Context::NEW_MAX_INCLUDES) }
+ it { expect(subject.max_includes).to eq(Gitlab::Ci::Config::External::Context::MAX_INCLUDES) }
it { expect(subject.execution_deadline).to eq(0) }
it { expect(subject.variables).to be_instance_of(Gitlab::Ci::Variables::Collection) }
it { expect(subject.variables_hash).to be_instance_of(ActiveSupport::HashWithIndifferentAccess) }
- end
-
- context 'when FF ci_includes_count_duplicates is disabled' do
- before do
- stub_feature_flags(ci_includes_count_duplicates: false)
- end
-
- context 'with values' do
- it { is_expected.to have_attributes(**attributes) }
- it { expect(subject.expandset).to eq(Set.new) }
- it { expect(subject.max_includes).to eq(Gitlab::Ci::Config::External::Context::MAX_INCLUDES) }
- it { expect(subject.execution_deadline).to eq(0) }
- it { expect(subject.variables).to be_instance_of(Gitlab::Ci::Variables::Collection) }
- it { expect(subject.variables_hash).to be_instance_of(ActiveSupport::HashWithIndifferentAccess) }
- it { expect(subject.variables_hash).to include('a' => 'b') }
- end
-
- context 'without values' do
- let(:attributes) { { project: nil, user: nil, sha: nil } }
-
- it { is_expected.to have_attributes(**attributes) }
- it { expect(subject.expandset).to eq(Set.new) }
- it { expect(subject.max_includes).to eq(Gitlab::Ci::Config::External::Context::MAX_INCLUDES) }
- it { expect(subject.execution_deadline).to eq(0) }
- it { expect(subject.variables).to be_instance_of(Gitlab::Ci::Variables::Collection) }
- it { expect(subject.variables_hash).to be_instance_of(ActiveSupport::HashWithIndifferentAccess) }
- end
+ it { expect(subject.pipeline_config).to be_nil }
end
end
@@ -170,4 +154,26 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
describe '#sentry_payload' do
it { expect(subject.sentry_payload).to match(a_hash_including(:project, :user)) }
end
+
+ describe '#internal_include?' do
+ context 'when pipeline_config is provided' do
+ where(:value) { [true, false] }
+
+ with_them do
+ it 'returns the value of .internal_include_prepended?' do
+ allow(pipeline_config).to receive(:internal_include_prepended?).and_return(value)
+
+ expect(subject.internal_include?).to eq(value)
+ end
+ end
+ end
+
+ context 'when pipeline_config is not provided' do
+ let(:pipeline_config) { nil }
+
+ it 'returns false' do
+ expect(subject.internal_include?).to eq(false)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb
index 45a15fb5f36..52b8dcbcb44 100644
--- a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::File::Artifact, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::File::Artifact, feature_category: :pipeline_composition do
let(:parent_pipeline) { create(:ci_pipeline) }
let(:variables) {}
let(:context) do
diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
index 55d95d0c1f8..959dcdf31af 100644
--- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipeline_composition do
let(:variables) {}
let(:context_params) { { sha: 'HEAD', variables: variables } }
let(:context) { Gitlab::Ci::Config::External::Context.new(**context_params) }
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 a162a1a8abf..1562e571060 100644
--- a/spec/lib/gitlab/ci/config/external/file/component_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/component_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::File::Component, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::File::Component, feature_category: :pipeline_composition do
let_it_be(:context_project) { create(:project, :repository) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/config/external/file/local_spec.rb b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
index b5895b4bc81..2bac8a6968b 100644
--- a/spec/lib/gitlab/ci/config/external/file/local_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::File::Local, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::File::Local, feature_category: :pipeline_composition do
include RepoHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/ci/config/external/file/project_spec.rb b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
index abe38cdbc3e..0ef39a22932 100644
--- a/spec/lib/gitlab/ci/config/external/file/project_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::File::Project, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::File::Project, feature_category: :pipeline_composition do
include RepoHelpers
let_it_be(:context_project) { create(:project) }
@@ -97,6 +97,36 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project, feature_category: :p
end
end
+ context 'when a valid path is used in uppercase' do
+ let(:params) do
+ { project: project.full_path.upcase, file: '/file.yml' }
+ end
+
+ around do |example|
+ create_and_delete_files(project, { '/file.yml' => 'image: image:1.0' }) do
+ example.run
+ end
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when a valid different case path is used' do
+ let_it_be(:project) { create(:project, :repository, path: 'mY-teSt-proJect', name: 'My Test Project') }
+
+ let(:params) do
+ { project: "#{project.namespace.full_path}/my-test-projecT", file: '/file.yml' }
+ end
+
+ around do |example|
+ create_and_delete_files(project, { '/file.yml' => 'image: image:1.0' }) do
+ example.run
+ end
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
context 'when a valid path with custom ref is used' do
let(:params) do
{ project: project.full_path, ref: 'master', file: '/file.yml' }
diff --git a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
index 27f401db76e..f8986e8fa10 100644
--- a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::File::Remote, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::File::Remote, feature_category: :pipeline_composition do
include StubRequests
let(:variables) { Gitlab::Ci::Variables::Collection.new([{ 'key' => 'GITLAB_TOKEN', 'value' => 'secret_file', 'masked' => true }]) }
diff --git a/spec/lib/gitlab/ci/config/external/file/template_spec.rb b/spec/lib/gitlab/ci/config/external/file/template_spec.rb
index 83e98874118..79fd4203c3e 100644
--- a/spec/lib/gitlab/ci/config/external/file/template_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/template_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::File::Template, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::File::Template, feature_category: :pipeline_composition do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/config/external/mapper/base_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/base_spec.rb
index 0fdcc5e8ff7..ce8f3756cbc 100644
--- a/spec/lib/gitlab/ci/config/external/mapper/base_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper/base_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Mapper::Base, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Mapper::Base, feature_category: :pipeline_composition do
let(:test_class) do
Class.new(described_class) do
def self.name
diff --git a/spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb
index df2a2f0fd01..5195567ebb4 100644
--- a/spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Mapper::Filter, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Mapper::Filter, feature_category: :pipeline_composition do
let_it_be(:variables) do
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'VARIABLE1', value: 'hello')
diff --git a/spec/lib/gitlab/ci/config/external/mapper/location_expander_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/location_expander_spec.rb
index b14b6b0ca29..1e490bf1d16 100644
--- a/spec/lib/gitlab/ci/config/external/mapper/location_expander_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper/location_expander_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Mapper::LocationExpander, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Mapper::LocationExpander, feature_category: :pipeline_composition do
include RepoHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/ci/config/external/mapper/matcher_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/matcher_spec.rb
index 11c79e19cff..6ca4fd24e61 100644
--- a/spec/lib/gitlab/ci/config/external/mapper/matcher_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper/matcher_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Mapper::Matcher, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Mapper::Matcher, feature_category: :pipeline_composition do
let_it_be(:variables) do
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'A_MASKED_VAR', value: 'this-is-secret', masked: true)
diff --git a/spec/lib/gitlab/ci/config/external/mapper/normalizer_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/normalizer_spec.rb
index 709c234253b..09212833d84 100644
--- a/spec/lib/gitlab/ci/config/external/mapper/normalizer_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper/normalizer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Mapper::Normalizer, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Mapper::Normalizer, feature_category: :pipeline_composition do
let_it_be(:variables) do
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'VARIABLE1', value: 'config')
diff --git a/spec/lib/gitlab/ci/config/external/mapper/variables_expander_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/variables_expander_spec.rb
index f7454dcd4be..e27e8034faa 100644
--- a/spec/lib/gitlab/ci/config/external/mapper/variables_expander_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper/variables_expander_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Mapper::VariablesExpander, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Mapper::VariablesExpander, feature_category: :pipeline_composition do
let_it_be(:variables) do
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'VARIABLE1', value: 'hello')
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 a219666f24e..ef5049158c1 100644
--- a/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb
@@ -2,11 +2,11 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category: :pipeline_composition do
include RepoHelpers
include StubRequests
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :small_repo) }
let_it_be(:user) { project.owner }
let(:context) do
@@ -38,7 +38,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category:
}
end
- around(:all) do |example|
+ around do |example|
create_and_delete_files(project, project_files) do
example.run
end
@@ -84,42 +84,105 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category:
end
context 'when files are project files' do
- let_it_be(:included_project) { create(:project, :repository, namespace: project.namespace, creator: user) }
+ let_it_be(:included_project1) { create(:project, :small_repo, namespace: project.namespace, creator: user) }
+ let_it_be(:included_project2) { create(:project, :small_repo, namespace: project.namespace, creator: user) }
let(:files) do
[
Gitlab::Ci::Config::External::File::Project.new(
- { file: 'myfolder/file1.yml', project: included_project.full_path }, context
+ { file: 'myfolder/file1.yml', project: included_project1.full_path }, context
),
Gitlab::Ci::Config::External::File::Project.new(
- { file: 'myfolder/file2.yml', project: included_project.full_path }, context
+ { file: 'myfolder/file2.yml', project: included_project1.full_path }, context
),
Gitlab::Ci::Config::External::File::Project.new(
- { file: 'myfolder/file3.yml', project: included_project.full_path }, context
+ { file: 'myfolder/file3.yml', project: included_project1.full_path, ref: 'master' }, context
+ ),
+ Gitlab::Ci::Config::External::File::Project.new(
+ { file: 'myfolder/file1.yml', project: included_project2.full_path }, context
+ ),
+ Gitlab::Ci::Config::External::File::Project.new(
+ { file: 'myfolder/file2.yml', project: included_project2.full_path }, context
)
]
end
- around(:all) do |example|
- create_and_delete_files(included_project, project_files) do
- example.run
+ around do |example|
+ create_and_delete_files(included_project1, project_files) do
+ create_and_delete_files(included_project2, project_files) do
+ example.run
+ end
end
end
- it 'returns an array of file objects' do
+ it 'returns an array of valid file objects' do
expect(process.map(&:location)).to contain_exactly(
- 'myfolder/file1.yml', 'myfolder/file2.yml', 'myfolder/file3.yml'
+ 'myfolder/file1.yml', 'myfolder/file2.yml', 'myfolder/file3.yml', 'myfolder/file1.yml', 'myfolder/file2.yml'
)
+
+ expect(process.all?(&:valid?)).to be_truthy
end
it 'adds files to the expandset' do
- expect { process }.to change { context.expandset.count }.by(3)
+ expect { process }.to change { context.expandset.count }.by(5)
end
it 'calls Gitaly only once for all files', :request_store do
- # 1 for project.commit.id, 3 for the sha check, 1 for the files
+ files # calling this to load project creations and the `project.commit.id` call
+
+ # 3 for the sha check, 2 for the files in batch
expect { process }.to change { Gitlab::GitalyClient.get_request_count }.by(5)
end
+
+ it 'queries with batch', :use_sql_query_cache do
+ files # calling this to load project creations and the `project.commit.id` call
+
+ queries = ActiveRecord::QueryRecorder.new(skip_cached: false) { process }
+ projects_queries = queries.occurrences_starting_with('SELECT "projects"')
+ access_check_queries = queries.occurrences_starting_with('SELECT MAX("project_authorizations"."access_level")')
+
+ # We could not reduce the number of projects queries because we need to call project for
+ # the `can_access_local_content?` and `sha` BatchLoaders.
+ expect(projects_queries.values.sum).to eq(2)
+ expect(access_check_queries.values.sum).to eq(2)
+ end
+
+ context 'when the FF ci_batch_project_includes_context is disabled' do
+ before do
+ stub_feature_flags(ci_batch_project_includes_context: false)
+ end
+
+ it 'returns an array of file objects' do
+ expect(process.map(&:location)).to contain_exactly(
+ 'myfolder/file1.yml', 'myfolder/file2.yml', 'myfolder/file3.yml',
+ 'myfolder/file1.yml', 'myfolder/file2.yml'
+ )
+ end
+
+ it 'adds files to the expandset' do
+ expect { process }.to change { context.expandset.count }.by(5)
+ end
+
+ it 'calls Gitaly for all files', :request_store do
+ files # calling this to load project creations and the `project.commit.id` call
+
+ # 5 for the sha check, 2 for the files in batch
+ expect { process }.to change { Gitlab::GitalyClient.get_request_count }.by(7)
+ end
+
+ it 'queries without batch', :use_sql_query_cache do
+ files # calling this to load project creations and the `project.commit.id` call
+
+ queries = ActiveRecord::QueryRecorder.new(skip_cached: false) { process }
+ projects_queries = queries.occurrences_starting_with('SELECT "projects"')
+ access_check_queries = queries.occurrences_starting_with(
+ 'SELECT MAX("project_authorizations"."access_level")'
+ )
+
+ expect(projects_queries.values.sum).to eq(5)
+ expect(access_check_queries.values.sum).to eq(5)
+ end
+ end
end
context 'when a file includes other files' do
@@ -150,7 +213,30 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category:
end
end
- context 'when total file count exceeds max_includes' do
+ describe 'max includes detection' do
+ shared_examples 'verifies max includes' do
+ context 'when total file count is equal to max_includes' do
+ before do
+ allow(context).to receive(:max_includes).and_return(expected_total_file_count)
+ end
+
+ it 'adds the expected number of files to expandset' do
+ expect { process }.not_to raise_error
+ expect(context.expandset.count).to eq(expected_total_file_count)
+ end
+ end
+
+ context 'when total file count exceeds max_includes' do
+ before do
+ allow(context).to receive(:max_includes).and_return(expected_total_file_count - 1)
+ end
+
+ it 'raises error' do
+ expect { process }.to raise_error(expected_error_class)
+ end
+ end
+ end
+
context 'when files are nested' do
let(:files) do
[
@@ -158,9 +244,21 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category:
]
end
- it 'raises Processor::IncludeError' do
- allow(context).to receive(:max_includes).and_return(1)
- expect { process }.to raise_error(Gitlab::Ci::Config::External::Processor::IncludeError)
+ let(:expected_total_file_count) { 4 } # Includes nested_configs.yml + 3 nested files
+ let(:expected_error_class) { Gitlab::Ci::Config::External::Processor::IncludeError }
+
+ it_behaves_like 'verifies max includes'
+
+ context 'when duplicate files are included' do
+ let(:expected_total_file_count) { 8 } # 2 x (Includes nested_configs.yml + 3 nested files)
+ let(:files) do
+ [
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'nested_configs.yml' }, context),
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'nested_configs.yml' }, context)
+ ]
+ end
+
+ it_behaves_like 'verifies max includes'
end
end
@@ -172,34 +270,162 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category:
]
end
- it 'raises Mapper::TooManyIncludesError' do
- allow(context).to receive(:max_includes).and_return(1)
- expect { process }.to raise_error(Gitlab::Ci::Config::External::Mapper::TooManyIncludesError)
+ let(:expected_total_file_count) { files.count }
+ let(:expected_error_class) { Gitlab::Ci::Config::External::Mapper::TooManyIncludesError }
+
+ it_behaves_like 'verifies max includes'
+
+ context 'when duplicate files are included' do
+ let(:files) do
+ [
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context),
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file2.yml' }, context),
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file2.yml' }, context)
+ ]
+ end
+
+ let(:expected_total_file_count) { files.count }
+
+ it_behaves_like 'verifies max includes'
end
end
- context 'when files are duplicates' do
+ context 'when there is a circular include' do
+ let(:project_files) do
+ {
+ 'myfolder/file1.yml' => <<~YAML
+ include: myfolder/file1.yml
+ YAML
+ }
+ end
+
let(:files) do
[
- Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context),
- Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context),
Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context)
]
end
+ before do
+ allow(context).to receive(:max_includes).and_return(10)
+ end
+
it 'raises error' do
- allow(context).to receive(:max_includes).and_return(2)
- expect { process }.to raise_error(Gitlab::Ci::Config::External::Mapper::TooManyIncludesError)
+ expect { process }.to raise_error(Gitlab::Ci::Config::External::Processor::IncludeError)
end
+ end
- context 'when FF ci_includes_count_duplicates is disabled' do
- before do
- stub_feature_flags(ci_includes_count_duplicates: false)
+ context 'when a file is an internal include' do
+ let(:project_files) do
+ {
+ 'myfolder/file1.yml' => <<~YAML,
+ my_build:
+ script: echo Hello World
+ YAML
+ '.internal-include.yml' => <<~YAML
+ include:
+ - local: myfolder/file1.yml
+ YAML
+ }
+ end
+
+ let(:files) do
+ [
+ Gitlab::Ci::Config::External::File::Local.new({ local: '.internal-include.yml' }, context)
+ ]
+ end
+
+ let(:total_file_count) { 2 } # Includes .internal-include.yml + myfolder/file1.yml
+ let(:pipeline_config) { instance_double(Gitlab::Ci::ProjectConfig) }
+
+ let(:context) do
+ Gitlab::Ci::Config::External::Context.new(
+ project: project,
+ user: user,
+ sha: project.commit.id,
+ pipeline_config: pipeline_config
+ )
+ end
+
+ before do
+ allow(pipeline_config).to receive(:internal_include_prepended?).and_return(true)
+ allow(context).to receive(:max_includes).and_return(1)
+ end
+
+ context 'when total file count excluding internal include is equal to max_includes' do
+ it 'does not add the internal include to expandset' do
+ expect { process }.not_to raise_error
+ expect(context.expandset.count).to eq(total_file_count - 1)
+ expect(context.expandset.first.location).to eq('myfolder/file1.yml')
end
+ end
- it 'does not raise error' do
+ context 'when total file count excluding internal include exceeds max_includes' do
+ let(:project_files) do
+ {
+ 'myfolder/file1.yml' => <<~YAML,
+ my_build:
+ script: echo Hello World
+ YAML
+ '.internal-include.yml' => <<~YAML
+ include:
+ - local: myfolder/file1.yml
+ - local: myfolder/file1.yml
+ YAML
+ }
+ end
+
+ it 'raises error' do
+ expect { process }.to raise_error(Gitlab::Ci::Config::External::Processor::IncludeError)
+ end
+ end
+ end
+ end
+
+ context 'when FF ci_fix_max_includes is disabled' do
+ before do
+ stub_feature_flags(ci_fix_max_includes: false)
+ end
+
+ context 'when total file count exceeds max_includes' do
+ context 'when files are nested' do
+ let(:files) do
+ [
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'nested_configs.yml' }, context)
+ ]
+ end
+
+ it 'raises Processor::IncludeError' do
+ allow(context).to receive(:max_includes).and_return(1)
+ expect { process }.to raise_error(Gitlab::Ci::Config::External::Processor::IncludeError)
+ end
+ end
+
+ context 'when files are not nested' do
+ let(:files) do
+ [
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context),
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file2.yml' }, context)
+ ]
+ end
+
+ it 'raises Mapper::TooManyIncludesError' do
+ allow(context).to receive(:max_includes).and_return(1)
+ expect { process }.to raise_error(Gitlab::Ci::Config::External::Mapper::TooManyIncludesError)
+ end
+ end
+
+ context 'when files are duplicates' do
+ let(:files) do
+ [
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context),
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context),
+ Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context)
+ ]
+ end
+
+ it 'raises error' do
allow(context).to receive(:max_includes).and_return(2)
- expect { process }.not_to raise_error
+ expect { process }.to raise_error(Gitlab::Ci::Config::External::Mapper::TooManyIncludesError)
end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index b3115617084..56d1ddee4b8 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Mapper, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Mapper, feature_category: :pipeline_composition do
include StubRequests
include RepoHelpers
@@ -234,17 +234,6 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper, feature_category: :pipeline
process
expect(context.expandset.size).to eq(2)
end
-
- context 'when FF ci_includes_count_duplicates is disabled' do
- before do
- stub_feature_flags(ci_includes_count_duplicates: false)
- end
-
- it 'has expanset with one' do
- process
- expect(context.expandset.size).to eq(1)
- end
- end
end
context 'when passing max number of files' do
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index bb65c2ef10c..97f600baf25 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Processor, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Processor, feature_category: :pipeline_composition do
include StubRequests
include RepoHelpers
diff --git a/spec/lib/gitlab/ci/config/external/rules_spec.rb b/spec/lib/gitlab/ci/config/external/rules_spec.rb
index 227b62d8ce8..cc73338b5a8 100644
--- a/spec/lib/gitlab/ci/config/external/rules_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/rules_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Rules, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::External::Rules, feature_category: :pipeline_composition do
let(:rule_hashes) {}
subject(:rules) { described_class.new(rule_hashes) }
diff --git a/spec/lib/gitlab/ci/config/header/input_spec.rb b/spec/lib/gitlab/ci/config/header/input_spec.rb
new file mode 100644
index 00000000000..73b5b8f9497
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/header/input_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Header::Input, feature_category: :pipeline_composition do
+ let(:factory) do
+ Gitlab::Config::Entry::Factory
+ .new(described_class)
+ .value(input_hash)
+ .with(key: input_name)
+ end
+
+ let(:input_name) { 'foo' }
+
+ subject(:config) { factory.create!.tap(&:compose!) }
+
+ shared_examples 'a valid input' do
+ let(:expected_hash) { input_hash }
+
+ it 'passes validations' do
+ expect(config).to be_valid
+ expect(config.errors).to be_empty
+ end
+
+ it 'returns the value' do
+ expect(config.value).to eq(expected_hash)
+ end
+ end
+
+ shared_examples 'an invalid input' do
+ let(:expected_hash) { input_hash }
+
+ it 'fails validations' do
+ expect(config).not_to be_valid
+ expect(config.errors).to eq(expected_errors)
+ end
+
+ it 'returns the value' do
+ expect(config.value).to eq(expected_hash)
+ end
+ end
+
+ context 'when has a default value' do
+ let(:input_hash) { { default: 'bar' } }
+
+ it_behaves_like 'a valid input'
+ end
+
+ context 'when is a required required input' do
+ let(:input_hash) { nil }
+
+ it_behaves_like 'a valid input'
+ end
+
+ context 'when contains unknown keywords' do
+ let(:input_hash) { { test: 123 } }
+ let(:expected_errors) { ['foo config contains unknown keys: test'] }
+
+ it_behaves_like 'an invalid input'
+ end
+
+ context 'when has invalid name' do
+ let(:input_name) { [123] }
+ let(:input_hash) { {} }
+
+ let(:expected_errors) { ['123 key must be an alphanumeric string'] }
+
+ it_behaves_like 'an invalid input'
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/header/root_spec.rb b/spec/lib/gitlab/ci/config/header/root_spec.rb
new file mode 100644
index 00000000000..55f77137619
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/header/root_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Header::Root, feature_category: :pipeline_composition do
+ let(:factory) { Gitlab::Config::Entry::Factory.new(described_class).value(header_hash) }
+
+ subject(:config) { factory.create!.tap(&:compose!) }
+
+ shared_examples 'a valid header' do
+ let(:expected_hash) { header_hash }
+
+ it 'passes validations' do
+ expect(config).to be_valid
+ expect(config.errors).to be_empty
+ end
+
+ it 'returns the value' do
+ expect(config.value).to eq(expected_hash)
+ end
+ end
+
+ shared_examples 'an invalid header' do
+ let(:expected_hash) { header_hash }
+
+ it 'fails validations' do
+ expect(config).not_to be_valid
+ expect(config.errors).to eq(expected_errors)
+ end
+
+ it 'returns the value' do
+ expect(config.value).to eq(expected_hash)
+ end
+ end
+
+ context 'when header contains default and required values for inputs' do
+ let(:header_hash) do
+ {
+ spec: {
+ inputs: {
+ test: {},
+ foo: {
+ default: 'bar'
+ }
+ }
+ }
+ }
+ end
+
+ it_behaves_like 'a valid header'
+ end
+
+ context 'when header contains minimal data' do
+ let(:header_hash) do
+ {
+ spec: {
+ inputs: nil
+ }
+ }
+ end
+
+ it_behaves_like 'a valid header' do
+ let(:expected_hash) { { spec: {} } }
+ end
+ end
+
+ context 'when header contains required inputs' do
+ let(:header_hash) do
+ {
+ spec: {
+ inputs: { foo: nil }
+ }
+ }
+ end
+
+ it_behaves_like 'a valid header' do
+ let(:expected_hash) do
+ {
+ spec: {
+ inputs: { foo: {} }
+ }
+ }
+ end
+ end
+ end
+
+ context 'when header contains unknown keywords' do
+ let(:header_hash) { { test: 123 } }
+ let(:expected_errors) { ['root config contains unknown keys: test'] }
+
+ it_behaves_like 'an invalid header'
+ end
+
+ context 'when header input entry has an unknown key' do
+ let(:header_hash) do
+ {
+ spec: {
+ inputs: {
+ foo: {
+ bad: 'value'
+ }
+ }
+ }
+ }
+ end
+
+ let(:expected_errors) { ['spec:inputs:foo config contains unknown keys: bad'] }
+
+ it_behaves_like 'an invalid header'
+ end
+
+ describe '#inputs_value' do
+ let(:header_hash) do
+ {
+ spec: {
+ inputs: {
+ foo: nil,
+ bar: {
+ default: 'baz'
+ }
+ }
+ }
+ }
+ end
+
+ it 'returns the inputs' do
+ expect(config.inputs_value).to eq({
+ foo: {},
+ bar: { default: 'baz' }
+ })
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/header/spec_spec.rb b/spec/lib/gitlab/ci/config/header/spec_spec.rb
new file mode 100644
index 00000000000..cb4237f84ce
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/header/spec_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Header::Spec, feature_category: :pipeline_composition do
+ let(:factory) { Gitlab::Config::Entry::Factory.new(described_class).value(spec_hash) }
+
+ subject(:config) { factory.create!.tap(&:compose!) }
+
+ context 'when spec contains default values for inputs' do
+ let(:spec_hash) do
+ {
+ inputs: {
+ foo: {
+ default: 'bar'
+ }
+ }
+ }
+ end
+
+ it 'passes validations' do
+ expect(config).to be_valid
+ expect(config.errors).to be_empty
+ end
+
+ it 'returns the value' do
+ expect(config.value).to eq(spec_hash)
+ end
+ end
+
+ context 'when spec contains unknown keywords' do
+ let(:spec_hash) { { test: 123 } }
+ let(:expected_errors) { ['spec config contains unknown keys: test'] }
+
+ it 'fails validations' do
+ expect(config).not_to be_valid
+ expect(config.errors).to eq(expected_errors)
+ end
+
+ it 'returns the value' do
+ expect(config.value).to eq(spec_hash)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/yaml/result_spec.rb b/spec/lib/gitlab/ci/config/yaml/result_spec.rb
new file mode 100644
index 00000000000..eda15ee9eb2
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/yaml/result_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Yaml::Result, feature_category: :pipeline_composition do
+ it 'does not have a header when config is a single hash' do
+ result = described_class.new(config: { a: 1, b: 2 })
+
+ expect(result).not_to have_header
+ end
+
+ it 'has a header when config is an array of hashes' do
+ result = described_class.new(config: [{ a: 1 }, { b: 2 }])
+
+ expect(result).to have_header
+ expect(result.header).to eq({ a: 1 })
+ end
+
+ it 'raises an error when reading a header when there is none' do
+ result = described_class.new(config: { b: 2 })
+
+ expect { result.header }.to raise_error(ArgumentError)
+ end
+
+ it 'stores an error / exception when initialized with it' do
+ result = described_class.new(error: ArgumentError.new('abc'))
+
+ expect(result).not_to be_valid
+ expect(result.error).to be_a ArgumentError
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/yaml_spec.rb b/spec/lib/gitlab/ci/config/yaml_spec.rb
index 4b34553f55e..f4b70069bbe 100644
--- a/spec/lib/gitlab/ci/config/yaml_spec.rb
+++ b/spec/lib/gitlab/ci/config/yaml_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Yaml, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config::Yaml, feature_category: :pipeline_composition do
describe '.load!' do
it 'loads a single-doc YAML file' do
yaml = <<~YAML
@@ -50,6 +50,15 @@ RSpec.describe Gitlab::Ci::Config::Yaml, feature_category: :pipeline_authoring d
})
end
+ context 'when YAML is invalid' do
+ let(:yaml) { 'some: invalid: syntax' }
+
+ it 'raises an error' do
+ expect { described_class.load!(yaml) }
+ .to raise_error ::Gitlab::Config::Loader::FormatError, /mapping values are not allowed in this context/
+ end
+ end
+
context 'when ci_multi_doc_yaml is disabled' do
before do
stub_feature_flags(ci_multi_doc_yaml: false)
@@ -102,4 +111,38 @@ RSpec.describe Gitlab::Ci::Config::Yaml, feature_category: :pipeline_authoring d
end
end
end
+
+ describe '.load_result!' do
+ context 'when syntax is invalid' do
+ let(:yaml) { 'some: invalid: syntax' }
+
+ it 'returns an invalid result object' do
+ result = described_class.load_result!(yaml)
+
+ expect(result).not_to be_valid
+ expect(result.error).to be_a ::Gitlab::Config::Loader::FormatError
+ end
+ end
+
+ context 'when syntax is valid and contains a header document' do
+ let(:yaml) do
+ <<~YAML
+ a: 1
+ ---
+ b: 2
+ YAML
+ end
+
+ let(:project) { create(:project) }
+
+ it 'returns a result object' do
+ result = described_class.load_result!(yaml, project: project)
+
+ expect(result).to be_valid
+ expect(result.error).to be_nil
+ expect(result.header).to eq({ a: 1 })
+ expect(result.content).to eq({ b: 2 })
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 5cdc9c21561..fdf152b3584 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_composition do
include StubRequests
include RepoHelpers
diff --git a/spec/lib/gitlab/ci/input/arguments/base_spec.rb b/spec/lib/gitlab/ci/input/arguments/base_spec.rb
new file mode 100644
index 00000000000..ed8e99b7257
--- /dev/null
+++ b/spec/lib/gitlab/ci/input/arguments/base_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Input::Arguments::Base, feature_category: :pipeline_composition do
+ subject do
+ Class.new(described_class) do
+ def validate!; end
+ def to_value; end
+ end
+ end
+
+ it 'fabricates an invalid input argument if unknown value is provided' do
+ argument = subject.new(:something, { spec: 123 }, [:a, :b])
+
+ expect(argument).not_to be_valid
+ expect(argument.errors.first).to eq 'unsupported value in input argument `something`'
+ end
+end
diff --git a/spec/lib/gitlab/ci/input/arguments/default_spec.rb b/spec/lib/gitlab/ci/input/arguments/default_spec.rb
new file mode 100644
index 00000000000..6b5dd441eb7
--- /dev/null
+++ b/spec/lib/gitlab/ci/input/arguments/default_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Input::Arguments::Default, feature_category: :pipeline_composition do
+ it 'returns a user-provided value if it is present' do
+ argument = described_class.new(:website, { default: 'https://gitlab.com' }, 'https://example.gitlab.com')
+
+ expect(argument).to be_valid
+ expect(argument.to_value).to eq 'https://example.gitlab.com'
+ expect(argument.to_hash).to eq({ website: 'https://example.gitlab.com' })
+ end
+
+ it 'returns an empty value if user-provider input is empty' do
+ argument = described_class.new(:website, { default: 'https://gitlab.com' }, '')
+
+ expect(argument).to be_valid
+ expect(argument.to_value).to eq ''
+ expect(argument.to_hash).to eq({ website: '' })
+ end
+
+ it 'returns a default value if user-provider one is unknown' do
+ argument = described_class.new(:website, { default: 'https://gitlab.com' }, nil)
+
+ expect(argument).to be_valid
+ expect(argument.to_value).to eq 'https://gitlab.com'
+ expect(argument.to_hash).to eq({ website: 'https://gitlab.com' })
+ end
+
+ it 'returns an error if the argument has not been fabricated correctly' do
+ argument = described_class.new(:website, { required: 'https://gitlab.com' }, 'https://example.gitlab.com')
+
+ expect(argument).not_to be_valid
+ end
+
+ describe '.matches?' do
+ it 'matches specs with default configuration' do
+ expect(described_class.matches?({ default: 'abc' })).to be true
+ end
+
+ it 'does not match specs different configuration keyword' do
+ expect(described_class.matches?({ options: %w[a b] })).to be false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/input/arguments/options_spec.rb b/spec/lib/gitlab/ci/input/arguments/options_spec.rb
new file mode 100644
index 00000000000..afa279ad48d
--- /dev/null
+++ b/spec/lib/gitlab/ci/input/arguments/options_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Input::Arguments::Options, feature_category: :pipeline_composition do
+ it 'returns a user-provided value if it is an allowed one' do
+ argument = described_class.new(:run, { options: %w[opt1 opt2] }, 'opt1')
+
+ expect(argument).to be_valid
+ expect(argument.to_value).to eq 'opt1'
+ expect(argument.to_hash).to eq({ run: 'opt1' })
+ end
+
+ it 'returns an error if user-provided value is not allowlisted' do
+ argument = described_class.new(:run, { options: %w[opt1 opt2] }, 'opt3')
+
+ expect(argument).not_to be_valid
+ expect(argument.errors.first).to eq '`run` input: argument value opt3 not allowlisted'
+ end
+
+ it 'returns an error if specification is not correct' do
+ argument = described_class.new(:website, { options: nil }, 'opt1')
+
+ expect(argument).not_to be_valid
+ expect(argument.errors.first).to eq '`website` input: argument specification invalid'
+ end
+
+ it 'returns an error if specification is using a hash' do
+ argument = described_class.new(:website, { options: { a: 1 } }, 'opt1')
+
+ expect(argument).not_to be_valid
+ expect(argument.errors.first).to eq '`website` input: argument value opt1 not allowlisted'
+ end
+
+ it 'returns an empty value if it is allowlisted' do
+ argument = described_class.new(:run, { options: ['opt1', ''] }, '')
+
+ expect(argument).to be_valid
+ expect(argument.to_value).to be_empty
+ expect(argument.to_hash).to eq({ run: '' })
+ end
+
+ describe '.matches?' do
+ it 'matches specs with options configuration' do
+ expect(described_class.matches?({ options: %w[a b] })).to be true
+ end
+
+ it 'does not match specs different configuration keyword' do
+ expect(described_class.matches?({ default: 'abc' })).to be false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/input/arguments/required_spec.rb b/spec/lib/gitlab/ci/input/arguments/required_spec.rb
new file mode 100644
index 00000000000..0c2ffc282ea
--- /dev/null
+++ b/spec/lib/gitlab/ci/input/arguments/required_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Input::Arguments::Required, feature_category: :pipeline_composition do
+ it 'returns a user-provided value if it is present' do
+ argument = described_class.new(:website, nil, 'https://example.gitlab.com')
+
+ expect(argument).to be_valid
+ expect(argument.to_value).to eq 'https://example.gitlab.com'
+ expect(argument.to_hash).to eq({ website: 'https://example.gitlab.com' })
+ end
+
+ it 'returns an empty value if user-provider value is empty' do
+ argument = described_class.new(:website, nil, '')
+
+ expect(argument).to be_valid
+ expect(argument.to_hash).to eq(website: '')
+ end
+
+ it 'returns an error if user-provided value is unspecified' do
+ argument = described_class.new(:website, nil, nil)
+
+ expect(argument).not_to be_valid
+ expect(argument.errors.first).to eq '`website` input: required value has not been provided'
+ end
+
+ describe '.matches?' do
+ it 'matches specs without configuration' do
+ expect(described_class.matches?(nil)).to be true
+ end
+
+ it 'matches specs with empty configuration' do
+ expect(described_class.matches?('')).to be true
+ end
+
+ it 'does not match specs with configuration' do
+ expect(described_class.matches?({ options: %w[a b] })).to be false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/input/arguments/unknown_spec.rb b/spec/lib/gitlab/ci/input/arguments/unknown_spec.rb
new file mode 100644
index 00000000000..1270423ac72
--- /dev/null
+++ b/spec/lib/gitlab/ci/input/arguments/unknown_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Input::Arguments::Unknown, feature_category: :pipeline_composition do
+ it 'raises an error when someone tries to evaluate the value' do
+ argument = described_class.new(:website, nil, 'https://example.gitlab.com')
+
+ expect(argument).not_to be_valid
+ expect { argument.to_value }.to raise_error ArgumentError
+ end
+
+ describe '.matches?' do
+ it 'always matches' do
+ expect(described_class.matches?('abc')).to be true
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/input/inputs_spec.rb b/spec/lib/gitlab/ci/input/inputs_spec.rb
new file mode 100644
index 00000000000..5d2d5192299
--- /dev/null
+++ b/spec/lib/gitlab/ci/input/inputs_spec.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Input::Inputs, feature_category: :pipeline_composition do
+ describe '#valid?' do
+ let(:spec) { { website: nil } }
+
+ it 'describes user-provided inputs' do
+ inputs = described_class.new(spec, { website: 'http://example.gitlab.com' })
+
+ expect(inputs).to be_valid
+ end
+ end
+
+ context 'when proper specification has been provided' do
+ let(:spec) do
+ {
+ website: nil,
+ env: { default: 'development' },
+ run: { options: %w[tests spec e2e] }
+ }
+ end
+
+ let(:args) { { website: 'https://gitlab.com', run: 'tests' } }
+
+ it 'fabricates desired input arguments' do
+ inputs = described_class.new(spec, args)
+
+ expect(inputs).to be_valid
+ expect(inputs.count).to eq 3
+ expect(inputs.to_hash).to eq(args.merge(env: 'development'))
+ end
+ end
+
+ context 'when inputs and args are empty' do
+ it 'is a valid use-case' do
+ inputs = described_class.new({}, {})
+
+ expect(inputs).to be_valid
+ expect(inputs.to_hash).to be_empty
+ end
+ end
+
+ context 'when there are arguments recoincilation errors present' do
+ context 'when required argument is missing' do
+ let(:spec) { { website: nil } }
+
+ it 'returns an error' do
+ inputs = described_class.new(spec, {})
+
+ expect(inputs).not_to be_valid
+ expect(inputs.errors.first).to eq '`website` input: required value has not been provided'
+ end
+ end
+
+ context 'when argument is not present but configured as allowlist' do
+ let(:spec) do
+ { run: { options: %w[opt1 opt2] } }
+ end
+
+ it 'returns an error' do
+ inputs = described_class.new(spec, {})
+
+ expect(inputs).not_to be_valid
+ expect(inputs.errors.first).to eq '`run` input: argument not provided'
+ end
+ end
+ end
+
+ context 'when unknown specification argument has been used' do
+ let(:spec) do
+ {
+ website: nil,
+ env: { default: 'development' },
+ run: { options: %w[tests spec e2e] },
+ test: { unknown: 'something' }
+ }
+ end
+
+ let(:args) { { website: 'https://gitlab.com', run: 'tests' } }
+
+ it 'fabricates an unknown argument entry and returns an error' do
+ inputs = described_class.new(spec, args)
+
+ expect(inputs).not_to be_valid
+ expect(inputs.count).to eq 4
+ expect(inputs.errors.first).to eq '`test` input: unrecognized input argument specification: `unknown`'
+ end
+ end
+
+ context 'when unknown arguments are being passed by a user' do
+ let(:spec) do
+ { env: { default: 'development' } }
+ end
+
+ let(:args) { { website: 'https://gitlab.com', run: 'tests' } }
+
+ it 'returns an error with a list of unknown arguments' do
+ inputs = described_class.new(spec, args)
+
+ expect(inputs).not_to be_valid
+ expect(inputs.errors.first).to eq 'unknown input arguments: [:website, :run]'
+ end
+ end
+
+ context 'when composite specification is being used' do
+ let(:spec) do
+ {
+ env: {
+ default: 'dev',
+ options: %w[test dev prod]
+ }
+ }
+ end
+
+ let(:args) { { env: 'dev' } }
+
+ it 'returns an error describing an unknown specification' do
+ inputs = described_class.new(spec, args)
+
+ expect(inputs).not_to be_valid
+ expect(inputs.errors.first).to eq '`env` input: unrecognized input argument definition'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/interpolation/access_spec.rb b/spec/lib/gitlab/ci/interpolation/access_spec.rb
index 9f6108a328d..f327377b7e3 100644
--- a/spec/lib/gitlab/ci/interpolation/access_spec.rb
+++ b/spec/lib/gitlab/ci/interpolation/access_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Ci::Interpolation::Access, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Interpolation::Access, feature_category: :pipeline_composition do
subject { described_class.new(access, ctx) }
let(:access) do
diff --git a/spec/lib/gitlab/ci/interpolation/block_spec.rb b/spec/lib/gitlab/ci/interpolation/block_spec.rb
index 7f2be505d17..4a8709df3dc 100644
--- a/spec/lib/gitlab/ci/interpolation/block_spec.rb
+++ b/spec/lib/gitlab/ci/interpolation/block_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Ci::Interpolation::Block, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Interpolation::Block, feature_category: :pipeline_composition do
subject { described_class.new(block, data, ctx) }
let(:data) do
diff --git a/spec/lib/gitlab/ci/interpolation/config_spec.rb b/spec/lib/gitlab/ci/interpolation/config_spec.rb
index e5987776e00..e745269d8c0 100644
--- a/spec/lib/gitlab/ci/interpolation/config_spec.rb
+++ b/spec/lib/gitlab/ci/interpolation/config_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Ci::Interpolation::Config, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Interpolation::Config, feature_category: :pipeline_composition do
subject { described_class.new(YAML.safe_load(config)) }
let(:config) do
diff --git a/spec/lib/gitlab/ci/interpolation/context_spec.rb b/spec/lib/gitlab/ci/interpolation/context_spec.rb
index ada896f4980..2b126f4a8b3 100644
--- a/spec/lib/gitlab/ci/interpolation/context_spec.rb
+++ b/spec/lib/gitlab/ci/interpolation/context_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Ci::Interpolation::Context, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Interpolation::Context, feature_category: :pipeline_composition do
subject { described_class.new(ctx) }
let(:ctx) do
diff --git a/spec/lib/gitlab/ci/interpolation/template_spec.rb b/spec/lib/gitlab/ci/interpolation/template_spec.rb
index 8a243b4db05..a3ef1bb4445 100644
--- a/spec/lib/gitlab/ci/interpolation/template_spec.rb
+++ b/spec/lib/gitlab/ci/interpolation/template_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Ci::Interpolation::Template, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Interpolation::Template, feature_category: :pipeline_composition do
subject { described_class.new(YAML.safe_load(config), ctx) }
let(:config) do
diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb
index b836ca395fa..b238e9161eb 100644
--- a/spec/lib/gitlab/ci/lint_spec.rb
+++ b/spec/lib/gitlab/ci/lint_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Lint, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Lint, feature_category: :pipeline_composition do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
@@ -100,8 +100,8 @@ RSpec.describe Gitlab::Ci::Lint, feature_category: :pipeline_authoring do
end
it 'sets merged_config' do
- root_config = YAML.safe_load(content, [Symbol])
- included_config = YAML.safe_load(included_content, [Symbol])
+ root_config = YAML.safe_load(content, permitted_classes: [Symbol])
+ included_config = YAML.safe_load(included_content, permitted_classes: [Symbol])
expected_config = included_config.merge(root_config).except(:include).deep_stringify_keys
expect(subject.merged_yaml).to eq(expected_config.to_yaml)
diff --git a/spec/lib/gitlab/ci/parsers/security/common_spec.rb b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
index 5d2d22c04fc..421aa29f860 100644
--- a/spec/lib/gitlab/ci/parsers/security/common_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Parsers::Security::Common do
+RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnerability_management do
describe '#parse!' do
let_it_be(:scanner_data) do
{
@@ -410,6 +410,12 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
end
end
+ describe 'setting the `found_by_pipeline` attribute' do
+ subject { report.findings.map(&:found_by_pipeline).uniq }
+
+ it { is_expected.to eq([pipeline]) }
+ end
+
describe 'parsing tracking' do
let(:finding) { report.findings.first }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
index e0d656f456e..a9a52972294 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content, feature_category: :continuous_integration do
let(:project) { create(:project, ci_config_path: ci_config_path) }
let(:pipeline) { build(:ci_pipeline, project: project) }
let(:content) { nil }
@@ -26,6 +26,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq 'bridge_source'
expect(command.config_content).to eq 'the-yaml'
+ expect(command.pipeline_config.internal_include_prepended?).to eq(false)
end
end
@@ -52,6 +53,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq 'repository_source'
expect(pipeline.pipeline_config.content).to eq(config_content_result)
expect(command.config_content).to eq(config_content_result)
+ expect(command.pipeline_config.internal_include_prepended?).to eq(true)
end
end
@@ -71,6 +73,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq 'remote_source'
expect(pipeline.pipeline_config.content).to eq(config_content_result)
expect(command.config_content).to eq(config_content_result)
+ expect(command.pipeline_config.internal_include_prepended?).to eq(true)
end
end
@@ -91,6 +94,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq 'external_project_source'
expect(pipeline.pipeline_config.content).to eq(config_content_result)
expect(command.config_content).to eq(config_content_result)
+ expect(command.pipeline_config.internal_include_prepended?).to eq(true)
end
context 'when path specifies a refname' do
@@ -111,6 +115,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq 'external_project_source'
expect(pipeline.pipeline_config.content).to eq(config_content_result)
expect(command.config_content).to eq(config_content_result)
+ expect(command.pipeline_config.internal_include_prepended?).to eq(true)
end
end
end
@@ -138,6 +143,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq 'repository_source'
expect(pipeline.pipeline_config.content).to eq(config_content_result)
expect(command.config_content).to eq(config_content_result)
+ expect(command.pipeline_config.internal_include_prepended?).to eq(true)
end
end
@@ -161,6 +167,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq 'auto_devops_source'
expect(pipeline.pipeline_config.content).to eq(config_content_result)
expect(command.config_content).to eq(config_content_result)
+ expect(command.pipeline_config.internal_include_prepended?).to eq(true)
end
end
@@ -181,6 +188,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq 'parameter_source'
expect(pipeline.pipeline_config.content).to eq(content)
expect(command.config_content).to eq(content)
+ expect(command.pipeline_config.internal_include_prepended?).to eq(false)
end
end
@@ -197,6 +205,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
expect(pipeline.config_source).to eq('unknown_source')
expect(pipeline.pipeline_config).to be_nil
expect(command.config_content).to be_nil
+ expect(command.pipeline_config).to be_nil
expect(pipeline.errors.full_messages).to include('Missing CI config file')
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/duration_spec.rb b/spec/lib/gitlab/ci/pipeline/duration_spec.rb
index 36714413da6..89c0ce46237 100644
--- a/spec/lib/gitlab/ci/pipeline/duration_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/duration_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Pipeline::Duration do
+RSpec.describe Gitlab::Ci::Pipeline::Duration, feature_category: :continuous_integration do
describe '.from_periods' do
let(:calculated_duration) { calculate(data) }
@@ -113,16 +113,17 @@ RSpec.describe Gitlab::Ci::Pipeline::Duration do
described_class::Period.new(first, last)
end
- described_class.from_periods(periods.sort_by(&:first))
+ described_class.send(:from_periods, periods.sort_by(&:first))
end
end
describe '.from_pipeline' do
+ let_it_be_with_reload(:pipeline) { create(:ci_pipeline) }
+
let_it_be(:start_time) { Time.current.change(usec: 0) }
let_it_be(:current) { start_time + 1000 }
- let_it_be(:pipeline) { create(:ci_pipeline) }
- let_it_be(:success_build) { create_build(:success, started_at: start_time, finished_at: start_time + 60) }
- let_it_be(:failed_build) { create_build(:failed, started_at: start_time + 60, finished_at: start_time + 120) }
+ let_it_be(:success_build) { create_build(:success, started_at: start_time, finished_at: start_time + 50) }
+ let_it_be(:failed_build) { create_build(:failed, started_at: start_time + 60, finished_at: start_time + 110) }
let_it_be(:canceled_build) { create_build(:canceled, started_at: start_time + 120, finished_at: start_time + 180) }
let_it_be(:skipped_build) { create_build(:skipped, started_at: start_time) }
let_it_be(:pending_build) { create_build(:pending) }
@@ -141,21 +142,55 @@ RSpec.describe Gitlab::Ci::Pipeline::Duration do
end
context 'when there is no running build' do
- let(:running_build) { nil }
+ let!(:running_build) { nil }
it 'returns the duration for all the builds' do
travel_to(current) do
- expect(described_class.from_pipeline(pipeline)).to eq 180.seconds
+ # 160 = success (50) + failed (50) + canceled (60)
+ expect(described_class.from_pipeline(pipeline)).to eq 160.seconds
end
end
end
- context 'when there are bridge jobs' do
- let!(:success_bridge) { create_bridge(:success, started_at: start_time + 220, finished_at: start_time + 280) }
- let!(:failed_bridge) { create_bridge(:failed, started_at: start_time + 180, finished_at: start_time + 240) }
- let!(:skipped_bridge) { create_bridge(:skipped, started_at: start_time) }
- let!(:created_bridge) { create_bridge(:created) }
- let!(:manual_bridge) { create_bridge(:manual) }
+ context 'when there are direct bridge jobs' do
+ let_it_be(:success_bridge) do
+ create_bridge(:success, started_at: start_time + 220, finished_at: start_time + 280)
+ end
+
+ let_it_be(:failed_bridge) { create_bridge(:failed, started_at: start_time + 180, finished_at: start_time + 240) }
+ # NOTE: bridge won't be `canceled` as it will be marked as failed when downstream pipeline is canceled
+ # @see Ci::Bridge#inherit_status_from_downstream
+ let_it_be(:canceled_bridge) do
+ create_bridge(:failed, started_at: start_time + 180, finished_at: start_time + 210)
+ end
+
+ let_it_be(:skipped_bridge) { create_bridge(:skipped, started_at: start_time) }
+ let_it_be(:created_bridge) { create_bridge(:created) }
+ let_it_be(:manual_bridge) { create_bridge(:manual) }
+
+ let_it_be(:success_bridge_pipeline) do
+ create(:ci_pipeline, :success, started_at: start_time + 230, finished_at: start_time + 280).tap do |p|
+ create(:ci_sources_pipeline, source_job: success_bridge, pipeline: p)
+ create_build(:success, pipeline: p, started_at: start_time + 235, finished_at: start_time + 280)
+ create_bridge(:success, pipeline: p, started_at: start_time + 240, finished_at: start_time + 280)
+ end
+ end
+
+ let_it_be(:failed_bridge_pipeline) do
+ create(:ci_pipeline, :failed, started_at: start_time + 225, finished_at: start_time + 240).tap do |p|
+ create(:ci_sources_pipeline, source_job: failed_bridge, pipeline: p)
+ create_build(:failed, pipeline: p, started_at: start_time + 230, finished_at: start_time + 240)
+ create_bridge(:success, pipeline: p, started_at: start_time + 235, finished_at: start_time + 240)
+ end
+ end
+
+ let_it_be(:canceled_bridge_pipeline) do
+ create(:ci_pipeline, :canceled, started_at: start_time + 190, finished_at: start_time + 210).tap do |p|
+ create(:ci_sources_pipeline, source_job: canceled_bridge, pipeline: p)
+ create_build(:canceled, pipeline: p, started_at: start_time + 200, finished_at: start_time + 210)
+ create_bridge(:success, pipeline: p, started_at: start_time + 205, finished_at: start_time + 210)
+ end
+ end
it 'returns the duration of the running build' do
travel_to(current) do
@@ -166,12 +201,99 @@ RSpec.describe Gitlab::Ci::Pipeline::Duration do
context 'when there is no running build' do
let!(:running_build) { nil }
- it 'returns the duration for all the builds and bridge jobs' do
+ it 'returns the duration for all the builds (including self and downstreams)' do
travel_to(current) do
- expect(described_class.from_pipeline(pipeline)).to eq 280.seconds
+ # 220 = 160 (see above)
+ # + success build (45) + failed (10) + canceled (10) - overlapping (success & failed) (5)
+ expect(described_class.from_pipeline(pipeline)).to eq 220.seconds
end
end
end
+
+ # rubocop:disable RSpec/MultipleMemoizedHelpers
+ context 'when there are downstream bridge jobs' do
+ let_it_be(:success_direct_bridge) do
+ create_bridge(:success, started_at: start_time + 280, finished_at: start_time + 400)
+ end
+
+ let_it_be(:success_downstream_pipeline) do
+ create(:ci_pipeline, :success, started_at: start_time + 285, finished_at: start_time + 300).tap do |p|
+ create(:ci_sources_pipeline, source_job: success_direct_bridge, pipeline: p)
+ create_build(:success, pipeline: p, started_at: start_time + 290, finished_at: start_time + 296)
+ create_bridge(:success, pipeline: p, started_at: start_time + 285, finished_at: start_time + 288)
+ end
+ end
+
+ let_it_be(:failed_downstream_pipeline) do
+ create(:ci_pipeline, :failed, started_at: start_time + 305, finished_at: start_time + 350).tap do |p|
+ create(:ci_sources_pipeline, source_job: success_direct_bridge, pipeline: p)
+ create_build(:failed, pipeline: p, started_at: start_time + 320, finished_at: start_time + 327)
+ create_bridge(:success, pipeline: p, started_at: start_time + 305, finished_at: start_time + 350)
+ end
+ end
+
+ let_it_be(:canceled_downstream_pipeline) do
+ create(:ci_pipeline, :canceled, started_at: start_time + 360, finished_at: start_time + 400).tap do |p|
+ create(:ci_sources_pipeline, source_job: success_direct_bridge, pipeline: p)
+ create_build(:canceled, pipeline: p, started_at: start_time + 390, finished_at: start_time + 398)
+ create_bridge(:success, pipeline: p, started_at: start_time + 360, finished_at: start_time + 378)
+ end
+ end
+
+ it 'returns the duration of the running build' do
+ travel_to(current) do
+ expect(described_class.from_pipeline(pipeline)).to eq 1000.seconds
+ end
+ end
+
+ context 'when there is no running build' do
+ let!(:running_build) { nil }
+
+ it 'returns the duration for all the builds (including self and downstreams)' do
+ travel_to(current) do
+ # 241 = 220 (see above)
+ # + success downstream build (6) + failed (7) + canceled (8)
+ expect(described_class.from_pipeline(pipeline)).to eq 241.seconds
+ end
+ end
+ end
+ end
+ # rubocop:enable RSpec/MultipleMemoizedHelpers
+ end
+
+ it 'does not generate N+1 queries if more builds are added' do
+ travel_to(current) do
+ expect do
+ described_class.from_pipeline(pipeline)
+ end.not_to exceed_query_limit(1)
+
+ create_list(:ci_build, 2, :success, pipeline: pipeline, started_at: start_time, finished_at: start_time + 50)
+
+ expect do
+ described_class.from_pipeline(pipeline)
+ end.not_to exceed_query_limit(1)
+ end
+ end
+
+ it 'does not generate N+1 queries if more bridges and their pipeline builds are added' do
+ travel_to(current) do
+ expect do
+ described_class.from_pipeline(pipeline)
+ end.not_to exceed_query_limit(1)
+
+ create_list(
+ :ci_bridge, 2, :success,
+ pipeline: pipeline, started_at: start_time + 220, finished_at: start_time + 280).each do |bridge|
+ create(:ci_pipeline, :success, started_at: start_time + 235, finished_at: start_time + 280).tap do |p|
+ create(:ci_sources_pipeline, source_job: bridge, pipeline: p)
+ create_builds(3, :success)
+ end
+ end
+
+ expect do
+ described_class.from_pipeline(pipeline)
+ end.not_to exceed_query_limit(1)
+ end
end
private
@@ -180,6 +302,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Duration do
create(:ci_build, trait, pipeline: pipeline, **opts)
end
+ def create_builds(counts, trait, **opts)
+ create_list(:ci_build, counts, trait, pipeline: pipeline, **opts)
+ end
+
def create_bridge(trait, **opts)
create(:ci_bridge, trait, pipeline: pipeline, **opts)
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 3043d7f5381..ce68e741d00 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Pipeline::Seed::Build, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Build, feature_category: :pipeline_composition do
let_it_be_with_reload(:project) { create(:project, :repository) }
let_it_be(:head_sha) { project.repository.head_commit.id }
diff --git a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
index 288ac3f3854..ae40626510f 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Pipeline::Seed::Stage, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Pipeline::Seed::Stage, feature_category: :pipeline_composition do
let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:previous_stages) { [] }
diff --git a/spec/lib/gitlab/ci/project_config/repository_spec.rb b/spec/lib/gitlab/ci/project_config/repository_spec.rb
index 2105b691d9e..e8a997a7e43 100644
--- a/spec/lib/gitlab/ci/project_config/repository_spec.rb
+++ b/spec/lib/gitlab/ci/project_config/repository_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::ProjectConfig::Repository do
+RSpec.describe Gitlab::Ci::ProjectConfig::Repository, feature_category: :continuous_integration do
let(:project) { create(:project, :custom_repo, files: files) }
let(:sha) { project.repository.head_commit.sha }
let(:files) { { 'README.md' => 'hello' } }
@@ -44,4 +44,10 @@ RSpec.describe Gitlab::Ci::ProjectConfig::Repository do
it { is_expected.to eq(:repository_source) }
end
+
+ describe '#internal_include_prepended?' do
+ subject { config.internal_include_prepended? }
+
+ it { is_expected.to eq(true) }
+ end
end
diff --git a/spec/lib/gitlab/ci/project_config/source_spec.rb b/spec/lib/gitlab/ci/project_config/source_spec.rb
index dda5c7cdce8..eefabe1babb 100644
--- a/spec/lib/gitlab/ci/project_config/source_spec.rb
+++ b/spec/lib/gitlab/ci/project_config/source_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::ProjectConfig::Source do
+RSpec.describe Gitlab::Ci::ProjectConfig::Source, feature_category: :continuous_integration do
let_it_be(:custom_config_class) { Class.new(described_class) }
let_it_be(:project) { build_stubbed(:project) }
let_it_be(:sha) { '123456' }
@@ -20,4 +20,10 @@ RSpec.describe Gitlab::Ci::ProjectConfig::Source do
it { expect { source }.to raise_error(NotImplementedError) }
end
+
+ describe '#internal_include_prepended?' do
+ subject(:internal_include_prepended) { custom_config.internal_include_prepended? }
+
+ it { expect(internal_include_prepended).to eq(false) }
+ end
end
diff --git a/spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb
deleted file mode 100644
index 6f75e2c55e8..00000000000
--- a/spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb
+++ /dev/null
@@ -1,163 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
- let(:identifier) { build(:ci_reports_security_identifier) }
-
- let_it_be(:project) { create(:project, :repository) }
-
- let(:location_param) { build(:ci_reports_security_locations_sast, :dynamic) }
- let(:vulnerability_params) { vuln_params(project.id, [identifier], confidence: :low, severity: :critical) }
- let(:base_vulnerability) { build(:ci_reports_security_finding, location: location_param, **vulnerability_params) }
- let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [base_vulnerability]) }
-
- let(:head_vulnerability) { build(:ci_reports_security_finding, location: location_param, uuid: base_vulnerability.uuid, **vulnerability_params) }
- let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: [head_vulnerability]) }
-
- shared_context 'comparing reports' do
- let(:vul_params) { vuln_params(project.id, [identifier]) }
- let(:base_vulnerability) { build(:ci_reports_security_finding, :dynamic, **vul_params) }
- let(:head_vulnerability) { build(:ci_reports_security_finding, :dynamic, **vul_params) }
- let(:head_vul_findings) { [head_vulnerability, vuln] }
- end
-
- subject { described_class.new(project, base_report, head_report) }
-
- where(vulnerability_finding_signatures: [true, false])
-
- with_them do
- before do
- stub_licensed_features(vulnerability_finding_signatures: vulnerability_finding_signatures)
- end
-
- describe '#base_report_out_of_date' do
- context 'no base report' do
- let(:base_report) { build(:ci_reports_security_aggregated_reports, reports: [], findings: []) }
-
- it 'is not out of date' do
- expect(subject.base_report_out_of_date).to be false
- end
- end
-
- context 'base report older than one week' do
- let(:report) { build(:ci_reports_security_report, created_at: 1.week.ago - 60.seconds) }
- let(:base_report) { build(:ci_reports_security_aggregated_reports, reports: [report]) }
-
- it 'is not out of date' do
- expect(subject.base_report_out_of_date).to be true
- end
- end
-
- context 'base report less than one week old' do
- let(:report) { build(:ci_reports_security_report, created_at: 1.week.ago + 60.seconds) }
- let(:base_report) { build(:ci_reports_security_aggregated_reports, reports: [report]) }
-
- it 'is not out of date' do
- expect(subject.base_report_out_of_date).to be false
- end
- end
- end
-
- describe '#added' do
- let(:new_location) { build(:ci_reports_security_locations_sast, :dynamic) }
- let(:vul_params) { vuln_params(project.id, [identifier], confidence: :high) }
- let(:vuln) { build(:ci_reports_security_finding, severity: Enums::Vulnerability.severity_levels[:critical], location: new_location, **vul_params) }
- let(:low_vuln) { build(:ci_reports_security_finding, severity: Enums::Vulnerability.severity_levels[:low], location: new_location, **vul_params) }
-
- context 'with new vulnerability' do
- let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: [head_vulnerability, vuln]) }
-
- it 'points to source tree' do
- expect(subject.added).to eq([vuln])
- end
- end
-
- context 'when comparing reports with different fingerprints' do
- include_context 'comparing reports'
-
- let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: head_vul_findings) }
-
- it 'does not find any overlap' do
- expect(subject.added).to eq(head_vul_findings)
- end
- end
-
- context 'order' do
- let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: [head_vulnerability, vuln, low_vuln]) }
-
- it 'does not change' do
- expect(subject.added).to eq([vuln, low_vuln])
- end
- end
- end
-
- describe '#fixed' do
- let(:vul_params) { vuln_params(project.id, [identifier]) }
- let(:vuln) { build(:ci_reports_security_finding, :dynamic, **vul_params ) }
- let(:medium_vuln) { build(:ci_reports_security_finding, confidence: ::Enums::Vulnerability.confidence_levels[:high], severity: Enums::Vulnerability.severity_levels[:medium], uuid: vuln.uuid, **vul_params) }
-
- context 'with fixed vulnerability' do
- let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [base_vulnerability, vuln]) }
-
- it 'points to base tree' do
- expect(subject.fixed).to eq([vuln])
- end
- end
-
- context 'when comparing reports with different fingerprints' do
- include_context 'comparing reports'
-
- let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [base_vulnerability, vuln]) }
-
- it 'does not find any overlap' do
- expect(subject.fixed).to eq([base_vulnerability, vuln])
- end
- end
-
- context 'order' do
- let(:vul_findings) { [vuln, medium_vuln] }
- let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [*vul_findings, base_vulnerability]) }
-
- it 'does not change' do
- expect(subject.fixed).to eq(vul_findings)
- end
- end
- end
-
- describe 'with empty vulnerabilities' do
- let(:empty_report) { build(:ci_reports_security_aggregated_reports, reports: [], findings: []) }
-
- it 'returns empty array when reports are not present' do
- comparer = described_class.new(project, empty_report, empty_report)
-
- expect(comparer.fixed).to eq([])
- expect(comparer.added).to eq([])
- end
-
- it 'returns added vulnerability when base is empty and head is not empty' do
- comparer = described_class.new(project, empty_report, head_report)
-
- expect(comparer.fixed).to eq([])
- expect(comparer.added).to eq([head_vulnerability])
- end
-
- it 'returns fixed vulnerability when head is empty and base is not empty' do
- comparer = described_class.new(project, base_report, empty_report)
-
- expect(comparer.fixed).to eq([base_vulnerability])
- expect(comparer.added).to eq([])
- end
- end
- end
-
- def vuln_params(project_id, identifiers, confidence: :high, severity: :critical)
- {
- project_id: project_id,
- report_type: :sast,
- identifiers: identifiers,
- confidence: ::Enums::Vulnerability.confidence_levels[confidence],
- severity: ::Enums::Vulnerability.severity_levels[severity]
- }
- end
-end
diff --git a/spec/lib/gitlab/ci/runner_releases_spec.rb b/spec/lib/gitlab/ci/runner_releases_spec.rb
index 14f3c95ec79..9e211327dee 100644
--- a/spec/lib/gitlab/ci/runner_releases_spec.rb
+++ b/spec/lib/gitlab/ci/runner_releases_spec.rb
@@ -177,6 +177,16 @@ RSpec.describe Gitlab::Ci::RunnerReleases, feature_category: :runner_fleet do
it 'returns parsed and sorted Gitlab::VersionInfo objects' do
expect(releases).to eq(expected_result)
end
+
+ context 'when fetching runner releases is disabled' do
+ before do
+ stub_application_setting(update_runner_versions_enabled: false)
+ end
+
+ it 'returns nil' do
+ expect(releases).to be_nil
+ end
+ end
end
context 'when response contains unexpected input type' do
@@ -218,6 +228,16 @@ RSpec.describe Gitlab::Ci::RunnerReleases, feature_category: :runner_fleet do
it 'returns parsed and grouped Gitlab::VersionInfo objects' do
expect(releases_by_minor).to eq(expected_result)
end
+
+ context 'when fetching runner releases is disabled' do
+ before do
+ stub_application_setting(update_runner_versions_enabled: false)
+ end
+
+ it 'returns nil' do
+ expect(releases_by_minor).to be_nil
+ end
+ end
end
context 'when response contains unexpected input type' do
@@ -233,6 +253,18 @@ RSpec.describe Gitlab::Ci::RunnerReleases, feature_category: :runner_fleet do
end
end
+ describe '#enabled?' do
+ it { is_expected.to be_enabled }
+
+ context 'when fetching runner releases is disabled' do
+ before do
+ stub_application_setting(update_runner_versions_enabled: false)
+ end
+
+ it { is_expected.not_to be_enabled }
+ end
+ end
+
def mock_http_response(response)
http_response = instance_double(HTTParty::Response)
diff --git a/spec/lib/gitlab/ci/templates/Jobs/build_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/build_gitlab_ci_yaml_spec.rb
index 07cfa939623..995922b6922 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/build_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/build_gitlab_ci_yaml_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'Jobs/Build.gitlab-ci.yml' do
describe 'AUTO_BUILD_IMAGE_VERSION' do
it 'corresponds to a published image in the registry' do
registry = "https://#{template_registry_host}"
- repository = "gitlab-org/cluster-integration/auto-build-image"
+ repository = auto_build_image_repository
reference = YAML.safe_load(template.content).dig('variables', 'AUTO_BUILD_IMAGE_VERSION')
expect(public_image_exist?(registry, repository, reference)).to be true
diff --git a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb
index 039a6a739dd..2b9213ea921 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb
@@ -23,27 +23,33 @@ RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml', feature_category: :continuo
allow(project).to receive(:default_branch).and_return(default_branch)
end
- context 'on feature branch' do
- let(:pipeline_ref) { 'feature' }
+ context 'when SAST_DISABLED="false"' do
+ before do
+ create(:ci_variable, key: 'SAST_DISABLED', value: 'false', project: project)
+ end
+
+ context 'on feature branch' do
+ let(:pipeline_ref) { 'feature' }
- it 'creates the kics-iac-sast job' do
- expect(build_names).to contain_exactly('kics-iac-sast')
+ it 'creates the kics-iac-sast job' do
+ expect(build_names).to contain_exactly('kics-iac-sast')
+ end
end
- end
- context 'on merge request' do
- let(:service) { MergeRequests::CreatePipelineService.new(project: project, current_user: user) }
- let(:merge_request) { create(:merge_request, :simple, source_project: project) }
- let(:pipeline) { service.execute(merge_request).payload }
+ context 'on merge request' do
+ let(:service) { MergeRequests::CreatePipelineService.new(project: project, current_user: user) }
+ let(:merge_request) { create(:merge_request, :simple, source_project: project) }
+ let(:pipeline) { service.execute(merge_request).payload }
- it 'creates a pipeline with the expected jobs' do
- expect(pipeline).to be_merge_request_event
- expect(pipeline.errors.full_messages).to be_empty
- expect(build_names).to match_array(%w(kics-iac-sast))
+ it 'creates a pipeline with the expected jobs' do
+ expect(pipeline).to be_merge_request_event
+ expect(pipeline.errors.full_messages).to be_empty
+ expect(build_names).to match_array(%w(kics-iac-sast))
+ end
end
end
- context 'SAST_DISABLED is set' do
+ context 'when SAST_DISABLED="true"' do
before do
create(:ci_variable, key: 'SAST_DISABLED', value: 'true', project: project)
end
diff --git a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
index a5365ae53b8..f8770457083 100644
--- a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :pipeline_composition do
let_it_be(:project) { create_default(:project, :repository, create_tag: 'test').freeze }
let_it_be(:user) { create(:user) }
diff --git a/spec/lib/gitlab/ci/variables/builder_spec.rb b/spec/lib/gitlab/ci/variables/builder_spec.rb
index bbd3dc54e6a..215b18ea614 100644
--- a/spec/lib/gitlab/ci/variables/builder_spec.rb
+++ b/spec/lib/gitlab/ci/variables/builder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, feature_category: :pipeline_composition do
include Ci::TemplateHelpers
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, namespace: group) }
diff --git a/spec/lib/gitlab/ci/variables/collection_spec.rb b/spec/lib/gitlab/ci/variables/collection_spec.rb
index 4ee122cc607..668f1173675 100644
--- a/spec/lib/gitlab/ci/variables/collection_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Variables::Collection, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Ci::Variables::Collection, feature_category: :pipeline_composition do
describe '.new' do
it 'can be initialized with an array' do
variable = { key: 'VAR', value: 'value', public: true, masked: false }
diff --git a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb
index 5c9f156e054..36ada9050b2 100644
--- a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb
@@ -47,8 +47,8 @@ module Gitlab
end
it 'returns expanded yaml config' do
- expanded_config = YAML.safe_load(config_metadata[:merged_yaml], [Symbol])
- included_config = YAML.safe_load(included_yml, [Symbol])
+ expanded_config = YAML.safe_load(config_metadata[:merged_yaml], permitted_classes: [Symbol])
+ included_config = YAML.safe_load(included_yml, permitted_classes: [Symbol])
expect(expanded_config).to include(*included_config.keys)
end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 360686ce65c..b00d9b46bc7 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
module Gitlab
module Ci
- RSpec.describe YamlProcessor, feature_category: :pipeline_authoring do
+ RSpec.describe YamlProcessor, feature_category: :pipeline_composition do
include StubRequests
include RepoHelpers
diff --git a/spec/lib/gitlab/color_schemes_spec.rb b/spec/lib/gitlab/color_schemes_spec.rb
index feb5648ff2d..bc69c8beeda 100644
--- a/spec/lib/gitlab/color_schemes_spec.rb
+++ b/spec/lib/gitlab/color_schemes_spec.rb
@@ -21,8 +21,9 @@ RSpec.describe Gitlab::ColorSchemes do
end
describe '.default' do
- it 'returns the default scheme' do
- expect(described_class.default.id).to eq 1
+ it 'use config default' do
+ stub_application_setting(default_syntax_highlighting_theme: 2)
+ expect(described_class.default.id).to eq 2
end
end
@@ -36,7 +37,8 @@ RSpec.describe Gitlab::ColorSchemes do
describe '.for_user' do
it 'returns default when user is nil' do
- expect(described_class.for_user(nil).id).to eq 1
+ stub_application_setting(default_syntax_highlighting_theme: 2)
+ expect(described_class.for_user(nil).id).to eq 2
end
it "returns user's preferred color scheme" do
diff --git a/spec/lib/gitlab/config/entry/validators_spec.rb b/spec/lib/gitlab/config/entry/validators_spec.rb
index 54a2adbefd2..abf3dbacb3d 100644
--- a/spec/lib/gitlab/config/entry/validators_spec.rb
+++ b/spec/lib/gitlab/config/entry/validators_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Config::Entry::Validators, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Config::Entry::Validators, feature_category: :pipeline_composition do
let(:klass) do
Class.new do
include ActiveModel::Validations
diff --git a/spec/lib/gitlab/config/loader/multi_doc_yaml_spec.rb b/spec/lib/gitlab/config/loader/multi_doc_yaml_spec.rb
index bae98f9bc35..f63aacecce6 100644
--- a/spec/lib/gitlab/config/loader/multi_doc_yaml_spec.rb
+++ b/spec/lib/gitlab/config/loader/multi_doc_yaml_spec.rb
@@ -2,26 +2,121 @@
require 'spec_helper'
-RSpec.describe Gitlab::Config::Loader::MultiDocYaml, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Config::Loader::MultiDocYaml, feature_category: :pipeline_composition do
let(:loader) { described_class.new(yml, max_documents: 2) }
describe '#load!' do
- let(:yml) do
- <<~YAML
- spec:
- inputs:
- test_input:
- ---
- test_job:
- script: echo "$[[ inputs.test_input ]]"
- YAML
+ context 'when a simple single delimiter is being used' do
+ let(:yml) do
+ <<~YAML
+ spec:
+ inputs:
+ env:
+ ---
+ test:
+ script: echo "$[[ inputs.env ]]"
+ YAML
+ end
+
+ it 'returns the loaded YAML with all keys as symbols' do
+ expect(loader.load!).to contain_exactly(
+ { spec: { inputs: { env: nil } } },
+ { test: { script: 'echo "$[[ inputs.env ]]"' } }
+ )
+ end
+ end
+
+ context 'when the delimiter has a trailing configuration' do
+ let(:yml) do
+ <<~YAML
+ spec:
+ inputs:
+ test_input:
+ --- !test/content
+ test_job:
+ script: echo "$[[ inputs.test_input ]]"
+ YAML
+ end
+
+ it 'returns the loaded YAML with all keys as symbols' do
+ expect(loader.load!).to contain_exactly(
+ { spec: { inputs: { test_input: nil } } },
+ { test_job: { script: 'echo "$[[ inputs.test_input ]]"' } }
+ )
+ end
+ end
+
+ context 'when the YAML file has a leading delimiter' do
+ let(:yml) do
+ <<~YAML
+ ---
+ spec:
+ inputs:
+ test_input:
+ --- !test/content
+ test_job:
+ script: echo "$[[ inputs.test_input ]]"
+ YAML
+ end
+
+ it 'returns the loaded YAML with all keys as symbols' do
+ expect(loader.load!).to contain_exactly(
+ { spec: { inputs: { test_input: nil } } },
+ { test_job: { script: 'echo "$[[ inputs.test_input ]]"' } }
+ )
+ end
+ end
+
+ context 'when the delimiter is followed by content on the same line' do
+ let(:yml) do
+ <<~YAML
+ --- a: 1
+ --- b: 2
+ YAML
+ end
+
+ it 'loads the content as part of the document' do
+ expect(loader.load!).to contain_exactly({ a: 1 }, { b: 2 })
+ end
end
- it 'returns the loaded YAML with all keys as symbols' do
- expect(loader.load!).to eq([
- { spec: { inputs: { test_input: nil } } },
- { test_job: { script: 'echo "$[[ inputs.test_input ]]"' } }
- ])
+ context 'when the delimiter does not have trailing whitespace' do
+ let(:yml) do
+ <<~YAML
+ --- a: 1
+ ---b: 2
+ YAML
+ end
+
+ it 'is not a valid delimiter' do
+ expect(loader.load!).to contain_exactly({ :'---b' => 2, a: 1 }) # rubocop:disable Style/HashSyntax
+ end
+ end
+
+ context 'when the YAML file has whitespace preceding the content' do
+ let(:yml) do
+ <<-EOYML
+ variables:
+ SUPPORTED: "parsed"
+
+ workflow:
+ rules:
+ - if: $VAR == "value"
+
+ hello:
+ script: echo world
+ EOYML
+ end
+
+ it 'loads everything correctly' do
+ expect(loader.load!).to contain_exactly(
+ {
+ variables: { SUPPORTED: 'parsed' },
+ workflow: { rules: [{ if: '$VAR == "value"' }] },
+ hello: { script: 'echo world' }
+ }
+ )
+ end
end
context 'when the YAML file is empty' do
@@ -32,67 +127,68 @@ RSpec.describe Gitlab::Config::Loader::MultiDocYaml, feature_category: :pipeline
end
end
- context 'when the parsed YAML is too big' do
+ context 'when there are more than the maximum number of documents' do
let(:yml) do
<<~YAML
- a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
- b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
- c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
- d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
- e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
- f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
- g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
- h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
- i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
- ---
- a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
- b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
- c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
- d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
- e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
- f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
- g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
- h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
- i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
+ --- a: 1
+ --- b: 2
+ --- c: 3
+ --- d: 4
YAML
end
- it 'raises a DataTooLargeError' do
- expect { loader.load! }.to raise_error(described_class::DataTooLargeError, 'The parsed YAML is too big')
+ it 'stops splitting documents after the maximum number' do
+ expect(loader.load!).to contain_exactly({ a: 1 }, { b: 2 })
end
end
+ end
+
+ describe '#load_raw!' do
+ let(:yml) do
+ <<~YAML
+ spec:
+ inputs:
+ test_input:
+ --- !test/content
+ test_job:
+ script: echo "$[[ inputs.test_input ]]"
+ YAML
+ end
+
+ it 'returns the loaded YAML with all keys as strings' do
+ expect(loader.load_raw!).to contain_exactly(
+ { 'spec' => { 'inputs' => { 'test_input' => nil } } },
+ { 'test_job' => { 'script' => 'echo "$[[ inputs.test_input ]]"' } }
+ )
+ end
+ end
- context 'when a document is not a hash' do
+ describe '#valid?' do
+ context 'when a document is invalid' do
let(:yml) do
<<~YAML
- not_a_hash
+ a: b
---
- test_job:
- script: echo "$[[ inputs.test_input ]]"
+ c
YAML
end
- it 'raises a NotHashError' do
- expect { loader.load! }.to raise_error(described_class::NotHashError, 'Invalid configuration format')
+ it 'returns false' do
+ expect(loader).not_to be_valid
end
end
- context 'when there are too many documents' do
+ context 'when the number of documents is below the maximum and all documents are valid' do
let(:yml) do
<<~YAML
a: b
---
c: d
- ---
- e: f
YAML
end
- it 'raises a TooManyDocumentsError' do
- expect { loader.load! }.to raise_error(
- described_class::TooManyDocumentsError,
- 'The parsed YAML has too many documents'
- )
+ it 'returns true' do
+ expect(loader).to be_valid
end
end
end
diff --git a/spec/lib/gitlab/config/loader/yaml_spec.rb b/spec/lib/gitlab/config/loader/yaml_spec.rb
index 346424d1681..bba66f33718 100644
--- a/spec/lib/gitlab/config/loader/yaml_spec.rb
+++ b/spec/lib/gitlab/config/loader/yaml_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Config::Loader::Yaml, feature_category: :pipeline_authoring do
+RSpec.describe Gitlab::Config::Loader::Yaml, feature_category: :pipeline_composition do
let(:loader) { described_class.new(yml) }
let(:yml) do
@@ -182,4 +182,30 @@ RSpec.describe Gitlab::Config::Loader::Yaml, feature_category: :pipeline_authori
)
end
end
+
+ describe '#blank?' do
+ context 'when the loaded YAML is empty' do
+ let(:yml) do
+ <<~YAML
+ # only comments here
+ YAML
+ end
+
+ it 'returns true' do
+ expect(loader).to be_blank
+ end
+ end
+
+ context 'when the loaded YAML has content' do
+ let(:yml) do
+ <<~YAML
+ test: value
+ YAML
+ end
+
+ it 'returns false' do
+ expect(loader).not_to be_blank
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/console_spec.rb b/spec/lib/gitlab/console_spec.rb
index f043433b4c5..5723a4421f6 100644
--- a/spec/lib/gitlab/console_spec.rb
+++ b/spec/lib/gitlab/console_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
-RSpec.describe Gitlab::Console do
+RSpec.describe Gitlab::Console, feature_category: :application_instrumentation do
describe '.welcome!' do
context 'when running in the Rails console' do
before do
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 f298890623f..ffb651fe23c 100644
--- a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
+++ b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
@@ -102,11 +102,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
end
describe 'Zuora directives' do
- context 'when is Gitlab.com?' do
- before do
- allow(::Gitlab).to receive(:com?).and_return(true)
- end
-
+ context 'when on SaaS', :saas do
it 'adds Zuora host to CSP' do
expect(directives['frame_src']).to include('https://*.zuora.com/apps/PublicHostedPageLite.do')
end
@@ -182,6 +178,53 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
end
end
+ context 'when KAS is configured' do
+ before do
+ stub_config_setting(host: 'gitlab.example.com')
+ allow(::Gitlab::Kas).to receive(:enabled?).and_return true
+ end
+
+ context 'when user access feature flag is disabled' do
+ before do
+ stub_feature_flags(kas_user_access: false)
+ end
+
+ it 'does not add KAS url to CSP' do
+ expect(directives['connect_src']).not_to eq("'self' ws://gitlab.example.com #{::Gitlab::Kas.tunnel_url}")
+ end
+ end
+
+ context 'when user access feature flag is enabled' do
+ before do
+ stub_feature_flags(kas_user_access: true)
+ end
+
+ context 'when KAS is on same domain as rails' do
+ let_it_be(:kas_tunnel_url) { "ws://gitlab.example.com/-/k8s-proxy/" }
+
+ before do
+ allow(::Gitlab::Kas).to receive(:tunnel_url).and_return(kas_tunnel_url)
+ end
+
+ it 'does not add KAS url to CSP' do
+ expect(directives['connect_src']).not_to eq("'self' ws://gitlab.example.com #{::Gitlab::Kas.tunnel_url}")
+ end
+ end
+
+ context 'when KAS is on subdomain' do
+ let_it_be(:kas_tunnel_url) { "ws://kas.gitlab.example.com/k8s-proxy/" }
+
+ before do
+ allow(::Gitlab::Kas).to receive(:tunnel_url).and_return(kas_tunnel_url)
+ end
+
+ it 'does add KAS url to CSP' do
+ expect(directives['connect_src']).to eq("'self' ws://gitlab.example.com #{kas_tunnel_url}")
+ end
+ end
+ end
+ end
+
context 'when CUSTOMER_PORTAL_URL is set' do
let(:customer_portal_url) { 'https://customers.example.com' }
diff --git a/spec/lib/gitlab/database/async_constraints/migration_helpers_spec.rb b/spec/lib/gitlab/database/async_constraints/migration_helpers_spec.rb
new file mode 100644
index 00000000000..4dd510499ab
--- /dev/null
+++ b/spec/lib/gitlab/database/async_constraints/migration_helpers_spec.rb
@@ -0,0 +1,288 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::AsyncConstraints::MigrationHelpers, feature_category: :database do
+ let(:migration) { Gitlab::Database::Migration[2.1].new }
+ let(:connection) { ApplicationRecord.connection }
+ let(:constraint_model) { Gitlab::Database::AsyncConstraints::PostgresAsyncConstraintValidation }
+ let(:table_name) { '_test_async_fks' }
+ let(:column_name) { 'parent_id' }
+ let(:fk_name) { nil }
+
+ context 'with async FK validation on regular tables' do
+ before do
+ allow(migration).to receive(:puts)
+ allow(migration.connection).to receive(:transaction_open?).and_return(false)
+
+ connection.create_table(table_name) do |t|
+ t.integer column_name
+ end
+
+ migration.add_concurrent_foreign_key(
+ table_name, table_name,
+ column: column_name, validate: false, name: fk_name)
+ end
+
+ describe '#prepare_async_foreign_key_validation' do
+ it 'creates the record for the async FK validation' do
+ expect do
+ migration.prepare_async_foreign_key_validation(table_name, column_name)
+ end.to change { constraint_model.where(table_name: table_name).count }.by(1)
+
+ record = constraint_model.find_by(table_name: table_name)
+
+ expect(record.name).to start_with('fk_')
+ expect(record).to be_foreign_key
+ end
+
+ context 'when an explicit name is given' do
+ let(:fk_name) { 'my_fk_name' }
+
+ it 'creates the record with the given name' do
+ expect do
+ migration.prepare_async_foreign_key_validation(table_name, name: fk_name)
+ end.to change { constraint_model.where(name: fk_name).count }.by(1)
+
+ record = constraint_model.find_by(name: fk_name)
+
+ expect(record.table_name).to eq(table_name)
+ expect(record).to be_foreign_key
+ end
+ end
+
+ context 'when the FK does not exist' do
+ it 'returns an error' do
+ expect do
+ migration.prepare_async_foreign_key_validation(table_name, name: 'no_fk')
+ end.to raise_error RuntimeError, /Could not find foreign key "no_fk" on table "_test_async_fks"/
+ end
+ end
+
+ context 'when the record already exists' do
+ let(:fk_name) { 'my_fk_name' }
+
+ it 'does attempt to create the record' do
+ create(:postgres_async_constraint_validation, table_name: table_name, name: fk_name)
+
+ expect do
+ migration.prepare_async_foreign_key_validation(table_name, name: fk_name)
+ end.not_to change { constraint_model.where(name: fk_name).count }
+ end
+ end
+
+ context 'when the async FK validation table does not exist' do
+ it 'does not raise an error' do
+ connection.drop_table(constraint_model.table_name)
+
+ expect(constraint_model).not_to receive(:safe_find_or_create_by!)
+
+ expect { migration.prepare_async_foreign_key_validation(table_name, column_name) }.not_to raise_error
+ end
+ end
+ end
+
+ describe '#unprepare_async_foreign_key_validation' do
+ context 'with foreign keys' do
+ before do
+ migration.prepare_async_foreign_key_validation(table_name, column_name, name: fk_name)
+ end
+
+ it 'destroys the record' do
+ expect do
+ migration.unprepare_async_foreign_key_validation(table_name, column_name)
+ end.to change { constraint_model.where(table_name: table_name).count }.by(-1)
+ end
+
+ context 'when an explicit name is given' do
+ let(:fk_name) { 'my_test_async_fk' }
+
+ it 'destroys the record' do
+ expect do
+ migration.unprepare_async_foreign_key_validation(table_name, name: fk_name)
+ end.to change { constraint_model.where(name: fk_name).count }.by(-1)
+ end
+ end
+
+ context 'when the async fk validation table does not exist' do
+ it 'does not raise an error' do
+ connection.drop_table(constraint_model.table_name)
+
+ expect(constraint_model).not_to receive(:find_by)
+
+ expect { migration.unprepare_async_foreign_key_validation(table_name, column_name) }.not_to raise_error
+ end
+ end
+ end
+
+ context 'with other types of constraints' do
+ let(:name) { 'my_test_async_constraint' }
+ let(:constraint) { create(:postgres_async_constraint_validation, table_name: table_name, name: name) }
+
+ it 'does not destroy the record' do
+ constraint.update_column(:constraint_type, 99)
+
+ expect do
+ migration.unprepare_async_foreign_key_validation(table_name, name: name)
+ end.not_to change { constraint_model.where(name: name).count }
+
+ expect(constraint).to be_present
+ end
+ end
+ end
+ end
+
+ context 'with partitioned tables' do
+ let(:partition_schema) { 'gitlab_partitions_dynamic' }
+ let(:partition1_name) { "#{partition_schema}.#{table_name}_202001" }
+ let(:partition2_name) { "#{partition_schema}.#{table_name}_202002" }
+ let(:fk_name) { 'my_partitioned_fk_name' }
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE #{table_name} (
+ id serial NOT NULL,
+ #{column_name} int NOT NULL,
+ created_at timestamptz NOT NULL,
+ PRIMARY KEY (id, created_at)
+ ) PARTITION BY RANGE (created_at);
+
+ CREATE TABLE #{partition1_name} PARTITION OF #{table_name}
+ FOR VALUES FROM ('2020-01-01') TO ('2020-02-01');
+
+ CREATE TABLE #{partition2_name} PARTITION OF #{table_name}
+ FOR VALUES FROM ('2020-02-01') TO ('2020-03-01');
+ SQL
+ end
+
+ describe '#prepare_partitioned_async_foreign_key_validation' do
+ it 'delegates to prepare_async_foreign_key_validation for each partition' do
+ expect(migration)
+ .to receive(:prepare_async_foreign_key_validation)
+ .with(partition1_name, column_name, name: fk_name)
+
+ expect(migration)
+ .to receive(:prepare_async_foreign_key_validation)
+ .with(partition2_name, column_name, name: fk_name)
+
+ migration.prepare_partitioned_async_foreign_key_validation(table_name, column_name, name: fk_name)
+ end
+ end
+
+ describe '#unprepare_partitioned_async_foreign_key_validation' do
+ it 'delegates to unprepare_async_foreign_key_validation for each partition' do
+ expect(migration)
+ .to receive(:unprepare_async_foreign_key_validation)
+ .with(partition1_name, column_name, name: fk_name)
+
+ expect(migration)
+ .to receive(:unprepare_async_foreign_key_validation)
+ .with(partition2_name, column_name, name: fk_name)
+
+ migration.unprepare_partitioned_async_foreign_key_validation(table_name, column_name, name: fk_name)
+ end
+ end
+ end
+
+ context 'with async check constraint validations' do
+ let(:table_name) { '_test_async_check_constraints' }
+ let(:check_name) { 'partitioning_constraint' }
+
+ before do
+ allow(migration).to receive(:puts)
+ allow(migration.connection).to receive(:transaction_open?).and_return(false)
+
+ connection.create_table(table_name) do |t|
+ t.integer column_name
+ end
+
+ migration.add_check_constraint(
+ table_name, "#{column_name} = 1",
+ check_name, validate: false)
+ end
+
+ describe '#prepare_async_check_constraint_validation' do
+ it 'creates the record for async validation' do
+ expect do
+ migration.prepare_async_check_constraint_validation(table_name, name: check_name)
+ end.to change { constraint_model.where(name: check_name).count }.by(1)
+
+ record = constraint_model.find_by(name: check_name)
+
+ expect(record.table_name).to eq(table_name)
+ expect(record).to be_check_constraint
+ end
+
+ context 'when the check constraint does not exist' do
+ it 'returns an error' do
+ expect do
+ migration.prepare_async_check_constraint_validation(table_name, name: 'missing')
+ end.to raise_error RuntimeError, /Could not find check constraint "missing" on table "#{table_name}"/
+ end
+ end
+
+ context 'when the record already exists' do
+ it 'does attempt to create the record' do
+ create(:postgres_async_constraint_validation,
+ table_name: table_name,
+ name: check_name,
+ constraint_type: :check_constraint)
+
+ expect do
+ migration.prepare_async_check_constraint_validation(table_name, name: check_name)
+ end.not_to change { constraint_model.where(name: check_name).count }
+ end
+ end
+
+ context 'when the async validation table does not exist' do
+ it 'does not raise an error' do
+ connection.drop_table(constraint_model.table_name)
+
+ expect(constraint_model).not_to receive(:safe_find_or_create_by!)
+
+ expect { migration.prepare_async_check_constraint_validation(table_name, name: check_name) }
+ .not_to raise_error
+ end
+ end
+ end
+
+ describe '#unprepare_async_check_constraint_validation' do
+ context 'with check constraints' do
+ before do
+ migration.prepare_async_check_constraint_validation(table_name, name: check_name)
+ end
+
+ it 'destroys the record' do
+ expect do
+ migration.unprepare_async_check_constraint_validation(table_name, name: check_name)
+ end.to change { constraint_model.where(name: check_name).count }.by(-1)
+ end
+
+ context 'when the async validation table does not exist' do
+ it 'does not raise an error' do
+ connection.drop_table(constraint_model.table_name)
+
+ expect(constraint_model).not_to receive(:find_by)
+
+ expect { migration.unprepare_async_check_constraint_validation(table_name, name: check_name) }
+ .not_to raise_error
+ end
+ end
+ end
+
+ context 'with other types of constraints' do
+ let(:constraint) { create(:postgres_async_constraint_validation, table_name: table_name, name: check_name) }
+
+ it 'does not destroy the record' do
+ constraint.update_column(:constraint_type, 99)
+
+ expect do
+ migration.unprepare_async_check_constraint_validation(table_name, name: check_name)
+ end.not_to change { constraint_model.where(name: check_name).count }
+
+ expect(constraint).to be_present
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/async_constraints/postgres_async_constraint_validation_spec.rb b/spec/lib/gitlab/database/async_constraints/postgres_async_constraint_validation_spec.rb
new file mode 100644
index 00000000000..52fbf6d2f9b
--- /dev/null
+++ b/spec/lib/gitlab/database/async_constraints/postgres_async_constraint_validation_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::AsyncConstraints::PostgresAsyncConstraintValidation, type: :model,
+ feature_category: :database do
+ it { is_expected.to be_a Gitlab::Database::SharedModel }
+
+ describe 'validations' do
+ let_it_be(:constraint_validation) { create(:postgres_async_constraint_validation) }
+ let(:identifier_limit) { described_class::MAX_IDENTIFIER_LENGTH }
+ let(:last_error_limit) { described_class::MAX_LAST_ERROR_LENGTH }
+
+ subject { constraint_validation }
+
+ it { is_expected.to validate_presence_of(:name) }
+ it { is_expected.to validate_uniqueness_of(:name).scoped_to(:table_name) }
+ it { is_expected.to validate_length_of(:name).is_at_most(identifier_limit) }
+ it { is_expected.to validate_presence_of(:table_name) }
+ it { is_expected.to validate_length_of(:table_name).is_at_most(identifier_limit) }
+ it { is_expected.to validate_length_of(:last_error).is_at_most(last_error_limit) }
+ end
+
+ describe 'scopes' do
+ let!(:failed_validation) { create(:postgres_async_constraint_validation, attempts: 1) }
+ let!(:new_validation) { create(:postgres_async_constraint_validation) }
+
+ describe '.ordered' do
+ subject { described_class.ordered }
+
+ it { is_expected.to eq([new_validation, failed_validation]) }
+ end
+
+ describe '.foreign_key_type' do
+ before do
+ new_validation.update_column(:constraint_type, 99)
+ end
+
+ subject { described_class.foreign_key_type }
+
+ it { is_expected.to eq([failed_validation]) }
+
+ it 'does not apply the filter if the column is not present' do
+ expect(described_class)
+ .to receive(:constraint_type_exists?)
+ .and_return(false)
+
+ is_expected.to match_array([failed_validation, new_validation])
+ end
+ end
+
+ describe '.check_constraint_type' do
+ before do
+ new_validation.update!(constraint_type: :check_constraint)
+ end
+
+ subject { described_class.check_constraint_type }
+
+ it { is_expected.to eq([new_validation]) }
+ end
+ end
+
+ describe '.table_available?' do
+ subject { described_class.table_available? }
+
+ it { is_expected.to be_truthy }
+
+ context 'when the table does not exist' do
+ before do
+ described_class
+ .connection
+ .drop_table(described_class.table_name)
+ end
+
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ describe '.constraint_type_exists?' do
+ it { expect(described_class.constraint_type_exists?).to be_truthy }
+
+ it 'always asks the database' do
+ control = ActiveRecord::QueryRecorder.new(skip_schema_queries: false) do
+ described_class.constraint_type_exists?
+ end
+
+ expect(control.count).to be >= 1
+ expect { described_class.constraint_type_exists? }.to issue_same_number_of_queries_as(control)
+ end
+ end
+
+ describe '#handle_exception!' do
+ let_it_be_with_reload(:constraint_validation) { create(:postgres_async_constraint_validation) }
+
+ let(:error) { instance_double(StandardError, message: 'Oups', backtrace: %w[this that]) }
+
+ subject { constraint_validation.handle_exception!(error) }
+
+ it 'increases the attempts number' do
+ expect { subject }.to change { constraint_validation.reload.attempts }.by(1)
+ end
+
+ it 'saves error details' do
+ subject
+
+ expect(constraint_validation.reload.last_error).to eq("Oups\nthis\nthat")
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/async_constraints/validators/check_constraint_spec.rb b/spec/lib/gitlab/database/async_constraints/validators/check_constraint_spec.rb
new file mode 100644
index 00000000000..7622b39feb1
--- /dev/null
+++ b/spec/lib/gitlab/database/async_constraints/validators/check_constraint_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::AsyncConstraints::Validators::CheckConstraint, feature_category: :database do
+ it_behaves_like 'async constraints validation' do
+ let(:constraint_type) { :check_constraint }
+
+ before do
+ connection.create_table(table_name) do |t|
+ t.integer :parent_id
+ end
+
+ connection.execute(<<~SQL.squish)
+ ALTER TABLE #{table_name} ADD CONSTRAINT #{constraint_name}
+ CHECK ( parent_id = 101 ) NOT VALID;
+ SQL
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/async_constraints/validators/foreign_key_spec.rb b/spec/lib/gitlab/database/async_constraints/validators/foreign_key_spec.rb
new file mode 100644
index 00000000000..0e345e0e9ae
--- /dev/null
+++ b/spec/lib/gitlab/database/async_constraints/validators/foreign_key_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::AsyncConstraints::Validators::ForeignKey, feature_category: :database do
+ it_behaves_like 'async constraints validation' do
+ let(:constraint_type) { :foreign_key }
+
+ before do
+ connection.create_table(table_name) do |t|
+ t.references :parent, foreign_key: { to_table: table_name, validate: false, name: constraint_name }
+ end
+ end
+
+ context 'with fully qualified table names' do
+ let(:validation) do
+ create(:postgres_async_constraint_validation,
+ table_name: "public.#{table_name}",
+ name: constraint_name,
+ constraint_type: constraint_type
+ )
+ end
+
+ it 'validates the constraint' do
+ allow(connection).to receive(:execute).and_call_original
+
+ expect(connection).to receive(:execute)
+ .with(/ALTER TABLE "public"."#{table_name}" VALIDATE CONSTRAINT "#{constraint_name}";/)
+ .ordered.and_call_original
+
+ subject.perform
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/async_constraints/validators_spec.rb b/spec/lib/gitlab/database/async_constraints/validators_spec.rb
new file mode 100644
index 00000000000..e903b79dd1b
--- /dev/null
+++ b/spec/lib/gitlab/database/async_constraints/validators_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::AsyncConstraints::Validators, feature_category: :database do
+ describe '.for' do
+ subject { described_class.for(record) }
+
+ context 'with foreign keys validations' do
+ let(:record) { build(:postgres_async_constraint_validation, :foreign_key) }
+
+ it { is_expected.to be_a(described_class::ForeignKey) }
+ end
+
+ context 'with check constraint validations' do
+ let(:record) { build(:postgres_async_constraint_validation, :check_constraint) }
+
+ it { is_expected.to be_a(described_class::CheckConstraint) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/async_constraints_spec.rb b/spec/lib/gitlab/database/async_constraints_spec.rb
new file mode 100644
index 00000000000..e5cf782485f
--- /dev/null
+++ b/spec/lib/gitlab/database/async_constraints_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::AsyncConstraints, feature_category: :database do
+ describe '.validate_pending_entries!' do
+ subject { described_class.validate_pending_entries! }
+
+ let!(:fk_validation) do
+ create(:postgres_async_constraint_validation, :foreign_key, attempts: 2)
+ end
+
+ let(:check_validation) do
+ create(:postgres_async_constraint_validation, :check_constraint, attempts: 1)
+ end
+
+ it 'executes pending validations' do
+ expect_next_instance_of(described_class::Validators::ForeignKey, fk_validation) do |validator|
+ expect(validator).to receive(:perform)
+ end
+
+ expect_next_instance_of(described_class::Validators::CheckConstraint, check_validation) do |validator|
+ expect(validator).to receive(:perform)
+ end
+
+ subject
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/async_foreign_keys/foreign_key_validator_spec.rb b/spec/lib/gitlab/database/async_foreign_keys/foreign_key_validator_spec.rb
deleted file mode 100644
index 90137e259f5..00000000000
--- a/spec/lib/gitlab/database/async_foreign_keys/foreign_key_validator_spec.rb
+++ /dev/null
@@ -1,152 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::AsyncForeignKeys::ForeignKeyValidator, feature_category: :database do
- include ExclusiveLeaseHelpers
-
- describe '#perform' do
- let!(:lease) { stub_exclusive_lease(lease_key, :uuid, timeout: lease_timeout) }
- let(:lease_key) { "gitlab/database/asyncddl/actions/#{Gitlab::Database::PRIMARY_DATABASE_NAME}" }
- let(:lease_timeout) { described_class::TIMEOUT_PER_ACTION }
-
- let(:fk_model) { Gitlab::Database::AsyncForeignKeys::PostgresAsyncForeignKeyValidation }
- let(:table_name) { '_test_async_fks' }
- let(:fk_name) { 'fk_parent_id' }
- let(:validation) { create(:postgres_async_foreign_key_validation, table_name: table_name, name: fk_name) }
- let(:connection) { validation.connection }
-
- subject { described_class.new(validation) }
-
- before do
- connection.create_table(table_name) do |t|
- t.references :parent, foreign_key: { to_table: table_name, validate: false, name: fk_name }
- end
- end
-
- it 'validates the FK while controlling statement timeout' do
- allow(connection).to receive(:execute).and_call_original
- expect(connection).to receive(:execute)
- .with("SET statement_timeout TO '43200s'").ordered.and_call_original
- expect(connection).to receive(:execute)
- .with('ALTER TABLE "_test_async_fks" VALIDATE CONSTRAINT "fk_parent_id";').ordered.and_call_original
- expect(connection).to receive(:execute)
- .with("RESET statement_timeout").ordered.and_call_original
-
- subject.perform
- end
-
- context 'with fully qualified table names' do
- let(:validation) do
- create(:postgres_async_foreign_key_validation,
- table_name: "public.#{table_name}",
- name: fk_name
- )
- end
-
- it 'validates the FK' do
- allow(connection).to receive(:execute).and_call_original
-
- expect(connection).to receive(:execute)
- .with('ALTER TABLE "public"."_test_async_fks" VALIDATE CONSTRAINT "fk_parent_id";').ordered.and_call_original
-
- subject.perform
- end
- end
-
- it 'removes the FK validation record from table' do
- expect(validation).to receive(:destroy!).and_call_original
-
- expect { subject.perform }.to change { fk_model.count }.by(-1)
- end
-
- it 'skips logic if not able to acquire exclusive lease' do
- expect(lease).to receive(:try_obtain).ordered.and_return(false)
- expect(connection).not_to receive(:execute).with(/ALTER TABLE/)
- expect(validation).not_to receive(:destroy!)
-
- expect { subject.perform }.not_to change { fk_model.count }
- end
-
- it 'logs messages around execution' do
- allow(Gitlab::AppLogger).to receive(:info).and_call_original
-
- subject.perform
-
- expect(Gitlab::AppLogger)
- .to have_received(:info)
- .with(a_hash_including(message: 'Starting to validate foreign key'))
-
- expect(Gitlab::AppLogger)
- .to have_received(:info)
- .with(a_hash_including(message: 'Finished validating foreign key'))
- end
-
- context 'when the FK does not exist' do
- before do
- connection.create_table(table_name, force: true)
- end
-
- it 'skips validation and removes the record' do
- expect(connection).not_to receive(:execute).with(/ALTER TABLE/)
-
- expect { subject.perform }.to change { fk_model.count }.by(-1)
- end
-
- it 'logs an appropriate message' do
- expected_message = "Skipping #{fk_name} validation since it does not exist. The queuing entry will be deleted"
-
- allow(Gitlab::AppLogger).to receive(:info).and_call_original
-
- subject.perform
-
- expect(Gitlab::AppLogger)
- .to have_received(:info)
- .with(a_hash_including(message: expected_message))
- end
- end
-
- context 'with error handling' do
- before do
- allow(connection).to receive(:execute).and_call_original
-
- allow(connection).to receive(:execute)
- .with('ALTER TABLE "_test_async_fks" VALIDATE CONSTRAINT "fk_parent_id";')
- .and_raise(ActiveRecord::StatementInvalid)
- end
-
- context 'on production' do
- before do
- allow(Gitlab::ErrorTracking).to receive(:should_raise_for_dev?).and_return(false)
- end
-
- it 'increases execution attempts' do
- expect { subject.perform }.to change { validation.attempts }.by(1)
-
- expect(validation.last_error).to be_present
- expect(validation).not_to be_destroyed
- end
-
- it 'logs an error message including the fk_name' do
- expect(Gitlab::AppLogger)
- .to receive(:error)
- .with(a_hash_including(:message, :fk_name))
- .and_call_original
-
- subject.perform
- end
- end
-
- context 'on development' do
- it 'also raises errors' do
- expect { subject.perform }
- .to raise_error(ActiveRecord::StatementInvalid)
- .and change { validation.attempts }.by(1)
-
- expect(validation.last_error).to be_present
- expect(validation).not_to be_destroyed
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/database/async_foreign_keys/migration_helpers_spec.rb b/spec/lib/gitlab/database/async_foreign_keys/migration_helpers_spec.rb
deleted file mode 100644
index 0bd0e8045ff..00000000000
--- a/spec/lib/gitlab/database/async_foreign_keys/migration_helpers_spec.rb
+++ /dev/null
@@ -1,167 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::AsyncForeignKeys::MigrationHelpers, feature_category: :database do
- let(:migration) { Gitlab::Database::Migration[2.1].new }
- let(:connection) { ApplicationRecord.connection }
- let(:fk_model) { Gitlab::Database::AsyncForeignKeys::PostgresAsyncForeignKeyValidation }
- let(:table_name) { '_test_async_fks' }
- let(:column_name) { 'parent_id' }
- let(:fk_name) { nil }
-
- context 'with regular tables' do
- before do
- allow(migration).to receive(:puts)
- allow(migration.connection).to receive(:transaction_open?).and_return(false)
-
- connection.create_table(table_name) do |t|
- t.integer column_name
- end
-
- migration.add_concurrent_foreign_key(
- table_name, table_name,
- column: column_name, validate: false, name: fk_name)
- end
-
- describe '#prepare_async_foreign_key_validation' do
- it 'creates the record for the async FK validation' do
- expect do
- migration.prepare_async_foreign_key_validation(table_name, column_name)
- end.to change { fk_model.where(table_name: table_name).count }.by(1)
-
- record = fk_model.find_by(table_name: table_name)
-
- expect(record.name).to start_with('fk_')
- end
-
- context 'when an explicit name is given' do
- let(:fk_name) { 'my_fk_name' }
-
- it 'creates the record with the given name' do
- expect do
- migration.prepare_async_foreign_key_validation(table_name, name: fk_name)
- end.to change { fk_model.where(name: fk_name).count }.by(1)
-
- record = fk_model.find_by(name: fk_name)
-
- expect(record.table_name).to eq(table_name)
- end
- end
-
- context 'when the FK does not exist' do
- it 'returns an error' do
- expect do
- migration.prepare_async_foreign_key_validation(table_name, name: 'no_fk')
- end.to raise_error RuntimeError, /Could not find foreign key "no_fk" on table "_test_async_fks"/
- end
- end
-
- context 'when the record already exists' do
- let(:fk_name) { 'my_fk_name' }
-
- it 'does attempt to create the record' do
- create(:postgres_async_foreign_key_validation, table_name: table_name, name: fk_name)
-
- expect do
- migration.prepare_async_foreign_key_validation(table_name, name: fk_name)
- end.not_to change { fk_model.where(name: fk_name).count }
- end
- end
-
- context 'when the async FK validation table does not exist' do
- it 'does not raise an error' do
- connection.drop_table(:postgres_async_foreign_key_validations)
-
- expect(fk_model).not_to receive(:safe_find_or_create_by!)
-
- expect { migration.prepare_async_foreign_key_validation(table_name, column_name) }.not_to raise_error
- end
- end
- end
-
- describe '#unprepare_async_foreign_key_validation' do
- before do
- migration.prepare_async_foreign_key_validation(table_name, column_name, name: fk_name)
- end
-
- it 'destroys the record' do
- expect do
- migration.unprepare_async_foreign_key_validation(table_name, column_name)
- end.to change { fk_model.where(table_name: table_name).count }.by(-1)
- end
-
- context 'when an explicit name is given' do
- let(:fk_name) { 'my_test_async_fk' }
-
- it 'destroys the record' do
- expect do
- migration.unprepare_async_foreign_key_validation(table_name, name: fk_name)
- end.to change { fk_model.where(name: fk_name).count }.by(-1)
- end
- end
-
- context 'when the async fk validation table does not exist' do
- it 'does not raise an error' do
- connection.drop_table(:postgres_async_foreign_key_validations)
-
- expect(fk_model).not_to receive(:find_by)
-
- expect { migration.unprepare_async_foreign_key_validation(table_name, column_name) }.not_to raise_error
- end
- end
- end
- end
-
- context 'with partitioned tables' do
- let(:partition_schema) { 'gitlab_partitions_dynamic' }
- let(:partition1_name) { "#{partition_schema}.#{table_name}_202001" }
- let(:partition2_name) { "#{partition_schema}.#{table_name}_202002" }
- let(:fk_name) { 'my_partitioned_fk_name' }
-
- before do
- connection.execute(<<~SQL)
- CREATE TABLE #{table_name} (
- id serial NOT NULL,
- #{column_name} int NOT NULL,
- created_at timestamptz NOT NULL,
- PRIMARY KEY (id, created_at)
- ) PARTITION BY RANGE (created_at);
-
- CREATE TABLE #{partition1_name} PARTITION OF #{table_name}
- FOR VALUES FROM ('2020-01-01') TO ('2020-02-01');
-
- CREATE TABLE #{partition2_name} PARTITION OF #{table_name}
- FOR VALUES FROM ('2020-02-01') TO ('2020-03-01');
- SQL
- end
-
- describe '#prepare_partitioned_async_foreign_key_validation' do
- it 'delegates to prepare_async_foreign_key_validation for each partition' do
- expect(migration)
- .to receive(:prepare_async_foreign_key_validation)
- .with(partition1_name, column_name, name: fk_name)
-
- expect(migration)
- .to receive(:prepare_async_foreign_key_validation)
- .with(partition2_name, column_name, name: fk_name)
-
- migration.prepare_partitioned_async_foreign_key_validation(table_name, column_name, name: fk_name)
- end
- end
-
- describe '#unprepare_partitioned_async_foreign_key_validation' do
- it 'delegates to unprepare_async_foreign_key_validation for each partition' do
- expect(migration)
- .to receive(:unprepare_async_foreign_key_validation)
- .with(partition1_name, column_name, name: fk_name)
-
- expect(migration)
- .to receive(:unprepare_async_foreign_key_validation)
- .with(partition2_name, column_name, name: fk_name)
-
- migration.unprepare_partitioned_async_foreign_key_validation(table_name, column_name, name: fk_name)
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation_spec.rb b/spec/lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation_spec.rb
deleted file mode 100644
index ba201d93f52..00000000000
--- a/spec/lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::AsyncForeignKeys::PostgresAsyncForeignKeyValidation, type: :model,
- feature_category: :database do
- it { is_expected.to be_a Gitlab::Database::SharedModel }
-
- describe 'validations' do
- let_it_be(:fk_validation) { create(:postgres_async_foreign_key_validation) }
- let(:identifier_limit) { described_class::MAX_IDENTIFIER_LENGTH }
- let(:last_error_limit) { described_class::MAX_LAST_ERROR_LENGTH }
-
- subject { fk_validation }
-
- it { is_expected.to validate_presence_of(:name) }
- it { is_expected.to validate_uniqueness_of(:name) }
- it { is_expected.to validate_length_of(:name).is_at_most(identifier_limit) }
- it { is_expected.to validate_presence_of(:table_name) }
- it { is_expected.to validate_length_of(:table_name).is_at_most(identifier_limit) }
- it { is_expected.to validate_length_of(:last_error).is_at_most(last_error_limit) }
- end
-
- describe 'scopes' do
- let!(:failed_validation) { create(:postgres_async_foreign_key_validation, attempts: 1) }
- let!(:new_validation) { create(:postgres_async_foreign_key_validation) }
-
- describe '.ordered' do
- subject { described_class.ordered }
-
- it { is_expected.to eq([new_validation, failed_validation]) }
- end
- end
-
- describe '#handle_exception!' do
- let_it_be_with_reload(:fk_validation) { create(:postgres_async_foreign_key_validation) }
-
- let(:error) { instance_double(StandardError, message: 'Oups', backtrace: %w[this that]) }
-
- subject { fk_validation.handle_exception!(error) }
-
- it 'increases the attempts number' do
- expect { subject }.to change { fk_validation.reload.attempts }.by(1)
- end
-
- it 'saves error details' do
- subject
-
- expect(fk_validation.reload.last_error).to eq("Oups\nthis\nthat")
- end
- end
-end
diff --git a/spec/lib/gitlab/database/async_foreign_keys_spec.rb b/spec/lib/gitlab/database/async_foreign_keys_spec.rb
deleted file mode 100644
index f15eb364929..00000000000
--- a/spec/lib/gitlab/database/async_foreign_keys_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::AsyncForeignKeys, feature_category: :database do
- describe '.validate_pending_entries!' do
- subject { described_class.validate_pending_entries! }
-
- before do
- create_list(:postgres_async_foreign_key_validation, 3)
- end
-
- it 'takes 2 pending FK validations and executes them' do
- validations = described_class::PostgresAsyncForeignKeyValidation.ordered.limit(2).to_a
-
- expect_next_instances_of(described_class::ForeignKeyValidator, 2, validations) do |validator|
- expect(validator).to receive(:perform)
- end
-
- subject
- end
- end
-end
diff --git a/spec/lib/gitlab/database/background_migration/batch_optimizer_spec.rb b/spec/lib/gitlab/database/background_migration/batch_optimizer_spec.rb
index c367f4a4493..fb9b16d46d6 100644
--- a/spec/lib/gitlab/database/background_migration/batch_optimizer_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batch_optimizer_spec.rb
@@ -113,5 +113,14 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchOptimizer do
expect { subject }.to change { migration.reload.batch_size }.to(1_000)
end
end
+
+ context 'when migration max_batch_size is less than MIN_BATCH_SIZE' do
+ let(:migration_params) { { max_batch_size: 900 } }
+
+ it 'does not raise an error' do
+ mock_efficiency(0.7)
+ expect { subject }.not_to raise_error
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
index cc9f3d5b7f1..073a30e7839 100644
--- a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
@@ -184,6 +184,35 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
expect(transition_log.exception_message).to eq('RuntimeError')
end
end
+
+ context 'when job fails during sub batch processing' do
+ let(:args) { { error: ActiveRecord::StatementTimeout.new, from_sub_batch: true } }
+ let(:attempts) { 0 }
+ let(:failure) { job.failure!(**args) }
+ let(:job) do
+ create(:batched_background_migration_job, :running, batch_size: 20, sub_batch_size: 10, attempts: attempts)
+ end
+
+ context 'when sub batch size can be reduced in 25%' do
+ it { expect { failure }.to change { job.sub_batch_size }.to 7 }
+ end
+
+ context 'when retries exceeds 2 attempts' do
+ let(:attempts) { 3 }
+
+ before do
+ allow(job).to receive(:split_and_retry!)
+ end
+
+ it 'calls split_and_retry! once sub_batch_size cannot be decreased anymore' do
+ failure
+
+ expect(job).to have_received(:split_and_retry!).once
+ end
+
+ it { expect { failure }.not_to change { job.sub_batch_size } }
+ end
+ end
end
describe 'scopes' do
@@ -271,6 +300,24 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
end
end
+ describe '.extract_transition_options' do
+ let(:perform) { subject.class.extract_transition_options(args) }
+
+ where(:args, :expected_result) do
+ [
+ [[], []],
+ [[{ error: StandardError }], [StandardError, nil]],
+ [[{ error: StandardError, from_sub_batch: true }], [StandardError, true]]
+ ]
+ end
+
+ with_them do
+ it 'matches expected keys and result' do
+ expect(perform).to match_array(expected_result)
+ end
+ end
+ end
+
describe '#can_split?' do
subject { job.can_split?(exception) }
@@ -327,6 +374,48 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
end
end
+ describe '#can_reduce_sub_batch_size?' do
+ let(:attempts) { 0 }
+ let(:batch_size) { 10 }
+ let(:sub_batch_size) { 6 }
+ let(:feature_flag) { :reduce_sub_batch_size_on_timeouts }
+ let(:job) do
+ create(:batched_background_migration_job, attempts: attempts,
+ batch_size: batch_size, sub_batch_size: sub_batch_size)
+ end
+
+ where(:feature_flag_state, :within_boundaries, :outside_boundaries, :limit_reached) do
+ [
+ [true, true, false, false],
+ [false, false, false, false]
+ ]
+ end
+
+ with_them do
+ before do
+ stub_feature_flags(feature_flag => feature_flag_state)
+ end
+
+ context 'when the number of attempts is lower than the limit and batch size are within boundaries' do
+ let(:attempts) { 1 }
+
+ it { expect(job.can_reduce_sub_batch_size?).to be(within_boundaries) }
+ end
+
+ context 'when the number of attempts is lower than the limit and batch size are outside boundaries' do
+ let(:batch_size) { 1 }
+
+ it { expect(job.can_reduce_sub_batch_size?).to be(outside_boundaries) }
+ end
+
+ context 'when the number of attempts is greater than the limit and batch size are within boundaries' do
+ let(:attempts) { 3 }
+
+ it { expect(job.can_reduce_sub_batch_size?).to be(limit_reached) }
+ end
+ end
+ end
+
describe '#time_efficiency' do
subject { job.time_efficiency }
@@ -465,4 +554,80 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
end
end
end
+
+ describe '#reduce_sub_batch_size!' do
+ let(:migration_batch_size) { 20 }
+ let(:migration_sub_batch_size) { 10 }
+ let(:job_batch_size) { 20 }
+ let(:job_sub_batch_size) { 10 }
+ let(:status) { :failed }
+
+ let(:migration) do
+ create(:batched_background_migration, :active, batch_size: migration_batch_size,
+ sub_batch_size: migration_sub_batch_size)
+ end
+
+ let(:job) do
+ create(:batched_background_migration_job, status, sub_batch_size: job_sub_batch_size,
+ batch_size: job_batch_size, batched_migration: migration)
+ end
+
+ context 'when the job sub batch size can be reduced' do
+ let(:expected_sub_batch_size) { 7 }
+
+ it 'reduces sub batch size in 25%' do
+ expect { job.reduce_sub_batch_size! }.to change { job.sub_batch_size }.to(expected_sub_batch_size)
+ end
+
+ it 'log the changes' do
+ expect(Gitlab::AppLogger).to receive(:warn).with(
+ message: 'Sub batch size reduced due to timeout',
+ batched_job_id: job.id,
+ sub_batch_size: job_sub_batch_size,
+ reduced_sub_batch_size: expected_sub_batch_size,
+ attempts: job.attempts,
+ batched_migration_id: migration.id,
+ job_class_name: job.migration_job_class_name,
+ job_arguments: job.migration_job_arguments
+ )
+
+ job.reduce_sub_batch_size!
+ end
+ end
+
+ context 'when reduced sub_batch_size is greater than sub_batch' do
+ let(:job_batch_size) { 5 }
+
+ it "doesn't allow sub_batch_size to greater than sub_batch" do
+ expect { job.reduce_sub_batch_size! }.to change { job.sub_batch_size }.to 5
+ end
+ end
+
+ context 'when sub_batch_size is already 1' do
+ let(:job_sub_batch_size) { 1 }
+
+ it "updates sub_batch_size to it's minimum value" do
+ expect { job.reduce_sub_batch_size! }.not_to change { job.sub_batch_size }
+ end
+ end
+
+ context 'when job has not failed' do
+ let(:status) { :succeeded }
+ let(:error) { Gitlab::Database::BackgroundMigration::ReduceSubBatchSizeError }
+
+ it 'raises an exception' do
+ expect { job.reduce_sub_batch_size! }.to raise_error(error)
+ end
+ end
+
+ context 'when the amount to be reduced exceeds the threshold' do
+ let(:migration_batch_size) { 150 }
+ let(:migration_sub_batch_size) { 100 }
+ let(:job_sub_batch_size) { 30 }
+
+ it 'prevents sub batch size to be reduced' do
+ expect { job.reduce_sub_batch_size! }.not_to change { job.sub_batch_size }
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
index f3a292abbae..8d74d16f4e5 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, '
let(:connection) { Gitlab::Database.database_base_models[:main].connection }
let(:metrics_tracker) { instance_double('::Gitlab::Database::BackgroundMigration::PrometheusMetrics', track: nil) }
let(:job_class) { Class.new(Gitlab::BackgroundMigration::BatchedMigrationJob) }
+ let(:sub_batch_exception) { Gitlab::Database::BackgroundMigration::SubBatchTimeoutError }
let_it_be(:pause_ms) { 250 }
let_it_be(:active_migration) { create(:batched_background_migration, :active, job_arguments: [:id, :other_id]) }
@@ -39,7 +40,8 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, '
sub_batch_size: 1,
pause_ms: pause_ms,
job_arguments: active_migration.job_arguments,
- connection: connection)
+ connection: connection,
+ sub_batch_exception: sub_batch_exception)
.and_return(job_instance)
expect(job_instance).to receive(:perform).with(no_args)
@@ -119,12 +121,14 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, '
end
context 'when the migration job raises an error' do
- shared_examples 'an error is raised' do |error_class|
+ shared_examples 'an error is raised' do |error_class, cause|
+ let(:expected_to_raise) { cause || error_class }
+
it 'marks the tracking record as failed' do
expect(job_instance).to receive(:perform).with(no_args).and_raise(error_class)
freeze_time do
- expect { perform }.to raise_error(error_class)
+ expect { perform }.to raise_error(expected_to_raise)
reloaded_job_record = job_record.reload
@@ -137,13 +141,16 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, '
expect(job_instance).to receive(:perform).with(no_args).and_raise(error_class)
expect(metrics_tracker).to receive(:track).with(job_record)
- expect { perform }.to raise_error(error_class)
+ expect { perform }.to raise_error(expected_to_raise)
end
end
it_behaves_like 'an error is raised', RuntimeError.new('Something broke!')
it_behaves_like 'an error is raised', SignalException.new('SIGTERM')
it_behaves_like 'an error is raised', ActiveRecord::StatementTimeout.new('Timeout!')
+
+ error = StandardError.new
+ it_behaves_like('an error is raised', Gitlab::Database::BackgroundMigration::SubBatchTimeoutError.new(error), error)
end
context 'when the batched background migration does not inherit from BatchedMigrationJob' do
diff --git a/spec/lib/gitlab/database/gitlab_schema_spec.rb b/spec/lib/gitlab/database/gitlab_schema_spec.rb
index 28a087d5401..b187b29c270 100644
--- a/spec/lib/gitlab/database/gitlab_schema_spec.rb
+++ b/spec/lib/gitlab/database/gitlab_schema_spec.rb
@@ -16,19 +16,21 @@ RSpec.shared_examples 'validate schema data' do |tables_and_views|
end
end
-RSpec.describe Gitlab::Database::GitlabSchema do
+RSpec.describe Gitlab::Database::GitlabSchema, feature_category: :database do
shared_examples 'maps table name to table schema' do
using RSpec::Parameterized::TableSyntax
where(:name, :classification) do
- 'ci_builds' | :gitlab_ci
- 'my_schema.ci_builds' | :gitlab_ci
- 'information_schema.columns' | :gitlab_internal
- 'audit_events_part_5fc467ac26' | :gitlab_main
- '_test_gitlab_main_table' | :gitlab_main
- '_test_gitlab_ci_table' | :gitlab_ci
- '_test_my_table' | :gitlab_shared
- 'pg_attribute' | :gitlab_internal
+ 'ci_builds' | :gitlab_ci
+ 'my_schema.ci_builds' | :gitlab_ci
+ 'my_schema.ci_runner_machine_builds_100' | :gitlab_ci
+ 'my_schema._test_gitlab_main_table' | :gitlab_main
+ 'information_schema.columns' | :gitlab_internal
+ 'audit_events_part_5fc467ac26' | :gitlab_main
+ '_test_gitlab_main_table' | :gitlab_main
+ '_test_gitlab_ci_table' | :gitlab_ci
+ '_test_my_table' | :gitlab_shared
+ 'pg_attribute' | :gitlab_internal
end
with_them do
diff --git a/spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb b/spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb
new file mode 100644
index 00000000000..b1971977e7c
--- /dev/null
+++ b/spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::MigrationHelpers::ConvertToBigint, feature_category: :database do
+ describe 'com_or_dev_or_test_but_not_jh?' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:dot_com, :dev_or_test, :jh, :expectation) do
+ true | true | true | false
+ true | false | true | false
+ false | true | true | false
+ false | false | true | false
+ true | true | false | true
+ true | false | false | true
+ false | true | false | true
+ false | false | false | false
+ end
+
+ with_them do
+ it 'returns true for GitLab.com (but not JH), dev, or test' do
+ allow(Gitlab).to receive(:com?).and_return(dot_com)
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test)
+ allow(Gitlab).to receive(:jh?).and_return(jh)
+
+ migration = Class
+ .new
+ .include(Gitlab::Database::MigrationHelpers::ConvertToBigint)
+ .new
+
+ expect(migration.com_or_dev_or_test_but_not_jh?).to eq(expectation)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 9df23776be8..3f6528558b1 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::MigrationHelpers do
+RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database do
include Database::TableSchemaHelpers
include Database::TriggerHelpers
@@ -928,13 +928,13 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
it 'references the custom target columns when provided', :aggregate_failures do
expect(model).to receive(:with_lock_retries).and_yield
expect(model).to receive(:execute).with(
- "ALTER TABLE projects\n" \
- "ADD CONSTRAINT fk_multiple_columns\n" \
- "FOREIGN KEY \(partition_number, user_id\)\n" \
- "REFERENCES users \(partition_number, id\)\n" \
- "ON UPDATE CASCADE\n" \
- "ON DELETE CASCADE\n" \
- "NOT VALID;\n"
+ "ALTER TABLE projects " \
+ "ADD CONSTRAINT fk_multiple_columns " \
+ "FOREIGN KEY \(partition_number, user_id\) " \
+ "REFERENCES users \(partition_number, id\) " \
+ "ON UPDATE CASCADE " \
+ "ON DELETE CASCADE " \
+ "NOT VALID;"
)
model.add_concurrent_foreign_key(
@@ -979,6 +979,80 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
end
+
+ context 'when creating foreign key on a partitioned table' do
+ let(:source) { :_test_source_partitioned_table }
+ let(:dest) { :_test_dest_partitioned_table }
+ let(:args) { [source, dest] }
+ let(:options) { { column: [:partition_id, :owner_id], target_column: [:partition_id, :id] } }
+
+ before do
+ model.execute(<<~SQL)
+ CREATE TABLE public.#{source} (
+ id serial NOT NULL,
+ partition_id serial NOT NULL,
+ owner_id bigint NOT NULL,
+ PRIMARY KEY (id, partition_id)
+ ) PARTITION BY LIST(partition_id);
+
+ CREATE TABLE #{source}_1
+ PARTITION OF public.#{source}
+ FOR VALUES IN (1);
+
+ CREATE TABLE public.#{dest} (
+ id serial NOT NULL,
+ partition_id serial NOT NULL,
+ PRIMARY KEY (id, partition_id)
+ );
+ SQL
+ end
+
+ it 'creates the FK without using NOT VALID', :aggregate_failures do
+ allow(model).to receive(:execute).and_call_original
+
+ expect(model).to receive(:with_lock_retries).and_yield
+
+ expect(model).to receive(:execute).with(
+ "ALTER TABLE #{source} " \
+ "ADD CONSTRAINT fk_multiple_columns " \
+ "FOREIGN KEY \(partition_id, owner_id\) " \
+ "REFERENCES #{dest} \(partition_id, id\) " \
+ "ON UPDATE CASCADE ON DELETE CASCADE ;"
+ )
+
+ model.add_concurrent_foreign_key(
+ *args,
+ name: :fk_multiple_columns,
+ on_update: :cascade,
+ allow_partitioned: true,
+ **options
+ )
+ end
+
+ it 'raises an error if allow_partitioned is not set' do
+ expect(model).not_to receive(:with_lock_retries).and_yield
+ expect(model).not_to receive(:execute).with(/FOREIGN KEY/)
+
+ expect { model.add_concurrent_foreign_key(*args, **options) }
+ .to raise_error ArgumentError, /use add_concurrent_partitioned_foreign_key/
+ end
+
+ context 'when the reverse_lock_order flag is set' do
+ it 'explicitly locks the tables in target-source order', :aggregate_failures do
+ expect(model).to receive(:with_lock_retries).and_call_original
+ expect(model).to receive(:disable_statement_timeout).and_call_original
+ expect(model).to receive(:statement_timeout_disabled?).and_return(false)
+ expect(model).to receive(:execute).with(/SET statement_timeout TO/)
+ expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
+ expect(model).to receive(:execute).ordered.with(/RESET statement_timeout/)
+
+ expect(model).to receive(:execute).with("LOCK TABLE #{dest}, #{source} IN ACCESS EXCLUSIVE MODE")
+ expect(model).to receive(:execute).with(/REFERENCES #{dest} \(partition_id, id\)/)
+
+ model.add_concurrent_foreign_key(*args, reverse_lock_order: true, allow_partitioned: true, **options)
+ end
+ end
+ end
end
end
@@ -1049,6 +1123,8 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
describe '#foreign_key_exists?' do
let(:referenced_table_name) { '_test_gitlab_main_referenced' }
let(:referencing_table_name) { '_test_gitlab_main_referencing' }
+ let(:schema) { 'public' }
+ let(:identifier) { "#{schema}.#{referencing_table_name}" }
before do
model.connection.execute(<<~SQL)
@@ -1085,6 +1161,10 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
expect(model.foreign_key_exists?(referencing_table_name, target_table)).to be_truthy
end
+ it 'finds existing foreign_keys by identifier' do
+ expect(model.foreign_key_exists?(identifier, target_table)).to be_truthy
+ end
+
it 'compares by column name if given' do
expect(model.foreign_key_exists?(referencing_table_name, target_table, column: :user_id)).to be_falsey
end
@@ -2890,4 +2970,18 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
it { is_expected.to be_falsey }
end
end
+
+ describe "#table_partitioned?" do
+ subject { model.table_partitioned?(table_name) }
+
+ let(:table_name) { 'p_ci_builds_metadata' }
+
+ it { is_expected.to be_truthy }
+
+ context 'with a non-partitioned table' do
+ let(:table_name) { 'users' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb b/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
index 3e249b14f2e..f5ce207773f 100644
--- a/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
@@ -482,16 +482,46 @@ RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers d
.not_to raise_error
end
- it 'logs a warning when migration does not exist' do
- expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!)
+ context 'when specified migration does not exist' do
+ let(:lab_key) { 'DBLAB_ENVIRONMENT' }
- create(:batched_background_migration, :active, migration_attributes.merge(gitlab_schema: :gitlab_something_else))
+ context 'when DBLAB_ENVIRONMENT is not set' do
+ it 'logs a warning' do
+ stub_env(lab_key, nil)
+ expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!)
- expect(Gitlab::AppLogger).to receive(:warn)
- .with("Could not find batched background migration for the given configuration: #{configuration}")
+ create(:batched_background_migration, :active, migration_attributes.merge(gitlab_schema: :gitlab_something_else))
- expect { ensure_batched_background_migration_is_finished }
- .not_to raise_error
+ expect(Gitlab::AppLogger).to receive(:warn)
+ .with("Could not find batched background migration for the given configuration: #{configuration}")
+
+ expect { ensure_batched_background_migration_is_finished }
+ .not_to raise_error
+ end
+ end
+
+ context 'when DBLAB_ENVIRONMENT is set' do
+ it 'raises an error' do
+ stub_env(lab_key, 'foo')
+ expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!)
+
+ create(:batched_background_migration, :active, migration_attributes.merge(gitlab_schema: :gitlab_something_else))
+
+ expect { ensure_batched_background_migration_is_finished }
+ .to raise_error(Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers::NonExistentMigrationError)
+ end
+ end
+ end
+
+ context 'when within transaction' do
+ before do
+ allow(migration).to receive(:transaction_open?).and_return(true)
+ end
+
+ it 'does raise an exception' do
+ expect { ensure_batched_background_migration_is_finished }
+ .to raise_error /`ensure_batched_background_migration_is_finished` cannot be run inside a transaction./
+ end
end
it 'finalizes the migration' do
diff --git a/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb b/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
index 6848fc85aa1..07d913cf5cc 100644
--- a/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
@@ -23,43 +23,46 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
end
end
- describe '#check_constraint_exists?' do
+ describe '#check_constraint_exists?', :aggregate_failures do
before do
- ActiveRecord::Migration.connection.execute(
- 'ALTER TABLE projects ADD CONSTRAINT check_1 CHECK (char_length(path) <= 5) NOT VALID'
- )
-
- ActiveRecord::Migration.connection.execute(
- 'CREATE SCHEMA new_test_schema'
- )
-
- ActiveRecord::Migration.connection.execute(
- 'CREATE TABLE new_test_schema.projects (id integer, name character varying)'
- )
-
- ActiveRecord::Migration.connection.execute(
- 'ALTER TABLE new_test_schema.projects ADD CONSTRAINT check_2 CHECK (char_length(name) <= 5)'
- )
+ ActiveRecord::Migration.connection.execute(<<~SQL)
+ ALTER TABLE projects ADD CONSTRAINT check_1 CHECK (char_length(path) <= 5) NOT VALID;
+ CREATE SCHEMA new_test_schema;
+ CREATE TABLE new_test_schema.projects (id integer, name character varying);
+ ALTER TABLE new_test_schema.projects ADD CONSTRAINT check_2 CHECK (char_length(name) <= 5);
+ SQL
end
it 'returns true if a constraint exists' do
expect(model)
.to be_check_constraint_exists(:projects, 'check_1')
+
+ expect(described_class)
+ .to be_check_constraint_exists(:projects, 'check_1', connection: model.connection)
end
it 'returns false if a constraint does not exist' do
expect(model)
.not_to be_check_constraint_exists(:projects, 'this_does_not_exist')
+
+ expect(described_class)
+ .not_to be_check_constraint_exists(:projects, 'this_does_not_exist', connection: model.connection)
end
it 'returns false if a constraint with the same name exists in another table' do
expect(model)
.not_to be_check_constraint_exists(:users, 'check_1')
+
+ expect(described_class)
+ .not_to be_check_constraint_exists(:users, 'check_1', connection: model.connection)
end
it 'returns false if a constraint with the same name exists for the same table in another schema' do
expect(model)
.not_to be_check_constraint_exists(:projects, 'check_2')
+
+ expect(described_class)
+ .not_to be_check_constraint_exists(:projects, 'check_2', connection: model.connection)
end
end
diff --git a/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb b/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
index 57c5011590c..6bcefa455cf 100644
--- a/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
+++ b/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
@@ -48,6 +48,7 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
let(:result_dir) { Pathname.new(Dir.mktmpdir) }
let(:connection) { base_model.connection }
let(:table_name) { "_test_column_copying" }
+ let(:num_rows_in_table) { 1000 }
let(:from_id) { 0 }
after do
@@ -61,7 +62,7 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
data bigint default 0
);
- insert into #{table_name} (id) select i from generate_series(1, 1000) g(i);
+ insert into #{table_name} (id) select i from generate_series(1, #{num_rows_in_table}) g(i);
SQL
end
@@ -134,6 +135,24 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
expect(calls).not_to be_empty
end
+ it 'samples 1 job with a batch size higher than the table size' do
+ calls = []
+ define_background_migration(migration_name) do |*args|
+ travel 1.minute
+ calls << args
+ end
+
+ queue_migration(migration_name, table_name, :id,
+ job_interval: 5.minutes,
+ batch_size: num_rows_in_table * 2,
+ sub_batch_size: num_rows_in_table * 2)
+
+ described_class.new(result_dir: result_dir, connection: connection,
+ from_id: from_id).run_jobs(for_duration: 3.minutes)
+
+ expect(calls.size).to eq(1)
+ end
+
context 'with multiple jobs to run' do
let(:last_id) do
Gitlab::Database::SharedModel.using_connection(connection) do
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
new file mode 100644
index 00000000000..f415e892818
--- /dev/null
+++ b/spec/lib/gitlab/database/partitioning/ci_sliding_list_strategy_spec.rb
@@ -0,0 +1,178 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Partitioning::CiSlidingListStrategy, feature_category: :database do
+ let(:connection) { ActiveRecord::Base.connection }
+ let(:table_name) { :_test_gitlab_ci_partitioned_test }
+ let(:model) { class_double(ApplicationRecord, table_name: table_name, connection: connection) }
+ let(:next_partition_if) { nil }
+ let(:detach_partition_if) { nil }
+
+ subject(:strategy) do
+ described_class.new(model, :partition,
+ next_partition_if: next_partition_if,
+ detach_partition_if: detach_partition_if)
+ end
+
+ before do
+ next if table_name.to_s.starts_with?('p_')
+
+ connection.execute(<<~SQL)
+ create table #{table_name}
+ (
+ id serial not null,
+ partition_id bigint not null,
+ created_at timestamptz not null,
+ primary key (id, partition_id)
+ )
+ partition by list(partition_id);
+
+ create table #{table_name}_100
+ partition of #{table_name} for values in (100);
+
+ create table #{table_name}_101
+ partition of #{table_name} for values in (101);
+ SQL
+ end
+
+ describe '#current_partitions' do
+ it 'detects both partitions' do
+ expect(strategy.current_partitions).to eq(
+ [
+ Gitlab::Database::Partitioning::SingleNumericListPartition.new(
+ table_name, 100, partition_name: "#{table_name}_100"
+ ),
+ Gitlab::Database::Partitioning::SingleNumericListPartition.new(
+ table_name, 101, partition_name: "#{table_name}_101"
+ )
+ ])
+ end
+ end
+
+ describe '#validate_and_fix' do
+ it 'does not call change_column_default' do
+ expect(strategy.model.connection).not_to receive(:change_column_default)
+
+ strategy.validate_and_fix
+ end
+ end
+
+ describe '#active_partition' do
+ it 'is the partition with the largest value' do
+ expect(strategy.active_partition.value).to eq(101)
+ end
+ end
+
+ describe '#missing_partitions' do
+ context 'when next_partition_if returns true' do
+ let(:next_partition_if) { proc { true } }
+
+ it 'is a partition definition for the next partition in the series' do
+ extra = strategy.missing_partitions
+
+ expect(extra.length).to eq(1)
+ expect(extra.first.value).to eq(102)
+ end
+ end
+
+ context 'when next_partition_if returns false' do
+ let(:next_partition_if) { proc { false } }
+
+ it 'is empty' do
+ expect(strategy.missing_partitions).to be_empty
+ end
+ end
+
+ context 'when there are no partitions for the table' do
+ it 'returns a partition for value 1' do
+ connection.execute("drop table #{table_name}_100; drop table #{table_name}_101;")
+
+ missing_partitions = strategy.missing_partitions
+
+ expect(missing_partitions.size).to eq(1)
+ missing_partition = missing_partitions.first
+
+ expect(missing_partition.value).to eq(100)
+ end
+ end
+ end
+
+ describe '#extra_partitions' do
+ context 'when all partitions are true for detach_partition_if' do
+ let(:detach_partition_if) { ->(_p) { true } }
+
+ it { expect(strategy.extra_partitions).to be_empty }
+ end
+
+ context 'when all partitions are false for detach_partition_if' do
+ let(:detach_partition_if) { proc { false } }
+
+ it { expect(strategy.extra_partitions).to be_empty }
+ end
+ end
+
+ describe '#initial_partition' do
+ it 'starts with the value 100', :aggregate_failures do
+ initial_partition = strategy.initial_partition
+ expect(initial_partition.value).to eq(100)
+ expect(initial_partition.table).to eq(strategy.table_name)
+ expect(initial_partition.partition_name).to eq("#{strategy.table_name}_100")
+ end
+
+ context 'with routing tables' do
+ let(:table_name) { :p_test_gitlab_ci_partitioned_test }
+
+ it 'removes the prefix', :aggregate_failures do
+ initial_partition = strategy.initial_partition
+
+ expect(initial_partition.value).to eq(100)
+ expect(initial_partition.table).to eq(strategy.table_name)
+ expect(initial_partition.partition_name).to eq('test_gitlab_ci_partitioned_test_100')
+ end
+ end
+ end
+
+ describe '#next_partition' do
+ before do
+ allow(strategy)
+ .to receive(:active_partition)
+ .and_return(instance_double(Gitlab::Database::Partitioning::SingleNumericListPartition, value: 105))
+ end
+
+ it 'is one after the active partition', :aggregate_failures do
+ next_partition = strategy.next_partition
+
+ expect(next_partition.value).to eq(106)
+ expect(next_partition.table).to eq(strategy.table_name)
+ expect(next_partition.partition_name).to eq("#{strategy.table_name}_106")
+ end
+
+ context 'with routing tables' do
+ let(:table_name) { :p_test_gitlab_ci_partitioned_test }
+
+ it 'removes the prefix', :aggregate_failures do
+ next_partition = strategy.next_partition
+
+ expect(next_partition.value).to eq(106)
+ expect(next_partition.table).to eq(strategy.table_name)
+ expect(next_partition.partition_name).to eq('test_gitlab_ci_partitioned_test_106')
+ end
+ end
+ end
+
+ describe '#ensure_partitioning_column_ignored_or_readonly!' do
+ it 'does not raise when the column is not ignored' do
+ expect 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.not_to raise_error
+ 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 2212cb09888..ac54c307108 100644
--- a/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
sync_partitions
end
- context 'with eplicitly provided connection' do
+ context 'with explicitly provided connection' do
let(:connection) { Ci::ApplicationRecord.connection }
it 'uses the explicitly provided connection when any' do
@@ -59,6 +59,14 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
end
end
+ context 'when an ArgumentError occurs during partition management' do
+ it 'raises error' do
+ expect(partitioning_strategy).to receive(:missing_partitions).and_raise(ArgumentError)
+
+ expect { sync_partitions }.to raise_error(ArgumentError)
+ end
+ end
+
context 'when an error occurs during partition management' do
it 'does not raise an error' do
expect(partitioning_strategy).to receive(:missing_partitions).and_raise('this should never happen (tm)')
@@ -230,23 +238,20 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
expect(pending_drop.drop_after).to eq(Time.current + described_class::RETAIN_DETACHED_PARTITIONS_FOR)
end
- # Postgres 11 does not support foreign keys to partitioned tables
- if ApplicationRecord.database.version.to_f >= 12
- context 'when the model is the target of a foreign key' do
- before do
- connection.execute(<<~SQL)
+ context 'when the model is the target of a foreign key' do
+ before do
+ connection.execute(<<~SQL)
create unique index idx_for_fk ON #{partitioned_table_name}(created_at);
create table _test_gitlab_main_referencing_table (
id bigserial primary key not null,
referencing_created_at timestamptz references #{partitioned_table_name}(created_at)
);
- SQL
- end
+ SQL
+ end
- it 'does not detach partitions with a referenced foreign key' do
- expect { subject }.not_to change { find_partitions(my_model.table_name).size }
- end
+ it 'does not detach partitions with a referenced foreign key' do
+ expect { subject }.not_to change { find_partitions(my_model.table_name).size }
end
end
end
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers_spec.rb
index f0e34476cf2..d5f4afd7ba4 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers do
+RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers, feature_category: :database do
include Database::TableSchemaHelpers
let(:migration) do
@@ -16,15 +16,23 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
let(:partition_schema) { 'gitlab_partitions_dynamic' }
let(:partition1_name) { "#{partition_schema}.#{source_table_name}_202001" }
let(:partition2_name) { "#{partition_schema}.#{source_table_name}_202002" }
+ let(:validate) { true }
let(:options) do
{
column: column_name,
name: foreign_key_name,
on_delete: :cascade,
- validate: true
+ on_update: nil,
+ primary_key: :id
}
end
+ let(:create_options) do
+ options
+ .except(:primary_key)
+ .merge!(reverse_lock_order: false, target_column: :id, validate: validate)
+ end
+
before do
allow(migration).to receive(:puts)
allow(migration).to receive(:transaction_open?).and_return(false)
@@ -67,12 +75,11 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
expect(migration).to receive(:concurrent_partitioned_foreign_key_name).and_return(foreign_key_name)
- expect_add_concurrent_fk_and_call_original(partition1_name, target_table_name, **options)
- expect_add_concurrent_fk_and_call_original(partition2_name, target_table_name, **options)
+ expect_add_concurrent_fk_and_call_original(partition1_name, target_table_name, **create_options)
+ expect_add_concurrent_fk_and_call_original(partition2_name, target_table_name, **create_options)
- expect(migration).to receive(:with_lock_retries).ordered.and_yield
- expect(migration).to receive(:add_foreign_key)
- .with(source_table_name, target_table_name, **options)
+ expect(migration).to receive(:add_concurrent_foreign_key)
+ .with(source_table_name, target_table_name, allow_partitioned: true, **create_options)
.ordered
.and_call_original
@@ -81,6 +88,39 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
expect_foreign_key_to_exist(source_table_name, foreign_key_name)
end
+ context 'with validate: false option' do
+ let(:validate) { false }
+ let(:options) do
+ {
+ column: column_name,
+ name: foreign_key_name,
+ on_delete: :cascade,
+ on_update: nil,
+ primary_key: :id
+ }
+ end
+
+ it 'creates the foreign key only on partitions' do
+ expect(migration).to receive(:foreign_key_exists?)
+ .with(source_table_name, target_table_name, **options)
+ .and_return(false)
+
+ expect(migration).to receive(:concurrent_partitioned_foreign_key_name).and_return(foreign_key_name)
+
+ expect_add_concurrent_fk_and_call_original(partition1_name, target_table_name, **create_options)
+ expect_add_concurrent_fk_and_call_original(partition2_name, target_table_name, **create_options)
+
+ expect(migration).not_to receive(:add_concurrent_foreign_key)
+ .with(source_table_name, target_table_name, **create_options)
+
+ migration.add_concurrent_partitioned_foreign_key(
+ source_table_name, target_table_name,
+ column: column_name, validate: false)
+
+ expect_foreign_key_not_to_exist(source_table_name, foreign_key_name)
+ end
+ end
+
def expect_add_concurrent_fk_and_call_original(source_table_name, target_table_name, options)
expect(migration).to receive(:add_concurrent_foreign_key)
.ordered
@@ -100,8 +140,6 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
.and_return(true)
expect(migration).not_to receive(:add_concurrent_foreign_key)
- expect(migration).not_to receive(:with_lock_retries)
- expect(migration).not_to receive(:add_foreign_key)
migration.add_concurrent_partitioned_foreign_key(source_table_name, target_table_name, column: column_name)
@@ -110,30 +148,43 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
end
context 'when additional foreign key options are given' do
- let(:options) do
+ let(:exits_options) do
{
column: column_name,
name: '_my_fk_name',
on_delete: :restrict,
- validate: true
+ on_update: nil,
+ primary_key: :id
}
end
+ let(:create_options) do
+ exits_options
+ .except(:primary_key)
+ .merge!(reverse_lock_order: false, target_column: :id, validate: true)
+ end
+
it 'forwards them to the foreign key helper methods' do
expect(migration).to receive(:foreign_key_exists?)
- .with(source_table_name, target_table_name, **options)
+ .with(source_table_name, target_table_name, **exits_options)
.and_return(false)
expect(migration).not_to receive(:concurrent_partitioned_foreign_key_name)
- expect_add_concurrent_fk(partition1_name, target_table_name, **options)
- expect_add_concurrent_fk(partition2_name, target_table_name, **options)
+ expect_add_concurrent_fk(partition1_name, target_table_name, **create_options)
+ expect_add_concurrent_fk(partition2_name, target_table_name, **create_options)
- expect(migration).to receive(:with_lock_retries).ordered.and_yield
- expect(migration).to receive(:add_foreign_key).with(source_table_name, target_table_name, **options).ordered
+ expect(migration).to receive(:add_concurrent_foreign_key)
+ .with(source_table_name, target_table_name, allow_partitioned: true, **create_options)
+ .ordered
- migration.add_concurrent_partitioned_foreign_key(source_table_name, target_table_name,
- column: column_name, name: '_my_fk_name', on_delete: :restrict)
+ migration.add_concurrent_partitioned_foreign_key(
+ source_table_name,
+ target_table_name,
+ column: column_name,
+ name: '_my_fk_name',
+ on_delete: :restrict
+ )
end
def expect_add_concurrent_fk(source_table_name, target_table_name, options)
@@ -153,4 +204,39 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::ForeignKeyHelpers
end
end
end
+
+ describe '#validate_partitioned_foreign_key' do
+ context 'when run inside a transaction block' do
+ it 'raises an error' do
+ expect(migration).to receive(:transaction_open?).and_return(true)
+
+ expect do
+ migration.validate_partitioned_foreign_key(source_table_name, column_name, name: '_my_fk_name')
+ end.to raise_error(/can not be run inside a transaction/)
+ end
+ end
+
+ context 'when run outside a transaction block' do
+ before do
+ migration.add_concurrent_partitioned_foreign_key(
+ source_table_name,
+ target_table_name,
+ column: column_name,
+ name: foreign_key_name,
+ validate: false
+ )
+ end
+
+ it 'validates FK for each partition' do
+ expect(migration).to receive(:execute).with(/SET statement_timeout TO 0/).twice
+ expect(migration).to receive(:execute).with(/RESET statement_timeout/).twice
+ expect(migration).to receive(:execute)
+ .with(/ALTER TABLE #{partition1_name} VALIDATE CONSTRAINT #{foreign_key_name}/).ordered
+ expect(migration).to receive(:execute)
+ .with(/ALTER TABLE #{partition2_name} VALIDATE CONSTRAINT #{foreign_key_name}/).ordered
+
+ migration.validate_partitioned_foreign_key(source_table_name, column_name, name: foreign_key_name)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/partitioning_spec.rb b/spec/lib/gitlab/database/partitioning_spec.rb
index ae74ee60a4b..4c0fde46b2f 100644
--- a/spec/lib/gitlab/database/partitioning_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_spec.rb
@@ -67,14 +67,19 @@ RSpec.describe Gitlab::Database::Partitioning do
let(:ci_connection) { Ci::ApplicationRecord.connection }
let(:table_names) { %w[partitioning_test1 partitioning_test2] }
let(:models) do
- table_names.map do |table_name|
+ [
Class.new(ApplicationRecord) do
include PartitionedTable
- self.table_name = table_name
+ self.table_name = 'partitioning_test1'
partitioned_by :created_at, strategy: :monthly
+ end,
+ Class.new(Gitlab::Database::Partitioning::TableWithoutModel).tap do |klass|
+ klass.table_name = 'partitioning_test2'
+ klass.partitioned_by(:created_at, strategy: :monthly)
+ klass.limit_connection_names = %i[main]
end
- end
+ ]
end
before do
diff --git a/spec/lib/gitlab/database/postgres_foreign_key_spec.rb b/spec/lib/gitlab/database/postgres_foreign_key_spec.rb
index ae56f66737d..c128c56c708 100644
--- a/spec/lib/gitlab/database/postgres_foreign_key_spec.rb
+++ b/spec/lib/gitlab/database/postgres_foreign_key_spec.rb
@@ -70,13 +70,29 @@ RSpec.describe Gitlab::Database::PostgresForeignKey, type: :model, feature_categ
end
describe '#by_constrained_table_name' do
- it 'finds the foreign keys for the constrained table' do
- expected = described_class.where(name: %w[fk_constrained_to_referenced fk_constrained_to_other_referenced]).to_a
+ let(:expected) { described_class.where(name: %w[fk_constrained_to_referenced fk_constrained_to_other_referenced]).to_a }
+ it 'finds the foreign keys for the constrained table' do
expect(described_class.by_constrained_table_name(table_name("constrained_table"))).to match_array(expected)
end
end
+ describe '#by_constrained_table_name_or_identifier' do
+ let(:expected) { described_class.where(name: %w[fk_constrained_to_referenced fk_constrained_to_other_referenced]).to_a }
+
+ context 'when using table name' do
+ it 'finds the foreign keys for the constrained table' do
+ expect(described_class.by_constrained_table_name_or_identifier(table_name("constrained_table"))).to match_array(expected)
+ end
+ end
+
+ context 'when using identifier' do
+ it 'finds the foreign keys for the constrained table' do
+ expect(described_class.by_constrained_table_name_or_identifier(schema_table_name('constrained_table'))).to match_array(expected)
+ end
+ end
+ end
+
describe '#by_name' do
it 'finds foreign keys by name' do
expect(described_class.by_name('fk_constrained_to_referenced').pluck(:name)).to contain_exactly('fk_constrained_to_referenced')
@@ -187,10 +203,8 @@ RSpec.describe Gitlab::Database::PostgresForeignKey, type: :model, feature_categ
end
end
- context 'when supporting foreign keys to inherited tables in postgres 12' do
+ context 'when supporting foreign keys to inherited tables' do
before do
- skip('not supported before postgres 12') if ApplicationRecord.database.version.to_f < 12
-
ApplicationRecord.connection.execute(<<~SQL)
create table #{schema_table_name('parent')} (
id bigserial primary key not null
diff --git a/spec/lib/gitlab/database/postgres_partition_spec.rb b/spec/lib/gitlab/database/postgres_partition_spec.rb
index 14a4d405621..48dbdbc7757 100644
--- a/spec/lib/gitlab/database/postgres_partition_spec.rb
+++ b/spec/lib/gitlab/database/postgres_partition_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::PostgresPartition, type: :model do
+RSpec.describe Gitlab::Database::PostgresPartition, type: :model, feature_category: :database do
+ let(:current_schema) { ActiveRecord::Base.connection.select_value("SELECT current_schema()") }
let(:schema) { 'gitlab_partitions_dynamic' }
let(:name) { '_test_partition_01' }
let(:identifier) { "#{schema}.#{name}" }
@@ -56,9 +57,20 @@ RSpec.describe Gitlab::Database::PostgresPartition, type: :model do
expect(partitions.pluck(:name)).to eq([name, second_name])
end
+ it 'returns the partitions if the parent table schema is included in the table name' do
+ partitions = described_class.for_parent_table("#{current_schema}._test_partitioned_table")
+
+ expect(partitions.count).to eq(2)
+ expect(partitions.pluck(:name)).to eq([name, second_name])
+ end
+
it 'does not return partitions for tables not in the current schema' do
expect(described_class.for_parent_table('_test_other_table').count).to eq(0)
end
+
+ it 'does not return partitions for tables if the schema is not the current' do
+ expect(described_class.for_parent_table('foo_bar._test_partitioned_table').count).to eq(0)
+ end
end
describe '#parent_identifier' do
diff --git a/spec/lib/gitlab/database/reindexing_spec.rb b/spec/lib/gitlab/database/reindexing_spec.rb
index a8af9bb5a38..4d0e58b0937 100644
--- a/spec/lib/gitlab/database/reindexing_spec.rb
+++ b/spec/lib/gitlab/database/reindexing_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe Gitlab::Database::Reindexing, feature_category: :database, time_t
context 'when async FK validation is enabled' do
it 'executes FK validation for each database prior to any reindexing actions' do
- expect(Gitlab::Database::AsyncForeignKeys).to receive(:validate_pending_entries!).ordered.exactly(databases_count).times
+ expect(Gitlab::Database::AsyncConstraints).to receive(:validate_pending_entries!).ordered.exactly(databases_count).times
expect(described_class).to receive(:automatic_reindexing).ordered.exactly(databases_count).times
described_class.invoke
@@ -82,7 +82,7 @@ RSpec.describe Gitlab::Database::Reindexing, feature_category: :database, time_t
it 'does not execute FK validation' do
stub_feature_flags(database_async_foreign_key_validation: false)
- expect(Gitlab::Database::AsyncForeignKeys).not_to receive(:validate_pending_entries!)
+ expect(Gitlab::Database::AsyncConstraints).not_to receive(:validate_pending_entries!)
described_class.invoke
end
diff --git a/spec/lib/gitlab/database/schema_validation/database_spec.rb b/spec/lib/gitlab/database/schema_validation/database_spec.rb
index c0026f91b46..eadaf683a29 100644
--- a/spec/lib/gitlab/database/schema_validation/database_spec.rb
+++ b/spec/lib/gitlab/database/schema_validation/database_spec.rb
@@ -3,43 +3,108 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::SchemaValidation::Database, feature_category: :database do
- let(:database_name) { 'main' }
- let(:database_indexes) do
- [['index', 'CREATE UNIQUE INDEX "index" ON public.achievements USING btree (namespace_id, lower(name))']]
- end
+ subject(:database) { described_class.new(connection) }
- let(:query_result) { instance_double('ActiveRecord::Result', rows: database_indexes) }
- let(:database_model) { Gitlab::Database.database_base_models[database_name] }
+ let(:database_model) { Gitlab::Database.database_base_models['main'] }
let(:connection) { database_model.connection }
- subject(:database) { described_class.new(connection) }
+ context 'when having indexes' do
+ let(:schema_object) { Gitlab::Database::SchemaValidation::SchemaObjects::Index }
+ let(:results) do
+ [['index', 'CREATE UNIQUE INDEX "index" ON public.achievements USING btree (namespace_id, lower(name))']]
+ end
- before do
- allow(connection).to receive(:exec_query).and_return(query_result)
- end
+ before do
+ allow(connection).to receive(:select_rows).and_return(results)
+ end
+
+ describe '#fetch_index_by_name' do
+ context 'when index does not exist' do
+ it 'returns nil' do
+ index = database.fetch_index_by_name('non_existing_index')
+
+ expect(index).to be_nil
+ end
+ end
+
+ it 'returns index by name' do
+ index = database.fetch_index_by_name('index')
+
+ expect(index.name).to eq('index')
+ end
+ end
+
+ describe '#index_exists?' do
+ context 'when index exists' do
+ it 'returns true' do
+ index_exists = database.index_exists?('index')
+
+ expect(index_exists).to be_truthy
+ end
+ end
- describe '#fetch_index_by_name' do
- context 'when index does not exist' do
- it 'returns nil' do
- index = database.fetch_index_by_name('non_existing_index')
+ context 'when index does not exist' do
+ it 'returns false' do
+ index_exists = database.index_exists?('non_existing_index')
- expect(index).to be_nil
+ expect(index_exists).to be_falsey
+ end
end
end
- it 'returns index by name' do
- index = database.fetch_index_by_name('index')
+ describe '#indexes' do
+ it 'returns indexes' do
+ indexes = database.indexes
- expect(index.name).to eq('index')
+ expect(indexes).to all(be_a(schema_object))
+ expect(indexes.map(&:name)).to eq(['index'])
+ end
end
end
- describe '#indexes' do
- it 'returns indexes' do
- indexes = database.indexes
+ context 'when having triggers' do
+ let(:schema_object) { Gitlab::Database::SchemaValidation::SchemaObjects::Trigger }
+ let(:results) do
+ { 'my_trigger' => 'CREATE TRIGGER my_trigger BEFORE INSERT ON todos FOR EACH ROW EXECUTE FUNCTION trigger()' }
+ end
+
+ before do
+ allow(database).to receive(:fetch_triggers).and_return(results)
+ end
+
+ describe '#fetch_trigger_by_name' do
+ context 'when trigger does not exist' do
+ it 'returns nil' do
+ expect(database.fetch_trigger_by_name('non_existing_trigger')).to be_nil
+ end
+ end
+
+ it 'returns trigger by name' do
+ expect(database.fetch_trigger_by_name('my_trigger').name).to eq('my_trigger')
+ end
+ end
+
+ describe '#trigger_exists?' do
+ context 'when trigger exists' do
+ it 'returns true' do
+ expect(database.trigger_exists?('my_trigger')).to be_truthy
+ end
+ end
+
+ context 'when trigger does not exist' do
+ it 'returns false' do
+ expect(database.trigger_exists?('non_existing_trigger')).to be_falsey
+ end
+ end
+ end
- expect(indexes).to all(be_a(Gitlab::Database::SchemaValidation::Index))
- expect(indexes.map(&:name)).to eq(['index'])
+ describe '#triggers' do
+ it 'returns triggers' do
+ triggers = database.triggers
+
+ expect(triggers).to all(be_a(schema_object))
+ expect(triggers.map(&:name)).to eq(['my_trigger'])
+ end
end
end
end
diff --git a/spec/lib/gitlab/database/schema_validation/index_spec.rb b/spec/lib/gitlab/database/schema_validation/index_spec.rb
deleted file mode 100644
index 297211d79ed..00000000000
--- a/spec/lib/gitlab/database/schema_validation/index_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::SchemaValidation::Index, feature_category: :database do
- let(:index_statement) { 'CREATE INDEX index_name ON public.achievements USING btree (namespace_id)' }
-
- let(:stmt) { PgQuery.parse(index_statement).tree.stmts.first.stmt.index_stmt }
-
- let(:index) { described_class.new(stmt) }
-
- describe '#name' do
- it 'returns index name' do
- expect(index.name).to eq('index_name')
- end
- end
-
- describe '#statement' do
- it 'returns index statement' do
- expect(index.statement).to eq(index_statement)
- end
- end
-end
diff --git a/spec/lib/gitlab/database/schema_validation/indexes_spec.rb b/spec/lib/gitlab/database/schema_validation/indexes_spec.rb
deleted file mode 100644
index 4351031a4b4..00000000000
--- a/spec/lib/gitlab/database/schema_validation/indexes_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::SchemaValidation::Indexes, feature_category: :database do
- let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
- let(:database_indexes) do
- [
- ['wrong_index', 'CREATE UNIQUE INDEX wrong_index ON public.table_name (column_name)'],
- ['extra_index', 'CREATE INDEX extra_index ON public.table_name (column_name)'],
- ['index', 'CREATE UNIQUE INDEX "index" ON public.achievements USING btree (namespace_id, lower(name))']
- ]
- end
-
- let(:database_name) { 'main' }
-
- let(:database_model) { Gitlab::Database.database_base_models[database_name] }
-
- let(:connection) { database_model.connection }
-
- let(:query_result) { instance_double('ActiveRecord::Result', rows: database_indexes) }
-
- let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
- let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path) }
-
- subject(:schema_validation) { described_class.new(structure_file, database) }
-
- before do
- allow(connection).to receive(:exec_query).and_return(query_result)
- end
-
- describe '#missing_indexes' do
- it 'returns missing indexes' do
- missing_indexes = %w[
- missing_index
- index_namespaces_public_groups_name_id
- index_on_deploy_keys_id_and_type_and_public
- index_users_on_public_email_excluding_null_and_empty
- ]
-
- expect(schema_validation.missing_indexes).to match_array(missing_indexes)
- end
- end
-
- describe '#extra_indexes' do
- it 'returns extra indexes' do
- expect(schema_validation.extra_indexes).to match_array(['extra_index'])
- end
- end
-
- describe '#wrong_indexes' do
- it 'returns wrong indexes' do
- expect(schema_validation.wrong_indexes).to match_array(['wrong_index'])
- end
- end
-end
diff --git a/spec/lib/gitlab/database/schema_validation/runner_spec.rb b/spec/lib/gitlab/database/schema_validation/runner_spec.rb
new file mode 100644
index 00000000000..ddbdedcd8b4
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/runner_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Runner, feature_category: :database do
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:connection) { ActiveRecord::Base.connection }
+
+ let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
+ let(:structure_sql) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, 'public') }
+
+ describe '#execute' do
+ subject(:inconsistencies) { described_class.new(structure_sql, database).execute }
+
+ it 'returns inconsistencies' do
+ expect(inconsistencies).not_to be_empty
+ end
+
+ it 'execute all validators' do
+ all_validators = Gitlab::Database::SchemaValidation::Validators::BaseValidator.all_validators
+
+ expect(all_validators).to all(receive(:new).with(structure_sql, database).and_call_original)
+
+ inconsistencies
+ end
+
+ context 'when validators are passed' do
+ subject(:inconsistencies) { described_class.new(structure_sql, database, validators: validators).execute }
+
+ let(:class_name) { 'Gitlab::Database::SchemaValidation::Validators::ExtraIndexes' }
+ let(:inconsistency_class_name) { 'Gitlab::Database::SchemaValidation::Validators::BaseValidator::Inconsistency' }
+
+ let(:extra_indexes) { class_double(class_name) }
+ let(:instace_extra_index) { instance_double(class_name, execute: [inconsistency]) }
+ let(:inconsistency) { instance_double(inconsistency_class_name, object_name: 'test') }
+
+ let(:validators) { [extra_indexes] }
+
+ it 'only execute the validators passed' do
+ expect(extra_indexes).to receive(:new).with(structure_sql, database).and_return(instace_extra_index)
+
+ Gitlab::Database::SchemaValidation::Validators::BaseValidator.all_validators.each do |validator|
+ expect(validator).not_to receive(:new).with(structure_sql, database)
+ end
+
+ expect(inconsistencies.map(&:object_name)).to eql ['test']
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb b/spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb
new file mode 100644
index 00000000000..1aaa994e3bb
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::SchemaObjects::Index, feature_category: :database do
+ let(:statement) { 'CREATE INDEX index_name ON public.achievements USING btree (namespace_id)' }
+ let(:name) { 'index_name' }
+
+ include_examples 'schema objects assertions for', 'index_stmt'
+end
diff --git a/spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb b/spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb
new file mode 100644
index 00000000000..8000a54ee27
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::SchemaObjects::Trigger, feature_category: :database do
+ let(:statement) { 'CREATE TRIGGER my_trigger BEFORE INSERT ON todos FOR EACH ROW EXECUTE FUNCTION trigger()' }
+ let(:name) { 'my_trigger' }
+
+ include_examples 'schema objects assertions for', 'create_trig_stmt'
+end
diff --git a/spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb b/spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb
new file mode 100644
index 00000000000..cc0bd4125ef
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::StructureSql, feature_category: :database do
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:schema_name) { 'public' }
+
+ subject(:structure_sql) { described_class.new(structure_file_path, schema_name) }
+
+ context 'when having indexes' do
+ describe '#index_exists?' do
+ subject(:index_exists) { structure_sql.index_exists?(index_name) }
+
+ context 'when the index does not exist' do
+ let(:index_name) { 'non-existent-index' }
+
+ it 'returns false' do
+ expect(index_exists).to be_falsey
+ end
+ end
+
+ context 'when the index exists' do
+ let(:index_name) { 'index' }
+
+ it 'returns true' do
+ expect(index_exists).to be_truthy
+ end
+ end
+ end
+
+ describe '#indexes' do
+ it 'returns indexes' do
+ indexes = structure_sql.indexes
+
+ expected_indexes = %w[
+ missing_index
+ wrong_index
+ index
+ index_namespaces_public_groups_name_id
+ index_on_deploy_keys_id_and_type_and_public
+ index_users_on_public_email_excluding_null_and_empty
+ ]
+
+ expect(indexes).to all(be_a(Gitlab::Database::SchemaValidation::SchemaObjects::Index))
+ expect(indexes.map(&:name)).to eq(expected_indexes)
+ end
+ end
+ end
+
+ context 'when having triggers' do
+ describe '#trigger_exists?' do
+ subject(:trigger_exists) { structure_sql.trigger_exists?(name) }
+
+ context 'when the trigger does not exist' do
+ let(:name) { 'non-existent-trigger' }
+
+ it 'returns false' do
+ expect(trigger_exists).to be_falsey
+ end
+ end
+
+ context 'when the trigger exists' do
+ let(:name) { 'trigger' }
+
+ it 'returns true' do
+ expect(trigger_exists).to be_truthy
+ end
+ end
+ end
+
+ describe '#triggers' do
+ it 'returns triggers' do
+ triggers = structure_sql.triggers
+ expected_triggers = %w[trigger wrong_trigger missing_trigger_1 projects_loose_fk_trigger]
+
+ expect(triggers).to all(be_a(Gitlab::Database::SchemaValidation::SchemaObjects::Trigger))
+ expect(triggers.map(&:name)).to eq(expected_triggers)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb
new file mode 100644
index 00000000000..2f38c25cf68
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::BaseValidator, feature_category: :database do
+ describe '.all_validators' do
+ subject(:all_validators) { described_class.all_validators }
+
+ it 'returns an array of all validators' do
+ expect(all_validators).to eq([
+ Gitlab::Database::SchemaValidation::Validators::ExtraIndexes,
+ Gitlab::Database::SchemaValidation::Validators::ExtraTriggers,
+ Gitlab::Database::SchemaValidation::Validators::MissingIndexes,
+ Gitlab::Database::SchemaValidation::Validators::MissingTriggers,
+ Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionIndexes,
+ Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionTriggers
+ ])
+ end
+ end
+
+ describe '#execute' do
+ let(:structure_sql) { instance_double(Gitlab::Database::SchemaValidation::StructureSql) }
+ let(:database) { instance_double(Gitlab::Database::SchemaValidation::Database) }
+
+ subject(:inconsistencies) { described_class.new(structure_sql, database).execute }
+
+ it 'raises an exception' do
+ expect { inconsistencies }.to raise_error(NoMethodError)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/different_definition_indexes_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/different_definition_indexes_spec.rb
new file mode 100644
index 00000000000..b9744c86b80
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/different_definition_indexes_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionIndexes,
+ feature_category: :database do
+ include_examples 'index validators', described_class, ['wrong_index']
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/different_definition_triggers_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/different_definition_triggers_spec.rb
new file mode 100644
index 00000000000..4d065929708
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/different_definition_triggers_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionTriggers,
+ feature_category: :database do
+ include_examples 'trigger validators', described_class, ['wrong_trigger']
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb
new file mode 100644
index 00000000000..842dbb42120
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::ExtraIndexes, feature_category: :database do
+ include_examples 'index validators', described_class, ['extra_index']
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/extra_triggers_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/extra_triggers_spec.rb
new file mode 100644
index 00000000000..d2e1c18a1ab
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/extra_triggers_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::ExtraTriggers, feature_category: :database do
+ include_examples 'trigger validators', described_class, ['extra_trigger']
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb
new file mode 100644
index 00000000000..c402c3a2fa7
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::MissingIndexes, feature_category: :database do
+ missing_indexes = %w[
+ missing_index
+ index_namespaces_public_groups_name_id
+ index_on_deploy_keys_id_and_type_and_public
+ index_users_on_public_email_excluding_null_and_empty
+ ]
+
+ include_examples 'index validators', described_class, missing_indexes
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/missing_triggers_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/missing_triggers_spec.rb
new file mode 100644
index 00000000000..87bc3ded808
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/missing_triggers_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::MissingTriggers, feature_category: :database do
+ missing_triggers = %w[missing_trigger_1 projects_loose_fk_trigger]
+
+ include_examples 'trigger validators', described_class, missing_triggers
+end
diff --git a/spec/lib/gitlab/database/tables_locker_spec.rb b/spec/lib/gitlab/database/tables_locker_spec.rb
index d74f455eaad..30f0f9376c8 100644
--- a/spec/lib/gitlab/database/tables_locker_spec.rb
+++ b/spec/lib/gitlab/database/tables_locker_spec.rb
@@ -2,20 +2,38 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base, :delete, :silence_stdout,
- :suppress_gitlab_schemas_validate_connection, feature_category: :pods do
- let(:detached_partition_table) { '_test_gitlab_main_part_20220101' }
- let(:lock_writes_manager) do
+RSpec.describe Gitlab::Database::TablesLocker, :suppress_gitlab_schemas_validate_connection, :silence_stdout,
+ feature_category: :pods do
+ let(:default_lock_writes_manager) do
instance_double(Gitlab::Database::LockWritesManager, lock_writes: nil, unlock_writes: nil)
end
before do
- allow(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(lock_writes_manager)
+ allow(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(default_lock_writes_manager)
+ # Limiting the scope of the tests to a subset of the database tables
+ allow(Gitlab::Database::GitlabSchema).to receive(:tables_to_schema).and_return({
+ 'application_setttings' => :gitlab_main_clusterwide,
+ 'projects' => :gitlab_main,
+ 'security_findings' => :gitlab_main,
+ 'ci_builds' => :gitlab_ci,
+ 'ci_jobs' => :gitlab_ci,
+ 'loose_foreign_keys_deleted_records' => :gitlab_shared,
+ 'ar_internal_metadata' => :gitlab_internal
+ })
end
before(:all) do
+ create_partition_sql = <<~SQL
+ CREATE TABLE IF NOT EXISTS #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.security_findings_test_partition
+ PARTITION OF security_findings
+ FOR VALUES IN (0)
+ SQL
+
+ ApplicationRecord.connection.execute(create_partition_sql)
+ Ci::ApplicationRecord.connection.execute(create_partition_sql)
+
create_detached_partition_sql = <<~SQL
- CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic._test_gitlab_main_part_20220101 (
+ CREATE TABLE IF NOT EXISTS #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_gitlab_main_part_202201 (
id bigserial primary key not null
)
SQL
@@ -29,35 +47,81 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base
drop_after: Time.current
)
end
+ Gitlab::Database::SharedModel.using_connection(Ci::ApplicationRecord.connection) do
+ Postgresql::DetachedPartition.create!(
+ table_name: '_test_gitlab_main_part_20220101',
+ drop_after: Time.current
+ )
+ end
end
- after(:all) do
- drop_detached_partition_sql = <<~SQL
- DROP TABLE IF EXISTS gitlab_partitions_dynamic._test_gitlab_main_part_20220101
- SQL
+ shared_examples "lock tables" do |gitlab_schema, database_name|
+ let(:connection) { Gitlab::Database.database_base_models[database_name].connection }
+ let(:tables_to_lock) do
+ Gitlab::Database::GitlabSchema
+ .tables_to_schema.filter_map { |table_name, schema| table_name if schema == gitlab_schema }
+ end
- ApplicationRecord.connection.execute(drop_detached_partition_sql)
- Ci::ApplicationRecord.connection.execute(drop_detached_partition_sql)
+ it "locks table in schema #{gitlab_schema} and database #{database_name}" do
+ expect(tables_to_lock).not_to be_empty
- Gitlab::Database::SharedModel.using_connection(ApplicationRecord.connection) do
- Postgresql::DetachedPartition.delete_all
+ tables_to_lock.each do |table_name|
+ lock_writes_manager = instance_double(Gitlab::Database::LockWritesManager, lock_writes: nil)
+
+ expect(Gitlab::Database::LockWritesManager).to receive(:new).with(
+ table_name: table_name,
+ connection: connection,
+ database_name: database_name,
+ with_retries: true,
+ logger: anything,
+ dry_run: anything
+ ).once.and_return(lock_writes_manager)
+ expect(lock_writes_manager).to receive(:lock_writes).once
+ end
+
+ subject
end
end
- shared_examples "lock tables" do |table_schema, database_name|
- let(:table_name) do
+ shared_examples "unlock tables" do |gitlab_schema, database_name|
+ let(:connection) { Gitlab::Database.database_base_models[database_name].connection }
+
+ let(:tables_to_unlock) do
Gitlab::Database::GitlabSchema
- .tables_to_schema.filter_map { |table_name, schema| table_name if schema == table_schema }
- .first
+ .tables_to_schema.filter_map { |table_name, schema| table_name if schema == gitlab_schema }
+ end
+
+ it "unlocks table in schema #{gitlab_schema} and database #{database_name}" do
+ expect(tables_to_unlock).not_to be_empty
+
+ tables_to_unlock.each do |table_name|
+ lock_writes_manager = instance_double(Gitlab::Database::LockWritesManager, unlock_writes: nil)
+
+ expect(Gitlab::Database::LockWritesManager).to receive(:new).with(
+ table_name: table_name,
+ connection: anything,
+ database_name: database_name,
+ with_retries: true,
+ logger: anything,
+ dry_run: anything
+ ).once.and_return(lock_writes_manager)
+ expect(lock_writes_manager).to receive(:unlock_writes)
+ end
+
+ subject
end
+ end
+
+ shared_examples "lock partitions" do |partition_identifier, database_name|
+ let(:connection) { Gitlab::Database.database_base_models[database_name].connection }
- let(:database) { database_name }
+ it 'locks the partition' do
+ lock_writes_manager = instance_double(Gitlab::Database::LockWritesManager, lock_writes: nil)
- it "locks table in schema #{table_schema} and database #{database_name}" do
expect(Gitlab::Database::LockWritesManager).to receive(:new).with(
- table_name: table_name,
- connection: anything,
- database_name: database,
+ table_name: partition_identifier,
+ connection: connection,
+ database_name: database_name,
with_retries: true,
logger: anything,
dry_run: anything
@@ -68,20 +132,16 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base
end
end
- shared_examples "unlock tables" do |table_schema, database_name|
- let(:table_name) do
- Gitlab::Database::GitlabSchema
- .tables_to_schema.filter_map { |table_name, schema| table_name if schema == table_schema }
- .first
- end
+ shared_examples "unlock partitions" do |partition_identifier, database_name|
+ let(:connection) { Gitlab::Database.database_base_models[database_name].connection }
- let(:database) { database_name }
+ it 'unlocks the partition' do
+ lock_writes_manager = instance_double(Gitlab::Database::LockWritesManager, unlock_writes: nil)
- it "unlocks table in schema #{table_schema} and database #{database_name}" do
expect(Gitlab::Database::LockWritesManager).to receive(:new).with(
- table_name: table_name,
- connection: anything,
- database_name: database,
+ table_name: partition_identifier,
+ connection: connection,
+ database_name: database_name,
with_retries: true,
logger: anything,
dry_run: anything
@@ -100,25 +160,29 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base
describe '#lock_writes' do
subject { described_class.new.lock_writes }
- it 'does not call Gitlab::Database::LockWritesManager.lock_writes' do
- expect(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(lock_writes_manager)
- expect(lock_writes_manager).not_to receive(:lock_writes)
+ it 'does not lock any table' do
+ expect(Gitlab::Database::LockWritesManager).to receive(:new)
+ .with(any_args).and_return(default_lock_writes_manager)
+ expect(default_lock_writes_manager).not_to receive(:lock_writes)
subject
end
- include_examples "unlock tables", :gitlab_main, 'main'
- include_examples "unlock tables", :gitlab_ci, 'ci'
- include_examples "unlock tables", :gitlab_shared, 'main'
- include_examples "unlock tables", :gitlab_internal, 'main'
+ it_behaves_like 'unlock tables', :gitlab_main, 'main'
+ it_behaves_like 'unlock tables', :gitlab_ci, 'main'
+ it_behaves_like 'unlock tables', :gitlab_main_clusterwide, 'main'
+ it_behaves_like 'unlock tables', :gitlab_shared, 'main'
+ it_behaves_like 'unlock tables', :gitlab_internal, 'main'
end
describe '#unlock_writes' do
subject { described_class.new.lock_writes }
it 'does call Gitlab::Database::LockWritesManager.unlock_writes' do
- expect(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(lock_writes_manager)
- expect(lock_writes_manager).to receive(:unlock_writes)
+ expect(Gitlab::Database::LockWritesManager).to receive(:new)
+ .with(any_args).and_return(default_lock_writes_manager)
+ expect(default_lock_writes_manager).to receive(:unlock_writes)
+ expect(default_lock_writes_manager).not_to receive(:lock_writes)
subject
end
@@ -133,43 +197,61 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base
describe '#lock_writes' do
subject { described_class.new.lock_writes }
- include_examples "lock tables", :gitlab_ci, 'main'
- include_examples "lock tables", :gitlab_main, 'ci'
-
- include_examples "unlock tables", :gitlab_main, 'main'
- include_examples "unlock tables", :gitlab_ci, 'ci'
- include_examples "unlock tables", :gitlab_shared, 'main'
- include_examples "unlock tables", :gitlab_shared, 'ci'
- include_examples "unlock tables", :gitlab_internal, 'main'
- include_examples "unlock tables", :gitlab_internal, 'ci'
+ it_behaves_like 'lock tables', :gitlab_ci, 'main'
+ it_behaves_like 'lock tables', :gitlab_main, 'ci'
+ it_behaves_like 'lock tables', :gitlab_main_clusterwide, 'ci'
+
+ it_behaves_like 'unlock tables', :gitlab_main_clusterwide, 'main'
+ it_behaves_like 'unlock tables', :gitlab_main, 'main'
+ it_behaves_like 'unlock tables', :gitlab_ci, 'ci'
+ it_behaves_like 'unlock tables', :gitlab_shared, 'main'
+ it_behaves_like 'unlock tables', :gitlab_shared, 'ci'
+ it_behaves_like 'unlock tables', :gitlab_internal, 'main'
+ it_behaves_like 'unlock tables', :gitlab_internal, 'ci'
+
+ gitlab_main_partition = "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.security_findings_test_partition"
+ it_behaves_like 'unlock partitions', gitlab_main_partition, 'main'
+ it_behaves_like 'lock partitions', gitlab_main_partition, 'ci'
+
+ gitlab_main_detached_partition = "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_gitlab_main_part_20220101"
+ it_behaves_like 'unlock partitions', gitlab_main_detached_partition, 'main'
+ it_behaves_like 'lock partitions', gitlab_main_detached_partition, 'ci'
end
describe '#unlock_writes' do
subject { described_class.new.unlock_writes }
- include_examples "unlock tables", :gitlab_ci, 'main'
- include_examples "unlock tables", :gitlab_main, 'ci'
- include_examples "unlock tables", :gitlab_main, 'main'
- include_examples "unlock tables", :gitlab_ci, 'ci'
- include_examples "unlock tables", :gitlab_shared, 'main'
- include_examples "unlock tables", :gitlab_shared, 'ci'
- include_examples "unlock tables", :gitlab_internal, 'main'
- include_examples "unlock tables", :gitlab_internal, 'ci'
+ it_behaves_like "unlock tables", :gitlab_ci, 'main'
+ it_behaves_like "unlock tables", :gitlab_main, 'ci'
+ it_behaves_like "unlock tables", :gitlab_main, 'main'
+ it_behaves_like "unlock tables", :gitlab_ci, 'ci'
+ it_behaves_like "unlock tables", :gitlab_shared, 'main'
+ it_behaves_like "unlock tables", :gitlab_shared, 'ci'
+ it_behaves_like "unlock tables", :gitlab_internal, 'main'
+ it_behaves_like "unlock tables", :gitlab_internal, 'ci'
+
+ gitlab_main_partition = "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.security_findings_test_partition"
+ it_behaves_like 'unlock partitions', gitlab_main_partition, 'main'
+ it_behaves_like 'unlock partitions', gitlab_main_partition, 'ci'
+
+ gitlab_main_detached_partition = "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_gitlab_main_part_20220101"
+ it_behaves_like 'unlock partitions', gitlab_main_detached_partition, 'main'
+ it_behaves_like 'unlock partitions', gitlab_main_detached_partition, 'ci'
end
context 'when running in dry_run mode' do
subject { described_class.new(dry_run: true).lock_writes }
- it 'passes dry_run flag to LockManger' do
+ it 'passes dry_run flag to LockWritesManager' do
expect(Gitlab::Database::LockWritesManager).to receive(:new).with(
- table_name: 'users',
+ table_name: 'security_findings',
connection: anything,
database_name: 'ci',
with_retries: true,
logger: anything,
dry_run: true
- ).and_return(lock_writes_manager)
- expect(lock_writes_manager).to receive(:lock_writes)
+ ).and_return(default_lock_writes_manager)
+ expect(default_lock_writes_manager).to receive(:lock_writes)
subject
end
@@ -185,8 +267,9 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base
end
it 'does not lock any tables if the ci database is shared with main database' do
- expect(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(lock_writes_manager)
- expect(lock_writes_manager).not_to receive(:lock_writes)
+ expect(Gitlab::Database::LockWritesManager).to receive(:new)
+ .with(any_args).and_return(default_lock_writes_manager)
+ expect(default_lock_writes_manager).not_to receive(:lock_writes)
subject
end
@@ -220,7 +303,3 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base
end
end
end
-
-def number_of_triggers(connection)
- connection.select_value("SELECT count(*) FROM information_schema.triggers")
-end
diff --git a/spec/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512_spec.rb b/spec/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512_spec.rb
index df17d92bb0c..fb433923db5 100644
--- a/spec/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512_spec.rb
+++ b/spec/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512_spec.rb
@@ -10,16 +10,6 @@ RSpec.describe Gitlab::DoorkeeperSecretStoring::Secret::Pbkdf2Sha512 do
expect(described_class.transform_secret(plaintext_secret))
.to eq("$pbkdf2-sha512$20000$$.c0G5XJVEew1TyeJk5TrkvB0VyOaTmDzPrsdNRED9vVeZlSyuG3G90F0ow23zUCiWKAVwmNnR/ceh.nJG3MdpQ") # rubocop:disable Layout/LineLength
end
-
- context 'when hash_oauth_secrets is disabled' do
- before do
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'returns a plaintext secret' do
- expect(described_class.transform_secret(plaintext_secret)).to eq(plaintext_secret)
- end
- end
end
describe 'STRETCHES' do
@@ -36,7 +26,6 @@ RSpec.describe Gitlab::DoorkeeperSecretStoring::Secret::Pbkdf2Sha512 do
describe '.secret_matches?' do
it "match by hashing the input if the stored value is hashed" do
- stub_feature_flags(hash_oauth_secrets: false)
plain_secret = 'plain_secret'
stored_value = '$pbkdf2-sha512$20000$$/BwQRdwSpL16xkQhstavh7nvA5avCP7.4n9LLKe9AupgJDeA7M5xOAvG3N3E5XbRyGWWBbbr.BsojPVWzd1Sqg' # rubocop:disable Layout/LineLength
expect(described_class.secret_matches?(plain_secret, stored_value)).to be true
diff --git a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
index 8ff8de2379a..369d7e994d2 100644
--- a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
@@ -116,7 +116,7 @@ RSpec.describe Gitlab::Email::Handler::CreateIssueHandler do
context "when the issue could not be saved" do
before do
allow_any_instance_of(Issue).to receive(:persisted?).and_return(false)
- allow_any_instance_of(Issue).to receive(:ensure_metrics).and_return(nil)
+ allow_any_instance_of(Issue).to receive(:ensure_metrics!).and_return(nil)
end
it "raises an InvalidIssueError" do
diff --git a/spec/lib/gitlab/email/html_to_markdown_parser_spec.rb b/spec/lib/gitlab/email/html_to_markdown_parser_spec.rb
index fe585d47d59..59c488739dc 100644
--- a/spec/lib/gitlab/email/html_to_markdown_parser_spec.rb
+++ b/spec/lib/gitlab/email/html_to_markdown_parser_spec.rb
@@ -1,17 +1,21 @@
# frozen_string_literal: true
-require 'spec_helper'
+require 'kramdown'
+require 'html2text'
+require 'fast_spec_helper'
+require 'support/helpers/fixture_helpers'
RSpec.describe Gitlab::Email::HtmlToMarkdownParser, feature_category: :service_desk do
+ include FixtureHelpers
+
subject { described_class.convert(html) }
describe '.convert' do
let(:html) { fixture_file("lib/gitlab/email/basic.html") }
it 'parses html correctly' do
- expect(subject)
- .to eq(
- <<-BODY.strip_heredoc.chomp
+ expect(subject).to eq(
+ <<~BODY.chomp
Hello, World!
This is some e-mail content. Even though it has whitespace and newlines, the e-mail converter will handle it correctly.
*Even* mismatched tags.
diff --git a/spec/lib/gitlab/email/message/build_ios_app_guide_spec.rb b/spec/lib/gitlab/email/message/build_ios_app_guide_spec.rb
index 3089f955252..4b77b2f7192 100644
--- a/spec/lib/gitlab/email/message/build_ios_app_guide_spec.rb
+++ b/spec/lib/gitlab/email/message/build_ios_app_guide_spec.rb
@@ -2,13 +2,9 @@
require 'spec_helper'
-RSpec.describe Gitlab::Email::Message::BuildIosAppGuide do
+RSpec.describe Gitlab::Email::Message::BuildIosAppGuide, :saas do
subject(:message) { described_class.new }
- before do
- allow(Gitlab).to receive(:com?) { true }
- end
-
it 'contains the correct message', :aggregate_failures do
expect(message.subject_line).to eq 'Get set up to build for iOS'
expect(message.title).to eq "Building for iOS? We've got you covered."
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/helper_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/helper_spec.rb
index 3c0d83d0f9e..a3c2d1b428e 100644
--- a/spec/lib/gitlab/email/message/in_product_marketing/helper_spec.rb
+++ b/spec/lib/gitlab/email/message/in_product_marketing/helper_spec.rb
@@ -27,11 +27,7 @@ RSpec.describe Gitlab::Email::Message::InProductMarketing::Helper do
subject(:class_with_helper) { dummy_class_with_helper.new(format) }
- context 'gitlab.com' do
- before do
- allow(Gitlab).to receive(:com?) { true }
- end
-
+ context 'for SaaS', :saas do
context 'format is HTML' do
it 'returns the correct HTML' do
message = "If you no longer wish to receive marketing emails from us, " \
diff --git a/spec/lib/gitlab/endpoint_attributes_spec.rb b/spec/lib/gitlab/endpoint_attributes_spec.rb
index 53f5b302f05..a623070c3eb 100644
--- a/spec/lib/gitlab/endpoint_attributes_spec.rb
+++ b/spec/lib/gitlab/endpoint_attributes_spec.rb
@@ -1,11 +1,8 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
-require_relative '../../support/matchers/be_request_urgency'
-require_relative '../../../lib/gitlab/endpoint_attributes/config'
-require_relative '../../../lib/gitlab/endpoint_attributes'
+require 'spec_helper'
-RSpec.describe Gitlab::EndpointAttributes do
+RSpec.describe Gitlab::EndpointAttributes, feature_category: :api do
let(:base_controller) do
Class.new do
include ::Gitlab::EndpointAttributes
diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb
index fa0b3d1c6dd..d25511843ff 100644
--- a/spec/lib/gitlab/etag_caching/middleware_spec.rb
+++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb
@@ -145,8 +145,11 @@ RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state
expect(payload[:headers].env['HTTP_IF_NONE_MATCH']).to eq('W/"123"')
end
- it 'log subscriber processes action' do
- expect_any_instance_of(ActionController::LogSubscriber).to receive(:process_action)
+ it "publishes process_action.action_controller event to be picked up by lograge's subscriber" do
+ # Lograge unhooks the default Rails subscriber (ActionController::LogSubscriber)
+ # and replaces with its own (Lograge::LogSubscribers::ActionController).
+ # When `lograge.keep_original_rails_log = true`, ActionController::LogSubscriber is kept.
+ expect_any_instance_of(Lograge::LogSubscribers::ActionController).to receive(:process_action)
.with(instance_of(ActiveSupport::Notifications::Event))
.and_call_original
diff --git a/spec/lib/gitlab/exception_log_formatter_spec.rb b/spec/lib/gitlab/exception_log_formatter_spec.rb
index 7dda56f0bf5..82166971603 100644
--- a/spec/lib/gitlab/exception_log_formatter_spec.rb
+++ b/spec/lib/gitlab/exception_log_formatter_spec.rb
@@ -45,6 +45,12 @@ RSpec.describe Gitlab::ExceptionLogFormatter do
allow(exception).to receive(:cause).and_return(ActiveRecord::StatementInvalid.new(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND "users"."foo" = $1'))
end
+ it 'adds the cause_class to payload' do
+ described_class.format!(exception, payload)
+
+ expect(payload['exception.cause_class']).to eq('ActiveRecord::StatementInvalid')
+ end
+
it 'adds the normalized SQL query to payload' do
described_class.format!(exception, payload)
diff --git a/spec/lib/gitlab/external_authorization/config_spec.rb b/spec/lib/gitlab/external_authorization/config_spec.rb
index 4231b0d3747..f1daa9249f4 100644
--- a/spec/lib/gitlab/external_authorization/config_spec.rb
+++ b/spec/lib/gitlab/external_authorization/config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ExternalAuthorization::Config, feature_category: :authentication_and_authorization do
+RSpec.describe Gitlab::ExternalAuthorization::Config, feature_category: :system_access do
it 'allows deploy tokens and keys when external authorization is disabled' do
stub_application_setting(external_authorization_service_enabled: false)
expect(described_class.allow_deploy_tokens_and_deploy_keys?).to be_eql(true)
diff --git a/spec/lib/gitlab/file_finder_spec.rb b/spec/lib/gitlab/file_finder_spec.rb
index 27750f10e87..8afaec3c381 100644
--- a/spec/lib/gitlab/file_finder_spec.rb
+++ b/spec/lib/gitlab/file_finder_spec.rb
@@ -13,124 +13,58 @@ RSpec.describe Gitlab::FileFinder, feature_category: :global_search do
let(:expected_file_by_content) { 'CHANGELOG' }
end
- context 'when code_basic_search_files_by_regexp is enabled' do
- before do
- stub_feature_flags(code_basic_search_files_by_regexp: true)
- end
-
- context 'with inclusive filters' do
- it 'filters by filename' do
- results = subject.find('files filename:wm.svg')
-
- expect(results.count).to eq(1)
- end
-
- it 'filters by path' do
- results = subject.find('white path:images')
-
- expect(results.count).to eq(2)
- end
-
- it 'filters by extension' do
- results = subject.find('files extension:md')
-
- expect(results.count).to eq(4)
- end
- end
-
- context 'with exclusive filters' do
- it 'filters by filename' do
- results = subject.find('files -filename:wm.svg')
-
- expect(results.count).to eq(26)
- end
-
- it 'filters by path' do
- results = subject.find('white -path:images')
-
- expect(results.count).to eq(5)
- end
-
- it 'filters by extension' do
- results = subject.find('files -extension:md')
+ context 'with inclusive filters' do
+ it 'filters by filename' do
+ results = subject.find('files filename:wm.svg')
- expect(results.count).to eq(23)
- end
+ expect(results.count).to eq(1)
end
- context 'with white space in the path' do
- it 'filters by path correctly' do
- results = subject.find('directory path:"with space/README.md"')
+ it 'filters by path' do
+ results = subject.find('white path:images')
- expect(results.count).to eq(1)
- end
+ expect(results.count).to eq(2)
end
- it 'does not cause N+1 query' do
- expect(Gitlab::GitalyClient).to receive(:call).at_most(10).times.and_call_original
+ it 'filters by extension' do
+ results = subject.find('files extension:md')
- subject.find(': filename:wm.svg')
+ expect(results.count).to eq(4)
end
end
- context 'when code_basic_search_files_by_regexp is disabled' do
- before do
- stub_feature_flags(code_basic_search_files_by_regexp: false)
- end
-
- context 'with inclusive filters' do
- it 'filters by filename' do
- results = subject.find('files filename:wm.svg')
-
- expect(results.count).to eq(1)
- end
-
- it 'filters by path' do
- results = subject.find('white path:images')
-
- expect(results.count).to eq(1)
- end
-
- it 'filters by extension' do
- results = subject.find('files extension:md')
+ context 'with exclusive filters' do
+ it 'filters by filename' do
+ results = subject.find('files -filename:wm.svg')
- expect(results.count).to eq(4)
- end
+ expect(results.count).to eq(26)
end
- context 'with exclusive filters' do
- it 'filters by filename' do
- results = subject.find('files -filename:wm.svg')
+ it 'filters by path' do
+ results = subject.find('white -path:images')
- expect(results.count).to eq(26)
- end
-
- it 'filters by path' do
- results = subject.find('white -path:images')
-
- expect(results.count).to eq(4)
- end
+ expect(results.count).to eq(5)
+ end
- it 'filters by extension' do
- results = subject.find('files -extension:md')
+ it 'filters by extension' do
+ results = subject.find('files -extension:md')
- expect(results.count).to eq(23)
- end
+ expect(results.count).to eq(23)
end
+ end
- context 'with white space in the path' do
- it 'filters by path correctly' do
- results = subject.find('directory path:"with space/README.md"')
+ context 'with white space in the path' do
+ it 'filters by path correctly' do
+ results = subject.find('directory path:"with space/README.md"')
- expect(results.count).to eq(1)
- end
+ expect(results.count).to eq(1)
end
+ end
- it 'does not cause N+1 query' do
- expect(Gitlab::GitalyClient).to receive(:call).at_most(10).times.and_call_original
+ it 'does not cause N+1 query' do
+ expect(Gitlab::GitalyClient).to receive(:call).at_most(10).times.and_call_original
- subject.find(': filename:wm.svg')
- end
+ subject.find(': filename:wm.svg')
end
end
end
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index d873151421d..26af9d5d5b8 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -660,7 +660,8 @@ RSpec.describe Gitlab::Git::Commit do
id: SeedRepo::Commit::ID,
message: "tree css fixes",
parent_ids: ["874797c3a73b60d2187ed6e2fcabd289ff75171e"],
- trailers: {}
+ trailers: {},
+ referenced_by: []
}
end
end
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index 7fa5bd8a92b..5fa0447091c 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -777,6 +777,26 @@ RSpec.describe Gitlab::Git::DiffCollection do
end
end
+ describe '.limits' do
+ let(:options) { {} }
+
+ subject { described_class.limits(options) }
+
+ context 'when options do not include max_patch_bytes_for_file_extension' do
+ it 'sets max_patch_bytes_for_file_extension as empty' do
+ expect(subject[:max_patch_bytes_for_file_extension]).to eq({})
+ end
+ end
+
+ context 'when options include max_patch_bytes_for_file_extension' do
+ let(:options) { { max_patch_bytes_for_file_extension: { '.file' => 1 } } }
+
+ it 'sets value for max_patch_bytes_for_file_extension' do
+ expect(subject[:max_patch_bytes_for_file_extension]).to eq({ '.file' => 1 })
+ end
+ end
+ end
+
def fake_diff(line_length, line_count)
{ 'diff' => "#{'a' * line_length}\n" * line_count }
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 72043ba2a21..483140052f0 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1794,47 +1794,37 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen
end
describe '#license' do
- where(from_gitaly: [true, false])
- with_them do
- subject(:license) { repository.license(from_gitaly) }
-
- context 'when no license file can be found' do
- let_it_be(:project) { create(:project, :repository) }
- let(:repository) { project.repository.raw_repository }
+ subject(:license) { repository.license }
- before do
- project.repository.delete_file(project.owner, 'LICENSE', message: 'remove license', branch_name: 'master')
- end
+ context 'when no license file can be found' do
+ let_it_be(:project) { create(:project, :repository) }
+ let(:repository) { project.repository.raw_repository }
- it { is_expected.to be_nil }
+ before do
+ project.repository.delete_file(project.owner, 'LICENSE', message: 'remove license', branch_name: 'master')
end
- context 'when an mit license is found' do
- it { is_expected.to have_attributes(key: 'mit') }
- end
+ it { is_expected.to be_nil }
+ end
- context 'when license is not recognized ' do
- let_it_be(:project) { create(:project, :repository) }
- let(:repository) { project.repository.raw_repository }
+ context 'when an mit license is found' do
+ it { is_expected.to have_attributes(key: 'mit') }
+ end
- before do
- project.repository.update_file(
- project.owner,
- 'LICENSE',
- 'This software is licensed under the Dummy license.',
- message: 'Update license',
- branch_name: 'master')
- end
+ context 'when license is not recognized ' do
+ let_it_be(:project) { create(:project, :repository) }
+ let(:repository) { project.repository.raw_repository }
- it { is_expected.to have_attributes(key: 'other', nickname: 'LICENSE') }
+ before do
+ project.repository.update_file(
+ project.owner,
+ 'LICENSE',
+ 'This software is licensed under the Dummy license.',
+ message: 'Update license',
+ branch_name: 'master')
end
- end
-
- it 'does not crash when license is invalid' do
- expect(Licensee::License).to receive(:new)
- .and_raise(Licensee::InvalidLicense)
- expect(repository.license(false)).to be_nil
+ it { is_expected.to have_attributes(key: 'other', nickname: 'LICENSE') }
end
end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index ea2c239df07..13e9aeb4c53 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GitAccess, :aggregate_failures, feature_category: :authentication_and_authorization do
+RSpec.describe Gitlab::GitAccess, :aggregate_failures, feature_category: :system_access do
include TermsHelper
include AdminModeHelper
include ExternalAuthorizationServiceHelpers
diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
index 09d8ea3cc0a..7bdfa8922d3 100644
--- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
@@ -213,8 +213,13 @@ RSpec.describe Gitlab::GitalyClient::RefService, feature_category: :gitaly do
client.local_branches(sort_by: 'name_asc')
end
- it 'raises an argument error if an invalid sort_by parameter is passed' do
- expect { client.local_branches(sort_by: 'invalid_sort') }.to raise_error(ArgumentError)
+ it 'uses default sort by name' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:find_local_branches)
+ .with(gitaly_request_with_params(sort_by: :NAME), kind_of(Hash))
+ .and_return([])
+
+ client.local_branches(sort_by: 'invalid')
end
end
@@ -270,6 +275,17 @@ RSpec.describe Gitlab::GitalyClient::RefService, feature_category: :gitaly do
client.tags(sort_by: 'version_asc')
end
end
+
+ context 'when sorting option is invalid' do
+ it 'uses default sort by name' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:find_all_tags)
+ .with(gitaly_request_with_params(sort_by: nil), kind_of(Hash))
+ .and_return([])
+
+ client.tags(sort_by: 'invalid')
+ end
+ end
end
context 'with pagination option' do
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
index 434550186c1..f457ba06074 100644
--- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -275,7 +275,8 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
it 'sends a create_repository message without arguments' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:create_repository)
- .with(gitaly_request_with_path(storage_name, relative_path).and(gitaly_request_with_params(default_branch: '')), kind_of(Hash))
+ .with(gitaly_request_with_path(storage_name, relative_path)
+ .and(gitaly_request_with_params(default_branch: '')), kind_of(Hash))
.and_return(double)
client.create_repository
@@ -284,11 +285,23 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
it 'sends a create_repository message with default branch' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:create_repository)
- .with(gitaly_request_with_path(storage_name, relative_path).and(gitaly_request_with_params(default_branch: 'default-branch-name')), kind_of(Hash))
+ .with(gitaly_request_with_path(storage_name, relative_path)
+ .and(gitaly_request_with_params(default_branch: 'default-branch-name')), kind_of(Hash))
.and_return(double)
client.create_repository('default-branch-name')
end
+
+ it 'sends a create_repository message with default branch containing non ascii chars' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:create_repository)
+ .with(gitaly_request_with_path(storage_name, relative_path)
+ .and(gitaly_request_with_params(
+ default_branch: Gitlab::EncodingHelper.encode_binary('feature/新機能'))), kind_of(Hash)
+ ).and_return(double)
+
+ client.create_repository('feature/新機能')
+ end
end
describe '#create_from_snapshot' do
@@ -314,17 +327,31 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
end
describe '#search_files_by_regexp' do
- subject(:result) { client.search_files_by_regexp('master', '.*') }
+ subject(:result) { client.search_files_by_regexp(ref, '.*') }
before do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:search_files_by_name)
- .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
- .and_return([double(files: ['file1.txt']), double(files: ['file2.txt'])])
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return([double(files: ['file1.txt']), double(files: ['file2.txt'])])
end
- it 'sends a search_files_by_name message and returns a flatten array' do
- expect(result).to contain_exactly('file1.txt', 'file2.txt')
+ shared_examples 'a search for files by regexp' do
+ it 'sends a search_files_by_name message and returns a flatten array' do
+ expect(result).to contain_exactly('file1.txt', 'file2.txt')
+ end
+ end
+
+ context 'with ASCII ref' do
+ let(:ref) { 'master' }
+
+ it_behaves_like 'a search for files by regexp'
+ end
+
+ context 'with non-ASCII ref' do
+ let(:ref) { 'ref-ñéüçæøß-val' }
+
+ it_behaves_like 'a search for files by regexp'
end
end
diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb
index e93d585bc3c..e37b27aeaef 100644
--- a/spec/lib/gitlab/github_import/client_spec.rb
+++ b/spec/lib/gitlab/github_import/client_spec.rb
@@ -600,7 +600,8 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
endCursor
hasNextPage
hasPreviousPage
- }
+ },
+ repositoryCount
}
}
TEXT
@@ -707,44 +708,30 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
end
end
- describe '#search_repos_by_name' do
- let(:expected_query) { 'test in:name is:public,private user:user repo:repo1 repo:repo2 org:org1 org:org2' }
-
- it 'searches for repositories based on name' do
- expect(client.octokit).to receive(:search_repositories).with(expected_query, {})
+ describe '#count_repos_by_relation_type_graphql' do
+ relation_types = {
+ 'owned' => ' in:name is:public,private user:user',
+ 'collaborated' => ' in:name is:public,private repo:repo1 repo:repo2',
+ 'organization' => 'org:org1 org:org2'
+ }
- client.search_repos_by_name('test')
- end
+ relation_types.each do |relation_type, expected_query|
+ expected_graphql_params = "type: REPOSITORY, query: \"#{expected_query}\""
+ expected_graphql =
+ <<-TEXT
+ {
+ search(#{expected_graphql_params}) {
+ repositoryCount
+ }
+ }
+ TEXT
- context 'when pagination options present' do
- it 'searches for repositories via expected query' do
- expect(client.octokit).to receive(:search_repositories).with(
- expected_query, { page: 2, per_page: 25 }
+ it 'returns count by relation_type' do
+ expect(client.octokit).to receive(:post).with(
+ '/graphql', { query: expected_graphql }.to_json
)
- client.search_repos_by_name('test', { page: 2, per_page: 25 })
- end
- end
-
- context 'when Faraday error received from octokit', :aggregate_failures do
- let(:error_class) { described_class::CLIENT_CONNECTION_ERROR }
- let(:info_params) { { 'error.class': error_class } }
-
- it 'retries on error and succeeds' do
- allow_retry(:search_repositories)
-
- expect(Gitlab::Import::Logger).to receive(:info).with(hash_including(info_params)).once
-
- expect(client.search_repos_by_name('test')).to eq({})
- end
-
- it 'retries and does not succeed' do
- allow(client.octokit)
- .to receive(:search_repositories)
- .with(expected_query, {})
- .and_raise(error_class, 'execution expired')
-
- expect { client.search_repos_by_name('test') }.to raise_error(error_class, 'execution expired')
+ client.count_repos_by_relation_type_graphql(relation_type: relation_type)
end
end
end
diff --git a/spec/lib/gitlab/github_import/clients/proxy_spec.rb b/spec/lib/gitlab/github_import/clients/proxy_spec.rb
index 0baff7bafcb..7b2a8fa9d74 100644
--- a/spec/lib/gitlab/github_import/clients/proxy_spec.rb
+++ b/spec/lib/gitlab/github_import/clients/proxy_spec.rb
@@ -8,6 +8,10 @@ RSpec.describe Gitlab::GithubImport::Clients::Proxy, :manage, feature_category:
let(:access_token) { 'test_token' }
let(:client_options) { { foo: :bar } }
+ it { expect(client).to delegate_method(:each_object).to(:client) }
+ it { expect(client).to delegate_method(:user).to(:client) }
+ it { expect(client).to delegate_method(:octokit).to(:client) }
+
describe '#repos' do
let(:search_text) { 'search text' }
let(:pagination_options) { { limit: 10 } }
@@ -15,54 +19,32 @@ RSpec.describe Gitlab::GithubImport::Clients::Proxy, :manage, feature_category:
context 'when remove_legacy_github_client FF is enabled' do
let(:client_stub) { instance_double(Gitlab::GithubImport::Client) }
- context 'with github_client_fetch_repos_via_graphql FF enabled' do
- let(:client_response) do
- {
- data: {
- search: {
- nodes: [{ name: 'foo' }, { name: 'bar' }],
- pageInfo: { startCursor: 'foo', endCursor: 'bar' }
- }
+ let(:client_response) do
+ {
+ data: {
+ search: {
+ nodes: [{ name: 'foo' }, { name: 'bar' }],
+ pageInfo: { startCursor: 'foo', endCursor: 'bar' },
+ repositoryCount: 2
}
}
- end
-
- it 'fetches repos with Gitlab::GithubImport::Client (GraphQL API)' do
- expect(Gitlab::GithubImport::Client)
- .to receive(:new).with(access_token).and_return(client_stub)
- expect(client_stub)
- .to receive(:search_repos_by_name_graphql)
- .with(search_text, pagination_options).and_return(client_response)
-
- expect(client.repos(search_text, pagination_options)).to eq(
- {
- repos: [{ name: 'foo' }, { name: 'bar' }],
- page_info: { startCursor: 'foo', endCursor: 'bar' }
- }
- )
- end
+ }
end
- context 'with github_client_fetch_repos_via_graphql FF disabled' do
- let(:client_response) do
- { items: [{ name: 'foo' }, { name: 'bar' }] }
- end
-
- before do
- stub_feature_flags(github_client_fetch_repos_via_graphql: false)
- end
-
- it 'fetches repos with Gitlab::GithubImport::Client (REST API)' do
- expect(Gitlab::GithubImport::Client)
- .to receive(:new).with(access_token).and_return(client_stub)
- expect(client_stub)
- .to receive(:search_repos_by_name)
- .with(search_text, pagination_options).and_return(client_response)
+ it 'fetches repos with Gitlab::GithubImport::Client (GraphQL API)' do
+ expect(Gitlab::GithubImport::Client)
+ .to receive(:new).with(access_token).and_return(client_stub)
+ expect(client_stub)
+ .to receive(:search_repos_by_name_graphql)
+ .with(search_text, pagination_options).and_return(client_response)
- expect(client.repos(search_text, pagination_options)).to eq(
- { repos: [{ name: 'foo' }, { name: 'bar' }] }
- )
- end
+ expect(client.repos(search_text, pagination_options)).to eq(
+ {
+ repos: [{ name: 'foo' }, { name: 'bar' }],
+ page_info: { startCursor: 'foo', endCursor: 'bar' },
+ count: 2
+ }
+ )
end
end
@@ -99,4 +81,59 @@ RSpec.describe Gitlab::GithubImport::Clients::Proxy, :manage, feature_category:
end
end
end
+
+ describe '#count_by', :clean_gitlab_redis_cache do
+ context 'when remove_legacy_github_client FF is enabled' do
+ let(:client_stub) { instance_double(Gitlab::GithubImport::Client) }
+ let(:client_response) { { data: { search: { repositoryCount: 1 } } } }
+
+ before do
+ stub_feature_flags(remove_legacy_github_client: true)
+ end
+
+ context 'when value is cached' do
+ before do
+ Gitlab::Cache::Import::Caching.write('github-importer/provider-repo-count/owned/user_id', 3)
+ end
+
+ it 'returns repository count from cache' do
+ expect(Gitlab::GithubImport::Client)
+ .to receive(:new).with(access_token).and_return(client_stub)
+ expect(client_stub)
+ .not_to receive(:count_repos_by_relation_type_graphql)
+ .with({ relation_type: 'owned' })
+ expect(client.count_repos_by('owned', 'user_id')).to eq(3)
+ end
+ end
+
+ context 'when value is not cached' do
+ it 'returns repository count' do
+ expect(Gitlab::GithubImport::Client)
+ .to receive(:new).with(access_token).and_return(client_stub)
+ expect(client_stub)
+ .to receive(:count_repos_by_relation_type_graphql)
+ .with({ relation_type: 'owned' }).and_return(client_response)
+ expect(Gitlab::Cache::Import::Caching)
+ .to receive(:write)
+ .with('github-importer/provider-repo-count/owned/user_id', 1, timeout: 5.minutes)
+ .and_call_original
+ expect(client.count_repos_by('owned', 'user_id')).to eq(1)
+ end
+ end
+ end
+
+ context 'when remove_legacy_github_client FF is disabled' do
+ let(:client_stub) { instance_double(Gitlab::LegacyGithubImport::Client) }
+
+ before do
+ stub_feature_flags(remove_legacy_github_client: false)
+ end
+
+ it 'returns nil' do
+ expect(Gitlab::LegacyGithubImport::Client)
+ .to receive(:new).with(access_token, client_options).and_return(client_stub)
+ expect(client.count_repos_by('owned', 'user_id')).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/github_import/importer/collaborator_importer_spec.rb b/spec/lib/gitlab/github_import/importer/collaborator_importer_spec.rb
new file mode 100644
index 00000000000..07c10fe57f0
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/collaborator_importer_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Importer::CollaboratorImporter, feature_category: :importers do
+ subject(:importer) { described_class.new(collaborator, project, client) }
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository, group: group) }
+ let_it_be(:user) { create(:user) }
+
+ let(:client) { instance_double(Gitlab::GithubImport::Client) }
+ let(:github_user_id) { rand(1000) }
+ let(:collaborator) do
+ Gitlab::GithubImport::Representation::Collaborator.from_json_hash(
+ 'id' => github_user_id,
+ 'login' => user.username,
+ 'role_name' => github_role_name
+ )
+ end
+
+ let(:basic_member_attrs) do
+ {
+ source: project,
+ user_id: user.id,
+ member_namespace_id: project.project_namespace_id,
+ created_by_id: project.creator_id
+ }.stringify_keys
+ end
+
+ describe '#execute' do
+ before do
+ allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder|
+ allow(finder).to receive(:find).with(github_user_id, user.username).and_return(user.id)
+ end
+ end
+
+ shared_examples 'role mapping' do |collaborator_role, member_access_level|
+ let(:github_role_name) { collaborator_role }
+
+ it 'creates expected member' do
+ expect { importer.execute }.to change { project.members.count }
+ .from(0).to(1)
+
+ expected_member_attrs = basic_member_attrs.merge(access_level: member_access_level)
+ expect(project.members.last).to have_attributes(expected_member_attrs)
+ end
+ end
+
+ it_behaves_like 'role mapping', 'read', Gitlab::Access::GUEST
+ it_behaves_like 'role mapping', 'triage', Gitlab::Access::REPORTER
+ it_behaves_like 'role mapping', 'write', Gitlab::Access::DEVELOPER
+ it_behaves_like 'role mapping', 'maintain', Gitlab::Access::MAINTAINER
+ it_behaves_like 'role mapping', 'admin', Gitlab::Access::OWNER
+
+ context 'when role name is unknown (custom role)' do
+ let(:github_role_name) { 'custom_role' }
+
+ it 'raises expected error' do
+ expect { importer.execute }.to raise_exception(
+ ::Gitlab::GithubImport::ObjectImporter::NotRetriableError
+ ).with_message("Unknown GitHub role: #{github_role_name}")
+ end
+ end
+
+ context 'when user has lower role in a project group' do
+ before do
+ create(:group_member, group: group, user: user, access_level: Gitlab::Access::DEVELOPER)
+ end
+
+ it_behaves_like 'role mapping', 'maintain', Gitlab::Access::MAINTAINER
+ end
+
+ context 'when user has higher role in a project group' do
+ let(:github_role_name) { 'write' }
+
+ before do
+ create(:group_member, group: group, user: user, access_level: Gitlab::Access::MAINTAINER)
+ end
+
+ it 'skips creating member for the project' do
+ expect { importer.execute }.not_to change { project.members.count }
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb b/spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb
new file mode 100644
index 00000000000..e48b562279e
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Importer::CollaboratorsImporter, feature_category: :importers do
+ subject(:importer) { described_class.new(project, client, parallel: parallel) }
+
+ let(:parallel) { true }
+ let(:project) { instance_double(Project, id: 4, import_source: 'foo/bar', import_state: nil) }
+ let(:client) { instance_double(Gitlab::GithubImport::Client) }
+
+ let(:github_collaborator) do
+ {
+ id: 100500,
+ login: 'bob',
+ role_name: 'maintainer'
+ }
+ end
+
+ describe '#parallel?' do
+ context 'when parallel option is true' do
+ it { expect(importer).to be_parallel }
+ end
+
+ context 'when parallel option is false' do
+ let(:parallel) { false }
+
+ it { expect(importer).not_to be_parallel }
+ end
+ end
+
+ describe '#execute' do
+ context 'when running in parallel mode' do
+ it 'imports collaborators in parallel' do
+ expect(importer).to receive(:parallel_import)
+ importer.execute
+ end
+ end
+
+ context 'when running in sequential mode' do
+ let(:parallel) { false }
+
+ it 'imports collaborators in sequence' do
+ expect(importer).to receive(:sequential_import)
+ importer.execute
+ end
+ end
+ end
+
+ describe '#sequential_import' do
+ let(:parallel) { false }
+
+ it 'imports each collaborator in sequence' do
+ collaborator_importer = instance_double(Gitlab::GithubImport::Importer::CollaboratorImporter)
+
+ allow(importer)
+ .to receive(:each_object_to_import)
+ .and_yield(github_collaborator)
+
+ expect(Gitlab::GithubImport::Importer::CollaboratorImporter)
+ .to receive(:new)
+ .with(
+ an_instance_of(Gitlab::GithubImport::Representation::Collaborator),
+ project,
+ client
+ )
+ .and_return(collaborator_importer)
+
+ expect(collaborator_importer).to receive(:execute)
+
+ importer.sequential_import
+ end
+ end
+
+ describe '#parallel_import', :clean_gitlab_redis_cache do
+ let(:page_struct) { Struct.new(:objects, :number, keyword_init: true) }
+
+ before do
+ allow(client).to receive(:each_page)
+ .with(:collaborators, project.import_source, { page: 1 })
+ .and_yield(page_struct.new(number: 1, objects: [github_collaborator]))
+ end
+
+ it 'imports each collaborator in parallel' do
+ expect(Gitlab::GithubImport::ImportCollaboratorWorker).to receive(:perform_in)
+ .with(1.second, project.id, an_instance_of(Hash), an_instance_of(String))
+
+ waiter = importer.parallel_import
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(1)
+ end
+
+ context 'when collaborator is already imported' do
+ before do
+ Gitlab::Cache::Import::Caching.set_add(
+ "github-importer/already-imported/#{project.id}/collaborators",
+ github_collaborator[:id]
+ )
+ end
+
+ it "doesn't run importer on it" do
+ expect(Gitlab::GithubImport::ImportCollaboratorWorker).not_to receive(:perform_in)
+
+ waiter = importer.parallel_import
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(0)
+ end
+ end
+ end
+
+ describe '#id_for_already_imported_cache' do
+ it 'returns the ID of the given note' do
+ expect(importer.id_for_already_imported_cache(github_collaborator))
+ .to eq(100500)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb b/spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb
index e005d8eda84..16816dfbcea 100644
--- a/spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb
@@ -44,6 +44,10 @@ RSpec.describe Gitlab::GithubImport::Importer::LabelLinksImporter do
end
it 'does not insert label links for non-existing labels' do
+ expect(importer)
+ .to receive(:find_target_id)
+ .and_return(4)
+
expect(importer.label_finder)
.to receive(:id_for)
.with('bug')
@@ -55,6 +59,20 @@ RSpec.describe Gitlab::GithubImport::Importer::LabelLinksImporter do
importer.create_labels
end
+
+ it 'does not insert label links for non-existing targets' do
+ expect(importer)
+ .to receive(:find_target_id)
+ .and_return(nil)
+
+ expect(importer.label_finder)
+ .not_to receive(:id_for)
+
+ expect(LabelLink)
+ .not_to receive(:bulk_insert!)
+
+ importer.create_labels
+ end
end
describe '#find_target_id' do
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 7d4e3c3bcce..450ebe9a719 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
@@ -2,10 +2,10 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter do
+RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter, feature_category: :importers do
subject(:importer) { described_class.new(note_text, project, client) }
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, import_source: 'nickname/public-test-repo') }
let(:note_text) { Gitlab::GithubImport::Representation::NoteText.from_db_record(record) }
let(:client) { instance_double('Gitlab::GithubImport::Client') }
@@ -13,6 +13,8 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter do
let(:doc_url) { 'https://github.com/nickname/public-test-repo/files/9020437/git-cheat-sheet.txt' }
let(:image_url) { 'https://user-images.githubusercontent.com/6833842/0cf366b61ef2.jpeg' }
let(:image_tag_url) { 'https://user-images.githubusercontent.com/6833842/0cf366b61ea5.jpeg' }
+ let(:project_blob_url) { 'https://github.com/nickname/public-test-repo/blob/main/example.md' }
+ let(:other_project_blob_url) { 'https://github.com/nickname/other-repo/blob/main/README.md' }
let(:text) do
<<-TEXT.split("\n").map(&:strip).join("\n")
Some text...
@@ -20,11 +22,14 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter do
[special-doc](#{doc_url})
![image.jpeg](#{image_url})
<img width=\"248\" alt=\"tag-image\" src="#{image_tag_url}">
+
+ [link to project blob file](#{project_blob_url})
+ [link to other project blob file](#{other_project_blob_url})
TEXT
end
shared_examples 'updates record description' do
- it do
+ it 'changes attachment links' do
importer.execute
record.reload
@@ -32,6 +37,22 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter do
expect(record.description).to include('![image.jpeg](/uploads/')
expect(record.description).to include('<img width="248" alt="tag-image" src="/uploads')
end
+
+ it 'changes link to project blob files' do
+ importer.execute
+
+ record.reload
+ expected_blob_link = "[link to project blob file](http://localhost/#{project.full_path}/-/blob/main/example.md)"
+ expect(record.description).not_to include("[link to project blob file](#{project_blob_url})")
+ expect(record.description).to include(expected_blob_link)
+ end
+
+ it "doesn't change links to other projects" do
+ importer.execute
+
+ record.reload
+ expect(record.description).to include("[link to other project blob file](#{other_project_blob_url})")
+ end
end
describe '#execute' do
@@ -72,7 +93,7 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter do
context 'when importing note attachments' do
let(:record) { create(:note, project: project, note: text) }
- it 'updates note text with new attachment urls' do
+ it 'changes note text with new attachment urls' do
importer.execute
record.reload
@@ -80,6 +101,22 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter do
expect(record.note).to include('![image.jpeg](/uploads/')
expect(record.note).to include('<img width="248" alt="tag-image" src="/uploads')
end
+
+ it 'changes note links to project blob files' do
+ importer.execute
+
+ record.reload
+ expected_blob_link = "[link to project blob file](http://localhost/#{project.full_path}/-/blob/main/example.md)"
+ expect(record.note).not_to include("[link to project blob file](#{project_blob_url})")
+ expect(record.note).to include(expected_blob_link)
+ end
+
+ it "doesn't change note links to other projects" do
+ importer.execute
+
+ record.reload
+ expect(record.note).to include("[link to other project blob file](#{other_project_blob_url})")
+ end
end
end
end
diff --git a/spec/lib/gitlab/github_import/markdown/attachment_spec.rb b/spec/lib/gitlab/github_import/markdown/attachment_spec.rb
index 588a3076f59..84b0886ebcc 100644
--- a/spec/lib/gitlab/github_import/markdown/attachment_spec.rb
+++ b/spec/lib/gitlab/github_import/markdown/attachment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Markdown::Attachment do
+RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :importers do
let(:name) { FFaker::Lorem.word }
let(:url) { FFaker::Internet.uri('https') }
@@ -101,6 +101,62 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment do
end
end
+ 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" }
+
+ it { expect(attachment.part_of_project_blob?(import_source)).to eq true }
+ end
+
+ context 'when url is not a part of project blob' do
+ let(:url) { "https://github.com/#{import_source}/files/9020437/git-cheat-sheet.txt" }
+
+ it { expect(attachment.part_of_project_blob?(import_source)).to eq false }
+ end
+ end
+
+ 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" }
+
+ it { expect(attachment.doc_belongs_to_project?(import_source)).to eq true }
+ end
+
+ context 'when url is not related to this project' do
+ let(:url) { 'https://github.com/nickname/other-repo/files/9020437/git-cheat-sheet.txt' }
+
+ it { expect(attachment.doc_belongs_to_project?(import_source)).to eq false }
+ end
+
+ context 'when url is a part of project blob' do
+ let(:url) { "https://github.com/#{import_source}/blob/main/example.md" }
+
+ it { expect(attachment.doc_belongs_to_project?(import_source)).to eq false }
+ end
+ end
+
+ describe '#media?' do
+ let(:attachment) { described_class.new('test', url) }
+
+ 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 }
+ 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 }
+ end
+ end
+
describe '#inspect' do
it 'returns attachment basic info' do
attachment = described_class.new(name, url)
diff --git a/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb b/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb
index c351ead91eb..9de39a3ff7e 100644
--- a/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb
+++ b/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb
@@ -289,77 +289,52 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling, feature_category: :impo
.and_return({ title: 'One' }, { title: 'Two' }, { title: 'Three' })
end
- context 'with multiple objects' do
- before do
- stub_feature_flags(improved_spread_parallel_import: false)
-
- expect(importer).to receive(:each_object_to_import).and_yield(object).and_yield(object).and_yield(object)
- end
-
- it 'imports data in parallel batches with delays' do
- expect(worker_class).to receive(:bulk_perform_in)
- .with(1.second, [
- [project.id, { title: 'One' }, an_instance_of(String)],
- [project.id, { title: 'Two' }, an_instance_of(String)],
- [project.id, { title: 'Three' }, an_instance_of(String)]
- ], batch_size: batch_size, batch_delay: batch_delay)
-
- importer.parallel_import
- end
+ it 'imports data in parallel with delays respecting parallel_import_batch definition and return job waiter' do
+ allow(::Gitlab::JobWaiter).to receive(:generate_key).and_return('waiter-key')
+ allow(importer).to receive(:parallel_import_batch).and_return({ size: 2, delay: 1.minute })
+
+ expect(importer).to receive(:each_object_to_import)
+ .and_yield(object).and_yield(object).and_yield(object)
+ expect(worker_class).to receive(:perform_in)
+ .with(1.second, project.id, { title: 'One' }, 'waiter-key').ordered
+ expect(worker_class).to receive(:perform_in)
+ .with(1.second, project.id, { title: 'Two' }, 'waiter-key').ordered
+ expect(worker_class).to receive(:perform_in)
+ .with(1.minute + 1.second, project.id, { title: 'Three' }, 'waiter-key').ordered
+
+ job_waiter = importer.parallel_import
+
+ expect(job_waiter.key).to eq('waiter-key')
+ expect(job_waiter.jobs_remaining).to eq(3)
end
- context 'when the feature flag `improved_spread_parallel_import` is enabled' do
+ context 'when job restarts due to API rate limit or Sidekiq interruption' do
before do
- stub_feature_flags(improved_spread_parallel_import: true)
+ cache_key = format(described_class::JOB_WAITER_CACHE_KEY,
+ project: project.id, collection: importer.collection_method)
+ Gitlab::Cache::Import::Caching.write(cache_key, 'waiter-key')
+
+ cache_key = format(described_class::JOB_WAITER_REMAINING_CACHE_KEY,
+ project: project.id, collection: importer.collection_method)
+ Gitlab::Cache::Import::Caching.write(cache_key, 3)
end
- it 'imports data in parallel with delays respecting parallel_import_batch definition and return job waiter' do
- allow(::Gitlab::JobWaiter).to receive(:generate_key).and_return('waiter-key')
- allow(importer).to receive(:parallel_import_batch).and_return({ size: 2, delay: 1.minute })
+ it "restores job waiter's key and jobs_remaining" do
+ allow(importer).to receive(:parallel_import_batch).and_return({ size: 1, delay: 1.minute })
+
+ expect(importer).to receive(:each_object_to_import).and_yield(object).and_yield(object).and_yield(object)
- expect(importer).to receive(:each_object_to_import)
- .and_yield(object).and_yield(object).and_yield(object)
expect(worker_class).to receive(:perform_in)
.with(1.second, project.id, { title: 'One' }, 'waiter-key').ordered
expect(worker_class).to receive(:perform_in)
- .with(1.second, project.id, { title: 'Two' }, 'waiter-key').ordered
+ .with(1.minute + 1.second, project.id, { title: 'Two' }, 'waiter-key').ordered
expect(worker_class).to receive(:perform_in)
- .with(1.minute + 1.second, project.id, { title: 'Three' }, 'waiter-key').ordered
+ .with(2.minutes + 1.second, project.id, { title: 'Three' }, 'waiter-key').ordered
job_waiter = importer.parallel_import
expect(job_waiter.key).to eq('waiter-key')
- expect(job_waiter.jobs_remaining).to eq(3)
- end
-
- context 'when job restarts due to API rate limit or Sidekiq interruption' do
- before do
- cache_key = format(described_class::JOB_WAITER_CACHE_KEY,
- project: project.id, collection: importer.collection_method)
- Gitlab::Cache::Import::Caching.write(cache_key, 'waiter-key')
-
- cache_key = format(described_class::JOB_WAITER_REMAINING_CACHE_KEY,
- project: project.id, collection: importer.collection_method)
- Gitlab::Cache::Import::Caching.write(cache_key, 3)
- end
-
- it "restores job waiter's key and jobs_remaining" do
- allow(importer).to receive(:parallel_import_batch).and_return({ size: 1, delay: 1.minute })
-
- expect(importer).to receive(:each_object_to_import).and_yield(object).and_yield(object).and_yield(object)
-
- expect(worker_class).to receive(:perform_in)
- .with(1.second, project.id, { title: 'One' }, 'waiter-key').ordered
- expect(worker_class).to receive(:perform_in)
- .with(1.minute + 1.second, project.id, { title: 'Two' }, 'waiter-key').ordered
- expect(worker_class).to receive(:perform_in)
- .with(2.minutes + 1.second, project.id, { title: 'Three' }, 'waiter-key').ordered
-
- job_waiter = importer.parallel_import
-
- expect(job_waiter.key).to eq('waiter-key')
- expect(job_waiter.jobs_remaining).to eq(6)
- end
+ expect(job_waiter.jobs_remaining).to eq(6)
end
end
end
diff --git a/spec/lib/gitlab/github_import/project_relation_type_spec.rb b/spec/lib/gitlab/github_import/project_relation_type_spec.rb
new file mode 100644
index 00000000000..419cb6de121
--- /dev/null
+++ b/spec/lib/gitlab/github_import/project_relation_type_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::ProjectRelationType, :manage, feature_category: :importers do
+ subject(:project_relation_type) { described_class.new(client) }
+
+ let(:octokit) { instance_double(Octokit::Client) }
+ let(:client) do
+ instance_double(Gitlab::GithubImport::Clients::Proxy, octokit: octokit, user: { login: 'nickname' })
+ end
+
+ describe '#for', :use_clean_rails_redis_caching do
+ before do
+ allow(client).to receive(:each_object).with(:organizations).and_yield({ login: 'great-org' })
+ allow(octokit).to receive(:access_token).and_return('stub')
+ end
+
+ context "when it's user owned repo" do
+ let(:import_source) { 'nickname/repo_name' }
+
+ it { expect(project_relation_type.for(import_source)).to eq 'owned' }
+ end
+
+ context "when it's organization repo" do
+ let(:import_source) { 'great-org/repo_name' }
+
+ it { expect(project_relation_type.for(import_source)).to eq 'organization' }
+ end
+
+ context "when it's user collaborated repo" do
+ let(:import_source) { 'some-another-namespace/repo_name' }
+
+ it { expect(project_relation_type.for(import_source)).to eq 'collaborated' }
+ end
+
+ context 'with cache' do
+ let(:import_source) { 'some-another-namespace/repo_name' }
+
+ it 'calls client only once during 5 minutes timeframe', :request_store do
+ expect(project_relation_type.for(import_source)).to eq 'collaborated'
+ expect(project_relation_type.for('another/repo')).to eq 'collaborated'
+
+ expect(client).to have_received(:each_object).once
+ expect(client).to have_received(:user).once
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/github_import/representation/collaborator_spec.rb b/spec/lib/gitlab/github_import/representation/collaborator_spec.rb
new file mode 100644
index 00000000000..d5952f9459b
--- /dev/null
+++ b/spec/lib/gitlab/github_import/representation/collaborator_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Representation::Collaborator, feature_category: :importers do
+ shared_examples 'a Collaborator' do
+ it 'returns an instance of Collaborator' do
+ expect(collaborator).to be_an_instance_of(described_class)
+ end
+
+ context 'with Collaborator' do
+ it 'includes the user ID' do
+ expect(collaborator.id).to eq(42)
+ end
+
+ it 'includes the username' do
+ expect(collaborator.login).to eq('alice')
+ end
+
+ it 'includes the role' do
+ expect(collaborator.role_name).to eq('maintainer')
+ end
+ end
+ end
+
+ describe '.from_api_response' do
+ it_behaves_like 'a Collaborator' do
+ let(:response) { { id: 42, login: 'alice', role_name: 'maintainer' } }
+ let(:collaborator) { described_class.from_api_response(response) }
+ end
+ end
+
+ describe '.from_json_hash' do
+ it_behaves_like 'a Collaborator' do
+ let(:hash) { { 'id' => 42, 'login' => 'alice', role_name: 'maintainer' } }
+ let(:collaborator) { described_class.from_json_hash(hash) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/i18n/pluralization_spec.rb b/spec/lib/gitlab/i18n/pluralization_spec.rb
new file mode 100644
index 00000000000..857562d549c
--- /dev/null
+++ b/spec/lib/gitlab/i18n/pluralization_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+require 'gettext_i18n_rails'
+
+RSpec.describe Gitlab::I18n::Pluralization, feature_category: :internationalization do
+ describe '.call' do
+ subject(:rule) { described_class.call(1) }
+
+ context 'with available locales' do
+ around do |example|
+ Gitlab::I18n.with_locale(locale, &example)
+ end
+
+ where(:locale) do
+ Gitlab::I18n.available_locales
+ end
+
+ with_them do
+ it 'supports pluralization' do
+ expect(rule).not_to be_nil
+ end
+ end
+
+ context 'with missing rules' do
+ let(:locale) { "pl_PL" }
+
+ before do
+ stub_const("#{described_class}::MAP", described_class::MAP.except(locale))
+ end
+
+ it 'raises an ArgumentError' do
+ expect { rule }.to raise_error(ArgumentError,
+ /Missing pluralization rule for locale "#{locale}"/
+ )
+ end
+ end
+ end
+ end
+
+ describe '.install_on' do
+ let(:mod) { Module.new }
+
+ before do
+ described_class.install_on(mod)
+ end
+
+ it 'adds pluralisation_rule method' do
+ expect(mod.pluralisation_rule).to eq(described_class)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/i18n_spec.rb b/spec/lib/gitlab/i18n_spec.rb
index b752d89bf0d..ee92831922d 100644
--- a/spec/lib/gitlab/i18n_spec.rb
+++ b/spec/lib/gitlab/i18n_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::I18n do
+RSpec.describe Gitlab::I18n, feature_category: :internationalization do
let(:user) { create(:user, preferred_language: :es) }
describe '.selectable_locales' do
@@ -47,4 +47,19 @@ RSpec.describe Gitlab::I18n do
expect(::I18n.locale).to eq(:en)
end
end
+
+ describe '.pluralisation_rule' do
+ context 'when overridden' do
+ before do
+ # Internally, FastGettext sets
+ # Thread.current[:fast_gettext_pluralisation_rule].
+ # Our patch patches `FastGettext.pluralisation_rule` instead.
+ FastGettext.pluralisation_rule = :something
+ end
+
+ it 'returns custom definition regardless' do
+ expect(FastGettext.pluralisation_rule).to eq(Gitlab::I18n::Pluralization)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/import/errors_spec.rb b/spec/lib/gitlab/import/errors_spec.rb
new file mode 100644
index 00000000000..f89cb36bbb4
--- /dev/null
+++ b/spec/lib/gitlab/import/errors_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Import::Errors, feature_category: :importers do
+ let_it_be(:project) { create(:project) }
+
+ describe '.merge_nested_errors' do
+ it 'merges nested collection errors' do
+ issue = project.issues.new(
+ title: 'test',
+ notes: [
+ Note.new(
+ award_emoji: [AwardEmoji.new(name: 'test')]
+ )
+ ],
+ sentry_issue: SentryIssue.new
+ )
+
+ issue.validate
+
+ expect(issue.errors.full_messages)
+ .to contain_exactly(
+ "Author can't be blank",
+ "Notes is invalid",
+ "Sentry issue sentry issue identifier can't be blank"
+ )
+
+ described_class.merge_nested_errors(issue)
+
+ expect(issue.errors.full_messages)
+ .to contain_exactly(
+ "Notes is invalid",
+ "Author can't be blank",
+ "Sentry issue sentry issue identifier can't be blank",
+ "Award emoji is invalid",
+ "Note can't be blank",
+ "Project can't be blank",
+ "Noteable can't be blank",
+ "Author can't be blank",
+ "Project does not match noteable project",
+ "User can't be blank",
+ "Awardable can't be blank",
+ "Name is not a valid emoji name"
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import/metrics_spec.rb b/spec/lib/gitlab/import/metrics_spec.rb
index 9b8b58d00f3..1a988af0dbd 100644
--- a/spec/lib/gitlab/import/metrics_spec.rb
+++ b/spec/lib/gitlab/import/metrics_spec.rb
@@ -11,7 +11,6 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
subject { described_class.new(importer, project) }
before do
- allow(Gitlab::Metrics).to receive(:counter) { counter }
allow(counter).to receive(:increment)
allow(histogram).to receive(:observe)
end
@@ -42,6 +41,13 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
context 'when project is not a github import' do
it 'does not emit importer metrics' do
expect(subject).not_to receive(:track_usage_event)
+ expect_no_snowplow_event(
+ category: :test_importer,
+ action: 'create',
+ label: 'github_import_project_state',
+ project: project,
+ extra: { import_type: 'github', state: 'failed' }
+ )
subject.track_failed_import
end
@@ -50,39 +56,81 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
context 'when project is a github import' do
before do
project.import_type = 'github'
+ allow(project).to receive(:import_status).and_return('failed')
end
it 'emits importer metrics' do
expect(subject).to receive(:track_usage_event).with(:github_import_project_failure, project.id)
subject.track_failed_import
+
+ expect_snowplow_event(
+ category: :test_importer,
+ action: 'create',
+ label: 'github_import_project_state',
+ project: project,
+ extra: { import_type: 'github', state: 'failed' }
+ )
end
end
end
describe '#track_finished_import' do
- before do
- allow(Gitlab::Metrics).to receive(:histogram) { histogram }
- end
+ context 'when project is a github import' do
+ before do
+ project.import_type = 'github'
+ allow(Gitlab::Metrics).to receive(:counter) { counter }
+ allow(Gitlab::Metrics).to receive(:histogram) { histogram }
+ allow(project).to receive(:beautified_import_status_name).and_return('completed')
+ end
- it 'emits importer metrics' do
- expect(Gitlab::Metrics).to receive(:counter).with(
- :test_importer_imported_projects_total,
- 'The number of imported projects'
- )
+ it 'emits importer metrics' do
+ expect(Gitlab::Metrics).to receive(:counter).with(
+ :test_importer_imported_projects_total,
+ 'The number of imported projects'
+ )
- expect(Gitlab::Metrics).to receive(:histogram).with(
- :test_importer_total_duration_seconds,
- 'Total time spent importing projects, in seconds',
- {},
- described_class::IMPORT_DURATION_BUCKETS
- )
+ expect(Gitlab::Metrics).to receive(:histogram).with(
+ :test_importer_total_duration_seconds,
+ 'Total time spent importing projects, in seconds',
+ {},
+ described_class::IMPORT_DURATION_BUCKETS
+ )
+
+ expect(counter).to receive(:increment)
- expect(counter).to receive(:increment)
+ subject.track_finished_import
- subject.track_finished_import
+ expect_snowplow_event(
+ category: :test_importer,
+ action: 'create',
+ label: 'github_import_project_state',
+ project: project,
+ extra: { import_type: 'github', state: 'completed' }
+ )
+
+ expect(subject.duration).not_to be_nil
+ end
- expect(subject.duration).not_to be_nil
+ context 'when import is partially completed' do
+ before do
+ allow(project).to receive(:beautified_import_status_name).and_return('partially completed')
+ end
+
+ it 'emits snowplow metrics' do
+ expect(subject).to receive(:track_usage_event).with(:github_import_project_partially_completed, project.id)
+
+ subject.track_finished_import
+
+ expect_snowplow_event(
+ category: :test_importer,
+ action: 'create',
+ label: 'github_import_project_state',
+ project: project,
+ extra: { import_type: 'github', state: 'partially completed' }
+ )
+ end
+ end
end
context 'when project is not a github import' do
@@ -91,7 +139,51 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
subject.track_finished_import
- expect(histogram).to have_received(:observe).with({ importer: :test_importer }, anything)
+ expect_no_snowplow_event(
+ category: :test_importer,
+ action: 'create',
+ label: 'github_import_project_state',
+ project: project,
+ extra: { import_type: 'github', state: 'completed' }
+ )
+ end
+ end
+ end
+
+ describe '#track_cancelled_import' do
+ context 'when project is not a github import' do
+ it 'does not emit importer metrics' do
+ expect(subject).not_to receive(:track_usage_event)
+ expect_no_snowplow_event(
+ category: :test_importer,
+ action: 'create',
+ label: 'github_import_project_state',
+ project: project,
+ extra: { import_type: 'github', state: 'canceled' }
+ )
+
+ subject.track_canceled_import
+ end
+ end
+
+ context 'when project is a github import' do
+ before do
+ project.import_type = 'github'
+ allow(project).to receive(:import_status).and_return('canceled')
+ end
+
+ it 'emits importer metrics' do
+ expect(subject).to receive(:track_usage_event).with(:github_import_project_cancelled, project.id)
+
+ subject.track_canceled_import
+
+ expect_snowplow_event(
+ category: :test_importer,
+ action: 'create',
+ label: 'github_import_project_state',
+ project: project,
+ extra: { import_type: 'github', state: 'canceled' }
+ )
end
end
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 0c2c3ffc664..f6d6a791e8c 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -92,6 +92,20 @@ notes:
- suggestions
- diff_note_positions
- review
+commit_notes:
+- award_emoji
+- noteable
+- author
+- updated_by
+- last_edited_by
+- resolved_by
+- todos
+- events
+- system_note_metadata
+- note_diff_file
+- suggestions
+- diff_note_positions
+- review
label_links:
- target
- label
@@ -283,6 +297,7 @@ ci_pipelines:
- job_artifacts
- vulnerabilities_finding_pipelines
- vulnerability_findings
+- vulnerability_state_transitions
- pipeline_config
- security_scans
- security_findings
@@ -317,6 +332,7 @@ stages:
- processables
- builds
- bridges
+- generic_commit_statuses
- latest_statuses
- retried_statuses
statuses:
@@ -327,6 +343,92 @@ statuses:
- auto_canceled_by
- needs
- ci_stage
+builds:
+- user
+- auto_canceled_by
+- ci_stage
+- needs
+- resource
+- pipeline
+- sourced_pipeline
+- resource_group
+- metadata
+- runner
+- trigger_request
+- erased_by
+- deployment
+- pending_state
+- queuing_entry
+- runtime_metadata
+- trace_chunks
+- report_results
+- namespace
+- job_artifacts
+- job_variables
+- sourced_pipelines
+- pages_deployments
+- job_artifacts_archive
+- job_artifacts_metadata
+- job_artifacts_trace
+- job_artifacts_junit
+- job_artifacts_sast
+- job_artifacts_dependency_scanning
+- job_artifacts_container_scanning
+- job_artifacts_dast
+- job_artifacts_codequality
+- job_artifacts_license_scanning
+- job_artifacts_performance
+- job_artifacts_metrics
+- job_artifacts_metrics_referee
+- job_artifacts_network_referee
+- job_artifacts_lsif
+- job_artifacts_dotenv
+- job_artifacts_cobertura
+- job_artifacts_terraform
+- job_artifacts_accessibility
+- job_artifacts_cluster_applications
+- job_artifacts_secret_detection
+- job_artifacts_requirements
+- job_artifacts_coverage_fuzzing
+- job_artifacts_browser_performance
+- job_artifacts_load_performance
+- job_artifacts_api_fuzzing
+- job_artifacts_cluster_image_scanning
+- job_artifacts_cyclonedx
+- job_artifacts_requirements_v2
+- runner_machine
+- runner_machine_build
+- runner_session
+- trace_metadata
+- terraform_state_versions
+- taggings
+- base_tags
+- tag_taggings
+- tags
+- security_scans
+- dast_site_profiles_build
+- dast_site_profile
+- dast_scanner_profiles_build
+- dast_scanner_profile
+bridges:
+- user
+- pipeline
+- auto_canceled_by
+- ci_stage
+- needs
+- resource
+- sourced_pipeline
+- resource_group
+- metadata
+- trigger_request
+- downstream_pipeline
+- upstream_pipeline
+generic_commit_statuses:
+- user
+- pipeline
+- auto_canceled_by
+- ci_stage
+- needs
variables:
- project
triggers:
@@ -408,6 +510,7 @@ project:
- project_namespace
- management_clusters
- boards
+- application_setting
- last_event
- integrations
- push_hooks_integrations
@@ -432,6 +535,7 @@ project:
- discord_integration
- drone_ci_integration
- emails_on_push_integration
+- google_play_integration
- pipelines_email_integration
- mattermost_slash_commands_integration
- shimo_integration
@@ -466,6 +570,7 @@ project:
- external_wiki_integration
- mock_ci_integration
- mock_monitoring_integration
+- squash_tm_integration
- forked_to_members
- forked_from_project
- forks
@@ -600,7 +705,7 @@ project:
- project_registry
- packages
- package_files
-- repository_files
+- rpm_repository_files
- packages_cleanup_policy
- alerting_setting
- project_setting
@@ -618,6 +723,7 @@ project:
- upstream_project_subscriptions
- downstream_project_subscriptions
- service_desk_setting
+- service_desk_custom_email_verification
- security_setting
- import_failures
- container_expiration_policy
@@ -859,6 +965,8 @@ bulk_import_export:
- group
service_desk_setting:
- file_template_project
+service_desk_custom_email_verification:
+ - triggerer
approvals:
- user
- merge_request
diff --git a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
index 572f809e43b..1d84cba3825 100644
--- a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
+++ b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
@@ -9,7 +9,7 @@ require 'spec_helper'
# to be included as part of the export, or blacklist them using the import_export.yml configuration file.
# Likewise, new models added to import_export.yml, will need to be added with their correspondent attributes
# to this spec.
-RSpec.describe 'Import/Export attribute configuration' do
+RSpec.describe 'Import/Export attribute configuration', feature_category: :importers do
include ConfigurationHelper
let(:safe_attributes_file) { 'spec/lib/gitlab/import_export/safe_model_attributes.yml' }
diff --git a/spec/lib/gitlab/import_export/attributes_finder_spec.rb b/spec/lib/gitlab/import_export/attributes_finder_spec.rb
index 6536b895b2f..767b7a3c84e 100644
--- a/spec/lib/gitlab/import_export/attributes_finder_spec.rb
+++ b/spec/lib/gitlab/import_export/attributes_finder_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::ImportExport::AttributesFinder do
+RSpec.describe Gitlab::ImportExport::AttributesFinder, feature_category: :importers do
describe '#find_root' do
subject { described_class.new(config: config).find_root(model_key) }
@@ -207,6 +207,19 @@ RSpec.describe Gitlab::ImportExport::AttributesFinder do
it { is_expected.to be_nil }
end
+
+ context 'when include_import_only_tree is true' do
+ subject { described_class.new(config: config).find_relations_tree(model_key, include_import_only_tree: true) }
+
+ let(:config) do
+ {
+ tree: { project: { ci_pipelines: { stages: { builds: nil } } } },
+ import_only_tree: { project: { ci_pipelines: { stages: { statuses: nil } } } }
+ }
+ end
+
+ it { is_expected.to eq({ ci_pipelines: { stages: { builds: nil, statuses: nil } } }) }
+ end
end
describe '#find_excluded_keys' do
diff --git a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
index c748f966463..8089b40cae8 100644
--- a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
+++ b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::AttributesPermitter do
+RSpec.describe Gitlab::ImportExport::AttributesPermitter, feature_category: :importers do
let(:yml_config) do
<<-EOF
tree:
@@ -12,6 +12,15 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter do
- milestones:
- events:
- :push_event_payload
+ - ci_pipelines:
+ - stages:
+ - :builds
+
+ import_only_tree:
+ project:
+ - ci_pipelines:
+ - stages:
+ - :statuses
included_attributes:
labels:
@@ -43,12 +52,16 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter do
it 'builds permitted attributes hash' do
expect(subject.permitted_attributes).to match(
a_hash_including(
- project: [:labels, :milestones],
+ project: [:labels, :milestones, :ci_pipelines],
labels: [:priorities, :title, :description, :type],
events: [:push_event_payload],
milestones: [:events],
priorities: [],
- push_event_payload: []
+ push_event_payload: [],
+ ci_pipelines: [:stages],
+ stages: [:builds, :statuses],
+ statuses: [],
+ builds: []
)
)
end
@@ -129,6 +142,9 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter do
:external_pull_request | true
:external_pull_requests | true
:statuses | true
+ :builds | true
+ :generic_commit_statuses | true
+ :bridges | true
:ci_pipelines | true
:stages | true
:actions | 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 a8b4b9a6f05..e42a1d0ff8b 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
@@ -82,24 +82,13 @@ RSpec.describe Gitlab::ImportExport::Base::RelationObjectSaver, feature_category
it 'saves valid subrelations and logs invalid subrelation' do
expect(relation_object.notes).to receive(:<<).twice.and_call_original
expect(relation_object).to receive(:save).and_call_original
- expect(Gitlab::Import::Logger)
- .to receive(:info)
- .with(
- message: '[Project/Group Import] Invalid subrelation',
- project_id: project.id,
- relation_key: 'issues',
- error_messages: "Project does not match noteable project"
- )
saver.execute
issue = project.issues.last
- import_failure = project.import_failures.last
expect(invalid_note.persisted?).to eq(false)
expect(issue.notes.count).to eq(5)
- expect(import_failure.source).to eq('RelationObjectSaver#save!')
- expect(import_failure.exception_message).to eq('Project does not match noteable project')
end
context 'when invalid subrelation can still be persisted' do
@@ -111,7 +100,6 @@ RSpec.describe Gitlab::ImportExport::Base::RelationObjectSaver, feature_category
it 'saves the subrelation' do
expect(approval_1.valid?).to eq(false)
- expect(Gitlab::Import::Logger).not_to receive(:info)
saver.execute
@@ -128,24 +116,10 @@ RSpec.describe Gitlab::ImportExport::Base::RelationObjectSaver, feature_category
let(:invalid_priority) { build(:label_priority, priority: -1) }
let(:relation_object) { build(:group_label, group: importable, title: 'test', priorities: valid_priorities + [invalid_priority]) }
- it 'logs invalid subrelation for a group' do
- expect(Gitlab::Import::Logger)
- .to receive(:info)
- .with(
- message: '[Project/Group Import] Invalid subrelation',
- group_id: importable.id,
- relation_key: 'labels',
- error_messages: 'Priority must be greater than or equal to 0'
- )
-
+ it 'saves relation without invalid subrelations' do
saver.execute
- label = importable.labels.last
- import_failure = importable.import_failures.last
-
- expect(label.priorities.count).to eq(5)
- expect(import_failure.source).to eq('RelationObjectSaver#save!')
- expect(import_failure.exception_message).to eq('Priority must be greater than or equal to 0')
+ expect(importable.labels.last.priorities.count).to eq(5)
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 f47f1ab58a8..91cfab1688a 100644
--- a/spec/lib/gitlab/import_export/command_line_util_spec.rb
+++ b/spec/lib/gitlab/import_export/command_line_util_spec.rb
@@ -2,13 +2,14 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::CommandLineUtil do
+RSpec.describe Gitlab::ImportExport::CommandLineUtil, feature_category: :importers do
include ExportFileHelper
let(:path) { "#{Dir.tmpdir}/symlink_test" }
let(:archive) { 'spec/fixtures/symlink_export.tar.gz' }
let(:shared) { Gitlab::ImportExport::Shared.new(nil) }
let(:tmpdir) { Dir.mktmpdir }
+ let(:archive_dir) { Dir.mktmpdir }
subject do
Class.new do
@@ -25,20 +26,38 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil do
before do
FileUtils.mkdir_p(path)
- subject.untar_zxf(archive: archive, dir: path)
end
after do
FileUtils.rm_rf(path)
+ FileUtils.rm_rf(archive_dir)
FileUtils.remove_entry(tmpdir)
end
- it 'has the right mask for project.json' do
- expect(file_permissions("#{path}/project.json")).to eq(0755) # originally 777
- end
-
- it 'has the right mask for uploads' do
- expect(file_permissions("#{path}/uploads")).to eq(0755) # originally 555
+ shared_examples 'deletes symlinks' do |compression, decompression|
+ it 'deletes the symlinks', :aggregate_failures do
+ Dir.mkdir("#{tmpdir}/.git")
+ Dir.mkdir("#{tmpdir}/folder")
+ FileUtils.touch("#{tmpdir}/file.txt")
+ FileUtils.touch("#{tmpdir}/folder/file.txt")
+ FileUtils.touch("#{tmpdir}/.gitignore")
+ FileUtils.touch("#{tmpdir}/.git/config")
+ File.symlink('file.txt', "#{tmpdir}/.symlink")
+ File.symlink('file.txt', "#{tmpdir}/.git/.symlink")
+ File.symlink('file.txt', "#{tmpdir}/folder/.symlink")
+ archive = File.join(archive_dir, 'archive')
+ subject.public_send(compression, archive: archive, dir: tmpdir)
+
+ subject.public_send(decompression, archive: archive, dir: archive_dir)
+
+ expect(File.exist?("#{archive_dir}/file.txt")).to eq(true)
+ expect(File.exist?("#{archive_dir}/folder/file.txt")).to eq(true)
+ expect(File.exist?("#{archive_dir}/.gitignore")).to eq(true)
+ expect(File.exist?("#{archive_dir}/.git/config")).to eq(true)
+ expect(File.exist?("#{archive_dir}/.symlink")).to eq(false)
+ expect(File.exist?("#{archive_dir}/.git/.symlink")).to eq(false)
+ expect(File.exist?("#{archive_dir}/folder/.symlink")).to eq(false)
+ end
end
describe '#download_or_copy_upload' do
@@ -228,12 +247,6 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil do
end
describe '#tar_cf' do
- let(:archive_dir) { Dir.mktmpdir }
-
- after do
- FileUtils.remove_entry(archive_dir)
- end
-
it 'archives a folder without compression' do
archive_file = File.join(archive_dir, 'archive.tar')
@@ -256,12 +269,24 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil do
end
end
- describe '#untar_xf' do
- let(:archive_dir) { Dir.mktmpdir }
+ describe '#untar_zxf' do
+ it_behaves_like 'deletes symlinks', :tar_czf, :untar_zxf
- after do
- FileUtils.remove_entry(archive_dir)
+ it 'has the right mask for project.json' do
+ subject.untar_zxf(archive: archive, dir: path)
+
+ expect(file_permissions("#{path}/project.json")).to eq(0755) # originally 777
+ end
+
+ it 'has the right mask for uploads' do
+ subject.untar_zxf(archive: archive, dir: path)
+
+ expect(file_permissions("#{path}/uploads")).to eq(0755) # originally 555
end
+ end
+
+ describe '#untar_xf' do
+ it_behaves_like 'deletes symlinks', :tar_cf, :untar_xf
it 'extracts archive without decompression' do
filename = 'archive.tar.gz'
diff --git a/spec/lib/gitlab/import_export/config_spec.rb b/spec/lib/gitlab/import_export/config_spec.rb
index 8f848af8bd3..2a52a0a2ff2 100644
--- a/spec/lib/gitlab/import_export/config_spec.rb
+++ b/spec/lib/gitlab/import_export/config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::Config do
+RSpec.describe Gitlab::ImportExport::Config, feature_category: :importers do
let(:yaml_file) { described_class.new }
describe '#to_h' do
@@ -21,7 +21,9 @@ RSpec.describe Gitlab::ImportExport::Config do
end
it 'parses default config' do
- expected_keys = [:tree, :excluded_attributes, :included_attributes, :methods, :preloads, :export_reorders]
+ expected_keys = [
+ :tree, :import_only_tree, :excluded_attributes, :included_attributes, :methods, :preloads, :export_reorders
+ ]
expected_keys << :include_if_exportable if ee
expect { subject }.not_to raise_error
@@ -82,7 +84,7 @@ RSpec.describe Gitlab::ImportExport::Config do
EOF
end
- let(:config_hash) { YAML.safe_load(config, [Symbol]) }
+ let(:config_hash) { YAML.safe_load(config, permitted_classes: [Symbol]) }
before do
allow_any_instance_of(described_class).to receive(:parse_yaml) do
@@ -110,6 +112,7 @@ RSpec.describe Gitlab::ImportExport::Config do
}
}
},
+ import_only_tree: {},
included_attributes: {
user: [:id]
},
@@ -153,6 +156,7 @@ RSpec.describe Gitlab::ImportExport::Config do
}
}
},
+ import_only_tree: {},
included_attributes: {
user: [:id, :name_ee]
},
diff --git a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
index f18d9e64f52..02419267f0e 100644
--- a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
+++ b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::FastHashSerializer, :with_license do
+RSpec.describe Gitlab::ImportExport::FastHashSerializer, :with_license, feature_category: :importers do
# FastHashSerializer#execute generates the hash which is not easily accessible
# and includes `JSONBatchRelation` items which are serialized at this point.
# Wrapping the result into JSON generating/parsing is for making
@@ -125,13 +125,13 @@ RSpec.describe Gitlab::ImportExport::FastHashSerializer, :with_license do
expect(subject.dig('ci_pipelines', 0, 'stages')).not_to be_empty
end
- it 'has pipeline statuses' do
- expect(subject.dig('ci_pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty
+ it 'has pipeline builds' do
+ expect(subject.dig('ci_pipelines', 0, 'stages', 0, 'builds')).not_to be_empty
end
it 'has pipeline builds' do
builds_count = subject
- .dig('ci_pipelines', 0, 'stages', 0, 'statuses')
+ .dig('ci_pipelines', 0, 'stages', 0, 'builds')
.count { |hash| hash['type'] == 'Ci::Build' }
expect(builds_count).to eq(1)
@@ -141,8 +141,8 @@ RSpec.describe Gitlab::ImportExport::FastHashSerializer, :with_license do
expect(subject['ci_pipelines']).not_to be_empty
end
- it 'has ci pipeline notes' do
- expect(subject['ci_pipelines'].first['notes']).not_to be_empty
+ it 'has commit notes' do
+ expect(subject['commit_notes']).not_to be_empty
end
it 'has labels with no associations' do
diff --git a/spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb
index 5e84284a060..07971d6271c 100644
--- a/spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb
@@ -9,7 +9,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::Group::RelationTreeRestorer do
+RSpec.describe Gitlab::ImportExport::Group::RelationTreeRestorer, feature_category: :importers do
let(:group) { create(:group).tap { |g| g.add_owner(user) } }
let(:importable) { create(:group, parent: group) }
@@ -60,4 +60,81 @@ RSpec.describe Gitlab::ImportExport::Group::RelationTreeRestorer do
subject
end
+
+ describe 'relation object saving' do
+ let(:importable) { create(:group) }
+ let(:relation_reader) do
+ Gitlab::ImportExport::Json::LegacyReader::File.new(
+ path,
+ relation_names: [:labels])
+ end
+
+ before do
+ allow(shared.logger).to receive(:info).and_call_original
+ allow(relation_reader).to receive(:consume_relation).and_call_original
+
+ allow(relation_reader)
+ .to receive(:consume_relation)
+ .with(nil, 'labels')
+ .and_return([[label, 0]])
+ end
+
+ context 'when relation object is new' do
+ context 'when relation object has invalid subrelations' do
+ let(:label) do
+ {
+ 'title' => 'test',
+ 'priorities' => [LabelPriority.new, LabelPriority.new],
+ 'type' => 'GroupLabel'
+ }
+ end
+
+ it 'logs invalid subrelations' do
+ expect(shared.logger)
+ .to receive(:info)
+ .with(
+ message: '[Project/Group Import] Invalid subrelation',
+ group_id: importable.id,
+ relation_key: 'labels',
+ error_messages: "Project can't be blank, Priority can't be blank, and Priority is not a number"
+ )
+
+ subject
+
+ label = importable.labels.first
+ failure = importable.import_failures.first
+
+ expect(importable.import_failures.count).to eq(2)
+ expect(label.title).to eq('test')
+ expect(failure.exception_class).to eq('ActiveRecord::RecordInvalid')
+ expect(failure.source).to eq('RelationTreeRestorer#save_relation_object')
+ expect(failure.exception_message)
+ .to eq("Project can't be blank, Priority can't be blank, and Priority is not a number")
+ end
+ end
+ end
+
+ context 'when relation object is persisted' do
+ context 'when relation object is invalid' do
+ let(:label) { create(:group_label, group: group, title: 'test') }
+
+ it 'saves import failure with nested errors' do
+ label.priorities << [LabelPriority.new, LabelPriority.new]
+
+ subject
+
+ failure = importable.import_failures.first
+
+ expect(importable.labels.count).to eq(0)
+ expect(importable.import_failures.count).to eq(1)
+ expect(failure.exception_class).to eq('ActiveRecord::RecordInvalid')
+ expect(failure.source).to eq('process_relation_item!')
+ expect(failure.exception_message)
+ .to eq("Validation failed: Priorities is invalid, Project can't be blank, Priority can't be blank, " \
+ "Priority is not a number, Project can't be blank, Priority can't be blank, " \
+ "Priority is not a number")
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/import_export/import_failure_service_spec.rb b/spec/lib/gitlab/import_export/import_failure_service_spec.rb
index 51f1fc9c6a2..30d16347828 100644
--- a/spec/lib/gitlab/import_export/import_failure_service_spec.rb
+++ b/spec/lib/gitlab/import_export/import_failure_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::ImportFailureService do
+RSpec.describe Gitlab::ImportExport::ImportFailureService, feature_category: :importers do
let(:importable) { create(:project, :builds_enabled, :issues_disabled, name: 'project', path: 'project') }
let(:label) { create(:label) }
let(:subject) { described_class.new(importable) }
diff --git a/spec/lib/gitlab/import_export/json/legacy_writer_spec.rb b/spec/lib/gitlab/import_export/json/legacy_writer_spec.rb
index e8ecd98b1e1..2c0f023ad2c 100644
--- a/spec/lib/gitlab/import_export/json/legacy_writer_spec.rb
+++ b/spec/lib/gitlab/import_export/json/legacy_writer_spec.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'tmpdir'
-RSpec.describe Gitlab::ImportExport::Json::LegacyWriter do
+RSpec.describe Gitlab::ImportExport::Json::LegacyWriter, feature_category: :importers do
let(:path) { "#{Dir.tmpdir}/legacy_writer_spec/test.json" }
subject do
diff --git a/spec/lib/gitlab/import_export/model_configuration_spec.rb b/spec/lib/gitlab/import_export/model_configuration_spec.rb
index 4f01f470ce7..ce965a05a32 100644
--- a/spec/lib/gitlab/import_export/model_configuration_spec.rb
+++ b/spec/lib/gitlab/import_export/model_configuration_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
# Part of the test security suite for the Import/Export feature
# Finds if a new model has been added that can potentially be part of the Import/Export
# If it finds a new model, it will show a +failure_message+ with the options available.
-RSpec.describe 'Import/Export model configuration' do
+RSpec.describe 'Import/Export model configuration', feature_category: :importers do
include ConfigurationHelper
let(:all_models_yml) { 'spec/lib/gitlab/import_export/all_models.yml' }
diff --git a/spec/lib/gitlab/import_export/project/import_task_spec.rb b/spec/lib/gitlab/import_export/project/import_task_spec.rb
index c847224cb9b..693f1984ce8 100644
--- a/spec/lib/gitlab/import_export/project/import_task_spec.rb
+++ b/spec/lib/gitlab/import_export/project/import_task_spec.rb
@@ -2,7 +2,7 @@
require 'rake_helper'
-RSpec.describe Gitlab::ImportExport::Project::ImportTask, :request_store, :silence_stdout do
+RSpec.describe Gitlab::ImportExport::Project::ImportTask, :request_store, :silence_stdout, feature_category: :importers do
let(:username) { 'root' }
let(:namespace_path) { username }
let!(:user) { create(:user, username: username) }
diff --git a/spec/lib/gitlab/import_export/project/object_builder_spec.rb b/spec/lib/gitlab/import_export/project/object_builder_spec.rb
index 189b798c2e8..5fa8590e8fd 100644
--- a/spec/lib/gitlab/import_export/project/object_builder_spec.rb
+++ b/spec/lib/gitlab/import_export/project/object_builder_spec.rb
@@ -86,13 +86,16 @@ RSpec.describe Gitlab::ImportExport::Project::ObjectBuilder do
'group' => group)).to eq(group_label)
end
- it 'creates a new label' do
+ it 'creates a new project label' do
label = described_class.build(Label,
'title' => 'group label',
'project' => project,
- 'group' => project.group)
+ 'group' => project.group,
+ 'group_id' => project.group.id)
expect(label.persisted?).to be true
+ expect(label).to be_an_instance_of(ProjectLabel)
+ expect(label.group_id).to be_nil
end
end
diff --git a/spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb
index 6053df8ba97..75012aa80ec 100644
--- a/spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb
@@ -50,6 +50,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationTreeRestorer, feature_cate
expect(project.custom_attributes.count).to eq(2)
expect(project.project_badges.count).to eq(2)
expect(project.snippets.count).to eq(1)
+ expect(project.commit_notes.count).to eq(3)
end
end
end
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 125d1736b9b..a07fe4fd29c 100644
--- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
@@ -295,6 +295,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
it 'has project labels' do
expect(ProjectLabel.count).to eq(3)
+ expect(ProjectLabel.pluck(:group_id).compact).to be_empty
end
it 'has merge request approvals' do
@@ -528,7 +529,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
it 'has the correct number of pipelines and statuses' do
expect(@project.ci_pipelines.size).to eq(7)
- @project.ci_pipelines.order(:id).zip([2, 0, 2, 2, 2, 2, 0])
+ @project.ci_pipelines.order(:id).zip([2, 0, 2, 3, 2, 2, 0])
.each do |(pipeline, expected_status_size)|
expect(pipeline.statuses.size).to eq(expected_status_size)
end
@@ -548,8 +549,16 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
expect(Ci::Stage.all).to all(have_attributes(pipeline_id: a_value > 0))
end
- it 'restores statuses' do
- expect(CommitStatus.all.count).to be 10
+ it 'restores builds' do
+ expect(Ci::Build.all.count).to be 7
+ end
+
+ it 'restores bridges' do
+ expect(Ci::Bridge.all.count).to be 1
+ end
+
+ it 'restores generic commit statuses' do
+ expect(GenericCommitStatus.all.count).to be 1
end
it 'correctly restores association between a stage and a job' do
@@ -574,6 +583,10 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
expect(@project.import_failures.size).to eq 0
end
end
+
+ it 'restores commit notes' do
+ expect(@project.commit_notes.count).to eq(3)
+ end
end
end
diff --git a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
index 74b6e039601..b87992c4594 100644
--- a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license do
+RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license, feature_category: :importers do
let_it_be(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let_it_be(:exportable_path) { 'project' }
let_it_be(:user) { create(:user) }
@@ -223,22 +223,31 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license do
expect(subject.dig(0, 'stages')).not_to be_empty
end
- it 'has pipeline statuses' do
- expect(subject.dig(0, 'stages', 0, 'statuses')).not_to be_empty
+ it 'has pipeline builds' do
+ count = subject.dig(0, 'stages', 0, 'builds').count
+
+ expect(count).to eq(1)
end
- it 'has pipeline builds' do
- builds_count = subject.dig(0, 'stages', 0, 'statuses')
- .count { |hash| hash['type'] == 'Ci::Build' }
+ it 'has pipeline generic_commit_statuses' do
+ count = subject.dig(0, 'stages', 0, 'generic_commit_statuses').count
- expect(builds_count).to eq(1)
+ expect(count).to eq(1)
end
- it 'has ci pipeline notes' do
- expect(subject.first['notes']).not_to be_empty
+ it 'has pipeline bridges' do
+ count = subject.dig(0, 'stages', 0, 'bridges').count
+
+ expect(count).to eq(1)
end
end
+ context 'with commit_notes' do
+ let(:relation_name) { :commit_notes }
+
+ it { is_expected.not_to be_empty }
+ end
+
context 'with labels' do
let(:relation_name) { :labels }
@@ -468,6 +477,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license do
end
end
+ # rubocop: disable Metrics/AbcSize
def setup_project
release = create(:release)
@@ -496,6 +506,8 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license do
ci_build = create(:ci_build, project: project, when: nil)
ci_build.pipeline.update!(project: project)
create(:commit_status, project: project, pipeline: ci_build.pipeline)
+ create(:generic_commit_status, pipeline: ci_build.pipeline, ci_stage: ci_build.ci_stage, project: project)
+ create(:ci_bridge, pipeline: ci_build.pipeline, ci_stage: ci_build.ci_stage, project: project)
create(:milestone, project: project)
discussion_note = create(:discussion_note, noteable: issue, project: project)
@@ -528,4 +540,5 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license do
project
end
+ # rubocop: enable Metrics/AbcSize
end
diff --git a/spec/lib/gitlab/import_export/references_configuration_spec.rb b/spec/lib/gitlab/import_export/references_configuration_spec.rb
index ad165790b77..84c5b564cb1 100644
--- a/spec/lib/gitlab/import_export/references_configuration_spec.rb
+++ b/spec/lib/gitlab/import_export/references_configuration_spec.rb
@@ -9,7 +9,7 @@ require 'spec_helper'
# or to be blacklisted by using the import_export.yml configuration file.
# Likewise, new models added to import_export.yml, will need to be added with their correspondent relations
# to this spec.
-RSpec.describe 'Import/Export Project configuration' do
+RSpec.describe 'Import/Export Project configuration', feature_category: :importers do
include ConfigurationHelper
where(:relation_path, :relation_name) do
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index e14e929faf3..2384baabb6b 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -86,6 +86,7 @@ Note:
- original_discussion_id
- confidential
- last_edited_at
+- internal
LabelLink:
- id
- target_type
@@ -347,7 +348,111 @@ Ci::Stage:
- pipeline_id
- created_at
- updated_at
-CommitStatus:
+Ci::Build:
+- id
+- project_id
+- status
+- finished_at
+- trace
+- created_at
+- updated_at
+- started_at
+- runner_id
+- coverage
+- commit_id
+- commands
+- job_id
+- name
+- deploy
+- options
+- allow_failure
+- stage
+- trigger_request_id
+- stage_idx
+- stage_id
+- tag
+- ref
+- user_id
+- type
+- target_url
+- description
+- artifacts_file
+- artifacts_file_store
+- artifacts_metadata
+- artifacts_metadata_store
+- erased_by_id
+- erased_at
+- artifacts_expire_at
+- environment
+- artifacts_size
+- when
+- yaml_variables
+- queued_at
+- token
+- lock_version
+- coverage_regex
+- auto_canceled_by_id
+- retried
+- protected
+- failure_reason
+- scheduled_at
+- upstream_pipeline_id
+- interruptible
+- processed
+- scheduling_type
+Ci::Bridge:
+- id
+- project_id
+- status
+- finished_at
+- trace
+- created_at
+- updated_at
+- started_at
+- runner_id
+- coverage
+- commit_id
+- commands
+- job_id
+- name
+- deploy
+- options
+- allow_failure
+- stage
+- trigger_request_id
+- stage_idx
+- stage_id
+- tag
+- ref
+- user_id
+- type
+- target_url
+- description
+- artifacts_file
+- artifacts_file_store
+- artifacts_metadata
+- artifacts_metadata_store
+- erased_by_id
+- erased_at
+- artifacts_expire_at
+- environment
+- artifacts_size
+- when
+- yaml_variables
+- queued_at
+- token
+- lock_version
+- coverage_regex
+- auto_canceled_by_id
+- retried
+- protected
+- failure_reason
+- scheduled_at
+- upstream_pipeline_id
+- interruptible
+- processed
+- scheduling_type
+GenericCommitStatus:
- id
- project_id
- status
diff --git a/spec/lib/gitlab/instrumentation/redis_base_spec.rb b/spec/lib/gitlab/instrumentation/redis_base_spec.rb
index 656e6ffba05..426997f6e86 100644
--- a/spec/lib/gitlab/instrumentation/redis_base_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_base_spec.rb
@@ -210,4 +210,16 @@ RSpec.describe Gitlab::Instrumentation::RedisBase, :request_store do
end
end
end
+
+ describe '.log_exception' do
+ it 'logs exception with storage details' do
+ expect(::Gitlab::ErrorTracking).to receive(:log_exception)
+ .with(
+ an_instance_of(StandardError),
+ storage: instrumentation_class_a.storage_key
+ )
+
+ instrumentation_class_a.log_exception(StandardError.new)
+ end
+ end
end
diff --git a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
index 187a6ff1739..18301f01a30 100644
--- a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
@@ -64,16 +64,34 @@ RSpec.describe Gitlab::Instrumentation::RedisInterceptor, :clean_gitlab_redis_sh
end
end
- it 'counts exceptions' do
- expect(instrumentation_class).to receive(:instance_count_exception)
- .with(instance_of(Redis::CommandError)).and_call_original
- expect(instrumentation_class).to receive(:instance_count_request).and_call_original
+ context 'when encountering exceptions' do
+ where(:case_name, :exception, :exception_counter) do
+ 'generic exception' | Redis::CommandError | :instance_count_exception
+ 'moved redirection' | Redis::CommandError.new("MOVED 123 127.0.0.1:6380") | :instance_count_cluster_redirection
+ 'ask redirection' | Redis::CommandError.new("ASK 123 127.0.0.1:6380") | :instance_count_cluster_redirection
+ end
- expect do
- Gitlab::Redis::SharedState.with do |redis|
- redis.call(:auth, 'foo', 'bar')
+ with_them do
+ before do
+ Gitlab::Redis::SharedState.with do |redis|
+ # We need to go 1 layer deeper to stub _client as we monkey-patch Redis::Client
+ # with the interceptor. Stubbing `redis` will skip the instrumentation_class.
+ allow(redis._client).to receive(:process).and_raise(exception)
+ end
end
- end.to raise_exception(Redis::CommandError)
+
+ it 'counts exception' do
+ expect(instrumentation_class).to receive(exception_counter)
+ .with(instance_of(Redis::CommandError)).and_call_original
+ expect(instrumentation_class).to receive(:log_exception)
+ .with(instance_of(Redis::CommandError)).and_call_original
+ expect(instrumentation_class).to receive(:instance_count_request).and_call_original
+
+ expect do
+ Gitlab::Redis::SharedState.with { |redis| redis.call(:auth, 'foo', 'bar') }
+ end.to raise_exception(Redis::CommandError)
+ end
+ end
end
context 'in production environment' do
diff --git a/spec/lib/gitlab/internal_post_receive/response_spec.rb b/spec/lib/gitlab/internal_post_receive/response_spec.rb
index 23ea5191486..2792cf49d06 100644
--- a/spec/lib/gitlab/internal_post_receive/response_spec.rb
+++ b/spec/lib/gitlab/internal_post_receive/response_spec.rb
@@ -76,7 +76,7 @@ RSpec.describe Gitlab::InternalPostReceive::Response do
describe '#add_alert_message' do
context 'when text is present' do
- it 'adds a alert message' do
+ it 'adds an alert message' do
subject.add_alert_message('hello')
expect(subject.messages.first.message).to eq('hello')
diff --git a/spec/lib/gitlab/issuable_sorter_spec.rb b/spec/lib/gitlab/issuable_sorter_spec.rb
index b8d0c7b0609..0d9940bab6f 100644
--- a/spec/lib/gitlab/issuable_sorter_spec.rb
+++ b/spec/lib/gitlab/issuable_sorter_spec.rb
@@ -4,16 +4,42 @@ require 'spec_helper'
RSpec.describe Gitlab::IssuableSorter do
let(:namespace1) { build_stubbed(:namespace, id: 1) }
- let(:project1) { build_stubbed(:project, id: 1, namespace: namespace1) }
-
- let(:project2) { build_stubbed(:project, id: 2, path: "a", namespace: project1.namespace) }
- let(:project3) { build_stubbed(:project, id: 3, path: "b", namespace: project1.namespace) }
-
let(:namespace2) { build_stubbed(:namespace, id: 2, path: "a") }
let(:namespace3) { build_stubbed(:namespace, id: 3, path: "b") }
- let(:project4) { build_stubbed(:project, id: 4, path: "a", namespace: namespace2) }
- let(:project5) { build_stubbed(:project, id: 5, path: "b", namespace: namespace2) }
- let(:project6) { build_stubbed(:project, id: 6, path: "a", namespace: namespace3) }
+
+ let(:project1) do
+ build_stubbed(:project, id: 1, namespace: namespace1, project_namespace: build_stubbed(:project_namespace))
+ end
+
+ let(:project2) do
+ build_stubbed(
+ :project, id: 2, path: "a", namespace: project1.namespace, project_namespace: build_stubbed(:project_namespace)
+ )
+ end
+
+ let(:project3) do
+ build_stubbed(
+ :project, id: 3, path: "b", namespace: project1.namespace, project_namespace: build_stubbed(:project_namespace)
+ )
+ end
+
+ let(:project4) do
+ build_stubbed(
+ :project, id: 4, path: "a", namespace: namespace2, project_namespace: build_stubbed(:project_namespace)
+ )
+ end
+
+ let(:project5) do
+ build_stubbed(
+ :project, id: 5, path: "b", namespace: namespace2, project_namespace: build_stubbed(:project_namespace)
+ )
+ end
+
+ let(:project6) do
+ build_stubbed(
+ :project, id: 6, path: "a", namespace: namespace3, project_namespace: build_stubbed(:project_namespace)
+ )
+ end
let(:unsorted) { [sorted[2], sorted[3], sorted[0], sorted[1]] }
diff --git a/spec/lib/gitlab/jira_import/issues_importer_spec.rb b/spec/lib/gitlab/jira_import/issues_importer_spec.rb
index 9f654bbcd15..36135c56dd9 100644
--- a/spec/lib/gitlab/jira_import/issues_importer_spec.rb
+++ b/spec/lib/gitlab/jira_import/issues_importer_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe Gitlab::JiraImport::IssuesImporter do
def mock_issue_serializer(count, raise_exception_on_even_mocks: false)
serializer = instance_double(Gitlab::JiraImport::IssueSerializer, execute: { key: 'data' })
- allow(Issue).to receive(:with_project_iid_supply).and_return('issue_iid')
+ allow(Issue).to receive(:with_namespace_iid_supply).and_return('issue_iid')
count.times do |i|
if raise_exception_on_even_mocks && i.even?
diff --git a/spec/lib/gitlab/kas/user_access_spec.rb b/spec/lib/gitlab/kas/user_access_spec.rb
new file mode 100644
index 00000000000..8795ad565d0
--- /dev/null
+++ b/spec/lib/gitlab/kas/user_access_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Kas::UserAccess, feature_category: :kubernetes_management do
+ describe '.enabled?' do
+ subject { described_class.enabled? }
+
+ before do
+ allow(::Gitlab::Kas).to receive(:enabled?).and_return true
+ end
+
+ it { is_expected.to be true }
+
+ context 'when flag kas_user_access is disabled' do
+ before do
+ stub_feature_flags(kas_user_access: false)
+ end
+
+ it { is_expected.to be false }
+ end
+ end
+
+ describe '.enabled_for?' do
+ subject { described_class.enabled_for?(agent) }
+
+ let(:agent) { build(:cluster_agent) }
+
+ before do
+ allow(::Gitlab::Kas).to receive(:enabled?).and_return true
+ end
+
+ it { is_expected.to be true }
+
+ context 'when flag kas_user_access is disabled' do
+ before do
+ stub_feature_flags(kas_user_access: false)
+ end
+
+ it { is_expected.to be false }
+ end
+
+ context 'when flag kas_user_access_project is disabled' do
+ before do
+ stub_feature_flags(kas_user_access_project: false)
+ end
+
+ it { is_expected.to be false }
+ end
+ end
+
+ describe '.{encrypt,decrypt}_public_session_id' do
+ let(:data) { 'the data' }
+ let(:encrypted) { described_class.encrypt_public_session_id(data) }
+ let(:decrypted) { described_class.decrypt_public_session_id(encrypted) }
+
+ it { expect(encrypted).not_to include data }
+ it { expect(decrypted).to eq data }
+ end
+
+ describe '.cookie_data' do
+ subject(:cookie_data) { described_class.cookie_data(public_session_id) }
+
+ let(:public_session_id) { 'the-public-session-id' }
+ let(:external_k8s_proxy_url) { 'https://example.com:1234' }
+
+ before do
+ stub_config(
+ gitlab: { host: 'example.com', https: true },
+ gitlab_kas: { external_k8s_proxy_url: external_k8s_proxy_url }
+ )
+ end
+
+ it 'is encrypted, secure, httponly', :aggregate_failures do
+ expect(cookie_data[:value]).not_to include public_session_id
+ expect(cookie_data).to include(httponly: true, secure: true, path: '/')
+ expect(cookie_data).not_to have_key(:domain)
+ end
+
+ context 'when on non-root path' do
+ let(:external_k8s_proxy_url) { 'https://example.com/k8s-proxy' }
+
+ it 'sets :path' do
+ expect(cookie_data).to include(httponly: true, secure: true, path: '/k8s-proxy')
+ end
+ end
+
+ context 'when on subdomain' do
+ let(:external_k8s_proxy_url) { 'https://k8s-proxy.example.com' }
+
+ it 'sets :domain' do
+ expect(cookie_data[:domain]).to eq "example.com"
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/kroki_spec.rb b/spec/lib/gitlab/kroki_spec.rb
index 3d6ecf20377..6d8e6ecbf54 100644
--- a/spec/lib/gitlab/kroki_spec.rb
+++ b/spec/lib/gitlab/kroki_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Kroki do
describe '.formats' do
def default_formats
- %w[bytefield c4plantuml ditaa erd graphviz nomnoml pikchr plantuml
+ %w[bytefield c4plantuml d2 dbml diagramsnet ditaa erd graphviz nomnoml pikchr plantuml
structurizr svgbob umlet vega vegalite wavedrom].freeze
end
diff --git a/spec/lib/gitlab/kubernetes/config_map_spec.rb b/spec/lib/gitlab/kubernetes/config_map_spec.rb
index 2d0d205ffb1..ebc2202921b 100644
--- a/spec/lib/gitlab/kubernetes/config_map_spec.rb
+++ b/spec/lib/gitlab/kubernetes/config_map_spec.rb
@@ -4,20 +4,23 @@ require 'spec_helper'
RSpec.describe Gitlab::Kubernetes::ConfigMap do
let(:kubeclient) { double('kubernetes client') }
- let(:application) { create(:clusters_applications_prometheus) }
- let(:config_map) { described_class.new(application.name, application.files) }
+ let(:name) { 'my-name' }
+ let(:files) { [] }
+ let(:config_map) { described_class.new(name, files) }
let(:namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
let(:metadata) do
{
- name: "values-content-configuration-#{application.name}",
+ name: "values-content-configuration-#{name}",
namespace: namespace,
- labels: { name: "values-content-configuration-#{application.name}" }
+ labels: { name: "values-content-configuration-#{name}" }
}
end
describe '#generate' do
- let(:resource) { ::Kubeclient::Resource.new(metadata: metadata, data: application.files) }
+ let(:resource) do
+ ::Kubeclient::Resource.new(metadata: metadata, data: files)
+ end
subject { config_map.generate }
@@ -28,7 +31,8 @@ RSpec.describe Gitlab::Kubernetes::ConfigMap do
describe '#config_map_name' do
it 'returns the config_map name' do
- expect(config_map.config_map_name).to eq("values-content-configuration-#{application.name}")
+ expect(config_map.config_map_name)
+ .to eq("values-content-configuration-#{name}")
end
end
end
diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
index e3763977add..8aa755bffce 100644
--- a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Gitlab::Kubernetes::Helm::Pod do
with_them do
let(:cluster) { create(:cluster, helm_major_version: helm_major_version) }
- let(:app) { create(:clusters_applications_prometheus, cluster: cluster) }
+ let(:app) { create(:clusters_applications_knative, cluster: cluster) }
let(:command) { app.install_command }
let(:namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
let(:service_account_name) { nil }
diff --git a/spec/lib/gitlab/legacy_github_import/importer_spec.rb b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
index cd66b93eb8b..bb38f4b1bca 100644
--- a/spec/lib/gitlab/legacy_github_import/importer_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
@@ -2,7 +2,9 @@
require 'spec_helper'
-RSpec.describe Gitlab::LegacyGithubImport::Importer do
+RSpec.describe Gitlab::LegacyGithubImport::Importer, feature_category: :importers do
+ subject(:importer) { described_class.new(project) }
+
shared_examples 'Gitlab::LegacyGithubImport::Importer#execute' do
let(:expected_not_called) { [] }
@@ -11,8 +13,6 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do
end
it 'calls import methods' do
- importer = described_class.new(project)
-
expected_called = [
:import_labels, :import_milestones, :import_pull_requests, :import_issues,
:import_wiki, :import_releases, :handle_errors,
@@ -51,11 +51,13 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do
allow_any_instance_of(Octokit::Client).to receive(:labels).and_return([label1, label2])
allow_any_instance_of(Octokit::Client).to receive(:milestones).and_return([milestone, milestone])
allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2])
- allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request])
+ allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request_missing_source_branch])
allow_any_instance_of(Octokit::Client).to receive(:issues_comments).and_raise(Octokit::NotFound)
allow_any_instance_of(Octokit::Client).to receive(:pull_requests_comments).and_return([])
allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil }))
allow_any_instance_of(Octokit::Client).to receive(:releases).and_return([release1, release2])
+
+ allow(importer).to receive(:restore_source_branch).and_raise(StandardError, 'Some error')
end
let(:label1) do
@@ -153,8 +155,6 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do
}
end
- subject { described_class.new(project) }
-
it 'returns true' do
expect(subject.execute).to eq true
end
@@ -163,18 +163,19 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do
expect { subject.execute }.not_to raise_error
end
- it 'stores error messages' do
+ it 'stores error messages', :unlimited_max_formatted_output_length do
error = {
message: 'The remote data could not be fully imported.',
errors: [
{ type: :label, url: "#{api_root}/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title can't be blank, Title is invalid" },
+ { type: :pull_request, url: "#{api_root}/repos/octocat/Hello-World/pulls/1347", errors: 'Some error' },
{ type: :issue, url: "#{api_root}/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank" },
{ type: :issues_comments, errors: 'Octokit::NotFound' },
{ type: :wiki, errors: "Gitlab::Git::CommandError" }
]
}
- described_class.new(project).execute
+ importer.execute
expect(project.import_state.last_error).to eq error.to_json
end
@@ -182,8 +183,6 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do
shared_examples 'Gitlab::LegacyGithubImport unit-testing' do
describe '#clean_up_restored_branches' do
- subject { described_class.new(project) }
-
before do
allow(gh_pull_request).to receive(:source_branch_exists?).at_least(:once) { false }
allow(gh_pull_request).to receive(:target_branch_exists?).at_least(:once) { false }
@@ -240,6 +239,16 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do
}
end
+ let(:pull_request_missing_source_branch) do
+ pull_request.merge(
+ head: {
+ ref: 'missing',
+ repo: repository,
+ sha: RepoHelpers.another_sample_commit
+ }
+ )
+ end
+
let(:closed_pull_request) do
{
number: 1347,
@@ -264,8 +273,6 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do
let(:api_root) { 'https://try.gitea.io/api/v1' }
let(:repo_root) { 'https://try.gitea.io' }
- subject { described_class.new(project) }
-
before do
project.update!(import_type: 'gitea', import_url: "#{repo_root}/foo/group/project.git")
end
diff --git a/spec/lib/gitlab/loggable_spec.rb b/spec/lib/gitlab/loggable_spec.rb
new file mode 100644
index 00000000000..8238e47014b
--- /dev/null
+++ b/spec/lib/gitlab/loggable_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Loggable, feature_category: :logging do
+ subject(:klass_instance) do
+ Class.new do
+ include Gitlab::Loggable
+
+ def self.name
+ 'MyTestClass'
+ end
+ end.new
+ end
+
+ describe '#build_structured_payload' do
+ it 'adds class and returns formatted json' do
+ expected = {
+ 'class' => 'MyTestClass',
+ 'message' => 'test'
+ }
+
+ expect(klass_instance.build_structured_payload(message: 'test')).to eq(expected)
+ end
+
+ it 'appends additional params and returns formatted json' do
+ expected = {
+ 'class' => 'MyTestClass',
+ 'message' => 'test',
+ 'extra_param' => 1
+ }
+
+ expect(klass_instance.build_structured_payload(message: 'test', extra_param: 1)).to eq(expected)
+ end
+
+ it 'does not raise an error in loggers when passed non-symbols' do
+ expected = {
+ 'class' => 'MyTestClass',
+ 'message' => 'test',
+ '["hello", "thing"]' => :world
+ }
+
+ payload = klass_instance.build_structured_payload(message: 'test', %w[hello thing] => :world)
+ expect(payload).to eq(expected)
+ expect { Gitlab::Export::Logger.info(payload) }.not_to raise_error
+ end
+
+ it 'handles anonymous classes' do
+ anonymous_klass_instance = Class.new { include Gitlab::Loggable }.new
+
+ expected = {
+ 'class' => '<Anonymous>',
+ 'message' => 'test'
+ }
+
+ expect(anonymous_klass_instance.build_structured_payload(message: 'test')).to eq(expected)
+ end
+
+ it 'handles duplicate keys' do
+ expected = {
+ 'class' => 'MyTestClass',
+ 'message' => 'test2'
+ }
+
+ expect(klass_instance.build_structured_payload(message: 'test', 'message' => 'test2')).to eq(expected)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb b/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb
index 4780b1eba53..67d185fd2f1 100644
--- a/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb
@@ -1,9 +1,10 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'prometheus/client'
require 'support/shared_examples/lib/gitlab/memory/watchdog/monitor_result_shared_examples'
-RSpec.describe Gitlab::Memory::Watchdog::Monitor::RssMemoryLimit do
+RSpec.describe Gitlab::Memory::Watchdog::Monitor::RssMemoryLimit, feature_category: :application_performance do
let(:max_rss_limit_gauge) { instance_double(::Prometheus::Client::Gauge) }
let(:memory_limit_bytes) { 2_097_152_000 }
let(:worker_memory_bytes) { 1_048_576_000 }
diff --git a/spec/lib/gitlab/metrics/boot_time_tracker_spec.rb b/spec/lib/gitlab/metrics/boot_time_tracker_spec.rb
index 8a17fa8dd2e..3175c0a6b32 100644
--- a/spec/lib/gitlab/metrics/boot_time_tracker_spec.rb
+++ b/spec/lib/gitlab/metrics/boot_time_tracker_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
-RSpec.describe Gitlab::Metrics::BootTimeTracker do
+RSpec.describe Gitlab::Metrics::BootTimeTracker, feature_category: :metrics do
let(:logger) { double('logger') }
let(:gauge) { double('gauge') }
diff --git a/spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb b/spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb
index 9f939d0d7d6..13965bf1244 100644
--- a/spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb
+++ b/spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb
@@ -32,33 +32,6 @@ RSpec.describe Gitlab::Metrics::Subscribers::RackAttack, :request_store do
end
end
- describe '#redis' do
- it 'accumulates per-request RackAttack cache usage' do
- freeze_time do
- subscriber.redis(
- ActiveSupport::Notifications::Event.new(
- 'redis.rack_attack', Time.current, Time.current + 1.second, '1', { operation: 'fetch' }
- )
- )
- subscriber.redis(
- ActiveSupport::Notifications::Event.new(
- 'redis.rack_attack', Time.current, Time.current + 2.seconds, '1', { operation: 'write' }
- )
- )
- subscriber.redis(
- ActiveSupport::Notifications::Event.new(
- 'redis.rack_attack', Time.current, Time.current + 3.seconds, '1', { operation: 'read' }
- )
- )
- end
-
- expect(Gitlab::SafeRequestStore[:rack_attack_instrumentation]).to eql(
- rack_attack_redis_count: 3,
- rack_attack_redis_duration_s: 6.0
- )
- end
- end
-
shared_examples 'log into auth logger' do
context 'when matched throttle does not require user information' do
let(:event) do
diff --git a/spec/lib/gitlab/metrics/subscribers/rails_cache_spec.rb b/spec/lib/gitlab/metrics/subscribers/rails_cache_spec.rb
index 59bfe2042fa..1731da9b752 100644
--- a/spec/lib/gitlab/metrics/subscribers/rails_cache_spec.rb
+++ b/spec/lib/gitlab/metrics/subscribers/rails_cache_spec.rb
@@ -6,13 +6,14 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
let(:env) { {} }
let(:transaction) { Gitlab::Metrics::WebTransaction.new(env) }
let(:subscriber) { described_class.new }
-
- let(:event) { double(:event, duration: 15.2, payload: { key: %w[a b c] }) }
+ let(:store) { 'Gitlab::CustomStore' }
+ let(:store_label) { 'CustomStore' }
+ let(:event) { double(:event, duration: 15.2, payload: { key: %w[a b c], store: store }) }
describe '#cache_read' do
it 'increments the cache_read duration' do
expect(subscriber).to receive(:observe)
- .with(:read, event.duration)
+ .with(:read, event)
subscriber.cache_read(event)
end
@@ -27,7 +28,7 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
let(:event) { double(:event, duration: 15.2, payload: { hit: true }) }
context 'when super operation is fetch' do
- let(:event) { double(:event, duration: 15.2, payload: { hit: true, super_operation: :fetch }) }
+ let(:event) { double(:event, duration: 15.2, payload: { hit: true, super_operation: :fetch, store: store }) }
it 'does not increment cache read miss total' do
expect(transaction).not_to receive(:increment)
@@ -39,7 +40,7 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
end
context 'with miss event' do
- let(:event) { double(:event, duration: 15.2, payload: { hit: false }) }
+ let(:event) { double(:event, duration: 15.2, payload: { hit: false, store: store }) }
it 'increments the cache_read_miss total' do
expect(transaction).to receive(:increment)
@@ -51,7 +52,7 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
end
context 'when super operation is fetch' do
- let(:event) { double(:event, duration: 15.2, payload: { hit: false, super_operation: :fetch }) }
+ let(:event) { double(:event, duration: 15.2, payload: { hit: false, super_operation: :fetch, store: store }) }
it 'does not increment cache read miss total' do
expect(transaction).not_to receive(:increment)
@@ -92,7 +93,7 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
it 'observes read_multi duration' do
expect(subscriber).to receive(:observe)
- .with(:read_multi, event.duration)
+ .with(:read_multi, event)
subject
end
@@ -101,7 +102,7 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
describe '#cache_write' do
it 'observes write duration' do
expect(subscriber).to receive(:observe)
- .with(:write, event.duration)
+ .with(:write, event)
subscriber.cache_write(event)
end
@@ -110,7 +111,7 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
describe '#cache_delete' do
it 'observes delete duration' do
expect(subscriber).to receive(:observe)
- .with(:delete, event.duration)
+ .with(:delete, event)
subscriber.cache_delete(event)
end
@@ -119,7 +120,7 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
describe '#cache_exist?' do
it 'observes the exists duration' do
expect(subscriber).to receive(:observe)
- .with(:exists, event.duration)
+ .with(:exists, event)
subscriber.cache_exist?(event)
end
@@ -179,7 +180,7 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
it 'returns' do
expect(transaction).not_to receive(:increment)
- subscriber.observe(:foo, 15.2)
+ subscriber.observe(:foo, event)
end
end
@@ -192,17 +193,17 @@ RSpec.describe Gitlab::Metrics::Subscribers::RailsCache do
it 'observes cache metric' do
expect(subscriber.send(:metric_cache_operation_duration_seconds))
.to receive(:observe)
- .with({ operation: :delete }, event.duration / 1000.0)
+ .with({ operation: :delete, store: store_label }, event.duration / 1000.0)
- subscriber.observe(:delete, event.duration)
+ subscriber.observe(:delete, event)
end
it 'increments the operations total' do
expect(transaction)
.to receive(:increment)
- .with(:gitlab_cache_operations_total, 1, { operation: :delete })
+ .with(:gitlab_cache_operations_total, 1, { operation: :delete, store: store_label })
- subscriber.observe(:delete, event.duration)
+ subscriber.observe(:delete, event)
end
end
end
diff --git a/spec/lib/gitlab/monitor/demo_projects_spec.rb b/spec/lib/gitlab/monitor/demo_projects_spec.rb
index 262c78eb62e..6b0f855e38d 100644
--- a/spec/lib/gitlab/monitor/demo_projects_spec.rb
+++ b/spec/lib/gitlab/monitor/demo_projects_spec.rb
@@ -6,15 +6,13 @@ RSpec.describe Gitlab::Monitor::DemoProjects do
describe '#primary_keys' do
subject { described_class.primary_keys }
- it 'fetches primary_keys when on gitlab.com' do
- allow(Gitlab).to receive(:com?).and_return(true)
+ it 'fetches primary_keys when on SaaS', :saas do
allow(Gitlab).to receive(:staging?).and_return(false)
expect(subject).to eq(Gitlab::Monitor::DemoProjects::DOT_COM_IDS)
end
- it 'fetches primary_keys when on staging' do
- allow(Gitlab).to receive(:com?).and_return(true)
+ it 'fetches primary_keys when on staging', :saas do
allow(Gitlab).to receive(:staging?).and_return(true)
expect(subject).to eq(Gitlab::Monitor::DemoProjects::STAGING_IDS)
diff --git a/spec/lib/gitlab/multi_collection_paginator_spec.rb b/spec/lib/gitlab/multi_collection_paginator_spec.rb
index 080b3382684..25baa8913bf 100644
--- a/spec/lib/gitlab/multi_collection_paginator_spec.rb
+++ b/spec/lib/gitlab/multi_collection_paginator_spec.rb
@@ -5,6 +5,13 @@ require 'spec_helper'
RSpec.describe Gitlab::MultiCollectionPaginator do
subject(:paginator) { described_class.new(Project.all.order(:id), Group.all.order(:id), per_page: 3) }
+ it 'raises an error for invalid page size' do
+ expect { described_class.new(Project.all.order(:id), Group.all.order(:id), per_page: 0) }
+ .to raise_error(ArgumentError)
+ expect { described_class.new(Project.all.order(:id), Group.all.order(:id), per_page: -1) }
+ .to raise_error(ArgumentError)
+ end
+
it 'combines both collections' do
project = create(:project)
group = create(:group)
diff --git a/spec/lib/gitlab/nav/top_nav_menu_item_spec.rb b/spec/lib/gitlab/nav/top_nav_menu_item_spec.rb
index 6632a8106ca..1d3452a004a 100644
--- a/spec/lib/gitlab/nav/top_nav_menu_item_spec.rb
+++ b/spec/lib/gitlab/nav/top_nav_menu_item_spec.rb
@@ -14,7 +14,8 @@ RSpec.describe ::Gitlab::Nav::TopNavMenuItem, feature_category: :navigation do
view: 'view',
css_class: 'css_class',
data: {},
- emoji: 'smile'
+ partial: 'groups/some_view_partial_file',
+ component: '_some_component_used_as_a_trigger_for_frontend_dropdown_item_render_'
}
expect(described_class.build(**item)).to eq(item.merge(type: :item))
diff --git a/spec/lib/gitlab/net_http_adapter_spec.rb b/spec/lib/gitlab/net_http_adapter_spec.rb
index fdaf35be31e..cfb90578a4b 100644
--- a/spec/lib/gitlab/net_http_adapter_spec.rb
+++ b/spec/lib/gitlab/net_http_adapter_spec.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'net/http'
-RSpec.describe Gitlab::NetHttpAdapter do
+RSpec.describe Gitlab::NetHttpAdapter, feature_category: :api do
describe '#connect' do
let(:url) { 'https://example.org' }
let(:net_http_adapter) { described_class.new(url) }
diff --git a/spec/lib/gitlab/observability_spec.rb b/spec/lib/gitlab/observability_spec.rb
index 8068d2f8ec9..5082d193197 100644
--- a/spec/lib/gitlab/observability_spec.rb
+++ b/spec/lib/gitlab/observability_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Observability do
+RSpec.describe Gitlab::Observability, feature_category: :error_tracking do
describe '.observability_url' do
let(:gitlab_url) { 'https://example.com' }
@@ -31,29 +31,189 @@ RSpec.describe Gitlab::Observability do
end
end
- describe '.observability_enabled?' do
- let_it_be(:group) { build(:user) }
- let_it_be(:user) { build(:group) }
+ describe '.build_full_url' do
+ let_it_be(:group) { build_stubbed(:group, id: 123) }
+ let(:observability_url) { described_class.observability_url }
+
+ it 'returns the full observability url for the given params' do
+ url = described_class.build_full_url(group, '/foo?bar=baz', '/')
+ expect(url).to eq("https://observe.gitlab.com/-/123/foo?bar=baz")
+ end
+
+ it 'handles missing / from observability_path' do
+ url = described_class.build_full_url(group, 'foo?bar=baz', '/')
+ expect(url).to eq("https://observe.gitlab.com/-/123/foo?bar=baz")
+ end
+
+ it 'sanitises observability_path' do
+ url = described_class.build_full_url(group, "/test?groupId=<script>alert('attack!')</script>", '/')
+ expect(url).to eq("https://observe.gitlab.com/-/123/test?groupId=alert('attack!')")
+ end
+
+ context 'when observability_path is missing' do
+ it 'builds the url with the fallback_path' do
+ url = described_class.build_full_url(group, nil, '/fallback')
+ expect(url).to eq("https://observe.gitlab.com/-/123/fallback")
+ end
+
+ it 'defaults to / if fallback_path is also missing' do
+ url = described_class.build_full_url(group, nil, nil)
+ expect(url).to eq("https://observe.gitlab.com/-/123/")
+ end
+ end
+ end
+
+ describe '.embeddable_url' do
+ before do
+ stub_config_setting(url: "https://www.gitlab.com")
+ # Can't use build/build_stubbed as we want the routes to be generated as well
+ create(:group, path: 'test-path', id: 123)
+ end
+
+ context 'when URL is valid' do
+ where(:input, :expected) do
+ [
+ [
+ "https://www.gitlab.com/groups/test-path/-/observability/explore?observability_path=%2Fexplore%3FgroupId%3D14485840%26left%3D%255B%2522now-1h%2522,%2522now%2522,%2522new-sentry.gitlab.net%2522,%257B%257D%255D",
+ "https://observe.gitlab.com/-/123/explore?groupId=14485840&left=%5B%22now-1h%22,%22now%22,%22new-sentry.gitlab.net%22,%7B%7D%5D"
+ ],
+ [
+ "https://www.gitlab.com/groups/test-path/-/observability/explore?observability_path=/goto/foo",
+ "https://observe.gitlab.com/-/123/goto/foo"
+ ]
+ ]
+ end
+
+ with_them do
+ it 'returns an embeddable observability url' do
+ expect(described_class.embeddable_url(input)).to eq(expected)
+ end
+ end
+ end
+
+ context 'when URL is invalid' do
+ where(:input) do
+ [
+ # direct links to observe.gitlab.com
+ "https://observe.gitlab.com/-/123/explore",
+ 'https://observe.gitlab.com/v1/auth/start',
+
+ # invalid GitLab URL
+ "not a link",
+ "https://foo.bar/groups/test-path/-/observability/explore?observability_path=/explore",
+ "http://www.gitlab.com/groups/test-path/-/observability/explore?observability_path=/explore",
+ "https://www.gitlab.com:123/groups/test-path/-/observability/explore?observability_path=/explore",
+ "https://www.gitlab.com@example.com/groups/test-path/-/observability/explore?observability_path=/explore",
+ "https://www.gitlab.com/groups/test-path/-/observability/explore?observability_path=@example.com",
+
+ # invalid group/controller/actions
+ "https://www.gitlab.com/groups/INVALID_GROUP/-/observability/explore?observability_path=/explore",
+ "https://www.gitlab.com/groups/test-path/-/INVALID_CONTROLLER/explore?observability_path=/explore",
+ "https://www.gitlab.com/groups/test-path/-/observability/INVALID_ACTION?observability_path=/explore",
+
+ # invalid observablity path
+ "https://www.gitlab.com/groups/test-path/-/observability/explore",
+ "https://www.gitlab.com/groups/test-path/-/observability/explore?missing_observability_path=/explore",
+ "https://www.gitlab.com/groups/test-path/-/observability/explore?observability_path=/not_embeddable",
+ "https://www.gitlab.com/groups/test-path/-/observability/explore?observability_path=/datasources",
+ "https://www.gitlab.com/groups/test-path/-/observability/explore?observability_path=not a valid path"
+ ]
+ end
+
+ with_them do
+ it 'returns nil' do
+ expect(described_class.embeddable_url(input)).to be_nil
+ end
+ end
+
+ it 'returns nil if the path detection throws an error' do
+ test_url = "https://www.gitlab.com/groups/test-path/-/observability/explore"
+ allow(Rails.application.routes).to receive(:recognize_path).with(test_url) {
+ raise ActionController::RoutingError, 'test'
+ }
+ expect(described_class.embeddable_url(test_url)).to be_nil
+ end
+
+ it 'returns nil if parsing observaboility path throws an error' do
+ observability_path = 'some-path'
+ test_url = "https://www.gitlab.com/groups/test-path/-/observability/explore?observability_path=#{observability_path}"
+
+ allow(URI).to receive(:parse).and_call_original
+ allow(URI).to receive(:parse).with(observability_path) {
+ raise URI::InvalidURIError, 'test'
+ }
+
+ expect(described_class.embeddable_url(test_url)).to be_nil
+ end
+ end
+ end
+
+ describe '.allowed_for_action?' do
+ let(:group) { build_stubbed(:group) }
+ let(:user) { build_stubbed(:user) }
+
+ before do
+ allow(described_class).to receive(:allowed?).and_call_original
+ end
+
+ it 'returns false if action is nil' do
+ expect(described_class.allowed_for_action?(user, group, nil)).to eq(false)
+ end
+
+ describe 'allowed? calls' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:action, :permission) do
+ :foo | :admin_observability
+ :explore | :read_observability
+ :datasources | :admin_observability
+ :manage | :admin_observability
+ :dashboards | :read_observability
+ end
+
+ with_them do
+ it "calls allowed? with #{params[:permission]} when actions is #{params[:action]}" do
+ described_class.allowed_for_action?(user, group, action)
+ expect(described_class).to have_received(:allowed?).with(user, group, permission)
+ end
+ end
+ end
+ end
+
+ describe '.allowed?' do
+ let(:user) { build_stubbed(:user) }
+ let(:group) { build_stubbed(:group) }
+ let(:test_permission) { :read_observability }
+
+ before do
+ allow(Ability).to receive(:allowed?).and_return(false)
+ end
subject do
- described_class.observability_enabled?(user, group)
+ described_class.allowed?(user, group, test_permission)
end
- it 'checks if read_observability ability is allowed for the given user and group' do
+ it 'checks if ability is allowed for the given user and group' do
allow(Ability).to receive(:allowed?).and_return(true)
subject
- expect(Ability).to have_received(:allowed?).with(user, :read_observability, group)
+ expect(Ability).to have_received(:allowed?).with(user, test_permission, group)
end
- it 'returns true if the read_observability ability is allowed' do
+ it 'checks for admin_observability if permission is missing' do
+ described_class.allowed?(user, group)
+
+ expect(Ability).to have_received(:allowed?).with(user, :admin_observability, group)
+ end
+
+ it 'returns true if the ability is allowed' do
allow(Ability).to receive(:allowed?).and_return(true)
expect(subject).to eq(true)
end
- it 'returns false if the read_observability ability is not allowed' do
+ it 'returns false if the ability is not allowed' do
allow(Ability).to receive(:allowed?).and_return(false)
expect(subject).to eq(false)
@@ -64,5 +224,13 @@ RSpec.describe Gitlab::Observability do
expect(subject).to eq(false)
end
+
+ it 'returns false if group is missing' do
+ expect(described_class.allowed?(user, nil, :read_observability)).to eq(false)
+ end
+
+ it 'returns false if user is missing' do
+ expect(described_class.allowed?(nil, group, :read_observability)).to eq(false)
+ end
end
end
diff --git a/spec/lib/gitlab/optimistic_locking_spec.rb b/spec/lib/gitlab/optimistic_locking_spec.rb
index 1d669573b74..34f197b5ddb 100644
--- a/spec/lib/gitlab/optimistic_locking_spec.rb
+++ b/spec/lib/gitlab/optimistic_locking_spec.rb
@@ -16,6 +16,19 @@ RSpec.describe Gitlab::OptimisticLocking do
describe '#retry_lock' do
let(:name) { 'optimistic_locking_spec' }
+ it 'does not change current_scope', :aggregate_failures do
+ instance = Class.new { include Gitlab::OptimisticLocking }.new
+ relation = pipeline.cancelable_statuses
+
+ expected_scope = Ci::Build.current_scope&.to_sql
+
+ instance.send(:retry_lock, relation, name: :test) do
+ expect(Ci::Build.current_scope&.to_sql).to eq(expected_scope)
+ end
+
+ expect(Ci::Build.current_scope&.to_sql).to eq(expected_scope)
+ end
+
context 'when state changed successfully without retries' do
subject do
described_class.retry_lock(pipeline, name: name) do |lock_subject|
diff --git a/spec/lib/gitlab/pages/random_domain_spec.rb b/spec/lib/gitlab/pages/random_domain_spec.rb
new file mode 100644
index 00000000000..978412bb72c
--- /dev/null
+++ b/spec/lib/gitlab/pages/random_domain_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Pages::RandomDomain, feature_category: :pages do
+ let(:namespace_path) { 'namespace' }
+
+ subject(:generator) do
+ described_class.new(project_path: project_path, namespace_path: namespace_path)
+ end
+
+ RSpec.shared_examples 'random domain' do |domain|
+ it do
+ expect(SecureRandom)
+ .to receive(:hex)
+ .and_wrap_original do |_, size, _|
+ ('h' * size)
+ end
+
+ generated = generator.generate
+
+ expect(generated).to eq(domain)
+ expect(generated.length).to eq(63)
+ end
+ end
+
+ context 'when project path is less than 48 chars' do
+ let(:project_path) { 'p' }
+
+ it_behaves_like 'random domain', 'p-namespace-hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh'
+ end
+
+ context 'when project path is close to 48 chars' do
+ let(:project_path) { 'p' * 45 }
+
+ it_behaves_like 'random domain', 'ppppppppppppppppppppppppppppppppppppppppppppp-na-hhhhhhhhhhhhhh'
+ end
+
+ context 'when project path is larger than 48 chars' do
+ let(:project_path) { 'p' * 49 }
+
+ it_behaves_like 'random domain', 'pppppppppppppppppppppppppppppppppppppppppppppppp-hhhhhhhhhhhhhh'
+ end
+end
diff --git a/spec/lib/gitlab/pages/virtual_host_finder_spec.rb b/spec/lib/gitlab/pages/virtual_host_finder_spec.rb
new file mode 100644
index 00000000000..4b584a45503
--- /dev/null
+++ b/spec/lib/gitlab/pages/virtual_host_finder_spec.rb
@@ -0,0 +1,214 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
+ let_it_be(:project) { create(:project) }
+
+ before_all do
+ project.update_pages_deployment!(create(:pages_deployment, project: project))
+ end
+
+ it 'returns nil when host is empty' do
+ expect(described_class.new(nil).execute).to be_nil
+ expect(described_class.new('').execute).to be_nil
+ end
+
+ context 'when host is a pages custom domain host' do
+ let_it_be(:pages_domain) { create(:pages_domain, project: project) }
+
+ subject(:virtual_domain) { described_class.new(pages_domain.domain).execute }
+
+ context 'when there are no pages deployed for the project' do
+ before_all do
+ project.mark_pages_as_not_deployed
+ end
+
+ it 'returns nil' do
+ expect(virtual_domain).to be_nil
+ end
+ end
+
+ context 'when there are pages deployed for the project' do
+ before_all do
+ project.mark_pages_as_deployed
+ 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 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
+
+ context 'when host is a namespace domain' do
+ context 'when there are no pages deployed for the project' do
+ before_all do
+ project.mark_pages_as_not_deployed
+ end
+
+ it 'returns no result if the provided host is not subdomain of the Pages host' do
+ virtual_domain = described_class.new("#{project.namespace.path}.something.io").execute
+
+ expect(virtual_domain).to eq(nil)
+ end
+
+ it 'returns the virual domain with no lookup_paths' do
+ virtual_domain = described_class.new("#{project.namespace.path}.#{Settings.pages.host}").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}.#{Settings.pages.host}".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
+ before_all do
+ project.mark_pages_as_deployed
+ project.namespace.update!(path: 'topNAMEspace')
+ end
+
+ it 'returns no result if the provided host is not subdomain of the Pages host' do
+ virtual_domain = described_class.new("#{project.namespace.path}.something.io").execute
+
+ expect(virtual_domain).to eq(nil)
+ end
+
+ it 'returns the virual domain when there are pages deployed for the project' do
+ virtual_domain = described_class.new("#{project.namespace.path}.#{Settings.pages.host}").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
+
+ it 'finds domain with case-insensitive' do
+ virtual_domain = described_class.new("#{project.namespace.path}.#{Settings.pages.host.upcase}").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}.#{Settings.pages.host}").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
+
+ context 'when host is a unique domain' do
+ before_all do
+ project.project_setting.update!(pages_unique_domain: 'unique-domain')
+ end
+
+ subject(:virtual_domain) { described_class.new("unique-domain.#{Settings.pages.host.upcase}").execute }
+
+ context 'when pages unique domain is enabled' do
+ before_all do
+ project.project_setting.update!(pages_unique_domain_enabled: true)
+ end
+
+ context 'when there are no pages deployed for the project' do
+ before_all do
+ project.mark_pages_as_not_deployed
+ end
+
+ it 'returns nil' do
+ expect(virtual_domain).to be_nil
+ end
+ end
+
+ context 'when there are pages deployed for the project' do
+ before_all do
+ project.mark_pages_as_deployed
+ 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
+
+ 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
+
+ context 'when pages unique domain is disabled' do
+ before_all do
+ project.project_setting.update!(pages_unique_domain_enabled: false)
+ end
+
+ context 'when there are no pages deployed for the project' do
+ before_all do
+ project.mark_pages_as_not_deployed
+ end
+
+ it 'returns nil' do
+ expect(virtual_domain).to be_nil
+ end
+ end
+
+ context 'when there are pages deployed for the project' do
+ before_all do
+ project.mark_pages_as_deployed
+ end
+
+ it 'returns nil' do
+ expect(virtual_domain).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/patch/node_loader_spec.rb b/spec/lib/gitlab/patch/node_loader_spec.rb
new file mode 100644
index 00000000000..000083fc6d0
--- /dev/null
+++ b/spec/lib/gitlab/patch/node_loader_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Patch::NodeLoader, feature_category: :redis do
+ using RSpec::Parameterized::TableSyntax
+
+ describe '#fetch_node_info' do
+ let(:redis) { double(:redis) } # rubocop:disable RSpec/VerifiedDoubles
+
+ # rubocop:disable Naming/InclusiveLanguage
+ where(:case_name, :args, :value) do
+ [
+ [
+ 'when only ip address is present',
+ "07c37df 127.0.0.1:30004@31004 slave e7d1eec 0 1426238317239 4 connected
+67ed2db 127.0.0.1:30002@31002 master - 0 1426238316232 2 connected 5461-10922
+292f8b3 127.0.0.1:30003@31003 master - 0 1426238318243 3 connected 10923-16383
+6ec2392 127.0.0.1:30005@31005 slave 67ed2db 0 1426238316232 5 connected
+824fe11 127.0.0.1:30006@31006 slave 292f8b3 0 1426238317741 6 connected
+e7d1eec 127.0.0.1:30001@31001 myself,master - 0 0 1 connected 0-5460",
+ {
+ '127.0.0.1:30004' => 'slave', '127.0.0.1:30002' => 'master', '127.0.0.1:30003' => 'master',
+ '127.0.0.1:30005' => 'slave', '127.0.0.1:30006' => 'slave', '127.0.0.1:30001' => 'master'
+ }
+ ],
+ [
+ 'when hostname is present',
+ "07c37df 127.0.0.1:30004@31004,host1 slave e7d1eec 0 1426238317239 4 connected
+67ed2db 127.0.0.1:30002@31002,host2 master - 0 1426238316232 2 connected 5461-10922
+292f8b3 127.0.0.1:30003@31003,host3 master - 0 1426238318243 3 connected 10923-16383
+6ec2392 127.0.0.1:30005@31005,host4 slave 67ed2db 0 1426238316232 5 connected
+824fe11 127.0.0.1:30006@31006,host5 slave 292f8b3 0 1426238317741 6 connected
+e7d1eec 127.0.0.1:30001@31001,host6 myself,master - 0 0 1 connected 0-5460",
+ {
+ 'host1:30004' => 'slave', 'host2:30002' => 'master', 'host3:30003' => 'master',
+ 'host4:30005' => 'slave', 'host5:30006' => 'slave', 'host6:30001' => 'master'
+ }
+ ],
+ [
+ 'when auxiliary fields are present',
+ "07c37df 127.0.0.1:30004@31004,,shard-id=69bc slave e7d1eec 0 1426238317239 4 connected
+67ed2db 127.0.0.1:30002@31002,,shard-id=114f master - 0 1426238316232 2 connected 5461-10922
+292f8b3 127.0.0.1:30003@31003,,shard-id=fdb3 master - 0 1426238318243 3 connected 10923-16383
+6ec2392 127.0.0.1:30005@31005,,shard-id=114f slave 67ed2db 0 1426238316232 5 connected
+824fe11 127.0.0.1:30006@31006,,shard-id=fdb3 slave 292f8b3 0 1426238317741 6 connected
+e7d1eec 127.0.0.1:30001@31001,,shard-id=69bc myself,master - 0 0 1 connected 0-5460",
+ {
+ '127.0.0.1:30004' => 'slave', '127.0.0.1:30002' => 'master', '127.0.0.1:30003' => 'master',
+ '127.0.0.1:30005' => 'slave', '127.0.0.1:30006' => 'slave', '127.0.0.1:30001' => 'master'
+ }
+ ],
+ [
+ 'when hostname and auxiliary fields are present',
+ "07c37df 127.0.0.1:30004@31004,host1,shard-id=69bc slave e7d1eec 0 1426238317239 4 connected
+67ed2db 127.0.0.1:30002@31002,host2,shard-id=114f master - 0 1426238316232 2 connected 5461-10922
+292f8b3 127.0.0.1:30003@31003,host3,shard-id=fdb3 master - 0 1426238318243 3 connected 10923-16383
+6ec2392 127.0.0.1:30005@31005,host4,shard-id=114f slave 67ed2db 0 1426238316232 5 connected
+824fe11 127.0.0.1:30006@31006,host5,shard-id=fdb3 slave 292f8b3 0 1426238317741 6 connected
+e7d1eec 127.0.0.1:30001@31001,host6,shard-id=69bc myself,master - 0 0 1 connected 0-5460",
+ {
+ 'host1:30004' => 'slave', 'host2:30002' => 'master', 'host3:30003' => 'master',
+ 'host4:30005' => 'slave', 'host5:30006' => 'slave', 'host6:30001' => 'master'
+ }
+ ]
+ ]
+ end
+ # rubocop:enable Naming/InclusiveLanguage
+
+ with_them do
+ before do
+ allow(redis).to receive(:call).with([:cluster, :nodes]).and_return(args)
+ end
+
+ it do
+ expect(Redis::Cluster::NodeLoader.load_flags([redis])).to eq(value)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb b/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb
deleted file mode 100644
index ff48b9ada90..00000000000
--- a/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Prometheus::Queries::KnativeInvocationQuery do
- include PrometheusHelpers
-
- let(:project) { create(:project) }
- let(:serverless_func) { ::Serverless::Function.new(project, 'test-name', 'test-ns') }
- let(:client) { double('prometheus_client') }
-
- subject { described_class.new(client) }
-
- context 'verify queries' do
- before do
- create(:prometheus_metric,
- :common,
- identifier: :system_metrics_knative_function_invocation_count,
- query: 'sum(ceil(rate(istio_requests_total{destination_service_namespace="%{kube_namespace}", destination_service=~"%{function_name}.*"}[1m])*60))')
- end
-
- it 'has the query, but no data' do
- expect(client).to receive(:query_range).with(
- 'sum(ceil(rate(istio_requests_total{destination_service_namespace="test-ns", destination_service=~"test-name.*"}[1m])*60))',
- hash_including(:start_time, :end_time)
- )
-
- subject.query(serverless_func.id)
- end
- end
-end
diff --git a/spec/lib/gitlab/rack_attack/instrumented_cache_store_spec.rb b/spec/lib/gitlab/rack_attack/instrumented_cache_store_spec.rb
deleted file mode 100644
index 8151519ddec..00000000000
--- a/spec/lib/gitlab/rack_attack/instrumented_cache_store_spec.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::RackAttack::InstrumentedCacheStore do
- using RSpec::Parameterized::TableSyntax
-
- let(:store) { ::ActiveSupport::Cache::NullStore.new }
-
- subject { described_class.new(upstream_store: store) }
-
- where(:operation, :params, :test_proc) do
- :fetch | [:key] | ->(s) { s.fetch(:key) }
- :read | [:key] | ->(s) { s.read(:key) }
- :read_multi | [:key_1, :key_2, :key_3] | ->(s) { s.read_multi(:key_1, :key_2, :key_3) }
- :write_multi | [{ key_1: 1, key_2: 2, key_3: 3 }] | ->(s) { s.write_multi(key_1: 1, key_2: 2, key_3: 3) }
- :fetch_multi | [:key_1, :key_2, :key_3] | ->(s) { s.fetch_multi(:key_1, :key_2, :key_3) {} }
- :write | [:key, :value, { option_1: 1 }] | ->(s) { s.write(:key, :value, option_1: 1) }
- :delete | [:key] | ->(s) { s.delete(:key) }
- :exist? | [:key, { option_1: 1 }] | ->(s) { s.exist?(:key, option_1: 1) }
- :delete_matched | [/^key$/, { option_1: 1 }] | ->(s) { s.delete_matched(/^key$/, option_1: 1 ) }
- :increment | [:key, 1] | ->(s) { s.increment(:key, 1) }
- :decrement | [:key, 1] | ->(s) { s.decrement(:key, 1) }
- :cleanup | [] | ->(s) { s.cleanup }
- :clear | [] | ->(s) { s.clear }
- end
-
- with_them do
- it 'publishes a notification' do
- event = nil
-
- begin
- subscriber = ActiveSupport::Notifications.subscribe("redis.rack_attack") do |*args|
- event = ActiveSupport::Notifications::Event.new(*args)
- end
-
- test_proc.call(subject)
- ensure
- ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
- end
-
- expect(event).not_to be_nil
- expect(event.name).to eq("redis.rack_attack")
- expect(event.duration).to be_a(Float).and(be > 0.0)
- expect(event.payload[:operation]).to eql(operation)
- end
-
- it 'publishes a notification even if the cache store returns an error' do
- allow(store).to receive(operation).and_raise('Something went wrong')
-
- event = nil
- exception = nil
-
- begin
- subscriber = ActiveSupport::Notifications.subscribe("redis.rack_attack") do |*args|
- event = ActiveSupport::Notifications::Event.new(*args)
- end
-
- begin
- test_proc.call(subject)
- rescue StandardError => e
- exception = e
- end
- ensure
- ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
- end
-
- expect(event).not_to be_nil
- expect(event.name).to eq("redis.rack_attack")
- expect(event.duration).to be_a(Float).and(be > 0.0)
- expect(event.payload[:operation]).to eql(operation)
-
- expect(exception).not_to be_nil
- expect(exception.message).to eql('Something went wrong')
- end
-
- it 'delegates to the upstream store' do
- allow(store).to receive(operation).and_call_original
-
- if params.empty?
- expect(store).to receive(operation).with(no_args)
- else
- expect(store).to receive(operation).with(*params)
- end
-
- test_proc.call(subject)
- end
- end
-end
diff --git a/spec/lib/gitlab/rack_attack/store_spec.rb b/spec/lib/gitlab/rack_attack/store_spec.rb
new file mode 100644
index 00000000000..19b3f239d91
--- /dev/null
+++ b/spec/lib/gitlab/rack_attack/store_spec.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::RackAttack::Store, :clean_gitlab_redis_rate_limiting, feature_category: :scalability do
+ let(:store) { described_class.new }
+ let(:key) { 'foobar' }
+ let(:namespaced_key) { "cache:gitlab:#{key}" }
+
+ def with_redis(&block)
+ Gitlab::Redis::RateLimiting.with(&block)
+ end
+
+ describe '#increment' do
+ it 'increments without expiry' do
+ 5.times do |i|
+ expect(store.increment(key, 1)).to eq(i + 1)
+
+ with_redis do |redis|
+ expect(redis.get(namespaced_key).to_i).to eq(i + 1)
+ expect(redis.ttl(namespaced_key)).to eq(-1)
+ end
+ end
+ end
+
+ it 'rejects amounts other than 1' do
+ expect { store.increment(key, 2) }.to raise_exception(described_class::InvalidAmount)
+ end
+
+ context 'with expiry' do
+ it 'increments and sets expiry' do
+ 5.times do |i|
+ expect(store.increment(key, 1, expires_in: 456)).to eq(i + 1)
+
+ with_redis do |redis|
+ expect(redis.get(namespaced_key).to_i).to eq(i + 1)
+ expect(redis.ttl(namespaced_key)).to be_within(10).of(456)
+ end
+ end
+ end
+ end
+ end
+
+ describe '#read' do
+ subject { store.read(key) }
+
+ it 'reads the namespaced key' do
+ with_redis { |r| r.set(namespaced_key, '123') }
+
+ expect(subject).to eq('123')
+ end
+ end
+
+ describe '#write' do
+ subject { store.write(key, '123', options) }
+
+ let(:options) { {} }
+
+ it 'sets the key' do
+ subject
+
+ with_redis do |redis|
+ expect(redis.get(namespaced_key)).to eq('123')
+ expect(redis.ttl(namespaced_key)).to eq(-1)
+ end
+ end
+
+ context 'with expiry' do
+ let(:options) { { expires_in: 456 } }
+
+ it 'sets the key with expiry' do
+ subject
+
+ with_redis do |redis|
+ expect(redis.get(namespaced_key)).to eq('123')
+ expect(redis.ttl(namespaced_key)).to be_within(10).of(456)
+ end
+ end
+ end
+ end
+
+ describe '#delete' do
+ subject { store.delete(key) }
+
+ it { expect(subject).to eq(0) }
+
+ context 'when the key exists' do
+ before do
+ with_redis { |r| r.set(namespaced_key, '123') }
+ end
+
+ it { expect(subject).to eq(1) }
+ end
+ end
+
+ describe '#with' do
+ subject { store.send(:with, &:ping) }
+
+ it { expect(subject).to eq('PONG') }
+
+ context 'when redis is unavailable' do
+ before do
+ broken_redis = Redis.new(
+ url: 'redis://127.0.0.0:0',
+ instrumentation_class: Gitlab::Redis::RateLimiting.instrumentation_class
+ )
+ allow(Gitlab::Redis::RateLimiting).to receive(:with).and_yield(broken_redis)
+ end
+
+ it { expect(subject).to eq(nil) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/redis/cache_spec.rb b/spec/lib/gitlab/redis/cache_spec.rb
index 64615c4d9ad..82ff8a26199 100644
--- a/spec/lib/gitlab/redis/cache_spec.rb
+++ b/spec/lib/gitlab/redis/cache_spec.rb
@@ -26,22 +26,5 @@ RSpec.describe Gitlab::Redis::Cache do
expect(described_class.active_support_config[:expires_in]).to eq(1.day)
end
-
- context 'when encountering an error' do
- let(:cache) { ActiveSupport::Cache::RedisCacheStore.new(**described_class.active_support_config) }
-
- subject { cache.read('x') }
-
- before do
- described_class.with do |redis|
- allow(redis).to receive(:get).and_raise(::Redis::CommandError)
- end
- end
-
- it 'logs error' do
- expect(::Gitlab::ErrorTracking).to receive(:log_exception)
- subject
- end
- end
end
end
diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb
index 423a7e80ead..baf2546fc5c 100644
--- a/spec/lib/gitlab/redis/multi_store_spec.rb
+++ b/spec/lib/gitlab/redis/multi_store_spec.rb
@@ -210,47 +210,6 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
- RSpec.shared_examples_for 'fallback read from the non-default store' do
- let(:counter) { Gitlab::Metrics::NullMetric.instance }
-
- before do
- allow(Gitlab::Metrics).to receive(:counter).and_return(counter)
- end
-
- it 'fallback and execute on secondary instance' do
- expect(multi_store.fallback_store).to receive(name).with(*expected_args).and_call_original
-
- subject
- end
-
- it 'logs the ReadFromPrimaryError' do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
- an_instance_of(Gitlab::Redis::MultiStore::ReadFromPrimaryError),
- hash_including(command_name: name, instance_name: instance_name)
- )
-
- subject
- end
-
- it 'increment read fallback count metrics' do
- expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
-
- subject
- end
-
- include_examples 'reads correct value'
-
- context 'when fallback read from the secondary instance raises an exception' do
- before do
- allow(multi_store.fallback_store).to receive(name).with(*expected_args).and_raise(StandardError)
- end
-
- it 'fails with exception' do
- expect { subject }.to raise_error(StandardError)
- end
- end
- end
-
RSpec.shared_examples_for 'secondary store' do
it 'execute on the secondary instance' do
expect(secondary_store).to receive(name).with(*expected_args).and_call_original
@@ -283,31 +242,21 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
subject
end
- unless params[:block]
- it 'does not execute on the secondary store' do
- expect(secondary_store).not_to receive(name)
-
- subject
- end
- end
-
include_examples 'reads correct value'
end
- context 'when reading from primary instance is raising an exception' do
+ context 'when reading from default instance is raising an exception' do
before do
allow(multi_store.default_store).to receive(name).with(*expected_args).and_raise(StandardError)
allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
- it 'logs the exception' do
+ it 'logs the exception and re-raises the error' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
hash_including(:multi_store_error_message, instance_name: instance_name, command_name: name))
- subject
+ expect { subject }.to raise_error(an_instance_of(StandardError))
end
-
- include_examples 'fallback read from the non-default store'
end
context 'when reading from empty default instance' do
@@ -316,7 +265,9 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
multi_store.default_store.flushdb
end
- include_examples 'fallback read from the non-default store'
+ it 'does not call the fallback store' do
+ expect(multi_store.fallback_store).not_to receive(name)
+ end
end
context 'when the command is executed within pipelined block' do
@@ -346,16 +297,16 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
context 'when block is provided' do
- it 'both stores yields to the block' do
+ it 'only default store yields to the block' do
expect(primary_store).to receive(name).and_yield(value)
- expect(secondary_store).to receive(name).and_yield(value)
+ expect(secondary_store).not_to receive(name).and_yield(value)
subject
end
- it 'both stores to execute' do
+ it 'only default store to execute' do
expect(primary_store).to receive(name).with(*expected_args).and_call_original
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
+ expect(secondary_store).not_to receive(name).with(*expected_args).and_call_original
subject
end
@@ -421,27 +372,19 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
subject do
multi_store.mget(values) do |v|
multi_store.sadd(skey, v)
- multi_store.scard(skey)
- end
- end
-
- RSpec.shared_examples_for 'primary instance executes block' do
- it 'ensures primary instance is executing the block' do
- expect(primary_store).to receive(:send).with(:mget, values).and_call_original
- expect(primary_store).to receive(:send).with(:sadd, skey, %w[1 2 3]).and_call_original
- expect(primary_store).to receive(:send).with(:scard, skey).and_call_original
-
- expect(secondary_store).to receive(:send).with(:mget, values).and_call_original
- expect(secondary_store).to receive(:send).with(:sadd, skey, %w[10 20 30]).and_call_original
- expect(secondary_store).to receive(:send).with(:scard, skey).and_call_original
-
- subject
end
end
context 'when using both stores' do
context 'when primary instance is default store' do
- it_behaves_like 'primary instance executes block'
+ it 'ensures primary instance is executing the block' do
+ expect(primary_store).to receive(:send).with(:mget, values).and_call_original
+ expect(primary_store).to receive(:send).with(:sadd, skey, %w[1 2 3]).and_call_original
+
+ expect(secondary_store).not_to receive(:send)
+
+ subject
+ end
end
context 'when secondary instance is default store' do
@@ -449,8 +392,14 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
stub_feature_flags(use_primary_store_as_default_for_test_store: false)
end
- # multistore read still favours the primary store
- it_behaves_like 'primary instance executes block'
+ it 'ensures secondary instance is executing the block' do
+ expect(primary_store).not_to receive(:send)
+
+ expect(secondary_store).to receive(:send).with(:mget, values).and_call_original
+ expect(secondary_store).to receive(:send).with(:sadd, skey, %w[10 20 30]).and_call_original
+
+ subject
+ end
end
end
@@ -465,7 +414,6 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
expect(primary_store).to receive(:send).with(:mget, values).and_call_original
expect(primary_store).to receive(:send).with(:sadd, skey, %w[1 2 3]).and_call_original
- expect(primary_store).to receive(:send).with(:scard, skey).and_call_original
subject
end
@@ -479,7 +427,6 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
it 'ensures only secondary instance is executing the block' do
expect(secondary_store).to receive(:send).with(:mget, values).and_call_original
expect(secondary_store).to receive(:send).with(:sadd, skey, %w[10 20 30]).and_call_original
- expect(secondary_store).to receive(:send).with(:scard, skey).and_call_original
expect(primary_store).not_to receive(:send)
@@ -668,120 +615,6 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
# rubocop:enable RSpec/MultipleMemoizedHelpers
- context 'with ENUMERATOR_COMMANDS redis commands' do
- let_it_be(:hkey) { "redis:hash" }
- let_it_be(:skey) { "redis:set" }
- let_it_be(:zkey) { "redis:sortedset" }
- let_it_be(:rvalue) { "value1" }
- let_it_be(:scan_kwargs) { { match: 'redis:hash' } }
-
- where(:case_name, :name, :args, :kwargs) do
- 'execute :scan_each command' | :scan_each | nil | ref(:scan_kwargs)
- 'execute :sscan_each command' | :sscan_each | ref(:skey) | {}
- 'execute :hscan_each command' | :hscan_each | ref(:hkey) | {}
- 'execute :zscan_each command' | :zscan_each | ref(:zkey) | {}
- end
-
- before(:all) do
- primary_store.hset(hkey, rvalue, 1)
- primary_store.sadd?(skey, rvalue)
- primary_store.zadd(zkey, 1, rvalue)
-
- secondary_store.hset(hkey, rvalue, 1)
- secondary_store.sadd?(skey, rvalue)
- secondary_store.zadd(zkey, 1, rvalue)
- end
-
- RSpec.shared_examples_for 'enumerator commands execution' do |both_stores, default_primary|
- context 'without block passed in' do
- subject do
- multi_store.send(name, *args, **kwargs)
- end
-
- it 'returns an enumerator' do
- expect(subject).to be_instance_of(Enumerator)
- end
- end
-
- context 'with block passed in' do
- subject do
- multi_store.send(name, *args, **kwargs) { |key| multi_store.incr(rvalue) }
- end
-
- it 'returns nil' do
- expect(subject).to eq(nil)
- end
-
- it 'runs block on correct Redis instance' do
- if both_stores
- expect(primary_store).to receive(name).with(*expected_args).and_call_original
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
-
- expect(primary_store).to receive(:incr).with(rvalue)
- expect(secondary_store).to receive(:incr).with(rvalue)
- elsif default_primary
- expect(primary_store).to receive(name).with(*expected_args).and_call_original
- expect(primary_store).to receive(:incr).with(rvalue)
-
- expect(secondary_store).not_to receive(name)
- expect(secondary_store).not_to receive(:incr).with(rvalue)
- else
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
- expect(secondary_store).to receive(:incr).with(rvalue)
-
- expect(primary_store).not_to receive(name)
- expect(primary_store).not_to receive(:incr).with(rvalue)
- end
-
- subject
- end
- end
- end
-
- with_them do
- describe name.to_s do
- let(:expected_args) { kwargs.present? ? [*args, { **kwargs }] : Array(args) }
-
- before do
- allow(primary_store).to receive(name).and_call_original
- allow(secondary_store).to receive(name).and_call_original
- end
-
- context 'when only using 1 store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
- end
-
- context 'when using secondary store as default' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
-
- it_behaves_like 'enumerator commands execution', false, false
- end
-
- context 'when using primary store as default' do
- it_behaves_like 'enumerator commands execution', false, true
- end
- end
-
- context 'when using both stores' do
- context 'when using secondary store as default' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
-
- it_behaves_like 'enumerator commands execution', true, false
- end
-
- context 'when using primary store as default' do
- it_behaves_like 'enumerator commands execution', true, true
- end
- end
- end
- end
- end
-
RSpec.shared_examples_for 'pipelined command' do |name|
let_it_be(:key1) { "redis:{1}:key_a" }
let_it_be(:value1) { "redis_value1" }
diff --git a/spec/lib/gitlab/redis/rate_limiting_spec.rb b/spec/lib/gitlab/redis/rate_limiting_spec.rb
index d82228426f0..0bea7f8bcb2 100644
--- a/spec/lib/gitlab/redis/rate_limiting_spec.rb
+++ b/spec/lib/gitlab/redis/rate_limiting_spec.rb
@@ -6,19 +6,8 @@ RSpec.describe Gitlab::Redis::RateLimiting do
include_examples "redis_new_instance_shared_examples", 'rate_limiting', Gitlab::Redis::Cache
describe '.cache_store' do
- context 'when encountering an error' do
- subject { described_class.cache_store.read('x') }
-
- before do
- described_class.with do |redis|
- allow(redis).to receive(:get).and_raise(::Redis::CommandError)
- end
- end
-
- it 'logs error' do
- expect(::Gitlab::ErrorTracking).to receive(:log_exception)
- subject
- end
+ it 'uses the CACHE_NAMESPACE namespace' do
+ expect(described_class.cache_store.options[:namespace]).to eq(Gitlab::Redis::Cache::CACHE_NAMESPACE)
end
end
end
diff --git a/spec/lib/gitlab/redis/repository_cache_spec.rb b/spec/lib/gitlab/redis/repository_cache_spec.rb
index 2c167a6eb62..8cdc4580f9e 100644
--- a/spec/lib/gitlab/redis/repository_cache_spec.rb
+++ b/spec/lib/gitlab/redis/repository_cache_spec.rb
@@ -17,20 +17,5 @@ RSpec.describe Gitlab::Redis::RepositoryCache, feature_category: :scalability do
it 'has a default ttl of 8 hours' do
expect(described_class.cache_store.options[:expires_in]).to eq(8.hours)
end
-
- context 'when encountering an error' do
- subject { described_class.cache_store.read('x') }
-
- before do
- described_class.with do |redis|
- allow(redis).to receive(:get).and_raise(::Redis::CommandError)
- end
- end
-
- it 'logs error' do
- expect(::Gitlab::ErrorTracking).to receive(:log_exception)
- subject
- end
- end
end
end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 31de4068bc5..d885051b93b 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -110,6 +110,8 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
it { is_expected.to match('.source/.full/.path') }
it { is_expected.to match('domain_namespace') }
it { is_expected.to match('gitlab-migration-test') }
+ it { is_expected.to match('1-project-path') }
+ it { is_expected.to match('e-project-path') }
it { is_expected.to match('') } # it is possible to pass an empty string for destination_namespace in bulk_import POST request
end
@@ -710,6 +712,7 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
it { is_expected.to match('libsample0_1.2.3~alpha2_amd64.deb') }
it { is_expected.to match('sample-dev_1.2.3~binary_amd64.deb') }
it { is_expected.to match('sample-udeb_1.2.3~alpha2_amd64.udeb') }
+ it { is_expected.to match('sample-ddeb_1.2.3~alpha2_amd64.ddeb') }
it { is_expected.not_to match('sample_1.2.3~alpha2_amd64.buildinfo') }
it { is_expected.not_to match('sample_1.2.3~alpha2_amd64.changes') }
@@ -1015,6 +1018,34 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
it { is_expected.not_to match('/api/v4/groups/1234/packages/debian/pool/compon/a/pkg/file.name') }
end
+ describe 'Packages::MAVEN_SNAPSHOT_DYNAMIC_PARTS' do
+ subject { described_class::Packages::MAVEN_SNAPSHOT_DYNAMIC_PARTS }
+
+ it { is_expected.to match('test-2.11-20230303.163304-1.jar') }
+ it { is_expected.to match('test-2.11-20230303.163304-1-javadoc.jar') }
+ it { is_expected.to match('test-2.11-20230303.163304-1-sources.jar') }
+ it { is_expected.to match('test-2.11-20230303.163304-1-20230303.163304-1.jar') }
+ it { is_expected.to match('test-2.11-20230303.163304-1-20230303.163304-1-javadoc.jar') }
+ it { is_expected.to match('test-2.11-20230303.163304-1-20230303.163304-1-sources.jar') }
+ it { is_expected.to match("#{'a' * 500}-20230303.163304-1-sources.jar") }
+ it { is_expected.to match("test-2.11-20230303.163304-1-#{'a' * 500}.jar") }
+ it { is_expected.to match("#{'a' * 500}-20230303.163304-1-#{'a' * 500}.jar") }
+
+ it { is_expected.not_to match('') }
+ it { is_expected.not_to match(nil) }
+ it { is_expected.not_to match('test') }
+ it { is_expected.not_to match('1.2.3') }
+ it { is_expected.not_to match('1.2.3-javadoc.jar') }
+ it { is_expected.not_to match('-202303039.163304-1.jar') }
+ it { is_expected.not_to match('test-2.11-202303039.163304-1.jar') }
+ it { is_expected.not_to match('test-2.11-20230303.16330-1.jar') }
+ it { is_expected.not_to match('test-2.11-202303039.163304.jar') }
+ it { is_expected.not_to match('test-2.11-202303039.163304-.jar') }
+ it { is_expected.not_to match("#{'a' * 2000}-20230303.163304-1-sources.jar") }
+ it { is_expected.not_to match("test-2.11-20230303.163304-1-#{'a' * 2000}.jar") }
+ it { is_expected.not_to match("#{'a' * 2000}-20230303.163304-1-#{'a' * 2000}.jar") }
+ end
+
describe '.composer_package_version_regex' do
subject { described_class.composer_package_version_regex }
diff --git a/spec/lib/gitlab/safe_device_detector_spec.rb b/spec/lib/gitlab/safe_device_detector_spec.rb
index c37dc1e1c7e..56ba084c435 100644
--- a/spec/lib/gitlab/safe_device_detector_spec.rb
+++ b/spec/lib/gitlab/safe_device_detector_spec.rb
@@ -4,7 +4,7 @@ require 'fast_spec_helper'
require 'device_detector'
require_relative '../../../lib/gitlab/safe_device_detector'
-RSpec.describe Gitlab::SafeDeviceDetector, feature_category: :authentication_and_authorization do
+RSpec.describe Gitlab::SafeDeviceDetector, feature_category: :system_access do
it 'retains the behavior for normal user agents' do
chrome_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
diff --git a/spec/lib/gitlab/sanitizers/exception_message_spec.rb b/spec/lib/gitlab/sanitizers/exception_message_spec.rb
index 8b54b353235..c2c4a5de32d 100644
--- a/spec/lib/gitlab/sanitizers/exception_message_spec.rb
+++ b/spec/lib/gitlab/sanitizers/exception_message_spec.rb
@@ -1,9 +1,10 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'addressable'
require 'rspec-parameterized'
-RSpec.describe Gitlab::Sanitizers::ExceptionMessage do
+RSpec.describe Gitlab::Sanitizers::ExceptionMessage, feature_category: :compliance_management do
describe '.clean' do
let(:exception_name) { exception.class.name }
let(:exception_message) { exception.message }
diff --git a/spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb b/spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb
index fe52b586d49..4597cc6b315 100644
--- a/spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb
+++ b/spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb
@@ -67,5 +67,29 @@ RSpec.describe ::Gitlab::Seeders::Ci::Runner::RunnerFleetSeeder, feature_categor
expect(::Ci::Build.where(runner_id: project[:runner_ids])).to be_empty
end
end
+
+ context 'when number of group runners exceeds plan limit' do
+ before do
+ create(:plan_limits, :default_plan, ci_registered_group_runners: 1)
+ end
+
+ it { is_expected.to be_nil }
+
+ it 'does not change runner count' do
+ expect { seed }.not_to change { Ci::Runner.count }
+ end
+ end
+
+ context 'when number of project runners exceeds plan limit' do
+ before do
+ create(:plan_limits, :default_plan, ci_registered_project_runners: 1)
+ end
+
+ it { is_expected.to be_nil }
+
+ it 'does not change runner count' do
+ expect { seed }.not_to change { Ci::Runner.count }
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/serverless/service_spec.rb b/spec/lib/gitlab/serverless/service_spec.rb
deleted file mode 100644
index 3400be5b48e..00000000000
--- a/spec/lib/gitlab/serverless/service_spec.rb
+++ /dev/null
@@ -1,136 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Serverless::Service do
- let(:cluster) { create(:cluster) }
- let(:environment) { create(:environment) }
- let(:attributes) do
- {
- 'apiVersion' => 'serving.knative.dev/v1alpha1',
- 'kind' => 'Service',
- 'metadata' => {
- 'creationTimestamp' => '2019-10-22T21:19:13Z',
- 'name' => 'kubetest',
- 'namespace' => 'project1-1-environment1'
- },
- 'spec' => {
- 'runLatest' => {
- 'configuration' => {
- 'build' => {
- 'template' => {
- 'name' => 'some-image'
- }
- }
- }
- }
- },
- 'environment_scope' => '*',
- 'cluster' => cluster,
- 'environment' => environment,
- 'podcount' => 0
- }
- end
-
- it 'exposes methods extracting data from the attributes hash' do
- service = Gitlab::Serverless::Service.new(attributes)
-
- expect(service.name).to eq('kubetest')
- expect(service.namespace).to eq('project1-1-environment1')
- expect(service.environment_scope).to eq('*')
- expect(service.podcount).to eq(0)
- expect(service.created_at).to eq(DateTime.parse('2019-10-22T21:19:13Z'))
- expect(service.image).to eq('some-image')
- expect(service.cluster).to eq(cluster)
- expect(service.environment).to eq(environment)
- end
-
- it 'returns nil for missing attributes' do
- service = Gitlab::Serverless::Service.new({})
-
- [:name, :namespace, :environment_scope, :cluster, :podcount, :created_at, :image, :description, :url, :environment].each do |method|
- expect(service.send(method)).to be_nil
- end
- end
-
- describe '#description' do
- it 'extracts the description in knative 7 format if available' do
- attributes = {
- 'spec' => {
- 'template' => {
- 'metadata' => {
- 'annotations' => {
- 'Description' => 'some description'
- }
- }
- }
- }
- }
- service = Gitlab::Serverless::Service.new(attributes)
-
- expect(service.description).to eq('some description')
- end
-
- it 'extracts the description in knative 5/6 format if 7 is not available' do
- attributes = {
- 'spec' => {
- 'runLatest' => {
- 'configuration' => {
- 'revisionTemplate' => {
- 'metadata' => {
- 'annotations' => {
- 'Description' => 'some description'
- }
- }
- }
- }
- }
- }
- }
- service = Gitlab::Serverless::Service.new(attributes)
-
- expect(service.description).to eq('some description')
- end
- end
-
- describe '#url' do
- let(:serverless_domain) { instance_double(::Serverless::Domain, uri: URI('https://proxy.example.com')) }
-
- it 'returns proxy URL if cluster has serverless domain' do
- # cluster = create(:cluster)
- knative = create(:clusters_applications_knative, :installed, cluster: cluster)
- create(:serverless_domain_cluster, clusters_applications_knative_id: knative.id)
- service = Gitlab::Serverless::Service.new(attributes.merge('cluster' => cluster))
-
- expect(::Serverless::Domain).to receive(:new).with(
- function_name: service.name,
- serverless_domain_cluster: service.cluster.serverless_domain,
- environment: service.environment
- ).and_return(serverless_domain)
-
- expect(service.url).to eq('https://proxy.example.com')
- end
-
- it 'returns the URL from the knative 6/7 format' do
- attributes = {
- 'status' => {
- 'url' => 'https://example.com'
- }
- }
- service = Gitlab::Serverless::Service.new(attributes)
-
- expect(service.url).to eq('https://example.com')
- end
-
- it 'returns the URL from the knative 5 format' do
- attributes = {
- 'status' => {
- 'domain' => 'example.com'
- }
- }
- service = Gitlab::Serverless::Service.new(attributes)
-
- expect(service.url).to eq('http://example.com')
- end
- end
-end
diff --git a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
index f7cee6beb58..80c1af1b913 100644
--- a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
@@ -331,7 +331,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
include_context 'server metrics call'
context 'when a worker has a feature category' do
- let(:worker_category) { 'authentication_and_authorization' }
+ let(:worker_category) { 'system_access' }
it 'uses that category for metrics' do
expect(completion_seconds_metric).to receive(:observe).with(a_hash_including(feature_category: worker_category), anything)
diff --git a/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb b/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
index 1b6cd7ac5fb..4fbc64a45d6 100644
--- a/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
@@ -123,7 +123,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
context 'when the feature category is already set in the surrounding block' do
it 'takes the feature category from the worker, not the caller' do
- Gitlab::ApplicationContext.with_context(feature_category: 'authentication_and_authorization') do
+ Gitlab::ApplicationContext.with_context(feature_category: 'system_access') do
TestWithContextWorker.bulk_perform_async_with_contexts(
%w(job1 job2),
arguments_proc: -> (name) { [name, 1, 2, 3] },
@@ -139,7 +139,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
end
it 'takes the feature category from the caller if the worker is not owned' do
- Gitlab::ApplicationContext.with_context(feature_category: 'authentication_and_authorization') do
+ Gitlab::ApplicationContext.with_context(feature_category: 'system_access') do
TestNotOwnedWithContextWorker.bulk_perform_async_with_contexts(
%w(job1 job2),
arguments_proc: -> (name) { [name, 1, 2, 3] },
@@ -150,8 +150,8 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
job1 = TestNotOwnedWithContextWorker.job_for_args(['job1', 1, 2, 3])
job2 = TestNotOwnedWithContextWorker.job_for_args(['job2', 1, 2, 3])
- expect(job1['meta.feature_category']).to eq('authentication_and_authorization')
- expect(job2['meta.feature_category']).to eq('authentication_and_authorization')
+ expect(job1['meta.feature_category']).to eq('system_access')
+ expect(job2['meta.feature_category']).to eq('system_access')
end
end
end
diff --git a/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb b/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
index 2deab3064eb..eb077a0371c 100644
--- a/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
@@ -69,7 +69,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
context 'feature category' do
it 'takes the feature category from the worker' do
- Gitlab::ApplicationContext.with_context(feature_category: 'authentication_and_authorization') do
+ Gitlab::ApplicationContext.with_context(feature_category: 'system_access') do
TestWorker.perform_async('identifier', 1)
end
@@ -78,11 +78,11 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
context 'when the worker is not owned' do
it 'takes the feature category from the surrounding context' do
- Gitlab::ApplicationContext.with_context(feature_category: 'authentication_and_authorization') do
+ Gitlab::ApplicationContext.with_context(feature_category: 'system_access') do
NotOwnedWorker.perform_async('identifier', 1)
end
- expect(NotOwnedWorker.contexts['identifier']).to include('meta.feature_category' => 'authentication_and_authorization')
+ expect(NotOwnedWorker.contexts['identifier']).to include('meta.feature_category' => 'system_access')
end
end
end
diff --git a/spec/lib/gitlab/sidekiq_queue_spec.rb b/spec/lib/gitlab/sidekiq_queue_spec.rb
index 5e91282612e..93632848788 100644
--- a/spec/lib/gitlab/sidekiq_queue_spec.rb
+++ b/spec/lib/gitlab/sidekiq_queue_spec.rb
@@ -4,15 +4,15 @@ require 'spec_helper'
RSpec.describe Gitlab::SidekiqQueue, :clean_gitlab_redis_queues do
around do |example|
- Sidekiq::Queue.new('default').clear
+ Sidekiq::Queue.new('foobar').clear
Sidekiq::Testing.disable!(&example)
- Sidekiq::Queue.new('default').clear
+ Sidekiq::Queue.new('foobar').clear
end
def add_job(args, user:, klass: 'AuthorizedProjectsWorker')
Sidekiq::Client.push(
'class' => klass,
- 'queue' => 'default',
+ 'queue' => 'foobar',
'args' => args,
'meta.user' => user.username
)
@@ -20,7 +20,7 @@ RSpec.describe Gitlab::SidekiqQueue, :clean_gitlab_redis_queues do
describe '#drop_jobs!' do
shared_examples 'queue processing' do
- let(:sidekiq_queue) { described_class.new('default') }
+ let(:sidekiq_queue) { described_class.new('foobar') }
let_it_be(:sidekiq_queue_user) { create(:user) }
before do
@@ -80,7 +80,7 @@ RSpec.describe Gitlab::SidekiqQueue, :clean_gitlab_redis_queues do
it 'raises NoMetadataError' do
add_job([1], user: create(:user))
- expect { described_class.new('default').drop_jobs!({ username: 'sidekiq_queue_user' }, timeout: 1) }
+ expect { described_class.new('foobar').drop_jobs!({ username: 'sidekiq_queue_user' }, timeout: 1) }
.to raise_error(described_class::NoMetadataError)
end
end
diff --git a/spec/lib/gitlab/slug/path_spec.rb b/spec/lib/gitlab/slug/path_spec.rb
index 9a7067e40a2..bbc2a05713d 100644
--- a/spec/lib/gitlab/slug/path_spec.rb
+++ b/spec/lib/gitlab/slug/path_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Slug::Path, feature_category: :not_owned do
+RSpec.describe Gitlab::Slug::Path, feature_category: :shared do
describe '#generate' do
{
'name': 'name',
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index 05f7af7606d..912093be29f 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -8,7 +8,9 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:schemes) { %w[http https] }
describe '#validate!' do
- subject { described_class.validate!(import_url, schemes: schemes) }
+ let(:options) { { schemes: schemes } }
+
+ subject { described_class.validate!(import_url, **options) }
shared_examples 'validates URI and hostname' do
it 'runs the url validations' do
@@ -19,6 +21,73 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
end
end
+ shared_context 'instance configured to deny all requests' do
+ before do
+ allow(Gitlab::CurrentSettings).to receive(:current_application_settings?).and_return(true)
+ stub_application_setting(deny_all_requests_except_allowed: true)
+ end
+ end
+
+ shared_examples 'a URI denied by `deny_all_requests_except_allowed`' do
+ context 'when instance setting is enabled' do
+ include_context '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 '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 }
@@ -26,6 +95,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_uri) { nil }
let(:expected_hostname) { nil }
end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
end
context 'when URI is internal' do
@@ -39,6 +110,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_uri) { 'http://127.0.0.1' }
let(:expected_hostname) { 'localhost' }
end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
end
context 'when URI is for a local object storage' do
@@ -61,7 +134,7 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
end
context 'when allow_object_storage is true' do
- subject { described_class.validate!(import_url, allow_object_storage: true, schemes: schemes) }
+ let(:options) { { allow_object_storage: true, schemes: schemes } }
context 'with a local domain name' do
let(:host) { 'http://review-minio-svc.svc:9000' }
@@ -74,6 +147,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only 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' }
end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
end
context 'with an IP address' do
@@ -83,6 +158,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_uri) { 'http://127.0.0.1:9000/external-diffs/merge_request_diffs/mr-1/diff-1' }
let(:expected_hostname) { nil }
end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
end
context 'when LFS object storage is enabled' do
@@ -164,6 +241,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_uri) { 'https://93.184.216.34' }
let(:expected_hostname) { 'example.org' }
end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
end
context 'when domain cannot be resolved' do
@@ -193,6 +272,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_hostname) { nil }
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' }
@@ -217,10 +298,12 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only 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' }
end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
end
context 'disabled DNS rebinding protection' do
- subject { described_class.validate!(import_url, dns_rebind_protection: false, schemes: schemes) }
+ let(:options) { { dns_rebind_protection: false, schemes: schemes } }
context 'when URI is internal' do
let(:import_url) { 'http://localhost' }
@@ -229,6 +312,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
end
context 'when the URL hostname is a domain' do
@@ -243,6 +328,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
end
context 'when domain cannot be resolved' do
@@ -252,6 +339,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
end
end
@@ -263,6 +352,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_hostname) { nil }
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' }
@@ -270,6 +361,8 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
let(:expected_uri) { import_url }
let(:expected_hostname) { nil }
end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
end
end
end
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index 2e9a444bd24..08a25666ae9 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -227,27 +227,5 @@ RSpec.describe Gitlab::UrlBuilder do
expect(subject.build(object, only_path: true)).to eq("/#{project.full_path}")
end
end
-
- context 'when use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- context 'when a task issue is passed' do
- it 'returns a path using the work item\'s ID and no query params' do
- task = create(:issue, :task)
-
- expect(subject.build(task, only_path: true)).to eq("/#{task.project.full_path}/-/work_items/#{task.id}")
- end
- end
-
- context 'when a work item is passed' do
- it 'returns a path using the work item\'s ID and no query params' do
- work_item = create(:work_item)
-
- expect(subject.build(work_item, only_path: true)).to eq("/#{work_item.project.full_path}/-/work_items/#{work_item.id}")
- end
- end
- end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb
index ce15d44b1e1..317929f77e6 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitiesMetric do
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitiesMetric, feature_category: :importers do
let_it_be(:user) { create(:user) }
let_it_be(:bulk_import_projects) do
create_list(:bulk_import_entity, 2, source_type: 'project_entity', created_at: 3.weeks.ago, status: 2)
@@ -163,4 +163,121 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
options: { status: 2, source_type: 'project_entity' }
end
end
+
+ context 'with has_failures: true' do
+ before(:all) do
+ create_list(:bulk_import_entity, 3, :project_entity, :finished, created_at: 3.weeks.ago, has_failures: true)
+ create_list(:bulk_import_entity, 2, :project_entity, :finished, created_at: 2.months.ago, has_failures: true)
+ create_list(:bulk_import_entity, 3, :group_entity, :finished, created_at: 3.weeks.ago, has_failures: true)
+ create_list(:bulk_import_entity, 2, :group_entity, :finished, created_at: 2.months.ago, has_failures: true)
+ end
+
+ context 'with all time frame' do
+ context 'with project entity' do
+ let(:expected_value) { 5 }
+ let(:expected_query) do
+ "SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
+ "WHERE \"bulk_import_entities\".\"source_type\" = 1 AND \"bulk_import_entities\".\"status\" = 2 " \
+ "AND \"bulk_import_entities\".\"has_failures\" = TRUE"
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query',
+ time_frame: 'all',
+ options: { status: 2, source_type: 'project_entity', has_failures: true }
+ end
+
+ context 'with group entity' do
+ let(:expected_value) { 5 }
+ let(:expected_query) do
+ "SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
+ "WHERE \"bulk_import_entities\".\"source_type\" = 0 AND \"bulk_import_entities\".\"status\" = 2 " \
+ "AND \"bulk_import_entities\".\"has_failures\" = TRUE"
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query',
+ time_frame: 'all',
+ options: { status: 2, source_type: 'group_entity', has_failures: true }
+ end
+ end
+
+ context 'for 28d time frame' do
+ let(:expected_value) { 3 }
+ let(:start) { 30.days.ago.to_s(:db) }
+ let(:finish) { 2.days.ago.to_s(:db) }
+ let(:expected_query) do
+ "SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
+ "WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' " \
+ "AND \"bulk_import_entities\".\"source_type\" = 1 AND \"bulk_import_entities\".\"status\" = 2 " \
+ "AND \"bulk_import_entities\".\"has_failures\" = TRUE"
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query',
+ time_frame: '28d',
+ options: { status: 2, source_type: 'project_entity', has_failures: true }
+ end
+ end
+
+ context 'with has_failures: false' do
+ context 'with all time frame' do
+ context 'with project entity' do
+ let(:expected_value) { 3 }
+ let(:expected_query) do
+ "SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
+ "WHERE \"bulk_import_entities\".\"source_type\" = 1 AND \"bulk_import_entities\".\"status\" = 2 " \
+ "AND \"bulk_import_entities\".\"has_failures\" = FALSE"
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query',
+ time_frame: 'all',
+ options: { status: 2, source_type: 'project_entity', has_failures: false }
+ end
+
+ context 'with group entity' do
+ let(:expected_value) { 2 }
+ let(:expected_query) do
+ "SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
+ "WHERE \"bulk_import_entities\".\"source_type\" = 0 AND \"bulk_import_entities\".\"status\" = 2 " \
+ "AND \"bulk_import_entities\".\"has_failures\" = FALSE"
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query',
+ time_frame: 'all',
+ options: { status: 2, source_type: 'group_entity', has_failures: false }
+ end
+ end
+
+ context 'for 28d time frame' do
+ context 'with project entity' do
+ let(:expected_value) { 2 }
+ let(:start) { 30.days.ago.to_s(:db) }
+ let(:finish) { 2.days.ago.to_s(:db) }
+ let(:expected_query) do
+ "SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
+ "WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' " \
+ "AND \"bulk_import_entities\".\"source_type\" = 1 AND \"bulk_import_entities\".\"status\" = 2 " \
+ "AND \"bulk_import_entities\".\"has_failures\" = FALSE"
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query',
+ time_frame: '28d',
+ options: { status: 2, source_type: 'project_entity', has_failures: false }
+ end
+
+ context 'with group entity' do
+ let(:expected_value) { 2 }
+ let(:start) { 30.days.ago.to_s(:db) }
+ let(:finish) { 2.days.ago.to_s(:db) }
+ let(:expected_query) do
+ "SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
+ "WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' " \
+ "AND \"bulk_import_entities\".\"source_type\" = 0 AND \"bulk_import_entities\".\"status\" = 2 " \
+ "AND \"bulk_import_entities\".\"has_failures\" = FALSE"
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query',
+ time_frame: '28d',
+ options: { status: 2, source_type: 'group_entity', has_failures: false }
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_ci_internal_pipelines_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_ci_internal_pipelines_metric_spec.rb
index afd8fccd56c..77c49d448d7 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_ci_internal_pipelines_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_ci_internal_pipelines_metric_spec.rb
@@ -4,25 +4,23 @@ require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountCiInternalPipelinesMetric,
feature_category: :service_ping do
- let_it_be(:ci_pipeline_1) { create(:ci_pipeline, source: :external) }
- let_it_be(:ci_pipeline_2) { create(:ci_pipeline, source: :push) }
-
- let(:expected_value) { 1 }
- let(:expected_query) do
- 'SELECT COUNT("ci_pipelines"."id") FROM "ci_pipelines" ' \
- 'WHERE ("ci_pipelines"."source" IN (1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15) ' \
- 'OR "ci_pipelines"."source" IS NULL)'
- end
+ let_it_be(:ci_pipeline_1) { create(:ci_pipeline, source: :external, created_at: 3.days.ago) }
+ let_it_be(:ci_pipeline_2) { create(:ci_pipeline, source: :push, created_at: 3.days.ago) }
+ let_it_be(:old_pipeline) { create(:ci_pipeline, source: :push, created_at: 2.months.ago) }
+ let_it_be(:expected_value) { 2 }
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }
- context 'on Gitlab.com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
+ context 'for monthly counts' do
+ let_it_be(:expected_value) { 1 }
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', data_source: 'database' }
+ end
- let(:expected_value) { -1 }
+ context 'on SaaS', :saas do
+ let_it_be(:expected_value) { -1 }
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', data_source: 'database' }
end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric_spec.rb
index 86f54c48666..65e514bf345 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric_spec.rb
@@ -16,11 +16,7 @@ feature_category: :service_ping do
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }
- context 'on Gitlab.com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
+ context 'on SaaS', :saas do
let(:expected_value) { -1 }
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric_spec.rb
new file mode 100644
index 00000000000..a35022ec2c4
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::GitlabDedicatedMetric, feature_category: :service_ping do
+ let(:expected_value) { Gitlab::CurrentSettings.gitlab_dedicated_instance }
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'none' }
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric_spec.rb
new file mode 100644
index 00000000000..afc9d610207
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::IndexInconsistenciesMetric, feature_category: :database do
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all' } do
+ let(:expected_value) do
+ [
+ { inconsistency_type: 'wrong_indexes', object_name: 'index_name_1' },
+ { inconsistency_type: 'missing_indexes', object_name: 'index_name_2' },
+ { inconsistency_type: 'extra_indexes', object_name: 'index_name_3' }
+ ]
+ end
+
+ let(:runner) { instance_double(Gitlab::Database::SchemaValidation::Runner, execute: inconsistencies) }
+ let(:inconsistency_class) { Gitlab::Database::SchemaValidation::Validators::BaseValidator::Inconsistency }
+
+ let(:inconsistencies) do
+ [
+ instance_double(inconsistency_class, object_name: 'index_name_1', type: 'wrong_indexes'),
+ instance_double(inconsistency_class, object_name: 'index_name_2', type: 'missing_indexes'),
+ instance_double(inconsistency_class, object_name: 'index_name_3', type: 'extra_indexes')
+ ]
+ end
+
+ before do
+ allow(Gitlab::Database::SchemaValidation::Runner).to receive(:new).and_return(runner)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric_spec.rb
new file mode 100644
index 00000000000..ff6be56c13f
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::InstallationCreationDateMetric,
+ feature_category: :service_ping do
+ context 'with a root user' do
+ let_it_be(:root) { create(:user, id: 1) }
+ let_it_be(:expected_value) { root.reload.created_at } # reloading to get the timestamp from the database
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }
+ end
+
+ context 'without a root user' do
+ let_it_be(:another_user) { create(:user, id: 2) }
+ let_it_be(:expected_value) { nil }
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }
+ end
+end
diff --git a/spec/lib/gitlab/usage_data_counters/code_review_events_spec.rb b/spec/lib/gitlab/usage_data_counters/code_review_events_spec.rb
index 63a1da490ed..8da86e4fae5 100644
--- a/spec/lib/gitlab/usage_data_counters/code_review_events_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/code_review_events_spec.rb
@@ -6,17 +6,23 @@ require 'spec_helper'
# NOTE: ONLY user related metrics to be added to the aggregates - otherwise add it to the exception list
RSpec.describe 'Code review events' do
it 'the aggregated metrics contain all the code review metrics' do
- code_review_events = Gitlab::UsageDataCounters::HLLRedisCounter.events_for_category("code_review")
+ mr_related_events = %w[i_code_review_create_mr i_code_review_mr_diffs i_code_review_mr_with_invalid_approvers i_code_review_mr_single_file_diffs i_code_review_total_suggestions_applied i_code_review_total_suggestions_added i_code_review_create_note_in_ipynb_diff i_code_review_create_note_in_ipynb_diff_mr i_code_review_create_note_in_ipynb_diff_commit i_code_review_merge_request_widget_license_compliance_warning]
+
+ all_code_review_events = Gitlab::Usage::MetricDefinition.all.flat_map do |definition|
+ next [] unless definition.attributes[:key_path].include?('.code_review.') &&
+ definition.attributes[:status] == 'active' &&
+ definition.attributes[:instrumentation_class] != 'AggregatedMetric'
+
+ definition.attributes.dig(:options, :events)
+ end.uniq.compact
+
code_review_aggregated_events = Gitlab::Usage::MetricDefinition.all.flat_map do |definition|
next [] unless code_review_aggregated_metric?(definition.attributes)
definition.attributes.dig(:options, :events)
end.uniq
- exceptions = %w[i_code_review_create_mr i_code_review_mr_diffs i_code_review_mr_with_invalid_approvers i_code_review_mr_single_file_diffs i_code_review_total_suggestions_applied i_code_review_total_suggestions_added i_code_review_create_note_in_ipynb_diff i_code_review_create_note_in_ipynb_diff_mr i_code_review_create_note_in_ipynb_diff_commit]
- code_review_aggregated_events += exceptions
-
- expect(code_review_events - code_review_aggregated_events).to be_empty
+ expect(all_code_review_events - (code_review_aggregated_events + mr_related_events)).to be_empty
end
def code_review_aggregated_metric?(attributes)
diff --git a/spec/lib/gitlab/usage_data_counters/container_registry_event_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/container_registry_event_counter_spec.rb
new file mode 100644
index 00000000000..052735db96b
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_counters/container_registry_event_counter_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::UsageDataCounters::ContainerRegistryEventCounter, :clean_gitlab_redis_shared_state,
+ feature_category: :container_registry do
+ described_class::KNOWN_EVENTS.each do |event|
+ it_behaves_like 'a redis usage counter', 'ContainerRegistryEvent', event
+ it_behaves_like 'a redis usage counter with totals', :container_registry_events, "#{event}": 5
+ end
+end
diff --git a/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb
index f8a4603c1f8..c16d31cd8ef 100644
--- a/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb
@@ -25,12 +25,29 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red
end
end
+ it 'track snowplow event' do
+ track_action(author: user1, project: project)
+
+ expect_snowplow_event(
+ category: described_class.name,
+ action: 'ide_edit',
+ label: 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit',
+ namespace: project.namespace,
+ property: event_name,
+ project: project,
+ user: user1,
+ context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_h]
+ )
+ end
+
it 'does not track edit actions if author is not present' do
expect(track_action(author: nil, project: project)).to be_nil
end
end
context 'for web IDE edit actions' do
+ let(:event_name) { described_class::EDIT_BY_WEB_IDE }
+
it_behaves_like 'tracks and counts action' do
def track_action(params)
described_class.track_web_ide_edit_action(**params)
@@ -43,6 +60,8 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red
end
context 'for SFE edit actions' do
+ let(:event_name) { described_class::EDIT_BY_SFE }
+
it_behaves_like 'tracks and counts action' do
def track_action(params)
described_class.track_sfe_edit_action(**params)
@@ -55,6 +74,8 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red
end
context 'for snippet editor edit actions' do
+ let(:event_name) { described_class::EDIT_BY_SNIPPET_EDITOR }
+
it_behaves_like 'tracks and counts action' do
def track_action(params)
described_class.track_snippet_editor_edit_action(**params)
diff --git a/spec/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter_spec.rb
index d6eb67e5c35..9cbac835a6f 100644
--- a/spec/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter_spec.rb
@@ -7,9 +7,18 @@ RSpec.describe Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter, :clean
let(:user2) { build(:user, id: 2) }
let(:time) { Time.current }
let(:action) { described_class::GITLAB_CLI_API_REQUEST_ACTION }
- let(:user_agent) { { user_agent: 'GLab - GitLab CLI' } }
context 'when tracking a gitlab cli request' do
- it_behaves_like 'a request from an extension'
+ context 'with the old UserAgent' do
+ let(:user_agent) { { user_agent: 'GLab - GitLab CLI' } }
+
+ it_behaves_like 'a request from an extension'
+ end
+
+ context 'with the current UserAgent' do
+ let(:user_agent) { { user_agent: 'glab/v1.25.3-27-g7ec258fb (built 2023-02-16), darwin' } }
+
+ it_behaves_like 'a request from an extension'
+ end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
index f955fd265e5..8c497970555 100644
--- a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
@@ -23,47 +23,12 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
described_class.clear_memoization(:known_events)
end
- describe '.categories' do
- it 'gets CE unique category names' do
- expect(described_class.categories).to include(
- 'analytics',
- 'ci_templates',
- 'ci_users',
- 'code_review',
- 'deploy_token_packages',
- 'ecosystem',
- 'environments',
- 'error_tracking',
- 'geo',
- 'ide_edit',
- 'importer',
- 'incident_management_alerts',
- 'incident_management',
- 'issues_edit',
- 'kubernetes_agent',
- 'manage',
- 'pipeline_authoring',
- 'quickactions',
- 'search',
- 'secure',
- 'snippets',
- 'source_code',
- 'terraform',
- 'testing',
- 'user_packages',
- 'work_items'
- )
- end
- end
-
describe '.known_events' do
let(:ce_temp_dir) { Dir.mktmpdir }
let(:ce_temp_file) { Tempfile.new(%w[common .yml], ce_temp_dir) }
let(:ce_event) do
{
"name" => "ce_event",
- "redis_slot" => "analytics",
- "category" => "analytics",
"aggregation" => "weekly"
}
end
@@ -84,8 +49,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
end
describe 'known_events' do
- let(:feature) { 'test_hll_redis_counter_ff_check' }
-
let(:weekly_event) { 'g_analytics_contribution' }
let(:daily_event) { 'g_analytics_search' }
let(:analytics_slot_event) { 'g_analytics_contribution' }
@@ -105,13 +68,13 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:known_events) do
[
- { name: weekly_event, redis_slot: "analytics", category: analytics_category, aggregation: "weekly", feature_flag: feature },
- { name: daily_event, redis_slot: "analytics", category: analytics_category, aggregation: "daily" },
- { name: category_productivity_event, redis_slot: "analytics", category: productivity_category, aggregation: "weekly" },
- { name: compliance_slot_event, redis_slot: "compliance", category: compliance_category, aggregation: "weekly" },
- { name: no_slot, category: global_category, aggregation: "daily" },
- { name: different_aggregation, category: global_category, aggregation: "monthly" },
- { name: context_event, category: other_category, aggregation: 'weekly' }
+ { name: weekly_event, aggregation: "weekly" },
+ { name: daily_event, aggregation: "daily" },
+ { name: category_productivity_event, aggregation: "weekly" },
+ { name: compliance_slot_event, aggregation: "weekly" },
+ { name: no_slot, aggregation: "daily" },
+ { name: different_aggregation, aggregation: "monthly" },
+ { name: context_event, aggregation: 'weekly' }
].map(&:with_indifferent_access)
end
@@ -121,12 +84,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
allow(described_class).to receive(:known_events).and_return(known_events)
end
- describe '.events_for_category' do
- it 'gets the event names for given category' do
- expect(described_class.events_for_category(:analytics)).to contain_exactly(weekly_event, daily_event)
- end
- end
-
describe '.track_event' do
context 'with redis_hll_tracking' do
it 'tracks the event when feature enabled' do
@@ -146,32 +103,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
end
end
- context 'with event feature flag set' do
- it 'tracks the event when feature enabled' do
- stub_feature_flags(feature => true)
-
- expect(Gitlab::Redis::HLL).to receive(:add)
-
- described_class.track_event(weekly_event, values: 1)
- end
-
- it 'does not track the event with feature flag disabled' do
- stub_feature_flags(feature => false)
-
- expect(Gitlab::Redis::HLL).not_to receive(:add)
-
- described_class.track_event(weekly_event, values: 1)
- end
- end
-
- context 'with no event feature flag set' do
- it 'tracks the event' do
- expect(Gitlab::Redis::HLL).to receive(:add)
-
- described_class.track_event(daily_event, values: 1)
- end
- end
-
context 'when usage_ping is disabled' do
it 'does not track the event' do
allow(::ServicePing::ServicePingSettings).to receive(:enabled?).and_return(false)
@@ -195,7 +126,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
it 'tracks events with multiple values' do
values = [entity1, entity2]
- expect(Gitlab::Redis::HLL).to receive(:add).with(key: /g_{analytics}_contribution/, value: values,
+ expect(Gitlab::Redis::HLL).to receive(:add).with(key: /g_analytics_contribution/, value: values,
expiry: described_class::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH)
described_class.track_event(:g_analytics_contribution, values: values)
@@ -237,7 +168,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
described_class.track_event("g_compliance_dashboard", values: entity1)
Gitlab::Redis::SharedState.with do |redis|
- keys = redis.scan_each(match: "g_{compliance}_dashboard-*").to_a
+ keys = redis.scan_each(match: "{#{described_class::REDIS_SLOT}}_g_compliance_dashboard-*").to_a
expect(keys).not_to be_empty
keys.each do |key|
@@ -252,7 +183,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
described_class.track_event("no_slot", values: entity1)
Gitlab::Redis::SharedState.with do |redis|
- keys = redis.scan_each(match: "*-{no_slot}").to_a
+ keys = redis.scan_each(match: "*_no_slot").to_a
expect(keys).not_to be_empty
keys.each do |key|
@@ -276,7 +207,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
it 'tracks events with multiple values' do
values = [entity1, entity2]
- expect(Gitlab::Redis::HLL).to receive(:add).with(key: /g_{analytics}_contribution/,
+ expect(Gitlab::Redis::HLL).to receive(:add).with(key: /g_analytics_contribution/,
value: values,
expiry: described_class::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH)
@@ -340,18 +271,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
expect(described_class.unique_events(event_names: [weekly_event], start_date: Date.current, end_date: 4.weeks.ago)).to eq(-1)
end
- it 'raise error if metrics are not in the same slot' do
- expect do
- described_class.unique_events(event_names: [compliance_slot_event, analytics_slot_event], start_date: 4.weeks.ago, end_date: Date.current)
- end.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::SlotMismatch)
- end
-
- it 'raise error if metrics are not in the same category' do
- expect do
- described_class.unique_events(event_names: [category_analytics_event, category_productivity_event], start_date: 4.weeks.ago, end_date: Date.current)
- end.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::CategoryMismatch)
- end
-
it "raise error if metrics don't have same aggregation" do
expect do
described_class.unique_events(event_names: [daily_event, weekly_event], start_date: 4.weeks.ago, end_date: Date.current)
@@ -398,6 +317,10 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:weekly_event) { 'i_search_total' }
let(:redis_event) { described_class.send(:event_for, weekly_event) }
+ let(:week_one) { "{#{described_class::REDIS_SLOT}}_i_search_total-2020-52" }
+ let(:week_two) { "{#{described_class::REDIS_SLOT}}_i_search_total-2020-53" }
+ let(:week_three) { "{#{described_class::REDIS_SLOT}}_i_search_total-2021-01" }
+ let(:week_four) { "{#{described_class::REDIS_SLOT}}_i_search_total-2021-02" }
subject(:weekly_redis_keys) { described_class.send(:weekly_redis_keys, events: [redis_event], start_date: DateTime.parse(start_date), end_date: DateTime.parse(end_date)) }
@@ -406,13 +329,13 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
'2020-12-21' | '2020-12-20' | []
'2020-12-21' | '2020-11-21' | []
'2021-01-01' | '2020-12-28' | []
- '2020-12-21' | '2020-12-28' | ['i_{search}_total-2020-52']
- '2020-12-21' | '2021-01-01' | ['i_{search}_total-2020-52']
- '2020-12-27' | '2021-01-01' | ['i_{search}_total-2020-52']
- '2020-12-26' | '2021-01-04' | ['i_{search}_total-2020-52', 'i_{search}_total-2020-53']
- '2020-12-26' | '2021-01-11' | ['i_{search}_total-2020-52', 'i_{search}_total-2020-53', 'i_{search}_total-2021-01']
- '2020-12-26' | '2021-01-17' | ['i_{search}_total-2020-52', 'i_{search}_total-2020-53', 'i_{search}_total-2021-01']
- '2020-12-26' | '2021-01-18' | ['i_{search}_total-2020-52', 'i_{search}_total-2020-53', 'i_{search}_total-2021-01', 'i_{search}_total-2021-02']
+ '2020-12-21' | '2020-12-28' | lazy { [week_one] }
+ '2020-12-21' | '2021-01-01' | lazy { [week_one] }
+ '2020-12-27' | '2021-01-01' | lazy { [week_one] }
+ '2020-12-26' | '2021-01-04' | lazy { [week_one, week_two] }
+ '2020-12-26' | '2021-01-11' | lazy { [week_one, week_two, week_three] }
+ '2020-12-26' | '2021-01-17' | lazy { [week_one, week_two, week_three] }
+ '2020-12-26' | '2021-01-18' | lazy { [week_one, week_two, week_three, week_four] }
end
with_them do
@@ -435,9 +358,9 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:known_events) do
[
- { name: 'event_name_1', redis_slot: 'event', category: 'category1', aggregation: "weekly" },
- { name: 'event_name_2', redis_slot: 'event', category: 'category1', aggregation: "weekly" },
- { name: 'event_name_3', redis_slot: 'event', category: 'category1', aggregation: "weekly" }
+ { name: 'event_name_1', aggregation: "weekly" },
+ { name: 'event_name_2', aggregation: "weekly" },
+ { name: 'event_name_3', aggregation: "weekly" }
].map(&:with_indifferent_access)
end
@@ -476,11 +399,11 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:time_range) { { start_date: 7.days.ago, end_date: DateTime.current } }
let(:known_events) do
[
- { name: 'event1_slot', redis_slot: "slot", category: 'category1', aggregation: "weekly" },
- { name: 'event2_slot', redis_slot: "slot", category: 'category2', aggregation: "weekly" },
- { name: 'event3_slot', redis_slot: "slot", category: 'category3', aggregation: "weekly" },
- { name: 'event5_slot', redis_slot: "slot", category: 'category4', aggregation: "daily" },
- { name: 'event4', category: 'category2', aggregation: "weekly" }
+ { name: 'event1_slot', aggregation: "weekly" },
+ { name: 'event2_slot', aggregation: "weekly" },
+ { name: 'event3_slot', aggregation: "weekly" },
+ { name: 'event5_slot', aggregation: "daily" },
+ { name: 'event4', aggregation: "weekly" }
].map(&:with_indifferent_access)
end
@@ -510,11 +433,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
expect(described_class.calculate_events_union(**time_range.merge(event_names: %w[event1_slot event2_slot event3_slot]))).to eq 3
end
- it 'validates and raise exception if events has mismatched slot or aggregation', :aggregate_failure do
- expect { described_class.calculate_events_union(**time_range.merge(event_names: %w[event1_slot event4])) }.to raise_error described_class::SlotMismatch
- expect { described_class.calculate_events_union(**time_range.merge(event_names: %w[event5_slot event3_slot])) }.to raise_error described_class::AggregationMismatch
- end
-
it 'returns 0 if there are no keys for given events' do
expect(Gitlab::Redis::HLL).not_to receive(:count)
expect(described_class.calculate_events_union(event_names: %w[event1_slot event2_slot event3_slot], start_date: Date.current, end_date: 4.weeks.ago)).to eq(-1)
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 33e0d446fca..383938b0324 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
@@ -306,7 +306,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
described_class.track_issue_assignee_changed_action(author: user3, project: project)
end
- events = Gitlab::UsageDataCounters::HLLRedisCounter.events_for_category(described_class::ISSUE_CATEGORY)
+ events = [described_class::ISSUE_TITLE_CHANGED, described_class::ISSUE_DESCRIPTION_CHANGED, described_class::ISSUE_ASSIGNEE_CHANGED]
today_count = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: events, start_date: time, end_date: time)
week_count = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: events, start_date: time - 5.days, end_date: 1.day.since(time))
diff --git a/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
index 42aa84c2c3e..e41da6d9ea2 100644
--- a/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
@@ -69,7 +69,6 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
let(:project) { target_project }
let(:namespace) { project.namespace.reload }
let(:user) { project.creator }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:label) { 'redis_hll_counters.code_review.i_code_review_user_create_mr_monthly' }
let(:property) { described_class::MR_USER_CREATE_ACTION }
end
@@ -118,7 +117,6 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
let(:project) { target_project }
let(:namespace) { project.namespace.reload }
let(:user) { project.creator }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:label) { 'redis_hll_counters.code_review.i_code_review_user_approve_mr_monthly' }
let(:property) { described_class::MR_APPROVE_ACTION }
end
diff --git a/spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb b/spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb
deleted file mode 100644
index d1144dd0bc5..00000000000
--- a/spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::UsageDataCounters::TrackUniqueEvents, :clean_gitlab_redis_shared_state do
- subject(:track_unique_events) { described_class }
-
- let(:time) { Time.zone.now }
-
- def track_event(params)
- track_unique_events.track_event(**params)
- end
-
- def count_unique(params)
- track_unique_events.count_unique_events(**params)
- end
-
- context 'tracking an event' do
- context 'when tracking successfully' do
- context 'when the application setting is enabled' do
- context 'when the target and the action is valid' do
- before do
- stub_application_setting(usage_ping_enabled: true)
- end
-
- it 'tracks and counts the events as expected' do
- project = Event::TARGET_TYPES[:project]
- design = Event::TARGET_TYPES[:design]
- wiki = Event::TARGET_TYPES[:wiki]
-
- expect(track_event(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy
- expect(track_event(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy
- expect(track_event(event_action: :pushed, event_target: project, author_id: 2)).to be_truthy
- expect(track_event(event_action: :pushed, event_target: project, author_id: 3)).to be_truthy
- expect(track_event(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days)).to be_truthy
-
- expect(track_event(event_action: :destroyed, event_target: design, author_id: 3)).to be_truthy
- expect(track_event(event_action: :created, event_target: design, author_id: 4)).to be_truthy
- expect(track_event(event_action: :updated, event_target: design, author_id: 5)).to be_truthy
-
- expect(track_event(event_action: :destroyed, event_target: wiki, author_id: 5)).to be_truthy
- expect(track_event(event_action: :created, event_target: wiki, author_id: 3)).to be_truthy
- expect(track_event(event_action: :updated, event_target: wiki, author_id: 4)).to be_truthy
-
- expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(3)
- expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: Date.tomorrow)).to eq(4)
- expect(count_unique(event_action: described_class::DESIGN_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3)
- expect(count_unique(event_action: described_class::WIKI_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3)
- expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: time - 2.days)).to eq(1)
- end
- end
- end
- end
-
- context 'when tracking unsuccessfully' do
- using RSpec::Parameterized::TableSyntax
-
- where(:target, :action) do
- Project | :invalid_action
- :invalid_target | :pushed
- Project | :created
- end
-
- with_them do
- it 'returns the expected values' do
- expect(track_event(event_action: action, event_target: target, author_id: 2)).to be_nil
- expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(0)
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 5325ef5b5dd..d529319e6e9 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -529,8 +529,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
expect(count_data[:projects_prometheus_active]).to eq(1)
expect(count_data[:projects_jenkins_active]).to eq(1)
expect(count_data[:projects_jira_active]).to eq(4)
- expect(count_data[:projects_jira_server_active]).to eq(2)
- expect(count_data[:projects_jira_cloud_active]).to eq(2)
expect(count_data[:jira_imports_projects_count]).to eq(2)
expect(count_data[:jira_imports_total_imported_count]).to eq(3)
expect(count_data[:jira_imports_total_imported_issues_count]).to eq(13)
@@ -614,14 +612,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
it 'raises an error' do
expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
end
-
- context 'when metric calls find_in_batches' do
- let(:metric_method) { :find_in_batches }
-
- it 'raises an error for jira_usage' do
- expect { described_class.jira_usage }.to raise_error(ActiveRecord::StatementInvalid)
- end
- end
end
context 'with should_raise_for_dev? false' do
@@ -630,14 +620,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
it 'does not raise an error' do
expect { subject }.not_to raise_error
end
-
- context 'when metric calls find_in_batches' do
- let(:metric_method) { :find_in_batches }
-
- it 'does not raise an error for jira_usage' do
- expect { described_class.jira_usage }.not_to raise_error
- end
- end
end
end
@@ -1044,16 +1026,12 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
let(:time) { Time.current }
before do
- counter = Gitlab::UsageDataCounters::TrackUniqueEvents
- merge_request = Event::TARGET_TYPES[:merge_request]
- design = Event::TARGET_TYPES[:design]
-
- counter.track_event(event_action: :commented, event_target: merge_request, author_id: 1, time: time)
- counter.track_event(event_action: :opened, event_target: merge_request, author_id: 1, time: time)
- counter.track_event(event_action: :merged, event_target: merge_request, author_id: 2, time: time)
- counter.track_event(event_action: :closed, event_target: merge_request, author_id: 3, time: time)
- counter.track_event(event_action: :opened, event_target: merge_request, author_id: 4, time: time - 3.days)
- counter.track_event(event_action: :created, event_target: design, author_id: 5, time: time)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: 1, time: time)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: 1, time: time)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: 2, time: time)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: 3, time: time)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:merge_request_action, values: 4, time: time - 3.days)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:design_action, values: 5, time: time)
end
it 'returns the distinct count of users using merge requests (via events table) within the specified time period' do
@@ -1069,42 +1047,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
end
end
- describe '#action_monthly_active_users', :clean_gitlab_redis_shared_state do
- let(:time_period) { { created_at: 2.days.ago..time } }
- let(:time) { Time.zone.now }
- let(:user1) { build(:user, id: 1) }
- let(:user2) { build(:user, id: 2) }
- let(:user3) { build(:user, id: 3) }
- let(:user4) { build(:user, id: 4) }
- let(:project) { build(:project) }
-
- before do
- counter = Gitlab::UsageDataCounters::EditorUniqueCounter
-
- counter.track_web_ide_edit_action(author: user1, project: project)
- counter.track_web_ide_edit_action(author: user1, project: project)
- counter.track_sfe_edit_action(author: user1, project: project)
- counter.track_snippet_editor_edit_action(author: user1, project: project)
- counter.track_snippet_editor_edit_action(author: user1, time: time - 3.days, project: project)
-
- counter.track_web_ide_edit_action(author: user2, project: project)
- counter.track_sfe_edit_action(author: user2, project: project)
-
- counter.track_web_ide_edit_action(author: user3, time: time - 3.days, project: project)
- counter.track_snippet_editor_edit_action(author: user3, project: project)
- end
-
- it 'returns the distinct count of user actions within the specified time period' do
- expect(described_class.action_monthly_active_users(time_period)).to eq(
- {
- action_monthly_active_users_web_ide_edit: 2,
- action_monthly_active_users_sfe_edit: 2,
- action_monthly_active_users_snippet_editor_edit: 2
- }
- )
- end
- end
-
describe '.service_desk_counts' do
subject { described_class.send(:service_desk_counts) }
diff --git a/spec/lib/gitlab/utils/error_message_spec.rb b/spec/lib/gitlab/utils/error_message_spec.rb
new file mode 100644
index 00000000000..2c2d16656e8
--- /dev/null
+++ b/spec/lib/gitlab/utils/error_message_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Utils::ErrorMessage, feature_category: :error_tracking do
+ let(:klass) do
+ Class.new do
+ include Gitlab::Utils::ErrorMessage
+ end
+ end
+
+ subject(:object) { klass.new }
+
+ describe 'error message' do
+ subject { object.to_user_facing(string) }
+
+ let(:string) { 'Error Message' }
+
+ it "returns input prefixed with UF:" do
+ is_expected.to eq 'UF: Error Message'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/utils/strong_memoize_spec.rb b/spec/lib/gitlab/utils/strong_memoize_spec.rb
index 71f2502b91c..27bfe181ef6 100644
--- a/spec/lib/gitlab/utils/strong_memoize_spec.rb
+++ b/spec/lib/gitlab/utils/strong_memoize_spec.rb
@@ -8,7 +8,7 @@ RSpec.configure do |config|
config.include RSpec::Benchmark::Matchers
end
-RSpec.describe Gitlab::Utils::StrongMemoize, feature_category: :not_owned do
+RSpec.describe Gitlab::Utils::StrongMemoize, feature_category: :shared do
let(:klass) do
strong_memoize_class = described_class
diff --git a/spec/lib/gitlab/utils/uniquify_spec.rb b/spec/lib/gitlab/utils/uniquify_spec.rb
new file mode 100644
index 00000000000..df02fbe8c82
--- /dev/null
+++ b/spec/lib/gitlab/utils/uniquify_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Utils::Uniquify, feature_category: :shared do
+ subject(:uniquify) { described_class.new }
+
+ describe "#string" do
+ it 'returns the given string if it does not exist' do
+ result = uniquify.string('test_string') { |_s| false }
+
+ expect(result).to eq('test_string')
+ end
+
+ it 'returns the given string with a counter attached if the string exists' do
+ result = uniquify.string('test_string') { |s| s == 'test_string' }
+
+ expect(result).to eq('test_string1')
+ end
+
+ it 'increments the counter for each candidate string that also exists' do
+ result = uniquify.string('test_string') { |s| s == 'test_string' || s == 'test_string1' }
+
+ expect(result).to eq('test_string2')
+ end
+
+ it 'allows to pass an initial value for the counter' do
+ start_counting_from = 2
+ uniquify = described_class.new(start_counting_from)
+
+ result = uniquify.string('test_string') { |s| s == 'test_string' }
+
+ expect(result).to eq('test_string2')
+ end
+
+ it 'allows passing in a base function that defines the location of the counter' do
+ result = uniquify.string(->(counter) { "test_#{counter}_string" }) do |s|
+ s == 'test__string'
+ end
+
+ expect(result).to eq('test_1_string')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/utils/usage_data_spec.rb b/spec/lib/gitlab/utils/usage_data_spec.rb
index 2925ceef256..586ee04a835 100644
--- a/spec/lib/gitlab/utils/usage_data_spec.rb
+++ b/spec/lib/gitlab/utils/usage_data_spec.rb
@@ -487,12 +487,12 @@ RSpec.describe Gitlab::Utils::UsageData do
end
context 'when Redis HLL raises any error' do
- subject { described_class.redis_usage_data { raise Gitlab::UsageDataCounters::HLLRedisCounter::CategoryMismatch } }
+ subject { described_class.redis_usage_data { raise Gitlab::UsageDataCounters::HLLRedisCounter::EventError } }
let(:fallback) { 15 }
let(:failing_class) { nil }
- it_behaves_like 'failing hardening method', Gitlab::UsageDataCounters::HLLRedisCounter::CategoryMismatch
+ it_behaves_like 'failing hardening method', Gitlab::UsageDataCounters::HLLRedisCounter::EventError
end
it 'returns the evaluated block when given' do
diff --git a/spec/lib/gitlab/utils/username_and_email_generator_spec.rb b/spec/lib/gitlab/utils/username_and_email_generator_spec.rb
new file mode 100644
index 00000000000..45df8f08055
--- /dev/null
+++ b/spec/lib/gitlab/utils/username_and_email_generator_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Utils::UsernameAndEmailGenerator, feature_category: :system_access do
+ let(:username_prefix) { 'username_prefix' }
+ let(:email_domain) { 'example.com' }
+
+ subject { described_class.new(username_prefix: username_prefix, email_domain: email_domain) }
+
+ describe 'email domain' do
+ it 'defaults to `Gitlab.config.gitlab.host`' do
+ expect(described_class.new(username_prefix: username_prefix).email).to end_with("@#{Gitlab.config.gitlab.host}")
+ end
+
+ context 'when specified' do
+ it 'uses the specified email domain' do
+ expect(subject.email).to end_with("@#{email_domain}")
+ end
+ end
+ end
+
+ include_examples 'username and email pair is generated by Gitlab::Utils::UsernameAndEmailGenerator'
+end
diff --git a/spec/lib/object_storage/config_spec.rb b/spec/lib/object_storage/config_spec.rb
index 2a81142ea44..412fcb9b6b8 100644
--- a/spec/lib/object_storage/config_spec.rb
+++ b/spec/lib/object_storage/config_spec.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
require 'rspec-parameterized'
require 'fog/core'
-RSpec.describe ObjectStorage::Config do
+RSpec.describe ObjectStorage::Config, feature_category: :shared do
using RSpec::Parameterized::TableSyntax
let(:region) { 'us-east-1' }
@@ -130,6 +130,11 @@ RSpec.describe ObjectStorage::Config do
it { expect(subject.provider).to eq('AWS') }
it { expect(subject.aws?).to be true }
it { expect(subject.google?).to be false }
+ it { expect(subject.credentials).to eq(credentials) }
+
+ context 'with FIPS enabled', :fips_mode do
+ it { expect(subject.credentials).to eq(credentials.merge(disable_content_md5_validation: true)) }
+ end
end
context 'with Google credentials' do
diff --git a/spec/lib/security/weak_passwords_spec.rb b/spec/lib/security/weak_passwords_spec.rb
index afa9448e746..14bab5ee6ec 100644
--- a/spec/lib/security/weak_passwords_spec.rb
+++ b/spec/lib/security/weak_passwords_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Security::WeakPasswords, feature_category: :authentication_and_authorization do
+RSpec.describe Security::WeakPasswords, feature_category: :system_access do
describe "#weak_for_user?" do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb b/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb
new file mode 100644
index 00000000000..f33cb4ab7f6
--- /dev/null
+++ b/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb
@@ -0,0 +1,139 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Sidebars::Concerns::SuperSidebarPanel, feature_category: :navigation do
+ let(:menu_class_foo) { Class.new(Sidebars::Menu) }
+ let(:menu_foo) { menu_class_foo.new({}) }
+
+ let(:menu_class_bar) do
+ Class.new(Sidebars::Menu) do
+ def title
+ "Bar"
+ end
+
+ def pick_into_super_sidebar?
+ true
+ end
+ end
+ end
+
+ let(:menu_bar) { menu_class_bar.new({}) }
+
+ subject do
+ Class.new(Sidebars::Panel) do
+ include Sidebars::Concerns::SuperSidebarPanel
+ end.new({})
+ end
+
+ before do
+ allow(menu_foo).to receive(:render?).and_return(true)
+ allow(menu_bar).to receive(:render?).and_return(true)
+ end
+
+ describe '#pick_from_old_menus' do
+ it 'removes items with #pick_into_super_sidebar? from a list and adds them to the panel menus' do
+ old_menus = [menu_foo, menu_bar]
+
+ subject.pick_from_old_menus(old_menus)
+
+ expect(old_menus).to include(menu_foo)
+ expect(subject.renderable_menus).not_to include(menu_foo)
+
+ expect(old_menus).not_to include(menu_bar)
+ expect(subject.renderable_menus).to include(menu_bar)
+ end
+ end
+
+ describe '#transform_old_menus' do
+ let(:uncategorized_menu) { ::Sidebars::UncategorizedMenu.new({}) }
+
+ let(:menu_item) do
+ Sidebars::MenuItem.new(title: 'foo3', link: 'foo3', active_routes: { controller: 'barc' },
+ super_sidebar_parent: menu_class_foo)
+ end
+
+ let(:nil_menu_item) { Sidebars::NilMenuItem.new(item_id: :nil_item) }
+ let(:existing_item) do
+ Sidebars::MenuItem.new(
+ item_id: :exists,
+ title: 'Existing item',
+ link: 'foo2',
+ active_routes: { controller: 'foo2' }
+ )
+ end
+
+ let(:current_menus) { [menu_foo, uncategorized_menu] }
+
+ before do
+ allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return(nil)
+ menu_foo.add_item(existing_item)
+ end
+
+ context 'for Menus with Menu Items' do
+ before do
+ menu_bar.add_item(menu_item)
+ menu_bar.add_item(nil_menu_item)
+ end
+
+ it 'adds Menu Items to defined super_sidebar_parent' do
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item, menu_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+
+ it 'adds Menu Items to defined super_sidebar_parent, before super_sidebar_before' do
+ allow(menu_item).to receive(:super_sidebar_before).and_return(:exists)
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([menu_item, existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+
+ it 'considers Menu Items uncategorized if super_sidebar_parent is nil' do
+ allow(menu_item).to receive(:super_sidebar_parent).and_return(nil)
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([menu_item])
+ end
+
+ it 'considers Menu Items uncategorized if super_sidebar_parent cannot be found' do
+ allow(menu_item).to receive(:super_sidebar_parent).and_return(menu_class_bar)
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([menu_item])
+ end
+
+ it 'considers Menu Items deleted if super_sidebar_parent is Sidebars::NilMenuItem' do
+ allow(menu_item).to receive(:super_sidebar_parent).and_return(::Sidebars::NilMenuItem)
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+ end
+
+ it 'converts "solo" top-level Menu entry to Menu Item' do
+ allow(Sidebars::MenuItem).to receive(:new).and_return(menu_item)
+ allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return({})
+
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item, menu_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+
+ it 'drops "solo" top-level Menu entries, if they serialize to nil' do
+ allow(Sidebars::MenuItem).to receive(:new).and_return(menu_item)
+ allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return(nil)
+
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+ end
+end
diff --git a/spec/lib/sidebars/groups/menus/group_information_menu_spec.rb b/spec/lib/sidebars/groups/menus/group_information_menu_spec.rb
index 1b27db53b6f..4a0301e2f2d 100644
--- a/spec/lib/sidebars/groups/menus/group_information_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/group_information_menu_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Groups::Menus::GroupInformationMenu do
+RSpec.describe Sidebars::Groups::Menus::GroupInformationMenu, feature_category: :navigation do
let_it_be(:owner) { create(:user) }
let_it_be(:root_group) do
build(:group, :private).tap do |g|
@@ -14,6 +14,10 @@ RSpec.describe Sidebars::Groups::Menus::GroupInformationMenu do
let(:user) { owner }
let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) }
+ it_behaves_like 'not serializable as super_sidebar_menu_args' do
+ let(:menu) { described_class.new(context) }
+ end
+
describe '#title' do
subject { described_class.new(context).title }
diff --git a/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb b/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb
deleted file mode 100644
index a79e5182f45..00000000000
--- a/spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Sidebars::Groups::Menus::InviteTeamMembersMenu do
- let_it_be(:owner) { create(:user) }
- let_it_be(:guest) { create(:user) }
- let_it_be(:group) do
- build(:group).tap do |g|
- g.add_owner(owner)
- end
- end
-
- let(:context) { Sidebars::Groups::Context.new(current_user: owner, container: group) }
-
- subject(:invite_menu) { described_class.new(context) }
-
- context 'when the group is viewed by an owner of the group' do
- describe '#render?' do
- it 'renders the Invite team members link' do
- expect(invite_menu.render?).to eq(true)
- end
-
- context 'when the group already has at least 2 members' do
- before do
- group.add_guest(guest)
- end
-
- it 'does not render the link' do
- expect(invite_menu.render?).to eq(false)
- end
- end
- end
-
- describe '#title' do
- it 'displays the correct Invite team members text for the link in the side nav' do
- expect(invite_menu.title).to eq('Invite members')
- end
- end
- end
-
- context 'when the group is viewed by a guest user without admin permissions' do
- let(:context) { Sidebars::Groups::Context.new(current_user: guest, container: group) }
-
- before do
- group.add_guest(guest)
- end
-
- describe '#render?' do
- it 'does not render the link' do
- expect(subject.render?).to eq(false)
- end
- end
- end
-end
diff --git a/spec/lib/sidebars/groups/menus/issues_menu_spec.rb b/spec/lib/sidebars/groups/menus/issues_menu_spec.rb
index 3d55eb3af40..ceeda4a7ac3 100644
--- a/spec/lib/sidebars/groups/menus/issues_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/issues_menu_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Groups::Menus::IssuesMenu do
+RSpec.describe Sidebars::Groups::Menus::IssuesMenu, feature_category: :navigation do
let_it_be(:owner) { create(:user) }
let_it_be(:group) do
build(:group, :private).tap do |g|
@@ -51,4 +51,17 @@ RSpec.describe Sidebars::Groups::Menus::IssuesMenu do
it_behaves_like 'pill_count formatted results' do
let(:count_service) { ::Groups::OpenIssuesCountService }
end
+
+ it_behaves_like 'serializable as super_sidebar_menu_args' do
+ let(:extra_attrs) do
+ {
+ item_id: :group_issue_list,
+ active_routes: { path: 'groups#issues' },
+ sprite_icon: 'issues',
+ pill_count: menu.pill_count,
+ has_pill: menu.has_pill?,
+ super_sidebar_parent: ::Sidebars::StaticMenu
+ }
+ end
+ end
end
diff --git a/spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb b/spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb
index 5bf8be9d6e5..8eb9a22e3e1 100644
--- a/spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Groups::Menus::KubernetesMenu, :request_store do
+RSpec.describe Sidebars::Groups::Menus::KubernetesMenu, :request_store, feature_category: :navigation do
let_it_be(:owner) { create(:user) }
let_it_be(:group) do
build(:group, :private).tap do |g|
@@ -14,6 +14,15 @@ RSpec.describe Sidebars::Groups::Menus::KubernetesMenu, :request_store do
let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) }
let(:menu) { described_class.new(context) }
+ it_behaves_like 'serializable as super_sidebar_menu_args' do
+ let(:extra_attrs) do
+ {
+ super_sidebar_parent: Sidebars::Groups::SuperSidebarMenus::OperationsMenu,
+ item_id: :group_kubernetes_clusters
+ }
+ end
+ end
+
describe '#render?' do
context 'when user can read clusters' do
it 'returns true' do
diff --git a/spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb b/spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb
index 3aceff29d6d..72f85f7930a 100644
--- a/spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Groups::Menus::MergeRequestsMenu do
+RSpec.describe Sidebars::Groups::Menus::MergeRequestsMenu, feature_category: :navigation do
let_it_be(:owner) { create(:user) }
let_it_be(:group) do
build(:group, :private).tap do |g|
@@ -33,4 +33,16 @@ RSpec.describe Sidebars::Groups::Menus::MergeRequestsMenu do
it_behaves_like 'pill_count formatted results' do
let(:count_service) { ::Groups::MergeRequestsCountService }
end
+
+ it_behaves_like 'serializable as super_sidebar_menu_args' do
+ let(:extra_attrs) do
+ {
+ item_id: :group_merge_request_list,
+ sprite_icon: 'git-merge',
+ pill_count: menu.pill_count,
+ has_pill: menu.has_pill?,
+ super_sidebar_parent: ::Sidebars::StaticMenu
+ }
+ end
+ end
end
diff --git a/spec/lib/sidebars/groups/menus/observability_menu_spec.rb b/spec/lib/sidebars/groups/menus/observability_menu_spec.rb
index 5b993cd6f28..20af8ea00be 100644
--- a/spec/lib/sidebars/groups/menus/observability_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/observability_menu_spec.rb
@@ -20,26 +20,74 @@ RSpec.describe Sidebars::Groups::Menus::ObservabilityMenu do
allow(menu).to receive(:can?).and_call_original
end
- context 'when observability is enabled' do
+ context 'when observability#explore is allowed' do
before do
- allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(true)
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, :explore).and_return(true)
end
it 'returns true' do
expect(menu.render?).to eq true
- expect(Gitlab::Observability).to have_received(:observability_enabled?).with(user, group)
+ expect(Gitlab::Observability).to have_received(:allowed_for_action?).with(user, group, :explore)
end
end
- context 'when observability is disabled' do
+ context 'when observability#explore is not allowed' do
before do
- allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(false)
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, :explore).and_return(false)
end
it 'returns false' do
expect(menu.render?).to eq false
- expect(Gitlab::Observability).to have_received(:observability_enabled?).with(user, group)
+ expect(Gitlab::Observability).to have_received(:allowed_for_action?).with(user, group, :explore)
end
end
end
+
+ describe "Menu items" do
+ before do
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).and_return(false)
+ end
+
+ subject { find_menu(menu, item_id) }
+
+ shared_examples 'observability menu entry' do
+ context 'when action is allowed' do
+ before do
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, item_id).and_return(true)
+ end
+
+ it 'the menu item is added to list of menu items' do
+ is_expected.not_to be_nil
+ end
+ end
+
+ context 'when action is not allowed' do
+ before do
+ allow(Gitlab::Observability).to receive(:allowed_for_action?).with(user, group, item_id).and_return(false)
+ end
+
+ it 'the menu item is added to list of menu items' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ describe 'Explore' do
+ it_behaves_like 'observability menu entry' do
+ let(:item_id) { :explore }
+ end
+ end
+
+ describe 'Datasources' do
+ it_behaves_like 'observability menu entry' do
+ let(:item_id) { :datasources }
+ end
+ end
+ end
+
+ private
+
+ def find_menu(menu, item)
+ menu.renderable_items.find { |i| i.item_id == item }
+ 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 ce368ad5bd6..382ee07e458 100644
--- a/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu do
+RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu, feature_category: :navigation do
let_it_be(:owner) { create(:user) }
let_it_be_with_reload(:group) do
build(:group, :private).tap do |g|
@@ -16,6 +16,8 @@ RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu do
let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) }
let(:menu) { described_class.new(context) }
+ it_behaves_like 'not serializable as super_sidebar_menu_args'
+
describe '#render?' do
context 'when menu has menu items to show' do
it 'returns true' do
diff --git a/spec/lib/sidebars/groups/menus/scope_menu_spec.rb b/spec/lib/sidebars/groups/menus/scope_menu_spec.rb
index 4b77a09117a..d3aceaf422b 100644
--- a/spec/lib/sidebars/groups/menus/scope_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/scope_menu_spec.rb
@@ -2,14 +2,26 @@
require 'spec_helper'
-RSpec.describe Sidebars::Groups::Menus::ScopeMenu do
+RSpec.describe Sidebars::Groups::Menus::ScopeMenu, feature_category: :navigation do
let(:group) { build(:group) }
let(:user) { group.owner }
let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) }
+ let(:menu) { described_class.new(context) }
describe '#extra_nav_link_html_options' do
- subject { described_class.new(context).extra_nav_link_html_options }
+ subject { menu.extra_nav_link_html_options }
specify { is_expected.to match(hash_including(class: 'context-header has-tooltip', title: context.group.name)) }
end
+
+ 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'),
+ item_id: :group_overview
+ }
+ end
+ end
end
diff --git a/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb b/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb
new file mode 100644
index 00000000000..beaf3875f1c
--- /dev/null
+++ b/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Groups::SuperSidebarPanel, feature_category: :navigation do
+ let_it_be(:group) { create(:group) }
+
+ let(:user) { group.first_owner }
+
+ let(:context) do
+ double("Stubbed context", current_user: user, container: group, group: group).as_null_object # rubocop:disable RSpec/VerifiedDoubles
+ end
+
+ 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
+ })
+ end
+
+ describe '#renderable_menus' do
+ let(:category_menu) do
+ [
+ Sidebars::StaticMenu,
+ Sidebars::Groups::SuperSidebarMenus::PlanMenu,
+ Sidebars::Groups::Menus::CiCdMenu,
+ (Sidebars::Groups::Menus::SecurityComplianceMenu if Gitlab.ee?),
+ Sidebars::Groups::SuperSidebarMenus::OperationsMenu,
+ Sidebars::Groups::Menus::ObservabilityMenu,
+ (Sidebars::Groups::Menus::AnalyticsMenu if Gitlab.ee?),
+ Sidebars::UncategorizedMenu,
+ Sidebars::Groups::Menus::SettingsMenu
+ ].compact
+ end
+
+ it "is exposed as a renderable menu" do
+ expect(subject.instance_variable_get(:@menus).map(&:class)).to eq(category_menu)
+ end
+ end
+end
diff --git a/spec/lib/sidebars/menu_spec.rb b/spec/lib/sidebars/menu_spec.rb
index 53a889c2db8..641f1c6e7e6 100644
--- a/spec/lib/sidebars/menu_spec.rb
+++ b/spec/lib/sidebars/menu_spec.rb
@@ -2,9 +2,10 @@
require 'spec_helper'
-RSpec.describe Sidebars::Menu do
+RSpec.describe Sidebars::Menu, feature_category: :navigation do
let(:menu) { described_class.new(context) }
let(:context) { Sidebars::Context.new(current_user: nil, container: nil) }
+
let(:nil_menu_item) { Sidebars::NilMenuItem.new(item_id: :foo) }
describe '#all_active_routes' do
@@ -21,6 +22,82 @@ RSpec.describe Sidebars::Menu do
end
end
+ describe '#serialize_for_super_sidebar' do
+ before do
+ allow(menu).to receive(:title).and_return('Title')
+ allow(menu).to receive(:active_routes).and_return({ path: 'foo' })
+ end
+
+ it 'returns a tree-like structure of itself and all menu items' do
+ menu.add_item(Sidebars::MenuItem.new(title: 'Is active', link: 'foo2', active_routes: { controller: 'fooc' }))
+ menu.add_item(Sidebars::MenuItem.new(
+ title: 'Not active',
+ link: 'foo3',
+ active_routes: { controller: 'barc' },
+ has_pill: true,
+ pill_count: 10
+ ))
+ menu.add_item(nil_menu_item)
+
+ allow(context).to receive(:route_is_active).and_return(->(x) { x[:controller] == 'fooc' })
+
+ expect(menu.serialize_for_super_sidebar).to eq(
+ {
+ title: "Title",
+ icon: nil,
+ link: "foo2",
+ is_active: true,
+ pill_count: nil,
+ items: [
+ {
+ title: "Is active",
+ icon: nil,
+ link: "foo2",
+ is_active: true,
+ pill_count: nil
+ },
+ {
+ title: "Not active",
+ icon: nil,
+ link: "foo3",
+ is_active: false,
+ pill_count: 10
+ }
+ ]
+ })
+ end
+
+ it 'returns pill data if defined' do
+ allow(menu).to receive(:has_pill?).and_return(true)
+ allow(menu).to receive(:pill_count).and_return('foo')
+ expect(menu.serialize_for_super_sidebar).to eq(
+ {
+ title: "Title",
+ icon: nil,
+ link: nil,
+ is_active: false,
+ pill_count: 'foo',
+ items: []
+ })
+ end
+ end
+
+ describe '#serialize_as_menu_item_args' do
+ it 'returns hash of title, link, active_routes, container_html_options' do
+ allow(menu).to receive(:title).and_return('Title')
+ allow(menu).to receive(:active_routes).and_return({ path: 'foo' })
+ allow(menu).to receive(:container_html_options).and_return({ class: 'foo' })
+ allow(menu).to receive(:link).and_return('/link')
+
+ expect(menu.serialize_as_menu_item_args).to eq({
+ title: 'Title',
+ link: '/link',
+ active_routes: { path: 'foo' },
+ container_html_options: { class: 'foo' }
+ })
+ end
+ end
+
describe '#render?' do
context 'when the menus has no items' do
it 'returns false' do
diff --git a/spec/lib/sidebars/panel_spec.rb b/spec/lib/sidebars/panel_spec.rb
index b70a79361d0..2c1b9c73595 100644
--- a/spec/lib/sidebars/panel_spec.rb
+++ b/spec/lib/sidebars/panel_spec.rb
@@ -2,11 +2,12 @@
require 'spec_helper'
-RSpec.describe Sidebars::Panel do
+RSpec.describe Sidebars::Panel, feature_category: :navigation do
let(:context) { Sidebars::Context.new(current_user: nil, container: nil) }
let(:panel) { Sidebars::Panel.new(context) }
let(:menu1) { Sidebars::Menu.new(context) }
let(:menu2) { Sidebars::Menu.new(context) }
+ let(:menu3) { Sidebars::Menu.new(context) }
describe '#renderable_menus' do
it 'returns only renderable menus' do
@@ -20,6 +21,31 @@ RSpec.describe Sidebars::Panel do
end
end
+ describe '#super_sidebar_menu_items' do
+ it "serializes every renderable menu and returns a flattened result" do
+ panel.add_menu(menu1)
+ panel.add_menu(menu2)
+ panel.add_menu(menu3)
+
+ allow(menu1).to receive(:render?).and_return(true)
+ allow(menu1).to receive(:serialize_for_super_sidebar).and_return("foo")
+
+ allow(menu2).to receive(:render?).and_return(false)
+ allow(menu2).to receive(:serialize_for_super_sidebar).and_return("i-should-not-appear-in-results")
+
+ allow(menu3).to receive(:render?).and_return(true)
+ allow(menu3).to receive(:serialize_for_super_sidebar).and_return(%w[bar baz])
+
+ expect(panel.super_sidebar_menu_items).to eq(%w[foo bar baz])
+ end
+ end
+
+ describe '#super_sidebar_context_header' do
+ it 'raises `NotImplementedError`' do
+ expect { panel.super_sidebar_context_header }.to raise_error(NotImplementedError)
+ end
+ end
+
describe '#has_renderable_menus?' do
it 'returns false when no renderable menus' do
expect(panel.has_renderable_menus?).to be false
diff --git a/spec/lib/sidebars/projects/menus/deployments_menu_spec.rb b/spec/lib/sidebars/projects/menus/deployments_menu_spec.rb
index ce971915174..5065c261cf8 100644
--- a/spec/lib/sidebars/projects/menus/deployments_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/deployments_menu_spec.rb
@@ -2,12 +2,16 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::DeploymentsMenu do
+RSpec.describe Sidebars::Projects::Menus::DeploymentsMenu, feature_category: :navigation do
let_it_be(:project, reload: true) { create(:project, :repository) }
let(:user) { project.first_owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
+ it_behaves_like 'not serializable as super_sidebar_menu_args' do
+ let(:menu) { described_class.new(context) }
+ end
+
describe '#render?' do
subject { described_class.new(context) }
diff --git a/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb b/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb
index 116948b7cb0..7f0e02892e4 100644
--- a/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb
@@ -2,11 +2,15 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do
+RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu, feature_category: :navigation do
let(:project) { build(:project) }
let(:user) { project.first_owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, show_cluster_hint: false) }
+ it_behaves_like 'not serializable as super_sidebar_menu_args' do
+ let(:menu) { described_class.new(context) }
+ end
+
describe '#render?' do
subject { described_class.new(context) }
@@ -103,6 +107,22 @@ RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do
let(:item_id) { :terraform }
it_behaves_like 'access rights checks'
+
+ context 'if terraform_state.enabled=true' do
+ before do
+ stub_config(terraform_state: { enabled: true })
+ end
+
+ it_behaves_like 'access rights checks'
+ end
+
+ context 'if terraform_state.enabled=false' do
+ before do
+ stub_config(terraform_state: { enabled: false })
+ end
+
+ it { is_expected.to be_nil }
+ end
end
describe 'Google Cloud' do
@@ -141,6 +161,56 @@ RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do
it_behaves_like 'access rights checks'
end
end
+
+ context 'when instance is not configured for Google OAuth2' do
+ before do
+ stub_feature_flags(incubation_5mp_google_cloud: true)
+ unconfigured_google_oauth2 = Struct.new(:app_id, :app_secret).new('', '')
+ allow(Gitlab::Auth::OAuth::Provider).to receive(:config_for)
+ .with('google_oauth2')
+ .and_return(unconfigured_google_oauth2)
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe 'AWS' do
+ let(:item_id) { :aws }
+
+ it_behaves_like 'access rights checks'
+
+ context 'when feature flag is turned off globally' do
+ before do
+ stub_feature_flags(cloudseed_aws: false)
+ end
+
+ it { is_expected.to be_nil }
+
+ context 'when feature flag is enabled for specific project' do
+ before do
+ stub_feature_flags(cloudseed_aws: project)
+ end
+
+ it_behaves_like 'access rights checks'
+ end
+
+ context 'when feature flag is enabled for specific group' do
+ before do
+ stub_feature_flags(cloudseed_aws: project.group)
+ end
+
+ it_behaves_like 'access rights checks'
+ end
+
+ context 'when feature flag is enabled for specific project' do
+ before do
+ stub_feature_flags(cloudseed_aws: user)
+ end
+
+ it_behaves_like 'access rights checks'
+ end
+ end
end
end
end
diff --git a/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb b/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb
deleted file mode 100644
index 9838aa8c3e3..00000000000
--- a/spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Sidebars::Projects::Menus::InviteTeamMembersMenu do
- let_it_be(:project) { create(:project) }
- let_it_be(:guest) { create(:user) }
-
- let(:context) { Sidebars::Projects::Context.new(current_user: owner, container: project) }
-
- subject(:invite_menu) { described_class.new(context) }
-
- context 'when the project is viewed by an owner of the group' do
- let(:owner) { project.first_owner }
-
- describe '#render?' do
- it 'renders the Invite team members link' do
- expect(invite_menu.render?).to eq(true)
- end
-
- context 'when the project already has at least 2 members' do
- before do
- project.add_guest(guest)
- end
-
- it 'does not render the link' do
- expect(invite_menu.render?).to eq(false)
- end
- end
- end
-
- describe '#title' do
- it 'displays the correct Invite team members text for the link in the side nav' do
- expect(invite_menu.title).to eq('Invite members')
- end
- end
- end
-
- context 'when the project is viewed by a guest user without admin permissions' do
- let(:context) { Sidebars::Projects::Context.new(current_user: guest, container: project) }
-
- before do
- project.add_guest(guest)
- end
-
- describe '#render?' do
- it 'does not render' do
- expect(invite_menu.render?).to eq(false)
- end
- end
- 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 4c0016a77a1..c7ff846bc95 100644
--- a/spec/lib/sidebars/projects/menus/issues_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/issues_menu_spec.rb
@@ -2,13 +2,26 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::IssuesMenu do
+RSpec.describe Sidebars::Projects::Menus::IssuesMenu, feature_category: :navigation do
let(:project) { build(:project) }
let(:user) { project.first_owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
subject { described_class.new(context) }
+ it_behaves_like 'serializable as super_sidebar_menu_args' do
+ let(:menu) { subject }
+ let(:extra_attrs) do
+ {
+ item_id: :project_issue_list,
+ sprite_icon: 'issues',
+ pill_count: menu.pill_count,
+ has_pill: menu.has_pill?,
+ super_sidebar_parent: ::Sidebars::StaticMenu
+ }
+ end
+ end
+
describe '#render?' do
context 'when user can read issues' do
it 'returns true' do
diff --git a/spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb b/spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb
index 45c49500e46..a19df559b58 100644
--- a/spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::MergeRequestsMenu do
+RSpec.describe Sidebars::Projects::Menus::MergeRequestsMenu, feature_category: :navigation do
let_it_be(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
@@ -10,6 +10,19 @@ RSpec.describe Sidebars::Projects::Menus::MergeRequestsMenu do
subject { described_class.new(context) }
+ it_behaves_like 'serializable as super_sidebar_menu_args' do
+ let(:menu) { subject }
+ let(:extra_attrs) do
+ {
+ item_id: :project_merge_request_list,
+ sprite_icon: 'git-merge',
+ pill_count: menu.pill_count,
+ has_pill: menu.has_pill?,
+ super_sidebar_parent: ::Sidebars::StaticMenu
+ }
+ end
+ end
+
describe '#render?' do
context 'when repository is not present' do
let(:project) { build(:project) }
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 b03269c424a..554bc763345 100644
--- a/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu do
+RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu, feature_category: :navigation do
let_it_be(:project) { create(:project) }
let_it_be(:harbor_integration) { create(:harbor_integration, project: project) }
@@ -12,6 +12,10 @@ RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu do
subject { described_class.new(context) }
+ it_behaves_like 'not serializable as super_sidebar_menu_args' do
+ let(:menu) { subject }
+ end
+
describe '#render?' do
context 'when menu does not have any menu item to show' do
it 'returns false' do
diff --git a/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb b/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb
index 7ff06ac229e..7547f152b27 100644
--- a/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb
@@ -2,12 +2,16 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::ProjectInformationMenu do
+RSpec.describe Sidebars::Projects::Menus::ProjectInformationMenu, feature_category: :navigation do
let_it_be_with_reload(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
+ it_behaves_like 'not serializable as super_sidebar_menu_args' do
+ let(:menu) { described_class.new(context) }
+ end
+
describe '#container_html_options' do
subject { described_class.new(context).container_html_options }
diff --git a/spec/lib/sidebars/projects/menus/repository_menu_spec.rb b/spec/lib/sidebars/projects/menus/repository_menu_spec.rb
index 40ca2107698..b0631aacdb9 100644
--- a/spec/lib/sidebars/projects/menus/repository_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/repository_menu_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe Sidebars::Projects::Menus::RepositoryMenu, feature_category: :sou
end
end
- describe 'Contributors' do
+ describe 'Contributor statistics' do
let_it_be(:item_id) { :contributors }
context 'when analytics is disabled' do
diff --git a/spec/lib/sidebars/projects/menus/scope_menu_spec.rb b/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
index 4e87f3b8ead..45464278880 100644
--- a/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
@@ -2,11 +2,23 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::ScopeMenu do
+RSpec.describe Sidebars::Projects::Menus::ScopeMenu, feature_category: :navigation do
let(:project) { build(:project) }
let(:user) { project.first_owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
+ it_behaves_like 'serializable as super_sidebar_menu_args' do
+ let(:menu) { described_class.new(context) }
+ let(:extra_attrs) do
+ {
+ title: _('Project overview'),
+ sprite_icon: 'project',
+ super_sidebar_parent: ::Sidebars::StaticMenu,
+ item_id: :project_overview
+ }
+ end
+ end
+
describe '#container_html_options' do
subject { described_class.new(context).container_html_options }
diff --git a/spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb b/spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb
index 41158bd58dc..697359b7941 100644
--- a/spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Sidebars::Projects::Menus::SecurityComplianceMenu do
end
context 'when user is authenticated' do
- context 'when the Security & Compliance is disabled' do
+ context 'when the Security and Compliance is disabled' do
before do
allow(Ability).to receive(:allowed?).with(user, :access_security_and_compliance, project).and_return(false)
end
@@ -28,7 +28,7 @@ RSpec.describe Sidebars::Projects::Menus::SecurityComplianceMenu do
it { is_expected.to be_falsey }
end
- context 'when the Security & Compliance is not disabled' do
+ context 'when the Security and Compliance is not disabled' do
it { is_expected.to be_truthy }
end
end
diff --git a/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb b/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb
index 04b8c128e3d..c5fd407dae9 100644
--- a/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb
@@ -2,13 +2,24 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::SnippetsMenu do
+RSpec.describe Sidebars::Projects::Menus::SnippetsMenu, feature_category: :navigation do
let(:project) { build(:project) }
let(:user) { project.first_owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
subject { described_class.new(context) }
+ it_behaves_like 'serializable as super_sidebar_menu_args' do
+ let(:menu) { subject }
+ let(:extra_attrs) do
+ {
+ super_sidebar_parent: ::Sidebars::Projects::Menus::RepositoryMenu,
+ super_sidebar_before: :contributors,
+ item_id: :project_snippets
+ }
+ end
+ end
+
describe '#render?' do
context 'when user cannot access snippets' do
let(:user) { nil }
diff --git a/spec/lib/sidebars/projects/menus/wiki_menu_spec.rb b/spec/lib/sidebars/projects/menus/wiki_menu_spec.rb
index 362da3e7b50..64050e3e488 100644
--- a/spec/lib/sidebars/projects/menus/wiki_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/wiki_menu_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Menus::WikiMenu do
+RSpec.describe Sidebars::Projects::Menus::WikiMenu, feature_category: :navigation do
let(:project) { build(:project) }
let(:user) { project.first_owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
@@ -28,4 +28,14 @@ RSpec.describe Sidebars::Projects::Menus::WikiMenu do
end
end
end
+
+ it_behaves_like 'serializable as super_sidebar_menu_args' do
+ let(:menu) { subject }
+ let(:extra_attrs) do
+ {
+ super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::PlanMenu,
+ item_id: :project_wiki
+ }
+ end
+ end
end
diff --git a/spec/lib/sidebars/projects/panel_spec.rb b/spec/lib/sidebars/projects/panel_spec.rb
index ff253eedd08..ec1df438cf1 100644
--- a/spec/lib/sidebars/projects/panel_spec.rb
+++ b/spec/lib/sidebars/projects/panel_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Sidebars::Projects::Panel do
+RSpec.describe Sidebars::Projects::Panel, feature_category: :navigation do
let_it_be(:project) { create(:project) }
let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project) }
diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/operations_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/operations_menu_spec.rb
new file mode 100644
index 00000000000..df3f7e6cdab
--- /dev/null
+++ b/spec/lib/sidebars/projects/super_sidebar_menus/operations_menu_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Projects::SuperSidebarMenus::OperationsMenu, feature_category: :navigation do
+ subject { described_class.new({}) }
+
+ it 'has title and sprite_icon' do
+ expect(subject.title).to eq(_("Operations"))
+ expect(subject.sprite_icon).to eq("deployments")
+ end
+end
diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb
new file mode 100644
index 00000000000..3917d26f6f2
--- /dev/null
+++ b/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Projects::SuperSidebarMenus::PlanMenu, feature_category: :navigation do
+ subject { described_class.new({}) }
+
+ it 'has title and sprite_icon' do
+ expect(subject.title).to eq(_("Plan"))
+ expect(subject.sprite_icon).to eq("planning")
+ end
+end
diff --git a/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb b/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb
new file mode 100644
index 00000000000..d6fc3fd8fe1
--- /dev/null
+++ b/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Projects::SuperSidebarPanel, feature_category: :navigation do
+ let_it_be(:project) { create(:project, :repository) }
+
+ let(:user) { project.first_owner }
+
+ let(:context) do
+ double("Stubbed context", current_user: user, container: project, project: project, current_ref: 'master').as_null_object # rubocop:disable RSpec/VerifiedDoubles
+ end
+
+ subject { described_class.new(context) }
+
+ 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
+ })
+ end
+
+ describe '#renderable_menus' do
+ let(:category_menu) do
+ [
+ Sidebars::StaticMenu,
+ Sidebars::Projects::SuperSidebarMenus::PlanMenu,
+ Sidebars::Projects::Menus::RepositoryMenu,
+ Sidebars::Projects::Menus::CiCdMenu,
+ Sidebars::Projects::Menus::SecurityComplianceMenu,
+ Sidebars::Projects::SuperSidebarMenus::OperationsMenu,
+ Sidebars::Projects::Menus::MonitorMenu,
+ Sidebars::Projects::Menus::AnalyticsMenu,
+ Sidebars::UncategorizedMenu,
+ Sidebars::Projects::Menus::SettingsMenu
+ ]
+ end
+
+ it "is exposed as a renderable menu" do
+ expect(subject.instance_variable_get(:@menus).map(&:class)).to eq(category_menu)
+ end
+ end
+end
diff --git a/spec/lib/sidebars/static_menu_spec.rb b/spec/lib/sidebars/static_menu_spec.rb
new file mode 100644
index 00000000000..086eb332a15
--- /dev/null
+++ b/spec/lib/sidebars/static_menu_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::StaticMenu, feature_category: :navigation do
+ let(:context) { {} }
+
+ subject { described_class.new(context) }
+
+ describe '#serialize_for_super_sidebar' do
+ it 'returns flat list of all menu items' do
+ subject.add_item(Sidebars::MenuItem.new(title: 'Is active', link: 'foo2', active_routes: { controller: 'fooc' }))
+ subject.add_item(Sidebars::MenuItem.new(title: 'Not active', link: 'foo3', active_routes: { controller: 'barc' }))
+ subject.add_item(Sidebars::NilMenuItem.new(item_id: 'nil_item'))
+
+ allow(context).to receive(:route_is_active).and_return(->(x) { x[:controller] == 'fooc' })
+
+ expect(subject.serialize_for_super_sidebar).to eq(
+ [
+ {
+ title: "Is active",
+ icon: nil,
+ link: "foo2",
+ is_active: true,
+ pill_count: nil
+ },
+ {
+ title: "Not active",
+ icon: nil,
+ link: "foo3",
+ is_active: false,
+ pill_count: nil
+ }
+ ]
+ )
+ end
+ end
+end
diff --git a/spec/lib/sidebars/uncategorized_menu_spec.rb b/spec/lib/sidebars/uncategorized_menu_spec.rb
new file mode 100644
index 00000000000..45e7c0c87e2
--- /dev/null
+++ b/spec/lib/sidebars/uncategorized_menu_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UncategorizedMenu, feature_category: :navigation do
+ subject { described_class.new({}) }
+
+ it 'has title and sprite_icon' do
+ expect(subject.title).to eq(_("Uncategorized"))
+ expect(subject.sprite_icon).to eq("question")
+ end
+end
diff --git a/spec/lib/sidebars/user_profile/menus/activity_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/activity_menu_spec.rb
new file mode 100644
index 00000000000..44492380f11
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/activity_menu_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::ActivityMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Activity'),
+ active_route: 'users#activity' do
+ let(:link) { "/users/#{user.username}/activity" }
+ end
+end
diff --git a/spec/lib/sidebars/user_profile/menus/contributed_projects_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/contributed_projects_menu_spec.rb
new file mode 100644
index 00000000000..a5371c36fd3
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/contributed_projects_menu_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::ContributedProjectsMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Contributed projects'),
+ active_route: 'users#contributed' do
+ let(:link) { "/users/#{user.username}/contributed" }
+ end
+end
diff --git a/spec/lib/sidebars/user_profile/menus/followers_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/followers_menu_spec.rb
new file mode 100644
index 00000000000..1b3efbf4ceb
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/followers_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::FollowersMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Followers'),
+ active_route: 'users#followers' do
+ let(:link) { "/users/#{user.username}/followers" }
+ end
+
+ it_behaves_like 'Followers/followees counts', :followers
+end
diff --git a/spec/lib/sidebars/user_profile/menus/following_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/following_menu_spec.rb
new file mode 100644
index 00000000000..167961f085e
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/following_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::FollowingMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Following'),
+ active_route: 'users#following' do
+ let(:link) { "/users/#{user.username}/following" }
+ end
+
+ it_behaves_like 'Followers/followees counts', :followees
+end
diff --git a/spec/lib/sidebars/user_profile/menus/groups_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/groups_menu_spec.rb
new file mode 100644
index 00000000000..6c48ad2e8d0
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/groups_menu_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::GroupsMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Groups'),
+ active_route: 'users#groups' do
+ let(:link) { "/users/#{user.username}/groups" }
+ end
+end
diff --git a/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb
new file mode 100644
index 00000000000..e34f59cddf0
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::OverviewMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Overview'),
+ active_route: 'users#show' do
+ let(:link) { "/#{user.username}" }
+ end
+end
diff --git a/spec/lib/sidebars/user_profile/menus/personal_projects_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/personal_projects_menu_spec.rb
new file mode 100644
index 00000000000..ba2c3d11b88
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/personal_projects_menu_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::PersonalProjectsMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Personal projects'),
+ active_route: 'users#projects' do
+ let(:link) { "/users/#{user.username}/projects" }
+ end
+end
diff --git a/spec/lib/sidebars/user_profile/menus/snippets_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/snippets_menu_spec.rb
new file mode 100644
index 00000000000..2760d172a51
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/snippets_menu_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::SnippetsMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Snippets'),
+ active_route: 'users#snippets' do
+ let(:link) { "/users/#{user.username}/snippets" }
+ end
+end
diff --git a/spec/lib/sidebars/user_profile/menus/starred_projects_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/starred_projects_menu_spec.rb
new file mode 100644
index 00000000000..e205d1f5492
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/menus/starred_projects_menu_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Menus::StarredProjectsMenu, feature_category: :navigation do
+ it_behaves_like 'User profile menu',
+ title: s_('UserProfile|Starred projects'),
+ active_route: 'users#starred' do
+ let(:link) { "/users/#{user.username}/starred" }
+ end
+end
diff --git a/spec/lib/sidebars/user_profile/panel_spec.rb b/spec/lib/sidebars/user_profile/panel_spec.rb
new file mode 100644
index 00000000000..af261dce3f3
--- /dev/null
+++ b/spec/lib/sidebars/user_profile/panel_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserProfile::Panel, feature_category: :navigation do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:user) { create(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
+
+ subject { described_class.new(context) }
+
+ 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'
+ })
+ end
+end
diff --git a/spec/lib/sidebars/user_settings/menus/access_tokens_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/access_tokens_menu_spec.rb
new file mode 100644
index 00000000000..fa33e7bedfb
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/access_tokens_menu_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::AccessTokensMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/personal_access_tokens',
+ title: _('Access Tokens'),
+ icon: 'token',
+ active_routes: { controller: :personal_access_tokens }
+
+ describe '#render?' do
+ subject { described_class.new(context) }
+
+ let_it_be(:user) { build(:user) }
+
+ context 'when personal access tokens are disabled' do
+ before do
+ allow(::Gitlab::CurrentSettings).to receive_messages(personal_access_tokens_disabled?: true)
+ end
+
+ context 'when user is logged in' do
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ it 'does not render' do
+ expect(subject.render?).to be false
+ end
+ end
+
+ context 'when user is not logged in' do
+ let(:context) { Sidebars::Context.new(current_user: nil, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'does not render' do
+ expect(subject.render?).to be false
+ end
+ end
+ end
+
+ context 'when personal access tokens are enabled' do
+ before do
+ allow(::Gitlab::CurrentSettings).to receive_messages(personal_access_tokens_disabled?: false)
+ end
+
+ context 'when user is logged in' do
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ it 'renders' do
+ expect(subject.render?).to be true
+ end
+ end
+
+ context 'when user is not logged in' do
+ let(:context) { Sidebars::Context.new(current_user: nil, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'does not render' do
+ expect(subject.render?).to be false
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/sidebars/user_settings/menus/account_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/account_menu_spec.rb
new file mode 100644
index 00000000000..d5810d9c5ae
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/account_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::AccountMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/account',
+ title: _('Account'),
+ icon: 'account',
+ active_routes: { controller: [:accounts, :two_factor_auths] }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/active_sessions_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/active_sessions_menu_spec.rb
new file mode 100644
index 00000000000..be5f826ee58
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/active_sessions_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::ActiveSessionsMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/active_sessions',
+ title: _('Active Sessions'),
+ icon: 'monitor-lines',
+ active_routes: { controller: :active_sessions }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/applications_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/applications_menu_spec.rb
new file mode 100644
index 00000000000..eeda4fb844c
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/applications_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::ApplicationsMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/applications',
+ title: _('Applications'),
+ icon: 'applications',
+ active_routes: { controller: 'oauth/applications' }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/authentication_log_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/authentication_log_menu_spec.rb
new file mode 100644
index 00000000000..33be5050c37
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/authentication_log_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::AuthenticationLogMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/audit_log',
+ title: _('Authentication Log'),
+ icon: 'log',
+ active_routes: { path: 'profiles#audit_log' }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/chat_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/chat_menu_spec.rb
new file mode 100644
index 00000000000..2a0587e2504
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/chat_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::ChatMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/chat',
+ title: _('Chat'),
+ icon: 'comment',
+ active_routes: { controller: :chat_names }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/emails_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/emails_menu_spec.rb
new file mode 100644
index 00000000000..2f16c68e601
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/emails_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::EmailsMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/emails',
+ title: _('Emails'),
+ icon: 'mail',
+ active_routes: { controller: :emails }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/gpg_keys_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/gpg_keys_menu_spec.rb
new file mode 100644
index 00000000000..1f4340ad29c
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/gpg_keys_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::GpgKeysMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/gpg_keys',
+ title: _('GPG Keys'),
+ icon: 'key',
+ active_routes: { controller: :gpg_keys }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/notifications_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/notifications_menu_spec.rb
new file mode 100644
index 00000000000..282324056d4
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/notifications_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::NotificationsMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/notifications',
+ title: _('Notifications'),
+ icon: 'notifications',
+ active_routes: { controller: :notifications }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/password_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/password_menu_spec.rb
new file mode 100644
index 00000000000..168019fea5d
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/password_menu_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::PasswordMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/password',
+ title: _('Password'),
+ icon: 'lock',
+ active_routes: { controller: :passwords }
+
+ describe '#render?' do
+ subject { described_class.new(context) }
+
+ let_it_be(:user) { build(:user) }
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ context 'when password authentication is enabled' do
+ before do
+ allow(user).to receive(:allow_password_authentication?).and_return(true)
+ end
+
+ it 'renders' do
+ expect(subject.render?).to be true
+ end
+ end
+
+ context 'when password authentication is disabled' do
+ before do
+ allow(user).to receive(:allow_password_authentication?).and_return(false)
+ end
+
+ it 'renders' do
+ expect(subject.render?).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/sidebars/user_settings/menus/preferences_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/preferences_menu_spec.rb
new file mode 100644
index 00000000000..83a67a40081
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/preferences_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::PreferencesMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/preferences',
+ title: _('Preferences'),
+ icon: 'preferences',
+ active_routes: { controller: :preferences }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/profile_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/profile_menu_spec.rb
new file mode 100644
index 00000000000..8410ba7cfcd
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/profile_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::ProfileMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile',
+ title: _('Profile'),
+ icon: 'profile',
+ active_routes: { path: 'profiles#show' }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/menus/saved_replies_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/saved_replies_menu_spec.rb
new file mode 100644
index 00000000000..ea1a2a3539f
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/saved_replies_menu_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::SavedRepliesMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/saved_replies',
+ title: _('Saved Replies'),
+ icon: 'symlink',
+ active_routes: { controller: :saved_replies }
+
+ describe '#render?' do
+ subject { described_class.new(context) }
+
+ let_it_be(:user) { build(:user) }
+
+ context 'when saved replies are enabled' do
+ before do
+ allow(subject).to receive(:saved_replies_enabled?).and_return(true)
+ end
+
+ context 'when user is logged in' do
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ it 'does not render' do
+ expect(subject.render?).to be true
+ end
+ end
+
+ context 'when user is not logged in' do
+ let(:context) { Sidebars::Context.new(current_user: nil, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'does not render' do
+ expect(subject.render?).to be false
+ end
+ end
+ end
+
+ context 'when saved replies are disabled' do
+ before do
+ allow(subject).to receive(:saved_replies_enabled?).and_return(false)
+ end
+
+ context 'when user is logged in' do
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ it 'renders' do
+ expect(subject.render?).to be false
+ end
+ end
+
+ context 'when user is not logged in' do
+ let(:context) { Sidebars::Context.new(current_user: nil, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'does not render' do
+ expect(subject.render?).to be false
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/sidebars/user_settings/menus/ssh_keys_menu_spec.rb b/spec/lib/sidebars/user_settings/menus/ssh_keys_menu_spec.rb
new file mode 100644
index 00000000000..8c781cc743b
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/menus/ssh_keys_menu_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Menus::SshKeysMenu, feature_category: :navigation do
+ it_behaves_like 'User settings menu',
+ link: '/-/profile/keys',
+ title: _('SSH Keys'),
+ icon: 'key',
+ active_routes: { controller: :keys }
+
+ it_behaves_like 'User settings menu #render? method'
+end
diff --git a/spec/lib/sidebars/user_settings/panel_spec.rb b/spec/lib/sidebars/user_settings/panel_spec.rb
new file mode 100644
index 00000000000..aa05d99912a
--- /dev/null
+++ b/spec/lib/sidebars/user_settings/panel_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UserSettings::Panel, feature_category: :navigation do
+ let_it_be(:user) { create(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'implements #super_sidebar_context_header' do
+ expect(subject.super_sidebar_context_header).to eq({ title: _('User settings'), avatar: user.avatar_url })
+ end
+end
diff --git a/spec/lib/sidebars/your_work/panel_spec.rb b/spec/lib/sidebars/your_work/panel_spec.rb
new file mode 100644
index 00000000000..97da94e4114
--- /dev/null
+++ b/spec/lib/sidebars/your_work/panel_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::YourWork::Panel, feature_category: :navigation do
+ let_it_be(:user) { create(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'implements #super_sidebar_context_header' do
+ expect(subject.super_sidebar_context_header).to eq({ title: 'Your work', icon: 'work' })
+ end
+end
diff --git a/spec/lib/unnested_in_filters/rewriter_spec.rb b/spec/lib/unnested_in_filters/rewriter_spec.rb
index bba27276037..fe34fba579b 100644
--- a/spec/lib/unnested_in_filters/rewriter_spec.rb
+++ b/spec/lib/unnested_in_filters/rewriter_spec.rb
@@ -69,21 +69,15 @@ RSpec.describe UnnestedInFilters::Rewriter 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_default_select_fields) do
- User.default_select_columns
- .map { |field| "\"users\".\"#{field.name}\"" }
- .join(',')
- end
-
let(:expected_query) do
<<~SQL
SELECT
- #{users_default_select_fields}
+ "users".*
FROM
unnest('{1,2}'::smallint[]) AS "user_types"("user_type"),
LATERAL (
SELECT
- #{users_default_select_fields}
+ "users".*
FROM
"users"
WHERE
@@ -107,13 +101,13 @@ RSpec.describe UnnestedInFilters::Rewriter do
let(:expected_query) do
<<~SQL
SELECT
- #{users_default_select_fields}
+ "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_default_select_fields}
+ "users".*
FROM
"users"
WHERE
@@ -135,12 +129,12 @@ RSpec.describe UnnestedInFilters::Rewriter do
let(:expected_query) do
<<~SQL
SELECT
- #{users_default_select_fields}
+ "users".*
FROM
unnest('{active,blocked,banned}'::charactervarying[]) AS "states"("state"),
LATERAL (
SELECT
- #{users_default_select_fields}
+ "users".*
FROM
"users"
WHERE
@@ -187,6 +181,8 @@ RSpec.describe UnnestedInFilters::Rewriter do
let(:expected_query) do
<<~SQL
+ SELECT
+ "users".*
FROM
"users"
WHERE
@@ -221,7 +217,7 @@ RSpec.describe UnnestedInFilters::Rewriter do
end
it 'changes the query' do
- expect(issued_query.gsub(/\s/, '')).to include(expected_query.gsub(/\s/, ''))
+ expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
end
end
@@ -230,6 +226,8 @@ RSpec.describe UnnestedInFilters::Rewriter do
let(:expected_query) do
<<~SQL
+ SELECT
+ "users".*
FROM
"users"
WHERE
@@ -259,7 +257,7 @@ RSpec.describe UnnestedInFilters::Rewriter do
end
it 'does not rewrite the in statement for the joined table' do
- expect(issued_query.gsub(/\s/, '')).to include(expected_query.gsub(/\s/, ''))
+ expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
end
end
diff --git a/spec/mailers/emails/in_product_marketing_spec.rb b/spec/mailers/emails/in_product_marketing_spec.rb
index 7c21e161ffe..5419c9e6798 100644
--- a/spec/mailers/emails/in_product_marketing_spec.rb
+++ b/spec/mailers/emails/in_product_marketing_spec.rb
@@ -10,11 +10,7 @@ RSpec.describe Emails::InProductMarketing do
let_it_be(:user) { create(:user) }
shared_examples 'has custom headers when on gitlab.com' do
- context 'when on gitlab.com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
+ context 'when on gitlab.com', :saas do
it 'has custom headers' do
aggregate_failures do
expect(subject).to deliver_from(described_class::FROM_ADDRESS)
diff --git a/spec/mailers/emails/issues_spec.rb b/spec/mailers/emails/issues_spec.rb
index 21e07c0252d..b5f3972f38e 100644
--- a/spec/mailers/emails/issues_spec.rb
+++ b/spec/mailers/emails/issues_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'email_spec'
-RSpec.describe Emails::Issues do
+RSpec.describe Emails::Issues, feature_category: :team_planning do
include EmailSpec::Matchers
it 'adds email methods to Notify' do
@@ -54,38 +54,6 @@ RSpec.describe Emails::Issues do
subject { Notify.issues_csv_email(user, empty_project, "dummy content", export_status) }
- include_context 'gitlab email notification'
-
- it 'attachment has csv mime type' do
- expect(attachment.mime_type).to eq 'text/csv'
- end
-
- it 'generates a useful filename' do
- expect(attachment.filename).to include(Date.today.year.to_s)
- expect(attachment.filename).to include('issues')
- expect(attachment.filename).to include('myproject')
- expect(attachment.filename).to end_with('.csv')
- end
-
- it 'mentions number of issues and project name' do
- expect(subject).to have_content '3'
- expect(subject).to have_content empty_project.name
- end
-
- it "doesn't need to mention truncation by default" do
- expect(subject).not_to have_content 'truncated'
- end
-
- context 'when truncated' do
- let(:export_status) { { truncated: true, rows_expected: 12, rows_written: 10 } }
-
- it 'mentions that the csv has been truncated' do
- expect(subject).to have_content 'truncated'
- end
-
- it 'mentions the number of issues written and expected' do
- expect(subject).to have_content '10 of 12 issues'
- end
- end
+ it_behaves_like 'export csv email', 'issues'
end
end
diff --git a/spec/mailers/emails/profile_spec.rb b/spec/mailers/emails/profile_spec.rb
index f5fce559778..c796801fdf9 100644
--- a/spec/mailers/emails/profile_spec.rb
+++ b/spec/mailers/emails/profile_spec.rb
@@ -429,11 +429,16 @@ RSpec.describe Emails::Profile do
is_expected.to have_subject "#{Gitlab.config.gitlab.host} sign-in from new location"
end
+ it 'mentions the username' do
+ is_expected.to have_body_text user.name
+ is_expected.to have_body_text user.username
+ end
+
it 'mentions the new sign-in IP' do
is_expected.to have_body_text ip
end
- it 'mentioned the time' do
+ it 'mentions the time' do
is_expected.to have_body_text current_time.strftime('%Y-%m-%d %H:%M:%S %Z')
end
@@ -476,7 +481,7 @@ RSpec.describe Emails::Profile do
end
it 'has the correct subject' do
- is_expected.to have_subject "Attempted sign in to #{Gitlab.config.gitlab.host} using a wrong two-factor authentication code"
+ is_expected.to have_subject "Attempted sign in to #{Gitlab.config.gitlab.host} using an incorrect verification code"
end
it 'mentions the IP address' do
diff --git a/spec/mailers/emails/work_items_spec.rb b/spec/mailers/emails/work_items_spec.rb
new file mode 100644
index 00000000000..eb2c751388d
--- /dev/null
+++ b/spec/mailers/emails/work_items_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'email_spec'
+
+RSpec.describe Emails::WorkItems, feature_category: :team_planning do
+ describe '#export_work_items_csv_email' do
+ let(:user) { build_stubbed(:user) }
+ let(:empty_project) { build_stubbed(:project, path: 'myproject') }
+ let(:export_status) { { truncated: false, rows_expected: 3, rows_written: 3 } }
+ let(:attachment) { subject.attachments.first }
+
+ subject { Notify.export_work_items_csv_email(user, empty_project, "dummy content", export_status) }
+
+ it_behaves_like 'export csv email', 'work_items'
+ end
+end
diff --git a/spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb b/spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb
index 0d89851cac1..56482e8bd25 100644
--- a/spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb
+++ b/spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_migration!
-RSpec.describe DropTemporaryColumnsAndTriggersForCiBuildNeeds, feature_category: :pipeline_authoring do
+RSpec.describe DropTemporaryColumnsAndTriggersForCiBuildNeeds, feature_category: :pipeline_composition do
let(:ci_build_needs_table) { table(:ci_build_needs) }
it 'correctly migrates up and down' do
diff --git a/spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb b/spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb
index 6b0c3a6db9a..5a3ba16fcc0 100644
--- a/spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb
+++ b/spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_migration!
-RSpec.describe DropInt4ColumnForCiSourcesPipelines, feature_category: :pipeline_authoring do
+RSpec.describe DropInt4ColumnForCiSourcesPipelines, feature_category: :pipeline_composition do
let(:ci_sources_pipelines) { table(:ci_sources_pipelines) }
it 'correctly migrates up and down' do
diff --git a/spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb b/spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb
index bfe2b661a31..ede9c5ea7e8 100644
--- a/spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb
+++ b/spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_migration!
-RSpec.describe MigrateRemainingU2fRegistrations, :migration, feature_category: :authentication_and_authorization do
+RSpec.describe MigrateRemainingU2fRegistrations, :migration, feature_category: :system_access do
let(:u2f_registrations) { table(:u2f_registrations) }
let(:webauthn_registrations) { table(:webauthn_registrations) }
let(:users) { table(:users) }
diff --git a/spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb b/spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb
index 735232dfac7..b03849b61a2 100644
--- a/spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb
+++ b/spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_migration!
-RSpec.describe RescheduleExpireOAuthTokens, feature_category: :authentication_and_authorization do
+RSpec.describe RescheduleExpireOAuthTokens, feature_category: :system_access do
let!(:migration) { described_class::MIGRATION }
describe '#up' do
diff --git a/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb b/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb
index 1b8ec47f61b..2eff65d5873 100644
--- a/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb
+++ b/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require_migration!
RSpec.describe AddUserIdAndIpAddressSuccessIndexToAuthenticationEvents,
-feature_category: :authentication_and_authorization do
+feature_category: :system_access do
let(:db) { described_class.new }
let(:old_index) { described_class::OLD_INDEX_NAME }
let(:new_index) { described_class::NEW_INDEX_NAME }
diff --git a/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb b/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb
index 19cf3b2fb69..7b0df403e30 100644
--- a/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb
+++ b/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
require_migration!
RSpec.describe RemoveOrphanGroupTokenUsers, :migration, :sidekiq_inline,
-feature_category: :authentication_and_authorization do
+feature_category: :system_access do
subject(:migration) { described_class.new }
let(:users) { table(:users) }
diff --git a/spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb b/spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb
index da6532a822a..e5890ffce17 100644
--- a/spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb
+++ b/spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_migration!
-RSpec.describe CleanupOAuthAccessTokensWithNullExpiresIn, feature_category: :authentication_and_authorization do
+RSpec.describe CleanupOAuthAccessTokensWithNullExpiresIn, feature_category: :system_access do
let(:batched_migration) { described_class::MIGRATION }
it 'schedules background jobs for each batch of oauth_access_tokens' do
diff --git a/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb b/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb
new file mode 100644
index 00000000000..f6d0f32b87c
--- /dev/null
+++ b/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ScheduleMigrationForRemediation, :migration, feature_category: :vulnerability_management do
+ let(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ it 'schedules a batched background migration' do
+ migrate!
+
+ expect(migration).not_to have_scheduled_batched_migration
+ 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
diff --git a/spec/migrations/20230125195503_queue_backfill_compliance_violations_spec.rb b/spec/migrations/20230125195503_queue_backfill_compliance_violations_spec.rb
new file mode 100644
index 00000000000..a70f9820855
--- /dev/null
+++ b/spec/migrations/20230125195503_queue_backfill_compliance_violations_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillComplianceViolations, feature_category: :compliance_management do
+ let(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ it 'schedules background jobs for each batch of merge_request_compliance_violations' do
+ migrate!
+
+ expect(migration).to(
+ have_scheduled_batched_migration(
+ table_name: :merge_requests_compliance_violations,
+ column_name: :id,
+ interval: described_class::INTERVAL,
+ batch_size: described_class::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
diff --git a/spec/migrations/20230130182412_schedule_create_vulnerability_links_migration_spec.rb b/spec/migrations/20230130182412_schedule_create_vulnerability_links_migration_spec.rb
new file mode 100644
index 00000000000..58e27379ef7
--- /dev/null
+++ b/spec/migrations/20230130182412_schedule_create_vulnerability_links_migration_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ScheduleCreateVulnerabilityLinksMigration, feature_category: :vulnerability_management do
+ let(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ it 'schedules background jobs for each batch of Vulnerabilities::Feedback' do
+ migrate!
+
+ expect(migration).to have_scheduled_batched_migration(
+ table_name: :vulnerability_feedback,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::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
diff --git a/spec/migrations/20230202211434_migrate_redis_slot_keys_spec.rb b/spec/migrations/20230202211434_migrate_redis_slot_keys_spec.rb
new file mode 100644
index 00000000000..ca2c50241bf
--- /dev/null
+++ b/spec/migrations/20230202211434_migrate_redis_slot_keys_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe MigrateRedisSlotKeys, :migration, feature_category: :service_ping do
+ let(:date) { Date.yesterday.strftime('%G-%j') }
+ let(:week) { Date.yesterday.strftime('%G-%V') }
+
+ before do
+ allow(described_class::BackupHLLRedisCounter).to receive(:known_events).and_return([{
+ redis_slot: 'analytics',
+ aggregation: 'daily',
+ name: 'users_viewing_analytics_group_devops_adoption'
+ }, {
+ aggregation: 'weekly',
+ name: 'wiki_action'
+ }])
+ end
+
+ describe "#up" do
+ it 'rename keys', :aggregate_failures do
+ expiry_daily = described_class::BackupHLLRedisCounter::DEFAULT_DAILY_KEY_EXPIRY_LENGTH
+ expiry_weekly = described_class::BackupHLLRedisCounter::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH
+
+ default_slot = described_class::BackupHLLRedisCounter::REDIS_SLOT
+
+ old_slot_a = "#{date}-users_viewing_{analytics}_group_devops_adoption"
+ old_slot_b = "{wiki_action}-#{week}"
+
+ new_slot_a = "#{date}-{#{default_slot}}_users_viewing_analytics_group_devops_adoption"
+ new_slot_b = "{#{default_slot}}_wiki_action-#{week}"
+
+ Gitlab::Redis::HLL.add(key: old_slot_a, value: 1, expiry: expiry_daily)
+ Gitlab::Redis::HLL.add(key: old_slot_b, value: 1, expiry: expiry_weekly)
+
+ # check that we merge values during migration
+ # i.e. we dont drop keys created after code deploy but before the migration
+ Gitlab::Redis::HLL.add(key: new_slot_a, value: 2, expiry: expiry_daily)
+ Gitlab::Redis::HLL.add(key: new_slot_b, value: 2, expiry: expiry_weekly)
+
+ migrate!
+
+ expect(Gitlab::Redis::HLL.count(keys: new_slot_a)).to eq(2)
+ expect(Gitlab::Redis::HLL.count(keys: new_slot_b)).to eq(2)
+ expect(with_redis { |r| r.ttl(new_slot_a) }).to be_within(600).of(expiry_daily)
+ expect(with_redis { |r| r.ttl(new_slot_b) }).to be_within(600).of(expiry_weekly)
+ end
+ end
+
+ def with_redis(&block)
+ Gitlab::Redis::SharedState.with(&block)
+ end
+end
diff --git a/spec/migrations/20230208125736_schedule_migration_for_links_spec.rb b/spec/migrations/20230208125736_schedule_migration_for_links_spec.rb
new file mode 100644
index 00000000000..dd1c30415a4
--- /dev/null
+++ b/spec/migrations/20230208125736_schedule_migration_for_links_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ScheduleMigrationForLinks, :migration, feature_category: :vulnerability_management do
+ let(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ it 'schedules a batched background migration' do
+ migrate!
+
+ expect(migration).to have_scheduled_batched_migration(
+ table_name: :vulnerability_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
+
+ 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
diff --git a/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb b/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb
new file mode 100644
index 00000000000..638fe2a12d5
--- /dev/null
+++ b/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe FinalizeCiBuildNeedsBigIntConversion, migration: :gitlab_ci, feature_category: :continuous_integration do
+ describe '#up' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:dot_com, :dev_or_test, :jh, :expectation) do
+ true | true | true | :not_to
+ true | false | true | :not_to
+ false | true | true | :not_to
+ false | false | true | :not_to
+ true | true | false | :to
+ true | false | false | :to
+ false | true | false | :to
+ false | false | false | :not_to
+ end
+
+ with_them do
+ it 'ensures the migration is completed for GitLab.com, dev, or test' do
+ allow(Gitlab).to receive(:com?).and_return(dot_com)
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test)
+ allow(Gitlab).to receive(:jh?).and_return(jh)
+
+ migration_arguments = {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'ci_build_needs',
+ column_name: 'id',
+ job_arguments: [['id'], ['id_convert_to_bigint']]
+ }
+
+ expect(described_class).send(
+ expectation,
+ ensure_batched_background_migration_is_finished_for(migration_arguments)
+ )
+
+ migrate!
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb b/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb
new file mode 100644
index 00000000000..1c21047c0c3
--- /dev/null
+++ b/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapColumnsCiBuildNeedsBigIntConversion, feature_category: :continuous_integration do
+ describe '#up' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:dot_com, :dev_or_test, :jh, :swap) do
+ true | true | true | false
+ true | false | true | false
+ false | true | true | false
+ false | false | true | false
+ true | true | false | true
+ true | false | false | true
+ false | true | false | true
+ false | false | false | false
+ end
+
+ with_them do
+ before do
+ connection = described_class.new.connection
+ connection.execute('ALTER TABLE ci_build_needs ALTER COLUMN id TYPE integer')
+ connection.execute('ALTER TABLE ci_build_needs ALTER COLUMN id_convert_to_bigint TYPE bigint')
+ end
+
+ it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do
+ allow(Gitlab).to receive(:com?).and_return(dot_com)
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test)
+ allow(Gitlab).to receive(:jh?).and_return(jh)
+
+ ci_build_needs = table(:ci_build_needs)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ ci_build_needs.reset_column_information
+
+ expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer')
+ expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ ci_build_needs.reset_column_information
+
+ if swap
+ expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
+ expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('integer')
+ else
+ expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer')
+ expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint')
+ end
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb b/spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb
new file mode 100644
index 00000000000..cbf6b2882c4
--- /dev/null
+++ b/spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+require_migration!
+
+RSpec.describe AddTmpPartialIndexOnVulnerabilityReportTypes, feature_category: :vulnerability_management do
+ let(:async_index) { Gitlab::Database::AsyncIndexes::PostgresAsyncIndex }
+ let(:index_name) { described_class::INDEX_NAME }
+
+ it "schedules the index" do
+ reversible_migration do |migration|
+ migration.before -> do
+ expect(async_index.where(name: index_name).count).to be(0)
+ end
+
+ migration.after -> do
+ expect(async_index.where(name: index_name).count).to be(1)
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress_spec.rb b/spec/migrations/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress_spec.rb
new file mode 100644
index 00000000000..be49a3e919d
--- /dev/null
+++ b/spec/migrations/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe RemoveIncorrectlyOnboardedNamespacesFromOnboardingProgress, feature_category: :onboarding do
+ let(:onboarding_progresses) { table(:onboarding_progresses) }
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+
+ # namespace to keep with name Learn Gitlab
+ let(:namespace1) { namespaces.create!(name: 'namespace1', type: 'Group', path: 'namespace1') }
+ let!(:onboard_keep_1) { onboarding_progresses.create!(namespace_id: namespace1.id) }
+ let!(:proj1) do
+ proj_namespace = namespaces.create!(name: 'proj1', path: 'proj1', type: 'Project', parent_id: namespace1.id)
+ projects.create!(name: 'project', namespace_id: namespace1.id, project_namespace_id: proj_namespace.id)
+ end
+
+ let!(:learn_gitlab) do
+ proj_namespace = namespaces.create!(name: 'projlg1', path: 'projlg1', type: 'Project', parent_id: namespace1.id)
+ projects.create!(name: 'Learn GitLab', namespace_id: namespace1.id, project_namespace_id: proj_namespace.id)
+ end
+
+ # namespace to keep with name Learn GitLab - Ultimate trial
+ let(:namespace2) { namespaces.create!(name: 'namespace2', type: 'Group', path: 'namespace2') }
+ let!(:onboard_keep_2) { onboarding_progresses.create!(namespace_id: namespace2.id) }
+ let!(:proj2) do
+ proj_namespace = namespaces.create!(name: 'proj2', path: 'proj2', type: 'Project', parent_id: namespace2.id)
+ projects.create!(name: 'project', namespace_id: namespace2.id, project_namespace_id: proj_namespace.id)
+ end
+
+ let!(:learn_gitlab2) do
+ proj_namespace = namespaces.create!(name: 'projlg2', path: 'projlg2', type: 'Project', parent_id: namespace2.id)
+ projects.create!(
+ name: 'Learn GitLab - Ultimate trial',
+ namespace_id: namespace2.id,
+ project_namespace_id: proj_namespace.id
+ )
+ end
+
+ # namespace to remove without learn gitlab project
+ let(:namespace3) { namespaces.create!(name: 'namespace3', type: 'Group', path: 'namespace3') }
+ let!(:onboarding_to_delete) { onboarding_progresses.create!(namespace_id: namespace3.id) }
+ let!(:proj3) do
+ proj_namespace = namespaces.create!(name: 'proj3', path: 'proj3', type: 'Project', parent_id: namespace3.id)
+ projects.create!(name: 'project', namespace_id: namespace3.id, project_namespace_id: proj_namespace.id)
+ end
+
+ # namespace to remove without any projects
+ let(:namespace4) { namespaces.create!(name: 'namespace4', type: 'Group', path: 'namespace4') }
+ let!(:onboarding_to_delete_without_project) { onboarding_progresses.create!(namespace_id: namespace4.id) }
+
+ describe '#up' do
+ it 'deletes the onboarding for namespaces without learn gitlab' do
+ expect { migrate! }.to change { onboarding_progresses.count }.by(-2)
+ expect(onboarding_progresses.all).to contain_exactly(onboard_keep_1, onboard_keep_2)
+ end
+ end
+end
diff --git a/spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb b/spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb
new file mode 100644
index 00000000000..9163c30fe30
--- /dev/null
+++ b/spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe FinalizeNullifyCreatorIdOfOrphanedProjects, :migration, feature_category: :projects do
+ let(:batched_migrations) { table(:batched_background_migrations) }
+ let(:batch_failed_status) { 2 }
+ let(:batch_finalized_status) { 3 }
+
+ let!(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ shared_examples 'finalizes the migration' do
+ it 'finalizes the migration' do
+ expect do
+ migrate!
+
+ migration_record.reload
+ failed_job.reload
+ end.to change { migration_record.status }.from(migration_record.status).to(3).and(
+ change { failed_job.status }.from(batch_failed_status).to(batch_finalized_status)
+ )
+ end
+ end
+
+ context 'when migration is missing' do
+ it 'warns migration not found' do
+ expect(Gitlab::AppLogger)
+ .to receive(:warn).with(/Could not find batched background migration for the given configuration:/)
+
+ migrate!
+ end
+ end
+
+ context 'with migration present' do
+ let!(:migration_record) do
+ batched_migrations.create!(
+ job_class_name: 'NullifyCreatorIdColumnOfOrphanedProjects',
+ table_name: :projects,
+ column_name: :id,
+ job_arguments: [],
+ interval: 2.minutes,
+ min_value: 1,
+ max_value: 2,
+ batch_size: 1000,
+ sub_batch_size: 500,
+ max_batch_size: 5000,
+ gitlab_schema: :gitlab_main,
+ status: 3 # finished
+ )
+ end
+
+ context 'when migration finished successfully' do
+ it 'does not raise exception' do
+ expect { migrate! }.not_to raise_error
+ end
+ end
+
+ context 'with different migration statuses', :redis do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:status, :description) do
+ 0 | 'paused'
+ 1 | 'active'
+ 4 | 'failed'
+ 5 | 'finalizing'
+ end
+
+ with_them do
+ let!(:failed_job) do
+ table(:batched_background_migration_jobs).create!(
+ batched_background_migration_id: migration_record.id,
+ status: batch_failed_status,
+ min_value: 1,
+ max_value: 10,
+ attempts: 2,
+ batch_size: 100,
+ sub_batch_size: 10
+ )
+ end
+
+ before do
+ migration_record.update!(status: status)
+ end
+
+ it_behaves_like 'finalizes the migration'
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb b/spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb
new file mode 100644
index 00000000000..7c7b58c7f0e
--- /dev/null
+++ b/spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe UpdateIssuesInternalIdScope, feature_category: :team_planning do
+ describe '#up' do
+ it 'schedules background migration' do
+ migrate!
+
+ expect(described_class::MIGRATION).to have_scheduled_batched_migration(
+ table_name: :internal_ids,
+ column_name: :id,
+ interval: described_class::INTERVAL)
+ end
+ end
+
+ describe '#down' do
+ it 'does not schedule background migration' do
+ schema_migrate_down!
+
+ expect(described_class::MIGRATION).not_to have_scheduled_batched_migration(
+ table_name: :internal_ids,
+ column_name: :id,
+ interval: described_class::INTERVAL)
+ end
+ end
+end
diff --git a/spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb b/spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb
new file mode 100644
index 00000000000..9b38557c8c3
--- /dev/null
+++ b/spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe MigrateEvidencesFromRawMetadata, :migration, feature_category: :vulnerability_management do
+ let(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ it 'schedules a batched background migration' do
+ migrate!
+
+ expect(migration).to have_scheduled_batched_migration(
+ table_name: :vulnerability_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
+
+ 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
diff --git a/spec/migrations/20230228142350_add_notifications_work_item_widget_spec.rb b/spec/migrations/20230228142350_add_notifications_work_item_widget_spec.rb
new file mode 100644
index 00000000000..065b6d00ddb
--- /dev/null
+++ b/spec/migrations/20230228142350_add_notifications_work_item_widget_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddNotificationsWorkItemWidget, :migration, feature_category: :team_planning do
+ let(:migration) { described_class.new }
+ let(:work_item_definitions) { table(:work_item_widget_definitions) }
+
+ describe '#up' do
+ it 'creates notifications widget definition in all types' do
+ work_item_definitions.where(name: 'Notifications').delete_all
+
+ expect { migrate! }.to change { work_item_definitions.count }.by(7)
+ expect(work_item_definitions.all.pluck(:name)).to include('Notifications')
+ end
+ end
+
+ describe '#down' do
+ it 'removes definitions for notifications widget' do
+ migrate!
+
+ expect { migration.down }.to change { work_item_definitions.count }.by(-7)
+ expect(work_item_definitions.all.pluck(:name)).not_to include('Notifications')
+ end
+ end
+end
diff --git a/spec/migrations/20230302185739_queue_fix_vulnerability_reads_has_issues_spec.rb b/spec/migrations/20230302185739_queue_fix_vulnerability_reads_has_issues_spec.rb
new file mode 100644
index 00000000000..54b1e231db2
--- /dev/null
+++ b/spec/migrations/20230302185739_queue_fix_vulnerability_reads_has_issues_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueFixVulnerabilityReadsHasIssues, 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_issue_links,
+ column_name: :vulnerability_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/20230303105806_queue_delete_orphaned_packages_dependencies_spec.rb b/spec/migrations/20230303105806_queue_delete_orphaned_packages_dependencies_spec.rb
new file mode 100644
index 00000000000..7fe90a08763
--- /dev/null
+++ b/spec/migrations/20230303105806_queue_delete_orphaned_packages_dependencies_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueDeleteOrphanedPackagesDependencies, 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_dependencies,
+ 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/20230306195007_queue_backfill_project_wiki_repositories_spec.rb b/spec/migrations/20230306195007_queue_backfill_project_wiki_repositories_spec.rb
new file mode 100644
index 00000000000..07f501a3f98
--- /dev/null
+++ b/spec/migrations/20230306195007_queue_backfill_project_wiki_repositories_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillProjectWikiRepositories, feature_category: :geo_replication 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: :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
diff --git a/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb b/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb
new file mode 100644
index 00000000000..4dd44cad158
--- /dev/null
+++ b/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe DeleteSecurityPolicyBotUsers, feature_category: :security_policy_management do
+ let(:users) { table(:users) }
+
+ before do
+ users.create!(user_type: 10, projects_limit: 0, email: 'security_policy_bot@example.com')
+ users.create!(user_type: 1, projects_limit: 0, email: 'support_bot@example.com')
+ users.create!(projects_limit: 0, email: 'human@example.com')
+ end
+
+ describe '#up' do
+ it 'deletes security_policy_bot users' do
+ expect { migrate! }.to change { users.count }.by(-1)
+
+ expect(users.where(user_type: 10).count).to eq(0)
+ expect(users.where(user_type: 1).count).to eq(1)
+ expect(users.where(user_type: nil).count).to eq(1)
+ end
+ end
+end
diff --git a/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb b/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb
new file mode 100644
index 00000000000..00f0836285b
--- /dev/null
+++ b/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe RescheduleMigrationForRemediation, :migration, feature_category: :vulnerability_management do
+ let(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ it 'schedules a batched background migration' do
+ migrate!
+
+ expect(migration).to have_scheduled_batched_migration(
+ table_name: :vulnerability_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
+
+ 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
diff --git a/spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb b/spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb
index 5029a861d31..83b47da3065 100644
--- a/spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb
+++ b/spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_migration!
-RSpec.describe BackfillIntegrationsEnableSslVerification, feature_category: :authentication_and_authorization do
+RSpec.describe BackfillIntegrationsEnableSslVerification, feature_category: :system_access do
let!(:migration) { described_class::MIGRATION }
let!(:integrations) { described_class::Integration }
diff --git a/spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb b/spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb
index 7aaa90ee985..5854dcd3cb0 100644
--- a/spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb
+++ b/spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require_migration!
RSpec.describe CleanupBackfillIntegrationsEnableSslVerification, :migration,
-feature_category: :authentication_and_authorization do
+feature_category: :system_access do
let(:job_class_name) { 'BackfillIntegrationsEnableSslVerification' }
before do
diff --git a/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
new file mode 100644
index 00000000000..118e0058922
--- /dev/null
+++ b/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe EnsureMergeRequestMetricsIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do
+ describe '#up' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:migration_arguments) do
+ {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'merge_request_metrics',
+ column_name: 'id',
+ job_arguments: [['id'], ['id_convert_to_bigint']]
+ }
+ end
+
+ it 'ensures the migration is completed 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).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+
+ migrate!
+ end
+
+ it 'skips the check for other 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).not_to receive(:ensure_batched_background_migration_is_finished)
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
new file mode 100644
index 00000000000..9066413ce68
--- /dev/null
+++ b/spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe EnsureTimelogsNoteIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do
+ describe '#up' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:migration_arguments) do
+ {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'timelogs',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ }
+ end
+
+ it 'ensures the migration is completed 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).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+
+ migrate!
+ end
+
+ it 'skips the check for other 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).not_to receive(:ensure_batched_background_migration_is_finished)
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb b/spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb
index 8209f317550..068da23113d 100644
--- a/spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb
+++ b/spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require_migration!
RSpec.describe QueueBackfillAdminModeScopeForPersonalAccessTokens,
- feature_category: :authentication_and_authorization do
+ feature_category: :system_access do
describe '#up' do
it 'schedules background migration' do
migrate!
diff --git a/spec/migrations/queue_backfill_prepared_at_data_spec.rb b/spec/migrations/queue_backfill_prepared_at_data_spec.rb
new file mode 100644
index 00000000000..ac3ea2f59c5
--- /dev/null
+++ b/spec/migrations/queue_backfill_prepared_at_data_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillPreparedAtData, feature_category: :code_review_workflow 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: :merge_requests,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com_spec.rb
new file mode 100644
index 00000000000..b819495aa89
--- /dev/null
+++ b/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapMergeRequestMetricsIdToBigintForGitlabDotCom, feature_category: :database do
+ describe '#up' 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 merge_request_metrics ALTER COLUMN id TYPE integer')
+ connection.execute('ALTER TABLE merge_request_metrics ALTER COLUMN id_convert_to_bigint TYPE bigint')
+ end
+
+ it 'swaps the integer and bigint columns for GitLab.com, dev, or test' 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
+
+ merge_request_metrics = table(:merge_request_metrics)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ merge_request_metrics.reset_column_information
+
+ expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer')
+ expect(merge_request_metrics.columns.find do |c|
+ c.name == 'id_convert_to_bigint'
+ end.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ merge_request_metrics.reset_column_information
+
+ expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
+ expect(merge_request_metrics.columns.find do |c|
+ c.name == 'id_convert_to_bigint'
+ end.sql_type).to eq('integer')
+ }
+ end
+ end
+ end
+
+ it 'is a no-op for other instances' 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
+
+ merge_request_metrics = table(:merge_request_metrics)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ merge_request_metrics.reset_column_information
+
+ expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer')
+ expect(merge_request_metrics.columns.find do |c|
+ c.name == 'id_convert_to_bigint'
+ end.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ merge_request_metrics.reset_column_information
+
+ expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer')
+ expect(merge_request_metrics.columns.find do |c|
+ c.name == 'id_convert_to_bigint'
+ end.sql_type).to eq('bigint')
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb
new file mode 100644
index 00000000000..708688ec446
--- /dev/null
+++ b/spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapTimelogsNoteIdToBigintForGitlabDotCom, feature_category: :database do
+ describe '#up' do
+ before do
+ # A 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 timelogs ALTER COLUMN note_id TYPE integer')
+ connection.execute('ALTER TABLE timelogs ALTER COLUMN note_id_convert_to_bigint TYPE bigint')
+ end
+
+ # rubocop: disable RSpec/AnyInstanceOf
+ it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+
+ timelogs = table(:timelogs)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ timelogs.reset_column_information
+
+ expect(timelogs.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(timelogs.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ timelogs.reset_column_information
+
+ expect(timelogs.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(timelogs.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer')
+ }
+ end
+ end
+ end
+
+ it 'is a no-op for other instances' do
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+
+ timelogs = table(:timelogs)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ timelogs.reset_column_information
+
+ expect(timelogs.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(timelogs.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ timelogs.reset_column_information
+
+ expect(timelogs.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(timelogs.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint')
+ }
+ end
+ end
+ end
+ # rubocop: enable RSpec/AnyInstanceOf
+ end
+end
diff --git a/spec/migrations/update_application_settings_protected_paths_spec.rb b/spec/migrations/update_application_settings_protected_paths_spec.rb
index d61eadf9f9c..055955c56f1 100644
--- a/spec/migrations/update_application_settings_protected_paths_spec.rb
+++ b/spec/migrations/update_application_settings_protected_paths_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require_migration!
RSpec.describe UpdateApplicationSettingsProtectedPaths, :aggregate_failures,
-feature_category: :authentication_and_authorization do
+feature_category: :system_access do
subject(:migration) { described_class.new }
let!(:application_settings) { table(:application_settings) }
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index 7995cc36383..9026a870138 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -70,6 +70,42 @@ RSpec.describe AbuseReport, feature_category: :insider_threat do
}
end
+ describe 'scopes' do
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:report1) { create(:abuse_report, reporter: reporter) }
+ let_it_be(:report2) { create(:abuse_report, :closed, category: 'phishing') }
+
+ describe '.by_reporter_id' do
+ subject(:results) { described_class.by_reporter_id(reporter.id) }
+
+ it 'returns reports with reporter_id equal to the given user id' do
+ expect(subject).to match_array([report1])
+ end
+ end
+
+ describe '.open' do
+ subject(:results) { described_class.open }
+
+ it 'returns reports without resolved_at value' do
+ expect(subject).to match_array([report, report1])
+ end
+ end
+
+ describe '.closed' do
+ subject(:results) { described_class.closed }
+
+ it 'returns reports with resolved_at value' do
+ expect(subject).to match_array([report2])
+ end
+ end
+
+ describe '.by_category' do
+ it 'returns abuse reports with the specified category' do
+ expect(described_class.by_category('phishing')).to match_array([report2])
+ end
+ end
+ end
+
describe 'before_validation' do
context 'when links to spam contains empty strings' do
let(:report) { create(:abuse_report, links_to_spam: ['', 'https://gitlab.com']) }
diff --git a/spec/models/achievements/user_achievement_spec.rb b/spec/models/achievements/user_achievement_spec.rb
index 9d88bfdd477..41eaadafa67 100644
--- a/spec/models/achievements/user_achievement_spec.rb
+++ b/spec/models/achievements/user_achievement_spec.rb
@@ -7,7 +7,34 @@ RSpec.describe Achievements::UserAchievement, type: :model, feature_category: :u
it { is_expected.to belong_to(:achievement).inverse_of(:user_achievements).required }
it { is_expected.to belong_to(:user).inverse_of(:user_achievements).required }
- it { is_expected.to belong_to(:awarded_by_user).class_name('User').inverse_of(:awarded_user_achievements).optional }
+ it { is_expected.to belong_to(:awarded_by_user).class_name('User').inverse_of(:awarded_user_achievements).required }
it { is_expected.to belong_to(:revoked_by_user).class_name('User').inverse_of(:revoked_user_achievements).optional }
+
+ describe '#revoked?' do
+ subject { achievement.revoked? }
+
+ context 'when revoked' do
+ let_it_be(:achievement) { create(:user_achievement, :revoked) }
+
+ it { is_expected.to be true }
+ end
+
+ context 'when not revoked' do
+ let_it_be(:achievement) { create(:user_achievement) }
+
+ it { is_expected.to be false }
+ end
+ end
+ end
+
+ describe 'scopes' do
+ let_it_be(:user_achievement) { create(:user_achievement) }
+ let_it_be(:revoked_user_achievement) { create(:user_achievement, :revoked) }
+
+ describe '.not_revoked' do
+ it 'only returns user achievements which have not been revoked' do
+ expect(described_class.not_revoked).to contain_exactly(user_achievement)
+ end
+ end
end
end
diff --git a/spec/models/airflow/dags_spec.rb b/spec/models/airflow/dags_spec.rb
deleted file mode 100644
index ff3c4522779..00000000000
--- a/spec/models/airflow/dags_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Airflow::Dags, feature_category: :dataops do
- describe 'associations' do
- it { is_expected.to belong_to(:project) }
- end
-
- describe 'validations' do
- it { is_expected.to validate_presence_of(:project) }
- it { is_expected.to validate_presence_of(:dag_name) }
- it { is_expected.to validate_length_of(:dag_name).is_at_most(255) }
- it { is_expected.to validate_length_of(:schedule).is_at_most(255) }
- it { is_expected.to validate_length_of(:fileloc).is_at_most(255) }
- end
-end
diff --git a/spec/models/alert_management/alert_assignee_spec.rb b/spec/models/alert_management/alert_assignee_spec.rb
index c50a3ec0d01..647195380b3 100644
--- a/spec/models/alert_management/alert_assignee_spec.rb
+++ b/spec/models/alert_management/alert_assignee_spec.rb
@@ -5,7 +5,11 @@ require 'spec_helper'
RSpec.describe AlertManagement::AlertAssignee do
describe 'associations' do
it { is_expected.to belong_to(:alert) }
- it { is_expected.to belong_to(:assignee) }
+
+ it do
+ is_expected.to belong_to(:assignee).class_name('User')
+ .with_foreign_key(:user_id).inverse_of(:alert_assignees)
+ end
end
describe 'validations' do
diff --git a/spec/models/alert_management/alert_spec.rb b/spec/models/alert_management/alert_spec.rb
index 685ed81ec84..ff77ca2ab64 100644
--- a/spec/models/alert_management/alert_spec.rb
+++ b/spec/models/alert_management/alert_spec.rb
@@ -16,9 +16,13 @@ RSpec.describe AlertManagement::Alert do
it { is_expected.to belong_to(:prometheus_alert).optional }
it { is_expected.to belong_to(:environment).optional }
it { is_expected.to have_many(:assignees).through(:alert_assignees) }
- it { is_expected.to have_many(:notes) }
- it { is_expected.to have_many(:ordered_notes) }
- it { is_expected.to have_many(:user_mentions) }
+ it { is_expected.to have_many(:notes).inverse_of(:noteable) }
+ it { is_expected.to have_many(:ordered_notes).class_name('Note').inverse_of(:noteable) }
+
+ it do
+ is_expected.to have_many(:user_mentions).class_name('AlertManagement::AlertUserMention')
+ .with_foreign_key(:alert_management_alert_id).inverse_of(:alert)
+ end
end
describe 'validations' do
diff --git a/spec/models/alert_management/alert_user_mention_spec.rb b/spec/models/alert_management/alert_user_mention_spec.rb
index 27c3d290dde..083bf667bea 100644
--- a/spec/models/alert_management/alert_user_mention_spec.rb
+++ b/spec/models/alert_management/alert_user_mention_spec.rb
@@ -4,7 +4,11 @@ require 'spec_helper'
RSpec.describe AlertManagement::AlertUserMention do
describe 'associations' do
- it { is_expected.to belong_to(:alert_management_alert) }
+ it do
+ is_expected.to belong_to(:alert).class_name('::AlertManagement::Alert')
+ .with_foreign_key(:alert_management_alert_id).inverse_of(:user_mentions)
+ end
+
it { is_expected.to belong_to(:note) }
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 5b99c68ec80..8387f4021b6 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
+RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
using RSpec::Parameterized::TableSyntax
subject(:setting) { described_class.create_from_defaults }
@@ -25,6 +25,20 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
it { expect(setting.kroki_formats).to eq({}) }
end
+ describe 'associations' do
+ it do
+ is_expected.to belong_to(:self_monitoring_project).class_name('Project')
+ .with_foreign_key(:instance_administration_project_id)
+ .inverse_of(:application_setting)
+ end
+
+ it do
+ is_expected.to belong_to(:instance_group).class_name('Group')
+ .with_foreign_key(:instance_administrators_group_id)
+ .inverse_of(:application_setting)
+ end
+ end
+
describe 'validations' do
let(:http) { 'http://example.com' }
let(:https) { 'https://example.com' }
@@ -132,6 +146,9 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
it { is_expected.to allow_value(false).for(:user_defaults_to_private_profile) }
it { is_expected.not_to allow_value(nil).for(:user_defaults_to_private_profile) }
+ it { is_expected.to allow_values([true, false]).for(:deny_all_requests_except_allowed) }
+ it { is_expected.not_to allow_value(nil).for(:deny_all_requests_except_allowed) }
+
it 'ensures max_pages_size is an integer greater than 0 (or equal to 0 to indicate unlimited/maximum)' do
is_expected.to validate_numericality_of(:max_pages_size).only_integer.is_greater_than_or_equal_to(0)
.is_less_than(::Gitlab::Pages::MAX_SIZE / 1.megabyte)
@@ -182,7 +199,8 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
it { is_expected.not_to allow_value('default' => 101).for(:repository_storages_weighted).with_message("value for 'default' must be between 0 and 100") }
it { is_expected.not_to allow_value('default' => 100, shouldntexist: 50).for(:repository_storages_weighted).with_message("can't include: shouldntexist") }
- %i[notes_create_limit search_rate_limit search_rate_limit_unauthenticated users_get_by_id_limit].each do |setting|
+ %i[notes_create_limit search_rate_limit search_rate_limit_unauthenticated users_get_by_id_limit
+ projects_api_rate_limit_unauthenticated].each do |setting|
it { is_expected.to allow_value(400).for(setting) }
it { is_expected.not_to allow_value('two').for(setting) }
it { is_expected.not_to allow_value(nil).for(setting) }
@@ -209,6 +227,12 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
it { is_expected.to allow_value('disabled').for(:whats_new_variant) }
it { is_expected.not_to allow_value(nil).for(:whats_new_variant) }
+ it { is_expected.to allow_value('http://example.com/').for(:public_runner_releases_url) }
+ it { is_expected.not_to allow_value(nil).for(:public_runner_releases_url) }
+
+ it { is_expected.to allow_value([true, false]).for(:update_runner_versions_enabled) }
+ it { is_expected.not_to allow_value(nil).for(:update_runner_versions_enabled) }
+
it { is_expected.not_to allow_value(['']).for(:valid_runner_registrars) }
it { is_expected.not_to allow_value(['OBVIOUSLY_WRONG']).for(:valid_runner_registrars) }
it { is_expected.not_to allow_value(%w(project project)).for(:valid_runner_registrars) }
@@ -228,6 +252,10 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
it { is_expected.to allow_value(false).for(:allow_runner_registration_token) }
it { is_expected.not_to allow_value(nil).for(:allow_runner_registration_token) }
+ it { is_expected.to allow_value(true).for(:gitlab_dedicated_instance) }
+ it { is_expected.to allow_value(false).for(:gitlab_dedicated_instance) }
+ it { is_expected.not_to allow_value(nil).for(:gitlab_dedicated_instance) }
+
context 'when deactivate_dormant_users is enabled' do
before do
stub_application_setting(deactivate_dormant_users: true)
@@ -318,7 +346,7 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
end
end
- describe 'default_branch_name validaitions' do
+ describe 'default_branch_name validations' do
context "when javascript tags get sanitized properly" do
it "gets sanitized properly" do
setting.update!(default_branch_name: "hello<script>alert(1)</script>")
@@ -585,6 +613,23 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
end
end
+ describe 'setting validated as `addressable_url` configured with external URI' do
+ before do
+ # Use any property that has the `addressable_url` validation.
+ setting.help_page_documentation_base_url = 'http://example.com'
+ end
+
+ it 'is valid by default' do
+ expect(setting).to be_valid
+ end
+
+ it 'is invalid when unpersisted `deny_all_requests_except_allowed` property is true' do
+ setting.deny_all_requests_except_allowed = true
+
+ expect(setting).not_to be_valid
+ end
+ end
+
context 'key restrictions' do
it 'does not allow all key types to be disabled' do
Gitlab::SSHPublicKey.supported_types.each do |type|
@@ -1124,6 +1169,11 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
it { is_expected.to allow_value(*Gitlab::I18n.available_locales).for(:default_preferred_language) }
it { is_expected.not_to allow_value(nil, '', 'invalid_locale').for(:default_preferred_language) }
end
+
+ context 'for default_syntax_highlighting_theme' do
+ it { is_expected.to allow_value(*Gitlab::ColorSchemes.valid_ids).for(:default_syntax_highlighting_theme) }
+ it { is_expected.not_to allow_value(nil, 0, Gitlab::ColorSchemes.available_schemes.size + 1).for(:default_syntax_highlighting_theme) }
+ end
end
context 'restrict creating duplicates' do
@@ -1144,6 +1194,17 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
end
end
+ describe 'ADDRESSABLE_URL_VALIDATION_OPTIONS' do
+ it 'is applied to all addressable_url validated properties' do
+ url_validators = described_class.validators.select { |validator| validator.is_a?(AddressableUrlValidator) }
+
+ url_validators.each do |validator|
+ expect(validator.options).to match(hash_including(described_class::ADDRESSABLE_URL_VALIDATION_OPTIONS)),
+ "#{validator.attributes} should use ADDRESSABLE_URL_VALIDATION_OPTIONS"
+ end
+ end
+ end
+
describe '#disabled_oauth_sign_in_sources=' do
before do
allow(Devise).to receive(:omniauth_providers).and_return([:github])
@@ -1474,4 +1535,50 @@ RSpec.describe ApplicationSetting, feature_category: :not_owned, type: :model do
expect(setting.personal_access_tokens_disabled?).to eq(false)
end
end
+
+ describe 'email_confirmation_setting prefixes' do
+ before do
+ described_class.create_from_defaults
+ end
+
+ context 'when feature flag `soft_email_confirmation` is not enabled' do
+ before do
+ stub_feature_flags(soft_email_confirmation: false)
+ end
+
+ where(:email_confirmation_setting, :off, :soft, :hard) do
+ 'off' | true | false | false
+ 'soft' | false | true | false
+ 'hard' | false | false | true
+ end
+
+ with_them do
+ it 'returns the correct value when prefixed' do
+ stub_application_setting_enum('email_confirmation_setting', email_confirmation_setting)
+
+ expect(described_class.last.email_confirmation_setting_off?).to be off
+ expect(described_class.last.email_confirmation_setting_soft?).to be soft
+ expect(described_class.last.email_confirmation_setting_hard?).to be hard
+ end
+ end
+
+ it 'calls super' do
+ expect(described_class.last.email_confirmation_setting_off?).to be true
+ expect(described_class.last.email_confirmation_setting_soft?).to be false
+ expect(described_class.last.email_confirmation_setting_hard?).to be false
+ end
+ end
+
+ context 'when feature flag `soft_email_confirmation` is enabled' do
+ before do
+ stub_feature_flags(soft_email_confirmation: true)
+ end
+
+ it 'returns correct value when enum is prefixed' do
+ expect(described_class.last.email_confirmation_setting_off?).to be false
+ expect(described_class.last.email_confirmation_setting_soft?).to be true
+ expect(described_class.last.email_confirmation_setting_hard?).to be false
+ end
+ end
+ end
end
diff --git a/spec/models/audit_event_spec.rb b/spec/models/audit_event_spec.rb
index 9f2724cebee..9e667836b45 100644
--- a/spec/models/audit_event_spec.rb
+++ b/spec/models/audit_event_spec.rb
@@ -3,6 +3,10 @@
require 'spec_helper'
RSpec.describe AuditEvent do
+ describe 'associations' do
+ it { is_expected.to belong_to(:user).with_foreign_key(:author_id).inverse_of(:audit_events) }
+ end
+
describe 'validations' do
include_examples 'validates IP address' do
let(:attribute) { :ip_address }
diff --git a/spec/models/board_spec.rb b/spec/models/board_spec.rb
index 6017298e85b..f469dee5ba1 100644
--- a/spec/models/board_spec.rb
+++ b/spec/models/board_spec.rb
@@ -8,7 +8,13 @@ RSpec.describe Board do
describe 'relationships' do
it { is_expected.to belong_to(:project) }
- it { is_expected.to have_many(:lists).order(list_type: :asc, position: :asc).dependent(:delete_all) }
+
+ it do
+ is_expected.to have_many(:lists).order(list_type: :asc, position: :asc).dependent(:delete_all)
+ .inverse_of(:board)
+ end
+
+ it { is_expected.to have_many(:destroyable_lists).order(list_type: :asc, position: :asc).inverse_of(:board) }
end
describe 'validations' do
diff --git a/spec/models/bulk_import_spec.rb b/spec/models/bulk_import_spec.rb
index 3430da43f62..acb1f4a2ef7 100644
--- a/spec/models/bulk_import_spec.rb
+++ b/spec/models/bulk_import_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImport, type: :model do
+RSpec.describe BulkImport, type: :model, feature_category: :importers do
let_it_be(:created_bulk_import) { create(:bulk_import, :created) }
let_it_be(:started_bulk_import) { create(:bulk_import, :started) }
let_it_be(:finished_bulk_import) { create(:bulk_import, :finished) }
@@ -48,4 +48,31 @@ RSpec.describe BulkImport, type: :model do
expect(bulk_import.source_version_info.to_s).to eq(bulk_import.source_version)
end
end
+
+ describe '#update_has_failures' do
+ let(:import) { create(:bulk_import, :started) }
+ let(:entity) { create(:bulk_import_entity, bulk_import: import) }
+
+ context 'when entity has failures' do
+ it 'sets has_failures flag to true' do
+ expect(import.has_failures).to eq(false)
+
+ entity.update!(has_failures: true)
+ import.fail_op!
+
+ expect(import.has_failures).to eq(true)
+ end
+ end
+
+ context 'when entity does not have failures' do
+ it 'sets has_failures flag to false' do
+ expect(import.has_failures).to eq(false)
+
+ entity.update!(has_failures: false)
+ import.fail_op!
+
+ expect(import.has_failures).to eq(false)
+ end
+ end
+ end
end
diff --git a/spec/models/bulk_imports/batch_tracker_spec.rb b/spec/models/bulk_imports/batch_tracker_spec.rb
new file mode 100644
index 00000000000..336943228c7
--- /dev/null
+++ b/spec/models/bulk_imports/batch_tracker_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::BatchTracker, type: :model, feature_category: :importers do
+ describe 'associations' do
+ it { is_expected.to belong_to(:tracker) }
+ end
+
+ describe 'validations' do
+ subject { build(:bulk_import_batch_tracker) }
+
+ it { is_expected.to validate_presence_of(:batch_number) }
+ it { is_expected.to validate_uniqueness_of(:batch_number).scoped_to(:tracker_id) }
+ end
+end
diff --git a/spec/models/bulk_imports/entity_spec.rb b/spec/models/bulk_imports/entity_spec.rb
index 56796aa1fe4..45f120e6773 100644
--- a/spec/models/bulk_imports/entity_spec.rb
+++ b/spec/models/bulk_imports/entity_spec.rb
@@ -6,8 +6,13 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
describe 'associations' do
it { is_expected.to belong_to(:bulk_import).required }
it { is_expected.to belong_to(:parent) }
- it { is_expected.to belong_to(:group) }
+ it { is_expected.to belong_to(:group).optional.with_foreign_key(:namespace_id).inverse_of(:bulk_import_entities) }
it { is_expected.to belong_to(:project) }
+
+ it do
+ is_expected.to have_many(:trackers).class_name('BulkImports::Tracker')
+ .with_foreign_key(:bulk_import_entity_id).inverse_of(:entity)
+ end
end
describe 'validations' do
@@ -93,8 +98,6 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
end
it 'is invalid as a project_entity' do
- stub_feature_flags(bulk_import_projects: true)
-
entity = build(:bulk_import_entity, :project_entity, group: build(:group), project: nil)
expect(entity).not_to be_valid
@@ -104,8 +107,6 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
context 'when associated with a project and no group' do
it 'is valid' do
- stub_feature_flags(bulk_import_projects: true)
-
entity = build(:bulk_import_entity, :project_entity, group: nil, project: build(:project))
expect(entity).to be_valid
@@ -135,8 +136,6 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
context 'when the parent is a project import' do
it 'is invalid' do
- stub_feature_flags(bulk_import_projects: true)
-
entity = build(:bulk_import_entity, parent: build(:bulk_import_entity, :project_entity))
expect(entity).not_to be_valid
@@ -178,38 +177,13 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
end
end
- context 'when bulk_import_projects feature flag is disabled and source_type is a project_entity' do
- it 'is invalid' do
- stub_feature_flags(bulk_import_projects: false)
-
- entity = build(:bulk_import_entity, :project_entity)
-
- expect(entity).not_to be_valid
- expect(entity.errors[:base]).to include('invalid entity source type')
- end
- end
-
- context 'when bulk_import_projects feature flag is enabled and source_type is a project_entity' do
+ context 'when source_type is a project_entity' do
it 'is valid' do
- stub_feature_flags(bulk_import_projects: true)
-
entity = build(:bulk_import_entity, :project_entity)
expect(entity).to be_valid
end
end
-
- context 'when bulk_import_projects feature flag is enabled on root ancestor level and source_type is a project_entity' do
- it 'is valid' do
- top_level_namespace = create(:group)
-
- stub_feature_flags(bulk_import_projects: top_level_namespace)
-
- entity = build(:bulk_import_entity, :project_entity, destination_namespace: top_level_namespace.full_path)
-
- expect(entity).to be_valid
- end
- end
end
describe '#encoded_source_full_path' do
@@ -412,4 +386,30 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
end
end
end
+
+ describe '#update_has_failures' do
+ let(:entity) { create(:bulk_import_entity) }
+
+ context 'when entity has failures' do
+ it 'sets has_failures flag to true' do
+ expect(entity.has_failures).to eq(false)
+
+ create(:bulk_import_failure, entity: entity)
+
+ entity.fail_op!
+
+ expect(entity.has_failures).to eq(true)
+ end
+ end
+
+ context 'when entity does not have failures' do
+ it 'sets has_failures flag to false' do
+ expect(entity.has_failures).to eq(false)
+
+ entity.fail_op!
+
+ expect(entity.has_failures).to eq(false)
+ end
+ end
+ end
end
diff --git a/spec/models/bulk_imports/export_batch_spec.rb b/spec/models/bulk_imports/export_batch_spec.rb
new file mode 100644
index 00000000000..43209921b9c
--- /dev/null
+++ b/spec/models/bulk_imports/export_batch_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::ExportBatch, type: :model, feature_category: :importers do
+ describe 'associations' do
+ it { is_expected.to belong_to(:export) }
+ it { is_expected.to have_one(:upload) }
+ end
+
+ describe 'validations' do
+ subject { build(:bulk_import_export_batch) }
+
+ it { is_expected.to validate_presence_of(:batch_number) }
+ it { is_expected.to validate_uniqueness_of(:batch_number).scoped_to(:export_id) }
+ end
+end
diff --git a/spec/models/bulk_imports/export_spec.rb b/spec/models/bulk_imports/export_spec.rb
index d85b77d599b..7173d032bc2 100644
--- a/spec/models/bulk_imports/export_spec.rb
+++ b/spec/models/bulk_imports/export_spec.rb
@@ -2,11 +2,12 @@
require 'spec_helper'
-RSpec.describe BulkImports::Export, type: :model do
+RSpec.describe BulkImports::Export, type: :model, feature_category: :importers do
describe 'associations' do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:project) }
it { is_expected.to have_one(:upload) }
+ it { is_expected.to have_many(:batches) }
end
describe 'validations' do
diff --git a/spec/models/bulk_imports/file_transfer/project_config_spec.rb b/spec/models/bulk_imports/file_transfer/project_config_spec.rb
index 0f02c5c546f..21fe6cfb3fa 100644
--- a/spec/models/bulk_imports/file_transfer/project_config_spec.rb
+++ b/spec/models/bulk_imports/file_transfer/project_config_spec.rb
@@ -42,6 +42,18 @@ RSpec.describe BulkImports::FileTransfer::ProjectConfig do
it 'returns relation tree of a top level relation' do
expect(subject.top_relation_tree('labels')).to eq('priorities' => {})
end
+
+ it 'returns relation tree with merged with deprecated tree' do
+ expect(subject.top_relation_tree('ci_pipelines')).to match(
+ a_hash_including(
+ {
+ 'external_pull_request' => {},
+ 'merge_request' => {},
+ 'stages' => { 'bridges' => {}, 'builds' => {}, 'generic_commit_statuses' => {}, 'statuses' => {} }
+ }
+ )
+ )
+ end
end
describe '#relation_excluded_keys' do
diff --git a/spec/models/bulk_imports/tracker_spec.rb b/spec/models/bulk_imports/tracker_spec.rb
index 1516ab106cb..a618a12df6b 100644
--- a/spec/models/bulk_imports/tracker_spec.rb
+++ b/spec/models/bulk_imports/tracker_spec.rb
@@ -4,7 +4,10 @@ require 'spec_helper'
RSpec.describe BulkImports::Tracker, type: :model do
describe 'associations' do
- it { is_expected.to belong_to(:entity).required }
+ it do
+ is_expected.to belong_to(:entity).required.class_name('BulkImports::Entity')
+ .with_foreign_key(:bulk_import_entity_id).inverse_of(:trackers)
+ end
end
describe 'validations' do
diff --git a/spec/models/chat_name_spec.rb b/spec/models/chat_name_spec.rb
index 0838c232872..9d6b1a56458 100644
--- a/spec/models/chat_name_spec.rb
+++ b/spec/models/chat_name_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe ChatName, feature_category: :integrations do
subject { chat_name }
- it { is_expected.to belong_to(:integration) }
it { is_expected.to belong_to(:user) }
it { is_expected.to validate_presence_of(:user) }
@@ -16,12 +15,6 @@ RSpec.describe ChatName, feature_category: :integrations do
it { is_expected.to validate_uniqueness_of(:chat_id).scoped_to(:team_id) }
- it 'is not removed when the project is deleted' do
- expect { subject.reload.integration.project.delete }.not_to change { ChatName.count }
-
- expect(ChatName.where(id: subject.id)).to exist
- end
-
describe '#update_last_used_at', :clean_gitlab_redis_shared_state do
it 'updates the last_used_at timestamp' do
expect(subject.last_used_at).to be_nil
diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index fb50ba89cd3..c3b445cbbe5 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -22,7 +22,6 @@ RSpec.describe Ci::BuildMetadata do
it { is_expected.to belong_to(:build) }
it { is_expected.to belong_to(:project) }
- it { is_expected.to belong_to(:runner_machine) }
describe '#update_timeout_state' do
subject { metadata }
diff --git a/spec/models/ci/build_pending_state_spec.rb b/spec/models/ci/build_pending_state_spec.rb
index bff0b35f878..c978e3dba36 100644
--- a/spec/models/ci/build_pending_state_spec.rb
+++ b/spec/models/ci/build_pending_state_spec.rb
@@ -3,10 +3,15 @@
require 'spec_helper'
RSpec.describe Ci::BuildPendingState, feature_category: :continuous_integration do
+ describe 'associations' do
+ it do
+ is_expected.to belong_to(:build).class_name('Ci::Build').with_foreign_key(:build_id).inverse_of(:pending_state)
+ end
+ end
+
describe 'validations' do
subject(:pending_state) { build(:ci_build_pending_state) }
- it { is_expected.to belong_to(:build) }
it { is_expected.to validate_presence_of(:build) }
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 80d6693e08e..ca7f4794a0c 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -22,20 +22,35 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
it { is_expected.to belong_to(:runner) }
it { is_expected.to belong_to(:trigger_request) }
it { is_expected.to belong_to(:erased_by) }
+ it { is_expected.to belong_to(:pipeline).inverse_of(:builds) }
it { is_expected.to have_many(:needs).with_foreign_key(:build_id) }
- it { is_expected.to have_many(:sourced_pipelines).with_foreign_key(:source_job_id) }
- it { is_expected.to have_one(:sourced_pipeline).with_foreign_key(:source_job_id) }
+
+ it do
+ is_expected.to have_many(:sourced_pipelines).class_name('Ci::Sources::Pipeline').with_foreign_key(:source_job_id)
+ .inverse_of(:build)
+ end
+
it { is_expected.to have_many(:job_variables).with_foreign_key(:job_id) }
it { is_expected.to have_many(:report_results).with_foreign_key(:build_id) }
it { is_expected.to have_many(:pages_deployments).with_foreign_key(:ci_build_id) }
it { is_expected.to have_one(:deployment) }
- it { is_expected.to have_one(:runner_machine).through(:metadata) }
+ it { is_expected.to have_one(:runner_machine).through(:runner_machine_build) }
it { is_expected.to have_one(:runner_session).with_foreign_key(:build_id) }
it { is_expected.to have_one(:trace_metadata).with_foreign_key(:build_id) }
it { is_expected.to have_one(:runtime_metadata).with_foreign_key(:build_id) }
- it { is_expected.to have_one(:pending_state).with_foreign_key(:build_id) }
+ it { is_expected.to have_one(:pending_state).with_foreign_key(:build_id).inverse_of(:build) }
+
+ it do
+ is_expected.to have_one(:queuing_entry).class_name('Ci::PendingBuild').with_foreign_key(:build_id).inverse_of(:build)
+ end
+
+ it do
+ is_expected.to have_one(:runtime_metadata).class_name('Ci::RunningBuild').with_foreign_key(:build_id)
+ .inverse_of(:build)
+ end
+
it { is_expected.to have_many(:terraform_state_versions).inverse_of(:build).with_foreign_key(:ci_build_id) }
it { is_expected.to validate_presence_of(:ref) }
@@ -1040,7 +1055,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
context 'non public artifacts' do
- let(:build) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
+ let(:build) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) }
it { is_expected.to be_falsey }
end
@@ -1422,11 +1437,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
let(:build) { create(:ci_build, trait, pipeline: pipeline) }
let(:event) { state }
- context "when transitioning to #{params[:state]}" do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
+ context "when transitioning to #{params[:state]}", :saas do
it 'increments build_completed_report_type metric' do
expect(
::Gitlab::Ci::Artifacts::Metrics
@@ -1926,62 +1937,6 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
end
- describe '#failed_but_allowed?' do
- subject { build.failed_but_allowed? }
-
- context 'when build is not allowed to fail' do
- before do
- build.allow_failure = false
- end
-
- context 'and build.status is success' do
- before do
- build.status = 'success'
- end
-
- it { is_expected.to be_falsey }
- end
-
- context 'and build.status is failed' do
- before do
- build.status = 'failed'
- end
-
- it { is_expected.to be_falsey }
- end
- end
-
- context 'when build is allowed to fail' do
- before do
- build.allow_failure = true
- end
-
- context 'and build.status is success' do
- before do
- build.status = 'success'
- end
-
- it { is_expected.to be_falsey }
- end
-
- context 'and build status is failed' do
- before do
- build.status = 'failed'
- end
-
- it { is_expected.to be_truthy }
- end
-
- context 'when build is a manual action' do
- before do
- build.status = 'manual'
- end
-
- it { is_expected.to be_falsey }
- end
- end
- end
-
describe 'flags' do
describe '#cancelable?' do
subject { build }
@@ -3639,6 +3594,46 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
end
+ context 'for the google_play integration' do
+ let_it_be(:google_play_integration) { create(:google_play_integration) }
+
+ let(:google_play_variables) do
+ [
+ { key: 'SUPPLY_JSON_KEY_DATA', value: google_play_integration.service_account_key, masked: true, public: false }
+ ]
+ end
+
+ context 'when the google_play integration exists' do
+ context 'when a build is protected' do
+ before do
+ allow(build.pipeline).to receive(:protected_ref?).and_return(true)
+ build.project.update!(google_play_integration: google_play_integration)
+ end
+
+ it 'includes google_play variables' do
+ is_expected.to include(*google_play_variables)
+ end
+ end
+
+ context 'when a build is not protected' do
+ before do
+ allow(build.pipeline).to receive(:protected_ref?).and_return(false)
+ build.project.update!(google_play_integration: google_play_integration)
+ end
+
+ it 'does not include the google_play variable' do
+ expect(subject[:key] == 'SUPPLY_JSON_KEY_DATA').to eq(false)
+ end
+ end
+ end
+
+ context 'when the googel_play integration does not exist' do
+ it 'does not include google_play variable' do
+ expect(subject[:key] == 'SUPPLY_JSON_KEY_DATA').to eq(false)
+ end
+ end
+ end
+
context 'when build has dependency which has dotenv variable' do
let!(:prepare) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
let!(:build) { create(:ci_build, pipeline: pipeline, stage_idx: 1, options: { dependencies: [prepare.name] }) }
@@ -5784,12 +5779,6 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
expect(build.token).to be_nil
expect(build.changes).to be_empty
end
-
- it 'does not remove the token when FF is disabled' do
- stub_feature_flags(remove_job_token_on_completion: false)
-
- expect { build.remove_token! }.not_to change(build, :token)
- end
end
describe 'metadata partitioning', :ci_partitioning do
@@ -5905,4 +5894,31 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
end
end
+
+ describe 'token format for builds transiting into pending' do
+ let(:partition_id) { 100 }
+ let(:ci_build) { described_class.new(partition_id: partition_id) }
+
+ context 'when build is initialized without a token and transits to pending' do
+ let(:partition_id_prefix_in_16_bit_encode) { partition_id.to_s(16) + '_' }
+
+ it 'generates a token' do
+ expect { ci_build.enqueue }
+ .to change { ci_build.token }.from(nil).to(a_string_starting_with(partition_id_prefix_in_16_bit_encode))
+ end
+ end
+
+ context 'when build is initialized with a token and transits to pending' do
+ let(:token) { 'an_existing_secret_token' }
+
+ before do
+ ci_build.set_token(token)
+ end
+
+ it 'does not change the existing token' do
+ expect { ci_build.enqueue }
+ .not_to change { ci_build.token }.from(token)
+ end
+ end
+ end
end
diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb
index ac0a18a176d..f338c2727ad 100644
--- a/spec/models/ci/build_trace_chunk_spec.rb
+++ b/spec/models/ci/build_trace_chunk_spec.rb
@@ -20,6 +20,12 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state, :clean_git
stub_artifacts_object_storage
end
+ describe 'associations' do
+ it do
+ is_expected.to belong_to(:build).class_name('Ci::Build').with_foreign_key(:build_id).inverse_of(:trace_chunks)
+ end
+ end
+
it_behaves_like 'having unique enum values'
def redis_instance
diff --git a/spec/models/ci/catalog/listing_spec.rb b/spec/models/ci/catalog/listing_spec.rb
new file mode 100644
index 00000000000..c9ccecbc9fe
--- /dev/null
+++ b/spec/models/ci/catalog/listing_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
+ let_it_be(:namespace) { create(:group) }
+ let_it_be(:project_1) { create(:project, namespace: namespace) }
+ let_it_be(:project_2) { create(:project, namespace: namespace) }
+ let_it_be(:project_3) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ let(:list) { described_class.new(namespace, user) }
+
+ describe '#new' do
+ context 'when namespace is not a root namespace' do
+ let(:namespace) { create(:group, :nested) }
+
+ it 'raises an exception' do
+ expect { list }.to raise_error(ArgumentError, 'Namespace is not a root namespace')
+ end
+ end
+ end
+
+ describe '#resources' do
+ subject(:resources) { list.resources }
+
+ context 'when the user has access to all projects in the namespace' do
+ before do
+ namespace.add_developer(user)
+ end
+
+ context 'when the namespace has no catalog resources' do
+ it { is_expected.to be_empty }
+ end
+
+ context 'when the namespace has catalog resources' do
+ let!(:resource) { create(:catalog_resource, project: project_1) }
+ let!(:other_namespace_resource) { create(:catalog_resource, project: project_3) }
+
+ it 'contains only catalog resources for projects in that namespace' do
+ is_expected.to contain_exactly(resource)
+ end
+ end
+ 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) }
+
+ before do
+ project_1.add_developer(user)
+ end
+
+ it 'only returns catalog resources for projects the user has access to' do
+ is_expected.to contain_exactly(resource_1)
+ end
+ end
+
+ context 'when the user does not have access to the namespace' do
+ let!(:resource) { create(:catalog_resource, project: project_1) }
+
+ it { is_expected.to be_empty }
+ end
+ end
+end
diff --git a/spec/models/ci/daily_build_group_report_result_spec.rb b/spec/models/ci/daily_build_group_report_result_spec.rb
index cd55817243f..6f73d89d760 100644
--- a/spec/models/ci/daily_build_group_report_result_spec.rb
+++ b/spec/models/ci/daily_build_group_report_result_spec.rb
@@ -6,7 +6,11 @@ RSpec.describe Ci::DailyBuildGroupReportResult do
let(:daily_build_group_report_result) { build(:ci_daily_build_group_report_result) }
describe 'associations' do
- it { is_expected.to belong_to(:last_pipeline) }
+ it do
+ is_expected.to belong_to(:last_pipeline).class_name('Ci::Pipeline')
+ .with_foreign_key(:last_pipeline_id).inverse_of(:daily_build_group_report_results)
+ end
+
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:group) }
end
diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb
index e73319cfcd7..f8f184c63a1 100644
--- a/spec/models/ci/group_variable_spec.rb
+++ b/spec/models/ci/group_variable_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::GroupVariable, feature_category: :pipeline_authoring do
+RSpec.describe Ci::GroupVariable, feature_category: :pipeline_composition do
let_it_be_with_refind(:group) { create(:group) }
subject { build(:ci_group_variable, group: group) }
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index e94445f17cd..f7fafd93f4b 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Ci::JobArtifact, feature_category: :build_artifacts do
describe "Associations" do
it { is_expected.to belong_to(:project) }
- it { is_expected.to belong_to(:job) }
+ it { is_expected.to belong_to(:job).class_name('Ci::Build').with_foreign_key(:job_id).inverse_of(:job_artifacts) }
it { is_expected.to validate_presence_of(:job) }
it { is_expected.to validate_presence_of(:partition_id) }
end
@@ -243,6 +243,29 @@ RSpec.describe Ci::JobArtifact, feature_category: :build_artifacts do
end
end
+ describe '.non_trace' do
+ subject { described_class.non_trace }
+
+ context 'when there is only a trace job artifact' do
+ let!(:trace) { create(:ci_job_artifact, :trace) }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when there is only a non-trace job artifact' do
+ let!(:junit) { create(:ci_job_artifact, :junit) }
+
+ it { is_expected.to eq([junit]) }
+ end
+
+ context 'when there are both trace and non-trace job artifacts' do
+ let!(:trace) { create(:ci_job_artifact, :trace) }
+ let!(:junit) { create(:ci_job_artifact, :junit) }
+
+ it { is_expected.to eq([junit]) }
+ end
+ end
+
describe '.downloadable' do
subject { described_class.downloadable }
diff --git a/spec/models/ci/job_token/scope_spec.rb b/spec/models/ci/job_token/scope_spec.rb
index 9ae061a3702..51f0f4878e7 100644
--- a/spec/models/ci/job_token/scope_spec.rb
+++ b/spec/models/ci/job_token/scope_spec.rb
@@ -160,13 +160,5 @@ RSpec.describe Ci::JobToken::Scope, feature_category: :continuous_integration, f
include_examples 'enforces outbound scope only'
end
-
- context 'when inbound scope flag disabled' do
- before do
- stub_feature_flags(ci_inbound_job_token_scope: false)
- end
-
- include_examples 'enforces outbound scope only'
- end
end
end
diff --git a/spec/models/ci/job_variable_spec.rb b/spec/models/ci/job_variable_spec.rb
index 0a65708160a..a56e6b6be43 100644
--- a/spec/models/ci/job_variable_spec.rb
+++ b/spec/models/ci/job_variable_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Ci::JobVariable, feature_category: :continuous_integration do
describe 'associations' do
let!(:job_variable) { create(:ci_job_variable) }
- it { is_expected.to belong_to(:job) }
+ it { is_expected.to belong_to(:job).class_name('Ci::Build').with_foreign_key(:job_id).inverse_of(:job_variables) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:job_id) }
end
diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb
index 9b70f7c2839..c441be58edf 100644
--- a/spec/models/ci/pipeline_schedule_spec.rb
+++ b/spec/models/ci/pipeline_schedule_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Ci::PipelineSchedule, feature_category: :continuous_integration d
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:owner) }
- it { is_expected.to have_many(:pipelines) }
+ it { is_expected.to have_many(:pipelines).dependent(:nullify) }
it { is_expected.to have_many(:variables) }
it { is_expected.to respond_to(:ref) }
@@ -281,4 +281,19 @@ RSpec.describe Ci::PipelineSchedule, feature_category: :continuous_integration d
let!(:model) { create(:ci_pipeline_schedule, project: parent) }
end
end
+
+ describe 'before_destroy' do
+ let_it_be_with_reload(:pipeline_schedule) { create(:ci_pipeline_schedule, cron: ' 0 0 * * * ') }
+ let_it_be_with_reload(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) }
+
+ it 'nullifys associated pipelines' do
+ expect(pipeline_schedule).to receive(:nullify_dependent_associations_in_batches).and_call_original
+
+ result = pipeline_schedule.destroy
+
+ expect(result).to be_truthy
+ expect(pipeline.reload.pipeline_schedule).to be_nil
+ expect(described_class.find_by(id: pipeline_schedule.id)).to be_nil
+ end
+ end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 61422978df7..d50672da8e5 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -19,32 +19,67 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category:
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:user) }
- it { is_expected.to belong_to(:auto_canceled_by) }
+ it { is_expected.to belong_to(:auto_canceled_by).class_name('Ci::Pipeline').inverse_of(:auto_canceled_pipelines) }
it { is_expected.to belong_to(:pipeline_schedule) }
it { is_expected.to belong_to(:merge_request) }
it { is_expected.to belong_to(:external_pull_request) }
it { is_expected.to have_many(:statuses) }
- it { is_expected.to have_many(:trigger_requests) }
+ it { is_expected.to have_many(:trigger_requests).with_foreign_key(:commit_id).inverse_of(:pipeline) }
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:builds) }
- it { is_expected.to have_many(:statuses_order_id_desc) }
+
+ it do
+ is_expected.to have_many(:statuses_order_id_desc)
+ .class_name('CommitStatus').with_foreign_key(:commit_id).inverse_of(:pipeline)
+ end
+
it { is_expected.to have_many(:bridges) }
it { is_expected.to have_many(:job_artifacts).through(:builds) }
it { is_expected.to have_many(:build_trace_chunks).through(:builds) }
- it { is_expected.to have_many(:auto_canceled_pipelines) }
- it { is_expected.to have_many(:auto_canceled_jobs) }
- it { is_expected.to have_many(:sourced_pipelines) }
+
it { is_expected.to have_many(:triggered_pipelines) }
it { is_expected.to have_many(:pipeline_artifacts) }
- it { is_expected.to have_one(:chat_data) }
+ it do
+ is_expected.to have_many(:failed_builds).class_name('Ci::Build')
+ .with_foreign_key(:commit_id).inverse_of(:pipeline)
+ end
+
+ it do
+ is_expected.to have_many(:cancelable_statuses).class_name('CommitStatus')
+ .with_foreign_key(:commit_id).inverse_of(:pipeline)
+ end
+
+ it do
+ is_expected.to have_many(:auto_canceled_pipelines).class_name('Ci::Pipeline')
+ .with_foreign_key(:auto_canceled_by_id).inverse_of(:auto_canceled_by)
+ end
+
+ it do
+ is_expected.to have_many(:auto_canceled_jobs).class_name('CommitStatus')
+ .with_foreign_key(:auto_canceled_by_id).inverse_of(:auto_canceled_by)
+ end
+
+ it do
+ is_expected.to have_many(:sourced_pipelines).class_name('Ci::Sources::Pipeline')
+ .with_foreign_key(:source_pipeline_id).inverse_of(:source_pipeline)
+ end
+
it { is_expected.to have_one(:source_pipeline) }
+ it { is_expected.to have_one(:chat_data) }
it { is_expected.to have_one(:triggered_by_pipeline) }
it { is_expected.to have_one(:source_job) }
it { is_expected.to have_one(:pipeline_config) }
it { is_expected.to have_one(:pipeline_metadata) }
+ it do
+ is_expected.to have_many(:daily_build_group_report_results).class_name('Ci::DailyBuildGroupReportResult')
+ .with_foreign_key(:last_pipeline_id).inverse_of(:last_pipeline)
+ end
+
+ it { is_expected.to have_many(:latest_builds_report_results).through(:latest_builds).source(:report_results) }
+
it { is_expected.to respond_to :git_author_name }
it { is_expected.to respond_to :git_author_email }
it { is_expected.to respond_to :git_author_full_text }
@@ -872,6 +907,26 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category:
expect(pipeline).to be_valid
end
end
+
+ context 'when source is unknown' do
+ subject(:pipeline) { create(:ci_empty_pipeline, :created) }
+
+ let(:attr) { :source }
+ let(:attr_value) { :unknown }
+
+ it_behaves_like 'having enum with nil value'
+ end
+ end
+
+ describe '#config_source' do
+ context 'when source is unknown' do
+ subject(:pipeline) { create(:ci_empty_pipeline, :created) }
+
+ let(:attr) { :config_source }
+ let(:attr_value) { :unknown_source }
+
+ it_behaves_like 'having enum with nil value'
+ end
end
describe '#block' do
@@ -1661,6 +1716,154 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category:
end
end
+ describe 'merge status subscription trigger' do
+ shared_examples 'state transition not triggering GraphQL subscription mergeRequestMergeStatusUpdated' do
+ context 'when state transitions to running' do
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.run }
+ end
+ end
+
+ context 'when state transitions to success' do
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.succeed }
+ end
+ end
+
+ context 'when state transitions to failed' do
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.drop }
+ end
+ end
+
+ context 'when state transitions to canceled' do
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.cancel }
+ end
+ end
+
+ context 'when state transitions to skipped' do
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.skip }
+ end
+ end
+ end
+
+ shared_examples 'state transition triggering GraphQL subscription mergeRequestMergeStatusUpdated' do
+ context 'when state transitions to running' do
+ it_behaves_like 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.run }
+ end
+ end
+
+ context 'when state transitions to success' do
+ it_behaves_like 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.succeed }
+ end
+ end
+
+ context 'when state transitions to failed' do
+ it_behaves_like 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.drop }
+ end
+ end
+
+ context 'when state transitions to canceled' do
+ it_behaves_like 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.cancel }
+ end
+ end
+
+ context 'when state transitions to skipped' do
+ it_behaves_like 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { pipeline.skip }
+ end
+ end
+
+ context 'when only_allow_merge_if_pipeline_succeeds? returns false' do
+ let(:only_allow_merge_if_pipeline_succeeds?) { false }
+
+ it_behaves_like 'state transition not triggering GraphQL subscription mergeRequestMergeStatusUpdated'
+ end
+
+ context 'when pipeline_trigger_merge_status feature flag is disabled' do
+ before do
+ stub_feature_flags(pipeline_trigger_merge_status: false)
+ end
+
+ it_behaves_like 'state transition not triggering GraphQL subscription mergeRequestMergeStatusUpdated'
+ end
+ end
+
+ context 'when pipeline has merge requests' do
+ let(:merge_request) do
+ create(
+ :merge_request,
+ :simple,
+ source_project: project,
+ target_project: project
+ )
+ end
+
+ let(:only_allow_merge_if_pipeline_succeeds?) { true }
+
+ before do
+ allow(project)
+ .to receive(:only_allow_merge_if_pipeline_succeeds?)
+ .and_return(only_allow_merge_if_pipeline_succeeds?)
+ end
+
+ context 'when for a specific merge request' do
+ let(:pipeline) do
+ create(
+ :ci_pipeline,
+ project: project,
+ merge_request: merge_request
+ )
+ end
+
+ it_behaves_like 'state transition triggering GraphQL subscription mergeRequestMergeStatusUpdated'
+
+ context 'when pipeline is a child' do
+ let(:parent_pipeline) do
+ create(
+ :ci_pipeline,
+ project: project,
+ merge_request: merge_request
+ )
+ end
+
+ let(:pipeline) do
+ create(
+ :ci_pipeline,
+ child_of: parent_pipeline,
+ merge_request: merge_request
+ )
+ end
+
+ it_behaves_like 'state transition not triggering GraphQL subscription mergeRequestMergeStatusUpdated'
+ end
+ end
+
+ context 'when for merge requests matching the source branch and SHA' do
+ let(:pipeline) do
+ create(
+ :ci_pipeline,
+ project: project,
+ ref: merge_request.source_branch,
+ sha: merge_request.diff_head_sha
+ )
+ end
+
+ it_behaves_like 'state transition triggering GraphQL subscription mergeRequestMergeStatusUpdated'
+ end
+ end
+
+ context 'when pipeline has no merge requests' do
+ it_behaves_like 'state transition not triggering GraphQL subscription mergeRequestMergeStatusUpdated'
+ end
+ end
+
def create_build(name, *traits, queued_at: current, started_from: 0, **opts)
create(:ci_build, *traits,
name: name,
diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb
index db22d8f3a6c..cf2c176816d 100644
--- a/spec/models/ci/processable_spec.rb
+++ b/spec/models/ci/processable_spec.rb
@@ -83,7 +83,7 @@ RSpec.describe Ci::Processable, feature_category: :continuous_integration do
runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id retried failure_reason
sourced_pipelines sourced_pipeline artifacts_file_store artifacts_metadata_store
- metadata runner_machine_id runner_machine runner_session trace_chunks upstream_pipeline_id
+ metadata runner_machine_build runner_machine runner_session trace_chunks upstream_pipeline_id
artifacts_file artifacts_metadata artifacts_size commands
resource resource_group_id processed security_scans author
pipeline_id report_results pending_state pages_deployments
diff --git a/spec/models/ci/runner_machine_build_spec.rb b/spec/models/ci/runner_machine_build_spec.rb
new file mode 100644
index 00000000000..b43ff535477
--- /dev/null
+++ b/spec/models/ci/runner_machine_build_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::RunnerMachineBuild, model: true, feature_category: :runner_fleet do
+ let_it_be(:runner) { create(:ci_runner) }
+ let_it_be(:runner_machine) { create(:ci_runner_machine, runner: runner) }
+ let_it_be(:build) { create(:ci_build, runner_machine: runner_machine) }
+
+ it { is_expected.to belong_to(:build) }
+ it { is_expected.to belong_to(:runner_machine) }
+
+ describe 'partitioning' do
+ context 'with build' do
+ let(:build) { FactoryBot.build(:ci_build, partition_id: ci_testing_partition_id) }
+ let(:runner_machine_build) { FactoryBot.build(:ci_runner_machine_build, build: build) }
+
+ it 'sets partition_id to the current partition value' do
+ expect { runner_machine_build.valid? }.to change { runner_machine_build.partition_id }
+ .to(ci_testing_partition_id)
+ end
+
+ context 'when it is already set' do
+ let(:runner_machine_build) { FactoryBot.build(:ci_runner_machine_build, partition_id: 125) }
+
+ it 'does not change the partition_id value' do
+ expect { runner_machine_build.valid? }.not_to change { runner_machine_build.partition_id }
+ end
+ end
+ end
+
+ context 'without build' do
+ let(:runner_machine_build) { FactoryBot.build(:ci_runner_machine_build, build: nil) }
+
+ it { is_expected.to validate_presence_of(:partition_id) }
+
+ it 'does not change the partition_id value' do
+ expect { runner_machine_build.valid? }.not_to change { runner_machine_build.partition_id }
+ end
+ end
+ end
+
+ describe 'ci_sliding_list partitioning' do
+ let(:connection) { described_class.connection }
+ let(:partition_manager) { Gitlab::Database::Partitioning::PartitionManager.new(described_class) }
+
+ let(:partitioning_strategy) { described_class.partitioning_strategy }
+
+ it { expect(partitioning_strategy.missing_partitions).to be_empty }
+ it { expect(partitioning_strategy.extra_partitions).to be_empty }
+ it { expect(partitioning_strategy.current_partitions).to include partitioning_strategy.initial_partition }
+ it { expect(partitioning_strategy.active_partition).to be_present }
+ end
+
+ context 'loose foreign key on p_ci_runner_machine_builds.runner_machine_id' do # rubocop:disable RSpec/ContextWording
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let!(:parent) { create(:ci_runner_machine) }
+ let!(:model) { create(:ci_runner_machine_build, runner_machine: parent) }
+ end
+ end
+
+ describe '.for_build' do
+ subject(:for_build) { described_class.for_build(build_id) }
+
+ context 'with valid build_id' do
+ let(:build_id) { build.id }
+
+ it { is_expected.to contain_exactly(described_class.find_by_build_id(build_id)) }
+ end
+
+ context 'with valid build_ids' do
+ let(:build2) { create(:ci_build, runner_machine: runner_machine) }
+ let(:build_id) { [build, build2] }
+
+ it { is_expected.to eq(described_class.where(build_id: build_id)) }
+ end
+
+ context 'with non-existeng build_id' do
+ let(:build_id) { non_existing_record_id }
+
+ it { is_expected.to be_empty }
+ end
+ end
+
+ describe '.pluck_runner_machine_id_and_build_id' do
+ subject { scope.pluck_build_id_and_runner_machine_id }
+
+ context 'with default scope' do
+ let(:scope) { described_class }
+
+ it { is_expected.to eq({ build.id => runner_machine.id }) }
+ end
+
+ context 'with scope excluding build' do
+ let(:scope) { described_class.where(build_id: non_existing_record_id) }
+
+ it { is_expected.to be_empty }
+ end
+ end
+end
diff --git a/spec/models/ci/runner_machine_spec.rb b/spec/models/ci/runner_machine_spec.rb
index d0979d8a485..0989477cd21 100644
--- a/spec/models/ci/runner_machine_spec.rb
+++ b/spec/models/ci/runner_machine_spec.rb
@@ -5,10 +5,14 @@ require 'spec_helper'
RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model do
it_behaves_like 'having unique enum values'
+ it_behaves_like 'it has loose foreign keys' do
+ let(:factory_name) { :ci_runner_machine }
+ end
+
it { is_expected.to belong_to(:runner) }
it { is_expected.to belong_to(:runner_version).with_foreign_key(:version) }
- it { is_expected.to have_many(:build_metadata) }
- it { is_expected.to have_many(:builds).through(:build_metadata) }
+ it { is_expected.to have_many(:runner_machine_builds) }
+ it { is_expected.to have_many(:builds).through(:runner_machine_builds) }
describe 'validation' do
it { is_expected.to validate_presence_of(:runner) }
@@ -53,10 +57,67 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model
end
end
+ describe '.online_contact_time_deadline', :freeze_time do
+ subject { described_class.online_contact_time_deadline }
+
+ it { is_expected.to eq(2.hours.ago) }
+ end
+
+ describe '.stale_deadline', :freeze_time do
+ subject { described_class.stale_deadline }
+
+ it { is_expected.to eq(7.days.ago) }
+ end
+
+ describe '#status', :freeze_time do
+ let(:runner_machine) { build(:ci_runner_machine, created_at: 8.days.ago) }
+
+ subject { runner_machine.status }
+
+ context 'if never connected' do
+ before do
+ runner_machine.contacted_at = nil
+ end
+
+ it { is_expected.to eq(:stale) }
+
+ context 'if created recently' do
+ before do
+ runner_machine.created_at = 1.day.ago
+ end
+
+ it { is_expected.to eq(:never_contacted) }
+ end
+ end
+
+ context 'if contacted 1s ago' do
+ before do
+ runner_machine.contacted_at = 1.second.ago
+ end
+
+ it { is_expected.to eq(:online) }
+ end
+
+ context 'if contacted recently' do
+ before do
+ runner_machine.contacted_at = 2.hours.ago
+ end
+
+ it { is_expected.to eq(:offline) }
+ end
+
+ context 'if contacted long time ago' do
+ before do
+ runner_machine.contacted_at = 7.days.ago
+ end
+
+ it { is_expected.to eq(:stale) }
+ end
+ end
+
describe '#heartbeat', :freeze_time do
- let(:runner_machine) { create(:ci_runner_machine) }
+ let(:runner_machine) { create(:ci_runner_machine, version: '15.0.0') }
let(:executor) { 'shell' }
- let(:version) { '15.0.1' }
let(:values) do
{
ip_address: '8.8.8.8',
@@ -76,18 +137,38 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model
runner_machine.contacted_at = Time.current
end
- it 'schedules version update' do
- expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version).once
+ context 'when version is changed' do
+ let(:version) { '15.0.1' }
- heartbeat
+ before do
+ allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version)
+ end
- expect(runner_machine.runner_version).to be_nil
- end
+ it 'schedules version information update' do
+ heartbeat
- it 'updates cache' do
- expect_redis_update
+ expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).with(version).once
+ end
- heartbeat
+ it 'updates cache' do
+ expect_redis_update
+
+ heartbeat
+
+ expect(runner_machine.runner_version).to be_nil
+ end
+
+ context 'when fetching runner releases is disabled' do
+ before do
+ stub_application_setting(update_runner_versions_enabled: false)
+ end
+
+ it 'does not schedule version information update' do
+ heartbeat
+
+ expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to have_received(:perform_async)
+ end
+ end
end
context 'with only ip_address specified' do
@@ -96,14 +177,21 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model
end
it 'updates only ip_address' do
- attrs = Gitlab::Json.dump(ip_address: '1.1.1.1', contacted_at: Time.current)
+ expect_redis_update(values.merge(contacted_at: Time.current))
+
+ heartbeat
+ end
+
+ context 'with new version having been cached' do
+ let(:version) { '15.0.1' }
- Gitlab::Redis::Cache.with do |redis|
- redis_key = runner_machine.send(:cache_attribute_key)
- expect(redis).to receive(:set).with(redis_key, attrs, any_args)
+ before do
+ runner_machine.cache_attributes(version: version)
end
- heartbeat
+ it 'does not lose cached version value' do
+ expect { heartbeat }.not_to change { runner_machine.version }.from(version)
+ end
end
end
end
@@ -112,17 +200,29 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model
before do
runner_machine.contacted_at = 2.hours.ago
- allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version).once
+ allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version)
end
- context 'with invalid runner_machine' do
- before do
- runner_machine.runner = nil
- end
+ context 'when version is changed' do
+ let(:version) { '15.0.1' }
- it 'still updates redis cache and database' do
- expect(runner_machine).to be_invalid
+ context 'with invalid runner_machine' do
+ before do
+ runner_machine.runner = nil
+ end
+ it 'still updates redis cache and database' do
+ expect(runner_machine).to be_invalid
+
+ expect_redis_update
+ does_db_update
+
+ expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async)
+ .with(version).once
+ end
+ end
+
+ it 'updates redis cache and database' do
expect_redis_update
does_db_update
@@ -132,58 +232,52 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model
end
context 'with unchanged runner_machine version' do
- let(:runner_machine) { create(:ci_runner_machine, version: version) }
+ let(:version) { runner_machine.version }
it 'does not schedule ci_runner_versions update' do
heartbeat
expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to have_received(:perform_async)
end
- end
-
- it 'updates redis cache and database' do
- expect_redis_update
- does_db_update
-
- expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async)
- .with(version).once
- end
- Ci::Runner::EXECUTOR_NAME_TO_TYPES.each_key do |executor|
- context "with #{executor} executor" do
- let(:executor) { executor }
+ Ci::Runner::EXECUTOR_NAME_TO_TYPES.each_key do |executor|
+ context "with #{executor} executor" do
+ let(:executor) { executor }
- it 'updates with expected executor type' do
- expect_redis_update
+ it 'updates with expected executor type' do
+ expect_redis_update
- heartbeat
+ heartbeat
- expect(runner_machine.reload.read_attribute(:executor_type)).to eq(expected_executor_type)
- end
+ expect(runner_machine.reload.read_attribute(:executor_type)).to eq(expected_executor_type)
+ end
- def expected_executor_type
- executor.gsub(/[+-]/, '_')
+ def expected_executor_type
+ executor.gsub(/[+-]/, '_')
+ end
end
end
- end
- context "with an unknown executor type" do
- let(:executor) { 'some-unknown-type' }
+ context 'with an unknown executor type' do
+ let(:executor) { 'some-unknown-type' }
- it 'updates with unknown executor type' do
- expect_redis_update
+ it 'updates with unknown executor type' do
+ expect_redis_update
- heartbeat
+ heartbeat
- expect(runner_machine.reload.read_attribute(:executor_type)).to eq('unknown')
+ expect(runner_machine.reload.read_attribute(:executor_type)).to eq('unknown')
+ end
end
end
end
- def expect_redis_update
+ def expect_redis_update(values = anything)
+ values_json = values == anything ? anything : Gitlab::Json.dump(values)
+
Gitlab::Redis::Cache.with do |redis|
redis_key = runner_machine.send(:cache_attribute_key)
- expect(redis).to receive(:set).with(redis_key, anything, any_args).and_call_original
+ expect(redis).to receive(:set).with(redis_key, values_json, any_args).and_call_original
end
end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 01d5fe7f90b..fe49b2c2c7f 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -541,9 +541,9 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
describe '.stale', :freeze_time do
subject { described_class.stale }
- let!(:runner1) { create(:ci_runner, :instance, created_at: 4.months.ago, contacted_at: 3.months.ago + 10.seconds) }
- let!(:runner2) { create(:ci_runner, :instance, created_at: 4.months.ago, contacted_at: 3.months.ago - 1.second) }
- let!(:runner3) { create(:ci_runner, :instance, created_at: 3.months.ago - 1.second, contacted_at: nil) }
+ let!(:runner1) { create(:ci_runner, :instance, created_at: 4.months.ago, contacted_at: 3.months.ago + 1.second) }
+ let!(:runner2) { create(:ci_runner, :instance, created_at: 4.months.ago, contacted_at: 3.months.ago) }
+ let!(:runner3) { create(:ci_runner, :instance, created_at: 3.months.ago, contacted_at: nil) }
let!(:runner4) { create(:ci_runner, :instance, created_at: 2.months.ago, contacted_at: nil) }
it 'returns stale runners' do
@@ -551,7 +551,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
end
- describe '#stale?', :clean_gitlab_redis_cache do
+ describe '#stale?', :clean_gitlab_redis_cache, :freeze_time do
let(:runner) { build(:ci_runner, :instance) }
subject { runner.stale? }
@@ -570,11 +570,11 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
using RSpec::Parameterized::TableSyntax
where(:created_at, :contacted_at, :expected_stale?) do
- nil | nil | false
- 3.months.ago - 1.second | 3.months.ago - 0.001.seconds | true
- 3.months.ago - 1.second | 3.months.ago + 1.hour | false
- 3.months.ago - 1.second | nil | true
- 3.months.ago + 1.hour | nil | false
+ nil | nil | false
+ 3.months.ago | 3.months.ago | true
+ 3.months.ago | (3.months - 1.hour).ago | false
+ 3.months.ago | nil | true
+ (3.months - 1.hour).ago | nil | false
end
with_them do
@@ -588,9 +588,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
runner.contacted_at = contacted_at
end
- specify do
- is_expected.to eq(expected_stale?)
- end
+ it { is_expected.to eq(expected_stale?) }
end
context 'with cache value' do
@@ -599,9 +597,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
stub_redis_runner_contacted_at(contacted_at.to_s)
end
- specify do
- is_expected.to eq(expected_stale?)
- end
+ it { is_expected.to eq(expected_stale?) }
end
def stub_redis_runner_contacted_at(value)
@@ -617,7 +613,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
end
- describe '.online' do
+ describe '.online', :freeze_time do
subject { described_class.online }
let!(:runner1) { create(:ci_runner, :instance, contacted_at: 2.hours.ago) }
@@ -626,7 +622,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
it { is_expected.to match_array([runner2]) }
end
- describe '#online?', :clean_gitlab_redis_cache do
+ describe '#online?', :clean_gitlab_redis_cache, :freeze_time do
let(:runner) { build(:ci_runner, :instance) }
subject { runner.online? }
@@ -891,8 +887,8 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
end
- describe '#status' do
- let(:runner) { build(:ci_runner, :instance, created_at: 4.months.ago) }
+ describe '#status', :freeze_time do
+ let(:runner) { build(:ci_runner, :instance, created_at: 3.months.ago) }
let(:legacy_mode) {}
subject { runner.status(legacy_mode) }
@@ -948,7 +944,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
context 'contacted recently' do
before do
- runner.contacted_at = (3.months - 1.hour).ago
+ runner.contacted_at = (3.months - 1.second).ago
end
it { is_expected.to eq(:offline) }
@@ -956,7 +952,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
context 'contacted long time ago' do
before do
- runner.contacted_at = (3.months + 1.second).ago
+ runner.contacted_at = 3.months.ago
end
context 'with legacy_mode enabled' do
@@ -971,7 +967,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
end
- describe '#deprecated_rest_status' do
+ describe '#deprecated_rest_status', :freeze_time do
let(:runner) { create(:ci_runner, :instance, contacted_at: 1.second.ago) }
subject { runner.deprecated_rest_status }
@@ -994,8 +990,8 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
context 'contacted long time ago' do
before do
- runner.created_at = 1.year.ago
- runner.contacted_at = 1.year.ago
+ runner.created_at = 3.months.ago
+ runner.contacted_at = 3.months.ago
end
it { is_expected.to eq(:stale) }
@@ -1076,13 +1072,13 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
end
- describe '#heartbeat' do
- let(:runner) { create(:ci_runner, :project) }
+ describe '#heartbeat', :freeze_time do
+ let(:runner) { create(:ci_runner, :project, version: '15.0.0') }
let(:executor) { 'shell' }
- let(:version) { '15.0.1' }
+ let(:values) { { architecture: '18-bit', config: { gpus: "all" }, executor: executor, version: version } }
subject(:heartbeat) do
- runner.heartbeat(architecture: '18-bit', config: { gpus: "all" }, executor: executor, version: version)
+ runner.heartbeat(values)
end
context 'when database was updated recently' do
@@ -1090,29 +1086,61 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
runner.contacted_at = Time.current
end
- it 'updates cache' do
- expect_redis_update
- expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to receive(:perform_async)
+ context 'when version is changed' do
+ let(:version) { '15.0.1' }
+
+ before do
+ allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version)
+ end
+
+ it 'updates cache' do
+ expect_redis_update
+
+ heartbeat
+
+ expect(runner.runner_version).to be_nil
+ end
+
+ it 'schedules version information update' do
+ heartbeat
+
+ expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).with(version).once
+ end
- heartbeat
+ context 'when fetching runner releases is disabled' do
+ before do
+ stub_application_setting(update_runner_versions_enabled: false)
+ end
+
+ it 'does not schedule version information update' do
+ heartbeat
- expect(runner.runner_version).to be_nil
+ expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to have_received(:perform_async)
+ end
+ end
end
context 'with only ip_address specified', :freeze_time do
- subject(:heartbeat) do
- runner.heartbeat(ip_address: '1.1.1.1')
+ let(:values) do
+ { ip_address: '1.1.1.1' }
end
it 'updates only ip_address' do
- attrs = Gitlab::Json.dump(ip_address: '1.1.1.1', contacted_at: Time.current)
+ expect_redis_update(values.merge(contacted_at: Time.current))
- Gitlab::Redis::Cache.with do |redis|
- redis_key = runner.send(:cache_attribute_key)
- expect(redis).to receive(:set).with(redis_key, attrs, any_args)
+ heartbeat
+ end
+
+ context 'with new version having been cached' do
+ let(:version) { '15.0.1' }
+
+ before do
+ runner.cache_attributes(version: version)
end
- heartbeat
+ it 'does not lose cached version value' do
+ expect { heartbeat }.not_to change { runner.version }.from(version)
+ end
end
end
end
@@ -1121,65 +1149,81 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
before do
runner.contacted_at = 2.hours.ago
- allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async)
+ allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version)
end
- context 'with invalid runner' do
- before do
- runner.runner_projects.delete_all
- end
+ context 'when version is changed' do
+ let(:version) { '15.0.1' }
- it 'still updates redis cache and database' do
- expect(runner).to be_invalid
+ context 'with invalid runner' do
+ before do
+ runner.runner_projects.delete_all
+ end
+ it 'still updates redis cache and database' do
+ expect(runner).to be_invalid
+
+ expect_redis_update
+ does_db_update
+
+ expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).with(version).once
+ end
+ end
+
+ it 'updates redis cache and database' do
expect_redis_update
does_db_update
-
- expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).once
+ expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).with(version).once
end
end
context 'with unchanged runner version' do
- let(:runner) { create(:ci_runner, version: version) }
+ let(:version) { runner.version }
it 'does not schedule ci_runner_versions update' do
heartbeat
expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to have_received(:perform_async)
end
- end
- it 'updates redis cache and database' do
- expect_redis_update
- does_db_update
- expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).once
- end
+ Ci::Runner::EXECUTOR_NAME_TO_TYPES.each_key do |executor|
+ context "with #{executor} executor" do
+ let(:executor) { executor }
- %w(custom shell docker docker-windows docker-ssh ssh parallels virtualbox docker+machine docker-ssh+machine kubernetes some-unknown-type).each do |executor|
- context "with #{executor} executor" do
- let(:executor) { executor }
+ it 'updates with expected executor type' do
+ expect_redis_update
- it 'updates with expected executor type' do
- expect_redis_update
+ heartbeat
- heartbeat
+ expect(runner.reload.read_attribute(:executor_type)).to eq(expected_executor_type)
+ end
- expect(runner.reload.read_attribute(:executor_type)).to eq(expected_executor_type)
+ def expected_executor_type
+ executor.gsub(/[+-]/, '_')
+ end
end
+ end
+
+ context 'with an unknown executor type' do
+ let(:executor) { 'some-unknown-type' }
+
+ it 'updates with unknown executor type' do
+ expect_redis_update
- def expected_executor_type
- return 'unknown' if executor == 'some-unknown-type'
+ heartbeat
- executor.gsub(/[+-]/, '_')
+ expect(runner.reload.read_attribute(:executor_type)).to eq('unknown')
end
end
end
end
- def expect_redis_update
+ def expect_redis_update(values = anything)
+ values_json = values == anything ? anything : Gitlab::Json.dump(values)
+
Gitlab::Redis::Cache.with do |redis|
redis_key = runner.send(:cache_attribute_key)
- expect(redis).to receive(:set).with(redis_key, anything, any_args)
+ expect(redis).to receive(:set).with(redis_key, values_json, any_args).and_call_original
end
end
@@ -1994,4 +2038,59 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
end
end
+
+ describe '.with_creator' do
+ subject { described_class.with_creator }
+
+ let!(:user) { create(:admin) }
+ let!(:runner) { create(:ci_runner, creator: user) }
+
+ it { is_expected.to contain_exactly(runner) }
+ end
+
+ describe '#ensure_token' do
+ let(:runner) { described_class.new(registration_type: registration_type) }
+ let(:token) { 'an_existing_secret_token' }
+ let(:static_prefix) { described_class::CREATED_RUNNER_TOKEN_PREFIX }
+
+ context 'when runner is initialized without a token' do
+ context 'with registration_token' do
+ let(:registration_type) { :registration_token }
+
+ it 'generates a token' do
+ expect { runner.ensure_token }.to change { runner.token }.from(nil)
+ end
+ end
+
+ context 'with authenticated_user' do
+ let(:registration_type) { :authenticated_user }
+
+ it 'generates a token with prefix' do
+ expect { runner.ensure_token }.to change { runner.token }.from(nil).to(a_string_starting_with(static_prefix))
+ end
+ end
+ end
+
+ context 'when runner is initialized with a token' do
+ before do
+ runner.set_token(token)
+ end
+
+ context 'with registration_token' do
+ let(:registration_type) { :registration_token }
+
+ it 'does not change the existing token' do
+ expect { runner.ensure_token }.not_to change { runner.token }.from(token)
+ end
+ end
+
+ context 'with authenticated_user' do
+ let(:registration_type) { :authenticated_user }
+
+ it 'does not change the existing token' do
+ expect { runner.ensure_token }.not_to change { runner.token }.from(token)
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/ci/runner_version_spec.rb b/spec/models/ci/runner_version_spec.rb
index 51a2f14c57c..511d120ab7f 100644
--- a/spec/models/ci/runner_version_spec.rb
+++ b/spec/models/ci/runner_version_spec.rb
@@ -39,4 +39,15 @@ RSpec.describe Ci::RunnerVersion, feature_category: :runner_fleet do
describe 'validation' do
it { is_expected.to validate_length_of(:version).is_at_most(2048) }
end
+
+ describe '#status' do
+ context 'when is not processed' do
+ subject(:ci_runner_version) { create(:ci_runner_version, version: 'abc124', status: :not_processed) }
+
+ let(:attr) { :status }
+ let(:attr_value) { :not_processed }
+
+ it_behaves_like 'having enum with nil value'
+ end
+ end
end
diff --git a/spec/models/ci/sources/pipeline_spec.rb b/spec/models/ci/sources/pipeline_spec.rb
index 707872d0a15..47f32353fef 100644
--- a/spec/models/ci/sources/pipeline_spec.rb
+++ b/spec/models/ci/sources/pipeline_spec.rb
@@ -6,6 +6,11 @@ RSpec.describe Ci::Sources::Pipeline, feature_category: :continuous_integration
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:pipeline) }
+ it do
+ is_expected.to belong_to(:build).class_name('Ci::Build')
+ .with_foreign_key(:source_job_id).inverse_of(:sourced_pipelines)
+ end
+
it { is_expected.to belong_to(:source_project).class_name('::Project') }
it { is_expected.to belong_to(:source_job) }
it { is_expected.to belong_to(:source_bridge) }
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index ce64b3ea158..7a313115965 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Variable, feature_category: :pipeline_authoring do
+RSpec.describe Ci::Variable, feature_category: :pipeline_composition do
let_it_be_with_reload(:project) { create(:project) }
subject { build(:ci_variable, project: project) }
diff --git a/spec/models/clusters/applications/crossplane_spec.rb b/spec/models/clusters/applications/crossplane_spec.rb
deleted file mode 100644
index d1abaa52c7f..00000000000
--- a/spec/models/clusters/applications/crossplane_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::Crossplane do
- let(:crossplane) { create(:clusters_applications_crossplane) }
-
- include_examples 'cluster application core specs', :clusters_applications_crossplane
- include_examples 'cluster application status specs', :clusters_applications_crossplane
- include_examples 'cluster application version specs', :clusters_applications_crossplane
- include_examples 'cluster application initial status specs'
-
- describe 'validations' do
- it { is_expected.to validate_presence_of(:stack) }
- end
-
- describe 'default values' do
- it { expect(subject.version).to eq(described_class::VERSION) }
- it { expect(subject.stack).to be_empty }
- end
-
- describe '#can_uninstall?' do
- subject { crossplane.can_uninstall? }
-
- it { is_expected.to be_truthy }
- end
-
- describe '#install_command' do
- let(:stack) { 'gcp' }
-
- subject { crossplane.install_command }
-
- it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) }
-
- it 'is initialized with crossplane arguments' do
- expect(subject.name).to eq('crossplane')
- expect(subject.chart).to eq('crossplane/crossplane')
- expect(subject.repository).to eq('https://charts.crossplane.io/alpha')
- expect(subject.version).to eq('0.4.1')
- expect(subject).to be_rbac
- end
-
- context 'application failed to install previously' do
- let(:crossplane) { create(:clusters_applications_crossplane, :errored, version: '0.0.1') }
-
- it 'is initialized with the locked version' do
- expect(subject.version).to eq('0.4.1')
- end
- end
- end
-
- describe '#files' do
- let(:application) { crossplane }
- let(:values) { subject[:'values.yaml'] }
-
- subject { application.files }
-
- it 'includes crossplane specific keys in the values.yaml file' do
- expect(values).to include('clusterStacks')
- end
- end
-end
diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb
index f6b13f4a93f..91e90de02c0 100644
--- a/spec/models/clusters/applications/knative_spec.rb
+++ b/spec/models/clusters/applications/knative_spec.rb
@@ -17,10 +17,6 @@ RSpec.describe Clusters::Applications::Knative do
include_examples 'cluster application version specs', :clusters_applications_knative
include_examples 'cluster application initial status specs'
- describe 'associations' do
- it { is_expected.to have_one(:serverless_domain_cluster).class_name('::Serverless::DomainCluster').with_foreign_key('clusters_applications_knative_id').inverse_of(:knative) }
- end
-
describe 'default values' do
it { expect(subject.version).to eq(described_class::VERSION) }
end
@@ -135,19 +131,6 @@ RSpec.describe Clusters::Applications::Knative do
it 'does not install metrics for prometheus' do
expect(subject.postinstall).to be_empty
end
-
- context 'with prometheus installed' do
- let(:prometheus) { create(:clusters_applications_prometheus, :installed) }
- let(:knative) { create(:clusters_applications_knative, cluster: prometheus.cluster) }
-
- subject { knative.install_command }
-
- it 'installs metrics' do
- expect(subject.postinstall).not_to be_empty
- expect(subject.postinstall.length).to be(1)
- expect(subject.postinstall[0]).to eql("kubectl apply -f #{Clusters::Applications::Knative::METRICS_CONFIG}")
- end
- end
end
describe '#install_command' do
@@ -249,12 +232,4 @@ RSpec.describe Clusters::Applications::Knative do
expect(subject.find_available_domain(domain.id)).to eq(domain)
end
end
-
- describe '#pages_domain' do
- let!(:sdc) { create(:serverless_domain_cluster, knative: knative) }
-
- it 'returns the the associated pages domain' do
- expect(knative.reload.pages_domain).to eq(sdc.pages_domain)
- end
- end
end
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
deleted file mode 100644
index 15c3162270e..00000000000
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ /dev/null
@@ -1,349 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::Prometheus do
- include KubernetesHelpers
- include StubRequests
-
- include_examples 'cluster application core specs', :clusters_applications_prometheus
- include_examples 'cluster application status specs', :clusters_applications_prometheus
- include_examples 'cluster application version specs', :clusters_applications_prometheus
- include_examples 'cluster application helm specs', :clusters_applications_prometheus
- include_examples 'cluster application initial status specs'
-
- describe 'default values' do
- subject(:prometheus) { build(:clusters_applications_prometheus) }
-
- it { expect(prometheus.alert_manager_token).to be_an_instance_of(String) }
- it { expect(prometheus.version).to eq(described_class::VERSION) }
- end
-
- describe 'after_destroy' do
- let(:cluster) { create(:cluster, :with_installed_helm) }
- let(:application) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
-
- it 'disables the corresponding integration' do
- application.destroy!
-
- expect(cluster.integration_prometheus).not_to be_enabled
- end
- end
-
- describe 'transition to installed' do
- let(:project) { create(:project) }
- let(:cluster) { create(:cluster, :with_installed_helm) }
- let(:application) { create(:clusters_applications_prometheus, :installing, cluster: cluster) }
-
- it 'enables the corresponding integration' do
- application.make_installed
-
- expect(cluster.integration_prometheus).to be_enabled
- end
- end
-
- describe 'transition to externally_installed' do
- let(:project) { create(:project) }
- let(:cluster) { create(:cluster, :with_installed_helm) }
- let(:application) { create(:clusters_applications_prometheus, :installing, cluster: cluster) }
-
- it 'enables the corresponding integration' do
- application.make_externally_installed!
-
- expect(cluster.integration_prometheus).to be_enabled
- end
- end
-
- describe 'transition to updating' do
- let(:project) { create(:project) }
- let(:cluster) { create(:cluster, projects: [project]) }
-
- subject { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
-
- it 'sets last_update_started_at to now' do
- freeze_time do
- expect { subject.make_updating }.to change { subject.reload.last_update_started_at }.to be_within(1.second).of(Time.current)
- end
- end
- end
-
- describe '#managed_prometheus?' do
- subject { prometheus.managed_prometheus? }
-
- let(:prometheus) { build(:clusters_applications_prometheus) }
-
- it { is_expected.to be_truthy }
-
- context 'externally installed' do
- let(:prometheus) { build(:clusters_applications_prometheus, :externally_installed) }
-
- it { is_expected.to be_falsey }
- end
-
- context 'uninstalled' do
- let(:prometheus) { build(:clusters_applications_prometheus, :uninstalled) }
-
- it { is_expected.to be_falsey }
- end
- end
-
- describe '#can_uninstall?' do
- let(:prometheus) { create(:clusters_applications_prometheus) }
-
- subject { prometheus.can_uninstall? }
-
- it { is_expected.to be_truthy }
- end
-
- describe '#prometheus_client' do
- include_examples '#prometheus_client shared' do
- let(:factory) { :clusters_applications_prometheus }
- end
- end
-
- describe '#install_command' do
- let(:prometheus) { create(:clusters_applications_prometheus) }
-
- subject { prometheus.install_command }
-
- it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) }
-
- it 'is initialized with 3 arguments' do
- expect(subject.name).to eq('prometheus')
- expect(subject.chart).to eq('prometheus/prometheus')
- expect(subject.version).to eq('10.4.1')
- expect(subject).to be_rbac
- expect(subject.files).to eq(prometheus.files)
- end
-
- context 'on a non rbac enabled cluster' do
- before do
- prometheus.cluster.platform_kubernetes.abac!
- end
-
- it { is_expected.not_to be_rbac }
- end
-
- context 'application failed to install previously' do
- let(:prometheus) { create(:clusters_applications_prometheus, :errored, version: '2.0.0') }
-
- it 'is initialized with the locked version' do
- expect(subject.version).to eq('10.4.1')
- end
- end
-
- it 'does not install knative metrics' do
- expect(subject.postinstall).to be_empty
- end
-
- context 'with knative installed' do
- let(:knative) { create(:clusters_applications_knative, :updated) }
- let(:prometheus) { create(:clusters_applications_prometheus, cluster: knative.cluster) }
-
- subject { prometheus.install_command }
-
- it 'installs knative metrics' do
- expect(subject.postinstall).to include("kubectl apply -f #{Clusters::Applications::Knative::METRICS_CONFIG}")
- end
- end
- end
-
- describe '#uninstall_command' do
- let(:prometheus) { create(:clusters_applications_prometheus) }
-
- subject { prometheus.uninstall_command }
-
- it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand) }
-
- it 'has the application name' do
- expect(subject.name).to eq('prometheus')
- end
-
- it 'has files' do
- expect(subject.files).to eq(prometheus.files)
- end
-
- it 'is rbac' do
- expect(subject).to be_rbac
- end
-
- describe '#predelete' do
- let(:knative) { create(:clusters_applications_knative, :updated) }
- let(:prometheus) { create(:clusters_applications_prometheus, cluster: knative.cluster) }
-
- subject { prometheus.uninstall_command.predelete }
-
- it 'deletes knative metrics' do
- metrics_config = Clusters::Applications::Knative::METRICS_CONFIG
- is_expected.to include("kubectl delete -f #{metrics_config} --ignore-not-found")
- end
- end
-
- context 'on a non rbac enabled cluster' do
- before do
- prometheus.cluster.platform_kubernetes.abac!
- end
-
- it { is_expected.not_to be_rbac }
- end
- end
-
- describe '#patch_command' do
- subject(:patch_command) { prometheus.patch_command(values) }
-
- let(:prometheus) { build(:clusters_applications_prometheus) }
- let(:values) { prometheus.values }
-
- it { is_expected.to be_an_instance_of(::Gitlab::Kubernetes::Helm::V3::PatchCommand) }
-
- it 'is initialized with 3 arguments' do
- expect(patch_command.name).to eq('prometheus')
- expect(patch_command.chart).to eq('prometheus/prometheus')
- expect(patch_command.version).to eq('10.4.1')
- expect(patch_command.files).to eq(prometheus.files)
- end
- end
-
- describe '#update_in_progress?' do
- context 'when app is updating' do
- it 'returns true' do
- cluster = create(:cluster)
- prometheus_app = build(:clusters_applications_prometheus, :updating, cluster: cluster)
-
- expect(prometheus_app.update_in_progress?).to be true
- end
- end
- end
-
- describe '#update_errored?' do
- context 'when app errored' do
- it 'returns true' do
- cluster = create(:cluster)
- prometheus_app = build(:clusters_applications_prometheus, :update_errored, cluster: cluster)
-
- expect(prometheus_app.update_errored?).to be true
- end
- end
- end
-
- describe '#files' do
- let(:application) { create(:clusters_applications_prometheus) }
- let(:values) { subject[:'values.yaml'] }
-
- subject { application.files }
-
- it 'includes prometheus valid values' do
- expect(values).to include('alertmanager')
- expect(values).to include('kubeStateMetrics')
- expect(values).to include('nodeExporter')
- expect(values).to include('pushgateway')
- expect(values).to include('serverFiles')
- end
- end
-
- describe '#files_with_replaced_values' do
- let(:application) { build(:clusters_applications_prometheus) }
- let(:files) { application.files }
-
- subject { application.files_with_replaced_values({ hello: :world }) }
-
- it 'does not modify #files' do
- expect(subject[:'values.yaml']).not_to eq(files[:'values.yaml'])
-
- expect(files[:'values.yaml']).to eq(application.values)
- end
-
- it 'returns values.yaml with replaced values' do
- expect(subject[:'values.yaml']).to eq({ hello: :world })
- end
-
- it 'uses values from #files, except for values.yaml' do
- allow(application).to receive(:files).and_return({
- 'values.yaml': 'some value specific to files',
- 'file_a.txt': 'file_a',
- 'file_b.txt': 'file_b'
- })
-
- expect(subject.except(:'values.yaml')).to eq({
- 'file_a.txt': 'file_a',
- 'file_b.txt': 'file_b'
- })
- end
- end
-
- describe '#configured?' do
- let(:prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
-
- subject { prometheus.configured? }
-
- context 'when a kubenetes client is present' do
- let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
-
- it { is_expected.to be_truthy }
-
- context 'when it is not availalble' do
- let(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) }
-
- it { is_expected.to be_falsey }
- end
-
- context 'when the kubernetes URL is blocked' do
- before do
- blocked_ip = '127.0.0.1' # localhost addresses are blocked by default
-
- stub_all_dns(cluster.platform.api_url, ip_address: blocked_ip)
- end
-
- it { is_expected.to be_falsey }
- end
- end
-
- context 'when a kubenetes client is not present' do
- let(:cluster) { create(:cluster) }
-
- it { is_expected.to be_falsy }
- end
- end
-
- describe '#updated_since?' do
- let(:cluster) { create(:cluster) }
- let(:prometheus_app) { build(:clusters_applications_prometheus, cluster: cluster) }
- let(:timestamp) { Time.current - 5.minutes }
-
- around do |example|
- freeze_time { example.run }
- end
-
- before do
- prometheus_app.last_update_started_at = Time.current
- end
-
- context 'when app does not have status failed' do
- it 'returns true when last update started after the timestamp' do
- expect(prometheus_app.updated_since?(timestamp)).to be true
- end
-
- it 'returns false when last update started before the timestamp' do
- expect(prometheus_app.updated_since?(Time.current + 5.minutes)).to be false
- end
- end
-
- context 'when app has status failed' do
- it 'returns false when last update started after the timestamp' do
- prometheus_app.status = 6
-
- expect(prometheus_app.updated_since?(timestamp)).to be false
- end
- end
- end
-
- describe 'alert manager token' do
- subject { create(:clusters_applications_prometheus) }
-
- it 'is autogenerated on creation' do
- expect(subject.alert_manager_token).to match(/\A\h{32}\z/)
- expect(subject.encrypted_alert_manager_token).not_to be_nil
- expect(subject.encrypted_alert_manager_token_iv).not_to be_nil
- end
- end
-end
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 2a2e2899d24..2d46714eb22 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -25,7 +25,6 @@ feature_category: :kubernetes_management do
it { is_expected.to have_one(:integration_prometheus) }
it { is_expected.to have_one(:application_helm) }
it { is_expected.to have_one(:application_ingress) }
- it { is_expected.to have_one(:application_prometheus) }
it { is_expected.to have_one(:application_runner) }
it { is_expected.to have_many(:kubernetes_namespaces) }
it { is_expected.to have_one(:cluster_project) }
@@ -714,13 +713,12 @@ feature_category: :kubernetes_management do
context 'when all applications are created' do
let!(:helm) { create(:clusters_applications_helm, cluster: cluster) }
let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) }
- let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) }
let!(:runner) { create(:clusters_applications_runner, cluster: cluster) }
let!(:jupyter) { create(:clusters_applications_jupyter, cluster: cluster) }
let!(:knative) { create(:clusters_applications_knative, cluster: cluster) }
it 'returns a list of created applications' do
- is_expected.to contain_exactly(helm, ingress, prometheus, runner, jupyter, knative)
+ is_expected.to contain_exactly(helm, ingress, runner, jupyter, knative)
end
end
@@ -1342,22 +1340,6 @@ feature_category: :kubernetes_management do
expect(cluster.prometheus_adapter).to eq(integration)
end
end
-
- context 'has application_prometheus' do
- let_it_be(:application) { create(:clusters_applications_prometheus, :no_helm_installed, cluster: cluster) }
-
- it 'returns nil' do
- expect(cluster.prometheus_adapter).to be_nil
- end
-
- context 'also has a integration_prometheus' do
- let_it_be(:integration) { create(:clusters_integrations_prometheus, cluster: cluster) }
-
- it 'returns the integration' do
- expect(cluster.prometheus_adapter).to eq(integration)
- end
- end
- end
end
describe '#delete_cached_resources!' do
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index b280275c2e5..efe511bf1c5 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -930,4 +930,13 @@ RSpec.describe Clusters::Platforms::Kubernetes do
end
end
end
+
+ describe '#authorization_type' do
+ subject(:kubernetes) { create(:cluster_platform_kubernetes) }
+
+ let(:attr) { :authorization_type }
+ let(:attr_value) { :unknown_authorization }
+
+ it_behaves_like 'having enum with nil value'
+ end
end
diff --git a/spec/models/commit_collection_spec.rb b/spec/models/commit_collection_spec.rb
index 6dd34c3e21f..706f18a5337 100644
--- a/spec/models/commit_collection_spec.rb
+++ b/spec/models/commit_collection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CommitCollection do
+RSpec.describe CommitCollection, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:commit) { project.commit("c1c67abbaf91f624347bb3ae96eabe3a1b742478") }
@@ -191,6 +191,19 @@ RSpec.describe CommitCollection do
end
end
+ describe '#load_tags' do
+ let(:gitaly_commit_with_tags) { project.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
+ let(:collection) { described_class.new(project, [gitaly_commit_with_tags]) }
+
+ subject { collection.load_tags }
+
+ it 'loads tags' do
+ subject
+
+ expect(collection.commits[0].referenced_by).to contain_exactly('refs/tags/v1.1.0')
+ end
+ end
+
describe '#respond_to_missing?' do
it 'returns true when the underlying Array responds to the message' do
collection = described_class.new(project, [])
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 4ff451af9de..54ca7f0c893 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -17,7 +17,11 @@ RSpec.describe CommitStatus do
it_behaves_like 'having unique enum values'
- it { is_expected.to belong_to(:pipeline) }
+ it do
+ is_expected.to belong_to(:pipeline).class_name('Ci::Pipeline')
+ .with_foreign_key(:commit_id).inverse_of(:statuses)
+ end
+
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:auto_canceled_by) }
@@ -33,6 +37,7 @@ RSpec.describe CommitStatus do
it { is_expected.to respond_to :running? }
it { is_expected.to respond_to :pending? }
it { is_expected.not_to be_retried }
+ it { expect(described_class.primary_key).to eq('id') }
describe '#author' do
subject { commit_status.author }
@@ -422,29 +427,6 @@ RSpec.describe CommitStatus do
end
end
- describe '.exclude_ignored' do
- subject { described_class.exclude_ignored.order(:id) }
-
- let(:statuses) do
- [create_status(when: 'manual', status: 'skipped'),
- create_status(when: 'manual', status: 'success'),
- create_status(when: 'manual', status: 'failed'),
- create_status(when: 'on_failure', status: 'skipped'),
- create_status(when: 'on_failure', status: 'success'),
- create_status(when: 'on_failure', status: 'failed'),
- create_status(allow_failure: true, status: 'success'),
- create_status(allow_failure: true, status: 'failed'),
- create_status(allow_failure: false, status: 'success'),
- create_status(allow_failure: false, status: 'failed'),
- create_status(allow_failure: true, status: 'manual'),
- create_status(allow_failure: false, status: 'manual')]
- end
-
- it 'returns statuses without what we want to ignore' do
- is_expected.to eq(statuses.values_at(0, 1, 2, 3, 4, 5, 6, 8, 9, 11))
- end
- end
-
describe '.failed_but_allowed' do
subject { described_class.failed_but_allowed.order(:id) }
@@ -1062,4 +1044,13 @@ RSpec.describe CommitStatus do
end
end
end
+
+ describe '#failure_reason' do
+ subject(:status) { commit_status }
+
+ let(:attr) { :failure_reason }
+ let(:attr_value) { :unknown_failure }
+
+ it_behaves_like 'having enum with nil value'
+ end
end
diff --git a/spec/models/concerns/atomic_internal_id_spec.rb b/spec/models/concerns/atomic_internal_id_spec.rb
index 5fe3141eb17..625d8fec0fb 100644
--- a/spec/models/concerns/atomic_internal_id_spec.rb
+++ b/spec/models/concerns/atomic_internal_id_spec.rb
@@ -250,11 +250,104 @@ RSpec.describe AtomicInternalId do
end
end
- describe '.track_project_iid!' do
+ describe '.track_namespace_iid!' do
it 'tracks the present value' do
expect do
- ::Issue.track_project_iid!(milestone.project, external_iid)
- end.to change { InternalId.find_by(project: milestone.project, usage: :issues)&.last_value.to_i }.to(external_iid)
+ ::Issue.track_namespace_iid!(milestone.project.project_namespace, external_iid)
+ end.to change {
+ InternalId.find_by(namespace: milestone.project.project_namespace, usage: :issues)&.last_value.to_i
+ }.to(external_iid)
+ end
+ end
+
+ context 'when transitioning a model from one scope to another' do
+ let!(:issue) { build(:issue, project: project) }
+ let(:old_issue_model) do
+ Class.new(ApplicationRecord) do
+ include AtomicInternalId
+
+ self.table_name = :issues
+
+ belongs_to :project
+ belongs_to :namespace
+
+ has_internal_id :iid, scope: :project
+
+ def self.name
+ 'TestClassA'
+ end
+ end
+ end
+
+ let(:old_issue_instance) { old_issue_model.new(issue.attributes) }
+ let(:new_issue_instance) { Issue.new(issue.attributes) }
+
+ it 'generates the iid on the new scope' do
+ # set a random iid, just so that it does not start at 1
+ old_issue_instance.iid = 123
+ old_issue_instance.save!
+
+ # creating a new old_issue_instance increments the iid.
+ expect { old_issue_model.new(issue.attributes).save! }.to change {
+ InternalId.find_by(project: project, usage: :issues)&.last_value.to_i
+ }.from(123).to(124).and(not_change { InternalId.count })
+
+ # creating a new Issue creates a new record in internal_ids, scoped to the namespace.
+ # Given the Issue#has_internal_id -> init definition the internal_ids#last_value would be the
+ # maximum between the old iid value in internal_ids, scoped to the project and max(iid) value from issues
+ # table by namespace_id.
+ # see Issue#has_internal_id
+ expect { new_issue_instance.save! }.to change {
+ InternalId.find_by(namespace: project.project_namespace, usage: :issues)&.last_value.to_i
+ }.to(125).and(change { InternalId.count }.by(1))
+
+ # transition back to project scope would generate overlapping IIDs and raise a duplicate key value error, unless
+ # we cleanup the issues usage scoped to the project first
+ expect { old_issue_model.new(issue.attributes).save! }.to raise_error(ActiveRecord::RecordNotUnique)
+
+ # delete issues usage scoped to te project
+ InternalId.where(project: project, usage: :issues).delete_all
+
+ expect { old_issue_model.new(issue.attributes).save! }.to change {
+ InternalId.find_by(project: project, usage: :issues)&.last_value.to_i
+ }.to(126).and(change { InternalId.count }.by(1))
+ end
+ end
+
+ context 'when models is scoped to namespace and does not have an init proc' do
+ let!(:issue) { build(:issue, namespace: create(:group)) }
+
+ let(:issue_model) do
+ Class.new(ApplicationRecord) do
+ include AtomicInternalId
+
+ self.table_name = :issues
+
+ belongs_to :project
+ belongs_to :namespace
+
+ has_internal_id :iid, scope: :namespace
+
+ def self.name
+ 'TestClass'
+ end
+ end
+ end
+
+ let(:model_instance) { issue_model.new(issue.attributes) }
+
+ it 'generates the iid on the new scope' do
+ expect { model_instance.save! }.to change {
+ InternalId.find_by(namespace: model_instance.namespace, usage: :issues)&.last_value.to_i
+ }.to(1).and(change { InternalId.count }.by(1))
+ end
+
+ it 'supplies a stream of iid values' do
+ expect do
+ issue_model.with_namespace_iid_supply(model_instance.namespace) do |supply|
+ 4.times { supply.next_value }
+ end
+ end.to change { InternalId.find_by(namespace: model_instance.namespace, usage: :issues)&.last_value.to_i }.by(4)
end
end
end
diff --git a/spec/models/concerns/ci/maskable_spec.rb b/spec/models/concerns/ci/maskable_spec.rb
index b57b2b15608..12157867062 100644
--- a/spec/models/concerns/ci/maskable_spec.rb
+++ b/spec/models/concerns/ci/maskable_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Maskable, feature_category: :pipeline_authoring do
+RSpec.describe Ci::Maskable, feature_category: :pipeline_composition do
let(:variable) { build(:ci_variable) }
describe 'masked value validations' do
diff --git a/spec/models/concerns/ci/partitionable/partitioned_filter_spec.rb b/spec/models/concerns/ci/partitionable/partitioned_filter_spec.rb
deleted file mode 100644
index bb25d7d1665..00000000000
--- a/spec/models/concerns/ci/partitionable/partitioned_filter_spec.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Ci::Partitionable::PartitionedFilter, :aggregate_failures, feature_category: :continuous_integration do
- before do
- create_tables(<<~SQL)
- CREATE TABLE _test_ci_jobs_metadata (
- id serial NOT NULL,
- partition_id int NOT NULL DEFAULT 10,
- name text,
- PRIMARY KEY (id, partition_id)
- ) PARTITION BY LIST(partition_id);
-
- CREATE TABLE _test_ci_jobs_metadata_1
- PARTITION OF _test_ci_jobs_metadata
- FOR VALUES IN (10);
- SQL
- end
-
- let(:model) do
- Class.new(Ci::ApplicationRecord) do
- include Ci::Partitionable::PartitionedFilter
-
- self.primary_key = :id
- self.table_name = :_test_ci_jobs_metadata
-
- def self.name
- 'TestCiJobMetadata'
- end
- end
- end
-
- let!(:record) { model.create! }
-
- let(:where_filter) do
- /WHERE "_test_ci_jobs_metadata"."id" = #{record.id} AND "_test_ci_jobs_metadata"."partition_id" = 10/
- end
-
- describe '#save' do
- it 'uses id and partition_id' do
- record.name = 'test'
- recorder = ActiveRecord::QueryRecorder.new { record.save! }
-
- expect(recorder.log).to include(where_filter)
- expect(record.name).to eq('test')
- end
- end
-
- describe '#update' do
- it 'uses id and partition_id' do
- recorder = ActiveRecord::QueryRecorder.new { record.update!(name: 'test') }
-
- expect(recorder.log).to include(where_filter)
- expect(record.name).to eq('test')
- end
- end
-
- describe '#delete' do
- it 'uses id and partition_id' do
- recorder = ActiveRecord::QueryRecorder.new { record.delete }
-
- expect(recorder.log).to include(where_filter)
- expect(model.count).to be_zero
- end
- end
-
- describe '#destroy' do
- it 'uses id and partition_id' do
- recorder = ActiveRecord::QueryRecorder.new { record.destroy! }
-
- expect(recorder.log).to include(where_filter)
- expect(model.count).to be_zero
- end
- end
-
- def create_tables(table_sql)
- Ci::ApplicationRecord.connection.execute(table_sql)
- end
-end
diff --git a/spec/models/concerns/ci/partitionable_spec.rb b/spec/models/concerns/ci/partitionable_spec.rb
index 430ef57d493..5100f20ed25 100644
--- a/spec/models/concerns/ci/partitionable_spec.rb
+++ b/spec/models/concerns/ci/partitionable_spec.rb
@@ -52,16 +52,16 @@ RSpec.describe Ci::Partitionable do
context 'when partitioned is true' do
let(:partitioned) { true }
- it { expect(ci_model.ancestors).to include(described_class::PartitionedFilter) }
- it { expect(ci_model).to be_partitioned }
+ it { expect(ci_model.ancestors).to include(PartitionedTable) }
+ it { expect(ci_model.partitioning_strategy).to be_a(Gitlab::Database::Partitioning::CiSlidingListStrategy) }
+ it { expect(ci_model.partitioning_strategy.partitioning_key).to eq(:partition_id) }
end
context 'when partitioned is false' do
let(:partitioned) { false }
- it { expect(ci_model.ancestors).not_to include(described_class::PartitionedFilter) }
-
- it { expect(ci_model).not_to be_partitioned }
+ it { expect(ci_model.ancestors).not_to include(PartitionedTable) }
+ it { expect(ci_model).not_to respond_to(:partitioning_strategy) }
end
end
end
diff --git a/spec/models/concerns/each_batch_spec.rb b/spec/models/concerns/each_batch_spec.rb
index 2c75d4d5c41..75c5cac899b 100644
--- a/spec/models/concerns/each_batch_spec.rb
+++ b/spec/models/concerns/each_batch_spec.rb
@@ -171,4 +171,36 @@ RSpec.describe EachBatch do
end
end
end
+
+ describe '.each_batch_count' do
+ let_it_be(:users) { create_list(:user, 5, updated_at: 1.day.ago) }
+
+ it 'counts the records' do
+ count, last_value = User.each_batch_count
+
+ expect(count).to eq(5)
+ expect(last_value).to eq(nil)
+ end
+
+ context 'when using a different column' do
+ it 'returns correct count' do
+ count, _ = User.each_batch_count(column: :email, of: 2)
+
+ expect(count).to eq(5)
+ end
+ end
+
+ context 'when stopping and resuming the counting' do
+ it 'returns the correct count' do
+ count, last_value = User.each_batch_count(of: 1) do |current_count, _current_value|
+ current_count == 3 # stop when count reaches 3
+ end
+
+ expect(count).to eq(3)
+
+ final_count, _ = User.each_batch_count(of: 1, last_value: last_value, last_count: count)
+ expect(final_count).to eq(5)
+ end
+ end
+ end
end
diff --git a/spec/models/concerns/has_user_type_spec.rb b/spec/models/concerns/has_user_type_spec.rb
index bd128112113..03d2c267098 100644
--- a/spec/models/concerns/has_user_type_spec.rb
+++ b/spec/models/concerns/has_user_type_spec.rb
@@ -2,11 +2,11 @@
require 'spec_helper'
-RSpec.describe User do
+RSpec.describe User, feature_category: :system_access do
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 visual_review_bot
- migration_bot automation_bot admin_bot suggested_reviewers_bot])
+ migration_bot automation_bot security_policy_bot admin_bot suggested_reviewers_bot service_account])
expect(described_class::USER_TYPES).to include(*described_class::BOT_USER_TYPES)
expect(described_class::USER_TYPES).to include(*described_class::NON_INTERNAL_USER_TYPES)
expect(described_class::USER_TYPES).to include(*described_class::INTERNAL_USER_TYPES)
diff --git a/spec/models/concerns/redis_cacheable_spec.rb b/spec/models/concerns/redis_cacheable_spec.rb
index c270f23defb..bf277b094ea 100644
--- a/spec/models/concerns/redis_cacheable_spec.rb
+++ b/spec/models/concerns/redis_cacheable_spec.rb
@@ -50,6 +50,58 @@ RSpec.describe RedisCacheable do
subject
end
+
+ context 'with existing cached attributes' do
+ before do
+ instance.cache_attributes({ existing_attr: 'value' })
+ end
+
+ it 'sets the cache attributes' do
+ Gitlab::Redis::Cache.with do |redis|
+ expect(redis).to receive(:set).with(cache_key, payload.to_json, anything).and_call_original
+ end
+
+ expect { subject }.to change { instance.cached_attribute(:existing_attr) }.from('value').to(nil)
+ end
+ end
+ end
+
+ describe '#merge_cache_attributes' do
+ subject { instance.merge_cache_attributes(payload) }
+
+ let(:existing_attributes) { { existing_attr: 'value', name: 'value' } }
+
+ before do
+ instance.cache_attributes(existing_attributes)
+ end
+
+ context 'with different attribute values' do
+ let(:payload) { { name: 'new_value' } }
+
+ it 'merges the cache attributes with existing values' do
+ Gitlab::Redis::Cache.with do |redis|
+ expect(redis).to receive(:set).with(cache_key, existing_attributes.merge(payload).to_json, anything)
+ .and_call_original
+ end
+
+ subject
+
+ expect(instance.cached_attribute(:existing_attr)).to eq 'value'
+ expect(instance.cached_attribute(:name)).to eq 'new_value'
+ end
+ end
+
+ context 'with no new or changed attribute values' do
+ let(:payload) { { name: 'value' } }
+
+ it 'does not try to set Redis key' do
+ Gitlab::Redis::Cache.with do |redis|
+ expect(redis).not_to receive(:set)
+ end
+
+ subject
+ end
+ end
end
describe '#cached_attr_reader', :clean_gitlab_redis_cache do
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index dc1002f3560..0bbe3dea812 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -74,6 +74,17 @@ RSpec.shared_examples 'routable resource with parent' do
describe '#full_name' do
it { expect(record.full_name).to eq "#{record.parent.human_name} / #{record.name}" }
+ context 'without route name' do
+ before do
+ stub_feature_flags(cached_route_lookups: true)
+ record.route.update_attribute(:name, nil)
+ end
+
+ it 'builds full name' do
+ expect(record.full_name).to eq("#{record.parent.human_name} / #{record.name}")
+ end
+ end
+
it 'hits the cache when not preloaded' do
forcibly_hit_cached_lookup(record, :full_name)
diff --git a/spec/models/concerns/subscribable_spec.rb b/spec/models/concerns/subscribable_spec.rb
index a60a0a5e26d..80060802de8 100644
--- a/spec/models/concerns/subscribable_spec.rb
+++ b/spec/models/concerns/subscribable_spec.rb
@@ -215,5 +215,31 @@ RSpec.describe Subscribable, 'Subscribable' do
expect(lazy_queries.count).to eq(0)
expect(preloaded_queries.count).to eq(1)
end
+
+ context 'with work items' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:work_item) { create(:work_item, :task, project: project) }
+ let_it_be(:issue) { create(:issue, project: project) }
+
+ before do
+ [issue, work_item].each do |item|
+ create(:subscription, user: user, subscribable: item, subscribed: true, project: project)
+ end
+ end
+
+ it 'loads correct subscribable type' do
+ expect(issue).to receive(:subscribable_type).and_return('Issue')
+ issue.lazy_subscription(user, project)
+
+ expect(work_item).to receive(:subscribable_type).and_return('Issue')
+ work_item.lazy_subscription(user, project)
+ end
+
+ it 'matches existing subscription type' do
+ expect(issue.subscribed?(user, project)).to eq(true)
+ expect(work_item.subscribed?(user, project)).to eq(true)
+ end
+ end
end
end
diff --git a/spec/models/concerns/token_authenticatable_strategies/base_spec.rb b/spec/models/concerns/token_authenticatable_strategies/base_spec.rb
index 89ddc797a9d..2679bd7d93b 100644
--- a/spec/models/concerns/token_authenticatable_strategies/base_spec.rb
+++ b/spec/models/concerns/token_authenticatable_strategies/base_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TokenAuthenticatableStrategies::Base do
+RSpec.describe TokenAuthenticatableStrategies::Base, feature_category: :system_access do
let(:instance) { double(:instance) }
let(:field) { double(:field) }
@@ -24,6 +24,41 @@ RSpec.describe TokenAuthenticatableStrategies::Base do
end
end
+ describe '#format_token' do
+ let(:strategy) { described_class.new(instance, field, options) }
+
+ let(:instance) { build(:ci_build, name: 'build_name_for_format_option', partition_id: partition_id) }
+ let(:partition_id) { 100 }
+ let(:field) { 'token' }
+ let(:options) { {} }
+
+ let(:token) { 'a_secret_token' }
+
+ it 'returns the origin token' do
+ expect(strategy.format_token(instance, token)).to eq(token)
+ end
+
+ context 'when format_with_prefix option is provided' do
+ context 'with symbol' do
+ let(:options) { { format_with_prefix: :partition_id_prefix_in_16_bit_encode } }
+ let(:partition_id_in_16_bit_encode_with_underscore) { "#{partition_id.to_s(16)}_" }
+ let(:formatted_token) { "#{partition_id_in_16_bit_encode_with_underscore}#{token}" }
+
+ it 'returns a formatted token from the format_with_prefix option' do
+ expect(strategy.format_token(instance, token)).to eq(formatted_token)
+ end
+ end
+
+ context 'with something else' do
+ let(:options) { { format_with_prefix: false } }
+
+ it 'raise not implemented' do
+ expect { strategy.format_token(instance, token) }.to raise_error(NotImplementedError)
+ end
+ end
+ end
+ end
+
describe '.fabricate' do
context 'when digest stragegy is specified' do
it 'fabricates digest strategy object' do
diff --git a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
index 2df86804f34..3bdb0647d62 100644
--- a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
+++ b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb
@@ -2,16 +2,20 @@
require 'spec_helper'
-RSpec.describe TokenAuthenticatableStrategies::Encrypted do
+RSpec.describe TokenAuthenticatableStrategies::Encrypted, feature_category: :system_access do
let(:model) { double(:model) }
let(:instance) { double(:instance) }
+ let(:original_token) { 'my-value' }
+ let(:resource) { double(:resource) }
+ let(:options) { other_options.merge(encrypted: encrypted_option) }
+ let(:other_options) { {} }
let(:encrypted) do
- TokenAuthenticatableStrategies::EncryptionHelper.encrypt_token('my-value')
+ TokenAuthenticatableStrategies::EncryptionHelper.encrypt_token(original_token)
end
let(:encrypted_with_static_iv) do
- Gitlab::CryptoHelper.aes256_gcm_encrypt('my-value')
+ Gitlab::CryptoHelper.aes256_gcm_encrypt(original_token)
end
subject(:strategy) do
@@ -19,7 +23,7 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
end
describe '#token_fields' do
- let(:options) { { encrypted: :required } }
+ let(:encrypted_option) { :required }
it 'includes the encrypted field' do
expect(strategy.token_fields).to contain_exactly('some_field', 'some_field_encrypted')
@@ -27,50 +31,70 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
end
describe '#find_token_authenticatable' do
+ shared_examples 'finds the resource' do
+ it 'finds the resource by cleartext' do
+ expect(subject.find_token_authenticatable(original_token))
+ .to eq(resource)
+ end
+ end
+
+ shared_examples 'does not find any resource' do
+ it 'does not find any resource by cleartext' do
+ expect(subject.find_token_authenticatable(original_token))
+ .to be_nil
+ end
+ end
+
+ shared_examples 'finds the resource with/without setting require_prefix_for_validation' do
+ let(:standard_runner_token_prefix) { 'GR1348941' }
+ it_behaves_like 'finds the resource'
+
+ context 'when a require_prefix_for_validation is provided' do
+ let(:other_options) { { format_with_prefix: :format_with_prefix_method, require_prefix_for_validation: true } }
+
+ before do
+ allow(resource).to receive(:format_with_prefix_method).and_return(standard_runner_token_prefix)
+ end
+
+ it_behaves_like 'does not find any resource'
+
+ context 'when token starts with prefix' do
+ let(:original_token) { "#{standard_runner_token_prefix}plain_token" }
+
+ it_behaves_like 'finds the resource'
+ end
+ end
+ end
+
context 'when encryption is required' do
- let(:options) { { encrypted: :required } }
+ let(:encrypted_option) { :required }
+ let(:resource) { double(:encrypted_resource) }
- it 'finds the encrypted resource by cleartext' do
+ before do
allow(model).to receive(:where)
.and_return(model)
allow(model).to receive(:find_by)
.with('some_field_encrypted' => [encrypted, encrypted_with_static_iv])
- .and_return('encrypted resource')
-
- expect(subject.find_token_authenticatable('my-value'))
- .to eq 'encrypted resource'
+ .and_return(resource)
end
- context 'when a prefix is required' do
- let(:options) { { encrypted: :required, prefix: 'GR1348941' } }
-
- it 'finds the encrypted resource by cleartext' do
- allow(model).to receive(:where)
- .and_return(model)
- allow(model).to receive(:find_by)
- .with('some_field_encrypted' => [encrypted, encrypted_with_static_iv])
- .and_return('encrypted resource')
-
- expect(subject.find_token_authenticatable('my-value'))
- .to be_nil
- end
- end
+ it_behaves_like 'finds the resource with/without setting require_prefix_for_validation'
end
context 'when encryption is optional' do
- let(:options) { { encrypted: :optional } }
+ let(:encrypted_option) { :optional }
+ let(:resource) { double(:encrypted_resource) }
- it 'finds the encrypted resource by cleartext' do
+ before do
allow(model).to receive(:where)
.and_return(model)
allow(model).to receive(:find_by)
.with('some_field_encrypted' => [encrypted, encrypted_with_static_iv])
- .and_return('encrypted resource')
-
- expect(subject.find_token_authenticatable('my-value'))
- .to eq 'encrypted resource'
+ .and_return(resource)
end
+ it_behaves_like 'finds the resource with/without setting require_prefix_for_validation'
+
it 'uses insecure strategy when encrypted token cannot be found' do
allow(subject.send(:insecure_strategy))
.to receive(:find_token_authenticatable)
@@ -85,68 +109,27 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
expect(subject.find_token_authenticatable('my-value'))
.to eq 'plaintext resource'
end
-
- context 'when a prefix is required' do
- let(:options) { { encrypted: :optional, prefix: 'GR1348941' } }
-
- it 'finds the encrypted resource by cleartext' do
- allow(model).to receive(:where)
- .and_return(model)
- allow(model).to receive(:find_by)
- .with('some_field_encrypted' => [encrypted, encrypted_with_static_iv])
- .and_return('encrypted resource')
-
- expect(subject.find_token_authenticatable('my-value'))
- .to be_nil
- end
- end
end
context 'when encryption is migrating' do
- let(:options) { { encrypted: :migrating } }
+ let(:encrypted_option) { :migrating }
+ let(:resource) { double(:cleartext_resource) }
- it 'finds the cleartext resource by cleartext' do
+ before do
allow(model).to receive(:where)
.and_return(model)
allow(model).to receive(:find_by)
- .with('some_field' => 'my-value')
- .and_return('cleartext resource')
-
- expect(subject.find_token_authenticatable('my-value'))
- .to eq 'cleartext resource'
+ .with('some_field' => original_token)
+ .and_return(resource)
end
- it 'returns nil if resource cannot be found' do
- allow(model).to receive(:where)
- .and_return(model)
- allow(model).to receive(:find_by)
- .with('some_field' => 'my-value')
- .and_return(nil)
-
- expect(subject.find_token_authenticatable('my-value'))
- .to be_nil
- end
-
- context 'when a prefix is required' do
- let(:options) { { encrypted: :migrating, prefix: 'GR1348941' } }
-
- it 'finds the encrypted resource by cleartext' do
- allow(model).to receive(:where)
- .and_return(model)
- allow(model).to receive(:find_by)
- .with('some_field' => 'my-value')
- .and_return('cleartext resource')
-
- expect(subject.find_token_authenticatable('my-value'))
- .to be_nil
- end
- end
+ it_behaves_like 'finds the resource with/without setting require_prefix_for_validation'
end
end
describe '#get_token' do
context 'when encryption is required' do
- let(:options) { { encrypted: :required } }
+ let(:encrypted_option) { :required }
it 'returns decrypted token when an encrypted with static iv token is present' do
allow(instance).to receive(:read_attribute)
@@ -166,7 +149,7 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
end
context 'when encryption is optional' do
- let(:options) { { encrypted: :optional } }
+ let(:encrypted_option) { :optional }
it 'returns decrypted token when an encrypted token is present' do
allow(instance).to receive(:read_attribute)
@@ -198,7 +181,7 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
end
context 'when encryption is migrating' do
- let(:options) { { encrypted: :migrating } }
+ let(:encrypted_option) { :migrating }
it 'returns cleartext token when an encrypted token is present' do
allow(instance).to receive(:read_attribute)
@@ -228,7 +211,7 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
describe '#set_token' do
context 'when encryption is required' do
- let(:options) { { encrypted: :required } }
+ let(:encrypted_option) { :required }
it 'writes encrypted token and returns it' do
expect(instance).to receive(:[]=)
@@ -239,7 +222,7 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
end
context 'when encryption is optional' do
- let(:options) { { encrypted: :optional } }
+ let(:encrypted_option) { :optional }
it 'writes encrypted token and removes plaintext token and returns it' do
expect(instance).to receive(:[]=)
@@ -252,7 +235,7 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do
end
context 'when encryption is migrating' do
- let(:options) { { encrypted: :migrating } }
+ let(:encrypted_option) { :migrating }
it 'writes encrypted token and writes plaintext token' do
expect(instance).to receive(:[]=)
diff --git a/spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb b/spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb
index 671e51e3913..004298bbdd9 100644
--- a/spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb
+++ b/spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb
@@ -6,96 +6,26 @@ RSpec.describe TokenAuthenticatableStrategies::EncryptionHelper do
let(:encrypted_token) { described_class.encrypt_token('my-value-my-value-my-value') }
describe '.encrypt_token' do
- context 'when dynamic_nonce feature flag is switched on' do
- it 'adds nonce identifier on the beginning' do
- expect(encrypted_token.first).to eq(described_class::DYNAMIC_NONCE_IDENTIFIER)
- end
-
- it 'adds nonce at the end' do
- nonce = encrypted_token.last(described_class::NONCE_SIZE)
-
- expect(nonce).to eq(::Digest::SHA256.hexdigest('my-value-my-value-my-value').bytes.take(described_class::NONCE_SIZE).pack('c*'))
- end
-
- it 'encrypts token' do
- expect(encrypted_token[1...-described_class::NONCE_SIZE]).not_to eq('my-value-my-value-my-value')
- end
+ it 'adds nonce identifier on the beginning' do
+ expect(encrypted_token.first).to eq(described_class::DYNAMIC_NONCE_IDENTIFIER)
end
- context 'when dynamic_nonce feature flag is switched off' do
- before do
- stub_feature_flags(dynamic_nonce: false)
- end
-
- it 'does not add nonce identifier on the beginning' do
- expect(encrypted_token.first).not_to eq(described_class::DYNAMIC_NONCE_IDENTIFIER)
- end
-
- it 'does not add nonce in the end' do
- nonce = encrypted_token.last(described_class::NONCE_SIZE)
-
- expect(nonce).not_to eq(::Digest::SHA256.hexdigest('my-value-my-value-my-value').bytes.take(described_class::NONCE_SIZE).pack('c*'))
- end
+ it 'adds nonce at the end' do
+ nonce = encrypted_token.last(described_class::NONCE_SIZE)
- it 'encrypts token with static iv' do
- token = Gitlab::CryptoHelper.aes256_gcm_encrypt('my-value-my-value-my-value')
+ expect(nonce).to eq(::Digest::SHA256.hexdigest('my-value-my-value-my-value').bytes.take(described_class::NONCE_SIZE).pack('c*'))
+ end
- expect(encrypted_token).to eq(token)
- end
+ it 'encrypts token' do
+ expect(encrypted_token[1...-described_class::NONCE_SIZE]).not_to eq('my-value-my-value-my-value')
end
end
describe '.decrypt_token' do
- context 'with feature flag switched off' do
- before do
- stub_feature_flags(dynamic_nonce: false)
- end
-
- it 'decrypts token with static iv' do
- encrypted_token = described_class.encrypt_token('my-value')
-
- expect(described_class.decrypt_token(encrypted_token)).to eq('my-value')
- end
-
- it 'decrypts token if feature flag changed after encryption' do
- encrypted_token = described_class.encrypt_token('my-value')
-
- expect(encrypted_token).not_to eq('my-value')
-
- stub_feature_flags(dynamic_nonce: true)
-
- expect(described_class.decrypt_token(encrypted_token)).to eq('my-value')
- end
-
- it 'decrypts token with dynamic iv' do
- iv = ::Digest::SHA256.hexdigest('my-value').bytes.take(described_class::NONCE_SIZE).pack('c*')
- token = Gitlab::CryptoHelper.aes256_gcm_encrypt('my-value', nonce: iv)
- encrypted_token = "#{described_class::DYNAMIC_NONCE_IDENTIFIER}#{token}#{iv}"
-
- expect(described_class.decrypt_token(encrypted_token)).to eq('my-value')
- end
- end
-
- context 'with feature flag switched on' do
- before do
- stub_feature_flags(dynamic_nonce: true)
- end
-
- it 'decrypts token with dynamic iv' do
- encrypted_token = described_class.encrypt_token('my-value')
-
- expect(described_class.decrypt_token(encrypted_token)).to eq('my-value')
- end
-
- it 'decrypts token if feature flag changed after encryption' do
- encrypted_token = described_class.encrypt_token('my-value')
-
- expect(encrypted_token).not_to eq('my-value')
-
- stub_feature_flags(dynamic_nonce: false)
+ it 'decrypts token with dynamic iv' do
+ encrypted_token = described_class.encrypt_token('my-value')
- expect(described_class.decrypt_token(encrypted_token)).to eq('my-value')
- end
+ expect(described_class.decrypt_token(encrypted_token)).to eq('my-value')
end
end
end
diff --git a/spec/models/concerns/uniquify_spec.rb b/spec/models/concerns/uniquify_spec.rb
deleted file mode 100644
index 9b79e4d4154..00000000000
--- a/spec/models/concerns/uniquify_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Uniquify do
- let(:uniquify) { described_class.new }
-
- describe "#string" do
- it 'returns the given string if it does not exist' do
- result = uniquify.string('test_string') { |s| false }
-
- expect(result).to eq('test_string')
- end
-
- it 'returns the given string with a counter attached if the string exists' do
- result = uniquify.string('test_string') { |s| s == 'test_string' }
-
- expect(result).to eq('test_string1')
- end
-
- it 'increments the counter for each candidate string that also exists' do
- result = uniquify.string('test_string') { |s| s == 'test_string' || s == 'test_string1' }
-
- expect(result).to eq('test_string2')
- end
-
- it 'allows to pass an initial value for the counter' do
- start_counting_from = 2
- uniquify = described_class.new(start_counting_from)
-
- result = uniquify.string('test_string') { |s| s == 'test_string' }
-
- expect(result).to eq('test_string2')
- end
-
- it 'allows passing in a base function that defines the location of the counter' do
- result = uniquify.string(-> (counter) { "test_#{counter}_string" }) do |s|
- s == 'test__string'
- end
-
- expect(result).to eq('test_1_string')
- end
- end
-end
diff --git a/spec/models/concerns/web_hooks/has_web_hooks_spec.rb b/spec/models/concerns/web_hooks/has_web_hooks_spec.rb
new file mode 100644
index 00000000000..afb2406a969
--- /dev/null
+++ b/spec/models/concerns/web_hooks/has_web_hooks_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WebHooks::HasWebHooks, feature_category: :integrations do
+ let(:minimal_test_class) do
+ Class.new do
+ include WebHooks::HasWebHooks
+
+ def id
+ 1
+ end
+ end
+ end
+
+ before do
+ stub_const('MinimalTestClass', minimal_test_class)
+ end
+
+ describe '#last_failure_redis_key' do
+ subject { MinimalTestClass.new.last_failure_redis_key }
+
+ it { is_expected.to eq('web_hooks:last_failure:minimal_test_class-1') }
+ end
+
+ describe 'last_webhook_failure', :clean_gitlab_redis_shared_state do
+ subject { MinimalTestClass.new.last_webhook_failure }
+
+ it { is_expected.to eq(nil) }
+
+ context 'when there was an older failure', :clean_gitlab_redis_shared_state do
+ let(:last_failure_date) { 1.month.ago.iso8601 }
+
+ before do
+ Gitlab::Redis::SharedState.with { |r| r.set('web_hooks:last_failure:minimal_test_class-1', last_failure_date) }
+ end
+
+ it { is_expected.to eq(last_failure_date) }
+ end
+ end
+end
diff --git a/spec/models/container_registry/data_repair_detail_spec.rb b/spec/models/container_registry/data_repair_detail_spec.rb
new file mode 100644
index 00000000000..92833553a1e
--- /dev/null
+++ b/spec/models/container_registry/data_repair_detail_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ContainerRegistry::DataRepairDetail, type: :model, feature_category: :container_registry do
+ let_it_be(:project) { create(:project) }
+
+ subject { described_class.new(project: project) }
+
+ it { is_expected.to belong_to(:project).required }
+end
diff --git a/spec/models/container_registry/event_spec.rb b/spec/models/container_registry/event_spec.rb
index 07ac35f7b6a..edec5afaddb 100644
--- a/spec/models/container_registry/event_spec.rb
+++ b/spec/models/container_registry/event_spec.rb
@@ -225,6 +225,28 @@ RSpec.describe ContainerRegistry::Event do
end
end
+ context 'when it is a manifest delete event' do
+ let(:raw_event) { { 'action' => 'delete', 'target' => { 'digest' => 'x' }, 'actor' => {} } }
+
+ it 'calls the ContainerRegistryEventCounter' do
+ expect(::Gitlab::UsageDataCounters::ContainerRegistryEventCounter)
+ .to receive(:count).with('i_container_registry_delete_manifest')
+
+ subject
+ end
+ end
+
+ context 'when it is not a manifest delete event' do
+ let(:raw_event) { { 'action' => 'push', 'target' => { 'digest' => 'x' }, 'actor' => {} } }
+
+ it 'does not call the ContainerRegistryEventCounter' do
+ expect(::Gitlab::UsageDataCounters::ContainerRegistryEventCounter)
+ .not_to receive(:count).with('i_container_registry_delete_manifest')
+
+ subject
+ end
+ end
+
context 'without an actor name' do
let(:raw_event) { { 'action' => 'push', 'target' => {}, 'actor' => { 'user_type' => 'personal_access_token' } } }
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index da7b54644bd..e028a82ff76 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -528,6 +528,10 @@ RSpec.describe ContainerRepository, :aggregate_failures, feature_category: :cont
describe '#each_tags_page' do
let(:page_size) { 100 }
+ before do
+ allow(repository).to receive(:migrated?).and_return(true)
+ end
+
shared_examples 'iterating through a page' do |expected_tags: true|
it 'iterates through one page' do
expect(repository.gitlab_api_client).to receive(:tags)
@@ -660,7 +664,7 @@ RSpec.describe ContainerRepository, :aggregate_failures, feature_category: :cont
context 'calling on a non migrated repository' do
before do
- repository.update!(created_at: described_class::MIGRATION_PHASE_1_ENDED_AT - 3.days)
+ allow(repository).to receive(:migrated?).and_return(false)
end
it 'raises an Argument error' do
@@ -795,6 +799,7 @@ RSpec.describe ContainerRepository, :aggregate_failures, feature_category: :cont
freeze_time do
expect { subject }
.to change { repository.expiration_policy_started_at }.from(nil).to(Time.zone.now)
+ .and change { repository.expiration_policy_cleanup_status }.from('cleanup_unscheduled').to('cleanup_ongoing')
.and change { repository.last_cleanup_deleted_tags_count }.from(10).to(nil)
end
end
@@ -1236,6 +1241,8 @@ RSpec.describe ContainerRepository, :aggregate_failures, feature_category: :cont
end
before do
+ allow(group).to receive(:first_project_with_container_registry_tags).and_return(nil)
+
group.parent = test_group
group.save!
end
@@ -1561,22 +1568,20 @@ RSpec.describe ContainerRepository, :aggregate_failures, feature_category: :cont
describe '#migrated?' do
subject { repository.migrated? }
- it { is_expected.to eq(true) }
-
- context 'with a created_at older than phase 1 ends' do
+ context 'on gitlab.com' do
before do
- repository.update!(created_at: described_class::MIGRATION_PHASE_1_ENDED_AT - 3.days)
+ allow(::Gitlab).to receive(:com?).and_return(true)
end
- it { is_expected.to eq(false) }
-
- context 'with migration state set to import_done' do
- before do
- repository.update!(migration_state: 'import_done')
- end
+ it { is_expected.to eq(true) }
+ end
- it { is_expected.to eq(true) }
+ context 'not on gitlab.com' do
+ before do
+ allow(::Gitlab).to receive(:com?).and_return(false)
end
+
+ it { is_expected.to eq(false) }
end
end
diff --git a/spec/models/design_management/design_spec.rb b/spec/models/design_management/design_spec.rb
index 57e0d1cad8b..cb122fa09fc 100644
--- a/spec/models/design_management/design_spec.rb
+++ b/spec/models/design_management/design_spec.rb
@@ -55,6 +55,7 @@ RSpec.describe DesignManagement::Design, feature_category: :design_management do
it { is_expected.to validate_presence_of(:issue) }
it { is_expected.to validate_presence_of(:filename) }
it { is_expected.to validate_length_of(:filename).is_at_most(255) }
+ it { is_expected.to validate_length_of(:description).is_at_most(Gitlab::Database::MAX_TEXT_SIZE_LIMIT) }
it { is_expected.to validate_uniqueness_of(:filename).scoped_to(:issue_id) }
it "validates that the extension is an image" do
@@ -512,11 +513,11 @@ RSpec.describe DesignManagement::Design, feature_category: :design_management do
end
describe '#to_reference' do
+ let(:filename) { 'homescreen.jpg' }
let(:namespace) { build(:namespace, id: non_existing_record_id, path: 'sample-namespace') }
let(:project) { build(:project, name: 'sample-project', namespace: namespace) }
- let(:group) { create(:group, name: 'Group', path: 'sample-group') }
+ let(:group) { build(:group, name: 'Group', path: 'sample-group') }
let(:issue) { build(:issue, iid: 1, project: project) }
- let(:filename) { 'homescreen.jpg' }
let(:design) { build(:design, filename: filename, issue: issue, project: project) }
context 'when nil argument' do
diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
index 26795c0ea7f..34be6ec7fa9 100644
--- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb
+++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
+RSpec.describe ErrorTracking::ProjectErrorTrackingSetting, feature_category: :error_tracking do
include ReactiveCachingHelpers
include Gitlab::Routing
@@ -93,9 +93,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
end
context 'with sentry backend' do
- before do
- subject.integrated = false
- end
+ subject { build(:project_error_tracking_setting, project: project) }
it 'does not create a new client key' do
expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count }
@@ -302,7 +300,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
it { expect(result[:issue].gitlab_commit_path).to eq(nil) }
end
- context 'when repo commit matches first release version' do
+ context 'when repo commit matches first relase version' do
let(:commit) { instance_double(Commit, id: commit_id) }
let(:repository) { instance_double(Repository, commit: commit) }
@@ -341,18 +339,19 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
describe '#update_issue' do
let(:result) { subject.update_issue(**opts) }
- let(:opts) { { issue_id: 1, params: {} } }
+ let(:issue_id) { 1 }
+ let(:opts) { { issue_id: issue_id, params: {} } }
before do
allow(subject).to receive(:sentry_client).and_return(sentry_client)
allow(sentry_client).to receive(:issue_details)
- .with({ issue_id: 1 })
+ .with({ issue_id: issue_id })
.and_return(Gitlab::ErrorTracking::DetailedError.new(project_id: sentry_project_id))
end
context 'when sentry response is successful' do
before do
- allow(sentry_client).to receive(:update_issue).with(opts).and_return(true)
+ allow(sentry_client).to receive(:update_issue).with(**opts).and_return(true)
end
it 'returns the successful response' do
@@ -362,7 +361,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
context 'when sentry raises an error' do
before do
- allow(sentry_client).to receive(:update_issue).with(opts).and_raise(StandardError)
+ allow(sentry_client).to receive(:update_issue).with(**opts).and_raise(StandardError)
end
it 'returns the successful response' do
@@ -391,7 +390,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
setting.update!(sentry_project_id: nil)
allow(sentry_client).to receive(:projects).and_return(sentry_projects)
- allow(sentry_client).to receive(:update_issue).with(opts).and_return(true)
+ allow(sentry_client).to receive(:update_issue).with(**opts).and_return(true)
end
it 'tries to backfill it from sentry API' do
@@ -419,6 +418,25 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
end
end
end
+
+ describe 'passing parameters to sentry client' do
+ include SentryClientHelpers
+
+ let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0' }
+ let(:sentry_request_url) { "#{sentry_url}/issues/#{issue_id}/" }
+ let(:token) { 'test-token' }
+ let(:sentry_client) { ErrorTracking::SentryClient.new(sentry_url, token) }
+
+ before do
+ stub_sentry_request(sentry_request_url, :put, body: true)
+
+ allow(sentry_client).to receive(:update_issue).and_call_original
+ end
+
+ it 'returns the successful response' do
+ expect(result).to eq(updated: true)
+ end
+ end
end
describe 'slugs' do
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 0a05c558d45..3134f2ba248 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -40,7 +40,19 @@ RSpec.describe Group, feature_category: :subgroups do
it { is_expected.to have_many(:debian_distributions).class_name('Packages::Debian::GroupDistribution').dependent(:destroy) }
it { is_expected.to have_many(:daily_build_group_report_results).class_name('Ci::DailyBuildGroupReportResult') }
it { is_expected.to have_many(:group_callouts).class_name('Users::GroupCallout').with_foreign_key(:group_id) }
+
+ it do
+ is_expected.to have_many(:application_setting)
+ .with_foreign_key(:instance_administrators_group_id).inverse_of(:instance_group)
+ end
+
it { is_expected.to have_many(:bulk_import_exports).class_name('BulkImports::Export') }
+
+ it do
+ is_expected.to have_many(:bulk_import_entities).class_name('BulkImports::Entity')
+ .with_foreign_key(:namespace_id).inverse_of(:group)
+ end
+
it { is_expected.to have_many(:contacts).class_name('CustomerRelations::Contact') }
it { is_expected.to have_many(:organizations).class_name('CustomerRelations::Organization') }
it { is_expected.to have_many(:protected_branches).inverse_of(:group).with_foreign_key(:namespace_id) }
@@ -448,6 +460,8 @@ RSpec.describe Group, feature_category: :subgroups do
it_behaves_like 'a BulkUsersByEmailLoad model'
+ it_behaves_like 'ensures runners_token is prefixed', :group
+
context 'after initialized' do
it 'has a group_feature' do
expect(described_class.new.group_feature).to be_present
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 72958a54e10..8fd76d2a835 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -318,7 +318,7 @@ RSpec.describe WebHook, feature_category: :integrations do
end
it 'is 10 minutes' do
- expect(hook.next_backoff).to eq(described_class::INITIAL_BACKOFF)
+ expect(hook.next_backoff).to eq(WebHooks::AutoDisabling::INITIAL_BACKOFF)
end
end
@@ -328,7 +328,7 @@ RSpec.describe WebHook, feature_category: :integrations do
end
it 'is twice the initial value' do
- expect(hook.next_backoff).to eq(2 * described_class::INITIAL_BACKOFF)
+ expect(hook.next_backoff).to eq(2 * WebHooks::AutoDisabling::INITIAL_BACKOFF)
end
end
@@ -338,7 +338,7 @@ RSpec.describe WebHook, feature_category: :integrations do
end
it 'grows exponentially' do
- expect(hook.next_backoff).to eq(2 * 2 * 2 * described_class::INITIAL_BACKOFF)
+ expect(hook.next_backoff).to eq(2 * 2 * 2 * WebHooks::AutoDisabling::INITIAL_BACKOFF)
end
end
@@ -348,7 +348,7 @@ RSpec.describe WebHook, feature_category: :integrations do
end
it 'does not exceed the max backoff value' do
- expect(hook.next_backoff).to eq(described_class::MAX_BACKOFF)
+ expect(hook.next_backoff).to eq(WebHooks::AutoDisabling::MAX_BACKOFF)
end
end
end
@@ -470,13 +470,13 @@ RSpec.describe WebHook, feature_category: :integrations do
end
it 'reduces to MAX_FAILURES' do
- expect { hook.backoff! }.to change(hook, :recent_failures).to(described_class::MAX_FAILURES)
+ expect { hook.backoff! }.to change(hook, :recent_failures).to(WebHooks::AutoDisabling::MAX_FAILURES)
end
end
context 'when the recent failure value is MAX_FAILURES' do
before do
- hook.update!(recent_failures: described_class::MAX_FAILURES, disabled_until: 1.hour.ago)
+ hook.update!(recent_failures: WebHooks::AutoDisabling::MAX_FAILURES, disabled_until: 1.hour.ago)
end
it 'does not change recent_failures' do
@@ -486,7 +486,7 @@ RSpec.describe WebHook, feature_category: :integrations do
context 'when we have exhausted the grace period' do
before do
- hook.update!(recent_failures: described_class::FAILURE_THRESHOLD)
+ hook.update!(recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD)
end
it 'sets disabled_until to the next backoff' do
@@ -499,8 +499,8 @@ RSpec.describe WebHook, feature_category: :integrations do
context 'when we have backed off MAX_FAILURES times' do
before do
- stub_const("#{described_class}::MAX_FAILURES", 5)
- (described_class::FAILURE_THRESHOLD + 5).times { hook.backoff! }
+ stub_const("WebHooks::AutoDisabling::MAX_FAILURES", 5)
+ (WebHooks::AutoDisabling::FAILURE_THRESHOLD + 5).times { hook.backoff! }
end
it 'does not let the backoff count exceed the maximum failure count' do
@@ -516,7 +516,7 @@ RSpec.describe WebHook, feature_category: :integrations do
it 'changes disabled_until when it has elapsed', :skip_freeze_time do
travel_to(hook.disabled_until + 1.minute) do
expect { hook.backoff! }.to change { hook.disabled_until }
- expect(hook.backoff_count).to eq(described_class::MAX_FAILURES)
+ expect(hook.backoff_count).to eq(WebHooks::AutoDisabling::MAX_FAILURES)
end
end
end
@@ -539,7 +539,7 @@ RSpec.describe WebHook, feature_category: :integrations do
end
it 'does not update the hook if the the failure count exceeds the maximum value' do
- hook.recent_failures = described_class::MAX_FAILURES
+ hook.recent_failures = WebHooks::AutoDisabling::MAX_FAILURES
sql_count = ActiveRecord::QueryRecorder.new { hook.failed! }.count
diff --git a/spec/models/import_export_upload_spec.rb b/spec/models/import_export_upload_spec.rb
index e13f504b82a..9811dbf60e3 100644
--- a/spec/models/import_export_upload_spec.rb
+++ b/spec/models/import_export_upload_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe ImportExportUpload do
let(:after_commit_callbacks) { described_class._commit_callbacks.select { |cb| cb.kind == :after } }
def find_callback(callbacks, key)
- callbacks.find { |cb| cb.instance_variable_get(:@key) == key }
+ callbacks.find { |cb| cb.filter == key }
end
it 'export file is stored in after_commit callback' do
diff --git a/spec/models/import_failure_spec.rb b/spec/models/import_failure_spec.rb
index 9fee1b0ae7b..0bdcb6dde31 100644
--- a/spec/models/import_failure_spec.rb
+++ b/spec/models/import_failure_spec.rb
@@ -10,7 +10,11 @@ RSpec.describe ImportFailure do
let_it_be(:soft_failure) { create(:import_failure, :soft_failure, project: project, correlation_id_value: correlation_id) }
let_it_be(:unrelated_failure) { create(:import_failure, project: project) }
- it 'returns hard failures given a correlation ID' do
+ it 'returns failures for the given correlation ID' do
+ expect(ImportFailure.failures_by_correlation_id(correlation_id)).to match_array([hard_failure, soft_failure])
+ end
+
+ it 'returns hard failures for the given correlation ID' do
expect(ImportFailure.hard_failures_by_correlation_id(correlation_id)).to eq([hard_failure])
end
@@ -45,5 +49,15 @@ RSpec.describe ImportFailure do
it { is_expected.to validate_presence_of(:group) }
end
+
+ describe '#external_identifiers' do
+ it { is_expected.to allow_value({ note_id: 234, noteable_id: 345, noteable_type: 'MergeRequest' }).for(:external_identifiers) }
+ it { is_expected.not_to allow_value(nil).for(:external_identifiers) }
+ it { is_expected.not_to allow_value({ ids: [123] }).for(:external_identifiers) }
+
+ it 'allows up to 3 fields' do
+ is_expected.not_to allow_value({ note_id: 234, noteable_id: 345, noteable_type: 'MergeRequest', extra_attribute: 'abc' }).for(:external_identifiers)
+ end
+ end
end
end
diff --git a/spec/models/integrations/apple_app_store_spec.rb b/spec/models/integrations/apple_app_store_spec.rb
index 1a57f556895..b2a52c8aaf0 100644
--- a/spec/models/integrations/apple_app_store_spec.rb
+++ b/spec/models/integrations/apple_app_store_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe Integrations::AppleAppStore, feature_category: :mobile_devops do
it { is_expected.to validate_presence_of :app_store_issuer_id }
it { is_expected.to validate_presence_of :app_store_key_id }
it { is_expected.to validate_presence_of :app_store_private_key }
+ it { is_expected.to validate_presence_of :app_store_private_key_file_name }
it { is_expected.to allow_value('aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee').for(:app_store_issuer_id) }
it { is_expected.not_to allow_value('abcde').for(:app_store_issuer_id) }
it { is_expected.to allow_value(File.read('spec/fixtures/ssl_key.pem')).for(:app_store_private_key) }
@@ -28,8 +29,8 @@ RSpec.describe Integrations::AppleAppStore, feature_category: :mobile_devops do
describe '#fields' do
it 'returns custom fields' do
- expect(apple_app_store_integration.fields.pluck(:name)).to eq(%w[app_store_issuer_id app_store_key_id
- app_store_private_key])
+ expect(apple_app_store_integration.fields.pluck(:name)).to match_array(%w[app_store_issuer_id app_store_key_id
+ app_store_private_key app_store_private_key_file_name])
end
end
diff --git a/spec/models/integrations/campfire_spec.rb b/spec/models/integrations/campfire_spec.rb
index ae923cd38fc..38d3d89cdbf 100644
--- a/spec/models/integrations/campfire_spec.rb
+++ b/spec/models/integrations/campfire_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::Campfire do
+RSpec.describe Integrations::Campfire, feature_category: :integrations do
include StubRequests
it_behaves_like Integrations::ResetSecretFields do
@@ -88,4 +88,16 @@ RSpec.describe Integrations::Campfire do
expect(WebMock).not_to have_requested(:post, '*/room/.*/speak.json')
end
end
+
+ describe '#log_error' do
+ subject { described_class.new.log_error('error') }
+
+ it 'logs an error' do
+ expect(Gitlab::IntegrationsLogger).to receive(:error).with(
+ hash_including(integration_class: 'Integrations::Campfire', message: 'error')
+ ).and_call_original
+
+ is_expected.to be_truthy
+ end
+ end
end
diff --git a/spec/models/integrations/google_play_spec.rb b/spec/models/integrations/google_play_spec.rb
new file mode 100644
index 00000000000..ab1aaad24e7
--- /dev/null
+++ b/spec/models/integrations/google_play_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Integrations::GooglePlay, feature_category: :mobile_devops do
+ describe 'Validations' do
+ context 'when active' do
+ before do
+ subject.active = true
+ end
+
+ it { is_expected.to validate_presence_of :service_account_key_file_name }
+ it { is_expected.to validate_presence_of :service_account_key }
+ it { is_expected.to allow_value(File.read('spec/fixtures/service_account.json')).for(:service_account_key) }
+ it { is_expected.not_to allow_value(File.read('spec/fixtures/group.json')).for(:service_account_key) }
+ end
+ end
+
+ context 'when integration is enabled' do
+ let(:google_play_integration) { build(:google_play_integration) }
+
+ describe '#fields' do
+ it 'returns custom fields' do
+ expect(google_play_integration.fields.pluck(:name)).to match_array(%w[service_account_key
+ service_account_key_file_name])
+ end
+ end
+
+ describe '#test' do
+ it 'returns true for a successful request' do
+ allow(Google::Auth::ServiceAccountCredentials).to receive_message_chain(:make_creds, :fetch_access_token!)
+ expect(google_play_integration.test[:success]).to be true
+ end
+
+ it 'returns false for an invalid request' do
+ allow(Google::Auth::ServiceAccountCredentials).to receive_message_chain(:make_creds,
+ :fetch_access_token!).and_raise(Signet::AuthorizationError.new('error'))
+ expect(google_play_integration.test[:success]).to be false
+ end
+ end
+
+ describe '#help' do
+ it 'renders prompt information' do
+ expect(google_play_integration.help).not_to be_empty
+ end
+ end
+
+ describe '.to_param' do
+ it 'returns the name of the integration' do
+ expect(described_class.to_param).to eq('google_play')
+ end
+ end
+
+ describe '#ci_variables' do
+ let(:google_play_integration) { build_stubbed(:google_play_integration) }
+
+ it 'returns vars when the integration is activated' do
+ ci_vars = [
+ {
+ key: 'SUPPLY_JSON_KEY_DATA',
+ value: google_play_integration.service_account_key,
+ masked: true,
+ public: false
+ }
+ ]
+
+ expect(google_play_integration.ci_variables).to match_array(ci_vars)
+ end
+ end
+ end
+
+ context 'when integration is disabled' do
+ let(:google_play_integration) { build_stubbed(:google_play_integration, active: false) }
+
+ describe '#ci_variables' do
+ it 'returns an empty array' do
+ expect(google_play_integration.ci_variables).to match_array([])
+ end
+ end
+ end
+end
diff --git a/spec/models/integrations/jira_spec.rb b/spec/models/integrations/jira_spec.rb
index a4ccae459cf..fad8768cba0 100644
--- a/spec/models/integrations/jira_spec.rb
+++ b/spec/models/integrations/jira_spec.rb
@@ -590,7 +590,6 @@ RSpec.describe Integrations::Jira do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject { close_issue }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { 'Integrations::Jira' }
let(:action) { 'perform_integrations_action' }
let(:namespace) { project.namespace }
@@ -944,7 +943,6 @@ RSpec.describe Integrations::Jira do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { 'Integrations::Jira' }
let(:action) { 'perform_integrations_action' }
let(:namespace) { project.namespace }
@@ -1095,9 +1093,7 @@ RSpec.describe Integrations::Jira do
expect(integration.web_url).to eq('')
end
- it 'includes Atlassian referrer for gitlab.com' do
- allow(Gitlab).to receive(:com?).and_return(true)
-
+ it 'includes Atlassian referrer for SaaS', :saas do
expect(integration.web_url).to eq("http://jira.test.com/path?#{described_class::ATLASSIAN_REFERRER_GITLAB_COM.to_query}")
allow(Gitlab).to receive(:staging?).and_return(true)
diff --git a/spec/models/integrations/mattermost_slash_commands_spec.rb b/spec/models/integrations/mattermost_slash_commands_spec.rb
index 070adb9ba93..e393a905f45 100644
--- a/spec/models/integrations/mattermost_slash_commands_spec.rb
+++ b/spec/models/integrations/mattermost_slash_commands_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::MattermostSlashCommands do
+RSpec.describe Integrations::MattermostSlashCommands, feature_category: :integrations do
it_behaves_like Integrations::BaseSlashCommands
describe 'Mattermost API' do
@@ -123,12 +123,5 @@ RSpec.describe Integrations::MattermostSlashCommands do
end
end
end
-
- describe '#chat_responder' do
- it 'returns the responder to use for Mattermost' do
- expect(described_class.new.chat_responder)
- .to eq(Gitlab::Chat::Responder::Mattermost)
- end
- end
end
end
diff --git a/spec/models/integrations/slack_slash_commands_spec.rb b/spec/models/integrations/slack_slash_commands_spec.rb
index 22cbaa777cd..f373fc2a2de 100644
--- a/spec/models/integrations/slack_slash_commands_spec.rb
+++ b/spec/models/integrations/slack_slash_commands_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::SlackSlashCommands do
+RSpec.describe Integrations::SlackSlashCommands, feature_category: :integrations do
it_behaves_like Integrations::BaseSlashCommands
describe '#trigger' do
@@ -40,11 +40,4 @@ RSpec.describe Integrations::SlackSlashCommands do
end
end
end
-
- describe '#chat_responder' do
- it 'returns the responder to use for Slack' do
- expect(described_class.new.chat_responder)
- .to eq(Gitlab::Chat::Responder::Slack)
- end
- end
end
diff --git a/spec/models/integrations/squash_tm_spec.rb b/spec/models/integrations/squash_tm_spec.rb
new file mode 100644
index 00000000000..f12e37dae6d
--- /dev/null
+++ b/spec/models/integrations/squash_tm_spec.rb
@@ -0,0 +1,117 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Integrations::SquashTm, feature_category: :integrations do
+ it_behaves_like Integrations::HasWebHook do
+ let_it_be(:project) { create(:project) }
+
+ let(:integration) { build(:squash_tm_integration, project: project) }
+ let(:hook_url) { "#{integration.url}?token={token}" }
+ end
+
+ it_behaves_like Integrations::ResetSecretFields do
+ let(:integration) { subject }
+ end
+
+ describe 'Validations' do
+ context 'when integration is active' do
+ before do
+ subject.active = true
+ end
+
+ it { is_expected.to validate_presence_of(:url) }
+ it { is_expected.to allow_value('https://example.com').for(:url) }
+ it { is_expected.not_to allow_value(nil).for(:url) }
+ it { is_expected.not_to allow_value('').for(:url) }
+ it { is_expected.not_to allow_value('foo').for(:url) }
+ it { is_expected.not_to allow_value('example.com').for(:url) }
+
+ it { is_expected.not_to validate_presence_of(:token) }
+ it { is_expected.to validate_length_of(:token).is_at_most(255) }
+ it { is_expected.to allow_value(nil).for(:token) }
+ it { is_expected.to allow_value('foo').for(:token) }
+ end
+
+ context 'when integration is inactive' do
+ before do
+ subject.active = false
+ end
+
+ it { is_expected.not_to validate_presence_of(:url) }
+ it { is_expected.not_to validate_presence_of(:token) }
+ end
+ end
+
+ describe '#execute' do
+ let(:integration) { build(:squash_tm_integration, project: build(:project)) }
+
+ let(:squash_tm_hook_url) do
+ "#{integration.url}?token=#{integration.token}"
+ end
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:issue) { create(:issue) }
+ let(:data) { issue.to_hook_data(user) }
+
+ before do
+ stub_request(:post, squash_tm_hook_url)
+ end
+
+ it 'calls Squash TM API' do
+ integration.execute(data)
+
+ expect(a_request(:post, squash_tm_hook_url)).to have_been_made.once
+ end
+ end
+
+ describe '#test' do
+ let(:integration) { build(:squash_tm_integration) }
+
+ let(:squash_tm_hook_url) do
+ "#{integration.url}?token=#{integration.token}"
+ end
+
+ subject(:result) { integration.test({}) }
+
+ context 'when server is responding' do
+ let(:body) { 'OK' }
+ let(:status) { 200 }
+
+ before do
+ stub_request(:post, squash_tm_hook_url)
+ .to_return(status: status, body: body)
+ end
+
+ it { is_expected.to eq(success: true, result: 'OK') }
+ end
+
+ context 'when server rejects the request' do
+ let(:body) { 'Unauthorized' }
+ let(:status) { 401 }
+
+ before do
+ stub_request(:post, squash_tm_hook_url)
+ .to_return(status: status, body: body)
+ end
+
+ it { is_expected.to eq(success: false, result: body) }
+ end
+
+ context 'when test request executes with errors' do
+ before do
+ allow(integration).to receive(:execute_web_hook!)
+ .with({}, "Test Configuration Hook")
+ .and_raise(StandardError, 'error message')
+ end
+
+ it { is_expected.to eq(success: false, result: 'error message') }
+ end
+ end
+
+ describe '.default_test_event' do
+ subject { described_class.default_test_event }
+
+ it { is_expected.to eq('issue') }
+ end
+end
diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb
index f0007e1203c..59ade8783e5 100644
--- a/spec/models/internal_id_spec.rb
+++ b/spec/models/internal_id_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe InternalId do
let(:usage) { :issues }
let(:issue) { build(:issue, project: project) }
let(:id_subject) { issue }
- let(:scope) { { project: project } }
+ let(:scope) { { namespace: project.project_namespace } }
let(:init) { ->(issue, scope) { issue&.project&.issues&.size || Issue.where(**scope).count } }
it_behaves_like 'having unique enum values'
@@ -17,7 +17,7 @@ RSpec.describe InternalId do
end
describe '.flush_records!' do
- subject { described_class.flush_records!(project: project) }
+ subject { described_class.flush_records!(namespace: project.project_namespace) }
let(:another_project) { create(:project) }
@@ -27,11 +27,11 @@ RSpec.describe InternalId do
end
it 'deletes all records for the given project' do
- expect { subject }.to change { described_class.where(project: project).count }.from(1).to(0)
+ expect { subject }.to change { described_class.where(namespace: project.project_namespace).count }.from(1).to(0)
end
it 'retains records for other projects' do
- expect { subject }.not_to change { described_class.where(project: another_project).count }
+ expect { subject }.not_to change { described_class.where(namespace: another_project.project_namespace).count }
end
it 'does not allow an empty filter' do
@@ -51,7 +51,7 @@ RSpec.describe InternalId do
subject
described_class.first.tap do |record|
- expect(record.project).to eq(project)
+ expect(record.namespace).to eq(project.project_namespace)
expect(record.usage).to eq(usage.to_s)
end
end
@@ -182,7 +182,7 @@ RSpec.describe InternalId do
subject
described_class.first.tap do |record|
- expect(record.project).to eq(project)
+ expect(record.namespace).to eq(project.project_namespace)
expect(record.usage).to eq(usage.to_s)
expect(record.last_value).to eq(value)
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index e29318a7e83..8072a60326c 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -63,13 +63,18 @@ RSpec.describe Issue, feature_category: :team_planning do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:issue) }
- let(:scope) { :project }
- let(:scope_attrs) { { project: instance.project } }
+ let(:scope) { :namespace }
+ let(:scope_attrs) { { namespace: instance.project.project_namespace } }
let(:usage) { :issues }
end
end
describe 'validations' do
+ it { is_expected.not_to allow_value(nil).for(:confidential) }
+ it { is_expected.to allow_value(true, false).for(:confidential) }
+ end
+
+ describe 'custom validations' do
subject(:valid?) { issue.valid? }
describe 'due_date_after_start_date' do
@@ -215,7 +220,7 @@ RSpec.describe Issue, feature_category: :team_planning do
subject { create(:issue, project: reusable_project) }
describe 'callbacks' do
- describe '#ensure_metrics' do
+ describe '#ensure_metrics!' do
it 'creates metrics after saving' do
expect(subject.metrics).to be_persisted
expect(Issue::Metrics.count).to eq(1)
@@ -575,38 +580,38 @@ RSpec.describe Issue, feature_category: :team_planning do
end
describe '#to_reference' do
- let(:namespace) { build(:namespace, path: 'sample-namespace') }
- let(:project) { build(:project, name: 'sample-project', namespace: namespace) }
- let(:issue) { build(:issue, iid: 1, project: project) }
+ let_it_be(:namespace) { create(:namespace, path: 'sample-namespace') }
+ let_it_be(:project) { create(:project, name: 'sample-project', namespace: namespace) }
+ let_it_be(:issue) { create(:issue, project: project) }
context 'when nil argument' do
it 'returns issue id' do
- expect(issue.to_reference).to eq "#1"
+ expect(issue.to_reference).to eq "##{issue.iid}"
end
it 'returns complete path to the issue with full: true' do
- expect(issue.to_reference(full: true)).to eq 'sample-namespace/sample-project#1'
+ expect(issue.to_reference(full: true)).to eq "#{project.full_path}##{issue.iid}"
end
end
context 'when argument is a project' do
context 'when same project' do
it 'returns issue id' do
- expect(issue.to_reference(project)).to eq("#1")
+ expect(issue.to_reference(project)).to eq("##{issue.iid}")
end
it 'returns full reference with full: true' do
- expect(issue.to_reference(project, full: true)).to eq 'sample-namespace/sample-project#1'
+ expect(issue.to_reference(project, full: true)).to eq "#{project.full_path}##{issue.iid}"
end
end
context 'when cross-project in same namespace' do
let(:another_project) do
- build(:project, name: 'another-project', namespace: project.namespace)
+ create(:project, name: 'another-project', namespace: project.namespace)
end
it 'returns a cross-project reference' do
- expect(issue.to_reference(another_project)).to eq "sample-project#1"
+ expect(issue.to_reference(another_project)).to eq "sample-project##{issue.iid}"
end
end
@@ -615,7 +620,7 @@ RSpec.describe Issue, feature_category: :team_planning do
let(:another_namespace_project) { build(:project, path: 'another-project', namespace: another_namespace) }
it 'returns complete path to the issue' do
- expect(issue.to_reference(another_namespace_project)).to eq 'sample-namespace/sample-project#1'
+ expect(issue.to_reference(another_namespace_project)).to eq "#{project.full_path}##{issue.iid}"
end
end
end
@@ -623,11 +628,11 @@ RSpec.describe Issue, feature_category: :team_planning do
context 'when argument is a namespace' do
context 'when same as issue' do
it 'returns path to the issue with the project name' do
- expect(issue.to_reference(namespace)).to eq 'sample-project#1'
+ expect(issue.to_reference(namespace)).to eq "sample-project##{issue.iid}"
end
it 'returns full reference with full: true' do
- expect(issue.to_reference(namespace, full: true)).to eq 'sample-namespace/sample-project#1'
+ expect(issue.to_reference(namespace, full: true)).to eq "#{project.full_path}##{issue.iid}"
end
end
@@ -635,12 +640,111 @@ RSpec.describe Issue, feature_category: :team_planning do
let(:group) { build(:group, name: 'Group', path: 'sample-group') }
it 'returns full path to the issue with full: true' do
- expect(issue.to_reference(group)).to eq 'sample-namespace/sample-project#1'
+ expect(issue.to_reference(group)).to eq "#{project.full_path}##{issue.iid}"
end
end
end
end
+ describe '#to_reference with table syntax' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:user_namespace) { user.namespace }
+
+ let_it_be(:parent) { create(:group) }
+ let_it_be(:group) { create(:group, parent: parent) }
+ let_it_be(:another_group) { create(:group) }
+
+ let_it_be(:project) { create(:project, namespace: group) }
+ let_it_be(:project_namespace) { project.project_namespace }
+ let_it_be(:same_namespace_project) { create(:project, namespace: group) }
+ let_it_be(:same_namespace_project_namespace) { same_namespace_project.project_namespace }
+
+ let_it_be(:another_namespace_project) { create(:project) }
+ let_it_be(:another_namespace_project_namespace) { another_namespace_project.project_namespace }
+
+ let_it_be(:project_issue) { build(:issue, project: project, iid: 123) }
+ let_it_be(:project_issue_full_reference) { "#{project.full_path}##{project_issue.iid}" }
+
+ let_it_be(:group_issue) { build(:issue, namespace: group, iid: 123) }
+ let_it_be(:group_issue_full_reference) { "#{group.full_path}##{group_issue.iid}" }
+
+ # this one is just theoretically possible, not smth to be supported for real
+ let_it_be(:user_issue) { build(:issue, namespace: user_namespace, iid: 123) }
+ let_it_be(:user_issue_full_reference) { "#{user_namespace.full_path}##{user_issue.iid}" }
+
+ # namespace would be group, project namespace or user namespace
+ where(:issue, :full, :from, :result) do
+ ref(:project_issue) | false | nil | lazy { "##{issue.iid}" }
+ ref(:project_issue) | true | nil | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:group) | lazy { "#{project.path}##{issue.iid}" }
+ ref(:project_issue) | true | ref(:group) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:parent) | ref(:project_issue_full_reference)
+ ref(:project_issue) | true | ref(:parent) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:project) | lazy { "##{issue.iid}" }
+ ref(:project_issue) | true | ref(:project) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:project_namespace) | lazy { "##{issue.iid}" }
+ ref(:project_issue) | true | ref(:project_namespace) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:same_namespace_project) | lazy { "#{project.path}##{issue.iid}" }
+ ref(:project_issue) | true | ref(:same_namespace_project) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:same_namespace_project_namespace) | lazy { "#{project.path}##{issue.iid}" }
+ ref(:project_issue) | true | ref(:same_namespace_project_namespace) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:another_group) | ref(:project_issue_full_reference)
+ ref(:project_issue) | true | ref(:another_group) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:another_namespace_project) | ref(:project_issue_full_reference)
+ ref(:project_issue) | true | ref(:another_namespace_project) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:another_namespace_project_namespace) | ref(:project_issue_full_reference)
+ ref(:project_issue) | true | ref(:another_namespace_project_namespace) | ref(:project_issue_full_reference)
+ ref(:project_issue) | false | ref(:user_namespace) | ref(:project_issue_full_reference)
+ ref(:project_issue) | true | ref(:user_namespace) | ref(:project_issue_full_reference)
+
+ ref(:group_issue) | false | nil | lazy { "##{issue.iid}" }
+ ref(:group_issue) | true | nil | ref(:group_issue_full_reference)
+ ref(:group_issue) | false | ref(:user_namespace) | ref(:group_issue_full_reference)
+ ref(:group_issue) | true | ref(:user_namespace) | ref(:group_issue_full_reference)
+ ref(:group_issue) | false | ref(:group) | lazy { "##{issue.iid}" }
+ ref(:group_issue) | true | ref(:group) | ref(:group_issue_full_reference)
+ ref(:group_issue) | false | ref(:parent) | lazy { "#{group.path}##{issue.iid}" }
+ ref(:group_issue) | true | ref(:parent) | ref(:group_issue_full_reference)
+ ref(:group_issue) | false | ref(:project) | lazy { "#{group.path}##{issue.iid}" }
+ ref(:group_issue) | true | ref(:project) | ref(:group_issue_full_reference)
+ ref(:group_issue) | false | ref(:project_namespace) | lazy { "#{group.path}##{issue.iid}" }
+ ref(:group_issue) | true | ref(:project_namespace) | ref(:group_issue_full_reference)
+ ref(:group_issue) | false | ref(:another_group) | ref(:group_issue_full_reference)
+ ref(:group_issue) | true | ref(:another_group) | ref(:group_issue_full_reference)
+ ref(:group_issue) | false | ref(:another_namespace_project) | ref(:group_issue_full_reference)
+ ref(:group_issue) | true | ref(:another_namespace_project) | ref(:group_issue_full_reference)
+ ref(:group_issue) | false | ref(:another_namespace_project_namespace) | ref(:group_issue_full_reference)
+ ref(:group_issue) | true | ref(:another_namespace_project_namespace) | ref(:group_issue_full_reference)
+
+ ref(:user_issue) | false | nil | lazy { "##{issue.iid}" }
+ ref(:user_issue) | true | nil | ref(:user_issue_full_reference)
+ ref(:user_issue) | false | ref(:user_namespace) | lazy { "##{issue.iid}" }
+ ref(:user_issue) | true | ref(:user_namespace) | ref(:user_issue_full_reference)
+ ref(:user_issue) | false | ref(:group) | ref(:user_issue_full_reference)
+ ref(:user_issue) | true | ref(:group) | ref(:user_issue_full_reference)
+ ref(:user_issue) | false | ref(:parent) | ref(:user_issue_full_reference)
+ ref(:user_issue) | true | ref(:parent) | ref(:user_issue_full_reference)
+ ref(:user_issue) | false | ref(:project) | ref(:user_issue_full_reference)
+ ref(:user_issue) | true | ref(:project) | ref(:user_issue_full_reference)
+ ref(:user_issue) | false | ref(:project_namespace) | ref(:user_issue_full_reference)
+ ref(:user_issue) | true | ref(:project_namespace) | ref(:user_issue_full_reference)
+ ref(:user_issue) | false | ref(:another_group) | ref(:user_issue_full_reference)
+ ref(:user_issue) | true | ref(:another_group) | ref(:user_issue_full_reference)
+ ref(:user_issue) | false | ref(:another_namespace_project) | ref(:user_issue_full_reference)
+ ref(:user_issue) | true | ref(:another_namespace_project) | ref(:user_issue_full_reference)
+ ref(:user_issue) | false | ref(:another_namespace_project_namespace) | ref(:user_issue_full_reference)
+ ref(:user_issue) | true | ref(:another_namespace_project_namespace) | ref(:user_issue_full_reference)
+ end
+
+ with_them do
+ it 'returns correct reference' do
+ expect(issue.to_reference(from, full: full)).to eq(result)
+ end
+ end
+ end
+
describe '#assignee_or_author?' do
let(:issue) { create(:issue, project: reusable_project) }
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 6a52f12553f..30607116c61 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -16,7 +16,6 @@ RSpec.describe Member, feature_category: :subgroups do
describe 'Associations' do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:member_namespace) }
- it { is_expected.to belong_to(:member_role) }
it { is_expected.to have_one(:member_task) }
end
@@ -173,96 +172,6 @@ RSpec.describe Member, feature_category: :subgroups do
end
end
end
-
- context 'member role access level' do
- let_it_be_with_reload(:member) { create(:group_member, access_level: Gitlab::Access::DEVELOPER) }
-
- context 'when no member role is associated' do
- it 'is valid' do
- expect(member).to be_valid
- end
- end
-
- context 'when member role is associated' do
- let!(:member_role) do
- create(
- :member_role,
- members: [member],
- base_access_level: Gitlab::Access::DEVELOPER,
- namespace: member.member_namespace
- )
- end
-
- context 'when member role matches access level' do
- it 'is valid' do
- expect(member).to be_valid
- end
- end
-
- context 'when member role does not match access level' do
- it 'is invalid' do
- member_role.base_access_level = Gitlab::Access::MAINTAINER
-
- expect(member).not_to be_valid
- end
- end
-
- context 'when access_level is changed' do
- it 'is invalid' do
- member.access_level = Gitlab::Access::MAINTAINER
-
- expect(member).not_to be_valid
- expect(member.errors[:access_level]).to include(
- _("cannot be changed since member is associated with a custom role")
- )
- end
- end
- end
- end
-
- context 'member role namespace' do
- let_it_be_with_reload(:member) { create(:group_member) }
-
- context 'when no member role is associated' do
- it 'is valid' do
- expect(member).to be_valid
- end
- end
-
- context 'when member role is associated' do
- let_it_be(:member_role) do
- create(:member_role, members: [member], namespace: member.group, base_access_level: member.access_level)
- end
-
- context 'when member#member_namespace is a group within hierarchy of member_role#namespace' do
- it 'is valid' do
- member.member_namespace = create(:group, parent: member_role.namespace)
-
- expect(member).to be_valid
- end
- end
-
- context 'when member#member_namespace is a project within hierarchy of member_role#namespace' do
- it 'is valid' do
- project = create(:project, group: member_role.namespace)
- member.member_namespace = Namespace.find(project.parent_id)
-
- expect(member).to be_valid
- end
- end
-
- context 'when member#member_namespace is outside hierarchy of member_role#namespace' do
- it 'is invalid' do
- member.member_namespace = create(:group)
-
- expect(member).not_to be_valid
- expect(member.errors[:member_namespace]).to include(
- _("must be in same hierarchy as custom role's namespace")
- )
- end
- end
- end
- end
end
describe 'Scopes & finders' do
@@ -774,6 +683,24 @@ RSpec.describe Member, feature_category: :subgroups do
end
end
+ describe '.filter_by_user_type' do
+ let_it_be(:service_account) { create(:user, :service_account) }
+ let_it_be(:service_account_member) { create(:group_member, user: service_account) }
+ let_it_be(:other_member) { create(:group_member) }
+
+ context 'when the user type is valid' do
+ it 'returns service accounts' do
+ expect(described_class.filter_by_user_type('service_account')).to match_array([service_account_member])
+ end
+ end
+
+ context 'when the user type is invalid' do
+ it 'returns nil' do
+ expect(described_class.filter_by_user_type('invalid_type')).to eq(nil)
+ end
+ end
+ end
+
describe '#accept_request' do
let(:member) { create(:project_member, requested_at: Time.current.utc) }
diff --git a/spec/models/members/member_role_spec.rb b/spec/models/members/member_role_spec.rb
deleted file mode 100644
index 4bf33eb1fce..00000000000
--- a/spec/models/members/member_role_spec.rb
+++ /dev/null
@@ -1,107 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe MemberRole, feature_category: :authentication_and_authorization do
- describe 'associations' do
- it { is_expected.to belong_to(:namespace) }
- it { is_expected.to have_many(:members) }
- end
-
- describe 'validation' do
- subject(:member_role) { build(:member_role) }
-
- it { is_expected.to validate_presence_of(:namespace) }
- it { is_expected.to validate_presence_of(:base_access_level) }
-
- context 'for attributes_locked_after_member_associated' do
- context 'when assigned to member' do
- it 'cannot be changed' do
- member_role.save!
- member_role.members << create(:project_member)
-
- expect(member_role).not_to be_valid
- expect(member_role.errors.messages[:base]).to include(
- s_("MemberRole|cannot be changed because it is already assigned to a user. "\
- "Please create a new Member Role instead")
- )
- end
- end
-
- context 'when not assigned to member' do
- it 'can be changed' do
- expect(member_role).to be_valid
- end
- end
- end
-
- context 'when for namespace' do
- let_it_be(:root_group) { create(:group) }
-
- context 'when namespace is a subgroup' do
- it 'is invalid' do
- subgroup = create(:group, parent: root_group)
- member_role.namespace = subgroup
-
- expect(member_role).to be_invalid
- expect(member_role.errors[:namespace]).to include(
- s_("MemberRole|must be top-level namespace")
- )
- end
- end
-
- context 'when namespace is a root group' do
- it 'is valid' do
- member_role.namespace = root_group
-
- expect(member_role).to be_valid
- end
- end
-
- context 'when namespace is not present' do
- it 'is invalid with a different error message' do
- member_role.namespace = nil
-
- expect(member_role).to be_invalid
- expect(member_role.errors[:namespace]).to include(_("can't be blank"))
- end
- end
-
- context 'when namespace is outside hierarchy of member' do
- it 'creates a validation error' do
- member_role.save!
- member_role.namespace = create(:group)
-
- expect(member_role).not_to be_valid
- expect(member_role.errors[:namespace]).to include(s_("MemberRole|can't be changed"))
- end
- end
- end
- end
-
- describe 'callbacks' do
- context 'for preventing deletion after member is associated' do
- let_it_be(:member_role) { create(:member_role) }
-
- subject(:destroy_member_role) { member_role.destroy } # rubocop: disable Rails/SaveBang
-
- it 'allows deletion without any member associated' do
- expect(destroy_member_role).to be_truthy
- end
-
- it 'prevent deletion when member is associated' do
- create(:group_member, { group: member_role.namespace,
- access_level: Gitlab::Access::DEVELOPER,
- member_role: member_role })
- member_role.members.reload
-
- expect(destroy_member_role).to be_falsey
- expect(member_role.errors.messages[:base])
- .to(
- include(s_("MemberRole|cannot be deleted because it is already assigned to a user. "\
- "Please disassociate the member role from all users before deletion."))
- )
- end
- end
- end
-end
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index f0069b89494..f2bc9b42b77 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe ProjectMember do
describe 'validations' do
it { is_expected.to allow_value('Project').for(:source_type) }
- it { is_expected.not_to allow_value('project').for(:source_type) }
+ it { is_expected.not_to allow_value('Group').for(:source_type) }
it { is_expected.to validate_inclusion_of(:access_level).in_array(Gitlab::Access.values) }
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 2e2355ba710..b82b16fdec3 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -20,6 +20,11 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
it { is_expected.to belong_to(:target_project).class_name('Project') }
it { is_expected.to belong_to(:source_project).class_name('Project') }
it { is_expected.to belong_to(:merge_user).class_name("User") }
+
+ it do
+ is_expected.to belong_to(:head_pipeline).class_name('Ci::Pipeline').inverse_of(:merge_requests_as_head_pipeline)
+ end
+
it { is_expected.to have_many(:assignees).through(:merge_request_assignees) }
it { is_expected.to have_many(:reviewers).through(:merge_request_reviewers) }
it { is_expected.to have_many(:merge_request_diffs) }
@@ -393,8 +398,8 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
instance1 = MergeRequest.find(merge_request.id)
instance2 = MergeRequest.find(merge_request.id)
- instance1.ensure_metrics
- instance2.ensure_metrics
+ instance1.ensure_metrics!
+ instance2.ensure_metrics!
metrics_records = MergeRequest::Metrics.where(merge_request_id: merge_request.id)
expect(metrics_records.size).to eq(1)
@@ -760,6 +765,23 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
end
end
+ context 'when scoped with :merged_before and :merged_after' do
+ before do
+ mr2.metrics.update!(merged_at: mr1.metrics.merged_at - 1.week)
+ mr3.metrics.update!(merged_at: mr1.metrics.merged_at + 1.week)
+ end
+
+ it 'excludes merge requests outside of the date range' do
+ expect(
+ project.merge_requests.merge(
+ MergeRequest::Metrics
+ .merged_before(mr1.metrics.merged_at + 1.day)
+ .merged_after(mr1.metrics.merged_at - 1.day)
+ ).total_time_to_merge
+ ).to be_within(1).of(expected_total_time([mr1]))
+ end
+ end
+
def expected_total_time(mrs)
mrs = mrs.reject { |mr| mr.merged_at.nil? }
mrs.reduce(0.0) do |sum, mr|
@@ -4274,8 +4296,11 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
it 'refreshes the number of open merge requests of the target project' do
project = subject.target_project
- expect { subject.destroy! }
- .to change { project.open_merge_requests_count }.from(1).to(0)
+ expect do
+ subject.destroy!
+
+ BatchLoader::Executor.clear_current
+ end.to change { project.open_merge_requests_count }.from(1).to(0)
end
end
@@ -4301,6 +4326,14 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
transition!
end
+ context 'when skip_merge_status_trigger is set to true' do
+ before do
+ subject.skip_merge_status_trigger = true
+ end
+
+ it_behaves_like 'transition not triggering mergeRequestMergeStatusUpdated GraphQL subscription'
+ end
+
context 'when transaction is not committed' do
it_behaves_like 'transition not triggering mergeRequestMergeStatusUpdated GraphQL subscription' do
def transition!
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index a0698ac30f5..89df24d75c9 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -31,7 +31,6 @@ RSpec.describe Namespace, feature_category: :subgroups do
it { is_expected.to have_many :pending_builds }
it { is_expected.to have_one :namespace_route }
it { is_expected.to have_many :namespace_members }
- it { is_expected.to have_many :member_roles }
it { is_expected.to have_one :cluster_enabled_grant }
it { is_expected.to have_many(:work_items) }
it { is_expected.to have_many :achievements }
@@ -173,15 +172,24 @@ RSpec.describe Namespace, feature_category: :subgroups do
# rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
where(:namespace_type, :path, :valid) do
- ref(:project_sti_name) | 'j' | true
- ref(:project_sti_name) | 'path.' | true
- ref(:project_sti_name) | 'blob' | false
- ref(:group_sti_name) | 'j' | false
- ref(:group_sti_name) | 'path.' | false
- ref(:group_sti_name) | 'blob' | true
- ref(:user_sti_name) | 'j' | false
- ref(:user_sti_name) | 'path.' | false
- ref(:user_sti_name) | 'blob' | true
+ ref(:project_sti_name) | 'j' | true
+ ref(:project_sti_name) | 'path.' | false
+ ref(:project_sti_name) | '.path' | false
+ ref(:project_sti_name) | 'path.git' | false
+ ref(:project_sti_name) | 'namespace__path' | false
+ ref(:project_sti_name) | 'blob' | false
+ ref(:group_sti_name) | 'j' | false
+ ref(:group_sti_name) | 'path.' | false
+ ref(:group_sti_name) | '.path' | false
+ ref(:group_sti_name) | 'path.git' | false
+ ref(:group_sti_name) | 'namespace__path' | false
+ ref(:group_sti_name) | 'blob' | true
+ ref(:user_sti_name) | 'j' | false
+ ref(:user_sti_name) | 'path.' | false
+ ref(:user_sti_name) | '.path' | false
+ ref(:user_sti_name) | 'path.git' | false
+ ref(:user_sti_name) | 'namespace__path' | false
+ ref(:user_sti_name) | 'blob' | true
end
# rubocop:enable Lint/BinaryOperatorWithIdenticalOperands
@@ -193,6 +201,26 @@ RSpec.describe Namespace, feature_category: :subgroups do
expect(namespace.valid?).to be(valid)
end
end
+
+ context 'when path starts or ends with a special character' do
+ it 'does not raise validation error for path for existing namespaces' do
+ parent.update_attribute(:path, '_path_')
+
+ expect { parent.update!(name: 'Foo') }.not_to raise_error
+ end
+ end
+
+ context 'when restrict_special_characters_in_namespace_path feature flag is disabled' do
+ before do
+ stub_feature_flags(restrict_special_characters_in_namespace_path: false)
+ end
+
+ it 'allows special character at the start or end of project namespace path' do
+ namespace = build(:namespace, type: project_sti_name, parent: parent, path: '_path_')
+
+ expect(namespace).to be_valid
+ end
+ end
end
describe '1 char path length' do
@@ -237,6 +265,117 @@ RSpec.describe Namespace, feature_category: :subgroups do
end
end
+ describe "ReferencePatternValidation" do
+ subject { described_class.reference_pattern }
+
+ it { is_expected.to match("@group1") }
+ it { is_expected.to match("@group1/group2/group3") }
+ it { is_expected.to match("@1234/1234/1234") }
+ it { is_expected.to match("@.q-w_e") }
+ end
+
+ describe '#to_reference_base' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:user_namespace) { user.namespace }
+
+ let_it_be(:parent) { create(:group) }
+ let_it_be(:group) { create(:group, parent: parent) }
+ let_it_be(:another_group) { create(:group) }
+
+ let_it_be(:project) { create(:project, namespace: group) }
+ let_it_be(:project_namespace) { project.project_namespace }
+
+ let_it_be(:another_namespace_project) { create(:project) }
+ let_it_be(:another_namespace_project_namespace) { another_namespace_project.project_namespace }
+
+ # testing references with namespace being: group, project namespace and user namespace
+ where(:namespace, :full, :from, :result) do
+ ref(:parent) | false | nil | nil
+ ref(:parent) | true | nil | lazy { parent.full_path }
+ ref(:parent) | false | ref(:group) | lazy { parent.path }
+ ref(:parent) | true | ref(:group) | lazy { parent.full_path }
+ ref(:parent) | false | ref(:parent) | nil
+ ref(:parent) | true | ref(:parent) | lazy { parent.full_path }
+ ref(:parent) | false | ref(:project) | lazy { parent.path }
+ ref(:parent) | true | ref(:project) | lazy { parent.full_path }
+ ref(:parent) | false | ref(:project_namespace) | lazy { parent.path }
+ ref(:parent) | true | ref(:project_namespace) | lazy { parent.full_path }
+ ref(:parent) | false | ref(:another_group) | lazy { parent.full_path }
+ ref(:parent) | true | ref(:another_group) | lazy { parent.full_path }
+ ref(:parent) | false | ref(:another_namespace_project) | lazy { parent.full_path }
+ ref(:parent) | true | ref(:another_namespace_project) | lazy { parent.full_path }
+ ref(:parent) | false | ref(:another_namespace_project_namespace) | lazy { parent.full_path }
+ ref(:parent) | true | ref(:another_namespace_project_namespace) | lazy { parent.full_path }
+ ref(:parent) | false | ref(:user_namespace) | lazy { parent.full_path }
+ ref(:parent) | true | ref(:user_namespace) | lazy { parent.full_path }
+
+ ref(:group) | false | nil | nil
+ ref(:group) | true | nil | lazy { group.full_path }
+ ref(:group) | false | ref(:group) | nil
+ ref(:group) | true | ref(:group) | lazy { group.full_path }
+ ref(:group) | false | ref(:parent) | lazy { group.path }
+ ref(:group) | true | ref(:parent) | lazy { group.full_path }
+ ref(:group) | false | ref(:project) | lazy { group.path }
+ ref(:group) | true | ref(:project) | lazy { group.full_path }
+ ref(:group) | false | ref(:project_namespace) | lazy { group.path }
+ ref(:group) | true | ref(:project_namespace) | lazy { group.full_path }
+ ref(:group) | false | ref(:another_group) | lazy { group.full_path }
+ ref(:group) | true | ref(:another_group) | lazy { group.full_path }
+ ref(:group) | false | ref(:another_namespace_project) | lazy { group.full_path }
+ ref(:group) | true | ref(:another_namespace_project) | lazy { group.full_path }
+ ref(:group) | false | ref(:another_namespace_project_namespace) | lazy { group.full_path }
+ ref(:group) | true | ref(:another_namespace_project_namespace) | lazy { group.full_path }
+ ref(:group) | false | ref(:user_namespace) | lazy { group.full_path }
+ ref(:group) | true | ref(:user_namespace) | lazy { group.full_path }
+
+ ref(:project_namespace) | false | nil | nil
+ ref(:project_namespace) | true | nil | lazy { project_namespace.full_path }
+ ref(:project_namespace) | false | ref(:group) | lazy { project_namespace.path }
+ ref(:project_namespace) | true | ref(:group) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | false | ref(:parent) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | true | ref(:parent) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | false | ref(:project) | nil
+ ref(:project_namespace) | true | ref(:project) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | false | ref(:project_namespace) | nil
+ ref(:project_namespace) | true | ref(:project_namespace) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | false | ref(:another_group) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | true | ref(:another_group) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | false | ref(:another_namespace_project) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | true | ref(:another_namespace_project) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | false | ref(:another_namespace_project_namespace) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | true | ref(:another_namespace_project_namespace) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | false | ref(:user_namespace) | lazy { project_namespace.full_path }
+ ref(:project_namespace) | true | ref(:user_namespace) | lazy { project_namespace.full_path }
+
+ ref(:user_namespace) | false | nil | nil
+ ref(:user_namespace) | true | nil | lazy { user_namespace.full_path }
+ ref(:user_namespace) | false | ref(:user_namespace) | nil
+ ref(:user_namespace) | true | ref(:user_namespace) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | false | ref(:group) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | true | ref(:group) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | false | ref(:parent) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | true | ref(:parent) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | false | ref(:project) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | true | ref(:project) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | false | ref(:project_namespace) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | true | ref(:project_namespace) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | false | ref(:another_group) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | true | ref(:another_group) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | false | ref(:another_namespace_project) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | true | ref(:another_namespace_project) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | false | ref(:another_namespace_project_namespace) | lazy { user_namespace.full_path }
+ ref(:user_namespace) | true | ref(:another_namespace_project_namespace) | lazy { user_namespace.full_path }
+ end
+
+ with_them do
+ it 'returns correct path' do
+ expect(namespace.to_reference_base(from, full: full)).to eq(result)
+ end
+ end
+ end
+
describe 'handling STI', :aggregate_failures do
let(:namespace_type) { nil }
let(:parent) { nil }
@@ -436,6 +575,14 @@ RSpec.describe Namespace, feature_category: :subgroups do
end
end
+ context 'when parent is nil' do
+ let(:namespace) { build(:group, parent: nil) }
+
+ it 'returns []' do
+ expect(namespace.traversal_ids).to eq []
+ end
+ end
+
context 'when made a child group' do
let!(:namespace) { create(:group) }
let!(:parent_namespace) { create(:group, children: [namespace]) }
@@ -458,6 +605,17 @@ RSpec.describe Namespace, feature_category: :subgroups do
expect(namespace.root_ancestor).to eq new_root
end
end
+
+ context 'within a transaction' do
+ # We would like traversal_ids to be defined within a transaction, but it's not possible yet.
+ # This spec exists to assert that the behavior is known.
+ it 'is not defined yet' do
+ Namespace.transaction do
+ group = create(:group)
+ expect(group.traversal_ids).to be_empty
+ end
+ end
+ end
end
context 'traversal scopes' do
@@ -542,17 +700,6 @@ RSpec.describe Namespace, feature_category: :subgroups do
it { expect(child.traversal_ids).to eq [parent.id, child.id] }
it { expect(parent.sync_events.count).to eq 1 }
it { expect(child.sync_events.count).to eq 1 }
-
- context 'when set_traversal_ids_on_save feature flag is disabled' do
- before do
- stub_feature_flags(set_traversal_ids_on_save: false)
- end
-
- it 'only sets traversal_ids on reload' do
- expect { parent.reload }.to change(parent, :traversal_ids).from([]).to([parent.id])
- expect { child.reload }.to change(child, :traversal_ids).from([]).to([parent.id, child.id])
- end
- end
end
context 'traversal_ids on update' do
@@ -565,18 +712,6 @@ RSpec.describe Namespace, feature_category: :subgroups do
it 'sets the traversal_ids attribute' do
expect { subject }.to change { namespace1.traversal_ids }.from([namespace1.id]).to([namespace2.id, namespace1.id])
end
-
- context 'when set_traversal_ids_on_save feature flag is disabled' do
- before do
- stub_feature_flags(set_traversal_ids_on_save: false)
- end
-
- it 'sets traversal_ids after reload' do
- subject
-
- expect { namespace1.reload }.to change(namespace1, :traversal_ids).from([]).to([namespace2.id, namespace1.id])
- end
- end
end
it 'creates a Namespaces::SyncEvent using triggers' do
@@ -677,24 +812,41 @@ RSpec.describe Namespace, feature_category: :subgroups do
describe '#any_project_has_container_registry_tags?' do
subject { namespace.any_project_has_container_registry_tags? }
- let!(:project_without_registry) { create(:project, namespace: namespace) }
+ let(:project) { create(:project, namespace: namespace) }
- context 'without tags' do
- it { is_expected.to be_falsey }
+ it 'returns true if there is a project with container registry tags' do
+ expect(namespace).to receive(:first_project_with_container_registry_tags).and_return(project)
+
+ expect(subject).to be_truthy
end
- context 'with tags' do
- before do
- repositories = create_list(:container_repository, 3)
- create(:project, namespace: namespace, container_repositories: repositories)
+ it 'returns false if there is no project with container registry tags' do
+ expect(namespace).to receive(:first_project_with_container_registry_tags).and_return(nil)
+ expect(subject).to be_falsey
+ end
+ end
+
+ describe '#first_project_with_container_registry_tags' do
+ let(:container_repository) { create(:container_repository) }
+ let!(:project) { create(:project, namespace: namespace, container_repositories: [container_repository]) }
+
+ context 'when Gitlab API is not supported' do
+ before do
stub_container_registry_config(enabled: true)
+ allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(false)
end
- it 'finds tags' do
+ it 'returns the project' do
stub_container_registry_tags(repository: :any, tags: ['tag'])
- is_expected.to be_truthy
+ expect(namespace.first_project_with_container_registry_tags).to eq(project)
+ end
+
+ it 'returns no project' do
+ stub_container_registry_tags(repository: :any, tags: nil)
+
+ expect(namespace.first_project_with_container_registry_tags).to be_nil
end
it 'does not cause N+1 query in fetching registries' do
@@ -704,29 +856,52 @@ RSpec.describe Namespace, feature_category: :subgroups do
other_repositories = create_list(:container_repository, 2)
create(:project, namespace: namespace, container_repositories: other_repositories)
- expect { namespace.any_project_has_container_registry_tags? }.not_to exceed_query_limit(control_count + 1)
+ expect { namespace.first_project_with_container_registry_tags }.not_to exceed_query_limit(control_count + 1)
end
end
- end
- describe '#first_project_with_container_registry_tags' do
- let(:container_repository) { create(:container_repository) }
- let!(:project) { create(:project, namespace: namespace, container_repositories: [container_repository]) }
+ context 'when Gitlab API is supported' do
+ before do
+ allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
+ stub_container_registry_config(enabled: true, api_url: 'http://container-registry', key: 'spec/fixtures/x509_certificate_pk.key')
+ end
- before do
- stub_container_registry_config(enabled: true)
- end
+ it 'calls and returns GitlabApiClient.one_project_with_container_registry_tag' do
+ expect(ContainerRegistry::GitlabApiClient)
+ .to receive(:one_project_with_container_registry_tag)
+ .with(namespace.full_path)
+ .and_return(project)
- it 'returns the project' do
- stub_container_registry_tags(repository: :any, tags: ['tag'])
+ expect(namespace.first_project_with_container_registry_tags).to eq(project)
+ end
- expect(namespace.first_project_with_container_registry_tags).to eq(project)
- end
+ context 'when the feature flag use_sub_repositories_api is disabled' do
+ before do
+ stub_feature_flags(use_sub_repositories_api: false)
+ end
+
+ it 'returns the project' do
+ stub_container_registry_tags(repository: :any, tags: ['tag'])
+
+ expect(namespace.first_project_with_container_registry_tags).to eq(project)
+ end
+
+ it 'returns no project' do
+ stub_container_registry_tags(repository: :any, tags: nil)
+
+ expect(namespace.first_project_with_container_registry_tags).to be_nil
+ end
- it 'returns no project' do
- stub_container_registry_tags(repository: :any, tags: nil)
+ it 'does not cause N+1 query in fetching registries' do
+ stub_container_registry_tags(repository: :any, tags: [])
+ control_count = ActiveRecord::QueryRecorder.new { namespace.any_project_has_container_registry_tags? }.count
- expect(namespace.first_project_with_container_registry_tags).to be_nil
+ other_repositories = create_list(:container_repository, 2)
+ create(:project, namespace: namespace, container_repositories: other_repositories)
+
+ expect { namespace.first_project_with_container_registry_tags }.not_to exceed_query_limit(control_count + 1)
+ end
+ end
end
end
@@ -755,6 +930,7 @@ RSpec.describe Namespace, feature_category: :subgroups do
with_them do
before do
+ allow(ContainerRegistry::GitlabApiClient).to receive(:one_project_with_container_registry_tag).and_return(nil)
stub_container_registry_config(enabled: true, api_url: 'http://container-registry', key: 'spec/fixtures/x509_certificate_pk.key')
allow(Gitlab).to receive(:com?).and_return(true)
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(gitlab_api_supported)
@@ -975,43 +1151,6 @@ RSpec.describe Namespace, feature_category: :subgroups do
end
end
- describe '.find_by_pages_host' do
- it 'finds namespace by GitLab Pages host and is case-insensitive' do
- namespace = create(:namespace, name: 'topNAMEspace', path: 'topNAMEspace')
- create(:namespace, name: 'annother_namespace')
- host = "TopNamespace.#{Settings.pages.host.upcase}"
-
- expect(described_class.find_by_pages_host(host)).to eq(namespace)
- end
-
- context 'when there is non-top-level group with searched name' do
- before do
- create(:group, :nested, path: 'pages')
- end
-
- it 'ignores this group' do
- host = "pages.#{Settings.pages.host.upcase}"
-
- expect(described_class.find_by_pages_host(host)).to be_nil
- end
-
- it 'finds right top level group' do
- group = create(:group, path: 'pages')
-
- host = "pages.#{Settings.pages.host.upcase}"
-
- expect(described_class.find_by_pages_host(host)).to eq(group)
- end
- end
-
- it "returns no result if the provided host is not subdomain of the Pages host" do
- create(:namespace, name: 'namespace.io')
- host = "namespace.io"
-
- expect(described_class.find_by_pages_host(host)).to eq(nil)
- end
- end
-
describe '.top_most' do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:group) { create(:group) }
@@ -1037,6 +1176,7 @@ RSpec.describe Namespace, feature_category: :subgroups do
allow(namespace).to receive(:path_was).and_return(namespace.path)
allow(namespace).to receive(:path).and_return('new_path')
+ allow(namespace).to receive(:first_project_with_container_registry_tags).and_return(project)
end
it 'raises an error about not movable project' do
@@ -1917,6 +2057,62 @@ RSpec.describe Namespace, feature_category: :subgroups do
expect(very_deep_nested_group.root_ancestor).to eq(root_group)
end
end
+
+ context 'when parent is changed' do
+ let(:group) { create(:group) }
+ let(:new_parent) { create(:group) }
+
+ shared_examples 'updates root_ancestor' do
+ it do
+ expect { subject }.to change { group.root_ancestor }.from(group).to(new_parent)
+ end
+ end
+
+ context 'by object' do
+ subject { group.parent = new_parent }
+
+ include_examples 'updates root_ancestor'
+ end
+
+ context 'by id' do
+ subject { group.parent_id = new_parent.id }
+
+ include_examples 'updates root_ancestor'
+ end
+ end
+
+ context 'within a transaction' do
+ context 'with a persisted parent' do
+ let(:parent) { create(:group) }
+
+ it do
+ Namespace.transaction do
+ group = create(:group, parent: parent)
+ expect(group.root_ancestor).to eq parent
+ end
+ end
+ end
+
+ context 'with a non-persisted parent' do
+ let(:parent) { build(:group) }
+
+ it do
+ Namespace.transaction do
+ group = create(:group, parent: parent)
+ expect(group.root_ancestor).to eq parent
+ end
+ end
+ end
+
+ context 'without a parent' do
+ it do
+ Namespace.transaction do
+ group = create(:group)
+ expect(group.root_ancestor).to eq group
+ end
+ end
+ end
+ end
end
describe '#full_path_before_last_save' do
@@ -2105,34 +2301,6 @@ RSpec.describe Namespace, feature_category: :subgroups do
end
end
- describe '#pages_virtual_domain' do
- let(:project) { create(:project, namespace: namespace) }
- let(:virtual_domain) { namespace.pages_virtual_domain }
-
- before do
- project.mark_pages_as_deployed
- project.update_pages_deployment!(create(:pages_deployment, project: project))
- end
-
- it 'returns the virual domain' do
- expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.lookup_paths).not_to be_empty
- expect(virtual_domain.cache_key).to match(/pages_domain_for_namespace_#{namespace.root_ancestor.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' do
- expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.lookup_paths).not_to be_empty
- expect(virtual_domain.cache_key).to be_nil
- end
- end
- end
-
describe '#any_project_with_pages_deployed?' do
it 'returns true if any project nested under the group has pages deployed' do
parent_1 = create(:group) # Three projects, one with pages
diff --git a/spec/models/namespaces/randomized_suffix_path_spec.rb b/spec/models/namespaces/randomized_suffix_path_spec.rb
index a2484030f3c..fc5ccd95ce6 100644
--- a/spec/models/namespaces/randomized_suffix_path_spec.rb
+++ b/spec/models/namespaces/randomized_suffix_path_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::RandomizedSuffixPath, feature_category: :not_owned do
+RSpec.describe Namespaces::RandomizedSuffixPath, feature_category: :shared do
let(:path) { 'backintime' }
subject(:suffixed_path) { described_class.new(path) }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 013070f7be5..c1de8125c0d 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -1100,6 +1100,16 @@ RSpec.describe Note do
end
end
+ describe '#for_work_item?' do
+ it 'returns true for a work item' do
+ expect(build(:note_on_work_item).for_work_item?).to be true
+ end
+
+ it 'returns false for an issue' do
+ expect(build(:note_on_issue).for_work_item?).to be false
+ end
+ end
+
describe '#for_project_snippet?' do
it 'returns true for a project snippet note' do
expect(build(:note_on_project_snippet).for_project_snippet?).to be true
diff --git a/spec/models/oauth_access_token_spec.rb b/spec/models/oauth_access_token_spec.rb
index fc53d926dd6..5fa590eab58 100644
--- a/spec/models/oauth_access_token_spec.rb
+++ b/spec/models/oauth_access_token_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe OauthAccessToken do
it 'uses the expires_in value' do
token = OauthAccessToken.new(expires_in: 1.minute)
- expect(token.expires_in).to eq 1.minute
+ expect(token).to be_valid
end
end
@@ -67,7 +67,7 @@ RSpec.describe OauthAccessToken do
it 'uses default value' do
token = OauthAccessToken.new(expires_in: nil)
- expect(token.expires_in).to eq 2.hours
+ expect(token).to be_invalid
end
end
end
diff --git a/spec/models/onboarding/completion_spec.rb b/spec/models/onboarding/completion_spec.rb
index e1fad4255bc..0639762b76c 100644
--- a/spec/models/onboarding/completion_spec.rb
+++ b/spec/models/onboarding/completion_spec.rb
@@ -2,24 +2,24 @@
require 'spec_helper'
-RSpec.describe Onboarding::Completion do
+RSpec.describe Onboarding::Completion, feature_category: :onboarding do
+ let(:completed_actions) { {} }
+ let(:project) { build(:project, namespace: namespace) }
+ let!(:onboarding_progress) { create(:onboarding_progress, namespace: namespace, **completed_actions) }
+
+ let_it_be(:namespace) { create(:namespace) }
+
describe '#percentage' do
- let(:completed_actions) { {} }
- let!(:onboarding_progress) { create(:onboarding_progress, namespace: namespace, **completed_actions) }
let(:tracked_action_columns) do
- [
- *described_class::ACTION_ISSUE_IDS.keys,
- *described_class::ACTION_PATHS,
- :security_scan_enabled
- ].map { |key| ::Onboarding::Progress.column_name(key) }
+ [*described_class::ACTION_PATHS, :security_scan_enabled].map do |key|
+ ::Onboarding::Progress.column_name(key)
+ end
end
- let_it_be(:namespace) { create(:namespace) }
-
- subject { described_class.new(namespace).percentage }
+ subject(:percentage) { described_class.new(project).percentage }
context 'when no onboarding_progress exists' do
- subject { described_class.new(build(:namespace)).percentage }
+ subject(:percentage) { described_class.new(build(:project)).percentage }
it { is_expected.to eq(0) }
end
@@ -29,6 +29,8 @@ RSpec.describe Onboarding::Completion do
end
context 'when all tracked actions have been completed' do
+ let(:project) { build(:project, :stubbed_commit_count, namespace: namespace) }
+
let(:completed_actions) do
tracked_action_columns.index_with { Time.current }
end
@@ -44,7 +46,7 @@ RSpec.describe Onboarding::Completion do
stub_experiments(security_actions_continuous_onboarding: :control)
end
- it { is_expected.to eq(11) }
+ it { is_expected.to eq(10) }
end
context 'when candidate' do
@@ -52,7 +54,50 @@ RSpec.describe Onboarding::Completion do
stub_experiments(security_actions_continuous_onboarding: :candidate)
end
- it { is_expected.to eq(9) }
+ it { is_expected.to eq(8) }
+ end
+ end
+ end
+
+ describe '#completed?' do
+ subject(:completed?) { described_class.new(project).completed?(column) }
+
+ context 'when code_added' do
+ let(:column) { :code_added }
+
+ context 'when commit_count > 1' do
+ let(:project) { build(:project, :stubbed_commit_count, namespace: namespace) }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when branch_count > 1' do
+ let(:project) { build(:project, :stubbed_branch_count, namespace: namespace) }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when empty repository' do
+ let(:project) { build(:project, namespace: namespace) }
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
+ context 'when security_scan_enabled' do
+ let(:column) { :security_scan_enabled_at }
+ let(:completed_actions) { { security_scan_enabled_at: security_scan_enabled_at } }
+
+ context 'when is completed' do
+ let(:security_scan_enabled_at) { Time.current }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when is not completed' do
+ let(:security_scan_enabled_at) { nil }
+
+ it { is_expected.to eq(false) }
end
end
end
diff --git a/spec/models/packages/debian/file_metadatum_spec.rb b/spec/models/packages/debian/file_metadatum_spec.rb
index 1215adfa6a1..8cbd83c3e2d 100644
--- a/spec/models/packages/debian/file_metadatum_spec.rb
+++ b/spec/models/packages/debian/file_metadatum_spec.rb
@@ -79,6 +79,7 @@ RSpec.describe Packages::Debian::FileMetadatum, type: :model do
:debian_package_file | :dsc | true | false | true
:debian_package_file | :deb | true | true | true
:debian_package_file | :udeb | true | true | true
+ :debian_package_file | :ddeb | true | true | true
:debian_package_file | :buildinfo | true | false | true
:debian_package_file | :changes | false | false | true
end
diff --git a/spec/models/packages/package_file_spec.rb b/spec/models/packages/package_file_spec.rb
index 9b341034aaa..d80f8247261 100644
--- a/spec/models/packages/package_file_spec.rb
+++ b/spec/models/packages/package_file_spec.rb
@@ -153,6 +153,7 @@ RSpec.describe Packages::PackageFile, type: :model do
let_it_be(:debian_changes) { debian_package.package_files.last }
let_it_be(:debian_deb) { create(:debian_package_file, package: debian_package) }
let_it_be(:debian_udeb) { create(:debian_package_file, :udeb, package: debian_package) }
+ let_it_be(:debian_ddeb) { create(:debian_package_file, :ddeb, package: debian_package) }
let_it_be(:debian_contrib) do
create(:debian_package_file, package: debian_package).tap do |pf|
diff --git a/spec/models/pages/lookup_path_spec.rb b/spec/models/pages/lookup_path_spec.rb
index ef79ba28d5d..38ff1bb090e 100644
--- a/spec/models/pages/lookup_path_spec.rb
+++ b/spec/models/pages/lookup_path_spec.rb
@@ -61,15 +61,13 @@ RSpec.describe Pages::LookupPath, feature_category: :pages do
it 'uses deployment from object storage' do
freeze_time do
- expect(source).to(
- eq({
- type: 'zip',
- path: deployment.file.url(expire_at: 1.day.from_now),
- global_id: "gid://gitlab/PagesDeployment/#{deployment.id}",
- sha256: deployment.file_sha256,
- file_size: deployment.size,
- file_count: deployment.file_count
- })
+ expect(source).to eq(
+ type: 'zip',
+ path: deployment.file.url(expire_at: 1.day.from_now),
+ global_id: "gid://gitlab/PagesDeployment/#{deployment.id}",
+ sha256: deployment.file_sha256,
+ file_size: deployment.size,
+ file_count: deployment.file_count
)
end
end
@@ -87,15 +85,13 @@ RSpec.describe Pages::LookupPath, feature_category: :pages do
it 'uses file protocol' do
freeze_time do
- expect(source).to(
- eq({
- type: 'zip',
- path: 'file://' + deployment.file.path,
- global_id: "gid://gitlab/PagesDeployment/#{deployment.id}",
- sha256: deployment.file_sha256,
- file_size: deployment.size,
- file_count: deployment.file_count
- })
+ expect(source).to eq(
+ type: 'zip',
+ path: "file://#{deployment.file.path}",
+ global_id: "gid://gitlab/PagesDeployment/#{deployment.id}",
+ sha256: deployment.file_sha256,
+ file_size: deployment.size,
+ file_count: deployment.file_count
)
end
end
@@ -108,15 +104,13 @@ RSpec.describe Pages::LookupPath, feature_category: :pages do
it 'uses deployment from object storage' do
freeze_time do
- expect(source).to(
- eq({
- type: 'zip',
- path: deployment.file.url(expire_at: 1.day.from_now),
- global_id: "gid://gitlab/PagesDeployment/#{deployment.id}",
- sha256: deployment.file_sha256,
- file_size: deployment.size,
- file_count: deployment.file_count
- })
+ expect(source).to eq(
+ type: 'zip',
+ path: deployment.file.url(expire_at: 1.day.from_now),
+ global_id: "gid://gitlab/PagesDeployment/#{deployment.id}",
+ sha256: deployment.file_sha256,
+ file_size: deployment.size,
+ file_count: deployment.file_count
)
end
end
@@ -143,4 +137,25 @@ RSpec.describe Pages::LookupPath, feature_category: :pages do
expect(lookup_path.prefix).to eq('/myproject/')
end
end
+
+ describe '#unique_domain' do
+ let(:project) { build(:project) }
+
+ context 'when unique domain is disabled' do
+ it 'returns nil' do
+ project.project_setting.pages_unique_domain_enabled = false
+
+ expect(lookup_path.unique_domain).to be_nil
+ end
+ end
+
+ context 'when unique domain is enabled' do
+ it 'returns the project unique domain' do
+ project.project_setting.pages_unique_domain_enabled = true
+ project.project_setting.pages_unique_domain = 'unique-domain'
+
+ expect(lookup_path.unique_domain).to eq('unique-domain')
+ end
+ end
+ end
end
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index f054fde78e7..b218d4dce09 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe PagesDomain do
describe 'associations' do
it { is_expected.to belong_to(:project) }
- it { is_expected.to have_many(:serverless_domain_clusters) }
end
describe '.for_project' do
@@ -546,44 +545,6 @@ RSpec.describe PagesDomain do
end
end
- describe '#pages_virtual_domain' do
- let(:project) { create(:project) }
- let(:pages_domain) { create(:pages_domain, project: project) }
-
- context 'when there are no pages deployed for the project' do
- it 'returns nil' do
- expect(pages_domain.pages_virtual_domain).to be_nil
- end
- end
-
- context 'when there are pages deployed for the project' do
- let(:virtual_domain) { pages_domain.pages_virtual_domain }
-
- before do
- project.mark_pages_as_deployed
- project.update_pages_deployment!(create(:pages_deployment, project: project))
- 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).not_to be_empty
- expect(virtual_domain.cache_key).to match(/pages_domain_for_domain_#{pages_domain.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.lookup_paths).not_to be_empty
- expect(virtual_domain.cache_key).to be_nil
- end
- end
- end
- end
-
describe '#validate_custom_domain_count_per_project' do
let_it_be(:project) { create(:project) }
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index 2320ff669d0..45b8de509fc 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PersonalAccessToken, feature_category: :authentication_and_authorization do
+RSpec.describe PersonalAccessToken, feature_category: :system_access do
subject { described_class }
describe '.build' do
@@ -405,4 +405,26 @@ RSpec.describe PersonalAccessToken, feature_category: :authentication_and_author
end
end
end
+
+ describe 'token format' do
+ let(:personal_access_token) { described_class.new }
+
+ it 'generates a token' do
+ expect { personal_access_token.ensure_token }
+ .to change { personal_access_token.token }.from(nil).to(a_string_starting_with(described_class.token_prefix))
+ end
+
+ context 'when there is an existing token' do
+ let(:token) { 'an_existing_secret_token' }
+
+ before do
+ personal_access_token.set_token(token)
+ end
+
+ it 'does not change the existing token' do
+ expect { personal_access_token.ensure_token }
+ .not_to change { personal_access_token.token }.from(token)
+ end
+ end
+ end
end
diff --git a/spec/models/preloaders/runner_machine_policy_preloader_spec.rb b/spec/models/preloaders/runner_machine_policy_preloader_spec.rb
new file mode 100644
index 00000000000..26fc101d8dc
--- /dev/null
+++ b/spec/models/preloaders/runner_machine_policy_preloader_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Preloaders::RunnerMachinePolicyPreloader, feature_category: :runner_fleet do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:runner1) { create(:ci_runner) }
+ let_it_be(:runner2) { create(:ci_runner) }
+ let_it_be(:runner_machine1) { create(:ci_runner_machine, runner: runner1) }
+ let_it_be(:runner_machine2) { create(:ci_runner_machine, runner: runner2) }
+
+ let(:base_runner_machines) do
+ Project.where(id: [runner_machine1, runner_machine2])
+ end
+
+ it 'avoids N+1 queries when authorizing a list of runner machines', :request_store do
+ preload_runner_machines_for_policy(user)
+ control = ActiveRecord::QueryRecorder.new { authorize_all_runner_machines(user) }
+
+ new_runner1 = create(:ci_runner)
+ new_runner2 = create(:ci_runner)
+ new_runner_machine1 = create(:ci_runner_machine, runner: new_runner1)
+ new_runner_machine2 = create(:ci_runner_machine, runner: new_runner2)
+
+ pristine_runner_machines = Project.where(id: base_runner_machines + [new_runner_machine1, new_runner_machine2])
+
+ preload_runner_machines_for_policy(user, pristine_runner_machines)
+ expect { authorize_all_runner_machines(user, pristine_runner_machines) }.not_to exceed_query_limit(control)
+ end
+
+ def authorize_all_runner_machines(current_user, runner_machine_list = base_runner_machines)
+ runner_machine_list.each { |runner_machine| current_user.can?(:read_runner_machine, runner_machine) }
+ end
+
+ def preload_runner_machines_for_policy(current_user, runner_machine_list = base_runner_machines)
+ described_class.new(runner_machine_list, current_user).execute
+ end
+end
diff --git a/spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb b/spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb
index 7d04817b621..3fba2ac003b 100644
--- a/spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb
+++ b/spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb
@@ -66,22 +66,6 @@ RSpec.describe Preloaders::UserMaxAccessLevelInGroupsPreloader do
create(:group_group_link, :guest, shared_with_group: group1, shared_group: group4)
end
- context 'when `include_memberships_from_group_shares_in_preloader` feature flag is disabled' do
- before do
- stub_feature_flags(include_memberships_from_group_shares_in_preloader: false)
- end
-
- it 'sets access_level to `NO_ACCESS` in cache for groups arising from group shares' do
- described_class.new(groups, user).execute
-
- groups.each do |group|
- cached_access_level = group.max_member_access_for_user(user)
-
- expect(cached_access_level).to eq(Gitlab::Access::NO_ACCESS)
- end
- end
- end
-
it 'sets the right access level in cache for groups arising from group shares' do
described_class.new(groups, user).execute
diff --git a/spec/models/project_ci_cd_setting_spec.rb b/spec/models/project_ci_cd_setting_spec.rb
index 2c490c33747..0a818147bfc 100644
--- a/spec/models/project_ci_cd_setting_spec.rb
+++ b/spec/models/project_ci_cd_setting_spec.rb
@@ -27,22 +27,8 @@ RSpec.describe ProjectCiCdSetting do
end
end
- describe '#set_default_for_inbound_job_token_scope_enabled' do
- context 'when feature flag ci_inbound_job_token_scope is enabled' do
- before do
- stub_feature_flags(ci_inbound_job_token_scope: true)
- end
-
- it { is_expected.to be_inbound_job_token_scope_enabled }
- end
-
- context 'when feature flag ci_inbound_job_token_scope is disabled' do
- before do
- stub_feature_flags(ci_inbound_job_token_scope: false)
- end
-
- it { is_expected.not_to be_inbound_job_token_scope_enabled }
- end
+ describe '#default_for_inbound_job_token_scope_enabled' do
+ it { is_expected.to be_inbound_job_token_scope_enabled }
end
describe '#default_git_depth' do
diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb
index fe0b46c3117..5da6a66b3ae 100644
--- a/spec/models/project_feature_spec.rb
+++ b/spec/models/project_feature_spec.rb
@@ -314,6 +314,40 @@ RSpec.describe ProjectFeature, feature_category: :projects do
end
end
+ describe '#public_packages?' do
+ let_it_be(:public_project) { create(:project, :public) }
+
+ context 'with packages config enabled' do
+ context 'when project is private' do
+ it 'returns false' do
+ expect(project.project_feature.public_packages?).to eq(false)
+ end
+
+ context 'with package_registry_access_level set to public' do
+ before do
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ it 'returns true' do
+ expect(project.project_feature.public_packages?).to eq(true)
+ end
+ end
+ end
+
+ context 'when project is public' do
+ it 'returns true' do
+ expect(public_project.project_feature.public_packages?).to eq(true)
+ end
+ end
+ end
+
+ it 'returns false if packages config is not enabled' do
+ stub_config(packages: { enabled: false })
+
+ expect(public_project.project_feature.public_packages?).to eq(false)
+ end
+ end
+
# rubocop:disable Gitlab/FeatureAvailableUsage
describe '#feature_available?' do
let(:features) { ProjectFeature::FEATURES }
diff --git a/spec/models/project_setting_spec.rb b/spec/models/project_setting_spec.rb
index feb5985818b..42433a2a84a 100644
--- a/spec/models/project_setting_spec.rb
+++ b/spec/models/project_setting_spec.rb
@@ -39,6 +39,44 @@ RSpec.describe ProjectSetting, type: :model do
[nil, 'not_allowed', :invalid].each do |invalid_value|
it { is_expected.not_to allow_value([invalid_value]).for(:target_platforms) }
end
+
+ context "when pages_unique_domain is required", feature_category: :pages do
+ it "is not required if pages_unique_domain_enabled is false" do
+ project_setting = build(:project_setting, pages_unique_domain_enabled: false)
+
+ expect(project_setting).to be_valid
+ expect(project_setting.errors.full_messages).not_to include("Pages unique domain can't be blank")
+ end
+
+ it "is required when pages_unique_domain_enabled is true" do
+ project_setting = build(:project_setting, pages_unique_domain_enabled: true)
+
+ expect(project_setting).not_to be_valid
+ expect(project_setting.errors.full_messages).to include("Pages unique domain can't be blank")
+ end
+
+ it "is required if it is already saved in the database" do
+ project_setting = create(
+ :project_setting,
+ pages_unique_domain: "random-unique-domain-here",
+ pages_unique_domain_enabled: true
+ )
+
+ project_setting.pages_unique_domain = nil
+
+ expect(project_setting).not_to be_valid
+ expect(project_setting.errors.full_messages).to include("Pages unique domain can't be blank")
+ end
+ end
+
+ it "validates uniqueness of pages_unique_domain", feature_category: :pages do
+ create(:project_setting, pages_unique_domain: "random-unique-domain-here")
+
+ project_setting = build(:project_setting, pages_unique_domain: "random-unique-domain-here")
+
+ expect(project_setting).not_to be_valid
+ expect(project_setting.errors.full_messages).to include("Pages unique domain has already been taken")
+ end
end
describe 'target_platforms=' do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index dfc8919e19d..15e5db5af60 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -14,6 +14,8 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
it_behaves_like 'having unique enum values'
+ it_behaves_like 'ensures runners_token is prefixed', :project
+
describe 'associations' do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
@@ -50,6 +52,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
it { is_expected.to have_one(:packagist_integration) }
it { is_expected.to have_one(:pushover_integration) }
it { is_expected.to have_one(:apple_app_store_integration) }
+ it { is_expected.to have_one(:google_play_integration) }
it { is_expected.to have_one(:asana_integration) }
it { is_expected.to have_many(:boards) }
it { is_expected.to have_one(:campfire_integration) }
@@ -88,6 +91,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
it { is_expected.to have_one(:alerting_setting).class_name('Alerting::ProjectAlertingSetting') }
it { is_expected.to have_one(:mock_ci_integration) }
it { is_expected.to have_one(:mock_monitoring_integration) }
+ it { is_expected.to have_one(:service_desk_custom_email_verification).class_name('ServiceDesk::CustomEmailVerification') }
it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:ci_pipelines) }
it { is_expected.to have_many(:ci_refs) }
@@ -135,6 +139,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
it { is_expected.to have_many(:reviews).inverse_of(:project) }
it { is_expected.to have_many(:packages).class_name('Packages::Package') }
it { is_expected.to have_many(:package_files).class_name('Packages::PackageFile') }
+ it { is_expected.to have_many(:rpm_repository_files).class_name('Packages::Rpm::RepositoryFile').inverse_of(:project).dependent(:destroy) }
it { is_expected.to have_many(:debian_distributions).class_name('Packages::Debian::ProjectDistribution').dependent(:destroy) }
it { is_expected.to have_one(:packages_cleanup_policy).class_name('Packages::Cleanup::Policy').inverse_of(:project) }
it { is_expected.to have_many(:pipeline_artifacts).dependent(:restrict_with_error) }
@@ -939,6 +944,17 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
end
+ describe '#commit_notes' do
+ let_it_be(:project) { create(:project) }
+
+ it "returns project's commit notes" do
+ note_1 = create(:note_on_commit, project: project, commit_id: 'commit_id_1')
+ note_2 = create(:note_on_commit, project: project, commit_id: 'commit_id_2')
+
+ expect(project.commit_notes).to match_array([note_1, note_2])
+ end
+ end
+
describe '#personal_namespace_holder?' do
let_it_be(:group) { create(:group) }
let_it_be(:namespace_user) { create(:user) }
@@ -1151,7 +1167,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
describe '#ci_inbound_job_token_scope_enabled?' do
- it_behaves_like 'a ci_cd_settings predicate method', prefix: 'ci_' do
+ it_behaves_like 'a ci_cd_settings predicate method', prefix: 'ci_', default: true do
let(:delegated_method) { :inbound_job_token_scope_enabled? }
end
end
@@ -1380,6 +1396,60 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
end
+ describe '#to_reference_base' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:user_namespace) { user.namespace }
+
+ let_it_be(:parent) { create(:group) }
+ let_it_be(:group) { create(:group, parent: parent) }
+ let_it_be(:another_group) { create(:group) }
+
+ let_it_be(:project1) { create(:project, namespace: group) }
+ let_it_be(:project_namespace) { project1.project_namespace }
+
+ # different project same group
+ let_it_be(:project2) { create(:project, namespace: group) }
+ let_it_be(:project_namespace2) { project2.project_namespace }
+
+ # different project from different group
+ let_it_be(:project3) { create(:project) }
+ let_it_be(:project_namespace3) { project3.project_namespace }
+
+ # testing references with namespace being: group, project namespace and user namespace
+ where(:project, :full, :from, :result) do
+ ref(:project1) | false | nil | nil
+ ref(:project1) | true | nil | lazy { project.full_path }
+ ref(:project1) | false | ref(:group) | lazy { project.path }
+ ref(:project1) | true | ref(:group) | lazy { project.full_path }
+ ref(:project1) | false | ref(:parent) | lazy { project.full_path }
+ ref(:project1) | true | ref(:parent) | lazy { project.full_path }
+ ref(:project1) | false | ref(:project1) | nil
+ ref(:project1) | true | ref(:project1) | lazy { project.full_path }
+ ref(:project1) | false | ref(:project_namespace) | nil
+ ref(:project1) | true | ref(:project_namespace) | lazy { project.full_path }
+ ref(:project1) | false | ref(:project2) | lazy { project.path }
+ ref(:project1) | true | ref(:project2) | lazy { project.full_path }
+ ref(:project1) | false | ref(:project_namespace2) | lazy { project.path }
+ ref(:project1) | true | ref(:project_namespace2) | lazy { project.full_path }
+ ref(:project1) | false | ref(:another_group) | lazy { project.full_path }
+ ref(:project1) | true | ref(:another_group) | lazy { project.full_path }
+ ref(:project1) | false | ref(:project3) | lazy { project.full_path }
+ ref(:project1) | true | ref(:project3) | lazy { project.full_path }
+ ref(:project1) | false | ref(:project_namespace3) | lazy { project.full_path }
+ ref(:project1) | true | ref(:project_namespace3) | lazy { project.full_path }
+ ref(:project1) | false | ref(:user_namespace) | lazy { project.full_path }
+ ref(:project1) | true | ref(:user_namespace) | lazy { project.full_path }
+ end
+
+ with_them do
+ it 'returns correct path' do
+ expect(project.to_reference_base(from, full: full)).to eq(result)
+ end
+ end
+ end
+
describe '#merge_method' do
where(:ff, :rebase, :method) do
true | true | :ff
@@ -2666,7 +2736,11 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
describe '#pages_url', feature_category: :pages do
+ let(:group_name) { 'group' }
+ let(:project_name) { 'project' }
+
let(:group) { create(:group, name: group_name) }
+ let(:nested_group) { create(:group, parent: group) }
let(:project_path) { project_name.downcase }
let(:project) do
@@ -2689,101 +2763,114 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
.and_return(['http://example.com', port].compact.join(':'))
end
- context 'group page' do
- let(:group_name) { 'Group' }
- let(:project_name) { 'group.example.com' }
+ context 'when pages_unique_domain feature flag is disabled' do
+ before do
+ stub_feature_flags(pages_unique_domain: false)
+ end
- it { is_expected.to eq("http://group.example.com") }
+ it { is_expected.to eq('http://group.example.com/project') }
+ end
- context 'mixed case path' do
- let(:project_path) { 'Group.example.com' }
+ context 'when pages_unique_domain feature flag is enabled' do
+ before do
+ stub_feature_flags(pages_unique_domain: true)
- it { is_expected.to eq("http://group.example.com") }
+ project.project_setting.update!(
+ pages_unique_domain_enabled: pages_unique_domain_enabled,
+ pages_unique_domain: 'unique-domain'
+ )
end
- end
- context 'project page' do
- let(:group_name) { 'Group' }
- let(:project_name) { 'Project' }
+ context 'when pages_unique_domain_enabled is false' do
+ let(:pages_unique_domain_enabled) { false }
- it { is_expected.to eq("http://group.example.com/project") }
+ it { is_expected.to eq('http://group.example.com/project') }
+ end
- context 'mixed case path' do
- let(:project_path) { 'Project' }
+ context 'when pages_unique_domain_enabled is false' do
+ let(:pages_unique_domain_enabled) { true }
- it { is_expected.to eq("http://group.example.com/Project") }
+ it { is_expected.to eq('http://unique-domain.example.com') }
end
end
- context 'when there is an explicit port' do
- let(:port) { 3000 }
-
- context 'when not in dev mode' do
- before do
- stub_rails_env('production')
- end
+ context 'with nested group' do
+ let(:project) { create(:project, namespace: nested_group, name: project_name) }
+ let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" }
- context 'group page' do
- let(:group_name) { 'Group' }
- let(:project_name) { 'group.example.com' }
+ context 'group page' do
+ let(:project_name) { 'group.example.com' }
- it { is_expected.to eq('http://group.example.com:3000/group.example.com') }
+ it { is_expected.to eq(expected_url) }
+ end
- context 'mixed case path' do
- let(:project_path) { 'Group.example.com' }
+ context 'project page' do
+ let(:project_name) { 'Project' }
- it { is_expected.to eq('http://group.example.com:3000/Group.example.com') }
- end
- end
+ it { is_expected.to eq(expected_url) }
+ end
+ end
- context 'project page' do
- let(:group_name) { 'Group' }
- let(:project_name) { 'Project' }
+ context 'when the project matches its namespace url' do
+ let(:project_name) { 'group.example.com' }
- it { is_expected.to eq("http://group.example.com:3000/project") }
+ it { is_expected.to eq('http://group.example.com') }
- context 'mixed case path' do
- let(:project_path) { 'Project' }
+ context 'with different group name capitalization' do
+ let(:group_name) { 'Group' }
- it { is_expected.to eq("http://group.example.com:3000/Project") }
- end
- end
+ it { is_expected.to eq("http://group.example.com") }
end
- context 'when in dev mode' do
- before do
- stub_rails_env('development')
- end
-
- context 'group page' do
- let(:group_name) { 'Group' }
- let(:project_name) { 'group.example.com' }
+ context 'with different project path capitalization' do
+ let(:project_path) { 'Group.example.com' }
- it { is_expected.to eq('http://group.example.com:3000') }
+ it { is_expected.to eq("http://group.example.com") }
+ end
- context 'mixed case path' do
- let(:project_path) { 'Group.example.com' }
+ context 'with different project name capitalization' do
+ let(:project_name) { 'Project' }
- it { is_expected.to eq('http://group.example.com:3000') }
- end
- end
+ it { is_expected.to eq("http://group.example.com/project") }
+ end
- context 'project page' do
- let(:group_name) { 'Group' }
- let(:project_name) { 'Project' }
+ context 'when there is an explicit port' do
+ let(:port) { 3000 }
- it { is_expected.to eq("http://group.example.com:3000/project") }
+ context 'when not in dev mode' do
+ before do
+ stub_rails_env('production')
+ end
- context 'mixed case path' do
- let(:project_path) { 'Project' }
+ it { is_expected.to eq('http://group.example.com:3000/group.example.com') }
+ end
- it { is_expected.to eq("http://group.example.com:3000/Project") }
+ context 'when in dev mode' do
+ before do
+ stub_rails_env('development')
end
+
+ it { is_expected.to eq('http://group.example.com:3000') }
end
end
end
end
+ describe '#pages_unique_url', feature_category: :pages do
+ let(:project_settings) { create(:project_setting, pages_unique_domain: 'unique-domain') }
+ let(:project) { build(:project, project_setting: project_settings) }
+ let(:domain) { 'example.com' }
+
+ before do
+ allow(Settings.pages).to receive(:host).and_return(domain)
+ allow(Gitlab.config.pages).to receive(:url).and_return("http://#{domain}")
+ end
+
+ it 'returns the pages unique url' do
+ expect(project.pages_unique_url).to eq('http://unique-domain.example.com')
+ end
+ end
+
describe '#pages_namespace_url', feature_category: :pages do
let(:group) { create(:group, name: group_name) }
let(:project) { create(:project, namespace: group, name: project_name) }
@@ -3565,6 +3652,44 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
end
+ describe '#beautified_import_status_name' do
+ context 'when import not finished' do
+ it 'returns the right beautified import status' do
+ project = create(:project, :import_started)
+
+ expect(project.beautified_import_status_name).to eq('started')
+ end
+ end
+
+ context 'when import is finished' do
+ context 'when import is partially completed' do
+ it 'returns partially completed' do
+ project = create(:project)
+
+ create(:import_state, project: project, status: 'finished', checksums: {
+ 'fetched' => { 'labels' => 10 },
+ 'imported' => { 'labels' => 9 }
+ })
+
+ expect(project.beautified_import_status_name).to eq('partially completed')
+ end
+ end
+
+ context 'when import is fully completed' do
+ it 'returns completed' do
+ project = create(:project)
+
+ create(:import_state, project: project, status: 'finished', checksums: {
+ 'fetched' => { 'labels' => 10 },
+ 'imported' => { 'labels' => 10 }
+ })
+
+ expect(project.beautified_import_status_name).to eq('completed')
+ end
+ end
+ end
+ end
+
describe '#add_import_job' do
let(:import_jid) { '123' }
@@ -3843,21 +3968,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
describe '#ancestors' do
- context 'with linear_project_ancestors feature flag enabled' do
- before do
- stub_feature_flags(linear_project_ancestors: true)
- end
-
- include_examples '#ancestors'
- end
-
- context 'with linear_project_ancestors feature flag disabled' do
- before do
- stub_feature_flags(linear_project_ancestors: false)
- end
-
- include_examples '#ancestors'
- end
+ include_examples '#ancestors'
end
describe '#ancestors_upto' do
@@ -4643,52 +4754,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
end
- describe '#pages_url' do
- let(:group) { create(:group, name: 'Group') }
- let(:nested_group) { create(:group, parent: group) }
- let(:domain) { 'Example.com' }
-
- subject { project.pages_url }
-
- before do
- allow(Settings.pages).to receive(:host).and_return(domain)
- allow(Gitlab.config.pages).to receive(:url).and_return('http://example.com')
- end
-
- context 'top-level group' do
- let(:project) { create(:project, namespace: group, name: project_name) }
-
- context 'group page' do
- let(:project_name) { 'group.example.com' }
-
- it { is_expected.to eq("http://group.example.com") }
- end
-
- context 'project page' do
- let(:project_name) { 'Project' }
-
- it { is_expected.to eq("http://group.example.com/project") }
- end
- end
-
- context 'nested group' do
- let(:project) { create(:project, namespace: nested_group, name: project_name) }
- let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" }
-
- context 'group page' do
- let(:project_name) { 'group.example.com' }
-
- it { is_expected.to eq(expected_url) }
- end
-
- context 'project page' do
- let(:project_name) { 'Project' }
-
- it { is_expected.to eq(expected_url) }
- end
- end
- end
-
describe '#lfs_http_url_to_repo' do
let(:project) { create(:project) }
@@ -6049,7 +6114,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
it 'executes hooks which were backed off and are no longer backed off' do
project = create(:project)
hook = create(:project_hook, project: project, push_events: true)
- WebHook::FAILURE_THRESHOLD.succ.times { hook.backoff! }
+ WebHooks::AutoDisabling::FAILURE_THRESHOLD.succ.times { hook.backoff! }
expect_any_instance_of(ProjectHook).to receive(:async_execute).once
@@ -7305,20 +7370,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
end
- describe 'with integrations and chat names' do
- subject { create(:project) }
-
- let(:integration) { create(:integration, project: subject) }
-
- before do
- create_list(:chat_name, 5, integration: integration)
- end
-
- it 'does not remove chat names on removal' do
- expect { subject.destroy! }.not_to change { ChatName.count }
- end
- end
-
describe 'with_issues_or_mrs_available_for_user' do
before do
Project.delete_all
@@ -8842,6 +8893,32 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
end
+ describe 'deprecated project attributes' do
+ where(:project_attr, :project_method, :project_feature_attr) do
+ :wiki_enabled | :wiki_enabled? | :wiki_access_level
+ :builds_enabled | :builds_enabled? | :builds_access_level
+ :merge_requests_enabled | :merge_requests_enabled? | :merge_requests_access_level
+ :issues_enabled | :issues_enabled? | :issues_access_level
+ :snippets_enabled | :snippets_enabled? | :snippets_access_level
+ end
+
+ with_them do
+ it 'delegates the attributes to project feature' do
+ project = Project.new(project_attr => false)
+
+ expect(project.public_send(project_method)).to eq(false)
+ expect(project.project_feature.public_send(project_feature_attr)).to eq(ProjectFeature::DISABLED)
+ end
+
+ it 'sets the default value' do
+ project = Project.new
+
+ expect(project.public_send(project_method)).to eq(true)
+ expect(project.project_feature.public_send(project_feature_attr)).to eq(ProjectFeature::ENABLED)
+ end
+ end
+ end
+
private
def finish_job(export_job)
diff --git a/spec/models/projects/data_transfer_spec.rb b/spec/models/projects/data_transfer_spec.rb
index 6d3ddbdd74e..ab798185bbb 100644
--- a/spec/models/projects/data_transfer_spec.rb
+++ b/spec/models/projects/data_transfer_spec.rb
@@ -7,6 +7,12 @@ RSpec.describe Projects::DataTransfer, feature_category: :source_code_management
it { expect(subject).to be_valid }
+ # tests DataTransferCounterAttribute with the appropiate attributes
+ it_behaves_like CounterAttribute,
+ %i[repository_egress artifacts_egress packages_egress registry_egress] do
+ let(:model) { create(:project_data_transfer, project: project) }
+ end
+
describe 'associations' do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:namespace) }
diff --git a/spec/models/projects/forks/details_spec.rb b/spec/models/projects/forks/details_spec.rb
new file mode 100644
index 00000000000..4c0a2e3453a
--- /dev/null
+++ b/spec/models/projects/forks/details_spec.rb
@@ -0,0 +1,162 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::Forks::Details, feature_category: :source_code_management do
+ include ExclusiveLeaseHelpers
+ include ProjectForksHelper
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:source_repo) { create(:project, :repository, :public).repository }
+ let_it_be(:fork_repo) { fork_project(source_repo.project, user, { repository: true }).repository }
+
+ let(:fork_branch) { 'fork-branch' }
+ let(:cache_key) { ['project_fork_details', fork_repo.project.id, fork_branch].join(':') }
+
+ describe '#counts', :use_clean_rails_redis_caching do
+ def expect_cached_counts(value)
+ counts = described_class.new(fork_repo.project, fork_branch).counts
+
+ ahead, behind = value
+ expect(counts).to eq({ ahead: ahead, behind: behind })
+
+ cached_value = {
+ source_sha: source_repo.commit.sha,
+ sha: fork_repo.commit(fork_branch).sha,
+ counts: value
+ }
+ expect(Rails.cache.read(cache_key)).to eq(cached_value)
+ end
+
+ it 'shows how far behind/ahead a fork is from the upstream' do
+ fork_repo.create_branch(fork_branch)
+
+ expect_cached_counts([0, 0])
+
+ fork_repo.commit_files(
+ user,
+ branch_name: fork_branch, message: 'Committing something',
+ actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'New file' }]
+ )
+
+ expect_cached_counts([1, 0])
+
+ fork_repo.commit_files(
+ user,
+ branch_name: fork_branch, message: 'Committing something else',
+ actions: [{ action: :create, file_path: 'encoding/ONE-MORE-CHANGELOG', content: 'One more new file' }]
+ )
+
+ expect_cached_counts([2, 0])
+
+ source_repo.commit_files(
+ user,
+ branch_name: source_repo.root_ref, message: 'Commit to root ref',
+ actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'One more' }]
+ )
+
+ expect_cached_counts([2, 1])
+
+ source_repo.commit_files(
+ user,
+ branch_name: source_repo.root_ref, message: 'Another commit to root ref',
+ actions: [{ action: :create, file_path: 'encoding/NEW-CHANGELOG', content: 'One more time' }]
+ )
+
+ expect_cached_counts([2, 2])
+
+ # When the fork is too far ahead
+ stub_const("#{described_class}::LATEST_COMMITS_COUNT", 1)
+ fork_repo.commit_files(
+ user,
+ branch_name: fork_branch, message: 'Another commit to fork',
+ actions: [{ action: :create, file_path: 'encoding/TOO-NEW-CHANGELOG', content: 'New file' }]
+ )
+
+ expect_cached_counts(nil)
+ end
+
+ context 'when counts calculated from a branch that exists upstream' do
+ let_it_be(:source_repo) { create(:project, :repository, :public).repository }
+ let_it_be(:fork_repo) { fork_project(source_repo.project, user, { repository: true }).repository }
+
+ let(:fork_branch) { 'feature' }
+
+ it 'compares the fork branch to upstream default branch' do
+ # The branch itself diverges from the upstream default branch
+ expect_cached_counts([1, 29])
+
+ source_repo.commit_files(
+ user,
+ branch_name: source_repo.root_ref, message: 'Commit to root ref',
+ actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'New file' }]
+ )
+
+ fork_repo.commit_files(
+ user,
+ branch_name: fork_branch, message: 'Committing to feature branch',
+ actions: [{ action: :create, file_path: 'encoding/FEATURE-BRANCH', content: 'New file' }]
+ )
+
+ # It takes into account diverged commits from upstream AND from fork
+ expect_cached_counts([2, 30])
+ end
+ end
+
+ context 'when specified branch does not exist' do
+ it 'returns nils as counts' do
+ counts = described_class.new(fork_repo.project, 'non-existent-branch').counts
+ expect(counts).to eq({ ahead: nil, behind: nil })
+ end
+ end
+ end
+
+ describe '#update!', :use_clean_rails_redis_caching do
+ it 'updates the cache with the specified value' do
+ value = { source_sha: source_repo.commit.sha, sha: fork_repo.commit.sha, counts: [0, 0], has_conflicts: true }
+
+ described_class.new(fork_repo.project, fork_branch).update!(value)
+
+ expect(Rails.cache.read(cache_key)).to eq(value)
+ end
+ end
+
+ describe '#has_conflicts', :use_clean_rails_redis_caching do
+ it 'returns whether merge for the stored commits failed due to conflicts' do
+ details = described_class.new(fork_repo.project, fork_branch)
+
+ expect do
+ value = { source_sha: source_repo.commit.sha, sha: fork_repo.commit.sha, counts: [0, 0], has_conflicts: true }
+
+ details.update!(value)
+ end.to change { details.has_conflicts? }.from(false).to(true)
+ end
+ end
+
+ describe '#exclusive_lease' do
+ it 'returns exclusive lease to the details' do
+ key = ['project_details', fork_repo.project.id, fork_branch].join(':')
+ uuid = SecureRandom.uuid
+ details = described_class.new(fork_repo.project, fork_branch)
+
+ expect(Gitlab::ExclusiveLease).to receive(:get_uuid).with(key).and_return(uuid)
+ expect(Gitlab::ExclusiveLease).to receive(:new).with(
+ key, uuid: uuid, timeout: described_class::LEASE_TIMEOUT
+ ).and_call_original
+
+ expect(details.exclusive_lease).to be_a(Gitlab::ExclusiveLease)
+ end
+ end
+
+ describe 'syncing?', :use_clean_rails_redis_caching do
+ it 'returns whether there is a sync in progress' do
+ details = described_class.new(fork_repo.project, fork_branch)
+
+ expect(details.exclusive_lease.try_obtain).to be_present
+ expect(details.syncing?).to eq(true)
+
+ details.exclusive_lease.cancel
+ expect(details.syncing?).to eq(false)
+ end
+ end
+end
diff --git a/spec/models/projects/forks/divergence_counts_spec.rb b/spec/models/projects/forks/divergence_counts_spec.rb
deleted file mode 100644
index fd69cc0f3e7..00000000000
--- a/spec/models/projects/forks/divergence_counts_spec.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::Forks::DivergenceCounts, feature_category: :source_code_management do
- include ProjectForksHelper
-
- let_it_be(:user) { create(:user) }
-
- describe '#counts', :use_clean_rails_redis_caching do
- let(:source_repo) { create(:project, :repository, :public).repository }
- let(:fork_repo) { fork_project(source_repo.project, user, { repository: true }).repository }
- let(:fork_branch) { 'fork-branch' }
- let(:cache_key) { ['project_forks', fork_repo.project.id, fork_branch, 'divergence_counts'] }
-
- def expect_cached_counts(value)
- counts = described_class.new(fork_repo.project, fork_branch).counts
-
- ahead, behind = value
- expect(counts).to eq({ ahead: ahead, behind: behind })
-
- cached_value = [source_repo.commit.sha, fork_repo.commit(fork_branch).sha, value]
- expect(Rails.cache.read(cache_key)).to eq(cached_value)
- end
-
- it 'shows how far behind/ahead a fork is from the upstream' do
- fork_repo.create_branch(fork_branch)
-
- expect_cached_counts([0, 0])
-
- fork_repo.commit_files(
- user,
- branch_name: fork_branch, message: 'Committing something',
- actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'New file' }]
- )
-
- expect_cached_counts([1, 0])
-
- fork_repo.commit_files(
- user,
- branch_name: fork_branch, message: 'Committing something else',
- actions: [{ action: :create, file_path: 'encoding/ONE-MORE-CHANGELOG', content: 'One more new file' }]
- )
-
- expect_cached_counts([2, 0])
-
- source_repo.commit_files(
- user,
- branch_name: source_repo.root_ref, message: 'Commit to root ref',
- actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'One more' }]
- )
-
- expect_cached_counts([2, 1])
-
- source_repo.commit_files(
- user,
- branch_name: source_repo.root_ref, message: 'Another commit to root ref',
- actions: [{ action: :create, file_path: 'encoding/NEW-CHANGELOG', content: 'One more time' }]
- )
-
- expect_cached_counts([2, 2])
-
- # When the fork is too far ahead
- stub_const("#{described_class}::LATEST_COMMITS_COUNT", 1)
- fork_repo.commit_files(
- user,
- branch_name: fork_branch, message: 'Another commit to fork',
- actions: [{ action: :create, file_path: 'encoding/TOO-NEW-CHANGELOG', content: 'New file' }]
- )
-
- expect_cached_counts(nil)
- end
-
- context 'when counts calculated from a branch that exists upstream' do
- let(:fork_branch) { 'feature' }
-
- it 'compares the fork branch to upstream default branch' do
- # The branch itself diverges from the upstream default branch
- expect_cached_counts([1, 29])
-
- source_repo.commit_files(
- user,
- branch_name: source_repo.root_ref, message: 'Commit to root ref',
- actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'New file' }]
- )
-
- fork_repo.commit_files(
- user,
- branch_name: fork_branch, message: 'Committing to feature branch',
- actions: [{ action: :create, file_path: 'encoding/FEATURE-BRANCH', content: 'New file' }]
- )
-
- # It takes into account diverged commits from upstream AND from fork
- expect_cached_counts([2, 30])
- end
- end
- end
-end
diff --git a/spec/models/projects/import_export/relation_export_spec.rb b/spec/models/projects/import_export/relation_export_spec.rb
index 8643fbc7b46..c724f30250d 100644
--- a/spec/models/projects/import_export/relation_export_spec.rb
+++ b/spec/models/projects/import_export/relation_export_spec.rb
@@ -2,9 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ImportExport::RelationExport, type: :model do
- subject { create(:project_relation_export) }
-
+RSpec.describe Projects::ImportExport::RelationExport, type: :model, feature_category: :importers do
describe 'associations' do
it { is_expected.to belong_to(:project_export_job) }
it { is_expected.to have_one(:upload) }
@@ -13,12 +11,16 @@ RSpec.describe Projects::ImportExport::RelationExport, type: :model do
describe 'validations' do
it { is_expected.to validate_presence_of(:project_export_job) }
it { is_expected.to validate_presence_of(:relation) }
- it { is_expected.to validate_uniqueness_of(:relation).scoped_to(:project_export_job_id) }
it { is_expected.to validate_presence_of(:status) }
it { is_expected.to validate_numericality_of(:status).only_integer }
it { is_expected.to validate_length_of(:relation).is_at_most(255) }
it { is_expected.to validate_length_of(:jid).is_at_most(255) }
it { is_expected.to validate_length_of(:export_error).is_at_most(300) }
+
+ it 'validates uniquness of the relation attribute' do
+ create(:project_relation_export)
+ expect(subject).to validate_uniqueness_of(:relation).scoped_to(:project_export_job_id)
+ end
end
describe '.by_relation' do
@@ -52,4 +54,16 @@ RSpec.describe Projects::ImportExport::RelationExport, type: :model do
expect(described_class.relation_names_list).not_to include('events', 'notes')
end
end
+
+ describe '#mark_as_failed' do
+ it 'sets status to failed and sets the export error', :aggregate_failures do
+ relation_export = create(:project_relation_export)
+
+ relation_export.mark_as_failed("Error message")
+ relation_export.reload
+
+ expect(relation_export.failed?).to eq(true)
+ expect(relation_export.export_error).to eq("Error message")
+ end
+ end
end
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index 71e22f848cc..c99c92e6c19 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProtectedBranch do
+RSpec.describe ProtectedBranch, feature_category: :source_code_management do
subject { build_stubbed(:protected_branch) }
describe 'Associations' do
@@ -214,85 +214,52 @@ RSpec.describe ProtectedBranch do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:protected_branch) { create(:protected_branch, project: project, name: "“jawnâ€") }
- let(:rely_on_new_cache) { true }
-
- shared_examples_for 'hash based cache implementation' do
- it 'calls only hash based cache implementation' do
- expect_next_instance_of(ProtectedBranches::CacheService) do |instance|
- expect(instance).to receive(:fetch).with('missing-branch', anything).and_call_original
- end
-
- expect(Rails.cache).not_to receive(:fetch)
-
- described_class.protected?(project, 'missing-branch')
- end
- end
-
before do
- stub_feature_flags(rely_on_protected_branches_cache: rely_on_new_cache)
allow(described_class).to receive(:matching).and_call_original
# the original call works and warms the cache
described_class.protected?(project, protected_branch.name)
end
- context 'Dry-run: true (rely_on_protected_branches_cache is off, new hash-based is used)' do
- let(:rely_on_new_cache) { false }
+ it 'correctly invalidates a cache' do
+ expect(described_class).to receive(:matching).with(protected_branch.name, protected_refs: anything).exactly(3).times.and_call_original
- it 'recalculates a fresh value every time in order to check the cache is not returning stale data' do
- expect(described_class).to receive(:matching).with(protected_branch.name, protected_refs: anything).twice
+ create_params = { name: 'bar', merge_access_levels_attributes: [{ access_level: Gitlab::Access::DEVELOPER }] }
+ branch = ProtectedBranches::CreateService.new(project, project.owner, create_params).execute
+ expect(described_class.protected?(project, protected_branch.name)).to eq(true)
- 2.times { described_class.protected?(project, protected_branch.name) }
- end
+ ProtectedBranches::UpdateService.new(project, project.owner, name: 'ber').execute(branch)
+ expect(described_class.protected?(project, protected_branch.name)).to eq(true)
- it_behaves_like 'hash based cache implementation'
+ ProtectedBranches::DestroyService.new(project, project.owner).execute(branch)
+ expect(described_class.protected?(project, protected_branch.name)).to eq(true)
end
- context 'Dry-run: false (rely_on_protected_branches_cache is enabled, new hash-based cache is used)' do
- let(:rely_on_new_cache) { true }
-
- it 'correctly invalidates a cache' do
- expect(described_class).to receive(:matching).with(protected_branch.name, protected_refs: anything).exactly(3).times.and_call_original
-
- create_params = { name: 'bar', merge_access_levels_attributes: [{ access_level: Gitlab::Access::DEVELOPER }] }
- branch = ProtectedBranches::CreateService.new(project, project.owner, create_params).execute
- expect(described_class.protected?(project, protected_branch.name)).to eq(true)
+ context 'when project is updated' do
+ it 'does not invalidate a cache' do
+ expect(described_class).not_to receive(:matching).with(protected_branch.name, protected_refs: anything)
- ProtectedBranches::UpdateService.new(project, project.owner, name: 'ber').execute(branch)
- expect(described_class.protected?(project, protected_branch.name)).to eq(true)
+ project.touch
- ProtectedBranches::DestroyService.new(project, project.owner).execute(branch)
- expect(described_class.protected?(project, protected_branch.name)).to eq(true)
- end
-
- it_behaves_like 'hash based cache implementation'
-
- context 'when project is updated' do
- it 'does not invalidate a cache' do
- expect(described_class).not_to receive(:matching).with(protected_branch.name, protected_refs: anything)
-
- project.touch
-
- described_class.protected?(project, protected_branch.name)
- end
+ described_class.protected?(project, protected_branch.name)
end
+ end
- context 'when other project protected branch is updated' do
- it 'does not invalidate the current project cache' do
- expect(described_class).not_to receive(:matching).with(protected_branch.name, protected_refs: anything)
+ context 'when other project protected branch is updated' do
+ it 'does not invalidate the current project cache' do
+ expect(described_class).not_to receive(:matching).with(protected_branch.name, protected_refs: anything)
- another_project = create(:project)
- ProtectedBranches::CreateService.new(another_project, another_project.owner, name: 'bar').execute
+ another_project = create(:project)
+ ProtectedBranches::CreateService.new(another_project, another_project.owner, name: 'bar').execute
- described_class.protected?(project, protected_branch.name)
- end
+ described_class.protected?(project, protected_branch.name)
end
+ end
- it 'correctly uses the cached version' do
- expect(described_class).not_to receive(:matching)
+ it 'correctly uses the cached version' do
+ expect(described_class).not_to receive(:matching)
- expect(described_class.protected?(project, protected_branch.name)).to eq(true)
- end
+ expect(described_class.protected?(project, protected_branch.name)).to eq(true)
end
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index b8780b3faae..f970e818db9 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -413,6 +413,27 @@ RSpec.describe Repository, feature_category: :source_code_management do
repository.commits('master', limit: 1)
end
end
+
+ context 'when include_referenced_by is passed' do
+ context 'when commit has references' do
+ let(:ref) { '5937ac0a7beb003549fc5fd26fc247adbce4a52e' }
+ let(:include_referenced_by) { ['refs/tags'] }
+
+ subject { repository.commits(ref, limit: 1, include_referenced_by: include_referenced_by).first }
+
+ it 'returns commits with referenced_by excluding that match the patterns' do
+ expect(subject.referenced_by).to match_array(['refs/tags/v1.1.0'])
+ end
+
+ context 'when matching multiple references' do
+ let(:include_referenced_by) { ['refs/tags', 'refs/heads'] }
+
+ it 'returns commits with referenced_by that match the patterns' do
+ expect(subject.referenced_by).to match_array(['refs/tags/v1.1.0', 'refs/heads/improve/awesome', 'refs/heads/merge-test'])
+ end
+ end
+ end
+ end
end
context "when 'author' is set" do
@@ -682,6 +703,14 @@ RSpec.describe Repository, feature_category: :source_code_management do
it { is_expected.to be_nil }
end
+
+ context 'when root reference is empty' do
+ subject { empty_repo.merged_to_root_ref?('master') }
+
+ let(:empty_repo) { build(:project, :empty_repo).repository }
+
+ it { is_expected.to be_nil }
+ end
end
describe "#root_ref_sha" do
@@ -690,7 +719,7 @@ RSpec.describe Repository, feature_category: :source_code_management do
subject { repository.root_ref_sha }
before do
- allow(repository).to receive(:commit).with(repository.root_ref) { commit }
+ allow(repository).to receive(:head_commit) { commit }
end
it { is_expected.to eq(commit.sha) }
@@ -1020,8 +1049,34 @@ RSpec.describe Repository, feature_category: :source_code_management do
end
end
+ describe "#move_dir_files" do
+ it 'move directory files successfully' do
+ expect do
+ repository.move_dir_files(user, 'files/new_js', 'files/js',
+ branch_name: 'master',
+ message: 'move directory images to new_images',
+ author_email: author_email,
+ author_name: author_name)
+ end.to change { repository.count_commits(ref: 'master') }.by(1)
+ files = repository.ls_files('master')
+
+ expect(files).not_to include('files/js/application.js')
+ expect(files).to include('files/new_js/application.js')
+ end
+
+ it 'skips commit with same path' do
+ expect do
+ repository.move_dir_files(user, 'files/js', 'files/js',
+ branch_name: 'master',
+ message: 'no commit',
+ author_email: author_email,
+ author_name: author_name)
+ end.to change { repository.count_commits(ref: 'master') }.by(0)
+ end
+ end
+
describe "#delete_file" do
- let(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
it 'removes file successfully' do
expect do
@@ -1422,46 +1477,38 @@ RSpec.describe Repository, feature_category: :source_code_management do
end
end
- [true, false].each do |ff|
- context "with feature flag license_from_gitaly=#{ff}" do
- before do
- stub_feature_flags(license_from_gitaly: ff)
- end
-
- describe '#license', :use_clean_rails_memory_store_caching, :clean_gitlab_redis_cache do
- let(:project) { create(:project, :repository) }
+ describe '#license', :use_clean_rails_memory_store_caching, :clean_gitlab_redis_cache do
+ let(:project) { create(:project, :repository) }
- before do
- repository.delete_file(user, 'LICENSE',
- message: 'Remove LICENSE', branch_name: 'master')
- end
+ before do
+ repository.delete_file(user, 'LICENSE',
+ message: 'Remove LICENSE', branch_name: 'master')
+ end
- it 'returns nil when no license is detected' do
- expect(repository.license).to be_nil
- end
+ it 'returns nil when no license is detected' do
+ expect(repository.license).to be_nil
+ end
- it 'returns nil when the repository does not exist' do
- expect(repository).to receive(:exists?).and_return(false)
+ it 'returns nil when the repository does not exist' do
+ expect(repository).to receive(:exists?).and_return(false)
- expect(repository.license).to be_nil
- end
+ expect(repository.license).to be_nil
+ end
- it 'returns other when the content is not recognizable' do
- repository.create_file(user, 'LICENSE', 'Gitlab B.V.',
- message: 'Add LICENSE', branch_name: 'master')
+ it 'returns other when the content is not recognizable' do
+ repository.create_file(user, 'LICENSE', 'Gitlab B.V.',
+ message: 'Add LICENSE', branch_name: 'master')
- expect(repository.license_key).to eq('other')
- end
+ expect(repository.license_key).to eq('other')
+ end
- it 'returns the license' do
- license = Licensee::License.new('mit')
- repository.create_file(user, 'LICENSE',
- license.content,
- message: 'Add LICENSE', branch_name: 'master')
+ it 'returns the license' do
+ license = Licensee::License.new('mit')
+ repository.create_file(user, 'LICENSE',
+ license.content,
+ message: 'Add LICENSE', branch_name: 'master')
- expect(repository.license_key).to eq(license.key)
- end
- end
+ expect(repository.license_key).to eq(license.key)
end
end
@@ -2302,7 +2349,6 @@ RSpec.describe Repository, feature_category: :source_code_management do
:contribution_guide,
:changelog,
:license_blob,
- :license_licensee,
:license_gitaly,
:gitignore,
:gitlab_ci_yml,
@@ -2957,11 +3003,10 @@ RSpec.describe Repository, feature_category: :source_code_management do
describe '#refresh_method_caches' do
it 'refreshes the caches of the given types' do
expect(repository).to receive(:expire_method_caches)
- .with(%i(readme_path license_blob license_licensee license_gitaly))
+ .with(%i(readme_path license_blob license_gitaly))
expect(repository).to receive(:readme_path)
expect(repository).to receive(:license_blob)
- expect(repository).to receive(:license_licensee)
expect(repository).to receive(:license_gitaly)
repository.refresh_method_caches(%i(readme license))
diff --git a/spec/models/serverless/domain_cluster_spec.rb b/spec/models/serverless/domain_cluster_spec.rb
deleted file mode 100644
index 487385c62c1..00000000000
--- a/spec/models/serverless/domain_cluster_spec.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ::Serverless::DomainCluster do
- subject { create(:serverless_domain_cluster) }
-
- describe 'default values' do
- subject(:domain_cluster) { build(:serverless_domain_cluster) }
-
- before do
- allow(::Serverless::Domain).to receive(:generate_uuid).and_return('randomtoken')
- end
-
- it { expect(domain_cluster.uuid).to eq('randomtoken') }
- end
-
- describe 'validations' do
- it { is_expected.to validate_presence_of(:pages_domain) }
- it { is_expected.to validate_presence_of(:knative) }
-
- it { is_expected.to validate_presence_of(:uuid) }
- it { is_expected.to validate_length_of(:uuid).is_equal_to(::Serverless::Domain::UUID_LENGTH) }
- it { is_expected.to validate_uniqueness_of(:uuid) }
-
- it 'validates that uuid has only hex characters' do
- subject = build(:serverless_domain_cluster, uuid: 'z1234567890123')
- subject.valid?
-
- expect(subject.errors[:uuid]).to include('only allows hex characters')
- end
- end
-
- describe 'associations' do
- it { is_expected.to belong_to(:pages_domain) }
- it { is_expected.to belong_to(:knative) }
- it { is_expected.to belong_to(:creator).optional }
- end
-
- describe 'uuid' do
- context 'when nil' do
- it 'generates a value by default' do
- attributes = build(:serverless_domain_cluster).attributes.merge(uuid: nil)
- expect(::Serverless::Domain).to receive(:generate_uuid).and_call_original
-
- subject = Serverless::DomainCluster.new(attributes)
-
- expect(subject.uuid).not_to be_blank
- end
- end
-
- context 'when not nil' do
- it 'does not override the existing value' do
- uuid = 'abcd1234567890'
- expect(build(:serverless_domain_cluster, uuid: uuid).uuid).to eq(uuid)
- end
- end
- end
-
- describe 'cluster' do
- it { is_expected.to respond_to(:cluster) }
- end
-
- describe 'domain' do
- it { is_expected.to respond_to(:domain) }
- end
-
- describe 'certificate' do
- it { is_expected.to respond_to(:certificate) }
- end
-
- describe 'key' do
- it { is_expected.to respond_to(:key) }
- end
-end
diff --git a/spec/models/serverless/domain_spec.rb b/spec/models/serverless/domain_spec.rb
deleted file mode 100644
index f997b28b149..00000000000
--- a/spec/models/serverless/domain_spec.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ::Serverless::Domain do
- let(:function_name) { 'test-function' }
- let(:pages_domain_name) { 'serverless.gitlab.io' }
- let(:pages_domain) { create(:pages_domain, :instance_serverless, domain: pages_domain_name) }
- let!(:serverless_domain_cluster) { create(:serverless_domain_cluster, uuid: 'abcdef12345678', pages_domain: pages_domain) }
- let(:valid_cluster_uuid) { 'aba1cdef123456f278' }
- let(:invalid_cluster_uuid) { 'aba1cdef123456f178' }
- let!(:environment) { create(:environment, name: 'test') }
-
- let(:valid_uri) { "https://#{function_name}-#{valid_cluster_uuid}#{"%x" % environment.id}-#{environment.slug}.#{pages_domain_name}" }
- let(:valid_fqdn) { "#{function_name}-#{valid_cluster_uuid}#{"%x" % environment.id}-#{environment.slug}.#{pages_domain_name}" }
- let(:invalid_uri) { "https://#{function_name}-#{invalid_cluster_uuid}#{"%x" % environment.id}-#{environment.slug}.#{pages_domain_name}" }
-
- shared_examples 'a valid Domain' do
- describe '#uri' do
- it 'matches valid URI' do
- expect(subject.uri.to_s).to eq valid_uri
- end
- end
-
- describe '#function_name' do
- it 'returns function_name' do
- expect(subject.function_name).to eq function_name
- end
- end
-
- describe '#serverless_domain_cluster' do
- it 'returns serverless_domain_cluster' do
- expect(subject.serverless_domain_cluster).to eq serverless_domain_cluster
- end
- end
-
- describe '#environment' do
- it 'returns environment' do
- expect(subject.environment).to eq environment
- end
- end
- end
-
- describe '.new' do
- context 'with valid arguments' do
- subject do
- described_class.new(
- function_name: function_name,
- serverless_domain_cluster: serverless_domain_cluster,
- environment: environment
- )
- end
-
- it_behaves_like 'a valid Domain'
- end
-
- context 'with invalid arguments' do
- subject do
- described_class.new(
- function_name: function_name,
- environment: environment
- )
- end
-
- it { is_expected.not_to be_valid }
- end
-
- context 'with nil cluster argument' do
- subject do
- described_class.new(
- function_name: function_name,
- serverless_domain_cluster: nil,
- environment: environment
- )
- end
-
- it { is_expected.not_to be_valid }
- end
- end
-
- describe '.generate_uuid' do
- it 'has 14 characters' do
- expect(described_class.generate_uuid.length).to eq(described_class::UUID_LENGTH)
- end
-
- it 'consists of only hexadecimal characters' do
- expect(described_class.generate_uuid).to match(/\A\h+\z/)
- end
-
- it 'uses random characters' do
- uuid = 'abcd1234567890'
-
- expect(SecureRandom).to receive(:hex).with(described_class::UUID_LENGTH / 2).and_return(uuid)
- expect(described_class.generate_uuid).to eq(uuid)
- end
- end
-end
diff --git a/spec/models/serverless/function_spec.rb b/spec/models/serverless/function_spec.rb
deleted file mode 100644
index 632f5eba5c3..00000000000
--- a/spec/models/serverless/function_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ::Serverless::Function do
- let(:project) { create(:project) }
- let(:func) { described_class.new(project, 'test', 'test-ns') }
-
- it 'has a proper id' do
- expect(func.id).to eql("#{project.id}/test/test-ns")
- expect(func.name).to eql("test")
- expect(func.namespace).to eql("test-ns")
- end
-
- it 'can decode an identifier' do
- f = described_class.find_by_id("#{project.id}/testfunc/dummy-ns")
-
- expect(f.name).to eql("testfunc")
- expect(f.namespace).to eql("dummy-ns")
- end
-end
diff --git a/spec/models/service_desk/custom_email_verification_spec.rb b/spec/models/service_desk/custom_email_verification_spec.rb
new file mode 100644
index 00000000000..f0a6028f21d
--- /dev/null
+++ b/spec/models/service_desk/custom_email_verification_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ServiceDesk::CustomEmailVerification, feature_category: :service_desk do
+ let(:user) { build_stubbed(:user) }
+ let(:project) { build_stubbed(:project) }
+ let(:verification) { build_stubbed(:service_desk_custom_email_verification, project: project) }
+ let(:token) { 'XXXXXXXXXXXX' }
+
+ describe '.generate_token' do
+ it 'matches expected output' do
+ expect(described_class.generate_token).to match(/\A\p{Alnum}{12}\z/)
+ end
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:state) }
+ end
+
+ describe '#accepted_until' do
+ context 'when no custom email is set up' do
+ it 'returns nil' do
+ expect(subject.accepted_until).to be_nil
+ end
+ end
+
+ context 'when custom email is set up' do
+ subject { verification.accepted_until }
+
+ it { is_expected.to be_nil }
+
+ context 'when verification process started' do
+ let(:triggered_at) { 2.minutes.ago }
+
+ before do
+ verification.assign_attributes(
+ state: "running",
+ triggered_at: triggered_at,
+ triggerer: user,
+ token: token
+ )
+ end
+
+ it { is_expected.to eq(described_class::TIMEFRAME.since(triggered_at)) }
+ end
+ end
+ end
+
+ describe '#in_timeframe?' do
+ context 'when no custom email is set up' do
+ it 'returns false' do
+ expect(subject).not_to be_in_timeframe
+ end
+ end
+
+ context 'when custom email is set up' do
+ it { is_expected.not_to be_in_timeframe }
+
+ context 'when verification process started' do
+ let(:triggered_at) { 1.second.ago }
+
+ before do
+ subject.assign_attributes(
+ state: "running",
+ triggered_at: triggered_at,
+ triggerer: user,
+ token: token
+ )
+ end
+
+ it { is_expected.to be_in_timeframe }
+
+ context 'and timeframe was missed' do
+ let(:triggered_at) { (described_class::TIMEFRAME + 1).ago }
+
+ before do
+ subject.triggered_at = triggered_at
+ end
+
+ it { is_expected.not_to be_in_timeframe }
+ end
+ end
+ end
+ end
+
+ describe 'encrypted #token' do
+ subject { build_stubbed(:service_desk_custom_email_verification, token: token) }
+
+ it 'saves and retrieves the encrypted token and iv correctly' do
+ expect(subject.encrypted_token).not_to be_nil
+ expect(subject.encrypted_token_iv).not_to be_nil
+
+ expect(subject.token).to eq(token)
+ end
+ end
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:triggerer) }
+
+ it 'can access service desk setting from project' do
+ setting = build_stubbed(:service_desk_setting, project: project)
+
+ expect(verification.service_desk_setting).to eq(setting)
+ end
+ end
+end
diff --git a/spec/models/service_desk_setting_spec.rb b/spec/models/service_desk_setting_spec.rb
index 32c36375a3d..b99494e6736 100644
--- a/spec/models/service_desk_setting_spec.rb
+++ b/spec/models/service_desk_setting_spec.rb
@@ -3,6 +3,9 @@
require 'spec_helper'
RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
+ let(:verification) { build(:service_desk_custom_email_verification) }
+ let(:project) { build(:project) }
+
describe 'validations' do
subject(:service_desk_setting) { create(:service_desk_setting) }
@@ -23,6 +26,8 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
context 'when custom_email_enabled is true' do
before do
+ # Test without ServiceDesk::CustomEmailVerification for simplicity
+ # See dedicated simplified tests below
subject.custom_email_enabled = true
end
@@ -55,7 +60,18 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
it { is_expected.not_to allow_value('/example').for(:custom_email_smtp_address) }
end
- describe '.valid_issue_template' do
+ context 'when custom email verification is present/was triggered' do
+ before do
+ subject.project.service_desk_custom_email_verification = verification
+ end
+
+ it { is_expected.to validate_presence_of(:custom_email) }
+ it { is_expected.to validate_presence_of(:custom_email_smtp_username) }
+ it { is_expected.to validate_presence_of(:custom_email_smtp_port) }
+ it { is_expected.to validate_presence_of(:custom_email_smtp_address) }
+ end
+
+ describe '#valid_issue_template' do
let_it_be(:project) { create(:project, :custom_repo, files: { '.gitlab/issue_templates/service_desk.md' => 'template' }) }
it 'is not valid if template does not exist' do
@@ -73,7 +89,20 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
end
end
- describe '.valid_project_key' do
+ describe '#custom_email_address_for_verification' do
+ it 'returns nil' do
+ expect(subject.custom_email_address_for_verification).to be_nil
+ end
+
+ context 'when custom_email exists' do
+ it 'returns correct verification address' do
+ subject.custom_email = 'support@example.com'
+ expect(subject.custom_email_address_for_verification).to eq('support+verify@example.com')
+ end
+ end
+ end
+
+ describe '#valid_project_key' do
# Creates two projects with same full path slug
# group1/test/one and group1/test-one will both have 'group-test-one' slug
let_it_be(:group) { create(:group) }
@@ -109,15 +138,15 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
end
end
- describe 'encrypted password' do
+ describe 'encrypted #custom_email_smtp_password' do
let_it_be(:settings) do
create(
:service_desk_setting,
custom_email_enabled: true,
- custom_email: 'supersupport@example.com',
+ custom_email: 'support@example.com',
custom_email_smtp_address: 'smtp.example.com',
custom_email_smtp_port: 587,
- custom_email_smtp_username: 'supersupport@example.com',
+ custom_email_smtp_username: 'support@example.com',
custom_email_smtp_password: 'supersecret'
)
end
@@ -131,6 +160,24 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
end
describe 'associations' do
+ let(:custom_email_settings) do
+ build_stubbed(
+ :service_desk_setting,
+ custom_email: 'support@example.com',
+ custom_email_smtp_address: 'smtp.example.com',
+ custom_email_smtp_port: 587,
+ custom_email_smtp_username: 'support@example.com',
+ custom_email_smtp_password: 'supersecret'
+ )
+ end
+
it { is_expected.to belong_to(:project) }
+
+ it 'can access custom email verification from project' do
+ project.service_desk_custom_email_verification = verification
+ custom_email_settings.project = project
+
+ expect(custom_email_settings.custom_email_verification).to eq(verification)
+ end
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index e87667d9604..04f1bffce0a 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -174,6 +174,11 @@ RSpec.describe User, feature_category: :user_profile do
it { is_expected.to have_many(:revoked_user_achievements).class_name('Achievements::UserAchievement').with_foreign_key('revoked_by_user_id').inverse_of(:revoked_by_user) }
it { is_expected.to have_many(:achievements).through(:user_achievements).class_name('Achievements::Achievement').inverse_of(:users) }
it { is_expected.to have_many(:namespace_commit_emails).class_name('Users::NamespaceCommitEmail') }
+ it { is_expected.to have_many(:audit_events).with_foreign_key(:author_id).inverse_of(:user) }
+
+ it do
+ is_expected.to have_many(:alert_assignees).class_name('::AlertManagement::AlertAssignee').inverse_of(:assignee)
+ end
describe 'default values' do
let(:user) { described_class.new }
@@ -188,6 +193,7 @@ RSpec.describe User, feature_category: :user_profile do
it { expect(user.notified_of_own_activity).to be_falsey }
it { expect(user.preferred_language).to eq(Gitlab::CurrentSettings.default_preferred_language) }
it { expect(user.theme_id).to eq(described_class.gitlab_config.default_theme) }
+ it { expect(user.color_scheme_id).to eq(Gitlab::CurrentSettings.default_syntax_highlighting_theme) }
end
describe '#user_detail' do
@@ -474,6 +480,37 @@ RSpec.describe User, feature_category: :user_profile do
expect(user).to be_valid
end
end
+
+ context 'namespace_move_dir_allowed' do
+ context 'when the user is not a new record' do
+ before do
+ expect(user.new_record?).to eq(false)
+ end
+
+ it 'checks when username changes' do
+ expect(user).to receive(:namespace_move_dir_allowed)
+
+ user.username = 'newuser'
+ user.validate
+ end
+
+ it 'does not check if the username did not change' do
+ expect(user).not_to receive(:namespace_move_dir_allowed)
+ expect(user.username_changed?).to eq(false)
+
+ user.validate
+ end
+ end
+
+ it 'does not check if the user is a new record' do
+ user = User.new(username: 'newuser')
+
+ expect(user.new_record?).to eq(true)
+ expect(user).not_to receive(:namespace_move_dir_allowed)
+
+ user.validate
+ end
+ end
end
describe 'name' do
@@ -978,10 +1015,6 @@ RSpec.describe User, feature_category: :user_profile do
end
end
- describe 'and U2F' do
- it_behaves_like "returns the right users", :two_factor_via_u2f
- end
-
describe 'and WebAuthn' do
it_behaves_like "returns the right users", :two_factor_via_webauthn
end
@@ -997,26 +1030,6 @@ RSpec.describe User, feature_category: :user_profile do
expect(users_without_two_factor).not_to include(user_with_2fa.id)
end
- describe 'and u2f' do
- it 'excludes users with 2fa enabled via U2F' do
- user_with_2fa = create(:user, :two_factor_via_u2f)
- user_without_2fa = create(:user)
- users_without_two_factor = described_class.without_two_factor.pluck(:id)
-
- expect(users_without_two_factor).to include(user_without_2fa.id)
- expect(users_without_two_factor).not_to include(user_with_2fa.id)
- end
-
- it 'excludes users with 2fa enabled via OTP and U2F' do
- user_with_2fa = create(:user, :two_factor_via_otp, :two_factor_via_u2f)
- user_without_2fa = create(:user)
- users_without_two_factor = described_class.without_two_factor.pluck(:id)
-
- expect(users_without_two_factor).to include(user_without_2fa.id)
- expect(users_without_two_factor).not_to include(user_with_2fa.id)
- end
- end
-
describe 'and webauthn' do
it 'excludes users with 2fa enabled via WebAuthn' do
user_with_2fa = create(:user, :two_factor_via_webauthn)
@@ -2174,6 +2187,24 @@ RSpec.describe User, feature_category: :user_profile do
end
end
+ context 'Duo Auth' do
+ context 'when enabled via GitLab settings' do
+ before do
+ allow(::Gitlab.config.duo_auth).to receive(:enabled).and_return(true)
+ end
+
+ it { expect(user.two_factor_otp_enabled?).to eq(true) }
+ end
+
+ context 'when disabled via GitLab settings' do
+ before do
+ allow(::Gitlab.config.duo_auth).to receive(:enabled).and_return(false)
+ end
+
+ it { expect(user.two_factor_otp_enabled?).to eq(false) }
+ end
+ end
+
context 'FortiTokenCloud' do
context 'when enabled via GitLab settings' do
before do
@@ -2207,54 +2238,6 @@ RSpec.describe User, feature_category: :user_profile do
end
end
- context 'two_factor_u2f_enabled?' do
- let_it_be(:user) { create(:user, :two_factor) }
-
- context 'when webauthn feature flag is enabled' do
- context 'user has no U2F registration' do
- it { expect(user.two_factor_u2f_enabled?).to eq(false) }
- end
-
- context 'user has existing U2F registration' do
- it 'returns false' do
- device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5))
- create(:u2f_registration,
- name: 'my u2f device',
- user: user,
- certificate: Base64.strict_encode64(device.cert_raw),
- key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
- public_key: Base64.strict_encode64(device.origin_public_key_raw))
-
- expect(user.two_factor_u2f_enabled?).to eq(false)
- end
- end
- end
-
- context 'when webauthn feature flag is disabled' do
- before do
- stub_feature_flags(webauthn: false)
- end
-
- context 'user has no U2F registration' do
- it { expect(user.two_factor_u2f_enabled?).to eq(false) }
- end
-
- context 'user has existing U2F registration' do
- it 'returns true' do
- device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5))
- create(:u2f_registration,
- name: 'my u2f device',
- user: user,
- certificate: Base64.strict_encode64(device.cert_raw),
- key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
- public_key: Base64.strict_encode64(device.origin_public_key_raw))
-
- expect(user.two_factor_u2f_enabled?).to eq(true)
- end
- end
- end
- end
-
describe 'needs_new_otp_secret?', :freeze_time do
let(:user) { create(:user) }
@@ -2396,14 +2379,6 @@ RSpec.describe User, feature_category: :user_profile do
end
it_behaves_like 'manageable groups examples'
-
- context 'when feature flag :linear_user_manageable_groups is disabled' do
- before do
- stub_feature_flags(linear_user_manageable_groups: false)
- end
-
- it_behaves_like 'manageable groups examples'
- end
end
end
end
@@ -7104,43 +7079,105 @@ RSpec.describe User, feature_category: :user_profile do
context 'when user is confirmed' do
let(:user) { create(:user) }
- it 'is falsey' do
- expect(user.confirmed?).to be_truthy
- expect(subject).to be_falsey
+ it 'is false' do
+ expect(user.confirmed?).to be(true)
+ expect(subject).to be(false)
end
end
context 'when user is not confirmed' do
let_it_be(:user) { build_stubbed(:user, :unconfirmed, confirmation_sent_at: Time.current) }
- it 'is truthy when soft_email_confirmation feature is disabled' do
- stub_feature_flags(soft_email_confirmation: false)
- expect(subject).to be_truthy
+ context 'when email confirmation setting is set to `off`' do
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'off')
+ end
+
+ it { is_expected.to be(false) }
end
- context 'when soft_email_confirmation feature is enabled' do
+ context 'when email confirmation setting is set to `soft`' do
before do
- stub_feature_flags(soft_email_confirmation: true)
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
end
- it 'is falsey when confirmation period is valid' do
- expect(subject).to be_falsey
+ context 'when confirmation period is valid' do
+ it { is_expected.to be(false) }
end
- it 'is truthy when confirmation period is expired' do
- travel_to(User.allow_unconfirmed_access_for.from_now + 1.day) do
- expect(subject).to be_truthy
+ context 'when confirmation period is expired' do
+ before do
+ travel_to(User.allow_unconfirmed_access_for.from_now + 1.day)
end
+
+ it { is_expected.to be(true) }
end
context 'when user has no confirmation email sent' do
let(:user) { build(:user, :unconfirmed, confirmation_sent_at: nil) }
- it 'is truthy' do
- expect(subject).to be_truthy
- end
+ it { is_expected.to be(true) }
end
end
+
+ context 'when email confirmation setting is set to `hard`' do
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'hard')
+ end
+
+ it { is_expected.to be(true) }
+ end
+ end
+ end
+
+ describe '#confirmation_period_valid?' do
+ subject { user.send(:confirmation_period_valid?) }
+
+ let_it_be(:user) { create(:user) }
+
+ context 'when email confirmation setting is set to `off`' do
+ before do
+ stub_feature_flags(soft_email_confirmation: false)
+ end
+
+ it { is_expected.to be(true) }
+ end
+
+ context 'when email confirmation setting is set to `soft`' do
+ before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
+ end
+
+ context 'when within confirmation window' do
+ before do
+ user.update!(confirmation_sent_at: Date.today)
+ end
+
+ it { is_expected.to be(true) }
+ end
+
+ context 'when outside confirmation window' do
+ before do
+ user.update!(confirmation_sent_at: Date.today - described_class.confirm_within - 7.days)
+ end
+
+ it { is_expected.to be(false) }
+ end
+ end
+
+ context 'when email confirmation setting is set to `hard`' do
+ before do
+ stub_feature_flags(soft_email_confirmation: false)
+ stub_application_setting_enum('email_confirmation_setting', 'hard')
+ end
+
+ it { is_expected.to be(true) }
+ end
+
+ describe '#in_confirmation_period?' do
+ it 'is expected to be an alias' do
+ expect(user.method(:in_confirmation_period?).original_name).to eq(:confirmation_period_valid?)
+ end
end
end
diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb
index 1b177934ace..c30e79f79ce 100644
--- a/spec/models/wiki_directory_spec.rb
+++ b/spec/models/wiki_directory_spec.rb
@@ -13,6 +13,8 @@ RSpec.describe WikiDirectory do
let_it_be(:toplevel1) { build(:wiki_page, title: 'aaa-toplevel1') }
let_it_be(:toplevel2) { build(:wiki_page, title: 'zzz-toplevel2') }
let_it_be(:toplevel3) { build(:wiki_page, title: 'zzz-toplevel3') }
+ let_it_be(:home) { build(:wiki_page, title: 'home') }
+ let_it_be(:homechild) { build(:wiki_page, title: 'Home/homechild') }
let_it_be(:parent1) { build(:wiki_page, title: 'parent1') }
let_it_be(:parent2) { build(:wiki_page, title: 'parent2') }
let_it_be(:child1) { build(:wiki_page, title: 'parent1/child1') }
@@ -24,13 +26,18 @@ RSpec.describe WikiDirectory do
it 'returns a nested array of entries' do
entries = described_class.group_pages(
- [toplevel1, toplevel2, toplevel3,
+ [toplevel1, toplevel2, toplevel3, home, homechild,
parent1, parent2, child1, child2, child3,
subparent, grandchild1, grandchild2].sort_by(&:title)
)
expect(entries).to match(
[
+ a_kind_of(WikiDirectory).and(
+ having_attributes(
+ slug: 'Home', entries: [homechild]
+ )
+ ),
toplevel1,
a_kind_of(WikiDirectory).and(
having_attributes(
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index 21da06a222f..efade74688a 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -588,6 +588,20 @@ RSpec.describe WikiPage do
expect(page.content).to eq new_content
end
+ context 'when page combine with directory' do
+ it 'moving the file and directory' do
+ wiki.create_page('testpage/testtitle', 'content')
+ wiki.create_page('testpage', 'content')
+
+ page = wiki.find_page('testpage')
+ page.update(title: 'testfolder/testpage')
+
+ page = wiki.find_page('testfolder/testpage/testtitle')
+
+ expect(page.slug).to eq 'testfolder/testpage/testtitle'
+ end
+ end
+
describe 'in subdir' do
it 'moves the page to the root folder if the title is preceded by /' do
page = create_wiki_page(container, title: 'foo/Existing Page')
diff --git a/spec/models/work_item_spec.rb b/spec/models/work_item_spec.rb
index 6aacaa3c119..13f17e11276 100644
--- a/spec/models/work_item_spec.rb
+++ b/spec/models/work_item_spec.rb
@@ -163,6 +163,30 @@ RSpec.describe WorkItem, feature_category: :portfolio_management do
end
end
+ describe 'transform_quick_action_params' do
+ let(:work_item) { build(:work_item, :task) }
+
+ subject(:transformed_params) do
+ work_item.transform_quick_action_params({
+ title: 'bar',
+ assignee_ids: ['foo']
+ })
+ end
+
+ it 'correctly separates widget params from regular params' do
+ expect(transformed_params).to eq({
+ common: {
+ title: 'bar'
+ },
+ widgets: {
+ assignees_widget: {
+ assignee_ids: ['foo']
+ }
+ }
+ })
+ end
+ end
+
describe 'callbacks' do
describe 'record_create_action' do
it 'records the creation action after saving' do
diff --git a/spec/models/work_items/widget_definition_spec.rb b/spec/models/work_items/widget_definition_spec.rb
index 08f8f4d9663..3a4670c996f 100644
--- a/spec/models/work_items/widget_definition_spec.rb
+++ b/spec/models/work_items/widget_definition_spec.rb
@@ -11,7 +11,8 @@ RSpec.describe WorkItems::WidgetDefinition, feature_category: :team_planning do
::WorkItems::Widgets::Assignees,
::WorkItems::Widgets::StartAndDueDate,
::WorkItems::Widgets::Milestone,
- ::WorkItems::Widgets::Notes
+ ::WorkItems::Widgets::Notes,
+ ::WorkItems::Widgets::Notifications
]
if Gitlab.ee?
diff --git a/spec/models/work_items/widgets/notifications_spec.rb b/spec/models/work_items/widgets/notifications_spec.rb
new file mode 100644
index 00000000000..2942c149660
--- /dev/null
+++ b/spec/models/work_items/widgets/notifications_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::Widgets::Notifications, feature_category: :team_planning do
+ let_it_be(:work_item) { create(:work_item) }
+
+ describe '.type' do
+ it { expect(described_class.type).to eq(:notifications) }
+ end
+
+ describe '#type' do
+ it { expect(described_class.new(work_item).type).to eq(:notifications) }
+ end
+
+ describe '#subscribed?' do
+ it { expect(described_class.new(work_item).subscribed?(work_item.author, work_item.project)).to eq(true) }
+ end
+end
diff --git a/spec/policies/ci/pipeline_schedule_policy_spec.rb b/spec/policies/ci/pipeline_schedule_policy_spec.rb
index 9aa50876b55..92ad37145c0 100644
--- a/spec/policies/ci/pipeline_schedule_policy_spec.rb
+++ b/spec/policies/ci/pipeline_schedule_policy_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe Ci::PipelineSchedulePolicy, :models, :clean_gitlab_redis_cache do
end
it 'includes abilities to take ownership' do
- expect(policy).to be_allowed :take_ownership_pipeline_schedule
+ expect(policy).to be_allowed :admin_pipeline_schedule
end
end
end
diff --git a/spec/policies/ci/runner_machine_policy_spec.rb b/spec/policies/ci/runner_machine_policy_spec.rb
new file mode 100644
index 00000000000..8b95f2d7526
--- /dev/null
+++ b/spec/policies/ci/runner_machine_policy_spec.rb
@@ -0,0 +1,176 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::RunnerMachinePolicy, feature_category: :runner_fleet do
+ let_it_be(:owner) { create(:user) }
+
+ describe 'ability :read_runner_machine' do
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+
+ let_it_be_with_reload(:group) { create(:group, name: 'top-level', path: 'top-level') }
+ let_it_be_with_reload(:subgroup) { create(:group, name: 'subgroup', path: 'subgroup', parent: group) }
+ let_it_be_with_reload(:project) { create(:project, group: subgroup) }
+
+ let_it_be(:instance_runner) { create(:ci_runner, :instance, :with_runner_machine) }
+ let_it_be(:group_runner) { create(:ci_runner, :group, :with_runner_machine, groups: [group]) }
+ let_it_be(:project_runner) { create(:ci_runner, :project, :with_runner_machine, projects: [project]) }
+
+ let(:runner_machine) { runner.runner_machines.first }
+
+ subject(:policy) { described_class.new(user, runner_machine) }
+
+ before_all do
+ group.add_guest(guest)
+ group.add_developer(developer)
+ group.add_maintainer(maintainer)
+ group.add_owner(owner)
+ end
+
+ shared_examples 'a policy allowing reading instance runner machine depending on runner sharing' do
+ context 'with instance runner' do
+ let(:runner) { instance_runner }
+
+ it { expect_allowed :read_runner_machine }
+
+ context 'with shared runners disabled on projects' do
+ before do
+ project.update!(shared_runners_enabled: false)
+ end
+
+ it { expect_allowed :read_runner_machine }
+ end
+
+ context 'with shared runners disabled for groups and projects' do
+ before do
+ group.update!(shared_runners_enabled: false)
+ project.update!(shared_runners_enabled: false)
+ end
+
+ it { expect_disallowed :read_runner_machine }
+ end
+ end
+ end
+
+ shared_examples 'a policy allowing reading group runner machine depending on runner sharing' do
+ context 'with group runner' do
+ let(:runner) { group_runner }
+
+ it { expect_allowed :read_runner_machine }
+
+ context 'with sharing of group runners disabled' do
+ before do
+ project.update!(group_runners_enabled: false)
+ end
+
+ it { expect_disallowed :read_runner_machine }
+ end
+ end
+ end
+
+ shared_examples 'does not allow reading runners machines on any scope' do
+ context 'with instance runner' do
+ let(:runner) { instance_runner }
+
+ it { expect_disallowed :read_runner_machine }
+
+ context 'with shared runners disabled for groups and projects' do
+ before do
+ group.update!(shared_runners_enabled: false)
+ project.update!(shared_runners_enabled: false)
+ end
+
+ it { expect_disallowed :read_runner_machine }
+ end
+ end
+
+ context 'with group runner' do
+ let(:runner) { group_runner }
+
+ it { expect_disallowed :read_runner_machine }
+
+ context 'with sharing of group runners disabled' do
+ before do
+ project.update!(group_runners_enabled: false)
+ end
+
+ it { expect_disallowed :read_runner_machine }
+ end
+ end
+
+ context 'with project runner' do
+ let(:runner) { project_runner }
+
+ it { expect_disallowed :read_runner_machine }
+ end
+ end
+
+ context 'without access' do
+ let_it_be(:user) { create(:user) }
+
+ it_behaves_like 'does not allow reading runners machines on any scope'
+ end
+
+ context 'with guest access' do
+ let(:user) { guest }
+
+ it_behaves_like 'does not allow reading runners machines on any scope'
+ end
+
+ context 'with developer access' do
+ let(:user) { developer }
+
+ it_behaves_like 'a policy allowing reading instance runner machine depending on runner sharing'
+
+ it_behaves_like 'a policy allowing reading group runner machine depending on runner sharing'
+
+ context 'with project runner' do
+ let(:runner) { project_runner }
+
+ it { expect_disallowed :read_runner_machine }
+ end
+ end
+
+ context 'with maintainer access' do
+ let(:user) { maintainer }
+
+ it_behaves_like 'a policy allowing reading instance runner machine depending on runner sharing'
+
+ it_behaves_like 'a policy allowing reading group runner machine depending on runner sharing'
+
+ context 'with project runner' do
+ let(:runner) { project_runner }
+
+ it { expect_allowed :read_runner_machine }
+ end
+ end
+
+ context 'with owner access' do
+ let(:user) { owner }
+
+ it_behaves_like 'a policy allowing reading instance runner machine depending on runner sharing'
+
+ context 'with group runner' do
+ let(:runner) { group_runner }
+
+ it { expect_allowed :read_runner_machine }
+
+ context 'with sharing of group runners disabled' do
+ before do
+ project.update!(group_runners_enabled: false)
+ end
+
+ it { expect_allowed :read_runner_machine }
+ end
+ end
+
+ context 'with project runner' do
+ let(:runner) { project_runner }
+
+ it { expect_allowed :read_runner_machine }
+ end
+ end
+ end
+end
diff --git a/spec/policies/design_management/design_policy_spec.rb b/spec/policies/design_management/design_policy_spec.rb
index c62e97dcdb9..1c0270a969e 100644
--- a/spec/policies/design_management/design_policy_spec.rb
+++ b/spec/policies/design_management/design_policy_spec.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
require "spec_helper"
-RSpec.describe DesignManagement::DesignPolicy do
+RSpec.describe DesignManagement::DesignPolicy, feature_category: :portfolio_management do
include DesignManagementTestHelpers
let(:guest_design_abilities) { %i[read_design] }
- let(:developer_design_abilities) { %i[create_design destroy_design move_design] }
+ let(:developer_design_abilities) { %i[create_design destroy_design move_design update_design] }
let(:design_abilities) { guest_design_abilities + developer_design_abilities }
let_it_be(:guest) { create(:user) }
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
index 0575ba3237b..3d6d95bb122 100644
--- a/spec/policies/global_policy_spec.rb
+++ b/spec/policies/global_policy_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
let_it_be(:admin_user) { create(:admin) }
let_it_be(:project_bot) { create(:user, :project_bot) }
+ let_it_be(:service_account) { create(:user, :service_account) }
let_it_be(:migration_bot) { create(:user, :migration_bot) }
let_it_be(:security_bot) { create(:user, :security_bot) }
let_it_be_with_reload(:current_user) { create(:user) }
@@ -219,6 +220,12 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
it { is_expected.to be_allowed(:access_api) }
end
+ context 'service account' do
+ let(:current_user) { service_account }
+
+ it { is_expected.to be_allowed(:access_api) }
+ end
+
context 'migration bot' do
let(:current_user) { migration_bot }
@@ -285,6 +292,7 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
context 'inactive user' do
before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
current_user.update!(confirmed_at: nil, confirmation_sent_at: 5.days.ago)
end
@@ -345,6 +353,12 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
it { is_expected.to be_disallowed(:receive_notifications) }
end
+ context 'service account' do
+ let(:current_user) { service_account }
+
+ it { is_expected.to be_disallowed(:receive_notifications) }
+ end
+
context 'migration bot' do
let(:current_user) { migration_bot }
@@ -399,6 +413,7 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
describe 'inactive user' do
before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
current_user.update!(confirmed_at: nil)
end
@@ -433,6 +448,12 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
it { is_expected.to be_allowed(:access_git) }
end
+ context 'service account' do
+ let(:current_user) { service_account }
+
+ it { is_expected.to be_allowed(:access_git) }
+ end
+
context 'user blocked pending approval' do
before do
current_user.block_pending_approval
@@ -497,6 +518,7 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
describe 'inactive user' do
before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
current_user.update!(confirmed_at: nil)
end
@@ -517,6 +539,12 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
it { is_expected.to be_allowed(:use_slash_commands) }
end
+ context 'service account' do
+ let(:current_user) { service_account }
+
+ it { is_expected.to be_allowed(:use_slash_commands) }
+ end
+
context 'migration bot' do
let(:current_user) { migration_bot }
@@ -571,6 +599,12 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
it { is_expected.to be_disallowed(:log_in) }
end
+ context 'service account' do
+ let(:current_user) { service_account }
+
+ it { is_expected.to be_disallowed(:log_in) }
+ end
+
context 'migration bot' do
let(:current_user) { migration_bot }
@@ -593,57 +627,51 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
end
describe 'create_instance_runners' do
- context 'create_runner_workflow flag enabled' do
- before do
- stub_feature_flags(create_runner_workflow: true)
- end
-
- context 'admin' do
- let(:current_user) { admin_user }
-
- context 'when admin mode is enabled', :enable_admin_mode do
- it { is_expected.to be_allowed(:create_instance_runners) }
- end
+ context 'admin' do
+ let(:current_user) { admin_user }
- context 'when admin mode is disabled' do
- it { is_expected.to be_disallowed(:create_instance_runners) }
- end
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed(:create_instance_runners) }
end
- context 'with project_bot' do
- let(:current_user) { project_bot }
-
+ context 'when admin mode is disabled' do
it { is_expected.to be_disallowed(:create_instance_runners) }
end
+ end
- context 'with migration_bot' do
- let(:current_user) { migration_bot }
+ context 'with project_bot' do
+ let(:current_user) { project_bot }
- it { is_expected.to be_disallowed(:create_instance_runners) }
- end
+ it { is_expected.to be_disallowed(:create_instance_runners) }
+ end
- context 'with security_bot' do
- let(:current_user) { security_bot }
+ context 'with migration_bot' do
+ let(:current_user) { migration_bot }
- it { is_expected.to be_disallowed(:create_instance_runners) }
- end
+ it { is_expected.to be_disallowed(:create_instance_runners) }
+ end
- context 'with regular user' do
- let(:current_user) { user }
+ context 'with security_bot' do
+ let(:current_user) { security_bot }
- it { is_expected.to be_disallowed(:create_instance_runners) }
- end
+ it { is_expected.to be_disallowed(:create_instance_runners) }
+ end
- context 'with anonymous' do
- let(:current_user) { nil }
+ context 'with regular user' do
+ let(:current_user) { user }
- it { is_expected.to be_disallowed(:create_instance_runners) }
- end
+ it { is_expected.to be_disallowed(:create_instance_runners) }
+ end
+
+ context 'with anonymous' do
+ let(:current_user) { nil }
+
+ it { is_expected.to be_disallowed(:create_instance_runners) }
end
- context 'create_runner_workflow flag disabled' do
+ context 'create_runner_workflow_for_admin flag disabled' do
before do
- stub_feature_flags(create_runner_workflow: false)
+ stub_feature_flags(create_runner_workflow_for_admin: false)
end
context 'admin' do
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index 451db9eaf9c..003ca2512dc 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GroupPolicy, feature_category: :authentication_and_authorization do
+RSpec.describe GroupPolicy, feature_category: :system_access do
include AdminModeHelper
include_context 'GroupPolicy context'
@@ -933,13 +933,14 @@ RSpec.describe GroupPolicy, feature_category: :authentication_and_authorization
describe 'observability' do
using RSpec::Parameterized::TableSyntax
- let(:allowed) { be_allowed(:read_observability) }
- let(:disallowed) { be_disallowed(:read_observability) }
+ let(:allowed_admin) { be_allowed(:read_observability) && be_allowed(:admin_observability) }
+ let(:allowed_read) { be_allowed(:read_observability) && be_disallowed(:admin_observability) }
+ let(:disallowed) { be_disallowed(:read_observability) && be_disallowed(:admin_observability) }
# rubocop:disable Layout/LineLength
where(:feature_enabled, :admin_matcher, :owner_matcher, :maintainer_matcher, :developer_matcher, :reporter_matcher, :guest_matcher, :non_member_matcher, :anonymous_matcher) do
false | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed)
- true | ref(:allowed) | ref(:allowed) | ref(:allowed) | ref(:allowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed)
+ true | ref(:allowed_admin) | ref(:allowed_admin) | ref(:allowed_admin) | ref(:allowed_read) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed)
end
# rubocop:enable Layout/LineLength
@@ -1296,9 +1297,9 @@ RSpec.describe GroupPolicy, feature_category: :authentication_and_authorization
end
end
- context 'create_runner_workflow flag enabled' do
+ context 'create_runner_workflow_for_namespace flag enabled' do
before do
- stub_feature_flags(create_runner_workflow: true)
+ stub_feature_flags(create_runner_workflow_for_namespace: [group])
end
context 'admin' do
@@ -1379,11 +1380,13 @@ RSpec.describe GroupPolicy, feature_category: :authentication_and_authorization
end
end
- context 'with create_runner_workflow flag disabled' do
+ context 'with create_runner_workflow_for_namespace flag disabled' do
before do
- stub_feature_flags(create_runner_workflow: false)
+ stub_feature_flags(create_runner_workflow_for_namespace: [other_group])
end
+ let_it_be(:other_group) { create(:group) }
+
context 'admin' do
let(:current_user) { admin }
@@ -1568,4 +1571,22 @@ RSpec.describe GroupPolicy, feature_category: :authentication_and_authorization
end
end
end
+
+ describe 'achievements' do
+ let(:current_user) { owner }
+
+ specify { is_expected.to be_allowed(:read_achievement) }
+ specify { is_expected.to be_allowed(:admin_achievement) }
+ specify { is_expected.to be_allowed(:award_achievement) }
+
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(achievements: false)
+ end
+
+ specify { is_expected.to be_disallowed(:read_achievement) }
+ specify { is_expected.to be_disallowed(:admin_achievement) }
+ specify { is_expected.to be_disallowed(:award_achievement) }
+ end
+ end
end
diff --git a/spec/policies/metrics/dashboard/annotation_policy_spec.rb b/spec/policies/metrics/dashboard/annotation_policy_spec.rb
index 9ea9f843f2c..2d1ef0ee0cb 100644
--- a/spec/policies/metrics/dashboard/annotation_policy_spec.rb
+++ b/spec/policies/metrics/dashboard/annotation_policy_spec.rb
@@ -14,9 +14,7 @@ RSpec.describe Metrics::Dashboard::AnnotationPolicy, :models do
end
it { expect(policy).to be_disallowed :read_metrics_dashboard_annotation }
- it { expect(policy).to be_disallowed :create_metrics_dashboard_annotation }
- it { expect(policy).to be_disallowed :update_metrics_dashboard_annotation }
- it { expect(policy).to be_disallowed :delete_metrics_dashboard_annotation }
+ it { expect(policy).to be_disallowed :admin_metrics_dashboard_annotation }
end
context 'when reporter' do
@@ -25,9 +23,7 @@ RSpec.describe Metrics::Dashboard::AnnotationPolicy, :models do
end
it { expect(policy).to be_allowed :read_metrics_dashboard_annotation }
- it { expect(policy).to be_disallowed :create_metrics_dashboard_annotation }
- it { expect(policy).to be_disallowed :update_metrics_dashboard_annotation }
- it { expect(policy).to be_disallowed :delete_metrics_dashboard_annotation }
+ it { expect(policy).to be_disallowed :admin_metrics_dashboard_annotation }
end
context 'when developer' do
@@ -36,9 +32,7 @@ RSpec.describe Metrics::Dashboard::AnnotationPolicy, :models do
end
it { expect(policy).to be_allowed :read_metrics_dashboard_annotation }
- it { expect(policy).to be_allowed :create_metrics_dashboard_annotation }
- it { expect(policy).to be_allowed :update_metrics_dashboard_annotation }
- it { expect(policy).to be_allowed :delete_metrics_dashboard_annotation }
+ it { expect(policy).to be_allowed :admin_metrics_dashboard_annotation }
end
context 'when maintainer' do
@@ -47,9 +41,7 @@ RSpec.describe Metrics::Dashboard::AnnotationPolicy, :models do
end
it { expect(policy).to be_allowed :read_metrics_dashboard_annotation }
- it { expect(policy).to be_allowed :create_metrics_dashboard_annotation }
- it { expect(policy).to be_allowed :update_metrics_dashboard_annotation }
- it { expect(policy).to be_allowed :delete_metrics_dashboard_annotation }
+ it { expect(policy).to be_allowed :admin_metrics_dashboard_annotation }
end
end
diff --git a/spec/policies/project_group_link_policy_spec.rb b/spec/policies/project_group_link_policy_spec.rb
index 7c8a4619e47..9461f33decb 100644
--- a/spec/policies/project_group_link_policy_spec.rb
+++ b/spec/policies/project_group_link_policy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProjectGroupLinkPolicy, feature_category: :authentication_and_authorization do
+RSpec.describe ProjectGroupLinkPolicy, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:group2) { create(:group, :private) }
diff --git a/spec/policies/project_hook_policy_spec.rb b/spec/policies/project_hook_policy_spec.rb
index cfa7b6ee4bf..a71940c319e 100644
--- a/spec/policies/project_hook_policy_spec.rb
+++ b/spec/policies/project_hook_policy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProjectHookPolicy do
+RSpec.describe ProjectHookPolicy, feature_category: :integrations do
let_it_be(:user) { create(:user) }
let(:hook) { create(:project_hook) }
@@ -15,7 +15,7 @@ RSpec.describe ProjectHookPolicy do
end
it "cannot read and destroy web-hooks" do
- expect(policy).to be_disallowed(:read_web_hook, :destroy_web_hook)
+ expect(policy).to be_disallowed(:destroy_web_hook)
end
end
@@ -25,7 +25,7 @@ RSpec.describe ProjectHookPolicy do
end
it "can read and destroy web-hooks" do
- expect(policy).to be_allowed(:read_web_hook, :destroy_web_hook)
+ expect(policy).to be_allowed(:destroy_web_hook)
end
end
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index b2fb310aca3..3759539677a 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorization do
+RSpec.describe ProjectPolicy, feature_category: :system_access do
include ExternalAuthorizationServiceHelpers
include AdminModeHelper
include_context 'ProjectPolicy context'
@@ -441,6 +441,36 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
end
end
+ context 'importing work items' do
+ %w(reporter developer maintainer owner).each do |role|
+ context "with #{role}" do
+ let(:current_user) { send(role) }
+
+ it { is_expected.to be_allowed(:import_work_items) }
+ end
+ end
+
+ %w(guest anonymous).each do |role|
+ context "with #{role}" do
+ let(:current_user) { send(role) }
+
+ it { is_expected.to be_disallowed(:import_work_items) }
+ end
+ end
+
+ context 'with an admin' do
+ let(:current_user) { admin }
+
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { expect_allowed(:import_work_items) }
+ end
+
+ context 'when admin mode is disabled' do
+ it { expect_disallowed(:import_work_items) }
+ end
+ end
+ end
+
context 'reading usage quotas' do
%w(maintainer owner).each do |role|
context "with #{role}" do
@@ -1219,7 +1249,7 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
it { is_expected.to be_allowed(:create_package) }
it { is_expected.to be_allowed(:read_package) }
it { is_expected.to be_allowed(:read_project) }
- it { is_expected.to be_disallowed(:destroy_package) }
+ it { is_expected.to be_allowed(:destroy_package) }
it_behaves_like 'package access with repository disabled'
end
@@ -1400,6 +1430,28 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
end
end
+ context 'infrastructure aws feature' do
+ %w(guest reporter developer).each do |role|
+ context role do
+ let(:current_user) { send(role) }
+
+ it 'disallows managing aws' do
+ expect_disallowed(:admin_project_aws)
+ end
+ end
+ end
+
+ %w(maintainer owner).each do |role|
+ context role do
+ let(:current_user) { send(role) }
+
+ it 'allows managing aws' do
+ expect_allowed(:admin_project_aws)
+ end
+ end
+ end
+ end
+
describe 'design permissions' do
include DesignManagementTestHelpers
@@ -2275,6 +2327,12 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
describe 'infrastructure feature' do
using RSpec::Parameterized::TableSyntax
+ before do
+ # assuming the default setting terraform_state.enabled=true
+ # the terraform_state permissions should follow the same logic as the other features
+ stub_config(terraform_state: { enabled: true })
+ end
+
let(:guest_permissions) { [] }
let(:developer_permissions) do
@@ -2338,10 +2396,35 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
end
end
end
+
+ context 'when terraform state management is disabled' do
+ before do
+ stub_config(terraform_state: { enabled: false })
+ end
+
+ with_them do
+ let(:current_user) { user_subject(role) }
+ let(:project) { project_subject(project_visibility) }
+
+ let(:developer_permissions) do
+ [:read_terraform_state]
+ end
+
+ let(:maintainer_permissions) do
+ developer_permissions + [:admin_terraform_state]
+ end
+
+ it 'always disallows the terraform_state feature' do
+ project.project_feature.update!(infrastructure_access_level: access_level)
+
+ expect_disallowed(*permissions_abilities(role))
+ end
+ end
+ end
end
describe 'access_security_and_compliance' do
- context 'when the "Security & Compliance" is enabled' do
+ context 'when the "Security and Compliance" is enabled' do
before do
project.project_feature.update!(security_and_compliance_access_level: Featurable::PRIVATE)
end
@@ -2387,7 +2470,7 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
end
end
- context 'when the "Security & Compliance" is not enabled' do
+ context 'when the "Security and Compliance" is not enabled' do
before do
project.project_feature.update!(security_and_compliance_access_level: Featurable::DISABLED)
end
@@ -2740,9 +2823,9 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
end
describe 'create_project_runners' do
- context 'create_runner_workflow flag enabled' do
+ context 'create_runner_workflow_for_namespace flag enabled' do
before do
- stub_feature_flags(create_runner_workflow: true)
+ stub_feature_flags(create_runner_workflow_for_namespace: [project.namespace])
end
context 'admin' do
@@ -2810,9 +2893,9 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
end
end
- context 'create_runner_workflow flag disabled' do
+ context 'create_runner_workflow_for_namespace flag disabled' do
before do
- stub_feature_flags(create_runner_workflow: false)
+ stub_feature_flags(create_runner_workflow_for_namespace: [group])
end
context 'admin' do
@@ -2981,6 +3064,26 @@ RSpec.describe ProjectPolicy, feature_category: :authentication_and_authorizatio
end
end
+ describe 'add_catalog_resource' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:current_user) { public_send(role) }
+
+ where(:role, :allowed) do
+ :owner | true
+ :maintainer | false
+ :developer | false
+ :reporter | false
+ :guest | false
+ end
+
+ with_them do
+ it do
+ expect(subject.can?(:add_catalog_resource)).to be(allowed)
+ end
+ end
+ end
+
describe 'read_code' do
let(:current_user) { create(:user) }
diff --git a/spec/presenters/blob_presenter_spec.rb b/spec/presenters/blob_presenter_spec.rb
index f8cba8e9203..f10150b819a 100644
--- a/spec/presenters/blob_presenter_spec.rb
+++ b/spec/presenters/blob_presenter_spec.rb
@@ -60,9 +60,13 @@ RSpec.describe BlobPresenter do
describe '#pipeline_editor_path' do
context 'when blob is .gitlab-ci.yml' do
before do
- project.repository.create_file(user, '.gitlab-ci.yml', '',
- message: 'Add a ci file',
- branch_name: 'main')
+ project.repository.create_file(
+ user,
+ '.gitlab-ci.yml',
+ '',
+ message: 'Add a ci file',
+ branch_name: 'main'
+ )
end
let(:blob) { repository.blob_at('main', '.gitlab-ci.yml') }
diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb
index dedfe6925c5..3f30127b07f 100644
--- a/spec/presenters/ci/build_runner_presenter_spec.rb
+++ b/spec/presenters/ci/build_runner_presenter_spec.rb
@@ -228,16 +228,20 @@ RSpec.describe Ci::BuildRunnerPresenter do
let(:pipeline) { build.pipeline }
it 'returns the correct refspecs' do
- is_expected.to contain_exactly("+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}",
- "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
+ is_expected.to contain_exactly(
+ "+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}",
+ "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}"
+ )
end
context 'when ref is tag' do
let(:build) { create(:ci_build, :tag) }
it 'returns the correct refspecs' do
- is_expected.to contain_exactly("+refs/tags/#{build.ref}:refs/tags/#{build.ref}",
- "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
+ is_expected.to contain_exactly(
+ "+refs/tags/#{build.ref}:refs/tags/#{build.ref}",
+ "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}"
+ )
end
context 'when GIT_DEPTH is zero' do
@@ -246,9 +250,11 @@ RSpec.describe Ci::BuildRunnerPresenter do
end
it 'returns the correct refspecs' do
- is_expected.to contain_exactly('+refs/tags/*:refs/tags/*',
- '+refs/heads/*:refs/remotes/origin/*',
- "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
+ is_expected.to contain_exactly(
+ '+refs/tags/*:refs/tags/*',
+ '+refs/heads/*:refs/remotes/origin/*',
+ "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}"
+ )
end
end
end
@@ -273,10 +279,11 @@ RSpec.describe Ci::BuildRunnerPresenter do
end
it 'returns the correct refspecs' do
- is_expected
- .to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
- '+refs/heads/*:refs/remotes/origin/*',
- '+refs/tags/*:refs/tags/*')
+ is_expected.to contain_exactly(
+ "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
+ '+refs/heads/*:refs/remotes/origin/*',
+ '+refs/tags/*:refs/tags/*'
+ )
end
end
@@ -284,8 +291,10 @@ RSpec.describe Ci::BuildRunnerPresenter do
let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
it 'returns the correct refspecs' do
- is_expected.to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
- "+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
+ is_expected.to contain_exactly(
+ "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
+ "+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}"
+ )
end
end
end
@@ -301,9 +310,10 @@ RSpec.describe Ci::BuildRunnerPresenter do
end
it 'exposes the persistent pipeline ref' do
- is_expected
- .to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
- "+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
+ is_expected.to contain_exactly(
+ "+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
+ "+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}"
+ )
end
end
end
@@ -327,16 +337,14 @@ RSpec.describe Ci::BuildRunnerPresenter do
context 'when there is a file variable to expand' do
before_all do
- create(:ci_variable, project: project,
- key: 'regular_var',
- value: 'value 1')
- create(:ci_variable, project: project,
- key: 'file_var',
- value: 'value 2',
- variable_type: :file)
- create(:ci_variable, project: project,
- key: 'var_with_variables',
- value: 'value 3 and $regular_var and $file_var and $undefined_var')
+ create(:ci_variable, project: project, key: 'regular_var', value: 'value 1')
+ create(:ci_variable, project: project, key: 'file_var', value: 'value 2', variable_type: :file)
+ create(
+ :ci_variable,
+ project: project,
+ key: 'var_with_variables',
+ value: 'value 3 and $regular_var and $file_var and $undefined_var'
+ )
end
it 'returns variables with expanded' do
@@ -353,16 +361,14 @@ RSpec.describe Ci::BuildRunnerPresenter do
context 'when there is a raw variable to expand' do
before_all do
- create(:ci_variable, project: project,
- key: 'regular_var',
- value: 'value 1')
- create(:ci_variable, project: project,
- key: 'raw_var',
- value: 'value 2',
- raw: true)
- create(:ci_variable, project: project,
- key: 'var_with_variables',
- value: 'value 3 and $regular_var and $raw_var and $undefined_var')
+ create(:ci_variable, project: project, key: 'regular_var', value: 'value 1')
+ create(:ci_variable, project: project, key: 'raw_var', value: 'value 2', raw: true)
+ create(
+ :ci_variable,
+ project: project,
+ key: 'var_with_variables',
+ value: 'value 3 and $regular_var and $raw_var and $undefined_var'
+ )
end
it 'returns expanded variables without expanding raws' do
diff --git a/spec/presenters/commit_presenter_spec.rb b/spec/presenters/commit_presenter_spec.rb
index eba393da2b7..5ac270a8df8 100644
--- a/spec/presenters/commit_presenter_spec.rb
+++ b/spec/presenters/commit_presenter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CommitPresenter do
+RSpec.describe CommitPresenter, feature_category: :source_code_management do
let(:commit) { project.commit }
let(:presenter) { described_class.new(commit, current_user: user) }
@@ -95,4 +95,15 @@ RSpec.describe CommitPresenter do
expect(presenter.signature_html).to eq(signature)
end
end
+
+ describe '#tags_for_display' do
+ subject { presenter.tags_for_display }
+
+ let(:stubbed_tags) { %w[refs/tags/v1.0 refs/tags/v1.1] }
+
+ it 'removes the refs prefix from tags' do
+ allow(commit).to receive(:referenced_by).and_return(stubbed_tags)
+ expect(subject).to eq(%w[v1.0 v1.1])
+ end
+ end
end
diff --git a/spec/presenters/issue_presenter_spec.rb b/spec/presenters/issue_presenter_spec.rb
index 22a86d04a5a..1e8fda08bdb 100644
--- a/spec/presenters/issue_presenter_spec.rb
+++ b/spec/presenters/issue_presenter_spec.rb
@@ -35,16 +35,6 @@ RSpec.describe IssuePresenter do
context 'when issue type is task' do
let(:presented_issue) { task }
- context 'when use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- it 'returns a work item url for the task' do
- expect(presenter.web_url).to eq(project_work_items_url(project, work_items_path: presented_issue.id))
- end
- end
-
it 'returns a work item url using iid for the task' do
expect(presenter.web_url).to eq(
project_work_items_url(project, work_items_path: presented_issue.iid, iid_path: true)
@@ -75,16 +65,6 @@ RSpec.describe IssuePresenter do
context 'when issue type is task' do
let(:presented_issue) { task }
- context 'when use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- it 'returns a work item path for the task' do
- expect(presenter.issue_path).to eq(project_work_items_path(project, work_items_path: presented_issue.id))
- end
- end
-
it 'returns a work item path using iid for the task' do
expect(presenter.issue_path).to eq(
project_work_items_path(project, work_items_path: presented_issue.iid, iid_path: true)
diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb
index 31aa4778d3c..6f40d3f5b48 100644
--- a/spec/presenters/merge_request_presenter_spec.rb
+++ b/spec/presenters/merge_request_presenter_spec.rb
@@ -125,9 +125,12 @@ RSpec.describe MergeRequestPresenter do
let_it_be(:issue_b) { create(:issue, project: project) }
let_it_be(:resource) do
- create(:merge_request,
- source_project: project, target_project: project,
- description: "Fixes #{issue_a.to_reference} Related #{issue_b.to_reference}")
+ create(
+ :merge_request,
+ source_project: project,
+ target_project: project,
+ description: "Fixes #{issue_a.to_reference} Related #{issue_b.to_reference}"
+ )
end
before_all do
diff --git a/spec/presenters/packages/detail/package_presenter_spec.rb b/spec/presenters/packages/detail/package_presenter_spec.rb
index 71ec3ee2d67..8caa70c988e 100644
--- a/spec/presenters/packages/detail/package_presenter_spec.rb
+++ b/spec/presenters/packages/detail/package_presenter_spec.rb
@@ -89,8 +89,7 @@ RSpec.describe ::Packages::Detail::PackagePresenter do
let_it_be(:package) { create(:npm_package, :with_build, project: project) }
let_it_be(:package_file_build_info) do
- create(:package_file_build_info, package_file: package.package_files.first,
- pipeline: package.pipelines.first)
+ create(:package_file_build_info, package_file: package.package_files.first, pipeline: package.pipelines.first)
end
it 'returns details with package_file pipeline' do
diff --git a/spec/rails_autoload.rb b/spec/rails_autoload.rb
new file mode 100644
index 00000000000..d3518acf8b2
--- /dev/null
+++ b/spec/rails_autoload.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+# Mimics Rails autoloading with zeitwerk when used outside of Rails.
+# This is used in:
+# * fast_spec_helper
+# * scripts/setup-test-env
+
+require 'zeitwerk'
+require 'active_support/string_inquirer'
+
+module Rails
+ extend self
+
+ def root
+ Pathname.new(File.expand_path('..', __dir__))
+ end
+
+ def env
+ @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test")
+ end
+
+ def autoloaders
+ @autoloaders ||= [
+ Zeitwerk::Loader.new.tap do |loader|
+ loader.inflector = _autoloader_inflector
+ end
+ ]
+ end
+
+ private
+
+ def _autoloader_inflector
+ # Try Rails 7 first.
+ require 'rails/autoloaders/inflector'
+
+ Rails::Autoloaders::Inflector
+ rescue LoadError
+ # Fallback to Rails 6.
+ require 'active_support/dependencies'
+ require 'active_support/dependencies/zeitwerk_integration'
+
+ ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
+ end
+end
+
+require_relative '../lib/gitlab'
+require_relative '../config/initializers/0_inject_enterprise_edition_module'
+require_relative '../config/initializers_before_autoloader/000_inflections'
+require_relative '../config/initializers_before_autoloader/004_zeitwerk'
+
+Rails.autoloaders.each do |autoloader|
+ autoloader.push_dir('lib')
+ autoloader.push_dir('ee/lib') if Gitlab.ee?
+ autoloader.push_dir('jh/lib') if Gitlab.jh?
+ autoloader.setup
+end
diff --git a/spec/requests/admin/abuse_reports_controller_spec.rb b/spec/requests/admin/abuse_reports_controller_spec.rb
new file mode 100644
index 00000000000..3d3bfcd3f60
--- /dev/null
+++ b/spec/requests/admin/abuse_reports_controller_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::AbuseReportsController, type: :request, feature_category: :insider_threat do
+ include AdminModeHelper
+
+ let_it_be(:admin) { create(:admin) }
+
+ before do
+ enable_admin_mode!(admin)
+ sign_in(admin)
+ end
+
+ describe 'GET #index' do
+ let!(:open_report) { create(:abuse_report) }
+ let!(:closed_report) { create(:abuse_report, :closed) }
+
+ it 'returns open reports by default' do
+ get admin_abuse_reports_path
+
+ expect(assigns(:abuse_reports).count).to eq 1
+ expect(assigns(:abuse_reports).first.open?).to eq true
+ end
+
+ it 'returns reports by specified status' do
+ get admin_abuse_reports_path, params: { status: 'closed' }
+
+ expect(assigns(:abuse_reports).count).to eq 1
+ 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 'returns all reports by default' do
+ get admin_abuse_reports_path
+
+ expect(assigns(:abuse_reports).count).to eq 2
+ end
+ end
+ end
+end
diff --git a/spec/requests/admin/applications_controller_spec.rb b/spec/requests/admin/applications_controller_spec.rb
index c83137ebbce..367697b1289 100644
--- a/spec/requests/admin/applications_controller_spec.rb
+++ b/spec/requests/admin/applications_controller_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Admin::ApplicationsController, :enable_admin_mode,
-feature_category: :authentication_and_authorization do
+feature_category: :system_access do
let_it_be(:admin) { create(:admin) }
let_it_be(:application) { create(:oauth_application, owner_id: nil, owner_type: nil) }
let_it_be(:show_path) { admin_application_path(application) }
diff --git a/spec/requests/admin/broadcast_messages_controller_spec.rb b/spec/requests/admin/broadcast_messages_controller_spec.rb
index 69b84d6d795..0143c9ce030 100644
--- a/spec/requests/admin/broadcast_messages_controller_spec.rb
+++ b/spec/requests/admin/broadcast_messages_controller_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe Admin::BroadcastMessagesController, :enable_admin_mode, feature_c
let_it_be(:invalid_broadcast_message) { { broadcast_message: { message: '' } } }
let_it_be(:test_message) { 'you owe me a new acorn' }
+ let_it_be(:test_preview) { '<p>Hello, world!</p>' }
before do
sign_in(create(:admin))
@@ -23,11 +24,11 @@ RSpec.describe Admin::BroadcastMessagesController, :enable_admin_mode, feature_c
end
describe 'POST /preview' do
- it 'renders preview partial' do
+ it 'renders preview html' do
post preview_admin_broadcast_messages_path, params: { broadcast_message: { message: "Hello, world!" } }
expect(response).to have_gitlab_http_status(:ok)
- expect(response.body).to render_template(:_preview)
+ expect(response.body).to eq(test_preview)
end
end
diff --git a/spec/requests/admin/impersonation_tokens_controller_spec.rb b/spec/requests/admin/impersonation_tokens_controller_spec.rb
index 15212db0e77..11fc5d94292 100644
--- a/spec/requests/admin/impersonation_tokens_controller_spec.rb
+++ b/spec/requests/admin/impersonation_tokens_controller_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Admin::ImpersonationTokensController, :enable_admin_mode,
-feature_category: :authentication_and_authorization do
+feature_category: :system_access do
let(:admin) { create(:admin) }
let!(:user) { create(:user) }
diff --git a/spec/requests/admin/projects_controller_spec.rb b/spec/requests/admin/projects_controller_spec.rb
new file mode 100644
index 00000000000..5ff49a30ed8
--- /dev/null
+++ b/spec/requests/admin/projects_controller_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::ProjectsController, :enable_admin_mode, feature_category: :projects do
+ let_it_be(:project) { create(:project, :public, name: 'test', description: 'test') }
+ let_it_be(:admin) { create(:admin) }
+
+ describe 'PUT #update' do
+ let(:project_params) { {} }
+ let(:params) { { project: project_params } }
+ let(:path_params) { { namespace_id: project.namespace.to_param, id: project.to_param } }
+
+ before do
+ sign_in(admin)
+ end
+
+ subject do
+ put admin_namespace_project_path(path_params), params: params
+ end
+
+ context 'when changing the name' do
+ let(:project_params) { { name: 'new name' } }
+
+ it 'returns success' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:found)
+ end
+
+ it 'changes the name' do
+ expect { subject }.to change { project.reload.name }.to('new name')
+ end
+ end
+
+ context 'when changing the description' do
+ let(:project_params) { { description: 'new description' } }
+
+ it 'returns success' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:found)
+ end
+
+ it 'changes the project description' do
+ expect { subject }.to change { project.reload.description }.to('new description')
+ end
+ end
+
+ context 'when changing the name to an invalid name' do
+ let(:project_params) { { name: 'invalid/project/name' } }
+
+ it 'does not change the name' do
+ expect { subject }.not_to change { project.reload.name }
+ end
+ end
+ end
+end
diff --git a/spec/requests/admin/version_check_controller_spec.rb b/spec/requests/admin/version_check_controller_spec.rb
index 47221bf37e5..a998c2f426b 100644
--- a/spec/requests/admin/version_check_controller_spec.rb
+++ b/spec/requests/admin/version_check_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Admin::VersionCheckController, :enable_admin_mode, feature_category: :not_owned do
+RSpec.describe Admin::VersionCheckController, :enable_admin_mode, feature_category: :shared do
let(:admin) { create(:admin) }
before do
diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb
index 8c14ead9e42..45d1594c734 100644
--- a/spec/requests/api/access_requests_spec.rb
+++ b/spec/requests/api/access_requests_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::AccessRequests, feature_category: :authentication_and_authorization do
+RSpec.describe API::AccessRequests, feature_category: :system_access do
let_it_be(:maintainer) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:access_requester) { create(:user) }
diff --git a/spec/requests/api/admin/batched_background_migrations_spec.rb b/spec/requests/api/admin/batched_background_migrations_spec.rb
index d946ac17f3f..e88fba3fbe7 100644
--- a/spec/requests/api/admin/batched_background_migrations_spec.rb
+++ b/spec/requests/api/admin/batched_background_migrations_spec.rb
@@ -4,22 +4,23 @@ require 'spec_helper'
RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :database do
let(:admin) { create(:admin) }
- let(:unauthorized_user) { create(:user) }
describe 'GET /admin/batched_background_migrations/:id' do
let!(:migration) { create(:batched_background_migration, :paused) }
let(:database) { :main }
let(:params) { { database: database } }
+ let(:path) { "/admin/batched_background_migrations/#{migration.id}" }
+
+ it_behaves_like "GET request permissions for admin mode"
subject(:show_migration) do
- get api("/admin/batched_background_migrations/#{migration.id}", admin), params: { database: database }
+ get api(path, admin, admin_mode: true), params: { database: database }
end
it 'fetches the batched background migration' do
show_migration
aggregate_failures "testing response" do
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response['id']).to eq(migration.id)
expect(json_response['status']).to eq('paused')
expect(json_response['job_class_name']).to eq(migration.job_class_name)
@@ -29,7 +30,8 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
context 'when the batched background migration does not exist' do
it 'returns 404' do
- get api("/admin/batched_background_migrations/#{non_existing_record_id}", admin), params: params
+ get api("/admin/batched_background_migrations/#{non_existing_record_id}", admin, admin_mode: true),
+ params: params
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -50,19 +52,11 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
end
end
- context 'when authenticated as a non-admin user' do
- it 'returns 403' do
- get api("/admin/batched_background_migrations/#{migration.id}", unauthorized_user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
context 'when the database name does not exist' do
let(:database) { :wrong_database }
- it 'returns bad request' do
- get api("/admin/batched_background_migrations/#{migration.id}", admin), params: params
+ it 'returns bad request', :aggregate_failures do
+ get api(path, admin, admin_mode: true), params: params
expect(response).to have_gitlab_http_status(:bad_request)
expect(response.body).to include('database does not have a valid value')
@@ -72,13 +66,15 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
describe 'GET /admin/batched_background_migrations' do
let!(:migration) { create(:batched_background_migration) }
+ let(:path) { '/admin/batched_background_migrations' }
+
+ it_behaves_like "GET request permissions for admin mode"
context 'when is an admin user' do
it 'returns batched background migrations' do
- get api('/admin/batched_background_migrations', admin)
+ get api(path, admin, admin_mode: true)
aggregate_failures "testing response" do
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to eq(1)
expect(json_response.first['id']).to eq(migration.id)
expect(json_response.first['job_class_name']).to eq(migration.job_class_name)
@@ -105,14 +101,14 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(ci_model.connection).and_yield
- get api('/admin/batched_background_migrations', admin), params: params
+ get api(path, admin, admin_mode: true), params: params
end
context 'when the database name does not exist' do
let(:database) { :wrong_database }
- it 'returns bad request' do
- get api("/admin/batched_background_migrations", admin), params: params
+ it 'returns bad request', :aggregate_failures do
+ get api(path, admin, admin_mode: true), params: params
expect(response).to have_gitlab_http_status(:bad_request)
expect(response.body).to include('database does not have a valid value')
@@ -127,10 +123,9 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
create(:batched_background_migration, :active, gitlab_schema: schema)
end
- get api('/admin/batched_background_migrations', admin), params: params
+ get api(path, admin, admin_mode: true), params: params
aggregate_failures "testing response" do
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to eq(1)
expect(json_response.first['id']).to eq(ci_database_migration.id)
expect(json_response.first['job_class_name']).to eq(ci_database_migration.job_class_name)
@@ -142,30 +137,24 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
end
end
end
-
- context 'when authenticated as a non-admin user' do
- it 'returns 403' do
- get api('/admin/batched_background_migrations', unauthorized_user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
end
describe 'PUT /admin/batched_background_migrations/:id/resume' do
let!(:migration) { create(:batched_background_migration, :paused) }
let(:database) { :main }
let(:params) { { database: database } }
+ let(:path) { "/admin/batched_background_migrations/#{migration.id}/resume" }
+
+ it_behaves_like "PUT request permissions for admin mode"
subject(:resume) do
- put api("/admin/batched_background_migrations/#{migration.id}/resume", admin), params: params
+ put api(path, admin, admin_mode: true), params: params
end
it 'pauses the batched background migration' do
resume
aggregate_failures "testing response" do
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response['id']).to eq(migration.id)
expect(json_response['status']).to eq('active')
end
@@ -173,7 +162,8 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
context 'when the batched background migration does not exist' do
it 'returns 404' do
- put api("/admin/batched_background_migrations/#{non_existing_record_id}/resume", admin), params: params
+ put api("/admin/batched_background_migrations/#{non_existing_record_id}/resume", admin, admin_mode: true),
+ params: params
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -183,7 +173,7 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
let!(:migration) { create(:batched_background_migration, :failed) }
it 'returns 422' do
- put api("/admin/batched_background_migrations/#{migration.id}/resume", admin), params: params
+ put api(path, admin, admin_mode: true), params: params
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
@@ -206,34 +196,28 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
context 'when the database name does not exist' do
let(:database) { :wrong_database }
- it 'returns bad request' do
- put api("/admin/batched_background_migrations/#{migration.id}/resume", admin), params: params
+ it 'returns bad request', :aggregate_failures do
+ put api(path, admin, admin_mode: true), params: params
expect(response).to have_gitlab_http_status(:bad_request)
expect(response.body).to include('database does not have a valid value')
end
end
end
-
- context 'when authenticated as a non-admin user' do
- it 'returns 403' do
- put api("/admin/batched_background_migrations/#{migration.id}/resume", unauthorized_user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
end
describe 'PUT /admin/batched_background_migrations/:id/pause' do
let!(:migration) { create(:batched_background_migration, :active) }
let(:database) { :main }
let(:params) { { database: database } }
+ let(:path) { "/admin/batched_background_migrations/#{migration.id}/pause" }
+
+ it_behaves_like "PUT request permissions for admin mode"
it 'pauses the batched background migration' do
- put api("/admin/batched_background_migrations/#{migration.id}/pause", admin), params: params
+ put api(path, admin, admin_mode: true), params: params
aggregate_failures "testing response" do
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response['id']).to eq(migration.id)
expect(json_response['status']).to eq('paused')
end
@@ -241,7 +225,8 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
context 'when the batched background migration does not exist' do
it 'returns 404' do
- put api("/admin/batched_background_migrations/#{non_existing_record_id}/pause", admin), params: params
+ put api("/admin/batched_background_migrations/#{non_existing_record_id}/pause", admin, admin_mode: true),
+ params: params
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -251,7 +236,7 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
let!(:migration) { create(:batched_background_migration, :failed) }
it 'returns 422' do
- put api("/admin/batched_background_migrations/#{migration.id}/pause", admin), params: params
+ put api(path, admin, admin_mode: true), params: params
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
@@ -268,27 +253,19 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab
it 'uses the correct connection' do
expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(ci_model.connection).and_yield
- put api("/admin/batched_background_migrations/#{migration.id}/pause", admin), params: params
+ put api(path, admin, admin_mode: true), params: params
end
context 'when the database name does not exist' do
let(:database) { :wrong_database }
- it 'returns bad request' do
- put api("/admin/batched_background_migrations/#{migration.id}/pause", admin), params: params
+ it 'returns bad request', :aggregate_failures do
+ put api(path, admin, admin_mode: true), params: params
expect(response).to have_gitlab_http_status(:bad_request)
expect(response.body).to include('database does not have a valid value')
end
end
end
-
- context 'when authenticated as a non-admin user' do
- it 'returns 403' do
- put api("/admin/batched_background_migrations/#{non_existing_record_id}/pause", unauthorized_user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
end
end
diff --git a/spec/requests/api/admin/ci/variables_spec.rb b/spec/requests/api/admin/ci/variables_spec.rb
index 4bdc44cb583..dd4171b257a 100644
--- a/spec/requests/api/admin/ci/variables_spec.rb
+++ b/spec/requests/api/admin/ci/variables_spec.rb
@@ -5,68 +5,60 @@ require 'spec_helper'
RSpec.describe ::API::Admin::Ci::Variables do
let_it_be(:admin) { create(:admin) }
let_it_be(:user) { create(:user) }
+ let_it_be(:variable) { create(:ci_instance_variable) }
+ let_it_be(:path) { '/admin/ci/variables' }
describe 'GET /admin/ci/variables' do
- let!(:variable) { create(:ci_instance_variable) }
+ it_behaves_like 'GET request permissions for admin mode'
it 'returns instance-level variables for admins', :aggregate_failures do
- get api('/admin/ci/variables', admin)
+ get api(path, admin, admin_mode: true)
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_a(Array)
end
- it 'does not return instance-level variables for regular users' do
- get api('/admin/ci/variables', user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
-
it 'does not return instance-level variables for unauthorized users' do
- get api('/admin/ci/variables')
+ get api(path, admin_mode: true)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
describe 'GET /admin/ci/variables/:key' do
- let!(:variable) { create(:ci_instance_variable) }
+ let_it_be(:path) { "/admin/ci/variables/#{variable.key}" }
+
+ it_behaves_like 'GET request permissions for admin mode'
it 'returns instance-level variable details for admins', :aggregate_failures do
- get api("/admin/ci/variables/#{variable.key}", admin)
+ get api(path, admin, admin_mode: true)
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response['value']).to eq(variable.value)
expect(json_response['protected']).to eq(variable.protected?)
expect(json_response['variable_type']).to eq(variable.variable_type)
end
it 'responds with 404 Not Found if requesting non-existing variable' do
- get api('/admin/ci/variables/non_existing_variable', admin)
+ get api('/admin/ci/variables/non_existing_variable', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
- it 'does not return instance-level variable details for regular users' do
- get api("/admin/ci/variables/#{variable.key}", user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
-
it 'does not return instance-level variable details for unauthorized users' do
- get api("/admin/ci/variables/#{variable.key}")
+ get api(path, admin_mode: true)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
describe 'POST /admin/ci/variables' do
- context 'authorized user with proper permissions' do
- let!(:variable) { create(:ci_instance_variable) }
+ it_behaves_like 'POST request permissions for admin mode' do
+ let(:params) { { key: 'KEY', value: 'VALUE' } }
+ end
+ context 'authorized user with proper permissions' do
it 'creates variable for admins', :aggregate_failures do
expect do
- post api('/admin/ci/variables', admin),
+ post api(path, admin, admin_mode: true),
params: {
key: 'TEST_VARIABLE_2',
value: 'PROTECTED_VALUE_2',
@@ -76,7 +68,6 @@ RSpec.describe ::API::Admin::Ci::Variables do
}
end.to change { ::Ci::InstanceVariable.count }.by(1)
- expect(response).to have_gitlab_http_status(:created)
expect(json_response['key']).to eq('TEST_VARIABLE_2')
expect(json_response['value']).to eq('PROTECTED_VALUE_2')
expect(json_response['protected']).to be_truthy
@@ -90,13 +81,13 @@ RSpec.describe ::API::Admin::Ci::Variables do
expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
- post api("/admin/ci/variables", user),
+ post api(path, user, admin_mode: true),
params: { key: 'VAR_KEY', value: 'SENSITIVE', protected: true, masked: true }
end
it 'creates variable with optional attributes', :aggregate_failures do
expect do
- post api('/admin/ci/variables', admin),
+ post api(path, admin, admin_mode: true),
params: {
variable_type: 'file',
key: 'TEST_VARIABLE_2',
@@ -104,7 +95,6 @@ RSpec.describe ::API::Admin::Ci::Variables do
}
end.to change { ::Ci::InstanceVariable.count }.by(1)
- expect(response).to have_gitlab_http_status(:created)
expect(json_response['key']).to eq('TEST_VARIABLE_2')
expect(json_response['value']).to eq('VALUE_2')
expect(json_response['protected']).to be_falsey
@@ -115,20 +105,20 @@ RSpec.describe ::API::Admin::Ci::Variables do
it 'does not allow to duplicate variable key' do
expect do
- post api('/admin/ci/variables', admin),
+ post api(path, admin, admin_mode: true),
params: { key: variable.key, value: 'VALUE_2' }
end.not_to change { ::Ci::InstanceVariable.count }
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'does not allow values above 10,000 characters' do
+ it 'does not allow values above 10,000 characters', :aggregate_failures do
too_long_message = <<~MESSAGE.strip
The value of the provided variable exceeds the 10000 character limit
MESSAGE
expect do
- post api('/admin/ci/variables', admin),
+ post api(path, admin, admin_mode: true),
params: { key: 'too_long', value: SecureRandom.hex(10_001) }
end.not_to change { ::Ci::InstanceVariable.count }
@@ -138,17 +128,9 @@ RSpec.describe ::API::Admin::Ci::Variables do
end
end
- context 'authorized user with invalid permissions' do
- it 'does not create variable' do
- post api('/admin/ci/variables', user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
context 'unauthorized user' do
it 'does not create variable' do
- post api('/admin/ci/variables')
+ post api(path, admin_mode: true)
expect(response).to have_gitlab_http_status(:unauthorized)
end
@@ -156,20 +138,23 @@ RSpec.describe ::API::Admin::Ci::Variables do
end
describe 'PUT /admin/ci/variables/:key' do
- let!(:variable) { create(:ci_instance_variable) }
+ let_it_be(:path) { "/admin/ci/variables/#{variable.key}" }
+ let_it_be(:params) do
+ {
+ variable_type: 'file',
+ value: 'VALUE_1_UP',
+ protected: true,
+ masked: true,
+ raw: true
+ }
+ end
+
+ it_behaves_like 'PUT request permissions for admin mode'
context 'authorized user with proper permissions' do
it 'updates variable data', :aggregate_failures do
- put api("/admin/ci/variables/#{variable.key}", admin),
- params: {
- variable_type: 'file',
- value: 'VALUE_1_UP',
- protected: true,
- masked: true,
- raw: true
- }
-
- expect(response).to have_gitlab_http_status(:ok)
+ put api(path, admin, admin_mode: true), params: params
+
expect(variable.reload.value).to eq('VALUE_1_UP')
expect(variable.reload).to be_protected
expect(json_response['variable_type']).to eq('file')
@@ -182,28 +167,20 @@ RSpec.describe ::API::Admin::Ci::Variables do
expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
- put api("/admin/ci/variables/#{variable.key}", admin),
+ put api(path, admin, admin_mode: true),
params: { value: 'SENSITIVE', protected: true, masked: true }
end
it 'responds with 404 Not Found if requesting non-existing variable' do
- put api('/admin/ci/variables/non_existing_variable', admin)
+ put api('/admin/ci/variables/non_existing_variable', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
end
- context 'authorized user with invalid permissions' do
- it 'does not update variable' do
- put api("/admin/ci/variables/#{variable.key}", user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
context 'unauthorized user' do
it 'does not update variable' do
- put api("/admin/ci/variables/#{variable.key}")
+ put api(path, admin_mode: true)
expect(response).to have_gitlab_http_status(:unauthorized)
end
@@ -211,35 +188,27 @@ RSpec.describe ::API::Admin::Ci::Variables do
end
describe 'DELETE /admin/ci/variables/:key' do
- let!(:variable) { create(:ci_instance_variable) }
+ let_it_be(:path) { "/admin/ci/variables/#{variable.key}" }
+
+ it_behaves_like 'DELETE request permissions for admin mode'
context 'authorized user with proper permissions' do
it 'deletes variable' do
expect do
- delete api("/admin/ci/variables/#{variable.key}", admin)
-
- expect(response).to have_gitlab_http_status(:no_content)
+ delete api(path, admin, admin_mode: true)
end.to change { ::Ci::InstanceVariable.count }.by(-1)
end
it 'responds with 404 Not Found if requesting non-existing variable' do
- delete api('/admin/ci/variables/non_existing_variable', admin)
+ delete api('/admin/ci/variables/non_existing_variable', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
end
- context 'authorized user with invalid permissions' do
- it 'does not delete variable' do
- delete api("/admin/ci/variables/#{variable.key}", user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
context 'unauthorized user' do
it 'does not delete variable' do
- delete api("/admin/ci/variables/#{variable.key}")
+ delete api(path, admin_mode: true)
expect(response).to have_gitlab_http_status(:unauthorized)
end
diff --git a/spec/requests/api/admin/instance_clusters_spec.rb b/spec/requests/api/admin/instance_clusters_spec.rb
index 7b510f74fd4..0a72f404e89 100644
--- a/spec/requests/api/admin/instance_clusters_spec.rb
+++ b/spec/requests/api/admin/instance_clusters_spec.rb
@@ -5,7 +5,6 @@ require 'spec_helper'
RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_management do
include KubernetesHelpers
- let_it_be(:regular_user) { create(:user) }
let_it_be(:admin_user) { create(:admin) }
let_it_be(:project) { create(:project) }
let_it_be(:project_cluster) do
@@ -17,35 +16,27 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
let(:project_cluster_id) { project_cluster.id }
describe "GET /admin/clusters" do
+ let_it_be(:path) { "/admin/clusters" }
let_it_be(:clusters) do
create_list(:cluster, 3, :provided_by_gcp, :instance, :production_environment)
end
- include_examples ':certificate_based_clusters feature flag API responses' do
- let(:subject) { get api("/admin/clusters", admin_user) }
- end
+ it_behaves_like 'GET request permissions for admin mode'
- context "when authenticated as a non-admin user" do
- it 'returns 403' do
- get api('/admin/clusters', regular_user)
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ include_examples ':certificate_based_clusters feature flag API responses' do
+ let(:subject) { get api(path, admin_user, admin_mode: true) }
end
context "when authenticated as admin" do
before do
- get api("/admin/clusters", admin_user)
- end
-
- it 'returns 200' do
- expect(response).to have_gitlab_http_status(:ok)
+ get api(path, admin_user, admin_mode: true)
end
it 'includes pagination headers' do
expect(response).to include_pagination_headers
end
- it 'only returns the instance clusters' do
+ it 'only returns the instance clusters', :aggregate_failures do
cluster_ids = json_response.map { |cluster| cluster['id'] }
expect(cluster_ids).to match_array(clusters.pluck(:id))
expect(cluster_ids).not_to include(project_cluster_id)
@@ -60,19 +51,23 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
let_it_be(:cluster) do
create(:cluster, :instance, :provided_by_gcp, :with_domain,
- platform_kubernetes: platform_kubernetes,
- user: admin_user)
+ { platform_kubernetes: platform_kubernetes,
+ user: admin_user })
end
let(:cluster_id) { cluster.id }
+ let(:path) { "/admin/clusters/#{cluster_id}" }
+
+ it_behaves_like 'GET request permissions for admin mode'
+
include_examples ':certificate_based_clusters feature flag API responses' do
- let(:subject) { get api("/admin/clusters/#{cluster_id}", admin_user) }
+ let(:subject) { get api(path, admin_user, admin_mode: true) }
end
context "when authenticated as admin" do
before do
- get api("/admin/clusters/#{cluster_id}", admin_user)
+ get api(path, admin_user, admin_mode: true)
end
context "when no cluster associated to the ID" do
@@ -84,15 +79,11 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
end
context "when cluster with cluster_id exists" do
- it 'returns 200' do
- expect(response).to have_gitlab_http_status(:ok)
- end
-
it 'returns the cluster with cluster_id' do
expect(json_response['id']).to eq(cluster.id)
end
- it 'returns the cluster information' do
+ it 'returns the cluster information', :aggregate_failures do
expect(json_response['provider_type']).to eq('gcp')
expect(json_response['platform_type']).to eq('kubernetes')
expect(json_response['environment_scope']).to eq('*')
@@ -102,21 +93,21 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
expect(json_response['managed']).to be_truthy
end
- it 'returns kubernetes platform information' do
+ it 'returns kubernetes platform information', :aggregate_failures do
platform = json_response['platform_kubernetes']
expect(platform['api_url']).to eq('https://kubernetes.example.com')
expect(platform['ca_cert']).to be_present
end
- it 'returns user information' do
+ it 'returns user information', :aggregate_failures do
user = json_response['user']
expect(user['id']).to eq(admin_user.id)
expect(user['username']).to eq(admin_user.username)
end
- it 'returns GCP provider information' do
+ it 'returns GCP provider information', :aggregate_failures do
gcp_provider = json_response['provider_gcp']
expect(gcp_provider['cluster_id']).to eq(cluster.id)
@@ -140,18 +131,11 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
context 'when trying to get a project cluster via the instance cluster endpoint' do
it 'returns 404' do
- get api("/admin/clusters/#{project_cluster_id}", admin_user)
+ get api("/admin/clusters/#{project_cluster_id}", admin_user, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
-
- context "when authenticated as a non-admin user" do
- it 'returns 403' do
- get api("/admin/clusters/#{cluster_id}", regular_user)
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
end
end
@@ -159,6 +143,7 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
let(:api_url) { 'https://example.com' }
let(:authorization_type) { 'rbac' }
let(:clusterable) { Clusters::Instance.new }
+ let_it_be(:path) { '/admin/clusters/add' }
let(:platform_kubernetes_attributes) do
{
@@ -196,20 +181,20 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
}
end
+ it_behaves_like 'POST request permissions for admin mode' do
+ let(:params) { cluster_params }
+ end
+
include_examples ':certificate_based_clusters feature flag API responses' do
- let(:subject) { post api('/admin/clusters/add', admin_user), params: cluster_params }
+ let(:subject) { post api(path, admin_user, admin_mode: true), params: cluster_params }
end
context 'authorized user' do
before do
- post api('/admin/clusters/add', admin_user), params: cluster_params
+ post api(path, admin_user, admin_mode: true), params: cluster_params
end
context 'with valid params' do
- it 'responds with 201' do
- expect(response).to have_gitlab_http_status(:created)
- end
-
it 'creates a new Clusters::Cluster', :aggregate_failures do
cluster_result = Clusters::Cluster.find(json_response["id"])
platform_kubernetes = cluster_result.platform
@@ -271,7 +256,7 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
context 'when an instance cluster already exists' do
it 'allows user to add multiple clusters' do
- post api('/admin/clusters/add', admin_user), params: multiple_cluster_params
+ post api(path, admin_user, admin_mode: true), params: multiple_cluster_params
expect(Clusters::Instance.new.clusters.count).to eq(2)
end
@@ -280,8 +265,8 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
context 'with invalid params' do
context 'when missing a required parameter' do
- it 'responds with 400' do
- post api('/admin/clusters/add', admin_user), params: invalid_cluster_params
+ it 'responds with 400', :aggregate_failures do
+ post api(path, admin_user, admin_mode: true), params: invalid_cluster_params
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eql('name is missing')
end
@@ -300,14 +285,6 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
end
end
end
-
- context 'non-authorized user' do
- it 'responds with 403' do
- post api('/admin/clusters/add', regular_user), params: cluster_params
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
end
describe 'PUT /admin/clusters/:cluster_id' do
@@ -329,23 +306,25 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
create(:cluster, :instance, :provided_by_gcp, domain: 'old-domain.com')
end
+ let(:path) { "/admin/clusters/#{cluster.id}" }
+
+ it_behaves_like 'PUT request permissions for admin mode' do
+ let(:params) { update_params }
+ end
+
include_examples ':certificate_based_clusters feature flag API responses' do
- let(:subject) { put api("/admin/clusters/#{cluster.id}", admin_user), params: update_params }
+ let(:subject) { put api(path, admin_user, admin_mode: true), params: update_params }
end
context 'authorized user' do
before do
- put api("/admin/clusters/#{cluster.id}", admin_user), params: update_params
+ put api(path, admin_user, admin_mode: true), params: update_params
cluster.reload
end
context 'with valid params' do
- it 'responds with 200' do
- expect(response).to have_gitlab_http_status(:ok)
- end
-
- it 'updates cluster attributes' do
+ it 'updates cluster attributes', :aggregate_failures do
expect(cluster.domain).to eq('new-domain.com')
expect(cluster.managed).to be_falsy
expect(cluster.enabled).to be_falsy
@@ -359,7 +338,7 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'does not update cluster attributes' do
+ it 'does not update cluster attributes', :aggregate_failures do
expect(cluster.domain).to eq('old-domain.com')
expect(cluster.managed).to be_truthy
expect(cluster.enabled).to be_truthy
@@ -422,7 +401,7 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
expect(response).to have_gitlab_http_status(:ok)
end
- it 'updates platform kubernetes attributes' do
+ it 'updates platform kubernetes attributes', :aggregate_failures do
platform_kubernetes = cluster.platform_kubernetes
expect(cluster.name).to eq('new-name')
@@ -435,26 +414,18 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
let(:cluster_id) { 1337 }
it 'returns 404' do
- put api("/admin/clusters/#{cluster_id}", admin_user), params: update_params
+ put api("/admin/clusters/#{cluster_id}", admin_user, admin_mode: true), params: update_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when trying to update a project cluster via the instance cluster endpoint' do
it 'returns 404' do
- put api("/admin/clusters/#{project_cluster_id}", admin_user), params: update_params
+ put api("/admin/clusters/#{project_cluster_id}", admin_user, admin_mode: true), params: update_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
-
- context 'non-authorized user' do
- it 'responds with 403' do
- put api("/admin/clusters/#{cluster.id}", regular_user), params: update_params
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
end
describe 'DELETE /admin/clusters/:cluster_id' do
@@ -464,17 +435,17 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
create(:cluster, :instance, :provided_by_gcp)
end
+ let_it_be(:path) { "/admin/clusters/#{cluster.id}" }
+
+ it_behaves_like 'DELETE request permissions for admin mode'
+
include_examples ':certificate_based_clusters feature flag API responses' do
- let(:subject) { delete api("/admin/clusters/#{cluster.id}", admin_user), params: cluster_params }
+ let(:subject) { delete api(path, admin_user, admin_mode: true), params: cluster_params }
end
context 'authorized user' do
before do
- delete api("/admin/clusters/#{cluster.id}", admin_user), params: cluster_params
- end
-
- it 'responds with 204' do
- expect(response).to have_gitlab_http_status(:no_content)
+ delete api(path, admin_user, admin_mode: true), params: cluster_params
end
it 'deletes the cluster' do
@@ -485,25 +456,17 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man
let(:cluster_id) { 1337 }
it 'returns 404' do
- delete api("/admin/clusters/#{cluster_id}", admin_user)
+ delete api(path, admin_user, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when trying to update a project cluster via the instance cluster endpoint' do
it 'returns 404' do
- delete api("/admin/clusters/#{project_cluster_id}", admin_user)
+ delete api("/admin/clusters/#{project_cluster_id}", admin_user, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
-
- context 'non-authorized user' do
- it 'responds with 403' do
- delete api("/admin/clusters/#{cluster.id}", regular_user), params: cluster_params
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
end
end
diff --git a/spec/requests/api/admin/plan_limits_spec.rb b/spec/requests/api/admin/plan_limits_spec.rb
index 2de7a66d803..dffe062c031 100644
--- a/spec/requests/api/admin/plan_limits_spec.rb
+++ b/spec/requests/api/admin/plan_limits_spec.rb
@@ -2,26 +2,19 @@
require 'spec_helper'
-RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owned do
- let_it_be(:user) { create(:user) }
+RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :shared do
let_it_be(:admin) { create(:admin) }
let_it_be(:plan) { create(:plan, name: 'default') }
+ let_it_be(:path) { '/application/plan_limits' }
describe 'GET /application/plan_limits' do
- context 'as a non-admin user' do
- it 'returns 403' do
- get api('/application/plan_limits', user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
+ it_behaves_like 'GET request permissions for admin mode'
context 'as an admin user' do
context 'no params' do
- it 'returns plan limits' do
- get api('/application/plan_limits', admin)
+ it 'returns plan limits', :aggregate_failures do
+ get api(path, admin, admin_mode: true)
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Hash
expect(json_response['ci_pipeline_size']).to eq(Plan.default.actual_limits.ci_pipeline_size)
expect(json_response['ci_active_jobs']).to eq(Plan.default.actual_limits.ci_active_jobs)
@@ -49,8 +42,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
@params = { plan_name: 'default' }
end
- it 'returns plan limits' do
- get api('/application/plan_limits', admin), params: @params
+ it 'returns plan limits', :aggregate_failures do
+ get api(path, admin, admin_mode: true), params: @params
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Hash
@@ -80,8 +73,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
@params = { plan_name: 'my-plan' }
end
- it 'returns validation error' do
- get api('/application/plan_limits', admin), params: @params
+ it 'returns validation error', :aggregate_failures do
+ get api(path, admin, admin_mode: true), params: @params
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq('plan_name does not have a valid value')
@@ -91,18 +84,14 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
end
describe 'PUT /application/plan_limits' do
- context 'as a non-admin user' do
- it 'returns 403' do
- put api('/application/plan_limits', user), params: { plan_name: 'default' }
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ it_behaves_like 'PUT request permissions for admin mode' do
+ let(:params) { { 'plan_name': 'default' } }
end
context 'as an admin user' do
context 'correct params' do
- it 'updates multiple plan limits' do
- put api('/application/plan_limits', admin), params: {
+ it 'updates multiple plan limits', :aggregate_failures do
+ put api(path, admin, admin_mode: true), params: {
'plan_name': 'default',
'ci_pipeline_size': 101,
'ci_active_jobs': 102,
@@ -124,7 +113,6 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
'pipeline_hierarchy_size': 250
}
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Hash
expect(json_response['ci_pipeline_size']).to eq(101)
expect(json_response['ci_active_jobs']).to eq(102)
@@ -146,8 +134,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
expect(json_response['pipeline_hierarchy_size']).to eq(250)
end
- it 'updates single plan limits' do
- put api('/application/plan_limits', admin), params: {
+ it 'updates single plan limits', :aggregate_failures do
+ put api(path, admin, admin_mode: true), params: {
'plan_name': 'default',
'maven_max_file_size': 100
}
@@ -159,8 +147,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
end
context 'empty params' do
- it 'fails to update plan limits' do
- put api('/application/plan_limits', admin), params: {}
+ it 'fails to update plan limits', :aggregate_failures do
+ put api(path, admin, admin_mode: true), params: {}
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to match('plan_name is missing')
@@ -168,8 +156,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
end
context 'params with wrong type' do
- it 'fails to update plan limits' do
- put api('/application/plan_limits', admin), params: {
+ it 'fails to update plan limits', :aggregate_failures do
+ put api(path, admin, admin_mode: true), params: {
'plan_name': 'default',
'ci_pipeline_size': 'z',
'ci_active_jobs': 'y',
@@ -216,8 +204,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
end
context 'missing plan_name in params' do
- it 'fails to update plan limits' do
- put api('/application/plan_limits', admin), params: { 'conan_max_file_size': 0 }
+ it 'fails to update plan limits', :aggregate_failures do
+ put api(path, admin, admin_mode: true), params: { 'conan_max_file_size': 0 }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to match('plan_name is missing')
@@ -229,8 +217,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne
Plan.default.actual_limits.update!({ 'golang_max_file_size': 1000 })
end
- it 'updates only declared plan limits' do
- put api('/application/plan_limits', admin), params: {
+ it 'updates only declared plan limits', :aggregate_failures do
+ put api(path, admin, admin_mode: true), params: {
'plan_name': 'default',
'pypi_max_file_size': 200,
'golang_max_file_size': 999
diff --git a/spec/requests/api/admin/sidekiq_spec.rb b/spec/requests/api/admin/sidekiq_spec.rb
index 0b456721d4f..8bcd7884fd2 100644
--- a/spec/requests/api/admin/sidekiq_spec.rb
+++ b/spec/requests/api/admin/sidekiq_spec.rb
@@ -2,18 +2,10 @@
require 'spec_helper'
-RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category: :not_owned do
+RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category: :shared do
let_it_be(:admin) { create(:admin) }
describe 'DELETE /admin/sidekiq/queues/:queue_name' do
- context 'when the user is not an admin' do
- it 'returns a 403' do
- delete api("/admin/sidekiq/queues/authorized_projects?user=#{admin.username}", create(:user))
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
context 'when the user is an admin' do
around do |example|
Sidekiq::Queue.new('authorized_projects').clear
@@ -31,14 +23,19 @@ RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category
end
context 'valid request' do
- it 'returns info about the deleted jobs' do
+ before do
add_job(admin, [1])
add_job(admin, [2])
add_job(create(:user), [3])
+ end
+
+ let_it_be(:path) { "/admin/sidekiq/queues/authorized_projects?user=#{admin.username}&worker_class=AuthorizedProjectsWorker" }
- delete api("/admin/sidekiq/queues/authorized_projects?user=#{admin.username}&worker_class=AuthorizedProjectsWorker", admin)
+ it_behaves_like 'DELETE request permissions for admin mode', success_status_code: :ok
+
+ it 'returns info about the deleted jobs' do
+ delete api(path, admin, admin_mode: true)
- expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq('completed' => true,
'deleted_jobs' => 2,
'queue_size' => 1)
@@ -47,7 +44,7 @@ RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category
context 'when no required params are provided' do
it 'returns a 400' do
- delete api("/admin/sidekiq/queues/authorized_projects?user_2=#{admin.username}", admin)
+ delete api("/admin/sidekiq/queues/authorized_projects?user_2=#{admin.username}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -55,7 +52,7 @@ RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category
context 'when the queue does not exist' do
it 'returns a 404' do
- delete api("/admin/sidekiq/queues/authorized_projects_2?user=#{admin.username}", admin)
+ delete api("/admin/sidekiq/queues/authorized_projects_2?user=#{admin.username}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
diff --git a/spec/requests/api/api_guard/admin_mode_middleware_spec.rb b/spec/requests/api/api_guard/admin_mode_middleware_spec.rb
index 21f3691c20b..7268fa2c90b 100644
--- a/spec/requests/api/api_guard/admin_mode_middleware_spec.rb
+++ b/spec/requests/api/api_guard/admin_mode_middleware_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::APIGuard::AdminModeMiddleware, :request_store, feature_category: :not_owned do
+RSpec.describe API::APIGuard::AdminModeMiddleware, :request_store, feature_category: :shared do
let(:user) { create(:admin) }
it 'is loaded' do
diff --git a/spec/requests/api/api_guard/response_coercer_middleware_spec.rb b/spec/requests/api/api_guard/response_coercer_middleware_spec.rb
index 77498c2e2b3..4a993d0b255 100644
--- a/spec/requests/api/api_guard/response_coercer_middleware_spec.rb
+++ b/spec/requests/api/api_guard/response_coercer_middleware_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::APIGuard::ResponseCoercerMiddleware, feature_category: :not_owned do
+RSpec.describe API::APIGuard::ResponseCoercerMiddleware, feature_category: :shared do
using RSpec::Parameterized::TableSyntax
it 'is loaded' do
diff --git a/spec/requests/api/api_spec.rb b/spec/requests/api/api_spec.rb
index 35851fff6c8..d5ad0779bd9 100644
--- a/spec/requests/api/api_spec.rb
+++ b/spec/requests/api/api_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::API, feature_category: :authentication_and_authorization do
+RSpec.describe API::API, feature_category: :system_access do
include GroupAPIHelpers
describe 'Record user last activity in after hook' do
diff --git a/spec/requests/api/appearance_spec.rb b/spec/requests/api/appearance_spec.rb
index c08ecae28e8..3550e51d585 100644
--- a/spec/requests/api/appearance_spec.rb
+++ b/spec/requests/api/appearance_spec.rb
@@ -36,7 +36,9 @@ RSpec.describe API::Appearance, 'Appearance', feature_category: :navigation do
end
describe "PUT /application/appearance" do
- it_behaves_like 'PUT request permissions for admin mode', { title: "Test" }
+ it_behaves_like 'PUT request permissions for admin mode' do
+ let(:params) { { title: "Test" } }
+ end
context 'as an admin user' do
context "instance basics" do
diff --git a/spec/requests/api/applications_spec.rb b/spec/requests/api/applications_spec.rb
index b81cdcfea8e..5b07bded82c 100644
--- a/spec/requests/api/applications_spec.rb
+++ b/spec/requests/api/applications_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Applications, :api, feature_category: :authentication_and_authorization do
+RSpec.describe API::Applications, :api, feature_category: :system_access do
let_it_be(:admin) { create(:admin) }
let_it_be(:user) { create(:user) }
let_it_be(:scopes) { 'api' }
@@ -10,7 +10,9 @@ RSpec.describe API::Applications, :api, feature_category: :authentication_and_au
let!(:application) { create(:application, name: 'another_application', owner: nil, redirect_uri: 'http://other_application.url', scopes: scopes) }
describe 'POST /applications' do
- it_behaves_like 'POST request permissions for admin mode', { name: 'application_name', redirect_uri: 'http://application.url', scopes: 'api' }
+ it_behaves_like 'POST request permissions for admin mode' do
+ let(:params) { { name: 'application_name', redirect_uri: 'http://application.url', scopes: 'api' } }
+ end
context 'authenticated and authorized user' do
it 'creates and returns an OAuth application' do
@@ -22,7 +24,7 @@ RSpec.describe API::Applications, :api, feature_category: :authentication_and_au
expect(json_response).to be_a Hash
expect(json_response['application_id']).to eq application.uid
- expect(json_response['secret']).to eq application.secret
+ expect(application.secret_matches?(json_response['secret'])).to eq(true)
expect(json_response['callback_url']).to eq application.redirect_uri
expect(json_response['confidential']).to eq application.confidential
expect(application.scopes.to_s).to eq('api')
diff --git a/spec/requests/api/avatar_spec.rb b/spec/requests/api/avatar_spec.rb
index fcef5b6ca78..0a77b6e228e 100644
--- a/spec/requests/api/avatar_spec.rb
+++ b/spec/requests/api/avatar_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe API::Avatar, feature_category: :user_profile do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['avatar_url']).to eql("#{::Settings.gitlab.base_url}#{user.avatar.local_url}")
+ is_expected.to have_request_urgency(:medium)
end
end
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index 87dc06b7d15..22c67a253e3 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::AwardEmoji, feature_category: :not_owned do
+RSpec.describe API::AwardEmoji, feature_category: :shared do
let_it_be_with_reload(:project) { create(:project, :private) }
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/requests/api/ci/job_artifacts_spec.rb b/spec/requests/api/ci/job_artifacts_spec.rb
index ee390773f29..7cea744cdb9 100644
--- a/spec/requests/api/ci/job_artifacts_spec.rb
+++ b/spec/requests/api/ci/job_artifacts_spec.rb
@@ -190,7 +190,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do
end
context 'when project is public with artifacts that are non public' do
- let(:job) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) }
it 'rejects access to artifacts' do
project.update_column(:visibility_level,
@@ -439,7 +439,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do
context 'when public project guest and artifacts are non public' do
let(:api_user) { guest }
- let(:job) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) }
before do
project.update_column(:visibility_level,
@@ -644,7 +644,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do
end
context 'when project is public with non public artifacts' do
- let(:job) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline, user: api_user) }
+ let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline, user: api_user) }
let(:visibility_level) { Gitlab::VisibilityLevel::PUBLIC }
let(:public_builds) { true }
diff --git a/spec/requests/api/ci/pipeline_schedules_spec.rb b/spec/requests/api/ci/pipeline_schedules_spec.rb
index 2a2c5f65aee..d760e4ddf28 100644
--- a/spec/requests/api/ci/pipeline_schedules_spec.rb
+++ b/spec/requests/api/ci/pipeline_schedules_spec.rb
@@ -473,12 +473,12 @@ RSpec.describe API::Ci::PipelineSchedules, feature_category: :continuous_integra
end
context 'as the existing owner of the schedule' do
- it 'rejects the request and leaves the schedule unchanged' do
+ it 'accepts the request and leaves the schedule unchanged' do
expect do
post api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}/take_ownership", developer)
end.not_to change { pipeline_schedule.reload.owner }
- expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response).to have_gitlab_http_status(:success)
end
end
end
diff --git a/spec/requests/api/ci/pipelines_spec.rb b/spec/requests/api/ci/pipelines_spec.rb
index 6d69da85449..4e81a052ecf 100644
--- a/spec/requests/api/ci/pipelines_spec.rb
+++ b/spec/requests/api/ci/pipelines_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
it_behaves_like 'pipelines visibility table'
context 'authorized user' do
- it 'returns project pipelines' do
+ it 'returns project pipelines', :aggregate_failures do
get api("/projects/#{project.id}/pipelines", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -52,7 +52,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
create(:ci_pipeline, project: project, status: target)
end
- it 'returns matched pipelines' do
+ it 'returns matched pipelines', :aggregate_failures do
get api("/projects/#{project.id}/pipelines", user), params: { scope: target }
expect(response).to have_gitlab_http_status(:ok)
@@ -307,7 +307,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'unauthorized user' do
- it 'does not return project pipelines' do
+ it 'does not return project pipelines', :aggregate_failures do
get api("/projects/#{project.id}/pipelines", non_member)
expect(response).to have_gitlab_http_status(:not_found)
@@ -335,13 +335,13 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'authorized user' do
- it 'returns pipeline jobs' do
+ it 'returns pipeline jobs', :aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
end
- it 'returns correct values' do
+ it 'returns correct values', :aggregate_failures do
expect(json_response).not_to be_empty
expect(json_response.first['commit']['id']).to eq project.commit.id
expect(Time.parse(json_response.first['artifacts_expire_at'])).to be_like_time(job.artifacts_expire_at)
@@ -354,7 +354,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let(:api_endpoint) { "/projects/#{project.id}/pipelines/#{pipeline.id}/jobs" }
end
- it 'returns pipeline data' do
+ it 'returns pipeline data', :aggregate_failures do
json_job = json_response.first
expect(json_job['pipeline']).not_to be_empty
@@ -368,7 +368,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'filter jobs with one scope element' do
let(:query) { { 'scope' => 'pending' } }
- it do
+ it :aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
@@ -382,7 +382,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'when filtering to only running jobs' do
let(:query) { { 'scope' => 'running' } }
- it do
+ it :aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
@@ -402,7 +402,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'filter jobs with array of scope elements' do
let(:query) { { scope: %w(pending running) } }
- it do
+ it :aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
end
@@ -442,7 +442,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let_it_be(:successor) { create(:ci_build, :success, name: 'build', pipeline: pipeline) }
- it 'does not return retried jobs by default' do
+ it 'does not return retried jobs by default', :aggregate_failures do
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
end
@@ -450,7 +450,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'when include_retried is false' do
let(:query) { { include_retried: false } }
- it 'does not return retried jobs' do
+ it 'does not return retried jobs', :aggregate_failures do
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
end
@@ -459,7 +459,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'when include_retried is true' do
let(:query) { { include_retried: true } }
- it 'returns retried jobs' do
+ it 'returns retried jobs', :aggregate_failures do
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
expect(json_response[0]['name']).to eq(json_response[1]['name'])
@@ -469,7 +469,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'no pipeline is found' do
- it 'does not return jobs' do
+ it 'does not return jobs', :aggregate_failures do
get api("/projects/#{project2.id}/pipelines/#{pipeline.id}/jobs", user)
expect(json_response['message']).to eq '404 Project Not Found'
@@ -481,7 +481,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'when user is not logged in' do
let(:api_user) { nil }
- it 'does not return jobs' do
+ it 'does not return jobs', :aggregate_failures do
expect(json_response['message']).to eq '404 Project Not Found'
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -523,13 +523,13 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'authorized user' do
- it 'returns pipeline bridges' do
+ it 'returns pipeline bridges', :aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
end
- it 'returns correct values' do
+ it 'returns correct values', :aggregate_failures do
expect(json_response).not_to be_empty
expect(json_response.first['commit']['id']).to eq project.commit.id
expect(json_response.first['id']).to eq bridge.id
@@ -537,7 +537,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
expect(json_response.first['stage']).to eq bridge.stage
end
- it 'returns pipeline data' do
+ it 'returns pipeline data', :aggregate_failures do
json_bridge = json_response.first
expect(json_bridge['pipeline']).not_to be_empty
@@ -548,7 +548,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
expect(json_bridge['pipeline']['status']).to eq bridge.pipeline.status
end
- it 'returns downstream pipeline data' do
+ it 'returns downstream pipeline data', :aggregate_failures do
json_bridge = json_response.first
expect(json_bridge['downstream_pipeline']).not_to be_empty
@@ -568,7 +568,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'with one scope element' do
let(:query) { { 'scope' => 'pending' } }
- it :skip_before_request do
+ it :skip_before_request, :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}/bridges", api_user), params: query
expect(response).to have_gitlab_http_status(:ok)
@@ -581,7 +581,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'with array of scope elements' do
let(:query) { { scope: %w(pending running) } }
- it :skip_before_request do
+ it :skip_before_request, :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}/bridges", api_user), params: query
expect(response).to have_gitlab_http_status(:ok)
@@ -635,7 +635,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'no pipeline is found' do
- it 'does not return bridges' do
+ it 'does not return bridges', :aggregate_failures do
get api("/projects/#{project2.id}/pipelines/#{pipeline.id}/bridges", user)
expect(json_response['message']).to eq '404 Project Not Found'
@@ -647,7 +647,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'when user is not logged in' do
let(:api_user) { nil }
- it 'does not return bridges' do
+ it 'does not return bridges', :aggregate_failures do
expect(json_response['message']).to eq '404 Project Not Found'
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -704,7 +704,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
stub_ci_pipeline_to_return_yaml_file
end
- it 'creates and returns a new pipeline' do
+ it 'creates and returns a new pipeline', :aggregate_failures do
expect do
post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch }
end.to change { project.ci_pipelines.count }.by(1)
@@ -717,7 +717,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'variables given' do
let(:variables) { [{ 'variable_type' => 'file', 'key' => 'UPLOAD_TO_S3', 'value' => 'true' }] }
- it 'creates and returns a new pipeline using the given variables' do
+ it 'creates and returns a new pipeline using the given variables', :aggregate_failures do
expect do
post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch, variables: variables }
end.to change { project.ci_pipelines.count }.by(1)
@@ -738,7 +738,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
stub_ci_pipeline_yaml_file(config)
end
- it 'creates and returns a new pipeline using the given variables' do
+ it 'creates and returns a new pipeline using the given variables', :aggregate_failures do
expect do
post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch, variables: variables }
end.to change { project.ci_pipelines.count }.by(1)
@@ -763,7 +763,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
end
- it 'fails when using an invalid ref' do
+ it 'fails when using an invalid ref', :aggregate_failures do
post api("/projects/#{project.id}/pipeline", user), params: { ref: 'invalid_ref' }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -778,7 +778,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
project.update!(auto_devops_attributes: { enabled: false })
end
- it 'fails to create pipeline' do
+ it 'fails to create pipeline', :aggregate_failures do
post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -790,7 +790,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'unauthorized user' do
- it 'does not create pipeline' do
+ it 'does not create pipeline', :aggregate_failures do
post api("/projects/#{project.id}/pipeline", non_member), params: { ref: project.default_branch }
expect(response).to have_gitlab_http_status(:not_found)
@@ -811,21 +811,21 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'authorized user' do
- it 'exposes known attributes' do
+ it 'exposes known attributes', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}", user)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/pipeline/detail')
end
- it 'returns project pipeline' do
+ it 'returns project pipeline', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['sha']).to match(/\A\h{40}\z/)
end
- it 'returns 404 when it does not exist' do
+ it 'returns 404 when it does not exist', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{non_existing_record_id}", user)
expect(response).to have_gitlab_http_status(:not_found)
@@ -847,7 +847,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'unauthorized user' do
- it 'does not return a project pipeline' do
+ it 'does not return a project pipeline', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}", non_member)
expect(response).to have_gitlab_http_status(:not_found)
@@ -863,7 +863,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
create(:ci_pipeline, source: dangling_source, project: project)
end
- it 'returns the specified pipeline' do
+ it 'returns the specified pipeline', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{dangling_pipeline.id}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -887,7 +887,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'default repository branch' do
- it 'gets the latest pipleine' do
+ it 'gets the latest pipleine', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/latest", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -898,7 +898,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'ref parameter' do
- it 'gets the latest pipleine' do
+ it 'gets the latest pipleine', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/latest", user), params: { ref: second_branch.name }
expect(response).to have_gitlab_http_status(:ok)
@@ -910,7 +910,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'unauthorized user' do
- it 'does not return a project pipeline' do
+ it 'does not return a project pipeline', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}", non_member)
expect(response).to have_gitlab_http_status(:not_found)
@@ -926,7 +926,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let(:api_user) { user }
context 'user is a mantainer' do
- it 'returns pipeline variables empty' do
+ it 'returns pipeline variables empty', :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:ok)
@@ -936,7 +936,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'with variables' do
let!(:variable) { create(:ci_pipeline_variable, pipeline: pipeline, key: 'foo', value: 'bar') }
- it 'returns pipeline variables' do
+ it 'returns pipeline variables', :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:ok)
@@ -962,7 +962,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let(:api_user) { pipeline_owner_user }
let!(:variable) { create(:ci_pipeline_variable, pipeline: pipeline, key: 'foo', value: 'bar') }
- it 'returns pipeline variables' do
+ it 'returns pipeline variables', :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:ok)
@@ -987,7 +987,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'user is not a project member' do
- it 'does not return pipeline variables' do
+ it 'does not return pipeline variables', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}/variables", non_member)
expect(response).to have_gitlab_http_status(:not_found)
@@ -1000,14 +1000,14 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'authorized user' do
let(:owner) { project.first_owner }
- it 'destroys the pipeline' do
+ it 'destroys the pipeline', :aggregate_failures do
delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner)
expect(response).to have_gitlab_http_status(:no_content)
expect { pipeline.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
- it 'returns 404 when it does not exist' do
+ it 'returns 404 when it does not exist', :aggregate_failures do
delete api("/projects/#{project.id}/pipelines/#{non_existing_record_id}", owner)
expect(response).to have_gitlab_http_status(:not_found)
@@ -1021,7 +1021,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'when the pipeline has jobs' do
let_it_be(:build) { create(:ci_build, project: project, pipeline: pipeline) }
- it 'destroys associated jobs' do
+ it 'destroys associated jobs', :aggregate_failures do
delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", owner)
expect(response).to have_gitlab_http_status(:no_content)
@@ -1044,7 +1044,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'unauthorized user' do
context 'when user is not member' do
- it 'returns a 404' do
+ it 'returns a 404', :aggregate_failures do
delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", non_member)
expect(response).to have_gitlab_http_status(:not_found)
@@ -1059,7 +1059,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
project.add_developer(developer)
end
- it 'returns a 403' do
+ it 'returns a 403', :aggregate_failures do
delete api("/projects/#{project.id}/pipelines/#{pipeline.id}", developer)
expect(response).to have_gitlab_http_status(:forbidden)
@@ -1078,7 +1078,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let_it_be(:build) { create(:ci_build, :failed, pipeline: pipeline) }
- it 'retries failed builds' do
+ it 'retries failed builds', :aggregate_failures do
expect do
post api("/projects/#{project.id}/pipelines/#{pipeline.id}/retry", user)
end.to change { pipeline.builds.count }.from(1).to(2)
@@ -1089,7 +1089,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'unauthorized user' do
- it 'does not return a project pipeline' do
+ it 'does not return a project pipeline', :aggregate_failures do
post api("/projects/#{project.id}/pipelines/#{pipeline.id}/retry", non_member)
expect(response).to have_gitlab_http_status(:not_found)
@@ -1106,7 +1106,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
end
- it 'returns error' do
+ it 'returns error', :aggregate_failures do
post api("/projects/#{project.id}/pipelines/#{pipeline.id}/retry", user)
expect(response).to have_gitlab_http_status(:forbidden)
@@ -1124,7 +1124,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let_it_be(:build) { create(:ci_build, :running, pipeline: pipeline) }
- context 'authorized user' do
+ context 'authorized user', :aggregate_failures do
it 'retries failed builds', :sidekiq_might_not_need_inline do
post api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", user)
@@ -1140,7 +1140,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
project.add_reporter(reporter)
end
- it 'rejects the action' do
+ it 'rejects the action', :aggregate_failures do
post api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", reporter)
expect(response).to have_gitlab_http_status(:forbidden)
@@ -1156,7 +1156,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let(:pipeline) { create(:ci_pipeline, project: project) }
context 'when pipeline does not have a test report' do
- it 'returns an empty test report' do
+ it 'returns an empty test report', :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:ok)
@@ -1167,7 +1167,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'when pipeline has a test report' do
let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) }
- it 'returns the test report' do
+ it 'returns the test report', :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:ok)
@@ -1180,7 +1180,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
create(:ci_build, :broken_test_reports, name: 'rspec', pipeline: pipeline)
end
- it 'returns a suite_error' do
+ it 'returns a suite_error', :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:ok)
@@ -1190,7 +1190,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'unauthorized user' do
- it 'does not return project pipelines' do
+ it 'does not return project pipelines', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}/test_report", non_member)
expect(response).to have_gitlab_http_status(:not_found)
@@ -1208,7 +1208,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let(:pipeline) { create(:ci_pipeline, project: project) }
context 'when pipeline does not have a test report summary' do
- it 'returns an empty test report summary' do
+ it 'returns an empty test report summary', :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:ok)
@@ -1219,7 +1219,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
context 'when pipeline has a test report summary' do
let(:pipeline) { create(:ci_pipeline, :with_report_results, project: project) }
- it 'returns the test report summary' do
+ it 'returns the test report summary', :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:ok)
@@ -1229,7 +1229,7 @@ RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
end
context 'unauthorized user' do
- it 'does not return project pipelines' do
+ it 'does not return project pipelines', :aggregate_failures do
get api("/projects/#{project.id}/pipelines/#{pipeline.id}/test_report_summary", non_member)
expect(response).to have_gitlab_http_status(:not_found)
diff --git a/spec/requests/api/ci/runner/jobs_put_spec.rb b/spec/requests/api/ci/runner/jobs_put_spec.rb
index ef3b38e3fc4..bf28b25e0a6 100644
--- a/spec/requests/api/ci/runner/jobs_put_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_put_spec.rb
@@ -43,6 +43,17 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
.and change { runner_machine.reload.contacted_at }
end
+ context 'when runner_machine_heartbeat is disabled' do
+ before do
+ stub_feature_flags(runner_machine_heartbeat: false)
+ end
+
+ it 'does not load runner machine' do
+ queries = ActiveRecord::QueryRecorder.new { update_job(state: 'success') }
+ expect(queries.log).not_to include(/ci_runner_machines/)
+ end
+ end
+
context 'when status is given' do
it 'marks job as succeeded' do
update_job(state: 'success')
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 6e721d40560..28dbc4fd168 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -831,19 +831,6 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
end
end
end
-
- context 'when the FF ci_hooks_pre_get_sources_script is disabled' do
- before do
- stub_feature_flags(ci_hooks_pre_get_sources_script: false)
- end
-
- it 'does not return the pre_get_sources_script' do
- request_job
-
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response).not_to have_key('hooks')
- end
- end
end
describe 'port support' do
diff --git a/spec/requests/api/ci/runner/runners_verify_post_spec.rb b/spec/requests/api/ci/runner/runners_verify_post_spec.rb
index a6a1ad947aa..1b7dfe7706c 100644
--- a/spec/requests/api/ci/runner/runners_verify_post_spec.rb
+++ b/spec/requests/api/ci/runner/runners_verify_post_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
end
describe '/api/v4/runners' do
- describe 'POST /api/v4/runners/verify' do
+ describe 'POST /api/v4/runners/verify', :freeze_time do
let_it_be_with_reload(:runner) { create(:ci_runner, token_expires_at: 3.days.from_now) }
let(:params) {}
@@ -50,6 +50,30 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
stub_feature_flags(create_runner_machine: true)
end
+ context 'with glrt-prefixed token' do
+ let_it_be(:registration_token) { 'glrt-abcdefg123456' }
+ let_it_be(:registration_type) { :authenticated_user }
+ let_it_be(:runner) do
+ create(:ci_runner, registration_type: registration_type,
+ token: registration_token, token_expires_at: 3.days.from_now)
+ end
+
+ it 'verifies Runner credentials' do
+ verify
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq({
+ 'id' => runner.id,
+ 'token' => runner.token,
+ 'token_expires_at' => runner.token_expires_at.iso8601(3)
+ })
+ end
+
+ it 'does not update contacted_at' do
+ expect { verify }.not_to change { runner.reload.contacted_at }.from(nil)
+ end
+ end
+
it 'verifies Runner credentials' do
verify
@@ -61,6 +85,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
})
end
+ it 'updates contacted_at' do
+ expect { verify }.to change { runner.reload.contacted_at }.from(nil).to(Time.current)
+ end
+
context 'with non-expiring runner token' do
before do
runner.update!(token_expires_at: nil)
diff --git a/spec/requests/api/ci/runners_reset_registration_token_spec.rb b/spec/requests/api/ci/runners_reset_registration_token_spec.rb
index 1110dbf5fbc..98edde93e95 100644
--- a/spec/requests/api/ci/runners_reset_registration_token_spec.rb
+++ b/spec/requests/api/ci/runners_reset_registration_token_spec.rb
@@ -3,10 +3,12 @@
require 'spec_helper'
RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
- subject { post api("#{prefix}/runners/reset_registration_token", user) }
+ let_it_be(:admin_mode) { false }
+
+ subject { post api("#{prefix}/runners/reset_registration_token", user, admin_mode: admin_mode) }
shared_examples 'bad request' do |result|
- it 'returns 400 error' do
+ it 'returns 400 error', :aggregate_failures do
expect { subject }.not_to change { get_token }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -15,7 +17,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
shared_examples 'unauthenticated' do
- it 'returns 401 error' do
+ it 'returns 401 error', :aggregate_failures do
expect { subject }.not_to change { get_token }
expect(response).to have_gitlab_http_status(:unauthorized)
@@ -23,7 +25,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
shared_examples 'unauthorized' do
- it 'returns 403 error' do
+ it 'returns 403 error', :aggregate_failures do
expect { subject }.not_to change { get_token }
expect(response).to have_gitlab_http_status(:forbidden)
@@ -31,7 +33,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
shared_examples 'not found' do |scope|
- it 'returns 404 error' do
+ it 'returns 404 error', :aggregate_failures do
expect { subject }.not_to change { get_token }
expect(response).to have_gitlab_http_status(:not_found)
@@ -58,7 +60,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
shared_context 'when authorized' do |scope|
- it 'resets runner registration token' do
+ it 'resets runner registration token', :aggregate_failures do
expect { subject }.to change { get_token }
expect(response).to have_gitlab_http_status(:success)
@@ -99,6 +101,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
include_context 'when authorized', 'instance' do
let_it_be(:user) { create(:user, :admin) }
+ let_it_be(:admin_mode) { true }
def get_token
ApplicationSetting.current_without_cache.runners_registration_token
diff --git a/spec/requests/api/ci/runners_spec.rb b/spec/requests/api/ci/runners_spec.rb
index ca051386265..ec9b5621c37 100644
--- a/spec/requests/api/ci/runners_spec.rb
+++ b/spec/requests/api/ci/runners_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
describe 'GET /runners' do
context 'authorized user' do
- it 'returns response status and headers' do
+ it 'returns response status and headers', :aggregate_failures do
get api('/runners', user)
expect(response).to have_gitlab_http_status(:ok)
@@ -53,7 +53,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
]
end
- it 'filters runners by scope' do
+ it 'filters runners by scope', :aggregate_failures do
create(:ci_runner, :project, :inactive, description: 'Inactive project runner', projects: [project])
get api('/runners?scope=paused', user)
@@ -112,7 +112,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'filters runners by tag_list' do
+ it 'filters runners by tag_list', :aggregate_failures do
create(:ci_runner, :project, description: 'Runner tagged with tag1 and tag2', projects: [project], tag_list: %w[tag1 tag2])
create(:ci_runner, :project, description: 'Runner tagged with tag2', projects: [project], tag_list: ['tag2'])
@@ -137,14 +137,14 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'authorized user' do
context 'with admin privileges' do
it 'returns response status and headers' do
- get api('/runners/all', admin)
+ get api('/runners/all', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
end
it 'returns all runners' do
- get api('/runners/all', admin)
+ get api('/runners/all', admin, admin_mode: true)
expect(json_response).to match_array [
a_hash_including('description' => 'Project runner', 'is_shared' => false, 'active' => true, 'paused' => false, 'runner_type' => 'project_type'),
@@ -155,8 +155,8 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
]
end
- it 'filters runners by scope' do
- get api('/runners/all?scope=shared', admin)
+ it 'filters runners by scope', :aggregate_failures do
+ get api('/runners/all?scope=shared', admin, admin_mode: true)
shared = json_response.all? { |r| r['is_shared'] }
expect(response).to have_gitlab_http_status(:ok)
@@ -166,8 +166,8 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(shared).to be_truthy
end
- it 'filters runners by scope' do
- get api('/runners/all?scope=specific', admin)
+ it 'filters runners by scope', :aggregate_failures do
+ get api('/runners/all?scope=specific', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -181,12 +181,12 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
it 'avoids filtering if scope is invalid' do
- get api('/runners/all?scope=unknown', admin)
+ get api('/runners/all?scope=unknown', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'filters runners by project type' do
- get api('/runners/all?type=project_type', admin)
+ get api('/runners/all?type=project_type', admin, admin_mode: true)
expect(json_response).to match_array [
a_hash_including('description' => 'Project runner'),
@@ -195,7 +195,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
it 'filters runners by group type' do
- get api('/runners/all?type=group_type', admin)
+ get api('/runners/all?type=group_type', admin, admin_mode: true)
expect(json_response).to match_array [
a_hash_including('description' => 'Group runner A'),
@@ -204,7 +204,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
it 'does not filter by invalid type' do
- get api('/runners/all?type=bogus', admin)
+ get api('/runners/all?type=bogus', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -213,7 +213,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
let_it_be(:runner) { create(:ci_runner, :project, :inactive, description: 'Inactive project runner', projects: [project]) }
it 'filters runners by status' do
- get api('/runners/all?paused=true', admin)
+ get api('/runners/all?paused=true', admin, admin_mode: true)
expect(json_response).to match_array [
a_hash_including('description' => 'Inactive project runner')
@@ -221,7 +221,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
it 'filters runners by status' do
- get api('/runners/all?status=paused', admin)
+ get api('/runners/all?status=paused', admin, admin_mode: true)
expect(json_response).to match_array [
a_hash_including('description' => 'Inactive project runner')
@@ -230,16 +230,16 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
it 'does not filter by invalid status' do
- get api('/runners/all?status=bogus', admin)
+ get api('/runners/all?status=bogus', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'filters runners by tag_list' do
+ it 'filters runners by tag_list', :aggregate_failures do
create(:ci_runner, :project, description: 'Runner tagged with tag1 and tag2', projects: [project], tag_list: %w[tag1 tag2])
create(:ci_runner, :project, description: 'Runner tagged with tag2', projects: [project], tag_list: ['tag2'])
- get api('/runners/all?tag_list=tag1,tag2', admin)
+ get api('/runners/all?tag_list=tag1,tag2', admin, admin_mode: true)
expect(json_response).to match_array [
a_hash_including('description' => 'Runner tagged with tag1 and tag2')
@@ -268,7 +268,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
describe 'GET /runners/:id' do
context 'admin user' do
context 'when runner is shared' do
- it "returns runner's details" do
+ it "returns runner's details", :aggregate_failures do
get api("/runners/#{shared_runner.id}", admin)
expect(response).to have_gitlab_http_status(:ok)
@@ -284,39 +284,39 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'when unused runner is present' do
let!(:unused_project_runner) { create(:ci_runner, :project, :without_projects) }
- it 'deletes unused runner' do
+ it 'deletes unused runner', :aggregate_failures do
expect do
- delete api("/runners/#{unused_project_runner.id}", admin)
+ delete api("/runners/#{unused_project_runner.id}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:no_content)
end.to change { ::Ci::Runner.project_type.count }.by(-1)
end
end
- it "returns runner's details" do
- get api("/runners/#{project_runner.id}", admin)
+ it "returns runner's details", :aggregate_failures do
+ get api("/runners/#{project_runner.id}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['description']).to eq(project_runner.description)
end
it "returns the project's details for a project runner" do
- get api("/runners/#{project_runner.id}", admin)
+ get api("/runners/#{project_runner.id}", admin, admin_mode: true)
expect(json_response['projects'].first['id']).to eq(project.id)
end
end
it 'returns 404 if runner does not exist' do
- get api('/runners/0', admin)
+ get api('/runners/0', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when the runner is a group runner' do
- it "returns the runner's details" do
- get api("/runners/#{group_runner_a.id}", admin)
+ it "returns the runner's details", :aggregate_failures do
+ get api("/runners/#{group_runner_a.id}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['description']).to eq(group_runner_a.description)
@@ -326,7 +326,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context "runner project's administrative user" do
context 'when runner is not shared' do
- it "returns runner's details" do
+ it "returns runner's details", :aggregate_failures do
get api("/runners/#{project_runner.id}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -335,7 +335,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when runner is shared' do
- it "returns runner's details" do
+ it "returns runner's details", :aggregate_failures do
get api("/runners/#{shared_runner.id}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -373,7 +373,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(shared_runner.reload.description).to eq("#{description}_updated")
end
- it 'runner active state' do
+ it 'runner active state', :aggregate_failures do
active = shared_runner.active
update_runner(shared_runner.id, admin, active: !active)
@@ -381,7 +381,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(shared_runner.reload.active).to eq(!active)
end
- it 'runner paused state' do
+ it 'runner paused state', :aggregate_failures do
active = shared_runner.active
update_runner(shared_runner.id, admin, paused: active)
@@ -389,14 +389,14 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(shared_runner.reload.active).to eq(!active)
end
- it 'runner tag list' do
+ it 'runner tag list', :aggregate_failures do
update_runner(shared_runner.id, admin, tag_list: ['ruby2.1', 'pgsql', 'mysql'])
expect(response).to have_gitlab_http_status(:ok)
expect(shared_runner.reload.tag_list).to include('ruby2.1', 'pgsql', 'mysql')
end
- it 'unrelated runner attribute on an existing runner with too many tags' do
+ it 'unrelated runner attribute on an existing runner with too many tags', :aggregate_failures do
# This test ensures that it is possible to update any attribute on a runner that currently fails the
# validation that ensures that there aren't too many tags associated with a runner
existing_invalid_shared_runner = build(:ci_runner, :instance, tag_list: (1..::Ci::Runner::TAG_LIST_MAX_LENGTH + 1).map { |i| "tag#{i}" })
@@ -409,7 +409,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(existing_invalid_shared_runner.reload.active).to eq(!active)
end
- it 'runner untagged flag' do
+ it 'runner untagged flag', :aggregate_failures do
# Ensure tag list is non-empty before setting untagged to false.
update_runner(shared_runner.id, admin, tag_list: ['ruby2.1', 'pgsql', 'mysql'])
update_runner(shared_runner.id, admin, run_untagged: 'false')
@@ -418,28 +418,28 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(shared_runner.reload.run_untagged?).to be(false)
end
- it 'runner unlocked flag' do
+ it 'runner unlocked flag', :aggregate_failures do
update_runner(shared_runner.id, admin, locked: 'true')
expect(response).to have_gitlab_http_status(:ok)
expect(shared_runner.reload.locked?).to be(true)
end
- it 'runner access level' do
+ it 'runner access level', :aggregate_failures do
update_runner(shared_runner.id, admin, access_level: 'ref_protected')
expect(response).to have_gitlab_http_status(:ok)
expect(shared_runner.reload.ref_protected?).to be_truthy
end
- it 'runner maximum timeout' do
+ it 'runner maximum timeout', :aggregate_failures do
update_runner(shared_runner.id, admin, maximum_timeout: 1234)
expect(response).to have_gitlab_http_status(:ok)
expect(shared_runner.reload.maximum_timeout).to eq(1234)
end
- it 'fails with no parameters' do
+ it 'fails with no parameters', :aggregate_failures do
put api("/runners/#{shared_runner.id}", admin)
shared_runner.reload
@@ -448,7 +448,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when runner is shared' do
- it 'updates runner' do
+ it 'updates runner', :aggregate_failures do
description = shared_runner.description
active = shared_runner.active
runner_queue_value = shared_runner.ensure_runner_queue_value
@@ -476,7 +476,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when runner is not shared' do
- it 'updates runner' do
+ it 'updates runner', :aggregate_failures do
description = project_runner.description
runner_queue_value = project_runner.ensure_runner_queue_value
@@ -498,14 +498,16 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
def update_runner(id, user, args)
- put api("/runners/#{id}", user), params: args
+ put api("/runners/#{id}", user, admin_mode: true), params: args
end
end
context 'authorized user' do
+ let_it_be(:params) { { description: 'test' } }
+
context 'when runner is shared' do
it 'does not update runner' do
- put api("/runners/#{shared_runner.id}", user), params: { description: 'test' }
+ put api("/runners/#{shared_runner.id}", user), params: params
expect(response).to have_gitlab_http_status(:forbidden)
end
@@ -518,12 +520,11 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(response).to have_gitlab_http_status(:forbidden)
end
- it 'updates project runner with access to it' do
+ it 'updates project runner with access to it', :aggregate_failures do
description = project_runner.description
- put api("/runners/#{project_runner.id}", admin), params: { description: 'test' }
+ put api("/runners/#{project_runner.id}", admin, admin_mode: true), params: params
project_runner.reload
- expect(response).to have_gitlab_http_status(:ok)
expect(project_runner.description).to eq('test')
expect(project_runner.description).not_to eq(description)
end
@@ -542,13 +543,13 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
describe 'DELETE /runners/:id' do
context 'admin user' do
context 'when runner is shared' do
- it 'deletes runner' do
+ it 'deletes runner', :aggregate_failures do
expect_next_instance_of(Ci::Runners::UnregisterRunnerService, shared_runner, admin) do |service|
expect(service).to receive(:execute).once.and_call_original
end
expect do
- delete api("/runners/#{shared_runner.id}", admin)
+ delete api("/runners/#{shared_runner.id}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:no_content)
end.to change { ::Ci::Runner.instance_type.count }.by(-1)
@@ -560,25 +561,25 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when runner is not shared' do
- it 'deletes used project runner' do
+ it 'deletes used project runner', :aggregate_failures do
expect_next_instance_of(Ci::Runners::UnregisterRunnerService, project_runner, admin) do |service|
expect(service).to receive(:execute).once.and_call_original
end
expect do
- delete api("/runners/#{project_runner.id}", admin)
+ delete api("/runners/#{project_runner.id}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:no_content)
end.to change { ::Ci::Runner.project_type.count }.by(-1)
end
end
- it 'returns 404 if runner does not exist' do
+ it 'returns 404 if runner does not exist', :aggregate_failures do
allow_next_instance_of(Ci::Runners::UnregisterRunnerService) do |service|
expect(service).not_to receive(:execute)
end
- delete api('/runners/0', admin)
+ delete api('/runners/0', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -603,7 +604,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(response).to have_gitlab_http_status(:forbidden)
end
- it 'deletes project runner for one owned project' do
+ it 'deletes project runner for one owned project', :aggregate_failures do
expect do
delete api("/runners/#{project_runner.id}", user)
@@ -658,7 +659,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'unauthorized user' do
- it 'does not delete project runner' do
+ it 'does not delete project runner', :aggregate_failures do
allow_next_instance_of(Ci::Runners::UnregisterRunnerService) do |service|
expect(service).not_to receive(:execute)
end
@@ -672,31 +673,31 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
describe 'POST /runners/:id/reset_authentication_token' do
context 'admin user' do
- it 'resets shared runner authentication token' do
+ it 'resets shared runner authentication token', :aggregate_failures do
expect do
- post api("/runners/#{shared_runner.id}/reset_authentication_token", admin)
+ post api("/runners/#{shared_runner.id}/reset_authentication_token", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:success)
expect(json_response).to eq({ 'token' => shared_runner.reload.token, 'token_expires_at' => nil })
end.to change { shared_runner.reload.token }
end
- it 'returns 404 if runner does not exist' do
- post api('/runners/0/reset_authentication_token', admin)
+ it 'returns 404 if runner does not exist', :aggregate_failures do
+ post api('/runners/0/reset_authentication_token', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'authorized user' do
- it 'does not reset project runner authentication token without access to it' do
+ it 'does not reset project runner authentication token without access to it', :aggregate_failures do
expect do
post api("/runners/#{project_runner.id}/reset_authentication_token", user2)
expect(response).to have_gitlab_http_status(:forbidden)
end.not_to change { project_runner.reload.token }
end
- it 'resets project runner authentication token for owned project' do
+ it 'resets project runner authentication token for owned project', :aggregate_failures do
expect do
post api("/runners/#{project_runner.id}/reset_authentication_token", user)
@@ -705,7 +706,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end.to change { project_runner.reload.token }
end
- it 'does not reset group runner authentication token with guest access' do
+ it 'does not reset group runner authentication token with guest access', :aggregate_failures do
expect do
post api("/runners/#{group_runner_a.id}/reset_authentication_token", group_guest)
@@ -713,7 +714,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end.not_to change { group_runner_a.reload.token }
end
- it 'does not reset group runner authentication token with reporter access' do
+ it 'does not reset group runner authentication token with reporter access', :aggregate_failures do
expect do
post api("/runners/#{group_runner_a.id}/reset_authentication_token", group_reporter)
@@ -721,7 +722,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end.not_to change { group_runner_a.reload.token }
end
- it 'does not reset group runner authentication token with developer access' do
+ it 'does not reset group runner authentication token with developer access', :aggregate_failures do
expect do
post api("/runners/#{group_runner_a.id}/reset_authentication_token", group_developer)
@@ -729,7 +730,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end.not_to change { group_runner_a.reload.token }
end
- it 'does not reset group runner authentication token with maintainer access' do
+ it 'does not reset group runner authentication token with maintainer access', :aggregate_failures do
expect do
post api("/runners/#{group_runner_a.id}/reset_authentication_token", group_maintainer)
@@ -737,7 +738,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end.not_to change { group_runner_a.reload.token }
end
- it 'resets group runner authentication token with owner access' do
+ it 'resets group runner authentication token with owner access', :aggregate_failures do
expect do
post api("/runners/#{group_runner_a.id}/reset_authentication_token", user)
@@ -746,7 +747,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end.to change { group_runner_a.reload.token }
end
- it 'resets group runner authentication token with owner access with expiration time', :freeze_time do
+ it 'resets group runner authentication token with owner access with expiration time', :aggregate_failures, :freeze_time do
expect(group_runner_a.reload.token_expires_at).to be_nil
group.update!(runner_token_expiration_interval: 5.days)
@@ -763,7 +764,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'unauthorized user' do
- it 'does not reset authentication token' do
+ it 'does not reset authentication token', :aggregate_failures do
expect do
post api("/runners/#{shared_runner.id}/reset_authentication_token")
@@ -783,8 +784,8 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'admin user' do
context 'when runner exists' do
context 'when runner is shared' do
- it 'return jobs' do
- get api("/runners/#{shared_runner.id}/jobs", admin)
+ it 'return jobs', :aggregate_failures do
+ get api("/runners/#{shared_runner.id}/jobs", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -795,8 +796,8 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when runner is a project runner' do
- it 'return jobs' do
- get api("/runners/#{project_runner.id}/jobs", admin)
+ it 'return jobs', :aggregate_failures do
+ get api("/runners/#{project_runner.id}/jobs", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -806,7 +807,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when user does not have authorization to see all jobs' do
- it 'shows only jobs it has permission to see' do
+ it 'shows only jobs it has permission to see', :aggregate_failures do
create(:ci_build, :running, runner: two_projects_runner, project: project)
create(:ci_build, :running, runner: two_projects_runner, project: project2)
@@ -824,8 +825,8 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when valid status is provided' do
- it 'return filtered jobs' do
- get api("/runners/#{project_runner.id}/jobs?status=failed", admin)
+ it 'return filtered jobs', :aggregate_failures do
+ get api("/runners/#{project_runner.id}/jobs?status=failed", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -838,8 +839,8 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'when valid order_by is provided' do
context 'when sort order is not specified' do
- it 'return jobs in descending order' do
- get api("/runners/#{project_runner.id}/jobs?order_by=id", admin)
+ it 'return jobs in descending order', :aggregate_failures do
+ get api("/runners/#{project_runner.id}/jobs?order_by=id", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -851,8 +852,8 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when sort order is specified as asc' do
- it 'return jobs sorted in ascending order' do
- get api("/runners/#{project_runner.id}/jobs?order_by=id&sort=asc", admin)
+ it 'return jobs sorted in ascending order', :aggregate_failures do
+ get api("/runners/#{project_runner.id}/jobs?order_by=id&sort=asc", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -866,7 +867,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'when invalid status is provided' do
it 'return 400' do
- get api("/runners/#{project_runner.id}/jobs?status=non-existing", admin)
+ get api("/runners/#{project_runner.id}/jobs?status=non-existing", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -874,7 +875,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'when invalid order_by is provided' do
it 'return 400' do
- get api("/runners/#{project_runner.id}/jobs?order_by=non-existing", admin)
+ get api("/runners/#{project_runner.id}/jobs?order_by=non-existing", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -882,7 +883,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'when invalid sort is provided' do
it 'return 400' do
- get api("/runners/#{project_runner.id}/jobs?sort=non-existing", admin)
+ get api("/runners/#{project_runner.id}/jobs?sort=non-existing", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -890,16 +891,16 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
it 'avoids N+1 DB queries' do
- get api("/runners/#{shared_runner.id}/jobs", admin)
+ get api("/runners/#{shared_runner.id}/jobs", admin, admin_mode: true)
control = ActiveRecord::QueryRecorder.new do
- get api("/runners/#{shared_runner.id}/jobs", admin)
+ get api("/runners/#{shared_runner.id}/jobs", admin, admin_mode: true)
end
create(:ci_build, :failed, runner: shared_runner, project: project)
expect do
- get api("/runners/#{shared_runner.id}/jobs", admin)
+ get api("/runners/#{shared_runner.id}/jobs", admin, admin_mode: true)
end.not_to exceed_query_limit(control.count)
end
@@ -925,12 +926,12 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
]).once.and_call_original
end
- get api("/runners/#{shared_runner.id}/jobs", admin), params: { per_page: 2, order_by: 'id', sort: 'desc' }
+ get api("/runners/#{shared_runner.id}/jobs", admin, admin_mode: true), params: { per_page: 2, order_by: 'id', sort: 'desc' }
end
context "when runner doesn't exist" do
it 'returns 404' do
- get api('/runners/0/jobs', admin)
+ get api('/runners/0/jobs', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -948,7 +949,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when runner is a project runner' do
- it 'return jobs' do
+ it 'return jobs', :aggregate_failures do
get api("/runners/#{project_runner.id}/jobs", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -960,7 +961,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when valid status is provided' do
- it 'return filtered jobs' do
+ it 'return filtered jobs', :aggregate_failures do
get api("/runners/#{project_runner.id}/jobs?status=failed", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -1027,8 +1028,8 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
describe 'GET /projects/:id/runners' do
context 'authorized user with maintainer privileges' do
- it 'returns response status and headers' do
- get api('/runners/all', admin)
+ it 'returns response status and headers', :aggregate_failures do
+ get api('/runners/all', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -1044,7 +1045,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
]
end
- it 'filters runners by scope' do
+ it 'filters runners by scope', :aggregate_failures do
get api("/projects/#{project.id}/runners?scope=specific", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -1102,7 +1103,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'filters runners by tag_list' do
+ it 'filters runners by tag_list', :aggregate_failures do
create(:ci_runner, :project, description: 'Runner tagged with tag1 and tag2', projects: [project], tag_list: %w[tag1 tag2])
create(:ci_runner, :project, description: 'Runner tagged with tag2', projects: [project], tag_list: ['tag2'])
@@ -1183,7 +1184,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
end
- it 'filters runners by tag_list' do
+ it 'filters runners by tag_list', :aggregate_failures do
create(:ci_runner, :group, description: 'Runner tagged with tag1 and tag2', groups: [group], tag_list: %w[tag1 tag2])
create(:ci_runner, :group, description: 'Runner tagged with tag2', groups: [group], tag_list: %w[tag1])
@@ -1203,21 +1204,21 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'authorized user' do
let_it_be(:project_runner2) { create(:ci_runner, :project, projects: [project2]) }
- it 'enables project runner' do
+ it 'enables project runner', :aggregate_failures do
expect do
post api("/projects/#{project.id}/runners", user), params: { runner_id: project_runner2.id }
end.to change { project.runners.count }.by(+1)
expect(response).to have_gitlab_http_status(:created)
end
- it 'avoids changes when enabling already enabled runner' do
+ it 'avoids changes when enabling already enabled runner', :aggregate_failures do
expect do
post api("/projects/#{project.id}/runners", user), params: { runner_id: project_runner.id }
end.to change { project.runners.count }.by(0)
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'does not enable locked runner' do
+ it 'does not enable locked runner', :aggregate_failures do
project_runner2.update!(locked: true)
expect do
@@ -1243,9 +1244,9 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
context 'when project runner is used' do
let!(:new_project_runner) { create(:ci_runner, :project) }
- it 'enables any project runner' do
+ it 'enables any project runner', :aggregate_failures do
expect do
- post api("/projects/#{project.id}/runners", admin), params: { runner_id: new_project_runner.id }
+ post api("/projects/#{project.id}/runners", admin, admin_mode: true), params: { runner_id: new_project_runner.id }
end.to change { project.runners.count }.by(+1)
expect(response).to have_gitlab_http_status(:created)
end
@@ -1255,9 +1256,9 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
create(:plan_limits, :default_plan, ci_registered_project_runners: 1)
end
- it 'does not enable project runner' do
+ it 'does not enable project runner', :aggregate_failures do
expect do
- post api("/projects/#{project.id}/runners", admin), params: { runner_id: new_project_runner.id }
+ post api("/projects/#{project.id}/runners", admin, admin_mode: true), params: { runner_id: new_project_runner.id }
end.not_to change { project.runners.count }
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -1266,7 +1267,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
it 'raises an error when no runner_id param is provided' do
- post api("/projects/#{project.id}/runners", admin)
+ post api("/projects/#{project.id}/runners", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -1316,7 +1317,7 @@ RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
end
context 'when runner have one associated projects' do
- it "does not disable project's runner" do
+ it "does not disable project's runner", :aggregate_failures do
expect do
delete api("/projects/#{project.id}/runners/#{project_runner.id}", user)
end.to change { project.runners.count }.by(0)
diff --git a/spec/requests/api/ci/variables_spec.rb b/spec/requests/api/ci/variables_spec.rb
index 0f9f1bc80d6..5ea9104cb15 100644
--- a/spec/requests/api/ci/variables_spec.rb
+++ b/spec/requests/api/ci/variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Variables, feature_category: :pipeline_authoring do
+RSpec.describe API::Ci::Variables, feature_category: :pipeline_composition do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, creator_id: user.id) }
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index bcc27a80cf8..b4bc4507021 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -132,6 +132,42 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
it_behaves_like 'project commits'
end
+ context 'with author parameter' do
+ let(:params) { { author: 'Zaporozhets' } }
+
+ it 'returns only this author commits' do
+ get api(route, user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ author_names = json_response.map { |commit| commit['author_name'] }.uniq
+
+ expect(author_names).to contain_exactly('Dmitriy Zaporozhets')
+ end
+
+ context 'when author is missing' do
+ let(:params) { { author: '' } }
+
+ it 'returns all commits' do
+ get api(route, user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.count).to eq(20)
+ end
+ end
+
+ context 'when author does not exists' do
+ let(:params) { { author: 'does not exist' } }
+
+ it 'returns an empty list' do
+ get api(route, user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq([])
+ end
+ end
+ end
+
context 'when repository does not exist' do
let(:project) { create(:project, creator: user, path: 'my.project') }
@@ -425,6 +461,27 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
describe "POST /projects/:id/repository/commits" do
let!(:url) { "/projects/#{project_id}/repository/commits" }
+ context 'when unauthenticated', 'and project is public' do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let(:params) do
+ {
+ branch: 'master',
+ commit_message: 'message',
+ actions: [
+ {
+ action: 'create',
+ file_path: '/test.rb',
+ content: 'puts 8'
+ }
+ ]
+ }
+ end
+
+ it_behaves_like '401 response' do
+ let(:request) { post api(url), params: params }
+ end
+ end
+
it 'returns a 403 unauthorized for user without permissions' do
post api(url, guest)
@@ -523,7 +580,6 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
let(:property) { 'g_edit_by_web_ide' }
let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit' }
let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context] }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
context 'counts.web_ide_commits Snowplow event tracking' do
@@ -1776,7 +1832,7 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
context 'when unauthenticated', 'and project is public' do
let_it_be(:project) { create(:project, :public, :repository) }
- it_behaves_like '403 response' do
+ it_behaves_like '401 response' do
let(:request) { post api(route), params: { branch: 'master' } }
end
end
@@ -1956,7 +2012,7 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
context 'when unauthenticated', 'and project is public' do
let_it_be(:project) { create(:project, :public, :repository) }
- it_behaves_like '403 response' do
+ it_behaves_like '401 response' do
let(:request) { post api(route), params: { branch: branch } }
end
end
diff --git a/spec/requests/api/composer_packages_spec.rb b/spec/requests/api/composer_packages_spec.rb
index 0c726d46a01..2bb2ffa03c4 100644
--- a/spec/requests/api/composer_packages_spec.rb
+++ b/spec/requests/api/composer_packages_spec.rb
@@ -504,7 +504,11 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do
include_context 'Composer user type', params[:user_role], params[:member] do
if params[:expected_status] == :success
let(:snowplow_gitlab_standard_context) do
- { project: project, namespace: project.namespace, property: 'i_package_composer_user' }
+ if user_role == :anonymous || (project_visibility_level == 'PUBLIC' && user_token == false)
+ { project: project, namespace: project.namespace, property: 'i_package_composer_user' }
+ else
+ { project: project, namespace: project.namespace, property: 'i_package_composer_user', user: user }
+ end
end
it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
diff --git a/spec/requests/api/debian_group_packages_spec.rb b/spec/requests/api/debian_group_packages_spec.rb
index 0c80b7d830f..25b99862100 100644
--- a/spec/requests/api/debian_group_packages_spec.rb
+++ b/spec/requests/api/debian_group_packages_spec.rb
@@ -31,9 +31,11 @@ RSpec.describe API::DebianGroupPackages, feature_category: :package_registry do
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
- let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/binary-#{architecture.name}/Packages" }
+ let(:target_component_file) { component_file }
+ let(:target_component_name) { component.name }
+ let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{target_component_name}/binary-#{architecture.name}/Packages" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete Packages file/
+ it_behaves_like 'Debian packages index endpoint', /Description: This is an incomplete Packages file/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages.gz' do
@@ -43,27 +45,37 @@ RSpec.describe API::DebianGroupPackages, feature_category: :package_registry do
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/by-hash/SHA256/:file_sha256' do
- let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/binary-#{architecture.name}/by-hash/SHA256/#{component_file_older_sha256.file_sha256}" }
+ let(:target_component_file) { component_file_older_sha256 }
+ let(:target_component_name) { component.name }
+ let(:target_sha256) { target_component_file.file_sha256 }
+ let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{target_component_name}/binary-#{architecture.name}/by-hash/SHA256/#{target_sha256}" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
+ it_behaves_like 'Debian packages index sha256 endpoint', /^Other SHA256$/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/source/Sources' do
- let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/source/Sources" }
+ let(:target_component_file) { component_file_sources }
+ let(:target_component_name) { component.name }
+ let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{target_component_name}/source/Sources" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete Sources file/
+ it_behaves_like 'Debian packages index endpoint', /^Description: This is an incomplete Sources file$/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/source/by-hash/SHA256/:file_sha256' do
- let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/source/by-hash/SHA256/#{component_file_sources_older_sha256.file_sha256}" }
+ let(:target_component_file) { component_file_sources_older_sha256 }
+ let(:target_component_name) { component.name }
+ let(:target_sha256) { target_component_file.file_sha256 }
+ let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{target_component_name}/source/by-hash/SHA256/#{target_sha256}" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
+ it_behaves_like 'Debian packages index sha256 endpoint', /^Other SHA256$/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/Packages' do
- let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/debian-installer/binary-#{architecture.name}/Packages" }
+ let(:target_component_file) { component_file_di }
+ let(:target_component_name) { component.name }
+ let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{target_component_name}/debian-installer/binary-#{architecture.name}/Packages" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete D-I Packages file/
+ it_behaves_like 'Debian packages index endpoint', /Description: This is an incomplete D-I Packages file/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/Packages.gz' do
@@ -73,9 +85,12 @@ RSpec.describe API::DebianGroupPackages, feature_category: :package_registry do
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/by-hash/SHA256/:file_sha256' do
- let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/debian-installer/binary-#{architecture.name}/by-hash/SHA256/#{component_file_di_older_sha256.file_sha256}" }
+ let(:target_component_file) { component_file_di_older_sha256 }
+ let(:target_component_name) { component.name }
+ let(:target_sha256) { target_component_file.file_sha256 }
+ let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{target_component_name}/debian-installer/binary-#{architecture.name}/by-hash/SHA256/#{target_sha256}" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
+ it_behaves_like 'Debian packages index sha256 endpoint', /^Other SHA256$/
end
describe 'GET groups/:id/-/packages/debian/pool/:codename/:project_id/:letter/:package_name/:package_version/:file_name' do
@@ -89,6 +104,7 @@ RSpec.describe API::DebianGroupPackages, feature_category: :package_registry do
'sample_1.2.3~alpha2.dsc' | /^Format: 3.0 \(native\)/
'libsample0_1.2.3~alpha2_amd64.deb' | /^!<arch>/
'sample-udeb_1.2.3~alpha2_amd64.udeb' | /^!<arch>/
+ 'sample-ddeb_1.2.3~alpha2_amd64.ddeb' | /^!<arch>/
'sample_1.2.3~alpha2_amd64.buildinfo' | /Build-Tainted-By/
'sample_1.2.3~alpha2_amd64.changes' | /urgency=medium/
end
diff --git a/spec/requests/api/debian_project_packages_spec.rb b/spec/requests/api/debian_project_packages_spec.rb
index 46f79efd928..e9ad39a08ab 100644
--- a/spec/requests/api/debian_project_packages_spec.rb
+++ b/spec/requests/api/debian_project_packages_spec.rb
@@ -44,9 +44,11 @@ RSpec.describe API::DebianProjectPackages, feature_category: :package_registry d
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
- let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/binary-#{architecture.name}/Packages" }
+ let(:target_component_file) { component_file }
+ let(:target_component_name) { component.name }
+ let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{target_component_name}/binary-#{architecture.name}/Packages" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete Packages file/
+ it_behaves_like 'Debian packages index endpoint', /Description: This is an incomplete Packages file/
it_behaves_like 'accept GET request on private project with access to package registry for everyone'
end
@@ -57,30 +59,40 @@ RSpec.describe API::DebianProjectPackages, feature_category: :package_registry d
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/binary-:architecture/by-hash/SHA256/:file_sha256' do
- let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/binary-#{architecture.name}/by-hash/SHA256/#{component_file_older_sha256.file_sha256}" }
+ let(:target_component_file) { component_file_older_sha256 }
+ let(:target_component_name) { component.name }
+ let(:target_sha256) { target_component_file.file_sha256 }
+ let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{target_component_name}/binary-#{architecture.name}/by-hash/SHA256/#{target_sha256}" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
+ it_behaves_like 'Debian packages index sha256 endpoint', /^Other SHA256$/
it_behaves_like 'accept GET request on private project with access to package registry for everyone'
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/source/Sources' do
- let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/source/Sources" }
+ let(:target_component_file) { component_file_sources }
+ let(:target_component_name) { component.name }
+ let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{target_component_name}/source/Sources" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete Sources file/
+ it_behaves_like 'Debian packages index endpoint', /^Description: This is an incomplete Sources file$/
it_behaves_like 'accept GET request on private project with access to package registry for everyone'
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/source/by-hash/SHA256/:file_sha256' do
- let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/source/by-hash/SHA256/#{component_file_sources_older_sha256.file_sha256}" }
+ let(:target_component_file) { component_file_sources_older_sha256 }
+ let(:target_component_name) { component.name }
+ let(:target_sha256) { target_component_file.file_sha256 }
+ let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{target_component_name}/source/by-hash/SHA256/#{target_sha256}" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
+ it_behaves_like 'Debian packages index sha256 endpoint', /^Other SHA256$/
it_behaves_like 'accept GET request on private project with access to package registry for everyone'
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/Packages' do
- let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/debian-installer/binary-#{architecture.name}/Packages" }
+ let(:target_component_file) { component_file_di }
+ let(:target_component_name) { component.name }
+ let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{target_component_name}/debian-installer/binary-#{architecture.name}/Packages" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete D-I Packages file/
+ it_behaves_like 'Debian packages index endpoint', /Description: This is an incomplete D-I Packages file/
it_behaves_like 'accept GET request on private project with access to package registry for everyone'
end
@@ -91,9 +103,12 @@ RSpec.describe API::DebianProjectPackages, feature_category: :package_registry d
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/by-hash/SHA256/:file_sha256' do
- let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/debian-installer/binary-#{architecture.name}/by-hash/SHA256/#{component_file_di_older_sha256.file_sha256}" }
+ let(:target_component_file) { component_file_di_older_sha256 }
+ let(:target_component_name) { component.name }
+ let(:target_sha256) { target_component_file.file_sha256 }
+ let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{target_component_name}/debian-installer/binary-#{architecture.name}/by-hash/SHA256/#{target_sha256}" }
- it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
+ it_behaves_like 'Debian packages index sha256 endpoint', /^Other SHA256$/
it_behaves_like 'accept GET request on private project with access to package registry for everyone'
end
@@ -108,6 +123,7 @@ RSpec.describe API::DebianProjectPackages, feature_category: :package_registry d
'sample_1.2.3~alpha2.dsc' | /^Format: 3.0 \(native\)/
'libsample0_1.2.3~alpha2_amd64.deb' | /^!<arch>/
'sample-udeb_1.2.3~alpha2_amd64.udeb' | /^!<arch>/
+ 'sample-ddeb_1.2.3~alpha2_amd64.ddeb' | /^!<arch>/
'sample_1.2.3~alpha2_amd64.buildinfo' | /Build-Tainted-By/
'sample_1.2.3~alpha2_amd64.changes' | /urgency=medium/
end
@@ -162,7 +178,7 @@ RSpec.describe API::DebianProjectPackages, feature_category: :package_registry d
let(:extra_params) { { distribution: distribution.codename, component: 'main' } }
it_behaves_like "Debian packages upload request", :bad_request,
- /^file_name Only debs and udebs can be directly added to a distribution$/
+ /^file_name Only debs, udebs and ddebs can be directly added to a distribution$/
end
end
end
diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb
index 5116f074894..888220c2251 100644
--- a/spec/requests/api/doorkeeper_access_spec.rb
+++ b/spec/requests/api/doorkeeper_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'doorkeeper access', feature_category: :authentication_and_authorization do
+RSpec.describe 'doorkeeper access', feature_category: :system_access do
let!(:user) { create(:user) }
let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
diff --git a/spec/requests/api/draft_notes_spec.rb b/spec/requests/api/draft_notes_spec.rb
index e8f519e004d..d239853ac1d 100644
--- a/spec/requests/api/draft_notes_spec.rb
+++ b/spec/requests/api/draft_notes_spec.rb
@@ -8,11 +8,16 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
let_it_be(:project) { create(:project, :public) }
let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
+ let_it_be(:private_project) { create(:project, :private) }
+ let_it_be(:private_merge_request) do
+ create(:merge_request, source_project: private_project, target_project: private_project)
+ end
+
let_it_be(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
let!(:draft_note_by_current_user) { create(:draft_note, merge_request: merge_request, author: user) }
let!(:draft_note_by_random_user) { create(:draft_note, merge_request: merge_request) }
- let_it_be(:api_stub) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}" }
+ let_it_be(:base_url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes" }
before do
project.add_developer(user)
@@ -20,13 +25,13 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
describe "Get a list of merge request draft notes" do
it "returns 200 OK status" do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes", user)
+ get api(base_url, user)
expect(response).to have_gitlab_http_status(:ok)
end
it "returns only draft notes authored by the current user" do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes", user)
+ get api(base_url, user)
draft_note_ids = json_response.pluck("id")
@@ -40,7 +45,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
context "when requesting an existing draft note by the user" do
before do
get api(
- "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_current_user.id}",
+ "#{base_url}/#{draft_note_by_current_user.id}",
user
)
end
@@ -56,7 +61,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
context "when requesting a non-existent draft note" do
it "returns a 404 Not Found response" do
get api(
- "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{DraftNote.last.id + 1}",
+ "#{base_url}/#{DraftNote.last.id + 1}",
user
)
@@ -67,7 +72,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
context "when requesting an existing draft note by another user" do
it "returns a 404 Not Found response" do
get api(
- "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_random_user.id}",
+ "#{base_url}/#{draft_note_by_random_user.id}",
user
)
@@ -83,7 +88,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
before do
delete api(
- "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_current_user.id}",
+ "#{base_url}/#{draft_note_by_current_user.id}",
user
)
end
@@ -100,7 +105,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
context "when deleting a non-existent draft note" do
it "returns a 404 Not Found" do
delete api(
- "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{non_existing_record_id}",
+ "#{base_url}/#{non_existing_record_id}",
user
)
@@ -111,7 +116,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
context "when deleting a draft note by a different user" do
it "returns a 404 Not Found" do
delete api(
- "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_random_user.id}",
+ "#{base_url}/#{draft_note_by_random_user.id}",
user
)
@@ -120,10 +125,152 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
end
end
+ def create_draft_note(params = {}, url = base_url)
+ post api(url, user), params: params
+ end
+
+ describe "Create a new draft note" do
+ let(:basic_create_params) do
+ {
+ note: "Example body string"
+ }
+ end
+
+ context "when creating a new draft note" do
+ context "with required params" do
+ it "returns 201 Created status" do
+ create_draft_note(basic_create_params)
+
+ expect(response).to have_gitlab_http_status(:created)
+ end
+
+ it "creates a new draft note with the submitted params" do
+ expect { create_draft_note(basic_create_params) }.to change { DraftNote.count }.by(1)
+
+ expect(json_response["note"]).to eq(basic_create_params[:note])
+ expect(json_response["merge_request_id"]).to eq(merge_request.id)
+ expect(json_response["author_id"]).to eq(user.id)
+ end
+ end
+
+ context "without required params" do
+ it "returns 400 Bad Request status" do
+ create_draft_note({})
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context "when providing a non-existing commit_id" do
+ it "returns a 400 Bad Request" do
+ create_draft_note(
+ basic_create_params.merge(
+ commit_id: 'bad SHA'
+ )
+ )
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context "when targeting a merge request the user doesn't have access to" do
+ it "returns a 404 Not Found" do
+ create_draft_note(
+ basic_create_params,
+ "/projects/#{private_project.id}/merge_requests/#{private_merge_request.iid}"
+ )
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context "when attempting to resolve a disscussion" do
+ context "when providing a non-existant ID" do
+ it "returns a 400 Bad Request" do
+ create_draft_note(
+ basic_create_params.merge(
+ resolve_discussion: true,
+ in_reply_to_discussion_id: non_existing_record_id
+ )
+ )
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context "when not providing an ID" do
+ it "returns a 400 Bad Request" do
+ create_draft_note(basic_create_params.merge(resolve_discussion: true))
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it "returns a validation error message" do
+ create_draft_note(basic_create_params.merge(resolve_discussion: true))
+
+ expect(response.body)
+ .to eq("{\"message\":{\"base\":[\"User is not allowed to resolve thread\"]}}")
+ end
+ end
+ end
+ end
+ end
+
+ def update_draft_note(params = {}, url = base_url)
+ put api("#{url}/#{draft_note_by_current_user.id}", user), params: params
+ end
+
+ describe "Update a draft note" do
+ let(:basic_update_params) do
+ {
+ note: "Example updated body string"
+ }
+ end
+
+ context "when updating an existing draft note" do
+ context "with required params" do
+ it "returns 200 Success status" do
+ update_draft_note(basic_update_params)
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+
+ it "updates draft note with the new content" do
+ update_draft_note(basic_update_params)
+
+ expect(json_response["note"]).to eq(basic_update_params[:note])
+ end
+ end
+
+ context "without including an update to the note body" do
+ it "returns the draft note with no changes" do
+ expect { update_draft_note({}) }
+ .not_to change { draft_note_by_current_user.note }
+ end
+ end
+
+ context "when updating a non-existent draft note" do
+ it "returns a 404 Not Found" do
+ put api("#{base_url}/#{non_existing_record_id}", user), params: basic_update_params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context "when updating a draft note by a different user" do
+ it "returns a 404 Not Found" do
+ put api("#{base_url}/#{draft_note_by_random_user.id}", user), params: basic_update_params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
describe "Publishing a draft note" do
let(:publish_draft_note) do
put api(
- "#{api_stub}/draft_notes/#{draft_note_by_current_user.id}/publish",
+ "#{base_url}/#{draft_note_by_current_user.id}/publish",
user
)
end
@@ -144,7 +291,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
context "when publishing a non-existent draft note" do
it "returns a 404 Not Found" do
put api(
- "#{api_stub}/draft_notes/#{non_existing_record_id}/publish",
+ "#{base_url}/#{non_existing_record_id}/publish",
user
)
@@ -155,7 +302,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
context "when publishing a draft note by a different user" do
it "returns a 404 Not Found" do
put api(
- "#{api_stub}/draft_notes/#{draft_note_by_random_user.id}/publish",
+ "#{base_url}/#{draft_note_by_random_user.id}/publish",
user
)
diff --git a/spec/requests/api/error_tracking/project_settings_spec.rb b/spec/requests/api/error_tracking/project_settings_spec.rb
index 5906cdf105a..3b01dec6f9c 100644
--- a/spec/requests/api/error_tracking/project_settings_spec.rb
+++ b/spec/requests/api/error_tracking/project_settings_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
end
end
- shared_examples 'returns 404' do
+ shared_examples 'returns no project settings' do
it 'returns no project settings' do
make_request
@@ -48,6 +48,57 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
end
end
+ shared_examples 'returns 400' do
+ it 'rejects request' do
+ make_request
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ shared_examples 'returns 401' do
+ it 'rejects request' do
+ make_request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ shared_examples 'returns 403' do
+ it 'rejects request' do
+ make_request
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ shared_examples 'returns 404' do
+ it 'rejects request' do
+ make_request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ shared_examples 'returns 400 with `integrated` param required or invalid' do |error|
+ it 'returns 400' do
+ make_request
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error'])
+ .to eq(error)
+ end
+ end
+
+ shared_examples "returns error from UpdateService" do
+ it "returns errors" do
+ make_request
+
+ expect(json_response['http_status']).to eq('forbidden')
+ expect(json_response['message']).to eq('An error occurred')
+ end
+ end
+
describe "PATCH /projects/:id/error_tracking/settings" do
let(:params) { { active: false } }
@@ -127,14 +178,34 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
end
context 'without a project setting' do
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
before do
project.add_maintainer(user)
end
context 'patch settings' do
- it_behaves_like 'returns 404'
+ it_behaves_like 'returns no project settings'
+ end
+ end
+
+ context "when ::Projects::Operations::UpdateService responds with an error" do
+ before do
+ allow_next_instance_of(::Projects::Operations::UpdateService) do |service|
+ allow(service)
+ .to receive(:execute)
+ .and_return({ status: :error, message: 'An error occurred', http_status: :forbidden })
+ end
+ end
+
+ context "when integrated" do
+ let(:integrated) { true }
+
+ it_behaves_like 'returns error from UpdateService'
+ end
+
+ context "without integrated" do
+ it_behaves_like 'returns error from UpdateService'
end
end
end
@@ -145,11 +216,7 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
end
context 'patch request' do
- it 'returns 403' do
- make_request
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ it_behaves_like 'returns 403'
end
end
@@ -159,21 +226,13 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
end
context 'patch request' do
- it 'returns 403' do
- make_request
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ it_behaves_like 'returns 403'
end
end
context 'when authenticated as non-member' do
context 'patch request' do
- it 'returns 404' do
- make_request
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
+ it_behaves_like 'returns 404'
end
end
@@ -181,11 +240,7 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
let(:user) { nil }
context 'patch request' do
- it 'returns 401 for update request' do
- make_request
-
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
+ it_behaves_like 'returns 401'
end
end
end
@@ -227,7 +282,7 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
end
context 'get settings' do
- it_behaves_like 'returns 404'
+ it_behaves_like 'returns no project settings'
end
end
@@ -236,11 +291,7 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
project.add_reporter(user)
end
- it 'returns 403' do
- make_request
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ it_behaves_like 'returns 403'
end
context 'when authenticated as developer' do
@@ -248,29 +299,138 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
project.add_developer(user)
end
- it 'returns 403' do
- make_request
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ it_behaves_like 'returns 403'
end
context 'when authenticated as non-member' do
- it 'returns 404' do
- make_request
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
+ it_behaves_like 'returns 404'
end
context 'when unauthenticated' do
let(:user) { nil }
- it 'returns 401' do
- make_request
+ it_behaves_like 'returns 401'
+ end
+ end
+
+ describe "PUT /projects/:id/error_tracking/settings" do
+ let(:params) { { active: active, integrated: integrated } }
+ let(:active) { true }
+ let(:integrated) { true }
+
+ def make_request
+ put api("/projects/#{project.id}/error_tracking/settings", user), params: params
+ end
+
+ context 'when authenticated' do
+ context 'as maintainer' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ context "when integrated" do
+ let(:integrated) { true }
+
+ context "with existing setting" do
+ let(:setting) { create(:project_error_tracking_setting, :integrated) }
+ let(:active) { false }
+
+ it "updates a setting" do
+ expect { make_request }.not_to change { ErrorTracking::ProjectErrorTrackingSetting.count }
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(json_response).to eq(
+ "active" => false,
+ "api_url" => nil,
+ "integrated" => integrated,
+ "project_name" => nil,
+ "sentry_external_url" => nil
+ )
+ end
+ end
+
+ context "without setting" do
+ let(:active) { true }
+ let_it_be(:project) { create(:project) }
+
+ it "creates a setting" do
+ expect { make_request }.to change { ErrorTracking::ProjectErrorTrackingSetting.count }
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(json_response).to eq(
+ "active" => true,
+ "api_url" => nil,
+ "integrated" => integrated,
+ "project_name" => nil,
+ "sentry_external_url" => nil
+ )
+ end
+ end
+
+ context "when ::Projects::Operations::UpdateService responds with an error" do
+ before do
+ allow_next_instance_of(::Projects::Operations::UpdateService) do |service|
+ allow(service)
+ .to receive(:execute)
+ .and_return({ status: :error, message: 'An error occurred', http_status: :forbidden })
+ end
+ end
+
+ it_behaves_like 'returns error from UpdateService'
+ end
+ end
- expect(response).to have_gitlab_http_status(:unauthorized)
+ context "integrated_error_tracking feature disabled" do
+ let(:integrated) { true }
+
+ before do
+ stub_feature_flags(integrated_error_tracking: false)
+ end
+
+ it_behaves_like 'returns 404'
+ end
+
+ context "when integrated param is invalid" do
+ let(:params) { { active: active, integrated: 'invalid_string' } }
+
+ it_behaves_like 'returns 400 with `integrated` param required or invalid', 'integrated is invalid'
+ end
+
+ context "when integrated param is missing" do
+ let(:params) { { active: active } }
+
+ it_behaves_like 'returns 400 with `integrated` param required or invalid', 'integrated is missing'
+ end
+ end
+
+ context 'as reporter' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it_behaves_like 'returns 403'
+ end
+
+ context "as developer" do
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'returns 403'
end
+
+ context 'as non-member' do
+ it_behaves_like 'returns 404'
+ end
+ end
+
+ context "when unauthorized" do
+ let(:user) { nil }
+ let(:integrated) { true }
+
+ it_behaves_like 'returns 401'
end
end
end
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index f4066c54c47..ed84e3e5f48 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -55,6 +55,11 @@ RSpec.describe API::Files, feature_category: :source_code_management do
}
end
+ let(:last_commit_for_path) do
+ Gitlab::Git::Commit
+ .last_for_path(project.repository, 'master', Addressable::URI.unencode_component(file_path))
+ end
+
shared_context 'with author parameters' do
let(:author_email) { 'user@example.org' }
let(:author_name) { 'John Doe' }
@@ -136,6 +141,12 @@ RSpec.describe API::Files, feature_category: :source_code_management do
it 'caches sha256 of the content', :use_clean_rails_redis_caching do
head api(route(file_path), current_user, **options), params: params
+ expect(Gitlab::Cache::Client).to receive(:build_with_metadata).with(
+ cache_identifier: 'API::Files#content_sha',
+ feature_category: :source_code_management,
+ backing_resource: :gitaly
+ ).and_call_original
+
expect(Rails.cache.fetch("blob_content_sha256:#{project.full_path}:#{response.headers['X-Gitlab-Blob-Id']}"))
.to eq(content_sha256)
@@ -829,7 +840,6 @@ RSpec.describe API::Files, feature_category: :source_code_management do
expect_to_send_git_blob(api(url, current_user), params)
expect(response.headers['Cache-Control']).to eq('max-age=0, private, must-revalidate, no-store, no-cache')
- expect(response.headers['Pragma']).to eq('no-cache')
expect(response.headers['Expires']).to eq('Fri, 01 Jan 1990 00:00:00 GMT')
end
@@ -1180,7 +1190,7 @@ RSpec.describe API::Files, feature_category: :source_code_management do
end
context 'when updating an existing file with stale last commit id' do
- let(:params_with_stale_id) { params.merge(last_commit_id: 'stale') }
+ let(:params_with_stale_id) { params.merge(last_commit_id: last_commit_for_path.parent_id) }
it 'returns a 400 bad request' do
put api(route(file_path), user), params: params_with_stale_id
@@ -1191,12 +1201,7 @@ RSpec.describe API::Files, feature_category: :source_code_management do
end
context 'with correct last commit id' do
- let(:last_commit) do
- Gitlab::Git::Commit
- .last_for_path(project.repository, 'master', Addressable::URI.unencode_component(file_path))
- end
-
- let(:params_with_correct_id) { params.merge(last_commit_id: last_commit.id) }
+ let(:params_with_correct_id) { params.merge(last_commit_id: last_commit_for_path.id) }
it 'updates existing file in project repo' do
put api(route(file_path), user), params: params_with_correct_id
@@ -1206,12 +1211,7 @@ RSpec.describe API::Files, feature_category: :source_code_management do
end
context 'when file path is invalid' do
- let(:last_commit) do
- Gitlab::Git::Commit
- .last_for_path(project.repository, 'master', Addressable::URI.unencode_component(file_path))
- end
-
- let(:params_with_correct_id) { params.merge(last_commit_id: last_commit.id) }
+ let(:params_with_correct_id) { params.merge(last_commit_id: last_commit_for_path.id) }
it 'returns a 400 bad request' do
put api(route(invalid_file_path), user), params: params_with_correct_id
@@ -1222,12 +1222,7 @@ RSpec.describe API::Files, feature_category: :source_code_management do
end
it_behaves_like 'when path is absolute' do
- let(:last_commit) do
- Gitlab::Git::Commit
- .last_for_path(project.repository, 'master', Addressable::URI.unencode_component(file_path))
- end
-
- let(:params_with_correct_id) { params.merge(last_commit_id: last_commit.id) }
+ let(:params_with_correct_id) { params.merge(last_commit_id: last_commit_for_path.id) }
subject { put api(route(absolute_path), user), params: params_with_correct_id }
end
diff --git a/spec/requests/api/freeze_periods_spec.rb b/spec/requests/api/freeze_periods_spec.rb
index 170871706dc..a53db516940 100644
--- a/spec/requests/api/freeze_periods_spec.rb
+++ b/spec/requests/api/freeze_periods_spec.rb
@@ -12,14 +12,12 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
let(:last_freeze_period) { project.freeze_periods.last }
describe 'GET /projects/:id/freeze_periods' do
+ let_it_be(:path) { "/projects/#{project.id}/freeze_periods" }
+
context 'when the user is the admin' do
let!(:freeze_period) { create(:ci_freeze_period, project: project, created_at: 2.days.ago) }
- it 'returns 200 HTTP status' do
- get api("/projects/#{project.id}/freeze_periods", admin)
-
- expect(response).to have_gitlab_http_status(:ok)
- end
+ it_behaves_like 'GET request permissions for admin mode when admin', :not_found
end
context 'when the user is the maintainer' do
@@ -31,36 +29,26 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
let!(:freeze_period_1) { create(:ci_freeze_period, project: project, created_at: 2.days.ago) }
let!(:freeze_period_2) { create(:ci_freeze_period, project: project, created_at: 1.day.ago) }
- it 'returns 200 HTTP status' do
- get api("/projects/#{project.id}/freeze_periods", user)
+ it 'returns freeze_periods ordered by created_at ascending', :aggregate_failures do
+ get api(path, user)
expect(response).to have_gitlab_http_status(:ok)
- end
-
- it 'returns freeze_periods ordered by created_at ascending' do
- get api("/projects/#{project.id}/freeze_periods", user)
-
expect(json_response.count).to eq(2)
expect(freeze_period_ids).to eq([freeze_period_1.id, freeze_period_2.id])
end
it 'matches response schema' do
- get api("/projects/#{project.id}/freeze_periods", user)
+ get api(path, user)
expect(response).to match_response_schema('public_api/v4/freeze_periods')
end
end
context 'when there are no freeze_periods' do
- it 'returns 200 HTTP status' do
- get api("/projects/#{project.id}/freeze_periods", user)
+ it 'returns 200 HTTP status with empty response', :aggregate_failures do
+ get api(path, user)
expect(response).to have_gitlab_http_status(:ok)
- end
-
- it 'returns an empty response' do
- get api("/projects/#{project.id}/freeze_periods", user)
-
expect(json_response).to be_empty
end
end
@@ -75,28 +63,21 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
create(:ci_freeze_period, project: project)
end
- it 'responds 403 Forbidden' do
- get api("/projects/#{project.id}/freeze_periods", user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'GET request permissions for admin mode when user', :forbidden do
+ let(:current_user) { user }
+ end
end
end
context 'when user is not a project member' do
- it 'responds 404 Not Found' do
- get api("/projects/#{project.id}/freeze_periods", user)
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
+ it_behaves_like 'GET request permissions for admin mode when user', :not_found
context 'when project is public' do
let(:project) { create(:project, :public) }
+ let(:path) { "/projects/#{project.id}/freeze_periods" }
- it 'responds 403 Forbidden' do
- get api("/projects/#{project.id}/freeze_periods", user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ it_behaves_like 'GET request permissions for admin mode when user', :forbidden
end
end
end
@@ -107,14 +88,12 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
create(:ci_freeze_period, project: project)
end
+ let(:path) { "/projects/#{project.id}/freeze_periods/#{freeze_period.id}" }
+
context 'when the user is the admin' do
let!(:freeze_period) { create(:ci_freeze_period, project: project, created_at: 2.days.ago) }
- it 'responds 200 OK' do
- get api("/projects/#{project.id}/freeze_periods/#{freeze_period.id}", admin)
-
- expect(response).to have_gitlab_http_status(:ok)
- end
+ it_behaves_like 'GET request permissions for admin mode when admin', :not_found
end
context 'when the user is the maintainer' do
@@ -122,15 +101,10 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
project.add_maintainer(user)
end
- it 'responds 200 OK' do
- get api("/projects/#{project.id}/freeze_periods/#{freeze_period.id}", user)
+ it 'returns a freeze period', :aggregate_failures do
+ get api(path, user)
expect(response).to have_gitlab_http_status(:ok)
- end
-
- it 'returns a freeze period' do
- get api("/projects/#{project.id}/freeze_periods/#{freeze_period.id}", user)
-
expect(json_response).to include(
'id' => freeze_period.id,
'freeze_start' => freeze_period.freeze_start,
@@ -139,7 +113,7 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
end
it 'matches response schema' do
- get api("/projects/#{project.id}/freeze_periods/#{freeze_period.id}", user)
+ get api(path, user)
expect(response).to match_response_schema('public_api/v4/freeze_period')
end
@@ -150,28 +124,26 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
project.add_guest(user)
end
- it 'responds 403 Forbidden' do
- get api("/projects/#{project.id}/freeze_periods/#{freeze_period.id}", user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'GET request permissions for admin mode when user' do
+ let(:current_user) { user }
+ end
end
context 'when project is public' do
let(:project) { create(:project, :public) }
- context 'when freeze_period exists' do
- it 'responds 403 Forbidden' do
- get api("/projects/#{project.id}/freeze_periods/#{freeze_period.id}", user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden when freeze_period exists' do
+ it_behaves_like 'GET request permissions for admin mode when user' do
+ let(:current_user) { user }
end
end
- context 'when freeze_period does not exist' do
- it 'responds 403 Forbidden' do
- get api("/projects/#{project.id}/freeze_periods/0", user)
+ context 'and responds 403 Forbidden when freeze_period does not exist' do
+ let(:path) { "/projects/#{project.id}/freeze_periods/0" }
- expect(response).to have_gitlab_http_status(:forbidden)
+ it_behaves_like 'GET request permissions for admin mode when user' do
+ let(:current_user) { user }
end
end
end
@@ -188,15 +160,13 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
}
end
- subject { post api("/projects/#{project.id}/freeze_periods", api_user), params: params }
+ let(:path) { "/projects/#{project.id}/freeze_periods" }
- context 'when the user is the admin' do
- let(:api_user) { admin }
-
- it 'accepts the request' do
- subject
+ subject { post api(path, api_user), params: params }
- expect(response).to have_gitlab_http_status(:created)
+ context 'when the user is the admin' do
+ it_behaves_like 'POST request permissions for admin mode when admin', :not_found do
+ let(:current_user) { admin }
end
end
@@ -212,7 +182,7 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
expect(response).to have_gitlab_http_status(:created)
end
- it 'creates a new freeze period' do
+ it 'creates a new freeze period', :aggregate_failures do
expect do
subject
end.to change { Ci::FreezePeriod.count }.by(1)
@@ -268,10 +238,10 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
project.add_developer(user)
end
- it 'responds 403 Forbidden' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'POST request permissions for admin mode when user' do
+ let(:current_user) { user }
+ end
end
end
@@ -280,28 +250,22 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
project.add_reporter(user)
end
- it 'responds 403 Forbidden' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'POST request permissions for admin mode when user' do
+ let(:current_user) { user }
+ end
end
end
context 'when user is not a project member' do
- it 'responds 403 Forbidden' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'POST request permissions for admin mode when user', :not_found
end
context 'when project is public' do
let(:project) { create(:project, :public) }
- it 'responds 403 Forbidden' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ it_behaves_like 'POST request permissions for admin mode when user', :forbidden
end
end
end
@@ -309,17 +273,12 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
describe 'PUT /projects/:id/freeze_periods/:freeze_period_id' do
let(:params) { { freeze_start: '0 22 * * 5', freeze_end: '5 4 * * sun' } }
let!(:freeze_period) { create :ci_freeze_period, project: project }
+ let(:path) { "/projects/#{project.id}/freeze_periods/#{freeze_period.id}" }
- subject { put api("/projects/#{project.id}/freeze_periods/#{freeze_period.id}", api_user), params: params }
+ subject { put api(path, api_user), params: params }
context 'when user is the admin' do
- let(:api_user) { admin }
-
- it 'accepts the request' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- end
+ it_behaves_like 'PUT request permissions for admin mode when admin', :not_found
end
context 'when user is the maintainer' do
@@ -367,27 +326,23 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
project.add_reporter(user)
end
- it 'responds 403 Forbidden' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'PUT request permissions for admin mode when user' do
+ let(:current_user) { user }
+ end
end
end
context 'when user is not a project member' do
- it 'responds 404 Not Found' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
+ context 'and responds 404 Not Found' do
+ it_behaves_like 'PUT request permissions for admin mode when user', :not_found
end
context 'when project is public' do
let(:project) { create(:project, :public) }
- it 'responds 403 Forbidden' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'PUT request permissions for admin mode when user'
end
end
end
@@ -396,17 +351,12 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
describe 'DELETE /projects/:id/freeze_periods/:freeze_period_id' do
let!(:freeze_period) { create :ci_freeze_period, project: project }
let(:freeze_period_id) { freeze_period.id }
+ let(:path) { "/projects/#{project.id}/freeze_periods/#{freeze_period_id}" }
- subject { delete api("/projects/#{project.id}/freeze_periods/#{freeze_period_id}", api_user) }
+ subject { delete api(path, api_user) }
context 'when user is the admin' do
- let(:api_user) { admin }
-
- it 'accepts the request' do
- subject
-
- expect(response).to have_gitlab_http_status(:no_content)
- end
+ it_behaves_like 'DELETE request permissions for admin mode when admin', failed_status_code: :not_found
end
context 'when user is the maintainer' do
@@ -442,27 +392,23 @@ RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
project.add_reporter(user)
end
- it 'responds 403 Forbidden' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'DELETE request permissions for admin mode when user' do
+ let(:current_user) { user }
+ end
end
end
context 'when user is not a project member' do
- it 'responds 404 Not Found' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
+ context 'and responds 404 Not Found' do
+ it_behaves_like 'DELETE request permissions for admin mode when user', :not_found
end
context 'when project is public' do
let(:project) { create(:project, :public) }
- it 'responds 403 Forbidden' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'and responds 403 Forbidden' do
+ it_behaves_like 'DELETE request permissions for admin mode when user'
end
end
end
diff --git a/spec/requests/api/graphql/achievements/user_achievements_query_spec.rb b/spec/requests/api/graphql/achievements/user_achievements_query_spec.rb
new file mode 100644
index 00000000000..dc19f3bdc91
--- /dev/null
+++ b/spec/requests/api/graphql/achievements/user_achievements_query_spec.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'UserAchievements', feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+ let_it_be(:user_achievement1) { create(:user_achievement, achievement: achievement, user: user) }
+ let_it_be(:user_achievement2) { create(:user_achievement, :revoked, achievement: achievement, user: user) }
+ let_it_be(:fields) do
+ <<~HEREDOC
+ id
+ achievements {
+ nodes {
+ userAchievements {
+ nodes {
+ id
+ achievement {
+ id
+ }
+ user {
+ id
+ }
+ awardedByUser {
+ id
+ }
+ revokedByUser {
+ id
+ }
+ }
+ }
+ }
+ }
+ HEREDOC
+ end
+
+ let_it_be(:query) do
+ graphql_query_for('namespace', { full_path: group.full_path }, fields)
+ end
+
+ before_all do
+ group.add_guest(user)
+ end
+
+ before do
+ post_graphql(query, current_user: user)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns all user_achievements' do
+ expect(graphql_data_at(:namespace, :achievements, :nodes, :userAchievements, :nodes))
+ .to contain_exactly(
+ a_graphql_entity_for(user_achievement1),
+ a_graphql_entity_for(user_achievement2)
+ )
+ end
+
+ it 'can lookahead to eliminate N+1 queries', :use_clean_rails_memory_store_caching do
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ post_graphql(query, current_user: user)
+ end.count
+
+ user2 = create(:user)
+ create_list(:achievement, 3, namespace: group) do |a|
+ create(:user_achievement, achievement: a, user: user2)
+ end
+
+ expect { post_graphql(query, current_user: user) }.not_to exceed_all_query_limit(control_count)
+ end
+
+ context 'when the achievements feature flag is disabled' do
+ before do
+ stub_feature_flags(achievements: false)
+ post_graphql(query, current_user: user)
+ end
+
+ specify { expect(graphql_data_at(:namespace, :achievements, :nodes, :userAchievements, :nodes)).to be_empty }
+ end
+end
diff --git a/spec/requests/api/graphql/ci/config_variables_spec.rb b/spec/requests/api/graphql/ci/config_variables_spec.rb
index f76bb8ff837..d77e66d2239 100644
--- a/spec/requests/api/graphql/ci/config_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/config_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).ciConfigVariables(sha)', feature_category: :pipeline_authoring do
+RSpec.describe 'Query.project(fullPath).ciConfigVariables(sha)', feature_category: :pipeline_composition do
include GraphqlHelpers
include ReactiveCachingHelpers
diff --git a/spec/requests/api/graphql/ci/group_variables_spec.rb b/spec/requests/api/graphql/ci/group_variables_spec.rb
index d78b30787c9..042f93e9779 100644
--- a/spec/requests/api/graphql/ci/group_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/group_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.group(fullPath).ciVariables', feature_category: :pipeline_authoring do
+RSpec.describe 'Query.group(fullPath).ciVariables', feature_category: :pipeline_composition do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/ci/instance_variables_spec.rb b/spec/requests/api/graphql/ci/instance_variables_spec.rb
index 5b65ae88426..286a7af3c01 100644
--- a/spec/requests/api/graphql/ci/instance_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/instance_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.ciVariables', feature_category: :pipeline_authoring do
+RSpec.describe 'Query.ciVariables', feature_category: :pipeline_composition do
include GraphqlHelpers
let(:query) do
diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb
index 674407c0a0e..3f556a75869 100644
--- a/spec/requests/api/graphql/ci/jobs_spec.rb
+++ b/spec/requests/api/graphql/ci/jobs_spec.rb
@@ -260,6 +260,68 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati
end
end
+ describe '.jobs.runnerMachine' do
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:runner_machine) { create(:ci_runner_machine, created_at: Time.current, contacted_at: Time.current) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:build) do
+ create(:ci_build, pipeline: pipeline, name: 'my test job', runner_machine: runner_machine)
+ end
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ pipeline(iid: "#{pipeline.iid}") {
+ jobs {
+ nodes {
+ id
+ name
+ runnerMachine {
+ #{all_graphql_fields_for('CiRunnerMachine', excluded: [:runner], max_depth: 1)}
+ }
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ let(:jobs_graphql_data) { graphql_data_at(:project, :pipeline, :jobs, :nodes) }
+
+ it 'returns the runner machine in each job of a pipeline' do
+ post_graphql(query, current_user: admin)
+
+ expect(jobs_graphql_data).to contain_exactly(
+ a_graphql_entity_for(
+ build,
+ name: build.name,
+ runner_machine: a_graphql_entity_for(
+ runner_machine,
+ system_id: runner_machine.system_xid,
+ created_at: runner_machine.created_at.iso8601,
+ contacted_at: runner_machine.contacted_at.iso8601,
+ status: runner_machine.status.to_s.upcase
+ )
+ )
+ )
+ end
+
+ it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do
+ admin2 = create(:admin)
+
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ post_graphql(query, current_user: admin)
+ end
+
+ runner_machine2 = create(:ci_runner_machine)
+ create(:ci_build, pipeline: pipeline, name: 'my test job2', runner_machine: runner_machine2)
+
+ expect { post_graphql(query, current_user: admin2) }.not_to exceed_all_query_limit(control)
+ end
+ end
+
describe '.jobs.count' do
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:successful_job) { create(:ci_build, :success, pipeline: pipeline) }
diff --git a/spec/requests/api/graphql/ci/manual_variables_spec.rb b/spec/requests/api/graphql/ci/manual_variables_spec.rb
index 921c69e535d..98d91e9ded0 100644
--- a/spec/requests/api/graphql/ci/manual_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/manual_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).pipelines.jobs.manualVariables', feature_category: :pipeline_authoring do
+RSpec.describe 'Query.project(fullPath).pipelines.jobs.manualVariables', feature_category: :pipeline_composition do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/ci/project_variables_spec.rb b/spec/requests/api/graphql/ci/project_variables_spec.rb
index 0ddcac89b34..947991a2e62 100644
--- a/spec/requests/api/graphql/ci/project_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/project_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).ciVariables', feature_category: :pipeline_authoring do
+RSpec.describe 'Query.project(fullPath).ciVariables', feature_category: :pipeline_composition do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 986e3ce9e52..da71ee675b7 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -6,11 +6,13 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
include GraphqlHelpers
let_it_be(:user) { create(:user, :admin) }
+ let_it_be(:another_admin) { create(:user, :admin) }
let_it_be(:group) { create(:group) }
let_it_be(:active_instance_runner) do
- create(:ci_runner, :instance,
+ create(:ci_runner, :instance, :with_runner_machine,
description: 'Runner 1',
+ creator: user,
contacted_at: 2.hours.ago,
active: true,
version: 'adfe156',
@@ -28,6 +30,7 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
let_it_be(:inactive_instance_runner) do
create(:ci_runner, :instance,
description: 'Runner 2',
+ creator: another_admin,
contacted_at: 1.day.ago,
active: false,
version: 'adfe157',
@@ -55,7 +58,9 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
end
let_it_be(:project1) { create(:project) }
- let_it_be(:active_project_runner) { create(:ci_runner, :project, projects: [project1]) }
+ let_it_be(:active_project_runner) do
+ create(:ci_runner, :project, :with_runner_machine, projects: [project1])
+ end
shared_examples 'runner details fetch' do
let(:query) do
@@ -77,6 +82,7 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
expect(runner_data).to match a_graphql_entity_for(
runner,
description: runner.description,
+ created_by: runner.creator ? a_graphql_entity_for(runner.creator) : nil,
created_at: runner.created_at&.iso8601,
contacted_at: runner.contacted_at&.iso8601,
version: runner.version,
@@ -107,15 +113,39 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
),
project_count: nil,
admin_url: "http://localhost/admin/runners/#{runner.id}",
+ edit_admin_url: "http://localhost/admin/runners/#{runner.id}/edit",
+ register_admin_url: runner.registration_available? ? "http://localhost/admin/runners/#{runner.id}/register" : nil,
user_permissions: {
'readRunner' => true,
'updateRunner' => true,
'deleteRunner' => true,
'assignRunner' => true
- }
+ },
+ machines: a_hash_including(
+ "count" => runner.runner_machines.count,
+ "nodes" => an_instance_of(Array),
+ "pageInfo" => anything
+ )
)
expect(runner_data['tagList']).to match_array runner.tag_list
end
+
+ it 'does not execute more queries per runner', :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 { 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_query_limit(control)
+ end
end
shared_examples 'retrieval with no admin url' do
@@ -135,7 +165,7 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
runner_data = graphql_data_at(:runner)
expect(runner_data).not_to be_nil
- expect(runner_data).to match a_graphql_entity_for(runner, admin_url: nil)
+ expect(runner_data).to match a_graphql_entity_for(runner, admin_url: nil, edit_admin_url: nil)
expect(runner_data['tagList']).to match_array runner.tag_list
end
end
@@ -307,6 +337,24 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
it_behaves_like 'runner details fetch'
end
+ describe 'for registration type' do
+ context 'when registered with registration token' do
+ let(:runner) do
+ create(:ci_runner, registration_type: :registration_token)
+ end
+
+ it_behaves_like 'runner details fetch'
+ end
+
+ context 'when registered with authenticated user' do
+ let(:runner) do
+ create(:ci_runner, registration_type: :authenticated_user)
+ end
+
+ it_behaves_like 'runner details fetch'
+ end
+ end
+
describe 'for group runner request' do
let(:query) do
%(
@@ -568,14 +616,14 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
end
end
- context 'with request made by creator' do
+ context 'with request made by creator', :frozen_time do
let(:user) { creator }
context 'with runner created in UI' do
let(:registration_type) { :authenticated_user }
- context 'with runner created in last 3 hours' do
- let(:created_at) { (3.hours - 1.second).ago }
+ context 'with runner created in last hour' do
+ let(:created_at) { (Ci::Runner::REGISTRATION_AVAILABILITY_TIME - 1.second).ago }
context 'with no runner machine registed yet' do
it_behaves_like 'an ephemeral_authentication_token'
@@ -589,13 +637,13 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
end
context 'with runner created almost too long ago' do
- let(:created_at) { (3.hours - 1.second).ago }
+ let(:created_at) { (Ci::Runner::REGISTRATION_AVAILABILITY_TIME - 1.second).ago }
it_behaves_like 'an ephemeral_authentication_token'
end
context 'with runner created too long ago' do
- let(:created_at) { 3.hours.ago }
+ let(:created_at) { Ci::Runner::REGISTRATION_AVAILABILITY_TIME.ago }
it_behaves_like 'a protected ephemeral_authentication_token'
end
@@ -604,8 +652,8 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
context 'with runner registered from command line' do
let(:registration_type) { :registration_token }
- context 'with runner created in last 3 hours' do
- let(:created_at) { (3.hours - 1.second).ago }
+ context 'with runner created in last 1 hour' do
+ let(:created_at) { (Ci::Runner::REGISTRATION_AVAILABILITY_TIME - 1.second).ago }
it_behaves_like 'a protected ephemeral_authentication_token'
end
@@ -628,6 +676,12 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
<<~SINGLE
runner(id: "#{runner.to_global_id}") {
#{all_graphql_fields_for('CiRunner', excluded: excluded_fields)}
+ createdBy {
+ id
+ username
+ webPath
+ webUrl
+ }
groups {
nodes {
id
@@ -658,7 +712,7 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
let(:active_group_runner2) { create(:ci_runner, :group) }
# Exclude fields that are already hardcoded above
- let(:excluded_fields) { %w[jobs groups projects ownerProject] }
+ let(:excluded_fields) { %w[createdBy jobs groups projects ownerProject] }
let(:single_query) do
<<~QUERY
@@ -691,6 +745,8 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
control = ActiveRecord::QueryRecorder.new { post_graphql(single_query, **args) }
+ personal_access_token = create(:personal_access_token, user: another_admin)
+ args = { current_user: another_admin, token: { personal_access_token: personal_access_token } }
expect { post_graphql(double_query, **args) }.not_to exceed_query_limit(control)
expect(graphql_data.count).to eq 6
diff --git a/spec/requests/api/graphql/ci/runners_spec.rb b/spec/requests/api/graphql/ci/runners_spec.rb
index 75d8609dc38..c8706ae9698 100644
--- a/spec/requests/api/graphql/ci/runners_spec.rb
+++ b/spec/requests/api/graphql/ci/runners_spec.rb
@@ -11,16 +11,24 @@ RSpec.describe 'Query.runners', feature_category: :runner_fleet do
let_it_be(:instance_runner) { create(:ci_runner, :instance, version: 'abc', revision: '123', description: 'Instance runner', ip_address: '127.0.0.1') }
let_it_be(:project_runner) { create(:ci_runner, :project, active: false, version: 'def', revision: '456', description: 'Project runner', projects: [project], ip_address: '127.0.0.1') }
- let(:runners_graphql_data) { graphql_data['runners'] }
+ let(:runners_graphql_data) { graphql_data_at(:runners) }
let(:params) { {} }
let(:fields) do
<<~QUERY
nodes {
- #{all_graphql_fields_for('CiRunner', excluded: %w[ownerProject])}
+ #{all_graphql_fields_for('CiRunner', excluded: %w[createdBy ownerProject])}
+ createdBy {
+ username
+ webPath
+ webUrl
+ }
ownerProject {
id
+ path
+ fullPath
+ webUrl
}
}
QUERY
@@ -50,6 +58,25 @@ RSpec.describe 'Query.runners', feature_category: :runner_fleet do
it 'returns expected runner' do
expect(runners_graphql_data['nodes']).to contain_exactly(a_graphql_entity_for(expected_runner))
end
+
+ it 'does not execute more queries per runner', :aggregate_failures do
+ # warm-up license cache and so on:
+ personal_access_token = create(:personal_access_token, user: current_user)
+ args = { current_user: current_user, token: { personal_access_token: personal_access_token } }
+ post_graphql(query, **args)
+ expect(graphql_data_at(:runners, :nodes)).not_to be_empty
+
+ admin2 = create(:admin)
+ personal_access_token = create(:personal_access_token, user: admin2)
+ 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],
+ creator: current_user)
+
+ expect { post_graphql(query, **args) }.not_to exceed_query_limit(control)
+ end
end
context 'runner_type is INSTANCE_TYPE and status is ACTIVE' do
diff --git a/spec/requests/api/graphql/current_user/todos_query_spec.rb b/spec/requests/api/graphql/current_user/todos_query_spec.rb
index f7e23aeb241..ee019a99f8d 100644
--- a/spec/requests/api/graphql/current_user/todos_query_spec.rb
+++ b/spec/requests/api/graphql/current_user/todos_query_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'Query current user todos', feature_category: :source_code_manage
let(:fields) do
<<~QUERY
nodes {
- #{all_graphql_fields_for('todos'.classify, max_depth: 2)}
+ #{all_graphql_fields_for('todos'.classify, max_depth: 2, excluded: ['productAnalyticsState'])}
}
QUERY
end
diff --git a/spec/requests/api/graphql/current_user_query_spec.rb b/spec/requests/api/graphql/current_user_query_spec.rb
index 53d2580caee..aceef77920d 100644
--- a/spec/requests/api/graphql/current_user_query_spec.rb
+++ b/spec/requests/api/graphql/current_user_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting project information', feature_category: :authentication_and_authorization do
+RSpec.describe 'getting project information', feature_category: :system_access do
include GraphqlHelpers
let(:fields) do
diff --git a/spec/requests/api/graphql/custom_emoji_query_spec.rb b/spec/requests/api/graphql/custom_emoji_query_spec.rb
index 7b804623e01..1858ea831dd 100644
--- a/spec/requests/api/graphql/custom_emoji_query_spec.rb
+++ b/spec/requests/api/graphql/custom_emoji_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting custom emoji within namespace', feature_category: :not_owned do
+RSpec.describe 'getting custom emoji within namespace', feature_category: :shared do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/multiplexed_queries_spec.rb b/spec/requests/api/graphql/multiplexed_queries_spec.rb
index 4d615d3eaa4..0a5c87ebef8 100644
--- a/spec/requests/api/graphql/multiplexed_queries_spec.rb
+++ b/spec/requests/api/graphql/multiplexed_queries_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Multiplexed queries', feature_category: :not_owned do
+RSpec.describe 'Multiplexed queries', feature_category: :shared do
include GraphqlHelpers
it 'returns responses for multiple queries' do
diff --git a/spec/requests/api/graphql/mutations/achievements/award_spec.rb b/spec/requests/api/graphql/mutations/achievements/award_spec.rb
new file mode 100644
index 00000000000..9bc0751e924
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/achievements/award_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Achievements::Award, feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+ let_it_be(:recipient) { create(:user) }
+
+ let(:mutation) { graphql_mutation(:achievements_award, params) }
+ let(:achievement_id) { achievement&.to_global_id }
+ let(:recipient_id) { recipient&.to_global_id }
+ let(:params) do
+ {
+ achievement_id: achievement_id,
+ user_id: recipient_id
+ }
+ end
+
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+ def mutation_response
+ graphql_mutation_response(:achievements_create)
+ end
+
+ before_all do
+ group.add_developer(developer)
+ group.add_maintainer(maintainer)
+ end
+
+ context 'when the user does not have permission' do
+ let(:current_user) { developer }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not create an achievement' do
+ expect { subject }.not_to change { Achievements::UserAchievement.count }
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { maintainer }
+
+ context 'when the params are invalid' do
+ let(:achievement) { nil }
+
+ it 'returns the validation error' do
+ subject
+
+ expect(graphql_errors.to_s).to include('invalid value for achievementId (Expected value to not be null)')
+ end
+ end
+
+ context 'when the recipient_id is invalid' do
+ let(:recipient_id) { "gid://gitlab/User/#{non_existing_record_id}" }
+
+ it 'returns the validation error' do
+ subject
+
+ expect(graphql_data_at(:achievements_award,
+ :errors)).to include("Couldn't find User with 'id'=#{non_existing_record_id}")
+ end
+ end
+
+ context 'when the achievement_id is invalid' do
+ let(:achievement_id) { "gid://gitlab/Achievements::Achievement/#{non_existing_record_id}" }
+
+ it 'returns the validation error' do
+ subject
+
+ expect(graphql_errors.to_s)
+ .to include("The resource that you are attempting to access does not exist or you don't have permission")
+ end
+ end
+
+ context 'when the feature flag is disabled' do
+ before do
+ stub_feature_flags(achievements: false)
+ end
+
+ it 'returns the relevant error' do
+ subject
+
+ expect(graphql_errors.to_s)
+ .to include("The resource that you are attempting to access does not exist or you don't have permission")
+ end
+ end
+
+ it 'creates an achievement' do
+ expect { subject }.to change { Achievements::UserAchievement.count }.by(1)
+ end
+
+ it 'returns the new achievement' do
+ subject
+
+ expect(graphql_data_at(:achievements_award, :user_achievement, :achievement, :id))
+ .to eq(achievement.to_global_id.to_s)
+ expect(graphql_data_at(:achievements_award, :user_achievement, :user, :id))
+ .to eq(recipient.to_global_id.to_s)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/achievements/revoke_spec.rb b/spec/requests/api/graphql/mutations/achievements/revoke_spec.rb
new file mode 100644
index 00000000000..925a1bb9fcc
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/achievements/revoke_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Achievements::Revoke, feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+ let_it_be(:user_achievement) { create(:user_achievement, achievement: achievement) }
+
+ let(:mutation) { graphql_mutation(:achievements_revoke, params) }
+ let(:user_achievement_id) { user_achievement&.to_global_id }
+ let(:params) { { user_achievement_id: user_achievement_id } }
+
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+ def mutation_response
+ graphql_mutation_response(:achievements_create)
+ end
+
+ before_all do
+ group.add_developer(developer)
+ group.add_maintainer(maintainer)
+ end
+
+ context 'when the user does not have permission' do
+ let(:current_user) { developer }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not revoke any achievements' do
+ expect { subject }.not_to change { Achievements::UserAchievement.where(revoked_by_user_id: nil).count }
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { maintainer }
+
+ context 'when the params are invalid' do
+ let(:user_achievement) { nil }
+
+ it 'returns the validation error' do
+ subject
+
+ expect(graphql_errors.to_s).to include('invalid value for userAchievementId (Expected value to not be null)')
+ end
+ end
+
+ context 'when the user_achievement_id is invalid' do
+ let(:user_achievement_id) { "gid://gitlab/Achievements::UserAchievement/#{non_existing_record_id}" }
+
+ it 'returns the validation error' do
+ subject
+
+ expect(graphql_errors.to_s)
+ .to include("The resource that you are attempting to access does not exist or you don't have permission")
+ end
+ end
+
+ context 'when the feature flag is disabled' do
+ before do
+ stub_feature_flags(achievements: false)
+ end
+
+ it 'returns the relevant error' do
+ subject
+
+ expect(graphql_errors.to_s)
+ .to include("The resource that you are attempting to access does not exist or you don't have permission")
+ end
+ end
+
+ it 'revokes an achievement' do
+ expect { subject }.to change { Achievements::UserAchievement.where(revoked_by_user_id: nil).count }.by(-1)
+ end
+
+ it 'returns the revoked achievement' do
+ subject
+
+ expect(graphql_data_at(:achievements_revoke, :user_achievement, :achievement, :id))
+ .to eq(achievement.to_global_id.to_s)
+ expect(graphql_data_at(:achievements_revoke, :user_achievement, :revoked_by_user, :id))
+ .to eq(current_user.to_global_id.to_s)
+ expect(graphql_data_at(:achievements_revoke, :user_achievement, :revoked_at))
+ .not_to be_nil
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb b/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
index 64ea6d32f5f..b3d25155a6f 100644
--- a/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
+++ b/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues, feature_category: :not_owned do
+RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues, feature_category: :shared do
include GraphqlHelpers
let_it_be(:admin) { create(:admin) }
diff --git a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
index fdbff0f93cd..18cc85d36e0 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Adding an AwardEmoji', feature_category: :not_owned do
+RSpec.describe 'Adding an AwardEmoji', feature_category: :shared do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
index e200bfc2d18..7ec2b061a88 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Removing an AwardEmoji', feature_category: :not_owned do
+RSpec.describe 'Removing an AwardEmoji', feature_category: :shared do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
index 6dba2b58357..7c6a487cdd0 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Toggling an AwardEmoji', feature_category: :not_owned do
+RSpec.describe 'Toggling an AwardEmoji', feature_category: :shared do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/job/cancel_spec.rb b/spec/requests/api/graphql/mutations/ci/job/cancel_spec.rb
new file mode 100644
index 00000000000..abad1ae0812
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job/cancel_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "JobCancel", feature_category: :continuous_integration do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
+ let_it_be(:job) { create(:ci_build, pipeline: pipeline, name: 'build') }
+
+ let(:mutation) do
+ variables = {
+ id: job.to_global_id.to_s
+ }
+ graphql_mutation(:job_cancel, variables,
+ <<-QL
+ errors
+ job {
+ id
+ }
+ QL
+ )
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:job_cancel) }
+
+ it 'returns an error if the user is not allowed to cancel the job' do
+ project.add_developer(user)
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(graphql_errors).not_to be_empty
+ end
+
+ it 'cancels a job' do
+ job_id = ::Gitlab::GlobalId.build(job, id: job.id).to_s
+ project.add_maintainer(user)
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['job']['id']).to eq(job_id)
+ expect(job.reload.status).to eq('canceled')
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/job/play_spec.rb b/spec/requests/api/graphql/mutations/ci/job/play_spec.rb
new file mode 100644
index 00000000000..8100274ed97
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job/play_spec.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'JobPlay', feature_category: :continuous_integration do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
+ let_it_be(:job) { create(:ci_build, :playable, pipeline: pipeline, name: 'build') }
+
+ let(:variables) do
+ {
+ id: job.to_global_id.to_s
+ }
+ end
+
+ let(:mutation) do
+ graphql_mutation(:job_play, variables,
+ <<-QL
+ errors
+ job {
+ id
+ manualVariables {
+ nodes {
+ key
+ }
+ }
+ }
+ QL
+ )
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:job_play) }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ it 'returns an error if the user is not allowed to play the job' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ end
+
+ it 'plays a job' do
+ job_id = ::Gitlab::GlobalId.build(job, id: job.id).to_s
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['job']['id']).to eq(job_id)
+ end
+
+ context 'when given variables' do
+ let(:variables) do
+ {
+ id: job.to_global_id.to_s,
+ variables: [
+ { key: 'MANUAL_VAR_1', value: 'test var' },
+ { key: 'MANUAL_VAR_2', value: 'test var 2' }
+ ]
+ }
+ end
+
+ it 'provides those variables to the job', :aggregated_errors do
+ expect_next_instance_of(Ci::PlayBuildService) do |instance|
+ expect(instance).to receive(:execute).with(an_instance_of(Ci::Build), variables[:variables]).and_call_original
+ end
+
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['job']['manualVariables']['nodes'].pluck('key')).to contain_exactly(
+ 'MANUAL_VAR_1', 'MANUAL_VAR_2'
+ )
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/job/retry_spec.rb b/spec/requests/api/graphql/mutations/ci/job/retry_spec.rb
new file mode 100644
index 00000000000..4114c77491b
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job/retry_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'JobRetry', feature_category: :continuous_integration do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
+
+ let(:job) { create(:ci_build, :success, pipeline: pipeline, name: 'build') }
+
+ let(:mutation) do
+ variables = {
+ id: job.to_global_id.to_s
+ }
+ graphql_mutation(:job_retry, variables,
+ <<-QL
+ errors
+ job {
+ id
+ }
+ QL
+ )
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:job_retry) }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ it 'returns an error if the user is not allowed to retry the job' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ end
+
+ it 'retries a job' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ new_job_id = GitlabSchema.object_from_id(mutation_response['job']['id']).sync.id
+
+ new_job = ::Ci::Build.find(new_job_id)
+ expect(new_job).not_to be_retried
+ end
+
+ context 'when given CI variables' do
+ let(:job) { create(:ci_build, :success, :actionable, pipeline: pipeline, name: 'build') }
+
+ let(:mutation) do
+ variables = {
+ id: job.to_global_id.to_s,
+ variables: { key: 'MANUAL_VAR', value: 'test manual var' }
+ }
+
+ graphql_mutation(:job_retry, variables,
+ <<-QL
+ errors
+ job {
+ id
+ }
+ QL
+ )
+ end
+
+ it 'applies them to a retried manual job' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+
+ new_job_id = GitlabSchema.object_from_id(mutation_response['job']['id']).sync.id
+ new_job = ::Ci::Build.find(new_job_id)
+ expect(new_job.job_variables.count).to be(1)
+ expect(new_job.job_variables.first.key).to eq('MANUAL_VAR')
+ expect(new_job.job_variables.first.value).to eq('test manual var')
+ end
+ end
+
+ context 'when the job is not retryable' do
+ let(:job) { create(:ci_build, :retried, pipeline: pipeline) }
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(mutation_response['job']).to be(nil)
+ expect(mutation_response['errors']).to match_array(['Job cannot be retried'])
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/job/unschedule_spec.rb b/spec/requests/api/graphql/mutations/ci/job/unschedule_spec.rb
new file mode 100644
index 00000000000..08e155e808b
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job/unschedule_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'JobUnschedule', feature_category: :continuous_integration do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
+ let_it_be(:job) { create(:ci_build, :scheduled, pipeline: pipeline, name: 'build') }
+
+ let(:mutation) do
+ variables = {
+ id: job.to_global_id.to_s
+ }
+ graphql_mutation(:job_unschedule, variables,
+ <<-QL
+ errors
+ job {
+ id
+ }
+ QL
+ )
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:job_unschedule) }
+
+ it 'returns an error if the user is not allowed to unschedule the job' do
+ project.add_developer(user)
+
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(graphql_errors).not_to be_empty
+ expect(job.reload.status).to eq('scheduled')
+ end
+
+ it 'unschedules a job' do
+ project.add_maintainer(user)
+
+ job_id = ::Gitlab::GlobalId.build(job, id: job.id).to_s
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['job']['id']).to eq(job_id)
+ expect(job.reload.status).to eq('manual')
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/job_artifact/bulk_destroy_spec.rb b/spec/requests/api/graphql/mutations/ci/job_artifact/bulk_destroy_spec.rb
new file mode 100644
index 00000000000..4e25669a0ca
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job_artifact/bulk_destroy_spec.rb
@@ -0,0 +1,197 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'BulkDestroy', feature_category: :build_artifacts do
+ include GraphqlHelpers
+
+ let(:maintainer) { create(:user) }
+ let(:developer) { create(:user) }
+ let(:first_artifact) { create(:ci_job_artifact) }
+ let(:second_artifact) { create(:ci_job_artifact, project: project) }
+ let(:second_artifact_another_project) { create(:ci_job_artifact) }
+ let(:project) { first_artifact.job.project }
+ let(:ids) { [first_artifact.to_global_id.to_s] }
+ let(:not_authorized_project_error_message) do
+ "The resource that you are attempting to access " \
+ "does not exist or you don't have permission to perform this action"
+ end
+
+ let(:mutation) do
+ variables = {
+ project_id: project.to_global_id.to_s,
+ ids: ids
+ }
+ graphql_mutation(:bulk_destroy_job_artifacts, variables, <<~FIELDS)
+ destroyedCount
+ destroyedIds
+ errors
+ FIELDS
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:bulk_destroy_job_artifacts) }
+
+ it 'fails to destroy the artifact if a user not in a project' do
+ post_graphql_mutation(mutation, current_user: maintainer)
+
+ expect(graphql_errors).to include(
+ a_hash_including('message' => not_authorized_project_error_message)
+ )
+
+ expect(first_artifact.reload).to be_persisted
+ end
+
+ context 'when the `ci_job_artifact_bulk_destroy` feature flag is disabled' do
+ before do
+ stub_feature_flags(ci_job_artifact_bulk_destroy: false)
+ project.add_maintainer(maintainer)
+ end
+
+ it 'returns a resource not available error' do
+ post_graphql_mutation(mutation, current_user: maintainer)
+
+ expect(graphql_errors).to contain_exactly(
+ hash_including(
+ 'message' => '`ci_job_artifact_bulk_destroy` feature flag is disabled.'
+ )
+ )
+ end
+ end
+
+ context "when the user is a developer in a project" do
+ before do
+ project.add_developer(developer)
+ end
+
+ it 'fails to destroy the artifact' do
+ post_graphql_mutation(mutation, current_user: developer)
+
+ expect(graphql_errors).to include(
+ a_hash_including('message' => not_authorized_project_error_message)
+ )
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(first_artifact.reload).to be_persisted
+ end
+ end
+
+ context "when the user is a maintainer in a project" do
+ before do
+ project.add_maintainer(maintainer)
+ end
+
+ shared_examples 'failing mutation' do
+ it 'rejects the request' do
+ post_graphql_mutation(mutation, current_user: maintainer)
+
+ expect(graphql_errors(mutation_response)).to include(expected_error_message)
+
+ expected_not_found_artifacts.each do |artifact|
+ expect { artifact.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ expected_found_artifacts.each do |artifact|
+ expect(artifact.reload).to be_persisted
+ end
+ end
+ end
+
+ it 'destroys the artifact' do
+ post_graphql_mutation(mutation, current_user: maintainer)
+
+ expect(mutation_response).to include("destroyedCount" => 1, "destroyedIds" => [gid_string(first_artifact)])
+ expect(response).to have_gitlab_http_status(:success)
+ expect { first_artifact.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ context "and one artifact doesn't belong to the project" do
+ let(:not_owned_artifact) { create(:ci_job_artifact) }
+ let(:ids) { [first_artifact.to_global_id.to_s, not_owned_artifact.to_global_id.to_s] }
+ let(:expected_error_message) { "Not all artifacts belong to requested project" }
+ let(:expected_not_found_artifacts) { [] }
+ let(:expected_found_artifacts) { [first_artifact, not_owned_artifact] }
+
+ it_behaves_like 'failing mutation'
+ end
+
+ context "and multiple artifacts belong to the maintainer's project" do
+ let(:ids) { [first_artifact.to_global_id.to_s, second_artifact.to_global_id.to_s] }
+
+ it 'destroys all artifacts' do
+ post_graphql_mutation(mutation, current_user: maintainer)
+
+ expect(mutation_response).to include(
+ "destroyedCount" => 2,
+ "destroyedIds" => [gid_string(first_artifact), gid_string(second_artifact)]
+ )
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect { first_artifact.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ expect { second_artifact.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+
+ context "and one artifact belongs to a different maintainer's project" do
+ let(:ids) { [first_artifact.to_global_id.to_s, second_artifact_another_project.to_global_id.to_s] }
+ let(:expected_found_artifacts) { [first_artifact, second_artifact_another_project] }
+ let(:expected_not_found_artifacts) { [] }
+ let(:expected_error_message) { "Not all artifacts belong to requested project" }
+
+ it_behaves_like 'failing mutation'
+ end
+
+ context "and not found" do
+ let(:ids) { [first_artifact.to_global_id.to_s, second_artifact.to_global_id.to_s] }
+ let(:not_found_ids) { expected_not_found_artifacts.map(&:id).join(',') }
+ let(:expected_error_message) { "Artifacts (#{not_found_ids}) not found" }
+
+ before do
+ expected_not_found_artifacts.each(&:destroy!)
+ end
+
+ context "with one artifact" do
+ let(:expected_not_found_artifacts) { [second_artifact] }
+ let(:expected_found_artifacts) { [first_artifact] }
+
+ it_behaves_like 'failing mutation'
+ end
+
+ context "with all artifact" do
+ let(:expected_not_found_artifacts) { [first_artifact, second_artifact] }
+ let(:expected_found_artifacts) { [] }
+
+ it_behaves_like 'failing mutation'
+ end
+ end
+
+ context 'when empty request' do
+ before do
+ project.add_maintainer(maintainer)
+ end
+
+ context 'with nil value' do
+ let(:ids) { nil }
+
+ it 'does nothing and returns empty answer' do
+ post_graphql_mutation(mutation, current_user: maintainer)
+
+ expect_graphql_errors_to_include(/was provided invalid value for ids \(Expected value to not be null\)/)
+ end
+ end
+
+ context 'with empty array' do
+ let(:ids) { [] }
+
+ it 'raises argument error' do
+ post_graphql_mutation(mutation, current_user: maintainer)
+
+ expect_graphql_errors_to_include(/IDs array of job artifacts can not be empty/)
+ end
+ end
+ end
+
+ def gid_string(object)
+ Gitlab::GlobalId.build(object, id: object.id).to_s
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb b/spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb
deleted file mode 100644
index 468a9e57f56..00000000000
--- a/spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe "JobCancel", feature_category: :continuous_integration do
- include GraphqlHelpers
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
- let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
- let_it_be(:job) { create(:ci_build, pipeline: pipeline, name: 'build') }
-
- let(:mutation) do
- variables = {
- id: job.to_global_id.to_s
- }
- graphql_mutation(:job_cancel, variables,
- <<-QL
- errors
- job {
- id
- }
- QL
- )
- end
-
- let(:mutation_response) { graphql_mutation_response(:job_cancel) }
-
- it 'returns an error if the user is not allowed to cancel the job' do
- project.add_developer(user)
- post_graphql_mutation(mutation, current_user: user)
-
- expect(graphql_errors).not_to be_empty
- end
-
- it 'cancels a job' do
- job_id = ::Gitlab::GlobalId.build(job, id: job.id).to_s
- project.add_maintainer(user)
- post_graphql_mutation(mutation, current_user: user)
-
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['job']['id']).to eq(job_id)
- expect(job.reload.status).to eq('canceled')
- end
-end
diff --git a/spec/requests/api/graphql/mutations/ci/job_play_spec.rb b/spec/requests/api/graphql/mutations/ci/job_play_spec.rb
deleted file mode 100644
index 9ba80e51dee..00000000000
--- a/spec/requests/api/graphql/mutations/ci/job_play_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'JobPlay', feature_category: :continuous_integration do
- include GraphqlHelpers
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
- let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
- let_it_be(:job) { create(:ci_build, :playable, pipeline: pipeline, name: 'build') }
-
- let(:variables) do
- {
- id: job.to_global_id.to_s
- }
- end
-
- let(:mutation) do
- graphql_mutation(:job_play, variables,
- <<-QL
- errors
- job {
- id
- manualVariables {
- nodes {
- key
- }
- }
- }
- QL
- )
- end
-
- let(:mutation_response) { graphql_mutation_response(:job_play) }
-
- before_all do
- project.add_maintainer(user)
- end
-
- it 'returns an error if the user is not allowed to play the job' do
- post_graphql_mutation(mutation, current_user: create(:user))
-
- expect(graphql_errors).not_to be_empty
- end
-
- it 'plays a job' do
- job_id = ::Gitlab::GlobalId.build(job, id: job.id).to_s
- post_graphql_mutation(mutation, current_user: user)
-
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['job']['id']).to eq(job_id)
- end
-
- context 'when given variables' do
- let(:variables) do
- {
- id: job.to_global_id.to_s,
- variables: [
- { key: 'MANUAL_VAR_1', value: 'test var' },
- { key: 'MANUAL_VAR_2', value: 'test var 2' }
- ]
- }
- end
-
- it 'provides those variables to the job', :aggregated_errors do
- expect_next_instance_of(Ci::PlayBuildService) do |instance|
- expect(instance).to receive(:execute).with(an_instance_of(Ci::Build), variables[:variables]).and_call_original
- end
-
- post_graphql_mutation(mutation, current_user: user)
-
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['job']['manualVariables']['nodes'].pluck('key')).to contain_exactly(
- 'MANUAL_VAR_1', 'MANUAL_VAR_2'
- )
- end
- end
-end
diff --git a/spec/requests/api/graphql/mutations/ci/job_retry_spec.rb b/spec/requests/api/graphql/mutations/ci/job_retry_spec.rb
deleted file mode 100644
index e49ee6f3163..00000000000
--- a/spec/requests/api/graphql/mutations/ci/job_retry_spec.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'JobRetry', feature_category: :continuous_integration do
- include GraphqlHelpers
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
- let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
-
- let(:job) { create(:ci_build, :success, pipeline: pipeline, name: 'build') }
-
- let(:mutation) do
- variables = {
- id: job.to_global_id.to_s
- }
- graphql_mutation(:job_retry, variables,
- <<-QL
- errors
- job {
- id
- }
- QL
- )
- end
-
- let(:mutation_response) { graphql_mutation_response(:job_retry) }
-
- before_all do
- project.add_maintainer(user)
- end
-
- it 'returns an error if the user is not allowed to retry the job' do
- post_graphql_mutation(mutation, current_user: create(:user))
-
- expect(graphql_errors).not_to be_empty
- end
-
- it 'retries a job' do
- post_graphql_mutation(mutation, current_user: user)
-
- expect(response).to have_gitlab_http_status(:success)
- new_job_id = GitlabSchema.object_from_id(mutation_response['job']['id']).sync.id
-
- new_job = ::Ci::Build.find(new_job_id)
- expect(new_job).not_to be_retried
- end
-
- context 'when given CI variables' do
- let(:job) { create(:ci_build, :success, :actionable, pipeline: pipeline, name: 'build') }
-
- let(:mutation) do
- variables = {
- id: job.to_global_id.to_s,
- variables: { key: 'MANUAL_VAR', value: 'test manual var' }
- }
-
- graphql_mutation(:job_retry, variables,
- <<-QL
- errors
- job {
- id
- }
- QL
- )
- end
-
- it 'applies them to a retried manual job' do
- post_graphql_mutation(mutation, current_user: user)
-
- expect(response).to have_gitlab_http_status(:success)
-
- new_job_id = GitlabSchema.object_from_id(mutation_response['job']['id']).sync.id
- new_job = ::Ci::Build.find(new_job_id)
- expect(new_job.job_variables.count).to be(1)
- expect(new_job.job_variables.first.key).to eq('MANUAL_VAR')
- expect(new_job.job_variables.first.value).to eq('test manual var')
- end
- end
-
- context 'when the job is not retryable' do
- let(:job) { create(:ci_build, :retried, pipeline: pipeline) }
-
- it 'returns an error' do
- post_graphql_mutation(mutation, current_user: user)
-
- expect(mutation_response['job']).to be(nil)
- expect(mutation_response['errors']).to match_array(['Job cannot be retried'])
- end
- end
-end
diff --git a/spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb b/spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb
deleted file mode 100644
index 6868b0ea279..00000000000
--- a/spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'JobUnschedule', feature_category: :continuous_integration do
- include GraphqlHelpers
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
- let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
- let_it_be(:job) { create(:ci_build, :scheduled, pipeline: pipeline, name: 'build') }
-
- let(:mutation) do
- variables = {
- id: job.to_global_id.to_s
- }
- graphql_mutation(:job_unschedule, variables,
- <<-QL
- errors
- job {
- id
- }
- QL
- )
- end
-
- let(:mutation_response) { graphql_mutation_response(:job_unschedule) }
-
- it 'returns an error if the user is not allowed to unschedule the job' do
- project.add_developer(user)
-
- post_graphql_mutation(mutation, current_user: user)
-
- expect(graphql_errors).not_to be_empty
- expect(job.reload.status).to eq('scheduled')
- end
-
- it 'unschedules a job' do
- project.add_maintainer(user)
-
- job_id = ::Gitlab::GlobalId.build(job, id: job.id).to_s
- post_graphql_mutation(mutation, current_user: user)
-
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['job']['id']).to eq(job_id)
- expect(job.reload.status).to eq('manual')
- end
-end
diff --git a/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
index 99e55c44773..0951d165d46 100644
--- a/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
@@ -101,21 +101,6 @@ RSpec.describe 'ProjectCiCdSettingsUpdate', feature_category: :continuous_integr
expect(response).to have_gitlab_http_status(:success)
expect(project.ci_inbound_job_token_scope_enabled).to eq(true)
end
-
- context 'when ci_inbound_job_token_scope disabled' do
- before do
- stub_feature_flags(ci_inbound_job_token_scope: false)
- end
-
- it 'does not update inbound_job_token_scope_enabled' do
- post_graphql_mutation(mutation, current_user: user)
-
- project.reload
-
- expect(response).to have_gitlab_http_status(:success)
- expect(project.ci_inbound_job_token_scope_enabled).to eq(true)
- end
- end
end
it 'updates ci_opt_in_jwt' do
diff --git a/spec/requests/api/graphql/mutations/ci/runner/create_spec.rb b/spec/requests/api/graphql/mutations/ci/runner/create_spec.rb
new file mode 100644
index 00000000000..f39f6f84c99
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/runner/create_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'RunnerCreate', feature_category: :runner_fleet do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:admin) { create(:admin) }
+
+ let(:mutation_params) do
+ {
+ description: 'create description',
+ maintenance_note: 'create maintenance note',
+ maximum_timeout: 900,
+ access_level: 'REF_PROTECTED',
+ paused: true,
+ run_untagged: false,
+ tag_list: %w[tag1 tag2]
+ }
+ end
+
+ let(:mutation) do
+ variables = {
+ **mutation_params
+ }
+
+ graphql_mutation(
+ :runner_create,
+ variables,
+ <<-QL
+ runner {
+ ephemeralAuthenticationToken
+
+ runnerType
+ description
+ maintenanceNote
+ paused
+ tagList
+ accessLevel
+ locked
+ maximumTimeout
+ runUntagged
+ }
+ errors
+ QL
+ )
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:runner_create) }
+
+ context 'when user does not have permissions' do
+ let(:current_user) { user }
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['errors']).to contain_exactly "Insufficient permissions"
+ end
+ end
+
+ context 'when user has permissions', :enable_admin_mode do
+ let(:current_user) { admin }
+
+ context 'when :create_runner_workflow_for_admin feature flag is disabled' do
+ before do
+ stub_feature_flags(create_runner_workflow_for_admin: false)
+ end
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).not_to be_empty
+ expect(graphql_errors[0]['message'])
+ .to eq("`create_runner_workflow_for_admin` feature flag is disabled.")
+ end
+ end
+
+ context 'when success' do
+ it do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+
+ mutation_params.each_key do |key|
+ expect(mutation_response['runner'][key.to_s.camelize(:lower)]).to eq mutation_params[key]
+ end
+
+ expect(mutation_response['runner']['ephemeralAuthenticationToken']).to start_with 'glrt'
+
+ expect(mutation_response['errors']).to eq([])
+ end
+ end
+
+ context 'when failure' do
+ let(:mutation_params) do
+ {
+ description: "",
+ maintenanceNote: "",
+ paused: true,
+ accessLevel: "NOT_PROTECTED",
+ runUntagged: false,
+ tagList:
+ [],
+ maximumTimeout: 1
+ }
+ end
+
+ it do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+
+ expect(mutation_response['errors']).to contain_exactly(
+ "Tags list can not be empty when runner is not allowed to pick untagged jobs",
+ "Maximum timeout needs to be at least 10 minutes"
+ )
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb
index ea2ce8a13e2..19a52086f34 100644
--- a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creation of a new Custom Emoji', feature_category: :not_owned do
+RSpec.describe 'Creation of a new Custom Emoji', feature_category: :shared do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb
index ad7a043909a..2623d3d8410 100644
--- a/spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Deletion of custom emoji', feature_category: :not_owned do
+RSpec.describe 'Deletion of custom emoji', feature_category: :shared do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/mutations/design_management/update_spec.rb b/spec/requests/api/graphql/mutations/design_management/update_spec.rb
new file mode 100644
index 00000000000..9558f2538f1
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/design_management/update_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe "updating designs", feature_category: :design_management do
+ include GraphqlHelpers
+ include DesignManagementTestHelpers
+
+ let_it_be(:issue) { create(:issue) }
+ let_it_be_with_reload(:design) { create(:design, description: 'old description', issue: issue) }
+ let_it_be(:developer) { create(:user, developer_projects: [issue.project]) }
+
+ let(:user) { developer }
+ let(:description) { 'new description' }
+
+ let(:mutation) do
+ input = {
+ id: design.to_global_id.to_s,
+ description: description
+ }.compact
+
+ graphql_mutation(:design_management_update, input, <<~FIELDS)
+ errors
+ design {
+ description
+ descriptionHtml
+ }
+ FIELDS
+ end
+
+ let(:update_design) { post_graphql_mutation(mutation, current_user: user) }
+ let(:mutation_response) { graphql_mutation_response(:design_management_update) }
+
+ before do
+ enable_design_management
+ end
+
+ it 'updates design' do
+ update_design
+
+ expect(graphql_errors).not_to be_present
+ expect(mutation_response).to eq(
+ 'errors' => [],
+ 'design' => {
+ 'description' => description,
+ 'descriptionHtml' => "<p data-sourcepos=\"1:1-1:15\" dir=\"auto\">#{description}</p>"
+ }
+ )
+ end
+
+ context 'when the user is not allowed to update designs' do
+ let(:user) { create(:user) }
+
+ it 'returns an error' do
+ update_design
+
+ expect(graphql_errors).to be_present
+ end
+ end
+
+ context 'when update fails' do
+ let(:description) { 'x' * 1_000_001 }
+
+ it 'returns an error' do
+ update_design
+
+ expect(graphql_errors).not_to be_present
+ expect(mutation_response).to eq(
+ 'errors' => ["Description is too long (maximum is 1000000 characters)"],
+ 'design' => {
+ 'description' => 'old description',
+ 'descriptionHtml' => '<p data-sourcepos="1:1-1:15" dir="auto">old description</p>'
+ }
+ )
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb b/spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb
index b9c83311908..b729585a89b 100644
--- a/spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb
@@ -8,7 +8,9 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
let_it_be(:developer) { create(:user) }
let_it_be(:group) { create(:group).tap { |group| group.add_developer(developer) } }
let_it_be(:project) { create(:project, group: group) }
- let_it_be(:updatable_issues, reload: true) { create_list(:issue, 2, project: project) }
+ let_it_be(:label1) { create(:group_label, group: group) }
+ let_it_be(:label2) { create(:group_label, group: group) }
+ let_it_be(:updatable_issues, reload: true) { create_list(:issue, 2, project: project, label_ids: [label1.id]) }
let_it_be(:milestone) { create(:milestone, group: group) }
let(:parent) { project }
@@ -21,10 +23,36 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
let(:additional_arguments) do
{
assignee_ids: [current_user.to_gid.to_s],
- milestone_id: milestone.to_gid.to_s
+ milestone_id: milestone.to_gid.to_s,
+ state_event: :CLOSE,
+ add_label_ids: [label2.to_gid.to_s],
+ remove_label_ids: [label1.to_gid.to_s],
+ subscription_event: :UNSUBSCRIBE
}
end
+ before_all do
+ updatable_issues.each { |i| i.subscribe(developer, project) }
+ end
+
+ context 'when Gitlab is FOSS only' do
+ unless Gitlab.ee?
+ context 'when parent is a group' do
+ let(:parent) { group }
+
+ it 'does not allow bulk updating issues at the group level' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).to contain_exactly(
+ hash_including(
+ 'message' => match(/does not represent an instance of IssueParent/)
+ )
+ )
+ end
+ end
+ end
+ end
+
context 'when the `bulk_update_issues_mutation` feature flag is disabled' do
before do
stub_feature_flags(bulk_update_issues_mutation: false)
@@ -67,6 +95,11 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
updatable_issues.each(&:reload)
end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([]).to([current_user.id] * 2)
.and(change { updatable_issues.map(&:milestone_id) }.from([nil] * 2).to([milestone.id] * 2))
+ .and(change { updatable_issues.map(&:state) }.from(['opened'] * 2).to(['closed'] * 2))
+ .and(change { updatable_issues.flat_map(&:label_ids) }.from([label1.id] * 2).to([label2.id] * 2))
+ .and(
+ change { updatable_issues.map { |i| i.subscribed?(developer, project) } }.from([true] * 2).to([false] * 2)
+ )
expect(mutation_response).to include(
'updatedIssueCount' => updatable_issues.count
@@ -88,37 +121,6 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
end
end
- context 'when scoping to a parent group' do
- let(:parent) { group }
-
- it 'updates all issues' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- updatable_issues.each(&:reload)
- end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([]).to([current_user.id] * 2)
- .and(change { updatable_issues.map(&:milestone_id) }.from([nil] * 2).to([milestone.id] * 2))
-
- expect(mutation_response).to include(
- 'updatedIssueCount' => updatable_issues.count
- )
- end
-
- context 'when current user cannot read the specified group' do
- let(:parent) { create(:group, :private) }
-
- it 'returns a resource not found error' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(graphql_errors).to contain_exactly(
- hash_including(
- 'message' => "The resource that you are attempting to access does not exist or you don't have " \
- 'permission to perform this action'
- )
- )
- end
- end
- end
-
context 'when setting arguments to null or none' do
let(:additional_arguments) { { assignee_ids: [], milestone_id: nil } }
diff --git a/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb b/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb
index ad70129a7bc..f15b52f53a3 100644
--- a/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/members/groups/bulk_update_spec.rb
@@ -5,126 +5,14 @@ require 'spec_helper'
RSpec.describe 'GroupMemberBulkUpdate', feature_category: :subgroups do
include GraphqlHelpers
- let_it_be(:current_user) { create(:user) }
- let_it_be(:user1) { create(:user) }
- let_it_be(:user2) { create(:user) }
- let_it_be(:group) { create(:group) }
- let_it_be(:group_member1) { create(:group_member, group: group, user: user1) }
- let_it_be(:group_member2) { create(:group_member, group: group, user: user2) }
+ let_it_be(:parent_group) { create(:group) }
+ let_it_be(:parent_group_member) { create(:group_member, group: parent_group) }
+ let_it_be(:group) { create(:group, parent: parent_group) }
+ let_it_be(:source) { group }
+ let_it_be(:member_type) { :group_member }
let_it_be(:mutation_name) { :group_member_bulk_update }
+ let_it_be(:source_id_key) { 'group_id' }
+ let_it_be(:response_member_field) { 'groupMembers' }
- let(:input) do
- {
- 'group_id' => group.to_global_id.to_s,
- 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s],
- 'access_level' => 'GUEST'
- }
- end
-
- let(:extra_params) { { expires_at: 10.days.from_now } }
- let(:input_params) { input.merge(extra_params) }
- let(:mutation) { graphql_mutation(mutation_name, input_params) }
- let(:mutation_response) { graphql_mutation_response(mutation_name) }
-
- context 'when user is not logged-in' do
- it_behaves_like 'a mutation that returns a top-level access error'
- end
-
- context 'when user is not an owner' do
- before do
- group.add_maintainer(current_user)
- end
-
- it_behaves_like 'a mutation that returns a top-level access error'
- end
-
- context 'when user is an owner' do
- before do
- group.add_owner(current_user)
- end
-
- shared_examples 'updates the user access role' do
- specify do
- post_graphql_mutation(mutation, current_user: current_user)
-
- new_access_levels = mutation_response['groupMembers'].map { |member| member['accessLevel']['integerValue'] }
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['errors']).to be_empty
- expect(new_access_levels).to all(be Gitlab::Access::GUEST)
- end
- end
-
- it_behaves_like 'updates the user access role'
-
- context 'when inherited members are passed' do
- let_it_be(:subgroup) { create(:group, parent: group) }
- let_it_be(:subgroup_member) { create(:group_member, group: subgroup) }
-
- let(:input) do
- {
- 'group_id' => group.to_global_id.to_s,
- 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s, subgroup_member.user.to_global_id.to_s],
- 'access_level' => 'GUEST'
- }
- end
-
- it 'does not update the members' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- error = Mutations::Members::Groups::BulkUpdate::INVALID_MEMBERS_ERROR
- expect(json_response['errors'].first['message']).to include(error)
- end
- end
-
- context 'when members count is more than the allowed limit' do
- let(:max_members_update_limit) { 1 }
-
- before do
- stub_const('Mutations::Members::Groups::BulkUpdate::MAX_MEMBERS_UPDATE_LIMIT', max_members_update_limit)
- end
-
- it 'does not update the members' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- error = Mutations::Members::Groups::BulkUpdate::MAX_MEMBERS_UPDATE_ERROR
- expect(json_response['errors'].first['message']).to include(error)
- end
- end
-
- context 'when the update service raises access denied error' do
- before do
- allow_next_instance_of(Members::UpdateService) do |instance|
- allow(instance).to receive(:execute).and_raise(Gitlab::Access::AccessDeniedError)
- end
- end
-
- it 'does not update the members' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(mutation_response['groupMembers']).to be_nil
- expect(mutation_response['errors'])
- .to contain_exactly("Unable to update members, please check user permissions.")
- end
- end
-
- context 'when the update service returns an error message' do
- before do
- allow_next_instance_of(Members::UpdateService) do |instance|
- error_result = {
- message: 'Expires at cannot be a date in the past',
- status: :error,
- members: [group_member1]
- }
- allow(instance).to receive(:execute).and_return(error_result)
- end
- end
-
- it 'will pass through the error' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(mutation_response['groupMembers'].first['id']).to eq(group_member1.to_global_id.to_s)
- expect(mutation_response['errors']).to contain_exactly('Expires at cannot be a date in the past')
- end
- end
- end
+ it_behaves_like 'members bulk update mutation'
end
diff --git a/spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb b/spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb
new file mode 100644
index 00000000000..cbef9715cbe
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'ProjectMemberBulkUpdate', feature_category: :projects do
+ include GraphqlHelpers
+
+ let_it_be(:parent_group) { create(:group) }
+ let_it_be(:parent_group_member) { create(:group_member, group: parent_group) }
+ let_it_be(:project) { create(:project, group: parent_group) }
+ let_it_be(:source) { project }
+ let_it_be(:member_type) { :project_member }
+ let_it_be(:mutation_name) { :project_member_bulk_update }
+ let_it_be(:source_id_key) { 'project_id' }
+ let_it_be(:response_member_field) { 'projectMembers' }
+
+ it_behaves_like 'members bulk update mutation'
+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 bce57b47aab..3c7f4a030f9 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,7 +19,7 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create, feature_categ
graphql_mutation_response(:create_annotation)
end
- specify { expect(described_class).to require_graphql_authorizations(:create_metrics_dashboard_annotation) }
+ specify { expect(described_class).to require_graphql_authorizations(:admin_metrics_dashboard_annotation) }
context 'when annotation source is environment' do
let(:mutation) do
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 f505dc25dc0..c104138b725 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
@@ -17,7 +17,7 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Delete, feature_categ
graphql_mutation_response(:delete_annotation)
end
- specify { expect(described_class).to require_graphql_authorizations(:delete_metrics_dashboard_annotation) }
+ specify { expect(described_class).to require_graphql_authorizations(:admin_metrics_dashboard_annotation) }
context 'when the user has permission to delete the annotation' do
before do
diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
index a6253ba424b..2a0b5f291dc 100644
--- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
@@ -104,7 +104,8 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
end
context 'as work item' do
- let(:noteable) { create(:work_item, :issue, project: project) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:noteable) { create(:work_item, :issue, project: project) }
context 'when using internal param' do
let(:variables_extra) { { internal: true } }
@@ -130,6 +131,19 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
it_behaves_like 'a mutation that returns top-level errors',
errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
+
+ context 'when body contains quick actions' do
+ let_it_be(:noteable) { create(:work_item, :task, project: project) }
+
+ let(:variables_extra) { {} }
+
+ it_behaves_like 'work item supports labels widget updates via quick actions'
+ it_behaves_like 'work item does not support labels widget updates via quick actions'
+ it_behaves_like 'work item supports assignee widget updates via quick actions'
+ it_behaves_like 'work item does not support assignee widget updates via quick actions'
+ it_behaves_like 'work item supports start and due date widget updates via quick actions'
+ it_behaves_like 'work item does not support start and due date widget updates via quick actions'
+ end
end
end
diff --git a/spec/requests/api/graphql/mutations/projects/sync_fork_spec.rb b/spec/requests/api/graphql/mutations/projects/sync_fork_spec.rb
new file mode 100644
index 00000000000..a77c026dd06
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/projects/sync_fork_spec.rb
@@ -0,0 +1,131 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "Sync project fork", feature_category: :source_code_management do
+ include GraphqlHelpers
+ include ProjectForksHelper
+ include ExclusiveLeaseHelpers
+
+ let_it_be(:source_project) { create(:project, :repository, :public) }
+ let_it_be(:current_user) { create(:user, maintainer_projects: [source_project]) }
+ let_it_be(:project, refind: true) { fork_project(source_project, current_user, { repository: true }) }
+ let_it_be(:target_branch) { project.default_branch }
+
+ let(:mutation) do
+ params = { project_path: project.full_path, target_branch: target_branch }
+
+ graphql_mutation(:project_sync_fork, params) do
+ <<-QL.strip_heredoc
+ details {
+ ahead
+ behind
+ isSyncing
+ hasConflicts
+ }
+ errors
+ QL
+ end
+ end
+
+ before do
+ source_project.change_head('feature')
+ end
+
+ context 'when synchronize_fork feature flag is disabled' do
+ before do
+ stub_feature_flags(synchronize_fork: false)
+ end
+
+ it 'does not call the sync service' do
+ expect(::Projects::Forks::SyncWorker).not_to receive(:perform_async)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_mutation_response(:project_sync_fork)).to eq(
+ {
+ 'details' => nil,
+ 'errors' => ['Feature flag is disabled']
+ })
+ end
+ end
+
+ context 'when the user does not have permission' do
+ let_it_be(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not call the sync service' do
+ expect(::Projects::Forks::SyncWorker).not_to receive(:perform_async)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+ end
+ end
+
+ context 'when the user has permission' do
+ context 'and the sync service executes successfully', :sidekiq_inline do
+ it 'calls the sync service' do
+ expect(::Projects::Forks::SyncWorker).to receive(:perform_async).and_call_original
+
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_mutation_response(:project_sync_fork)).to eq(
+ {
+ 'details' => { 'ahead' => 30, 'behind' => 0, "hasConflicts" => false, "isSyncing" => false },
+ 'errors' => []
+ })
+ end
+ end
+
+ context 'and the sync service fails to execute' do
+ let(:target_branch) { 'markdown' }
+
+ def expect_error_response(message)
+ expect(::Projects::Forks::SyncWorker).not_to receive(:perform_async)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_mutation_response(:project_sync_fork)['errors']).to eq([message])
+ end
+
+ context 'when fork details cannot be resolved' do
+ let_it_be(:project) { source_project }
+
+ it 'returns an error' do
+ expect_error_response('This branch of this project cannot be updated from the upstream')
+ end
+ end
+
+ context 'when the previous execution resulted in a conflict' do
+ it 'returns an error' do
+ expect_next_instance_of(::Projects::Forks::Details) do |instance|
+ expect(instance).to receive(:has_conflicts?).twice.and_return(true)
+ end
+
+ expect_error_response('The synchronization cannot happen due to the merge conflict')
+ expect(graphql_mutation_response(:project_sync_fork)['details']['hasConflicts']).to eq(true)
+ end
+ end
+
+ context 'when the request is rate limited' do
+ it 'returns an error' do
+ expect(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
+
+ expect_error_response('This service has been called too many times.')
+ end
+ end
+
+ context 'when another fork sync is in progress' do
+ it 'returns an error' do
+ expect_next_instance_of(Projects::Forks::Details) do |instance|
+ lease = instance_double(Gitlab::ExclusiveLease, try_obtain: false, exists?: true)
+ expect(instance).to receive(:exclusive_lease).twice.and_return(lease)
+ end
+
+ expect_error_response('Another fork sync is already in progress')
+ expect(graphql_mutation_response(:project_sync_fork)['details']['isSyncing']).to eq(true)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/snippets/update_spec.rb b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
index fa087e6773c..3b98ee3c2e9 100644
--- a/spec/requests/api/graphql/mutations/snippets/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
@@ -193,7 +193,6 @@ RSpec.describe 'Updating a Snippet', feature_category: :source_code_management d
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:user) { current_user }
let(:property) { 'g_edit_by_snippet_ide' }
let(:namespace) { project.namespace }
@@ -203,8 +202,6 @@ RSpec.describe 'Updating a Snippet', feature_category: :source_code_management d
let(:context) do
[Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context]
end
-
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
end
end
diff --git a/spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb
index 97bf060356a..d2df3e8bda2 100644
--- a/spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe "Create a work item from a task in a work item's description", fe
}
end
- let(:mutation) { graphql_mutation(:workItemCreateFromTask, input) }
+ let(:mutation) { graphql_mutation(:workItemCreateFromTask, input, nil, ['productAnalyticsState']) }
let(:mutation_response) { graphql_mutation_response(:work_item_create_from_task) }
context 'the user is not allowed to update a work item' do
diff --git a/spec/requests/api/graphql/mutations/work_items/create_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
index 16f78b67b5c..7519389ab49 100644
--- a/spec/requests/api/graphql/mutations/work_items/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
'title' => 'new title',
'description' => 'new description',
'confidential' => true,
- 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_global_id.to_s
+ 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_gid.to_s
}
end
@@ -43,14 +43,14 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
expect(created_work_item.work_item_type.base_type).to eq('task')
expect(mutation_response['workItem']).to include(
input.except('workItemTypeId').merge(
- 'id' => created_work_item.to_global_id.to_s,
+ 'id' => created_work_item.to_gid.to_s,
'workItemType' => hash_including('name' => 'Task')
)
)
end
context 'when input is invalid' do
- let(:input) { { 'title' => '', 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_global_id.to_s } }
+ let(:input) { { 'title' => '', 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_gid.to_s } }
it 'does not create and returns validation errors' do
expect do
@@ -98,8 +98,8 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
let(:input) do
{
title: 'item1',
- workItemTypeId: WorkItems::Type.default_by_type(:task).to_global_id.to_s,
- hierarchyWidget: { 'parentId' => parent.to_global_id.to_s }
+ workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s,
+ hierarchyWidget: { 'parentId' => parent.to_gid.to_s }
}
end
@@ -110,7 +110,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
expect(widgets_response).to include(
{
'children' => { 'edges' => [] },
- 'parent' => { 'id' => parent.to_global_id.to_s },
+ 'parent' => { 'id' => parent.to_gid.to_s },
'type' => 'HIERARCHY'
}
)
@@ -137,6 +137,40 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
expect(graphql_errors.first['message']).to include('No object found for `parentId')
end
end
+
+ context 'when adjacent is already in place' do
+ let_it_be(:adjacent) { create(:work_item, :task, project: project) }
+
+ let(:work_item) { WorkItem.last }
+
+ let(:input) do
+ {
+ title: 'item1',
+ workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s,
+ hierarchyWidget: { 'parentId' => parent.to_gid.to_s }
+ }
+ end
+
+ before(:all) do
+ create(:parent_link, work_item_parent: parent, work_item: adjacent, relative_position: 0)
+ end
+
+ it 'creates work item and sets the relative position to be AFTER adjacent' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change(WorkItem, :count).by(1)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(widgets_response).to include(
+ {
+ 'children' => { 'edges' => [] },
+ 'parent' => { 'id' => parent.to_gid.to_s },
+ 'type' => 'HIERARCHY'
+ }
+ )
+ expect(work_item.parent_link.relative_position).to be > adjacent.parent_link.relative_position
+ end
+ end
end
context 'when unsupported widget input is sent' do
@@ -144,7 +178,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
{
'title' => 'new title',
'description' => 'new description',
- 'workItemTypeId' => WorkItems::Type.default_by_type(:test_case).to_global_id.to_s,
+ 'workItemTypeId' => WorkItems::Type.default_by_type(:test_case).to_gid.to_s,
'hierarchyWidget' => {}
}
end
@@ -181,8 +215,8 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
let(:input) do
{
title: 'some WI',
- workItemTypeId: WorkItems::Type.default_by_type(:task).to_global_id.to_s,
- milestoneWidget: { 'milestoneId' => milestone.to_global_id.to_s }
+ workItemTypeId: WorkItems::Type.default_by_type(:task).to_gid.to_s,
+ milestoneWidget: { 'milestoneId' => milestone.to_gid.to_s }
}
end
@@ -196,7 +230,7 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do
expect(widgets_response).to include(
{
'type' => 'MILESTONE',
- 'milestone' => { 'id' => milestone.to_global_id.to_s }
+ 'milestone' => { 'id' => milestone.to_gid.to_s }
}
)
end
diff --git a/spec/requests/api/graphql/mutations/work_items/export_spec.rb b/spec/requests/api/graphql/mutations/work_items/export_spec.rb
new file mode 100644
index 00000000000..3cadaab5201
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/work_items/export_spec.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Export work items', feature_category: :team_planning do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:reporter) { create(:user).tap { |user| project.add_reporter(user) } }
+ let_it_be(:guest) { create(:user).tap { |user| project.add_guest(user) } }
+ let_it_be(:work_item) { create(:work_item, project: project) }
+
+ let(:input) { { 'projectPath' => project.full_path } }
+ let(:mutation) { graphql_mutation(:workItemExport, input) }
+ let(:mutation_response) { graphql_mutation_response(:work_item_export) }
+
+ context 'when user is not allowed to export work items' do
+ let(:current_user) { guest }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when import_export_work_items_csv feature flag is disabled' do
+ let(:current_user) { reporter }
+
+ before do
+ stub_feature_flags(import_export_work_items_csv: false)
+ end
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['`import_export_work_items_csv` feature flag is disabled.']
+ end
+
+ context 'when user has permissions to export work items' do
+ let(:current_user) { reporter }
+ let(:input) do
+ super().merge(
+ 'selectedFields' => %w[TITLE AUTHOR TYPE AUTHOR_USERNAME CREATED_AT],
+ 'authorUsername' => 'admin',
+ 'iids' => [work_item.iid.to_s],
+ 'state' => 'opened',
+ 'types' => 'TASK',
+ 'search' => 'any',
+ 'in' => 'TITLE'
+ )
+ end
+
+ it 'schedules export job with given arguments', :aggregate_failures do
+ expected_arguments = {
+ selected_fields: ['title', 'author', 'type', 'author username', 'created_at'],
+ author_username: 'admin',
+ iids: [work_item.iid.to_s],
+ state: 'opened',
+ issue_types: ['task'],
+ search: 'any',
+ in: ['title']
+ }
+
+ expect(IssuableExportCsvWorker)
+ .to receive(:perform_async).with(:work_item, current_user.id, project.id, expected_arguments)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['errors']).to be_empty
+ 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 ddd294e8f82..76dc60be799 100644
--- a/spec/requests/api/graphql/mutations/work_items/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/update_spec.rb
@@ -7,10 +7,11 @@ RSpec.describe 'Update a work item', feature_category: :team_planning do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:author) { create(:user).tap { |user| project.add_reporter(user) } }
let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } }
let_it_be(:reporter) { create(:user).tap { |user| project.add_reporter(user) } }
let_it_be(:guest) { create(:user).tap { |user| project.add_guest(user) } }
- let_it_be(:work_item, refind: true) { create(:work_item, project: project) }
+ let_it_be(:work_item, refind: true) { create(:work_item, project: project, author: author) }
let(:work_item_event) { 'CLOSE' }
let(:input) { { 'stateEvent' => work_item_event, 'title' => 'updated title' } }
@@ -843,6 +844,140 @@ RSpec.describe 'Update a work item', feature_category: :team_planning do
end
end
+ context 'when updating notifications subscription' do
+ let_it_be(:current_user) { reporter }
+ let(:input) { { 'notificationsWidget' => { 'subscribed' => desired_state } } }
+
+ let(:fields) do
+ <<~FIELDS
+ workItem {
+ widgets {
+ type
+ ... on WorkItemWidgetNotifications {
+ subscribed
+ }
+ }
+ }
+ errors
+ FIELDS
+ end
+
+ subject(:update_work_item) { post_graphql_mutation(mutation, current_user: current_user) }
+
+ shared_examples 'subscription updated successfully' do
+ let_it_be(:subscription) do
+ create(
+ :subscription, project: project,
+ user: current_user,
+ subscribable: work_item,
+ subscribed: !desired_state
+ )
+ end
+
+ it "updates existing work item's subscription state" do
+ expect do
+ update_work_item
+ subscription.reload
+ end.to change(subscription, :subscribed).to(desired_state)
+ .and(change { work_item.reload.subscribed?(reporter, project) }.to(desired_state))
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['workItem']['widgets']).to include(
+ {
+ 'subscribed' => desired_state,
+ 'type' => 'NOTIFICATIONS'
+ }
+ )
+ end
+ end
+
+ shared_examples 'subscription update ignored' do
+ context 'when user is subscribed with a subscription record' do
+ let_it_be(:subscription) do
+ create(
+ :subscription, project: project,
+ user: current_user,
+ subscribable: work_item,
+ subscribed: !desired_state
+ )
+ end
+
+ it 'ignores the update request' do
+ expect do
+ update_work_item
+ subscription.reload
+ end.to not_change(subscription, :subscribed)
+ .and(not_change { work_item.subscribed?(current_user, project) })
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+
+ context 'when user is subscribed by being a participant' do
+ let_it_be(:current_user) { author }
+
+ it 'ignores the update request' do
+ expect do
+ update_work_item
+ end.to not_change(Subscription, :count)
+ .and(not_change { work_item.subscribed?(current_user, project) })
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+ end
+
+ context 'when work item update fails' do
+ let_it_be(:desired_state) { false }
+ let(:input) { { 'title' => nil, 'notificationsWidget' => { 'subscribed' => desired_state } } }
+
+ it_behaves_like 'subscription update ignored'
+ end
+
+ context 'when user cannot update work item' do
+ let_it_be(:desired_state) { false }
+
+ before do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?)
+ .with(current_user, :update_subscription, work_item).and_return(false)
+ end
+
+ it_behaves_like 'subscription update ignored'
+ end
+
+ context 'when user can update work item' do
+ context 'when subscribing to notifications' do
+ let_it_be(:desired_state) { true }
+
+ it_behaves_like 'subscription updated successfully'
+ end
+
+ context 'when unsubscribing from notifications' do
+ let_it_be(:desired_state) { false }
+
+ it_behaves_like 'subscription updated successfully'
+
+ context 'when user is subscribed by being a participant' do
+ let_it_be(:current_user) { author }
+
+ it 'creates a subscription with desired state' do
+ expect { update_work_item }.to change(Subscription, :count).by(1)
+ .and(change { work_item.reload.subscribed?(author, project) }.to(desired_state))
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['workItem']['widgets']).to include(
+ {
+ 'subscribed' => desired_state,
+ 'type' => 'NOTIFICATIONS'
+ }
+ )
+ end
+ end
+ end
+ end
+ end
+
context 'when unsupported widget input is sent' do
let_it_be(:test_case) { create(:work_item_type, :default, :test_case) }
let_it_be(:work_item) { create(:work_item, work_item_type: test_case, project: project) }
diff --git a/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb
index 999c685ac6a..717de983871 100644
--- a/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe 'Update a work item task', feature_category: :team_planning do
let(:task_params) { { 'title' => 'UPDATED' } }
let(:task_input) { { 'id' => task.to_global_id.to_s }.merge(task_params) }
let(:input) { { 'id' => work_item.to_global_id.to_s, 'taskData' => task_input } }
- let(:mutation) { graphql_mutation(:workItemUpdateTask, input) }
+ let(:mutation) { graphql_mutation(:workItemUpdateTask, input, nil, ['productAnalyticsState']) }
let(:mutation_response) { graphql_mutation_response(:work_item_update_task) }
context 'the user is not allowed to read a work item' do
diff --git a/spec/requests/api/graphql/namespace/projects_spec.rb b/spec/requests/api/graphql/namespace/projects_spec.rb
index 4e12da3e3ab..83edacaf831 100644
--- a/spec/requests/api/graphql/namespace/projects_spec.rb
+++ b/spec/requests/api/graphql/namespace/projects_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'getting projects', feature_category: :projects do
projects(includeSubgroups: #{include_subgroups}) {
edges {
node {
- #{all_graphql_fields_for('Project', max_depth: 1)}
+ #{all_graphql_fields_for('Project', max_depth: 1, excluded: ['productAnalyticsState'])}
}
}
}
diff --git a/spec/requests/api/graphql/packages/package_spec.rb b/spec/requests/api/graphql/packages/package_spec.rb
index 82fcc5254ad..7610a4aaac1 100644
--- a/spec/requests/api/graphql/packages/package_spec.rb
+++ b/spec/requests/api/graphql/packages/package_spec.rb
@@ -270,6 +270,31 @@ RSpec.describe 'package details', feature_category: :package_registry do
it 'returns composer_config_repository_url correctly' do
expect(graphql_data_at(:package, :composer_config_repository_url)).to eq("localhost/#{group.id}")
end
+
+ context 'with access to package registry for everyone' do
+ before do
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ subject
+ end
+
+ it 'returns pypi_url correctly' do
+ expect(graphql_data_at(:package, :pypi_url)).to eq("http://__token__:<your_personal_token>@localhost/api/v4/projects/#{project.id}/packages/pypi/simple")
+ end
+ end
+
+ context 'when project is public' do
+ let_it_be(:public_project) { create(:project, :public, group: group) }
+ let_it_be(:composer_package) { create(:composer_package, project: public_project) }
+ let(:package_global_id) { global_id_of(composer_package) }
+
+ before do
+ subject
+ end
+
+ it 'returns pypi_url correctly' do
+ expect(graphql_data_at(:package, :pypi_url)).to eq("http://localhost/api/v4/projects/#{public_project.id}/packages/pypi/simple")
+ end
+ end
end
context 'web_path' do
diff --git a/spec/requests/api/graphql/project/base_service_spec.rb b/spec/requests/api/graphql/project/base_service_spec.rb
index 7b1b95eaf58..b27cddea07b 100644
--- a/spec/requests/api/graphql/project/base_service_spec.rb
+++ b/spec/requests/api/graphql/project/base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'query Jira service', feature_category: :authentication_and_authorization do
+RSpec.describe 'query Jira service', feature_category: :system_access do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/container_repositories_spec.rb b/spec/requests/api/graphql/project/container_repositories_spec.rb
index 7ccf8a6f5bf..9a40a972256 100644
--- a/spec/requests/api/graphql/project/container_repositories_spec.rb
+++ b/spec/requests/api/graphql/project/container_repositories_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'getting container repositories in a project', feature_category:
let_it_be(:container_repositories) { [container_repository, container_repositories_delete_scheduled, container_repositories_delete_failed].flatten }
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
- let(:excluded_fields) { %w[pipeline jobs] }
+ let(:excluded_fields) { %w[pipeline jobs productAnalyticsState] }
let(:container_repositories_fields) do
<<~GQL
edges {
@@ -155,7 +155,7 @@ RSpec.describe 'getting container repositories in a project', feature_category:
it_behaves_like 'handling graphql network errors with the container registry'
it_behaves_like 'not hitting graphql network errors with the container registry' do
- let(:excluded_fields) { %w[pipeline jobs tags tagsCount] }
+ let(:excluded_fields) { %w[pipeline jobs tags tagsCount productAnalyticsState] }
end
it 'returns the total count of container repositories' do
diff --git a/spec/requests/api/graphql/project/flow_metrics_spec.rb b/spec/requests/api/graphql/project/flow_metrics_spec.rb
new file mode 100644
index 00000000000..3b5758b3a2e
--- /dev/null
+++ b/spec/requests/api/graphql/project/flow_metrics_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting project flow metrics', feature_category: :value_stream_management do
+ include GraphqlHelpers
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project1) { create(:project, :repository, group: group) }
+ # This is done so we can use the same count expectations in the shared examples and
+ # reuse the shared example for the group-level test.
+ let_it_be(:project2) { project1 }
+ let_it_be(:production_environment1) { create(:environment, :production, project: project1) }
+ let_it_be(:production_environment2) { production_environment1 }
+ let_it_be(:current_user) { create(:user, maintainer_projects: [project1]) }
+
+ let(:full_path) { project1.full_path }
+ let(:context) { :project }
+
+ it_behaves_like 'value stream analytics flow metrics issueCount examples'
+
+ it_behaves_like 'value stream analytics flow metrics deploymentCount examples'
+end
diff --git a/spec/requests/api/graphql/project/fork_details_spec.rb b/spec/requests/api/graphql/project/fork_details_spec.rb
index efd48b00833..0baf29b970e 100644
--- a/spec/requests/api/graphql/project/fork_details_spec.rb
+++ b/spec/requests/api/graphql/project/fork_details_spec.rb
@@ -10,12 +10,13 @@ RSpec.describe 'getting project fork details', feature_category: :source_code_ma
let_it_be(:current_user) { create(:user, maintainer_projects: [project]) }
let_it_be(:forked_project) { fork_project(project, current_user, repository: true) }
+ let(:ref) { 'feature' }
let(:queried_project) { forked_project }
let(:query) do
graphql_query_for(:project,
{ full_path: queried_project.full_path }, <<~QUERY
- forkDetails(ref: "feature"){
+ forkDetails(ref: "#{ref}"){
ahead
behind
}
@@ -41,6 +42,38 @@ RSpec.describe 'getting project fork details', feature_category: :source_code_ma
end
end
+ context 'when project source is not visible' do
+ it 'does not return fork details' do
+ project.team.truncate
+
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['forkDetails']).to be_nil
+ end
+ end
+
+ context 'when the specified ref does not exist' do
+ let(:ref) { 'non-existent-branch' }
+
+ it 'does not return fork details' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['forkDetails']).to be_nil
+ end
+ end
+
+ context 'when fork_divergence_counts feature flag is disabled' do
+ before do
+ stub_feature_flags(fork_divergence_counts: false)
+ end
+
+ it 'does not return fork details' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['forkDetails']).to be_nil
+ end
+ end
+
context 'when a user cannot read the code' do
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb
index 8407faa967e..156886ca211 100644
--- a/spec/requests/api/graphql/project/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/project/merge_requests_spec.rb
@@ -588,8 +588,9 @@ RSpec.describe 'getting merge request listings nested in a project', feature_cat
end
let(:query) do
+ # Adding a no-op `not` filter to mimic the same query as the frontend does
graphql_query_for(:project, { full_path: project.full_path }, <<~QUERY)
- mergeRequests(mergedAfter: "2020-01-01", mergedBefore: "2020-01-05", first: 0) {
+ mergeRequests(mergedAfter: "2020-01-01", mergedBefore: "2020-01-05", first: 0, not: { labels: null }) {
totalTimeToMerge
count
}
diff --git a/spec/requests/api/graphql/project/work_items_spec.rb b/spec/requests/api/graphql/project/work_items_spec.rb
index f49165a88ea..d5dd12de63e 100644
--- a/spec/requests/api/graphql/project/work_items_spec.rb
+++ b/spec/requests/api/graphql/project/work_items_spec.rb
@@ -313,6 +313,34 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team
end
end
+ context 'when fetching work item notifications widget' do
+ let(:fields) do
+ <<~GRAPHQL
+ nodes {
+ widgets {
+ type
+ ... on WorkItemWidgetNotifications {
+ subscribed
+ }
+ }
+ }
+ GRAPHQL
+ end
+
+ it 'executes limited number of N+1 queries', :use_sql_query_cache do
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ post_graphql(query, current_user: current_user)
+ end
+
+ create_list(:work_item, 3, project: project)
+
+ # Performs 1 extra query per item to fetch subscriptions
+ expect { post_graphql(query, current_user: current_user) }
+ .not_to exceed_all_query_limit(control).with_threshold(3)
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
def item_ids
graphql_dig_at(items_data, :node, :id)
end
diff --git a/spec/requests/api/graphql/query_spec.rb b/spec/requests/api/graphql/query_spec.rb
index 2b9d66ec744..d93077b1c70 100644
--- a/spec/requests/api/graphql/query_spec.rb
+++ b/spec/requests/api/graphql/query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query', feature_category: :not_owned do
+RSpec.describe 'Query', feature_category: :shared do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/user/user_achievements_query_spec.rb b/spec/requests/api/graphql/user/user_achievements_query_spec.rb
new file mode 100644
index 00000000000..bf9b2b429cc
--- /dev/null
+++ b/spec/requests/api/graphql/user/user_achievements_query_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'UserAchievements', feature_category: :user_profile do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group, :private) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+ let_it_be(:user_achievements) { create_list(:user_achievement, 2, achievement: achievement, user: user) }
+ let_it_be(:fields) do
+ <<~HEREDOC
+ userAchievements {
+ nodes {
+ id
+ achievement {
+ id
+ }
+ user {
+ id
+ }
+ awardedByUser {
+ id
+ }
+ revokedByUser {
+ id
+ }
+ }
+ }
+ HEREDOC
+ end
+
+ let_it_be(:query) do
+ graphql_query_for('user', { id: user.to_global_id.to_s }, fields)
+ end
+
+ let(:current_user) { user }
+
+ before_all do
+ group.add_guest(user)
+ end
+
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns all user_achievements' do
+ expect(graphql_data_at(:user, :userAchievements, :nodes)).to contain_exactly(
+ a_graphql_entity_for(user_achievements[0]),
+ a_graphql_entity_for(user_achievements[1])
+ )
+ end
+
+ it 'can lookahead to eliminate N+1 queries', :use_clean_rails_memory_store_caching do
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ post_graphql(query, current_user: user)
+ end.count
+
+ achievement2 = create(:achievement, namespace: group)
+ create_list(:user_achievement, 2, achievement: achievement2, user: user)
+
+ expect { post_graphql(query, current_user: user) }.not_to exceed_all_query_limit(control_count)
+ end
+
+ context 'when the achievements feature flag is disabled for a namespace' do
+ let_it_be(:group2) { create(:group) }
+ let_it_be(:achievement2) { create(:achievement, namespace: group2) }
+ let_it_be(:user_achievement2) { create(:user_achievement, achievement: achievement2, user: user) }
+
+ before do
+ stub_feature_flags(achievements: false)
+ stub_feature_flags(achievements: group2)
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'does not return user_achievements for that namespace' do
+ expect(graphql_data_at(:user, :userAchievements, :nodes)).to contain_exactly(
+ a_graphql_entity_for(user_achievement2)
+ )
+ end
+ end
+
+ context 'when current user is not a member of the private group' do
+ let(:current_user) { create(:user) }
+
+ specify { expect(graphql_data_at(:user, :userAchievements, :nodes)).to be_empty }
+ end
+end
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
index 0fad4f4ff3a..24c72a8bb00 100644
--- a/spec/requests/api/graphql/work_item_spec.rb
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -373,6 +373,32 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
)
end
end
+
+ describe 'notifications widget' do
+ let(:work_item_fields) do
+ <<~GRAPHQL
+ id
+ widgets {
+ type
+ ... on WorkItemWidgetNotifications {
+ subscribed
+ }
+ }
+ GRAPHQL
+ end
+
+ it 'returns widget information' do
+ expect(work_item_data).to include(
+ 'id' => work_item.to_gid.to_s,
+ 'widgets' => include(
+ hash_including(
+ 'type' => 'NOTIFICATIONS',
+ 'subscribed' => work_item.subscribed?(current_user, project)
+ )
+ )
+ )
+ end
+ end
end
context 'when an Issue Global ID is provided' do
diff --git a/spec/requests/api/graphql_spec.rb b/spec/requests/api/graphql_spec.rb
index d7724371cce..8a3c5261eb6 100644
--- a/spec/requests/api/graphql_spec.rb
+++ b/spec/requests/api/graphql_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'GraphQL', feature_category: :not_owned do
+RSpec.describe 'GraphQL', feature_category: :shared do
include GraphqlHelpers
include AfterNextHelpers
diff --git a/spec/requests/api/group_milestones_spec.rb b/spec/requests/api/group_milestones_spec.rb
index 91f64d02d43..2f05b0fcf21 100644
--- a/spec/requests/api/group_milestones_spec.rb
+++ b/spec/requests/api/group_milestones_spec.rb
@@ -4,35 +4,41 @@ require 'spec_helper'
RSpec.describe API::GroupMilestones, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
- let_it_be(:group) { create(:group, :private) }
+ let_it_be_with_refind(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:group_member) { create(:group_member, group: group, user: user) }
- let_it_be(:closed_milestone) { create(:closed_milestone, group: group, title: 'version1', description: 'closed milestone') }
- let_it_be(:milestone) { create(:milestone, group: group, title: 'version2', description: 'open milestone') }
+ let_it_be(:closed_milestone) do
+ create(:closed_milestone, group: group, title: 'version1', description: 'closed milestone')
+ end
+
+ let_it_be_with_reload(:milestone) do
+ create(:milestone, group: group, title: 'version2', description: 'open milestone', updated_at: 4.days.ago)
+ end
let(:route) { "/groups/#{group.id}/milestones" }
+ shared_examples 'listing all milestones' do
+ it 'returns correct list of milestones' do
+ get api(route, user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.size).to eq(milestones.size)
+ expect(json_response.map { |entry| entry["id"] }).to eq(milestones.map(&:id))
+ end
+ end
+
it_behaves_like 'group and project milestones', "/groups/:id/milestones"
describe 'GET /groups/:id/milestones' do
- context 'when include_parent_milestones is true' do
- let_it_be(:ancestor_group) { create(:group, :private) }
- let_it_be(:ancestor_group_milestone) { create(:milestone, group: ancestor_group) }
- let_it_be(:params) { { include_parent_milestones: true } }
-
- before_all do
- group.update!(parent: ancestor_group)
- end
+ let_it_be(:ancestor_group) { create(:group, :private) }
+ let_it_be(:ancestor_group_milestone) { create(:milestone, group: ancestor_group, updated_at: 2.days.ago) }
- shared_examples 'listing all milestones' do
- it 'returns correct list of milestones' do
- get api(route, user), params: params
+ before_all do
+ group.update!(parent: ancestor_group)
+ end
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.size).to eq(milestones.size)
- expect(json_response.map { |entry| entry["id"] }).to eq(milestones.map(&:id))
- end
- end
+ context 'when include_parent_milestones is true' do
+ let(:params) { { include_parent_milestones: true } }
context 'when user has access to ancestor groups' do
let(:milestones) { [ancestor_group_milestone, milestone, closed_milestone] }
@@ -45,10 +51,26 @@ RSpec.describe API::GroupMilestones, feature_category: :team_planning do
it_behaves_like 'listing all milestones'
context 'when iids param is present' do
- let_it_be(:params) { { include_parent_milestones: true, iids: [milestone.iid] } }
+ let(:params) { { include_parent_milestones: true, iids: [milestone.iid] } }
it_behaves_like 'listing all milestones'
end
+
+ context 'when updated_before param is present' do
+ let(:params) { { updated_before: 1.day.ago.iso8601, include_parent_milestones: true } }
+
+ it_behaves_like 'listing all milestones' do
+ let(:milestones) { [ancestor_group_milestone, milestone] }
+ end
+ end
+
+ context 'when updated_after param is present' do
+ let(:params) { { updated_after: 1.day.ago.iso8601, include_parent_milestones: true } }
+
+ it_behaves_like 'listing all milestones' do
+ let(:milestones) { [closed_milestone] }
+ end
+ end
end
context 'when user has no access to ancestor groups' do
@@ -63,6 +85,22 @@ RSpec.describe API::GroupMilestones, feature_category: :team_planning do
end
end
end
+
+ context 'when updated_before param is present' do
+ let(:params) { { updated_before: 1.day.ago.iso8601 } }
+
+ it_behaves_like 'listing all milestones' do
+ let(:milestones) { [milestone] }
+ end
+ end
+
+ context 'when updated_after param is present' do
+ let(:params) { { updated_after: 1.day.ago.iso8601 } }
+
+ it_behaves_like 'listing all milestones' do
+ let(:milestones) { [closed_milestone] }
+ end
+ end
end
describe 'GET /groups/:id/milestones/:milestone_id/issues' do
diff --git a/spec/requests/api/group_variables_spec.rb b/spec/requests/api/group_variables_spec.rb
index e3d538d72ba..ff20e7ea9dd 100644
--- a/spec/requests/api/group_variables_spec.rb
+++ b/spec/requests/api/group_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupVariables, feature_category: :pipeline_authoring do
+RSpec.describe API::GroupVariables, feature_category: :pipeline_composition do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:variable) { create(:ci_group_variable, group: group) }
diff --git a/spec/requests/api/helm_packages_spec.rb b/spec/requests/api/helm_packages_spec.rb
index 584f6e3c7d4..d6afd6f86ff 100644
--- a/spec/requests/api/helm_packages_spec.rb
+++ b/spec/requests/api/helm_packages_spec.rb
@@ -17,7 +17,15 @@ RSpec.describe API::HelmPackages, feature_category: :package_registry do
let_it_be(:package_file2_2) { create(:helm_package_file, package: package2, file_sha256: 'file2', file_name: 'filename2.tgz', channel: 'test', description: 'hello from test channel') }
let_it_be(:other_package) { create(:npm_package, project: project) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_helm_user' } }
+ let(:snowplow_gitlab_standard_context) { snowplow_context }
+
+ def snowplow_context(user_role: :developer)
+ if user_role == :anonymous
+ { project: project, namespace: project.namespace, property: 'i_package_helm_user' }
+ else
+ { project: project, namespace: project.namespace, property: 'i_package_helm_user', user: user }
+ end
+ end
describe 'GET /api/v4/projects/:id/packages/helm/:channel/index.yaml' do
let(:project_id) { project.id }
@@ -65,6 +73,7 @@ RSpec.describe API::HelmPackages, feature_category: :package_registry do
with_them do
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, personal_access_token.token) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
before do
project.update!(visibility: visibility.to_s)
@@ -75,6 +84,8 @@ RSpec.describe API::HelmPackages, feature_category: :package_registry do
end
context 'with access to package registry for everyone' do
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: :anonymous) }
+
before do
project.update!(visibility: Gitlab::VisibilityLevel::PRIVATE)
project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
@@ -116,6 +127,7 @@ RSpec.describe API::HelmPackages, feature_category: :package_registry do
with_them do
let(:user_headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, personal_access_token.token) }
let(:headers) { user_headers.merge(workhorse_headers) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
@@ -178,6 +190,7 @@ RSpec.describe API::HelmPackages, feature_category: :package_registry do
with_them do
let(:user_headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, personal_access_token.token) }
let(:headers) { user_headers.merge(workhorse_headers) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 38275ce0057..0be9df41e8f 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require 'raven/transports/dummy'
require_relative '../../../config/initializers/sentry'
-RSpec.describe API::Helpers, :enable_admin_mode, feature_category: :authentication_and_authorization do
+RSpec.describe API::Helpers, :enable_admin_mode, feature_category: :system_access do
include API::APIGuard::HelperMethods
include described_class
include TermsHelper
diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb
index ca32271f573..dff41c4c477 100644
--- a/spec/requests/api/internal/base_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::Base, feature_category: :authentication_and_authorization do
+RSpec.describe API::Internal::Base, feature_category: :system_access do
include GitlabShellHelpers
include APIInternalBaseHelpers
@@ -514,7 +514,7 @@ RSpec.describe API::Internal::Base, feature_category: :authentication_and_author
expect(json_response["gl_repository"]).to eq("wiki-#{project.id}")
expect(json_response["gl_key_type"]).to eq("key")
expect(json_response["gl_key_id"]).to eq(key.id)
- expect(user.reload.last_activity_on).to be_nil
+ expect(user.reload.last_activity_on).to eql(Date.today)
end
it_behaves_like 'sets hook env' do
@@ -553,7 +553,7 @@ RSpec.describe API::Internal::Base, feature_category: :authentication_and_author
expect(json_response["status"]).to be_truthy
expect(json_response["gl_project_path"]).to eq(personal_snippet.repository.full_path)
expect(json_response["gl_repository"]).to eq("snippet-#{personal_snippet.id}")
- expect(user.reload.last_activity_on).to be_nil
+ expect(user.reload.last_activity_on).to eql(Date.today)
end
it_behaves_like 'sets hook env' do
@@ -585,7 +585,7 @@ RSpec.describe API::Internal::Base, feature_category: :authentication_and_author
expect(json_response["status"]).to be_truthy
expect(json_response["gl_project_path"]).to eq(project_snippet.repository.full_path)
expect(json_response["gl_repository"]).to eq("snippet-#{project_snippet.id}")
- expect(user.reload.last_activity_on).to be_nil
+ expect(user.reload.last_activity_on).to eql(Date.today)
end
it_behaves_like 'sets hook env' do
@@ -703,7 +703,7 @@ RSpec.describe API::Internal::Base, feature_category: :authentication_and_author
expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
- expect(user.reload.last_activity_on).to be_nil
+ expect(user.reload.last_activity_on).to eql(Date.today)
end
it_behaves_like 'rate limited request' do
@@ -862,7 +862,7 @@ RSpec.describe API::Internal::Base, feature_category: :authentication_and_author
expect(json_response['status']).to be_truthy
expect(json_response['payload']).to eql(payload)
expect(json_response['gl_console_messages']).to eql(console_messages)
- expect(user.reload.last_activity_on).to be_nil
+ expect(user.reload.last_activity_on).to eql(Date.today)
end
end
end
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index be76e55269a..547b9071f94 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -306,4 +306,151 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
end
end
end
+
+ describe 'POST /internal/kubernetes/authorize_proxy_user', :clean_gitlab_redis_sessions do
+ include SessionHelpers
+
+ def send_request(headers: {}, params: {})
+ post api('/internal/kubernetes/authorize_proxy_user'), params: params, headers: headers.reverse_merge(jwt_auth_headers)
+ end
+
+ def stub_user_session(user, csrf_token)
+ stub_session(
+ {
+ 'warden.user.user.key' => [[user.id], user.authenticatable_salt],
+ '_csrf_token' => csrf_token
+ }
+ )
+ end
+
+ def stub_user_session_with_no_user_id(user, csrf_token)
+ stub_session(
+ {
+ 'warden.user.user.key' => [[nil], user.authenticatable_salt],
+ '_csrf_token' => csrf_token
+ }
+ )
+ end
+
+ def mask_token(encoded_token)
+ controller = ActionController::Base.new
+ raw_token = controller.send(:decode_csrf_token, encoded_token)
+ controller.send(:mask_token, raw_token)
+ end
+
+ def new_token
+ ActionController::Base.new.send(:generate_csrf_token)
+ end
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:user_access_config) do
+ {
+ 'user_access' => {
+ 'access_as' => { 'agent' => {} },
+ 'projects' => [{ 'id' => project.full_path }],
+ 'groups' => [{ 'id' => group.full_path }]
+ }
+ }
+ end
+
+ let_it_be(:configuration_project) do
+ create(
+ :project, :custom_repo,
+ files: {
+ ".gitlab/agents/the-agent/config.yaml" => user_access_config.to_yaml
+ }
+ )
+ end
+
+ let_it_be(:agent) { create(:cluster_agent, name: 'the-agent', project: configuration_project) }
+ let_it_be(:another_agent) { create(:cluster_agent) }
+
+ let(:user) { create(:user) }
+
+ before do
+ allow(::Gitlab::Kas).to receive(:enabled?).and_return true
+ 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) })
+
+ 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
+ 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
+ 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 global flag is disabled' do
+ stub_feature_flags(kas_user_access: false)
+
+ 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(:unauthorized)
+ end
+
+ it 'returns 401 when user id is not found in session' do
+ 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
diff --git a/spec/requests/api/internal/pages_spec.rb b/spec/requests/api/internal/pages_spec.rb
index 56f1089843b..20fb9100ebb 100644
--- a/spec/requests/api/internal/pages_spec.rb
+++ b/spec/requests/api/internal/pages_spec.rb
@@ -3,193 +3,97 @@
require 'spec_helper'
RSpec.describe API::Internal::Pages, feature_category: :pages do
- let(:auth_headers) do
- jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256')
- { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token }
+ let_it_be(:group) { create(:group, name: 'mygroup') }
+ let_it_be_with_reload(:project) { create(:project, name: 'myproject', group: group) }
+
+ let(:auth_header) do
+ {
+ Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => JWT.encode(
+ { 'iss' => 'gitlab-pages' },
+ Gitlab::Pages.secret, 'HS256')
+ }
end
- let(:pages_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) }
-
before do
- allow(Gitlab::Pages).to receive(:secret).and_return(pages_secret)
+ allow(Gitlab::Pages)
+ .to receive(:secret)
+ .and_return(SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH))
+
stub_pages_object_storage(::Pages::DeploymentUploader)
end
- describe "GET /internal/pages/status" do
- def query_enabled(headers = {})
- get api("/internal/pages/status"), headers: headers
- end
-
+ describe 'GET /internal/pages/status' do
it 'responds with 401 Unauthorized' do
- query_enabled
+ get api('/internal/pages/status')
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'responds with 204 no content' do
- query_enabled(auth_headers)
+ get api('/internal/pages/status'), headers: auth_header
expect(response).to have_gitlab_http_status(:no_content)
expect(response.body).to be_empty
end
end
- describe "GET /internal/pages" do
- def query_host(host, headers = {})
- get api("/internal/pages"), headers: headers, params: { host: host }
- end
-
- around do |example|
- freeze_time do
- example.run
- end
- end
-
- context 'not authenticated' do
+ describe 'GET /internal/pages' do
+ context 'when not authenticated' do
it 'responds with 401 Unauthorized' do
- query_host('pages.gitlab.io')
+ get api('/internal/pages')
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
- context 'authenticated' do
- def query_host(host)
- jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256')
- headers = { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token }
-
- super(host, headers)
+ context 'when authenticated' do
+ before do
+ project.update_pages_deployment!(create(:pages_deployment, project: project))
end
- def deploy_pages(project)
- deployment = create(:pages_deployment, project: project)
- project.mark_pages_as_deployed
- project.update_pages_deployment!(deployment)
+ around do |example|
+ freeze_time do
+ example.run
+ end
end
- context 'domain does not exist' do
+ context 'when domain does not exist' do
it 'responds with 204 no content' do
- query_host('pages.gitlab.io')
+ get api('/internal/pages'), headers: auth_header, params: { host: 'any-domain.gitlab.io' }
expect(response).to have_gitlab_http_status(:no_content)
expect(response.body).to be_empty
end
end
- context 'serverless domain' do
- let(:namespace) { create(:namespace, name: 'gitlab-org') }
- let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') }
- let(:environment) { create(:environment, project: project) }
- let(:pages_domain) { create(:pages_domain, domain: 'serverless.gitlab.io') }
- let(:knative_without_ingress) { create(:clusters_applications_knative) }
- let(:knative_with_ingress) { create(:clusters_applications_knative, external_ip: '10.0.0.1') }
-
- context 'without a knative ingress gateway IP' do
- let!(:serverless_domain_cluster) do
- create(
- :serverless_domain_cluster,
- uuid: 'abcdef12345678',
- pages_domain: pages_domain,
- knative: knative_without_ingress
- )
- end
-
- let(:serverless_domain) do
- create(
- :serverless_domain,
- serverless_domain_cluster: serverless_domain_cluster,
- environment: environment
- )
- end
-
- it 'responds with 204 no content' do
- query_host(serverless_domain.uri.host)
-
- expect(response).to have_gitlab_http_status(:no_content)
- expect(response.body).to be_empty
- end
- end
-
- context 'with a knative ingress gateway IP' do
- let!(:serverless_domain_cluster) do
- create(
- :serverless_domain_cluster,
- uuid: 'abcdef12345678',
- pages_domain: pages_domain,
- knative: knative_with_ingress
- )
- end
-
- let(:serverless_domain) do
- create(
- :serverless_domain,
- serverless_domain_cluster: serverless_domain_cluster,
- environment: environment
- )
- end
-
- it 'responds with 204 because of feature deprecation' do
- query_host(serverless_domain.uri.host)
+ context 'when querying a custom domain' do
+ let_it_be(:pages_domain) { create(:pages_domain, domain: 'pages.io', project: project) }
- expect(response).to have_gitlab_http_status(:no_content)
- expect(response.body).to be_empty
-
- ##
- # Serverless serving and reverse proxy to Kubernetes / Knative has
- # been deprecated and disabled, as per
- # https://gitlab.com/gitlab-org/gitlab-pages/-/issues/467
- #
- # expect(response).to match_response_schema('internal/serverless/virtual_domain')
- # expect(json_response['certificate']).to eq(pages_domain.certificate)
- # expect(json_response['key']).to eq(pages_domain.key)
- #
- # expect(json_response['lookup_paths']).to eq(
- # [
- # {
- # 'source' => {
- # 'type' => 'serverless',
- # 'service' => "test-function.#{project.name}-#{project.id}-#{environment.slug}.#{serverless_domain_cluster.knative.hostname}",
- # 'cluster' => {
- # 'hostname' => serverless_domain_cluster.knative.hostname,
- # 'address' => serverless_domain_cluster.knative.external_ip,
- # 'port' => 443,
- # 'cert' => serverless_domain_cluster.certificate,
- # 'key' => serverless_domain_cluster.key
- # }
- # }
- # }
- # ]
- # )
+ context 'when there are no pages deployed for the related project' do
+ before do
+ project.mark_pages_as_not_deployed
end
- end
- end
- context 'custom domain' do
- let(:namespace) { create(:namespace, name: 'gitlab-org') }
- let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') }
- let!(:pages_domain) { create(:pages_domain, domain: 'pages.io', project: project) }
-
- context 'when there are no pages deployed for the related project' do
it 'responds with 204 No Content' do
- query_host('pages.io')
+ get api('/internal/pages'), headers: auth_header, params: { host: 'pages.io' }
expect(response).to have_gitlab_http_status(:no_content)
end
end
context 'when there are pages deployed for the related project' do
- it 'domain lookup is case insensitive' do
- deploy_pages(project)
+ before do
+ project.mark_pages_as_deployed
+ end
- query_host('Pages.IO')
+ it 'domain lookup is case insensitive' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'Pages.IO' }
expect(response).to have_gitlab_http_status(:ok)
end
it 'responds with the correct domain configuration' do
- deploy_pages(project)
-
- query_host('pages.io')
+ get api('/internal/pages'), headers: auth_header, params: { host: 'pages.io' }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('internal/pages/virtual_domain')
@@ -212,7 +116,8 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do
'sha256' => deployment.file_sha256,
'file_size' => deployment.size,
'file_count' => deployment.file_count
- }
+ },
+ 'unique_domain' => nil
}
]
)
@@ -220,20 +125,67 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do
end
end
- context 'namespaced domain' do
- let(:group) { create(:group, name: 'mygroup') }
+ context 'when querying a unique domain' do
+ before_all do
+ project.project_setting.update!(
+ pages_unique_domain: 'unique-domain',
+ pages_unique_domain_enabled: true
+ )
+ end
- before do
- allow(Settings.pages).to receive(:host).and_return('gitlab-pages.io')
- allow(Gitlab.config.pages).to receive(:url).and_return("http://gitlab-pages.io")
+ context 'when there are no pages deployed for the related project' do
+ before do
+ project.mark_pages_as_not_deployed
+ end
+
+ it 'responds with 204 No Content' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'unique-domain.example.com' }
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
end
- context 'regular project' do
- it 'responds with the correct domain configuration' do
- project = create(:project, group: group, name: 'myproject')
- deploy_pages(project)
+ context 'when there are pages deployed for the related project' do
+ before do
+ project.mark_pages_as_deployed
+ end
+
+ context 'when the feature flag is disabled' do
+ before do
+ stub_feature_flags(pages_unique_domain: false)
+ end
- query_host('mygroup.gitlab-pages.io')
+ context 'when there are no pages deployed for the related project' do
+ it 'responds with 204 No Content' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'unique-domain.example.com' }
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
+ end
+
+ context 'when the unique domain is disabled' do
+ before do
+ project.project_setting.update!(pages_unique_domain_enabled: false)
+ end
+
+ context 'when there are no pages deployed for the related project' do
+ it 'responds with 204 No Content' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'unique-domain.example.com' }
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
+ end
+
+ it 'domain lookup is case insensitive' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'Unique-Domain.example.com' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'responds with the correct domain configuration' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'unique-domain.example.com' }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('internal/pages/virtual_domain')
@@ -245,7 +197,7 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do
'project_id' => project.id,
'access_control' => false,
'https_only' => false,
- 'prefix' => '/myproject/',
+ 'prefix' => '/',
'source' => {
'type' => 'zip',
'path' => deployment.file.url(expire_at: 1.day.from_now),
@@ -253,56 +205,116 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do
'sha256' => deployment.file_sha256,
'file_size' => deployment.size,
'file_count' => deployment.file_count
- }
+ },
+ 'unique_domain' => 'unique-domain'
}
]
)
end
end
+ end
- it 'avoids N+1 queries' do
- project = create(:project, group: group)
- deploy_pages(project)
-
- control = ActiveRecord::QueryRecorder.new { query_host('mygroup.gitlab-pages.io') }
+ context 'when querying a namespaced domain' do
+ before do
+ allow(Settings.pages).to receive(:host).and_return('gitlab-pages.io')
+ allow(Gitlab.config.pages).to receive(:url).and_return("http://gitlab-pages.io")
+ end
- 3.times do
- project = create(:project, group: group)
- deploy_pages(project)
+ context 'when there are no pages deployed for the related project' do
+ before do
+ project.mark_pages_as_not_deployed
end
- expect { query_host('mygroup.gitlab-pages.io') }.not_to exceed_query_limit(control)
+ it 'responds with 204 No Content' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('internal/pages/virtual_domain')
+ expect(json_response['lookup_paths']).to eq([])
+ end
end
- context 'group root project' do
- it 'responds with the correct domain configuration' do
- project = create(:project, group: group, name: 'mygroup.gitlab-pages.io')
- deploy_pages(project)
+ context 'when there are pages deployed for the related project' do
+ before do
+ project.mark_pages_as_deployed
+ end
- query_host('mygroup.gitlab-pages.io')
+ context 'with a regular project' do
+ it 'responds with the correct domain configuration' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('internal/pages/virtual_domain')
+
+ deployment = project.pages_metadatum.pages_deployment
+ expect(json_response['lookup_paths']).to eq(
+ [
+ {
+ 'project_id' => project.id,
+ 'access_control' => false,
+ 'https_only' => false,
+ 'prefix' => '/myproject/',
+ 'source' => {
+ 'type' => 'zip',
+ 'path' => deployment.file.url(expire_at: 1.day.from_now),
+ 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}",
+ 'sha256' => deployment.file_sha256,
+ 'file_size' => deployment.size,
+ 'file_count' => deployment.file_count
+ },
+ 'unique_domain' => nil
+ }
+ ]
+ )
+ end
+ end
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('internal/pages/virtual_domain')
+ it 'avoids N+1 queries' do
+ control = ActiveRecord::QueryRecorder.new do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' }
+ end
- deployment = project.pages_metadatum.pages_deployment
- expect(json_response['lookup_paths']).to eq(
- [
- {
- 'project_id' => project.id,
- 'access_control' => false,
- 'https_only' => false,
- 'prefix' => '/',
- 'source' => {
- 'type' => 'zip',
- 'path' => deployment.file.url(expire_at: 1.day.from_now),
- 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}",
- 'sha256' => deployment.file_sha256,
- 'file_size' => deployment.size,
- 'file_count' => deployment.file_count
+ 3.times do
+ project = create(:project, group: group)
+ project.mark_pages_as_deployed
+ end
+
+ expect { get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' } }
+ .not_to exceed_query_limit(control)
+ end
+
+ context 'with a group root project' do
+ before do
+ project.update!(path: 'mygroup.gitlab-pages.io')
+ end
+
+ it 'responds with the correct domain configuration' do
+ get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('internal/pages/virtual_domain')
+
+ deployment = project.pages_metadatum.pages_deployment
+ expect(json_response['lookup_paths']).to eq(
+ [
+ {
+ 'project_id' => project.id,
+ 'access_control' => false,
+ 'https_only' => false,
+ 'prefix' => '/',
+ 'source' => {
+ 'type' => 'zip',
+ 'path' => deployment.file.url(expire_at: 1.day.from_now),
+ 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}",
+ 'sha256' => deployment.file_sha256,
+ 'file_size' => deployment.size,
+ 'file_count' => deployment.file_count
+ },
+ 'unique_domain' => nil
}
- }
- ]
- )
+ ]
+ )
+ end
end
end
end
diff --git a/spec/requests/api/internal/workhorse_spec.rb b/spec/requests/api/internal/workhorse_spec.rb
index 99d0ecabbb7..2657abffae6 100644
--- a/spec/requests/api/internal/workhorse_spec.rb
+++ b/spec/requests/api/internal/workhorse_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::Workhorse, :allow_forgery_protection, feature_category: :not_owned do
+RSpec.describe API::Internal::Workhorse, :allow_forgery_protection, feature_category: :shared do
include WorkhorseHelpers
context '/authorize_upload' do
diff --git a/spec/requests/api/issues/get_group_issues_spec.rb b/spec/requests/api/issues/get_group_issues_spec.rb
index 0641c2135c1..eaa3c46d0ca 100644
--- a/spec/requests/api/issues/get_group_issues_spec.rb
+++ b/spec/requests/api/issues/get_group_issues_spec.rb
@@ -74,7 +74,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let(:base_url) { "/groups/#{group.id}/issues" }
shared_examples 'group issues statistics' do
- it 'returns issues statistics' do
+ it 'returns issues statistics', :aggregate_failures do
get api("/groups/#{group.id}/issues_statistics", user), params: params
expect(response).to have_gitlab_http_status(:ok)
@@ -346,7 +346,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
group_project.add_reporter(user)
end
- it 'exposes known attributes' do
+ it 'exposes known attributes', :aggregate_failures do
get api(base_url, admin)
expect(response).to have_gitlab_http_status(:ok)
@@ -355,7 +355,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
it 'returns all group issues (including opened and closed)' do
- get api(base_url, admin)
+ get api(base_url, admin, admin_mode: true)
expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id, group_issue.id])
end
@@ -385,7 +385,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
it 'returns group confidential issues for admin' do
- get api(base_url, admin), params: { state: :opened }
+ get api(base_url, admin, admin_mode: true), params: { state: :opened }
expect_paginated_array_response([group_confidential_issue.id, group_issue.id])
end
@@ -403,7 +403,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'labels parameter' do
- it 'returns an array of labeled group issues' do
+ it 'returns an array of labeled group issues', :aggregate_failures do
get api(base_url, user), params: { labels: group_label.title }
expect_paginated_array_response(group_issue.id)
@@ -486,7 +486,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'returns an array of issues found by iids' do
+ it 'returns an array of issues found by iids', :aggregate_failures do
get api(base_url, user), params: { iids: [group_issue.iid] }
expect_paginated_array_response(group_issue.id)
@@ -505,14 +505,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect_paginated_array_response([])
end
- it 'returns an array of group issues with any label' do
+ it 'returns an array of group issues with any label', :aggregate_failures do
get api(base_url, user), params: { labels: IssuableFinder::Params::FILTER_ANY }
expect_paginated_array_response(group_issue.id)
expect(json_response.first['id']).to eq(group_issue.id)
end
- it 'returns an array of group issues with any label with labels param as array' do
+ it 'returns an array of group issues with any label with labels param as array', :aggregate_failures do
get api(base_url, user), params: { labels: [IssuableFinder::Params::FILTER_ANY] }
expect_paginated_array_response(group_issue.id)
@@ -555,7 +555,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect_paginated_array_response(group_closed_issue.id)
end
- it 'returns an array of issues with no milestone' do
+ it 'returns an array of issues with no milestone', :aggregate_failures do
get api(base_url, user), params: { milestone: no_milestone_title }
expect(response).to have_gitlab_http_status(:ok)
@@ -688,28 +688,28 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let!(:issue2) { create(:issue, author: user2, project: group_project, created_at: 2.days.ago) }
let!(:issue3) { create(:issue, author: user2, assignees: [assignee, another_assignee], project: group_project, created_at: 1.day.ago) }
- it 'returns issues with by assignee_username' do
+ it 'returns issues with by assignee_username', :aggregate_failures do
get api(base_url, user), params: { assignee_username: [assignee.username], scope: 'all' }
expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id])
expect_paginated_array_response([issue3.id, group_confidential_issue.id])
end
- it 'returns issues by assignee_username as string' do
+ it 'returns issues by assignee_username as string', :aggregate_failures do
get api(base_url, user), params: { assignee_username: assignee.username, scope: 'all' }
expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id])
expect_paginated_array_response([issue3.id, group_confidential_issue.id])
end
- it 'returns error when multiple assignees are passed' do
+ it 'returns error when multiple assignees are passed', :aggregate_failures do
get api(base_url, user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response["error"]).to include("allows one value, but found 2")
end
- it 'returns error when assignee_username and assignee_id are passed together' do
+ it 'returns error when assignee_username and assignee_id are passed together', :aggregate_failures do
get api(base_url, user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -719,7 +719,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
describe "#to_reference" do
- it 'exposes reference path in context of group' do
+ it 'exposes reference path in context of group', :aggregate_failures do
get api(base_url, user)
expect(json_response.first['references']['short']).to eq("##{group_closed_issue.iid}")
@@ -735,7 +735,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
group_closed_issue.reload
end
- it 'exposes reference path in context of parent group' do
+ it 'exposes reference path in context of parent group', :aggregate_failures do
get api("/groups/#{parent_group.id}/issues")
expect(json_response.first['references']['short']).to eq("##{group_closed_issue.iid}")
diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb
index 6fc3903103b..915b8fff75e 100644
--- a/spec/requests/api/issues/get_project_issues_spec.rb
+++ b/spec/requests/api/issues/get_project_issues_spec.rb
@@ -99,7 +99,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
shared_examples 'project issues statistics' do
- it 'returns project issues statistics' do
+ it 'returns project issues statistics', :aggregate_failures do
get api("/projects/#{project.id}/issues_statistics", current_user), params: params
expect(response).to have_gitlab_http_status(:ok)
@@ -317,7 +317,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
it 'returns project confidential issues for admin' do
- get api("#{base_url}/issues", admin)
+ get api("#{base_url}/issues", admin, admin_mode: true)
expect_paginated_array_response([issue.id, confidential_issue.id, closed_issue.id])
end
@@ -526,7 +526,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect_paginated_array_response([closed_issue.id, confidential_issue.id, issue.id])
end
- it 'exposes known attributes' do
+ it 'exposes known attributes', :aggregate_failures do
get api("#{base_url}/issues", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -607,28 +607,28 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let!(:issue2) { create(:issue, author: user2, project: project, created_at: 2.days.ago) }
let!(:issue3) { create(:issue, author: user2, assignees: [assignee, another_assignee], project: project, created_at: 1.day.ago) }
- it 'returns issues by assignee_username' do
+ it 'returns issues by assignee_username', :aggregate_failures do
get api("/issues", user), params: { assignee_username: [assignee.username], scope: 'all' }
expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id])
expect_paginated_array_response([confidential_issue.id, issue3.id])
end
- it 'returns issues by assignee_username as string' do
+ it 'returns issues by assignee_username as string', :aggregate_failures do
get api("/issues", user), params: { assignee_username: assignee.username, scope: 'all' }
expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id])
expect_paginated_array_response([confidential_issue.id, issue3.id])
end
- it 'returns error when multiple assignees are passed' do
+ it 'returns error when multiple assignees are passed', :aggregate_failures do
get api("/issues", user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response["error"]).to include("allows one value, but found 2")
end
- it 'returns error when assignee_username and assignee_id are passed together' do
+ it 'returns error when assignee_username and assignee_id are passed together', :aggregate_failures do
get api("/issues", user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -646,7 +646,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'exposes known attributes' do
+ it 'exposes known attributes', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{issue.iid}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -686,7 +686,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'exposes the closed_at attribute' do
+ it 'exposes the closed_at attribute', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{closed_issue.iid}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -694,7 +694,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'links exposure' do
- it 'exposes related resources full URIs' do
+ it 'exposes related resources full URIs', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{issue.iid}", user)
links = json_response['_links']
@@ -706,7 +706,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'returns a project issue by internal id' do
+ it 'returns a project issue by internal id', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{issue.iid}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -738,7 +738,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(response).to have_gitlab_http_status(:not_found)
end
- it 'returns confidential issue for project members' do
+ it 'returns confidential issue for project members', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -746,7 +746,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['iid']).to eq(confidential_issue.iid)
end
- it 'returns confidential issue for author' do
+ it 'returns confidential issue for author', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", author)
expect(response).to have_gitlab_http_status(:ok)
@@ -754,7 +754,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['iid']).to eq(confidential_issue.iid)
end
- it 'returns confidential issue for assignee' do
+ it 'returns confidential issue for assignee', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", assignee)
expect(response).to have_gitlab_http_status(:ok)
@@ -762,8 +762,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['iid']).to eq(confidential_issue.iid)
end
- it 'returns confidential issue for admin' do
- get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", admin)
+ it 'returns confidential issue for admin', :aggregate_failures do
+ get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(confidential_issue.title)
@@ -829,7 +829,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let!(:related_mr) { create_referencing_mr(user, project, issue) }
context 'when unauthenticated' do
- it 'return list of referenced merge requests from issue' do
+ it 'return list of referenced merge requests from issue', :aggregate_failures do
get_related_merge_requests(project.id, issue.iid)
expect_paginated_array_response(related_mr.id)
@@ -898,8 +898,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'exposes known attributes' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin)
+ it 'exposes known attributes', :aggregate_failures do
+ get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['user_agent']).to eq(user_agent_detail.user_agent)
@@ -936,7 +936,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
)
end
- it 'returns a full list of participants' do
+ it 'returns a full list of participants', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{issue.iid}/participants", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -945,7 +945,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when user cannot see a confidential note' do
- it 'returns a limited list of participants' do
+ it 'returns a limited list of participants', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{issue.iid}/participants", create(:user))
expect(response).to have_gitlab_http_status(:ok)
diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb
index 4b60eaadcbc..33f49cefc69 100644
--- a/spec/requests/api/issues/issues_spec.rb
+++ b/spec/requests/api/issues/issues_spec.rb
@@ -78,7 +78,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
shared_examples 'issues statistics' do
- it 'returns issues statistics' do
+ it 'returns issues statistics', :aggregate_failures do
get api("/issues_statistics", user), params: params
expect(response).to have_gitlab_http_status(:ok)
@@ -109,8 +109,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do
context 'as an admin' do
context 'when issue exists' do
- it 'returns the issue' do
- get api("/issues/#{issue.id}", admin)
+ it 'returns the issue', :aggregate_failures do
+ get api("/issues/#{issue.id}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.dig('author', 'id')).to eq(issue.author.id)
@@ -121,7 +121,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
context 'when issue does not exist' do
it 'returns 404' do
- get api("/issues/0", admin)
+ get api("/issues/0", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -132,7 +132,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
describe 'GET /issues' do
context 'when unauthenticated' do
- it 'returns an array of all issues' do
+ it 'returns an array of all issues', :aggregate_failures do
get api('/issues'), params: { scope: 'all' }
expect(response).to have_gitlab_http_status(:ok)
@@ -162,14 +162,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(response).to have_gitlab_http_status(:unauthorized)
end
- it 'returns an array of issues matching state in milestone' do
+ it 'returns an array of issues matching state in milestone', :aggregate_failures do
get api('/issues'), params: { milestone: 'foo', scope: 'all' }
expect(response).to have_gitlab_http_status(:ok)
expect_paginated_array_response([])
end
- it 'returns an array of issues matching state in milestone' do
+ it 'returns an array of issues matching state in milestone', :aggregate_failures do
get api('/issues'), params: { milestone: milestone.title, scope: 'all' }
expect(response).to have_gitlab_http_status(:ok)
@@ -273,7 +273,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when authenticated' do
- it 'returns an array of issues' do
+ it 'returns an array of issues', :aggregate_failures do
get api('/issues', user)
expect_paginated_array_response([issue.id, closed_issue.id])
@@ -532,7 +532,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
context 'with incident issues' do
let_it_be(:incident) { create(:incident, project: project) }
- it 'avoids N+1 queries' do
+ it 'avoids N+1 queries', :aggregate_failures do
get api('/issues', user) # warm up
control = ActiveRecord::QueryRecorder.new do
@@ -553,7 +553,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
context 'with issues closed as duplicates' do
let_it_be(:dup_issue_1) { create(:issue, :closed_as_duplicate, project: project) }
- it 'avoids N+1 queries' do
+ it 'avoids N+1 queries', :aggregate_failures do
get api('/issues', user) # warm up
control = ActiveRecord::QueryRecorder.new do
@@ -639,7 +639,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect_paginated_array_response([])
end
- it 'returns an array of labeled issues matching given state' do
+ it 'returns an array of labeled issues matching given state', :aggregate_failures do
get api('/issues', user), params: { labels: label.title, state: :opened }
expect_paginated_array_response(issue.id)
@@ -647,7 +647,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response.first['state']).to eq('opened')
end
- it 'returns an array of labeled issues matching given state with labels param as array' do
+ it 'returns an array of labeled issues matching given state with labels param as array', :aggregate_failures do
get api('/issues', user), params: { labels: [label.title], state: :opened }
expect_paginated_array_response(issue.id)
@@ -917,14 +917,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'matches V4 response schema' do
+ it 'matches V4 response schema', :aggregate_failures do
get api('/issues', user)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/issues')
end
- it 'returns a related merge request count of 0 if there are no related merge requests' do
+ it 'returns a related merge request count of 0 if there are no related merge requests', :aggregate_failures do
get api('/issues', user)
expect(response).to have_gitlab_http_status(:ok)
@@ -932,7 +932,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response.first).to include('merge_requests_count' => 0)
end
- it 'returns a related merge request count > 0 if there are related merge requests' do
+ it 'returns a related merge request count > 0 if there are related merge requests', :aggregate_failures do
create(:merge_requests_closing_issues, issue: issue)
get api('/issues', user)
@@ -1013,28 +1013,28 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let!(:issue2) { create(:issue, author: user2, project: project, created_at: 2.days.ago) }
let!(:issue3) { create(:issue, author: user2, assignees: [assignee, another_assignee], project: project, created_at: 1.day.ago) }
- it 'returns issues with by assignee_username' do
+ it 'returns issues with by assignee_username', :aggregate_failures do
get api("/issues", user), params: { assignee_username: [assignee.username], scope: 'all' }
expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id])
expect_paginated_array_response([confidential_issue.id, issue3.id])
end
- it 'returns issues by assignee_username as string' do
+ it 'returns issues by assignee_username as string', :aggregate_failures do
get api("/issues", user), params: { assignee_username: assignee.username, scope: 'all' }
expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id])
expect_paginated_array_response([confidential_issue.id, issue3.id])
end
- it 'returns error when multiple assignees are passed' do
+ it 'returns error when multiple assignees are passed', :aggregate_failures do
get api("/issues", user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response["error"]).to include("allows one value, but found 2")
end
- it 'returns error when assignee_username and assignee_id are passed together' do
+ it 'returns error when assignee_username and assignee_id are passed together', :aggregate_failures do
get api("/issues", user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -1088,7 +1088,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
describe 'GET /projects/:id/issues/:issue_iid' do
- it 'exposes full reference path' do
+ it 'exposes full reference path', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{issue.iid}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -1106,7 +1106,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'user does not have permission to view new issue' do
- it 'does not return the issue as closed_as_duplicate_of' do
+ it 'does not return the issue as closed_as_duplicate_of', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{issue_closed_as_dup.iid}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -1119,7 +1119,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
new_issue.project.add_guest(user)
end
- it 'returns the issue as closed_as_duplicate_of' do
+ it 'returns the issue as closed_as_duplicate_of', :aggregate_failures do
get api("/projects/#{project.id}/issues/#{issue_closed_as_dup.iid}", user)
expect(response).to have_gitlab_http_status(:ok)
@@ -1131,7 +1131,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
describe "POST /projects/:id/issues" do
- it 'creates a new project issue' do
+ it 'creates a new project issue', :aggregate_failures do
post api("/projects/#{project.id}/issues", user), params: { title: 'new issue' }
expect(response).to have_gitlab_http_status(:created)
@@ -1139,6 +1139,15 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['issue_type']).to eq('issue')
end
+ context 'when confidential is null' do
+ it 'responds with 400 error', :aggregate_failures do
+ post api("/projects/#{project.id}/issues", user), params: { title: 'issue', confidential: nil }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq('confidential is empty')
+ end
+ end
+
context 'when issue create service returns an unrecoverable error' do
before do
allow_next_instance_of(Issues::CreateService) do |create_service|
@@ -1146,7 +1155,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'returns and error message and status code from the service' do
+ it 'returns and error message and status code from the service', :aggregate_failures do
post api("/projects/#{project.id}/issues", user), params: { title: 'new issue' }
expect(response).to have_gitlab_http_status(:forbidden)
@@ -1168,15 +1177,15 @@ RSpec.describe API::Issues, feature_category: :team_planning do
travel_to fixed_time
end
- it 'allows admins to set the timestamp' do
- put api("/projects/#{project.id}/issues/#{issue.iid}", admin), params: { labels: 'label1', updated_at: updated_at }
+ it 'allows admins to set the timestamp', :aggregate_failures do
+ put api("/projects/#{project.id}/issues/#{issue.iid}", admin, admin_mode: true), params: { labels: 'label1', updated_at: updated_at }
expect(response).to have_gitlab_http_status(:ok)
expect(Time.parse(json_response['updated_at'])).to be_like_time(updated_at)
expect(ResourceLabelEvent.last.created_at).to be_like_time(updated_at)
end
- it 'does not allow other users to set the timestamp' do
+ it 'does not allow other users to set the timestamp', :aggregate_failures do
reporter = create(:user)
project.add_developer(reporter)
@@ -1259,7 +1268,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'with valid params' do
- it 'reorders issues and returns a successful 200 response' do
+ it 'reorders issues and returns a successful 200 response', :aggregate_failures do
put api("/projects/#{project.id}/issues/#{issue1.iid}/reorder", user), params: { move_after_id: issue2.id, move_before_id: issue3.id }
expect(response).to have_gitlab_http_status(:ok)
@@ -1286,7 +1295,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let(:other_project) { create(:project, group: group) }
let(:other_issue) { create(:issue, project: other_project, relative_position: 80) }
- it 'reorders issues and returns a successful 200 response' do
+ it 'reorders issues and returns a successful 200 response', :aggregate_failures do
put api("/projects/#{other_project.id}/issues/#{other_issue.iid}/reorder", user), params: { move_after_id: issue2.id, move_before_id: issue3.id }
expect(response).to have_gitlab_http_status(:ok)
diff --git a/spec/requests/api/issues/post_projects_issues_spec.rb b/spec/requests/api/issues/post_projects_issues_spec.rb
index 265091fa698..a17c1389e83 100644
--- a/spec/requests/api/issues/post_projects_issues_spec.rb
+++ b/spec/requests/api/issues/post_projects_issues_spec.rb
@@ -75,7 +75,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
describe 'POST /projects/:id/issues' do
context 'support for deprecated assignee_id' do
- it 'creates a new project issue' do
+ it 'creates a new project issue', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', assignee_id: user2.id }
@@ -85,7 +85,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['assignees'].first['name']).to eq(user2.name)
end
- it 'creates a new project issue when assignee_id is empty' do
+ it 'creates a new project issue when assignee_id is empty', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', assignee_id: '' }
@@ -96,7 +96,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'single assignee restrictions' do
- it 'creates a new project issue with no more than one assignee' do
+ it 'creates a new project issue with no more than one assignee', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', assignee_ids: [user2.id, guest.id] }
@@ -122,8 +122,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do
context 'an internal ID is provided' do
context 'by an admin' do
- it 'sets the internal ID on the new issue' do
- post api("/projects/#{project.id}/issues", admin),
+ it 'sets the internal ID on the new issue', :aggregate_failures do
+ post api("/projects/#{project.id}/issues", admin, admin_mode: true),
params: { title: 'new issue', iid: 9001 }
expect(response).to have_gitlab_http_status(:created)
@@ -132,7 +132,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'by an owner' do
- it 'sets the internal ID on the new issue' do
+ it 'sets the internal ID on the new issue', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', iid: 9001 }
@@ -145,7 +145,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let(:group) { create(:group) }
let(:group_project) { create(:project, :public, namespace: group) }
- it 'sets the internal ID on the new issue' do
+ it 'sets the internal ID on the new issue', :aggregate_failures do
group.add_owner(user2)
post api("/projects/#{group_project.id}/issues", user2),
params: { title: 'new issue', iid: 9001 }
@@ -156,7 +156,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'by another user' do
- it 'ignores the given internal ID' do
+ it 'ignores the given internal ID', :aggregate_failures do
post api("/projects/#{project.id}/issues", user2),
params: { title: 'new issue', iid: 9001 }
@@ -166,8 +166,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when an issue with the same IID exists on database' do
- it 'returns 409' do
- post api("/projects/#{project.id}/issues", admin),
+ it 'returns 409', :aggregate_failures do
+ post api("/projects/#{project.id}/issues", admin, admin_mode: true),
params: { title: 'new issue', iid: issue.iid }
expect(response).to have_gitlab_http_status(:conflict)
@@ -176,7 +176,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'creates a new project issue' do
+ it 'creates a new project issue', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', labels: 'label, label2', weight: 3, assignee_ids: [user2.id] }
@@ -189,7 +189,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['assignees'].first['name']).to eq(user2.name)
end
- it 'creates a new project issue with labels param as array' do
+ it 'creates a new project issue with labels param as array', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', labels: %w(label label2), weight: 3, assignee_ids: [user2.id] }
@@ -202,7 +202,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['assignees'].first['name']).to eq(user2.name)
end
- it 'creates a new confidential project issue' do
+ it 'creates a new confidential project issue', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', confidential: true }
@@ -211,7 +211,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['confidential']).to be_truthy
end
- it 'creates a new confidential project issue with a different param' do
+ it 'creates a new confidential project issue with a different param', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', confidential: 'y' }
@@ -220,7 +220,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['confidential']).to be_truthy
end
- it 'creates a public issue when confidential param is false' do
+ it 'creates a public issue when confidential param is false', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', confidential: false }
@@ -229,7 +229,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['confidential']).to be_falsy
end
- it 'creates a public issue when confidential param is invalid' do
+ it 'creates a public issue when confidential param is invalid', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'new issue', confidential: 'foo' }
@@ -242,7 +242,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'allows special label names' do
+ it 'allows special label names', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: {
title: 'new issue',
@@ -256,7 +256,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['labels']).to include '&'
end
- it 'allows special label names with labels param as array' do
+ it 'allows special label names with labels param as array', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: {
title: 'new issue',
@@ -270,7 +270,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['labels']).to include '&'
end
- it 'returns 400 if title is too long' do
+ it 'returns 400 if title is too long', :aggregate_failures do
post api("/projects/#{project.id}/issues", user),
params: { title: 'g' * 256 }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -313,7 +313,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'with due date' do
- it 'creates a new project issue' do
+ it 'creates a new project issue', :aggregate_failures do
due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
post api("/projects/#{project.id}/issues", user),
@@ -336,8 +336,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'by an admin' do
- it 'sets the creation time on the new issue' do
- post api("/projects/#{project.id}/issues", admin), params: params
+ it 'sets the creation time on the new issue', :aggregate_failures do
+ post api("/projects/#{project.id}/issues", admin, admin_mode: true), params: params
expect(response).to have_gitlab_http_status(:created)
expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
@@ -346,7 +346,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'by a project owner' do
- it 'sets the creation time on the new issue' do
+ it 'sets the creation time on the new issue', :aggregate_failures do
post api("/projects/#{project.id}/issues", user), params: params
expect(response).to have_gitlab_http_status(:created)
@@ -356,7 +356,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'by a group owner' do
- it 'sets the creation time on the new issue' do
+ it 'sets the creation time on the new issue', :aggregate_failures do
group = create(:group)
group_project = create(:project, :public, namespace: group)
group.add_owner(user2)
@@ -370,7 +370,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'by another user' do
- it 'ignores the given creation time' do
+ it 'ignores the given creation time', :aggregate_failures do
project.add_developer(user2)
post api("/projects/#{project.id}/issues", user2), params: params
@@ -397,7 +397,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when request exceeds the rate limit' do
- it 'prevents users from creating more issues' do
+ it 'prevents users from creating more issues', :aggregate_failures do
allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
post api("/projects/#{project.id}/issues", user),
@@ -437,7 +437,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect { post_issue }.not_to change(Issue, :count)
end
- it 'returns correct status and message' do
+ it 'returns correct status and message', :aggregate_failures do
post_issue
expect(response).to have_gitlab_http_status(:bad_request)
@@ -476,7 +476,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let!(:target_project) { create(:project, creator_id: user.id, namespace: user.namespace) }
let!(:target_project2) { create(:project, creator_id: non_member.id, namespace: non_member.namespace) }
- it 'moves an issue' do
+ it 'moves an issue', :aggregate_failures do
post api("/projects/#{project.id}/issues/#{issue.iid}/move", user),
params: { to_project_id: target_project.id }
@@ -485,7 +485,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when source and target projects are the same' do
- it 'returns 400 when trying to move an issue' do
+ it 'returns 400 when trying to move an issue', :aggregate_failures do
post api("/projects/#{project.id}/issues/#{issue.iid}/move", user),
params: { to_project_id: project.id }
@@ -495,7 +495,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when the user does not have the permission to move issues' do
- it 'returns 400 when trying to move an issue' do
+ it 'returns 400 when trying to move an issue', :aggregate_failures do
post api("/projects/#{project.id}/issues/#{issue.iid}/move", user),
params: { to_project_id: target_project2.id }
@@ -504,8 +504,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'moves the issue to another namespace if I am admin' do
- post api("/projects/#{project.id}/issues/#{issue.iid}/move", admin),
+ it 'moves the issue to another namespace if I am admin', :aggregate_failures do
+ post api("/projects/#{project.id}/issues/#{issue.iid}/move", admin, admin_mode: true),
params: { to_project_id: target_project2.id }
expect(response).to have_gitlab_http_status(:created)
@@ -513,7 +513,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when using the issue ID instead of iid' do
- it 'returns 404 when trying to move an issue', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341520' do
+ it 'returns 404 when trying to move an issue', :aggregate_failures, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341520' do
post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
params: { to_project_id: target_project.id }
@@ -523,7 +523,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when issue does not exist' do
- it 'returns 404 when trying to move an issue' do
+ it 'returns 404 when trying to move an issue', :aggregate_failures do
post api("/projects/#{project.id}/issues/123/move", user),
params: { to_project_id: target_project.id }
@@ -533,7 +533,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when source project does not exist' do
- it 'returns 404 when trying to move an issue' do
+ it 'returns 404 when trying to move an issue', :aggregate_failures do
post api("/projects/0/issues/#{issue.iid}/move", user),
params: { to_project_id: target_project.id }
@@ -562,7 +562,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
context 'when user can admin the issue' do
context 'when the user can admin the target project' do
- it 'clones the issue' do
+ it 'clones the issue', :aggregate_failures do
expect do
post_clone_issue(user, issue, valid_target_project)
end.to change { valid_target_project.issues.count }.by(1)
@@ -577,7 +577,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when target project is the same source project' do
- it 'clones the issue' do
+ it 'clones the issue', :aggregate_failures do
expect do
post_clone_issue(user, issue, issue.project)
end.to change { issue.reset.project.issues.count }.by(1)
@@ -595,7 +595,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when the user does not have the permission to clone issues' do
- it 'returns 400' do
+ it 'returns 400', :aggregate_failures do
post api("/projects/#{project.id}/issues/#{issue.iid}/clone", user),
params: { to_project_id: invalid_target_project.id }
@@ -605,7 +605,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when using the issue ID instead of iid' do
- it 'returns 404', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341520' do
+ it 'returns 404', :aggregate_failures, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341520' do
post api("/projects/#{project.id}/issues/#{issue.id}/clone", user),
params: { to_project_id: valid_target_project.id }
@@ -615,7 +615,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when issue does not exist' do
- it 'returns 404' do
+ it 'returns 404', :aggregate_failures do
post api("/projects/#{project.id}/issues/12300/clone", user),
params: { to_project_id: valid_target_project.id }
@@ -625,7 +625,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when source project does not exist' do
- it 'returns 404' do
+ it 'returns 404', :aggregate_failures do
post api("/projects/0/issues/#{issue.iid}/clone", user),
params: { to_project_id: valid_target_project.id }
@@ -635,7 +635,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
context 'when target project does not exist' do
- it 'returns 404' do
+ it 'returns 404', :aggregate_failures do
post api("/projects/#{project.id}/issues/#{issue.iid}/clone", user),
params: { to_project_id: 0 }
@@ -644,7 +644,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'clones the issue with notes when with_notes is true' do
+ it 'clones the issue with notes when with_notes is true', :aggregate_failures do
expect do
post api("/projects/#{project.id}/issues/#{issue.iid}/clone", user),
params: { to_project_id: valid_target_project.id, with_notes: true }
@@ -661,7 +661,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
describe 'POST :id/issues/:issue_iid/subscribe' do
- it 'subscribes to an issue' do
+ it 'subscribes to an issue', :aggregate_failures do
post api("/projects/#{project.id}/issues/#{issue.iid}/subscribe", user2)
expect(response).to have_gitlab_http_status(:created)
@@ -694,7 +694,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
describe 'POST :id/issues/:issue_id/unsubscribe' do
- it 'unsubscribes from an issue' do
+ it 'unsubscribes from an issue', :aggregate_failures do
post api("/projects/#{project.id}/issues/#{issue.iid}/unsubscribe", user)
expect(response).to have_gitlab_http_status(:created)
diff --git a/spec/requests/api/issues/put_projects_issues_spec.rb b/spec/requests/api/issues/put_projects_issues_spec.rb
index f0d174c9e78..6cc639c0bcc 100644
--- a/spec/requests/api/issues/put_projects_issues_spec.rb
+++ b/spec/requests/api/issues/put_projects_issues_spec.rb
@@ -80,7 +80,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
describe 'PUT /projects/:id/issues/:issue_iid to update only title' do
- it 'updates a project issue' do
+ it 'updates a project issue', :aggregate_failures do
put api_for_user, params: { title: updated_title }
expect(response).to have_gitlab_http_status(:ok)
@@ -109,7 +109,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(response).to have_gitlab_http_status(:ok)
end
- it 'allows special label names with labels param as array' do
+ it 'allows special label names with labels param as array', :aggregate_failures do
put api_for_user,
params: {
title: updated_title,
@@ -135,42 +135,42 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(response).to have_gitlab_http_status(:forbidden)
end
- it 'updates a confidential issue for project members' do
+ it 'updates a confidential issue for project members', :aggregate_failures do
put api(confidential_issue_path, user), params: { title: updated_title }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(updated_title)
end
- it 'updates a confidential issue for author' do
+ it 'updates a confidential issue for author', :aggregate_failures do
put api(confidential_issue_path, author), params: { title: updated_title }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(updated_title)
end
- it 'updates a confidential issue for admin' do
- put api(confidential_issue_path, admin), params: { title: updated_title }
+ it 'updates a confidential issue for admin', :aggregate_failures do
+ put api(confidential_issue_path, admin, admin_mode: true), params: { title: updated_title }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(updated_title)
end
- it 'sets an issue to confidential' do
+ it 'sets an issue to confidential', :aggregate_failures do
put api_for_user, params: { confidential: true }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be_truthy
end
- it 'makes a confidential issue public' do
+ it 'makes a confidential issue public', :aggregate_failures do
put api(confidential_issue_path, user), params: { confidential: false }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be_falsy
end
- it 'does not update a confidential issue with wrong confidential flag' do
+ it 'does not update a confidential issue with wrong confidential flag', :aggregate_failures do
put api(confidential_issue_path, user), params: { confidential: 'foo' }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -209,7 +209,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect { update_issue }.not_to change { issue.reload.title }
end
- it 'returns correct status and message' do
+ it 'returns correct status and message', :aggregate_failures do
update_issue
expect(response).to have_gitlab_http_status(:bad_request)
@@ -246,14 +246,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do
describe 'PUT /projects/:id/issues/:issue_iid to update assignee' do
context 'support for deprecated assignee_id' do
- it 'removes assignee' do
+ it 'removes assignee', :aggregate_failures do
put api_for_user, params: { assignee_id: 0 }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['assignee']).to be_nil
end
- it 'updates an issue with new assignee' do
+ it 'updates an issue with new assignee', :aggregate_failures do
put api_for_user, params: { assignee_id: user2.id }
expect(response).to have_gitlab_http_status(:ok)
@@ -261,21 +261,21 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'removes assignee' do
+ it 'removes assignee', :aggregate_failures do
put api_for_user, params: { assignee_ids: [0] }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['assignees']).to be_empty
end
- it 'updates an issue with new assignee' do
+ it 'updates an issue with new assignee', :aggregate_failures do
put api_for_user, params: { assignee_ids: [user2.id] }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['assignees'].first['name']).to eq(user2.name)
end
- context 'single assignee restrictions' do
+ context 'single assignee restrictions', :aggregate_failures do
it 'updates an issue with several assignees but only one has been applied' do
put api_for_user, params: { assignee_ids: [user2.id, guest.id] }
@@ -289,7 +289,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let!(:label) { create(:label, title: 'dummy', project: project) }
let!(:label_link) { create(:label_link, label: label, target: issue) }
- it 'adds relevant labels' do
+ it 'adds relevant labels', :aggregate_failures do
put api_for_user, params: { add_labels: '1, 2' }
expect(response).to have_gitlab_http_status(:ok)
@@ -300,14 +300,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let!(:label2) { create(:label, title: 'a-label', project: project) }
let!(:label_link2) { create(:label_link, label: label2, target: issue) }
- it 'removes relevant labels' do
+ it 'removes relevant labels', :aggregate_failures do
put api_for_user, params: { remove_labels: label2.title }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['labels']).to eq([label.title])
end
- it 'removes all labels' do
+ it 'removes all labels', :aggregate_failures do
put api_for_user, params: { remove_labels: "#{label.title}, #{label2.title}" }
expect(response).to have_gitlab_http_status(:ok)
@@ -315,14 +315,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
end
- it 'does not update labels if not present' do
+ it 'does not update labels if not present', :aggregate_failures do
put api_for_user, params: { title: updated_title }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['labels']).to eq([label.title])
end
- it 'removes all labels and touches the record' do
+ it 'removes all labels and touches the record', :aggregate_failures do
travel_to(2.minutes.from_now) do
put api_for_user, params: { labels: '' }
end
@@ -332,7 +332,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['updated_at']).to be > Time.current
end
- it 'removes all labels and touches the record with labels param as array' do
+ it 'removes all labels and touches the record with labels param as array', :aggregate_failures do
travel_to(2.minutes.from_now) do
put api_for_user, params: { labels: [''] }
end
@@ -342,7 +342,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['updated_at']).to be > Time.current
end
- it 'updates labels and touches the record' do
+ it 'updates labels and touches the record', :aggregate_failures do
travel_to(2.minutes.from_now) do
put api_for_user, params: { labels: 'foo,bar' }
end
@@ -352,7 +352,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['updated_at']).to be > Time.current
end
- it 'updates labels and touches the record with labels param as array' do
+ it 'updates labels and touches the record with labels param as array', :aggregate_failures do
travel_to(2.minutes.from_now) do
put api_for_user, params: { labels: %w(foo bar) }
end
@@ -363,21 +363,21 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['updated_at']).to be > Time.current
end
- it 'allows special label names' do
+ it 'allows special label names', :aggregate_failures do
put api_for_user, params: { labels: 'label:foo, label-bar,label_bar,label/bar,label?bar,label&bar,?,&' }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['labels']).to contain_exactly('label:foo', 'label-bar', 'label_bar', 'label/bar', 'label?bar', 'label&bar', '?', '&')
end
- it 'allows special label names with labels param as array' do
+ it 'allows special label names with labels param as array', :aggregate_failures do
put api_for_user, params: { labels: ['label:foo', 'label-bar', 'label_bar', 'label/bar,label?bar,label&bar,?,&'] }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['labels']).to contain_exactly('label:foo', 'label-bar', 'label_bar', 'label/bar', 'label?bar', 'label&bar', '?', '&')
end
- it 'returns 400 if title is too long' do
+ it 'returns 400 if title is too long', :aggregate_failures do
put api_for_user, params: { title: 'g' * 256 }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -386,7 +386,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
describe 'PUT /projects/:id/issues/:issue_iid to update state and label' do
- it 'updates a project issue' do
+ it 'updates a project issue', :aggregate_failures do
put api_for_user, params: { labels: 'label2', state_event: 'close' }
expect(response).to have_gitlab_http_status(:ok)
@@ -394,7 +394,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(json_response['state']).to eq 'closed'
end
- it 'reopens a project isssue' do
+ it 'reopens a project isssue', :aggregate_failures do
put api(issue_path, user), params: { state_event: 'reopen' }
expect(response).to have_gitlab_http_status(:ok)
@@ -404,7 +404,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
describe 'PUT /projects/:id/issues/:issue_iid to update updated_at param' do
context 'when reporter makes request' do
- it 'accepts the update date to be set' do
+ it 'accepts the update date to be set', :aggregate_failures do
update_time = 2.weeks.ago
put api_for_user, params: { title: 'some new title', updated_at: update_time }
@@ -436,7 +436,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'accepts the update date to be set' do
+ it 'accepts the update date to be set', :aggregate_failures do
update_time = 2.weeks.ago
put api_for_owner, params: { title: 'some new title', updated_at: update_time }
@@ -448,7 +448,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
describe 'PUT /projects/:id/issues/:issue_iid to update due date' do
- it 'creates a new project issue' do
+ it 'creates a new project issue', :aggregate_failures do
due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
put api_for_user, params: { due_date: due_date }
diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb
index d9a0f061156..0ca1a7d030f 100644
--- a/spec/requests/api/keys_spec.rb
+++ b/spec/requests/api/keys_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Keys, feature_category: :authentication_and_authorization do
+RSpec.describe API::Keys, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
let_it_be(:email) { create(:email, user: user) }
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index 82b87007a9b..3f131862a41 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Lint, feature_category: :pipeline_authoring do
+RSpec.describe API::Lint, feature_category: :pipeline_composition do
describe 'POST /ci/lint' do
context 'when signup settings are disabled' do
before do
@@ -245,8 +245,8 @@ RSpec.describe API::Lint, feature_category: :pipeline_authoring do
it 'passes validation' do
ci_lint
- included_config = YAML.safe_load(included_content, [Symbol])
- root_config = YAML.safe_load(yaml_content, [Symbol])
+ included_config = YAML.safe_load(included_content, permitted_classes: [Symbol])
+ root_config = YAML.safe_load(yaml_content, permitted_classes: [Symbol])
expected_yaml = included_config.merge(root_config).except(:include).deep_stringify_keys.to_yaml
expect(response).to have_gitlab_http_status(:ok)
@@ -535,8 +535,8 @@ RSpec.describe API::Lint, feature_category: :pipeline_authoring do
it 'passes validation' do
ci_lint
- included_config = YAML.safe_load(included_content, [Symbol])
- root_config = YAML.safe_load(yaml_content, [Symbol])
+ included_config = YAML.safe_load(included_content, permitted_classes: [Symbol])
+ root_config = YAML.safe_load(yaml_content, permitted_classes: [Symbol])
expected_yaml = included_config.merge(root_config).except(:include).deep_stringify_keys.to_yaml
expect(response).to have_gitlab_http_status(:ok)
diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb
index 20aa660d95b..7b850fed79c 100644
--- a/spec/requests/api/maven_packages_spec.rb
+++ b/spec/requests/api/maven_packages_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token_for_group, group: group) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_maven_user' } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_maven_user' } }
let(:package_name) { 'com/example/my-app' }
let(:headers) { workhorse_headers }
@@ -285,6 +285,8 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
describe 'GET /api/v4/packages/maven/*path/:file_name' do
context 'a public project' do
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_maven_user' } }
+
subject { download_file(file_name: package_file.file_name) }
shared_examples 'getting a file' do
@@ -451,6 +453,8 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
it_behaves_like 'forwarding package requests'
context 'a public project' do
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_maven_user' } }
+
subject { download_file(file_name: package_file.file_name) }
shared_examples 'getting a file for a group' do
@@ -660,6 +664,8 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
describe 'GET /api/v4/projects/:id/packages/maven/*path/:file_name' do
context 'a public project' do
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_maven_user' } }
+
subject { download_file(file_name: package_file.file_name) }
it_behaves_like 'tracking the file download event'
@@ -901,8 +907,6 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
it_behaves_like 'package workhorse uploads'
context 'event tracking' do
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_maven_user' } }
-
it_behaves_like 'a package tracking event', described_class.name, 'push_package'
context 'when the package file fails to be created' do
@@ -962,6 +966,17 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
expect(response).to have_gitlab_http_status(:forbidden)
end
+ context 'file name is too long' do
+ let(:file_name) { 'a' * (Packages::Maven::FindOrCreatePackageService::MAX_FILE_NAME_LENGTH + 1) }
+
+ it 'rejects request' do
+ expect { upload_file_with_token(params: params, file_name: file_name) }.not_to change { project.packages.count }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to include('File name is too long')
+ end
+ end
+
context 'version is not correct' do
let(:version) { '$%123' }
@@ -981,9 +996,9 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
package_settings.update!(maven_duplicates_allowed: false)
end
- shared_examples 'storing the package file' do
+ shared_examples 'storing the package file' do |file_name: 'my-app-1.0-20180724.124855-1'|
it 'stores the file', :aggregate_failures do
- expect { upload_file_with_token(params: params) }.to change { package.package_files.count }.by(1)
+ expect { upload_file_with_token(params: params, file_name: file_name) }.to change { package.package_files.count }.by(1)
expect(response).to have_gitlab_http_status(:ok)
expect(jar_file.file_name).to eq(file_upload.original_filename)
@@ -1023,6 +1038,10 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
it_behaves_like 'storing the package file'
end
+
+ context 'when uploading a similar package file name with a classifier' do
+ it_behaves_like 'storing the package file', file_name: 'my-app-1.0-20180724.124855-1-javadoc'
+ end
end
context 'for sha1 file' do
@@ -1088,8 +1107,8 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
end
end
- def upload_file(params: {}, request_headers: headers, file_extension: 'jar')
- url = "/projects/#{project.id}/packages/maven/#{param_path}/my-app-1.0-20180724.124855-1.#{file_extension}"
+ def upload_file(params: {}, request_headers: headers, file_extension: 'jar', file_name: 'my-app-1.0-20180724.124855-1')
+ url = "/projects/#{project.id}/packages/maven/#{param_path}/#{file_name}.#{file_extension}"
workhorse_finalize(
api(url),
method: :put,
@@ -1100,8 +1119,8 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do
)
end
- def upload_file_with_token(params: {}, request_headers: headers_with_token, file_extension: 'jar')
- upload_file(params: params, request_headers: request_headers, file_extension: file_extension)
+ def upload_file_with_token(params: {}, request_headers: headers_with_token, file_extension: 'jar', file_name: 'my-app-1.0-20180724.124855-1')
+ upload_file(params: params, request_headers: request_headers, file_name: file_name, file_extension: file_extension)
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 19a630e5218..81815fdab62 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -168,6 +168,17 @@ RSpec.describe API::MergeRequests, feature_category: :source_code_management do
end
end
+ context 'when DB timeouts occur' do
+ it 'returns a :request_timeout status' do
+ allow(MergeRequestsFinder).to receive(:new).and_raise(ActiveRecord::QueryCanceled)
+
+ path = endpoint_path + '?view=simple'
+ get api(path, user)
+
+ expect(response).to have_gitlab_http_status(:request_timeout)
+ end
+ end
+
it 'returns an array of all merge_requests using simple mode' do
path = endpoint_path + '?view=simple'
diff --git a/spec/requests/api/metadata_spec.rb b/spec/requests/api/metadata_spec.rb
index b9bdadb01cc..e15186c48a5 100644
--- a/spec/requests/api/metadata_spec.rb
+++ b/spec/requests/api/metadata_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Metadata, feature_category: :not_owned do
+RSpec.describe API::Metadata, feature_category: :shared do
shared_examples_for 'GET /metadata' do
context 'when unauthenticated' do
it 'returns authentication error' do
diff --git a/spec/requests/api/npm_instance_packages_spec.rb b/spec/requests/api/npm_instance_packages_spec.rb
index dcd2e4ae677..591a8ee68dc 100644
--- a/spec/requests/api/npm_instance_packages_spec.rb
+++ b/spec/requests/api/npm_instance_packages_spec.rb
@@ -11,8 +11,38 @@ RSpec.describe API::NpmInstancePackages, feature_category: :package_registry do
include_context 'npm api setup'
describe 'GET /api/v4/packages/npm/*package_name' do
- it_behaves_like 'handling get metadata requests', scope: :instance do
- let(:url) { api("/packages/npm/#{package_name}") }
+ let(:url) { api("/packages/npm/#{package_name}") }
+
+ it_behaves_like 'handling get metadata requests', scope: :instance
+
+ context 'with a duplicate package name in another project' do
+ subject { get(url) }
+
+ 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
end
diff --git a/spec/requests/api/npm_project_packages_spec.rb b/spec/requests/api/npm_project_packages_spec.rb
index c62c0849776..2f67e1e8eea 100644
--- a/spec/requests/api/npm_project_packages_spec.rb
+++ b/spec/requests/api/npm_project_packages_spec.rb
@@ -115,6 +115,8 @@ RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do
end
context 'private project' do
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_npm_user' } }
+
before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end
@@ -143,6 +145,8 @@ RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do
end
context 'internal project' do
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_npm_user' } }
+
before do
project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
end
diff --git a/spec/requests/api/nuget_group_packages_spec.rb b/spec/requests/api/nuget_group_packages_spec.rb
index 4335ad75ab6..facbc01220d 100644
--- a/spec/requests/api/nuget_group_packages_spec.rb
+++ b/spec/requests/api/nuget_group_packages_spec.rb
@@ -12,8 +12,17 @@ RSpec.describe API::NugetGroupPackages, feature_category: :package_registry do
let_it_be(:deploy_token) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token, group: group) }
- let(:snowplow_gitlab_standard_context) { { namespace: project.group, property: 'i_package_nuget_user' } }
let(:target_type) { 'groups' }
+ let(:snowplow_gitlab_standard_context) { snowplow_context }
+ let(:target) { subgroup }
+
+ def snowplow_context(user_role: :developer)
+ if user_role == :anonymous
+ { namespace: target, property: 'i_package_nuget_user' }
+ else
+ { namespace: target, property: 'i_package_nuget_user', user: user }
+ end
+ end
shared_examples 'handling all endpoints' do
describe 'GET /api/v4/groups/:id/-/packages/nuget' do
@@ -84,7 +93,6 @@ RSpec.describe API::NugetGroupPackages, feature_category: :package_registry do
context 'a group' do
let(:target) { group }
- let(:snowplow_gitlab_standard_context) { { namespace: target, property: 'i_package_nuget_user' } }
it_behaves_like 'handling all endpoints'
diff --git a/spec/requests/api/nuget_project_packages_spec.rb b/spec/requests/api/nuget_project_packages_spec.rb
index 1e0d35ad451..887dfd4beeb 100644
--- a/spec/requests/api/nuget_project_packages_spec.rb
+++ b/spec/requests/api/nuget_project_packages_spec.rb
@@ -13,7 +13,15 @@ RSpec.describe API::NugetProjectPackages, feature_category: :package_registry do
let(:target) { project }
let(:target_type) { 'projects' }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_nuget_user' } }
+ let(:snowplow_gitlab_standard_context) { snowplow_context }
+
+ def snowplow_context(user_role: :developer)
+ if user_role == :anonymous
+ { project: target, namespace: target.namespace, property: 'i_package_nuget_user' }
+ else
+ { project: target, namespace: target.namespace, property: 'i_package_nuget_user', user: user }
+ end
+ end
shared_examples 'accept get request on private project with access to package registry for everyone' do
subject { get api(url) }
@@ -149,6 +157,7 @@ RSpec.describe API::NugetProjectPackages, feature_category: :package_registry do
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
subject { get api(url), headers: headers }
diff --git a/spec/requests/api/oauth_tokens_spec.rb b/spec/requests/api/oauth_tokens_spec.rb
index b29f1e9e661..19a943477d2 100644
--- a/spec/requests/api/oauth_tokens_spec.rb
+++ b/spec/requests/api/oauth_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'OAuth tokens', feature_category: :authentication_and_authorization do
+RSpec.describe 'OAuth tokens', feature_category: :system_access do
include HttpBasicAuthHelpers
context 'Resource Owner Password Credentials' do
@@ -124,6 +124,8 @@ RSpec.describe 'OAuth tokens', feature_category: :authentication_and_authorizati
context 'when user account is not confirmed' do
before do
+ stub_application_setting_enum('email_confirmation_setting', 'soft')
+
user.update!(confirmed_at: nil)
request_oauth_token(user, client_basic_auth_header(client))
diff --git a/spec/requests/api/pages/internal_access_spec.rb b/spec/requests/api/pages/internal_access_spec.rb
index fdc25ecdcd3..3e7837866ae 100644
--- a/spec/requests/api/pages/internal_access_spec.rb
+++ b/spec/requests/api/pages/internal_access_spec.rb
@@ -35,39 +35,39 @@ RSpec.describe "Internal Project Pages Access", feature_category: :pages do
describe "GET /projects/:id/pages_access" do
context 'access depends on the level' do
- where(:pages_access_level, :with_user, :expected_result) do
- ProjectFeature::DISABLED | "admin" | 403
- ProjectFeature::DISABLED | "owner" | 403
- ProjectFeature::DISABLED | "master" | 403
- ProjectFeature::DISABLED | "developer" | 403
- ProjectFeature::DISABLED | "reporter" | 403
- ProjectFeature::DISABLED | "guest" | 403
- ProjectFeature::DISABLED | "user" | 403
- ProjectFeature::DISABLED | nil | 404
- ProjectFeature::PUBLIC | "admin" | 200
- ProjectFeature::PUBLIC | "owner" | 200
- ProjectFeature::PUBLIC | "master" | 200
- ProjectFeature::PUBLIC | "developer" | 200
- ProjectFeature::PUBLIC | "reporter" | 200
- ProjectFeature::PUBLIC | "guest" | 200
- ProjectFeature::PUBLIC | "user" | 200
- ProjectFeature::PUBLIC | nil | 404
- ProjectFeature::ENABLED | "admin" | 200
- ProjectFeature::ENABLED | "owner" | 200
- ProjectFeature::ENABLED | "master" | 200
- ProjectFeature::ENABLED | "developer" | 200
- ProjectFeature::ENABLED | "reporter" | 200
- ProjectFeature::ENABLED | "guest" | 200
- ProjectFeature::ENABLED | "user" | 200
- ProjectFeature::ENABLED | nil | 404
- ProjectFeature::PRIVATE | "admin" | 200
- ProjectFeature::PRIVATE | "owner" | 200
- ProjectFeature::PRIVATE | "master" | 200
- ProjectFeature::PRIVATE | "developer" | 200
- ProjectFeature::PRIVATE | "reporter" | 200
- ProjectFeature::PRIVATE | "guest" | 200
- ProjectFeature::PRIVATE | "user" | 403
- ProjectFeature::PRIVATE | nil | 404
+ where(:pages_access_level, :with_user, :admin_mode, :expected_result) do
+ ProjectFeature::DISABLED | "admin" | true | 403
+ ProjectFeature::DISABLED | "owner" | false | 403
+ ProjectFeature::DISABLED | "master" | false | 403
+ ProjectFeature::DISABLED | "developer" | false | 403
+ ProjectFeature::DISABLED | "reporter" | false | 403
+ ProjectFeature::DISABLED | "guest" | false | 403
+ ProjectFeature::DISABLED | "user" | false | 403
+ ProjectFeature::DISABLED | nil | false | 404
+ ProjectFeature::PUBLIC | "admin" | false | 200
+ ProjectFeature::PUBLIC | "owner" | false | 200
+ ProjectFeature::PUBLIC | "master" | false | 200
+ ProjectFeature::PUBLIC | "developer" | false | 200
+ ProjectFeature::PUBLIC | "reporter" | false | 200
+ ProjectFeature::PUBLIC | "guest" | false | 200
+ ProjectFeature::PUBLIC | "user" | false | 200
+ ProjectFeature::PUBLIC | nil | false | 404
+ ProjectFeature::ENABLED | "admin" | false | 200
+ ProjectFeature::ENABLED | "owner" | false | 200
+ ProjectFeature::ENABLED | "master" | false | 200
+ ProjectFeature::ENABLED | "developer" | false | 200
+ ProjectFeature::ENABLED | "reporter" | false | 200
+ ProjectFeature::ENABLED | "guest" | false | 200
+ ProjectFeature::ENABLED | "user" | false | 200
+ ProjectFeature::ENABLED | nil | false | 404
+ ProjectFeature::PRIVATE | "admin" | true | 200
+ ProjectFeature::PRIVATE | "owner" | false | 200
+ ProjectFeature::PRIVATE | "master" | false | 200
+ ProjectFeature::PRIVATE | "developer" | false | 200
+ ProjectFeature::PRIVATE | "reporter" | false | 200
+ ProjectFeature::PRIVATE | "guest" | false | 200
+ ProjectFeature::PRIVATE | "user" | false | 403
+ ProjectFeature::PRIVATE | nil | false | 404
end
with_them do
@@ -77,7 +77,7 @@ RSpec.describe "Internal Project Pages Access", feature_category: :pages do
it "correct return value" do
if !with_user.nil?
user = public_send(with_user)
- get api("/projects/#{project.id}/pages_access", user)
+ get api("/projects/#{project.id}/pages_access", user, admin_mode: admin_mode)
else
get api("/projects/#{project.id}/pages_access")
end
diff --git a/spec/requests/api/pages/pages_spec.rb b/spec/requests/api/pages/pages_spec.rb
index c426f2a433c..0f6675799ad 100644
--- a/spec/requests/api/pages/pages_spec.rb
+++ b/spec/requests/api/pages/pages_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe API::Pages, feature_category: :pages do
- let_it_be(:project) { create(:project, path: 'my.project', pages_https_only: false) }
+ let_it_be_with_reload(:project) { create(:project, path: 'my.project', pages_https_only: false) }
let_it_be(:admin) { create(:admin) }
let_it_be(:user) { create(:user) }
@@ -19,7 +19,7 @@ RSpec.describe API::Pages, feature_category: :pages do
end
it_behaves_like '404 response' do
- let(:request) { delete api("/projects/#{project.id}/pages", admin) }
+ let(:request) { delete api("/projects/#{project.id}/pages", admin, admin_mode: true) }
end
end
@@ -30,13 +30,13 @@ RSpec.describe API::Pages, feature_category: :pages do
context 'when Pages are deployed' do
it 'returns 204' do
- delete api("/projects/#{project.id}/pages", admin)
+ delete api("/projects/#{project.id}/pages", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:no_content)
end
it 'removes the pages' do
- delete api("/projects/#{project.id}/pages", admin)
+ delete api("/projects/#{project.id}/pages", admin, admin_mode: true)
expect(project.reload.pages_metadatum.deployed?).to be(false)
end
@@ -48,7 +48,7 @@ RSpec.describe API::Pages, feature_category: :pages do
end
it 'returns 204' do
- delete api("/projects/#{project.id}/pages", admin)
+ delete api("/projects/#{project.id}/pages", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:no_content)
end
@@ -58,7 +58,7 @@ RSpec.describe API::Pages, feature_category: :pages do
it 'returns 404' do
id = -1
- delete api("/projects/#{id}/pages", admin)
+ delete api("/projects/#{id}/pages", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:not_found)
end
diff --git a/spec/requests/api/pages/private_access_spec.rb b/spec/requests/api/pages/private_access_spec.rb
index 5cc1b8f9a69..602eff73b0a 100644
--- a/spec/requests/api/pages/private_access_spec.rb
+++ b/spec/requests/api/pages/private_access_spec.rb
@@ -35,39 +35,39 @@ RSpec.describe "Private Project Pages Access", feature_category: :pages do
describe "GET /projects/:id/pages_access" do
context 'access depends on the level' do
- where(:pages_access_level, :with_user, :expected_result) do
- ProjectFeature::DISABLED | "admin" | 403
- ProjectFeature::DISABLED | "owner" | 403
- ProjectFeature::DISABLED | "master" | 403
- ProjectFeature::DISABLED | "developer" | 403
- ProjectFeature::DISABLED | "reporter" | 403
- ProjectFeature::DISABLED | "guest" | 403
- ProjectFeature::DISABLED | "user" | 404
- ProjectFeature::DISABLED | nil | 404
- ProjectFeature::PUBLIC | "admin" | 200
- ProjectFeature::PUBLIC | "owner" | 200
- ProjectFeature::PUBLIC | "master" | 200
- ProjectFeature::PUBLIC | "developer" | 200
- ProjectFeature::PUBLIC | "reporter" | 200
- ProjectFeature::PUBLIC | "guest" | 200
- ProjectFeature::PUBLIC | "user" | 404
- ProjectFeature::PUBLIC | nil | 404
- ProjectFeature::ENABLED | "admin" | 200
- ProjectFeature::ENABLED | "owner" | 200
- ProjectFeature::ENABLED | "master" | 200
- ProjectFeature::ENABLED | "developer" | 200
- ProjectFeature::ENABLED | "reporter" | 200
- ProjectFeature::ENABLED | "guest" | 200
- ProjectFeature::ENABLED | "user" | 404
- ProjectFeature::ENABLED | nil | 404
- ProjectFeature::PRIVATE | "admin" | 200
- ProjectFeature::PRIVATE | "owner" | 200
- ProjectFeature::PRIVATE | "master" | 200
- ProjectFeature::PRIVATE | "developer" | 200
- ProjectFeature::PRIVATE | "reporter" | 200
- ProjectFeature::PRIVATE | "guest" | 200
- ProjectFeature::PRIVATE | "user" | 404
- ProjectFeature::PRIVATE | nil | 404
+ where(:pages_access_level, :with_user, :admin_mode, :expected_result) do
+ ProjectFeature::DISABLED | "admin" | true | 403
+ ProjectFeature::DISABLED | "owner" | false | 403
+ ProjectFeature::DISABLED | "master" | false | 403
+ ProjectFeature::DISABLED | "developer" | false | 403
+ ProjectFeature::DISABLED | "reporter" | false | 403
+ ProjectFeature::DISABLED | "guest" | false | 403
+ ProjectFeature::DISABLED | "user" | false | 404
+ ProjectFeature::DISABLED | nil | false | 404
+ ProjectFeature::PUBLIC | "admin" | true | 200
+ ProjectFeature::PUBLIC | "owner" | false | 200
+ ProjectFeature::PUBLIC | "master" | false | 200
+ ProjectFeature::PUBLIC | "developer" | false | 200
+ ProjectFeature::PUBLIC | "reporter" | false | 200
+ ProjectFeature::PUBLIC | "guest" | false | 200
+ ProjectFeature::PUBLIC | "user" | false | 404
+ ProjectFeature::PUBLIC | nil | false | 404
+ ProjectFeature::ENABLED | "admin" | true | 200
+ ProjectFeature::ENABLED | "owner" | false | 200
+ ProjectFeature::ENABLED | "master" | false | 200
+ ProjectFeature::ENABLED | "developer" | false | 200
+ ProjectFeature::ENABLED | "reporter" | false | 200
+ ProjectFeature::ENABLED | "guest" | false | 200
+ ProjectFeature::ENABLED | "user" | false | 404
+ ProjectFeature::ENABLED | nil | false | 404
+ ProjectFeature::PRIVATE | "admin" | true | 200
+ ProjectFeature::PRIVATE | "owner" | false | 200
+ ProjectFeature::PRIVATE | "master" | false | 200
+ ProjectFeature::PRIVATE | "developer" | false | 200
+ ProjectFeature::PRIVATE | "reporter" | false | 200
+ ProjectFeature::PRIVATE | "guest" | false | 200
+ ProjectFeature::PRIVATE | "user" | false | 404
+ ProjectFeature::PRIVATE | nil | false | 404
end
with_them do
@@ -77,7 +77,7 @@ RSpec.describe "Private Project Pages Access", feature_category: :pages do
it "correct return value" do
if !with_user.nil?
user = public_send(with_user)
- get api("/projects/#{project.id}/pages_access", user)
+ get api("/projects/#{project.id}/pages_access", user, admin_mode: admin_mode)
else
get api("/projects/#{project.id}/pages_access")
end
diff --git a/spec/requests/api/pages/public_access_spec.rb b/spec/requests/api/pages/public_access_spec.rb
index 1137f91f4b0..8b0ed7c59ab 100644
--- a/spec/requests/api/pages/public_access_spec.rb
+++ b/spec/requests/api/pages/public_access_spec.rb
@@ -35,39 +35,39 @@ RSpec.describe "Public Project Pages Access", feature_category: :pages do
describe "GET /projects/:id/pages_access" do
context 'access depends on the level' do
- where(:pages_access_level, :with_user, :expected_result) do
- ProjectFeature::DISABLED | "admin" | 403
- ProjectFeature::DISABLED | "owner" | 403
- ProjectFeature::DISABLED | "master" | 403
- ProjectFeature::DISABLED | "developer" | 403
- ProjectFeature::DISABLED | "reporter" | 403
- ProjectFeature::DISABLED | "guest" | 403
- ProjectFeature::DISABLED | "user" | 403
- ProjectFeature::DISABLED | nil | 403
- ProjectFeature::PUBLIC | "admin" | 200
- ProjectFeature::PUBLIC | "owner" | 200
- ProjectFeature::PUBLIC | "master" | 200
- ProjectFeature::PUBLIC | "developer" | 200
- ProjectFeature::PUBLIC | "reporter" | 200
- ProjectFeature::PUBLIC | "guest" | 200
- ProjectFeature::PUBLIC | "user" | 200
- ProjectFeature::PUBLIC | nil | 200
- ProjectFeature::ENABLED | "admin" | 200
- ProjectFeature::ENABLED | "owner" | 200
- ProjectFeature::ENABLED | "master" | 200
- ProjectFeature::ENABLED | "developer" | 200
- ProjectFeature::ENABLED | "reporter" | 200
- ProjectFeature::ENABLED | "guest" | 200
- ProjectFeature::ENABLED | "user" | 200
- ProjectFeature::ENABLED | nil | 200
- ProjectFeature::PRIVATE | "admin" | 200
- ProjectFeature::PRIVATE | "owner" | 200
- ProjectFeature::PRIVATE | "master" | 200
- ProjectFeature::PRIVATE | "developer" | 200
- ProjectFeature::PRIVATE | "reporter" | 200
- ProjectFeature::PRIVATE | "guest" | 200
- ProjectFeature::PRIVATE | "user" | 403
- ProjectFeature::PRIVATE | nil | 403
+ where(:pages_access_level, :with_user, :admin_mode, :expected_result) do
+ ProjectFeature::DISABLED | "admin" | false | 403
+ ProjectFeature::DISABLED | "owner" | false | 403
+ ProjectFeature::DISABLED | "master" | false | 403
+ ProjectFeature::DISABLED | "developer" | false | 403
+ ProjectFeature::DISABLED | "reporter" | false | 403
+ ProjectFeature::DISABLED | "guest" | false | 403
+ ProjectFeature::DISABLED | "user" | false | 403
+ ProjectFeature::DISABLED | nil | false | 403
+ ProjectFeature::PUBLIC | "admin" | false | 200
+ ProjectFeature::PUBLIC | "owner" | false | 200
+ ProjectFeature::PUBLIC | "master" | false | 200
+ ProjectFeature::PUBLIC | "developer" | false | 200
+ ProjectFeature::PUBLIC | "reporter" | false | 200
+ ProjectFeature::PUBLIC | "guest" | false | 200
+ ProjectFeature::PUBLIC | "user" | false | 200
+ ProjectFeature::PUBLIC | nil | false | 200
+ ProjectFeature::ENABLED | "admin" | false | 200
+ ProjectFeature::ENABLED | "owner" | false | 200
+ ProjectFeature::ENABLED | "master" | false | 200
+ ProjectFeature::ENABLED | "developer" | false | 200
+ ProjectFeature::ENABLED | "reporter" | false | 200
+ ProjectFeature::ENABLED | "guest" | false | 200
+ ProjectFeature::ENABLED | "user" | false | 200
+ ProjectFeature::ENABLED | nil | false | 200
+ ProjectFeature::PRIVATE | "admin" | true | 200
+ ProjectFeature::PRIVATE | "owner" | false | 200
+ ProjectFeature::PRIVATE | "master" | false | 200
+ ProjectFeature::PRIVATE | "developer" | false | 200
+ ProjectFeature::PRIVATE | "reporter" | false | 200
+ ProjectFeature::PRIVATE | "guest" | false | 200
+ ProjectFeature::PRIVATE | "user" | false | 403
+ ProjectFeature::PRIVATE | nil | false | 403
end
with_them do
@@ -77,7 +77,7 @@ RSpec.describe "Public Project Pages Access", feature_category: :pages do
it "correct return value" do
if !with_user.nil?
user = public_send(with_user)
- get api("/projects/#{project.id}/pages_access", user)
+ get api("/projects/#{project.id}/pages_access", user, admin_mode: admin_mode)
else
get api("/projects/#{project.id}/pages_access")
end
diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb
index ba1fb5105b8..ea83fa384af 100644
--- a/spec/requests/api/pages_domains_spec.rb
+++ b/spec/requests/api/pages_domains_spec.rb
@@ -41,14 +41,14 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
end
it_behaves_like '404 response' do
- let(:request) { get api('/pages/domains', admin) }
+ let(:request) { get api('/pages/domains', admin, admin_mode: true) }
end
end
context 'when pages is enabled' do
context 'when authenticated as an admin' do
- it 'returns paginated all pages domains' do
- get api('/pages/domains', admin)
+ it 'returns paginated all pages domains', :aggregate_failures do
+ get api('/pages/domains', admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/pages_domain_basics')
@@ -74,7 +74,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
describe 'GET /projects/:project_id/pages/domains' do
shared_examples_for 'get pages domains' do
- it 'returns paginated pages domains' do
+ it 'returns paginated pages domains', :aggregate_failures do
get api(route, user)
expect(response).to have_gitlab_http_status(:ok)
@@ -145,7 +145,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
describe 'GET /projects/:project_id/pages/domains/:domain' do
shared_examples_for 'get pages domain' do
- it 'returns pages domain' do
+ it 'returns pages domain', :aggregate_failures do
get api(route_domain, user)
expect(response).to have_gitlab_http_status(:ok)
@@ -155,7 +155,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(json_response['certificate']).to be_nil
end
- it 'returns pages domain with project path' do
+ it 'returns pages domain with project path', :aggregate_failures do
get api(route_domain_path, user)
expect(response).to have_gitlab_http_status(:ok)
@@ -165,7 +165,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(json_response['certificate']).to be_nil
end
- it 'returns pages domain with a certificate' do
+ it 'returns pages domain with a certificate', :aggregate_failures do
get api(route_secure_domain, user)
expect(response).to have_gitlab_http_status(:ok)
@@ -177,7 +177,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(json_response['auto_ssl_enabled']).to be false
end
- it 'returns pages domain with an expired certificate' do
+ it 'returns pages domain with an expired certificate', :aggregate_failures do
get api(route_expired_domain, user)
expect(response).to have_gitlab_http_status(:ok)
@@ -185,7 +185,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(json_response['certificate']['expired']).to be true
end
- it 'returns pages domain with letsencrypt' do
+ it 'returns pages domain with letsencrypt', :aggregate_failures do
get api(route_letsencrypt_domain, user)
expect(response).to have_gitlab_http_status(:ok)
@@ -258,7 +258,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
let(:params_secure) { pages_domain_secure_params.slice(:domain, :certificate, :key) }
shared_examples_for 'post pages domains' do
- it 'creates a new pages domain' do
+ it 'creates a new pages domain', :aggregate_failures do
expect { post api(route, user), params: params }
.to publish_event(PagesDomains::PagesDomainCreatedEvent)
.with(
@@ -279,7 +279,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(pages_domain.auto_ssl_enabled).to be false
end
- it 'creates a new secure pages domain' do
+ it 'creates a new secure pages domain', :aggregate_failures do
post api(route, user), params: params_secure
pages_domain = PagesDomain.find_by(domain: json_response['domain'])
@@ -291,7 +291,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(pages_domain.auto_ssl_enabled).to be false
end
- it 'creates domain with letsencrypt enabled' do
+ it 'creates domain with letsencrypt enabled', :aggregate_failures do
post api(route, user), params: pages_domain_with_letsencrypt_params
pages_domain = PagesDomain.find_by(domain: json_response['domain'])
@@ -301,7 +301,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(pages_domain.auto_ssl_enabled).to be true
end
- it 'creates domain with letsencrypt enabled and provided certificate' do
+ it 'creates domain with letsencrypt enabled and provided certificate', :aggregate_failures do
post api(route, user), params: params_secure.merge(auto_ssl_enabled: true)
pages_domain = PagesDomain.find_by(domain: json_response['domain'])
@@ -376,7 +376,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
let(:params_secure_nokey) { pages_domain_secure_params.slice(:certificate) }
shared_examples_for 'put pages domain' do
- it 'updates pages domain removing certificate' do
+ it 'updates pages domain removing certificate', :aggregate_failures do
put api(route_secure_domain, user), params: { certificate: nil, key: nil }
pages_domain_secure.reload
@@ -399,7 +399,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
)
end
- it 'updates pages domain adding certificate' do
+ it 'updates pages domain adding certificate', :aggregate_failures do
put api(route_domain, user), params: params_secure
pages_domain.reload
@@ -409,7 +409,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(pages_domain.key).to eq(params_secure[:key])
end
- it 'updates pages domain adding certificate with letsencrypt' do
+ it 'updates pages domain adding certificate with letsencrypt', :aggregate_failures do
put api(route_domain, user), params: params_secure.merge(auto_ssl_enabled: true)
pages_domain.reload
@@ -420,7 +420,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(pages_domain.auto_ssl_enabled).to be true
end
- it 'updates pages domain enabling letsencrypt' do
+ it 'updates pages domain enabling letsencrypt', :aggregate_failures do
put api(route_domain, user), params: { auto_ssl_enabled: true }
pages_domain.reload
@@ -429,7 +429,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(pages_domain.auto_ssl_enabled).to be true
end
- it 'updates pages domain disabling letsencrypt while preserving the certificate' do
+ it 'updates pages domain disabling letsencrypt while preserving the certificate', :aggregate_failures do
put api(route_letsencrypt_domain, user), params: { auto_ssl_enabled: false }
pages_domain_with_letsencrypt.reload
@@ -440,7 +440,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(pages_domain_with_letsencrypt.certificate).to be
end
- it 'updates pages domain with expired certificate' do
+ it 'updates pages domain with expired certificate', :aggregate_failures do
put api(route_expired_domain, user), params: params_secure
pages_domain_expired.reload
@@ -450,7 +450,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do
expect(pages_domain_expired.key).to eq(params_secure[:key])
end
- it 'updates pages domain with expired certificate not updating key' do
+ it 'updates pages domain with expired certificate not updating key', :aggregate_failures do
put api(route_secure_domain, user), params: params_secure_nokey
pages_domain_secure.reload
diff --git a/spec/requests/api/personal_access_tokens/self_information_spec.rb b/spec/requests/api/personal_access_tokens/self_information_spec.rb
index 4a3c0ad8904..2a7af350054 100644
--- a/spec/requests/api/personal_access_tokens/self_information_spec.rb
+++ b/spec/requests/api/personal_access_tokens/self_information_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::PersonalAccessTokens::SelfInformation, feature_category: :authentication_and_authorization do
+RSpec.describe API::PersonalAccessTokens::SelfInformation, feature_category: :system_access do
let(:path) { '/personal_access_tokens/self' }
let(:token) { create(:personal_access_token, user: current_user) }
diff --git a/spec/requests/api/personal_access_tokens_spec.rb b/spec/requests/api/personal_access_tokens_spec.rb
index 32adc7ebd61..cca94c7a012 100644
--- a/spec/requests/api/personal_access_tokens_spec.rb
+++ b/spec/requests/api/personal_access_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::PersonalAccessTokens, feature_category: :authentication_and_authorization do
+RSpec.describe API::PersonalAccessTokens, feature_category: :system_access do
let_it_be(:path) { '/personal_access_tokens' }
describe 'GET /personal_access_tokens' do
diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb
index 9d722e4a445..978ac28ef73 100644
--- a/spec/requests/api/project_milestones_spec.rb
+++ b/spec/requests/api/project_milestones_spec.rb
@@ -6,8 +6,12 @@ RSpec.describe API::ProjectMilestones, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:project) { create(:project, namespace: user.namespace) }
let_it_be(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
- let_it_be(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') }
let_it_be(:route) { "/projects/#{project.id}/milestones" }
+ let_it_be(:milestone) do
+ create(:milestone, project: project, title: 'version2', description: 'open milestone', updated_at: 5.days.ago)
+ end
+
+ let(:params) { {} }
before_all do
project.add_reporter(user)
@@ -15,38 +19,43 @@ RSpec.describe API::ProjectMilestones, feature_category: :team_planning do
it_behaves_like 'group and project milestones', "/projects/:id/milestones"
+ shared_examples 'listing all milestones' do
+ it 'returns correct list of milestones' do
+ get api(route, user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.size).to eq(milestones.size)
+ expect(json_response.map { |entry| entry["id"] }).to match_array(milestones.map(&:id))
+ end
+ end
+
describe 'GET /projects/:id/milestones' do
- context 'when include_parent_milestones is true' do
- let_it_be(:ancestor_group) { create(:group, :private) }
- let_it_be(:group) { create(:group, :private, parent: ancestor_group) }
- let_it_be(:ancestor_group_milestone) { create(:milestone, group: ancestor_group) }
- let_it_be(:group_milestone) { create(:milestone, group: group) }
+ let_it_be(:ancestor_group) { create(:group, :private) }
+ let_it_be(:group) { create(:group, :private, parent: ancestor_group) }
+ let_it_be(:ancestor_group_milestone) { create(:milestone, group: ancestor_group, updated_at: 1.day.ago) }
+ let_it_be(:group_milestone) { create(:milestone, group: group, updated_at: 3.days.ago) }
- let(:params) { { include_parent_milestones: true } }
+ context 'when project parent is a namespace' do
+ let(:milestones) { [milestone, closed_milestone] }
- shared_examples 'listing all milestones' do
- it 'returns correct list of milestones' do
- get api(route, user), params: params
+ it_behaves_like 'listing all milestones'
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.size).to eq(milestones.size)
- expect(json_response.map { |entry| entry["id"] }).to eq(milestones.map(&:id))
- end
+ context 'when include_parent_milestones is true' do
+ let(:params) { { include_parent_milestones: true } }
+
+ it_behaves_like 'listing all milestones'
end
+ end
- context 'when project parent is a namespace' do
- it_behaves_like 'listing all milestones' do
- let(:milestones) { [milestone, closed_milestone] }
- end
+ context 'when project parent is a group' do
+ before_all do
+ project.update!(namespace: group)
end
- context 'when project parent is a group' do
+ context 'when include_parent_milestones is true' do
+ let(:params) { { include_parent_milestones: true } }
let(:milestones) { [group_milestone, ancestor_group_milestone, milestone, closed_milestone] }
- before_all do
- project.update!(namespace: group)
- end
-
it_behaves_like 'listing all milestones'
context 'when iids param is present' do
@@ -64,6 +73,38 @@ RSpec.describe API::ProjectMilestones, feature_category: :team_planning do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ context 'when updated_before param is present' do
+ let(:params) { { updated_before: 12.hours.ago.iso8601, include_parent_milestones: true } }
+
+ it_behaves_like 'listing all milestones' do
+ let(:milestones) { [group_milestone, ancestor_group_milestone, milestone] }
+ end
+ end
+
+ context 'when updated_after param is present' do
+ let(:params) { { updated_after: 2.days.ago.iso8601, include_parent_milestones: true } }
+
+ it_behaves_like 'listing all milestones' do
+ let(:milestones) { [ancestor_group_milestone, closed_milestone] }
+ end
+ end
+ end
+
+ context 'when updated_before param is present' do
+ let(:params) { { updated_before: 12.hours.ago.iso8601 } }
+
+ it_behaves_like 'listing all milestones' do
+ let(:milestones) { [milestone] }
+ end
+ end
+
+ context 'when updated_after param is present' do
+ let(:params) { { updated_after: 2.days.ago.iso8601 } }
+
+ it_behaves_like 'listing all milestones' do
+ let(:milestones) { [closed_milestone] }
+ end
end
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index e78ef2f7630..d755a4231da 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1109,6 +1109,66 @@ RSpec.describe API::Projects, feature_category: :projects do
end.not_to exceed_query_limit(control)
end
end
+
+ context 'rate limiting' do
+ let_it_be(:current_user) { create(:user) }
+
+ shared_examples_for 'does not log request and does not block the request' do
+ specify do
+ request
+ request
+
+ expect(response).not_to have_gitlab_http_status(:too_many_requests)
+ expect(Gitlab::AuthLogger).not_to receive(:error)
+ end
+ end
+
+ before do
+ stub_application_setting(projects_api_rate_limit_unauthenticated: 1)
+ end
+
+ context 'when the user is signed in' do
+ it_behaves_like 'does not log request and does not block the request' do
+ def request
+ get api('/projects', current_user)
+ end
+ end
+ end
+
+ context 'when the user is not signed in' do
+ let_it_be(:current_user) { nil }
+
+ it_behaves_like 'rate limited endpoint', rate_limit_key: :projects_api_rate_limit_unauthenticated do
+ def request
+ get api('/projects', current_user)
+ end
+ end
+ end
+
+ context 'when the feature flag `rate_limit_for_unauthenticated_projects_api_access` is disabled' do
+ before do
+ stub_feature_flags(rate_limit_for_unauthenticated_projects_api_access: false)
+ end
+
+ context 'when the user is not signed in' do
+ let_it_be(:current_user) { nil }
+
+ it_behaves_like 'does not log request and does not block the request' do
+ def request
+ get api('/projects', current_user)
+ end
+ end
+ end
+
+ context 'when the user is signed in' do
+ it_behaves_like 'does not log request and does not block the request' do
+ def request
+ get api('/projects', current_user)
+ end
+ end
+ end
+ end
+ end
end
describe 'POST /projects' do
@@ -2006,19 +2066,6 @@ RSpec.describe API::Projects, feature_category: :projects do
end
end
- context 'with upload size enforcement disabled' do
- before do
- stub_feature_flags(enforce_max_attachment_size_upload_api: false)
- end
-
- it "returns 200" do
- post api("/projects/#{project.id}/uploads/authorize", user), headers: headers
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['MaximumSize']).to eq(1.gigabyte)
- end
- end
-
context 'with no Workhorse headers' do
it "returns 403" do
post api("/projects/#{project.id}/uploads/authorize", user)
@@ -2095,14 +2142,6 @@ RSpec.describe API::Projects, feature_category: :projects do
it_behaves_like 'capped upload attachments', true
end
-
- context 'with upload size enforcement disabled' do
- before do
- stub_feature_flags(enforce_max_attachment_size_upload_api: false)
- end
-
- it_behaves_like 'capped upload attachments', false
- end
end
describe "GET /projects/:id/groups" do
@@ -2228,9 +2267,9 @@ RSpec.describe API::Projects, feature_category: :projects do
end
describe 'GET /project/:id/share_locations' do
- let_it_be(:root_group) { create(:group, :public, name: 'root group') }
- let_it_be(:project_group1) { create(:group, :public, parent: root_group, name: 'group1') }
- let_it_be(:project_group2) { create(:group, :public, parent: root_group, name: 'group2') }
+ let_it_be(:root_group) { create(:group, :public, name: 'root group', path: 'root-group-path') }
+ let_it_be(:project_group1) { create(:group, :public, parent: root_group, name: 'group1', path: 'group-1-path') }
+ let_it_be(:project_group2) { create(:group, :public, parent: root_group, name: 'group2', path: 'group-2-path') }
let_it_be(:project) { create(:project, :private, group: project_group1) }
shared_examples_for 'successful groups response' do
@@ -2280,10 +2319,22 @@ RSpec.describe API::Projects, feature_category: :projects do
end
context 'when searching by group name' do
- let(:params) { { search: 'group1' } }
+ context 'searching by group name' do
+ it_behaves_like 'successful groups response' do
+ let(:params) { { search: 'group1' } }
+ let(:expected_groups) { [project_group1] }
+ end
+ end
- it_behaves_like 'successful groups response' do
- let(:expected_groups) { [project_group1] }
+ context 'searching by full group path' do
+ let_it_be(:project_group2_subgroup) do
+ create(:group, :public, parent: project_group2, name: 'subgroup', path: 'subgroup-path')
+ end
+
+ it_behaves_like 'successful groups response' do
+ let(:params) { { search: 'root-group-path/group-2-path/subgroup-path' } }
+ let(:expected_groups) { [project_group2_subgroup] }
+ end
end
end
end
diff --git a/spec/requests/api/protected_branches_spec.rb b/spec/requests/api/protected_branches_spec.rb
index 8e8a25a8dc2..463893afd13 100644
--- a/spec/requests/api/protected_branches_spec.rb
+++ b/spec/requests/api/protected_branches_spec.rb
@@ -266,6 +266,15 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management
end.to change { protected_branch.reload.allow_force_push }.from(false).to(true)
expect(response).to have_gitlab_http_status(:ok)
end
+
+ context 'when allow_force_push is not set' do
+ it 'responds with a bad request error' do
+ patch api(route, user), params: { allow_force_push: nil }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq 'allow_force_push is empty'
+ end
+ end
end
context 'when returned protected branch is invalid' do
diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb
index 978d4f72a4a..0b2641b062c 100644
--- a/spec/requests/api/pypi_packages_spec.rb
+++ b/spec/requests/api/pypi_packages_spec.rb
@@ -14,10 +14,18 @@ RSpec.describe API::PypiPackages, feature_category: :package_registry do
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_pypi_user' } }
+ let(:snowplow_gitlab_standard_context) { snowplow_context }
let(:headers) { {} }
+ def snowplow_context(user_role: :developer)
+ if user_role == :anonymous
+ { project: project, namespace: project.namespace, property: 'i_package_pypi_user' }
+ else
+ { project: project, namespace: project.namespace, property: 'i_package_pypi_user', user: user }
+ end
+ end
+
context 'simple index API endpoint' do
let_it_be(:package) { create(:pypi_package, project: project) }
let_it_be(:package2) { create(:pypi_package, project: project) }
@@ -26,7 +34,6 @@ RSpec.describe API::PypiPackages, feature_category: :package_registry do
describe 'GET /api/v4/groups/:id/-/packages/pypi/simple' do
let(:url) { "/groups/#{group.id}/-/packages/pypi/simple" }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_pypi_user' } }
it_behaves_like 'pypi simple index API endpoint'
it_behaves_like 'rejects PyPI access with unknown group id'
@@ -82,13 +89,13 @@ RSpec.describe API::PypiPackages, feature_category: :package_registry do
context 'simple package API endpoint' do
let_it_be(:package) { create(:pypi_package, project: project) }
- let(:snowplow_gitlab_standard_context) { { project: nil, namespace: group, property: 'i_package_pypi_user' } }
subject { get api(url), headers: headers }
describe 'GET /api/v4/groups/:id/-/packages/pypi/simple/:package_name' do
let(:package_name) { package.name }
let(:url) { "/groups/#{group.id}/-/packages/pypi/simple/#{package_name}" }
+ let(:snowplow_context) { { project: nil, namespace: project.namespace, property: 'i_package_pypi_user' } }
it_behaves_like 'pypi simple API endpoint'
it_behaves_like 'rejects PyPI access with unknown group id'
@@ -126,7 +133,7 @@ RSpec.describe API::PypiPackages, feature_category: :package_registry do
describe 'GET /api/v4/projects/:id/packages/pypi/simple/:package_name' do
let(:package_name) { package.name }
let(:url) { "/projects/#{project.id}/packages/pypi/simple/#{package_name}" }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_pypi_user' } }
+ let(:snowplow_context) { { project: project, namespace: project.namespace, property: 'i_package_pypi_user' } }
it_behaves_like 'pypi simple API endpoint'
it_behaves_like 'rejects PyPI access with unknown project id'
@@ -242,6 +249,13 @@ RSpec.describe API::PypiPackages, feature_category: :package_registry do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:user_headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
let(:headers) { user_headers.merge(workhorse_headers) }
+ let(:snowplow_gitlab_standard_context) do
+ if user_role == :anonymous || (visibility_level == :public && !user_token)
+ { project: project, namespace: project.namespace, property: 'i_package_pypi_user' }
+ else
+ { project: project, namespace: project.namespace, property: 'i_package_pypi_user', user: user }
+ end
+ end
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
@@ -379,6 +393,14 @@ RSpec.describe API::PypiPackages, feature_category: :package_registry do
let_it_be(:package_name) { 'Dummy-Package' }
let_it_be(:package) { create(:pypi_package, project: project, name: package_name, version: '1.0.0') }
+ let(:snowplow_gitlab_standard_context) do
+ if user_role == :anonymous || (visibility_level == :public && !user_token)
+ { project: project, namespace: project.namespace, property: 'i_package_pypi_user' }
+ else
+ { project: project, namespace: project.namespace, property: 'i_package_pypi_user', user: user }
+ end
+ end
+
subject { get api(url), headers: headers }
describe 'GET /api/v4/groups/:id/-/packages/pypi/files/:sha256/*file_identifier' do
diff --git a/spec/requests/api/release/links_spec.rb b/spec/requests/api/release/links_spec.rb
index 462cc1e3b5d..4b388304621 100644
--- a/spec/requests/api/release/links_spec.rb
+++ b/spec/requests/api/release/links_spec.rb
@@ -377,6 +377,15 @@ RSpec.describe API::Release::Links, feature_category: :release_orchestration do
expect(response).to match_response_schema('release/link')
end
+ context 'when params are invalid' do
+ it 'returns 400 error' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer),
+ params: params.merge(url: 'wrong_url')
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
context 'when using `direct_asset_path`' do
it 'updates the release link' do
put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer),
@@ -534,6 +543,21 @@ RSpec.describe API::Release::Links, feature_category: :release_orchestration do
end
end
+ context 'when destroy process fails' do
+ before do
+ allow_next_instance_of(::Releases::Links::DestroyService) do |service|
+ allow(service).to receive(:execute).and_return(ServiceResponse.error(message: 'error'))
+ end
+ end
+
+ it_behaves_like '400 response' do
+ let(:message) { 'error' }
+ let(:request) do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer)
+ end
+ end
+ end
+
context 'when there are no corresponding release link' do
let!(:release_link) {}
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 555ba2bc978..b146dda5030 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -236,7 +236,6 @@ RSpec.describe API::Repositories, feature_category: :source_code_management do
get api(route, current_user)
expect(response.headers["Cache-Control"]).to eq("max-age=0, private, must-revalidate, no-store, no-cache")
- expect(response.headers["Pragma"]).to eq("no-cache")
expect(response.headers["Expires"]).to eq("Fri, 01 Jan 1990 00:00:00 GMT")
end
diff --git a/spec/requests/api/resource_access_tokens_spec.rb b/spec/requests/api/resource_access_tokens_spec.rb
index 6a89e9a56df..9277fa18219 100644
--- a/spec/requests/api/resource_access_tokens_spec.rb
+++ b/spec/requests/api/resource_access_tokens_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe API::ResourceAccessTokens, feature_category: :authentication_and_authorization do
+RSpec.describe API::ResourceAccessTokens, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:user_non_priviledged) { create(:user) }
diff --git a/spec/requests/api/rubygem_packages_spec.rb b/spec/requests/api/rubygem_packages_spec.rb
index 34cf6033811..1774b43ccb3 100644
--- a/spec/requests/api/rubygem_packages_spec.rb
+++ b/spec/requests/api/rubygem_packages_spec.rb
@@ -8,6 +8,14 @@ RSpec.describe API::RubygemPackages, feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
let_it_be_with_reload(:project) { create(:project) }
+ let(:tokens) do
+ {
+ personal_access_token: personal_access_token.token,
+ deploy_token: deploy_token.token,
+ job_token: job.token
+ }
+ end
+
let_it_be(:personal_access_token) { create(:personal_access_token) }
let_it_be(:user) { personal_access_token.user }
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
@@ -15,14 +23,14 @@ RSpec.describe API::RubygemPackages, feature_category: :package_registry do
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:headers) { {} }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_rubygems_user' } }
+ let(:snowplow_gitlab_standard_context) { snowplow_context }
- let(:tokens) do
- {
- personal_access_token: personal_access_token.token,
- deploy_token: deploy_token.token,
- job_token: job.token
- }
+ def snowplow_context(user_role: :developer)
+ if user_role == :anonymous
+ { project: project, namespace: project.namespace, property: 'i_package_rubygems_user' }
+ else
+ { project: project, namespace: project.namespace, property: 'i_package_rubygems_user', user: user }
+ end
end
shared_examples 'when feature flag is disabled' do
@@ -164,7 +172,13 @@ RSpec.describe API::RubygemPackages, feature_category: :package_registry do
with_them do
let(:token) { valid_token ? tokens[token_type] : 'invalid-token123' }
let(:headers) { user_role == :anonymous ? {} : { 'HTTP_AUTHORIZATION' => token } }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_rubygems_user' } }
+ let(:snowplow_gitlab_standard_context) do
+ if token_type == :deploy_token
+ snowplow_context.merge(user: deploy_token)
+ else
+ snowplow_context(user_role: user_role)
+ end
+ end
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility.to_s))
diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb
index 035f53db12e..eb0f3b3eaee 100644
--- a/spec/requests/api/search_spec.rb
+++ b/spec/requests/api/search_spec.rb
@@ -174,6 +174,23 @@ RSpec.describe API::Search, feature_category: :global_search do
end
end
+ context 'when there is a search error' do
+ let(:results) { instance_double('Gitlab::SearchResults', failed?: true, error: 'failed to parse query') }
+
+ before do
+ allow_next_instance_of(SearchService) do |service|
+ allow(service).to receive(:search_objects).and_return([])
+ allow(service).to receive(:search_results).and_return(results)
+ end
+ end
+
+ it 'returns 400 error' do
+ get api(endpoint, user), params: { scope: 'issues', search: 'expected to fail' }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
context 'with correct params' do
context 'for projects scope' do
before do
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 4d85849cff3..e91d777bfb0 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, feature_category: :not_owned do
+RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, feature_category: :shared do
let(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
@@ -66,6 +66,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
expect(json_response['jira_connect_application_key']).to eq(nil)
expect(json_response['jira_connect_proxy_url']).to eq(nil)
expect(json_response['user_defaults_to_private_profile']).to eq(false)
+ expect(json_response['default_syntax_highlighting_theme']).to eq(1)
+ expect(json_response['projects_api_rate_limit_unauthenticated']).to eq(400)
end
end
@@ -169,7 +171,9 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
jira_connect_proxy_url: 'http://example.com',
bulk_import_enabled: false,
allow_runner_registration_token: true,
- user_defaults_to_private_profile: true
+ user_defaults_to_private_profile: true,
+ default_syntax_highlighting_theme: 2,
+ projects_api_rate_limit_unauthenticated: 100
}
expect(response).to have_gitlab_http_status(:ok)
@@ -237,6 +241,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
expect(json_response['bulk_import_enabled']).to be(false)
expect(json_response['allow_runner_registration_token']).to be(true)
expect(json_response['user_defaults_to_private_profile']).to be(true)
+ expect(json_response['default_syntax_highlighting_theme']).to eq(2)
+ expect(json_response['projects_api_rate_limit_unauthenticated']).to be(100)
end
end
diff --git a/spec/requests/api/sidekiq_metrics_spec.rb b/spec/requests/api/sidekiq_metrics_spec.rb
index 1085df97cc7..32c4c323923 100644
--- a/spec/requests/api/sidekiq_metrics_spec.rb
+++ b/spec/requests/api/sidekiq_metrics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::SidekiqMetrics, feature_category: :not_owned do
+RSpec.describe API::SidekiqMetrics, feature_category: :shared do
let(:admin) { create(:user, :admin) }
describe 'GET sidekiq/*' do
diff --git a/spec/requests/api/terraform/modules/v1/packages_spec.rb b/spec/requests/api/terraform/modules/v1/packages_spec.rb
index 2bd7cb027aa..f479ca25f3c 100644
--- a/spec/requests/api/terraform/modules/v1/packages_spec.rb
+++ b/spec/requests/api/terraform/modules/v1/packages_spec.rb
@@ -415,12 +415,15 @@ RSpec.describe API::Terraform::Modules::V1::Packages, feature_category: :package
with_them do
let(:snowplow_gitlab_standard_context) do
- {
+ context = {
project: project,
- user: user_role == :anonymous ? nil : user,
namespace: project.namespace,
property: 'i_package_terraform_module_user'
}
+
+ context[:user] = user if user_role != :anonymous
+
+ context
end
before do
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index fd34345d814..c94643242c9 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -21,6 +21,7 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
before do
stub_terraform_state_object_storage
+ stub_config(terraform_state: { enabled: true })
end
shared_examples 'endpoint with unique user tracking' do
@@ -51,7 +52,6 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject(:api_request) { request }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'terraform_state_api_request' }
let(:label) { 'redis_hll_counters.terraform.p_terraform_state_api_unique_users_monthly' }
@@ -82,6 +82,7 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
subject(:request) { get api(state_path), headers: auth_header }
it_behaves_like 'endpoint with unique user tracking'
+ it_behaves_like 'it depends on value of the `terraform_state.enabled` config'
context 'without authentication' do
let(:auth_header) { basic_auth_header('bad', 'token') }
@@ -194,6 +195,7 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
subject(:request) { post api(state_path), headers: auth_header, as: :json, params: params }
it_behaves_like 'endpoint with unique user tracking'
+ it_behaves_like 'it depends on value of the `terraform_state.enabled` config'
context 'when terraform state with a given name is already present' do
context 'with maintainer permissions' do
@@ -372,6 +374,7 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
subject(:request) { delete api(state_path), headers: auth_header }
it_behaves_like 'endpoint with unique user tracking'
+ it_behaves_like 'it depends on value of the `terraform_state.enabled` config'
shared_examples 'schedules the state for deletion' do
it 'returns empty body' do
@@ -553,6 +556,10 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
let(:lock_id) { 'irrelevant to this test, just needs to be present' }
end
+ it_behaves_like 'it depends on value of the `terraform_state.enabled` config' do
+ let(:lock_id) { '123.456' }
+ end
+
where(given_state_name: %w[test-state test.state test%2Ffoo])
with_them do
let(:state_name) { given_state_name }
diff --git a/spec/requests/api/terraform/state_version_spec.rb b/spec/requests/api/terraform/state_version_spec.rb
index 28abbb5749d..24b3ca94581 100644
--- a/spec/requests/api/terraform/state_version_spec.rb
+++ b/spec/requests/api/terraform/state_version_spec.rb
@@ -22,9 +22,15 @@ RSpec.describe API::Terraform::StateVersion, feature_category: :infrastructure_a
let(:version_serial) { version.version }
let(:state_version_path) { "/projects/#{project_id}/terraform/state/#{state_name}/versions/#{version_serial}" }
+ before do
+ stub_config(terraform_state: { enabled: true })
+ end
+
describe 'GET /projects/:id/terraform/state/:name/versions/:serial' do
subject(:request) { get api(state_version_path), headers: auth_header }
+ it_behaves_like 'it depends on value of the `terraform_state.enabled` config'
+
context 'with invalid authentication' do
let(:auth_header) { basic_auth_header('bad', 'token') }
@@ -147,6 +153,8 @@ RSpec.describe API::Terraform::StateVersion, feature_category: :infrastructure_a
describe 'DELETE /projects/:id/terraform/state/:name/versions/:serial' do
subject(:request) { delete api(state_version_path), headers: auth_header }
+ it_behaves_like 'it depends on value of the `terraform_state.enabled` config', { success_status: :no_content }
+
context 'with invalid authentication' do
let(:auth_header) { basic_auth_header('bad', 'token') }
diff --git a/spec/requests/api/unleash_spec.rb b/spec/requests/api/unleash_spec.rb
index 5daf7cd7b75..75b26b98228 100644
--- a/spec/requests/api/unleash_spec.rb
+++ b/spec/requests/api/unleash_spec.rb
@@ -88,6 +88,14 @@ RSpec.describe API::Unleash, feature_category: :feature_flags do
end
end
+ describe 'GET /feature_flags/unleash/:project_id/client/features', :use_clean_rails_redis_caching do
+ specify do
+ get api("/feature_flags/unleash/#{project_id}/client/features"), params: params, headers: headers
+
+ is_expected.to have_request_urgency(:medium)
+ end
+ end
+
%w(/feature_flags/unleash/:project_id/features /feature_flags/unleash/:project_id/client/features).each do |features_endpoint|
describe "GET #{features_endpoint}", :use_clean_rails_redis_caching do
let(:features_url) { features_endpoint.sub(':project_id', project_id.to_s) }
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 34867b13db2..c924f529e11 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -1288,7 +1288,7 @@ RSpec.describe API::Users, feature_category: :user_profile do
expect(json_response['message']['projects_limit'])
.to eq(['must be greater than or equal to 0'])
expect(json_response['message']['username'])
- .to eq([Gitlab::PathRegex.namespace_format_message])
+ .to match_array([Gitlab::PathRegex.namespace_format_message, Gitlab::Regex.oci_repository_path_regex_message])
end
it 'tracks weak password errors' do
@@ -1823,7 +1823,7 @@ RSpec.describe API::Users, feature_category: :user_profile do
expect(json_response['message']['projects_limit'])
.to eq(['must be greater than or equal to 0'])
expect(json_response['message']['username'])
- .to eq([Gitlab::PathRegex.namespace_format_message])
+ .to match_array([Gitlab::PathRegex.namespace_format_message, Gitlab::Regex.oci_repository_path_regex_message])
end
it 'returns 400 if provider is missing for identity update' do
@@ -4150,7 +4150,7 @@ RSpec.describe API::Users, feature_category: :user_profile do
set_user_status
expect(response).to have_gitlab_http_status(:success)
- expect(user_with_status.status).to be_nil
+ expect(user_with_status.reset.status).to be_nil
end
end
end
@@ -4178,7 +4178,7 @@ RSpec.describe API::Users, feature_category: :user_profile do
set_user_status
expect(response).to have_gitlab_http_status(:success)
- expect(user_with_status.status.clear_status_at).to be_nil
+ expect(user_with_status.reset.status.clear_status_at).to be_nil
end
end
@@ -4217,7 +4217,7 @@ RSpec.describe API::Users, feature_category: :user_profile do
set_user_status
expect(response).to have_gitlab_http_status(:success)
- expect(user_with_status.status).to be_nil
+ expect(user_with_status.reset.status).to be_nil
end
end
@@ -4229,7 +4229,7 @@ RSpec.describe API::Users, feature_category: :user_profile do
set_user_status
expect(response).to have_gitlab_http_status(:success)
- expect(user_with_status.status.clear_status_at).to be_nil
+ expect(user_with_status.reset.status.clear_status_at).to be_nil
end
end
end
diff --git a/spec/requests/dashboard_controller_spec.rb b/spec/requests/dashboard_controller_spec.rb
index 1c8ab843ebe..d7f01b8a7ab 100644
--- a/spec/requests/dashboard_controller_spec.rb
+++ b/spec/requests/dashboard_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DashboardController, feature_category: :authentication_and_authorization do
+RSpec.describe DashboardController, feature_category: :system_access do
context 'token authentication' do
it_behaves_like 'authenticates sessionless user for the request spec', 'issues atom', public_resource: false do
let(:url) { issues_dashboard_url(:atom, assignee_username: user.username) }
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 02b99eba8ce..d3d1a2a6cd0 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -230,6 +230,12 @@ RSpec.describe 'Git HTTP requests', feature_category: :source_code_management do
context 'when authenticated' do
it 'creates a new project under the existing namespace' do
+ # current scenario does not matter with the user activity case,
+ # so stub/double it to escape more sql running times limit
+ activity_service = instance_double(::Users::ActivityService)
+ allow(::Users::ActivityService).to receive(:new).and_return(activity_service)
+ allow(activity_service).to receive(:execute)
+
expect do
upload(path, user: user.username, password: user.password) do |response|
expect(response).to have_gitlab_http_status(:ok)
@@ -472,10 +478,11 @@ RSpec.describe 'Git HTTP requests', feature_category: :source_code_management do
end
context 'when the request is not from gitlab-workhorse' do
- it 'raises an exception' do
- expect do
- get("/#{project.full_path}.git/info/refs?service=git-upload-pack")
- end.to raise_error(JWT::DecodeError)
+ it 'responds with 403 Forbidden' do
+ get("/#{project.full_path}.git/info/refs?service=git-upload-pack")
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response.body).to eq('Nil JSON web token')
end
end
@@ -1112,10 +1119,11 @@ RSpec.describe 'Git HTTP requests', feature_category: :source_code_management do
end
context 'when the request is not from gitlab-workhorse' do
- it 'raises an exception' do
- expect do
- get("/#{project.full_path}.git/info/refs?service=git-upload-pack")
- end.to raise_error(JWT::DecodeError)
+ it 'responds with 403 Forbidden' do
+ get("/#{project.full_path}.git/info/refs?service=git-upload-pack")
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response.body).to eq('Nil JSON web token')
end
end
diff --git a/spec/requests/groups/email_campaigns_controller_spec.rb b/spec/requests/groups/email_campaigns_controller_spec.rb
index 7db5c084793..b6e765eba37 100644
--- a/spec/requests/groups/email_campaigns_controller_spec.rb
+++ b/spec/requests/groups/email_campaigns_controller_spec.rb
@@ -38,11 +38,7 @@ RSpec.describe Groups::EmailCampaignsController, feature_category: :navigation d
expect(subject).to have_gitlab_http_status(:redirect)
end
- context 'on .com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
+ context 'on SaaS', :saas do
it 'emits a snowplow event', :snowplow do
subject
diff --git a/spec/requests/groups/observability_controller_spec.rb b/spec/requests/groups/observability_controller_spec.rb
index 471cad40c90..b82cf2b0bad 100644
--- a/spec/requests/groups/observability_controller_spec.rb
+++ b/spec/requests/groups/observability_controller_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Groups::ObservabilityController, feature_category: :tracing do
end
end
- context 'when user is not a developer' do
+ context 'when user is a guest' do
before do
sign_in(user)
end
@@ -36,10 +36,10 @@ RSpec.describe Groups::ObservabilityController, feature_category: :tracing do
end
end
- context 'when user is authenticated and a developer' do
+ context 'when user has the correct permissions' do
before do
sign_in(user)
- group.add_developer(user)
+ set_permissions
end
context 'when observability url is missing' do
@@ -75,13 +75,21 @@ RSpec.describe Groups::ObservabilityController, feature_category: :tracing do
let(:path) { group_observability_explore_path(group) }
let(:expected_observability_path) { "#{observability_url}/-/#{group.id}/explore" }
- it_behaves_like 'observability route request'
+ it_behaves_like 'observability route request' do
+ let(:set_permissions) do
+ group.add_developer(user)
+ end
+ end
end
describe 'GET #datasources' do
let(:path) { group_observability_datasources_path(group) }
let(:expected_observability_path) { "#{observability_url}/-/#{group.id}/datasources" }
- it_behaves_like 'observability route request'
+ it_behaves_like 'observability route request' do
+ let(:set_permissions) do
+ group.add_maintainer(user)
+ 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 f26b69f8d30..0204af8ea8e 100644
--- a/spec/requests/groups/settings/access_tokens_controller_spec.rb
+++ b/spec/requests/groups/settings/access_tokens_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::Settings::AccessTokensController, feature_category: :authentication_and_authorization do
+RSpec.describe Groups::Settings::AccessTokensController, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:resource) { create(:group) }
let_it_be(:access_token_user) { create(:user, :project_bot) }
diff --git a/spec/requests/groups/settings/applications_controller_spec.rb b/spec/requests/groups/settings/applications_controller_spec.rb
index fb91cd8bdab..2fcf80658b2 100644
--- a/spec/requests/groups/settings/applications_controller_spec.rb
+++ b/spec/requests/groups/settings/applications_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::Settings::ApplicationsController, feature_category: :authentication_and_authorization do
+RSpec.describe Groups::Settings::ApplicationsController, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:application) { create(:oauth_application, owner_id: group.id, owner_type: 'Namespace') }
diff --git a/spec/requests/ide_controller_spec.rb b/spec/requests/ide_controller_spec.rb
index b287ded799d..38708399519 100644
--- a/spec/requests/ide_controller_spec.rb
+++ b/spec/requests/ide_controller_spec.rb
@@ -19,7 +19,6 @@ RSpec.describe IdeController, feature_category: :web_ide do
let_it_be(:top_nav_partial) { 'layouts/header/_default' }
let(:user) { creator }
- let(:branch) { '' }
def find_csp_frame_src
csp = response.headers['Content-Security-Policy']
@@ -42,14 +41,14 @@ RSpec.describe IdeController, feature_category: :web_ide do
subject { get route }
shared_examples 'user access rights check' do
- context 'user can read project' do
+ context 'when user can read project' do
it 'increases the views counter' do
expect(Gitlab::UsageDataCounters::WebIdeCounter).to receive(:increment_views_count)
subject
end
- context 'user can read project but cannot push code' do
+ context 'when user can read project but cannot push code' do
include ProjectForksHelper
let(:user) { reporter }
@@ -60,7 +59,15 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:project)).to eq project
- expect(assigns(:fork_info)).to eq({ fork_path: controller.helpers.ide_fork_and_edit_path(project, branch, '', with_notice: false) })
+
+ expect(assigns(:fork_info)).to eq({
+ fork_path: controller.helpers.ide_fork_and_edit_path(
+ project,
+ '',
+ '',
+ with_notice: false
+ )
+ })
end
it 'has nil fork_info if user cannot fork' do
@@ -81,13 +88,13 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:project)).to eq project
- expect(assigns(:fork_info)).to eq({ ide_path: controller.helpers.ide_edit_path(fork, branch, '') })
+ expect(assigns(:fork_info)).to eq({ ide_path: controller.helpers.ide_edit_path(fork, '', '') })
end
end
end
end
- context 'user cannot read project' do
+ context 'when user cannot read project' do
let(:user) { other_user }
it 'returns 404' do
@@ -98,7 +105,7 @@ RSpec.describe IdeController, feature_category: :web_ide do
end
end
- context '/-/ide' do
+ context 'with /-/ide' do
let(:route) { '/-/ide' }
it 'returns 404' do
@@ -108,7 +115,7 @@ RSpec.describe IdeController, feature_category: :web_ide do
end
end
- context '/-/ide/project' do
+ context 'with /-/ide/project' do
let(:route) { '/-/ide/project' }
it 'returns 404' do
@@ -118,7 +125,7 @@ RSpec.describe IdeController, feature_category: :web_ide do
end
end
- context '/-/ide/project/:project' do
+ context 'with /-/ide/project/:project' do
let(:route) { "/-/ide/project/#{project.full_path}" }
it 'instantiates project instance var and returns 200' do
@@ -126,16 +133,13 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:project)).to eq project
- expect(assigns(:branch)).to be_nil
- expect(assigns(:path)).to be_nil
- expect(assigns(:merge_request)).to be_nil
expect(assigns(:fork_info)).to be_nil
end
it_behaves_like 'user access rights check'
- %w(edit blob tree).each do |action|
- context "/-/ide/project/:project/#{action}" do
+ %w[edit blob tree].each do |action|
+ context "with /-/ide/project/:project/#{action}" do
let(:route) { "/-/ide/project/#{project.full_path}/#{action}" }
it 'instantiates project instance var and returns 200' do
@@ -143,87 +147,11 @@ RSpec.describe IdeController, feature_category: :web_ide do
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:project)).to eq project
- expect(assigns(:branch)).to be_nil
- expect(assigns(:path)).to be_nil
- expect(assigns(:merge_request)).to be_nil
expect(assigns(:fork_info)).to be_nil
end
it_behaves_like 'user access rights check'
-
- context "/-/ide/project/:project/#{action}/:branch" do
- let(:branch) { 'master' }
- let(:route) { "/-/ide/project/#{project.full_path}/#{action}/#{branch}" }
-
- it 'instantiates project and branch instance vars and returns 200' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:project)).to eq project
- expect(assigns(:branch)).to eq branch
- expect(assigns(:path)).to be_nil
- expect(assigns(:merge_request)).to be_nil
- expect(assigns(:fork_info)).to be_nil
- end
-
- it_behaves_like 'user access rights check'
-
- context "/-/ide/project/:project/#{action}/:branch/-" do
- let(:branch) { 'branch/slash' }
- let(:route) { "/-/ide/project/#{project.full_path}/#{action}/#{branch}/-" }
-
- it 'instantiates project and branch instance vars and returns 200' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:project)).to eq project
- expect(assigns(:branch)).to eq branch
- expect(assigns(:path)).to be_nil
- expect(assigns(:merge_request)).to be_nil
- expect(assigns(:fork_info)).to be_nil
- end
-
- it_behaves_like 'user access rights check'
-
- context "/-/ide/project/:project/#{action}/:branch/-/:path" do
- let(:branch) { 'master' }
- let(:route) { "/-/ide/project/#{project.full_path}/#{action}/#{branch}/-/foo/.bar" }
-
- it 'instantiates project, branch, and path instance vars and returns 200' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:project)).to eq project
- expect(assigns(:branch)).to eq branch
- expect(assigns(:path)).to eq 'foo/.bar'
- expect(assigns(:merge_request)).to be_nil
- expect(assigns(:fork_info)).to be_nil
- end
-
- it_behaves_like 'user access rights check'
- end
- end
- end
- end
- end
-
- context '/-/ide/project/:project/merge_requests/:merge_request_id' do
- let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
-
- let(:route) { "/-/ide/project/#{project.full_path}/merge_requests/#{merge_request.id}" }
-
- it 'instantiates project and merge_request instance vars and returns 200' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:project)).to eq project
- expect(assigns(:branch)).to be_nil
- expect(assigns(:path)).to be_nil
- expect(assigns(:merge_request)).to eq merge_request.id.to_s
- expect(assigns(:fork_info)).to be_nil
end
-
- it_behaves_like 'user access rights check'
end
describe 'Snowplow view event', :snowplow do
@@ -237,18 +165,6 @@ RSpec.describe IdeController, feature_category: :web_ide do
user: user
)
end
-
- context 'when route_hll_to_snowplow_phase2 FF is disabled' do
- before do
- stub_feature_flags(route_hll_to_snowplow_phase2: false)
- end
-
- it 'does not track Snowplow event' do
- subject
-
- expect_no_snowplow_event
- end
- end
end
# This indirectly tests that `minimal: true` was passed to the fullscreen layout
diff --git a/spec/requests/jira_connect/oauth_application_ids_controller_spec.rb b/spec/requests/jira_connect/oauth_application_ids_controller_spec.rb
index d111edd06da..2f6113c6dd7 100644
--- a/spec/requests/jira_connect/oauth_application_ids_controller_spec.rb
+++ b/spec/requests/jira_connect/oauth_application_ids_controller_spec.rb
@@ -38,11 +38,7 @@ RSpec.describe JiraConnect::OauthApplicationIdsController, feature_category: :in
end
end
- context 'on GitLab.com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
+ context 'on SaaS', :saas do
it 'renders not found' do
get '/-/jira_connect/oauth_application_id'
diff --git a/spec/requests/jira_connect/public_keys_controller_spec.rb b/spec/requests/jira_connect/public_keys_controller_spec.rb
index 7f0262eaf65..62a81d43e65 100644
--- a/spec/requests/jira_connect/public_keys_controller_spec.rb
+++ b/spec/requests/jira_connect/public_keys_controller_spec.rb
@@ -5,11 +5,10 @@ require 'spec_helper'
RSpec.describe JiraConnect::PublicKeysController, feature_category: :integrations do
describe 'GET /-/jira_connect/public_keys/:uuid' do
let(:uuid) { non_existing_record_id }
- let(:public_key_storage_enabled_config) { true }
+ let(:public_key_storage_enabled) { true }
before do
- allow(Gitlab.config.jira_connect).to receive(:enable_public_keys_storage)
- .and_return(public_key_storage_enabled_config)
+ stub_application_setting(jira_connect_public_key_storage_enabled: public_key_storage_enabled)
end
it 'renders 404' do
@@ -30,26 +29,14 @@ RSpec.describe JiraConnect::PublicKeysController, feature_category: :integration
expect(response.body).to eq(public_key.key)
end
- context 'when public key storage config disabled' do
- let(:public_key_storage_enabled_config) { false }
+ context 'when public key storage setting disabled' do
+ let(:public_key_storage_enabled) { false }
it 'renders 404' do
get jira_connect_public_key_path(id: uuid)
expect(response).to have_gitlab_http_status(:not_found)
end
-
- context 'when public key storage setting is enabled' do
- before do
- stub_application_setting(jira_connect_public_key_storage_enabled: true)
- end
-
- it 'renders 404' do
- get jira_connect_public_key_path(id: uuid)
-
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
end
end
end
diff --git a/spec/requests/jwks_controller_spec.rb b/spec/requests/jwks_controller_spec.rb
index ac9765c35d8..c6f5f7c6bea 100644
--- a/spec/requests/jwks_controller_spec.rb
+++ b/spec/requests/jwks_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JwksController, feature_category: :authentication_and_authorization do
+RSpec.describe JwksController, feature_category: :system_access do
describe 'Endpoints from the parent Doorkeeper::OpenidConnect::DiscoveryController' do
it 'respond successfully' do
[
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index 00222cb1977..69127a7526e 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JwtController, feature_category: :authentication_and_authorization do
+RSpec.describe JwtController, feature_category: :system_access do
include_context 'parsed logs'
let(:service) { double(execute: {} ) }
@@ -53,6 +53,14 @@ RSpec.describe JwtController, feature_category: :authentication_and_authorizatio
end
end
+ context 'POST /jwt/auth' do
+ it 'returns 404' do
+ post '/jwt/auth'
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
context 'authenticating against container registry' do
context 'existing service' do
subject! { get '/jwt/auth', params: parameters }
diff --git a/spec/requests/oauth/applications_controller_spec.rb b/spec/requests/oauth/applications_controller_spec.rb
index 94ee08f6272..8c2856b87d1 100644
--- a/spec/requests/oauth/applications_controller_spec.rb
+++ b/spec/requests/oauth/applications_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Oauth::ApplicationsController, feature_category: :authentication_and_authorization do
+RSpec.describe Oauth::ApplicationsController, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:application) { create(:oauth_application, owner: user) }
let_it_be(:show_path) { oauth_application_path(application) }
diff --git a/spec/requests/oauth/authorizations_controller_spec.rb b/spec/requests/oauth/authorizations_controller_spec.rb
index 52188717210..257f238d9ef 100644
--- a/spec/requests/oauth/authorizations_controller_spec.rb
+++ b/spec/requests/oauth/authorizations_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Oauth::AuthorizationsController, feature_category: :authentication_and_authorization do
+RSpec.describe Oauth::AuthorizationsController, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:application) { create(:oauth_application, redirect_uri: 'custom://test') }
let_it_be(:oauth_authorization_path) do
diff --git a/spec/requests/oauth/tokens_controller_spec.rb b/spec/requests/oauth/tokens_controller_spec.rb
index cdfad8cb59c..58203a81bac 100644
--- a/spec/requests/oauth/tokens_controller_spec.rb
+++ b/spec/requests/oauth/tokens_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Oauth::TokensController, feature_category: :authentication_and_authorization do
+RSpec.describe Oauth::TokensController, feature_category: :system_access do
let(:cors_request_headers) { { 'Origin' => 'http://notgitlab.com' } }
let(:other_headers) { {} }
let(:headers) { cors_request_headers.merge(other_headers) }
diff --git a/spec/requests/oauth_tokens_spec.rb b/spec/requests/oauth_tokens_spec.rb
index 053bd317fcc..67c676fdb40 100644
--- a/spec/requests/oauth_tokens_spec.rb
+++ b/spec/requests/oauth_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'OAuth Tokens requests', feature_category: :authentication_and_authorization do
+RSpec.describe 'OAuth Tokens requests', feature_category: :system_access do
let(:user) { create :user }
let(:application) { create :oauth_application, scopes: 'api' }
let(:grant_type) { 'authorization_code' }
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index 9035e723abe..2e158190734 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'OpenID Connect requests', feature_category: :authentication_and_authorization do
+RSpec.describe 'OpenID Connect requests', feature_category: :system_access do
let(:user) do
create(
:user,
diff --git a/spec/requests/projects/airflow/dags_controller_spec.rb b/spec/requests/projects/airflow/dags_controller_spec.rb
deleted file mode 100644
index 2dcedf5f128..00000000000
--- a/spec/requests/projects/airflow/dags_controller_spec.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::Airflow::DagsController, feature_category: :dataops do
- let_it_be(:non_member) { create(:user) }
- let_it_be(:user) { create(:user) }
- let_it_be(:group) { create(:group).tap { |p| p.add_developer(user) } }
- let_it_be(:project) { create(:project, group: group).tap { |p| p.add_developer(user) } }
-
- let(:current_user) { user }
- let(:feature_flag) { true }
-
- let_it_be(:dags) do
- create_list(:airflow_dags, 5, project: project)
- end
-
- let(:params) { { namespace_id: project.namespace.to_param, project_id: project } }
- let(:extra_params) { {} }
-
- before do
- sign_in(current_user) if current_user
- stub_feature_flags(airflow_dags: false)
- stub_feature_flags(airflow_dags: project) if feature_flag
- list_dags
- end
-
- shared_examples 'returns a 404 if feature flag disabled' do
- context 'when :airflow_dags disabled' do
- let(:feature_flag) { false }
-
- it 'is 404' do
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- describe 'GET index' do
- it 'renders the template' do
- expect(response).to render_template('projects/airflow/dags/index')
- end
-
- describe 'pagination' do
- before do
- stub_const("Projects::Airflow::DagsController::MAX_DAGS_PER_PAGE", 2)
- dags
-
- list_dags
- end
-
- context 'when out of bounds' do
- let(:params) { extra_params.merge(page: 10000) }
-
- it 'redirects to last page' do
- last_page = (dags.size + 1) / 2
- expect(response).to redirect_to(project_airflow_dags_path(project, page: last_page))
- end
- end
-
- context 'when bad page' do
- let(:params) { extra_params.merge(page: 's') }
-
- it 'uses first page' do
- expect(assigns(:pagination)).to include(
- page: 1,
- is_last_page: false,
- per_page: 2,
- total_items: dags.size)
- end
- end
- end
-
- it 'does not perform N+1 sql queries' do
- control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { list_dags }
-
- create_list(:airflow_dags, 1, project: project)
-
- expect { list_dags }.not_to exceed_all_query_limit(control_count)
- end
-
- context 'when user is not logged in' do
- let(:current_user) { nil }
-
- it 'redirects to login' do
- expect(response).to redirect_to(new_user_session_path)
- end
- end
-
- context 'when user is not a member' do
- let(:current_user) { non_member }
-
- it 'returns a 404' do
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- it_behaves_like 'returns a 404 if feature flag disabled'
- end
-
- private
-
- def list_dags
- get project_airflow_dags_path(project), params: params
- end
-end
diff --git a/spec/requests/projects/ci/promeheus_metrics/histograms_controller_spec.rb b/spec/requests/projects/ci/promeheus_metrics/histograms_controller_spec.rb
index b0c7427fa81..11f962e0e96 100644
--- a/spec/requests/projects/ci/promeheus_metrics/histograms_controller_spec.rb
+++ b/spec/requests/projects/ci/promeheus_metrics/histograms_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Projects::Ci::PrometheusMetrics::HistogramsController', feature_category: :pipeline_authoring do
+RSpec.describe 'Projects::Ci::PrometheusMetrics::HistogramsController', feature_category: :pipeline_composition do
let_it_be(:project) { create(:project, :public) }
describe 'POST /*namespace_id/:project_id/-/ci/prometheus_metrics/histograms' do
diff --git a/spec/requests/projects/google_cloud/deployments_controller_spec.rb b/spec/requests/projects/google_cloud/deployments_controller_spec.rb
index d564a31f835..14214b8fdfb 100644
--- a/spec/requests/projects/google_cloud/deployments_controller_spec.rb
+++ b/spec/requests/projects/google_cloud/deployments_controller_spec.rb
@@ -108,66 +108,104 @@ RSpec.describe Projects::GoogleCloud::DeploymentsController, feature_category: :
end
end
- it 'redirects to google cloud deployments on enable service error' do
- get url
-
- expect(response).to redirect_to(project_google_cloud_deployments_path(project))
- # since GPC_PROJECT_ID is not set, enable cloud run service should return an error
- expect_snowplow_event(
- category: 'Projects::GoogleCloud::DeploymentsController',
- action: 'error_enable_services',
- label: nil,
- project: project,
- user: user_maintainer
- )
- end
+ context 'when enable service fails' do
+ before do
+ allow_next_instance_of(GoogleCloud::EnableCloudRunService) do |service|
+ allow(service)
+ .to receive(:execute)
+ .and_return(
+ status: :error,
+ message: 'No GCP projects found. Configure a service account or GCP_PROJECT_ID ci variable'
+ )
+ end
+ end
- it 'redirects to google cloud deployments with error' do
- mock_gcp_error = Google::Apis::ClientError.new('some_error')
+ it 'redirects to google cloud deployments and tracks event on enable service error' do
+ get url
- allow_next_instance_of(GoogleCloud::EnableCloudRunService) do |service|
- allow(service).to receive(:execute).and_raise(mock_gcp_error)
+ expect(response).to redirect_to(project_google_cloud_deployments_path(project))
+ # since GPC_PROJECT_ID is not set, enable cloud run service should return an error
+ expect_snowplow_event(
+ category: 'Projects::GoogleCloud::DeploymentsController',
+ action: 'error_enable_services',
+ label: nil,
+ project: project,
+ user: user_maintainer
+ )
end
- get url
+ it 'shows a flash alert' do
+ get url
- expect(response).to redirect_to(project_google_cloud_deployments_path(project))
- expect_snowplow_event(
- category: 'Projects::GoogleCloud::DeploymentsController',
- action: 'error_google_api',
- label: nil,
- project: project,
- user: user_maintainer
- )
+ expect(flash[:alert])
+ .to eq('No GCP projects found. Configure a service account or GCP_PROJECT_ID ci variable')
+ end
end
- context 'GCP_PROJECT_IDs are defined' do
- it 'redirects to google_cloud deployments on generate pipeline error' do
- allow_next_instance_of(GoogleCloud::EnableCloudRunService) do |enable_cloud_run_service|
- allow(enable_cloud_run_service).to receive(:execute).and_return({ status: :success })
- end
+ context 'when enable service raises an error' do
+ before do
+ mock_gcp_error = Google::Apis::ClientError.new('some_error')
- allow_next_instance_of(GoogleCloud::GeneratePipelineService) do |generate_pipeline_service|
- allow(generate_pipeline_service).to receive(:execute).and_return({ status: :error })
+ allow_next_instance_of(GoogleCloud::EnableCloudRunService) do |service|
+ allow(service).to receive(:execute).and_raise(mock_gcp_error)
end
+ end
+ it 'redirects to google cloud deployments with error' do
get url
expect(response).to redirect_to(project_google_cloud_deployments_path(project))
expect_snowplow_event(
category: 'Projects::GoogleCloud::DeploymentsController',
- action: 'error_generate_cloudrun_pipeline',
+ action: 'error_google_api',
label: nil,
project: project,
user: user_maintainer
)
end
- it 'redirects to create merge request form' do
- allow_next_instance_of(GoogleCloud::EnableCloudRunService) do |service|
- allow(service).to receive(:execute).and_return({ status: :success })
+ it 'shows a flash warning' do
+ get url
+
+ expect(flash[:warning]).to eq(format(_('Google Cloud Error - %{error}'), error: 'some_error'))
+ end
+ end
+
+ context 'GCP_PROJECT_IDs are defined' do
+ before do
+ allow_next_instance_of(GoogleCloud::EnableCloudRunService) do |enable_cloud_run_service|
+ allow(enable_cloud_run_service).to receive(:execute).and_return({ status: :success })
+ end
+ end
+
+ context 'when generate pipeline service fails' do
+ before do
+ allow_next_instance_of(GoogleCloud::GeneratePipelineService) do |generate_pipeline_service|
+ allow(generate_pipeline_service).to receive(:execute).and_return({ status: :error })
+ end
+ end
+
+ it 'redirects to google_cloud deployments and tracks event on generate pipeline error' do
+ get url
+
+ expect(response).to redirect_to(project_google_cloud_deployments_path(project))
+ expect_snowplow_event(
+ category: 'Projects::GoogleCloud::DeploymentsController',
+ action: 'error_generate_cloudrun_pipeline',
+ label: nil,
+ project: project,
+ user: user_maintainer
+ )
+ end
+
+ it 'shows a flash alert' do
+ get url
+
+ expect(flash[:alert]).to eq('Failed to generate pipeline')
end
+ end
+ it 'redirects to create merge request form' do
allow_next_instance_of(GoogleCloud::GeneratePipelineService) do |service|
allow(service).to receive(:execute).and_return({ status: :success })
end
diff --git a/spec/requests/projects/issue_links_controller_spec.rb b/spec/requests/projects/issue_links_controller_spec.rb
index 0535156b4b8..5678a81a4b0 100644
--- a/spec/requests/projects/issue_links_controller_spec.rb
+++ b/spec/requests/projects/issue_links_controller_spec.rb
@@ -28,22 +28,6 @@ RSpec.describe Projects::IssueLinksController, feature_category: :team_planning
context 'when linked issue is a task' do
let(:issue_b) { create :issue, :task, project: project }
- context 'when the use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- it 'returns a work item path for the linked task' do
- get namespace_project_issue_links_path(issue_links_params)
-
- expect(json_response.count).to eq(1)
- expect(json_response.first).to include(
- 'path' => project_work_items_path(issue_b.project, issue_b.id),
- 'type' => 'TASK'
- )
- end
- end
-
it 'returns a work item path for the linked task using the iid in the path' do
get namespace_project_issue_links_path(issue_links_params)
diff --git a/spec/requests/projects/issues_controller_spec.rb b/spec/requests/projects/issues_controller_spec.rb
index 67a73834f2d..29ea20210c7 100644
--- a/spec/requests/projects/issues_controller_spec.rb
+++ b/spec/requests/projects/issues_controller_spec.rb
@@ -25,33 +25,28 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do
end
describe 'GET #show' do
- include_context 'group project issue'
+ before do
+ login_as(user)
+ end
it_behaves_like "observability csp policy", described_class do
+ include_context 'group project issue'
let(:tested_path) do
project_issue_path(project, issue)
end
end
- end
- describe 'GET #index.json' do
- let_it_be(:public_project) { create(:project, :public) }
+ describe 'incident tabs' do
+ let_it_be(:incident) { create(:incident, project: project) }
- it_behaves_like 'rate limited endpoint', rate_limit_key: :search_rate_limit do
- let_it_be(:current_user) { create(:user) }
-
- before do
- sign_in current_user
- end
-
- def request
- get project_issues_path(public_project, format: :json), params: { scope: 'all', search: 'test' }
+ it 'redirects to the issues route for non-incidents' do
+ get incident_issue_project_issue_path(project, issue, 'timeline')
+ expect(response).to redirect_to project_issue_path(project, issue)
end
- end
- it_behaves_like 'rate limited endpoint', rate_limit_key: :search_rate_limit_unauthenticated do
- def request
- get project_issues_path(public_project, format: :json), params: { scope: 'all', search: 'test' }
+ it 'responds with selected tab for incidents' do
+ get incident_issue_project_issue_path(project, incident, 'timeline')
+ expect(response.body).to match(/&quot;currentTab&quot;:&quot;timeline&quot;/)
end
end
end
diff --git a/spec/requests/projects/merge_requests_discussions_spec.rb b/spec/requests/projects/merge_requests_discussions_spec.rb
index d82fa284a42..54ee5e489f7 100644
--- a/spec/requests/projects/merge_requests_discussions_spec.rb
+++ b/spec/requests/projects/merge_requests_discussions_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe 'merge requests discussions', feature_category: :source_code_mana
.to change { Gitlab::GitalyClient.get_request_count }.by_at_most(4)
end
- context 'caching', :use_clean_rails_memory_store_caching do
+ context 'caching' do
let(:reference) { create(:issue, project: project) }
let(:author) { create(:user) }
let!(:first_note) { create(:diff_note_on_merge_request, author: author, noteable: merge_request, project: project, note: "reference: #{reference.to_reference}") }
@@ -81,193 +81,180 @@ RSpec.describe 'merge requests discussions', feature_category: :source_code_mana
shared_examples 'cache hit' do
it 'gets cached on subsequent requests' do
- expect_next_instance_of(DiscussionSerializer) do |serializer|
- expect(serializer).not_to receive(:represent)
- end
+ expect(DiscussionSerializer).not_to receive(:new)
send_request
end
end
- context 'when mr_discussions_http_cache and disabled_mr_discussions_redis_cache are enabled' do
- before do
- send_request
- end
-
- it_behaves_like 'cache hit'
+ before do
+ send_request
+ end
- context 'when a note in a discussion got updated' do
- before do
- first_note.update!(updated_at: 1.minute.from_now)
- end
+ it_behaves_like 'cache hit'
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ context 'when a note in a discussion got updated' do
+ before do
+ first_note.update!(updated_at: 1.minute.from_now)
end
- context 'when a note in a discussion got its reference state updated' do
- before do
- reference.close!
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ context 'when a note in a discussion got its reference state updated' do
+ before do
+ reference.close!
end
- context 'when a note in a discussion got resolved' do
- before do
- travel_to(1.minute.from_now) do
- first_note.resolve!(user)
- end
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
+ context 'when a note in a discussion got resolved' do
+ before do
+ travel_to(1.minute.from_now) do
+ first_note.resolve!(user)
end
end
- context 'when a note is added to a discussion' do
- let!(:third_note) { create(:diff_note_on_merge_request, in_reply_to: first_note, noteable: merge_request, project: project) }
-
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note, third_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
end
+ end
- context 'when a note is removed from a discussion' do
- before do
- second_note.destroy!
- end
+ context 'when a note is added to a discussion' do
+ let!(:third_note) { create(:diff_note_on_merge_request, in_reply_to: first_note, noteable: merge_request, project: project) }
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note, third_note] }
end
+ end
- context 'when an emoji is awarded to a note in discussion' do
- before do
- travel_to(1.minute.from_now) do
- create(:award_emoji, awardable: first_note)
- end
- end
+ context 'when a note is removed from a discussion' do
+ before do
+ second_note.destroy!
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note] }
end
+ end
- context 'when an award emoji is removed from a note in discussion' do
- before do
- travel_to(1.minute.from_now) do
- award_emoji.destroy!
- end
+ context 'when an emoji is awarded to a note in discussion' do
+ before do
+ travel_to(1.minute.from_now) do
+ create(:award_emoji, awardable: first_note)
end
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
end
+ end
- context 'when the diff note position changes' do
- before do
- # This replicates a position change wherein timestamps aren't updated
- # which is why `Gitlab::Timeless.timeless` is utilized. This is the
- # same approach being used in Discussions::UpdateDiffPositionService
- # which is responsible for updating the positions of diff discussions
- # when MR updates.
- first_note.position = Gitlab::Diff::Position.new(
- old_path: first_note.position.old_path,
- new_path: first_note.position.new_path,
- old_line: first_note.position.old_line,
- new_line: first_note.position.new_line + 1,
- diff_refs: first_note.position.diff_refs
- )
-
- Gitlab::Timeless.timeless(first_note, &:save)
+ context 'when an award emoji is removed from a note in discussion' do
+ before do
+ travel_to(1.minute.from_now) do
+ award_emoji.destroy!
end
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
end
+ end
- context 'when the HEAD diff note position changes' do
- before do
- # This replicates a DiffNotePosition change. This is the same approach
- # being used in Discussions::CaptureDiffNotePositionService which is
- # responsible for updating/creating DiffNotePosition of a diff discussions
- # in relation to HEAD diff.
- new_position = Gitlab::Diff::Position.new(
- old_path: first_note.position.old_path,
- new_path: first_note.position.new_path,
- old_line: first_note.position.old_line,
- new_line: first_note.position.new_line + 1,
- diff_refs: first_note.position.diff_refs
- )
-
- DiffNotePosition.create_or_update_for(
- first_note,
- diff_type: :head,
- position: new_position,
- line_code: 'bd4b7bfff3a247ccf6e3371c41ec018a55230bcc_534_521'
- )
- end
+ context 'when the diff note position changes' do
+ before do
+ # This replicates a position change wherein timestamps aren't updated
+ # which is why `Gitlab::Timeless.timeless` is utilized. This is the
+ # same approach being used in Discussions::UpdateDiffPositionService
+ # which is responsible for updating the positions of diff discussions
+ # when MR updates.
+ first_note.position = Gitlab::Diff::Position.new(
+ old_path: first_note.position.old_path,
+ new_path: first_note.position.new_path,
+ old_line: first_note.position.old_line,
+ new_line: first_note.position.new_line + 1,
+ diff_refs: first_note.position.diff_refs
+ )
+
+ Gitlab::Timeless.timeless(first_note, &:save)
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
end
+ end
- context 'when author detail changes' do
- before do
- author.update!(name: "#{author.name} (Updated)")
- end
+ context 'when the HEAD diff note position changes' do
+ before do
+ # This replicates a DiffNotePosition change. This is the same approach
+ # being used in Discussions::CaptureDiffNotePositionService which is
+ # responsible for updating/creating DiffNotePosition of a diff discussions
+ # in relation to HEAD diff.
+ new_position = Gitlab::Diff::Position.new(
+ old_path: first_note.position.old_path,
+ new_path: first_note.position.new_path,
+ old_line: first_note.position.old_line,
+ new_line: first_note.position.new_line + 1,
+ diff_refs: first_note.position.diff_refs
+ )
+
+ DiffNotePosition.create_or_update_for(
+ first_note,
+ diff_type: :head,
+ position: new_position,
+ line_code: 'bd4b7bfff3a247ccf6e3371c41ec018a55230bcc_534_521'
+ )
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
end
+ end
- context 'when author status changes' do
- before do
- Users::SetStatusService.new(author, message: "updated status").execute
- end
+ context 'when author detail changes' do
+ before do
+ author.update!(name: "#{author.name} (Updated)")
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
end
+ end
- context 'when author role changes' do
- before do
- Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(author_membership)
- end
+ context 'when author status changes' do
+ before do
+ Users::SetStatusService.new(author, message: "updated status").execute
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
end
+ end
- context 'when current_user role changes' do
- before do
- Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(project.member(user))
- end
+ context 'when author role changes' do
+ before do
+ Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(author_membership)
+ end
- it_behaves_like 'cache miss' do
- let(:changed_notes) { [first_note, second_note] }
- end
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
end
end
- context 'when disabled_mr_discussions_redis_cache is disabled' do
+ context 'when current_user role changes' do
before do
- stub_feature_flags(disabled_mr_discussions_redis_cache: false)
- send_request
+ Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(project.member(user))
end
- it_behaves_like 'cache hit'
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
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 defb35fd496..666dc42bcab 100644
--- a/spec/requests/projects/settings/access_tokens_controller_spec.rb
+++ b/spec/requests/projects/settings/access_tokens_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::Settings::AccessTokensController, feature_category: :authentication_and_authorization do
+RSpec.describe Projects::Settings::AccessTokensController, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:resource) { create(:project, group: group) }
diff --git a/spec/requests/projects/uploads_spec.rb b/spec/requests/projects/uploads_spec.rb
index aec2636b69c..a591f479763 100644
--- a/spec/requests/projects/uploads_spec.rb
+++ b/spec/requests/projects/uploads_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'File uploads', feature_category: :not_owned do
+RSpec.describe 'File uploads', feature_category: :shared do
include WorkhorseHelpers
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/requests/projects/wikis_controller_spec.rb b/spec/requests/projects/wikis_controller_spec.rb
new file mode 100644
index 00000000000..4768e7134e8
--- /dev/null
+++ b/spec/requests/projects/wikis_controller_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::WikisController, feature_category: :wiki do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
+ let_it_be(:project_wiki) { create(:project_wiki, project: project, user: user) }
+ let_it_be(:wiki_page) do
+ create(:wiki_page,
+ wiki: project_wiki,
+ title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})")
+ end
+
+ let_it_be(:csp_nonce) { 'just=some=noncense' }
+
+ before do
+ sign_in(user)
+
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:content_security_policy_nonce).and_return(csp_nonce)
+ end
+ end
+
+ shared_examples 'embed.diagrams.net frame-src directive' do
+ it 'adds drawio frame-src directive to the Content Security Policy header' do
+ frame_src = response.headers['Content-Security-Policy'].split(';')
+ .map(&:strip)
+ .find { |entry| entry.starts_with?('frame-src') }
+
+ expect(frame_src).to include('https://embed.diagrams.net')
+ end
+ end
+
+ describe 'CSP policy' do
+ describe '#new' do
+ before do
+ get wiki_path(project_wiki, action: :new)
+ end
+
+ it_behaves_like 'embed.diagrams.net frame-src directive'
+ end
+
+ describe '#edit' do
+ before do
+ get wiki_page_path(project_wiki, wiki_page, action: 'edit')
+ end
+
+ it_behaves_like 'embed.diagrams.net frame-src directive'
+ end
+
+ describe '#create' do
+ before do
+ # Creating a page with an invalid title to render edit page
+ post wiki_path(project_wiki, action: 'create'), params: { wiki: { title: 'home' } }
+ end
+
+ it_behaves_like 'embed.diagrams.net frame-src directive'
+ end
+
+ describe '#update' do
+ before do
+ # Setting an invalid page title to render edit page
+ put wiki_page_path(project_wiki, wiki_page), params: { wiki: { title: '' } }
+ print(response.body)
+ end
+
+ it_behaves_like 'embed.diagrams.net frame-src directive'
+ end
+ end
+end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index 91595f7826a..0dd8a15c3a4 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_caching,
-feature_category: :authentication_and_authorization do
+feature_category: :system_access do
include RackAttackSpecHelpers
include SessionHelpers
diff --git a/spec/requests/sandbox_controller_spec.rb b/spec/requests/sandbox_controller_spec.rb
index 77913065380..26a7422680c 100644
--- a/spec/requests/sandbox_controller_spec.rb
+++ b/spec/requests/sandbox_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SandboxController, feature_category: :not_owned do
+RSpec.describe SandboxController, feature_category: :shared do
describe 'GET #mermaid' do
it 'renders page without template' do
get sandbox_mermaid_path
diff --git a/spec/requests/sessions_spec.rb b/spec/requests/sessions_spec.rb
index 7b3fd23980a..bc4ac3b7335 100644
--- a/spec/requests/sessions_spec.rb
+++ b/spec/requests/sessions_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Sessions', feature_category: :authentication_and_authorization do
+RSpec.describe 'Sessions', feature_category: :system_access do
context 'authentication', :allow_forgery_protection do
let(:user) { create(:user) }
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index 11d8be24e06..75ae0c970c0 100644
--- a/spec/requests/users_controller_spec.rb
+++ b/spec/requests/users_controller_spec.rb
@@ -174,39 +174,95 @@ RSpec.describe UsersController, feature_category: :user_management do
end
context 'requested in json format' do
- let(:project) { create(:project) }
+ context 'when profile_tabs_vue feature flag is turned OFF' do
+ let(:project) { create(:project) }
- before do
- project.add_developer(user)
- Gitlab::DataBuilder::Push.build_sample(project, user)
+ before do
+ project.add_developer(user)
+ Gitlab::DataBuilder::Push.build_sample(project, user)
+ stub_feature_flags(profile_tabs_vue: false)
+ sign_in(user)
+ end
- sign_in(user)
- end
+ it 'loads events' do
+ get user_activity_url user.username, format: :json
- it 'loads events' do
- get user_activity_url user.username, format: :json
+ expect(response.media_type).to eq('application/json')
+ expect(Gitlab::Json.parse(response.body)['count']).to eq(1)
+ end
- expect(response.media_type).to eq('application/json')
- expect(Gitlab::Json.parse(response.body)['count']).to eq(1)
- end
+ it 'hides events if the user cannot read cross project' do
+ allow(Ability).to receive(:allowed?).and_call_original
+ expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
- it 'hides events if the user cannot read cross project' do
- allow(Ability).to receive(:allowed?).and_call_original
- expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
+ get user_activity_url user.username, format: :json
- get user_activity_url user.username, format: :json
+ expect(response.media_type).to eq('application/json')
+ expect(Gitlab::Json.parse(response.body)['count']).to eq(0)
+ end
- expect(response.media_type).to eq('application/json')
- expect(Gitlab::Json.parse(response.body)['count']).to eq(0)
+ it 'hides events if the user has a private profile' do
+ Gitlab::DataBuilder::Push.build_sample(project, private_user)
+
+ get user_activity_url private_user.username, format: :json
+
+ expect(response.media_type).to eq('application/json')
+ expect(Gitlab::Json.parse(response.body)['count']).to eq(0)
+ end
end
- it 'hides events if the user has a private profile' do
- Gitlab::DataBuilder::Push.build_sample(project, private_user)
+ context 'when profile_tabs_vue feature flag is turned ON' do
+ let(:project) { create(:project) }
- get user_activity_url private_user.username, format: :json
+ before do
+ project.add_developer(user)
+ Gitlab::DataBuilder::Push.build_sample(project, user)
+ stub_feature_flags(profile_tabs_vue: true)
+ sign_in(user)
+ end
- expect(response.media_type).to eq('application/json')
- expect(Gitlab::Json.parse(response.body)['count']).to eq(0)
+ it 'loads events' do
+ get user_activity_url user.username, format: :json
+
+ expect(response.media_type).to eq('application/json')
+ expect(Gitlab::Json.parse(response.body).count).to eq(1)
+ end
+
+ it 'hides events if the user cannot read cross project' do
+ allow(Ability).to receive(:allowed?).and_call_original
+ expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
+
+ get user_activity_url user.username, format: :json
+
+ expect(response.media_type).to eq('application/json')
+ expect(Gitlab::Json.parse(response.body).count).to eq(0)
+ end
+
+ it 'hides events if the user has a private profile' do
+ Gitlab::DataBuilder::Push.build_sample(project, private_user)
+
+ get user_activity_url private_user.username, format: :json
+
+ expect(response.media_type).to eq('application/json')
+ expect(Gitlab::Json.parse(response.body).count).to eq(0)
+ end
+
+ it 'hides events if the user has a private profile' do
+ project = create(:project, :private)
+ private_event_user = create(:user, include_private_contributions: true)
+ push_data = Gitlab::DataBuilder::Push.build_sample(project, private_event_user)
+ EventCreateService.new.push(project, private_event_user, push_data)
+
+ get user_activity_url private_event_user.username, format: :json
+
+ response_body = Gitlab::Json.parse(response.body)
+ event = response_body.first
+ expect(response.media_type).to eq('application/json')
+ expect(response_body.count).to eq(1)
+ expect(event).to include('created_at', 'author', 'action')
+ expect(event['action']).to eq('private')
+ expect(event).not_to include('ref', 'commit', 'target', 'resource_parent')
+ end
end
end
end
diff --git a/spec/requests/verifies_with_email_spec.rb b/spec/requests/verifies_with_email_spec.rb
index 8a6a7e717ff..3184fe151be 100644
--- a/spec/requests/verifies_with_email_spec.rb
+++ b/spec/requests/verifies_with_email_spec.rb
@@ -42,7 +42,7 @@ feature_category: :user_management do
shared_examples_for 'two factor prompt or successful login' do
it 'shows the 2FA prompt when enabled or redirects to the root path' do
if user.two_factor_enabled?
- expect(response.body).to include('Two-factor authentication code')
+ expect(response.body).to include('Enter verification code')
else
expect(response).to redirect_to(root_path)
end
diff --git a/spec/routing/import_routing_spec.rb b/spec/routing/import_routing_spec.rb
index ac3f2a4b7ca..4d6090d6027 100644
--- a/spec/routing/import_routing_spec.rb
+++ b/spec/routing/import_routing_spec.rb
@@ -75,6 +75,10 @@ RSpec.describe Import::GithubController, 'routing' do
it 'to #cancel_all' do
expect(post('/import/github/cancel_all')).to route_to('import/github#cancel_all')
end
+
+ it 'to #counts' do
+ expect(get('/import/github/counts')).to route_to('import/github#counts')
+ end
end
# personal_access_token_import_gitea POST /import/gitea/personal_access_token(.:format) import/gitea#personal_access_token
diff --git a/spec/routing/user_routing_spec.rb b/spec/routing/user_routing_spec.rb
index 7bb589565fa..b155560c9f0 100644
--- a/spec/routing/user_routing_spec.rb
+++ b/spec/routing/user_routing_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'user routing', :clean_gitlab_redis_sessions, feature_category: :authentication_and_authorization do
+RSpec.describe 'user routing', :clean_gitlab_redis_sessions, feature_category: :system_access do
include SessionHelpers
context 'when GitHub OAuth on project import is cancelled' do
diff --git a/spec/rubocop/cop/background_migration/missing_dictionary_file_spec.rb b/spec/rubocop/cop/background_migration/missing_dictionary_file_spec.rb
new file mode 100644
index 00000000000..32b958426b9
--- /dev/null
+++ b/spec/rubocop/cop/background_migration/missing_dictionary_file_spec.rb
@@ -0,0 +1,137 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+require_relative '../../../../rubocop/cop/background_migration/missing_dictionary_file'
+
+RSpec.describe RuboCop::Cop::BackgroundMigration::MissingDictionaryFile, feature_category: :database do
+ let(:config) do
+ RuboCop::Config.new(
+ 'BackgroundMigration/MissingDictionaryFile' => {
+ 'EnforcedSince' => 20230307160251
+ }
+ )
+ end
+
+ context 'for non post migrations' do
+ before do
+ allow(cop).to receive(:in_post_deployment_migration?).and_return(false)
+ end
+
+ it 'does not throw any offense' do
+ expect_no_offenses(<<~RUBY)
+ class QueueMyMigration < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'MyMigration'
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :users,
+ :id
+ )
+ end
+ end
+ RUBY
+ end
+ end
+
+ context 'for post migrations' do
+ before do
+ allow(cop).to receive(:in_post_deployment_migration?).and_return(true)
+ end
+
+ context 'without enqueuing batched migrations' do
+ it 'does not throw any offense' do
+ expect_no_offenses(<<~RUBY)
+ class CreateTestTable < Gitlab::Database::Migration[2.1]
+ def change
+ create_table(:tests)
+ end
+ end
+ RUBY
+ end
+ end
+
+ context 'with enqueuing batched migration' do
+ let(:rails_root) { File.expand_path('../../../..', __dir__) }
+ let(:dictionary_file_path) { File.join(rails_root, 'db/docs/batched_background_migrations/my_migration.yml') }
+
+ context 'for migrations before enforced time' do
+ before do
+ allow(cop).to receive(:version).and_return(20230307160250)
+ end
+
+ it 'does not throw any offenses' do
+ expect_no_offenses(<<~RUBY)
+ class QueueMyMigration < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'MyMigration'
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :users,
+ :id
+ )
+ end
+ end
+ RUBY
+ end
+ end
+
+ context 'for migrations after enforced time' do
+ before do
+ allow(cop).to receive(:version).and_return(20230307160252)
+ end
+
+ it 'throws offense on not having the appropriate dictionary file with migration name as a constant' do
+ expect_offense(<<~RUBY)
+ class QueueMyMigration < Gitlab::Database::Migration[2.1]
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{format("Missing %{file_name}. Use the generator 'batched_background_migration' to create dictionary files automatically. For more details refer: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#generator", file_name: dictionary_file_path)}
+ MIGRATION = 'MyMigration'
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :users,
+ :id
+ )
+ end
+ end
+ RUBY
+ end
+
+ it 'throws offense on not having the appropriate dictionary file with migration name as a variable' do
+ expect_offense(<<~RUBY)
+ class QueueMyMigration < Gitlab::Database::Migration[2.1]
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{format("Missing %{file_name}. Use the generator 'batched_background_migration' to create dictionary files automatically. For more details refer: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#generator", file_name: dictionary_file_path)}
+ def up
+ queue_batched_background_migration(
+ 'MyMigration',
+ :users,
+ :id
+ )
+ end
+ end
+ RUBY
+ end
+
+ it 'does not throw offense with appropriate dictionary file' do
+ expect(File).to receive(:exist?).with(dictionary_file_path).and_return(true)
+
+ expect_no_offenses(<<~RUBY)
+ class QueueMyMigration < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'MyMigration'
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :users,
+ :id
+ )
+ end
+ end
+ RUBY
+ end
+ end
+ end
+ end
+end
diff --git a/spec/rubocop/cop/gitlab/doc_url_spec.rb b/spec/rubocop/cop/gitlab/doc_url_spec.rb
index 4a7ef14ccbc..957edc8286b 100644
--- a/spec/rubocop/cop/gitlab/doc_url_spec.rb
+++ b/spec/rubocop/cop/gitlab/doc_url_spec.rb
@@ -3,7 +3,7 @@
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/doc_url'
-RSpec.describe RuboCop::Cop::Gitlab::DocUrl, feature_category: :not_owned do
+RSpec.describe RuboCop::Cop::Gitlab::DocUrl, feature_category: :shared do
context 'when string literal is added with docs url prefix' do
context 'when inlined' do
it 'registers an offense' do
diff --git a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
index bfc0cebe203..9d550d9c56e 100644
--- a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
+++ b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
@@ -205,14 +205,4 @@ RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do
include_examples 'sets flag as used', 'deduplicate :delayed, feature_flag: :foo', 'foo'
include_examples 'does not set any flags as used', 'deduplicate :delayed'
end
-
- describe "tracking of usage data metrics known events happens at the beginning of inspection" do
- let(:usage_data_counters_known_event_feature_flags) { ['an_event_feature_flag'] }
-
- before do
- allow(cop).to receive(:usage_data_counters_known_event_feature_flags).and_return(usage_data_counters_known_event_feature_flags)
- end
-
- include_examples 'sets flag as used', "FEATURE_FLAG = :foo", %w[foo an_event_feature_flag]
- end
end
diff --git a/spec/rubocop/cop/lint/last_keyword_argument_spec.rb b/spec/rubocop/cop/lint/last_keyword_argument_spec.rb
index 53f19cd01ee..edd54a40b79 100644
--- a/spec/rubocop/cop/lint/last_keyword_argument_spec.rb
+++ b/spec/rubocop/cop/lint/last_keyword_argument_spec.rb
@@ -3,7 +3,7 @@
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/lint/last_keyword_argument'
-RSpec.describe RuboCop::Cop::Lint::LastKeywordArgument, :ruby27, feature_category: :not_owned do
+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
diff --git a/spec/rubocop/cop/rspec/avoid_test_prof_spec.rb b/spec/rubocop/cop/rspec/avoid_test_prof_spec.rb
index b180134b226..db8c7b1d783 100644
--- a/spec/rubocop/cop/rspec/avoid_test_prof_spec.rb
+++ b/spec/rubocop/cop/rspec/avoid_test_prof_spec.rb
@@ -5,7 +5,7 @@ require 'rspec-parameterized'
require_relative '../../../../rubocop/cop/rspec/avoid_test_prof'
-RSpec.describe RuboCop::Cop::RSpec::AvoidTestProf, feature_category: :not_owned do
+RSpec.describe RuboCop::Cop::RSpec::AvoidTestProf, feature_category: :shared do
using RSpec::Parameterized::TableSyntax
context 'when there are offenses' do
diff --git a/spec/scripts/database/schema_validator_spec.rb b/spec/scripts/database/schema_validator_spec.rb
new file mode 100644
index 00000000000..13be8e291da
--- /dev/null
+++ b/spec/scripts/database/schema_validator_spec.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+require_relative '../../../scripts/database/schema_validator'
+
+RSpec.describe SchemaValidator, feature_category: :database do
+ subject(:validator) { described_class.new }
+
+ describe "#validate!" do
+ before do
+ allow(validator).to receive(:committed_migrations).and_return(committed_migrations)
+ allow(validator).to receive(:run).and_return(schema_changes)
+ end
+
+ context 'when schema changes are introduced without migrations' do
+ let(:committed_migrations) { [] }
+ let(:schema_changes) { 'db/structure.sql' }
+
+ it 'terminates the execution' do
+ expect { validator.validate! }.to raise_error(SystemExit)
+ end
+ end
+
+ context 'when schema changes are introduced with migrations' do
+ let(:committed_migrations) { ['20211006103122_my_migration.rb'] }
+ let(:schema_changes) { 'db/structure.sql' }
+ let(:command) { 'git diff db/structure.sql -- db/structure.sql' }
+ let(:base_message) { 'db/structure.sql was changed, and no migrations were added' }
+
+ before do
+ allow(validator).to receive(:die)
+ end
+
+ it 'skips schema validations' do
+ expect(validator.validate!).to be_nil
+ end
+ end
+
+ context 'when skipping validations through ENV variable' do
+ let(:committed_migrations) { [] }
+ let(:schema_changes) { 'db/structure.sql' }
+
+ before do
+ stub_env('ALLOW_SCHEMA_CHANGES', true)
+ end
+
+ it 'skips schema validations' do
+ expect(validator.validate!).to be_nil
+ end
+ end
+
+ context 'when skipping validations through commit message' do
+ let(:committed_migrations) { [] }
+ let(:schema_changes) { 'db/structure.sql' }
+ let(:commit_message) { "Changes db/strucure.sql file\nskip-db-structure-check" }
+
+ before do
+ allow(validator).to receive(:run).and_return(commit_message)
+ end
+
+ it 'skips schema validations' do
+ expect(validator.validate!).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/scripts/generate_rspec_pipeline_spec.rb b/spec/scripts/generate_rspec_pipeline_spec.rb
new file mode 100644
index 00000000000..b3eaf9e9127
--- /dev/null
+++ b/spec/scripts/generate_rspec_pipeline_spec.rb
@@ -0,0 +1,198 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'tempfile'
+
+require_relative '../../scripts/generate_rspec_pipeline'
+
+RSpec.describe GenerateRspecPipeline, :silence_stdout, feature_category: :tooling do
+ describe '#generate!' do
+ let!(:rspec_files) { Tempfile.new(['rspec_files_path', '.txt']) }
+ let(:rspec_files_content) do
+ "spec/migrations/a_spec.rb spec/migrations/b_spec.rb " \
+ "spec/lib/gitlab/background_migration/a_spec.rb spec/lib/gitlab/background_migration/b_spec.rb " \
+ "spec/models/a_spec.rb spec/models/b_spec.rb " \
+ "spec/controllers/a_spec.rb spec/controllers/b_spec.rb " \
+ "spec/features/a_spec.rb spec/features/b_spec.rb"
+ end
+
+ let(:pipeline_template) { Tempfile.new(['pipeline_template', '.yml.erb']) }
+ let(:pipeline_template_content) do
+ <<~YAML
+ <% if rspec_files_per_test_level[:migration][:files].size > 0 %>
+ rspec migration:
+ <% if rspec_files_per_test_level[:migration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:migration][:parallelization] %>
+ <% end %>
+ <% end %>
+ <% if rspec_files_per_test_level[:background_migration][:files].size > 0 %>
+ rspec background_migration:
+ <% if rspec_files_per_test_level[:background_migration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:background_migration][:parallelization] %>
+ <% end %>
+ <% end %>
+ <% if rspec_files_per_test_level[:unit][:files].size > 0 %>
+ rspec unit:
+ <% if rspec_files_per_test_level[:unit][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:unit][:parallelization] %>
+ <% end %>
+ <% end %>
+ <% if rspec_files_per_test_level[:integration][:files].size > 0 %>
+ rspec integration:
+ <% if rspec_files_per_test_level[:integration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:integration][:parallelization] %>
+ <% end %>
+ <% end %>
+ <% if rspec_files_per_test_level[:system][:files].size > 0 %>
+ rspec system:
+ <% if rspec_files_per_test_level[:system][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:system][:parallelization] %>
+ <% end %>
+ <% end %>
+ YAML
+ end
+
+ let(:knapsack_report) { Tempfile.new(['knapsack_report', '.json']) }
+ let(:knapsack_report_content) do
+ <<~JSON
+ {
+ "spec/migrations/a_spec.rb": 360.3,
+ "spec/migrations/b_spec.rb": 180.1,
+ "spec/lib/gitlab/background_migration/a_spec.rb": 60.5,
+ "spec/lib/gitlab/background_migration/b_spec.rb": 180.3,
+ "spec/models/a_spec.rb": 360.2,
+ "spec/models/b_spec.rb": 180.6,
+ "spec/controllers/a_spec.rb": 60.2,
+ "spec/controllers/ab_spec.rb": 180.4,
+ "spec/features/a_spec.rb": 360.1,
+ "spec/features/b_spec.rb": 180.5
+ }
+ JSON
+ end
+
+ around do |example|
+ rspec_files.write(rspec_files_content)
+ rspec_files.rewind
+ pipeline_template.write(pipeline_template_content)
+ pipeline_template.rewind
+ knapsack_report.write(knapsack_report_content)
+ knapsack_report.rewind
+ example.run
+ ensure
+ rspec_files.close
+ rspec_files.unlink
+ pipeline_template.close
+ pipeline_template.unlink
+ knapsack_report.close
+ knapsack_report.unlink
+ end
+
+ context 'when rspec_files and pipeline_template_path exists' do
+ subject do
+ described_class.new(
+ rspec_files_path: rspec_files.path,
+ pipeline_template_path: pipeline_template.path
+ )
+ end
+
+ it 'generates the pipeline config with default parallelization' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml"))
+ .to eq(
+ "rspec migration:\nrspec background_migration:\nrspec unit:\n" \
+ "rspec integration:\nrspec system:"
+ )
+ end
+
+ context 'when parallelization > 0' do
+ before do
+ stub_const("#{described_class}::DEFAULT_AVERAGE_TEST_FILE_DURATION_IN_SECONDS", 360)
+ end
+
+ it 'generates the pipeline config' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml"))
+ .to eq(
+ "rspec migration:\n parallel: 2\nrspec background_migration:\n parallel: 2\n" \
+ "rspec unit:\n parallel: 2\nrspec integration:\n parallel: 2\n" \
+ "rspec system:\n parallel: 2"
+ )
+ end
+ end
+
+ context 'when parallelization > MAX_NODES_COUNT' do
+ let(:rspec_files_content) do
+ Array.new(51) { |i| "spec/migrations/#{i}_spec.rb" }.join(' ')
+ end
+
+ before do
+ stub_const(
+ "#{described_class}::DEFAULT_AVERAGE_TEST_FILE_DURATION_IN_SECONDS",
+ described_class::OPTIMAL_TEST_JOB_DURATION_IN_SECONDS
+ )
+ end
+
+ it 'generates the pipeline config with max parallelization of 50' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml")).to eq("rspec migration:\n parallel: 50")
+ end
+ end
+ end
+
+ context 'when knapsack_report_path is given' do
+ subject do
+ described_class.new(
+ rspec_files_path: rspec_files.path,
+ pipeline_template_path: pipeline_template.path,
+ knapsack_report_path: knapsack_report.path
+ )
+ end
+
+ it 'generates the pipeline config with parallelization based on Knapsack' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml"))
+ .to eq(
+ "rspec migration:\n parallel: 2\nrspec background_migration:\n" \
+ "rspec unit:\n parallel: 2\nrspec integration:\n" \
+ "rspec system:\n parallel: 2"
+ )
+ end
+
+ context 'and Knapsack report does not contain valid JSON' do
+ let(:knapsack_report_content) { "#{super()}," }
+
+ it 'generates the pipeline config with default parallelization' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml"))
+ .to eq(
+ "rspec migration:\nrspec background_migration:\nrspec unit:\n" \
+ "rspec integration:\nrspec system:"
+ )
+ end
+ end
+ end
+
+ context 'when rspec_files does not exist' do
+ subject { described_class.new(rspec_files_path: nil, pipeline_template_path: pipeline_template.path) }
+
+ it 'generates the pipeline config using the no-op template' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml")).to include("no-op:")
+ end
+ end
+
+ context 'when pipeline_template_path does not exist' do
+ subject { described_class.new(rspec_files_path: rspec_files.path, pipeline_template_path: nil) }
+
+ it 'generates the pipeline config using the no-op template' do
+ expect { subject }.to raise_error(ArgumentError)
+ end
+ end
+ end
+end
diff --git a/spec/scripts/lib/glfm/shared_spec.rb b/spec/scripts/lib/glfm/shared_spec.rb
index 3717c7ce18f..d407bd49d75 100644
--- a/spec/scripts/lib/glfm/shared_spec.rb
+++ b/spec/scripts/lib/glfm/shared_spec.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'tmpdir'
require_relative '../../../../scripts/lib/glfm/shared'
-RSpec.describe Glfm::Shared do
+RSpec.describe Glfm::Shared, feature_category: :team_planning do
let(:instance) do
Class.new do
include Glfm::Shared
diff --git a/spec/scripts/pipeline/create_test_failure_issues_spec.rb b/spec/scripts/pipeline/create_test_failure_issues_spec.rb
new file mode 100644
index 00000000000..fa27727542e
--- /dev/null
+++ b/spec/scripts/pipeline/create_test_failure_issues_spec.rb
@@ -0,0 +1,145 @@
+# frozen_string_literal: true
+
+# rubocop:disable RSpec/VerifiedDoubles
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+require_relative '../../../scripts/pipeline/create_test_failure_issues'
+
+RSpec.describe CreateTestFailureIssues, feature_category: :tooling do
+ describe CreateTestFailureIssue do
+ let(:env) do
+ {
+ 'CI_JOB_URL' => 'ci_job_url',
+ 'CI_PIPELINE_URL' => 'ci_pipeline_url'
+ }
+ end
+
+ let(:project) { 'group/project' }
+ let(:api_token) { 'api_token' }
+ let(:creator) { described_class.new(project: project, api_token: api_token) }
+ let(:test_name) { 'The test description' }
+ let(:test_file) { 'spec/path/to/file_spec.rb' }
+ let(:test_file_content) do
+ <<~CONTENT
+ # comment
+
+ RSpec.describe Foo, feature_category: :source_code_management do
+ end
+
+ CONTENT
+ end
+
+ let(:test_file_stub) { double(read: test_file_content) }
+ let(:failed_test) do
+ {
+ 'name' => test_name,
+ 'file' => test_file,
+ 'job_url' => 'job_url'
+ }
+ end
+
+ let(:categories_mapping) do
+ {
+ 'source_code_management' => {
+ 'group' => 'source_code',
+ 'label' => 'Category:Source Code Management'
+ }
+ }
+ end
+
+ let(:groups_mapping) do
+ {
+ 'source_code' => {
+ 'label' => 'group::source_code'
+ }
+ }
+ end
+
+ before do
+ stub_env(env)
+ end
+
+ describe '#find' do
+ let(:expected_payload) do
+ {
+ state: 'opened',
+ search: "#{failed_test['file']} - ID: #{Digest::SHA256.hexdigest(failed_test['name'])[0...12]}"
+ }
+ end
+
+ let(:find_issue_stub) { double('FindIssues') }
+ let(:issue_stub) { double(title: expected_payload[:title], web_url: 'issue_web_url') }
+
+ before do
+ allow(creator).to receive(:puts)
+ end
+
+ it 'calls FindIssues#execute(payload)' do
+ expect(FindIssues).to receive(:new).with(project: project, api_token: api_token).and_return(find_issue_stub)
+ expect(find_issue_stub).to receive(:execute).with(expected_payload).and_return([issue_stub])
+
+ creator.find(failed_test)
+ end
+
+ context 'when no issues are found' do
+ it 'calls FindIssues#execute(payload)' do
+ expect(FindIssues).to receive(:new).with(project: project, api_token: api_token).and_return(find_issue_stub)
+ expect(find_issue_stub).to receive(:execute).with(expected_payload).and_return([])
+
+ creator.find(failed_test)
+ end
+ end
+ end
+
+ describe '#create' do
+ let(:expected_description) do
+ <<~DESCRIPTION
+ ### Full description
+
+ `#{failed_test['name']}`
+
+ ### File path
+
+ `#{failed_test['file']}`
+
+ <!-- Don't add anything after the report list since it's updated automatically -->
+ ### Reports
+
+ - #{failed_test['job_url']} (#{env['CI_PIPELINE_URL']})
+ DESCRIPTION
+ end
+
+ let(:expected_payload) do
+ {
+ title: "#{failed_test['file']} - ID: #{Digest::SHA256.hexdigest(failed_test['name'])[0...12]}",
+ description: expected_description,
+ labels: described_class::DEFAULT_LABELS.map { |label| "wip-#{label}" } + [
+ "wip-#{categories_mapping['source_code_management']['label']}", "wip-#{groups_mapping['source_code']['label']}" # rubocop:disable Layout/LineLength
+ ]
+ }
+ end
+
+ let(:create_issue_stub) { double('CreateIssue') }
+ let(:issue_stub) { double(title: expected_payload[:title], web_url: 'issue_web_url') }
+
+ before do
+ allow(creator).to receive(:puts)
+ allow(File).to receive(:open).and_call_original
+ allow(File).to receive(:open).with(File.expand_path(File.join('..', '..', '..', test_file), __dir__))
+ .and_return(test_file_stub)
+ allow(creator).to receive(:categories_mapping).and_return(categories_mapping)
+ allow(creator).to receive(:groups_mapping).and_return(groups_mapping)
+ end
+
+ it 'calls CreateIssue#execute(payload)' do
+ expect(CreateIssue).to receive(:new).with(project: project, api_token: api_token).and_return(create_issue_stub)
+ expect(create_issue_stub).to receive(:execute).with(expected_payload).and_return(issue_stub)
+
+ creator.create(failed_test) # rubocop:disable Rails/SaveBang
+ end
+ end
+ end
+end
+# rubocop:enable RSpec/VerifiedDoubles
diff --git a/spec/scripts/pipeline_test_report_builder_spec.rb b/spec/scripts/pipeline_test_report_builder_spec.rb
index e7529eb0d41..bee2a4a5835 100644
--- a/spec/scripts/pipeline_test_report_builder_spec.rb
+++ b/spec/scripts/pipeline_test_report_builder_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe PipelineTestReportBuilder, feature_category: :tooling do
let(:options) do
described_class::DEFAULT_OPTIONS.merge(
target_project: 'gitlab-org/gitlab',
+ current_pipeline_id: '42',
mr_id: '999',
instance_base_url: 'https://gitlab.com',
output_file_path: output_file_path
@@ -191,10 +192,14 @@ RSpec.describe PipelineTestReportBuilder, feature_category: :tooling do
context 'for latest pipeline' do
let(:failed_build_uri) { "#{latest_pipeline_url}/tests/suite.json?build_ids[]=#{failed_build_id}" }
+ let(:current_pipeline_uri) do
+ "#{options[:api_endpoint]}/projects/#{options[:target_project]}/pipelines/#{options[:current_pipeline_id]}"
+ end
subject { described_class.new(options.merge(pipeline_index: :latest)) }
it 'fetches builds from pipeline related to MR' do
+ expect(subject).to receive(:fetch).with(current_pipeline_uri).and_return(mr_pipelines[0])
expect(subject).to receive(:fetch).with(failed_build_uri).and_return(test_report_for_build)
subject.test_report_for_pipeline
diff --git a/spec/scripts/review_apps/automated_cleanup_spec.rb b/spec/scripts/review_apps/automated_cleanup_spec.rb
new file mode 100644
index 00000000000..546bf55a934
--- /dev/null
+++ b/spec/scripts/review_apps/automated_cleanup_spec.rb
@@ -0,0 +1,261 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'time'
+require_relative '../../../scripts/review_apps/automated_cleanup'
+
+RSpec.describe ReviewApps::AutomatedCleanup, feature_category: :tooling do
+ let(:instance) { described_class.new(options: options) }
+ let(:options) do
+ {
+ project_path: 'my-project-path',
+ gitlab_token: 'glpat-test-secret-token',
+ api_endpoint: 'gitlab.test/api/v4',
+ dry_run: dry_run
+ }
+ end
+
+ let(:kubernetes_client) { instance_double(Tooling::KubernetesClient) }
+ let(:helm_client) { instance_double(Tooling::Helm3Client) }
+ let(:gitlab_client) { double('GitLab') } # rubocop:disable RSpec/VerifiedDoubles
+ let(:dry_run) { false }
+ let(:now) { Time.now }
+ let(:one_day_ago) { (now - (1 * 24 * 3600)) }
+ let(:two_days_ago) { (now - (2 * 24 * 3600)) }
+ let(:three_days_ago) { (now - (3 * 24 * 3600)) }
+
+ before do
+ allow(instance).to receive(:gitlab).and_return(gitlab_client)
+ allow(Time).to receive(:now).and_return(now)
+ allow(Tooling::Helm3Client).to receive(:new).and_return(helm_client)
+ allow(Tooling::KubernetesClient).to receive(:new).and_return(kubernetes_client)
+
+ allow(kubernetes_client).to receive(:cleanup_by_created_at)
+ allow(kubernetes_client).to receive(:cleanup_by_release)
+ allow(kubernetes_client).to receive(:cleanup_review_app_namespaces)
+ allow(kubernetes_client).to receive(:delete_namespaces_by_exact_names)
+ end
+
+ shared_examples 'the days argument is an integer in the correct range' do
+ context 'when days is nil' do
+ let(:days) { nil }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error('days should be an integer between 1 and 365 inclusive! Got 0')
+ end
+ end
+
+ context 'when days is zero' do
+ let(:days) { 0 }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error('days should be an integer between 1 and 365 inclusive! Got 0')
+ end
+ end
+
+ context 'when days is above 365' do
+ let(:days) { 366 }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error('days should be an integer between 1 and 365 inclusive! Got 366')
+ end
+ end
+
+ context 'when days is a string' do
+ let(:days) { '10' }
+
+ it 'does not raise an error' do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context 'when days is a float' do
+ let(:days) { 3.0 }
+
+ it 'does not raise an error' do
+ expect { subject }.not_to raise_error
+ end
+ end
+ end
+
+ describe '#perform_stale_pvc_cleanup!' do
+ subject { instance.perform_stale_pvc_cleanup!(days: days) }
+
+ let(:days) { 2 }
+
+ it_behaves_like 'the days argument is an integer in the correct range'
+
+ it 'performs Kubernetes cleanup by created at' do
+ expect(kubernetes_client).to receive(:cleanup_by_created_at).with(
+ resource_type: 'pvc',
+ created_before: two_days_ago,
+ wait: false
+ )
+
+ subject
+ end
+
+ context 'when the dry-run flag is true' do
+ let(:dry_run) { true }
+
+ it 'does not delete anything' do
+ expect(kubernetes_client).not_to receive(:cleanup_by_created_at)
+ end
+ end
+ end
+
+ describe '#perform_stale_namespace_cleanup!' do
+ subject { instance.perform_stale_namespace_cleanup!(days: days) }
+
+ let(:days) { 2 }
+
+ it_behaves_like 'the days argument is an integer in the correct range'
+
+ it 'performs Kubernetes cleanup for review apps namespaces' do
+ expect(kubernetes_client).to receive(:cleanup_review_app_namespaces).with(
+ created_before: two_days_ago,
+ wait: false
+ )
+
+ subject
+ end
+
+ context 'when the dry-run flag is true' do
+ let(:dry_run) { true }
+
+ it 'does not delete anything' do
+ expect(kubernetes_client).not_to receive(:cleanup_review_app_namespaces)
+ end
+ end
+ end
+
+ describe '#perform_helm_releases_cleanup!' do
+ subject { instance.perform_helm_releases_cleanup!(days: days) }
+
+ let(:days) { 2 }
+ let(:helm_releases) { [] }
+
+ before do
+ allow(helm_client).to receive(:releases).and_return(helm_releases)
+
+ # Silence outputs to stdout
+ allow(instance).to receive(:puts)
+ end
+
+ shared_examples 'deletes the helm release' do
+ let(:releases_names) { helm_releases.map(&:name) }
+
+ before do
+ allow(helm_client).to receive(:delete)
+ allow(kubernetes_client).to receive(:cleanup_by_release)
+ allow(kubernetes_client).to receive(:delete_namespaces_by_exact_names)
+ end
+
+ it 'deletes the helm release' do
+ expect(helm_client).to receive(:delete).with(release_name: releases_names)
+
+ subject
+ end
+
+ it 'empties the k8s resources in the k8s namespace for the release' do
+ expect(kubernetes_client).to receive(:cleanup_by_release).with(release_name: releases_names, wait: false)
+
+ subject
+ end
+
+ it 'deletes the associated k8s namespace' do
+ expect(kubernetes_client).to receive(:delete_namespaces_by_exact_names).with(
+ resource_names: releases_names, wait: false
+ )
+
+ subject
+ end
+ end
+
+ shared_examples 'does not delete the helm release' do
+ it 'does not delete the helm release' do
+ expect(helm_client).not_to receive(:delete)
+
+ subject
+ end
+
+ it 'does not empty the k8s resources in the k8s namespace for the release' do
+ expect(kubernetes_client).not_to receive(:cleanup_by_release)
+
+ subject
+ end
+
+ it 'does not delete the associated k8s namespace' do
+ expect(kubernetes_client).not_to receive(:delete_namespaces_by_exact_names)
+
+ subject
+ end
+ end
+
+ shared_examples 'does nothing on a dry run' do
+ it_behaves_like 'does not delete the helm release'
+ end
+
+ it_behaves_like 'the days argument is an integer in the correct range'
+
+ context 'when the helm release is not a review-app release' do
+ let(:helm_releases) do
+ [
+ Tooling::Helm3Client::Release.new(
+ name: 'review-apps', namespace: 'review-apps', revision: 1, status: 'success', updated: three_days_ago.to_s
+ )
+ ]
+ end
+
+ it_behaves_like 'does not delete the helm release'
+ end
+
+ context 'when the helm release is a review-app release' do
+ let(:helm_releases) do
+ [
+ Tooling::Helm3Client::Release.new(
+ name: 'review-test', namespace: 'review-test', revision: 1, status: status, updated: updated_at
+ )
+ ]
+ end
+
+ context 'when the helm release was deployed recently enough' do
+ let(:updated_at) { one_day_ago.to_s }
+
+ context 'when the helm release is in failed state' do
+ let(:status) { 'failed' }
+
+ it_behaves_like 'deletes the helm release'
+
+ context 'when the dry-run flag is true' do
+ let(:dry_run) { true }
+
+ it_behaves_like 'does nothing on a dry run'
+ end
+ end
+
+ context 'when the helm release is not in failed state' do
+ let(:status) { 'success' }
+
+ it_behaves_like 'does not delete the helm release'
+ end
+ end
+
+ context 'when the helm release was deployed a while ago' do
+ let(:updated_at) { three_days_ago.to_s }
+
+ context 'when the helm release is in failed state' do
+ let(:status) { 'failed' }
+
+ it_behaves_like 'deletes the helm release'
+ end
+
+ context 'when the helm release is not in failed state' do
+ let(:status) { 'success' }
+
+ it_behaves_like 'deletes the helm release'
+ end
+ end
+ end
+ end
+end
diff --git a/spec/serializers/admin/abuse_report_entity_spec.rb b/spec/serializers/admin/abuse_report_entity_spec.rb
new file mode 100644
index 00000000000..7d18310977c
--- /dev/null
+++ b/spec/serializers/admin/abuse_report_entity_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe Admin::AbuseReportEntity, feature_category: :insider_threat do
+ let_it_be(:abuse_report) { build_stubbed(:abuse_report) }
+
+ let(:entity) do
+ described_class.new(abuse_report)
+ end
+
+ describe '#as_json' do
+ subject(:entity_hash) { entity.as_json }
+
+ it 'exposes correct attributes' do
+ expect(entity_hash.keys).to include(
+ :category,
+ :updated_at,
+ :reported_user,
+ :reporter
+ )
+ end
+
+ it 'correctly exposes `reported user`' do
+ expect(entity_hash[:reported_user].keys).to match_array([:name])
+ end
+
+ it 'correctly exposes `reporter`' do
+ expect(entity_hash[:reporter].keys).to match_array([:name])
+ end
+ end
+end
diff --git a/spec/serializers/admin/abuse_report_serializer_spec.rb b/spec/serializers/admin/abuse_report_serializer_spec.rb
new file mode 100644
index 00000000000..5b9c229584b
--- /dev/null
+++ b/spec/serializers/admin/abuse_report_serializer_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe Admin::AbuseReportSerializer, feature_category: :insider_threat do
+ let(:resource) { build(:abuse_report) }
+
+ subject { described_class.new.represent(resource) }
+
+ describe '#represent' do
+ it 'serializes an abuse report' do
+ expect(subject[:id]).to eq resource.id
+ end
+
+ context 'when multiple objects are being serialized' do
+ let(:resource) { build_list(:abuse_report, 2) }
+
+ it 'serializers the array of abuse reports' do
+ expect(subject).not_to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb
index 916798c669c..ea3826f903a 100644
--- a/spec/serializers/build_details_entity_spec.rb
+++ b/spec/serializers/build_details_entity_spec.rb
@@ -285,7 +285,7 @@ RSpec.describe BuildDetailsEntity do
end
context 'when the build has non public archive type artifacts' do
- let(:build) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
+ let(:build) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) }
it 'does not expose non public artifacts' do
expect(subject.keys).not_to include(:artifact)
diff --git a/spec/serializers/cluster_application_entity_spec.rb b/spec/serializers/cluster_application_entity_spec.rb
deleted file mode 100644
index 1e71e45948c..00000000000
--- a/spec/serializers/cluster_application_entity_spec.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ClusterApplicationEntity do
- describe '#as_json' do
- let(:application) { build(:clusters_applications_helm, version: '0.1.1') }
-
- subject { described_class.new(application).as_json }
-
- it 'has name' do
- expect(subject[:name]).to eq(application.name)
- end
-
- it 'has status' do
- expect(subject[:status]).to eq(:not_installable)
- end
-
- it 'has version' do
- expect(subject[:version]).to eq('0.1.1')
- end
-
- it 'has no status_reason' do
- expect(subject[:status_reason]).to be_nil
- end
-
- it 'has can_uninstall' do
- expect(subject[:can_uninstall]).to be_truthy
- end
-
- context 'non-helm application' do
- let(:application) { build(:clusters_applications_runner, version: '0.0.0') }
-
- it 'has update_available' do
- expect(subject[:update_available]).to be_truthy
- end
- end
-
- context 'when application is errored' do
- let(:application) { build(:clusters_applications_helm, :errored) }
-
- it 'has corresponded data' do
- expect(subject[:status]).to eq(:errored)
- expect(subject[:status_reason]).not_to be_nil
- expect(subject[:status_reason]).to eq(application.status_reason)
- end
- end
-
- context 'for ingress application' do
- let(:application) do
- build(
- :clusters_applications_ingress,
- :installed,
- external_ip: '111.222.111.222'
- )
- end
-
- it 'includes external_ip' do
- expect(subject[:external_ip]).to eq('111.222.111.222')
- end
- end
-
- context 'for knative application' do
- let(:pages_domain) { create(:pages_domain, :instance_serverless) }
- let(:application) { build(:clusters_applications_knative, :installed) }
-
- before do
- create(:serverless_domain_cluster, knative: application, pages_domain: pages_domain)
- end
-
- it 'includes available domains' do
- expect(subject[:available_domains].length).to eq(1)
- expect(subject[:available_domains].first).to eq(id: pages_domain.id, domain: pages_domain.domain)
- end
-
- it 'includes pages_domain' do
- expect(subject[:pages_domain]).to eq(id: pages_domain.id, domain: pages_domain.domain)
- end
- end
- end
-end
diff --git a/spec/serializers/cluster_entity_spec.rb b/spec/serializers/cluster_entity_spec.rb
index 2de27deeffe..ff1a9a4feac 100644
--- a/spec/serializers/cluster_entity_spec.rb
+++ b/spec/serializers/cluster_entity_spec.rb
@@ -41,19 +41,5 @@ RSpec.describe ClusterEntity do
expect(subject[:status_reason]).to be_nil
end
end
-
- context 'when no application has been installed' do
- let(:cluster) { create(:cluster, :instance) }
-
- subject { described_class.new(cluster, request: request).as_json[:applications] }
-
- it 'contains helm as not_installable' do
- expect(subject).not_to be_empty
-
- helm = subject[0]
- expect(helm[:name]).to eq('helm')
- expect(helm[:status]).to eq(:not_installable)
- end
- end
end
end
diff --git a/spec/serializers/cluster_serializer_spec.rb b/spec/serializers/cluster_serializer_spec.rb
index 7ec6d3c8bb8..cf102e11b90 100644
--- a/spec/serializers/cluster_serializer_spec.rb
+++ b/spec/serializers/cluster_serializer_spec.rb
@@ -34,13 +34,13 @@ RSpec.describe ClusterSerializer do
end
it 'serializes attrs correctly' do
- is_expected.to contain_exactly(:status, :status_reason, :applications)
+ is_expected.to contain_exactly(:status, :status_reason)
end
end
context 'when provider type is user' do
it 'serializes attrs correctly' do
- is_expected.to contain_exactly(:status, :status_reason, :applications)
+ is_expected.to contain_exactly(:status, :status_reason)
end
end
end
diff --git a/spec/serializers/entity_date_helper_spec.rb b/spec/serializers/entity_date_helper_spec.rb
index 5a4571339b3..70094991c09 100644
--- a/spec/serializers/entity_date_helper_spec.rb
+++ b/spec/serializers/entity_date_helper_spec.rb
@@ -47,8 +47,10 @@ RSpec.describe EntityDateHelper do
end
describe '#remaining_days_in_words' do
+ let(:current_time) { Time.utc(2017, 3, 17) }
+
around do |example|
- travel_to(Time.utc(2017, 3, 17)) { example.run }
+ travel_to(current_time) { example.run }
end
context 'when less than 31 days remaining' do
@@ -74,10 +76,10 @@ RSpec.describe EntityDateHelper do
expect(milestone_remaining).to eq("<strong>1</strong> day remaining")
end
- it 'returns 1 day remaining when queried mid-day' do
- travel_back
+ context 'when queried mid-day' do
+ let(:current_time) { Time.utc(2017, 3, 17, 13, 10) }
- travel_to(Time.utc(2017, 3, 17, 13, 10)) do
+ it 'returns 1 day remaining' do
expect(milestone_remaining).to eq("<strong>1</strong> day remaining")
end
end
diff --git a/spec/serializers/group_issuable_autocomplete_entity_spec.rb b/spec/serializers/group_issuable_autocomplete_entity_spec.rb
index 86ef9dea23b..977239c67da 100644
--- a/spec/serializers/group_issuable_autocomplete_entity_spec.rb
+++ b/spec/serializers/group_issuable_autocomplete_entity_spec.rb
@@ -4,7 +4,8 @@ require 'spec_helper'
RSpec.describe GroupIssuableAutocompleteEntity do
let(:group) { build_stubbed(:group) }
- let(:project) { build_stubbed(:project, group: group) }
+ let(:project_namespace) { build_stubbed(:project_namespace) }
+ let(:project) { build_stubbed(:project, group: group, project_namespace: project_namespace) }
let(:issue) { build_stubbed(:issue, project: project) }
describe '#represent' do
diff --git a/spec/serializers/issue_board_entity_spec.rb b/spec/serializers/issue_board_entity_spec.rb
index 0c9c8f05e17..75aee7f04f0 100644
--- a/spec/serializers/issue_board_entity_spec.rb
+++ b/spec/serializers/issue_board_entity_spec.rb
@@ -57,16 +57,6 @@ RSpec.describe IssueBoardEntity do
context 'when issue is of type task' do
let(:resource) { create(:issue, :task, project: project) }
- context 'when the use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- it 'has a work item path' do
- expect(subject[:real_path]).to eq(project_work_items_path(project, resource.id))
- end
- end
-
it 'has a work item path with iid' do
expect(subject[:real_path]).to eq(project_work_items_path(project, resource.iid, iid_path: true))
end
diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb
index 06d8523b2e7..795cc357a67 100644
--- a/spec/serializers/issue_entity_spec.rb
+++ b/spec/serializers/issue_entity_spec.rb
@@ -17,17 +17,7 @@ RSpec.describe IssueEntity do
context 'when issue is of type task' do
let(:resource) { create(:issue, :task, project: project) }
- context 'when use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- # This was already a path and not a url when the work items change was introduced
- it 'has a work item path' do
- expect(subject[:web_url]).to eq(project_work_items_path(project, resource.id))
- end
- end
-
+ # This was already a path and not a url when the work items change was introduced
it 'has a work item path with iid' do
expect(subject[:web_url]).to eq(project_work_items_path(project, resource.iid, iid_path: true))
end
diff --git a/spec/serializers/linked_project_issue_entity_spec.rb b/spec/serializers/linked_project_issue_entity_spec.rb
index d415d1cbcb2..b863ccde40e 100644
--- a/spec/serializers/linked_project_issue_entity_spec.rb
+++ b/spec/serializers/linked_project_issue_entity_spec.rb
@@ -47,16 +47,6 @@ RSpec.describe LinkedProjectIssueEntity do
context 'when related issue is a task' do
let_it_be(:issue_link) { create(:issue_link, target: create(:issue, :task)) }
- context 'when use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- end
-
- it 'returns a work items path' do
- expect(serialized_entity).to include(path: project_work_items_path(related_issue.project, related_issue.id))
- end
- end
-
it 'returns a work items path using iid' do
expect(serialized_entity).to include(
path: project_work_items_path(related_issue.project, related_issue.iid, iid_path: true)
diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb
index de05d2afd2b..b4cc0b4db36 100644
--- a/spec/serializers/pipeline_details_entity_spec.rb
+++ b/spec/serializers/pipeline_details_entity_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PipelineDetailsEntity do
+RSpec.describe PipelineDetailsEntity, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let(:request) { double('request') }
@@ -32,7 +32,7 @@ RSpec.describe PipelineDetailsEntity do
expect(subject[:details])
.to include :duration, :finished_at
expect(subject[:details])
- .to include :stages, :manual_actions, :scheduled_actions
+ .to include :stages, :manual_actions, :has_manual_actions, :scheduled_actions, :has_scheduled_actions
expect(subject[:details][:status]).to include :icon, :favicon, :text, :label
end
@@ -44,6 +44,30 @@ RSpec.describe PipelineDetailsEntity do
end
end
+ context 'when disable_manual_and_scheduled_actions is true' do
+ let(:pipeline) { create(:ci_pipeline, status: :success) }
+ let(:subject) do
+ described_class.represent(pipeline, request: request, disable_manual_and_scheduled_actions: true).as_json
+ end
+
+ it 'does not contain manual and scheduled actions' do
+ expect(subject[:details])
+ .not_to include :manual_actions, :scheduled_actions
+ end
+ end
+
+ context 'when pipeline has manual builds' do
+ let(:pipeline) { create(:ci_pipeline, status: :success) }
+
+ before do
+ create(:ci_build, :manual, pipeline: pipeline)
+ end
+
+ it 'sets :has_manual_actions to true' do
+ expect(subject[:details][:has_manual_actions]).to eq true
+ end
+ end
+
context 'when pipeline is retryable' do
let(:project) { create(:project) }
diff --git a/spec/serializers/profile/event_entity_spec.rb b/spec/serializers/profile/event_entity_spec.rb
new file mode 100644
index 00000000000..1551fc76466
--- /dev/null
+++ b/spec/serializers/profile/event_entity_spec.rb
@@ -0,0 +1,149 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Profile::EventEntity, feature_category: :user_profile do
+ let_it_be(:group) { create(:group) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
+ let_it_be(:project) { build(:project_empty_repo, group: group) }
+ let_it_be(:user) { create(:user) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
+ let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
+
+ let(:target_user) { user }
+ let(:event) { build(:event, :merged, author: user, project: project, target: merge_request) }
+ let(:request) { double(described_class, current_user: user, target_user: target_user) } # rubocop:disable RSpec/VerifiedDoubles
+ let(:entity) { described_class.new(event, request: request) }
+
+ subject { entity.as_json }
+
+ before do
+ group.add_maintainer(user)
+ end
+
+ it 'exposes fields', :aggregate_failures do
+ expect(subject[:created_at]).to eq(event.created_at)
+ expect(subject[:action]).to eq(event.action)
+ expect(subject[:author][:id]).to eq(target_user.id)
+ expect(subject[:author][:name]).to eq(target_user.name)
+ expect(subject[:author][:path]).to eq(target_user.username)
+ end
+
+ context 'for push events' do
+ let_it_be(:commit_from) { Gitlab::Git::BLANK_SHA }
+ let_it_be(:commit_title) { 'My commit' }
+ let(:event) { build(:push_event, project: project, author: target_user) }
+
+ it 'exposes ref fields' do
+ build(:push_event_payload, event: event, ref_count: 3)
+
+ expect(subject[:ref][:type]).to eq(event.ref_type)
+ expect(subject[:ref][:count]).to eq(event.ref_count)
+ expect(subject[:ref][:name]).to eq(event.ref_name)
+ expect(subject[:ref][:path]).to be_nil
+ end
+
+ shared_examples 'returns ref path' do
+ specify do
+ expect(subject[:ref][:path]).to be_present
+ end
+ end
+
+ context 'with tag' do
+ before do
+ allow(project.repository).to receive(:tag_exists?).and_return(true)
+ build(:push_event_payload, event: event, ref_type: :tag)
+ end
+
+ it_behaves_like 'returns ref path'
+ end
+
+ context 'with branch' do
+ before do
+ allow(project.repository).to receive(:branch_exists?).and_return(true)
+ build(:push_event_payload, event: event, ref_type: :branch)
+ end
+
+ it_behaves_like 'returns ref path'
+ end
+
+ it 'exposes commit fields' do
+ build(:push_event_payload, event: event, commit_title: commit_title, commit_from: commit_from, commit_count: 2)
+
+ compare_path = "/#{group.path}/#{project.path}/-/compare/#{commit_from}...#{event.commit_to}"
+ expect(subject[:commit][:compare_path]).to eq(compare_path)
+ expect(event.commit_id).to include(subject[:commit][:truncated_sha])
+ expect(subject[:commit][:path]).to be_present
+ expect(subject[:commit][:title]).to eq(commit_title)
+ expect(subject[:commit][:count]).to eq(2)
+ expect(commit_from).to include(subject[:commit][:from_truncated_sha])
+ expect(event.commit_to).to include(subject[:commit][:to_truncated_sha])
+ expect(subject[:commit][:create_mr_path]).to be_nil
+ end
+
+ it 'exposes create_mr_path' do
+ allow(project).to receive(:default_branch).and_return('main')
+ allow(project.repository).to receive(:branch_exists?).and_return(true)
+ build(:push_event_payload, event: event, action: :created, commit_from: commit_from, commit_count: 2)
+
+ new_mr_path = "/#{group.path}/#{project.path}/-/merge_requests/new?" \
+ "merge_request%5Bsource_branch%5D=#{event.branch_name}"
+ expect(subject[:commit][:create_mr_path]).to eq(new_mr_path)
+ end
+ end
+
+ context 'with target' do
+ let_it_be(:note) { build(:note_on_merge_request, :with_attachment, noteable: merge_request, project: project) }
+
+ context 'when target does not responds to :reference_link_text' do
+ let(:event) { build(:event, :commented, project: project, target: note, author: target_user) }
+
+ it 'exposes target fields' do
+ expect(subject[:target]).not_to include(:reference_link_text)
+ expect(subject[:target][:target_type]).to eq(note.class.to_s)
+ expect(subject[:target][:target_url]).to be_present
+ expect(subject[:target][:title]).to eq(note.title)
+ expect(subject[:target][:first_line_in_markdown]).to be_present
+ expect(subject[:target][:attachment][:url]).to eq(note.attachment.url)
+ end
+ end
+
+ context 'when target responds to :reference_link_text' do
+ it 'exposes reference_link_text' do
+ expect(subject[:target][:reference_link_text]).to eq(merge_request.reference_link_text)
+ end
+ end
+ end
+
+ context 'with resource parent' do
+ it 'exposes resource parent fields' do
+ resource_parent = event.resource_parent
+
+ expect(subject[:resource_parent][:type]).to eq('project')
+ expect(subject[:resource_parent][:full_name]).to eq(resource_parent.full_name)
+ expect(subject[:resource_parent][:full_path]).to eq(resource_parent.full_path)
+ end
+ end
+
+ context 'for private events' do
+ let(:event) { build(:event, :merged, author: target_user) }
+
+ context 'when include_private_contributions? is true' do
+ let(:target_user) { build(:user, include_private_contributions: true) }
+
+ it 'exposes only created_at, action, and author', :aggregate_failures do
+ expect(subject[:created_at]).to eq(event.created_at)
+ expect(subject[:action]).to eq('private')
+ expect(subject[:author][:id]).to eq(target_user.id)
+ expect(subject[:author][:name]).to eq(target_user.name)
+ expect(subject[:author][:path]).to eq(target_user.username)
+
+ is_expected.not_to include(:ref, :commit, :target, :resource_parent)
+ end
+ end
+
+ context 'when include_private_contributions? is false' do
+ let(:target_user) { build(:user, include_private_contributions: false) }
+
+ it { is_expected.to be_empty }
+ end
+ end
+end
diff --git a/spec/serializers/project_import_entity_spec.rb b/spec/serializers/project_import_entity_spec.rb
index 6d292d18ae7..521d0127dbb 100644
--- a/spec/serializers/project_import_entity_spec.rb
+++ b/spec/serializers/project_import_entity_spec.rb
@@ -5,10 +5,11 @@ require 'spec_helper'
RSpec.describe ProjectImportEntity, feature_category: :importers do
include ImportHelper
- let_it_be(:project) { create(:project, import_status: :started, import_source: 'namespace/project') }
+ let_it_be(:project) { create(:project, import_status: :started, import_source: 'import_user/project') }
let(:provider_url) { 'https://provider.com' }
- let(:entity) { described_class.represent(project, provider_url: provider_url) }
+ let(:client) { nil }
+ let(:entity) { described_class.represent(project, provider_url: provider_url, client: client) }
before do
create(:import_failure, project: project)
@@ -23,6 +24,31 @@ RSpec.describe ProjectImportEntity, feature_category: :importers do
expect(subject[:human_import_status_name]).to eq(project.human_import_status_name)
expect(subject[:provider_link]).to eq(provider_project_link_url(provider_url, project[:import_source]))
expect(subject[:import_error]).to eq(nil)
+ expect(subject[:relation_type]).to eq(nil)
+ end
+
+ context 'when client option present', :clean_gitlab_redis_cache do
+ let(:octokit) { instance_double(Octokit::Client, access_token: 'stub') }
+ let(:client) do
+ instance_double(
+ ::Gitlab::GithubImport::Clients::Proxy,
+ user: { login: 'import_user' }, octokit: octokit
+ )
+ end
+
+ it 'includes relation_type' do
+ expect(subject[:relation_type]).to eq('owned')
+ end
+
+ context 'with remove_legacy_github_client FF is disabled' do
+ before do
+ stub_feature_flags(remove_legacy_github_client: false)
+ end
+
+ it "doesn't include relation_type" do
+ expect(subject[:relation_type]).to eq(nil)
+ end
+ end
end
context 'when import is failed' do
diff --git a/spec/services/access_token_validation_service_spec.rb b/spec/services/access_token_validation_service_spec.rb
index 2bf74d64dc9..4cdce094358 100644
--- a/spec/services/access_token_validation_service_spec.rb
+++ b/spec/services/access_token_validation_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AccessTokenValidationService do
+RSpec.describe AccessTokenValidationService, feature_category: :system_access do
describe ".include_any_scope?" do
let(:request) { double("request") }
diff --git a/spec/services/achievements/award_service_spec.rb b/spec/services/achievements/award_service_spec.rb
new file mode 100644
index 00000000000..fb45a634ddd
--- /dev/null
+++ b/spec/services/achievements/award_service_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Achievements::AwardService, feature_category: :user_profile do
+ describe '#execute' do
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+ let_it_be(:recipient) { create(:user) }
+
+ let(:achievement_id) { achievement.id }
+ let(:recipient_id) { recipient.id }
+
+ subject(:response) { described_class.new(current_user, achievement_id, recipient_id).execute }
+
+ before_all do
+ group.add_developer(developer)
+ group.add_maintainer(maintainer)
+ end
+
+ context 'when user does not have permission' do
+ let(:current_user) { developer }
+
+ it 'returns an error' do
+ expect(response).to be_error
+ expect(response.message).to match_array(
+ ['You have insufficient permissions to award this achievement'])
+ end
+ end
+
+ context 'when user has permission' do
+ let(:current_user) { maintainer }
+
+ it 'creates an achievement' do
+ expect(response).to be_success
+ end
+
+ context 'when the achievement is not persisted' do
+ let(:user_achievement) { instance_double('Achievements::UserAchievement') }
+
+ it 'returns the correct error' do
+ allow(user_achievement).to receive(:persisted?).and_return(false)
+ allow(user_achievement).to receive(:errors).and_return(nil)
+ allow(Achievements::UserAchievement).to receive(:create).and_return(user_achievement)
+
+ expect(response).to be_error
+ expect(response.message).to match_array(["Failed to award achievement"])
+ end
+ end
+
+ context 'when the achievement does not exist' do
+ let(:achievement_id) { non_existing_record_id }
+
+ it 'returns the correct error' do
+ expect(response).to be_error
+ expect(response.message)
+ .to contain_exactly("Couldn't find Achievements::Achievement with 'id'=#{non_existing_record_id}")
+ end
+ end
+
+ context 'when the recipient does not exist' do
+ let(:recipient_id) { non_existing_record_id }
+
+ it 'returns the correct error' do
+ expect(response).to be_error
+ expect(response.message).to contain_exactly("Couldn't find User with 'id'=#{non_existing_record_id}")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/achievements/revoke_service_spec.rb b/spec/services/achievements/revoke_service_spec.rb
new file mode 100644
index 00000000000..c9925f1e3df
--- /dev/null
+++ b/spec/services/achievements/revoke_service_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Achievements::RevokeService, feature_category: :user_profile do
+ describe '#execute' do
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:achievement) { create(:achievement, namespace: group) }
+ let_it_be(:user_achievement) { create(:user_achievement, achievement: achievement) }
+
+ let(:user_achievement_param) { user_achievement }
+
+ subject(:response) { described_class.new(current_user, user_achievement_param).execute }
+
+ before_all do
+ group.add_developer(developer)
+ group.add_maintainer(maintainer)
+ end
+
+ context 'when user does not have permission' do
+ let(:current_user) { developer }
+
+ it 'returns an error' do
+ expect(response).to be_error
+ expect(response.message).to match_array(
+ ['You have insufficient permissions to revoke this achievement'])
+ end
+ end
+
+ context 'when user has permission' do
+ let(:current_user) { maintainer }
+
+ it 'revokes an achievement' do
+ expect(response).to be_success
+ end
+
+ context 'when the achievement has already been revoked' do
+ let_it_be(:revoked_achievement) { create(:user_achievement, :revoked, achievement: achievement) }
+ let(:user_achievement_param) { revoked_achievement }
+
+ it 'returns the correct error' do
+ expect(response).to be_error
+ expect(response.message)
+ .to contain_exactly('This achievement has already been revoked')
+ end
+ end
+
+ context 'when the user achievement fails to save' do
+ let(:user_achievement_param) { instance_double('Achievements::UserAchievement') }
+
+ it 'returns the correct error' do
+ allow(user_achievement_param).to receive(:save).and_return(false)
+ allow(user_achievement_param).to receive(:achievement).and_return(achievement)
+ allow(user_achievement_param).to receive(:revoked?).and_return(false)
+ allow(user_achievement_param).to receive(:errors).and_return(nil)
+ expect(user_achievement_param).to receive(:assign_attributes)
+
+ expect(response).to be_error
+ expect(response.message).to match_array(["Failed to revoke achievement"])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/admin/set_feature_flag_service_spec.rb b/spec/services/admin/set_feature_flag_service_spec.rb
index 45ee914558a..e66802f6332 100644
--- a/spec/services/admin/set_feature_flag_service_spec.rb
+++ b/spec/services/admin/set_feature_flag_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Admin::SetFeatureFlagService do
+RSpec.describe Admin::SetFeatureFlagService, feature_category: :feature_flags do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group) }
diff --git a/spec/services/alert_management/alerts/todo/create_service_spec.rb b/spec/services/alert_management/alerts/todo/create_service_spec.rb
index fa4fd8ed0b2..fd81c0893ed 100644
--- a/spec/services/alert_management/alerts/todo/create_service_spec.rb
+++ b/spec/services/alert_management/alerts/todo/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AlertManagement::Alerts::Todo::CreateService do
+RSpec.describe AlertManagement::Alerts::Todo::CreateService, feature_category: :incident_management do
let_it_be(:user) { create(:user) }
let_it_be(:alert) { create(:alert_management_alert) }
diff --git a/spec/services/alert_management/alerts/update_service_spec.rb b/spec/services/alert_management/alerts/update_service_spec.rb
index 8375c8cdf7d..69e2f2de291 100644
--- a/spec/services/alert_management/alerts/update_service_spec.rb
+++ b/spec/services/alert_management/alerts/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AlertManagement::Alerts::UpdateService do
+RSpec.describe AlertManagement::Alerts::UpdateService, feature_category: :incident_management do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:other_user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
diff --git a/spec/services/alert_management/create_alert_issue_service_spec.rb b/spec/services/alert_management/create_alert_issue_service_spec.rb
index 7255a722d26..b8d93f99ae4 100644
--- a/spec/services/alert_management/create_alert_issue_service_spec.rb
+++ b/spec/services/alert_management/create_alert_issue_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AlertManagement::CreateAlertIssueService do
+RSpec.describe AlertManagement::CreateAlertIssueService, feature_category: :incident_management do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
diff --git a/spec/services/alert_management/http_integrations/create_service_spec.rb b/spec/services/alert_management/http_integrations/create_service_spec.rb
index ac5c62caf84..5200ec27dd1 100644
--- a/spec/services/alert_management/http_integrations/create_service_spec.rb
+++ b/spec/services/alert_management/http_integrations/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AlertManagement::HttpIntegrations::CreateService do
+RSpec.describe AlertManagement::HttpIntegrations::CreateService, feature_category: :incident_management do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be_with_reload(:project) { create(:project) }
diff --git a/spec/services/alert_management/http_integrations/destroy_service_spec.rb b/spec/services/alert_management/http_integrations/destroy_service_spec.rb
index cd949d728de..a8e9746cb85 100644
--- a/spec/services/alert_management/http_integrations/destroy_service_spec.rb
+++ b/spec/services/alert_management/http_integrations/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AlertManagement::HttpIntegrations::DestroyService do
+RSpec.describe AlertManagement::HttpIntegrations::DestroyService, feature_category: :incident_management do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/services/alert_management/http_integrations/update_service_spec.rb b/spec/services/alert_management/http_integrations/update_service_spec.rb
index 94c34d9a29c..3f1a0967aa9 100644
--- a/spec/services/alert_management/http_integrations/update_service_spec.rb
+++ b/spec/services/alert_management/http_integrations/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AlertManagement::HttpIntegrations::UpdateService do
+RSpec.describe AlertManagement::HttpIntegrations::UpdateService, feature_category: :incident_management do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/services/alert_management/metric_images/upload_service_spec.rb b/spec/services/alert_management/metric_images/upload_service_spec.rb
index 527d9db0fd9..2cafd2c9029 100644
--- a/spec/services/alert_management/metric_images/upload_service_spec.rb
+++ b/spec/services/alert_management/metric_images/upload_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AlertManagement::MetricImages::UploadService do
+RSpec.describe AlertManagement::MetricImages::UploadService, feature_category: :metrics do
subject(:service) { described_class.new(alert, current_user, params) }
let_it_be_with_refind(:project) { create(:project) }
diff --git a/spec/services/alert_management/process_prometheus_alert_service_spec.rb b/spec/services/alert_management/process_prometheus_alert_service_spec.rb
index ae52a09be48..eb5f3808021 100644
--- a/spec/services/alert_management/process_prometheus_alert_service_spec.rb
+++ b/spec/services/alert_management/process_prometheus_alert_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AlertManagement::ProcessPrometheusAlertService do
+RSpec.describe AlertManagement::ProcessPrometheusAlertService, feature_category: :incident_management do
let_it_be(:project, reload: true) { create(:project, :repository) }
let(:service) { described_class.new(project, payload) }
diff --git a/spec/services/analytics/cycle_analytics/stages/list_service_spec.rb b/spec/services/analytics/cycle_analytics/stages/list_service_spec.rb
index 7bfae0cd9fc..c39965a2799 100644
--- a/spec/services/analytics/cycle_analytics/stages/list_service_spec.rb
+++ b/spec/services/analytics/cycle_analytics/stages/list_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Analytics::CycleAnalytics::Stages::ListService do
+RSpec.describe Analytics::CycleAnalytics::Stages::ListService, feature_category: :value_stream_management do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:project_namespace) { project.project_namespace.reload }
diff --git a/spec/services/application_settings/update_service_spec.rb b/spec/services/application_settings/update_service_spec.rb
index e20d59fb0ef..79d4fc67538 100644
--- a/spec/services/application_settings/update_service_spec.rb
+++ b/spec/services/application_settings/update_service_spec.rb
@@ -110,7 +110,7 @@ RSpec.describe ApplicationSettings::UpdateService do
end
end
- describe 'markdown cache invalidators' do
+ describe 'markdown cache invalidators', feature_category: :team_planning do
shared_examples 'invalidates markdown cache' do |attribute|
let(:params) { attribute }
@@ -144,7 +144,7 @@ RSpec.describe ApplicationSettings::UpdateService do
end
end
- describe 'performance bar settings' do
+ describe 'performance bar settings', feature_category: :application_performance do
using RSpec::Parameterized::TableSyntax
where(:params_performance_bar_enabled,
@@ -247,7 +247,7 @@ RSpec.describe ApplicationSettings::UpdateService do
end
end
- context 'when external authorization is enabled' do
+ context 'when external authorization is enabled', feature_category: :system_access do
before do
enable_external_authorization_service_check
end
diff --git a/spec/services/audit_event_service_spec.rb b/spec/services/audit_event_service_spec.rb
index 4f8b90fcb4a..8a20f7775eb 100644
--- a/spec/services/audit_event_service_spec.rb
+++ b/spec/services/audit_event_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuditEventService, :with_license do
+RSpec.describe AuditEventService, :with_license, feature_category: :audit_events do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, :with_sign_ins) }
let_it_be(:project_member) { create(:project_member, user: user) }
diff --git a/spec/services/audit_events/build_service_spec.rb b/spec/services/audit_events/build_service_spec.rb
index caf405a53aa..575ec9e58b8 100644
--- a/spec/services/audit_events/build_service_spec.rb
+++ b/spec/services/audit_events/build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuditEvents::BuildService do
+RSpec.describe AuditEvents::BuildService, feature_category: :audit_events do
let(:author) { build_stubbed(:author, current_sign_in_ip: '127.0.0.1') }
let(:deploy_token) { build_stubbed(:deploy_token, user: author) }
let(:scope) { build_stubbed(:group) }
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index ba7acd3d3df..90aba1ae54c 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Auth::ContainerRegistryAuthenticationService do
+RSpec.describe Auth::ContainerRegistryAuthenticationService, feature_category: :container_registry do
include AdminModeHelper
it_behaves_like 'a container registry auth service'
diff --git a/spec/services/auth/dependency_proxy_authentication_service_spec.rb b/spec/services/auth/dependency_proxy_authentication_service_spec.rb
index 667f361dc34..8f92fbe272c 100644
--- a/spec/services/auth/dependency_proxy_authentication_service_spec.rb
+++ b/spec/services/auth/dependency_proxy_authentication_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Auth::DependencyProxyAuthenticationService do
+RSpec.describe Auth::DependencyProxyAuthenticationService, feature_category: :dependency_proxy do
let_it_be(:user) { create(:user) }
let(:service) { Auth::DependencyProxyAuthenticationService.new(nil, user) }
diff --git a/spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb b/spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb
index 691fb3f60f4..e8f86b4d7c5 100644
--- a/spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb
+++ b/spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
+RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService, feature_category: :projects do
# We're using let! here so that any expectations for the service class are not
# triggered twice.
let!(:project) { create(:project) }
diff --git a/spec/services/authorized_project_update/periodic_recalculate_service_spec.rb b/spec/services/authorized_project_update/periodic_recalculate_service_spec.rb
index 782f6858870..51cab6d188b 100644
--- a/spec/services/authorized_project_update/periodic_recalculate_service_spec.rb
+++ b/spec/services/authorized_project_update/periodic_recalculate_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::PeriodicRecalculateService do
+RSpec.describe AuthorizedProjectUpdate::PeriodicRecalculateService, feature_category: :projects do
subject(:service) { described_class.new }
describe '#execute' do
diff --git a/spec/services/authorized_project_update/project_access_changed_service_spec.rb b/spec/services/authorized_project_update/project_access_changed_service_spec.rb
index da428bece20..7c09d7755ca 100644
--- a/spec/services/authorized_project_update/project_access_changed_service_spec.rb
+++ b/spec/services/authorized_project_update/project_access_changed_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::ProjectAccessChangedService do
+RSpec.describe AuthorizedProjectUpdate::ProjectAccessChangedService, feature_category: :projects do
describe '#execute' do
it 'executes projects_authorizations refresh' do
expect(AuthorizedProjectUpdate::ProjectRecalculateWorker).to receive(:bulk_perform_async)
diff --git a/spec/services/authorized_project_update/project_recalculate_per_user_service_spec.rb b/spec/services/authorized_project_update/project_recalculate_per_user_service_spec.rb
index 62862d0e558..7b2dd52810f 100644
--- a/spec/services/authorized_project_update/project_recalculate_per_user_service_spec.rb
+++ b/spec/services/authorized_project_update/project_recalculate_per_user_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::ProjectRecalculatePerUserService, '#execute' do
+RSpec.describe AuthorizedProjectUpdate::ProjectRecalculatePerUserService, '#execute', feature_category: :projects do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:another_user) { create(:user) }
diff --git a/spec/services/authorized_project_update/project_recalculate_service_spec.rb b/spec/services/authorized_project_update/project_recalculate_service_spec.rb
index c339faaeabf..8360f3c67ab 100644
--- a/spec/services/authorized_project_update/project_recalculate_service_spec.rb
+++ b/spec/services/authorized_project_update/project_recalculate_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::ProjectRecalculateService, '#execute' do
+RSpec.describe AuthorizedProjectUpdate::ProjectRecalculateService, '#execute', feature_category: :projects do
let_it_be(:project) { create(:project) }
subject(:execute) { described_class.new(project).execute }
diff --git a/spec/services/auto_merge/base_service_spec.rb b/spec/services/auto_merge/base_service_spec.rb
index 6c804a14620..7afe5d406ba 100644
--- a/spec/services/auto_merge/base_service_spec.rb
+++ b/spec/services/auto_merge/base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AutoMerge::BaseService do
+RSpec.describe AutoMerge::BaseService, feature_category: :code_review_workflow do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:service) { described_class.new(project, user, params) }
diff --git a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
index 676f55be28a..a0b22267960 100644
--- a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
+++ b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AutoMerge::MergeWhenPipelineSucceedsService do
+RSpec.describe AutoMerge::MergeWhenPipelineSucceedsService, feature_category: :code_review_workflow do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/services/auto_merge_service_spec.rb b/spec/services/auto_merge_service_spec.rb
index 7584e44152e..94f4b414dca 100644
--- a/spec/services/auto_merge_service_spec.rb
+++ b/spec/services/auto_merge_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AutoMergeService do
+RSpec.describe AutoMergeService, feature_category: :code_review_workflow do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/award_emojis/add_service_spec.rb b/spec/services/award_emojis/add_service_spec.rb
index 0fbb785e2d6..99dbe6dc606 100644
--- a/spec/services/award_emojis/add_service_spec.rb
+++ b/spec/services/award_emojis/add_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AwardEmojis::AddService do
+RSpec.describe AwardEmojis::AddService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:awardable) { create(:note, project: project) }
diff --git a/spec/services/award_emojis/base_service_spec.rb b/spec/services/award_emojis/base_service_spec.rb
index e0c8fd39ad9..f1ee4d1cfb8 100644
--- a/spec/services/award_emojis/base_service_spec.rb
+++ b/spec/services/award_emojis/base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AwardEmojis::BaseService do
+RSpec.describe AwardEmojis::BaseService, feature_category: :team_planning do
let(:awardable) { build(:note) }
let(:current_user) { build(:user) }
diff --git a/spec/services/award_emojis/collect_user_emoji_service_spec.rb b/spec/services/award_emojis/collect_user_emoji_service_spec.rb
index bf5aa0eb9ef..d75d5804f93 100644
--- a/spec/services/award_emojis/collect_user_emoji_service_spec.rb
+++ b/spec/services/award_emojis/collect_user_emoji_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AwardEmojis::CollectUserEmojiService do
+RSpec.describe AwardEmojis::CollectUserEmojiService, feature_category: :team_planning do
describe '#execute' do
it 'returns an Array containing the awarded emoji names' do
user = create(:user)
diff --git a/spec/services/award_emojis/copy_service_spec.rb b/spec/services/award_emojis/copy_service_spec.rb
index abb9c65e25d..6c1d7fb21e2 100644
--- a/spec/services/award_emojis/copy_service_spec.rb
+++ b/spec/services/award_emojis/copy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AwardEmojis::CopyService do
+RSpec.describe AwardEmojis::CopyService, feature_category: :team_planning do
let_it_be(:from_awardable) do
create(
:issue,
diff --git a/spec/services/award_emojis/destroy_service_spec.rb b/spec/services/award_emojis/destroy_service_spec.rb
index f743de7c59e..109bdbfa986 100644
--- a/spec/services/award_emojis/destroy_service_spec.rb
+++ b/spec/services/award_emojis/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AwardEmojis::DestroyService do
+RSpec.describe AwardEmojis::DestroyService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:awardable) { create(:note) }
let_it_be(:project) { awardable.project }
diff --git a/spec/services/award_emojis/toggle_service_spec.rb b/spec/services/award_emojis/toggle_service_spec.rb
index 74e97c66193..61dcc22561f 100644
--- a/spec/services/award_emojis/toggle_service_spec.rb
+++ b/spec/services/award_emojis/toggle_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AwardEmojis::ToggleService do
+RSpec.describe AwardEmojis::ToggleService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:awardable) { create(:note, project: project) }
diff --git a/spec/services/base_container_service_spec.rb b/spec/services/base_container_service_spec.rb
index 1de79eec702..7406f0aea93 100644
--- a/spec/services/base_container_service_spec.rb
+++ b/spec/services/base_container_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BaseContainerService do
+RSpec.describe BaseContainerService, feature_category: :container_registry do
let(:project) { Project.new }
let(:user) { User.new }
diff --git a/spec/services/base_count_service_spec.rb b/spec/services/base_count_service_spec.rb
index 18cab2e8e9a..9a731f52b09 100644
--- a/spec/services/base_count_service_spec.rb
+++ b/spec/services/base_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BaseCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe BaseCountService, :use_clean_rails_memory_store_caching, feature_category: :shared do
let(:service) { described_class.new }
describe '#relation_for_count' do
diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb
index f6a9f0903ce..5aaef9d529c 100644
--- a/spec/services/boards/create_service_spec.rb
+++ b/spec/services/boards/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::CreateService do
+RSpec.describe Boards::CreateService, feature_category: :team_planning do
describe '#execute' do
context 'when board parent is a project' do
let(:parent) { create(:project) }
diff --git a/spec/services/boards/destroy_service_spec.rb b/spec/services/boards/destroy_service_spec.rb
index cd6df832547..feaca3cfcce 100644
--- a/spec/services/boards/destroy_service_spec.rb
+++ b/spec/services/boards/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::DestroyService do
+RSpec.describe Boards::DestroyService, feature_category: :team_planning do
context 'with project board' do
let_it_be(:parent) { create(:project) }
diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb
index c4f1eb093dc..f9a9c338f58 100644
--- a/spec/services/boards/issues/create_service_spec.rb
+++ b/spec/services/boards/issues/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Issues::CreateService do
+RSpec.describe Boards::Issues::CreateService, feature_category: :team_planning do
describe '#execute' do
let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index 1959710bb0c..5e10d1d216c 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Issues::ListService do
+RSpec.describe Boards::Issues::ListService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:user) { create(:user) }
diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb
index 3a25f13762c..9c173f3f86e 100644
--- a/spec/services/boards/issues/move_service_spec.rb
+++ b/spec/services/boards/issues/move_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Issues::MoveService do
+RSpec.describe Boards::Issues::MoveService, feature_category: :team_planning do
describe '#execute' do
context 'when parent is a project' do
let(:user) { create(:user) }
diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb
index cac26b3c88d..da317fdd474 100644
--- a/spec/services/boards/lists/create_service_spec.rb
+++ b/spec/services/boards/lists/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Lists::CreateService do
+RSpec.describe Boards::Lists::CreateService, feature_category: :team_planning do
context 'when board parent is a project' do
let_it_be(:parent) { create(:project) }
let_it_be(:board) { create(:board, project: parent) }
diff --git a/spec/services/boards/lists/destroy_service_spec.rb b/spec/services/boards/lists/destroy_service_spec.rb
index d5358bcc1e1..837635d49e8 100644
--- a/spec/services/boards/lists/destroy_service_spec.rb
+++ b/spec/services/boards/lists/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Lists::DestroyService do
+RSpec.describe Boards::Lists::DestroyService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let(:list_type) { :list }
diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb
index 2d41de42581..90b705e05c3 100644
--- a/spec/services/boards/lists/list_service_spec.rb
+++ b/spec/services/boards/lists/list_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Lists::ListService do
+RSpec.describe Boards::Lists::ListService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
diff --git a/spec/services/boards/lists/move_service_spec.rb b/spec/services/boards/lists/move_service_spec.rb
index 2861fc48b4d..abf7d48e114 100644
--- a/spec/services/boards/lists/move_service_spec.rb
+++ b/spec/services/boards/lists/move_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Lists::MoveService do
+RSpec.describe Boards::Lists::MoveService, feature_category: :team_planning do
describe '#execute' do
context 'when board parent is a project' do
let(:project) { create(:project) }
diff --git a/spec/services/boards/lists/update_service_spec.rb b/spec/services/boards/lists/update_service_spec.rb
index 21216e1b945..341eaa52292 100644
--- a/spec/services/boards/lists/update_service_spec.rb
+++ b/spec/services/boards/lists/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Lists::UpdateService do
+RSpec.describe Boards::Lists::UpdateService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let!(:list) { create(:list, board: board, position: 0) }
diff --git a/spec/services/boards/visits/create_service_spec.rb b/spec/services/boards/visits/create_service_spec.rb
index 8910345d170..4af4e914da5 100644
--- a/spec/services/boards/visits/create_service_spec.rb
+++ b/spec/services/boards/visits/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Boards::Visits::CreateService do
+RSpec.describe Boards::Visits::CreateService, feature_category: :team_planning do
describe '#execute' do
let(:user) { create(:user) }
diff --git a/spec/services/branches/create_service_spec.rb b/spec/services/branches/create_service_spec.rb
index 19a32aafa38..7fb7d9d440d 100644
--- a/spec/services/branches/create_service_spec.rb
+++ b/spec/services/branches/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Branches::CreateService, :use_clean_rails_redis_caching do
+RSpec.describe Branches::CreateService, :use_clean_rails_redis_caching, feature_category: :source_code_management do
subject(:service) { described_class.new(project, user) }
let_it_be(:project) { create(:project_empty_repo) }
@@ -108,7 +108,7 @@ RSpec.describe Branches::CreateService, :use_clean_rails_redis_caching do
control = RedisCommands::Recorder.new(pattern: ':branch_names:') { subject }
- expect(control.by_command(:sadd).count).to eq(1)
+ expect(control).not_to exceed_redis_command_calls_limit(:sadd, 1)
end
end
diff --git a/spec/services/branches/delete_merged_service_spec.rb b/spec/services/branches/delete_merged_service_spec.rb
index 46611670fe1..23a892a56ef 100644
--- a/spec/services/branches/delete_merged_service_spec.rb
+++ b/spec/services/branches/delete_merged_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Branches::DeleteMergedService do
+RSpec.describe Branches::DeleteMergedService, feature_category: :source_code_management do
include ProjectForksHelper
subject(:service) { described_class.new(project, project.first_owner) }
diff --git a/spec/services/branches/delete_service_spec.rb b/spec/services/branches/delete_service_spec.rb
index 727cadc5a50..003645b1b8c 100644
--- a/spec/services/branches/delete_service_spec.rb
+++ b/spec/services/branches/delete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Branches::DeleteService do
+RSpec.describe Branches::DeleteService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
diff --git a/spec/services/branches/diverging_commit_counts_service_spec.rb b/spec/services/branches/diverging_commit_counts_service_spec.rb
index 34a2b81c831..3cccc74735c 100644
--- a/spec/services/branches/diverging_commit_counts_service_spec.rb
+++ b/spec/services/branches/diverging_commit_counts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Branches::DivergingCommitCountsService do
+RSpec.describe Branches::DivergingCommitCountsService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
diff --git a/spec/services/branches/validate_new_service_spec.rb b/spec/services/branches/validate_new_service_spec.rb
index 02127c8c10d..a5b75a09353 100644
--- a/spec/services/branches/validate_new_service_spec.rb
+++ b/spec/services/branches/validate_new_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Branches::ValidateNewService do
+RSpec.describe Branches::ValidateNewService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
subject(:service) { described_class.new(project) }
diff --git a/spec/services/bulk_create_integration_service_spec.rb b/spec/services/bulk_create_integration_service_spec.rb
index 22bb1736f9f..57bdfdbd4cb 100644
--- a/spec/services/bulk_create_integration_service_spec.rb
+++ b/spec/services/bulk_create_integration_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkCreateIntegrationService do
+RSpec.describe BulkCreateIntegrationService, feature_category: :integrations do
include JiraIntegrationHelpers
before_all do
diff --git a/spec/services/bulk_imports/archive_extraction_service_spec.rb b/spec/services/bulk_imports/archive_extraction_service_spec.rb
index da9df31cde9..40f8d8718ae 100644
--- a/spec/services/bulk_imports/archive_extraction_service_spec.rb
+++ b/spec/services/bulk_imports/archive_extraction_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::ArchiveExtractionService do
+RSpec.describe BulkImports::ArchiveExtractionService, feature_category: :importers do
let_it_be(:tmpdir) { Dir.mktmpdir }
let_it_be(:filename) { 'symlink_export.tar' }
let_it_be(:filepath) { File.join(tmpdir, filename) }
diff --git a/spec/services/bulk_imports/export_service_spec.rb b/spec/services/bulk_imports/export_service_spec.rb
index 2414f7c5ca7..ac7514fde5b 100644
--- a/spec/services/bulk_imports/export_service_spec.rb
+++ b/spec/services/bulk_imports/export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::ExportService do
+RSpec.describe BulkImports::ExportService, feature_category: :importers do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/bulk_imports/file_decompression_service_spec.rb b/spec/services/bulk_imports/file_decompression_service_spec.rb
index 77348428d60..9b8320aeac5 100644
--- a/spec/services/bulk_imports/file_decompression_service_spec.rb
+++ b/spec/services/bulk_imports/file_decompression_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::FileDecompressionService do
+RSpec.describe BulkImports::FileDecompressionService, feature_category: :importers do
let_it_be(:tmpdir) { Dir.mktmpdir }
let_it_be(:ndjson_filename) { 'labels.ndjson' }
let_it_be(:ndjson_filepath) { File.join(tmpdir, ndjson_filename) }
diff --git a/spec/services/bulk_imports/file_download_service_spec.rb b/spec/services/bulk_imports/file_download_service_spec.rb
index 27f77b678e3..7c64d6efc65 100644
--- a/spec/services/bulk_imports/file_download_service_spec.rb
+++ b/spec/services/bulk_imports/file_download_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::FileDownloadService do
+RSpec.describe BulkImports::FileDownloadService, feature_category: :importers do
describe '#execute' do
let_it_be(:allowed_content_types) { %w(application/gzip application/octet-stream) }
let_it_be(:file_size_limit) { 5.gigabytes }
diff --git a/spec/services/bulk_imports/file_export_service_spec.rb b/spec/services/bulk_imports/file_export_service_spec.rb
index 453fc1d0c0d..3c23b86ad5c 100644
--- a/spec/services/bulk_imports/file_export_service_spec.rb
+++ b/spec/services/bulk_imports/file_export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::FileExportService do
+RSpec.describe BulkImports::FileExportService, feature_category: :importers do
let_it_be(:project) { create(:project) }
describe '#execute' do
diff --git a/spec/services/bulk_imports/lfs_objects_export_service_spec.rb b/spec/services/bulk_imports/lfs_objects_export_service_spec.rb
index 894789c7941..4f721a3a259 100644
--- a/spec/services/bulk_imports/lfs_objects_export_service_spec.rb
+++ b/spec/services/bulk_imports/lfs_objects_export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::LfsObjectsExportService do
+RSpec.describe BulkImports::LfsObjectsExportService, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:lfs_json_filename) { "#{BulkImports::FileTransfer::ProjectConfig::LFS_OBJECTS_RELATION}.json" }
let_it_be(:remote_url) { 'http://my-object-storage.local' }
diff --git a/spec/services/bulk_imports/relation_export_service_spec.rb b/spec/services/bulk_imports/relation_export_service_spec.rb
index f0f85217d2e..bc999b0b9b3 100644
--- a/spec/services/bulk_imports/relation_export_service_spec.rb
+++ b/spec/services/bulk_imports/relation_export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::RelationExportService do
+RSpec.describe BulkImports::RelationExportService, feature_category: :importers do
let_it_be(:jid) { 'jid' }
let_it_be(:relation) { 'labels' }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/bulk_imports/repository_bundle_export_service_spec.rb b/spec/services/bulk_imports/repository_bundle_export_service_spec.rb
index f0d63de1ab9..92d5d21c33f 100644
--- a/spec/services/bulk_imports/repository_bundle_export_service_spec.rb
+++ b/spec/services/bulk_imports/repository_bundle_export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::RepositoryBundleExportService do
+RSpec.describe BulkImports::RepositoryBundleExportService, feature_category: :importers do
let(:project) { create(:project) }
let(:export_path) { Dir.mktmpdir }
diff --git a/spec/services/bulk_imports/tree_export_service_spec.rb b/spec/services/bulk_imports/tree_export_service_spec.rb
index 6e26cb6dc2b..fa96641f1c1 100644
--- a/spec/services/bulk_imports/tree_export_service_spec.rb
+++ b/spec/services/bulk_imports/tree_export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::TreeExportService do
+RSpec.describe BulkImports::TreeExportService, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:export_path) { Dir.mktmpdir }
diff --git a/spec/services/bulk_imports/uploads_export_service_spec.rb b/spec/services/bulk_imports/uploads_export_service_spec.rb
index ad6e005485c..8dc67b28d12 100644
--- a/spec/services/bulk_imports/uploads_export_service_spec.rb
+++ b/spec/services/bulk_imports/uploads_export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::UploadsExportService do
+RSpec.describe BulkImports::UploadsExportService, feature_category: :importers do
let_it_be(:export_path) { Dir.mktmpdir }
let_it_be(:project) { create(:project, avatar: fixture_file_upload('spec/fixtures/rails_sample.png', 'image/png')) }
diff --git a/spec/services/bulk_push_event_payload_service_spec.rb b/spec/services/bulk_push_event_payload_service_spec.rb
index 381c735c003..95e1c831498 100644
--- a/spec/services/bulk_push_event_payload_service_spec.rb
+++ b/spec/services/bulk_push_event_payload_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkPushEventPayloadService do
+RSpec.describe BulkPushEventPayloadService, feature_category: :source_code_management do
let(:event) { create(:push_event) }
let(:push_data) do
diff --git a/spec/services/bulk_update_integration_service_spec.rb b/spec/services/bulk_update_integration_service_spec.rb
index 24a868b524d..260eed3c734 100644
--- a/spec/services/bulk_update_integration_service_spec.rb
+++ b/spec/services/bulk_update_integration_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkUpdateIntegrationService do
+RSpec.describe BulkUpdateIntegrationService, feature_category: :integrations do
include JiraIntegrationHelpers
before_all do
diff --git a/spec/services/captcha/captcha_verification_service_spec.rb b/spec/services/captcha/captcha_verification_service_spec.rb
index fe2199fb53e..b67e725bf91 100644
--- a/spec/services/captcha/captcha_verification_service_spec.rb
+++ b/spec/services/captcha/captcha_verification_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Captcha::CaptchaVerificationService do
+RSpec.describe Captcha::CaptchaVerificationService, feature_category: :team_planning do
describe '#execute' do
let(:captcha_response) { 'abc123' }
let(:fake_ip) { '1.2.3.4' }
diff --git a/spec/services/chat_names/find_user_service_spec.rb b/spec/services/chat_names/find_user_service_spec.rb
index 10cb0a2f065..14bece4efb4 100644
--- a/spec/services/chat_names/find_user_service_spec.rb
+++ b/spec/services/chat_names/find_user_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ChatNames::FindUserService, :clean_gitlab_redis_shared_state do
+RSpec.describe ChatNames::FindUserService, :clean_gitlab_redis_shared_state, feature_category: :user_profile do
describe '#execute' do
subject { described_class.new(team_id, user_id).execute }
diff --git a/spec/services/ci/abort_pipelines_service_spec.rb b/spec/services/ci/abort_pipelines_service_spec.rb
index e43faf0af51..60f3ee11442 100644
--- a/spec/services/ci/abort_pipelines_service_spec.rb
+++ b/spec/services/ci/abort_pipelines_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::AbortPipelinesService do
+RSpec.describe Ci::AbortPipelinesService, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/ci/append_build_trace_service_spec.rb b/spec/services/ci/append_build_trace_service_spec.rb
index 20f7967d1f1..113c88dc5f3 100644
--- a/spec/services/ci/append_build_trace_service_spec.rb
+++ b/spec/services/ci/append_build_trace_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::AppendBuildTraceService do
+RSpec.describe Ci::AppendBuildTraceService, feature_category: :continuous_integration do
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be_with_reload(:build) { create(:ci_build, :running, pipeline: pipeline) }
diff --git a/spec/services/ci/build_cancel_service_spec.rb b/spec/services/ci/build_cancel_service_spec.rb
index fe036dc1368..314d2e86bd3 100644
--- a/spec/services/ci/build_cancel_service_spec.rb
+++ b/spec/services/ci/build_cancel_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::BuildCancelService do
+RSpec.describe Ci::BuildCancelService, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/build_erase_service_spec.rb b/spec/services/ci/build_erase_service_spec.rb
index e750a163621..35e74f76a26 100644
--- a/spec/services/ci/build_erase_service_spec.rb
+++ b/spec/services/ci/build_erase_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::BuildEraseService do
+RSpec.describe Ci::BuildEraseService, feature_category: :continuous_integration do
let_it_be(:user) { user }
let(:build) { create(:ci_build, :artifacts, :trace_artifact, artifacts_expire_at: 100.days.from_now) }
diff --git a/spec/services/ci/build_report_result_service_spec.rb b/spec/services/ci/build_report_result_service_spec.rb
index c5238b7f5e0..c3ce6714241 100644
--- a/spec/services/ci/build_report_result_service_spec.rb
+++ b/spec/services/ci/build_report_result_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::BuildReportResultService do
+RSpec.describe Ci::BuildReportResultService, feature_category: :continuous_integration do
describe '#execute', :clean_gitlab_redis_shared_state do
subject(:build_report_result) { described_class.new.execute(build) }
diff --git a/spec/services/ci/build_unschedule_service_spec.rb b/spec/services/ci/build_unschedule_service_spec.rb
index d784d9a2754..539c66047e4 100644
--- a/spec/services/ci/build_unschedule_service_spec.rb
+++ b/spec/services/ci/build_unschedule_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::BuildUnscheduleService do
+RSpec.describe Ci::BuildUnscheduleService, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/catalog/add_resource_service_spec.rb b/spec/services/ci/catalog/add_resource_service_spec.rb
new file mode 100644
index 00000000000..ecb939e3c2d
--- /dev/null
+++ b/spec/services/ci/catalog/add_resource_service_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::Catalog::AddResourceService, feature_category: :pipeline_composition do
+ let_it_be(:project) { create(:project, :repository, description: 'Our components') }
+ let_it_be(:user) { create(:user) }
+
+ let(:service) { described_class.new(project, user) }
+
+ describe '#execute' do
+ context 'with an unauthorized user' do
+ it 'raises an AccessDeniedError' do
+ expect { service.execute }.to raise_error(Gitlab::Access::AccessDeniedError)
+ end
+ end
+
+ context 'with an authorized user' do
+ before do
+ project.add_owner(user)
+ end
+
+ context 'and a valid project' do
+ it 'creates a catalog resource' do
+ response = service.execute
+
+ expect(response.payload.project).to eq(project)
+ end
+ end
+
+ context 'with an invalid project' do
+ let_it_be(:project) { create(:project, :repository) }
+
+ it 'does not create a catalog resource' do
+ response = service.execute
+
+ expect(response.message).to eq('Project must have a description')
+ end
+ end
+
+ context 'with an invalid catalog resource' do
+ it 'does not save the catalog resource' do
+ catalog_resource = instance_double(::Ci::Catalog::Resource,
+ valid?: false,
+ errors: instance_double(ActiveModel::Errors, full_messages: ['not valid']))
+ allow(::Ci::Catalog::Resource).to receive(:new).and_return(catalog_resource)
+
+ response = service.execute
+
+ expect(response.message).to eq('not valid')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/catalog/validate_resource_service_spec.rb b/spec/services/ci/catalog/validate_resource_service_spec.rb
new file mode 100644
index 00000000000..3bee37b7e55
--- /dev/null
+++ b/spec/services/ci/catalog/validate_resource_service_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::Catalog::ValidateResourceService, feature_category: :pipeline_composition do
+ describe '#execute' do
+ context 'with a project that has a README and a description' do
+ it 'is valid' do
+ project = create(:project, :repository, description: 'Component project')
+ response = described_class.new(project, project.default_branch).execute
+
+ expect(response).to be_success
+ end
+ end
+
+ context 'with a project that has neither a description nor a README' do
+ it 'is not valid' do
+ project = create(:project, :empty_repo)
+ project.repository.create_file(
+ project.creator,
+ 'ruby.rb',
+ 'I like this',
+ message: 'Ruby like this',
+ branch_name: 'master'
+ )
+ response = described_class.new(project, project.default_branch).execute
+
+ expect(response.message).to eq('Project must have a README , Project must have a description')
+ end
+ end
+
+ context 'with a project that has a description but not a README' do
+ it 'is not valid' do
+ project = create(:project, :empty_repo, description: 'project with no README')
+ project.repository.create_file(
+ project.creator,
+ 'text.txt',
+ 'I do not like this',
+ message: 'only text like text',
+ branch_name: 'master'
+ )
+ response = described_class.new(project, project.default_branch).execute
+
+ expect(response.message).to eq('Project must have a README')
+ end
+ end
+
+ context 'with a project that has a README and not a description' do
+ it 'is not valid' do
+ project = create(:project, :repository)
+ response = described_class.new(project, project.default_branch).execute
+
+ expect(response.message).to eq('Project must have a description')
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/change_variable_service_spec.rb b/spec/services/ci/change_variable_service_spec.rb
index f86a87132b1..a9f9e4233d7 100644
--- a/spec/services/ci/change_variable_service_spec.rb
+++ b/spec/services/ci/change_variable_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ChangeVariableService do
+RSpec.describe Ci::ChangeVariableService, feature_category: :pipeline_composition do
let(:service) { described_class.new(container: group, current_user: user, params: params) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/ci/change_variables_service_spec.rb b/spec/services/ci/change_variables_service_spec.rb
index b710ca78554..1bc36a78762 100644
--- a/spec/services/ci/change_variables_service_spec.rb
+++ b/spec/services/ci/change_variables_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ChangeVariablesService do
+RSpec.describe Ci::ChangeVariablesService, feature_category: :pipeline_composition do
let(:service) { described_class.new(container: group, current_user: user, params: params) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/ci/compare_accessibility_reports_service_spec.rb b/spec/services/ci/compare_accessibility_reports_service_spec.rb
index e0b84219834..57514c18042 100644
--- a/spec/services/ci/compare_accessibility_reports_service_spec.rb
+++ b/spec/services/ci/compare_accessibility_reports_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CompareAccessibilityReportsService do
+RSpec.describe Ci::CompareAccessibilityReportsService, feature_category: :continuous_integration do
let(:service) { described_class.new(project) }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/ci/compare_codequality_reports_service_spec.rb b/spec/services/ci/compare_codequality_reports_service_spec.rb
index ef762a2e9ad..de2300c354b 100644
--- a/spec/services/ci/compare_codequality_reports_service_spec.rb
+++ b/spec/services/ci/compare_codequality_reports_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CompareCodequalityReportsService do
+RSpec.describe Ci::CompareCodequalityReportsService, feature_category: :continuous_integration do
let(:service) { described_class.new(project) }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/ci/compare_reports_base_service_spec.rb b/spec/services/ci/compare_reports_base_service_spec.rb
index 20d8cd37553..2906d61066d 100644
--- a/spec/services/ci/compare_reports_base_service_spec.rb
+++ b/spec/services/ci/compare_reports_base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CompareReportsBaseService do
+RSpec.describe Ci::CompareReportsBaseService, feature_category: :continuous_integration do
let(:service) { described_class.new(project) }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/ci/compare_test_reports_service_spec.rb b/spec/services/ci/compare_test_reports_service_spec.rb
index f259072fe87..d29cef0c583 100644
--- a/spec/services/ci/compare_test_reports_service_spec.rb
+++ b/spec/services/ci/compare_test_reports_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CompareTestReportsService do
+RSpec.describe Ci::CompareTestReportsService, feature_category: :continuous_integration do
let(:service) { described_class.new(project) }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/ci/components/fetch_service_spec.rb b/spec/services/ci/components/fetch_service_spec.rb
index f2eaa8d31b4..532098b3b20 100644
--- a/spec/services/ci/components/fetch_service_spec.rb
+++ b/spec/services/ci/components/fetch_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Components::FetchService, feature_category: :pipeline_authoring do
+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 }
diff --git a/spec/services/ci/copy_cross_database_associations_service_spec.rb b/spec/services/ci/copy_cross_database_associations_service_spec.rb
index 5938ac258d0..2be0cbd9582 100644
--- a/spec/services/ci/copy_cross_database_associations_service_spec.rb
+++ b/spec/services/ci/copy_cross_database_associations_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CopyCrossDatabaseAssociationsService do
+RSpec.describe Ci::CopyCrossDatabaseAssociationsService, feature_category: :continuous_integration do
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:old_build) { create(:ci_build, pipeline: pipeline) }
diff --git a/spec/services/ci/create_pipeline_service/artifacts_spec.rb b/spec/services/ci/create_pipeline_service/artifacts_spec.rb
index e5e405492a0..c193900b2d3 100644
--- a/spec/services/ci/create_pipeline_service/artifacts_spec.rb
+++ b/spec/services/ci/create_pipeline_service/artifacts_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :build_artifacts do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/cache_spec.rb b/spec/services/ci/create_pipeline_service/cache_spec.rb
index f9640f99031..e8d9cec6695 100644
--- a/spec/services/ci/create_pipeline_service/cache_spec.rb
+++ b/spec/services/ci/create_pipeline_service/cache_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
context 'cache' do
let(:project) { create(:project, :custom_repo, files: files) }
let(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb
index 0ebcecdd6e6..036116dc037 100644
--- a/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb
+++ b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :continuous_integration do
describe 'creation errors and warnings' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
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 0d5017a763f..dc87cc872e3 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
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
let_it_be(:group) { create(:group, name: 'my-organization') }
let(:upstream_project) { create(:project, :repository, name: 'upstream', group: group) }
diff --git a/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb b/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb
index dafa227c4c8..819946bfd27 100644
--- a/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb
+++ b/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb b/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb
index 3b042f05fc0..b78ad68194a 100644
--- a/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb
+++ b/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
describe '!reference tags' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/dry_run_spec.rb b/spec/services/ci/create_pipeline_service/dry_run_spec.rb
index de1ed251c82..7136fa5dc13 100644
--- a/spec/services/ci/create_pipeline_service/dry_run_spec.rb
+++ b/spec/services/ci/create_pipeline_service/dry_run_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/environment_spec.rb b/spec/services/ci/create_pipeline_service/environment_spec.rb
index b713cad2cad..96e54af43cd 100644
--- a/spec/services/ci/create_pipeline_service/environment_spec.rb
+++ b/spec/services/ci/create_pipeline_service/environment_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :pipeline_composition do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:developer) { create(:user) }
diff --git a/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb b/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb
index e84726d31f6..b40e504f99b 100644
--- a/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb
+++ b/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :pipeline_composition do
let_it_be(:group) { create(:group, :private) }
let_it_be(:group_variable) { create(:ci_group_variable, group: group, key: 'RUNNER_TAG', value: 'group') }
let_it_be(:project) { create(:project, :repository, group: group) }
diff --git a/spec/services/ci/create_pipeline_service/include_spec.rb b/spec/services/ci/create_pipeline_service/include_spec.rb
index f18b4883aaf..86f71be5971 100644
--- a/spec/services/ci/create_pipeline_service/include_spec.rb
+++ b/spec/services/ci/create_pipeline_service/include_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService,
-:yaml_processor_feature_flag_corectness, feature_category: :pipeline_authoring do
+:yaml_processor_feature_flag_corectness, feature_category: :pipeline_composition do
include RepoHelpers
context 'include:' do
diff --git a/spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb b/spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb
index 003d109a27c..b0730eaf215 100644
--- a/spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb
+++ b/spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
let_it_be(:existing_pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/create_pipeline_service/logger_spec.rb b/spec/services/ci/create_pipeline_service/logger_spec.rb
index ecb24a61075..082a09db69e 100644
--- a/spec/services/ci/create_pipeline_service/logger_spec.rb
+++ b/spec/services/ci/create_pipeline_service/logger_spec.rb
@@ -142,7 +142,7 @@ RSpec.describe Ci::CreatePipelineService, # rubocop: disable RSpec/FilePath
describe 'pipeline includes count' do
before do
- stub_const('Gitlab::Ci::Config::External::Context::MAX_INCLUDES', 2)
+ stub_const('Gitlab::Ci::Config::External::Context::TEMP_MAX_INCLUDES', 2)
end
context 'when the includes count exceeds the maximum' do
diff --git a/spec/services/ci/create_pipeline_service/merge_requests_spec.rb b/spec/services/ci/create_pipeline_service/merge_requests_spec.rb
index 80f48451e5c..8d04b3d020f 100644
--- a/spec/services/ci/create_pipeline_service/merge_requests_spec.rb
+++ b/spec/services/ci/create_pipeline_service/merge_requests_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+feature_category: :continuous_integration do
context 'merge requests handling' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/needs_spec.rb b/spec/services/ci/create_pipeline_service/needs_spec.rb
index 38e330316ea..068cad68e64 100644
--- a/spec/services/ci/create_pipeline_service/needs_spec.rb
+++ b/spec/services/ci/create_pipeline_service/needs_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :pipeline_composition do
context 'needs' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/parallel_spec.rb b/spec/services/ci/create_pipeline_service/parallel_spec.rb
index 5ee378a9719..71434fe0b0c 100644
--- a/spec/services/ci/create_pipeline_service/parallel_spec.rb
+++ b/spec/services/ci/create_pipeline_service/parallel_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/parameter_content_spec.rb b/spec/services/ci/create_pipeline_service/parameter_content_spec.rb
index cae88bb67cf..16555dd68d6 100644
--- a/spec/services/ci/create_pipeline_service/parameter_content_spec.rb
+++ b/spec/services/ci/create_pipeline_service/parameter_content_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
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 eb17935967c..e644273df9a 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
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb b/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb
index db110bdc608..d935824e6cc 100644
--- a/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb
+++ b/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
describe '.pre/.post stages' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/rate_limit_spec.rb b/spec/services/ci/create_pipeline_service/rate_limit_spec.rb
index dfa74870341..31bea10f062 100644
--- a/spec/services/ci/create_pipeline_service/rate_limit_spec.rb
+++ b/spec/services/ci/create_pipeline_service/rate_limit_spec.rb
@@ -3,7 +3,8 @@ require 'spec_helper'
RSpec.describe Ci::CreatePipelineService, :freeze_time,
:clean_gitlab_redis_rate_limiting,
- :yaml_processor_feature_flag_corectness do
+ :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
describe 'rate limiting' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb
index 26bb8b7d006..19f9e7e3e4a 100644
--- a/spec/services/ci/create_pipeline_service/rules_spec.rb
+++ b/spec/services/ci/create_pipeline_service/rules_spec.rb
@@ -1,25 +1,18 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :pipeline_authoring do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :pipeline_composition do
let(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
let(:ref) { 'refs/heads/master' }
let(:source) { :push }
- let(:service) { described_class.new(project, user, { ref: ref }) }
- let(:response) { execute_service }
+ let(:service) { described_class.new(project, user, initialization_params) }
+ let(:response) { service.execute(source) }
let(:pipeline) { response.payload }
let(:build_names) { pipeline.builds.pluck(:name) }
- def execute_service(before: '00000000', variables_attributes: nil)
- params = { ref: ref, before: before, after: project.commit(ref).sha, variables_attributes: variables_attributes }
-
- described_class
- .new(project, user, params)
- .execute(source) do |pipeline|
- yield(pipeline) if block_given?
- end
- end
+ let(:base_initialization_params) { { ref: ref, before: '00000000', after: project.commit(ref).sha, variables_attributes: nil } }
+ let(:initialization_params) { base_initialization_params }
context 'job:rules' do
let(:regular_job) { find_job('regular-job') }
@@ -516,11 +509,10 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
)
end
+ let(:initialization_params) { base_initialization_params.merge(before: nil) }
let(:changed_file) { 'file2.txt' }
let(:ref) { 'feature_2' }
- let(:response) { execute_service(before: nil) }
-
context 'for jobs rules' do
let(:config) do
<<-EOY
@@ -1230,9 +1222,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
context 'with pipeline variables' do
- let(:pipeline) do
- execute_service(variables_attributes: variables_attributes).payload
- end
+ let(:initialization_params) { base_initialization_params.merge(variables_attributes: variables_attributes) }
let(:config) do
<<-EOY
@@ -1267,10 +1257,10 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
context 'with trigger variables' do
- let(:pipeline) do
- execute_service do |pipeline|
+ let(:response) do
+ service.execute(source) do |pipeline|
pipeline.variables.build(variables)
- end.payload
+ end
end
let(:config) do
@@ -1434,10 +1424,10 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
[{ key: 'SOME_VARIABLE', secret_value: 'SOME_VAL' }]
end
- let(:pipeline) do
- execute_service do |pipeline|
+ let(:response) do
+ service.execute(source) do |pipeline|
pipeline.variables.build(variables)
- end.payload
+ end
end
let(:config) do
diff --git a/spec/services/ci/create_pipeline_service/scripts_spec.rb b/spec/services/ci/create_pipeline_service/scripts_spec.rb
index 50b558e505a..d541257a086 100644
--- a/spec/services/ci/create_pipeline_service/scripts_spec.rb
+++ b/spec/services/ci/create_pipeline_service/scripts_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
@@ -83,30 +84,5 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
options: { script: ["echo 'hello job3 script'"] }
)
end
-
- context 'when the FF ci_hooks_pre_get_sources_script is disabled' do
- before do
- stub_feature_flags(ci_hooks_pre_get_sources_script: false)
- end
-
- it 'creates jobs without hook data' do
- expect(pipeline).to be_created_successfully
- expect(pipeline.builds.find_by(name: 'job1')).to have_attributes(
- name: 'job1',
- stage: 'test',
- options: { script: ["echo 'hello job1 script'"] }
- )
- expect(pipeline.builds.find_by(name: 'job2')).to have_attributes(
- name: 'job2',
- stage: 'test',
- options: { script: ["echo 'hello job2 script'"] }
- )
- expect(pipeline.builds.find_by(name: 'job3')).to have_attributes(
- name: 'job3',
- stage: 'test',
- options: { script: ["echo 'hello job3 script'"] }
- )
- end
- end
end
end
diff --git a/spec/services/ci/create_pipeline_service/tags_spec.rb b/spec/services/ci/create_pipeline_service/tags_spec.rb
index 7450df11eac..cb2dbf1c3a4 100644
--- a/spec/services/ci/create_pipeline_service/tags_spec.rb
+++ b/spec/services/ci/create_pipeline_service/tags_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :continuous_integration do
describe 'tags:' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/variables_spec.rb b/spec/services/ci/create_pipeline_service/variables_spec.rb
index fd138bde656..64f8b90f2f2 100644
--- a/spec/services/ci/create_pipeline_service/variables_spec.rb
+++ b/spec/services/ci/create_pipeline_service/variables_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
+ feature_category: :pipeline_composition do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_web_ide_terminal_service_spec.rb b/spec/services/ci/create_web_ide_terminal_service_spec.rb
index 3462b48cfe7..b22ca1472b7 100644
--- a/spec/services/ci/create_web_ide_terminal_service_spec.rb
+++ b/spec/services/ci/create_web_ide_terminal_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CreateWebIdeTerminalService do
+RSpec.describe Ci::CreateWebIdeTerminalService, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/ci/daily_build_group_report_result_service_spec.rb b/spec/services/ci/daily_build_group_report_result_service_spec.rb
index 32651247adb..bb6ce559fbd 100644
--- a/spec/services/ci/daily_build_group_report_result_service_spec.rb
+++ b/spec/services/ci/daily_build_group_report_result_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do
+RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute', feature_category: :continuous_integration do
let_it_be(:group) { create(:group, :private) }
let_it_be(:pipeline) { create(:ci_pipeline, project: create(:project, group: group), created_at: '2020-02-06 00:01:10') }
let_it_be(:rspec_job) { create(:ci_build, pipeline: pipeline, name: 'rspec 3/3', coverage: 80) }
diff --git a/spec/services/ci/delete_objects_service_spec.rb b/spec/services/ci/delete_objects_service_spec.rb
index 448f8979681..d84ee596721 100644
--- a/spec/services/ci/delete_objects_service_spec.rb
+++ b/spec/services/ci/delete_objects_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DeleteObjectsService, :aggregate_failure do
+RSpec.describe Ci::DeleteObjectsService, :aggregate_failure, feature_category: :continuous_integration do
let(:service) { described_class.new }
let(:artifact) { create(:ci_job_artifact, :archive) }
let(:data) { [artifact] }
diff --git a/spec/services/ci/delete_unit_tests_service_spec.rb b/spec/services/ci/delete_unit_tests_service_spec.rb
index 4c63c513d48..2f07e709107 100644
--- a/spec/services/ci/delete_unit_tests_service_spec.rb
+++ b/spec/services/ci/delete_unit_tests_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DeleteUnitTestsService do
+RSpec.describe Ci::DeleteUnitTestsService, feature_category: :continuous_integration do
describe '#execute' do
let!(:unit_test_1) { create(:ci_unit_test) }
let!(:unit_test_2) { create(:ci_unit_test) }
diff --git a/spec/services/ci/deployments/destroy_service_spec.rb b/spec/services/ci/deployments/destroy_service_spec.rb
index 60a57c05728..d0e7f5acb2b 100644
--- a/spec/services/ci/deployments/destroy_service_spec.rb
+++ b/spec/services/ci/deployments/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Deployments::DestroyService do
+RSpec.describe ::Ci::Deployments::DestroyService, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) }
diff --git a/spec/services/ci/destroy_pipeline_service_spec.rb b/spec/services/ci/destroy_pipeline_service_spec.rb
index 6bd7fe7559c..a1883d90b0a 100644
--- a/spec/services/ci/destroy_pipeline_service_spec.rb
+++ b/spec/services/ci/destroy_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::DestroyPipelineService do
+RSpec.describe ::Ci::DestroyPipelineService, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let!(:pipeline) { create(:ci_pipeline, :success, project: project, sha: project.commit.id) }
diff --git a/spec/services/ci/destroy_secure_file_service_spec.rb b/spec/services/ci/destroy_secure_file_service_spec.rb
index 6a30d33f4ca..321efc2ed71 100644
--- a/spec/services/ci/destroy_secure_file_service_spec.rb
+++ b/spec/services/ci/destroy_secure_file_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::DestroySecureFileService do
+RSpec.describe ::Ci::DestroySecureFileService, feature_category: :continuous_integration do
let_it_be(:maintainer_user) { create(:user) }
let_it_be(:developer_user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb b/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb
index 4ff8dcf075b..d422cf0dab9 100644
--- a/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb
+++ b/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DisableUserPipelineSchedulesService do
+RSpec.describe Ci::DisableUserPipelineSchedulesService, feature_category: :continuous_integration do
describe '#execute' do
let(:user) { create(:user) }
diff --git a/spec/services/ci/drop_pipeline_service_spec.rb b/spec/services/ci/drop_pipeline_service_spec.rb
index ddb53712d9c..ed45b3460c1 100644
--- a/spec/services/ci/drop_pipeline_service_spec.rb
+++ b/spec/services/ci/drop_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DropPipelineService do
+RSpec.describe Ci::DropPipelineService, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let(:failure_reason) { :user_blocked }
diff --git a/spec/services/ci/ensure_stage_service_spec.rb b/spec/services/ci/ensure_stage_service_spec.rb
index 026814edda6..5d6025095a1 100644
--- a/spec/services/ci/ensure_stage_service_spec.rb
+++ b/spec/services/ci/ensure_stage_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::EnsureStageService, '#execute' do
+RSpec.describe Ci::EnsureStageService, '#execute', feature_category: :continuous_integration do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/ci/expire_pipeline_cache_service_spec.rb b/spec/services/ci/expire_pipeline_cache_service_spec.rb
index 8cfe756faf3..3d0ce456aa5 100644
--- a/spec/services/ci/expire_pipeline_cache_service_spec.rb
+++ b/spec/services/ci/expire_pipeline_cache_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ExpirePipelineCacheService do
+RSpec.describe Ci::ExpirePipelineCacheService, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb b/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb
index d5881d3b204..1b548aaf614 100644
--- a/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb
+++ b/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ExternalPullRequests::CreatePipelineService do
+RSpec.describe Ci::ExternalPullRequests::CreatePipelineService, feature_category: :continuous_integration do
describe '#execute' do
let_it_be(:project) { create(:project, :auto_devops, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/ci/find_exposed_artifacts_service_spec.rb b/spec/services/ci/find_exposed_artifacts_service_spec.rb
index 6e11c153a75..69360e73b86 100644
--- a/spec/services/ci/find_exposed_artifacts_service_spec.rb
+++ b/spec/services/ci/find_exposed_artifacts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::FindExposedArtifactsService do
+RSpec.describe Ci::FindExposedArtifactsService, feature_category: :build_artifacts do
include Gitlab::Routing
let(:metadata) do
diff --git a/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb b/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb
index 63bc7a1caf8..c33b182e9a9 100644
--- a/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb
+++ b/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::GenerateCodequalityMrDiffReportService do
+RSpec.describe Ci::GenerateCodequalityMrDiffReportService, feature_category: :code_review_workflow do
let(:service) { described_class.new(project) }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/ci/generate_coverage_reports_service_spec.rb b/spec/services/ci/generate_coverage_reports_service_spec.rb
index 212e6be9d07..811431bf9d6 100644
--- a/spec/services/ci/generate_coverage_reports_service_spec.rb
+++ b/spec/services/ci/generate_coverage_reports_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::GenerateCoverageReportsService do
+RSpec.describe Ci::GenerateCoverageReportsService, feature_category: :code_testing do
let_it_be(:project) { create(:project, :repository) }
let(:service) { described_class.new(project) }
diff --git a/spec/services/ci/generate_kubeconfig_service_spec.rb b/spec/services/ci/generate_kubeconfig_service_spec.rb
index c0858b0f0c9..da18dfe04c3 100644
--- a/spec/services/ci/generate_kubeconfig_service_spec.rb
+++ b/spec/services/ci/generate_kubeconfig_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::GenerateKubeconfigService do
+RSpec.describe Ci::GenerateKubeconfigService, feature_category: :kubernetes_management do
describe '#execute' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
diff --git a/spec/services/ci/generate_terraform_reports_service_spec.rb b/spec/services/ci/generate_terraform_reports_service_spec.rb
index c32e8bcaeb8..b2142d391b8 100644
--- a/spec/services/ci/generate_terraform_reports_service_spec.rb
+++ b/spec/services/ci/generate_terraform_reports_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::GenerateTerraformReportsService do
+RSpec.describe Ci::GenerateTerraformReportsService, feature_category: :infrastructure_as_code do
let_it_be(:project) { create(:project, :repository) }
describe '#execute' do
diff --git a/spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb b/spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb
new file mode 100644
index 00000000000..a180837f9a9
--- /dev/null
+++ b/spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Ci::JobArtifacts::BulkDeleteByProjectService, "#execute", feature_category: :build_artifacts do
+ subject(:execute) do
+ described_class.new(
+ job_artifact_ids: job_artifact_ids,
+ current_user: current_user,
+ project: project).execute
+ end
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:build, reload: true) do
+ create(:ci_build, :artifacts, :trace_artifact, user: current_user)
+ end
+
+ let_it_be(:project) { build.project }
+ let_it_be(:job_artifact_ids) { build.job_artifacts.map(&:id) }
+
+ describe '#execute' do
+ context 'when number of artifacts exceeds limits to delete' do
+ let_it_be(:second_build, reload: true) do
+ create(:ci_build, :artifacts, :trace_artifact, user: current_user, project: project)
+ end
+
+ let_it_be(:job_artifact_ids) { ::Ci::JobArtifact.all.map(&:id) }
+
+ before do
+ project.add_maintainer(current_user)
+ stub_const("#{described_class}::JOB_ARTIFACTS_COUNT_LIMIT", 1)
+ end
+
+ it 'fails to destroy' do
+ result = execute
+
+ expect(result).to be_error
+ expect(result[:message]).to eq('Can only delete up to 1 job artifacts per call')
+ end
+ end
+
+ context 'when requested not existing artifacts do delete' do
+ let_it_be(:deleted_build, reload: true) do
+ create(:ci_build, :artifacts, :trace_artifact, user: current_user, project: project)
+ end
+
+ let_it_be(:deleted_job_artifacts) { deleted_build.job_artifacts }
+ let_it_be(:job_artifact_ids) { ::Ci::JobArtifact.all.map(&:id) }
+
+ before do
+ project.add_maintainer(current_user)
+ deleted_job_artifacts.each(&:destroy!)
+ end
+
+ it 'fails to destroy' do
+ result = execute
+
+ expect(result).to be_error
+ expect(result[:message]).to eq("Artifacts (#{deleted_job_artifacts.map(&:id).join(',')}) not found")
+ end
+ end
+
+ context 'when maintainer has access to the project' do
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ it 'is successful' do
+ result = execute
+
+ expect(result).to be_success
+ expect(result.payload).to eq(
+ {
+ destroyed_count: job_artifact_ids.count,
+ destroyed_ids: job_artifact_ids,
+ errors: []
+ }
+ )
+ expect(::Ci::JobArtifact.where(id: job_artifact_ids).count).to eq(0)
+ end
+
+ context 'and partially owns artifacts' do
+ let_it_be(:orphan_artifact) { create(:ci_job_artifact, :archive) }
+ let_it_be(:orphan_artifact_id) { orphan_artifact.id }
+ let_it_be(:owned_artifacts_ids) { build.job_artifacts.erasable.map(&:id) }
+ let_it_be(:job_artifact_ids) { [orphan_artifact_id] + owned_artifacts_ids }
+
+ it 'fails to destroy' do
+ result = execute
+
+ expect(result).to be_error
+ expect(result[:message]).to be('Not all artifacts belong to requested project')
+ expect(::Ci::JobArtifact.where(id: job_artifact_ids).count).to eq(3)
+ end
+ end
+
+ context 'and request all artifacts from a different project' do
+ let_it_be(:different_project_artifact) { create(:ci_job_artifact, :archive) }
+ let_it_be(:job_artifact_ids) { [different_project_artifact] }
+
+ let_it_be(:different_build, reload: true) do
+ create(:ci_build, :artifacts, :trace_artifact, user: current_user)
+ end
+
+ let_it_be(:different_project) { different_build.project }
+
+ before do
+ different_project.add_maintainer(current_user)
+ end
+
+ it 'returns a error' do
+ result = execute
+
+ expect(result).to be_error
+ expect(result[:message]).to be('Not all artifacts belong to requested project')
+ expect(::Ci::JobArtifact.where(id: job_artifact_ids).count).to eq(job_artifact_ids.count)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/job_artifacts/create_service_spec.rb b/spec/services/ci/job_artifacts/create_service_spec.rb
index 47e9e5994ef..69f760e28ca 100644
--- a/spec/services/ci/job_artifacts/create_service_spec.rb
+++ b/spec/services/ci/job_artifacts/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::CreateService do
+RSpec.describe Ci::JobArtifacts::CreateService, feature_category: :build_artifacts do
let_it_be(:project) { create(:project) }
let(:service) { described_class.new(job) }
@@ -33,6 +33,66 @@ RSpec.describe Ci::JobArtifacts::CreateService do
describe '#execute' do
subject { service.execute(artifacts_file, params, metadata_file: metadata_file) }
+ def expect_accessibility_be(accessibility)
+ if accessibility == :public
+ expect(job.job_artifacts).to all be_public_accessibility
+ else
+ expect(job.job_artifacts).to all be_private_accessibility
+ end
+ end
+
+ shared_examples 'job does not have public artifacts in the CI config' do |expected_artifacts_count, accessibility|
+ it "sets accessibility by default to #{accessibility}" do
+ expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
+
+ expect_accessibility_be(accessibility)
+ end
+ end
+
+ shared_examples 'job artifact set as private in the CI config' do |expected_artifacts_count, accessibility|
+ let!(:job) { create(:ci_build, :with_private_artifacts_config, project: project) }
+
+ it "sets accessibility to #{accessibility}" do
+ expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
+
+ expect_accessibility_be(accessibility)
+ end
+ end
+
+ shared_examples 'job artifact set as public in the CI config' do |expected_artifacts_count, accessibility|
+ let!(:job) { create(:ci_build, :with_public_artifacts_config, project: project) }
+
+ it "sets accessibility to #{accessibility}" do
+ expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
+
+ expect_accessibility_be(accessibility)
+ end
+ end
+
+ shared_examples 'when accessibility level passed as private' do |expected_artifacts_count, accessibility|
+ before do
+ params.merge!('accessibility' => 'private')
+ end
+
+ it 'sets accessibility to private level' do
+ expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
+
+ expect_accessibility_be(accessibility)
+ end
+ end
+
+ shared_examples 'when accessibility passed as public' do |expected_artifacts_count|
+ before do
+ params.merge!('accessibility' => 'public')
+ end
+
+ it 'sets accessibility level to public' do
+ expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
+
+ expect(job.job_artifacts).to all be_public_accessibility
+ end
+ end
+
context 'when artifacts file is uploaded' do
it 'logs the created artifact' do
expect(Gitlab::Ci::Artifacts::Logger)
@@ -61,37 +121,19 @@ RSpec.describe Ci::JobArtifacts::CreateService do
expect(new_artifact.locked).to eq(job.pipeline.locked)
end
- it 'sets accessibility level by default to public' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(1)
-
- new_artifact = job.job_artifacts.last
- expect(new_artifact).to be_public_accessibility
- end
-
- context 'when accessibility level passed as private' do
+ context 'when non_public_artifacts feature flag is disabled' do
before do
- params.merge!('accessibility' => 'private')
+ stub_feature_flags(non_public_artifacts: false)
end
- it 'sets accessibility level to private' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(1)
-
- new_artifact = job.job_artifacts.last
- expect(new_artifact).to be_private_accessibility
+ context 'when accessibility level not passed to the service' do
+ it_behaves_like 'job does not have public artifacts in the CI config', 1, :public
+ it_behaves_like 'job artifact set as private in the CI config', 1, :public
+ it_behaves_like 'job artifact set as public in the CI config', 1, :public
end
- end
- context 'when accessibility passed as public' do
- before do
- params.merge!('accessibility' => 'public')
- end
-
- it 'sets accessibility to public level' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(1)
-
- new_artifact = job.job_artifacts.last
- expect(new_artifact).to be_public_accessibility
- end
+ it_behaves_like 'when accessibility level passed as private', 1, :public
+ it_behaves_like 'when accessibility passed as public', 1
end
context 'when accessibility passed as invalid value' do
@@ -104,6 +146,16 @@ RSpec.describe Ci::JobArtifacts::CreateService do
end
end
+ context 'when accessibility level not passed to the service' do
+ it_behaves_like 'job does not have public artifacts in the CI config', 1, :public
+ it_behaves_like 'job artifact set as private in the CI config', 1, :private
+ it_behaves_like 'job artifact set as public in the CI config', 1, :public
+ end
+
+ it_behaves_like 'when accessibility level passed as private', 1, :private
+
+ it_behaves_like 'when accessibility passed as public', 1
+
context 'when metadata file is also uploaded' do
let(:metadata_file) do
file_to_upload('spec/fixtures/ci_build_artifacts_metadata.gz', sha256: artifacts_sha256)
@@ -125,13 +177,16 @@ RSpec.describe Ci::JobArtifacts::CreateService do
expect(new_artifact.locked).to eq(job.pipeline.locked)
end
- it 'sets accessibility by default to public' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(2)
-
- new_artifact = job.job_artifacts.last
- expect(new_artifact).to be_public_accessibility
+ context 'when accessibility level not passed to the service' do
+ it_behaves_like 'job does not have public artifacts in the CI config', 2, :public
+ it_behaves_like 'job artifact set as private in the CI config', 2, :private
+ it_behaves_like 'job artifact set as public in the CI config', 2, :public
end
+ it_behaves_like 'when accessibility level passed as private', 2, :privatge
+
+ it_behaves_like 'when accessibility passed as public', 2
+
it 'logs the created artifact and metadata' do
expect(Gitlab::Ci::Artifacts::Logger)
.to receive(:log_created)
@@ -140,32 +195,6 @@ RSpec.describe Ci::JobArtifacts::CreateService do
subject
end
- context 'when accessibility level passed as private' do
- before do
- params.merge!('accessibility' => 'private')
- end
-
- it 'sets accessibility to private level' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(2)
-
- new_artifact = job.job_artifacts.last
- expect(new_artifact).to be_private_accessibility
- end
- end
-
- context 'when accessibility passed as public' do
- before do
- params.merge!('accessibility' => 'public')
- end
-
- it 'sets accessibility level to public' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(2)
-
- new_artifact = job.job_artifacts.last
- expect(new_artifact).to be_public_accessibility
- end
- end
-
it 'sets expiration date according to application settings' do
expected_expire_at = 1.day.from_now
diff --git a/spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb b/spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb
index 74fa42962f3..9c711e54b00 100644
--- a/spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb
+++ b/spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::DeleteProjectArtifactsService do
+RSpec.describe Ci::JobArtifacts::DeleteProjectArtifactsService, feature_category: :build_artifacts do
let_it_be(:project) { create(:project) }
subject { described_class.new(project: project) }
diff --git a/spec/services/ci/job_artifacts/delete_service_spec.rb b/spec/services/ci/job_artifacts/delete_service_spec.rb
index 78e8be48255..1560d0fc6f4 100644
--- a/spec/services/ci/job_artifacts/delete_service_spec.rb
+++ b/spec/services/ci/job_artifacts/delete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::DeleteService do
+RSpec.describe Ci::JobArtifacts::DeleteService, feature_category: :build_artifacts do
let_it_be(:build, reload: true) do
create(:ci_build, :artifacts, :trace_artifact, artifacts_expire_at: 100.days.from_now)
end
diff --git a/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb b/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb
index 457be67c1ea..d1ec2a1d3a6 100644
--- a/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb
+++ b/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb
@@ -39,32 +39,12 @@ feature_category: :build_artifacts do
second_artifact
end
- context 'with ci_destroy_unlocked_job_artifacts feature flag disabled' do
- before do
- stub_feature_flags(ci_destroy_unlocked_job_artifacts: false)
- end
-
- it 'performs a consistent number of queries' do
- control = ActiveRecord::QueryRecorder.new { service.execute }
-
- more_artifacts
-
- expect { subject }.not_to exceed_query_limit(control.count)
- end
- end
-
- context 'with ci_destroy_unlocked_job_artifacts feature flag enabled' do
- before do
- stub_feature_flags(ci_destroy_unlocked_job_artifacts: true)
- end
-
- it 'performs a consistent number of queries' do
- control = ActiveRecord::QueryRecorder.new { service.execute }
+ it 'performs a consistent number of queries' do
+ control = ActiveRecord::QueryRecorder.new { service.execute }
- more_artifacts
+ more_artifacts
- expect { subject }.not_to exceed_query_limit(control.count)
- end
+ expect { subject }.not_to exceed_query_limit(control.count)
end
end
@@ -251,6 +231,16 @@ feature_category: :build_artifacts do
end
end
+ context 'when some artifacts are trace' do
+ let!(:artifact) { create(:ci_job_artifact, :expired, job: job, locked: job.pipeline.locked) }
+ let!(:trace_artifact) { create(:ci_job_artifact, :trace, :expired, job: job, locked: job.pipeline.locked) }
+
+ it 'destroys only non trace artifacts' do
+ expect { subject }.to change { Ci::JobArtifact.count }.by(-1)
+ expect(trace_artifact).to be_persisted
+ end
+ end
+
context 'when all artifacts are locked' do
let!(:artifact) { create(:ci_job_artifact, :expired, job: locked_job, locked: locked_job.pipeline.locked) }
diff --git a/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb b/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb
index ca36c923dcf..f4839ccb04b 100644
--- a/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb
+++ b/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb
@@ -2,24 +2,37 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::DestroyAssociationsService do
+RSpec.describe Ci::JobArtifacts::DestroyAssociationsService, feature_category: :build_artifacts do
let_it_be(:project_1) { create(:project) }
let_it_be(:project_2) { create(:project) }
let_it_be(:artifact_1, refind: true) { create(:ci_job_artifact, :zip, project: project_1) }
- let_it_be(:artifact_2, refind: true) { create(:ci_job_artifact, :zip, project: project_2) }
- let_it_be(:artifact_3, refind: true) { create(:ci_job_artifact, :zip, project: project_1) }
+ let_it_be(:artifact_2, refind: true) { create(:ci_job_artifact, :junit, project: project_2) }
+ let_it_be(:artifact_3, refind: true) { create(:ci_job_artifact, :terraform, project: project_1) }
+ let_it_be(:artifact_4, refind: true) { create(:ci_job_artifact, :trace, project: project_2) }
+ let_it_be(:artifact_5, refind: true) { create(:ci_job_artifact, :metadata, project: project_2) }
- let(:artifacts) { Ci::JobArtifact.where(id: [artifact_1.id, artifact_2.id, artifact_3.id]) }
+ let_it_be(:locked_artifact, refind: true) { create(:ci_job_artifact, :zip, :locked, project: project_1) }
+
+ let(:artifact_ids_to_be_removed) { [artifact_1.id, artifact_2.id, artifact_3.id, artifact_4.id, artifact_5.id] }
+ let(:artifacts) { Ci::JobArtifact.where(id: artifact_ids_to_be_removed) }
let(:service) { described_class.new(artifacts) }
describe '#destroy_records' do
- it 'removes artifacts without updating statistics' do
+ it 'removes all types of artifacts without updating statistics' do
expect_next_instance_of(Ci::JobArtifacts::DestroyBatchService) do |service|
expect(service).to receive(:execute).with(update_stats: false).and_call_original
end
- expect { service.destroy_records }.to change { Ci::JobArtifact.count }.by(-3)
+ expect { service.destroy_records }.to change { Ci::JobArtifact.count }.by(-artifact_ids_to_be_removed.count)
+ end
+
+ context 'with a locked artifact' do
+ let(:artifact_ids_to_be_removed) { [artifact_1.id, locked_artifact.id] }
+
+ it 'removes all artifacts' do
+ expect { service.destroy_records }.to change { Ci::JobArtifact.count }.by(-artifact_ids_to_be_removed.count)
+ end
end
context 'when there are no artifacts' do
@@ -42,7 +55,11 @@ RSpec.describe Ci::JobArtifacts::DestroyAssociationsService do
have_attributes(amount: -artifact_1.size, ref: artifact_1.id),
have_attributes(amount: -artifact_3.size, ref: artifact_3.id)
]
- project2_increments = [have_attributes(amount: -artifact_2.size, ref: artifact_2.id)]
+ project2_increments = [
+ have_attributes(amount: -artifact_2.size, ref: artifact_2.id),
+ have_attributes(amount: -artifact_4.size, ref: artifact_4.id),
+ have_attributes(amount: -artifact_5.size, ref: artifact_5.id)
+ ]
expect(ProjectStatistics).to receive(:bulk_increment_statistic).once
.with(project_1, :build_artifacts_size, match_array(project1_increments))
diff --git a/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb b/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb
index cde42783d8c..6f9dcf47535 100644
--- a/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb
+++ b/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::DestroyBatchService do
- let(:artifacts) { Ci::JobArtifact.where(id: [artifact_with_file.id, artifact_without_file.id, trace_artifact.id]) }
+RSpec.describe Ci::JobArtifacts::DestroyBatchService, feature_category: :build_artifacts do
+ let(:artifacts) { Ci::JobArtifact.where(id: [artifact_with_file.id, artifact_without_file.id]) }
let(:skip_projects_on_refresh) { false }
let(:service) do
described_class.new(
@@ -25,10 +25,6 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do
create(:ci_job_artifact)
end
- let_it_be(:trace_artifact, refind: true) do
- create(:ci_job_artifact, :trace, :expired)
- end
-
describe '#execute' do
subject(:execute) { service.execute }
@@ -60,11 +56,6 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do
execute
end
- it 'preserves trace artifacts' do
- expect { subject }
- .to not_change { Ci::JobArtifact.exists?(trace_artifact.id) }
- end
-
context 'when artifact belongs to a project that is undergoing stats refresh' do
let!(:artifact_under_refresh_1) do
create(:ci_job_artifact, :zip)
@@ -287,7 +278,7 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do
end
it 'reports the number of destroyed artifacts' do
- is_expected.to eq(destroyed_artifacts_count: 0, statistics_updates: {}, status: :success)
+ is_expected.to eq(destroyed_artifacts_count: 0, destroyed_ids: [], statistics_updates: {}, status: :success)
end
end
end
diff --git a/spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb b/spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb
index fb9dd6b876b..69cdf39107a 100644
--- a/spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb
+++ b/spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::ExpireProjectBuildArtifactsService do
+RSpec.describe Ci::JobArtifacts::ExpireProjectBuildArtifactsService, feature_category: :build_artifacts do
let_it_be(:project) { create(:project) }
let_it_be(:pipeline, reload: true) { create(:ci_pipeline, :unlocked, project: project) }
diff --git a/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb b/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb
index d4d56825e1f..5355bec2d6c 100644
--- a/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb
+++ b/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
+RSpec.describe Ci::JobArtifacts::TrackArtifactReportService, feature_category: :build_artifacts do
describe '#execute', :clean_gitlab_redis_shared_state do
let_it_be(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, group: group) }
diff --git a/spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb b/spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb
index 67412e41fb8..5f6a89b89e1 100644
--- a/spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb
+++ b/spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::UpdateUnknownLockedStatusService, :clean_gitlab_redis_shared_state do
+RSpec.describe Ci::JobArtifacts::UpdateUnknownLockedStatusService, :clean_gitlab_redis_shared_state,
+ feature_category: :build_artifacts do
include ExclusiveLeaseHelpers
let(:service) { described_class.new }
diff --git a/spec/services/ci/list_config_variables_service_spec.rb b/spec/services/ci/list_config_variables_service_spec.rb
index e2bbdefef7f..56a392221be 100644
--- a/spec/services/ci/list_config_variables_service_spec.rb
+++ b/spec/services/ci/list_config_variables_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::ListConfigVariablesService,
-:use_clean_rails_memory_store_caching, feature_category: :pipeline_authoring do
+:use_clean_rails_memory_store_caching, feature_category: :pipeline_composition do
include ReactiveCachingHelpers
let(:ci_config) { {} }
diff --git a/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb b/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb
index c4558bddc85..b7b32d2a0af 100644
--- a/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb
+++ b/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineArtifacts::CoverageReportService do
+RSpec.describe Ci::PipelineArtifacts::CoverageReportService, feature_category: :build_artifacts do
describe '#execute' do
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb b/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb
index 5d854b61f14..20265a0ca48 100644
--- a/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb
+++ b/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::PipelineArtifacts::CreateCodeQualityMrDiffReportService do
+RSpec.describe ::Ci::PipelineArtifacts::CreateCodeQualityMrDiffReportService, feature_category: :build_artifacts do
describe '#execute' do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
diff --git a/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb b/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb
index 47e8766c215..b46648760e1 100644
--- a/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb
+++ b/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineArtifacts::DestroyAllExpiredService, :clean_gitlab_redis_shared_state do
+RSpec.describe Ci::PipelineArtifacts::DestroyAllExpiredService, :clean_gitlab_redis_shared_state,
+ feature_category: :build_artifacts do
let(:service) { described_class.new }
describe '.execute' do
diff --git a/spec/services/ci/pipeline_bridge_status_service_spec.rb b/spec/services/ci/pipeline_bridge_status_service_spec.rb
index 1346f68c952..3d8219251d6 100644
--- a/spec/services/ci/pipeline_bridge_status_service_spec.rb
+++ b/spec/services/ci/pipeline_bridge_status_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineBridgeStatusService do
+RSpec.describe Ci::PipelineBridgeStatusService, feature_category: :continuous_integration do
let(:user) { build(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb b/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb
index ab4ba20e716..06139c091b9 100644
--- a/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb
+++ b/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineCreation::StartPipelineService do
+RSpec.describe Ci::PipelineCreation::StartPipelineService, feature_category: :continuous_integration do
let(:pipeline) { build(:ci_pipeline) }
subject(:service) { described_class.new(pipeline) }
diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
index d0aa1ba4c6c..46ea0036e49 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection do
+RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection,
+ feature_category: :continuous_integration do
using RSpec::Parameterized::TableSyntax
let_it_be(:pipeline) { create(:ci_pipeline) }
@@ -35,7 +36,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
it 'does update existing status of processable' do
collection.set_processable_status(test_a.id, 'success', 100)
- expect(collection.status_for_names(['test-a'], dag: false)).to eq('success')
+ expect(collection.status_of_processables(['test-a'], dag: false)).to eq('success')
end
it 'ignores a missing processable' do
@@ -49,7 +50,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
end
end
- describe '#status_for_names' do
+ describe '#status_of_processables' do
where(:names, :status, :dag) do
%w[build-a] | 'success' | false
%w[build-a build-b] | 'failed' | false
@@ -61,12 +62,12 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
with_them do
it 'returns composite status of given names' do
- expect(collection.status_for_names(names, dag: dag)).to eq(status)
+ expect(collection.status_of_processables(names, dag: dag)).to eq(status)
end
end
end
- describe '#status_for_prior_stage_position' do
+ describe '#status_of_processables_prior_to_stage' do
where(:stage, :status) do
0 | 'success'
1 | 'failed'
@@ -75,12 +76,12 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
with_them do
it 'returns composite status for processables in prior stages' do
- expect(collection.status_for_prior_stage_position(stage)).to eq(status)
+ expect(collection.status_of_processables_prior_to_stage(stage)).to eq(status)
end
end
end
- describe '#status_for_stage_position' do
+ describe '#status_of_stage' do
where(:stage, :status) do
0 | 'failed'
1 | 'running'
@@ -89,16 +90,16 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
with_them do
it 'returns composite status for processables at a given stages' do
- expect(collection.status_for_stage_position(stage)).to eq(status)
+ expect(collection.status_of_stage(stage)).to eq(status)
end
end
end
- describe '#created_processable_ids_for_stage_position' do
+ describe '#created_processable_ids_in_stage' do
it 'returns IDs of processables at a given stage position' do
- expect(collection.created_processable_ids_for_stage_position(0)).to be_empty
- expect(collection.created_processable_ids_for_stage_position(1)).to be_empty
- expect(collection.created_processable_ids_for_stage_position(2)).to contain_exactly(deploy.id)
+ expect(collection.created_processable_ids_in_stage(0)).to be_empty
+ expect(collection.created_processable_ids_in_stage(1)).to be_empty
+ expect(collection.created_processable_ids_in_stage(2)).to contain_exactly(deploy.id)
end
end
diff --git a/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb b/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb
index 9a3aad20d89..1d45a06f9ea 100644
--- a/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb
+++ b/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineSchedules::TakeOwnershipService do
+RSpec.describe Ci::PipelineSchedules::TakeOwnershipService, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:owner) { create(:user) }
let_it_be(:reporter) { create(:user) }
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
index 4946367380e..b6e07e82bb5 100644
--- a/spec/services/ci/pipeline_trigger_service_spec.rb
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineTriggerService do
+RSpec.describe Ci::PipelineTriggerService, feature_category: :continuous_integration do
include AfterNextHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/services/ci/pipelines/add_job_service_spec.rb b/spec/services/ci/pipelines/add_job_service_spec.rb
index c62aa9506bd..9fb1d6933c6 100644
--- a/spec/services/ci/pipelines/add_job_service_spec.rb
+++ b/spec/services/ci/pipelines/add_job_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Pipelines::AddJobService do
+RSpec.describe Ci::Pipelines::AddJobService, feature_category: :continuous_integration do
include ExclusiveLeaseHelpers
let_it_be_with_reload(:pipeline) { create(:ci_pipeline) }
diff --git a/spec/services/ci/pipelines/hook_service_spec.rb b/spec/services/ci/pipelines/hook_service_spec.rb
index 8d138a3d957..e773ae2d2c3 100644
--- a/spec/services/ci/pipelines/hook_service_spec.rb
+++ b/spec/services/ci/pipelines/hook_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Pipelines::HookService do
+RSpec.describe Ci::Pipelines::HookService, feature_category: :continuous_integration do
describe '#execute_hooks' do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:project) { create(:project, :repository, namespace: namespace) }
diff --git a/spec/services/ci/play_bridge_service_spec.rb b/spec/services/ci/play_bridge_service_spec.rb
index 56b1615a56d..5727ed64f8b 100644
--- a/spec/services/ci/play_bridge_service_spec.rb
+++ b/spec/services/ci/play_bridge_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PlayBridgeService, '#execute' do
+RSpec.describe Ci::PlayBridgeService, '#execute', feature_category: :continuous_integration do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb
index fc07801b672..f439538b4cc 100644
--- a/spec/services/ci/play_build_service_spec.rb
+++ b/spec/services/ci/play_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PlayBuildService, '#execute' do
+RSpec.describe Ci::PlayBuildService, '#execute', feature_category: :continuous_integration do
let(:user) { create(:user, developer_projects: [project]) }
let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/play_manual_stage_service_spec.rb b/spec/services/ci/play_manual_stage_service_spec.rb
index 24f0a21f3dd..1aca4ffec2d 100644
--- a/spec/services/ci/play_manual_stage_service_spec.rb
+++ b/spec/services/ci/play_manual_stage_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PlayManualStageService, '#execute' do
+RSpec.describe Ci::PlayManualStageService, '#execute', feature_category: :continuous_integration do
let(:current_user) { create(:user) }
let(:pipeline) { create(:ci_pipeline, user: current_user) }
let(:project) { pipeline.project }
diff --git a/spec/services/ci/prepare_build_service_spec.rb b/spec/services/ci/prepare_build_service_spec.rb
index f75cb322fe9..8583b8e667c 100644
--- a/spec/services/ci/prepare_build_service_spec.rb
+++ b/spec/services/ci/prepare_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PrepareBuildService do
+RSpec.describe Ci::PrepareBuildService, feature_category: :continuous_integration do
describe '#execute' do
let(:build) { create(:ci_build, :preparing) }
diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb
index de308bb1a87..d1442b75731 100644
--- a/spec/services/ci/process_build_service_spec.rb
+++ b/spec/services/ci/process_build_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Ci::ProcessBuildService, '#execute' do
+RSpec.describe Ci::ProcessBuildService, '#execute', feature_category: :continuous_integration do
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb
index 404e1bf7c87..d1586ad4c8b 100644
--- a/spec/services/ci/process_pipeline_service_spec.rb
+++ b/spec/services/ci/process_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ProcessPipelineService do
+RSpec.describe Ci::ProcessPipelineService, feature_category: :continuous_integration do
let_it_be(:project) { create(:project) }
let(:pipeline) do
diff --git a/spec/services/ci/process_sync_events_service_spec.rb b/spec/services/ci/process_sync_events_service_spec.rb
index 7ab7911e578..c042a9bd46e 100644
--- a/spec/services/ci/process_sync_events_service_spec.rb
+++ b/spec/services/ci/process_sync_events_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ProcessSyncEventsService do
+RSpec.describe Ci::ProcessSyncEventsService, feature_category: :continuous_integration do
let!(:group) { create(:group) }
let!(:project1) { create(:project, group: group) }
let!(:project2) { create(:project, group: group) }
diff --git a/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb b/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb
index 0b100af5902..a9ee5216d81 100644
--- a/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb
+++ b/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PrometheusMetrics::ObserveHistogramsService do
+RSpec.describe Ci::PrometheusMetrics::ObserveHistogramsService, feature_category: :continuous_integration do
let_it_be(:project) { create(:project) }
let(:params) { {} }
diff --git a/spec/services/ci/queue/pending_builds_strategy_spec.rb b/spec/services/ci/queue/pending_builds_strategy_spec.rb
index 6f22c256c17..ea9207ddb8f 100644
--- a/spec/services/ci/queue/pending_builds_strategy_spec.rb
+++ b/spec/services/ci/queue/pending_builds_strategy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Queue::PendingBuildsStrategy do
+RSpec.describe Ci::Queue::PendingBuildsStrategy, feature_category: :continuous_integration do
let_it_be(:group) { create(:group) }
let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let_it_be(:project) { create(:project, group: group) }
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 9183df359b4..18cb016f94a 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -16,126 +16,155 @@ module Ci
describe '#execute' do
subject(:execute) { described_class.new(runner, runner_machine).execute }
- context 'with runner_machine specified' do
- let(:runner) { project_runner }
- let!(:runner_machine) { create(:ci_runner_machine, runner: project_runner) }
+ let(:runner_machine) { nil }
+
+ context 'checks database loadbalancing stickiness' do
+ let(:runner) { shared_runner }
before do
- pending_job.update!(tag_list: ["linux"])
- pending_job.reload
- pending_job.create_queuing_entry!
- project_runner.update!(tag_list: ["linux"])
+ project.update!(shared_runners_enabled: false)
end
- it 'sets runner_machine on job' do
- expect { execute }.to change { pending_job.reload.runner_machine }.from(nil).to(runner_machine)
+ 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(execute.build).to eq(pending_job)
+ expect { execute }.not_to change { Ci::RunnerMachineBuild.count }.from(0)
+ expect(execute).to be_valid
+ expect(execute.build).to be_nil
+ expect(execute.build_json).to be_nil
end
- end
-
- context 'with no runner machine' do
- let(:runner_machine) { nil }
-
- context 'checks database loadbalancing stickiness' do
- let(:runner) { shared_runner }
-
- before do
- project.update!(shared_runners_enabled: false)
- 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 }
+ 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(execute).to be_valid
- expect(execute.build).to be_nil
- expect(execute.build_json).to be_nil
- end
+ expect(subject).not_to be_valid
+ expect(subject.build).to be_nil
+ expect(subject.build_json).to be_nil
+ end
+ 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 }
+ shared_examples 'handles runner assignment' do
+ context 'runner follows tag list' do
+ subject(:build) { build_on(project_runner, runner_machine: project_runner_machine) }
- expect(subject).not_to be_valid
- expect(subject.build).to be_nil
- expect(subject.build_json).to be_nil
- end
- end
+ let(:project_runner_machine) { nil }
- shared_examples 'handles runner assignment' do
- context 'runner follow tag list' do
- it "picks build with the same tag" do
+ context 'when job has tag' do
+ before do
pending_job.update!(tag_list: ["linux"])
pending_job.reload
pending_job.create_queuing_entry!
- project_runner.update!(tag_list: ["linux"])
- expect(build_on(project_runner)).to eq(pending_job)
end
- it "does not pick build with different tag" do
- pending_job.update!(tag_list: ["linux"])
- pending_job.reload
- pending_job.create_queuing_entry!
- project_runner.update!(tag_list: ["win32"])
- expect(build_on(project_runner)).to be_falsey
+ context 'and runner has matching tag' do
+ before do
+ project_runner.update!(tag_list: ["linux"])
+ end
+
+ context 'with no runner machine specified' do
+ it 'picks build' do
+ expect(build).to eq(pending_job)
+ expect(pending_job.runner_machine).to be_nil
+ end
+ end
+
+ context 'with runner machine specified' do
+ let(:project_runner_machine) { create(:ci_runner_machine, runner: project_runner) }
+
+ it 'picks build and assigns runner machine' do
+ expect(build).to eq(pending_job)
+ expect(pending_job.runner_machine).to eq(project_runner_machine)
+ end
+ end
end
- it "picks build without tag" do
- expect(build_on(project_runner)).to eq(pending_job)
+ it 'does not pick build with different tag' do
+ project_runner.update!(tag_list: ["win32"])
+ expect(build).to be_falsey
end
- it "does not pick build with tag" do
- pending_job.update!(tag_list: ["linux"])
- pending_job.reload
+ it 'does not pick build with tag' do
pending_job.create_queuing_entry!
- expect(build_on(project_runner)).to be_falsey
+ expect(build).to be_falsey
end
+ end
- it "pick build without tag" do
- project_runner.update!(tag_list: ["win32"])
- expect(build_on(project_runner)).to eq(pending_job)
+ context 'when job has no tag' do
+ it 'picks build' do
+ expect(build).to eq(pending_job)
+ end
+
+ context 'when runner has tag' do
+ before do
+ project_runner.update!(tag_list: ["win32"])
+ end
+
+ it 'picks build' do
+ expect(build).to eq(pending_job)
+ end
end
end
+ end
- context 'deleted projects' do
+ context 'deleted projects' do
+ before do
+ project.update!(pending_delete: true)
+ end
+
+ context 'for shared runners' do
before do
- project.update!(pending_delete: true)
+ project.update!(shared_runners_enabled: true)
end
- context 'for shared runners' do
- before do
- project.update!(shared_runners_enabled: true)
- end
+ it 'does not pick a build' do
+ expect(build_on(shared_runner)).to be_nil
+ end
+ end
+
+ context 'for project runner' do
+ subject(:build) { build_on(project_runner, runner_machine: project_runner_machine) }
+ let(:project_runner_machine) { nil }
+
+ context 'with no runner machine specified' do
it 'does not pick a build' do
- expect(build_on(shared_runner)).to be_nil
+ expect(build).to be_nil
+ expect(pending_job.reload).to be_failed
+ expect(pending_job.queuing_entry).to be_nil
+ expect(Ci::RunnerMachineBuild.all).to be_empty
end
end
- context 'for project runner' do
+ context 'with runner machine specified' do
+ let(:project_runner_machine) { create(:ci_runner_machine, runner: project_runner) }
+
it 'does not pick a build' do
- expect(build_on(project_runner)).to be_nil
+ expect(build).to be_nil
expect(pending_job.reload).to be_failed
expect(pending_job.queuing_entry).to be_nil
+ expect(Ci::RunnerMachineBuild.all).to be_empty
end
end
end
+ end
- context 'allow shared runners' do
- before do
- project.update!(shared_runners_enabled: true)
- pipeline.reload
- pending_job.reload
- pending_job.create_queuing_entry!
- end
+ context 'allow shared runners' do
+ before do
+ project.update!(shared_runners_enabled: true)
+ pipeline.reload
+ pending_job.reload
+ pending_job.create_queuing_entry!
+ end
- context 'when build owner has been blocked' do
- let(:user) { create(:user, :blocked) }
+ context 'when build owner has been blocked' do
+ let(:user) { create(:user, :blocked) }
- before do
- pending_job.update!(user: user)
- end
+ before do
+ pending_job.update!(user: user)
+ end
+ context 'with no runner machine specified' do
it 'does not pick the build and drops the build' do
expect(build_on(shared_runner)).to be_falsey
@@ -143,690 +172,701 @@ module Ci
end
end
- context 'for multiple builds' do
- let!(:project2) { create :project, shared_runners_enabled: true }
- let!(:pipeline2) { create :ci_pipeline, project: project2 }
- let!(:project3) { create :project, shared_runners_enabled: true }
- let!(:pipeline3) { create :ci_pipeline, project: project3 }
- let!(:build1_project1) { pending_job }
- let!(:build2_project1) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
- let!(:build3_project1) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
- let!(:build1_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) }
- let!(:build2_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) }
- let!(:build1_project3) { create(:ci_build, :pending, :queued, pipeline: pipeline3) }
+ context 'with runner machine specified' do
+ let(:runner_machine) { create(:ci_runner_machine, runner: runner) }
- it 'picks builds one-by-one' do
- expect(Ci::Build).to receive(:find).with(pending_job.id).and_call_original
+ it 'does not pick the build and does not create join record' do
+ expect(build_on(shared_runner, runner_machine: runner_machine)).to be_falsey
- expect(build_on(shared_runner)).to eq(build1_project1)
+ expect(Ci::RunnerMachineBuild.all).to be_empty
end
+ end
+ end
- context 'when using fair scheduling' do
- context 'when all builds are pending' do
- it 'prefers projects without builds first' do
- # it gets for one build from each of the projects
- expect(build_on(shared_runner)).to eq(build1_project1)
- expect(build_on(shared_runner)).to eq(build1_project2)
- expect(build_on(shared_runner)).to eq(build1_project3)
-
- # then it gets a second build from each of the projects
- expect(build_on(shared_runner)).to eq(build2_project1)
- expect(build_on(shared_runner)).to eq(build2_project2)
-
- # in the end the third build
- expect(build_on(shared_runner)).to eq(build3_project1)
- end
- end
+ context 'for multiple builds' do
+ let!(:project2) { create :project, shared_runners_enabled: true }
+ let!(:pipeline2) { create :ci_pipeline, project: project2 }
+ let!(:project3) { create :project, shared_runners_enabled: true }
+ let!(:pipeline3) { create :ci_pipeline, project: project3 }
+ let!(:build1_project1) { pending_job }
+ let!(:build2_project1) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
+ let!(:build3_project1) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
+ let!(:build1_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) }
+ let!(:build2_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) }
+ let!(:build1_project3) { create(:ci_build, :pending, :queued, pipeline: pipeline3) }
+
+ it 'picks builds one-by-one' do
+ expect(Ci::Build).to receive(:find).with(pending_job.id).and_call_original
+
+ expect(build_on(shared_runner)).to eq(build1_project1)
+ end
- context 'when some builds transition to success' do
- it 'equalises number of running builds' do
- # after finishing the first build for project 1, get a second build from the same project
- expect(build_on(shared_runner)).to eq(build1_project1)
- build1_project1.reload.success
- expect(build_on(shared_runner)).to eq(build2_project1)
-
- expect(build_on(shared_runner)).to eq(build1_project2)
- build1_project2.reload.success
- expect(build_on(shared_runner)).to eq(build2_project2)
- expect(build_on(shared_runner)).to eq(build1_project3)
- expect(build_on(shared_runner)).to eq(build3_project1)
- end
+ context 'when using fair scheduling' do
+ context 'when all builds are pending' do
+ it 'prefers projects without builds first' do
+ # it gets for one build from each of the projects
+ expect(build_on(shared_runner)).to eq(build1_project1)
+ expect(build_on(shared_runner)).to eq(build1_project2)
+ expect(build_on(shared_runner)).to eq(build1_project3)
+
+ # then it gets a second build from each of the projects
+ expect(build_on(shared_runner)).to eq(build2_project1)
+ expect(build_on(shared_runner)).to eq(build2_project2)
+
+ # in the end the third build
+ expect(build_on(shared_runner)).to eq(build3_project1)
end
end
- context 'when using DEFCON mode that disables fair scheduling' do
- before do
- stub_feature_flags(ci_queueing_disaster_recovery_disable_fair_scheduling: true)
+ context 'when some builds transition to success' do
+ it 'equalises number of running builds' do
+ # after finishing the first build for project 1, get a second build from the same project
+ expect(build_on(shared_runner)).to eq(build1_project1)
+ build1_project1.reload.success
+ expect(build_on(shared_runner)).to eq(build2_project1)
+
+ expect(build_on(shared_runner)).to eq(build1_project2)
+ build1_project2.reload.success
+ expect(build_on(shared_runner)).to eq(build2_project2)
+ expect(build_on(shared_runner)).to eq(build1_project3)
+ expect(build_on(shared_runner)).to eq(build3_project1)
end
+ end
+ end
- context 'when all builds are pending' do
- it 'returns builds in order of creation (FIFO)' do
- # it gets for one build from each of the projects
- expect(build_on(shared_runner)).to eq(build1_project1)
- expect(build_on(shared_runner)).to eq(build2_project1)
- expect(build_on(shared_runner)).to eq(build3_project1)
- expect(build_on(shared_runner)).to eq(build1_project2)
- expect(build_on(shared_runner)).to eq(build2_project2)
- expect(build_on(shared_runner)).to eq(build1_project3)
- end
+ context 'when using DEFCON mode that disables fair scheduling' do
+ before do
+ stub_feature_flags(ci_queueing_disaster_recovery_disable_fair_scheduling: true)
+ end
+
+ context 'when all builds are pending' do
+ it 'returns builds in order of creation (FIFO)' do
+ # it gets for one build from each of the projects
+ expect(build_on(shared_runner)).to eq(build1_project1)
+ expect(build_on(shared_runner)).to eq(build2_project1)
+ expect(build_on(shared_runner)).to eq(build3_project1)
+ expect(build_on(shared_runner)).to eq(build1_project2)
+ expect(build_on(shared_runner)).to eq(build2_project2)
+ expect(build_on(shared_runner)).to eq(build1_project3)
end
+ end
- context 'when some builds transition to success' do
- it 'returns builds in order of creation (FIFO)' do
- expect(build_on(shared_runner)).to eq(build1_project1)
- build1_project1.reload.success
- expect(build_on(shared_runner)).to eq(build2_project1)
-
- expect(build_on(shared_runner)).to eq(build3_project1)
- build2_project1.reload.success
- expect(build_on(shared_runner)).to eq(build1_project2)
- expect(build_on(shared_runner)).to eq(build2_project2)
- expect(build_on(shared_runner)).to eq(build1_project3)
- end
+ context 'when some builds transition to success' do
+ it 'returns builds in order of creation (FIFO)' do
+ expect(build_on(shared_runner)).to eq(build1_project1)
+ build1_project1.reload.success
+ expect(build_on(shared_runner)).to eq(build2_project1)
+
+ expect(build_on(shared_runner)).to eq(build3_project1)
+ build2_project1.reload.success
+ expect(build_on(shared_runner)).to eq(build1_project2)
+ expect(build_on(shared_runner)).to eq(build2_project2)
+ expect(build_on(shared_runner)).to eq(build1_project3)
end
end
end
+ end
- context 'shared runner' do
- let(:response) { described_class.new(shared_runner, nil).execute }
- let(:build) { response.build }
+ context 'shared runner' do
+ let(:response) { described_class.new(shared_runner, nil).execute }
+ let(:build) { response.build }
- it { expect(build).to be_kind_of(Build) }
- it { expect(build).to be_valid }
- it { expect(build).to be_running }
- it { expect(build.runner).to eq(shared_runner) }
- it { expect(Gitlab::Json.parse(response.build_json)['id']).to eq(build.id) }
- end
+ it { expect(build).to be_kind_of(Build) }
+ it { expect(build).to be_valid }
+ it { expect(build).to be_running }
+ it { expect(build.runner).to eq(shared_runner) }
+ it { expect(Gitlab::Json.parse(response.build_json)['id']).to eq(build.id) }
+ end
- context 'project runner' do
- let(:build) { build_on(project_runner) }
+ context 'project runner' do
+ let(:build) { build_on(project_runner) }
- it { expect(build).to be_kind_of(Build) }
- it { expect(build).to be_valid }
- it { expect(build).to be_running }
- it { expect(build.runner).to eq(project_runner) }
- end
+ it { expect(build).to be_kind_of(Build) }
+ it { expect(build).to be_valid }
+ it { expect(build).to be_running }
+ it { expect(build.runner).to eq(project_runner) }
end
+ end
- context 'disallow shared runners' do
- before do
- project.update!(shared_runners_enabled: false)
- end
+ context 'disallow shared runners' do
+ before do
+ project.update!(shared_runners_enabled: false)
+ end
- context 'shared runner' do
- let(:build) { build_on(shared_runner) }
+ context 'shared runner' do
+ let(:build) { build_on(shared_runner) }
- it { expect(build).to be_nil }
- end
+ it { expect(build).to be_nil }
+ end
- context 'project runner' do
- let(:build) { build_on(project_runner) }
+ context 'project runner' do
+ let(:build) { build_on(project_runner) }
- it { expect(build).to be_kind_of(Build) }
- it { expect(build).to be_valid }
- it { expect(build).to be_running }
- it { expect(build.runner).to eq(project_runner) }
- end
+ it { expect(build).to be_kind_of(Build) }
+ it { expect(build).to be_valid }
+ it { expect(build).to be_running }
+ it { expect(build.runner).to eq(project_runner) }
end
+ end
- context 'disallow when builds are disabled' do
- before do
- project.update!(shared_runners_enabled: true, group_runners_enabled: true)
- project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
+ context 'disallow when builds are disabled' do
+ before do
+ project.update!(shared_runners_enabled: true, group_runners_enabled: true)
+ project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
- pending_job.reload.create_queuing_entry!
- end
+ pending_job.reload.create_queuing_entry!
+ end
- context 'and uses shared runner' do
- let(:build) { build_on(shared_runner) }
+ context 'and uses shared runner' do
+ let(:build) { build_on(shared_runner) }
- it { expect(build).to be_nil }
- end
+ it { expect(build).to be_nil }
+ end
- context 'and uses group runner' do
- let(:build) { build_on(group_runner) }
+ context 'and uses group runner' do
+ let(:build) { build_on(group_runner) }
- it { expect(build).to be_nil }
- end
+ it { expect(build).to be_nil }
+ end
- context 'and uses project runner' do
- let(:build) { build_on(project_runner) }
+ context 'and uses project runner' do
+ let(:build) { build_on(project_runner) }
- it 'does not pick a build' do
- expect(build).to be_nil
- expect(pending_job.reload).to be_failed
- expect(pending_job.queuing_entry).to be_nil
- end
+ it 'does not pick a build' do
+ expect(build).to be_nil
+ expect(pending_job.reload).to be_failed
+ expect(pending_job.queuing_entry).to be_nil
end
end
+ end
- context 'allow group runners' do
- before do
- project.update!(group_runners_enabled: true)
- end
+ context 'allow group runners' do
+ before do
+ project.update!(group_runners_enabled: true)
+ end
- context 'for multiple builds' do
- let!(:project2) { create(:project, group_runners_enabled: true, group: group) }
- let!(:pipeline2) { create(:ci_pipeline, project: project2) }
- let!(:project3) { create(:project, group_runners_enabled: true, group: group) }
- let!(:pipeline3) { create(:ci_pipeline, project: project3) }
+ context 'for multiple builds' do
+ let!(:project2) { create(:project, group_runners_enabled: true, group: group) }
+ let!(:pipeline2) { create(:ci_pipeline, project: project2) }
+ let!(:project3) { create(:project, group_runners_enabled: true, group: group) }
+ let!(:pipeline3) { create(:ci_pipeline, project: project3) }
- let!(:build1_project1) { pending_job }
- let!(:build2_project1) { create(:ci_build, :queued, pipeline: pipeline) }
- let!(:build3_project1) { create(:ci_build, :queued, pipeline: pipeline) }
- let!(:build1_project2) { create(:ci_build, :queued, pipeline: pipeline2) }
- let!(:build2_project2) { create(:ci_build, :queued, pipeline: pipeline2) }
- let!(:build1_project3) { create(:ci_build, :queued, pipeline: pipeline3) }
+ let!(:build1_project1) { pending_job }
+ let!(:build2_project1) { create(:ci_build, :queued, pipeline: pipeline) }
+ let!(:build3_project1) { create(:ci_build, :queued, pipeline: pipeline) }
+ let!(:build1_project2) { create(:ci_build, :queued, pipeline: pipeline2) }
+ let!(:build2_project2) { create(:ci_build, :queued, pipeline: pipeline2) }
+ let!(:build1_project3) { create(:ci_build, :queued, pipeline: pipeline3) }
- # these shouldn't influence the scheduling
- let!(:unrelated_group) { create(:group) }
- let!(:unrelated_project) { create(:project, group_runners_enabled: true, group: unrelated_group) }
- let!(:unrelated_pipeline) { create(:ci_pipeline, project: unrelated_project) }
- let!(:build1_unrelated_project) { create(:ci_build, :pending, :queued, pipeline: unrelated_pipeline) }
- let!(:unrelated_group_runner) { create(:ci_runner, :group, groups: [unrelated_group]) }
+ # these shouldn't influence the scheduling
+ let!(:unrelated_group) { create(:group) }
+ let!(:unrelated_project) { create(:project, group_runners_enabled: true, group: unrelated_group) }
+ let!(:unrelated_pipeline) { create(:ci_pipeline, project: unrelated_project) }
+ let!(:build1_unrelated_project) { create(:ci_build, :pending, :queued, pipeline: unrelated_pipeline) }
+ let!(:unrelated_group_runner) { create(:ci_runner, :group, groups: [unrelated_group]) }
- it 'does not consider builds from other group runners' do
- queue = ::Ci::Queue::BuildQueueService.new(group_runner)
+ it 'does not consider builds from other group runners' do
+ queue = ::Ci::Queue::BuildQueueService.new(group_runner)
- expect(queue.builds_for_group_runner.size).to eq 6
- build_on(group_runner)
+ expect(queue.builds_for_group_runner.size).to eq 6
+ build_on(group_runner)
- expect(queue.builds_for_group_runner.size).to eq 5
- build_on(group_runner)
+ expect(queue.builds_for_group_runner.size).to eq 5
+ build_on(group_runner)
- expect(queue.builds_for_group_runner.size).to eq 4
- build_on(group_runner)
+ expect(queue.builds_for_group_runner.size).to eq 4
+ build_on(group_runner)
- expect(queue.builds_for_group_runner.size).to eq 3
- build_on(group_runner)
+ expect(queue.builds_for_group_runner.size).to eq 3
+ build_on(group_runner)
- expect(queue.builds_for_group_runner.size).to eq 2
- build_on(group_runner)
+ expect(queue.builds_for_group_runner.size).to eq 2
+ build_on(group_runner)
- expect(queue.builds_for_group_runner.size).to eq 1
- build_on(group_runner)
+ expect(queue.builds_for_group_runner.size).to eq 1
+ build_on(group_runner)
- expect(queue.builds_for_group_runner.size).to eq 0
- expect(build_on(group_runner)).to be_nil
- end
+ expect(queue.builds_for_group_runner.size).to eq 0
+ expect(build_on(group_runner)).to be_nil
end
+ end
- context 'group runner' do
- let(:build) { build_on(group_runner) }
+ context 'group runner' do
+ let(:build) { build_on(group_runner) }
- it { expect(build).to be_kind_of(Build) }
- it { expect(build).to be_valid }
- it { expect(build).to be_running }
- it { expect(build.runner).to eq(group_runner) }
- end
+ it { expect(build).to be_kind_of(Build) }
+ it { expect(build).to be_valid }
+ it { expect(build).to be_running }
+ it { expect(build.runner).to eq(group_runner) }
end
+ end
- context 'disallow group runners' do
- before do
- project.update!(group_runners_enabled: false)
+ context 'disallow group runners' do
+ before do
+ project.update!(group_runners_enabled: false)
- pending_job.reload.create_queuing_entry!
- end
+ pending_job.reload.create_queuing_entry!
+ end
- context 'group runner' do
- let(:build) { build_on(group_runner) }
+ context 'group runner' do
+ let(:build) { build_on(group_runner) }
- it { expect(build).to be_nil }
- end
+ it { expect(build).to be_nil }
end
+ end
- context 'when first build is stalled' do
- before do
- allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!).and_call_original
- allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!)
- .with(pending_job, anything).and_raise(ActiveRecord::StaleObjectError)
- end
+ context 'when first build is stalled' do
+ before do
+ allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!).and_call_original
+ allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!)
+ .with(pending_job, anything).and_raise(ActiveRecord::StaleObjectError)
+ end
- subject { described_class.new(project_runner, nil).execute }
+ subject { described_class.new(project_runner, nil).execute }
- context 'with multiple builds are in queue' do
- let!(:other_build) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
+ context 'with multiple builds are in queue' do
+ let!(:other_build) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
- before do
- allow_any_instance_of(::Ci::Queue::BuildQueueService)
- .to receive(:execute)
- .and_return(Ci::Build.where(id: [pending_job, other_build]).pluck(:id))
- end
+ before do
+ allow_any_instance_of(::Ci::Queue::BuildQueueService)
+ .to receive(:execute)
+ .and_return(Ci::Build.where(id: [pending_job, other_build]).pluck(:id))
+ end
- it "receives second build from the queue" do
- expect(subject).to be_valid
- expect(subject.build).to eq(other_build)
- end
+ it "receives second build from the queue" do
+ expect(subject).to be_valid
+ expect(subject.build).to eq(other_build)
end
+ end
- context 'when single build is in queue' do
- before do
- allow_any_instance_of(::Ci::Queue::BuildQueueService)
- .to receive(:execute)
- .and_return(Ci::Build.where(id: pending_job).pluck(:id))
- end
+ context 'when single build is in queue' do
+ before do
+ allow_any_instance_of(::Ci::Queue::BuildQueueService)
+ .to receive(:execute)
+ .and_return(Ci::Build.where(id: pending_job).pluck(:id))
+ end
- it "does not receive any valid result" do
- expect(subject).not_to be_valid
- end
+ it "does not receive any valid result" do
+ expect(subject).not_to be_valid
end
+ end
- context 'when there is no build in queue' do
- before do
- allow_any_instance_of(::Ci::Queue::BuildQueueService)
- .to receive(:execute)
- .and_return([])
- end
+ context 'when there is no build in queue' do
+ before do
+ allow_any_instance_of(::Ci::Queue::BuildQueueService)
+ .to receive(:execute)
+ .and_return([])
+ end
- it "does not receive builds but result is valid" do
- expect(subject).to be_valid
- expect(subject.build).to be_nil
- end
+ it "does not receive builds but result is valid" do
+ expect(subject).to be_valid
+ expect(subject.build).to be_nil
end
end
+ end
- context 'when access_level of runner is not_protected' do
- let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
+ context 'when access_level of runner is not_protected' do
+ let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
- context 'when a job is protected' do
- let!(:pending_job) { create(:ci_build, :pending, :queued, :protected, pipeline: pipeline) }
+ context 'when a job is protected' do
+ let!(:pending_job) { create(:ci_build, :pending, :queued, :protected, pipeline: pipeline) }
- it 'picks the job' do
- expect(build_on(project_runner)).to eq(pending_job)
- end
+ it 'picks the job' do
+ expect(build_on(project_runner)).to eq(pending_job)
end
+ end
- context 'when a job is unprotected' do
- let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
+ context 'when a job is unprotected' do
+ let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
- it 'picks the job' do
- expect(build_on(project_runner)).to eq(pending_job)
- end
+ it 'picks the job' do
+ expect(build_on(project_runner)).to eq(pending_job)
end
+ end
- context 'when protected attribute of a job is nil' do
- let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
+ context 'when protected attribute of a job is nil' do
+ let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
- before do
- pending_job.update_attribute(:protected, nil)
- end
+ before do
+ pending_job.update_attribute(:protected, nil)
+ end
- it 'picks the job' do
- expect(build_on(project_runner)).to eq(pending_job)
- end
+ it 'picks the job' do
+ expect(build_on(project_runner)).to eq(pending_job)
end
end
+ end
- context 'when access_level of runner is ref_protected' do
- let!(:project_runner) { create(:ci_runner, :project, :ref_protected, projects: [project]) }
+ context 'when access_level of runner is ref_protected' do
+ let!(:project_runner) { create(:ci_runner, :project, :ref_protected, projects: [project]) }
- context 'when a job is protected' do
- let!(:pending_job) { create(:ci_build, :pending, :queued, :protected, pipeline: pipeline) }
+ context 'when a job is protected' do
+ let!(:pending_job) { create(:ci_build, :pending, :queued, :protected, pipeline: pipeline) }
- it 'picks the job' do
- expect(build_on(project_runner)).to eq(pending_job)
- end
+ it 'picks the job' do
+ expect(build_on(project_runner)).to eq(pending_job)
end
+ end
- context 'when a job is unprotected' do
- let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
+ context 'when a job is unprotected' do
+ let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
- it 'does not pick the job' do
- expect(build_on(project_runner)).to be_nil
- end
+ it 'does not pick the job' do
+ expect(build_on(project_runner)).to be_nil
end
+ end
- context 'when protected attribute of a job is nil' do
- let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
+ context 'when protected attribute of a job is nil' do
+ let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
- before do
- pending_job.update_attribute(:protected, nil)
- end
+ before do
+ pending_job.update_attribute(:protected, nil)
+ end
- it 'does not pick the job' do
- expect(build_on(project_runner)).to be_nil
- end
+ it 'does not pick the job' do
+ expect(build_on(project_runner)).to be_nil
end
end
+ end
- context 'runner feature set is verified' do
- let(:options) { { artifacts: { reports: { junit: "junit.xml" } } } }
- let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, options: options) }
+ context 'runner feature set is verified' do
+ let(:options) { { artifacts: { reports: { junit: "junit.xml" } } } }
+ let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, options: options) }
- subject { build_on(project_runner, params: params) }
+ subject { build_on(project_runner, params: params) }
- context 'when feature is missing by runner' do
- let(:params) { {} }
+ context 'when feature is missing by runner' do
+ let(:params) { {} }
- it 'does not pick the build and drops the build' do
- expect(subject).to be_nil
- expect(pending_job.reload).to be_failed
- expect(pending_job).to be_runner_unsupported
- end
+ it 'does not pick the build and drops the build' do
+ expect(subject).to be_nil
+ expect(pending_job.reload).to be_failed
+ expect(pending_job).to be_runner_unsupported
end
+ end
- context 'when feature is supported by runner' do
- let(:params) do
- { info: { features: { upload_multiple_artifacts: true } } }
- end
+ context 'when feature is supported by runner' do
+ let(:params) do
+ { info: { features: { upload_multiple_artifacts: true } } }
+ end
- it 'does pick job' do
- expect(subject).not_to be_nil
- end
+ it 'does pick job' do
+ expect(subject).not_to be_nil
end
end
+ end
- context 'when "dependencies" keyword is specified' do
- let!(:pre_stage_job) do
- create(:ci_build, :success, :artifacts, pipeline: pipeline, name: 'test', stage_idx: 0)
- end
+ context 'when "dependencies" keyword is specified' do
+ let!(:pre_stage_job) do
+ create(:ci_build, :success, :artifacts, pipeline: pipeline, name: 'test', stage_idx: 0)
+ end
- let!(:pending_job) do
- create(:ci_build, :pending, :queued,
- pipeline: pipeline, stage_idx: 1,
- options: { script: ["bash"], dependencies: dependencies })
- end
+ let!(:pending_job) do
+ create(:ci_build, :pending, :queued,
+ pipeline: pipeline, stage_idx: 1,
+ options: { script: ["bash"], dependencies: dependencies })
+ end
- let(:dependencies) { %w[test] }
+ let(:dependencies) { %w[test] }
- subject { build_on(project_runner) }
+ subject { build_on(project_runner) }
- it 'picks a build with a dependency' do
- picked_build = build_on(project_runner)
+ it 'picks a build with a dependency' do
+ picked_build = build_on(project_runner)
- expect(picked_build).to be_present
+ expect(picked_build).to be_present
+ end
+
+ context 'when there are multiple dependencies with artifacts' do
+ let!(:pre_stage_job_second) do
+ create(:ci_build, :success, :artifacts, pipeline: pipeline, name: 'deploy', stage_idx: 0)
end
- context 'when there are multiple dependencies with artifacts' do
- let!(:pre_stage_job_second) do
- create(:ci_build, :success, :artifacts, pipeline: pipeline, name: 'deploy', stage_idx: 0)
- end
+ let(:dependencies) { %w[test deploy] }
- let(:dependencies) { %w[test deploy] }
+ it 'logs build artifacts size' do
+ build_on(project_runner)
- it 'logs build artifacts size' do
- build_on(project_runner)
+ artifacts_size = [pre_stage_job, pre_stage_job_second].sum do |job|
+ job.job_artifacts_archive.size
+ end
- artifacts_size = [pre_stage_job, pre_stage_job_second].sum do |job|
- job.job_artifacts_archive.size
- end
+ expect(artifacts_size).to eq 107464 * 2
+ expect(Gitlab::ApplicationContext.current).to include({
+ 'meta.artifacts_dependencies_size' => artifacts_size,
+ 'meta.artifacts_dependencies_count' => 2
+ })
+ end
+ end
- expect(artifacts_size).to eq 107464 * 2
- expect(Gitlab::ApplicationContext.current).to include({
- 'meta.artifacts_dependencies_size' => artifacts_size,
- 'meta.artifacts_dependencies_count' => 2
- })
- end
+ shared_examples 'not pick' do
+ it 'does not pick the build and drops the build' do
+ expect(subject).to be_nil
+ expect(pending_job.reload).to be_failed
+ expect(pending_job).to be_missing_dependency_failure
end
+ end
- shared_examples 'not pick' do
- it 'does not pick the build and drops the build' do
- expect(subject).to be_nil
- expect(pending_job.reload).to be_failed
- expect(pending_job).to be_missing_dependency_failure
+ shared_examples 'validation is active' do
+ context 'when depended job has not been completed yet' do
+ let!(:pre_stage_job) do
+ create(:ci_build, :pending, :queued, :manual, pipeline: pipeline, name: 'test', stage_idx: 0)
end
- end
- shared_examples 'validation is active' do
- context 'when depended job has not been completed yet' do
- let!(:pre_stage_job) do
- create(:ci_build, :pending, :queued, :manual, pipeline: pipeline, name: 'test', stage_idx: 0)
- end
+ it { is_expected.to eq(pending_job) }
+ end
- it { is_expected.to eq(pending_job) }
+ context 'when artifacts of depended job has been expired' do
+ let!(:pre_stage_job) do
+ create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0)
end
- context 'when artifacts of depended job has been expired' do
- let!(:pre_stage_job) do
- create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0)
+ context 'when the pipeline is locked' do
+ before do
+ pipeline.artifacts_locked!
end
- context 'when the pipeline is locked' do
- before do
- pipeline.artifacts_locked!
- end
+ it { is_expected.to eq(pending_job) }
+ end
- it { is_expected.to eq(pending_job) }
+ context 'when the pipeline is unlocked' do
+ before do
+ pipeline.unlocked!
end
- context 'when the pipeline is unlocked' do
- before do
- pipeline.unlocked!
- end
+ it_behaves_like 'not pick'
+ end
+ end
- it_behaves_like 'not pick'
- end
+ context 'when artifacts of depended job has been erased' do
+ let!(:pre_stage_job) do
+ create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago)
end
- context 'when artifacts of depended job has been erased' do
- let!(:pre_stage_job) do
- create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago)
- end
+ it_behaves_like 'not pick'
+ end
- it_behaves_like 'not pick'
+ context 'when job object is staled' do
+ let!(:pre_stage_job) do
+ create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0)
end
- context 'when job object is staled' do
- let!(:pre_stage_job) do
- create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0)
- end
-
- before do
- pipeline.unlocked!
+ before do
+ pipeline.unlocked!
- allow_next_instance_of(Ci::Build) do |build|
- expect(build).to receive(:drop!)
- .and_raise(ActiveRecord::StaleObjectError.new(pending_job, :drop!))
- end
+ allow_next_instance_of(Ci::Build) do |build|
+ expect(build).to receive(:drop!)
+ .and_raise(ActiveRecord::StaleObjectError.new(pending_job, :drop!))
end
+ end
- it 'does not drop nor pick' do
- expect(subject).to be_nil
- end
+ it 'does not drop nor pick' do
+ expect(subject).to be_nil
end
end
+ end
- shared_examples 'validation is not active' do
- context 'when depended job has not been completed yet' do
- let!(:pre_stage_job) do
- create(:ci_build, :pending, :queued, :manual, pipeline: pipeline, name: 'test', stage_idx: 0)
- end
-
- it { expect(subject).to eq(pending_job) }
+ shared_examples 'validation is not active' do
+ context 'when depended job has not been completed yet' do
+ let!(:pre_stage_job) do
+ create(:ci_build, :pending, :queued, :manual, pipeline: pipeline, name: 'test', stage_idx: 0)
end
- context 'when artifacts of depended job has been expired' do
- let!(:pre_stage_job) do
- create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0)
- end
+ it { expect(subject).to eq(pending_job) }
+ end
- it { expect(subject).to eq(pending_job) }
+ context 'when artifacts of depended job has been expired' do
+ let!(:pre_stage_job) do
+ create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0)
end
- context 'when artifacts of depended job has been erased' do
- let!(:pre_stage_job) do
- create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago)
- end
+ it { expect(subject).to eq(pending_job) }
+ end
- it { expect(subject).to eq(pending_job) }
+ context 'when artifacts of depended job has been erased' do
+ let!(:pre_stage_job) do
+ create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago)
end
- end
- it_behaves_like 'validation is active'
+ it { expect(subject).to eq(pending_job) }
+ end
end
- context 'when build is degenerated' do
- let!(:pending_job) { create(:ci_build, :pending, :queued, :degenerated, pipeline: pipeline) }
+ it_behaves_like 'validation is active'
+ end
- subject { build_on(project_runner) }
+ context 'when build is degenerated' do
+ let!(:pending_job) { create(:ci_build, :pending, :queued, :degenerated, pipeline: pipeline) }
- it 'does not pick the build and drops the build' do
- expect(subject).to be_nil
+ subject { build_on(project_runner) }
- pending_job.reload
- expect(pending_job).to be_failed
- expect(pending_job).to be_archived_failure
- end
+ it 'does not pick the build and drops the build' do
+ expect(subject).to be_nil
+
+ pending_job.reload
+ expect(pending_job).to be_failed
+ expect(pending_job).to be_archived_failure
end
+ end
- context 'when build has data integrity problem' do
- let!(:pending_job) do
- create(:ci_build, :pending, :queued, pipeline: pipeline)
- end
+ context 'when build has data integrity problem' do
+ let!(:pending_job) do
+ create(:ci_build, :pending, :queued, pipeline: pipeline)
+ end
- before do
- pending_job.update_columns(options: "string")
- end
+ before do
+ pending_job.update_columns(options: "string")
+ end
- subject { build_on(project_runner) }
+ subject { build_on(project_runner) }
- it 'does drop the build and logs both failures' do
- expect(Gitlab::ErrorTracking).to receive(:track_exception)
- .with(anything, a_hash_including(build_id: pending_job.id))
- .twice
- .and_call_original
+ it 'does drop the build and logs both failures' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+ .with(anything, a_hash_including(build_id: pending_job.id))
+ .twice
+ .and_call_original
- expect(subject).to be_nil
+ expect(subject).to be_nil
- pending_job.reload
- expect(pending_job).to be_failed
- expect(pending_job).to be_data_integrity_failure
- end
+ pending_job.reload
+ expect(pending_job).to be_failed
+ expect(pending_job).to be_data_integrity_failure
end
+ end
- context 'when build fails to be run!' do
- let!(:pending_job) do
- create(:ci_build, :pending, :queued, pipeline: pipeline)
- end
+ context 'when build fails to be run!' do
+ let!(:pending_job) do
+ create(:ci_build, :pending, :queued, pipeline: pipeline)
+ end
- before do
- expect_any_instance_of(Ci::Build).to receive(:run!)
- .and_raise(RuntimeError, 'scheduler error')
- end
+ before do
+ expect_any_instance_of(Ci::Build).to receive(:run!)
+ .and_raise(RuntimeError, 'scheduler error')
+ end
- subject { build_on(project_runner) }
+ subject { build_on(project_runner) }
- it 'does drop the build and logs failure' do
- expect(Gitlab::ErrorTracking).to receive(:track_exception)
- .with(anything, a_hash_including(build_id: pending_job.id))
- .once
- .and_call_original
+ it 'does drop the build and logs failure' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+ .with(anything, a_hash_including(build_id: pending_job.id))
+ .once
+ .and_call_original
- expect(subject).to be_nil
+ expect(subject).to be_nil
- pending_job.reload
- expect(pending_job).to be_failed
- expect(pending_job).to be_scheduler_failure
- end
+ pending_job.reload
+ expect(pending_job).to be_failed
+ expect(pending_job).to be_scheduler_failure
end
+ end
- context 'when an exception is raised during a persistent ref creation' do
- before do
- allow_any_instance_of(Ci::PersistentRef).to receive(:exist?) { false }
- allow_any_instance_of(Ci::PersistentRef).to receive(:create_ref) { raise ArgumentError }
- end
+ context 'when an exception is raised during a persistent ref creation' do
+ before do
+ allow_any_instance_of(Ci::PersistentRef).to receive(:exist?) { false }
+ allow_any_instance_of(Ci::PersistentRef).to receive(:create_ref) { raise ArgumentError }
+ end
- subject { build_on(project_runner) }
+ subject { build_on(project_runner) }
- it 'picks the build' do
- expect(subject).to eq(pending_job)
+ it 'picks the build' do
+ expect(subject).to eq(pending_job)
- pending_job.reload
- expect(pending_job).to be_running
- end
+ pending_job.reload
+ expect(pending_job).to be_running
end
+ end
- context 'when only some builds can be matched by runner' do
- let!(:project_runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[matching]) }
- let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[matching]) }
+ context 'when only some builds can be matched by runner' do
+ let!(:project_runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[matching]) }
+ let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[matching]) }
- before do
- # create additional matching and non-matching jobs
- create_list(:ci_build, 2, :pending, :queued, pipeline: pipeline, tag_list: %w[matching])
- create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[non-matching])
- end
+ before do
+ # create additional matching and non-matching jobs
+ create_list(:ci_build, 2, :pending, :queued, pipeline: pipeline, tag_list: %w[matching])
+ create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[non-matching])
+ end
- it 'observes queue size of only matching jobs' do
- # pending_job + 2 x matching ones
- expect(Gitlab::Ci::Queue::Metrics.queue_size_total).to receive(:observe)
- .with({ runner_type: project_runner.runner_type }, 3)
+ it 'observes queue size of only matching jobs' do
+ # pending_job + 2 x matching ones
+ expect(Gitlab::Ci::Queue::Metrics.queue_size_total).to receive(:observe)
+ .with({ runner_type: project_runner.runner_type }, 3)
- expect(build_on(project_runner)).to eq(pending_job)
- end
+ expect(build_on(project_runner)).to eq(pending_job)
+ end
- it 'observes queue processing time by the runner type' do
- expect(Gitlab::Ci::Queue::Metrics.queue_iteration_duration_seconds)
- .to receive(:observe)
- .with({ runner_type: project_runner.runner_type }, anything)
+ it 'observes queue processing time by the runner type' do
+ expect(Gitlab::Ci::Queue::Metrics.queue_iteration_duration_seconds)
+ .to receive(:observe)
+ .with({ runner_type: project_runner.runner_type }, anything)
- expect(Gitlab::Ci::Queue::Metrics.queue_retrieval_duration_seconds)
- .to receive(:observe)
- .with({ runner_type: project_runner.runner_type }, anything)
+ expect(Gitlab::Ci::Queue::Metrics.queue_retrieval_duration_seconds)
+ .to receive(:observe)
+ .with({ runner_type: project_runner.runner_type }, anything)
- expect(build_on(project_runner)).to eq(pending_job)
- end
+ expect(build_on(project_runner)).to eq(pending_job)
end
+ end
- context 'when ci_register_job_temporary_lock is enabled' do
- before do
- stub_feature_flags(ci_register_job_temporary_lock: true)
+ context 'when ci_register_job_temporary_lock is enabled' do
+ before do
+ stub_feature_flags(ci_register_job_temporary_lock: true)
+
+ allow(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment)
+ end
- allow(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment)
+ context 'when a build is temporarily locked' do
+ let(:service) { described_class.new(project_runner, nil) }
+
+ before do
+ service.send(:acquire_temporary_lock, pending_job.id)
end
- context 'when a build is temporarily locked' do
- let(:service) { described_class.new(project_runner, nil) }
+ it 'skips this build and marks queue as invalid' do
+ expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment)
+ .with(operation: :queue_iteration)
+ expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment)
+ .with(operation: :build_temporary_locked)
- before do
- service.send(:acquire_temporary_lock, pending_job.id)
- end
+ expect(service.execute).not_to be_valid
+ end
- it 'skips this build and marks queue as invalid' do
+ context 'when there is another build in queue' do
+ let!(:next_pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
+
+ it 'skips this build and picks another build' do
expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment)
- .with(operation: :queue_iteration)
+ .with(operation: :queue_iteration).twice
expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment)
.with(operation: :build_temporary_locked)
- expect(service.execute).not_to be_valid
- end
-
- context 'when there is another build in queue' do
- let!(:next_pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
-
- it 'skips this build and picks another build' do
- expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment)
- .with(operation: :queue_iteration).twice
- expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment)
- .with(operation: :build_temporary_locked)
+ result = service.execute
- result = service.execute
-
- expect(result.build).to eq(next_pending_job)
- expect(result).to be_valid
- end
+ expect(result.build).to eq(next_pending_job)
+ expect(result).to be_valid
end
end
end
end
+ end
- context 'when using pending builds table' do
- include_examples 'handles runner assignment'
+ context 'when using pending builds table' do
+ let!(:runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[conflict]) }
- context 'when a conflicting data is stored in denormalized table' do
- let!(:runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[conflict]) }
- let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[conflict]) }
+ include_examples 'handles runner assignment'
- before do
- pending_job.update_column(:status, :running)
- end
+ context 'when a conflicting data is stored in denormalized table' do
+ let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[conflict]) }
- it 'removes queuing entry upon build assignment attempt' do
- expect(pending_job.reload).to be_running
- expect(pending_job.queuing_entry).to be_present
+ before do
+ pending_job.update_column(:status, :running)
+ end
- expect(execute).not_to be_valid
- expect(pending_job.reload.queuing_entry).not_to be_present
- end
+ it 'removes queuing entry upon build assignment attempt' do
+ expect(pending_job.reload).to be_running
+ expect(pending_job.queuing_entry).to be_present
+
+ expect(execute).not_to be_valid
+ expect(pending_job.reload.queuing_entry).not_to be_present
end
end
end
diff --git a/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb b/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb
index 3d1abe290bc..ea15e3ea2c0 100644
--- a/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb
+++ b/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupService do
+RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupService, feature_category: :continuous_integration do
include ConcurrentHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index 07518c35fab..51a894640ab 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::RetryPipelineService, '#execute' do
+RSpec.describe Ci::RetryPipelineService, '#execute', feature_category: :continuous_integration do
include ProjectForksHelper
let_it_be_with_refind(:user) { create(:user) }
diff --git a/spec/services/ci/run_scheduled_build_service_spec.rb b/spec/services/ci/run_scheduled_build_service_spec.rb
index 27d25e88944..e3ae1d93e5e 100644
--- a/spec/services/ci/run_scheduled_build_service_spec.rb
+++ b/spec/services/ci/run_scheduled_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::RunScheduledBuildService do
+RSpec.describe Ci::RunScheduledBuildService, feature_category: :continuous_integration do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/runners/create_runner_service_spec.rb b/spec/services/ci/runners/create_runner_service_spec.rb
index 673bf3ef90e..52acfcbb7af 100644
--- a/spec/services/ci/runners/create_runner_service_spec.rb
+++ b/spec/services/ci/runners/create_runner_service_spec.rb
@@ -83,6 +83,49 @@ RSpec.describe ::Ci::Runners::CreateRunnerService, "#execute", feature_category:
expect(runner.authenticated_user_registration_type?).to be_truthy
expect(runner.runner_type).to eq 'instance_type'
end
+
+ context 'with a nil paused value' do
+ let(:args) do
+ {
+ paused: nil,
+ description: 'some description',
+ maintenance_note: 'a note',
+ tag_list: %w[tag1 tag2],
+ access_level: 'ref_protected',
+ locked: true,
+ maximum_timeout: 600,
+ run_untagged: false
+ }
+ end
+
+ it { is_expected.to be_success }
+
+ it 'creates runner with active set to true' do
+ expect(runner).to be_an_instance_of(::Ci::Runner)
+ expect(runner.active).to eq true
+ end
+ end
+
+ context 'with no paused value given' do
+ let(:args) do
+ {
+ description: 'some description',
+ maintenance_note: 'a note',
+ tag_list: %w[tag1 tag2],
+ access_level: 'ref_protected',
+ locked: true,
+ maximum_timeout: 600,
+ run_untagged: false
+ }
+ end
+
+ it { is_expected.to be_success }
+
+ it 'creates runner with active set to true' do
+ expect(runner).to be_an_instance_of(::Ci::Runner)
+ expect(runner.active).to eq true
+ end
+ end
end
end
diff --git a/spec/services/ci/runners/process_runner_version_update_service_spec.rb b/spec/services/ci/runners/process_runner_version_update_service_spec.rb
index e62cb1ec3e3..f8b7aa281af 100644
--- a/spec/services/ci/runners/process_runner_version_update_service_spec.rb
+++ b/spec/services/ci/runners/process_runner_version_update_service_spec.rb
@@ -29,6 +29,19 @@ RSpec.describe Ci::Runners::ProcessRunnerVersionUpdateService, feature_category:
end
end
+ context 'when fetching runner releases is disabled' do
+ before do
+ stub_application_setting(update_runner_versions_enabled: false)
+ end
+
+ it 'does not update ci_runner_versions records', :aggregate_failures do
+ expect do
+ expect(execute).to be_error
+ expect(execute.message).to eq 'version update disabled'
+ end.not_to change(Ci::RunnerVersion, :count).from(0)
+ end
+ end
+
context 'with successful result from upgrade check' do
before do
url = ::Gitlab::CurrentSettings.current_application_settings.public_runner_releases_url
diff --git a/spec/services/ci/stuck_builds/drop_pending_service_spec.rb b/spec/services/ci/stuck_builds/drop_pending_service_spec.rb
index a452a65829a..6d91f5098eb 100644
--- a/spec/services/ci/stuck_builds/drop_pending_service_spec.rb
+++ b/spec/services/ci/stuck_builds/drop_pending_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::StuckBuilds::DropPendingService do
+RSpec.describe Ci::StuckBuilds::DropPendingService, feature_category: :runner_fleet do
let_it_be(:runner) { create(:ci_runner) }
let_it_be(:pipeline) { create(:ci_empty_pipeline) }
let_it_be_with_reload(:job) do
diff --git a/spec/services/ci/stuck_builds/drop_running_service_spec.rb b/spec/services/ci/stuck_builds/drop_running_service_spec.rb
index c1c92c2b8e2..deb807753c2 100644
--- a/spec/services/ci/stuck_builds/drop_running_service_spec.rb
+++ b/spec/services/ci/stuck_builds/drop_running_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::StuckBuilds::DropRunningService do
+RSpec.describe Ci::StuckBuilds::DropRunningService, feature_category: :runner_fleet do
let!(:runner) { create :ci_runner }
let!(:job) { create(:ci_build, runner: runner, created_at: created_at, updated_at: updated_at, status: status) }
diff --git a/spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb b/spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb
index a4f9f97fffc..f2e658c3ae3 100644
--- a/spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb
+++ b/spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::StuckBuilds::DropScheduledService do
+RSpec.describe Ci::StuckBuilds::DropScheduledService, feature_category: :runner_fleet do
let_it_be(:runner) { create :ci_runner }
let!(:job) { create :ci_build, :scheduled, scheduled_at: scheduled_at, runner: runner }
diff --git a/spec/services/ci/test_failure_history_service_spec.rb b/spec/services/ci/test_failure_history_service_spec.rb
index 10f6c6f5007..e77c6533483 100644
--- a/spec/services/ci/test_failure_history_service_spec.rb
+++ b/spec/services/ci/test_failure_history_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
+RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be_with_reload(:pipeline) do
diff --git a/spec/services/ci/track_failed_build_service_spec.rb b/spec/services/ci/track_failed_build_service_spec.rb
index 676769d2fc7..23e7cee731d 100644
--- a/spec/services/ci/track_failed_build_service_spec.rb
+++ b/spec/services/ci/track_failed_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::TrackFailedBuildService do
+RSpec.describe Ci::TrackFailedBuildService, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
diff --git a/spec/services/ci/unlock_artifacts_service_spec.rb b/spec/services/ci/unlock_artifacts_service_spec.rb
index c15e1cb2b5d..1921ea4bdba 100644
--- a/spec/services/ci/unlock_artifacts_service_spec.rb
+++ b/spec/services/ci/unlock_artifacts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::UnlockArtifactsService do
+RSpec.describe Ci::UnlockArtifactsService, feature_category: :continuous_integration do
using RSpec::Parameterized::TableSyntax
where(:tag) do
@@ -24,7 +24,7 @@ RSpec.describe Ci::UnlockArtifactsService do
let!(:older_ambiguous_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: !tag, project: project, locked: :artifacts_locked) }
let!(:code_coverage_pipeline) { create(:ci_pipeline, :with_coverage_report_artifact, ref: ref, tag: tag, project: project, locked: :artifacts_locked) }
let!(:pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: tag, project: project, locked: :artifacts_locked) }
- let!(:child_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: tag, project: project, locked: :artifacts_locked) }
+ let!(:child_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: tag, child_of: pipeline, project: project, locked: :artifacts_locked) }
let!(:newer_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: tag, project: project, locked: :artifacts_locked) }
let!(:other_ref_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: 'other_ref', tag: tag, project: project, locked: :artifacts_locked) }
let!(:sources_pipeline) { create(:ci_sources_pipeline, source_job: source_job, source_project: project, pipeline: child_pipeline, project: project) }
@@ -201,8 +201,7 @@ RSpec.describe Ci::UnlockArtifactsService do
describe '#unlock_job_artifacts_query' do
subject { described_class.new(pipeline.project, pipeline.user).unlock_job_artifacts_query(pipeline_ids) }
- context 'when running on a ref before a pipeline' do
- let(:before_pipeline) { pipeline }
+ context 'when given a single pipeline ID' do
let(:pipeline_ids) { [older_pipeline.id] }
it 'produces the expected SQL string' do
@@ -226,8 +225,7 @@ RSpec.describe Ci::UnlockArtifactsService do
end
end
- context 'when running on just the ref' do
- let(:before_pipeline) { nil }
+ context 'when given multiple pipeline IDs' do
let(:pipeline_ids) { [older_pipeline.id, newer_pipeline.id, pipeline.id] }
it 'produces the expected SQL string' do
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index dd26339831c..4fd4492278d 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::UpdateBuildQueueService do
+RSpec.describe Ci::UpdateBuildQueueService, feature_category: :continuous_integration do
let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
diff --git a/spec/services/ci/update_instance_variables_service_spec.rb b/spec/services/ci/update_instance_variables_service_spec.rb
index f235d006e34..19f28793f90 100644
--- a/spec/services/ci/update_instance_variables_service_spec.rb
+++ b/spec/services/ci/update_instance_variables_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::UpdateInstanceVariablesService do
+RSpec.describe Ci::UpdateInstanceVariablesService, feature_category: :pipeline_composition do
let(:params) { { variables_attributes: variables_attributes } }
subject { described_class.new(params) }
diff --git a/spec/services/ci/update_pending_build_service_spec.rb b/spec/services/ci/update_pending_build_service_spec.rb
index e49b22299f0..abf31dd5184 100644
--- a/spec/services/ci/update_pending_build_service_spec.rb
+++ b/spec/services/ci/update_pending_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::UpdatePendingBuildService do
+RSpec.describe Ci::UpdatePendingBuildService, feature_category: :continuous_integration do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be_with_reload(:pending_build_1) { create(:ci_pending_build, project: project, instance_runners_enabled: false) }
diff --git a/spec/services/clusters/agent_tokens/create_service_spec.rb b/spec/services/clusters/agent_tokens/create_service_spec.rb
index dc7abd1504b..519a3ba7ce5 100644
--- a/spec/services/clusters/agent_tokens/create_service_spec.rb
+++ b/spec/services/clusters/agent_tokens/create_service_spec.rb
@@ -2,14 +2,14 @@
require 'spec_helper'
-RSpec.describe Clusters::AgentTokens::CreateService do
- subject(:service) { described_class.new(container: project, current_user: user, params: params) }
+RSpec.describe Clusters::AgentTokens::CreateService, feature_category: :kubernetes_management do
+ subject(:service) { described_class.new(agent: cluster_agent, current_user: user, params: params) }
let_it_be(:user) { create(:user) }
let(:cluster_agent) { create(:cluster_agent) }
let(:project) { cluster_agent.project }
- let(:params) { { agent_id: cluster_agent.id, description: 'token description', name: 'token name' } }
+ let(:params) { { description: 'token description', name: 'token name' } }
describe '#execute' do
subject { service.execute }
@@ -75,7 +75,7 @@ RSpec.describe Clusters::AgentTokens::CreateService do
it 'returns validation errors', :aggregate_failures do
expect(subject.status).to eq(:error)
- expect(subject.message).to eq(["Agent must exist", "Name can't be blank"])
+ expect(subject.message).to eq(["Name can't be blank"])
end
end
end
diff --git a/spec/services/clusters/agent_tokens/revoke_service_spec.rb b/spec/services/clusters/agent_tokens/revoke_service_spec.rb
new file mode 100644
index 00000000000..9e511de0a13
--- /dev/null
+++ b/spec/services/clusters/agent_tokens/revoke_service_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Clusters::AgentTokens::RevokeService, feature_category: :kubernetes_management do
+ describe '#execute' do
+ subject { described_class.new(token: agent_token, current_user: user).execute }
+
+ let(:agent) { create(:cluster_agent) }
+ let(:agent_token) { create(:cluster_agent_token, agent: agent) }
+ let(:project) { agent.project }
+ let(:user) { agent.created_by_user }
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ context 'when user is authorized' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ context 'when user revokes agent token' do
+ it 'succeeds' do
+ subject
+
+ expect(agent_token.revoked?).to be true
+ end
+
+ it 'creates an activity event' do
+ expect { subject }.to change { ::Clusters::Agents::ActivityEvent.count }.by(1)
+
+ event = agent.activity_events.last
+
+ expect(event).to have_attributes(
+ kind: 'token_revoked',
+ level: 'info',
+ recorded_at: agent_token.reload.updated_at,
+ user: user,
+ agent_token: agent_token
+ )
+ end
+ end
+
+ context 'when there is a validation failure' do
+ before do
+ agent_token.name = '' # make the record invalid, as we require a name to be present
+ end
+
+ it 'fails without raising an error', :aggregate_failures do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq(["Name can't be blank"])
+ end
+
+ it 'does not create an activity event' do
+ expect { subject }.not_to change { ::Clusters::Agents::ActivityEvent.count }
+ end
+ end
+ end
+
+ context 'when user is not authorized' do
+ let(:user) { create(:user) }
+
+ before do
+ project.add_guest(user)
+ end
+
+ context 'when user attempts to revoke agent token' do
+ it 'fails' do
+ subject
+
+ expect(agent_token.revoked?).to be false
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/clusters/agent_tokens/track_usage_service_spec.rb b/spec/services/clusters/agent_tokens/track_usage_service_spec.rb
index 3350b15a5ce..e9e1a5f7ad9 100644
--- a/spec/services/clusters/agent_tokens/track_usage_service_spec.rb
+++ b/spec/services/clusters/agent_tokens/track_usage_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::AgentTokens::TrackUsageService do
+RSpec.describe Clusters::AgentTokens::TrackUsageService, feature_category: :kubernetes_management do
let_it_be(:agent) { create(:cluster_agent) }
describe '#execute', :clean_gitlab_redis_cache do
diff --git a/spec/services/clusters/agents/authorize_proxy_user_service_spec.rb b/spec/services/clusters/agents/authorize_proxy_user_service_spec.rb
new file mode 100644
index 00000000000..c099d87f6eb
--- /dev/null
+++ b/spec/services/clusters/agents/authorize_proxy_user_service_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Clusters::Agents::AuthorizeProxyUserService, feature_category: :kubernetes_management do
+ subject(:service_response) { service.execute }
+
+ let(:service) { described_class.new(user, agent) }
+ let(:user) { create(:user) }
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:user_access_config) do
+ {
+ 'user_access' => {
+ 'access_as' => { 'agent' => {} },
+ 'projects' => [{ 'id' => project.full_path }],
+ 'groups' => [{ 'id' => group.full_path }]
+ }
+ }
+ end
+
+ let_it_be(:configuration_project) do
+ create(
+ :project, :custom_repo,
+ files: {
+ ".gitlab/agents/the-agent/config.yaml" => user_access_config.to_yaml
+ }
+ )
+ end
+
+ let_it_be(:agent) { create(:cluster_agent, name: 'the-agent', project: configuration_project) }
+
+ it 'returns forbidden when user has no access to any project', :aggregate_failures do
+ expect(service_response).to be_error
+ expect(service_response.reason).to eq :forbidden
+ end
+
+ context 'when user is member of an authorized group' do
+ it 'authorizes developers', :aggregate_failures do
+ group.add_member(user, :developer)
+ expect(service_response).to be_success
+ expect(service_response.payload[:user]).to include(id: user.id, username: user.username)
+ expect(service_response.payload[:agent]).to include(id: agent.id, config_project: { id: agent.project.id })
+ end
+
+ it 'does not authorize reporters', :aggregate_failures do
+ group.add_member(user, :reporter)
+ expect(service_response).to be_error
+ expect(service_response.reason).to eq :forbidden
+ end
+ end
+
+ context 'when user is member of an authorized project' do
+ it 'authorizes developers', :aggregate_failures do
+ project.add_member(user, :developer)
+ expect(service_response).to be_success
+ expect(service_response.payload[:user]).to include(id: user.id, username: user.username)
+ expect(service_response.payload[:agent]).to include(id: agent.id, config_project: { id: agent.project.id })
+ end
+
+ it 'does not authorize reporters', :aggregate_failures do
+ project.add_member(user, :reporter)
+ expect(service_response).to be_error
+ expect(service_response.reason).to eq :forbidden
+ end
+ end
+end
diff --git a/spec/services/clusters/agents/create_activity_event_service_spec.rb b/spec/services/clusters/agents/create_activity_event_service_spec.rb
index 7a8f0e16d60..3da8ecddb8d 100644
--- a/spec/services/clusters/agents/create_activity_event_service_spec.rb
+++ b/spec/services/clusters/agents/create_activity_event_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::CreateActivityEventService do
+RSpec.describe Clusters::Agents::CreateActivityEventService, feature_category: :kubernetes_management do
let_it_be(:agent) { create(:cluster_agent) }
let_it_be(:token) { create(:cluster_agent_token, agent: agent) }
let_it_be(:user) { create(:user) }
@@ -40,5 +40,16 @@ RSpec.describe Clusters::Agents::CreateActivityEventService do
subject
end
+
+ context 'when activity event creation fails' do
+ let(:params) { {} }
+
+ it 'tracks the exception without raising' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+ .with(instance_of(ActiveRecord::RecordInvalid), agent_id: agent.id)
+
+ subject
+ end
+ end
end
end
diff --git a/spec/services/clusters/agents/create_service_spec.rb b/spec/services/clusters/agents/create_service_spec.rb
index 2b3bbcae13c..dc69dfb5e27 100644
--- a/spec/services/clusters/agents/create_service_spec.rb
+++ b/spec/services/clusters/agents/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::CreateService do
+RSpec.describe Clusters::Agents::CreateService, feature_category: :kubernetes_management do
subject(:service) { described_class.new(project, user) }
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/services/clusters/agents/delete_expired_events_service_spec.rb b/spec/services/clusters/agents/delete_expired_events_service_spec.rb
index 3dc166f54eb..892cd5a70ea 100644
--- a/spec/services/clusters/agents/delete_expired_events_service_spec.rb
+++ b/spec/services/clusters/agents/delete_expired_events_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::DeleteExpiredEventsService do
+RSpec.describe Clusters::Agents::DeleteExpiredEventsService, feature_category: :kubernetes_management do
let_it_be(:agent) { create(:cluster_agent) }
describe '#execute' do
diff --git a/spec/services/clusters/agents/delete_service_spec.rb b/spec/services/clusters/agents/delete_service_spec.rb
index abe1bdaab27..da97cdee4ca 100644
--- a/spec/services/clusters/agents/delete_service_spec.rb
+++ b/spec/services/clusters/agents/delete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::DeleteService do
+RSpec.describe Clusters::Agents::DeleteService, feature_category: :kubernetes_management do
subject(:service) { described_class.new(container: project, current_user: user) }
let(:cluster_agent) { create(:cluster_agent) }
diff --git a/spec/services/clusters/build_kubernetes_namespace_service_spec.rb b/spec/services/clusters/build_kubernetes_namespace_service_spec.rb
index 4ee933374f6..b1be3eb4199 100644
--- a/spec/services/clusters/build_kubernetes_namespace_service_spec.rb
+++ b/spec/services/clusters/build_kubernetes_namespace_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::BuildKubernetesNamespaceService do
+RSpec.describe Clusters::BuildKubernetesNamespaceService, feature_category: :kubernetes_management do
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:environment) { create(:environment) }
let(:project) { environment.project }
diff --git a/spec/services/clusters/build_service_spec.rb b/spec/services/clusters/build_service_spec.rb
index c7a64435d3b..9e71b7a8115 100644
--- a/spec/services/clusters/build_service_spec.rb
+++ b/spec/services/clusters/build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::BuildService do
+RSpec.describe Clusters::BuildService, feature_category: :kubernetes_management do
describe '#execute' do
subject { described_class.new(cluster_subject).execute }
diff --git a/spec/services/clusters/cleanup/project_namespace_service_spec.rb b/spec/services/clusters/cleanup/project_namespace_service_spec.rb
index 8d3ae217a9f..366e4fa9c03 100644
--- a/spec/services/clusters/cleanup/project_namespace_service_spec.rb
+++ b/spec/services/clusters/cleanup/project_namespace_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Cleanup::ProjectNamespaceService do
+RSpec.describe Clusters::Cleanup::ProjectNamespaceService, feature_category: :kubernetes_management do
describe '#execute' do
subject { service.execute }
diff --git a/spec/services/clusters/cleanup/service_account_service_spec.rb b/spec/services/clusters/cleanup/service_account_service_spec.rb
index 769762237f9..881ec85b3d5 100644
--- a/spec/services/clusters/cleanup/service_account_service_spec.rb
+++ b/spec/services/clusters/cleanup/service_account_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Cleanup::ServiceAccountService do
+RSpec.describe Clusters::Cleanup::ServiceAccountService, feature_category: :kubernetes_management do
describe '#execute' do
subject { service.execute }
diff --git a/spec/services/clusters/create_service_spec.rb b/spec/services/clusters/create_service_spec.rb
index 95f10cdbd80..0d170f66f4a 100644
--- a/spec/services/clusters/create_service_spec.rb
+++ b/spec/services/clusters/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::CreateService do
+RSpec.describe Clusters::CreateService, feature_category: :kubernetes_management do
let(:access_token) { 'xxx' }
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/services/clusters/destroy_service_spec.rb b/spec/services/clusters/destroy_service_spec.rb
index dc600c9e830..2bc0099ff04 100644
--- a/spec/services/clusters/destroy_service_spec.rb
+++ b/spec/services/clusters/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::DestroyService do
+RSpec.describe Clusters::DestroyService, feature_category: :kubernetes_management do
describe '#execute' do
subject { described_class.new(cluster.user, params).execute(cluster) }
diff --git a/spec/services/clusters/integrations/create_service_spec.rb b/spec/services/clusters/integrations/create_service_spec.rb
index 9104e07504d..fa47811dc6b 100644
--- a/spec/services/clusters/integrations/create_service_spec.rb
+++ b/spec/services/clusters/integrations/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Integrations::CreateService, '#execute' do
+RSpec.describe Clusters::Integrations::CreateService, '#execute', feature_category: :kubernetes_management do
let_it_be(:project) { create(:project) }
let_it_be_with_reload(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
diff --git a/spec/services/clusters/integrations/prometheus_health_check_service_spec.rb b/spec/services/clusters/integrations/prometheus_health_check_service_spec.rb
index 526462931a6..2d527bb0872 100644
--- a/spec/services/clusters/integrations/prometheus_health_check_service_spec.rb
+++ b/spec/services/clusters/integrations/prometheus_health_check_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Integrations::PrometheusHealthCheckService, '#execute' do
+RSpec.describe Clusters::Integrations::PrometheusHealthCheckService, '#execute', feature_category: :kubernetes_management do
let(:service) { described_class.new(cluster) }
subject { service.execute }
diff --git a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
index 90956e7b4ea..8ae34e4f9ab 100644
--- a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
+++ b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do
+RSpec.describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute', feature_category: :kubernetes_management do
include KubernetesHelpers
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
diff --git a/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb
index 37478a0bcd9..bdf46c19e36 100644
--- a/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb
+++ b/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
+RSpec.describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService, feature_category: :kubernetes_management do
include KubernetesHelpers
let(:api_url) { 'http://111.111.111.111' }
diff --git a/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb b/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb
index 03c402fb066..2b77df1eb6d 100644
--- a/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb
+++ b/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Kubernetes::FetchKubernetesTokenService do
+RSpec.describe Clusters::Kubernetes::FetchKubernetesTokenService, feature_category: :kubernetes_management do
include KubernetesHelpers
describe '#execute' do
diff --git a/spec/services/clusters/kubernetes_spec.rb b/spec/services/clusters/kubernetes_spec.rb
index 12af63890fc..7e22c2f95df 100644
--- a/spec/services/clusters/kubernetes_spec.rb
+++ b/spec/services/clusters/kubernetes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Kubernetes do
+RSpec.describe Clusters::Kubernetes, feature_category: :kubernetes_management do
it { is_expected.to be_const_defined(:GITLAB_SERVICE_ACCOUNT_NAME) }
it { is_expected.to be_const_defined(:GITLAB_SERVICE_ACCOUNT_NAMESPACE) }
it { is_expected.to be_const_defined(:GITLAB_ADMIN_TOKEN_NAME) }
diff --git a/spec/services/clusters/management/validate_management_project_permissions_service_spec.rb b/spec/services/clusters/management/validate_management_project_permissions_service_spec.rb
index a21c378d3d1..8a49d90aa48 100644
--- a/spec/services/clusters/management/validate_management_project_permissions_service_spec.rb
+++ b/spec/services/clusters/management/validate_management_project_permissions_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Management::ValidateManagementProjectPermissionsService do
+RSpec.describe Clusters::Management::ValidateManagementProjectPermissionsService, feature_category: :kubernetes_management do
describe '#execute' do
subject { described_class.new(user).execute(cluster, management_project_id) }
diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb
index 9aead97f41c..31661d30f41 100644
--- a/spec/services/clusters/update_service_spec.rb
+++ b/spec/services/clusters/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::UpdateService do
+RSpec.describe Clusters::UpdateService, feature_category: :kubernetes_management do
include KubernetesHelpers
describe '#execute' do
diff --git a/spec/services/cohorts_service_spec.rb b/spec/services/cohorts_service_spec.rb
index dce8d4f80f2..ab53bcf8657 100644
--- a/spec/services/cohorts_service_spec.rb
+++ b/spec/services/cohorts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CohortsService do
+RSpec.describe CohortsService, feature_category: :shared do
describe '#execute' do
def month_start(months_ago)
months_ago.months.ago.beginning_of_month.to_date
diff --git a/spec/services/commits/cherry_pick_service_spec.rb b/spec/services/commits/cherry_pick_service_spec.rb
index 2565e17ac90..880ebea1c09 100644
--- a/spec/services/commits/cherry_pick_service_spec.rb
+++ b/spec/services/commits/cherry_pick_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Commits::CherryPickService do
+RSpec.describe Commits::CherryPickService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
# * ddd0f15ae83993f5cb66a927a28673882e99100b (HEAD -> master, origin/master, origin/HEAD) Merge branch 'po-fix-test-en
# |\
diff --git a/spec/services/commits/commit_patch_service_spec.rb b/spec/services/commits/commit_patch_service_spec.rb
index edd0918e488..a9d61be23be 100644
--- a/spec/services/commits/commit_patch_service_spec.rb
+++ b/spec/services/commits/commit_patch_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Commits::CommitPatchService do
+RSpec.describe Commits::CommitPatchService, feature_category: :source_code_management do
describe '#execute' do
let(:patches) do
patches_folder = Rails.root.join('spec/fixtures/patchfiles')
diff --git a/spec/services/commits/tag_service_spec.rb b/spec/services/commits/tag_service_spec.rb
index dd742ebe469..25aa84276c3 100644
--- a/spec/services/commits/tag_service_spec.rb
+++ b/spec/services/commits/tag_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Commits::TagService do
+RSpec.describe Commits::TagService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb
index e96a7f2f4f4..6757fbdf5d4 100644
--- a/spec/services/compare_service_spec.rb
+++ b/spec/services/compare_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CompareService do
+RSpec.describe CompareService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:service) { described_class.new(project, 'feature') }
diff --git a/spec/services/concerns/audit_event_save_type_spec.rb b/spec/services/concerns/audit_event_save_type_spec.rb
index fbaebd9f85c..a89eb513d27 100644
--- a/spec/services/concerns/audit_event_save_type_spec.rb
+++ b/spec/services/concerns/audit_event_save_type_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuditEventSaveType do
+RSpec.describe AuditEventSaveType, feature_category: :audit_events do
subject(:target) { Object.new.extend(described_class) }
describe '#should_save_database? and #should_save_stream?' do
diff --git a/spec/services/concerns/exclusive_lease_guard_spec.rb b/spec/services/concerns/exclusive_lease_guard_spec.rb
index 6a2aa0a377b..b081d2642c0 100644
--- a/spec/services/concerns/exclusive_lease_guard_spec.rb
+++ b/spec/services/concerns/exclusive_lease_guard_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ExclusiveLeaseGuard, :clean_gitlab_redis_shared_state do
+RSpec.describe ExclusiveLeaseGuard, :clean_gitlab_redis_shared_state, feature_category: :shared do
subject :subject_class do
Class.new do
include ExclusiveLeaseGuard
diff --git a/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb b/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb
index 5b1e8fca31b..c6ee5b78c13 100644
--- a/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb
+++ b/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::AssignsMergeParams do
+RSpec.describe MergeRequests::AssignsMergeParams, feature_category: :code_review_workflow do
it 'raises an error when used from an instance that does not respond to #current_user' do
define_class = -> { Class.new { include MergeRequests::AssignsMergeParams }.new }
diff --git a/spec/services/concerns/rate_limited_service_spec.rb b/spec/services/concerns/rate_limited_service_spec.rb
index d913cd17067..2172c756ecf 100644
--- a/spec/services/concerns/rate_limited_service_spec.rb
+++ b/spec/services/concerns/rate_limited_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RateLimitedService do
+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] } } }
diff --git a/spec/services/container_expiration_policies/cleanup_service_spec.rb b/spec/services/container_expiration_policies/cleanup_service_spec.rb
index 6e1be7271e1..4663944f0b9 100644
--- a/spec/services/container_expiration_policies/cleanup_service_spec.rb
+++ b/spec/services/container_expiration_policies/cleanup_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ContainerExpirationPolicies::CleanupService do
+RSpec.describe ContainerExpirationPolicies::CleanupService, feature_category: :container_registry do
let_it_be(:repository, reload: true) { create(:container_repository, expiration_policy_started_at: 30.minutes.ago) }
let_it_be(:project) { repository.project }
@@ -190,6 +190,7 @@ RSpec.describe ContainerExpirationPolicies::CleanupService do
context 'with only the current repository started_at before the policy next_run_at' do
before do
+ repository.update!(expiration_policy_started_at: policy.next_run_at + 9.minutes)
repository2.update!(expiration_policy_started_at: policy.next_run_at + 10.minutes)
repository3.update!(expiration_policy_started_at: policy.next_run_at + 12.minutes)
end
diff --git a/spec/services/container_expiration_policies/update_service_spec.rb b/spec/services/container_expiration_policies/update_service_spec.rb
index 7d949b77de7..992240201e0 100644
--- a/spec/services/container_expiration_policies/update_service_spec.rb
+++ b/spec/services/container_expiration_policies/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ContainerExpirationPolicies::UpdateService do
+RSpec.describe ContainerExpirationPolicies::UpdateService, feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
let_it_be(:project, reload: true) { create(:project) }
diff --git a/spec/services/customer_relations/contacts/create_service_spec.rb b/spec/services/customer_relations/contacts/create_service_spec.rb
index db6cce799fe..610143586e3 100644
--- a/spec/services/customer_relations/contacts/create_service_spec.rb
+++ b/spec/services/customer_relations/contacts/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CustomerRelations::Contacts::CreateService do
+RSpec.describe CustomerRelations::Contacts::CreateService, feature_category: :service_desk do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:not_found_or_does_not_belong) { 'The specified organization was not found or does not belong to this group' }
diff --git a/spec/services/customer_relations/contacts/update_service_spec.rb b/spec/services/customer_relations/contacts/update_service_spec.rb
index 729fdc2058b..105b5bad5f7 100644
--- a/spec/services/customer_relations/contacts/update_service_spec.rb
+++ b/spec/services/customer_relations/contacts/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CustomerRelations::Contacts::UpdateService do
+RSpec.describe CustomerRelations::Contacts::UpdateService, feature_category: :service_desk do
let_it_be(:user) { create(:user) }
let(:contact) { create(:contact, first_name: 'Mark', group: group, state: 'active') }
diff --git a/spec/services/customer_relations/organizations/create_service_spec.rb b/spec/services/customer_relations/organizations/create_service_spec.rb
index 18eefdd716e..3b1ae5606b1 100644
--- a/spec/services/customer_relations/organizations/create_service_spec.rb
+++ b/spec/services/customer_relations/organizations/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CustomerRelations::Organizations::CreateService do
+RSpec.describe CustomerRelations::Organizations::CreateService, feature_category: :service_desk do
describe '#execute' do
let_it_be(:user) { create(:user) }
diff --git a/spec/services/customer_relations/organizations/update_service_spec.rb b/spec/services/customer_relations/organizations/update_service_spec.rb
index 4764ba85551..ac71a211bf8 100644
--- a/spec/services/customer_relations/organizations/update_service_spec.rb
+++ b/spec/services/customer_relations/organizations/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CustomerRelations::Organizations::UpdateService do
+RSpec.describe CustomerRelations::Organizations::UpdateService, feature_category: :service_desk do
let_it_be(:user) { create(:user) }
let(:organization) { create(:organization, name: 'Test', group: group, state: 'active') }
diff --git a/spec/services/database/consistency_fix_service_spec.rb b/spec/services/database/consistency_fix_service_spec.rb
index 9a0fac2191c..fcc776cbc2a 100644
--- a/spec/services/database/consistency_fix_service_spec.rb
+++ b/spec/services/database/consistency_fix_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Database::ConsistencyFixService do
+RSpec.describe Database::ConsistencyFixService, feature_category: :pods do
describe '#execute' do
context 'fixing namespaces inconsistencies' do
subject(:consistency_fix_service) do
diff --git a/spec/services/dependency_proxy/auth_token_service_spec.rb b/spec/services/dependency_proxy/auth_token_service_spec.rb
index c686f57c5cb..2612c5765a4 100644
--- a/spec/services/dependency_proxy/auth_token_service_spec.rb
+++ b/spec/services/dependency_proxy/auth_token_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DependencyProxy::AuthTokenService do
+RSpec.describe DependencyProxy::AuthTokenService, feature_category: :dependency_proxy do
include DependencyProxyHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/dependency_proxy/find_cached_manifest_service_spec.rb b/spec/services/dependency_proxy/find_cached_manifest_service_spec.rb
index 470c6eb9e03..13620b3dfc1 100644
--- a/spec/services/dependency_proxy/find_cached_manifest_service_spec.rb
+++ b/spec/services/dependency_proxy/find_cached_manifest_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DependencyProxy::FindCachedManifestService do
+RSpec.describe DependencyProxy::FindCachedManifestService, feature_category: :dependency_proxy do
include DependencyProxyHelpers
let_it_be(:image) { 'alpine' }
diff --git a/spec/services/dependency_proxy/group_settings/update_service_spec.rb b/spec/services/dependency_proxy/group_settings/update_service_spec.rb
index 4954d9ec267..38f837a828a 100644
--- a/spec/services/dependency_proxy/group_settings/update_service_spec.rb
+++ b/spec/services/dependency_proxy/group_settings/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::DependencyProxy::GroupSettings::UpdateService do
+RSpec.describe ::DependencyProxy::GroupSettings::UpdateService, feature_category: :dependency_proxy do
using RSpec::Parameterized::TableSyntax
let_it_be_with_reload(:group) { create(:group) }
diff --git a/spec/services/dependency_proxy/head_manifest_service_spec.rb b/spec/services/dependency_proxy/head_manifest_service_spec.rb
index 949a8eb3bee..a9646a185bc 100644
--- a/spec/services/dependency_proxy/head_manifest_service_spec.rb
+++ b/spec/services/dependency_proxy/head_manifest_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DependencyProxy::HeadManifestService do
+RSpec.describe DependencyProxy::HeadManifestService, feature_category: :dependency_proxy do
include DependencyProxyHelpers
let(:image) { 'alpine' }
diff --git a/spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb b/spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb
index 3a6ba2cca71..f58434222a5 100644
--- a/spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb
+++ b/spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::DependencyProxy::ImageTtlGroupPolicies::UpdateService do
+RSpec.describe ::DependencyProxy::ImageTtlGroupPolicies::UpdateService, feature_category: :dependency_proxy do
using RSpec::Parameterized::TableSyntax
let_it_be_with_reload(:group) { create(:group) }
diff --git a/spec/services/dependency_proxy/request_token_service_spec.rb b/spec/services/dependency_proxy/request_token_service_spec.rb
index 8b3ba783b8d..0cc3695f0b0 100644
--- a/spec/services/dependency_proxy/request_token_service_spec.rb
+++ b/spec/services/dependency_proxy/request_token_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DependencyProxy::RequestTokenService do
+RSpec.describe DependencyProxy::RequestTokenService, feature_category: :dependency_proxy do
include DependencyProxyHelpers
let(:image) { 'alpine:3.9' }
diff --git a/spec/services/deploy_keys/create_service_spec.rb b/spec/services/deploy_keys/create_service_spec.rb
index 2e3318236f5..8bff80b2d11 100644
--- a/spec/services/deploy_keys/create_service_spec.rb
+++ b/spec/services/deploy_keys/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DeployKeys::CreateService do
+RSpec.describe DeployKeys::CreateService, feature_category: :continuous_delivery do
let(:user) { create(:user) }
let(:params) { attributes_for(:deploy_key) }
diff --git a/spec/services/deployments/archive_in_project_service_spec.rb b/spec/services/deployments/archive_in_project_service_spec.rb
index a316c210d64..ed03ce06255 100644
--- a/spec/services/deployments/archive_in_project_service_spec.rb
+++ b/spec/services/deployments/archive_in_project_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::ArchiveInProjectService do
+RSpec.describe Deployments::ArchiveInProjectService, feature_category: :continuous_delivery do
let_it_be(:project) { create(:project, :repository) }
let(:service) { described_class.new(project, nil) }
diff --git a/spec/services/deployments/create_for_build_service_spec.rb b/spec/services/deployments/create_for_build_service_spec.rb
index 3748df87d99..c07fc07cfbf 100644
--- a/spec/services/deployments/create_for_build_service_spec.rb
+++ b/spec/services/deployments/create_for_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::CreateForBuildService do
+RSpec.describe Deployments::CreateForBuildService, feature_category: :continuous_delivery do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/deployments/create_service_spec.rb b/spec/services/deployments/create_service_spec.rb
index 0f2a6ce32e1..2a70d450575 100644
--- a/spec/services/deployments/create_service_spec.rb
+++ b/spec/services/deployments/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::CreateService do
+RSpec.describe Deployments::CreateService, feature_category: :continuous_delivery do
let(:user) { create(:user) }
describe '#execute' do
diff --git a/spec/services/deployments/link_merge_requests_service_spec.rb b/spec/services/deployments/link_merge_requests_service_spec.rb
index a653cd2b48b..a468af90ffb 100644
--- a/spec/services/deployments/link_merge_requests_service_spec.rb
+++ b/spec/services/deployments/link_merge_requests_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::LinkMergeRequestsService do
+RSpec.describe Deployments::LinkMergeRequestsService, feature_category: :continuous_delivery do
let(:project) { create(:project, :repository) }
# * ddd0f15 Merge branch 'po-fix-test-env-path' into 'master'
diff --git a/spec/services/deployments/older_deployments_drop_service_spec.rb b/spec/services/deployments/older_deployments_drop_service_spec.rb
index d9a512a5dd2..7e3074a1688 100644
--- a/spec/services/deployments/older_deployments_drop_service_spec.rb
+++ b/spec/services/deployments/older_deployments_drop_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::OlderDeploymentsDropService do
+RSpec.describe Deployments::OlderDeploymentsDropService, feature_category: :continuous_delivery do
let(:environment) { create(:environment) }
let(:deployment) { create(:deployment, environment: environment) }
let(:service) { described_class.new(deployment) }
diff --git a/spec/services/deployments/update_environment_service_spec.rb b/spec/services/deployments/update_environment_service_spec.rb
index 31a3abda8c7..33c9c9ed592 100644
--- a/spec/services/deployments/update_environment_service_spec.rb
+++ b/spec/services/deployments/update_environment_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::UpdateEnvironmentService do
+RSpec.describe Deployments::UpdateEnvironmentService, feature_category: :continuous_delivery do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:options) { { name: environment_name } }
diff --git a/spec/services/deployments/update_service_spec.rb b/spec/services/deployments/update_service_spec.rb
index d3840189ba4..0814091765c 100644
--- a/spec/services/deployments/update_service_spec.rb
+++ b/spec/services/deployments/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::UpdateService do
+RSpec.describe Deployments::UpdateService, feature_category: :continuous_delivery do
let(:deploy) { create(:deployment) }
describe '#execute' do
diff --git a/spec/services/design_management/copy_design_collection/copy_service_spec.rb b/spec/services/design_management/copy_design_collection/copy_service_spec.rb
index 89a78c9bf5f..048327792e0 100644
--- a/spec/services/design_management/copy_design_collection/copy_service_spec.rb
+++ b/spec/services/design_management/copy_design_collection/copy_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DesignManagement::CopyDesignCollection::CopyService, :clean_gitlab_redis_shared_state do
+RSpec.describe DesignManagement::CopyDesignCollection::CopyService, :clean_gitlab_redis_shared_state, feature_category: :portfolio_management do
include DesignManagementTestHelpers
let_it_be(:user) { create(:user) }
@@ -117,6 +117,7 @@ RSpec.describe DesignManagement::CopyDesignCollection::CopyService, :clean_gitla
new_designs.zip(old_designs).each do |new_design, old_design|
expect(new_design).to have_attributes(
filename: old_design.filename,
+ description: old_design.description,
relative_position: old_design.relative_position,
issue: target_issue,
project: target_issue.project
diff --git a/spec/services/design_management/copy_design_collection/queue_service_spec.rb b/spec/services/design_management/copy_design_collection/queue_service_spec.rb
index 05a7b092ccf..e6809e65d8a 100644
--- a/spec/services/design_management/copy_design_collection/queue_service_spec.rb
+++ b/spec/services/design_management/copy_design_collection/queue_service_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DesignManagement::CopyDesignCollection::QueueService, :clean_gitlab_redis_shared_state do
+RSpec.describe DesignManagement::CopyDesignCollection::QueueService, :clean_gitlab_redis_shared_state,
+ feature_category: :design_management do
include DesignManagementTestHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/design_management/delete_designs_service_spec.rb b/spec/services/design_management/delete_designs_service_spec.rb
index 48e53a92758..09ff2c5b897 100644
--- a/spec/services/design_management/delete_designs_service_spec.rb
+++ b/spec/services/design_management/delete_designs_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DesignManagement::DeleteDesignsService do
+RSpec.describe DesignManagement::DeleteDesignsService, feature_category: :design_management do
include DesignManagementTestHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/services/design_management/design_user_notes_count_service_spec.rb b/spec/services/design_management/design_user_notes_count_service_spec.rb
index 37806d3461c..1dbd055038c 100644
--- a/spec/services/design_management/design_user_notes_count_service_spec.rb
+++ b/spec/services/design_management/design_user_notes_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DesignManagement::DesignUserNotesCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe DesignManagement::DesignUserNotesCountService, :use_clean_rails_memory_store_caching, feature_category: :design_management do
let_it_be(:design) { create(:design, :with_file) }
subject { described_class.new(design) }
diff --git a/spec/services/design_management/generate_image_versions_service_spec.rb b/spec/services/design_management/generate_image_versions_service_spec.rb
index 5409ec12016..08442f221fa 100644
--- a/spec/services/design_management/generate_image_versions_service_spec.rb
+++ b/spec/services/design_management/generate_image_versions_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DesignManagement::GenerateImageVersionsService do
+RSpec.describe DesignManagement::GenerateImageVersionsService, feature_category: :design_management do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:version) { create(:design, :with_lfs_file, issue: issue).versions.first }
diff --git a/spec/services/design_management/move_designs_service_spec.rb b/spec/services/design_management/move_designs_service_spec.rb
index 519378a8dd4..8276d8d186a 100644
--- a/spec/services/design_management/move_designs_service_spec.rb
+++ b/spec/services/design_management/move_designs_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DesignManagement::MoveDesignsService do
+RSpec.describe DesignManagement::MoveDesignsService, feature_category: :design_management do
include DesignManagementTestHelpers
let_it_be(:issue) { create(:issue) }
diff --git a/spec/services/discussions/capture_diff_note_position_service_spec.rb b/spec/services/discussions/capture_diff_note_position_service_spec.rb
index 11614ccfd55..313e828bf0a 100644
--- a/spec/services/discussions/capture_diff_note_position_service_spec.rb
+++ b/spec/services/discussions/capture_diff_note_position_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Discussions::CaptureDiffNotePositionService do
+RSpec.describe Discussions::CaptureDiffNotePositionService, feature_category: :code_review_workflow do
subject { described_class.new(note.noteable, paths) }
context 'image note on diff' do
diff --git a/spec/services/discussions/capture_diff_note_positions_service_spec.rb b/spec/services/discussions/capture_diff_note_positions_service_spec.rb
index 8ba54495d4c..96922535eb2 100644
--- a/spec/services/discussions/capture_diff_note_positions_service_spec.rb
+++ b/spec/services/discussions/capture_diff_note_positions_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Discussions::CaptureDiffNotePositionsService do
+RSpec.describe Discussions::CaptureDiffNotePositionsService, feature_category: :code_review_workflow do
context 'when merge request has a discussion' do
let(:source_branch) { 'compare-with-merge-head-source' }
let(:target_branch) { 'compare-with-merge-head-target' }
diff --git a/spec/services/discussions/update_diff_position_service_spec.rb b/spec/services/discussions/update_diff_position_service_spec.rb
index e7a3505bbd4..274430fdccb 100644
--- a/spec/services/discussions/update_diff_position_service_spec.rb
+++ b/spec/services/discussions/update_diff_position_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Discussions::UpdateDiffPositionService do
+RSpec.describe Discussions::UpdateDiffPositionService, feature_category: :code_review_workflow do
let(:project) { create(:project, :repository) }
let(:current_user) { project.first_owner }
let(:create_commit) { project.commit("913c66a37b4a45b9769037c55c2d238bd0942d2e") }
diff --git a/spec/services/draft_notes/create_service_spec.rb b/spec/services/draft_notes/create_service_spec.rb
index 528c8717525..93731a80dcc 100644
--- a/spec/services/draft_notes/create_service_spec.rb
+++ b/spec/services/draft_notes/create_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DraftNotes::CreateService do
+RSpec.describe DraftNotes::CreateService, feature_category: :code_review_workflow do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.target_project }
let(:user) { merge_request.author }
diff --git a/spec/services/draft_notes/destroy_service_spec.rb b/spec/services/draft_notes/destroy_service_spec.rb
index 1f246a56eb3..f4cc9daa9e9 100644
--- a/spec/services/draft_notes/destroy_service_spec.rb
+++ b/spec/services/draft_notes/destroy_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DraftNotes::DestroyService do
+RSpec.describe DraftNotes::DestroyService, feature_category: :code_review_workflow do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.target_project }
let(:user) { merge_request.author }
diff --git a/spec/services/draft_notes/publish_service_spec.rb b/spec/services/draft_notes/publish_service_spec.rb
index 44fe9063ac9..a4b1d8742d0 100644
--- a/spec/services/draft_notes/publish_service_spec.rb
+++ b/spec/services/draft_notes/publish_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DraftNotes::PublishService do
+RSpec.describe DraftNotes::PublishService, feature_category: :code_review_workflow do
include RepoHelpers
let(:merge_request) { create(:merge_request) }
diff --git a/spec/services/emails/confirm_service_spec.rb b/spec/services/emails/confirm_service_spec.rb
index e8d3c0d673b..43fca75a5ea 100644
--- a/spec/services/emails/confirm_service_spec.rb
+++ b/spec/services/emails/confirm_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Emails::ConfirmService do
+RSpec.describe Emails::ConfirmService, feature_category: :user_management do
let_it_be(:user) { create(:user) }
subject(:service) { described_class.new(user) }
diff --git a/spec/services/emails/create_service_spec.rb b/spec/services/emails/create_service_spec.rb
index b13197f21b8..3ef67036483 100644
--- a/spec/services/emails/create_service_spec.rb
+++ b/spec/services/emails/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Emails::CreateService do
+RSpec.describe Emails::CreateService, feature_category: :user_management do
let_it_be(:user) { create(:user) }
let(:opts) { { email: 'new@email.com', user: user } }
diff --git a/spec/services/emails/destroy_service_spec.rb b/spec/services/emails/destroy_service_spec.rb
index 7dcf367016e..9d5e2b45647 100644
--- a/spec/services/emails/destroy_service_spec.rb
+++ b/spec/services/emails/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Emails::DestroyService do
+RSpec.describe Emails::DestroyService, feature_category: :user_management do
let!(:user) { create(:user) }
let!(:email) { create(:email, user: user) }
diff --git a/spec/services/environments/auto_stop_service_spec.rb b/spec/services/environments/auto_stop_service_spec.rb
index d688690c376..57fb860a557 100644
--- a/spec/services/environments/auto_stop_service_spec.rb
+++ b/spec/services/environments/auto_stop_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Environments::AutoStopService, :clean_gitlab_redis_shared_state, :sidekiq_inline do
+RSpec.describe Environments::AutoStopService, :clean_gitlab_redis_shared_state, :sidekiq_inline,
+ feature_category: :continuous_delivery do
include CreateEnvironmentsHelpers
include ExclusiveLeaseHelpers
diff --git a/spec/services/environments/canary_ingress/update_service_spec.rb b/spec/services/environments/canary_ingress/update_service_spec.rb
index 531f7d68a9f..f7d446c13f9 100644
--- a/spec/services/environments/canary_ingress/update_service_spec.rb
+++ b/spec/services/environments/canary_ingress/update_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Environments::CanaryIngress::UpdateService, :clean_gitlab_redis_cache do
+RSpec.describe Environments::CanaryIngress::UpdateService, :clean_gitlab_redis_cache,
+ feature_category: :continuous_delivery do
include KubernetesHelpers
let_it_be(:project, refind: true) { create(:project) }
diff --git a/spec/services/environments/create_for_build_service_spec.rb b/spec/services/environments/create_for_build_service_spec.rb
index c7aadb20c01..223401a243d 100644
--- a/spec/services/environments/create_for_build_service_spec.rb
+++ b/spec/services/environments/create_for_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Environments::CreateForBuildService do
+RSpec.describe Environments::CreateForBuildService, feature_category: :continuous_delivery do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/environments/reset_auto_stop_service_spec.rb b/spec/services/environments/reset_auto_stop_service_spec.rb
index 4a0b091c12d..a3b8b2e0aa1 100644
--- a/spec/services/environments/reset_auto_stop_service_spec.rb
+++ b/spec/services/environments/reset_auto_stop_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Environments::ResetAutoStopService do
+RSpec.describe Environments::ResetAutoStopService, feature_category: :continuous_delivery do
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } }
let_it_be(:reporter) { create(:user).tap { |user| project.add_reporter(user) } }
diff --git a/spec/services/environments/schedule_to_delete_review_apps_service_spec.rb b/spec/services/environments/schedule_to_delete_review_apps_service_spec.rb
index 401d6203b2c..3047f415815 100644
--- a/spec/services/environments/schedule_to_delete_review_apps_service_spec.rb
+++ b/spec/services/environments/schedule_to_delete_review_apps_service_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Environments::ScheduleToDeleteReviewAppsService do
+RSpec.describe Environments::ScheduleToDeleteReviewAppsService, feature_category: :continuous_delivery do
include ExclusiveLeaseHelpers
let_it_be(:maintainer) { create(:user) }
diff --git a/spec/services/environments/stop_service_spec.rb b/spec/services/environments/stop_service_spec.rb
index 5f983a2151a..6e3b36b5636 100644
--- a/spec/services/environments/stop_service_spec.rb
+++ b/spec/services/environments/stop_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Environments::StopService do
+RSpec.describe Environments::StopService, feature_category: :continuous_delivery do
include CreateEnvironmentsHelpers
let(:project) { create(:project, :private, :repository) }
diff --git a/spec/services/error_tracking/base_service_spec.rb b/spec/services/error_tracking/base_service_spec.rb
index de3523cb847..ed9efd9f95a 100644
--- a/spec/services/error_tracking/base_service_spec.rb
+++ b/spec/services/error_tracking/base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ErrorTracking::BaseService do
+RSpec.describe ErrorTracking::BaseService, feature_category: :error_tracking do
describe '#compose_response' do
let(:project) { build_stubbed(:project) }
let(:user) { build_stubbed(:user, id: non_existing_record_id) }
diff --git a/spec/services/error_tracking/collect_error_service_spec.rb b/spec/services/error_tracking/collect_error_service_spec.rb
index 159c070c683..3ff753e8c65 100644
--- a/spec/services/error_tracking/collect_error_service_spec.rb
+++ b/spec/services/error_tracking/collect_error_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ErrorTracking::CollectErrorService do
+RSpec.describe ErrorTracking::CollectErrorService, feature_category: :error_tracking do
let_it_be(:project) { create(:project) }
let(:parsed_event_file) { 'error_tracking/parsed_event.json' }
diff --git a/spec/services/error_tracking/issue_details_service_spec.rb b/spec/services/error_tracking/issue_details_service_spec.rb
index 29f8154a27c..7ac41ffead6 100644
--- a/spec/services/error_tracking/issue_details_service_spec.rb
+++ b/spec/services/error_tracking/issue_details_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ErrorTracking::IssueDetailsService do
+RSpec.describe ErrorTracking::IssueDetailsService, feature_category: :error_tracking do
include_context 'sentry error tracking context'
subject { described_class.new(project, user, params) }
diff --git a/spec/services/error_tracking/issue_latest_event_service_spec.rb b/spec/services/error_tracking/issue_latest_event_service_spec.rb
index aa2430ddffb..bfde14c7ef1 100644
--- a/spec/services/error_tracking/issue_latest_event_service_spec.rb
+++ b/spec/services/error_tracking/issue_latest_event_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ErrorTracking::IssueLatestEventService do
+RSpec.describe ErrorTracking::IssueLatestEventService, feature_category: :error_tracking do
include_context 'sentry error tracking context'
let(:params) { {} }
diff --git a/spec/services/error_tracking/issue_update_service_spec.rb b/spec/services/error_tracking/issue_update_service_spec.rb
index a06c3588264..4dae6cc2fa0 100644
--- a/spec/services/error_tracking/issue_update_service_spec.rb
+++ b/spec/services/error_tracking/issue_update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ErrorTracking::IssueUpdateService do
+RSpec.describe ErrorTracking::IssueUpdateService, feature_category: :error_tracking do
include_context 'sentry error tracking context'
let(:arguments) { { issue_id: non_existing_record_id, status: 'resolved' } }
diff --git a/spec/services/error_tracking/list_issues_service_spec.rb b/spec/services/error_tracking/list_issues_service_spec.rb
index a7bd6c75df5..2c35c2b8acd 100644
--- a/spec/services/error_tracking/list_issues_service_spec.rb
+++ b/spec/services/error_tracking/list_issues_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ErrorTracking::ListIssuesService do
+RSpec.describe ErrorTracking::ListIssuesService, feature_category: :error_tracking do
include_context 'sentry error tracking context'
let(:params) { {} }
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index b969bd76053..d14f130233e 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state do
+RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state, feature_category: :service_ping do
include SnowplowHelpers
let(:service) { described_class.new }
@@ -12,10 +12,20 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
shared_examples 'it records the event in the event counter' do
specify do
- tracking_params = { event_action: event_action, date_from: Date.yesterday, date_to: Date.today }
+ tracking_params = { event_names: event_action, start_date: Date.yesterday, end_date: Date.today }
expect { subject }
- .to change { Gitlab::UsageDataCounters::TrackUniqueEvents.count_unique_events(**tracking_params) }
+ .to change { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(**tracking_params) }
+ .by(1)
+ end
+ end
+
+ shared_examples 'it records a git write event' do
+ specify do
+ tracking_params = { event_names: 'git_write_action', start_date: Date.yesterday, end_date: Date.today }
+
+ expect { subject }
+ .to change { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(**tracking_params) }
.by(1)
end
end
@@ -65,11 +75,10 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like "it records the event in the event counter" do
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION }
+ let(:event_action) { :merge_request_action }
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'created' }
let(:label) { described_class::MR_EVENT_LABEL }
@@ -95,11 +104,10 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like "it records the event in the event counter" do
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION }
+ let(:event_action) { :merge_request_action }
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'closed' }
let(:label) { described_class::MR_EVENT_LABEL }
@@ -125,11 +133,10 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like "it records the event in the event counter" do
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION }
+ let(:event_action) { :merge_request_action }
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.name }
let(:action) { 'merged' }
let(:label) { described_class::MR_EVENT_LABEL }
@@ -276,8 +283,10 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like "it records the event in the event counter" do
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::WIKI_ACTION }
+ let(:event_action) { :wiki_action }
end
+
+ it_behaves_like "it records a git write event"
end
(Event.actions.keys - Event::WIKI_ACTIONS).each do |bad_action|
@@ -312,9 +321,11 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
it_behaves_like 'service for creating a push event', PushEventPayloadService
it_behaves_like "it records the event in the event counter" do
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::PUSH_ACTION }
+ let(:event_action) { :project_action }
end
+ it_behaves_like "it records a git write event"
+
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
let(:category) { described_class.to_s }
let(:action) { :push }
@@ -338,9 +349,11 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
it_behaves_like 'service for creating a push event', BulkPushEventPayloadService
it_behaves_like "it records the event in the event counter" do
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::PUSH_ACTION }
+ let(:event_action) { :project_action }
end
+ it_behaves_like "it records a git write event"
+
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
let(:category) { described_class.to_s }
let(:action) { :push }
@@ -400,16 +413,17 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like "it records the event in the event counter" do
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION }
+ let(:event_action) { :design_action }
end
+ it_behaves_like "it records a git write event"
+
describe 'Snowplow tracking' do
let(:project) { design.project }
let(:namespace) { project.namespace }
let(:category) { described_class.name }
- let(:property) { Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s }
+ let(:property) { :design_action.to_s }
let(:label) { ::EventCreateService::DEGIGN_EVENT_LABEL }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
context 'for create event' do
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
@@ -448,9 +462,11 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
it_behaves_like "it records the event in the event counter" do
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION }
+ let(:event_action) { :design_action }
end
+ it_behaves_like "it records a git write event"
+
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
subject(:design_service) { service.destroy_designs([design], author) }
@@ -459,9 +475,8 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:category) { described_class.name }
let(:action) { 'destroy' }
let(:user) { author }
- let(:property) { Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION.to_s }
+ let(:property) { :design_action.to_s }
let(:label) { ::EventCreateService::DEGIGN_EVENT_LABEL }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
end
end
@@ -471,7 +486,7 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:note) { create(:note) }
let(:author) { create(:user) }
- let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION }
+ let(:event_action) { :merge_request_action }
it { expect(leave_note).to be_truthy }
@@ -485,7 +500,6 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
it_behaves_like "it records the event in the event counter"
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:note) { create(:diff_note_on_merge_request) }
let(:category) { described_class.name }
let(:action) { 'commented' }
@@ -502,10 +516,9 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
context 'when it is not a diff note' do
it 'does not change the unique action counter' do
- counter_class = Gitlab::UsageDataCounters::TrackUniqueEvents
- tracking_params = { event_action: event_action, date_from: Date.yesterday, date_to: Date.today }
+ tracking_params = { event_names: event_action, start_date: Date.yesterday, end_date: Date.today }
- expect { subject }.not_to change { counter_class.count_unique_events(**tracking_params) }
+ expect { subject }.not_to change { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(**tracking_params) }
end
end
end
diff --git a/spec/services/events/destroy_service_spec.rb b/spec/services/events/destroy_service_spec.rb
index 8b07852c040..e50fe247238 100644
--- a/spec/services/events/destroy_service_spec.rb
+++ b/spec/services/events/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Events::DestroyService do
+RSpec.describe Events::DestroyService, feature_category: :user_profile do
subject(:service) { described_class.new(project) }
let_it_be(:project, reload: true) { create(:project, :repository) }
diff --git a/spec/services/events/render_service_spec.rb b/spec/services/events/render_service_spec.rb
index 24a3b9abe14..2e8cd26781b 100644
--- a/spec/services/events/render_service_spec.rb
+++ b/spec/services/events/render_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Events::RenderService do
+RSpec.describe Events::RenderService, feature_category: :user_profile do
describe '#execute' do
let!(:note) { build(:note) }
let!(:event) { build(:event, target: note, project: note.project) }
diff --git a/spec/services/feature_flags/create_service_spec.rb b/spec/services/feature_flags/create_service_spec.rb
index 1a32faad948..18c48714ccd 100644
--- a/spec/services/feature_flags/create_service_spec.rb
+++ b/spec/services/feature_flags/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe FeatureFlags::CreateService do
+RSpec.describe FeatureFlags::CreateService, feature_category: :feature_flags do
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
@@ -46,6 +46,8 @@ RSpec.describe FeatureFlags::CreateService do
end
context 'when feature flag is saved correctly' do
+ let(:audit_event_details) { AuditEvent.last.details }
+ let(:audit_event_message) { audit_event_details[:custom_message] }
let(:params) do
{
name: 'feature_flag',
@@ -88,9 +90,9 @@ RSpec.describe FeatureFlags::CreateService do
it 'creates audit event', :with_license do
expect { subject }.to change { AuditEvent.count }.by(1)
- expect(AuditEvent.last.details[:custom_message]).to start_with('Created feature flag feature_flag with description "description".')
- expect(AuditEvent.last.details[:custom_message]).to include('Created strategy "default" with scopes "*".')
- expect(AuditEvent.last.details[:custom_message]).to include('Created strategy "default" with scopes "production".')
+ expect(audit_event_message).to start_with('Created feature flag feature_flag with description "description".')
+ expect(audit_event_message).to include('Created strategy "default" with scopes "*".')
+ expect(audit_event_message).to include('Created strategy "default" with scopes "production".')
end
context 'when user is reporter' do
diff --git a/spec/services/feature_flags/destroy_service_spec.rb b/spec/services/feature_flags/destroy_service_spec.rb
index b2793dc0560..1ec0ee6e68c 100644
--- a/spec/services/feature_flags/destroy_service_spec.rb
+++ b/spec/services/feature_flags/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe FeatureFlags::DestroyService do
+RSpec.describe FeatureFlags::DestroyService, feature_category: :feature_flags do
include FeatureFlagHelpers
let_it_be(:project) { create(:project) }
@@ -20,7 +20,8 @@ RSpec.describe FeatureFlags::DestroyService do
describe '#execute' do
subject { described_class.new(project, user, params).execute(feature_flag) }
- let(:audit_event_message) { AuditEvent.last.details[:custom_message] }
+ let(:audit_event_details) { AuditEvent.last.details }
+ let(:audit_event_message) { audit_event_details[:custom_message] }
let(:params) { {} }
it 'returns status success' do
diff --git a/spec/services/feature_flags/hook_service_spec.rb b/spec/services/feature_flags/hook_service_spec.rb
index f3edaca52a9..2a3ce9085b8 100644
--- a/spec/services/feature_flags/hook_service_spec.rb
+++ b/spec/services/feature_flags/hook_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe FeatureFlags::HookService do
+RSpec.describe FeatureFlags::HookService, feature_category: :feature_flags do
describe '#execute_hooks' do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:project) { create(:project, :repository, namespace: namespace) }
diff --git a/spec/services/feature_flags/update_service_spec.rb b/spec/services/feature_flags/update_service_spec.rb
index 1c5af71a50a..55c09f06f16 100644
--- a/spec/services/feature_flags/update_service_spec.rb
+++ b/spec/services/feature_flags/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe FeatureFlags::UpdateService, :with_license do
+RSpec.describe FeatureFlags::UpdateService, :with_license, feature_category: :feature_flags do
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
@@ -19,9 +19,8 @@ RSpec.describe FeatureFlags::UpdateService, :with_license do
subject { described_class.new(project, user, params).execute(feature_flag) }
let(:params) { { name: 'new_name' } }
- let(:audit_event_message) do
- AuditEvent.last.details[:custom_message]
- end
+ let(:audit_event_details) { AuditEvent.last.details }
+ let(:audit_event_message) { audit_event_details[:custom_message] }
it 'returns success status' do
expect(subject[:status]).to eq(:success)
diff --git a/spec/services/files/create_service_spec.rb b/spec/services/files/create_service_spec.rb
index 3b3dbd1fcfe..26f57f43120 100644
--- a/spec/services/files/create_service_spec.rb
+++ b/spec/services/files/create_service_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Files::CreateService do
+RSpec.describe Files::CreateService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user, :commit_email) }
diff --git a/spec/services/files/delete_service_spec.rb b/spec/services/files/delete_service_spec.rb
index 3823d027812..dd99e5f9742 100644
--- a/spec/services/files/delete_service_spec.rb
+++ b/spec/services/files/delete_service_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Files::DeleteService do
+RSpec.describe Files::DeleteService, feature_category: :source_code_management do
subject { described_class.new(project, user, commit_params) }
let(:project) { create(:project, :repository) }
@@ -52,8 +52,8 @@ RSpec.describe Files::DeleteService do
end
describe "#execute" do
- context "when the file's last commit sha does not match the supplied last_commit_sha" do
- let(:last_commit_sha) { "foo" }
+ context "when the file's last commit is earlier than the latest commit for this branch" do
+ 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 }
diff --git a/spec/services/files/multi_service_spec.rb b/spec/services/files/multi_service_spec.rb
index 6a5c7d2749d..7149fa77d6a 100644
--- a/spec/services/files/multi_service_spec.rb
+++ b/spec/services/files/multi_service_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Files::MultiService do
+RSpec.describe Files::MultiService, feature_category: :source_code_management do
subject { described_class.new(project, user, commit_params) }
let(:project) { create(:project, :repository) }
@@ -19,6 +19,10 @@ RSpec.describe Files::MultiService do
Gitlab::Git::Commit.last_for_path(project.repository, branch_name, original_file_path).sha
end
+ let(:branch_commit_id) do
+ Gitlab::Git::Commit.find(project.repository, branch_name).sha
+ end
+
let(:default_action) do
{
action: action,
@@ -78,6 +82,16 @@ RSpec.describe Files::MultiService do
end
end
+ context 'when file not changed, but later commit id is used' do
+ let(:actions) { [default_action.merge(last_commit_id: branch_commit_id)] }
+
+ it 'accepts the commit' do
+ results = subject.execute
+
+ expect(results[:status]).to eq(:success)
+ end
+ end
+
context 'when the file have not been modified' do
it 'accepts the commit' do
results = subject.execute
diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb
index 6d7459e0b29..6a9f9d6b86f 100644
--- a/spec/services/files/update_service_spec.rb
+++ b/spec/services/files/update_service_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Files::UpdateService do
+RSpec.describe Files::UpdateService, feature_category: :source_code_management do
subject { described_class.new(project, user, commit_params) }
let(:project) { create(:project, :repository) }
@@ -31,8 +31,8 @@ RSpec.describe Files::UpdateService do
end
describe "#execute" do
- context "when the file's last commit sha does not match the supplied last_commit_sha" do
- let(:last_commit_sha) { "foo" }
+ context "when the file's last commit sha is earlier than the latest change for that branch" do
+ 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 }
diff --git a/spec/services/git/base_hooks_service_spec.rb b/spec/services/git/base_hooks_service_spec.rb
index 5afd7b30ab0..9d49943ccfb 100644
--- a/spec/services/git/base_hooks_service_spec.rb
+++ b/spec/services/git/base_hooks_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Git::BaseHooksService do
+RSpec.describe Git::BaseHooksService, feature_category: :source_code_management do
include RepoHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/git/branch_hooks_service_spec.rb b/spec/services/git/branch_hooks_service_spec.rb
index 973ead28462..e991b5bd842 100644
--- a/spec/services/git/branch_hooks_service_spec.rb
+++ b/spec/services/git/branch_hooks_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Git::BranchHooksService, :clean_gitlab_redis_shared_state do
+RSpec.describe Git::BranchHooksService, :clean_gitlab_redis_shared_state, feature_category: :source_code_management do
include RepoHelpers
include ProjectForksHelper
diff --git a/spec/services/git/branch_push_service_spec.rb b/spec/services/git/branch_push_service_spec.rb
index a9f5b07fef4..aa534777f3e 100644
--- a/spec/services/git/branch_push_service_spec.rb
+++ b/spec/services/git/branch_push_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Git::BranchPushService, :use_clean_rails_redis_caching, services: true do
+RSpec.describe Git::BranchPushService, :use_clean_rails_redis_caching, services: true, feature_category: :source_code_management do
include RepoHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/git/process_ref_changes_service_spec.rb b/spec/services/git/process_ref_changes_service_spec.rb
index 8d2da4a899e..9ec13bc957b 100644
--- a/spec/services/git/process_ref_changes_service_spec.rb
+++ b/spec/services/git/process_ref_changes_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Git::ProcessRefChangesService do
+RSpec.describe Git::ProcessRefChangesService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
let(:params) { { changes: git_changes } }
diff --git a/spec/services/git/tag_hooks_service_spec.rb b/spec/services/git/tag_hooks_service_spec.rb
index 01a0d2e8600..73f6eff36ba 100644
--- a/spec/services/git/tag_hooks_service_spec.rb
+++ b/spec/services/git/tag_hooks_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Git::TagHooksService, :service do
+RSpec.describe Git::TagHooksService, :service, feature_category: :source_code_management do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/git/tag_push_service_spec.rb b/spec/services/git/tag_push_service_spec.rb
index 597254d46fa..0d40c331d11 100644
--- a/spec/services/git/tag_push_service_spec.rb
+++ b/spec/services/git/tag_push_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Git::TagPushService do
+RSpec.describe Git::TagPushService, feature_category: :source_code_management do
include RepoHelpers
let(:user) { create(:user) }
diff --git a/spec/services/git/wiki_push_service/change_spec.rb b/spec/services/git/wiki_push_service/change_spec.rb
index 3616bf62b20..ad3c4ae68c0 100644
--- a/spec/services/git/wiki_push_service/change_spec.rb
+++ b/spec/services/git/wiki_push_service/change_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Git::WikiPushService::Change do
+RSpec.describe Git::WikiPushService::Change, feature_category: :source_code_management do
subject { described_class.new(project_wiki, change, raw_change) }
let(:project_wiki) { double('ProjectWiki') }
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 cd0dd75e576..4f2e0bea623 100644
--- a/spec/services/google_cloud/create_cloudsql_instance_service_spec.rb
+++ b/spec/services/google_cloud/create_cloudsql_instance_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::CreateCloudsqlInstanceService do
+RSpec.describe GoogleCloud::CreateCloudsqlInstanceService, feature_category: :deployment_management do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:gcp_project_id) { 'gcp_project_120' }
diff --git a/spec/services/google_cloud/create_service_accounts_service_spec.rb b/spec/services/google_cloud/create_service_accounts_service_spec.rb
index 3f500e7c235..3b57f2a9e5f 100644
--- a/spec/services/google_cloud/create_service_accounts_service_spec.rb
+++ b/spec/services/google_cloud/create_service_accounts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::CreateServiceAccountsService do
+RSpec.describe GoogleCloud::CreateServiceAccountsService, feature_category: :deployment_management do
describe '#execute' do
before do
mock_google_oauth2_creds = Struct.new(:app_id, :app_secret)
diff --git a/spec/services/google_cloud/enable_cloud_run_service_spec.rb b/spec/services/google_cloud/enable_cloud_run_service_spec.rb
index 6d2b1f5cfd5..3de9e7fcd5c 100644
--- a/spec/services/google_cloud/enable_cloud_run_service_spec.rb
+++ b/spec/services/google_cloud/enable_cloud_run_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::EnableCloudRunService do
+RSpec.describe GoogleCloud::EnableCloudRunService, feature_category: :deployment_management do
describe 'when a project does not have any gcp projects' do
let_it_be(:project) { create(:project) }
diff --git a/spec/services/google_cloud/enable_cloudsql_service_spec.rb b/spec/services/google_cloud/enable_cloudsql_service_spec.rb
index aa6d2402d7c..b14b827e8b8 100644
--- a/spec/services/google_cloud/enable_cloudsql_service_spec.rb
+++ b/spec/services/google_cloud/enable_cloudsql_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::EnableCloudsqlService do
+RSpec.describe GoogleCloud::EnableCloudsqlService, feature_category: :deployment_management do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:params) do
diff --git a/spec/services/google_cloud/gcp_region_add_or_replace_service_spec.rb b/spec/services/google_cloud/gcp_region_add_or_replace_service_spec.rb
index b2cd5632be0..a748fed7134 100644
--- a/spec/services/google_cloud/gcp_region_add_or_replace_service_spec.rb
+++ b/spec/services/google_cloud/gcp_region_add_or_replace_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::GcpRegionAddOrReplaceService do
+RSpec.describe GoogleCloud::GcpRegionAddOrReplaceService, feature_category: :deployment_management do
it 'adds and replaces GCP region vars' do
project = create(:project, :public)
service = described_class.new(project)
diff --git a/spec/services/google_cloud/generate_pipeline_service_spec.rb b/spec/services/google_cloud/generate_pipeline_service_spec.rb
index a78d8ff6661..c18514884ca 100644
--- a/spec/services/google_cloud/generate_pipeline_service_spec.rb
+++ b/spec/services/google_cloud/generate_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::GeneratePipelineService do
+RSpec.describe GoogleCloud::GeneratePipelineService, feature_category: :deployment_management do
describe 'for cloud-run' do
describe 'when there is no existing pipeline' do
let_it_be(:project) { create(:project, :repository) }
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 4587a5077c0..ed41d0fd487 100644
--- a/spec/services/google_cloud/get_cloudsql_instances_service_spec.rb
+++ b/spec/services/google_cloud/get_cloudsql_instances_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::GetCloudsqlInstancesService do
+RSpec.describe GoogleCloud::GetCloudsqlInstancesService, feature_category: :deployment_management do
let(:service) { described_class.new(project) }
let(:project) { create(:project) }
diff --git a/spec/services/google_cloud/service_accounts_service_spec.rb b/spec/services/google_cloud/service_accounts_service_spec.rb
index 10e387126a3..c900bf7d300 100644
--- a/spec/services/google_cloud/service_accounts_service_spec.rb
+++ b/spec/services/google_cloud/service_accounts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::ServiceAccountsService do
+RSpec.describe GoogleCloud::ServiceAccountsService, feature_category: :deployment_management do
let(:service) { described_class.new(project) }
describe 'find_for_project' do
diff --git a/spec/services/google_cloud/setup_cloudsql_instance_service_spec.rb b/spec/services/google_cloud/setup_cloudsql_instance_service_spec.rb
index 0a0f05ab4be..5095277f61a 100644
--- a/spec/services/google_cloud/setup_cloudsql_instance_service_spec.rb
+++ b/spec/services/google_cloud/setup_cloudsql_instance_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GoogleCloud::SetupCloudsqlInstanceService do
+RSpec.describe GoogleCloud::SetupCloudsqlInstanceService, feature_category: :deployment_management do
let(:random_user) { create(:user) }
let(:project) { create(:project) }
let(:list_databases_empty) { Google::Apis::SqladminV1beta4::ListDatabasesResponse.new(items: []) }
diff --git a/spec/services/gpg_keys/create_service_spec.rb b/spec/services/gpg_keys/create_service_spec.rb
index 9ac56355b4b..d603ce951ec 100644
--- a/spec/services/gpg_keys/create_service_spec.rb
+++ b/spec/services/gpg_keys/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GpgKeys::CreateService do
+RSpec.describe GpgKeys::CreateService, feature_category: :source_code_management do
let(:user) { create(:user) }
let(:params) { attributes_for(:gpg_key) }
diff --git a/spec/services/grafana/proxy_service_spec.rb b/spec/services/grafana/proxy_service_spec.rb
index 99120de3593..7029bab379a 100644
--- a/spec/services/grafana/proxy_service_spec.rb
+++ b/spec/services/grafana/proxy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Grafana::ProxyService do
+RSpec.describe Grafana::ProxyService, feature_category: :metrics do
include ReactiveCachingHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/services/gravatar_service_spec.rb b/spec/services/gravatar_service_spec.rb
index a6418b02f78..6ccb362cc5c 100644
--- a/spec/services/gravatar_service_spec.rb
+++ b/spec/services/gravatar_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GravatarService do
+RSpec.describe GravatarService, feature_category: :user_profile do
describe '#execute' do
let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' }
diff --git a/spec/services/groups/auto_devops_service_spec.rb b/spec/services/groups/auto_devops_service_spec.rb
index 486a99dd8df..0724e072dab 100644
--- a/spec/services/groups/auto_devops_service_spec.rb
+++ b/spec/services/groups/auto_devops_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Groups::AutoDevopsService, '#execute' do
+RSpec.describe Groups::AutoDevopsService, '#execute', feature_category: :auto_devops do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/groups/autocomplete_service_spec.rb b/spec/services/groups/autocomplete_service_spec.rb
index 00d0ad3b347..9f55322e72d 100644
--- a/spec/services/groups/autocomplete_service_spec.rb
+++ b/spec/services/groups/autocomplete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::AutocompleteService do
+RSpec.describe Groups::AutocompleteService, feature_category: :subgroups do
let_it_be(:group, refind: true) { create(:group, :nested, :private, avatar: fixture_file_upload('spec/fixtures/dk.png')) }
let_it_be(:sub_group) { create(:group, :private, parent: group) }
diff --git a/spec/services/groups/deploy_tokens/create_service_spec.rb b/spec/services/groups/deploy_tokens/create_service_spec.rb
index 0c28075f998..e408c2787d8 100644
--- a/spec/services/groups/deploy_tokens/create_service_spec.rb
+++ b/spec/services/groups/deploy_tokens/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::DeployTokens::CreateService do
+RSpec.describe Groups::DeployTokens::CreateService, feature_category: :deployment_management do
it_behaves_like 'a deploy token creation service' do
let(:entity) { create(:group) }
let(:deploy_token_class) { GroupDeployToken }
diff --git a/spec/services/groups/deploy_tokens/destroy_service_spec.rb b/spec/services/groups/deploy_tokens/destroy_service_spec.rb
index 28e60b12993..c4694758b2f 100644
--- a/spec/services/groups/deploy_tokens/destroy_service_spec.rb
+++ b/spec/services/groups/deploy_tokens/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::DeployTokens::DestroyService do
+RSpec.describe Groups::DeployTokens::DestroyService, feature_category: :deployment_management do
it_behaves_like 'a deploy token deletion service' do
let_it_be(:entity) { create(:group) }
let_it_be(:deploy_token_class) { GroupDeployToken }
diff --git a/spec/services/groups/deploy_tokens/revoke_service_spec.rb b/spec/services/groups/deploy_tokens/revoke_service_spec.rb
index fcf11bbb8e6..c302dd14e3b 100644
--- a/spec/services/groups/deploy_tokens/revoke_service_spec.rb
+++ b/spec/services/groups/deploy_tokens/revoke_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::DeployTokens::RevokeService do
+RSpec.describe Groups::DeployTokens::RevokeService, feature_category: :deployment_management do
let_it_be(:entity) { create(:group) }
let_it_be(:deploy_token) { create(:deploy_token, :group, groups: [entity]) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/groups/group_links/create_service_spec.rb b/spec/services/groups/group_links/create_service_spec.rb
index bfbaedbd06f..ced87421858 100644
--- a/spec/services/groups/group_links/create_service_spec.rb
+++ b/spec/services/groups/group_links/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::GroupLinks::CreateService, '#execute' do
+RSpec.describe Groups::GroupLinks::CreateService, '#execute', feature_category: :subgroups do
let_it_be(:shared_with_group_parent) { create(:group, :private) }
let_it_be(:shared_with_group) { create(:group, :private, parent: shared_with_group_parent) }
let_it_be(:shared_with_group_child) { create(:group, :private, parent: shared_with_group) }
diff --git a/spec/services/groups/group_links/destroy_service_spec.rb b/spec/services/groups/group_links/destroy_service_spec.rb
index a570c28cf8b..5821ec44192 100644
--- a/spec/services/groups/group_links/destroy_service_spec.rb
+++ b/spec/services/groups/group_links/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::GroupLinks::DestroyService, '#execute' do
+RSpec.describe Groups::GroupLinks::DestroyService, '#execute', feature_category: :subgroups do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:shared_group) { create(:group, :private) }
diff --git a/spec/services/groups/group_links/update_service_spec.rb b/spec/services/groups/group_links/update_service_spec.rb
index 31446c8e4bf..f17d2f50a02 100644
--- a/spec/services/groups/group_links/update_service_spec.rb
+++ b/spec/services/groups/group_links/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::GroupLinks::UpdateService, '#execute' do
+RSpec.describe Groups::GroupLinks::UpdateService, '#execute', feature_category: :subgroups do
let(:user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
@@ -18,7 +18,7 @@ RSpec.describe Groups::GroupLinks::UpdateService, '#execute' do
expires_at: expiry_date }
end
- subject { described_class.new(link).execute(group_link_params) }
+ subject { described_class.new(link, user).execute(group_link_params) }
before do
group.add_developer(group_member_user)
diff --git a/spec/services/groups/import_export/export_service_spec.rb b/spec/services/groups/import_export/export_service_spec.rb
index ec42a728409..c44c2e3b911 100644
--- a/spec/services/groups/import_export/export_service_spec.rb
+++ b/spec/services/groups/import_export/export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::ImportExport::ExportService do
+RSpec.describe Groups::ImportExport::ExportService, feature_category: :importers do
describe '#async_execute' do
let(:user) { create(:user) }
let(:group) { create(:group) }
diff --git a/spec/services/groups/import_export/import_service_spec.rb b/spec/services/groups/import_export/import_service_spec.rb
index 972b12d7ee5..75db6e26cbf 100644
--- a/spec/services/groups/import_export/import_service_spec.rb
+++ b/spec/services/groups/import_export/import_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::ImportExport::ImportService do
+RSpec.describe Groups::ImportExport::ImportService, feature_category: :importers do
describe '#async_execute' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
diff --git a/spec/services/groups/merge_requests_count_service_spec.rb b/spec/services/groups/merge_requests_count_service_spec.rb
index 8bd350d6f0e..32c4c618eda 100644
--- a/spec/services/groups/merge_requests_count_service_spec.rb
+++ b/spec/services/groups/merge_requests_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::MergeRequestsCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Groups::MergeRequestsCountService, :use_clean_rails_memory_store_caching, feature_category: :subgroups do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :repository, namespace: group) }
diff --git a/spec/services/groups/nested_create_service_spec.rb b/spec/services/groups/nested_create_service_spec.rb
index a43c1d8d9c3..476bc2aa23c 100644
--- a/spec/services/groups/nested_create_service_spec.rb
+++ b/spec/services/groups/nested_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::NestedCreateService do
+RSpec.describe Groups::NestedCreateService, feature_category: :subgroups do
let(:user) { create(:user) }
subject(:service) { described_class.new(user, params) }
diff --git a/spec/services/groups/open_issues_count_service_spec.rb b/spec/services/groups/open_issues_count_service_spec.rb
index 923caa6c150..725b913bf15 100644
--- a/spec/services/groups/open_issues_count_service_spec.rb
+++ b/spec/services/groups/open_issues_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::OpenIssuesCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Groups::OpenIssuesCountService, :use_clean_rails_memory_store_caching, feature_category: :subgroups do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, namespace: group) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/groups/participants_service_spec.rb b/spec/services/groups/participants_service_spec.rb
index 750aead277f..37966a523c2 100644
--- a/spec/services/groups/participants_service_spec.rb
+++ b/spec/services/groups/participants_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::ParticipantsService do
+RSpec.describe Groups::ParticipantsService, feature_category: :subgroups do
describe '#group_members' do
let(:user) { create(:user) }
let(:parent_group) { create(:group) }
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index c758d3d5477..6baa8e5d6b6 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::UpdateService do
+RSpec.describe Groups::UpdateService, feature_category: :subgroups do
let!(:user) { create(:user) }
let!(:private_group) { create(:group, :private) }
let!(:internal_group) { create(:group, :internal) }
diff --git a/spec/services/groups/update_shared_runners_service_spec.rb b/spec/services/groups/update_shared_runners_service_spec.rb
index a29f73a71c2..48c81f109aa 100644
--- a/spec/services/groups/update_shared_runners_service_spec.rb
+++ b/spec/services/groups/update_shared_runners_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::UpdateSharedRunnersService do
+RSpec.describe Groups::UpdateSharedRunnersService, feature_category: :subgroups do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:params) { {} }
diff --git a/spec/services/groups/update_statistics_service_spec.rb b/spec/services/groups/update_statistics_service_spec.rb
index 84b18b670a7..13a88839de0 100644
--- a/spec/services/groups/update_statistics_service_spec.rb
+++ b/spec/services/groups/update_statistics_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::UpdateStatisticsService do
+RSpec.describe Groups::UpdateStatisticsService, feature_category: :subgroups do
let_it_be(:group, reload: true) { create(:group) }
let(:statistics) { %w(wiki_size) }
diff --git a/spec/services/ide/base_config_service_spec.rb b/spec/services/ide/base_config_service_spec.rb
index ee57f2c18ec..ac57a13d7fc 100644
--- a/spec/services/ide/base_config_service_spec.rb
+++ b/spec/services/ide/base_config_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ide::BaseConfigService do
+RSpec.describe Ide::BaseConfigService, feature_category: :web_ide do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/ide/schemas_config_service_spec.rb b/spec/services/ide/schemas_config_service_spec.rb
index f277b8e9954..b6f229edc78 100644
--- a/spec/services/ide/schemas_config_service_spec.rb
+++ b/spec/services/ide/schemas_config_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ide::SchemasConfigService do
+RSpec.describe Ide::SchemasConfigService, feature_category: :web_ide do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/ide/terminal_config_service_spec.rb b/spec/services/ide/terminal_config_service_spec.rb
index 73614f28b06..76c8d9f2e6f 100644
--- a/spec/services/ide/terminal_config_service_spec.rb
+++ b/spec/services/ide/terminal_config_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ide::TerminalConfigService do
+RSpec.describe Ide::TerminalConfigService, feature_category: :web_ide do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/import/bitbucket_server_service_spec.rb b/spec/services/import/bitbucket_server_service_spec.rb
index 555812ca9cf..aea6c45b3a8 100644
--- a/spec/services/import/bitbucket_server_service_spec.rb
+++ b/spec/services/import/bitbucket_server_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::BitbucketServerService do
+RSpec.describe Import::BitbucketServerService, feature_category: :importers do
let_it_be(:user) { create(:user) }
let(:base_uri) { "https://test:7990" }
diff --git a/spec/services/import/fogbugz_service_spec.rb b/spec/services/import/fogbugz_service_spec.rb
index 027d0240a7a..6953213add7 100644
--- a/spec/services/import/fogbugz_service_spec.rb
+++ b/spec/services/import/fogbugz_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::FogbugzService do
+RSpec.describe Import::FogbugzService, feature_category: :importers do
let_it_be(:user) { create(:user) }
let(:base_uri) { "https://test:7990" }
diff --git a/spec/services/import/github/cancel_project_import_service_spec.rb b/spec/services/import/github/cancel_project_import_service_spec.rb
index 77b8771ee65..d8ea303fa50 100644
--- a/spec/services/import/github/cancel_project_import_service_spec.rb
+++ b/spec/services/import/github/cancel_project_import_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::Github::CancelProjectImportService do
+RSpec.describe Import::Github::CancelProjectImportService, feature_category: :importers do
subject(:import_cancel) { described_class.new(project, project.owner) }
let_it_be(:user) { create(:user) }
@@ -14,6 +14,18 @@ RSpec.describe Import::Github::CancelProjectImportService do
it 'update import state to be canceled' do
expect(import_cancel.execute).to eq({ status: :success, project: project })
end
+
+ it 'tracks canceled imports' do
+ metrics_double = instance_double('Gitlab::Import::Metrics')
+
+ expect(Gitlab::Import::Metrics)
+ .to receive(:new)
+ .with(:github_importer, project)
+ .and_return(metrics_double)
+ expect(metrics_double).to receive(:track_canceled_import)
+
+ import_cancel.execute
+ end
end
context 'when import is finished' do
diff --git a/spec/services/import/github/notes/create_service_spec.rb b/spec/services/import/github/notes/create_service_spec.rb
index 57699def848..37cb903b66e 100644
--- a/spec/services/import/github/notes/create_service_spec.rb
+++ b/spec/services/import/github/notes/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::Github::Notes::CreateService do
+RSpec.describe Import::Github::Notes::CreateService, feature_category: :importers do
it 'does not support quick actions' do
project = create(:project, :repository)
user = create(:user)
diff --git a/spec/services/import/github_service_spec.rb b/spec/services/import/github_service_spec.rb
index 293e247c140..5d762568a62 100644
--- a/spec/services/import/github_service_spec.rb
+++ b/spec/services/import/github_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::GithubService do
+RSpec.describe Import::GithubService, feature_category: :importers do
let_it_be(:user) { create(:user) }
let_it_be(:token) { 'complex-token' }
let_it_be(:access_params) { { github_access_token: 'github-complex-token' } }
diff --git a/spec/services/import/gitlab_projects/create_project_service_spec.rb b/spec/services/import/gitlab_projects/create_project_service_spec.rb
index 59c384bad3c..35378bcee92 100644
--- a/spec/services/import/gitlab_projects/create_project_service_spec.rb
+++ b/spec/services/import/gitlab_projects/create_project_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Import::GitlabProjects::CreateProjectService, :aggregate_failures do
+RSpec.describe ::Import::GitlabProjects::CreateProjectService, :aggregate_failures, feature_category: :importers do
let(:fake_file_acquisition_strategy) do
Class.new do
attr_reader :errors
@@ -127,7 +127,7 @@ RSpec.describe ::Import::GitlabProjects::CreateProjectService, :aggregate_failur
expect(response.payload).to eq(other_errors: [])
end
- context 'when the project contains multilple errors' do
+ context 'when the project contains multiple errors' do
it 'fails to create a project' do
params.merge!(name: '_ an invalid name _', path: '_ an invalid path _')
@@ -137,10 +137,13 @@ RSpec.describe ::Import::GitlabProjects::CreateProjectService, :aggregate_failur
expect(response).to be_error
expect(response.http_status).to eq(:bad_request)
- expect(response.message)
- .to eq(%{Project namespace path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'})
+ expect(response.message).to eq(
+ 'Project namespace path must not start or end with a special character and must not contain consecutive ' \
+ 'special characters.'
+ )
expect(response.payload).to eq(
other_errors: [
+ %{Project namespace path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'},
%{Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'},
%{Path must not start or end with a special character and must not contain consecutive special characters.}
])
diff --git a/spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb b/spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb
index 3c788138157..3a94ed02dd5 100644
--- a/spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb
+++ b/spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Import::GitlabProjects::FileAcquisitionStrategies::FileUpload, :aggregate_failures do
+RSpec.describe ::Import::GitlabProjects::FileAcquisitionStrategies::FileUpload, :aggregate_failures, feature_category: :importers do
let(:file) { UploadedFile.new(File.join('spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz')) }
describe 'validation' do
diff --git a/spec/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3_spec.rb b/spec/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3_spec.rb
index d9042e95149..411e2ec5286 100644
--- a/spec/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3_spec.rb
+++ b/spec/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Import::GitlabProjects::FileAcquisitionStrategies::RemoteFileS3, :aggregate_failures do
+RSpec.describe ::Import::GitlabProjects::FileAcquisitionStrategies::RemoteFileS3, :aggregate_failures, feature_category: :importers do
let(:region_name) { 'region_name' }
let(:bucket_name) { 'bucket_name' }
let(:file_key) { 'file_key' }
diff --git a/spec/services/import/prepare_service_spec.rb b/spec/services/import/prepare_service_spec.rb
index 0097198f7a9..fcb90575d96 100644
--- a/spec/services/import/prepare_service_spec.rb
+++ b/spec/services/import/prepare_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::PrepareService do
+RSpec.describe Import::PrepareService, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/import/validate_remote_git_endpoint_service_spec.rb b/spec/services/import/validate_remote_git_endpoint_service_spec.rb
index 221ac2cd73a..1d2b3975832 100644
--- a/spec/services/import/validate_remote_git_endpoint_service_spec.rb
+++ b/spec/services/import/validate_remote_git_endpoint_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::ValidateRemoteGitEndpointService do
+RSpec.describe Import::ValidateRemoteGitEndpointService, feature_category: :importers do
include StubRequests
let_it_be(:base_url) { 'http://demo.host/path' }
@@ -35,6 +35,28 @@ RSpec.describe Import::ValidateRemoteGitEndpointService do
end
end
+ context 'when uri is using an invalid protocol' do
+ subject { described_class.new(url: 'ssh://demo.host/repo') }
+
+ it 'reports error when invalid URL is provided' do
+ result = subject.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result.error?).to be(true)
+ end
+ end
+
+ context 'when uri is invalid' do
+ subject { described_class.new(url: 'http:example.com') }
+
+ it 'reports error when invalid URL is provided' do
+ result = subject.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result.error?).to be(true)
+ end
+ end
+
context 'when receiving HTTP response' do
subject { described_class.new(url: base_url) }
diff --git a/spec/services/import_csv/base_service_spec.rb b/spec/services/import_csv/base_service_spec.rb
index 0c0ed40ff4d..93fff0d546a 100644
--- a/spec/services/import_csv/base_service_spec.rb
+++ b/spec/services/import_csv/base_service_spec.rb
@@ -24,40 +24,65 @@ RSpec.describe ImportCsv::BaseService, feature_category: :importers do
it_behaves_like 'abstract method', :validate_headers_presence!, "any"
it_behaves_like 'abstract method', :create_object_class
- describe '#detect_col_sep' do
- context 'when header contains invalid separators' do
- it 'raises error' do
- header = 'Name&email'
+ context 'when given a class' do
+ let(:importer_klass) do
+ Class.new(described_class) do
+ def attributes_for(row)
+ { title: row[:title] }
+ end
- expect { subject.send(:detect_col_sep, header) }.to raise_error(CSV::MalformedCSVError)
- end
- end
+ def validate_headers_presence!(headers)
+ raise CSV::MalformedCSVError.new("Missing required headers", 1) unless headers.present?
+ end
- context 'when header is valid' do
- shared_examples 'header with valid separators' do
- let(:header) { "Name#{separator}email" }
+ def create_object_class
+ Class.new
+ end
- it 'returns separator value' do
- expect(subject.send(:detect_col_sep, header)).to eq(separator)
+ def email_results_to_user
+ # no-op
end
end
+ end
- context 'with ; as separator' do
- let(:separator) { ';' }
+ let(:service) do
+ uploader = FileUploader.new(project)
+ uploader.store!(file)
- it_behaves_like 'header with valid separators'
- end
+ importer_klass.new(user, project, uploader)
+ end
+
+ subject { service.execute }
+
+ it_behaves_like 'correctly handles invalid files'
+
+ describe '#detect_col_sep' do
+ using RSpec::Parameterized::TableSyntax
- context 'with \t as separator' do
- let(:separator) { "\t" }
+ let(:file) { double }
- it_behaves_like 'header with valid separators'
+ before do
+ allow(service).to receive_message_chain('csv_data.lines.first').and_return(header)
end
- context 'with , as separator' do
- let(:separator) { ',' }
+ where(:sep_character, :valid) do
+ '&' | false
+ '?' | false
+ ';' | true
+ ',' | true
+ "\t" | true
+ end
+
+ with_them do
+ let(:header) { "Name#{sep_character}email" }
- it_behaves_like 'header with valid separators'
+ it 'responds appropriately' do
+ if valid
+ expect(service.send(:detect_col_sep)).to eq sep_character
+ else
+ expect { service.send(:detect_col_sep) }.to raise_error(CSV::MalformedCSVError)
+ end
+ 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 2bcdfa6dd8f..7b638b4948b 100644
--- a/spec/services/import_export_clean_up_service_spec.rb
+++ b/spec/services/import_export_clean_up_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ImportExportCleanUpService do
+RSpec.describe ImportExportCleanUpService, feature_category: :importers do
describe '#execute' do
let(:service) { described_class.new }
diff --git a/spec/services/incident_management/incidents/create_service_spec.rb b/spec/services/incident_management/incidents/create_service_spec.rb
index 7db762b9c5b..e6ded379434 100644
--- a/spec/services/incident_management/incidents/create_service_spec.rb
+++ b/spec/services/incident_management/incidents/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::Incidents::CreateService do
+RSpec.describe IncidentManagement::Incidents::CreateService, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
let_it_be(:user) { User.alert_bot }
diff --git a/spec/services/incident_management/issuable_escalation_statuses/after_update_service_spec.rb b/spec/services/incident_management/issuable_escalation_statuses/after_update_service_spec.rb
index 4b0c8d9113c..9b1994af1bb 100644
--- a/spec/services/incident_management/issuable_escalation_statuses/after_update_service_spec.rb
+++ b/spec/services/incident_management/issuable_escalation_statuses/after_update_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::IssuableEscalationStatuses::AfterUpdateService do
+RSpec.describe IncidentManagement::IssuableEscalationStatuses::AfterUpdateService,
+ feature_category: :incident_management do
let_it_be(:current_user) { create(:user) }
let_it_be(:escalation_status, reload: true) { create(:incident_management_issuable_escalation_status, :triggered) }
let_it_be(:issue, reload: true) { escalation_status.issue }
diff --git a/spec/services/incident_management/issuable_escalation_statuses/build_service_spec.rb b/spec/services/incident_management/issuable_escalation_statuses/build_service_spec.rb
index b5c5238d483..56a159f452c 100644
--- a/spec/services/incident_management/issuable_escalation_statuses/build_service_spec.rb
+++ b/spec/services/incident_management/issuable_escalation_statuses/build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::IssuableEscalationStatuses::BuildService do
+RSpec.describe IncidentManagement::IssuableEscalationStatuses::BuildService, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
let_it_be(:incident, reload: true) { create(:incident, project: project) }
diff --git a/spec/services/incident_management/issuable_escalation_statuses/create_service_spec.rb b/spec/services/incident_management/issuable_escalation_statuses/create_service_spec.rb
index b6ae03a19fe..e6c63d63123 100644
--- a/spec/services/incident_management/issuable_escalation_statuses/create_service_spec.rb
+++ b/spec/services/incident_management/issuable_escalation_statuses/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::IssuableEscalationStatuses::CreateService do
+RSpec.describe IncidentManagement::IssuableEscalationStatuses::CreateService, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
let(:incident) { create(:incident, project: project) }
diff --git a/spec/services/incident_management/issuable_escalation_statuses/prepare_update_service_spec.rb b/spec/services/incident_management/issuable_escalation_statuses/prepare_update_service_spec.rb
index e8208c410d5..3f3174d0112 100644
--- a/spec/services/incident_management/issuable_escalation_statuses/prepare_update_service_spec.rb
+++ b/spec/services/incident_management/issuable_escalation_statuses/prepare_update_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::IssuableEscalationStatuses::PrepareUpdateService, factory_default: :keep do
+RSpec.describe IncidentManagement::IssuableEscalationStatuses::PrepareUpdateService, factory_default: :keep,
+ feature_category: :incident_management do
let_it_be(:project) { create_default(:project) }
let_it_be(:escalation_status) { create(:incident_management_issuable_escalation_status, :triggered) }
let_it_be(:user_with_permissions) { create(:user) }
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 2fda789cf56..caa5ee495b7 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
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::PagerDuty::CreateIncidentIssueService do
+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 }
diff --git a/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb b/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb
index e2aba0b61af..06f423bc63c 100644
--- a/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb
+++ b/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::PagerDuty::ProcessWebhookService do
+RSpec.describe IncidentManagement::PagerDuty::ProcessWebhookService, feature_category: :incident_management do
let_it_be(:project, reload: true) { create(:project) }
describe '#execute' do
diff --git a/spec/services/incident_management/timeline_event_tags/create_service_spec.rb b/spec/services/incident_management/timeline_event_tags/create_service_spec.rb
index c1b993ce3d9..b21a116d5f9 100644
--- a/spec/services/incident_management/timeline_event_tags/create_service_spec.rb
+++ b/spec/services/incident_management/timeline_event_tags/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::TimelineEventTags::CreateService do
+RSpec.describe IncidentManagement::TimelineEventTags::CreateService, feature_category: :incident_management do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be_with_reload(:project) { create(:project) }
diff --git a/spec/services/incident_management/timeline_events/create_service_spec.rb b/spec/services/incident_management/timeline_events/create_service_spec.rb
index fa5f4c64a43..fff6241f083 100644
--- a/spec/services/incident_management/timeline_events/create_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::TimelineEvents::CreateService do
+RSpec.describe IncidentManagement::TimelineEvents::CreateService, feature_category: :incident_management do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be(:project) { create(:project) }
@@ -57,7 +57,6 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
it_behaves_like 'an incident management tracked event', :incident_management_timeline_event_created
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
@@ -286,7 +285,6 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
it_behaves_like 'an incident management tracked event', :incident_management_timeline_event_created
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/services/incident_management/timeline_events/destroy_service_spec.rb b/spec/services/incident_management/timeline_events/destroy_service_spec.rb
index f90ff72a2bf..78f6659beec 100644
--- a/spec/services/incident_management/timeline_events/destroy_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::TimelineEvents::DestroyService do
+RSpec.describe IncidentManagement::TimelineEvents::DestroyService, feature_category: :incident_management do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be(:project) { create(:project) }
@@ -67,7 +67,6 @@ RSpec.describe IncidentManagement::TimelineEvents::DestroyService do
it_behaves_like 'an incident management tracked event', :incident_management_timeline_event_deleted
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:user) { current_user }
diff --git a/spec/services/incident_management/timeline_events/update_service_spec.rb b/spec/services/incident_management/timeline_events/update_service_spec.rb
index ebaa4dde7a2..c38126baa65 100644
--- a/spec/services/incident_management/timeline_events/update_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/update_service_spec.rb
@@ -50,7 +50,6 @@ RSpec.describe IncidentManagement::TimelineEvents::UpdateService, feature_catego
it_behaves_like 'an incident management tracked event', :incident_management_timeline_event_edited
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace.reload }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_timeline_event_edited' }
diff --git a/spec/services/integrations/propagate_service_spec.rb b/spec/services/integrations/propagate_service_spec.rb
index c971c4a0ad0..0267b1b0ed0 100644
--- a/spec/services/integrations/propagate_service_spec.rb
+++ b/spec/services/integrations/propagate_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::PropagateService do
+RSpec.describe Integrations::PropagateService, feature_category: :integrations do
describe '.propagate' do
include JiraIntegrationHelpers
diff --git a/spec/services/integrations/test/project_service_spec.rb b/spec/services/integrations/test/project_service_spec.rb
index 74833686283..4f8f932fb45 100644
--- a/spec/services/integrations/test/project_service_spec.rb
+++ b/spec/services/integrations/test/project_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::Test::ProjectService do
+RSpec.describe Integrations::Test::ProjectService, feature_category: :integrations do
include AfterNextHelpers
describe '#execute' do
diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index 7ba349ceeae..a76d575a1e0 100644
--- a/spec/services/issuable/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issuable::BulkUpdateService do
+RSpec.describe Issuable::BulkUpdateService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, namespace: user.namespace) }
diff --git a/spec/services/issuable/common_system_notes_service_spec.rb b/spec/services/issuable/common_system_notes_service_spec.rb
index 0d2b8a4ac3c..9306aeaac44 100644
--- a/spec/services/issuable/common_system_notes_service_spec.rb
+++ b/spec/services/issuable/common_system_notes_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issuable::CommonSystemNotesService do
+RSpec.describe Issuable::CommonSystemNotesService, feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/issuable/destroy_label_links_service_spec.rb b/spec/services/issuable/destroy_label_links_service_spec.rb
index bbc69e266c9..f0a92c201d2 100644
--- a/spec/services/issuable/destroy_label_links_service_spec.rb
+++ b/spec/services/issuable/destroy_label_links_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issuable::DestroyLabelLinksService do
+RSpec.describe Issuable::DestroyLabelLinksService, feature_category: :team_planning do
describe '#execute' do
context 'when target is an Issue' do
let_it_be(:target) { create(:issue) }
diff --git a/spec/services/issuable/destroy_service_spec.rb b/spec/services/issuable/destroy_service_spec.rb
index 29f548e1c47..1acaf01dce0 100644
--- a/spec/services/issuable/destroy_service_spec.rb
+++ b/spec/services/issuable/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issuable::DestroyService do
+RSpec.describe Issuable::DestroyService, feature_category: :team_planning do
let(:user) { create(:user) }
let(:group) { create(:group, :public) }
let(:project) { create(:project, :public, group: group) }
diff --git a/spec/services/issuable/discussions_list_service_spec.rb b/spec/services/issuable/discussions_list_service_spec.rb
index a6f57088ad1..03b6a1b4556 100644
--- a/spec/services/issuable/discussions_list_service_spec.rb
+++ b/spec/services/issuable/discussions_list_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issuable::DiscussionsListService do
+RSpec.describe Issuable::DiscussionsListService, feature_category: :team_planning do
let_it_be(:current_user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, :repository, :private, group: group) }
diff --git a/spec/services/issuable/process_assignees_spec.rb b/spec/services/issuable/process_assignees_spec.rb
index 9e909b68172..2c8d4c5e11d 100644
--- a/spec/services/issuable/process_assignees_spec.rb
+++ b/spec/services/issuable/process_assignees_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issuable::ProcessAssignees do
+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 = Issuable::ProcessAssignees.new(assignee_ids: %w(5 7 9),
diff --git a/spec/services/issue_links/create_service_spec.rb b/spec/services/issue_links/create_service_spec.rb
index 0629b8b091b..71603da1c90 100644
--- a/spec/services/issue_links/create_service_spec.rb
+++ b/spec/services/issue_links/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IssueLinks::CreateService do
+RSpec.describe IssueLinks::CreateService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:user) { create :user }
let_it_be(:namespace) { create :namespace }
@@ -43,7 +43,6 @@ RSpec.describe IssueLinks::CreateService do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_relate' }
diff --git a/spec/services/issue_links/destroy_service_spec.rb b/spec/services/issue_links/destroy_service_spec.rb
index ecb53b5cd31..5c4814f5ad1 100644
--- a/spec/services/issue_links/destroy_service_spec.rb
+++ b/spec/services/issue_links/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IssueLinks::DestroyService do
+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) }
@@ -27,7 +27,6 @@ RSpec.describe IssueLinks::DestroyService do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue_b.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_unrelate' }
diff --git a/spec/services/issue_links/list_service_spec.rb b/spec/services/issue_links/list_service_spec.rb
index 7a3ba845c7c..bfb6127ed56 100644
--- a/spec/services/issue_links/list_service_spec.rb
+++ b/spec/services/issue_links/list_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IssueLinks::ListService do
+RSpec.describe IssueLinks::ListService, feature_category: :team_planning do
let(:user) { create :user }
let(:project) { create(:project_empty_repo, :private) }
let(:issue) { create :issue, project: project }
diff --git a/spec/services/issues/after_create_service_spec.rb b/spec/services/issues/after_create_service_spec.rb
index 39a6799dbad..594caed23d7 100644
--- a/spec/services/issues/after_create_service_spec.rb
+++ b/spec/services/issues/after_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::AfterCreateService do
+RSpec.describe Issues::AfterCreateService, feature_category: :team_planning do
include AfterNextHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/services/issues/base_service_spec.rb b/spec/services/issues/base_service_spec.rb
new file mode 100644
index 00000000000..94165d557d8
--- /dev/null
+++ b/spec/services/issues/base_service_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Issues::BaseService, feature_category: :team_planning do
+ describe '#constructor_container_arg' do
+ it { expect(described_class.constructor_container_arg("some-value")).to eq({ container: "some-value" }) }
+ end
+end
diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb
index 2160c45d079..0f89a746520 100644
--- a/spec/services/issues/build_service_spec.rb
+++ b/spec/services/issues/build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::BuildService do
+RSpec.describe Issues::BuildService, feature_category: :team_planning do
using RSpec::Parameterized::TableSyntax
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/services/issues/clone_service_spec.rb b/spec/services/issues/clone_service_spec.rb
index eafaea93015..2fb14d8ce8e 100644
--- a/spec/services/issues/clone_service_spec.rb
+++ b/spec/services/issues/clone_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::CloneService do
+RSpec.describe Issues::CloneService, feature_category: :team_planning do
include DesignManagementTestHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index 803808e667c..0d9b3306540 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::CloseService do
+RSpec.describe Issues::CloseService, feature_category: :team_planning do
let(:project) { create(:project, :repository) }
let(:user) { create(:user, email: "user@example.com") }
let(:user2) { create(:user, email: "user2@example.com") }
@@ -100,7 +100,6 @@ RSpec.describe Issues::CloseService do
it_behaves_like 'an incident management tracked event', :incident_management_incident_closed
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_closed' }
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index ada5b300d7a..d5d88baca1f 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::CreateService do
+RSpec.describe Issues::CreateService, feature_category: :team_planning do
include AfterNextHelpers
let_it_be(:group) { create(:group, :crm_enabled) }
diff --git a/spec/services/issues/duplicate_service_spec.rb b/spec/services/issues/duplicate_service_spec.rb
index f49bce70cd0..f9d8bf04ae9 100644
--- a/spec/services/issues/duplicate_service_spec.rb
+++ b/spec/services/issues/duplicate_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::DuplicateService do
+RSpec.describe Issues::DuplicateService, feature_category: :team_planning do
let(:user) { create(:user) }
let(:canonical_project) { create(:project) }
let(:duplicate_project) { create(:project) }
diff --git a/spec/services/issues/import_csv_service_spec.rb b/spec/services/issues/import_csv_service_spec.rb
index 90e360f9cf1..6a147782209 100644
--- a/spec/services/issues/import_csv_service_spec.rb
+++ b/spec/services/issues/import_csv_service_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Issues::ImportCsvService, feature_category: :team_planning do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:assignee) { create(:user, username: 'csv_assignee') }
+ let(:file) { fixture_file_upload('spec/fixtures/csv_complex.csv') }
let(:service) do
uploader = FileUploader.new(project)
uploader.store!(file)
@@ -19,8 +20,6 @@ RSpec.describe Issues::ImportCsvService, feature_category: :team_planning do
end
describe '#execute' do
- let(:file) { fixture_file_upload('spec/fixtures/csv_complex.csv') }
-
subject { service.execute }
it 'sets all issueable attributes and executes quick actions' do
diff --git a/spec/services/issues/issuable_base_service_spec.rb b/spec/services/issues/issuable_base_service_spec.rb
new file mode 100644
index 00000000000..e1680d5c908
--- /dev/null
+++ b/spec/services/issues/issuable_base_service_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IssuableBaseService, feature_category: :team_planning do
+ describe '#constructor_container_arg' do
+ it { expect(described_class.constructor_container_arg("some-value")).to eq({ container: "some-value" }) }
+ end
+end
diff --git a/spec/services/issues/prepare_import_csv_service_spec.rb b/spec/services/issues/prepare_import_csv_service_spec.rb
index ded23ee43b9..d318d4fd25e 100644
--- a/spec/services/issues/prepare_import_csv_service_spec.rb
+++ b/spec/services/issues/prepare_import_csv_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::PrepareImportCsvService do
+RSpec.describe Issues::PrepareImportCsvService, feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/issues/referenced_merge_requests_service_spec.rb b/spec/services/issues/referenced_merge_requests_service_spec.rb
index aee3583b834..4781daf7688 100644
--- a/spec/services/issues/referenced_merge_requests_service_spec.rb
+++ b/spec/services/issues/referenced_merge_requests_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::ReferencedMergeRequestsService do
+RSpec.describe Issues::ReferencedMergeRequestsService, feature_category: :team_planning do
def create_referencing_mr(attributes = {})
create(:merge_request, attributes).tap do |merge_request|
create(:note, :system, project: project, noteable: issue, author: user, note: merge_request.to_reference(full: true))
diff --git a/spec/services/issues/related_branches_service_spec.rb b/spec/services/issues/related_branches_service_spec.rb
index 05c61d0abfc..940d988668e 100644
--- a/spec/services/issues/related_branches_service_spec.rb
+++ b/spec/services/issues/related_branches_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::RelatedBranchesService do
+RSpec.describe Issues::RelatedBranchesService, feature_category: :team_planning do
let_it_be(:project) { create(:project, :repository, :public, public_builds: false) }
let_it_be(:developer) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/services/issues/relative_position_rebalancing_service_spec.rb b/spec/services/issues/relative_position_rebalancing_service_spec.rb
index 27c0394ac8b..68f1af49b5f 100644
--- a/spec/services/issues/relative_position_rebalancing_service_spec.rb
+++ b/spec/services/issues/relative_position_rebalancing_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::RelativePositionRebalancingService, :clean_gitlab_redis_shared_state do
+RSpec.describe Issues::RelativePositionRebalancingService, :clean_gitlab_redis_shared_state, feature_category: :team_planning do
let_it_be(:project, reload: true) { create(:project, :repository_disabled, skip_disk_validation: true) }
let_it_be(:user) { project.creator }
let_it_be(:start) { RelativePositioning::START_POSITION }
diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb
index 68015a2327e..0f89844a2c1 100644
--- a/spec/services/issues/reopen_service_spec.rb
+++ b/spec/services/issues/reopen_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::ReopenService do
+RSpec.describe Issues::ReopenService, feature_category: :team_planning do
let(:project) { create(:project) }
let(:issue) { create(:issue, :closed, project: project) }
@@ -75,7 +75,6 @@ RSpec.describe Issues::ReopenService do
it_behaves_like 'an incident management tracked event', :incident_management_incident_reopened
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_reopened' }
diff --git a/spec/services/issues/reorder_service_spec.rb b/spec/services/issues/reorder_service_spec.rb
index 430a9e9f526..b98d23e0f7f 100644
--- a/spec/services/issues/reorder_service_spec.rb
+++ b/spec/services/issues/reorder_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::ReorderService do
+RSpec.describe Issues::ReorderService, feature_category: :team_planning do
let_it_be(:user) { create_default(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project, reload: true) { create(:project, namespace: group) }
diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb
index 1ac71b966bc..c2111bffdda 100644
--- a/spec/services/issues/resolve_discussions_spec.rb
+++ b/spec/services/issues/resolve_discussions_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::ResolveDiscussions do
+RSpec.describe Issues::ResolveDiscussions, feature_category: :team_planning do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
@@ -11,7 +11,7 @@ RSpec.describe Issues::ResolveDiscussions do
DummyService.class_eval do
include ::Issues::ResolveDiscussions
- def initialize(project:, current_user: nil, params: {})
+ def initialize(container:, current_user: nil, params: {})
super
filter_resolve_discussion_params
end
@@ -26,7 +26,7 @@ RSpec.describe Issues::ResolveDiscussions do
let(:other_merge_request) { create(:merge_request, source_project: project, source_branch: "fix") }
describe "#merge_request_for_resolving_discussion" do
- let(:service) { DummyService.new(project: project, current_user: user, params: { merge_request_to_resolve_discussions_of: merge_request.iid }) }
+ let(:service) { DummyService.new(container: project, current_user: user, params: { merge_request_to_resolve_discussions_of: merge_request.iid }) }
it "finds the merge request" do
expect(service.merge_request_to_resolve_discussions_of).to eq(merge_request)
@@ -45,7 +45,7 @@ RSpec.describe Issues::ResolveDiscussions do
describe "#discussions_to_resolve" do
it "contains a single discussion when matching merge request and discussion are passed" do
service = DummyService.new(
- project: project,
+ container: project,
current_user: user,
params: {
discussion_to_resolve: discussion.id,
@@ -65,7 +65,7 @@ RSpec.describe Issues::ResolveDiscussions do
project: merge_request.target_project,
line_number: 15)])
service = DummyService.new(
- project: project,
+ container: project,
current_user: user,
params: { merge_request_to_resolve_discussions_of: merge_request.iid }
)
@@ -83,7 +83,7 @@ RSpec.describe Issues::ResolveDiscussions do
line_number: 15
)])
service = DummyService.new(
- project: project,
+ container: project,
current_user: user,
params: { merge_request_to_resolve_discussions_of: merge_request.iid }
)
@@ -96,7 +96,7 @@ RSpec.describe Issues::ResolveDiscussions do
it "is empty when a discussion and another merge request are passed" do
service = DummyService.new(
- project: project,
+ container: project,
current_user: user,
params: {
discussion_to_resolve: discussion.id,
diff --git a/spec/services/issues/set_crm_contacts_service_spec.rb b/spec/services/issues/set_crm_contacts_service_spec.rb
index 5613cc49cc5..aa5dec20a13 100644
--- a/spec/services/issues/set_crm_contacts_service_spec.rb
+++ b/spec/services/issues/set_crm_contacts_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::SetCrmContactsService do
+RSpec.describe Issues::SetCrmContactsService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :crm_enabled) }
let_it_be(:project) { create(:project, group: create(:group, :crm_enabled, parent: group)) }
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 973025bd2e3..9c81015e05e 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::UpdateService, :mailer do
+RSpec.describe Issues::UpdateService, :mailer, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
let_it_be(:user3) { create(:user) }
@@ -191,7 +191,6 @@ RSpec.describe Issues::UpdateService, :mailer do
it_behaves_like 'an incident management tracked event', :incident_management_incident_change_confidential
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' }
@@ -696,7 +695,6 @@ RSpec.describe Issues::UpdateService, :mailer do
it_behaves_like 'an incident management tracked event', :incident_management_incident_assigned
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:label) { 'redis_hll_counters.incident_management.incident_management_total_unique_counts_monthly' }
diff --git a/spec/services/issues/zoom_link_service_spec.rb b/spec/services/issues/zoom_link_service_spec.rb
index 230e4c1b5e1..f2a81cbe33f 100644
--- a/spec/services/issues/zoom_link_service_spec.rb
+++ b/spec/services/issues/zoom_link_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::ZoomLinkService do
+RSpec.describe Issues::ZoomLinkService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue) }
@@ -97,7 +97,6 @@ RSpec.describe Issues::ZoomLinkService do
it_behaves_like 'an incident management tracked event', :incident_management_incident_zoom_meeting
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_zoom_meeting' }
diff --git a/spec/services/jira/requests/projects/list_service_spec.rb b/spec/services/jira/requests/projects/list_service_spec.rb
index 78ee9cb9698..37e9f66d273 100644
--- a/spec/services/jira/requests/projects/list_service_spec.rb
+++ b/spec/services/jira/requests/projects/list_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Jira::Requests::Projects::ListService do
+RSpec.describe Jira::Requests::Projects::ListService, feature_category: :projects do
include AfterNextHelpers
let(:jira_integration) { create(:jira_integration) }
diff --git a/spec/services/jira_connect/sync_service_spec.rb b/spec/services/jira_connect/sync_service_spec.rb
index 32580a7735f..fc1b4e997a5 100644
--- a/spec/services/jira_connect/sync_service_spec.rb
+++ b/spec/services/jira_connect/sync_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraConnect::SyncService do
+RSpec.describe JiraConnect::SyncService, feature_category: :integrations do
include AfterNextHelpers
describe '#execute' do
diff --git a/spec/services/jira_connect_installations/destroy_service_spec.rb b/spec/services/jira_connect_installations/destroy_service_spec.rb
index bb5bab53ccb..b8b59d6cc57 100644
--- a/spec/services/jira_connect_installations/destroy_service_spec.rb
+++ b/spec/services/jira_connect_installations/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraConnectInstallations::DestroyService do
+RSpec.describe JiraConnectInstallations::DestroyService, feature_category: :integrations do
describe '.execute' do
it 'creates an instance and calls execute' do
expect_next_instance_of(described_class, 'param1', 'param2', 'param3') do |destroy_service|
diff --git a/spec/services/jira_connect_installations/proxy_lifecycle_event_service_spec.rb b/spec/services/jira_connect_installations/proxy_lifecycle_event_service_spec.rb
index c621388a734..3c144de2208 100644
--- a/spec/services/jira_connect_installations/proxy_lifecycle_event_service_spec.rb
+++ b/spec/services/jira_connect_installations/proxy_lifecycle_event_service_spec.rb
@@ -94,9 +94,9 @@ RSpec.describe JiraConnectInstallations::ProxyLifecycleEventService, feature_cat
expect(Gitlab::IntegrationsLogger).to receive(:info).with(
integration: 'JiraConnect',
message: 'Proxy lifecycle event received error response',
- event_type: evnet_type,
- status_code: 422,
- body: 'Error message'
+ jira_event_type: evnet_type,
+ jira_status_code: 422,
+ jira_body: 'Error message'
)
execute_service
diff --git a/spec/services/jira_connect_subscriptions/create_service_spec.rb b/spec/services/jira_connect_subscriptions/create_service_spec.rb
index 85208a30c30..f9d3954b84c 100644
--- a/spec/services/jira_connect_subscriptions/create_service_spec.rb
+++ b/spec/services/jira_connect_subscriptions/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraConnectSubscriptions::CreateService do
+RSpec.describe JiraConnectSubscriptions::CreateService, feature_category: :integrations do
let_it_be(:installation) { create(:jira_connect_installation) }
let_it_be(:current_user) { create(:user) }
let_it_be(:group) { create(:group) }
diff --git a/spec/services/jira_import/cloud_users_mapper_service_spec.rb b/spec/services/jira_import/cloud_users_mapper_service_spec.rb
index 6b06a982a80..e3f3d550467 100644
--- a/spec/services/jira_import/cloud_users_mapper_service_spec.rb
+++ b/spec/services/jira_import/cloud_users_mapper_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraImport::CloudUsersMapperService do
+RSpec.describe JiraImport::CloudUsersMapperService, feature_category: :integrations do
let(:start_at) { 7 }
let(:url) { "/rest/api/2/users?maxResults=50&startAt=#{start_at}" }
diff --git a/spec/services/jira_import/server_users_mapper_service_spec.rb b/spec/services/jira_import/server_users_mapper_service_spec.rb
index 71cb8aea0be..e2304953dd2 100644
--- a/spec/services/jira_import/server_users_mapper_service_spec.rb
+++ b/spec/services/jira_import/server_users_mapper_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraImport::ServerUsersMapperService do
+RSpec.describe JiraImport::ServerUsersMapperService, feature_category: :integrations do
let(:start_at) { 7 }
let(:url) { "/rest/api/2/user/search?username=''&maxResults=50&startAt=#{start_at}" }
diff --git a/spec/services/jira_import/start_import_service_spec.rb b/spec/services/jira_import/start_import_service_spec.rb
index c0db3012a30..9cb163e3d1a 100644
--- a/spec/services/jira_import/start_import_service_spec.rb
+++ b/spec/services/jira_import/start_import_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraImport::StartImportService do
+RSpec.describe JiraImport::StartImportService, feature_category: :integrations do
include JiraIntegrationHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/jira_import/users_importer_spec.rb b/spec/services/jira_import/users_importer_spec.rb
index ace9e0d5779..39f8475754a 100644
--- a/spec/services/jira_import/users_importer_spec.rb
+++ b/spec/services/jira_import/users_importer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraImport::UsersImporter do
+RSpec.describe JiraImport::UsersImporter, feature_category: :integrations do
include JiraIntegrationHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/keys/create_service_spec.rb b/spec/services/keys/create_service_spec.rb
index 1dbe383ad8e..0a9fe2f5856 100644
--- a/spec/services/keys/create_service_spec.rb
+++ b/spec/services/keys/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Keys::CreateService do
+RSpec.describe Keys::CreateService, feature_category: :source_code_management do
let(:user) { create(:user) }
let(:params) { attributes_for(:key) }
diff --git a/spec/services/keys/destroy_service_spec.rb b/spec/services/keys/destroy_service_spec.rb
index dd40f9d73fd..9f064cb7236 100644
--- a/spec/services/keys/destroy_service_spec.rb
+++ b/spec/services/keys/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Keys::DestroyService do
+RSpec.describe Keys::DestroyService, feature_category: :source_code_management do
let(:user) { create(:user) }
subject { described_class.new(user) }
diff --git a/spec/services/keys/expiry_notification_service_spec.rb b/spec/services/keys/expiry_notification_service_spec.rb
index 7cb6cbce311..b8db4f28df7 100644
--- a/spec/services/keys/expiry_notification_service_spec.rb
+++ b/spec/services/keys/expiry_notification_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Keys::ExpiryNotificationService do
+RSpec.describe Keys::ExpiryNotificationService, feature_category: :source_code_management do
let_it_be_with_reload(:user) { create(:user) }
let(:params) { { keys: user.keys, expiring_soon: expiring_soon } }
diff --git a/spec/services/keys/last_used_service_spec.rb b/spec/services/keys/last_used_service_spec.rb
index a2cd5ffdd38..3113fe27acf 100644
--- a/spec/services/keys/last_used_service_spec.rb
+++ b/spec/services/keys/last_used_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Keys::LastUsedService do
+RSpec.describe Keys::LastUsedService, feature_category: :source_code_management do
describe '#execute', :clean_gitlab_redis_shared_state do
it 'updates the key when it has not been used recently' do
key = create(:key, last_used_at: 1.year.ago)
diff --git a/spec/services/keys/revoke_service_spec.rb b/spec/services/keys/revoke_service_spec.rb
index ec07701b4b7..8294ec5bbd1 100644
--- a/spec/services/keys/revoke_service_spec.rb
+++ b/spec/services/keys/revoke_service_spec.rb
@@ -32,17 +32,4 @@ RSpec.describe Keys::RevokeService, feature_category: :source_code_management do
expect { service.execute(key) }.not_to change { signature.reload.verification_status }
expect(key).to be_persisted
end
-
- context 'when revoke_ssh_signatures disabled' do
- before do
- stub_feature_flags(revoke_ssh_signatures: false)
- end
-
- it 'does not unverifies signatures' do
- key = create(:key)
- signature = create(:ssh_signature, key: key)
-
- expect { service.execute(key) }.not_to change { signature.reload.verification_status }
- end
- end
end
diff --git a/spec/services/labels/available_labels_service_spec.rb b/spec/services/labels/available_labels_service_spec.rb
index 355dbd0c712..51314c2c226 100644
--- a/spec/services/labels/available_labels_service_spec.rb
+++ b/spec/services/labels/available_labels_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Labels::AvailableLabelsService do
+RSpec.describe Labels::AvailableLabelsService, feature_category: :team_planning do
let(:user) { create(:user) }
let(:project) { create(:project, :public, group: group) }
let(:group) { create(:group) }
diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb
index 02dec8ae690..9be611490cf 100644
--- a/spec/services/labels/create_service_spec.rb
+++ b/spec/services/labels/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Labels::CreateService do
+RSpec.describe Labels::CreateService, feature_category: :team_planning do
describe '#execute' do
let(:project) { create(:project) }
let(:group) { create(:group) }
diff --git a/spec/services/labels/find_or_create_service_spec.rb b/spec/services/labels/find_or_create_service_spec.rb
index 3ea2727dc60..0bc1326942d 100644
--- a/spec/services/labels/find_or_create_service_spec.rb
+++ b/spec/services/labels/find_or_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Labels::FindOrCreateService do
+RSpec.describe Labels::FindOrCreateService, feature_category: :team_planning do
describe '#execute' do
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb
index 3af6cf4c8f4..79cc88c65c8 100644
--- a/spec/services/labels/promote_service_spec.rb
+++ b/spec/services/labels/promote_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Labels::PromoteService do
+RSpec.describe Labels::PromoteService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:user) { create(:user) }
diff --git a/spec/services/labels/transfer_service_spec.rb b/spec/services/labels/transfer_service_spec.rb
index e67ab6025a5..bf895692e64 100644
--- a/spec/services/labels/transfer_service_spec.rb
+++ b/spec/services/labels/transfer_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Labels::TransferService do
+RSpec.describe Labels::TransferService, feature_category: :team_planning do
shared_examples 'transfer labels' do
describe '#execute' do
let_it_be(:user) { create(:user) }
diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb
index abc456f75f9..b9ac5282d10 100644
--- a/spec/services/labels/update_service_spec.rb
+++ b/spec/services/labels/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Labels::UpdateService do
+RSpec.describe Labels::UpdateService, feature_category: :team_planning do
describe '#execute' do
let(:project) { create(:project) }
diff --git a/spec/services/lfs/lock_file_service_spec.rb b/spec/services/lfs/lock_file_service_spec.rb
index b3a121866c8..47bf0c5f4ce 100644
--- a/spec/services/lfs/lock_file_service_spec.rb
+++ b/spec/services/lfs/lock_file_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Lfs::LockFileService do
+RSpec.describe Lfs::LockFileService, feature_category: :source_code_management do
let(:project) { create(:project) }
let(:current_user) { create(:user) }
diff --git a/spec/services/lfs/locks_finder_service_spec.rb b/spec/services/lfs/locks_finder_service_spec.rb
index 1167212eb69..38f8dadd38d 100644
--- a/spec/services/lfs/locks_finder_service_spec.rb
+++ b/spec/services/lfs/locks_finder_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Lfs::LocksFinderService do
+RSpec.describe Lfs::LocksFinderService, feature_category: :source_code_management do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:params) { {} }
diff --git a/spec/services/lfs/push_service_spec.rb b/spec/services/lfs/push_service_spec.rb
index f52bba94eea..1ec143a7fc9 100644
--- a/spec/services/lfs/push_service_spec.rb
+++ b/spec/services/lfs/push_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Lfs::PushService do
+RSpec.describe Lfs::PushService, feature_category: :source_code_management do
let(:logger) { service.send(:logger) }
let(:lfs_client) { service.send(:lfs_client) }
diff --git a/spec/services/lfs/unlock_file_service_spec.rb b/spec/services/lfs/unlock_file_service_spec.rb
index 7ab269f897a..45fd1adcfb4 100644
--- a/spec/services/lfs/unlock_file_service_spec.rb
+++ b/spec/services/lfs/unlock_file_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Lfs::UnlockFileService do
+RSpec.describe Lfs::UnlockFileService, feature_category: :source_code_management do
let(:project) { create(:project) }
let(:current_user) { create(:user) }
let(:lock_author) { create(:user) }
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 735f090d926..6eee83d5ee9 100644
--- a/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb
+++ b/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe LooseForeignKeys::BatchCleanerService do
+RSpec.describe LooseForeignKeys::BatchCleanerService, feature_category: :database do
include MigrationsHelpers
def create_table_structure
diff --git a/spec/services/loose_foreign_keys/cleaner_service_spec.rb b/spec/services/loose_foreign_keys/cleaner_service_spec.rb
index 2cfd8385953..04f6270c5f2 100644
--- a/spec/services/loose_foreign_keys/cleaner_service_spec.rb
+++ b/spec/services/loose_foreign_keys/cleaner_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe LooseForeignKeys::CleanerService do
+RSpec.describe LooseForeignKeys::CleanerService, feature_category: :database do
let(:schema) { ApplicationRecord.connection.current_schema }
let(:deleted_records) 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 1824f822ba8..af010547cc9 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
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe LooseForeignKeys::ProcessDeletedRecordsService do
+RSpec.describe LooseForeignKeys::ProcessDeletedRecordsService, feature_category: :database do
include MigrationsHelpers
def create_table_structure
diff --git a/spec/services/markdown_content_rewriter_service_spec.rb b/spec/services/markdown_content_rewriter_service_spec.rb
index d94289856cf..bf15ef08647 100644
--- a/spec/services/markdown_content_rewriter_service_spec.rb
+++ b/spec/services/markdown_content_rewriter_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MarkdownContentRewriterService do
+RSpec.describe MarkdownContentRewriterService, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:source_parent) { create(:project, :public) }
let_it_be(:target_parent) { create(:project, :public) }
diff --git a/spec/services/markup/rendering_service_spec.rb b/spec/services/markup/rendering_service_spec.rb
index 99ab87f2072..952ee33da98 100644
--- a/spec/services/markup/rendering_service_spec.rb
+++ b/spec/services/markup/rendering_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Markup::RenderingService do
+RSpec.describe Markup::RenderingService, feature_category: :projects do
describe '#execute' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) do
@@ -111,5 +111,22 @@ RSpec.describe Markup::RenderingService do
is_expected.to eq(expected_html)
end
end
+
+ context 'with reStructuredText' do
+ let(:file_name) { 'foo.rst' }
+ let(:text) { "####\nPART\n####" }
+
+ it 'returns rendered html' do
+ is_expected.to eq("<h1>PART</h1>\n\n")
+ end
+
+ context 'when input has an invalid syntax' do
+ let(:text) { "####\nPART\n##" }
+
+ it 'uses a simple formatter for html' do
+ is_expected.to eq("<p>####\n<br>PART\n<br>##</p>")
+ end
+ end
+ end
end
end
diff --git a/spec/services/mattermost/create_team_service_spec.rb b/spec/services/mattermost/create_team_service_spec.rb
new file mode 100644
index 00000000000..b9e5162aab4
--- /dev/null
+++ b/spec/services/mattermost/create_team_service_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mattermost::CreateTeamService, feature_category: :integrations do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+
+ subject { described_class.new(group, user) }
+
+ it 'creates a team' do
+ expect_next_instance_of(::Mattermost::Team) do |instance|
+ expect(instance).to receive(:create).with(name: anything, display_name: anything, type: anything)
+ end
+
+ subject.execute
+ end
+
+ it 'adds an error if a team could not be created' do
+ expect_next_instance_of(::Mattermost::Team) do |instance|
+ expect(instance).to receive(:create).and_raise(::Mattermost::ClientError, 'client error')
+ end
+
+ subject.execute
+
+ expect(group.errors).to be_present
+ end
+end
diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb
index ca5c052d032..de5074809cb 100644
--- a/spec/services/members/approve_access_request_service_spec.rb
+++ b/spec/services/members/approve_access_request_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::ApproveAccessRequestService do
+RSpec.describe Members::ApproveAccessRequestService, feature_category: :subgroups do
let(:project) { create(:project, :public) }
let(:group) { create(:group, :public) }
let(:current_user) { create(:user) }
diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb
index 756e1cf403c..13f233162cd 100644
--- a/spec/services/members/create_service_spec.rb
+++ b/spec/services/members/create_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state, :sidekiq_inline do
+RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state, :sidekiq_inline,
+ feature_category: :subgroups do
let_it_be(:source, reload: true) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:member) { create(:user) }
diff --git a/spec/services/members/creator_service_spec.rb b/spec/services/members/creator_service_spec.rb
index ad4c649086b..8191eefbe95 100644
--- a/spec/services/members/creator_service_spec.rb
+++ b/spec/services/members/creator_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::CreatorService do
+RSpec.describe Members::CreatorService, feature_category: :subgroups do
let_it_be(:source, reload: true) { create(:group, :public) }
let_it_be(:member_type) { GroupMember }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/members/groups/creator_service_spec.rb b/spec/services/members/groups/creator_service_spec.rb
index fced7195046..48c971297c1 100644
--- a/spec/services/members/groups/creator_service_spec.rb
+++ b/spec/services/members/groups/creator_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::Groups::CreatorService do
+RSpec.describe Members::Groups::CreatorService, feature_category: :subgroups do
let_it_be(:source, reload: true) { create(:group, :public) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/members/import_project_team_service_spec.rb b/spec/services/members/import_project_team_service_spec.rb
index 96e8db1ba73..af9b30aa0b3 100644
--- a/spec/services/members/import_project_team_service_spec.rb
+++ b/spec/services/members/import_project_team_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::ImportProjectTeamService do
+RSpec.describe Members::ImportProjectTeamService, feature_category: :subgroups do
describe '#execute' do
let_it_be(:source_project) { create(:project) }
let_it_be(:target_project) { create(:project) }
diff --git a/spec/services/members/invitation_reminder_email_service_spec.rb b/spec/services/members/invitation_reminder_email_service_spec.rb
index 768a8719d54..da23965eabe 100644
--- a/spec/services/members/invitation_reminder_email_service_spec.rb
+++ b/spec/services/members/invitation_reminder_email_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::InvitationReminderEmailService do
+RSpec.describe Members::InvitationReminderEmailService, feature_category: :subgroups do
describe 'sending invitation reminders' do
subject { described_class.new(invitation).execute }
diff --git a/spec/services/members/invite_member_builder_spec.rb b/spec/services/members/invite_member_builder_spec.rb
index 52de65364c4..e7bbec4e0ef 100644
--- a/spec/services/members/invite_member_builder_spec.rb
+++ b/spec/services/members/invite_member_builder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::InviteMemberBuilder do
+RSpec.describe Members::InviteMemberBuilder, feature_category: :subgroups do
let_it_be(:source) { create(:group) }
let_it_be(:existing_member) { create(:group_member) }
diff --git a/spec/services/members/invite_service_spec.rb b/spec/services/members/invite_service_spec.rb
index 23d4d671afc..22294b3fda5 100644
--- a/spec/services/members/invite_service_spec.rb
+++ b/spec/services/members/invite_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_shared_state, :sidekiq_inline do
+RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_shared_state, :sidekiq_inline,
+ feature_category: :subgroups do
let_it_be(:project, reload: true) { create(:project) }
let_it_be(:user) { project.first_owner }
let_it_be(:project_user) { create(:user) }
diff --git a/spec/services/members/projects/creator_service_spec.rb b/spec/services/members/projects/creator_service_spec.rb
index 5dfba7adf0f..f09682347ef 100644
--- a/spec/services/members/projects/creator_service_spec.rb
+++ b/spec/services/members/projects/creator_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::Projects::CreatorService do
+RSpec.describe Members::Projects::CreatorService, feature_category: :projects do
let_it_be(:source, reload: true) { create(:project, :public) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/members/request_access_service_spec.rb b/spec/services/members/request_access_service_spec.rb
index 69eea2aea4b..ef8ee6492ab 100644
--- a/spec/services/members/request_access_service_spec.rb
+++ b/spec/services/members/request_access_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::RequestAccessService do
+RSpec.describe Members::RequestAccessService, feature_category: :subgroups do
let(:user) { create(:user) }
shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do
diff --git a/spec/services/members/standard_member_builder_spec.rb b/spec/services/members/standard_member_builder_spec.rb
index 16daff53d31..69b764f3f16 100644
--- a/spec/services/members/standard_member_builder_spec.rb
+++ b/spec/services/members/standard_member_builder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::StandardMemberBuilder do
+RSpec.describe Members::StandardMemberBuilder, feature_category: :subgroups do
let_it_be(:source) { create(:group) }
let_it_be(:existing_member) { create(:group_member) }
diff --git a/spec/services/members/unassign_issuables_service_spec.rb b/spec/services/members/unassign_issuables_service_spec.rb
index 3f7ccb7bab3..37dfbd16c56 100644
--- a/spec/services/members/unassign_issuables_service_spec.rb
+++ b/spec/services/members/unassign_issuables_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::UnassignIssuablesService do
+RSpec.describe Members::UnassignIssuablesService, feature_category: :subgroups do
let_it_be(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:user, reload: true) { create(:user) }
diff --git a/spec/services/members/update_service_spec.rb b/spec/services/members/update_service_spec.rb
index 8a7f9a84c77..b94b44c8485 100644
--- a/spec/services/members/update_service_spec.rb
+++ b/spec/services/members/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::UpdateService do
+RSpec.describe Members::UpdateService, feature_category: :subgroups do
let_it_be(:project) { create(:project, :public) }
let_it_be(:group) { create(:group, :public) }
let_it_be(:current_user) { create(:user) }
diff --git a/spec/services/merge_requests/add_context_service_spec.rb b/spec/services/merge_requests/add_context_service_spec.rb
index 448be27efe8..5fca2c17a3c 100644
--- a/spec/services/merge_requests/add_context_service_spec.rb
+++ b/spec/services/merge_requests/add_context_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::AddContextService do
+RSpec.describe MergeRequests::AddContextService, feature_category: :code_review_workflow do
let(:project) { create(:project, :repository) }
let(:admin) { create(:admin) }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: admin) }
diff --git a/spec/services/merge_requests/add_spent_time_service_spec.rb b/spec/services/merge_requests/add_spent_time_service_spec.rb
index 1e0b3e07f26..5d6d33c14d7 100644
--- a/spec/services/merge_requests/add_spent_time_service_spec.rb
+++ b/spec/services/merge_requests/add_spent_time_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::AddSpentTimeService do
+RSpec.describe MergeRequests::AddSpentTimeService, feature_category: :code_review_workflow do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be_with_reload(:merge_request) { create(:merge_request, :simple, :unique_branches, source_project: project) }
diff --git a/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb b/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb
index 8d1abe5ea89..3c37792b576 100644
--- a/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb
+++ b/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::MergeRequests::AddTodoWhenBuildFailsService do
+RSpec.describe ::MergeRequests::AddTodoWhenBuildFailsService, feature_category: :code_review_workflow do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:sha) { '1234567890abcdef1234567890abcdef12345678' }
diff --git a/spec/services/merge_requests/approval_service_spec.rb b/spec/services/merge_requests/approval_service_spec.rb
index 1d6427900b9..6140021c8d2 100644
--- a/spec/services/merge_requests/approval_service_spec.rb
+++ b/spec/services/merge_requests/approval_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ApprovalService do
+RSpec.describe MergeRequests::ApprovalService, feature_category: :code_review_workflow do
describe '#execute' do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request, reviewers: [user]) }
diff --git a/spec/services/merge_requests/assign_issues_service_spec.rb b/spec/services/merge_requests/assign_issues_service_spec.rb
index cf405c0102e..f5fb88b6161 100644
--- a/spec/services/merge_requests/assign_issues_service_spec.rb
+++ b/spec/services/merge_requests/assign_issues_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::AssignIssuesService do
+RSpec.describe MergeRequests::AssignIssuesService, feature_category: :code_review_workflow do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/services/merge_requests/base_service_spec.rb b/spec/services/merge_requests/base_service_spec.rb
index bd907ba6015..deabb1c9804 100644
--- a/spec/services/merge_requests/base_service_spec.rb
+++ b/spec/services/merge_requests/base_service_spec.rb
@@ -123,4 +123,8 @@ RSpec.describe MergeRequests::BaseService, feature_category: :code_review_workfl
end
end
end
+
+ describe '#constructor_container_arg' do
+ it { expect(described_class.constructor_container_arg("some-value")).to eq({ project: "some-value" }) }
+ end
end
diff --git a/spec/services/merge_requests/cleanup_refs_service_spec.rb b/spec/services/merge_requests/cleanup_refs_service_spec.rb
index e8690ae5bf2..960b8101c36 100644
--- a/spec/services/merge_requests/cleanup_refs_service_spec.rb
+++ b/spec/services/merge_requests/cleanup_refs_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::CleanupRefsService do
+RSpec.describe MergeRequests::CleanupRefsService, feature_category: :code_review_workflow do
describe '.schedule' do
let(:merge_request) { create(:merge_request) }
diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb
index 2c0817550c6..25c75ae7244 100644
--- a/spec/services/merge_requests/close_service_spec.rb
+++ b/spec/services/merge_requests/close_service_spec.rb
@@ -88,7 +88,11 @@ RSpec.describe MergeRequests::CloseService, feature_category: :code_review_workf
end
it 'refreshes the number of open merge requests for a valid MR', :use_clean_rails_memory_store_caching do
- expect { execute }
+ expect do
+ execute
+
+ BatchLoader::Executor.clear_current
+ end
.to change { project.open_merge_requests_count }.from(1).to(0)
end
diff --git a/spec/services/merge_requests/conflicts/list_service_spec.rb b/spec/services/merge_requests/conflicts/list_service_spec.rb
index 5132eac0158..5eb53b1bcba 100644
--- a/spec/services/merge_requests/conflicts/list_service_spec.rb
+++ b/spec/services/merge_requests/conflicts/list_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Conflicts::ListService do
+RSpec.describe MergeRequests::Conflicts::ListService, feature_category: :code_review_workflow do
describe '#can_be_resolved_in_ui?' do
def create_merge_request(source_branch, target_branch = 'conflict-start')
create(:merge_request, source_branch: source_branch, target_branch: target_branch, merge_status: :unchecked) do |mr|
diff --git a/spec/services/merge_requests/conflicts/resolve_service_spec.rb b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
index 0abc70f71b0..e11cccaa54a 100644
--- a/spec/services/merge_requests/conflicts/resolve_service_spec.rb
+++ b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Conflicts::ResolveService do
+RSpec.describe MergeRequests::Conflicts::ResolveService, feature_category: :code_review_workflow do
include ProjectForksHelper
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/services/merge_requests/create_approval_event_service_spec.rb b/spec/services/merge_requests/create_approval_event_service_spec.rb
index 3d41ace11a7..4876c992337 100644
--- a/spec/services/merge_requests/create_approval_event_service_spec.rb
+++ b/spec/services/merge_requests/create_approval_event_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::CreateApprovalEventService do
+RSpec.describe MergeRequests::CreateApprovalEventService, feature_category: :code_review_workflow do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
diff --git a/spec/services/merge_requests/create_pipeline_service_spec.rb b/spec/services/merge_requests/create_pipeline_service_spec.rb
index f11e3d0d1df..9c2321a2f16 100644
--- a/spec/services/merge_requests/create_pipeline_service_spec.rb
+++ b/spec/services/merge_requests/create_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::CreatePipelineService, :clean_gitlab_redis_cache do
+RSpec.describe MergeRequests::CreatePipelineService, :clean_gitlab_redis_cache, feature_category: :code_review_workflow do
include ProjectForksHelper
let_it_be(:project, refind: true) { create(:project, :repository) }
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 394fc269ac3..7e20af32985 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -43,8 +43,11 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state, f
end
it 'refreshes the number of open merge requests', :use_clean_rails_memory_store_caching do
- expect { service.execute }
- .to change { project.open_merge_requests_count }.from(0).to(1)
+ expect do
+ service.execute
+
+ BatchLoader::Executor.clear_current
+ end.to change { project.open_merge_requests_count }.from(0).to(1)
end
it 'creates exactly 1 create MR event', :sidekiq_might_not_need_inline do
diff --git a/spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb b/spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb
index d2070a466b1..d9e60911ada 100644
--- a/spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb
+++ b/spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe MergeRequests::DeleteNonLatestDiffsService, :clean_gitlab_redis_shared_state do
+RSpec.describe MergeRequests::DeleteNonLatestDiffsService, :clean_gitlab_redis_shared_state,
+ feature_category: :code_review_workflow do
let(:merge_request) { create(:merge_request) }
let!(:subject) { described_class.new(merge_request) }
diff --git a/spec/services/merge_requests/execute_approval_hooks_service_spec.rb b/spec/services/merge_requests/execute_approval_hooks_service_spec.rb
index 863c47e8191..9f460648b05 100644
--- a/spec/services/merge_requests/execute_approval_hooks_service_spec.rb
+++ b/spec/services/merge_requests/execute_approval_hooks_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ExecuteApprovalHooksService do
+RSpec.describe MergeRequests::ExecuteApprovalHooksService, feature_category: :code_review_workflow do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb
index 5027acbba0a..993b7cfa85b 100644
--- a/spec/services/merge_requests/ff_merge_service_spec.rb
+++ b/spec/services/merge_requests/ff_merge_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::FfMergeService do
+RSpec.describe MergeRequests::FfMergeService, feature_category: :code_review_workflow do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:merge_request) do
diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb
index 5f81e1728fa..31b3e513a51 100644
--- a/spec/services/merge_requests/get_urls_service_spec.rb
+++ b/spec/services/merge_requests/get_urls_service_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe MergeRequests::GetUrlsService do
+RSpec.describe MergeRequests::GetUrlsService, feature_category: :code_review_workflow do
include ProjectForksHelper
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/services/merge_requests/handle_assignees_change_service_spec.rb b/spec/services/merge_requests/handle_assignees_change_service_spec.rb
index 3db3efedb84..951e59afe7f 100644
--- a/spec/services/merge_requests/handle_assignees_change_service_spec.rb
+++ b/spec/services/merge_requests/handle_assignees_change_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::HandleAssigneesChangeService do
+RSpec.describe MergeRequests::HandleAssigneesChangeService, feature_category: :code_review_workflow do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let_it_be(:assignee) { create(:user) }
diff --git a/spec/services/merge_requests/mark_reviewer_reviewed_service_spec.rb b/spec/services/merge_requests/mark_reviewer_reviewed_service_spec.rb
index 8437876c3cf..172c2133168 100644
--- a/spec/services/merge_requests/mark_reviewer_reviewed_service_spec.rb
+++ b/spec/services/merge_requests/mark_reviewer_reviewed_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::MarkReviewerReviewedService do
+RSpec.describe MergeRequests::MarkReviewerReviewedService, feature_category: :code_review_workflow do
let(:current_user) { create(:user) }
let(:merge_request) { create(:merge_request, reviewers: [current_user]) }
let(:reviewer) { merge_request.merge_request_reviewers.find_by(user_id: current_user.id) }
diff --git a/spec/services/merge_requests/merge_orchestration_service_spec.rb b/spec/services/merge_requests/merge_orchestration_service_spec.rb
index ebcd2f0e277..41da7abfeab 100644
--- a/spec/services/merge_requests/merge_orchestration_service_spec.rb
+++ b/spec/services/merge_requests/merge_orchestration_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::MergeOrchestrationService do
+RSpec.describe MergeRequests::MergeOrchestrationService, feature_category: :code_review_workflow do
let_it_be(:maintainer) { create(:user) }
let(:merge_params) { { sha: merge_request.diff_head_sha } }
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index d3bf203d6bb..f380357a659 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::MergeService do
+RSpec.describe MergeRequests::MergeService, feature_category: :code_review_workflow do
include ExclusiveLeaseHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb
index 19fac3b5095..8428848c3c8 100644
--- a/spec/services/merge_requests/merge_to_ref_service_spec.rb
+++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::MergeToRefService do
+RSpec.describe MergeRequests::MergeToRefService, feature_category: :code_review_workflow do
shared_examples_for 'MergeService for target ref' do
it 'target_ref has the same state of target branch' do
repo = merge_request.target_project.repository
diff --git a/spec/services/merge_requests/mergeability/check_base_service_spec.rb b/spec/services/merge_requests/mergeability/check_base_service_spec.rb
index f07522b43cb..806bde61c23 100644
--- a/spec/services/merge_requests/mergeability/check_base_service_spec.rb
+++ b/spec/services/merge_requests/mergeability/check_base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Mergeability::CheckBaseService do
+RSpec.describe MergeRequests::Mergeability::CheckBaseService, feature_category: :code_review_workflow do
subject(:check_base_service) { described_class.new(merge_request: merge_request, params: params) }
let(:merge_request) { double }
diff --git a/spec/services/merge_requests/mergeability/check_broken_status_service_spec.rb b/spec/services/merge_requests/mergeability/check_broken_status_service_spec.rb
index 6cc1079c94a..b6ee1049bb9 100644
--- a/spec/services/merge_requests/mergeability/check_broken_status_service_spec.rb
+++ b/spec/services/merge_requests/mergeability/check_broken_status_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Mergeability::CheckBrokenStatusService do
+RSpec.describe MergeRequests::Mergeability::CheckBrokenStatusService, feature_category: :code_review_workflow do
subject(:check_broken_status) { described_class.new(merge_request: merge_request, params: {}) }
let(:merge_request) { build(:merge_request) }
diff --git a/spec/services/merge_requests/mergeability/check_ci_status_service_spec.rb b/spec/services/merge_requests/mergeability/check_ci_status_service_spec.rb
index def3cb0ca28..cf835cf70a3 100644
--- a/spec/services/merge_requests/mergeability/check_ci_status_service_spec.rb
+++ b/spec/services/merge_requests/mergeability/check_ci_status_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Mergeability::CheckCiStatusService do
+RSpec.describe MergeRequests::Mergeability::CheckCiStatusService, feature_category: :code_review_workflow do
subject(:check_ci_status) { described_class.new(merge_request: merge_request, params: params) }
let(:merge_request) { build(:merge_request) }
diff --git a/spec/services/merge_requests/mergeability/check_discussions_status_service_spec.rb b/spec/services/merge_requests/mergeability/check_discussions_status_service_spec.rb
index 9f107ce046a..a3b77558ec3 100644
--- a/spec/services/merge_requests/mergeability/check_discussions_status_service_spec.rb
+++ b/spec/services/merge_requests/mergeability/check_discussions_status_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Mergeability::CheckDiscussionsStatusService do
+RSpec.describe MergeRequests::Mergeability::CheckDiscussionsStatusService, feature_category: :code_review_workflow do
subject(:check_discussions_status) { described_class.new(merge_request: merge_request, params: params) }
let(:merge_request) { build(:merge_request) }
diff --git a/spec/services/merge_requests/mergeability/check_draft_status_service_spec.rb b/spec/services/merge_requests/mergeability/check_draft_status_service_spec.rb
index e9363e5d676..cb624705a02 100644
--- a/spec/services/merge_requests/mergeability/check_draft_status_service_spec.rb
+++ b/spec/services/merge_requests/mergeability/check_draft_status_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Mergeability::CheckDraftStatusService do
+RSpec.describe MergeRequests::Mergeability::CheckDraftStatusService, feature_category: :code_review_workflow do
subject(:check_draft_status) { described_class.new(merge_request: merge_request, params: {}) }
let(:merge_request) { build(:merge_request) }
diff --git a/spec/services/merge_requests/mergeability/check_open_status_service_spec.rb b/spec/services/merge_requests/mergeability/check_open_status_service_spec.rb
index 936524b020a..53ad77ea4df 100644
--- a/spec/services/merge_requests/mergeability/check_open_status_service_spec.rb
+++ b/spec/services/merge_requests/mergeability/check_open_status_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Mergeability::CheckOpenStatusService do
+RSpec.describe MergeRequests::Mergeability::CheckOpenStatusService, feature_category: :code_review_workflow do
subject(:check_open_status) { described_class.new(merge_request: merge_request, params: {}) }
let(:merge_request) { build(:merge_request) }
diff --git a/spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb b/spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb
index 5722bb79cc5..876b1e7f23a 100644
--- a/spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb
+++ b/spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::MergeRequests::Mergeability::DetailedMergeStatusService do
+RSpec.describe ::MergeRequests::Mergeability::DetailedMergeStatusService, feature_category: :code_review_workflow do
subject(:detailed_merge_status) { described_class.new(merge_request: merge_request).execute }
context 'when merge status is cannot_be_merged_rechecking' do
diff --git a/spec/services/merge_requests/mergeability/logger_spec.rb b/spec/services/merge_requests/mergeability/logger_spec.rb
index 3e2a1e9f9fd..1f56b6bebdb 100644
--- a/spec/services/merge_requests/mergeability/logger_spec.rb
+++ b/spec/services/merge_requests/mergeability/logger_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Mergeability::Logger, :request_store do
+RSpec.describe MergeRequests::Mergeability::Logger, :request_store, feature_category: :code_review_workflow do
let_it_be(:merge_request) { create(:merge_request) }
subject(:logger) { described_class.new(merge_request: merge_request) }
diff --git a/spec/services/merge_requests/mergeability/run_checks_service_spec.rb b/spec/services/merge_requests/mergeability/run_checks_service_spec.rb
index c56b38bccc1..bfff582994b 100644
--- a/spec/services/merge_requests/mergeability/run_checks_service_spec.rb
+++ b/spec/services/merge_requests/mergeability/run_checks_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::Mergeability::RunChecksService, :clean_gitlab_redis_cache do
+RSpec.describe MergeRequests::Mergeability::RunChecksService, :clean_gitlab_redis_cache, feature_category: :code_review_workflow do
subject(:run_checks) { described_class.new(merge_request: merge_request, params: {}) }
describe '#execute' do
diff --git a/spec/services/merge_requests/mergeability_check_service_spec.rb b/spec/services/merge_requests/mergeability_check_service_spec.rb
index ee23238314e..881157e7f11 100644
--- a/spec/services/merge_requests/mergeability_check_service_spec.rb
+++ b/spec/services/merge_requests/mergeability_check_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shared_state do
+RSpec.describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shared_state, feature_category: :code_review_workflow do
shared_examples_for 'unmergeable merge request' do
it 'updates or keeps merge status as cannot_be_merged' do
subject
diff --git a/spec/services/merge_requests/migrate_external_diffs_service_spec.rb b/spec/services/merge_requests/migrate_external_diffs_service_spec.rb
index 6ea8626ba73..c7f78dfa992 100644
--- a/spec/services/merge_requests/migrate_external_diffs_service_spec.rb
+++ b/spec/services/merge_requests/migrate_external_diffs_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::MigrateExternalDiffsService do
+RSpec.describe MergeRequests::MigrateExternalDiffsService, feature_category: :code_review_workflow do
let(:merge_request) { create(:merge_request) }
let(:diff) { merge_request.merge_request_diff }
diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb
index e486daae15e..f7526c169bd 100644
--- a/spec/services/merge_requests/post_merge_service_spec.rb
+++ b/spec/services/merge_requests/post_merge_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::PostMergeService do
+RSpec.describe MergeRequests::PostMergeService, feature_category: :code_review_workflow do
include ProjectForksHelper
let_it_be(:user) { create(:user) }
@@ -23,7 +23,11 @@ RSpec.describe MergeRequests::PostMergeService do
# Cache the counter before the MR changed state.
project.open_merge_requests_count
- expect { subject }.to change { project.open_merge_requests_count }.from(1).to(0)
+ expect do
+ subject
+
+ BatchLoader::Executor.clear_current
+ end.to change { project.open_merge_requests_count }.from(1).to(0)
end
it 'updates metrics' do
diff --git a/spec/services/merge_requests/push_options_handler_service_spec.rb b/spec/services/merge_requests/push_options_handler_service_spec.rb
index 251bf6f0d9d..7ca795ecd1a 100644
--- a/spec/services/merge_requests/push_options_handler_service_spec.rb
+++ b/spec/services/merge_requests/push_options_handler_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::PushOptionsHandlerService do
+RSpec.describe MergeRequests::PushOptionsHandlerService, feature_category: :source_code_management do
include ProjectForksHelper
let_it_be(:parent_group) { create(:group, :public) }
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 0814942b6b7..d8e5eb3bcde 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -109,6 +109,14 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor
expect(@fork_build_failed_todo).to be_done
end
+ it 'triggers mergeRequestMergeStatusUpdated GraphQL subscription conditionally' do
+ expect(GraphqlTriggers).to receive(:merge_request_merge_status_updated).with(@merge_request)
+ expect(GraphqlTriggers).to receive(:merge_request_merge_status_updated).with(@another_merge_request)
+ expect(GraphqlTriggers).not_to receive(:merge_request_merge_status_updated).with(@fork_merge_request)
+
+ refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
+ end
+
context 'when a merge error exists' do
let(:error_message) { 'This is a merge error' }
diff --git a/spec/services/merge_requests/reload_diffs_service_spec.rb b/spec/services/merge_requests/reload_diffs_service_spec.rb
index 3d5b65207e6..4dd05f75a3e 100644
--- a/spec/services/merge_requests/reload_diffs_service_spec.rb
+++ b/spec/services/merge_requests/reload_diffs_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_caching do
+RSpec.describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_caching,
+feature_category: :code_review_workflow do
let(:current_user) { create(:user) }
let(:merge_request) { create(:merge_request) }
let(:subject) { described_class.new(merge_request, current_user) }
diff --git a/spec/services/merge_requests/reload_merge_head_diff_service_spec.rb b/spec/services/merge_requests/reload_merge_head_diff_service_spec.rb
index 20b5cf5e3a1..1c315f12221 100644
--- a/spec/services/merge_requests/reload_merge_head_diff_service_spec.rb
+++ b/spec/services/merge_requests/reload_merge_head_diff_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ReloadMergeHeadDiffService do
+RSpec.describe MergeRequests::ReloadMergeHeadDiffService, feature_category: :code_review_workflow do
let(:merge_request) { create(:merge_request) }
subject { described_class.new(merge_request).execute }
diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb
index b9df31b6727..7399b29d06e 100644
--- a/spec/services/merge_requests/reopen_service_spec.rb
+++ b/spec/services/merge_requests/reopen_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ReopenService do
+RSpec.describe MergeRequests::ReopenService, feature_category: :code_review_workflow do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest) { create(:user) }
@@ -92,7 +92,11 @@ RSpec.describe MergeRequests::ReopenService do
it 'refreshes the number of open merge requests for a valid MR' do
service = described_class.new(project: project, current_user: user)
- expect { service.execute(merge_request) }
+ expect do
+ service.execute(merge_request)
+
+ BatchLoader::Executor.clear_current
+ end
.to change { project.open_merge_requests_count }.from(0).to(1)
end
diff --git a/spec/services/merge_requests/request_review_service_spec.rb b/spec/services/merge_requests/request_review_service_spec.rb
index 1d3f92b083f..ef96bf11e0b 100644
--- a/spec/services/merge_requests/request_review_service_spec.rb
+++ b/spec/services/merge_requests/request_review_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::RequestReviewService do
+RSpec.describe MergeRequests::RequestReviewService, feature_category: :code_review_workflow do
let(:current_user) { create(:user) }
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request, reviewers: [user]) }
diff --git a/spec/services/merge_requests/resolve_todos_service_spec.rb b/spec/services/merge_requests/resolve_todos_service_spec.rb
index 53bd259f0f4..de7ddbea8bb 100644
--- a/spec/services/merge_requests/resolve_todos_service_spec.rb
+++ b/spec/services/merge_requests/resolve_todos_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ResolveTodosService do
+RSpec.describe MergeRequests::ResolveTodosService, feature_category: :code_review_workflow do
let_it_be(:merge_request) { create(:merge_request) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
index 2f191f2ee44..c3a99431dcc 100644
--- a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
+++ b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ResolvedDiscussionNotificationService do
+RSpec.describe MergeRequests::ResolvedDiscussionNotificationService, feature_category: :code_review_workflow do
let(:merge_request) { create(:merge_request) }
let(:user) { create(:user) }
let(:project) { merge_request.project }
diff --git a/spec/services/merge_requests/squash_service_spec.rb b/spec/services/merge_requests/squash_service_spec.rb
index 471bb03f18c..26e225db9fc 100644
--- a/spec/services/merge_requests/squash_service_spec.rb
+++ b/spec/services/merge_requests/squash_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::SquashService do
+RSpec.describe MergeRequests::SquashService, feature_category: :source_code_management do
let(:service) { described_class.new(project: project, current_user: user, params: { merge_request: merge_request }) }
let(:user) { project.first_owner }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/merge_requests/update_assignees_service_spec.rb b/spec/services/merge_requests/update_assignees_service_spec.rb
index 2d80d75a262..7d08eb86441 100644
--- a/spec/services/merge_requests/update_assignees_service_spec.rb
+++ b/spec/services/merge_requests/update_assignees_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::UpdateAssigneesService do
+RSpec.describe MergeRequests::UpdateAssigneesService, feature_category: :code_review_workflow do
include AfterNextHelpers
let_it_be(:group) { create(:group, :public) }
diff --git a/spec/services/merge_requests/update_reviewers_service_spec.rb b/spec/services/merge_requests/update_reviewers_service_spec.rb
index 9f935e1cecf..ed2d448b523 100644
--- a/spec/services/merge_requests/update_reviewers_service_spec.rb
+++ b/spec/services/merge_requests/update_reviewers_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::UpdateReviewersService do
+RSpec.describe MergeRequests::UpdateReviewersService, feature_category: :code_review_workflow do
include AfterNextHelpers
let_it_be(:group) { create(:group, :public) }
diff --git a/spec/services/metrics/dashboard/annotations/create_service_spec.rb b/spec/services/metrics/dashboard/annotations/create_service_spec.rb
index 8f5484fcabe..2bcfa54ead7 100644
--- a/spec/services/metrics/dashboard/annotations/create_service_spec.rb
+++ b/spec/services/metrics/dashboard/annotations/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::Annotations::CreateService do
+RSpec.describe Metrics::Dashboard::Annotations::CreateService, feature_category: :metrics do
let_it_be(:user) { create(:user) }
let(:description) { 'test annotation' }
diff --git a/spec/services/metrics/dashboard/annotations/delete_service_spec.rb b/spec/services/metrics/dashboard/annotations/delete_service_spec.rb
index ec2bd3772bf..557d6d95767 100644
--- a/spec/services/metrics/dashboard/annotations/delete_service_spec.rb
+++ b/spec/services/metrics/dashboard/annotations/delete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::Annotations::DeleteService do
+RSpec.describe Metrics::Dashboard::Annotations::DeleteService, feature_category: :metrics do
let(:user) { create(:user) }
let(:service_instance) { described_class.new(user, annotation) }
diff --git a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb
index 47e5557105b..40ec37c393d 100644
--- a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_store_caching, feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb b/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb
index f2e32d5eb35..beed23a366f 100644
--- a/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::ClusterDashboardService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::ClusterDashboardService, :use_clean_rails_memory_store_caching,
+ feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb b/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb
index dbb89af45d0..5d63505e5cc 100644
--- a/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::ClusterMetricsEmbedService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::ClusterMetricsEmbedService, :use_clean_rails_memory_store_caching,
+ feature_category: :metrics do
include MetricsDashboardHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb b/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb
index afeb1646005..940daa38ae7 100644
--- a/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::CustomDashboardService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::CustomDashboardService, :use_clean_rails_memory_store_caching,
+ feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb
index 127cec6275c..8117296b048 100644
--- a/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::CustomMetricEmbedService do
+RSpec.describe Metrics::Dashboard::CustomMetricEmbedService, feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:project, reload: true) { build(:project) }
diff --git a/spec/services/metrics/dashboard/default_embed_service_spec.rb b/spec/services/metrics/dashboard/default_embed_service_spec.rb
index 647778eadc1..6ef248f6b09 100644
--- a/spec/services/metrics/dashboard/default_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/default_embed_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::DefaultEmbedService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::DefaultEmbedService, :use_clean_rails_memory_store_caching,
+ feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:project) { build(:project) }
diff --git a/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb b/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb
index 5eb8f24266c..1643f552a70 100644
--- a/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::DynamicEmbedService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::DynamicEmbedService, :use_clean_rails_memory_store_caching,
+ feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:project) { build(:project) }
diff --git a/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb b/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb
index 2905e4599f3..25812a492b2 100644
--- a/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::GitlabAlertEmbedService do
+RSpec.describe Metrics::Dashboard::GitlabAlertEmbedService, feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:alert) { create(:prometheus_alert) }
diff --git a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
index 5263fd40a40..877a455ea44 100644
--- a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::GrafanaMetricEmbedService do
+RSpec.describe Metrics::Dashboard::GrafanaMetricEmbedService, feature_category: :metrics do
include MetricsDashboardHelpers
include ReactiveCachingHelpers
include GrafanaApiHelpers
diff --git a/spec/services/metrics/dashboard/panel_preview_service_spec.rb b/spec/services/metrics/dashboard/panel_preview_service_spec.rb
index 787c61cc918..2a70c667ee5 100644
--- a/spec/services/metrics/dashboard/panel_preview_service_spec.rb
+++ b/spec/services/metrics/dashboard/panel_preview_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::PanelPreviewService do
+RSpec.describe Metrics::Dashboard::PanelPreviewService, feature_category: :metrics do
let_it_be(:project) { create(:project) }
let_it_be(:environment) { create(:environment, project: project) }
let_it_be(:panel_yml) do
diff --git a/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb b/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb
index 0ea812e93ee..d26b27d7a18 100644
--- a/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::PodDashboardService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::PodDashboardService, :use_clean_rails_memory_store_caching,
+ feature_category: :pods do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb b/spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb
index d0cefdbeb30..930789ed701 100644
--- a/spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::SelfMonitoringDashboardService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::SelfMonitoringDashboardService, :use_clean_rails_memory_store_caching,
+ feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/metrics/dashboard/system_dashboard_service_spec.rb b/spec/services/metrics/dashboard/system_dashboard_service_spec.rb
index e1c6aaeec66..b08b980e50e 100644
--- a/spec/services/metrics/dashboard/system_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/system_dashboard_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_store_caching,
+ feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/metrics/dashboard/transient_embed_service_spec.rb b/spec/services/metrics/dashboard/transient_embed_service_spec.rb
index 53ea83c33d6..1e3ccde6ae3 100644
--- a/spec/services/metrics/dashboard/transient_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/transient_embed_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::TransientEmbedService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::TransientEmbedService, :use_clean_rails_memory_store_caching,
+ feature_category: :metrics do
let_it_be(:project) { build(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:environment) { create(:environment, project: project) }
diff --git a/spec/services/metrics/dashboard/update_dashboard_service_spec.rb b/spec/services/metrics/dashboard/update_dashboard_service_spec.rb
index 148005480ea..15bbe9f9364 100644
--- a/spec/services/metrics/dashboard/update_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/update_dashboard_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::UpdateDashboardService, :use_clean_rails_memory_store_caching do
+RSpec.describe Metrics::Dashboard::UpdateDashboardService, :use_clean_rails_memory_store_caching, feature_category: :metrics do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/services/metrics/sample_metrics_service_spec.rb b/spec/services/metrics/sample_metrics_service_spec.rb
index b94345500f0..3442b4303db 100644
--- a/spec/services/metrics/sample_metrics_service_spec.rb
+++ b/spec/services/metrics/sample_metrics_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::SampleMetricsService do
+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' }
diff --git a/spec/services/metrics/users_starred_dashboards/create_service_spec.rb b/spec/services/metrics/users_starred_dashboards/create_service_spec.rb
index 1435e39e458..e08bdca8410 100644
--- a/spec/services/metrics/users_starred_dashboards/create_service_spec.rb
+++ b/spec/services/metrics/users_starred_dashboards/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::UsersStarredDashboards::CreateService do
+RSpec.describe Metrics::UsersStarredDashboards::CreateService, feature_category: :metrics do
let_it_be(:user) { create(:user) }
let(:dashboard_path) { 'config/prometheus/common_metrics.yml' }
diff --git a/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb b/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb
index 5cdffe681eb..8c4bcecc239 100644
--- a/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb
+++ b/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::UsersStarredDashboards::DeleteService do
+RSpec.describe Metrics::UsersStarredDashboards::DeleteService, feature_category: :metrics do
subject(:service_instance) { described_class.new(user, project, dashboard_path) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb
index 53751b40667..f362c8da642 100644
--- a/spec/services/milestones/close_service_spec.rb
+++ b/spec/services/milestones/close_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Milestones::CloseService do
+RSpec.describe Milestones::CloseService, feature_category: :team_planning do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) }
diff --git a/spec/services/milestones/closed_issues_count_service_spec.rb b/spec/services/milestones/closed_issues_count_service_spec.rb
index a3865d08972..f0ed0872c2d 100644
--- a/spec/services/milestones/closed_issues_count_service_spec.rb
+++ b/spec/services/milestones/closed_issues_count_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Milestones::ClosedIssuesCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Milestones::ClosedIssuesCountService, :use_clean_rails_memory_store_caching,
+ feature_category: :team_planning do
let(:project) { create(:project) }
let(:milestone) { create(:milestone, project: project) }
diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb
index 93ca4ff653f..78cb05532eb 100644
--- a/spec/services/milestones/create_service_spec.rb
+++ b/spec/services/milestones/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Milestones::CreateService do
+RSpec.describe Milestones::CreateService, feature_category: :team_planning do
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb
index 6c08b7db43a..209177c348b 100644
--- a/spec/services/milestones/destroy_service_spec.rb
+++ b/spec/services/milestones/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Milestones::DestroyService do
+RSpec.describe Milestones::DestroyService, feature_category: :team_planning do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:milestone) { create(:milestone, title: 'Milestone v1.0', project: project) }
diff --git a/spec/services/milestones/find_or_create_service_spec.rb b/spec/services/milestones/find_or_create_service_spec.rb
index 1bcaf578441..8a72778a22a 100644
--- a/spec/services/milestones/find_or_create_service_spec.rb
+++ b/spec/services/milestones/find_or_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Milestones::FindOrCreateService do
+RSpec.describe Milestones::FindOrCreateService, feature_category: :team_planning do
describe '#execute' do
subject(:service) { described_class.new(project, user, params) }
diff --git a/spec/services/milestones/issues_count_service_spec.rb b/spec/services/milestones/issues_count_service_spec.rb
index c944055e4e7..a80b27822b6 100644
--- a/spec/services/milestones/issues_count_service_spec.rb
+++ b/spec/services/milestones/issues_count_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Milestones::IssuesCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Milestones::IssuesCountService, :use_clean_rails_memory_store_caching,
+ feature_category: :team_planning do
let(:project) { create(:project) }
let(:milestone) { create(:milestone, project: project) }
diff --git a/spec/services/milestones/merge_requests_count_service_spec.rb b/spec/services/milestones/merge_requests_count_service_spec.rb
index aecc7d5ef52..00b7b95aeb6 100644
--- a/spec/services/milestones/merge_requests_count_service_spec.rb
+++ b/spec/services/milestones/merge_requests_count_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Milestones::MergeRequestsCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Milestones::MergeRequestsCountService, :use_clean_rails_memory_store_caching,
+ feature_category: :team_planning do
let_it_be(:project) { create(:project, :empty_repo) }
let_it_be(:milestone) { create(:milestone, project: project) }
diff --git a/spec/services/milestones/promote_service_spec.rb b/spec/services/milestones/promote_service_spec.rb
index 8f4201d8d94..203ac2d3f40 100644
--- a/spec/services/milestones/promote_service_spec.rb
+++ b/spec/services/milestones/promote_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Milestones::PromoteService do
+RSpec.describe Milestones::PromoteService, feature_category: :team_planning do
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
let(:user) { create(:user) }
diff --git a/spec/services/milestones/transfer_service_spec.rb b/spec/services/milestones/transfer_service_spec.rb
index de02226661c..ea65f713902 100644
--- a/spec/services/milestones/transfer_service_spec.rb
+++ b/spec/services/milestones/transfer_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Milestones::TransferService do
+RSpec.describe Milestones::TransferService, feature_category: :team_planning do
describe '#execute' do
subject(:service) { described_class.new(user, old_group, project) }
diff --git a/spec/services/milestones/update_service_spec.rb b/spec/services/milestones/update_service_spec.rb
index 85fd89c11ac..76110af2514 100644
--- a/spec/services/milestones/update_service_spec.rb
+++ b/spec/services/milestones/update_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Milestones::UpdateService do
+RSpec.describe Milestones::UpdateService, feature_category: :team_planning do
let(:project) { create(:project) }
let(:user) { build(:user) }
let(:milestone) { create(:milestone, project: project) }
diff --git a/spec/services/ml/experiment_tracking/candidate_repository_spec.rb b/spec/services/ml/experiment_tracking/candidate_repository_spec.rb
index e3c05178025..45a4792426c 100644
--- a/spec/services/ml/experiment_tracking/candidate_repository_spec.rb
+++ b/spec/services/ml/experiment_tracking/candidate_repository_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ml::ExperimentTracking::CandidateRepository do
+RSpec.describe ::Ml::ExperimentTracking::CandidateRepository, feature_category: :experimentation_activation do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:experiment) { create(:ml_experiments, user: user, project: project) }
diff --git a/spec/services/ml/experiment_tracking/experiment_repository_spec.rb b/spec/services/ml/experiment_tracking/experiment_repository_spec.rb
index c3c716b831a..3c645fa84b4 100644
--- a/spec/services/ml/experiment_tracking/experiment_repository_spec.rb
+++ b/spec/services/ml/experiment_tracking/experiment_repository_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ml::ExperimentTracking::ExperimentRepository do
+RSpec.describe ::Ml::ExperimentTracking::ExperimentRepository, feature_category: :experimentation_activation do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:experiment) { create(:ml_experiments, user: user, project: project) }
diff --git a/spec/services/namespace_settings/update_service_spec.rb b/spec/services/namespace_settings/update_service_spec.rb
index e0f32cb3821..5f1ff6746bc 100644
--- a/spec/services/namespace_settings/update_service_spec.rb
+++ b/spec/services/namespace_settings/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe NamespaceSettings::UpdateService do
+RSpec.describe NamespaceSettings::UpdateService, feature_category: :subgroups do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:settings) { {} }
diff --git a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
index b44c256802f..8a2ecd5c3e0 100644
--- a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
+++ b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::InProductMarketingEmailsService, '#execute' do
+RSpec.describe Namespaces::InProductMarketingEmailsService, '#execute', feature_category: :purchase do
subject(:execute_service) { described_class.new(track, interval).execute }
let(:track) { :create }
diff --git a/spec/services/namespaces/package_settings/update_service_spec.rb b/spec/services/namespaces/package_settings/update_service_spec.rb
index 10926c5ef57..e21c9a8f1b9 100644
--- a/spec/services/namespaces/package_settings/update_service_spec.rb
+++ b/spec/services/namespaces/package_settings/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Namespaces::PackageSettings::UpdateService do
+RSpec.describe ::Namespaces::PackageSettings::UpdateService, feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
let_it_be_with_reload(:namespace) { create(:group) }
diff --git a/spec/services/namespaces/statistics_refresher_service_spec.rb b/spec/services/namespaces/statistics_refresher_service_spec.rb
index 2d5f9235bd4..750f98615cc 100644
--- a/spec/services/namespaces/statistics_refresher_service_spec.rb
+++ b/spec/services/namespaces/statistics_refresher_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::StatisticsRefresherService, '#execute' do
+RSpec.describe Namespaces::StatisticsRefresherService, '#execute', feature_category: :subgroups do
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
let(:projects) { create_list(:project, 5, namespace: group) }
diff --git a/spec/services/note_summary_spec.rb b/spec/services/note_summary_spec.rb
index ad244f62292..1cbbb68205d 100644
--- a/spec/services/note_summary_spec.rb
+++ b/spec/services/note_summary_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe NoteSummary do
+RSpec.describe NoteSummary, feature_category: :code_review_workflow do
let(:project) { build(:project) }
let(:noteable) { build(:issue) }
let(:user) { build(:user) }
diff --git a/spec/services/notes/build_service_spec.rb b/spec/services/notes/build_service_spec.rb
index 67d8b37f809..97c736e373b 100644
--- a/spec/services/notes/build_service_spec.rb
+++ b/spec/services/notes/build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::BuildService do
+RSpec.describe Notes::BuildService, feature_category: :team_planning do
include AdminModeHelper
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/services/notes/copy_service_spec.rb b/spec/services/notes/copy_service_spec.rb
index 2fa9a462bb9..5a48f6e7560 100644
--- a/spec/services/notes/copy_service_spec.rb
+++ b/spec/services/notes/copy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::CopyService do
+RSpec.describe Notes::CopyService, feature_category: :team_planning do
describe '#initialize' do
let_it_be(:noteable) { create(:issue) }
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 1ee9e51433e..05a41ddc6c5 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -108,7 +108,6 @@ RSpec.describe Notes::CreateService, feature_category: :team_planning do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { issue.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_comment' }
@@ -124,10 +123,6 @@ RSpec.describe Notes::CreateService, feature_category: :team_planning do
let(:execute_create_service) { described_class.new(project, user, opts).execute }
- before do
- stub_feature_flags(notes_create_service_tracking: false)
- end
-
it 'tracks commit comment usage data', :clean_gitlab_redis_shared_state do
expect(counter).to receive(:count).with(:create, 'Commit').and_call_original
diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb
index 744808525f5..43132b4221f 100644
--- a/spec/services/notes/destroy_service_spec.rb
+++ b/spec/services/notes/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::DestroyService do
+RSpec.describe Notes::DestroyService, feature_category: :team_planning do
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb
index 17001733c5b..0bcfd6b63d2 100644
--- a/spec/services/notes/post_process_service_spec.rb
+++ b/spec/services/notes/post_process_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::PostProcessService do
+RSpec.describe Notes::PostProcessService, feature_category: :team_planning do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb
index bca954c3959..b474285e67e 100644
--- a/spec/services/notes/quick_actions_service_spec.rb
+++ b/spec/services/notes/quick_actions_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::QuickActionsService do
+RSpec.describe Notes::QuickActionsService, feature_category: :team_planning do
shared_context 'note on noteable' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } }
@@ -253,6 +253,12 @@ RSpec.describe Notes::QuickActionsService do
describe '.noteable_update_service_class' do
include_context 'note on noteable'
+ it 'returns WorkItems::UpdateService for a note on a work item' do
+ note = create(:note_on_work_item, project: project)
+
+ expect(described_class.noteable_update_service_class(note)).to eq(WorkItems::UpdateService)
+ end
+
it 'returns Issues::UpdateService for a note on an issue' do
note = create(:note_on_issue, project: project)
@@ -322,6 +328,84 @@ RSpec.describe Notes::QuickActionsService do
let(:merge_request) { create(:merge_request, source_project: project) }
let(:note) { build(:note_on_merge_request, project: project, noteable: merge_request) }
end
+
+ context 'note on work item that supports quick actions' do
+ include_context 'note on noteable'
+
+ let_it_be(:work_item, reload: true) { create(:work_item, project: project) }
+
+ let(:note) { build(:note_on_work_item, project: project, noteable: work_item) }
+
+ let!(:labels) { create_pair(:label, project: project) }
+
+ before do
+ note.note = note_text
+ end
+
+ describe 'note with only command' do
+ describe '/close, /label & /assign' do
+ let(:note_text) do
+ %(/close\n/label ~#{labels.first.name} ~#{labels.last.name}\n/assign @#{assignee.username}\n)
+ end
+
+ it 'closes noteable, sets labels, assigns and leave no note' do
+ content = execute(note)
+
+ expect(content).to be_empty
+ expect(note.noteable).to be_closed
+ expect(note.noteable.labels).to match_array(labels)
+ expect(note.noteable.assignees).to eq([assignee])
+ end
+ end
+
+ describe '/reopen' do
+ before do
+ note.noteable.close!
+ expect(note.noteable).to be_closed
+ end
+ let(:note_text) { '/reopen' }
+
+ it 'opens the noteable, and leave no note' do
+ content = execute(note)
+
+ expect(content).to be_empty
+ expect(note.noteable).to be_open
+ end
+ end
+ end
+
+ describe 'note with command & text' do
+ describe '/close, /label, /assign' do
+ let(:note_text) do
+ %(HELLO\n/close\n/label ~#{labels.first.name} ~#{labels.last.name}\n/assign @#{assignee.username}\nWORLD)
+ end
+
+ it 'closes noteable, sets labels, assigns, and sets milestone to noteable' do
+ content = execute(note)
+
+ expect(content).to eq "HELLO\nWORLD"
+ expect(note.noteable).to be_closed
+ expect(note.noteable.labels).to match_array(labels)
+ expect(note.noteable.assignees).to eq([assignee])
+ end
+ end
+
+ describe '/reopen' do
+ before do
+ note.noteable.close
+ expect(note.noteable).to be_closed
+ end
+ let(:note_text) { "HELLO\n/reopen\nWORLD" }
+
+ it 'opens the noteable' do
+ content = execute(note)
+
+ expect(content).to eq "HELLO\nWORLD"
+ expect(note.noteable).to be_open
+ end
+ end
+ end
+ end
end
context 'CE restriction for issue assignees' do
diff --git a/spec/services/notes/render_service_spec.rb b/spec/services/notes/render_service_spec.rb
index 09cd7dc572b..8ebecddffa7 100644
--- a/spec/services/notes/render_service_spec.rb
+++ b/spec/services/notes/render_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::RenderService do
+RSpec.describe Notes::RenderService, feature_category: :team_planning do
describe '#execute' do
it 'renders a Note' do
note = double(:note)
diff --git a/spec/services/notes/resolve_service_spec.rb b/spec/services/notes/resolve_service_spec.rb
index 1c5b308aed1..1b5586ee1b3 100644
--- a/spec/services/notes/resolve_service_spec.rb
+++ b/spec/services/notes/resolve_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::ResolveService do
+RSpec.describe Notes::ResolveService, feature_category: :team_planning do
let(:merge_request) { create(:merge_request) }
let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: merge_request.project) }
let(:user) { merge_request.author }
diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb
index 05703ac548d..0d5a0ae7706 100644
--- a/spec/services/notes/update_service_spec.rb
+++ b/spec/services/notes/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::UpdateService do
+RSpec.describe Notes::UpdateService, feature_category: :team_planning do
let(:group) { create(:group, :public) }
let(:project) { create(:project, :public, group: group) }
let(:private_group) { create(:group, :private) }
diff --git a/spec/services/notification_recipients/build_service_spec.rb b/spec/services/notification_recipients/build_service_spec.rb
index 899d23ec641..bfd1dcd7d80 100644
--- a/spec/services/notification_recipients/build_service_spec.rb
+++ b/spec/services/notification_recipients/build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe NotificationRecipients::BuildService do
+RSpec.describe NotificationRecipients::BuildService, feature_category: :team_planning do
let(:service) { described_class }
let(:assignee) { create(:user) }
let(:project) { create(:project, :public) }
diff --git a/spec/services/notification_recipients/builder/default_spec.rb b/spec/services/notification_recipients/builder/default_spec.rb
index 4d0ddc7c4f7..da991b5951a 100644
--- a/spec/services/notification_recipients/builder/default_spec.rb
+++ b/spec/services/notification_recipients/builder/default_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe NotificationRecipients::Builder::Default do
+RSpec.describe NotificationRecipients::Builder::Default, feature_category: :team_planning do
describe '#build!' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, group: group).tap { |p| p.add_developer(project_watcher) if project_watcher } }
diff --git a/spec/services/notification_recipients/builder/new_note_spec.rb b/spec/services/notification_recipients/builder/new_note_spec.rb
index 7d2a4f682c5..e87824f3156 100644
--- a/spec/services/notification_recipients/builder/new_note_spec.rb
+++ b/spec/services/notification_recipients/builder/new_note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe NotificationRecipients::Builder::NewNote do
+RSpec.describe NotificationRecipients::Builder::NewNote, feature_category: :team_planning do
describe '#notification_recipients' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, group: group) }
diff --git a/spec/services/onboarding/progress_service_spec.rb b/spec/services/onboarding/progress_service_spec.rb
index 8f3f723613e..e1d6b4cd44b 100644
--- a/spec/services/onboarding/progress_service_spec.rb
+++ b/spec/services/onboarding/progress_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Onboarding::ProgressService do
+RSpec.describe Onboarding::ProgressService, feature_category: :onboarding do
describe '.async' do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:action) { :git_pull }
diff --git a/spec/services/packages/cleanup/execute_policy_service_spec.rb b/spec/services/packages/cleanup/execute_policy_service_spec.rb
index 93335c4a821..a083dc0d4ea 100644
--- a/spec/services/packages/cleanup/execute_policy_service_spec.rb
+++ b/spec/services/packages/cleanup/execute_policy_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Cleanup::ExecutePolicyService do
+RSpec.describe Packages::Cleanup::ExecutePolicyService, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be_with_reload(:policy) { create(:packages_cleanup_policy, project: project) }
diff --git a/spec/services/packages/cleanup/update_policy_service_spec.rb b/spec/services/packages/cleanup/update_policy_service_spec.rb
index a11fbb766f5..8068c351e5f 100644
--- a/spec/services/packages/cleanup/update_policy_service_spec.rb
+++ b/spec/services/packages/cleanup/update_policy_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Cleanup::UpdatePolicyService do
+RSpec.describe Packages::Cleanup::UpdatePolicyService, feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
let_it_be_with_reload(:project) { create(:project) }
diff --git a/spec/services/packages/composer/composer_json_service_spec.rb b/spec/services/packages/composer/composer_json_service_spec.rb
index d2187688c4c..15acd79c49e 100644
--- a/spec/services/packages/composer/composer_json_service_spec.rb
+++ b/spec/services/packages/composer/composer_json_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Composer::ComposerJsonService do
+RSpec.describe Packages::Composer::ComposerJsonService, feature_category: :package_registry do
describe '#execute' do
let(:branch) { project.repository.find_branch('master') }
let(:target) { branch.target }
diff --git a/spec/services/packages/composer/create_package_service_spec.rb b/spec/services/packages/composer/create_package_service_spec.rb
index 26429a7b5d9..78d5d76fe4f 100644
--- a/spec/services/packages/composer/create_package_service_spec.rb
+++ b/spec/services/packages/composer/create_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Composer::CreatePackageService do
+RSpec.describe Packages::Composer::CreatePackageService, feature_category: :package_registry do
include PackagesManagerApiSpecHelpers
let_it_be(:package_name) { 'composer-package-name' }
diff --git a/spec/services/packages/composer/version_parser_service_spec.rb b/spec/services/packages/composer/version_parser_service_spec.rb
index 69253ff934e..ac50f2e2e55 100644
--- a/spec/services/packages/composer/version_parser_service_spec.rb
+++ b/spec/services/packages/composer/version_parser_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Composer::VersionParserService do
+RSpec.describe Packages::Composer::VersionParserService, feature_category: :package_registry do
let_it_be(:params) { {} }
describe '#execute' do
diff --git a/spec/services/packages/conan/create_package_file_service_spec.rb b/spec/services/packages/conan/create_package_file_service_spec.rb
index e655b8d1f9e..6859e52560a 100644
--- a/spec/services/packages/conan/create_package_file_service_spec.rb
+++ b/spec/services/packages/conan/create_package_file_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Conan::CreatePackageFileService do
+RSpec.describe Packages::Conan::CreatePackageFileService, feature_category: :package_registry do
include WorkhorseHelpers
let_it_be(:package) { create(:conan_package) }
diff --git a/spec/services/packages/conan/create_package_service_spec.rb b/spec/services/packages/conan/create_package_service_spec.rb
index 6f644f5ef95..db06463b7fa 100644
--- a/spec/services/packages/conan/create_package_service_spec.rb
+++ b/spec/services/packages/conan/create_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Conan::CreatePackageService do
+RSpec.describe Packages::Conan::CreatePackageService, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/packages/create_dependency_service_spec.rb b/spec/services/packages/create_dependency_service_spec.rb
index f95e21cd045..06a7a13bdd9 100644
--- a/spec/services/packages/create_dependency_service_spec.rb
+++ b/spec/services/packages/create_dependency_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::CreateDependencyService do
+RSpec.describe Packages::CreateDependencyService, feature_category: :package_registry do
describe '#execute' do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:version) { '1.0.1' }
diff --git a/spec/services/packages/create_event_service_spec.rb b/spec/services/packages/create_event_service_spec.rb
index 58fa68b11fe..44ad3f29c58 100644
--- a/spec/services/packages/create_event_service_spec.rb
+++ b/spec/services/packages/create_event_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::CreateEventService do
+RSpec.describe Packages::CreateEventService, feature_category: :package_registry do
let(:scope) { 'generic' }
let(:event_name) { 'push_package' }
diff --git a/spec/services/packages/create_package_file_service_spec.rb b/spec/services/packages/create_package_file_service_spec.rb
index 2ff00ea8568..5b4ea3e1530 100644
--- a/spec/services/packages/create_package_file_service_spec.rb
+++ b/spec/services/packages/create_package_file_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::CreatePackageFileService do
+RSpec.describe Packages::CreatePackageFileService, feature_category: :package_registry do
let_it_be(:package) { create(:maven_package) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/packages/create_temporary_package_service_spec.rb b/spec/services/packages/create_temporary_package_service_spec.rb
index 4b8d37401d8..be8b5afc1e0 100644
--- a/spec/services/packages/create_temporary_package_service_spec.rb
+++ b/spec/services/packages/create_temporary_package_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::CreateTemporaryPackageService do
+RSpec.describe Packages::CreateTemporaryPackageService, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:params) { {} }
diff --git a/spec/services/packages/debian/create_package_file_service_spec.rb b/spec/services/packages/debian/create_package_file_service_spec.rb
index 43928669eb1..b527bf8c1de 100644
--- a/spec/services/packages/debian/create_package_file_service_spec.rb
+++ b/spec/services/packages/debian/create_package_file_service_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe Packages::Debian::CreatePackageFileService, feature_category: :pa
expect(package_file).to be_valid
expect(package_file.file.read).to start_with('Format: 1.8')
- expect(package_file.size).to eq(2143)
+ expect(package_file.size).to eq(2422)
expect(package_file.file_name).to eq(file_name)
expect(package_file.file_sha1).to eq('54321')
expect(package_file.file_sha256).to eq('543212345')
diff --git a/spec/services/packages/debian/extract_changes_metadata_service_spec.rb b/spec/services/packages/debian/extract_changes_metadata_service_spec.rb
index 4d6acac219b..a22c1fc7acc 100644
--- a/spec/services/packages/debian/extract_changes_metadata_service_spec.rb
+++ b/spec/services/packages/debian/extract_changes_metadata_service_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Packages::Debian::ExtractChangesMetadataService, feature_category
expect(subject[:file_type]).to eq(:changes)
expect(subject[:architecture]).to be_nil
expect(subject[:fields]).to include(expected_fields)
- expect(subject[:files].count).to eq(6)
+ expect(subject[:files].count).to eq(7)
end
end
diff --git a/spec/services/packages/debian/extract_metadata_service_spec.rb b/spec/services/packages/debian/extract_metadata_service_spec.rb
index 412f285152b..1983c49c6b7 100644
--- a/spec/services/packages/debian/extract_metadata_service_spec.rb
+++ b/spec/services/packages/debian/extract_metadata_service_spec.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+
require 'spec_helper'
RSpec.describe Packages::Debian::ExtractMetadataService, feature_category: :package_registry do
@@ -6,12 +7,13 @@ RSpec.describe Packages::Debian::ExtractMetadataService, feature_category: :pack
subject { service.execute }
- RSpec.shared_context 'Debian ExtractMetadata Service' do |trait|
+ RSpec.shared_context 'with Debian package file' do |trait|
let(:package_file) { create(:debian_package_file, trait) }
end
RSpec.shared_examples 'Test Debian ExtractMetadata Service' do |expected_file_type, expected_architecture, expected_fields|
- it "returns file_type #{expected_file_type.inspect}, architecture #{expected_architecture.inspect} and fields #{expected_fields.nil? ? '' : 'including '}#{expected_fields.inspect}", :aggregate_failures do
+ it "returns file_type #{expected_file_type.inspect}, architecture #{expected_architecture.inspect} and fields #{expected_fields.nil? ? '' : 'including '}#{expected_fields.inspect}",
+ :aggregate_failures do
expect(subject[:file_type]).to eq(expected_file_type)
expect(subject[:architecture]).to eq(expected_architecture)
@@ -25,29 +27,79 @@ RSpec.describe Packages::Debian::ExtractMetadataService, feature_category: :pack
using RSpec::Parameterized::TableSyntax
- where(:case_name, :trait, :expected_file_type, :expected_architecture, :expected_fields) do
- 'with invalid' | :invalid | :unknown | nil | nil
- 'with source' | :source | :source | nil | nil
- 'with dsc' | :dsc | :dsc | nil | { 'Binary' => 'sample-dev, libsample0, sample-udeb' }
- 'with deb' | :deb | :deb | 'amd64' | { 'Multi-Arch' => 'same' }
- 'with udeb' | :udeb | :udeb | 'amd64' | { 'Package' => 'sample-udeb' }
- 'with buildinfo' | :buildinfo | :buildinfo | nil | { 'Architecture' => 'amd64 source', 'Build-Architecture' => 'amd64' }
- 'with changes' | :changes | :changes | nil | { 'Architecture' => 'source amd64', 'Binary' => 'libsample0 sample-dev sample-udeb' }
+ context 'with valid file types' do
+ where(:case_name, :trait, :expected_file_type, :expected_architecture, :expected_fields) do
+ 'with source' | :source | :source | nil | nil
+ 'with dsc' | :dsc | :dsc | nil | { 'Binary' => 'sample-dev, libsample0, sample-udeb, sample-ddeb' }
+ 'with deb' | :deb | :deb | 'amd64' | { 'Multi-Arch' => 'same' }
+ 'with udeb' | :udeb | :udeb | 'amd64' | { 'Package' => 'sample-udeb' }
+ 'with ddeb' | :ddeb | :ddeb | 'amd64' | { 'Package' => 'sample-ddeb' }
+ 'with buildinfo' | :buildinfo | :buildinfo | nil | { 'Architecture' => 'amd64 source',
+ 'Build-Architecture' => 'amd64' }
+ 'with changes' | :changes | :changes | nil | { 'Architecture' => 'source amd64',
+ 'Binary' => 'libsample0 sample-dev sample-udeb' }
+ end
+
+ with_them do
+ include_context 'with Debian package file', params[:trait] do
+ it_behaves_like 'Test Debian ExtractMetadata Service',
+ params[:expected_file_type],
+ params[:expected_architecture],
+ params[:expected_fields]
+ end
+ end
end
- with_them do
- include_context 'Debian ExtractMetadata Service', params[:trait] do
- it_behaves_like 'Test Debian ExtractMetadata Service',
- params[:expected_file_type],
- params[:expected_architecture],
- params[:expected_fields]
+ context 'with valid source extensions' do
+ where(:ext) do
+ %i[gz bz2 lzma xz]
+ end
+
+ with_them do
+ let(:package_file) do
+ create(:debian_package_file, :source, file_name: "myfile.tar.#{ext}",
+ file_fixture: 'spec/fixtures/packages/debian/sample_1.2.3~alpha2.tar.xz')
+ end
+
+ it_behaves_like 'Test Debian ExtractMetadata Service', :source
+ end
+ end
+
+ context 'with invalid source extensions' do
+ where(:ext) do
+ %i[gzip bzip2]
+ end
+
+ with_them do
+ let(:package_file) do
+ create(:debian_package_file, :source, file_name: "myfile.tar.#{ext}",
+ file_fixture: 'spec/fixtures/packages/debian/sample_1.2.3~alpha2.tar.xz')
+ end
+
+ it 'raises an error' do
+ expect do
+ subject
+ end.to raise_error(described_class::ExtractionError,
+ "unsupported file extension for file #{package_file.file_name}")
+ end
+ end
+ end
+
+ context 'with invalid file name' do
+ let(:package_file) { create(:debian_package_file, :invalid) }
+
+ it 'raises an error' do
+ expect do
+ subject
+ end.to raise_error(described_class::ExtractionError,
+ "unsupported file extension for file #{package_file.file_name}")
end
end
context 'with invalid package file' do
let(:package_file) { create(:conan_package_file) }
- it 'raise error' do
+ it 'raises an error' do
expect { subject }.to raise_error(described_class::ExtractionError, 'invalid package file')
end
end
diff --git a/spec/services/packages/debian/generate_distribution_service_spec.rb b/spec/services/packages/debian/generate_distribution_service_spec.rb
index 6d179c791a3..27206b847e4 100644
--- a/spec/services/packages/debian/generate_distribution_service_spec.rb
+++ b/spec/services/packages/debian/generate_distribution_service_spec.rb
@@ -3,20 +3,32 @@
require 'spec_helper'
RSpec.describe Packages::Debian::GenerateDistributionService, feature_category: :package_registry do
- describe '#execute' do
- subject { described_class.new(distribution).execute }
+ include_context 'with published Debian package'
- let(:subject2) { described_class.new(distribution).execute }
- let(:subject3) { described_class.new(distribution).execute }
+ let(:service) { described_class.new(distribution) }
- include_context 'with published Debian package'
+ [:project, :group].each do |container_type|
+ context "for #{container_type}" do
+ include_context 'with Debian distribution', container_type
- [:project, :group].each do |container_type|
- context "for #{container_type}" do
- include_context 'with Debian distribution', container_type
+ describe '#execute' do
+ subject { service.execute }
+
+ let(:subject2) { described_class.new(distribution).execute }
+ let(:subject3) { described_class.new(distribution).execute }
it_behaves_like 'Generate Debian Distribution and component files'
end
+
+ describe '#lease_key' do
+ subject { service.send(:lease_key) }
+
+ let(:prefix) { "packages:debian:generate_distribution_service:" }
+
+ it 'returns an unique key' do
+ is_expected.to eq "#{prefix}#{container_type}_distribution:#{distribution.id}"
+ end
+ end
end
end
end
diff --git a/spec/services/packages/debian/parse_debian822_service_spec.rb b/spec/services/packages/debian/parse_debian822_service_spec.rb
index 35b7ead9209..624d4d95e5a 100644
--- a/spec/services/packages/debian/parse_debian822_service_spec.rb
+++ b/spec/services/packages/debian/parse_debian822_service_spec.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+
require 'spec_helper'
RSpec.describe Packages::Debian::ParseDebian822Service, feature_category: :package_registry do
@@ -76,14 +77,19 @@ RSpec.describe Packages::Debian::ParseDebian822Service, feature_category: :packa
'Multi-Arch' => 'same',
'Depends' => '${shlibs:Depends}, ${misc:Depends}',
'Description' => "Some mostly empty lib\nUsed in GitLab tests.\n\nTesting another paragraph."
- },
+ },
'Package: sample-udeb' => {
- 'Package' => 'sample-udeb',
- 'Package-Type' => 'udeb',
- 'Architecture' => 'any',
- 'Depends' => 'installed-base',
- 'Description' => 'Some mostly empty udeb'
- }
+ 'Package' => 'sample-udeb',
+ 'Package-Type' => 'udeb',
+ 'Architecture' => 'any',
+ 'Depends' => 'installed-base',
+ 'Description' => 'Some mostly empty udeb'
+ },
+ 'Package: sample-ddeb' => {
+ 'Package' => 'sample-ddeb',
+ 'Architecture' => 'any',
+ 'Description' => 'Some fake Ubuntu ddeb'
+ }
}
expect(subject.execute.to_s).to eq(expected.to_s)
diff --git a/spec/services/packages/debian/process_changes_service_spec.rb b/spec/services/packages/debian/process_changes_service_spec.rb
index e3ed744377e..d2c05b678ea 100644
--- a/spec/services/packages/debian/process_changes_service_spec.rb
+++ b/spec/services/packages/debian/process_changes_service_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Packages::Debian::ProcessChangesService, feature_category: :packa
expect { subject.execute }
.to change { Packages::Package.count }.from(1).to(2)
.and not_change { Packages::PackageFile.count }
- .and change { incoming.package_files.count }.from(7).to(0)
+ .and change { incoming.package_files.count }.from(8).to(0)
.and change { package_file.debian_file_metadatum&.reload&.file_type }.from('unknown').to('changes')
created_package = Packages::Package.last
diff --git a/spec/services/packages/debian/process_package_file_service_spec.rb b/spec/services/packages/debian/process_package_file_service_spec.rb
index caf29cfc4fa..2684b69785a 100644
--- a/spec/services/packages/debian/process_package_file_service_spec.rb
+++ b/spec/services/packages/debian/process_package_file_service_spec.rb
@@ -35,6 +35,7 @@ RSpec.describe Packages::Debian::ProcessPackageFileService, feature_category: :p
where(:case_name, :expected_file_type, :file_name, :component_name) do
'with a deb' | 'deb' | 'libsample0_1.2.3~alpha2_amd64.deb' | 'main'
'with an udeb' | 'udeb' | 'sample-udeb_1.2.3~alpha2_amd64.udeb' | 'contrib'
+ 'with an ddeb' | 'ddeb' | 'sample-ddeb_1.2.3~alpha2_amd64.ddeb' | 'main'
end
with_them do
@@ -67,9 +68,9 @@ RSpec.describe Packages::Debian::ProcessPackageFileService, feature_category: :p
.to receive(:perform_async).with(:project, distribution.id)
expect { subject.execute }
.to change(Packages::Package, :count).from(2).to(1)
- .and change(Packages::PackageFile, :count).from(14).to(8)
+ .and change(Packages::PackageFile, :count).from(16).to(9)
.and not_change(Packages::Debian::Publication, :count)
- .and change(package.package_files, :count).from(7).to(0)
+ .and change(package.package_files, :count).from(8).to(0)
.and change(package_file, :package).from(package).to(matching_package)
.and not_change(matching_package, :name)
.and not_change(matching_package, :version)
diff --git a/spec/services/packages/generic/create_package_file_service_spec.rb b/spec/services/packages/generic/create_package_file_service_spec.rb
index 9d6784b7721..08c4cbdbe11 100644
--- a/spec/services/packages/generic/create_package_file_service_spec.rb
+++ b/spec/services/packages/generic/create_package_file_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Generic::CreatePackageFileService do
+RSpec.describe Packages::Generic::CreatePackageFileService, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:pipeline) { create(:ci_pipeline, user: user) }
diff --git a/spec/services/packages/generic/find_or_create_package_service_spec.rb b/spec/services/packages/generic/find_or_create_package_service_spec.rb
index 10ec917bc99..07054fe3651 100644
--- a/spec/services/packages/generic/find_or_create_package_service_spec.rb
+++ b/spec/services/packages/generic/find_or_create_package_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Generic::FindOrCreatePackageService do
+RSpec.describe Packages::Generic::FindOrCreatePackageService, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:ci_build) { create(:ci_build, :running, user: user) }
diff --git a/spec/services/packages/go/create_package_service_spec.rb b/spec/services/packages/go/create_package_service_spec.rb
index 4ca1119fbaa..f552af81077 100644
--- a/spec/services/packages/go/create_package_service_spec.rb
+++ b/spec/services/packages/go/create_package_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Go::CreatePackageService do
+RSpec.describe Packages::Go::CreatePackageService, feature_category: :package_registry do
let_it_be(:project) { create :project_empty_repo, path: 'my-go-lib' }
let_it_be(:mod) { create :go_module, project: project }
diff --git a/spec/services/packages/go/sync_packages_service_spec.rb b/spec/services/packages/go/sync_packages_service_spec.rb
index 565b0f252ce..2881b6fdac9 100644
--- a/spec/services/packages/go/sync_packages_service_spec.rb
+++ b/spec/services/packages/go/sync_packages_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Go::SyncPackagesService do
+RSpec.describe Packages::Go::SyncPackagesService, feature_category: :package_registry do
include_context 'basic Go module'
let(:params) { { info: true, mod: true, zip: true } }
diff --git a/spec/services/packages/helm/extract_file_metadata_service_spec.rb b/spec/services/packages/helm/extract_file_metadata_service_spec.rb
index f4c61c12344..861d326d12a 100644
--- a/spec/services/packages/helm/extract_file_metadata_service_spec.rb
+++ b/spec/services/packages/helm/extract_file_metadata_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Helm::ExtractFileMetadataService do
+RSpec.describe Packages::Helm::ExtractFileMetadataService, feature_category: :package_registry do
let_it_be(:package_file) { create(:helm_package_file) }
let(:service) { described_class.new(package_file) }
diff --git a/spec/services/packages/helm/process_file_service_spec.rb b/spec/services/packages/helm/process_file_service_spec.rb
index 1be0153a4a5..a1f53e8756c 100644
--- a/spec/services/packages/helm/process_file_service_spec.rb
+++ b/spec/services/packages/helm/process_file_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Helm::ProcessFileService do
+RSpec.describe Packages::Helm::ProcessFileService, feature_category: :package_registry do
let(:package) { create(:helm_package, without_package_files: true, status: 'processing') }
let!(:package_file) { create(:helm_package_file, without_loaded_metadatum: true, package: package) }
let(:channel) { 'stable' }
diff --git a/spec/services/packages/mark_package_files_for_destruction_service_spec.rb b/spec/services/packages/mark_package_files_for_destruction_service_spec.rb
index 66534338003..a00a0b79854 100644
--- a/spec/services/packages/mark_package_files_for_destruction_service_spec.rb
+++ b/spec/services/packages/mark_package_files_for_destruction_service_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Packages::MarkPackageFilesForDestructionService, :aggregate_failures do
+RSpec.describe Packages::MarkPackageFilesForDestructionService, :aggregate_failures,
+ feature_category: :package_registry do
let(:service) { described_class.new(package_files) }
describe '#execute', :aggregate_failures do
diff --git a/spec/services/packages/mark_package_for_destruction_service_spec.rb b/spec/services/packages/mark_package_for_destruction_service_spec.rb
index 125ec53ad61..d65e62b84a6 100644
--- a/spec/services/packages/mark_package_for_destruction_service_spec.rb
+++ b/spec/services/packages/mark_package_for_destruction_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::MarkPackageForDestructionService do
+RSpec.describe Packages::MarkPackageForDestructionService, feature_category: :package_registry do
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:package) { create(:npm_package) }
@@ -36,6 +36,12 @@ RSpec.describe Packages::MarkPackageForDestructionService do
end
it 'returns an error ServiceResponse' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
+ instance_of(StandardError),
+ project_id: package.project_id,
+ package_id: package.id
+ )
+
response = service.execute
expect(package).not_to receive(:sync_maven_metadata)
diff --git a/spec/services/packages/mark_packages_for_destruction_service_spec.rb b/spec/services/packages/mark_packages_for_destruction_service_spec.rb
index 5c043b89de8..22278f9927d 100644
--- a/spec/services/packages/mark_packages_for_destruction_service_spec.rb
+++ b/spec/services/packages/mark_packages_for_destruction_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline do
+RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be_with_reload(:packages) { create_list(:npm_package, 3, project: project) }
@@ -76,6 +76,11 @@ RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline do
it 'returns an error ServiceResponse' do
expect(::Packages::Maven::Metadata::SyncService).not_to receive(:new)
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
+ instance_of(StandardError),
+ package_ids: package_ids
+ )
+
expect { subject }.to not_change { ::Packages::Package.pending_destruction.count }
.and not_change { ::Packages::PackageFile.pending_destruction.count }
diff --git a/spec/services/packages/maven/create_package_service_spec.rb b/spec/services/packages/maven/create_package_service_spec.rb
index 11bf00c1399..2c528c3591e 100644
--- a/spec/services/packages/maven/create_package_service_spec.rb
+++ b/spec/services/packages/maven/create_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Maven::CreatePackageService do
+RSpec.describe Packages::Maven::CreatePackageService, feature_category: :package_registry do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:app_name) { 'my-app' }
diff --git a/spec/services/packages/maven/find_or_create_package_service_spec.rb b/spec/services/packages/maven/find_or_create_package_service_spec.rb
index cca074e2fa6..8b84d2541eb 100644
--- a/spec/services/packages/maven/find_or_create_package_service_spec.rb
+++ b/spec/services/packages/maven/find_or_create_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Maven::FindOrCreatePackageService do
+RSpec.describe Packages::Maven::FindOrCreatePackageService, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
@@ -44,6 +44,15 @@ RSpec.describe Packages::Maven::FindOrCreatePackageService do
end
end
+ shared_examples 'returning an error' do |with_message: ''|
+ it { expect { subject }.not_to change { project.package_files.count } }
+
+ it 'returns an error', :aggregate_failures do
+ expect(subject.payload).to be_empty
+ expect(subject.errors).to include(with_message)
+ end
+ end
+
context 'path with version' do
# Note that "path with version" and "file type maven metadata xml" only exists for snapshot versions
# In other words, we will never have an metadata xml upload on a path with version for a non snapshot version
@@ -128,11 +137,19 @@ RSpec.describe Packages::Maven::FindOrCreatePackageService do
let!(:existing_package) { create(:maven_package, name: path, version: version, project: project) }
- it { expect { subject }.not_to change { project.package_files.count } }
+ let(:existing_file_name) { file_name }
+ let(:jar_file) { existing_package.package_files.with_file_name_like('%.jar').first }
- it 'returns an error', :aggregate_failures do
- expect(subject.payload).to be_empty
- expect(subject.errors).to include('Duplicate package is not allowed')
+ before do
+ jar_file.update_column(:file_name, existing_file_name)
+ end
+
+ it_behaves_like 'returning an error', with_message: 'Duplicate package is not allowed'
+
+ context 'for a SNAPSHOT version' do
+ let(:version) { '1.0.0-SNAPSHOT' }
+
+ it_behaves_like 'returning an error', with_message: 'Duplicate package is not allowed'
end
context 'when uploading to the versionless package which contains metadata about all versions' do
@@ -144,8 +161,7 @@ RSpec.describe Packages::Maven::FindOrCreatePackageService do
context 'when uploading different non-duplicate files to the same package' do
before do
- package_file = existing_package.package_files.find_by(file_name: 'my-app-1.0-20180724.124855-1.jar')
- package_file.destroy!
+ jar_file.destroy!
end
it_behaves_like 'reuse existing package'
@@ -166,6 +182,27 @@ RSpec.describe Packages::Maven::FindOrCreatePackageService do
it_behaves_like 'reuse existing package'
end
+
+ context 'when uploading a similar package file name with a classifier' do
+ let(:existing_file_name) { 'test.jar' }
+ let(:file_name) { 'test-javadoc.jar' }
+
+ it_behaves_like 'reuse existing package'
+
+ context 'for a SNAPSHOT version' do
+ let(:version) { '1.0.0-SNAPSHOT' }
+ let(:existing_file_name) { 'test-1.0-20230303.163304-1.jar' }
+ let(:file_name) { 'test-1.0-20230303.163304-1-javadoc.jar' }
+
+ it_behaves_like 'reuse existing package'
+ end
+ end
+ end
+
+ context 'with a very large file name' do
+ let(:params) { super().merge(file_name: 'a' * (described_class::MAX_FILE_NAME_LENGTH + 1)) }
+
+ it_behaves_like 'returning an error', with_message: 'File name is too long'
end
end
end
diff --git a/spec/services/packages/maven/metadata/append_package_file_service_spec.rb b/spec/services/packages/maven/metadata/append_package_file_service_spec.rb
index f3a90d31158..f65029f7b64 100644
--- a/spec/services/packages/maven/metadata/append_package_file_service_spec.rb
+++ b/spec/services/packages/maven/metadata/append_package_file_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Packages::Maven::Metadata::AppendPackageFileService do
+RSpec.describe ::Packages::Maven::Metadata::AppendPackageFileService, feature_category: :package_registry do
let_it_be(:package) { create(:maven_package, version: nil) }
let(:service) { described_class.new(package: package, metadata_content: content) }
diff --git a/spec/services/packages/maven/metadata/create_plugins_xml_service_spec.rb b/spec/services/packages/maven/metadata/create_plugins_xml_service_spec.rb
index 6fc1087940d..d0ef037b2d9 100644
--- a/spec/services/packages/maven/metadata/create_plugins_xml_service_spec.rb
+++ b/spec/services/packages/maven/metadata/create_plugins_xml_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Packages::Maven::Metadata::CreatePluginsXmlService do
+RSpec.describe ::Packages::Maven::Metadata::CreatePluginsXmlService, feature_category: :package_registry do
let_it_be(:group_id) { 'my/test' }
let_it_be(:package) { create(:maven_package, name: group_id, version: nil) }
diff --git a/spec/services/packages/maven/metadata/create_versions_xml_service_spec.rb b/spec/services/packages/maven/metadata/create_versions_xml_service_spec.rb
index 70c2bbad87a..6ae84b5df4e 100644
--- a/spec/services/packages/maven/metadata/create_versions_xml_service_spec.rb
+++ b/spec/services/packages/maven/metadata/create_versions_xml_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Packages::Maven::Metadata::CreateVersionsXmlService do
+RSpec.describe ::Packages::Maven::Metadata::CreateVersionsXmlService, feature_category: :package_registry do
let_it_be(:package) { create(:maven_package, version: nil) }
let(:versions_in_database) { %w[1.3 2.0-SNAPSHOT 1.6 1.4 1.5-SNAPSHOT] }
diff --git a/spec/services/packages/maven/metadata/sync_service_spec.rb b/spec/services/packages/maven/metadata/sync_service_spec.rb
index 9a704d749b3..eaed54d959b 100644
--- a/spec/services/packages/maven/metadata/sync_service_spec.rb
+++ b/spec/services/packages/maven/metadata/sync_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Packages::Maven::Metadata::SyncService do
+RSpec.describe ::Packages::Maven::Metadata::SyncService, feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
let_it_be(:project) { create(:project) }
diff --git a/spec/services/packages/npm/create_package_service_spec.rb b/spec/services/packages/npm/create_package_service_spec.rb
index ef8cdf2e8ab..70c79dae437 100644
--- a/spec/services/packages/npm/create_package_service_spec.rb
+++ b/spec/services/packages/npm/create_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Npm::CreatePackageService do
+RSpec.describe Packages::Npm::CreatePackageService, feature_category: :package_registry do
let(:namespace) { create(:namespace) }
let(:project) { create(:project, namespace: namespace) }
let(:user) { create(:user) }
diff --git a/spec/services/packages/npm/create_tag_service_spec.rb b/spec/services/packages/npm/create_tag_service_spec.rb
index a4b07bf97cc..682effc9f4f 100644
--- a/spec/services/packages/npm/create_tag_service_spec.rb
+++ b/spec/services/packages/npm/create_tag_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Npm::CreateTagService do
+RSpec.describe Packages::Npm::CreateTagService, feature_category: :package_registry do
let(:package) { create(:npm_package) }
let(:tag_name) { 'test-tag' }
diff --git a/spec/services/packages/nuget/create_dependency_service_spec.rb b/spec/services/packages/nuget/create_dependency_service_spec.rb
index 268c8837e25..10daec8b871 100644
--- a/spec/services/packages/nuget/create_dependency_service_spec.rb
+++ b/spec/services/packages/nuget/create_dependency_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Nuget::CreateDependencyService do
+RSpec.describe Packages::Nuget::CreateDependencyService, feature_category: :package_registry do
let_it_be(:package, reload: true) { create(:nuget_package) }
describe '#execute' do
diff --git a/spec/services/packages/nuget/metadata_extraction_service_spec.rb b/spec/services/packages/nuget/metadata_extraction_service_spec.rb
index 12bab30b4a7..9177a5379d9 100644
--- a/spec/services/packages/nuget/metadata_extraction_service_spec.rb
+++ b/spec/services/packages/nuget/metadata_extraction_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Nuget::MetadataExtractionService do
+RSpec.describe Packages::Nuget::MetadataExtractionService, feature_category: :package_registry do
let_it_be(:package_file) { create(:nuget_package).package_files.first }
let(:service) { described_class.new(package_file.id) }
diff --git a/spec/services/packages/nuget/search_service_spec.rb b/spec/services/packages/nuget/search_service_spec.rb
index 66c91487a8f..b5f32c9b727 100644
--- a/spec/services/packages/nuget/search_service_spec.rb
+++ b/spec/services/packages/nuget/search_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Nuget::SearchService do
+RSpec.describe Packages::Nuget::SearchService, feature_category: :package_registry do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: group) }
diff --git a/spec/services/packages/nuget/sync_metadatum_service_spec.rb b/spec/services/packages/nuget/sync_metadatum_service_spec.rb
index 32093c48b76..ae07f312fcc 100644
--- a/spec/services/packages/nuget/sync_metadatum_service_spec.rb
+++ b/spec/services/packages/nuget/sync_metadatum_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Nuget::SyncMetadatumService do
+RSpec.describe Packages::Nuget::SyncMetadatumService, feature_category: :package_registry do
let_it_be(:package, reload: true) { create(:nuget_package) }
let_it_be(:metadata) do
{
diff --git a/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb b/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb
index 6a4dbeb10dc..3a13f2ff902 100644
--- a/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb
+++ b/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_shared_state do
+RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_shared_state, feature_category: :package_registry do
include ExclusiveLeaseHelpers
let!(:package) { create(:nuget_package, :processing, :with_symbol_package) }
diff --git a/spec/services/packages/pypi/create_package_service_spec.rb b/spec/services/packages/pypi/create_package_service_spec.rb
index 6794ab4d9d6..0d278e32e89 100644
--- a/spec/services/packages/pypi/create_package_service_spec.rb
+++ b/spec/services/packages/pypi/create_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Pypi::CreatePackageService, :aggregate_failures do
+RSpec.describe Packages::Pypi::CreatePackageService, :aggregate_failures, feature_category: :package_registry do
include PackagesManagerApiSpecHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/services/packages/remove_tag_service_spec.rb b/spec/services/packages/remove_tag_service_spec.rb
index 084635824e5..4ad478d487a 100644
--- a/spec/services/packages/remove_tag_service_spec.rb
+++ b/spec/services/packages/remove_tag_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::RemoveTagService do
+RSpec.describe Packages::RemoveTagService, feature_category: :package_registry do
let!(:package_tag) { create(:packages_tag) }
describe '#execute' do
diff --git a/spec/services/packages/rpm/parse_package_service_spec.rb b/spec/services/packages/rpm/parse_package_service_spec.rb
index f330587bfa0..80907d8f43f 100644
--- a/spec/services/packages/rpm/parse_package_service_spec.rb
+++ b/spec/services/packages/rpm/parse_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rpm::ParsePackageService do
+RSpec.describe Packages::Rpm::ParsePackageService, feature_category: :package_registry do
let(:package_file) { File.open('spec/fixtures/packages/rpm/hello-0.0.1-1.fc29.x86_64.rpm') }
describe 'dynamic private methods' do
diff --git a/spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb b/spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb
index d93d6ab9fcb..e0d9e192d97 100644
--- a/spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb
+++ b/spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rpm::RepositoryMetadata::BuildFilelistXmlService do
+RSpec.describe Packages::Rpm::RepositoryMetadata::BuildFilelistXmlService, feature_category: :package_registry do
describe '#execute' do
subject { described_class.new(data).execute }
diff --git a/spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb b/spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb
index 201f9e67ce9..e81a436e006 100644
--- a/spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb
+++ b/spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rpm::RepositoryMetadata::BuildOtherXmlService do
+RSpec.describe Packages::Rpm::RepositoryMetadata::BuildOtherXmlService, feature_category: :package_registry do
describe '#execute' do
subject { described_class.new(data).execute }
diff --git a/spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb b/spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb
index 9bbfa5c9863..1e534782841 100644
--- a/spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb
+++ b/spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rpm::RepositoryMetadata::BuildPrimaryXmlService do
+RSpec.describe Packages::Rpm::RepositoryMetadata::BuildPrimaryXmlService, feature_category: :package_registry do
describe '#execute' do
subject { described_class.new(data).execute }
diff --git a/spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb b/spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb
index cf28301fa2c..99fcf0fabbf 100644
--- a/spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb
+++ b/spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rpm::RepositoryMetadata::BuildRepomdXmlService do
+RSpec.describe Packages::Rpm::RepositoryMetadata::BuildRepomdXmlService, feature_category: :package_registry do
describe '#execute' do
subject { described_class.new(data).execute }
diff --git a/spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb b/spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb
index e351392ba1c..68a3ac7d82f 100644
--- a/spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb
+++ b/spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rpm::RepositoryMetadata::UpdateXmlService do
+RSpec.describe Packages::Rpm::RepositoryMetadata::UpdateXmlService, feature_category: :package_registry do
describe '#execute' do
subject { described_class.new(filename: filename, xml: xml, data: data).execute }
diff --git a/spec/services/packages/rubygems/create_dependencies_service_spec.rb b/spec/services/packages/rubygems/create_dependencies_service_spec.rb
index b6e12b1cc61..d689bae96ff 100644
--- a/spec/services/packages/rubygems/create_dependencies_service_spec.rb
+++ b/spec/services/packages/rubygems/create_dependencies_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rubygems::CreateDependenciesService do
+RSpec.describe Packages::Rubygems::CreateDependenciesService, feature_category: :package_registry do
include RubygemsHelpers
let_it_be(:package) { create(:rubygems_package) }
diff --git a/spec/services/packages/rubygems/create_gemspec_service_spec.rb b/spec/services/packages/rubygems/create_gemspec_service_spec.rb
index 839fb4d955a..17890100b93 100644
--- a/spec/services/packages/rubygems/create_gemspec_service_spec.rb
+++ b/spec/services/packages/rubygems/create_gemspec_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rubygems::CreateGemspecService do
+RSpec.describe Packages::Rubygems::CreateGemspecService, feature_category: :package_registry do
include RubygemsHelpers
let_it_be(:package_file) { create(:package_file, :gem) }
diff --git a/spec/services/packages/rubygems/dependency_resolver_service_spec.rb b/spec/services/packages/rubygems/dependency_resolver_service_spec.rb
index bb84e0cd361..9a72c51e99c 100644
--- a/spec/services/packages/rubygems/dependency_resolver_service_spec.rb
+++ b/spec/services/packages/rubygems/dependency_resolver_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Rubygems::DependencyResolverService do
+RSpec.describe Packages::Rubygems::DependencyResolverService, feature_category: :package_registry do
let_it_be(:project) { create(:project, :private) }
let_it_be(:package) { create(:package, project: project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/packages/rubygems/metadata_extraction_service_spec.rb b/spec/services/packages/rubygems/metadata_extraction_service_spec.rb
index bbd5b6f3d59..87d63eff311 100644
--- a/spec/services/packages/rubygems/metadata_extraction_service_spec.rb
+++ b/spec/services/packages/rubygems/metadata_extraction_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
require 'rubygems/package'
-RSpec.describe Packages::Rubygems::MetadataExtractionService do
+RSpec.describe Packages::Rubygems::MetadataExtractionService, feature_category: :package_registry do
include RubygemsHelpers
let_it_be(:package) { create(:rubygems_package) }
diff --git a/spec/services/packages/rubygems/process_gem_service_spec.rb b/spec/services/packages/rubygems/process_gem_service_spec.rb
index caff338ef53..a1b4eae9655 100644
--- a/spec/services/packages/rubygems/process_gem_service_spec.rb
+++ b/spec/services/packages/rubygems/process_gem_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Rubygems::ProcessGemService do
+RSpec.describe Packages::Rubygems::ProcessGemService, feature_category: :package_registry do
include ExclusiveLeaseHelpers
include RubygemsHelpers
diff --git a/spec/services/packages/terraform_module/create_package_service_spec.rb b/spec/services/packages/terraform_module/create_package_service_spec.rb
index f73b5682835..3355dfcf5ec 100644
--- a/spec/services/packages/terraform_module/create_package_service_spec.rb
+++ b/spec/services/packages/terraform_module/create_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::TerraformModule::CreatePackageService do
+RSpec.describe Packages::TerraformModule::CreatePackageService, feature_category: :package_registry do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:project) { create(:project, namespace: namespace) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/packages/update_package_file_service_spec.rb b/spec/services/packages/update_package_file_service_spec.rb
index d988049c43a..5d081059105 100644
--- a/spec/services/packages/update_package_file_service_spec.rb
+++ b/spec/services/packages/update_package_file_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::UpdatePackageFileService do
+RSpec.describe Packages::UpdatePackageFileService, feature_category: :package_registry do
let_it_be(:another_package) { create(:package) }
let_it_be(:old_file_name) { 'old_file_name.txt' }
let_it_be(:new_file_name) { 'new_file_name.txt' }
diff --git a/spec/services/packages/update_tags_service_spec.rb b/spec/services/packages/update_tags_service_spec.rb
index c4256699c94..d8f572fff32 100644
--- a/spec/services/packages/update_tags_service_spec.rb
+++ b/spec/services/packages/update_tags_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::UpdateTagsService do
+RSpec.describe Packages::UpdateTagsService, feature_category: :package_registry do
let_it_be(:package, reload: true) { create(:nuget_package) }
let(:tags) { %w(test-tag tag1 tag2 tag3) }
diff --git a/spec/services/pages/delete_service_spec.rb b/spec/services/pages/delete_service_spec.rb
index 8b9e72ac9b1..590378af22b 100644
--- a/spec/services/pages/delete_service_spec.rb
+++ b/spec/services/pages/delete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Pages::DeleteService do
+RSpec.describe Pages::DeleteService, feature_category: :pages do
let_it_be(:admin) { create(:admin) }
let(:project) { create(:project, path: "my.project") }
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 177467aac85..b18f62c1c28 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
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Pages::MigrateLegacyStorageToDeploymentService do
+RSpec.describe Pages::MigrateLegacyStorageToDeploymentService, feature_category: :pages do
let(:project) { create(:project, :repository) }
let(:service) { described_class.new(project) }
diff --git a/spec/services/pages/zip_directory_service_spec.rb b/spec/services/pages/zip_directory_service_spec.rb
index 00fe75dbbfd..4917bc65a02 100644
--- a/spec/services/pages/zip_directory_service_spec.rb
+++ b/spec/services/pages/zip_directory_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Pages::ZipDirectoryService do
+RSpec.describe Pages::ZipDirectoryService, feature_category: :pages do
around do |example|
Dir.mktmpdir do |dir|
@work_dir = dir
diff --git a/spec/services/pages_domains/create_acme_order_service_spec.rb b/spec/services/pages_domains/create_acme_order_service_spec.rb
index 35b2cc56973..97534d52c67 100644
--- a/spec/services/pages_domains/create_acme_order_service_spec.rb
+++ b/spec/services/pages_domains/create_acme_order_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PagesDomains::CreateAcmeOrderService do
+RSpec.describe PagesDomains::CreateAcmeOrderService, feature_category: :pages do
include LetsEncryptHelpers
let(:pages_domain) { create(:pages_domain) }
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 ecb445fa441..2377fbcf003 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
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PagesDomains::ObtainLetsEncryptCertificateService do
+RSpec.describe PagesDomains::ObtainLetsEncryptCertificateService, feature_category: :pages do
include LetsEncryptHelpers
let(:pages_domain) { create(:pages_domain, :without_certificate, :without_key) }
diff --git a/spec/services/personal_access_tokens/create_service_spec.rb b/spec/services/personal_access_tokens/create_service_spec.rb
index b8a4c8f30d2..d80be5cccce 100644
--- a/spec/services/personal_access_tokens/create_service_spec.rb
+++ b/spec/services/personal_access_tokens/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PersonalAccessTokens::CreateService do
+RSpec.describe PersonalAccessTokens::CreateService, feature_category: :system_access do
shared_examples_for 'a successfully created token' do
it 'creates personal access token record' do
expect(subject.success?).to be true
@@ -40,7 +40,7 @@ RSpec.describe PersonalAccessTokens::CreateService do
let(:current_user) { create(:user) }
let(:user) { create(:user) }
let(:params) { { name: 'Test token', impersonation: false, scopes: [:api], expires_at: Date.today + 1.month } }
- let(:service) { described_class.new(current_user: current_user, target_user: user, params: params) }
+ let(:service) { described_class.new(current_user: current_user, target_user: user, params: params, concatenate_errors: false) }
let(:token) { subject.payload[:personal_access_token] }
context 'when current_user is an administrator' do
@@ -66,5 +66,21 @@ RSpec.describe PersonalAccessTokens::CreateService do
it_behaves_like 'a successfully created token'
end
end
+
+ context 'when invalid scope' do
+ let(:params) { { name: 'Test token', impersonation: false, scopes: [:no_valid], expires_at: Date.today + 1.month } }
+
+ context 'when concatenate_errors: true' do
+ let(:service) { described_class.new(current_user: user, target_user: user, params: params) }
+
+ it { expect(subject.message).to be_an_instance_of(String) }
+ end
+
+ context 'when concatenate_errors: false' do
+ let(:service) { described_class.new(current_user: user, target_user: user, params: params, concatenate_errors: false) }
+
+ it { expect(subject.message).to be_an_instance_of(Array) }
+ end
+ end
end
end
diff --git a/spec/services/personal_access_tokens/last_used_service_spec.rb b/spec/services/personal_access_tokens/last_used_service_spec.rb
index 6fc74e27dd9..20eabc20338 100644
--- a/spec/services/personal_access_tokens/last_used_service_spec.rb
+++ b/spec/services/personal_access_tokens/last_used_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PersonalAccessTokens::LastUsedService do
+RSpec.describe PersonalAccessTokens::LastUsedService, feature_category: :system_access do
describe '#execute' do
subject { described_class.new(personal_access_token).execute }
diff --git a/spec/services/personal_access_tokens/revoke_service_spec.rb b/spec/services/personal_access_tokens/revoke_service_spec.rb
index a9b4df9749f..4c5d106660a 100644
--- a/spec/services/personal_access_tokens/revoke_service_spec.rb
+++ b/spec/services/personal_access_tokens/revoke_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PersonalAccessTokens::RevokeService do
+RSpec.describe PersonalAccessTokens::RevokeService, feature_category: :system_access do
shared_examples_for 'a successfully revoked token' do
it { expect(subject.success?).to be true }
it { expect(service.token.revoked?).to be true }
diff --git a/spec/services/post_receive_service_spec.rb b/spec/services/post_receive_service_spec.rb
index aa955b3445b..13bd103003f 100644
--- a/spec/services/post_receive_service_spec.rb
+++ b/spec/services/post_receive_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PostReceiveService do
+RSpec.describe PostReceiveService, feature_category: :team_planning do
include GitlabShellHelpers
include Gitlab::Routing
diff --git a/spec/services/preview_markdown_service_spec.rb b/spec/services/preview_markdown_service_spec.rb
index d1bc10cfd28..97e31ec2cd3 100644
--- a/spec/services/preview_markdown_service_spec.rb
+++ b/spec/services/preview_markdown_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PreviewMarkdownService do
+RSpec.describe PreviewMarkdownService, feature_category: :team_planning do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/product_analytics/build_activity_graph_service_spec.rb b/spec/services/product_analytics/build_activity_graph_service_spec.rb
index e303656da34..cd1bc42e156 100644
--- a/spec/services/product_analytics/build_activity_graph_service_spec.rb
+++ b/spec/services/product_analytics/build_activity_graph_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProductAnalytics::BuildActivityGraphService do
+RSpec.describe ProductAnalytics::BuildActivityGraphService, feature_category: :product_analytics do
let_it_be(:project) { create(:project) }
let_it_be(:time_now) { Time.zone.now }
let_it_be(:time_ago) { Time.zone.now - 5.days }
diff --git a/spec/services/product_analytics/build_graph_service_spec.rb b/spec/services/product_analytics/build_graph_service_spec.rb
index 933a2bfee92..ee0e2190501 100644
--- a/spec/services/product_analytics/build_graph_service_spec.rb
+++ b/spec/services/product_analytics/build_graph_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProductAnalytics::BuildGraphService do
+RSpec.describe ProductAnalytics::BuildGraphService, feature_category: :product_analytics do
let_it_be(:project) { create(:project) }
let_it_be(:events) do
diff --git a/spec/services/projects/after_rename_service_spec.rb b/spec/services/projects/after_rename_service_spec.rb
index 72bb0adbf56..3097d6d1498 100644
--- a/spec/services/projects/after_rename_service_spec.rb
+++ b/spec/services/projects/after_rename_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::AfterRenameService do
+RSpec.describe Projects::AfterRenameService, feature_category: :projects do
let(:legacy_storage) { Storage::LegacyProject.new(project) }
let(:hashed_storage) { Storage::Hashed.new(project) }
let!(:path_before_rename) { project.path }
diff --git a/spec/services/projects/alerting/notify_service_spec.rb b/spec/services/projects/alerting/notify_service_spec.rb
index aa2ef39bf98..8cd9b5d3e00 100644
--- a/spec/services/projects/alerting/notify_service_spec.rb
+++ b/spec/services/projects/alerting/notify_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::Alerting::NotifyService do
+RSpec.describe Projects::Alerting::NotifyService, feature_category: :projects do
let_it_be_with_reload(:project) { create(:project) }
let(:payload) { ActionController::Parameters.new(payload_raw).permit! }
diff --git a/spec/services/projects/all_issues_count_service_spec.rb b/spec/services/projects/all_issues_count_service_spec.rb
index d7e35991940..e8e08a25c45 100644
--- a/spec/services/projects/all_issues_count_service_spec.rb
+++ b/spec/services/projects/all_issues_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::AllIssuesCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Projects::AllIssuesCountService, :use_clean_rails_memory_store_caching, feature_category: :projects do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, namespace: group) }
let_it_be(:banned_user) { create(:user, :banned) }
diff --git a/spec/services/projects/all_merge_requests_count_service_spec.rb b/spec/services/projects/all_merge_requests_count_service_spec.rb
index 13954d688aa..dc7038611ed 100644
--- a/spec/services/projects/all_merge_requests_count_service_spec.rb
+++ b/spec/services/projects/all_merge_requests_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::AllMergeRequestsCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Projects::AllMergeRequestsCountService, :use_clean_rails_memory_store_caching, feature_category: :projects do
let_it_be(:project) { create(:project) }
subject { described_class.new(project) }
diff --git a/spec/services/projects/android_target_platform_detector_service_spec.rb b/spec/services/projects/android_target_platform_detector_service_spec.rb
index 74fd320bb48..d5feef4ec3d 100644
--- a/spec/services/projects/android_target_platform_detector_service_spec.rb
+++ b/spec/services/projects/android_target_platform_detector_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::AndroidTargetPlatformDetectorService do
+RSpec.describe Projects::AndroidTargetPlatformDetectorService, feature_category: :projects do
let_it_be(:project) { build(:project) }
subject { described_class.new(project).execute }
diff --git a/spec/services/projects/apple_target_platform_detector_service_spec.rb b/spec/services/projects/apple_target_platform_detector_service_spec.rb
index 6391161824c..787faaa0f79 100644
--- a/spec/services/projects/apple_target_platform_detector_service_spec.rb
+++ b/spec/services/projects/apple_target_platform_detector_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::AppleTargetPlatformDetectorService do
+RSpec.describe Projects::AppleTargetPlatformDetectorService, feature_category: :projects do
let_it_be(:project) { build(:project) }
subject { described_class.new(project).execute }
diff --git a/spec/services/projects/auto_devops/disable_service_spec.rb b/spec/services/projects/auto_devops/disable_service_spec.rb
index 1f161990fb2..fd70362a53f 100644
--- a/spec/services/projects/auto_devops/disable_service_spec.rb
+++ b/spec/services/projects/auto_devops/disable_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::AutoDevops::DisableService, '#execute' do
+RSpec.describe Projects::AutoDevops::DisableService, '#execute', feature_category: :auto_devops do
let(:project) { create(:project, :repository, :auto_devops) }
let(:auto_devops) { project.auto_devops }
diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb
index bc95a1f3c8b..9d3075874a2 100644
--- a/spec/services/projects/autocomplete_service_spec.rb
+++ b/spec/services/projects/autocomplete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::AutocompleteService do
+RSpec.describe Projects::AutocompleteService, feature_category: :projects do
describe '#issues' do
describe 'confidential issues' do
let(:author) { create(:user) }
diff --git a/spec/services/projects/batch_open_issues_count_service_spec.rb b/spec/services/projects/batch_open_issues_count_service_spec.rb
index 89a4abbf9c9..d29115a697f 100644
--- a/spec/services/projects/batch_open_issues_count_service_spec.rb
+++ b/spec/services/projects/batch_open_issues_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::BatchOpenIssuesCountService do
+RSpec.describe Projects::BatchOpenIssuesCountService, feature_category: :projects do
let!(:project_1) { create(:project) }
let!(:project_2) { create(:project) }
diff --git a/spec/services/projects/batch_open_merge_requests_count_service_spec.rb b/spec/services/projects/batch_open_merge_requests_count_service_spec.rb
new file mode 100644
index 00000000000..96fc6c5e9dd
--- /dev/null
+++ b/spec/services/projects/batch_open_merge_requests_count_service_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::BatchOpenMergeRequestsCountService, feature_category: :code_review_workflow do
+ subject { described_class.new([project_1, project_2]) }
+
+ let_it_be(:project_1) { create(:project) }
+ let_it_be(:project_2) { create(:project) }
+
+ describe '#refresh_cache_and_retrieve_data', :use_clean_rails_memory_store_caching do
+ before do
+ create(:merge_request, source_project: project_1, target_project: project_1)
+ create(:merge_request, source_project: project_2, target_project: project_2)
+ end
+
+ it 'refreshes cache keys correctly when cache is clean', :aggregate_failures do
+ subject.refresh_cache_and_retrieve_data
+
+ expect(Rails.cache.read(get_cache_key(subject, project_1))).to eq(1)
+ expect(Rails.cache.read(get_cache_key(subject, project_2))).to eq(1)
+
+ expect { subject.refresh_cache_and_retrieve_data }.not_to exceed_query_limit(0)
+ end
+ end
+
+ def get_cache_key(subject, project)
+ subject.count_service
+ .new(project)
+ .cache_key
+ end
+end
diff --git a/spec/services/projects/blame_service_spec.rb b/spec/services/projects/blame_service_spec.rb
index 52b0ed3412d..e3df69b3b7b 100644
--- a/spec/services/projects/blame_service_spec.rb
+++ b/spec/services/projects/blame_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::BlameService, :aggregate_failures do
+RSpec.describe Projects::BlameService, :aggregate_failures, feature_category: :source_code_management do
subject(:service) { described_class.new(blob, commit, params) }
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/services/projects/branches_by_mode_service_spec.rb b/spec/services/projects/branches_by_mode_service_spec.rb
index 9a63563b37b..bfe76b34310 100644
--- a/spec/services/projects/branches_by_mode_service_spec.rb
+++ b/spec/services/projects/branches_by_mode_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::BranchesByModeService do
+RSpec.describe Projects::BranchesByModeService, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/services/projects/cleanup_service_spec.rb b/spec/services/projects/cleanup_service_spec.rb
index f2c052d9397..533a09f7bc7 100644
--- a/spec/services/projects/cleanup_service_spec.rb
+++ b/spec/services/projects/cleanup_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::CleanupService do
+RSpec.describe Projects::CleanupService, feature_category: :source_code_management do
subject(:service) { described_class.new(project) }
describe '.enqueue' do
diff --git a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
index 8311c4e4d9b..b8ad63d9b8a 100644
--- a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ContainerRepository::CleanupTagsService do
+RSpec.describe Projects::ContainerRepository::CleanupTagsService, feature_category: :container_registry do
let_it_be_with_reload(:container_repository) { create(:container_repository) }
let_it_be(:user) { container_repository.project.owner }
@@ -77,7 +77,7 @@ RSpec.describe Projects::ContainerRepository::CleanupTagsService do
context 'with a migrated repository' do
before do
- container_repository.update_column(:migration_state, :import_done)
+ allow(container_repository).to receive(:migrated?).and_return(true)
end
context 'supporting the gitlab api' do
@@ -99,8 +99,7 @@ RSpec.describe Projects::ContainerRepository::CleanupTagsService do
context 'with a non migrated repository' do
before do
- container_repository.update_column(:migration_state, :default)
- container_repository.update!(created_at: ContainerRepository::MIGRATION_PHASE_1_ENDED_AT - 1.week)
+ allow(container_repository).to receive(:migrated?).and_return(false)
end
it_behaves_like 'calling service', ::Projects::ContainerRepository::ThirdParty::CleanupTagsService, extra_log_data: { third_party_cleanup_tags_service: true }
diff --git a/spec/services/projects/container_repository/delete_tags_service_spec.rb b/spec/services/projects/container_repository/delete_tags_service_spec.rb
index 9e6849aa514..5b67d614dfb 100644
--- a/spec/services/projects/container_repository/delete_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/delete_tags_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ContainerRepository::DeleteTagsService do
+RSpec.describe Projects::ContainerRepository::DeleteTagsService, feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
include_context 'container repository delete tags service shared context'
diff --git a/spec/services/projects/container_repository/destroy_service_spec.rb b/spec/services/projects/container_repository/destroy_service_spec.rb
index fed1d13daa5..a142360f99d 100644
--- a/spec/services/projects/container_repository/destroy_service_spec.rb
+++ b/spec/services/projects/container_repository/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ContainerRepository::DestroyService do
+RSpec.describe Projects::ContainerRepository::DestroyService, feature_category: :container_registry do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :private) }
let_it_be(:params) { {} }
diff --git a/spec/services/projects/container_repository/gitlab/cleanup_tags_service_spec.rb b/spec/services/projects/container_repository/gitlab/cleanup_tags_service_spec.rb
index b06a5709bd5..416a3ed9782 100644
--- a/spec/services/projects/container_repository/gitlab/cleanup_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/gitlab/cleanup_tags_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ContainerRepository::Gitlab::CleanupTagsService do
+RSpec.describe Projects::ContainerRepository::Gitlab::CleanupTagsService, feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
include_context 'for a cleanup tags service'
@@ -11,11 +11,13 @@ RSpec.describe Projects::ContainerRepository::Gitlab::CleanupTagsService do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :private) }
- let(:repository) { create(:container_repository, :root, :import_done, project: project) }
+ let(:repository) { create(:container_repository, :root, project: project) }
let(:service) { described_class.new(container_repository: repository, current_user: user, params: params) }
let(:tags) { %w[latest A Ba Bb C D E] }
before do
+ allow(repository).to receive(:migrated?).and_return(true)
+
project.add_maintainer(user) if user
stub_container_registry_config(enabled: true)
@@ -147,6 +149,20 @@ RSpec.describe Projects::ContainerRepository::Gitlab::CleanupTagsService do
it_behaves_like 'when running a container_expiration_policy',
delete_expectations: [%w[Ba Bb C]]
end
+
+ context 'with no tags page' do
+ let(:tags_page_size) { 1000 }
+ let(:deleted) { [] }
+ let(:params) { {} }
+
+ before do
+ allow(repository.gitlab_api_client)
+ .to receive(:tags)
+ .and_return({})
+ end
+
+ it { is_expected.to eq(expected_service_response(status: :success, deleted: [], original_size: 0)) }
+ end
end
private
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 f03912dba80..c4e6c7f4a11 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
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ContainerRepository::Gitlab::DeleteTagsService do
+RSpec.describe Projects::ContainerRepository::Gitlab::DeleteTagsService, feature_category: :container_registry do
include_context 'container repository delete tags service shared context'
let(:service) { described_class.new(repository, tags) }
diff --git a/spec/services/projects/container_repository/third_party/cleanup_tags_service_spec.rb b/spec/services/projects/container_repository/third_party/cleanup_tags_service_spec.rb
index 7227834b131..d9b30428fb5 100644
--- a/spec/services/projects/container_repository/third_party/cleanup_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/third_party/cleanup_tags_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ContainerRepository::ThirdParty::CleanupTagsService, :clean_gitlab_redis_cache do
+RSpec.describe Projects::ContainerRepository::ThirdParty::CleanupTagsService, :clean_gitlab_redis_cache, feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
include_context 'for a cleanup tags service'
diff --git a/spec/services/projects/container_repository/third_party/delete_tags_service_spec.rb b/spec/services/projects/container_repository/third_party/delete_tags_service_spec.rb
index 4de36452684..0c297b6e1f7 100644
--- a/spec/services/projects/container_repository/third_party/delete_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/third_party/delete_tags_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ContainerRepository::ThirdParty::DeleteTagsService do
+RSpec.describe Projects::ContainerRepository::ThirdParty::DeleteTagsService, feature_category: :container_registry do
include_context 'container repository delete tags service shared context'
let(:service) { described_class.new(repository, tags) }
diff --git a/spec/services/projects/count_service_spec.rb b/spec/services/projects/count_service_spec.rb
index 11b2b57a277..71940fa396e 100644
--- a/spec/services/projects/count_service_spec.rb
+++ b/spec/services/projects/count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::CountService do
+RSpec.describe Projects::CountService, feature_category: :projects do
let(:project) { build(:project, id: 1) }
let(:service) { described_class.new(project) }
diff --git a/spec/services/projects/create_from_template_service_spec.rb b/spec/services/projects/create_from_template_service_spec.rb
index fba6225b87a..a3fdb258f75 100644
--- a/spec/services/projects/create_from_template_service_spec.rb
+++ b/spec/services/projects/create_from_template_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::CreateFromTemplateService do
+RSpec.describe Projects::CreateFromTemplateService, feature_category: :projects do
let(:user) { create(:user) }
let(:template_name) { 'rails' }
let(:project_params) do
diff --git a/spec/services/projects/deploy_tokens/create_service_spec.rb b/spec/services/projects/deploy_tokens/create_service_spec.rb
index 831dbc06588..96458a51fb4 100644
--- a/spec/services/projects/deploy_tokens/create_service_spec.rb
+++ b/spec/services/projects/deploy_tokens/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::DeployTokens::CreateService do
+RSpec.describe Projects::DeployTokens::CreateService, feature_category: :continuous_delivery do
it_behaves_like 'a deploy token creation service' do
let(:entity) { create(:project) }
let(:deploy_token_class) { ProjectDeployToken }
diff --git a/spec/services/projects/deploy_tokens/destroy_service_spec.rb b/spec/services/projects/deploy_tokens/destroy_service_spec.rb
index edb2345aa6c..3d0323c60ba 100644
--- a/spec/services/projects/deploy_tokens/destroy_service_spec.rb
+++ b/spec/services/projects/deploy_tokens/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::DeployTokens::DestroyService do
+RSpec.describe Projects::DeployTokens::DestroyService, feature_category: :continuous_delivery do
it_behaves_like 'a deploy token deletion service' do
let_it_be(:entity) { create(:project) }
let_it_be(:deploy_token_class) { ProjectDeployToken }
diff --git a/spec/services/projects/detect_repository_languages_service_spec.rb b/spec/services/projects/detect_repository_languages_service_spec.rb
index cf4c7a5024d..5759f8128d0 100644
--- a/spec/services/projects/detect_repository_languages_service_spec.rb
+++ b/spec/services/projects/detect_repository_languages_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::DetectRepositoryLanguagesService, :clean_gitlab_redis_shared_state do
+RSpec.describe Projects::DetectRepositoryLanguagesService, :clean_gitlab_redis_shared_state, feature_category: :projects do
let_it_be(:project, reload: true) { create(:project, :repository) }
subject { described_class.new(project) }
diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb
index f158b11a9fa..52bdbefe01a 100644
--- a/spec/services/projects/download_service_spec.rb
+++ b/spec/services/projects/download_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::DownloadService do
+RSpec.describe Projects::DownloadService, feature_category: :projects do
describe 'File service' do
before do
@user = create(:user)
diff --git a/spec/services/projects/enable_deploy_key_service_spec.rb b/spec/services/projects/enable_deploy_key_service_spec.rb
index c0b3992037e..59c76a96d07 100644
--- a/spec/services/projects/enable_deploy_key_service_spec.rb
+++ b/spec/services/projects/enable_deploy_key_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::EnableDeployKeyService do
+RSpec.describe Projects::EnableDeployKeyService, feature_category: :continuous_delivery do
let(:deploy_key) { create(:deploy_key, public: true) }
let(:project) { create(:project) }
let(:user) { project.creator }
diff --git a/spec/services/projects/fetch_statistics_increment_service_spec.rb b/spec/services/projects/fetch_statistics_increment_service_spec.rb
index 16121a42c39..9e24e68fa98 100644
--- a/spec/services/projects/fetch_statistics_increment_service_spec.rb
+++ b/spec/services/projects/fetch_statistics_increment_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
module Projects
- RSpec.describe FetchStatisticsIncrementService do
+ RSpec.describe FetchStatisticsIncrementService, feature_category: :projects do
let(:project) { create(:project) }
describe '#execute' do
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index 48756cf774b..8f42f5c8f87 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ForkService do
+RSpec.describe Projects::ForkService, feature_category: :source_code_management do
include ProjectForksHelper
shared_examples 'forks count cache refresh' do
diff --git a/spec/services/projects/forks/sync_service_spec.rb b/spec/services/projects/forks/sync_service_spec.rb
new file mode 100644
index 00000000000..aeb53992ed4
--- /dev/null
+++ b/spec/services/projects/forks/sync_service_spec.rb
@@ -0,0 +1,185 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::Forks::SyncService, feature_category: :source_code_management do
+ include ProjectForksHelper
+ include RepoHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:source_project) { create(:project, :repository, :public) }
+ let_it_be(:project) { fork_project(source_project, user, { repository: true }) }
+
+ let(:fork_branch) { project.default_branch }
+ let(:service) { described_class.new(project, user, fork_branch) }
+
+ def details
+ Projects::Forks::Details.new(project, fork_branch)
+ end
+
+ def expect_to_cancel_exclusive_lease
+ expect(Gitlab::ExclusiveLease).to receive(:cancel)
+ end
+
+ describe '#execute' do
+ context 'when fork is up-to-date with the upstream' do
+ it 'does not perform merge' do
+ expect_to_cancel_exclusive_lease
+ expect(project.repository).not_to receive(:merge_to_branch)
+ expect(project.repository).not_to receive(:ff_merge)
+
+ expect(service.execute).to be_success
+ end
+ end
+
+ context 'when fork is behind the upstream' do
+ let_it_be(:base_commit) { source_project.commit.sha }
+
+ before_all do
+ source_project.repository.commit_files(
+ user,
+ branch_name: source_project.repository.root_ref, message: 'Commit to root ref',
+ actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'One more' }]
+ )
+
+ source_project.repository.commit_files(
+ user,
+ branch_name: source_project.repository.root_ref, message: 'Another commit to root ref',
+ actions: [{ action: :create, file_path: 'encoding/NEW-CHANGELOG', content: 'One more time' }]
+ )
+ end
+
+ before do
+ project.repository.create_branch(fork_branch, base_commit)
+ end
+
+ context 'when fork is not ahead of the upstream' do
+ let(:fork_branch) { 'fork-without-new-commits' }
+
+ it 'updates the fork using ff merge' do
+ expect_to_cancel_exclusive_lease
+ expect(project.commit(fork_branch).sha).to eq(base_commit)
+ expect(project.repository).to receive(:ff_merge)
+ .with(user, source_project.commit.sha, fork_branch, target_sha: base_commit)
+ .and_call_original
+
+ expect do
+ expect(service.execute).to be_success
+ end.to change { details.counts }.from({ ahead: 0, behind: 2 }).to({ ahead: 0, behind: 0 })
+ end
+ end
+
+ context 'when fork is ahead of the upstream' do
+ context 'and has conflicts with the upstream', :use_clean_rails_redis_caching do
+ let(:fork_branch) { 'fork-with-conflicts' }
+
+ it 'returns an error' do
+ project.repository.commit_files(
+ user,
+ branch_name: fork_branch, message: 'Committing something',
+ actions: [{ action: :create, file_path: 'encoding/CHANGELOG', content: 'New file' }]
+ )
+
+ expect_to_cancel_exclusive_lease
+ expect(details).not_to have_conflicts
+
+ expect do
+ result = service.execute
+
+ expect(result).to be_error
+ expect(result.message).to eq("9:merging commits: merge: there are conflicting files.")
+ end.not_to change { details.counts }
+
+ expect(details).to have_conflicts
+ end
+ end
+
+ context 'and does not have conflicts with the upstream' do
+ let(:fork_branch) { 'fork-with-new-commits' }
+
+ it 'updates the fork using merge' do
+ project.repository.commit_files(
+ user,
+ branch_name: fork_branch, message: 'Committing completely new changelog',
+ actions: [{ action: :create, file_path: 'encoding/COMPLETELY-NEW-CHANGELOG', content: 'New file' }]
+ )
+
+ commit_message = "Merge branch #{source_project.path}:#{source_project.default_branch} into #{fork_branch}"
+ expect(project.repository).to receive(:merge_to_branch).with(
+ user,
+ source_sha: source_project.commit.sha,
+ target_branch: fork_branch,
+ target_sha: project.commit(fork_branch).sha,
+ message: commit_message
+ ).and_call_original
+ expect_to_cancel_exclusive_lease
+
+ expect do
+ expect(service.execute).to be_success
+ end.to change { details.counts }.from({ ahead: 1, behind: 2 }).to({ ahead: 2, behind: 0 })
+
+ commits = project.repository.commits_between(source_project.commit.sha, project.commit(fork_branch).sha)
+ expect(commits.map(&:message)).to eq([
+ "Committing completely new changelog",
+ commit_message
+ ])
+ end
+ end
+ end
+
+ context 'when a merge cannot happen due to another ongoing merge' do
+ it 'does not merge' do
+ expect(service).to receive(:perform_merge).and_return(nil)
+
+ result = service.execute
+
+ expect(result).to be_error
+ expect(result.message).to eq(described_class::ONGOING_MERGE_ERROR)
+ end
+ end
+
+ context 'when upstream branch contains lfs reference' do
+ let(:source_project) { create(:project, :repository, :public) }
+ let(:project) { fork_project(source_project, user, { repository: true }) }
+ let(:fork_branch) { 'fork-fetches-lfs-pointers' }
+
+ before do
+ source_project.change_head('lfs')
+
+ allow(source_project).to receive(:lfs_enabled?).and_return(true)
+ allow(project).to receive(:lfs_enabled?).and_return(true)
+
+ create_file_in_repo(source_project, 'lfs', 'lfs', 'one.lfs', 'One')
+ create_file_in_repo(source_project, 'lfs', 'lfs', 'two.lfs', 'Two')
+ end
+
+ it 'links fetched lfs objects to the fork project', :aggregate_failures do
+ expect_to_cancel_exclusive_lease
+
+ expect do
+ expect(service.execute).to be_success
+ end.to change { project.reload.lfs_objects.size }.from(0).to(2)
+ .and change { details.counts }.from({ ahead: 0, behind: 3 }).to({ ahead: 0, behind: 0 })
+
+ expect(project.lfs_objects).to match_array(source_project.lfs_objects)
+ end
+
+ context 'and there are too many of them for a single sync' do
+ let(:fork_branch) { 'fork-too-many-lfs-pointers' }
+
+ it 'updates the fork successfully' do
+ expect_to_cancel_exclusive_lease
+ stub_const('Projects::LfsPointers::LfsLinkService::MAX_OIDS', 1)
+
+ expect do
+ result = service.execute
+
+ expect(result).to be_error
+ expect(result.message).to eq('Too many LFS object ids to link, please push them manually')
+ end.not_to change { details.counts }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/projects/forks_count_service_spec.rb b/spec/services/projects/forks_count_service_spec.rb
index 31662f78973..403d8656b7c 100644
--- a/spec/services/projects/forks_count_service_spec.rb
+++ b/spec/services/projects/forks_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ForksCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Projects::ForksCountService, :use_clean_rails_memory_store_caching, feature_category: :source_code_management do
let(:project) { build(:project) }
subject { described_class.new(project) }
diff --git a/spec/services/projects/git_deduplication_service_spec.rb b/spec/services/projects/git_deduplication_service_spec.rb
index e6eff936de7..314c9d160dd 100644
--- a/spec/services/projects/git_deduplication_service_spec.rb
+++ b/spec/services/projects/git_deduplication_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::GitDeduplicationService do
+RSpec.describe Projects::GitDeduplicationService, feature_category: :source_code_management do
include ExclusiveLeaseHelpers
let(:pool) { create(:pool_repository, :ready) }
diff --git a/spec/services/projects/gitlab_projects_import_service_spec.rb b/spec/services/projects/gitlab_projects_import_service_spec.rb
index d32e720a49f..b1468a40212 100644
--- a/spec/services/projects/gitlab_projects_import_service_spec.rb
+++ b/spec/services/projects/gitlab_projects_import_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::GitlabProjectsImportService do
+RSpec.describe Projects::GitlabProjectsImportService, feature_category: :importers do
let_it_be(:namespace) { create(:namespace) }
let(:path) { 'test-path' }
diff --git a/spec/services/projects/group_links/create_service_spec.rb b/spec/services/projects/group_links/create_service_spec.rb
index eae898b4f68..b62fd0ecb68 100644
--- a/spec/services/projects/group_links/create_service_spec.rb
+++ b/spec/services/projects/group_links/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::GroupLinks::CreateService, '#execute' do
+RSpec.describe Projects::GroupLinks::CreateService, '#execute', feature_category: :subgroups do
let_it_be(:user) { create :user }
let_it_be(:group) { create :group }
let_it_be(:project) { create(:project, namespace: create(:namespace, :with_namespace_settings)) }
diff --git a/spec/services/projects/group_links/destroy_service_spec.rb b/spec/services/projects/group_links/destroy_service_spec.rb
index 89865d6bc3b..e1f915e18bd 100644
--- a/spec/services/projects/group_links/destroy_service_spec.rb
+++ b/spec/services/projects/group_links/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::GroupLinks::DestroyService, '#execute' do
+RSpec.describe Projects::GroupLinks::DestroyService, '#execute', feature_category: :subgroups do
let_it_be(:user) { create :user }
let_it_be(:project) { create(:project, :private) }
let_it_be(:group) { create(:group) }
diff --git a/spec/services/projects/group_links/update_service_spec.rb b/spec/services/projects/group_links/update_service_spec.rb
index 1acbb770763..b3336cb91fd 100644
--- a/spec/services/projects/group_links/update_service_spec.rb
+++ b/spec/services/projects/group_links/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::GroupLinks::UpdateService, '#execute' do
+RSpec.describe Projects::GroupLinks::UpdateService, '#execute', feature_category: :subgroups do
let_it_be(:user) { create :user }
let_it_be(:group) { create :group }
let_it_be(:project) { create :project }
diff --git a/spec/services/projects/hashed_storage/base_attachment_service_spec.rb b/spec/services/projects/hashed_storage/base_attachment_service_spec.rb
index 86e3fb3820c..01036fc2d9c 100644
--- a/spec/services/projects/hashed_storage/base_attachment_service_spec.rb
+++ b/spec/services/projects/hashed_storage/base_attachment_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::HashedStorage::BaseAttachmentService do
+RSpec.describe Projects::HashedStorage::BaseAttachmentService, feature_category: :projects do
let(:project) { create(:project, :repository, storage_version: 0, skip_disk_validation: true) }
subject(:service) { described_class.new(project: project, old_disk_path: project.full_path, logger: nil) }
diff --git a/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb b/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
index c8f24c6ce00..39263506bca 100644
--- a/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::HashedStorage::MigrateAttachmentsService do
+RSpec.describe Projects::HashedStorage::MigrateAttachmentsService, feature_category: :projects do
subject(:service) { described_class.new(project: project, old_disk_path: project.full_path, logger: nil) }
let(:project) { create(:project, :repository, storage_version: 1, skip_disk_validation: true) }
diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
index eb8d94ebfa5..bcc914e72b5 100644
--- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::HashedStorage::MigrateRepositoryService do
+RSpec.describe Projects::HashedStorage::MigrateRepositoryService, feature_category: :projects do
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project) { create(:project, :legacy_storage, :repository, :wiki_repo, :design_repo) }
let(:legacy_storage) { Storage::LegacyProject.new(project) }
diff --git a/spec/services/projects/hashed_storage/migration_service_spec.rb b/spec/services/projects/hashed_storage/migration_service_spec.rb
index ef96c17dd85..14bfa645be2 100644
--- a/spec/services/projects/hashed_storage/migration_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migration_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::HashedStorage::MigrationService do
+RSpec.describe Projects::HashedStorage::MigrationService, feature_category: :projects do
let(:project) { create(:project, :empty_repo, :wiki_repo, :legacy_storage) }
let(:logger) { double }
let!(:project_attachment) { build(:file_uploader, project: project) }
diff --git a/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb b/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb
index d4cb46c82ad..95491d63df2 100644
--- a/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb
+++ b/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::HashedStorage::RollbackAttachmentsService do
+RSpec.describe Projects::HashedStorage::RollbackAttachmentsService, feature_category: :projects do
subject(:service) { described_class.new(project: project, old_disk_path: project.disk_path, logger: nil) }
let(:project) { create(:project, :repository, skip_disk_validation: true) }
diff --git a/spec/services/projects/hashed_storage/rollback_repository_service_spec.rb b/spec/services/projects/hashed_storage/rollback_repository_service_spec.rb
index 385c03e6308..19f1856e39a 100644
--- a/spec/services/projects/hashed_storage/rollback_repository_service_spec.rb
+++ b/spec/services/projects/hashed_storage/rollback_repository_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::HashedStorage::RollbackRepositoryService, :clean_gitlab_redis_shared_state do
+RSpec.describe Projects::HashedStorage::RollbackRepositoryService, :clean_gitlab_redis_shared_state, feature_category: :projects do
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project) { create(:project, :repository, :wiki_repo, :design_repo, storage_version: ::Project::HASHED_STORAGE_FEATURES[:repository]) }
let(:legacy_storage) { Storage::LegacyProject.new(project) }
diff --git a/spec/services/projects/hashed_storage/rollback_service_spec.rb b/spec/services/projects/hashed_storage/rollback_service_spec.rb
index 0bd63f2da2a..6d047f856ec 100644
--- a/spec/services/projects/hashed_storage/rollback_service_spec.rb
+++ b/spec/services/projects/hashed_storage/rollback_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::HashedStorage::RollbackService do
+RSpec.describe Projects::HashedStorage::RollbackService, feature_category: :projects do
let(:project) { create(:project, :empty_repo, :wiki_repo) }
let(:logger) { double }
let!(:project_attachment) { build(:file_uploader, project: project) }
diff --git a/spec/services/projects/import_error_filter_spec.rb b/spec/services/projects/import_error_filter_spec.rb
index fd31cd52cc4..be07208c7f2 100644
--- a/spec/services/projects/import_error_filter_spec.rb
+++ b/spec/services/projects/import_error_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ImportErrorFilter do
+RSpec.describe Projects::ImportErrorFilter, feature_category: :importers do
it 'filters any full paths' do
message = 'Error importing into /my/folder Permission denied @ unlink_internal - /var/opt/gitlab/gitlab-rails/shared/a/b/c/uploads/file'
diff --git a/spec/services/projects/import_export/relation_export_service_spec.rb b/spec/services/projects/import_export/relation_export_service_spec.rb
index 94f5653ee7d..4b44a37b299 100644
--- a/spec/services/projects/import_export/relation_export_service_spec.rb
+++ b/spec/services/projects/import_export/relation_export_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ImportExport::RelationExportService do
+RSpec.describe Projects::ImportExport::RelationExportService, feature_category: :importers do
using RSpec::Parameterized::TableSyntax
subject(:service) { described_class.new(relation_export, 'jid') }
@@ -49,6 +49,7 @@ RSpec.describe Projects::ImportExport::RelationExportService do
expect(logger).to receive(:error).with(
export_error: '',
message: 'Project relation export failed',
+ relation: relation_export.relation,
project_export_job_id: project_export_job.id,
project_id: project_export_job.project.id,
project_name: project_export_job.project.name
@@ -78,6 +79,7 @@ RSpec.describe Projects::ImportExport::RelationExportService do
expect(logger).to receive(:error).with(
export_error: 'Error!',
message: 'Project relation export failed',
+ relation: relation_export.relation,
project_export_job_id: project_export_job.id,
project_id: project_export_job.project.id,
project_name: project_export_job.project.name
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 4c51c8a4ac8..4ad6fd0edff 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
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::InProductMarketingCampaignEmailsService do
+RSpec.describe Projects::InProductMarketingCampaignEmailsService, feature_category: :experimentation_adoption do
describe '#execute' do
let(:user) { create(:user, email_opted_in: true) }
let(:project) { create(:project) }
diff --git a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb
index 80b3c4d0403..0aaaae19f5a 100644
--- a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::LfsPointers::LfsDownloadLinkListService do
+RSpec.describe Projects::LfsPointers::LfsDownloadLinkListService, feature_category: :source_code_management do
let(:import_url) { 'http://www.gitlab.com/demo/repo.git' }
let(:lfs_endpoint) { "#{import_url}/info/lfs/objects/batch" }
let!(:project) { create(:project, import_url: import_url) }
diff --git a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
index c815ad38843..00c156ba538 100644
--- a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::LfsPointers::LfsDownloadService do
+RSpec.describe Projects::LfsPointers::LfsDownloadService, feature_category: :source_code_management do
include StubRequests
let_it_be(:project) { create(:project) }
diff --git a/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb
index 32b86ade81e..f1e4db55962 100644
--- a/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::LfsPointers::LfsImportService do
+RSpec.describe Projects::LfsPointers::LfsImportService, feature_category: :source_code_management do
let(:project) { create(:project) }
let(:user) { project.creator }
let(:import_url) { 'http://www.gitlab.com/demo/repo.git' }
diff --git a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
index 0e7d16f18e8..e8a08d95bba 100644
--- a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
@@ -1,9 +1,10 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::LfsPointers::LfsLinkService do
- let!(:project) { create(:project, lfs_enabled: true) }
- let!(:lfs_objects_project) { create_list(:lfs_objects_project, 2, project: project) }
+RSpec.describe Projects::LfsPointers::LfsLinkService, feature_category: :source_code_management do
+ let_it_be(:project) { create(:project, lfs_enabled: true) }
+ let_it_be(:lfs_objects_project) { create_list(:lfs_objects_project, 2, project: project) }
+
let(:new_oids) { { 'oid1' => 123, 'oid2' => 125 } }
let(:all_oids) { LfsObject.pluck(:oid, :size).to_h.merge(new_oids) }
let(:new_lfs_object) { create(:lfs_object) }
@@ -17,12 +18,26 @@ RSpec.describe Projects::LfsPointers::LfsLinkService do
describe '#execute' do
it 'raises an error when trying to link too many objects at once' do
+ stub_const("#{described_class}::MAX_OIDS", 5)
+
oids = Array.new(described_class::MAX_OIDS) { |i| "oid-#{i}" }
oids << 'the straw'
expect { subject.execute(oids) }.to raise_error(described_class::TooManyOidsError)
end
+ it 'executes a block after validation and before execution' do
+ block = instance_double(Proc)
+
+ expect(subject).to receive(:validate!).ordered
+ expect(block).to receive(:call).ordered
+ expect(subject).to receive(:link_existing_lfs_objects).ordered
+
+ subject.execute([]) do
+ block.call
+ end
+ end
+
it 'links existing lfs objects to the project' do
expect(project.lfs_objects.count).to eq 2
diff --git a/spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb
index 59eb1ed7a29..f5dcae05959 100644
--- a/spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::LfsPointers::LfsObjectDownloadListService do
+RSpec.describe Projects::LfsPointers::LfsObjectDownloadListService, feature_category: :source_code_management do
let(:import_url) { 'http://www.gitlab.com/demo/repo.git' }
let(:default_endpoint) { "#{import_url}/info/lfs/objects/batch" }
let(:group) { create(:group, lfs_enabled: true) }
diff --git a/spec/services/projects/move_access_service_spec.rb b/spec/services/projects/move_access_service_spec.rb
index 45e10c3ca84..b9244002f6c 100644
--- a/spec/services/projects/move_access_service_spec.rb
+++ b/spec/services/projects/move_access_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveAccessService do
+RSpec.describe Projects::MoveAccessService, feature_category: :projects do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project_with_access) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/move_deploy_keys_projects_service_spec.rb b/spec/services/projects/move_deploy_keys_projects_service_spec.rb
index 59674a3a4ef..b40eb4a18d1 100644
--- a/spec/services/projects/move_deploy_keys_projects_service_spec.rb
+++ b/spec/services/projects/move_deploy_keys_projects_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveDeployKeysProjectsService do
+RSpec.describe Projects::MoveDeployKeysProjectsService, feature_category: :continuous_delivery do
let!(:user) { create(:user) }
let!(:project_with_deploy_keys) { create(:project, namespace: user.namespace) }
let!(:target_project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/move_forks_service_spec.rb b/spec/services/projects/move_forks_service_spec.rb
index 7d3637b7758..093562207dd 100644
--- a/spec/services/projects/move_forks_service_spec.rb
+++ b/spec/services/projects/move_forks_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveForksService do
+RSpec.describe Projects::MoveForksService, feature_category: :source_code_management do
include ProjectForksHelper
let!(:user) { create(:user) }
diff --git a/spec/services/projects/move_lfs_objects_projects_service_spec.rb b/spec/services/projects/move_lfs_objects_projects_service_spec.rb
index e3df5fed9cf..f3cc4014b1c 100644
--- a/spec/services/projects/move_lfs_objects_projects_service_spec.rb
+++ b/spec/services/projects/move_lfs_objects_projects_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveLfsObjectsProjectsService do
+RSpec.describe Projects::MoveLfsObjectsProjectsService, feature_category: :source_code_management do
let!(:user) { create(:user) }
let!(:project_with_lfs_objects) { create(:project, namespace: user.namespace) }
let!(:target_project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/move_notification_settings_service_spec.rb b/spec/services/projects/move_notification_settings_service_spec.rb
index e381ae7590f..5ef6e8a0647 100644
--- a/spec/services/projects/move_notification_settings_service_spec.rb
+++ b/spec/services/projects/move_notification_settings_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveNotificationSettingsService do
+RSpec.describe Projects::MoveNotificationSettingsService, feature_category: :projects do
let(:user) { create(:user) }
let(:project_with_notifications) { create(:project, namespace: user.namespace) }
let(:target_project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/move_project_authorizations_service_spec.rb b/spec/services/projects/move_project_authorizations_service_spec.rb
index d47b13ca939..6cd0b056325 100644
--- a/spec/services/projects/move_project_authorizations_service_spec.rb
+++ b/spec/services/projects/move_project_authorizations_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveProjectAuthorizationsService do
+RSpec.describe Projects::MoveProjectAuthorizationsService, feature_category: :projects do
let!(:user) { create(:user) }
let(:project_with_users) { create(:project, namespace: user.namespace) }
let(:target_project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/move_project_group_links_service_spec.rb b/spec/services/projects/move_project_group_links_service_spec.rb
index 1fca96a0367..cfd4b51b001 100644
--- a/spec/services/projects/move_project_group_links_service_spec.rb
+++ b/spec/services/projects/move_project_group_links_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveProjectGroupLinksService do
+RSpec.describe Projects::MoveProjectGroupLinksService, feature_category: :projects do
let!(:user) { create(:user) }
let(:project_with_groups) { create(:project, namespace: user.namespace) }
let(:target_project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/move_project_members_service_spec.rb b/spec/services/projects/move_project_members_service_spec.rb
index 8fbd0ba3270..364fb7faaf2 100644
--- a/spec/services/projects/move_project_members_service_spec.rb
+++ b/spec/services/projects/move_project_members_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveProjectMembersService do
+RSpec.describe Projects::MoveProjectMembersService, feature_category: :projects do
let!(:user) { create(:user) }
let(:project_with_users) { create(:project, namespace: user.namespace) }
let(:target_project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/move_users_star_projects_service_spec.rb b/spec/services/projects/move_users_star_projects_service_spec.rb
index b580d3d8772..b99e51d954b 100644
--- a/spec/services/projects/move_users_star_projects_service_spec.rb
+++ b/spec/services/projects/move_users_star_projects_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::MoveUsersStarProjectsService do
+RSpec.describe Projects::MoveUsersStarProjectsService, feature_category: :projects do
let!(:user) { create(:user) }
let!(:project_with_stars) { create(:project, namespace: user.namespace) }
let!(:target_project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/open_issues_count_service_spec.rb b/spec/services/projects/open_issues_count_service_spec.rb
index c739fea5ecf..89405f06f5d 100644
--- a/spec/services/projects/open_issues_count_service_spec.rb
+++ b/spec/services/projects/open_issues_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::OpenIssuesCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Projects::OpenIssuesCountService, :use_clean_rails_memory_store_caching, feature_category: :team_planning do
let(:project) { create(:project) }
subject { described_class.new(project) }
diff --git a/spec/services/projects/open_merge_requests_count_service_spec.rb b/spec/services/projects/open_merge_requests_count_service_spec.rb
index 6caef181e77..74eead39ec4 100644
--- a/spec/services/projects/open_merge_requests_count_service_spec.rb
+++ b/spec/services/projects/open_merge_requests_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::OpenMergeRequestsCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Projects::OpenMergeRequestsCountService, :use_clean_rails_memory_store_caching, feature_category: :code_review_workflow do
let_it_be(:project) { create(:project) }
subject { described_class.new(project) }
diff --git a/spec/services/projects/operations/update_service_spec.rb b/spec/services/projects/operations/update_service_spec.rb
index 95f2176dbc0..7babaf4d0d8 100644
--- a/spec/services/projects/operations/update_service_spec.rb
+++ b/spec/services/projects/operations/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::Operations::UpdateService do
+RSpec.describe Projects::Operations::UpdateService, feature_category: :projects do
let_it_be_with_refind(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/projects/overwrite_project_service_spec.rb b/spec/services/projects/overwrite_project_service_spec.rb
index 7038910508f..b4faf45a1cb 100644
--- a/spec/services/projects/overwrite_project_service_spec.rb
+++ b/spec/services/projects/overwrite_project_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::OverwriteProjectService do
+RSpec.describe Projects::OverwriteProjectService, feature_category: :projects do
include ProjectForksHelper
let(:user) { create(:user) }
diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb
index fc745cd669f..bd297343879 100644
--- a/spec/services/projects/participants_service_spec.rb
+++ b/spec/services/projects/participants_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ParticipantsService do
+RSpec.describe Projects::ParticipantsService, feature_category: :projects do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/services/projects/prometheus/alerts/notify_service_spec.rb b/spec/services/projects/prometheus/alerts/notify_service_spec.rb
index 43d23023d83..d747cc4b424 100644
--- a/spec/services/projects/prometheus/alerts/notify_service_spec.rb
+++ b/spec/services/projects/prometheus/alerts/notify_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::Prometheus::Alerts::NotifyService do
+RSpec.describe Projects::Prometheus::Alerts::NotifyService, feature_category: :metrics do
include PrometheusHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/services/projects/prometheus/metrics/destroy_service_spec.rb b/spec/services/projects/prometheus/metrics/destroy_service_spec.rb
index b4af81f2c87..4c2a959a149 100644
--- a/spec/services/projects/prometheus/metrics/destroy_service_spec.rb
+++ b/spec/services/projects/prometheus/metrics/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::Prometheus::Metrics::DestroyService do
+RSpec.describe Projects::Prometheus::Metrics::DestroyService, feature_category: :metrics do
let(:metric) { create(:prometheus_metric) }
subject { described_class.new(metric) }
diff --git a/spec/services/projects/protect_default_branch_service_spec.rb b/spec/services/projects/protect_default_branch_service_spec.rb
index 9f9e89ff8f8..21743e2a656 100644
--- a/spec/services/projects/protect_default_branch_service_spec.rb
+++ b/spec/services/projects/protect_default_branch_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ProtectDefaultBranchService do
+RSpec.describe Projects::ProtectDefaultBranchService, feature_category: :source_code_management do
let(:service) { described_class.new(project) }
let(:project) { create(:project) }
diff --git a/spec/services/projects/readme_renderer_service_spec.rb b/spec/services/projects/readme_renderer_service_spec.rb
index 14cdcf67640..58b967b7e9c 100644
--- a/spec/services/projects/readme_renderer_service_spec.rb
+++ b/spec/services/projects/readme_renderer_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ReadmeRendererService, '#execute' do
+RSpec.describe Projects::ReadmeRendererService, '#execute', feature_category: :projects do
using RSpec::Parameterized::TableSyntax
subject(:service) { described_class.new(project, nil, opts) }
diff --git a/spec/services/projects/record_target_platforms_service_spec.rb b/spec/services/projects/record_target_platforms_service_spec.rb
index 22ff325a62e..dd4e9fe19e0 100644
--- a/spec/services/projects/record_target_platforms_service_spec.rb
+++ b/spec/services/projects/record_target_platforms_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::RecordTargetPlatformsService, '#execute' do
+RSpec.describe Projects::RecordTargetPlatformsService, '#execute', feature_category: :projects do
let_it_be(:project) { create(:project) }
let(:detector_service) { Projects::AppleTargetPlatformDetectorService }
diff --git a/spec/services/projects/refresh_build_artifacts_size_statistics_service_spec.rb b/spec/services/projects/refresh_build_artifacts_size_statistics_service_spec.rb
index 62330441d2f..591cd1cba8d 100644
--- a/spec/services/projects/refresh_build_artifacts_size_statistics_service_spec.rb
+++ b/spec/services/projects/refresh_build_artifacts_size_statistics_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::RefreshBuildArtifactsSizeStatisticsService, :clean_gitlab_redis_shared_state do
+RSpec.describe Projects::RefreshBuildArtifactsSizeStatisticsService, :clean_gitlab_redis_shared_state, feature_category: :build_artifacts do
let(:service) { described_class.new }
describe '#execute' do
diff --git a/spec/services/projects/repository_languages_service_spec.rb b/spec/services/projects/repository_languages_service_spec.rb
index 50d5fba6b84..a02844309b2 100644
--- a/spec/services/projects/repository_languages_service_spec.rb
+++ b/spec/services/projects/repository_languages_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::RepositoryLanguagesService do
+RSpec.describe Projects::RepositoryLanguagesService, feature_category: :source_code_management do
let(:service) { described_class.new(project, project.first_owner) }
context 'when detected_repository_languages flag is set' do
diff --git a/spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb b/spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb
index 76830396104..3d89f6efa6f 100644
--- a/spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb
+++ b/spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ScheduleBulkRepositoryShardMovesService do
+RSpec.describe Projects::ScheduleBulkRepositoryShardMovesService, feature_category: :source_code_management do
it_behaves_like 'moves repository shard in bulk' do
let_it_be_with_reload(:container) { create(:project, :repository) }
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 32818535146..755ee795ebe 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::TransferService do
+RSpec.describe Projects::TransferService, feature_category: :projects do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:group_integration) { create(:integrations_slack, :group, group: group, webhook: 'http://group.slack.com') }
diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb
index d939a79b7e9..f9fb1f65550 100644
--- a/spec/services/projects/unlink_fork_service_spec.rb
+++ b/spec/services/projects/unlink_fork_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::UnlinkForkService, :use_clean_rails_memory_store_caching do
+RSpec.describe Projects::UnlinkForkService, :use_clean_rails_memory_store_caching, feature_category: :source_code_management do
include ProjectForksHelper
subject { described_class.new(forked_project, user) }
diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb
index d908a169898..8157dce4ce8 100644
--- a/spec/services/projects/update_pages_service_spec.rb
+++ b/spec/services/projects/update_pages_service_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Projects::UpdatePagesService do
+RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
let_it_be(:project, refind: true) { create(:project, :repository) }
let_it_be(:old_pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) }
diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb
index 547641867bc..b65f7a50e4c 100644
--- a/spec/services/projects/update_remote_mirror_service_spec.rb
+++ b/spec/services/projects/update_remote_mirror_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::UpdateRemoteMirrorService do
+RSpec.describe Projects::UpdateRemoteMirrorService, feature_category: :source_code_management do
let_it_be(:project) { create(:project, :repository, lfs_enabled: true) }
let_it_be(:remote_project) { create(:forked_project_with_submodules) }
let_it_be(:remote_mirror) { create(:remote_mirror, project: project, enabled: true) }
diff --git a/spec/services/projects/update_repository_storage_service_spec.rb b/spec/services/projects/update_repository_storage_service_spec.rb
index ee8f7fb2ef2..af920d51776 100644
--- a/spec/services/projects/update_repository_storage_service_spec.rb
+++ b/spec/services/projects/update_repository_storage_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::UpdateRepositoryStorageService do
+RSpec.describe Projects::UpdateRepositoryStorageService, feature_category: :source_code_management do
include Gitlab::ShellAdapter
subject { described_class.new(repository_storage_move) }
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 3cda6bc2627..bdb2e6e09e5 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::UpdateService do
+RSpec.describe Projects::UpdateService, feature_category: :projects do
include ExternalAuthorizationServiceHelpers
include ProjectForksHelper
@@ -227,48 +227,16 @@ RSpec.describe Projects::UpdateService do
let(:user) { project.first_owner }
let(:forked_project) { fork_project(project) }
- context 'and unlink forks feature flag is off' do
- before do
- stub_feature_flags(unlink_fork_network_upon_visibility_decrease: false)
- end
-
- it 'updates forks visibility level when parent set to more restrictive' do
- opts = { visibility_level: Gitlab::VisibilityLevel::PRIVATE }
-
- expect(project).to be_internal
- expect(forked_project).to be_internal
-
- expect(update_project(project, user, opts)).to eq({ status: :success })
-
- expect(project).to be_private
- expect(forked_project.reload).to be_private
- end
-
- it 'does not update forks visibility level when parent set to less restrictive' do
- opts = { visibility_level: Gitlab::VisibilityLevel::PUBLIC }
+ it 'does not change visibility of forks' do
+ opts = { visibility_level: Gitlab::VisibilityLevel::PRIVATE }
- expect(project).to be_internal
- expect(forked_project).to be_internal
+ expect(project).to be_internal
+ expect(forked_project).to be_internal
- expect(update_project(project, user, opts)).to eq({ status: :success })
+ expect(update_project(project, user, opts)).to eq({ status: :success })
- expect(project).to be_public
- expect(forked_project.reload).to be_internal
- end
- end
-
- context 'and unlink forks feature flag is on' do
- it 'does not change visibility of forks' do
- opts = { visibility_level: Gitlab::VisibilityLevel::PRIVATE }
-
- expect(project).to be_internal
- expect(forked_project).to be_internal
-
- expect(update_project(project, user, opts)).to eq({ status: :success })
-
- expect(project).to be_private
- expect(forked_project.reload).to be_internal
- end
+ expect(project).to be_private
+ expect(forked_project.reload).to be_internal
end
end
@@ -794,6 +762,112 @@ RSpec.describe Projects::UpdateService do
expect(project.topic_list).to eq(%w[tag_list])
end
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) }
+
+ context 'with pages_unique_domain feature flag disabled' do
+ before do
+ stub_feature_flags(pages_unique_domain: false)
+ end
+
+ it 'does not change pages unique domain' do
+ expect(project)
+ .to receive(:update)
+ .with({ project_setting_attributes: { has_confluence: true } })
+ .and_call_original
+
+ expect do
+ update_project(project, user, project_setting_attributes: {
+ has_confluence: true,
+ pages_unique_domain_enabled: true
+ })
+ end.not_to change { project.project_setting.pages_unique_domain_enabled }
+ end
+
+ it 'does not remove other attributes' do
+ expect(project)
+ .to receive(:update)
+ .with({ name: 'True' })
+ .and_call_original
+
+ update_project(project, user, name: 'True')
+ end
+ end
+
+ context 'with pages_unique_domain feature flag enabled' do
+ before do
+ stub_feature_flags(pages_unique_domain: true)
+ end
+
+ 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'
+ 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 }
+
+ expect(project.project_setting.pages_unique_domain_enabled).to eq false
+ expect(project.project_setting.pages_unique_domain).to eq 'unique-domain'
+ 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')
+
+ 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'
+ )
+ end
+ end
+ end
+ end
end
describe '#run_auto_devops_pipeline?' do
diff --git a/spec/services/projects/update_statistics_service_spec.rb b/spec/services/projects/update_statistics_service_spec.rb
index 1cc69e7e2fe..313e1c29cd2 100644
--- a/spec/services/projects/update_statistics_service_spec.rb
+++ b/spec/services/projects/update_statistics_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::UpdateStatisticsService do
+RSpec.describe Projects::UpdateStatisticsService, feature_category: :projects do
using RSpec::Parameterized::TableSyntax
let(:service) { described_class.new(project, nil, statistics: statistics) }
diff --git a/spec/services/prometheus/proxy_service_spec.rb b/spec/services/prometheus/proxy_service_spec.rb
index b78683cace7..f71662f62ad 100644
--- a/spec/services/prometheus/proxy_service_spec.rb
+++ b/spec/services/prometheus/proxy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Prometheus::ProxyService do
+RSpec.describe Prometheus::ProxyService, feature_category: :metrics do
include ReactiveCachingHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/services/prometheus/proxy_variable_substitution_service_spec.rb b/spec/services/prometheus/proxy_variable_substitution_service_spec.rb
index d8c1fdffb98..fbee4b9c7d7 100644
--- a/spec/services/prometheus/proxy_variable_substitution_service_spec.rb
+++ b/spec/services/prometheus/proxy_variable_substitution_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Prometheus::ProxyVariableSubstitutionService do
+RSpec.describe Prometheus::ProxyVariableSubstitutionService, feature_category: :metrics do
describe '#execute' do
let_it_be(:environment) { create(:environment) }
diff --git a/spec/services/protected_branches/api_service_spec.rb b/spec/services/protected_branches/api_service_spec.rb
index c98e253267b..f7f5f451a49 100644
--- a/spec/services/protected_branches/api_service_spec.rb
+++ b/spec/services/protected_branches/api_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProtectedBranches::ApiService do
+RSpec.describe ProtectedBranches::ApiService, feature_category: :compliance_management do
shared_examples 'execute with entity' do
it 'creates a protected branch with prefilled defaults' do
expect(::ProtectedBranches::CreateService).to receive(:new).with(
diff --git a/spec/services/protected_branches/cache_service_spec.rb b/spec/services/protected_branches/cache_service_spec.rb
index ea434922661..3aa3b56640b 100644
--- a/spec/services/protected_branches/cache_service_spec.rb
+++ b/spec/services/protected_branches/cache_service_spec.rb
@@ -3,7 +3,7 @@
#
require 'spec_helper'
-RSpec.describe ProtectedBranches::CacheService, :clean_gitlab_redis_cache do
+RSpec.describe ProtectedBranches::CacheService, :clean_gitlab_redis_cache, feature_category: :compliance_management do
shared_examples 'execute with entity' do
subject(:service) { described_class.new(entity, user) }
diff --git a/spec/services/protected_branches/destroy_service_spec.rb b/spec/services/protected_branches/destroy_service_spec.rb
index 421d4aae5bb..e02b4475c02 100644
--- a/spec/services/protected_branches/destroy_service_spec.rb
+++ b/spec/services/protected_branches/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProtectedBranches::DestroyService do
+RSpec.describe ProtectedBranches::DestroyService, feature_category: :compliance_management do
shared_examples 'execute with entity' do
subject(:service) { described_class.new(entity, user) }
diff --git a/spec/services/protected_branches/update_service_spec.rb b/spec/services/protected_branches/update_service_spec.rb
index c70cc032a6a..8b11604aa15 100644
--- a/spec/services/protected_branches/update_service_spec.rb
+++ b/spec/services/protected_branches/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProtectedBranches::UpdateService do
+RSpec.describe ProtectedBranches::UpdateService, feature_category: :compliance_management do
shared_examples 'execute with entity' do
let(:params) { { name: new_name } }
diff --git a/spec/services/protected_tags/create_service_spec.rb b/spec/services/protected_tags/create_service_spec.rb
index a0b99b595e3..78b14aae029 100644
--- a/spec/services/protected_tags/create_service_spec.rb
+++ b/spec/services/protected_tags/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProtectedTags::CreateService do
+RSpec.describe ProtectedTags::CreateService, feature_category: :compliance_management do
let(:project) { create(:project) }
let(:user) { project.first_owner }
let(:params) do
diff --git a/spec/services/protected_tags/destroy_service_spec.rb b/spec/services/protected_tags/destroy_service_spec.rb
index 658a4f5557e..fcb30d39520 100644
--- a/spec/services/protected_tags/destroy_service_spec.rb
+++ b/spec/services/protected_tags/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProtectedTags::DestroyService do
+RSpec.describe ProtectedTags::DestroyService, feature_category: :compliance_management do
let(:protected_tag) { create(:protected_tag) }
let(:project) { protected_tag.project }
let(:user) { project.first_owner }
diff --git a/spec/services/protected_tags/update_service_spec.rb b/spec/services/protected_tags/update_service_spec.rb
index 4b6e726bb6e..2fb6cf84719 100644
--- a/spec/services/protected_tags/update_service_spec.rb
+++ b/spec/services/protected_tags/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProtectedTags::UpdateService do
+RSpec.describe ProtectedTags::UpdateService, feature_category: :compliance_management do
let(:protected_tag) { create(:protected_tag) }
let(:project) { protected_tag.project }
let(:user) { project.first_owner }
diff --git a/spec/services/push_event_payload_service_spec.rb b/spec/services/push_event_payload_service_spec.rb
index de2bec21a3c..50da5ca9b24 100644
--- a/spec/services/push_event_payload_service_spec.rb
+++ b/spec/services/push_event_payload_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PushEventPayloadService do
+RSpec.describe PushEventPayloadService, feature_category: :source_code_management do
let(:event) { create(:push_event) }
describe '#execute' do
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 257e7eb972b..b8abfd1e6ba 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -746,10 +746,10 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
it 'assigns to users with escaped underscores' do
user = create(:user)
base = user.username
- user.update!(username: "#{base}_")
+ user.update!(username: "#{base}_new")
issuable.project.add_developer(user)
- cmd = "/assign @#{base}\\_"
+ cmd = "/assign @#{base}\\_new"
_, updates, _ = service.execute(cmd, issuable)
diff --git a/spec/services/quick_actions/target_service_spec.rb b/spec/services/quick_actions/target_service_spec.rb
index 1b0a5d4ae73..5f4e92cf955 100644
--- a/spec/services/quick_actions/target_service_spec.rb
+++ b/spec/services/quick_actions/target_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe QuickActions::TargetService do
+RSpec.describe QuickActions::TargetService, feature_category: :team_planning do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:service) { described_class.new(project, user) }
diff --git a/spec/services/releases/create_evidence_service_spec.rb b/spec/services/releases/create_evidence_service_spec.rb
index 0ac15a7291d..75d0a2b9c0e 100644
--- a/spec/services/releases/create_evidence_service_spec.rb
+++ b/spec/services/releases/create_evidence_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Releases::CreateEvidenceService do
+RSpec.describe Releases::CreateEvidenceService, feature_category: :release_orchestration do
let_it_be(:project) { create(:project) }
let(:release) { create(:release, project: project) }
diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb
index 46550ac5bef..953490ac379 100644
--- a/spec/services/releases/destroy_service_spec.rb
+++ b/spec/services/releases/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Releases::DestroyService do
+RSpec.describe Releases::DestroyService, feature_category: :release_orchestration do
let(:project) { create(:project, :repository) }
let(:mainatiner) { create(:user) }
let(:repoter) { create(:user) }
diff --git a/spec/services/releases/links/create_service_spec.rb b/spec/services/releases/links/create_service_spec.rb
new file mode 100644
index 00000000000..9928d2162d7
--- /dev/null
+++ b/spec/services/releases/links/create_service_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Releases::Links::CreateService, feature_category: :release_orchestration do
+ let(:service) { described_class.new(release, user, params) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:release) { create(:release, project: project, author: user, tag: 'v1.1.0') }
+
+ let(:params) { { name: name, url: url, direct_asset_path: direct_asset_path, link_type: link_type } }
+ let(:name) { 'link' }
+ let(:url) { 'https://example.com' }
+ let(:direct_asset_path) { '/path' }
+ let(:link_type) { 'other' }
+
+ before do
+ project.add_developer(user)
+ end
+
+ describe '#execute' do
+ subject(:execute) { service.execute }
+
+ let(:link) { subject.payload[:link] }
+
+ it 'successfully creates a release link' do
+ expect { execute }.to change { Releases::Link.count }.by(1)
+
+ expect(link).to have_attributes(
+ name: name,
+ url: url,
+ filepath: direct_asset_path,
+ link_type: link_type
+ )
+ end
+
+ context 'when user does not have access to create release link' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns an error' do
+ expect { execute }.not_to change { Releases::Link.count }
+
+ is_expected.to be_error
+ expect(execute.message).to include('Access Denied')
+ expect(execute.reason).to eq(:forbidden)
+ end
+ end
+
+ context 'when url is invalid' do
+ let(:url) { 'not_a_url' }
+
+ it 'returns an error' do
+ expect { execute }.not_to change { Releases::Link.count }
+
+ is_expected.to be_error
+ expect(execute.message[0]).to include('Url is blocked')
+ expect(execute.reason).to eq(:bad_request)
+ end
+ end
+
+ context 'when both direct_asset_path and filepath are provided' do
+ let(:params) { super().merge(filepath: '/filepath') }
+
+ it 'prefers direct_asset_path' do
+ is_expected.to be_success
+
+ expect(link.filepath).to eq(direct_asset_path)
+ end
+ end
+
+ context 'when only filepath is set' do
+ let(:params) { super().merge(filepath: '/filepath') }
+ let(:direct_asset_path) { nil }
+
+ it 'uses filepath' do
+ is_expected.to be_success
+
+ expect(link.filepath).to eq('/filepath')
+ end
+ end
+ end
+end
diff --git a/spec/services/releases/links/destroy_service_spec.rb b/spec/services/releases/links/destroy_service_spec.rb
new file mode 100644
index 00000000000..a248932eada
--- /dev/null
+++ b/spec/services/releases/links/destroy_service_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Releases::Links::DestroyService, feature_category: :release_orchestration do
+ let(:service) { described_class.new(release, user, {}) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:release) { create(:release, project: project, author: user, tag: 'v1.1.0') }
+
+ let!(:release_link) do
+ create(
+ :release_link,
+ release: release,
+ name: 'awesome-app.dmg',
+ url: 'https://example.com/download/awesome-app.dmg'
+ )
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ describe '#execute' do
+ subject(:execute) { service.execute(release_link) }
+
+ it 'successfully deletes a release link' do
+ expect { execute }.to change { release.links.count }.by(-1)
+
+ is_expected.to be_success
+ end
+
+ context 'when user does not have access to delete release link' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns an error' do
+ expect { execute }.not_to change { release.links.count }
+
+ is_expected.to be_error
+ expect(execute.message).to include('Access Denied')
+ expect(execute.reason).to eq(:forbidden)
+ end
+ end
+
+ context 'when release link does not exist' do
+ let(:release_link) { nil }
+
+ it 'returns an error' do
+ expect { execute }.not_to change { release.links.count }
+
+ is_expected.to be_error
+ expect(execute.message).to eq('Link does not exist')
+ expect(execute.reason).to eq(:not_found)
+ end
+ end
+
+ context 'when release link deletion failed' do
+ before do
+ allow(release_link).to receive(:destroy).and_return(false)
+ end
+
+ it 'returns an error' do
+ expect { execute }.not_to change { release.links.count }
+
+ is_expected.to be_error
+ expect(execute.reason).to eq(:bad_request)
+ end
+ end
+ end
+end
diff --git a/spec/services/releases/links/update_service_spec.rb b/spec/services/releases/links/update_service_spec.rb
new file mode 100644
index 00000000000..3f48985cf60
--- /dev/null
+++ b/spec/services/releases/links/update_service_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Releases::Links::UpdateService, feature_category: :release_orchestration do
+ let(:service) { described_class.new(release, user, params) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:release) { create(:release, project: project, author: user, tag: 'v1.1.0') }
+
+ let(:release_link) do
+ create(
+ :release_link,
+ release: release,
+ name: 'awesome-app.dmg',
+ url: 'https://example.com/download/awesome-app.dmg'
+ )
+ end
+
+ let(:params) { { name: name, url: url, direct_asset_path: direct_asset_path, link_type: link_type } }
+ let(:name) { 'link' }
+ let(:url) { 'https://example.com' }
+ let(:direct_asset_path) { '/path' }
+ let(:link_type) { 'other' }
+
+ before do
+ project.add_developer(user)
+ end
+
+ describe '#execute' do
+ subject(:execute) { service.execute(release_link) }
+
+ let(:updated_link) { execute.payload[:link] }
+
+ it 'successfully updates a release link' do
+ is_expected.to be_success
+
+ expect(updated_link).to have_attributes(
+ name: name,
+ url: url,
+ filepath: direct_asset_path,
+ link_type: link_type
+ )
+ end
+
+ context 'when user does not have access to update release link' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns an error' do
+ is_expected.to be_error
+ expect(execute.message).to include('Access Denied')
+ expect(execute.reason).to eq(:forbidden)
+ end
+ end
+
+ context 'when url is invalid' do
+ let(:url) { 'not_a_url' }
+
+ it 'returns an error' do
+ is_expected.to be_error
+ expect(execute.message[0]).to include('Url is blocked')
+ expect(execute.reason).to eq(:bad_request)
+ end
+ end
+
+ context 'when both direct_asset_path and filepath are provided' do
+ let(:params) { super().merge(filepath: '/filepath') }
+
+ it 'prefers direct_asset_path' do
+ is_expected.to be_success
+
+ expect(updated_link.filepath).to eq(direct_asset_path)
+ end
+ end
+
+ context 'when only filepath is set' do
+ let(:params) { super().merge(filepath: '/filepath') }
+ let(:direct_asset_path) { nil }
+
+ it 'uses filepath' do
+ is_expected.to be_success
+
+ expect(updated_link.filepath).to eq('/filepath')
+ end
+ end
+ end
+end
diff --git a/spec/services/repositories/changelog_service_spec.rb b/spec/services/repositories/changelog_service_spec.rb
index 42b586637ad..1b5300672e3 100644
--- a/spec/services/repositories/changelog_service_spec.rb
+++ b/spec/services/repositories/changelog_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Repositories::ChangelogService do
+RSpec.describe Repositories::ChangelogService, feature_category: :source_code_management do
describe '#execute' do
let!(:project) { create(:project, :empty_repo) }
let!(:creator) { project.creator }
diff --git a/spec/services/repositories/destroy_service_spec.rb b/spec/services/repositories/destroy_service_spec.rb
index 565a18d501a..b3bad4fd84d 100644
--- a/spec/services/repositories/destroy_service_spec.rb
+++ b/spec/services/repositories/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Repositories::DestroyService do
+RSpec.describe Repositories::DestroyService, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
let!(:project) { create(:project, :repository, namespace: user.namespace) }
diff --git a/spec/services/repository_archive_clean_up_service_spec.rb b/spec/services/repository_archive_clean_up_service_spec.rb
index 8db1a6858fa..1ce68080c73 100644
--- a/spec/services/repository_archive_clean_up_service_spec.rb
+++ b/spec/services/repository_archive_clean_up_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RepositoryArchiveCleanUpService do
+RSpec.describe RepositoryArchiveCleanUpService, feature_category: :source_code_management do
subject(:service) { described_class.new }
describe '#execute (new archive locations)' do
diff --git a/spec/services/reset_project_cache_service_spec.rb b/spec/services/reset_project_cache_service_spec.rb
index 165b38ee338..6ae516a5f07 100644
--- a/spec/services/reset_project_cache_service_spec.rb
+++ b/spec/services/reset_project_cache_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResetProjectCacheService do
+RSpec.describe ResetProjectCacheService, feature_category: :projects do
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/services/resource_access_tokens/create_service_spec.rb b/spec/services/resource_access_tokens/create_service_spec.rb
index a8c8d41ca09..464fc18f1f0 100644
--- a/spec/services/resource_access_tokens/create_service_spec.rb
+++ b/spec/services/resource_access_tokens/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResourceAccessTokens::CreateService do
+RSpec.describe ResourceAccessTokens::CreateService, feature_category: :system_access do
subject { described_class.new(user, resource, params).execute }
let_it_be(:user) { create(:user) }
@@ -99,12 +99,20 @@ RSpec.describe ResourceAccessTokens::CreateService do
end
end
- context 'bot email' do
- it 'check email domain' do
- response = subject
- access_token = response.payload[:access_token]
+ context 'bot username and email' do
+ include_examples 'username and email pair is generated by Gitlab::Utils::UsernameAndEmailGenerator' do
+ subject do
+ response = described_class.new(user, resource, params).execute
+ response.payload[:access_token].user
+ end
+
+ let(:username_prefix) do
+ "#{resource.class.name.downcase}_#{resource.id}_bot"
+ end
- expect(access_token.user.email).to end_with("@noreply.#{Gitlab.config.gitlab.host}")
+ let(:email_domain) do
+ "noreply.#{Gitlab.config.gitlab.host}"
+ end
end
end
@@ -119,9 +127,7 @@ RSpec.describe ResourceAccessTokens::CreateService do
end
end
- context 'when user specifies an access level' do
- let_it_be(:params) { { access_level: Gitlab::Access::DEVELOPER } }
-
+ shared_examples 'bot with access level' do
it 'adds the bot user with the specified access level in the resource' do
response = subject
access_token = response.payload[:access_token]
@@ -131,6 +137,18 @@ RSpec.describe ResourceAccessTokens::CreateService do
end
end
+ context 'when user specifies an access level' do
+ let_it_be(:params) { { access_level: Gitlab::Access::DEVELOPER } }
+
+ it_behaves_like 'bot with access level'
+ end
+
+ context 'with DEVELOPER access_level, in string format' do
+ let_it_be(:params) { { access_level: Gitlab::Access::DEVELOPER.to_s } }
+
+ it_behaves_like 'bot with access level'
+ end
+
context 'when user is external' do
before do
user.update!(external: true)
@@ -219,17 +237,31 @@ RSpec.describe ResourceAccessTokens::CreateService do
let_it_be(:bot_user) { create(:user, :project_bot) }
let(:unpersisted_member) { build(:project_member, source: resource, user: bot_user) }
- let(:error_message) { 'Could not provision maintainer access to project access token' }
+ let(:error_message) { 'Could not provision maintainer access to the access token. ERROR: error message' }
before do
allow_next_instance_of(ResourceAccessTokens::CreateService) do |service|
allow(service).to receive(:create_user).and_return(bot_user)
allow(service).to receive(:create_membership).and_return(unpersisted_member)
end
+
+ allow(unpersisted_member).to receive_message_chain(:errors, :full_messages, :to_sentence)
+ .and_return('error message')
+ end
+
+ context 'with MAINTAINER access_level, in integer format' do
+ let_it_be(:params) { { access_level: Gitlab::Access::MAINTAINER } }
+
+ it_behaves_like 'token creation fails'
+ it_behaves_like 'correct error message'
end
- it_behaves_like 'token creation fails'
- it_behaves_like 'correct error message'
+ context 'with MAINTAINER access_level, in string format' do
+ let_it_be(:params) { { access_level: Gitlab::Access::MAINTAINER.to_s } }
+
+ it_behaves_like 'token creation fails'
+ it_behaves_like 'correct error message'
+ end
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 28f173f1bc7..c00146961e3 100644
--- a/spec/services/resource_access_tokens/revoke_service_spec.rb
+++ b/spec/services/resource_access_tokens/revoke_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResourceAccessTokens::RevokeService do
+RSpec.describe ResourceAccessTokens::RevokeService, feature_category: :system_access do
subject { described_class.new(user, resource, access_token).execute }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/resource_events/change_labels_service_spec.rb b/spec/services/resource_events/change_labels_service_spec.rb
index d94b49de9d7..8393ce78df8 100644
--- a/spec/services/resource_events/change_labels_service_spec.rb
+++ b/spec/services/resource_events/change_labels_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# feature category is shared among plan(issues, epics), monitor(incidents), create(merge request) stages
-RSpec.describe ResourceEvents::ChangeLabelsService, feature_category: :shared do
+RSpec.describe ResourceEvents::ChangeLabelsService, feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:author) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/services/resource_events/change_milestone_service_spec.rb b/spec/services/resource_events/change_milestone_service_spec.rb
index 425d5b19907..077058df1d5 100644
--- a/spec/services/resource_events/change_milestone_service_spec.rb
+++ b/spec/services/resource_events/change_milestone_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResourceEvents::ChangeMilestoneService do
+RSpec.describe ResourceEvents::ChangeMilestoneService, feature_category: :team_planning do
let_it_be(:timebox) { create(:milestone) }
let(:created_at_time) { Time.utc(2019, 12, 30) }
diff --git a/spec/services/resource_events/change_state_service_spec.rb b/spec/services/resource_events/change_state_service_spec.rb
index b679943073c..a63b4302635 100644
--- a/spec/services/resource_events/change_state_service_spec.rb
+++ b/spec/services/resource_events/change_state_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResourceEvents::ChangeStateService do
+RSpec.describe ResourceEvents::ChangeStateService, feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
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 ebfd942066f..6eb6780d704 100644
--- a/spec/services/resource_events/merge_into_notes_service_spec.rb
+++ b/spec/services/resource_events/merge_into_notes_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResourceEvents::MergeIntoNotesService do
+RSpec.describe ResourceEvents::MergeIntoNotesService, feature_category: :team_planning do
def create_event(params)
event_params = { action: :add, label: label, issue: resource,
user: user }
diff --git a/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb b/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb
index 71b1d0993ee..3396abaff9e 100644
--- a/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb
+++ b/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResourceEvents::SyntheticLabelNotesBuilderService do
+RSpec.describe ResourceEvents::SyntheticLabelNotesBuilderService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:user) { create(:user) }
diff --git a/spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb b/spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb
index f368e107c60..ca61afc7914 100644
--- a/spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb
+++ b/spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResourceEvents::SyntheticMilestoneNotesBuilderService do
+RSpec.describe ResourceEvents::SyntheticMilestoneNotesBuilderService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue, author: user) }
diff --git a/spec/services/resource_events/synthetic_state_notes_builder_service_spec.rb b/spec/services/resource_events/synthetic_state_notes_builder_service_spec.rb
index 79500f3768b..9f838660f92 100644
--- a/spec/services/resource_events/synthetic_state_notes_builder_service_spec.rb
+++ b/spec/services/resource_events/synthetic_state_notes_builder_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ResourceEvents::SyntheticStateNotesBuilderService do
+RSpec.describe ResourceEvents::SyntheticStateNotesBuilderService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:user) { create(:user) }
diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb
index e8716ef4d90..6250d32574f 100644
--- a/spec/services/search/global_service_spec.rb
+++ b/spec/services/search/global_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Search::GlobalService do
+RSpec.describe Search::GlobalService, feature_category: :global_search do
let(:user) { create(:user) }
let(:internal_user) { create(:user) }
diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb
index c9bfa7cb7b4..e8a4a228f8f 100644
--- a/spec/services/search/group_service_spec.rb
+++ b/spec/services/search/group_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Search::GroupService do
+RSpec.describe Search::GroupService, feature_category: :global_search do
shared_examples_for 'group search' do
context 'finding projects by name' do
let(:user) { create(:user) }
diff --git a/spec/services/search/snippet_service_spec.rb b/spec/services/search/snippet_service_spec.rb
index d204f626635..d60b60d28e4 100644
--- a/spec/services/search/snippet_service_spec.rb
+++ b/spec/services/search/snippet_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Search::SnippetService do
+RSpec.describe Search::SnippetService, feature_category: :global_search do
let_it_be(:author) { create(:author) }
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/services/security/ci_configuration/container_scanning_create_service_spec.rb b/spec/services/security/ci_configuration/container_scanning_create_service_spec.rb
index df76750efc8..a56fbb026c1 100644
--- a/spec/services/security/ci_configuration/container_scanning_create_service_spec.rb
+++ b/spec/services/security/ci_configuration/container_scanning_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Security::CiConfiguration::ContainerScanningCreateService, :snowplow do
+RSpec.describe Security::CiConfiguration::ContainerScanningCreateService, :snowplow, feature_category: :container_scanning do
subject(:result) { described_class.new(project, user).execute }
let(:branch_name) { 'set-container-scanning-config-1' }
diff --git a/spec/services/security/ci_configuration/sast_iac_create_service_spec.rb b/spec/services/security/ci_configuration/sast_iac_create_service_spec.rb
index deb10732b37..7f1ad543f7c 100644
--- a/spec/services/security/ci_configuration/sast_iac_create_service_spec.rb
+++ b/spec/services/security/ci_configuration/sast_iac_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Security::CiConfiguration::SastIacCreateService, :snowplow do
+RSpec.describe Security::CiConfiguration::SastIacCreateService, :snowplow, feature_category: :static_application_security_testing do
subject(:result) { described_class.new(project, user).execute }
let(:branch_name) { 'set-sast-iac-config-1' }
diff --git a/spec/services/security/ci_configuration/sast_parser_service_spec.rb b/spec/services/security/ci_configuration/sast_parser_service_spec.rb
index 9211beb76f8..051bbcd194b 100644
--- a/spec/services/security/ci_configuration/sast_parser_service_spec.rb
+++ b/spec/services/security/ci_configuration/sast_parser_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Security::CiConfiguration::SastParserService do
+RSpec.describe Security::CiConfiguration::SastParserService, feature_category: :static_application_security_testing do
describe '#configuration' do
include_context 'read ci configuration for sast enabled project'
diff --git a/spec/services/security/ci_configuration/secret_detection_create_service_spec.rb b/spec/services/security/ci_configuration/secret_detection_create_service_spec.rb
index c1df3ebdca5..6cbeb219d11 100644
--- a/spec/services/security/ci_configuration/secret_detection_create_service_spec.rb
+++ b/spec/services/security/ci_configuration/secret_detection_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Security::CiConfiguration::SecretDetectionCreateService, :snowplow do
+RSpec.describe Security::CiConfiguration::SecretDetectionCreateService, :snowplow, feature_category: :container_scanning do
subject(:result) { described_class.new(project, user).execute }
let(:branch_name) { 'set-secret-detection-config-1' }
diff --git a/spec/services/security/merge_reports_service_spec.rb b/spec/services/security/merge_reports_service_spec.rb
index 249f4da5f34..809d0b27c20 100644
--- a/spec/services/security/merge_reports_service_spec.rb
+++ b/spec/services/security/merge_reports_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# rubocop: disable RSpec/MultipleMemoizedHelpers
-RSpec.describe Security::MergeReportsService, '#execute' do
+RSpec.describe Security::MergeReportsService, '#execute', feature_category: :code_review_workflow do
let(:scanner_1) { build(:ci_reports_security_scanner, external_id: 'scanner-1', name: 'Scanner 1') }
let(:scanner_2) { build(:ci_reports_security_scanner, external_id: 'scanner-2', name: 'Scanner 2') }
let(:scanner_3) { build(:ci_reports_security_scanner, external_id: 'scanner-3', name: 'Scanner 3') }
diff --git a/spec/services/serverless/associate_domain_service_spec.rb b/spec/services/serverless/associate_domain_service_spec.rb
deleted file mode 100644
index 2f45806589e..00000000000
--- a/spec/services/serverless/associate_domain_service_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Serverless::AssociateDomainService do
- let_it_be(:sdc_pages_domain) { create(:pages_domain, :instance_serverless) }
- let_it_be(:sdc_cluster) { create(:cluster, :with_installed_helm, :provided_by_gcp) }
- let_it_be(:sdc_knative) { create(:clusters_applications_knative, cluster: sdc_cluster) }
- let_it_be(:sdc_creator) { create(:user) }
-
- let(:sdc) do
- create(:serverless_domain_cluster,
- knative: sdc_knative,
- creator: sdc_creator,
- pages_domain: sdc_pages_domain)
- end
-
- let(:knative) { sdc.knative }
- let(:creator) { sdc.creator }
- let(:pages_domain_id) { sdc.pages_domain_id }
-
- subject { described_class.new(knative, pages_domain_id: pages_domain_id, creator: creator) }
-
- context 'when the domain is unchanged' do
- let(:creator) { create(:user) }
-
- it 'does not update creator' do
- expect { subject.execute }.not_to change { sdc.reload.creator }
- end
- end
-
- context 'when domain is changed to nil' do
- let_it_be(:creator) { create(:user) }
- let_it_be(:pages_domain_id) { nil }
-
- it 'removes the association between knative and the domain' do
- expect { subject.execute }.to change { knative.reload.pages_domain }.from(sdc.pages_domain).to(nil)
- end
-
- it 'does not attempt to update creator' do
- expect { subject.execute }.not_to raise_error
- end
- end
-
- context 'when a new domain is associated' do
- let_it_be(:creator) { create(:user) }
- let_it_be(:pages_domain_id) { create(:pages_domain, :instance_serverless).id }
-
- it 'creates an association with the domain' do
- expect { subject.execute }.to change { knative.reload.pages_domain.id }
- .from(sdc.pages_domain.id)
- .to(pages_domain_id)
- end
-
- it 'updates creator' do
- expect { subject.execute }.to change { sdc.reload.creator }.from(sdc.creator).to(creator)
- end
- end
-
- context 'when knative is not authorized to use the pages domain' do
- let_it_be(:pages_domain_id) { create(:pages_domain).id }
-
- before do
- expect(knative).to receive(:available_domains).and_return(PagesDomain.none)
- end
-
- it 'sets pages_domain_id to nil' do
- expect { subject.execute }.to change { knative.reload.pages_domain }.from(sdc.pages_domain).to(nil)
- end
- end
-
- describe 'for new knative application' do
- let_it_be(:cluster) { create(:cluster, :with_installed_helm, :provided_by_gcp) }
-
- context 'when knative hostname is nil' do
- let(:knative) { build(:clusters_applications_knative, cluster: cluster, hostname: nil) }
-
- it 'sets hostname to a placeholder value' do
- expect { subject.execute }.to change { knative.hostname }.to('example.com')
- end
- end
-
- context 'when knative hostname exists' do
- let(:knative) { build(:clusters_applications_knative, cluster: cluster, hostname: 'hostname.com') }
-
- it 'does not change hostname' do
- expect { subject.execute }.not_to change { knative.hostname }
- end
- end
- end
-end
diff --git a/spec/services/service_desk_settings/update_service_spec.rb b/spec/services/service_desk_settings/update_service_spec.rb
index 72134af1369..342fb2b6b7a 100644
--- a/spec/services/service_desk_settings/update_service_spec.rb
+++ b/spec/services/service_desk_settings/update_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe ServiceDeskSettings::UpdateService do
+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(:user) { create(:user) }
diff --git a/spec/services/service_ping/submit_service_ping_service_spec.rb b/spec/services/service_ping/submit_service_ping_service_spec.rb
index b02f1e84d25..2248febda5c 100644
--- a/spec/services/service_ping/submit_service_ping_service_spec.rb
+++ b/spec/services/service_ping/submit_service_ping_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ServicePing::SubmitService do
+RSpec.describe ServicePing::SubmitService, feature_category: :service_ping do
include StubRequests
include UsageDataHelpers
diff --git a/spec/services/service_response_spec.rb b/spec/services/service_response_spec.rb
index 58dd2fd4c5e..6171ca1a8a6 100644
--- a/spec/services/service_response_spec.rb
+++ b/spec/services/service_response_spec.rb
@@ -7,7 +7,7 @@ require 're2'
require_relative '../../app/services/service_response'
require_relative '../../lib/gitlab/error_tracking'
-RSpec.describe ServiceResponse do
+RSpec.describe ServiceResponse, feature_category: :shared do
describe '.success' do
it 'creates a successful response without a message' do
expect(described_class.success).to be_success
diff --git a/spec/services/snippets/bulk_destroy_service_spec.rb b/spec/services/snippets/bulk_destroy_service_spec.rb
index 4142aa349e4..208386aee48 100644
--- a/spec/services/snippets/bulk_destroy_service_spec.rb
+++ b/spec/services/snippets/bulk_destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::BulkDestroyService do
+RSpec.describe Snippets::BulkDestroyService, feature_category: :source_code_management do
let_it_be(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/services/snippets/count_service_spec.rb b/spec/services/snippets/count_service_spec.rb
index 5ce637d0bac..4ad9b07d518 100644
--- a/spec/services/snippets/count_service_spec.rb
+++ b/spec/services/snippets/count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::CountService do
+RSpec.describe Snippets::CountService, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/services/snippets/create_service_spec.rb b/spec/services/snippets/create_service_spec.rb
index 0eb73c8edd2..725f1b165a2 100644
--- a/spec/services/snippets/create_service_spec.rb
+++ b/spec/services/snippets/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::CreateService do
+RSpec.describe Snippets::CreateService, feature_category: :source_code_management do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }
diff --git a/spec/services/snippets/destroy_service_spec.rb b/spec/services/snippets/destroy_service_spec.rb
index 23765243dd6..d78b5429189 100644
--- a/spec/services/snippets/destroy_service_spec.rb
+++ b/spec/services/snippets/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::DestroyService do
+RSpec.describe Snippets::DestroyService, feature_category: :source_code_management do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:other_user) { create(:user) }
diff --git a/spec/services/snippets/repository_validation_service_spec.rb b/spec/services/snippets/repository_validation_service_spec.rb
index 8166ce144e1..c9cd9f21481 100644
--- a/spec/services/snippets/repository_validation_service_spec.rb
+++ b/spec/services/snippets/repository_validation_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::RepositoryValidationService do
+RSpec.describe Snippets::RepositoryValidationService, feature_category: :source_code_management do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:snippet) { create(:personal_snippet, :empty_repo, author: user) }
diff --git a/spec/services/snippets/schedule_bulk_repository_shard_moves_service_spec.rb b/spec/services/snippets/schedule_bulk_repository_shard_moves_service_spec.rb
index 9286d73ed4a..e88969ccf2d 100644
--- a/spec/services/snippets/schedule_bulk_repository_shard_moves_service_spec.rb
+++ b/spec/services/snippets/schedule_bulk_repository_shard_moves_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::ScheduleBulkRepositoryShardMovesService do
+RSpec.describe Snippets::ScheduleBulkRepositoryShardMovesService, feature_category: :source_code_management do
it_behaves_like 'moves repository shard in bulk' do
let_it_be_with_reload(:container) { create(:snippet, :repository) }
diff --git a/spec/services/snippets/update_repository_storage_service_spec.rb b/spec/services/snippets/update_repository_storage_service_spec.rb
index 9874189f73a..c417fbfd8b1 100644
--- a/spec/services/snippets/update_repository_storage_service_spec.rb
+++ b/spec/services/snippets/update_repository_storage_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::UpdateRepositoryStorageService do
+RSpec.describe Snippets::UpdateRepositoryStorageService, feature_category: :source_code_management do
subject { described_class.new(repository_storage_move) }
describe "#execute" do
diff --git a/spec/services/snippets/update_service_spec.rb b/spec/services/snippets/update_service_spec.rb
index 67cc258b4b6..99bb70a3077 100644
--- a/spec/services/snippets/update_service_spec.rb
+++ b/spec/services/snippets/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::UpdateService do
+RSpec.describe Snippets::UpdateService, feature_category: :source_code_management do
describe '#execute', :aggregate_failures do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create :user, admin: true }
diff --git a/spec/services/snippets/update_statistics_service_spec.rb b/spec/services/snippets/update_statistics_service_spec.rb
index 27ae054676a..2d1872a09c4 100644
--- a/spec/services/snippets/update_statistics_service_spec.rb
+++ b/spec/services/snippets/update_statistics_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::UpdateStatisticsService do
+RSpec.describe Snippets::UpdateStatisticsService, feature_category: :source_code_management do
describe '#execute' do
subject { described_class.new(snippet).execute }
diff --git a/spec/services/spam/akismet_mark_as_spam_service_spec.rb b/spec/services/spam/akismet_mark_as_spam_service_spec.rb
index 12666e23e47..f07fa8d262b 100644
--- a/spec/services/spam/akismet_mark_as_spam_service_spec.rb
+++ b/spec/services/spam/akismet_mark_as_spam_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Spam::AkismetMarkAsSpamService do
+RSpec.describe Spam::AkismetMarkAsSpamService, feature_category: :instance_resiliency do
let(:user_agent_detail) { build(:user_agent_detail) }
let(:spammable) { build(:issue, user_agent_detail: user_agent_detail) }
let(:fake_akismet_service) { double(:akismet_service, submit_spam: true) }
diff --git a/spec/services/spam/akismet_service_spec.rb b/spec/services/spam/akismet_service_spec.rb
index d9f62258a53..4d6a1650327 100644
--- a/spec/services/spam/akismet_service_spec.rb
+++ b/spec/services/spam/akismet_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Spam::AkismetService do
+RSpec.describe Spam::AkismetService, feature_category: :instance_resiliency do
let(:fake_akismet_client) { double(:akismet_client) }
let(:ip) { '1.2.3.4' }
let(:user_agent) { 'some user_agent' }
diff --git a/spec/services/spam/ham_service_spec.rb b/spec/services/spam/ham_service_spec.rb
index 0101a8e7704..00906bc4b3d 100644
--- a/spec/services/spam/ham_service_spec.rb
+++ b/spec/services/spam/ham_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Spam::HamService do
+RSpec.describe Spam::HamService, feature_category: :instance_resiliency do
let_it_be(:user) { create(:user) }
let!(:spam_log) { create(:spam_log, user: user, submitted_as_ham: false) }
diff --git a/spec/services/spam/spam_action_service_spec.rb b/spec/services/spam/spam_action_service_spec.rb
index 4dfec9735ba..882b325b7b7 100644
--- a/spec/services/spam/spam_action_service_spec.rb
+++ b/spec/services/spam/spam_action_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Spam::SpamActionService do
+RSpec.describe Spam::SpamActionService, feature_category: :instance_resiliency do
include_context 'includes Spam constants'
let(:issue) { create(:issue, project: project, author: author) }
diff --git a/spec/services/spam/spam_params_spec.rb b/spec/services/spam/spam_params_spec.rb
index 7e74641c0fa..39c3b303529 100644
--- a/spec/services/spam/spam_params_spec.rb
+++ b/spec/services/spam/spam_params_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Spam::SpamParams do
+RSpec.describe Spam::SpamParams, feature_category: :instance_resiliency do
shared_examples 'constructs from a request' do
it 'constructs from a request' do
expected = ::Spam::SpamParams.new(
diff --git a/spec/services/spam/spam_verdict_service_spec.rb b/spec/services/spam/spam_verdict_service_spec.rb
index dde93aa6b93..42993491459 100644
--- a/spec/services/spam/spam_verdict_service_spec.rb
+++ b/spec/services/spam/spam_verdict_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Spam::SpamVerdictService do
+RSpec.describe Spam::SpamVerdictService, feature_category: :instance_resiliency do
include_context 'includes Spam constants'
let(:fake_ip) { '1.2.3.4' }
diff --git a/spec/services/submodules/update_service_spec.rb b/spec/services/submodules/update_service_spec.rb
index 1a53da7b9fe..aeaf8ec1c7b 100644
--- a/spec/services/submodules/update_service_spec.rb
+++ b/spec/services/submodules/update_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Submodules::UpdateService do
+RSpec.describe Submodules::UpdateService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user, :commit_email) }
diff --git a/spec/services/suggestions/apply_service_spec.rb b/spec/services/suggestions/apply_service_spec.rb
index 41ccd8523fa..6e2c623035e 100644
--- a/spec/services/suggestions/apply_service_spec.rb
+++ b/spec/services/suggestions/apply_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Suggestions::ApplyService do
+RSpec.describe Suggestions::ApplyService, feature_category: :code_suggestions do
include ProjectForksHelper
def build_position(**optional_args)
diff --git a/spec/services/suggestions/create_service_spec.rb b/spec/services/suggestions/create_service_spec.rb
index a4e62431128..a8bc3cba697 100644
--- a/spec/services/suggestions/create_service_spec.rb
+++ b/spec/services/suggestions/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Suggestions::CreateService do
+RSpec.describe Suggestions::CreateService, feature_category: :code_suggestions do
let(:project_with_repo) { create(:project, :repository) }
let(:merge_request) do
create(:merge_request, source_project: project_with_repo,
diff --git a/spec/services/suggestions/outdate_service_spec.rb b/spec/services/suggestions/outdate_service_spec.rb
index e8891f88548..7bd70866bf7 100644
--- a/spec/services/suggestions/outdate_service_spec.rb
+++ b/spec/services/suggestions/outdate_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Suggestions::OutdateService do
+RSpec.describe Suggestions::OutdateService, feature_category: :code_suggestions do
describe '#execute' do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.target_project }
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index 5d60b6e0487..883a7d3a2ce 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SystemHooksService do
+RSpec.describe SystemHooksService, feature_category: :webhooks do
describe '#execute_hooks_for' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
diff --git a/spec/services/system_notes/alert_management_service_spec.rb b/spec/services/system_notes/alert_management_service_spec.rb
index 039975c1bf6..4d40a6a6cfd 100644
--- a/spec/services/system_notes/alert_management_service_spec.rb
+++ b/spec/services/system_notes/alert_management_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::SystemNotes::AlertManagementService do
+RSpec.describe ::SystemNotes::AlertManagementService, feature_category: :projects do
let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:noteable) { create(:alert_management_alert, :with_incident, :acknowledged, project: project) }
diff --git a/spec/services/system_notes/base_service_spec.rb b/spec/services/system_notes/base_service_spec.rb
index efb165f8e4c..6ea4751b613 100644
--- a/spec/services/system_notes/base_service_spec.rb
+++ b/spec/services/system_notes/base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SystemNotes::BaseService do
+RSpec.describe SystemNotes::BaseService, feature_category: :projects do
let(:noteable) { double }
let(:project) { double }
let(:author) { double }
diff --git a/spec/services/system_notes/commit_service_spec.rb b/spec/services/system_notes/commit_service_spec.rb
index 0399603980d..8dfb83f63fe 100644
--- a/spec/services/system_notes/commit_service_spec.rb
+++ b/spec/services/system_notes/commit_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SystemNotes::CommitService do
+RSpec.describe SystemNotes::CommitService, feature_category: :code_review_workflow do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, group: group) }
let_it_be(:author) { create(:user) }
@@ -13,7 +13,7 @@ RSpec.describe SystemNotes::CommitService do
subject { commit_service.add_commits(new_commits, old_commits, oldrev) }
let(:noteable) { create(:merge_request, source_project: project, target_project: project) }
- let(:new_commits) { noteable.commits }
+ let(:new_commits) { create_commits(10) }
let(:old_commits) { [] }
let(:oldrev) { nil }
@@ -43,6 +43,48 @@ RSpec.describe SystemNotes::CommitService do
expect(decoded_note_content).to include("<li>#{commit.short_id} - #{commit.title}</li>")
end
end
+
+ context 'with HTML content' do
+ let(:new_commits) { [double(title: '<pre>This is a test</pre>', short_id: '12345678')] }
+
+ it 'escapes HTML titles' do
+ expect(note_lines[1]).to eq("<ul><li>12345678 - &lt;pre&gt;This is a test&lt;/pre&gt;</li></ul>")
+ end
+ end
+
+ context 'with one commit exceeding the NEW_COMMIT_DISPLAY_LIMIT' do
+ let(:new_commits) { create_commits(11) }
+ let(:earlier_commit_summary_line) { note_lines[1] }
+
+ it 'includes the truncated new commits summary' do
+ expect(earlier_commit_summary_line).to start_with("<ul><li>#{new_commits[0].short_id} - 1 earlier commit")
+ end
+
+ context 'with oldrev' do
+ let(:oldrev) { '12345678abcd' }
+
+ it 'includes the truncated new commits summary with the oldrev' do
+ expect(earlier_commit_summary_line).to start_with("<ul><li>#{new_commits[0].short_id} - 1 earlier commit")
+ end
+ end
+ end
+
+ context 'with multiple commits exceeding the NEW_COMMIT_DISPLAY_LIMIT' do
+ let(:new_commits) { create_commits(13) }
+ let(:earlier_commit_summary_line) { note_lines[1] }
+
+ it 'includes the truncated new commits summary' do
+ expect(earlier_commit_summary_line).to start_with("<ul><li>#{new_commits[0].short_id}..#{new_commits[2].short_id} - 3 earlier commits")
+ end
+
+ context 'with oldrev' do
+ let(:oldrev) { '12345678abcd' }
+
+ it 'includes the truncated new commits summary with the oldrev' do
+ expect(earlier_commit_summary_line).to start_with("<ul><li>12345678...#{new_commits[2].short_id} - 3 earlier commits")
+ end
+ end
+ end
end
describe 'summary line for existing commits' do
@@ -54,6 +96,15 @@ RSpec.describe SystemNotes::CommitService do
it 'includes the existing commit' do
expect(summary_line).to start_with("<ul><li>#{old_commits.first.short_id} - 1 commit from branch <code>feature</code>")
end
+
+ context 'with new commits exceeding the display limit' do
+ let(:summary_line) { note_lines[1] }
+ let(:new_commits) { create_commits(13) }
+
+ it 'includes the existing commit as well as the truncated new commit summary' do
+ expect(summary_line).to start_with("<ul><li>#{old_commits.first.short_id} - 1 commit from branch <code>feature</code></li><li>#{old_commits.last.short_id}...#{new_commits[2].short_id} - 3 earlier commits")
+ end
+ end
end
context 'with multiple existing commits' do
@@ -66,6 +117,15 @@ RSpec.describe SystemNotes::CommitService do
expect(summary_line)
.to start_with("<ul><li>#{Commit.truncate_sha(oldrev)}...#{old_commits.last.short_id} - 26 commits from branch <code>feature</code>")
end
+
+ context 'with new commits exceeding the display limit' do
+ let(:new_commits) { create_commits(13) }
+
+ it 'includes the existing commit as well as the truncated new commit summary' do
+ expect(summary_line)
+ .to start_with("<ul><li>#{Commit.truncate_sha(oldrev)}...#{old_commits.last.short_id} - 26 commits from branch <code>feature</code></li><li>#{old_commits.last.short_id}...#{new_commits[2].short_id} - 3 earlier commits")
+ end
+ end
end
context 'without oldrev' do
@@ -73,6 +133,15 @@ RSpec.describe SystemNotes::CommitService do
expect(summary_line)
.to start_with("<ul><li>#{old_commits[0].short_id}..#{old_commits[-1].short_id} - 26 commits from branch <code>feature</code>")
end
+
+ context 'with new commits exceeding the display limit' do
+ let(:new_commits) { create_commits(13) }
+
+ it 'includes the existing commit as well as the truncated new commit summary' do
+ expect(summary_line)
+ .to start_with("<ul><li>#{old_commits.first.short_id}..#{old_commits.last.short_id} - 26 commits from branch <code>feature</code></li><li>#{old_commits.last.short_id}...#{new_commits[2].short_id} - 3 earlier commits")
+ end
+ end
end
context 'on a fork' do
@@ -106,12 +175,9 @@ RSpec.describe SystemNotes::CommitService do
end
end
- describe '#new_commit_summary' do
- it 'escapes HTML titles' do
- commit = double(title: '<pre>This is a test</pre>', short_id: '12345678')
- escaped = '&lt;pre&gt;This is a test&lt;/pre&gt;'
-
- expect(described_class.new.new_commit_summary([commit])).to all(match(/- #{escaped}/))
+ def create_commits(count)
+ Array.new(count) do |i|
+ double(title: "Test commit #{i}", short_id: "abcd00#{i}")
end
end
end
diff --git a/spec/services/system_notes/design_management_service_spec.rb b/spec/services/system_notes/design_management_service_spec.rb
index 19e1f338eb8..92568890c6f 100644
--- a/spec/services/system_notes/design_management_service_spec.rb
+++ b/spec/services/system_notes/design_management_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SystemNotes::DesignManagementService do
+RSpec.describe SystemNotes::DesignManagementService, feature_category: :design_management do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/services/system_notes/incident_service_spec.rb b/spec/services/system_notes/incident_service_spec.rb
index 5de352ad8fa..0e9828c0a81 100644
--- a/spec/services/system_notes/incident_service_spec.rb
+++ b/spec/services/system_notes/incident_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::SystemNotes::IncidentService do
+RSpec.describe ::SystemNotes::IncidentService, feature_category: :incident_management do
let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:noteable) { create(:incident, project: project) }
diff --git a/spec/services/system_notes/incidents_service_spec.rb b/spec/services/system_notes/incidents_service_spec.rb
index 6439f9fae93..5452d51dfc0 100644
--- a/spec/services/system_notes/incidents_service_spec.rb
+++ b/spec/services/system_notes/incidents_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SystemNotes::IncidentsService do
+RSpec.describe SystemNotes::IncidentsService, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:author) { create(:user) }
diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb
index 3263e410d3c..08a91234174 100644
--- a/spec/services/system_notes/issuables_service_spec.rb
+++ b/spec/services/system_notes/issuables_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::SystemNotes::IssuablesService do
+RSpec.describe ::SystemNotes::IssuablesService, feature_category: :team_planning do
include ProjectForksHelper
let_it_be(:group) { create(:group) }
diff --git a/spec/services/system_notes/merge_requests_service_spec.rb b/spec/services/system_notes/merge_requests_service_spec.rb
index 3e66ccef106..7ddcd799a55 100644
--- a/spec/services/system_notes/merge_requests_service_spec.rb
+++ b/spec/services/system_notes/merge_requests_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::SystemNotes::MergeRequestsService do
+RSpec.describe ::SystemNotes::MergeRequestsService, feature_category: :code_review_workflow do
include Gitlab::Routing
let_it_be(:group) { create(:group) }
diff --git a/spec/services/system_notes/time_tracking_service_spec.rb b/spec/services/system_notes/time_tracking_service_spec.rb
index c856caa3f3e..5cc17f55012 100644
--- a/spec/services/system_notes/time_tracking_service_spec.rb
+++ b/spec/services/system_notes/time_tracking_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::SystemNotes::TimeTrackingService do
+RSpec.describe ::SystemNotes::TimeTrackingService, feature_category: :team_planning do
let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/services/system_notes/zoom_service_spec.rb b/spec/services/system_notes/zoom_service_spec.rb
index 986324c9664..b46b4113e12 100644
--- a/spec/services/system_notes/zoom_service_spec.rb
+++ b/spec/services/system_notes/zoom_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::SystemNotes::ZoomService do
+RSpec.describe ::SystemNotes::ZoomService, feature_category: :integrations do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:author) { create(:user) }
diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb
index bbf6fe62959..51b8bace626 100644
--- a/spec/services/tags/create_service_spec.rb
+++ b/spec/services/tags/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Tags::CreateService do
+RSpec.describe Tags::CreateService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
diff --git a/spec/services/tags/destroy_service_spec.rb b/spec/services/tags/destroy_service_spec.rb
index 6160f337552..343a87785ad 100644
--- a/spec/services/tags/destroy_service_spec.rb
+++ b/spec/services/tags/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Tags::DestroyService do
+RSpec.describe Tags::DestroyService, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
diff --git a/spec/services/task_list_toggle_service_spec.rb b/spec/services/task_list_toggle_service_spec.rb
index f889f298213..b0444a5ba72 100644
--- a/spec/services/task_list_toggle_service_spec.rb
+++ b/spec/services/task_list_toggle_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TaskListToggleService do
+RSpec.describe TaskListToggleService, feature_category: :team_planning do
let(:markdown) do
<<-EOT.strip_heredoc
* [ ] Task 1
diff --git a/spec/services/tasks_to_be_done/base_service_spec.rb b/spec/services/tasks_to_be_done/base_service_spec.rb
index cfeff36cc0d..ff4eefdfb3a 100644
--- a/spec/services/tasks_to_be_done/base_service_spec.rb
+++ b/spec/services/tasks_to_be_done/base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TasksToBeDone::BaseService do
+RSpec.describe TasksToBeDone::BaseService, feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:assignee_one) { create(:user) }
diff --git a/spec/services/terraform/remote_state_handler_spec.rb b/spec/services/terraform/remote_state_handler_spec.rb
index 369309e4d5a..f4f7a8a0985 100644
--- a/spec/services/terraform/remote_state_handler_spec.rb
+++ b/spec/services/terraform/remote_state_handler_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Terraform::RemoteStateHandler do
+RSpec.describe Terraform::RemoteStateHandler, feature_category: :infrastructure_as_code do
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user, developer_projects: [project]) }
let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) }
diff --git a/spec/services/terraform/states/destroy_service_spec.rb b/spec/services/terraform/states/destroy_service_spec.rb
index 5acf32cd73c..3515a758827 100644
--- a/spec/services/terraform/states/destroy_service_spec.rb
+++ b/spec/services/terraform/states/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Terraform::States::DestroyService do
+RSpec.describe Terraform::States::DestroyService, feature_category: :infrastructure_as_code do
let_it_be(:state) { create(:terraform_state, :with_version, :deletion_in_progress) }
let(:file) { instance_double(Terraform::StateUploader, relative_path: 'path') }
diff --git a/spec/services/terraform/states/trigger_destroy_service_spec.rb b/spec/services/terraform/states/trigger_destroy_service_spec.rb
index 459f4c3bdb9..0b37d962353 100644
--- a/spec/services/terraform/states/trigger_destroy_service_spec.rb
+++ b/spec/services/terraform/states/trigger_destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Terraform::States::TriggerDestroyService do
+RSpec.describe Terraform::States::TriggerDestroyService, feature_category: :infrastructure_as_code do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, maintainer_projects: [project]) }
diff --git a/spec/services/test_hooks/project_service_spec.rb b/spec/services/test_hooks/project_service_spec.rb
index 13f863dbbdb..31f97edbd08 100644
--- a/spec/services/test_hooks/project_service_spec.rb
+++ b/spec/services/test_hooks/project_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TestHooks::ProjectService do
+RSpec.describe TestHooks::ProjectService, feature_category: :code_testing do
include AfterNextHelpers
let(:current_user) { create(:user) }
diff --git a/spec/services/test_hooks/system_service_spec.rb b/spec/services/test_hooks/system_service_spec.rb
index e94ea4669c6..4c5009fea54 100644
--- a/spec/services/test_hooks/system_service_spec.rb
+++ b/spec/services/test_hooks/system_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TestHooks::SystemService do
+RSpec.describe TestHooks::SystemService, feature_category: :code_testing do
include AfterNextHelpers
describe '#execute' do
diff --git a/spec/services/timelogs/delete_service_spec.rb b/spec/services/timelogs/delete_service_spec.rb
index ee1133af6b3..c0543bafcec 100644
--- a/spec/services/timelogs/delete_service_spec.rb
+++ b/spec/services/timelogs/delete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Timelogs::DeleteService do
+RSpec.describe Timelogs::DeleteService, feature_category: :team_planning do
let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index f73eae70d3c..f0aabd0a8dc 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TodoService do
+RSpec.describe TodoService, feature_category: :team_planning do
include AfterNextHelpers
let_it_be(:project) { create(:project, :repository) }
@@ -211,7 +211,6 @@ RSpec.describe TodoService do
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:namespace) { project.namespace }
let(:category) { described_class.to_s }
let(:action) { 'incident_management_incident_todo' }
diff --git a/spec/services/todos/allowed_target_filter_service_spec.rb b/spec/services/todos/allowed_target_filter_service_spec.rb
index 1d2b1b044db..3929e3788d0 100644
--- a/spec/services/todos/allowed_target_filter_service_spec.rb
+++ b/spec/services/todos/allowed_target_filter_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Todos::AllowedTargetFilterService do
+RSpec.describe Todos::AllowedTargetFilterService, feature_category: :team_planning do
include DesignManagementTestHelpers
let_it_be(:authorized_group) { create(:group, :private) }
diff --git a/spec/services/todos/destroy/confidential_issue_service_spec.rb b/spec/services/todos/destroy/confidential_issue_service_spec.rb
index e3dcc2bae95..9de71faf8bf 100644
--- a/spec/services/todos/destroy/confidential_issue_service_spec.rb
+++ b/spec/services/todos/destroy/confidential_issue_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Todos::Destroy::ConfidentialIssueService do
+RSpec.describe Todos::Destroy::ConfidentialIssueService, feature_category: :team_planning do
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
let(:author) { create(:user) }
diff --git a/spec/services/todos/destroy/design_service_spec.rb b/spec/services/todos/destroy/design_service_spec.rb
index 92b25d94dc6..628398e7062 100644
--- a/spec/services/todos/destroy/design_service_spec.rb
+++ b/spec/services/todos/destroy/design_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Todos::Destroy::DesignService do
+RSpec.describe Todos::Destroy::DesignService, feature_category: :design_management do
let_it_be(:user) { create(:user) }
let_it_be(:user_2) { create(:user) }
let_it_be(:design) { create(:design) }
diff --git a/spec/services/todos/destroy/destroyed_issuable_service_spec.rb b/spec/services/todos/destroy/destroyed_issuable_service_spec.rb
index 6d6abe06d1c..63ff189ede5 100644
--- a/spec/services/todos/destroy/destroyed_issuable_service_spec.rb
+++ b/spec/services/todos/destroy/destroyed_issuable_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Todos::Destroy::DestroyedIssuableService do
+RSpec.describe Todos::Destroy::DestroyedIssuableService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:user) { create(:user) }
diff --git a/spec/services/todos/destroy/project_private_service_spec.rb b/spec/services/todos/destroy/project_private_service_spec.rb
index 1d1c010535d..cc15f6eab8b 100644
--- a/spec/services/todos/destroy/project_private_service_spec.rb
+++ b/spec/services/todos/destroy/project_private_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Todos::Destroy::ProjectPrivateService do
+RSpec.describe Todos::Destroy::ProjectPrivateService, feature_category: :team_planning do
let(:group) { create(:group, :public) }
let(:project) { create(:project, :public, group: group) }
let(:user) { create(:user) }
diff --git a/spec/services/todos/destroy/unauthorized_features_service_spec.rb b/spec/services/todos/destroy/unauthorized_features_service_spec.rb
index 5f6c9b0cdf0..c02c0dfd5c8 100644
--- a/spec/services/todos/destroy/unauthorized_features_service_spec.rb
+++ b/spec/services/todos/destroy/unauthorized_features_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Todos::Destroy::UnauthorizedFeaturesService do
+RSpec.describe Todos::Destroy::UnauthorizedFeaturesService, feature_category: :team_planning do
let_it_be(:project, reload: true) { create(:project, :public, :repository) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:mr) { create(:merge_request, source_project: project) }
diff --git a/spec/services/topics/merge_service_spec.rb b/spec/services/topics/merge_service_spec.rb
index 98247250a61..41afabdf2ca 100644
--- a/spec/services/topics/merge_service_spec.rb
+++ b/spec/services/topics/merge_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Topics::MergeService do
+RSpec.describe Topics::MergeService, feature_category: :shared do
let_it_be(:source_topic) { create(:topic, name: 'source_topic') }
let_it_be(:target_topic) { create(:topic, name: 'target_topic') }
let_it_be(:project_1) { create(:project, :public, topic_list: source_topic.name) }
diff --git a/spec/services/two_factor/destroy_service_spec.rb b/spec/services/two_factor/destroy_service_spec.rb
index 30c189520fd..0811ce336c8 100644
--- a/spec/services/two_factor/destroy_service_spec.rb
+++ b/spec/services/two_factor/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TwoFactor::DestroyService do
+RSpec.describe TwoFactor::DestroyService, feature_category: :system_access do
let_it_be(:current_user) { create(:user) }
subject { described_class.new(current_user, user: user).execute }
diff --git a/spec/services/update_container_registry_info_service_spec.rb b/spec/services/update_container_registry_info_service_spec.rb
index 64071e79508..416b08bd04b 100644
--- a/spec/services/update_container_registry_info_service_spec.rb
+++ b/spec/services/update_container_registry_info_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UpdateContainerRegistryInfoService do
+RSpec.describe UpdateContainerRegistryInfoService, feature_category: :container_registry do
let_it_be(:application_settings) { Gitlab::CurrentSettings }
let_it_be(:api_url) { 'http://registry.gitlab' }
diff --git a/spec/services/update_merge_request_metrics_service_spec.rb b/spec/services/update_merge_request_metrics_service_spec.rb
index a07fcee91e4..f30836fbaf5 100644
--- a/spec/services/update_merge_request_metrics_service_spec.rb
+++ b/spec/services/update_merge_request_metrics_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequestMetricsService do
+RSpec.describe MergeRequestMetricsService, feature_category: :code_review_workflow do
let(:metrics) { create(:merge_request).metrics }
describe '#merge' do
diff --git a/spec/services/upload_service_spec.rb b/spec/services/upload_service_spec.rb
index 48aa65451f3..518d12d5b41 100644
--- a/spec/services/upload_service_spec.rb
+++ b/spec/services/upload_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UploadService do
+RSpec.describe UploadService, feature_category: :shared do
describe 'File service' do
before do
@user = create(:user)
diff --git a/spec/services/uploads/destroy_service_spec.rb b/spec/services/uploads/destroy_service_spec.rb
index bb58da231b6..76ac2ec245e 100644
--- a/spec/services/uploads/destroy_service_spec.rb
+++ b/spec/services/uploads/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Uploads::DestroyService do
+RSpec.describe Uploads::DestroyService, feature_category: :shared do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:upload) { create(:upload, :issuable_upload, model: project) }
diff --git a/spec/services/user_preferences/update_service_spec.rb b/spec/services/user_preferences/update_service_spec.rb
index 59089a4a7af..09acc01729e 100644
--- a/spec/services/user_preferences/update_service_spec.rb
+++ b/spec/services/user_preferences/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UserPreferences::UpdateService do
+RSpec.describe UserPreferences::UpdateService, feature_category: :user_profile do
let(:user) { create(:user) }
let(:params) { { view_diffs_file_by_file: false } }
diff --git a/spec/services/user_project_access_changed_service_spec.rb b/spec/services/user_project_access_changed_service_spec.rb
index 356675d55f2..563af8e7e9e 100644
--- a/spec/services/user_project_access_changed_service_spec.rb
+++ b/spec/services/user_project_access_changed_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UserProjectAccessChangedService, feature_category: :authentication_and_authorization do
+RSpec.describe UserProjectAccessChangedService, feature_category: :system_access do
describe '#execute' do
it 'permits high-priority operation' do
expect(AuthorizedProjectsWorker).to receive(:bulk_perform_async)
diff --git a/spec/services/users/activity_service_spec.rb b/spec/services/users/activity_service_spec.rb
index 6c0d93f568a..f78535569b3 100644
--- a/spec/services/users/activity_service_spec.rb
+++ b/spec/services/users/activity_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::ActivityService do
+RSpec.describe Users::ActivityService, feature_category: :user_profile do
include ExclusiveLeaseHelpers
let(:user) { create(:user, last_activity_on: last_activity_on) }
diff --git a/spec/services/users/approve_service_spec.rb b/spec/services/users/approve_service_spec.rb
index 34eb5b18ff6..1b063a9ad1c 100644
--- a/spec/services/users/approve_service_spec.rb
+++ b/spec/services/users/approve_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::ApproveService do
+RSpec.describe Users::ApproveService, feature_category: :user_management do
let_it_be(:current_user) { create(:admin) }
let(:user) { create(:user, :blocked_pending_approval) }
diff --git a/spec/services/users/authorized_build_service_spec.rb b/spec/services/users/authorized_build_service_spec.rb
index 57a122cbf35..7eed6833cba 100644
--- a/spec/services/users/authorized_build_service_spec.rb
+++ b/spec/services/users/authorized_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::AuthorizedBuildService do
+RSpec.describe Users::AuthorizedBuildService, feature_category: :user_management do
describe '#execute' do
let_it_be(:current_user) { create(:user) }
diff --git a/spec/services/users/ban_service_spec.rb b/spec/services/users/ban_service_spec.rb
index 3f9c7ebf067..5be5de82e91 100644
--- a/spec/services/users/ban_service_spec.rb
+++ b/spec/services/users/ban_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::BanService do
+RSpec.describe Users::BanService, feature_category: :user_management do
let(:user) { create(:user) }
let_it_be(:current_user) { create(:admin) }
diff --git a/spec/services/users/banned_user_base_service_spec.rb b/spec/services/users/banned_user_base_service_spec.rb
index 29a549f0f49..65b24e08d80 100644
--- a/spec/services/users/banned_user_base_service_spec.rb
+++ b/spec/services/users/banned_user_base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::BannedUserBaseService do
+RSpec.describe Users::BannedUserBaseService, feature_category: :user_management do
let(:admin) { create(:admin) }
let(:base_service) { described_class.new(admin) }
diff --git a/spec/services/users/batch_status_cleaner_service_spec.rb b/spec/services/users/batch_status_cleaner_service_spec.rb
index 46a004542d8..8feec761fd0 100644
--- a/spec/services/users/batch_status_cleaner_service_spec.rb
+++ b/spec/services/users/batch_status_cleaner_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::BatchStatusCleanerService do
+RSpec.describe Users::BatchStatusCleanerService, feature_category: :user_management do
let_it_be(:user_status_1) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 1.year.ago) }
let_it_be(:user_status_2) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 1.year.from_now) }
let_it_be(:user_status_3) { create(:user_status, emoji: 'coffee', message: 'msg1', clear_status_at: 2.years.ago) }
diff --git a/spec/services/users/block_service_spec.rb b/spec/services/users/block_service_spec.rb
index 7ff9a887f38..63aa375c8af 100644
--- a/spec/services/users/block_service_spec.rb
+++ b/spec/services/users/block_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::BlockService do
+RSpec.describe Users::BlockService, feature_category: :user_management do
let_it_be(:current_user) { create(:admin) }
subject(:service) { described_class.new(current_user) }
diff --git a/spec/services/users/build_service_spec.rb b/spec/services/users/build_service_spec.rb
index 98fe6d9b5ba..f3236d40412 100644
--- a/spec/services/users/build_service_spec.rb
+++ b/spec/services/users/build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::BuildService do
+RSpec.describe Users::BuildService, feature_category: :user_management do
using RSpec::Parameterized::TableSyntax
describe '#execute' do
diff --git a/spec/services/users/create_service_spec.rb b/spec/services/users/create_service_spec.rb
index f3c9701c556..eac4faa2042 100644
--- a/spec/services/users/create_service_spec.rb
+++ b/spec/services/users/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::CreateService do
+RSpec.describe Users::CreateService, feature_category: :user_management do
describe '#execute' do
let(:password) { User.random_password }
let(:admin_user) { create(:admin) }
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index 18ad946b289..5cd11efe942 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::DestroyService do
+RSpec.describe Users::DestroyService, feature_category: :user_management do
let!(:user) { create(:user) }
let!(:admin) { create(:admin) }
let!(:namespace) { user.namespace }
diff --git a/spec/services/users/dismiss_callout_service_spec.rb b/spec/services/users/dismiss_callout_service_spec.rb
index 6ba9f180444..776388ef5f1 100644
--- a/spec/services/users/dismiss_callout_service_spec.rb
+++ b/spec/services/users/dismiss_callout_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::DismissCalloutService do
+RSpec.describe Users::DismissCalloutService, feature_category: :user_management do
describe '#execute' do
let_it_be(:user) { create(:user) }
diff --git a/spec/services/users/dismiss_group_callout_service_spec.rb b/spec/services/users/dismiss_group_callout_service_spec.rb
index d74602a7606..a653fa7ee00 100644
--- a/spec/services/users/dismiss_group_callout_service_spec.rb
+++ b/spec/services/users/dismiss_group_callout_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::DismissGroupCalloutService do
+RSpec.describe Users::DismissGroupCalloutService, feature_category: :user_management do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
diff --git a/spec/services/users/dismiss_project_callout_service_spec.rb b/spec/services/users/dismiss_project_callout_service_spec.rb
index 73e50a4c37d..7bcb11e4dbc 100644
--- a/spec/services/users/dismiss_project_callout_service_spec.rb
+++ b/spec/services/users/dismiss_project_callout_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::DismissProjectCalloutService do
+RSpec.describe Users::DismissProjectCalloutService, feature_category: :user_management do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/services/users/email_verification/generate_token_service_spec.rb b/spec/services/users/email_verification/generate_token_service_spec.rb
index e7aa1bf8306..3b299622a90 100644
--- a/spec/services/users/email_verification/generate_token_service_spec.rb
+++ b/spec/services/users/email_verification/generate_token_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::EmailVerification::GenerateTokenService do
+RSpec.describe Users::EmailVerification::GenerateTokenService, feature_category: :system_access do
using RSpec::Parameterized::TableSyntax
let(:service) { described_class.new(attr: attr) }
diff --git a/spec/services/users/email_verification/validate_token_service_spec.rb b/spec/services/users/email_verification/validate_token_service_spec.rb
index 44af4a4d36f..9b69034290a 100644
--- a/spec/services/users/email_verification/validate_token_service_spec.rb
+++ b/spec/services/users/email_verification/validate_token_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::EmailVerification::ValidateTokenService, :clean_gitlab_redis_rate_limiting do
+RSpec.describe Users::EmailVerification::ValidateTokenService, :clean_gitlab_redis_rate_limiting, feature_category: :system_access do
using RSpec::Parameterized::TableSyntax
let(:service) { described_class.new(attr: attr, user: user, token: token) }
diff --git a/spec/services/users/in_product_marketing_email_records_spec.rb b/spec/services/users/in_product_marketing_email_records_spec.rb
index 0b9400dcd12..059f0890b53 100644
--- a/spec/services/users/in_product_marketing_email_records_spec.rb
+++ b/spec/services/users/in_product_marketing_email_records_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::InProductMarketingEmailRecords do
+RSpec.describe Users::InProductMarketingEmailRecords, feature_category: :onboarding do
let_it_be(:user) { create :user }
subject(:records) { described_class.new }
diff --git a/spec/services/users/keys_count_service_spec.rb b/spec/services/users/keys_count_service_spec.rb
index 607d2946b2c..258fe351e4b 100644
--- a/spec/services/users/keys_count_service_spec.rb
+++ b/spec/services/users/keys_count_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::KeysCountService, :use_clean_rails_memory_store_caching do
+RSpec.describe Users::KeysCountService, :use_clean_rails_memory_store_caching, feature_category: :system_access do
let(:user) { create(:user) }
subject { described_class.new(user) }
diff --git a/spec/services/users/last_push_event_service_spec.rb b/spec/services/users/last_push_event_service_spec.rb
index 5b755db407f..fe61f12fe1a 100644
--- a/spec/services/users/last_push_event_service_spec.rb
+++ b/spec/services/users/last_push_event_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::LastPushEventService do
+RSpec.describe Users::LastPushEventService, feature_category: :source_code_management do
let(:user) { build(:user, id: 1) }
let(:project) { build(:project, id: 2) }
let(:event) { build(:push_event, id: 3, author: user, project: project) }
diff --git a/spec/services/users/migrate_records_to_ghost_user_in_batches_service_spec.rb b/spec/services/users/migrate_records_to_ghost_user_in_batches_service_spec.rb
index 107ff82016c..0b9f92a868e 100644
--- a/spec/services/users/migrate_records_to_ghost_user_in_batches_service_spec.rb
+++ b/spec/services/users/migrate_records_to_ghost_user_in_batches_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::MigrateRecordsToGhostUserInBatchesService do
+RSpec.describe Users::MigrateRecordsToGhostUserInBatchesService, feature_category: :user_management do
let(:service) { described_class.new }
let_it_be(:ghost_user_migration) { create(:ghost_user_migration) }
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 827d6f652a4..cfa0ddff04d 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
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::MigrateRecordsToGhostUserService do
+RSpec.describe Users::MigrateRecordsToGhostUserService, feature_category: :user_management do
include BatchDestroyDependentAssociationsHelper
let!(:user) { create(:user) }
diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb
index e33886d2add..55b27954a74 100644
--- a/spec/services/users/refresh_authorized_projects_service_spec.rb
+++ b/spec/services/users/refresh_authorized_projects_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::RefreshAuthorizedProjectsService do
+RSpec.describe Users::RefreshAuthorizedProjectsService, feature_category: :user_management do
include ExclusiveLeaseHelpers
# We're using let! here so that any expectations for the service class are not
diff --git a/spec/services/users/registrations_build_service_spec.rb b/spec/services/users/registrations_build_service_spec.rb
index fa53a4cc604..736db855fe0 100644
--- a/spec/services/users/registrations_build_service_spec.rb
+++ b/spec/services/users/registrations_build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::RegistrationsBuildService do
+RSpec.describe Users::RegistrationsBuildService, feature_category: :system_access do
describe '#execute' do
let(:base_params) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) }
let(:skip_param) { {} }
diff --git a/spec/services/users/reject_service_spec.rb b/spec/services/users/reject_service_spec.rb
index 37d003c5dac..f72666d8a63 100644
--- a/spec/services/users/reject_service_spec.rb
+++ b/spec/services/users/reject_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::RejectService do
+RSpec.describe Users::RejectService, feature_category: :user_management do
let_it_be(:current_user) { create(:admin) }
let(:user) { create(:user, :blocked_pending_approval) }
diff --git a/spec/services/users/repair_ldap_blocked_service_spec.rb b/spec/services/users/repair_ldap_blocked_service_spec.rb
index 54540d68af2..424c14ccdbc 100644
--- a/spec/services/users/repair_ldap_blocked_service_spec.rb
+++ b/spec/services/users/repair_ldap_blocked_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::RepairLdapBlockedService do
+RSpec.describe Users::RepairLdapBlockedService, feature_category: :system_access do
let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') }
let(:identity) { user.ldap_identity }
diff --git a/spec/services/users/respond_to_terms_service_spec.rb b/spec/services/users/respond_to_terms_service_spec.rb
index 1997dcd0e04..dc33f98535a 100644
--- a/spec/services/users/respond_to_terms_service_spec.rb
+++ b/spec/services/users/respond_to_terms_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::RespondToTermsService do
+RSpec.describe Users::RespondToTermsService, feature_category: :user_profile do
let(:user) { create(:user) }
let(:term) { create(:term) }
diff --git a/spec/services/users/saved_replies/create_service_spec.rb b/spec/services/users/saved_replies/create_service_spec.rb
index e01b6248308..ee42a53a220 100644
--- a/spec/services/users/saved_replies/create_service_spec.rb
+++ b/spec/services/users/saved_replies/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::SavedReplies::CreateService do
+RSpec.describe Users::SavedReplies::CreateService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:current_user) { create(:user) }
let_it_be(:saved_reply) { create(:saved_reply, user: current_user) }
diff --git a/spec/services/users/saved_replies/destroy_service_spec.rb b/spec/services/users/saved_replies/destroy_service_spec.rb
index cb97fac7b7c..41c2013e3df 100644
--- a/spec/services/users/saved_replies/destroy_service_spec.rb
+++ b/spec/services/users/saved_replies/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::SavedReplies::DestroyService do
+RSpec.describe Users::SavedReplies::DestroyService, feature_category: :team_planning do
describe '#execute' do
let!(:saved_reply) { create(:saved_reply) }
diff --git a/spec/services/users/saved_replies/update_service_spec.rb b/spec/services/users/saved_replies/update_service_spec.rb
index bdb54d7c8f7..c18b7395040 100644
--- a/spec/services/users/saved_replies/update_service_spec.rb
+++ b/spec/services/users/saved_replies/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::SavedReplies::UpdateService do
+RSpec.describe Users::SavedReplies::UpdateService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:current_user) { create(:user) }
let_it_be(:saved_reply) { create(:saved_reply, user: current_user) }
diff --git a/spec/services/users/set_status_service_spec.rb b/spec/services/users/set_status_service_spec.rb
index 76e86506d94..b75c558785f 100644
--- a/spec/services/users/set_status_service_spec.rb
+++ b/spec/services/users/set_status_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::SetStatusService do
+RSpec.describe Users::SetStatusService, feature_category: :user_management do
let(:current_user) { create(:user) }
subject(:service) { described_class.new(current_user, params) }
diff --git a/spec/services/users/signup_service_spec.rb b/spec/services/users/signup_service_spec.rb
index ef532e01d0b..29663411346 100644
--- a/spec/services/users/signup_service_spec.rb
+++ b/spec/services/users/signup_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::SignupService do
+RSpec.describe Users::SignupService, feature_category: :system_access do
let(:user) { create(:user, setup_for_company: true) }
describe '#execute' do
@@ -48,11 +48,7 @@ RSpec.describe Users::SignupService do
expect(user.reload.setup_for_company).to be(false)
end
- context 'when on .com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
+ context 'when on SaaS', :saas do
it 'returns an error result when setup_for_company is missing' do
result = update_user(user, setup_for_company: '')
diff --git a/spec/services/users/unban_service_spec.rb b/spec/services/users/unban_service_spec.rb
index 3dcb8450e7b..20fe40b370f 100644
--- a/spec/services/users/unban_service_spec.rb
+++ b/spec/services/users/unban_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::UnbanService do
+RSpec.describe Users::UnbanService, feature_category: :user_management do
let(:user) { create(:user) }
let_it_be(:current_user) { create(:admin) }
diff --git a/spec/services/users/unblock_service_spec.rb b/spec/services/users/unblock_service_spec.rb
index 25ee99427ab..95a077d6100 100644
--- a/spec/services/users/unblock_service_spec.rb
+++ b/spec/services/users/unblock_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::UnblockService do
+RSpec.describe Users::UnblockService, feature_category: :user_management do
let_it_be(:current_user) { create(:admin) }
subject(:service) { described_class.new(current_user) }
diff --git a/spec/services/users/update_canonical_email_service_spec.rb b/spec/services/users/update_canonical_email_service_spec.rb
index 1dead13d338..559b759a400 100644
--- a/spec/services/users/update_canonical_email_service_spec.rb
+++ b/spec/services/users/update_canonical_email_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::UpdateCanonicalEmailService do
+RSpec.describe Users::UpdateCanonicalEmailService, feature_category: :user_profile do
let(:other_email) { "differentaddress@includeddomain.com" }
before do
diff --git a/spec/services/users/update_highest_member_role_service_spec.rb b/spec/services/users/update_highest_member_role_service_spec.rb
index 89ddd635bb6..06f4d787d72 100644
--- a/spec/services/users/update_highest_member_role_service_spec.rb
+++ b/spec/services/users/update_highest_member_role_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::UpdateHighestMemberRoleService do
+RSpec.describe Users::UpdateHighestMemberRoleService, feature_category: :user_management do
let(:user) { create(:user) }
let(:execute_service) { described_class.new(user).execute }
diff --git a/spec/services/users/update_service_spec.rb b/spec/services/users/update_service_spec.rb
index f4ea757f81a..1716685566c 100644
--- a/spec/services/users/update_service_spec.rb
+++ b/spec/services/users/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::UpdateService do
+RSpec.describe Users::UpdateService, feature_category: :user_profile do
let(:password) { User.random_password }
let(:user) { create(:user, password: password, password_confirmation: password) }
diff --git a/spec/services/users/update_todo_count_cache_service_spec.rb b/spec/services/users/update_todo_count_cache_service_spec.rb
index 3d96af928df..eec637cf5b4 100644
--- a/spec/services/users/update_todo_count_cache_service_spec.rb
+++ b/spec/services/users/update_todo_count_cache_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::UpdateTodoCountCacheService do
+RSpec.describe Users::UpdateTodoCountCacheService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:user1) { create(:user) }
let_it_be(:user2) { create(:user) }
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 ac7e619612f..37aa5fed838 100644
--- a/spec/services/users/upsert_credit_card_validation_service_spec.rb
+++ b/spec/services/users/upsert_credit_card_validation_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::UpsertCreditCardValidationService do
+RSpec.describe Users::UpsertCreditCardValidationService, feature_category: :user_profile do
let_it_be(:user) { create(:user, requires_credit_card_verification: true) }
let(:user_id) { user.id }
diff --git a/spec/services/users/validate_manual_otp_service_spec.rb b/spec/services/users/validate_manual_otp_service_spec.rb
index d71735814f2..9a6083bc41c 100644
--- a/spec/services/users/validate_manual_otp_service_spec.rb
+++ b/spec/services/users/validate_manual_otp_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::ValidateManualOtpService do
+RSpec.describe Users::ValidateManualOtpService, feature_category: :user_profile do
let_it_be(:user) { create(:user) }
let(:otp_code) { 42 }
@@ -32,6 +32,20 @@ RSpec.describe Users::ValidateManualOtpService do
validate
end
+
+ it 'handles unexpected error' do
+ error_message = "boom!"
+
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::FortiAuthenticator::ManualOtp) do |strategy|
+ expect(strategy).to receive(:validate).with(otp_code).once.and_raise(StandardError, error_message)
+ end
+ expect(Gitlab::ErrorTracking).to receive(:log_exception)
+
+ result = validate
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq(error_message)
+ end
end
context 'FortiTokenCloud' do
@@ -49,16 +63,23 @@ RSpec.describe Users::ValidateManualOtpService do
end
end
- context 'unexpected error' do
+ context 'DuoAuth' do
before do
- stub_feature_flags(forti_authenticator: user)
- allow(::Gitlab.config.forti_authenticator).to receive(:enabled).and_return(true)
+ allow(::Gitlab.config.duo_auth).to receive(:enabled).and_return(true)
end
- it 'returns error' do
+ it 'calls DuoAuth strategy' do
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::DuoAuth::ManualOtp) do |strategy|
+ expect(strategy).to receive(:validate).with(otp_code).once
+ end
+
+ validate
+ end
+
+ it "handles unexpected error" do
error_message = "boom!"
- expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::FortiAuthenticator::ManualOtp) do |strategy|
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::DuoAuth::ManualOtp) do |strategy|
expect(strategy).to receive(:validate).with(otp_code).once.and_raise(StandardError, error_message)
end
expect(Gitlab::ErrorTracking).to receive(:log_exception)
diff --git a/spec/services/users/validate_push_otp_service_spec.rb b/spec/services/users/validate_push_otp_service_spec.rb
index 960b6bcd3bb..4ef374cbb7f 100644
--- a/spec/services/users/validate_push_otp_service_spec.rb
+++ b/spec/services/users/validate_push_otp_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::ValidatePushOtpService do
+RSpec.describe Users::ValidatePushOtpService, feature_category: :user_profile do
let_it_be(:user) { create(:user) }
subject(:validate) { described_class.new(user).execute }
diff --git a/spec/services/verify_pages_domain_service_spec.rb b/spec/services/verify_pages_domain_service_spec.rb
index 42f7ebc85f9..d66d584d3d0 100644
--- a/spec/services/verify_pages_domain_service_spec.rb
+++ b/spec/services/verify_pages_domain_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe VerifyPagesDomainService do
+RSpec.describe VerifyPagesDomainService, feature_category: :pages do
using RSpec::Parameterized::TableSyntax
include EmailHelpers
diff --git a/spec/services/web_hooks/destroy_service_spec.rb b/spec/services/web_hooks/destroy_service_spec.rb
index ca8cb8a1b75..642c25ab312 100644
--- a/spec/services/web_hooks/destroy_service_spec.rb
+++ b/spec/services/web_hooks/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WebHooks::DestroyService do
+RSpec.describe WebHooks::DestroyService, feature_category: :webhooks do
let_it_be(:user) { create(:user) }
subject { described_class.new(user) }
diff --git a/spec/services/web_hooks/log_destroy_service_spec.rb b/spec/services/web_hooks/log_destroy_service_spec.rb
index 7634726e5a4..b0444b659ba 100644
--- a/spec/services/web_hooks/log_destroy_service_spec.rb
+++ b/spec/services/web_hooks/log_destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WebHooks::LogDestroyService do
+RSpec.describe WebHooks::LogDestroyService, feature_category: :webhooks do
subject(:service) { described_class.new(hook.id) }
describe '#execute' do
diff --git a/spec/services/web_hooks/log_execution_service_spec.rb b/spec/services/web_hooks/log_execution_service_spec.rb
index 8a845f60ad2..f56c07386fa 100644
--- a/spec/services/web_hooks/log_execution_service_spec.rb
+++ b/spec/services/web_hooks/log_execution_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WebHooks::LogExecutionService do
+RSpec.describe WebHooks::LogExecutionService, feature_category: :webhooks do
include ExclusiveLeaseHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/services/webauthn/authenticate_service_spec.rb b/spec/services/webauthn/authenticate_service_spec.rb
index b40f9465b63..ca940dff0eb 100644
--- a/spec/services/webauthn/authenticate_service_spec.rb
+++ b/spec/services/webauthn/authenticate_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'webauthn/fake_client'
-RSpec.describe Webauthn::AuthenticateService do
+RSpec.describe Webauthn::AuthenticateService, feature_category: :system_access do
let(:client) { WebAuthn::FakeClient.new(origin) }
let(:user) { create(:user) }
let(:challenge) { Base64.strict_encode64(SecureRandom.random_bytes(32)) }
diff --git a/spec/services/webauthn/register_service_spec.rb b/spec/services/webauthn/register_service_spec.rb
index bb9fa2080d2..2286d261e94 100644
--- a/spec/services/webauthn/register_service_spec.rb
+++ b/spec/services/webauthn/register_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'webauthn/fake_client'
-RSpec.describe Webauthn::RegisterService do
+RSpec.describe Webauthn::RegisterService, feature_category: :system_access do
let(:client) { WebAuthn::FakeClient.new(origin) }
let(:user) { create(:user) }
let(:challenge) { Base64.strict_encode64(SecureRandom.random_bytes(32)) }
diff --git a/spec/services/wiki_pages/base_service_spec.rb b/spec/services/wiki_pages/base_service_spec.rb
index 6ccc796014c..f434dc689ef 100644
--- a/spec/services/wiki_pages/base_service_spec.rb
+++ b/spec/services/wiki_pages/base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WikiPages::BaseService do
+RSpec.describe WikiPages::BaseService, feature_category: :wiki do
let(:project) { double('project') }
let(:user) { double('user') }
diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb
index fd3776f4207..ca2d38ad70d 100644
--- a/spec/services/wiki_pages/create_service_spec.rb
+++ b/spec/services/wiki_pages/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WikiPages::CreateService do
+RSpec.describe WikiPages::CreateService, feature_category: :wiki do
it_behaves_like 'WikiPages::CreateService#execute', :project
describe '#execute' do
diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb
index 9384ea1cd43..ff29fc59b3e 100644
--- a/spec/services/wiki_pages/destroy_service_spec.rb
+++ b/spec/services/wiki_pages/destroy_service_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe WikiPages::DestroyService do
+RSpec.describe WikiPages::DestroyService, feature_category: :wiki do
it_behaves_like 'WikiPages::DestroyService#execute', :project
end
diff --git a/spec/services/wiki_pages/event_create_service_spec.rb b/spec/services/wiki_pages/event_create_service_spec.rb
index 8476f872e98..cbc2bd82a98 100644
--- a/spec/services/wiki_pages/event_create_service_spec.rb
+++ b/spec/services/wiki_pages/event_create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WikiPages::EventCreateService do
+RSpec.describe WikiPages::EventCreateService, feature_category: :wiki do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb
index 62881817e32..79b2b55907b 100644
--- a/spec/services/wiki_pages/update_service_spec.rb
+++ b/spec/services/wiki_pages/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WikiPages::UpdateService do
+RSpec.describe WikiPages::UpdateService, feature_category: :wiki do
it_behaves_like 'WikiPages::UpdateService#execute', :project
describe '#execute' do
diff --git a/spec/services/wikis/create_attachment_service_spec.rb b/spec/services/wikis/create_attachment_service_spec.rb
index 22e34e1f373..fccdbd3040b 100644
--- a/spec/services/wikis/create_attachment_service_spec.rb
+++ b/spec/services/wikis/create_attachment_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Wikis::CreateAttachmentService do
+RSpec.describe Wikis::CreateAttachmentService, feature_category: :wiki do
let(:container) { create(:project, :wiki_repo) }
let(:user) { create(:user) }
let(:file_name) { 'filename.txt' }
diff --git a/spec/services/work_items/build_service_spec.rb b/spec/services/work_items/build_service_spec.rb
index 405b4414fc2..3ecf78e0659 100644
--- a/spec/services/work_items/build_service_spec.rb
+++ b/spec/services/work_items/build_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::BuildService do
+RSpec.describe WorkItems::BuildService, feature_category: :team_planning do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:guest) { create(:user) }
diff --git a/spec/services/work_items/create_from_task_service_spec.rb b/spec/services/work_items/create_from_task_service_spec.rb
index 7c5430f038c..b2f81f1dc54 100644
--- a/spec/services/work_items/create_from_task_service_spec.rb
+++ b/spec/services/work_items/create_from_task_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::CreateFromTaskService do
+RSpec.describe WorkItems::CreateFromTaskService, feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user) }
let_it_be(:list_work_item, refind: true) { create(:work_item, project: project, description: "- [ ] Item to be converted\n second line\n third line") }
diff --git a/spec/services/work_items/create_service_spec.rb b/spec/services/work_items/create_service_spec.rb
index 1b134c308f2..ecd7937f933 100644
--- a/spec/services/work_items/create_service_spec.rb
+++ b/spec/services/work_items/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::CreateService do
+RSpec.describe WorkItems::CreateService, feature_category: :team_planning do
include AfterNextHelpers
let_it_be_with_reload(:project) { create(:project) }
diff --git a/spec/services/work_items/delete_service_spec.rb b/spec/services/work_items/delete_service_spec.rb
index 69ae881a12f..ac72815a57e 100644
--- a/spec/services/work_items/delete_service_spec.rb
+++ b/spec/services/work_items/delete_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::DeleteService do
+RSpec.describe WorkItems::DeleteService, feature_category: :team_planning do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:guest) { create(:user) }
let_it_be(:work_item, refind: true) { create(:work_item, project: project, author: guest) }
diff --git a/spec/services/work_items/delete_task_service_spec.rb b/spec/services/work_items/delete_task_service_spec.rb
index 07a0d8d6c1a..dc01da65771 100644
--- a/spec/services/work_items/delete_task_service_spec.rb
+++ b/spec/services/work_items/delete_task_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::DeleteTaskService do
+RSpec.describe WorkItems::DeleteTaskService, feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let_it_be_with_refind(:task) { create(:work_item, project: project, author: developer) }
diff --git a/spec/services/work_items/export_csv_service_spec.rb b/spec/services/work_items/export_csv_service_spec.rb
index 0718d3b686a..7c22312ce1f 100644
--- a/spec/services/work_items/export_csv_service_spec.rb
+++ b/spec/services/work_items/export_csv_service_spec.rb
@@ -30,9 +30,8 @@ RSpec.describe WorkItems::ExportCsvService, :with_license, feature_category: :te
end
describe '#email' do
- # TODO - will be implemented as part of https://gitlab.com/gitlab-org/gitlab/-/issues/379082
- xit 'emails csv' do
- expect { subject.email(user) }.o change { ActionMailer::Base.deliveries.count }.from(0).to(1)
+ it 'emails csv' do
+ expect { subject.email(user) }.to change { ActionMailer::Base.deliveries.count }.from(0).to(1)
end
end
diff --git a/spec/services/work_items/import_csv_service_spec.rb b/spec/services/work_items/import_csv_service_spec.rb
new file mode 100644
index 00000000000..3c710640f4a
--- /dev/null
+++ b/spec/services/work_items/import_csv_service_spec.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::ImportCsvService, feature_category: :team_planning do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:author) { create(:user, username: 'csv_author') }
+ let(:file) { fixture_file_upload('spec/fixtures/work_items_valid_types.csv') }
+ let(:service) do
+ uploader = FileUploader.new(project)
+ uploader.store!(file)
+
+ described_class.new(user, project, uploader)
+ end
+
+ let_it_be(:issue_type) { ::WorkItems::Type.default_issue_type }
+
+ let(:work_items) { ::WorkItems::WorkItemsFinder.new(user, project: project).execute }
+ let(:email_method) { :import_work_items_csv_email }
+
+ subject { service.execute }
+
+ describe '#execute', :aggregate_failures do
+ context 'when user has permission' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it_behaves_like 'importer with email notification'
+
+ context 'when file format is valid' do
+ context 'when work item types are available' do
+ it 'creates the expected number of work items' do
+ expect { subject }.to change { work_items.count }.by 2
+ end
+
+ it 'sets work item attributes' do
+ result = subject
+
+ expect(work_items.reload).to contain_exactly(
+ have_attributes(
+ title: 'Valid issue',
+ work_item_type_id: issue_type.id
+ ),
+ have_attributes(
+ title: 'Valid issue with alternate case',
+ work_item_type_id: issue_type.id
+ )
+ )
+
+ expect(result[:success]).to eq(2)
+ expect(result[:error_lines]).to eq([])
+ expect(result[:type_errors]).to be_nil
+ expect(result[:parse_error]).to eq(false)
+ end
+ end
+
+ context 'when csv contains work item types that are missing or not available' do
+ let(:file) { fixture_file_upload('spec/fixtures/work_items_invalid_types.csv') }
+
+ it 'creates no work items' do
+ expect { subject }.not_to change { work_items.count }
+ end
+
+ it 'returns the correct result' do
+ result = subject
+
+ expect(result[:success]).to eq(0)
+ expect(result[:error_lines]).to be_empty # there are problematic lines detailed below
+ expect(result[:parse_error]).to eq(false)
+ expect(result[:type_errors]).to match({
+ blank: [4],
+ disallowed: {}, # tested in the EE version
+ missing: {
+ "isssue" => [2],
+ "issue!!" => [3]
+ }
+ })
+ end
+ end
+ end
+
+ context 'when file is missing necessary headers' do
+ let(:file) { fixture_file_upload('spec/fixtures/work_items_missing_header.csv') }
+
+ it 'creates no records' do
+ result = subject
+
+ expect(result[:success]).to eq(0)
+ expect(result[:error_lines]).to eq([1])
+ expect(result[:type_errors]).to be_nil
+ expect(result[:parse_error]).to eq(true)
+ end
+
+ it 'creates no work items' do
+ expect { subject }.not_to change { work_items.count }
+ end
+ end
+
+ context 'when import_export_work_items_csv feature flag is off' do
+ before do
+ stub_feature_flags(import_export_work_items_csv: false)
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(/This feature is currently behind a feature flag and it is not available./)
+ end
+ end
+ end
+
+ context 'when user does not have permission' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(/You do not have permission to import work items in this project/)
+ end
+ end
+ end
+end
diff --git a/spec/services/work_items/parent_links/create_service_spec.rb b/spec/services/work_items/parent_links/create_service_spec.rb
index 5884847eac3..a989ecf9c07 100644
--- a/spec/services/work_items/parent_links/create_service_spec.rb
+++ b/spec/services/work_items/parent_links/create_service_spec.rb
@@ -68,6 +68,40 @@ RSpec.describe WorkItems::ParentLinks::CreateService, feature_category: :portfol
end
end
+ context 'when adjacent is already in place' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be_with_reload(:parent_item) { create(:work_item, :objective, project: project) }
+ let_it_be_with_reload(:current_item) { create(:work_item, :objective, project: project) }
+
+ let_it_be_with_reload(:adjacent) do
+ create(:work_item, :objective, project: project)
+ end
+
+ let_it_be_with_reload(:link_to_adjacent) do
+ create(:parent_link, work_item_parent: parent_item, work_item: adjacent)
+ end
+
+ subject { described_class.new(parent_item, user, { target_issuable: current_item }).execute }
+
+ where(:adjacent_position, :expected_order) do
+ -100 | lazy { [adjacent, current_item] }
+ 0 | lazy { [adjacent, current_item] }
+ 100 | lazy { [adjacent, current_item] }
+ end
+
+ with_them do
+ before do
+ link_to_adjacent.update!(relative_position: adjacent_position)
+ end
+
+ it 'sets relative positions' do
+ expect { subject }.to change(parent_link_class, :count).by(1)
+ expect(parent_item.work_item_children_by_relative_position).to eq(expected_order)
+ end
+ end
+ end
+
context 'when there are tasks to relate' do
let(:params) { { issuable_references: [task1, task2] } }
diff --git a/spec/services/work_items/parent_links/destroy_service_spec.rb b/spec/services/work_items/parent_links/destroy_service_spec.rb
index 654a03ef6f7..c77546f6ca1 100644
--- a/spec/services/work_items/parent_links/destroy_service_spec.rb
+++ b/spec/services/work_items/parent_links/destroy_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::ParentLinks::DestroyService do
+RSpec.describe WorkItems::ParentLinks::DestroyService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
diff --git a/spec/services/work_items/task_list_reference_removal_service_spec.rb b/spec/services/work_items/task_list_reference_removal_service_spec.rb
index 91b7814ae92..4e87ce66c21 100644
--- a/spec/services/work_items/task_list_reference_removal_service_spec.rb
+++ b/spec/services/work_items/task_list_reference_removal_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::TaskListReferenceRemovalService do
+RSpec.describe WorkItems::TaskListReferenceRemovalService, feature_category: :team_planning do
let_it_be(:developer) { create(:user) }
let_it_be(:project) { create(:project, :repository).tap { |project| project.add_developer(developer) } }
let_it_be(:task) { create(:work_item, project: project, title: 'Task title') }
diff --git a/spec/services/work_items/task_list_reference_replacement_service_spec.rb b/spec/services/work_items/task_list_reference_replacement_service_spec.rb
index 965c5f1d554..8f696109fa1 100644
--- a/spec/services/work_items/task_list_reference_replacement_service_spec.rb
+++ b/spec/services/work_items/task_list_reference_replacement_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::TaskListReferenceReplacementService do
+RSpec.describe WorkItems::TaskListReferenceReplacementService, feature_category: :team_planning do
let_it_be(:developer) { create(:user) }
let_it_be(:project) { create(:project, :repository).tap { |project| project.add_developer(developer) } }
let_it_be(:single_line_work_item, refind: true) { create(:work_item, project: project, description: '- [ ] single line', lock_version: 3) }
diff --git a/spec/services/work_items/update_service_spec.rb b/spec/services/work_items/update_service_spec.rb
index 435995c6570..5647f8c085c 100644
--- a/spec/services/work_items/update_service_spec.rb
+++ b/spec/services/work_items/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::UpdateService do
+RSpec.describe WorkItems::UpdateService, feature_category: :team_planning do
let_it_be(:developer) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/services/work_items/widgets/assignees_service/update_service_spec.rb b/spec/services/work_items/widgets/assignees_service/update_service_spec.rb
index 0ab2c85f078..67736592876 100644
--- a/spec/services/work_items/widgets/assignees_service/update_service_spec.rb
+++ b/spec/services/work_items/widgets/assignees_service/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::Widgets::AssigneesService::UpdateService, :freeze_time do
+RSpec.describe WorkItems::Widgets::AssigneesService::UpdateService, :freeze_time, feature_category: :portfolio_management do
let_it_be(:reporter) { create(:user) }
let_it_be(:project) { create(:project, :private) }
let_it_be(:new_assignee) { create(:user) }
diff --git a/spec/services/work_items/widgets/description_service/update_service_spec.rb b/spec/services/work_items/widgets/description_service/update_service_spec.rb
index 4275950e720..20b5758dde9 100644
--- a/spec/services/work_items/widgets/description_service/update_service_spec.rb
+++ b/spec/services/work_items/widgets/description_service/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::Widgets::DescriptionService::UpdateService do
+RSpec.describe WorkItems::Widgets::DescriptionService::UpdateService, feature_category: :portfolio_management do
let_it_be(:random_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:guest) { create(:user) }
diff --git a/spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb b/spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb
new file mode 100644
index 00000000000..8d834c9a4f8
--- /dev/null
+++ b/spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::Widgets::HierarchyService::CreateService, feature_category: :portfolio_management do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:parent_item) { create(:work_item, project: project) }
+
+ let(:widget) { parent_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Hierarchy) } }
+
+ shared_examples 'raises a WidgetError' do
+ it { expect { subject }.to raise_error(described_class::WidgetError, message) }
+ end
+
+ before(:all) do
+ project.add_developer(user)
+ end
+
+ describe '#create' do
+ subject { described_class.new(widget: widget, current_user: user).after_create_in_transaction(params: params) }
+
+ context 'when invalid params are present' do
+ let(:params) { { other_parent: 'parent_work_item' } }
+
+ it_behaves_like 'raises a WidgetError' do
+ let(:message) { 'One or more arguments are invalid: other_parent.' }
+ end
+ end
+ end
+end
diff --git a/spec/services/work_items/widgets/milestone_service/create_service_spec.rb b/spec/services/work_items/widgets/milestone_service/create_service_spec.rb
index 3f90784b703..64ab2421c74 100644
--- a/spec/services/work_items/widgets/milestone_service/create_service_spec.rb
+++ b/spec/services/work_items/widgets/milestone_service/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::Widgets::MilestoneService::CreateService do
+RSpec.describe WorkItems::Widgets::MilestoneService::CreateService, feature_category: :portfolio_management do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :private, group: group) }
let_it_be(:project_milestone) { create(:milestone, project: project) }
diff --git a/spec/services/work_items/widgets/milestone_service/update_service_spec.rb b/spec/services/work_items/widgets/milestone_service/update_service_spec.rb
index f3a7fc156b9..c5bc2b12fc5 100644
--- a/spec/services/work_items/widgets/milestone_service/update_service_spec.rb
+++ b/spec/services/work_items/widgets/milestone_service/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::Widgets::MilestoneService::UpdateService do
+RSpec.describe WorkItems::Widgets::MilestoneService::UpdateService, feature_category: :portfolio_management do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :private, group: group) }
let_it_be(:project_milestone) { create(:milestone, project: project) }
diff --git a/spec/services/work_items/widgets/notifications_service/update_service_spec.rb b/spec/services/work_items/widgets/notifications_service/update_service_spec.rb
new file mode 100644
index 00000000000..9615020fe49
--- /dev/null
+++ b/spec/services/work_items/widgets/notifications_service/update_service_spec.rb
@@ -0,0 +1,117 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::Widgets::NotificationsService::UpdateService, feature_category: :team_planning do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :private, group: group) }
+ let_it_be(:guest) { create(:user).tap { |u| project.add_guest(u) } }
+ let_it_be(:author) { create(:user).tap { |u| project.add_guest(u) } }
+ let_it_be_with_reload(:work_item) { create(:work_item, project: project, author: author) }
+ let_it_be(:current_user) { guest }
+
+ let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Notifications) } }
+ let(:service) { described_class.new(widget: widget, current_user: current_user) }
+
+ describe '#before_update_in_transaction' do
+ let(:expected) { params[:subscribed] }
+
+ subject(:update_notifications) { service.before_update_in_transaction(params: params) }
+
+ shared_examples 'failing to update subscription' do
+ context 'when user is subscribed with a subscription record' do
+ let_it_be(:subscription) { create_subscription(:subscribed) }
+
+ it "does not update the work item's subscription" do
+ expect do
+ update_notifications
+ subscription.reload
+ end.to not_change { subscription.subscribed }
+ .and(not_change { work_item.subscribed?(current_user, project) })
+ end
+ end
+
+ context 'when user is subscribed by being a participant' do
+ let_it_be(:current_user) { author }
+
+ it 'does not create subscription record or change subscription state' do
+ expect { update_notifications }
+ .to not_change { Subscription.count }
+ .and(not_change { work_item.subscribed?(current_user, project) })
+ end
+ end
+ end
+
+ shared_examples 'updating notifications subscription successfully' do
+ it 'updates existing subscription record' do
+ expect do
+ update_notifications
+ subscription.reload
+ end.to change { subscription.subscribed }.to(expected)
+ .and(change { work_item.subscribed?(current_user, project) }.to(expected))
+ end
+ end
+
+ context 'when update fails' do
+ context 'when user lack update_subscription permissions' do
+ let_it_be(:params) { { subscribed: false } }
+
+ before do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?)
+ .with(current_user, :update_subscription, work_item)
+ .and_return(false)
+ end
+
+ it_behaves_like 'failing to update subscription'
+ end
+
+ context 'when notifications params are not present' do
+ let_it_be(:params) { {} }
+
+ it_behaves_like 'failing to update subscription'
+ end
+ end
+
+ context 'when update is successful' do
+ context 'when subscribing' do
+ let_it_be(:subscription) { create_subscription(:unsubscribed) }
+ let(:params) { { subscribed: true } }
+
+ it_behaves_like 'updating notifications subscription successfully'
+ end
+
+ context 'when unsubscribing' do
+ let(:params) { { subscribed: false } }
+
+ context 'when user is subscribed with a subscription record' do
+ let_it_be(:subscription) { create_subscription(:subscribed) }
+
+ it_behaves_like 'updating notifications subscription successfully'
+ end
+
+ context 'when user is subscribed by being a participant' do
+ let_it_be(:current_user) { author }
+
+ it 'creates a subscription with expected value' do
+ expect { update_notifications }
+ .to change { Subscription.count }.by(1)
+ .and(change { work_item.subscribed?(current_user, project) }.to(expected))
+
+ expect(Subscription.last.subscribed).to eq(expected)
+ end
+ end
+ end
+ end
+ end
+
+ def create_subscription(state)
+ create(
+ :subscription,
+ project: project,
+ user: current_user,
+ subscribable: work_item,
+ subscribed: (state == :subscribed)
+ )
+ end
+end
diff --git a/spec/services/work_items/widgets/start_and_due_date_service/update_service_spec.rb b/spec/services/work_items/widgets/start_and_due_date_service/update_service_spec.rb
index d328c541fc7..a46e9ac9f7a 100644
--- a/spec/services/work_items/widgets/start_and_due_date_service/update_service_spec.rb
+++ b/spec/services/work_items/widgets/start_and_due_date_service/update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkItems::Widgets::StartAndDueDateService::UpdateService do
+RSpec.describe WorkItems::Widgets::StartAndDueDateService::UpdateService, feature_category: :portfolio_management do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be_with_reload(:work_item) { create(:work_item, project: project) }
diff --git a/spec/services/x509_certificate_revoke_service_spec.rb b/spec/services/x509_certificate_revoke_service_spec.rb
index ff5d2dc058b..460381afd79 100644
--- a/spec/services/x509_certificate_revoke_service_spec.rb
+++ b/spec/services/x509_certificate_revoke_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe X509CertificateRevokeService do
+RSpec.describe X509CertificateRevokeService, feature_category: :system_access do
describe '#execute' do
let(:service) { described_class.new }
let!(:x509_signature_1) { create(:x509_commit_signature, x509_certificate: x509_certificate, verification_status: :verified) }
diff --git a/spec/simplecov_env.rb b/spec/simplecov_env.rb
index 07a23021ef5..bea312369f7 100644
--- a/spec/simplecov_env.rb
+++ b/spec/simplecov_env.rb
@@ -10,6 +10,7 @@ module SimpleCovEnv
def start!
return if !ENV.key?('SIMPLECOV') || ENV['SIMPLECOV'] == '0'
+ return if SimpleCov.running
configure_profile
configure_job
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 4e8f990fc10..3b50d821b4c 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -7,9 +7,7 @@ if $LOADED_FEATURES.include?(File.expand_path('fast_spec_helper.rb', __dir__))
abort 'Aborting...'
end
-# Enable deprecation warnings by default and make them more visible
-# to developers to ease upgrading to newer Ruby versions.
-Warning[:deprecated] = true unless ENV.key?('SILENCE_DEPRECATIONS')
+require './spec/deprecation_warnings'
require './spec/deprecation_toolkit_env'
DeprecationToolkitEnv.configure!
@@ -38,6 +36,7 @@ require 'test_prof/recipes/rspec/let_it_be'
require 'test_prof/factory_default'
require 'test_prof/factory_prof/nate_heckler'
require 'parslet/rig/rspec'
+require 'axe-rspec'
rspec_profiling_is_configured =
ENV['RSPEC_PROFILING_POSTGRES_URL'].present? ||
@@ -178,6 +177,8 @@ RSpec.configure do |config|
config.include RenderedHelpers
config.include RSpec::Benchmark::Matchers, type: :benchmark
config.include DetailedErrorHelpers
+ config.include RequestUrgencyMatcher, type: :controller
+ config.include RequestUrgencyMatcher, type: :request
config.include_context 'when rendered has no HTML escapes', type: :view
@@ -356,35 +357,14 @@ RSpec.configure do |config|
# All API specs will be adapted continuously. The following list contains the specs that have not yet been adapted.
# The feature flag is disabled for these specs as long as they are not yet adapted.
admin_mode_for_api_feature_flag_paths = %w[
- ./spec/frontend/fixtures/api_deploy_keys.rb
- ./spec/requests/api/admin/batched_background_migrations_spec.rb
- ./spec/requests/api/admin/ci/variables_spec.rb
- ./spec/requests/api/admin/instance_clusters_spec.rb
- ./spec/requests/api/admin/plan_limits_spec.rb
- ./spec/requests/api/admin/sidekiq_spec.rb
./spec/requests/api/broadcast_messages_spec.rb
- ./spec/requests/api/ci/pipelines_spec.rb
- ./spec/requests/api/ci/runners_reset_registration_token_spec.rb
- ./spec/requests/api/ci/runners_spec.rb
./spec/requests/api/deploy_keys_spec.rb
./spec/requests/api/deploy_tokens_spec.rb
- ./spec/requests/api/freeze_periods_spec.rb
- ./spec/requests/api/graphql/user/starred_projects_query_spec.rb
./spec/requests/api/groups_spec.rb
- ./spec/requests/api/issues/get_group_issues_spec.rb
- ./spec/requests/api/issues/get_project_issues_spec.rb
- ./spec/requests/api/issues/issues_spec.rb
- ./spec/requests/api/issues/post_projects_issues_spec.rb
- ./spec/requests/api/issues/put_projects_issues_spec.rb
./spec/requests/api/keys_spec.rb
./spec/requests/api/merge_requests_spec.rb
./spec/requests/api/namespaces_spec.rb
./spec/requests/api/notes_spec.rb
- ./spec/requests/api/pages/internal_access_spec.rb
- ./spec/requests/api/pages/pages_spec.rb
- ./spec/requests/api/pages/private_access_spec.rb
- ./spec/requests/api/pages/public_access_spec.rb
- ./spec/requests/api/pages_domains_spec.rb
./spec/requests/api/personal_access_tokens/self_information_spec.rb
./spec/requests/api/personal_access_tokens_spec.rb
./spec/requests/api/project_export_spec.rb
@@ -544,19 +524,17 @@ RSpec.configure do |config|
end
end
- # Makes diffs show entire non-truncated values.
- config.before(:each, unlimited_max_formatted_output_length: true) do |_example|
- config.expect_with :rspec do |c|
- c.max_formatted_output_length = nil
- end
- end
-
# Ensures that any Javascript script that tries to make the external VersionCheck API call skips it and returns a response
config.before(:each, :js) do
allow_any_instance_of(VersionCheck).to receive(:response).and_return({ "severity" => "success" })
end
end
+# Disabled because it's causing N+1 queries.
+# See https://gitlab.com/gitlab-org/gitlab/-/issues/396352.
+# Support::AbilityCheck.inject(Ability.singleton_class)
+Support::PermissionsCheck.inject(Ability.singleton_class)
+
ActiveRecord::Migration.maintain_test_schema!
Shoulda::Matchers.configure do |config|
diff --git a/spec/support/ability_check.rb b/spec/support/ability_check.rb
new file mode 100644
index 00000000000..213944506bb
--- /dev/null
+++ b/spec/support/ability_check.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'gitlab/utils/strong_memoize'
+
+module Support
+ module AbilityCheck
+ def self.inject(mod)
+ mod.prepend AbilityExtension
+ end
+
+ module AbilityExtension
+ def before_check(policy, ability, user, subject, opts)
+ return super if Checker.ok?(policy, ability)
+
+ ActiveSupport::Deprecation.warn(<<~WARNING)
+ Ability #{ability.inspect} in #{policy.class} not found.
+ user=#{user.inspect}, subject=#{subject}, opts=#{opts.inspect}"
+
+ To exclude this check add this entry to #{Checker::TODO_YAML}:
+ #{policy.class}:
+ - #{ability}
+ WARNING
+ end
+ end
+
+ module Checker
+ include Gitlab::Utils::StrongMemoize
+ extend self
+
+ TODO_YAML = File.join(__dir__, 'ability_check_todo.yml')
+
+ def ok?(policy, ability)
+ ignored?(policy, ability) || ability_found?(policy, ability)
+ end
+
+ private
+
+ def ignored?(policy, ability)
+ todo_list[policy.class.name]&.include?(ability.to_s)
+ end
+
+ # Use Policy#has_ability? instead after it has been accepted and released.
+ # See https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/issues/25
+ def ability_found?(policy, ability)
+ # NilPolicy has no abilities. Ignore it.
+ return true if policy.is_a?(DeclarativePolicy::NilPolicy)
+
+ # Search in current policy first
+ return true if policy.class.ability_map.map.key?(ability)
+
+ # Search recursively in all delegations otherwise.
+ # This is potentially slow.
+ # Stolen from:
+ # https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/blob/d691e/lib/declarative_policy/base.rb#L360-369
+ policy.class.delegations.any? do |_, block|
+ new_subject = policy.instance_eval(&block)
+ new_policy = policy.policy_for(new_subject)
+
+ ability_found?(new_policy, ability)
+ end
+ end
+
+ def todo_list
+ hash = YAML.load_file(TODO_YAML)
+ return {} unless hash.is_a?(Hash)
+
+ hash.transform_values(&:to_set)
+ end
+
+ strong_memoize_attr :todo_list
+ end
+ end
+end
diff --git a/spec/support/ability_check_todo.yml b/spec/support/ability_check_todo.yml
new file mode 100644
index 00000000000..eafd595b137
--- /dev/null
+++ b/spec/support/ability_check_todo.yml
@@ -0,0 +1,73 @@
+# This list tracks unknown abilities per policy.
+#
+# This file is used by `spec/support/ability_check.rb`.
+#
+# Each TODO entry means that an ability wasn't found in
+# the particular policy class or its delegations.
+#
+# This could be one of the reasons:
+# * The ability is misspelled.
+# - Suggested action: Fix typo.
+# * The ability has been removed from a policy but is still in use.
+# - Remove production code in question.
+# * The ability is defined in EE policy but is used in FOSS code.
+# - Guard the check or move it to EE folder.
+# - See https://docs.gitlab.com/ee/development/ee_features.html
+# * The ability is defined in another policy but delegation is missing.
+# - Add delegation policy or guard the check with a type check.
+# - See https://docs.gitlab.com/ee/development/policies.html#delegation
+# * The ability check is polymorphic (for example, Issuable) and some policies
+# do not implement this ability.
+# - Exclude TODO permanently below.
+# - Guard the check with a type check.
+# * The ability check is defined on GraphQL field which does not support
+# authorization on resolved field values yet.
+# See https://gitlab.com/gitlab-org/gitlab/-/issues/300922
+---
+# <Policy class>:
+# - <ability name>
+# - <ability name>
+# ...
+
+# Temporary excludes:
+
+Ci::BridgePolicy:
+- read_job_artifacts
+CommitStatusPolicy:
+- read_job_artifacts
+EpicPolicy:
+- create_timelog
+- read_emoji
+- set_issue_crm_contacts
+GlobalPolicy:
+- read_achievement
+- read_on_demand_dast_scan
+- update_max_pages_size
+GroupPolicy:
+- admin_merge_request
+- change_push_rules
+- manage_owners
+IssuePolicy:
+- create_test_case
+MergeRequestPolicy:
+- set_confidentiality
+- set_issue_crm_contacts
+Namespaces::UserNamespacePolicy:
+- read_crm_contact
+PersonalSnippetPolicy:
+- read_internal_note
+- read_project
+ProjectMemberPolicy:
+- override_project_member
+ProjectPolicy:
+- admin_feature_flags_issue_links
+- admin_vulnerability
+- create_requirement
+- create_test_case
+- read_group_saml_identity
+UserPolicy:
+- admin_observability
+- admin_terraform_state
+- read_observability
+
+# Permanent excludes (please provide a reason):
diff --git a/spec/support/helpers/ci/template_helpers.rb b/spec/support/helpers/ci/template_helpers.rb
index cd3ab4bd82d..1818dec5fc7 100644
--- a/spec/support/helpers/ci/template_helpers.rb
+++ b/spec/support/helpers/ci/template_helpers.rb
@@ -6,6 +6,10 @@ module Ci
'registry.gitlab.com'
end
+ def auto_build_image_repository
+ "gitlab-org/cluster-integration/auto-build-image"
+ end
+
def public_image_exist?(registry, repository, image)
public_image_manifest(registry, repository, image).present?
end
diff --git a/spec/support/helpers/content_editor_helpers.rb b/spec/support/helpers/content_editor_helpers.rb
new file mode 100644
index 00000000000..c12fd1fbbd7
--- /dev/null
+++ b/spec/support/helpers/content_editor_helpers.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module ContentEditorHelpers
+ def switch_to_content_editor
+ click_button _('Viewing markdown')
+ click_button _('Rich text')
+ end
+
+ def type_in_content_editor(keys)
+ find(content_editor_testid).send_keys keys
+ end
+
+ def open_insert_media_dropdown
+ page.find('svg[data-testid="media-icon"]').click
+ end
+
+ def set_source_editor_content(content)
+ find('.js-gfm-input').set content
+ end
+
+ def expect_formatting_menu_to_be_visible
+ expect(page).to have_css('[data-testid="formatting-bubble-menu"]')
+ end
+
+ def expect_formatting_menu_to_be_hidden
+ expect(page).not_to have_css('[data-testid="formatting-bubble-menu"]')
+ end
+
+ def expect_media_bubble_menu_to_be_visible
+ expect(page).to have_css('[data-testid="media-bubble-menu"]')
+ end
+
+ def upload_asset(fixture_name)
+ attach_file('content_editor_image', Rails.root.join('spec', 'fixtures', fixture_name), make_visible: true)
+ end
+
+ def wait_until_hidden_field_is_updated(value)
+ expect(page).to have_field(with: value, type: 'hidden')
+ end
+
+ def display_media_bubble_menu(media_element_selector, fixture_file)
+ upload_asset fixture_file
+
+ wait_for_requests
+
+ expect(page).to have_css(media_element_selector)
+
+ page.find(media_element_selector).click
+ end
+
+ def click_edit_diagram_button
+ page.find('[data-testid="edit-diagram"]').click
+ end
+
+ def expect_drawio_editor_is_opened
+ expect(page).to have_css('#drawio-frame', visible: :hidden)
+ end
+end
diff --git a/spec/support/helpers/fake_u2f_device.rb b/spec/support/helpers/fake_u2f_device.rb
deleted file mode 100644
index 2ed1222ebd3..00000000000
--- a/spec/support/helpers/fake_u2f_device.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-class FakeU2fDevice
- attr_reader :name
-
- def initialize(page, name, device = nil)
- @page = page
- @name = name
- @u2f_device = device
- end
-
- def respond_to_u2f_registration
- app_id = @page.evaluate_script('gon.u2f.app_id')
- challenges = @page.evaluate_script('gon.u2f.challenges')
-
- json_response = u2f_device(app_id).register_response(challenges[0])
-
- @page.execute_script("
- u2f.register = function(appId, registerRequests, signRequests, callback) {
- callback(#{json_response});
- };
- ")
- end
-
- def respond_to_u2f_authentication
- app_id = @page.evaluate_script('gon.u2f.app_id')
- challenge = @page.evaluate_script('gon.u2f.challenge')
- json_response = u2f_device(app_id).sign_response(challenge)
-
- @page.execute_script("
- u2f.sign = function(appId, challenges, signRequests, callback) {
- callback(#{json_response});
- };
- window.gl.u2fAuthenticate.start();
- ")
- end
-
- def fake_u2f_authentication
- @page.execute_script("window.gl.u2fAuthenticate.renderAuthenticated('abc');")
- end
-
- private
-
- def u2f_device(app_id)
- @u2f_device ||= U2F::FakeU2F.new(app_id)
- end
-end
diff --git a/spec/support/helpers/features/two_factor_helpers.rb b/spec/support/helpers/features/two_factor_helpers.rb
index 08a7665201f..d5f069a40ea 100644
--- a/spec/support/helpers/features/two_factor_helpers.rb
+++ b/spec/support/helpers/features/two_factor_helpers.rb
@@ -14,23 +14,25 @@ module Spec
module Helpers
module Features
module TwoFactorHelpers
+ def copy_recovery_codes
+ click_on _('Copy codes')
+ click_on _('Proceed')
+ end
+
+ def enable_two_factor_authentication
+ click_on _('Enable two-factor authentication')
+ expect(page).to have_content(_('Set up new device'))
+ wait_for_requests
+ end
+
def manage_two_factor_authentication
click_on 'Manage two-factor authentication'
expect(page).to have_content("Set up new device")
wait_for_requests
end
- def register_u2f_device(u2f_device = nil, name: 'My device')
- u2f_device ||= FakeU2fDevice.new(page, name)
- u2f_device.respond_to_u2f_registration
- click_on 'Set up new device'
- expect(page).to have_content('Your device was successfully set up')
- fill_in "Pick a name", with: name
- click_on 'Register device'
- u2f_device
- end
-
# Registers webauthn device via UI
+ # Remove after `webauthn_without_totp` feature flag is deleted.
def register_webauthn_device(webauthn_device = nil, name: 'My device')
webauthn_device ||= FakeWebauthnDevice.new(page, name)
webauthn_device.respond_to_webauthn_registration
@@ -41,6 +43,25 @@ module Spec
webauthn_device
end
+ def webauthn_device_registration(webauthn_device: nil, name: 'My device', password: 'fake')
+ webauthn_device ||= FakeWebauthnDevice.new(page, name)
+ webauthn_device.respond_to_webauthn_registration
+ click_on _('Set up new device')
+ webauthn_fill_form_and_submit(name: name, password: password)
+ webauthn_device
+ end
+
+ def webauthn_fill_form_and_submit(name: 'My device', password: 'fake')
+ expect(page).to have_content(
+ _('Your device was successfully set up! Give it a name and register it with the GitLab server.')
+ )
+ within '[data-testid="create-webauthn"]' do
+ fill_in _('Device name'), with: name
+ fill_in _('Current password'), with: password
+ click_on _('Register device')
+ end
+ end
+
# Adds webauthn device directly via database
def add_webauthn_device(app_id, user, fake_device = nil, name: 'My device')
fake_device ||= WebAuthn::FakeClient.new(app_id)
diff --git a/spec/support/helpers/filtered_search_helpers.rb b/spec/support/helpers/filtered_search_helpers.rb
index 677cea7b804..b07f5dcf2e1 100644
--- a/spec/support/helpers/filtered_search_helpers.rb
+++ b/spec/support/helpers/filtered_search_helpers.rb
@@ -190,9 +190,9 @@ module FilteredSearchHelpers
##
# For use with gl-filtered-search
- def select_tokens(*args, submit: false)
+ def select_tokens(*args, submit: false, input_text: 'Search')
within '[data-testid="filtered-search-input"]' do
- find_field('Search').click
+ find_field(input_text).click
args.each do |token|
# Move mouse away to prevent invoking tooltips on usernames, which blocks the search input
@@ -230,6 +230,13 @@ module FilteredSearchHelpers
find('.gl-filtered-search-token-segment', text: value).click
end
+ def toggle_sort_direction
+ page.within('.vue-filtered-search-bar-container .sort-dropdown-container') do
+ page.find("button[title^='Sort direction']").click
+ wait_for_requests
+ end
+ end
+
def expect_visible_suggestions_list
expect(page).to have_css('.gl-filtered-search-suggestion-list')
end
diff --git a/spec/support/helpers/fixture_helpers.rb b/spec/support/helpers/fixture_helpers.rb
index 7b3b8ae5f7a..eafdecb2e3d 100644
--- a/spec/support/helpers/fixture_helpers.rb
+++ b/spec/support/helpers/fixture_helpers.rb
@@ -8,6 +8,6 @@ module FixtureHelpers
end
def expand_fixture_path(filename, dir: '')
- File.expand_path(Rails.root.join(dir, 'spec', 'fixtures', filename))
+ File.expand_path(rails_root_join(dir, 'spec', 'fixtures', filename))
end
end
diff --git a/spec/support/helpers/gitaly_setup.rb b/spec/support/helpers/gitaly_setup.rb
index 398a2a20f2f..bf3c67a1818 100644
--- a/spec/support/helpers/gitaly_setup.rb
+++ b/spec/support/helpers/gitaly_setup.rb
@@ -198,8 +198,23 @@ module GitalySetup
end
LOGGER.debug "Checking gitaly-ruby bundle...\n"
+
+ bundle_install unless bundle_check
+
+ abort 'bundle check failed' unless bundle_check
+ end
+
+ def bundle_check
+ bundle_cmd('check')
+ end
+
+ def bundle_install
+ bundle_cmd('install')
+ end
+
+ def bundle_cmd(cmd)
out = ENV['CI'] ? $stdout : '/dev/null'
- abort 'bundle check failed' unless system(env, 'bundle', 'check', out: out, chdir: gemfile_dir)
+ system(env, 'bundle', cmd, out: out, chdir: gemfile_dir)
end
def connect_proc(toml)
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 2176a477371..191e5192a61 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -310,7 +310,7 @@ module GraphqlHelpers
"{ #{q} }"
end
- def graphql_mutation(name, input, fields = nil, &block)
+ def graphql_mutation(name, input, fields = nil, excluded = [], &block)
raise ArgumentError, 'Please pass either `fields` parameter or a block to `#graphql_mutation`, but not both.' if fields.present? && block
name = name.graphql_name if name.respond_to?(:graphql_name)
@@ -319,7 +319,7 @@ module GraphqlHelpers
mutation_field = GitlabSchema.mutation.fields[mutation_name]
fields = yield if block
- fields ||= all_graphql_fields_for(mutation_field.type.to_type_signature)
+ fields ||= all_graphql_fields_for(mutation_field.type.to_type_signature, excluded: excluded)
query = <<~MUTATION
mutation(#{input_variable_name}: #{mutation_field.arguments['input'].type.to_type_signature}) {
diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb
index 5fde80e6dc9..e93d04a0b80 100644
--- a/spec/support/helpers/login_helpers.rb
+++ b/spec/support/helpers/login_helpers.rb
@@ -139,11 +139,6 @@ module LoginHelpers
click_link_or_button "oauth-login-#{provider}"
end
- def fake_successful_u2f_authentication
- allow(U2fRegistration).to receive(:authenticate).and_return(true)
- FakeU2fDevice.new(page, nil).fake_u2f_authentication
- end
-
def fake_successful_webauthn_authentication
allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true)
FakeWebauthnDevice.new(page, nil).fake_webauthn_authentication
@@ -218,6 +213,15 @@ module LoginHelpers
config
end
+ def prepare_provider_route(provider_name)
+ routes = Rails.application.routes
+ routes.disable_clear_and_finalize = true
+ routes.formatter.clear
+ routes.draw do
+ post "/users/auth/#{provider_name}" => "omniauth_callbacks##{provider_name}"
+ end
+ end
+
def stub_omniauth_provider(provider, context: Rails.application)
env = env_from_context(context)
diff --git a/spec/support/helpers/navbar_structure_helper.rb b/spec/support/helpers/navbar_structure_helper.rb
index 48c6e590e1b..8248ea0bb84 100644
--- a/spec/support/helpers/navbar_structure_helper.rb
+++ b/spec/support/helpers/navbar_structure_helper.rb
@@ -106,6 +106,14 @@ module NavbarStructureHelper
)
end
+ def insert_infrastructure_aws_nav
+ insert_after_sub_nav_item(
+ _('Google Cloud'),
+ within: _('Infrastructure'),
+ new_sub_nav_item_name: _('AWS')
+ )
+ end
+
def project_analytics_sub_nav_item
[
_('Value stream'),
diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb
index 5be9ba9ae1e..e8fa73a1b95 100644
--- a/spec/support/helpers/query_recorder.rb
+++ b/spec/support/helpers/query_recorder.rb
@@ -102,6 +102,10 @@ module ActiveRecord
@occurrences ||= @log.group_by(&:to_s).transform_values(&:count)
end
+ def occurrences_starting_with(str)
+ occurrences.select { |query, _count| query.starts_with?(str) }
+ end
+
def ignorable?(values)
return true if skip_schema_queries && values[:name]&.include?("SCHEMA")
return true if values[:name]&.match(/License Load/)
diff --git a/spec/support/helpers/repo_helpers.rb b/spec/support/helpers/repo_helpers.rb
index 9f37cf61cc9..45467fb7099 100644
--- a/spec/support/helpers/repo_helpers.rb
+++ b/spec/support/helpers/repo_helpers.rb
@@ -41,6 +41,7 @@ eos
line_code: '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14',
line_code_path: 'files/ruby/popen.rb',
del_line_code: '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13',
+ referenced_by: [],
message: <<eos
Change some files
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
@@ -56,6 +57,7 @@ eos
author_full_name: "Sytse Sijbrandij",
author_email: "sytse@gitlab.com",
files_changed_count: 1,
+ referenced_by: [],
message: <<eos
Add directory structure for tree_helper spec
@@ -74,6 +76,7 @@ eos
sha: "913c66a37b4a45b9769037c55c2d238bd0942d2e",
author_full_name: "Dmitriy Zaporozhets",
author_email: "dmitriy.zaporozhets@gmail.com",
+ referenced_by: [],
message: <<eos
Files, encoding and much more
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
@@ -89,6 +92,7 @@ eos
author_email: "dmitriy.zaporozhets@gmail.com",
old_blob_id: '33f3729a45c02fc67d00adb1b8bca394b0e761d9',
new_blob_id: '2f63565e7aac07bcdadb654e253078b727143ec4',
+ referenced_by: [],
message: <<eos
Modified image
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index 4ca8f26be9e..2a7b36a4c00 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -179,7 +179,7 @@ module StubConfiguration
def to_settings(hash)
hash.transform_values do |value|
if value.is_a? Hash
- Settingslogic.new(value.deep_stringify_keys)
+ Settingslogic.new(value.to_h.deep_stringify_keys)
else
value
end
diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb
index 6b633856228..d120e1805e3 100644
--- a/spec/support/helpers/stub_object_storage.rb
+++ b/spec/support/helpers/stub_object_storage.rb
@@ -15,7 +15,7 @@ module StubObjectStorage
direct_upload: false,
cdn: {}
)
- old_config = Settingslogic.new(config.deep_stringify_keys)
+ old_config = Settingslogic.new(config.to_h.deep_stringify_keys)
new_config = config.to_h.deep_symbolize_keys.merge({
enabled: enabled,
proxy_download: proxy_download,
@@ -30,7 +30,7 @@ module StubObjectStorage
allow(config).to receive(:proxy_download) { proxy_download }
allow(config).to receive(:direct_upload) { direct_upload }
- uploader_config = Settingslogic.new(new_config.deep_stringify_keys)
+ uploader_config = Settingslogic.new(new_config.to_h.deep_stringify_keys)
allow(uploader).to receive(:object_store_options).and_return(uploader_config)
allow(uploader.options).to receive(:object_store).and_return(uploader_config)
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index 3403064bf0b..727b8a6b880 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -2,6 +2,7 @@
require 'parallel'
require_relative 'gitaly_setup'
+require_relative '../../../lib/gitlab/setup_helper'
module TestEnv
extend self
diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb
index 2bec945fbc8..9abfc39e31f 100644
--- a/spec/support/helpers/usage_data_helpers.rb
+++ b/spec/support/helpers/usage_data_helpers.rb
@@ -54,8 +54,6 @@ module UsageDataHelpers
projects_asana_active
projects_jenkins_active
projects_jira_active
- projects_jira_server_active
- projects_jira_cloud_active
projects_jira_dvcs_cloud_active
projects_jira_dvcs_server_active
projects_slack_active
diff --git a/spec/support/matchers/background_migrations_matchers.rb b/spec/support/matchers/background_migrations_matchers.rb
index 9f39f576b95..97993b158c8 100644
--- a/spec/support/matchers/background_migrations_matchers.rb
+++ b/spec/support/matchers/background_migrations_matchers.rb
@@ -100,3 +100,17 @@ RSpec::Matchers.define :be_finalize_background_migration_of do |migration|
end
end
end
+
+RSpec::Matchers.define :ensure_batched_background_migration_is_finished_for do |migration_arguments|
+ define_method :matches? do |klass|
+ expect_next_instance_of(klass) do |instance|
+ expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+ end
+
+ define_method :does_not_match? do |klass|
+ expect_next_instance_of(klass) do |instance|
+ expect(instance).not_to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+ end
+end
diff --git a/spec/support/matchers/exceed_redis_call_limit.rb b/spec/support/matchers/exceed_redis_call_limit.rb
new file mode 100644
index 00000000000..2b1e1ebad23
--- /dev/null
+++ b/spec/support/matchers/exceed_redis_call_limit.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module ExceedRedisCallLimitHelpers
+ def build_recorder(block)
+ return block if block.is_a?(RedisCommands::Recorder)
+
+ RedisCommands::Recorder.new(&block)
+ end
+
+ def verify_count(expected, block)
+ @actual = build_recorder(block).count
+
+ @actual > expected
+ end
+
+ def verify_commands_count(command, expected, block)
+ @actual = build_recorder(block).by_command(command).count
+
+ @actual > expected
+ end
+end
+
+RSpec::Matchers.define :exceed_redis_calls_limit do |expected|
+ supports_block_expectations
+
+ include ExceedRedisCallLimitHelpers
+
+ match do |block|
+ verify_count(expected, block)
+ end
+
+ failure_message do
+ "Expected at least #{expected} calls, but got #{actual}"
+ end
+
+ failure_message_when_negated do
+ "Expected a maximum of #{expected} calls, but got #{actual}"
+ end
+end
+
+RSpec::Matchers.define :exceed_redis_command_calls_limit do |command, expected|
+ supports_block_expectations
+
+ include ExceedRedisCallLimitHelpers
+
+ match do |block|
+ verify_commands_count(command, expected, block)
+ end
+
+ failure_message do
+ "Expected at least #{expected} calls to '#{command}', but got #{actual}"
+ end
+
+ failure_message_when_negated do
+ "Expected a maximum of #{expected} calls to '#{command}', but got #{actual}"
+ end
+end
diff --git a/spec/support/matchers/request_urgency_matcher.rb b/spec/support/matchers/request_urgency_matcher.rb
new file mode 100644
index 00000000000..d3c5093719e
--- /dev/null
+++ b/spec/support/matchers/request_urgency_matcher.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+module RequestUrgencyMatcher
+ RSpec::Matchers.define :have_request_urgency do |request_urgency|
+ match do |_actual|
+ if controller_instance = request.env["action_controller.instance"]
+ controller_instance.urgency.name == request_urgency
+ elsif endpoint = request.env['api.endpoint']
+ urgency = endpoint.options[:for].try(:urgency_for_app, endpoint)
+ urgency.name == request_urgency
+ else
+ raise 'neither a controller nor a request spec'
+ end
+ end
+
+ failure_message do |_actual|
+ if controller_instance = request.env["action_controller.instance"]
+ "request urgency #{controller_instance.urgency.name} is set, \
+ but expected to be #{request_urgency}".squish
+ elsif endpoint = request.env['api.endpoint']
+ urgency = endpoint.options[:for].try(:urgency_for_app, endpoint)
+ "request urgency #{urgency.name} is set, \
+ but expected to be #{request_urgency}".squish
+ end
+ end
+ end
+end
diff --git a/spec/support/permissions_check.rb b/spec/support/permissions_check.rb
new file mode 100644
index 00000000000..efe0ecb530b
--- /dev/null
+++ b/spec/support/permissions_check.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Support
+ module PermissionsCheck
+ def self.inject(mod)
+ mod.prepend PermissionsExtension if Gitlab::Utils.to_boolean(ENV['GITLAB_DEBUG_POLICIES'])
+ end
+
+ module PermissionsExtension
+ def before_check(policy, ability, _user, _subject, _opts)
+ puts(
+ "POLICY CHECK DEBUG -> " \
+ "policy: #{policy.class.name}, ability: #{ability}, called_from: #{caller_locations(2, 5)}"
+ )
+ end
+ end
+ end
+end
diff --git a/spec/support/protected_tags/access_control_ce_shared_examples.rb b/spec/support/protected_tags/access_control_ce_shared_examples.rb
index 8666c19481c..6aa9647bcec 100644
--- a/spec/support/protected_tags/access_control_ce_shared_examples.rb
+++ b/spec/support/protected_tags/access_control_ce_shared_examples.rb
@@ -6,18 +6,8 @@ RSpec.shared_examples "protected tags > access control > CE" do
visit project_protected_tags_path(project)
set_protected_tag_name('master')
-
- within('.js-new-protected-tag') do
- allowed_to_create_button = find(".js-allowed-to-create")
-
- unless allowed_to_create_button.text == access_type_name
- allowed_to_create_button.click
- find('.create_access_levels-container .dropdown-menu li', match: :first)
- within('.create_access_levels-container .dropdown-menu') { click_on access_type_name }
- end
- end
-
- click_on "Protect"
+ set_allowed_to('create', access_type_name)
+ click_on_protect
expect(ProtectedTag.count).to eq(1)
expect(ProtectedTag.last.create_access_levels.map(&:access_level)).to eq([access_type_id])
@@ -27,19 +17,12 @@ RSpec.shared_examples "protected tags > access control > CE" do
visit project_protected_tags_path(project)
set_protected_tag_name('master')
-
- click_on "Protect"
+ set_allowed_to('create', 'No one')
+ click_on_protect
expect(ProtectedTag.count).to eq(1)
- within(".protected-tags-list") do
- find(".js-allowed-to-create").click
-
- within('.js-allowed-to-create-container') do
- expect(first("li")).to have_content("Roles")
- click_on access_type_name
- end
- end
+ set_allowed_to('create', access_type_name, form: '.protected-tags-list')
wait_for_requests
diff --git a/spec/support/rspec.rb b/spec/support/rspec.rb
index ff0b5bebe33..6e377b8cb0d 100644
--- a/spec/support/rspec.rb
+++ b/spec/support/rspec.rb
@@ -19,6 +19,13 @@ RSpec.configure do |config|
# Re-run failures locally with `--only-failures`
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.expect_with :rspec do |c|
+ c.max_formatted_output_length = nil
+ end
+ end
+
unless ENV['CI']
# Allow running `:focus` examples locally,
# falling back to all tests when there is no `:focus` example.
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 7aa7d8e8abd..74b80c4864c 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -226,7 +226,6 @@
- './ee/spec/features/analytics/code_analytics_spec.rb'
- './ee/spec/features/analytics/group_analytics_spec.rb'
- './ee/spec/features/billings/billing_plans_spec.rb'
-- './ee/spec/features/billings/extend_reactivate_trial_spec.rb'
- './ee/spec/features/billings/qrtly_reconciliation_alert_spec.rb'
- './ee/spec/features/boards/board_filters_spec.rb'
- './ee/spec/features/boards/boards_licensed_features_spec.rb'
@@ -957,7 +956,6 @@
- './ee/spec/helpers/ee/geo_helper_spec.rb'
- './ee/spec/helpers/ee/gitlab_routing_helper_spec.rb'
- './ee/spec/helpers/ee/graph_helper_spec.rb'
-- './ee/spec/helpers/ee/groups/analytics/cycle_analytics_helper_spec.rb'
- './ee/spec/helpers/ee/groups/group_members_helper_spec.rb'
- './ee/spec/helpers/ee/groups_helper_spec.rb'
- './ee/spec/helpers/ee/groups/settings_helper_spec.rb'
@@ -1577,7 +1575,6 @@
- './ee/spec/lib/omni_auth/strategies/group_saml_spec.rb'
- './ee/spec/lib/omni_auth/strategies/kerberos_spec.rb'
- './ee/spec/lib/peek/views/elasticsearch_spec.rb'
-- './ee/spec/lib/sidebars/groups/menus/administration_menu_spec.rb'
- './ee/spec/lib/sidebars/groups/menus/analytics_menu_spec.rb'
- './ee/spec/lib/sidebars/groups/menus/epics_menu_spec.rb'
- './ee/spec/lib/sidebars/groups/menus/security_compliance_menu_spec.rb'
@@ -3201,7 +3198,6 @@
- './ee/spec/workers/concerns/elastic/indexing_control_spec.rb'
- './ee/spec/workers/concerns/elastic/migration_obsolete_spec.rb'
- './ee/spec/workers/concerns/elastic/migration_options_spec.rb'
-- './ee/spec/workers/concerns/geo_queue_spec.rb'
- './ee/spec/workers/concerns/update_orchestration_policy_configuration_spec.rb'
- './ee/spec/workers/create_github_webhook_worker_spec.rb'
- './ee/spec/workers/deployments/auto_rollback_worker_spec.rb'
@@ -5084,7 +5080,6 @@
- './spec/helpers/admin/deploy_key_helper_spec.rb'
- './spec/helpers/admin/identities_helper_spec.rb'
- './spec/helpers/admin/user_actions_helper_spec.rb'
-- './spec/helpers/analytics/cycle_analytics_helper_spec.rb'
- './spec/helpers/appearances_helper_spec.rb'
- './spec/helpers/application_helper_spec.rb'
- './spec/helpers/application_settings_helper_spec.rb'
@@ -5142,7 +5137,6 @@
- './spec/helpers/groups/settings_helper_spec.rb'
- './spec/helpers/hooks_helper_spec.rb'
- './spec/helpers/icons_helper_spec.rb'
-- './spec/helpers/ide_helper_spec.rb'
- './spec/helpers/import_helper_spec.rb'
- './spec/helpers/instance_configuration_helper_spec.rb'
- './spec/helpers/integrations_helper_spec.rb'
@@ -7956,7 +7950,6 @@
- './spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb'
- './spec/models/concerns/transactions_spec.rb'
- './spec/models/concerns/triggerable_hooks_spec.rb'
-- './spec/models/concerns/uniquify_spec.rb'
- './spec/models/concerns/usage_statistics_spec.rb'
- './spec/models/concerns/vulnerability_finding_helpers_spec.rb'
- './spec/models/concerns/vulnerability_finding_signature_helpers_spec.rb'
@@ -8956,7 +8949,6 @@
- './spec/requests/groups/settings/access_tokens_controller_spec.rb'
- './spec/requests/groups/settings/applications_controller_spec.rb'
- './spec/requests/health_controller_spec.rb'
-- './spec/requests/ide_controller_spec.rb'
- './spec/requests/import/gitlab_groups_controller_spec.rb'
- './spec/requests/import/gitlab_projects_controller_spec.rb'
- './spec/requests/import/url_controller_spec.rb'
@@ -10381,18 +10373,14 @@
- './spec/workers/clusters/integrations/check_prometheus_health_worker_spec.rb'
- './spec/workers/concerns/application_worker_spec.rb'
- './spec/workers/concerns/cluster_agent_queue_spec.rb'
-- './spec/workers/concerns/cluster_queue_spec.rb'
- './spec/workers/concerns/cronjob_queue_spec.rb'
- './spec/workers/concerns/gitlab/github_import/object_importer_spec.rb'
-- './spec/workers/concerns/gitlab/github_import/queue_spec.rb'
- './spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb'
- './spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb'
- './spec/workers/concerns/gitlab/notify_upon_death_spec.rb'
- './spec/workers/concerns/limited_capacity/job_tracker_spec.rb'
- './spec/workers/concerns/limited_capacity/worker_spec.rb'
- './spec/workers/concerns/packages/cleanup_artifact_worker_spec.rb'
-- './spec/workers/concerns/pipeline_background_queue_spec.rb'
-- './spec/workers/concerns/pipeline_queue_spec.rb'
- './spec/workers/concerns/project_import_options_spec.rb'
- './spec/workers/concerns/reenqueuer_spec.rb'
- './spec/workers/concerns/repository_check_queue_spec.rb'
diff --git a/spec/support/services/import_csv_service_shared_examples.rb b/spec/support/services/import_csv_service_shared_examples.rb
new file mode 100644
index 00000000000..1555497ae48
--- /dev/null
+++ b/spec/support/services/import_csv_service_shared_examples.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples_for 'importer with email notification' do
+ it 'notifies user of import result' do
+ expect(Notify).to receive_message_chain(email_method, :deliver_later)
+
+ subject
+ end
+end
+
+RSpec.shared_examples 'correctly handles invalid files' do
+ shared_examples_for 'invalid file' do
+ it 'returns invalid file error' do
+ expect(subject[:success]).to eq(0)
+ expect(subject[:parse_error]).to eq(true)
+ end
+ end
+
+ context 'when given file with unsupported extension' do
+ let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
+
+ it_behaves_like 'invalid file'
+ end
+
+ context 'when given empty file' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_empty.csv') }
+
+ it_behaves_like 'invalid file'
+ end
+
+ context 'when given file without headers' do
+ let(:file) { fixture_file_upload('spec/fixtures/csv_no_headers.csv') }
+
+ it_behaves_like 'invalid file'
+ end
+end
diff --git a/spec/support/services/issuable_import_csv_service_shared_examples.rb b/spec/support/services/issuable_import_csv_service_shared_examples.rb
index 0dea6cfb729..71740ba8ab2 100644
--- a/spec/support/services/issuable_import_csv_service_shared_examples.rb
+++ b/spec/support/services/issuable_import_csv_service_shared_examples.rb
@@ -18,45 +18,14 @@ RSpec.shared_examples 'issuable import csv service' do |issuable_type|
end
end
- shared_examples_for 'importer with email notification' do
- it 'notifies user of import result' do
- expect(Notify).to receive_message_chain(email_method, :deliver_later)
-
- subject
- end
- end
-
- shared_examples_for 'invalid file' do
- it 'returns invalid file error' do
- expect(subject[:success]).to eq(0)
- expect(subject[:parse_error]).to eq(true)
- end
-
- it_behaves_like 'importer with email notification'
- it_behaves_like 'an issuable importer'
- end
-
describe '#execute' do
before do
project.add_developer(user)
end
- context 'invalid file extension' do
- let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
-
- it_behaves_like 'invalid file'
- end
-
- context 'empty file' do
- let(:file) { fixture_file_upload('spec/fixtures/csv_empty.csv') }
-
- it_behaves_like 'invalid file'
- end
-
- context 'file without headers' do
- let(:file) { fixture_file_upload('spec/fixtures/csv_no_headers.csv') }
-
- it_behaves_like 'invalid file'
+ it_behaves_like 'correctly handles invalid files' do
+ it_behaves_like 'importer with email notification'
+ it_behaves_like 'an issuable importer'
end
context 'with a file generated by Gitlab CSV export' do
diff --git a/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb
index 2c92ef64815..9612b657093 100644
--- a/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb
+++ b/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb
@@ -74,6 +74,12 @@ Integration.available_integration_names.each do |integration|
hash.merge!(k => File.read('spec/fixtures/ssl_key.pem'))
elsif integration == 'apple_app_store' && k == :app_store_key_id
hash.merge!(k => 'ABC1')
+ elsif integration == 'apple_app_store' && k == :app_store_private_key_file_name
+ hash.merge!(k => 'ssl_key.pem')
+ elsif integration == 'google_play' && k == :service_account_key
+ hash.merge!(k => File.read('spec/fixtures/service_account.json'))
+ elsif integration == 'google_play' && k == :service_account_key_file_name
+ hash.merge!(k => 'service_account.json')
else
hash.merge!(k => "someword")
end
diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb
index b74819d2ac7..866a97b0e3c 100644
--- a/spec/support/shared_contexts/navbar_structure_context.rb
+++ b/spec/support/shared_contexts/navbar_structure_context.rb
@@ -5,10 +5,10 @@ RSpec.shared_context 'project navbar structure' do
let(:security_and_compliance_nav_item) do
{
- nav_item: _('Security & Compliance'),
+ nav_item: _('Security and Compliance'),
nav_sub_items: [
(_('Audit events') if Gitlab.ee?),
- _('Configuration')
+ _('Security configuration')
]
}
end
@@ -34,10 +34,10 @@ RSpec.shared_context 'project navbar structure' do
_('Commits'),
_('Branches'),
_('Tags'),
- _('Contributors'),
+ _('Contributor statistics'),
_('Graph'),
- _('Compare'),
- (_('Locked Files') if Gitlab.ee?)
+ _('Compare revisions'),
+ (_('Locked files') if Gitlab.ee?)
]
},
{
@@ -85,8 +85,7 @@ RSpec.shared_context 'project navbar structure' do
_('Metrics'),
_('Error Tracking'),
_('Alerts'),
- _('Incidents'),
- _('Airflow')
+ _('Incidents')
]
},
{
@@ -141,6 +140,7 @@ RSpec.shared_context 'group navbar structure' do
_('CI/CD'),
_('Applications'),
_('Packages and registries'),
+ s_('UsageQuota|Usage Quotas'),
_('Domain Verification')
]
}
@@ -155,18 +155,9 @@ RSpec.shared_context 'group navbar structure' do
}
end
- let(:administration_nav_item) do
- {
- nav_item: _('Administration'),
- nav_sub_items: [
- s_('UsageQuota|Usage Quotas')
- ]
- }
- end
-
let(:security_and_compliance_nav_item) do
{
- nav_item: _('Security & Compliance'),
+ nav_item: _('Security and Compliance'),
nav_sub_items: [
_('Audit events')
]
@@ -268,3 +259,30 @@ RSpec.shared_context 'dashboard navbar structure' do
]
end
end
+
+RSpec.shared_context '"Explore" navbar structure' do
+ let(:structure) do
+ [
+ {
+ nav_item: "Explore",
+ nav_sub_items: []
+ },
+ {
+ nav_item: _("Projects"),
+ nav_sub_items: []
+ },
+ {
+ nav_item: _("Groups"),
+ nav_sub_items: []
+ },
+ {
+ nav_item: _("Topics"),
+ nav_sub_items: []
+ },
+ {
+ nav_item: _("Snippets"),
+ nav_sub_items: []
+ }
+ ]
+ end
+end
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 4c081c8464e..a9b12d47393 100644
--- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
@@ -42,9 +42,7 @@ RSpec.shared_context 'GroupPolicy context' do
let(:developer_permissions) do
%i[
- create_metrics_dashboard_annotation
- delete_metrics_dashboard_annotation
- update_metrics_dashboard_annotation
+ admin_metrics_dashboard_annotation
create_custom_emoji
create_package
read_cluster
@@ -59,6 +57,7 @@ RSpec.shared_context 'GroupPolicy context' do
create_cluster update_cluster admin_cluster add_cluster
destroy_upload
admin_achievement
+ award_achievement
]
end
diff --git a/spec/support/shared_contexts/policies/project_policy_shared_context.rb b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
index afc7fc8766f..5014a810f35 100644
--- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
@@ -38,8 +38,8 @@ RSpec.shared_context 'ProjectPolicy context' do
read_commit_status read_confidential_issues read_container_image
read_harbor_registry read_deployment read_environment read_merge_request
read_metrics_dashboard_annotation read_pipeline read_prometheus
- read_sentry_issue update_issue create_merge_request_in read_external_emails
- read_internal_note
+ read_sentry_issue update_issue create_merge_request_in
+ read_external_emails read_internal_note export_work_items
]
end
@@ -52,12 +52,11 @@ RSpec.shared_context 'ProjectPolicy context' do
admin_merge_request admin_tag create_build
create_commit_status create_container_image create_deployment
create_environment create_merge_request_from
- create_metrics_dashboard_annotation create_pipeline create_release
- create_wiki delete_metrics_dashboard_annotation
- destroy_container_image push_code read_pod_logs read_terraform_state
- resolve_note update_build update_commit_status update_container_image
- update_deployment update_environment update_merge_request
- update_metrics_dashboard_annotation update_pipeline update_release destroy_release
+ admin_metrics_dashboard_annotation create_pipeline create_release
+ create_wiki destroy_container_image push_code read_pod_logs
+ read_terraform_state resolve_note update_build update_commit_status
+ update_container_image update_deployment update_environment
+ update_merge_request update_pipeline update_release destroy_release
read_resource_group update_resource_group update_escalation_status
]
end
diff --git a/spec/support/shared_contexts/rack_attack_shared_context.rb b/spec/support/shared_contexts/rack_attack_shared_context.rb
index 12625ead72b..4e8c6e9dec6 100644
--- a/spec/support/shared_contexts/rack_attack_shared_context.rb
+++ b/spec/support/shared_contexts/rack_attack_shared_context.rb
@@ -5,8 +5,7 @@ RSpec.shared_context 'rack attack cache store' do
# Instead of test environment's :null_store so the throttles can increment
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
- # Make time-dependent tests deterministic
- freeze_time { example.run }
+ example.run
Rack::Attack.cache.store = Rails.cache
end
diff --git a/spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb b/spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb
index 57967fb9414..ad64e4d5be5 100644
--- a/spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb
+++ b/spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb
@@ -58,6 +58,9 @@ RSpec.shared_context 'Debian repository shared context' do |container_type, can_
let(:distribution) { { private: private_distribution, public: public_distribution }[visibility_level] }
let(:architecture) { { private: private_architecture, public: public_architecture }[visibility_level] }
let(:component) { { private: private_component, public: public_component }[visibility_level] }
+ let(:component_file) { { private: private_component_file, public: public_component_file }[visibility_level] }
+ let(:component_file_sources) { { private: private_component_file_sources, public: public_component_file_sources }[visibility_level] }
+ let(:component_file_di) { { private: private_component_file_di, public: public_component_file_di }[visibility_level] }
let(:component_file_older_sha256) { { private: private_component_file_older_sha256, public: public_component_file_older_sha256 }[visibility_level] }
let(:component_file_sources_older_sha256) { { private: private_component_file_sources_older_sha256, public: public_component_file_sources_older_sha256 }[visibility_level] }
let(:component_file_di_older_sha256) { { private: private_component_file_di_older_sha256, public: public_component_file_di_older_sha256 }[visibility_level] }
diff --git a/spec/support/shared_contexts/security_and_compliance_permissions_shared_context.rb b/spec/support/shared_contexts/security_and_compliance_permissions_shared_context.rb
index dc5195e4b01..1fa1a5c69f4 100644
--- a/spec/support/shared_contexts/security_and_compliance_permissions_shared_context.rb
+++ b/spec/support/shared_contexts/security_and_compliance_permissions_shared_context.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_context '"Security & Compliance" permissions' do
+RSpec.shared_context '"Security and Compliance" permissions' do
let(:project_instance) { an_instance_of(Project) }
let(:user_instance) { an_instance_of(User) }
let(:before_request_defined) { false }
@@ -18,7 +18,7 @@ RSpec.shared_context '"Security & Compliance" permissions' do
allow(Ability).to receive(:allowed?).with(user_instance, :access_security_and_compliance, project_instance).and_return(true)
end
- context 'when the "Security & Compliance" feature is disabled' do
+ context 'when the "Security and Compliance" feature is disabled' do
subject { response }
before do
diff --git a/spec/support/shared_examples/analytics/cycle_analytics/flow_metrics_examples.rb b/spec/support/shared_examples/analytics/cycle_analytics/flow_metrics_examples.rb
new file mode 100644
index 00000000000..b324a5886a9
--- /dev/null
+++ b/spec/support/shared_examples/analytics/cycle_analytics/flow_metrics_examples.rb
@@ -0,0 +1,464 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'value stream analytics flow metrics issueCount examples' do
+ let_it_be(:milestone) { create(:milestone, group: group) }
+ let_it_be(:label) { create(:group_label, group: group) }
+
+ let_it_be(:author) { create(:user) }
+ let_it_be(:assignee) { create(:user) }
+
+ let_it_be(:issue1) { create(:issue, project: project1, author: author, created_at: 12.days.ago) }
+ let_it_be(:issue2) { create(:issue, project: project2, author: author, created_at: 13.days.ago) }
+
+ let_it_be(:issue3) do
+ create(:labeled_issue,
+ project: project1,
+ labels: [label],
+ author: author,
+ milestone: milestone,
+ assignees: [assignee],
+ created_at: 14.days.ago)
+ end
+
+ let_it_be(:issue4) do
+ create(:labeled_issue,
+ project: project2,
+ labels: [label],
+ assignees: [assignee],
+ created_at: 15.days.ago)
+ end
+
+ let_it_be(:issue_outside_of_the_range) { create(:issue, project: project2, author: author, created_at: 50.days.ago) }
+
+ let(:query) do
+ <<~QUERY
+ query($path: ID!, $assigneeUsernames: [String!], $authorUsername: String, $milestoneTitle: String, $labelNames: [String!], $from: Time!, $to: Time!) {
+ #{context}(fullPath: $path) {
+ flowMetrics {
+ issueCount(assigneeUsernames: $assigneeUsernames, authorUsername: $authorUsername, milestoneTitle: $milestoneTitle, labelNames: $labelNames, from: $from, to: $to) {
+ value
+ unit
+ identifier
+ title
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ let(:variables) do
+ {
+ path: full_path,
+ from: 20.days.ago.iso8601,
+ to: 10.days.ago.iso8601
+ }
+ end
+
+ subject(:result) do
+ post_graphql(query, current_user: current_user, variables: variables)
+
+ graphql_data.dig(context.to_s, 'flowMetrics', 'issueCount')
+ end
+
+ it 'returns the correct count' do
+ expect(result).to eq({
+ 'identifier' => 'issues',
+ 'unit' => nil,
+ 'value' => 4,
+ 'title' => n_('New Issue', 'New Issues', 4)
+ })
+ end
+
+ context 'with partial filters' do
+ let(:variables) do
+ {
+ path: full_path,
+ assigneeUsernames: [assignee.username],
+ labelNames: [label.title],
+ from: 20.days.ago.iso8601,
+ to: 10.days.ago.iso8601
+ }
+ end
+
+ it 'returns filtered count' do
+ expect(result).to eq({
+ 'identifier' => 'issues',
+ 'unit' => nil,
+ 'value' => 2,
+ 'title' => n_('New Issue', 'New Issues', 2)
+ })
+ end
+ end
+
+ context 'with all filters' do
+ let(:variables) do
+ {
+ path: full_path,
+ assigneeUsernames: [assignee.username],
+ labelNames: [label.title],
+ authorUsername: author.username,
+ milestoneTitle: milestone.title,
+ from: 20.days.ago.iso8601,
+ to: 10.days.ago.iso8601
+ }
+ end
+
+ it 'returns filtered count' do
+ expect(result).to eq({
+ 'identifier' => 'issues',
+ 'unit' => nil,
+ 'value' => 1,
+ 'title' => n_('New Issue', 'New Issues', 1)
+ })
+ end
+ end
+
+ context 'when the user is not authorized' do
+ let(:current_user) { create(:user) }
+
+ it 'returns nil' do
+ expect(result).to eq(nil)
+ end
+ end
+end
+
+RSpec.shared_examples 'value stream analytics flow metrics deploymentCount examples' do
+ let_it_be(:deployment1) do
+ create(:deployment, :success, environment: production_environment1, finished_at: 5.days.ago)
+ end
+
+ let_it_be(:deployment2) do
+ create(:deployment, :success, environment: production_environment2, finished_at: 10.days.ago)
+ end
+
+ let_it_be(:deployment3) do
+ create(:deployment, :success, environment: production_environment2, finished_at: 15.days.ago)
+ end
+
+ let(:variables) do
+ {
+ path: full_path,
+ from: 12.days.ago.iso8601,
+ to: 3.days.ago.iso8601
+ }
+ end
+
+ let(:query) do
+ <<~QUERY
+ query($path: ID!, $from: Time!, $to: Time!) {
+ #{context}(fullPath: $path) {
+ flowMetrics {
+ deploymentCount(from: $from, to: $to) {
+ value
+ unit
+ identifier
+ title
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ subject(:result) do
+ post_graphql(query, current_user: current_user, variables: variables)
+
+ graphql_data.dig(context.to_s, 'flowMetrics', 'deploymentCount')
+ end
+
+ it 'returns the correct count' do
+ expect(result).to eq({
+ 'identifier' => 'deploys',
+ 'unit' => nil,
+ 'value' => 2,
+ 'title' => n_('Deploy', 'Deploys', 2)
+ })
+ end
+
+ context 'when the user is not authorized' do
+ let(:current_user) { create(:user) }
+
+ it 'returns nil' do
+ expect(result).to eq(nil)
+ end
+ end
+
+ context 'when outside of the date range' do
+ let(:variables) do
+ {
+ path: full_path,
+ from: 20.days.ago.iso8601,
+ to: 18.days.ago.iso8601
+ }
+ end
+
+ it 'returns 0 count' do
+ expect(result).to eq({
+ 'identifier' => 'deploys',
+ 'unit' => nil,
+ 'value' => 0,
+ 'title' => n_('Deploy', 'Deploys', 0)
+ })
+ end
+ end
+end
+
+RSpec.shared_examples 'value stream analytics flow metrics leadTime examples' do
+ let_it_be(:milestone) { create(:milestone, group: group) }
+ let_it_be(:label) { create(:group_label, group: group) }
+
+ let_it_be(:author) { create(:user) }
+ let_it_be(:assignee) { create(:user) }
+
+ let_it_be(:issue1) do
+ create(:issue, project: project1, author: author, created_at: 17.days.ago, closed_at: 12.days.ago)
+ end
+
+ let_it_be(:issue2) do
+ create(:issue, project: project2, author: author, created_at: 16.days.ago, closed_at: 13.days.ago)
+ end
+
+ let_it_be(:issue3) do
+ create(:labeled_issue,
+ project: project1,
+ labels: [label],
+ author: author,
+ milestone: milestone,
+ assignees: [assignee],
+ created_at: 14.days.ago,
+ closed_at: 11.days.ago)
+ end
+
+ let_it_be(:issue4) do
+ create(:labeled_issue,
+ project: project2,
+ labels: [label],
+ assignees: [assignee],
+ created_at: 20.days.ago,
+ closed_at: 15.days.ago)
+ end
+
+ before do
+ Analytics::CycleAnalytics::DataLoaderService.new(group: group, model: Issue).execute
+ end
+
+ let(:query) do
+ <<~QUERY
+ query($path: ID!, $assigneeUsernames: [String!], $authorUsername: String, $milestoneTitle: String, $labelNames: [String!], $from: Time!, $to: Time!) {
+ #{context}(fullPath: $path) {
+ flowMetrics {
+ leadTime(assigneeUsernames: $assigneeUsernames, authorUsername: $authorUsername, milestoneTitle: $milestoneTitle, labelNames: $labelNames, from: $from, to: $to) {
+ value
+ unit
+ identifier
+ title
+ links {
+ label
+ url
+ }
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ let(:variables) do
+ {
+ path: full_path,
+ from: 21.days.ago.iso8601,
+ to: 10.days.ago.iso8601
+ }
+ end
+
+ subject(:result) do
+ post_graphql(query, current_user: current_user, variables: variables)
+
+ graphql_data.dig(context.to_s, 'flowMetrics', 'leadTime')
+ end
+
+ it 'returns the correct value' do
+ expect(result).to match(a_hash_including({
+ 'identifier' => 'lead_time',
+ 'unit' => n_('day', 'days', 4),
+ 'value' => 4,
+ 'title' => _('Lead Time'),
+ 'links' => [
+ { 'label' => s_('ValueStreamAnalytics|Dashboard'), 'url' => match(/issues_analytics/) },
+ { 'label' => s_('ValueStreamAnalytics|Go to docs'), 'url' => match(/definitions/) }
+ ]
+ }))
+ end
+
+ context 'when the user is not authorized' do
+ let(:current_user) { create(:user) }
+
+ it 'returns nil' do
+ expect(result).to eq(nil)
+ end
+ end
+
+ context 'when outside of the date range' do
+ let(:variables) do
+ {
+ path: full_path,
+ from: 30.days.ago.iso8601,
+ to: 25.days.ago.iso8601
+ }
+ end
+
+ it 'returns 0 count' do
+ expect(result).to match(a_hash_including({ 'value' => nil }))
+ end
+ end
+
+ context 'with all filters' do
+ let(:variables) do
+ {
+ path: full_path,
+ assigneeUsernames: [assignee.username],
+ labelNames: [label.title],
+ authorUsername: author.username,
+ milestoneTitle: milestone.title,
+ from: 20.days.ago.iso8601,
+ to: 10.days.ago.iso8601
+ }
+ end
+
+ it 'returns filtered count' do
+ expect(result).to match(a_hash_including({ 'value' => 3 }))
+ end
+ end
+end
+
+RSpec.shared_examples 'value stream analytics flow metrics cycleTime examples' do
+ let_it_be(:milestone) { create(:milestone, group: group) }
+ let_it_be(:label) { create(:group_label, group: group) }
+
+ let_it_be(:author) { create(:user) }
+ let_it_be(:assignee) { create(:user) }
+
+ let_it_be(:issue1) do
+ create(:issue, project: project1, author: author, closed_at: 12.days.ago).tap do |issue|
+ issue.metrics.update!(first_mentioned_in_commit_at: 17.days.ago)
+ end
+ end
+
+ let_it_be(:issue2) do
+ create(:issue, project: project2, author: author, closed_at: 13.days.ago).tap do |issue|
+ issue.metrics.update!(first_mentioned_in_commit_at: 16.days.ago)
+ end
+ end
+
+ let_it_be(:issue3) do
+ create(:labeled_issue,
+ project: project1,
+ labels: [label],
+ author: author,
+ milestone: milestone,
+ assignees: [assignee],
+ closed_at: 11.days.ago).tap do |issue|
+ issue.metrics.update!(first_mentioned_in_commit_at: 14.days.ago)
+ end
+ end
+
+ let_it_be(:issue4) do
+ create(:labeled_issue,
+ project: project2,
+ labels: [label],
+ assignees: [assignee],
+ closed_at: 15.days.ago).tap do |issue|
+ issue.metrics.update!(first_mentioned_in_commit_at: 20.days.ago)
+ end
+ end
+
+ before do
+ Analytics::CycleAnalytics::DataLoaderService.new(group: group, model: Issue).execute
+ end
+
+ let(:query) do
+ <<~QUERY
+ query($path: ID!, $assigneeUsernames: [String!], $authorUsername: String, $milestoneTitle: String, $labelNames: [String!], $from: Time!, $to: Time!) {
+ #{context}(fullPath: $path) {
+ flowMetrics {
+ cycleTime(assigneeUsernames: $assigneeUsernames, authorUsername: $authorUsername, milestoneTitle: $milestoneTitle, labelNames: $labelNames, from: $from, to: $to) {
+ value
+ unit
+ identifier
+ title
+ links {
+ label
+ url
+ }
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ let(:variables) do
+ {
+ path: full_path,
+ from: 21.days.ago.iso8601,
+ to: 10.days.ago.iso8601
+ }
+ end
+
+ subject(:result) do
+ post_graphql(query, current_user: current_user, variables: variables)
+
+ graphql_data.dig(context.to_s, 'flowMetrics', 'cycleTime')
+ end
+
+ it 'returns the correct value' do
+ expect(result).to eq({
+ 'identifier' => 'cycle_time',
+ 'unit' => n_('day', 'days', 4),
+ 'value' => 4,
+ 'title' => _('Cycle Time'),
+ 'links' => []
+ })
+ end
+
+ context 'when the user is not authorized' do
+ let(:current_user) { create(:user) }
+
+ it 'returns nil' do
+ expect(result).to eq(nil)
+ end
+ end
+
+ context 'when outside of the date range' do
+ let(:variables) do
+ {
+ path: full_path,
+ from: 30.days.ago.iso8601,
+ to: 25.days.ago.iso8601
+ }
+ end
+
+ it 'returns 0 count' do
+ expect(result).to match(a_hash_including({ 'value' => nil }))
+ end
+ end
+
+ context 'with all filters' do
+ let(:variables) do
+ {
+ path: full_path,
+ assigneeUsernames: [assignee.username],
+ labelNames: [label.title],
+ authorUsername: author.username,
+ milestoneTitle: milestone.title,
+ from: 20.days.ago.iso8601,
+ to: 10.days.ago.iso8601
+ }
+ end
+
+ it 'returns filtered count' do
+ expect(result).to match(a_hash_including({ 'value' => 3 }))
+ end
+ end
+end
diff --git a/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb b/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb
new file mode 100644
index 00000000000..f1ffddf6507
--- /dev/null
+++ b/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'unlicensed cycle analytics request params' do
+ let(:params) do
+ {
+ created_after: '2019-01-01',
+ created_before: '2019-03-01',
+ project_ids: [2, 3],
+ namespace: namespace,
+ current_user: user
+ }
+ end
+
+ subject { described_class.new(params) }
+
+ before do
+ root_group.add_owner(user)
+ end
+
+ describe 'validations' do
+ it 'is valid' do
+ expect(subject).to be_valid
+ end
+
+ context 'when `created_before` is missing' do
+ before do
+ params[:created_before] = nil
+ end
+
+ it 'is valid', time_travel_to: '2019-03-01' do
+ expect(subject).to be_valid
+ end
+ end
+
+ context 'when `created_before` is earlier than `created_after`' do
+ before do
+ params[:created_before] = '2015-01-01'
+ end
+
+ it 'is invalid' do
+ expect(subject).not_to be_valid
+ expect(subject.errors.messages[:created_before]).not_to be_empty
+ end
+ end
+
+ context 'when the date range exceeds 180 days' do
+ before do
+ params[:created_before] = '2019-07-15'
+ end
+
+ it 'is invalid' do
+ expect(subject).not_to be_valid
+ message = s_('CycleAnalytics|The given date range is larger than 180 days')
+ expect(subject.errors.messages[:created_after]).to include(message)
+ end
+ end
+ end
+
+ it 'casts `created_after` to `Time`' do
+ expect(subject.created_after).to be_a_kind_of(Time)
+ end
+
+ it 'casts `created_before` to `Time`' do
+ expect(subject.created_before).to be_a_kind_of(Time)
+ end
+
+ describe 'optional `value_stream`' do
+ context 'when `value_stream` is not empty' do
+ let(:value_stream) { instance_double('Analytics::CycleAnalytics::ValueStream') }
+
+ before do
+ params[:value_stream] = value_stream
+ end
+
+ it { expect(subject.value_stream).to eq(value_stream) }
+ end
+
+ context 'when `value_stream` is nil' do
+ before do
+ params[:value_stream] = nil
+ end
+
+ it { expect(subject.value_stream).to eq(nil) }
+ end
+ end
+
+ describe 'sorting params' do
+ before do
+ params.merge!(sort: 'duration', direction: 'asc')
+ end
+
+ it 'converts sorting params to symbol when passing it to data collector' do
+ data_collector_params = subject.to_data_collector_params
+
+ expect(data_collector_params[:sort]).to eq(:duration)
+ expect(data_collector_params[:direction]).to eq(:asc)
+ end
+
+ it 'adds sorting params to data attributes' do
+ data_attributes = subject.to_data_attributes
+
+ expect(data_attributes[:sort]).to eq('duration')
+ expect(data_attributes[:direction]).to eq('asc')
+ end
+ end
+
+ describe 'aggregation params' do
+ context 'when not licensed' do
+ it 'returns nil' do
+ data_collector_params = subject.to_data_attributes
+ expect(data_collector_params[:aggregation]).to eq(nil)
+ end
+ end
+ end
+
+ describe 'use_aggregated_data_collector param' do
+ subject(:value) { described_class.new(params).to_data_collector_params[:use_aggregated_data_collector] }
+
+ it { is_expected.to eq(false) }
+ end
+
+ describe 'enable_tasks_by_type_chart data attribute' do
+ subject(:value) { described_class.new(params).to_data_attributes[:enable_tasks_by_type_chart] }
+
+ it { is_expected.to eq('false') }
+ end
+end
diff --git a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
index 7df4b7635d3..ddd3bbd636a 100644
--- a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
+++ b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
@@ -80,7 +80,7 @@ RSpec.shared_examples 'multiple issue boards' do
click_button 'Select a label'
- page.choose(planning.title)
+ find('label', text: planning.title).click
click_button 'Add to board'
diff --git a/spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb b/spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb
index cc28a79b4ca..e75188f8249 100644
--- a/spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb
@@ -60,19 +60,6 @@ RSpec.shared_examples Repositories::GitHttpController do
expect(response).to have_gitlab_http_status(:ok)
end
- it 'updates the user activity' do
- activity_project = container.is_a?(PersonalSnippet) ? nil : project
-
- activity_service = instance_double(Users::ActivityService)
-
- args = { author: user, project: activity_project, namespace: activity_project&.namespace }
- expect(Users::ActivityService).to receive(:new).with(args).and_return(activity_service)
-
- expect(activity_service).to receive(:execute)
-
- get :info_refs, params: params
- end
-
include_context 'parsed logs' do
it 'adds user info to the logs' do
get :info_refs, params: params
@@ -87,14 +74,20 @@ RSpec.shared_examples Repositories::GitHttpController do
end
describe 'POST #git_upload_pack' do
- before do
+ it 'returns 200' do
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
- end
- it 'returns 200' do
post :git_upload_pack, params: params
expect(response).to have_gitlab_http_status(:ok)
end
+
+ context 'when JWT token is not provided' do
+ it 'returns 403' do
+ post :git_upload_pack, params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ 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 44f30c32472..b6339607d6b 100644
--- a/spec/support/shared_examples/features/2fa_shared_examples.rb
+++ b/spec/support/shared_examples/features/2fa_shared_examples.rb
@@ -6,8 +6,6 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
def register_device(device_type, **kwargs)
case device_type.downcase
- when "u2f"
- register_u2f_device(**kwargs)
when "webauthn"
register_webauthn_device(**kwargs)
else
diff --git a/spec/support/shared_examples/features/abuse_report_shared_examples.rb b/spec/support/shared_examples/features/abuse_report_shared_examples.rb
new file mode 100644
index 00000000000..7a520fb0cd2
--- /dev/null
+++ b/spec/support/shared_examples/features/abuse_report_shared_examples.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'reports the user with an abuse category' do
+ it 'creates abuse report' do
+ click_button 'Report abuse to administrator'
+ choose "They're posting spam."
+ click_button 'Next'
+
+ fill_in 'abuse_report_message', with: 'This user sends spam'
+ click_button 'Send report'
+
+ expect(page).to have_content 'Thank you for your report'
+ end
+end
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 6cd9c4ce1c4..7582e67efbd 100644
--- a/spec/support/shared_examples/features/content_editor_shared_examples.rb
+++ b/spec/support/shared_examples/features/content_editor_shared_examples.rb
@@ -1,44 +1,9 @@
# frozen_string_literal: true
RSpec.shared_examples 'edits content using the content editor' do
- let(:content_editor_testid) { '[data-testid="content-editor"] [contenteditable].ProseMirror' }
-
- def switch_to_content_editor
- click_button _('View rich text')
- click_button _('Rich text')
- end
-
- def type_in_content_editor(keys)
- find(content_editor_testid).send_keys keys
- end
-
- def open_insert_media_dropdown
- page.find('svg[data-testid="media-icon"]').click
- end
-
- def set_source_editor_content(content)
- find('.js-gfm-input').set content
- end
-
- def expect_formatting_menu_to_be_visible
- expect(page).to have_css('[data-testid="formatting-bubble-menu"]')
- end
-
- def expect_formatting_menu_to_be_hidden
- expect(page).not_to have_css('[data-testid="formatting-bubble-menu"]')
- end
-
- def expect_media_bubble_menu_to_be_visible
- expect(page).to have_css('[data-testid="media-bubble-menu"]')
- end
+ include ContentEditorHelpers
- def upload_asset(fixture_name)
- attach_file('content_editor_image', Rails.root.join('spec', 'fixtures', fixture_name), make_visible: true)
- end
-
- def wait_until_hidden_field_is_updated(value)
- expect(page).to have_field('wiki[content]', with: value, type: 'hidden')
- end
+ let(:content_editor_testid) { '[data-testid="content-editor"] [contenteditable].ProseMirror' }
it 'saves page content in local storage if the user navigates away' do
switch_to_content_editor
@@ -52,16 +17,6 @@ RSpec.shared_examples 'edits content using the content editor' do
refresh
expect(page).to have_text('Typing text in the content editor')
-
- refresh # also retained after second refresh
-
- expect(page).to have_text('Typing text in the content editor')
-
- click_link 'Cancel' # draft is deleted on cancel
-
- page.go_back
-
- expect(page).not_to have_text('Typing text in the content editor')
end
describe 'formatting bubble menu' do
@@ -92,25 +47,18 @@ RSpec.shared_examples 'edits content using the content editor' do
open_insert_media_dropdown
end
- def test_displays_media_bubble_menu(media_element_selector, fixture_file)
- upload_asset fixture_file
-
- wait_for_requests
-
- expect(page).to have_css(media_element_selector)
-
- page.find(media_element_selector).click
+ it 'displays correct media bubble menu for images', :js do
+ display_media_bubble_menu '[data-testid="content_editor_editablebox"] img[src]', 'dk.png'
expect_formatting_menu_to_be_hidden
expect_media_bubble_menu_to_be_visible
end
- it 'displays correct media bubble menu for images', :js do
- test_displays_media_bubble_menu '[data-testid="content_editor_editablebox"] img[src]', 'dk.png'
- end
-
it 'displays correct media bubble menu for video', :js do
- test_displays_media_bubble_menu '[data-testid="content_editor_editablebox"] video', 'video_sample.mp4'
+ display_media_bubble_menu '[data-testid="content_editor_editablebox"] video', 'video_sample.mp4'
+
+ expect_formatting_menu_to_be_hidden
+ expect_media_bubble_menu_to_be_visible
end
end
@@ -225,7 +173,7 @@ RSpec.shared_examples 'edits content using the content editor' do
before do
if defined?(project)
create(:issue, project: project, title: 'My Cool Linked Issue')
- create(:merge_request, source_project: project, title: 'My Cool Merge Request')
+ create(:merge_request, source_project: project, source_branch: 'branch-1', title: 'My Cool Merge Request')
create(:label, project: project, title: 'My Cool Label')
create(:milestone, project: project, title: 'My Cool Milestone')
@@ -234,7 +182,7 @@ RSpec.shared_examples 'edits content using the content editor' do
project = create(:project, group: group)
create(:issue, project: project, title: 'My Cool Linked Issue')
- create(:merge_request, source_project: project, title: 'My Cool Merge Request')
+ create(:merge_request, source_project: project, source_branch: 'branch-1', title: 'My Cool Merge Request')
create(:group_label, group: group, title: 'My Cool Label')
create(:milestone, group: group, title: 'My Cool Milestone')
@@ -251,7 +199,9 @@ RSpec.shared_examples 'edits content using the content editor' do
expect(find(suggestions_dropdown)).to have_text('abc123')
expect(find(suggestions_dropdown)).to have_text('all')
- expect(find(suggestions_dropdown)).to have_text('Group Members (2)')
+ expect(find(suggestions_dropdown)).to have_text('Group Members')
+
+ type_in_content_editor 'bc'
send_keys [:arrow_down, :enter]
@@ -332,3 +282,24 @@ RSpec.shared_examples 'edits content using the content editor' do
end
end
end
+
+RSpec.shared_examples 'inserts diagrams.net diagram using the content editor' do
+ include ContentEditorHelpers
+
+ before do
+ switch_to_content_editor
+
+ open_insert_media_dropdown
+ end
+
+ it 'displays correct media bubble menu with edit diagram button' do
+ display_media_bubble_menu '[data-testid="content_editor_editablebox"] img[src]', 'diagram.drawio.svg'
+
+ expect_formatting_menu_to_be_hidden
+ expect_media_bubble_menu_to_be_visible
+
+ click_edit_diagram_button
+
+ expect_drawio_editor_is_opened
+ end
+end
diff --git a/spec/support/shared_examples/features/incident_details_routing_shared_examples.rb b/spec/support/shared_examples/features/incident_details_routing_shared_examples.rb
index dab125caa60..b8e42843e6f 100644
--- a/spec/support/shared_examples/features/incident_details_routing_shared_examples.rb
+++ b/spec/support/shared_examples/features/incident_details_routing_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'for each incident details route' do |example, tab_text:|
+RSpec.shared_examples 'for each incident details route' do |example, tab_text:, tab:|
before do
sign_in(user)
visit incident_path
@@ -25,4 +25,16 @@ RSpec.shared_examples 'for each incident details route' do |example, tab_text:|
it_behaves_like example
end
+
+ context "for /-/issues/incident/:id/#{tab} route" do
+ let(:incident_path) { incident_project_issues_path(project, incident, tab) }
+
+ it_behaves_like example
+ end
+
+ context "for /-/issues/:id/#{tab} route" do
+ let(:incident_path) { incident_issue_project_issue_path(project, incident, tab) }
+
+ it_behaves_like example
+ end
end
diff --git a/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb b/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb
index 4c312b42c0a..148ff2cfb54 100644
--- a/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb
+++ b/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb
@@ -8,7 +8,7 @@ RSpec.shared_examples 'user activates the Mattermost Slash Command integration'
it 'shows a token placeholder' do
token_placeholder = find_field('service_token')['placeholder']
- expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx')
+ expect(token_placeholder).to eq('')
end
it 'redirects to the integrations page after saving but not activating' do
diff --git a/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb b/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb
index b6f7094e422..13adcfe9191 100644
--- a/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb
+++ b/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb
@@ -17,8 +17,6 @@ RSpec.shared_examples 'issuable invite members' do
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite Members')
- expect(page).to have_selector('[data-track-action="click_invite_members"]')
- expect(page).to have_selector('[data-track-label="edit_assignee"]')
end
click_link 'Invite Members'
diff --git a/spec/support/shared_examples/features/manage_applications_shared_examples.rb b/spec/support/shared_examples/features/manage_applications_shared_examples.rb
index b59f3f1e27b..63ba5832771 100644
--- a/spec/support/shared_examples/features/manage_applications_shared_examples.rb
+++ b/spec/support/shared_examples/features/manage_applications_shared_examples.rb
@@ -5,87 +5,40 @@ RSpec.shared_examples 'manage applications' do
let_it_be(:application_name_changed) { "#{application_name} changed" }
let_it_be(:application_redirect_uri) { 'https://foo.bar' }
- context 'when hash_oauth_secrets flag set' do
- before do
- stub_feature_flags(hash_oauth_secrets: true)
- end
-
- it 'allows user to manage applications', :js do
- visit new_application_path
+ it 'allows user to manage applications', :js do
+ visit new_application_path
- expect(page).to have_content 'Add new application'
+ expect(page).to have_content 'Add new application'
- fill_in :doorkeeper_application_name, with: application_name
- fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri
- check :doorkeeper_application_scopes_read_user
- click_on 'Save application'
+ fill_in :doorkeeper_application_name, with: application_name
+ fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri
+ check :doorkeeper_application_scopes_read_user
+ click_on 'Save application'
- validate_application(application_name, 'Yes')
- expect(page).to have_content _('This is the only time the secret is accessible. Copy the secret and store it securely')
- expect(page).to have_link('Continue', href: index_path)
+ validate_application(application_name, 'Yes')
+ expect(page).to have_content _('This is the only time the secret is accessible. Copy the secret and store it securely')
+ expect(page).to have_link('Continue', href: index_path)
- expect(page).to have_css("button[title=\"Copy secret\"]", text: 'Copy')
+ expect(page).to have_css("button[title=\"Copy secret\"]", text: 'Copy')
- click_on 'Edit'
+ click_on 'Edit'
- application_name_changed = "#{application_name} changed"
+ application_name_changed = "#{application_name} changed"
- fill_in :doorkeeper_application_name, with: application_name_changed
- uncheck :doorkeeper_application_confidential
- click_on 'Save application'
-
- validate_application(application_name_changed, 'No')
- expect(page).not_to have_link('Continue')
- expect(page).to have_content _('The secret is only available when you first create the application')
-
- visit_applications_path
-
- page.within '.oauth-applications' do
- click_on 'Destroy'
- end
- expect(page.find('.oauth-applications')).not_to have_content 'test_changed'
- end
- end
-
- context 'when hash_oauth_secrets flag not set' do
- before do
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'allows user to manage applications', :js do
- visit new_application_path
-
- expect(page).to have_content 'Add new application'
-
- fill_in :doorkeeper_application_name, with: application_name
- fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri
- check :doorkeeper_application_scopes_read_user
- click_on 'Save application'
-
- validate_application(application_name, 'Yes')
- expect(page).to have_link('Continue', href: index_path)
-
- application = Doorkeeper::Application.find_by(name: application_name)
- expect(page).to have_css("button[title=\"Copy secret\"][data-clipboard-text=\"#{application.secret}\"]", text: 'Copy')
-
- click_on 'Edit'
-
- application_name_changed = "#{application_name} changed"
-
- fill_in :doorkeeper_application_name, with: application_name_changed
- uncheck :doorkeeper_application_confidential
- click_on 'Save application'
+ fill_in :doorkeeper_application_name, with: application_name_changed
+ uncheck :doorkeeper_application_confidential
+ click_on 'Save application'
- validate_application(application_name_changed, 'No')
- expect(page).not_to have_link('Continue')
+ validate_application(application_name_changed, 'No')
+ expect(page).not_to have_link('Continue')
+ expect(page).to have_content _('The secret is only available when you create the application or renew the secret.')
- visit_applications_path
+ visit_applications_path
- page.within '.oauth-applications' do
- click_on 'Destroy'
- end
- expect(page.find('.oauth-applications')).not_to have_content 'test_changed'
+ page.within '.oauth-applications' do
+ click_on 'Destroy'
end
+ expect(page.find('.oauth-applications')).not_to have_content 'test_changed'
end
context 'when scopes are blank' do
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
new file mode 100644
index 00000000000..cc0984b6226
--- /dev/null
+++ b/spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'Deploy keys with protected tags' do
+ let(:dropdown_sections_minus_deploy_keys) { all_dropdown_sections - ['Deploy Keys'] }
+
+ context 'when deploy keys are enabled to this project' do
+ let!(:deploy_key_1) { create(:deploy_key, title: 'title 1', projects: [project]) }
+ let!(:deploy_key_2) { create(:deploy_key, title: 'title 2', projects: [project]) }
+
+ context 'when only one deploy key can push' do
+ before do
+ deploy_key_1.deploy_keys_projects.first.update!(can_push: true)
+ end
+
+ it "shows all dropdown sections in the 'Allowed to create' main dropdown, with only one deploy key" do
+ visit project_protected_tags_path(project)
+
+ find(".js-allowed-to-create").click
+ wait_for_requests
+
+ within('[data-testid="allowed-to-create-dropdown"]') do
+ dropdown_headers = page.all('.dropdown-header').map(&:text)
+
+ expect(dropdown_headers).to contain_exactly(*all_dropdown_sections)
+ expect(page).to have_content('title 1')
+ expect(page).not_to have_content('title 2')
+ end
+ end
+
+ it "shows all sections in the 'Allowed to create' update dropdown" do
+ create(:protected_tag, :no_one_can_create, project: project, name: 'v1.0.0')
+
+ visit project_protected_tags_path(project)
+
+ within(".js-protected-tag-edit-form") do
+ find(".js-allowed-to-create").click
+ wait_for_requests
+
+ dropdown_headers = page.all('.dropdown-header').map(&:text)
+
+ expect(dropdown_headers).to contain_exactly(*all_dropdown_sections)
+ end
+ end
+ end
+
+ context 'when no deploy key can push' do
+ it "just shows all sections but not deploy keys in the 'Allowed to create' dropdown" do
+ visit project_protected_tags_path(project)
+
+ find(".js-allowed-to-create").click
+ wait_for_requests
+
+ within('[data-testid="allowed-to-create-dropdown"]') do
+ dropdown_headers = page.all('.dropdown-header').map(&:text)
+
+ expect(dropdown_headers).to contain_exactly(*dropdown_sections_minus_deploy_keys)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb b/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb
index 028e075c87a..231406289b4 100644
--- a/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb
+++ b/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb
@@ -10,7 +10,7 @@ RSpec.shared_examples 'Secure OAuth Authorizations' do
end
context 'when user is unconfirmed' do
- let(:user) { create(:user, confirmed_at: nil) }
+ let(:user) { create(:user, :unconfirmed) }
it 'displays an error' do
expect(page).to have_text I18n.t('doorkeeper.errors.messages.unconfirmed_email')
diff --git a/spec/support/shared_examples/features/trial_email_validation_shared_example.rb b/spec/support/shared_examples/features/trial_email_validation_shared_example.rb
index 8304a91af86..81c9ac1164b 100644
--- a/spec/support/shared_examples/features/trial_email_validation_shared_example.rb
+++ b/spec/support/shared_examples/features/trial_email_validation_shared_example.rb
@@ -1,59 +1,38 @@
# frozen_string_literal: true
RSpec.shared_examples 'user email validation' do
- let(:email_hint_message) { 'We recommend a work email address.' }
- let(:email_error_message) { 'Please provide a valid email address.' }
+ let(:email_hint_message) { _('We recommend a work email address.') }
+ let(:email_error_message) { _('Please provide a valid email address.') }
let(:email_warning_message) do
- 'This email address does not look right, are you sure you typed it correctly?'
+ _('This email address does not look right, are you sure you typed it correctly?')
end
- context 'with trial_email_validation flag enabled' do
- it 'shows an error message until a correct email is entered' do
- visit path
- expect(page).to have_content(email_hint_message)
- expect(page).not_to have_content(email_error_message)
- expect(page).not_to have_content(email_warning_message)
+ it 'shows an error message until a correct email is entered' do
+ visit path
+ expect(page).to have_content(email_hint_message)
+ expect(page).not_to have_content(email_error_message)
+ expect(page).not_to have_content(email_warning_message)
- fill_in 'new_user_email', with: 'foo@'
- fill_in 'new_user_first_name', with: ''
+ fill_in 'new_user_email', with: 'foo@'
+ fill_in 'new_user_first_name', with: ''
- expect(page).not_to have_content(email_hint_message)
- expect(page).to have_content(email_error_message)
- expect(page).not_to have_content(email_warning_message)
+ expect(page).not_to have_content(email_hint_message)
+ expect(page).to have_content(email_error_message)
+ expect(page).not_to have_content(email_warning_message)
- fill_in 'new_user_email', with: 'foo@bar'
- fill_in 'new_user_first_name', with: ''
+ fill_in 'new_user_email', with: 'foo@bar'
+ fill_in 'new_user_first_name', with: ''
- expect(page).not_to have_content(email_hint_message)
- expect(page).not_to have_content(email_error_message)
- expect(page).to have_content(email_warning_message)
+ expect(page).not_to have_content(email_hint_message)
+ expect(page).not_to have_content(email_error_message)
+ expect(page).to have_content(email_warning_message)
- fill_in 'new_user_email', with: 'foo@gitlab.com'
- fill_in 'new_user_first_name', with: ''
+ fill_in 'new_user_email', with: 'foo@gitlab.com'
+ fill_in 'new_user_first_name', with: ''
- expect(page).not_to have_content(email_hint_message)
- expect(page).not_to have_content(email_error_message)
- expect(page).not_to have_content(email_warning_message)
- end
- end
-
- context 'when trial_email_validation flag disabled' do
- before do
- stub_feature_flags trial_email_validation: false
- end
-
- it 'does not show an error message' do
- visit path
- expect(page).to have_content(email_hint_message)
- expect(page).not_to have_content(email_error_message)
- expect(page).not_to have_content(email_warning_message)
-
- fill_in 'new_user_email', with: 'foo@'
-
- expect(page).to have_content(email_hint_message)
- expect(page).not_to have_content(email_error_message)
- expect(page).not_to have_content(email_warning_message)
- end
+ expect(page).not_to have_content(email_hint_message)
+ expect(page).not_to have_content(email_error_message)
+ expect(page).not_to have_content(email_warning_message)
end
end
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
new file mode 100644
index 00000000000..0b0c9edcb42
--- /dev/null
+++ b/spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'variable list pagination' do |variable_type|
+ first_page_count = 20
+
+ before do
+ first_page_count.times do |i|
+ case variable_type
+ when :ci_variable
+ create(variable_type, key: "test_key_#{i}", value: 'test_value', masked: true, project: project)
+ when :ci_group_variable
+ create(variable_type, key: "test_key_#{i}", value: 'test_value', masked: true, group: group)
+ else
+ create(variable_type, key: "test_key_#{i}", value: 'test_value', masked: true)
+ end
+ end
+
+ visit page_path
+ wait_for_requests
+ end
+
+ it 'can navigate between pages' do
+ page.within('[data-testid="ci-variable-table"]') do
+ expect(page.all('.js-ci-variable-row').length).to be(first_page_count)
+ end
+
+ click_button 'Next'
+ wait_for_requests
+
+ page.within('[data-testid="ci-variable-table"]') do
+ expect(page.all('.js-ci-variable-row').length).to be(1)
+ end
+
+ click_button 'Previous'
+ wait_for_requests
+
+ page.within('[data-testid="ci-variable-table"]') do
+ expect(page.all('.js-ci-variable-row').length).to be(first_page_count)
+ end
+ end
+
+ 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')
+ 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')
+ end
+
+ page.within('[data-testid="ci-variable-table"]') do
+ find('.b-table-sort-icon-left').click
+ end
+
+ 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')
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
index 0334187e4b1..c1e4185e058 100644
--- a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
@@ -150,6 +150,7 @@ RSpec.shared_examples 'User updates wiki page' do
end
it_behaves_like 'edits content using the content editor'
+ it_behaves_like 'inserts diagrams.net diagram using the content editor'
it_behaves_like 'autocompletes items'
end
diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb
index 639eb3f2b99..b3378c76658 100644
--- a/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb
@@ -84,6 +84,30 @@ RSpec.shared_examples 'User views wiki sidebar' do
expect(page).not_to have_link('View All Pages')
end
+ it 'shows all collapse buttons in the sidebar' do
+ visit wiki_path(wiki)
+
+ within('.right-sidebar') do
+ expect(page.all("[data-testid='chevron-down-icon']").size).to eq(3)
+ end
+ end
+
+ it 'collapses/expands children when click collapse/expand button in the sidebar', :js do
+ visit wiki_path(wiki)
+
+ within('.right-sidebar') do
+ first("[data-testid='chevron-down-icon']").click
+ (11..15).each { |i| expect(page).not_to have_content("my page #{i}") }
+ expect(page.all("[data-testid='chevron-down-icon']").size).to eq(1)
+ expect(page.all("[data-testid='chevron-right-icon']").size).to eq(1)
+
+ first("[data-testid='chevron-right-icon']").click
+ (11..15).each { |i| expect(page).to have_content("my page #{i}") }
+ expect(page.all("[data-testid='chevron-down-icon']").size).to eq(3)
+ expect(page.all("[data-testid='chevron-right-icon']").size).to eq(0)
+ end
+ end
+
context 'when there are more than 15 existing pages' do
before do
create(:wiki_page, wiki: wiki, title: 'my page 16')
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 4f3d957ad71..0b8bfc4d2a2 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -1,5 +1,20 @@
# frozen_string_literal: true
+RSpec.shared_examples 'work items title' do
+ let(:title_selector) { '[data-testid="work-item-title"]' }
+
+ it 'successfully shows and changes the title of the work item' do
+ expect(work_item.reload.title).to eq work_item.title
+
+ find(title_selector).set("Work item title")
+ find(title_selector).native.send_keys(:return)
+
+ wait_for_requests
+
+ expect(work_item.reload.title).to eq 'Work item title'
+ end
+end
+
RSpec.shared_examples 'work items status' do
let(:state_selector) { '[data-testid="work-item-state-select"]' }
@@ -19,7 +34,7 @@ RSpec.shared_examples 'work items comments' do
let(:form_selector) { '[data-testid="work-item-add-comment"]' }
it 'successfully creates and shows comments' do
- click_button 'Add a comment'
+ click_button 'Add a reply'
find(form_selector).fill_in(with: "Test comment")
click_button "Comment"
@@ -39,7 +54,6 @@ RSpec.shared_examples 'work items assignees' do
# submit and simulate blur to save
send_keys(:enter)
find("body").click
-
wait_for_requests
expect(work_item.assignees).to include(user)
@@ -47,6 +61,8 @@ RSpec.shared_examples 'work items assignees' do
end
RSpec.shared_examples 'work items labels' do
+ let(:label_title_selector) { '[data-testid="labels-title"]' }
+
it 'successfully assigns a label' do
label = create(:label, project: work_item.project, title: "testing-label")
@@ -55,8 +71,7 @@ RSpec.shared_examples 'work items labels' do
# submit and simulate blur to save
send_keys(:enter)
- find("body").click
-
+ find(label_title_selector).click
wait_for_requests
expect(work_item.labels).to include(label)
@@ -139,3 +154,27 @@ RSpec.shared_examples 'work items invite members' do
end
end
end
+
+RSpec.shared_examples 'work items milestone' do
+ def set_milestone(milestone_dropdown, milestone_text)
+ milestone_dropdown.click
+
+ find('[data-testid="work-item-milestone-dropdown"] .gl-form-input', visible: true).send_keys "\"#{milestone_text}\""
+ wait_for_requests
+
+ click_button(milestone_text)
+ wait_for_requests
+ end
+
+ let(:milestone_dropdown_selector) { '[data-testid="work-item-milestone-dropdown"]' }
+
+ it 'searches and sets or removes milestone for the work item' do
+ set_milestone(find(milestone_dropdown_selector), milestone.title)
+
+ expect(page.find(milestone_dropdown_selector)).to have_text(milestone.title)
+
+ set_milestone(find(milestone_dropdown_selector), 'No milestone')
+
+ expect(page.find(milestone_dropdown_selector)).to have_text('Add to milestone')
+ end
+end
diff --git a/spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb
new file mode 100644
index 00000000000..e885b5d283e
--- /dev/null
+++ b/spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'members bulk update mutation' do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:user1) { create(:user) }
+ let_it_be(:user2) { create(:user) }
+ let_it_be(:member1) { create(member_type, source: source, user: user1) }
+ let_it_be(:member2) { create(member_type, source: source, user: user2) }
+
+ let(:extra_params) { { expires_at: 10.days.from_now } }
+ let(:input_params) { input.merge(extra_params) }
+ let(:mutation) { graphql_mutation(mutation_name, input_params) }
+ let(:mutation_response) { graphql_mutation_response(mutation_name) }
+
+ let(:input) do
+ {
+ source_id_key => source.to_global_id.to_s,
+ 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s],
+ 'access_level' => 'GUEST'
+ }
+ end
+
+ context 'when user is not logged-in' do
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user is not an owner' do
+ before do
+ source.add_developer(current_user)
+ end
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user is an owner' do
+ before do
+ source.add_owner(current_user)
+ end
+
+ shared_examples 'updates the user access role' do
+ specify do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ new_access_levels = mutation_response[response_member_field].map do |member|
+ member['accessLevel']['integerValue']
+ end
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['errors']).to be_empty
+ expect(new_access_levels).to all(be Gitlab::Access::GUEST)
+ end
+ end
+
+ it_behaves_like 'updates the user access role'
+
+ context 'when inherited members are passed' do
+ let(:input) do
+ {
+ source_id_key => source.to_global_id.to_s,
+ 'user_ids' => [user1.to_global_id.to_s, user2.to_global_id.to_s, parent_group_member.user.to_global_id.to_s],
+ 'access_level' => 'GUEST'
+ }
+ end
+
+ it 'does not update the members' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ error = Mutations::Members::BulkUpdateBase::INVALID_MEMBERS_ERROR
+ expect(json_response['errors'].first['message']).to include(error)
+ end
+ end
+
+ context 'when members count is more than the allowed limit' do
+ let(:max_members_update_limit) { 1 }
+
+ before do
+ stub_const('Mutations::Members::BulkUpdateBase::MAX_MEMBERS_UPDATE_LIMIT', max_members_update_limit)
+ end
+
+ it 'does not update the members' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ error = Mutations::Members::BulkUpdateBase::MAX_MEMBERS_UPDATE_ERROR
+ expect(json_response['errors'].first['message']).to include(error)
+ end
+ end
+
+ context 'when the update service raises access denied error' do
+ before do
+ allow_next_instance_of(Members::UpdateService) do |instance|
+ allow(instance).to receive(:execute).and_raise(Gitlab::Access::AccessDeniedError)
+ end
+ end
+
+ it 'does not update the members' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response[response_member_field]).to be_nil
+ expect(mutation_response['errors'])
+ .to contain_exactly("Unable to update members, please check user permissions.")
+ end
+ end
+
+ context 'when the update service returns an error message' do
+ before do
+ allow_next_instance_of(Members::UpdateService) do |instance|
+ error_result = {
+ message: 'Expires at cannot be a date in the past',
+ status: :error,
+ members: [member1]
+ }
+ allow(instance).to receive(:execute).and_return(error_result)
+ end
+ end
+
+ it 'will pass through the error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response[response_member_field].first['id']).to eq(member1.to_global_id.to_s)
+ expect(mutation_response['errors']).to contain_exactly('Expires at cannot be a date in the past')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb b/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
index 0d2e9f6ec8c..09239ced73a 100644
--- a/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_on_noteables_shared_examples.rb
@@ -46,7 +46,7 @@ RSpec.shared_context 'exposing regular notes on a noteable in GraphQL' do
discussions {
edges {
node {
- #{all_graphql_fields_for('Discussion', max_depth: 4)}
+ #{all_graphql_fields_for('Discussion', max_depth: 4, excluded: ['productAnalyticsState'])}
}
}
}
diff --git a/spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb b/spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb
new file mode 100644
index 00000000000..5f4e7e5d4e7
--- /dev/null
+++ b/spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb
@@ -0,0 +1,154 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'work item supports assignee widget updates via quick actions' do
+ let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } }
+
+ context 'when assigning a user' do
+ let(:body) { "/assign @#{developer.username}" }
+
+ it 'updates the work item assignee' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ noteable.reload
+ end.to change { noteable.assignee_ids }.from([]).to([developer.id])
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+
+ context 'when unassigning a user' do
+ let(:body) { "/unassign @#{developer.username}" }
+
+ before do
+ noteable.update!(assignee_ids: [developer.id])
+ end
+
+ it 'updates the work item assignee' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ noteable.reload
+ end.to change { noteable.assignee_ids }.from([developer.id]).to([])
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+end
+
+RSpec.shared_examples 'work item does not support assignee widget updates via quick actions' do
+ let(:developer) { create(:user).tap { |user| project.add_developer(user) } }
+ let(:body) { "Updating assignee.\n/assign @#{developer.username}" }
+
+ before do
+ WorkItems::Type.default_by_type(:task).widget_definitions
+ .find_by_widget_type(:assignees).update!(disabled: true)
+ end
+
+ it 'ignores the quick action' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ noteable.reload
+ end.not_to change { noteable.assignee_ids }
+ end
+end
+
+RSpec.shared_examples 'work item supports labels widget updates via quick actions' do
+ shared_examples 'work item labels are updated' do
+ it do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ noteable.reload
+ end.to change { noteable.labels.count }.to(expected_labels.count)
+
+ expect(noteable.labels).to match_array(expected_labels)
+ end
+ end
+
+ let_it_be(:existing_label) { create(:label, project: project) }
+ let_it_be(:label1) { create(:label, project: project) }
+ let_it_be(:label2) { create(:label, project: project) }
+
+ let(:add_label_ids) { [] }
+ let(:remove_label_ids) { [] }
+
+ before_all do
+ noteable.update!(labels: [existing_label])
+ end
+
+ context 'when only removing labels' do
+ let(:remove_label_ids) { [existing_label.to_gid.to_s] }
+ let(:expected_labels) { [] }
+ let(:body) { "/remove_label ~\"#{existing_label.name}\"" }
+
+ it_behaves_like 'work item labels are updated'
+ end
+
+ context 'when only adding labels' do
+ let(:add_label_ids) { [label1.to_gid.to_s, label2.to_gid.to_s] }
+ let(:expected_labels) { [label1, label2, existing_label] }
+ let(:body) { "/labels ~\"#{label1.name}\" ~\"#{label2.name}\"" }
+
+ it_behaves_like 'work item labels are updated'
+ end
+
+ context 'when adding and removing labels' do
+ let(:remove_label_ids) { [existing_label.to_gid.to_s] }
+ let(:add_label_ids) { [label1.to_gid.to_s, label2.to_gid.to_s] }
+ let(:expected_labels) { [label1, label2] }
+ let(:body) { "/label ~\"#{label1.name}\" ~\"#{label2.name}\"\n/remove_label ~\"#{existing_label.name}\"" }
+
+ it_behaves_like 'work item labels are updated'
+ end
+end
+
+RSpec.shared_examples 'work item does not support labels widget updates via quick actions' do
+ let(:label1) { create(:label, project: project) }
+ let(:body) { "Updating labels.\n/labels ~\"#{label1.name}\"" }
+
+ before do
+ WorkItems::Type.default_by_type(:task).widget_definitions
+ .find_by_widget_type(:labels).update!(disabled: true)
+ end
+
+ it 'ignores the quick action' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ noteable.reload
+ end.not_to change { noteable.labels.count }
+
+ expect(noteable.labels).to be_empty
+ end
+end
+
+RSpec.shared_examples 'work item supports start and due date widget updates via quick actions' do
+ let(:due_date) { Date.today }
+ let(:body) { "/remove_due_date" }
+
+ before do
+ noteable.update!(due_date: due_date)
+ end
+
+ it 'updates start and due date' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ noteable.reload
+ end.to not_change(noteable, :start_date).and(
+ change { noteable.due_date }.from(due_date).to(nil)
+ )
+ end
+end
+
+RSpec.shared_examples 'work item does not support start and due date widget updates via quick actions' do
+ let(:body) { "Updating due date.\n/due today" }
+
+ before do
+ WorkItems::Type.default_by_type(:task).widget_definitions
+ .find_by_widget_type(:start_and_due_date).update!(disabled: true)
+ end
+
+ it 'ignores the quick action' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ noteable.reload
+ end.not_to change { noteable.due_date }
+ end
+end
diff --git a/spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb b/spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb
index bb33a7559dc..ed193d06161 100644
--- a/spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/types/merge_request_interactions_type_shared_examples.rb
@@ -42,6 +42,7 @@ RSpec.shared_examples "a user type with merge request interaction type" do
profileEnableGitpodPath
savedReplies
savedReply
+ user_achievements
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/support/shared_examples/helpers/callouts_for_web_hooks.rb b/spec/support/shared_examples/helpers/callouts_for_web_hooks.rb
new file mode 100644
index 00000000000..b3d3000aa06
--- /dev/null
+++ b/spec/support/shared_examples/helpers/callouts_for_web_hooks.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'CalloutsHelper#web_hook_disabled_dismissed shared examples' do
+ context 'when the web-hook failure callout has never been dismissed' do
+ it 'is false' do
+ expect(helper).not_to be_web_hook_disabled_dismissed(container)
+ end
+ end
+
+ context 'when the web-hook failure callout has been dismissed', :freeze_time, :clean_gitlab_redis_shared_state do
+ before do
+ create(factory,
+ feature_name: Users::CalloutsHelper::WEB_HOOK_DISABLED,
+ user: user,
+ dismissed_at: 1.week.ago,
+ container_key => container)
+ end
+
+ it 'is true' do
+ expect(helper).to be_web_hook_disabled_dismissed(container)
+ end
+
+ it 'is true when passed as a presenter' do
+ skip "Does not apply to #{container.class}" unless container.is_a?(Presentable)
+
+ expect(helper).to be_web_hook_disabled_dismissed(container.present)
+ end
+
+ context 'when there was an older failure' do
+ before do
+ Gitlab::Redis::SharedState.with { |r| r.set(key, 1.month.ago.iso8601) }
+ end
+
+ it 'is true' do
+ expect(helper).to be_web_hook_disabled_dismissed(container)
+ end
+ end
+
+ context 'when there has been a more recent failure' do
+ before do
+ Gitlab::Redis::SharedState.with { |r| r.set(key, 1.day.ago.iso8601) }
+ end
+
+ it 'is false' do
+ expect(helper).not_to be_web_hook_disabled_dismissed(container)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/integrations/integration_settings_form.rb b/spec/support/shared_examples/integrations/integration_settings_form.rb
index aeb4e0feb12..a21eddb182c 100644
--- a/spec/support/shared_examples/integrations/integration_settings_form.rb
+++ b/spec/support/shared_examples/integrations/integration_settings_form.rb
@@ -7,7 +7,6 @@ RSpec.shared_examples 'integration settings form' do
it 'displays all the integrations', feature_category: :integrations do
aggregate_failures do
integrations.each do |integration|
- stub_feature_flags(integration_slack_app_notifications: false)
navigate_to_integration(integration)
page.within('form.integration-settings-form') do
diff --git a/spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb b/spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb
new file mode 100644
index 00000000000..b88eade7db2
--- /dev/null
+++ b/spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'it depends on value of the `terraform_state.enabled` config' do |params = {}|
+ let(:expected_success_status) { params[:success_status] || :ok }
+
+ context 'when terraform_state.enabled=false' do
+ before do
+ stub_config(terraform_state: { enabled: false })
+ end
+
+ it 'returns `forbidden` response' do
+ request
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when terraform_state.enabled=true' do
+ before do
+ stub_config(terraform_state: { enabled: true })
+ end
+
+ it 'returns a successful response' do
+ request
+
+ expect(response).to have_gitlab_http_status(expected_success_status)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb
new file mode 100644
index 00000000000..b9d71183851
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb
@@ -0,0 +1,131 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'async constraints validation' do
+ include ExclusiveLeaseHelpers
+
+ let!(:lease) { stub_exclusive_lease(lease_key, :uuid, timeout: lease_timeout) }
+ let(:lease_key) { "gitlab/database/asyncddl/actions/#{Gitlab::Database::PRIMARY_DATABASE_NAME}" }
+ let(:lease_timeout) { described_class::TIMEOUT_PER_ACTION }
+
+ let(:constraints_model) { Gitlab::Database::AsyncConstraints::PostgresAsyncConstraintValidation }
+ let(:table_name) { '_test_async_constraints' }
+ let(:constraint_name) { 'constraint_parent_id' }
+
+ let(:validation) do
+ create(:postgres_async_constraint_validation,
+ table_name: table_name,
+ name: constraint_name,
+ constraint_type: constraint_type)
+ end
+
+ let(:connection) { validation.connection }
+
+ subject { described_class.new(validation) }
+
+ it 'validates the constraint while controlling statement timeout' do
+ allow(connection).to receive(:execute).and_call_original
+ expect(connection).to receive(:execute)
+ .with("SET statement_timeout TO '43200s'").ordered.and_call_original
+ expect(connection).to receive(:execute)
+ .with(/ALTER TABLE "#{table_name}" VALIDATE CONSTRAINT "#{constraint_name}";/).ordered.and_call_original
+ expect(connection).to receive(:execute)
+ .with("RESET statement_timeout").ordered.and_call_original
+
+ subject.perform
+ end
+
+ it 'removes the constraint validation record from table' do
+ expect(validation).to receive(:destroy!).and_call_original
+
+ expect { subject.perform }.to change { constraints_model.count }.by(-1)
+ end
+
+ it 'skips logic if not able to acquire exclusive lease' do
+ expect(lease).to receive(:try_obtain).ordered.and_return(false)
+ expect(connection).not_to receive(:execute).with(/ALTER TABLE/)
+ expect(validation).not_to receive(:destroy!)
+
+ expect { subject.perform }.not_to change { constraints_model.count }
+ end
+
+ it 'logs messages around execution' do
+ allow(Gitlab::AppLogger).to receive(:info).and_call_original
+
+ subject.perform
+
+ expect(Gitlab::AppLogger)
+ .to have_received(:info)
+ .with(a_hash_including(message: 'Starting to validate constraint'))
+
+ expect(Gitlab::AppLogger)
+ .to have_received(:info)
+ .with(a_hash_including(message: 'Finished validating constraint'))
+ end
+
+ context 'when the constraint does not exist' do
+ before do
+ connection.create_table(table_name, force: true)
+ end
+
+ it 'skips validation and removes the record' do
+ expect(connection).not_to receive(:execute).with(/ALTER TABLE/)
+
+ expect { subject.perform }.to change { constraints_model.count }.by(-1)
+ end
+
+ it 'logs an appropriate message' do
+ expected_message = /Skipping #{constraint_name} validation since it does not exist/
+
+ allow(Gitlab::AppLogger).to receive(:info).and_call_original
+
+ subject.perform
+
+ expect(Gitlab::AppLogger)
+ .to have_received(:info)
+ .with(a_hash_including(message: expected_message))
+ end
+ end
+
+ context 'with error handling' do
+ before do
+ allow(connection).to receive(:execute).and_call_original
+
+ allow(connection).to receive(:execute)
+ .with(/ALTER TABLE "#{table_name}" VALIDATE CONSTRAINT "#{constraint_name}";/)
+ .and_raise(ActiveRecord::StatementInvalid)
+ end
+
+ context 'on production' do
+ before do
+ allow(Gitlab::ErrorTracking).to receive(:should_raise_for_dev?).and_return(false)
+ end
+
+ it 'increases execution attempts' do
+ expect { subject.perform }.to change { validation.attempts }.by(1)
+
+ expect(validation.last_error).to be_present
+ expect(validation).not_to be_destroyed
+ end
+
+ it 'logs an error message including the constraint_name' do
+ expect(Gitlab::AppLogger)
+ .to receive(:error)
+ .with(a_hash_including(:message, :constraint_name))
+ .and_call_original
+
+ subject.perform
+ end
+ end
+
+ context 'on development' do
+ it 'also raises errors' do
+ expect { subject.perform }
+ .to raise_error(ActiveRecord::StatementInvalid)
+ .and change { validation.attempts }.by(1)
+
+ expect(validation.last_error).to be_present
+ expect(validation).not_to be_destroyed
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb
new file mode 100644
index 00000000000..6f0cede7130
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples "index validators" do |validator, expected_result|
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:database_indexes) do
+ [
+ ['wrong_index', 'CREATE UNIQUE INDEX wrong_index ON public.table_name (column_name)'],
+ ['extra_index', 'CREATE INDEX extra_index ON public.table_name (column_name)'],
+ ['index', 'CREATE UNIQUE INDEX "index" ON public.achievements USING btree (namespace_id, lower(name))']
+ ]
+ end
+
+ let(:inconsistency_type) { validator.name.demodulize.underscore }
+
+ let(:database_name) { 'main' }
+
+ let(:database_model) { Gitlab::Database.database_base_models[database_name] }
+
+ let(:connection) { database_model.connection }
+
+ let(:schema) { connection.current_schema }
+
+ let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
+ let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
+
+ subject(:result) { validator.new(structure_file, database).execute }
+
+ before do
+ allow(connection).to receive(:select_rows).and_return(database_indexes)
+ end
+
+ it 'returns index inconsistencies' do
+ expect(result.map(&:object_name)).to match_array(expected_result)
+ expect(result.map(&:type)).to all(eql inconsistency_type)
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb
new file mode 100644
index 00000000000..d5ecab0cb6b
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples "schema objects assertions for" do |stmt_name|
+ let(:stmt) { PgQuery.parse(statement).tree.stmts.first.stmt }
+ let(:schema_object) { described_class.new(stmt.public_send(stmt_name)) }
+
+ describe '#name' do
+ it 'returns schema object name' do
+ expect(schema_object.name).to eq(name)
+ end
+ end
+
+ describe '#statement' do
+ it 'returns schema object statement' do
+ expect(schema_object.statement).to eq(statement)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb
new file mode 100644
index 00000000000..13a112275c2
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'trigger validators' do |validator, expected_result|
+ subject(:result) { validator.new(structure_file, database).execute }
+
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
+ let(:inconsistency_type) { validator.name.demodulize.underscore }
+ let(:database_name) { 'main' }
+ let(:schema) { 'public' }
+ let(:database_model) { Gitlab::Database.database_base_models[database_name] }
+ let(:connection) { database_model.connection }
+ let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
+
+ let(:database_triggers) do
+ [
+ ['trigger', 'CREATE TRIGGER trigger AFTER INSERT ON public.t1 FOR EACH ROW EXECUTE FUNCTION t1()'],
+ ['wrong_trigger', 'CREATE TRIGGER wrong_trigger BEFORE UPDATE ON public.t2 FOR EACH ROW EXECUTE FUNCTION t2()'],
+ ['extra_trigger', 'CREATE TRIGGER extra_trigger BEFORE INSERT ON public.t4 FOR EACH ROW EXECUTE FUNCTION t4()']
+ ]
+ end
+
+ before do
+ allow(connection).to receive(:select_rows).and_return(database_triggers)
+ end
+
+ it 'returns trigger inconsistencies' do
+ expect(result.map(&:object_name)).to match_array(expected_result)
+ expect(result.map(&:type)).to all(eql inconsistency_type)
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
index a3e4379f4d3..18545698c27 100644
--- a/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
@@ -26,29 +26,4 @@ RSpec.shared_examples 'search results filtered by language' do
expect(blob_results.size).to eq(5)
expect(paths).to match_array(expected_paths)
end
-
- context 'when the search_blobs_language_aggregation feature flag is disabled' do
- before do
- stub_feature_flags(search_blobs_language_aggregation: false)
- end
-
- it 'does not filter by language', :sidekiq_inline, :aggregate_failures do
- expected_paths = %w[
- CHANGELOG
- CONTRIBUTING.md
- bar/branch-test.txt
- custom-highlighting/test.gitlab-custom
- files/ruby/popen.rb
- files/ruby/regex.rb
- files/ruby/version_info.rb
- files/whitespace
- encoding/test.txt
- files/markdown/ruby-style-guide.md
- ]
-
- paths = blob_results.map { |blob| blob.binary_path }
- expect(blob_results.size).to eq(10)
- expect(paths).to match_array(expected_paths)
- 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
index d4802a19202..9873bab1caf 100644
--- 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
@@ -27,18 +27,6 @@ RSpec.shared_examples 'a daily tracked issuable snowplow and service ping events
expect_snowplow_event(**{ category: category, action: event_action, user: user1 }.merge(event_params))
end
-
- context 'with route_hll_to_snowplow_phase2 disabled' do
- before do
- stub_feature_flags(route_hll_to_snowplow_phase2: false)
- end
-
- it 'does not emit snowplow event' do
- track_action({ author: user1 }.merge(track_params))
-
- expect_no_snowplow_event
- end
- end
end
RSpec.shared_examples 'daily tracked issuable snowplow and service ping events with project' do
diff --git a/spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb
new file mode 100644
index 00000000000..a42d1450e4d
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'username and email pair is generated by Gitlab::Utils::UsernameAndEmailGenerator' do
+ let(:randomhex) { 'randomhex' }
+
+ it 'check email domain' do
+ expect(subject.email).to end_with("@#{email_domain}")
+ end
+
+ it 'contains SecureRandom part' do
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+
+ expect(subject.username).to include("_#{randomhex}")
+ expect(subject.email).to include("_#{randomhex}@")
+ end
+
+ it 'email name is the same as username' do
+ expect(subject.email).to include("#{subject.username}@")
+ end
+
+ context 'when conflicts' do
+ let(:reserved_username) { "#{username_prefix}_#{randomhex}" }
+ let(:reserved_email) { "#{reserved_username}@#{email_domain}" }
+
+ shared_examples 'uniquifies username and email' do
+ it 'uniquifies username and email' do
+ expect(subject.username).to eq("#{reserved_username}1")
+ expect(subject.email).to include("#{subject.username}@")
+ end
+ end
+
+ context 'when username is reserved' do
+ context 'when username is reserved by user' do
+ before do
+ create(:user, username: reserved_username)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+
+ context 'when it conflicts with top-level group namespace' do
+ before do
+ create(:group, path: reserved_username)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+
+ context 'when it conflicts with top-level group namespace that includes upcased characters' do
+ before do
+ create(:group, path: reserved_username.upcase)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+ end
+
+ context 'when email is reserved' do
+ context 'when it conflicts with confirmed primary email' do
+ before do
+ create(:user, email: reserved_email)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+
+ context 'when it conflicts with unconfirmed primary email' do
+ before do
+ create(:user, :unconfirmed, email: reserved_email)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+
+ context 'when it conflicts with confirmed secondary email' do
+ before do
+ create(:email, :confirmed, email: reserved_email)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+ end
+
+ context 'when email and username is reserved' do
+ before do
+ create(:user, email: reserved_email)
+ create(:user, username: "#{reserved_username}1")
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ it 'uniquifies username and email' do
+ expect(subject.username).to eq("#{reserved_username}2")
+
+ expect(subject.email).to include("#{subject.username}@")
+ end
+ 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 2c2cb362b07..ed3165079fb 100644
--- a/spec/support/shared_examples/lib/menus_shared_examples.rb
+++ b/spec/support/shared_examples/lib/menus_shared_examples.rb
@@ -37,3 +37,27 @@ RSpec.shared_examples_for 'pill_count formatted results' do
expect(pill_count).to eq('112.6k')
end
end
+
+RSpec.shared_examples_for 'serializable as super_sidebar_menu_args' do
+ let(:extra_attrs) { raise NotImplementedError }
+
+ it 'returns hash with provided attributes' do
+ expect(menu.serialize_as_menu_item_args).to eq({
+ title: menu.title,
+ link: menu.link,
+ active_routes: menu.active_routes,
+ container_html_options: menu.container_html_options,
+ **extra_attrs
+ })
+ end
+
+ it 'returns hash with an item_id' do
+ expect(menu.serialize_as_menu_item_args[:item_id]).not_to be_nil
+ end
+end
+
+RSpec.shared_examples_for 'not serializable as super_sidebar_menu_args' do
+ it 'returns nil' do
+ expect(menu.serialize_as_menu_item_args).to be_nil
+ end
+end
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
new file mode 100644
index 00000000000..92c51a03b31
--- /dev/null
+++ b/spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'User profile menu' do |title:, active_route:|
+ let_it_be(:current_user) { build(:user) }
+ let_it_be(:user) { build(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
+
+ subject { described_class.new(context) }
+
+ it 'does not contain any sub menu' do
+ expect(subject.has_items?).to be false
+ end
+
+ it 'renders the correct link' do
+ expect(subject.link).to match link
+ end
+
+ it 'renders the correct title' do
+ expect(subject.title).to eq title
+ end
+
+ it 'defines correct active route' do
+ expect(subject.active_routes[:path]).to be active_route
+ end
+
+ it 'renders if user is logged in' do
+ expect(subject.render?).to be true
+ end
+
+ [:blocked, :banned].each do |trait|
+ context "when viewed user is #{trait}" do
+ let_it_be(:viewed_user) { build(:user, trait) }
+ let(:context) { Sidebars::Context.new(current_user: user, container: viewed_user) }
+
+ context 'when user is not logged in' do
+ it 'is not allowed to view the menu item' do
+ expect(described_class.new(Sidebars::Context.new(current_user: nil,
+ container: viewed_user)).render?).to be false
+ end
+ end
+
+ context 'when current user has permission' do
+ before do
+ allow(Ability).to receive(:allowed?).with(user, :read_user_profile, viewed_user).and_return(true)
+ end
+
+ it 'is allowed to view the menu item' do
+ expect(described_class.new(context).render?).to be true
+ end
+ end
+
+ context 'when current user does not have permission' do
+ it 'is not allowed to view the menu item' do
+ expect(described_class.new(context).render?).to be false
+ end
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'Followers/followees counts' do |symbol|
+ let_it_be(:current_user) { build(:user) }
+ let_it_be(:user) { build(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
+
+ subject { described_class.new(context) }
+
+ context 'when there are items' do
+ before do
+ allow(user).to receive(symbol).and_return([1, 2])
+ end
+
+ it 'renders the pill' do
+ expect(subject.has_pill?).to be(true)
+ end
+
+ it 'returns the count' do
+ expect(subject.pill_count).to be(2)
+ end
+ end
+
+ context 'when there are no items' do
+ it 'does not render the pill' do
+ expect(subject.has_pill?).to be(false)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb b/spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb
new file mode 100644
index 00000000000..b91386d1935
--- /dev/null
+++ b/spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'User settings menu' do |link:, title:, icon:, active_routes:|
+ let_it_be(:user) { create(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'does not contain any sub menu' do
+ expect(subject.has_items?).to be false
+ end
+
+ it 'renders the correct link' do
+ expect(subject.link).to match link
+ end
+
+ it 'renders the correct title' do
+ expect(subject.title).to eq title
+ end
+
+ it 'renders the correct icon' do
+ expect(subject.sprite_icon).to be icon
+ end
+
+ it 'defines correct active route' do
+ expect(subject.active_routes).to eq active_routes
+ end
+end
+
+RSpec.shared_examples 'User settings menu #render? method' do
+ describe '#render?' do
+ subject { described_class.new(context) }
+
+ context 'when user is logged in' do
+ let_it_be(:user) { build(:user) }
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ it 'renders' do
+ expect(subject.render?).to be true
+ end
+ end
+
+ context 'when user is not logged in' do
+ let(:context) { Sidebars::Context.new(current_user: nil, container: nil) }
+
+ it 'does not render' do
+ expect(subject.render?).to be false
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/mailers/export_csv_shared_examples.rb b/spec/support/shared_examples/mailers/export_csv_shared_examples.rb
new file mode 100644
index 00000000000..731d7c810f9
--- /dev/null
+++ b/spec/support/shared_examples/mailers/export_csv_shared_examples.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'export csv email' do |collection_type|
+ include_context 'gitlab email notification'
+
+ it 'attachment has csv mime type' do
+ expect(attachment.mime_type).to eq 'text/csv'
+ end
+
+ it 'generates a useful filename' do
+ expect(attachment.filename).to include(Date.today.year.to_s)
+ expect(attachment.filename).to include(collection_type)
+ expect(attachment.filename).to include('myproject')
+ expect(attachment.filename).to end_with('.csv')
+ end
+
+ it 'mentions number of objects and project name' do
+ expect(subject).to have_content '3'
+ expect(subject).to have_content empty_project.name
+ end
+
+ it "doesn't need to mention truncation by default" do
+ expect(subject).not_to have_content 'truncated'
+ end
+
+ context 'when truncated' do
+ let(:export_status) { { truncated: true, rows_expected: 12, rows_written: 10 } }
+
+ it 'mentions that the csv has been truncated' do
+ expect(subject).to have_content 'truncated'
+ end
+
+ it 'mentions the number of objects written and expected' do
+ expect(subject).to have_content "10 of 12 #{collection_type.humanize.downcase}"
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/active_record_enum_shared_examples.rb b/spec/support/shared_examples/models/active_record_enum_shared_examples.rb
index 3d765b6ca93..10f3263d4fc 100644
--- a/spec/support/shared_examples/models/active_record_enum_shared_examples.rb
+++ b/spec/support/shared_examples/models/active_record_enum_shared_examples.rb
@@ -10,3 +10,13 @@ RSpec.shared_examples 'having unique enum values' do
end
end
end
+
+RSpec.shared_examples 'having enum with nil value' do
+ it 'has enum with nil value' do
+ subject.public_send("#{attr_value}!")
+
+ expect(subject.public_send("#{attr}_for_database")).to be_nil
+ expect(subject.public_send("#{attr}?")).to eq(true)
+ expect(subject.class.public_send(attr_value)).to eq([subject])
+ end
+end
diff --git a/spec/support/shared_examples/models/ci/token_format_shared_examples.rb b/spec/support/shared_examples/models/ci/token_format_shared_examples.rb
new file mode 100644
index 00000000000..0272982e2d0
--- /dev/null
+++ b/spec/support/shared_examples/models/ci/token_format_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples_for 'ensures runners_token is prefixed' do |factory|
+ subject(:record) { FactoryBot.build(factory) }
+
+ describe '#runners_token', feature_category: :system_access do
+ let(:runners_prefix) { RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX }
+
+ it 'generates runners_token which starts with runner prefix' do
+ expect(record.runners_token).to match(a_string_starting_with(runners_prefix))
+ end
+
+ context 'when record has an invalid token' do
+ subject(:record) { FactoryBot.build(factory, runners_token: invalid_runners_token) }
+
+ let(:invalid_runners_token) { "not_start_with_runners_prefix" }
+
+ it 'generates runners_token which starts with runner prefix' do
+ expect(record.runners_token).to match(a_string_starting_with(runners_prefix))
+ end
+
+ it 'changes the attribute values for runners_token and runners_token_encrypted' do
+ expect { record.runners_token }
+ .to change { record[:runners_token] }.from(invalid_runners_token).to(nil)
+ .and change { record[:runners_token_encrypted] }.from(nil)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/concerns/auto_disabling_hooks_shared_examples.rb b/spec/support/shared_examples/models/concerns/auto_disabling_hooks_shared_examples.rb
index 122774a9028..a26c20ccc61 100644
--- a/spec/support/shared_examples/models/concerns/auto_disabling_hooks_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/auto_disabling_hooks_shared_examples.rb
@@ -61,6 +61,20 @@ disabled_until: disabled_until)
# Nothing is missing
expect(find_hooks.executable.to_a + find_hooks.disabled.to_a).to match_array(find_hooks.to_a)
end
+
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it 'causes all hooks to be considered executable' do
+ expect(find_hooks.executable.count).to eq(16)
+ end
+
+ it 'causes no hooks to be considered disabled' do
+ expect(find_hooks.disabled).to be_empty
+ end
+ end
end
describe '#executable?', :freeze_time do
@@ -108,6 +122,16 @@ disabled_until: disabled_until)
it 'has the correct state' do
expect(web_hook.executable?).to eq(executable)
end
+
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it 'is always executable' do
+ expect(web_hook).to be_executable
+ end
+ end
end
end
@@ -151,7 +175,7 @@ disabled_until: disabled_until)
context 'when we have exhausted the grace period' do
before do
- hook.update!(recent_failures: WebHook::FAILURE_THRESHOLD)
+ hook.update!(recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD)
end
context 'when the hook is permanently disabled' do
@@ -172,6 +196,16 @@ disabled_until: disabled_until)
def run_expectation
expect { hook.backoff! }.to change { hook.backoff_count }.by(1)
end
+
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it 'does not increment backoff count' do
+ expect { hook.failed! }.not_to change { hook.backoff_count }
+ end
+ end
end
end
end
@@ -181,6 +215,16 @@ disabled_until: disabled_until)
def run_expectation
expect { hook.failed! }.to change { hook.recent_failures }.by(1)
end
+
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it 'does not increment recent failure count' do
+ expect { hook.failed! }.not_to change { hook.recent_failures }
+ end
+ end
end
end
@@ -189,6 +233,16 @@ disabled_until: disabled_until)
expect { hook.disable! }.to change { hook.executable? }.from(true).to(false)
end
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it 'does not disable the hook' do
+ expect { hook.disable! }.not_to change { hook.executable? }
+ end
+ end
+
it 'does nothing if the hook is already disabled' do
allow(hook).to receive(:permanently_disabled?).and_return(true)
@@ -210,7 +264,7 @@ disabled_until: disabled_until)
end
it 'allows FAILURE_THRESHOLD initial failures before we back-off' do
- WebHook::FAILURE_THRESHOLD.times do
+ WebHooks::AutoDisabling::FAILURE_THRESHOLD.times do
hook.backoff!
expect(hook).not_to be_temporarily_disabled
end
@@ -221,13 +275,23 @@ disabled_until: disabled_until)
context 'when hook has been told to back off' do
before do
- hook.update!(recent_failures: WebHook::FAILURE_THRESHOLD)
+ hook.update!(recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD)
hook.backoff!
end
it 'is true' do
expect(hook).to be_temporarily_disabled
end
+
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it 'is false' do
+ expect(hook).not_to be_temporarily_disabled
+ end
+ end
end
end
@@ -244,6 +308,16 @@ disabled_until: disabled_until)
it 'is true' do
expect(hook).to be_permanently_disabled
end
+
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it 'is false' do
+ expect(hook).not_to be_permanently_disabled
+ end
+ end
end
end
@@ -258,15 +332,31 @@ disabled_until: disabled_until)
end
it { is_expected.to eq :disabled }
+
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it { is_expected.to eq(:executable) }
+ end
end
context 'when hook has been backed off' do
before do
- hook.update!(recent_failures: WebHook::FAILURE_THRESHOLD + 1)
+ hook.update!(recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1)
hook.disabled_until = 1.hour.from_now
end
it { is_expected.to eq :temporarily_disabled }
+
+ context 'when the flag is disabled' do
+ before do
+ stub_feature_flags(auto_disabling_web_hooks: false)
+ end
+
+ it { is_expected.to eq(:executable) }
+ end
end
end
end
diff --git a/spec/support/shared_examples/models/concerns/cascading_namespace_setting_shared_examples.rb b/spec/support/shared_examples/models/concerns/cascading_namespace_setting_shared_examples.rb
index a4db4e25db3..9dec1a5056c 100644
--- a/spec/support/shared_examples/models/concerns/cascading_namespace_setting_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/cascading_namespace_setting_shared_examples.rb
@@ -171,15 +171,59 @@ RSpec.shared_examples 'a cascading namespace setting boolean attribute' do
end
describe "##{settings_attribute_name}=" do
- before do
- subgroup_settings.update!(settings_attribute_name => nil)
- group_settings.update!(settings_attribute_name => true)
+ using RSpec::Parameterized::TableSyntax
+
+ where(:parent_value, :current_subgroup_value, :new_subgroup_value, :expected_subgroup_value_after_update) do
+ true | nil | true | nil
+ true | nil | "true" | nil
+ true | false | true | true
+ true | false | "true" | true
+ true | true | false | false
+ true | true | "false" | false
+ false | nil | false | nil
+ false | nil | true | true
+ false | true | false | false
+ false | false | true | true
end
- it 'does not save the value locally when it matches the cascaded value' do
- subgroup_settings.update!(settings_attribute_name => true)
+ with_them do
+ before do
+ subgroup_settings.update!(settings_attribute_name => current_subgroup_value)
+ group_settings.update!(settings_attribute_name => parent_value)
+ end
+
+ it 'validates starting values from before block', :aggregate_failures do
+ expect(group_settings.reload.read_attribute(settings_attribute_name)).to eq(parent_value)
+ expect(subgroup_settings.reload.read_attribute(settings_attribute_name)).to eq(current_subgroup_value)
+ end
+
+ it 'does not save the value locally when it matches cascaded value', :aggregate_failures do
+ subgroup_settings.send("#{settings_attribute_name}=", new_subgroup_value)
+
+ # Verify dirty value
+ expect(subgroup_settings.read_attribute(settings_attribute_name)).to eq(expected_subgroup_value_after_update)
+
+ subgroup_settings.save!
- expect(subgroup_settings.read_attribute(settings_attribute_name)).to eq(nil)
+ # Verify persisted value
+ expect(subgroup_settings.reload.read_attribute(settings_attribute_name))
+ .to eq(expected_subgroup_value_after_update)
+ end
+
+ context 'when mass assigned' do
+ before do
+ subgroup_settings.attributes =
+ { settings_attribute_name => new_subgroup_value, "lock_#{settings_attribute_name}" => false }
+ end
+
+ it 'does not save the value locally when it matches cascaded value', :aggregate_failures do
+ subgroup_settings.save!
+
+ # Verify persisted value
+ expect(subgroup_settings.reload.read_attribute(settings_attribute_name))
+ .to eq(expected_subgroup_value_after_update)
+ end
+ end
end
end
diff --git a/spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb b/spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb
index 5755b9a56b1..139deaaece9 100644
--- a/spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/counter_attribute_shared_examples.rb
@@ -17,6 +17,11 @@ RSpec.shared_examples_for CounterAttribute do |counter_attributes|
let(:amount) { 10 }
let(:increment) { Gitlab::Counters::Increment.new(amount: amount, ref: 3) }
let(:counter_key) { model.counter(attribute).key }
+ let(:returns_current) do
+ model.class.counter_attributes
+ .find { |a| a[:attribute] == attribute }
+ .fetch(:returns_current, false)
+ end
subject { model.increment_counter(attribute, increment) }
@@ -61,6 +66,33 @@ RSpec.shared_examples_for CounterAttribute do |counter_attributes|
end
end
+ describe '#increment_amount' do
+ it 'increases the egress in cache' do
+ model.increment_amount(attribute, 3)
+
+ expect(model.counter(attribute).get).to eq(3)
+ end
+ end
+
+ describe '#current_counter' do
+ let(:data_transfer_node) do
+ args = { project: project }
+ args[attribute] = 2
+ create(:project_data_transfer, **args)
+ end
+
+ it 'increases the amount in cache' do
+ if returns_current
+ incremented_by = 4
+ db_state = model.read_attribute(attribute)
+
+ model.send("increment_#{attribute}".to_sym, incremented_by)
+
+ expect(model.send(attribute)).to eq(db_state + incremented_by)
+ end
+ end
+ end
+
context 'when increment amount is 0' do
let(:amount) { 0 }
@@ -155,14 +187,24 @@ RSpec.shared_examples_for CounterAttribute do |counter_attributes|
end
describe '#update_counters_with_lease' do
- let(:increments) { { build_artifacts_size: 1, packages_size: 2 } }
+ let_it_be(:first_attribute) { counter_attributes.first }
+ let_it_be(:second_attribute) { counter_attributes.second }
+
+ let_it_be(:increments) do
+ increments_hash = {}
+
+ increments_hash[first_attribute] = 1
+ increments_hash[second_attribute] = 2
+
+ increments_hash
+ end
subject { model.update_counters_with_lease(increments) }
it 'updates counters of the record' do
expect { subject }
- .to change { model.reload.build_artifacts_size }.by(1)
- .and change { model.reload.packages_size }.by(2)
+ .to change { model.reload.send(first_attribute) }.by(1)
+ .and change { model.reload.send(second_attribute) }.by(2)
end
it_behaves_like 'obtaining lease to update database' do
diff --git a/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
index 2e528f7996c..2dad35dc46e 100644
--- a/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
@@ -35,7 +35,6 @@ RSpec.shared_examples Integrations::BaseSlackNotification do |factory:|
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:category) { described_class.to_s }
let(:action) { 'perform_integrations_action' }
let(:namespace) { project.namespace }
diff --git a/spec/support/shared_examples/models/concerns/unstoppable_hooks_shared_examples.rb b/spec/support/shared_examples/models/concerns/unstoppable_hooks_shared_examples.rb
index 848840ee297..24d114bbe23 100644
--- a/spec/support/shared_examples/models/concerns/unstoppable_hooks_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/unstoppable_hooks_shared_examples.rb
@@ -110,7 +110,7 @@ disabled_until: disabled_until)
context 'when we have exhausted the grace period' do
before do
- hook.update!(recent_failures: WebHook::FAILURE_THRESHOLD)
+ hook.update!(recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD)
end
it 'does not disable the hook' do
@@ -131,7 +131,7 @@ disabled_until: disabled_until)
expect(hook).not_to be_temporarily_disabled
# Backing off
- WebHook::FAILURE_THRESHOLD.times do
+ WebHooks::AutoDisabling::FAILURE_THRESHOLD.times do
hook.backoff!
expect(hook).not_to be_temporarily_disabled
end
@@ -167,7 +167,7 @@ disabled_until: disabled_until)
context 'when hook has been backed off' do
before do
- hook.update!(recent_failures: WebHook::FAILURE_THRESHOLD + 1)
+ hook.update!(recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1)
hook.disabled_until = 1.hour.from_now
end
diff --git a/spec/support/shared_examples/models/concerns/web_hooks/has_web_hooks_shared_examples.rb b/spec/support/shared_examples/models/concerns/web_hooks/has_web_hooks_shared_examples.rb
index cd6eb8c77fa..113dcc266fc 100644
--- a/spec/support/shared_examples/models/concerns/web_hooks/has_web_hooks_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/web_hooks/has_web_hooks_shared_examples.rb
@@ -19,7 +19,7 @@ RSpec.shared_examples 'something that has web-hooks' do
context 'when there is a failed hook' do
before do
hook = create_hook
- hook.update!(recent_failures: WebHook::FAILURE_THRESHOLD + 1)
+ hook.update!(recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1)
end
it { is_expected.to eq(true) }
@@ -83,7 +83,7 @@ RSpec.shared_examples 'something that has web-hooks' do
describe '#fetch_web_hook_failure', :clean_gitlab_redis_shared_state do
context 'when a value has not been stored' do
- it 'does not call #any_hook_failed?' do
+ it 'calls #any_hook_failed?' do
expect(object.get_web_hook_failure).to be_nil
expect(object).to receive(:any_hook_failed?).and_return(true)
diff --git a/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb b/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
index 5eeefacdeb9..3f532629961 100644
--- a/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
+++ b/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
@@ -290,6 +290,7 @@ RSpec.shared_examples 'value stream analytics label based stage' do
context 'when `ProjectLabel is given' do
let_it_be(:label) { create(:label) }
+ let(:expected_error) { s_('CycleAnalyticsStage|is not available for the selected group') }
it 'raises error when `ProjectLabel` is given for `start_event_label`' do
params = {
@@ -300,7 +301,9 @@ RSpec.shared_examples 'value stream analytics label based stage' do
end_event_identifier: :issue_closed
}
- expect { described_class.new(params) }.to raise_error(ActiveRecord::AssociationTypeMismatch)
+ stage = described_class.new(params)
+ expect(stage).to be_invalid
+ expect(stage.errors.messages_for(:start_event_label_id)).to eq([expected_error])
end
it 'raises error when `ProjectLabel` is given for `end_event_label`' do
@@ -312,7 +315,9 @@ RSpec.shared_examples 'value stream analytics label based stage' do
end_event_label: label
}
- expect { described_class.new(params) }.to raise_error(ActiveRecord::AssociationTypeMismatch)
+ stage = described_class.new(params)
+ expect(stage).to be_invalid
+ expect(stage.errors.messages_for(:end_event_label_id)).to eq([expected_error])
end
end
end
diff --git a/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb b/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb
index 7dfdd24177e..0cf109ce5c5 100644
--- a/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb
+++ b/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb
@@ -3,7 +3,6 @@
RSpec.shared_examples Integrations::BaseSlashCommands do
describe "Associations" do
it { is_expected.to respond_to :token }
- it { is_expected.to have_many :chat_names }
end
describe 'default values' do
@@ -85,7 +84,7 @@ RSpec.shared_examples Integrations::BaseSlashCommands do
end
context 'when the user is authenticated' do
- let!(:chat_name) { create(:chat_name, integration: subject) }
+ let!(:chat_name) { create(:chat_name) }
let(:params) { { token: 'token', team_id: chat_name.team_id, user_id: chat_name.chat_id } }
subject do
diff --git a/spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb b/spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb
index 5be0f6349ea..78591482696 100644
--- a/spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb
+++ b/spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb
@@ -231,4 +231,20 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
it { is_expected.to eq("#{component1_1.name}/binary-#{architecture1_1.name}/Packages.xz") }
end
end
+
+ describe '#empty?' do
+ subject { component_file_with_architecture.empty? }
+
+ context 'with a non-empty component' do
+ it { is_expected.to be_falsey }
+ end
+
+ context 'with an empty component' do
+ before do
+ component_file_with_architecture.update! size: 0
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
end
diff --git a/spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb b/spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb
index 3caf58da4d2..f1af1760e8d 100644
--- a/spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb
+++ b/spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb
@@ -19,7 +19,7 @@ RSpec.shared_examples 'ci_cd_settings delegation' do
end
end
-RSpec.shared_examples 'a ci_cd_settings predicate method' do |prefix: ''|
+RSpec.shared_examples 'a ci_cd_settings predicate method' do |prefix: '', default: false|
using RSpec::Parameterized::TableSyntax
context 'when ci_cd_settings is nil' do
@@ -28,7 +28,7 @@ RSpec.shared_examples 'a ci_cd_settings predicate method' do |prefix: ''|
end
it 'returns false' do
- expect(project.send("#{prefix}#{delegated_method}")).to be(false)
+ expect(project.send("#{prefix}#{delegated_method}")).to be(default)
end
end
diff --git a/spec/support/shared_examples/observability/csp_shared_examples.rb b/spec/support/shared_examples/observability/csp_shared_examples.rb
index 0cd211f69eb..9d6e7e75f4d 100644
--- a/spec/support/shared_examples/observability/csp_shared_examples.rb
+++ b/spec/support/shared_examples/observability/csp_shared_examples.rb
@@ -31,19 +31,19 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
let(:observability_url) { Gitlab::Observability.observability_url }
let(:signin_url) do
Gitlab::Utils.append_path(Gitlab.config.gitlab.url,
- '/users/sign_in')
+ '/users/sign_in')
end
let(:oauth_url) do
Gitlab::Utils.append_path(Gitlab.config.gitlab.url,
- '/oauth/authorize')
+ '/oauth/authorize')
end
before do
setup_csp_for_controller(controller_class, csp, any_time: true)
group.add_developer(user)
login_as(user)
- allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(true)
+ stub_feature_flags(observability_group_tab: true)
end
subject do
@@ -67,7 +67,7 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
end
before do
- allow(Gitlab::Observability).to receive(:observability_enabled?).and_return(false)
+ stub_feature_flags(observability_group_tab: false)
end
it 'does not add observability urls to the csp header' do
@@ -76,23 +76,6 @@ RSpec.shared_examples 'observability csp policy' do |controller_class = describe
end
end
- context 'when checking if observability is enabled' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.frame_src 'https://something.test'
- end
- end
-
- it 'check access for a given user and group' do
- allow(Gitlab::Observability).to receive(:observability_enabled?)
-
- get tested_path
-
- expect(Gitlab::Observability).to have_received(:observability_enabled?)
- .with(user, group).at_least(:once)
- end
- end
-
context 'when frame-src exists in the CSP config' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
diff --git a/spec/support/shared_examples/observability/embed_observabilities_examples.rb b/spec/support/shared_examples/observability/embed_observabilities_examples.rb
new file mode 100644
index 00000000000..c8d4e9e0d7e
--- /dev/null
+++ b/spec/support/shared_examples/observability/embed_observabilities_examples.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'embeds observability' do
+ it 'renders iframe in description' do
+ page.within('.description') do
+ expect_observability_iframe(page.html)
+ end
+ end
+
+ it 'renders iframe in comment' do
+ expect(page).not_to have_css('.note-text')
+
+ page.within('.js-main-target-form') do
+ fill_in('note[note]', with: observable_url)
+ click_button('Comment')
+ end
+
+ wait_for_requests
+
+ page.within('.note-text') do
+ expect_observability_iframe(page.html)
+ end
+ end
+end
+
+RSpec.shared_examples 'does not embed observability' do
+ it 'does not render iframe in description' do
+ page.within('.description') do
+ expect_observability_iframe(page.html, to_be_nil: true)
+ end
+ end
+
+ it 'does not render iframe in comment' do
+ expect(page).not_to have_css('.note-text')
+
+ page.within('.js-main-target-form') do
+ fill_in('note[note]', with: observable_url)
+ click_button('Comment')
+ end
+
+ wait_for_requests
+
+ page.within('.note-text') do
+ expect_observability_iframe(page.html, to_be_nil: true)
+ end
+ end
+end
+
+def expect_observability_iframe(html, to_be_nil: false)
+ iframe = Nokogiri::HTML.parse(html).at_css('#observability-ui-iframe')
+
+ expect(html).to include(observable_url)
+
+ if to_be_nil
+ expect(iframe).to be_nil
+ else
+ expect(iframe).not_to be_nil
+ iframe_src = "#{expected_observable_url}&theme=light&username=#{user.username}&kiosk=inline-embed"
+ expect(iframe.attributes['src'].value).to eq(iframe_src)
+ end
+end
diff --git a/spec/support/shared_examples/policies/project_policy_shared_examples.rb b/spec/support/shared_examples/policies/project_policy_shared_examples.rb
index 9ec1b8b3f5a..d1f5a01b10c 100644
--- a/spec/support/shared_examples/policies/project_policy_shared_examples.rb
+++ b/spec/support/shared_examples/policies/project_policy_shared_examples.rb
@@ -401,3 +401,24 @@ RSpec.shared_examples 'package access with repository disabled' do
it { is_expected.to be_allowed(:read_package) }
end
+
+RSpec.shared_examples 'equivalent project policy abilities' do
+ where(:project_visibility, :user_role_on_project) do
+ project_visibilities = [:public, :internal, :private]
+ user_role_on_project = [:anonymous, :non_member, :guest, :reporter, :developer, :maintainer, :owner, :admin]
+ project_visibilities.product(user_role_on_project)
+ end
+
+ with_them do
+ it 'evaluates the same' do
+ project = public_send("#{project_visibility}_project")
+ current_user = public_send(user_role_on_project)
+ enable_admin_mode!(current_user) if user_role_on_project == :admin
+ policy = ProjectPolicy.new(current_user, project)
+ old_permissions = policy.allowed?(old_policy)
+ new_permissions = policy.allowed?(new_policy)
+
+ expect(old_permissions).to eq new_permissions
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/admin_mode_shared_examples.rb b/spec/support/shared_examples/requests/admin_mode_shared_examples.rb
index 07fde7d3f35..ceb57fca786 100644
--- a/spec/support/shared_examples/requests/admin_mode_shared_examples.rb
+++ b/spec/support/shared_examples/requests/admin_mode_shared_examples.rb
@@ -1,94 +1,99 @@
# frozen_string_literal: true
-RSpec.shared_examples 'GET request permissions for admin mode' do
- it_behaves_like 'GET request permissions for admin mode when user'
- it_behaves_like 'GET request permissions for admin mode when admin'
+RSpec.shared_examples 'GET request permissions for admin mode' do |failed_status_code = :forbidden|
+ it_behaves_like 'GET request permissions for admin mode when user', failed_status_code
+ it_behaves_like 'GET request permissions for admin mode when admin', failed_status_code
end
-RSpec.shared_examples 'PUT request permissions for admin mode' do |params|
- it_behaves_like 'PUT request permissions for admin mode when user', params
- it_behaves_like 'PUT request permissions for admin mode when admin', params
+RSpec.shared_examples 'PUT request permissions for admin mode' do |failed_status_code = :forbidden|
+ it_behaves_like 'PUT request permissions for admin mode when user', failed_status_code
+ it_behaves_like 'PUT request permissions for admin mode when admin', failed_status_code
end
-RSpec.shared_examples 'POST request permissions for admin mode' do |params|
- it_behaves_like 'POST request permissions for admin mode when user', params
- it_behaves_like 'POST request permissions for admin mode when admin', params
+RSpec.shared_examples 'POST request permissions for admin mode' do |failed_status_code = :forbidden|
+ it_behaves_like 'POST request permissions for admin mode when user', failed_status_code
+ it_behaves_like 'POST request permissions for admin mode when admin', failed_status_code
end
-RSpec.shared_examples 'DELETE request permissions for admin mode' do
- it_behaves_like 'DELETE request permissions for admin mode when user'
- it_behaves_like 'DELETE request permissions for admin mode when admin'
+RSpec.shared_examples 'DELETE request permissions for admin mode' do |success_status_code: :no_content,
+ failed_status_code: :forbidden|
+
+ it_behaves_like 'DELETE request permissions for admin mode when user', failed_status_code
+ it_behaves_like 'DELETE request permissions for admin mode when admin', success_status_code: success_status_code,
+ failed_status_code: failed_status_code
end
-RSpec.shared_examples 'GET request permissions for admin mode when user' do
+RSpec.shared_examples 'GET request permissions for admin mode when user' do |failed_status_code = :forbidden|
subject { get api(path, current_user, admin_mode: admin_mode) }
let_it_be(:current_user) { create(:user) }
- it_behaves_like 'admin mode on', true, :forbidden
- it_behaves_like 'admin mode on', false, :forbidden
+ it_behaves_like 'admin mode on', true, failed_status_code
+ it_behaves_like 'admin mode on', false, failed_status_code
end
-RSpec.shared_examples 'GET request permissions for admin mode when admin' do
+RSpec.shared_examples 'GET request permissions for admin mode when admin' do |failed_status_code = :forbidden|
subject { get api(path, current_user, admin_mode: admin_mode) }
let_it_be(:current_user) { create(:admin) }
it_behaves_like 'admin mode on', true, :ok
- it_behaves_like 'admin mode on', false, :forbidden
+ it_behaves_like 'admin mode on', false, failed_status_code
end
-RSpec.shared_examples 'PUT request permissions for admin mode when user' do |params|
+RSpec.shared_examples 'PUT request permissions for admin mode when user' do |failed_status_code = :forbidden|
subject { put api(path, current_user, admin_mode: admin_mode), params: params }
let_it_be(:current_user) { create(:user) }
- it_behaves_like 'admin mode on', true, :forbidden
- it_behaves_like 'admin mode on', false, :forbidden
+ it_behaves_like 'admin mode on', true, failed_status_code
+ it_behaves_like 'admin mode on', false, failed_status_code
end
-RSpec.shared_examples 'PUT request permissions for admin mode when admin' do |params|
+RSpec.shared_examples 'PUT request permissions for admin mode when admin' do |failed_status_code = :forbidden|
subject { put api(path, current_user, admin_mode: admin_mode), params: params }
let_it_be(:current_user) { create(:admin) }
it_behaves_like 'admin mode on', true, :ok
- it_behaves_like 'admin mode on', false, :forbidden
+ it_behaves_like 'admin mode on', false, failed_status_code
end
-RSpec.shared_examples 'POST request permissions for admin mode when user' do |params|
+RSpec.shared_examples 'POST request permissions for admin mode when user' do |failed_status_code = :forbidden|
subject { post api(path, current_user, admin_mode: admin_mode), params: params }
let_it_be(:current_user) { create(:user) }
- it_behaves_like 'admin mode on', true, :forbidden
- it_behaves_like 'admin mode on', false, :forbidden
+ it_behaves_like 'admin mode on', true, failed_status_code
+ it_behaves_like 'admin mode on', false, failed_status_code
end
-RSpec.shared_examples 'POST request permissions for admin mode when admin' do |params|
+RSpec.shared_examples 'POST request permissions for admin mode when admin' do |failed_status_code = :forbidden|
subject { post api(path, current_user, admin_mode: admin_mode), params: params }
let_it_be(:current_user) { create(:admin) }
it_behaves_like 'admin mode on', true, :created
- it_behaves_like 'admin mode on', false, :forbidden
+ it_behaves_like 'admin mode on', false, failed_status_code
end
-RSpec.shared_examples 'DELETE request permissions for admin mode when user' do
+RSpec.shared_examples 'DELETE request permissions for admin mode when user' do |failed_status_code = :forbidden|
subject { delete api(path, current_user, admin_mode: admin_mode) }
let_it_be(:current_user) { create(:user) }
- it_behaves_like 'admin mode on', true, :forbidden
- it_behaves_like 'admin mode on', false, :forbidden
+ it_behaves_like 'admin mode on', true, failed_status_code
+ it_behaves_like 'admin mode on', false, failed_status_code
end
-RSpec.shared_examples 'DELETE request permissions for admin mode when admin' do
+RSpec.shared_examples 'DELETE request permissions for admin mode when admin' do |success_status_code: :no_content,
+ failed_status_code: :forbidden|
+
subject { delete api(path, current_user, admin_mode: admin_mode) }
let_it_be(:current_user) { create(:admin) }
- it_behaves_like 'admin mode on', true, :no_content
- it_behaves_like 'admin mode on', false, :forbidden
+ it_behaves_like 'admin mode on', true, success_status_code
+ it_behaves_like 'admin mode on', false, failed_status_code
end
RSpec.shared_examples "admin mode on" do |admin_mode, status|
diff --git a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
index 6d29076da0f..66554f18e80 100644
--- a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
@@ -165,3 +165,29 @@ RSpec.shared_examples 'Debian packages write endpoint' do |desired_behavior, suc
it_behaves_like 'rejects Debian access with unknown container id', :unauthorized, :basic
end
+
+RSpec.shared_examples 'Debian packages index endpoint' do |success_body|
+ it_behaves_like 'Debian packages read endpoint', 'GET', :success, success_body
+
+ context 'when no ComponentFile is found' do
+ let(:target_component_name) { component.name + FFaker::Lorem.word }
+
+ it_behaves_like 'Debian packages read endpoint', 'GET', :no_content, /^$/
+ end
+end
+
+RSpec.shared_examples 'Debian packages index sha256 endpoint' do |success_body|
+ it_behaves_like 'Debian packages read endpoint', 'GET', :success, success_body
+
+ context 'with empty checksum' do
+ let(:target_sha256) { 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' }
+
+ it_behaves_like 'Debian packages read endpoint', 'GET', :no_content, /^$/
+ end
+
+ context 'when ComponentFile is not found' do
+ let(:target_component_name) { component.name + FFaker::Lorem.word }
+
+ it_behaves_like 'Debian packages read endpoint', 'GET', :not_found, /^{"message":"404 Not Found"}$/
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/discussions_shared_examples.rb b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
index f577e2ad323..a90fa06d458 100644
--- a/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
@@ -123,18 +123,6 @@ RSpec.shared_examples 'discussions API' do |parent_type, noteable_type, id_name,
expect_snowplow_event(category: 'Notes::CreateService', action: 'execute', label: 'note', value: anything)
end
- context 'with notes_create_service_tracking feature flag disabled' do
- before do
- stub_feature_flags(notes_create_service_tracking: false)
- end
-
- it 'does not track Notes::CreateService events', :snowplow do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), params: { body: 'hi!' }
-
- expect_no_snowplow_event(category: 'Notes::CreateService', action: 'execute')
- end
- end
-
context 'when an admin or owner makes the request' do
it 'accepts the creation date to be set' do
creation_time = 2.weeks.ago
diff --git a/spec/support/shared_examples/requests/api/hooks_shared_examples.rb b/spec/support/shared_examples/requests/api/hooks_shared_examples.rb
index f2002de4b55..797c5be802e 100644
--- a/spec/support/shared_examples/requests/api/hooks_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/hooks_shared_examples.rb
@@ -135,7 +135,7 @@ RSpec.shared_examples 'web-hook API endpoints' do |prefix|
context 'the hook is backed-off' do
before do
- WebHook::FAILURE_THRESHOLD.times { hook.backoff! }
+ WebHooks::AutoDisabling::FAILURE_THRESHOLD.times { hook.backoff! }
hook.backoff!
end
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 b55639a6b82..ace76b5ef84 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
@@ -507,55 +507,118 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project|
it_behaves_like 'returning response status', status
end
- shared_examples 'handling different package names, visibilities and user roles' do
- where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do
- :scoped_naming_convention | :public | :anonymous | :accept | :ok
- :scoped_naming_convention | :public | :guest | :accept | :ok
- :scoped_naming_convention | :public | :reporter | :accept | :ok
- :scoped_no_naming_convention | :public | :anonymous | :accept | :ok
- :scoped_no_naming_convention | :public | :guest | :accept | :ok
- :scoped_no_naming_convention | :public | :reporter | :accept | :ok
- :unscoped | :public | :anonymous | :accept | :ok
- :unscoped | :public | :guest | :accept | :ok
- :unscoped | :public | :reporter | :accept | :ok
- :non_existing | :public | :anonymous | :reject | :not_found
- :non_existing | :public | :guest | :reject | :not_found
- :non_existing | :public | :reporter | :reject | :not_found
-
- :scoped_naming_convention | :private | :anonymous | :reject | :not_found
- :scoped_naming_convention | :private | :guest | :reject | :forbidden
- :scoped_naming_convention | :private | :reporter | :accept | :ok
- :scoped_no_naming_convention | :private | :anonymous | :reject | :not_found
- :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
- :scoped_no_naming_convention | :private | :reporter | :accept | :ok
- :unscoped | :private | :anonymous | :reject | :not_found
- :unscoped | :private | :guest | :reject | :forbidden
- :unscoped | :private | :reporter | :accept | :ok
- :non_existing | :private | :anonymous | :reject | :not_found
- :non_existing | :private | :guest | :reject | :forbidden
- :non_existing | :private | :reporter | :reject | :not_found
-
- :scoped_naming_convention | :internal | :anonymous | :reject | :not_found
- :scoped_naming_convention | :internal | :guest | :accept | :ok
- :scoped_naming_convention | :internal | :reporter | :accept | :ok
- :scoped_no_naming_convention | :internal | :anonymous | :reject | :not_found
- :scoped_no_naming_convention | :internal | :guest | :accept | :ok
- :scoped_no_naming_convention | :internal | :reporter | :accept | :ok
- :unscoped | :internal | :anonymous | :reject | :not_found
- :unscoped | :internal | :guest | :accept | :ok
- :unscoped | :internal | :reporter | :accept | :ok
- :non_existing | :internal | :anonymous | :reject | :not_found
- :non_existing | :internal | :guest | :reject | :not_found
- :non_existing | :internal | :reporter | :reject | :not_found
+ shared_examples 'handling all conditions' do
+ where(:auth, :package_name_type, :visibility, :user_role, :expected_result, :expected_status) do
+ nil | :scoped_naming_convention | :public | nil | :accept | :ok
+ nil | :scoped_no_naming_convention | :public | nil | :accept | :ok
+ nil | :unscoped | :public | nil | :accept | :ok
+ nil | :non_existing | :public | nil | :reject | :not_found
+ nil | :scoped_naming_convention | :private | nil | :reject | :not_found
+ nil | :scoped_no_naming_convention | :private | nil | :reject | :not_found
+ nil | :unscoped | :private | nil | :reject | :not_found
+ nil | :non_existing | :private | nil | :reject | :not_found
+ nil | :scoped_naming_convention | :internal | nil | :reject | :not_found
+ nil | :scoped_no_naming_convention | :internal | nil | :reject | :not_found
+ nil | :unscoped | :internal | nil | :reject | :not_found
+ nil | :non_existing | :internal | nil | :reject | :not_found
+
+ :oauth | :scoped_naming_convention | :public | :guest | :accept | :ok
+ :oauth | :scoped_naming_convention | :public | :reporter | :accept | :ok
+ :oauth | :scoped_no_naming_convention | :public | :guest | :accept | :ok
+ :oauth | :scoped_no_naming_convention | :public | :reporter | :accept | :ok
+ :oauth | :unscoped | :public | :guest | :accept | :ok
+ :oauth | :unscoped | :public | :reporter | :accept | :ok
+ :oauth | :non_existing | :public | :guest | :reject | :not_found
+ :oauth | :non_existing | :public | :reporter | :reject | :not_found
+ :oauth | :scoped_naming_convention | :private | :guest | :reject | :forbidden
+ :oauth | :scoped_naming_convention | :private | :reporter | :accept | :ok
+ :oauth | :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
+ :oauth | :scoped_no_naming_convention | :private | :reporter | :accept | :ok
+ :oauth | :unscoped | :private | :guest | :reject | :forbidden
+ :oauth | :unscoped | :private | :reporter | :accept | :ok
+ :oauth | :non_existing | :private | :guest | :reject | :forbidden
+ :oauth | :non_existing | :private | :reporter | :reject | :not_found
+ :oauth | :scoped_naming_convention | :internal | :guest | :accept | :ok
+ :oauth | :scoped_naming_convention | :internal | :reporter | :accept | :ok
+ :oauth | :scoped_no_naming_convention | :internal | :guest | :accept | :ok
+ :oauth | :scoped_no_naming_convention | :internal | :reporter | :accept | :ok
+ :oauth | :unscoped | :internal | :guest | :accept | :ok
+ :oauth | :unscoped | :internal | :reporter | :accept | :ok
+ :oauth | :non_existing | :internal | :guest | :reject | :not_found
+ :oauth | :non_existing | :internal | :reporter | :reject | :not_found
+
+ :personal_access_token | :scoped_naming_convention | :public | :guest | :accept | :ok
+ :personal_access_token | :scoped_naming_convention | :public | :reporter | :accept | :ok
+ :personal_access_token | :scoped_no_naming_convention | :public | :guest | :accept | :ok
+ :personal_access_token | :scoped_no_naming_convention | :public | :reporter | :accept | :ok
+ :personal_access_token | :unscoped | :public | :guest | :accept | :ok
+ :personal_access_token | :unscoped | :public | :reporter | :accept | :ok
+ :personal_access_token | :non_existing | :public | :guest | :reject | :not_found
+ :personal_access_token | :non_existing | :public | :reporter | :reject | :not_found
+ :personal_access_token | :scoped_naming_convention | :private | :guest | :reject | :forbidden
+ :personal_access_token | :scoped_naming_convention | :private | :reporter | :accept | :ok
+ :personal_access_token | :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
+ :personal_access_token | :scoped_no_naming_convention | :private | :reporter | :accept | :ok
+ :personal_access_token | :unscoped | :private | :guest | :reject | :forbidden
+ :personal_access_token | :unscoped | :private | :reporter | :accept | :ok
+ :personal_access_token | :non_existing | :private | :guest | :reject | :forbidden
+ :personal_access_token | :non_existing | :private | :reporter | :reject | :not_found
+ :personal_access_token | :scoped_naming_convention | :internal | :guest | :accept | :ok
+ :personal_access_token | :scoped_naming_convention | :internal | :reporter | :accept | :ok
+ :personal_access_token | :scoped_no_naming_convention | :internal | :guest | :accept | :ok
+ :personal_access_token | :scoped_no_naming_convention | :internal | :reporter | :accept | :ok
+ :personal_access_token | :unscoped | :internal | :guest | :accept | :ok
+ :personal_access_token | :unscoped | :internal | :reporter | :accept | :ok
+ :personal_access_token | :non_existing | :internal | :guest | :reject | :not_found
+ :personal_access_token | :non_existing | :internal | :reporter | :reject | :not_found
+
+ :job_token | :scoped_naming_convention | :public | :developer | :accept | :ok
+ :job_token | :scoped_no_naming_convention | :public | :developer | :accept | :ok
+ :job_token | :unscoped | :public | :developer | :accept | :ok
+ :job_token | :non_existing | :public | :developer | :reject | :not_found
+ :job_token | :scoped_naming_convention | :private | :developer | :accept | :ok
+ :job_token | :scoped_no_naming_convention | :private | :developer | :accept | :ok
+ :job_token | :unscoped | :private | :developer | :accept | :ok
+ :job_token | :non_existing | :private | :developer | :reject | :not_found
+ :job_token | :scoped_naming_convention | :internal | :developer | :accept | :ok
+ :job_token | :scoped_no_naming_convention | :internal | :developer | :accept | :ok
+ :job_token | :unscoped | :internal | :developer | :accept | :ok
+ :job_token | :non_existing | :internal | :developer | :reject | :not_found
+
+ :deploy_token | :scoped_naming_convention | :public | nil | :accept | :ok
+ :deploy_token | :scoped_no_naming_convention | :public | nil | :accept | :ok
+ :deploy_token | :unscoped | :public | nil | :accept | :ok
+ :deploy_token | :non_existing | :public | nil | :reject | :not_found
+ :deploy_token | :scoped_naming_convention | :private | nil | :accept | :ok
+ :deploy_token | :scoped_no_naming_convention | :private | nil | :accept | :ok
+ :deploy_token | :unscoped | :private | nil | :accept | :ok
+ :deploy_token | :non_existing | :private | nil | :reject | :not_found
+ :deploy_token | :scoped_naming_convention | :internal | nil | :accept | :ok
+ :deploy_token | :scoped_no_naming_convention | :internal | nil | :accept | :ok
+ :deploy_token | :unscoped | :internal | nil | :accept | :ok
+ :deploy_token | :non_existing | :internal | nil | :reject | :not_found
end
with_them do
- let(:anonymous) { user_role == :anonymous }
+ let(:headers) do
+ case auth
+ when :oauth
+ build_token_auth_header(token.plaintext_token)
+ when :personal_access_token
+ build_token_auth_header(personal_access_token.token)
+ when :job_token
+ build_token_auth_header(job.token)
+ when :deploy_token
+ build_token_auth_header(deploy_token.token)
+ else
+ {}
+ end
+ end
- subject { get(url, headers: anonymous ? {} : headers) }
+ subject { get(url, headers: headers) }
before do
- project.send("add_#{user_role}", user) unless anonymous
+ project.send("add_#{user_role}", user) if user_role
project.update!(visibility: visibility.to_s)
end
@@ -571,20 +634,6 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project|
end
end
- shared_examples 'handling all conditions' do
- context 'with oauth token' do
- let(:headers) { build_token_auth_header(token.plaintext_token) }
-
- it_behaves_like 'handling different package names, visibilities and user roles'
- end
-
- context 'with personal access token' do
- let(:headers) { build_token_auth_header(personal_access_token.token) }
-
- it_behaves_like 'handling different package names, visibilities and user roles'
- end
- end
-
context 'with a group namespace' do
it_behaves_like 'handling all conditions'
end
@@ -599,7 +648,6 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project|
end
RSpec.shared_examples 'handling create dist tag requests' do |scope: :project|
- using RSpec::Parameterized::TableSyntax
include_context 'set package name from package name type'
let_it_be(:tag_name) { 'test' }
@@ -617,82 +665,10 @@ RSpec.shared_examples 'handling create dist tag requests' do |scope: :project|
it_behaves_like 'returning response status', status
end
- shared_examples 'handling different package names, visibilities and user roles' do
- where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do
- :scoped_naming_convention | :public | :anonymous | :reject | :forbidden
- :scoped_naming_convention | :public | :guest | :reject | :forbidden
- :scoped_naming_convention | :public | :developer | :accept | :ok
- :scoped_no_naming_convention | :public | :anonymous | :reject | :forbidden
- :scoped_no_naming_convention | :public | :guest | :reject | :forbidden
- :scoped_no_naming_convention | :public | :developer | :accept | :ok
- :unscoped | :public | :anonymous | :reject | :forbidden
- :unscoped | :public | :guest | :reject | :forbidden
- :unscoped | :public | :developer | :accept | :ok
- :non_existing | :public | :anonymous | :reject | :forbidden
- :non_existing | :public | :guest | :reject | :forbidden
- :non_existing | :public | :developer | :reject | :not_found
-
- :scoped_naming_convention | :private | :anonymous | :reject | :not_found
- :scoped_naming_convention | :private | :guest | :reject | :forbidden
- :scoped_naming_convention | :private | :developer | :accept | :ok
- :scoped_no_naming_convention | :private | :anonymous | :reject | :not_found
- :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
- :scoped_no_naming_convention | :private | :developer | :accept | :ok
- :unscoped | :private | :anonymous | :reject | :not_found
- :unscoped | :private | :guest | :reject | :forbidden
- :unscoped | :private | :developer | :accept | :ok
- :non_existing | :private | :anonymous | :reject | :not_found
- :non_existing | :private | :guest | :reject | :forbidden
- :non_existing | :private | :developer | :reject | :not_found
-
- :scoped_naming_convention | :internal | :anonymous | :reject | :forbidden
- :scoped_naming_convention | :internal | :guest | :reject | :forbidden
- :scoped_naming_convention | :internal | :developer | :accept | :ok
- :scoped_no_naming_convention | :internal | :anonymous | :reject | :forbidden
- :scoped_no_naming_convention | :internal | :guest | :reject | :forbidden
- :scoped_no_naming_convention | :internal | :developer | :accept | :ok
- :unscoped | :internal | :anonymous | :reject | :forbidden
- :unscoped | :internal | :guest | :reject | :forbidden
- :unscoped | :internal | :developer | :accept | :ok
- :non_existing | :internal | :anonymous | :reject | :forbidden
- :non_existing | :internal | :guest | :reject | :forbidden
- :non_existing | :internal | :developer | :reject | :not_found
- end
-
- with_them do
- let(:anonymous) { user_role == :anonymous }
-
- subject { put(url, env: env, headers: headers) }
-
- before do
- project.send("add_#{user_role}", user) unless anonymous
- project.update!(visibility: visibility.to_s)
- end
-
- example_name = "#{params[:expected_result]} create package tag request"
- status = params[:expected_status]
-
- if scope == :instance && params[:package_name_type] != :scoped_naming_convention
- example_name = 'reject create package tag request'
- status = :not_found
- end
-
- it_behaves_like example_name, status: status
- end
- end
-
shared_examples 'handling all conditions' do
- context 'with oauth token' do
- let(:headers) { build_token_auth_header(token.plaintext_token) }
+ subject { put(url, env: env, headers: headers) }
- it_behaves_like 'handling different package names, visibilities and user roles'
- end
-
- context 'with personal access token' do
- let(:headers) { build_token_auth_header(personal_access_token.token) }
-
- it_behaves_like 'handling different package names, visibilities and user roles'
- end
+ it_behaves_like 'handling different package names, visibilities and user roles for tags create or delete', action: :create, scope: scope
end
context 'with a group namespace' do
@@ -709,7 +685,6 @@ RSpec.shared_examples 'handling create dist tag requests' do |scope: :project|
end
RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project|
- using RSpec::Parameterized::TableSyntax
include_context 'set package name from package name type'
let_it_be(:package_tag) { create(:packages_tag, package: package) }
@@ -725,82 +700,10 @@ RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project|
it_behaves_like 'returning response status', status
end
- shared_examples 'handling different package names, visibilities and user roles' do
- where(:package_name_type, :visibility, :user_role, :expected_result, :expected_status) do
- :scoped_naming_convention | :public | :anonymous | :reject | :forbidden
- :scoped_naming_convention | :public | :guest | :reject | :forbidden
- :scoped_naming_convention | :public | :maintainer | :accept | :ok
- :scoped_no_naming_convention | :public | :anonymous | :reject | :forbidden
- :scoped_no_naming_convention | :public | :guest | :reject | :forbidden
- :scoped_no_naming_convention | :public | :maintainer | :accept | :ok
- :unscoped | :public | :anonymous | :reject | :forbidden
- :unscoped | :public | :guest | :reject | :forbidden
- :unscoped | :public | :maintainer | :accept | :ok
- :non_existing | :public | :anonymous | :reject | :forbidden
- :non_existing | :public | :guest | :reject | :forbidden
- :non_existing | :public | :maintainer | :reject | :not_found
-
- :scoped_naming_convention | :private | :anonymous | :reject | :not_found
- :scoped_naming_convention | :private | :guest | :reject | :forbidden
- :scoped_naming_convention | :private | :maintainer | :accept | :ok
- :scoped_no_naming_convention | :private | :anonymous | :reject | :not_found
- :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
- :scoped_no_naming_convention | :private | :maintainer | :accept | :ok
- :unscoped | :private | :anonymous | :reject | :not_found
- :unscoped | :private | :guest | :reject | :forbidden
- :unscoped | :private | :maintainer | :accept | :ok
- :non_existing | :private | :anonymous | :reject | :not_found
- :non_existing | :private | :guest | :reject | :forbidden
- :non_existing | :private | :maintainer | :reject | :not_found
-
- :scoped_naming_convention | :internal | :anonymous | :reject | :forbidden
- :scoped_naming_convention | :internal | :guest | :reject | :forbidden
- :scoped_naming_convention | :internal | :maintainer | :accept | :ok
- :scoped_no_naming_convention | :internal | :anonymous | :reject | :forbidden
- :scoped_no_naming_convention | :internal | :guest | :reject | :forbidden
- :scoped_no_naming_convention | :internal | :maintainer | :accept | :ok
- :unscoped | :internal | :anonymous | :reject | :forbidden
- :unscoped | :internal | :guest | :reject | :forbidden
- :unscoped | :internal | :maintainer | :accept | :ok
- :non_existing | :internal | :anonymous | :reject | :forbidden
- :non_existing | :internal | :guest | :reject | :forbidden
- :non_existing | :internal | :maintainer | :reject | :not_found
- end
-
- with_them do
- let(:anonymous) { user_role == :anonymous }
-
- subject { delete(url, headers: headers) }
-
- before do
- project.send("add_#{user_role}", user) unless anonymous
- project.update!(visibility: visibility.to_s)
- end
-
- example_name = "#{params[:expected_result]} delete package tag request"
- status = params[:expected_status]
-
- if scope == :instance && params[:package_name_type] != :scoped_naming_convention
- example_name = 'reject delete package tag request'
- status = :not_found
- end
-
- it_behaves_like example_name, status: status
- end
- end
-
shared_examples 'handling all conditions' do
- context 'with oauth token' do
- let(:headers) { build_token_auth_header(token.plaintext_token) }
-
- it_behaves_like 'handling different package names, visibilities and user roles'
- end
-
- context 'with personal access token' do
- let(:headers) { build_token_auth_header(personal_access_token.token) }
+ subject { delete(url, headers: headers) }
- it_behaves_like 'handling different package names, visibilities and user roles'
- end
+ it_behaves_like 'handling different package names, visibilities and user roles for tags create or delete', action: :delete, scope: scope
end
context 'with a group namespace' do
@@ -815,3 +718,141 @@ RSpec.shared_examples 'handling delete dist tag requests' do |scope: :project|
end
end
end
+
+RSpec.shared_examples 'handling different package names, visibilities and user roles for tags create or delete' do |action:, scope: :project|
+ using RSpec::Parameterized::TableSyntax
+
+ role = action == :create ? :developer : :maintainer
+
+ where(:auth, :package_name_type, :visibility, :user_role, :expected_result, :expected_status) do
+ :oauth | :scoped_naming_convention | :public | nil | :reject | :forbidden
+ :oauth | :scoped_naming_convention | :public | :guest | :reject | :forbidden
+ :oauth | :scoped_naming_convention | :public | role | :accept | :ok
+ :oauth | :scoped_no_naming_convention | :public | nil | :reject | :forbidden
+ :oauth | :scoped_no_naming_convention | :public | :guest | :reject | :forbidden
+ :oauth | :scoped_no_naming_convention | :public | role | :accept | :ok
+ :oauth | :unscoped | :public | nil | :reject | :forbidden
+ :oauth | :unscoped | :public | :guest | :reject | :forbidden
+ :oauth | :unscoped | :public | role | :accept | :ok
+ :oauth | :non_existing | :public | nil | :reject | :forbidden
+ :oauth | :non_existing | :public | :guest | :reject | :forbidden
+ :oauth | :non_existing | :public | role | :reject | :not_found
+ :oauth | :scoped_naming_convention | :private | nil | :reject | :not_found
+ :oauth | :scoped_naming_convention | :private | :guest | :reject | :forbidden
+ :oauth | :scoped_naming_convention | :private | role | :accept | :ok
+ :oauth | :scoped_no_naming_convention | :private | nil | :reject | :not_found
+ :oauth | :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
+ :oauth | :scoped_no_naming_convention | :private | role | :accept | :ok
+ :oauth | :unscoped | :private | nil | :reject | :not_found
+ :oauth | :unscoped | :private | :guest | :reject | :forbidden
+ :oauth | :unscoped | :private | role | :accept | :ok
+ :oauth | :non_existing | :private | nil | :reject | :not_found
+ :oauth | :non_existing | :private | :guest | :reject | :forbidden
+ :oauth | :non_existing | :private | role | :reject | :not_found
+ :oauth | :scoped_naming_convention | :internal | nil | :reject | :forbidden
+ :oauth | :scoped_naming_convention | :internal | :guest | :reject | :forbidden
+ :oauth | :scoped_naming_convention | :internal | role | :accept | :ok
+ :oauth | :scoped_no_naming_convention | :internal | nil | :reject | :forbidden
+ :oauth | :scoped_no_naming_convention | :internal | :guest | :reject | :forbidden
+ :oauth | :scoped_no_naming_convention | :internal | role | :accept | :ok
+ :oauth | :unscoped | :internal | nil | :reject | :forbidden
+ :oauth | :unscoped | :internal | :guest | :reject | :forbidden
+ :oauth | :unscoped | :internal | role | :accept | :ok
+ :oauth | :non_existing | :internal | nil | :reject | :forbidden
+ :oauth | :non_existing | :internal | :guest | :reject | :forbidden
+ :oauth | :non_existing | :internal | role | :reject | :not_found
+
+ :personal_access_token | :scoped_naming_convention | :public | nil | :reject | :forbidden
+ :personal_access_token | :scoped_naming_convention | :public | :guest | :reject | :forbidden
+ :personal_access_token | :scoped_naming_convention | :public | role | :accept | :ok
+ :personal_access_token | :scoped_no_naming_convention | :public | nil | :reject | :forbidden
+ :personal_access_token | :scoped_no_naming_convention | :public | :guest | :reject | :forbidden
+ :personal_access_token | :scoped_no_naming_convention | :public | role | :accept | :ok
+ :personal_access_token | :unscoped | :public | nil | :reject | :forbidden
+ :personal_access_token | :unscoped | :public | :guest | :reject | :forbidden
+ :personal_access_token | :unscoped | :public | role | :accept | :ok
+ :personal_access_token | :non_existing | :public | nil | :reject | :forbidden
+ :personal_access_token | :non_existing | :public | :guest | :reject | :forbidden
+ :personal_access_token | :non_existing | :public | role | :reject | :not_found
+ :personal_access_token | :scoped_naming_convention | :private | nil | :reject | :not_found
+ :personal_access_token | :scoped_naming_convention | :private | :guest | :reject | :forbidden
+ :personal_access_token | :scoped_naming_convention | :private | role | :accept | :ok
+ :personal_access_token | :scoped_no_naming_convention | :private | nil | :reject | :not_found
+ :personal_access_token | :scoped_no_naming_convention | :private | :guest | :reject | :forbidden
+ :personal_access_token | :scoped_no_naming_convention | :private | role | :accept | :ok
+ :personal_access_token | :unscoped | :private | nil | :reject | :not_found
+ :personal_access_token | :unscoped | :private | :guest | :reject | :forbidden
+ :personal_access_token | :unscoped | :private | role | :accept | :ok
+ :personal_access_token | :non_existing | :private | nil | :reject | :not_found
+ :personal_access_token | :non_existing | :private | :guest | :reject | :forbidden
+ :personal_access_token | :non_existing | :private | role | :reject | :not_found
+ :personal_access_token | :scoped_naming_convention | :internal | nil | :reject | :forbidden
+ :personal_access_token | :scoped_naming_convention | :internal | :guest | :reject | :forbidden
+ :personal_access_token | :scoped_naming_convention | :internal | role | :accept | :ok
+ :personal_access_token | :scoped_no_naming_convention | :internal | nil | :reject | :forbidden
+ :personal_access_token | :scoped_no_naming_convention | :internal | :guest | :reject | :forbidden
+ :personal_access_token | :scoped_no_naming_convention | :internal | role | :accept | :ok
+ :personal_access_token | :unscoped | :internal | nil | :reject | :forbidden
+ :personal_access_token | :unscoped | :internal | :guest | :reject | :forbidden
+ :personal_access_token | :unscoped | :internal | role | :accept | :ok
+ :personal_access_token | :non_existing | :internal | nil | :reject | :forbidden
+ :personal_access_token | :non_existing | :internal | :guest | :reject | :forbidden
+ :personal_access_token | :non_existing | :internal | role | :reject | :not_found
+
+ :job_token | :scoped_naming_convention | :public | role | :accept | :ok
+ :job_token | :scoped_no_naming_convention | :public | role | :accept | :ok
+ :job_token | :unscoped | :public | role | :accept | :ok
+ :job_token | :non_existing | :public | role | :reject | :not_found
+ :job_token | :scoped_naming_convention | :private | role | :accept | :ok
+ :job_token | :scoped_no_naming_convention | :private | role | :accept | :ok
+ :job_token | :unscoped | :private | role | :accept | :ok
+ :job_token | :non_existing | :private | role | :reject | :not_found
+ :job_token | :scoped_naming_convention | :internal | role | :accept | :ok
+ :job_token | :scoped_no_naming_convention | :internal | role | :accept | :ok
+ :job_token | :unscoped | :internal | role | :accept | :ok
+ :job_token | :non_existing | :internal | role | :reject | :not_found
+
+ :deploy_token | :scoped_naming_convention | :public | nil | :accept | :ok
+ :deploy_token | :scoped_no_naming_convention | :public | nil | :accept | :ok
+ :deploy_token | :unscoped | :public | nil | :accept | :ok
+ :deploy_token | :non_existing | :public | nil | :reject | :not_found
+ :deploy_token | :scoped_naming_convention | :private | nil | :accept | :ok
+ :deploy_token | :scoped_no_naming_convention | :private | nil | :accept | :ok
+ :deploy_token | :unscoped | :private | nil | :accept | :ok
+ :deploy_token | :non_existing | :private | nil | :reject | :not_found
+ :deploy_token | :scoped_naming_convention | :internal | nil | :accept | :ok
+ :deploy_token | :scoped_no_naming_convention | :internal | nil | :accept | :ok
+ :deploy_token | :unscoped | :internal | nil | :accept | :ok
+ :deploy_token | :non_existing | :internal | nil | :reject | :not_found
+ end
+
+ with_them do
+ let(:headers) do
+ case auth
+ when :oauth
+ build_token_auth_header(token.plaintext_token)
+ when :personal_access_token
+ build_token_auth_header(personal_access_token.token)
+ when :job_token
+ build_token_auth_header(job.token)
+ when :deploy_token
+ build_token_auth_header(deploy_token.token)
+ end
+ end
+
+ before do
+ project.send("add_#{user_role}", user) if user_role
+ project.update!(visibility: visibility.to_s)
+ end
+
+ example_name = "#{params[:expected_result]} #{action} package tag request"
+ status = params[:expected_status]
+
+ if scope == :instance && params[:package_name_type] != :scoped_naming_convention
+ example_name = "reject #{action} package tag request"
+ status = :not_found
+ end
+
+ it_behaves_like example_name, status: status
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb b/spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb
index 17d8b9c7fab..7cafe8bb368 100644
--- a/spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/nuget_endpoints_shared_examples.rb
@@ -36,6 +36,7 @@ RSpec.shared_examples 'handling nuget service requests' do |example_names_with_s
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
subject { get api(url), headers: headers }
@@ -72,6 +73,7 @@ RSpec.shared_examples 'handling nuget service requests' do |example_names_with_s
with_them do
let(:job) { user_token ? create(:ci_build, project: project, user: user, status: :running) : double(token: 'wrong') }
let(:headers) { user_role == :anonymous ? {} : job_basic_auth_header(job) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
subject { get api(url), headers: headers }
@@ -140,6 +142,7 @@ RSpec.shared_examples 'handling nuget metadata requests with package name' do |e
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
subject { get api(url), headers: headers }
@@ -207,6 +210,7 @@ RSpec.shared_examples 'handling nuget metadata requests with package name and pa
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
subject { get api(url), headers: headers }
@@ -277,6 +281,7 @@ RSpec.shared_examples 'handling nuget search requests' do |example_names_with_st
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+ let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
subject { get api(url), headers: headers }
diff --git a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
index 6065b1163c4..9bd430c3b4f 100644
--- a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
@@ -254,6 +254,13 @@ RSpec.shared_examples 'pypi simple API endpoint' do
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+ let(:snowplow_gitlab_standard_context) do
+ if user_role == :anonymous || (visibility_level == :public && !user_token)
+ snowplow_context
+ else
+ snowplow_context.merge(user: user)
+ end
+ end
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
@@ -269,7 +276,7 @@ RSpec.shared_examples 'pypi simple API endpoint' do
let(:url) { "/projects/#{project.id}/packages/pypi/simple/my-package" }
let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: group, property: 'i_package_pypi_user' } }
+ let(:snowplow_gitlab_standard_context) { snowplow_context.merge({ project: project, user: user }) }
it_behaves_like 'PyPI package versions', :developer, :success
end
diff --git a/spec/support/shared_examples/requests/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb
index 40843ccbd15..fad5211fc59 100644
--- a/spec/support/shared_examples/requests/api/status_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb
@@ -21,6 +21,23 @@ RSpec.shared_examples '400 response' do
end
end
+RSpec.shared_examples '401 response' do
+ let(:message) { nil }
+
+ before do
+ # Fires the request
+ request
+ end
+
+ it 'returns 401' do
+ expect(response).to have_gitlab_http_status(:unauthorized)
+
+ if message.present?
+ expect(json_response['message']).to eq(message)
+ end
+ end
+end
+
RSpec.shared_examples '403 response' do
before do
# Fires the request
diff --git a/spec/support/shared_examples/requests/applications_controller_shared_examples.rb b/spec/support/shared_examples/requests/applications_controller_shared_examples.rb
index 642930dd982..4a7a7492398 100644
--- a/spec/support/shared_examples/requests/applications_controller_shared_examples.rb
+++ b/spec/support/shared_examples/requests/applications_controller_shared_examples.rb
@@ -7,40 +7,14 @@ RSpec.shared_examples 'applications controller - GET #show' do
expect(response).to render_template :show
end
-
- context 'when application is viewed after being created' do
- before do
- create_application
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'sets `@created` instance variable to `true`' do
- get show_path
-
- expect(assigns[:created]).to eq(true)
- end
- end
-
- context 'when application is reviewed' do
- before do
- stub_feature_flags(hash_oauth_secrets: false)
- end
-
- it 'sets `@created` instance variable to `false`' do
- get show_path
-
- expect(assigns[:created]).to eq(false)
- end
- end
end
end
RSpec.shared_examples 'applications controller - POST #create' do
- it "sets `#{OauthApplications::CREATED_SESSION_KEY}` session key to `true`" do
- stub_feature_flags(hash_oauth_secrets: false)
+ it "sets `@created` instance variable to `true`" do
create_application
- expect(session[OauthApplications::CREATED_SESSION_KEY]).to eq(true)
+ expect(assigns[:created]).to eq(true)
end
end
diff --git a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
index a3042ac2e26..5abdac07431 100644
--- a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
+++ b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
@@ -29,26 +29,76 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
let_it_be(:architecture_amd64) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'amd64') }
let_it_be(:architecture_arm64) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'arm64') }
- let_it_be(:component_file1) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_all, updated_at: '2020-01-24T08:00:00Z', file_sha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', file_md5: 'd41d8cd98f00b204e9800998ecf8427e', file_fixture: nil, size: 0) } # updated
- let_it_be(:component_file2) { create("debian_#{container_type}_component_file", component: component_main, architecture: architecture_all, updated_at: '2020-01-24T09:00:00Z', file_sha256: 'a') } # destroyed
- let_it_be(:component_file3) { create("debian_#{container_type}_component_file", component: component_main, architecture: architecture_amd64, updated_at: '2020-01-24T10:54:59Z', file_sha256: 'b') } # destroyed, 1 second before last generation
- let_it_be(:component_file4) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_all, updated_at: '2020-01-24T10:55:00Z', file_sha256: 'c') } # kept, last generation
- let_it_be(:component_file5) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_all, updated_at: '2020-01-24T10:55:00Z', file_sha256: 'd') } # kept, last generation
- let_it_be(:component_file6) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_amd64, updated_at: '2020-01-25T15:17:18Z', file_sha256: 'e') } # kept, less than 1 hour ago
-
- def check_component_file(release_date, component_name, component_file_type, architecture_name, expected_content)
+ let_it_be(:component_file_old_main_amd64) { create("debian_#{container_type}_component_file", component: component_main, architecture: architecture_amd64, updated_at: '2020-01-24T08:00:00Z', file_sha256: 'a') } # destroyed
+
+ let_it_be(:component_file_oldest_kept_contrib_all) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_all, updated_at: '2020-01-24T10:55:00Z', file_sha256: 'b') } # oldest kept
+ let_it_be(:component_file_oldest_kept_contrib_amd64) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_amd64, updated_at: '2020-01-24T10:55:00Z', file_sha256: 'c') } # oldest kept
+ let_it_be(:component_file_recent_contrib_amd64) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_amd64, updated_at: '2020-01-25T15:17:18Z', file_sha256: 'd') } # kept, less than 1 hour ago
+
+ let_it_be(:component_file_empty_contrib_all_di) { create("debian_#{container_type}_component_file", :di_packages, :empty, component: component_contrib, architecture: architecture_all, updated_at: '2020-01-24T10:55:00Z') } # oldest kept
+ let_it_be(:component_file_empty_contrib_amd64_di) { create("debian_#{container_type}_component_file", :di_packages, :empty, component: component_contrib, architecture: architecture_amd64, updated_at: '2020-01-24T10:55:00Z') } # touched, as last empty
+ let_it_be(:component_file_recent_contrib_amd64_di) { create("debian_#{container_type}_component_file", :di_packages, component: component_contrib, architecture: architecture_amd64, updated_at: '2020-01-25T15:17:18Z', file_sha256: 'f') } # kept, less than 1 hour ago
+
+ let(:pool_prefix) do
+ prefix = "pool/#{distribution.codename}"
+ prefix += "/#{project.id}" if container_type == :group
+ prefix += "/#{package.name[0]}/#{package.name}/#{package.version}"
+ prefix
+ end
+
+ let(:expected_main_amd64_di_content) do
+ <<~MAIN_AMD64_DI_CONTENT
+ Section: misc
+ Priority: extra
+ Filename: #{pool_prefix}/sample-udeb_1.2.3~alpha2_amd64.udeb
+ Size: 409600
+ SHA256: #{package.package_files.with_debian_file_type(:udeb).first.file_sha256}
+ MAIN_AMD64_DI_CONTENT
+ end
+
+ let(:expected_main_amd64_di_sha256) { Digest::SHA256.hexdigest(expected_main_amd64_di_content) }
+ let!(:component_file_old_main_amd64_di) do # touched
+ create("debian_#{container_type}_component_file", :di_packages, component: component_main, architecture: architecture_amd64, updated_at: '2020-01-24T08:00:00Z', file_sha256: expected_main_amd64_di_sha256).tap do |cf|
+ cf.update! file: CarrierWaveStringFile.new(expected_main_amd64_di_content), size: expected_main_amd64_di_content.size
+ end
+ end
+
+ def check_component_file(
+ release_date, component_name, component_file_type, architecture_name, expected_content,
+ updated: true, id_of: nil
+ )
component_file = distribution
.component_files
.with_component_name(component_name)
.with_file_type(component_file_type)
.with_architecture_name(architecture_name)
+ .with_compression_type(nil)
.order_updated_asc
.last
+ if expected_content.nil?
+ expect(component_file).to be_nil
+ return
+ end
+
expect(component_file).not_to be_nil
- expect(component_file.updated_at).to eq(release_date)
- unless expected_content.nil?
+ if id_of
+ expect(component_file&.id).to eq(id_of.id)
+ else
+ # created
+ expect(component_file&.id).to be > component_file_old_main_amd64_di.id
+ end
+
+ if updated
+ expect(component_file.updated_at).to eq(release_date)
+ else
+ expect(component_file.updated_at).not_to eq(release_date)
+ end
+
+ if expected_content == ''
+ expect(component_file.size).to eq(0)
+ else
expect(expected_content).not_to include('MD5')
component_file.file.use_file do |file_path|
expect(File.read(file_path)).to eq(expected_content)
@@ -57,30 +107,23 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
end
it 'generates Debian distribution and component files', :aggregate_failures do
- current_time = Time.utc(2020, 01, 25, 15, 17, 18, 123456)
+ current_time = Time.utc(2020, 1, 25, 15, 17, 19)
travel_to(current_time) do
expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
- components_count = 2
- architectures_count = 3
-
- initial_count = 6
- destroyed_count = 2
- updated_count = 1
- created_count = components_count * (architectures_count * 2 + 1) - updated_count
+ initial_count = 8
+ destroyed_count = 1
+ created_count = 4 # main_amd64 + main_sources + empty contrib_all + empty contrib_amd64
expect { subject }
.to not_change { Packages::Package.count }
.and not_change { Packages::PackageFile.count }
.and change { distribution.reload.updated_at }.to(current_time.round)
.and change { distribution.component_files.reset.count }.from(initial_count).to(initial_count - destroyed_count + created_count)
- .and change { component_file1.reload.updated_at }.to(current_time.round)
+ .and change { component_file_old_main_amd64_di.reload.updated_at }.to(current_time.round)
package_files = package.package_files.order(id: :asc).preload_debian_file_metadata.to_a
- pool_prefix = "pool/#{distribution.codename}"
- pool_prefix += "/#{project.id}" if container_type == :group
- pool_prefix += "/#{package.name[0]}/#{package.name}/#{package.version}"
expected_main_amd64_content = <<~EOF
Package: libsample0
Source: #{package.name}
@@ -120,17 +163,9 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
SHA256: #{package_files[3].file_sha256}
EOF
- expected_main_amd64_di_content = <<~EOF
- Section: misc
- Priority: extra
- Filename: #{pool_prefix}/sample-udeb_1.2.3~alpha2_amd64.udeb
- Size: 409600
- SHA256: #{package_files[4].file_sha256}
- EOF
-
expected_main_sources_content = <<~EOF
Package: #{package.name}
- Binary: sample-dev, libsample0, sample-udeb
+ Binary: sample-dev, libsample0, sample-udeb, sample-ddeb
Version: #{package.version}
Maintainer: #{package_files[1].debian_fields['Maintainer']}
Build-Depends: debhelper-compat (= 13)
@@ -139,13 +174,13 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
Format: 3.0 (native)
Files:
#{package_files[1].file_md5} #{package_files[1].size} #{package_files[1].file_name}
- d5ca476e4229d135a88f9c729c7606c9 864 sample_1.2.3~alpha2.tar.xz
+ #{package_files[0].file_md5} 964 #{package_files[0].file_name}
Checksums-Sha256:
#{package_files[1].file_sha256} #{package_files[1].size} #{package_files[1].file_name}
- 40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da 864 sample_1.2.3~alpha2.tar.xz
+ #{package_files[0].file_sha256} 964 #{package_files[0].file_name}
Checksums-Sha1:
#{package_files[1].file_sha1} #{package_files[1].size} #{package_files[1].file_name}
- c5cfc111ea924842a89a06d5673f07dfd07de8ca 864 sample_1.2.3~alpha2.tar.xz
+ #{package_files[0].file_sha1} 964 #{package_files[0].file_name}
Homepage: #{package_files[1].debian_fields['Homepage']}
Section: misc
Priority: extra
@@ -157,42 +192,38 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
check_component_file(current_time.round, 'main', :packages, 'arm64', nil)
check_component_file(current_time.round, 'main', :di_packages, 'all', nil)
- check_component_file(current_time.round, 'main', :di_packages, 'amd64', expected_main_amd64_di_content)
+ check_component_file(current_time.round, 'main', :di_packages, 'amd64', expected_main_amd64_di_content, id_of: component_file_old_main_amd64_di)
check_component_file(current_time.round, 'main', :di_packages, 'arm64', nil)
check_component_file(current_time.round, 'main', :sources, nil, expected_main_sources_content)
- check_component_file(current_time.round, 'contrib', :packages, 'all', nil)
- check_component_file(current_time.round, 'contrib', :packages, 'amd64', nil)
+ check_component_file(current_time.round, 'contrib', :packages, 'all', '')
+ check_component_file(current_time.round, 'contrib', :packages, 'amd64', '')
check_component_file(current_time.round, 'contrib', :packages, 'arm64', nil)
- check_component_file(current_time.round, 'contrib', :di_packages, 'all', nil)
- check_component_file(current_time.round, 'contrib', :di_packages, 'amd64', nil)
+ check_component_file(current_time.round, 'contrib', :di_packages, 'all', '', updated: false, id_of: component_file_empty_contrib_all_di)
+ check_component_file(current_time.round, 'contrib', :di_packages, 'amd64', '', id_of: component_file_empty_contrib_amd64_di)
check_component_file(current_time.round, 'contrib', :di_packages, 'arm64', nil)
check_component_file(current_time.round, 'contrib', :sources, nil, nil)
- main_amd64_size = expected_main_amd64_content.length
- main_amd64_sha256 = Digest::SHA256.hexdigest(expected_main_amd64_content)
+ expected_main_amd64_size = expected_main_amd64_content.length
+ expected_main_amd64_sha256 = Digest::SHA256.hexdigest(expected_main_amd64_content)
- contrib_all_size = component_file1.size
- contrib_all_sha256 = component_file1.file_sha256
+ expected_main_amd64_di_size = expected_main_amd64_di_content.length
- main_amd64_di_size = expected_main_amd64_di_content.length
- main_amd64_di_sha256 = Digest::SHA256.hexdigest(expected_main_amd64_di_content)
-
- main_sources_size = expected_main_sources_content.length
- main_sources_sha256 = Digest::SHA256.hexdigest(expected_main_sources_content)
+ expected_main_sources_size = expected_main_sources_content.length
+ expected_main_sources_sha256 = Digest::SHA256.hexdigest(expected_main_sources_content)
expected_release_content = <<~EOF
Codename: #{distribution.codename}
- Date: Sat, 25 Jan 2020 15:17:18 +0000
- Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
+ Date: Sat, 25 Jan 2020 15:17:19 +0000
+ Valid-Until: Mon, 27 Jan 2020 15:17:19 +0000
Acquire-By-Hash: yes
Architectures: all amd64 arm64
Components: contrib main
SHA256:
- #{contrib_all_sha256} #{contrib_all_size.to_s.rjust(8)} contrib/binary-all/Packages
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-all/Packages
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-all/Packages
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-amd64/Packages
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-amd64/Packages
@@ -201,11 +232,11 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/source/Sources
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-all/Packages
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/debian-installer/binary-all/Packages
- #{main_amd64_sha256} #{main_amd64_size.to_s.rjust(8)} main/binary-amd64/Packages
- #{main_amd64_di_sha256} #{main_amd64_di_size.to_s.rjust(8)} main/debian-installer/binary-amd64/Packages
+ #{expected_main_amd64_sha256} #{expected_main_amd64_size.to_s.rjust(8)} main/binary-amd64/Packages
+ #{expected_main_amd64_di_sha256} #{expected_main_amd64_di_size.to_s.rjust(8)} main/debian-installer/binary-amd64/Packages
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-arm64/Packages
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/debian-installer/binary-arm64/Packages
- #{main_sources_sha256} #{main_sources_size.to_s.rjust(8)} main/source/Sources
+ #{expected_main_sources_sha256} #{expected_main_sources_size.to_s.rjust(8)} main/source/Sources
EOF
expected_release_content = "Suite: #{distribution.suite}\n#{expected_release_content}" if distribution.suite
@@ -222,7 +253,7 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
context 'without components and architectures' do
it 'generates minimal distribution', :aggregate_failures do
- travel_to(Time.utc(2020, 01, 25, 15, 17, 18, 123456)) do
+ travel_to(Time.utc(2020, 1, 25, 15, 17, 18, 123456)) do
expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
expect { subject }
diff --git a/spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb b/spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb
index 9f940d27341..2070cac24b0 100644
--- a/spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/projects/update_repository_storage_service_shared_examples.rb
@@ -63,35 +63,6 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type|
expect(gitlab_shell.repository_exists?('default', old_project_repository_path)).to be(false)
expect(gitlab_shell.repository_exists?('default', old_repository_path)).to be(false)
end
-
- context ':repack_after_shard_migration feature flag disabled' do
- before do
- stub_feature_flags(repack_after_shard_migration: false)
- end
-
- it 'does not enqueue a GC run' do
- expect { subject.execute }
- .not_to change { Projects::GitGarbageCollectWorker.jobs.count }
- end
- end
-
- context ':repack_after_shard_migration feature flag enabled' do
- before do
- stub_feature_flags(repack_after_shard_migration: true)
- end
-
- it 'does not enqueue a GC run if housekeeping is disabled' do
- stub_application_setting(housekeeping_enabled: false)
-
- expect { subject.execute }
- .not_to change { Projects::GitGarbageCollectWorker.jobs.count }
- end
-
- it 'enqueues a GC run' do
- expect { subject.execute }
- .to change { Projects::GitGarbageCollectWorker.jobs.count }.by(1)
- end
- end
end
context 'when the filesystems are the same' do
diff --git a/spec/support/shared_examples/services/security/ci_configuration/create_service_shared_examples.rb b/spec/support/shared_examples/services/security/ci_configuration/create_service_shared_examples.rb
index 209be09c807..9fcdd296ebe 100644
--- a/spec/support/shared_examples/services/security/ci_configuration/create_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/security/ci_configuration/create_service_shared_examples.rb
@@ -145,7 +145,7 @@ RSpec.shared_examples_for 'services security ci configuration create service' do
let_it_be(:repository) { project.repository }
it 'is successful' do
- expect(repository).to receive(:root_ref_sha).and_raise(StandardError)
+ expect(repository).to receive(:commit).and_return(nil)
expect(result.status).to eq(:success)
end
end
@@ -168,7 +168,7 @@ RSpec.shared_examples_for 'services security ci configuration create service' do
it 'returns an error' do
expect { result }.to raise_error { |error|
expect(error).to be_a(Gitlab::Graphql::Errors::MutationError)
- expect(error.message).to eq('You must <a target="_blank" rel="noopener noreferrer" ' \
+ expect(error.message).to eq('UF: You must <a target="_blank" rel="noopener noreferrer" ' \
'href="http://localhost/help/user/project/repository/index.md' \
'#add-files-to-a-repository">add at least one file to the repository' \
'</a> before using Security features.')
diff --git a/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb b/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
index e72e8e79411..d3b3434b339 100644
--- a/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
+++ b/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb
@@ -5,7 +5,6 @@ RSpec.shared_examples 'issue_edit snowplow tracking' do
let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_ACTION }
let(:label) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_LABEL }
let(:namespace) { project.namespace }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
it_behaves_like 'Snowplow event tracking with RedisHLL context'
end
diff --git a/spec/support/stub_dot_com_check.rb b/spec/support/stub_dot_com_check.rb
new file mode 100644
index 00000000000..6934b33d111
--- /dev/null
+++ b/spec/support/stub_dot_com_check.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+RSpec.configure do |config|
+ %i[saas saas_registration].each do |metadata|
+ config.before(:context, metadata) do
+ # Ensure Gitlab.com? returns true during context.
+ # This is needed for let_it_be which is shared across examples,
+ # therefore the value must be changed in before_all,
+ # but RSpec prevent stubbing method calls in before_all,
+ # therefore we have to resort to temporarily swap url value.
+ @_original_gitlab_url = Gitlab.config.gitlab['url']
+ Gitlab.config.gitlab['url'] = Gitlab::Saas.com_url
+ end
+
+ config.after(:context, metadata) do
+ # Swap back original value
+ Gitlab.config.gitlab['url'] = @_original_gitlab_url
+ end
+ end
+end
diff --git a/spec/support_specs/ability_check_spec.rb b/spec/support_specs/ability_check_spec.rb
new file mode 100644
index 00000000000..ce841112d86
--- /dev/null
+++ b/spec/support_specs/ability_check_spec.rb
@@ -0,0 +1,148 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+require 'declarative_policy'
+require 'request_store'
+require 'tempfile'
+
+require 'gitlab/safe_request_store'
+
+require_relative '../../app/models/ability'
+require_relative '../support/ability_check'
+
+RSpec.describe Support::AbilityCheck, feature_category: :system_access do # rubocop:disable RSpec/FilePath
+ let(:user) { :user }
+ let(:child) { Testing::Child.new }
+ let(:parent) { Testing::Parent.new(child) }
+
+ before do
+ # Usually done in spec/spec_helper.
+ described_class.inject(Ability.singleton_class)
+
+ stub_const('Testing::BasePolicy', Class.new(DeclarativePolicy::Base))
+
+ stub_const('Testing::Parent', Struct.new(:parent_of))
+ stub_const('Testing::ParentPolicy', Class.new(Testing::BasePolicy) do
+ delegate { @subject.parent_of }
+ condition(:is_adult) { @subject.is_a?(Testing::Parent) }
+ rule { is_adult }.enable :drink_coffee
+ end)
+
+ stub_const('Testing::Child', Class.new)
+ stub_const('Testing::ChildPolicy', Class.new(Testing::BasePolicy) do
+ condition(:always) { true }
+ rule { always }.enable :eat_ice
+ end)
+ end
+
+ def expect_no_deprecation_warning(&block)
+ expect(&block).not_to output.to_stderr
+ end
+
+ def expect_deprecation_warning(policy_class, ability, &block)
+ expect(&block)
+ .to output(/DEPRECATION WARNING: Ability :#{ability} in #{policy_class} not found./)
+ .to_stderr
+ end
+
+ def expect_allowed(user, ability, subject)
+ expect(Ability.allowed?(user, ability, subject))
+ end
+
+ shared_examples 'ability found' do
+ it 'policy ability is found' do
+ expect_no_deprecation_warning do
+ expect_allowed(user, ability, subject).to eq(true)
+ end
+ end
+ end
+
+ shared_examples 'ability not found' do |warning:|
+ description = 'policy ability is not found'
+ description += warning ? ' and emits a warning' : ' without warning'
+
+ it description do
+ check = -> { expect_allowed(user, ability, subject).to eq(false) }
+
+ if warning
+ expect_deprecation_warning(warning, ability, &check)
+ else
+ expect_no_deprecation_warning(&check)
+ end
+ end
+ end
+
+ shared_context 'with custom TODO YAML' do
+ let(:yaml_file) { Tempfile.new }
+
+ before do
+ yaml_file.write(yaml_content)
+ yaml_file.rewind
+
+ stub_const("#{described_class}::Checker::TODO_YAML", yaml_file.path)
+ described_class::Checker.clear_memoization(:todo_list)
+ end
+
+ after do
+ described_class::Checker.clear_memoization(:todo_list)
+ yaml_file.unlink
+ end
+ end
+
+ describe 'checking ability' do
+ context 'with valid direct ability' do
+ let(:subject) { parent }
+ let(:ability) { :drink_coffee }
+
+ include_examples 'ability found'
+
+ context 'with empty TODO yaml' do
+ let(:yaml_content) { nil }
+
+ include_context 'with custom TODO YAML'
+ include_examples 'ability found'
+ end
+
+ context 'with non-Hash TODO yaml' do
+ let(:yaml_content) { '[]' }
+
+ include_context 'with custom TODO YAML'
+ include_examples 'ability found'
+ end
+ end
+
+ context 'with unreachable ability' do
+ let(:subject) { child }
+ let(:ability) { :drink_coffee }
+
+ include_examples 'ability not found', warning: 'Testing::ChildPolicy'
+
+ context 'when ignored in TODO YAML' do
+ let(:yaml_content) do
+ <<~YAML
+ Testing::ChildPolicy:
+ - #{ability}
+ YAML
+ end
+
+ include_context 'with custom TODO YAML'
+ include_examples 'ability not found', warning: false
+ end
+ end
+
+ context 'with unknown ability' do
+ let(:subject) { parent }
+ let(:ability) { :unknown }
+
+ include_examples 'ability not found', warning: 'Testing::ParentPolicy'
+ end
+
+ context 'with delegated ability' do
+ let(:subject) { parent }
+ let(:ability) { :eat_ice }
+
+ include_examples 'ability found'
+ end
+ end
+end
diff --git a/spec/support_specs/helpers/packages/npm_spec.rb b/spec/support_specs/helpers/packages/npm_spec.rb
new file mode 100644
index 00000000000..e1316a10fb1
--- /dev/null
+++ b/spec/support_specs/helpers/packages/npm_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::API::Helpers::Packages::Npm, feature_category: :package_registry do # rubocop: disable RSpec/FilePath
+ let(:object) { klass.new(params) }
+ let(:klass) do
+ Struct.new(:params) do
+ include ::API::Helpers
+ include ::API::Helpers::Packages::Npm
+ end
+ end
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:namespace) { group }
+ let_it_be(:project) { create(:project, :public, namespace: namespace) }
+ let_it_be(:package) { create(:npm_package, project: project) }
+
+ describe '#endpoint_scope' do
+ subject { object.endpoint_scope }
+
+ context 'when params includes an id' do
+ let(:params) { { id: 42, package_name: 'foo' } }
+
+ it { is_expected.to eq(:project) }
+ end
+
+ context 'when params does not include an id' do
+ let(:params) { { package_name: 'foo' } }
+
+ it { is_expected.to eq(:instance) }
+ end
+ end
+
+ describe '#finder_for_endpoint_scope' do
+ subject { object.finder_for_endpoint_scope(package_name) }
+
+ let(:package_name) { package.name }
+
+ context 'when called with project scope' do
+ let(:params) { { id: project.id } }
+
+ it 'returns a PackageFinder for project scope' do
+ expect(::Packages::Npm::PackageFinder).to receive(:new).with(package_name, project: project)
+
+ subject
+ end
+ end
+
+ context 'when called with instance scope' do
+ let(:params) { { package_name: package_name } }
+
+ it 'returns a PackageFinder for namespace scope' do
+ expect(::Packages::Npm::PackageFinder).to receive(:new).with(package_name, namespace: group)
+
+ subject
+ end
+ end
+ end
+
+ describe '#project_id_or_nil' do
+ subject { object.project_id_or_nil }
+
+ context 'when called with project scope' do
+ let(:params) { { id: project.id } }
+
+ it { is_expected.to eq(project.id) }
+ end
+
+ context 'when called with namespace scope' do
+ context 'when given an unscoped name' do
+ let(:params) { { package_name: 'foo' } }
+
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'when given a scope that does not match a group name' do
+ let(:params) { { package_name: '@nonexistent-group/foo' } }
+
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'when given a scope that matches a group name' do
+ let(:params) { { package_name: package.name } }
+
+ it { is_expected.to eq(project.id) }
+
+ context 'with another package with the same name, in another project in the namespace' do
+ let_it_be(:project2) { create(:project, :public, namespace: namespace) }
+ let_it_be(:package2) { create(:npm_package, name: package.name, project: project2) }
+
+ it 'returns the project id for the newest matching package within the scope' do
+ expect(subject).to eq(project2.id)
+ end
+ end
+ end
+
+ context 'with npm_allow_packages_in_multiple_projects disabled' do
+ before do
+ stub_feature_flags(npm_allow_packages_in_multiple_projects: false)
+ end
+
+ context 'when given an unscoped name' do
+ let(:params) { { package_name: 'foo' } }
+
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'when given a scope that does not match a group name' do
+ let(:params) { { package_name: '@nonexistent-group/foo' } }
+
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'when given a scope that matches a group name' do
+ let(:params) { { package_name: package.name } }
+
+ it { is_expected.to eq(project.id) }
+
+ context 'with another package with the same name, in another project in the namespace' do
+ let_it_be(:project2) { create(:project, :public, namespace: namespace) }
+ let_it_be(:package2) { create(:npm_package, name: package.name, project: project2) }
+
+ it 'returns the project id for the newest matching package within the scope' do
+ expect(subject).to eq(project2.id)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support_specs/matchers/exceed_redis_call_limit_spec.rb b/spec/support_specs/matchers/exceed_redis_call_limit_spec.rb
new file mode 100644
index 00000000000..819f50e26b6
--- /dev/null
+++ b/spec/support_specs/matchers/exceed_redis_call_limit_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'RedisCommand matchers', :use_clean_rails_redis_caching, feature_category: :source_code_management do
+ let(:control) do
+ RedisCommands::Recorder.new do
+ Rails.cache.read('test')
+ Rails.cache.read('test')
+ Rails.cache.write('test', 1)
+ end
+ end
+
+ before do
+ Rails.cache.read('warmup')
+ end
+
+ it 'verifies maximum number of Redis calls' do
+ expect(control).not_to exceed_redis_calls_limit(3)
+
+ expect(control).not_to exceed_redis_command_calls_limit(:get, 2)
+ expect(control).not_to exceed_redis_command_calls_limit(:set, 1)
+ end
+
+ it 'verifies minimum number of Redis calls' do
+ expect(control).to exceed_redis_calls_limit(2)
+
+ expect(control).to exceed_redis_command_calls_limit(:get, 1)
+ expect(control).to exceed_redis_command_calls_limit(:set, 0)
+ end
+
+ context 'with Recorder matching only some Redis calls' do
+ it 'counts only Redis calls captured by Recorder' do
+ Rails.cache.write('ignored', 1)
+
+ control = RedisCommands::Recorder.new do
+ Rails.cache.read('recorded')
+ end
+
+ Rails.cache.write('also_ignored', 1)
+
+ expect(control).not_to exceed_redis_calls_limit(1)
+ expect(control).not_to exceed_redis_command_calls_limit(:set, 0)
+ expect(control).not_to exceed_redis_command_calls_limit(:get, 1)
+ end
+ end
+
+ context 'when expect part is a function' do
+ it 'automatically enables RedisCommand::Recorder for it' do
+ func = -> do
+ Rails.cache.read('test')
+ Rails.cache.read('test')
+ end
+
+ expect { func.call }.not_to exceed_redis_calls_limit(2)
+ expect { func.call }.not_to exceed_redis_command_calls_limit(:get, 2)
+ end
+ end
+end
diff --git a/spec/tasks/gitlab/db/decomposition/connection_status_spec.rb b/spec/tasks/gitlab/db/decomposition/connection_status_spec.rb
new file mode 100644
index 00000000000..55a50035222
--- /dev/null
+++ b/spec/tasks/gitlab/db/decomposition/connection_status_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'rake_helper'
+
+RSpec.describe 'gitlab:db:decomposition:connection_status', feature_category: :pods do
+ let(:max_connections) { 500 }
+ let(:current_connections) { 300 }
+
+ subject { run_rake_task('gitlab:db:decomposition:connection_status') }
+
+ before :all do
+ Rake.application.rake_require 'tasks/gitlab/db/decomposition/connection_status'
+ end
+
+ before do
+ allow(ApplicationRecord.connection).to receive(:select_one).with(any_args).and_return(
+ { "active" => current_connections, "max" => max_connections }
+ )
+ end
+
+ context 'when separate ci database is not configured' do
+ before do
+ skip_if_multiple_databases_are_setup
+ end
+
+ context "when PostgreSQL max_connections is too low" do
+ it 'suggests to increase it' do
+ expect { subject }.to output(
+ "Currently using #{current_connections} connections out of #{max_connections} max_connections,\n" \
+ "which may run out when you switch to two database connections.\n\n" \
+ "Consider increasing PostgreSQL 'max_connections' setting.\n" \
+ "Depending on the installation method, there are different ways to\n" \
+ "increase that setting. Please consult the GitLab documentation.\n"
+ ).to_stdout
+ end
+ end
+
+ context "when PostgreSQL max_connections is high enough" do
+ let(:max_connections) { 1000 }
+
+ it 'only shows current status' do
+ expect { subject }.to output(
+ "Currently using #{current_connections} connections out of #{max_connections} max_connections,\n" \
+ "which is enough for running GitLab using two database connections.\n"
+ ).to_stdout
+ end
+ end
+ end
+
+ context 'when separate ci database is configured' do
+ before do
+ skip_if_multiple_databases_not_setup
+ end
+
+ it "does not show connection information" do
+ expect { subject }.to output(
+ "GitLab database already running on two connections\n"
+ ).to_stdout
+ end
+ end
+end
diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb
index 933eba40719..0f13840ae01 100644
--- a/spec/tasks/gitlab/db_rake_spec.rb
+++ b/spec/tasks/gitlab/db_rake_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
before do
# Stub out db tasks
allow(Rake::Task['db:migrate']).to receive(:invoke).and_return(true)
- allow(Rake::Task['db:structure:load']).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)
end
@@ -395,13 +395,19 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
end
end
- context 'when the dictionary files already exist' do
+ context 'when a new model class is added to the codebase' do
let(:table_class) do
Class.new(ApplicationRecord) do
self.table_name = 'table1'
end
end
+ let(:migration_table_class) do
+ Class.new(Gitlab::Database::Migration[1.0]::MigrationRecord) do
+ self.table_name = 'table1'
+ end
+ end
+
let(:view_class) do
Class.new(ApplicationRecord) do
self.table_name = 'view1'
@@ -410,7 +416,7 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
table_metadata = {
'table_name' => 'table1',
- 'classes' => [],
+ 'classes' => ['TableClass'],
'feature_categories' => [],
'description' => nil,
'introduced_by_url' => nil,
@@ -418,7 +424,7 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
}
view_metadata = {
'view_name' => 'view1',
- 'classes' => [],
+ 'classes' => ['ViewClass'],
'feature_categories' => [],
'description' => nil,
'introduced_by_url' => nil,
@@ -426,23 +432,60 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
}
before do
- stub_const('TableClass', table_class)
- stub_const('ViewClass', view_class)
+ stub_const('TableClass1', table_class)
+ stub_const('MIgrationTableClass1', migration_table_class)
+ stub_const('ViewClass1', view_class)
File.write(table_file_path, table_metadata.to_yaml)
File.write(view_file_path, view_metadata.to_yaml)
- allow(model).to receive(:descendants).and_return([table_class, view_class])
+ allow(model).to receive(:descendants).and_return([table_class, migration_table_class, view_class])
end
- it 'update the dictionary content' do
+ it 'appends new classes to the dictionary' do
run_rake_task('gitlab:db:dictionary:generate')
table_metadata = YAML.safe_load(File.read(table_file_path))
- expect(table_metadata['classes']).to match_array(['TableClass'])
+ expect(table_metadata['classes']).to match_array(%w[TableClass TableClass1])
view_metadata = YAML.safe_load(File.read(view_file_path))
- expect(view_metadata['classes']).to match_array(['ViewClass'])
+ expect(view_metadata['classes']).to match_array(%w[ViewClass ViewClass1])
+ end
+ end
+
+ context 'when a model class is removed from the codebase' do
+ table_metadata = {
+ 'table_name' => 'table1',
+ 'classes' => ['TableClass'],
+ 'feature_categories' => [],
+ 'description' => nil,
+ 'introduced_by_url' => nil,
+ 'milestone' => 14.3
+ }
+ view_metadata = {
+ 'view_name' => 'view1',
+ 'classes' => ['ViewClass'],
+ 'feature_categories' => [],
+ 'description' => nil,
+ 'introduced_by_url' => nil,
+ 'milestone' => 14.3
+ }
+
+ before do
+ File.write(table_file_path, table_metadata.to_yaml)
+ File.write(view_file_path, view_metadata.to_yaml)
+
+ allow(model).to receive(:descendants).and_return([])
+ end
+
+ it 'keeps the dictionary classes' do
+ run_rake_task('gitlab:db:dictionary:generate')
+
+ table_metadata = YAML.safe_load(File.read(table_file_path))
+ expect(table_metadata['classes']).to match_array(%w[TableClass])
+
+ view_metadata = YAML.safe_load(File.read(view_file_path))
+ expect(view_metadata['classes']).to match_array(%w[ViewClass])
end
end
end
@@ -805,6 +848,80 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
end
end
+ describe 'validate_async_constraints' do
+ before do
+ skip_if_multiple_databases_not_setup
+ end
+
+ it 'delegates ci task to Gitlab::Database::AsyncConstraints' do
+ expect(Gitlab::Database::AsyncConstraints).to receive(:validate_pending_entries!).with(how_many: 2)
+
+ run_rake_task('gitlab:db:validate_async_constraints:ci')
+ end
+
+ it 'delegates ci task to Gitlab::Database::AsyncConstraints with specified argument' do
+ expect(Gitlab::Database::AsyncConstraints).to receive(:validate_pending_entries!).with(how_many: 5)
+
+ run_rake_task('gitlab:db:validate_async_constraints:ci', '[5]')
+ end
+
+ it 'delegates main task to Gitlab::Database::AsyncConstraints' do
+ expect(Gitlab::Database::AsyncConstraints).to receive(:validate_pending_entries!).with(how_many: 2)
+
+ run_rake_task('gitlab:db:validate_async_constraints:main')
+ end
+
+ it 'delegates main task to Gitlab::Database::AsyncConstraints with specified argument' do
+ expect(Gitlab::Database::AsyncConstraints).to receive(:validate_pending_entries!).with(how_many: 7)
+
+ run_rake_task('gitlab:db:validate_async_constraints:main', '[7]')
+ end
+
+ it 'delegates all task to every database with higher default for dev' do
+ expect(Rake::Task['gitlab:db:validate_async_constraints:ci']).to receive(:invoke).with(1000)
+ expect(Rake::Task['gitlab:db:validate_async_constraints:main']).to receive(:invoke).with(1000)
+
+ run_rake_task('gitlab:db:validate_async_constraints:all')
+ end
+
+ it 'delegates all task to every database with lower default for prod' do
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
+
+ expect(Rake::Task['gitlab:db:validate_async_constraints:ci']).to receive(:invoke).with(2)
+ expect(Rake::Task['gitlab:db:validate_async_constraints:main']).to receive(:invoke).with(2)
+
+ run_rake_task('gitlab:db:validate_async_constraints:all')
+ end
+
+ it 'delegates all task to every database with specified argument' do
+ expect(Rake::Task['gitlab:db:validate_async_constraints:ci']).to receive(:invoke).with('50')
+ expect(Rake::Task['gitlab:db:validate_async_constraints:main']).to receive(:invoke).with('50')
+
+ run_rake_task('gitlab:db:validate_async_constraints:all', '[50]')
+ end
+
+ context 'when feature is not enabled' do
+ it 'is a no-op' do
+ stub_feature_flags(database_async_foreign_key_validation: false)
+
+ 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
+ end
+
+ it 'does not create a task for the geo database' do
+ expect { run_rake_task('gitlab:db:validate_async_constraints:geo') }
+ .to raise_error(/Don't know how to build task 'gitlab:db:validate_async_constraints:geo'/)
+ end
+ end
+ end
+
describe 'active' do
using RSpec::Parameterized::TableSyntax
@@ -975,14 +1092,6 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
skip_unless_ci_uses_database_tasks
end
- describe 'db:structure:dump against a single database' do
- it 'invokes gitlab:db:clean_structure_sql' do
- expect(Rake::Task['gitlab:db:clean_structure_sql']).to receive(:invoke).twice.and_return(true)
-
- expect { run_rake_task('db:structure:dump:main') }.not_to raise_error
- end
- end
-
describe 'db:schema:dump against a single database' do
it 'invokes gitlab:db:clean_structure_sql' do
expect(Rake::Task['gitlab:db:clean_structure_sql']).to receive(:invoke).once.and_return(true)
diff --git a/spec/tasks/gitlab/feature_categories_rake_spec.rb b/spec/tasks/gitlab/feature_categories_rake_spec.rb
index 22f36309a7c..33f4bca4c85 100644
--- a/spec/tasks/gitlab/feature_categories_rake_spec.rb
+++ b/spec/tasks/gitlab/feature_categories_rake_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe 'gitlab:feature_categories:index', :silence_stdout, feature_categ
)
),
'api_endpoints' => a_hash_including(
- 'authentication_and_authorization' => a_collection_including(
+ 'system_access' => a_collection_including(
klass: 'API::AccessRequests',
action: '/groups/:id/access_requests',
source_location: [
diff --git a/spec/tasks/gitlab/security/update_banned_ssh_keys_rake_spec.rb b/spec/tasks/gitlab/security/update_banned_ssh_keys_rake_spec.rb
index 25ea5d75a56..264dea815f4 100644
--- a/spec/tasks/gitlab/security/update_banned_ssh_keys_rake_spec.rb
+++ b/spec/tasks/gitlab/security/update_banned_ssh_keys_rake_spec.rb
@@ -7,7 +7,7 @@ require 'rake_helper'
# is hit in the rake task.
require 'git'
-RSpec.describe 'gitlab:security namespace rake tasks', :silence_stdout, feature_category: :credential_management do
+RSpec.describe 'gitlab:security namespace rake tasks', :silence_stdout, feature_category: :user_management do
let(:fixture_path) { Rails.root.join('spec/fixtures/tasks/gitlab/security') }
let(:output_file) { File.join(__dir__, 'tmp/banned_keys_test.yml') }
let(:git_url) { 'https://github.com/rapid7/ssh-badkeys.git' }
diff --git a/spec/tooling/danger/sidekiq_args_spec.rb b/spec/tooling/danger/sidekiq_args_spec.rb
new file mode 100644
index 00000000000..bfa9ef169de
--- /dev/null
+++ b/spec/tooling/danger/sidekiq_args_spec.rb
@@ -0,0 +1,125 @@
+# 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/sidekiq_args'
+require_relative '../../../tooling/danger/project_helper'
+
+RSpec.describe Tooling::Danger::SidekiqArgs, feature_category: :tooling do
+ include_context "with dangerfile"
+
+ let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
+ let(:fake_project_helper) { Tooling::Danger::ProjectHelper }
+
+ subject(:specs) { fake_danger.new(helper: fake_helper) }
+
+ before do
+ allow(specs).to receive(:project_helper).and_return(fake_project_helper)
+ end
+
+ describe '#args_changed?' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:before, :after, :result) do
+ " - def perform" | " + def perform(abc)" | true
+ " - def perform" | " + def perform(abc)" | true
+ " - def perform(abc)" | " + def perform(def)" | true
+ " - def perform(abc, def)" | " + def perform(abc)" | true
+ " - def perform(abc, def)" | " + def perform(def, abc)" | true
+ " - def perform" | " - def perform" | false
+ " + def perform" | " + def perform" | false
+ " - def perform(abc)" | " - def perform(abc)" | false
+ " + def perform(abc)" | " + def perform(abc)" | false
+ " - def perform(abc)" | " + def perform_foo(abc)" | false
+ end
+
+ with_them do
+ it 'returns correct result' do
+ expect(specs.args_changed?([before, after])).to eq(result)
+ end
+ end
+ end
+
+ describe '#add_comment_for_matched_line' do
+ let(:filename) { 'app/workers/hello_worker.rb' }
+ let(:file_lines) do
+ [
+ "Module Worker",
+ " def perform",
+ " puts hello world",
+ " end",
+ "end"
+ ]
+ end
+
+ before do
+ allow(specs.project_helper).to receive(:file_lines).and_return(file_lines)
+ end
+
+ context 'when args are changed' do
+ before do
+ allow(specs.helper).to receive(:changed_lines).and_return([" - def perform", " + def perform(abc)"])
+ allow(specs).to receive(:args_changed?).and_return(true)
+ end
+
+ it 'adds suggestion at the correct lines' do
+ expect(specs).to receive(:markdown).with(format(described_class::SUGGEST_MR_COMMENT), file: filename, line: 2)
+
+ specs.add_comment_for_matched_line(filename)
+ end
+ end
+
+ context 'when args are not changed' do
+ before do
+ allow(specs.helper).to receive(:changed_lines).and_return([" - def perform", " - def perform"])
+ allow(specs).to receive(:args_changed?).and_return(false)
+ end
+
+ it 'does not add suggestion' do
+ expect(specs).not_to receive(:markdown)
+
+ specs.add_comment_for_matched_line(filename)
+ end
+ end
+ end
+
+ describe '#changed_worker_files' do
+ let(:base_expected_files) { %w[app/workers/a.rb app/workers/b.rb ee/app/workers/e.rb] }
+
+ before do
+ all_changed_files = %w[
+ app/workers/a.rb
+ app/workers/b.rb
+ ee/app/workers/e.rb
+ spec/foo_spec.rb
+ ee/spec/foo_spec.rb
+ spec/bar_spec.rb
+ ee/spec/bar_spec.rb
+ spec/zab_spec.rb
+ ee/spec/zab_spec.rb
+ ]
+
+ allow(specs.helper).to receive(:all_changed_files).and_return(all_changed_files)
+ end
+
+ it 'returns added, modified, and renamed_after files by default' do
+ expect(specs.changed_worker_files).to match_array(base_expected_files)
+ end
+
+ context 'with include_ee: :exclude' do
+ it 'returns spec files without EE-specific files' do
+ expect(specs.changed_worker_files(ee: :exclude)).not_to include(%w[ee/app/workers/e.rb])
+ end
+ end
+
+ context 'with include_ee: :only' do
+ it 'returns EE-specific spec files only' do
+ expect(specs.changed_worker_files(ee: :only)).to match_array(%w[ee/app/workers/e.rb])
+ end
+ end
+ end
+end
diff --git a/spec/tooling/danger/specs_spec.rb b/spec/tooling/danger/specs_spec.rb
index cdac5954f92..09550f037d6 100644
--- a/spec/tooling/danger/specs_spec.rb
+++ b/spec/tooling/danger/specs_spec.rb
@@ -259,6 +259,10 @@ RSpec.describe Tooling::Danger::Specs, feature_category: :tooling do
" ee: true do",
"\n",
"RSpec.describe Issues :aggregate_failures,",
+ " feature_category: :team_planning do",
+ "\n",
+ "RSpec.describe MergeRequest :aggregate_failures,",
+ " :js,",
" feature_category: :team_planning do"
]
end
@@ -275,7 +279,11 @@ RSpec.describe Tooling::Danger::Specs, feature_category: :tooling do
"+ feature_category: planning_analytics do",
"+RSpec.describe Epics :aggregate_failures,",
"+ ee: true do",
- "+RSpec.describe Issues :aggregate_failures,"
+ "+RSpec.describe Issues :aggregate_failures,",
+ "+RSpec.describe MergeRequest :aggregate_failures,",
+ "+ :js,",
+ "+ feature_category: :team_planning do",
+ "+RSpec.describe 'line in commit diff but no longer in working copy' do"
]
end
diff --git a/spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb b/spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb
index 72e02547938..12a73480440 100644
--- a/spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb
+++ b/spec/tooling/lib/tooling/mappings/js_to_system_specs_mappings_spec.rb
@@ -129,6 +129,20 @@ RSpec.describe Tooling::Mappings::JsToSystemSpecsMappings, feature_category: :to
it 'returns a singularized keyword based on the first folder the file is in' do
expect(subject).to eq(%w[board query])
end
+
+ context 'when the files are under the pages folder' do
+ let(:js_files) do
+ %w[
+ app/assets/javascripts/pages/boards/issue_board_filters.js
+ ee/app/assets/javascripts/pages2/queries/epic_due_date.query.graphql
+ ee/app/assets/javascripts/queries/epic_due_date.query.graphql
+ ]
+ end
+
+ it 'captures the second folder' do
+ expect(subject).to eq(%w[board pages2 query])
+ end
+ end
end
describe '#system_specs_for_edition' do
diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb
index f62ab726631..bd86f1fe08a 100644
--- a/spec/uploaders/gitlab_uploader_spec.rb
+++ b/spec/uploaders/gitlab_uploader_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'carrierwave/storage/fog'
-RSpec.describe GitlabUploader do
+RSpec.describe GitlabUploader, feature_category: :shared do
let(:uploader_class) { Class.new(described_class) }
subject(:uploader) { uploader_class.new(double) }
@@ -179,4 +179,19 @@ RSpec.describe GitlabUploader do
it { expect { subject }.to raise_error(RuntimeError, /not supported/) }
end
+
+ describe '.storage_location' do
+ it 'sets the identifier for the storage location options' do
+ uploader_class.storage_location(:artifacts)
+
+ expect(uploader_class.options).to eq(Gitlab.config.artifacts)
+ end
+
+ context 'when given identifier is not known' do
+ it 'raises an error' do
+ expect { uploader_class.storage_location(:foo) }
+ .to raise_error(KeyError)
+ end
+ end
+ end
end
diff --git a/spec/uploaders/object_storage/cdn_spec.rb b/spec/uploaders/object_storage/cdn_spec.rb
index d6c638297fa..0c1966b4df2 100644
--- a/spec/uploaders/object_storage/cdn_spec.rb
+++ b/spec/uploaders/object_storage/cdn_spec.rb
@@ -3,19 +3,6 @@
require 'spec_helper'
RSpec.describe ObjectStorage::CDN, feature_category: :build_artifacts do
- let(:cdn_options) do
- {
- 'object_store' => {
- 'cdn' => {
- 'provider' => 'google',
- 'url' => 'https://gitlab.example.com',
- 'key_name' => 'test-key',
- 'key' => Base64.urlsafe_encode64('12345')
- }
- }
- }.freeze
- end
-
let(:uploader_class) do
Class.new(GitlabUploader) do
include ObjectStorage::Concern
@@ -39,44 +26,66 @@ RSpec.describe ObjectStorage::CDN, feature_category: :build_artifacts do
subject { uploader_class.new(object, :file) }
context 'with CDN config' do
+ let(:cdn_options) do
+ {
+ 'object_store' => {
+ 'cdn' => {
+ 'provider' => cdn_provider,
+ 'url' => 'https://gitlab.example.com',
+ 'key_name' => 'test-key',
+ 'key' => Base64.urlsafe_encode64('12345')
+ }
+ }
+ }.freeze
+ end
+
before do
stub_artifacts_object_storage(enabled: true)
- uploader_class.options = Settingslogic.new(Gitlab.config.uploads.deep_merge(cdn_options))
+ options = Settingslogic.new(Gitlab.config.uploads.deep_merge(cdn_options))
+ allow(uploader_class).to receive(:options).and_return(options)
end
- describe '#cdn_enabled_url' do
- it 'calls #cdn_signed_url' do
- expect(subject).not_to receive(:url)
- expect(subject).to receive(:cdn_signed_url).with(query_params).and_call_original
+ context 'with a known CDN provider' do
+ let(:cdn_provider) { 'google' }
- result = subject.cdn_enabled_url(public_ip, query_params)
+ describe '#cdn_enabled_url' do
+ it 'calls #cdn_signed_url' do
+ expect(subject).not_to receive(:url)
+ expect(subject).to receive(:cdn_signed_url).with(query_params).and_call_original
+
+ result = subject.cdn_enabled_url(public_ip, query_params)
- expect(result.used_cdn).to be true
+ expect(result.used_cdn).to be true
+ end
end
- end
- describe '#use_cdn?' do
- it 'returns true' do
- expect(subject.use_cdn?(public_ip)).to be true
+ describe '#use_cdn?' do
+ it 'returns true' do
+ expect(subject.use_cdn?(public_ip)).to be true
+ end
end
- end
- describe '#cdn_signed_url' do
- it 'returns a URL' do
- expect_next_instance_of(ObjectStorage::CDN::GoogleCDN) do |cdn|
- expect(cdn).to receive(:signed_url).and_return("https://cdn.example.com/path")
+ describe '#cdn_signed_url' do
+ it 'returns a URL' do
+ expect_next_instance_of(ObjectStorage::CDN::GoogleCDN) do |cdn|
+ expect(cdn).to receive(:signed_url).and_return("https://cdn.example.com/path")
+ end
+
+ expect(subject.cdn_signed_url).to eq("https://cdn.example.com/path")
end
+ end
+ end
+
+ context 'with an unknown CDN provider' do
+ let(:cdn_provider) { 'amazon' }
- expect(subject.cdn_signed_url).to eq("https://cdn.example.com/path")
+ it 'raises an error' do
+ expect { subject.use_cdn?(public_ip) }.to raise_error("Unknown CDN provider: amazon")
end
end
end
context 'without CDN config' do
- before do
- uploader_class.options = Gitlab.config.uploads
- end
-
describe '#cdn_enabled_url' do
it 'calls #url' do
expect(subject).not_to receive(:cdn_signed_url)
@@ -94,15 +103,4 @@ RSpec.describe ObjectStorage::CDN, feature_category: :build_artifacts do
end
end
end
-
- context 'with an unknown CDN provider' do
- before do
- cdn_options['object_store']['cdn']['provider'] = 'amazon'
- uploader_class.options = Settingslogic.new(Gitlab.config.uploads.deep_merge(cdn_options))
- end
-
- it 'raises an error' do
- expect { subject.use_cdn?(public_ip) }.to raise_error("Unknown CDN provider: amazon")
- end
- end
end
diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb
index 5344dbeb512..0e293ec973c 100644
--- a/spec/uploaders/object_storage_spec.rb
+++ b/spec/uploaders/object_storage_spec.rb
@@ -8,7 +8,7 @@ class Implementation < GitlabUploader
include ::RecordsUploads::Concern
prepend ::ObjectStorage::Extension::RecordsUploads
- storage_options Gitlab.config.uploads
+ storage_location :uploads
private
diff --git a/spec/validators/addressable_url_validator_spec.rb b/spec/validators/addressable_url_validator_spec.rb
index 9109a899881..c95c0563a55 100644
--- a/spec/validators/addressable_url_validator_spec.rb
+++ b/spec/validators/addressable_url_validator_spec.rb
@@ -49,10 +49,15 @@ RSpec.describe AddressableUrlValidator do
end
end
- it 'provides all arguments to UrlBlock validate' do
+ it 'provides all arguments to UrlBlocker.validate!' do
+ # AddressableUrlValidator evaluates all procs before passing as arguments.
+ expected_opts = described_class::BLOCKER_VALIDATE_OPTIONS.transform_values do |value|
+ value.is_a?(Proc) ? value.call : value
+ end
+
expect(Gitlab::UrlBlocker)
.to receive(:validate!)
- .with(badge.link_url, described_class::BLOCKER_VALIDATE_OPTIONS)
+ .with(badge.link_url, expected_opts)
.and_return(true)
subject
@@ -302,6 +307,67 @@ RSpec.describe AddressableUrlValidator do
end
end
+ context 'when deny_all_requests_except_allowed is' do
+ let(:url) { 'http://example.com' }
+ let(:options) { { attributes: [:link_url] } }
+ let(:validator) { described_class.new(**options) }
+
+ context 'true' do
+ let(:options) { super().merge(deny_all_requests_except_allowed: true) }
+
+ it 'prevents the url' do
+ badge.link_url = url
+
+ subject
+
+ expect(badge.errors).to be_present
+ end
+ end
+
+ context 'false' do
+ let(:options) { super().merge(deny_all_requests_except_allowed: false) }
+
+ it 'allows the url' do
+ badge.link_url = url
+
+ subject
+
+ expect(badge.errors).to be_empty
+ end
+ end
+
+ context 'not given' do
+ before do
+ allow(Gitlab::CurrentSettings).to receive(:current_application_settings?).and_return(true)
+ stub_application_setting(deny_all_requests_except_allowed: app_setting)
+ end
+
+ context 'when app setting is true' do
+ let(:app_setting) { true }
+
+ it 'prevents the url' do
+ badge.link_url = url
+
+ subject
+
+ expect(badge.errors).to be_present
+ end
+ end
+
+ context 'when app setting is false' do
+ let(:app_setting) { false }
+
+ it 'allows the url' do
+ badge.link_url = url
+
+ subject
+
+ expect(badge.errors).to be_empty
+ end
+ end
+ end
+ end
+
context 'when enforce_sanitization is' do
let(:validator) { described_class.new(attributes: [:link_url], enforce_sanitization: enforce_sanitization) }
let(:unsafe_url) { "https://replaceme.com/'><script>alert(document.cookie)</script>" }
diff --git a/spec/views/admin/application_settings/ci_cd.html.haml_spec.rb b/spec/views/admin/application_settings/ci_cd.html.haml_spec.rb
index 5ef9399487f..d2a30f2c5c0 100644
--- a/spec/views/admin/application_settings/ci_cd.html.haml_spec.rb
+++ b/spec/views/admin/application_settings/ci_cd.html.haml_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe 'admin/application_settings/ci_cd.html.haml' do
allow(view).to receive(:current_user).and_return(user)
end
- describe 'CI CD Runner Registration' do
+ describe 'CI CD Runners' do
it 'has the setting section' do
render
@@ -26,6 +26,9 @@ RSpec.describe 'admin/application_settings/ci_cd.html.haml' do
expect(rendered).to have_content("Runner registration")
expect(rendered).to have_content(s_("Runners|If both settings are disabled, new runners cannot be registered."))
+ expect(rendered).to have_content(
+ s_("Runners|Fetch GitLab Runner release version data from GitLab.com")
+ )
end
end
end
diff --git a/spec/views/admin/application_settings/network.html.haml_spec.rb b/spec/views/admin/application_settings/network.html.haml_spec.rb
new file mode 100644
index 00000000000..3df55be92d5
--- /dev/null
+++ b/spec/views/admin/application_settings/network.html.haml_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'admin/application_settings/network.html.haml', feature_category: :projects do
+ let_it_be(:admin) { build_stubbed(:admin) }
+ let_it_be(:application_setting) { build(:application_setting) }
+
+ before do
+ assign(:application_setting, application_setting)
+ allow(view).to receive(:current_user) { admin }
+ end
+
+ context 'for Projects API rate limit' do
+ it 'renders the `projects_api_rate_limit_unauthenticated` field' do
+ render
+
+ expect(rendered).to have_field('application_setting_projects_api_rate_limit_unauthenticated')
+ end
+
+ context 'when the feature flag `rate_limit_for_unauthenticated_projects_api_access` is turned off' do
+ before do
+ stub_feature_flags(rate_limit_for_unauthenticated_projects_api_access: false)
+ end
+
+ it 'does not render the `projects_api_rate_limit_unauthenticated` field' do
+ render
+
+ expect(rendered).not_to have_field('application_setting_projects_api_rate_limit_unauthenticated')
+ end
+ end
+ end
+end
diff --git a/spec/views/admin/sessions/two_factor.html.haml_spec.rb b/spec/views/admin/sessions/two_factor.html.haml_spec.rb
index c7e0edbcd58..6503c08b84c 100644
--- a/spec/views/admin/sessions/two_factor.html.haml_spec.rb
+++ b/spec/views/admin/sessions/two_factor.html.haml_spec.rb
@@ -29,14 +29,10 @@ RSpec.describe 'admin/sessions/two_factor.html.haml' do
end
end
- context 'user has u2f active' do
- let(:user) { create(:admin, :two_factor_via_u2f) }
+ context 'user has WebAuthn active' do
+ let(:user) { create(:admin, :two_factor_via_webauthn) }
- before do
- stub_feature_flags(webauthn: false)
- end
-
- it 'shows enter u2f form' do
+ it 'shows enter WebAuthn form' do
render
expect(rendered).to have_css('#js-login-2fa-device.btn')
diff --git a/spec/views/devise/confirmations/almost_there.html.haml_spec.rb b/spec/views/devise/confirmations/almost_there.html.haml_spec.rb
index c091efe9295..8e12fb5a17e 100644
--- a/spec/views/devise/confirmations/almost_there.html.haml_spec.rb
+++ b/spec/views/devise/confirmations/almost_there.html.haml_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'devise/confirmations/almost_there' do
- describe 'confirmations text' do
- subject { render(template: 'devise/confirmations/almost_there') }
+ subject { render(template: 'devise/confirmations/almost_there') }
+ describe 'confirmations text' do
before do
allow(view).to receive(:params).and_return(email: email)
end
@@ -34,4 +34,17 @@ RSpec.describe 'devise/confirmations/almost_there' do
end
end
end
+
+ describe 'register again prompt' do
+ specify do
+ subject
+
+ expect(rendered).to have_content(
+ 'If the email address is incorrect, you can register again with a different email'
+ )
+ expect(rendered).to have_link(
+ 'register again with a different email', href: new_user_registration_path
+ )
+ end
+ end
end
diff --git a/spec/views/devise/sessions/new.html.haml_spec.rb b/spec/views/devise/sessions/new.html.haml_spec.rb
index 798c891e75c..bad01ec2c3d 100644
--- a/spec/views/devise/sessions/new.html.haml_spec.rb
+++ b/spec/views/devise/sessions/new.html.haml_spec.rb
@@ -3,14 +3,13 @@
require 'spec_helper'
RSpec.describe 'devise/sessions/new' do
- describe 'marketing text' do
+ describe 'marketing text', :saas do
subject { render(template: 'devise/sessions/new', layout: 'layouts/devise') }
before do
stub_devise
disable_captcha
stub_feature_flags(restyle_login_page: false)
- allow(Gitlab).to receive(:com?).and_return(true)
end
it 'when flash is anything it renders marketing text' do
diff --git a/spec/views/devise/shared/_error_messages.html.haml_spec.rb b/spec/views/devise/shared/_error_messages.html.haml_spec.rb
new file mode 100644
index 00000000000..9f23b049caf
--- /dev/null
+++ b/spec/views/devise/shared/_error_messages.html.haml_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'devise/shared/_error_messages', feature_category: :system_access do
+ describe 'Error messages' do
+ let(:resource) do
+ instance_spy(User, errors: errors, class: User)
+ end
+
+ before do
+ allow(view).to receive(:resource).and_return(resource)
+ end
+
+ context 'with errors', :aggregate_failures do
+ let(:errors) { errors_stub(['Invalid name', 'Invalid password']) }
+
+ it 'shows errors' do
+ render
+
+ expect(rendered).to have_selector('#error_explanation')
+ expect(rendered).to have_content('Invalid name')
+ expect(rendered).to have_content('Invalid password')
+ end
+ end
+
+ context 'without errors' do
+ let(:errors) { [] }
+
+ it 'does not show errors' do
+ render
+
+ expect(rendered).not_to have_selector('#error_explanation')
+ end
+ end
+ end
+
+ def errors_stub(*messages)
+ ActiveModel::Errors.new(double).tap do |errors|
+ messages.each { |msg| errors.add(:base, msg) }
+ end
+ end
+end
diff --git a/spec/views/devise/shared/_signup_box.html.haml_spec.rb b/spec/views/devise/shared/_signup_box.html.haml_spec.rb
index ee9ccbf6ff5..94a5871cb97 100644
--- a/spec/views/devise/shared/_signup_box.html.haml_spec.rb
+++ b/spec/views/devise/shared/_signup_box.html.haml_spec.rb
@@ -20,6 +20,7 @@ RSpec.describe 'devise/shared/_signup_box' do
before do
stub_devise
+ allow(view).to receive(:arkose_labs_enabled?).and_return(false)
allow(view).to receive(:show_omniauth_providers).and_return(false)
allow(view).to receive(:url).and_return('_url_')
allow(view).to receive(:terms_path).and_return(terms_path)
diff --git a/spec/views/events/event/_common.html.haml_spec.rb b/spec/views/events/event/_common.html.haml_spec.rb
index 2160245fb63..cff1ec43a14 100644
--- a/spec/views/events/event/_common.html.haml_spec.rb
+++ b/spec/views/events/event/_common.html.haml_spec.rb
@@ -18,19 +18,6 @@ RSpec.describe 'events/event/_common.html.haml' do
create(:event, :created, project: project, target: work_item, target_type: 'WorkItem', author: user)
end
- context 'when use_iid_in_work_items_path feature flag is disabled' do
- before do
- stub_feature_flags(use_iid_in_work_items_path: false)
- render partial: 'events/event/common', locals: { event: event.present }
- end
-
- it 'renders the correct url' do
- expect(rendered).to have_link(
- work_item.reference_link_text, href: "/#{project.full_path}/-/work_items/#{work_item.id}"
- )
- end
- end
-
it 'renders the correct url with iid' do
expect(rendered).to have_link(
work_item.reference_link_text, href: "/#{project.full_path}/-/work_items/#{work_item.iid}?iid_path=true"
diff --git a/spec/views/groups/group_members/index.html.haml_spec.rb b/spec/views/groups/group_members/index.html.haml_spec.rb
index 0b3b149238f..fdc6b09d32a 100644
--- a/spec/views/groups/group_members/index.html.haml_spec.rb
+++ b/spec/views/groups/group_members/index.html.haml_spec.rb
@@ -25,7 +25,6 @@ RSpec.describe 'groups/group_members/index', :aggregate_failures, feature_catego
expect(rendered).to have_selector('.js-invite-group-trigger')
expect(rendered).to have_selector('.js-invite-members-trigger')
- expect(response).to render_template(partial: 'groups/_invite_members_modal')
end
end
diff --git a/spec/views/layouts/group.html.haml_spec.rb b/spec/views/layouts/group.html.haml_spec.rb
new file mode 100644
index 00000000000..0b8f735a1d6
--- /dev/null
+++ b/spec/views/layouts/group.html.haml_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'layouts/group', feature_category: :subgroups do
+ let_it_be(:group) { create(:group) } # rubocop:todo RSpec/FactoryBot/AvoidCreate
+ let(:invite_member) { true }
+
+ before do
+ allow(view).to receive(:can_admin_group_member?).and_return(invite_member)
+ assign(:group, group)
+ allow(view).to receive(:current_user_mode).and_return(Gitlab::Auth::CurrentUserMode.new(build_stubbed(:user)))
+ end
+
+ subject do
+ render
+
+ rendered
+ end
+
+ context 'with ability to invite members' do
+ it { is_expected.to have_selector('.js-invite-members-modal') }
+ end
+
+ context 'without ability to invite members' do
+ let(:invite_member) { false }
+
+ it { is_expected.not_to have_selector('.js-invite-members-modal') }
+ end
+end
diff --git a/spec/views/layouts/header/_new_dropdown.haml_spec.rb b/spec/views/layouts/header/_new_dropdown.haml_spec.rb
index 178448022d1..2c5882fce3d 100644
--- a/spec/views/layouts/header/_new_dropdown.haml_spec.rb
+++ b/spec/views/layouts/header/_new_dropdown.haml_spec.rb
@@ -7,13 +7,13 @@ RSpec.describe 'layouts/header/_new_dropdown', feature_category: :navigation do
shared_examples_for 'invite member selector' do
context 'with ability to invite members' do
- it { is_expected.to have_link('Invite members', href: href) }
+ it { is_expected.to have_selector('.js-invite-members-trigger') }
end
context 'without ability to invite members' do
let(:invite_member) { false }
- it { is_expected.not_to have_link('Invite members') }
+ it { is_expected.not_to have_selector('.js-invite-members-trigger') }
end
end
@@ -159,6 +159,29 @@ RSpec.describe 'layouts/header/_new_dropdown', feature_category: :navigation do
expect(rendered).to have_link('New snippet', href: new_snippet_path)
end
+ context 'when partial exists in a menu item' do
+ it 'renders the menu item partial without rendering invite modal partial' do
+ view_model = {
+ title: '_title_',
+ menu_sections: [
+ {
+ title: '_section_title_',
+ menu_items: [
+ ::Gitlab::Nav::TopNavMenuItem
+ .build(id: '_id_', title: '_title_', partial: 'groups/invite_members_top_nav_link')
+ ]
+ }
+ ]
+ }
+
+ allow(view).to receive(:new_dropdown_view_model).and_return(view_model)
+
+ render
+
+ expect(response).to render_template(partial: 'groups/_invite_members_top_nav_link')
+ end
+ end
+
context 'when the user is not allowed to do anything' do
let(:user) { create(:user, :external) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
index cddff276317..0df490f9b41 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -106,11 +106,11 @@ RSpec.describe 'layouts/nav/sidebar/_project', feature_category: :navigation do
end
end
- describe 'Contributors' do
+ describe 'Contributor statistics' do
it 'has a link to the project contributors path' do
render
- expect(rendered).to have_link('Contributors', href: project_graph_path(project, current_ref, ref_type: 'heads'))
+ expect(rendered).to have_link('Contributor statistics', href: project_graph_path(project, current_ref, ref_type: 'heads'))
end
end
@@ -122,11 +122,11 @@ RSpec.describe 'layouts/nav/sidebar/_project', feature_category: :navigation do
end
end
- describe 'Compare' do
+ describe 'Compare revisions' do
it 'has a link to the project compare path' do
render
- expect(rendered).to have_link('Compare', href: project_compare_index_path(project, from: project.repository.root_ref, to: current_ref))
+ expect(rendered).to have_link('Compare revisions', href: project_compare_index_path(project, from: project.repository.root_ref, to: current_ref))
end
end
end
@@ -310,7 +310,7 @@ RSpec.describe 'layouts/nav/sidebar/_project', feature_category: :navigation do
it 'top level navigation link is not visible' do
render
- expect(rendered).not_to have_link('Security & Compliance')
+ expect(rendered).not_to have_link('Security and Compliance')
end
end
@@ -322,11 +322,11 @@ RSpec.describe 'layouts/nav/sidebar/_project', feature_category: :navigation do
end
it 'top level navigation link is visible' do
- expect(rendered).to have_link('Security & Compliance')
+ expect(rendered).to have_link('Security and Compliance')
end
it 'security configuration link is visible' do
- expect(rendered).to have_link('Configuration', href: project_security_configuration_path(project))
+ expect(rendered).to have_link('Security configuration', href: project_security_configuration_path(project))
end
end
end
diff --git a/spec/views/layouts/project.html.haml_spec.rb b/spec/views/layouts/project.html.haml_spec.rb
new file mode 100644
index 00000000000..588828f7bd6
--- /dev/null
+++ b/spec/views/layouts/project.html.haml_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'layouts/project', feature_category: :projects do
+ let(:invite_member) { true }
+
+ before do
+ allow(view).to receive(:can_admin_project_member?).and_return(invite_member)
+ assign(:project, build_stubbed(:project))
+ allow(view).to receive(:current_user_mode).and_return(Gitlab::Auth::CurrentUserMode.new(build_stubbed(:user)))
+ end
+
+ subject do
+ render
+
+ rendered
+ end
+
+ context 'with ability to invite members' do
+ it { is_expected.to have_selector('.js-invite-members-modal') }
+ end
+
+ context 'without ability to invite members' do
+ let(:invite_member) { false }
+
+ it { is_expected.not_to have_selector('.js-invite-members-modal') }
+ end
+end
diff --git a/spec/views/notify/import_issues_csv_email.html.haml_spec.rb b/spec/views/notify/import_issues_csv_email.html.haml_spec.rb
index 43dfab87ac9..c3d320a837b 100644
--- a/spec/views/notify/import_issues_csv_email.html.haml_spec.rb
+++ b/spec/views/notify/import_issues_csv_email.html.haml_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'notify/import_issues_csv_email.html.haml' do
let(:user) { create(:user) }
let(:project) { create(:project) }
- let(:correct_results) { { success: 3, valid_file: true } }
- let(:errored_results) { { success: 3, error_lines: [5, 6, 7], valid_file: true } }
+ let(:correct_results) { { success: 3, parse_error: false } }
+ let(:errored_results) { { success: 3, error_lines: [5, 6, 7], parse_error: false } }
let(:parse_error_results) { { success: 0, parse_error: true } }
before do
diff --git a/spec/views/notify/import_work_items_csv_email.html.haml_spec.rb b/spec/views/notify/import_work_items_csv_email.html.haml_spec.rb
new file mode 100644
index 00000000000..989481fc2e6
--- /dev/null
+++ b/spec/views/notify/import_work_items_csv_email.html.haml_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'notify/import_work_items_csv_email.html.haml', feature_category: :team_planning do
+ let_it_be(:user) { create(:user) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
+ let_it_be(:project) { create(:project) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
+
+ let(:parse_error) { "Error parsing CSV file. Please make sure it has the correct format" }
+
+ before do
+ assign(:user, user)
+ assign(:project, project)
+ assign(:results, results)
+
+ render
+ end
+
+ shared_examples_for 'no records created' do
+ specify do
+ expect(rendered).to have_content("No work items have been imported.")
+ expect(rendered).not_to have_content("work items successfully imported.")
+ end
+ end
+
+ shared_examples_for 'work item records created' do
+ specify do
+ expect(rendered).not_to have_content("No work items have been imported.")
+ expect(rendered).to have_content("work items successfully imported.")
+ end
+ end
+
+ shared_examples_for 'contains project link' do
+ specify do
+ expect(rendered).to have_link(project.full_name, href: project_url(project))
+ end
+ end
+
+ shared_examples_for 'contains parse error' do
+ specify do
+ expect(rendered).to have_content(parse_error)
+ end
+ end
+
+ shared_examples_for 'does not contain parse error' do
+ specify do
+ expect(rendered).not_to have_content(parse_error)
+ end
+ end
+
+ context 'when no errors found while importing' do
+ let(:results) { { success: 3, parse_error: false } }
+
+ it 'renders correctly' do
+ expect(rendered).not_to have_content("Errors found on line")
+ end
+
+ it_behaves_like 'contains project link'
+ it_behaves_like 'work item records created'
+ it_behaves_like 'does not contain parse error'
+ end
+
+ context 'when import errors reported' do
+ let(:results) { { success: 3, error_lines: [5, 6, 7], parse_error: false } }
+
+ it 'renders correctly' do
+ expect(rendered).to have_content("Errors found on lines: #{results[:error_lines].join(', ')}. \
+Please check that these lines have the following fields: title, type")
+ end
+
+ it_behaves_like 'contains project link'
+ it_behaves_like 'work item records created'
+ it_behaves_like 'does not contain parse error'
+ end
+
+ context 'when parse error reported while importing' do
+ let(:results) { { success: 0, parse_error: true } }
+
+ it_behaves_like 'contains project link'
+ it_behaves_like 'no records created'
+ it_behaves_like 'contains parse error'
+ end
+
+ context 'when work item type column contains blank entries' do
+ let(:results) { { success: 0, parse_error: false, type_errors: { blank: [4] } } }
+
+ it 'renders with missing work item message' do
+ expect(rendered).to have_content("Work item type is empty")
+ end
+
+ it_behaves_like 'contains project link'
+ it_behaves_like 'no records created'
+ it_behaves_like 'does not contain parse error'
+ end
+
+ context 'when work item type column contains missing entries' do
+ let(:results) { { success: 0, parse_error: false, type_errors: { missing: [5] } } }
+
+ it 'renders with missing work item message' do
+ expect(rendered).to have_content("Work item type cannot be found or is not supported.")
+ end
+
+ it_behaves_like 'contains project link'
+ it_behaves_like 'no records created'
+ it_behaves_like 'does not contain parse error'
+ end
+
+ context 'when work item type column contains disallowed entries' do
+ let(:results) { { success: 0, parse_error: false, type_errors: { disallowed: [6] } } }
+
+ it 'renders with missing work item message' do
+ expect(rendered).to have_content("Work item type is not available.")
+ end
+
+ it_behaves_like 'contains project link'
+ it_behaves_like 'no records created'
+ it_behaves_like 'does not contain parse error'
+ end
+
+ context 'when CSV contains multiple kinds of work item type errors' do
+ let(:results) { { success: 0, parse_error: false, type_errors: { blank: [4], missing: [5], disallowed: [6] } } }
+
+ it 'renders with missing work item message' do
+ expect(rendered).to have_content("Work item type is empty")
+ expect(rendered).to have_content("Work item type cannot be found or is not supported.")
+ expect(rendered).to have_content("Work item type is not available. Please check your license and permissions.")
+ end
+
+ it_behaves_like 'contains project link'
+ it_behaves_like 'no records created'
+ it_behaves_like 'does not contain parse error'
+ end
+end
diff --git a/spec/views/profiles/keys/_key.html.haml_spec.rb b/spec/views/profiles/keys/_key.html.haml_spec.rb
index 2ddbd3e6e14..d51bfd19c37 100644
--- a/spec/views/profiles/keys/_key.html.haml_spec.rb
+++ b/spec/views/profiles/keys/_key.html.haml_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'profiles/keys/_key.html.haml', feature_category: :authentication_and_authorization do
+RSpec.describe 'profiles/keys/_key.html.haml', feature_category: :system_access do
let_it_be(:user) { create(:user) }
before do
@@ -68,30 +68,21 @@ RSpec.describe 'profiles/keys/_key.html.haml', feature_category: :authentication
end
context 'displays the usage type' do
- where(:usage_type, :usage_type_text, :displayed_buttons, :hidden_buttons, :revoke_ssh_signatures_ff) do
+ where(:usage_type, :usage_type_text, :displayed_buttons, :hidden_buttons) do
[
- [:auth, 'Authentication', ['Remove'], ['Revoke'], true],
- [:auth_and_signing, 'Authentication & Signing', %w[Remove Revoke], [], true],
- [:signing, 'Signing', %w[Remove Revoke], [], true],
- [:auth, 'Authentication', ['Remove'], ['Revoke'], false],
- [:auth_and_signing, 'Authentication & Signing', %w[Remove], ['Revoke'], false],
- [:signing, 'Signing', %w[Remove], ['Revoke'], false]
+ [:auth, 'Authentication', ['Remove'], ['Revoke']],
+ [:auth_and_signing, 'Authentication & Signing', %w[Remove Revoke], []],
+ [:signing, 'Signing', %w[Remove Revoke], []]
]
end
with_them do
let(:key) { create(:key, user: user, usage_type: usage_type) }
- it 'renders usage type text' do
+ it 'renders usage type text and remove/revoke buttons', :aggregate_failures do
render
expect(rendered).to have_text(usage_type_text)
- end
-
- it 'renders remove/revoke buttons', :aggregate_failures do
- stub_feature_flags(revoke_ssh_signatures: revoke_ssh_signatures_ff)
-
- render
displayed_buttons.each do |button|
expect(rendered).to have_text(button)
diff --git a/spec/views/projects/edit.html.haml_spec.rb b/spec/views/projects/edit.html.haml_spec.rb
index bf154b61609..aeb12abd240 100644
--- a/spec/views/projects/edit.html.haml_spec.rb
+++ b/spec/views/projects/edit.html.haml_spec.rb
@@ -101,4 +101,28 @@ RSpec.describe 'projects/edit' do
it_behaves_like 'renders registration features prompt', :project_disabled_repository_size_limit
end
end
+
+ describe 'pages menu entry callout' do
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(show_pages_in_deployments_menu: false)
+ end
+
+ it 'does not show a callout' do
+ render
+ expect(rendered).not_to have_content('GitLab Pages has moved')
+ end
+ end
+
+ context 'with feature flag enabled' do
+ before do
+ stub_feature_flags(show_pages_in_deployments_menu: true)
+ end
+
+ it 'does show a callout' do
+ render
+ expect(rendered).to have_content('GitLab Pages has moved')
+ end
+ end
+ end
end
diff --git a/spec/views/projects/empty.html.haml_spec.rb b/spec/views/projects/empty.html.haml_spec.rb
index 6077dda3c98..2b19b364365 100644
--- a/spec/views/projects/empty.html.haml_spec.rb
+++ b/spec/views/projects/empty.html.haml_spec.rb
@@ -73,9 +73,6 @@ 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('.js-invite-members-modal')
- expect(rendered).to have_selector('[data-label=invite_members_empty_project]')
- expect(rendered).to have_selector('[data-event=click_button]')
expect(rendered).to have_selector('[data-trigger-source=project-empty-page]')
end
@@ -87,7 +84,6 @@ RSpec.describe 'projects/empty' do
expect(rendered).not_to have_content('Invite your team')
expect(rendered).not_to have_selector('.js-invite-members-trigger')
- expect(rendered).not_to have_selector('.js-invite-members-modal')
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
index 37c9908af1d..13ec7207ec9 100644
--- a/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb
+++ b/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'projects/pipeline_schedules/_pipeline_schedule' do
let(:user) { maintainer }
before do
- allow(view).to receive(:can?).with(maintainer, :take_ownership_pipeline_schedule, pipeline_schedule).and_return(true)
+ 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
@@ -36,7 +36,7 @@ RSpec.describe 'projects/pipeline_schedules/_pipeline_schedule' do
let(:user) { owner }
before do
- allow(view).to receive(:can?).with(owner, :take_ownership_pipeline_schedule, pipeline_schedule).and_return(false)
+ allow(view).to receive(:can?).with(owner, :admin_pipeline_schedule, pipeline_schedule).and_return(false)
end
it 'owner cannot take ownership of pipeline' do
diff --git a/spec/views/projects/pipelines/show.html.haml_spec.rb b/spec/views/projects/pipelines/show.html.haml_spec.rb
index b9c7da20d1a..81a11874886 100644
--- a/spec/views/projects/pipelines/show.html.haml_spec.rb
+++ b/spec/views/projects/pipelines/show.html.haml_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'projects/pipelines/show', feature_category: :pipeline_authoring do
+RSpec.describe 'projects/pipelines/show', feature_category: :pipeline_composition do
include Devise::Test::ControllerHelpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
@@ -13,6 +13,7 @@ RSpec.describe 'projects/pipelines/show', feature_category: :pipeline_authoring
before do
assign(:project, project)
assign(:pipeline, presented_pipeline)
+ allow(view).to receive(:current_user) { user }
end
context 'when pipeline has errors' do
@@ -32,6 +33,22 @@ RSpec.describe 'projects/pipelines/show', feature_category: :pipeline_authoring
expect(rendered).not_to have_selector('#js-pipeline-tabs')
end
+
+ it 'renders the pipeline editor button with correct link for users who can view' do
+ project.add_developer(user)
+
+ render
+
+ expect(rendered).to have_link s_('Go to the pipeline editor'),
+ href: project_ci_pipeline_editor_path(project)
+ end
+
+ it 'renders the pipeline editor button with correct link for users who can not view' do
+ render
+
+ expect(rendered).not_to have_link s_('Go to the pipeline editor'),
+ href: project_ci_pipeline_editor_path(project)
+ end
end
context 'when pipeline is valid' do
diff --git a/spec/views/projects/project_members/index.html.haml_spec.rb b/spec/views/projects/project_members/index.html.haml_spec.rb
index 4c4cde01cca..2fcc5c6935b 100644
--- a/spec/views/projects/project_members/index.html.haml_spec.rb
+++ b/spec/views/projects/project_members/index.html.haml_spec.rb
@@ -28,7 +28,6 @@ RSpec.describe 'projects/project_members/index', :aggregate_failures, feature_ca
expect(rendered).to have_selector('.js-invite-group-trigger')
expect(rendered).to have_selector('.js-invite-members-trigger')
expect(rendered).not_to have_content('Members can be added by project')
- expect(response).to render_template(partial: 'projects/_invite_members_modal')
end
context 'when project is not allowed to share with group' do
diff --git a/spec/workers/admin_email_worker_spec.rb b/spec/workers/admin_email_worker_spec.rb
index 1a5cb90bc17..bedf8f0362f 100644
--- a/spec/workers/admin_email_worker_spec.rb
+++ b/spec/workers/admin_email_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AdminEmailWorker do
+RSpec.describe AdminEmailWorker, feature_category: :source_code_management do
subject(:worker) { described_class.new }
describe '.perform' do
diff --git a/spec/workers/analytics/usage_trends/count_job_trigger_worker_spec.rb b/spec/workers/analytics/usage_trends/count_job_trigger_worker_spec.rb
index 735e4a214a9..cdb7357c184 100644
--- a/spec/workers/analytics/usage_trends/count_job_trigger_worker_spec.rb
+++ b/spec/workers/analytics/usage_trends/count_job_trigger_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Analytics::UsageTrends::CountJobTriggerWorker do
+RSpec.describe Analytics::UsageTrends::CountJobTriggerWorker, feature_category: :devops_reports do
it_behaves_like 'an idempotent worker'
context 'triggers a job for each measurement identifiers' do
diff --git a/spec/workers/analytics/usage_trends/counter_job_worker_spec.rb b/spec/workers/analytics/usage_trends/counter_job_worker_spec.rb
index ee1bbafa9b5..4155e3522a7 100644
--- a/spec/workers/analytics/usage_trends/counter_job_worker_spec.rb
+++ b/spec/workers/analytics/usage_trends/counter_job_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Analytics::UsageTrends::CounterJobWorker do
+RSpec.describe Analytics::UsageTrends::CounterJobWorker, feature_category: :devops_reports do
let_it_be(:user_1) { create(:user) }
let_it_be(:user_2) { create(:user) }
diff --git a/spec/workers/approve_blocked_pending_approval_users_worker_spec.rb b/spec/workers/approve_blocked_pending_approval_users_worker_spec.rb
index bd603bd870d..ffcc58132db 100644
--- a/spec/workers/approve_blocked_pending_approval_users_worker_spec.rb
+++ b/spec/workers/approve_blocked_pending_approval_users_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ApproveBlockedPendingApprovalUsersWorker, type: :worker do
+RSpec.describe ApproveBlockedPendingApprovalUsersWorker, type: :worker, feature_category: :user_profile do
let_it_be(:admin) { create(:admin) }
let_it_be(:active_user) { create(:user) }
let_it_be(:blocked_user) { create(:user, state: 'blocked_pending_approval') }
diff --git a/spec/workers/authorized_keys_worker_spec.rb b/spec/workers/authorized_keys_worker_spec.rb
index 50236f9ea7b..9fab6910441 100644
--- a/spec/workers/authorized_keys_worker_spec.rb
+++ b/spec/workers/authorized_keys_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedKeysWorker do
+RSpec.describe AuthorizedKeysWorker, feature_category: :source_code_management do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb b/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb
index 9d4d48d0568..77c56497ef0 100644
--- a/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb
+++ b/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::PeriodicRecalculateWorker do
+RSpec.describe AuthorizedProjectUpdate::PeriodicRecalculateWorker, feature_category: :source_code_management do
describe '#perform' do
it 'calls AuthorizedProjectUpdate::PeriodicRecalculateService' do
expect_next_instance_of(AuthorizedProjectUpdate::PeriodicRecalculateService) do |service|
diff --git a/spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb b/spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb
index 57a0726000f..5dcb4a67ae4 100644
--- a/spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb
+++ b/spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker do
+RSpec.describe AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker, feature_category: :system_access do
include ExclusiveLeaseHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/workers/authorized_project_update/project_recalculate_worker_spec.rb b/spec/workers/authorized_project_update/project_recalculate_worker_spec.rb
index a9a15565580..7c9d2891b01 100644
--- a/spec/workers/authorized_project_update/project_recalculate_worker_spec.rb
+++ b/spec/workers/authorized_project_update/project_recalculate_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::ProjectRecalculateWorker do
+RSpec.describe AuthorizedProjectUpdate::ProjectRecalculateWorker, feature_category: :system_access do
include ExclusiveLeaseHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/workers/authorized_project_update/user_refresh_from_replica_worker_spec.rb b/spec/workers/authorized_project_update/user_refresh_from_replica_worker_spec.rb
index da4b726c0b5..e6a312d34ce 100644
--- a/spec/workers/authorized_project_update/user_refresh_from_replica_worker_spec.rb
+++ b/spec/workers/authorized_project_update/user_refresh_from_replica_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::UserRefreshFromReplicaWorker do
+RSpec.describe AuthorizedProjectUpdate::UserRefreshFromReplicaWorker, feature_category: :system_access do
let_it_be(:project) { create(:project) }
let_it_be(:user) { project.namespace.owner }
diff --git a/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb b/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb
index 7c0c4d5bab4..081bece09e9 100644
--- a/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb
+++ b/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::UserRefreshOverUserRangeWorker do
+RSpec.describe AuthorizedProjectUpdate::UserRefreshOverUserRangeWorker, feature_category: :system_access do
let_it_be(:project) { create(:project) }
let(:user) { project.namespace.owner }
diff --git a/spec/workers/authorized_project_update/user_refresh_with_low_urgency_worker_spec.rb b/spec/workers/authorized_project_update/user_refresh_with_low_urgency_worker_spec.rb
index bd16eeb4712..ef6c3dd43c8 100644
--- a/spec/workers/authorized_project_update/user_refresh_with_low_urgency_worker_spec.rb
+++ b/spec/workers/authorized_project_update/user_refresh_with_low_urgency_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker do
+RSpec.describe AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker, feature_category: :system_access do
it 'is labeled as low urgency' do
expect(described_class.get_urgency).to eq(:low)
end
diff --git a/spec/workers/authorized_projects_worker_spec.rb b/spec/workers/authorized_projects_worker_spec.rb
index fbfde77be97..ea009f06a28 100644
--- a/spec/workers/authorized_projects_worker_spec.rb
+++ b/spec/workers/authorized_projects_worker_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe AuthorizedProjectsWorker do
+RSpec.describe AuthorizedProjectsWorker, feature_category: :system_access do
it_behaves_like "refreshes user's project authorizations"
end
diff --git a/spec/workers/auto_devops/disable_worker_spec.rb b/spec/workers/auto_devops/disable_worker_spec.rb
index e1de97e0ce5..8f7f305b186 100644
--- a/spec/workers/auto_devops/disable_worker_spec.rb
+++ b/spec/workers/auto_devops/disable_worker_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe AutoDevops::DisableWorker, '#perform' do
+RSpec.describe AutoDevops::DisableWorker, '#perform', feature_category: :auto_devops do
let(:user) { create(:user, developer_projects: [project]) }
let(:project) { create(:project, :repository, :auto_devops) }
let(:auto_devops) { project.auto_devops }
diff --git a/spec/workers/auto_merge_process_worker_spec.rb b/spec/workers/auto_merge_process_worker_spec.rb
index 00d27d9c2b5..550590ff6a3 100644
--- a/spec/workers/auto_merge_process_worker_spec.rb
+++ b/spec/workers/auto_merge_process_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe AutoMergeProcessWorker do
+RSpec.describe AutoMergeProcessWorker, feature_category: :continuous_delivery do
describe '#perform' do
subject { described_class.new.perform(merge_request&.id) }
diff --git a/spec/workers/background_migration/ci_database_worker_spec.rb b/spec/workers/background_migration/ci_database_worker_spec.rb
index 82c562c4042..1048a06bb12 100644
--- a/spec/workers/background_migration/ci_database_worker_spec.rb
+++ b/spec/workers/background_migration/ci_database_worker_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe BackgroundMigration::CiDatabaseWorker, :clean_gitlab_redis_shared_state, if: Gitlab::Database.has_config?(:ci) do
+RSpec.describe BackgroundMigration::CiDatabaseWorker, :clean_gitlab_redis_shared_state, if: Gitlab::Database.has_config?(:ci), feature_category: :database do
it_behaves_like 'it runs background migration jobs', 'ci'
end
diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb
index 1558c3c9250..32ee6708736 100644
--- a/spec/workers/background_migration_worker_spec.rb
+++ b/spec/workers/background_migration_worker_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe BackgroundMigrationWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe BackgroundMigrationWorker, :clean_gitlab_redis_shared_state, feature_category: :database do
it_behaves_like 'it runs background migration jobs', 'main'
end
diff --git a/spec/workers/build_hooks_worker_spec.rb b/spec/workers/build_hooks_worker_spec.rb
index 80dc36d268f..f8efc9c455d 100644
--- a/spec/workers/build_hooks_worker_spec.rb
+++ b/spec/workers/build_hooks_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BuildHooksWorker do
+RSpec.describe BuildHooksWorker, feature_category: :continuous_integration do
describe '#perform' do
context 'when build exists' do
let!(:build) { create(:ci_build) }
diff --git a/spec/workers/build_queue_worker_spec.rb b/spec/workers/build_queue_worker_spec.rb
index 0786722e647..1f3640e7496 100644
--- a/spec/workers/build_queue_worker_spec.rb
+++ b/spec/workers/build_queue_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BuildQueueWorker do
+RSpec.describe BuildQueueWorker, feature_category: :continuous_integration do
describe '#perform' do
context 'when build exists' do
let!(:build) { create(:ci_build) }
diff --git a/spec/workers/build_success_worker_spec.rb b/spec/workers/build_success_worker_spec.rb
index 3241c931dc5..be9802eb2ce 100644
--- a/spec/workers/build_success_worker_spec.rb
+++ b/spec/workers/build_success_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BuildSuccessWorker do
+RSpec.describe BuildSuccessWorker, feature_category: :continuous_integration do
describe '#perform' do
subject { described_class.new.perform(build.id) }
diff --git a/spec/workers/bulk_imports/entity_worker_spec.rb b/spec/workers/bulk_imports/entity_worker_spec.rb
index 4cd37c93d5f..dada4ef63b3 100644
--- a/spec/workers/bulk_imports/entity_worker_spec.rb
+++ b/spec/workers/bulk_imports/entity_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::EntityWorker do
+RSpec.describe BulkImports::EntityWorker, feature_category: :importers do
let_it_be(:entity) { create(:bulk_import_entity) }
let_it_be(:pipeline_tracker) do
diff --git a/spec/workers/bulk_imports/relation_export_worker_spec.rb b/spec/workers/bulk_imports/relation_export_worker_spec.rb
index 63f1992d186..c2f7831896b 100644
--- a/spec/workers/bulk_imports/relation_export_worker_spec.rb
+++ b/spec/workers/bulk_imports/relation_export_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::RelationExportWorker do
+RSpec.describe BulkImports::RelationExportWorker, feature_category: :importers do
let_it_be(:jid) { 'jid' }
let_it_be(:relation) { 'labels' }
let_it_be(:user) { create(:user) }
diff --git a/spec/workers/bulk_imports/stuck_import_worker_spec.rb b/spec/workers/bulk_imports/stuck_import_worker_spec.rb
index 7dfb6532c07..ba1b1b66b00 100644
--- a/spec/workers/bulk_imports/stuck_import_worker_spec.rb
+++ b/spec/workers/bulk_imports/stuck_import_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::StuckImportWorker do
+RSpec.describe BulkImports::StuckImportWorker, feature_category: :importers do
let_it_be(:created_bulk_import) { create(:bulk_import, :created) }
let_it_be(:started_bulk_import) { create(:bulk_import, :started) }
let_it_be(:stale_created_bulk_import) { create(:bulk_import, :created, created_at: 3.days.ago) }
diff --git a/spec/workers/chat_notification_worker_spec.rb b/spec/workers/chat_notification_worker_spec.rb
index a20a136d197..a9413a94e4b 100644
--- a/spec/workers/chat_notification_worker_spec.rb
+++ b/spec/workers/chat_notification_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ChatNotificationWorker do
+RSpec.describe ChatNotificationWorker, feature_category: :integrations do
let(:worker) { described_class.new }
let(:chat_build) do
create(:ci_build, pipeline: create(:ci_pipeline, source: :chat))
diff --git a/spec/workers/ci/archive_trace_worker_spec.rb b/spec/workers/ci/archive_trace_worker_spec.rb
index 3ac769aab9e..056093f01b4 100644
--- a/spec/workers/ci/archive_trace_worker_spec.rb
+++ b/spec/workers/ci/archive_trace_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ArchiveTraceWorker do
+RSpec.describe Ci::ArchiveTraceWorker, feature_category: :continuous_integration do
describe '#perform' do
subject { described_class.new.perform(job&.id) }
diff --git a/spec/workers/ci/archive_traces_cron_worker_spec.rb b/spec/workers/ci/archive_traces_cron_worker_spec.rb
index 0c1010960a1..1eb88258c62 100644
--- a/spec/workers/ci/archive_traces_cron_worker_spec.rb
+++ b/spec/workers/ci/archive_traces_cron_worker_spec.rb
@@ -42,20 +42,6 @@ RSpec.describe Ci::ArchiveTracesCronWorker, feature_category: :continuous_integr
subject
end
- context "with FF deduplicate_archive_traces_cron_worker false" do
- before do
- stub_feature_flags(deduplicate_archive_traces_cron_worker: false)
- end
-
- it 'calls execute service' do
- expect_next_instance_of(Ci::ArchiveTraceService) do |instance|
- expect(instance).to receive(:execute).with(build, worker_name: "Ci::ArchiveTracesCronWorker")
- end
-
- subject
- end
- end
-
context 'when the job finished recently' do
let(:finished_at) { 1.hour.ago }
diff --git a/spec/workers/ci/build_finished_worker_spec.rb b/spec/workers/ci/build_finished_worker_spec.rb
index 049f3af1dd7..6da30a86b54 100644
--- a/spec/workers/ci/build_finished_worker_spec.rb
+++ b/spec/workers/ci/build_finished_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::BuildFinishedWorker do
+RSpec.describe Ci::BuildFinishedWorker, feature_category: :continuous_integration do
include AfterNextHelpers
subject { described_class.new.perform(build.id) }
diff --git a/spec/workers/ci/build_prepare_worker_spec.rb b/spec/workers/ci/build_prepare_worker_spec.rb
index b2c74a920ea..d3d607d8f39 100644
--- a/spec/workers/ci/build_prepare_worker_spec.rb
+++ b/spec/workers/ci/build_prepare_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::BuildPrepareWorker do
+RSpec.describe Ci::BuildPrepareWorker, feature_category: :continuous_integration do
subject { described_class.new.perform(build_id) }
context 'build exists' do
diff --git a/spec/workers/ci/build_schedule_worker_spec.rb b/spec/workers/ci/build_schedule_worker_spec.rb
index f8b4efc562b..f0d43ef810d 100644
--- a/spec/workers/ci/build_schedule_worker_spec.rb
+++ b/spec/workers/ci/build_schedule_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::BuildScheduleWorker do
+RSpec.describe Ci::BuildScheduleWorker, feature_category: :continuous_integration do
subject { described_class.new.perform(build.id) }
context 'when build is found' do
diff --git a/spec/workers/ci/build_trace_chunk_flush_worker_spec.rb b/spec/workers/ci/build_trace_chunk_flush_worker_spec.rb
index 8aac80a02be..851b8f6bc90 100644
--- a/spec/workers/ci/build_trace_chunk_flush_worker_spec.rb
+++ b/spec/workers/ci/build_trace_chunk_flush_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::BuildTraceChunkFlushWorker do
+RSpec.describe Ci::BuildTraceChunkFlushWorker, feature_category: :continuous_integration do
let(:data) { 'x' * Ci::BuildTraceChunk::CHUNK_SIZE }
let(:chunk) do
diff --git a/spec/workers/ci/cancel_pipeline_worker_spec.rb b/spec/workers/ci/cancel_pipeline_worker_spec.rb
index 6165aaff1c7..874273a39e1 100644
--- a/spec/workers/ci/cancel_pipeline_worker_spec.rb
+++ b/spec/workers/ci/cancel_pipeline_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CancelPipelineWorker, :aggregate_failures do
+RSpec.describe Ci::CancelPipelineWorker, :aggregate_failures, feature_category: :continuous_integration do
let!(:pipeline) { create(:ci_pipeline, :running) }
describe '#perform' do
diff --git a/spec/workers/ci/create_cross_project_pipeline_worker_spec.rb b/spec/workers/ci/create_cross_project_pipeline_worker_spec.rb
index 372b0de1b54..6f4bfe897a8 100644
--- a/spec/workers/ci/create_cross_project_pipeline_worker_spec.rb
+++ b/spec/workers/ci/create_cross_project_pipeline_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CreateCrossProjectPipelineWorker do
+RSpec.describe Ci::CreateCrossProjectPipelineWorker, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/workers/ci/create_downstream_pipeline_worker_spec.rb b/spec/workers/ci/create_downstream_pipeline_worker_spec.rb
index b4add681e67..bb763e68504 100644
--- a/spec/workers/ci/create_downstream_pipeline_worker_spec.rb
+++ b/spec/workers/ci/create_downstream_pipeline_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CreateDownstreamPipelineWorker do
+RSpec.describe Ci::CreateDownstreamPipelineWorker, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/workers/ci/daily_build_group_report_results_worker_spec.rb b/spec/workers/ci/daily_build_group_report_results_worker_spec.rb
index e13c6311e46..3d86ff6999b 100644
--- a/spec/workers/ci/daily_build_group_report_results_worker_spec.rb
+++ b/spec/workers/ci/daily_build_group_report_results_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DailyBuildGroupReportResultsWorker do
+RSpec.describe Ci::DailyBuildGroupReportResultsWorker, feature_category: :code_testing do
describe '#perform' do
let!(:pipeline) { create(:ci_pipeline) }
diff --git a/spec/workers/ci/delete_objects_worker_spec.rb b/spec/workers/ci/delete_objects_worker_spec.rb
index 3d985dffdc5..808ad95531e 100644
--- a/spec/workers/ci/delete_objects_worker_spec.rb
+++ b/spec/workers/ci/delete_objects_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DeleteObjectsWorker do
+RSpec.describe Ci::DeleteObjectsWorker, feature_category: :continuous_integration do
let(:worker) { described_class.new }
it { expect(described_class.idempotent?).to be_truthy }
diff --git a/spec/workers/ci/delete_unit_tests_worker_spec.rb b/spec/workers/ci/delete_unit_tests_worker_spec.rb
index ff2575b19c1..ae8fe762334 100644
--- a/spec/workers/ci/delete_unit_tests_worker_spec.rb
+++ b/spec/workers/ci/delete_unit_tests_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DeleteUnitTestsWorker do
+RSpec.describe Ci::DeleteUnitTestsWorker, feature_category: :code_testing do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/ci/drop_pipeline_worker_spec.rb b/spec/workers/ci/drop_pipeline_worker_spec.rb
index 5e626112520..23ae95ee53a 100644
--- a/spec/workers/ci/drop_pipeline_worker_spec.rb
+++ b/spec/workers/ci/drop_pipeline_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DropPipelineWorker do
+RSpec.describe Ci::DropPipelineWorker, feature_category: :continuous_integration do
include AfterNextHelpers
let(:pipeline) { create(:ci_pipeline, :running) }
diff --git a/spec/workers/ci/job_artifacts/expire_project_build_artifacts_worker_spec.rb b/spec/workers/ci/job_artifacts/expire_project_build_artifacts_worker_spec.rb
index 0460738f3f2..9d4e5380474 100644
--- a/spec/workers/ci/job_artifacts/expire_project_build_artifacts_worker_spec.rb
+++ b/spec/workers/ci/job_artifacts/expire_project_build_artifacts_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::ExpireProjectBuildArtifactsWorker do
+RSpec.describe Ci::JobArtifacts::ExpireProjectBuildArtifactsWorker, feature_category: :build_artifacts do
let(:worker) { described_class.new }
let(:current_time) { Time.current }
diff --git a/spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb b/spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb
index 0d4b8243050..bbc2bcf9ac9 100644
--- a/spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb
+++ b/spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifacts::TrackArtifactReportWorker do
+RSpec.describe Ci::JobArtifacts::TrackArtifactReportWorker, feature_category: :code_testing do
describe '#perform', :clean_gitlab_redis_shared_state do
let_it_be(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, group: group) }
diff --git a/spec/workers/ci/merge_requests/add_todo_when_build_fails_worker_spec.rb b/spec/workers/ci/merge_requests/add_todo_when_build_fails_worker_spec.rb
index e5de0ba0143..ec12ee845a4 100644
--- a/spec/workers/ci/merge_requests/add_todo_when_build_fails_worker_spec.rb
+++ b/spec/workers/ci/merge_requests/add_todo_when_build_fails_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::MergeRequests::AddTodoWhenBuildFailsWorker do
+RSpec.describe Ci::MergeRequests::AddTodoWhenBuildFailsWorker, feature_category: :code_review_workflow do
describe '#perform' do
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, :detached_merge_request_pipeline) }
diff --git a/spec/workers/ci/parse_secure_file_metadata_worker_spec.rb b/spec/workers/ci/parse_secure_file_metadata_worker_spec.rb
index 57bbd8a6ff0..11a01352fcc 100644
--- a/spec/workers/ci/parse_secure_file_metadata_worker_spec.rb
+++ b/spec/workers/ci/parse_secure_file_metadata_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ParseSecureFileMetadataWorker do
+RSpec.describe Ci::ParseSecureFileMetadataWorker, feature_category: :mobile_devops do
describe '#perform' do
include_examples 'an idempotent worker' do
let(:secure_file) { create(:ci_secure_file) }
diff --git a/spec/workers/ci/pending_builds/update_group_worker_spec.rb b/spec/workers/ci/pending_builds/update_group_worker_spec.rb
index 8c6bf018158..c16262c0502 100644
--- a/spec/workers/ci/pending_builds/update_group_worker_spec.rb
+++ b/spec/workers/ci/pending_builds/update_group_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PendingBuilds::UpdateGroupWorker do
+RSpec.describe Ci::PendingBuilds::UpdateGroupWorker, feature_category: :subgroups do
describe '#perform' do
let(:worker) { described_class.new }
diff --git a/spec/workers/ci/pending_builds/update_project_worker_spec.rb b/spec/workers/ci/pending_builds/update_project_worker_spec.rb
index 4a67127564e..281b4fb920b 100644
--- a/spec/workers/ci/pending_builds/update_project_worker_spec.rb
+++ b/spec/workers/ci/pending_builds/update_project_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PendingBuilds::UpdateProjectWorker do
+RSpec.describe Ci::PendingBuilds::UpdateProjectWorker, feature_category: :projects do
describe '#perform' do
let(:worker) { described_class.new }
diff --git a/spec/workers/ci/pipeline_artifacts/coverage_report_worker_spec.rb b/spec/workers/ci/pipeline_artifacts/coverage_report_worker_spec.rb
index 7b28384a5bf..b594f661a9a 100644
--- a/spec/workers/ci/pipeline_artifacts/coverage_report_worker_spec.rb
+++ b/spec/workers/ci/pipeline_artifacts/coverage_report_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineArtifacts::CoverageReportWorker do
+RSpec.describe Ci::PipelineArtifacts::CoverageReportWorker, feature_category: :code_testing do
describe '#perform' do
let(:pipeline_id) { pipeline.id }
diff --git a/spec/workers/ci/pipeline_artifacts/create_quality_report_worker_spec.rb b/spec/workers/ci/pipeline_artifacts/create_quality_report_worker_spec.rb
index 5096691270a..2ad1609c7c4 100644
--- a/spec/workers/ci/pipeline_artifacts/create_quality_report_worker_spec.rb
+++ b/spec/workers/ci/pipeline_artifacts/create_quality_report_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::PipelineArtifacts::CreateQualityReportWorker do
+RSpec.describe ::Ci::PipelineArtifacts::CreateQualityReportWorker, feature_category: :code_quality do
describe '#perform' do
subject { described_class.new.perform(pipeline_id) }
diff --git a/spec/workers/ci/pipeline_artifacts/expire_artifacts_worker_spec.rb b/spec/workers/ci/pipeline_artifacts/expire_artifacts_worker_spec.rb
index 274f848ad88..ca4fcc564fa 100644
--- a/spec/workers/ci/pipeline_artifacts/expire_artifacts_worker_spec.rb
+++ b/spec/workers/ci/pipeline_artifacts/expire_artifacts_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineArtifacts::ExpireArtifactsWorker do
+RSpec.describe Ci::PipelineArtifacts::ExpireArtifactsWorker, feature_category: :build_artifacts do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/ci/pipeline_bridge_status_worker_spec.rb b/spec/workers/ci/pipeline_bridge_status_worker_spec.rb
index 6ec5eb0e639..4662b25a3cb 100644
--- a/spec/workers/ci/pipeline_bridge_status_worker_spec.rb
+++ b/spec/workers/ci/pipeline_bridge_status_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineBridgeStatusWorker do
+RSpec.describe Ci::PipelineBridgeStatusWorker, feature_category: :continuous_integration do
describe '#perform' do
subject { described_class.new.perform(pipeline_id) }
diff --git a/spec/workers/ci/pipeline_success_unlock_artifacts_worker_spec.rb b/spec/workers/ci/pipeline_success_unlock_artifacts_worker_spec.rb
index 3b33972c76f..70821f3a833 100644
--- a/spec/workers/ci/pipeline_success_unlock_artifacts_worker_spec.rb
+++ b/spec/workers/ci/pipeline_success_unlock_artifacts_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineSuccessUnlockArtifactsWorker do
+RSpec.describe Ci::PipelineSuccessUnlockArtifactsWorker, feature_category: :build_artifacts do
describe '#perform' do
subject(:perform) { described_class.new.perform(pipeline_id) }
diff --git a/spec/workers/ci/ref_delete_unlock_artifacts_worker_spec.rb b/spec/workers/ci/ref_delete_unlock_artifacts_worker_spec.rb
index f14b7f9d1d0..ede4dad1272 100644
--- a/spec/workers/ci/ref_delete_unlock_artifacts_worker_spec.rb
+++ b/spec/workers/ci/ref_delete_unlock_artifacts_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::RefDeleteUnlockArtifactsWorker do
+RSpec.describe Ci::RefDeleteUnlockArtifactsWorker, feature_category: :build_artifacts do
describe '#perform' do
subject(:perform) { worker.perform(project_id, user_id, ref) }
diff --git a/spec/workers/ci/resource_groups/assign_resource_from_resource_group_worker_spec.rb b/spec/workers/ci/resource_groups/assign_resource_from_resource_group_worker_spec.rb
index 785cba24f9d..e3e7047db56 100644
--- a/spec/workers/ci/resource_groups/assign_resource_from_resource_group_worker_spec.rb
+++ b/spec/workers/ci/resource_groups/assign_resource_from_resource_group_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupWorker do
+RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupWorker, feature_category: :continuous_delivery do
let(:worker) { described_class.new }
it 'has the `until_executed` deduplicate strategy' do
diff --git a/spec/workers/ci/retry_pipeline_worker_spec.rb b/spec/workers/ci/retry_pipeline_worker_spec.rb
index c7600a24280..f41b6b88c6f 100644
--- a/spec/workers/ci/retry_pipeline_worker_spec.rb
+++ b/spec/workers/ci/retry_pipeline_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::RetryPipelineWorker do
+RSpec.describe Ci::RetryPipelineWorker, feature_category: :continuous_integration do
describe '#perform' do
subject(:perform) { described_class.new.perform(pipeline_id, user_id) }
diff --git a/spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb b/spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb
index 142df271f90..cab282df5f2 100644
--- a/spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb
+++ b/spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::ScheduleDeleteObjectsCronWorker do
+RSpec.describe Ci::ScheduleDeleteObjectsCronWorker, feature_category: :continuous_integration do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/ci/stuck_builds/drop_running_worker_spec.rb b/spec/workers/ci/stuck_builds/drop_running_worker_spec.rb
index 6d3aa71fe81..6823686997f 100644
--- a/spec/workers/ci/stuck_builds/drop_running_worker_spec.rb
+++ b/spec/workers/ci/stuck_builds/drop_running_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::StuckBuilds::DropRunningWorker do
+RSpec.describe Ci::StuckBuilds::DropRunningWorker, feature_category: :continuous_integration do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new }
diff --git a/spec/workers/ci/stuck_builds/drop_scheduled_worker_spec.rb b/spec/workers/ci/stuck_builds/drop_scheduled_worker_spec.rb
index 57be799d890..58b07d11d33 100644
--- a/spec/workers/ci/stuck_builds/drop_scheduled_worker_spec.rb
+++ b/spec/workers/ci/stuck_builds/drop_scheduled_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::StuckBuilds::DropScheduledWorker do
+RSpec.describe Ci::StuckBuilds::DropScheduledWorker, feature_category: :continuous_integration do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new }
diff --git a/spec/workers/ci/test_failure_history_worker_spec.rb b/spec/workers/ci/test_failure_history_worker_spec.rb
index 7530077d4ad..bf8ec44ce4d 100644
--- a/spec/workers/ci/test_failure_history_worker_spec.rb
+++ b/spec/workers/ci/test_failure_history_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::TestFailureHistoryWorker do
+RSpec.describe ::Ci::TestFailureHistoryWorker, feature_category: :static_application_security_testing do
describe '#perform' do
subject(:perform) { described_class.new.perform(pipeline_id) }
diff --git a/spec/workers/ci/track_failed_build_worker_spec.rb b/spec/workers/ci/track_failed_build_worker_spec.rb
index 12d0e64afc5..5d12e86d844 100644
--- a/spec/workers/ci/track_failed_build_worker_spec.rb
+++ b/spec/workers/ci/track_failed_build_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::TrackFailedBuildWorker do
+RSpec.describe ::Ci::TrackFailedBuildWorker, feature_category: :static_application_security_testing do
let_it_be(:build) { create(:ci_build, :failed, :sast_report) }
let_it_be(:exit_code) { 42 }
let_it_be(:failure_reason) { "script_failure" }
diff --git a/spec/workers/ci/update_locked_unknown_artifacts_worker_spec.rb b/spec/workers/ci/update_locked_unknown_artifacts_worker_spec.rb
index b42d135b1b6..4bb1d3561f9 100644
--- a/spec/workers/ci/update_locked_unknown_artifacts_worker_spec.rb
+++ b/spec/workers/ci/update_locked_unknown_artifacts_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::UpdateLockedUnknownArtifactsWorker do
+RSpec.describe Ci::UpdateLockedUnknownArtifactsWorker, feature_category: :build_artifacts do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/ci_platform_metrics_update_cron_worker_spec.rb b/spec/workers/ci_platform_metrics_update_cron_worker_spec.rb
index 0bb6822a0a5..ac00956e1c0 100644
--- a/spec/workers/ci_platform_metrics_update_cron_worker_spec.rb
+++ b/spec/workers/ci_platform_metrics_update_cron_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CiPlatformMetricsUpdateCronWorker, type: :worker do
+RSpec.describe CiPlatformMetricsUpdateCronWorker, type: :worker, feature_category: :continuous_integration do
describe '#perform' do
subject { described_class.new.perform }
diff --git a/spec/workers/cleanup_container_repository_worker_spec.rb b/spec/workers/cleanup_container_repository_worker_spec.rb
index 817b71c8cc6..c970c9ef842 100644
--- a/spec/workers/cleanup_container_repository_worker_spec.rb
+++ b/spec/workers/cleanup_container_repository_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CleanupContainerRepositoryWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe CleanupContainerRepositoryWorker, :clean_gitlab_redis_shared_state, feature_category: :container_registry do
let(:repository) { create(:container_repository) }
let(:project) { repository.project }
let(:user) { project.first_owner }
diff --git a/spec/workers/clusters/agents/delete_expired_events_worker_spec.rb b/spec/workers/clusters/agents/delete_expired_events_worker_spec.rb
index 1a5ca744091..b439df4e119 100644
--- a/spec/workers/clusters/agents/delete_expired_events_worker_spec.rb
+++ b/spec/workers/clusters/agents/delete_expired_events_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::DeleteExpiredEventsWorker do
+RSpec.describe Clusters::Agents::DeleteExpiredEventsWorker, feature_category: :kubernetes_management do
let(:agent) { create(:cluster_agent) }
describe '#perform' do
diff --git a/spec/workers/clusters/applications/activate_integration_worker_spec.rb b/spec/workers/clusters/applications/activate_integration_worker_spec.rb
index 5163e4681fa..40a774e1818 100644
--- a/spec/workers/clusters/applications/activate_integration_worker_spec.rb
+++ b/spec/workers/clusters/applications/activate_integration_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Applications::ActivateIntegrationWorker, '#perform' do
+RSpec.describe Clusters::Applications::ActivateIntegrationWorker, '#perform', feature_category: :kubernetes_management do
context 'when cluster exists' do
describe 'prometheus integration' do
let(:integration_name) { 'prometheus' }
diff --git a/spec/workers/clusters/applications/deactivate_integration_worker_spec.rb b/spec/workers/clusters/applications/deactivate_integration_worker_spec.rb
index 62792a3b7d9..f02ad18c7cc 100644
--- a/spec/workers/clusters/applications/deactivate_integration_worker_spec.rb
+++ b/spec/workers/clusters/applications/deactivate_integration_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Applications::DeactivateIntegrationWorker, '#perform' do
+RSpec.describe Clusters::Applications::DeactivateIntegrationWorker, '#perform', feature_category: :kubernetes_management do
context 'when cluster exists' do
describe 'prometheus integration' do
let(:integration_name) { 'prometheus' }
diff --git a/spec/workers/clusters/cleanup/project_namespace_worker_spec.rb b/spec/workers/clusters/cleanup/project_namespace_worker_spec.rb
index c24ca71eb35..15fc9e8678e 100644
--- a/spec/workers/clusters/cleanup/project_namespace_worker_spec.rb
+++ b/spec/workers/clusters/cleanup/project_namespace_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Cleanup::ProjectNamespaceWorker do
+RSpec.describe Clusters::Cleanup::ProjectNamespaceWorker, feature_category: :kubernetes_management do
describe '#perform' do
context 'when cluster.cleanup_status is cleanup_removing_project_namespaces' do
let!(:cluster) { create(:cluster, :with_environments, :cleanup_removing_project_namespaces) }
diff --git a/spec/workers/clusters/cleanup/service_account_worker_spec.rb b/spec/workers/clusters/cleanup/service_account_worker_spec.rb
index dabc32a0ccd..0d4df795278 100644
--- a/spec/workers/clusters/cleanup/service_account_worker_spec.rb
+++ b/spec/workers/clusters/cleanup/service_account_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Cleanup::ServiceAccountWorker do
+RSpec.describe Clusters::Cleanup::ServiceAccountWorker, feature_category: :kubernetes_management do
describe '#perform' do
let!(:cluster) { create(:cluster, :cleanup_removing_service_account) }
diff --git a/spec/workers/clusters/integrations/check_prometheus_health_worker_spec.rb b/spec/workers/clusters/integrations/check_prometheus_health_worker_spec.rb
index 6f70870bd09..1f5892a36da 100644
--- a/spec/workers/clusters/integrations/check_prometheus_health_worker_spec.rb
+++ b/spec/workers/clusters/integrations/check_prometheus_health_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Integrations::CheckPrometheusHealthWorker, '#perform' do
+RSpec.describe Clusters::Integrations::CheckPrometheusHealthWorker, '#perform', feature_category: :incident_management do
subject { described_class.new.perform }
it 'triggers health service' do
diff --git a/spec/workers/concerns/application_worker_spec.rb b/spec/workers/concerns/application_worker_spec.rb
index 0abb029f146..e4df91adef2 100644
--- a/spec/workers/concerns/application_worker_spec.rb
+++ b/spec/workers/concerns/application_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ApplicationWorker do
+RSpec.describe ApplicationWorker, feature_category: :shared do
# We depend on the lazy-load characteristic of rspec. If the worker is loaded
# before setting up, it's likely to go wrong. Consider this catcha:
# before do
diff --git a/spec/workers/concerns/cluster_agent_queue_spec.rb b/spec/workers/concerns/cluster_agent_queue_spec.rb
index b5189cbd8c8..c30616d04e1 100644
--- a/spec/workers/concerns/cluster_agent_queue_spec.rb
+++ b/spec/workers/concerns/cluster_agent_queue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ClusterAgentQueue do
+RSpec.describe ClusterAgentQueue, feature_category: :kubernetes_management do
let(:worker) do
Class.new do
def self.name
@@ -14,6 +14,5 @@ RSpec.describe ClusterAgentQueue do
end
end
- it { expect(worker.queue).to eq('cluster_agent:example') }
it { expect(worker.get_feature_category).to eq(:kubernetes_management) }
end
diff --git a/spec/workers/concerns/cluster_queue_spec.rb b/spec/workers/concerns/cluster_queue_spec.rb
deleted file mode 100644
index c03ca9cea48..00000000000
--- a/spec/workers/concerns/cluster_queue_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ClusterQueue do
- let(:worker) do
- Class.new do
- def self.name
- 'DummyWorker'
- end
-
- include ApplicationWorker
- include ClusterQueue
- end
- end
-
- it 'sets a default pipelines queue automatically' do
- expect(worker.sidekiq_options['queue'])
- .to eq 'gcp_cluster:dummy'
- end
-end
diff --git a/spec/workers/concerns/cronjob_queue_spec.rb b/spec/workers/concerns/cronjob_queue_spec.rb
index 0244535051f..7e00093b686 100644
--- a/spec/workers/concerns/cronjob_queue_spec.rb
+++ b/spec/workers/concerns/cronjob_queue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CronjobQueue do
+RSpec.describe CronjobQueue, feature_category: :shared do
let(:worker) do
Class.new do
def self.name
@@ -40,10 +40,6 @@ RSpec.describe CronjobQueue do
stub_const("AnotherWorker", another_worker)
end
- it 'sets the queue name of a worker' do
- expect(worker.sidekiq_options['queue'].to_s).to eq('cronjob:dummy')
- end
-
it 'disables retrying of failed jobs' do
expect(worker.sidekiq_options['retry']).to eq(false)
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 02190201986..f72caf3a8c2 100644
--- a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures do
+RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures, feature_category: :importers do
let(:worker) do
Class.new do
def self.name
@@ -196,6 +196,19 @@ RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures do
end
context 'when the record is invalid' do
+ let(:exception) { ActiveRecord::RecordInvalid.new }
+
+ before do
+ expect(importer_class)
+ .to receive(:new)
+ .with(instance_of(MockRepresantation), project, client)
+ .and_return(importer_instance)
+
+ expect(importer_instance)
+ .to receive(:execute)
+ .and_raise(exception)
+ end
+
it 'logs an error' do
expect(Gitlab::GithubImport::Logger)
.to receive(:info)
@@ -208,16 +221,6 @@ RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures do
}
)
- expect(importer_class)
- .to receive(:new)
- .with(instance_of(MockRepresantation), project, client)
- .and_return(importer_instance)
-
- exception = ActiveRecord::RecordInvalid.new
- expect(importer_instance)
- .to receive(:execute)
- .and_raise(exception)
-
expect(Gitlab::Import::ImportFailureService)
.to receive(:track)
.with(
@@ -230,6 +233,15 @@ RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures do
worker.import(project, client, { 'number' => 10, 'github_id' => 1 })
end
+
+ it 'updates external_identifiers of the correct failure' do
+ worker.import(project, client, { 'number' => 10, 'github_id' => 1 })
+
+ import_failures = project.import_failures
+
+ expect(import_failures.count).to eq(1)
+ expect(import_failures.first.external_identifiers).to eq(github_identifiers.with_indifferent_access)
+ end
end
end
@@ -240,4 +252,56 @@ RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures do
expect(worker).to be_increment_object_counter(issue)
end
end
+
+ describe '.sidekiq_retries_exhausted' do
+ let(:correlation_id) { 'abc' }
+ let(:job) do
+ {
+ 'args' => [project.id, { number: 123, state: 'open' }, '123abc'],
+ 'jid' => '123',
+ 'correlation_id' => correlation_id
+ }
+ end
+
+ subject(:sidekiq_retries_exhausted) { worker.class.sidekiq_retries_exhausted_block.call(job, StandardError.new) }
+
+ context 'when all arguments are given' do
+ it 'notifies the JobWaiter' do
+ expect(Gitlab::JobWaiter)
+ .to receive(:notify)
+ .with(
+ job['args'].last,
+ job['jid']
+ )
+
+ sidekiq_retries_exhausted
+ end
+ end
+
+ context 'when not all arguments are given' do
+ let(:job) do
+ {
+ 'args' => [project.id, { number: 123, state: 'open' }],
+ 'jid' => '123',
+ 'correlation_id' => correlation_id
+ }
+ end
+
+ it 'does not notify the JobWaiter' do
+ expect(Gitlab::JobWaiter).not_to receive(:notify)
+
+ sidekiq_retries_exhausted
+ end
+ end
+
+ it 'updates external_identifiers of the correct failure' do
+ failure_1, failure_2 = create_list(:import_failure, 2, project: project)
+ failure_2.update_column(:correlation_id_value, correlation_id)
+
+ sidekiq_retries_exhausted
+
+ expect(failure_1.reload.external_identifiers).to be_empty
+ expect(failure_2.reload.external_identifiers).to eq(github_identifiers.with_indifferent_access)
+ end
+ end
end
diff --git a/spec/workers/concerns/gitlab/github_import/queue_spec.rb b/spec/workers/concerns/gitlab/github_import/queue_spec.rb
deleted file mode 100644
index beca221b593..00000000000
--- a/spec/workers/concerns/gitlab/github_import/queue_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::GithubImport::Queue do
- it 'sets the Sidekiq options for the worker' do
- worker = Class.new do
- def self.name
- 'DummyWorker'
- end
-
- include ApplicationWorker
- include Gitlab::GithubImport::Queue
- end
-
- expect(worker.sidekiq_options['queue']).to eq('github_importer:dummy')
- end
-end
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 8727756ce50..f7ba368f312 100644
--- a/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ReschedulingMethods do
+RSpec.describe Gitlab::GithubImport::ReschedulingMethods, feature_category: :importers do
let(:worker) do
Class.new { include(Gitlab::GithubImport::ReschedulingMethods) }.new
end
diff --git a/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb b/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
index 0ac1733781a..ce9a9db5dd9 100644
--- a/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::StageMethods do
+RSpec.describe Gitlab::GithubImport::StageMethods, feature_category: :importers do
let_it_be(:project) { create(:project, :import_started, import_url: 'https://t0ken@github.com/repo/repo.git') }
let_it_be(:project2) { create(:project, :import_canceled) }
diff --git a/spec/workers/concerns/gitlab/notify_upon_death_spec.rb b/spec/workers/concerns/gitlab/notify_upon_death_spec.rb
index dd0a1cadc9c..36faf3ee296 100644
--- a/spec/workers/concerns/gitlab/notify_upon_death_spec.rb
+++ b/spec/workers/concerns/gitlab/notify_upon_death_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::NotifyUponDeath do
+RSpec.describe Gitlab::NotifyUponDeath, feature_category: :shared do
let(:worker_class) do
Class.new do
include Sidekiq::Worker
diff --git a/spec/workers/concerns/limited_capacity/job_tracker_spec.rb b/spec/workers/concerns/limited_capacity/job_tracker_spec.rb
index 0e3fa350fcd..20635d1a045 100644
--- a/spec/workers/concerns/limited_capacity/job_tracker_spec.rb
+++ b/spec/workers/concerns/limited_capacity/job_tracker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe LimitedCapacity::JobTracker, :clean_gitlab_redis_shared_state do
+RSpec.describe LimitedCapacity::JobTracker, :clean_gitlab_redis_shared_state, feature_category: :shared do
let(:job_tracker) do
described_class.new('namespace')
end
diff --git a/spec/workers/concerns/limited_capacity/worker_spec.rb b/spec/workers/concerns/limited_capacity/worker_spec.rb
index 790b5c3544d..65906eef0fa 100644
--- a/spec/workers/concerns/limited_capacity/worker_spec.rb
+++ b/spec/workers/concerns/limited_capacity/worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe LimitedCapacity::Worker, :clean_gitlab_redis_queues, :aggregate_failures do
+RSpec.describe LimitedCapacity::Worker, :clean_gitlab_redis_queues, :aggregate_failures, feature_category: :shared do
let(:worker_class) do
Class.new do
def self.name
diff --git a/spec/workers/concerns/packages/cleanup_artifact_worker_spec.rb b/spec/workers/concerns/packages/cleanup_artifact_worker_spec.rb
index 95962d4810e..daecda8c92e 100644
--- a/spec/workers/concerns/packages/cleanup_artifact_worker_spec.rb
+++ b/spec/workers/concerns/packages/cleanup_artifact_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Packages::CleanupArtifactWorker do
+RSpec.describe ::Packages::CleanupArtifactWorker, feature_category: :build_artifacts do
let_it_be(:worker_class) do
Class.new do
def self.name
diff --git a/spec/workers/concerns/pipeline_background_queue_spec.rb b/spec/workers/concerns/pipeline_background_queue_spec.rb
deleted file mode 100644
index 77c7e7440c5..00000000000
--- a/spec/workers/concerns/pipeline_background_queue_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe PipelineBackgroundQueue do
- let(:worker) do
- Class.new do
- def self.name
- 'DummyWorker'
- end
-
- include ApplicationWorker
- include PipelineBackgroundQueue
- end
- end
-
- it 'sets a default object storage queue automatically' do
- expect(worker.sidekiq_options['queue'])
- .to eq 'pipeline_background:dummy'
- end
-end
diff --git a/spec/workers/concerns/pipeline_queue_spec.rb b/spec/workers/concerns/pipeline_queue_spec.rb
deleted file mode 100644
index 6c1ac2052e4..00000000000
--- a/spec/workers/concerns/pipeline_queue_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe PipelineQueue do
- let(:worker) do
- Class.new do
- def self.name
- 'DummyWorker'
- end
-
- include ApplicationWorker
- include PipelineQueue
- end
- end
-
- it 'sets a default pipelines queue automatically' do
- expect(worker.sidekiq_options['queue'])
- .to eq 'pipeline_default:dummy'
- end
-end
diff --git a/spec/workers/concerns/project_import_options_spec.rb b/spec/workers/concerns/project_import_options_spec.rb
index 85a26ddb0cb..51d7f9fdea4 100644
--- a/spec/workers/concerns/project_import_options_spec.rb
+++ b/spec/workers/concerns/project_import_options_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProjectImportOptions do
+RSpec.describe ProjectImportOptions, feature_category: :importers do
let(:project) { create(:project, :import_started) }
let(:job) { { 'args' => [project.id, nil, nil], 'jid' => '123' } }
let(:worker_class) do
diff --git a/spec/workers/concerns/reenqueuer_spec.rb b/spec/workers/concerns/reenqueuer_spec.rb
index e7287b55af2..42873578014 100644
--- a/spec/workers/concerns/reenqueuer_spec.rb
+++ b/spec/workers/concerns/reenqueuer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Reenqueuer do
+RSpec.describe Reenqueuer, feature_category: :shared do
include ExclusiveLeaseHelpers
let_it_be(:worker_class) do
diff --git a/spec/workers/concerns/repository_check_queue_spec.rb b/spec/workers/concerns/repository_check_queue_spec.rb
index ae377c09b37..12082e2dff5 100644
--- a/spec/workers/concerns/repository_check_queue_spec.rb
+++ b/spec/workers/concerns/repository_check_queue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RepositoryCheckQueue do
+RSpec.describe RepositoryCheckQueue, feature_category: :source_code_management do
let(:worker) do
Class.new do
def self.name
@@ -14,10 +14,6 @@ RSpec.describe RepositoryCheckQueue do
end
end
- it 'sets the queue name of a worker' do
- expect(worker.sidekiq_options['queue'].to_s).to eq('repository_check:dummy')
- end
-
it 'disables retrying of failed jobs' do
expect(worker.sidekiq_options['retry']).to eq(false)
end
diff --git a/spec/workers/concerns/waitable_worker_spec.rb b/spec/workers/concerns/waitable_worker_spec.rb
index 737424ffd8c..9cb34bbbab9 100644
--- a/spec/workers/concerns/waitable_worker_spec.rb
+++ b/spec/workers/concerns/waitable_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WaitableWorker do
+RSpec.describe WaitableWorker, feature_category: :shared do
let(:worker) do
Class.new do
def self.name
diff --git a/spec/workers/concerns/worker_attributes_spec.rb b/spec/workers/concerns/worker_attributes_spec.rb
index 5e8f68923fd..ac9d3fa824e 100644
--- a/spec/workers/concerns/worker_attributes_spec.rb
+++ b/spec/workers/concerns/worker_attributes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkerAttributes do
+RSpec.describe WorkerAttributes, feature_category: :shared do
using RSpec::Parameterized::TableSyntax
let(:worker) do
diff --git a/spec/workers/concerns/worker_context_spec.rb b/spec/workers/concerns/worker_context_spec.rb
index 80b427b2b42..0bbe14842bb 100644
--- a/spec/workers/concerns/worker_context_spec.rb
+++ b/spec/workers/concerns/worker_context_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WorkerContext do
+RSpec.describe WorkerContext, feature_category: :shared do
let(:worker) do
Class.new do
def self.name
diff --git a/spec/workers/container_expiration_policies/cleanup_container_repository_worker_spec.rb b/spec/workers/container_expiration_policies/cleanup_container_repository_worker_spec.rb
index 8eda943f36e..8dae859b168 100644
--- a/spec/workers/container_expiration_policies/cleanup_container_repository_worker_spec.rb
+++ b/spec/workers/container_expiration_policies/cleanup_container_repository_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ContainerExpirationPolicies::CleanupContainerRepositoryWorker do
+RSpec.describe ContainerExpirationPolicies::CleanupContainerRepositoryWorker, feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
let_it_be(:repository, refind: true) { create(:container_repository, :cleanup_scheduled, expiration_policy_started_at: 1.month.ago) }
@@ -348,16 +348,18 @@ RSpec.describe ContainerExpirationPolicies::CleanupContainerRepositoryWorker do
subject { worker.send(:container_repository) }
- if params[:expected_selected_repository] == :none
- it 'does not select any repository' do
+ it 'selects the correct repository', :freeze_time do
+ case expected_selected_repository
+ when :none
expect(subject).to eq(nil)
+ next
+ when :repository
+ expect(subject).to eq(repository)
+ when :other_repository
+ expect(subject).to eq(other_repository)
end
- else
- it 'does select a repository' do
- selected_repository = expected_selected_repository == :repository ? repository : other_repository
-
- expect(subject).to eq(selected_repository)
- end
+ expect(subject).to be_cleanup_ongoing
+ expect(subject.expiration_policy_started_at).to eq(Time.zone.now)
end
def update_container_repository(container_repository, cleanup_status, policy_status)
@@ -511,6 +513,16 @@ RSpec.describe ContainerExpirationPolicies::CleanupContainerRepositoryWorker do
subject
end
end
+
+ context 'with a stuck container repository' do
+ before do
+ repository.cleanup_ongoing!
+ repository.update_column(:expiration_policy_started_at, nil)
+ policy.update_column(:next_run_at, 5.minutes.ago)
+ end
+
+ it { is_expected.to eq(0) }
+ end
end
describe '#max_running_jobs' do
diff --git a/spec/workers/container_expiration_policy_worker_spec.rb b/spec/workers/container_expiration_policy_worker_spec.rb
index ef6266aeba3..fcb43b86084 100644
--- a/spec/workers/container_expiration_policy_worker_spec.rb
+++ b/spec/workers/container_expiration_policy_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ContainerExpirationPolicyWorker do
+RSpec.describe ContainerExpirationPolicyWorker, feature_category: :container_registry do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new }
@@ -33,15 +33,17 @@ RSpec.describe ContainerExpirationPolicyWorker do
end
context 'process stale ongoing cleanups' do
- let_it_be(:stuck_cleanup) { create(:container_repository, :cleanup_ongoing, expiration_policy_started_at: 1.day.ago) }
+ let_it_be(:stuck_cleanup1) { create(:container_repository, :cleanup_ongoing, expiration_policy_started_at: 1.day.ago) }
+ let_it_be(:stuck_cleanup2) { create(:container_repository, :cleanup_ongoing, expiration_policy_started_at: nil) }
let_it_be(:container_repository1) { create(:container_repository, :cleanup_scheduled) }
let_it_be(:container_repository2) { create(:container_repository, :cleanup_unfinished) }
it 'set them as unfinished' do
expect { subject }
- .to change { ContainerRepository.cleanup_ongoing.count }.from(1).to(0)
- .and change { ContainerRepository.cleanup_unfinished.count }.from(1).to(2)
- expect(stuck_cleanup.reload).to be_cleanup_unfinished
+ .to change { ContainerRepository.cleanup_ongoing.count }.from(2).to(0)
+ .and change { ContainerRepository.cleanup_unfinished.count }.from(1).to(3)
+ expect(stuck_cleanup1.reload).to be_cleanup_unfinished
+ expect(stuck_cleanup2.reload).to be_cleanup_unfinished
end
end
diff --git a/spec/workers/container_registry/cleanup_worker_spec.rb b/spec/workers/container_registry/cleanup_worker_spec.rb
index a510b660412..72e1243ccb5 100644
--- a/spec/workers/container_registry/cleanup_worker_spec.rb
+++ b/spec/workers/container_registry/cleanup_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ContainerRegistry::CleanupWorker, :aggregate_failures do
+RSpec.describe ContainerRegistry::CleanupWorker, :aggregate_failures, feature_category: :container_registry do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/container_registry/delete_container_repository_worker_spec.rb b/spec/workers/container_registry/delete_container_repository_worker_spec.rb
index 381e0cc164c..8bab0133d55 100644
--- a/spec/workers/container_registry/delete_container_repository_worker_spec.rb
+++ b/spec/workers/container_registry/delete_container_repository_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ContainerRegistry::DeleteContainerRepositoryWorker, :aggregate_failures do
+RSpec.describe ContainerRegistry::DeleteContainerRepositoryWorker, :aggregate_failures, feature_category: :container_registry do
let_it_be_with_reload(:container_repository) { create(:container_repository) }
let_it_be(:second_container_repository) { create(:container_repository) }
diff --git a/spec/workers/container_registry/migration/enqueuer_worker_spec.rb b/spec/workers/container_registry/migration/enqueuer_worker_spec.rb
index c2381c0ced7..4a603e538ef 100644
--- a/spec/workers/container_registry/migration/enqueuer_worker_spec.rb
+++ b/spec/workers/container_registry/migration/enqueuer_worker_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe ContainerRegistry::Migration::EnqueuerWorker, :aggregate_failures, :clean_gitlab_redis_shared_state do
+RSpec.describe ContainerRegistry::Migration::EnqueuerWorker, :aggregate_failures, :clean_gitlab_redis_shared_state,
+ feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
include ExclusiveLeaseHelpers
diff --git a/spec/workers/container_registry/migration/guard_worker_spec.rb b/spec/workers/container_registry/migration/guard_worker_spec.rb
index 4ad2d5c300c..40ade93ab0d 100644
--- a/spec/workers/container_registry/migration/guard_worker_spec.rb
+++ b/spec/workers/container_registry/migration/guard_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ContainerRegistry::Migration::GuardWorker, :aggregate_failures do
+RSpec.describe ContainerRegistry::Migration::GuardWorker, :aggregate_failures, feature_category: :container_registry do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/container_registry/migration/observer_worker_spec.rb b/spec/workers/container_registry/migration/observer_worker_spec.rb
index fec6640d7ec..7bf3d90d9d3 100644
--- a/spec/workers/container_registry/migration/observer_worker_spec.rb
+++ b/spec/workers/container_registry/migration/observer_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ContainerRegistry::Migration::ObserverWorker, :aggregate_failures do
+RSpec.describe ContainerRegistry::Migration::ObserverWorker, :aggregate_failures, feature_category: :container_registry do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/counters/cleanup_refresh_worker_spec.rb b/spec/workers/counters/cleanup_refresh_worker_spec.rb
index a56c98f72a0..a18f78f1706 100644
--- a/spec/workers/counters/cleanup_refresh_worker_spec.rb
+++ b/spec/workers/counters/cleanup_refresh_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Counters::CleanupRefreshWorker do
+RSpec.describe Counters::CleanupRefreshWorker, feature_category: :shared do
let(:model) { create(:project_statistics) }
describe '#perform', :redis do
diff --git a/spec/workers/create_commit_signature_worker_spec.rb b/spec/workers/create_commit_signature_worker_spec.rb
index 9d3c63efc8a..722632b6796 100644
--- a/spec/workers/create_commit_signature_worker_spec.rb
+++ b/spec/workers/create_commit_signature_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CreateCommitSignatureWorker do
+RSpec.describe CreateCommitSignatureWorker, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:commits) { project.repository.commits('HEAD', limit: 3).commits }
let(:commit_shas) { commits.map(&:id) }
diff --git a/spec/workers/create_note_diff_file_worker_spec.rb b/spec/workers/create_note_diff_file_worker_spec.rb
index 6d1d6d93e44..6e4a5e3ab6a 100644
--- a/spec/workers/create_note_diff_file_worker_spec.rb
+++ b/spec/workers/create_note_diff_file_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CreateNoteDiffFileWorker do
+RSpec.describe CreateNoteDiffFileWorker, feature_category: :code_review_workflow do
describe '#perform' do
let(:diff_note) { create(:diff_note_on_merge_request) }
diff --git a/spec/workers/create_pipeline_worker_spec.rb b/spec/workers/create_pipeline_worker_spec.rb
index da85d700429..23a2dc075a7 100644
--- a/spec/workers/create_pipeline_worker_spec.rb
+++ b/spec/workers/create_pipeline_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CreatePipelineWorker do
+RSpec.describe CreatePipelineWorker, feature_category: :continuous_integration do
describe '#perform' do
let(:worker) { described_class.new }
diff --git a/spec/workers/database/batched_background_migration/ci_database_worker_spec.rb b/spec/workers/database/batched_background_migration/ci_database_worker_spec.rb
index dfe7a266be2..91ba6e5a20a 100644
--- a/spec/workers/database/batched_background_migration/ci_database_worker_spec.rb
+++ b/spec/workers/database/batched_background_migration/ci_database_worker_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe Database::BatchedBackgroundMigration::CiDatabaseWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe Database::BatchedBackgroundMigration::CiDatabaseWorker, :clean_gitlab_redis_shared_state, feature_category: :database do
it_behaves_like 'it runs batched background migration jobs', :ci, :ci_builds
end
diff --git a/spec/workers/database/batched_background_migration_worker_spec.rb b/spec/workers/database/batched_background_migration_worker_spec.rb
index e57bd7581c2..a6825c5ca76 100644
--- a/spec/workers/database/batched_background_migration_worker_spec.rb
+++ b/spec/workers/database/batched_background_migration_worker_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe Database::BatchedBackgroundMigrationWorker do
+RSpec.describe Database::BatchedBackgroundMigrationWorker, feature_category: :database do
it_behaves_like 'it runs batched background migration jobs', :main, :events
end
diff --git a/spec/workers/database/ci_namespace_mirrors_consistency_check_worker_spec.rb b/spec/workers/database/ci_namespace_mirrors_consistency_check_worker_spec.rb
index 1c083d1d8a3..6b6723a468f 100644
--- a/spec/workers/database/ci_namespace_mirrors_consistency_check_worker_spec.rb
+++ b/spec/workers/database/ci_namespace_mirrors_consistency_check_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Database::CiNamespaceMirrorsConsistencyCheckWorker do
+RSpec.describe Database::CiNamespaceMirrorsConsistencyCheckWorker, feature_category: :pods do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/database/ci_project_mirrors_consistency_check_worker_spec.rb b/spec/workers/database/ci_project_mirrors_consistency_check_worker_spec.rb
index 8c839410ccd..613d40b57d8 100644
--- a/spec/workers/database/ci_project_mirrors_consistency_check_worker_spec.rb
+++ b/spec/workers/database/ci_project_mirrors_consistency_check_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Database::CiProjectMirrorsConsistencyCheckWorker do
+RSpec.describe Database::CiProjectMirrorsConsistencyCheckWorker, feature_category: :pods do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/database/drop_detached_partitions_worker_spec.rb b/spec/workers/database/drop_detached_partitions_worker_spec.rb
index a10fcaaa5d9..2ab77e71070 100644
--- a/spec/workers/database/drop_detached_partitions_worker_spec.rb
+++ b/spec/workers/database/drop_detached_partitions_worker_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Database::DropDetachedPartitionsWorker do
+RSpec.describe Database::DropDetachedPartitionsWorker, feature_category: :database do
describe '#perform' do
subject { described_class.new.perform }
diff --git a/spec/workers/database/partition_management_worker_spec.rb b/spec/workers/database/partition_management_worker_spec.rb
index e5362e95f48..203181ef28d 100644
--- a/spec/workers/database/partition_management_worker_spec.rb
+++ b/spec/workers/database/partition_management_worker_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Database::PartitionManagementWorker do
+RSpec.describe Database::PartitionManagementWorker, feature_category: :database do
describe '#perform' do
subject { described_class.new.perform }
diff --git a/spec/workers/delete_container_repository_worker_spec.rb b/spec/workers/delete_container_repository_worker_spec.rb
index 6ad131b4c14..6260bea6949 100644
--- a/spec/workers/delete_container_repository_worker_spec.rb
+++ b/spec/workers/delete_container_repository_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DeleteContainerRepositoryWorker do
+RSpec.describe DeleteContainerRepositoryWorker, feature_category: :container_registry do
let_it_be(:repository) { create(:container_repository) }
let(:project) { repository.project }
diff --git a/spec/workers/delete_diff_files_worker_spec.rb b/spec/workers/delete_diff_files_worker_spec.rb
index c124847ca45..1f1b00e324e 100644
--- a/spec/workers/delete_diff_files_worker_spec.rb
+++ b/spec/workers/delete_diff_files_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DeleteDiffFilesWorker do
+RSpec.describe DeleteDiffFilesWorker, feature_category: :code_review_workflow do
describe '#perform' do
let(:merge_request) { create(:merge_request) }
let(:merge_request_diff) { merge_request.merge_request_diff }
diff --git a/spec/workers/delete_merged_branches_worker_spec.rb b/spec/workers/delete_merged_branches_worker_spec.rb
index 056fcb1200d..f3b6dccad2e 100644
--- a/spec/workers/delete_merged_branches_worker_spec.rb
+++ b/spec/workers/delete_merged_branches_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DeleteMergedBranchesWorker do
+RSpec.describe DeleteMergedBranchesWorker, feature_category: :source_code_management do
subject(:worker) { described_class.new }
let(:project) { create(:project, :repository) }
diff --git a/spec/workers/delete_user_worker_spec.rb b/spec/workers/delete_user_worker_spec.rb
index 4046b670640..05c2b0e7930 100644
--- a/spec/workers/delete_user_worker_spec.rb
+++ b/spec/workers/delete_user_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DeleteUserWorker do
+RSpec.describe DeleteUserWorker, feature_category: :user_management do
let!(:user) { create(:user) }
let!(:current_user) { create(:user) }
diff --git a/spec/workers/dependency_proxy/cleanup_blob_worker_spec.rb b/spec/workers/dependency_proxy/cleanup_blob_worker_spec.rb
index b67a56cca7b..9ef5fd9ec93 100644
--- a/spec/workers/dependency_proxy/cleanup_blob_worker_spec.rb
+++ b/spec/workers/dependency_proxy/cleanup_blob_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DependencyProxy::CleanupBlobWorker do
+RSpec.describe DependencyProxy::CleanupBlobWorker, feature_category: :dependency_proxy do
let_it_be(:factory_type) { :dependency_proxy_blob }
it_behaves_like 'dependency_proxy_cleanup_worker'
diff --git a/spec/workers/dependency_proxy/cleanup_dependency_proxy_worker_spec.rb b/spec/workers/dependency_proxy/cleanup_dependency_proxy_worker_spec.rb
index 1100f9a7fae..3040189d1c8 100644
--- a/spec/workers/dependency_proxy/cleanup_dependency_proxy_worker_spec.rb
+++ b/spec/workers/dependency_proxy/cleanup_dependency_proxy_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DependencyProxy::CleanupDependencyProxyWorker do
+RSpec.describe DependencyProxy::CleanupDependencyProxyWorker, feature_category: :dependency_proxy do
describe '#perform' do
subject { described_class.new.perform }
diff --git a/spec/workers/dependency_proxy/cleanup_manifest_worker_spec.rb b/spec/workers/dependency_proxy/cleanup_manifest_worker_spec.rb
index d53b3e6a1fd..730acc49110 100644
--- a/spec/workers/dependency_proxy/cleanup_manifest_worker_spec.rb
+++ b/spec/workers/dependency_proxy/cleanup_manifest_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DependencyProxy::CleanupManifestWorker do
+RSpec.describe DependencyProxy::CleanupManifestWorker, feature_category: :dependency_proxy do
let_it_be(:factory_type) { :dependency_proxy_manifest }
it_behaves_like 'dependency_proxy_cleanup_worker'
diff --git a/spec/workers/dependency_proxy/image_ttl_group_policy_worker_spec.rb b/spec/workers/dependency_proxy/image_ttl_group_policy_worker_spec.rb
index 6a2fdfbe8f5..44a21439ff8 100644
--- a/spec/workers/dependency_proxy/image_ttl_group_policy_worker_spec.rb
+++ b/spec/workers/dependency_proxy/image_ttl_group_policy_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DependencyProxy::ImageTtlGroupPolicyWorker do
+RSpec.describe DependencyProxy::ImageTtlGroupPolicyWorker, feature_category: :dependency_proxy do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/deployments/archive_in_project_worker_spec.rb b/spec/workers/deployments/archive_in_project_worker_spec.rb
index 6435fe8bea1..2d244344913 100644
--- a/spec/workers/deployments/archive_in_project_worker_spec.rb
+++ b/spec/workers/deployments/archive_in_project_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::ArchiveInProjectWorker do
+RSpec.describe Deployments::ArchiveInProjectWorker, feature_category: :continuous_delivery do
subject { described_class.new.perform(deployment&.project_id) }
describe '#perform' do
diff --git a/spec/workers/deployments/drop_older_deployments_worker_spec.rb b/spec/workers/deployments/drop_older_deployments_worker_spec.rb
index 0cf524ca16f..8637a7788cc 100644
--- a/spec/workers/deployments/drop_older_deployments_worker_spec.rb
+++ b/spec/workers/deployments/drop_older_deployments_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::DropOlderDeploymentsWorker do
+RSpec.describe Deployments::DropOlderDeploymentsWorker, feature_category: :continuous_delivery do
subject { described_class.new.perform(deployment&.id) }
describe '#perform' do
diff --git a/spec/workers/deployments/hooks_worker_spec.rb b/spec/workers/deployments/hooks_worker_spec.rb
index 7c5f288fa57..51614f8b0cb 100644
--- a/spec/workers/deployments/hooks_worker_spec.rb
+++ b/spec/workers/deployments/hooks_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::HooksWorker do
+RSpec.describe Deployments::HooksWorker, feature_category: :continuous_delivery do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/deployments/link_merge_request_worker_spec.rb b/spec/workers/deployments/link_merge_request_worker_spec.rb
index a55dd897bc7..0e484c50f21 100644
--- a/spec/workers/deployments/link_merge_request_worker_spec.rb
+++ b/spec/workers/deployments/link_merge_request_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::LinkMergeRequestWorker do
+RSpec.describe Deployments::LinkMergeRequestWorker, feature_category: :continuous_delivery do
subject(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/deployments/update_environment_worker_spec.rb b/spec/workers/deployments/update_environment_worker_spec.rb
index d67cbd62616..befe8576e88 100644
--- a/spec/workers/deployments/update_environment_worker_spec.rb
+++ b/spec/workers/deployments/update_environment_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Deployments::UpdateEnvironmentWorker do
+RSpec.describe Deployments::UpdateEnvironmentWorker, feature_category: :continuous_delivery do
subject(:worker) { described_class.new }
context 'when successful deployment' do
diff --git a/spec/workers/design_management/copy_design_collection_worker_spec.rb b/spec/workers/design_management/copy_design_collection_worker_spec.rb
index 45bfc47ca7e..daa69a8bd6d 100644
--- a/spec/workers/design_management/copy_design_collection_worker_spec.rb
+++ b/spec/workers/design_management/copy_design_collection_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DesignManagement::CopyDesignCollectionWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe DesignManagement::CopyDesignCollectionWorker, :clean_gitlab_redis_shared_state, feature_category: :design_management do
describe '#perform' do
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue) }
diff --git a/spec/workers/design_management/new_version_worker_spec.rb b/spec/workers/design_management/new_version_worker_spec.rb
index 3320d7a062d..afc908d925a 100644
--- a/spec/workers/design_management/new_version_worker_spec.rb
+++ b/spec/workers/design_management/new_version_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DesignManagement::NewVersionWorker do
+RSpec.describe DesignManagement::NewVersionWorker, feature_category: :design_management do
describe '#perform' do
let(:worker) { described_class.new }
diff --git a/spec/workers/destroy_pages_deployments_worker_spec.rb b/spec/workers/destroy_pages_deployments_worker_spec.rb
index 2c20c9004ef..4bfde6d220a 100644
--- a/spec/workers/destroy_pages_deployments_worker_spec.rb
+++ b/spec/workers/destroy_pages_deployments_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DestroyPagesDeploymentsWorker do
+RSpec.describe DestroyPagesDeploymentsWorker, feature_category: :pages do
subject(:worker) { described_class.new }
let(:project) { create(:project) }
diff --git a/spec/workers/detect_repository_languages_worker_spec.rb b/spec/workers/detect_repository_languages_worker_spec.rb
index 217e16bd155..27d60720d24 100644
--- a/spec/workers/detect_repository_languages_worker_spec.rb
+++ b/spec/workers/detect_repository_languages_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DetectRepositoryLanguagesWorker do
+RSpec.describe DetectRepositoryLanguagesWorker, feature_category: :source_code_management do
let_it_be(:project) { create(:project) }
subject { described_class.new }
diff --git a/spec/workers/disallow_two_factor_for_group_worker_spec.rb b/spec/workers/disallow_two_factor_for_group_worker_spec.rb
index 3a875727cce..c732f8a3d00 100644
--- a/spec/workers/disallow_two_factor_for_group_worker_spec.rb
+++ b/spec/workers/disallow_two_factor_for_group_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DisallowTwoFactorForGroupWorker do
+RSpec.describe DisallowTwoFactorForGroupWorker, feature_category: :subgroups do
let_it_be(:group) { create(:group, require_two_factor_authentication: true) }
let_it_be(:user) { create(:user, require_two_factor_authentication_from_group: true) }
diff --git a/spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb b/spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb
index c3be8263171..7584355deab 100644
--- a/spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb
+++ b/spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DisallowTwoFactorForSubgroupsWorker do
+RSpec.describe DisallowTwoFactorForSubgroupsWorker, feature_category: :subgroups do
let_it_be(:group) { create(:group) }
let_it_be(:subgroup_with_2fa) { create(:group, parent: group, require_two_factor_authentication: true) }
let_it_be(:subgroup_without_2fa) { create(:group, parent: group, require_two_factor_authentication: false) }
diff --git a/spec/workers/email_receiver_worker_spec.rb b/spec/workers/email_receiver_worker_spec.rb
index dba535654a1..4c464c797e4 100644
--- a/spec/workers/email_receiver_worker_spec.rb
+++ b/spec/workers/email_receiver_worker_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe EmailReceiverWorker, :mailer do
+RSpec.describe EmailReceiverWorker, :mailer, feature_category: :team_planning do
let(:raw_message) { fixture_file('emails/valid_reply.eml') }
context "when reply by email is enabled" do
diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb
index 7d11957e2df..9e8fad19c20 100644
--- a/spec/workers/emails_on_push_worker_spec.rb
+++ b/spec/workers/emails_on_push_worker_spec.rb
@@ -2,12 +2,12 @@
require 'spec_helper'
-RSpec.describe EmailsOnPushWorker, :mailer do
- include RepoHelpers
+RSpec.describe EmailsOnPushWorker, :mailer, feature_category: :source_code_management do
include EmailSpec::Matchers
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+
let(:data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
let(:recipients) { user.email }
let(:perform) { subject.perform(project.id, recipients, data.stringify_keys) }
@@ -91,7 +91,7 @@ RSpec.describe EmailsOnPushWorker, :mailer do
context "when there is an SMTP error" do
before do
- allow(Notify).to receive(:repository_push_email).and_raise(Net::SMTPFatalError)
+ allow(Notify).to receive(:repository_push_email).and_raise(Net::SMTPFatalError.new(nil))
allow(subject).to receive_message_chain(:logger, :info)
perform
end
diff --git a/spec/workers/environments/auto_delete_cron_worker_spec.rb b/spec/workers/environments/auto_delete_cron_worker_spec.rb
index b18f3da5d10..d7e707b225e 100644
--- a/spec/workers/environments/auto_delete_cron_worker_spec.rb
+++ b/spec/workers/environments/auto_delete_cron_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Environments::AutoDeleteCronWorker do
+RSpec.describe Environments::AutoDeleteCronWorker, feature_category: :continuous_delivery do
include CreateEnvironmentsHelpers
let(:worker) { described_class.new }
diff --git a/spec/workers/environments/auto_stop_cron_worker_spec.rb b/spec/workers/environments/auto_stop_cron_worker_spec.rb
index 1e86597d288..ad44cf97e07 100644
--- a/spec/workers/environments/auto_stop_cron_worker_spec.rb
+++ b/spec/workers/environments/auto_stop_cron_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Environments::AutoStopCronWorker do
+RSpec.describe Environments::AutoStopCronWorker, feature_category: :continuous_delivery do
subject { worker.perform }
let(:worker) { described_class.new }
diff --git a/spec/workers/environments/auto_stop_worker_spec.rb b/spec/workers/environments/auto_stop_worker_spec.rb
index cb162b5a01c..cfdca4a385c 100644
--- a/spec/workers/environments/auto_stop_worker_spec.rb
+++ b/spec/workers/environments/auto_stop_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Environments::AutoStopWorker do
+RSpec.describe Environments::AutoStopWorker, feature_category: :continuous_delivery do
include CreateEnvironmentsHelpers
subject { worker.perform(environment_id) }
diff --git a/spec/workers/environments/canary_ingress/update_worker_spec.rb b/spec/workers/environments/canary_ingress/update_worker_spec.rb
index e7782c2fba1..abfca54c850 100644
--- a/spec/workers/environments/canary_ingress/update_worker_spec.rb
+++ b/spec/workers/environments/canary_ingress/update_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Environments::CanaryIngress::UpdateWorker do
+RSpec.describe Environments::CanaryIngress::UpdateWorker, feature_category: :continuous_delivery do
let_it_be(:environment) { create(:environment) }
let(:worker) { described_class.new }
diff --git a/spec/workers/error_tracking_issue_link_worker_spec.rb b/spec/workers/error_tracking_issue_link_worker_spec.rb
index 90e747c8788..fcb39597f9e 100644
--- a/spec/workers/error_tracking_issue_link_worker_spec.rb
+++ b/spec/workers/error_tracking_issue_link_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ErrorTrackingIssueLinkWorker do
+RSpec.describe ErrorTrackingIssueLinkWorker, feature_category: :error_tracking do
let_it_be(:error_tracking) { create(:project_error_tracking_setting) }
let_it_be(:project) { error_tracking.project }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index c0d46a206ce..f080e2ef1c3 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Every Sidekiq worker' do
+RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
let(:workers_without_defaults) do
Gitlab::SidekiqConfig.workers - Gitlab::SidekiqConfig::DEFAULT_WORKERS.values
end
@@ -272,6 +272,7 @@ RSpec.describe 'Every Sidekiq worker' do
'Gitlab::GithubImport::ImportLfsObjectWorker' => 5,
'Gitlab::GithubImport::ImportNoteWorker' => 5,
'Gitlab::GithubImport::ImportProtectedBranchWorker' => 5,
+ 'Gitlab::GithubImport::ImportCollaboratorWorker' => 5,
'Gitlab::GithubImport::ImportPullRequestMergedByWorker' => 5,
'Gitlab::GithubImport::ImportPullRequestReviewWorker' => 5,
'Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker' => 5,
@@ -285,6 +286,7 @@ RSpec.describe 'Every Sidekiq worker' do
'Gitlab::GithubImport::Stage::ImportAttachmentsWorker' => 5,
'Gitlab::GithubImport::Stage::ImportProtectedBranchesWorker' => 5,
'Gitlab::GithubImport::Stage::ImportNotesWorker' => 5,
+ 'Gitlab::GithubImport::Stage::ImportCollaboratorsWorker' => 5,
'Gitlab::GithubImport::Stage::ImportPullRequestsMergedByWorker' => 5,
'Gitlab::GithubImport::Stage::ImportPullRequestsReviewRequestsWorker' => 5,
'Gitlab::GithubImport::Stage::ImportPullRequestsReviewsWorker' => 5,
diff --git a/spec/workers/expire_build_artifacts_worker_spec.rb b/spec/workers/expire_build_artifacts_worker_spec.rb
index 3f8da3fb71c..2ef832eaaed 100644
--- a/spec/workers/expire_build_artifacts_worker_spec.rb
+++ b/spec/workers/expire_build_artifacts_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ExpireBuildArtifactsWorker do
+RSpec.describe ExpireBuildArtifactsWorker, feature_category: :build_artifacts do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/export_csv_worker_spec.rb b/spec/workers/export_csv_worker_spec.rb
index 88ccfac0a02..2de6c58958f 100644
--- a/spec/workers/export_csv_worker_spec.rb
+++ b/spec/workers/export_csv_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ExportCsvWorker do
+RSpec.describe ExportCsvWorker, feature_category: :team_planning do
let(:user) { create(:user) }
let(:project) { create(:project, creator: user) }
diff --git a/spec/workers/external_service_reactive_caching_worker_spec.rb b/spec/workers/external_service_reactive_caching_worker_spec.rb
index 907894d9b9a..58d9bec343a 100644
--- a/spec/workers/external_service_reactive_caching_worker_spec.rb
+++ b/spec/workers/external_service_reactive_caching_worker_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe ExternalServiceReactiveCachingWorker do
+RSpec.describe ExternalServiceReactiveCachingWorker, feature_category: :shared do
it_behaves_like 'reactive cacheable worker'
end
diff --git a/spec/workers/file_hook_worker_spec.rb b/spec/workers/file_hook_worker_spec.rb
index c171dc37e5f..00cd0e9c98e 100644
--- a/spec/workers/file_hook_worker_spec.rb
+++ b/spec/workers/file_hook_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe FileHookWorker do
+RSpec.describe FileHookWorker, feature_category: :integrations do
include RepoHelpers
let(:filename) { 'my_file_hook.rb' }
diff --git a/spec/workers/flush_counter_increments_worker_spec.rb b/spec/workers/flush_counter_increments_worker_spec.rb
index 83670acf4b6..1bdda3100c9 100644
--- a/spec/workers/flush_counter_increments_worker_spec.rb
+++ b/spec/workers/flush_counter_increments_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe FlushCounterIncrementsWorker, :counter_attribute do
+RSpec.describe FlushCounterIncrementsWorker, :counter_attribute, feature_category: :shared do
let(:project_statistics) { create(:project_statistics) }
let(:model) { CounterAttributeModel.find(project_statistics.id) }
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 4e8261f61c4..121f30ea9d5 100644
--- a/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::AdvanceStageWorker, :clean_gitlab_redis_shared_state do
+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 }
diff --git a/spec/workers/gitlab/github_import/attachments/import_issue_worker_spec.rb b/spec/workers/gitlab/github_import/attachments/import_issue_worker_spec.rb
index 6d617755861..fc03e14c20e 100644
--- a/spec/workers/gitlab/github_import/attachments/import_issue_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/attachments/import_issue_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Attachments::ImportIssueWorker do
+RSpec.describe Gitlab::GithubImport::Attachments::ImportIssueWorker, feature_category: :importers do
subject(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/attachments/import_merge_request_worker_spec.rb b/spec/workers/gitlab/github_import/attachments/import_merge_request_worker_spec.rb
index 66dfc027e6e..bd90cee567e 100644
--- a/spec/workers/gitlab/github_import/attachments/import_merge_request_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/attachments/import_merge_request_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Attachments::ImportMergeRequestWorker do
+RSpec.describe Gitlab::GithubImport::Attachments::ImportMergeRequestWorker, feature_category: :importers do
subject(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/attachments/import_note_worker_spec.rb b/spec/workers/gitlab/github_import/attachments/import_note_worker_spec.rb
index 7b60cdecca6..7d8fb9bc788 100644
--- a/spec/workers/gitlab/github_import/attachments/import_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/attachments/import_note_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Attachments::ImportNoteWorker do
+RSpec.describe Gitlab::GithubImport::Attachments::ImportNoteWorker, feature_category: :importers do
subject(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/attachments/import_release_worker_spec.rb b/spec/workers/gitlab/github_import/attachments/import_release_worker_spec.rb
index e49b2fb6504..50eebc6ce8c 100644
--- a/spec/workers/gitlab/github_import/attachments/import_release_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/attachments/import_release_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Attachments::ImportReleaseWorker do
+RSpec.describe Gitlab::GithubImport::Attachments::ImportReleaseWorker, feature_category: :importers do
subject(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/import_collaborator_worker_spec.rb b/spec/workers/gitlab/github_import/import_collaborator_worker_spec.rb
new file mode 100644
index 00000000000..b9463fb9a2d
--- /dev/null
+++ b/spec/workers/gitlab/github_import/import_collaborator_worker_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::ImportCollaboratorWorker, feature_category: :importers do
+ let(:worker) { described_class.new }
+
+ describe '#import' do
+ let(:project) do
+ instance_double('Project', full_path: 'foo/bar', id: 1, import_state: import_state)
+ end
+
+ let(:import_state) { build_stubbed(:import_state, :started) }
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:importer) { instance_double('Gitlab::GithubImport::Importer::NoteAttachmentsImporter') }
+
+ it 'imports a collaborator' do
+ expect(Gitlab::GithubImport::Importer::CollaboratorImporter)
+ .to receive(:new)
+ .with(
+ an_instance_of(Gitlab::GithubImport::Representation::Collaborator),
+ project,
+ client
+ )
+ .and_return(importer)
+
+ expect(importer).to receive(:execute)
+
+ expect(Gitlab::GithubImport::ObjectCounter)
+ .to receive(:increment)
+ .and_call_original
+
+ worker.import(
+ project, client, { 'id' => 100500, 'login' => 'alice', 'role_name' => 'maintainer' }
+ )
+ end
+ end
+end
diff --git a/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb b/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
index c92741e8f10..35d31848fe1 100644
--- a/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportDiffNoteWorker do
+RSpec.describe Gitlab::GithubImport::ImportDiffNoteWorker, feature_category: :importers do
let(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb b/spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb
index 03a6503fb84..aa8243154ef 100644
--- a/spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_issue_event_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportIssueEventWorker do
+RSpec.describe Gitlab::GithubImport::ImportIssueEventWorker, feature_category: :importers do
subject(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/import_issue_worker_spec.rb b/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
index ef1d2e3f3e7..76f0b512af4 100644
--- a/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportIssueWorker do
+RSpec.describe Gitlab::GithubImport::ImportIssueWorker, feature_category: :importers do
let(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/import_note_worker_spec.rb b/spec/workers/gitlab/github_import/import_note_worker_spec.rb
index 16ca5658f77..b11ea560516 100644
--- a/spec/workers/gitlab/github_import/import_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_note_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportNoteWorker do
+RSpec.describe Gitlab::GithubImport::ImportNoteWorker, feature_category: :importers do
let(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/import_protected_branch_worker_spec.rb b/spec/workers/gitlab/github_import/import_protected_branch_worker_spec.rb
index c2b8ee661a3..d6e8f760033 100644
--- a/spec/workers/gitlab/github_import/import_protected_branch_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_protected_branch_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportProtectedBranchWorker do
+RSpec.describe Gitlab::GithubImport::ImportProtectedBranchWorker, feature_category: :importers do
let(:worker) { described_class.new }
let(:import_state) { build_stubbed(:import_state, :started) }
diff --git a/spec/workers/gitlab/github_import/import_pull_request_merged_by_worker_spec.rb b/spec/workers/gitlab/github_import/import_pull_request_merged_by_worker_spec.rb
index 728b4c6b440..6f771a1b79d 100644
--- a/spec/workers/gitlab/github_import/import_pull_request_merged_by_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_pull_request_merged_by_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportPullRequestMergedByWorker do
+RSpec.describe Gitlab::GithubImport::ImportPullRequestMergedByWorker, feature_category: :importers do
it { is_expected.to include_module(Gitlab::GithubImport::ObjectImporter) }
describe '#representation_class' do
diff --git a/spec/workers/gitlab/github_import/import_pull_request_review_worker_spec.rb b/spec/workers/gitlab/github_import/import_pull_request_review_worker_spec.rb
index 0607add52cd..ede74a75ce5 100644
--- a/spec/workers/gitlab/github_import/import_pull_request_review_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_pull_request_review_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportPullRequestReviewWorker do
+RSpec.describe Gitlab::GithubImport::ImportPullRequestReviewWorker, feature_category: :importers do
it { is_expected.to include_module(Gitlab::GithubImport::ObjectImporter) }
describe '#representation_class' do
diff --git a/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb b/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
index 59f45b437c4..864075ca3d7 100644
--- a/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportPullRequestWorker do
+RSpec.describe Gitlab::GithubImport::ImportPullRequestWorker, feature_category: :importers do
let(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/import_release_attachments_worker_spec.rb b/spec/workers/gitlab/github_import/import_release_attachments_worker_spec.rb
index 1d32d5c0e21..f4f5353a9cf 100644
--- a/spec/workers/gitlab/github_import/import_release_attachments_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_release_attachments_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ImportReleaseAttachmentsWorker do
+RSpec.describe Gitlab::GithubImport::ImportReleaseAttachmentsWorker, feature_category: :importers do
subject(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb b/spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb
index fdcbfb18beb..99ed83ae2db 100644
--- a/spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker do
+RSpec.describe Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker, feature_category: :importers do
subject(:worker) { described_class.new }
describe '#import' do
diff --git a/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb b/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb
index 3a8b585fa77..abba6cd7734 100644
--- a/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::RefreshImportJidWorker do
+RSpec.describe Gitlab::GithubImport::RefreshImportJidWorker, feature_category: :importers do
let(:worker) { described_class.new }
describe '.perform_in_the_future' do
diff --git a/spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb b/spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb
index 5f60dfc8ca1..e517f30ee2c 100644
--- a/spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::FinishImportWorker do
+RSpec.describe Gitlab::GithubImport::Stage::FinishImportWorker, feature_category: :importers do
let(:project) { create(:project) }
let(:worker) { described_class.new }
diff --git a/spec/workers/gitlab/github_import/stage/import_attachments_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_attachments_worker_spec.rb
index ecfece735af..2945bcbe641 100644
--- a/spec/workers/gitlab/github_import/stage/import_attachments_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_attachments_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportAttachmentsWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportAttachmentsWorker, feature_category: :importers do
subject(:worker) { described_class.new }
let_it_be(:project) { create(:project) }
diff --git a/spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb
index 7b2218b1725..1ad027a007a 100644
--- a/spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportBaseDataWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportBaseDataWorker, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:import_state) { create(:import_state, project: project) }
diff --git a/spec/workers/gitlab/github_import/stage/import_collaborators_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_collaborators_worker_spec.rb
new file mode 100644
index 00000000000..0eac9f21b77
--- /dev/null
+++ b/spec/workers/gitlab/github_import/stage/import_collaborators_worker_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Stage::ImportCollaboratorsWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:import_state) { create(:import_state, project: project) }
+
+ let(:worker) { described_class.new }
+ let(:importer) { instance_double(Gitlab::GithubImport::Importer::CollaboratorsImporter) }
+ let(:client) { instance_double(Gitlab::GithubImport::Client) }
+
+ describe '#import' do
+ let(:push_rights_granted) { true }
+
+ before do
+ allow(client).to receive(:repository).with(project.import_source)
+ .and_return({ permissions: { push: push_rights_granted } })
+ end
+
+ context 'when user has push access for this repo' do
+ it 'imports all the pull requests' do
+ waiter = Gitlab::JobWaiter.new(2, '123')
+
+ expect(Gitlab::GithubImport::Importer::CollaboratorsImporter)
+ .to receive(:new)
+ .with(project, client)
+ .and_return(importer)
+ expect(importer).to receive(:execute).and_return(waiter)
+
+ expect(import_state).to receive(:refresh_jid_expiration)
+
+ expect(Gitlab::GithubImport::AdvanceStageWorker)
+ .to receive(:perform_async)
+ .with(project.id, { '123' => 2 }, :pull_requests_merged_by)
+
+ worker.import(client, project)
+ end
+ end
+
+ context 'when user do not have push access for this repo' do
+ let(:push_rights_granted) { false }
+
+ it 'skips stage' do
+ expect(Gitlab::GithubImport::Importer::CollaboratorsImporter).not_to receive(:new)
+
+ expect(Gitlab::GithubImport::AdvanceStageWorker)
+ .to receive(:perform_async)
+ .with(project.id, {}, :pull_requests_merged_by)
+
+ worker.import(client, project)
+ end
+ end
+
+ it 'raises an error' do
+ exception = StandardError.new('_some_error_')
+
+ expect_next_instance_of(Gitlab::GithubImport::Importer::CollaboratorsImporter) do |importer|
+ expect(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: true,
+ metrics: true
+ ).and_call_original
+
+ expect { worker.import(client, project) }.to raise_error(StandardError)
+ end
+ end
+end
diff --git a/spec/workers/gitlab/github_import/stage/import_issue_events_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_issue_events_worker_spec.rb
index 199d1b9a3ca..c70ee0250e8 100644
--- a/spec/workers/gitlab/github_import/stage/import_issue_events_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_issue_events_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportIssueEventsWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportIssueEventsWorker, feature_category: :importers do
subject(:worker) { described_class.new }
let(:project) { create(:project) }
diff --git a/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
index beef0864715..872201ece93 100644
--- a/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportIssuesAndDiffNotesWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportIssuesAndDiffNotesWorker, feature_category: :importers do
let(:project) { create(:project) }
let(:worker) { described_class.new }
diff --git a/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb
index 103d55890c4..2449c0505f5 100644
--- a/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportLfsObjectsWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportLfsObjectsWorker, feature_category: :importers do
let(:project) { create(:project) }
let(:worker) { described_class.new }
diff --git a/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
index dbcf2083ec1..8c0004c0f3f 100644
--- a/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportNotesWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportNotesWorker, feature_category: :importers do
let(:project) { create(:project) }
let(:worker) { described_class.new }
diff --git a/spec/workers/gitlab/github_import/stage/import_protected_branches_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_protected_branches_worker_spec.rb
index 0770af524a1..f848293a3b2 100644
--- a/spec/workers/gitlab/github_import/stage/import_protected_branches_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_protected_branches_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportProtectedBranchesWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportProtectedBranchesWorker, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:import_state) { create(:import_state, project: project) }
diff --git a/spec/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker_spec.rb
index 5d6dcdc10ee..4ffc5a956a3 100644
--- a/spec/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsMergedByWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsMergedByWorker, feature_category: :importers do
let(:project) { create(:project) }
let(:import_state) { create(:import_state, project: project) }
let(:worker) { described_class.new }
diff --git a/spec/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker_spec.rb
index 151de9bdffc..41c0b29df7c 100644
--- a/spec/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsReviewRequestsWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsReviewRequestsWorker, feature_category: :importers do
subject(:worker) { described_class.new }
let(:project) { instance_double(Project, id: 1, import_state: import_state) }
diff --git a/spec/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker_spec.rb
index 18a70273219..c68e84475cb 100644
--- a/spec/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsReviewsWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsReviewsWorker, feature_category: :importers do
let(:project) { create(:project) }
let(:import_state) { create(:import_state, project: project) }
let(:worker) { described_class.new }
diff --git a/spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb
index b18b5ce64d1..6ebf93730eb 100644
--- a/spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsWorker, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:import_state) { create(:import_state, project: project) }
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsWorker do
expect(Gitlab::GithubImport::AdvanceStageWorker)
.to receive(:perform_async)
- .with(project.id, { '123' => 2 }, :pull_requests_merged_by)
+ .with(project.id, { '123' => 2 }, :collaborators)
worker.import(client, project)
end
diff --git a/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
index 24fca3b7c73..94d8155d371 100644
--- a/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Stage::ImportRepositoryWorker do
+RSpec.describe Gitlab::GithubImport::Stage::ImportRepositoryWorker, feature_category: :importers do
let_it_be(:project) { create(:project, :import_started) }
let(:worker) { described_class.new }
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportRepositoryWorker do
:issues, project.import_source, options
).and_return([{ number: 5 }].each)
- expect(Issue).to receive(:track_project_iid!).with(project, 5)
+ expect(Issue).to receive(:track_namespace_iid!).with(project.project_namespace, 5)
expect(Gitlab::GithubImport::Stage::ImportBaseDataWorker)
.to receive(:perform_async)
@@ -54,7 +54,7 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportRepositoryWorker do
expect(InternalId).to receive(:exists?).and_return(false)
expect(client).to receive(:each_object).with(:issues, project.import_source, options).and_return([nil].each)
- expect(Issue).not_to receive(:track_project_iid!)
+ expect(Issue).not_to receive(:track_namespace_iid!)
expect(Gitlab::GithubImport::Stage::ImportBaseDataWorker)
.to receive(:perform_async)
@@ -74,7 +74,7 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportRepositoryWorker do
expect(InternalId).to receive(:exists?).and_return(true)
expect(client).not_to receive(:each_object)
- expect(Issue).not_to receive(:track_project_iid!)
+ expect(Issue).not_to receive(:track_namespace_iid!)
expect(Gitlab::GithubImport::Stage::ImportBaseDataWorker)
.to receive(:perform_async)
@@ -96,7 +96,7 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportRepositoryWorker do
expect(InternalId).to receive(:exists?).and_return(false)
expect(client).to receive(:each_object).and_return([nil].each)
- expect(Issue).not_to receive(:track_project_iid!)
+ expect(Issue).not_to receive(:track_namespace_iid!)
expect(Gitlab::Import::ImportFailureService).to receive(:track)
.with(
diff --git a/spec/workers/gitlab/import/stuck_import_job_spec.rb b/spec/workers/gitlab/import/stuck_import_job_spec.rb
index 3a1463e98a0..52721168143 100644
--- a/spec/workers/gitlab/import/stuck_import_job_spec.rb
+++ b/spec/workers/gitlab/import/stuck_import_job_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Import::StuckImportJob do
+RSpec.describe Gitlab::Import::StuckImportJob, feature_category: :importers do
let_it_be(:project) { create(:project, :import_started, import_source: 'foo/bar') }
let(:worker) do
diff --git a/spec/workers/gitlab/import/stuck_project_import_jobs_worker_spec.rb b/spec/workers/gitlab/import/stuck_project_import_jobs_worker_spec.rb
index d12d5a605a7..9994896d3c8 100644
--- a/spec/workers/gitlab/import/stuck_project_import_jobs_worker_spec.rb
+++ b/spec/workers/gitlab/import/stuck_project_import_jobs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Import::StuckProjectImportJobsWorker do
+RSpec.describe Gitlab::Import::StuckProjectImportJobsWorker, feature_category: :importers do
let(:worker) { described_class.new }
describe 'with scheduled import_status' do
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 0244e69b7b6..5209395923f 100644
--- a/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::JiraImport::ImportIssueWorker do
+RSpec.describe Gitlab::JiraImport::ImportIssueWorker, feature_category: :importers do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:jira_issue_label_1) { create(:label, project: project) }
diff --git a/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb
index 23a764bd972..d1bf71a2095 100644
--- a/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::JiraImport::Stage::FinishImportWorker do
+RSpec.describe Gitlab::JiraImport::Stage::FinishImportWorker, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:worker) { described_class.new }
diff --git a/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb
index 28da93b8d00..c594182bf75 100644
--- a/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::JiraImport::Stage::ImportAttachmentsWorker do
+RSpec.describe Gitlab::JiraImport::Stage::ImportAttachmentsWorker, feature_category: :importers do
let_it_be(:project) { create(:project, import_type: 'jira') }
describe 'modules' do
diff --git a/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb
index 2b08a592164..594f9618770 100644
--- a/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::JiraImport::Stage::ImportIssuesWorker do
+RSpec.describe Gitlab::JiraImport::Stage::ImportIssuesWorker, feature_category: :importers do
include JiraIntegrationHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb
index d15f2caba19..d9c2407a423 100644
--- a/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::JiraImport::Stage::ImportLabelsWorker do
+RSpec.describe Gitlab::JiraImport::Stage::ImportLabelsWorker, feature_category: :importers do
include JiraIntegrationHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb
index 2502bbf1df4..41216356033 100644
--- a/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::JiraImport::Stage::ImportNotesWorker do
+RSpec.describe Gitlab::JiraImport::Stage::ImportNotesWorker, feature_category: :importers do
let_it_be(:project) { create(:project, import_type: 'jira') }
describe 'modules' do
diff --git a/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb
index e440884553f..ea0291b1c44 100644
--- a/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::JiraImport::Stage::StartImportWorker do
+RSpec.describe Gitlab::JiraImport::Stage::StartImportWorker, feature_category: :importers do
let_it_be(:project) { create(:project, import_type: 'jira') }
let_it_be(:jid) { '12345678' }
diff --git a/spec/workers/gitlab/jira_import/stuck_jira_import_jobs_worker_spec.rb b/spec/workers/gitlab/jira_import/stuck_jira_import_jobs_worker_spec.rb
index 92754513988..0f9f9b70c3e 100644
--- a/spec/workers/gitlab/jira_import/stuck_jira_import_jobs_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/stuck_jira_import_jobs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Gitlab::JiraImport::StuckJiraImportJobsWorker do
+RSpec.describe ::Gitlab::JiraImport::StuckJiraImportJobsWorker, feature_category: :importers do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/workers/gitlab/phabricator_import/base_worker_spec.rb b/spec/workers/gitlab/phabricator_import/base_worker_spec.rb
index 18fa484aa7a..9adba391d0f 100644
--- a/spec/workers/gitlab/phabricator_import/base_worker_spec.rb
+++ b/spec/workers/gitlab/phabricator_import/base_worker_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Gitlab::PhabricatorImport::BaseWorker do
+RSpec.describe Gitlab::PhabricatorImport::BaseWorker, feature_category: :importers do
let(:subclass) do
# Creating an anonymous class for a worker is complicated, as we generate the
# queue name from the class name.
diff --git a/spec/workers/gitlab/phabricator_import/import_tasks_worker_spec.rb b/spec/workers/gitlab/phabricator_import/import_tasks_worker_spec.rb
index 221b6202166..6c1da983640 100644
--- a/spec/workers/gitlab/phabricator_import/import_tasks_worker_spec.rb
+++ b/spec/workers/gitlab/phabricator_import/import_tasks_worker_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Gitlab::PhabricatorImport::ImportTasksWorker do
+RSpec.describe Gitlab::PhabricatorImport::ImportTasksWorker, feature_category: :importers do
describe '#perform' do
it 'calls the correct importer' do
project = create(:project, :import_started, import_url: "https://the.phab.ulr")
diff --git a/spec/workers/gitlab_performance_bar_stats_worker_spec.rb b/spec/workers/gitlab_performance_bar_stats_worker_spec.rb
index 3638add1524..45fb58826ba 100644
--- a/spec/workers/gitlab_performance_bar_stats_worker_spec.rb
+++ b/spec/workers/gitlab_performance_bar_stats_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabPerformanceBarStatsWorker do
+RSpec.describe GitlabPerformanceBarStatsWorker, feature_category: :metrics do
include ExclusiveLeaseHelpers
subject(:worker) { described_class.new }
diff --git a/spec/workers/gitlab_service_ping_worker_spec.rb b/spec/workers/gitlab_service_ping_worker_spec.rb
index f17847a7b33..1d16e8c3496 100644
--- a/spec/workers/gitlab_service_ping_worker_spec.rb
+++ b/spec/workers/gitlab_service_ping_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabServicePingWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe GitlabServicePingWorker, :clean_gitlab_redis_shared_state, feature_category: :service_ping do
let(:payload) { { recorded_at: Time.current.rfc3339 } }
before do
@@ -14,15 +14,13 @@ RSpec.describe GitlabServicePingWorker, :clean_gitlab_redis_shared_state do
allow(subject).to receive(:sleep)
end
- it 'does not run for GitLab.com when triggered from cron' do
- allow(Gitlab).to receive(:com?).and_return(true)
+ it 'does not run for SaaS when triggered from cron', :saas do
expect(ServicePing::SubmitService).not_to receive(:new)
subject.perform
end
- it 'runs for GitLab.com when triggered manually' do
- allow(Gitlab).to receive(:com?).and_return(true)
+ it 'runs for SaaS when triggered manually', :saas do
expect(ServicePing::SubmitService).to receive(:new)
subject.perform('triggered_from_cron' => false)
diff --git a/spec/workers/gitlab_shell_worker_spec.rb b/spec/workers/gitlab_shell_worker_spec.rb
index 838f2ef4ba4..9fff4489667 100644
--- a/spec/workers/gitlab_shell_worker_spec.rb
+++ b/spec/workers/gitlab_shell_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GitlabShellWorker, :sidekiq_inline do
+RSpec.describe GitlabShellWorker, :sidekiq_inline, feature_category: :source_code_management do
describe '#perform' do
Gitlab::Shell::PERMITTED_ACTIONS.each do |action|
describe "with the #{action} action" do
diff --git a/spec/workers/google_cloud/create_cloudsql_instance_worker_spec.rb b/spec/workers/google_cloud/create_cloudsql_instance_worker_spec.rb
index 5d595a3679b..7aea40807e8 100644
--- a/spec/workers/google_cloud/create_cloudsql_instance_worker_spec.rb
+++ b/spec/workers/google_cloud/create_cloudsql_instance_worker_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'google/apis/sqladmin_v1beta4'
-RSpec.describe GoogleCloud::CreateCloudsqlInstanceWorker do
+RSpec.describe GoogleCloud::CreateCloudsqlInstanceWorker, feature_category: :shared do
let(:random_user) { create(:user) }
let(:project) { create(:project) }
let(:worker_options) do
diff --git a/spec/workers/group_destroy_worker_spec.rb b/spec/workers/group_destroy_worker_spec.rb
index 82ae9010a24..fba4573718a 100644
--- a/spec/workers/group_destroy_worker_spec.rb
+++ b/spec/workers/group_destroy_worker_spec.rb
@@ -2,20 +2,29 @@
require 'spec_helper'
-RSpec.describe GroupDestroyWorker do
- let(:group) { create(:group) }
- let!(:project) { create(:project, namespace: group) }
- let(:user) { create(:user) }
+RSpec.describe GroupDestroyWorker, feature_category: :subgroups do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, namespace: group) }
+ let_it_be(:user) { create(:user) }
before do
group.add_owner(user)
end
- subject { described_class.new }
+ subject(:worker) { described_class.new }
+
+ include_examples 'an idempotent worker' do
+ let(:job_args) { [group.id, user.id] }
+
+ it 'does not change groups when run twice' do
+ expect { worker.perform(group.id, user.id) }.to change { Group.count }.by(-1)
+ expect { worker.perform(group.id, user.id) }.not_to change { Group.count }
+ end
+ end
describe "#perform" do
- it "deletes the project" do
- subject.perform(group.id, user.id)
+ it "deletes the group and associated projects" do
+ worker.perform(group.id, user.id)
expect(Group.all).not_to include(group)
expect(Project.all).not_to include(project)
diff --git a/spec/workers/group_export_worker_spec.rb b/spec/workers/group_export_worker_spec.rb
index 4e58e3886a4..54f9c38a506 100644
--- a/spec/workers/group_export_worker_spec.rb
+++ b/spec/workers/group_export_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GroupExportWorker do
+RSpec.describe GroupExportWorker, feature_category: :importers do
let!(:user) { create(:user) }
let!(:group) { create(:group) }
diff --git a/spec/workers/group_import_worker_spec.rb b/spec/workers/group_import_worker_spec.rb
index 5171de7086b..9aa6aaec24c 100644
--- a/spec/workers/group_import_worker_spec.rb
+++ b/spec/workers/group_import_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GroupImportWorker do
+RSpec.describe GroupImportWorker, feature_category: :importers do
let(:user) { create(:user) }
let(:group) { create(:group) }
diff --git a/spec/workers/groups/update_statistics_worker_spec.rb b/spec/workers/groups/update_statistics_worker_spec.rb
index 7fc166ed300..f47606f0580 100644
--- a/spec/workers/groups/update_statistics_worker_spec.rb
+++ b/spec/workers/groups/update_statistics_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::UpdateStatisticsWorker do
+RSpec.describe Groups::UpdateStatisticsWorker, feature_category: :source_code_management do
let_it_be(:group) { create(:group) }
let(:statistics) { %w(wiki_size) }
diff --git a/spec/workers/groups/update_two_factor_requirement_for_members_worker_spec.rb b/spec/workers/groups/update_two_factor_requirement_for_members_worker_spec.rb
index 9d202b9452f..aa1ca698095 100644
--- a/spec/workers/groups/update_two_factor_requirement_for_members_worker_spec.rb
+++ b/spec/workers/groups/update_two_factor_requirement_for_members_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::UpdateTwoFactorRequirementForMembersWorker do
+RSpec.describe Groups::UpdateTwoFactorRequirementForMembersWorker, feature_category: :system_access do
let_it_be(:group) { create(:group) }
let(:worker) { described_class.new }
diff --git a/spec/workers/hashed_storage/migrator_worker_spec.rb b/spec/workers/hashed_storage/migrator_worker_spec.rb
index e014297756e..f188928cf92 100644
--- a/spec/workers/hashed_storage/migrator_worker_spec.rb
+++ b/spec/workers/hashed_storage/migrator_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe HashedStorage::MigratorWorker do
+RSpec.describe HashedStorage::MigratorWorker, feature_category: :source_code_management do
subject(:worker) { described_class.new }
let(:projects) { create_list(:project, 2, :legacy_storage, :empty_repo) }
diff --git a/spec/workers/hashed_storage/project_migrate_worker_spec.rb b/spec/workers/hashed_storage/project_migrate_worker_spec.rb
index fd460888932..84592e85eaa 100644
--- a/spec/workers/hashed_storage/project_migrate_worker_spec.rb
+++ b/spec/workers/hashed_storage/project_migrate_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe HashedStorage::ProjectMigrateWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe HashedStorage::ProjectMigrateWorker, :clean_gitlab_redis_shared_state, feature_category: :source_code_management do
include ExclusiveLeaseHelpers
let(:migration_service) { ::Projects::HashedStorage::MigrationService }
diff --git a/spec/workers/hashed_storage/project_rollback_worker_spec.rb b/spec/workers/hashed_storage/project_rollback_worker_spec.rb
index fc89ac728b1..f27b5e4b9ce 100644
--- a/spec/workers/hashed_storage/project_rollback_worker_spec.rb
+++ b/spec/workers/hashed_storage/project_rollback_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe HashedStorage::ProjectRollbackWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe HashedStorage::ProjectRollbackWorker, :clean_gitlab_redis_shared_state, feature_category: :source_code_management do
include ExclusiveLeaseHelpers
describe '#perform' do
diff --git a/spec/workers/hashed_storage/rollbacker_worker_spec.rb b/spec/workers/hashed_storage/rollbacker_worker_spec.rb
index 46cca068273..af8957d9b96 100644
--- a/spec/workers/hashed_storage/rollbacker_worker_spec.rb
+++ b/spec/workers/hashed_storage/rollbacker_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe HashedStorage::RollbackerWorker do
+RSpec.describe HashedStorage::RollbackerWorker, feature_category: :source_code_management do
subject(:worker) { described_class.new }
let(:projects) { create_list(:project, 2, :empty_repo) }
diff --git a/spec/workers/import_issues_csv_worker_spec.rb b/spec/workers/import_issues_csv_worker_spec.rb
index 919ab2b1adf..7f38119d499 100644
--- a/spec/workers/import_issues_csv_worker_spec.rb
+++ b/spec/workers/import_issues_csv_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ImportIssuesCsvWorker do
+RSpec.describe ImportIssuesCsvWorker, feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/workers/incident_management/add_severity_system_note_worker_spec.rb b/spec/workers/incident_management/add_severity_system_note_worker_spec.rb
index 4d6e6610a92..cd19c5694b5 100644
--- a/spec/workers/incident_management/add_severity_system_note_worker_spec.rb
+++ b/spec/workers/incident_management/add_severity_system_note_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::AddSeveritySystemNoteWorker do
+RSpec.describe IncidentManagement::AddSeveritySystemNoteWorker, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:incident) { create(:incident, project: project) }
diff --git a/spec/workers/incident_management/close_incident_worker_spec.rb b/spec/workers/incident_management/close_incident_worker_spec.rb
index 145ee780573..bf967a42ceb 100644
--- a/spec/workers/incident_management/close_incident_worker_spec.rb
+++ b/spec/workers/incident_management/close_incident_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::CloseIncidentWorker do
+RSpec.describe IncidentManagement::CloseIncidentWorker, feature_category: :incident_management do
subject(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb b/spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb
index b81f1a575b5..f537acfaa05 100644
--- a/spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb
+++ b/spec/workers/incident_management/pager_duty/process_incident_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::PagerDuty::ProcessIncidentWorker do
+RSpec.describe IncidentManagement::PagerDuty::ProcessIncidentWorker, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) }
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 6cde8b758fa..476b6f04942 100644
--- a/spec/workers/incident_management/process_alert_worker_v2_spec.rb
+++ b/spec/workers/incident_management/process_alert_worker_v2_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IncidentManagement::ProcessAlertWorkerV2 do
+RSpec.describe IncidentManagement::ProcessAlertWorkerV2, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
let_it_be(:settings) { create(:project_incident_management_setting, project: project, create_issue: true) }
diff --git a/spec/workers/integrations/create_external_cross_reference_worker_spec.rb b/spec/workers/integrations/create_external_cross_reference_worker_spec.rb
index 8e586b90905..ee974fe2b28 100644
--- a/spec/workers/integrations/create_external_cross_reference_worker_spec.rb
+++ b/spec/workers/integrations/create_external_cross_reference_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::CreateExternalCrossReferenceWorker do
+RSpec.describe Integrations::CreateExternalCrossReferenceWorker, feature_category: :integrations do
include AfterNextHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/workers/integrations/execute_worker_spec.rb b/spec/workers/integrations/execute_worker_spec.rb
index 0e585e3006c..717e3c65820 100644
--- a/spec/workers/integrations/execute_worker_spec.rb
+++ b/spec/workers/integrations/execute_worker_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Integrations::ExecuteWorker, '#perform' do
+RSpec.describe Integrations::ExecuteWorker, '#perform', feature_category: :integrations do
let_it_be(:integration) { create(:jira_integration) }
let(:worker) { described_class.new }
diff --git a/spec/workers/integrations/irker_worker_spec.rb b/spec/workers/integrations/irker_worker_spec.rb
index 3b7b9af72fd..257a6f72709 100644
--- a/spec/workers/integrations/irker_worker_spec.rb
+++ b/spec/workers/integrations/irker_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::IrkerWorker, '#perform' do
+RSpec.describe Integrations::IrkerWorker, '#perform', feature_category: :integrations do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let_it_be(:push_data) { HashWithIndifferentAccess.new(Gitlab::DataBuilder::Push.build_sample(project, user)) }
diff --git a/spec/workers/invalid_gpg_signature_update_worker_spec.rb b/spec/workers/invalid_gpg_signature_update_worker_spec.rb
index 25c48b55cbb..81a15e79579 100644
--- a/spec/workers/invalid_gpg_signature_update_worker_spec.rb
+++ b/spec/workers/invalid_gpg_signature_update_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe InvalidGpgSignatureUpdateWorker do
+RSpec.describe InvalidGpgSignatureUpdateWorker, feature_category: :source_code_management do
context 'when GpgKey is found' do
it 'calls NotificationService.new.run' do
gpg_key = create(:gpg_key)
diff --git a/spec/workers/issuable/label_links_destroy_worker_spec.rb b/spec/workers/issuable/label_links_destroy_worker_spec.rb
index a838f1c8017..d993c6cb22f 100644
--- a/spec/workers/issuable/label_links_destroy_worker_spec.rb
+++ b/spec/workers/issuable/label_links_destroy_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issuable::LabelLinksDestroyWorker do
+RSpec.describe Issuable::LabelLinksDestroyWorker, feature_category: :team_planning do
let(:job_args) { [1, 'MergeRequest'] }
let(:service) { double }
diff --git a/spec/workers/issuable_export_csv_worker_spec.rb b/spec/workers/issuable_export_csv_worker_spec.rb
index a5172d916b6..66198157edb 100644
--- a/spec/workers/issuable_export_csv_worker_spec.rb
+++ b/spec/workers/issuable_export_csv_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IssuableExportCsvWorker do
+RSpec.describe IssuableExportCsvWorker, feature_category: :team_planning do
let(:user) { create(:user) }
let(:project) { create(:project, creator: user) }
let(:params) { {} }
@@ -50,6 +50,19 @@ RSpec.describe IssuableExportCsvWorker do
end
end
+ shared_examples 'export with selected fields' do
+ let(:selected_fields) { %w[Title Description'] }
+
+ it 'calls the export service with selected fields' do
+ params[:selected_fields] = selected_fields
+
+ expect(export_service)
+ .to receive(:new).with(anything, project, selected_fields).once.and_call_original
+
+ subject
+ end
+ end
+
context 'when issuable type is MergeRequest' do
let(:issuable_type) { :merge_request }
@@ -58,7 +71,7 @@ RSpec.describe IssuableExportCsvWorker do
end
it 'calls the MR export service' do
- expect(MergeRequests::ExportCsvService).to receive(:new).with(anything, project).once.and_call_original
+ expect(MergeRequests::ExportCsvService).to receive(:new).with(anything, project, []).once.and_call_original
subject
end
@@ -68,6 +81,34 @@ RSpec.describe IssuableExportCsvWorker do
subject
end
+
+ it_behaves_like 'export with selected fields' do
+ let(:export_service) { MergeRequests::ExportCsvService }
+ end
+ end
+
+ context 'for type WorkItem' do
+ let(:issuable_type) { :work_item }
+
+ it 'emails a CSV' do
+ expect { subject }.to change { ActionMailer::Base.deliveries.size }.by(1)
+ end
+
+ it 'calls the work item export service' do
+ expect(WorkItems::ExportCsvService).to receive(:new).with(anything, project, []).once.and_call_original
+
+ subject
+ end
+
+ it 'calls the WorkItemsFinder' do
+ expect(WorkItems::WorkItemsFinder).to receive(:new).once.and_call_original
+
+ subject
+ end
+
+ it_behaves_like 'export with selected fields' do
+ let(:export_service) { WorkItems::ExportCsvService }
+ end
end
context 'when issuable type is User' do
diff --git a/spec/workers/issuables/clear_groups_issue_counter_worker_spec.rb b/spec/workers/issuables/clear_groups_issue_counter_worker_spec.rb
index ac430f42e7a..e8f39388328 100644
--- a/spec/workers/issuables/clear_groups_issue_counter_worker_spec.rb
+++ b/spec/workers/issuables/clear_groups_issue_counter_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issuables::ClearGroupsIssueCounterWorker do
+RSpec.describe Issuables::ClearGroupsIssueCounterWorker, feature_category: :team_planning do
describe '#perform' do
let_it_be(:user) { create(:user) }
let_it_be(:parent_group) { create(:group) }
diff --git a/spec/workers/issue_due_scheduler_worker_spec.rb b/spec/workers/issue_due_scheduler_worker_spec.rb
index aecff4a3d93..8988dc86168 100644
--- a/spec/workers/issue_due_scheduler_worker_spec.rb
+++ b/spec/workers/issue_due_scheduler_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IssueDueSchedulerWorker do
+RSpec.describe IssueDueSchedulerWorker, feature_category: :team_planning do
describe '#perform' do
it 'schedules one MailScheduler::IssueDueWorker per project with open issues due tomorrow' do
project1 = create(:project)
diff --git a/spec/workers/issues/close_worker_spec.rb b/spec/workers/issues/close_worker_spec.rb
index 3902618ae03..488be7eb067 100644
--- a/spec/workers/issues/close_worker_spec.rb
+++ b/spec/workers/issues/close_worker_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Issues::CloseWorker do
+RSpec.describe Issues::CloseWorker, feature_category: :team_planning do
describe "#perform" do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
diff --git a/spec/workers/issues/placement_worker_spec.rb b/spec/workers/issues/placement_worker_spec.rb
index 33fa0b31b72..710b3d07938 100644
--- a/spec/workers/issues/placement_worker_spec.rb
+++ b/spec/workers/issues/placement_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::PlacementWorker do
+RSpec.describe Issues::PlacementWorker, feature_category: :team_planning do
describe '#perform' do
let_it_be(:time) { Time.now.utc }
let_it_be(:group) { create(:group) }
diff --git a/spec/workers/issues/rebalancing_worker_spec.rb b/spec/workers/issues/rebalancing_worker_spec.rb
index e1c0b348a4f..e0dccf0c56e 100644
--- a/spec/workers/issues/rebalancing_worker_spec.rb
+++ b/spec/workers/issues/rebalancing_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::RebalancingWorker do
+RSpec.describe Issues::RebalancingWorker, feature_category: :team_planning do
describe '#perform' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
diff --git a/spec/workers/issues/reschedule_stuck_issue_rebalances_worker_spec.rb b/spec/workers/issues/reschedule_stuck_issue_rebalances_worker_spec.rb
index 6723c425f34..fa23ffe92f1 100644
--- a/spec/workers/issues/reschedule_stuck_issue_rebalances_worker_spec.rb
+++ b/spec/workers/issues/reschedule_stuck_issue_rebalances_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Issues::RescheduleStuckIssueRebalancesWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe Issues::RescheduleStuckIssueRebalancesWorker, :clean_gitlab_redis_shared_state, feature_category: :team_planning do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
diff --git a/spec/workers/jira_connect/forward_event_worker_spec.rb b/spec/workers/jira_connect/forward_event_worker_spec.rb
index d3db07b8cb4..1be59d846f2 100644
--- a/spec/workers/jira_connect/forward_event_worker_spec.rb
+++ b/spec/workers/jira_connect/forward_event_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraConnect::ForwardEventWorker do
+RSpec.describe JiraConnect::ForwardEventWorker, feature_category: :integrations do
describe '#perform' do
let!(:jira_connect_installation) { create(:jira_connect_installation, instance_url: self_managed_url, client_key: client_key, shared_secret: shared_secret) }
let(:base_path) { '/-/jira_connect' }
diff --git a/spec/workers/jira_connect/retry_request_worker_spec.rb b/spec/workers/jira_connect/retry_request_worker_spec.rb
index 7a93e5fe41d..e96a050da13 100644
--- a/spec/workers/jira_connect/retry_request_worker_spec.rb
+++ b/spec/workers/jira_connect/retry_request_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraConnect::RetryRequestWorker do
+RSpec.describe JiraConnect::RetryRequestWorker, feature_category: :integrations do
describe '#perform' do
let(:jwt) { 'some-jwt' }
let(:event_url) { 'https://example.com/somewhere' }
diff --git a/spec/workers/jira_connect/sync_branch_worker_spec.rb b/spec/workers/jira_connect/sync_branch_worker_spec.rb
index 349ccd10694..54b1915b253 100644
--- a/spec/workers/jira_connect/sync_branch_worker_spec.rb
+++ b/spec/workers/jira_connect/sync_branch_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraConnect::SyncBranchWorker do
+RSpec.describe JiraConnect::SyncBranchWorker, feature_category: :integrations do
include AfterNextHelpers
it_behaves_like 'worker with data consistency',
diff --git a/spec/workers/jira_connect/sync_builds_worker_spec.rb b/spec/workers/jira_connect/sync_builds_worker_spec.rb
index 9be0cccae2b..6ef15b084a3 100644
--- a/spec/workers/jira_connect/sync_builds_worker_spec.rb
+++ b/spec/workers/jira_connect/sync_builds_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::JiraConnect::SyncBuildsWorker do
+RSpec.describe ::JiraConnect::SyncBuildsWorker, feature_category: :integrations do
include AfterNextHelpers
it_behaves_like 'worker with data consistency',
diff --git a/spec/workers/jira_connect/sync_deployments_worker_spec.rb b/spec/workers/jira_connect/sync_deployments_worker_spec.rb
index 86ba11ebe9c..2e72a94bc1e 100644
--- a/spec/workers/jira_connect/sync_deployments_worker_spec.rb
+++ b/spec/workers/jira_connect/sync_deployments_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::JiraConnect::SyncDeploymentsWorker do
+RSpec.describe ::JiraConnect::SyncDeploymentsWorker, feature_category: :integrations do
include AfterNextHelpers
it_behaves_like 'worker with data consistency',
diff --git a/spec/workers/jira_connect/sync_feature_flags_worker_spec.rb b/spec/workers/jira_connect/sync_feature_flags_worker_spec.rb
index 6763aefcbec..c2dbd52398f 100644
--- a/spec/workers/jira_connect/sync_feature_flags_worker_spec.rb
+++ b/spec/workers/jira_connect/sync_feature_flags_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::JiraConnect::SyncFeatureFlagsWorker do
+RSpec.describe ::JiraConnect::SyncFeatureFlagsWorker, feature_category: :integrations do
include AfterNextHelpers
it_behaves_like 'worker with data consistency',
diff --git a/spec/workers/jira_connect/sync_merge_request_worker_spec.rb b/spec/workers/jira_connect/sync_merge_request_worker_spec.rb
index 65976566b22..23abb915d68 100644
--- a/spec/workers/jira_connect/sync_merge_request_worker_spec.rb
+++ b/spec/workers/jira_connect/sync_merge_request_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraConnect::SyncMergeRequestWorker do
+RSpec.describe JiraConnect::SyncMergeRequestWorker, feature_category: :integrations do
include AfterNextHelpers
it_behaves_like 'worker with data consistency',
diff --git a/spec/workers/jira_connect/sync_project_worker_spec.rb b/spec/workers/jira_connect/sync_project_worker_spec.rb
index d172bde2400..afd56a3b5c1 100644
--- a/spec/workers/jira_connect/sync_project_worker_spec.rb
+++ b/spec/workers/jira_connect/sync_project_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe JiraConnect::SyncProjectWorker, factory_default: :keep do
+RSpec.describe JiraConnect::SyncProjectWorker, factory_default: :keep, feature_category: :integrations do
include AfterNextHelpers
it_behaves_like 'worker with data consistency',
diff --git a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
index 09d58a1189e..19860f32b29 100644
--- a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
+++ b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe LooseForeignKeys::CleanupWorker do
+RSpec.describe LooseForeignKeys::CleanupWorker, feature_category: :pods do
include MigrationsHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/workers/mail_scheduler/issue_due_worker_spec.rb b/spec/workers/mail_scheduler/issue_due_worker_spec.rb
index c03cc0bda61..9bdfcd7ca49 100644
--- a/spec/workers/mail_scheduler/issue_due_worker_spec.rb
+++ b/spec/workers/mail_scheduler/issue_due_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MailScheduler::IssueDueWorker do
+RSpec.describe MailScheduler::IssueDueWorker, feature_category: :team_planning do
describe '#perform' do
let(:worker) { described_class.new }
let(:project) { create(:project) }
diff --git a/spec/workers/mail_scheduler/notification_service_worker_spec.rb b/spec/workers/mail_scheduler/notification_service_worker_spec.rb
index 482d99a43c2..5ba7a0c555f 100644
--- a/spec/workers/mail_scheduler/notification_service_worker_spec.rb
+++ b/spec/workers/mail_scheduler/notification_service_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MailScheduler::NotificationServiceWorker do
+RSpec.describe MailScheduler::NotificationServiceWorker, feature_category: :team_planning do
let(:worker) { described_class.new }
let(:method) { 'new_key' }
diff --git a/spec/workers/member_invitation_reminder_emails_worker_spec.rb b/spec/workers/member_invitation_reminder_emails_worker_spec.rb
index bb4ff466584..4c6295285ea 100644
--- a/spec/workers/member_invitation_reminder_emails_worker_spec.rb
+++ b/spec/workers/member_invitation_reminder_emails_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MemberInvitationReminderEmailsWorker do
+RSpec.describe MemberInvitationReminderEmailsWorker, feature_category: :subgroups do
describe '#perform' do
subject { described_class.new.perform }
diff --git a/spec/workers/members_destroyer/unassign_issuables_worker_spec.rb b/spec/workers/members_destroyer/unassign_issuables_worker_spec.rb
index 2a325be1225..51fca67ae99 100644
--- a/spec/workers/members_destroyer/unassign_issuables_worker_spec.rb
+++ b/spec/workers/members_destroyer/unassign_issuables_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MembersDestroyer::UnassignIssuablesWorker do
+RSpec.describe MembersDestroyer::UnassignIssuablesWorker, feature_category: :user_management do
let_it_be(:group) { create(:group, :private) }
let_it_be(:user, reload: true) { create(:user) }
diff --git a/spec/workers/merge_request_cleanup_refs_worker_spec.rb b/spec/workers/merge_request_cleanup_refs_worker_spec.rb
index 1de927a81e4..a2df31037be 100644
--- a/spec/workers/merge_request_cleanup_refs_worker_spec.rb
+++ b/spec/workers/merge_request_cleanup_refs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequestCleanupRefsWorker do
+RSpec.describe MergeRequestCleanupRefsWorker, feature_category: :code_review_workflow do
let(:worker) { described_class.new }
describe '#perform_work' do
@@ -30,12 +30,12 @@ RSpec.describe MergeRequestCleanupRefsWorker do
expect(cleanup_schedule.completed_at).to be_nil
end
- context "and cleanup schedule has already failed #{described_class::FAILURE_THRESHOLD} times" do
- let(:failed_count) { described_class::FAILURE_THRESHOLD }
+ context "and cleanup schedule has already failed #{WebHooks::AutoDisabling::FAILURE_THRESHOLD} times" do
+ let(:failed_count) { WebHooks::AutoDisabling::FAILURE_THRESHOLD }
it 'marks the cleanup schedule as failed and track the failure' do
expect(cleanup_schedule.reload).to be_failed
- expect(cleanup_schedule.failed_count).to eq(described_class::FAILURE_THRESHOLD + 1)
+ expect(cleanup_schedule.failed_count).to eq(failed_count + 1)
expect(cleanup_schedule.completed_at).to be_nil
end
end
diff --git a/spec/workers/merge_request_mergeability_check_worker_spec.rb b/spec/workers/merge_request_mergeability_check_worker_spec.rb
index 32debcf9651..fd959803006 100644
--- a/spec/workers/merge_request_mergeability_check_worker_spec.rb
+++ b/spec/workers/merge_request_mergeability_check_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequestMergeabilityCheckWorker do
+RSpec.describe MergeRequestMergeabilityCheckWorker, feature_category: :code_review_workflow do
subject { described_class.new }
describe '#perform' do
diff --git a/spec/workers/merge_requests/close_issue_worker_spec.rb b/spec/workers/merge_requests/close_issue_worker_spec.rb
index 72fb3be7470..0facd34e790 100644
--- a/spec/workers/merge_requests/close_issue_worker_spec.rb
+++ b/spec/workers/merge_requests/close_issue_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::CloseIssueWorker do
+RSpec.describe MergeRequests::CloseIssueWorker, feature_category: :code_review_workflow do
subject(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/merge_requests/create_approval_event_worker_spec.rb b/spec/workers/merge_requests/create_approval_event_worker_spec.rb
index 8389949ecc9..a9a46420fd5 100644
--- a/spec/workers/merge_requests/create_approval_event_worker_spec.rb
+++ b/spec/workers/merge_requests/create_approval_event_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::CreateApprovalEventWorker do
+RSpec.describe MergeRequests::CreateApprovalEventWorker, feature_category: :code_review_workflow do
let!(:user) { create(:user) }
let!(:project) { create(:project) }
let!(:merge_request) { create(:merge_request, source_project: project) }
diff --git a/spec/workers/merge_requests/create_approval_note_worker_spec.rb b/spec/workers/merge_requests/create_approval_note_worker_spec.rb
index f58d38599fc..1a9e15c18f0 100644
--- a/spec/workers/merge_requests/create_approval_note_worker_spec.rb
+++ b/spec/workers/merge_requests/create_approval_note_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::CreateApprovalNoteWorker do
+RSpec.describe MergeRequests::CreateApprovalNoteWorker, feature_category: :code_review_workflow do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
diff --git a/spec/workers/merge_requests/delete_source_branch_worker_spec.rb b/spec/workers/merge_requests/delete_source_branch_worker_spec.rb
index e17ad02e272..d8e49f444a9 100644
--- a/spec/workers/merge_requests/delete_source_branch_worker_spec.rb
+++ b/spec/workers/merge_requests/delete_source_branch_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::DeleteSourceBranchWorker do
+RSpec.describe MergeRequests::DeleteSourceBranchWorker, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
let_it_be(:merge_request) { create(:merge_request, author: user) }
diff --git a/spec/workers/merge_requests/execute_approval_hooks_worker_spec.rb b/spec/workers/merge_requests/execute_approval_hooks_worker_spec.rb
index 0130ef63f50..13c97f8fe49 100644
--- a/spec/workers/merge_requests/execute_approval_hooks_worker_spec.rb
+++ b/spec/workers/merge_requests/execute_approval_hooks_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ExecuteApprovalHooksWorker do
+RSpec.describe MergeRequests::ExecuteApprovalHooksWorker, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
diff --git a/spec/workers/merge_requests/handle_assignees_change_worker_spec.rb b/spec/workers/merge_requests/handle_assignees_change_worker_spec.rb
index 4b45f3562d6..f776c6408ed 100644
--- a/spec/workers/merge_requests/handle_assignees_change_worker_spec.rb
+++ b/spec/workers/merge_requests/handle_assignees_change_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::HandleAssigneesChangeWorker do
+RSpec.describe MergeRequests::HandleAssigneesChangeWorker, feature_category: :code_review_workflow do
include AfterNextHelpers
let_it_be(:merge_request) { create(:merge_request) }
diff --git a/spec/workers/merge_requests/resolve_todos_after_approval_worker_spec.rb b/spec/workers/merge_requests/resolve_todos_after_approval_worker_spec.rb
index f8316a8ff05..39443d48ff6 100644
--- a/spec/workers/merge_requests/resolve_todos_after_approval_worker_spec.rb
+++ b/spec/workers/merge_requests/resolve_todos_after_approval_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ResolveTodosAfterApprovalWorker do
+RSpec.describe MergeRequests::ResolveTodosAfterApprovalWorker, feature_category: :code_review_workflow do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
diff --git a/spec/workers/merge_requests/resolve_todos_worker_spec.rb b/spec/workers/merge_requests/resolve_todos_worker_spec.rb
index 223b8b6803c..1164a1c1ddd 100644
--- a/spec/workers/merge_requests/resolve_todos_worker_spec.rb
+++ b/spec/workers/merge_requests/resolve_todos_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::ResolveTodosWorker do
+RSpec.describe MergeRequests::ResolveTodosWorker, feature_category: :code_review_workflow do
include AfterNextHelpers
let_it_be(:merge_request) { create(:merge_request) }
diff --git a/spec/workers/merge_requests/update_head_pipeline_worker_spec.rb b/spec/workers/merge_requests/update_head_pipeline_worker_spec.rb
index 3574b8296a4..912afb59412 100644
--- a/spec/workers/merge_requests/update_head_pipeline_worker_spec.rb
+++ b/spec/workers/merge_requests/update_head_pipeline_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequests::UpdateHeadPipelineWorker do
+RSpec.describe MergeRequests::UpdateHeadPipelineWorker, feature_category: :code_review_workflow do
include ProjectForksHelper
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/workers/merge_worker_spec.rb b/spec/workers/merge_worker_spec.rb
index 0268bc2388f..9c6a6564df6 100644
--- a/spec/workers/merge_worker_spec.rb
+++ b/spec/workers/merge_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeWorker do
+RSpec.describe MergeWorker, feature_category: :source_code_management do
describe "remove source branch" do
let!(:merge_request) { create(:merge_request, source_branch: "markdown") }
let!(:source_project) { merge_request.source_project }
diff --git a/spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb b/spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb
index 491ea64cff1..c7e2bbc2ad9 100644
--- a/spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb
+++ b/spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::PruneOldAnnotationsWorker do
+RSpec.describe Metrics::Dashboard::PruneOldAnnotationsWorker, feature_category: :metrics do
let_it_be(:now) { DateTime.parse('2020-06-02T00:12:00Z') }
let_it_be(:two_weeks_old_annotation) { create(:metrics_dashboard_annotation, starting_at: now.advance(weeks: -2)) }
let_it_be(:one_day_old_annotation) { create(:metrics_dashboard_annotation, starting_at: now.advance(days: -1)) }
diff --git a/spec/workers/metrics/dashboard/schedule_annotations_prune_worker_spec.rb b/spec/workers/metrics/dashboard/schedule_annotations_prune_worker_spec.rb
index e0a5a8fd448..75866a4eca2 100644
--- a/spec/workers/metrics/dashboard/schedule_annotations_prune_worker_spec.rb
+++ b/spec/workers/metrics/dashboard/schedule_annotations_prune_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::ScheduleAnnotationsPruneWorker do
+RSpec.describe Metrics::Dashboard::ScheduleAnnotationsPruneWorker, feature_category: :metrics do
describe '#perform' do
it 'schedules annotations prune job with default cut off date' do
expect(Metrics::Dashboard::PruneOldAnnotationsWorker).to receive(:perform_async)
diff --git a/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb b/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb
index 4b670a753e7..f7d67b2064e 100644
--- a/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb
+++ b/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Metrics::Dashboard::SyncDashboardsWorker do
+RSpec.describe Metrics::Dashboard::SyncDashboardsWorker, feature_category: :metrics do
include MetricsDashboardHelpers
subject(:worker) { described_class.new }
diff --git a/spec/workers/migrate_external_diffs_worker_spec.rb b/spec/workers/migrate_external_diffs_worker_spec.rb
index 36669b4e694..cb5e3ff3651 100644
--- a/spec/workers/migrate_external_diffs_worker_spec.rb
+++ b/spec/workers/migrate_external_diffs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MigrateExternalDiffsWorker do
+RSpec.describe MigrateExternalDiffsWorker, feature_category: :code_review_workflow do
let(:worker) { described_class.new }
let(:diff) { create(:merge_request).merge_request_diff }
diff --git a/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb b/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
index 2e7b6356692..237b5081bb1 100644
--- a/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
+++ b/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::InProductMarketingEmailsWorker, '#perform', unless: Gitlab.ee? do
+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.
diff --git a/spec/workers/namespaces/process_sync_events_worker_spec.rb b/spec/workers/namespaces/process_sync_events_worker_spec.rb
index 9f389089609..efa0053c145 100644
--- a/spec/workers/namespaces/process_sync_events_worker_spec.rb
+++ b/spec/workers/namespaces/process_sync_events_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::ProcessSyncEventsWorker do
+RSpec.describe Namespaces::ProcessSyncEventsWorker, feature_category: :pods do
let!(:group1) { create(:group) }
let!(:group2) { create(:group) }
let!(:group3) { create(:group) }
diff --git a/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb b/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb
index d8c60932d92..02856e16552 100644
--- a/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb
+++ b/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::PruneAggregationSchedulesWorker, '#perform', :clean_gitlab_redis_shared_state do
+RSpec.describe Namespaces::PruneAggregationSchedulesWorker, '#perform', :clean_gitlab_redis_shared_state, feature_category: :source_code_management do
include ExclusiveLeaseHelpers
let(:namespaces) { create_list(:namespace, 5, :with_aggregation_schedule) }
diff --git a/spec/workers/namespaces/root_statistics_worker_spec.rb b/spec/workers/namespaces/root_statistics_worker_spec.rb
index e047c94816f..8409fffca26 100644
--- a/spec/workers/namespaces/root_statistics_worker_spec.rb
+++ b/spec/workers/namespaces/root_statistics_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::RootStatisticsWorker, '#perform' do
+RSpec.describe Namespaces::RootStatisticsWorker, '#perform', feature_category: :source_code_management do
let(:group) { create(:group, :with_aggregation_schedule) }
subject(:worker) { described_class.new }
diff --git a/spec/workers/namespaces/schedule_aggregation_worker_spec.rb b/spec/workers/namespaces/schedule_aggregation_worker_spec.rb
index 62f9be501cc..69bd0f1ce47 100644
--- a/spec/workers/namespaces/schedule_aggregation_worker_spec.rb
+++ b/spec/workers/namespaces/schedule_aggregation_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::ScheduleAggregationWorker, '#perform', :clean_gitlab_redis_shared_state do
+RSpec.describe Namespaces::ScheduleAggregationWorker, '#perform', :clean_gitlab_redis_shared_state, feature_category: :source_code_management do
let(:group) { create(:group) }
subject(:worker) { described_class.new }
diff --git a/spec/workers/namespaces/update_root_statistics_worker_spec.rb b/spec/workers/namespaces/update_root_statistics_worker_spec.rb
index f2f633a39ca..85fd68094ce 100644
--- a/spec/workers/namespaces/update_root_statistics_worker_spec.rb
+++ b/spec/workers/namespaces/update_root_statistics_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Namespaces::UpdateRootStatisticsWorker do
+RSpec.describe Namespaces::UpdateRootStatisticsWorker, feature_category: :source_code_management do
let(:namespace_id) { 123 }
let(:event) do
diff --git a/spec/workers/new_issue_worker_spec.rb b/spec/workers/new_issue_worker_spec.rb
index b9053b10419..540296374ef 100644
--- a/spec/workers/new_issue_worker_spec.rb
+++ b/spec/workers/new_issue_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe NewIssueWorker do
+RSpec.describe NewIssueWorker, feature_category: :team_planning do
include AfterNextHelpers
describe '#perform' do
diff --git a/spec/workers/new_merge_request_worker_spec.rb b/spec/workers/new_merge_request_worker_spec.rb
index a8e1c3f4bf1..58f6792f9a0 100644
--- a/spec/workers/new_merge_request_worker_spec.rb
+++ b/spec/workers/new_merge_request_worker_spec.rb
@@ -107,18 +107,6 @@ RSpec.describe NewMergeRequestWorker, feature_category: :code_review_workflow do
stub_feature_flags(add_prepared_state_to_mr: true)
end
- context 'when the merge request is prepared' do
- before do
- merge_request.update!(prepared_at: Time.current)
- 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 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|
diff --git a/spec/workers/new_note_worker_spec.rb b/spec/workers/new_note_worker_spec.rb
index 7ba3fe94254..651b5742854 100644
--- a/spec/workers/new_note_worker_spec.rb
+++ b/spec/workers/new_note_worker_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe NewNoteWorker do
+RSpec.describe NewNoteWorker, feature_category: :team_planning do
context 'when Note found' do
let(:note) { create(:note) }
diff --git a/spec/workers/object_pool/create_worker_spec.rb b/spec/workers/object_pool/create_worker_spec.rb
index 4ec409bdf47..573cb3413f5 100644
--- a/spec/workers/object_pool/create_worker_spec.rb
+++ b/spec/workers/object_pool/create_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ObjectPool::CreateWorker do
+RSpec.describe ObjectPool::CreateWorker, feature_category: :shared do
let(:pool) { create(:pool_repository, :scheduled) }
subject { described_class.new }
diff --git a/spec/workers/object_pool/destroy_worker_spec.rb b/spec/workers/object_pool/destroy_worker_spec.rb
index 130a666a42e..f83d3814c63 100644
--- a/spec/workers/object_pool/destroy_worker_spec.rb
+++ b/spec/workers/object_pool/destroy_worker_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ObjectPool::DestroyWorker do
+RSpec.describe ObjectPool::DestroyWorker, feature_category: :shared do
describe '#perform' do
context 'when no pool is in the database' do
it "doesn't raise an error" do
diff --git a/spec/workers/object_pool/join_worker_spec.rb b/spec/workers/object_pool/join_worker_spec.rb
index 335c45e14e0..e0173cad53b 100644
--- a/spec/workers/object_pool/join_worker_spec.rb
+++ b/spec/workers/object_pool/join_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ObjectPool::JoinWorker do
+RSpec.describe ObjectPool::JoinWorker, feature_category: :shared do
let(:pool) { create(:pool_repository, :ready) }
let(:project) { pool.source_project }
let(:repository) { project.repository }
diff --git a/spec/workers/onboarding/issue_created_worker_spec.rb b/spec/workers/onboarding/issue_created_worker_spec.rb
index 70a0156d444..d12f51ceff6 100644
--- a/spec/workers/onboarding/issue_created_worker_spec.rb
+++ b/spec/workers/onboarding/issue_created_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Onboarding::IssueCreatedWorker, '#perform' do
+RSpec.describe Onboarding::IssueCreatedWorker, '#perform', feature_category: :onboarding do
let_it_be(:issue) { create(:issue) }
let(:namespace) { issue.project.namespace }
diff --git a/spec/workers/onboarding/pipeline_created_worker_spec.rb b/spec/workers/onboarding/pipeline_created_worker_spec.rb
index 75bdea28eef..e6dc0f9b689 100644
--- a/spec/workers/onboarding/pipeline_created_worker_spec.rb
+++ b/spec/workers/onboarding/pipeline_created_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Onboarding::PipelineCreatedWorker, '#perform' do
+RSpec.describe Onboarding::PipelineCreatedWorker, '#perform', feature_category: :onboarding do
let_it_be(:ci_pipeline) { create(:ci_pipeline) }
it_behaves_like 'records an onboarding progress action', :pipeline_created do
diff --git a/spec/workers/onboarding/progress_worker_spec.rb b/spec/workers/onboarding/progress_worker_spec.rb
index bbf4875069e..da760c23367 100644
--- a/spec/workers/onboarding/progress_worker_spec.rb
+++ b/spec/workers/onboarding/progress_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Onboarding::ProgressWorker, '#perform' do
+RSpec.describe Onboarding::ProgressWorker, '#perform', feature_category: :onboarding do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:action) { 'git_pull' }
diff --git a/spec/workers/onboarding/user_added_worker_spec.rb b/spec/workers/onboarding/user_added_worker_spec.rb
index 6dbd875c93b..d32bd5ee19c 100644
--- a/spec/workers/onboarding/user_added_worker_spec.rb
+++ b/spec/workers/onboarding/user_added_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Onboarding::UserAddedWorker, '#perform' do
+RSpec.describe Onboarding::UserAddedWorker, '#perform', feature_category: :onboarding do
let_it_be(:namespace) { create(:group) }
subject { described_class.new.perform(namespace.id) }
diff --git a/spec/workers/packages/cleanup/execute_policy_worker_spec.rb b/spec/workers/packages/cleanup/execute_policy_worker_spec.rb
index 6325a82ed3d..fc3ed1f3a05 100644
--- a/spec/workers/packages/cleanup/execute_policy_worker_spec.rb
+++ b/spec/workers/packages/cleanup/execute_policy_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Cleanup::ExecutePolicyWorker do
+RSpec.describe Packages::Cleanup::ExecutePolicyWorker, feature_category: :package_registry do
let(:worker) { described_class.new }
describe '#perform_work' do
diff --git a/spec/workers/packages/cleanup_package_file_worker_spec.rb b/spec/workers/packages/cleanup_package_file_worker_spec.rb
index 95cf65c18c5..6e42565abbc 100644
--- a/spec/workers/packages/cleanup_package_file_worker_spec.rb
+++ b/spec/workers/packages/cleanup_package_file_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::CleanupPackageFileWorker do
+RSpec.describe Packages::CleanupPackageFileWorker, feature_category: :package_registry do
let_it_be_with_reload(:package) { create(:package) }
let(:worker) { described_class.new }
diff --git a/spec/workers/packages/cleanup_package_registry_worker_spec.rb b/spec/workers/packages/cleanup_package_registry_worker_spec.rb
index e12f2198f66..f70103070ef 100644
--- a/spec/workers/packages/cleanup_package_registry_worker_spec.rb
+++ b/spec/workers/packages/cleanup_package_registry_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::CleanupPackageRegistryWorker do
+RSpec.describe Packages::CleanupPackageRegistryWorker, feature_category: :package_registry do
describe '#perform' do
let_it_be_with_reload(:package_files) { create_list(:package_file, 2, :pending_destruction) }
let_it_be(:policy) { create(:packages_cleanup_policy, :runnable) }
diff --git a/spec/workers/packages/composer/cache_cleanup_worker_spec.rb b/spec/workers/packages/composer/cache_cleanup_worker_spec.rb
index 39eac4e4ae1..67d4ce36437 100644
--- a/spec/workers/packages/composer/cache_cleanup_worker_spec.rb
+++ b/spec/workers/packages/composer/cache_cleanup_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Composer::CacheCleanupWorker, type: :worker do
+RSpec.describe Packages::Composer::CacheCleanupWorker, type: :worker, feature_category: :package_registry do
describe '#perform' do
let_it_be(:group) { create(:group) }
diff --git a/spec/workers/packages/composer/cache_update_worker_spec.rb b/spec/workers/packages/composer/cache_update_worker_spec.rb
index 6c17d49e986..cc3047895d4 100644
--- a/spec/workers/packages/composer/cache_update_worker_spec.rb
+++ b/spec/workers/packages/composer/cache_update_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Composer::CacheUpdateWorker, type: :worker do
+RSpec.describe Packages::Composer::CacheUpdateWorker, type: :worker, feature_category: :package_registry do
describe '#perform' do
let_it_be(:package_name) { 'sample-project' }
let_it_be(:json) { { 'name' => package_name } }
diff --git a/spec/workers/packages/debian/generate_distribution_worker_spec.rb b/spec/workers/packages/debian/generate_distribution_worker_spec.rb
index c4e974ec8eb..acdfcc5275f 100644
--- a/spec/workers/packages/debian/generate_distribution_worker_spec.rb
+++ b/spec/workers/packages/debian/generate_distribution_worker_spec.rb
@@ -4,13 +4,13 @@ require 'spec_helper'
RSpec.describe Packages::Debian::GenerateDistributionWorker, type: :worker, feature_category: :package_registry do
describe '#perform' do
- let(:container_type) { distribution.container_type }
+ let(:container_type_as_string) { container_type.to_s }
let(:distribution_id) { distribution.id }
- subject { described_class.new.perform(container_type, distribution_id) }
+ subject { described_class.new.perform(container_type_as_string, distribution_id) }
- let(:subject2) { described_class.new.perform(container_type, distribution_id) }
- let(:subject3) { described_class.new.perform(container_type, distribution_id) }
+ let(:subject2) { described_class.new.perform(container_type_as_string, distribution_id) }
+ let(:subject3) { described_class.new.perform(container_type_as_string, distribution_id) }
include_context 'with published Debian package'
@@ -54,7 +54,7 @@ RSpec.describe Packages::Debian::GenerateDistributionWorker, type: :worker, feat
context 'with valid parameters' do
it_behaves_like 'an idempotent worker' do
- let(:job_args) { [container_type, distribution_id] }
+ let(:job_args) { [container_type_as_string, distribution_id] }
it_behaves_like 'Generate Debian Distribution and component files'
end
diff --git a/spec/workers/packages/debian/process_changes_worker_spec.rb b/spec/workers/packages/debian/process_changes_worker_spec.rb
index b96b75e93b9..ddd608e768c 100644
--- a/spec/workers/packages/debian/process_changes_worker_spec.rb
+++ b/spec/workers/packages/debian/process_changes_worker_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe Packages::Debian::ProcessChangesWorker, type: :worker, feature_ca
expect { subject }
.to not_change { Packages::Package.count }
.and change { Packages::PackageFile.count }.by(-1)
- .and change { incoming.package_files.count }.from(7).to(6)
+ .and change { incoming.package_files.count }.from(8).to(7)
end
end
@@ -104,7 +104,7 @@ RSpec.describe Packages::Debian::ProcessChangesWorker, type: :worker, feature_ca
expect { subject }
.to not_change { Packages::Package.count }
.and change { Packages::PackageFile.count }.by(-1)
- .and change { incoming.package_files.count }.from(7).to(6)
+ .and change { incoming.package_files.count }.from(8).to(7)
expect { package_file.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
@@ -120,7 +120,7 @@ RSpec.describe Packages::Debian::ProcessChangesWorker, type: :worker, feature_ca
expect { subject }
.to change { Packages::Package.count }.from(1).to(2)
.and not_change { Packages::PackageFile.count }
- .and change { incoming.package_files.count }.from(7).to(0)
+ .and change { incoming.package_files.count }.from(8).to(0)
.and change { package_file&.debian_file_metadatum&.reload&.file_type }.from('unknown').to('changes')
created_package = Packages::Package.last
diff --git a/spec/workers/packages/debian/process_package_file_worker_spec.rb b/spec/workers/packages/debian/process_package_file_worker_spec.rb
index 239ee8e1035..44769ec6a14 100644
--- a/spec/workers/packages/debian/process_package_file_worker_spec.rb
+++ b/spec/workers/packages/debian/process_package_file_worker_spec.rb
@@ -31,6 +31,7 @@ RSpec.describe Packages::Debian::ProcessPackageFileWorker, type: :worker, featur
where(:case_name, :expected_file_type, :file_name, :component_name) do
'with a deb' | 'deb' | 'libsample0_1.2.3~alpha2_amd64.deb' | 'main'
'with an udeb' | 'udeb' | 'sample-udeb_1.2.3~alpha2_amd64.udeb' | 'contrib'
+ 'with a ddeb' | 'ddeb' | 'sample-ddeb_1.2.3~alpha2_amd64.ddeb' | 'main'
end
with_them do
diff --git a/spec/workers/packages/go/sync_packages_worker_spec.rb b/spec/workers/packages/go/sync_packages_worker_spec.rb
index 5eeef1f7c08..5fdb7a242f6 100644
--- a/spec/workers/packages/go/sync_packages_worker_spec.rb
+++ b/spec/workers/packages/go/sync_packages_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Go::SyncPackagesWorker, type: :worker do
+RSpec.describe Packages::Go::SyncPackagesWorker, type: :worker, feature_category: :package_registry do
include_context 'basic Go module'
before do
diff --git a/spec/workers/packages/helm/extraction_worker_spec.rb b/spec/workers/packages/helm/extraction_worker_spec.rb
index 70a090d6989..a764c2ad939 100644
--- a/spec/workers/packages/helm/extraction_worker_spec.rb
+++ b/spec/workers/packages/helm/extraction_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Helm::ExtractionWorker, type: :worker do
+RSpec.describe Packages::Helm::ExtractionWorker, type: :worker, feature_category: :package_registry do
describe '#perform' do
let_it_be(:package) { create(:helm_package, without_package_files: true, status: 'processing') }
diff --git a/spec/workers/packages/mark_package_files_for_destruction_worker_spec.rb b/spec/workers/packages/mark_package_files_for_destruction_worker_spec.rb
index 15d9e4c347b..29fbf17d49a 100644
--- a/spec/workers/packages/mark_package_files_for_destruction_worker_spec.rb
+++ b/spec/workers/packages/mark_package_files_for_destruction_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::MarkPackageFilesForDestructionWorker, :aggregate_failures do
+RSpec.describe Packages::MarkPackageFilesForDestructionWorker, :aggregate_failures, feature_category: :package_registry do
describe '#perform' do
let_it_be(:package) { create(:package) }
let_it_be(:package_files) { create_list(:package_file, 3, package: package) }
diff --git a/spec/workers/packages/nuget/extraction_worker_spec.rb b/spec/workers/packages/nuget/extraction_worker_spec.rb
index 5186c037dc5..d6cc2315fb3 100644
--- a/spec/workers/packages/nuget/extraction_worker_spec.rb
+++ b/spec/workers/packages/nuget/extraction_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Nuget::ExtractionWorker, type: :worker do
+RSpec.describe Packages::Nuget::ExtractionWorker, type: :worker, feature_category: :package_registry do
describe '#perform' do
let!(:package) { create(:nuget_package) }
let(:package_file) { package.package_files.first }
diff --git a/spec/workers/packages/rubygems/extraction_worker_spec.rb b/spec/workers/packages/rubygems/extraction_worker_spec.rb
index 0e67f3ac62e..8ad4c2e6447 100644
--- a/spec/workers/packages/rubygems/extraction_worker_spec.rb
+++ b/spec/workers/packages/rubygems/extraction_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Rubygems::ExtractionWorker, type: :worker do
+RSpec.describe Packages::Rubygems::ExtractionWorker, type: :worker, feature_category: :package_registry do
describe '#perform' do
let_it_be(:package) { create(:rubygems_package, :processing) }
diff --git a/spec/workers/pages_domain_removal_cron_worker_spec.rb b/spec/workers/pages_domain_removal_cron_worker_spec.rb
index f152d019de6..eb9f87bd831 100644
--- a/spec/workers/pages_domain_removal_cron_worker_spec.rb
+++ b/spec/workers/pages_domain_removal_cron_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PagesDomainRemovalCronWorker do
+RSpec.describe PagesDomainRemovalCronWorker, feature_category: :pages do
subject(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb b/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb
index 70ffef5342e..5711b7787ea 100644
--- a/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb
+++ b/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PagesDomainSslRenewalCronWorker do
+RSpec.describe PagesDomainSslRenewalCronWorker, feature_category: :pages do
include LetsEncryptHelpers
subject(:worker) { described_class.new }
diff --git a/spec/workers/pages_domain_ssl_renewal_worker_spec.rb b/spec/workers/pages_domain_ssl_renewal_worker_spec.rb
index f8149b23a08..daaa939ecfe 100644
--- a/spec/workers/pages_domain_ssl_renewal_worker_spec.rb
+++ b/spec/workers/pages_domain_ssl_renewal_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PagesDomainSslRenewalWorker do
+RSpec.describe PagesDomainSslRenewalWorker, feature_category: :pages do
include LetsEncryptHelpers
subject(:worker) { described_class.new }
diff --git a/spec/workers/pages_domain_verification_cron_worker_spec.rb b/spec/workers/pages_domain_verification_cron_worker_spec.rb
index 01eaf984c90..be30e45fc94 100644
--- a/spec/workers/pages_domain_verification_cron_worker_spec.rb
+++ b/spec/workers/pages_domain_verification_cron_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PagesDomainVerificationCronWorker do
+RSpec.describe PagesDomainVerificationCronWorker, feature_category: :pages do
subject(:worker) { described_class.new }
describe '#perform', :sidekiq do
diff --git a/spec/workers/pages_domain_verification_worker_spec.rb b/spec/workers/pages_domain_verification_worker_spec.rb
index 6d2f9ee2f8d..08f383c954f 100644
--- a/spec/workers/pages_domain_verification_worker_spec.rb
+++ b/spec/workers/pages_domain_verification_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PagesDomainVerificationWorker do
+RSpec.describe PagesDomainVerificationWorker, feature_category: :pages do
subject(:worker) { described_class.new }
let(:domain) { create(:pages_domain) }
diff --git a/spec/workers/pages_worker_spec.rb b/spec/workers/pages_worker_spec.rb
index f0d29037fa4..74da4707205 100644
--- a/spec/workers/pages_worker_spec.rb
+++ b/spec/workers/pages_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PagesWorker, :sidekiq_inline do
+RSpec.describe PagesWorker, :sidekiq_inline, feature_category: :pages do
let_it_be(:ci_build) { create(:ci_build) }
context 'when called with the deploy action' do
diff --git a/spec/workers/partition_creation_worker_spec.rb b/spec/workers/partition_creation_worker_spec.rb
index 5d15870b7f6..ab525fd5ce2 100644
--- a/spec/workers/partition_creation_worker_spec.rb
+++ b/spec/workers/partition_creation_worker_spec.rb
@@ -2,7 +2,7 @@
#
require 'spec_helper'
-RSpec.describe PartitionCreationWorker do
+RSpec.describe PartitionCreationWorker, feature_category: :database do
subject { described_class.new.perform }
let(:management_worker) { double }
diff --git a/spec/workers/personal_access_tokens/expired_notification_worker_spec.rb b/spec/workers/personal_access_tokens/expired_notification_worker_spec.rb
index 7c3c48b3f80..7a3491b49d6 100644
--- a/spec/workers/personal_access_tokens/expired_notification_worker_spec.rb
+++ b/spec/workers/personal_access_tokens/expired_notification_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PersonalAccessTokens::ExpiredNotificationWorker, type: :worker do
+RSpec.describe PersonalAccessTokens::ExpiredNotificationWorker, type: :worker, feature_category: :system_access do
subject(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/personal_access_tokens/expiring_worker_spec.rb b/spec/workers/personal_access_tokens/expiring_worker_spec.rb
index 7fa777b911a..01ce4e85fe2 100644
--- a/spec/workers/personal_access_tokens/expiring_worker_spec.rb
+++ b/spec/workers/personal_access_tokens/expiring_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PersonalAccessTokens::ExpiringWorker, type: :worker do
+RSpec.describe PersonalAccessTokens::ExpiringWorker, type: :worker, feature_category: :system_access do
subject(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/pipeline_hooks_worker_spec.rb b/spec/workers/pipeline_hooks_worker_spec.rb
index 5d28b1e129a..a8b0f91bf7d 100644
--- a/spec/workers/pipeline_hooks_worker_spec.rb
+++ b/spec/workers/pipeline_hooks_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PipelineHooksWorker do
+RSpec.describe PipelineHooksWorker, feature_category: :continuous_integration do
describe '#perform' do
context 'when pipeline exists' do
let(:pipeline) { create(:ci_pipeline) }
diff --git a/spec/workers/pipeline_metrics_worker_spec.rb b/spec/workers/pipeline_metrics_worker_spec.rb
index c73b84e26a6..f7b397d91a6 100644
--- a/spec/workers/pipeline_metrics_worker_spec.rb
+++ b/spec/workers/pipeline_metrics_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PipelineMetricsWorker do
+RSpec.describe PipelineMetricsWorker, feature_category: :continuous_integration do
let(:project) { create(:project, :repository) }
let!(:merge_request) do
diff --git a/spec/workers/pipeline_notification_worker_spec.rb b/spec/workers/pipeline_notification_worker_spec.rb
index 672debd0501..05d0186e873 100644
--- a/spec/workers/pipeline_notification_worker_spec.rb
+++ b/spec/workers/pipeline_notification_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PipelineNotificationWorker, :mailer do
+RSpec.describe PipelineNotificationWorker, :mailer, feature_category: :continuous_integration do
let_it_be(:pipeline) { create(:ci_pipeline) }
describe '#execute' do
diff --git a/spec/workers/pipeline_process_worker_spec.rb b/spec/workers/pipeline_process_worker_spec.rb
index 6e95b7a4753..6c6851c51ce 100644
--- a/spec/workers/pipeline_process_worker_spec.rb
+++ b/spec/workers/pipeline_process_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PipelineProcessWorker do
+RSpec.describe PipelineProcessWorker, feature_category: :continuous_integration do
let_it_be(:pipeline) { create(:ci_pipeline) }
include_examples 'an idempotent worker' do
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 210987555c9..bd1bfc46d53 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PostReceive do
+RSpec.describe PostReceive, feature_category: :source_code_management do
include AfterNextHelpers
let(:changes) do
@@ -280,7 +280,6 @@ RSpec.describe PostReceive do
let(:category) { described_class.name }
let(:namespace) { project.namespace }
let(:user) { project.creator }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
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] }
diff --git a/spec/workers/process_commit_worker_spec.rb b/spec/workers/process_commit_worker_spec.rb
index 143809e8f2a..1fc77c42cbc 100644
--- a/spec/workers/process_commit_worker_spec.rb
+++ b/spec/workers/process_commit_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProcessCommitWorker do
+RSpec.describe ProcessCommitWorker, feature_category: :source_code_management do
let(:worker) { described_class.new }
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/workers/project_cache_worker_spec.rb b/spec/workers/project_cache_worker_spec.rb
index 3c807ef9ffd..508dacea2fb 100644
--- a/spec/workers/project_cache_worker_spec.rb
+++ b/spec/workers/project_cache_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProjectCacheWorker do
+RSpec.describe ProjectCacheWorker, feature_category: :source_code_management do
include ExclusiveLeaseHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/workers/project_destroy_worker_spec.rb b/spec/workers/project_destroy_worker_spec.rb
index 25508928bbf..d699393d7a0 100644
--- a/spec/workers/project_destroy_worker_spec.rb
+++ b/spec/workers/project_destroy_worker_spec.rb
@@ -2,15 +2,26 @@
require 'spec_helper'
-RSpec.describe ProjectDestroyWorker do
- let(:project) { create(:project, :repository, pending_delete: true) }
- let!(:repository) { project.repository.raw }
+RSpec.describe ProjectDestroyWorker, feature_category: :source_code_management do
+ let_it_be(:project) { create(:project, :repository, pending_delete: true) }
+ let_it_be(:repository) { project.repository.raw }
- subject { described_class.new }
+ let(:user) { project.first_owner }
+
+ subject(:worker) { described_class.new }
+
+ include_examples 'an idempotent worker' do
+ let(:job_args) { [project.id, user.id, {}] }
+
+ it 'does not change projects when run twice' do
+ expect { worker.perform(project.id, user.id, {}) }.to change { Project.count }.by(-1)
+ expect { worker.perform(project.id, user.id, {}) }.not_to change { Project.count }
+ end
+ end
describe '#perform' do
it 'deletes the project' do
- subject.perform(project.id, project.first_owner.id, {})
+ worker.perform(project.id, user.id, {})
expect(Project.all).not_to include(project)
expect(repository).not_to exist
@@ -18,13 +29,13 @@ RSpec.describe ProjectDestroyWorker do
it 'does not raise error when project could not be found' do
expect do
- subject.perform(-1, project.first_owner.id, {})
+ worker.perform(-1, user.id, {})
end.not_to raise_error
end
it 'does not raise error when user could not be found' do
expect do
- subject.perform(project.id, -1, {})
+ worker.perform(project.id, -1, {})
end.not_to raise_error
end
end
diff --git a/spec/workers/project_export_worker_spec.rb b/spec/workers/project_export_worker_spec.rb
index dd0a921059d..eaf1536da63 100644
--- a/spec/workers/project_export_worker_spec.rb
+++ b/spec/workers/project_export_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProjectExportWorker do
+RSpec.describe ProjectExportWorker, feature_category: :importers do
it_behaves_like 'export worker'
context 'exporters duration measuring' do
diff --git a/spec/workers/projects/after_import_worker_spec.rb b/spec/workers/projects/after_import_worker_spec.rb
index 85d15c89b0a..5af4f49d6e0 100644
--- a/spec/workers/projects/after_import_worker_spec.rb
+++ b/spec/workers/projects/after_import_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::AfterImportWorker do
+RSpec.describe Projects::AfterImportWorker, feature_category: :importers do
subject { worker.perform(project.id) }
let(:worker) { described_class.new }
diff --git a/spec/workers/projects/finalize_project_statistics_refresh_worker_spec.rb b/spec/workers/projects/finalize_project_statistics_refresh_worker_spec.rb
index 932ba29f806..1379b6785eb 100644
--- a/spec/workers/projects/finalize_project_statistics_refresh_worker_spec.rb
+++ b/spec/workers/projects/finalize_project_statistics_refresh_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::FinalizeProjectStatisticsRefreshWorker do
+RSpec.describe Projects::FinalizeProjectStatisticsRefreshWorker, feature_category: :projects do
let_it_be(:record) { create(:project_build_artifacts_size_refresh, :finalizing) }
describe '#perform' do
diff --git a/spec/workers/projects/import_export/create_relation_exports_worker_spec.rb b/spec/workers/projects/import_export/create_relation_exports_worker_spec.rb
new file mode 100644
index 00000000000..2ff91150fda
--- /dev/null
+++ b/spec/workers/projects/import_export/create_relation_exports_worker_spec.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::ImportExport::CreateRelationExportsWorker, feature_category: :importers do
+ let_it_be(:user) { build_stubbed(:user) }
+ let_it_be(:project) { create(:project) }
+
+ let(:after_export_strategy) { {} }
+ let(:job_args) { [user.id, project.id, after_export_strategy] }
+
+ before do
+ allow_next_instance_of(described_class) do |job|
+ allow(job).to receive(:jid) { SecureRandom.hex(8) }
+ end
+ end
+
+ it_behaves_like 'an idempotent worker'
+
+ context 'when job is re-enqueued after an interuption and same JID is used' do
+ before do
+ allow_next_instance_of(described_class) do |job|
+ allow(job).to receive(:jid).and_return(1234)
+ end
+ end
+
+ it_behaves_like 'an idempotent worker'
+
+ it 'does not start the export process twice' do
+ project.export_jobs.create!(jid: 1234, status_event: :start)
+
+ expect { described_class.new.perform(user.id, project.id, after_export_strategy) }
+ .to change { Projects::ImportExport::WaitRelationExportsWorker.jobs.size }.by(0)
+ end
+ end
+
+ it 'creates a export_job and sets the status to `started`' do
+ described_class.new.perform(user.id, project.id, after_export_strategy)
+
+ export_job = project.export_jobs.last
+ expect(export_job.started?).to eq(true)
+ end
+
+ it 'creates relation export records and enqueues a worker for each relation to be exported' do
+ allow(Projects::ImportExport::RelationExport).to receive(:relation_names_list).and_return(%w[relation_1 relation_2])
+
+ expect { described_class.new.perform(user.id, project.id, after_export_strategy) }
+ .to change { Projects::ImportExport::RelationExportWorker.jobs.size }.by(2)
+
+ relation_exports = project.export_jobs.last.relation_exports
+ expect(relation_exports.collect(&:relation)).to match_array(%w[relation_1 relation_2])
+ end
+
+ it 'enqueues a WaitRelationExportsWorker' do
+ allow(Projects::ImportExport::WaitRelationExportsWorker).to receive(:perform_in)
+
+ described_class.new.perform(user.id, project.id, after_export_strategy)
+
+ export_job = project.export_jobs.last
+ expect(Projects::ImportExport::WaitRelationExportsWorker).to have_received(:perform_in).with(
+ described_class::INITIAL_DELAY,
+ export_job.id,
+ user.id,
+ after_export_strategy
+ )
+ end
+end
diff --git a/spec/workers/projects/import_export/relation_export_worker_spec.rb b/spec/workers/projects/import_export/relation_export_worker_spec.rb
index 236650fe55b..16ee73040b1 100644
--- a/spec/workers/projects/import_export/relation_export_worker_spec.rb
+++ b/spec/workers/projects/import_export/relation_export_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ImportExport::RelationExportWorker, type: :worker do
+RSpec.describe Projects::ImportExport::RelationExportWorker, type: :worker, feature_category: :importers do
let(:project_relation_export) { create(:project_relation_export) }
let(:job_args) { [project_relation_export.id] }
@@ -11,26 +11,61 @@ RSpec.describe Projects::ImportExport::RelationExportWorker, type: :worker do
describe '#perform' do
subject(:worker) { described_class.new }
- context 'when relation export has initial state queued' do
- let(:project_relation_export) { create(:project_relation_export) }
+ context 'when relation export has initial status `queued`' do
+ it 'exports the relation' do
+ expect_next_instance_of(Projects::ImportExport::RelationExportService) do |service|
+ expect(service).to receive(:execute)
+ end
- it 'calls RelationExportService' do
+ worker.perform(project_relation_export.id)
+ end
+ end
+
+ context 'when relation export has status `started`' do
+ let(:project_relation_export) { create(:project_relation_export, :started) }
+
+ it 'retries the export of the relation' do
expect_next_instance_of(Projects::ImportExport::RelationExportService) do |service|
expect(service).to receive(:execute)
end
worker.perform(project_relation_export.id)
+
+ expect(project_relation_export.reload.queued?).to eq(true)
end
end
- context 'when relation export does not have queued state' do
- let(:project_relation_export) { create(:project_relation_export, status_event: :start) }
+ context 'when relation export does not have status `queued` or `started`' do
+ let(:project_relation_export) { create(:project_relation_export, :finished) }
- it 'does not call RelationExportService' do
+ it 'does not export the relation' do
expect(Projects::ImportExport::RelationExportService).not_to receive(:new)
worker.perform(project_relation_export.id)
end
end
end
+
+ describe '.sidekiq_retries_exhausted' do
+ let(:job) { { 'args' => [project_relation_export.id], 'error_message' => 'Error message' } }
+
+ it 'sets relation export status to `failed`' do
+ described_class.sidekiq_retries_exhausted_block.call(job)
+
+ expect(project_relation_export.reload.failed?).to eq(true)
+ end
+
+ it 'logs the error message' do
+ expect_next_instance_of(Gitlab::Export::Logger) do |logger|
+ expect(logger).to receive(:error).with(
+ hash_including(
+ message: 'Project relation export failed',
+ export_error: 'Error message'
+ )
+ )
+ end
+
+ described_class.sidekiq_retries_exhausted_block.call(job)
+ end
+ end
end
diff --git a/spec/workers/projects/import_export/wait_relation_exports_worker_spec.rb b/spec/workers/projects/import_export/wait_relation_exports_worker_spec.rb
new file mode 100644
index 00000000000..52394b8998e
--- /dev/null
+++ b/spec/workers/projects/import_export/wait_relation_exports_worker_spec.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::ImportExport::WaitRelationExportsWorker, feature_category: :importers do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project_export_job) { create(:project_export_job, :started) }
+
+ let(:after_export_strategy) { {} }
+ let(:job_args) { [project_export_job.id, user.id, after_export_strategy] }
+
+ def create_relation_export(trait, relation, export_error = nil)
+ create(:project_relation_export, trait,
+ { project_export_job: project_export_job, relation: relation, export_error: export_error }
+ )
+ end
+
+ before do
+ allow_next_instance_of(described_class) do |job|
+ allow(job).to receive(:jid) { SecureRandom.hex(8) }
+ end
+ end
+
+ context 'when export job status is not `started`' do
+ it 'does not perform any operation and finishes the worker' do
+ finished_export_job = create(:project_export_job, :finished)
+
+ expect { described_class.new.perform(finished_export_job.id, user.id, after_export_strategy) }
+ .to change { Projects::ImportExport::ParallelProjectExportWorker.jobs.size }.by(0)
+ .and change { described_class.jobs.size }.by(0)
+ end
+ end
+
+ context 'when there are relation exports with status `queued`' do
+ before do
+ create_relation_export(:finished, 'labels')
+ create_relation_export(:started, 'milestones')
+ create_relation_export(:queued, 'merge_requests')
+ end
+
+ it 'does not enqueue ParallelProjectExportWorker and re-enqueue WaitRelationExportsWorker' do
+ expect { described_class.new.perform(*job_args) }
+ .to change { Projects::ImportExport::ParallelProjectExportWorker.jobs.size }.by(0)
+ .and change { described_class.jobs.size }.by(1)
+ end
+ end
+
+ context 'when there are relation exports with status `started`' do
+ let(:started_relation_export) { create_relation_export(:started, 'releases') }
+
+ before do
+ create_relation_export(:finished, 'labels')
+ create_relation_export(:queued, 'merge_requests')
+ end
+
+ context 'when the Sidekiq Job exporting the relation is still running' do
+ it "does not change relation export's status and re-enqueue WaitRelationExportsWorker" do
+ allow(Gitlab::SidekiqStatus).to receive(:running?).with(started_relation_export.jid).and_return(true)
+
+ expect { described_class.new.perform(*job_args) }
+ .to change { described_class.jobs.size }.by(1)
+
+ expect(started_relation_export.reload.started?).to eq(true)
+ end
+ end
+
+ context 'when the Sidekiq Job exporting the relation is still is no longer running' do
+ it "set the relation export's status to `failed`" do
+ allow(Gitlab::SidekiqStatus).to receive(:running?).with(started_relation_export.jid).and_return(false)
+
+ expect { described_class.new.perform(*job_args) }
+ .to change { described_class.jobs.size }.by(1)
+
+ expect(started_relation_export.reload.failed?).to eq(true)
+ end
+ end
+ end
+
+ context 'when all relation exports have status `finished`' do
+ before do
+ create_relation_export(:finished, 'labels')
+ create_relation_export(:finished, 'issues')
+ end
+
+ it 'enqueues ParallelProjectExportWorker and does not reenqueue WaitRelationExportsWorker' do
+ expect { described_class.new.perform(*job_args) }
+ .to change { Projects::ImportExport::ParallelProjectExportWorker.jobs.size }.by(1)
+ .and change { described_class.jobs.size }.by(0)
+ end
+
+ it_behaves_like 'an idempotent worker'
+ end
+
+ context 'when at least one relation export has status `failed` and the rest have status `finished` or `failed`' do
+ before do
+ create_relation_export(:finished, 'labels')
+ create_relation_export(:failed, 'issues', 'Failed to export issues')
+ create_relation_export(:failed, 'releases', 'Failed to export releases')
+ end
+
+ it_behaves_like 'an idempotent worker' do
+ it 'notifies the failed exports to the user' do
+ expect_next_instance_of(NotificationService) do |notification_service|
+ expect(notification_service).to receive(:project_not_exported)
+ .with(
+ project_export_job.project,
+ user,
+ array_including(['Failed to export issues', 'Failed to export releases'])
+ )
+ .once
+ end
+
+ described_class.new.perform(*job_args)
+ end
+ end
+
+ it 'does not enqueue ParallelProjectExportWorker and re-enqueue WaitRelationExportsWorker' do
+ expect { described_class.new.perform(*job_args) }
+ .to change { Projects::ImportExport::ParallelProjectExportWorker.jobs.size }.by(0)
+ .and change { described_class.jobs.size }.by(0)
+ end
+ end
+end
diff --git a/spec/workers/projects/inactive_projects_deletion_cron_worker_spec.rb b/spec/workers/projects/inactive_projects_deletion_cron_worker_spec.rb
index f3c6434dc85..15234827efa 100644
--- a/spec/workers/projects/inactive_projects_deletion_cron_worker_spec.rb
+++ b/spec/workers/projects/inactive_projects_deletion_cron_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::InactiveProjectsDeletionCronWorker do
+RSpec.describe Projects::InactiveProjectsDeletionCronWorker, feature_category: :compliance_management do
include ProjectHelpers
shared_examples 'worker is running for more than 4 minutes' do
diff --git a/spec/workers/projects/inactive_projects_deletion_notification_worker_spec.rb b/spec/workers/projects/inactive_projects_deletion_notification_worker_spec.rb
index 3ddfec0d346..28668188497 100644
--- a/spec/workers/projects/inactive_projects_deletion_notification_worker_spec.rb
+++ b/spec/workers/projects/inactive_projects_deletion_notification_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::InactiveProjectsDeletionNotificationWorker do
+RSpec.describe Projects::InactiveProjectsDeletionNotificationWorker, feature_category: :compliance_management do
describe "#perform" do
subject(:worker) { described_class.new }
diff --git a/spec/workers/projects/post_creation_worker_spec.rb b/spec/workers/projects/post_creation_worker_spec.rb
index b702eed9ea4..2c50a07cf48 100644
--- a/spec/workers/projects/post_creation_worker_spec.rb
+++ b/spec/workers/projects/post_creation_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::PostCreationWorker do
+RSpec.describe Projects::PostCreationWorker, feature_category: :source_code_management do
let_it_be(:user) { create :user }
let(:worker) { described_class.new }
diff --git a/spec/workers/projects/process_sync_events_worker_spec.rb b/spec/workers/projects/process_sync_events_worker_spec.rb
index a10a4797b2c..77ccf14a32b 100644
--- a/spec/workers/projects/process_sync_events_worker_spec.rb
+++ b/spec/workers/projects/process_sync_events_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ProcessSyncEventsWorker do
+RSpec.describe Projects::ProcessSyncEventsWorker, feature_category: :pods do
let!(:group) { create(:group) }
let!(:project) { create(:project) }
diff --git a/spec/workers/projects/record_target_platforms_worker_spec.rb b/spec/workers/projects/record_target_platforms_worker_spec.rb
index 01852f252b7..c1e99d52473 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 do
+RSpec.describe Projects::RecordTargetPlatformsWorker, feature_category: :projects do
include ExclusiveLeaseHelpers
let_it_be(:swift) { create(:programming_language, name: 'Swift') }
diff --git a/spec/workers/projects/refresh_build_artifacts_size_statistics_worker_spec.rb b/spec/workers/projects/refresh_build_artifacts_size_statistics_worker_spec.rb
index 99627ff1ad2..f2b7e75fa10 100644
--- a/spec/workers/projects/refresh_build_artifacts_size_statistics_worker_spec.rb
+++ b/spec/workers/projects/refresh_build_artifacts_size_statistics_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::RefreshBuildArtifactsSizeStatisticsWorker do
+RSpec.describe Projects::RefreshBuildArtifactsSizeStatisticsWorker, feature_category: :build_artifacts do
let(:worker) { described_class.new }
describe '#perform_work' do
diff --git a/spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb b/spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb
index 7eff8e4dcd7..1d328280389 100644
--- a/spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb
+++ b/spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ScheduleBulkRepositoryShardMovesWorker do
+RSpec.describe Projects::ScheduleBulkRepositoryShardMovesWorker, feature_category: :gitaly do
it_behaves_like 'schedules bulk repository shard moves' do
let_it_be_with_reload(:container) { create(:project, :repository) }
diff --git a/spec/workers/projects/schedule_refresh_build_artifacts_size_statistics_worker_spec.rb b/spec/workers/projects/schedule_refresh_build_artifacts_size_statistics_worker_spec.rb
index b5775f37678..b2111b2efb0 100644
--- a/spec/workers/projects/schedule_refresh_build_artifacts_size_statistics_worker_spec.rb
+++ b/spec/workers/projects/schedule_refresh_build_artifacts_size_statistics_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::ScheduleRefreshBuildArtifactsSizeStatisticsWorker do
+RSpec.describe Projects::ScheduleRefreshBuildArtifactsSizeStatisticsWorker, feature_category: :build_artifacts do
subject(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/projects/update_repository_storage_worker_spec.rb b/spec/workers/projects/update_repository_storage_worker_spec.rb
index 7570d706325..91445c2bbf6 100644
--- a/spec/workers/projects/update_repository_storage_worker_spec.rb
+++ b/spec/workers/projects/update_repository_storage_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::UpdateRepositoryStorageWorker do
+RSpec.describe Projects::UpdateRepositoryStorageWorker, feature_category: :source_code_management do
subject { described_class.new }
it_behaves_like 'an update storage move worker' do
diff --git a/spec/workers/propagate_integration_group_worker_spec.rb b/spec/workers/propagate_integration_group_worker_spec.rb
index 60442438a1d..0d797d22137 100644
--- a/spec/workers/propagate_integration_group_worker_spec.rb
+++ b/spec/workers/propagate_integration_group_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PropagateIntegrationGroupWorker do
+RSpec.describe PropagateIntegrationGroupWorker, feature_category: :integrations do
describe '#perform' do
let_it_be(:group) { create(:group) }
let_it_be(:another_group) { create(:group) }
diff --git a/spec/workers/propagate_integration_inherit_descendant_worker_spec.rb b/spec/workers/propagate_integration_inherit_descendant_worker_spec.rb
index c9a7bfaa8b6..d69dd45a209 100644
--- a/spec/workers/propagate_integration_inherit_descendant_worker_spec.rb
+++ b/spec/workers/propagate_integration_inherit_descendant_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PropagateIntegrationInheritDescendantWorker do
+RSpec.describe PropagateIntegrationInheritDescendantWorker, feature_category: :integrations do
let_it_be(:group) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: group) }
let_it_be(:group_integration) { create(:redmine_integration, :group, group: group) }
diff --git a/spec/workers/propagate_integration_inherit_worker_spec.rb b/spec/workers/propagate_integration_inherit_worker_spec.rb
index dd5d246d7f9..f5535696fd1 100644
--- a/spec/workers/propagate_integration_inherit_worker_spec.rb
+++ b/spec/workers/propagate_integration_inherit_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PropagateIntegrationInheritWorker do
+RSpec.describe PropagateIntegrationInheritWorker, feature_category: :integrations do
describe '#perform' do
let_it_be(:integration) { create(:redmine_integration, :instance) }
let_it_be(:integration1) { create(:redmine_integration, inherit_from_id: integration.id) }
diff --git a/spec/workers/propagate_integration_worker_spec.rb b/spec/workers/propagate_integration_worker_spec.rb
index 030caefb833..90134b5cd64 100644
--- a/spec/workers/propagate_integration_worker_spec.rb
+++ b/spec/workers/propagate_integration_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PropagateIntegrationWorker do
+RSpec.describe PropagateIntegrationWorker, feature_category: :integrations do
describe '#perform' do
let(:project) { create(:project) }
let(:integration) do
diff --git a/spec/workers/prune_old_events_worker_spec.rb b/spec/workers/prune_old_events_worker_spec.rb
index c1ba9128475..8046fff2cf3 100644
--- a/spec/workers/prune_old_events_worker_spec.rb
+++ b/spec/workers/prune_old_events_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PruneOldEventsWorker do
+RSpec.describe PruneOldEventsWorker, feature_category: :user_profile do
describe '#perform' do
let(:user) { create(:user) }
@@ -30,5 +30,17 @@ RSpec.describe PruneOldEventsWorker do
subject.perform
expect(not_expired_3_years_event).to be_present
end
+
+ context 'with ops_prune_old_events FF disabled' do
+ before do
+ stub_feature_flags(ops_prune_old_events: false)
+ end
+
+ it 'does not delete' do
+ subject.perform
+
+ expect(Event.find_by(id: expired_event.id)).to be_present
+ end
+ end
end
end
diff --git a/spec/workers/purge_dependency_proxy_cache_worker_spec.rb b/spec/workers/purge_dependency_proxy_cache_worker_spec.rb
index 84315fd6ee9..49ef73bad53 100644
--- a/spec/workers/purge_dependency_proxy_cache_worker_spec.rb
+++ b/spec/workers/purge_dependency_proxy_cache_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PurgeDependencyProxyCacheWorker do
+RSpec.describe PurgeDependencyProxyCacheWorker, feature_category: :dependency_proxy do
let_it_be(:user) { create(:admin) }
let_it_be_with_refind(:blob) { create(:dependency_proxy_blob ) }
let_it_be_with_reload(:group) { blob.group }
diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb
index 63b26817a7a..4e9d638c1e1 100644
--- a/spec/workers/reactive_caching_worker_spec.rb
+++ b/spec/workers/reactive_caching_worker_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe ReactiveCachingWorker do
+RSpec.describe ReactiveCachingWorker, feature_category: :shared do
it_behaves_like 'reactive cacheable worker'
end
diff --git a/spec/workers/rebase_worker_spec.rb b/spec/workers/rebase_worker_spec.rb
index 4bdfd7219f2..eec221094e6 100644
--- a/spec/workers/rebase_worker_spec.rb
+++ b/spec/workers/rebase_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RebaseWorker, '#perform' do
+RSpec.describe RebaseWorker, '#perform', feature_category: :source_code_management do
include ProjectForksHelper
context 'when rebasing an MR from a fork where upstream has protected branches' do
diff --git a/spec/workers/releases/create_evidence_worker_spec.rb b/spec/workers/releases/create_evidence_worker_spec.rb
index 7e3edcfe44a..8631b154920 100644
--- a/spec/workers/releases/create_evidence_worker_spec.rb
+++ b/spec/workers/releases/create_evidence_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Releases::CreateEvidenceWorker do
+RSpec.describe Releases::CreateEvidenceWorker, feature_category: :release_evidence do
let(:project) { create(:project, :repository) }
let(:release) { create(:release, project: project) }
let(:pipeline) { create(:ci_empty_pipeline, sha: release.sha, project: project) }
diff --git a/spec/workers/releases/manage_evidence_worker_spec.rb b/spec/workers/releases/manage_evidence_worker_spec.rb
index 0004a4f4bfb..ca33e28b760 100644
--- a/spec/workers/releases/manage_evidence_worker_spec.rb
+++ b/spec/workers/releases/manage_evidence_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Releases::ManageEvidenceWorker do
+RSpec.describe Releases::ManageEvidenceWorker, feature_category: :release_evidence do
let(:project) { create(:project, :repository) }
shared_examples_for 'does not create a new Evidence record' do
diff --git a/spec/workers/remote_mirror_notification_worker_spec.rb b/spec/workers/remote_mirror_notification_worker_spec.rb
index e415e72645c..46f44d0047b 100644
--- a/spec/workers/remote_mirror_notification_worker_spec.rb
+++ b/spec/workers/remote_mirror_notification_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RemoteMirrorNotificationWorker, :mailer do
+RSpec.describe RemoteMirrorNotificationWorker, :mailer, feature_category: :source_code_management do
let_it_be(:project) { create(:project, :repository, :remote_mirror) }
let_it_be(:mirror) { project.remote_mirrors.first }
diff --git a/spec/workers/remove_expired_group_links_worker_spec.rb b/spec/workers/remove_expired_group_links_worker_spec.rb
index 7bdf6fc0d59..e08cc3fb5c5 100644
--- a/spec/workers/remove_expired_group_links_worker_spec.rb
+++ b/spec/workers/remove_expired_group_links_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RemoveExpiredGroupLinksWorker do
+RSpec.describe RemoveExpiredGroupLinksWorker, feature_category: :system_access do
describe '#perform' do
context 'ProjectGroupLinks' do
let!(:expired_project_group_link) { create(:project_group_link, expires_at: 1.hour.ago) }
diff --git a/spec/workers/remove_expired_members_worker_spec.rb b/spec/workers/remove_expired_members_worker_spec.rb
index 062a9bcfa83..354ce3fc9b4 100644
--- a/spec/workers/remove_expired_members_worker_spec.rb
+++ b/spec/workers/remove_expired_members_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RemoveExpiredMembersWorker do
+RSpec.describe RemoveExpiredMembersWorker, feature_category: :system_access do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/remove_unaccepted_member_invites_worker_spec.rb b/spec/workers/remove_unaccepted_member_invites_worker_spec.rb
index 96d7cf535ed..97ddf9223b3 100644
--- a/spec/workers/remove_unaccepted_member_invites_worker_spec.rb
+++ b/spec/workers/remove_unaccepted_member_invites_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RemoveUnacceptedMemberInvitesWorker do
+RSpec.describe RemoveUnacceptedMemberInvitesWorker, feature_category: :system_access do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb b/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
index 2562a7bc6fe..56dc3511cfc 100644
--- a/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
+++ b/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RemoveUnreferencedLfsObjectsWorker do
+RSpec.describe RemoveUnreferencedLfsObjectsWorker, feature_category: :source_code_management do
let(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/repository_check/batch_worker_spec.rb b/spec/workers/repository_check/batch_worker_spec.rb
index 643b55af573..bb4a4844b9b 100644
--- a/spec/workers/repository_check/batch_worker_spec.rb
+++ b/spec/workers/repository_check/batch_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RepositoryCheck::BatchWorker do
+RSpec.describe RepositoryCheck::BatchWorker, feature_category: :source_code_management do
let(:shard_name) { 'default' }
subject { described_class.new }
diff --git a/spec/workers/repository_check/clear_worker_spec.rb b/spec/workers/repository_check/clear_worker_spec.rb
index b5f09e8a05f..dd11a2705ac 100644
--- a/spec/workers/repository_check/clear_worker_spec.rb
+++ b/spec/workers/repository_check/clear_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RepositoryCheck::ClearWorker do
+RSpec.describe RepositoryCheck::ClearWorker, feature_category: :source_code_management do
it 'clears repository check columns' do
project = create(:project)
project.update_columns(
diff --git a/spec/workers/repository_check/dispatch_worker_spec.rb b/spec/workers/repository_check/dispatch_worker_spec.rb
index 829abc7d895..34ecc645675 100644
--- a/spec/workers/repository_check/dispatch_worker_spec.rb
+++ b/spec/workers/repository_check/dispatch_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RepositoryCheck::DispatchWorker do
+RSpec.describe RepositoryCheck::DispatchWorker, feature_category: :source_code_management do
subject { described_class.new }
it 'does nothing when repository checks are disabled' do
diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb
index 0a37a296e7a..3e52ce781ee 100644
--- a/spec/workers/repository_check/single_repository_worker_spec.rb
+++ b/spec/workers/repository_check/single_repository_worker_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'fileutils'
-RSpec.describe RepositoryCheck::SingleRepositoryWorker do
+RSpec.describe RepositoryCheck::SingleRepositoryWorker, feature_category: :source_code_management do
subject(:worker) { described_class.new }
before do
diff --git a/spec/workers/repository_cleanup_worker_spec.rb b/spec/workers/repository_cleanup_worker_spec.rb
index 2b700b944d2..1e80a48451b 100644
--- a/spec/workers/repository_cleanup_worker_spec.rb
+++ b/spec/workers/repository_cleanup_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RepositoryCleanupWorker do
+RSpec.describe RepositoryCleanupWorker, feature_category: :source_code_management do
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index 85dee935001..3a5528b6a04 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RepositoryForkWorker do
+RSpec.describe RepositoryForkWorker, feature_category: :source_code_management do
include ProjectForksHelper
describe 'modules' do
diff --git a/spec/workers/repository_update_remote_mirror_worker_spec.rb b/spec/workers/repository_update_remote_mirror_worker_spec.rb
index ef6a8d76d2c..c1987658b0d 100644
--- a/spec/workers/repository_update_remote_mirror_worker_spec.rb
+++ b/spec/workers/repository_update_remote_mirror_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RepositoryUpdateRemoteMirrorWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe RepositoryUpdateRemoteMirrorWorker, :clean_gitlab_redis_shared_state, feature_category: :source_code_management do
let_it_be(:remote_mirror) { create(:remote_mirror) }
let(:scheduled_time) { Time.current - 5.minutes }
diff --git a/spec/workers/schedule_merge_request_cleanup_refs_worker_spec.rb b/spec/workers/schedule_merge_request_cleanup_refs_worker_spec.rb
index 49730d9ab8c..b93202fe9b3 100644
--- a/spec/workers/schedule_merge_request_cleanup_refs_worker_spec.rb
+++ b/spec/workers/schedule_merge_request_cleanup_refs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ScheduleMergeRequestCleanupRefsWorker do
+RSpec.describe ScheduleMergeRequestCleanupRefsWorker, feature_category: :code_review_workflow do
subject(:worker) { described_class.new }
describe '#perform' do
diff --git a/spec/workers/schedule_migrate_external_diffs_worker_spec.rb b/spec/workers/schedule_migrate_external_diffs_worker_spec.rb
index 09a0124f6e0..061467a28e0 100644
--- a/spec/workers/schedule_migrate_external_diffs_worker_spec.rb
+++ b/spec/workers/schedule_migrate_external_diffs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ScheduleMigrateExternalDiffsWorker do
+RSpec.describe ScheduleMigrateExternalDiffsWorker, feature_category: :code_review_workflow do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new }
diff --git a/spec/workers/self_monitoring_project_create_worker_spec.rb b/spec/workers/self_monitoring_project_create_worker_spec.rb
index b618b8ede99..cc31804acc1 100644
--- a/spec/workers/self_monitoring_project_create_worker_spec.rb
+++ b/spec/workers/self_monitoring_project_create_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SelfMonitoringProjectCreateWorker do
+RSpec.describe SelfMonitoringProjectCreateWorker, feature_category: :projects do
describe '#perform' do
let(:service_class) { Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService }
let(:service) { instance_double(service_class) }
diff --git a/spec/workers/self_monitoring_project_delete_worker_spec.rb b/spec/workers/self_monitoring_project_delete_worker_spec.rb
index 9a53fe59a40..808f65a25bd 100644
--- a/spec/workers/self_monitoring_project_delete_worker_spec.rb
+++ b/spec/workers/self_monitoring_project_delete_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SelfMonitoringProjectDeleteWorker do
+RSpec.describe SelfMonitoringProjectDeleteWorker, feature_category: :projects do
let_it_be(:jid) { 'b5b28910d97563e58c2fe55f' }
let_it_be(:data_key) { "self_monitoring_delete_result:#{jid}" }
diff --git a/spec/workers/service_desk_email_receiver_worker_spec.rb b/spec/workers/service_desk_email_receiver_worker_spec.rb
index 60fc951f627..bed66875f34 100644
--- a/spec/workers/service_desk_email_receiver_worker_spec.rb
+++ b/spec/workers/service_desk_email_receiver_worker_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe ServiceDeskEmailReceiverWorker, :mailer do
+RSpec.describe ServiceDeskEmailReceiverWorker, :mailer, feature_category: :service_desk do
describe '#perform' do
let(:worker) { described_class.new }
let(:email) { fixture_file('emails/service_desk_custom_address.eml') }
diff --git a/spec/workers/snippets/schedule_bulk_repository_shard_moves_worker_spec.rb b/spec/workers/snippets/schedule_bulk_repository_shard_moves_worker_spec.rb
index be7d8ebe2d3..d31600d9cba 100644
--- a/spec/workers/snippets/schedule_bulk_repository_shard_moves_worker_spec.rb
+++ b/spec/workers/snippets/schedule_bulk_repository_shard_moves_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::ScheduleBulkRepositoryShardMovesWorker do
+RSpec.describe Snippets::ScheduleBulkRepositoryShardMovesWorker, feature_category: :gitaly do
it_behaves_like 'schedules bulk repository shard moves' do
let_it_be_with_reload(:container) { create(:snippet, :repository).tap { |snippet| snippet.create_repository } }
diff --git a/spec/workers/snippets/update_repository_storage_worker_spec.rb b/spec/workers/snippets/update_repository_storage_worker_spec.rb
index 38e9012e9c5..b26384fc75c 100644
--- a/spec/workers/snippets/update_repository_storage_worker_spec.rb
+++ b/spec/workers/snippets/update_repository_storage_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Snippets::UpdateRepositoryStorageWorker do
+RSpec.describe Snippets::UpdateRepositoryStorageWorker, feature_category: :source_code_management do
subject { described_class.new }
it_behaves_like 'an update storage move worker' do
diff --git a/spec/workers/ssh_keys/expired_notification_worker_spec.rb b/spec/workers/ssh_keys/expired_notification_worker_spec.rb
index 26d9460d73e..f3ba586c21e 100644
--- a/spec/workers/ssh_keys/expired_notification_worker_spec.rb
+++ b/spec/workers/ssh_keys/expired_notification_worker_spec.rb
@@ -2,12 +2,11 @@
require 'spec_helper'
-RSpec.describe SshKeys::ExpiredNotificationWorker, type: :worker do
+RSpec.describe SshKeys::ExpiredNotificationWorker, type: :worker, feature_category: :compliance_management do
subject(:worker) { described_class.new }
it 'uses a cronjob queue' do
expect(worker.sidekiq_options_hash).to include(
- 'queue' => 'cronjob:ssh_keys_expired_notification',
'queue_namespace' => :cronjob
)
end
diff --git a/spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb b/spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb
index e907d035020..f6eaf76b54d 100644
--- a/spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb
+++ b/spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb
@@ -2,12 +2,11 @@
require 'spec_helper'
-RSpec.describe SshKeys::ExpiringSoonNotificationWorker, type: :worker do
+RSpec.describe SshKeys::ExpiringSoonNotificationWorker, type: :worker, feature_category: :compliance_management do
subject(:worker) { described_class.new }
it 'uses a cronjob queue' do
expect(worker.sidekiq_options_hash).to include(
- 'queue' => 'cronjob:ssh_keys_expiring_soon_notification',
'queue_namespace' => :cronjob
)
end
diff --git a/spec/workers/stage_update_worker_spec.rb b/spec/workers/stage_update_worker_spec.rb
index e50c7183153..bb2f63d3b50 100644
--- a/spec/workers/stage_update_worker_spec.rb
+++ b/spec/workers/stage_update_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe StageUpdateWorker do
+RSpec.describe StageUpdateWorker, feature_category: :continuous_integration do
describe '#perform' do
context 'when stage exists' do
let(:stage) { create(:ci_stage) }
diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb
index 19ff8ec55c2..1c5f54dc55f 100644
--- a/spec/workers/stuck_ci_jobs_worker_spec.rb
+++ b/spec/workers/stuck_ci_jobs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe StuckCiJobsWorker do
+RSpec.describe StuckCiJobsWorker, feature_category: :continuous_integration do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new }
diff --git a/spec/workers/stuck_export_jobs_worker_spec.rb b/spec/workers/stuck_export_jobs_worker_spec.rb
index cbc7adc8e3f..0e300b0077b 100644
--- a/spec/workers/stuck_export_jobs_worker_spec.rb
+++ b/spec/workers/stuck_export_jobs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe StuckExportJobsWorker do
+RSpec.describe StuckExportJobsWorker, feature_category: :importers do
let(:worker) { described_class.new }
shared_examples 'project export job detection' do
diff --git a/spec/workers/stuck_merge_jobs_worker_spec.rb b/spec/workers/stuck_merge_jobs_worker_spec.rb
index bade2e1ca1b..44dc6550cdb 100644
--- a/spec/workers/stuck_merge_jobs_worker_spec.rb
+++ b/spec/workers/stuck_merge_jobs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe StuckMergeJobsWorker do
+RSpec.describe StuckMergeJobsWorker, feature_category: :code_review_workflow do
describe 'perform' do
let(:worker) { described_class.new }
diff --git a/spec/workers/system_hook_push_worker_spec.rb b/spec/workers/system_hook_push_worker_spec.rb
index 43a3f8e3e19..35e44e635cc 100644
--- a/spec/workers/system_hook_push_worker_spec.rb
+++ b/spec/workers/system_hook_push_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SystemHookPushWorker do
+RSpec.describe SystemHookPushWorker, feature_category: :source_code_management do
include RepoHelpers
subject { described_class.new }
diff --git a/spec/workers/tasks_to_be_done/create_worker_spec.rb b/spec/workers/tasks_to_be_done/create_worker_spec.rb
index c3c3612f9a7..643424ae068 100644
--- a/spec/workers/tasks_to_be_done/create_worker_spec.rb
+++ b/spec/workers/tasks_to_be_done/create_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TasksToBeDone::CreateWorker do
+RSpec.describe TasksToBeDone::CreateWorker, feature_category: :onboarding do
let_it_be(:member_task) { create(:member_task, tasks: MemberTask::TASKS.values) }
let_it_be(:current_user) { create(:user) }
diff --git a/spec/workers/terraform/states/destroy_worker_spec.rb b/spec/workers/terraform/states/destroy_worker_spec.rb
index 02e79373279..7cc20e0ad5d 100644
--- a/spec/workers/terraform/states/destroy_worker_spec.rb
+++ b/spec/workers/terraform/states/destroy_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Terraform::States::DestroyWorker do
+RSpec.describe Terraform::States::DestroyWorker, feature_category: :infrastructure_as_code do
let(:state) { create(:terraform_state) }
describe '#perform' do
diff --git a/spec/workers/todos_destroyer/confidential_issue_worker_spec.rb b/spec/workers/todos_destroyer/confidential_issue_worker_spec.rb
index 86202fac1ed..54e2061217f 100644
--- a/spec/workers/todos_destroyer/confidential_issue_worker_spec.rb
+++ b/spec/workers/todos_destroyer/confidential_issue_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TodosDestroyer::ConfidentialIssueWorker do
+RSpec.describe TodosDestroyer::ConfidentialIssueWorker, feature_category: :team_planning do
let(:service) { double }
it "calls the Todos::Destroy::ConfidentialIssueService with issue_id parameter" do
diff --git a/spec/workers/todos_destroyer/destroyed_designs_worker_spec.rb b/spec/workers/todos_destroyer/destroyed_designs_worker_spec.rb
index 113faeb0d2f..b85ea1a5847 100644
--- a/spec/workers/todos_destroyer/destroyed_designs_worker_spec.rb
+++ b/spec/workers/todos_destroyer/destroyed_designs_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TodosDestroyer::DestroyedDesignsWorker do
+RSpec.describe TodosDestroyer::DestroyedDesignsWorker, feature_category: :team_planning do
let(:service) { double }
it 'calls the Todos::Destroy::DesignService with design_ids parameter' do
diff --git a/spec/workers/todos_destroyer/destroyed_issuable_worker_spec.rb b/spec/workers/todos_destroyer/destroyed_issuable_worker_spec.rb
index 6ccad25ad76..72adc7ba0c7 100644
--- a/spec/workers/todos_destroyer/destroyed_issuable_worker_spec.rb
+++ b/spec/workers/todos_destroyer/destroyed_issuable_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TodosDestroyer::DestroyedIssuableWorker do
+RSpec.describe TodosDestroyer::DestroyedIssuableWorker, feature_category: :team_planning do
let(:job_args) { [1, 'MergeRequest'] }
it 'calls the Todos::Destroy::DestroyedIssuableService' do
diff --git a/spec/workers/todos_destroyer/entity_leave_worker_spec.rb b/spec/workers/todos_destroyer/entity_leave_worker_spec.rb
index db3b0252056..d7682ad0e5e 100644
--- a/spec/workers/todos_destroyer/entity_leave_worker_spec.rb
+++ b/spec/workers/todos_destroyer/entity_leave_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TodosDestroyer::EntityLeaveWorker do
+RSpec.describe TodosDestroyer::EntityLeaveWorker, feature_category: :team_planning do
it "calls the Todos::Destroy::EntityLeaveService with the params it was given" do
service = double
diff --git a/spec/workers/todos_destroyer/group_private_worker_spec.rb b/spec/workers/todos_destroyer/group_private_worker_spec.rb
index 4903edd4bbe..4d49a852a3e 100644
--- a/spec/workers/todos_destroyer/group_private_worker_spec.rb
+++ b/spec/workers/todos_destroyer/group_private_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TodosDestroyer::GroupPrivateWorker do
+RSpec.describe TodosDestroyer::GroupPrivateWorker, feature_category: :team_planning do
it "calls the Todos::Destroy::GroupPrivateService with the params it was given" do
service = double
diff --git a/spec/workers/todos_destroyer/private_features_worker_spec.rb b/spec/workers/todos_destroyer/private_features_worker_spec.rb
index 88d9be051d0..834e0fb2201 100644
--- a/spec/workers/todos_destroyer/private_features_worker_spec.rb
+++ b/spec/workers/todos_destroyer/private_features_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TodosDestroyer::PrivateFeaturesWorker do
+RSpec.describe TodosDestroyer::PrivateFeaturesWorker, feature_category: :team_planning do
it "calls the Todos::Destroy::PrivateFeaturesService with the params it was given" do
service = double
diff --git a/spec/workers/todos_destroyer/project_private_worker_spec.rb b/spec/workers/todos_destroyer/project_private_worker_spec.rb
index 4e54fbdb275..2435fcade22 100644
--- a/spec/workers/todos_destroyer/project_private_worker_spec.rb
+++ b/spec/workers/todos_destroyer/project_private_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TodosDestroyer::ProjectPrivateWorker do
+RSpec.describe TodosDestroyer::ProjectPrivateWorker, feature_category: :team_planning do
it "calls the Todos::Destroy::ProjectPrivateService with the params it was given" do
service = double
diff --git a/spec/workers/trending_projects_worker_spec.rb b/spec/workers/trending_projects_worker_spec.rb
index 1f1e312e457..b6acd01f7c4 100644
--- a/spec/workers/trending_projects_worker_spec.rb
+++ b/spec/workers/trending_projects_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe TrendingProjectsWorker do
+RSpec.describe TrendingProjectsWorker, feature_category: :source_code_management do
describe '#perform' do
it 'refreshes the trending projects' do
expect(TrendingProject).to receive(:refresh!)
diff --git a/spec/workers/update_container_registry_info_worker_spec.rb b/spec/workers/update_container_registry_info_worker_spec.rb
index ace9e55cbce..a8c501efd51 100644
--- a/spec/workers/update_container_registry_info_worker_spec.rb
+++ b/spec/workers/update_container_registry_info_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UpdateContainerRegistryInfoWorker do
+RSpec.describe UpdateContainerRegistryInfoWorker, feature_category: :container_registry do
describe '#perform' do
it 'calls UpdateContainerRegistryInfoService' do
expect_next_instance_of(UpdateContainerRegistryInfoService) do |service|
diff --git a/spec/workers/update_external_pull_requests_worker_spec.rb b/spec/workers/update_external_pull_requests_worker_spec.rb
index cb6a4e2ebf8..254a4b69f3b 100644
--- a/spec/workers/update_external_pull_requests_worker_spec.rb
+++ b/spec/workers/update_external_pull_requests_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UpdateExternalPullRequestsWorker do
+RSpec.describe UpdateExternalPullRequestsWorker, feature_category: :continuous_integration do
describe '#perform' do
let_it_be(:project) { create(:project, import_source: 'tanuki/repository') }
let_it_be(:user) { create(:user) }
diff --git a/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb b/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
index 5ed600e308b..5eae275be36 100644
--- a/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
+++ b/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UpdateHeadPipelineForMergeRequestWorker do
+RSpec.describe UpdateHeadPipelineForMergeRequestWorker, feature_category: :continuous_integration do
describe '#perform' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/workers/update_highest_role_worker_spec.rb b/spec/workers/update_highest_role_worker_spec.rb
index cd127f26e95..94811260f0e 100644
--- a/spec/workers/update_highest_role_worker_spec.rb
+++ b/spec/workers/update_highest_role_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UpdateHighestRoleWorker, :clean_gitlab_redis_shared_state do
+RSpec.describe UpdateHighestRoleWorker, :clean_gitlab_redis_shared_state, feature_category: :subscription_cost_management do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new }
diff --git a/spec/workers/update_merge_requests_worker_spec.rb b/spec/workers/update_merge_requests_worker_spec.rb
index 64fcc2bd388..de164fe352a 100644
--- a/spec/workers/update_merge_requests_worker_spec.rb
+++ b/spec/workers/update_merge_requests_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UpdateMergeRequestsWorker do
+RSpec.describe UpdateMergeRequestsWorker, feature_category: :code_review_workflow do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let_it_be(:oldrev) { "123456" }
diff --git a/spec/workers/update_project_statistics_worker_spec.rb b/spec/workers/update_project_statistics_worker_spec.rb
index 2f356376d7c..c5e6f45a201 100644
--- a/spec/workers/update_project_statistics_worker_spec.rb
+++ b/spec/workers/update_project_statistics_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UpdateProjectStatisticsWorker do
+RSpec.describe UpdateProjectStatisticsWorker, feature_category: :source_code_management do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new }
diff --git a/spec/workers/upload_checksum_worker_spec.rb b/spec/workers/upload_checksum_worker_spec.rb
index 75d7509b6e6..6c47a8e198c 100644
--- a/spec/workers/upload_checksum_worker_spec.rb
+++ b/spec/workers/upload_checksum_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UploadChecksumWorker do
+RSpec.describe UploadChecksumWorker, feature_category: :geo_replication do
describe '#perform' do
subject { described_class.new }
diff --git a/spec/workers/user_status_cleanup/batch_worker_spec.rb b/spec/workers/user_status_cleanup/batch_worker_spec.rb
index 2fd84d0e085..e2ad12672de 100644
--- a/spec/workers/user_status_cleanup/batch_worker_spec.rb
+++ b/spec/workers/user_status_cleanup/batch_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe UserStatusCleanup::BatchWorker do
+RSpec.describe UserStatusCleanup::BatchWorker, feature_category: :user_profile do
include_examples 'an idempotent worker' do
subject do
perform_multiple([], worker: described_class.new)
diff --git a/spec/workers/users/create_statistics_worker_spec.rb b/spec/workers/users/create_statistics_worker_spec.rb
index 2118cc42f3a..2c1c7738533 100644
--- a/spec/workers/users/create_statistics_worker_spec.rb
+++ b/spec/workers/users/create_statistics_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::CreateStatisticsWorker do
+RSpec.describe Users::CreateStatisticsWorker, feature_category: :user_profile do
describe '#perform' do
subject { described_class.new.perform }
diff --git a/spec/workers/users/deactivate_dormant_users_worker_spec.rb b/spec/workers/users/deactivate_dormant_users_worker_spec.rb
index a8318de669b..1fb936b1fc2 100644
--- a/spec/workers/users/deactivate_dormant_users_worker_spec.rb
+++ b/spec/workers/users/deactivate_dormant_users_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::DeactivateDormantUsersWorker do
+RSpec.describe Users::DeactivateDormantUsersWorker, feature_category: :subscription_cost_management do
using RSpec::Parameterized::TableSyntax
describe '#perform' do
@@ -12,8 +12,7 @@ RSpec.describe Users::DeactivateDormantUsersWorker do
subject(:worker) { described_class.new }
- it 'does not run for GitLab.com' do
- expect(Gitlab).to receive(:com?).and_return(true)
+ it 'does not run for SaaS', :saas do
# Now makes a call to current settings to determine period of dormancy
worker.perform
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 7c585542e30..73faffb5387 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
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::MigrateRecordsToGhostUserInBatchesWorker do
+RSpec.describe Users::MigrateRecordsToGhostUserInBatchesWorker, feature_category: :subscription_cost_management do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new }
diff --git a/spec/workers/web_hook_worker_spec.rb b/spec/workers/web_hook_worker_spec.rb
index e2ff36975c4..e39017c4ccf 100644
--- a/spec/workers/web_hook_worker_spec.rb
+++ b/spec/workers/web_hook_worker_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe WebHookWorker do
+RSpec.describe WebHookWorker, feature_category: :integrations do
include AfterNextHelpers
let_it_be(:project_hook) { create(:project_hook) }
diff --git a/spec/workers/web_hooks/log_destroy_worker_spec.rb b/spec/workers/web_hooks/log_destroy_worker_spec.rb
index 0c107c05360..8c7d29d559d 100644
--- a/spec/workers/web_hooks/log_destroy_worker_spec.rb
+++ b/spec/workers/web_hooks/log_destroy_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe WebHooks::LogDestroyWorker do
+RSpec.describe WebHooks::LogDestroyWorker, feature_category: :integrations do
include AfterNextHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/workers/x509_certificate_revoke_worker_spec.rb b/spec/workers/x509_certificate_revoke_worker_spec.rb
index 392cb52d084..badeff25b34 100644
--- a/spec/workers/x509_certificate_revoke_worker_spec.rb
+++ b/spec/workers/x509_certificate_revoke_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe X509CertificateRevokeWorker do
+RSpec.describe X509CertificateRevokeWorker, feature_category: :source_code_management do
describe '#perform' do
context 'with a revoked certificate' do
subject { described_class.new }
diff --git a/spec/workers/x509_issuer_crl_check_worker_spec.rb b/spec/workers/x509_issuer_crl_check_worker_spec.rb
index 5564147d274..55e2e8d335d 100644
--- a/spec/workers/x509_issuer_crl_check_worker_spec.rb
+++ b/spec/workers/x509_issuer_crl_check_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe X509IssuerCrlCheckWorker do
+RSpec.describe X509IssuerCrlCheckWorker, feature_category: :source_code_management do
subject(:worker) { described_class.new }
let(:project) { create(:project, :public, :repository) }
diff --git a/tooling/danger/sidekiq_args.rb b/tooling/danger/sidekiq_args.rb
new file mode 100644
index 00000000000..d06bb92ca6d
--- /dev/null
+++ b/tooling/danger/sidekiq_args.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+module Tooling
+ module Danger
+ module SidekiqArgs
+ include ::Danger::Helpers
+
+ WORKER_FILES_REGEX = 'app/workers'
+ EE_PREFIX = 'ee/'
+ DEF_PERFORM = "def perform"
+ DEF_PERFORM_REGEX = /[\s+-]*def perform\((.*)\)/
+ BEFORE_DEF_PERFORM_REGEX = /^[\s-]*def perform\b/
+ AFTER_DEF_PERFORM_REGEX = /^[\s+]*def perform\b/
+
+ SUGGEST_MR_COMMENT = <<~SUGGEST_COMMENT
+ Please follow the [sidekiq development guidelines](https://docs.gitlab.com/ee/development/sidekiq/compatibility_across_updates.html#changing-the-arguments-for-a-worker) when changing sidekiq worker arguments.
+ SUGGEST_COMMENT
+
+ def changed_worker_files(ee: :include)
+ changed_files = helper.all_changed_files
+ folder_prefix =
+ case ee
+ when :include
+ "(#{EE_PREFIX})?"
+ when :only
+ EE_PREFIX
+ when :exclude
+ nil
+ end
+
+ changed_files.grep(%r{\A#{folder_prefix}#{WORKER_FILES_REGEX}})
+ end
+
+ def args_changed?(diff)
+ # Find the "before" and "after" versions of the perform method definition
+ before_def_perform = diff.find { |line| BEFORE_DEF_PERFORM_REGEX.match?(line) }
+ after_def_perform = diff.find { |line| AFTER_DEF_PERFORM_REGEX.match?(line) }
+
+ # args are not changed if there is no before or after def perform method
+ return false unless before_def_perform && after_def_perform
+
+ # Extract the perform method arguments from the "before" and "after" versions
+ before_args, after_args = diff.flat_map { |line| line.scan(DEF_PERFORM_REGEX) }
+
+ before_args != after_args
+ end
+
+ def add_comment_for_matched_line(filename)
+ diff = helper.changed_lines(filename)
+ return unless args_changed?(diff)
+
+ file_lines = project_helper.file_lines(filename)
+
+ perform_method_line = file_lines.index { |line| line.include?(DEF_PERFORM) }
+ markdown(format(SUGGEST_MR_COMMENT), file: filename, line: perform_method_line.succ)
+ end
+ end
+ end
+end
diff --git a/tooling/danger/sidekiq_queues.rb b/tooling/danger/sidekiq_queues.rb
index ae32b128682..bd6480fcba6 100644
--- a/tooling/danger/sidekiq_queues.rb
+++ b/tooling/danger/sidekiq_queues.rb
@@ -14,7 +14,7 @@ module Tooling
def changed_queue_names
@changed_queue_names ||=
(new_queues.values_at(*old_queues.keys) - old_queues.values)
- .compact.map { |queue| queue[:name] }
+ .compact.map { |queue| queue[:name] } # rubocop:disable Rails/Pluck
end
private
diff --git a/tooling/danger/specs.rb b/tooling/danger/specs.rb
index f95a798d53e..5359e71f8cc 100644
--- a/tooling/danger/specs.rb
+++ b/tooling/danger/specs.rb
@@ -90,15 +90,17 @@ module Tooling
changed_lines.each_with_index do |changed_line, i|
next unless changed_line =~ RSPEC_TOP_LEVEL_DESCRIBE_REGEX
- next_line_in_file = file_lines[file_lines.find_index(changed_line.delete_prefix('+')) + 1]
-
- if changed_line.include?(FEATURE_CATEGORY_KEYWORD) || next_line_in_file.to_s.include?(FEATURE_CATEGORY_KEYWORD)
- next
- end
-
line_number = file_lines.find_index(changed_line.delete_prefix('+'))
next unless line_number
+ # Get the top level RSpec.describe line and the next 5 lines
+ lines_to_check = file_lines[line_number, 5]
+ # Remove all the lines after the first one that ends in `do`
+ last_line_number_of_describe_declaration = lines_to_check.index { |line| line.end_with?(' do') }
+ lines_to_check = lines_to_check[0..last_line_number_of_describe_declaration]
+
+ next if lines_to_check.any? { |line| line.include?(FEATURE_CATEGORY_KEYWORD) }
+
suggested_line = file_lines[line_number]
markdown(comment(FEATURE_CATEGORY_SUGGESTION, suggested_line), file: filename, line: line_number.succ)
diff --git a/tooling/lib/tooling/find_codeowners.rb b/tooling/lib/tooling/find_codeowners.rb
index cc37d4db1ec..e542ab9967c 100644
--- a/tooling/lib/tooling/find_codeowners.rb
+++ b/tooling/lib/tooling/find_codeowners.rb
@@ -48,11 +48,7 @@ module Tooling
def load_config
config_path = "#{__dir__}/../../config/CODEOWNERS.yml"
- if YAML.respond_to?(:safe_load_file) # Ruby 3.0+
- YAML.safe_load_file(config_path, symbolize_names: true)
- else
- YAML.safe_load(File.read(config_path), symbolize_names: true)
- end
+ YAML.safe_load_file(config_path, symbolize_names: true)
end
# Copied and modified from ee/lib/gitlab/code_owners/file.rb
diff --git a/tooling/lib/tooling/kubernetes_client.rb b/tooling/lib/tooling/kubernetes_client.rb
index ab914db5777..27eb4c8151e 100644
--- a/tooling/lib/tooling/kubernetes_client.rb
+++ b/tooling/lib/tooling/kubernetes_client.rb
@@ -35,6 +35,19 @@ module Tooling
delete_namespaces_by_exact_names(resource_names: namespaces, wait: wait)
end
+ def delete_namespaces_by_exact_names(resource_names:, wait:)
+ command = [
+ 'delete',
+ 'namespace',
+ '--now',
+ '--ignore-not-found',
+ %(--wait=#{wait}),
+ resource_names.join(' ')
+ ]
+
+ run_command(command)
+ end
+
private
def delete_by_selector(release_name:, wait:)
@@ -74,19 +87,6 @@ module Tooling
run_command(command)
end
- def delete_namespaces_by_exact_names(resource_names:, wait:)
- command = [
- 'delete',
- 'namespace',
- '--now',
- '--ignore-not-found',
- %(--wait=#{wait}),
- resource_names.join(' ')
- ]
-
- run_command(command)
- end
-
def delete_by_matching_name(release_name:)
resource_names = raw_resource_names
command = [
diff --git a/tooling/lib/tooling/mappings/js_to_system_specs_mappings.rb b/tooling/lib/tooling/mappings/js_to_system_specs_mappings.rb
index 365e466011b..e78ce266a32 100644
--- a/tooling/lib/tooling/mappings/js_to_system_specs_mappings.rb
+++ b/tooling/lib/tooling/mappings/js_to_system_specs_mappings.rb
@@ -18,6 +18,7 @@ module Tooling
@first_js_folder_extract_regexp = %r{
(?:.*/)? # Skips the GitLab edition (e.g. ee/, jh/)
#{@js_base_folder}/ # Most likely app/assets/javascripts/
+ (?:pages/)? # If under a pages folder, we capture the following folder
([\w-]*) # Captures the first folder
}x
end
diff --git a/tooling/lib/tooling/test_map_generator.rb b/tooling/lib/tooling/test_map_generator.rb
index f96f33ff074..88b4353b232 100644
--- a/tooling/lib/tooling/test_map_generator.rb
+++ b/tooling/lib/tooling/test_map_generator.rb
@@ -12,7 +12,9 @@ module Tooling
def parse(yaml_files)
Array(yaml_files).each do |yaml_file|
data = File.read(yaml_file)
- metadata, example_groups = data.split("---\n").reject(&:empty?).map { |yml| YAML.safe_load(yml, [Symbol]) }
+ metadata, example_groups = data.split("---\n").reject(&:empty?).map do |yml|
+ YAML.safe_load(yml, permitted_classes: [Symbol])
+ end
if example_groups.nil?
puts "No examples in #{yaml_file}! Metadata: #{metadata}"
diff --git a/vendor/assets/javascripts/u2f.js b/vendor/assets/javascripts/u2f.js
deleted file mode 100644
index a33e5e0ade9..00000000000
--- a/vendor/assets/javascripts/u2f.js
+++ /dev/null
@@ -1,750 +0,0 @@
-//Copyright 2014-2015 Google Inc. All rights reserved.
-
-//Use of this source code is governed by a BSD-style
-//license that can be found in the LICENSE file or at
-//https://developers.google.com/open-source/licenses/bsd
-
-/**
- * @fileoverview The U2F api.
- */
-'use strict';
-
-
-/**
- * Namespace for the U2F api.
- * @type {Object}
- */
-var u2f = u2f || {};
-
-/**
- * FIDO U2F Javascript API Version
- * @number
- */
-var js_api_version;
-
-/**
- * The U2F extension id
- * @const {string}
- */
-// The Chrome packaged app extension ID.
-// Uncomment this if you want to deploy a server instance that uses
-// the package Chrome app and does not require installing the U2F Chrome extension.
-u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
-// The U2F Chrome extension ID.
-// Uncomment this if you want to deploy a server instance that uses
-// the U2F Chrome extension to authenticate.
-// u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
-
-
-/**
- * Message types for messsages to/from the extension
- * @const
- * @enum {string}
- */
-u2f.MessageTypes = {
- 'U2F_REGISTER_REQUEST': 'u2f_register_request',
- 'U2F_REGISTER_RESPONSE': 'u2f_register_response',
- 'U2F_SIGN_REQUEST': 'u2f_sign_request',
- 'U2F_SIGN_RESPONSE': 'u2f_sign_response',
- 'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
- 'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
-};
-
-
-/**
- * Response status codes
- * @const
- * @enum {number}
- */
-u2f.ErrorCodes = {
- 'OK': 0,
- 'OTHER_ERROR': 1,
- 'BAD_REQUEST': 2,
- 'CONFIGURATION_UNSUPPORTED': 3,
- 'DEVICE_INELIGIBLE': 4,
- 'TIMEOUT': 5
-};
-
-
-/**
- * A message for registration requests
- * @typedef {{
- * type: u2f.MessageTypes,
- * appId: ?string,
- * timeoutSeconds: ?number,
- * requestId: ?number
- * }}
- */
-u2f.U2fRequest;
-
-
-/**
- * A message for registration responses
- * @typedef {{
- * type: u2f.MessageTypes,
- * responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
- * requestId: ?number
- * }}
- */
-u2f.U2fResponse;
-
-
-/**
- * An error object for responses
- * @typedef {{
- * errorCode: u2f.ErrorCodes,
- * errorMessage: ?string
- * }}
- */
-u2f.Error;
-
-/**
- * Data object for a single sign request.
- * @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}}
- */
-u2f.Transport;
-
-
-/**
- * Data object for a single sign request.
- * @typedef {Array<u2f.Transport>}
- */
-u2f.Transports;
-
-/**
- * Data object for a single sign request.
- * @typedef {{
- * version: string,
- * challenge: string,
- * keyHandle: string,
- * appId: string
- * }}
- */
-u2f.SignRequest;
-
-
-/**
- * Data object for a sign response.
- * @typedef {{
- * keyHandle: string,
- * signatureData: string,
- * clientData: string
- * }}
- */
-u2f.SignResponse;
-
-
-/**
- * Data object for a registration request.
- * @typedef {{
- * version: string,
- * challenge: string
- * }}
- */
-u2f.RegisterRequest;
-
-
-/**
- * Data object for a registration response.
- * @typedef {{
- * version: string,
- * keyHandle: string,
- * transports: Transports,
- * appId: string
- * }}
- */
-u2f.RegisterResponse;
-
-
-/**
- * Data object for a registered key.
- * @typedef {{
- * version: string,
- * keyHandle: string,
- * transports: ?Transports,
- * appId: ?string
- * }}
- */
-u2f.RegisteredKey;
-
-
-/**
- * Data object for a get API register response.
- * @typedef {{
- * js_api_version: number
- * }}
- */
-u2f.GetJsApiVersionResponse;
-
-
-//Low level MessagePort API support
-
-/**
- * Sets up a MessagePort to the U2F extension using the
- * available mechanisms.
- * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
- */
-u2f.getMessagePort = function(callback) {
- if (typeof chrome != 'undefined' && chrome.runtime) {
- // The actual message here does not matter, but we need to get a reply
- // for the callback to run. Thus, send an empty signature request
- // in order to get a failure response.
- var msg = {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- signRequests: []
- };
- chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() {
- if (!chrome.runtime.lastError) {
- // We are on a whitelisted origin and can talk directly
- // with the extension.
- u2f.getChromeRuntimePort_(callback);
- } else {
- // chrome.runtime was available, but we couldn't message
- // the extension directly, use iframe
- u2f.getIframePort_(callback);
- }
- });
- } else if (u2f.isAndroidChrome_()) {
- u2f.getAuthenticatorPort_(callback);
- } else if (u2f.isIosChrome_()) {
- u2f.getIosPort_(callback);
- } else {
- // chrome.runtime was not available at all, which is normal
- // when this origin doesn't have access to any extensions.
- u2f.getIframePort_(callback);
- }
-};
-
-/**
- * Detect chrome running on android based on the browser's useragent.
- * @private
- */
-u2f.isAndroidChrome_ = function() {
- var userAgent = navigator.userAgent;
- return userAgent.indexOf('Chrome') != -1 &&
- userAgent.indexOf('Android') != -1;
-};
-
-/**
- * Detect chrome running on iOS based on the browser's platform.
- * @private
- */
-u2f.isIosChrome_ = function() {
- return $.inArray(navigator.platform, ["iPhone", "iPad", "iPod"]) > -1;
-};
-
-/**
- * Connects directly to the extension via chrome.runtime.connect.
- * @param {function(u2f.WrappedChromeRuntimePort_)} callback
- * @private
- */
-u2f.getChromeRuntimePort_ = function(callback) {
- var port = chrome.runtime.connect(u2f.EXTENSION_ID,
- {'includeTlsChannelId': true});
- setTimeout(function() {
- callback(new u2f.WrappedChromeRuntimePort_(port));
- }, 0);
-};
-
-/**
- * Return a 'port' abstraction to the Authenticator app.
- * @param {function(u2f.WrappedAuthenticatorPort_)} callback
- * @private
- */
-u2f.getAuthenticatorPort_ = function(callback) {
- setTimeout(function() {
- callback(new u2f.WrappedAuthenticatorPort_());
- }, 0);
-};
-
-/**
- * Return a 'port' abstraction to the iOS client app.
- * @param {function(u2f.WrappedIosPort_)} callback
- * @private
- */
-u2f.getIosPort_ = function(callback) {
- setTimeout(function() {
- callback(new u2f.WrappedIosPort_());
- }, 0);
-};
-
-/**
- * A wrapper for chrome.runtime.Port that is compatible with MessagePort.
- * @param {Port} port
- * @constructor
- * @private
- */
-u2f.WrappedChromeRuntimePort_ = function(port) {
- this.port_ = port;
-};
-
-/**
- * Format and return a sign request compliant with the JS API version supported by the extension.
- * @param {Array<u2f.SignRequest>} signRequests
- * @param {number} timeoutSeconds
- * @param {number} reqId
- * @return {Object}
- */
-u2f.formatSignRequest_ =
- function(appId, challenge, registeredKeys, timeoutSeconds, reqId) {
- if (js_api_version === undefined || js_api_version < 1.1) {
- // Adapt request to the 1.0 JS API
- var signRequests = [];
- for (var i = 0; i < registeredKeys.length; i++) {
- signRequests[i] = {
- version: registeredKeys[i].version,
- challenge: challenge,
- keyHandle: registeredKeys[i].keyHandle,
- appId: appId
- };
- }
- return {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- signRequests: signRequests,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId
- };
- }
- // JS 1.1 API
- return {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- appId: appId,
- challenge: challenge,
- registeredKeys: registeredKeys,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId
- };
- };
-
-/**
- * Format and return a register request compliant with the JS API version supported by the extension..
- * @param {Array<u2f.SignRequest>} signRequests
- * @param {Array<u2f.RegisterRequest>} signRequests
- * @param {number} timeoutSeconds
- * @param {number} reqId
- * @return {Object}
- */
-u2f.formatRegisterRequest_ =
- function(appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
- if (js_api_version === undefined || js_api_version < 1.1) {
- // Adapt request to the 1.0 JS API
- for (var i = 0; i < registerRequests.length; i++) {
- registerRequests[i].appId = appId;
- }
- var signRequests = [];
- for (var i = 0; i < registeredKeys.length; i++) {
- signRequests[i] = {
- version: registeredKeys[i].version,
- challenge: registerRequests[0],
- keyHandle: registeredKeys[i].keyHandle,
- appId: appId
- };
- }
- return {
- type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
- signRequests: signRequests,
- registerRequests: registerRequests,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId
- };
- }
- // JS 1.1 API
- return {
- type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
- appId: appId,
- registerRequests: registerRequests,
- registeredKeys: registeredKeys,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId
- };
- };
-
-
-/**
- * Posts a message on the underlying channel.
- * @param {Object} message
- */
-u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) {
- this.port_.postMessage(message);
-};
-
-
-/**
- * Emulates the HTML 5 addEventListener interface. Works only for the
- * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
-u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
- function(eventName, handler) {
- var name = eventName.toLowerCase();
- if (name == 'message' || name == 'onmessage') {
- this.port_.onMessage.addListener(function(message) {
- // Emulate a minimal MessageEvent object
- handler({'data': message});
- });
- } else {
- console.error('WrappedChromeRuntimePort only supports onMessage');
- }
- };
-
-/**
- * Wrap the Authenticator app with a MessagePort interface.
- * @constructor
- * @private
- */
-u2f.WrappedAuthenticatorPort_ = function() {
- this.requestId_ = -1;
- this.requestObject_ = null;
-}
-
-/**
- * Launch the Authenticator intent.
- * @param {Object} message
- */
-u2f.WrappedAuthenticatorPort_.prototype.postMessage = function(message) {
- var intentUrl =
- u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
- ';S.request=' + encodeURIComponent(JSON.stringify(message)) +
- ';end';
- document.location = intentUrl;
-};
-
-/**
- * Tells what type of port this is.
- * @return {String} port type
- */
-u2f.WrappedAuthenticatorPort_.prototype.getPortType = function() {
- return "WrappedAuthenticatorPort_";
-};
-
-
-/**
- * Emulates the HTML 5 addEventListener interface.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
-u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function(eventName, handler) {
- var name = eventName.toLowerCase();
- if (name == 'message') {
- var self = this;
- /* Register a callback to that executes when
- * chrome injects the response. */
- window.addEventListener(
- 'message', self.onRequestUpdate_.bind(self, handler), false);
- } else {
- console.error('WrappedAuthenticatorPort only supports message');
- }
-};
-
-/**
- * Callback invoked when a response is received from the Authenticator.
- * @param function({data: Object}) callback
- * @param {Object} message message Object
- */
-u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
- function(callback, message) {
- var messageObject = JSON.parse(message.data);
- var intentUrl = messageObject['intentURL'];
-
- var errorCode = messageObject['errorCode'];
- var responseObject = null;
- if (messageObject.hasOwnProperty('data')) {
- responseObject = /** @type {Object} */ (
- JSON.parse(messageObject['data']));
- }
-
- callback({'data': responseObject});
- };
-
-/**
- * Base URL for intents to Authenticator.
- * @const
- * @private
- */
-u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
- 'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
-
-/**
- * Wrap the iOS client app with a MessagePort interface.
- * @constructor
- * @private
- */
-u2f.WrappedIosPort_ = function() {};
-
-/**
- * Launch the iOS client app request
- * @param {Object} message
- */
-u2f.WrappedIosPort_.prototype.postMessage = function(message) {
- var str = JSON.stringify(message);
- var url = "u2f://auth?" + encodeURI(str);
- location.replace(url);
-};
-
-/**
- * Tells what type of port this is.
- * @return {String} port type
- */
-u2f.WrappedIosPort_.prototype.getPortType = function() {
- return "WrappedIosPort_";
-};
-
-/**
- * Emulates the HTML 5 addEventListener interface.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
-u2f.WrappedIosPort_.prototype.addEventListener = function(eventName, handler) {
- var name = eventName.toLowerCase();
- if (name !== 'message') {
- console.error('WrappedIosPort only supports message');
- }
-};
-
-/**
- * Sets up an embedded trampoline iframe, sourced from the extension.
- * @param {function(MessagePort)} callback
- * @private
- */
-u2f.getIframePort_ = function(callback) {
- // Create the iframe
- var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
- var iframe = document.createElement('iframe');
- iframe.src = iframeOrigin + '/u2f-comms.html';
- iframe.setAttribute('style', 'display:none');
- document.body.appendChild(iframe);
-
- var channel = new MessageChannel();
- var ready = function(message) {
- if (message.data == 'ready') {
- channel.port1.removeEventListener('message', ready);
- callback(channel.port1);
- } else {
- console.error('First event on iframe port was not "ready"');
- }
- };
- channel.port1.addEventListener('message', ready);
- channel.port1.start();
-
- iframe.addEventListener('load', function() {
- // Deliver the port to the iframe and initialize
- iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
- });
-};
-
-
-//High-level JS API
-
-/**
- * Default extension response timeout in seconds.
- * @const
- */
-u2f.EXTENSION_TIMEOUT_SEC = 30;
-
-/**
- * A singleton instance for a MessagePort to the extension.
- * @type {MessagePort|u2f.WrappedChromeRuntimePort_}
- * @private
- */
-u2f.port_ = null;
-
-/**
- * Callbacks waiting for a port
- * @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
- * @private
- */
-u2f.waitingForPort_ = [];
-
-/**
- * A counter for requestIds.
- * @type {number}
- * @private
- */
-u2f.reqCounter_ = 0;
-
-/**
- * A map from requestIds to client callbacks
- * @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
- * |function((u2f.Error|u2f.SignResponse)))>}
- * @private
- */
-u2f.callbackMap_ = {};
-
-/**
- * Creates or retrieves the MessagePort singleton to use.
- * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
- * @private
- */
-u2f.getPortSingleton_ = function(callback) {
- if (u2f.port_) {
- callback(u2f.port_);
- } else {
- if (u2f.waitingForPort_.length == 0) {
- u2f.getMessagePort(function(port) {
- u2f.port_ = port;
- u2f.port_.addEventListener('message',
- /** @type {function(Event)} */ (u2f.responseHandler_));
-
- // Careful, here be async callbacks. Maybe.
- while (u2f.waitingForPort_.length)
- u2f.waitingForPort_.shift()(u2f.port_);
- });
- }
- u2f.waitingForPort_.push(callback);
- }
-};
-
-/**
- * Handles response messages from the extension.
- * @param {MessageEvent.<u2f.Response>} message
- * @private
- */
-u2f.responseHandler_ = function(message) {
- var response = message.data;
- var reqId = response['requestId'];
- if (!reqId || !u2f.callbackMap_[reqId]) {
- console.error('Unknown or missing requestId in response.');
- return;
- }
- var cb = u2f.callbackMap_[reqId];
- delete u2f.callbackMap_[reqId];
- cb(response['responseData']);
-};
-
-/**
- * Dispatches an array of sign requests to available U2F tokens.
- * If the JS API version supported by the extension is unknown, it first sends a
- * message to the extension to find out the supported API version and then it sends
- * the sign request.
- * @param {string=} appId
- * @param {string=} challenge
- * @param {Array<u2f.RegisteredKey>} registeredKeys
- * @param {function((u2f.Error|u2f.SignResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
-u2f.sign = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
- if (js_api_version === undefined) {
- // Send a message to get the extension to JS API version, then send the actual sign request.
- u2f.getApiVersion(
- function (response) {
- js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
- console.log("Extension JS API Version: ", js_api_version);
- u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
- });
- } else {
- // We know the JS API version. Send the actual sign request in the supported API version.
- u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
- }
-};
-
-/**
- * Dispatches an array of sign requests to available U2F tokens.
- * @param {string=} appId
- * @param {string=} challenge
- * @param {Array<u2f.RegisteredKey>} registeredKeys
- * @param {function((u2f.Error|u2f.SignResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
-u2f.sendSignRequest = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
- u2f.getPortSingleton_(function(port) {
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
- opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
- var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
- port.postMessage(req);
- });
-};
-
-/**
- * Dispatches register requests to available U2F tokens. An array of sign
- * requests identifies already registered tokens.
- * If the JS API version supported by the extension is unknown, it first sends a
- * message to the extension to find out the supported API version and then it sends
- * the register request.
- * @param {string=} appId
- * @param {Array<u2f.RegisterRequest>} registerRequests
- * @param {Array<u2f.RegisteredKey>} registeredKeys
- * @param {function((u2f.Error|u2f.RegisterResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
-u2f.register = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
- if (js_api_version === undefined) {
- // Send a message to get the extension to JS API version, then send the actual register request.
- u2f.getApiVersion(
- function (response) {
- js_api_version = response['js_api_version'] === undefined ? 0: response['js_api_version'];
- console.log("Extension JS API Version: ", js_api_version);
- u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
- callback, opt_timeoutSeconds);
- });
- } else {
- // We know the JS API version. Send the actual register request in the supported API version.
- u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
- callback, opt_timeoutSeconds);
- }
-};
-
-/**
- * Dispatches register requests to available U2F tokens. An array of sign
- * requests identifies already registered tokens.
- * @param {string=} appId
- * @param {Array<u2f.RegisterRequest>} registerRequests
- * @param {Array<u2f.RegisteredKey>} registeredKeys
- * @param {function((u2f.Error|u2f.RegisterResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
-u2f.sendRegisterRequest = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
- u2f.getPortSingleton_(function(port) {
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
- opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
- var req = u2f.formatRegisterRequest_(
- appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
- port.postMessage(req);
- });
-};
-
-
-/**
- * Dispatches a message to the extension to find out the supported
- * JS API version.
- * If the user is on a mobile phone and is thus using Google Authenticator instead
- * of the Chrome extension, don't send the request and simply return 0.
- * @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
-u2f.getApiVersion = function(callback, opt_timeoutSeconds) {
- u2f.getPortSingleton_(function(port) {
- // If we are using Android Google Authenticator or iOS client app,
- // do not fire an intent to ask which JS API version to use.
- if (port.getPortType) {
- var apiVersion;
- switch (port.getPortType()) {
- case 'WrappedIosPort_':
- case 'WrappedAuthenticatorPort_':
- apiVersion = 1.1;
- break;
-
- default:
- apiVersion = 0;
- break;
- }
- callback({ 'js_api_version': apiVersion });
- return;
- }
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var req = {
- type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
- timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
- opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
- requestId: reqId
- };
- port.postMessage(req);
- });
-};
-
-window.u2f || (window.u2f = u2f);
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 d18c5f3ee97..f6838ddbb92 100644
--- a/vendor/assets/javascripts/vue-virtual-scroller/src/components/RecycleScroller.vue
+++ b/vendor/assets/javascripts/vue-virtual-scroller/src/components/RecycleScroller.vue
@@ -222,6 +222,10 @@ export default {
position: 0,
}
const nonReactive = {
+ // FIXME: replace with markRaw in Vue3
+ // See https://gitlab.com/gitlab-org/gitlab/-/issues/395772
+ __v_skip: true,
+
id: uid++,
index,
used: true,
diff --git a/vendor/gems/cloud_profiler_agent/.gitlab-ci.yml b/vendor/gems/cloud_profiler_agent/.gitlab-ci.yml
new file mode 100644
index 00000000000..9e508d920e8
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/.gitlab-ci.yml
@@ -0,0 +1,32 @@
+workflow:
+ rules:
+ - if: $CI_MERGE_REQUEST_ID
+
+.rspec:
+ cache:
+ key: cloud_profiler_agent-ruby-${RUBY_VERSION}
+ paths:
+ - vendor/gems/cloud_profiler_agent/vendor/ruby
+ before_script:
+ - cd vendor/gems/cloud_profiler_agent
+ - ruby -v # Print out ruby version for debugging
+ - gem install bundler --no-document # Bundler is not installed with the image
+ - bundle config set --local path 'vendor' # Install dependencies into ./vendor/ruby
+ - bundle config set with 'development'
+ - bundle config set --local frozen 'true' # Disallow Gemfile.lock changes on CI
+ - bundle config # Show bundler configuration
+ - bundle install -j $(nproc)
+ script:
+ - bundle exec rspec
+
+rspec-3.0:
+ image: "ruby:3.0"
+ extends: .rspec
+
+rspec-3.1:
+ image: "ruby:3.1"
+ extends: .rspec
+
+rspec-3.2:
+ image: "ruby:3.2"
+ extends: .rspec
diff --git a/vendor/gems/cloud_profiler_agent/Gemfile b/vendor/gems/cloud_profiler_agent/Gemfile
new file mode 100644
index 00000000000..5f10ba8c95a
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/Gemfile
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+gemspec
diff --git a/vendor/gems/cloud_profiler_agent/Gemfile.lock b/vendor/gems/cloud_profiler_agent/Gemfile.lock
new file mode 100644
index 00000000000..47087362534
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/Gemfile.lock
@@ -0,0 +1,126 @@
+PATH
+ remote: .
+ specs:
+ cloud_profiler_agent (0.0.1.pre)
+ google-cloud-profiler-v2 (~> 0.3)
+ google-protobuf (~> 3.13)
+ googleauth (>= 0.14)
+ stackprof (~> 0.2)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ addressable (2.8.1)
+ public_suffix (>= 2.0.2, < 6.0)
+ ast (2.4.2)
+ diff-lcs (1.5.0)
+ faraday (1.10.2)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0)
+ faraday-multipart (~> 1.0)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.0)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
+ faraday-retry (~> 1.0)
+ ruby2_keywords (>= 0.0.4)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.0)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-multipart (1.0.4)
+ multipart-post (~> 2)
+ faraday-net_http (1.0.1)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ faraday-retry (1.0.3)
+ gapic-common (0.17.1)
+ faraday (>= 1.9, < 3.a)
+ faraday-retry (>= 1.0, < 3.a)
+ google-protobuf (~> 3.14)
+ googleapis-common-protos (>= 1.3.12, < 2.a)
+ googleapis-common-protos-types (>= 1.3.1, < 2.a)
+ googleauth (~> 1.0)
+ grpc (~> 1.36)
+ google-cloud-errors (1.3.0)
+ google-cloud-profiler-v2 (0.3.0)
+ gapic-common (>= 0.10, < 2.a)
+ google-cloud-errors (~> 1.0)
+ google-protobuf (3.22.0)
+ googleapis-common-protos (1.4.0)
+ google-protobuf (~> 3.14)
+ googleapis-common-protos-types (~> 1.2)
+ grpc (~> 1.27)
+ googleapis-common-protos-types (1.5.0)
+ google-protobuf (~> 3.14)
+ googleauth (1.3.0)
+ faraday (>= 0.17.3, < 3.a)
+ jwt (>= 1.4, < 3.0)
+ memoist (~> 0.16)
+ multi_json (~> 1.11)
+ os (>= 0.9, < 2.0)
+ signet (>= 0.16, < 2.a)
+ grpc (1.52.0)
+ google-protobuf (~> 3.21)
+ googleapis-common-protos-types (~> 1.0)
+ json (2.6.2)
+ jwt (2.1.0)
+ memoist (0.16.2)
+ multi_json (1.14.1)
+ multipart-post (2.2.3)
+ os (1.1.1)
+ parallel (1.22.1)
+ parser (3.1.3.0)
+ ast (~> 2.4.1)
+ public_suffix (5.0.0)
+ rainbow (3.1.1)
+ regexp_parser (2.6.0)
+ rexml (3.2.5)
+ rspec (3.11.0)
+ rspec-core (~> 3.11.0)
+ rspec-expectations (~> 3.11.0)
+ rspec-mocks (~> 3.11.0)
+ rspec-core (3.11.0)
+ rspec-support (~> 3.11.0)
+ rspec-expectations (3.11.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.11.0)
+ rspec-mocks (3.11.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.11.0)
+ rspec-support (3.11.1)
+ rubocop (1.38.0)
+ json (~> 2.3)
+ parallel (~> 1.10)
+ parser (>= 3.1.2.1)
+ rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 1.8, < 3.0)
+ rexml (>= 3.2.5, < 4.0)
+ rubocop-ast (>= 1.23.0, < 2.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (>= 1.4.0, < 3.0)
+ rubocop-ast (1.23.0)
+ parser (>= 3.1.1.0)
+ ruby-progressbar (1.11.0)
+ ruby2_keywords (0.0.5)
+ signet (0.17.0)
+ addressable (~> 2.8)
+ faraday (>= 0.17.5, < 3.a)
+ jwt (>= 1.5, < 3.0)
+ multi_json (~> 1.10)
+ stackprof (0.2.21)
+ unicode-display_width (2.3.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ cloud_profiler_agent!
+ rspec (>= 3.10)
+ rubocop (>= 1.2)
+
+BUNDLED WITH
+ 2.3.26
diff --git a/vendor/gems/cloud_profiler_agent/LICENSE b/vendor/gems/cloud_profiler_agent/LICENSE
new file mode 100644
index 00000000000..4a8062eea52
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2020, Remind101, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/gems/cloud_profiler_agent/README.md b/vendor/gems/cloud_profiler_agent/README.md
new file mode 100644
index 00000000000..5ae2ec7c15c
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/README.md
@@ -0,0 +1,30 @@
+# ruby-cloud-profiler
+
+An implementation of [Google Cloud Profiler](https://cloud.google.com/profiler/docs)
+for Ruby.
+
+This project is not officially supported or endorsed by Google in any way.
+
+Under the hood, the agent uses [Stackprof](https://github.com/tmm1/stackprof)
+to collect the profiling data, and then converts it to
+[the pprof format](https://github.com/google/pprof/blob/master/proto/profile.proto)
+expected by Cloud Profiler. The Cloud Profiler API doesn't have pretty HTML
+documentation, but is described
+[in the googleapis specification](https://github.com/googleapis/googleapis/blob/master/google/devtools/cloudprofiler/v2/profiler.proto)
+which creates
+[generated code in google-api-ruby-client](https://github.com/googleapis/google-api-ruby-client/tree/master/generated/google/apis/cloudprofiler_v2).
+
+To use, you need to decide what to name your service and you need a Google
+Cloud project ID:
+
+ require 'cloud_profiler_agent'
+ agent = CloudProfilerAgent::Agent.new(service: 'my-service', project_id: 'my-project-id')
+ agent.start
+
+This will start a background thread that will merrily poll the Cloud Profiler
+API to see what kinds of profiles it should collect, and when. Then it will run
+stackprof, and upload the profiles.
+
+Note: the agent can only profile its own process. If your Ruby application is
+running from a webserver that forks subprocesses, then you'll need to somehow
+arrange to start the agent in the subprocess.
diff --git a/vendor/gems/cloud_profiler_agent/cloud_profiler_agent.gemspec b/vendor/gems/cloud_profiler_agent/cloud_profiler_agent.gemspec
new file mode 100644
index 00000000000..82e5041491d
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/cloud_profiler_agent.gemspec
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+lib = File.expand_path('lib', __dir__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'cloud_profiler_agent'
+
+Gem::Specification.new do |spec|
+ spec.name = 'cloud_profiler_agent'
+ spec.version = CloudProfilerAgent::VERSION
+ spec.authors = ['Remind']
+
+ spec.summary = 'Profiling agent for Google Cloud Profiler'
+ spec.homepage = 'https://github.com/remind101/ruby-cloud-profiler'
+ spec.license = 'BSD-2-Clause'
+
+ spec.files = ['lib/profile_pb.rb',
+ 'lib/cloud_profiler_agent.rb',
+ 'lib/cloud_profiler_agent/agent.rb',
+ 'lib/cloud_profiler_agent/looper.rb',
+ 'lib/cloud_profiler_agent/pprof_builder.rb']
+
+ spec.add_runtime_dependency 'googleauth', '>= 0.14'
+ spec.add_runtime_dependency 'google-cloud-profiler-v2', '~> 0.3'
+ spec.add_runtime_dependency 'google-protobuf', '~> 3.13'
+ spec.add_runtime_dependency 'stackprof', '~> 0.2'
+
+ spec.add_development_dependency 'rspec', '>= 3.10'
+ spec.add_development_dependency 'rubocop', '>= 1.2'
+end
diff --git a/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent.rb b/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent.rb
new file mode 100644
index 00000000000..60350e2e54a
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module CloudProfilerAgent
+ VERSION = '0.0.1.pre'
+ autoload :Agent, 'cloud_profiler_agent/agent'
+ autoload :PprofBuilder, 'cloud_profiler_agent/pprof_builder'
+ autoload :Looper, 'cloud_profiler_agent/looper'
+end
+
+module Perftools
+ autoload :Profiles, 'profile_pb'
+end
diff --git a/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/agent.rb b/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/agent.rb
new file mode 100644
index 00000000000..d4231d12f72
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/agent.rb
@@ -0,0 +1,147 @@
+# frozen_string_literal: true
+
+require "google/cloud/profiler/v2"
+require 'googleauth'
+require 'stackprof'
+require 'logger'
+
+module CloudProfilerAgent
+ GoogleCloudProfiler = ::Google::Cloud::Profiler::V2
+
+ PROFILE_TYPES = {
+ CPU: :cpu,
+ WALL: :wall
+ }.freeze
+ # This regexp will ensure the service name is valid.
+ # See https://cloud.google.com/ruby/docs/reference/google-cloud-profiler-v2/latest/Google-Cloud-Profiler-V2-Deployment#Google__Cloud__Profiler__V2__Deployment_target_instance_
+ SERVICE_REGEXP = /^[a-z]([-a-z0-9_.]{0,253}[a-z0-9])?$/
+
+ # Agent interfaces with the CloudProfiler API.
+ class Agent
+ def initialize(
+ service:, project_id:, service_version: nil, instance: nil, zone: nil,
+ logger: nil, log_labels: {})
+ raise ArgumentError, "service must match #{SERVICE_REGEXP}" unless SERVICE_REGEXP =~ service
+
+ @service = service
+ @project_id = project_id
+
+ @labels = { language: 'ruby' }
+ @labels[:version] = service_version unless service_version.nil?
+ @labels[:zone] = zone unless zone.nil?
+
+ @deployment = GoogleCloudProfiler::Deployment.new(project_id: project_id, target: service, labels: @labels)
+
+ @profile_labels = {}
+ @profile_labels[:instance] = instance unless instance.nil?
+
+ @google_profiler = GoogleCloudProfiler::ProfilerService::Client.new
+
+ @logger = logger || ::Logger.new($stdout)
+ @log_labels = log_labels
+ end
+
+ attr_reader :service, :project_id, :labels, :deployment, :profile_labels, :logger, :log_labels
+
+ def create_google_profile
+ google_profile_request = GoogleCloudProfiler::CreateProfileRequest.new(
+ deployment: deployment,
+ profile_type: PROFILE_TYPES.keys)
+
+ google_profile, wall_time, cpu_time = time { @google_profiler.create_profile(google_profile_request) }
+
+ logger.info(
+ gcp_ruby_status: "google profile resource created",
+ duration_s: wall_time,
+ cpu_s: cpu_time,
+ **log_labels
+ )
+
+ google_profile
+ end
+
+ # start will begin creating profiles in a background thread, looping
+ # forever. Exceptions are rescued and logged, and retries are made with
+ # exponential backoff.
+ def start
+ return if @thread&.alive?
+
+ @thread = Thread.new do
+ Looper.new(logger: logger, log_labels: log_labels).run do
+ google_profile = create_google_profile
+ google_profile = profile_app(google_profile)
+ upload_profile_to_google(google_profile)
+ end
+ end
+ end
+
+ private
+
+ def time
+ start_monotonic_time = Gitlab::Metrics::System.monotonic_time
+ start_thread_cpu_time = Gitlab::Metrics::System.thread_cpu_time
+
+ result = yield
+
+ finish_monotonic_time = Gitlab::Metrics::System.monotonic_time
+ finish_thread_cpu_time = Gitlab::Metrics::System.thread_cpu_time
+ [
+ result,
+ finish_monotonic_time - start_monotonic_time,
+ finish_thread_cpu_time - start_thread_cpu_time
+ ]
+ end
+
+ def stackprof_profile_as_pprof(duration, mode)
+ start_time = Time.now
+
+ stackprof, wall_time, cpu_time = time do
+ StackProf.run(mode: mode, raw: true, interval: ::Gitlab::StackProf.interval(mode)) do
+ sleep(duration)
+ end
+ end
+
+ logger.info(
+ gcp_ruby_status: "stackprof run finished",
+ duration_s: wall_time,
+ cpu_s: cpu_time,
+ **log_labels
+ )
+
+ pprof_result, wall_time, cpu_time = time do
+ CloudProfilerAgent::PprofBuilder.convert_stackprof(stackprof, start_time, Time.now)
+ end
+
+ logger.info(
+ gcp_ruby_status: "stackprof to pprof converted",
+ duration_s: wall_time,
+ cpu_s: cpu_time,
+ **log_labels
+ )
+
+ pprof_result
+ end
+
+ def profile_app(google_profile)
+ google_profile.profile_bytes = stackprof_profile_as_pprof(google_profile.duration.seconds,
+ PROFILE_TYPES.fetch(google_profile.profile_type))
+ google_profile
+ end
+
+ def upload_profile_to_google(google_profile)
+ start_monotonic_time = Gitlab::Metrics::System.monotonic_time
+ start_thread_cpu_time = Gitlab::Metrics::System.thread_cpu_time
+
+ @google_profiler.update_profile(profile: google_profile)
+
+ finish_monotonic_time = Gitlab::Metrics::System.monotonic_time
+ finish_thread_cpu_time = Gitlab::Metrics::System.thread_cpu_time
+ logger.info(
+ gcp_ruby_status: "profile resource updated",
+ duration_s: finish_monotonic_time - start_monotonic_time,
+ cpu_s: finish_thread_cpu_time - start_thread_cpu_time,
+ **log_labels
+ )
+ end
+ end
+end
diff --git a/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/looper.rb b/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/looper.rb
new file mode 100644
index 00000000000..9f0a5ef2abd
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/looper.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require "google/cloud/profiler/v2"
+require "logger"
+
+module CloudProfilerAgent
+ # Looper is responsible for the main loop of the agent. It calls a
+ # block repeatedly, handling errors, backing off, and retrying as
+ # appropriate.
+
+ class Looper
+ LOG_MESSAGE = "Google Cloud Profiler Ruby"
+
+ def initialize(
+ min_iteration_sec: 10,
+ max_iteration_sec: 60 * 60,
+ backoff_factor: 1.5,
+ sleeper: ->(sec) { sleep(sec) },
+ clock: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) },
+ rander: -> { rand },
+ logger: nil,
+ log_labels: {}
+ )
+
+ # the minimum and maximum time between iterations of the profiler loop,
+ # in seconds. Normally the Cloud Profiler API tells us how fast to go,
+ # but we back off in case of error.
+ @min_iteration_sec = min_iteration_sec
+ @max_iteration_sec = max_iteration_sec
+ @backoff_factor = backoff_factor
+
+ # stubbable for testing
+ @sleeper = sleeper
+ @clock = clock
+ @rander = rander
+
+ @logger = logger || ::Logger.new($stdout)
+ @log_labels = log_labels
+ end
+
+ attr_reader :min_iteration_sec, :max_iteration_sec, :backoff_factor, :logger, :log_labels
+
+ def run(max_iterations = 0)
+ iterations = 0
+ iteration_time = @min_iteration_sec
+ loop do
+ start_time = @clock.call
+ iterations += 1
+ begin
+ yield
+ rescue ::Google::Cloud::Error => e
+ backoff = backoff_duration(e)
+ if backoff.nil?
+ iteration_time = @max_iteration_sec
+ else
+ # This might be longer than max_iteration_sec and that's OK: with
+ # a very large number of agents it might be necessary to achieve
+ # the objective of 1 profile per minute.
+ @sleeper.call(backoff)
+ iteration_time = @min_iteration_sec
+ end
+ rescue StandardError => e
+ iteration_time *= @backoff_factor + (@rander.call / 2)
+ elapsed = @clock.call - start_time
+ logger.error(
+ gcp_ruby_status: "error",
+ error: e.inspect,
+ duration_s: elapsed,
+ **log_labels
+ )
+ else
+ iteration_time = @min_iteration_sec
+ end
+
+ return unless iterations < max_iterations || max_iterations == 0
+
+ iteration_time = [@max_iteration_sec, iteration_time].min
+ next_time = start_time + iteration_time
+ delay = next_time - @clock.call
+ @sleeper.call(delay) if delay > 0
+ end
+ end
+
+ private
+
+ def backoff_duration(error)
+ # It's unclear how this should work, so this is based on a guess.
+ #
+ # https://github.com/googleapis/google-api-ruby-client/issues/1498
+ match = /backoff for (?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?/.match(error.message)
+ return if match.nil?
+
+ hours = Integer(match[1] || 0)
+ minutes = Integer(match[2] || 0)
+ seconds = Integer(match[3] || 0)
+
+ seconds + (minutes * 60) + (hours * 60 * 60)
+ end
+ end
+end
diff --git a/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/pprof_builder.rb b/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/pprof_builder.rb
new file mode 100644
index 00000000000..a2ca3323d98
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/lib/cloud_profiler_agent/pprof_builder.rb
@@ -0,0 +1,198 @@
+# frozen_string_literal: true
+
+require 'zlib'
+require 'stackprof'
+
+module CloudProfilerAgent
+ # PprofBuilder converts from stackprof to pprof formats.
+ #
+ # Typical usage:
+ #
+ # start_time = Time.now
+ # stackprof = StackProf.run(mode: :cpu, raw: true) do
+ # # ...
+ # end
+ # pprof = PprofBuilder.convert_stackprof(stackprof, start_time, Time.now)
+ # IO::binwrite('profile.pprof', pprof)
+ #
+ # StackProf must be invoked with raw: true for the conversion to work.
+ #
+ # The pprof format is a gzip-compressed protobuf, documented here:
+ # https://github.com/google/pprof/blob/master/proto/profile.proto
+ #
+ # The conversion is not quite isomorphic. In particular, each sample in pprof
+ # consists of a stack with line numbers and even instruction addresses.
+ # StackProf on the other hand records stack frames with only function-level
+ # granularity. Thus, the line numbers in the pprof output only reflect the
+ # first line of the function, regardless of which line was actually in the
+ # stack frame.
+ class PprofBuilder
+ def self.convert_stackprof(stackprof, start_time, end_time)
+ converter = PprofBuilder.new(stackprof, start_time, end_time)
+ converter.pprof_bytes
+ end
+
+ def initialize(profile, start_time, end_time)
+ @profile = profile
+ @start_time = start_time
+ @duration = end_time - start_time
+
+ @string_map = StringMap.new
+ end
+
+ # message returns a Perftools::Profiles::Profile, the deserialized version
+ # of a pprof profile.
+ def message
+ main_mapping = Perftools::Profiles::Mapping.new(
+ id: 1,
+ filename: @string_map.add('TODO')
+ )
+
+ message = Perftools::Profiles::Profile.new(
+ sample_type: [sample_type],
+ mapping: [main_mapping],
+ time_nanos: @start_time.to_i * 1_000_000_000,
+ duration_nanos: @duration * 1_000_000_000,
+ period_type: sample_type,
+ period: period,
+ default_sample_type: 0
+ )
+ process_raw(message)
+ process_frames(message)
+ message.string_table += @string_map.strings
+ message
+ end
+
+ # pprof_bytes returns a gzip'd protobuf object, like would be written to
+ # disk, returned by a profiling endpoint, or otherwise consumed by the
+ # `pprof` tool.
+ def pprof_bytes
+ Zlib.gzip(Perftools::Profiles::Profile.encode(message))
+ end
+
+ private
+
+ def to_pprof_unit(value)
+ case @profile.fetch(:mode)
+ when :cpu, :wall
+ value * 1000 # stackprof uses microseconds, pprof nanoseconds
+ when :object
+ value # both stackprof and pprof are counting allocations
+ else
+ raise "unknown profile mode #{@profile.fetch(:mode)}"
+ end
+ end
+
+ def period
+ to_pprof_unit @profile.fetch(:interval)
+ end
+
+ def sample_type
+ case @profile.fetch(:mode)
+ when :cpu
+ type = 'cpu'
+ unit = 'nanoseconds'
+ when :wall
+ type = 'wall'
+ unit = 'nanoseconds'
+ when :object
+ type = 'alloc_objects'
+ unit = 'count'
+ else
+ raise "unknown profile mode #{@profile.fetch(:mode)}"
+ end
+
+ Perftools::Profiles::ValueType.new(
+ type: @string_map.add(type),
+ unit: @string_map.add(unit)
+ )
+ end
+
+ # process_raw reads the :raw section of the stackprof profile and adds to
+ # the given protobuf message as appropriate
+ def process_raw(message)
+ i = 0
+ raw = @profile.fetch(:raw, [])
+
+ # It would be cleaner to use raw.shift here, but since that changes the
+ # size of the array each time it is much slower. So we use an
+ # incrementing pointer instead.
+ while i < raw.length
+ len = raw.fetch(i)
+ i += 1
+
+ frames = raw.slice(i, len)
+ i += len
+ frames.reverse!
+
+ # "weight" is how many times stackprof has seen this stack. It's
+ # usually 1, but can be 2 or more if stackprof sees the same stack in
+ # sequential samples.
+ weight = raw.fetch(i)
+ i += 1
+
+ sample = Perftools::Profiles::Sample.new(
+ value: [weight * period],
+ location_id: frames
+ )
+ message.sample.push(sample)
+ end
+ end
+
+ # process_frames reads the :frames section of the stackprof profile and adds to
+ # the given protobuf message as appropriate
+ def process_frames(message)
+ @profile.fetch(:frames, []).each do |location_id, location|
+ message.function.push(Perftools::Profiles::Function.new(
+ id: location_id,
+ name: @string_map.add(cleaned_name(location.fetch(:name))),
+ filename: @string_map.add(location.fetch(:file)),
+ start_line: location.fetch(:line, nil)
+ ))
+
+ line = Perftools::Profiles::Line.new(
+ function_id: location_id,
+ line: location.fetch(:line, nil)
+ )
+
+ message.location.push(Perftools::Profiles::Location.new(
+ id: location_id,
+ line: [line]
+ ))
+ end
+ end
+
+ def cleaned_name(name)
+ # Google Cloud Profiler has trouble identifying class structure in Ruby. It prefers everything separated by a
+ # dot as it is in for example Golang.
+ # We have to substitute `ActionView::Template#render` to `ActionView.Template.render`
+ name.gsub!(/::|#/, '.') || name
+ end
+ end
+
+ # The pprof format has one table of strings, and objects that need strings
+ # (like filenames, function names, etc) are indexes into this table,
+ # achieving a cheap kind of compression for commonly repeated strings.
+ # StringMap is a helper for building this table.
+ class StringMap
+ def initialize
+ @strings = []
+ @string_hash = {}
+ add('') # spec says string_table[0] must always be "".
+ end
+
+ # strings an array of all the strings which will go into the pprof message.
+ attr_reader :strings
+
+ # add will return an index for the given string, either returning the
+ # existing index or adding a new string to the table as appropriate.
+ def add(str)
+ i = @string_hash.fetch(str, nil)
+ return i unless i.nil?
+
+ i = strings.push(str).length - 1
+ @string_hash[str] = i
+ i
+ end
+ end
+end
diff --git a/vendor/gems/cloud_profiler_agent/lib/profile_pb.rb b/vendor/gems/cloud_profiler_agent/lib/profile_pb.rb
new file mode 100644
index 00000000000..01ef0d99141
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/lib/profile_pb.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: profile.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_file("profile.proto", syntax: :proto3) do
+ add_message "perftools.profiles.Profile" do
+ repeated :sample_type, :message, 1, "perftools.profiles.ValueType"
+ repeated :sample, :message, 2, "perftools.profiles.Sample"
+ repeated :mapping, :message, 3, "perftools.profiles.Mapping"
+ repeated :location, :message, 4, "perftools.profiles.Location"
+ repeated :function, :message, 5, "perftools.profiles.Function"
+ repeated :string_table, :string, 6
+ optional :drop_frames, :int64, 7
+ optional :keep_frames, :int64, 8
+ optional :time_nanos, :int64, 9
+ optional :duration_nanos, :int64, 10
+ optional :period_type, :message, 11, "perftools.profiles.ValueType"
+ optional :period, :int64, 12
+ repeated :comment, :int64, 13
+ optional :default_sample_type, :int64, 14
+ end
+ add_message "perftools.profiles.ValueType" do
+ optional :type, :int64, 1
+ optional :unit, :int64, 2
+ end
+ add_message "perftools.profiles.Sample" do
+ repeated :location_id, :uint64, 1
+ repeated :value, :int64, 2
+ repeated :label, :message, 3, "perftools.profiles.Label"
+ end
+ add_message "perftools.profiles.Label" do
+ optional :key, :int64, 1
+ optional :str, :int64, 2
+ optional :num, :int64, 3
+ optional :num_unit, :int64, 4
+ end
+ add_message "perftools.profiles.Mapping" do
+ optional :id, :uint64, 1
+ optional :memory_start, :uint64, 2
+ optional :memory_limit, :uint64, 3
+ optional :file_offset, :uint64, 4
+ optional :filename, :int64, 5
+ optional :build_id, :int64, 6
+ optional :has_functions, :bool, 7
+ optional :has_filenames, :bool, 8
+ optional :has_line_numbers, :bool, 9
+ optional :has_inline_frames, :bool, 10
+ end
+ add_message "perftools.profiles.Location" do
+ optional :id, :uint64, 1
+ optional :mapping_id, :uint64, 2
+ optional :address, :uint64, 3
+ repeated :line, :message, 4, "perftools.profiles.Line"
+ optional :is_folded, :bool, 5
+ end
+ add_message "perftools.profiles.Line" do
+ optional :function_id, :uint64, 1
+ optional :line, :int64, 2
+ end
+ add_message "perftools.profiles.Function" do
+ optional :id, :uint64, 1
+ optional :name, :int64, 2
+ optional :system_name, :int64, 3
+ optional :filename, :int64, 4
+ optional :start_line, :int64, 5
+ end
+ end
+end
+
+module Perftools
+ module Profiles
+ Profile = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Profile").msgclass
+ ValueType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.ValueType").msgclass
+ Sample = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Sample").msgclass
+ Label = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Label").msgclass
+ Mapping = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Mapping").msgclass
+ Location = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Location").msgclass
+ Line = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Line").msgclass
+ Function = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Function").msgclass
+ end
+end
diff --git a/vendor/gems/cloud_profiler_agent/script/generate_profile.rb b/vendor/gems/cloud_profiler_agent/script/generate_profile.rb
new file mode 100755
index 00000000000..d31c8415186
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/script/generate_profile.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'prime'
+require 'stackprof'
+
+StackProf.run(mode: :cpu, raw: true, interval: 100, out: 'spec/cloud_profiler_agent/cpu.stackprof') do
+ (1..1000).each { |i| Prime.prime_division(i) }
+end
+
+StackProf.run(mode: :wall, raw: true, interval: 100, out: 'spec/cloud_profiler_agent/wall.stackprof') do
+ sleep(1)
+end
+
+StackProf.run(mode: :object, raw: true, interval: 100, out: 'spec/cloud_profiler_agent/object.stackprof') do
+ (1..1000).each { |i| Prime.prime_division(i) }
+end
diff --git a/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/cpu.stackprof b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/cpu.stackprof
new file mode 100644
index 00000000000..ccd82272fbb
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/cpu.stackprof
Binary files differ
diff --git a/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/looper_spec.rb b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/looper_spec.rb
new file mode 100644
index 00000000000..407d185c18f
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/looper_spec.rb
@@ -0,0 +1,157 @@
+# frozen_string_literal: true
+
+require 'cloud_profiler_agent'
+
+RSpec.describe CloudProfilerAgent::Looper, feature_category: :application_performance do
+ # rubocop:disable RSpec/InstanceVariable
+ before do
+ @now = 0.0
+ end
+
+ subject do
+ described_class.new(
+ clock: -> { @now },
+ sleeper: ->(secs) {
+ sleeps.push(secs)
+ @now += secs
+ },
+ rander: -> { rand },
+ logger: Logger.new('/dev/null')
+ )
+ end
+
+ let!(:sleeps) { [] }
+ let(:rand) { 0.4 } # chosen by fair dice roll. guaranteed to be random.
+ let(:min_time) { subject.min_iteration_sec }
+ let(:max_time) { subject.max_iteration_sec }
+ let(:backoff) { subject.backoff_factor }
+
+ describe '#run' do
+ it 'runs the block the specified number of times' do
+ runs = []
+ subject.run(3) do
+ runs.push(true)
+ end
+ expect(runs.length).to eq(3)
+ end
+
+ it 'runs the block forever when max_iterations is not given' do
+ # but we don't test this, because how do you test an infinite loop?
+ end
+
+ it 'will not run faster than min_iteration_sec' do
+ subject.run(3) { nil }
+ expect(sleeps).to eq([min_time, min_time])
+ end
+
+ context 'when the block takes some time' do
+ it 'accounts for time taken by the block' do
+ subject.run(3) { @now += 1 }
+ expect(sleeps).to eq([min_time - 1, min_time - 1])
+ end
+ end
+
+ context 'when the block takes longer than min_iteration_sec' do
+ it 'does not sleep between iterations' do
+ subject.run(3) { @now += 11 }
+ expect(sleeps).to eq([])
+ end
+ end
+
+ context 'when the block raises a StandardError' do
+ it 'exponentially backs off' do
+ subject.run(3) do
+ @now += 1
+ raise StandardError, 'bam'
+ end
+
+ factor = backoff + (rand / 2)
+ expect(sleeps).to eq([(min_time * factor) - 1, (min_time * (factor**2)) - 1])
+ end
+
+ it 'respects max_iteration_sec' do
+ subject.run(15) do
+ @now += 1
+ raise StandardError, 'bam'
+ end
+
+ expect(sleeps.last).to eq(max_time - 1)
+ end
+ end
+
+ context 'when Google asks for backoff' do
+ it 'slows down' do
+ subject.run(2) do
+ @now += 1
+ raise backoff_exception('44m0s')
+ end
+
+ expect(sleeps.first).to eq(60 * 44)
+ end
+ end
+
+ context 'when the block raises some other ClientError' do
+ it 'goes to the maximum iteration time' do
+ subject.run(2) do
+ @now += 1
+ raise ::Google::Cloud::InvalidArgumentError, 'you are a bad client'
+ end
+
+ expect(sleeps).to eq([max_time - 1])
+ end
+ end
+
+ context 'when the block fails then works' do
+ it 'backs off then returns to normal' do
+ i = 0
+ subject.run(4) do
+ @now += 1
+ i += 1
+ raise 'whoops' if i == 1
+ end
+
+ factor = backoff + (rand / 2)
+ expect(sleeps).to eq([(min_time * factor) - 1, min_time - 1, min_time - 1])
+ end
+ end
+ end
+
+ describe '#max_iteration_sec' do
+ it 'is 1 hour by default' do
+ expect(subject.max_iteration_sec).to eq(60 * 60)
+ end
+ end
+
+ describe '#min_iteration_sec' do
+ it 'is 10 seconds by default' do
+ expect(subject.min_iteration_sec).to eq(10)
+ end
+ end
+
+ describe '#backoff_factor' do
+ it 'is 1.5 by default' do
+ expect(subject.backoff_factor).to eq(1.5)
+ end
+ end
+
+ def backoff_exception(duration)
+ body = "{
+ \"error\": {
+ \"code\": 409,
+ \"message\": \"generic::aborted: action throttled, backoff for #{duration}\",
+ \"errors\": [
+ {
+ \"message\": \"generic::aborted: action throttled, backoff for #{duration}\",
+ \"domain\": \"global\",
+ \"reason\": \"aborted\"
+ }
+ ],
+ \"status\": \"ABORTED\"
+ }
+ }
+ "
+ ::Google::Cloud::AlreadyExistsError.new(body) # AbortedError
+ end
+
+ # rubocop:enable RSpec/InstanceVariable
+end
diff --git a/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/object.stackprof b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/object.stackprof
new file mode 100644
index 00000000000..781e38dcb05
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/object.stackprof
Binary files differ
diff --git a/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/pprof_builder_spec.rb b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/pprof_builder_spec.rb
new file mode 100644
index 00000000000..02d6a7a70c2
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/pprof_builder_spec.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require 'cloud_profiler_agent'
+
+RSpec.describe CloudProfilerAgent::PprofBuilder, feature_category: :application_performance do
+ subject { described_class.new(profile, start_time, end_time) }
+
+ # load_profile loads one of the example profiles created by
+ # script/generate_profile.rb
+ def load_profile(name)
+ # We are disabling this security check since we are loading static files that we generated ourselves, and it is
+ # only used in specs. This is the same method StackProf uses:
+ # https://github.com/tmm1/stackprof/blob/master/lib/stackprof/report.rb#L14
+ Marshal.load(File.binread(File.expand_path("#{name}.stackprof", __dir__))) # rubocop:disable Security/MarshalLoad
+ end
+
+ def get_str(index)
+ message.string_table.fetch(index)
+ end
+
+ let(:start_time) { Time.new(2020, 10, 31, 17, 12, 0) }
+ let(:end_time) { Time.new(2020, 10, 31, 17, 12, 30) }
+
+ # message is the protobuf object, which typically gets serialized and gzip'd
+ # before being sent to the Profiler API or written to disk. Rather than
+ # unzipping and deserializing all the time, we will be making a lot of
+ # assertions about the message directly.
+ let(:message) { subject.message }
+
+ context '#process_frames' do
+ let(:profile) { load_profile(:cpu) }
+ let(:string_map) { subject.instance_variable_get(:@string_map) }
+
+ it 'converts method names to dot notation' do
+ original_frame_name = profile[:frames].to_a[0].last[:name]
+ expect(original_frame_name).to eq("Prime#prime_division")
+ second_original_frame_name = profile[:frames].to_a[1].last[:name]
+ expect(second_original_frame_name).to eq("Prime::PseudoPrimeGenerator#each")
+
+ message
+
+ cleaned_frame_name = string_map.strings[4] # the first 4 items are profile metadata
+ expect(cleaned_frame_name).to eq("Prime.prime_division")
+ second_cleaned_frame_name = string_map.strings[6] # 5 is the file location
+ expect(second_cleaned_frame_name).to eq("Prime.PseudoPrimeGenerator.each")
+ end
+ end
+
+ context 'with :cpu profile' do
+ let(:profile) { load_profile(:cpu) }
+
+ it 'has a sample type of [["cpu", "nanoseconds"]]' do
+ expect(message.sample_type.length).to eq(1)
+
+ sample_type = message.sample_type.first
+ expect(get_str(sample_type.type)).to eq('cpu')
+ expect(get_str(sample_type.unit)).to eq('nanoseconds')
+ end
+
+ it 'has a period of 100,000 cpu nanoseconds' do
+ expect(message.period).to eq(100_000)
+ period_type = message.period_type
+ expect(get_str(period_type.type)).to eq('cpu')
+ expect(get_str(period_type.unit)).to eq('nanoseconds')
+ end
+
+ it 'has a duration of 30 seconds' do
+ expect(message.duration_nanos).to eq(30 * 1_000_000_000)
+ end
+
+ it 'has the start time' do
+ expect(message.time_nanos).to eq(start_time.to_i * 1_000_000_000)
+ end
+ end
+
+ context 'with :wall profile' do
+ let(:profile) { load_profile(:wall) }
+
+ it 'has a sample type of [["wall", "nanoseconds"]]' do
+ expect(message.sample_type.length).to eq(1)
+
+ sample_type = message.sample_type.first
+ expect(get_str(sample_type.type)).to eq('wall')
+ expect(get_str(sample_type.unit)).to eq('nanoseconds')
+ end
+
+ it 'has a period of 100,000 wall nanoseconds' do
+ expect(message.period).to eq(100_000)
+ period_type = message.period_type
+ expect(get_str(period_type.type)).to eq('wall')
+ expect(get_str(period_type.unit)).to eq('nanoseconds')
+ end
+
+ it 'has a sum time of about 1 second' do
+ sum_nanos = 0
+ message.sample.each do |sample|
+ sum_nanos += sample.value.first
+ end
+
+ expect(sum_nanos).to be_within(1_000_000).of(1_000_000_000)
+ end
+ end
+
+ context 'with :object profile' do
+ let(:profile) { load_profile(:object) }
+
+ it 'has a sample type of [["alloc_objects", "count"]]' do
+ expect(message.sample_type.length).to eq(1)
+
+ sample_type = message.sample_type.first
+ expect(get_str(sample_type.type)).to eq('alloc_objects')
+ expect(get_str(sample_type.unit)).to eq('count')
+ end
+
+ it 'has a period of 100 alloc_objects count' do
+ expect(message.period).to eq(100)
+ period_type = message.period_type
+ expect(get_str(period_type.type)).to eq('alloc_objects')
+ expect(get_str(period_type.unit)).to eq('count')
+ end
+ end
+end
diff --git a/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/wall.stackprof b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/wall.stackprof
new file mode 100644
index 00000000000..90db8c3721e
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/spec/cloud_profiler_agent/wall.stackprof
Binary files differ
diff --git a/vendor/gems/cloud_profiler_agent/spec/spec_helper.rb b/vendor/gems/cloud_profiler_agent/spec/spec_helper.rb
new file mode 100644
index 00000000000..e02fd27e9c8
--- /dev/null
+++ b/vendor/gems/cloud_profiler_agent/spec/spec_helper.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+RSpec.configure do |config|
+ config.expect_with :rspec do |expectations|
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ end
+
+ config.mock_with :rspec do |mocks|
+ mocks.verify_partial_doubles = true
+ end
+
+ config.shared_context_metadata_behavior = :apply_to_host_groups
+ config.filter_run_when_matching :focus
+ config.example_status_persistence_file_path = 'spec/examples.txt'
+ config.disable_monkey_patching!
+ config.warnings = true
+ config.default_formatter = 'doc' if config.files_to_run.one?
+ config.order = :random
+ Kernel.srand config.seed
+end
diff --git a/vendor/gems/kubeclient/.gitignore b/vendor/gems/kubeclient/.gitignore
deleted file mode 100644
index a0afe33a553..00000000000
--- a/vendor/gems/kubeclient/.gitignore
+++ /dev/null
@@ -1,16 +0,0 @@
-/.bundle/
-/.yardoc
-/Gemfile.lock
-/_yardoc/
-/coverage/
-/doc/
-/pkg/
-/spec/reports/
-/tmp/
-*.bundle
-*.so
-*.o
-*.a
-mkmf.log
-*.idea*
-/Gemfile.dev.rb
diff --git a/vendor/gems/kubeclient/CHANGELOG.md b/vendor/gems/kubeclient/CHANGELOG.md
deleted file mode 100644
index 3237d4a3c2d..00000000000
--- a/vendor/gems/kubeclient/CHANGELOG.md
+++ /dev/null
@@ -1,247 +0,0 @@
-# Changelog
-
-Notable changes to this project will be documented in this file.
-The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
-Kubeclient release versioning follows [SemVer](https://semver.org/).
-
-## 4.9.3 — 2021-03-23
-
-### Fixed
-
-- VULNERABILITY FIX: Previously, whenever kubeconfig did not define custom CA
- (normal situation for production clusters with public domain and certificate!),
- `Config` was returning ssl_options[:verify_ssl] hard-coded to `VERIFY_NONE` :-(
-
- Assuming you passed those ssl_options to Kubeclient::Client, this means that
- instead of checking server's certificate against your system CA store,
- it would accept ANY certificate, allowing easy man-in-the middle attacks.
-
- This is especially dangerous with user/password or token credentials
- because MITM attacker could simply steal those credentials to the cluster
- and do anything you could do on the cluster.
-
- This was broken IN ALL RELEASES MADE BEFORE 2022, ever since
- [`Kubeclient::Config` was created](https://github.com/ManageIQ/kubeclient/pull/127/files#diff-32e70f2f6781a9e9c7b83ae5e7eaf5ffd068a05649077fa38f6789e72f3de837R41-R48).
-
-- Bug fix: kubeconfig `insecure-skip-tls-verify` field was ignored.
- When kubeconfig did define custom CA, `Config` was returning hard-coded `VERIFY_PEER`.
-
- Now we honor it, return `VERIFY_NONE` iff kubeconfig has explicit
- `insecure-skip-tls-verify: true`, otherwise `VERIFY_PEER`.
-
-- `Config`: fixed parsing of `certificate-authority` file containing concatenation of
- several certificates. Previously, server's cert was checked against only first CA cert,
- resulting in possible "certificate verify failed" errors.
-
- An important use case is a chain of root & intermediate cert(s) - necessary when cluster's CA
- itself is signed by another custom CA.
- But also helps when you simply concatenate independent certs. (#461, #552)
-
- - Still broken (#460): inline `certificate-authority-data` is still parsed using `add_cert`
- method that handles only one cert.
-
-These don't affect code that supplies `Client` parameters directly,
-only code that uses `Config`.
-
-## 4.9.2 — 2021-05-30
-
-### Added
-- Ruby 3.0 compatibility (#500, #505).
-
-### Removed
-- Reduce .gem size by dropping test/ directory, it's useless at run time (#502).
-
-## 4.9.1 — 2020-08-31
-### Fixed
-- Now should work with apiserver deployed not at root of domain but a sub-path,
- which is standard with Rancher.
- Notably, `create_...` methods were sending bad apiVersion and getting 400 error.
- (#457, hopefully fixes #318, #418 and https://gitlab.com/gitlab-org/gitlab/-/issues/22043)
-
-## 4.9.0 - 2020-08-03
-### Added
-- Support for `user: exec` credential plugins using TLS client auth (#453)
-
-## 4.8.0 — 2020-07-03
-
-### Added
-- Support for server-side apply (#448).
-
-### Fixed
-- Declared forgotten dependency on jsonpath, needed for `gcp` provider with `cmd-path` (#450).
-
-## 4.7.0 — 2020-06-14
-
-### Fixed
-- Ruby 2.7 compatibility: bumped minimum recursive-open-struct to one that works on 2.7 (#439).
-- Ruby 2.7 warnings (#433, #438).
-- Improved watch documentation, including behavior planned to change in 5.0.0 (#436).
-
-### Added
-- Google Application Default Credentials: Added `userinfo.email` to requested scopes, which is necessary for RBAC policies (#441).
-
-## 4.6.0 — 2019-12-30
-
-### Fixed
-- AmazonEksCredentials was sometimes leaving base64 padding that IAM auth of the EKS cluster rejects. Now padding is always stripped. (#424, #423)
-
-### Added
-- Allow calling `watch_foos` methods with a block, simpler to use and guarantees closing the connection. (#425)
-
-- Support `limitBytes` query parameter for `get_pod_log`. (#426)
-
-## 4.5.0 — 2019-09-27
-
-### Added
-- Support `:resourceVersion` parameter in `get_foos` methods (similar to existing support in `watch_foos` methods). (#420)
-
-- Relax dependency on `http` gem to allow both 3.x and 4.x. (#413)
-
-## 4.4.0 — 2019-05-03
-
-### Added
-- GCP configs with `user[auth-provider][name] == 'gcp'` will execute credential plugin (normally the `gcloud config config-helper` subcommand) when the config specifies it in `cmd-path`, `cmd-args` fields (similar to `exec` support). This code path works without `googleauth` gem. Otherwise, `GoogleApplicationDefaultCredentials` path will be tried as before. (#410)
-- `AmazonEksCredentials` helper for obtaining a token to authenticate against Amazon EKS. This is not currently integrated in `Config`, you will need to invoke it yourself. You'll need some aws gems that Kubeclient _does not_ include. (#404, #406)
-
-### Changed
-- OpenID Connect tokens which cannot be validaded because we cannot identify the key they were signed with will be considered expired and refreshed as usual. (#407)
-
-## 4.3.0 — 2019-03-03
-
-### Changed
-- `GoogleApplicationDefaultCredentials` will now automatically be used by `Config` if the `user[auth-provider][name] == 'gcp'` in the provided context. Note that `user[exec]` is checked first in anticipation of this functionality being added to GCP sometime in the future. Kubeclient _does not_ include the required `googleauth` gem, so you will need to include it in your calling application. (#394)
-
-### Added
-- OpenID Connect credentials will automatically be used if the `user[auth-provider][name] == 'oidc'` in the provided context. Note that `user[exec]` is checked first. Kubeclient _does not_ include the required `openid_connect` gem, so you will need to include it in your calling application. (#396)
-
-- Support for `json_patch_#{entity}` and `merge_patch_#{entity}`. `patch_#{entity}` will continue to use strategic merge patch. (#390)
-
-## 4.2.2 — 2019-01-09
-
-### Added
-- New `http_max_redirects` option (#374).
-
-### Changed
-- Default max redirects for watch increased from 4 to 10, to match other verbs (#374).
-
-## 4.2.1 — 2018-12-26
-
-### Fixed
-- For resources that contain dashes in name, there will be an attempt to resolve the method name based on singular name prefix or by replacing the dash in names with underscores (#383).
-
-## 4.2.0 — 2018-12-20
-
-### Added
-- Support `user: exec: ...` credential plugins like in Go client (#363, #375).
-
-### Security
-- Really made `Kubeclient::Config.new(data, nil)` prevent external file lookups. (#372)
- README documented this since 3.1.1 (#334) but alas that was a lie — absolute paths always worked.
- Now this also prevents credential plugin execution.
-
- Even in this mode, using config from untrusted sources is not recommended.
-
-This release included all changes up to 4.1.1, but NOT 4.1.2 which was branched off later (4.2.1 does include same fix).
-
-## 4.1.2 — 2018-12-26
-
-### Fixed
-- For resources that contain dashes in name, there will be an attempt to resolve the method name based on singular name prefix or by replacing the dash in names with underscores (#382).
-
-## 4.1.1 — 2018-12-17
-
-### Fixed
-- Fixed method names for non-suffix plurals such as y -> ies (#377).
-
-## 4.1.0 — 2018-11-28 — REGRESSION
-
-This version broke method names where plural is not just adding a suffix, notably y -> ies (bug #376).
-
-### Fixed
-- Support custom resources with lowercase `kind` (#361).
-- `create_security_context_constraint` now works (#366).
-- `get_security_context_constraints.kind`, `get_endpoints.kind` are now plural as in kubernetes (#366).
-
-### Added
-- Add support for retrieving large lists of objects in chunks (#356).
-
-## 4.0.0 — 2018-07-23
-
-### Removed
-- Bumped officially supported kubernetes versions to >= 1.3.
-- Specifically `proxy_url` no longer works for <= 1.2 (#323).
-
-### Fixed
-- `proxy_url` now works for kubernetes 1.10 and later (#323).
-
-### Changed
-- Switched `http` gem dependency from 2.y to 3.y (#321).
-
-## 3.1.2 — 2018-06-11
-
-### Fixed
-- Fixed `Kubeclient::Config.read` regression, no longer crashes on YAML timestamps (#338).
-
-## 3.1.1 - 2018-06-01 — REGRESSION
-
-In this version `Kubeclient::Config.read` raises Psych::DisallowedClass on legal yaml configs containing a timestamp, for example gcp access-token expiry (bug #337).
-
-### Security
-- Changed `Kubeclient::Config.read` to use `YAML.safe_load` (#334).
-
- Previously, could deserialize arbitrary ruby classes. The risk depends on ruby classes available in the application; sometimes a class may have side effects - up to arbitrary code execution - when instantiated and/or built up with `x[key] = value` during YAML parsing.
-
- Despite this fix, using config from untrusted sources is not recommended.
-
-## 3.1.0 - 2018-05-27
-
-### Fixed
-- Fixed watch `.finish` sometimes caused `HTTP::ConnectionError` exception from the reading loop (#315).
-
-### Added
-- `get_pod_log` now has `timestamps`, `since_time` (#319) and `tail_lines` (#326) params.
-- `Kubeclient::Config::Context#namespace` now set, if present in kubeconfig file (#308).
-- Improved README directions for authenticating within a kubernetes cluster (#316).
-- `Kubeclient::GoogleApplicationDefaultCredentials` helper for Google application default credentials (#213). Needs `googleauth` gem.
-- New `as: :parsed` and `as: :parsed_symbolized` formats (#306).
-- Allow setting default `as:` format for the whole client (#299, #305).
-- Relaxed `recursive-open-struct` dependency to allow 1.1+ as well (#313).
-
-## 3.0.0 - 2018-02-04
-### Removed
-- Dropped entity classes (`Kubeclient::Pod` etc.), only `Kubeclient::Resource` exists now (#292, #288).
-- Ruby 2.0, 2.1 no longer supported (#253, #291).
-
-### Fixed
-- Added missing singular `get_security_context_constraint`, fixed `get_security_context_constraints` to mean plural (#261).
-- Fixed `@http_proxy_uri` undefined warning (#261).
-- Documentation fixes & improvements (#225, #229, #243, #296).
-
-### Added
-- `delete_options:` parameter to `delete_*` methods, useful for cascade delete (#267).
-- `as: :raw` option for watch (#285).
-- Now raises `Kubeclient::HttpError`. Rescuing `KubeException` still works but is deprecated. (#195, #288)
- - 404 error raise `Kubeclient::ResourceNotFoundError`, a subclass of `HttpError` (#233).
-- Include request info in exception message (#221).
-- Ruby 2.4 and 2.5 are now supported & tested (#247, #295).
-
-### Changed
-- `Kubeclient::Config#context(nonexistent_context_name)` raises `KeyError` instead of `RuntimeError`.
-- `update_*`, `delete_*`, `patch_*` now all return `RecursiveOpenStruct` consistently (#290).
-- Many dependencies bumped (#204, #231, #253, #269).
-
-## 2.5.2 - 2018-02-04
-- Watch results are now `RecursiveOpenStruct` inside arrays too (#279).
-- Fixed watch `.finish` sometimes caused `Errno::EBADF` exception from the reading loop (#280).
-- Easing dependency version (#287, #301)
-
-## 2.5.1 - 2017-10-12
-No changes since 2.5.0, fixed packaging mistake.
-
-## [2.5.0 - 2017-10-12 was YANKED]
-
-### Added
-
-- `as: raw` option for `get_*` methods returning a string (#262 via #271).
-
-## 2.4.0 - 2017-05-10
diff --git a/vendor/gems/kubeclient/Gemfile b/vendor/gems/kubeclient/Gemfile
deleted file mode 100644
index da50b39459f..00000000000
--- a/vendor/gems/kubeclient/Gemfile
+++ /dev/null
@@ -1,7 +0,0 @@
-source 'https://rubygems.org'
-
-dev_gemfile = File.expand_path('Gemfile.dev.rb', __dir__)
-eval_gemfile(dev_gemfile) if File.exist?(dev_gemfile)
-
-# Specify your gem's dependencies in kubeclient.gemspec
-gemspec
diff --git a/vendor/gems/kubeclient/LICENSE.txt b/vendor/gems/kubeclient/LICENSE.txt
deleted file mode 100644
index c79ef416c4b..00000000000
--- a/vendor/gems/kubeclient/LICENSE.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-Copyright (c) 2014 Alissa Bonas
-
-MIT License
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/gems/kubeclient/README.md b/vendor/gems/kubeclient/README.md
deleted file mode 100644
index 6cf0fb67293..00000000000
--- a/vendor/gems/kubeclient/README.md
+++ /dev/null
@@ -1,889 +0,0 @@
-# Kubeclient
-
-[![Gem Version](https://badge.fury.io/rb/kubeclient.svg)](http://badge.fury.io/rb/kubeclient)
-[![Build Status](https://travis-ci.org/abonas/kubeclient.svg?branch=master)](https://travis-ci.org/abonas/kubeclient)
-[![Code Climate](http://img.shields.io/codeclimate/github/abonas/kubeclient.svg)](https://codeclimate.com/github/abonas/kubeclient)
-
-A Ruby client for Kubernetes REST api.
-The client supports GET, POST, PUT, DELETE on all the entities available in kubernetes in both the core and group apis.
-The client currently supports Kubernetes REST api version v1.
-To learn more about groups and versions in kubernetes refer to [k8s docs](https://kubernetes.io/docs/api/)
-
-## VULNERABILITYâ—
-
-If you use `Kubeclient::Config`, all gem versions released before 2022 could return incorrect `ssl_options[:verify_ssl]`,
-endangering your connection and cluster credentials.
-See [latest CHANGELOG.md](https://github.com/ManageIQ/kubeclient/blob/master/CHANGELOG.md) for details and which versions got a fix.
-Open an issue if you want a backport to another version.
-
-## Installation
-
-Add this line to your application's Gemfile:
-
-```ruby
-gem 'kubeclient'
-```
-
-And then execute:
-
-```Bash
-bundle
-```
-
-Or install it yourself as:
-
-```Bash
-gem install kubeclient
-```
-
-## Usage
-
-Initialize the client:
-
-```ruby
-client = Kubeclient::Client.new('http://localhost:8080/api/', "v1")
-```
-
-Or without specifying version (it will be set by default to "v1")
-
-```ruby
-client = Kubeclient::Client.new('http://localhost:8080/api/')
-```
-
-For A Group Api:
-
-```ruby
-client = Kubeclient::Client.new('http://localhost:8080/apis/batch', 'v1')
-```
-
-Another option is to initialize the client with URI object:
-
-```ruby
-uri = URI::HTTP.build(host: "somehostname", port: 8080)
-client = Kubeclient::Client.new(uri)
-```
-
-### SSL
-
-It is also possible to use https and configure ssl with:
-
-```ruby
-ssl_options = {
- client_cert: OpenSSL::X509::Certificate.new(File.read('/path/to/client.crt')),
- client_key: OpenSSL::PKey::RSA.new(File.read('/path/to/client.key')),
- ca_file: '/path/to/ca.crt',
- verify_ssl: OpenSSL::SSL::VERIFY_PEER
-}
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', "v1", ssl_options: ssl_options
-)
-```
-
-As an alternative to the `ca_file` it's possible to use the `cert_store`:
-
-```ruby
-cert_store = OpenSSL::X509::Store.new
-cert_store.add_cert(OpenSSL::X509::Certificate.new(ca_cert_data))
-ssl_options = {
- cert_store: cert_store,
- verify_ssl: OpenSSL::SSL::VERIFY_PEER
-}
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', "v1", ssl_options: ssl_options
-)
-```
-
-For testing and development purpose you can disable the ssl check with:
-
-```ruby
-ssl_options = { verify_ssl: OpenSSL::SSL::VERIFY_NONE }
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', 'v1', ssl_options: ssl_options
-)
-```
-
-### Authentication
-
-If you are using basic authentication or bearer tokens as described
-[here](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authentication.md) then you can specify one
-of the following:
-
-```ruby
-auth_options = {
- username: 'username',
- password: 'password'
-}
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', 'v1', auth_options: auth_options
-)
-```
-
-or
-
-```ruby
-auth_options = {
- bearer_token: 'MDExMWJkMjItOWY1Ny00OGM5LWJlNDEtMjBiMzgxODkxYzYz'
-}
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', 'v1', auth_options: auth_options
-)
-```
-
-or
-
-```ruby
-auth_options = {
- bearer_token_file: '/path/to/token_file'
-}
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', 'v1', auth_options: auth_options
-)
-```
-
-#### Inside a Kubernetes cluster
-
-The [recommended way to locate the API server](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod) within the pod is with the `kubernetes.default.svc` DNS name, which resolves to a Service IP which in turn will be routed to an API server.
-
-The recommended way to authenticate to the API server is with a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/). kube-system associates a pod with a service account and a bearer token for that service account is placed into the filesystem tree of each container in that pod at `/var/run/secrets/kubernetes.io/serviceaccount/token`.
-
-If available, a certificate bundle is placed into the filesystem tree of each container at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`, and should be used to verify the serving certificate of the API server.
-
-For example:
-
-```ruby
-auth_options = {
- bearer_token_file: '/var/run/secrets/kubernetes.io/serviceaccount/token'
-}
-ssl_options = {}
-if File.exist?("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
- ssl_options[:ca_file] = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
-end
-client = Kubeclient::Client.new(
- 'https://kubernetes.default.svc',
- 'v1',
- auth_options: auth_options,
- ssl_options: ssl_options
-)
-```
-
-Finally, the default namespace to be used for namespaced API operations is placed in a file at `/var/run/secrets/kubernetes.io/serviceaccount/namespace` in each container. It is recommended that you use this namespace when issuing API commands below.
-
-```ruby
-namespace = File.read('/var/run/secrets/kubernetes.io/serviceaccount/namespace')
-```
-You can find information about tokens in [this guide](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod) and in [this reference](http://kubernetes.io/docs/admin/authentication/).
-
-### Non-blocking IO
-
-You can also use kubeclient with non-blocking sockets such as Celluloid::IO, see [here](https://github.com/httprb/http/wiki/Parallel-requests-with-Celluloid%3A%3AIO)
-for details. For example:
-
-```ruby
-require 'celluloid/io'
-socket_options = {
- socket_class: Celluloid::IO::TCPSocket,
- ssl_socket_class: Celluloid::IO::SSLSocket
-}
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', 'v1', socket_options: socket_options
-)
-```
-
-This affects only `.watch_*` sockets, not one-off actions like `.get_*`, `.delete_*` etc.
-
-### Proxies
-
-You can also use kubeclient with an http proxy server such as tinyproxy. It can be entered as a string or a URI object.
-For example:
-```ruby
-proxy_uri = URI::HTTP.build(host: "myproxyhost", port: 8443)
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', http_proxy_uri: proxy_uri
-)
-```
-
-### Redirects
-
-You can optionally not allow redirection with kubeclient. For example:
-
-```ruby
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', http_max_redirects: 0
-)
-```
-
-### Timeouts
-
-Watching configures the socket to never time out (however, sooner or later all watches terminate).
-
-One-off actions like `.get_*`, `.delete_*` have a configurable timeout:
-```ruby
-timeouts = {
- open: 10, # unit is seconds
- read: nil # nil means never time out
-}
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', timeouts: timeouts
-)
-```
-
-Default timeouts match `Net::HTTP` and `RestClient`, which unfortunately depends on ruby version:
-- open was infinite up to ruby 2.2, 60 seconds in 2.3+.
-- read is 60 seconds.
-
-If you want ruby-independent behavior, always specify `:open`.
-
-### Discovery
-
-Discovery from the kube-apiserver is done lazily on method calls so it would not change behavior.
-
-It can also be done explicitly:
-
-```ruby
-client = Kubeclient::Client.new('http://localhost:8080/api', 'v1')
-client.discover
-```
-
-It is possible to check the status of discovery
-
-```ruby
-unless client.discovered
- client.discover
-end
-```
-
-### Kubeclient::Config
-
-If you've been using `kubectl` and have a `.kube/config` file (possibly referencing other files in fields such as `client-certificate`), you can auto-populate a config object using `Kubeclient::Config`:
-
-```ruby
-# assuming $KUBECONFIG is one file, won't merge multiple like kubectl
-config = Kubeclient::Config.read(ENV['KUBECONFIG'] || '/path/to/.kube/config')
-```
-
-This will lookup external files; relative paths will be resolved relative to the file's directory, if config refers to them with relative path.
-This includes external [`exec:` credential plugins][exec] to be executed.
-
-[exec]: https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
-
-You can also construct `Config` directly from nested data. For example if you have JSON or YAML config data in a variable:
-
-```ruby
-config = Kubeclient::Config.new(YAML.safe_load(yaml_text), nil)
-# or
-config = Kubeclient::Config.new(JSON.parse(json_text), nil)
-```
-
-The 2nd argument is a base directory for finding external files, if config refers to them with relative path.
-Setting it to `nil` disables file lookups, and `exec:` execution - such configs will raise an exception. (A config can be self-contained by using inline fields such as `client-certificate-data`.)
-
-To create a client based on a Config object:
-
-```ruby
-# default context according to `current-context` field:
-context = config.context
-# or to use a specific context, by name:
-context = config.context('default/192-168-99-100:8443/system:admin')
-
-Kubeclient::Client.new(
- context.api_endpoint,
- 'v1',
- ssl_options: context.ssl_options,
- auth_options: context.auth_options
-)
-```
-
-
-#### Amazon EKS Credentials
-
-On Amazon EKS by default the authentication method is IAM. When running kubectl a temporary token is generated by shelling out to
-the aws-iam-authenticator binary which is sent to authenticate the user.
-See [aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator).
-To replicate that functionality, the `Kubeclient::AmazonEksCredentials` class can accept a set of IAM credentials and
-contains a helper method to generate the authentication token for you.
-
-This requires a set of gems which are _not_ included in
-`kubeclient` dependencies (`aws-sigv4`) so you should add them to your bundle.
-You will also require either the `aws-sdk` v2 or `aws-sdk-core` v3 gems to generate the required `Aws:Credentials` object to pass to this method.
-
-To obtain a token:
-
-```ruby
-require 'aws-sdk-core'
-# Use keys
-credentials = Aws::Credentials.new(access_key, secret_key)
-# Or a profile
-credentials = Aws::SharedCredentials.new(profile_name: 'default').credentials
-
-auth_options = {
- bearer_token: Kubeclient::AmazonEksCredentials.token(credentials, eks_cluster_name)
-}
-client = Kubeclient::Client.new(
- eks_cluster_https_endpoint, 'v1', auth_options: auth_options
-)
-```
-
-Note that this returns a token good for one minute. If your code requires authorization for longer than that, you should plan to
-acquire a new one, see [How to manually renew](#how-to-manually-renew-expired-credentials) section.
-
-#### Google GCP credential plugin
-
-If kubeconfig file has `user: {auth-provider: {name: gcp, cmd-path: ..., cmd-args: ..., token-key: ...}}`, the command will be executed to obtain a token.
-(Normally this would be a `gcloud config config-helper` command.)
-
-Note that this returns an expiring token. If your code requires authorization for a long time, you should plan to acquire a new one, see [How to manually renew](#how-to-manually-renew-expired-credentials) section.
-
-#### Google's Application Default Credentials
-
-On Google Compute Engine, Google App Engine, or Google Cloud Functions, as well as `gcloud`-configured systems
-with [application default credentials](https://developers.google.com/identity/protocols/application-default-credentials),
-kubeclient can use `googleauth` gem to authorize.
-
-This requires the [`googleauth` gem](https://github.com/google/google-auth-library-ruby) that is _not_ included in
-`kubeclient` dependencies so you should add it to your bundle.
-
-If you use `Config.context(...).auth_options` and the kubeconfig file has `user: {auth-provider: {name: gcp}}`, but does not contain `cmd-path` key, kubeclient will automatically try this (raising LoadError if you don't have `googleauth` in your bundle).
-
-Or you can obtain a token manually:
-
-```ruby
-require 'googleauth'
-
-auth_options = {
- bearer_token: Kubeclient::GoogleApplicationDefaultCredentials.token
-}
-client = Kubeclient::Client.new(
- 'https://localhost:8443/api/', 'v1', auth_options: auth_options
-)
-```
-
-Note that this returns a token good for one hour. If your code requires authorization for longer than that, you should plan to
-acquire a new one, see [How to manually renew](#how-to-manually-renew-expired-credentials) section.
-
-#### OIDC Auth Provider
-
-If the cluster you are using has OIDC authentication enabled you can use the `openid_connect` gem to obtain
-id-tokens if the one in your kubeconfig has expired.
-
-This requires the [`openid_connect` gem](https://github.com/nov/openid_connect) which is not included in
-the `kubeclient` dependencies so should be added to your own applications bundle.
-
-The OIDC Auth Provider will not perform the initial setup of your `$KUBECONFIG` file. You will need to use something
-like [`dexter`](https://github.com/gini/dexter) in order to configure the auth-provider in your `$KUBECONFIG` file.
-
-If you use `Config.context(...).auth_options` and the `$KUBECONFIG` file has user: `{auth-provider: {name: oidc}}`,
-kubeclient will automatically obtain a token (or use `id-token` if still valid)
-
-Tokens are typically short-lived (e.g. 1 hour) and the expiration time is determined by the OIDC Provider (e.g. Google).
-If your code requires authentication for longer than that you should obtain a new token periodically, see [How to manually renew](#how-to-manually-renew-expired-credentials) section.
-
-Note: id-tokens retrieved via this provider are not written back to the `$KUBECONFIG` file as they would be when
-using `kubectl`.
-
-#### How to manually renew expired credentials
-
-Kubeclient [does not yet](https://github.com/abonas/kubeclient/issues/393) help with this.
-
-The division of labor between `Config` and `Context` objects may change, for now please make no assumptions at which stage `exec:` and `auth-provider:` are handled and whether they're cached.
-The currently guaranteed way to renew is create a new `Config` object.
-
-The more painful part is that you'll then need to create new `Client` object(s) with the credentials from new config.
-So repeat all of this:
-```ruby
-config = Kubeclient::Config.read(ENV['KUBECONFIG'] || '/path/to/.kube/config')
-context = config.context
-ssl_options = context.ssl_options
-auth_options = context.auth_options
-
-client = Kubeclient::Client.new(
- context.api_endpoint, 'v1',
- ssl_options: ssl_options, auth_options: auth_options
-)
-# and additional Clients if needed...
-```
-
-#### Security: Don't use config from untrusted sources
-
-`Config.read` is catastrophically unsafe — it will execute arbitrary command lines specified by the config!
-
-`Config.new(data, nil)` is better but Kubeclient was never reviewed for behaving safely with malicious / malformed config.
-It might crash / misbehave in unexpected ways...
-
-#### namespace
-
-Additionally, the `config.context` object will contain a `namespace` attribute, if it was defined in the file.
-It is recommended that you use this namespace when issuing API commands below.
-This is the same behavior that is implemented by `kubectl` command.
-
-You can read it as follows:
-
-```ruby
-puts config.context.namespace
-```
-
-### Supported kubernetes versions
-
-We try to support the last 3 minor versions, matching the [official support policy for Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/release/versioning.md#supported-releases-and-component-skew).
-Kubernetes 1.2 and below have known issues and are unsupported.
-Kubernetes 1.3 presumed to still work although nobody is really testing on such old versions...
-
-## Supported actions & examples:
-
-Summary of main CRUD actions:
-
-```
-get_foos(namespace: 'namespace', **opts) # namespaced collection
-get_foos(**opts) # all namespaces or global collection
-
-get_foo('name', 'namespace', opts) # namespaced
-get_foo('name', nil, opts) # global
-
-watch_foos(namespace: ns, **opts) # namespaced collection
-watch_foos(**opts) # all namespaces or global collection
-watch_foos(namespace: ns, name: 'name', **opts) # namespaced single object
-watch_foos(name: 'name', **opts) # global single object
-
-delete_foo('name', 'namespace', opts) # namespaced
-delete_foo('name', nil, opts) # global
-
-create_foo(Kubeclient::Resource.new({metadata: {name: 'name', namespace: 'namespace', ...}, ...}))
-create_foo(Kubeclient::Resource.new({metadata: {name: 'name', ...}, ...})) # global
-
-update_foo(Kubeclient::Resource.new({metadata: {name: 'name', namespace: 'namespace', ...}, ...}))
-update_foo(Kubeclient::Resource.new({metadata: {name: 'name', ...}, ...})) # global
-
-patch_foo('name', patch, 'namespace') # namespaced
-patch_foo('name', patch) # global
-
-apply_foo(Kubeclient::Resource.new({metadata: {name: 'name', namespace: 'namespace', ...}, ...}), field_manager: 'myapp', **opts)
-apply_foo(Kubeclient::Resource.new({metadata: {name: 'name', ...}, ...}), field_manager: 'myapp', **opts) # global
-```
-
-These grew to be quite inconsistent :confounded:, see https://github.com/abonas/kubeclient/issues/312 and https://github.com/abonas/kubeclient/issues/332 for improvement plans.
-
-### Get all instances of a specific entity type
-Such as: `get_pods`, `get_secrets`, `get_services`, `get_nodes`, `get_replication_controllers`, `get_resource_quotas`, `get_limit_ranges`, `get_persistent_volumes`, `get_persistent_volume_claims`, `get_component_statuses`, `get_service_accounts`
-
-```ruby
-pods = client.get_pods
-```
-
-Get all entities of a specific type in a namespace:
-
-```ruby
-services = client.get_services(namespace: 'development')
-```
-
-You can get entities which have specific labels by specifying a parameter named `label_selector` (named `labelSelector` in Kubernetes server):
-
-```ruby
-pods = client.get_pods(label_selector: 'name=redis-master')
-```
-
-You can specify multiple labels (that option will return entities which have both labels:
-
-```ruby
-pods = client.get_pods(label_selector: 'name=redis-master,app=redis')
-```
-
-There is also [a limited ability to filter by *some* fields](https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/). Which fields are supported is not documented, you can try and see if you get an error...
-```ruby
-client.get_pods(field_selector: 'spec.nodeName=master-0')
-```
-
-You can ask for entities at a specific version by specifying a parameter named `resource_version`:
-```ruby
-pods = client.get_pods(resource_version: '0')
-```
-but it's not guaranteed you'll get it. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions to understand the semantics.
-
-With default (`as: :ros`) return format, the returned object acts like an array of the individual pods, but also supports a `.resourceVersion` method.
-
-With `:parsed` and `:parsed_symbolized` formats, the returned data structure matches kubernetes list structure: it's a hash containing `metadata` and `items` keys, the latter containing the individual pods.
-
-#### Get all entities of a specific type in chunks
-
-```ruby
-continue = nil
-loop do
- entities = client.get_pods(limit: 1_000, continue: continue)
- continue = entities.continue
-
- break if entities.last?
-end
-```
-
-See https://kubernetes.io/docs/reference/using-api/api-concepts/#retrieving-large-results-sets-in-chunks for more information.
-
-The continue tokens expire after a short amount of time, so similar to a watch if you don't request a subsequent page within aprox. 5 minutes of the previous page being returned the server will return a `410 Gone` error and the client must request the list from the start (i.e. omit the continue token for the next call).
-
-Support for chunking was added in v1.9 so previous versions will ignore the option and return the full collection.
-
-#### Get a specific instance of an entity (by name)
-Such as: `get_service "service name"` , `get_pod "pod name"` , `get_replication_controller "rc name"`, `get_secret "secret name"`, `get_resource_quota "resource quota name"`, `get_limit_range "limit range name"` , `get_persistent_volume "persistent volume name"` , `get_persistent_volume_claim "persistent volume claim name"`, `get_component_status "component name"`, `get_service_account "service account name"`
-
-The GET request should include the namespace name, except for nodes and namespaces entities.
-
-```ruby
-node = client.get_node "127.0.0.1"
-```
-
-```ruby
-service = client.get_service "guestbook", 'development'
-```
-
-Note - Kubernetes doesn't work with the uid, but rather with the 'name' property.
-Querying with uid causes 404.
-
-#### Getting raw responses
-
-To avoid overhead from parsing and building `RecursiveOpenStruct` objects for each reply, pass the `as: :raw` option when initializing `Kubeclient::Client` or when calling `get_` / `watch_` methods.
-The result can then be printed, or searched with a regex, or parsed via `JSON.parse(r)`.
-
-```ruby
-client = Kubeclient::Client.new(as: :raw)
-```
-
-or
-
-```ruby
-pods = client.get_pods as: :raw
-node = client.get_node "127.0.0.1", as: :raw
-```
-
-Other formats are:
- - `:ros` (default) for `RecursiveOpenStruct`
- - `:parsed` for `JSON.parse`
- - `:parsed_symbolized` for `JSON.parse(..., symbolize_names: true)`
-
-### Watch — Receive entities updates
-
-See https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes for an overview.
-
-It is possible to receive live update notices watching the relevant entities:
-
-```ruby
-client.watch_pods do |notice|
- # process notice data
-end
-```
-
-The notices have `.type` field which may be `'ADDED'`, `'MODIFIED'`, `'DELETED'`, or currently `'ERROR'`, and an `.object` field containing the object. **UPCOMING CHANGE**: In next major version, we plan to raise exceptions instead of passing on ERROR into the block.
-
-For namespaced entities, the default watches across all namespaces, and you can specify `client.watch_secrets(namespace: 'foo')` to only watch in a single namespace.
-
-You can narrow down using `label_selector:` and `field_selector:` params, like with `get_pods` methods.
-
-You can also watch a single object by specifying `name:` e.g. `client.watch_nodes(name: 'gandalf')` (not namespaced so a name is enough) or `client.watch_pods(namespace: 'foo', name: 'bar')` (namespaced, need both params).
-Note the method name is still plural! There is no `watch_pod`, only `watch_pods`. The yielded "type" remains the same — watch notices, it's just they'll always refer to the same object.
-
-You can use `as:` param to control the format of the yielded notices.
-
-#### All watches come to an end!
-
-While nominally the watch block *looks* like an infinite loop, that's unrealistic. Network connections eventually get severed, and kubernetes apiserver is known to terminate watches.
-
-Unfortunately, this sometimes raises an exception and sometimes the loop just exits. **UPCOMING CHANGE**: In next major version, non-deliberate termination will always raise an exception; the block will only exit silenty if stopped deliberately.
-
-#### Deliberately stopping a watch
-
-You can use `break` or `return` inside the watch block.
-
-It is possible to interrupt the watcher from another thread with:
-
-```ruby
-watcher = client.watch_pods
-
-watcher.each do |notice|
- # process notice data
-end
-# <- control will pass here after .finish is called
-
-### In another thread ###
-watcher.finish
-```
-
-#### Starting watch version
-
-You can specify version to start from, commonly used in "List+Watch" pattern:
-```
-list = client.get_pods
-collection_version = list.resourceVersion
-# or with other return formats:
-list = client.get_pods(as: :parsed)
-collection_version = list['metadata']['resourceVersion']
-
-# note spelling resource_version vs resourceVersion.
-client.watch_pods(resource_version: collection_version) do |notice|
- # process notice data
-end
-```
-It's important to understand [the effects of unset/0/specific resource_version](https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions) as it modifies the behavior of the watch — in some modes you'll first see a burst of synthetic 'ADDED' notices for all existing objects.
-
-If you re-try a terminated watch again without specific resourceVersion, you might see previously seen notices again, and might miss some events.
-
-To attempt resuming a watch from same point, you can try using last resourceVersion observed during the watch. Or do list+watch again.
-
-Whenever you ask for a specific version, you must be prepared for an 410 "Gone" error if the server no longer recognizes it.
-
-#### Watch events about a particular object
-Events are [entities in their own right](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#event-v1-core).
-You can use the `field_selector` option as part of the watch methods.
-
-```ruby
-client.watch_events(namespace: 'development', field_selector: 'involvedObject.name=redis-master') do |notice|
- # process notice date
-end
-```
-
-### Delete an entity (by name)
-
-For example: `delete_pod "pod name"` , `delete_replication_controller "rc name"`, `delete_node "node name"`, `delete_secret "secret name"`
-
-Input parameter - name (string) specifying service name, pod name, replication controller name.
-
-```ruby
-deleted = client.delete_service("redis-service")
-```
-
-If you want to cascade delete, for example a deployment, you can use the `delete_options` parameter.
-
-```ruby
-deployment_name = 'redis-deployment'
-namespace = 'default'
-delete_options = Kubeclient::Resource.new(
- apiVersion: 'meta/v1',
- gracePeriodSeconds: 0,
- kind: 'DeleteOptions',
- propagationPolicy: 'Foreground' # Orphan, Foreground, or Background
-)
-client.delete_deployment(deployment_name, namespace, delete_options: delete_options)
-```
-
-### Create an entity
-For example: `create_pod pod_object`, `create_replication_controller rc_obj`, `create_secret secret_object`, `create_resource_quota resource_quota_object`, `create_limit_range limit_range_object`, `create_persistent_volume persistent_volume_object`, `create_persistent_volume_claim persistent_volume_claim_object`, `create_service_account service_account_object`
-
-Input parameter - object of type `Service`, `Pod`, `ReplicationController`.
-
-The below example is for v1
-
-```ruby
-service = Kubeclient::Resource.new
-service.metadata = {}
-service.metadata.name = "redis-master"
-service.metadata.namespace = 'staging'
-service.spec = {}
-service.spec.ports = [{
- 'port' => 6379,
- 'targetPort' => 'redis-server'
-}]
-service.spec.selector = {}
-service.spec.selector.name = "redis"
-service.spec.selector.role = "master"
-service.metadata.labels = {}
-service.metadata.labels.app = 'redis'
-service.metadata.labels.role = 'slave'
-client.create_service(service)
-```
-
-### Update an entity
-For example: `update_pod`, `update_service`, `update_replication_controller`, `update_secret`, `update_resource_quota`, `update_limit_range`, `update_persistent_volume`, `update_persistent_volume_claim`, `update_service_account`
-
-Input parameter - object of type `Pod`, `Service`, `ReplicationController` etc.
-
-The below example is for v1
-
-```ruby
-updated = client.update_service(service1)
-```
-
-### Patch an entity (by name)
-For example: `patch_pod`, `patch_service`, `patch_secret`, `patch_resource_quota`, `patch_persistent_volume`
-
-Input parameters - name (string) specifying the entity name, patch (hash) to be applied to the resource, optional: namespace name (string)
-
-The PATCH request should include the namespace name, except for nodes and namespaces entities.
-
-The below example is for v1
-
-```ruby
-patched = client.patch_pod("docker-registry", {metadata: {annotations: {key: 'value'}}}, "default")
-```
-
-`patch_#{entity}` is called using a [strategic merge patch](https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/#notes-on-the-strategic-merge-patch). `json_patch_#{entity}` and `merge_patch_#{entity}` are also available that use JSON patch and JSON merge patch, respectively. These strategies are useful for resources that do not support strategic merge patch, such as Custom Resources. Consult the [Kubernetes docs](https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/#use-a-json-merge-patch-to-update-a-deployment) for more information about the different patch strategies.
-
-### Apply an entity
-
-This is similar to `kubectl apply --server-side` (kubeclient doesn't implement logic for client-side apply). See https://kubernetes.io/docs/reference/using-api/api-concepts/#server-side-apply
-
-For example: `apply_pod`
-
-Input parameters - resource (Kubeclient::Resource) representing the desired state of the resource, field_manager (String) to identify the system managing the state of the resource, force (Boolean) whether or not to override a field managed by someone else.
-
-Example:
-
-```ruby
-service = Kubeclient::Resource.new(
- metadata: {
- name: 'redis-master',
- namespace: 'staging',
- },
- spec: {
- ...
- }
-)
-
-client.apply_service(service, field_manager: 'myapp')
-```
-
-### Get all entities of all types : all_entities
-
-Makes requests for all entities of each discovered kind (in this client's API group). This method is a convenience method instead of calling each entity's get method separately.
-
-Returns a hash with keys being the *singular* entity kind, in lowercase underscore style. For example for core API group may return keys `"node'`, `"secret"`, `"service"`, `"pod"`, `"replication_controller"`, `"namespace"`, `"resource_quota"`, `"limit_range"`, `"endpoint"`, `"event"`, `"persistent_volume"`, `"persistent_volume_claim"`, `"component_status"`, `"service_account"`. Each key points to an EntityList of same type.
-
-```ruby
-client.all_entities
-```
-
-### Get a proxy URL
-You can get a complete URL for connecting a kubernetes entity via the proxy.
-
-```ruby
-client.proxy_url('service', 'srvname', 'srvportname', 'ns')
-# => "https://localhost.localdomain:8443/api/v1/proxy/namespaces/ns/services/srvname:srvportname"
-```
-
-Note the third parameter, port, is a port name for services and an integer for pods:
-
-```ruby
-client.proxy_url('pod', 'podname', 5001, 'ns')
-# => "https://localhost.localdomain:8443/api/v1/namespaces/ns/pods/podname:5001/proxy"
-```
-
-### Get the logs of a pod
-You can get the logs of a running pod, specifying the name of the pod and the
-namespace where the pod is running:
-
-```ruby
-client.get_pod_log('pod-name', 'default')
-# => "Running...\nRunning...\nRunning...\n"
-```
-
-If that pod has more than one container, you must specify the container:
-
-```ruby
-client.get_pod_log('pod-name', 'default', container: 'ruby')
-# => "..."
-```
-
-If a container in a pod terminates, a new container is started, and you want to
-retrieve the logs of the dead container, you can pass in the `:previous` option:
-
-```ruby
-client.get_pod_log('pod-name', 'default', previous: true)
-# => "..."
-```
-
-Kubernetes can add timestamps to every log line or filter by lines time:
-```ruby
-client.get_pod_log('pod-name', 'default', timestamps: true, since_time: '2018-04-27T18:30:17.480321984Z')
-# => "..."
-```
-`since_time` can be a a `Time`, `DateTime` or `String` formatted according to RFC3339
-
-Kubernetes can fetch a specific number of lines from the end of the logs:
-```ruby
-client.get_pod_log('pod-name', 'default', tail_lines: 10)
-# => "..."
-```
-
-Kubernetes can fetch a specific number of bytes from the log, but the exact size is not guaranteed and last line may not be terminated:
-```ruby
-client.get_pod_log('pod-name', 'default', limit_bytes: 10)
-# => "..."
-```
-
-You can also watch the logs of a pod to get a stream of data:
-
-```ruby
-client.watch_pod_log('pod-name', 'default', container: 'ruby') do |line|
- puts line
-end
-```
-
-### OpenShift: Process a template
-Returns a processed template containing a list of objects to create.
-Input parameter - template (hash)
-Besides its metadata, the template should include a list of objects to be processed and a list of parameters
-to be substituted. Note that for a required parameter that does not provide a generated value, you must supply a value.
-
-##### Note: This functionality is not supported by K8s at this moment. See the following [issue](https://github.com/kubernetes/kubernetes/issues/23896)
-
-```ruby
-client.process_template template
-```
-
-## Upgrading
-
-Kubeclient release versioning follows [SemVer](https://semver.org/).
-See [CHANGELOG.md](CHANGELOG.md) for full changelog.
-
-#### past version 4.0
-
-Old kubernetes versions < 1.3 no longer supported.
-
-#### past version 3.0
-
-Ruby versions < 2.2 are no longer supported
-
-Specific entity classes mentioned in [past version 1.2.0](#past_version_1.2.0) have been dropped.
-Return values and expected classes are always Kubeclient::Resource.
-Checking the type of a resource can be done using:
-```
-> pod.kind
-=> "Pod"
-```
-
-update_* delete_* and patch_* now return a RecursiveOpenStruct like the get_* methods
-
-The `Kubeclient::Client` class raises `Kubeclient::HttpError` or subclasses now. Catching `KubeException` still works but is deprecated.
-
-`Kubeclient::Config#context` raises `KeyError` instead of `RuntimeError` for non-existent context name.
-
-<a name="past_version_1.2.0">
-
-#### past version 1.2.0
-Replace Specific Entity class references:
-
-```ruby
-Kubeclient::Service
-```
-
-with the generic
-
-```ruby
-Kubeclient::Resource.new
-```
-
-Where ever possible.
-
-## Contributing
-
-1. Fork it ( https://github.com/[my-github-username]/kubeclient/fork )
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Test your changes with `rake test rubocop`, add new tests if needed.
-4. If you added a new functionality, add it to README
-5. Commit your changes (`git commit -am 'Add some feature'`)
-6. Push to the branch (`git push origin my-new-feature`)
-7. Create a new Pull Request
-
-## Tests
-
-This client is tested with Minitest and also uses VCR recordings in some tests.
-Please run all tests before submitting a Pull Request, and add new tests for new functionality.
-
-Running tests:
-```ruby
-rake test
-```
diff --git a/vendor/gems/kubeclient/RELEASING.md b/vendor/gems/kubeclient/RELEASING.md
deleted file mode 100644
index c8a9a121eda..00000000000
--- a/vendor/gems/kubeclient/RELEASING.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Releasing Kubeclient
-
-## Versioning
-Kubeclient release versioning follows [SemVer](https://semver.org/).
-At some point in time it is decided to release version x.y.z.
-
-```bash
-RELEASE_BRANCH="master"
-```
-
-## 0. (once) Install gem-release, needed for several commands here:
-
-```bash
-gem install gem-release
-```
-
-## 1. PR(s) for changelog & bump
-
-Edit `CHANGELOG.md` as necessary. Even if all included changes remembered to update it, you should replace "Unreleased" section header with appropriate "x.y.z — 20yy-mm-dd" header.
-
-Bump `lib/kubeclient/version.rb` manually, or by using:
-```bash
-RELEASE_VERSION=x.y.z
-
-git checkout -b "release-$RELEASE_VERSION" $RELEASE_BRANCH
-# Won't work with uncommitted changes, you have to commit the changelog first.
-gem bump --version $RELEASE_VERSION
-git show # View version bump change.
-```
-
-Open a PR with target branch $RELEASE_BRANCH and get it reviewed & merged (if open for long, remember to update date in CHANGELOG to actual day of release).
-
-## 2. (once) Grabbing an authentication token for rubygems.org api
-```bash
-RUBYGEMS_USERNAME=bob
-curl -u $RUBYGEMS_USERNAME https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
-
-cat ~/.gem/credentials
-# Should look like this:
-:rubygems_api_key: ****
-```
-
-## 3. Actual release
-
-Make sure we're locally after the bump PR *merge commit*:
-```bash
-git checkout $RELEASE_BRANCH
-git status # Make sure there are no local changes
-git pull --ff-only https://github.com/abonas/kubeclient $RELEASE_BRANCH
-git log -n1
-```
-
-Last sanity check:
-```bash
-bundle install
-bundle exec rake test rubocop
-```
-
-Create and push the tag:
-```bash
-gem tag --no-push
-git push --tags --dry-run https://github.com/abonas/kubeclient # Check for unexpected tags
-git push --tags https://github.com/abonas/kubeclient
-```
-
-Release onto rubygems.org:
-```bash
-gem release
-```
diff --git a/vendor/gems/kubeclient/Rakefile b/vendor/gems/kubeclient/Rakefile
deleted file mode 100644
index a749a9c926e..00000000000
--- a/vendor/gems/kubeclient/Rakefile
+++ /dev/null
@@ -1,9 +0,0 @@
-require 'bundler/gem_tasks'
-require 'rake/testtask'
-require 'rubocop/rake_task'
-require 'yaml'
-
-task default: %i[test rubocop] # same as .travis.yml
-
-Rake::TestTask.new
-RuboCop::RakeTask.new
diff --git a/vendor/gems/kubeclient/kubeclient.gemspec b/vendor/gems/kubeclient/kubeclient.gemspec
deleted file mode 100644
index 975db8cdb59..00000000000
--- a/vendor/gems/kubeclient/kubeclient.gemspec
+++ /dev/null
@@ -1,39 +0,0 @@
-# coding: utf-8
-
-lib = File.expand_path('../lib', __FILE__)
-$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
-require 'kubeclient/version'
-
-Gem::Specification.new do |spec|
- spec.name = 'kubeclient'
- spec.version = Kubeclient::VERSION
- spec.authors = ['Alissa Bonas']
- spec.email = ['abonas@redhat.com']
- spec.summary = 'A client for Kubernetes REST api'
- spec.description = 'A client for Kubernetes REST api'
- spec.homepage = 'https://github.com/abonas/kubeclient'
- spec.license = 'MIT'
-
- spec.files = Dir.glob("lib/**/*.*")
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
- spec.test_files = []
- spec.require_paths = ['lib']
- spec.required_ruby_version = '>= 2.2.0'
-
- spec.add_development_dependency 'bundler', '>= 1.6'
- spec.add_development_dependency 'rake', '~> 13.0'
- spec.add_development_dependency 'minitest', '~> 5.15.0'
- spec.add_development_dependency 'minitest-rg'
- spec.add_development_dependency 'webmock', '~> 3.0'
- spec.add_development_dependency 'vcr'
- spec.add_development_dependency 'rubocop', '= 0.49.1'
- spec.add_development_dependency 'googleauth', '~> 0.5.1'
- spec.add_development_dependency('mocha', '~> 1.5')
- spec.add_development_dependency 'openid_connect', '~> 1.1'
- spec.add_development_dependency 'net-smtp'
-
- spec.add_dependency 'jsonpath', '~> 1.0'
- spec.add_dependency 'rest-client', '~> 2.0'
- spec.add_dependency 'recursive-open-struct', '~> 1.1', '>= 1.1.1'
- spec.add_dependency 'http', '>= 3.0', '< 6.0'
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient.rb b/vendor/gems/kubeclient/lib/kubeclient.rb
deleted file mode 100644
index eed4872834e..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'json'
-require 'rest-client'
-
-require 'kubeclient/aws_eks_credentials'
-require 'kubeclient/common'
-require 'kubeclient/config'
-require 'kubeclient/entity_list'
-require 'kubeclient/exec_credentials'
-require 'kubeclient/gcp_auth_provider'
-require 'kubeclient/http_error'
-require 'kubeclient/missing_kind_compatibility'
-require 'kubeclient/oidc_auth_provider'
-require 'kubeclient/resource'
-require 'kubeclient/resource_not_found_error'
-require 'kubeclient/version'
-require 'kubeclient/watch_stream'
-
-module Kubeclient
- # Kubernetes Client
- class Client
- include ClientMixin
- def initialize(
- uri,
- version = 'v1',
- **options
- )
- initialize_client(
- uri,
- '/api',
- version,
- **options
- )
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/aws_eks_credentials.rb b/vendor/gems/kubeclient/lib/kubeclient/aws_eks_credentials.rb
deleted file mode 100644
index 9b54b9e06cc..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/aws_eks_credentials.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-module Kubeclient
- # Get a bearer token to authenticate against aws eks.
- class AmazonEksCredentials
- class AmazonEksDependencyError < LoadError # rubocop:disable Lint/InheritException
- end
-
- class << self
- def token(credentials, eks_cluster)
- begin
- require 'aws-sigv4'
- require 'base64'
- require 'cgi'
- rescue LoadError => e
- raise AmazonEksDependencyError,
- 'Error requiring aws gems. Kubeclient itself does not include the following ' \
- 'gems: [aws-sigv4]. To support auth-provider eks, you must ' \
- "include it in your calling application. Failed with: #{e.message}"
- end
- # https://github.com/aws/aws-sdk-ruby/pull/1848
- # Get a signer
- # Note - sts only has ONE endpoint (not regional) so 'us-east-1' hardcoding should be OK
- signer = Aws::Sigv4::Signer.new(
- service: 'sts',
- region: 'us-east-1',
- credentials: credentials
- )
-
- # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Sigv4/Signer.html#presign_url-instance_method
- presigned_url_string = signer.presign_url(
- http_method: 'GET',
- url: 'https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15',
- body: '',
- credentials: credentials,
- expires_in: 60,
- headers: {
- 'X-K8s-Aws-Id' => eks_cluster
- }
- )
- kube_token = 'k8s-aws-v1.' + Base64.urlsafe_encode64(presigned_url_string.to_s).sub(/=*$/, '') # rubocop:disable Metrics/LineLength
- kube_token
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/common.rb b/vendor/gems/kubeclient/lib/kubeclient/common.rb
deleted file mode 100644
index 51087fbe888..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/common.rb
+++ /dev/null
@@ -1,661 +0,0 @@
-require 'json'
-require 'rest-client'
-
-module Kubeclient
- # Common methods
- # this is mixed in by other gems
- module ClientMixin
- ENTITY_METHODS = %w[get watch delete create update patch json_patch merge_patch apply].freeze
-
- DEFAULT_SSL_OPTIONS = {
- client_cert: nil,
- client_key: nil,
- ca_file: nil,
- cert_store: nil,
- verify_ssl: OpenSSL::SSL::VERIFY_PEER
- }.freeze
-
- DEFAULT_AUTH_OPTIONS = {
- username: nil,
- password: nil,
- bearer_token: nil,
- bearer_token_file: nil
- }.freeze
-
- DEFAULT_SOCKET_OPTIONS = {
- socket_class: nil,
- ssl_socket_class: nil
- }.freeze
-
- DEFAULT_TIMEOUTS = {
- # These do NOT affect watch, watching never times out.
- open: Net::HTTP.new('127.0.0.1').open_timeout, # depends on ruby version
- read: Net::HTTP.new('127.0.0.1').read_timeout
- }.freeze
-
- DEFAULT_HTTP_PROXY_URI = nil
- DEFAULT_HTTP_MAX_REDIRECTS = 10
-
- SEARCH_ARGUMENTS = {
- 'labelSelector' => :label_selector,
- 'fieldSelector' => :field_selector,
- 'resourceVersion' => :resource_version,
- 'limit' => :limit,
- 'continue' => :continue
- }.freeze
-
- WATCH_ARGUMENTS = {
- 'labelSelector' => :label_selector,
- 'fieldSelector' => :field_selector,
- 'resourceVersion' => :resource_version
- }.freeze
-
- attr_reader :api_endpoint
- attr_reader :ssl_options
- attr_reader :auth_options
- attr_reader :http_proxy_uri
- attr_reader :http_max_redirects
- attr_reader :headers
- attr_reader :discovered
-
- def initialize_client(
- uri,
- path,
- version,
- ssl_options: DEFAULT_SSL_OPTIONS,
- auth_options: DEFAULT_AUTH_OPTIONS,
- socket_options: DEFAULT_SOCKET_OPTIONS,
- timeouts: DEFAULT_TIMEOUTS,
- http_proxy_uri: DEFAULT_HTTP_PROXY_URI,
- http_max_redirects: DEFAULT_HTTP_MAX_REDIRECTS,
- as: :ros
- )
- validate_auth_options(auth_options)
- handle_uri(uri, path)
-
- @entities = {}
- @discovered = false
- @api_version = version
- @headers = {}
- @ssl_options = ssl_options
- @auth_options = auth_options
- @socket_options = socket_options
- # Allow passing partial timeouts hash, without unspecified
- # @timeouts[:foo] == nil resulting in infinite timeout.
- @timeouts = DEFAULT_TIMEOUTS.merge(timeouts)
- @http_proxy_uri = http_proxy_uri ? http_proxy_uri.to_s : nil
- @http_max_redirects = http_max_redirects
- @as = as
-
- if auth_options[:bearer_token]
- bearer_token(@auth_options[:bearer_token])
- elsif auth_options[:bearer_token_file]
- validate_bearer_token_file
- bearer_token(File.read(@auth_options[:bearer_token_file]))
- end
- end
-
- def method_missing(method_sym, *args, &block)
- if discovery_needed?(method_sym)
- discover
- send(method_sym, *args, &block)
- else
- super
- end
- end
-
- def respond_to_missing?(method_sym, include_private = false)
- if discovery_needed?(method_sym)
- discover
- respond_to?(method_sym, include_private)
- else
- super
- end
- end
-
- def discovery_needed?(method_sym)
- !@discovered && ENTITY_METHODS.any? { |x| method_sym.to_s.start_with?(x) }
- end
-
- def handle_exception
- yield
- rescue RestClient::Exception => e
- json_error_msg = begin
- JSON.parse(e.response || '') || {}
- rescue JSON::ParserError
- {}
- end
- err_message = json_error_msg['message'] || e.message
- error_klass = e.http_code == 404 ? ResourceNotFoundError : HttpError
- raise error_klass.new(e.http_code, err_message, e.response)
- end
-
- def discover
- load_entities
- define_entity_methods
- @discovered = true
- end
-
- def self.parse_definition(kind, name)
- # Kubernetes gives us 3 inputs:
- # kind: "ComponentStatus", "NetworkPolicy", "Endpoints"
- # name: "componentstatuses", "networkpolicies", "endpoints"
- # singularName: "componentstatus" etc (usually omitted, defaults to kind.downcase)
- # and want to derive singular and plural method names, with underscores:
- # "network_policy"
- # "network_policies"
- # kind's CamelCase word boundaries determine our placement of underscores.
-
- if IRREGULAR_NAMES[kind]
- # In a few cases, the given kind / singularName itself is still plural.
- # We require a distinct singular method name, so force it.
- method_names = IRREGULAR_NAMES[kind]
- else
- # TODO: respect singularName from discovery?
- # But how? If it differs from kind.downcase, kind's word boundaries don't apply.
- singular_name = kind.downcase
-
- if !(/[A-Z]/ =~ kind)
- # Some custom resources have a fully lowercase kind - can't infer underscores.
- method_names = [singular_name, name]
- else
- # Some plurals are not exact suffixes, e.g. NetworkPolicy -> networkpolicies.
- # So don't expect full last word to match.
- /^(?<prefix>(.*[A-Z]))(?<singular_suffix>[^A-Z]*)$/ =~ kind # "NetworkP", "olicy"
- if name.start_with?(prefix.downcase)
- plural_suffix = name[prefix.length..-1] # "olicies"
- prefix_underscores = ClientMixin.underscore_entity(prefix) # "network_p"
- method_names = [prefix_underscores + singular_suffix, # "network_policy"
- prefix_underscores + plural_suffix] # "network_policies"
- else
- method_names = resolve_unconventional_method_names(name, kind, singular_name)
- end
- end
- end
-
- OpenStruct.new(
- entity_type: kind,
- resource_name: name,
- method_names: method_names
- )
- end
-
- def self.resolve_unconventional_method_names(name, kind, singular_name)
- underscored_name = name.tr('-', '_')
- singular_underscores = ClientMixin.underscore_entity(kind)
- if underscored_name.start_with?(singular_underscores)
- [singular_underscores, underscored_name]
- else
- # fallback to lowercase, no separators for both names
- [singular_name, underscored_name.tr('_', '')]
- end
- end
-
- def handle_uri(uri, path)
- raise ArgumentError, 'Missing uri' unless uri
- @api_endpoint = (uri.is_a?(URI) ? uri : URI.parse(uri))
-
- # This regex will anchor at the last `/api`, `/oapi` or`/apis/:group`) part of the URL
- # The whole path will be matched and if existing, the api_group will be extracted.
- re = /^(?<path>.*\/o?api(?:s\/(?<apigroup>[^\/]+))?)$/mi
- match = re.match(@api_endpoint.path.chomp('/'))
-
- if match
- # Since `re` captures 2 groups, match will always have 3 elements
- # If thus we have a non-nil value in match 2, this is our api_group.
- @api_group = match[:apigroup].nil? ? '' : match[:apigroup] + '/'
- @api_endpoint.path = match[:path]
- else
- # This is a fallback, for when `/api` was not provided as part of the uri
- @api_group = ''
- @api_endpoint.path = @api_endpoint.path.chomp('/') + path
- end
- end
-
- def build_namespace_prefix(namespace)
- namespace.to_s.empty? ? '' : "namespaces/#{namespace}/"
- end
-
- # rubocop:disable Metrics/BlockLength
- def define_entity_methods
- @entities.values.each do |entity|
- # get all entities of a type e.g. get_nodes, get_pods, etc.
- define_singleton_method("get_#{entity.method_names[1]}") do |options = {}|
- get_entities(entity.entity_type, entity.resource_name, options)
- end
-
- # watch all entities of a type e.g. watch_nodes, watch_pods, etc.
- define_singleton_method("watch_#{entity.method_names[1]}") do |options = {}, &block|
- # This method used to take resource_version as a param, so
- # this conversion is to keep backwards compatibility
- options = { resource_version: options } unless options.is_a?(Hash)
-
- watch_entities(entity.resource_name, options, &block)
- end
-
- # get a single entity of a specific type by name
- define_singleton_method("get_#{entity.method_names[0]}") \
- do |name, namespace = nil, opts = {}|
- get_entity(entity.resource_name, name, namespace, opts)
- end
-
- define_singleton_method("delete_#{entity.method_names[0]}") \
- do |name, namespace = nil, opts = {}|
- delete_entity(entity.resource_name, name, namespace, **opts)
- end
-
- define_singleton_method("create_#{entity.method_names[0]}") do |entity_config|
- create_entity(entity.entity_type, entity.resource_name, entity_config)
- end
-
- define_singleton_method("update_#{entity.method_names[0]}") do |entity_config|
- update_entity(entity.resource_name, entity_config)
- end
-
- define_singleton_method("patch_#{entity.method_names[0]}") \
- do |name, patch, namespace = nil|
- patch_entity(entity.resource_name, name, patch, 'strategic-merge-patch', namespace)
- end
-
- define_singleton_method("json_patch_#{entity.method_names[0]}") \
- do |name, patch, namespace = nil|
- patch_entity(entity.resource_name, name, patch, 'json-patch', namespace)
- end
-
- define_singleton_method("merge_patch_#{entity.method_names[0]}") \
- do |name, patch, namespace = nil|
- patch_entity(entity.resource_name, name, patch, 'merge-patch', namespace)
- end
-
- define_singleton_method("apply_#{entity.method_names[0]}") do |resource, opts = {}|
- apply_entity(entity.resource_name, resource, **opts)
- end
- end
- end
- # rubocop:enable Metrics/BlockLength
-
- def self.underscore_entity(entity_name)
- entity_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
- end
-
- def create_rest_client(path = nil)
- path ||= @api_endpoint.path
- options = {
- ssl_ca_file: @ssl_options[:ca_file],
- ssl_cert_store: @ssl_options[:cert_store],
- verify_ssl: @ssl_options[:verify_ssl],
- ssl_client_cert: @ssl_options[:client_cert],
- ssl_client_key: @ssl_options[:client_key],
- proxy: @http_proxy_uri,
- max_redirects: @http_max_redirects,
- user: @auth_options[:username],
- password: @auth_options[:password],
- open_timeout: @timeouts[:open],
- read_timeout: @timeouts[:read]
- }
- RestClient::Resource.new(@api_endpoint.merge(path).to_s, options)
- end
-
- def rest_client
- @rest_client ||= begin
- create_rest_client("#{@api_endpoint.path}/#{@api_version}")
- end
- end
-
- # Accepts the following options:
- # :namespace (string) - the namespace of the entity.
- # :name (string) - the name of the entity to watch.
- # :label_selector (string) - a selector to restrict the list of returned objects by labels.
- # :field_selector (string) - a selector to restrict the list of returned objects by fields.
- # :resource_version (string) - shows changes that occur after passed version of a resource.
- # :as (:raw|:ros) - defaults to :ros
- # :raw - return the raw response body as a string
- # :ros - return a collection of RecursiveOpenStruct objects
- # Accepts an optional block, that will be called with each entity,
- # otherwise returns a WatchStream
- def watch_entities(resource_name, options = {}, &block)
- ns = build_namespace_prefix(options[:namespace])
-
- path = "watch/#{ns}#{resource_name}"
- path += "/#{options[:name]}" if options[:name]
- uri = @api_endpoint.merge("#{@api_endpoint.path}/#{@api_version}/#{path}")
-
- params = {}
- WATCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] }
- uri.query = URI.encode_www_form(params) if params.any?
-
- watcher = Kubeclient::Common::WatchStream.new(
- uri,
- http_options(uri),
- formatter: ->(value) { format_response(options[:as] || @as, value) }
- )
-
- return_or_yield_to_watcher(watcher, &block)
- end
-
- # Accepts the following options:
- # :namespace (string) - the namespace of the entity.
- # :label_selector (string) - a selector to restrict the list of returned objects by labels.
- # :field_selector (string) - a selector to restrict the list of returned objects by fields.
- # :limit (integer) - a maximum number of items to return in each response
- # :continue (string) - a token used to retrieve the next chunk of entities
- # :as (:raw|:ros) - defaults to :ros
- # :raw - return the raw response body as a string
- # :ros - return a collection of RecursiveOpenStruct objects
- def get_entities(entity_type, resource_name, options = {})
- params = {}
- SEARCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] }
-
- ns_prefix = build_namespace_prefix(options[:namespace])
- response = handle_exception do
- rest_client[ns_prefix + resource_name]
- .get({ 'params' => params }.merge(@headers))
- end
- format_response(options[:as] || @as, response.body, entity_type)
- end
-
- # Accepts the following options:
- # :as (:raw|:ros) - defaults to :ros
- # :raw - return the raw response body as a string
- # :ros - return a collection of RecursiveOpenStruct objects
- def get_entity(resource_name, name, namespace = nil, options = {})
- ns_prefix = build_namespace_prefix(namespace)
- response = handle_exception do
- rest_client[ns_prefix + resource_name + "/#{name}"]
- .get(@headers)
- end
- format_response(options[:as] || @as, response.body)
- end
-
- # delete_options are passed as a JSON payload in the delete request
- def delete_entity(resource_name, name, namespace = nil, delete_options: {})
- delete_options_hash = delete_options.to_hash
- ns_prefix = build_namespace_prefix(namespace)
- payload = delete_options_hash.to_json unless delete_options_hash.empty?
- response = handle_exception do
- rs = rest_client[ns_prefix + resource_name + "/#{name}"]
- RestClient::Request.execute(
- rs.options.merge(
- method: :delete,
- url: rs.url,
- headers: { 'Content-Type' => 'application/json' }.merge(@headers),
- payload: payload
- )
- )
- end
- format_response(@as, response.body)
- end
-
- def create_entity(entity_type, resource_name, entity_config)
- # Duplicate the entity_config to a hash so that when we assign
- # kind and apiVersion, this does not mutate original entity_config obj.
- hash = entity_config.to_hash
-
- ns_prefix = build_namespace_prefix(hash[:metadata][:namespace])
-
- # TODO: temporary solution to add "kind" and apiVersion to request
- # until this issue is solved
- # https://github.com/GoogleCloudPlatform/kubernetes/issues/6439
- hash[:kind] = entity_type
- hash[:apiVersion] = @api_group + @api_version
- response = handle_exception do
- rest_client[ns_prefix + resource_name]
- .post(hash.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
- end
- format_response(@as, response.body)
- end
-
- def update_entity(resource_name, entity_config)
- name = entity_config[:metadata][:name]
- ns_prefix = build_namespace_prefix(entity_config[:metadata][:namespace])
- response = handle_exception do
- rest_client[ns_prefix + resource_name + "/#{name}"]
- .put(entity_config.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
- end
- format_response(@as, response.body)
- end
-
- def patch_entity(resource_name, name, patch, strategy, namespace)
- ns_prefix = build_namespace_prefix(namespace)
- response = handle_exception do
- rest_client[ns_prefix + resource_name + "/#{name}"]
- .patch(
- patch.to_json,
- { 'Content-Type' => "application/#{strategy}+json" }.merge(@headers)
- )
- end
- format_response(@as, response.body)
- end
-
- def apply_entity(resource_name, resource, field_manager:, force: true)
- name = "#{resource[:metadata][:name]}?fieldManager=#{field_manager}&force=#{force}"
- ns_prefix = build_namespace_prefix(resource[:metadata][:namespace])
- response = handle_exception do
- rest_client[ns_prefix + resource_name + "/#{name}"]
- .patch(
- resource.to_json,
- { 'Content-Type' => 'application/apply-patch+yaml' }.merge(@headers)
- )
- end
- format_response(@as, response.body)
- end
-
- def all_entities(options = {})
- discover unless @discovered
- @entities.values.each_with_object({}) do |entity, result_hash|
- # method call for get each entities
- # build hash of entity name to array of the entities
- method_name = "get_#{entity.method_names[1]}"
- begin
- result_hash[entity.method_names[0]] = send(method_name, options)
- rescue Kubeclient::HttpError
- next # do not fail due to resources not supporting get
- end
- end
- end
-
- def get_pod_log(pod_name, namespace,
- container: nil, previous: false,
- timestamps: false, since_time: nil, tail_lines: nil, limit_bytes: nil)
- params = {}
- params[:previous] = true if previous
- params[:container] = container if container
- params[:timestamps] = timestamps if timestamps
- params[:sinceTime] = format_datetime(since_time) if since_time
- params[:tailLines] = tail_lines if tail_lines
- params[:limitBytes] = limit_bytes if limit_bytes
-
- ns = build_namespace_prefix(namespace)
- handle_exception do
- rest_client[ns + "pods/#{pod_name}/log"]
- .get({ 'params' => params }.merge(@headers))
- end
- end
-
- def watch_pod_log(pod_name, namespace, container: nil, &block)
- # Adding the "follow=true" query param tells the Kubernetes API to keep
- # the connection open and stream updates to the log.
- params = { follow: true }
- params[:container] = container if container
-
- ns = build_namespace_prefix(namespace)
-
- uri = @api_endpoint.dup
- uri.path += "/#{@api_version}/#{ns}pods/#{pod_name}/log"
- uri.query = URI.encode_www_form(params)
-
- watcher = Kubeclient::Common::WatchStream.new(
- uri, http_options(uri), formatter: ->(value) { value }
- )
- return_or_yield_to_watcher(watcher, &block)
- end
-
- def proxy_url(kind, name, port, namespace = '')
- discover unless @discovered
- entity_name_plural =
- if %w[services pods nodes].include?(kind.to_s)
- kind.to_s
- else
- @entities[kind.to_s].resource_name
- end
- ns_prefix = build_namespace_prefix(namespace)
- rest_client["#{ns_prefix}#{entity_name_plural}/#{name}:#{port}/proxy"].url
- end
-
- def process_template(template)
- ns_prefix = build_namespace_prefix(template[:metadata][:namespace])
- response = handle_exception do
- rest_client[ns_prefix + 'processedtemplates']
- .post(template.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
- end
- JSON.parse(response)
- end
-
- def api_valid?
- result = api
- result.is_a?(Hash) && (result['versions'] || []).any? do |group|
- @api_group.empty? ? group.include?(@api_version) : group['version'] == @api_version
- end
- end
-
- def api
- response = handle_exception { create_rest_client.get(@headers) }
- JSON.parse(response)
- end
-
- private
-
- IRREGULAR_NAMES = {
- # In a few cases, the given kind itself is still plural.
- # https://github.com/kubernetes/kubernetes/issues/8115
- 'Endpoints' => %w[endpoint endpoints],
- 'SecurityContextConstraints' => %w[security_context_constraint
- security_context_constraints]
- }.freeze
-
- # Format datetime according to RFC3339
- def format_datetime(value)
- case value
- when DateTime, Time
- value.strftime('%FT%T.%9N%:z')
- when String
- value
- else
- raise ArgumentError, "unsupported type '#{value.class}' of time value '#{value}'"
- end
- end
-
- def format_response(as, body, list_type = nil)
- case as
- when :raw
- body
- when :parsed
- JSON.parse(body)
- when :parsed_symbolized
- JSON.parse(body, symbolize_names: true)
- when :ros
- result = JSON.parse(body)
-
- if list_type
- resource_version =
- result.fetch('resourceVersion') do
- result.fetch('metadata', {}).fetch('resourceVersion', nil)
- end
-
- # If 'limit' was passed save the continue token
- # see https://kubernetes.io/docs/reference/using-api/api-concepts/#retrieving-large-results-sets-in-chunks
- continue = result.fetch('metadata', {}).fetch('continue', nil)
-
- # result['items'] might be nil due to https://github.com/kubernetes/kubernetes/issues/13096
- collection = result['items'].to_a.map { |item| Kubeclient::Resource.new(item) }
-
- Kubeclient::Common::EntityList.new(list_type, resource_version, collection, continue)
- else
- Kubeclient::Resource.new(result)
- end
- else
- raise ArgumentError, "Unsupported format #{as.inspect}"
- end
- end
-
- def load_entities
- @entities = {}
- fetch_entities['resources'].each do |resource|
- next if resource['name'].include?('/')
- # Not a regular entity, special functionality covered by `process_template`.
- # https://github.com/openshift/origin/issues/21668
- next if resource['kind'] == 'Template' && resource['name'] == 'processedtemplates'
- resource['kind'] ||=
- Kubeclient::Common::MissingKindCompatibility.resource_kind(resource['name'])
- entity = ClientMixin.parse_definition(resource['kind'], resource['name'])
- @entities[entity.method_names[0]] = entity if entity
- end
- end
-
- def fetch_entities
- JSON.parse(handle_exception { rest_client.get(@headers) })
- end
-
- def bearer_token(bearer_token)
- @headers ||= {}
- @headers[:Authorization] = "Bearer #{bearer_token}"
- end
-
- def validate_auth_options(opts)
- # maintain backward compatibility:
- opts[:username] = opts[:user] if opts[:user]
-
- if %i[bearer_token bearer_token_file username].count { |key| opts[key] } > 1
- raise(
- ArgumentError,
- 'Invalid auth options: specify only one of username/password,' \
- ' bearer_token or bearer_token_file'
- )
- elsif %i[username password].count { |key| opts[key] } == 1
- raise ArgumentError, 'Basic auth requires both username & password'
- end
- end
-
- def validate_bearer_token_file
- msg = "Token file #{@auth_options[:bearer_token_file]} does not exist"
- raise ArgumentError, msg unless File.file?(@auth_options[:bearer_token_file])
-
- msg = "Cannot read token file #{@auth_options[:bearer_token_file]}"
- raise ArgumentError, msg unless File.readable?(@auth_options[:bearer_token_file])
- end
-
- def return_or_yield_to_watcher(watcher, &block)
- return watcher unless block_given?
-
- begin
- watcher.each(&block)
- ensure
- watcher.finish
- end
- end
-
- def http_options(uri)
- options = {
- basic_auth_user: @auth_options[:username],
- basic_auth_password: @auth_options[:password],
- headers: @headers,
- http_proxy_uri: @http_proxy_uri,
- http_max_redirects: http_max_redirects
- }
-
- if uri.scheme == 'https'
- options[:ssl] = {
- ca_file: @ssl_options[:ca_file],
- cert: @ssl_options[:client_cert],
- cert_store: @ssl_options[:cert_store],
- key: @ssl_options[:client_key],
- # ruby HTTP uses verify_mode instead of verify_ssl
- # http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
- verify_mode: @ssl_options[:verify_ssl]
- }
- end
-
- options.merge(@socket_options)
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/config.rb b/vendor/gems/kubeclient/lib/kubeclient/config.rb
deleted file mode 100644
index 3598afe83fe..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/config.rb
+++ /dev/null
@@ -1,202 +0,0 @@
-require 'yaml'
-require 'base64'
-require 'pathname'
-
-module Kubeclient
- # Kubernetes client configuration class
- class Config
- # Kubernetes client configuration context class
- class Context
- attr_reader :api_endpoint, :api_version, :ssl_options, :auth_options, :namespace
-
- def initialize(api_endpoint, api_version, ssl_options, auth_options, namespace)
- @api_endpoint = api_endpoint
- @api_version = api_version
- @ssl_options = ssl_options
- @auth_options = auth_options
- @namespace = namespace
- end
- end
-
- # data (Hash) - Parsed kubeconfig data.
- # kcfg_path (string) - Base directory for resolving relative references to external files.
- # If set to nil, all external lookups & commands are disabled (even for absolute paths).
- # See also the more convenient Config.read
- def initialize(data, kcfg_path)
- @kcfg = data
- @kcfg_path = kcfg_path
- raise 'Unknown kubeconfig version' if @kcfg['apiVersion'] != 'v1'
- end
-
- # Builds Config instance by parsing given file, with lookups relative to file's directory.
- def self.read(filename)
- parsed =
- if RUBY_VERSION >= '2.6'
- YAML.safe_load(File.read(filename), permitted_classes: [Date, Time])
- else
- YAML.safe_load(File.read(filename), [Date, Time])
- end
- Config.new(parsed, File.dirname(filename))
- end
-
- def contexts
- @kcfg['contexts'].map { |x| x['name'] }
- end
-
- def context(context_name = nil)
- cluster, user, namespace = fetch_context(context_name || @kcfg['current-context'])
-
- if user.key?('exec')
- exec_opts = expand_command_option(user['exec'], 'command')
- user['exec_result'] = ExecCredentials.run(exec_opts)
- end
-
- client_cert_data = fetch_user_cert_data(user)
- client_key_data = fetch_user_key_data(user)
- auth_options = fetch_user_auth_options(user)
-
- ssl_options = {}
-
- ssl_options[:verify_ssl] = if cluster['insecure-skip-tls-verify'] == true
- OpenSSL::SSL::VERIFY_NONE
- else
- OpenSSL::SSL::VERIFY_PEER
- end
-
- if cluster_ca_data?(cluster)
- cert_store = OpenSSL::X509::Store.new
- populate_cert_store_from_cluster_ca_data(cluster, cert_store)
- ssl_options[:cert_store] = cert_store
- end
-
- unless client_cert_data.nil?
- ssl_options[:client_cert] = OpenSSL::X509::Certificate.new(client_cert_data)
- end
-
- unless client_key_data.nil?
- ssl_options[:client_key] = OpenSSL::PKey.read(client_key_data)
- end
-
- Context.new(cluster['server'], @kcfg['apiVersion'], ssl_options, auth_options, namespace)
- end
-
- private
-
- def allow_external_lookups?
- @kcfg_path != nil
- end
-
- def ext_file_path(path)
- unless allow_external_lookups?
- raise "Kubeclient::Config: external lookups disabled, can't load '#{path}'"
- end
- Pathname(path).absolute? ? path : File.join(@kcfg_path, path)
- end
-
- def ext_command_path(path)
- unless allow_external_lookups?
- raise "Kubeclient::Config: external lookups disabled, can't execute '#{path}'"
- end
- # Like go client https://github.com/kubernetes/kubernetes/pull/59495#discussion_r171138995,
- # distinguish 3 cases:
- # - absolute (e.g. /path/to/foo)
- # - $PATH-based (e.g. curl)
- # - relative to config file's dir (e.g. ./foo)
- if Pathname(path).absolute?
- path
- elsif File.basename(path) == path
- path
- else
- File.join(@kcfg_path, path)
- end
- end
-
- def fetch_context(context_name)
- context = @kcfg['contexts'].detect do |x|
- break x['context'] if x['name'] == context_name
- end
-
- raise KeyError, "Unknown context #{context_name}" unless context
-
- cluster = @kcfg['clusters'].detect do |x|
- break x['cluster'] if x['name'] == context['cluster']
- end
-
- raise KeyError, "Unknown cluster #{context['cluster']}" unless cluster
-
- user = @kcfg['users'].detect do |x|
- break x['user'] if x['name'] == context['user']
- end || {}
-
- namespace = context['namespace']
-
- [cluster, user, namespace]
- end
-
- def cluster_ca_data?(cluster)
- cluster.key?('certificate-authority') || cluster.key?('certificate-authority-data')
- end
-
- def populate_cert_store_from_cluster_ca_data(cluster, cert_store)
- if cluster.key?('certificate-authority')
- cert_store.add_file(ext_file_path(cluster['certificate-authority']))
- elsif cluster.key?('certificate-authority-data')
- ca_cert_data = Base64.decode64(cluster['certificate-authority-data'])
- cert_store.add_cert(OpenSSL::X509::Certificate.new(ca_cert_data))
- end
- end
-
- def fetch_user_cert_data(user)
- if user.key?('client-certificate')
- File.read(ext_file_path(user['client-certificate']))
- elsif user.key?('client-certificate-data')
- Base64.decode64(user['client-certificate-data'])
- elsif user.key?('exec_result') && user['exec_result'].key?('clientCertificateData')
- user['exec_result']['clientCertificateData']
- end
- end
-
- def fetch_user_key_data(user)
- if user.key?('client-key')
- File.read(ext_file_path(user['client-key']))
- elsif user.key?('client-key-data')
- Base64.decode64(user['client-key-data'])
- elsif user.key?('exec_result') && user['exec_result'].key?('clientKeyData')
- user['exec_result']['clientKeyData']
- end
- end
-
- def fetch_user_auth_options(user)
- options = {}
- if user.key?('token')
- options[:bearer_token] = user['token']
- elsif user.key?('exec_result') && user['exec_result'].key?('token')
- options[:bearer_token] = user['exec_result']['token']
- elsif user.key?('auth-provider')
- options[:bearer_token] = fetch_token_from_provider(user['auth-provider'])
- else
- %w[username password].each do |attr|
- options[attr.to_sym] = user[attr] if user.key?(attr)
- end
- end
- options
- end
-
- def fetch_token_from_provider(auth_provider)
- case auth_provider['name']
- when 'gcp'
- config = expand_command_option(auth_provider['config'], 'cmd-path')
- Kubeclient::GCPAuthProvider.token(config)
- when 'oidc'
- Kubeclient::OIDCAuthProvider.token(auth_provider['config'])
- end
- end
-
- def expand_command_option(config, key)
- config = config.dup
- config[key] = ext_command_path(config[key]) if config[key]
-
- config
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/entity_list.rb b/vendor/gems/kubeclient/lib/kubeclient/entity_list.rb
deleted file mode 100644
index 2f734560a4b..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/entity_list.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'delegate'
-module Kubeclient
- module Common
- # Kubernetes Entity List
- class EntityList < DelegateClass(Array)
- attr_reader :continue, :kind, :resourceVersion
-
- def initialize(kind, resource_version, list, continue = nil)
- @kind = kind
- # rubocop:disable Style/VariableName
- @resourceVersion = resource_version
- @continue = continue
- super(list)
- end
-
- def last?
- continue.nil?
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/exec_credentials.rb b/vendor/gems/kubeclient/lib/kubeclient/exec_credentials.rb
deleted file mode 100644
index 016d48ae289..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/exec_credentials.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-# frozen_string_literal: true
-
-module Kubeclient
- # An exec-based client auth provide
- # https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuration
- # Inspired by https://github.com/kubernetes/client-go/blob/master/plugin/pkg/client/auth/exec/exec.go
- class ExecCredentials
- class << self
- def run(opts)
- require 'open3'
- require 'json'
-
- raise ArgumentError, 'exec options are required' if opts.nil?
-
- cmd = opts['command']
- args = opts['args']
- env = map_env(opts['env'])
-
- # Validate exec options
- validate_opts(opts)
-
- out, err, st = Open3.capture3(env, cmd, *args)
-
- raise "exec command failed: #{err}" unless st.success?
-
- creds = JSON.parse(out)
- validate_credentials(opts, creds)
- creds['status']
- end
-
- private
-
- def validate_opts(opts)
- raise KeyError, 'exec command is required' unless opts['command']
- end
-
- def validate_client_credentials_status(status)
- has_client_cert_data = status.key?('clientCertificateData')
- has_client_key_data = status.key?('clientKeyData')
-
- if has_client_cert_data && !has_client_key_data
- raise 'exec plugin didn\'t return client key data'
- end
-
- if !has_client_cert_data && has_client_key_data
- raise 'exec plugin didn\'t return client certificate data'
- end
-
- has_client_cert_data && has_client_key_data
- end
-
- def validate_credentials_status(status)
- raise 'exec plugin didn\'t return a status field' if status.nil?
-
- has_client_credentials = validate_client_credentials_status(status)
- has_token = status.key?('token')
-
- if has_client_credentials && has_token
- raise 'exec plugin returned both token and client data'
- end
-
- return if has_client_credentials || has_token
-
- raise 'exec plugin didn\'t return a token or client data' unless has_token
- end
-
- def validate_credentials(opts, creds)
- # out should have ExecCredential structure
- raise 'invalid credentials' if creds.nil?
-
- # Verify apiVersion?
- api_version = opts['apiVersion']
- if api_version && api_version != creds['apiVersion']
- raise "exec plugin is configured to use API version #{api_version}, " \
- "plugin returned version #{creds['apiVersion']}"
- end
-
- validate_credentials_status(creds['status'])
- end
-
- # Transform name/value pairs to hash
- def map_env(env)
- return {} unless env
-
- Hash[env.map { |e| [e['name'], e['value']] }]
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/gcp_auth_provider.rb b/vendor/gems/kubeclient/lib/kubeclient/gcp_auth_provider.rb
deleted file mode 100644
index b28e54bfd88..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/gcp_auth_provider.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require 'kubeclient/google_application_default_credentials'
-require 'kubeclient/gcp_command_credentials'
-
-module Kubeclient
- # Handle different ways to get a bearer token for Google Cloud Platform.
- class GCPAuthProvider
- class << self
- def token(config)
- if config.key?('cmd-path')
- Kubeclient::GCPCommandCredentials.token(config)
- else
- Kubeclient::GoogleApplicationDefaultCredentials.token
- end
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/gcp_command_credentials.rb b/vendor/gems/kubeclient/lib/kubeclient/gcp_command_credentials.rb
deleted file mode 100644
index 9c68c1a2847..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/gcp_command_credentials.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Kubeclient
- # Generates a bearer token for Google Cloud Platform.
- class GCPCommandCredentials
- class << self
- def token(config)
- require 'open3'
- require 'shellwords'
- require 'json'
- require 'jsonpath'
-
- cmd = config['cmd-path']
- args = config['cmd-args']
- token_key = config['token-key']
-
- out, err, st = Open3.capture3(cmd, *args.split(' '))
-
- raise "exec command failed: #{err}" unless st.success?
-
- extract_token(out, token_key)
- end
-
- private
-
- def extract_token(output, token_key)
- JsonPath.on(output, token_key.gsub(/^{|}$/, '')).first
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/google_application_default_credentials.rb b/vendor/gems/kubeclient/lib/kubeclient/google_application_default_credentials.rb
deleted file mode 100644
index 78f99ec9f32..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/google_application_default_credentials.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Kubeclient
- # Get a bearer token from the Google's application default credentials.
- class GoogleApplicationDefaultCredentials
- class GoogleDependencyError < LoadError # rubocop:disable Lint/InheritException
- end
-
- class << self
- def token
- begin
- require 'googleauth'
- rescue LoadError => e
- raise GoogleDependencyError,
- 'Error requiring googleauth gem. Kubeclient itself does not include the ' \
- 'googleauth gem. To support auth-provider gcp, you must include it in your ' \
- "calling application. Failed with: #{e.message}"
- end
-
- scopes = [
- 'https://www.googleapis.com/auth/cloud-platform',
- 'https://www.googleapis.com/auth/userinfo.email'
- ]
-
- authorization = Google::Auth.get_application_default(scopes)
- authorization.apply({})
- authorization.access_token
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/http_error.rb b/vendor/gems/kubeclient/lib/kubeclient/http_error.rb
deleted file mode 100644
index 121368c2f17..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/http_error.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# TODO: remove this on next major version bump
-# Deprected http exception
-class KubeException < StandardError
- attr_reader :error_code, :message, :response
-
- def initialize(error_code, message, response)
- @error_code = error_code
- @message = message
- @response = response
- end
-
- def to_s
- string = "HTTP status code #{@error_code}, #{@message}"
- if @response.is_a?(RestClient::Response) && @response.request
- string << " for #{@response.request.method.upcase} #{@response.request.url}"
- end
- string
- end
-end
-
-module Kubeclient
- # Exception that is raised when a http request fails
- class HttpError < KubeException
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/missing_kind_compatibility.rb b/vendor/gems/kubeclient/lib/kubeclient/missing_kind_compatibility.rb
deleted file mode 100644
index ec88960a546..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/missing_kind_compatibility.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-module Kubeclient
- module Common
- # Backward compatibility for old versions where kind is missing (e.g. OpenShift Enterprise 3.1)
- class MissingKindCompatibility
- MAPPING = {
- 'bindings' => 'Binding',
- 'componentstatuses' => 'ComponentStatus',
- 'endpoints' => 'Endpoints',
- 'events' => 'Event',
- 'limitranges' => 'LimitRange',
- 'namespaces' => 'Namespace',
- 'nodes' => 'Node',
- 'persistentvolumeclaims' => 'PersistentVolumeClaim',
- 'persistentvolumes' => 'PersistentVolume',
- 'pods' => 'Pod',
- 'podtemplates' => 'PodTemplate',
- 'replicationcontrollers' => 'ReplicationController',
- 'resourcequotas' => 'ResourceQuota',
- 'secrets' => 'Secret',
- 'securitycontextconstraints' => 'SecurityContextConstraints',
- 'serviceaccounts' => 'ServiceAccount',
- 'services' => 'Service',
- 'buildconfigs' => 'BuildConfig',
- 'builds' => 'Build',
- 'clusternetworks' => 'ClusterNetwork',
- 'clusterpolicies' => 'ClusterPolicy',
- 'clusterpolicybindings' => 'ClusterPolicyBinding',
- 'clusterrolebindings' => 'ClusterRoleBinding',
- 'clusterroles' => 'ClusterRole',
- 'deploymentconfigrollbacks' => 'DeploymentConfigRollback',
- 'deploymentconfigs' => 'DeploymentConfig',
- 'generatedeploymentconfigs' => 'DeploymentConfig',
- 'groups' => 'Group',
- 'hostsubnets' => 'HostSubnet',
- 'identities' => 'Identity',
- 'images' => 'Image',
- 'imagestreamimages' => 'ImageStreamImage',
- 'imagestreammappings' => 'ImageStreamMapping',
- 'imagestreams' => 'ImageStream',
- 'imagestreamtags' => 'ImageStreamTag',
- 'localresourceaccessreviews' => 'LocalResourceAccessReview',
- 'localsubjectaccessreviews' => 'LocalSubjectAccessReview',
- 'netnamespaces' => 'NetNamespace',
- 'oauthaccesstokens' => 'OAuthAccessToken',
- 'oauthauthorizetokens' => 'OAuthAuthorizeToken',
- 'oauthclientauthorizations' => 'OAuthClientAuthorization',
- 'oauthclients' => 'OAuthClient',
- 'policies' => 'Policy',
- 'policybindings' => 'PolicyBinding',
- 'processedtemplates' => 'Template',
- 'projectrequests' => 'ProjectRequest',
- 'projects' => 'Project',
- 'resourceaccessreviews' => 'ResourceAccessReview',
- 'rolebindings' => 'RoleBinding',
- 'roles' => 'Role',
- 'routes' => 'Route',
- 'subjectaccessreviews' => 'SubjectAccessReview',
- 'templates' => 'Template',
- 'useridentitymappings' => 'UserIdentityMapping',
- 'users' => 'User'
- }.freeze
-
- def self.resource_kind(name)
- MAPPING[name]
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/oidc_auth_provider.rb b/vendor/gems/kubeclient/lib/kubeclient/oidc_auth_provider.rb
deleted file mode 100644
index ffdfd7e2a5d..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/oidc_auth_provider.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-module Kubeclient
- # Uses OIDC id-tokens and refreshes them if they are stale.
- class OIDCAuthProvider
- class OpenIDConnectDependencyError < LoadError # rubocop:disable Lint/InheritException
- end
-
- class << self
- def token(provider_config)
- begin
- require 'openid_connect'
- rescue LoadError => e
- raise OpenIDConnectDependencyError,
- 'Error requiring openid_connect gem. Kubeclient itself does not include the ' \
- 'openid_connect gem. To support auth-provider oidc, you must include it in your ' \
- "calling application. Failed with: #{e.message}"
- end
-
- issuer_url = provider_config['idp-issuer-url']
- discovery = OpenIDConnect::Discovery::Provider::Config.discover! issuer_url
-
- if provider_config.key? 'id-token'
- return provider_config['id-token'] unless expired?(provider_config['id-token'], discovery)
- end
-
- client = OpenIDConnect::Client.new(
- identifier: provider_config['client-id'],
- secret: provider_config['client-secret'],
- authorization_endpoint: discovery.authorization_endpoint,
- token_endpoint: discovery.token_endpoint,
- userinfo_endpoint: discovery.userinfo_endpoint
- )
- client.refresh_token = provider_config['refresh-token']
- client.access_token!.id_token
- end
-
- def expired?(id_token, discovery)
- decoded_token = OpenIDConnect::ResponseObject::IdToken.decode(
- id_token,
- discovery.jwks
- )
- # If token expired or expiring within 60 seconds
- Time.now.to_i + 60 > decoded_token.exp.to_i
- rescue JSON::JWK::Set::KidNotFound
- # Token cannot be verified: the kid it was signed with is not available for discovery
- # Consider it expired and fetch a new one.
- true
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/resource.rb b/vendor/gems/kubeclient/lib/kubeclient/resource.rb
deleted file mode 100644
index 08a50c3fe4f..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/resource.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require 'recursive_open_struct'
-
-module Kubeclient
- # Represents all the objects returned by Kubeclient
- class Resource < RecursiveOpenStruct
- def initialize(hash = nil, args = {})
- args[:recurse_over_arrays] = true
- super(hash, args)
- end
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/resource_not_found_error.rb b/vendor/gems/kubeclient/lib/kubeclient/resource_not_found_error.rb
deleted file mode 100644
index 045a83642d7..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/resource_not_found_error.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-module Kubeclient
- class ResourceNotFoundError < HttpError
- end
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/version.rb b/vendor/gems/kubeclient/lib/kubeclient/version.rb
deleted file mode 100644
index bff50841794..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/version.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# Kubernetes REST-API Client
-module Kubeclient
- VERSION = '4.9.4-gitlab1'.freeze
-end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/watch_stream.rb b/vendor/gems/kubeclient/lib/kubeclient/watch_stream.rb
deleted file mode 100644
index ef676660d53..00000000000
--- a/vendor/gems/kubeclient/lib/kubeclient/watch_stream.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-require 'json'
-require 'http'
-module Kubeclient
- module Common
- # HTTP Stream used to watch changes on entities
- class WatchStream
- def initialize(uri, http_options, formatter:)
- @uri = uri
- @http_client = nil
- @http_options = http_options
- @http_options[:http_max_redirects] ||= Kubeclient::Client::DEFAULT_HTTP_MAX_REDIRECTS
- @formatter = formatter
- end
-
- def each
- @finished = false
-
- @http_client = build_client
- response = @http_client.request(:get, @uri, build_client_options)
- unless response.code < 300
- raise Kubeclient::HttpError.new(response.code, response.reason, response)
- end
-
- buffer = ''
- response.body.each do |chunk|
- buffer << chunk
- while (line = buffer.slice!(/.+\n/))
- yield @formatter.call(line.chomp)
- end
- end
- rescue StandardError
- raise unless @finished
- end
-
- def finish
- @finished = true
- @http_client.close unless @http_client.nil?
- end
-
- private
-
- def max_hops
- @http_options[:http_max_redirects] + 1
- end
-
- def follow_option
- if max_hops > 1
- { max_hops: max_hops }
- else
- # i.e. Do not follow redirects as we have set http_max_redirects to 0
- # Setting `{ max_hops: 1 }` does not work FWIW
- false
- end
- end
-
- def build_client
- client = HTTP::Client.new(follow: follow_option)
-
- if @http_options[:basic_auth_user] && @http_options[:basic_auth_password]
- client = client.basic_auth(
- user: @http_options[:basic_auth_user],
- pass: @http_options[:basic_auth_password]
- )
- end
-
- client
- end
-
- def using_proxy
- proxy = @http_options[:http_proxy_uri]
- return nil unless proxy
- p_uri = URI.parse(proxy)
- {
- proxy_address: p_uri.hostname,
- proxy_port: p_uri.port,
- proxy_username: p_uri.user,
- proxy_password: p_uri.password
- }
- end
-
- def build_client_options
- client_options = {
- headers: @http_options[:headers],
- proxy: using_proxy
- }
- if @http_options[:ssl]
- client_options[:ssl] = @http_options[:ssl]
- socket_option = :ssl_socket_class
- else
- socket_option = :socket_class
- end
- client_options[socket_option] = @http_options[socket_option] if @http_options[socket_option]
- client_options
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/test/cassettes/kubernetes_guestbook.yml b/vendor/gems/kubeclient/test/cassettes/kubernetes_guestbook.yml
deleted file mode 100644
index 3829add6d75..00000000000
--- a/vendor/gems/kubeclient/test/cassettes/kubernetes_guestbook.yml
+++ /dev/null
@@ -1,879 +0,0 @@
----
-http_interactions:
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 404
- message: Not Found
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '253'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "namespaces \"kubeclient-ns\" not found",
- "reason": "NotFound",
- "details": {
- "name": "kubeclient-ns",
- "kind": "namespaces"
- },
- "code": 404
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/guestbook
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 404
- message: Not Found
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '239'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "service \"guestbook\" not found",
- "reason": "NotFound",
- "details": {
- "name": "guestbook",
- "kind": "service"
- },
- "code": 404
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-master
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 404
- message: Not Found
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '245'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "service \"redis-master\" not found",
- "reason": "NotFound",
- "details": {
- "name": "redis-master",
- "kind": "service"
- },
- "code": 404
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-slave
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 404
- message: Not Found
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '243'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "service \"redis-slave\" not found",
- "reason": "NotFound",
- "details": {
- "name": "redis-slave",
- "kind": "service"
- },
- "code": 404
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 404
- message: Not Found
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '269'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "replicationControllers \"guestbook\" not found",
- "reason": "NotFound",
- "details": {
- "name": "guestbook",
- "kind": "replicationControllers"
- },
- "code": 404
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 404
- message: Not Found
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '275'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "replicationControllers \"redis-master\" not found",
- "reason": "NotFound",
- "details": {
- "name": "redis-master",
- "kind": "replicationControllers"
- },
- "code": 404
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 404
- message: Not Found
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '273'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "replicationControllers \"redis-slave\" not found",
- "reason": "NotFound",
- "details": {
- "name": "redis-slave",
- "kind": "replicationControllers"
- },
- "code": 404
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: post
- uri: http://10.35.0.23:8080/api/v1/namespaces
- body:
- encoding: UTF-8
- string: '{"metadata":{"name":"kubeclient-ns"},"kind":"Namespace","apiVersion":"v1"}'
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- Content-Length:
- - '74'
- User-Agent:
- - Ruby
- response:
- status:
- code: 201
- message: Created
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '297'
- body:
- encoding: UTF-8
- string: '{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"534","creationTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: post
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services
- body:
- encoding: UTF-8
- string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"name":"guestbook"},"name":"guestbook"},"spec":{"selector":{"app":"guestbook"},"ports":[{"port":3000,"targetPort":"http-server"}]},"type":"LoadBalancer","kind":"Service","apiVersion":"v1"}'
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- Content-Length:
- - '239'
- User-Agent:
- - Ruby
- response:
- status:
- code: 201
- message: Created
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '521'
- body:
- encoding: UTF-8
- string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/guestbook","uid":"f42187e1-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"538","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"name":"guestbook"}},"spec":{"ports":[{"protocol":"TCP","port":3000,"targetPort":"http-server","nodePort":0}],"selector":{"app":"guestbook"},"clusterIP":"10.0.0.80","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: post
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services
- body:
- encoding: UTF-8
- string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"master"},"name":"redis-master"},"spec":{"selector":{"app":"redis","role":"master"},"ports":[{"port":6379,"targetPort":"redis-server"}]},"kind":"Service","apiVersion":"v1"}'
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- Content-Length:
- - '244'
- User-Agent:
- - Ruby
- response:
- status:
- code: 201
- message: Created
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '552'
- body:
- encoding: UTF-8
- string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-master","uid":"f423bf8b-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"542","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"master"},"clusterIP":"10.0.0.140","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: post
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services
- body:
- encoding: UTF-8
- string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"slave"},"name":"redis-slave"},"spec":{"selector":{"app":"redis","role":"slave"},"ports":[{"port":6379,"targetPort":"redis-server"}]},"kind":"Service","apiVersion":"v1"}'
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- Content-Length:
- - '241'
- User-Agent:
- - Ruby
- response:
- status:
- code: 201
- message: Created
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '548'
- body:
- encoding: UTF-8
- string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-slave","uid":"f4264678-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"545","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"slave"},"clusterIP":"10.0.0.154","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: post
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers
- body:
- encoding: UTF-8
- string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"guestbook","role":"slave"},"name":"guestbook"},"spec":{"selector":{"app":"guestbook"},"template":{"metadata":{"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000}]}]}},"replicas":3},"kind":"ReplicationController","apiVersion":"v1"}'
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- Content-Length:
- - '395'
- User-Agent:
- - Ruby
- response:
- status:
- code: 201
- message: Created
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '815'
- body:
- encoding: UTF-8
- string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook","uid":"f4287784-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"547","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"guestbook","role":"slave"}},"spec":{"replicas":3,"selector":{"app":"guestbook"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: post
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers
- body:
- encoding: UTF-8
- string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"master"},"name":"redis-master"},"spec":{"selector":{"app":"redis","role":"master"},"template":{"metadata":{"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379}]}]}},"replicas":1},"kind":"ReplicationController","apiVersion":"v1"}'
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- Content-Length:
- - '405'
- User-Agent:
- - Ruby
- response:
- status:
- code: 201
- message: Created
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '828'
- body:
- encoding: UTF-8
- string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master","uid":"f42a9800-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"558","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"replicas":1,"selector":{"app":"redis","role":"master"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: post
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers
- body:
- encoding: UTF-8
- string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"slave"},"name":"redis-slave"},"spec":{"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379}]}]}},"replicas":2},"kind":"ReplicationController","apiVersion":"v1"}'
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- Content-Length:
- - '420'
- User-Agent:
- - Ruby
- response:
- status:
- code: 201
- message: Created
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '842'
- body:
- encoding: UTF-8
- string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave","uid":"f42e1d09-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"567","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"replicas":2,"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: get
- uri: http://10.35.0.23:8080/api/v1/namespaces
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '629'
- body:
- encoding: UTF-8
- string: '{"kind":"NamespaceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces","resourceVersion":"570"},"items":[{"metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"37360c82-3e77-11e5-a75a-18037327aaeb","resourceVersion":"6","creationTimestamp":"2015-08-09T09:15:45Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"534","creationTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}]}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: get
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '1661'
- body:
- encoding: UTF-8
- string: '{"kind":"ServiceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces/kubeclient-ns/services","resourceVersion":"571"},"items":[{"metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/guestbook","uid":"f42187e1-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"538","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"name":"guestbook"}},"spec":{"ports":[{"protocol":"TCP","port":3000,"targetPort":"http-server","nodePort":0}],"selector":{"app":"guestbook"},"clusterIP":"10.0.0.80","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}},{"metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-master","uid":"f423bf8b-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"542","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"master"},"clusterIP":"10.0.0.140","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}},{"metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-slave","uid":"f4264678-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"545","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"slave"},"clusterIP":"10.0.0.154","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}]}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: get
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Transfer-Encoding:
- - chunked
- body:
- encoding: UTF-8
- string: '{"kind":"ReplicationControllerList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers","resourceVersion":"571"},"items":[{"metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook","uid":"f4287784-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"557","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"guestbook","role":"slave"}},"spec":{"replicas":3,"selector":{"app":"guestbook"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":3,"observedGeneration":1}},{"metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master","uid":"f42a9800-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"565","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"replicas":1,"selector":{"app":"redis","role":"master"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0,"observedGeneration":1}},{"metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave","uid":"f42e1d09-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"567","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"replicas":2,"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}]}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/guestbook
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '100'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Success",
- "code": 200
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-master
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '100'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Success",
- "code": 200
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-slave
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '100'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Success",
- "code": 200
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '100'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Success",
- "code": 200
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '100'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Success",
- "code": 200
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '100'
- body:
- encoding: UTF-8
- string: |-
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Success",
- "code": 200
- }
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: delete
- uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - '*/*; q=0.5, application/xml'
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - Ruby
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Sun, 09 Aug 2015 10:03:59 GMT
- Content-Length:
- - '345'
- body:
- encoding: UTF-8
- string: '{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"584","creationTimestamp":"2015-08-09T10:03:59Z","deletionTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Terminating"}}'
- http_version:
- recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
-- request:
- method: get
- uri: http://10.35.0.23:8080/api/v1
- body:
- encoding: US-ASCII
- string: ''
- headers:
- Accept:
- - "*/*"
- Accept-Encoding:
- - gzip, deflate
- User-Agent:
- - rest-client/2.0.0 (linux-gnu x86_64) ruby/2.3.0p0
- Host:
- - localhost:8080
- response:
- status:
- code: 200
- message: OK
- headers:
- Content-Type:
- - application/json
- Date:
- - Mon, 29 Aug 2016 15:51:30 GMT
- Transfer-Encoding:
- - chunked
- body:
- encoding: UTF-8
- string: '{"kind":"APIResourceList","groupVersion":"v1","resources":[{"name":"bindings","namespaced":true,"kind":"Binding"},{"name":"componentstatuses","namespaced":false,"kind":"ComponentStatus"},{"name":"configmaps","namespaced":true,"kind":"ConfigMap"},{"name":"endpoints","namespaced":true,"kind":"Endpoints"},{"name":"events","namespaced":true,"kind":"Event"},{"name":"limitranges","namespaced":true,"kind":"LimitRange"},{"name":"namespaces","namespaced":false,"kind":"Namespace"},{"name":"namespaces/finalize","namespaced":false,"kind":"Namespace"},{"name":"namespaces/status","namespaced":false,"kind":"Namespace"},{"name":"nodes","namespaced":false,"kind":"Node"},{"name":"nodes/proxy","namespaced":false,"kind":"Node"},{"name":"nodes/status","namespaced":false,"kind":"Node"},{"name":"persistentvolumeclaims","namespaced":true,"kind":"PersistentVolumeClaim"},{"name":"persistentvolumeclaims/status","namespaced":true,"kind":"PersistentVolumeClaim"},{"name":"persistentvolumes","namespaced":false,"kind":"PersistentVolume"},{"name":"persistentvolumes/status","namespaced":false,"kind":"PersistentVolume"},{"name":"pods","namespaced":true,"kind":"Pod"},{"name":"pods/attach","namespaced":true,"kind":"Pod"},{"name":"pods/binding","namespaced":true,"kind":"Binding"},{"name":"pods/exec","namespaced":true,"kind":"Pod"},{"name":"pods/log","namespaced":true,"kind":"Pod"},{"name":"pods/portforward","namespaced":true,"kind":"Pod"},{"name":"pods/proxy","namespaced":true,"kind":"Pod"},{"name":"pods/status","namespaced":true,"kind":"Pod"},{"name":"podtemplates","namespaced":true,"kind":"PodTemplate"},{"name":"replicationcontrollers","namespaced":true,"kind":"ReplicationController"},{"name":"replicationcontrollers/scale","namespaced":true,"kind":"Scale"},{"name":"replicationcontrollers/status","namespaced":true,"kind":"ReplicationController"},{"name":"resourcequotas","namespaced":true,"kind":"ResourceQuota"},{"name":"resourcequotas/status","namespaced":true,"kind":"ResourceQuota"},{"name":"secrets","namespaced":true,"kind":"Secret"},{"name":"serviceaccounts","namespaced":true,"kind":"ServiceAccount"},{"name":"services","namespaced":true,"kind":"Service"},{"name":"services/proxy","namespaced":true,"kind":"Service"},{"name":"services/status","namespaced":true,"kind":"Service"}]}
-
-'
- http_version:
- recorded_at: Mon, 29 Aug 2016 15:51:30 GMT
-recorded_with: VCR 3.0.3
diff --git a/vendor/gems/kubeclient/test/config/allinone.kubeconfig b/vendor/gems/kubeclient/test/config/allinone.kubeconfig
deleted file mode 100644
index f06db6af123..00000000000
--- a/vendor/gems/kubeclient/test/config/allinone.kubeconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-
-apiVersion: v1
-clusters:
-- cluster:
- server: https://localhost:6443
- certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvekNDQWVlZ0F3SUJBZ0lUUGJmcHkyOWFCRzY3Q2hSZEI2bEplZ1RrbURBTkJna3Foa2lHOXcwQkFRc0YKQURBWU1SWXdGQVlEVlFRREV3MXJkV0psY201bGRHVnpMV05oTUI0WERUSXlNREl5TVRBNU1ESXdNRm9YRFRNeQpNREl4T1RBNU1ESXdNRm93R0RFV01CUUdBMVVFQXhNTmEzVmlaWEp1WlhSbGN5MWpZVENDQVNJd0RRWUpLb1pJCmh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUxqWjJjRkJhbHpvaW1hRWNwVDlKejJKbWRnc0hNT2FnVmQKSXQ3T1FwVHdEWjNucElJQ1ZwZ3VFaDl4dG92UjhtOC9IWU0rL2E0dk1RSFQrM3A4SFBqaURhUllHZzdPWjlMKwpGcC85emhCdWlhSXZnOForQmJ5czlROVV1ajZWRXdmRkpCY05INlRtemRpRGdRVXM1L2srNi92dHVKNHlzM3NECktrQU94cVBYRGFCb0FObkxwSXhkSU1RRGNXU0xGQTB3bUZoZFpKcTNLRUFvSnBFTDBXWW8xWlJCVjNpSDc3eWYKc0RiTjFPQnUydk5uUlorRHJWMFpKNUFwbWJGWFBYOGk0S0phVzlsQ0I2MkZOMGo1WHNORG95VGVBVnBlc2ZOcwp6WXVmVnBCZHFOWkZrT0tnOWRpTXVUTWlrYTJhWWZEdWlWemRlYkRnY3A5YU1sb0t0YkVDQXdFQUFhTkNNRUF3CkRnWURWUjBQQVFIL0JBUURBZ0VHTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkJkT2l5Z0MKTGN1SnJxOHJOYTF4QURyNVNwN0NNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUURDeTRJbGhBU2g2QnI1WEVjSQpUcFA1VGhEMU95UnpRbnNQZTZQMXFnV1Aza0JYSy9BY3NTbCtWR3RhWnAyb0VoSm9VbnN6N2tFOHlXM2dLK1BBCjUxelk0YUhUaUY5eGt5ZDV6T0NBR0IrY2ZwOVlzK3N6V3p5dTBRUTlJQmpKNCtlRGpnN1cwL1MrQk0yUW4xaUwKalRGSWUyQmRmK1EvSjI0L3Eza3NUWEsxN1VOdW4xNHZEUnNKZ3NOY3JGdC9ydW1mSFB4MXl0d3NpcUt5RUtWNwprRnhTd2EzZDgvQXZoR2dGcFBtZlJqVTdnQUpDRmNIejUwMXpoaTJhNkw1VFlCVGVjVlJicVpvZUhpWjBZTldJCmlzNWc0Vm1WQitCeE1BTTJXRWQyOXY0bC8zb0kxUGV5OXJ2dDdOSnFTZTFpbTl1cVpnVkRlZy92UDh6S3MvZEYKWll3OAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
- name: local
-contexts:
-- context:
- cluster: local
- namespace: default
- user: user
- name: Default
-current-context: Default
-kind: Config
-preferences: {}
-users:
-- name: user
- user:
- client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURXVENDQWtHZ0F3SUJBZ0lVS08xZVJtWG1DYyt2dk0rTG9CeVpFMElNR0Q4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd0dERVdNQlFHQTFVRUF4TU5hM1ZpWlhKdVpYUmxjeTFqWVRBZUZ3MHlNakF5TWpFd09UQXlNREJhRncweQpNekF5TWpFd09UQXlNREJhTURReEZ6QVZCZ05WQkFvVERuTjVjM1JsYlRwdFlYTjBaWEp6TVJrd0Z3WURWUVFECkV4QnJkV0psY201bGRHVnpMV0ZrYldsdU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0MKQVFFQXdodzF6SmFBWVcwa0ljbjVtV3lYTm03SVlEYStRTXpIM0hWWnJnd1l5Y0NaWlA5MGJZSmo0VEYrKyszbgpQTVoydU1mWkVYY21OcEdYQ0lxek5ZSlF6dlQrYTF6Q011VVQ5K3YxZzM0My9WYVlweFJ6R3VlQ1ZGK3B2Qi9nCmpJMFU0bDFZbUpJRWs1WGNETTl4RStob1Vrd3FWYWhNbXJ2c3E4aHluWWp6V0V0bDBtSitUTzg5LzFaandBdVEKdDRvaE5PMXBRdTNyNEhDdTNIR2JGU1RQSjZFNG94UmdkTXFIbHFzd3BHMCtaTFJYVmtvZ1VidGxJVUx0Y3RvVQpUNjdmaHNUaFJDWXUyQUFpbitMMjBncjNUY3A0VXRNV3RUY1o2NnZsTDJFcDZUa1dpdXRiMDRML0JvNDZWZnhPCnNLQkNkTjFqeXNPZVRQZ1RXS2gwODh2TTB3SURBUUFCbzM4d2ZUQU9CZ05WSFE4QkFmOEVCQU1DQmFBd0hRWUQKVlIwbEJCWXdGQVlJS3dZQkJRVUhBd0VHQ0NzR0FRVUZCd01DTUF3R0ExVWRFd0VCL3dRQ01BQXdIUVlEVlIwTwpCQllFRko2NzV6N0dDSXVKY2JHeEo3YkxJM0pBTDNCZU1COEdBMVVkSXdRWU1CYUFGQmRPaXlnQ0xjdUpycThyCk5hMXhBRHI1U3A3Q01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ1hHQ2hlbytWVXhsRlJQRVhSU3B3NDgwbGIKMm12ZHpCNE8vck9JRzJIOXZ6Z2poeGJkQ0pOVmVka0d6bUhaNzVlRUh6djFFa0luZWJTR0xGejUvUDNCUVVYdwp4eXU4NGpOSmVyOVJlMmdlbVYwdDJtd3pIV0NmUUdMS0c0QUppN00rY3haNDlYaHVtWlJWa3c3aU9SRitxWU9qCmhTbG9CLzRrZnlxM1VhcHJLQ3ZocWpFc0tKcURuZHdsT3dLTFZNaWMzbFFETExYb0thNVRpdjZpaEJpQ1ZXQUkKWFV5NWwyZG9EdlpoemdFakxlUTBDR0hiNTl2Q3Zkb3RUYzBiN0hKNFp3MjFBTHoyQ0Y3eGt3WGpQNXVVSXE1Ngo2UG1RK2dwSFhrbGJOSklPRHRrZi85STRyTWxIVXplSzVEVllZNWtkeEpUemgybng0UjBpY0Z4MWpuYzAKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
- client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBd2h3MXpKYUFZVzBrSWNuNW1XeVhObTdJWURhK1FNekgzSFZacmd3WXljQ1paUDkwCmJZSmo0VEYrKyszblBNWjJ1TWZaRVhjbU5wR1hDSXF6TllKUXp2VCthMXpDTXVVVDkrdjFnMzQzL1ZhWXB4UnoKR3VlQ1ZGK3B2Qi9nakkwVTRsMVltSklFazVYY0RNOXhFK2hvVWt3cVZhaE1tcnZzcThoeW5ZanpXRXRsMG1KKwpUTzg5LzFaandBdVF0NG9oTk8xcFF1M3I0SEN1M0hHYkZTVFBKNkU0b3hSZ2RNcUhscXN3cEcwK1pMUlhWa29nClVidGxJVUx0Y3RvVVQ2N2Zoc1RoUkNZdTJBQWluK0wyMGdyM1RjcDRVdE1XdFRjWjY2dmxMMkVwNlRrV2l1dGIKMDRML0JvNDZWZnhPc0tCQ2ROMWp5c09lVFBnVFdLaDA4OHZNMHdJREFRQUJBb0lCQVFEQlhHQ3JRSEQ2bkVJVgo5cURSR0w4NDFmcDgvWXRmK1o1T0dnZ1B2TFVrcE5zcEpOL1NCc1dBR2xJb204QnhaakgxdC82ZnkxVWhucjRaCklER002QmVmVWFYdlJTT2VsMXZnNkFoVnlISDF4MEdoamxsclA1c3dlV3NYbjVtTDZTNFlvR3dVNzcvblZLMHoKaGFGYTkzU1VKcE0xYU1XR2poVWd1amlTZlU0TGNMRFJWS0RFUk80OFhQOEZpQ0E2UEIySUpYUDBTOUJhTVZLUQpIQVJDV05HWDV6aU5hbzFyb0l2UFFORU1EVHRuV2JiNHo0U3ZSbXBjRjYwRS9mNEpwMDZTSDAwUU5lVHY3bjU3CkR6U1hZZGNxbGZMUjlRU1RkVmt0U094UThjSGFsVGN5NXNVMnh5RndjMVM5YVpaOG56UnBiRnUxVllGQ0lWY2YKRTRRVnYxVUJBb0dCQU1XZzRuWlRIaUd0aGY2S3l6T0draDFyMmtCU21WeTlCY1lqQjhUYnpRYnJOVXk3WUFsVAppN2VPbkYrdVRLY2FWYzV2blVyVjBsN3pEM1dTV3UxQVJiOUs2WnBWTDV3allObW0venVyUittSmM4TEtsN2Q2CjU0ejFjMTExVDVpaXZNMWJZUm5VME91akhEb1g1WkQ1V0dzeE1LYUh0TGFHV1gvZ0s0OWhQYmZ6QW9HQkFQdHgKVFdRSGlPcS91VnNrMFFuWWtLWkV3ZXpmZEMyZGFWSm9BeURBVjVnY1U0TnNONjJVS2ZnVHJhRCtDaG15SjVSNwpqT1NMOGJVWDMzUVFFdm1LOVdZWE1WQnd6MjhIclp5cHVCeVFFRWM4ZTl5eTRZUStSWVoxTDJrbUdkYWVaOE16CmlEZmZMclhieTdOWnA0eGNmTVpXWW1Md2RHRVNZbzhqenVjaTFLK2hBb0dCQUpESXprQmJvbTZQM3VQZHNRTGQKcXZ4TkFJY3hQRlA1MDFvV1hlRzJHaDNnZ1pybWgzUXR0ZVZUWUhLa2tsbTE3SGtod2oyS0t1WU84aHR6anBQVQpDNFVhajh2V2J0dlgrMk5aZWhHdjZTNUoyZm95VERaS240cmdZNVZybFZYQW04dGpEOTlKejRsaVpSS1dZVVAxCnVQWkhBbHB1ZjFGZFdnSmFLKytPRVJaTEFvR0FLSmQ5K3V3TWVubEJIeW11Wlh5RXZaTFVDNzEzTC9YOWpzUWoKM1NHd0FtcHdRUU16YWQ1RmVEc1ZDS3g2VFBPcDJCcXFBQ3RuZGVqSXRoL3lNRDd5cHV5UGxZRGd1L2Z0V3lFNwpDOEZtSDFud1ZReTd3M0dhSDc3RFRLSk9BWXZKRElaQk0yUGdVcE9OS3dNS1BXcWc2aFFBQmlEemFNaGpDT0NyCkFqMXBRSUVDZ1lFQWw2THZncFl6enlUVThtRmFYazUrQXVaVHB1dlZzNXNOVEUwQmdyUWJBN0haL0hjT3hLaWQKYkxPU1diVzNaZ05aV0xXOFNhdWlURCt4L2lmVGR6UUJHQnZOaGFJaklGNnltdFlwTzNaWCs2MG15L1hUZmJGUQordUJ3UDducU1JUnNuQjUzRlc0S3VWcWljMDVEbGdvRWJ5NWM1eTlPQjlyWUQzUnJTT01EbGFzPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
diff --git a/vendor/gems/kubeclient/test/config/another-ca1.pem b/vendor/gems/kubeclient/test/config/another-ca1.pem
deleted file mode 100644
index 50825d47519..00000000000
--- a/vendor/gems/kubeclient/test/config/another-ca1.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDADCCAeigAwIBAgIUQZjM/5qoAF78qIDyc+rKi4qBdOIwDQYJKoZIhvcNAQEL
-BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAzMjIxNDQzMDBaFw0z
-MjAzMTkxNDQzMDBaMBgxFjAUBgNVBAMTDWt1YmVybmV0ZXMtY2EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGkG7g+UjpDhZ7A4Pm7Hme+RWs5IHz4I2X
-IclvtO3LuJ26yzz2S8VaXFFeUqzEPb2G1RxFGvoAVN7qrTw0n5MQJCFLAA4dI7oY
-8XLRJ7KgTBBIw1jYpgKb2zyHPIJE6VmslliKUiX+QDovdRU/dsbdup2EucrnGw4+
-QNNAc3XMbXgm6lubA6znYZlSpcQ8BKer3tq75q4KUZicIjS6gKQyZjk9a6fcOuCS
-ybtlAKp9lYzcwxZkNrx+V1PJMQ1qaJWPnMAVi7Oj5Dm3Jmf1WHBcNEh52Q/0vYlt
-4WSaeM5t/Py/m/7c4Ve97f5m2X6EhYyUbzov4qeZOnIJI3MnU1FxAgMBAAGjQjBA
-MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSl1qyt
-jd96WstRE8h9x5qkCvZUvjANBgkqhkiG9w0BAQsFAAOCAQEAJt55qYvBaniAwvgO
-tbO79g1FcQGrxpMX45TuoCE/K+MWDjrr6bp+FbLOqT8MwOsbGwwJIRTHGvkEkVso
-5AWI5aSNs3hWnltOdz27ZSHeX77WB4daK1tLK6ggZrp3v9iIpbBwWBFdmAqsPvEs
-H17K2BgAzdh6xRKPQd0BGTUpJBfk50R2gDMj7FKyIzBN69IOGytBfAXBhHzEGy4+
-MvtTEIMUjR//KgCrpNeyDuaWHttR5FdnuRxFO7O3BAfyNSaNmd/IEHQf7DIGgzOy
-+xWLyH/HRHj5C70qAqjbnrgBODI99BsA9U7oXTuyPLdIboAcFt2zD5DIYgZET52X
-53w4jA==
------END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/another-ca2.pem b/vendor/gems/kubeclient/test/config/another-ca2.pem
deleted file mode 100644
index 53be72e87d7..00000000000
--- a/vendor/gems/kubeclient/test/config/another-ca2.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDADCCAeigAwIBAgIUHW3OPnmuTquJ0YgbGpmm/blsY2QwDQYJKoZIhvcNAQEL
-BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAzMjIxNDQ0MDBaFw0z
-MjAzMTkxNDQ0MDBaMBgxFjAUBgNVBAMTDWt1YmVybmV0ZXMtY2EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLMEJs5agS0hNQBxPTtsI6dIhIi/pY8liI
-sNukbi5KwKf80FYNyRXqE8ufDVyTFzOc+MG96jnHjDaBWjrVN9On0PgUBo4nPyd4
-DtyvYx2jMzwToSEIo/Z1aroMx1oGywCgdS4/3FWAbhlSbyXKJmhfh6gX0TxWz+dV
-zqNuqQq9EWuRhOMg9vgzjfp3mjiPE10lW8pT0j5JT3PI/eGO+C2Z7z33LJXb6GM2
-nXvhGFMGY+7XG65pqJ3L8g1mk+LjPiwyIItw8wPtrnrZ2VXMklMd5Mn+jgCTNe1B
-om0nPpPIiTblCr6gcNcVjy5WGN37OKlqrT0JTuSPHcxSUp05LFjDAgMBAAGjQjBA
-MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQvV/sB
-wbR3UwjkLAMN+6P3fZ/3OjANBgkqhkiG9w0BAQsFAAOCAQEACAk4EQwCkw2EBsSR
-2SKoa1SjYFkZzIr/0/TB2YcMUvHF+RpvlD5vQ8/RJjeAl1kc6/niZ9TWCemjBLqI
-hPoFe49zr49DyQjC2ZfsXVJvFCr6g7o4q4DtQ6ltyBuTJbkn1hI+aB8zgvpofG44
-mKj18Y7tPvgXtRua4SaeBq777+22AOvKxPied9p4PTrMN4RKTP6+yIbLflej7dBD
-zQDjfmmYsH0T2ZRtBpE1dYrUbU3tkizcMZRJBgreoxoff+r5coibMIm/7gh+YoSb
-BCItCaeuGSKQ8CJb8DElcPUd6nKUjmeiQL68ztsG/+CXLiL/TZb914VaaCXvPInw
-49jJ7w==
------END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/concatenated-ca.kubeconfig b/vendor/gems/kubeclient/test/config/concatenated-ca.kubeconfig
deleted file mode 100644
index ed20e4dde50..00000000000
--- a/vendor/gems/kubeclient/test/config/concatenated-ca.kubeconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- certificate-authority: concatenated-ca.pem
- server: https://localhost:6443
- name: local
-contexts:
-- context:
- cluster: local
- namespace: default
- user: user
- name: Default
-current-context: Default
-kind: Config
-preferences: {}
-users:
-- name: user
- user:
- client-certificate: external-cert.pem
- client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/concatenated-ca.pem b/vendor/gems/kubeclient/test/config/concatenated-ca.pem
deleted file mode 100644
index 1117298ff2d..00000000000
--- a/vendor/gems/kubeclient/test/config/concatenated-ca.pem
+++ /dev/null
@@ -1,57 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDADCCAeigAwIBAgIUQZjM/5qoAF78qIDyc+rKi4qBdOIwDQYJKoZIhvcNAQEL
-BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAzMjIxNDQzMDBaFw0z
-MjAzMTkxNDQzMDBaMBgxFjAUBgNVBAMTDWt1YmVybmV0ZXMtY2EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGkG7g+UjpDhZ7A4Pm7Hme+RWs5IHz4I2X
-IclvtO3LuJ26yzz2S8VaXFFeUqzEPb2G1RxFGvoAVN7qrTw0n5MQJCFLAA4dI7oY
-8XLRJ7KgTBBIw1jYpgKb2zyHPIJE6VmslliKUiX+QDovdRU/dsbdup2EucrnGw4+
-QNNAc3XMbXgm6lubA6znYZlSpcQ8BKer3tq75q4KUZicIjS6gKQyZjk9a6fcOuCS
-ybtlAKp9lYzcwxZkNrx+V1PJMQ1qaJWPnMAVi7Oj5Dm3Jmf1WHBcNEh52Q/0vYlt
-4WSaeM5t/Py/m/7c4Ve97f5m2X6EhYyUbzov4qeZOnIJI3MnU1FxAgMBAAGjQjBA
-MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSl1qyt
-jd96WstRE8h9x5qkCvZUvjANBgkqhkiG9w0BAQsFAAOCAQEAJt55qYvBaniAwvgO
-tbO79g1FcQGrxpMX45TuoCE/K+MWDjrr6bp+FbLOqT8MwOsbGwwJIRTHGvkEkVso
-5AWI5aSNs3hWnltOdz27ZSHeX77WB4daK1tLK6ggZrp3v9iIpbBwWBFdmAqsPvEs
-H17K2BgAzdh6xRKPQd0BGTUpJBfk50R2gDMj7FKyIzBN69IOGytBfAXBhHzEGy4+
-MvtTEIMUjR//KgCrpNeyDuaWHttR5FdnuRxFO7O3BAfyNSaNmd/IEHQf7DIGgzOy
-+xWLyH/HRHj5C70qAqjbnrgBODI99BsA9U7oXTuyPLdIboAcFt2zD5DIYgZET52X
-53w4jA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIC/zCCAeegAwIBAgITPbfpy29aBG67ChRdB6lJegTkmDANBgkqhkiG9w0BAQsF
-ADAYMRYwFAYDVQQDEw1rdWJlcm5ldGVzLWNhMB4XDTIyMDIyMTA5MDIwMFoXDTMy
-MDIxOTA5MDIwMFowGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAMLjZ2cFBalzoimaEcpT9Jz2JmdgsHMOagVd
-It7OQpTwDZ3npIICVpguEh9xtovR8m8/HYM+/a4vMQHT+3p8HPjiDaRYGg7OZ9L+
-Fp/9zhBuiaIvg8Z+Bbys9Q9Uuj6VEwfFJBcNH6TmzdiDgQUs5/k+6/vtuJ4ys3sD
-KkAOxqPXDaBoANnLpIxdIMQDcWSLFA0wmFhdZJq3KEAoJpEL0WYo1ZRBV3iH77yf
-sDbN1OBu2vNnRZ+DrV0ZJ5ApmbFXPX8i4KJaW9lCB62FN0j5XsNDoyTeAVpesfNs
-zYufVpBdqNZFkOKg9diMuTMika2aYfDuiVzdebDgcp9aMloKtbECAwEAAaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBdOiygC
-LcuJrq8rNa1xADr5Sp7CMA0GCSqGSIb3DQEBCwUAA4IBAQDCy4IlhASh6Br5XEcI
-TpP5ThD1OyRzQnsPe6P1qgWP3kBXK/AcsSl+VGtaZp2oEhJoUnsz7kE8yW3gK+PA
-51zY4aHTiF9xkyd5zOCAGB+cfp9Ys+szWzyu0QQ9IBjJ4+eDjg7W0/S+BM2Qn1iL
-jTFIe2Bdf+Q/J24/q3ksTXK17UNun14vDRsJgsNcrFt/rumfHPx1ytwsiqKyEKV7
-kFxSwa3d8/AvhGgFpPmfRjU7gAJCFcHz501zhi2a6L5TYBTecVRbqZoeHiZ0YNWI
-is5g4VmVB+BxMAM2WEd29v4l/3oI1Pey9rvt7NJqSe1im9uqZgVDeg/vP8zKs/dF
-ZYw8
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDADCCAeigAwIBAgIUHW3OPnmuTquJ0YgbGpmm/blsY2QwDQYJKoZIhvcNAQEL
-BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAzMjIxNDQ0MDBaFw0z
-MjAzMTkxNDQ0MDBaMBgxFjAUBgNVBAMTDWt1YmVybmV0ZXMtY2EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLMEJs5agS0hNQBxPTtsI6dIhIi/pY8liI
-sNukbi5KwKf80FYNyRXqE8ufDVyTFzOc+MG96jnHjDaBWjrVN9On0PgUBo4nPyd4
-DtyvYx2jMzwToSEIo/Z1aroMx1oGywCgdS4/3FWAbhlSbyXKJmhfh6gX0TxWz+dV
-zqNuqQq9EWuRhOMg9vgzjfp3mjiPE10lW8pT0j5JT3PI/eGO+C2Z7z33LJXb6GM2
-nXvhGFMGY+7XG65pqJ3L8g1mk+LjPiwyIItw8wPtrnrZ2VXMklMd5Mn+jgCTNe1B
-om0nPpPIiTblCr6gcNcVjy5WGN37OKlqrT0JTuSPHcxSUp05LFjDAgMBAAGjQjBA
-MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQvV/sB
-wbR3UwjkLAMN+6P3fZ/3OjANBgkqhkiG9w0BAQsFAAOCAQEACAk4EQwCkw2EBsSR
-2SKoa1SjYFkZzIr/0/TB2YcMUvHF+RpvlD5vQ8/RJjeAl1kc6/niZ9TWCemjBLqI
-hPoFe49zr49DyQjC2ZfsXVJvFCr6g7o4q4DtQ6ltyBuTJbkn1hI+aB8zgvpofG44
-mKj18Y7tPvgXtRua4SaeBq777+22AOvKxPied9p4PTrMN4RKTP6+yIbLflej7dBD
-zQDjfmmYsH0T2ZRtBpE1dYrUbU3tkizcMZRJBgreoxoff+r5coibMIm/7gh+YoSb
-BCItCaeuGSKQ8CJb8DElcPUd6nKUjmeiQL68ztsG/+CXLiL/TZb914VaaCXvPInw
-49jJ7w==
------END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/execauth.kubeconfig b/vendor/gems/kubeclient/test/config/execauth.kubeconfig
deleted file mode 100644
index c9a9773fe5e..00000000000
--- a/vendor/gems/kubeclient/test/config/execauth.kubeconfig
+++ /dev/null
@@ -1,61 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- server: https://localhost:6443
- name: localhost:6443
-contexts:
-- context:
- cluster: localhost:6443
- namespace: default
- user: system:admin:exec-search-path
- name: localhost/system:admin:exec-search-path
-- context:
- cluster: localhost:6443
- namespace: default
- user: system:admin:exec-relative-path
- name: localhost/system:admin:exec-relative-path
-- context:
- cluster: localhost:6443
- namespace: default
- user: system:admin:exec-absolute-path
- name: localhost/system:admin:exec-absolute-path
-kind: Config
-preferences: {}
-users:
-- name: system:admin:exec-search-path
- user:
- exec:
- # Command to execute. Required.
- command: "example-exec-plugin"
-
- # API version to use when decoding the ExecCredentials resource. Required.
- #
- # The API version returned by the plugin MUST match the version listed here.
- #
- # To integrate with tools that support multiple versions (such as client.authentication.k8s.io/v1alpha1),
- # set an environment variable or pass an argument to the tool that indicates which version the exec plugin expects.
- apiVersion: "client.authentication.k8s.io/v1beta1"
-
- # Environment variables to set when executing the plugin. Optional.
- env:
- - name: "FOO"
- value: "bar"
-
- # Arguments to pass when executing the plugin. Optional.
- args:
- - "arg1"
- - "arg2"
-
-- name: system:admin:exec-relative-path
- user:
- exec:
- # Command to execute. Required.
- command: "dir/example-exec-plugin"
- apiVersion: "client.authentication.k8s.io/v1beta1"
-
-- name: system:admin:exec-absolute-path
- user:
- exec:
- # Command to execute. Required.
- command: "/abs/path/example-exec-plugin"
- apiVersion: "client.authentication.k8s.io/v1beta1"
diff --git a/vendor/gems/kubeclient/test/config/external-ca.pem b/vendor/gems/kubeclient/test/config/external-ca.pem
deleted file mode 100644
index f1c8a8b615d..00000000000
--- a/vendor/gems/kubeclient/test/config/external-ca.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIC/zCCAeegAwIBAgITPbfpy29aBG67ChRdB6lJegTkmDANBgkqhkiG9w0BAQsF
-ADAYMRYwFAYDVQQDEw1rdWJlcm5ldGVzLWNhMB4XDTIyMDIyMTA5MDIwMFoXDTMy
-MDIxOTA5MDIwMFowGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAMLjZ2cFBalzoimaEcpT9Jz2JmdgsHMOagVd
-It7OQpTwDZ3npIICVpguEh9xtovR8m8/HYM+/a4vMQHT+3p8HPjiDaRYGg7OZ9L+
-Fp/9zhBuiaIvg8Z+Bbys9Q9Uuj6VEwfFJBcNH6TmzdiDgQUs5/k+6/vtuJ4ys3sD
-KkAOxqPXDaBoANnLpIxdIMQDcWSLFA0wmFhdZJq3KEAoJpEL0WYo1ZRBV3iH77yf
-sDbN1OBu2vNnRZ+DrV0ZJ5ApmbFXPX8i4KJaW9lCB62FN0j5XsNDoyTeAVpesfNs
-zYufVpBdqNZFkOKg9diMuTMika2aYfDuiVzdebDgcp9aMloKtbECAwEAAaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBdOiygC
-LcuJrq8rNa1xADr5Sp7CMA0GCSqGSIb3DQEBCwUAA4IBAQDCy4IlhASh6Br5XEcI
-TpP5ThD1OyRzQnsPe6P1qgWP3kBXK/AcsSl+VGtaZp2oEhJoUnsz7kE8yW3gK+PA
-51zY4aHTiF9xkyd5zOCAGB+cfp9Ys+szWzyu0QQ9IBjJ4+eDjg7W0/S+BM2Qn1iL
-jTFIe2Bdf+Q/J24/q3ksTXK17UNun14vDRsJgsNcrFt/rumfHPx1ytwsiqKyEKV7
-kFxSwa3d8/AvhGgFpPmfRjU7gAJCFcHz501zhi2a6L5TYBTecVRbqZoeHiZ0YNWI
-is5g4VmVB+BxMAM2WEd29v4l/3oI1Pey9rvt7NJqSe1im9uqZgVDeg/vP8zKs/dF
-ZYw8
------END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/external-cert.pem b/vendor/gems/kubeclient/test/config/external-cert.pem
deleted file mode 100644
index 6c8b5232d7a..00000000000
--- a/vendor/gems/kubeclient/test/config/external-cert.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDWTCCAkGgAwIBAgIUKO1eRmXmCc+vvM+LoByZE0IMGD8wDQYJKoZIhvcNAQEL
-BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAyMjEwOTAyMDBaFw0y
-MzAyMjEwOTAyMDBaMDQxFzAVBgNVBAoTDnN5c3RlbTptYXN0ZXJzMRkwFwYDVQQD
-ExBrdWJlcm5ldGVzLWFkbWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAwhw1zJaAYW0kIcn5mWyXNm7IYDa+QMzH3HVZrgwYycCZZP90bYJj4TF+++3n
-PMZ2uMfZEXcmNpGXCIqzNYJQzvT+a1zCMuUT9+v1g343/VaYpxRzGueCVF+pvB/g
-jI0U4l1YmJIEk5XcDM9xE+hoUkwqVahMmrvsq8hynYjzWEtl0mJ+TO89/1ZjwAuQ
-t4ohNO1pQu3r4HCu3HGbFSTPJ6E4oxRgdMqHlqswpG0+ZLRXVkogUbtlIULtctoU
-T67fhsThRCYu2AAin+L20gr3Tcp4UtMWtTcZ66vlL2Ep6TkWiutb04L/Bo46VfxO
-sKBCdN1jysOeTPgTWKh088vM0wIDAQABo38wfTAOBgNVHQ8BAf8EBAMCBaAwHQYD
-VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0O
-BBYEFJ675z7GCIuJcbGxJ7bLI3JAL3BeMB8GA1UdIwQYMBaAFBdOiygCLcuJrq8r
-Na1xADr5Sp7CMA0GCSqGSIb3DQEBCwUAA4IBAQCXGCheo+VUxlFRPEXRSpw480lb
-2mvdzB4O/rOIG2H9vzgjhxbdCJNVedkGzmHZ75eEHzv1EkInebSGLFz5/P3BQUXw
-xyu84jNJer9Re2gemV0t2mwzHWCfQGLKG4AJi7M+cxZ49XhumZRVkw7iORF+qYOj
-hSloB/4kfyq3UaprKCvhqjEsKJqDndwlOwKLVMic3lQDLLXoKa5Tiv6ihBiCVWAI
-XUy5l2doDvZhzgEjLeQ0CGHb59vCvdotTc0b7HJ4Zw21ALz2CF7xkwXjP5uUIq56
-6PmQ+gpHXklbNJIODtkf/9I4rMlHUzeK5DVYY5kdxJTzh2nx4R0icFx1jnc0
------END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/external-key.rsa b/vendor/gems/kubeclient/test/config/external-key.rsa
deleted file mode 100644
index c79c1f2c310..00000000000
--- a/vendor/gems/kubeclient/test/config/external-key.rsa
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpQIBAAKCAQEAwhw1zJaAYW0kIcn5mWyXNm7IYDa+QMzH3HVZrgwYycCZZP90
-bYJj4TF+++3nPMZ2uMfZEXcmNpGXCIqzNYJQzvT+a1zCMuUT9+v1g343/VaYpxRz
-GueCVF+pvB/gjI0U4l1YmJIEk5XcDM9xE+hoUkwqVahMmrvsq8hynYjzWEtl0mJ+
-TO89/1ZjwAuQt4ohNO1pQu3r4HCu3HGbFSTPJ6E4oxRgdMqHlqswpG0+ZLRXVkog
-UbtlIULtctoUT67fhsThRCYu2AAin+L20gr3Tcp4UtMWtTcZ66vlL2Ep6TkWiutb
-04L/Bo46VfxOsKBCdN1jysOeTPgTWKh088vM0wIDAQABAoIBAQDBXGCrQHD6nEIV
-9qDRGL841fp8/Ytf+Z5OGggPvLUkpNspJN/SBsWAGlIom8BxZjH1t/6fy1Uhnr4Z
-IDGM6BefUaXvRSOel1vg6AhVyHH1x0GhjllrP5sweWsXn5mL6S4YoGwU77/nVK0z
-haFa93SUJpM1aMWGjhUgujiSfU4LcLDRVKDERO48XP8FiCA6PB2IJXP0S9BaMVKQ
-HARCWNGX5ziNao1roIvPQNEMDTtnWbb4z4SvRmpcF60E/f4Jp06SH00QNeTv7n57
-DzSXYdcqlfLR9QSTdVktSOxQ8cHalTcy5sU2xyFwc1S9aZZ8nzRpbFu1VYFCIVcf
-E4QVv1UBAoGBAMWg4nZTHiGthf6KyzOGkh1r2kBSmVy9BcYjB8TbzQbrNUy7YAlT
-i7eOnF+uTKcaVc5vnUrV0l7zD3WSWu1ARb9K6ZpVL5wjYNmm/zurR+mJc8LKl7d6
-54z1c111T5iivM1bYRnU0OujHDoX5ZD5WGsxMKaHtLaGWX/gK49hPbfzAoGBAPtx
-TWQHiOq/uVsk0QnYkKZEwezfdC2daVJoAyDAV5gcU4NsN62UKfgTraD+ChmyJ5R7
-jOSL8bUX33QQEvmK9WYXMVBwz28HrZypuByQEEc8e9yy4YQ+RYZ1L2kmGdaeZ8Mz
-iDffLrXby7NZp4xcfMZWYmLwdGESYo8jzuci1K+hAoGBAJDIzkBbom6P3uPdsQLd
-qvxNAIcxPFP501oWXeG2Gh3ggZrmh3QtteVTYHKkklm17Hkhwj2KKuYO8htzjpPU
-C4Uaj8vWbtvX+2NZehGv6S5J2foyTDZKn4rgY5VrlVXAm8tjD99Jz4liZRKWYUP1
-uPZHAlpuf1FdWgJaK++OERZLAoGAKJd9+uwMenlBHymuZXyEvZLUC713L/X9jsQj
-3SGwAmpwQQMzad5FeDsVCKx6TPOp2BqqACtndejIth/yMD7ypuyPlYDgu/ftWyE7
-C8FmH1nwVQy7w3GaH77DTKJOAYvJDIZBM2PgUpONKwMKPWqg6hQABiDzaMhjCOCr
-Aj1pQIECgYEAl6LvgpYzzyTU8mFaXk5+AuZTpuvVs5sNTE0BgrQbA7HZ/HcOxKid
-bLOSWbW3ZgNZWLW8SauiTD+x/ifTdzQBGBvNhaIjIF6ymtYpO3ZX+60my/XTfbFQ
-+uBwP7nqMIRsnB53FW4KuVqic05DlgoEby5c5y9OB9rYD3RrSOMDlas=
------END RSA PRIVATE KEY-----
diff --git a/vendor/gems/kubeclient/test/config/external-without-ca.kubeconfig b/vendor/gems/kubeclient/test/config/external-without-ca.kubeconfig
deleted file mode 100644
index 1f3d617a40d..00000000000
--- a/vendor/gems/kubeclient/test/config/external-without-ca.kubeconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- # Not defining custom `certificate-authority`.
- # Without it, the localhost cert should be rejected.
- server: https://localhost:6443
- name: local
-contexts:
-- context:
- cluster: local
- namespace: default
- user: user
- name: Default
-current-context: Default
-kind: Config
-preferences: {}
-users:
-- name: user
- user:
- client-certificate: external-cert.pem
- client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/external.kubeconfig b/vendor/gems/kubeclient/test/config/external.kubeconfig
deleted file mode 100644
index ef2dca61348..00000000000
--- a/vendor/gems/kubeclient/test/config/external.kubeconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- certificate-authority: external-ca.pem
- server: https://localhost:6443
- name: local
-contexts:
-- context:
- cluster: local
- namespace: default
- user: user
- name: Default
-current-context: Default
-kind: Config
-preferences: {}
-users:
-- name: user
- user:
- client-certificate: external-cert.pem
- client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/gcpauth.kubeconfig b/vendor/gems/kubeclient/test/config/gcpauth.kubeconfig
deleted file mode 100644
index 0ee387ebb16..00000000000
--- a/vendor/gems/kubeclient/test/config/gcpauth.kubeconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- server: https://localhost:8443
- name: localhost:8443
-contexts:
-- context:
- cluster: localhost:8443
- namespace: default
- user: application-default-credentials
- name: localhost/application-default-credentials
-kind: Config
-preferences: {}
-users:
-- name: application-default-credentials
- user:
- auth-provider:
- config:
- access-token: <fake_token>
- expiry: 2019-02-19T11:07:29.827352-05:00
- name: gcp
diff --git a/vendor/gems/kubeclient/test/config/gcpcmdauth.kubeconfig b/vendor/gems/kubeclient/test/config/gcpcmdauth.kubeconfig
deleted file mode 100644
index 2e2db395834..00000000000
--- a/vendor/gems/kubeclient/test/config/gcpcmdauth.kubeconfig
+++ /dev/null
@@ -1,25 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- server: https://localhost:8443
- name: localhost:8443
-contexts:
-- context:
- cluster: localhost:8443
- namespace: default
- user: application-default-credentials
- name: localhost/application-default-credentials
-kind: Config
-preferences: {}
-users:
-- name: application-default-credentials
- user:
- auth-provider:
- config:
- access-token: <fake_token>
- cmd-args: config config-helper --format=json
- cmd-path: /path/to/gcloud
- expiry: 2019-04-09T19:26:18Z
- expiry-key: '{.credential.token_expiry}'
- token-key: '{.credential.access_token}'
- name: gcp
diff --git a/vendor/gems/kubeclient/test/config/insecure-custom-ca.kubeconfig b/vendor/gems/kubeclient/test/config/insecure-custom-ca.kubeconfig
deleted file mode 100644
index 06c803c16bf..00000000000
--- a/vendor/gems/kubeclient/test/config/insecure-custom-ca.kubeconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- # This is a silly configuration, skip-tls-verify makes CA data useless, but testing for completeness.
- certificate-authority: external-ca.pem
- server: https://localhost:6443
- insecure-skip-tls-verify: true
- name: local
-contexts:
-- context:
- cluster: local
- namespace: default
- user: user
- name: Default
-current-context: Default
-kind: Config
-preferences: {}
-users:
-- name: user
- user:
- client-certificate: external-cert.pem
- client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/insecure.kubeconfig b/vendor/gems/kubeclient/test/config/insecure.kubeconfig
deleted file mode 100644
index d7c28087a92..00000000000
--- a/vendor/gems/kubeclient/test/config/insecure.kubeconfig
+++ /dev/null
@@ -1,25 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- server: https://localhost:6443
- insecure-skip-tls-verify: true
- name: local
-contexts:
-- context:
- cluster: local
- namespace: default
- user: user
- name: Default
-current-context: Default
-kind: Config
-preferences: {}
-users:
-- name: user
- user:
- # Providing ANY credentials in `insecure-skip-tls-verify` mode is unwise due to MITM risk.
- # At least client certs are not as catastrophic as bearer tokens.
- #
- # This combination of insecure + client certs was once broken in kubernetes but
- # is meaningful since 2015 (https://github.com/kubernetes/kubernetes/pull/15430).
- client-certificate: external-cert.pem
- client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/nouser.kubeconfig b/vendor/gems/kubeclient/test/config/nouser.kubeconfig
deleted file mode 100644
index 9289895cc81..00000000000
--- a/vendor/gems/kubeclient/test/config/nouser.kubeconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- server: https://localhost:6443
- name: localhost:6443
-contexts:
-- context:
- cluster: localhost:6443
- namespace: default
- user: ""
- name: default/localhost:6443/nouser
-current-context: default/localhost:6443/nouser
-kind: Config
-preferences: {}
-users: []
diff --git a/vendor/gems/kubeclient/test/config/oidcauth.kubeconfig b/vendor/gems/kubeclient/test/config/oidcauth.kubeconfig
deleted file mode 100644
index e1f389da46f..00000000000
--- a/vendor/gems/kubeclient/test/config/oidcauth.kubeconfig
+++ /dev/null
@@ -1,24 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- server: https://localhost:8443
- name: localhost:8443
-contexts:
-- context:
- cluster: localhost:8443
- namespace: default
- user: oidc-auth-provider
- name: localhost/oidc-auth-provider
-kind: Config
-preferences: {}
-users:
-- name: oidc-auth-provider
- user:
- auth-provider:
- config:
- client-id: fake-client-id
- client-secret: fake-client-secret
- id-token: fake-id-token
- idp-issuer-url: https://accounts.google.com
- refresh-token: fake-refresh-token
- name: oidc
diff --git a/vendor/gems/kubeclient/test/config/secure-without-ca.kubeconfig b/vendor/gems/kubeclient/test/config/secure-without-ca.kubeconfig
deleted file mode 100644
index 1b1acefe905..00000000000
--- a/vendor/gems/kubeclient/test/config/secure-without-ca.kubeconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- # Not defining custom `certificate-authority`.
- # Without it, the localhost cert should be rejected.
- server: https://localhost:6443
- insecure-skip-tls-verify: false # Same as external-without-ca.kubeconfig but with explicit false here.
- name: local
-contexts:
-- context:
- cluster: local
- namespace: default
- user: user
- name: Default
-current-context: Default
-kind: Config
-preferences: {}
-users:
-- name: user
- user:
- client-certificate: external-cert.pem
- client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/secure.kubeconfig b/vendor/gems/kubeclient/test/config/secure.kubeconfig
deleted file mode 100644
index b0a00bb8d0d..00000000000
--- a/vendor/gems/kubeclient/test/config/secure.kubeconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- certificate-authority: external-ca.pem
- server: https://localhost:6443
- insecure-skip-tls-verify: false # Same as external.kubeconfig but with explicit false here.
- name: local
-contexts:
-- context:
- cluster: local
- namespace: default
- user: user
- name: Default
-current-context: Default
-kind: Config
-preferences: {}
-users:
-- name: user
- user:
- client-certificate: external-cert.pem
- client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/timestamps.kubeconfig b/vendor/gems/kubeclient/test/config/timestamps.kubeconfig
deleted file mode 100644
index 7b718da21e9..00000000000
--- a/vendor/gems/kubeclient/test/config/timestamps.kubeconfig
+++ /dev/null
@@ -1,25 +0,0 @@
-apiVersion: v1
-users:
-- name: gke_username
- user:
- auth-provider:
- config:
- access-token: REDACTED
- cmd-args: config config-helper --format=json
- cmd-path: /Users/tannerbruce/opt/google-cloud-sdk/bin/gcloud
- expiry: 2018-07-07T18:25:36Z
- expiry-key: '{.credential.token_expiry}'
- token-key: '{.credential.access_token}'
- name: gcp
-
-# More syntaxes from go-yaml tests, hopefully covering all types possible in kubeconfig
-IPv4: 1.2.3.4
-Duration: 3s
-date_only: 2015-01-01
-rfc3339: 2015-02-24T18:19:39Z
-longer: 2015-02-24T18:19:39.123456789-03:00
-shorter: 2015-2-3T3:4:5Z
-iso_lower_t: 2015-02-24t18:19:39Z
-space_no_tz: 2015-02-24 18:19:39
-space_tz: 2001-12-14 21:59:43.10 -5
-timestamp_like_string: "2015-02-24T18:19:39Z"
diff --git a/vendor/gems/kubeclient/test/config/update_certs_k0s.rb b/vendor/gems/kubeclient/test/config/update_certs_k0s.rb
deleted file mode 100755
index 2632d72685c..00000000000
--- a/vendor/gems/kubeclient/test/config/update_certs_k0s.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env ruby
-# https://docs.k0sproject.io/latest/k0s-in-docker/
-# Runs in --prividged mode, only run this if you trust the k0s distribution.
-
-require 'English'
-
-# Like Kernel#system, returns true iff exit status == 0
-def sh?(*cmd)
- puts("+ #{cmd.join(' ')}")
- system(*cmd)
-end
-
-# Raises if exit status != 0
-def sh!(*cmd)
- sh?(*cmd) || raise("returned #{$CHILD_STATUS}")
-end
-
-# allow DOCKER='sudo docker', DOCKER=podman etc.
-DOCKER = ENV['DOCKER'] || 'docker'
-
-CONTAINER = 'k0s'.freeze
-
-sh! "#{DOCKER} container inspect #{CONTAINER} --format='exists' ||
- #{DOCKER} run -d --name #{CONTAINER} --hostname k0s --privileged -v /var/lib/k0s -p 6443:6443 \
- ghcr.io/k0sproject/k0s/k0s:v1.23.3-k0s.1"
-
-# sh! "#{DOCKER} exec #{CONTAINER} kubectl config view --raw"
-# is another way to dump kubeconfig but succeeds with dummy output even before admin.conf exists;
-# so accessing the file is better way as it lets us poll until ready:
-sleep(1) until sh?("#{DOCKER} exec #{CONTAINER} ls -l /var/lib/k0s/pki/admin.conf")
-
-sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/admin.conf > test/config/allinone.kubeconfig"
-# The rest could easily be extracted from allinone.kubeconfig, but the test is more robust
-# if we don't reuse YAML and/or Kubeclient::Config parsing to construct test data.
-sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/ca.crt > test/config/external-ca.pem"
-sh! 'cat test/config/another-ca1.pem test/config/external-ca.pem '\
- ' test/config/another-ca2.pem > test/config/concatenated-ca.pem'
-sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/admin.crt > test/config/external-cert.pem"
-sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/admin.key > test/config/external-key.rsa"
-
-# Wait for apiserver to be up. To speed startup, this only retries connection errors;
-# without `--fail-with-body` curl still returns 0 for well-formed 4xx or 5xx responses.
-sleep(1) until sh?(
- 'curl --cacert test/config/external-ca.pem ' \
- '--key test/config/external-key.rsa ' \
- '--cert test/config/external-cert.pem https://127.0.0.1:6443/healthz'
-)
-
-sh! 'env KUBECLIENT_TEST_REAL_CLUSTER=true bundle exec rake test'
-
-sh! "#{DOCKER} rm -f #{CONTAINER}"
-
-puts 'If you run this only for tests, cleanup by running: git restore test/config/'
diff --git a/vendor/gems/kubeclient/test/config/userauth.kubeconfig b/vendor/gems/kubeclient/test/config/userauth.kubeconfig
deleted file mode 100644
index 604e3bda920..00000000000
--- a/vendor/gems/kubeclient/test/config/userauth.kubeconfig
+++ /dev/null
@@ -1,27 +0,0 @@
-apiVersion: v1
-clusters:
-- cluster:
- server: https://localhost:6443
- name: localhost:6443
-contexts:
-- context:
- cluster: localhost:6443
- namespace: default
- user: system:admin:token
- name: localhost/system:admin:token
-- context:
- cluster: localhost:6443
- namespace: default
- user: system:admin:userpass
- name: localhost/system:admin:userpass
-current-context: localhost/system:admin:token
-kind: Config
-preferences: {}
-users:
-- name: system:admin:token
- user:
- token: 0123456789ABCDEF0123456789ABCDEF
-- name: system:admin:userpass
- user:
- username: admin
- password: pAssw0rd123
diff --git a/vendor/gems/kubeclient/test/json/bindings_list.json b/vendor/gems/kubeclient/test/json/bindings_list.json
deleted file mode 100644
index 260748c3aa4..00000000000
--- a/vendor/gems/kubeclient/test/json/bindings_list.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "the server could not find the requested resource",
- "reason": "NotFound",
- "details": {},
- "code": 404
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/component_status.json b/vendor/gems/kubeclient/test/json/component_status.json
deleted file mode 100644
index 109936d3dac..00000000000
--- a/vendor/gems/kubeclient/test/json/component_status.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "kind": "ComponentStatus",
- "apiVersion": "v1",
- "metadata": {
- "name": "etcd-0",
- "selfLink": "/api/v1/namespaces/componentstatuses/etcd-0",
- "creationTimestamp": null
- },
- "conditions": [
- {
- "type": "Healthy",
- "status": "True",
- "message": "{\"health\": \"true\"}",
- "error": "nil"
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/component_status_list.json b/vendor/gems/kubeclient/test/json/component_status_list.json
deleted file mode 100644
index 1849f489eb2..00000000000
--- a/vendor/gems/kubeclient/test/json/component_status_list.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "kind": "ComponentStatusList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/componentstatuses"
- },
- "items": [
- {
- "metadata": {
- "name": "controller-manager",
- "selfLink": "/api/v1/namespaces/componentstatuses/controller-manager",
- "creationTimestamp": null
- },
- "conditions": [
- {
- "type": "Healthy",
- "status": "Unknown",
- "error": "Get http://127.0.0.1:10252/healthz: dial tcp 127.0.0.1:10252: connection refused"
- }
- ]
- },
- {
- "metadata": {
- "name": "scheduler",
- "selfLink": "/api/v1/namespaces/componentstatuses/scheduler",
- "creationTimestamp": null
- },
- "conditions": [
- {
- "type": "Healthy",
- "status": "Unknown",
- "error": "Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: connection refused"
- }
- ]
- },
- {
- "metadata": {
- "name": "etcd-0",
- "selfLink": "/api/v1/namespaces/componentstatuses/etcd-0",
- "creationTimestamp": null
- },
- "conditions": [
- {
- "type": "Healthy",
- "status": "True",
- "message": "{\"health\": \"true\"}",
- "error": "nil"
- }
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/config.istio.io_api_resource_list.json b/vendor/gems/kubeclient/test/json/config.istio.io_api_resource_list.json
deleted file mode 100644
index 5317e865b63..00000000000
--- a/vendor/gems/kubeclient/test/json/config.istio.io_api_resource_list.json
+++ /dev/null
@@ -1,679 +0,0 @@
-{
- "kind": "APIResourceList",
- "apiVersion": "v1",
- "groupVersion": "config.istio.io/v1alpha2",
- "resources": [
- {
- "name": "metrics",
- "singularName": "metric",
- "namespaced": true,
- "kind": "metric",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "servicecontrolreports",
- "singularName": "servicecontrolreport",
- "namespaced": true,
- "kind": "servicecontrolreport",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "opas",
- "singularName": "opa",
- "namespaced": true,
- "kind": "opa",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "redisquotas",
- "singularName": "redisquota",
- "namespaced": true,
- "kind": "redisquota",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "authorizations",
- "singularName": "authorization",
- "namespaced": true,
- "kind": "authorization",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "listentries",
- "singularName": "listentry",
- "namespaced": true,
- "kind": "listentry",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "logentries",
- "singularName": "logentry",
- "namespaced": true,
- "kind": "logentry",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "tracespans",
- "singularName": "tracespan",
- "namespaced": true,
- "kind": "tracespan",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "quotaspecs",
- "singularName": "quotaspec",
- "namespaced": true,
- "kind": "QuotaSpec",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "fluentds",
- "singularName": "fluentd",
- "namespaced": true,
- "kind": "fluentd",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "rbacs",
- "singularName": "rbac",
- "namespaced": true,
- "kind": "rbac",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "checknothings",
- "singularName": "checknothing",
- "namespaced": true,
- "kind": "checknothing",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "edges",
- "singularName": "edge",
- "namespaced": true,
- "kind": "edge",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "apikeys",
- "singularName": "apikey",
- "namespaced": true,
- "kind": "apikey",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "kuberneteses",
- "singularName": "kubernetes",
- "namespaced": true,
- "kind": "kubernetes",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "httpapispecs",
- "singularName": "httpapispec",
- "namespaced": true,
- "kind": "HTTPAPISpec",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "attributemanifests",
- "singularName": "attributemanifest",
- "namespaced": true,
- "kind": "attributemanifest",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "kubernetesenvs",
- "singularName": "kubernetesenv",
- "namespaced": true,
- "kind": "kubernetesenv",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "listcheckers",
- "singularName": "listchecker",
- "namespaced": true,
- "kind": "listchecker",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "quotas",
- "singularName": "quota",
- "namespaced": true,
- "kind": "quota",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "instances",
- "singularName": "instance",
- "namespaced": true,
- "kind": "instance",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "memquotas",
- "singularName": "memquota",
- "namespaced": true,
- "kind": "memquota",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "noops",
- "singularName": "noop",
- "namespaced": true,
- "kind": "noop",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "prometheuses",
- "singularName": "prometheus",
- "namespaced": true,
- "kind": "prometheus",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "solarwindses",
- "singularName": "solarwinds",
- "namespaced": true,
- "kind": "solarwinds",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "cloudwatches",
- "singularName": "cloudwatch",
- "namespaced": true,
- "kind": "cloudwatch",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "reportnothings",
- "singularName": "reportnothing",
- "namespaced": true,
- "kind": "reportnothing",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "stackdrivers",
- "singularName": "stackdriver",
- "namespaced": true,
- "kind": "stackdriver",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "statsds",
- "singularName": "statsd",
- "namespaced": true,
- "kind": "statsd",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "httpapispecbindings",
- "singularName": "httpapispecbinding",
- "namespaced": true,
- "kind": "HTTPAPISpecBinding",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "quotaspecbindings",
- "singularName": "quotaspecbinding",
- "namespaced": true,
- "kind": "QuotaSpecBinding",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "bypasses",
- "singularName": "bypass",
- "namespaced": true,
- "kind": "bypass",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "circonuses",
- "singularName": "circonus",
- "namespaced": true,
- "kind": "circonus",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "deniers",
- "singularName": "denier",
- "namespaced": true,
- "kind": "denier",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "signalfxs",
- "singularName": "signalfx",
- "namespaced": true,
- "kind": "signalfx",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "adapters",
- "singularName": "adapter",
- "namespaced": true,
- "kind": "adapter",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "servicecontrols",
- "singularName": "servicecontrol",
- "namespaced": true,
- "kind": "servicecontrol",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "templates",
- "singularName": "template",
- "namespaced": true,
- "kind": "template",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "handlers",
- "singularName": "handler",
- "namespaced": true,
- "kind": "handler",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "rules",
- "singularName": "rule",
- "namespaced": true,
- "kind": "rule",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "dogstatsds",
- "singularName": "dogstatsd",
- "namespaced": true,
- "kind": "dogstatsd",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- },
- {
- "name": "stdios",
- "singularName": "stdio",
- "namespaced": true,
- "kind": "stdio",
- "verbs": [
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "create",
- "update",
- "watch"
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/config_map_list.json b/vendor/gems/kubeclient/test/json/config_map_list.json
deleted file mode 100644
index 85e0e30d7fe..00000000000
--- a/vendor/gems/kubeclient/test/json/config_map_list.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "kind": "ConfigMapList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/configmaps",
- "resourceVersion": "665"
- },
- "items": []
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/core_api_resource_list.json b/vendor/gems/kubeclient/test/json/core_api_resource_list.json
deleted file mode 100644
index 395acb249df..00000000000
--- a/vendor/gems/kubeclient/test/json/core_api_resource_list.json
+++ /dev/null
@@ -1,181 +0,0 @@
-{
- "kind": "APIResourceList",
- "groupVersion": "v1",
- "resources": [
- {
- "name": "bindings",
- "namespaced": true,
- "kind": "Binding"
- },
- {
- "name": "componentstatuses",
- "namespaced": false,
- "kind": "ComponentStatus"
- },
- {
- "name": "configmaps",
- "namespaced": true,
- "kind": "ConfigMap"
- },
- {
- "name": "endpoints",
- "namespaced": true,
- "kind": "Endpoints"
- },
- {
- "name": "events",
- "namespaced": true,
- "kind": "Event"
- },
- {
- "name": "limitranges",
- "namespaced": true,
- "kind": "LimitRange"
- },
- {
- "name": "namespaces",
- "namespaced": false,
- "kind": "Namespace"
- },
- {
- "name": "namespaces/finalize",
- "namespaced": false,
- "kind": "Namespace"
- },
- {
- "name": "namespaces/status",
- "namespaced": false,
- "kind": "Namespace"
- },
- {
- "name": "nodes",
- "namespaced": false,
- "kind": "Node"
- },
- {
- "name": "nodes/proxy",
- "namespaced": false,
- "kind": "Node"
- },
- {
- "name": "nodes/status",
- "namespaced": false,
- "kind": "Node"
- },
- {
- "name": "persistentvolumeclaims",
- "namespaced": true,
- "kind": "PersistentVolumeClaim"
- },
- {
- "name": "persistentvolumeclaims/status",
- "namespaced": true,
- "kind": "PersistentVolumeClaim"
- },
- {
- "name": "persistentvolumes",
- "namespaced": false,
- "kind": "PersistentVolume"
- },
- {
- "name": "persistentvolumes/status",
- "namespaced": false,
- "kind": "PersistentVolume"
- },
- {
- "name": "pods",
- "namespaced": true,
- "kind": "Pod"
- },
- {
- "name": "pods/attach",
- "namespaced": true,
- "kind": "Pod"
- },
- {
- "name": "pods/binding",
- "namespaced": true,
- "kind": "Binding"
- },
- {
- "name": "pods/exec",
- "namespaced": true,
- "kind": "Pod"
- },
- {
- "name": "pods/log",
- "namespaced": true,
- "kind": "Pod"
- },
- {
- "name": "pods/portforward",
- "namespaced": true,
- "kind": "Pod"
- },
- {
- "name": "pods/proxy",
- "namespaced": true,
- "kind": "Pod"
- },
- {
- "name": "pods/status",
- "namespaced": true,
- "kind": "Pod"
- },
- {
- "name": "podtemplates",
- "namespaced": true,
- "kind": "PodTemplate"
- },
- {
- "name": "replicationcontrollers",
- "namespaced": true,
- "kind": "ReplicationController"
- },
- {
- "name": "replicationcontrollers/scale",
- "namespaced": true,
- "kind": "Scale"
- },
- {
- "name": "replicationcontrollers/status",
- "namespaced": true,
- "kind": "ReplicationController"
- },
- {
- "name": "resourcequotas",
- "namespaced": true,
- "kind": "ResourceQuota"
- },
- {
- "name": "resourcequotas/status",
- "namespaced": true,
- "kind": "ResourceQuota"
- },
- {
- "name": "secrets",
- "namespaced": true,
- "kind": "Secret"
- },
- {
- "name": "serviceaccounts",
- "namespaced": true,
- "kind": "ServiceAccount"
- },
- {
- "name": "services",
- "namespaced": true,
- "kind": "Service"
- },
- {
- "name": "services/proxy",
- "namespaced": true,
- "kind": "Service"
- },
- {
- "name": "services/status",
- "namespaced": true,
- "kind": "Service"
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/core_api_resource_list_without_kind.json b/vendor/gems/kubeclient/test/json/core_api_resource_list_without_kind.json
deleted file mode 100644
index f60e113d6e5..00000000000
--- a/vendor/gems/kubeclient/test/json/core_api_resource_list_without_kind.json
+++ /dev/null
@@ -1,129 +0,0 @@
-{
- "groupVersion": "v1",
- "resources": [
- {
- "name": "bindings",
- "namespaced": true
- },
- {
- "name": "componentstatuses",
- "namespaced": true
- },
- {
- "name": "endpoints",
- "namespaced": true
- },
- {
- "name": "events",
- "namespaced": true
- },
- {
- "name": "limitranges",
- "namespaced": true
- },
- {
- "name": "namespaces",
- "namespaced": false
- },
- {
- "name": "namespaces/finalize",
- "namespaced": false
- },
- {
- "name": "namespaces/status",
- "namespaced": false
- },
- {
- "name": "nodes",
- "namespaced": false
- },
- {
- "name": "nodes/status",
- "namespaced": false
- },
- {
- "name": "persistentvolumeclaims",
- "namespaced": true
- },
- {
- "name": "persistentvolumeclaims/status",
- "namespaced": true
- },
- {
- "name": "persistentvolumes",
- "namespaced": false
- },
- {
- "name": "persistentvolumes/status",
- "namespaced": false
- },
- {
- "name": "pods",
- "namespaced": true
- },
- {
- "name": "pods/attach",
- "namespaced": true
- },
- {
- "name": "pods/binding",
- "namespaced": true
- },
- {
- "name": "pods/exec",
- "namespaced": true
- },
- {
- "name": "pods/log",
- "namespaced": true
- },
- {
- "name": "pods/portforward",
- "namespaced": true
- },
- {
- "name": "pods/proxy",
- "namespaced": true
- },
- {
- "name": "pods/status",
- "namespaced": true
- },
- {
- "name": "podtemplates",
- "namespaced": true
- },
- {
- "name": "replicationcontrollers",
- "namespaced": true
- },
- {
- "name": "replicationcontrollers/status",
- "namespaced": true
- },
- {
- "name": "resourcequotas",
- "namespaced": true
- },
- {
- "name": "resourcequotas/status",
- "namespaced": true
- },
- {
- "name": "secrets",
- "namespaced": true
- },
- {
- "name": "securitycontextconstraints",
- "namespaced": false
- },
- {
- "name": "serviceaccounts",
- "namespaced": true
- },
- {
- "name": "services",
- "namespaced": true
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/core_oapi_resource_list_without_kind.json b/vendor/gems/kubeclient/test/json/core_oapi_resource_list_without_kind.json
deleted file mode 100644
index a902a6a7fd1..00000000000
--- a/vendor/gems/kubeclient/test/json/core_oapi_resource_list_without_kind.json
+++ /dev/null
@@ -1,197 +0,0 @@
-{
- "groupVersion": "v1",
- "resources": [
- {
- "name": "buildconfigs",
- "namespaced": true
- },
- {
- "name": "buildconfigs/instantiate",
- "namespaced": true
- },
- {
- "name": "buildconfigs/instantiatebinary",
- "namespaced": true
- },
- {
- "name": "buildconfigs/webhooks",
- "namespaced": true
- },
- {
- "name": "builds",
- "namespaced": true
- },
- {
- "name": "builds/clone",
- "namespaced": true
- },
- {
- "name": "builds/details",
- "namespaced": true
- },
- {
- "name": "builds/log",
- "namespaced": true
- },
- {
- "name": "clusternetworks",
- "namespaced": false
- },
- {
- "name": "clusterpolicies",
- "namespaced": false
- },
- {
- "name": "clusterpolicybindings",
- "namespaced": false
- },
- {
- "name": "clusterrolebindings",
- "namespaced": false
- },
- {
- "name": "clusterroles",
- "namespaced": false
- },
- {
- "name": "deploymentconfigrollbacks",
- "namespaced": true
- },
- {
- "name": "deploymentconfigs",
- "namespaced": true
- },
- {
- "name": "deploymentconfigs/log",
- "namespaced": true
- },
- {
- "name": "deploymentconfigs/scale",
- "namespaced": true
- },
- {
- "name": "generatedeploymentconfigs",
- "namespaced": true
- },
- {
- "name": "groups",
- "namespaced": false
- },
- {
- "name": "hostsubnets",
- "namespaced": false
- },
- {
- "name": "identities",
- "namespaced": false
- },
- {
- "name": "images",
- "namespaced": false
- },
- {
- "name": "imagestreamimages",
- "namespaced": true
- },
- {
- "name": "imagestreammappings",
- "namespaced": true
- },
- {
- "name": "imagestreams",
- "namespaced": true
- },
- {
- "name": "imagestreams/status",
- "namespaced": true
- },
- {
- "name": "imagestreamtags",
- "namespaced": true
- },
- {
- "name": "localresourceaccessreviews",
- "namespaced": true
- },
- {
- "name": "localsubjectaccessreviews",
- "namespaced": true
- },
- {
- "name": "netnamespaces",
- "namespaced": false
- },
- {
- "name": "oauthaccesstokens",
- "namespaced": false
- },
- {
- "name": "oauthauthorizetokens",
- "namespaced": false
- },
- {
- "name": "oauthclientauthorizations",
- "namespaced": false
- },
- {
- "name": "oauthclients",
- "namespaced": false
- },
- {
- "name": "policies",
- "namespaced": true
- },
- {
- "name": "policybindings",
- "namespaced": true
- },
- {
- "name": "processedtemplates",
- "namespaced": true
- },
- {
- "name": "projectrequests",
- "namespaced": false
- },
- {
- "name": "projects",
- "namespaced": false
- },
- {
- "name": "resourceaccessreviews",
- "namespaced": true
- },
- {
- "name": "rolebindings",
- "namespaced": true
- },
- {
- "name": "roles",
- "namespaced": true
- },
- {
- "name": "routes",
- "namespaced": true
- },
- {
- "name": "routes/status",
- "namespaced": true
- },
- {
- "name": "subjectaccessreviews",
- "namespaced": true
- },
- {
- "name": "templates",
- "namespaced": true
- },
- {
- "name": "useridentitymappings",
- "namespaced": false
- },
- {
- "name": "users",
- "namespaced": false
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/created_endpoint.json b/vendor/gems/kubeclient/test/json/created_endpoint.json
deleted file mode 100644
index 1e0fd7dc41d..00000000000
--- a/vendor/gems/kubeclient/test/json/created_endpoint.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "kind": "Endpoints",
- "apiVersion": "v1",
- "metadata": {
- "name": "myendpoint",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/endpoints/myendpoint",
- "uid": "59d05b48-dadb-11e5-937e-18037327aaeb",
- "resourceVersion": "393",
- "creationTimestamp": "2016-02-24T09:45:34Z"
- },
- "subsets": [
- {
- "addresses": [
- {
- "ip": "172.17.0.25"
- }
- ],
- "ports": [
- {
- "name": "https",
- "port": 6443,
- "protocol": "TCP"
- }
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/created_namespace.json b/vendor/gems/kubeclient/test/json/created_namespace.json
deleted file mode 100644
index 218bc000aa8..00000000000
--- a/vendor/gems/kubeclient/test/json/created_namespace.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-"kind": "Namespace",
-"apiVersion": "v1",
-"metadata": {
-"name": "development",
-"selfLink": "/api/v1/namespaces/development",
-"uid": "13d820d6-df5b-11e4-bd42-f8b156af4ae1",
-"resourceVersion": "2533",
-"creationTimestamp": "2015-04-10T08:24:59Z"
-},
-"spec": {
-"finalizers": [
-"kubernetes"
-]
-},
-"status": {
-"phase": "Active"
-}
-}
-
diff --git a/vendor/gems/kubeclient/test/json/created_secret.json b/vendor/gems/kubeclient/test/json/created_secret.json
deleted file mode 100644
index bcea8848335..00000000000
--- a/vendor/gems/kubeclient/test/json/created_secret.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "kind": "Secret",
- "apiVersion": "v1",
- "metadata": {
- "name": "test-secret",
- "namespace": "dev",
- "selfLink": "/api/v1/namespaces/dev/secrets/test-secret",
- "uid": "4e38a198-2bcb-11e5-a483-0e840567604d",
- "resourceVersion": "245569",
- "creationTimestamp": "2015-07-16T14:59:49Z"
- },
- "data": {
- "super-secret": "Y2F0J3MgYXJlIGF3ZXNvbWUK"
- },
- "type": "Opaque"
-}
diff --git a/vendor/gems/kubeclient/test/json/created_security_context_constraint.json b/vendor/gems/kubeclient/test/json/created_security_context_constraint.json
deleted file mode 100644
index c2981712cb5..00000000000
--- a/vendor/gems/kubeclient/test/json/created_security_context_constraint.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "allowHostDirVolumePlugin": false,
- "allowHostIPC": false,
- "allowHostNetwork": false,
- "allowHostPID": false,
- "allowHostPorts": false,
- "allowPrivilegedContainer": false,
- "allowedCapabilities": null,
- "allowedFlexVolumes": null,
- "apiVersion": "security.openshift.io/v1",
- "defaultAddCapabilities": null,
- "fsGroup": {
- "type": "RunAsAny"
- },
- "groups": [],
- "kind": "SecurityContextConstraints",
- "metadata": {
- "creationTimestamp": "2018-11-23T10:01:42Z",
- "name": "teleportation",
- "resourceVersion": "5274",
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/teleportation",
- "uid": "c6e8e2ec-ef06-11e8-b4c0-68f728fac3ab"
- },
- "priority": null,
- "readOnlyRootFilesystem": false,
- "requiredDropCapabilities": null,
- "runAsUser": {
- "type": "MustRunAs"
- },
- "seLinuxContext": {
- "type": "MustRunAs"
- },
- "supplementalGroups": {
- "type": "RunAsAny"
- },
- "users": [],
- "volumes": [
- "awsElasticBlockStore",
- "azureDisk",
- "azureFile",
- "cephFS",
- "cinder",
- "configMap",
- "downwardAPI",
- "emptyDir",
- "fc",
- "flexVolume",
- "flocker",
- "gcePersistentDisk",
- "gitRepo",
- "glusterfs",
- "iscsi",
- "nfs",
- "persistentVolumeClaim",
- "photonPersistentDisk",
- "portworxVolume",
- "projected",
- "quobyte",
- "rbd",
- "scaleIO",
- "secret",
- "storageOS",
- "vsphere"
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/created_service.json b/vendor/gems/kubeclient/test/json/created_service.json
deleted file mode 100644
index 4c2bc7d7196..00000000000
--- a/vendor/gems/kubeclient/test/json/created_service.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "kind": "Service",
- "apiVersion": "v1",
- "metadata": {
- "name": "guestbook",
- "namespace": "staging",
- "selfLink": "/api/v1/namespaces/staging/services/guestbook",
- "uid": "29885239-df58-11e4-bd42-f8b156af4ae1",
- "resourceVersion": "1908",
- "creationTimestamp": "2015-04-10T08:04:07Z",
- "labels": {
- "name": "guestbook"
- }
- },
- "spec": {
- "ports": [
- {
- "name": "",
- "protocol": "TCP",
- "port": 3000,
- "targetPort": "http-server"
- }
- ],
- "selector": {
- "name": "guestbook"
- },
- "clusterIP": "10.0.0.99",
- "sessionAffinity": "None"
- },
- "status": {}
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/empty_pod_list.json b/vendor/gems/kubeclient/test/json/empty_pod_list.json
deleted file mode 100644
index a82cba1148f..00000000000
--- a/vendor/gems/kubeclient/test/json/empty_pod_list.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "kind": "PodList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/pods",
- "resourceVersion": "565"
- },
- "items": []
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/endpoint_list.json b/vendor/gems/kubeclient/test/json/endpoint_list.json
deleted file mode 100644
index bd6c00ab678..00000000000
--- a/vendor/gems/kubeclient/test/json/endpoint_list.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "kind": "EndpointsList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/namespaces/endpoints",
- "resourceVersion": "39"
- },
- "items": [
- {
- "metadata": {
- "name": "example",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/endpoints/example",
- "uid": "db467530-b6aa-11e4-974a-525400c903c1",
- "resourceVersion": "38",
- "creationTimestamp": "2015-02-17T08:42:46-05:00"
- },
- "endpoints": [
- "172.17.0.63:80",
- "172.17.0.64:80"
- ]
- },
- {
- "metadata": {
- "name": "kubernetes",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/endpoints/kubernetes",
- "resourceVersion": "8",
- "creationTimestamp": null
- },
- "endpoints": [
- "192.168.122.4:6443"
- ]
- },
- {
- "metadata": {
- "name": "kubernetes-ro",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/endpoints/kubernetes-ro",
- "resourceVersion": "7",
- "creationTimestamp": null
- },
- "endpoints": [
- "192.168.122.4:7080"
- ]
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/entity_list.json b/vendor/gems/kubeclient/test/json/entity_list.json
deleted file mode 100644
index 3dd140d38c8..00000000000
--- a/vendor/gems/kubeclient/test/json/entity_list.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "kind": "ServiceList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/services",
- "resourceVersion": "59"
- },
- "items": [
- {
- "metadata": {
- "name": "kubernetes",
- "namespace": "default",
- "selfLink": "/api/v1/services/kubernetes?namespace=default",
- "uid": "016e9dcd-ce39-11e4-ac24-3c970e4a436a",
- "resourceVersion": "6",
- "creationTimestamp": "2015-03-19T15:08:16+02:00",
- "labels": {
- "component": "apiserver",
- "provider": "kubernetes"
- }
- },
- "spec": {
- "port": 443,
- "protocol": "TCP",
- "selector": null,
- "clusterIP": "10.0.0.2",
- "containerPort": 0,
- "sessionAffinity": "None"
- },
- "status": {}
- },
- {
- "metadata": {
- "name": "kubernetes-ro",
- "namespace": "default",
- "selfLink": "/api/v1/services/kubernetes-ro?namespace=default",
- "uid": "015b78bf-ce39-11e4-ac24-3c970e4a436a",
- "resourceVersion": "5",
- "creationTimestamp": "2015-03-19T15:08:15+02:00",
- "labels": {
- "component": "apiserver",
- "provider": "kubernetes"
- }
- },
- "spec": {
- "port": 80,
- "protocol": "TCP",
- "selector": null,
- "clusterIP": "10.0.0.1",
- "containerPort": 0,
- "sessionAffinity": "None"
- },
- "status": {}
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/event_list.json b/vendor/gems/kubeclient/test/json/event_list.json
deleted file mode 100644
index 45abfccc278..00000000000
--- a/vendor/gems/kubeclient/test/json/event_list.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "kind": "EventList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/events",
- "resourceVersion": "152"
- },
- "items": [
- {
- "metadata": {
- "name": "php.13c130f78da4641e",
- "namespace": "default",
- "selfLink": "/api/v1/events/php.13c130f78da4641e?namespace=default",
- "uid": "f3a454d2-b03a-11e4-89e4-525400c903c1",
- "resourceVersion": "178",
- "creationTimestamp": "2015-02-09T04:06:37-05:00"
- },
- "involvedObject": {
- "kind": "BoundPod",
- "namespace": "default",
- "name": "php",
- "uid": "64273d20-b03a-11e4-89e4-525400c903c1",
- "apiVersion": "v1beta1",
- "fieldPath": "spec.containers{nginx}"
- },
- "reason": "created",
- "message": "Created with docker id 9ba2a714411d2d0dd1e826b2fe5c3222b5cbfd9dd9133c841585cbb96b8c2c0f",
- "source": {
- "component": "kubelet",
- "host": "127.0.0.1"
- },
- "timestamp": "2015-02-09T04:06:37-05:00"
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/extensions_v1beta1_api_resource_list.json b/vendor/gems/kubeclient/test/json/extensions_v1beta1_api_resource_list.json
deleted file mode 100644
index 16fc80cf4d7..00000000000
--- a/vendor/gems/kubeclient/test/json/extensions_v1beta1_api_resource_list.json
+++ /dev/null
@@ -1,217 +0,0 @@
-{
- "kind": "APIResourceList",
- "groupVersion": "extensions/v1beta1",
- "resources": [
- {
- "name": "daemonsets",
- "singularName": "",
- "namespaced": true,
- "kind": "DaemonSet",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ],
- "shortNames": [
- "ds"
- ]
- },
- {
- "name": "daemonsets/status",
- "singularName": "",
- "namespaced": true,
- "kind": "DaemonSet",
- "verbs": [
- "get",
- "patch",
- "update"
- ]
- },
- {
- "name": "deployments",
- "singularName": "",
- "namespaced": true,
- "kind": "Deployment",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ],
- "shortNames": [
- "deploy"
- ]
- },
- {
- "name": "deployments/rollback",
- "singularName": "",
- "namespaced": true,
- "kind": "DeploymentRollback",
- "verbs": [
- "create"
- ]
- },
- {
- "name": "deployments/scale",
- "singularName": "",
- "namespaced": true,
- "group": "extensions",
- "version": "v1beta1",
- "kind": "Scale",
- "verbs": [
- "get",
- "patch",
- "update"
- ]
- },
- {
- "name": "deployments/status",
- "singularName": "",
- "namespaced": true,
- "kind": "Deployment",
- "verbs": [
- "get",
- "patch",
- "update"
- ]
- },
- {
- "name": "ingresses",
- "singularName": "",
- "namespaced": true,
- "kind": "Ingress",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ],
- "shortNames": [
- "ing"
- ]
- },
- {
- "name": "ingresses/status",
- "singularName": "",
- "namespaced": true,
- "kind": "Ingress",
- "verbs": [
- "get",
- "patch",
- "update"
- ]
- },
- {
- "name": "networkpolicies",
- "singularName": "",
- "namespaced": true,
- "kind": "NetworkPolicy",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ],
- "shortNames": [
- "netpol"
- ]
- },
- {
- "name": "podsecuritypolicies",
- "singularName": "",
- "namespaced": false,
- "kind": "PodSecurityPolicy",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ],
- "shortNames": [
- "psp"
- ]
- },
- {
- "name": "replicasets",
- "singularName": "",
- "namespaced": true,
- "kind": "ReplicaSet",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ],
- "shortNames": [
- "rs"
- ]
- },
- {
- "name": "replicasets/scale",
- "singularName": "",
- "namespaced": true,
- "group": "extensions",
- "version": "v1beta1",
- "kind": "Scale",
- "verbs": [
- "get",
- "patch",
- "update"
- ]
- },
- {
- "name": "replicasets/status",
- "singularName": "",
- "namespaced": true,
- "kind": "ReplicaSet",
- "verbs": [
- "get",
- "patch",
- "update"
- ]
- },
- {
- "name": "replicationcontrollers",
- "singularName": "",
- "namespaced": true,
- "kind": "ReplicationControllerDummy",
- "verbs": []
- },
- {
- "name": "replicationcontrollers/scale",
- "singularName": "",
- "namespaced": true,
- "kind": "Scale",
- "verbs": [
- "get",
- "patch",
- "update"
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/limit_range.json b/vendor/gems/kubeclient/test/json/limit_range.json
deleted file mode 100644
index ac2e21aa744..00000000000
--- a/vendor/gems/kubeclient/test/json/limit_range.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "kind": "LimitRange",
- "apiVersion": "v1",
- "metadata": {
- "name": "limits",
- "namespace": "quota-example",
- "selfLink": "/api/v1/namespaces/quota-example/limitranges/limits",
- "uid": "7a76a44c-3e9d-11e5-8214-0aaeec44370e",
- "resourceVersion": "103384",
- "creationTimestamp": "2015-08-09T13:49:39Z"
- },
- "spec": {
- "limits": [
- {
- "type": "Container",
- "default": {
- "cpu": "100m",
- "memory": "512Mi"
- }
- }
- ]
- }
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/limit_range_list.json b/vendor/gems/kubeclient/test/json/limit_range_list.json
deleted file mode 100644
index 7986ec861d8..00000000000
--- a/vendor/gems/kubeclient/test/json/limit_range_list.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "kind": "LimitRangeList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/namespaces/quota-example/limitranges/",
- "resourceVersion": "103421"
- },
- "items": [
- {
- "metadata": {
- "name": "limits",
- "namespace": "quota-example",
- "selfLink": "/api/v1/namespaces/quota-example/limitranges/limits",
- "uid": "7a76a44c-3e9d-11e5-8214-0aaeec44370e",
- "resourceVersion": "103384",
- "creationTimestamp": "2015-08-09T13:49:39Z"
- },
- "spec": {
- "limits": [
- {
- "type": "Container",
- "default": {
- "cpu": "100m",
- "memory": "512Mi"
- }
- }
- ]
- }
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/namespace.json b/vendor/gems/kubeclient/test/json/namespace.json
deleted file mode 100644
index 5a856730188..00000000000
--- a/vendor/gems/kubeclient/test/json/namespace.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "kind": "Namespace",
- "apiVersion": "v1",
- "metadata": {
- "name": "staging",
- "selfLink": "/api/v1/namespaces/staging",
- "uid": "e388bc10-c021-11e4-a514-3c970e4a436a",
- "resourceVersion": "1168",
- "creationTimestamp": "2015-03-01T16:47:31+02:00"
- },
- "spec": {},
- "status": {}
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/namespace_exception.json b/vendor/gems/kubeclient/test/json/namespace_exception.json
deleted file mode 100644
index 555ef24cabb..00000000000
--- a/vendor/gems/kubeclient/test/json/namespace_exception.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {},
- "status": "Failure",
- "message": "converting to : type names don't match (Pod, Namespace)",
- "code": 500
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/namespace_list.json b/vendor/gems/kubeclient/test/json/namespace_list.json
deleted file mode 100644
index af6feb7485c..00000000000
--- a/vendor/gems/kubeclient/test/json/namespace_list.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "kind": "NamespaceList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/namespaces",
- "resourceVersion": "1707"
- },
- "items": [
- {
- "metadata": {
- "name": "default",
- "selfLink": "/api/v1/namespaces/default",
- "uid": "56c3eb7c-c009-11e4-a514-3c970e4a436a",
- "resourceVersion": "4",
- "creationTimestamp": "2015-03-01T13:51:47+02:00"
- },
- "spec": {},
- "status": {}
- },
- {
- "metadata": {
- "name": "staging",
- "selfLink": "/api/v1/namespaces/staging",
- "uid": "e388bc10-c021-11e4-a514-3c970e4a436a",
- "resourceVersion": "1168",
- "creationTimestamp": "2015-03-01T16:47:31+02:00"
- },
- "spec": {},
- "status": {}
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/node.json b/vendor/gems/kubeclient/test/json/node.json
deleted file mode 100644
index bb4772c3f20..00000000000
--- a/vendor/gems/kubeclient/test/json/node.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "kind": "Node",
- "apiVersion": "v1",
- "metadata": {
- "name": "127.0.0.1",
- "selfLink": "/api/v1/nodes/127.0.0.1",
- "uid": "041143c5-ce39-11e4-ac24-3c970e4a436a",
- "resourceVersion": "1724",
- "creationTimestamp": "2015-03-19T15:08:20+02:00"
- },
- "spec": {
- "capacity": {
- "cpu": "1",
- "memory": "3Gi"
- }
- },
- "status": {
- "hostIP": "127.0.0.1",
- "conditions": [
- {
- "kind": "Ready",
- "status": "None",
- "lastProbeTime": "2015-03-20T14:16:52+02:00",
- "lastTransitionTime": "2015-03-19T15:08:20+02:00",
- "reason": "Node health check failed: kubelet /healthz endpoint returns not ok"
- }
- ]
- }
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/node_list.json b/vendor/gems/kubeclient/test/json/node_list.json
deleted file mode 100644
index a5c7cbb77a3..00000000000
--- a/vendor/gems/kubeclient/test/json/node_list.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "kind": "NodeList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/nodes",
- "resourceVersion": "137"
- },
- "items": [
- {
- "metadata": {
- "name": "127.0.0.1",
- "selfLink": "/api/v1/nodes/127.0.0.1",
- "uid": "041143c5-ce39-11e4-ac24-3c970e4a436a",
- "resourceVersion": "137",
- "creationTimestamp": "2015-03-19T15:08:20+02:00"
- },
- "spec": {
- "capacity": {
- "cpu": "1",
- "memory": "3Gi"
- }
- },
- "status": {
- "hostIP": "127.0.0.1",
- "conditions": [
- {
- "kind": "Ready",
- "status": "None",
- "lastProbeTime": "2015-03-19T15:29:33+02:00",
- "lastTransitionTime": "2015-03-19T15:08:20+02:00",
- "reason": "Node health check failed: kubelet /healthz endpoint returns not ok"
- }
- ]
- }
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/node_notice.json b/vendor/gems/kubeclient/test/json/node_notice.json
deleted file mode 100644
index 69ee438ecc2..00000000000
--- a/vendor/gems/kubeclient/test/json/node_notice.json
+++ /dev/null
@@ -1,160 +0,0 @@
-{
- "type": "ADDED",
- "object": {
- "apiVersion": "v1",
- "kind": "Node",
- "metadata": {
- "annotations": {
- "volumes.kubernetes.io/controller-managed-attach-detach": "true"
- },
- "creationTimestamp": "2017-12-11T12:00:13Z",
- "labels": {
- "beta.kubernetes.io/arch": "amd64",
- "beta.kubernetes.io/os": "linux",
- "kubernetes.io/hostname": "openshift.local",
- "openshift-infra": "apiserver"
- },
- "name": "openshift.local",
- "resourceVersion": "367410",
- "selfLink": "/api/v1/nodes/openshift.local",
- "uid": "d88c7af6-de6a-11e7-8725-52540080f1d2"
- },
- "spec": {
- "externalID": "openshift.local"
- },
- "status": {
- "addresses": [
- {
- "address": "192.168.122.40",
- "type": "InternalIP"
- },
- {
- "address": "openshift.local",
- "type": "Hostname"
- }
- ],
- "allocatable": {
- "cpu": "2",
- "memory": "8072896Ki",
- "pods": "20"
- },
- "capacity": {
- "cpu": "2",
- "memory": "8175296Ki",
- "pods": "20"
- },
- "conditions": [
- {
- "lastHeartbeatTime": "2017-12-15T00:36:13Z",
- "lastTransitionTime": "2017-12-11T12:00:13Z",
- "message": "kubelet has sufficient disk space available",
- "reason": "KubeletHasSufficientDisk",
- "status": "False",
- "type": "OutOfDisk"
- },
- {
- "lastHeartbeatTime": "2017-12-15T00:36:13Z",
- "lastTransitionTime": "2017-12-11T12:00:13Z",
- "message": "kubelet has sufficient memory available",
- "reason": "KubeletHasSufficientMemory",
- "status": "False",
- "type": "MemoryPressure"
- },
- {
- "lastHeartbeatTime": "2017-12-15T00:36:13Z",
- "lastTransitionTime": "2017-12-11T12:00:13Z",
- "message": "kubelet has no disk pressure",
- "reason": "KubeletHasNoDiskPressure",
- "status": "False",
- "type": "DiskPressure"
- },
- {
- "lastHeartbeatTime": "2017-12-15T00:36:13Z",
- "lastTransitionTime": "2017-12-14T15:43:39Z",
- "message": "kubelet is posting ready status",
- "reason": "KubeletReady",
- "status": "True",
- "type": "Ready"
- }
- ],
- "daemonEndpoints": {
- "kubeletEndpoint": {
- "Port": 10250
- }
- },
- "images": [
- {
- "names": [
- "docker.io/openshift/origin@sha256:908c6c9ccf0e0feefe2658899656c6e73d2854777fa340738fb903f0a40c328d",
- "docker.io/openshift/origin:latest"
- ],
- "sizeBytes": 1222636603
- },
- {
- "names": [
- "docker.io/openshift/origin-deployer@sha256:3d324bce1870047edc418041cefdec88e0a5bbb5b3b9f6fd35b43f14919a656c",
- "docker.io/openshift/origin-deployer:v3.7.0"
- ],
- "sizeBytes": 1098951248
- },
- {
- "names": [
- "docker.io/cockpit/kubernetes@sha256:a8e58cd5e6f5a4d12d1e2dfd339686b74f3c22586952ca7aa184dc254ab49714",
- "docker.io/cockpit/kubernetes:latest"
- ],
- "sizeBytes": 375926556
- },
- {
- "names": [
- "docker.io/cockpit/kubernetes@sha256:0745b3823efc57e03a5ef378614dfcb6c2b1e3964220bbf908fb3046a91cef70"
- ],
- "sizeBytes": 350062743
- },
- {
- "names": [
- "docker.io/openshift/origin-service-catalog@sha256:ef851e06276af96838a93320d0e4be51cc8de6e5afb2fb0efd4e56cec114b937"
- ],
- "sizeBytes": 284732029
- },
- {
- "names": [
- "docker.io/openshift/origin-service-catalog@sha256:8addfd742d92d8da819b091d6bda40edc45e88d1446ffd1ad658b6d21b3c36fd"
- ],
- "sizeBytes": 284731998
- },
- {
- "names": [
- "docker.io/openshift/origin-service-catalog@sha256:b3a737cc346b3cae85ef2f5d020b607781a1cac38fe70678cb78fee2c2a3bf8a"
- ],
- "sizeBytes": 284731943
- },
- {
- "names": [
- "docker.io/openshift/origin-service-catalog@sha256:957934537721da33362693d4f1590dc79dc5da7438799bf14d645165768e53ef",
- "docker.io/openshift/origin-service-catalog:latest"
- ],
- "sizeBytes": 283929631
- },
- {
- "names": [
- "docker.io/openshift/origin-pod@sha256:2c257d83a01607b229ef5e3dca09f52c3a2a2788c09dc33f0444ec4e572a9e1d",
- "docker.io/openshift/origin-pod:v3.7.0"
- ],
- "sizeBytes": 218423400
- }
- ],
- "nodeInfo": {
- "architecture": "amd64",
- "bootID": "75be791d-88a2-4f56-a588-c071a80bf7cf",
- "containerRuntimeVersion": "docker://1.12.6",
- "kernelVersion": "3.10.0-693.11.1.el7.x86_64",
- "kubeProxyVersion": "v1.7.6+a08f5eeb62",
- "kubeletVersion": "v1.7.6+a08f5eeb62",
- "machineID": "adf09ffc2de2624aa5ed335727c7400d",
- "operatingSystem": "linux",
- "osImage": "CentOS Linux 7 (Core)",
- "systemUUID": "FC9FF0AD-E22D-4A62-A5ED-335727C7400D"
- }
- }
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume.json b/vendor/gems/kubeclient/test/json/persistent_volume.json
deleted file mode 100644
index 612d9df1564..00000000000
--- a/vendor/gems/kubeclient/test/json/persistent_volume.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "kind": "PersistentVolume",
- "apiVersion": "v1",
- "metadata": {
- "name": "pv0001",
- "selfLink": "/api/v1/persistentvolumes/pv0001",
- "uid": "c83eece1-4b38-11e5-8d27-28d2447dcefe",
- "resourceVersion": "1585",
- "creationTimestamp": "2015-08-25T14:51:35Z",
- "labels": {
- "type": "local"
- }
- },
- "spec": {
- "capacity": {
- "storage": "10Gi"
- },
- "hostPath": {
- "path": "/tmp/data01"
- },
- "accessModes": [
- "ReadWriteOnce"
- ],
- "claimRef": {
- "kind": "PersistentVolumeClaim",
- "namespace": "default",
- "name": "myclaim-1",
- "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe",
- "apiVersion": "v1",
- "resourceVersion": "1582"
- },
- "persistentVolumeReclaimPolicy": "Retain"
- },
- "status": {
- "phase": "Bound"
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume_claim.json b/vendor/gems/kubeclient/test/json/persistent_volume_claim.json
deleted file mode 100644
index 65154685348..00000000000
--- a/vendor/gems/kubeclient/test/json/persistent_volume_claim.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "kind": "PersistentVolumeClaim",
- "apiVersion": "v1",
- "metadata": {
- "name": "myclaim-1",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1",
- "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe",
- "resourceVersion": "1584",
- "creationTimestamp": "2015-08-25T14:51:55Z"
- },
- "spec": {
- "accessModes": [
- "ReadWriteOnce"
- ],
- "resources": {
- "requests": {
- "storage": "3Gi"
- }
- },
- "volumeName": "pv0001"
- },
- "status": {
- "phase": "Bound",
- "accessModes": [
- "ReadWriteOnce"
- ],
- "capacity": {
- "storage": "10Gi"
- }
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume_claim_list.json b/vendor/gems/kubeclient/test/json/persistent_volume_claim_list.json
deleted file mode 100644
index 9533d75603b..00000000000
--- a/vendor/gems/kubeclient/test/json/persistent_volume_claim_list.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "kind": "PersistentVolumeClaimList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/persistentvolumeclaims",
- "resourceVersion": "3188"
- },
- "items": [
- {
- "metadata": {
- "name": "myclaim-1",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1",
- "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe",
- "resourceVersion": "1584",
- "creationTimestamp": "2015-08-25T14:51:55Z"
- },
- "spec": {
- "accessModes": [
- "ReadWriteOnce"
- ],
- "resources": {
- "requests": {
- "storage": "3Gi"
- }
- },
- "volumeName": "pv0001"
- },
- "status": {
- "phase": "Bound",
- "accessModes": [
- "ReadWriteOnce"
- ],
- "capacity": {
- "storage": "10Gi"
- }
- }
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume_claims_nil_items.json b/vendor/gems/kubeclient/test/json/persistent_volume_claims_nil_items.json
deleted file mode 100644
index b23ff4dcffd..00000000000
--- a/vendor/gems/kubeclient/test/json/persistent_volume_claims_nil_items.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "kind": "PersistentVolumeClaimList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/persistentvolumeclaims",
- "resourceVersion": "1089012"
- }
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume_list.json b/vendor/gems/kubeclient/test/json/persistent_volume_list.json
deleted file mode 100644
index fa7e53cb914..00000000000
--- a/vendor/gems/kubeclient/test/json/persistent_volume_list.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "kind": "PersistentVolumeList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/persistentvolumes",
- "resourceVersion": "2999"
- },
- "items": [
- {
- "metadata": {
- "name": "pv0001",
- "selfLink": "/api/v1/persistentvolumes/pv0001",
- "uid": "c83eece1-4b38-11e5-8d27-28d2447dcefe",
- "resourceVersion": "1585",
- "creationTimestamp": "2015-08-25T14:51:35Z",
- "labels": {
- "type": "local"
- }
- },
- "spec": {
- "capacity": {
- "storage": "10Gi"
- },
- "hostPath": {
- "path": "/tmp/data01"
- },
- "accessModes": [
- "ReadWriteOnce"
- ],
- "claimRef": {
- "kind": "PersistentVolumeClaim",
- "namespace": "default",
- "name": "myclaim-1",
- "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe",
- "apiVersion": "v1",
- "resourceVersion": "1582"
- },
- "persistentVolumeReclaimPolicy": "Retain"
- },
- "status": {
- "phase": "Bound"
- }
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/pod.json b/vendor/gems/kubeclient/test/json/pod.json
deleted file mode 100644
index 913c2146f6a..00000000000
--- a/vendor/gems/kubeclient/test/json/pod.json
+++ /dev/null
@@ -1,92 +0,0 @@
-{
- "kind": "Pod",
- "apiVersion": "v1",
- "metadata": {
- "name": "redis-master3",
- "namespace": "default",
- "selfLink": "/api/v1/pods/redis-master3?namespace=default",
- "uid": "a344023f-a23c-11e4-a36b-3c970e4a436a",
- "resourceVersion": "9",
- "creationTimestamp": "2015-01-22T15:43:24+02:00",
- "labels": {
- "name": "redis-master"
- }
- },
- "spec": {
- "volumes": null,
- "containers": [
- {
- "name": "master",
- "image": "dockerfile/redis",
- "ports": [
- {
- "hostPort": 6379,
- "containerPort": 6379,
- "protocol": "TCP"
- }
- ],
- "memory": "0",
- "cpu": "100m",
- "imagePullPolicy": ""
- },
- {
- "name": "php-redis",
- "image": "kubernetes/example-guestbook-php-redis",
- "ports": [
- {
- "hostPort": 8000,
- "containerPort": 80,
- "protocol": "TCP"
- }
- ],
- "memory": "50000000",
- "cpu": "100m",
- "imagePullPolicy": ""
- }
- ],
- "restartPolicy": {
- "always": {
-
- }
- },
- "dnsPolicy": "ClusterFirst"
- },
- "status": {
- "phase": "Running",
- "host": "127.0.0.1",
- "podIP": "172.17.0.2",
- "info": {
- "master": {
- "state": {
- "running": {
- "startedAt": "2015-01-22T13:43:29Z"
- }
- },
- "restartCount": 0,
- "containerID": "docker://87458d9a12f9dc9a01b52c1eee5f09cf48939380271c0eaf31af298ce67b125e",
- "image": "dockerfile/redis"
- },
- "net": {
- "state": {
- "running": {
- "startedAt": "2015-01-22T13:43:27Z"
- }
- },
- "restartCount": 0,
- "containerID": "docker://3bb5ced1f831322d370f70b58137e1dd41216c2960b7a99394542b5230cbd259",
- "podIP": "172.17.0.2",
- "image": "kubernetes/pause:latest"
- },
- "php-redis": {
- "state": {
- "running": {
- "startedAt": "2015-01-22T13:43:31Z"
- }
- },
- "restartCount": 0,
- "containerID": "docker://5f08685c0a7a5c974d438a52c6560d72bb0aae7e805d2a34302b9b460f1297c7",
- "image": "kubernetes/example-guestbook-php-redis"
- }
- }
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/pod_list.json b/vendor/gems/kubeclient/test/json/pod_list.json
deleted file mode 100644
index d08bbdce0c0..00000000000
--- a/vendor/gems/kubeclient/test/json/pod_list.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
- "kind": "PodList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/pods",
- "resourceVersion": "1315"
- },
- "items": [
- {
- "metadata": {
- "name": "redis-master3",
- "namespace": "default",
- "selfLink": "/api/v1/pods/redis-master3?namespace=default",
- "uid": "1da148b4-cef5-11e4-ac24-3c970e4a436a",
- "resourceVersion": "1301",
- "creationTimestamp": "2015-03-20T13:34:48+02:00",
- "labels": {
- "mylabel": "mylabelvalue",
- "role": "pod"
- }
- },
- "spec": {
- "volumes": null,
- "containers": [
- {
- "name": "master",
- "image": "dockerfile/redis",
- "ports": [
- {
- "hostPort": 6379,
- "containerPort": 6379,
- "protocol": "TCP"
- }
- ],
- "resources": {
- "limits": {
- "cpu": "100m"
- }
- },
- "terminationMessagePath": "/dev/termination-log",
- "imagePullPolicy": "IfNotPresent",
- "securityContext": {
- "capabilities": {}
- }
- },
- {
- "name": "php-redis",
- "image": "kubernetes/example-guestbook-php-redis",
- "ports": [
- {
- "hostPort": 8000,
- "containerPort": 80,
- "protocol": "TCP"
- }
- ],
- "resources": {
- "limits": {
- "cpu": "100m",
- "memory": "50000000"
- }
- },
- "terminationMessagePath": "/dev/termination-log",
- "imagePullPolicy": "IfNotPresent",
- "securityContext": {
- "capabilities": {}
- }
- }
- ],
- "restartPolicy": {
- "always": {}
- },
- "dnsPolicy": "ClusterFirst"
- },
- "status": {
- "phase": "Pending"
- }
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/pod_template_list.json b/vendor/gems/kubeclient/test/json/pod_template_list.json
deleted file mode 100644
index 5acb2c2f83a..00000000000
--- a/vendor/gems/kubeclient/test/json/pod_template_list.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "kind": "PodTemplateList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/podtemplates",
- "resourceVersion": "672"
- },
- "items": []
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/pods_1.json b/vendor/gems/kubeclient/test/json/pods_1.json
deleted file mode 100644
index ec00bd3b5cc..00000000000
--- a/vendor/gems/kubeclient/test/json/pods_1.json
+++ /dev/null
@@ -1,265 +0,0 @@
-{
- "kind":"PodList",
- "apiVersion":"v1",
- "metadata":{
- "selfLink":"/api/v1/pods",
- "resourceVersion":"53225946",
- "continue":"eyJ2IjoibWV0YS5rOHMua"
- },
- "items":[
- {
- "metadata":{
- "name":"my-ruby-project-2-build",
- "namespace":"my-project",
- "selfLink":"/api/v1/namespaces/my-project/pods/my-ruby-project-2-build",
- "uid":"0c478b50-babb-11e8-ba7e-d094660d31fb",
- "resourceVersion":"42398462",
- "creationTimestamp":"2018-09-17T20:48:36Z",
- "deletionTimestamp":"2018-09-19T13:22:50Z",
- "deletionGracePeriodSeconds":0,
- "labels":{
- "openshift.io/build.name":"my-ruby-project-2"
- },
- "annotations":{
- "openshift.io/build.name":"my-ruby-project-2",
- "openshift.io/scc":"privileged"
- },
- "ownerReferences":[
- {
- "apiVersion":"build.openshift.io/v1",
- "kind":"Build",
- "name":"my-ruby-project-2",
- "uid":"0c450e6d-babb-11e8-ba7e-d094660d31fb",
- "controller":true
- }
- ],
- "finalizers":[
- "foregroundDeletion"
- ]
- },
- "spec":{
- "volumes":[
- {
- "name":"buildworkdir",
- "emptyDir":{
-
- }
- },
- {
- "name":"docker-socket",
- "hostPath":{
- "path":"/var/run/docker.sock",
- "type":""
- }
- },
- {
- "name":"crio-socket",
- "hostPath":{
- "path":"/var/run/crio/crio.sock",
- "type":""
- }
- },
- {
- "name":"builder-dockercfg-rjgnm-push",
- "secret":{
- "secretName":"builder-dockercfg-rjgnm",
- "defaultMode":384
- }
- },
- {
- "name":"builder-token-zkpb6",
- "secret":{
- "secretName":"builder-token-zkpb6",
- "defaultMode":420
- }
- }
- ],
- "containers":[
- {
- "name":"sti-build",
- "image":"openshift3/ose-sti-builder:v3.9.25",
- "command":[
- "openshift-sti-build"
- ]
- }
- ],
- "restartPolicy":"Never",
- "terminationGracePeriodSeconds":30,
- "dnsPolicy":"ClusterFirst",
- "nodeSelector":{
- "node-role.kubernetes.io/compute":"true"
- },
- "serviceAccountName":"builder",
- "serviceAccount":"builder",
- "nodeName":"dell-r430-20.example.com",
- "securityContext":{
-
- },
- "imagePullSecrets":[
- {
- "name":"builder-dockercfg-rjgnm"
- }
- ],
- "schedulerName":"default-scheduler"
- },
- "status":{
- "phase":"Failed",
- "conditions":[
- {
- "type":"Initialized",
- "status":"True",
- "lastProbeTime":null,
- "lastTransitionTime":"2018-09-17T20:48:49Z"
- },
- {
- "type":"Ready",
- "status":"False",
- "lastProbeTime":null,
- "lastTransitionTime":"2018-09-17T20:49:08Z",
- "reason":"ContainersNotReady",
- "message":"containers with unready status: [sti-build]"
- },
- {
- "type":"PodScheduled",
- "status":"True",
- "lastProbeTime":null,
- "lastTransitionTime":"2018-09-17T20:48:36Z"
- }
- ],
- "hostIP":"10.8.96.55",
- "podIP":"10.129.0.207",
- "startTime":"2018-09-17T20:48:36Z",
- "qosClass":"BestEffort"
- }
- },
- {
- "metadata":{
- "name":"redis-1-94zxb",
- "generateName":"redis-1-",
- "namespace":"customer-logging",
- "selfLink":"/api/v1/namespaces/customer-logging/pods/redis-1-94zxb",
- "uid":"a8aea5f4-5f91-11e8-ba7e-d094660d31fb",
- "resourceVersion":"47622190",
- "creationTimestamp":"2018-05-24T20:33:03Z",
- "labels":{
- "app":"elastic-log-ripper",
- "deployment":"redis-1",
- "deploymentconfig":"redis",
- "name":"redis"
- },
- "annotations":{
- "openshift.io/deployment-config.latest-version":"1",
- "openshift.io/deployment-config.name":"redis",
- "openshift.io/deployment.name":"redis-1",
- "openshift.io/generated-by":"OpenShiftNewApp",
- "openshift.io/scc":"restricted"
- },
- "ownerReferences":[
- {
- "apiVersion":"v1",
- "kind":"ReplicationController",
- "name":"redis-1",
- "uid":"9e2e46b3-5f91-11e8-ba7e-d094660d31fb",
- "controller":true,
- "blockOwnerDeletion":true
- }
- ]
- },
- "spec":{
- "volumes":[
- {
- "name":"default-token-n2wzs",
- "secret":{
- "secretName":"default-token-n2wzs",
- "defaultMode":420
- }
- }
- ],
- "containers":[
- {
- "name":"redis",
- "image":"manageiq/redis:latest",
- "ports":[
- {
- "containerPort":6379,
- "protocol":"TCP"
- }
- ],
- "resources":{
-
- },
- "volumeMounts":[
- {
- "name":"default-token-n2wzs",
- "readOnly":true,
- "mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"
- }
- ],
- "terminationMessagePath":"/dev/termination-log",
- "terminationMessagePolicy":"File",
- "imagePullPolicy":"Always",
- "securityContext":{
- "capabilities":{
- "drop":[
- "KILL",
- "MKNOD",
- "SETGID",
- "SETUID"
- ]
- },
- "runAsUser":1000260000
- }
- }
- ],
- "restartPolicy":"Always",
- "terminationGracePeriodSeconds":30,
- "dnsPolicy":"ClusterFirst",
- "nodeSelector":{
- "node-role.kubernetes.io/compute":"true"
- },
- "serviceAccountName":"default",
- "serviceAccount":"default",
- "nodeName":"dell-r430-20.example.com",
- "securityContext":{
- "seLinuxOptions":{
- "level":"s0:c16,c10"
- },
- "fsGroup":1000260000
- },
- "imagePullSecrets":[
- {
- "name":"default-dockercfg-ck286"
- }
- ],
- "schedulerName":"default-scheduler"
- },
- "status":{
- "phase":"Running",
- "conditions":[
- {
- "type":"Initialized",
- "status":"True",
- "lastProbeTime":null,
- "lastTransitionTime":"2018-05-24T20:33:04Z"
- },
- {
- "type":"Ready",
- "status":"True",
- "lastProbeTime":null,
- "lastTransitionTime":"2018-09-18T12:06:18Z"
- },
- {
- "type":"PodScheduled",
- "status":"True",
- "lastProbeTime":null,
- "lastTransitionTime":"2018-05-24T20:33:03Z"
- }
- ],
- "hostIP":"10.8.96.55",
- "podIP":"10.129.0.222",
- "startTime":"2018-05-24T20:33:04Z",
- "qosClass":"BestEffort"
- }
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/pods_2.json b/vendor/gems/kubeclient/test/json/pods_2.json
deleted file mode 100644
index fd6085bc5de..00000000000
--- a/vendor/gems/kubeclient/test/json/pods_2.json
+++ /dev/null
@@ -1,102 +0,0 @@
-{
- "kind":"PodList",
- "apiVersion":"v1",
- "metadata":{
- "selfLink":"/api/v1/pods",
- "resourceVersion":"53226147"
- },
- "items":[
- {
- "metadata":{
- "name":"topological-inventory-persister-9-hznds",
- "generateName":"topological-inventory-persister-9-",
- "namespace":"topological-inventory-ci",
- "selfLink":"/api/v1/namespaces/topological-inventory-ci/pods/topological-inventory-persister-9-hznds",
- "uid":"0c114dde-d865-11e8-ba7e-d094660d31fb",
- "resourceVersion":"51987342",
- "creationTimestamp":"2018-10-25T14:48:34Z",
- "labels":{
- "name":"topological-inventory-persister"
- }
- },
- "spec":{
- "volumes":[
- {
- "name":"default-token-5pdjl",
- "secret":{
- "secretName":"default-token-5pdjl",
- "defaultMode":420
- }
- }
- ],
- "containers":[
- {
- "name":"topological-inventory-persister",
- "image":"docker-registry.default.svc:5000/topological-inventory-ci/topological-inventory-persister@sha256:0f654ea09e749019cf3bcc4b8ee43b8dd813fcbf487843b917cf190213741927",
- "resources":{
- }
- }
- ],
- "restartPolicy":"Always",
- "terminationGracePeriodSeconds":30,
- "dnsPolicy":"ClusterFirst",
- "nodeSelector":{
- "node-role.kubernetes.io/compute":"true"
- },
- "serviceAccountName":"default",
- "serviceAccount":"default",
- "nodeName":"dell-r430-20.example.com",
- "schedulerName":"default-scheduler"
- },
- "status":{
- "phase":"Running",
- "hostIP":"10.8.96.55",
- "podIP":"10.129.1.108",
- "startTime":"2018-10-25T14:48:34Z",
- "qosClass":"BestEffort"
- }
- },
- {
- "metadata":{
- "name":"topological-inventory-persister-9-vzr6h",
- "generateName":"topological-inventory-persister-9-",
- "namespace":"topological-inventory-ci",
- "selfLink":"/api/v1/namespaces/topological-inventory-ci/pods/topological-inventory-persister-9-vzr6h",
- "uid":"3065d8ce-d86a-11e8-ba7e-d094660d31fb",
- "resourceVersion":"51996115",
- "creationTimestamp":"2018-10-25T15:25:22Z",
- "labels":{
- "name":"topological-inventory-persister"
- }
- },
- "spec":{
- "volumes":null,
- "containers":[
- {
- "name":"topological-inventory-persister",
- "image":"docker-registry.default.svc:5000/topological-inventory-ci/topological-inventory-persister@sha256:0f654ea09e749019cf3bcc4b8ee43b8dd813fcbf487843b917cf190213741927",
- "resources":{
- }
- }
- ],
- "restartPolicy":"Always",
- "terminationGracePeriodSeconds":30,
- "dnsPolicy":"ClusterFirst",
- "nodeSelector":{
- "node-role.kubernetes.io/compute":"true"
- },
- "serviceAccountName":"default",
- "serviceAccount":"default",
- "nodeName":"dell-r430-20.example.com",
- "schedulerName":"default-scheduler"
- },
- "status":{
- "phase":"Running",
- "hostIP":"10.8.96.55",
- "podIP":"10.129.1.168",
- "startTime":"2018-10-25T15:25:22Z",
- "qosClass":"BestEffort"
- }
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/pods_410.json b/vendor/gems/kubeclient/test/json/pods_410.json
deleted file mode 100644
index eb1a31937b7..00000000000
--- a/vendor/gems/kubeclient/test/json/pods_410.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "kind":"Status",
- "apiVersion":"v1",
- "metadata":{},
- "status":"Failure",
- "message":"The provided from parameter is too old to display a consistent list result. You must start a new list without the from.",
- "reason":"Expired",
- "code":410
-}
diff --git a/vendor/gems/kubeclient/test/json/processed_template.json b/vendor/gems/kubeclient/test/json/processed_template.json
deleted file mode 100644
index 66c6e32ea70..00000000000
--- a/vendor/gems/kubeclient/test/json/processed_template.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "kind": "Template",
- "apiVersion": "v1",
- "metadata": {
- "name": "my-templtae",
- "namespace": "default",
- "selfLink": "/oapi/v1/namespaces/default/processedtemplates/my-templtae",
- "uid": "2240c61c-8f70-11e5-a806-001a4a231290",
- "resourceVersion": "1399",
- "creationTimestamp": "2015-11-20T10:19:07Z"
- },
- "objects": [
- {
- "apiVersion": "v1",
- "kind": "Service",
- "metadata": {
- "name": "test/my-service"
- }
- }
- ],
- "parameters": [
- {
- "name": "NAME_PREFIX",
- "value": "test/"
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/replication_controller.json b/vendor/gems/kubeclient/test/json/replication_controller.json
deleted file mode 100644
index 26ac7a9a39e..00000000000
--- a/vendor/gems/kubeclient/test/json/replication_controller.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "kind": "ReplicationController",
- "apiVersion": "v1",
- "metadata": {
- "name": "guestbook-controller",
- "namespace": "default",
- "selfLink": "/api/v1/replicationcontrollers/guestbook-controller?namespace=default",
- "uid": "c71aa4c0-a240-11e4-a265-3c970e4a436a",
- "resourceVersion": "8",
- "creationTimestamp": "2015-01-22T16:13:02+02:00",
- "labels": {
- "name": "guestbook"
- }
- },
- "spec": {
- "replicas": 3,
- "selector": {
- "name": "guestbook"
- },
- "template": {
- "metadata": {
- "creationTimestamp": null,
- "labels": {
- "name": "guestbook"
- }
- },
- "spec": {
- "volumes": null,
- "containers": [
- {
- "name": "guestbook",
- "image": "kubernetes/guestbook",
- "ports": [
- {
- "name": "http-server",
- "containerPort": 3000,
- "protocol": "TCP"
- }
- ],
- "memory": "0",
- "cpu": "0m",
- "imagePullPolicy": ""
- }
- ],
- "restartPolicy": {
- "always": {
-
- }
- },
- "dnsPolicy": "ClusterFirst"
- }
- }
- },
- "status": {
- "replicas": 3
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/replication_controller_list.json b/vendor/gems/kubeclient/test/json/replication_controller_list.json
deleted file mode 100644
index b7f2f7bd521..00000000000
--- a/vendor/gems/kubeclient/test/json/replication_controller_list.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "kind": "ReplicationControllerList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/namespaces/default/replicationcontrollers",
- "resourceVersion": "1636"
- },
- "items": [
- {
- "metadata": {
- "name": "redis-master-controller",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/replicationcontrollers/redis-master-controller?namespace=default",
- "uid": "108eb547-cefa-11e4-ac24-3c970e4a436a",
- "resourceVersion": "1631",
- "creationTimestamp": "2015-03-20T14:10:14+02:00",
- "labels": {
- "name": "redis-master"
- }
- },
- "spec": {
- "replicas": 1,
- "selector": {
- "name": "redis-master"
- },
- "template": {
- "metadata": {
- "creationTimestamp": null,
- "labels": {
- "app": "redis",
- "name": "redis-master"
- }
- },
- "spec": {
- "volumes": null,
- "containers": [
- {
- "name": "redis-master",
- "image": "dockerfile/redis",
- "ports": [
- {
- "containerPort": 6379,
- "protocol": "TCP"
- }
- ],
- "resources": {},
- "terminationMessagePath": "/dev/termination-log",
- "imagePullPolicy": "IfNotPresent",
- "securityContext": {
- "capabilities": {}
- }
- }
- ],
- "restartPolicy": {
- "always": {}
- },
- "dnsPolicy": "ClusterFirst"
- }
- }
- },
- "status": {
- "replicas": 1
- }
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/resource_quota.json b/vendor/gems/kubeclient/test/json/resource_quota.json
deleted file mode 100644
index 75b40391d68..00000000000
--- a/vendor/gems/kubeclient/test/json/resource_quota.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "kind": "ResourceQuota",
- "apiVersion": "v1",
- "metadata": {
- "name": "quota",
- "namespace": "quota-example",
- "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/quota",
- "uid": "ab9f24a4-3c43-11e5-8214-0aaeec44370e",
- "resourceVersion": "12919",
- "creationTimestamp": "2015-08-06T14:01:44Z"
- },
- "spec": {
- "hard": {
- "cpu": "20",
- "memory": "1Gi",
- "persistentvolumeclaims": "10",
- "pods": "10",
- "replicationcontrollers": "20",
- "resourcequotas": "1",
- "secrets": "10",
- "services": "5"
- }
- },
- "status": {
- "hard": {
- "cpu": "20",
- "memory": "1Gi",
- "persistentvolumeclaims": "10",
- "pods": "10",
- "replicationcontrollers": "20",
- "resourcequotas": "1",
- "secrets": "10",
- "services": "5"
- },
- "used": {
- "cpu": "0",
- "memory": "0",
- "persistentvolumeclaims": "0",
- "pods": "0",
- "replicationcontrollers": "1",
- "resourcequotas": "1",
- "secrets": "9",
- "services": "0"
- }
- }
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/resource_quota_list.json b/vendor/gems/kubeclient/test/json/resource_quota_list.json
deleted file mode 100644
index 371f3feb649..00000000000
--- a/vendor/gems/kubeclient/test/json/resource_quota_list.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "kind": "ResourceQuotaList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/",
- "resourceVersion": "102452"
- },
- "items": [
- {
- "metadata": {
- "name": "quota",
- "namespace": "quota-example",
- "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/quota",
- "uid": "ab9f24a4-3c43-11e5-8214-0aaeec44370e",
- "resourceVersion": "12919",
- "creationTimestamp": "2015-08-06T14:01:44Z"
- },
- "spec": {
- "hard": {
- "cpu": "20",
- "memory": "1Gi",
- "persistentvolumeclaims": "10",
- "pods": "10",
- "replicationcontrollers": "20",
- "resourcequotas": "1",
- "secrets": "10",
- "services": "5"
- }
- },
- "status": {
- "hard": {
- "cpu": "20",
- "memory": "1Gi",
- "persistentvolumeclaims": "10",
- "pods": "10",
- "replicationcontrollers": "20",
- "resourcequotas": "1",
- "secrets": "10",
- "services": "5"
- },
- "used": {
- "cpu": "0",
- "memory": "0",
- "persistentvolumeclaims": "0",
- "pods": "0",
- "replicationcontrollers": "1",
- "resourcequotas": "1",
- "secrets": "9",
- "services": "0"
- }
- }
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/secret_list.json b/vendor/gems/kubeclient/test/json/secret_list.json
deleted file mode 100644
index bfd7661b390..00000000000
--- a/vendor/gems/kubeclient/test/json/secret_list.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "kind": "SecretList",
- "apiVersion":"v1",
- "metadata":{
- "selfLink":"/api/v1/secrets",
- "resourceVersion":"256788"
- },
- "items": [
- {
- "metadata": {
- "name":"default-token-my2pi",
- "namespace":"default",
- "selfLink":"/api/v1/namespaces/default/secrets/default-token-my2pi",
- "uid":"07b60654-2a65-11e5-a483-0e840567604d",
- "resourceVersion":"11",
- "creationTimestamp":"2015-07-14T20:15:11Z",
- "annotations": {
- "kubernetes.io/service-account.name":"default",
- "kubernetes.io/service-account.uid":"07b350a0-2a65-11e5-a483-0e840567604d"
- }
- },
- "data":{
- "ca.crt":"Y2F0J3MgYXJlIGF3ZXNvbWUK",
- "token":"Y2F0J3MgYXJlIGF3ZXNvbWUK"
- },
- "type":"kubernetes.io/service-account-token"
- },
- {
- "metadata": {
- "name": "test-secret",
- "namespace": "dev",
- "selfLink": "/api/v1/namespaces/dev/secrets/test-secret",
- "uid": "4e38a198-2bcb-11e5-a483-0e840567604d",
- "resourceVersion": "245569",
- "creationTimestamp": "2015-07-16T14:59:49Z"
- },
- "data": {
- "super-secret": "Y2F0J3MgYXJlIGF3ZXNvbWUK"
- },
- "type": "Opaque"
- }
- ]
-}
-
diff --git a/vendor/gems/kubeclient/test/json/security.openshift.io_api_resource_list.json b/vendor/gems/kubeclient/test/json/security.openshift.io_api_resource_list.json
deleted file mode 100644
index 18e2021cff5..00000000000
--- a/vendor/gems/kubeclient/test/json/security.openshift.io_api_resource_list.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "kind": "APIResourceList",
- "apiVersion": "v1",
- "groupVersion": "security.openshift.io/v1",
- "resources": [
- {
- "name": "podsecuritypolicyreviews",
- "singularName": "",
- "namespaced": true,
- "kind": "PodSecurityPolicyReview",
- "verbs": [
- "create"
- ]
- },
- {
- "name": "podsecuritypolicyselfsubjectreviews",
- "singularName": "",
- "namespaced": true,
- "kind": "PodSecurityPolicySelfSubjectReview",
- "verbs": [
- "create"
- ]
- },
- {
- "name": "podsecuritypolicysubjectreviews",
- "singularName": "",
- "namespaced": true,
- "kind": "PodSecurityPolicySubjectReview",
- "verbs": [
- "create"
- ]
- },
- {
- "name": "rangeallocations",
- "singularName": "",
- "namespaced": false,
- "kind": "RangeAllocation",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ]
- },
- {
- "name": "securitycontextconstraints",
- "singularName": "",
- "namespaced": false,
- "kind": "SecurityContextConstraints",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ],
- "shortNames": [
- "scc"
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/security_context_constraint_list.json b/vendor/gems/kubeclient/test/json/security_context_constraint_list.json
deleted file mode 100644
index 1e9d4c474a7..00000000000
--- a/vendor/gems/kubeclient/test/json/security_context_constraint_list.json
+++ /dev/null
@@ -1,375 +0,0 @@
-{
- "kind": "SecurityContextConstraintsList",
- "apiVersion": "security.openshift.io/v1",
- "metadata": {
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints",
- "resourceVersion": "5751"
- },
- "items": [
- {
- "metadata": {
- "name": "anyuid",
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/anyuid",
- "uid": "12ba8540-ef00-11e8-b4c0-68f728fac3ab",
- "resourceVersion": "71",
- "creationTimestamp": "2018-11-23T09:13:42Z",
- "annotations": {
- "kubernetes.io/description": "anyuid provides all features of the restricted SCC but allows users to run with any UID and any GID."
- }
- },
- "priority": 10,
- "allowPrivilegedContainer": false,
- "defaultAddCapabilities": null,
- "requiredDropCapabilities": [
- "MKNOD"
- ],
- "allowedCapabilities": null,
- "allowHostDirVolumePlugin": false,
- "volumes": [
- "configMap",
- "downwardAPI",
- "emptyDir",
- "persistentVolumeClaim",
- "projected",
- "secret"
- ],
- "allowedFlexVolumes": null,
- "allowHostNetwork": false,
- "allowHostPorts": false,
- "allowHostPID": false,
- "allowHostIPC": false,
- "seLinuxContext": {
- "type": "MustRunAs"
- },
- "runAsUser": {
- "type": "RunAsAny"
- },
- "supplementalGroups": {
- "type": "RunAsAny"
- },
- "fsGroup": {
- "type": "RunAsAny"
- },
- "readOnlyRootFilesystem": false,
- "users": [],
- "groups": [
- "system:cluster-admins"
- ]
- },
- {
- "metadata": {
- "name": "hostaccess",
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/hostaccess",
- "uid": "12b5b3a2-ef00-11e8-b4c0-68f728fac3ab",
- "resourceVersion": "69",
- "creationTimestamp": "2018-11-23T09:13:42Z",
- "annotations": {
- "kubernetes.io/description": "hostaccess allows access to all host namespaces but still requires pods to be run with a UID and SELinux context that are allocated to the namespace. WARNING: this SCC allows host access to namespaces, file systems, and PIDS. It should only be used by trusted pods. Grant with caution."
- }
- },
- "priority": null,
- "allowPrivilegedContainer": false,
- "defaultAddCapabilities": null,
- "requiredDropCapabilities": [
- "KILL",
- "MKNOD",
- "SETUID",
- "SETGID"
- ],
- "allowedCapabilities": null,
- "allowHostDirVolumePlugin": true,
- "volumes": [
- "configMap",
- "downwardAPI",
- "emptyDir",
- "hostPath",
- "persistentVolumeClaim",
- "projected",
- "secret"
- ],
- "allowedFlexVolumes": null,
- "allowHostNetwork": true,
- "allowHostPorts": true,
- "allowHostPID": true,
- "allowHostIPC": true,
- "seLinuxContext": {
- "type": "MustRunAs"
- },
- "runAsUser": {
- "type": "MustRunAsRange"
- },
- "supplementalGroups": {
- "type": "RunAsAny"
- },
- "fsGroup": {
- "type": "MustRunAs"
- },
- "readOnlyRootFilesystem": false,
- "users": [],
- "groups": []
- },
- {
- "metadata": {
- "name": "hostmount-anyuid",
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/hostmount-anyuid",
- "uid": "12b512c0-ef00-11e8-b4c0-68f728fac3ab",
- "resourceVersion": "68",
- "creationTimestamp": "2018-11-23T09:13:42Z",
- "annotations": {
- "kubernetes.io/description": "hostmount-anyuid provides all the features of the restricted SCC but allows host mounts and any UID by a pod. This is primarily used by the persistent volume recycler. WARNING: this SCC allows host file system access as any UID, including UID 0. Grant with caution."
- }
- },
- "priority": null,
- "allowPrivilegedContainer": false,
- "defaultAddCapabilities": null,
- "requiredDropCapabilities": [
- "MKNOD"
- ],
- "allowedCapabilities": null,
- "allowHostDirVolumePlugin": true,
- "volumes": [
- "configMap",
- "downwardAPI",
- "emptyDir",
- "hostPath",
- "nfs",
- "persistentVolumeClaim",
- "projected",
- "secret"
- ],
- "allowedFlexVolumes": null,
- "allowHostNetwork": false,
- "allowHostPorts": false,
- "allowHostPID": false,
- "allowHostIPC": false,
- "seLinuxContext": {
- "type": "MustRunAs"
- },
- "runAsUser": {
- "type": "RunAsAny"
- },
- "supplementalGroups": {
- "type": "RunAsAny"
- },
- "fsGroup": {
- "type": "RunAsAny"
- },
- "readOnlyRootFilesystem": false,
- "users": [
- "system:serviceaccount:openshift-infra:pv-recycler-controller"
- ],
- "groups": []
- },
- {
- "metadata": {
- "name": "hostnetwork",
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/hostnetwork",
- "uid": "12bb0984-ef00-11e8-b4c0-68f728fac3ab",
- "resourceVersion": "72",
- "creationTimestamp": "2018-11-23T09:13:42Z",
- "annotations": {
- "kubernetes.io/description": "hostnetwork allows using host networking and host ports but still requires pods to be run with a UID and SELinux context that are allocated to the namespace."
- }
- },
- "priority": null,
- "allowPrivilegedContainer": false,
- "defaultAddCapabilities": null,
- "requiredDropCapabilities": [
- "KILL",
- "MKNOD",
- "SETUID",
- "SETGID"
- ],
- "allowedCapabilities": null,
- "allowHostDirVolumePlugin": false,
- "volumes": [
- "configMap",
- "downwardAPI",
- "emptyDir",
- "persistentVolumeClaim",
- "projected",
- "secret"
- ],
- "allowedFlexVolumes": null,
- "allowHostNetwork": true,
- "allowHostPorts": true,
- "allowHostPID": false,
- "allowHostIPC": false,
- "seLinuxContext": {
- "type": "MustRunAs"
- },
- "runAsUser": {
- "type": "MustRunAsRange"
- },
- "supplementalGroups": {
- "type": "MustRunAs"
- },
- "fsGroup": {
- "type": "MustRunAs"
- },
- "readOnlyRootFilesystem": false,
- "users": [],
- "groups": []
- },
- {
- "metadata": {
- "name": "nonroot",
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/nonroot",
- "uid": "12b37c59-ef00-11e8-b4c0-68f728fac3ab",
- "resourceVersion": "67",
- "creationTimestamp": "2018-11-23T09:13:42Z",
- "annotations": {
- "kubernetes.io/description": "nonroot provides all features of the restricted SCC but allows users to run with any non-root UID. The user must specify the UID or it must be specified on the by the manifest of the container runtime."
- }
- },
- "priority": null,
- "allowPrivilegedContainer": false,
- "defaultAddCapabilities": null,
- "requiredDropCapabilities": [
- "KILL",
- "MKNOD",
- "SETUID",
- "SETGID"
- ],
- "allowedCapabilities": null,
- "allowHostDirVolumePlugin": false,
- "volumes": [
- "configMap",
- "downwardAPI",
- "emptyDir",
- "persistentVolumeClaim",
- "projected",
- "secret"
- ],
- "allowedFlexVolumes": null,
- "allowHostNetwork": false,
- "allowHostPorts": false,
- "allowHostPID": false,
- "allowHostIPC": false,
- "seLinuxContext": {
- "type": "MustRunAs"
- },
- "runAsUser": {
- "type": "MustRunAsNonRoot"
- },
- "supplementalGroups": {
- "type": "RunAsAny"
- },
- "fsGroup": {
- "type": "RunAsAny"
- },
- "readOnlyRootFilesystem": false,
- "users": [],
- "groups": []
- },
- {
- "metadata": {
- "name": "privileged",
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/privileged",
- "uid": "12b18f4a-ef00-11e8-b4c0-68f728fac3ab",
- "resourceVersion": "300",
- "creationTimestamp": "2018-11-23T09:13:42Z",
- "annotations": {
- "kubernetes.io/description": "privileged allows access to all privileged and host features and the ability to run as any user, any group, any fsGroup, and with any SELinux context. WARNING: this is the most relaxed SCC and should be used only for cluster administration. Grant with caution."
- }
- },
- "priority": null,
- "allowPrivilegedContainer": true,
- "defaultAddCapabilities": null,
- "requiredDropCapabilities": null,
- "allowedCapabilities": [
- "*"
- ],
- "allowHostDirVolumePlugin": true,
- "volumes": [
- "*"
- ],
- "allowedFlexVolumes": null,
- "allowHostNetwork": true,
- "allowHostPorts": true,
- "allowHostPID": true,
- "allowHostIPC": true,
- "seLinuxContext": {
- "type": "RunAsAny"
- },
- "runAsUser": {
- "type": "RunAsAny"
- },
- "supplementalGroups": {
- "type": "RunAsAny"
- },
- "fsGroup": {
- "type": "RunAsAny"
- },
- "readOnlyRootFilesystem": false,
- "users": [
- "system:admin",
- "system:serviceaccount:openshift-infra:build-controller",
- "system:serviceaccount:default:pvinstaller",
- "system:serviceaccount:default:registry",
- "system:serviceaccount:default:router"
- ],
- "groups": [
- "system:cluster-admins",
- "system:nodes",
- "system:masters"
- ],
- "seccompProfiles": [
- "*"
- ]
- },
- {
- "metadata": {
- "name": "restricted",
- "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/restricted",
- "uid": "12b9a842-ef00-11e8-b4c0-68f728fac3ab",
- "resourceVersion": "70",
- "creationTimestamp": "2018-11-23T09:13:42Z",
- "annotations": {
- "kubernetes.io/description": "restricted denies access to all host features and requires pods to be run with a UID, and SELinux context that are allocated to the namespace. This is the most restrictive SCC and it is used by default for authenticated users."
- }
- },
- "priority": null,
- "allowPrivilegedContainer": false,
- "defaultAddCapabilities": null,
- "requiredDropCapabilities": [
- "KILL",
- "MKNOD",
- "SETUID",
- "SETGID"
- ],
- "allowedCapabilities": null,
- "allowHostDirVolumePlugin": false,
- "volumes": [
- "configMap",
- "downwardAPI",
- "emptyDir",
- "persistentVolumeClaim",
- "projected",
- "secret"
- ],
- "allowedFlexVolumes": null,
- "allowHostNetwork": false,
- "allowHostPorts": false,
- "allowHostPID": false,
- "allowHostIPC": false,
- "seLinuxContext": {
- "type": "MustRunAs"
- },
- "runAsUser": {
- "type": "MustRunAsRange"
- },
- "supplementalGroups": {
- "type": "RunAsAny"
- },
- "fsGroup": {
- "type": "MustRunAs"
- },
- "readOnlyRootFilesystem": false,
- "users": [],
- "groups": [
- "system:authenticated"
- ]
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/service.json b/vendor/gems/kubeclient/test/json/service.json
deleted file mode 100644
index 6e2e5c79ce1..00000000000
--- a/vendor/gems/kubeclient/test/json/service.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "kind": "Service",
- "apiVersion": "v1",
- "metadata": {
- "name": "redis-slave",
- "namespace": "development",
- "selfLink": "/api/v1/namespaces/development/services/redis-slave",
- "uid": "bdb80a8f-db93-11e4-b293-f8b156af4ae1",
- "resourceVersion": "2815",
- "creationTimestamp": "2015-04-05T13:00:31Z",
- "labels": {
- "name": "redis",
- "role": "slave"
- }
- },
- "spec": {
- "ports": [
- {
- "name": "",
- "protocol": "TCP",
- "port": 6379,
- "targetPort": "redis-server"
- }
- ],
- "selector": {
- "name": "redis",
- "role": "slave"
- },
- "clusterIP": "10.0.0.140",
- "sessionAffinity": "None"
- },
- "status": {}
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/service_account.json b/vendor/gems/kubeclient/test/json/service_account.json
deleted file mode 100644
index 632d429260d..00000000000
--- a/vendor/gems/kubeclient/test/json/service_account.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "ServiceAccount",
- "apiVersion": "v1",
- "metadata": {
- "name": "default",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/serviceaccounts/default",
- "uid": "d3d773f4-6bf0-11e5-843a-525400f8b93e",
- "resourceVersion": "94",
- "creationTimestamp": "2015-10-06T06:09:39Z"
- },
- "secrets": [
- {
- "name": "default-token-6s23q"
- },
- {
- "name": "default-dockercfg-62tf3"
- }
- ],
- "imagePullSecrets": [
- {
- "name": "default-dockercfg-62tf3"
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/service_account_list.json b/vendor/gems/kubeclient/test/json/service_account_list.json
deleted file mode 100644
index 934e729ed08..00000000000
--- a/vendor/gems/kubeclient/test/json/service_account_list.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "kind": "List",
- "apiVersion": "v1",
- "metadata": {},
- "items": [
- {
- "kind": "ServiceAccount",
- "apiVersion": "v1",
- "metadata": {
- "name": "builder",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/serviceaccounts/builder",
- "uid": "d40655f6-6bf0-11e5-843a-525400f8b93e",
- "resourceVersion": "133",
- "creationTimestamp": "2015-10-06T06:09:39Z"
- },
- "secrets": [
- {
- "name": "builder-token-5v6z2"
- },
- {
- "name": "builder-dockercfg-qe2re"
- }
- ],
- "imagePullSecrets": [
- {
- "name": "builder-dockercfg-qe2re"
- }
- ]
- },
- {
- "kind": "ServiceAccount",
- "apiVersion": "v1",
- "metadata": {
- "name": "default",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/serviceaccounts/default",
- "uid": "d3d773f4-6bf0-11e5-843a-525400f8b93e",
- "resourceVersion": "94",
- "creationTimestamp": "2015-10-06T06:09:39Z"
- },
- "secrets": [
- {
- "name": "default-token-6s23q"
- },
- {
- "name": "default-dockercfg-62tf3"
- }
- ],
- "imagePullSecrets": [
- {
- "name": "default-dockercfg-62tf3"
- }
- ]
- },
- {
- "kind": "ServiceAccount",
- "apiVersion": "v1",
- "metadata": {
- "name": "deployer",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/serviceaccounts/deployer",
- "uid": "d41d385e-6bf0-11e5-843a-525400f8b93e",
- "resourceVersion": "137",
- "creationTimestamp": "2015-10-06T06:09:39Z"
- },
- "secrets": [
- {
- "name": "deployer-token-h3i57"
- },
- {
- "name": "deployer-dockercfg-qgjjj"
- }
- ],
- "imagePullSecrets": [
- {
- "name": "deployer-dockercfg-qgjjj"
- }
- ]
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/service_illegal_json_404.json b/vendor/gems/kubeclient/test/json/service_illegal_json_404.json
deleted file mode 100644
index faa82b3aa87..00000000000
--- a/vendor/gems/kubeclient/test/json/service_illegal_json_404.json
+++ /dev/null
@@ -1 +0,0 @@
-404: Page Not Found \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/service_json_patch.json b/vendor/gems/kubeclient/test/json/service_json_patch.json
deleted file mode 100644
index f960242ba4d..00000000000
--- a/vendor/gems/kubeclient/test/json/service_json_patch.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "status" : {},
- "kind" : "Service",
- "apiVersion" : "v1",
- "spec" : {
- "ports" : [
- {
- "targetPort" : 80,
- "nodePort" : 0,
- "port" : 80,
- "protocol" : "TCP"
- }
- ],
- "clusterIP" : "1.2.3.4",
- "type": "LoadBalancer"
- },
- "metadata" : {
- "name" : "my-service",
- "creationTimestamp" : null,
- "namespace" : "development",
- "resourceVersion" : "2",
- "annotations" : {
- "key" : "value"
- }
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/service_list.json b/vendor/gems/kubeclient/test/json/service_list.json
deleted file mode 100644
index f0f97a12c4e..00000000000
--- a/vendor/gems/kubeclient/test/json/service_list.json
+++ /dev/null
@@ -1,97 +0,0 @@
-{
- "kind": "ServiceList",
- "apiVersion": "v1",
- "metadata": {
- "selfLink": "/api/v1/services",
- "resourceVersion": "36727"
- },
- "items": [
- {
- "metadata": {
- "name": "kubernetes",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/services/kubernetes",
- "uid": "b6606490-db86-11e4-b293-f8b156af4ae1",
- "resourceVersion": "6",
- "creationTimestamp": "2015-04-05T11:27:15Z",
- "labels": {
- "component": "apiserver",
- "provider": "kubernetes"
- }
- },
- "spec": {
- "ports": [
- {
- "name": "",
- "protocol": "TCP",
- "port": 443,
- "targetPort": 443
- }
- ],
- "selector": null,
- "clusterIP": "10.0.0.2",
- "sessionAffinity": "None"
- },
- "status": {}
- },
- {
- "metadata": {
- "name": "kubernetes-ro",
- "namespace": "default",
- "selfLink": "/api/v1/namespaces/default/services/kubernetes-ro",
- "uid": "b6606694-db86-11e4-b293-f8b156af4ae1",
- "resourceVersion": "5",
- "creationTimestamp": "2015-04-05T11:27:15Z",
- "labels": {
- "component": "apiserver",
- "provider": "kubernetes"
- }
- },
- "spec": {
- "ports": [
- {
- "name": "",
- "protocol": "TCP",
- "port": 80,
- "targetPort": 80
- }
- ],
- "selector": null,
- "clusterIP": "10.0.0.1",
- "sessionAffinity": "None"
- },
- "status": {}
- },
- {
- "metadata": {
- "name": "redis-slave",
- "namespace": "development",
- "selfLink": "/api/v1/namespaces/development/services/redis-slave",
- "uid": "bdb80a8f-db93-11e4-b293-f8b156af4ae1",
- "resourceVersion": "2815",
- "creationTimestamp": "2015-04-05T13:00:31Z",
- "labels": {
- "name": "redis",
- "role": "slave"
- }
- },
- "spec": {
- "ports": [
- {
- "name": "",
- "protocol": "TCP",
- "port": 6379,
- "targetPort": "redis-server"
- }
- ],
- "selector": {
- "name": "redis",
- "role": "slave"
- },
- "clusterIP": "10.0.0.140",
- "sessionAffinity": "None"
- },
- "status": {}
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/service_merge_patch.json b/vendor/gems/kubeclient/test/json/service_merge_patch.json
deleted file mode 100644
index 5a9cf7dd384..00000000000
--- a/vendor/gems/kubeclient/test/json/service_merge_patch.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "status" : {},
- "kind" : "Service",
- "apiVersion" : "v1",
- "spec" : {
- "ports" : [
- {
- "targetPort" : 80,
- "nodePort" : 0,
- "port" : 80,
- "protocol" : "TCP"
- }
- ],
- "clusterIP" : "1.2.3.4",
- "type": "NodePort"
- },
- "metadata" : {
- "name" : "my-service",
- "creationTimestamp" : null,
- "namespace" : "development",
- "resourceVersion" : "2",
- "annotations" : {
- "key" : "value"
- }
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/service_patch.json b/vendor/gems/kubeclient/test/json/service_patch.json
deleted file mode 100644
index d6c9c29e691..00000000000
--- a/vendor/gems/kubeclient/test/json/service_patch.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "status" : {},
- "kind" : "Service",
- "apiVersion" : "v1",
- "spec" : {
- "ports" : [
- {
- "targetPort" : 80,
- "nodePort" : 0,
- "port" : 80,
- "protocol" : "TCP"
- }
- ],
- "clusterIP" : "1.2.3.4"
- },
- "metadata" : {
- "name" : "my_service",
- "creationTimestamp" : null,
- "namespace" : "development",
- "resourceVersion" : "2",
- "annotations" : {
- "key" : "value"
- }
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/service_update.json b/vendor/gems/kubeclient/test/json/service_update.json
deleted file mode 100644
index 1053d750e60..00000000000
--- a/vendor/gems/kubeclient/test/json/service_update.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "status" : {},
- "kind" : "Service",
- "apiVersion" : "v1",
- "spec" : {
- "ports" : [
- {
- "targetPort" : 80,
- "nodePort" : 0,
- "port" : 80,
- "protocol" : "TCP"
- }
- ],
- "clusterIP" : "1.2.3.4"
- },
- "metadata" : {
- "name" : "my_service",
- "creationTimestamp" : null,
- "namespace" : "default",
- "resourceVersion" : "2"
- }
-}
diff --git a/vendor/gems/kubeclient/test/json/template.json b/vendor/gems/kubeclient/test/json/template.json
deleted file mode 100644
index 85d8bad748e..00000000000
--- a/vendor/gems/kubeclient/test/json/template.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "apiVersion": "template.openshift.io/v1",
- "kind": "Template",
- "metadata": {
- "creationTimestamp": "2018-12-17T16:11:36Z",
- "name": "my-template",
- "namespace": "default",
- "resourceVersion": "21954",
- "selfLink": "/apis/template.openshift.io/v1/namespaces/default/templates/my-template",
- "uid": "6e03e3e6-0216-11e9-b1e0-68f728fac3ab"
- },
- "objects": [
- {
- "apiVersion": "v1",
- "kind": "Service",
- "metadata": {
- "name": "${NAME_PREFIX}my-service"
- }
- }
- ],
- "parameters": [
- {
- "description": "Prefix for names",
- "name": "NAME_PREFIX"
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/template.openshift.io_api_resource_list.json b/vendor/gems/kubeclient/test/json/template.openshift.io_api_resource_list.json
deleted file mode 100644
index 1ba147f795d..00000000000
--- a/vendor/gems/kubeclient/test/json/template.openshift.io_api_resource_list.json
+++ /dev/null
@@ -1,75 +0,0 @@
-{
- "kind": "APIResourceList",
- "apiVersion": "v1",
- "groupVersion": "template.openshift.io/v1",
- "resources": [
- {
- "name": "brokertemplateinstances",
- "singularName": "",
- "namespaced": false,
- "kind": "BrokerTemplateInstance",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ]
- },
- {
- "name": "processedtemplates",
- "singularName": "",
- "namespaced": true,
- "kind": "Template",
- "verbs": [
- "create"
- ]
- },
- {
- "name": "templateinstances",
- "singularName": "",
- "namespaced": true,
- "kind": "TemplateInstance",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ]
- },
- {
- "name": "templateinstances/status",
- "singularName": "",
- "namespaced": true,
- "kind": "TemplateInstance",
- "verbs": [
- "get",
- "patch",
- "update"
- ]
- },
- {
- "name": "templates",
- "singularName": "",
- "namespaced": true,
- "kind": "Template",
- "verbs": [
- "create",
- "delete",
- "deletecollection",
- "get",
- "list",
- "patch",
- "update",
- "watch"
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/template_list.json b/vendor/gems/kubeclient/test/json/template_list.json
deleted file mode 100644
index a0f84ad3e01..00000000000
--- a/vendor/gems/kubeclient/test/json/template_list.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "kind": "TemplateList",
- "apiVersion": "template.openshift.io/v1",
- "metadata": {
- "selfLink": "/apis/template.openshift.io/v1/namespaces/default/templates",
- "resourceVersion": "22758"
- },
- "items": [
- {
- "metadata": {
- "name": "my-template",
- "namespace": "default",
- "selfLink": "/apis/template.openshift.io/v1/namespaces/default/templates/my-template",
- "uid": "6e03e3e6-0216-11e9-b1e0-68f728fac3ab",
- "resourceVersion": "21954",
- "creationTimestamp": "2018-12-17T16:11:36Z"
- },
- "objects": [
- {
- "apiVersion": "v1",
- "kind": "Service",
- "metadata": {
- "name": "${NAME_PREFIX}my-service"
- }
- }
- ],
- "parameters": [
- {
- "name": "NAME_PREFIX",
- "description": "Prefix for names"
- }
- ]
- }
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/versions_list.json b/vendor/gems/kubeclient/test/json/versions_list.json
deleted file mode 100644
index 372e101b6ab..00000000000
--- a/vendor/gems/kubeclient/test/json/versions_list.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "versions": [
- "v1beta3",
- "v1"
- ]
-}
diff --git a/vendor/gems/kubeclient/test/json/watch_stream.json b/vendor/gems/kubeclient/test/json/watch_stream.json
deleted file mode 100644
index aa8f03dd078..00000000000
--- a/vendor/gems/kubeclient/test/json/watch_stream.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1389","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending"}}}
-{"type":"MODIFIED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1390","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending","host":"127.0.0.1"}}}
-{"type":"DELETED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1398","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending","host":"127.0.0.1"}}}
diff --git a/vendor/gems/kubeclient/test/test_common.rb b/vendor/gems/kubeclient/test/test_common.rb
deleted file mode 100644
index 32bf826085d..00000000000
--- a/vendor/gems/kubeclient/test/test_common.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-
-require_relative 'test_helper'
-
-# Unit tests for the common module
-class CommonTest < MiniTest::Test
- class ClientStub
- include Kubeclient::ClientMixin
- end
-
- def client
- @client ||= ClientStub.new
- end
-
- def test_underscore_entity
- %w[
- Pod pod
- Service service
- ReplicationController replication_controller
- Node node
- Event event
- Endpoint endpoint
- Namespace namespace
- Secret secret
- ResourceQuota resource_quota
- LimitRange limit_range
- PersistentVolume persistent_volume
- PersistentVolumeClaim persistent_volume_claim
- ComponentStatus component_status
- ServiceAccount service_account
- Project project
- Route route
- ClusterRoleBinding cluster_role_binding
- Build build
- BuildConfig build_config
- Image image
- ImageStream image_stream
- dogstatsd dogstatsd
- lowerCamelUPPERCase lower_camel_uppercase
- HTTPAPISpecBinding httpapispec_binding
- APIGroup apigroup
- APIGroupList apigroup_list
- APIResourceList apiresource_list
- APIService apiservice
- APIServiceList apiservice_list
- APIVersions apiversions
- OAuthAccessToken oauth_access_token
- OAuthAccessTokenList oauth_access_token_list
- OAuthAuthorizeToken oauth_authorize_token
- OAuthAuthorizeTokenList oauth_authorize_token_list
- OAuthClient oauth_client
- OAuthClientAuthorization oauth_client_authorization
- OAuthClientAuthorizationList oauth_client_authorization_list
- OAuthClientList oauth_client_list
- ].each_slice(2) do |kind, expected_underscore|
- underscore = Kubeclient::ClientMixin.underscore_entity(kind)
- assert_equal(underscore, expected_underscore)
- end
- end
-
- def test_format_datetime_with_string
- value = '2018-04-27T18:30:17.480321984Z'
- formatted = client.send(:format_datetime, value)
- assert_equal(formatted, value)
- end
-
- def test_format_datetime_with_datetime
- value = DateTime.new(2018, 4, 30, 19, 20, 33)
- formatted = client.send(:format_datetime, value)
- assert_equal(formatted, '2018-04-30T19:20:33.000000000+00:00')
- end
-
- def test_format_datetime_with_time
- value = Time.new(2018, 4, 30, 19, 20, 33, 0)
- formatted = client.send(:format_datetime, value)
- assert_equal(formatted, '2018-04-30T19:20:33.000000000+00:00')
- end
-
- def test_parse_definition_with_unconventional_names
- %w[
- PluralPolicy pluralpolicies plural_policy plural_policies
- LatinDatum latindata latin_datum latin_data
- Noseparator noseparators noseparator noseparators
- lowercase lowercases lowercase lowercases
- TestWithDash test-with-dashes test_with_dash test_with_dashes
- TestUnderscore test_underscores test_underscore test_underscores
- TestMismatch other-odd-name testmismatch otheroddname
- MixedDashMinus mixed-dash_minuses mixed_dash_minus mixed_dash_minuses
- SameUptoWordboundary sameup-toword-boundarys sameuptowordboundary sameuptowordboundarys
- ].each_slice(4) do |kind, plural, expected_single, expected_plural|
- method_names = Kubeclient::ClientMixin.parse_definition(kind, plural).method_names
- assert_equal(method_names[0], expected_single)
- assert_equal(method_names[1], expected_plural)
- end
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_common_url_handling.rb b/vendor/gems/kubeclient/test/test_common_url_handling.rb
deleted file mode 100644
index e7798c2f489..00000000000
--- a/vendor/gems/kubeclient/test/test_common_url_handling.rb
+++ /dev/null
@@ -1,160 +0,0 @@
-require_relative 'test_helper'
-
-# URLHandling tests
-class TestCommonUrlHandling < MiniTest::Test
- def test_no_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
- end
-
- def test_with_api_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080/api', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
- end
-
- def test_with_api_path_in_uri_other_version
- client = Kubeclient::Client.new('http://localhost:8080/api', 'v2')
- rest_client = client.rest_client
- assert_equal('v2', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/api/v2', rest_client.url.to_s)
- end
-
- def test_with_api_group_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080/apis/this_is_the_group', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('this_is_the_group/', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/apis/this_is_the_group/v1', rest_client.url.to_s)
- end
-
- def test_with_api_group_path_in_uri_other_version
- client = Kubeclient::Client.new('http://localhost:8080/apis/this_is_the_group', 'v2')
- rest_client = client.rest_client
- assert_equal('v2', client.instance_variable_get(:@api_version))
- assert_equal('this_is_the_group/', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/apis/this_is_the_group/v2', rest_client.url.to_s)
- end
-
- def test_with_api_path_in_uri_trailing_slash
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
- end
-
- def test_with_api_path_in_api
- client = Kubeclient::Client.new('http://localhost:8080/api/but/I/want/a/hidden/k8s/api', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/api/but/I/want/a/hidden/k8s/api/v1', rest_client.url.to_s)
- end
-
- def test_with_api_group_path_in_api
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/but/I/want/a/hidden/k8s/apis/this_is_the_group',
- 'v1'
- )
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('this_is_the_group/', client.instance_variable_get(:@api_group))
- assert_equal(
- 'http://localhost:8080/api/but/I/want/a/hidden/k8s/apis/this_is_the_group/v1',
- rest_client.url.to_s
- )
- end
-
- def test_rancher_with_api_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080/k8s/clusters/c-somerancherID/api', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/k8s/clusters/c-somerancherID/api/v1', rest_client.url.to_s)
- end
-
- def test_rancher_no_api_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080/k8s/clusters/c-somerancherID', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/k8s/clusters/c-somerancherID/api/v1', rest_client.url.to_s)
- end
-
- def test_rancher_no_api_path_in_uri_trailing_slash
- client = Kubeclient::Client.new('http://localhost:8080/k8s/clusters/c-somerancherID/', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/k8s/clusters/c-somerancherID/api/v1', rest_client.url.to_s)
- end
-
- def test_rancher_with_api_path_in_uri_trailing_slash
- client = Kubeclient::Client.new('http://localhost:8080/k8s/clusters/c-somerancherID/api/', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/k8s/clusters/c-somerancherID/api/v1', rest_client.url.to_s)
- end
-
- def test_rancher_with_api_group_in_uri_trailing_slash
- client = Kubeclient::Client.new(
- 'http://localhost:8080/k8s/clusters/c-somerancherID/apis/this_is_the_group',
- 'v1'
- )
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('this_is_the_group/', client.instance_variable_get(:@api_group))
- assert_equal(
- 'http://localhost:8080/k8s/clusters/c-somerancherID/apis/this_is_the_group/v1',
- rest_client.url.to_s
- )
- end
-
- def test_with_openshift_api_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080/oapi', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/oapi/v1', rest_client.url.to_s)
- end
-
- def test_arbitrary_path_with_openshift_api_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080/foobarbaz/oapi', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/foobarbaz/oapi/v1', rest_client.url.to_s)
- end
-
- def test_with_openshift_api_path_in_uri_trailing_slash
- client = Kubeclient::Client.new('http://localhost:8080/oapi/', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/oapi/v1', rest_client.url.to_s)
- end
-
- def test_with_arbitrary_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080/foobarbaz', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/foobarbaz/api/v1', rest_client.url.to_s)
- end
-
- def test_with_arbitrary_and_api_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080/foobarbaz/api', 'v1')
- rest_client = client.rest_client
- assert_equal('v1', client.instance_variable_get(:@api_version))
- assert_equal('', client.instance_variable_get(:@api_group))
- assert_equal('http://localhost:8080/foobarbaz/api/v1', rest_client.url.to_s)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_component_status.rb b/vendor/gems/kubeclient/test/test_component_status.rb
deleted file mode 100644
index 7bb4ca1ad51..00000000000
--- a/vendor/gems/kubeclient/test/test_component_status.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative 'test_helper'
-
-# ComponentStatus tests
-class TestComponentStatus < MiniTest::Test
- def test_get_from_json_v3
- stub_core_api_list
- stub_request(:get, %r{/componentstatuses})
- .to_return(body: open_test_file('component_status.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- component_status = client.get_component_status('etcd-0', 'default')
-
- assert_instance_of(Kubeclient::Resource, component_status)
- assert_equal('etcd-0', component_status.metadata.name)
- assert_equal('Healthy', component_status.conditions[0].type)
- assert_equal('True', component_status.conditions[0].status)
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1',
- times: 1
- )
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/namespaces/default/componentstatuses/etcd-0',
- times: 1
- )
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_config.rb b/vendor/gems/kubeclient/test/test_config.rb
deleted file mode 100644
index d47827e0393..00000000000
--- a/vendor/gems/kubeclient/test/test_config.rb
+++ /dev/null
@@ -1,271 +0,0 @@
-require_relative 'test_helper'
-require 'yaml'
-require 'open3'
-
-# Testing Kubernetes client configuration
-class KubeclientConfigTest < MiniTest::Test
- def test_allinone
- config = Kubeclient::Config.read(config_file('allinone.kubeconfig'))
- assert_equal(['Default'], config.contexts)
- check_context(config.context, ssl: true, custom_ca: true, client_cert: true)
- end
-
- def test_external
- config = Kubeclient::Config.read(config_file('external.kubeconfig'))
- assert_equal(['Default'], config.contexts)
- check_context(config.context, ssl: true, custom_ca: true, client_cert: true)
- end
-
- def test_explicit_secure
- config = Kubeclient::Config.read(config_file('secure.kubeconfig'))
- assert_equal(['Default'], config.contexts)
- # Same as external.kubeconfig, but with explicit `insecure-skip-tls-verify: false`
- check_context(config.context, ssl: true, custom_ca: true, client_cert: true)
- end
-
- def test_external_public_ca
- config = Kubeclient::Config.read(config_file('external-without-ca.kubeconfig'))
- assert_equal(['Default'], config.contexts)
- # Same as external.kubeconfig, no custom CA data (cluster has a publicly trusted cert)
- check_context(config.context, ssl: true, custom_ca: false, client_cert: true)
- end
-
- def test_secure_public_ca
- config = Kubeclient::Config.read(config_file('secure-without-ca.kubeconfig'))
- assert_equal(['Default'], config.contexts)
- # no custom CA data + explicit `insecure-skip-tls-verify: false`
- check_context(config.context, ssl: true, custom_ca: false, client_cert: true)
- end
-
- def test_insecure
- config = Kubeclient::Config.read(config_file('insecure.kubeconfig'))
- assert_equal(['Default'], config.contexts)
- # Has explicit `insecure-skip-tls-verify: false`
- check_context(config.context, ssl: false, custom_ca: false, client_cert: true)
- end
-
- def test_insecure_custom_ca
- config = Kubeclient::Config.read(config_file('insecure-custom-ca.kubeconfig'))
- assert_equal(['Default'], config.contexts)
- # Has explicit `insecure-skip-tls-verify: false`
- check_context(config.context, ssl: false, custom_ca: true, client_cert: true)
- end
-
- def test_allinone_nopath
- yaml = File.read(config_file('allinone.kubeconfig'))
- # A self-contained config shouldn't depend on kcfg_path.
- config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
- assert_equal(['Default'], config.contexts)
- check_context(config.context, ssl: true, custom_ca: true, client_cert: true)
- end
-
- def test_external_nopath
- yaml = File.read(config_file('external.kubeconfig'))
- # kcfg_path = nil should prevent file access
- config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
- assert_raises(StandardError) do
- config.context
- end
- end
-
- def test_external_nopath_absolute
- yaml = File.read(config_file('external.kubeconfig'))
- # kcfg_path = nil should prevent file access, even if absolute path specified
- ca_absolute_path = File.absolute_path(config_file('external-'))
- yaml = yaml.gsub('external-', ca_absolute_path)
- config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
- assert_raises(StandardError) do
- config.context
- end
- end
-
- def test_concatenated_ca
- config = Kubeclient::Config.read(config_file('concatenated-ca.kubeconfig'))
- assert_equal(['Default'], config.contexts)
- check_context(config.context, ssl: true)
- end
-
- def test_nouser
- config = Kubeclient::Config.read(config_file('nouser.kubeconfig'))
- assert_equal(['default/localhost:6443/nouser'], config.contexts)
- check_context(config.context, ssl: true, custom_ca: false, client_cert: false)
- end
-
- def test_user_token
- config = Kubeclient::Config.read(config_file('userauth.kubeconfig'))
- assert_equal(['localhost/system:admin:token', 'localhost/system:admin:userpass'],
- config.contexts)
- context = config.context('localhost/system:admin:token')
- check_context(context, ssl: true, custom_ca: false, client_cert: false)
- assert_equal('0123456789ABCDEF0123456789ABCDEF', context.auth_options[:bearer_token])
- end
-
- def test_user_password
- config = Kubeclient::Config.read(config_file('userauth.kubeconfig'))
- assert_equal(['localhost/system:admin:token', 'localhost/system:admin:userpass'],
- config.contexts)
- context = config.context('localhost/system:admin:userpass')
- check_context(context, ssl: true, custom_ca: false, client_cert: false)
- assert_equal('admin', context.auth_options[:username])
- assert_equal('pAssw0rd123', context.auth_options[:password])
- end
-
- def test_timestamps
- # Test YAML parsing doesn't crash on YAML timestamp syntax.
- Kubeclient::Config.read(config_file('timestamps.kubeconfig'))
- end
-
- def test_user_exec
- token = '0123456789ABCDEF0123456789ABCDEF'
- creds = {
- 'apiVersion': 'client.authentication.k8s.io/v1beta1',
- 'status': {
- 'token': token
- }
- }
-
- config = Kubeclient::Config.read(config_file('execauth.kubeconfig'))
- assert_equal(['localhost/system:admin:exec-search-path',
- 'localhost/system:admin:exec-relative-path',
- 'localhost/system:admin:exec-absolute-path'],
- config.contexts)
-
- # A bare command name in config means search PATH, so it's executed as bare command.
- stub_exec(%r{^example-exec-plugin$}, creds) do
- context = config.context('localhost/system:admin:exec-search-path')
- check_context(context, ssl: true, custom_ca: false, client_cert: false)
- assert_equal(token, context.auth_options[:bearer_token])
- end
-
- # A relative path is taken relative to the dir of the kubeconfig.
- stub_exec(%r{.*config/dir/example-exec-plugin$}, creds) do
- context = config.context('localhost/system:admin:exec-relative-path')
- check_context(context, ssl: true, custom_ca: false, client_cert: false)
- assert_equal(token, context.auth_options[:bearer_token])
- end
-
- # An absolute path is taken as-is.
- stub_exec(%r{^/abs/path/example-exec-plugin$}, creds) do
- context = config.context('localhost/system:admin:exec-absolute-path')
- check_context(context, ssl: true, custom_ca: false, client_cert: false)
- assert_equal(token, context.auth_options[:bearer_token])
- end
- end
-
- def test_user_exec_nopath
- yaml = File.read(config_file('execauth.kubeconfig'))
- config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
- config.contexts.each do |context_name|
- Open3.stub(:capture3, proc { flunk 'should not execute command' }) do
- assert_raises(StandardError) do
- config.context(context_name)
- end
- end
- end
- end
-
- def test_gcp_default_auth
- Kubeclient::GoogleApplicationDefaultCredentials.expects(:token).returns('token1').once
- parsed = load_yaml(config_file('gcpauth.kubeconfig'))
- config = Kubeclient::Config.new(parsed, nil)
- config.context(config.contexts.first)
- end
-
- # Each call to .context() obtains a new token, calling .auth_options doesn't change anything.
- # NOTE: this is not a guarantee, may change, just testing current behavior.
- def test_gcp_default_auth_renew
- Kubeclient::GoogleApplicationDefaultCredentials.expects(:token).returns('token1').once
- parsed = load_yaml(config_file('gcpauth.kubeconfig'))
- config = Kubeclient::Config.new(parsed, nil)
- context = config.context(config.contexts.first)
- assert_equal({ bearer_token: 'token1' }, context.auth_options)
- assert_equal({ bearer_token: 'token1' }, context.auth_options)
-
- Kubeclient::GoogleApplicationDefaultCredentials.expects(:token).returns('token2').once
- context2 = config.context(config.contexts.first)
- assert_equal({ bearer_token: 'token2' }, context2.auth_options)
- assert_equal({ bearer_token: 'token1' }, context.auth_options)
- end
-
- def test_gcp_command_auth
- Kubeclient::GCPCommandCredentials.expects(:token)
- .with('access-token' => '<fake_token>',
- 'cmd-args' => 'config config-helper --format=json',
- 'cmd-path' => '/path/to/gcloud',
- 'expiry' => '2019-04-09 19:26:18 UTC',
- 'expiry-key' => '{.credential.token_expiry}',
- 'token-key' => '{.credential.access_token}')
- .returns('token1')
- .once
- config = Kubeclient::Config.read(config_file('gcpcmdauth.kubeconfig'))
- config.context(config.contexts.first)
- end
-
- def test_oidc_auth_provider
- Kubeclient::OIDCAuthProvider.expects(:token)
- .with('client-id' => 'fake-client-id',
- 'client-secret' => 'fake-client-secret',
- 'id-token' => 'fake-id-token',
- 'idp-issuer-url' => 'https://accounts.google.com',
- 'refresh-token' => 'fake-refresh-token')
- .returns('token1')
- .once
- parsed = YAML.safe_load(File.read(config_file('oidcauth.kubeconfig')))
- config = Kubeclient::Config.new(parsed, nil)
- config.context(config.contexts.first)
- end
-
- private
-
- def check_context(context, ssl: true, custom_ca: true, client_cert: true)
- assert_equal('https://localhost:6443', context.api_endpoint)
- assert_equal('v1', context.api_version)
- assert_equal('default', context.namespace)
- if custom_ca
- assert_kind_of(OpenSSL::X509::Store, context.ssl_options[:cert_store])
- else
- assert_nil(context.ssl_options[:cert_store])
- end
- if client_cert
- assert_kind_of(OpenSSL::X509::Certificate, context.ssl_options[:client_cert])
- assert_kind_of(OpenSSL::PKey::RSA, context.ssl_options[:client_key])
- if custom_ca
- # When certificates expire one way to recreate them is using a k0s single-node cluster:
- # test/config/update_certs_k0s.rb
- assert(context.ssl_options[:cert_store].verify(context.ssl_options[:client_cert]))
- end
- else
- assert_nil(context.ssl_options[:client_cert])
- assert_nil(context.ssl_options[:client_key])
- end
- if ssl
- assert_equal(OpenSSL::SSL::VERIFY_PEER, context.ssl_options[:verify_ssl],
- 'expected VERIFY_PEER')
- else
- assert_equal(OpenSSL::SSL::VERIFY_NONE, context.ssl_options[:verify_ssl],
- 'expected VERIFY_NONE')
- end
- end
-
- def stub_exec(command_regexp, creds)
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- capture3_stub = lambda do |_env, command, *_args|
- assert_match command_regexp, command
- [JSON.dump(creds), nil, st]
- end
-
- Open3.stub(:capture3, capture3_stub) do
- yield
- end
- end
-
- def load_yaml(file_name)
- if RUBY_VERSION >= '2.6'
- YAML.safe_load(File.read(file_name), permitted_classes: [Date, Time])
- else
- YAML.safe_load(File.read(file_name), [Date, Time])
- end
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_endpoint.rb b/vendor/gems/kubeclient/test/test_endpoint.rb
deleted file mode 100644
index ec2cd9306d4..00000000000
--- a/vendor/gems/kubeclient/test/test_endpoint.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative 'test_helper'
-
-# kind: 'Endpoints' entity tests.
-# This is one of the unusual `kind`s that are already plural (https://github.com/kubernetes/kubernetes/issues/8115).
-# We force singular in method names like 'create_endpoint',
-# but `kind` should remain plural as in kubernetes.
-class TestEndpoint < MiniTest::Test
- def test_create_endpoint
- stub_core_api_list
- testing_ep = Kubeclient::Resource.new
- testing_ep.metadata = {}
- testing_ep.metadata.name = 'myendpoint'
- testing_ep.metadata.namespace = 'default'
- testing_ep.subsets = [
- {
- 'addresses' => [{ 'ip' => '172.17.0.25' }],
- 'ports' => [{ 'name' => 'https', 'port' => 6443, 'protocol' => 'TCP' }]
- }
- ]
-
- req_body = '{"metadata":{"name":"myendpoint","namespace":"default"},' \
- '"subsets":[{"addresses":[{"ip":"172.17.0.25"}],"ports":[{"name":"https",' \
- '"port":6443,"protocol":"TCP"}]}],"kind":"Endpoints","apiVersion":"v1"}'
-
- stub_request(:post, 'http://localhost:8080/api/v1/namespaces/default/endpoints')
- .with(body: req_body)
- .to_return(body: open_test_file('created_endpoint.json'), status: 201)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- created_ep = client.create_endpoint(testing_ep)
- assert_equal('Endpoints', created_ep.kind)
- assert_equal('v1', created_ep.apiVersion)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1', as: :parsed_symbolized)
- created_ep = client.create_endpoint(testing_ep)
- assert_equal('Endpoints', created_ep[:kind])
- assert_equal('v1', created_ep[:apiVersion])
- end
-
- def test_get_endpoints
- stub_core_api_list
- stub_request(:get, %r{/endpoints})
- .to_return(body: open_test_file('endpoint_list.json'), status: 200)
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
-
- collection = client.get_endpoints(as: :parsed_symbolized)
- assert_equal('EndpointsList', collection[:kind])
- assert_equal('v1', collection[:apiVersion])
-
- # Stripping of 'List' in collection.kind RecursiveOpenStruct mode only is historic.
- collection = client.get_endpoints
- assert_equal('Endpoints', collection.kind)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_exec_credentials.rb b/vendor/gems/kubeclient/test/test_exec_credentials.rb
deleted file mode 100644
index f0e51827f55..00000000000
--- a/vendor/gems/kubeclient/test/test_exec_credentials.rb
+++ /dev/null
@@ -1,225 +0,0 @@
-require_relative 'test_helper'
-require 'open3'
-
-# Unit tests for the ExecCredentials provider
-class ExecCredentialsTest < MiniTest::Test
- def test_exec_opts_missing
- expected_msg =
- 'exec options are required'
- exception = assert_raises(ArgumentError) do
- Kubeclient::ExecCredentials.run(nil)
- end
- assert_equal(expected_msg, exception.message)
- end
-
- def test_exec_command_missing
- expected_msg =
- 'exec command is required'
- exception = assert_raises(KeyError) do
- Kubeclient::ExecCredentials.run({})
- end
- assert_equal(expected_msg, exception.message)
- end
-
- def test_exec_command_failure
- err = 'Error'
- expected_msg =
- "exec command failed: #{err}"
-
- st = Minitest::Mock.new
- st.expect(:success?, false)
-
- opts = { 'command' => 'dummy' }
-
- Open3.stub(:capture3, [nil, err, st]) do
- exception = assert_raises(RuntimeError) do
- Kubeclient::ExecCredentials.run(opts)
- end
- assert_equal(expected_msg, exception.message)
- end
- end
-
- def test_run_with_token_credentials
- opts = { 'command' => 'dummy' }
-
- credentials = {
- 'token' => '0123456789ABCDEF0123456789ABCDEF'
- }
-
- creds = JSON.dump(
- 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
- 'status' => credentials
- )
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- Open3.stub(:capture3, [creds, nil, st]) do
- assert_equal(credentials, Kubeclient::ExecCredentials.run(opts))
- end
- end
-
- def test_run_with_client_credentials
- opts = { 'command' => 'dummy' }
-
- credentials = {
- 'clientCertificateData' => '0123456789ABCDEF0123456789ABCDEF',
- 'clientKeyData' => '0123456789ABCDEF0123456789ABCDEF'
- }
-
- creds = JSON.dump(
- 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
- 'status' => credentials
- )
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- Open3.stub(:capture3, [creds, nil, st]) do
- assert_equal(credentials, Kubeclient::ExecCredentials.run(opts))
- end
- end
-
- def test_run_with_missing_client_certificate_data
- opts = { 'command' => 'dummy' }
-
- credentials = {
- 'clientKeyData' => '0123456789ABCDEF0123456789ABCDEF'
- }
-
- creds = JSON.dump(
- 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
- 'status' => credentials
- )
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- expected_msg = 'exec plugin didn\'t return client certificate data'
-
- Open3.stub(:capture3, [creds, nil, st]) do
- exception = assert_raises(RuntimeError) do
- Kubeclient::ExecCredentials.run(opts)
- end
- assert_equal(expected_msg, exception.message)
- end
- end
-
- def test_run_with_missing_client_key_data
- opts = { 'command' => 'dummy' }
-
- credentials = {
- 'clientCertificateData' => '0123456789ABCDEF0123456789ABCDEF'
- }
-
- creds = JSON.dump(
- 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
- 'status' => credentials
- )
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- expected_msg = 'exec plugin didn\'t return client key data'
-
- Open3.stub(:capture3, [creds, nil, st]) do
- exception = assert_raises(RuntimeError) do
- Kubeclient::ExecCredentials.run(opts)
- end
- assert_equal(expected_msg, exception.message)
- end
- end
-
- def test_run_with_client_data_and_token
- opts = { 'command' => 'dummy' }
-
- credentials = {
- 'clientCertificateData' => '0123456789ABCDEF0123456789ABCDEF',
- 'clientKeyData' => '0123456789ABCDEF0123456789ABCDEF',
- 'token' => '0123456789ABCDEF0123456789ABCDEF'
- }
-
- creds = JSON.dump(
- 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
- 'status' => credentials
- )
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- expected_msg = 'exec plugin returned both token and client data'
-
- Open3.stub(:capture3, [creds, nil, st]) do
- exception = assert_raises(RuntimeError) do
- Kubeclient::ExecCredentials.run(opts)
- end
- assert_equal(expected_msg, exception.message)
- end
- end
-
- def test_status_missing
- opts = { 'command' => 'dummy' }
-
- creds = JSON.dump('apiVersion' => 'client.authentication.k8s.io/v1alpha1')
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- expected_msg = 'exec plugin didn\'t return a status field'
-
- Open3.stub(:capture3, [creds, nil, st]) do
- exception = assert_raises(RuntimeError) do
- Kubeclient::ExecCredentials.run(opts)
- end
- assert_equal(expected_msg, exception.message)
- end
- end
-
- def test_credentials_missing
- opts = { 'command' => 'dummy' }
-
- creds = JSON.dump(
- 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
- 'status' => {}
- )
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- expected_msg = 'exec plugin didn\'t return a token or client data'
-
- Open3.stub(:capture3, [creds, nil, st]) do
- exception = assert_raises(RuntimeError) do
- Kubeclient::ExecCredentials.run(opts)
- end
- assert_equal(expected_msg, exception.message)
- end
- end
-
- def test_api_version_mismatch
- api_version = 'client.authentication.k8s.io/v1alpha1'
- expected_version = 'client.authentication.k8s.io/v1beta1'
-
- opts = {
- 'command' => 'dummy',
- 'apiVersion' => expected_version
- }
-
- creds = JSON.dump(
- 'apiVersion' => api_version
- )
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- expected_msg = "exec plugin is configured to use API version #{expected_version}," \
- " plugin returned version #{api_version}"
-
- Open3.stub(:capture3, [creds, nil, st]) do
- exception = assert_raises(RuntimeError) do
- Kubeclient::ExecCredentials.run(opts)
- end
- assert_equal(expected_msg, exception.message)
- end
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_gcp_command_credentials.rb b/vendor/gems/kubeclient/test/test_gcp_command_credentials.rb
deleted file mode 100644
index f95b8fd045e..00000000000
--- a/vendor/gems/kubeclient/test/test_gcp_command_credentials.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative 'test_helper'
-require 'open3'
-
-# Unit tests for the GCPCommandCredentials token provider
-class GCPCommandCredentialsTest < MiniTest::Test
- def test_token
- opts = { 'cmd-args' => 'config config-helper --format=json',
- 'cmd-path' => '/path/to/gcloud',
- 'expiry-key' => '{.credential.token_expiry}',
- 'token-key' => '{.credential.access_token}' }
-
- creds = JSON.dump(
- 'credential' => {
- 'access_token' => '9A3A941836F2458175BE18AA1971EBBF47949B07',
- 'token_expiry' => '2019-04-12T15:02:51Z'
- }
- )
-
- st = Minitest::Mock.new
- st.expect(:success?, true)
-
- Open3.stub(:capture3, [creds, nil, st]) do
- assert_equal('9A3A941836F2458175BE18AA1971EBBF47949B07',
- Kubeclient::GCPCommandCredentials.token(opts))
- end
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_google_application_default_credentials.rb b/vendor/gems/kubeclient/test/test_google_application_default_credentials.rb
deleted file mode 100644
index 238ae729c16..00000000000
--- a/vendor/gems/kubeclient/test/test_google_application_default_credentials.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative 'test_helper'
-require 'googleauth'
-
-# Unit tests for the ApplicationDefaultCredentials token provider
-class GoogleApplicationDefaultCredentialsTest < MiniTest::Test
- def test_token
- auth = Minitest::Mock.new
- auth.expect(:apply, nil, [{}])
- auth.expect(:access_token, 'valid_token')
-
- Google::Auth.stub(:get_application_default, auth) do
- assert_equal('valid_token', Kubeclient::GoogleApplicationDefaultCredentials.token)
- end
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_guestbook_go.rb b/vendor/gems/kubeclient/test/test_guestbook_go.rb
deleted file mode 100644
index a50e192a0c5..00000000000
--- a/vendor/gems/kubeclient/test/test_guestbook_go.rb
+++ /dev/null
@@ -1,237 +0,0 @@
-require_relative 'test_helper'
-require 'vcr'
-
-# creation of google's example of guest book
-class CreateGuestbookGo < MiniTest::Test
- def test_create_guestbook_entities
- VCR.configure do |c|
- c.cassette_library_dir = 'test/cassettes'
- c.hook_into(:webmock)
- end
-
- # WebMock.allow_net_connect!
- VCR.use_cassette('kubernetes_guestbook') do # , record: :new_episodes) do
- client = Kubeclient::Client.new('http://10.35.0.23:8080/api/', 'v1')
-
- testing_ns = Kubeclient::Resource.new
- testing_ns.metadata = {}
- testing_ns.metadata.name = 'kubeclient-ns'
-
- # delete in case they existed before so creation can be tested
- delete_namespace(client, testing_ns.metadata.name)
- delete_services(
- client, testing_ns.metadata.name,
- ['guestbook', 'redis-master', 'redis-slave']
- )
- delete_replication_controllers(
- client, testing_ns.metadata.name,
- ['guestbook', 'redis-master', 'redis-slave']
- )
-
- client.create_namespace(testing_ns)
- services = create_services(client, testing_ns.metadata.name)
- replicators = create_replication_controllers(client, testing_ns.metadata.name)
-
- get_namespaces(client)
- get_services(client, testing_ns.metadata.name)
- get_replication_controllers(client, testing_ns.metadata.name)
-
- delete_services(client, testing_ns.metadata.name, services)
- delete_replication_controllers(client, testing_ns.metadata.name, replicators)
-
- client.delete_namespace(testing_ns.metadata.name)
- end
- ensure
- VCR.turn_off!
- end
-
- def delete_namespace(client, namespace_name)
- client.delete_namespace(namespace_name)
- rescue Kubeclient::ResourceNotFoundError => exception
- assert_equal(404, exception.error_code)
- end
-
- def get_namespaces(client)
- namespaces = client.get_namespaces
- assert(true, namespaces.size > 2)
- end
-
- def get_services(client, ns)
- retrieved_services = client.get_services(namespace: ns)
- assert_equal(3, retrieved_services.size)
- end
-
- def get_replication_controllers(client, ns)
- retrieved_replicators = client.get_replication_controllers(namespace: ns)
- assert_equal(3, retrieved_replicators.size)
- end
-
- def create_services(client, ns)
- guestbook_service = client.create_service(guestbook_service(ns))
- redis_service = client.create_service(redis_service(ns))
- redis_slave_service = client.create_service(redis_slave_service(ns))
- [guestbook_service, redis_service, redis_slave_service]
- end
-
- def create_replication_controllers(client, namespace)
- rc = client.create_replication_controller(guestbook_rc(namespace))
- rc2 = client.create_replication_controller(redis_master_rc(namespace))
- rc3 = client.create_replication_controller(redis_slave_rc(namespace))
- [rc, rc2, rc3]
- end
-
- def delete_services(client, namespace, services)
- # if the entity is not found, no need to fail the test
- services.each do |service|
- begin
- if service.instance_of?(Kubeclient::Resource)
- client.delete_service(service.metadata.name, namespace)
- else
- # it's just a string - service name
- client.delete_service(service, namespace)
- end
- rescue Kubeclient::ResourceNotFoundError => exception
- assert_equal(404, exception.error_code)
- end
- end
- end
-
- def delete_replication_controllers(client, namespace, replication_controllers)
- # if the entity is not found, no need to fail the test
- replication_controllers.each do |rc|
- begin
- if rc.instance_of?(Kubeclient::Resource)
- client.delete_replication_controller(rc.metadata.name, namespace)
- else
- # it's just a string - rc name
- client.delete_replication_controller(rc, namespace)
- end
- rescue Kubeclient::ResourceNotFoundError => exception
- assert_equal(404, exception.error_code)
- end
- end
- end
-
- private
-
- def construct_base_rc(namespace)
- rc = Kubeclient::Resource.new
- rc.metadata = {}
- rc.metadata.namespace = namespace
- rc.metadata.labels = {}
- rc.spec = {}
- rc.spec.selector = {}
- rc.spec.template = {}
- rc.spec.template.metadata = {}
- rc.spec.template.spec = {}
- rc.spec.template.metadata.labels = {}
- rc
- end
-
- def redis_master_rc(namespace)
- rc = construct_base_rc(namespace)
- rc.metadata.name = 'redis-master'
- rc.metadata.labels.app = 'redis'
- rc.metadata.labels.role = 'master'
- rc.spec.replicas = 1
- rc.spec.selector.app = 'redis'
- rc.spec.selector.role = 'master'
- rc.spec.template.metadata.labels.app = 'redis'
- rc.spec.template.metadata.labels.role = 'master'
- rc.spec.template.spec.containers = [{
- 'name' => 'redis-master',
- 'image' => 'redis',
- 'ports' => [{
- 'name' => 'redis-server',
- 'containerPort' => 6379
- }]
- }]
- rc
- end
-
- def redis_slave_rc(namespace)
- rc = construct_base_rc(namespace)
- rc.metadata.name = 'redis-slave'
- rc.metadata.labels.app = 'redis'
- rc.metadata.labels.role = 'slave'
- rc.spec.replicas = 2
- rc.spec.selector.app = 'redis'
- rc.spec.selector.role = 'slave'
- rc.spec.template.metadata.labels.app = 'redis'
- rc.spec.template.metadata.labels.role = 'slave'
- rc.spec.template.spec.containers = [{
- 'name' => 'redis-slave',
- 'image' => 'kubernetes/redis-slave:v2',
- 'ports' => [{
- 'name' => 'redis-server',
- 'containerPort' => 6379
- }]
- }]
- rc
- end
-
- def guestbook_rc(namespace)
- rc = construct_base_rc(namespace)
- rc.metadata.name = 'guestbook'
- rc.metadata.labels.app = 'guestbook'
- rc.metadata.labels.role = 'slave'
- rc.spec.replicas = 3
- rc.spec.selector.app = 'guestbook'
- rc.spec.template.metadata.labels.app = 'guestbook'
- rc.spec.template.spec.containers = [
- {
- 'name' => 'guestbook',
- 'image' => 'kubernetes/guestbook:v2',
- 'ports' => [
- {
- 'name' => 'http-server',
- 'containerPort' => 3000
- }
- ]
- }
- ]
- rc
- end
-
- def base_service(namespace)
- our_service = Kubeclient::Resource.new
- our_service.metadata = {}
- our_service.metadata.namespace = namespace
- our_service.metadata.labels = {}
- our_service.spec = {}
- our_service.spec.selector = {}
- our_service
- end
-
- def redis_slave_service(namespace)
- our_service = base_service(namespace)
- our_service.metadata.name = 'redis-slave'
- our_service.metadata.labels.app = 'redis'
- our_service.metadata.labels.role = 'slave'
- our_service.spec.ports = [{ 'port' => 6379, 'targetPort' => 'redis-server' }]
- our_service.spec.selector.app = 'redis'
- our_service.spec.selector.role = 'slave'
- our_service
- end
-
- def redis_service(namespace)
- our_service = base_service(namespace)
- our_service.metadata.name = 'redis-master'
- our_service.metadata.labels.app = 'redis'
- our_service.metadata.labels.role = 'master'
- our_service.spec.ports = [{ 'port' => 6379, 'targetPort' => 'redis-server' }]
- our_service.spec.selector.app = 'redis'
- our_service.spec.selector.role = 'master'
- our_service
- end
-
- def guestbook_service(namespace)
- our_service = base_service(namespace)
- our_service.metadata.name = 'guestbook'
- our_service.metadata.labels.name = 'guestbook'
- our_service.spec.ports = [{ 'port' => 3000, 'targetPort' => 'http-server' }]
- our_service.spec.selector.app = 'guestbook'
- our_service.type = 'LoadBalancer'
- our_service
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_helper.rb b/vendor/gems/kubeclient/test/test_helper.rb
deleted file mode 100644
index 042a08a0d80..00000000000
--- a/vendor/gems/kubeclient/test/test_helper.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'bundler/setup'
-require 'minitest/autorun'
-require 'minitest/rg'
-require 'webmock/minitest'
-require 'mocha/minitest'
-require 'json'
-require 'kubeclient'
-
-MiniTest::Test.class_eval do
- # Assumes test files will be in a subdirectory with the same name as the
- # file suffix. e.g. a file named foo.json would be a "json" subdirectory.
- def open_test_file(name)
- File.new(File.join(File.dirname(__FILE__), name.split('.').last, name))
- end
-
- # kubeconfig files deviate from above convention.
- # They link to relaved certs etc. with various extensions, all in same dir.
- def config_file(name)
- File.join(File.dirname(__FILE__), 'config', name)
- end
-
- def stub_core_api_list
- stub_request(:get, %r{/api/v1$})
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
- end
-end
-
-WebMock.disable_net_connect!
diff --git a/vendor/gems/kubeclient/test/test_kubeclient.rb b/vendor/gems/kubeclient/test/test_kubeclient.rb
deleted file mode 100644
index f866bfc89df..00000000000
--- a/vendor/gems/kubeclient/test/test_kubeclient.rb
+++ /dev/null
@@ -1,881 +0,0 @@
-require_relative 'test_helper'
-
-# Kubernetes client entity tests
-class KubeclientTest < MiniTest::Test
- def test_json
- our_object = Kubeclient::Resource.new
- our_object.foo = 'bar'
- our_object.nested = {}
- our_object.nested.again = {}
- our_object.nested.again.again = {}
- our_object.nested.again.again.name = 'aaron'
-
- expected = {
- 'foo' => 'bar',
- 'nested' => { 'again' => { 'again' => { 'name' => 'aaron' } } }
- }
-
- assert_equal(expected, JSON.parse(JSON.dump(our_object.to_h)))
- end
-
- def test_pass_uri
- # URI::Generic#hostname= was added in ruby 1.9.3 and will automatically
- # wrap an ipv6 address in []
- uri = URI::HTTP.build(port: 8080)
- uri.hostname = 'localhost'
- client = Kubeclient::Client.new(uri)
- rest_client = client.rest_client
- assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
- end
-
- def test_no_path_in_uri
- client = Kubeclient::Client.new('http://localhost:8080', 'v1')
- rest_client = client.rest_client
- assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
- end
-
- def test_no_version_passed
- client = Kubeclient::Client.new('http://localhost:8080')
- rest_client = client.rest_client
- assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
- end
-
- def test_pass_proxy
- uri = URI::HTTP.build(host: 'localhost', port: 8080)
- proxy_uri = URI::HTTP.build(host: 'myproxyhost', port: 8888)
- stub_core_api_list
-
- client = Kubeclient::Client.new(uri, http_proxy_uri: proxy_uri)
- rest_client = client.rest_client
- assert_equal(proxy_uri.to_s, rest_client.options[:proxy])
-
- watch_client = client.watch_pods
- assert_equal(watch_client.send(:build_client_options)[:proxy][:proxy_address], proxy_uri.host)
- assert_equal(watch_client.send(:build_client_options)[:proxy][:proxy_port], proxy_uri.port)
- end
-
- def test_pass_max_redirects
- max_redirects = 0
- client = Kubeclient::Client.new('http://localhost:8080/api/', http_max_redirects: max_redirects)
- rest_client = client.rest_client
- assert_equal(max_redirects, rest_client.options[:max_redirects])
-
- stub_request(:get, 'http://localhost:8080/api')
- .to_return(status: 302, headers: { location: 'http://localhost:1234/api' })
-
- exception = assert_raises(Kubeclient::HttpError) { client.api }
- assert_equal(302, exception.error_code)
- end
-
- def test_exception
- stub_core_api_list
- stub_request(:post, %r{/services})
- .to_return(body: open_test_file('namespace_exception.json'), status: 409)
-
- service = Kubeclient::Resource.new
- service.metadata = {}
- service.metadata.name = 'redisslave'
- service.metadata.namespace = 'default'
- # service.port = 80
- # service.container_port = 6379
- # service.protocol = 'TCP'
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
-
- exception = assert_raises(Kubeclient::HttpError) do
- service = client.create_service(service)
- end
-
- assert_instance_of(Kubeclient::HttpError, exception)
- assert_equal("converting to : type names don't match (Pod, Namespace)",
- exception.message)
-
- assert_includes(exception.to_s, ' for POST http://localhost:8080/api')
- assert_equal(409, exception.error_code)
- end
-
- def test_deprecated_exception
- error_message = 'certificate verify failed'
-
- stub_request(:get, 'http://localhost:8080/api')
- .to_raise(OpenSSL::SSL::SSLError.new(error_message))
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
-
- exception = assert_raises(KubeException) { client.api }
- assert_equal(error_message, exception.message)
- end
-
- def test_api
- stub_request(:get, 'http://localhost:8080/api')
- .to_return(status: 200, body: open_test_file('versions_list.json'))
-
- response = client.api
- assert_includes(response, 'versions')
- end
-
- def test_api_ssl_failure
- error_message = 'certificate verify failed'
-
- stub_request(:get, 'http://localhost:8080/api')
- .to_raise(OpenSSL::SSL::SSLError.new(error_message))
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
-
- exception = assert_raises(Kubeclient::HttpError) { client.api }
- assert_equal(error_message, exception.message)
- end
-
- def test_api_timeout
- stub_request(:get, 'http://localhost:8080/api').to_timeout
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
-
- exception = assert_raises(Kubeclient::HttpError) { client.api }
- assert_match(/(timed out|timeout)/i, exception.message)
- end
-
- def test_api_valid
- stub_request(:get, 'http://localhost:8080/api')
- .to_return(status: 200, body: open_test_file('versions_list.json'))
-
- args = ['http://localhost:8080/api/']
-
- [nil, 'v1beta3', 'v1'].each do |version|
- client = Kubeclient::Client.new(*(version ? args + [version] : args))
- assert client.api_valid?
- end
- end
-
- def test_api_valid_with_invalid_version
- stub_request(:get, 'http://localhost:8080/api')
- .to_return(status: 200, body: open_test_file('versions_list.json'))
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'foobar1')
- refute client.api_valid?
- end
-
- def test_api_valid_with_unreported_versions
- stub_request(:get, 'http://localhost:8080/api')
- .to_return(status: 200, body: '{}')
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- refute client.api_valid?
- end
-
- def test_api_valid_with_invalid_json
- stub_request(:get, 'http://localhost:8080/api')
- .to_return(status: 200, body: '[]')
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- refute client.api_valid?
- end
-
- def test_api_valid_with_bad_endpoint
- stub_request(:get, 'http://localhost:8080/api')
- .to_return(status: [404, 'Resource Not Found'])
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- assert_raises(Kubeclient::HttpError) { client.api_valid? }
- end
-
- def test_api_valid_with_non_json
- stub_request(:get, 'http://localhost:8080/api')
- .to_return(status: 200, body: '<html></html>')
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- assert_raises(JSON::ParserError) { client.api_valid? }
- end
-
- def test_nonjson_exception
- stub_core_api_list
- stub_request(:get, %r{/servic})
- .to_return(body: open_test_file('service_illegal_json_404.json'), status: 404)
-
- exception = assert_raises(Kubeclient::ResourceNotFoundError) do
- client.get_services
- end
-
- assert(exception.message.include?('Not Found'))
- assert_equal(404, exception.error_code)
- end
-
- def test_nonjson_exception_raw
- stub_core_api_list
- stub_request(:get, %r{/servic})
- .to_return(body: open_test_file('service_illegal_json_404.json'), status: 404)
-
- exception = assert_raises(Kubeclient::ResourceNotFoundError) do
- client.get_services(as: :raw)
- end
-
- assert(exception.message.include?('Not Found'))
- assert_equal(404, exception.error_code)
- end
-
- def test_entity_list
- stub_core_api_list
- stub_get_services
-
- services = client.get_services
-
- refute_empty(services)
- assert_instance_of(Kubeclient::Common::EntityList, services)
- # Stripping of 'List' in collection.kind RecursiveOpenStruct mode only is historic.
- assert_equal('Service', services.kind)
- assert_equal(2, services.size)
- assert_instance_of(Kubeclient::Resource, services[0])
- assert_instance_of(Kubeclient::Resource, services[1])
-
- assert_requested(:get, 'http://localhost:8080/api/v1/services', times: 1)
- end
-
- def test_entity_list_raw
- stub_core_api_list
- stub_get_services
-
- response = client.get_services(as: :raw)
-
- refute_empty(response)
- assert_equal(open_test_file('entity_list.json').read, response)
-
- assert_requested(:get, 'http://localhost:8080/api/v1/services', times: 1)
- end
-
- def test_entity_list_parsed
- stub_core_api_list
- stub_get_services
-
- response = client.get_services(as: :parsed)
- assert_equal Hash, response.class
- assert_equal 'ServiceList', response['kind']
- assert_equal %w[metadata spec status], response['items'].first.keys
- end
-
- def test_entity_list_parsed_symbolized
- stub_core_api_list
- stub_get_services
-
- response = client.get_services(as: :parsed_symbolized)
- assert_equal Hash, response.class
- assert_equal 'ServiceList', response[:kind]
- assert_equal %i[metadata spec status], response[:items].first.keys
- end
-
- def test_entity_list_unknown
- stub_core_api_list
- stub_get_services
-
- e = assert_raises(ArgumentError) { client.get_services(as: :whoops) }
- assert_equal 'Unsupported format :whoops', e.message
- end
-
- def test_entity_list_raw_failure
- stub_core_api_list
- stub_request(:get, %r{/services})
- .to_return(body: open_test_file('entity_list.json'), status: 500)
-
- exception = assert_raises(Kubeclient::HttpError) { client.get_services(as: :raw) }
- assert_equal('500 Internal Server Error', exception.message)
- assert_equal(500, exception.error_code)
- end
-
- def test_entities_with_label_selector
- selector = 'component=apiserver'
-
- stub_core_api_list
- stub_get_services
-
- services = client.get_services(label_selector: selector)
-
- assert_instance_of(Kubeclient::Common::EntityList, services)
- assert_requested(
- :get,
- "http://localhost:8080/api/v1/services?labelSelector=#{selector}",
- times: 1
- )
- end
-
- def test_entities_with_resource_version
- version = '329'
-
- stub_core_api_list
- stub_get_services
-
- services = client.get_services(resource_version: version)
-
- assert_instance_of(Kubeclient::Common::EntityList, services)
- assert_requested(
- :get,
- "http://localhost:8080/api/v1/services?resourceVersion=#{version}",
- times: 1
- )
- end
-
- def test_entities_with_field_selector
- selector = 'involvedObject.name=redis-master'
-
- stub_core_api_list
- stub_get_services
-
- services = client.get_services(field_selector: selector)
-
- assert_instance_of(Kubeclient::Common::EntityList, services)
- assert_requested(
- :get,
- "http://localhost:8080/api/v1/services?fieldSelector=#{selector}",
- times: 1
- )
- end
-
- def test_empty_list
- stub_core_api_list
- stub_request(:get, %r{/pods})
- .to_return(body: open_test_file('empty_pod_list.json'), status: 200)
-
- pods = client.get_pods
- assert_instance_of(Kubeclient::Common::EntityList, pods)
- assert_equal(0, pods.size)
- end
-
- def test_get_all
- stub_core_api_list
-
- stub_request(:get, %r{/bindings})
- .to_return(body: open_test_file('bindings_list.json'), status: 404)
-
- stub_request(:get, %r{/configmaps})
- .to_return(body: open_test_file('config_map_list.json'), status: 200)
-
- stub_request(:get, %r{/podtemplates})
- .to_return(body: open_test_file('pod_template_list.json'), status: 200)
-
- stub_request(:get, %r{/services})
- .to_return(body: open_test_file('service_list.json'), status: 200)
-
- stub_request(:get, %r{/pods})
- .to_return(body: open_test_file('pod_list.json'), status: 200)
-
- stub_request(:get, %r{/nodes})
- .to_return(body: open_test_file('node_list.json'), status: 200)
-
- stub_request(:get, %r{/replicationcontrollers})
- .to_return(body: open_test_file('replication_controller_list.json'), status: 200)
-
- stub_request(:get, %r{/events})
- .to_return(body: open_test_file('event_list.json'), status: 200)
-
- stub_request(:get, %r{/endpoints})
- .to_return(body: open_test_file('endpoint_list.json'), status: 200)
-
- stub_request(:get, %r{/namespaces})
- .to_return(body: open_test_file('namespace_list.json'), status: 200)
-
- stub_request(:get, %r{/secrets})
- .to_return(body: open_test_file('secret_list.json'), status: 200)
-
- stub_request(:get, %r{/resourcequotas})
- .to_return(body: open_test_file('resource_quota_list.json'), status: 200)
-
- stub_request(:get, %r{/limitranges})
- .to_return(body: open_test_file('limit_range_list.json'), status: 200)
-
- stub_request(:get, %r{/persistentvolumes})
- .to_return(body: open_test_file('persistent_volume_list.json'), status: 200)
-
- stub_request(:get, %r{/persistentvolumeclaims})
- .to_return(body: open_test_file('persistent_volume_claim_list.json'), status: 200)
-
- stub_request(:get, %r{/componentstatuses})
- .to_return(body: open_test_file('component_status_list.json'), status: 200)
-
- stub_request(:get, %r{/serviceaccounts})
- .to_return(body: open_test_file('service_account_list.json'), status: 200)
-
- result = client.all_entities
- assert_equal(16, result.keys.size)
- assert_instance_of(Kubeclient::Common::EntityList, result['node'])
- assert_instance_of(Kubeclient::Common::EntityList, result['service'])
- assert_instance_of(Kubeclient::Common::EntityList, result['replication_controller'])
- assert_instance_of(Kubeclient::Common::EntityList, result['pod'])
- assert_instance_of(Kubeclient::Common::EntityList, result['event'])
- assert_instance_of(Kubeclient::Common::EntityList, result['namespace'])
- assert_instance_of(Kubeclient::Common::EntityList, result['secret'])
- assert_instance_of(Kubeclient::Resource, result['service'][0])
- assert_instance_of(Kubeclient::Resource, result['node'][0])
- assert_instance_of(Kubeclient::Resource, result['event'][0])
- assert_instance_of(Kubeclient::Resource, result['endpoint'][0])
- assert_instance_of(Kubeclient::Resource, result['namespace'][0])
- assert_instance_of(Kubeclient::Resource, result['secret'][0])
- assert_instance_of(Kubeclient::Resource, result['resource_quota'][0])
- assert_instance_of(Kubeclient::Resource, result['limit_range'][0])
- assert_instance_of(Kubeclient::Resource, result['persistent_volume'][0])
- assert_instance_of(Kubeclient::Resource, result['persistent_volume_claim'][0])
- assert_instance_of(Kubeclient::Resource, result['component_status'][0])
- assert_instance_of(Kubeclient::Resource, result['service_account'][0])
- end
-
- def test_get_all_raw
- stub_core_api_list
-
- stub_request(:get, %r{/bindings})
- .to_return(body: open_test_file('bindings_list.json'), status: 404)
-
- stub_request(:get, %r{/configmaps})
- .to_return(body: open_test_file('config_map_list.json'), status: 200)
-
- stub_request(:get, %r{/podtemplates})
- .to_return(body: open_test_file('pod_template_list.json'), status: 200)
-
- stub_request(:get, %r{/services})
- .to_return(body: open_test_file('service_list.json'), status: 200)
-
- stub_request(:get, %r{/pods})
- .to_return(body: open_test_file('pod_list.json'), status: 200)
-
- stub_request(:get, %r{/nodes})
- .to_return(body: open_test_file('node_list.json'), status: 200)
-
- stub_request(:get, %r{/replicationcontrollers})
- .to_return(body: open_test_file('replication_controller_list.json'), status: 200)
-
- stub_request(:get, %r{/events})
- .to_return(body: open_test_file('event_list.json'), status: 200)
-
- stub_request(:get, %r{/endpoints})
- .to_return(body: open_test_file('endpoint_list.json'), status: 200)
-
- stub_request(:get, %r{/namespaces})
- .to_return(body: open_test_file('namespace_list.json'), status: 200)
-
- stub_request(:get, %r{/secrets})
- .to_return(body: open_test_file('secret_list.json'), status: 200)
-
- stub_request(:get, %r{/resourcequotas})
- .to_return(body: open_test_file('resource_quota_list.json'), status: 200)
-
- stub_request(:get, %r{/limitranges})
- .to_return(body: open_test_file('limit_range_list.json'), status: 200)
-
- stub_request(:get, %r{/persistentvolumes})
- .to_return(body: open_test_file('persistent_volume_list.json'), status: 200)
-
- stub_request(:get, %r{/persistentvolumeclaims})
- .to_return(body: open_test_file('persistent_volume_claim_list.json'), status: 200)
-
- stub_request(:get, %r{/componentstatuses})
- .to_return(body: open_test_file('component_status_list.json'), status: 200)
-
- stub_request(:get, %r{/serviceaccounts})
- .to_return(body: open_test_file('service_account_list.json'), status: 200)
-
- result = client.all_entities(as: :raw)
- assert_equal(16, result.keys.size)
-
- %w[
- component_status config_map endpoint event limit_range namespace node
- persistent_volume persistent_volume_claim pod replication_controller
- resource_quota secret service service_account
- ].each do |entity|
- assert_equal(open_test_file("#{entity}_list.json").read, result[entity])
- end
- end
-
- def test_api_bearer_token_with_params_success
- stub_request(:get, 'http://localhost:8080/api/v1/pods?labelSelector=name=redis-master')
- .with(headers: { Authorization: 'Bearer valid_token' })
- .to_return(body: open_test_file('pod_list.json'), status: 200)
- stub_request(:get, %r{/api/v1$})
- .with(headers: { Authorization: 'Bearer valid_token' })
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
-
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { bearer_token: 'valid_token' }
- )
-
- pods = client.get_pods(label_selector: 'name=redis-master')
-
- assert_equal('Pod', pods.kind)
- assert_equal(1, pods.size)
- end
-
- def test_api_bearer_token_success
- stub_core_api_list
- stub_request(:get, 'http://localhost:8080/api/v1/pods')
- .with(headers: { Authorization: 'Bearer valid_token' })
- .to_return(
- body: open_test_file('pod_list.json'), status: 200
- )
-
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { bearer_token: 'valid_token' }
- )
-
- pods = client.get_pods
-
- assert_equal('Pod', pods.kind)
- assert_equal(1, pods.size)
- end
-
- def test_api_bearer_token_failure
- error_message =
- '"/api/v1" is forbidden because ' \
- 'system:anonymous cannot list on pods in'
- response = OpenStruct.new(code: 401, message: error_message)
-
- stub_request(:get, 'http://localhost:8080/api/v1')
- .with(headers: { Authorization: 'Bearer invalid_token' })
- .to_raise(Kubeclient::HttpError.new(403, error_message, response))
-
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { bearer_token: 'invalid_token' }
- )
-
- exception = assert_raises(Kubeclient::HttpError) { client.get_pods }
- assert_equal(403, exception.error_code)
- assert_equal(error_message, exception.message)
- assert_equal(response, exception.response)
- end
-
- def test_api_bearer_token_failure_raw
- error_message =
- '"/api/v1" is forbidden because ' \
- 'system:anonymous cannot list on pods in'
- response = OpenStruct.new(code: 401, message: error_message)
-
- stub_request(:get, 'http://localhost:8080/api/v1')
- .with(headers: { Authorization: 'Bearer invalid_token' })
- .to_raise(Kubeclient::HttpError.new(403, error_message, response))
-
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { bearer_token: 'invalid_token' }
- )
-
- exception = assert_raises(Kubeclient::HttpError) { client.get_pods(as: :raw) }
- assert_equal(403, exception.error_code)
- assert_equal(error_message, exception.message)
- assert_equal(response, exception.response)
- end
-
- def test_api_basic_auth_success
- stub_request(:get, 'http://localhost:8080/api/v1')
- .with(basic_auth: %w[username password])
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
- stub_request(:get, 'http://localhost:8080/api/v1/pods')
- .with(basic_auth: %w[username password])
- .to_return(body: open_test_file('pod_list.json'), status: 200)
-
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { username: 'username', password: 'password' }
- )
-
- pods = client.get_pods
-
- assert_equal('Pod', pods.kind)
- assert_equal(1, pods.size)
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/pods',
- times: 1
- )
- end
-
- def test_api_basic_auth_back_comp_success
- stub_request(:get, 'http://localhost:8080/api/v1')
- .with(basic_auth: %w[username password])
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
- stub_request(:get, 'http://localhost:8080/api/v1/pods')
- .with(basic_auth: %w[username password])
- .to_return(body: open_test_file('pod_list.json'), status: 200)
-
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { user: 'username', password: 'password' }
- )
-
- pods = client.get_pods
-
- assert_equal('Pod', pods.kind)
- assert_equal(1, pods.size)
- assert_requested(:get, 'http://localhost:8080/api/v1/pods', times: 1)
- end
-
- def test_api_basic_auth_failure
- error_message = 'HTTP status code 401, 401 Unauthorized'
- response = OpenStruct.new(code: 401, message: '401 Unauthorized')
-
- stub_request(:get, 'http://localhost:8080/api/v1')
- .with(basic_auth: %w[username password])
- .to_raise(Kubeclient::HttpError.new(401, error_message, response))
-
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { username: 'username', password: 'password' }
- )
-
- exception = assert_raises(Kubeclient::HttpError) { client.get_pods }
- assert_equal(401, exception.error_code)
- assert_equal(error_message, exception.message)
- assert_equal(response, exception.response)
- assert_requested(:get, 'http://localhost:8080/api/v1', times: 1)
- end
-
- def test_api_basic_auth_failure_raw
- error_message = 'HTTP status code 401, 401 Unauthorized'
- response = OpenStruct.new(code: 401, message: '401 Unauthorized')
-
- stub_request(:get, 'http://localhost:8080/api/v1')
- .with(basic_auth: %w[username password])
- .to_raise(Kubeclient::HttpError.new(401, error_message, response))
-
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { username: 'username', password: 'password' }
- )
-
- exception = assert_raises(Kubeclient::HttpError) { client.get_pods(as: :raw) }
- assert_equal(401, exception.error_code)
- assert_equal(error_message, exception.message)
- assert_equal(response, exception.response)
-
- assert_requested(:get, 'http://localhost:8080/api/v1', times: 1)
- end
-
- def test_init_username_no_password
- expected_msg = 'Basic auth requires both username & password'
- exception = assert_raises(ArgumentError) do
- Kubeclient::Client.new(
- 'http://localhost:8080',
- auth_options: { username: 'username' }
- )
- end
- assert_equal(expected_msg, exception.message)
- end
-
- def test_init_user_no_password
- expected_msg = 'Basic auth requires both username & password'
- exception = assert_raises(ArgumentError) do
- Kubeclient::Client.new(
- 'http://localhost:8080',
- auth_options: { user: 'username' }
- )
- end
- assert_equal(expected_msg, exception.message)
- end
-
- def test_init_username_and_bearer_token
- expected_msg = 'Invalid auth options: specify only one of username/password,' \
- ' bearer_token or bearer_token_file'
- exception = assert_raises(ArgumentError) do
- Kubeclient::Client.new(
- 'http://localhost:8080',
- auth_options: { username: 'username', bearer_token: 'token' }
- )
- end
- assert_equal(expected_msg, exception.message)
- end
-
- def test_init_username_and_bearer_token_file
- expected_msg = 'Invalid auth options: specify only one of username/password,' \
- ' bearer_token or bearer_token_file'
- exception = assert_raises(ArgumentError) do
- Kubeclient::Client.new(
- 'http://localhost:8080',
- auth_options: { username: 'username', bearer_token_file: 'token-file' }
- )
- end
- assert_equal(expected_msg, exception.message)
- end
-
- def test_bearer_token_and_bearer_token_file
- expected_msg =
- 'Invalid auth options: specify only one of username/password,' \
- ' bearer_token or bearer_token_file'
- exception = assert_raises(ArgumentError) do
- Kubeclient::Client.new(
- 'http://localhost:8080',
- auth_options: { bearer_token: 'token', bearer_token_file: 'token-file' }
- )
- end
- assert_equal(expected_msg, exception.message)
- end
-
- def test_bearer_token_file_not_exist
- expected_msg = 'Token file token-file does not exist'
- exception = assert_raises(ArgumentError) do
- Kubeclient::Client.new(
- 'http://localhost:8080',
- auth_options: { bearer_token_file: 'token-file' }
- )
- end
- assert_equal(expected_msg, exception.message)
- end
-
- def test_api_bearer_token_file_success
- stub_core_api_list
- stub_request(:get, 'http://localhost:8080/api/v1/pods')
- .with(headers: { Authorization: 'Bearer valid_token' })
- .to_return(body: open_test_file('pod_list.json'), status: 200)
-
- file = File.join(File.dirname(__FILE__), 'valid_token_file')
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- auth_options: { bearer_token_file: file }
- )
-
- pods = client.get_pods
-
- assert_equal('Pod', pods.kind)
- assert_equal(1, pods.size)
- end
-
- def test_proxy_url
- stub_core_api_list
-
- client = Kubeclient::Client.new('http://host:8080', 'v1')
- assert_equal(
- 'http://host:8080/api/v1/namespaces/ns/services/srvname:srvportname/proxy',
- client.proxy_url('service', 'srvname', 'srvportname', 'ns')
- )
-
- assert_equal(
- 'http://host:8080/api/v1/namespaces/ns/services/srvname:srvportname/proxy',
- client.proxy_url('services', 'srvname', 'srvportname', 'ns')
- )
-
- assert_equal(
- 'http://host:8080/api/v1/namespaces/ns/pods/srvname:srvportname/proxy',
- client.proxy_url('pod', 'srvname', 'srvportname', 'ns')
- )
-
- assert_equal(
- 'http://host:8080/api/v1/namespaces/ns/pods/srvname:srvportname/proxy',
- client.proxy_url('pods', 'srvname', 'srvportname', 'ns')
- )
-
- # Check no namespace provided
- assert_equal(
- 'http://host:8080/api/v1/nodes/srvname:srvportname/proxy',
- client.proxy_url('nodes', 'srvname', 'srvportname')
- )
-
- assert_equal(
- 'http://host:8080/api/v1/nodes/srvname:srvportname/proxy',
- client.proxy_url('node', 'srvname', 'srvportname')
- )
-
- # Check integer port
- assert_equal(
- 'http://host:8080/api/v1/nodes/srvname:5001/proxy',
- client.proxy_url('nodes', 'srvname', 5001)
- )
-
- assert_equal(
- 'http://host:8080/api/v1/nodes/srvname:5001/proxy',
- client.proxy_url('node', 'srvname', 5001)
- )
- end
-
- def test_attr_readers
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- ssl_options: { client_key: 'secret' },
- auth_options: { bearer_token: 'token' }
- )
- assert_equal('/api', client.api_endpoint.path)
- assert_equal('secret', client.ssl_options[:client_key])
- assert_equal('token', client.auth_options[:bearer_token])
- assert_equal('Bearer token', client.headers[:Authorization])
- end
-
- def test_nil_items
- # handle https://github.com/kubernetes/kubernetes/issues/13096
- stub_core_api_list
- stub_request(:get, %r{/persistentvolumeclaims})
- .to_return(body: open_test_file('persistent_volume_claims_nil_items.json'), status: 200)
-
- client.get_persistent_volume_claims
- end
-
- # Timeouts
-
- def test_timeouts_defaults
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/'
- )
- rest_client = client.rest_client
- assert_default_open_timeout(rest_client.open_timeout)
- assert_equal(60, rest_client.read_timeout)
- end
-
- def test_timeouts_open
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- timeouts: { open: 10 }
- )
- rest_client = client.rest_client
- assert_equal(10, rest_client.open_timeout)
- assert_equal(60, rest_client.read_timeout)
- end
-
- def test_timeouts_read
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- timeouts: { read: 300 }
- )
- rest_client = client.rest_client
- assert_default_open_timeout(rest_client.open_timeout)
- assert_equal(300, rest_client.read_timeout)
- end
-
- def test_timeouts_both
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- timeouts: { open: 10, read: 300 }
- )
- rest_client = client.rest_client
- assert_equal(10, rest_client.open_timeout)
- assert_equal(300, rest_client.read_timeout)
- end
-
- def test_timeouts_infinite
- client = Kubeclient::Client.new(
- 'http://localhost:8080/api/',
- timeouts: { open: nil, read: nil }
- )
- rest_client = client.rest_client
- assert_nil(rest_client.open_timeout)
- assert_nil(rest_client.read_timeout)
- end
-
- def assert_default_open_timeout(actual)
- if RUBY_VERSION >= '2.3'
- assert_equal(60, actual)
- else
- assert_nil(actual)
- end
- end
-
- private
-
- def stub_get_services
- stub_request(:get, %r{/services})
- .to_return(body: open_test_file('entity_list.json'), status: 200)
- end
-
- def client
- @client ||= Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- end
-
- # dup method creates a shallow copy which is not good in this case
- # since rename_keys changes the input hash
- # hence need to create a deep_copy
- def deep_copy(hash)
- Marshal.load(Marshal.dump(hash))
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_limit_range.rb b/vendor/gems/kubeclient/test/test_limit_range.rb
deleted file mode 100644
index e9822578e00..00000000000
--- a/vendor/gems/kubeclient/test/test_limit_range.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative 'test_helper'
-
-# LimitRange tests
-class TestLimitRange < MiniTest::Test
- def test_get_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/limitranges})
- .to_return(body: open_test_file('limit_range.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- limit_range = client.get_limit_range('limits', 'quota-example')
-
- assert_instance_of(Kubeclient::Resource, limit_range)
- assert_equal('limits', limit_range.metadata.name)
- assert_equal('Container', limit_range.spec.limits[0].type)
- assert_equal('100m', limit_range.spec.limits[0].default.cpu)
- assert_equal('512Mi', limit_range.spec.limits[0].default.memory)
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/namespaces/quota-example/limitranges/limits',
- times: 1
- )
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_missing_methods.rb b/vendor/gems/kubeclient/test/test_missing_methods.rb
deleted file mode 100644
index 67614c95adc..00000000000
--- a/vendor/gems/kubeclient/test/test_missing_methods.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-require_relative 'test_helper'
-
-# Test method_missing, respond_to? and respond_to_missing behaviour
-class TestMissingMethods < MiniTest::Test
- def test_missing
- stub_core_api_list
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- assert_equal(true, client.respond_to?(:get_pod))
- assert_equal(true, client.respond_to?(:get_pods))
- assert_equal(false, client.respond_to?(:get_pie))
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery
- assert_equal(false, client.respond_to?(:get_pie))
- assert_equal(true, client.respond_to?(:get_pods))
- assert_equal(true, client.respond_to?(:get_pod))
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery
- assert_instance_of(Method, client.method(:get_pods))
- assert_raises(NameError) do
- client.method(:get_pies)
- end
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery
- assert_raises(NameError) do
- client.method(:get_pies)
- end
- assert_instance_of(Method, client.method(:get_pods))
-
- stub_request(:get, %r{/api/v1$}).to_return(
- body: '',
- status: 404
- ) # If discovery fails we expect the below raise an exception
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- assert_raises(Kubeclient::HttpError) do
- client.discover
- end
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- assert_raises(Kubeclient::HttpError) do
- client.method(:get_pods)
- end
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- assert_raises(Kubeclient::HttpError) do
- client.respond_to?(:get_pods)
- end
- end
-
- def test_nonsuffix_plurals
- stub_request(:get, %r{/apis/extensions/v1beta1$}).to_return(
- body: open_test_file('extensions_v1beta1_api_resource_list.json'),
- status: 200
- )
- client = Kubeclient::Client.new('http://localhost:8080/apis/extensions', 'v1beta1')
- assert_equal(true, client.respond_to?(:get_network_policy))
- assert_equal(true, client.respond_to?(:get_network_policies))
- assert_equal(true, client.respond_to?(:get_pod_security_policy))
- assert_equal(true, client.respond_to?(:get_pod_security_policies))
- end
-
- def test_irregular_names
- stub_core_api_list
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- assert_equal(true, client.respond_to?(:get_endpoint))
- assert_equal(true, client.respond_to?(:get_endpoints))
-
- stub_request(:get, %r{/apis/security.openshift.io/v1$}).to_return(
- body: open_test_file('security.openshift.io_api_resource_list.json'),
- status: 200
- )
- client = Kubeclient::Client.new('http://localhost:8080/apis/security.openshift.io', 'v1')
- assert_equal(true, client.respond_to?(:get_security_context_constraint))
- assert_equal(true, client.respond_to?(:get_security_context_constraints))
- end
-
- def test_lowercase_kind
- stub_request(:get, %r{/apis/config.istio.io/v1alpha2$}).to_return(
- body: open_test_file('config.istio.io_api_resource_list.json'),
- status: 200
- )
- client = Kubeclient::Client.new('http://localhost:8080/apis/config.istio.io', 'v1alpha2')
- assert_equal(true, client.respond_to?(:get_servicecontrolreport))
- assert_equal(true, client.respond_to?(:get_servicecontrolreports))
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_namespace.rb b/vendor/gems/kubeclient/test/test_namespace.rb
deleted file mode 100644
index 7283aa69b67..00000000000
--- a/vendor/gems/kubeclient/test/test_namespace.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require_relative 'test_helper'
-
-# Namespace entity tests
-class TestNamespace < MiniTest::Test
- def test_get_namespace_v1
- stub_core_api_list
- stub_request(:get, %r{/namespaces})
- .to_return(body: open_test_file('namespace.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- namespace = client.get_namespace('staging')
-
- assert_instance_of(Kubeclient::Resource, namespace)
- assert_equal('e388bc10-c021-11e4-a514-3c970e4a436a', namespace.metadata.uid)
- assert_equal('staging', namespace.metadata.name)
- assert_equal('1168', namespace.metadata.resourceVersion)
- assert_equal('v1', namespace.apiVersion)
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/namespaces/staging',
- times: 1
- )
- end
-
- def test_delete_namespace_v1
- our_namespace = Kubeclient::Resource.new
- our_namespace.metadata = {}
- our_namespace.metadata.name = 'staging'
-
- stub_core_api_list
- stub_request(:delete, %r{/namespaces})
- .to_return(body: open_test_file('namespace.json'), status: 200)
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- our_namespace = client.delete_namespace(our_namespace.metadata.name)
- assert_kind_of(RecursiveOpenStruct, our_namespace)
-
- assert_requested(
- :delete,
- 'http://localhost:8080/api/v1/namespaces/staging',
- times: 1
- )
- end
-
- def test_create_namespace
- stub_core_api_list
- stub_request(:post, %r{/namespaces})
- .to_return(body: open_test_file('created_namespace.json'), status: 201)
-
- namespace = Kubeclient::Resource.new
- namespace.metadata = {}
- namespace.metadata.name = 'development'
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- created_namespace = client.create_namespace(namespace)
- assert_instance_of(Kubeclient::Resource, created_namespace)
- assert_equal(namespace.metadata.name, created_namespace.metadata.name)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_node.rb b/vendor/gems/kubeclient/test/test_node.rb
deleted file mode 100644
index aa7459d63c9..00000000000
--- a/vendor/gems/kubeclient/test/test_node.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require_relative 'test_helper'
-
-# Node entity tests
-class TestNode < MiniTest::Test
- def test_get_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/nodes})
- .to_return(body: open_test_file('node.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- node = client.get_node('127.0.0.1')
-
- assert_instance_of(Kubeclient::Resource, node)
-
- assert_equal('041143c5-ce39-11e4-ac24-3c970e4a436a', node.metadata.uid)
- assert_equal('127.0.0.1', node.metadata.name)
- assert_equal('1724', node.metadata.resourceVersion)
- assert_equal('v1', node.apiVersion)
- assert_equal('2015-03-19T15:08:20+02:00', node.metadata.creationTimestamp)
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1',
- times: 1
- )
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/nodes/127.0.0.1',
- times: 1
- )
- end
-
- def test_get_from_json_v1_raw
- stub_core_api_list
- stub_request(:get, %r{/nodes})
- .to_return(body: open_test_file('node.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- response = client.get_node('127.0.0.1', nil, as: :raw)
-
- assert_equal(open_test_file('node.json').read, response)
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1',
- times: 1
- )
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/nodes/127.0.0.1',
- times: 1
- )
- end
-
- def test_get_from_json_v1_raw_error
- stub_request(:get, %r{/nodes})
- .to_return(body: open_test_file('node.json'), status: 200)
- stub_request(:get, %r{/api/v1$})
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 500)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
-
- exception = assert_raises(Kubeclient::HttpError) do
- client.get_node('127.0.0.1', nil, as: :raw)
- end
-
- assert_instance_of(Kubeclient::HttpError, exception)
- assert_equal('500 Internal Server Error', exception.message)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_oidc_auth_provider.rb b/vendor/gems/kubeclient/test/test_oidc_auth_provider.rb
deleted file mode 100644
index cdf325e9406..00000000000
--- a/vendor/gems/kubeclient/test/test_oidc_auth_provider.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-require_relative 'test_helper'
-require 'openid_connect'
-
-class OIDCAuthProviderTest < MiniTest::Test
- def setup
- @client_id = 'client_id'
- @client_secret = 'client_secret'
- @idp_issuer_url = 'idp_issuer_url'
- @refresh_token = 'refresh_token'
- @id_token = 'id_token'
- @new_id_token = 'new_id_token'
- end
-
- def test_expired_token
- OpenIDConnect::Discovery::Provider::Config.stub(:discover!, discovery_mock) do
- OpenIDConnect::ResponseObject::IdToken.stub(:decode, id_token_mock(Time.now.to_i - 7200)) do
- OpenIDConnect::Client.stub(:new, openid_client_mock) do
- retrieved_id_token = Kubeclient::OIDCAuthProvider.token(
- 'client-id' => @client_id,
- 'client-secret' => @client_secret,
- 'id-token' => @id_token,
- 'idp-issuer-url' => @idp_issuer_url,
- 'refresh-token' => @refresh_token
- )
- assert_equal(@new_id_token, retrieved_id_token)
- end
- end
- end
- end
-
- def test_valid_token
- OpenIDConnect::Discovery::Provider::Config.stub(:discover!, discovery_mock) do
- OpenIDConnect::ResponseObject::IdToken.stub(:decode, id_token_mock(Time.now.to_i + 7200)) do
- retrieved_id_token = Kubeclient::OIDCAuthProvider.token(
- 'client-id' => @client_id,
- 'client-secret' => @client_secret,
- 'id-token' => @id_token,
- 'idp-issuer-url' => @idp_issuer_url,
- 'refresh-token' => @refresh_token
- )
- assert_equal(@id_token, retrieved_id_token)
- end
- end
- end
-
- def test_missing_id_token
- OpenIDConnect::Discovery::Provider::Config.stub(:discover!, discovery_mock) do
- OpenIDConnect::Client.stub(:new, openid_client_mock) do
- retrieved_id_token = Kubeclient::OIDCAuthProvider.token(
- 'client-id' => @client_id,
- 'client-secret' => @client_secret,
- 'idp-issuer-url' => @idp_issuer_url,
- 'refresh-token' => @refresh_token
- )
- assert_equal(@new_id_token, retrieved_id_token)
- end
- end
- end
-
- def test_token_with_unknown_kid
- OpenIDConnect::Discovery::Provider::Config.stub(:discover!, discovery_mock) do
- OpenIDConnect::ResponseObject::IdToken.stub(
- :decode, ->(_token, _jwks) { raise JSON::JWK::Set::KidNotFound }
- ) do
- OpenIDConnect::Client.stub(:new, openid_client_mock) do
- retrieved_id_token = Kubeclient::OIDCAuthProvider.token(
- 'client-id' => @client_id,
- 'client-secret' => @client_secret,
- 'id-token' => @id_token,
- 'idp-issuer-url' => @idp_issuer_url,
- 'refresh-token' => @refresh_token
- )
- assert_equal(@new_id_token, retrieved_id_token)
- end
- end
- end
- end
-
- private
-
- def openid_client_mock
- access_token = Minitest::Mock.new
- access_token.expect(@id_token, @new_id_token)
-
- openid_client = Minitest::Mock.new
- openid_client.expect(:refresh_token=, nil, [@refresh_token])
- openid_client.expect(:access_token!, access_token)
- end
-
- def id_token_mock(expiry)
- id_token_mock = Minitest::Mock.new
- id_token_mock.expect(:exp, expiry)
- end
-
- def discovery_mock
- discovery = Minitest::Mock.new
- discovery.expect(:jwks, 'jwks')
- discovery.expect(:authorization_endpoint, 'authz_endpoint')
- discovery.expect(:token_endpoint, 'token_endpoint')
- discovery.expect(:userinfo_endpoint, 'userinfo_endpoint')
- discovery
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_persistent_volume.rb b/vendor/gems/kubeclient/test/test_persistent_volume.rb
deleted file mode 100644
index 8b283868a1f..00000000000
--- a/vendor/gems/kubeclient/test/test_persistent_volume.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative 'test_helper'
-
-# PersistentVolume tests
-class TestPersistentVolume < MiniTest::Test
- def test_get_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/persistentvolumes})
- .to_return(body: open_test_file('persistent_volume.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- volume = client.get_persistent_volume('pv0001')
-
- assert_instance_of(Kubeclient::Resource, volume)
- assert_equal('pv0001', volume.metadata.name)
- assert_equal('10Gi', volume.spec.capacity.storage)
- assert_equal('/tmp/data01', volume.spec.hostPath.path)
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1',
- times: 1
- )
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/persistentvolumes/pv0001',
- times: 1
- )
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_persistent_volume_claim.rb b/vendor/gems/kubeclient/test/test_persistent_volume_claim.rb
deleted file mode 100644
index e51d8562e60..00000000000
--- a/vendor/gems/kubeclient/test/test_persistent_volume_claim.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative 'test_helper'
-
-# PersistentVolumeClaim tests
-class TestPersistentVolumeClaim < MiniTest::Test
- def test_get_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/persistentvolumeclaims})
- .to_return(body: open_test_file('persistent_volume_claim.json'), status: 200)
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- claim = client.get_persistent_volume_claim('myclaim-1', 'default')
-
- assert_instance_of(Kubeclient::Resource, claim)
- assert_equal('myclaim-1', claim.metadata.name)
- assert_equal('3Gi', claim.spec.resources.requests.storage)
- assert_equal('pv0001', claim.spec.volumeName)
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1',
- times: 1
- )
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1',
- times: 1
- )
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_pod.rb b/vendor/gems/kubeclient/test/test_pod.rb
deleted file mode 100644
index afad1774f5e..00000000000
--- a/vendor/gems/kubeclient/test/test_pod.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-require_relative 'test_helper'
-
-# Pod entity tests
-class TestPod < MiniTest::Test
- def test_get_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/pods})
- .to_return(body: open_test_file('pod.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- pod = client.get_pod('redis-master-pod', 'default')
-
- assert_instance_of(Kubeclient::Resource, pod)
- assert_equal('redis-master3', pod.metadata.name)
- assert_equal('dockerfile/redis', pod.spec.containers[0]['image'])
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1',
- times: 1
- )
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod',
- times: 1
- )
- end
-
- def test_get_chunks
- stub_core_api_list
- stub_request(:get, %r{/pods})
- .to_return(body: open_test_file('pods_1.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- pods = client.get_pods(limit: 2)
-
- assert_equal(2, pods.count)
- assert_equal('eyJ2IjoibWV0YS5rOHMua', pods.continue)
-
- continue = pods.continue
-
- stub_request(:get, %r{/pods})
- .to_return(body: open_test_file('pods_2.json'), status: 200)
-
- pods = client.get_pods(limit: 2, continue: continue)
- assert_equal(2, pods.count)
- assert_nil(pods.continue)
-
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1',
- times: 1
- )
- assert_requested(
- :get,
- 'http://localhost:8080/api/v1/pods?limit=2',
- times: 1
- )
- assert_requested(
- :get,
- "http://localhost:8080/api/v1/pods?continue=#{continue}&limit=2",
- times: 1
- )
- end
-
- def test_get_chunks_410_gone
- stub_core_api_list
- stub_request(:get, %r{/pods})
- .to_return(body: open_test_file('pods_410.json'), status: 410)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
-
- err = assert_raises Kubeclient::HttpError do
- client.get_pods(limit: 2, continue: 'eyJ2IjoibWV0YS5')
- end
-
- assert_equal(err.message,
- "The provided from parameter is too old to display a consistent list result. \
-You must start a new list without the from.")
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_pod_log.rb b/vendor/gems/kubeclient/test/test_pod_log.rb
deleted file mode 100644
index d9ba3eaabbd..00000000000
--- a/vendor/gems/kubeclient/test/test_pod_log.rb
+++ /dev/null
@@ -1,157 +0,0 @@
-require_relative 'test_helper'
-
-# Pod log tests
-class TestPodLog < MiniTest::Test
- def test_get_pod_log
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
- .to_return(body: open_test_file('pod_log.txt'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- retrieved_log = client.get_pod_log('redis-master-pod', 'default')
-
- assert_equal(open_test_file('pod_log.txt').read, retrieved_log)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log',
- times: 1)
- end
-
- def test_get_pod_log_container
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
- .to_return(body: open_test_file('pod_log.txt'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- retrieved_log = client.get_pod_log('redis-master-pod', 'default', container: 'ruby')
-
- assert_equal(open_test_file('pod_log.txt').read, retrieved_log)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?container=ruby',
- times: 1)
- end
-
- def test_get_pod_log_since_time
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
- .to_return(body: open_test_file('pod_log.txt'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- retrieved_log = client.get_pod_log('redis-master-pod',
- 'default',
- timestamps: true,
- since_time: '2018-04-27T18:30:17.480321984Z')
-
- assert_equal(open_test_file('pod_log.txt').read, retrieved_log)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?sinceTime=2018-04-27T18:30:17.480321984Z&timestamps=true',
- times: 1)
- end
-
- def test_get_pod_log_tail_lines
- selected_lines = open_test_file('pod_log.txt').to_a[-2..1].join
-
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
- .to_return(body: selected_lines,
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- retrieved_log = client.get_pod_log('redis-master-pod',
- 'default',
- tail_lines: 2)
-
- assert_equal(selected_lines, retrieved_log)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?tailLines=2',
- times: 1)
- end
-
- def test_get_pod_limit_bytes
- selected_bytes = open_test_file('pod_log.txt').read(10)
-
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
- .to_return(body: selected_bytes,
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- retrieved_log = client.get_pod_log('redis-master-pod',
- 'default',
- limit_bytes: 10)
-
- assert_equal(selected_bytes, retrieved_log)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?limitBytes=10',
- times: 1)
- end
-
- def test_watch_pod_log
- file = open_test_file('pod_log.txt')
- expected_lines = file.read.split("\n")
-
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow})
- .to_return(body: file, status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
-
- stream = client.watch_pod_log('redis-master-pod', 'default')
- stream.to_enum.with_index do |notice, index|
- assert_instance_of(String, notice)
- assert_equal(expected_lines[index], notice)
- end
- end
-
- def test_watch_pod_log_with_block
- file = open_test_file('pod_log.txt')
- first = file.readlines.first.chomp
-
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow})
- .to_return(body: file, status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
-
- client.watch_pod_log('redis-master-pod', 'default') do |line|
- assert_equal first, line
- break
- end
- end
-
- def test_watch_pod_log_follow_redirect
- expected_lines = open_test_file('pod_log.txt').read.split("\n")
- redirect = 'http://localhost:1234/api/namespaces/default/pods/redis-master-pod/log'
-
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow})
- .to_return(status: 302, headers: { location: redirect })
-
- stub_request(:get, redirect)
- .to_return(body: open_test_file('pod_log.txt'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- stream = client.watch_pod_log('redis-master-pod', 'default')
- stream.to_enum.with_index do |notice, index|
- assert_instance_of(String, notice)
- assert_equal(expected_lines[index], notice)
- end
- end
-
- def test_watch_pod_log_max_redirect
- redirect = 'http://localhost:1234/api/namespaces/default/pods/redis-master-pod/log'
-
- stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow})
- .to_return(status: 302, headers: { location: redirect })
-
- stub_request(:get, redirect)
- .to_return(body: open_test_file('pod_log.txt'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1', http_max_redirects: 0)
- assert_raises(Kubeclient::HttpError) do
- client.watch_pod_log('redis-master-pod', 'default').each do
- end
- end
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_process_template.rb b/vendor/gems/kubeclient/test/test_process_template.rb
deleted file mode 100644
index e3b4670fb87..00000000000
--- a/vendor/gems/kubeclient/test/test_process_template.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-require_relative 'test_helper'
-
-# Process Template tests
-class TestProcessTemplate < MiniTest::Test
- def test_process_template
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- template = {}
- template[:metadata] = {}
- template[:metadata][:name] = 'my-template'
- template[:metadata][:namespace] = 'default'
- template[:kind] = 'Template'
- template[:apiVersion] = 'v1'
- service = {}
- service[:metadata] = {}
- service[:metadata][:name] = '${NAME_PREFIX}my-service'
- service[:kind] = 'Service'
- service[:apiVersion] = 'v1'
- template[:objects] = [service]
- param = { name: 'NAME_PREFIX', value: 'test/' }
- template[:parameters] = [param]
-
- req_body = '{"metadata":{"name":"my-template","namespace":"default"},' \
- '"kind":"Template","apiVersion":"v1","objects":[{"metadata":' \
- '{"name":"${NAME_PREFIX}my-service"},"kind":"Service","apiVersion":"v1"}],' \
- '"parameters":[{"name":"NAME_PREFIX","value":"test/"}]}'
-
- expected_url = 'http://localhost:8080/api/v1/namespaces/default/processedtemplates'
- stub_request(:post, expected_url)
- .with(body: req_body, headers: { 'Content-Type' => 'application/json' })
- .to_return(body: open_test_file('processed_template.json'), status: 200)
-
- processed_template = client.process_template(template)
-
- assert_equal('test/my-service', processed_template['objects'].first['metadata']['name'])
-
- assert_requested(:post, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- data['kind'] == 'Template' &&
- data['apiVersion'] == 'v1' &&
- data['metadata']['name'] == 'my-template' &&
- data['metadata']['namespace'] == 'default'
- end
- end
-
- # Ensure _template and _templates methods hit `/templates` rather than
- # `/processedtemplates` URL.
- def test_templates_methods
- stub_request(:get, %r{/apis/template\.openshift\.io/v1$}).to_return(
- body: open_test_file('template.openshift.io_api_resource_list.json'),
- status: 200
- )
- client = Kubeclient::Client.new('http://localhost:8080/apis/template.openshift.io', 'v1')
-
- expected_url = 'http://localhost:8080/apis/template.openshift.io/v1/namespaces/default/templates'
- stub_request(:get, expected_url)
- .to_return(body: open_test_file('template_list.json'), status: 200)
- client.get_templates(namespace: 'default')
- assert_requested(:get, expected_url, times: 1)
-
- expected_url = 'http://localhost:8080/apis/template.openshift.io/v1/namespaces/default/templates/my-template'
- stub_request(:get, expected_url)
- .to_return(body: open_test_file('template.json'), status: 200)
- client.get_template('my-template', 'default')
- assert_requested(:get, expected_url, times: 1)
- end
-
- def test_no_processedtemplates_methods
- stub_request(:get, %r{/apis/template\.openshift\.io/v1$}).to_return(
- body: open_test_file('template.openshift.io_api_resource_list.json'),
- status: 200
- )
- client = Kubeclient::Client.new('http://localhost:8080/apis/template.openshift.io', 'v1')
- client.discover
-
- refute_respond_to(client, :get_processedtemplates)
- refute_respond_to(client, :get_processedtemplate)
- refute_respond_to(client, :get_processed_templates)
- refute_respond_to(client, :get_processed_template)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_real_cluster.rb b/vendor/gems/kubeclient/test/test_real_cluster.rb
deleted file mode 100644
index 7ce9493a1bb..00000000000
--- a/vendor/gems/kubeclient/test/test_real_cluster.rb
+++ /dev/null
@@ -1,162 +0,0 @@
-require_relative 'test_helper'
-
-class KubeclientRealClusterTest < MiniTest::Test
- # Tests here actually connect to a cluster!
- # For simplicity, these tests use same config/*.kubeconfig files as test_config.rb,
- # so are intended to run from config/update_certs_k0s.rb script.
- def setup
- if ENV['KUBECLIENT_TEST_REAL_CLUSTER'] == 'true'
- WebMock.enable_net_connect!
- else
- skip('Requires real cluster, see test/config/update_certs_k0s.rb.')
- end
- end
-
- def teardown
- WebMock.disable_net_connect! # Don't allow any connections in other tests.
- end
-
- # Partially isolated tests that check Client behavior with given `verify_ssl` value:
-
- # localhost and 127.0.0.1 are among names on the certificate
- HOSTNAME_COVERED_BY_CERT = 'https://127.0.0.1:6443'.freeze
- # 127.0.0.2 also means localhost but is not included in the certificate.
- HOSTNAME_NOT_ON_CERT = 'https://127.0.0.2:6443'.freeze
-
- def test_real_cluster_verify_peer
- config = Kubeclient::Config.read(config_file('external.kubeconfig'))
- context = config.context
- client1 = Kubeclient::Client.new(
- HOSTNAME_COVERED_BY_CERT, 'v1',
- ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_PEER),
- auth_options: context.auth_options
- )
- check_cert_accepted(client1)
- client2 = Kubeclient::Client.new(
- HOSTNAME_NOT_ON_CERT, 'v1',
- ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_PEER),
- auth_options: context.auth_options
- )
- check_cert_rejected(client2)
- end
-
- def test_real_cluster_verify_none
- config = Kubeclient::Config.read(config_file('external.kubeconfig'))
- context = config.context
- client1 = Kubeclient::Client.new(
- HOSTNAME_COVERED_BY_CERT, 'v1',
- ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_NONE),
- auth_options: context.auth_options
- )
- check_cert_accepted(client1)
- client2 = Kubeclient::Client.new(
- HOSTNAME_NOT_ON_CERT, 'v1',
- ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_NONE),
- auth_options: context.auth_options
- )
- check_cert_accepted(client2)
- end
-
- # Integration tests that check combined Config -> Client behavior wrt. `verify_ssl`.
- # Quite redundant, but this was an embarrasing vulnerability so want to confirm...
-
- def test_real_cluster_concatenated_ca
- config = Kubeclient::Config.read(config_file('concatenated-ca.kubeconfig'))
- context = config.context
- client1 = Kubeclient::Client.new(
- HOSTNAME_COVERED_BY_CERT, 'v1',
- ssl_options: context.ssl_options, auth_options: context.auth_options
- )
- check_cert_accepted(client1)
- client2 = Kubeclient::Client.new(
- HOSTNAME_NOT_ON_CERT, 'v1',
- ssl_options: context.ssl_options, auth_options: context.auth_options
- )
- check_cert_rejected(client2)
- end
-
- def test_real_cluster_verify_ssl_with_ca
- config = Kubeclient::Config.read(config_file('external.kubeconfig'))
- context = config.context
- client1 = Kubeclient::Client.new(
- HOSTNAME_COVERED_BY_CERT, 'v1',
- ssl_options: context.ssl_options, auth_options: context.auth_options
- )
- check_cert_accepted(client1)
- client2 = Kubeclient::Client.new(
- HOSTNAME_NOT_ON_CERT, 'v1',
- ssl_options: context.ssl_options, auth_options: context.auth_options
- )
- check_cert_rejected(client2)
- end
-
- def test_real_cluster_verify_ssl_without_ca
- config = Kubeclient::Config.read(config_file('external-without-ca.kubeconfig'))
- context = config.context
- # Hostname matches cert but the local cluster uses self-signed certs from custom CA,
- # and this config omits CA data, so verification can't succeed.
- client1 = Kubeclient::Client.new(
- HOSTNAME_COVERED_BY_CERT, 'v1',
- ssl_options: context.ssl_options, auth_options: context.auth_options
- )
- check_cert_rejected(client1)
- client2 = Kubeclient::Client.new(
- HOSTNAME_NOT_ON_CERT, 'v1',
- ssl_options: context.ssl_options, auth_options: context.auth_options
- )
- check_cert_rejected(client2)
- end
-
- def test_real_cluster_insecure_without_ca
- config = Kubeclient::Config.read(config_file('insecure.kubeconfig'))
- context = config.context
- # Hostname matches cert but the local cluster uses self-signed certs from custom CA,
- # and this config omits CA data, so verification would fail;
- # however, this config specifies `insecure-skip-tls-verify: true` so any cert goes.
- client1 = Kubeclient::Client.new(
- HOSTNAME_COVERED_BY_CERT, 'v1',
- ssl_options: context.ssl_options, auth_options: context.auth_options
- )
- check_cert_accepted(client1)
- client2 = Kubeclient::Client.new(
- HOSTNAME_NOT_ON_CERT, 'v1',
- ssl_options: context.ssl_options, auth_options: context.auth_options
- )
- check_cert_accepted(client2)
- end
-
- private
-
- # Test cert checking on discovery, CRUD, and watch code paths.
- def check_cert_accepted(client)
- client.discover
- client.get_nodes
- exercise_watcher_with_timeout(client.watch_nodes)
- end
-
- def check_cert_rejected(client)
- # TODO: all OpenSSL exceptions should be wrapped with Kubeclient error.
- assert_raises(Kubeclient::HttpError, OpenSSL::SSL::SSLError) do
- client.discover
- end
- # Since discovery fails, methods like .get_nodes, .watch_nodes would all fail
- # on method_missing -> discover. Call lower-level methods to test actual connection.
- assert_raises(Kubeclient::HttpError, OpenSSL::SSL::SSLError) do
- client.get_entities('Node', 'nodes', {})
- end
- assert_raises(Kubeclient::HttpError, OpenSSL::SSL::SSLError) do
- exercise_watcher_with_timeout(client.watch_entities('nodes'))
- end
- end
-
- def exercise_watcher_with_timeout(watcher)
- thread = Thread.new do
- sleep(1)
- watcher.finish
- end
- watcher.each do |_notice|
- break
- end
- thread.join
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_replication_controller.rb b/vendor/gems/kubeclient/test/test_replication_controller.rb
deleted file mode 100644
index 47af72210e5..00000000000
--- a/vendor/gems/kubeclient/test/test_replication_controller.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require_relative 'test_helper'
-
-# Replication Controller entity tests
-class TestReplicationController < MiniTest::Test
- def test_get_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/replicationcontrollers})
- .to_return(body: open_test_file('replication_controller.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- rc = client.get_replication_controller('frontendController', 'default')
-
- assert_instance_of(Kubeclient::Resource, rc)
- assert_equal('guestbook-controller', rc.metadata.name)
- assert_equal('c71aa4c0-a240-11e4-a265-3c970e4a436a', rc.metadata.uid)
- assert_equal('default', rc.metadata.namespace)
- assert_equal(3, rc.spec.replicas)
- assert_equal('guestbook', rc.spec.selector.name)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController',
- times: 1)
- end
-
- def test_delete_replicaset_cascade
- stub_core_api_list
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- opts = Kubeclient::Resource.new(
- apiVersion: 'meta/v1',
- gracePeriodSeconds: 0,
- kind: 'DeleteOptions',
- propagationPolicy: 'Foreground'
- )
-
- stub_request(:delete,
- 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController')
- .with(body: opts.to_hash.to_json)
- .to_return(status: 200, body: open_test_file('replication_controller.json'), headers: {})
- rc = client.delete_replication_controller('frontendController', 'default', delete_options: opts)
- assert_kind_of(RecursiveOpenStruct, rc)
-
- assert_requested(:delete,
- 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController',
- times: 1)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_resource_list_without_kind.rb b/vendor/gems/kubeclient/test/test_resource_list_without_kind.rb
deleted file mode 100644
index 89ab042b5f5..00000000000
--- a/vendor/gems/kubeclient/test/test_resource_list_without_kind.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-require_relative 'test_helper'
-
-# Core api resource list without kind tests
-class TestResourceListWithoutKind < MiniTest::Test
- def test_get_from_json_api_v1
- stub_request(:get, %r{/api/v1$})
- .to_return(body: open_test_file('core_api_resource_list_without_kind.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- client.discover
-
- [
- {
- entity: 'pod',
- type: 'Pod',
- name: 'pods',
- methods: %w[pod pods]
- },
- {
- entity: 'node',
- type: 'Node',
- name: 'nodes',
- methods: %w[node nodes]
- },
- {
- entity: 'service',
- type: 'Service',
- name: 'services',
- methods: %w[service services]
- }
- ].each { |h| assert_entities(client.instance_variable_get(:@entities)[h[:entity]], h) }
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1',
- times: 1)
- end
-
- def test_get_from_json_oapi_v1
- stub_request(:get, %r{/oapi/v1$})
- .to_return(body: open_test_file('core_oapi_resource_list_without_kind.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/oapi/', 'v1')
- client.discover
-
- [
- {
- entity: 'template',
- type: 'Template',
- name: 'templates',
- methods: %w[template templates]
- },
- {
- entity: 'build',
- type: 'Build',
- name: 'builds',
- methods: %w[build builds]
- },
- {
- entity: 'project',
- type: 'Project',
- name: 'projects',
- methods: %w[project projects]
- }
- ].each { |h| assert_entities(client.instance_variable_get(:@entities)[h[:entity]], h) }
-
- assert_requested(:get,
- 'http://localhost:8080/oapi/v1',
- times: 1)
- end
-
- def assert_entities(entity, h)
- assert_equal(entity.entity_type, h[:type])
- assert_equal(entity.resource_name, h[:name])
- assert_equal(entity.method_names, h[:methods])
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_resource_quota.rb b/vendor/gems/kubeclient/test/test_resource_quota.rb
deleted file mode 100644
index cf91a111196..00000000000
--- a/vendor/gems/kubeclient/test/test_resource_quota.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative 'test_helper'
-
-# ResourceQuota tests
-class TestResourceQuota < MiniTest::Test
- def test_get_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/resourcequotas})
- .to_return(body: open_test_file('resource_quota.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- quota = client.get_resource_quota('quota', 'quota-example')
-
- assert_instance_of(Kubeclient::Resource, quota)
- assert_equal('quota', quota.metadata.name)
- assert_equal('20', quota.spec.hard.cpu)
- assert_equal('10', quota.spec.hard.secrets)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/quota-example/resourcequotas/quota',
- times: 1)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_secret.rb b/vendor/gems/kubeclient/test/test_secret.rb
deleted file mode 100644
index ec129075a14..00000000000
--- a/vendor/gems/kubeclient/test/test_secret.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require_relative 'test_helper'
-
-# Namespace entity tests
-class TestSecret < MiniTest::Test
- def test_get_secret_v1
- stub_core_api_list
- stub_request(:get, %r{/secrets})
- .to_return(body: open_test_file('created_secret.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- secret = client.get_secret('test-secret', 'dev')
-
- assert_instance_of(Kubeclient::Resource, secret)
- assert_equal('4e38a198-2bcb-11e5-a483-0e840567604d', secret.metadata.uid)
- assert_equal('test-secret', secret.metadata.name)
- assert_equal('v1', secret.apiVersion)
- assert_equal('Y2F0J3MgYXJlIGF3ZXNvbWUK', secret.data['super-secret'])
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/dev/secrets/test-secret',
- times: 1)
- end
-
- def test_delete_secret_v1
- stub_core_api_list
- stub_request(:delete, %r{/secrets})
- .to_return(status: 200, body: open_test_file('created_secret.json'))
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- secret = client.delete_secret('test-secret', 'dev')
- assert_kind_of(RecursiveOpenStruct, secret)
-
- assert_requested(:delete,
- 'http://localhost:8080/api/v1/namespaces/dev/secrets/test-secret',
- times: 1)
- end
-
- def test_create_secret_v1
- stub_core_api_list
- stub_request(:post, %r{/secrets})
- .to_return(body: open_test_file('created_secret.json'),
- status: 201)
-
- secret = Kubeclient::Resource.new
- secret.metadata = {}
- secret.metadata.name = 'test-secret'
- secret.metadata.namespace = 'dev'
- secret.data = {}
- secret.data['super-secret'] = 'Y2F0J3MgYXJlIGF3ZXNvbWUK'
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- created_secret = client.create_secret(secret)
- assert_instance_of(Kubeclient::Resource, created_secret)
- assert_equal(secret.metadata.name, created_secret.metadata.name)
- assert_equal(secret.metadata.namespace, created_secret.metadata.namespace)
- assert_equal(
- secret.data['super-secret'],
- created_secret.data['super-secret']
- )
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_security_context_constraint.rb b/vendor/gems/kubeclient/test/test_security_context_constraint.rb
deleted file mode 100644
index 23e53c4464e..00000000000
--- a/vendor/gems/kubeclient/test/test_security_context_constraint.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require_relative 'test_helper'
-
-# kind: 'SecurityContextConstraints' entity tests.
-# This is one of the unusual `kind`s that are already plural (https://github.com/kubernetes/kubernetes/issues/8115).
-# We force singular in method names like 'create_endpoint',
-# but `kind` should remain plural as in kubernetes.
-class TestSecurityContextConstraints < MiniTest::Test
- def test_create_security_context_constraint
- stub_request(:get, %r{/apis/security.openshift.io/v1$}).to_return(
- body: open_test_file('security.openshift.io_api_resource_list.json'),
- status: 200
- )
-
- testing_scc = Kubeclient::Resource.new(
- metadata: {
- name: 'teleportation'
- },
- runAsUser: {
- type: 'MustRunAs'
- },
- seLinuxContext: {
- type: 'MustRunAs'
- }
- )
- req_body = '{"metadata":{"name":"teleportation"},"runAsUser":{"type":"MustRunAs"},' \
- '"seLinuxContext":{"type":"MustRunAs"},' \
- '"kind":"SecurityContextConstraints","apiVersion":"security.openshift.io/v1"}'
-
- stub_request(:post, 'http://localhost:8080/apis/security.openshift.io/v1/securitycontextconstraints')
- .with(body: req_body)
- .to_return(body: open_test_file('created_security_context_constraint.json'), status: 201)
-
- client = Kubeclient::Client.new('http://localhost:8080/apis/security.openshift.io', 'v1')
- created_scc = client.create_security_context_constraint(testing_scc)
- assert_equal('SecurityContextConstraints', created_scc.kind)
- assert_equal('security.openshift.io/v1', created_scc.apiVersion)
-
- client = Kubeclient::Client.new('http://localhost:8080/apis/security.openshift.io', 'v1',
- as: :parsed_symbolized)
- created_scc = client.create_security_context_constraint(testing_scc)
- assert_equal('SecurityContextConstraints', created_scc[:kind])
- assert_equal('security.openshift.io/v1', created_scc[:apiVersion])
- end
-
- def test_get_security_context_constraints
- stub_request(:get, %r{/apis/security.openshift.io/v1$}).to_return(
- body: open_test_file('security.openshift.io_api_resource_list.json'),
- status: 200
- )
- stub_request(:get, %r{/securitycontextconstraints})
- .to_return(body: open_test_file('security_context_constraint_list.json'), status: 200)
- client = Kubeclient::Client.new('http://localhost:8080/apis/security.openshift.io', 'v1')
-
- collection = client.get_security_context_constraints(as: :parsed_symbolized)
- assert_equal('SecurityContextConstraintsList', collection[:kind])
- assert_equal('security.openshift.io/v1', collection[:apiVersion])
-
- # Stripping of 'List' in collection.kind RecursiveOpenStruct mode only is historic.
- collection = client.get_security_context_constraints
- assert_equal('SecurityContextConstraints', collection.kind)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_service.rb b/vendor/gems/kubeclient/test/test_service.rb
deleted file mode 100644
index 6ef3368780d..00000000000
--- a/vendor/gems/kubeclient/test/test_service.rb
+++ /dev/null
@@ -1,357 +0,0 @@
-require_relative 'test_helper'
-
-# Service entity tests
-class TestService < MiniTest::Test
- def test_construct_our_own_service
- our_service = Kubeclient::Resource.new
- our_service.metadata = {}
- our_service.metadata.name = 'guestbook'
- our_service.metadata.namespace = 'staging'
- our_service.metadata.labels = {}
- our_service.metadata.labels.name = 'guestbook'
-
- our_service.spec = {}
- our_service.spec.ports = [{
- 'port' => 3000,
- 'targetPort' => 'http-server',
- 'protocol' => 'TCP'
- }]
-
- assert_equal('guestbook', our_service.metadata.labels.name)
-
- hash = our_service.to_h
-
- assert_equal(our_service.metadata.labels.name,
- hash[:metadata][:labels][:name])
-
- expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services'
- stub_core_api_list
- stub_request(:post, expected_url)
- .to_return(body: open_test_file('created_service.json'), status: 201)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- created = client.create_service(our_service)
-
- assert_instance_of(Kubeclient::Resource, created)
- assert_equal(created.metadata.name, our_service.metadata.name)
- assert_equal(created.spec.ports.size, our_service.spec.ports.size)
-
- # Check that original entity_config is not modified by kind/apiVersion patches:
- assert_nil(our_service.kind)
-
- assert_requested(:post, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- data['kind'] == 'Service' &&
- data['apiVersion'] == 'v1' &&
- data['metadata']['name'] == 'guestbook' &&
- data['metadata']['namespace'] == 'staging'
- end
- end
-
- def test_construct_service_from_symbol_keys
- service = Kubeclient::Resource.new
- service.metadata = {
- labels: { tier: 'frontend' },
- name: 'test-service',
- namespace: 'staging'
- }
- service.spec = {
- ports: [{
- port: 3000,
- targetPort: 'http-server',
- protocol: 'TCP'
- }]
- }
-
- expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services'
- stub_core_api_list
- stub_request(:post, expected_url)
- .to_return(body: open_test_file('created_service.json'), status: 201)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- client.create_service(service)
-
- assert_requested(:post, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- data['kind'] == 'Service' &&
- data['apiVersion'] == 'v1' &&
- data['metadata']['name'] == 'test-service' &&
- data['metadata']['labels']['tier'] == 'frontend' &&
- data['metadata']['namespace'] == 'staging'
- end
- end
-
- def test_construct_service_from_string_keys
- service = Kubeclient::Resource.new
- service.metadata = {
- 'labels' => { 'tier' => 'frontend' },
- 'name' => 'test-service',
- 'namespace' => 'staging'
- }
- service.spec = {
- 'ports' => [{
- 'port' => 3000,
- 'targetPort' => 'http-server',
- 'protocol' => 'TCP'
- }]
- }
-
- stub_core_api_list
- expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services'
- stub_request(:post, %r{namespaces/staging/services})
- .to_return(body: open_test_file('created_service.json'), status: 201)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- client.create_service(service)
-
- assert_requested(:post, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- data['kind'] == 'Service' &&
- data['apiVersion'] == 'v1' &&
- data['metadata']['name'] == 'test-service' &&
- data['metadata']['labels']['tier'] == 'frontend' &&
- data['metadata']['namespace'] == 'staging'
- end
- end
-
- def test_conversion_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/services})
- .to_return(body: open_test_file('service.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- service = client.get_service('redis-slave', 'development')
-
- assert_instance_of(Kubeclient::Resource, service)
- assert_equal('2015-04-05T13:00:31Z',
- service.metadata.creationTimestamp)
- assert_equal('bdb80a8f-db93-11e4-b293-f8b156af4ae1', service.metadata.uid)
- assert_equal('redis-slave', service.metadata.name)
- assert_equal('2815', service.metadata.resourceVersion)
- assert_equal('v1', service.apiVersion)
- assert_equal('10.0.0.140', service.spec.clusterIP)
- assert_equal('development', service.metadata.namespace)
-
- assert_equal('TCP', service.spec.ports[0].protocol)
- assert_equal(6379, service.spec.ports[0].port)
- assert_equal('', service.spec.ports[0].name)
- assert_equal('redis-server', service.spec.ports[0].targetPort)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/development/services/redis-slave',
- times: 1)
- end
-
- def test_delete_service
- our_service = Kubeclient::Resource.new
- our_service.name = 'redis-service'
- # TODO, new ports assignment to be added
- our_service.labels = {}
- our_service.labels.component = 'apiserver'
- our_service.labels.provider = 'kubernetes'
-
- stub_core_api_list
- stub_request(:delete, %r{/namespaces/default/services})
- .to_return(body: open_test_file('service.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- our_service = client.delete_service(our_service.name, 'default')
- assert_kind_of(RecursiveOpenStruct, our_service)
-
- assert_requested(:delete,
- 'http://localhost:8080/api/v1/namespaces/default/services/redis-service',
- times: 1)
- end
-
- def test_get_service_no_ns
- stub_core_api_list
- # when not specifying namespace for entities which
- # are not node or namespace, the request will fail
- stub_request(:get, %r{/services/redis-slave})
- .to_return(status: 404)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
-
- exception = assert_raises(Kubeclient::HttpError) do
- client.get_service('redis-slave')
- end
- assert_equal(404, exception.error_code)
- end
-
- def test_get_service
- stub_core_api_list
- stub_request(:get, %r{/namespaces/development/services/redis-slave})
- .to_return(body: open_test_file('service.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/')
- service = client.get_service('redis-slave', 'development')
- assert_equal('redis-slave', service.metadata.name)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/namespaces/development/services/redis-slave',
- times: 1)
- end
-
- def test_update_service
- service = Kubeclient::Resource.new
- name = 'my_service'
-
- service.metadata = {}
- service.metadata.name = name
- service.metadata.namespace = 'development'
-
- stub_core_api_list
- expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
- stub_request(:put, expected_url)
- .to_return(body: open_test_file('service_update.json'), status: 201)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- service = client.update_service(service)
- assert_kind_of(RecursiveOpenStruct, service)
-
- assert_requested(:put, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- data['metadata']['name'] == name &&
- data['metadata']['namespace'] == 'development'
- end
- end
-
- def test_update_service_with_string_keys
- service = Kubeclient::Resource.new
- name = 'my_service'
-
- service.metadata = {
- 'name' => name,
- 'namespace' => 'development'
- }
-
- stub_core_api_list
- expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
- stub_request(:put, expected_url)
- .to_return(body: open_test_file('service_update.json'), status: 201)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- service = client.update_service(service)
- assert_kind_of(RecursiveOpenStruct, service)
-
- assert_requested(:put, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- data['metadata']['name'] == name &&
- data['metadata']['namespace'] == 'development'
- end
- end
-
- def test_patch_service
- service = Kubeclient::Resource.new
- name = 'my_service'
-
- service.metadata = {}
- service.metadata.name = name
- service.metadata.namespace = 'development'
-
- stub_core_api_list
- expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
- stub_request(:patch, expected_url)
- .to_return(body: open_test_file('service_patch.json'), status: 200)
-
- patch = {
- metadata: {
- annotations: {
- key: 'value'
- }
- }
- }
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- service = client.patch_service(name, patch, 'development')
- assert_kind_of(RecursiveOpenStruct, service)
-
- assert_requested(:patch, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- data['metadata']['annotations']['key'] == 'value'
- end
- end
-
- def test_apply_service
- service = Kubeclient::Resource.new
- name = 'my_service'
-
- service.metadata = {}
- service.metadata.name = name
- service.metadata.namespace = 'development'
- service.metadata.annotations = {}
- service.metadata.annotations['key'] = 'value'
-
- stub_core_api_list
- resource_name = "#{name}?fieldManager=myapp&force=true"
- expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{resource_name}"
- stub_request(:patch, expected_url)
- .to_return(body: open_test_file('service_patch.json'), status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- service = client.apply_service(service, field_manager: 'myapp')
- assert_kind_of(RecursiveOpenStruct, service)
-
- assert_requested(:patch, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- req.headers['Content-Type'] == 'application/apply-patch+yaml' &&
- data['metadata']['annotations']['key'] == 'value'
- end
- end
-
- def test_json_patch_service
- service = Kubeclient::Resource.new
- name = 'my-service'
-
- service.metadata = {}
- service.metadata.name = name
- service.metadata.namespace = 'development'
-
- stub_core_api_list
- expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
- stub_request(:patch, expected_url)
- .to_return(body: open_test_file('service_json_patch.json'), status: 200)
-
- patch = [
- { 'op' => 'add', 'path' => '/spec/type', 'value' => 'LoadBalancer' }
- ]
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- service = client.json_patch_service(name, patch, 'development')
- assert_kind_of(RecursiveOpenStruct, service)
-
- assert_requested(:patch, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- req.headers['Content-Type'] == 'application/json-patch+json' &&
- data == patch
- end
- end
-
- def test_merge_patch_service
- service = Kubeclient::Resource.new
- name = 'my-service'
-
- service.metadata = {}
- service.metadata.name = name
- service.metadata.namespace = 'development'
-
- stub_core_api_list
- expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
- stub_request(:patch, expected_url)
- .to_return(body: open_test_file('service_merge_patch.json'), status: 200)
-
- patch = { spec: { type: 'NodePort' } }
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- service = client.merge_patch_service(name, patch, 'development')
- assert_kind_of(RecursiveOpenStruct, service)
-
- assert_requested(:patch, expected_url, times: 1) do |req|
- data = JSON.parse(req.body)
- req.headers['Content-Type'] == 'application/merge-patch+json' &&
- data['spec']['type'] == 'NodePort'
- end
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_service_account.rb b/vendor/gems/kubeclient/test/test_service_account.rb
deleted file mode 100644
index 87a08a215bd..00000000000
--- a/vendor/gems/kubeclient/test/test_service_account.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative 'test_helper'
-
-# ServiceAccount tests
-class TestServiceAccount < MiniTest::Test
- def test_get_from_json_v1
- stub_core_api_list
- stub_request(:get, %r{/serviceaccounts})
- .to_return(body: open_test_file('service_account.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- account = client.get_service_account('default')
-
- assert_instance_of(Kubeclient::Resource, account)
- assert_equal('default', account.metadata.name)
- assert_equal('default-token-6s23q', account.secrets[0].name)
- assert_equal('default-dockercfg-62tf3', account.secrets[1].name)
-
- assert_requested(:get,
- 'http://localhost:8080/api/v1/serviceaccounts/default',
- times: 1)
- assert_requested(:get,
- 'http://localhost:8080/api/v1',
- times: 1)
- end
-end
diff --git a/vendor/gems/kubeclient/test/test_watch.rb b/vendor/gems/kubeclient/test/test_watch.rb
deleted file mode 100644
index 8d74008c851..00000000000
--- a/vendor/gems/kubeclient/test/test_watch.rb
+++ /dev/null
@@ -1,195 +0,0 @@
-require_relative 'test_helper'
-
-# Watch entity tests
-class TestWatch < MiniTest::Test
- def test_watch_pod_success
- stub_core_api_list
-
- expected = [
- { 'type' => 'ADDED', 'resourceVersion' => '1389' },
- { 'type' => 'MODIFIED', 'resourceVersion' => '1390' },
- { 'type' => 'DELETED', 'resourceVersion' => '1398' }
- ]
-
- stub_request(:get, %r{/watch/pods})
- .to_return(body: open_test_file('watch_stream.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
-
- client.watch_pods.to_enum.with_index do |notice, index|
- assert_instance_of(Kubeclient::Resource, notice)
- assert_equal(expected[index]['type'], notice.type)
- assert_equal('Pod', notice.object.kind)
- assert_equal('php', notice.object.metadata.name)
- assert_equal(expected[index]['resourceVersion'],
- notice.object.metadata.resourceVersion)
- end
- end
-
- def test_watch_pod_block
- stub_core_api_list
- stub_request(:get, %r{/watch/pods})
- .to_return(body: open_test_file('watch_stream.json'),
- status: 200)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- yielded = []
- client.watch_pods { |notice| yielded << notice.type }
-
- assert_equal %w[ADDED MODIFIED DELETED], yielded
- end
-
- def test_watch_pod_raw
- stub_core_api_list
-
- stub_request(:get, %r{/watch/pods}).to_return(
- body: open_test_file('watch_stream.json'),
- status: 200
- )
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
-
- got = nil
- client.watch_pods(as: :raw).each { |notice| got = notice }
- assert_match(/\A{"type":"DELETED"/, got)
- end
-
- def test_watch_pod_failure
- stub_core_api_list
- stub_request(:get, %r{/watch/pods}).to_return(status: 404)
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
- assert_raises(Kubeclient::HttpError) do
- client.watch_pods.each do
- end
- end
- end
-
- def test_watch_pod_follow_redirect
- stub_core_api_list
-
- redirect = 'http://localhost:1234/api/v1/watch/pods'
- stub_request(:get, %r{/watch/pods})
- .to_return(status: 302, headers: { location: redirect })
-
- stub_request(:get, redirect).to_return(
- body: open_test_file('watch_stream.json'),
- status: 200
- )
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
-
- got = nil
- client.watch_pods.each { |notice| got = notice }
- assert_equal('DELETED', got.type)
- end
-
- def test_watch_pod_max_redirect
- stub_core_api_list
-
- redirect = 'http://localhost:1234/api/v1/watcher/pods'
- stub_request(:get, %r{/watch/pods})
- .to_return(status: 302, headers: { location: redirect })
-
- stub_request(:get, redirect).to_return(
- body: open_test_file('watch_stream.json'),
- status: 200
- )
-
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1', http_max_redirects: 0)
-
- assert_raises(Kubeclient::HttpError) do
- client.watch_pods.each do
- end
- end
- end
-
- # Ensure that WatchStream respects a format that's not JSON
- def test_watch_stream_text
- url = 'http://www.example.com/foobar'
- expected_lines = open_test_file('pod_log.txt').read.split("\n")
-
- stub_request(:get, url)
- .to_return(body: open_test_file('pod_log.txt'),
- status: 200)
-
- stream = Kubeclient::Common::WatchStream.new(URI.parse(url), {}, formatter: ->(v) { v })
- stream.to_enum.with_index do |line, index|
- assert_instance_of(String, line)
- assert_equal(expected_lines[index], line)
- end
- end
-
- def test_watch_with_resource_version
- api_host = 'http://localhost:8080/api'
- version = '1995'
- stub_core_api_list
- stub_request(:get, %r{.*\/watch/events})
- .to_return(body: open_test_file('watch_stream.json'),
- status: 200)
-
- client = Kubeclient::Client.new(api_host, 'v1')
- results = client.watch_events(version).to_enum
-
- assert_equal(3, results.count)
- assert_requested(:get,
- "#{api_host}/v1/watch/events?resourceVersion=#{version}",
- times: 1)
- end
-
- def test_watch_with_label_selector
- api_host = 'http://localhost:8080/api'
- selector = 'name=redis-master'
-
- stub_core_api_list
- stub_request(:get, %r{.*\/watch/events})
- .to_return(body: open_test_file('watch_stream.json'),
- status: 200)
-
- client = Kubeclient::Client.new(api_host, 'v1')
- results = client.watch_events(label_selector: selector).to_enum
-
- assert_equal(3, results.count)
- assert_requested(:get,
- "#{api_host}/v1/watch/events?labelSelector=#{selector}",
- times: 1)
- end
-
- def test_watch_with_field_selector
- api_host = 'http://localhost:8080/api'
- selector = 'involvedObject.kind=Pod'
-
- stub_core_api_list
- stub_request(:get, %r{.*\/watch/events})
- .to_return(body: open_test_file('watch_stream.json'),
- status: 200)
-
- client = Kubeclient::Client.new(api_host, 'v1')
- results = client.watch_events(field_selector: selector).to_enum
-
- assert_equal(3, results.count)
- assert_requested(:get,
- "#{api_host}/v1/watch/events?fieldSelector=#{selector}",
- times: 1)
- end
-
- def test_watch_with_finish_and_ebadf
- api_host = 'http://localhost:8080/api'
-
- stub_core_api_list
- stub_request(:get, %r{.*\/watch/events})
- .to_return(body: open_test_file('watch_stream.json'), status: 200)
-
- client = Kubeclient::Client.new(api_host, 'v1')
- watcher = client.watch_events
-
- # explodes when StandardError is not caught
- watcher.each do
- watcher.finish
- raise StandardError
- end
-
- assert_requested(:get, "#{api_host}/v1/watch/events", times: 1)
- end
-end
diff --git a/vendor/gems/kubeclient/test/txt/pod_log.txt b/vendor/gems/kubeclient/test/txt/pod_log.txt
deleted file mode 100644
index 9f9a75157aa..00000000000
--- a/vendor/gems/kubeclient/test/txt/pod_log.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Initializing server...
-...loaded configuration
-...updated settings
-...discovered local servers
-...frobinated disks
-Complete!
diff --git a/vendor/gems/kubeclient/test/valid_token_file b/vendor/gems/kubeclient/test/valid_token_file
deleted file mode 100644
index df2c2eb6572..00000000000
--- a/vendor/gems/kubeclient/test/valid_token_file
+++ /dev/null
@@ -1 +0,0 @@
-valid_token
diff --git a/vendor/gems/omniauth-salesforce/README.md b/vendor/gems/omniauth-salesforce/README.md
index df59e99bc55..a306fafa936 100755
--- a/vendor/gems/omniauth-salesforce/README.md
+++ b/vendor/gems/omniauth-salesforce/README.md
@@ -13,13 +13,7 @@ should be used in favor of this vendored fork.
[OmniAuth](https://github.com/intridea/omniauth) Strategy for [salesforce.com](salesforce.com).
-Note: This is a fork of the [original](https://github.com/richardvanhook/omniauth-salesforce) project and is now the main repository for the omniauth-salesforce gem.
-
-## See it in action
-
-[http://omniauth-salesforce-example.herokuapp.com](http://omniauth-salesforce-example.herokuapp.com)
-
-[Source for above app](https://github.com/richardvanhook/omniauth-salesforce-example)
+Note: This is a fork of the [original](https://github.com/richardvanhook/omniauth-salesforce) project and is now the main repository for the omniauth-salesforce gem for consumption within GitLab.
## Basic Usage
diff --git a/vendor/project_templates/learn_gitlab_ultimate.tar.gz b/vendor/project_templates/learn_gitlab_ultimate.tar.gz
deleted file mode 100644
index b134ac89815..00000000000
--- a/vendor/project_templates/learn_gitlab_ultimate.tar.gz
+++ /dev/null
Binary files differ
diff --git a/workhorse/go.mod b/workhorse/go.mod
index 76374a28f5c..4f0d1cabbc9 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -3,59 +3,59 @@ module gitlab.com/gitlab-org/gitlab/workhorse
go 1.18
require (
- github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.6.1
+ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0
github.com/BurntSushi/toml v1.2.1
github.com/FZambia/sentinel v1.1.1
github.com/alecthomas/chroma/v2 v2.5.0
- github.com/aws/aws-sdk-go v1.44.199
+ github.com/aws/aws-sdk-go v1.44.218
github.com/disintegration/imaging v1.6.2
github.com/getsentry/raven-go v0.2.0
- github.com/golang-jwt/jwt/v4 v4.4.3
+ github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f
- github.com/golang/protobuf v1.5.2
+ 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.3.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
- github.com/johannesboyne/gofakes3 v0.0.0-20230129080941-f6a8a9ae6fd3
+ github.com/johannesboyne/gofakes3 v0.0.0-20230310080033-c0edf658332b
github.com/jpillora/backoff v1.0.0
github.com/mitchellh/copystructure v1.2.0
github.com/prometheus/client_golang v1.14.0
- github.com/rafaeljusto/redigomock/v3 v3.1.1
+ github.com/rafaeljusto/redigomock/v3 v3.1.2
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
github.com/sirupsen/logrus v1.9.0
github.com/smartystreets/goconvey v1.7.2
- github.com/stretchr/testify v1.8.1
- gitlab.com/gitlab-org/gitaly/v15 v15.9.0-rc4
+ github.com/stretchr/testify v1.8.2
+ gitlab.com/gitlab-org/gitaly/v15 v15.9.3
gitlab.com/gitlab-org/golang-archive-zip v0.1.1
- gitlab.com/gitlab-org/labkit v1.17.0
- gocloud.dev v0.28.0
- golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
+ gitlab.com/gitlab-org/labkit v1.18.0
+ gocloud.dev v0.29.0
+ golang.org/x/image v0.5.0
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
- golang.org/x/net v0.5.0
- golang.org/x/oauth2 v0.4.0
- golang.org/x/tools v0.2.0
+ golang.org/x/net v0.7.0
+ golang.org/x/oauth2 v0.5.0
+ golang.org/x/tools v0.6.0
google.golang.org/grpc v1.53.0
- google.golang.org/protobuf v1.28.1
+ google.golang.org/protobuf v1.29.0
honnef.co/go/tools v0.3.3
)
require (
- cloud.google.com/go v0.107.0 // indirect
- cloud.google.com/go/compute v1.15.1 // indirect
+ cloud.google.com/go v0.109.0 // indirect
+ cloud.google.com/go/compute v1.18.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
- cloud.google.com/go/iam v0.8.0 // indirect
- cloud.google.com/go/monitoring v1.9.0 // indirect
+ cloud.google.com/go/iam v0.10.0 // indirect
+ cloud.google.com/go/monitoring v1.12.0 // indirect
cloud.google.com/go/profiler v0.1.0 // indirect
- cloud.google.com/go/storage v1.28.0 // indirect
- cloud.google.com/go/trace v1.4.0 // indirect
+ cloud.google.com/go/storage v1.29.0 // indirect
+ cloud.google.com/go/trace v1.8.0 // indirect
contrib.go.opencensus.io/exporter/stackdriver v0.13.14 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.1 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
- github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 // indirect
+ github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1 // indirect
github.com/DataDog/datadog-go v4.4.0+incompatible // indirect
github.com/DataDog/sketches-go v1.0.0 // indirect
github.com/Microsoft/go-winio v0.5.1 // indirect
@@ -72,10 +72,10 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/go-cmp v0.5.9 // indirect
- github.com/google/pprof v0.0.0-20221102093814-76f304f74e5e // indirect
+ github.com/google/pprof v0.0.0-20230111200839-76d1ae5aea2b // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/wire v0.5.0 // indirect
- github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
+ github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
@@ -84,7 +84,7 @@ require (
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20210210170715-a8dfcb80d3a7 // indirect
github.com/lightstep/lightstep-tracer-go v0.25.0 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/oklog/ulid/v2 v2.0.2 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
@@ -93,9 +93,9 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
- github.com/prometheus/common v0.37.0 // indirect
+ github.com/prometheus/common v0.39.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
- github.com/prometheus/prometheus v0.40.5 // indirect
+ github.com/prometheus/prometheus v0.42.0 // indirect
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 // indirect
github.com/shirou/gopsutil/v3 v3.21.2 // indirect
@@ -107,17 +107,17 @@ require (
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
- golang.org/x/crypto v0.5.0 // indirect
+ golang.org/x/crypto v0.6.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
- golang.org/x/mod v0.6.0 // indirect
+ golang.org/x/mod v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.5.0 // indirect
- golang.org/x/text v0.6.0 // indirect
+ golang.org/x/text v0.7.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
- google.golang.org/api v0.103.0 // indirect
+ google.golang.org/api v0.110.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20230117162540-28d6b9783ac4 // indirect
+ google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc // indirect
gopkg.in/DataDog/dd-trace-go.v1 v1.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/workhorse/go.sum b/workhorse/go.sum
index 64749d157d3..e7cd75f0745 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -33,19 +33,22 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
+cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
-cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww=
cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I=
+cloud.google.com/go v0.109.0 h1:38CZoKGlCnPZjGdyj0ZfpoGae0/wgNfy5F0byyxg0Gk=
+cloud.google.com/go v0.109.0/go.mod h1:2sYycXt75t/CSB5R9M2wPU1tJmire7AQZTPtITcGBVE=
cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4=
cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw=
cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o=
cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE=
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
+cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg=
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk=
@@ -88,6 +91,7 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=
cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw=
+cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc=
cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI=
@@ -118,8 +122,10 @@ cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOt
cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE=
-cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE=
+cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=
cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA=
+cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY=
+cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
@@ -154,6 +160,7 @@ cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4c
cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM=
cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g=
@@ -175,6 +182,7 @@ cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1
cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
+cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU=
cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI=
cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8=
cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc=
@@ -182,6 +190,7 @@ cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEu
cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w=
cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE=
cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
@@ -202,32 +211,38 @@ cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZ
cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM=
cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o=
+cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc=
cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
-cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk=
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
+cloud.google.com/go/iam v0.10.0 h1:fpP/gByFs6US1ma53v7VxhvbJpO2Aapng6wabJ99MuI=
+cloud.google.com/go/iam v0.10.0/go.mod h1:nXAECrMt2qHpF6RZUZseteD6QyanL68reN4OXPw0UWM=
cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc=
cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A=
cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM=
cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY=
cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs=
cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g=
+cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA=
cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg=
cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0=
-cloud.google.com/go/kms v1.7.0/go.mod h1:k2UdVoNIHLJi/Rnng6dN0vlq7lS3jHSDiZasft+gmYE=
+cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg=
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE=
cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8=
cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=
+cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw=
cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE=
-cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc=
+cloud.google.com/go/longrunning v0.4.0 h1:v+X4EwhHl6xE+TG1XgXj4T1XpKKs7ZevcAJ3FOu0YmY=
+cloud.google.com/go/longrunning v0.4.0/go.mod h1:eF3Qsw58iX/bkKtVjMTYpH0LRjQ2goDkjkNQTlzq/ZM=
cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE=
cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM=
+cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI=
cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=
@@ -241,8 +256,8 @@ cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U
cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TElyanS95vIcl4=
cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk=
cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4=
-cloud.google.com/go/monitoring v1.9.0 h1:O2A5HsrhvRMzD3OMUimPXF46vOzwc9vh6oGCGf9i/ws=
-cloud.google.com/go/monitoring v1.9.0/go.mod h1:/FsTS0gkEFUc4cgB16s6jYDnyjzRBkRJNRzBn5Zx+wA=
+cloud.google.com/go/monitoring v1.12.0 h1:+X79DyOP/Ny23XIqSIb37AvFWSxDN15w/ktklVvPLso=
+cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w=
cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM=
@@ -281,7 +296,10 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/pubsub v1.27.0/go.mod h1:BgkDyjrFNV8c7txDxPrlQkM/XtbJQVEeAWmt56lVVf8=
+cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI=
+cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0=
+cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8=
+cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg=
cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
@@ -315,6 +333,7 @@ cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJe
cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4=
cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4=
+cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU=
cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=
cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=
cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=
@@ -336,6 +355,7 @@ cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5
cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU=
cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4=
cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw=
+cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos=
cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0=
@@ -349,8 +369,9 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
-cloud.google.com/go/storage v1.28.0 h1:DLrIZ6xkeZX6K70fU/boWx5INJumt6f+nwwWSHXzzGY=
-cloud.google.com/go/storage v1.28.0/go.mod h1:qlgZML35PXA3zoEnIkiPLY4/TOkUleufRlu6qmcf7sI=
+cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=
+cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
+cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w=
cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I=
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
@@ -363,8 +384,9 @@ cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG
cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg=
cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguHpGcr6A=
cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28=
-cloud.google.com/go/trace v1.4.0 h1:qO9eLn2esajC9sxpqp1YKX37nXC3L4BfGnPS0Cx9dYo=
cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y=
+cloud.google.com/go/trace v1.8.0 h1:GFPLxbp5/FzdgTzor3nlNYNxMd6hLmzkE7sA9F0qQcA=
+cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA=
cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs=
cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg=
cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk=
@@ -380,6 +402,7 @@ cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb
cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E=
cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE=
cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g=
+cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208=
cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w=
cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8=
cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=
@@ -406,25 +429,26 @@ github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 h1:sVW/AFBTGyJxDaMYlq0ct3jUXTtj12tQ6zE2GZUgVQw=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.2/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0/go.mod h1:tZoQYdDZNOiIjdSn0dVWVfl0NEPGOJqVLzSrcFk4Is0=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.1 h1:gVXuXcWd1i4C2Ruxe321aU+IKGaStvGB/S90PUPB/W8=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.1/go.mod h1:DffdKW9RFqa5VgmsjUOsS7UE7eiA5iAvYUs63bhKQ0M=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 h1:t/W5MYAuQy81cvM8VUNfRLzhtKpXhVUAN7Cd7KVbTyc=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0/go.mod h1:NBanQUfSWiWn3QEpWDTCU0IjBECKOYvl2R8xdRtMtiM=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 h1:T8quHYlUGyb/oqtSTwqlCr1ilJHrDv+ZtpSfo+hm1BU=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1/go.mod h1:gLa1CL2RNE4s7M3yopJ/p0iq5DdY6Yv5ZUt9MTRZOQM=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 h1:+5VZ72z0Qan5Bog5C+ZkgSqUbeVUd9wgtHOrIKuc5b8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.9.0/go.mod h1:EAyXOW1F6BTJPiK2pDvmnvxOHPxoTYWoqBeIlql+QhI=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
-github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.3/go.mod h1:Eo6WMP/iw9sp06+v8y030eReUwX6sULn5i3fxCDWPag=
-github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.6.1 h1:YvQv9Mz6T8oR5ypQOL6erY0Z5t71ak1uHV4QFokCOZk=
-github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.6.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU=
+github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.2.0/go.mod h1:R6+0udeRV8iYSTVuT5RT7If4sc46K5Bz3ZKrmvZQF7U=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag=
github.com/Azure/go-amqp v0.17.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
-github.com/Azure/go-amqp v0.17.5/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
+github.com/Azure/go-amqp v0.18.1/go.mod h1:+bg0x3ce5+Q3ahCEXnCsGG3ETpDQe3MEVnOuT2ywPwc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
@@ -434,14 +458,12 @@ github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW
github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
github.com/Azure/go-autorest/autorest v0.11.25/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U=
-github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U=
github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA=
github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
-github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
-github.com/Azure/go-autorest/autorest/adal v0.9.21/go.mod h1:zua7mBUaCc5YnSLKYgGJR/w5ePdMDA6H56upLsHzA9U=
+github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
@@ -454,8 +476,8 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
-github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 h1:VgSJlZH5u0k2qxSpqyghcFQKmvYckj46uymKK5XzkBM=
-github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0/go.mod h1:BDJ5qMFKx9DugEg3+uQSDCdbYPr5s9vBTrL9P8TpqOU=
+github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1 h1:oPdPEZFSbl7oSPEAIPMPBMUmiL+mqgzBJwM/9qYcwNg=
+github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1/go.mod h1:4qFor3D/HDsvBME35Xy9rwW9DecL+M2sNw1ybjPtwA0=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
@@ -468,8 +490,10 @@ github.com/DataDog/sketches-go v1.0.0 h1:chm5KSXO7kO+ywGWJ0Zs6tdmWU8PBXSbywFVciL
github.com/DataDog/sketches-go v1.0.0/go.mod h1:O+XkJHWk9w4hDwY2ZUDU31ZC9sNYlYo8DiFsxjYeo1k=
github.com/FZambia/sentinel v1.1.1 h1:0ovTimlR7Ldm+wR15GgO+8C2dt7kkn+tm3PQS+Qk3Ek=
github.com/FZambia/sentinel v1.1.1/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI=
-github.com/GoogleCloudPlatform/cloudsql-proxy v1.33.1/go.mod h1:n3KDPrdaY2p9Nr0B1allAdjYArwIpXQcitNbsS/Qiok=
-github.com/HdrHistogram/hdrhistogram-go v1.1.1 h1:cJXY5VLMHgejurPjZH6Fo9rIwRGLefBGdiaENZALqrg=
+github.com/GoogleCloudPlatform/cloudsql-proxy v1.33.2/go.mod h1:uqoR4sJc63p7ugW8a/vsEspOsNuehbi7ptS2CHCyOnY=
+github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
@@ -509,6 +533,7 @@ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUW
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
+github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/chroma/v2 v2.5.0 h1:CQCdj1BiBV17sD4Bd32b/Bzuiq/EqoNTrnIhyQAZ+Rk=
github.com/alecthomas/chroma/v2 v2.5.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw=
@@ -526,74 +551,77 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
+github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
-github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
-github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.33.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
+github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
-github.com/aws/aws-sdk-go v1.44.128/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
-github.com/aws/aws-sdk-go v1.44.151/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/aws/aws-sdk-go v1.44.199 h1:hYuQmS4zLMJR9v2iOp2UOD6Vi/0V+nwyR/Uhrkrtlbc=
-github.com/aws/aws-sdk-go v1.44.199/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
-github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk=
-github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 h1:RKci2D7tMwpvGpDNZnGQw9wk6v7o/xSwFcUAuNPoB8k=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9/go.mod h1:vCmV1q1VK8eoQJ5+aYE7PkK1K6v41qJ5pJdK3ggCDvg=
-github.com/aws/aws-sdk-go-v2/config v1.18.3 h1:3kfBKcX3votFX84dm00U8RGA1sCCh3eRMOGzg5dCWfU=
-github.com/aws/aws-sdk-go-v2/config v1.18.3/go.mod h1:BYdrbeCse3ZnOD5+2/VE/nATOK8fEUpBtmPMdKSyhMU=
-github.com/aws/aws-sdk-go-v2/credentials v1.13.3 h1:ur+FHdp4NbVIv/49bUjBW+FE7e57HOo03ELodttmagk=
-github.com/aws/aws-sdk-go-v2/credentials v1.13.3/go.mod h1:/rOMmqYBcFfNbRPU0iN9IgGqD5+V2yp3iWNmIlz0wI4=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42 h1:bxgBYvvBh+W1RnNYP4ROXEB8N+HSSucDszfE7Rb+kfU=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42/go.mod h1:LHOsygMiW/14CkFxdXxvzKyMh3jbk/QfZVaDtCbLkl8=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 h1:oRHDrwCTVT8ZXi4sr9Ld+EXk7N/KGssOr2ygNeojEhw=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 h1:2EXB7dtGwRYIN3XQ9qwIW504DVbKIw3r89xQnonGdsQ=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16/go.mod h1:XH+3h395e3WVdd6T2Z3mPxuI+x/HVtdqVOREkTiyubs=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 h1:dpiPHgmFstgkLG07KaYAewvuptq5kvo52xn7tVSrtrQ=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10/go.mod h1:9cBNUHI2aW4ho0A5T87O294iPDuuUOSIEDjnd1Lq/z0=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 h1:KSvtm1+fPXE0swe9GPjc6msyrdTT0LB/BP8eLugL1FI=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20/go.mod h1:Mp4XI/CkWGD79AQxZ5lIFlgvC0A+gl+4BmyG1F+SfNc=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 h1:GE25AWCdNUPh9AOJzI9KIJnja7IwUc1WyUqz/JTyJ/I=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19/go.mod h1:02CP6iuYP+IVnBX5HULVdSAku/85eHB2Y9EsFhrkEwU=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 h1:piDBAaWkaxkkVV3xJJbTehXCZRXYs49kvpi/LG6LR2o=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19/go.mod h1:BmQWRVkLTmyNzYPFAZgon53qKLWBNSvonugD1MrSWUs=
-github.com/aws/aws-sdk-go-v2/service/kms v1.19.0/go.mod h1:kZodDPTQjSH/qM6/OvyTfM5mms5JHB/EKYp5dhn/vI4=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4 h1:QgmmWifaYZZcpaw3y1+ccRlgH6jAvLm4K/MBGUc7cNM=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0=
-github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.8/go.mod h1:k6CPuxyzO247nYEM1baEwHH1kRtosRCvgahAepaaShw=
-github.com/aws/aws-sdk-go-v2/service/sns v1.18.6/go.mod h1:2cPUjR63iE9MPMPJtSyzYmsTFCNrN/Xi9j0v9BL5OU0=
-github.com/aws/aws-sdk-go-v2/service/sqs v1.19.15/go.mod h1:DKX/7/ZiAzHO6p6AhArnGdrV4r+d461weby8KeVtvC4=
-github.com/aws/aws-sdk-go-v2/service/ssm v1.33.1/go.mod h1:rEsqsZrOp9YvSGPOrcL3pR9+i/QJaWRkAYbuxMa7yCU=
-github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 h1:GFZitO48N/7EsFDt8fMa5iYdmWqkUDDB3Eje6z3kbG0=
-github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vboR0FeJ89OkEy1M9mWbK2ifCI=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI=
-github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 h1:60SJ4lhvn///8ygCzYy2l53bFW/Q15bVfyjyAWo6zuw=
-github.com/aws/aws-sdk-go-v2/service/sts v1.17.5/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4=
-github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk=
-github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
+github.com/aws/aws-sdk-go v1.44.156/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go v1.44.187/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go v1.44.200/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go v1.44.218 h1:p707+xOCazWhkSpZOeyhtTcg7Z+asxxvueGgYPSitn4=
+github.com/aws/aws-sdk-go v1.44.218/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
+github.com/aws/aws-sdk-go-v2 v1.17.4 h1:wyC6p9Yfq6V2y98wfDsj6OnNQa4w2BLGCLIxzNhwOGY=
+github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
+github.com/aws/aws-sdk-go-v2/config v1.18.12 h1:fKs/I4wccmfrNRO9rdrbMO1NgLxct6H9rNMiPdBxHWw=
+github.com/aws/aws-sdk-go-v2/config v1.18.12/go.mod h1:J36fOhj1LQBr+O4hJCiT8FwVvieeoSGOtPuvhKlsNu8=
+github.com/aws/aws-sdk-go-v2/credentials v1.13.12 h1:Cb+HhuEnV19zHRaYYVglwvdHGMJWbdsyP4oHhw04xws=
+github.com/aws/aws-sdk-go-v2/credentials v1.13.12/go.mod h1:37HG2MBroXK3jXfxVGtbM2J48ra2+Ltu+tmwr/jO0KA=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 h1:3aMfcTmoXtTZnaT86QlVaYh+BRMbvrrmZwIQ5jWqCZQ=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22/go.mod h1:YGSIJyQ6D6FjKMQh16hVFSIUD54L4F7zTGePqYMYYJU=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.51 h1:iTFYCAdKzSAjGnVIUe88Hxvix0uaBqr0Rv7qJEOX5hE=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.51/go.mod h1:7Grl2gV+dx9SWrUIgwwlUvU40t7+lOSbx34XwfmsTkY=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 h1:r+XwaCLpIvCKjBIYy/HVZujQS9tsz5ohHG3ZIe0wKoE=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 h1:7AwGYXDdqRQYsluvKFmWoqpcOQJ4bH634SkYf3FNj/A=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 h1:J4xhFd6zHhdF9jPP0FQJ6WknzBboGMBNjKOv4iTuw4A=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19 h1:FGvpyTg2LKEmMrLlpjOgkoNp9XF5CGeyAyo33LdqZW8=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19/go.mod h1:8W88sW3PjamQpKFUQvHWWKay6ARsNvZnzU7+a4apubw=
+github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 h1:c5+bNdV8E4fIPteWx4HZSkqI07oY9exbfQ7JH7Yx4PI=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23/go.mod h1:1jcUfF+FAOEwtIcNiHPaV4TSoZqkUIPzrohmD7fb95c=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 h1:LjFQf8hFuMO22HkV5VWGLBvmCLBCLPivUAmpdpnp4Vs=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22 h1:ISLJ2BKXe4zzyZ7mp5ewKECiw0U7KpLgS3S6OxY9Cm0=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22/go.mod h1:QFVbqK54XArazLvn2wvWMRBi/jGrWii46qbr5DyPGjc=
+github.com/aws/aws-sdk-go-v2/service/kms v1.20.2/go.mod h1:vdqtUOdVuf5ooy+hJ2GnzqNo94xiAA9s1xbZ1hQgRE0=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2 h1:5EQWIFO+Hc8E2hFcXQJ1vm6ufl/PMt/6RVRDZRju2vM=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2/go.mod h1:SXDHd6fI2RhqB7vmAzyYQCTQnpZrIprVJvYxpzW3JAM=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.3/go.mod h1:hqPcyOuLU6yWIbLy3qMnQnmidgKuIEwqIlW6+chYnog=
+github.com/aws/aws-sdk-go-v2/service/sns v1.20.2/go.mod h1:VN2n9SOMS1lNbh5YD7o+ho0/rgfifSrK//YYNiVVF5E=
+github.com/aws/aws-sdk-go-v2/service/sqs v1.20.2/go.mod h1:1ttxGjUHZliCQMpPss1sU5+Ph/5NvdMFRzr96bv8gm0=
+github.com/aws/aws-sdk-go-v2/service/ssm v1.35.2/go.mod h1:VLSz2SHUKYFSOlXB/GlXoLU6KPYQJAbw7I20TDJdyws=
+github.com/aws/aws-sdk-go-v2/service/sso v1.12.1 h1:lQKN/LNa3qqu2cDOQZybP7oL4nMGGiFqob0jZJaR8/4=
+github.com/aws/aws-sdk-go-v2/service/sso v1.12.1/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 h1:0bLhH6DRAqox+g0LatcjGKjjhU6Eudyys6HB6DJVPj8=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1/go.mod h1:O1YSOg3aekZibh2SngvCRRG+cRHKKlYgxf/JBF/Kr/k=
+github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 h1:s49mSnsBZEXjfGBkRfmK+nPqzT7Lt3+t2SmAKNyHblw=
+github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiOVVG8uVjGI6HaZ8WBHdgDgU=
+github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
+github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
+github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw=
github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -613,11 +641,10 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
-github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
-github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
@@ -648,7 +675,7 @@ github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
-github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
+github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/client9/reopen v1.0.0 h1:8tpLVR74DLpLObrn2KvsyxJY++2iORGR17WLUdSzUws=
github.com/client9/reopen v1.0.0/go.mod h1:caXVCEr+lUtoN1FlsRiOWdfQtdRHIYfcb0ai8qKWtkQ=
@@ -657,18 +684,19 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
-github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
@@ -807,7 +835,7 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
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=
-github.com/digitalocean/godo v1.88.0/go.mod h1:NRpFznZFvhHjBoqZAaOD3khVzsJ3EibzKqFL4R60dmA=
+github.com/digitalocean/godo v1.95.0/go.mod h1:NRpFznZFvhHjBoqZAaOD3khVzsJ3EibzKqFL4R60dmA=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
@@ -820,9 +848,10 @@ github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.23+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
@@ -845,7 +874,7 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
+github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -859,27 +888,31 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.
github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
-github.com/envoyproxy/protoc-gen-validate v0.6.13/go.mod h1:qEySVqXrEugbHKvmhI8ZqtQi75/RHSSRNpffvB4I6Bw=
+github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
+github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
+github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
@@ -898,7 +931,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
+github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
@@ -918,9 +951,11 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
+github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo=
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
+github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -930,11 +965,16 @@ github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwoh
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
+github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
+github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw=
github.com/go-openapi/runtime v0.23.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk=
+github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
+github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
+github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
@@ -945,15 +985,16 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
+github.com/go-openapi/validate v0.22.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
-github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
@@ -997,11 +1038,10 @@ github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
-github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@@ -1013,10 +1053,12 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
+github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg=
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -1055,8 +1097,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -1125,8 +1168,8 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210804190019-f964ff605595/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20220318212150-b2ab0324ddda/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
-github.com/google/pprof v0.0.0-20221102093814-76f304f74e5e h1:F1LLQqQ8WoIbyoxLUY+JUZe1kuHdxThM6CPUATzE6Io=
-github.com/google/pprof v0.0.0-20221102093814-76f304f74e5e/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
+github.com/google/pprof v0.0.0-20230111200839-76d1ae5aea2b h1:8htHrh2bw9c7Idkb7YNac+ZpTqLMjRpI+FWu51ltaQc=
+github.com/google/pprof v0.0.0-20230111200839-76d1ae5aea2b/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -1139,8 +1182,10 @@ github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
-github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs=
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
+github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
+github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
+github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@@ -1159,7 +1204,7 @@ github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97Dwqy
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gophercloud/gophercloud v0.24.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
-github.com/gophercloud/gophercloud v1.0.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
+github.com/gophercloud/gophercloud v1.1.1/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
@@ -1168,6 +1213,8 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
+github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -1175,7 +1222,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grafana/regexp v0.0.0-20220304095617-2e8d9baf4ac2/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
-github.com/grafana/regexp v0.0.0-20221005093135-b4c2bcb0a4b6/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
+github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
github.com/gregjones/httpcache v0.0.0-20170920190843-316c5e0ff04e/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@@ -1190,16 +1237,14 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.1/go.mod h1:G+WkljZi4mflcqVxYSgvt8MNctRQHjEH8ubKtt1Ka3w=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
-github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=
-github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc=
+github.com/hanwen/go-fuse/v2 v2.2.0/go.mod h1:B1nGE/6RBFyBRC1RRnf23UpwCdyJ31eukw34oAKukAc=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
-github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY=
+github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
-github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw=
+github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE=
github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -1210,12 +1255,12 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
@@ -1230,30 +1275,36 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
-github.com/hashicorp/nomad/api v0.0.0-20221102143410-8a95f1239005/go.mod h1:vgJmrz4Bz9E1cR/uy70oP9udUJKFRkcEYHlHTp4nFwI=
+github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
+github.com/hashicorp/nomad/api v0.0.0-20230124213148-69fd1a0e4bf7/go.mod h1:xYYd4dybIhRhhzDemKx7Ddt8CvCosgrEek8YM7/cF0A=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
+github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hetznercloud/hcloud-go v1.33.1/go.mod h1:XX/TQub3ge0yWR2yHWmnDVIrB+MQbda1pHxkUmDlUME=
-github.com/hetznercloud/hcloud-go v1.35.3/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzSY9xWL1e9dyxXpgA=
+github.com/hetznercloud/hcloud-go v1.39.0/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzSY9xWL1e9dyxXpgA=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
+github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -1267,7 +1318,7 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
github.com/ionos-cloud/sdk-go/v6 v6.1.3/go.mod h1:Ox3W0iiEz0GHnfY9e5LmAxwklsxguuNFEUSu0gVRTME=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
@@ -1310,18 +1361,23 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
+github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
+github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
+github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
+github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
+github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
-github.com/johannesboyne/gofakes3 v0.0.0-20230129080941-f6a8a9ae6fd3 h1:aTscQmvmU/1AS3PqVaNtUtJUwyMexxqVErkhwsWoEpw=
-github.com/johannesboyne/gofakes3 v0.0.0-20230129080941-f6a8a9ae6fd3/go.mod h1:Cnosl0cRZIfKjTMuH49sQog2LeNsU5Hf4WnPIDWIDV0=
+github.com/johannesboyne/gofakes3 v0.0.0-20230310080033-c0edf658332b h1:dRMf9/2xfp4tky4wnvFxsMQz78n92VeqDIxR27uass4=
+github.com/johannesboyne/gofakes3 v0.0.0-20230310080033-c0edf658332b/go.mod h1:Cnosl0cRZIfKjTMuH49sQog2LeNsU5Hf4WnPIDWIDV0=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
@@ -1330,7 +1386,6 @@ github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2E
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -1341,6 +1396,7 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -1350,6 +1406,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
@@ -1362,6 +1419,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -1379,21 +1437,19 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20210210170715-a8dfcb80d3a7 h1:YjW+hUb8Fh2S58z4av4t/0cBMK/Q0aP48RocCFsC8yI=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20210210170715-a8dfcb80d3a7/go.mod h1:Spd59icnvRxSKuyijbbwe5AemzvcyXAUBgApa7VybMw=
-github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lightstep/lightstep-tracer-go v0.25.0 h1:sGVnz8h3jTQuHKMbUe2949nXm3Sg09N1UcR3VoQNN5E=
github.com/lightstep/lightstep-tracer-go v0.25.0/go.mod h1:G1ZAEaqTHFPWpWunnbUn1ADEY/Jvzz7jIOaXwAfD6A8=
github.com/linode/linodego v1.4.0/go.mod h1:PVsRxSlOiJyvG4/scTszpmZDTdgS+to3X6eS8pRrWI8=
-github.com/linode/linodego v1.9.3/go.mod h1:h6AuFR/JpqwwM/vkj7s8KV3iGN8/jxn+zc437F8SZ8w=
+github.com/linode/linodego v1.12.0/go.mod h1:NJlzvlNtdMRRkXb0oN6UWzUkj6t+IBsyveHgZ5Ppjyk=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
-github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -1426,18 +1482,23 @@ github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U=
-github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
+github.com/microsoft/go-mssqldb v0.18.0/go.mod h1:ukJCBnnzLzpVF0qYRT+eg1e+eSwjeQ7IvenUv8QPook=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
+github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
+github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
@@ -1455,6 +1516,7 @@ github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:F
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
@@ -1486,16 +1548,18 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
-github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q=
+github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY=
+github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g=
+github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
+github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
+github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
-github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc=
@@ -1513,11 +1577,14 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
+github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
+github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -1527,11 +1594,15 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
+github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
-github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
+github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
+github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
+github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
+github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -1560,33 +1631,27 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
-github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
-github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
-github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
-github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
+github.com/ovh/go-ovh v1.3.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
+github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
@@ -1606,37 +1671,32 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/alertmanager v0.24.0/go.mod h1:r6fy/D7FRuZh5YbnX6J3MBY0eI4Pb5yPYS7/bPSXXqI=
+github.com/prometheus/alertmanager v0.25.0/go.mod h1:MEZ3rFVHqKZsw7IcNS/m4AWZeXThmJhumpiWR4eHU/w=
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
-github.com/prometheus/client_golang v1.13.1/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
@@ -1644,8 +1704,10 @@ github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
-github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
+github.com/prometheus/common v0.38.0/go.mod h1:MBXfmBQZrK5XpbCkjofnXs96LD2QQ7fEq4C0xjC/yec=
+github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI=
+github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y=
github.com/prometheus/common/assets v0.1.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI=
github.com/prometheus/common/assets v0.2.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI=
github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
@@ -1653,7 +1715,6 @@ github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQY
github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -1667,11 +1728,11 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY=
-github.com/prometheus/prometheus v0.40.5 h1:wmk5yNrQlkQ2OvZucMhUB4k78AVfG34szb1UtopS8Vc=
-github.com/prometheus/prometheus v0.40.5/go.mod h1:bxgdmtoSNLmmIVPGmeTJ3OiP67VmuY4yalE4ZP6L/j8=
+github.com/prometheus/prometheus v0.42.0 h1:G769v8covTkOiNckXFIwLx01XE04OE6Fr0JPA0oR2nI=
+github.com/prometheus/prometheus v0.42.0/go.mod h1:Pfqb/MLnnR2KK+0vchiaH39jXxvLMBk+3lnIGP4N7Vk=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rafaeljusto/redigomock/v3 v3.1.1 h1:SdWE9v+SPy3x6G5hS3aofIJgHJY3OdBJ0BdUTk4dYbA=
-github.com/rafaeljusto/redigomock/v3 v3.1.1/go.mod h1:F9zPqz8rMriScZkPtUiLJoLruYcpGo/XXREpeyasREM=
+github.com/rafaeljusto/redigomock/v3 v3.1.2 h1:B4Y0XJQiPjpwYmkH55aratKX1VfR+JRqzmDKyZbC99o=
+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/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -1679,6 +1740,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
@@ -1692,9 +1754,10 @@ github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
-github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
+github.com/scaleway/scaleway-sdk-go v1.0.0-beta.12/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -1707,7 +1770,7 @@ github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 h1:WnNuhiq+F
github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500/go.mod h1:+njLrG5wSeoG4Ds61rFgEzKvenR2UHbjMoDHsczxly0=
github.com/shirou/gopsutil/v3 v3.21.2 h1:fIOk3hyqV1oGKogfGNjUZa0lUbtlkx3+ZT0IoJth2uM=
github.com/shirou/gopsutil/v3 v3.21.2/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
-github.com/shoenig/test v0.4.3/go.mod h1:xYtyGBC5Q3kzCNyJg/SjgNpfAa2kvmgA0i5+lQso8x0=
+github.com/shoenig/test v0.6.0/go.mod h1:xYtyGBC5Q3kzCNyJg/SjgNpfAa2kvmgA0i5+lQso8x0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
@@ -1741,16 +1804,19 @@ github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
+github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -1760,11 +1826,12 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
+github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -1780,10 +1847,13 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@@ -1846,22 +1916,25 @@ github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
-gitlab.com/gitlab-org/gitaly/v15 v15.9.0-rc4 h1:n6VW2djSoiGaajMUkVy+crRnyiUePcW1v1T3wPd2hhI=
-gitlab.com/gitlab-org/gitaly/v15 v15.9.0-rc4/go.mod h1:y0OCqEn0WWmyycVpde494A5qhCszhlx2b+od6vSzsOU=
+gitlab.com/gitlab-org/gitaly/v15 v15.9.3 h1:jloqZdc+TkpZHU2pr4grHKNAp+zg6NeB4vQZgRrOvCE=
+gitlab.com/gitlab-org/gitaly/v15 v15.9.3/go.mod h1:MLAmjPsXan0TixWBOnF2GUTjHcNLoAiYv1x1LRx7gHQ=
gitlab.com/gitlab-org/golang-archive-zip v0.1.1 h1:35k9giivbxwF03+8A05Cm8YoxoakU8FBCj5gysjCTCE=
gitlab.com/gitlab-org/golang-archive-zip v0.1.1/go.mod h1:ZDtqpWPGPB9qBuZnZDrKQjIdJtkN7ZAoVwhT6H2o2kE=
-gitlab.com/gitlab-org/labkit v1.17.0 h1:mEkoLzXorLNdt8NkfgYS5xMDhdqCsIJaeEVtSf7d8cU=
-gitlab.com/gitlab-org/labkit v1.17.0/go.mod h1:nlLJvKgXcIclqWMI+rga2TckNBVHOtRCHMxBoVByNoE=
+gitlab.com/gitlab-org/labkit v1.18.0 h1:uYCIqDt/5V1hLIecTR4UNc1sD2+xiYplyKeyfpNN26A=
+gitlab.com/gitlab-org/labkit v1.18.0/go.mod h1:nlLJvKgXcIclqWMI+rga2TckNBVHOtRCHMxBoVByNoE=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
-go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
+go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU=
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
+go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
@@ -1869,11 +1942,9 @@ go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R7
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
-go.mongodb.org/mongo-driver v1.10.2/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8=
+go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -1888,33 +1959,35 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.2
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0/go.mod h1:+ARmXlUlc51J7sZeCBkBJNdHGySrdOzgzxp6VWRWM1U=
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=
go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ=
go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ=
go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE=
+go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI=
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.1/go.mod h1:NEu79Xo32iVb+0gVNV8PMd7GoWqnyDXRlj04yFjqz40=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ=
+go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2/go.mod h1:rqbht/LlhVBgn5+k3M5QK96K5Xb0DvXpMJ5SFQpY6uw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.1/go.mod h1:YJ/JbY5ag/tSQFXzH3mtDmHqzF3aFn3DI/aB1n7pt4w=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1/go.mod h1:19O5I2U5iys38SsmT2uDJja/300woyzE1KPIQxEUBUc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.2/go.mod h1:5Qn6qvgkMsLDX+sYK64rHb1FPhpn0UtxF+ouX1uhyJE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.1/go.mod h1:UJJXJj0rltNIemDMwkOJyggsvyMG9QHfJeFH0HS5JjM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1/go.mod h1:QrRRQiY3kzAoYPNLP0W/Ikg0gR6V3LMc+ODSxr7yyvg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.2/go.mod h1:jWZUM2MWhWCJ9J9xVbRx7tzK1mXKpAlze4CeulycwVY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.1/go.mod h1:DAKwdo06hFLc0U88O10x4xnb5sc7dDRDqRuiN+io8JE=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.1/go.mod h1:X620Jww3RajCJXw/unA+8IRTgxkdS7pi+ZwK9b7KUJk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.2/go.mod h1:GZWSQQky8AgdJj50r1KJm8oiQiIPaAX7uZCFQX9GzC8=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw=
-go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI=
+go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8=
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs=
go.opentelemetry.io/otel/sdk v1.6.1/go.mod h1:IVYrddmFZ+eJqu2k38qD3WezFR2pymCzm8tdxyh3R4E=
go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys=
+go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU=
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
@@ -1922,6 +1995,7 @@ go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKu
go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE=
go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0=
go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk=
+go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ=
go.opentelemetry.io/proto/otlp v0.12.1/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
@@ -1937,6 +2011,7 @@ go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
@@ -1945,16 +2020,17 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
+go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
-gocloud.dev v0.28.0 h1:PjL1f9zu8epY1pFCIHdrQnJRZzRcDyAr18hNTkXIKlQ=
-gocloud.dev v0.28.0/go.mod h1:nzSs01FpRYyIb/OqXLNNa+NMPZG9CdTUY/pGLgSpIN0=
+gocloud.dev v0.29.0 h1:fBy0jwJSmxs0IjT0fE32MO+Mj+307VZQwyHaTyFZbC4=
+gocloud.dev v0.29.0/go.mod h1:E3dAjji80g+lIkq4CQeF/BTWqv1CBeTftmOb+gpyapQ=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1970,31 +2046,38 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
-golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
-golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
+golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
@@ -2004,15 +2087,17 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
-golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20230124195608-d38c7dcee874/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w=
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM=
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU=
-golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
+golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
+golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -2041,8 +2126,10 @@ golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -2052,7 +2139,6 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -2102,9 +2188,11 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -2114,20 +2202,25 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220907135653-1e95f45603a7/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
-golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -2145,6 +2238,7 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
@@ -2156,10 +2250,10 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
-golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
-golang.org/x/oauth2 v0.2.0/go.mod h1:Cwn6afJ8jrQwYMxQDTpISoXmXW9I6qF6vDeuuoX3Ibs=
-golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
+golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
+golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
+golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -2173,6 +2267,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -2185,7 +2280,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -2222,7 +2317,6 @@ golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -2324,12 +2418,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220908150016-7ac13a9a928d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -2340,6 +2434,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2352,8 +2448,9 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2367,15 +2464,15 @@ golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190308174544-00c44ba9c14f/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -2455,8 +2552,12 @@ golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyj
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
+golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
+golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
+golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
+golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2468,9 +2569,12 @@ golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNq
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
+gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
+gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
+gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20170921000349-586095a6e407/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -2502,6 +2606,7 @@ google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E=
+google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
@@ -2512,6 +2617,7 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
+google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko=
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
@@ -2523,10 +2629,14 @@ google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ
google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08=
google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo=
-google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ=
google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
+google.golang.org/api v0.104.0/go.mod h1:JCspTXJbBxa5ySXw4UgUqVer7DfVxbvc/CTUFqAED5U=
+google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
+google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
+google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
+google.golang.org/api v0.110.0 h1:l+rh0KYUooe9JGbGVx71tbFo4SMbMTXK3I3ia2QSEeU=
+google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
@@ -2606,7 +2716,9 @@ google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEc
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211018162055-cf77aa76bad2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
@@ -2627,6 +2739,7 @@ google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
@@ -2655,21 +2768,27 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz
google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo=
-google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
+google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
+google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
-google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
-google.golang.org/genproto v0.0.0-20230117162540-28d6b9783ac4 h1:yF0uHwqqYt2tIL2F4hxRWA1ZFX43SEunWAK8MnQiclk=
-google.golang.org/genproto v0.0.0-20230117162540-28d6b9783ac4/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
+google.golang.org/genproto v0.0.0-20221205194025-8222ab48f5fc/go.mod h1:1dOng4TWOomJrDGhpXjfCD35wQC6jnC7HpRmOFRqEV0=
+google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6/go.mod h1:1dOng4TWOomJrDGhpXjfCD35wQC6jnC7HpRmOFRqEV0=
+google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc h1:ijGwO+0vL2hJt5gaygqP2j6PfflOBrRot0IczKbmtio=
+google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
@@ -2707,6 +2826,7 @@ google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
+google.golang.org/grpc v1.52.1/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
@@ -2724,8 +2844,9 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.29.0 h1:44S3JjaKmLEE4YIkjzexaP+NzZsudE3Zin5Njn/pYX0=
+google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/DataDog/dd-trace-go.v1 v1.32.0 h1:DkD0plWEVUB8v/Ru6kRBW30Hy/fRNBC8hPdcExuBZMc=
gopkg.in/DataDog/dd-trace-go.v1 v1.32.0/go.mod h1:wRKMf/tRASHwH/UOfPQ3IQmVFhTz2/1a1/mpXoIjF54=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
@@ -2747,13 +2868,16 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/telebot.v3 v3.0.0/go.mod h1:7rExV8/0mDDNu9epSrDm/8j22KLaActH1Tbee6YjzWg=
+gopkg.in/telebot.v3 v3.1.2/go.mod h1:GJKwwWqp9nSkIVN51eRKU78aB5f5OnQuWdwiIZfPbko=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -2776,7 +2900,6 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -2791,14 +2914,14 @@ k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs=
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
-k8s.io/api v0.25.3/go.mod h1:o42gKscFrEVjHdQnyRenACrMtbuJsVdP+WVjqejfzmI=
+k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg=
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U=
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
-k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
+k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74=
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
@@ -2808,7 +2931,7 @@ k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y=
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
-k8s.io/client-go v0.25.3/go.mod h1:t39LPczAIMwycjcXkVc+CB+PZV69jQuNx4um5ORDjQA=
+k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE=
k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0=
k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
@@ -2830,23 +2953,25 @@ k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/klog/v2 v2.80.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
-k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU=
+k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
+k8s.io/kube-openapi v0.0.0-20221207184640-f3cff1453715/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
@@ -2854,6 +2979,7 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyz
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
@@ -2863,4 +2989,3 @@ sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ih
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
-sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/yarn.lock b/yarn.lock
index 244e5dada65..db5f1a23fd8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,17 +2,6 @@
# yarn lockfile v1
-"@_ueberdosis/prosemirror-tables@1.1.3", "@_ueberdosis/prosemirror-tables@^1.1.3":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@_ueberdosis/prosemirror-tables/-/prosemirror-tables-1.1.3.tgz#56fdbc8b1d6ec43e7b7beb21e213c131eec451cd"
- integrity sha512-su3pbFi1DT89g6Cuh72TE0MWWKHmWgHcQJ3ODRkm6XfIppWaGpU49t02ur3sgJc7hUhfQXjB93aSkDgOmIii2w==
- dependencies:
- prosemirror-keymap "^1.1.2"
- prosemirror-model "^1.8.1"
- prosemirror-state "^1.3.1"
- prosemirror-transform "^1.2.1"
- prosemirror-view "^1.13.3"
-
"@ampproject/remapping@^2.1.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34"
@@ -349,10 +338,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.8", "@babel/parser@^7.18.10", "@babel/parser@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.0.tgz#497fcafb1d5b61376959c1c338745ef0577aa02c"
- integrity sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==
+"@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.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==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.17.12":
version "7.17.12"
@@ -976,12 +965,12 @@
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.13.10", "@babel/runtime@^7.8.4":
- version "7.14.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6"
- integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==
+"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.13.10", "@babel/runtime@^7.8.4":
+ version "7.21.0"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
+ integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
dependencies:
- regenerator-runtime "^0.13.4"
+ regenerator-runtime "^0.13.11"
"@babel/template@^7.16.7", "@babel/template@^7.18.10", "@babel/template@^7.3.3":
version "7.18.10"
@@ -1027,23 +1016,17 @@
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz#fe364f025ba74f6de6c837a84ef44bdb1d61e68f"
integrity sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==
-"@cspotcode/source-map-support@^0.8.0":
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
- integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
- dependencies:
- "@jridgewell/trace-mapping" "0.3.9"
-
"@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==
-"@cubejs-client/core@^0.31.15":
- version "0.31.15"
- resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.31.15.tgz#db0ee90f5ba7f33a3fae6c81e5e13ab1cf2cd71b"
- integrity sha512-VQqvvJn++nqO8aOr/dFtyUURNFYAlP3XlDiupiGLXmSsuUn0BuozJQAmJ5XxPPhvz5k9qBko7KkZuC6ikZTdcA==
+"@cubejs-client/core@^0.32.0":
+ version "0.32.0"
+ resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.32.0.tgz#9018ea2e3658107adacbc188c0c1ebcc54ee9436"
+ integrity sha512-Jqpv2S/CQUN0TNgFiKzVR8JehDgQA+z19yQOM/3Z0UrE6llYXu6x5zlI7FldtuXwFaLO1gfRd4yHsjp/Mf39TA==
dependencies:
+ "@babel/runtime" "^7.1.2"
core-js "^3.6.5"
cross-fetch "^3.0.2"
dayjs "^1.10.4"
@@ -1051,12 +1034,12 @@
url-search-params-polyfill "^7.0.0"
uuid "^8.3.2"
-"@cubejs-client/vue@^0.31.19":
- version "0.31.19"
- resolved "https://registry.yarnpkg.com/@cubejs-client/vue/-/vue-0.31.19.tgz#cd8f588e14046091b085c3405f28a62f3e4d949d"
- integrity sha512-SY2+flIZJARp0cpS7e9ewYwaYCqqh8ifyc11S55ENo2KJsyzdLELSIiTDqy6hppXqtALSOE4feW4Eb/blh6e0w==
+"@cubejs-client/vue@^0.32.0":
+ version "0.32.0"
+ resolved "https://registry.yarnpkg.com/@cubejs-client/vue/-/vue-0.32.0.tgz#06901d4d0fdeaf462e6374d5b973c8d5e4f26b37"
+ integrity sha512-i4Mp3zZiL+bdjdgcLj1JIKPq444pQem8ega0MUb8RBG6A4texip1HMLpXFBGcgdZ1XQ/a8MQTW8ytntMS8BE/A==
dependencies:
- "@cubejs-client/core" "^0.31.15"
+ "@cubejs-client/core" "^0.32.0"
core-js "^3.6.5"
ramda "^0.27.2"
@@ -1065,234 +1048,136 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz#d5e0706cf8c6acd8c6032f8d54070af261bbbb2f"
integrity sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==
-"@esbuild/android-arm64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23"
- integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==
-
-"@esbuild/android-arm64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.4.tgz#0a900a7e448cc038ae5a751255257fc67163ed32"
- integrity sha512-91VwDrl4EpxBCiG6h2LZZEkuNvVZYJkv2T9gyLG/mhGG1qrM7i5SwUcg/hlSPnL/4hDT0TFcF35/XMGSn0bemg==
-
-"@esbuild/android-arm@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2"
- integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==
-
-"@esbuild/android-arm@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.4.tgz#fe32ce82eb6064d3dc13c0d8ca0e440bbc776c93"
- integrity sha512-R9GCe2xl2XDSc2XbQB63mFiFXHIVkOP+ltIxICKXqUPrFX97z6Z7vONCLQM1pSOLGqfLrGi3B7nbhxmFY/fomg==
-
-"@esbuild/android-x64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e"
- integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==
-
-"@esbuild/android-x64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.4.tgz#6ae1056f6ecf1963c1d076cf5f0109b52d8049f6"
- integrity sha512-mGSqhEPL7029XL7QHNPxPs15JVa02hvZvysUcyMP9UXdGFwncl2WU0bqx+Ysgzd+WAbv8rfNa73QveOxAnAM2w==
-
-"@esbuild/darwin-arm64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220"
- integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==
-
-"@esbuild/darwin-arm64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.4.tgz#5064d81ee5b8d646a5b7cc3e53c98cb983c4af55"
- integrity sha512-tTyJRM9dHvlMPt1KrBFVB5OW1kXOsRNvAPtbzoKazd5RhD5/wKlXk1qR2MpaZRYwf4WDMadt0Pv0GwxB41CVow==
-
-"@esbuild/darwin-x64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4"
- integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==
-
-"@esbuild/darwin-x64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.4.tgz#67f0213b3333248b32a97a7fc3fee880c2157674"
- integrity sha512-phQuC2Imrb3TjOJwLN8EO50nb2FHe8Ew0OwgZDH1SV6asIPGudnwTQtighDF2EAYlXChLoMJwqjAp4vAaACq6w==
-
-"@esbuild/freebsd-arm64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27"
- integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==
-
-"@esbuild/freebsd-arm64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.4.tgz#8eaaa126d9ff24822c730f06a71ac2d1091dc1c2"
- integrity sha512-oH6JUZkocgmjzzYaP5juERLpJQSwazdjZrTPgLRmAU2bzJ688x0vfMB/WTv4r58RiecdHvXOPC46VtsMy/mepg==
-
-"@esbuild/freebsd-x64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72"
- integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==
-
-"@esbuild/freebsd-x64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.4.tgz#314eff900a71abf64d4e5bea31e430d8ebd78d79"
- integrity sha512-U4iWGn/9TrAfpAdfd56eO0pRxIgb0a8Wj9jClrhT8hvZnOnS4dfMPW7o4fn15D/KqoiVYHRm43jjBaTt3g/2KA==
-
-"@esbuild/linux-arm64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca"
- integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==
-
-"@esbuild/linux-arm64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.4.tgz#5bed6bb8eb1d331644f8b31c87b8df57f204e84e"
- integrity sha512-UkGfQvYlwOaeYJzZG4cLV0hCASzQZnKNktRXUo3/BMZvdau40AOz9GzmGA063n1piq6VrFFh43apRDQx8hMP2w==
-
-"@esbuild/linux-arm@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196"
- integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==
-
-"@esbuild/linux-arm@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.4.tgz#6eaa41f37e231d113da715a1d9cc820e5523aeb6"
- integrity sha512-S2s9xWTGMTa/fG5EyMGDeL0wrWVgOSQcNddJWgu6rG1NCSXJHs76ZP9AsxjB3f2nZow9fWOyApklIgiTGZKhiw==
-
-"@esbuild/linux-ia32@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54"
- integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==
-
-"@esbuild/linux-ia32@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.4.tgz#3fc352bb54e0959fda273cd2253b1c72ca41b8c2"
- integrity sha512-3lqFi4VFo/Vwvn77FZXeLd0ctolIJH/uXkH3yNgEk89Eh6D3XXAC9/iTPEzeEpsNE5IqGIsFa5Z0iPeOh25IyA==
-
-"@esbuild/linux-loong64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8"
- integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==
-
-"@esbuild/linux-loong64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.4.tgz#86d54f690be53669cd2a38a5333ecf2608c11189"
- integrity sha512-HqpWZkVslDHIwdQ9D+gk7NuAulgQvRxF9no54ut/M55KEb3mi7sQS3GwpPJzSyzzP0UkjQVN7/tbk88/CaX4EQ==
-
-"@esbuild/linux-mips64el@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726"
- integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==
-
-"@esbuild/linux-mips64el@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.4.tgz#3dbd897bd8f047fef35e69bd253b8f07ca7fe483"
- integrity sha512-d/nMCKKh/SVDbqR9ju+b78vOr0tNXtfBjcp5vfHONCCOAL9ad8gN9dC/u+UnH939pz7wO+0u/x9y1MaZcb/lKA==
-
-"@esbuild/linux-ppc64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8"
- integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==
-
-"@esbuild/linux-ppc64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.4.tgz#defaff6db9a60f08936fc0c59e0eabfb1055968a"
- integrity sha512-lOD9p2dmjZcNiTU+sGe9Nn6G3aYw3k0HBJies1PU0j5IGfp6tdKOQ6mzfACRFCqXjnBuTqK7eTYpwx09O5LLfg==
-
-"@esbuild/linux-riscv64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9"
- integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==
-
-"@esbuild/linux-riscv64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.4.tgz#270a09f6f4205a8a8c8ed3c7dbabdcebaafa8a84"
- integrity sha512-mTGnwWwVshAjGsd8rP+K6583cPDgxOunsqqldEYij7T5/ysluMHKqUIT4TJHfrDFadUwrghAL6QjER4FeqQXoA==
-
-"@esbuild/linux-s390x@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87"
- integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==
-
-"@esbuild/linux-s390x@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.4.tgz#197695bece68f514dcdcc286562b5d48c5dad5f9"
- integrity sha512-AQYuUGp50XM29/N/dehADxvc2bUqDcoqrVuijop1Wv72SyxT6dDB9wjUxuPZm2HwIM876UoNNBMVd+iX/UTKVQ==
-
-"@esbuild/linux-x64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f"
- integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==
-
-"@esbuild/linux-x64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.4.tgz#db50cdfb071c0d367025c1c98563aab1318f800e"
- integrity sha512-+AsFBwKgQuhV2shfGgA9YloxLDVjXgUEWZum7glR5lLmV94IThu/u2JZGxTgjYby6kyXEx8lKOqP5rTEVBR0Rw==
-
-"@esbuild/netbsd-x64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775"
- integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==
-
-"@esbuild/netbsd-x64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.4.tgz#e4d5d8022f8eddbd7d9899d58265915444f46f3b"
- integrity sha512-zD1TKYX9553OiLS/qkXPMlWoELYkH/VkzRYNKEU+GwFiqkq0SuxsKnsCg5UCdxN3cqd+1KZ8SS3R+WG/Hxy2jQ==
-
-"@esbuild/openbsd-x64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35"
- integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==
-
-"@esbuild/openbsd-x64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.4.tgz#9b770e1e7745824cbe155f5a742fc781855a7e68"
- integrity sha512-PY1NjEsLRhPEFFg1AV0/4Or/gR+q2dOb9s5rXcPuCjyHRzbt8vnHJl3vYj+641TgWZzTFmSUnZbzs1zwTzjeqw==
-
-"@esbuild/sunos-x64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c"
- integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==
-
-"@esbuild/sunos-x64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.4.tgz#4c6d2290f8bf39ab9284f5a1b9a2210858e2d6e6"
- integrity sha512-B3Z7s8QZQW9tKGleMRXvVmwwLPAUoDCHs4WZ2ElVMWiortLJFowU1NjAhXOKjDgC7o9ByeVcwyOlJ+F2r6ZgmQ==
-
-"@esbuild/win32-arm64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a"
- integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==
-
-"@esbuild/win32-arm64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.4.tgz#424954b6d598f40e2c5a0d85e3af07147fb41909"
- integrity sha512-0HCu8R3mY/H5V7N6kdlsJkvrT591bO/oRZy8ztF1dhgNU5xD5tAh5bKByT1UjTGjp/VVBsl1PDQ3L18SfvtnBQ==
-
-"@esbuild/win32-ia32@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09"
- integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==
-
-"@esbuild/win32-ia32@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.4.tgz#2c94e9c3a82c779d3f07b3fb5c482a2e3fecedb1"
- integrity sha512-VUjhVDQycse1gLbe06pC/uaA0M+piQXJpdpNdhg8sPmeIZZqu5xPoGWVCmcsOO2gaM2cywuTYTHkXRozo3/Nkg==
-
-"@esbuild/win32-x64@0.16.17":
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091"
- integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==
-
-"@esbuild/win32-x64@0.17.4":
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.4.tgz#9b7760cdc77678bdbc5b582fae2cf3de449df048"
- integrity sha512-0kLAjs+xN5OjhTt/aUA6t48SfENSCKgGPfExADYTOo/UCn0ivxos9/anUVeSfg+L+2O9xkFxvJXIJfG+Q4sYSg==
-
-"@eslint/eslintrc@^1.4.1":
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e"
- integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==
+"@esbuild/android-arm64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.11.tgz#52c3e6cabc19c5e4c1c0c01cb58f0442338e1c14"
+ integrity sha512-QnK4d/zhVTuV4/pRM4HUjcsbl43POALU2zvBynmrrqZt9LPcLA3x1fTZPBg2RRguBQnJcnU059yKr+bydkntjg==
+
+"@esbuild/android-arm@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.11.tgz#f3fc768235aecbeb840d0049fdf13cd28592105f"
+ integrity sha512-CdyX6sRVh1NzFCsf5vw3kULwlAhfy9wVt8SZlrhQ7eL2qBjGbFhRBWkkAzuZm9IIEOCKJw4DXA6R85g+qc8RDw==
+
+"@esbuild/android-x64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.11.tgz#443ed47771a7e917e4282469ba350d117473550c"
+ integrity sha512-3PL3HKtsDIXGQcSCKtWD/dy+mgc4p2Tvo2qKgKHj9Yf+eniwFnuoQ0OUhlSfAEpKAFzF9N21Nwgnap6zy3L3MQ==
+
+"@esbuild/darwin-arm64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.11.tgz#0e8c78d94d5759a48521dbfd83189d2ed3499a16"
+ integrity sha512-pJ950bNKgzhkGNO3Z9TeHzIFtEyC2GDQL3wxkMApDEghYx5Qers84UTNc1bAxWbRkuJOgmOha5V0WUeh8G+YGw==
+
+"@esbuild/darwin-x64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.11.tgz#2405cfdf70eb961c7cf973463ca7263dc2004c88"
+ integrity sha512-iB0dQkIHXyczK3BZtzw1tqegf0F0Ab5texX2TvMQjiJIWXAfM4FQl7D909YfXWnB92OQz4ivBYQ2RlxBJrMJOw==
+
+"@esbuild/freebsd-arm64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.11.tgz#d5138e873e15f87bd4564c024dfa00ef37e623fd"
+ integrity sha512-7EFzUADmI1jCHeDRGKgbnF5sDIceZsQGapoO6dmw7r/ZBEKX7CCDnIz8m9yEclzr7mFsd+DyasHzpjfJnmBB1Q==
+
+"@esbuild/freebsd-x64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.11.tgz#e850b58b8fabf8e9ef0e125af3c25229ad2d6c38"
+ integrity sha512-iPgenptC8i8pdvkHQvXJFzc1eVMR7W2lBPrTE6GbhR54sLcF42mk3zBOjKPOodezzuAz/KSu8CPyFSjcBMkE9g==
+
+"@esbuild/linux-arm64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.11.tgz#2bfb93d0809ec2357c12ebb27736b750c9ae0aa5"
+ integrity sha512-Qxth3gsWWGKz2/qG2d5DsW/57SeA2AmpSMhdg9TSB5Svn2KDob3qxfQSkdnWjSd42kqoxIPy3EJFs+6w1+6Qjg==
+
+"@esbuild/linux-arm@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.11.tgz#e56fb3b76828317a704f4a167c5bd790fe5314e7"
+ integrity sha512-M9iK/d4lgZH0U5M1R2p2gqhPV/7JPJcRz+8O8GBKVgqndTzydQ7B2XGDbxtbvFkvIs53uXTobOhv+RyaqhUiMg==
+
+"@esbuild/linux-ia32@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.11.tgz#59fa1c49b271793d14eb5effc757e8c0d0cb2cab"
+ integrity sha512-dB1nGaVWtUlb/rRDHmuDQhfqazWE0LMro/AIbT2lWM3CDMHJNpLckH+gCddQyhhcLac2OYw69ikUMO34JLt3wA==
+
+"@esbuild/linux-loong64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.11.tgz#89575bc189099c03a36daa54f3f481780c7fd502"
+ integrity sha512-aCWlq70Q7Nc9WDnormntGS1ar6ZFvUpqr8gXtO+HRejRYPweAFQN615PcgaSJkZjhHp61+MNLhzyVALSF2/Q0g==
+
+"@esbuild/linux-mips64el@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.11.tgz#0e18ca039dc7e4645efd8edc1b10952933eb6b1b"
+ integrity sha512-cGeGNdQxqY8qJwlYH1BP6rjIIiEcrM05H7k3tR7WxOLmD1ZxRMd6/QIOWMb8mD2s2YJFNRuNQ+wjMhgEL2oCEw==
+
+"@esbuild/linux-ppc64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.11.tgz#2d152cb3a253afb8c100a165ad132dc96f36cb11"
+ integrity sha512-BdlziJQPW/bNe0E8eYsHB40mYOluS+jULPCjlWiHzDgr+ZBRXPtgMV1nkLEGdpjrwgmtkZHEGEPaKdS/8faLDA==
+
+"@esbuild/linux-riscv64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.11.tgz#c6ac494a81221d53d65b33e665c7df1747952d3c"
+ integrity sha512-MDLwQbtF+83oJCI1Cixn68Et/ME6gelmhssPebC40RdJaect+IM+l7o/CuG0ZlDs6tZTEIoxUe53H3GmMn8oMA==
+
+"@esbuild/linux-s390x@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.11.tgz#4bad33894bc7415cea4be8fa90fe456226a424ad"
+ integrity sha512-4N5EMESvws0Ozr2J94VoUD8HIRi7X0uvUv4c0wpTHZyZY9qpaaN7THjosdiW56irQ4qnJ6Lsc+i+5zGWnyqWqQ==
+
+"@esbuild/linux-x64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.11.tgz#903fda743459f530a16a6c6ee8d2c0f6c1a12fc7"
+ integrity sha512-rM/v8UlluxpytFSmVdbCe1yyKQd/e+FmIJE2oPJvbBo+D0XVWi1y/NQ4iTNx+436WmDHQBjVLrbnAQLQ6U7wlw==
+
+"@esbuild/netbsd-x64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.11.tgz#b589239fe7d9b16ee03c5e191f3f5b640f1518a1"
+ integrity sha512-4WaAhuz5f91h3/g43VBGdto1Q+X7VEZfpcWGtOFXnggEuLvjV+cP6DyLRU15IjiU9fKLLk41OoJfBFN5DhPvag==
+
+"@esbuild/openbsd-x64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.11.tgz#b355019754116bef39ec688f8fd2fe6471b9779b"
+ integrity sha512-UBj135Nx4FpnvtE+C8TWGp98oUgBcmNmdYgl5ToKc0mBHxVVqVE7FUS5/ELMImOp205qDAittL6Ezhasc2Ev/w==
+
+"@esbuild/sunos-x64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.11.tgz#2ea47fb592e68406e5025a7696dc714fc6a115dc"
+ integrity sha512-1/gxTifDC9aXbV2xOfCbOceh5AlIidUrPsMpivgzo8P8zUtczlq1ncFpeN1ZyQJ9lVs2hILy1PG5KPp+w8QPPg==
+
+"@esbuild/win32-arm64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.11.tgz#47e6fdab17c4c52e6e0d606dd9cb843b29826325"
+ integrity sha512-vtSfyx5yRdpiOW9yp6Ax0zyNOv9HjOAw8WaZg3dF5djEHKKm3UnoohftVvIJtRh0Ec7Hso0RIdTqZvPXJ7FdvQ==
+
+"@esbuild/win32-ia32@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.11.tgz#a97273aa3164c8d8f501899f55cc75a4a79599a3"
+ integrity sha512-GFPSLEGQr4wHFTiIUJQrnJKZhZjjq4Sphf+mM76nQR6WkQn73vm7IsacmBRPkALfpOCHsopSvLgqdd4iUW2mYw==
+
+"@esbuild/win32-x64@0.17.11":
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.11.tgz#9be796d93ae27b636da32d960899a4912bca27a1"
+ integrity sha512-N9vXqLP3eRL8BqSy8yn4Y98cZI2pZ8fyuHx6lKjiG2WABpT2l01TXdzq5Ma2ZUBzfB7tx5dXVhge8X9u0S70ZQ==
+
+"@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"
+ integrity sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==
+ dependencies:
+ eslint-visitor-keys "^3.3.0"
+
+"@eslint-community/regexpp@^4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403"
+ integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==
+
+"@eslint/eslintrc@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz#7888fe7ec8f21bc26d646dbd2c11cd776e21192d"
+ integrity sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
- espree "^9.4.0"
+ espree "^9.5.0"
globals "^13.19.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
@@ -1300,15 +1185,20 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
+"@eslint/js@8.36.0":
+ version "8.36.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe"
+ integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==
+
"@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/eslint-plugin@18.1.0":
- version "18.1.0"
- resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-18.1.0.tgz#8300cc938f50114b3e74d97660721486c13caea5"
- integrity sha512-O803ResZfPpbSk8USzYwT79OXKSyuR4z4qbjOae/NIhzobxrlEHm4LbauVuaFpHurF5gYceNtHltczwK8e+mOg==
+"@gitlab/eslint-plugin@18.2.0":
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-18.2.0.tgz#82810648a2273acfa5fd04fec9bf5dfa0f736c63"
+ integrity sha512-ynj2KyRkNykvZKqNDYInh5hZZRYxzZdOB6VUFOAjxW/nu2LDXquepqa+BDF956LDAhWMG0BGFqhqa8GRjxdi2w==
dependencies:
"@babel/core" "^7.17.0"
"@babel/eslint-parser" "^7.17.0"
@@ -1342,19 +1232,19 @@
stylelint-declaration-strict-value "1.8.0"
stylelint-scss "4.2.0"
-"@gitlab/svgs@3.20.0":
- version "3.20.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.20.0.tgz#4ee4f2f24304d13ccce58f82c2ecd87e556f35b4"
- integrity sha512-nYTF4j5kon4XbBr/sAzuubgxjIne9+RTZLmSrSaL9FL4eyuv9aa7YMCcOrlIbYX5jlSYlcD+ck2F2M1sqXXOBA==
+"@gitlab/svgs@3.26.0":
+ version "3.26.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.26.0.tgz#0324301f2aada66c39259ff050a567947db34515"
+ integrity sha512-tidak1UyCsrJ2jylybChNjJNnXUSoQ7rLzxMV2NJ/l2JiDDG7Bh8gn2CL2gk2icWa4Z2/DUfu2EhAAtdJtE0fQ==
-"@gitlab/ui@55.2.1":
- version "55.2.1"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-55.2.1.tgz#140d8e2c7428777a745fb1cfb33c29c3f1133113"
- integrity sha512-fIvGzM4nZtHWaUWfaM9PSPJJJFcnvCLCrdAsobiiMlxFFCEwDNm99oL+uzQgbatQRjjIdHqyFKFNMo3rg6U+AQ==
+"@gitlab/ui@58.2.0":
+ version "58.2.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-58.2.0.tgz#3fa8f34ab77783feba0d71abd8db644322796c4c"
+ integrity sha512-LWuNTzLd7+FoZxFt5i3C3/0hVOVIlnZbAZgQ6WwDbTlFn1f/slN7B5L89kleVE1OkgLLoqFuYwRUDPI0eySmvQ==
dependencies:
"@popperjs/core" "^2.11.2"
- bootstrap-vue "2.20.1"
- dompurify "^2.4.3"
+ bootstrap-vue "2.23.1"
+ dompurify "^2.4.5"
echarts "^5.3.2"
iframe-resizer "^4.3.2"
lodash "^4.17.20"
@@ -1366,26 +1256,27 @@
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-20230216131813":
- version "0.0.1-dev-20230216131813"
- resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20230216131813.tgz#f1c5de4e9bea0a1736296b0e63356ca39c065f54"
- integrity sha512-eqGh/gol3vnT62Fs2dR1JWfkX/hVDwcJaYT1JkFPtiaTi2hFwvqw7k3uKL3qIiYzL7V22avxwRIkbAZCI7aKbQ==
+"@gitlab/web-ide@0.0.1-dev-20230223005157":
+ version "0.0.1-dev-20230223005157"
+ resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20230223005157.tgz#e8ef36229dbe25bbfccfc57d5f02cce0c94b53c5"
+ integrity sha512-JLSIC/elod3txZL6CPe6hk07a97VAMjv+DmAvQFAJ/W/cj2wE+AG/ztr/brX2O88Cf4dX4nh48s1n49efMlajQ==
-"@graphql-eslint/eslint-plugin@3.12.0":
- version "3.12.0"
- resolved "https://registry.yarnpkg.com/@graphql-eslint/eslint-plugin/-/eslint-plugin-3.12.0.tgz#8676ef4ae113a8f0e5893e41ab0e391bf6667381"
- integrity sha512-DHa6hhCYxGjUtGK6VWcaWHs1RNSIpuZaQOzI7F2ZoVdtd3+amxv6S7h0KwUe+CX+oV3Oxa7x5bFonc/Td6wjaw==
+"@graphql-eslint/eslint-plugin@3.16.1":
+ version "3.16.1"
+ resolved "https://registry.yarnpkg.com/@graphql-eslint/eslint-plugin/-/eslint-plugin-3.16.1.tgz#04d7642b1779af48bf700229d297d2ac982b4fb2"
+ integrity sha512-sKmtlwVWjxCXlmgpNJSdvBqapluyrp6PA7FbSnpkyHD0ejkp3mhwZtCiR6843LmVFgWSzfAtEdjPCT2TcJ5p/w==
dependencies:
"@babel/code-frame" "^7.18.6"
"@graphql-tools/code-file-loader" "^7.3.6"
"@graphql-tools/graphql-tag-pluck" "^7.3.6"
- "@graphql-tools/utils" "^8.12.0"
+ "@graphql-tools/utils" "^9.0.0"
chalk "^4.1.2"
debug "^4.3.4"
fast-glob "^3.2.12"
- graphql-config "^4.3.6"
+ graphql-config "^4.4.0"
graphql-depth-limit "^1.1.0"
lodash.lowercase "^4.3.0"
+ tslib "^2.4.1"
"@graphql-tools/batch-execute@8.4.1":
version "8.4.1"
@@ -1514,7 +1405,7 @@
value-or-promise "^1.0.11"
ws "^8.3.0"
-"@graphql-tools/utils@8.12.0", "@graphql-tools/utils@^8.12.0", "@graphql-tools/utils@^8.6.5":
+"@graphql-tools/utils@8.12.0":
version "8.12.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.12.0.tgz#243bc4f5fc2edbc9e8fd1038189e57d837cbe31f"
integrity sha512-TeO+MJWGXjUTS52qfK4R8HiPoF/R7X+qmgtOYd8DTH0l6b+5Y/tlg5aGeUJefqImRq7nvi93Ms40k/Uz4D5CWw==
@@ -1528,6 +1419,14 @@
dependencies:
tslib "~2.3.0"
+"@graphql-tools/utils@^9.0.0":
+ version "9.2.1"
+ resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.1.tgz#1b3df0ef166cfa3eae706e3518b17d5922721c57"
+ integrity sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==
+ dependencies:
+ "@graphql-typed-document-node/core" "^3.1.1"
+ tslib "^2.4.0"
+
"@graphql-tools/wrap@8.4.10":
version "8.4.10"
resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-8.4.10.tgz#010be7d4bafa5d79cd1917c65d09f2682bcb9d54"
@@ -1539,10 +1438,10 @@
tslib "~2.3.0"
value-or-promise "1.0.11"
-"@graphql-typed-document-node/core@^3.0.0":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.0.tgz#0eee6373e11418bfe0b5638f654df7a4ca6a3950"
- integrity sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg==
+"@graphql-typed-document-node/core@^3.0.0", "@graphql-typed-document-node/core@^3.1.1":
+ version "3.1.2"
+ 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.8":
version "0.11.8"
@@ -1563,11 +1462,6 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
-"@iarna/toml@^2.2.5":
- version "2.2.5"
- resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c"
- integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==
-
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@@ -1812,14 +1706,6 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec"
integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==
-"@jridgewell/trace-mapping@0.3.9":
- version "0.3.9"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
- integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
- dependencies:
- "@jridgewell/resolve-uri" "^3.0.3"
- "@jridgewell/sourcemap-codec" "^1.4.10"
-
"@jridgewell/trace-mapping@^0.3.0", "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.9":
version "0.3.15"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
@@ -1838,6 +1724,16 @@
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz#0300943770e04231041a51bd39f0439b5c7ab4f0"
integrity sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==
+"@linaria/core@3.0.0-beta.13":
+ version "3.0.0-beta.13"
+ resolved "https://registry.yarnpkg.com/@linaria/core/-/core-3.0.0-beta.13.tgz#049c5be5faa67e341e413a0f6b641d5d78d91056"
+ integrity sha512-3zEi5plBCOsEzUneRVuQb+2SAx3qaC1dj0FfFAI6zIJQoDWu0dlSwKijMRack7oO9tUWrchfj3OkKQAd1LBdVg==
+
+"@mattiasbuelens/web-streams-adapter@^0.1.0":
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/@mattiasbuelens/web-streams-adapter/-/web-streams-adapter-0.1.0.tgz#607b5a25682f4ae2741da7ba6df39302505336b3"
+ integrity sha512-oV4PyZfwJNtmFWhvlJLqYIX1Nn22ML8FZpS16ZUKv0hg7414xV1fjsGqxQzLT2dyK92TKxsJSwMOd7VNHAtPmA==
+
"@miragejs/pretender-node-polyfill@^0.1.0":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@miragejs/pretender-node-polyfill/-/pretender-node-polyfill-0.1.2.tgz#d26b6b7483fb70cd62189d05c95d2f67153e43f2"
@@ -1905,6 +1801,41 @@
resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-6.1.4-7.tgz#ef0b83ef40f64bc6704e13ae6624236a4a91fa6f"
integrity sha512-842WcLh0BErNgGE8rdqNh31VnqGQcklPQ7RXzQfA0ilQNZcU7AO+t576g1m//18Lk8m7cXZ8fIKA1YB41LKWAQ==
+"@remirror/core-constants@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@remirror/core-constants/-/core-constants-2.0.0.tgz#a52f89059d93955e00810023cc76b4f7db9650bf"
+ integrity sha512-vpePPMecHJllBqCWXl6+FIcZqS+tRUM2kSCCKFeEo1H3XUEv3ocijBIPhnlSAa7g6maX+12ATTgxrOsLpWVr2g==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@remirror/core-helpers@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@remirror/core-helpers/-/core-helpers-2.0.1.tgz#6847666a009ada8c9b9f3a093c13a6d07a95d9bb"
+ integrity sha512-s8M1pn33aBUhduvD1QR02uUQMegnFkGaTr4c1iBzxTTyg0rbQstzuQ7Q8TkL6n64JtgCdJS9jLz2dONb2meBKQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@linaria/core" "3.0.0-beta.13"
+ "@remirror/core-constants" "^2.0.0"
+ "@remirror/types" "^1.0.0"
+ "@types/object.omit" "^3.0.0"
+ "@types/object.pick" "^1.3.1"
+ "@types/throttle-debounce" "^2.1.0"
+ case-anything "^2.1.10"
+ dash-get "^1.0.2"
+ deepmerge "^4.2.2"
+ fast-deep-equal "^3.1.3"
+ make-error "^1.3.6"
+ object.omit "^3.0.0"
+ object.pick "^1.3.0"
+ throttle-debounce "^3.0.1"
+
+"@remirror/types@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@remirror/types/-/types-1.0.0.tgz#cc8764440089a2ada71f149c409739575b73b12e"
+ integrity sha512-7HQbW7k8VxrAtfzs9FxwO6XSDabn8tSFDi1wwzShOnU+cvaYpfxu0ygyTk3TpXsag1hgFKY3ZIlAfB4WVz2LkQ==
+ dependencies:
+ type-fest "^2.0.0"
+
"@sentry/core@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3"
@@ -2006,253 +1937,220 @@
dom-accessibility-api "^0.5.1"
pretty-format "^26.4.2"
-"@tiptap/core@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.202.tgz#be4c6a200e81875c552e1cc15ae9c6cdd86c37c2"
- integrity sha512-KnOcZBtkWoDT7EsVLiJr9DyBnQcKJQHI8kOhNIL0snUrksr25q8xBW05iYqw6cGAF7iu1cFM80VikfgefsZUpw==
- dependencies:
- prosemirror-commands "^1.3.1"
- prosemirror-keymap "^1.2.0"
- prosemirror-model "^1.18.1"
- prosemirror-schema-list "^1.2.2"
- prosemirror-state "^1.4.1"
- prosemirror-transform "^1.7.0"
- prosemirror-view "^1.28.2"
+"@tiptap/core@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.220.tgz#ced4b8f13ad6361f957275510bd0c005de29d18c"
+ integrity sha512-F2Q666xJqijBU5o+GqekqseNgIEMTs6BhsLDaf9DwThhljGLS8RXKnSvQxrxLNrYEPpw39n/G3Qt8YAOk5qR6w==
-"@tiptap/extension-blockquote@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.202.tgz#91168b32387ed0ce4d03dd3b6c802682287ede3c"
- integrity sha512-weLbMxM7VfI4hJsThw1+mB4jbQnVFizmzRlGU40LKMzEU5yIgIhuaomQ02Z7V0cRgfXsoKX9oc0BYGiO0Ra6/g==
+"@tiptap/extension-blockquote@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.220.tgz#acce6a7d2fda829296e1e0b6386f618ea8ae328e"
+ integrity sha512-uE1VRU/doQzXsfsZ/JqsbSbXeZYTJnyQkSfHYA2ZYhbEM2XqDEsYkgcmZEJgunUZJpERf+3ZTfTpqaHq29iMMg==
-"@tiptap/extension-bold@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.202.tgz#877309e7b84701c22865517f09cbc5d288aa9369"
- integrity sha512-AsfoChIleoSbY9gAuhbLF8BAEhHPrRKofmU09xJ62SBkL1rtgci8YzJYhL9leQCM4n1MQZEDeVf0ho75HeTPMA==
+"@tiptap/extension-bold@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.220.tgz#f10468317fd5c63ebab68be907e33fb138a60ef9"
+ integrity sha512-KcEuKI85Drug/cCWbDy+HxhYrD+rLXHEBG10DmKPvgPpKHG/2wOau6LwUwyV4muWR8CR2mIO+mEc3yVBD8nNwQ==
-"@tiptap/extension-bubble-menu@2.0.0-beta.200", "@tiptap/extension-bubble-menu@^2.0.0-beta.200":
- version "2.0.0-beta.200"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.200.tgz#7851efdb5b9bccf78a020e386ee0f5eb92103198"
- integrity sha512-57EIDlYpI+jRurzHzsnulkAgf+LFoGytK5YcoXmuq8A2f295mj9ANzuOUnLJ76nm2NBmt8Y6ks0zUIIktKKK0Q==
+"@tiptap/extension-bubble-menu@2.0.0-beta.220", "@tiptap/extension-bubble-menu@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.220.tgz#3fea0c846f73a237f562fdce05671ef1fa025943"
+ integrity sha512-wthyec7s0vZlTSEAAZEgoFfx/1Arwg1zxDUrrE+YAost/Yn+w4xQksz/ts5Bx90iOk2qsJ+jzzttLRV17Ku7lA==
dependencies:
- prosemirror-state "^1.4.1"
- prosemirror-view "^1.28.2"
+ lodash "^4.17.21"
tippy.js "^6.3.7"
-"@tiptap/extension-bullet-list@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.202.tgz#1826ec86a83cc2feba3f90b3015c0e642a925f8c"
- integrity sha512-Su+GvRGyW9FTBtcFjvNkkYwzDRo+1O2YTNOZi1Z/OkDqbg3g89kRue78avs0nHW7HEgdhCap+z8KtAPrie4eBg==
-
-"@tiptap/extension-code-block-lowlight@2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.0.0-beta.202.tgz#a94635bbe26f94eec0aef08682ebc6cadd3ca05f"
- integrity sha512-FnYBl0Bgir+KkSScK4bUKVfvmEb2Q0aeDQh53umCeCGpVIzyO6JqggNqtBh0RqnJDptCSoP72fq7lu8uhQtYhw==
+"@tiptap/extension-bullet-list@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.220.tgz#ffc04992bbee53bc858aab6c082f17419a2236b7"
+ integrity sha512-QQ/0ZlYy6Hgb+UAc79V+fxvI+AaQf20cbKtBXaR8TIZ0x4FotSma89bKh+CIXMhFiBGXTcYBaYhl7OwACsKtxw==
+
+"@tiptap/extension-code-block-lowlight@2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.0.0-beta.220.tgz#9496a1989b5385872456f6910a43ac822b4896c1"
+ integrity sha512-xMwbl5O50yaIGYQF3yrBM7Ft0JYejkuEo161jRElYG+PYvUCvbf2wB5oLNtRknj00WOM01kPXH2xMTuk8fTOPg==
+
+"@tiptap/extension-code-block@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.220.tgz#8396b72f634d77d23b9ea01c9a253e8a7f471471"
+ integrity sha512-fgA7yTfHqhBtMJF7I9FPJ6UWuZPtxOQiN45Iv9LNmFIB6YRucdpmF+daZ27sElu0a+eICZyXwVn4w4iJphifuw==
+
+"@tiptap/extension-code@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.220.tgz#3543afeda2b0b240682a36eeb401b00a3da56ab6"
+ integrity sha512-JKKDZoceagqVXeC1XF/gOkKhLtsbYJYV+MRDorLnQVz4tXcg/SMs5Ez7OM9MxSSior8fIbUFMNsj1/UNlG+tFw==
+
+"@tiptap/extension-document@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.220.tgz#15b4db7a92659eff7efc6d4d877dcf72e3fd61b6"
+ integrity sha512-2sja4ZvOb4iynHrzinnclCSFgLyo6fJc1fBV5fIYaOgZOYcvz9KK8fgKiq+wIpG58sJEmQ5kcwwBlkXv+NTK+g==
+
+"@tiptap/extension-dropcursor@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.220.tgz#b635fa6cdf9be1027579c7ab6c00e5a811b3b30b"
+ integrity sha512-BIaA4Lvb3xL9KFN+K6SO2IHqLO6hDmGN2/rGKHFaU3Eh+oiXM2G73KTSS5KIP1u872zY1RpAtswSc4kjv3cuVw==
+
+"@tiptap/extension-floating-menu@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.220.tgz#35eb154227533ada738c922be2f8cf18426fe4bf"
+ integrity sha512-+WfcBEedm82ntaVIEQAGz0Om96Rpav7a+4f7e8N4PrLKm6nZ3gBaEkZVQ6vjJ6S/1htiWCv1XosYIwRboPBG0w==
dependencies:
- prosemirror-model "^1.18.1"
- prosemirror-state "^1.4.1"
- prosemirror-view "^1.28.2"
-
-"@tiptap/extension-code-block@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.202.tgz#a76fcb90e8e22082bedd9853f7a9bd0a541a800e"
- integrity sha512-tfK9khIroGjsXQvk2K/9z1/UyQrB4+zghkjyK1xikzRmhgfOeqQzA0TDrFrz7ywFXmSFQ7GnnYAp+RW6r6wyUg==
- dependencies:
- prosemirror-state "^1.4.1"
-
-"@tiptap/extension-code@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.202.tgz#5d4352a6cc4a2d16262472fb11c54cfca24bd40a"
- integrity sha512-XwAr7ysSWJVZWHNXDaNBTPH1CTyVxHnPv/PiCWTGhf8Fkx7R7xW2QCUKx4ablwxFlTY7H8xGmCujaewUQBdO5w==
-
-"@tiptap/extension-document@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.202.tgz#fa2b1a42075b1a6bfbcd9564289dfbf7347c903c"
- integrity sha512-UsDSe93QtnuDrUo11wYCMtp7XlTIBvL5HNhx+enLRY7B8nUhX+d78u1BzspTpCkMYKcdwDmAGfIYMqqPViPEvA==
-
-"@tiptap/extension-dropcursor@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.202.tgz#a7e2b3c66dfb5c05077c05991fccd5e4166bdc1d"
- integrity sha512-4Q3LnqvMnxP0KdX7tIgCoTCKg949rg351m0wguVb1bo4v9lA0zfJpSgqjQ1Xs2vaYVBwkFjLoqrfhTRn5mnopQ==
- dependencies:
- prosemirror-dropcursor "1.5.0"
-
-"@tiptap/extension-floating-menu@^2.0.0-beta.200":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.202.tgz#9f895a04cd93cf4b41542ef3b09f3c90bfd0e215"
- integrity sha512-09liirOFsPDFRLS2FiFdnfzyyOQwwyVXLzI6MzUOw5RZbOsGJ5kB8jZdkXvsAIiOs0YYsH3fyOyWirIwSRhBTQ==
- dependencies:
- prosemirror-state "^1.4.1"
- prosemirror-view "^1.28.2"
tippy.js "^6.3.7"
-"@tiptap/extension-gapcursor@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.202.tgz#567fb6281068db7fb5da2092550e83e01530d8cf"
- integrity sha512-jOPMPPnTfVuc5YpFTcQM42/cg1J3+OeHitYb1/vBMpaNinVijuafsK14xDoVP8+sydKVgtBzYkfP/faN82I9iA==
- dependencies:
+"@tiptap/extension-gapcursor@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.220.tgz#07c96f7adc354d19b6209ea1e080188fb8d63de5"
+ integrity sha512-W5N2Ey+thufUOrs2TFGpEGBGue7ZEhcUXvxcsZlGbrjVa9Y+4rEp68Du4y7yM0hCeSj2GGwiV+uPzkc0CSDE/g==
+
+"@tiptap/extension-hard-break@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.220.tgz#8ff432615d9c9090c3d59c2a745c88e4f39ab1a3"
+ integrity sha512-oY3454o53YNFbuokzyGzG4PdMHkIYreY3nrALioZ0SwYeoFNcGA6Zcn4rDRfdp+QvbbiHfeBTR/CpWF13HZYTg==
+
+"@tiptap/extension-heading@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.220.tgz#b4889de7b3f152ff88a119d6cb6a22537eff73a2"
+ integrity sha512-7mrHRj++UaZ26C2Gjwb0WKWAzpiKb8TOYkVC2uMaCwaNhLDXpFEwZ7RtJRSTNBHkIGnMO46BH8Z0qlkFMmk9Jw==
+
+"@tiptap/extension-highlight@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.220.tgz#1bf2954524b99bb393dad46b5613b84aa660713f"
+ integrity sha512-+h4seFq99b0dCmShVlSc44PBQUiW4xBXze61V6ZNILLkfzo27wrj0W+I3WrdSXX9uz3wwE/BR+3T8m1Ro8lHng==
+
+"@tiptap/extension-history@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.220.tgz#6370b28872b29288d655cd14211efb8dc76daba0"
+ integrity sha512-qNL2a9UhnlmCs4y2iQYrfeMB8vEX3bHozBJanHu0PWNQJcj90R5xqorBp/bRcqZdi0kuQfxcTnGHtLUpN/U0TA==
+
+"@tiptap/extension-horizontal-rule@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.220.tgz#4b8eaf081b38359235312308ebd59950705c7b10"
+ integrity sha512-XMIs4R+4BoH5LpIxey513mZuus0XLHqjVayqtf03enmjBTLWzkixvvWLPLw4a47FJL5Q8l4REFHxjNifRzOKkg==
+
+"@tiptap/extension-image@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.220.tgz#c197b0dbd2f5d7a08f91e63cb8ca98c1972159a4"
+ integrity sha512-xyzlY/cupj/7AVqybQDaPaJ3SwKqe12xMWQlWxhhksuNpbQ6RGHrJz0DBSe61kIkaTZmIUBw055IFEMOPFF53g==
+
+"@tiptap/extension-italic@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.220.tgz#94e442689f69e694a2a983eabcae0ccc803262b9"
+ integrity sha512-aWAgqoR8fql9fJ7T/ZrEqovkEjZXbUpvlvWEvdBDMG3id8ZTGNDpdDKdvI6J/Rl5ZGPIg1TpHJtd+UixheWQsQ==
+
+"@tiptap/extension-link@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.220.tgz#c9954613cd1e0a0f1527853b732ef50dff734eac"
+ integrity sha512-vjEA8cE37ZZVVgPHSpttw3kbJoClb+ya/BVukDtJ1h6C7mIR1rqzNxTgpbnXJuA8xww0JOjpa5dpzEgcs294fA==
+ dependencies:
+ linkifyjs "^4.1.0"
+
+"@tiptap/extension-list-item@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.220.tgz#c2fcff1fb9148d303d78b0336032a6353a86ff6c"
+ integrity sha512-+O0ivwxPP2l/m9PAowb2ytDT/cM5kwu0s1W5MUsHPIqf+M6ahnl4ESjhWZfDHUzvjqPq6MTbqoQLHbB1KS/N7w==
+
+"@tiptap/extension-ordered-list@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.220.tgz#1fac8e8c2f8c0187e23ede59764fd031d5d1a83a"
+ integrity sha512-j3DmxJfwmNxFfMnvO7glmGlhYeZSIUnRrKnZu2KkpD6OcGJSh9y/yfnYwcuK80XbzEG/jKKIw0M2yRveOvyVwA==
+
+"@tiptap/extension-paragraph@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.220.tgz#d552dfdeeab9856e9eb8f0a7cf850f37d7cced69"
+ integrity sha512-ZGCzNGFYV4wa3l1nXtDIaYp7O6f0DrGTSl3alKkDTQe3SOmzXS2HjgWl9yPw8VXpU9W5mMGhXd+nGn/jUk+f/A==
+
+"@tiptap/extension-strike@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.220.tgz#2beb02d2d8807056ff3ea4ea74d9f6abba42bf78"
+ integrity sha512-cIM2ma6mzk08pijOn+KS3ZoHWaUVsVT+OF3m6xewjwJdC0ILg9nApEOhPFrhbeDcxcPmJMlgBl/xeUrEu1HQMg==
+
+"@tiptap/extension-subscript@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-subscript/-/extension-subscript-2.0.0-beta.220.tgz#3b9ebd181804f411f7755b8a73d1863dc72c5b8a"
+ integrity sha512-+C6nyAU4aaeCMvtBI1CJrMseE+YYqLUmmUVOK4ka3ZjmYkn1n+Tduf0ZGQHYmSSMDHPqQ8KsN+AQwaeSWKM/dA==
+
+"@tiptap/extension-superscript@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-superscript/-/extension-superscript-2.0.0-beta.220.tgz#93289e25bce0fb13608d7d41e74a13a3faf4d3c6"
+ integrity sha512-h7Qh8Jqb5r84hS0GhhQdNPFk+6AZhvbOKv/4dP6g9S5mRc287WlfhTrbpMdHI/p0r5vKkpLmAXpNCn6IImd3jQ==
+
+"@tiptap/extension-table-cell@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.0.0-beta.220.tgz#b3ae21a72a2012cb5e2656d91c90b7424672e6f8"
+ integrity sha512-JvX9CTaDBBbI1Qra7pwhsv0vD6Y3A+X6PL7EYVrqIHZlmWq7Lz2ELxjx8RkWyp2LzowVNgZwUu2i3yHakaX5oA==
+
+"@tiptap/extension-table-header@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.0.0-beta.220.tgz#3f6050847bc978dbcb117a9fa7dd16e13dd3b633"
+ integrity sha512-oOCBxrOuHCy4feuZKcBU9WWxi2SqBwfn/rmzSU6loKK8rR1+0olyAYu8IREb6DMmemTxl0ITp74hBxKeZyzjrA==
+
+"@tiptap/extension-table-row@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.0.0-beta.220.tgz#5339c2be44cbbf871768a809a1f3694bef2031e0"
+ integrity sha512-DbYfrzLREulL+xOx74XAuhuqHUNi0t9hXDzG6RYdPiNnMhX/HhmTIV7bLNjEGxy6rOX0LhDzrBpNlA1elYUrwQ==
+
+"@tiptap/extension-table@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.0.0-beta.220.tgz#42731e23e98d2c074e4e0460525718e57ebfc6a9"
+ integrity sha512-wdA957lSwIPtaSEAGw/KDXvhKAv28XkooHctY8FxqxEtvyMyCA8v0YXuOhGny/Uz6VZE+vdRiESMjwRU4ZQQ4g==
+
+"@tiptap/extension-task-item@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.0.0-beta.220.tgz#4c83d7b55587da9c8ed51cca6cd0edee13ff188d"
+ integrity sha512-dta4V3GkL3C+gYUUkv26gxvCD11JYE7XYp4GSED/1X/3aHOdV9HcYRtIVnHqb4YwfuX/AJyIDfjhxc2tNGevkQ==
+
+"@tiptap/extension-task-list@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.0.0-beta.220.tgz#ba349d84dfb9fd5dff90bfea8fb234cd90383d78"
+ integrity sha512-Hix7/Er4T4xKz4uLTxniJaDtcctmooaxoHiHv4yDUOXZYiK5BZypr8cbCcUaoD3qpfGe8O5JBzY2sbwk0PkNwA==
+
+"@tiptap/extension-text@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.220.tgz#3f51d4aac11c16d79cf8ca22502898b67f5bc2f5"
+ integrity sha512-3tnffc2YMjNyv7Lbad6fx9wYDE/Buz8vhx76M2AOSrjYbzmTJf7mLkgdlPM0VTy7FGZD5CGgHJAgYNt5HIqPkQ==
+
+"@tiptap/pm@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.0.0-beta.220.tgz#04e4c98e4d042ea8d67148ec6676f7078c6bac5a"
+ integrity sha512-O9mGcmwUpEr630HY9RylIyZJKnpXi3xWINWNiAEfRJ1br5j5pHRoVRJQ1HzU+6+Z+i/8qp3zRHGLTBqihaZETA==
+ dependencies:
+ prosemirror-changeset "^2.2.0"
+ prosemirror-collab "^1.3.0"
+ prosemirror-commands "^1.3.1"
+ prosemirror-dropcursor "^1.5.0"
prosemirror-gapcursor "^1.3.1"
-
-"@tiptap/extension-hard-break@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.202.tgz#f82c29f71082ae44c361964fb42e6e78d339dc29"
- integrity sha512-Nr9BXeP+dXS5vLP/C2voTrhl+4YkDHBtPlc+5xm5NPBn04slTGSPO2lgV3YrMsfUOMNXHqeob1lq4qiLF4pybQ==
-
-"@tiptap/extension-heading@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.202.tgz#da12041c626825f8a3f3173ac922e11f2df55cbf"
- integrity sha512-sF271jSWHgtoJLDNFLS7eyUcUStl7mBDQNJIENWVI+lFu2Ax8GmO7AoB74Q6L5Zaw4h73L6TAvaafHIXurz7tA==
-
-"@tiptap/extension-highlight@^2.0.0-beta.209":
- version "2.0.0-beta.209"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.209.tgz#f373884097c17daf92ce3aecdc6c3781a4904c31"
- integrity sha512-uy0Zu1dU2VcozvqpECb7+mxiazxstlb6w7jQQx8n4PAwIfN2LGv1UIil+VKRkc9amjBVwz+knm9psXEeJfjiBw==
-
-"@tiptap/extension-history@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.202.tgz#d94770367a1a7b4e8f81f36d8b1731ca1fbc6879"
- integrity sha512-BLwaOWmFHBQjOonojYHl1Po27IHxgjSAPw+ijMKtKzqa2msJRJevjC4tBaX5s/YrB7PQ2tFE7rfJED4HLjBm6w==
- dependencies:
prosemirror-history "^1.3.0"
-
-"@tiptap/extension-horizontal-rule@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.202.tgz#12da36ea8ede0e720c7b2e5d1a2dd4c255798b2f"
- integrity sha512-ut2Im/TNQynnuqdoY9yOjMDUKmxn97ERVEpqcQSaIgqBuF6bjk60Wa13ob6oS2g6vqXxwWFrnQVz48A9TcF5FQ==
- dependencies:
- prosemirror-state "^1.4.1"
-
-"@tiptap/extension-image@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.202.tgz#5e50fdf7d7ac67b3475b1cfba71fb3acaddab0df"
- integrity sha512-aHPJMXuoMgToTYkGZsz2ue8gKzes+B92qb9lVRYlY9f+r/tC2K4q3HMtx6qvh8l4Dei5/yeV9TqliY79E9A5dg==
-
-"@tiptap/extension-italic@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.202.tgz#0a991167dd06064bdf3c811d638d04cea9029206"
- integrity sha512-vgSLy4KDp6AmnAHLHXe/nWeNbLnyUXxmf4U4+esebAV5Hu2F7LgceknFt9D8AGEtYUU+/fYKSeE2NGJgTQG9lA==
-
-"@tiptap/extension-link@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.202.tgz#2b10ef877937bf2d491fffaf3e0545105f61b6fb"
- integrity sha512-/9bZd43dMkzmo7SCCDtEscgdFKCat9yZAyAyg+PHYdhI8Lbqv5GfjxzBbx58v7jEP1eDKFnwTDFVwAsxCE9f0w==
- dependencies:
- linkifyjs "^3.0.5"
- prosemirror-model "^1.18.1"
- prosemirror-state "^1.4.1"
-
-"@tiptap/extension-list-item@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.202.tgz#32bc4beacb0f692abfc8283760292a6354f070dc"
- integrity sha512-15yAsO+CCM8ievdX4oxg8kMBVFqhzVAw7pU6E8KL76kIwWCIIyVW6hU3VZdglyBVnAG0ws5/DaZ4VRFtVPRDvg==
-
-"@tiptap/extension-ordered-list@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.202.tgz#5b5987d3a1c98e579071e70485db2e82bf638ed9"
- integrity sha512-PpJn8EtS8MLZ4NN9R3crmrivbjTMHjuSE2Ab3Y9TdeR9x9DIF23O/EkunnkPUiBUx6sNADprEWJIQesgpakrtw==
-
-"@tiptap/extension-paragraph@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.202.tgz#5a395a8107bfc767f80335a0cf7f89278ad0cf20"
- integrity sha512-QI86DMUAz5froDJJXpbFV0I+iSFikjhQ8W5clYDbnrP/clRI/FYxklQ3oxSk4VzGBGB5EaBJf+jD7htLKb39UA==
-
-"@tiptap/extension-strike@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.202.tgz#8bf200fb044e5b2401edef26e26920b94ab35249"
- integrity sha512-cs87UI/VTkmSfIwlHpm7nAPXok2bAQvxmNJ1y7UPzTATVl+ixP1F4aIkwiYk+X7rE/Sys+09PGg1Pr1shwUUkQ==
-
-"@tiptap/extension-subscript@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-subscript/-/extension-subscript-2.0.0-beta.202.tgz#730e0181c5b8d623fb4674d568d5ef4f3bd986d5"
- integrity sha512-s/90xjDJGlWxontzyL0howpdTEbnl5EyvIDDYdAwalnHOGkyfWq8JMxL3klnxUL+Rn10sjatHnEYaLS2A5tN+Q==
-
-"@tiptap/extension-superscript@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-superscript/-/extension-superscript-2.0.0-beta.202.tgz#d756fb63585f8214ce3a7e2333978f2fb68b1259"
- integrity sha512-kDOc+Sf1N5LzKWDBrTYBWaQFG40z3dCt/ljIMDWJt3Vka8ahnH4kcXhW9eNZLeIWavoj+M+4th+CPSfMdAYJbg==
-
-"@tiptap/extension-table-cell@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.0.0-beta.202.tgz#95f3f9c14d4f21122bab109fb82e10b64ca5e613"
- integrity sha512-Ypmcq7zaMSZ0VNKwDPINOsSzyuH+gSIw+FrXy6O1dzVHAo1gNFJ2pEG/ZhQ2RqpDTpGfJFD8tNDx8wjCCAVlxA==
-
-"@tiptap/extension-table-header@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.0.0-beta.202.tgz#e9284abcfbe17c3c1ddfff55bb98873879c9d34a"
- integrity sha512-/l0lz3Hmc+hikj+RfSW7F6B/jYV2dROGQnK1/EYjgbvOK0158ml1mB6/Dhm+BhldV73MI7eU8+3YLB9uhsPR4w==
-
-"@tiptap/extension-table-row@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.0.0-beta.202.tgz#60cc878e7f7ae4ad82e1013471cb39a4058f9844"
- integrity sha512-IsHBT3lp//XSqcAWPIGWjPIKQ4okVaDJbwcElehlOo/rcRBeK0orT+c10T08PoOsozi4BeMYRo0nfA5tvrJMEw==
-
-"@tiptap/extension-table@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.0.0-beta.202.tgz#841254bf183e84a5b76edb4f1719883c85d51df8"
- integrity sha512-WMfXtDfx45FgU81WnfxGOSJbVoaDpe8hjuBJSGbwJj+Qj4HGhbK7/RbTtDrM8oqseHRzHuGWgNX+EfOUQppjdA==
- dependencies:
- "@_ueberdosis/prosemirror-tables" "1.1.3"
+ prosemirror-inputrules "^1.2.0"
+ prosemirror-keymap "^1.2.0"
+ prosemirror-markdown "^1.10.1"
+ prosemirror-menu "^1.2.1"
prosemirror-model "^1.18.1"
+ prosemirror-schema-basic "^1.2.0"
+ prosemirror-schema-list "^1.2.2"
prosemirror-state "^1.4.1"
+ prosemirror-tables "^1.3.0"
+ prosemirror-trailing-node "^2.0.2"
+ prosemirror-transform "^1.7.0"
prosemirror-view "^1.28.2"
-"@tiptap/extension-task-item@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.0.0-beta.202.tgz#350fd2d823300bd9e64a56c98404bbcffe802f08"
- integrity sha512-yOd72ELIr/NK3wb4SjetFCsTW/YU66LMjUCv6RFxgbcPtTN3auoaCelyo1l7EZSZmWbovR7G2QOiG1fQmfNgMg==
-
-"@tiptap/extension-task-list@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.0.0-beta.202.tgz#b2484ca0507f1d8b413e7f2967f4b71afefa91a9"
- integrity sha512-0E7hL2+vVeBm1khONomqk4Lac/LcQfKYesLvzLhjHOEuC7t8wTt7sZxI407b87YnQ+l8dsZey0vrcmV2/Wi4YQ==
+"@tiptap/suggestion@^2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.0.0-beta.220.tgz#2dc05f65e89006ffaad9f2b6a3468311a305e5ee"
+ integrity sha512-lYb2HOAKJLjEBbTx5VXA32wRryQiMwaKkNfr3v6UhlwoNgD6NkCYID08UJbpMV7iM+iFQp9408D/vVWFwvOuKg==
-"@tiptap/extension-text@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.202.tgz#d0152f547572a14c4e0e88287acb2b0c311fef04"
- integrity sha512-6UsfU9xvKTxHfZYxVJy5DSQ0ibnhC403KLRQ4ePwpJql0TotBx93/CBfPCVLFEwF86HNhf1fFUCx+j2wuwVxmA==
-
-"@tiptap/suggestion@^2.0.0-beta.202":
- version "2.0.0-beta.202"
- resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.0.0-beta.202.tgz#f0bc6a6712aeea266d7ed156c7c70ad29fb864e5"
- integrity sha512-V2BepOUj3ycvogOZE/nY9q2J4Hm1oH44YhOkqHB+QFQeOu6vqhFRqgGniJji52z2tAF+dvydSpQEzG+uCf2MEA==
- dependencies:
- prosemirror-model "^1.18.1"
- prosemirror-state "^1.4.1"
- prosemirror-view "^1.28.2"
-
-"@tiptap/vue-2@2.0.0-beta.200":
- version "2.0.0-beta.200"
- resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.200.tgz#ca3c2be6a813644de0e0ddbf96d973d355971e57"
- integrity sha512-sLa7arOVuHUfuoqAKGQrbJACxYaZ0Qlh4pO9rAxbGglVvO+L2VOXKqLORnsh6Sr/G1G6CnfUPSjf/S6BVHFmGg==
+"@tiptap/vue-2@2.0.0-beta.220":
+ version "2.0.0-beta.220"
+ resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.220.tgz#a3d9d84fc3cb6f1130bcd7e23fab9a4c56034312"
+ integrity sha512-GGK2M/pBVZSh2E0y1JXWVW7vllKvc2b/AwqPFZmbOGLKmxbH/xeaIeqOvt2w8b8RiA3G7UOq2lUGyjhn0/PnoQ==
dependencies:
- "@tiptap/extension-bubble-menu" "^2.0.0-beta.200"
- "@tiptap/extension-floating-menu" "^2.0.0-beta.200"
- prosemirror-view "^1.28.2"
+ "@tiptap/extension-bubble-menu" "^2.0.0-beta.220"
+ "@tiptap/extension-floating-menu" "^2.0.0-beta.220"
"@tootallnate/once@2":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
-"@tsconfig/node10@^1.0.7":
- version "1.0.9"
- resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
- integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
-
-"@tsconfig/node12@^1.0.7":
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
- integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
-
-"@tsconfig/node14@^1.0.0":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
- integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
-
-"@tsconfig/node16@^1.0.2":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
- integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
-
"@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"
@@ -2470,6 +2368,16 @@
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
+"@types/object.omit@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/object.omit/-/object.omit-3.0.0.tgz#0d31e1208eac8fe2ad5c9499a1016a8273bbfafc"
+ integrity sha512-I27IoPpH250TUzc9FzXd0P1BV/BMJuzqD3jOz98ehf9dQqGkxlq+hO1bIqZGWqCg5bVOy0g4AUVJtnxe0klDmw==
+
+"@types/object.pick@^1.3.1":
+ version "1.3.2"
+ 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"
@@ -2542,6 +2450,11 @@
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
+"@types/throttle-debounce@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@types/throttle-debounce/-/throttle-debounce-2.1.0.tgz#1c3df624bfc4b62f992d3012b84c56d41eab3776"
+ integrity sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==
+
"@types/tough-cookie@*":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397"
@@ -2631,6 +2544,57 @@
"@typescript-eslint/types" "5.38.0"
eslint-visitor-keys "^3.3.0"
+"@vue/compat@^3.2.47":
+ version "3.2.47"
+ resolved "https://registry.yarnpkg.com/@vue/compat/-/compat-3.2.47.tgz#315c9708a46ce13a1d81e7ff0bec33060a210741"
+ integrity sha512-spULbnhceN3fIGYRRgq75RPRqsakfUV0tyZ4zTweOB48bWtwHUn677exg8/58uLOBc1F5B5lXTD5qf7epqpTuw==
+ dependencies:
+ "@babel/parser" "^7.16.4"
+ estree-walker "^2.0.2"
+ source-map "^0.6.1"
+
+"@vue/compiler-core@3.2.47":
+ version "3.2.47"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.47.tgz#3e07c684d74897ac9aa5922c520741f3029267f8"
+ integrity sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==
+ dependencies:
+ "@babel/parser" "^7.16.4"
+ "@vue/shared" "3.2.47"
+ estree-walker "^2.0.2"
+ source-map "^0.6.1"
+
+"@vue/compiler-dom@3.2.47", "@vue/compiler-dom@^3.0.1":
+ version "3.2.47"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz#a0b06caf7ef7056939e563dcaa9cbde30794f305"
+ integrity sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==
+ dependencies:
+ "@vue/compiler-core" "3.2.47"
+ "@vue/shared" "3.2.47"
+
+"@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==
+ dependencies:
+ "@babel/parser" "^7.16.4"
+ "@vue/compiler-core" "3.2.47"
+ "@vue/compiler-dom" "3.2.47"
+ "@vue/compiler-ssr" "3.2.47"
+ "@vue/reactivity-transform" "3.2.47"
+ "@vue/shared" "3.2.47"
+ estree-walker "^2.0.2"
+ magic-string "^0.25.7"
+ postcss "^8.1.10"
+ source-map "^0.6.1"
+
+"@vue/compiler-ssr@3.2.47":
+ version "3.2.47"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz#35872c01a273aac4d6070ab9d8da918ab13057ee"
+ integrity sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==
+ dependencies:
+ "@vue/compiler-dom" "3.2.47"
+ "@vue/shared" "3.2.47"
+
"@vue/component-compiler-utils@^3.1.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz#f9f5fb53464b0c37b2c8d2f3fbfe44df60f61dc9"
@@ -2647,6 +2611,40 @@
optionalDependencies:
prettier "^1.18.2 || ^2.0.0"
+"@vue/reactivity-transform@3.2.47":
+ version "3.2.47"
+ resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz#e45df4d06370f8abf29081a16afd25cffba6d84e"
+ integrity sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==
+ dependencies:
+ "@babel/parser" "^7.16.4"
+ "@vue/compiler-core" "3.2.47"
+ "@vue/shared" "3.2.47"
+ estree-walker "^2.0.2"
+ magic-string "^0.25.7"
+
+"@vue/server-renderer@^3.0.1":
+ version "3.2.47"
+ resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.47.tgz#8aa1d1871fc4eb5a7851aa7f741f8f700e6de3c0"
+ integrity sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==
+ dependencies:
+ "@vue/compiler-ssr" "3.2.47"
+ "@vue/shared" "3.2.47"
+
+"@vue/shared@3.2.47":
+ version "3.2.47"
+ resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.47.tgz#e597ef75086c6e896ff5478a6bfc0a7aa4bbd14c"
+ integrity sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==
+
+"@vue/test-utils-vue3@npm:@vue/test-utils@2":
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-2.3.1.tgz#411883ea52091fa3e59d9b0b83f2934111c10776"
+ integrity sha512-tRtHRPEETQSUrqXgAewNZHm5iypxDFxwenfdcvMRm1kbGo4bcqHb1XHHlsaIjoDbLkuE2NYiF8vBQDNYrzlrSA==
+ dependencies:
+ js-beautify "1.14.6"
+ optionalDependencies:
+ "@vue/compiler-dom" "^3.0.1"
+ "@vue/server-renderer" "^3.0.1"
+
"@vue/test-utils@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.3.0.tgz#d563decdcd9c68a7bca151d4179a2bfd6d5c3e15"
@@ -2668,6 +2666,18 @@
source-map "0.5.6"
tsconfig "^7.0.0"
+"@vue/vue3-jest@^29.2.3":
+ version "29.2.3"
+ resolved "https://registry.yarnpkg.com/@vue/vue3-jest/-/vue3-jest-29.2.3.tgz#79caa80e6faff1f26be90c9da92447e7e03de9a0"
+ integrity sha512-wbit0rGgy9ARUBtc5dZ6PGCrxazCPs5pZ6ycB0qYMoEPmkRj8lIVUfJmTz03ryIAeVQOcTKnEWdcqgrTErl3vg==
+ dependencies:
+ "@babel/plugin-transform-modules-commonjs" "^7.2.0"
+ chalk "^2.1.0"
+ convert-source-map "^1.6.0"
+ css-tree "^2.0.1"
+ source-map "0.5.6"
+ tsconfig "^7.0.0"
+
"@webassemblyjs/ast@1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
@@ -2871,7 +2881,7 @@ abab@^2.0.5, abab@^2.0.6:
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
-abbrev@1:
+abbrev@1, abbrev@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
@@ -2909,7 +2919,7 @@ acorn-walk@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
-acorn-walk@^8.0.0, acorn-walk@^8.1.1:
+acorn-walk@^8.0.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
@@ -2924,7 +2934,7 @@ acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-acorn@^8.0.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.8.0:
+acorn@^8.0.4, acorn@^8.5.0, acorn@^8.8.0:
version "8.8.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
@@ -3059,11 +3069,6 @@ aproba@^1.1.1:
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
-arg@^4.1.0:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
- integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
-
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@@ -3426,21 +3431,21 @@ boolbase@^1.0.0:
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
-bootstrap-vue@2.20.1:
- version "2.20.1"
- resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.20.1.tgz#1b6cd4368632c1a6dd4a5ed161242baa131c3cd5"
- integrity sha512-s+w83q0T2mo/RbFwTM8gExbLJMEOYpdTUqmyFaHv2Ir+TFprMvTWpeAzeNuawJ130W1gePZ3LW3cNp1t/tZbOw==
+bootstrap-vue@2.23.1:
+ version "2.23.1"
+ resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.23.1.tgz#8f866f7cda27eb0e7e13a0bea8d55d8fc7a82199"
+ integrity sha512-SEWkG4LzmMuWjQdSYmAQk1G/oOKm37dtNfjB5kxq0YafnL2W6qUAmeDTcIZVbPiQd2OQlIkWOMPBRGySk/zGsg==
dependencies:
"@nuxt/opencollective" "^0.3.2"
- bootstrap ">=4.5.3 <5.0.0"
+ bootstrap "^4.6.1"
popper.js "^1.16.1"
portal-vue "^2.1.7"
vue-functional-data-merge "^3.1.0"
-bootstrap@4.5.3, "bootstrap@>=4.5.3 <5.0.0":
- version "4.5.3"
- resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.5.3.tgz#c6a72b355aaf323920be800246a6e4ef30997fe6"
- integrity sha512-o9ppKQioXGqhw8Z7mah6KdTYpNQY//tipnkxppWhPbiSWdD+1raYsnhwEZjkTHYbGee4cVQ0Rx65EhOY/HNLcQ==
+bootstrap@4.6.2, bootstrap@^4.6.1:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.2.tgz#8e0cd61611728a5bf65a3a2b8d6ff6c77d5d7479"
+ integrity sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==
brace-expansion@^1.1.7:
version "1.1.11"
@@ -3735,6 +3740,11 @@ canvas-confetti@^1.4.0:
resolved "https://registry.yarnpkg.com/canvas-confetti/-/canvas-confetti-1.4.0.tgz#840f6db4a566f8f32abe28c00dcd82acf39c92bd"
integrity sha512-S18o4Y9PqI/uabdlT/jI3MY7XBJjNxnfapFIkjkMwpz6qNxLFZOm2b22OMf4ZYDL9lpNWI+Ih4fEMVPwO1KHFQ==
+case-anything@^2.1.10:
+ version "2.1.10"
+ resolved "https://registry.yarnpkg.com/case-anything/-/case-anything-2.1.10.tgz#d18a6ca968d54ec3421df71e3e190f3bced23410"
+ integrity sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ==
+
ccount@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5"
@@ -4060,10 +4070,10 @@ condense-newlines@^0.2.1:
is-whitespace "^0.3.0"
kind-of "^3.0.2"
-config-chain@^1.1.12:
- version "1.1.12"
- resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
- integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==
+config-chain@^1.1.13:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
+ integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
dependencies:
ini "^1.3.4"
proto-list "~1.2.1"
@@ -4178,29 +4188,27 @@ 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.28.0, core-js@^3.6.5:
- version "3.28.0"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.28.0.tgz#ed8b9e99c273879fdfff0edfc77ee709a5800e4a"
- integrity sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw==
+core-js@^3.29.1, core-js@^3.6.5:
+ version "3.29.1"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.29.1.tgz#40ff3b41588b091aaed19ca1aa5cb111803fa9a6"
+ integrity sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
-cosmiconfig-toml-loader@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/cosmiconfig-toml-loader/-/cosmiconfig-toml-loader-1.0.0.tgz#0681383651cceff918177debe9084c0d3769509b"
- integrity sha512-H/2gurFWVi7xXvCyvsWRLCMekl4tITJcX0QEsDMpzxtuxDyM59xLatYNg4s/k9AA/HdtCYfj2su8mgA0GSDLDA==
+cosmiconfig@8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.0.0.tgz#e9feae014eab580f858f8a0288f38997a7bebe97"
+ integrity sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==
dependencies:
- "@iarna/toml" "^2.2.5"
-
-cosmiconfig-typescript-loader@^4.0.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.1.1.tgz#38dd3578344038dae40fdf09792bc2e9df529f78"
- integrity sha512-9DHpa379Gp0o0Zefii35fcmuuin6q92FnLDffzdZ0l9tVd3nEobG3O+MZ06+kuBvFTSVScvNb/oHA13Nd4iipg==
+ import-fresh "^3.2.1"
+ js-yaml "^4.1.0"
+ parse-json "^5.0.0"
+ path-type "^4.0.0"
-cosmiconfig@7.0.1, cosmiconfig@^7.0.1:
+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==
@@ -4241,10 +4249,10 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
-create-require@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
- integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
+crelt@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.5.tgz#57c0d52af8c859e354bace1883eb2e1eb182bb94"
+ integrity sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==
cron-validator@^1.1.1:
version "1.2.1"
@@ -4944,6 +4952,11 @@ dagre@^0.8.5:
graphlib "^2.1.8"
lodash "^4.17.15"
+dash-get@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/dash-get/-/dash-get-1.0.2.tgz#4c9e9ad5ef04c4bf9d3c9a451f6f7997298dcc7c"
+ integrity sha512-4FbVrHDwfOASx7uQVxeiCTo7ggSdYZbqs8lH+WU6ViypPlDbe9y6IP5VVUDQBv9DcnyaiPT5XT0UWHgJ64zLeQ==
+
data-urls@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143"
@@ -5166,11 +5179,6 @@ diff@^3.4.0:
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
-diff@^4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
- integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
-
diff@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
@@ -5276,10 +5284,10 @@ dompurify@2.3.8:
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f"
integrity sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw==
-dompurify@^2.4.3:
- version "2.4.3"
- resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.3.tgz#f4133af0e6a50297fc8874e2eaedc13a3c308c03"
- integrity sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==
+dompurify@^2.4.5:
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.5.tgz#0e89a27601f0bad978f9a924e7a05d5d2cccdd87"
+ integrity sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==
domutils@^2.5.2, domutils@^2.6.0:
version "2.6.0"
@@ -5504,73 +5512,43 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
-esbuild-loader@^2.21.0:
- version "2.21.0"
- resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-2.21.0.tgz#2698a3e565b0db2bb19a3dd91c2b6c9aad526c80"
- integrity sha512-k7ijTkCT43YBSZ6+fBCW1Gin7s46RrJ0VQaM8qA7lq7W+OLsGgtLyFV8470FzYi/4TeDexniTBTPTwZUnXXR5g==
+esbuild-loader@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-3.0.1.tgz#9871c0e8817c4c11b6249d1916832e75272e6c7e"
+ integrity sha512-aZfGybqTeuyCd4AsVvWOOfkhIuN+wfZFjMyh3gyQEU1Uvsl8L6vye9HqP93iRa0iTA+6Jclap514PJIC3cLnMA==
dependencies:
- esbuild "^0.16.17"
- joycon "^3.0.1"
- json5 "^2.2.0"
- loader-utils "^2.0.0"
- tapable "^2.2.0"
+ esbuild "^0.17.6"
+ get-tsconfig "^4.4.0"
+ loader-utils "^2.0.4"
webpack-sources "^1.4.3"
-esbuild@0.17.4:
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.4.tgz#af4f8f78604c67f8e6afbdee36a3f4211ecfc859"
- integrity sha512-zBn9MeCwT7W5F1a3lXClD61ip6vQM+H8Msb0w8zMT4ZKBpDg+rFAraNyWCDelB/2L6M3g6AXHPnsyvjMFnxtFw==
+esbuild@0.17.11, esbuild@^0.17.6:
+ version "0.17.11"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.11.tgz#9f3122643b21d7e7731e42f18576c10bfa28152b"
+ integrity sha512-pAMImyokbWDtnA/ufPxjQg0fYo2DDuzAlqwnDvbXqHLphe+m80eF++perYKVm8LeTuj2zUuFXC+xgSVxyoHUdg==
optionalDependencies:
- "@esbuild/android-arm" "0.17.4"
- "@esbuild/android-arm64" "0.17.4"
- "@esbuild/android-x64" "0.17.4"
- "@esbuild/darwin-arm64" "0.17.4"
- "@esbuild/darwin-x64" "0.17.4"
- "@esbuild/freebsd-arm64" "0.17.4"
- "@esbuild/freebsd-x64" "0.17.4"
- "@esbuild/linux-arm" "0.17.4"
- "@esbuild/linux-arm64" "0.17.4"
- "@esbuild/linux-ia32" "0.17.4"
- "@esbuild/linux-loong64" "0.17.4"
- "@esbuild/linux-mips64el" "0.17.4"
- "@esbuild/linux-ppc64" "0.17.4"
- "@esbuild/linux-riscv64" "0.17.4"
- "@esbuild/linux-s390x" "0.17.4"
- "@esbuild/linux-x64" "0.17.4"
- "@esbuild/netbsd-x64" "0.17.4"
- "@esbuild/openbsd-x64" "0.17.4"
- "@esbuild/sunos-x64" "0.17.4"
- "@esbuild/win32-arm64" "0.17.4"
- "@esbuild/win32-ia32" "0.17.4"
- "@esbuild/win32-x64" "0.17.4"
-
-esbuild@^0.16.17:
- version "0.16.17"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259"
- integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==
- optionalDependencies:
- "@esbuild/android-arm" "0.16.17"
- "@esbuild/android-arm64" "0.16.17"
- "@esbuild/android-x64" "0.16.17"
- "@esbuild/darwin-arm64" "0.16.17"
- "@esbuild/darwin-x64" "0.16.17"
- "@esbuild/freebsd-arm64" "0.16.17"
- "@esbuild/freebsd-x64" "0.16.17"
- "@esbuild/linux-arm" "0.16.17"
- "@esbuild/linux-arm64" "0.16.17"
- "@esbuild/linux-ia32" "0.16.17"
- "@esbuild/linux-loong64" "0.16.17"
- "@esbuild/linux-mips64el" "0.16.17"
- "@esbuild/linux-ppc64" "0.16.17"
- "@esbuild/linux-riscv64" "0.16.17"
- "@esbuild/linux-s390x" "0.16.17"
- "@esbuild/linux-x64" "0.16.17"
- "@esbuild/netbsd-x64" "0.16.17"
- "@esbuild/openbsd-x64" "0.16.17"
- "@esbuild/sunos-x64" "0.16.17"
- "@esbuild/win32-arm64" "0.16.17"
- "@esbuild/win32-ia32" "0.16.17"
- "@esbuild/win32-x64" "0.16.17"
+ "@esbuild/android-arm" "0.17.11"
+ "@esbuild/android-arm64" "0.17.11"
+ "@esbuild/android-x64" "0.17.11"
+ "@esbuild/darwin-arm64" "0.17.11"
+ "@esbuild/darwin-x64" "0.17.11"
+ "@esbuild/freebsd-arm64" "0.17.11"
+ "@esbuild/freebsd-x64" "0.17.11"
+ "@esbuild/linux-arm" "0.17.11"
+ "@esbuild/linux-arm64" "0.17.11"
+ "@esbuild/linux-ia32" "0.17.11"
+ "@esbuild/linux-loong64" "0.17.11"
+ "@esbuild/linux-mips64el" "0.17.11"
+ "@esbuild/linux-ppc64" "0.17.11"
+ "@esbuild/linux-riscv64" "0.17.11"
+ "@esbuild/linux-s390x" "0.17.11"
+ "@esbuild/linux-x64" "0.17.11"
+ "@esbuild/netbsd-x64" "0.17.11"
+ "@esbuild/openbsd-x64" "0.17.11"
+ "@esbuild/sunos-x64" "0.17.11"
+ "@esbuild/win32-arm64" "0.17.11"
+ "@esbuild/win32-ia32" "0.17.11"
+ "@esbuild/win32-x64" "0.17.11"
escalade@^3.1.1:
version "3.1.1"
@@ -5801,12 +5779,15 @@ eslint-visitor-keys@^3.3.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-eslint@8.32.0:
- version "8.32.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.32.0.tgz#d9690056bb6f1a302bd991e7090f5b68fbaea861"
- integrity sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==
+eslint@8.36.0:
+ version "8.36.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf"
+ integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==
dependencies:
- "@eslint/eslintrc" "^1.4.1"
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/regexpp" "^4.4.0"
+ "@eslint/eslintrc" "^2.0.1"
+ "@eslint/js" "8.36.0"
"@humanwhocodes/config-array" "^0.11.8"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
@@ -5817,10 +5798,9 @@ eslint@8.32.0:
doctrine "^3.0.0"
escape-string-regexp "^4.0.0"
eslint-scope "^7.1.1"
- eslint-utils "^3.0.0"
eslint-visitor-keys "^3.3.0"
- espree "^9.4.0"
- esquery "^1.4.0"
+ espree "^9.5.0"
+ esquery "^1.4.2"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
@@ -5841,15 +5821,14 @@ eslint@8.32.0:
minimatch "^3.1.2"
natural-compare "^1.4.0"
optionator "^0.9.1"
- regexpp "^3.2.0"
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
text-table "^0.2.0"
-espree@^9.3.1, espree@^9.4.0:
- version "9.4.0"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a"
- integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==
+espree@^9.3.1, espree@^9.5.0:
+ version "9.5.0"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.0.tgz#3646d4e3f58907464edba852fa047e6a27bdf113"
+ integrity sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==
dependencies:
acorn "^8.8.0"
acorn-jsx "^5.3.2"
@@ -5860,10 +5839,10 @@ esprima@^4.0.0, esprima@^4.0.1:
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-esquery@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5"
- integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
+esquery@^1.4.0, esquery@^1.4.2:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+ integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
dependencies:
estraverse "^5.1.0"
@@ -5884,6 +5863,11 @@ estraverse@^5.1.0, estraverse@^5.2.0:
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
+estree-walker@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+ integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
@@ -6438,6 +6422,11 @@ get-symbol-description@^1.0.0:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"
+get-tsconfig@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.4.0.tgz#64eee64596668a81b8fce18403f94f245ee0d4e5"
+ integrity sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==
+
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
@@ -6489,7 +6478,7 @@ glob-parent@^6.0.2:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@~8.0.3:
+glob@^8.0.3, glob@~8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e"
integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==
@@ -6591,23 +6580,21 @@ graphlib@^2.1.8:
dependencies:
lodash "^4.17.15"
-graphql-config@^4.3.6:
- version "4.3.6"
- resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-4.3.6.tgz#908ef03d6670c3068e51fe2e84e10e3e0af220b6"
- integrity sha512-i7mAPwc0LAZPnYu2bI8B6yXU5820Wy/ArvmOseDLZIu0OU1UTULEuexHo6ZcHXeT9NvGGaUPQZm8NV3z79YydA==
+graphql-config@^4.4.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-4.5.0.tgz#257c2338950b8dce295a27f75c5f6c39f8f777b2"
+ integrity sha512-x6D0/cftpLUJ0Ch1e5sj1TZn6Wcxx4oMfmhaG9shM0DKajA9iR+j1z86GSTQ19fShbGvrSSvbIQsHku6aQ6BBw==
dependencies:
"@graphql-tools/graphql-file-loader" "^7.3.7"
"@graphql-tools/json-file-loader" "^7.3.7"
"@graphql-tools/load" "^7.5.5"
"@graphql-tools/merge" "^8.2.6"
"@graphql-tools/url-loader" "^7.9.7"
- "@graphql-tools/utils" "^8.6.5"
- cosmiconfig "7.0.1"
- cosmiconfig-toml-loader "1.0.0"
- cosmiconfig-typescript-loader "^4.0.0"
- minimatch "4.2.1"
+ "@graphql-tools/utils" "^9.0.0"
+ cosmiconfig "8.0.0"
+ jiti "1.17.1"
+ minimatch "4.2.3"
string-env-interpolation "1.0.1"
- ts-node "^10.8.1"
tslib "^2.4.0"
graphql-depth-limit@^1.1.0:
@@ -6763,6 +6750,11 @@ hash-sum@^1.0.2:
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04"
integrity sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==
+hash-sum@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
+ integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
+
hash.js@^1.0.0, hash.js@^1.0.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846"
@@ -7320,7 +7312,7 @@ is-extendable@^0.1.0, is-extendable@^0.1.1:
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
-is-extendable@^1.0.1:
+is-extendable@^1.0.0, is-extendable@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
@@ -7981,10 +7973,10 @@ jest@^28.1.3:
import-local "^3.0.2"
jest-cli "^28.1.3"
-joycon@^3.0.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03"
- integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==
+jiti@1.17.1:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.17.1.tgz#264daa43ee89a03e8be28c3d712ccc4eb9f1e8ed"
+ integrity sha512-NZIITw8uZQFuzQimqjUxIrIcEdxYDFIe/0xYfIlVXTkiBjjyBEvgasj5bb0/cHtPRD/NziPbT312sFrkI5ALpw==
jquery.caret@^0.3.1:
version "0.3.1"
@@ -7996,16 +7988,15 @@ jquery.caret@^0.3.1:
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470"
integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==
-js-beautify@^1.6.12:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.11.0.tgz#afb873dc47d58986360093dcb69951e8bcd5ded2"
- integrity sha512-a26B+Cx7USQGSWnz9YxgJNMmML/QG2nqIaL7VVYPCXbqiKz8PN0waSNvroMtvAK6tY7g/wPdNWGEP+JTNIBr6A==
+js-beautify@1.14.6, js-beautify@^1.6.12:
+ version "1.14.6"
+ resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.14.6.tgz#b23ca5d74a462c282c7711bb51150bcc97f2b507"
+ integrity sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==
dependencies:
- config-chain "^1.1.12"
+ config-chain "^1.1.13"
editorconfig "^0.15.3"
- glob "^7.1.3"
- mkdirp "~1.0.3"
- nopt "^4.0.3"
+ glob "^8.0.3"
+ nopt "^6.0.0"
js-cookie@^3.0.0:
version "3.0.1"
@@ -8112,7 +8103,7 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"
-json5@^2.1.2, json5@^2.2.0, json5@^2.2.1:
+json5@^2.1.2, json5@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
@@ -8237,16 +8228,21 @@ linkify-it@^4.0.1:
dependencies:
uc.micro "^1.0.1"
-linkifyjs@^3.0.5:
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-3.0.5.tgz#99e51a3a0c0e232fcb63ebb89eea3ff923378f34"
- integrity sha512-1Y9XQH65eQKA9p2xtk+zxvnTeQBG7rdAXSkUG97DmuI/Xhji9uaUzaWxRj6rf9YC0v8KKHkxav7tnLX82Sz5Fg==
+linkifyjs@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.1.0.tgz#0460bfcc37d3348fa80e078d92e7bbc82588db15"
+ integrity sha512-Ffv8VoY3+ixI1b3aZ3O+jM6x17cOsgwfB1Wq7pkytbo1WlyRp6ZO0YDMqiWT/gQPY/CmtiGuKfzDIVqxh1aCTA==
loader-runner@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
+loader-runner@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
+ 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"
@@ -8256,10 +8252,10 @@ loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2
emojis-list "^3.0.0"
json5 "^1.0.1"
-loader-utils@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0"
- integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==
+loader-utils@^2.0.0, loader-utils@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
+ integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"
@@ -8470,6 +8466,13 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
+magic-string@^0.25.7:
+ version "0.25.9"
+ resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
+ integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
+ dependencies:
+ sourcemap-codec "^1.4.8"
+
make-dir@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
@@ -8485,7 +8488,7 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
dependencies:
semver "^6.0.0"
-make-error@^1.1.1:
+make-error@^1.3.6:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
@@ -9196,10 +9199,10 @@ minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
-minimatch@4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4"
- integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==
+minimatch@4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.3.tgz#b4dcece1d674dee104bb0fb833ebb85a78cbbca6"
+ integrity sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng==
dependencies:
brace-expansion "^1.1.7"
@@ -9330,7 +9333,7 @@ mkdirp@^0.5.1, mkdirp@^0.5.3:
dependencies:
minimist "^1.2.5"
-mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.3:
+mkdirp@^1.0.3, mkdirp@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
@@ -9467,7 +9470,7 @@ negotiator@0.6.3:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
-neo-async@^2.5.0, neo-async@^2.6.1:
+neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
@@ -9549,13 +9552,12 @@ nodemon@^2.0.19:
touch "^3.1.0"
undefsafe "^2.0.5"
-nopt@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
- integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==
+nopt@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d"
+ integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==
dependencies:
- abbrev "1"
- osenv "^0.1.4"
+ abbrev "^1.0.0"
nopt@~1.0.10:
version "1.0.10"
@@ -9665,6 +9667,13 @@ object.entries@^1.1.5:
define-properties "^1.1.3"
es-abstract "^1.19.1"
+object.omit@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-3.0.0.tgz#0e3edc2fce2ba54df5577ff529f6d97bd8a522af"
+ integrity sha512-EO+BCv6LJfu+gBIF3ggLicFebFLN5zqzz/WWJlMFfkMyGth+oBkhxzDl0wx2W4GkLzuQs/FsSkXZb2IMWQqmBQ==
+ dependencies:
+ is-extendable "^1.0.0"
+
object.pick@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
@@ -9776,24 +9785,11 @@ os-browserify@^0.3.0:
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
-os-homedir@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
- integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-
-os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
+os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-osenv@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
- integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
- dependencies:
- os-homedir "^1.0.0"
- os-tmpdir "^1.0.0"
-
p-limit@3.1.0, p-limit@^3.0.2, p-limit@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
@@ -10145,7 +10141,7 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^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.2.1, postcss@^8.4.14:
+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==
@@ -10251,19 +10247,33 @@ property-information@^6.0.0:
resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.1.1.tgz#5ca85510a3019726cb9afed4197b7b8ac5926a22"
integrity sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==
-prosemirror-commands@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.3.1.tgz#926c88801eebaa50363d4658850b41406d375a31"
- integrity sha512-XTporPgoECkOQACVw0JTe3RZGi+fls3/byqt+tXwGTkD7qLuB4KdVrJamDMJf4kfKga3uB8hZ+kUUyZ5oWpnfg==
+prosemirror-changeset@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/prosemirror-changeset/-/prosemirror-changeset-2.2.0.tgz#22c05da271a118be40d3e339fa2cace789b1254b"
+ integrity sha512-QM7ohGtkpVpwVGmFb8wqVhaz9+6IUXcIQBGZ81YNAKYuHiFJ1ShvSzab4pKqTinJhwciZbrtBEk/2WsqSt2PYg==
+ dependencies:
+ prosemirror-transform "^1.0.0"
+
+prosemirror-collab@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.3.0.tgz#601d33473bf72e6c43041a54b860c84c60b37769"
+ integrity sha512-+S/IJ69G2cUu2IM5b3PBekuxs94HO1CxJIWOFrLQXUaUDKL/JfBx+QcH31ldBlBXyDEUl+k3Vltfi1E1MKp2mA==
+ dependencies:
+ prosemirror-state "^1.0.0"
+
+prosemirror-commands@^1.0.0, prosemirror-commands@^1.3.1:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.5.0.tgz#d10efece1647c1d984fef6f65d52fdc77785560b"
+ integrity sha512-zL0Fxbj3fh71GPNHn5YdYgYGX2aU2XLecZYk2ekEF0oOD259HcXtM+96VjPVi5o3h4sGUdDfEEhGiREXW6U+4A==
dependencies:
prosemirror-model "^1.0.0"
prosemirror-state "^1.0.0"
prosemirror-transform "^1.0.0"
-prosemirror-dropcursor@1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.5.0.tgz#edbc61d6f71f9f924130eec8e85b0861357957c9"
- integrity sha512-vy7i77ddKyXlu8kKBB3nlxLBnsWyKUmQIPB5x8RkYNh01QNp/qqGmdd5yZefJs0s3rtv5r7Izfu2qbtr+tYAMQ==
+prosemirror-dropcursor@^1.5.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.7.0.tgz#a846ba49414dcd99cf8fc8bb26e4f9f24b8f09d0"
+ integrity sha512-vzab/iPd3CjWILFv6WJz4+BlOwCywOcAGhvY5G/66OYPcaZehN8IVbGtHCV3oyhXk2yAA67nwMv/oNMvBV9k1A==
dependencies:
prosemirror-state "^1.0.0"
prosemirror-transform "^1.1.0"
@@ -10279,7 +10289,7 @@ prosemirror-gapcursor@^1.3.1:
prosemirror-state "^1.0.0"
prosemirror-view "^1.0.0"
-prosemirror-history@^1.3.0:
+prosemirror-history@^1.0.0, prosemirror-history@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.3.0.tgz#bf5a1ff7759aca759ddf0c722c2fa5b14fb0ddc1"
integrity sha512-qo/9Wn4B/Bq89/YD+eNWFbAytu6dmIM85EhID+fz9Jcl9+DfGEo8TTSrRhP15+fFEoaPqpHSxlvSzSEbmlxlUA==
@@ -10288,10 +10298,18 @@ prosemirror-history@^1.3.0:
prosemirror-transform "^1.0.0"
rope-sequence "^1.3.0"
-prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.0:
+prosemirror-inputrules@^1.2.0:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.2.0.tgz#d5cc9da9b712020690a994b50b92a0e448a60bf5"
- integrity sha512-TdSfu+YyLDd54ufN/ZeD1VtBRYpgZnTPnnbY+4R08DDgs84KrIPEPbJL8t1Lm2dkljFx6xeBE26YWH3aIzkPKg==
+ resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.2.0.tgz#476dde2dc244050b3aca00cf58a82adfad6749e7"
+ integrity sha512-eAW/M/NTSSzpCOxfR8Abw6OagdG0MiDAiWHQMQveIsZtoKVYzm0AflSPq/ymqJd56/Su1YPbwy9lM13wgHOFmQ==
+ dependencies:
+ prosemirror-state "^1.0.0"
+ prosemirror-transform "^1.0.0"
+
+prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.2.1.tgz#3839e7db66cecddae7451f4246e73bdd8489be1d"
+ integrity sha512-kVK6WGC+83LZwuSJnuCb9PsADQnFZllt94qPP3Rx/vLcOUV65+IbBeH2nS5cFggPyEVJhGkGrgYFRrG250WhHQ==
dependencies:
prosemirror-state "^1.0.0"
w3c-keyname "^2.2.0"
@@ -10304,19 +10322,37 @@ prosemirror-markdown@1.9.1:
markdown-it "^13.0.1"
prosemirror-model "^1.0.0"
-prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.2.0, prosemirror-model@^1.8.1:
- version "1.18.1"
- resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.18.1.tgz#1d5d6b6de7b983ee67a479dc607165fdef3935bd"
- integrity sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw==
+prosemirror-markdown@^1.10.1:
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.10.1.tgz#e20468201cda1916a6182686159398b242bb78ab"
+ integrity sha512-s7iaTLiX+qO5z8kF2NcMmy2T7mIlxzkS4Sp3vTKSYChPtbMpg6YxFkU0Y06rUg2WtKlvBu7v1bXzlGBkfjUWAA==
+ dependencies:
+ markdown-it "^13.0.1"
+ prosemirror-model "^1.0.0"
+
+prosemirror-menu@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.1.tgz#94d99a8547b7ba5680c20e9c497ce19846ce3b2c"
+ integrity sha512-sBirXxVfHalZO4f1ZS63WzewINK4182+7dOmoMeBkqYO8wqMBvBS7wQuwVOHnkMWPEh0+N0LJ856KYUN+vFkmQ==
+ dependencies:
+ crelt "^1.0.0"
+ prosemirror-commands "^1.0.0"
+ prosemirror-history "^1.0.0"
+ prosemirror-state "^1.0.0"
+
+prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.19.0, prosemirror-model@^1.8.1:
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.19.0.tgz#d7ad9a65ada0bb12196f64fe0dd4fc392c841c29"
+ integrity sha512-/CvFGJnwc41EJSfDkQLly1cAJJJmBpZwwUJtwZPTjY2RqZJfM8HVbCreOY/jti8wTRbVyjagcylyGoeJH/g/3w==
dependencies:
orderedmap "^2.0.0"
prosemirror-schema-basic@^1.0.0, prosemirror-schema-basic@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.0.tgz#c33ad74426efae1d41e2260371866f623e8eb10e"
- integrity sha512-JMN/ammP94ObOUS6cpIy121r0MEDN9V95mAxFVALwC4bbmhpWXGjBGHTA5LHPPdbqZKyR6Jar1Akv4Z5k9CNLw==
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.1.tgz#a5a137a6399d1a829873332117d2fe8131d291d0"
+ integrity sha512-vYBdIHsYKSDIqYmPBC7lnwk9DsKn8PnVqK97pMYP5MLEDFqWIX75JiaJTzndBii4bRuNqhC2UfDOfM3FKhlBHg==
dependencies:
- prosemirror-model "^1.2.0"
+ prosemirror-model "^1.19.0"
prosemirror-schema-list@^1.0.0, prosemirror-schema-list@^1.2.2:
version "1.2.2"
@@ -10328,12 +10364,24 @@ prosemirror-schema-list@^1.0.0, prosemirror-schema-list@^1.2.2:
prosemirror-transform "^1.0.0"
prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, prosemirror-state@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.1.tgz#f6e26c7b6a7e11206176689eb6ebbf91870953e1"
- integrity sha512-U/LBDW2gNmVa07sz/D229XigSdDQ5CLFwVB1Vb32MJbAHHhWe/6pOc721faI17tqw4pZ49i1xfY/jEZ9tbIhPg==
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.2.tgz#f93bd8a33a4454efab917ba9b738259d828db7e5"
+ integrity sha512-puuzLD2mz/oTdfgd8msFbe0A42j5eNudKAAPDB0+QJRw8cO1ygjLmhLrg9RvDpf87Dkd6D4t93qdef00KKNacQ==
dependencies:
prosemirror-model "^1.0.0"
prosemirror-transform "^1.0.0"
+ prosemirror-view "^1.27.0"
+
+prosemirror-tables@^1.3.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.3.2.tgz#ca208c6a55d510af14b652d23e800e00ba6bebd4"
+ integrity sha512-/9JTeN6s58Zq66HXaxP6uf8PAmc7XXKZFPlOGVtLvxEd6xBP6WtzaJB9wBjiGUzwbdhdMEy7V62yuHqk/3VrnQ==
+ dependencies:
+ prosemirror-keymap "^1.1.2"
+ prosemirror-model "^1.8.1"
+ prosemirror-state "^1.3.1"
+ prosemirror-transform "^1.2.1"
+ prosemirror-view "^1.13.3"
prosemirror-test-builder@^1.1.0:
version "1.1.0"
@@ -10344,17 +10392,27 @@ prosemirror-test-builder@^1.1.0:
prosemirror-schema-basic "^1.0.0"
prosemirror-schema-list "^1.0.0"
+prosemirror-trailing-node@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.3.tgz#213fc0e545a434ff3c37b5218a0de69561bf3892"
+ integrity sha512-lGrjMrn97KWkjQSW/FjdvnhJmqFACmQIyr6lKYApvHitDnKsCoZz6XzrHB7RZYHni/0NxQmZ01p/2vyK2SkvaA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@remirror/core-constants" "^2.0.0"
+ "@remirror/core-helpers" "^2.0.1"
+ escape-string-regexp "^4.0.0"
+
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.7.0.tgz#a8a0768f3ee6418d26ebef435beda9d43c65e472"
- integrity sha512-O4T697Cqilw06Zvc3Wm+e237R6eZtJL/xGMliCi+Uo8VL6qHk6afz1qq0zNjT3eZMuYwnP8ZS0+YxX/tfcE9TQ==
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.7.1.tgz#b516e818c3add0bdf960f4ca8ccb9d057a3ba21b"
+ integrity sha512-VteoifAfpt46z0yEt6Fc73A5OID9t/y2QIeR5MgxEwTuitadEunD/V0c9jQW8ziT8pbFM54uTzRLJ/nLuQjMxg==
dependencies:
prosemirror-model "^1.0.0"
-prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.28.2:
- version "1.28.2"
- resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.28.2.tgz#e997ef9dc623d01afd170e328fc924e6f4382003"
- integrity sha512-uK28mJbu0GI8Oz7Aclt6BKL4g+C59EBShBXDB0Y9Y71H25p4bQgmLQLfDWjsT1J9XOw0bR8QQajZmdK8RvXI9g==
+prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.28.2:
+ version "1.30.1"
+ resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.30.1.tgz#7cf0ae8dc8553a02c32961e82eca25079c4d8fc9"
+ integrity sha512-pZUfr7lICJkEY7XwzldAKrkflZDeIvnbfuu2RIS01N5NwJmR/dfZzDzJRzhb3SM2QtT/bM8b4Nnib8X3MGpAhA==
dependencies:
prosemirror-model "^1.16.0"
prosemirror-state "^1.0.0"
@@ -10622,10 +10680,10 @@ regenerate@^1.4.2:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
-regenerator-runtime@^0.13.4:
- version "0.13.5"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
- integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
+regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.4:
+ version "0.13.11"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
+ integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
regenerator-transform@^0.15.0:
version "0.15.0"
@@ -10656,11 +10714,6 @@ regexp.prototype.flags@^1.4.3:
define-properties "^1.1.3"
functions-have-names "^1.2.2"
-regexpp@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
- integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
-
regexpu-core@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3"
@@ -10852,9 +10905,9 @@ robust-predicates@^3.0.0:
integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==
rope-sequence@^1.3.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.2.tgz#a19e02d72991ca71feb6b5f8a91154e48e3c098b"
- integrity sha512-ku6MFrwEVSVmXLvy3dYph3LAMNS0890K7fabn+0YIRQ2T96T9F4gkFf0vf0WW0JUraNWwGRtInEpH7yO4tbQZg==
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.3.tgz#3f67fc106288b84b71532b4a5fd9d4881e4457f0"
+ integrity sha512-85aZYCxweiD5J8yTEbw+E6A27zSnLPNDL0WfPdw3YYodq7WjnTKo0q4dtyQ2gz23iPT8Q9CUyJtAaUNcTxRf5Q==
route-recognizer@^0.3.3:
version "0.3.4"
@@ -11344,6 +11397,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+sourcemap-codec@^1.4.8:
+ version "1.4.8"
+ resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
+ integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
+
space-separated-tokens@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz#43193cec4fb858a2ce934b7f98b7f2c18107098b"
@@ -11770,11 +11828,6 @@ tapable@^1.0.0, tapable@^1.1.3:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
-tapable@^2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
- integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
-
tar@^6.0.2:
version "6.1.11"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
@@ -11833,6 +11886,17 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+thread-loader@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/thread-loader/-/thread-loader-3.0.4.tgz#c392e4c0241fbc80430eb680e4886819b504a31b"
+ integrity sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA==
+ dependencies:
+ json-parse-better-errors "^1.0.2"
+ loader-runner "^4.1.0"
+ loader-utils "^2.0.0"
+ neo-async "^2.6.2"
+ schema-utils "^3.0.0"
+
three@^0.143.0:
version "0.143.0"
resolved "https://registry.yarnpkg.com/three/-/three-0.143.0.tgz#1455bca132cc2b20beb7f41d313e10c29e5ed9df"
@@ -11843,6 +11907,11 @@ throttle-debounce@^2.1.0:
resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.1.0.tgz#257e648f0a56bd9e54fe0f132c4ab8611df4e1d5"
integrity sha512-AOvyNahXQuU7NN+VVvOOX+uW6FPaWdAOdRP5HfwYxAfCzXTFKRMoIMk+n+po318+ktcChx+F1Dd91G3YHeMKyg==
+throttle-debounce@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb"
+ integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==
+
through2@^2.0.0:
version "2.0.5"
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
@@ -11999,25 +12068,6 @@ ts-invariant@^0.9.4:
dependencies:
tslib "^2.1.0"
-ts-node@^10.8.1:
- version "10.9.1"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
- integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
- dependencies:
- "@cspotcode/source-map-support" "^0.8.0"
- "@tsconfig/node10" "^1.0.7"
- "@tsconfig/node12" "^1.0.7"
- "@tsconfig/node14" "^1.0.0"
- "@tsconfig/node16" "^1.0.2"
- acorn "^8.4.1"
- acorn-walk "^8.1.1"
- arg "^4.1.0"
- create-require "^1.1.0"
- diff "^4.0.1"
- make-error "^1.1.1"
- v8-compile-cache-lib "^3.0.1"
- yn "3.1.1"
-
tsconfig-paths@^3.14.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
@@ -12038,7 +12088,7 @@ tsconfig@^7.0.0:
strip-bom "^3.0.0"
strip-json-comments "^2.0.0"
-tslib@2.3.0, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@~2.3.0:
+tslib@2.3.0, tslib@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
@@ -12048,10 +12098,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.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
- integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
+tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.4.1:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
+ integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
tsutils@^3.21.0:
version "3.21.0"
@@ -12109,6 +12159,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@^2.0.0:
+ version "2.19.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
+ integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==
+
type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
@@ -12157,9 +12212,9 @@ undefsafe@^2.0.5:
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
undici@^5.0.0:
- version "5.8.0"
- resolved "https://registry.yarnpkg.com/undici/-/undici-5.8.0.tgz#dec9a8ccd90e5a1d81d43c0eab6503146d649a4f"
- integrity sha512-1F7Vtcez5w/LwH2G2tGnFIihuWUlc58YidwLiCv+jR2Z50x0tNXpRRw7eOIJ+GvqCqIkg9SB7NWAJ/T9TLfv8Q==
+ version "5.8.2"
+ resolved "https://registry.yarnpkg.com/undici/-/undici-5.8.2.tgz#071fc8a6a5d24db0ad510ad442f607d9b09d5eec"
+ integrity sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A==
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"
@@ -12221,10 +12276,10 @@ unique-slug@^2.0.0:
dependencies:
imurmurhash "^0.1.4"
-unist-builder@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-3.0.0.tgz#728baca4767c0e784e1e64bb44b5a5a753021a04"
- integrity sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==
+unist-builder@^3.0.0, unist-builder@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-3.0.1.tgz#258b89dcadd3c973656b2327b347863556907f58"
+ integrity sha512-gnpOw7DIpCA0vpr6NqdPvTWnlPTApCTRzr+38E6hCWx3rz/cjo83SsKIlS1Z+L5ttScQ2AwutNnb8+tAvpb6qQ==
dependencies:
"@types/unist" "^2.0.0"
@@ -12260,10 +12315,10 @@ unist-util-visit-parents@^4.0.0:
"@types/unist" "^2.0.0"
unist-util-is "^5.0.0"
-unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz#44bbc5d25f2411e7dfc5cecff12de43296aa8521"
- integrity sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg==
+unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz#b4520811b0ca34285633785045df7a8d6776cfeb"
+ integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==
dependencies:
"@types/unist" "^2.0.0"
unist-util-is "^5.0.0"
@@ -12402,11 +12457,6 @@ uvu@^0.5.0:
kleur "^4.0.3"
sade "^1.7.3"
-v8-compile-cache-lib@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
- integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
-
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"
@@ -12522,6 +12572,15 @@ vue-hot-reload-api@^2.3.0:
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==
+"vue-loader-vue3@npm:vue-loader@17":
+ version "17.0.1"
+ resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-17.0.1.tgz#c0ee8875e0610a0c2d13ba9b4d50a9c8442e7a3a"
+ integrity sha512-/OOyugJnImKCkAKrAvdsWMuwoCqGxWT5USLsjohzWbMgOwpA5wQmzQiLMzZd7DjhIfunzAGIApTOgIylz/kwcg==
+ dependencies:
+ chalk "^4.1.0"
+ hash-sum "^2.0.0"
+ loader-utils "^2.0.0"
+
vue-loader@15.9.6:
version "15.9.6"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.6.tgz#f4bb9ae20c3a8370af3ecf09b8126d38ffdb6b8b"
@@ -12576,6 +12635,11 @@ 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.11:
+ version "0.0.11"
+ resolved "https://registry.yarnpkg.com/vue-test-utils-compat/-/vue-test-utils-compat-0.0.11.tgz#d3e92bcee6893e7506b5d6463f774678f144fe7a"
+ integrity sha512-vAc19M4GS0qxGZGB0UZg7mG6j90hyNoDQXWYCEG4Sjahyi+v+CHq9xHa6js70S8HExNkm2f4LF3x2+gbCMFVUQ==
+
vue-virtual-scroll-list@^1.4.7:
version "1.4.7"
resolved "https://registry.yarnpkg.com/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.4.7.tgz#12ee26833885f5bb4d37dc058085ccf3ce5b5a74"
@@ -13099,11 +13163,6 @@ yarn-deduplicate@^6.0.0:
semver "^7.3.7"
tslib "^2.4.0"
-yn@3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
- integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
-
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"